Repository: Atmosphere-NX/Atmosphere Branch: master Commit: 61ac03e22d20 Files: 3719 Total size: 26.5 MB Directory structure: gitextract_x8an86a0/ ├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── atmosphere.mk ├── config_templates/ │ ├── exosphere.ini │ ├── hbl_html/ │ │ └── accessible-urls/ │ │ └── accessible-urls.txt │ ├── override_config.ini │ ├── stratosphere.ini │ └── system_settings.ini ├── docs/ │ ├── building.md │ ├── changelog.md │ ├── components/ │ │ ├── detail/ │ │ │ └── exosphere_memory_layout.txt │ │ ├── emummc.md │ │ ├── exosphere.md │ │ ├── fusee.md │ │ ├── libraries.md │ │ ├── mesosphere.md │ │ ├── modules/ │ │ │ ├── ams_mitm.md │ │ │ ├── boot.md │ │ │ ├── boot2.md │ │ │ ├── creport.md │ │ │ ├── dmnt.md │ │ │ ├── eclct.stub.md │ │ │ ├── erpt.md │ │ │ ├── fatal.md │ │ │ ├── jpegdec.md │ │ │ ├── loader.md │ │ │ ├── ncm.md │ │ │ ├── pgl.md │ │ │ ├── pm.md │ │ │ ├── ro.md │ │ │ ├── sm.md │ │ │ └── spl.md │ │ ├── stratosphere.md │ │ ├── thermosphere.md │ │ └── troposphere.md │ ├── faq.md │ ├── features/ │ │ ├── cheats.md │ │ ├── configurations.md │ │ └── dns_mitm.md │ ├── licensing_exemptions/ │ │ └── MIT_LICENSE │ ├── main.md │ └── roadmap.md ├── emummc/ │ ├── .gitignore │ ├── .gitrepo │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── build.sh │ ├── emummc.json │ ├── emummc.ld │ ├── emummc.specs │ ├── source/ │ │ ├── FS/ │ │ │ ├── FS.h │ │ │ ├── FS_offsets.c │ │ │ ├── FS_offsets.h │ │ │ ├── FS_structs.h │ │ │ ├── FS_versions.h │ │ │ └── offsets/ │ │ │ ├── 100.h │ │ │ ├── 1000.h │ │ │ ├── 1000_exfat.h │ │ │ ├── 1020.h │ │ │ ├── 1020_exfat.h │ │ │ ├── 1100.h │ │ │ ├── 1100_exfat.h │ │ │ ├── 1200.h │ │ │ ├── 1200_exfat.h │ │ │ ├── 1203.h │ │ │ ├── 1203_exfat.h │ │ │ ├── 1300.h │ │ │ ├── 1300_exfat.h │ │ │ ├── 1310.h │ │ │ ├── 1310_exfat.h │ │ │ ├── 1400.h │ │ │ ├── 1400_exfat.h │ │ │ ├── 1500.h │ │ │ ├── 1500_exfat.h │ │ │ ├── 1600.h │ │ │ ├── 1600_exfat.h │ │ │ ├── 1603.h │ │ │ ├── 1603_exfat.h │ │ │ ├── 1700.h │ │ │ ├── 1700_exfat.h │ │ │ ├── 1800.h │ │ │ ├── 1800_exfat.h │ │ │ ├── 1810.h │ │ │ ├── 1810_exfat.h │ │ │ ├── 1900.h │ │ │ ├── 1900_exfat.h │ │ │ ├── 200.h │ │ │ ├── 2000.h │ │ │ ├── 2000_exfat.h │ │ │ ├── 200_exfat.h │ │ │ ├── 2010.h │ │ │ ├── 2010_exfat.h │ │ │ ├── 210.h │ │ │ ├── 2100.h │ │ │ ├── 2100_exfat.h │ │ │ ├── 210_exfat.h │ │ │ ├── 2120.h │ │ │ ├── 2120_exfat.h │ │ │ ├── 300.h │ │ │ ├── 300_exfat.h │ │ │ ├── 301.h │ │ │ ├── 301_exfat.h │ │ │ ├── 400.h │ │ │ ├── 400_exfat.h │ │ │ ├── 410.h │ │ │ ├── 410_exfat.h │ │ │ ├── 500.h │ │ │ ├── 500_exfat.h │ │ │ ├── 510.h │ │ │ ├── 510_exfat.h │ │ │ ├── 600.h │ │ │ ├── 600_exfat.h │ │ │ ├── 700.h │ │ │ ├── 700_exfat.h │ │ │ ├── 800.h │ │ │ ├── 800_exfat.h │ │ │ ├── 810.h │ │ │ ├── 810_exfat.h │ │ │ ├── 900.h │ │ │ ├── 900_exfat.h │ │ │ ├── 910.h │ │ │ └── 910_exfat.h │ │ ├── emmc/ │ │ │ ├── mmc.h │ │ │ ├── nx_emmc.c │ │ │ ├── nx_emmc.h │ │ │ ├── nx_sd.c │ │ │ ├── nx_sd.h │ │ │ ├── sd.h │ │ │ ├── sdmmc.c │ │ │ ├── sdmmc.h │ │ │ ├── sdmmc_driver.c │ │ │ ├── sdmmc_driver.h │ │ │ └── sdmmc_t210.h │ │ ├── emuMMC/ │ │ │ ├── emummc.c │ │ │ ├── emummc.h │ │ │ └── emummc_ctx.h │ │ ├── libs/ │ │ │ └── fatfs/ │ │ │ ├── diskio.c │ │ │ ├── diskio.h │ │ │ ├── ff.c │ │ │ ├── ff.h │ │ │ ├── ffconf.h │ │ │ ├── ffsystem.c │ │ │ └── ffunicode.c │ │ ├── main.c │ │ ├── nx/ │ │ │ ├── cache.h │ │ │ ├── cache.s │ │ │ ├── counter.h │ │ │ ├── dynamic.c │ │ │ ├── smc.c │ │ │ ├── smc.h │ │ │ ├── start.s │ │ │ ├── svc.h │ │ │ └── svc.s │ │ ├── power/ │ │ │ ├── max77620.h │ │ │ ├── max7762x.c │ │ │ └── max7762x.h │ │ ├── soc/ │ │ │ ├── clock.c │ │ │ ├── clock.h │ │ │ ├── gpio.c │ │ │ ├── gpio.h │ │ │ ├── i2c.c │ │ │ ├── i2c.h │ │ │ ├── pinmux.c │ │ │ ├── pinmux.h │ │ │ ├── pmc.h │ │ │ ├── pmc_lp0_t210.h │ │ │ └── t210.h │ │ └── utils/ │ │ ├── fatal.c │ │ ├── fatal.h │ │ ├── types.h │ │ ├── util.c │ │ └── util.h │ └── tools/ │ ├── fs_ida_nintendo_folder_xref_formatter.au3 │ └── kip1converter.py ├── exosphere/ │ ├── Makefile │ ├── exosphere.mk │ ├── loader_stub/ │ │ ├── Makefile │ │ ├── loader_stub.ld │ │ ├── loader_stub.mk │ │ ├── loader_stub.specs │ │ └── source/ │ │ ├── secmon_loader_error.cpp │ │ ├── secmon_loader_error.hpp │ │ ├── secmon_loader_main.cpp │ │ ├── secmon_loader_uncompress.cpp │ │ ├── secmon_loader_uncompress.hpp │ │ └── start.s │ ├── mariko_fatal/ │ │ ├── Makefile │ │ ├── mariko_fatal.ld │ │ ├── mariko_fatal.mk │ │ ├── mariko_fatal.specs │ │ └── source/ │ │ ├── fatal_abort_impl.cpp │ │ ├── fatal_crt0.s │ │ ├── fatal_crt0_cpp.cpp │ │ ├── fatal_device_page_table.cpp │ │ ├── fatal_device_page_table.hpp │ │ ├── fatal_display.cpp │ │ ├── fatal_display.hpp │ │ ├── fatal_display_config.inc │ │ ├── fatal_font.inc │ │ ├── fatal_main.cpp │ │ ├── fatal_print.cpp │ │ ├── fatal_print.hpp │ │ ├── fatal_registers_di.hpp │ │ ├── fatal_save_context.cpp │ │ ├── fatal_save_context.hpp │ │ ├── fatal_sdmmc.cpp │ │ ├── fatal_sdmmc.hpp │ │ ├── fatal_sdmmc_c.cpp │ │ ├── fatal_sdmmc_c.h │ │ ├── fatal_sound.cpp │ │ ├── fatal_sound.hpp │ │ ├── fatfs/ │ │ │ ├── 00history.txt │ │ │ ├── 00readme.txt │ │ │ ├── diskio.c │ │ │ ├── diskio.h │ │ │ ├── ff.c │ │ │ ├── ff.h │ │ │ ├── ffconf.h │ │ │ ├── ffsystem.c │ │ │ └── ffunicode.c │ │ └── fs/ │ │ ├── fatal_fs_api.cpp │ │ └── fatal_fs_api.hpp │ ├── program/ │ │ ├── Makefile │ │ ├── program.ld │ │ ├── program.mk │ │ ├── program.specs │ │ ├── rebootstub/ │ │ │ ├── Makefile │ │ │ ├── rebootstub.ld │ │ │ ├── rebootstub.mk │ │ │ ├── rebootstub.specs │ │ │ └── source/ │ │ │ ├── rebootstub_exception_vectors.s │ │ │ ├── rebootstub_main.s │ │ │ └── rebootstub_power_off.cpp │ │ ├── sc7fw/ │ │ │ ├── Makefile │ │ │ ├── sc7fw.ld │ │ │ ├── sc7fw.mk │ │ │ ├── sc7fw.specs │ │ │ └── source/ │ │ │ ├── sc7fw_dram.cpp │ │ │ ├── sc7fw_dram.hpp │ │ │ ├── sc7fw_exception_vectors.s │ │ │ ├── sc7fw_main.cpp │ │ │ ├── sc7fw_start.s │ │ │ ├── sc7fw_util.hpp │ │ │ └── sc7fw_util_asm.s │ │ ├── source/ │ │ │ ├── boot/ │ │ │ │ ├── secmon_boot.hpp │ │ │ │ ├── secmon_boot_cache.cpp │ │ │ │ ├── secmon_boot_cache.hpp │ │ │ │ ├── secmon_boot_config.cpp │ │ │ │ ├── secmon_boot_functions.cpp │ │ │ │ ├── secmon_boot_functions.hpp │ │ │ │ ├── secmon_boot_key_data.s │ │ │ │ ├── secmon_boot_rsa.cpp │ │ │ │ ├── secmon_boot_setup.cpp │ │ │ │ ├── secmon_crt0.s │ │ │ │ ├── secmon_crt0_cpp.cpp │ │ │ │ ├── secmon_main.cpp │ │ │ │ ├── secmon_make_page_table.cpp │ │ │ │ ├── secmon_package2.cpp │ │ │ │ └── secmon_size_data.s │ │ │ ├── secmon_cache.cpp │ │ │ ├── secmon_cache.hpp │ │ │ ├── secmon_cache.inc │ │ │ ├── secmon_cache_impl.inc │ │ │ ├── secmon_cpu_context.cpp │ │ │ ├── secmon_cpu_context.hpp │ │ │ ├── secmon_error.cpp │ │ │ ├── secmon_error.hpp │ │ │ ├── secmon_exception_handler.cpp │ │ │ ├── secmon_exception_vectors.s │ │ │ ├── secmon_interrupt_handler.cpp │ │ │ ├── secmon_interrupt_handler.hpp │ │ │ ├── secmon_key_storage.cpp │ │ │ ├── secmon_key_storage.hpp │ │ │ ├── secmon_map.cpp │ │ │ ├── secmon_map.hpp │ │ │ ├── secmon_mariko_fatal_error.cpp │ │ │ ├── secmon_mariko_fatal_error.hpp │ │ │ ├── secmon_misc.cpp │ │ │ ├── secmon_misc.hpp │ │ │ ├── secmon_page_mapper.cpp │ │ │ ├── secmon_page_mapper.hpp │ │ │ ├── secmon_setup.cpp │ │ │ ├── secmon_setup.hpp │ │ │ ├── secmon_setup_warm.cpp │ │ │ ├── secmon_spinlock.hpp │ │ │ ├── secmon_spinlock.s │ │ │ ├── secmon_stack_warm.s │ │ │ ├── secmon_start_virtual.s │ │ │ ├── secmon_start_warm.s │ │ │ ├── secmon_user_power_management.cpp │ │ │ ├── secmon_user_power_management.hpp │ │ │ └── smc/ │ │ │ ├── secmon_define_access_table.inc │ │ │ ├── secmon_define_mc01_access_table.inc │ │ │ ├── secmon_define_mc_access_table.inc │ │ │ ├── secmon_define_pmc_access_table.inc │ │ │ ├── secmon_mc01_access_table_data.inc │ │ │ ├── secmon_mc_access_table_data.inc │ │ │ ├── secmon_pmc_access_table_data.inc │ │ │ ├── secmon_random_cache.cpp │ │ │ ├── secmon_random_cache.hpp │ │ │ ├── secmon_smc_aes.cpp │ │ │ ├── secmon_smc_aes.hpp │ │ │ ├── secmon_smc_carveout.cpp │ │ │ ├── secmon_smc_carveout.hpp │ │ │ ├── secmon_smc_common.hpp │ │ │ ├── secmon_smc_cpu_asm.s │ │ │ ├── secmon_smc_device_unique_data.cpp │ │ │ ├── secmon_smc_device_unique_data.hpp │ │ │ ├── secmon_smc_error.cpp │ │ │ ├── secmon_smc_error.hpp │ │ │ ├── secmon_smc_handler.cpp │ │ │ ├── secmon_smc_handler.hpp │ │ │ ├── secmon_smc_info.cpp │ │ │ ├── secmon_smc_info.hpp │ │ │ ├── secmon_smc_memory_access.cpp │ │ │ ├── secmon_smc_memory_access.hpp │ │ │ ├── secmon_smc_power_management.cpp │ │ │ ├── secmon_smc_power_management.hpp │ │ │ ├── secmon_smc_random.cpp │ │ │ ├── secmon_smc_random.hpp │ │ │ ├── secmon_smc_register_access.cpp │ │ │ ├── secmon_smc_register_access.hpp │ │ │ ├── secmon_smc_result.cpp │ │ │ ├── secmon_smc_result.hpp │ │ │ ├── secmon_smc_rsa.cpp │ │ │ ├── secmon_smc_rsa.hpp │ │ │ ├── secmon_smc_se_lock.cpp │ │ │ └── secmon_smc_se_lock.hpp │ │ └── split_program.py │ ├── sdmmc_test/ │ │ ├── Makefile │ │ ├── sdmmc_test.ld │ │ ├── sdmmc_test.specs │ │ └── source/ │ │ ├── sdmmc_test_main.cpp │ │ └── sdmmc_test_start.s │ └── warmboot/ │ ├── Makefile │ ├── source/ │ │ ├── warmboot_bootrom_workaround.cpp │ │ ├── warmboot_bootrom_workaround.hpp │ │ ├── warmboot_clkrst.cpp │ │ ├── warmboot_clkrst.hpp │ │ ├── warmboot_cpu_cluster.cpp │ │ ├── warmboot_cpu_cluster.hpp │ │ ├── warmboot_dram.cpp │ │ ├── warmboot_dram.hpp │ │ ├── warmboot_exception_vectors.s │ │ ├── warmboot_main.cpp │ │ ├── warmboot_main.hpp │ │ ├── warmboot_misc.cpp │ │ ├── warmboot_misc.hpp │ │ ├── warmboot_secure_monitor.cpp │ │ ├── warmboot_secure_monitor.hpp │ │ ├── warmboot_start.s │ │ ├── warmboot_util.hpp │ │ └── warmboot_util_asm.s │ ├── warmboot.ld │ ├── warmboot.mk │ └── warmboot.specs ├── fusee/ │ ├── Makefile │ ├── build_package3.py │ ├── fusee.mk │ ├── loader_stub/ │ │ ├── Makefile │ │ ├── loader_stub.ld │ │ ├── loader_stub.mk │ │ ├── loader_stub.specs │ │ └── source/ │ │ ├── fusee_loader_error.cpp │ │ ├── fusee_loader_error.hpp │ │ ├── fusee_loader_main.cpp │ │ ├── fusee_loader_start.s │ │ ├── fusee_loader_uncompress.cpp │ │ └── fusee_loader_uncompress.hpp │ └── program/ │ ├── Makefile │ ├── lz4_compress.py │ ├── program.ld │ ├── program.mk │ ├── program.specs │ ├── program_ovl.ld │ ├── source/ │ │ ├── fatfs/ │ │ │ ├── diskio.c │ │ │ ├── diskio.h │ │ │ ├── diskio_cpp.h │ │ │ ├── ff.c │ │ │ ├── ff.h │ │ │ ├── ffconf.h │ │ │ ├── ffsystem.c │ │ │ ├── ffunicode.c │ │ │ └── fusee_diskio.cpp │ │ ├── fs/ │ │ │ ├── fusee_fs_api.cpp │ │ │ ├── fusee_fs_api.hpp │ │ │ ├── fusee_fs_file_storage.cpp │ │ │ └── fusee_fs_storage.hpp │ │ ├── fusee_cpu.cpp │ │ ├── fusee_cpu.hpp │ │ ├── fusee_crt0.cpp │ │ ├── fusee_display.cpp │ │ ├── fusee_display.hpp │ │ ├── fusee_display_config.inc │ │ ├── fusee_emummc.cpp │ │ ├── fusee_emummc.hpp │ │ ├── fusee_exception_handler.cpp │ │ ├── fusee_exception_handler.hpp │ │ ├── fusee_exception_handler_asm.s │ │ ├── fusee_external_package.hpp │ │ ├── fusee_fatal.cpp │ │ ├── fusee_fatal.hpp │ │ ├── fusee_font.inc │ │ ├── fusee_ini.cpp │ │ ├── fusee_ini.hpp │ │ ├── fusee_key_derivation.cpp │ │ ├── fusee_key_derivation.hpp │ │ ├── fusee_main.cpp │ │ ├── fusee_malloc.cpp │ │ ├── fusee_malloc.hpp │ │ ├── fusee_mmc.cpp │ │ ├── fusee_mmc.hpp │ │ ├── fusee_overlay_manager.cpp │ │ ├── fusee_overlay_manager.hpp │ │ ├── fusee_package2.cpp │ │ ├── fusee_package2.hpp │ │ ├── fusee_print.cpp │ │ ├── fusee_print.hpp │ │ ├── fusee_registers_di.hpp │ │ ├── fusee_sd_card.cpp │ │ ├── fusee_sd_card.hpp │ │ ├── fusee_secmon_sync.cpp │ │ ├── fusee_secmon_sync.hpp │ │ ├── fusee_setup_horizon.cpp │ │ ├── fusee_setup_horizon.hpp │ │ ├── fusee_start.s │ │ ├── fusee_stratosphere.cpp │ │ ├── fusee_stratosphere.hpp │ │ ├── fusee_uncompress.cpp │ │ ├── fusee_uncompress.hpp │ │ ├── mtc/ │ │ │ ├── fusee_mtc.cpp │ │ │ ├── fusee_mtc.hpp │ │ │ ├── fusee_mtc_erista.cpp │ │ │ ├── fusee_mtc_mariko.cpp │ │ │ ├── fusee_mtc_ram_training_pattern.inc │ │ │ ├── fusee_mtc_tables_erista.inc │ │ │ ├── fusee_mtc_tables_mariko.inc │ │ │ ├── fusee_mtc_timing_table_common.hpp │ │ │ ├── fusee_mtc_timing_table_erista.hpp │ │ │ └── fusee_mtc_timing_table_mariko.hpp │ │ ├── sdram/ │ │ │ ├── fusee_sdram.cpp │ │ │ ├── fusee_sdram.hpp │ │ │ ├── fusee_sdram_params.inc │ │ │ ├── fusee_sdram_params_lp0_erista.inc │ │ │ └── fusee_sdram_params_lp0_mariko.inc │ │ └── sein/ │ │ ├── fusee_secure_initialize.cpp │ │ └── fusee_secure_initialize.hpp │ ├── update_mtc_tables.py │ └── update_sdram_params.py ├── img/ │ └── atmosphere.sketch ├── libraries/ │ ├── .gitignore │ ├── .gitmodules │ ├── .gitrepo │ ├── LICENSE │ ├── README.md │ ├── config/ │ │ ├── arch/ │ │ │ ├── arm/ │ │ │ │ ├── arch.mk │ │ │ │ └── cpu/ │ │ │ │ └── arm7tdmi/ │ │ │ │ └── cpu.mk │ │ │ ├── arm64/ │ │ │ │ ├── arch.mk │ │ │ │ ├── base_rules │ │ │ │ ├── base_tools │ │ │ │ └── cpu/ │ │ │ │ ├── cortex_a57/ │ │ │ │ │ └── cpu.mk │ │ │ │ └── generic_arm64/ │ │ │ │ └── cpu.mk │ │ │ ├── armv4t/ │ │ │ │ └── arch.mk │ │ │ ├── armv8a/ │ │ │ │ └── arch.mk │ │ │ └── x64/ │ │ │ ├── arch.mk │ │ │ ├── base_rules │ │ │ ├── base_tools │ │ │ └── cpu/ │ │ │ └── generic_x64/ │ │ │ └── cpu.mk │ │ ├── board/ │ │ │ ├── generic/ │ │ │ │ ├── linux/ │ │ │ │ │ └── board.mk │ │ │ │ ├── macos/ │ │ │ │ │ └── board.mk │ │ │ │ └── windows/ │ │ │ │ └── board.mk │ │ │ ├── nintendo/ │ │ │ │ ├── nx/ │ │ │ │ │ └── board.mk │ │ │ │ └── nx_bpmp/ │ │ │ │ └── board.mk │ │ │ └── qemu/ │ │ │ └── virt/ │ │ │ └── board.mk │ │ ├── common.mk │ │ ├── os/ │ │ │ ├── horizon/ │ │ │ │ └── os.mk │ │ │ ├── linux/ │ │ │ │ └── os.mk │ │ │ ├── macos/ │ │ │ │ └── os.mk │ │ │ └── windows/ │ │ │ └── os.mk │ │ └── templates/ │ │ ├── exosphere.mk │ │ ├── mesosphere.mk │ │ └── stratosphere.mk │ ├── libexosphere/ │ │ ├── Makefile │ │ ├── include/ │ │ │ ├── exosphere/ │ │ │ │ ├── actmon.hpp │ │ │ │ ├── br/ │ │ │ │ │ ├── br_types.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── br_common_types.hpp │ │ │ │ │ ├── br_erista_types.hpp │ │ │ │ │ └── br_mariko_types.hpp │ │ │ │ ├── br.hpp │ │ │ │ ├── charger.hpp │ │ │ │ ├── clkrst.hpp │ │ │ │ ├── common.hpp │ │ │ │ ├── diag/ │ │ │ │ │ └── diag_detailed_assertion_impl.inc │ │ │ │ ├── flow.hpp │ │ │ │ ├── fuse.hpp │ │ │ │ ├── gic.hpp │ │ │ │ ├── hw/ │ │ │ │ │ ├── hw_arm.hpp │ │ │ │ │ ├── hw_arm64.hpp │ │ │ │ │ ├── hw_arm64_cache.hpp │ │ │ │ │ └── hw_arm64_system_registers.hpp │ │ │ │ ├── hw.hpp │ │ │ │ ├── i2c.hpp │ │ │ │ ├── log.hpp │ │ │ │ ├── mmu/ │ │ │ │ │ ├── mmu_api.arch.arm.hpp │ │ │ │ │ ├── mmu_api.arch.arm64.hpp │ │ │ │ │ └── mmu_api.hpp │ │ │ │ ├── mmu.hpp │ │ │ │ ├── pinmux.hpp │ │ │ │ ├── pkg1/ │ │ │ │ │ ├── pkg1_api.hpp │ │ │ │ │ ├── pkg1_boot_config.hpp │ │ │ │ │ ├── pkg1_bootloader_parameters.hpp │ │ │ │ │ ├── pkg1_error_types.hpp │ │ │ │ │ ├── pkg1_key_generation.hpp │ │ │ │ │ └── pkg1_se_key_slots.hpp │ │ │ │ ├── pkg1.hpp │ │ │ │ ├── pkg2.hpp │ │ │ │ ├── pmc.hpp │ │ │ │ ├── pmic.hpp │ │ │ │ ├── pmic_setup.hpp │ │ │ │ ├── rtc.hpp │ │ │ │ ├── se/ │ │ │ │ │ ├── se_aes.hpp │ │ │ │ │ ├── se_common.hpp │ │ │ │ │ ├── se_hash.hpp │ │ │ │ │ ├── se_management.hpp │ │ │ │ │ ├── se_oaep.hpp │ │ │ │ │ ├── se_rng.hpp │ │ │ │ │ ├── se_rsa.hpp │ │ │ │ │ └── se_suspend.hpp │ │ │ │ ├── se.hpp │ │ │ │ ├── secmon/ │ │ │ │ │ ├── secmon_configuration_context.arch.arm64.hpp │ │ │ │ │ ├── secmon_configuration_context.hpp │ │ │ │ │ ├── secmon_emummc_context.hpp │ │ │ │ │ ├── secmon_log.hpp │ │ │ │ │ ├── secmon_memory_layout.hpp │ │ │ │ │ ├── secmon_monitor_context.hpp │ │ │ │ │ └── secmon_volatile_context.hpp │ │ │ │ ├── secmon.hpp │ │ │ │ ├── tsec.hpp │ │ │ │ ├── uart.hpp │ │ │ │ ├── util.hpp │ │ │ │ └── wdt.hpp │ │ │ └── exosphere.hpp │ │ ├── libexosphere.mk │ │ └── source/ │ │ ├── actmon/ │ │ │ ├── actmon_api.cpp │ │ │ └── actmon_registers.hpp │ │ ├── charger/ │ │ │ └── charger_api.cpp │ │ ├── clkrst/ │ │ │ └── clkrst_api.cpp │ │ ├── crypto/ │ │ │ └── crypto_aes_impl_security_engine.cpp │ │ ├── flow/ │ │ │ └── flow_api.cpp │ │ ├── fuse/ │ │ │ ├── fuse_api.cpp │ │ │ └── fuse_registers.hpp │ │ ├── gic/ │ │ │ └── gic_api.cpp │ │ ├── hw/ │ │ │ ├── hw_cache.arch.arm.cpp │ │ │ └── hw_cache.arch.arm64.cpp │ │ ├── i2c/ │ │ │ └── i2c_api.cpp │ │ ├── impl/ │ │ │ └── ams_impl_unexpected_default.cpp │ │ ├── kfuse/ │ │ │ └── kfuse_registers.hpp │ │ ├── libc/ │ │ │ ├── libc.c │ │ │ └── libexo_cxx.cpp │ │ ├── log/ │ │ │ └── log_api.cpp │ │ ├── pinmux/ │ │ │ └── pinmux_api.cpp │ │ ├── pkg1/ │ │ │ └── pkg1_api.cpp │ │ ├── pmc/ │ │ │ ├── pmc_api.cpp │ │ │ └── pmc_secure_scratch_test.inc │ │ ├── pmic/ │ │ │ ├── max77620.h │ │ │ ├── max7762x.h │ │ │ └── pmic_api.cpp │ │ ├── rtc/ │ │ │ ├── max77620-rtc.h │ │ │ └── rtc_api.cpp │ │ ├── se/ │ │ │ ├── se_aes.cpp │ │ │ ├── se_execute.cpp │ │ │ ├── se_execute.hpp │ │ │ ├── se_hash.cpp │ │ │ ├── se_management.cpp │ │ │ ├── se_oaep.cpp │ │ │ ├── se_registers.hpp │ │ │ ├── se_rng.cpp │ │ │ ├── se_rsa.cpp │ │ │ └── se_suspend.cpp │ │ ├── tsec/ │ │ │ ├── tsec_api.cpp │ │ │ └── tsec_registers.hpp │ │ ├── uart/ │ │ │ ├── uart_api.cpp │ │ │ └── uart_registers.hpp │ │ ├── util/ │ │ │ └── util_api.cpp │ │ └── wdt/ │ │ └── wdt_api.cpp │ ├── libmesosphere/ │ │ ├── Makefile │ │ ├── README.md │ │ ├── include/ │ │ │ ├── mesosphere/ │ │ │ │ ├── arch/ │ │ │ │ │ ├── arm/ │ │ │ │ │ │ ├── kern_generic_interrupt_controller.hpp │ │ │ │ │ │ ├── kern_k_interrupt_controller.hpp │ │ │ │ │ │ └── kern_k_memory_region_device_types.inc │ │ │ │ │ └── arm64/ │ │ │ │ │ ├── init/ │ │ │ │ │ │ ├── kern_k_init_arguments.hpp │ │ │ │ │ │ └── kern_k_init_page_table.hpp │ │ │ │ │ ├── kern_assembly_macros.h │ │ │ │ │ ├── kern_assembly_offsets.h │ │ │ │ │ ├── kern_cpu.hpp │ │ │ │ │ ├── kern_cpu_system_registers.hpp │ │ │ │ │ ├── kern_k_debug.hpp │ │ │ │ │ ├── kern_k_exception_context.hpp │ │ │ │ │ ├── kern_k_hardware_timer.hpp │ │ │ │ │ ├── kern_k_interrupt_controller.hpp │ │ │ │ │ ├── kern_k_interrupt_manager.hpp │ │ │ │ │ ├── kern_k_interrupt_name.hpp │ │ │ │ │ ├── kern_k_memory_region_device_types.inc │ │ │ │ │ ├── kern_k_page_table.hpp │ │ │ │ │ ├── kern_k_page_table_entry.hpp │ │ │ │ │ ├── kern_k_page_table_impl.hpp │ │ │ │ │ ├── kern_k_process_page_table.hpp │ │ │ │ │ ├── kern_k_slab_heap_impl.hpp │ │ │ │ │ ├── kern_k_spin_lock.hpp │ │ │ │ │ ├── kern_k_supervisor_page_table.hpp │ │ │ │ │ ├── kern_k_thread_context.hpp │ │ │ │ │ ├── kern_secure_monitor_base.hpp │ │ │ │ │ └── kern_userspace_memory_access.hpp │ │ │ │ ├── board/ │ │ │ │ │ ├── generic/ │ │ │ │ │ │ └── kern_k_device_page_table.hpp │ │ │ │ │ ├── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── kern_cpu_map.hpp │ │ │ │ │ │ ├── kern_k_device_page_table.hpp │ │ │ │ │ │ ├── kern_k_memory_layout.hpp │ │ │ │ │ │ ├── kern_k_memory_region_device_types.inc │ │ │ │ │ │ └── kern_k_system_control.hpp │ │ │ │ │ └── qemu/ │ │ │ │ │ └── virt/ │ │ │ │ │ ├── kern_cpu_map.hpp │ │ │ │ │ ├── kern_k_memory_layout.hpp │ │ │ │ │ ├── kern_k_memory_region_device_types.inc │ │ │ │ │ └── kern_k_system_control.hpp │ │ │ │ ├── init/ │ │ │ │ │ ├── kern_init_arguments_select.hpp │ │ │ │ │ ├── kern_init_elf.hpp │ │ │ │ │ ├── kern_init_elf64.hpp │ │ │ │ │ ├── kern_init_layout.hpp │ │ │ │ │ ├── kern_init_page_table_select.hpp │ │ │ │ │ └── kern_init_slab_setup.hpp │ │ │ │ ├── kern_build_config.hpp │ │ │ │ ├── kern_common.hpp │ │ │ │ ├── kern_debug_log.hpp │ │ │ │ ├── kern_initial_process.hpp │ │ │ │ ├── kern_k_address_arbiter.hpp │ │ │ │ ├── kern_k_address_space_info.hpp │ │ │ │ ├── kern_k_affinity_mask.hpp │ │ │ │ ├── kern_k_auto_object.hpp │ │ │ │ ├── kern_k_auto_object_container.hpp │ │ │ │ ├── kern_k_auto_object_impls.hpp │ │ │ │ ├── kern_k_capabilities.hpp │ │ │ │ ├── kern_k_class_token.hpp │ │ │ │ ├── kern_k_client_port.hpp │ │ │ │ ├── kern_k_client_session.hpp │ │ │ │ ├── kern_k_code_memory.hpp │ │ │ │ ├── kern_k_condition_variable.hpp │ │ │ │ ├── kern_k_current_context.hpp │ │ │ │ ├── kern_k_debug_base.hpp │ │ │ │ ├── kern_k_device_address_space.hpp │ │ │ │ ├── kern_k_dpc_manager.hpp │ │ │ │ ├── kern_k_dump_object.hpp │ │ │ │ ├── kern_k_dynamic_page_manager.hpp │ │ │ │ ├── kern_k_dynamic_resource_manager.hpp │ │ │ │ ├── kern_k_dynamic_slab_heap.hpp │ │ │ │ ├── kern_k_event.hpp │ │ │ │ ├── kern_k_event_info.hpp │ │ │ │ ├── kern_k_exception_context.hpp │ │ │ │ ├── kern_k_handle_table.hpp │ │ │ │ ├── kern_k_hardware_timer_base.hpp │ │ │ │ ├── kern_k_initial_process_reader.hpp │ │ │ │ ├── kern_k_interrupt_event.hpp │ │ │ │ ├── kern_k_interrupt_task.hpp │ │ │ │ ├── kern_k_interrupt_task_manager.hpp │ │ │ │ ├── kern_k_io_pool.hpp │ │ │ │ ├── kern_k_io_region.hpp │ │ │ │ ├── kern_k_light_client_session.hpp │ │ │ │ ├── kern_k_light_condition_variable.hpp │ │ │ │ ├── kern_k_light_lock.hpp │ │ │ │ ├── kern_k_light_server_session.hpp │ │ │ │ ├── kern_k_light_session.hpp │ │ │ │ ├── kern_k_memory_block.hpp │ │ │ │ ├── kern_k_memory_block_manager.hpp │ │ │ │ ├── kern_k_memory_layout.hpp │ │ │ │ ├── kern_k_memory_manager.hpp │ │ │ │ ├── kern_k_memory_region.hpp │ │ │ │ ├── kern_k_memory_region_type.hpp │ │ │ │ ├── kern_k_object_name.hpp │ │ │ │ ├── kern_k_page_bitmap.hpp │ │ │ │ ├── kern_k_page_buffer.hpp │ │ │ │ ├── kern_k_page_group.hpp │ │ │ │ ├── kern_k_page_heap.hpp │ │ │ │ ├── kern_k_page_table_base.hpp │ │ │ │ ├── kern_k_page_table_manager.hpp │ │ │ │ ├── kern_k_page_table_slab_heap.hpp │ │ │ │ ├── kern_k_port.hpp │ │ │ │ ├── kern_k_priority_queue.hpp │ │ │ │ ├── kern_k_process.hpp │ │ │ │ ├── kern_k_readable_event.hpp │ │ │ │ ├── kern_k_resource_limit.hpp │ │ │ │ ├── kern_k_scheduler.hpp │ │ │ │ ├── kern_k_scheduler_impls.hpp │ │ │ │ ├── kern_k_scheduler_lock.hpp │ │ │ │ ├── kern_k_scoped_lock.hpp │ │ │ │ ├── kern_k_scoped_resource_reservation.hpp │ │ │ │ ├── kern_k_scoped_scheduler_lock_and_sleep.hpp │ │ │ │ ├── kern_k_server_port.hpp │ │ │ │ ├── kern_k_server_session.hpp │ │ │ │ ├── kern_k_session.hpp │ │ │ │ ├── kern_k_session_request.hpp │ │ │ │ ├── kern_k_shared_memory.hpp │ │ │ │ ├── kern_k_shared_memory_info.hpp │ │ │ │ ├── kern_k_slab_heap.hpp │ │ │ │ ├── kern_k_spin_lock.hpp │ │ │ │ ├── kern_k_synchronization_object.hpp │ │ │ │ ├── kern_k_system_control_base.hpp │ │ │ │ ├── kern_k_system_resource.hpp │ │ │ │ ├── kern_k_target_system.hpp │ │ │ │ ├── kern_k_thread.hpp │ │ │ │ ├── kern_k_thread_context.hpp │ │ │ │ ├── kern_k_thread_local_page.hpp │ │ │ │ ├── kern_k_thread_queue.hpp │ │ │ │ ├── kern_k_timer_task.hpp │ │ │ │ ├── kern_k_trace.hpp │ │ │ │ ├── kern_k_transfer_memory.hpp │ │ │ │ ├── kern_k_typed_address.hpp │ │ │ │ ├── kern_k_unsafe_memory.hpp │ │ │ │ ├── kern_k_unused_slab_memory.hpp │ │ │ │ ├── kern_k_wait_object.hpp │ │ │ │ ├── kern_k_worker_task.hpp │ │ │ │ ├── kern_k_worker_task_manager.hpp │ │ │ │ ├── kern_kernel.hpp │ │ │ │ ├── kern_main.hpp │ │ │ │ ├── kern_panic.hpp │ │ │ │ ├── kern_select_assembly_macros.h │ │ │ │ ├── kern_select_assembly_offsets.h │ │ │ │ ├── kern_select_cpu.hpp │ │ │ │ ├── kern_select_debug.hpp │ │ │ │ ├── kern_select_device_page_table.hpp │ │ │ │ ├── kern_select_hardware_timer.hpp │ │ │ │ ├── kern_select_interrupt_controller.hpp │ │ │ │ ├── kern_select_interrupt_manager.hpp │ │ │ │ ├── kern_select_interrupt_name.hpp │ │ │ │ ├── kern_select_page_table.hpp │ │ │ │ ├── kern_select_page_table_impl.hpp │ │ │ │ ├── kern_select_system_control.hpp │ │ │ │ ├── kern_select_userspace_memory_access.hpp │ │ │ │ ├── kern_slab_helpers.hpp │ │ │ │ ├── kern_svc.hpp │ │ │ │ └── svc/ │ │ │ │ ├── kern_svc_k_user_pointer.hpp │ │ │ │ ├── kern_svc_prototypes.hpp │ │ │ │ ├── kern_svc_results.hpp │ │ │ │ └── kern_svc_tables.hpp │ │ │ └── mesosphere.hpp │ │ ├── libmesosphere.mk │ │ └── source/ │ │ ├── arch/ │ │ │ ├── arm/ │ │ │ │ ├── kern_generic_interrupt_controller.inc │ │ │ │ └── kern_k_interrupt_controller.board.generic.cpp │ │ │ └── arm64/ │ │ │ ├── kern_cpu.cpp │ │ │ ├── kern_cpu_asm.s │ │ │ ├── kern_exception_handlers.cpp │ │ │ ├── kern_k_debug.cpp │ │ │ ├── kern_k_hardware_timer.cpp │ │ │ ├── kern_k_interrupt_controller.board.generic.cpp │ │ │ ├── kern_k_interrupt_manager.cpp │ │ │ ├── kern_k_page_table.cpp │ │ │ ├── kern_k_page_table_impl.cpp │ │ │ ├── kern_k_supervisor_page_table.cpp │ │ │ ├── kern_k_thread_context.cpp │ │ │ ├── kern_panic_asm.s │ │ │ ├── kern_userspace_memory_access_asm.s │ │ │ └── svc/ │ │ │ ├── kern_svc_address_arbiter_asm.s │ │ │ ├── kern_svc_call_secure_monitor_asm.s │ │ │ ├── kern_svc_exception_asm.s │ │ │ ├── kern_svc_handlers.cpp │ │ │ ├── kern_svc_handlers_asm.s │ │ │ ├── kern_svc_light_ipc_asm.s │ │ │ └── kern_svc_tables.cpp │ │ ├── board/ │ │ │ ├── nintendo/ │ │ │ │ └── nx/ │ │ │ │ ├── kern_atomics_registers.hpp │ │ │ │ ├── kern_bpmp_api.hpp │ │ │ │ ├── kern_ictlr_registers.hpp │ │ │ │ ├── kern_k_device_page_table.cpp │ │ │ │ ├── kern_k_io_pool.board.nintendo_nx.inc │ │ │ │ ├── kern_k_sleep_manager.cpp │ │ │ │ ├── kern_k_sleep_manager.hpp │ │ │ │ ├── kern_k_sleep_manager_asm.s │ │ │ │ ├── kern_k_system_control.cpp │ │ │ │ ├── kern_lps_driver.cpp │ │ │ │ ├── kern_lps_driver.hpp │ │ │ │ ├── kern_secure_monitor.cpp │ │ │ │ ├── kern_secure_monitor.hpp │ │ │ │ └── kern_sema_registers.hpp │ │ │ └── qemu/ │ │ │ └── virt/ │ │ │ ├── kern_k_system_control.cpp │ │ │ ├── kern_secure_monitor.cpp │ │ │ └── kern_secure_monitor.hpp │ │ ├── init/ │ │ │ ├── kern_init_elf.cpp │ │ │ └── kern_init_slab_setup.cpp │ │ ├── kern_debug_log.cpp │ │ ├── kern_debug_log_impl.arch.arm64.s │ │ ├── kern_debug_log_impl.board.nintendo_nx.cpp │ │ ├── kern_debug_log_impl.board.qemu_virt.cpp │ │ ├── kern_debug_log_impl.hpp │ │ ├── kern_initial_process.cpp │ │ ├── kern_k_address_arbiter.cpp │ │ ├── kern_k_address_space_info.cpp │ │ ├── kern_k_capabilities.cpp │ │ ├── kern_k_class_token.cpp │ │ ├── kern_k_client_port.cpp │ │ ├── kern_k_client_session.cpp │ │ ├── kern_k_code_memory.cpp │ │ ├── kern_k_condition_variable.cpp │ │ ├── kern_k_debug_base.cpp │ │ ├── kern_k_device_address_space.cpp │ │ ├── kern_k_dpc_manager.cpp │ │ ├── kern_k_dump_object.cpp │ │ ├── kern_k_event.cpp │ │ ├── kern_k_handle_table.cpp │ │ ├── kern_k_initial_process_reader.cpp │ │ ├── kern_k_interrupt_event.cpp │ │ ├── kern_k_interrupt_task_manager.cpp │ │ ├── kern_k_io_pool.cpp │ │ ├── kern_k_io_pool.unsupported.inc │ │ ├── kern_k_io_region.cpp │ │ ├── kern_k_light_client_session.cpp │ │ ├── kern_k_light_condition_variable.cpp │ │ ├── kern_k_light_lock.cpp │ │ ├── kern_k_light_server_session.cpp │ │ ├── kern_k_light_session.cpp │ │ ├── kern_k_memory_block_manager.cpp │ │ ├── kern_k_memory_layout.board.nintendo_nx.cpp │ │ ├── kern_k_memory_layout.board.qemu_virt.cpp │ │ ├── kern_k_memory_layout.cpp │ │ ├── kern_k_memory_manager.cpp │ │ ├── kern_k_object_name.cpp │ │ ├── kern_k_page_group.cpp │ │ ├── kern_k_page_heap.cpp │ │ ├── kern_k_page_table_base.cpp │ │ ├── kern_k_port.cpp │ │ ├── kern_k_process.cpp │ │ ├── kern_k_readable_event.cpp │ │ ├── kern_k_resource_limit.cpp │ │ ├── kern_k_scheduler.cpp │ │ ├── kern_k_scoped_disable_dispatch.cpp │ │ ├── kern_k_server_port.cpp │ │ ├── kern_k_server_session.cpp │ │ ├── kern_k_session.cpp │ │ ├── kern_k_session_request.cpp │ │ ├── kern_k_shared_memory.cpp │ │ ├── kern_k_synchronization_object.cpp │ │ ├── kern_k_system_control_base.cpp │ │ ├── kern_k_system_resource.cpp │ │ ├── kern_k_thread.cpp │ │ ├── kern_k_thread_local_page.cpp │ │ ├── kern_k_thread_queue.cpp │ │ ├── kern_k_trace.cpp │ │ ├── kern_k_transfer_memory.cpp │ │ ├── kern_k_unused_slab_memory.cpp │ │ ├── kern_k_wait_object.cpp │ │ ├── kern_k_worker_task_manager.cpp │ │ ├── kern_kernel.cpp │ │ ├── kern_main.cpp │ │ ├── kern_panic.cpp │ │ ├── libc/ │ │ │ └── kern_cxx.cpp │ │ └── svc/ │ │ ├── kern_svc_activity.cpp │ │ ├── kern_svc_address_arbiter.cpp │ │ ├── kern_svc_address_translation.cpp │ │ ├── kern_svc_cache.cpp │ │ ├── kern_svc_code_memory.cpp │ │ ├── kern_svc_condition_variable.cpp │ │ ├── kern_svc_debug.cpp │ │ ├── kern_svc_debug_string.cpp │ │ ├── kern_svc_device_address_space.cpp │ │ ├── kern_svc_event.cpp │ │ ├── kern_svc_exception.cpp │ │ ├── kern_svc_info.cpp │ │ ├── kern_svc_insecure_memory.cpp │ │ ├── kern_svc_interrupt_event.cpp │ │ ├── kern_svc_io_pool.cpp │ │ ├── kern_svc_ipc.cpp │ │ ├── kern_svc_kernel_debug.cpp │ │ ├── kern_svc_light_ipc.cpp │ │ ├── kern_svc_lock.cpp │ │ ├── kern_svc_memory.cpp │ │ ├── kern_svc_physical_memory.cpp │ │ ├── kern_svc_port.cpp │ │ ├── kern_svc_power_management.cpp │ │ ├── kern_svc_process.cpp │ │ ├── kern_svc_process_memory.cpp │ │ ├── kern_svc_processor.cpp │ │ ├── kern_svc_query_memory.cpp │ │ ├── kern_svc_register.cpp │ │ ├── kern_svc_resource_limit.cpp │ │ ├── kern_svc_secure_monitor_call.cpp │ │ ├── kern_svc_session.cpp │ │ ├── kern_svc_shared_memory.cpp │ │ ├── kern_svc_synchronization.cpp │ │ ├── kern_svc_thread.cpp │ │ ├── kern_svc_thread_profiler.cpp │ │ ├── kern_svc_tick.cpp │ │ └── kern_svc_transfer_memory.cpp │ ├── libstratosphere/ │ │ ├── Makefile │ │ ├── README.md │ │ ├── discard-ehframe.ld │ │ ├── include/ │ │ │ ├── stratosphere/ │ │ │ │ ├── ams/ │ │ │ │ │ ├── ams_emummc_api.hpp │ │ │ │ │ ├── ams_environment.hpp │ │ │ │ │ ├── ams_exosphere_api.hpp │ │ │ │ │ ├── ams_types.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ └── ams_system_thread_definitions.hpp │ │ │ │ ├── ams.hpp │ │ │ │ ├── boot2/ │ │ │ │ │ └── boot2_api.hpp │ │ │ │ ├── boot2.hpp │ │ │ │ ├── cal/ │ │ │ │ │ └── cal_battery_api.hpp │ │ │ │ ├── cal.hpp │ │ │ │ ├── capsrv/ │ │ │ │ │ ├── capsrv_screen_shot_control_api.hpp │ │ │ │ │ ├── capsrv_screen_shot_decode_option.hpp │ │ │ │ │ └── server/ │ │ │ │ │ ├── capsrv_server_config.hpp │ │ │ │ │ └── capsrv_server_decoder_api.hpp │ │ │ │ ├── capsrv.hpp │ │ │ │ ├── cfg/ │ │ │ │ │ ├── cfg_api.hpp │ │ │ │ │ ├── cfg_locale_types.hpp │ │ │ │ │ └── cfg_types.hpp │ │ │ │ ├── cfg.hpp │ │ │ │ ├── clkrst/ │ │ │ │ │ ├── clkrst_api.hpp │ │ │ │ │ ├── clkrst_session_api.hpp │ │ │ │ │ └── clkrst_types.hpp │ │ │ │ ├── clkrst.hpp │ │ │ │ ├── cs/ │ │ │ │ │ ├── cs_audio_server.hpp │ │ │ │ │ ├── cs_command_processor.hpp │ │ │ │ │ ├── cs_hid_server.hpp │ │ │ │ │ ├── cs_remote_video_server.hpp │ │ │ │ │ └── cs_target_io_server.hpp │ │ │ │ ├── cs.hpp │ │ │ │ ├── dd/ │ │ │ │ │ ├── dd_device_address_space.hpp │ │ │ │ │ ├── dd_device_address_space_api.hpp │ │ │ │ │ ├── dd_device_address_space_common.hpp │ │ │ │ │ ├── dd_device_address_space_types.hpp │ │ │ │ │ ├── dd_io_mappings.hpp │ │ │ │ │ ├── dd_process_handle.hpp │ │ │ │ │ └── dd_types.hpp │ │ │ │ ├── dd.hpp │ │ │ │ ├── ddsf/ │ │ │ │ │ ├── ddsf_device_code_entry.hpp │ │ │ │ │ ├── ddsf_device_code_entry_manager.hpp │ │ │ │ │ ├── ddsf_event_handler_manager.hpp │ │ │ │ │ ├── ddsf_i_castable.hpp │ │ │ │ │ ├── ddsf_i_device.hpp │ │ │ │ │ ├── ddsf_i_driver.hpp │ │ │ │ │ ├── ddsf_i_event_handler.hpp │ │ │ │ │ ├── ddsf_i_session.hpp │ │ │ │ │ ├── ddsf_memory_api.hpp │ │ │ │ │ ├── ddsf_types.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── ddsf_for_each.hpp │ │ │ │ │ └── ddsf_type_tag.hpp │ │ │ │ ├── ddsf.hpp │ │ │ │ ├── diag/ │ │ │ │ │ ├── diag_abort_observer.hpp │ │ │ │ │ ├── diag_assertion_failure_handler.hpp │ │ │ │ │ ├── diag_backtrace.hpp │ │ │ │ │ ├── diag_log.hpp │ │ │ │ │ ├── diag_log_observer.hpp │ │ │ │ │ ├── diag_log_types.hpp │ │ │ │ │ ├── diag_sdk_log.hpp │ │ │ │ │ ├── diag_symbol.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── diag_backtrace_impl.os.horizon.hpp │ │ │ │ │ ├── diag_backtrace_impl.os.linux.hpp │ │ │ │ │ ├── diag_backtrace_impl.os.macos.hpp │ │ │ │ │ ├── diag_backtrace_impl.os.windows.hpp │ │ │ │ │ ├── diag_impl_build_config.hpp │ │ │ │ │ ├── diag_impl_log.hpp │ │ │ │ │ ├── diag_impl_structured_log.hpp │ │ │ │ │ ├── diag_impl_structured_sdk_log.hpp │ │ │ │ │ └── diag_utf8_util.hpp │ │ │ │ ├── diag.hpp │ │ │ │ ├── dmnt/ │ │ │ │ │ └── dmnt_cheat_types.hpp │ │ │ │ ├── dmnt.hpp │ │ │ │ ├── erpt/ │ │ │ │ │ ├── erpt_ids.autogen.hpp │ │ │ │ │ ├── erpt_multiple_category_context.hpp │ │ │ │ │ ├── erpt_types.hpp │ │ │ │ │ ├── sf/ │ │ │ │ │ │ ├── erpt_sf_i_attachment.hpp │ │ │ │ │ │ ├── erpt_sf_i_context.hpp │ │ │ │ │ │ ├── erpt_sf_i_manager.hpp │ │ │ │ │ │ ├── erpt_sf_i_report.hpp │ │ │ │ │ │ └── erpt_sf_i_session.hpp │ │ │ │ │ └── srv/ │ │ │ │ │ ├── erpt_srv_api.hpp │ │ │ │ │ └── erpt_srv_types.hpp │ │ │ │ ├── erpt.hpp │ │ │ │ ├── err/ │ │ │ │ │ ├── err_error_context.hpp │ │ │ │ │ ├── err_system_api.hpp │ │ │ │ │ └── err_types.hpp │ │ │ │ ├── err.hpp │ │ │ │ ├── fat/ │ │ │ │ │ └── fat_file_system.hpp │ │ │ │ ├── fat.hpp │ │ │ │ ├── fatal/ │ │ │ │ │ ├── fatal_types.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── fatal_i_private_service.hpp │ │ │ │ │ └── fatal_i_service.hpp │ │ │ │ ├── fatal.hpp │ │ │ │ ├── fs/ │ │ │ │ │ ├── common/ │ │ │ │ │ │ ├── fs_dbm_hierarchical_rom_file_table.hpp │ │ │ │ │ │ ├── fs_dbm_rom_key_value_storage.hpp │ │ │ │ │ │ ├── fs_dbm_rom_path_tool.hpp │ │ │ │ │ │ ├── fs_dbm_rom_types.hpp │ │ │ │ │ │ ├── fs_directory_path_parser.hpp │ │ │ │ │ │ └── fs_file_storage.hpp │ │ │ │ │ ├── fs_access_log.hpp │ │ │ │ │ ├── fs_api.hpp │ │ │ │ │ ├── fs_application.hpp │ │ │ │ │ ├── fs_bis.hpp │ │ │ │ │ ├── fs_code.hpp │ │ │ │ │ ├── fs_code_verification_data.hpp │ │ │ │ │ ├── fs_common.hpp │ │ │ │ │ ├── fs_content.hpp │ │ │ │ │ ├── fs_content_attributes.hpp │ │ │ │ │ ├── fs_content_storage.hpp │ │ │ │ │ ├── fs_content_storage_id.hpp │ │ │ │ │ ├── fs_context.hpp │ │ │ │ │ ├── fs_device_save_data.hpp │ │ │ │ │ ├── fs_directory.hpp │ │ │ │ │ ├── fs_error_info.hpp │ │ │ │ │ ├── fs_file.hpp │ │ │ │ │ ├── fs_filesystem.hpp │ │ │ │ │ ├── fs_filesystem_for_debug.hpp │ │ │ │ │ ├── fs_filesystem_utils.hpp │ │ │ │ │ ├── fs_game_card.hpp │ │ │ │ │ ├── fs_host.hpp │ │ │ │ │ ├── fs_i_buffer_manager.hpp │ │ │ │ │ ├── fs_i_event_notifier.hpp │ │ │ │ │ ├── fs_image_directory.hpp │ │ │ │ │ ├── fs_istorage.hpp │ │ │ │ │ ├── fs_memory_management.hpp │ │ │ │ │ ├── fs_memory_report_info.hpp │ │ │ │ │ ├── fs_memory_storage.hpp │ │ │ │ │ ├── fs_mmc.hpp │ │ │ │ │ ├── fs_mount.hpp │ │ │ │ │ ├── fs_operate_range.hpp │ │ │ │ │ ├── fs_path.hpp │ │ │ │ │ ├── fs_path_utility.hpp │ │ │ │ │ ├── fs_priority.hpp │ │ │ │ │ ├── fs_program_id.hpp │ │ │ │ │ ├── fs_program_index_map_info.hpp │ │ │ │ │ ├── fs_query_range.hpp │ │ │ │ │ ├── fs_read_only_filesystem.hpp │ │ │ │ │ ├── fs_remote_filesystem.hpp │ │ │ │ │ ├── fs_remote_storage.hpp │ │ │ │ │ ├── fs_result_config.hpp │ │ │ │ │ ├── fs_rights_id.hpp │ │ │ │ │ ├── fs_romfs_filesystem.hpp │ │ │ │ │ ├── fs_save_data_management.hpp │ │ │ │ │ ├── fs_save_data_transaction.hpp │ │ │ │ │ ├── fs_save_data_types.hpp │ │ │ │ │ ├── fs_sd_card.hpp │ │ │ │ │ ├── fs_signed_system_partition.hpp │ │ │ │ │ ├── fs_speed_emulation.hpp │ │ │ │ │ ├── fs_storage_type.hpp │ │ │ │ │ ├── fs_substorage.hpp │ │ │ │ │ ├── fs_system_data.hpp │ │ │ │ │ ├── fs_system_save_data.hpp │ │ │ │ │ ├── fsa/ │ │ │ │ │ │ ├── fs_idirectory.hpp │ │ │ │ │ │ ├── fs_ifile.hpp │ │ │ │ │ │ ├── fs_ifilesystem.hpp │ │ │ │ │ │ └── fs_registrar.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── fs_access_log_impl.hpp │ │ │ │ │ ├── fs_common_mount_name.hpp │ │ │ │ │ ├── fs_data.hpp │ │ │ │ │ ├── fs_filesystem_proxy_type.hpp │ │ │ │ │ ├── fs_fs_inline_context_utils.hpp │ │ │ │ │ ├── fs_hash_generator_factory_selector.hpp │ │ │ │ │ ├── fs_newable.hpp │ │ │ │ │ ├── fs_priority_utils.hpp │ │ │ │ │ ├── fs_result_utils.hpp │ │ │ │ │ ├── fs_service_name.hpp │ │ │ │ │ └── fs_storage_service_object_adapter.hpp │ │ │ │ ├── fs.hpp │ │ │ │ ├── fssrv/ │ │ │ │ │ ├── fscreator/ │ │ │ │ │ │ ├── fssrv_local_file_system_creator.hpp │ │ │ │ │ │ ├── fssrv_partition_file_system_creator.hpp │ │ │ │ │ │ ├── fssrv_rom_file_system_creator.hpp │ │ │ │ │ │ ├── fssrv_storage_on_nca_creator.hpp │ │ │ │ │ │ └── fssrv_subdirectory_file_system_creator.hpp │ │ │ │ │ ├── fssrv_file_system_proxy_api.hpp │ │ │ │ │ ├── fssrv_file_system_proxy_impl.hpp │ │ │ │ │ ├── fssrv_file_system_proxy_server_session_resource_manager.hpp │ │ │ │ │ ├── fssrv_i_file_system_creator.hpp │ │ │ │ │ ├── fssrv_interface_adapters.hpp │ │ │ │ │ ├── fssrv_memory_resource_from_exp_heap.hpp │ │ │ │ │ ├── fssrv_memory_resource_from_standard_allocator.hpp │ │ │ │ │ ├── fssrv_nca_crypto_configuration.hpp │ │ │ │ │ ├── fssrv_nca_file_system_service_impl.hpp │ │ │ │ │ ├── fssrv_program_registry_impl.hpp │ │ │ │ │ ├── fssrv_program_registry_service.hpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── fssrv_access_control.hpp │ │ │ │ │ │ ├── fssrv_access_control_bits.hpp │ │ │ │ │ │ ├── fssrv_external_key_manager.hpp │ │ │ │ │ │ ├── fssrv_file_system_proxy_service_object.hpp │ │ │ │ │ │ └── fssrv_impl_program_index_map_info_manager.hpp │ │ │ │ │ ├── interface_adapters/ │ │ │ │ │ │ ├── fssrv_filesystem_interface_adapter.hpp │ │ │ │ │ │ └── fssrv_storage_interface_adapter.hpp │ │ │ │ │ └── sf/ │ │ │ │ │ ├── fssrv_sf_i_device_operator.hpp │ │ │ │ │ ├── fssrv_sf_i_event_notifier.hpp │ │ │ │ │ ├── fssrv_sf_i_file_system_proxy.hpp │ │ │ │ │ ├── fssrv_sf_i_file_system_proxy_for_loader.hpp │ │ │ │ │ ├── fssrv_sf_i_program_registry.hpp │ │ │ │ │ ├── fssrv_sf_idirectory.hpp │ │ │ │ │ ├── fssrv_sf_ifile.hpp │ │ │ │ │ ├── fssrv_sf_ifilesystem.hpp │ │ │ │ │ ├── fssrv_sf_istorage.hpp │ │ │ │ │ └── fssrv_sf_path.hpp │ │ │ │ ├── fssrv.hpp │ │ │ │ ├── fssystem/ │ │ │ │ │ ├── buffers/ │ │ │ │ │ │ ├── fssystem_buffer_manager_utils.hpp │ │ │ │ │ │ ├── fssystem_file_system_buddy_heap.hpp │ │ │ │ │ │ └── fssystem_file_system_buffer_manager.hpp │ │ │ │ │ ├── fssystem_aes_ctr_counter_extended_storage.hpp │ │ │ │ │ ├── fssystem_aes_ctr_storage.hpp │ │ │ │ │ ├── fssystem_aes_ctr_storage_external.hpp │ │ │ │ │ ├── fssystem_aes_xts_storage.hpp │ │ │ │ │ ├── fssystem_aes_xts_storage_external.hpp │ │ │ │ │ ├── fssystem_alignment_matching_storage.hpp │ │ │ │ │ ├── fssystem_alignment_matching_storage_impl.hpp │ │ │ │ │ ├── fssystem_allocator_utility.hpp │ │ │ │ │ ├── fssystem_asynchronous_access.hpp │ │ │ │ │ ├── fssystem_bitmap_utils.hpp │ │ │ │ │ ├── fssystem_block_cache_buffered_storage.hpp │ │ │ │ │ ├── fssystem_bucket_tree.hpp │ │ │ │ │ ├── fssystem_bucket_tree_template_impl.hpp │ │ │ │ │ ├── fssystem_bucket_tree_utils.hpp │ │ │ │ │ ├── fssystem_buffered_storage.hpp │ │ │ │ │ ├── fssystem_compressed_storage.hpp │ │ │ │ │ ├── fssystem_compression_common.hpp │ │ │ │ │ ├── fssystem_compression_configuration.hpp │ │ │ │ │ ├── fssystem_crypto_configuration.hpp │ │ │ │ │ ├── fssystem_directory_redirection_filesystem.hpp │ │ │ │ │ ├── fssystem_directory_savedata_filesystem.hpp │ │ │ │ │ ├── fssystem_external_code.hpp │ │ │ │ │ ├── fssystem_file_system_proxy_api.hpp │ │ │ │ │ ├── fssystem_forwarding_file_system.hpp │ │ │ │ │ ├── fssystem_hierarchical_integrity_verification_storage.hpp │ │ │ │ │ ├── fssystem_i_hash_256_generator.hpp │ │ │ │ │ ├── fssystem_indirect_storage.hpp │ │ │ │ │ ├── fssystem_indirect_storage_template_impl.hpp │ │ │ │ │ ├── fssystem_integrity_romfs_storage.hpp │ │ │ │ │ ├── fssystem_integrity_verification_storage.hpp │ │ │ │ │ ├── fssystem_local_file_system.hpp │ │ │ │ │ ├── fssystem_nca_file_system_driver.hpp │ │ │ │ │ ├── fssystem_nca_header.hpp │ │ │ │ │ ├── fssystem_partition_file_system.hpp │ │ │ │ │ ├── fssystem_partition_file_system_meta.hpp │ │ │ │ │ ├── fssystem_pimpl.hpp │ │ │ │ │ ├── fssystem_pooled_buffer.hpp │ │ │ │ │ ├── fssystem_romfs_file_system.hpp │ │ │ │ │ ├── fssystem_service_context.hpp │ │ │ │ │ ├── fssystem_sha_hash_generator.hpp │ │ │ │ │ ├── fssystem_sparse_storage.hpp │ │ │ │ │ ├── fssystem_speed_emulation_configuration.hpp │ │ │ │ │ ├── fssystem_subdirectory_filesystem.hpp │ │ │ │ │ ├── fssystem_switch_storage.hpp │ │ │ │ │ ├── fssystem_thread_priority_changer.hpp │ │ │ │ │ ├── fssystem_utility.hpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── fssystem_block_cache_manager.hpp │ │ │ │ │ └── save/ │ │ │ │ │ ├── fssystem_i_save_file.hpp │ │ │ │ │ └── fssystem_i_save_file_system_driver.hpp │ │ │ │ ├── fssystem.hpp │ │ │ │ ├── gc/ │ │ │ │ │ ├── gc.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── gc_embedded_data_holder.hpp │ │ │ │ │ ├── gc_gc_crypto.hpp │ │ │ │ │ └── gc_types.hpp │ │ │ │ ├── gc.hpp │ │ │ │ ├── gpio/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ ├── board/ │ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ │ └── gpio_driver_api.hpp │ │ │ │ │ │ ├── gpio_driver_client_api.hpp │ │ │ │ │ │ ├── gpio_driver_service_api.hpp │ │ │ │ │ │ ├── gpio_i_gpio_driver.hpp │ │ │ │ │ │ ├── gpio_pad.hpp │ │ │ │ │ │ ├── gpio_pad_accessor.hpp │ │ │ │ │ │ ├── gpio_select_driver_api.hpp │ │ │ │ │ │ └── impl/ │ │ │ │ │ │ ├── gpio_event_holder.hpp │ │ │ │ │ │ └── gpio_pad_session_impl.hpp │ │ │ │ │ ├── gpio_api.hpp │ │ │ │ │ ├── gpio_pad_api.hpp │ │ │ │ │ ├── gpio_pad_name.board.nintendo_nx.hpp │ │ │ │ │ ├── gpio_pad_name.generic.hpp │ │ │ │ │ ├── gpio_select_pad_name.hpp │ │ │ │ │ ├── gpio_types.hpp │ │ │ │ │ ├── server/ │ │ │ │ │ │ └── gpio_server_api.hpp │ │ │ │ │ └── sf/ │ │ │ │ │ ├── gpio_sf_i_manager.hpp │ │ │ │ │ └── gpio_sf_i_pad_session.hpp │ │ │ │ ├── gpio.hpp │ │ │ │ ├── hid/ │ │ │ │ │ └── hid_api.hpp │ │ │ │ ├── hid.hpp │ │ │ │ ├── hos/ │ │ │ │ │ ├── hos_stratosphere_api.hpp │ │ │ │ │ ├── hos_types.hpp │ │ │ │ │ └── hos_version_api.hpp │ │ │ │ ├── hos.hpp │ │ │ │ ├── htc/ │ │ │ │ │ ├── server/ │ │ │ │ │ │ ├── htc_htcmisc_channel_ids.hpp │ │ │ │ │ │ └── htc_htcmisc_hipc_server.hpp │ │ │ │ │ └── tenv/ │ │ │ │ │ ├── htc_tenv.hpp │ │ │ │ │ ├── htc_tenv_i_service.hpp │ │ │ │ │ ├── htc_tenv_i_service_manager.hpp │ │ │ │ │ ├── htc_tenv_service_manager.hpp │ │ │ │ │ └── htc_tenv_types.hpp │ │ │ │ ├── htc.hpp │ │ │ │ ├── htcfs/ │ │ │ │ │ └── htcfs_hipc_server.hpp │ │ │ │ ├── htcfs.hpp │ │ │ │ ├── htclow/ │ │ │ │ │ ├── htclow_channel_types.hpp │ │ │ │ │ ├── htclow_manager_holder.hpp │ │ │ │ │ ├── htclow_module_types.hpp │ │ │ │ │ ├── htclow_types.hpp │ │ │ │ │ └── impl/ │ │ │ │ │ └── htclow_internal_types.hpp │ │ │ │ ├── htclow.hpp │ │ │ │ ├── htcs/ │ │ │ │ │ ├── htcs_api.hpp │ │ │ │ │ ├── htcs_socket.hpp │ │ │ │ │ ├── htcs_types.hpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── htcs_channel_ids.hpp │ │ │ │ │ │ └── htcs_manager_holder.hpp │ │ │ │ │ └── server/ │ │ │ │ │ └── htcs_hipc_server.hpp │ │ │ │ ├── htcs.hpp │ │ │ │ ├── i2c/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ ├── board/ │ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ │ └── i2c_driver_api.hpp │ │ │ │ │ │ ├── i2c_bus_api.hpp │ │ │ │ │ │ ├── i2c_driver_client_api.hpp │ │ │ │ │ │ ├── i2c_driver_service_api.hpp │ │ │ │ │ │ ├── i2c_i2c_device_property.hpp │ │ │ │ │ │ ├── i2c_i_i2c_driver.hpp │ │ │ │ │ │ ├── i2c_select_driver_api.hpp │ │ │ │ │ │ └── impl/ │ │ │ │ │ │ └── i2c_i2c_session_impl.hpp │ │ │ │ │ ├── i2c_api.hpp │ │ │ │ │ ├── i2c_bus_api.hpp │ │ │ │ │ ├── i2c_command_list_formatter.hpp │ │ │ │ │ ├── i2c_device_name.board.nintendo_nx.hpp │ │ │ │ │ ├── i2c_device_name.generic.hpp │ │ │ │ │ ├── i2c_register_accessor.hpp │ │ │ │ │ ├── i2c_select_device_name.hpp │ │ │ │ │ ├── i2c_types.hpp │ │ │ │ │ ├── server/ │ │ │ │ │ │ └── i2c_server_api.hpp │ │ │ │ │ └── sf/ │ │ │ │ │ ├── i2c_sf_i_manager.hpp │ │ │ │ │ └── i2c_sf_i_session.hpp │ │ │ │ ├── i2c.hpp │ │ │ │ ├── init/ │ │ │ │ │ └── init_malloc.hpp │ │ │ │ ├── init.hpp │ │ │ │ ├── kvdb/ │ │ │ │ │ ├── kvdb_archive.hpp │ │ │ │ │ ├── kvdb_auto_buffer.hpp │ │ │ │ │ ├── kvdb_bounded_string.hpp │ │ │ │ │ ├── kvdb_file_key_value_cache.hpp │ │ │ │ │ ├── kvdb_file_key_value_store.hpp │ │ │ │ │ └── kvdb_memory_key_value_store.hpp │ │ │ │ ├── kvdb.hpp │ │ │ │ ├── ldr/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── ldr_debug_monitor_interface.hpp │ │ │ │ │ │ ├── ldr_process_manager_interface.hpp │ │ │ │ │ │ └── ldr_shell_interface.hpp │ │ │ │ │ ├── ldr_pm_api.hpp │ │ │ │ │ ├── ldr_shell_api.hpp │ │ │ │ │ └── ldr_types.hpp │ │ │ │ ├── ldr.hpp │ │ │ │ ├── lm/ │ │ │ │ │ ├── lm_api.hpp │ │ │ │ │ ├── lm_log_getter.hpp │ │ │ │ │ └── lm_types.hpp │ │ │ │ ├── lm.hpp │ │ │ │ ├── lmem/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── lmem_impl_common.hpp │ │ │ │ │ ├── lmem_common.hpp │ │ │ │ │ ├── lmem_exp_heap.hpp │ │ │ │ │ └── lmem_unit_heap.hpp │ │ │ │ ├── lmem.hpp │ │ │ │ ├── lr/ │ │ │ │ │ ├── lr_add_on_content_location_resolver.hpp │ │ │ │ │ ├── lr_api.hpp │ │ │ │ │ ├── lr_i_add_on_content_location_resolver.hpp │ │ │ │ │ ├── lr_i_location_resolver.hpp │ │ │ │ │ ├── lr_i_location_resolver_manager.hpp │ │ │ │ │ ├── lr_i_registered_location_resolver.hpp │ │ │ │ │ ├── lr_location_resolver.hpp │ │ │ │ │ ├── lr_location_resolver_manager_impl.hpp │ │ │ │ │ ├── lr_registered_location_resolver.hpp │ │ │ │ │ └── lr_types.hpp │ │ │ │ ├── lr.hpp │ │ │ │ ├── mem/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── heap/ │ │ │ │ │ │ │ ├── mem_impl_heap_cached_heap.hpp │ │ │ │ │ │ │ └── mem_impl_heap_central_heap.hpp │ │ │ │ │ │ ├── mem_impl_common.hpp │ │ │ │ │ │ ├── mem_impl_declarations.hpp │ │ │ │ │ │ └── mem_impl_heap.hpp │ │ │ │ │ └── mem_standard_allocator.hpp │ │ │ │ ├── mem.hpp │ │ │ │ ├── mitm/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── mitm_pm_interface.hpp │ │ │ │ │ └── mitm_pm_api.hpp │ │ │ │ ├── mitm.hpp │ │ │ │ ├── ncm/ │ │ │ │ │ ├── ncm_api.hpp │ │ │ │ │ ├── ncm_auto_buffer.hpp │ │ │ │ │ ├── ncm_bounded_map.hpp │ │ │ │ │ ├── ncm_content_id.hpp │ │ │ │ │ ├── ncm_content_id_utils.hpp │ │ │ │ │ ├── ncm_content_info.hpp │ │ │ │ │ ├── ncm_content_info_data.hpp │ │ │ │ │ ├── ncm_content_info_utils.hpp │ │ │ │ │ ├── ncm_content_management_utils.hpp │ │ │ │ │ ├── ncm_content_manager_config.hpp │ │ │ │ │ ├── ncm_content_manager_impl.hpp │ │ │ │ │ ├── ncm_content_meta.hpp │ │ │ │ │ ├── ncm_content_meta_database.hpp │ │ │ │ │ ├── ncm_content_meta_extended_data.hpp │ │ │ │ │ ├── ncm_content_meta_id.hpp │ │ │ │ │ ├── ncm_content_meta_key.hpp │ │ │ │ │ ├── ncm_content_meta_platform.hpp │ │ │ │ │ ├── ncm_content_meta_type.hpp │ │ │ │ │ ├── ncm_content_meta_utils.hpp │ │ │ │ │ ├── ncm_content_storage.hpp │ │ │ │ │ ├── ncm_content_type.hpp │ │ │ │ │ ├── ncm_data_id.hpp │ │ │ │ │ ├── ncm_firmware_variation.hpp │ │ │ │ │ ├── ncm_i_content_manager.hpp │ │ │ │ │ ├── ncm_i_content_meta_database.hpp │ │ │ │ │ ├── ncm_i_content_storage.hpp │ │ │ │ │ ├── ncm_ids.hpp │ │ │ │ │ ├── ncm_install_progress.hpp │ │ │ │ │ ├── ncm_install_task_base.hpp │ │ │ │ │ ├── ncm_install_task_data.hpp │ │ │ │ │ ├── ncm_install_task_occupied_size.hpp │ │ │ │ │ ├── ncm_integrated_content_meta_database_impl.hpp │ │ │ │ │ ├── ncm_integrated_content_storage_impl.hpp │ │ │ │ │ ├── ncm_integrated_list.hpp │ │ │ │ │ ├── ncm_make_path.hpp │ │ │ │ │ ├── ncm_mapped_memory.hpp │ │ │ │ │ ├── ncm_max_count.hpp │ │ │ │ │ ├── ncm_memory_report.hpp │ │ │ │ │ ├── ncm_package_install_task.hpp │ │ │ │ │ ├── ncm_package_install_task_base.hpp │ │ │ │ │ ├── ncm_package_system_downgrade_task.hpp │ │ │ │ │ ├── ncm_package_system_update_task.hpp │ │ │ │ │ ├── ncm_path.hpp │ │ │ │ │ ├── ncm_path_string.hpp │ │ │ │ │ ├── ncm_placeholder_id.hpp │ │ │ │ │ ├── ncm_program_id.hpp │ │ │ │ │ ├── ncm_program_location.hpp │ │ │ │ │ ├── ncm_registered_host_content.hpp │ │ │ │ │ ├── ncm_rights_id.hpp │ │ │ │ │ ├── ncm_rights_id_cache.hpp │ │ │ │ │ ├── ncm_storage_id.hpp │ │ │ │ │ ├── ncm_storage_utils.hpp │ │ │ │ │ ├── ncm_submission_package_install_task.hpp │ │ │ │ │ ├── ncm_system_content_meta_id.hpp │ │ │ │ │ └── ncm_system_update_task_apply_info.hpp │ │ │ │ ├── ncm.hpp │ │ │ │ ├── nim/ │ │ │ │ │ ├── nim_network_install_manager_api.hpp │ │ │ │ │ ├── nim_system_update_task_id.hpp │ │ │ │ │ └── nim_task_id_common.hpp │ │ │ │ ├── nim.hpp │ │ │ │ ├── ns/ │ │ │ │ │ └── impl/ │ │ │ │ │ └── ns_i_async.hpp │ │ │ │ ├── ns.hpp │ │ │ │ ├── nsd/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── device/ │ │ │ │ │ │ └── nsd_device.hpp │ │ │ │ │ └── nsd_types.hpp │ │ │ │ ├── nsd.hpp │ │ │ │ ├── os/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── os_internal_busy_mutex.hpp │ │ │ │ │ │ ├── os_internal_busy_mutex_impl.os.generic.hpp │ │ │ │ │ │ ├── os_internal_busy_mutex_impl.os.horizon.hpp │ │ │ │ │ │ ├── os_internal_condition_variable.hpp │ │ │ │ │ │ ├── os_internal_condition_variable_impl.os.horizon.hpp │ │ │ │ │ │ ├── os_internal_condition_variable_impl.os.windows.hpp │ │ │ │ │ │ ├── os_internal_condition_variable_impl.pthread.hpp │ │ │ │ │ │ ├── os_internal_critical_section.hpp │ │ │ │ │ │ ├── os_internal_critical_section_impl.os.horizon.hpp │ │ │ │ │ │ ├── os_internal_critical_section_impl.os.windows.hpp │ │ │ │ │ │ ├── os_internal_critical_section_impl.pthread.hpp │ │ │ │ │ │ ├── os_internal_light_event.hpp │ │ │ │ │ │ ├── os_internal_light_event_impl.os.generic.hpp │ │ │ │ │ │ ├── os_internal_light_event_impl.os.horizon.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.horizon.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.linux.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.macos.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.windows.hpp │ │ │ │ │ │ ├── os_internal_rw_busy_mutex_value.hpp │ │ │ │ │ │ ├── os_memory_fence_api.os.generic.hpp │ │ │ │ │ │ └── os_memory_fence_api.os.horizon.hpp │ │ │ │ │ ├── os_argument.hpp │ │ │ │ │ ├── os_barrier.hpp │ │ │ │ │ ├── os_barrier_api.hpp │ │ │ │ │ ├── os_barrier_types.hpp │ │ │ │ │ ├── os_busy_mutex.hpp │ │ │ │ │ ├── os_busy_mutex_api.hpp │ │ │ │ │ ├── os_busy_mutex_types.hpp │ │ │ │ │ ├── os_cache.hpp │ │ │ │ │ ├── os_common_config.hpp │ │ │ │ │ ├── os_common_types.hpp │ │ │ │ │ ├── os_condition_variable.hpp │ │ │ │ │ ├── os_condition_variable_api.hpp │ │ │ │ │ ├── os_condition_variable_common.hpp │ │ │ │ │ ├── os_condition_variable_types.hpp │ │ │ │ │ ├── os_debug.hpp │ │ │ │ │ ├── os_debug_api.hpp │ │ │ │ │ ├── os_debug_types.hpp │ │ │ │ │ ├── os_event.hpp │ │ │ │ │ ├── os_event_api.hpp │ │ │ │ │ ├── os_event_common.hpp │ │ │ │ │ ├── os_event_types.hpp │ │ │ │ │ ├── os_insecure_memory_api.hpp │ │ │ │ │ ├── os_interrupt_event.hpp │ │ │ │ │ ├── os_interrupt_event_api.hpp │ │ │ │ │ ├── os_interrupt_event_common.hpp │ │ │ │ │ ├── os_interrupt_event_types.hpp │ │ │ │ │ ├── os_io_region.hpp │ │ │ │ │ ├── os_io_region_api.hpp │ │ │ │ │ ├── os_io_region_types.hpp │ │ │ │ │ ├── os_light_event.hpp │ │ │ │ │ ├── os_light_event_api.hpp │ │ │ │ │ ├── os_light_event_types.hpp │ │ │ │ │ ├── os_light_message_queue.hpp │ │ │ │ │ ├── os_light_message_queue_api.hpp │ │ │ │ │ ├── os_light_message_queue_types.hpp │ │ │ │ │ ├── os_light_semaphore.hpp │ │ │ │ │ ├── os_light_semaphore_api.hpp │ │ │ │ │ ├── os_light_semaphore_types.hpp │ │ │ │ │ ├── os_memory_attribute.hpp │ │ │ │ │ ├── os_memory_common.hpp │ │ │ │ │ ├── os_memory_fence.hpp │ │ │ │ │ ├── os_memory_fence_api.hpp │ │ │ │ │ ├── os_memory_heap.hpp │ │ │ │ │ ├── os_memory_heap_api.hpp │ │ │ │ │ ├── os_memory_heap_common.hpp │ │ │ │ │ ├── os_memory_permission.hpp │ │ │ │ │ ├── os_message_queue.hpp │ │ │ │ │ ├── os_message_queue_api.hpp │ │ │ │ │ ├── os_message_queue_common.hpp │ │ │ │ │ ├── os_message_queue_types.hpp │ │ │ │ │ ├── os_multiple_wait.hpp │ │ │ │ │ ├── os_multiple_wait_api.hpp │ │ │ │ │ ├── os_multiple_wait_types.hpp │ │ │ │ │ ├── os_multiple_wait_utils.hpp │ │ │ │ │ ├── os_mutex.hpp │ │ │ │ │ ├── os_mutex_api.hpp │ │ │ │ │ ├── os_mutex_common.hpp │ │ │ │ │ ├── os_mutex_types.hpp │ │ │ │ │ ├── os_native_handle.hpp │ │ │ │ │ ├── os_native_handle_api.hpp │ │ │ │ │ ├── os_native_handle_types.hpp │ │ │ │ │ ├── os_process_code_memory_api.hpp │ │ │ │ │ ├── os_process_handle_api.hpp │ │ │ │ │ ├── os_process_memory_api.hpp │ │ │ │ │ ├── os_random.hpp │ │ │ │ │ ├── os_rw_busy_mutex.hpp │ │ │ │ │ ├── os_rw_busy_mutex_api.hpp │ │ │ │ │ ├── os_rw_busy_mutex_types.hpp │ │ │ │ │ ├── os_rw_lock.hpp │ │ │ │ │ ├── os_rw_lock_api.hpp │ │ │ │ │ ├── os_rw_lock_common.hpp │ │ │ │ │ ├── os_rw_lock_types.hpp │ │ │ │ │ ├── os_sdk_condition_variable.hpp │ │ │ │ │ ├── os_sdk_mutex.hpp │ │ │ │ │ ├── os_sdk_recursive_mutex.hpp │ │ │ │ │ ├── os_sdk_reply_and_receive.hpp │ │ │ │ │ ├── os_sdk_thread_api.hpp │ │ │ │ │ ├── os_sdk_thread_info.hpp │ │ │ │ │ ├── os_sdk_thread_info_api.hpp │ │ │ │ │ ├── os_sdk_thread_info_types.hpp │ │ │ │ │ ├── os_sdk_thread_local_storage.hpp │ │ │ │ │ ├── os_sdk_thread_local_storage_api.hpp │ │ │ │ │ ├── os_sdk_thread_types.hpp │ │ │ │ │ ├── os_semaphore.hpp │ │ │ │ │ ├── os_semaphore_api.hpp │ │ │ │ │ ├── os_semaphore_types.hpp │ │ │ │ │ ├── os_shared_memory.hpp │ │ │ │ │ ├── os_shared_memory_api.hpp │ │ │ │ │ ├── os_shared_memory_types.hpp │ │ │ │ │ ├── os_system_event.hpp │ │ │ │ │ ├── os_system_event_api.hpp │ │ │ │ │ ├── os_system_event_types.hpp │ │ │ │ │ ├── os_thread.hpp │ │ │ │ │ ├── os_thread_api.hpp │ │ │ │ │ ├── os_thread_common.hpp │ │ │ │ │ ├── os_thread_local_storage.hpp │ │ │ │ │ ├── os_thread_local_storage_api.hpp │ │ │ │ │ ├── os_thread_local_storage_common.hpp │ │ │ │ │ ├── os_thread_types.hpp │ │ │ │ │ ├── os_tick.hpp │ │ │ │ │ ├── os_timer_event.hpp │ │ │ │ │ ├── os_timer_event_api.hpp │ │ │ │ │ ├── os_timer_event_types.hpp │ │ │ │ │ ├── os_transfer_memory.hpp │ │ │ │ │ ├── os_transfer_memory_api.hpp │ │ │ │ │ ├── os_transfer_memory_types.hpp │ │ │ │ │ ├── os_unsafe_memory_api.hpp │ │ │ │ │ ├── os_virtual_address_memory.hpp │ │ │ │ │ ├── os_virtual_address_memory_api.hpp │ │ │ │ │ ├── os_virtual_address_memory_common.hpp │ │ │ │ │ └── os_virtual_address_memory_types.hpp │ │ │ │ ├── os.hpp │ │ │ │ ├── osdbg/ │ │ │ │ │ ├── osdbg_thread.hpp │ │ │ │ │ ├── osdbg_thread_api.hpp │ │ │ │ │ ├── osdbg_thread_api_impl.hpp │ │ │ │ │ └── osdbg_thread_types.hpp │ │ │ │ ├── osdbg.hpp │ │ │ │ ├── patcher/ │ │ │ │ │ └── patcher_api.hpp │ │ │ │ ├── patcher.hpp │ │ │ │ ├── pcv/ │ │ │ │ │ ├── pcv_api.hpp │ │ │ │ │ └── pcv_types.hpp │ │ │ │ ├── pcv.hpp │ │ │ │ ├── pgl/ │ │ │ │ │ ├── pgl_event_observer.hpp │ │ │ │ │ ├── pgl_shell_api.hpp │ │ │ │ │ ├── pgl_types.hpp │ │ │ │ │ ├── sf/ │ │ │ │ │ │ ├── pgl_sf_i_event_observer.hpp │ │ │ │ │ │ └── pgl_sf_i_shell_interface.hpp │ │ │ │ │ ├── srv/ │ │ │ │ │ │ ├── pgl_srv_api.hpp │ │ │ │ │ │ └── pgl_srv_shell_interface.hpp │ │ │ │ │ └── tipc/ │ │ │ │ │ ├── pgl_tipc_i_event_observer.hpp │ │ │ │ │ └── pgl_tipc_i_shell_interface.hpp │ │ │ │ ├── pgl.hpp │ │ │ │ ├── pinmux/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ └── pinmux_driver_api.hpp │ │ │ │ │ └── pinmux_api.hpp │ │ │ │ ├── pinmux.hpp │ │ │ │ ├── pm/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── pm_boot_mode_interface.hpp │ │ │ │ │ │ ├── pm_debug_monitor_interface.hpp │ │ │ │ │ │ ├── pm_information_interface.hpp │ │ │ │ │ │ └── pm_shell_interface.hpp │ │ │ │ │ ├── pm_boot_mode_api.hpp │ │ │ │ │ ├── pm_dmnt_api.hpp │ │ │ │ │ ├── pm_info_api.hpp │ │ │ │ │ ├── pm_shell_api.hpp │ │ │ │ │ └── pm_types.hpp │ │ │ │ ├── pm.hpp │ │ │ │ ├── powctl/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ │ ├── powctl_charge_arbiter.hpp │ │ │ │ │ │ │ ├── powctl_charger_parameters.board.nintendo_nx.hpp │ │ │ │ │ │ │ ├── powctl_charger_parameters.generic.hpp │ │ │ │ │ │ │ └── powctl_select_charger_parameters.hpp │ │ │ │ │ │ └── powctl_driver_api.hpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── powctl_battery_charge_percentage.hpp │ │ │ │ │ ├── powctl_battery_api.hpp │ │ │ │ │ ├── powctl_charger_api.hpp │ │ │ │ │ ├── powctl_devices.board.nintendo_nx.hpp │ │ │ │ │ ├── powctl_select_devices.hpp │ │ │ │ │ ├── powctl_session_api.hpp │ │ │ │ │ └── powctl_types.hpp │ │ │ │ ├── powctl.hpp │ │ │ │ ├── psc/ │ │ │ │ │ ├── psc_pm_module.hpp │ │ │ │ │ ├── psc_pm_module.os.generic.hpp │ │ │ │ │ ├── psc_pm_module.os.horizon.hpp │ │ │ │ │ ├── psc_pm_module_id.hpp │ │ │ │ │ ├── psc_types.hpp │ │ │ │ │ └── sf/ │ │ │ │ │ ├── psc_sf_i_pm_module.hpp │ │ │ │ │ └── psc_sf_i_pm_service.hpp │ │ │ │ ├── psc.hpp │ │ │ │ ├── pwm/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ ├── board/ │ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ │ └── pwm_driver_api.hpp │ │ │ │ │ │ ├── pwm_channel_api.hpp │ │ │ │ │ │ ├── pwm_driver_client_api.hpp │ │ │ │ │ │ ├── pwm_driver_service_api.hpp │ │ │ │ │ │ ├── pwm_i_pwm_device.hpp │ │ │ │ │ │ ├── pwm_i_pwm_driver.hpp │ │ │ │ │ │ └── pwm_select_driver_api.hpp │ │ │ │ │ ├── pwm_api.hpp │ │ │ │ │ ├── pwm_channel_api.hpp │ │ │ │ │ ├── pwm_channel_name.board.nintendo_nx.hpp │ │ │ │ │ ├── pwm_channel_name.generic.hpp │ │ │ │ │ ├── pwm_select_channel_name.hpp │ │ │ │ │ ├── pwm_types.hpp │ │ │ │ │ ├── server/ │ │ │ │ │ │ └── pwm_server_api.hpp │ │ │ │ │ └── sf/ │ │ │ │ │ ├── pwm_sf_i_channel_session.hpp │ │ │ │ │ └── pwm_sf_i_manager.hpp │ │ │ │ ├── pwm.hpp │ │ │ │ ├── rapidjson/ │ │ │ │ │ ├── allocators.h │ │ │ │ │ ├── cursorstreamwrapper.h │ │ │ │ │ ├── document.h │ │ │ │ │ ├── encodedstream.h │ │ │ │ │ ├── encodings.h │ │ │ │ │ ├── error/ │ │ │ │ │ │ ├── en.h │ │ │ │ │ │ └── error.h │ │ │ │ │ ├── filereadstream.h │ │ │ │ │ ├── filewritestream.h │ │ │ │ │ ├── fwd.h │ │ │ │ │ ├── internal/ │ │ │ │ │ │ ├── biginteger.h │ │ │ │ │ │ ├── clzll.h │ │ │ │ │ │ ├── diyfp.h │ │ │ │ │ │ ├── dtoa.h │ │ │ │ │ │ ├── ieee754.h │ │ │ │ │ │ ├── itoa.h │ │ │ │ │ │ ├── meta.h │ │ │ │ │ │ ├── pow10.h │ │ │ │ │ │ ├── regex.h │ │ │ │ │ │ ├── stack.h │ │ │ │ │ │ ├── strfunc.h │ │ │ │ │ │ ├── strtod.h │ │ │ │ │ │ └── swap.h │ │ │ │ │ ├── istreamwrapper.h │ │ │ │ │ ├── memorybuffer.h │ │ │ │ │ ├── memorystream.h │ │ │ │ │ ├── msinttypes/ │ │ │ │ │ │ ├── inttypes.h │ │ │ │ │ │ └── stdint.h │ │ │ │ │ ├── ostreamwrapper.h │ │ │ │ │ ├── pointer.h │ │ │ │ │ ├── prettywriter.h │ │ │ │ │ ├── rapidjson.h │ │ │ │ │ ├── reader.h │ │ │ │ │ ├── schema.h │ │ │ │ │ ├── stream.h │ │ │ │ │ ├── stringbuffer.h │ │ │ │ │ └── writer.h │ │ │ │ ├── rapidjson.hpp │ │ │ │ ├── regulator/ │ │ │ │ │ ├── regulator_api.hpp │ │ │ │ │ ├── regulator_session_api.hpp │ │ │ │ │ └── regulator_types.hpp │ │ │ │ ├── regulator.hpp │ │ │ │ ├── ro/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── ro_debug_monitor_interface.hpp │ │ │ │ │ │ ├── ro_ro_exception_info.hpp │ │ │ │ │ │ └── ro_ro_interface.hpp │ │ │ │ │ └── ro_types.hpp │ │ │ │ ├── ro.hpp │ │ │ │ ├── rocrt/ │ │ │ │ │ └── rocrt.hpp │ │ │ │ ├── scs/ │ │ │ │ │ ├── scs_command_processor.hpp │ │ │ │ │ ├── scs_server_manager.hpp │ │ │ │ │ ├── scs_shell.hpp │ │ │ │ │ ├── scs_shell_server.hpp │ │ │ │ │ └── scs_tenv.hpp │ │ │ │ ├── scs.hpp │ │ │ │ ├── settings/ │ │ │ │ │ ├── factory/ │ │ │ │ │ │ ├── settings_configuration_id.hpp │ │ │ │ │ │ ├── settings_device_certificate.hpp │ │ │ │ │ │ └── settings_serial_number.hpp │ │ │ │ │ ├── settings_fwdbg_api.hpp │ │ │ │ │ ├── settings_fwdbg_types.hpp │ │ │ │ │ ├── settings_types.hpp │ │ │ │ │ └── system/ │ │ │ │ │ ├── settings_error_report.hpp │ │ │ │ │ ├── settings_firmware_version.hpp │ │ │ │ │ ├── settings_platform_region.hpp │ │ │ │ │ ├── settings_product_model.hpp │ │ │ │ │ ├── settings_region.hpp │ │ │ │ │ └── settings_serial_number.hpp │ │ │ │ ├── settings.hpp │ │ │ │ ├── sf/ │ │ │ │ │ ├── cmif/ │ │ │ │ │ │ ├── sf_cmif_domain_api.hpp │ │ │ │ │ │ ├── sf_cmif_domain_manager.hpp │ │ │ │ │ │ ├── sf_cmif_domain_service_object.hpp │ │ │ │ │ │ ├── sf_cmif_inline_context.hpp │ │ │ │ │ │ ├── sf_cmif_pointer_and_size.hpp │ │ │ │ │ │ ├── sf_cmif_server_message_processor.hpp │ │ │ │ │ │ ├── sf_cmif_service_dispatch.hpp │ │ │ │ │ │ └── sf_cmif_service_object_holder.hpp │ │ │ │ │ ├── hipc/ │ │ │ │ │ │ ├── sf_hipc_api.hpp │ │ │ │ │ │ ├── sf_hipc_server_domain_session_manager.hpp │ │ │ │ │ │ ├── sf_hipc_server_manager.hpp │ │ │ │ │ │ └── sf_hipc_server_session_manager.hpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── sf_impl_autogen_impl_macros.hpp │ │ │ │ │ │ ├── sf_impl_autogen_interface_macros.hpp │ │ │ │ │ │ ├── sf_impl_command_serialization.hpp │ │ │ │ │ │ ├── sf_impl_template_base.hpp │ │ │ │ │ │ └── sf_service_object_impl.hpp │ │ │ │ │ ├── sf_allocation_policies.hpp │ │ │ │ │ ├── sf_buffer_tags.hpp │ │ │ │ │ ├── sf_buffers.hpp │ │ │ │ │ ├── sf_common.hpp │ │ │ │ │ ├── sf_default_allocation_policy.hpp │ │ │ │ │ ├── sf_exp_heap_allocator.hpp │ │ │ │ │ ├── sf_fs_inline_context.hpp │ │ │ │ │ ├── sf_lmem_utility.hpp │ │ │ │ │ ├── sf_mem_utility.hpp │ │ │ │ │ ├── sf_memory_resource.hpp │ │ │ │ │ ├── sf_mitm_config.hpp │ │ │ │ │ ├── sf_mitm_dispatch.h │ │ │ │ │ ├── sf_native_handle.hpp │ │ │ │ │ ├── sf_object_factory.hpp │ │ │ │ │ ├── sf_object_impl_factory.hpp │ │ │ │ │ ├── sf_out.hpp │ │ │ │ │ ├── sf_service_object.hpp │ │ │ │ │ ├── sf_shared_object.hpp │ │ │ │ │ ├── sf_standard_allocation_policy.hpp │ │ │ │ │ ├── sf_std_allocation_policy.hpp │ │ │ │ │ └── sf_types.hpp │ │ │ │ ├── sf.hpp │ │ │ │ ├── sm/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── sm_manager_interface.hpp │ │ │ │ │ │ └── sm_user_interface.hpp │ │ │ │ │ ├── sm_api.hpp │ │ │ │ │ ├── sm_manager_api.hpp │ │ │ │ │ ├── sm_mitm_api.hpp │ │ │ │ │ └── sm_types.hpp │ │ │ │ ├── sm.hpp │ │ │ │ ├── socket/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── socket_platform_types_translation.hpp │ │ │ │ │ ├── socket_api.hpp │ │ │ │ │ ├── socket_config.hpp │ │ │ │ │ ├── socket_constants.hpp │ │ │ │ │ ├── socket_errno.hpp │ │ │ │ │ ├── socket_options.hpp │ │ │ │ │ ├── socket_system_config.hpp │ │ │ │ │ └── socket_types.hpp │ │ │ │ ├── socket.hpp │ │ │ │ ├── spl/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── spl_api_impl.hpp │ │ │ │ │ │ ├── spl_crypto_interface.hpp │ │ │ │ │ │ ├── spl_deprecated_general_interface.hpp │ │ │ │ │ │ ├── spl_device_unique_data_interface.hpp │ │ │ │ │ │ ├── spl_es_interface.hpp │ │ │ │ │ │ ├── spl_fs_interface.hpp │ │ │ │ │ │ ├── spl_general_interface.hpp │ │ │ │ │ │ ├── spl_manu_interface.hpp │ │ │ │ │ │ ├── spl_random_interface.hpp │ │ │ │ │ │ └── spl_ssl_interface.hpp │ │ │ │ │ ├── smc/ │ │ │ │ │ │ └── spl_secure_monitor_api.hpp │ │ │ │ │ ├── spl_api.hpp │ │ │ │ │ └── spl_types.hpp │ │ │ │ ├── spl.hpp │ │ │ │ ├── sprofile/ │ │ │ │ │ ├── sprofile_types.hpp │ │ │ │ │ └── srv/ │ │ │ │ │ └── sprofile_srv_api.hpp │ │ │ │ ├── sprofile.hpp │ │ │ │ ├── svc/ │ │ │ │ │ └── svc_stratosphere_shims.hpp │ │ │ │ ├── time/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ └── util/ │ │ │ │ │ │ └── time_impl_util_api.hpp │ │ │ │ │ ├── time_api.hpp │ │ │ │ │ ├── time_calendar_time.hpp │ │ │ │ │ ├── time_common.hpp │ │ │ │ │ ├── time_posix_time.hpp │ │ │ │ │ ├── time_standard_network_system_clock.hpp │ │ │ │ │ ├── time_standard_steady_clock.hpp │ │ │ │ │ ├── time_standard_user_system_clock.hpp │ │ │ │ │ ├── time_steady_clock_time_point.hpp │ │ │ │ │ ├── time_system_clock_common.hpp │ │ │ │ │ └── time_timezone_api.hpp │ │ │ │ ├── time.hpp │ │ │ │ ├── tipc/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── tipc_autogen_interface_macros.hpp │ │ │ │ │ │ ├── tipc_impl_command_serialization.hpp │ │ │ │ │ │ ├── tipc_impl_message_api.hpp │ │ │ │ │ │ ├── tipc_impl_message_api.os.horizon.hpp │ │ │ │ │ │ ├── tipc_impl_message_api.os.linux.hpp │ │ │ │ │ │ ├── tipc_impl_message_api.os.macos.hpp │ │ │ │ │ │ ├── tipc_impl_message_api.os.windows.hpp │ │ │ │ │ │ └── tipc_impl_template_base.hpp │ │ │ │ │ ├── tipc_allocators.hpp │ │ │ │ │ ├── tipc_buffers.hpp │ │ │ │ │ ├── tipc_common.hpp │ │ │ │ │ ├── tipc_deferral_manager.hpp │ │ │ │ │ ├── tipc_handles.hpp │ │ │ │ │ ├── tipc_message_types.hpp │ │ │ │ │ ├── tipc_object_holder.hpp │ │ │ │ │ ├── tipc_object_manager.hpp │ │ │ │ │ ├── tipc_out.hpp │ │ │ │ │ ├── tipc_pointer_and_size.hpp │ │ │ │ │ ├── tipc_server_manager.hpp │ │ │ │ │ ├── tipc_service_object.hpp │ │ │ │ │ └── tipc_service_object_base.hpp │ │ │ │ ├── tipc.hpp │ │ │ │ ├── tma/ │ │ │ │ │ ├── tma_i_directory_accessor.hpp │ │ │ │ │ ├── tma_i_file_accessor.hpp │ │ │ │ │ ├── tma_i_file_manager.hpp │ │ │ │ │ ├── tma_i_htc_manager.hpp │ │ │ │ │ ├── tma_i_htcs_manager.hpp │ │ │ │ │ ├── tma_i_socket.hpp │ │ │ │ │ └── tma_path.hpp │ │ │ │ ├── tma.hpp │ │ │ │ ├── updater/ │ │ │ │ │ ├── updater_api.hpp │ │ │ │ │ └── updater_types.hpp │ │ │ │ ├── updater.hpp │ │ │ │ ├── usb/ │ │ │ │ │ ├── ds/ │ │ │ │ │ │ ├── usb_i_ds_endpoint.hpp │ │ │ │ │ │ ├── usb_i_ds_interface.hpp │ │ │ │ │ │ └── usb_i_ds_service.hpp │ │ │ │ │ ├── usb_device.hpp │ │ │ │ │ ├── usb_device_types.hpp │ │ │ │ │ ├── usb_limits.hpp │ │ │ │ │ └── usb_types.hpp │ │ │ │ ├── usb.hpp │ │ │ │ ├── util/ │ │ │ │ │ ├── util_compression.hpp │ │ │ │ │ ├── util_ini.hpp │ │ │ │ │ ├── util_lock_free_atomic_type.hpp │ │ │ │ │ ├── util_singleton_traits.hpp │ │ │ │ │ └── util_uuid_api.hpp │ │ │ │ ├── util.hpp │ │ │ │ ├── vi/ │ │ │ │ │ └── vi_layer_stack.hpp │ │ │ │ ├── vi.hpp │ │ │ │ ├── wec/ │ │ │ │ │ ├── wec_api.hpp │ │ │ │ │ ├── wec_types.hpp │ │ │ │ │ ├── wec_wake_event.board.nintendo_nx.hpp │ │ │ │ │ └── wec_wake_event.generic.hpp │ │ │ │ ├── wec.hpp │ │ │ │ └── windows.hpp │ │ │ └── stratosphere.hpp │ │ ├── libstratosphere.mk │ │ ├── source/ │ │ │ ├── ams/ │ │ │ │ ├── ams_bpc.os.horizon.c │ │ │ │ ├── ams_bpc.os.horizon.h │ │ │ │ ├── ams_emummc_api.cpp │ │ │ │ ├── ams_environment.os.horizon.cpp │ │ │ │ ├── ams_environment_weak.os.horizon.cpp │ │ │ │ ├── ams_environment_weak.os.linux.cpp │ │ │ │ ├── ams_environment_weak.os.macos.cpp │ │ │ │ ├── ams_environment_weak.os.windows.cpp │ │ │ │ └── ams_exosphere_api.cpp │ │ │ ├── boot2/ │ │ │ │ └── boot2_api.board.nintendo_nx.cpp │ │ │ ├── cal/ │ │ │ │ ├── cal_battery_api.cpp │ │ │ │ ├── cal_crc_utils.cpp │ │ │ │ ├── cal_crc_utils.hpp │ │ │ │ ├── cal_fs_utils.cpp │ │ │ │ └── cal_fs_utils.hpp │ │ │ ├── capsrv/ │ │ │ │ ├── capsrv_screen_shot_control_api.cpp │ │ │ │ └── server/ │ │ │ │ ├── capsrv_server_decoder_api.cpp │ │ │ │ ├── decodersrv/ │ │ │ │ │ ├── decodersrv_decoder_control_server_manager.cpp │ │ │ │ │ ├── decodersrv_decoder_control_server_manager.hpp │ │ │ │ │ ├── decodersrv_decoder_control_service.cpp │ │ │ │ │ ├── decodersrv_decoder_control_service.hpp │ │ │ │ │ ├── decodersrv_decoder_server_object.cpp │ │ │ │ │ ├── decodersrv_decoder_server_object.hpp │ │ │ │ │ └── decodersrv_decoder_work_memory.hpp │ │ │ │ └── jpeg/ │ │ │ │ ├── capsrv_server_jpeg_error_handler.hpp │ │ │ │ ├── capsrv_server_jpeg_library_types.hpp │ │ │ │ ├── decodersrv_software_jpeg_decoder.cpp │ │ │ │ ├── decodersrv_software_jpeg_decoder.hpp │ │ │ │ ├── decodersrv_software_jpeg_shrinker.cpp │ │ │ │ └── decodersrv_software_jpeg_shrinker.hpp │ │ │ ├── cfg/ │ │ │ │ ├── cfg_flags.board.nintendo_nx.inc │ │ │ │ ├── cfg_flags.cpp │ │ │ │ ├── cfg_flags.generic.inc │ │ │ │ ├── cfg_override.board.nintendo_nx.inc │ │ │ │ ├── cfg_override.cpp │ │ │ │ ├── cfg_override.generic.inc │ │ │ │ ├── cfg_sd_card.board.nintendo_nx.inc │ │ │ │ ├── cfg_sd_card.cpp │ │ │ │ └── cfg_sd_card.generic.inc │ │ │ ├── crypto/ │ │ │ │ ├── crypto_csrng.os.generic.cpp │ │ │ │ ├── crypto_csrng.os.horizon.cpp │ │ │ │ └── crypto_csrng.os.windows.cpp │ │ │ ├── cs/ │ │ │ │ ├── cs_audio_server.cpp │ │ │ │ ├── cs_command_impl.hpp │ │ │ │ ├── cs_command_impl.inc │ │ │ │ ├── cs_command_processor.cpp │ │ │ │ ├── cs_hid_server.cpp │ │ │ │ ├── cs_remote_video_server.cpp │ │ │ │ └── cs_target_io_server.cpp │ │ │ ├── dd/ │ │ │ │ ├── dd_device_address_space.cpp │ │ │ │ └── impl/ │ │ │ │ ├── dd_device_address_space_impl.generic.hpp │ │ │ │ ├── dd_device_address_space_impl.hpp │ │ │ │ ├── dd_device_address_space_impl.os.horizon.cpp │ │ │ │ └── dd_device_address_space_impl.os.horizon.hpp │ │ │ ├── ddsf/ │ │ │ │ ├── ddsf_device_code_entry_manager.cpp │ │ │ │ ├── ddsf_event_handler.cpp │ │ │ │ ├── ddsf_memory_api.cpp │ │ │ │ └── ddsf_session_api.cpp │ │ │ ├── diag/ │ │ │ │ ├── diag_abort_observer.cpp │ │ │ │ ├── diag_assertion_impl.cpp │ │ │ │ ├── diag_assertion_impl_for_nx_asm.board.nintendo_nx.s │ │ │ │ ├── diag_backtrace.cpp │ │ │ │ ├── diag_log.cpp │ │ │ │ ├── diag_log_impl.hpp │ │ │ │ ├── diag_log_observer.cpp │ │ │ │ ├── diag_symbol.cpp │ │ │ │ └── impl/ │ │ │ │ ├── diag_abort_observer_manager.cpp │ │ │ │ ├── diag_abort_observer_manager.hpp │ │ │ │ ├── diag_backtrace_impl.os.generic.cpp │ │ │ │ ├── diag_backtrace_impl.os.horizon.cpp │ │ │ │ ├── diag_default_abort_observer.cpp │ │ │ │ ├── diag_dump_stack_trace.hpp │ │ │ │ ├── diag_dump_stack_trace.os.generic.cpp │ │ │ │ ├── diag_dump_stack_trace.os.horizon.cpp │ │ │ │ ├── diag_get_all_backtrace.cpp │ │ │ │ ├── diag_get_all_backtrace.hpp │ │ │ │ ├── diag_invoke_abort.hpp │ │ │ │ ├── diag_invoke_abort.os.generic.cpp │ │ │ │ ├── diag_invoke_abort.os.horizon.cpp │ │ │ │ ├── diag_module_impl.os.horizon.cpp │ │ │ │ ├── diag_observer_manager.hpp │ │ │ │ ├── diag_print_debug_string.hpp │ │ │ │ ├── diag_print_debug_string.os.horizon.cpp │ │ │ │ ├── diag_print_debug_string.os.linux.cpp │ │ │ │ ├── diag_print_debug_string.os.macos.cpp │ │ │ │ ├── diag_print_debug_string.os.windows.cpp │ │ │ │ ├── diag_process.os.horizon.cpp │ │ │ │ ├── diag_symbol_impl.hpp │ │ │ │ ├── diag_symbol_impl.os.generic.cpp │ │ │ │ ├── diag_symbol_impl.os.horizon.cpp │ │ │ │ ├── diag_symbol_impl.os.macos.cpp │ │ │ │ ├── diag_symbol_impl.os.windows.cpp │ │ │ │ └── diag_utf8_util.cpp │ │ │ ├── dmnt/ │ │ │ │ ├── dmntcht.h │ │ │ │ └── dmntcht.os.horizon.c │ │ │ ├── erpt/ │ │ │ │ └── srv/ │ │ │ │ ├── erpt_srv_allocator.hpp │ │ │ │ ├── erpt_srv_attachment.cpp │ │ │ │ ├── erpt_srv_attachment.hpp │ │ │ │ ├── erpt_srv_attachment_impl.cpp │ │ │ │ ├── erpt_srv_attachment_impl.hpp │ │ │ │ ├── erpt_srv_cipher.cpp │ │ │ │ ├── erpt_srv_cipher.hpp │ │ │ │ ├── erpt_srv_context.cpp │ │ │ │ ├── erpt_srv_context.hpp │ │ │ │ ├── erpt_srv_context_impl.cpp │ │ │ │ ├── erpt_srv_context_impl.hpp │ │ │ │ ├── erpt_srv_context_record.cpp │ │ │ │ ├── erpt_srv_context_record.hpp │ │ │ │ ├── erpt_srv_forced_shutdown.cpp │ │ │ │ ├── erpt_srv_forced_shutdown.hpp │ │ │ │ ├── erpt_srv_formatter.hpp │ │ │ │ ├── erpt_srv_fs_info.hpp │ │ │ │ ├── erpt_srv_fs_info.os.horizon.cpp │ │ │ │ ├── erpt_srv_journal.cpp │ │ │ │ ├── erpt_srv_journal.hpp │ │ │ │ ├── erpt_srv_journal_for_attachments.cpp │ │ │ │ ├── erpt_srv_journal_for_meta.cpp │ │ │ │ ├── erpt_srv_journal_for_reports.cpp │ │ │ │ ├── erpt_srv_journal_record.hpp │ │ │ │ ├── erpt_srv_keys.cpp │ │ │ │ ├── erpt_srv_keys.hpp │ │ │ │ ├── erpt_srv_main.cpp │ │ │ │ ├── erpt_srv_manager_impl.cpp │ │ │ │ ├── erpt_srv_manager_impl.hpp │ │ │ │ ├── erpt_srv_ref_count.hpp │ │ │ │ ├── erpt_srv_report.cpp │ │ │ │ ├── erpt_srv_report.hpp │ │ │ │ ├── erpt_srv_report_impl.cpp │ │ │ │ ├── erpt_srv_report_impl.hpp │ │ │ │ ├── erpt_srv_reporter.cpp │ │ │ │ ├── erpt_srv_reporter.hpp │ │ │ │ ├── erpt_srv_service.cpp │ │ │ │ ├── erpt_srv_service.hpp │ │ │ │ ├── erpt_srv_session_impl.cpp │ │ │ │ ├── erpt_srv_session_impl.hpp │ │ │ │ ├── erpt_srv_stream.cpp │ │ │ │ └── erpt_srv_stream.hpp │ │ │ ├── err/ │ │ │ │ ├── err_api.cpp │ │ │ │ └── impl/ │ │ │ │ ├── err_string_util.cpp │ │ │ │ └── err_string_util.hpp │ │ │ ├── fs/ │ │ │ │ ├── common/ │ │ │ │ │ ├── fs_dbm_hierarchical_rom_file_table.cpp │ │ │ │ │ ├── fs_dbm_rom_path_tool.cpp │ │ │ │ │ └── fs_file_storage.cpp │ │ │ │ ├── fs_access_log.cpp │ │ │ │ ├── fs_api.cpp │ │ │ │ ├── fs_application.cpp │ │ │ │ ├── fs_bis.cpp │ │ │ │ ├── fs_code.cpp │ │ │ │ ├── fs_content.cpp │ │ │ │ ├── fs_content_storage.cpp │ │ │ │ ├── fs_context.cpp │ │ │ │ ├── fs_data.cpp │ │ │ │ ├── fs_device_save_data.cpp │ │ │ │ ├── fs_error_info.cpp │ │ │ │ ├── fs_file_path_hash.hpp │ │ │ │ ├── fs_filesystem_utils.cpp │ │ │ │ ├── fs_game_card.cpp │ │ │ │ ├── fs_host.cpp │ │ │ │ ├── fs_image_directory.cpp │ │ │ │ ├── fs_memory_management.cpp │ │ │ │ ├── fs_memory_report_info.cpp │ │ │ │ ├── fs_mmc.cpp │ │ │ │ ├── fs_priority.cpp │ │ │ │ ├── fs_program_id.cpp │ │ │ │ ├── fs_remote_file_system_proxy.cpp │ │ │ │ ├── fs_remote_file_system_proxy.hpp │ │ │ │ ├── fs_remote_file_system_proxy_for_loader.hpp │ │ │ │ ├── fs_result_utils.cpp │ │ │ │ ├── fs_rights_id.cpp │ │ │ │ ├── fs_romfs_filesystem.cpp │ │ │ │ ├── fs_save_data_management.cpp │ │ │ │ ├── fs_scoped_setter.hpp │ │ │ │ ├── fs_sd_card.cpp │ │ │ │ ├── fs_signed_system_partition.cpp │ │ │ │ ├── fs_system_data.cpp │ │ │ │ ├── fs_system_save_data.cpp │ │ │ │ ├── fsa/ │ │ │ │ │ ├── fs_directory_accessor.cpp │ │ │ │ │ ├── fs_directory_accessor.hpp │ │ │ │ │ ├── fs_file_accessor.cpp │ │ │ │ │ ├── fs_file_accessor.hpp │ │ │ │ │ ├── fs_filesystem_accessor.cpp │ │ │ │ │ ├── fs_filesystem_accessor.hpp │ │ │ │ │ ├── fs_mount_name.hpp │ │ │ │ │ ├── fs_mount_table.cpp │ │ │ │ │ ├── fs_mount_table.hpp │ │ │ │ │ ├── fs_mount_utils.cpp │ │ │ │ │ ├── fs_mount_utils.hpp │ │ │ │ │ ├── fs_registrar.cpp │ │ │ │ │ ├── fs_user_directory.cpp │ │ │ │ │ ├── fs_user_file.cpp │ │ │ │ │ ├── fs_user_filesystem.cpp │ │ │ │ │ ├── fs_user_filesystem_for_debug.cpp │ │ │ │ │ ├── fs_user_mount_table.cpp │ │ │ │ │ └── fs_user_mount_table.hpp │ │ │ │ ├── impl/ │ │ │ │ │ ├── fs_event_notifier_service_object_adapter.hpp │ │ │ │ │ ├── fs_file_system_proxy_service_object.hpp │ │ │ │ │ ├── fs_file_system_service_object_adapter.hpp │ │ │ │ │ ├── fs_hash_generator_factory_selector.cpp │ │ │ │ │ ├── fs_id_string_impl.os.generic.cpp │ │ │ │ │ ├── fs_library.cpp │ │ │ │ │ ├── fs_library.hpp │ │ │ │ │ ├── fs_remote_device_operator.hpp │ │ │ │ │ └── fs_remote_event_notifier.hpp │ │ │ │ └── tests/ │ │ │ │ ├── fs_path_formatter_tests.cpp │ │ │ │ ├── fs_path_normalizer_tests.cpp │ │ │ │ └── fs_path_utility_tests.cpp │ │ │ ├── fssrv/ │ │ │ │ ├── fscreator/ │ │ │ │ │ ├── fssrv_local_file_system_creator.cpp │ │ │ │ │ ├── fssrv_partition_file_system_creator.cpp │ │ │ │ │ ├── fssrv_rom_file_system_creator.cpp │ │ │ │ │ ├── fssrv_storage_on_nca_creator.cpp │ │ │ │ │ └── fssrv_subdirectory_file_system_creator.cpp │ │ │ │ ├── fssrv_access_control.cpp │ │ │ │ ├── fssrv_deferred_process_manager.hpp │ │ │ │ ├── fssrv_file_system_proxy_api.cpp │ │ │ │ ├── fssrv_file_system_proxy_impl.cpp │ │ │ │ ├── fssrv_filesystem_interface_adapter.cpp │ │ │ │ ├── fssrv_memory_resource_from_exp_heap.cpp │ │ │ │ ├── fssrv_memory_resource_from_standard_allocator.cpp │ │ │ │ ├── fssrv_nca_crypto_configuration.cpp │ │ │ │ ├── fssrv_program_registry_impl.cpp │ │ │ │ ├── fssrv_program_registry_service.cpp │ │ │ │ ├── fssrv_retry_utility.hpp │ │ │ │ ├── fssrv_storage_interface_adapter.cpp │ │ │ │ └── impl/ │ │ │ │ ├── fssrv_allocator_for_service_framework.hpp │ │ │ │ ├── fssrv_file_system_proxy_service_object.cpp │ │ │ │ ├── fssrv_program_info.cpp │ │ │ │ ├── fssrv_program_info.hpp │ │ │ │ ├── fssrv_program_registry_manager.cpp │ │ │ │ ├── fssrv_program_registry_manager.hpp │ │ │ │ ├── fssrv_utility.cpp │ │ │ │ └── fssrv_utility.hpp │ │ │ ├── fssystem/ │ │ │ │ ├── buffers/ │ │ │ │ │ ├── fssystem_buffer_manager_utils.cpp │ │ │ │ │ ├── fssystem_file_system_buddy_heap.cpp │ │ │ │ │ └── fssystem_file_system_buffer_manager.cpp │ │ │ │ ├── fssystem_aes_ctr_counter_extended_storage.cpp │ │ │ │ ├── fssystem_aes_ctr_storage.cpp │ │ │ │ ├── fssystem_aes_ctr_storage_external.cpp │ │ │ │ ├── fssystem_aes_xts_storage.cpp │ │ │ │ ├── fssystem_aes_xts_storage_external.cpp │ │ │ │ ├── fssystem_alignment_matching_storage_impl.cpp │ │ │ │ ├── fssystem_allocator_utility.cpp │ │ │ │ ├── fssystem_block_cache_buffered_storage.cpp │ │ │ │ ├── fssystem_bucket_tree.cpp │ │ │ │ ├── fssystem_buffered_storage.cpp │ │ │ │ ├── fssystem_compression_configuration.cpp │ │ │ │ ├── fssystem_crypto_configuration.cpp │ │ │ │ ├── fssystem_directory_savedata_filesystem.cpp │ │ │ │ ├── fssystem_external_code.cpp │ │ │ │ ├── fssystem_file_system_proxy_api.cpp │ │ │ │ ├── fssystem_hierarchical_integrity_verification_storage.cpp │ │ │ │ ├── fssystem_hierarchical_sha256_storage.cpp │ │ │ │ ├── fssystem_hierarchical_sha256_storage.hpp │ │ │ │ ├── fssystem_indirect_storage.cpp │ │ │ │ ├── fssystem_integrity_romfs_storage.cpp │ │ │ │ ├── fssystem_integrity_verification_storage.cpp │ │ │ │ ├── fssystem_key_slot_cache.hpp │ │ │ │ ├── fssystem_local_file_system.cpp │ │ │ │ ├── fssystem_lru_list_cache.hpp │ │ │ │ ├── fssystem_memory_resource_buffer_hold_storage.hpp │ │ │ │ ├── fssystem_nca_file_system_driver.cpp │ │ │ │ ├── fssystem_nca_header.cpp │ │ │ │ ├── fssystem_nca_reader.cpp │ │ │ │ ├── fssystem_partition_file_system.cpp │ │ │ │ ├── fssystem_partition_file_system_meta.cpp │ │ │ │ ├── fssystem_pooled_buffer.cpp │ │ │ │ ├── fssystem_read_only_block_cache_storage.hpp │ │ │ │ ├── fssystem_romfs_filesystem.cpp │ │ │ │ ├── fssystem_service_context.cpp │ │ │ │ ├── fssystem_sparse_storage.cpp │ │ │ │ ├── fssystem_speed_emulation_configuration.cpp │ │ │ │ ├── fssystem_thread_priority_changer.cpp │ │ │ │ └── fssystem_utility.cpp │ │ │ ├── gc/ │ │ │ │ └── impl/ │ │ │ │ ├── gc_embedded_data_holder.cpp │ │ │ │ └── gc_gc_crypto.cpp │ │ │ ├── gpio/ │ │ │ │ ├── driver/ │ │ │ │ │ ├── board/ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── gpio_driver_api.cpp │ │ │ │ │ │ └── impl/ │ │ │ │ │ │ ├── gpio_driver_impl.cpp │ │ │ │ │ │ ├── gpio_driver_impl.hpp │ │ │ │ │ │ ├── gpio_initial_config.cpp │ │ │ │ │ │ ├── gpio_initial_config.hpp │ │ │ │ │ │ ├── gpio_initial_config_aula.inc │ │ │ │ │ │ ├── gpio_initial_config_calcio.inc │ │ │ │ │ │ ├── gpio_initial_config_hoag.inc │ │ │ │ │ │ ├── gpio_initial_config_icosa.inc │ │ │ │ │ │ ├── gpio_initial_config_iowa.inc │ │ │ │ │ │ ├── gpio_initial_wake_pin_config_aula.inc │ │ │ │ │ │ ├── gpio_initial_wake_pin_config_calcio.inc │ │ │ │ │ │ ├── gpio_initial_wake_pin_config_hoag.inc │ │ │ │ │ │ ├── gpio_initial_wake_pin_config_icosa.inc │ │ │ │ │ │ ├── gpio_initial_wake_pin_config_iowa.inc │ │ │ │ │ │ ├── gpio_internal_pad_map_combination.inc │ │ │ │ │ │ ├── gpio_register_accessor.hpp │ │ │ │ │ │ ├── gpio_suspend_handler.cpp │ │ │ │ │ │ ├── gpio_suspend_handler.hpp │ │ │ │ │ │ ├── gpio_tegra_pad.hpp │ │ │ │ │ │ └── gpio_wake_pin_config.hpp │ │ │ │ │ ├── gpio_driver_client_api.cpp │ │ │ │ │ ├── gpio_driver_service_api.cpp │ │ │ │ │ ├── gpio_pad.cpp │ │ │ │ │ ├── gpio_pad_api.cpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── gpio_driver_core.cpp │ │ │ │ │ ├── gpio_driver_core.hpp │ │ │ │ │ └── gpio_pad_session_impl.cpp │ │ │ │ ├── gpio_client_api.cpp │ │ │ │ ├── gpio_remote_manager_impl.cpp │ │ │ │ ├── gpio_remote_manager_impl.hpp │ │ │ │ ├── gpio_remote_pad_session_impl.hpp │ │ │ │ └── server/ │ │ │ │ ├── gpio_server_api.cpp │ │ │ │ ├── gpio_server_manager_impl.cpp │ │ │ │ ├── gpio_server_manager_impl.hpp │ │ │ │ └── gpio_server_pad_session_impl.hpp │ │ │ ├── hid/ │ │ │ │ └── hid_api.cpp │ │ │ ├── hos/ │ │ │ │ ├── hos_stratosphere_api.cpp │ │ │ │ ├── hos_version_api.cpp │ │ │ │ ├── hos_version_api_private.cpp │ │ │ │ └── hos_version_api_weak_for_unit_test.cpp │ │ │ ├── htc/ │ │ │ │ ├── server/ │ │ │ │ │ ├── driver/ │ │ │ │ │ │ ├── htc_driver_manager.hpp │ │ │ │ │ │ ├── htc_htclow_driver.cpp │ │ │ │ │ │ ├── htc_htclow_driver.hpp │ │ │ │ │ │ └── htc_i_driver.hpp │ │ │ │ │ ├── htc_htc_service_object.cpp │ │ │ │ │ ├── htc_htc_service_object.hpp │ │ │ │ │ ├── htc_htcmisc_hipc_server.cpp │ │ │ │ │ ├── htc_htcmisc_impl.cpp │ │ │ │ │ ├── htc_htcmisc_impl.hpp │ │ │ │ │ ├── htc_htcmisc_manager.cpp │ │ │ │ │ ├── htc_htcmisc_manager.hpp │ │ │ │ │ ├── htc_observer.cpp │ │ │ │ │ ├── htc_observer.hpp │ │ │ │ │ ├── htc_power_state_control.cpp │ │ │ │ │ └── rpc/ │ │ │ │ │ ├── htc_htcmisc_rpc_server.cpp │ │ │ │ │ ├── htc_htcmisc_rpc_server.hpp │ │ │ │ │ ├── htc_htcmisc_rpc_tasks.cpp │ │ │ │ │ ├── htc_htcmisc_rpc_tasks.hpp │ │ │ │ │ ├── htc_rpc_client.cpp │ │ │ │ │ ├── htc_rpc_client.hpp │ │ │ │ │ ├── htc_rpc_task_id_free_list.hpp │ │ │ │ │ ├── htc_rpc_task_queue.hpp │ │ │ │ │ ├── htc_rpc_task_table.hpp │ │ │ │ │ └── htc_rpc_tasks.hpp │ │ │ │ └── tenv/ │ │ │ │ ├── htc_tenv.cpp │ │ │ │ ├── htc_tenv_service.cpp │ │ │ │ ├── htc_tenv_service.hpp │ │ │ │ ├── htc_tenv_service_manager.cpp │ │ │ │ └── impl/ │ │ │ │ ├── htc_tenv_allocator.cpp │ │ │ │ ├── htc_tenv_allocator.hpp │ │ │ │ ├── htc_tenv_definition_file_info.hpp │ │ │ │ ├── htc_tenv_impl.cpp │ │ │ │ └── htc_tenv_impl.hpp │ │ │ ├── htcfs/ │ │ │ │ ├── htcfs_cache_manager.hpp │ │ │ │ ├── htcfs_client.cpp │ │ │ │ ├── htcfs_client.hpp │ │ │ │ ├── htcfs_client_impl.cpp │ │ │ │ ├── htcfs_client_impl.hpp │ │ │ │ ├── htcfs_directory_service_object.cpp │ │ │ │ ├── htcfs_directory_service_object.hpp │ │ │ │ ├── htcfs_file_service_object.cpp │ │ │ │ ├── htcfs_file_service_object.hpp │ │ │ │ ├── htcfs_file_system_service_object.cpp │ │ │ │ ├── htcfs_file_system_service_object.hpp │ │ │ │ ├── htcfs_header_factory.hpp │ │ │ │ ├── htcfs_hipc_server.cpp │ │ │ │ ├── htcfs_result.hpp │ │ │ │ ├── htcfs_result_utils.hpp │ │ │ │ ├── htcfs_working_directory.cpp │ │ │ │ └── htcfs_working_directory.hpp │ │ │ ├── htclow/ │ │ │ │ ├── ctrl/ │ │ │ │ │ ├── htclow_ctrl_packet.hpp │ │ │ │ │ ├── htclow_ctrl_packet_factory.cpp │ │ │ │ │ ├── htclow_ctrl_packet_factory.hpp │ │ │ │ │ ├── htclow_ctrl_send_buffer.cpp │ │ │ │ │ ├── htclow_ctrl_send_buffer.hpp │ │ │ │ │ ├── htclow_ctrl_service.cpp │ │ │ │ │ ├── htclow_ctrl_service.hpp │ │ │ │ │ ├── htclow_ctrl_service_channels.hpp │ │ │ │ │ ├── htclow_ctrl_settings_holder.cpp │ │ │ │ │ ├── htclow_ctrl_settings_holder.hpp │ │ │ │ │ ├── htclow_ctrl_state.hpp │ │ │ │ │ ├── htclow_ctrl_state_machine.cpp │ │ │ │ │ ├── htclow_ctrl_state_machine.hpp │ │ │ │ │ ├── htclow_json.cpp │ │ │ │ │ ├── htclow_json.hpp │ │ │ │ │ ├── htclow_service_channel_parser.cpp │ │ │ │ │ └── htclow_service_channel_parser.hpp │ │ │ │ ├── driver/ │ │ │ │ │ ├── htclow_driver_manager.cpp │ │ │ │ │ ├── htclow_driver_manager.hpp │ │ │ │ │ ├── htclow_driver_memory_management.cpp │ │ │ │ │ ├── htclow_driver_memory_management.hpp │ │ │ │ │ ├── htclow_i_driver.hpp │ │ │ │ │ ├── htclow_socket_discovery_manager.cpp │ │ │ │ │ ├── htclow_socket_discovery_manager.hpp │ │ │ │ │ ├── htclow_socket_discovery_util.cpp │ │ │ │ │ ├── htclow_socket_discovery_util.hpp │ │ │ │ │ ├── htclow_socket_driver.cpp │ │ │ │ │ ├── htclow_socket_driver.hpp │ │ │ │ │ ├── htclow_usb_driver.cpp │ │ │ │ │ ├── htclow_usb_driver.hpp │ │ │ │ │ ├── htclow_usb_impl.cpp │ │ │ │ │ └── htclow_usb_impl.hpp │ │ │ │ ├── htclow_channel.cpp │ │ │ │ ├── htclow_channel.hpp │ │ │ │ ├── htclow_default_channel_config.hpp │ │ │ │ ├── htclow_listener.cpp │ │ │ │ ├── htclow_listener.hpp │ │ │ │ ├── htclow_manager.cpp │ │ │ │ ├── htclow_manager.hpp │ │ │ │ ├── htclow_manager_holder.cpp │ │ │ │ ├── htclow_manager_impl.cpp │ │ │ │ ├── htclow_manager_impl.hpp │ │ │ │ ├── htclow_packet.hpp │ │ │ │ ├── htclow_packet_factory.cpp │ │ │ │ ├── htclow_packet_factory.hpp │ │ │ │ ├── htclow_worker.cpp │ │ │ │ ├── htclow_worker.hpp │ │ │ │ └── mux/ │ │ │ │ ├── htclow_mux.cpp │ │ │ │ ├── htclow_mux.hpp │ │ │ │ ├── htclow_mux_channel_impl.cpp │ │ │ │ ├── htclow_mux_channel_impl.hpp │ │ │ │ ├── htclow_mux_channel_impl_map.cpp │ │ │ │ ├── htclow_mux_channel_impl_map.hpp │ │ │ │ ├── htclow_mux_global_send_buffer.cpp │ │ │ │ ├── htclow_mux_global_send_buffer.hpp │ │ │ │ ├── htclow_mux_ring_buffer.cpp │ │ │ │ ├── htclow_mux_ring_buffer.hpp │ │ │ │ ├── htclow_mux_send_buffer.cpp │ │ │ │ ├── htclow_mux_send_buffer.hpp │ │ │ │ ├── htclow_mux_task_manager.cpp │ │ │ │ └── htclow_mux_task_manager.hpp │ │ │ ├── htcs/ │ │ │ │ ├── client/ │ │ │ │ │ ├── htcs_session.hpp │ │ │ │ │ ├── htcs_session.os.horizon.cpp │ │ │ │ │ ├── htcs_session.os.windows.cpp │ │ │ │ │ ├── htcs_virtual_socket_collection.cpp │ │ │ │ │ └── htcs_virtual_socket_collection.hpp │ │ │ │ ├── htcs_socket.cpp │ │ │ │ ├── impl/ │ │ │ │ │ ├── htcs_impl.cpp │ │ │ │ │ ├── htcs_impl.hpp │ │ │ │ │ ├── htcs_manager.cpp │ │ │ │ │ ├── htcs_manager.hpp │ │ │ │ │ ├── htcs_manager_holder.cpp │ │ │ │ │ ├── htcs_manager_impl.cpp │ │ │ │ │ ├── htcs_manager_impl.hpp │ │ │ │ │ ├── htcs_monitor.cpp │ │ │ │ │ ├── htcs_monitor.hpp │ │ │ │ │ ├── htcs_service.cpp │ │ │ │ │ ├── htcs_service.hpp │ │ │ │ │ ├── htcs_util.cpp │ │ │ │ │ ├── htcs_util.hpp │ │ │ │ │ └── rpc/ │ │ │ │ │ ├── htcs_data_channel_manager.cpp │ │ │ │ │ ├── htcs_data_channel_manager.hpp │ │ │ │ │ ├── htcs_rpc_accept_task.cpp │ │ │ │ │ ├── htcs_rpc_bind_task.cpp │ │ │ │ │ ├── htcs_rpc_close_task.cpp │ │ │ │ │ ├── htcs_rpc_connect_task.cpp │ │ │ │ │ ├── htcs_rpc_fcntl_task.cpp │ │ │ │ │ ├── htcs_rpc_listen_task.cpp │ │ │ │ │ ├── htcs_rpc_receive_small_task.cpp │ │ │ │ │ ├── htcs_rpc_receive_task.cpp │ │ │ │ │ ├── htcs_rpc_select_task.cpp │ │ │ │ │ ├── htcs_rpc_send_small_task.cpp │ │ │ │ │ ├── htcs_rpc_send_task.cpp │ │ │ │ │ ├── htcs_rpc_shutdown_task.cpp │ │ │ │ │ ├── htcs_rpc_signaling_task.cpp │ │ │ │ │ ├── htcs_rpc_socket_task.cpp │ │ │ │ │ └── htcs_rpc_tasks.hpp │ │ │ │ └── server/ │ │ │ │ ├── htcs_hipc_server.cpp │ │ │ │ ├── htcs_manager_service_object.cpp │ │ │ │ ├── htcs_manager_service_object.hpp │ │ │ │ ├── htcs_manager_service_object_deprecated.cpp │ │ │ │ ├── htcs_service_object_allocator.hpp │ │ │ │ ├── htcs_socket_service_object.cpp │ │ │ │ ├── htcs_socket_service_object.hpp │ │ │ │ └── htcs_socket_service_object_deprecated.cpp │ │ │ ├── i2c/ │ │ │ │ ├── driver/ │ │ │ │ │ ├── board/ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── i2c_bus_device_map.inc │ │ │ │ │ │ ├── i2c_driver_api.cpp │ │ │ │ │ │ └── impl/ │ │ │ │ │ │ ├── i2c_bus_accessor.cpp │ │ │ │ │ │ ├── i2c_bus_accessor.hpp │ │ │ │ │ │ ├── i2c_bus_manager.hpp │ │ │ │ │ │ ├── i2c_device_property_manager.hpp │ │ │ │ │ │ ├── i2c_i2c_registers.hpp │ │ │ │ │ │ └── i2c_i_allocator.hpp │ │ │ │ │ ├── i2c_driver_bus_api.cpp │ │ │ │ │ ├── i2c_driver_client_api.cpp │ │ │ │ │ ├── i2c_driver_service_api.cpp │ │ │ │ │ └── impl/ │ │ │ │ │ ├── i2c_driver_core.cpp │ │ │ │ │ ├── i2c_driver_core.hpp │ │ │ │ │ └── i2c_i2c_session_impl.cpp │ │ │ │ ├── i2c_client_api.cpp │ │ │ │ ├── i2c_command_list_formatter.cpp │ │ │ │ ├── impl/ │ │ │ │ │ └── i2c_command_list_format.hpp │ │ │ │ └── server/ │ │ │ │ ├── i2c_server_api.cpp │ │ │ │ ├── i2c_server_manager_impl.cpp │ │ │ │ ├── i2c_server_manager_impl.hpp │ │ │ │ └── i2c_server_session_impl.hpp │ │ │ ├── init/ │ │ │ │ ├── init_libnx_shim.os.horizon.cpp │ │ │ │ ├── init_malloc.cpp │ │ │ │ ├── init_operator_new.cpp │ │ │ │ └── init_system_module.cpp │ │ │ ├── kvdb/ │ │ │ │ ├── kvdb_archive.cpp │ │ │ │ └── kvdb_file_key_value_store.cpp │ │ │ ├── ldr/ │ │ │ │ ├── ldr_ams.os.horizon.c │ │ │ │ ├── ldr_ams.os.horizon.h │ │ │ │ ├── ldr_pm_api.os.horizon.cpp │ │ │ │ └── ldr_shell_api.os.horizon.cpp │ │ │ ├── lm/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── lm_log_data_chunk.hpp │ │ │ │ │ ├── lm_log_packet_header.hpp │ │ │ │ │ ├── lm_log_packet_transmitter.hpp │ │ │ │ │ ├── lm_log_packet_transmitter_base.cpp │ │ │ │ │ └── lm_log_packet_transmitter_base.hpp │ │ │ │ ├── lm_api.cpp │ │ │ │ ├── lm_remote_log_service.cpp │ │ │ │ ├── lm_remote_log_service.hpp │ │ │ │ ├── lm_service_name.hpp │ │ │ │ ├── sf/ │ │ │ │ │ ├── lm_i_log_getter.hpp │ │ │ │ │ └── lm_i_log_service.hpp │ │ │ │ └── srv/ │ │ │ │ ├── lm_custom_sink_buffer.cpp │ │ │ │ ├── lm_custom_sink_buffer.hpp │ │ │ │ ├── lm_event_log_transmitter.cpp │ │ │ │ ├── lm_event_log_transmitter.hpp │ │ │ │ ├── lm_flush_thread.cpp │ │ │ │ ├── lm_ipc_server.cpp │ │ │ │ ├── lm_log_buffer.cpp │ │ │ │ ├── lm_log_buffer.hpp │ │ │ │ ├── lm_log_getter.cpp │ │ │ │ ├── lm_log_getter.hpp │ │ │ │ ├── lm_log_getter_impl.cpp │ │ │ │ ├── lm_log_getter_impl.hpp │ │ │ │ ├── lm_log_packet_parser.cpp │ │ │ │ ├── lm_log_packet_parser.hpp │ │ │ │ ├── lm_log_server_proxy.cpp │ │ │ │ ├── lm_log_server_proxy.hpp │ │ │ │ ├── lm_log_service_impl.cpp │ │ │ │ ├── lm_log_service_impl.hpp │ │ │ │ ├── lm_logger_impl.cpp │ │ │ │ ├── lm_logger_impl.hpp │ │ │ │ ├── lm_sd_card_logger.cpp │ │ │ │ ├── lm_sd_card_logger.hpp │ │ │ │ ├── lm_time_util.cpp │ │ │ │ └── lm_time_util.hpp │ │ │ ├── lmem/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── lmem_impl_common_heap.cpp │ │ │ │ │ ├── lmem_impl_common_heap.hpp │ │ │ │ │ ├── lmem_impl_exp_heap.cpp │ │ │ │ │ ├── lmem_impl_exp_heap.hpp │ │ │ │ │ ├── lmem_impl_unit_heap.cpp │ │ │ │ │ └── lmem_impl_unit_heap.hpp │ │ │ │ ├── lmem_common.cpp │ │ │ │ ├── lmem_exp_heap.cpp │ │ │ │ └── lmem_unit_heap.cpp │ │ │ ├── lr/ │ │ │ │ ├── lr_add_on_content_location_resolver_impl.cpp │ │ │ │ ├── lr_add_on_content_location_resolver_impl.hpp │ │ │ │ ├── lr_api.cpp │ │ │ │ ├── lr_content_location_resolver_impl.cpp │ │ │ │ ├── lr_content_location_resolver_impl.hpp │ │ │ │ ├── lr_location_redirector.cpp │ │ │ │ ├── lr_location_redirector.hpp │ │ │ │ ├── lr_location_resolver_impl_base.hpp │ │ │ │ ├── lr_location_resolver_manager_factory.cpp │ │ │ │ ├── lr_location_resolver_manager_factory.hpp │ │ │ │ ├── lr_location_resolver_manager_impl.cpp │ │ │ │ ├── lr_redirect_only_location_resolver_impl.cpp │ │ │ │ ├── lr_redirect_only_location_resolver_impl.hpp │ │ │ │ ├── lr_registered_data.hpp │ │ │ │ ├── lr_registered_location_resolver_impl.cpp │ │ │ │ ├── lr_registered_location_resolver_impl.hpp │ │ │ │ ├── lr_remote_location_resolver_impl.hpp │ │ │ │ ├── lr_remote_location_resolver_manager_impl.hpp │ │ │ │ └── lr_remote_registered_location_resolver_impl.hpp │ │ │ ├── mem/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── heap/ │ │ │ │ │ │ ├── mem_impl_heap_cached_heap.cpp │ │ │ │ │ │ ├── mem_impl_heap_central_heap.cpp │ │ │ │ │ │ ├── mem_impl_heap_platform.hpp │ │ │ │ │ │ ├── mem_impl_heap_tls_heap_cache.cpp │ │ │ │ │ │ ├── mem_impl_heap_tls_heap_cache.hpp │ │ │ │ │ │ ├── mem_impl_heap_tls_heap_central.cpp │ │ │ │ │ │ ├── mem_impl_heap_tls_heap_central.hpp │ │ │ │ │ │ └── mem_impl_heap_tls_heap_static.hpp │ │ │ │ │ ├── mem_impl_platform.hpp │ │ │ │ │ ├── mem_impl_platform.os.horizon.cpp │ │ │ │ │ ├── mem_impl_platform.os.linux.cpp │ │ │ │ │ ├── mem_impl_platform.os.macos.cpp │ │ │ │ │ └── mem_impl_platform.os.windows.cpp │ │ │ │ └── mem_standard_allocator.cpp │ │ │ ├── mitm/ │ │ │ │ ├── mitm_pm.os.horizon.c │ │ │ │ ├── mitm_pm.os.horizon.h │ │ │ │ └── mitm_pm_api.cpp │ │ │ ├── ncm/ │ │ │ │ ├── ncm_api.cpp │ │ │ │ ├── ncm_content_id_utils.cpp │ │ │ │ ├── ncm_content_info_utils.cpp │ │ │ │ ├── ncm_content_management_utils.cpp │ │ │ │ ├── ncm_content_manager_factory.cpp │ │ │ │ ├── ncm_content_manager_factory.hpp │ │ │ │ ├── ncm_content_manager_impl.cpp │ │ │ │ ├── ncm_content_meta.cpp │ │ │ │ ├── ncm_content_meta_database_impl.cpp │ │ │ │ ├── ncm_content_meta_database_impl.hpp │ │ │ │ ├── ncm_content_meta_database_impl_base.hpp │ │ │ │ ├── ncm_content_meta_type.cpp │ │ │ │ ├── ncm_content_meta_utils.cpp │ │ │ │ ├── ncm_content_storage_impl.cpp │ │ │ │ ├── ncm_content_storage_impl.hpp │ │ │ │ ├── ncm_content_storage_impl_base.hpp │ │ │ │ ├── ncm_extended_data_mapper.hpp │ │ │ │ ├── ncm_file_mapper_file.hpp │ │ │ │ ├── ncm_fs_utils.cpp │ │ │ │ ├── ncm_fs_utils.hpp │ │ │ │ ├── ncm_host_content_storage_impl.cpp │ │ │ │ ├── ncm_host_content_storage_impl.hpp │ │ │ │ ├── ncm_install_task_base.cpp │ │ │ │ ├── ncm_install_task_data.cpp │ │ │ │ ├── ncm_integrated_content_meta_database_impl.cpp │ │ │ │ ├── ncm_integrated_content_storage_impl.cpp │ │ │ │ ├── ncm_make_path.cpp │ │ │ │ ├── ncm_memory_report.cpp │ │ │ │ ├── ncm_on_memory_content_meta_database_impl.cpp │ │ │ │ ├── ncm_on_memory_content_meta_database_impl.hpp │ │ │ │ ├── ncm_package_install_task.cpp │ │ │ │ ├── ncm_package_install_task_base.cpp │ │ │ │ ├── ncm_package_system_downgrade_task.cpp │ │ │ │ ├── ncm_package_system_update_task.cpp │ │ │ │ ├── ncm_placeholder_accessor.cpp │ │ │ │ ├── ncm_placeholder_accessor.hpp │ │ │ │ ├── ncm_read_only_content_storage_impl.cpp │ │ │ │ ├── ncm_read_only_content_storage_impl.hpp │ │ │ │ ├── ncm_registered_host_content.cpp │ │ │ │ ├── ncm_remote_content_manager_impl.hpp │ │ │ │ ├── ncm_remote_content_meta_database_impl.hpp │ │ │ │ ├── ncm_remote_content_storage_impl.hpp │ │ │ │ ├── ncm_storage_utils.cpp │ │ │ │ └── ncm_submission_package_install_task.cpp │ │ │ ├── nim/ │ │ │ │ └── nim_network_install_manager_api.cpp │ │ │ ├── nsd/ │ │ │ │ └── impl/ │ │ │ │ └── device/ │ │ │ │ └── nsd_device.cpp │ │ │ ├── os/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── os_address_space_allocator.cpp │ │ │ │ │ ├── os_address_space_allocator.hpp │ │ │ │ │ ├── os_address_space_allocator_forbidden_region.hpp │ │ │ │ │ ├── os_address_space_allocator_impl.generic.hpp │ │ │ │ │ ├── os_address_space_allocator_impl.os.horizon.hpp │ │ │ │ │ ├── os_aslr_space_manager.hpp │ │ │ │ │ ├── os_aslr_space_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_aslr_space_manager_impl.os.linux.hpp │ │ │ │ │ ├── os_aslr_space_manager_impl.os.macos.hpp │ │ │ │ │ ├── os_aslr_space_manager_impl.os.windows.hpp │ │ │ │ │ ├── os_aslr_space_manager_types.hpp │ │ │ │ │ ├── os_cache_impl.hpp │ │ │ │ │ ├── os_cache_impl.os.horizon.hpp │ │ │ │ │ ├── os_cache_impl.os.linux.hpp │ │ │ │ │ ├── os_cache_impl.os.macos.hpp │ │ │ │ │ ├── os_cache_impl.os.windows.hpp │ │ │ │ │ ├── os_debug_impl.hpp │ │ │ │ │ ├── os_debug_impl.os.horizon.hpp │ │ │ │ │ ├── os_debug_impl.os.linux.hpp │ │ │ │ │ ├── os_debug_impl.os.macos.hpp │ │ │ │ │ ├── os_debug_impl.os.windows.hpp │ │ │ │ │ ├── os_disable_counter.os.horizon.hpp │ │ │ │ │ ├── os_giant_lock.hpp │ │ │ │ │ ├── os_giant_lock.os.horizon.hpp │ │ │ │ │ ├── os_giant_lock.os.linux.cpp │ │ │ │ │ ├── os_giant_lock.os.linux.hpp │ │ │ │ │ ├── os_giant_lock.os.macos.cpp │ │ │ │ │ ├── os_giant_lock.os.macos.hpp │ │ │ │ │ ├── os_giant_lock.os.windows.cpp │ │ │ │ │ ├── os_giant_lock.os.windows.hpp │ │ │ │ │ ├── os_giant_lock_types.hpp │ │ │ │ │ ├── os_initialize.os.horizon.cpp │ │ │ │ │ ├── os_initialize.os.linux.cpp │ │ │ │ │ ├── os_initialize.os.macos.cpp │ │ │ │ │ ├── os_initialize.os.windows.cpp │ │ │ │ │ ├── os_insecure_memory_impl.hpp │ │ │ │ │ ├── os_insecure_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_inter_process_event.cpp │ │ │ │ │ ├── os_inter_process_event.hpp │ │ │ │ │ ├── os_inter_process_event_impl.hpp │ │ │ │ │ ├── os_inter_process_event_impl.os.horizon.cpp │ │ │ │ │ ├── os_inter_process_event_impl.os.horizon.hpp │ │ │ │ │ ├── os_inter_process_event_impl.os.linux.cpp │ │ │ │ │ ├── os_inter_process_event_impl.os.linux.hpp │ │ │ │ │ ├── os_inter_process_event_impl.os.macos.cpp │ │ │ │ │ ├── os_inter_process_event_impl.os.macos.hpp │ │ │ │ │ ├── os_inter_process_event_impl.os.windows.cpp │ │ │ │ │ ├── os_inter_process_event_impl.os.windows.hpp │ │ │ │ │ ├── os_internal_busy_mutex_impl.os.horizon.hpp │ │ │ │ │ ├── os_internal_condition_variable_impl.os.horizon.cpp │ │ │ │ │ ├── os_internal_condition_variable_impl.os.windows.cpp │ │ │ │ │ ├── os_internal_condition_variable_impl.pthread.cpp │ │ │ │ │ ├── os_internal_critical_section_impl.os.horizon.cpp │ │ │ │ │ ├── os_internal_critical_section_impl.os.windows.cpp │ │ │ │ │ ├── os_internal_critical_section_impl.os.windows.hpp │ │ │ │ │ ├── os_internal_critical_section_impl.pthread.cpp │ │ │ │ │ ├── os_internal_light_event_impl.os.generic.hpp │ │ │ │ │ ├── os_internal_light_event_impl.os.horizon.hpp │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.horizon.hpp │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.linux.hpp │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.macos.hpp │ │ │ │ │ ├── os_internal_rw_busy_mutex_impl.os.windows.hpp │ │ │ │ │ ├── os_interrupt_event_impl.hpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.horizon.cpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.horizon.hpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.linux.hpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.macos.hpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.windows.cpp │ │ │ │ │ ├── os_interrupt_event_target_impl.os.windows.hpp │ │ │ │ │ ├── os_io_region_impl.hpp │ │ │ │ │ ├── os_io_region_impl.os.horizon.cpp │ │ │ │ │ ├── os_io_region_impl.os.windows.cpp │ │ │ │ │ ├── os_memory_attribute_impl.hpp │ │ │ │ │ ├── os_memory_attribute_impl.os.horizon.cpp │ │ │ │ │ ├── os_memory_attribute_impl.os.linux.cpp │ │ │ │ │ ├── os_memory_attribute_impl.os.macos.cpp │ │ │ │ │ ├── os_memory_attribute_impl.os.windows.cpp │ │ │ │ │ ├── os_memory_heap_manager.cpp │ │ │ │ │ ├── os_memory_heap_manager.hpp │ │ │ │ │ ├── os_memory_heap_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_memory_heap_manager_impl.os.linux.hpp │ │ │ │ │ ├── os_memory_heap_manager_impl.os.macos.hpp │ │ │ │ │ ├── os_memory_heap_manager_impl.os.windows.hpp │ │ │ │ │ ├── os_memory_heap_manager_types.hpp │ │ │ │ │ ├── os_memory_permission_impl.hpp │ │ │ │ │ ├── os_memory_permission_impl.os.horizon.cpp │ │ │ │ │ ├── os_memory_permission_impl.os.linux.cpp │ │ │ │ │ ├── os_memory_permission_impl.os.macos.cpp │ │ │ │ │ ├── os_memory_permission_impl.os.windows.cpp │ │ │ │ │ ├── os_message_queue_helper.hpp │ │ │ │ │ ├── os_multiple_wait_holder_base.hpp │ │ │ │ │ ├── os_multiple_wait_holder_impl.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_event.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_inter_process_event.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_interrupt_event.cpp │ │ │ │ │ ├── os_multiple_wait_holder_of_interrupt_event.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_message_queue.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_native_handle.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_semaphore.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_thread.hpp │ │ │ │ │ ├── os_multiple_wait_holder_of_timer_event.hpp │ │ │ │ │ ├── os_multiple_wait_impl.cpp │ │ │ │ │ ├── os_multiple_wait_impl.hpp │ │ │ │ │ ├── os_multiple_wait_object_list.hpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.horizon.cpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.horizon.hpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.linux.cpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.linux.hpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.macos.cpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.macos.hpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.windows.cpp │ │ │ │ │ ├── os_multiple_wait_target_impl.os.windows.hpp │ │ │ │ │ ├── os_mutex_impl.hpp │ │ │ │ │ ├── os_native_handle_impl.hpp │ │ │ │ │ ├── os_native_handle_impl.os.horizon.hpp │ │ │ │ │ ├── os_native_handle_impl.os.linux.hpp │ │ │ │ │ ├── os_native_handle_impl.os.macos.hpp │ │ │ │ │ ├── os_native_handle_impl.os.windows.hpp │ │ │ │ │ ├── os_process_code_memory_impl.hpp │ │ │ │ │ ├── os_process_code_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_process_handle_impl.hpp │ │ │ │ │ ├── os_process_handle_impl.os.horizon.hpp │ │ │ │ │ ├── os_process_handle_impl.os.linux.hpp │ │ │ │ │ ├── os_process_handle_impl.os.macos.hpp │ │ │ │ │ ├── os_process_handle_impl.os.windows.hpp │ │ │ │ │ ├── os_process_memory_impl.hpp │ │ │ │ │ ├── os_process_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_random_impl.hpp │ │ │ │ │ ├── os_random_impl.os.horizon.cpp │ │ │ │ │ ├── os_random_impl.os.linux.cpp │ │ │ │ │ ├── os_random_impl.os.macos.cpp │ │ │ │ │ ├── os_random_impl.os.windows.cpp │ │ │ │ │ ├── os_resource_manager.cpp │ │ │ │ │ ├── os_resource_manager.hpp │ │ │ │ │ ├── os_rng_manager.hpp │ │ │ │ │ ├── os_rng_manager_impl.cpp │ │ │ │ │ ├── os_rng_manager_impl.hpp │ │ │ │ │ ├── os_rng_manager_impl.os.horizon.cpp │ │ │ │ │ ├── os_rng_manager_impl.os.linux.cpp │ │ │ │ │ ├── os_rng_manager_impl.os.macos.cpp │ │ │ │ │ ├── os_rng_manager_impl.os.windows.cpp │ │ │ │ │ ├── os_rw_lock_impl.hpp │ │ │ │ │ ├── os_rw_lock_target_impl.os.generic.cpp │ │ │ │ │ ├── os_rw_lock_target_impl.os.generic.hpp │ │ │ │ │ ├── os_rw_lock_target_impl.os.horizon.cpp │ │ │ │ │ ├── os_rw_lock_target_impl.os.horizon.hpp │ │ │ │ │ ├── os_shared_memory_impl.hpp │ │ │ │ │ ├── os_shared_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_stack_guard_manager.hpp │ │ │ │ │ ├── os_stack_guard_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_stack_guard_manager_impl.os.linux.hpp │ │ │ │ │ ├── os_stack_guard_manager_impl.os.macos.hpp │ │ │ │ │ ├── os_stack_guard_manager_impl.os.windows.hpp │ │ │ │ │ ├── os_stack_guard_manager_types.hpp │ │ │ │ │ ├── os_thread_manager.cpp │ │ │ │ │ ├── os_thread_manager.hpp │ │ │ │ │ ├── os_thread_manager_impl.os.horizon.cpp │ │ │ │ │ ├── os_thread_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_thread_manager_impl.os.windows.cpp │ │ │ │ │ ├── os_thread_manager_impl.os.windows.hpp │ │ │ │ │ ├── os_thread_manager_impl.pthread.cpp │ │ │ │ │ ├── os_thread_manager_impl.pthread.hpp │ │ │ │ │ ├── os_thread_manager_impl.pthread.inc │ │ │ │ │ ├── os_thread_manager_types.hpp │ │ │ │ │ ├── os_tick_manager.hpp │ │ │ │ │ ├── os_tick_manager_impl.cpp │ │ │ │ │ ├── os_tick_manager_impl.hpp │ │ │ │ │ ├── os_tick_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_tick_manager_impl.os.windows.hpp │ │ │ │ │ ├── os_tick_manager_impl.std_chrono.hpp │ │ │ │ │ ├── os_timeout_helper.cpp │ │ │ │ │ ├── os_timeout_helper.hpp │ │ │ │ │ ├── os_timeout_helper_impl.os.horizon.cpp │ │ │ │ │ ├── os_timeout_helper_impl.os.horizon.hpp │ │ │ │ │ ├── os_timeout_helper_impl.os.linux.cpp │ │ │ │ │ ├── os_timeout_helper_impl.os.linux.hpp │ │ │ │ │ ├── os_timeout_helper_impl.os.macos.cpp │ │ │ │ │ ├── os_timeout_helper_impl.os.macos.hpp │ │ │ │ │ ├── os_timeout_helper_impl.os.windows.cpp │ │ │ │ │ ├── os_timeout_helper_impl.os.windows.hpp │ │ │ │ │ ├── os_timer_event_helper.cpp │ │ │ │ │ ├── os_timer_event_helper.hpp │ │ │ │ │ ├── os_tls_manager.cpp │ │ │ │ │ ├── os_tls_manager.hpp │ │ │ │ │ ├── os_tls_manager_types.hpp │ │ │ │ │ ├── os_transfer_memory_impl.hpp │ │ │ │ │ ├── os_transfer_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_unsafe_memory_impl.hpp │ │ │ │ │ ├── os_unsafe_memory_impl.os.horizon.cpp │ │ │ │ │ ├── os_utility.cpp │ │ │ │ │ ├── os_utility.hpp │ │ │ │ │ ├── os_vamm_manager.cpp │ │ │ │ │ ├── os_vamm_manager.hpp │ │ │ │ │ ├── os_vamm_manager_impl.os.horizon.hpp │ │ │ │ │ ├── os_vamm_manager_impl.os.linux.hpp │ │ │ │ │ ├── os_vamm_manager_impl.os.macos.hpp │ │ │ │ │ ├── os_vamm_manager_impl.os.windows.hpp │ │ │ │ │ └── os_vamm_manager_types.hpp │ │ │ │ ├── os_argument.cpp │ │ │ │ ├── os_barrier.cpp │ │ │ │ ├── os_busy_mutex.cpp │ │ │ │ ├── os_cache.cpp │ │ │ │ ├── os_condition_variable.cpp │ │ │ │ ├── os_debug.cpp │ │ │ │ ├── os_event.cpp │ │ │ │ ├── os_insecure_memory.cpp │ │ │ │ ├── os_interrupt_event.cpp │ │ │ │ ├── os_io_region.cpp │ │ │ │ ├── os_light_event.cpp │ │ │ │ ├── os_light_message_queue.cpp │ │ │ │ ├── os_light_semaphore.cpp │ │ │ │ ├── os_memory_attribute.cpp │ │ │ │ ├── os_memory_heap.cpp │ │ │ │ ├── os_memory_permission.cpp │ │ │ │ ├── os_message_queue.cpp │ │ │ │ ├── os_multiple_wait.cpp │ │ │ │ ├── os_mutex.cpp │ │ │ │ ├── os_native_handle_api.cpp │ │ │ │ ├── os_process_code_memory.cpp │ │ │ │ ├── os_process_handle_api.cpp │ │ │ │ ├── os_process_memory.cpp │ │ │ │ ├── os_random.cpp │ │ │ │ ├── os_rw_busy_mutex.cpp │ │ │ │ ├── os_rw_lock.cpp │ │ │ │ ├── os_sdk_condition_variable.cpp │ │ │ │ ├── os_sdk_mutex.cpp │ │ │ │ ├── os_sdk_recursive_mutex.cpp │ │ │ │ ├── os_sdk_reply_and_receive.cpp │ │ │ │ ├── os_sdk_thread_local_storage_api.cpp │ │ │ │ ├── os_semaphore.cpp │ │ │ │ ├── os_shared_memory.cpp │ │ │ │ ├── os_system_event.cpp │ │ │ │ ├── os_thread.cpp │ │ │ │ ├── os_thread_local_storage_api.cpp │ │ │ │ ├── os_tick.cpp │ │ │ │ ├── os_timer_event.cpp │ │ │ │ ├── os_transfer_memory.cpp │ │ │ │ ├── os_unsafe_memory.cpp │ │ │ │ └── os_virtual_address_memory.cpp │ │ │ ├── osdbg/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── osdbg_thread_info.generic.hpp │ │ │ │ │ ├── osdbg_thread_info.os.horizon.cpp │ │ │ │ │ ├── osdbg_thread_info.os.horizon.hpp │ │ │ │ │ ├── osdbg_thread_local_region.os.horizon.cpp │ │ │ │ │ ├── osdbg_thread_local_region.os.horizon.hpp │ │ │ │ │ ├── osdbg_thread_type.os.horizon.hpp │ │ │ │ │ └── osdbg_types.hpp │ │ │ │ └── osdbg_thread.cpp │ │ │ ├── patcher/ │ │ │ │ └── patcher_api.cpp │ │ │ ├── pgl/ │ │ │ │ ├── pgl_remote_event_observer.hpp │ │ │ │ ├── pgl_shell_api.cpp │ │ │ │ └── srv/ │ │ │ │ ├── pgl_srv_api.cpp │ │ │ │ ├── pgl_srv_shell.cpp │ │ │ │ ├── pgl_srv_shell.hpp │ │ │ │ ├── pgl_srv_shell_event_observer.cpp │ │ │ │ ├── pgl_srv_shell_event_observer.hpp │ │ │ │ ├── pgl_srv_shell_host_utils.cpp │ │ │ │ ├── pgl_srv_shell_host_utils.hpp │ │ │ │ ├── pgl_srv_shell_interface.cpp │ │ │ │ └── pgl_srv_tipc_utils.hpp │ │ │ ├── pinmux/ │ │ │ │ └── driver/ │ │ │ │ ├── board/ │ │ │ │ │ └── nintendo/ │ │ │ │ │ └── nx/ │ │ │ │ │ ├── pinmux_board_driver_api.cpp │ │ │ │ │ ├── pinmux_board_driver_api.hpp │ │ │ │ │ ├── pinmux_drive_pad_characters.inc │ │ │ │ │ ├── pinmux_initial_drive_pad_config.inc │ │ │ │ │ ├── pinmux_initial_drive_pad_config_hoag.inc │ │ │ │ │ ├── pinmux_initial_pad_config_aula.inc │ │ │ │ │ ├── pinmux_initial_pad_config_calcio.inc │ │ │ │ │ ├── pinmux_initial_pad_config_hoag.inc │ │ │ │ │ ├── pinmux_initial_pad_config_icosa.inc │ │ │ │ │ ├── pinmux_initial_pad_config_iowa.inc │ │ │ │ │ ├── pinmux_pad_characters.inc │ │ │ │ │ ├── pinmux_pad_index.hpp │ │ │ │ │ ├── pinmux_platform_pads.cpp │ │ │ │ │ └── pinmux_platform_pads.hpp │ │ │ │ ├── pinmux_driver_api.cpp │ │ │ │ └── pinmux_select_board_impl.hpp │ │ │ ├── pm/ │ │ │ │ ├── pm_ams.os.horizon.c │ │ │ │ ├── pm_ams.os.horizon.h │ │ │ │ ├── pm_boot_mode_api.cpp │ │ │ │ ├── pm_dmnt_api.cpp │ │ │ │ ├── pm_info_api.cpp │ │ │ │ ├── pm_info_api_weak.cpp │ │ │ │ └── pm_shell_api.cpp │ │ │ ├── powctl/ │ │ │ │ ├── driver/ │ │ │ │ │ └── impl/ │ │ │ │ │ ├── powctl_charger_parameters.board.nintendo_nx.cpp │ │ │ │ │ └── powctl_charger_parameters.board.nintendo_nx.inc │ │ │ │ ├── impl/ │ │ │ │ │ ├── board/ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── powctl_battery_driver.cpp │ │ │ │ │ │ ├── powctl_battery_driver.hpp │ │ │ │ │ │ ├── powctl_board_impl.cpp │ │ │ │ │ │ ├── powctl_board_impl.hpp │ │ │ │ │ │ ├── powctl_bq24193_driver.cpp │ │ │ │ │ │ ├── powctl_bq24193_driver.hpp │ │ │ │ │ │ ├── powctl_charger_driver.cpp │ │ │ │ │ │ ├── powctl_charger_driver.hpp │ │ │ │ │ │ ├── powctl_interrupt_event_handler.cpp │ │ │ │ │ │ ├── powctl_interrupt_event_handler.hpp │ │ │ │ │ │ ├── powctl_max17050_custom_parameters.inc │ │ │ │ │ │ ├── powctl_max17050_driver.cpp │ │ │ │ │ │ ├── powctl_max17050_driver.hpp │ │ │ │ │ │ └── powctl_retry_helper.hpp │ │ │ │ │ ├── powctl_device_management.cpp │ │ │ │ │ ├── powctl_device_management.hpp │ │ │ │ │ ├── powctl_i_power_control_driver.hpp │ │ │ │ │ └── powctl_select_board_driver.hpp │ │ │ │ ├── powctl_battery_api.cpp │ │ │ │ ├── powctl_charger_api.cpp │ │ │ │ ├── powctl_driver_api.cpp │ │ │ │ └── powctl_session_api.cpp │ │ │ ├── psc/ │ │ │ │ ├── psc_pm_module.os.horizon.cpp │ │ │ │ └── psc_remote_pm_module.hpp │ │ │ ├── pwm/ │ │ │ │ ├── driver/ │ │ │ │ │ ├── board/ │ │ │ │ │ │ └── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ │ ├── pwm_impl_pwm_driver_api.cpp │ │ │ │ │ │ │ ├── pwm_impl_pwm_driver_api.hpp │ │ │ │ │ │ │ ├── pwm_pwm_driver_impl.cpp │ │ │ │ │ │ │ └── pwm_pwm_driver_impl.hpp │ │ │ │ │ │ └── pwm_driver_api.cpp │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── pwm_channel_session_impl.cpp │ │ │ │ │ │ ├── pwm_channel_session_impl.hpp │ │ │ │ │ │ ├── pwm_driver_core.cpp │ │ │ │ │ │ └── pwm_driver_core.hpp │ │ │ │ │ ├── pwm_driver_channel_api.cpp │ │ │ │ │ ├── pwm_driver_client_api.cpp │ │ │ │ │ └── pwm_driver_service_api.cpp │ │ │ │ ├── pwm_api.cpp │ │ │ │ └── server/ │ │ │ │ ├── pwm_server_api.cpp │ │ │ │ ├── pwm_server_channel_session_impl.hpp │ │ │ │ ├── pwm_server_manager_impl.cpp │ │ │ │ └── pwm_server_manager_impl.hpp │ │ │ ├── ro/ │ │ │ │ └── impl/ │ │ │ │ └── ro_ro_exception_info.os.horizon.cpp │ │ │ ├── scs/ │ │ │ │ ├── scs_command_processor.cpp │ │ │ │ ├── scs_server_manager.cpp │ │ │ │ ├── scs_shell.cpp │ │ │ │ ├── scs_shell_server.cpp │ │ │ │ └── scs_tenv.cpp │ │ │ ├── service_guard.h │ │ │ ├── settings/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── settings_configuration_id_impl.cpp │ │ │ │ │ ├── settings_configuration_id_impl.hpp │ │ │ │ │ ├── settings_error_report_impl.cpp │ │ │ │ │ ├── settings_error_report_impl.hpp │ │ │ │ │ ├── settings_firmware_version_impl.cpp │ │ │ │ │ ├── settings_firmware_version_impl.hpp │ │ │ │ │ ├── settings_key_value_store.cpp │ │ │ │ │ ├── settings_key_value_store.hpp │ │ │ │ │ ├── settings_platform_region_impl.cpp │ │ │ │ │ ├── settings_platform_region_impl.hpp │ │ │ │ │ ├── settings_product_model_impl.cpp │ │ │ │ │ ├── settings_product_model_impl.hpp │ │ │ │ │ ├── settings_region_impl.cpp │ │ │ │ │ ├── settings_region_impl.hpp │ │ │ │ │ ├── settings_serial_number_impl.cpp │ │ │ │ │ ├── settings_serial_number_impl.hpp │ │ │ │ │ ├── settings_spl.cpp │ │ │ │ │ ├── settings_spl.hpp │ │ │ │ │ ├── settings_static_object.hpp │ │ │ │ │ ├── settings_system_data.cpp │ │ │ │ │ ├── settings_system_data.hpp │ │ │ │ │ ├── settings_system_save_data.cpp │ │ │ │ │ └── settings_system_save_data.hpp │ │ │ │ ├── settings_configuration_id.cpp │ │ │ │ ├── settings_error_report.cpp │ │ │ │ ├── settings_firmware_version.cpp │ │ │ │ ├── settings_fwdbg_api.cpp │ │ │ │ ├── settings_platform_region.cpp │ │ │ │ ├── settings_product_model.cpp │ │ │ │ ├── settings_region.cpp │ │ │ │ └── settings_serial_number.cpp │ │ │ ├── sf/ │ │ │ │ ├── cmif/ │ │ │ │ │ ├── sf_cmif_domain_manager.cpp │ │ │ │ │ ├── sf_cmif_domain_service_object.cpp │ │ │ │ │ ├── sf_cmif_inline_context.cpp │ │ │ │ │ ├── sf_cmif_service_dispatch.cpp │ │ │ │ │ └── sf_cmif_service_object_holder.cpp │ │ │ │ ├── hipc/ │ │ │ │ │ ├── sf_hipc_api.os.generic.cpp │ │ │ │ │ ├── sf_hipc_api.os.horizon.cpp │ │ │ │ │ ├── sf_hipc_mitm_query_api.cpp │ │ │ │ │ ├── sf_hipc_mitm_query_api.hpp │ │ │ │ │ ├── sf_hipc_server_domain_session_manager.cpp │ │ │ │ │ ├── sf_hipc_server_manager.cpp │ │ │ │ │ ├── sf_hipc_server_session_manager.cpp │ │ │ │ │ └── sf_i_hipc_manager.hpp │ │ │ │ ├── sf_default_allocation_policy.cpp │ │ │ │ └── sf_interface_id_for_debug_enforcement.os.horizon.cpp │ │ │ ├── sm/ │ │ │ │ ├── sm_ams.os.horizon.c │ │ │ │ ├── sm_ams.os.horizon.h │ │ │ │ ├── sm_api.cpp │ │ │ │ ├── sm_manager_api.cpp │ │ │ │ ├── sm_mitm_api.cpp │ │ │ │ ├── sm_utils.cpp │ │ │ │ ├── sm_utils.hpp │ │ │ │ ├── smm_ams.os.horizon.c │ │ │ │ └── smm_ams.os.horizon.h │ │ │ ├── socket/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── socket_allocator.hpp │ │ │ │ │ ├── socket_api.hpp │ │ │ │ │ ├── socket_api.os.horizon.cpp │ │ │ │ │ ├── socket_api.os.windows.cpp │ │ │ │ │ └── socket_platform_types_translation.os.windows.cpp │ │ │ │ └── socket_api.cpp │ │ │ ├── spl/ │ │ │ │ ├── impl/ │ │ │ │ │ ├── spl_api_impl.cpp │ │ │ │ │ ├── spl_ctr_drbg.hpp │ │ │ │ │ ├── spl_device_address_mapper.hpp │ │ │ │ │ └── spl_key_slot_cache.hpp │ │ │ │ ├── smc/ │ │ │ │ │ ├── spl_secure_monitor_api.os.generic.cpp │ │ │ │ │ └── spl_secure_monitor_api.os.horizon.cpp │ │ │ │ ├── spl_api.os.generic.cpp │ │ │ │ └── spl_api.os.horizon.cpp │ │ │ ├── sprofile/ │ │ │ │ └── srv/ │ │ │ │ ├── sprofile_srv_api.cpp │ │ │ │ ├── sprofile_srv_fs_utils.cpp │ │ │ │ ├── sprofile_srv_fs_utils.hpp │ │ │ │ ├── sprofile_srv_i_profile_controller_for_debug.hpp │ │ │ │ ├── sprofile_srv_i_profile_importer.hpp │ │ │ │ ├── sprofile_srv_i_profile_reader.hpp │ │ │ │ ├── sprofile_srv_i_profile_update_observer.hpp │ │ │ │ ├── sprofile_srv_i_service_for_bg_agent.hpp │ │ │ │ ├── sprofile_srv_i_service_for_system_process.hpp │ │ │ │ ├── sprofile_srv_i_service_getter.hpp │ │ │ │ ├── sprofile_srv_profile_controller_for_debug_impl.cpp │ │ │ │ ├── sprofile_srv_profile_controller_for_debug_impl.hpp │ │ │ │ ├── sprofile_srv_profile_importer.hpp │ │ │ │ ├── sprofile_srv_profile_importer_impl.cpp │ │ │ │ ├── sprofile_srv_profile_importer_impl.hpp │ │ │ │ ├── sprofile_srv_profile_manager.cpp │ │ │ │ ├── sprofile_srv_profile_manager.hpp │ │ │ │ ├── sprofile_srv_profile_reader_impl.cpp │ │ │ │ ├── sprofile_srv_profile_reader_impl.hpp │ │ │ │ ├── sprofile_srv_profile_update_observer_impl.cpp │ │ │ │ ├── sprofile_srv_profile_update_observer_impl.hpp │ │ │ │ ├── sprofile_srv_service_for_bg_agent.cpp │ │ │ │ ├── sprofile_srv_service_for_bg_agent.hpp │ │ │ │ ├── sprofile_srv_service_for_system_process.cpp │ │ │ │ ├── sprofile_srv_service_for_system_process.hpp │ │ │ │ ├── sprofile_srv_service_getter.cpp │ │ │ │ ├── sprofile_srv_service_getter.hpp │ │ │ │ └── sprofile_srv_types.hpp │ │ │ ├── time/ │ │ │ │ ├── impl/ │ │ │ │ │ └── util/ │ │ │ │ │ └── time_impl_util_api.cpp │ │ │ │ ├── time_api.cpp │ │ │ │ ├── time_calendar_time.cpp │ │ │ │ ├── time_standard_network_system_clock.cpp │ │ │ │ ├── time_standard_steady_clock.cpp │ │ │ │ ├── time_standard_user_system_clock.cpp │ │ │ │ └── time_timezone_api.cpp │ │ │ ├── updater/ │ │ │ │ ├── updater_api.cpp │ │ │ │ ├── updater_bis_management.cpp │ │ │ │ ├── updater_bis_management.hpp │ │ │ │ ├── updater_bis_save.cpp │ │ │ │ ├── updater_bis_save.hpp │ │ │ │ ├── updater_files.cpp │ │ │ │ ├── updater_files.hpp │ │ │ │ ├── updater_paths.cpp │ │ │ │ └── updater_paths.hpp │ │ │ ├── usb/ │ │ │ │ ├── impl/ │ │ │ │ │ └── usb_util.hpp │ │ │ │ ├── usb_device.cpp │ │ │ │ ├── usb_remote_ds_endpoint.cpp │ │ │ │ ├── usb_remote_ds_endpoint.hpp │ │ │ │ ├── usb_remote_ds_interface.cpp │ │ │ │ ├── usb_remote_ds_interface.hpp │ │ │ │ ├── usb_remote_ds_root_session.cpp │ │ │ │ ├── usb_remote_ds_root_session.hpp │ │ │ │ ├── usb_remote_ds_service.cpp │ │ │ │ └── usb_remote_ds_service.hpp │ │ │ ├── util/ │ │ │ │ ├── ini.c │ │ │ │ ├── ini.h │ │ │ │ ├── lz4.c │ │ │ │ ├── lz4.h │ │ │ │ ├── util_compression.cpp │ │ │ │ ├── util_ini.cpp │ │ │ │ └── util_uuid_api.cpp │ │ │ └── wec/ │ │ │ └── wec_api.cpp │ │ └── stratosphere.specs │ └── libvapours/ │ ├── include/ │ │ ├── vapours/ │ │ │ ├── allocator.hpp │ │ │ ├── ams/ │ │ │ │ ├── ams_api_version.h │ │ │ │ ├── ams_fatal_error_context.hpp │ │ │ │ └── ams_target_firmware.h │ │ │ ├── ams_version.h │ │ │ ├── assert.hpp │ │ │ ├── common.hpp │ │ │ ├── compiler.hpp │ │ │ ├── crypto/ │ │ │ │ ├── crypto_aes_128_cmac_generator.hpp │ │ │ │ ├── crypto_aes_cbc_encryptor_decryptor.hpp │ │ │ │ ├── crypto_aes_ccm_encryptor_decryptor.hpp │ │ │ │ ├── crypto_aes_ctr_encryptor_decryptor.hpp │ │ │ │ ├── crypto_aes_decryptor.hpp │ │ │ │ ├── crypto_aes_encryptor.hpp │ │ │ │ ├── crypto_aes_gcm_encryptor.hpp │ │ │ │ ├── crypto_aes_xts_encryptor_decryptor.hpp │ │ │ │ ├── crypto_cbc_decryptor.hpp │ │ │ │ ├── crypto_cbc_encryptor.hpp │ │ │ │ ├── crypto_ccm_decryptor.hpp │ │ │ │ ├── crypto_ccm_encryptor.hpp │ │ │ │ ├── crypto_cmac_generator.hpp │ │ │ │ ├── crypto_csrng.hpp │ │ │ │ ├── crypto_ctr_decryptor.hpp │ │ │ │ ├── crypto_ctr_encryptor.hpp │ │ │ │ ├── crypto_gcm_encryptor.hpp │ │ │ │ ├── crypto_hmac_generator.hpp │ │ │ │ ├── crypto_hmac_sha1_generator.hpp │ │ │ │ ├── crypto_hmac_sha256_generator.hpp │ │ │ │ ├── crypto_md5_generator.hpp │ │ │ │ ├── crypto_memory_clear.hpp │ │ │ │ ├── crypto_memory_compare.hpp │ │ │ │ ├── crypto_rsa_calculator.hpp │ │ │ │ ├── crypto_rsa_oaep_decryptor.hpp │ │ │ │ ├── crypto_rsa_oaep_encryptor.hpp │ │ │ │ ├── crypto_rsa_oaep_sha256_decoder.hpp │ │ │ │ ├── crypto_rsa_oaep_sha256_decryptor.hpp │ │ │ │ ├── crypto_rsa_oaep_sha256_encryptor.hpp │ │ │ │ ├── crypto_rsa_pkcs1_sha256_verifier.hpp │ │ │ │ ├── crypto_rsa_pkcs1_verifier.hpp │ │ │ │ ├── crypto_rsa_pss_sha256_verifier.hpp │ │ │ │ ├── crypto_rsa_pss_verifier.hpp │ │ │ │ ├── crypto_sha1_generator.hpp │ │ │ │ ├── crypto_sha256_generator.hpp │ │ │ │ ├── crypto_sha3_generator.hpp │ │ │ │ ├── crypto_xts_decryptor.hpp │ │ │ │ ├── crypto_xts_encryptor.hpp │ │ │ │ └── impl/ │ │ │ │ ├── crypto_aes_impl.hpp │ │ │ │ ├── crypto_bignum.hpp │ │ │ │ ├── crypto_block_cipher.hpp │ │ │ │ ├── crypto_cbc_mac_impl.hpp │ │ │ │ ├── crypto_cbc_mode_impl.hpp │ │ │ │ ├── crypto_ccm_mode_impl.hpp │ │ │ │ ├── crypto_cmac_impl.hpp │ │ │ │ ├── crypto_ctr_mode_impl.hpp │ │ │ │ ├── crypto_gcm_mode_impl.hpp │ │ │ │ ├── crypto_hash_function.hpp │ │ │ │ ├── crypto_hmac_impl.hpp │ │ │ │ ├── crypto_md5_impl.hpp │ │ │ │ ├── crypto_rsa_oaep_impl.hpp │ │ │ │ ├── crypto_rsa_pkcs1_impl.hpp │ │ │ │ ├── crypto_rsa_pss_impl.hpp │ │ │ │ ├── crypto_sha1_impl.hpp │ │ │ │ ├── crypto_sha256_impl.hpp │ │ │ │ ├── crypto_sha256_impl_constexpr.hpp │ │ │ │ ├── crypto_sha3_impl.hpp │ │ │ │ └── crypto_xts_mode_impl.hpp │ │ │ ├── crypto.hpp │ │ │ ├── dd/ │ │ │ │ ├── dd_cache.hpp │ │ │ │ ├── dd_common_types.hpp │ │ │ │ └── dd_io_mapping.hpp │ │ │ ├── dd.hpp │ │ │ ├── defines.hpp │ │ │ ├── device_code.hpp │ │ │ ├── freebsd/ │ │ │ │ └── tree.hpp │ │ │ ├── impl/ │ │ │ │ ├── compiler_impl.clang.hpp │ │ │ │ └── compiler_impl.gcc.hpp │ │ │ ├── includes.hpp │ │ │ ├── literals.hpp │ │ │ ├── reg.hpp │ │ │ ├── results/ │ │ │ │ ├── cal_results.hpp │ │ │ │ ├── capsrv_results.hpp │ │ │ │ ├── creport_results.hpp │ │ │ │ ├── cs_results.hpp │ │ │ │ ├── dd_results.hpp │ │ │ │ ├── ddsf_results.hpp │ │ │ │ ├── debug_results.hpp │ │ │ │ ├── dmnt_results.hpp │ │ │ │ ├── erpt_results.hpp │ │ │ │ ├── err_results.hpp │ │ │ │ ├── exosphere_results.hpp │ │ │ │ ├── fatal_results.hpp │ │ │ │ ├── fs_results.hpp │ │ │ │ ├── gpio_results.hpp │ │ │ │ ├── hipc_results.hpp │ │ │ │ ├── htc_results.hpp │ │ │ │ ├── htcfs_results.hpp │ │ │ │ ├── htclow_results.hpp │ │ │ │ ├── htcs_results.hpp │ │ │ │ ├── i2c_results.hpp │ │ │ │ ├── kvdb_results.hpp │ │ │ │ ├── loader_results.hpp │ │ │ │ ├── lr_results.hpp │ │ │ │ ├── ncm_results.hpp │ │ │ │ ├── nim_results.hpp │ │ │ │ ├── ns_results.hpp │ │ │ │ ├── os_results.hpp │ │ │ │ ├── osdbg_results.hpp │ │ │ │ ├── pcv_results.hpp │ │ │ │ ├── pgl_results.hpp │ │ │ │ ├── pm_results.hpp │ │ │ │ ├── powctl_results.hpp │ │ │ │ ├── psc_results.hpp │ │ │ │ ├── pwm_results.hpp │ │ │ │ ├── results_common.hpp │ │ │ │ ├── ro_results.hpp │ │ │ │ ├── scs_results.hpp │ │ │ │ ├── sdmmc_results.hpp │ │ │ │ ├── settings_results.hpp │ │ │ │ ├── sf_results.hpp │ │ │ │ ├── sm_results.hpp │ │ │ │ ├── socket_results.hpp │ │ │ │ ├── spl_results.hpp │ │ │ │ ├── sprofile_results.hpp │ │ │ │ ├── svc_results.hpp │ │ │ │ ├── time_results.hpp │ │ │ │ ├── tipc_results.hpp │ │ │ │ ├── tma_results.hpp │ │ │ │ ├── updater_results.hpp │ │ │ │ ├── usb_results.hpp │ │ │ │ └── vi_results.hpp │ │ │ ├── results.hpp │ │ │ ├── sdmmc/ │ │ │ │ ├── sdmmc_build_config.hpp │ │ │ │ ├── sdmmc_common.hpp │ │ │ │ ├── sdmmc_gc_asic.hpp │ │ │ │ ├── sdmmc_mmc.hpp │ │ │ │ └── sdmmc_sd_card.hpp │ │ │ ├── sdmmc.hpp │ │ │ ├── span.hpp │ │ │ ├── svc/ │ │ │ │ ├── arch/ │ │ │ │ │ ├── arm/ │ │ │ │ │ │ └── svc_thread_local_region.hpp │ │ │ │ │ └── arm64/ │ │ │ │ │ └── svc_thread_local_region.hpp │ │ │ │ ├── board/ │ │ │ │ │ ├── generic/ │ │ │ │ │ │ └── svc_device_name.hpp │ │ │ │ │ ├── nintendo/ │ │ │ │ │ │ └── nx/ │ │ │ │ │ │ ├── svc_device_name.hpp │ │ │ │ │ │ ├── svc_hardware_constants.hpp │ │ │ │ │ │ └── svc_io_pool_type.hpp │ │ │ │ │ └── qemu/ │ │ │ │ │ └── virt/ │ │ │ │ │ └── svc_hardware_constants.hpp │ │ │ │ ├── codegen/ │ │ │ │ │ ├── impl/ │ │ │ │ │ │ ├── svc_codegen_impl_code_generator.hpp │ │ │ │ │ │ ├── svc_codegen_impl_common.hpp │ │ │ │ │ │ ├── svc_codegen_impl_kernel_svc_wrapper.hpp │ │ │ │ │ │ ├── svc_codegen_impl_layout.hpp │ │ │ │ │ │ ├── svc_codegen_impl_layout_conversion.hpp │ │ │ │ │ │ ├── svc_codegen_impl_meta_code.hpp │ │ │ │ │ │ └── svc_codegen_impl_parameter.hpp │ │ │ │ │ └── svc_codegen_kernel_svc_wrapper.hpp │ │ │ │ ├── ipc/ │ │ │ │ │ └── svc_message_buffer.hpp │ │ │ │ ├── svc_codegen.hpp │ │ │ │ ├── svc_common.hpp │ │ │ │ ├── svc_definition_macro.hpp │ │ │ │ ├── svc_definitions.hpp │ │ │ │ ├── svc_memory_map.hpp │ │ │ │ ├── svc_select_device_name.hpp │ │ │ │ ├── svc_select_hardware_constants.hpp │ │ │ │ ├── svc_select_io_pool_type.hpp │ │ │ │ ├── svc_select_thread_local_region.hpp │ │ │ │ ├── svc_tick.hpp │ │ │ │ ├── svc_types.hpp │ │ │ │ ├── svc_types_base.hpp │ │ │ │ ├── svc_types_common.hpp │ │ │ │ ├── svc_types_dd.hpp │ │ │ │ ├── svc_types_dmnt.hpp │ │ │ │ ├── svc_types_priv.hpp │ │ │ │ └── svc_version.hpp │ │ │ ├── svc.hpp │ │ │ ├── tegra/ │ │ │ │ ├── tegra_ahb_arbc.hpp │ │ │ │ ├── tegra_apb_misc.hpp │ │ │ │ ├── tegra_avp_cache.hpp │ │ │ │ ├── tegra_clkrst.hpp │ │ │ │ ├── tegra_emc.hpp │ │ │ │ ├── tegra_evp.hpp │ │ │ │ ├── tegra_flow_ctlr.hpp │ │ │ │ ├── tegra_i2c.hpp │ │ │ │ ├── tegra_i2s.hpp │ │ │ │ ├── tegra_ictlr.hpp │ │ │ │ ├── tegra_mc.hpp │ │ │ │ ├── tegra_mipi_cal.hpp │ │ │ │ ├── tegra_mselect.hpp │ │ │ │ ├── tegra_pg_up.hpp │ │ │ │ ├── tegra_pinmux.hpp │ │ │ │ ├── tegra_pmc.hpp │ │ │ │ ├── tegra_pwm.hpp │ │ │ │ ├── tegra_sb.hpp │ │ │ │ ├── tegra_sysctr0.hpp │ │ │ │ └── tegra_timer.hpp │ │ │ ├── tegra.hpp │ │ │ ├── timespan.hpp │ │ │ ├── types.hpp │ │ │ ├── util/ │ │ │ │ ├── arch/ │ │ │ │ │ ├── arm64/ │ │ │ │ │ │ └── util_atomic.hpp │ │ │ │ │ └── generic/ │ │ │ │ │ └── util_atomic.hpp │ │ │ │ ├── impl/ │ │ │ │ │ ├── util_available_index_finder.hpp │ │ │ │ │ └── util_enable_copy_move.hpp │ │ │ │ ├── util_aligned_buffer.hpp │ │ │ │ ├── util_alignment.hpp │ │ │ │ ├── util_atomic.hpp │ │ │ │ ├── util_bitflagset.hpp │ │ │ │ ├── util_bitpack.hpp │ │ │ │ ├── util_bitset.hpp │ │ │ │ ├── util_bitutil.hpp │ │ │ │ ├── util_bounded_map.hpp │ │ │ │ ├── util_character_encoding.hpp │ │ │ │ ├── util_endian.hpp │ │ │ │ ├── util_enum.hpp │ │ │ │ ├── util_exchange.hpp │ │ │ │ ├── util_fixed_map.hpp │ │ │ │ ├── util_fixed_set.hpp │ │ │ │ ├── util_fixed_tree.hpp │ │ │ │ ├── util_format_string.hpp │ │ │ │ ├── util_fourcc.hpp │ │ │ │ ├── util_function_local_static.hpp │ │ │ │ ├── util_i_function.hpp │ │ │ │ ├── util_in_place.hpp │ │ │ │ ├── util_int_util.hpp │ │ │ │ ├── util_intrusive_list.hpp │ │ │ │ ├── util_intrusive_red_black_tree.hpp │ │ │ │ ├── util_mutex_utils.hpp │ │ │ │ ├── util_optional.hpp │ │ │ │ ├── util_overlap.hpp │ │ │ │ ├── util_parent_of_member.hpp │ │ │ │ ├── util_pointer_util.hpp │ │ │ │ ├── util_range.hpp │ │ │ │ ├── util_scope_guard.hpp │ │ │ │ ├── util_size.hpp │ │ │ │ ├── util_specialization_of.hpp │ │ │ │ ├── util_string_util.hpp │ │ │ │ ├── util_string_view.hpp │ │ │ │ ├── util_timer.hpp │ │ │ │ ├── util_tinymt.hpp │ │ │ │ ├── util_type_traits.hpp │ │ │ │ ├── util_typed_storage.hpp │ │ │ │ ├── util_utf8_string_util.hpp │ │ │ │ ├── util_uuid.hpp │ │ │ │ └── util_variadic.hpp │ │ │ └── util.hpp │ │ └── vapours.hpp │ └── source/ │ ├── crypto/ │ │ ├── crypto_aes_cbc_encryptor_decryptor.cpp │ │ ├── crypto_aes_ctr_encryptor_decryptor.cpp │ │ ├── crypto_hmac_sha1_generator.cpp │ │ ├── crypto_hmac_sha256_generator.cpp │ │ ├── crypto_md5_generator.cpp │ │ ├── crypto_memory_clear.cpp │ │ ├── crypto_memory_compare.arch.arm.cpp │ │ ├── crypto_memory_compare.arch.arm64.cpp │ │ ├── crypto_memory_compare.arch.generic.cpp │ │ ├── crypto_sha1_generator.cpp │ │ ├── crypto_sha256_generator.cpp │ │ └── impl/ │ │ ├── crypto_aes_impl.arch.arm64.cpp │ │ ├── crypto_aes_impl.arch.x64.cpp │ │ ├── crypto_aes_impl.arch.x64.hpp │ │ ├── crypto_bignum.cpp │ │ ├── crypto_bignum_operations.cpp │ │ ├── crypto_bignum_operations_asm.arch.arm64.s │ │ ├── crypto_cbc_mac_impl.arch.generic.cpp │ │ ├── crypto_cbc_mac_impl.cpp │ │ ├── crypto_ctr_mode_impl.arch.arm64.cpp │ │ ├── crypto_ctr_mode_impl.arch.x64.cpp │ │ ├── crypto_gcm_mode_impl.arch.arm64.cpp │ │ ├── crypto_md5_impl.cpp │ │ ├── crypto_sha1_impl.arch.arm64.cpp │ │ ├── crypto_sha1_impl.arch.generic.cpp │ │ ├── crypto_sha256_impl.arch.arm64.cpp │ │ ├── crypto_sha256_impl.arch.generic.cpp │ │ ├── crypto_sha3_impl.cpp │ │ ├── crypto_update_impl.hpp │ │ ├── crypto_xts_mode_impl.arch.arm64.cpp │ │ ├── crypto_xts_mode_impl.arch.generic.cpp │ │ └── crypto_xts_mode_impl.cpp │ ├── dd/ │ │ ├── dd_cache.cpp │ │ ├── dd_io_mapping.os.horizon.cpp │ │ └── impl/ │ │ ├── dd_cache_impl.os.horizon.hpp │ │ ├── dd_cache_impl.os.linux.hpp │ │ ├── dd_cache_impl.os.macos.hpp │ │ ├── dd_cache_impl.os.windows.hpp │ │ └── dd_select_cache_impl.hpp │ ├── result/ │ │ └── result_get_name.cpp │ ├── sdmmc/ │ │ ├── impl/ │ │ │ ├── sdmmc_base_device_accessor.cpp │ │ │ ├── sdmmc_base_device_accessor.hpp │ │ │ ├── sdmmc_clock_reset_controller.board.nintendo_nx.cpp │ │ │ ├── sdmmc_clock_reset_controller.hpp │ │ │ ├── sdmmc_clock_reset_controller.pcv.board.nintendo_nx.cpp │ │ │ ├── sdmmc_clock_reset_controller.pcv.board.nintendo_nx.hpp │ │ │ ├── sdmmc_clock_reset_controller.reg.board.nintendo_nx.cpp │ │ │ ├── sdmmc_clock_reset_controller.reg.board.nintendo_nx.hpp │ │ │ ├── sdmmc_device_detector.cpp │ │ │ ├── sdmmc_device_detector.hpp │ │ │ ├── sdmmc_gc_asic_device_accessor.cpp │ │ │ ├── sdmmc_gc_asic_device_accessor.hpp │ │ │ ├── sdmmc_i_device_accessor.hpp │ │ │ ├── sdmmc_i_host_controller.hpp │ │ │ ├── sdmmc_io_impl.board.nintendo_nx.cpp │ │ │ ├── sdmmc_io_impl.board.nintendo_nx.hpp │ │ │ ├── sdmmc_mmc_device_accessor.cpp │ │ │ ├── sdmmc_mmc_device_accessor.hpp │ │ │ ├── sdmmc_port_gc_asic0.board.nintendo_nx.cpp │ │ │ ├── sdmmc_port_gc_asic0.hpp │ │ │ ├── sdmmc_port_mmc0.board.nintendo_nx.cpp │ │ │ ├── sdmmc_port_mmc0.hpp │ │ │ ├── sdmmc_port_sd_card0.board.nintendo_nx.cpp │ │ │ ├── sdmmc_port_sd_card0.hpp │ │ │ ├── sdmmc_sd_card_device_accessor.cpp │ │ │ ├── sdmmc_sd_card_device_accessor.hpp │ │ │ ├── sdmmc_sd_host_standard_controller.cpp │ │ │ ├── sdmmc_sd_host_standard_controller.hpp │ │ │ ├── sdmmc_sd_host_standard_registers.hpp │ │ │ ├── sdmmc_sdmmc_controller.board.nintendo_nx.cpp │ │ │ ├── sdmmc_sdmmc_controller.board.nintendo_nx.hpp │ │ │ ├── sdmmc_select_sdmmc_controller.hpp │ │ │ ├── sdmmc_timer.cpp │ │ │ └── sdmmc_timer.hpp │ │ ├── sdmmc_common.cpp │ │ ├── sdmmc_gc_asic.cpp │ │ ├── sdmmc_mmc.cpp │ │ └── sdmmc_sd_card.cpp │ ├── test/ │ │ └── test_intrusive_red_black_tree.cpp │ └── util/ │ ├── util_format_string.cpp │ └── util_utf8_string_util.cpp ├── mesosphere/ │ ├── Makefile │ ├── build_mesosphere.py │ ├── kernel/ │ │ ├── Makefile │ │ ├── kernel.ld │ │ ├── kernel.mk │ │ ├── kernel.specs │ │ └── source/ │ │ ├── arch/ │ │ │ └── arm64/ │ │ │ ├── exception_vectors.s │ │ │ ├── init/ │ │ │ │ ├── kern_init_core.cpp │ │ │ │ └── start.s │ │ │ ├── kern_exception_handlers_asm.s │ │ │ ├── kern_k_scheduler_asm.s │ │ │ ├── kern_k_thread_context_asm.s │ │ │ └── svc/ │ │ │ └── kern_svc_tables_asm.s │ │ ├── kern_kernel_instantiations.cpp │ │ └── libc/ │ │ ├── arch/ │ │ │ └── arm64/ │ │ │ ├── asmdefs.h │ │ │ ├── memcmp.arch.arm64.s │ │ │ ├── memcpy.arch.arm64.s │ │ │ └── memset.arch.arm64.s │ │ ├── kern_env.cpp │ │ ├── kern_libc_config.arch.arm64.h │ │ ├── kern_libc_config.h │ │ └── kern_libc_generic.c │ ├── kernel_ldr/ │ │ ├── Makefile │ │ ├── kernel_ldr.ld │ │ ├── kernel_ldr.mk │ │ ├── kernel_ldr.specs │ │ └── source/ │ │ ├── arch/ │ │ │ └── arm64/ │ │ │ ├── exceptions.s │ │ │ ├── kern_init_loader_asm.s │ │ │ └── start.s │ │ ├── board/ │ │ │ └── nintendo/ │ │ │ └── nx/ │ │ │ └── kern_init_loader_board_setup.cpp │ │ ├── kern_init_loader.cpp │ │ ├── kern_init_loader_asm.hpp │ │ ├── kern_init_loader_board_default_setup.arch.arm64.cpp │ │ ├── kern_init_loader_board_setup.hpp │ │ ├── kern_loader_panic.cpp │ │ └── libc/ │ │ ├── kern_libc_config.arch.arm64.h │ │ ├── kern_libc_config.h │ │ └── kern_libc_generic.c │ └── mesosphere.mk ├── stratosphere/ │ ├── LogManager/ │ │ ├── LogManager.json │ │ ├── Makefile │ │ ├── source/ │ │ │ └── lm_main.cpp │ │ └── system_module.mk │ ├── Makefile │ ├── TioServer/ │ │ ├── Makefile │ │ ├── TioServer.json │ │ ├── source/ │ │ │ ├── tio_file_server.cpp │ │ │ ├── tio_file_server.hpp │ │ │ ├── tio_file_server_htcs_server.cpp │ │ │ ├── tio_file_server_htcs_server.hpp │ │ │ ├── tio_file_server_packet.hpp │ │ │ ├── tio_file_server_processor.cpp │ │ │ ├── tio_file_server_processor.hpp │ │ │ ├── tio_main.cpp │ │ │ ├── tio_sd_card_observer.cpp │ │ │ └── tio_sd_card_observer.hpp │ │ └── system_module.mk │ ├── ams_mitm/ │ │ ├── Makefile │ │ ├── ams_mitm.json │ │ ├── source/ │ │ │ ├── amsmitm_fs_utils.cpp │ │ │ ├── amsmitm_fs_utils.hpp │ │ │ ├── amsmitm_initialization.cpp │ │ │ ├── amsmitm_initialization.hpp │ │ │ ├── amsmitm_main.cpp │ │ │ ├── amsmitm_module.hpp │ │ │ ├── amsmitm_module_management.cpp │ │ │ ├── amsmitm_module_management.hpp │ │ │ ├── amsmitm_prodinfo_utils.cpp │ │ │ ├── amsmitm_prodinfo_utils.hpp │ │ │ ├── bpc_mitm/ │ │ │ │ ├── bpc_ams_module.cpp │ │ │ │ ├── bpc_ams_module.hpp │ │ │ │ ├── bpc_ams_power_utils.cpp │ │ │ │ ├── bpc_ams_power_utils.hpp │ │ │ │ ├── bpc_ams_service.cpp │ │ │ │ ├── bpc_ams_service.hpp │ │ │ │ ├── bpc_mitm_service.cpp │ │ │ │ ├── bpc_mitm_service.hpp │ │ │ │ ├── bpcmitm_module.cpp │ │ │ │ └── bpcmitm_module.hpp │ │ │ ├── dns_mitm/ │ │ │ │ ├── dnsmitm_debug.cpp │ │ │ │ ├── dnsmitm_debug.hpp │ │ │ │ ├── dnsmitm_host_redirection.cpp │ │ │ │ ├── dnsmitm_host_redirection.hpp │ │ │ │ ├── dnsmitm_module.cpp │ │ │ │ ├── dnsmitm_module.hpp │ │ │ │ ├── dnsmitm_resolver_impl.cpp │ │ │ │ ├── dnsmitm_resolver_impl.hpp │ │ │ │ ├── serializer/ │ │ │ │ │ ├── serializer.cpp │ │ │ │ │ ├── serializer.hpp │ │ │ │ │ ├── serializer_impls_addrinfo.cpp │ │ │ │ │ ├── serializer_impls_hostent.cpp │ │ │ │ │ ├── serializer_impls_in_addr.cpp │ │ │ │ │ ├── serializer_impls_ints.cpp │ │ │ │ │ ├── serializer_impls_sockaddrin_4.cpp │ │ │ │ │ ├── serializer_impls_sockaddrin_6.cpp │ │ │ │ │ └── serializer_impls_string.cpp │ │ │ │ ├── sfdnsres_shim.c │ │ │ │ ├── sfdnsres_shim.h │ │ │ │ └── socket_allocator.hpp │ │ │ ├── fs_mitm/ │ │ │ │ ├── fs_mitm_service.cpp │ │ │ │ ├── fs_mitm_service.hpp │ │ │ │ ├── fs_shim.c │ │ │ │ ├── fs_shim.h │ │ │ │ ├── fsmitm_boot0storage.cpp │ │ │ │ ├── fsmitm_boot0storage.hpp │ │ │ │ ├── fsmitm_calibration_binary_storage.cpp │ │ │ │ ├── fsmitm_calibration_binary_storage.hpp │ │ │ │ ├── fsmitm_layered_romfs_storage.cpp │ │ │ │ ├── fsmitm_layered_romfs_storage.hpp │ │ │ │ ├── fsmitm_module.cpp │ │ │ │ ├── fsmitm_module.hpp │ │ │ │ ├── fsmitm_readonly_layered_filesystem.hpp │ │ │ │ ├── fsmitm_romfs.cpp │ │ │ │ ├── fsmitm_romfs.hpp │ │ │ │ ├── fsmitm_save_utils.cpp │ │ │ │ ├── fsmitm_save_utils.hpp │ │ │ │ └── memlet/ │ │ │ │ ├── memlet.c │ │ │ │ ├── memlet.h │ │ │ │ └── service_guard.h │ │ │ ├── mitm_pm/ │ │ │ │ ├── mitm_pm_module.cpp │ │ │ │ ├── mitm_pm_module.hpp │ │ │ │ ├── mitm_pm_service.cpp │ │ │ │ └── mitm_pm_service.hpp │ │ │ ├── ns_mitm/ │ │ │ │ ├── ns_am_mitm_service.cpp │ │ │ │ ├── ns_am_mitm_service.hpp │ │ │ │ ├── ns_shim.c │ │ │ │ ├── ns_shim.h │ │ │ │ ├── ns_web_mitm_service.cpp │ │ │ │ ├── ns_web_mitm_service.hpp │ │ │ │ ├── nsmitm_module.cpp │ │ │ │ └── nsmitm_module.hpp │ │ │ ├── set_mitm/ │ │ │ │ ├── set_mitm_service.cpp │ │ │ │ ├── set_mitm_service.hpp │ │ │ │ ├── set_shim.c │ │ │ │ ├── set_shim.h │ │ │ │ ├── setmitm_module.cpp │ │ │ │ ├── setmitm_module.hpp │ │ │ │ ├── setsys_mitm_service.cpp │ │ │ │ ├── setsys_mitm_service.hpp │ │ │ │ ├── setsys_shim.c │ │ │ │ ├── setsys_shim.h │ │ │ │ ├── settings_fwdbg_api_override.cpp │ │ │ │ ├── settings_sd_kvs.cpp │ │ │ │ └── settings_sd_kvs.hpp │ │ │ └── sysupdater/ │ │ │ ├── sysupdater_apply_manager.cpp │ │ │ ├── sysupdater_apply_manager.hpp │ │ │ ├── sysupdater_async_impl.cpp │ │ │ ├── sysupdater_async_impl.hpp │ │ │ ├── sysupdater_async_thread_allocator.cpp │ │ │ ├── sysupdater_async_thread_allocator.hpp │ │ │ ├── sysupdater_fs_utils.cpp │ │ │ ├── sysupdater_fs_utils.hpp │ │ │ ├── sysupdater_module.cpp │ │ │ ├── sysupdater_module.hpp │ │ │ ├── sysupdater_service.cpp │ │ │ ├── sysupdater_service.hpp │ │ │ ├── sysupdater_thread_allocator.cpp │ │ │ └── sysupdater_thread_allocator.hpp │ │ └── system_module.mk │ ├── boot/ │ │ ├── Makefile │ │ ├── boot.json │ │ ├── source/ │ │ │ ├── api_overrides/ │ │ │ │ ├── pcv_clkrst_api_for_boot.board.nintendo_nx.cpp │ │ │ │ └── regulator_api_for_boot.cpp │ │ │ ├── boot_battery_driver.hpp │ │ │ ├── boot_battery_icon_charging.inc │ │ │ ├── boot_battery_icon_charging_red.inc │ │ │ ├── boot_battery_icon_low.inc │ │ │ ├── boot_battery_icons.cpp │ │ │ ├── boot_battery_icons.hpp │ │ │ ├── boot_boot_reason.cpp │ │ │ ├── boot_boot_reason.hpp │ │ │ ├── boot_change_voltage.cpp │ │ │ ├── boot_change_voltage.hpp │ │ │ ├── boot_charger_driver.hpp │ │ │ ├── boot_check_battery.cpp │ │ │ ├── boot_check_battery.hpp │ │ │ ├── boot_check_clock.cpp │ │ │ ├── boot_check_clock.hpp │ │ │ ├── boot_clock_initial_configuration.cpp │ │ │ ├── boot_clock_initial_configuration.hpp │ │ │ ├── boot_display.cpp │ │ │ ├── boot_display.hpp │ │ │ ├── boot_display_config.inc │ │ │ ├── boot_driver_management.cpp │ │ │ ├── boot_driver_management.hpp │ │ │ ├── boot_fan_enable.cpp │ │ │ ├── boot_fan_enable.hpp │ │ │ ├── boot_i2c_utils.cpp │ │ │ ├── boot_i2c_utils.hpp │ │ │ ├── boot_main.cpp │ │ │ ├── boot_pinmux_initial_configuration.cpp │ │ │ ├── boot_pinmux_initial_configuration.hpp │ │ │ ├── boot_pmic_driver.cpp │ │ │ ├── boot_pmic_driver.hpp │ │ │ ├── boot_power_utils.cpp │ │ │ ├── boot_power_utils.hpp │ │ │ ├── boot_registers_di.hpp │ │ │ ├── boot_repair_boot_images.cpp │ │ │ ├── boot_repair_boot_images.hpp │ │ │ ├── boot_rtc_driver.cpp │ │ │ ├── boot_rtc_driver.hpp │ │ │ ├── boot_splash_screen.cpp │ │ │ ├── boot_splash_screen.hpp │ │ │ ├── boot_splash_screen_notext.inc │ │ │ └── boot_splash_screen_text.inc │ │ └── system_module.mk │ ├── boot2/ │ │ ├── Makefile │ │ ├── boot2.json │ │ ├── source/ │ │ │ └── boot2_main.cpp │ │ └── system_module.mk │ ├── creport/ │ │ ├── Makefile │ │ ├── creport.json │ │ ├── source/ │ │ │ ├── creport_crash_report.cpp │ │ │ ├── creport_crash_report.hpp │ │ │ ├── creport_main.cpp │ │ │ ├── creport_modules.cpp │ │ │ ├── creport_modules.hpp │ │ │ ├── creport_scoped_file.cpp │ │ │ ├── creport_scoped_file.hpp │ │ │ ├── creport_threads.cpp │ │ │ ├── creport_threads.hpp │ │ │ ├── creport_utils.cpp │ │ │ └── creport_utils.hpp │ │ └── system_module.mk │ ├── cs/ │ │ ├── Makefile │ │ ├── cs.json │ │ ├── source/ │ │ │ └── cs_main.cpp │ │ └── system_module.mk │ ├── dmnt/ │ │ ├── Makefile │ │ ├── dmnt.json │ │ ├── source/ │ │ │ ├── cheat/ │ │ │ │ ├── dmnt_cheat_service.cpp │ │ │ │ ├── dmnt_cheat_service.hpp │ │ │ │ └── impl/ │ │ │ │ ├── dmnt_cheat_api.cpp │ │ │ │ ├── dmnt_cheat_api.hpp │ │ │ │ ├── dmnt_cheat_debug_events_manager.cpp │ │ │ │ ├── dmnt_cheat_debug_events_manager.hpp │ │ │ │ ├── dmnt_cheat_vm.cpp │ │ │ │ └── dmnt_cheat_vm.hpp │ │ │ └── dmnt_main.cpp │ │ └── system_module.mk │ ├── dmnt.gen2/ │ │ ├── Makefile │ │ ├── dmnt.gen2.json │ │ ├── source/ │ │ │ ├── dmnt2_breakpoint_manager.cpp │ │ │ ├── dmnt2_breakpoint_manager.hpp │ │ │ ├── dmnt2_breakpoint_manager_base.cpp │ │ │ ├── dmnt2_breakpoint_manager_base.hpp │ │ │ ├── dmnt2_debug_log.cpp │ │ │ ├── dmnt2_debug_log.hpp │ │ │ ├── dmnt2_debug_process.cpp │ │ │ ├── dmnt2_debug_process.hpp │ │ │ ├── dmnt2_gdb_packet_io.cpp │ │ │ ├── dmnt2_gdb_packet_io.hpp │ │ │ ├── dmnt2_gdb_server.cpp │ │ │ ├── dmnt2_gdb_server.hpp │ │ │ ├── dmnt2_gdb_server_impl.cpp │ │ │ ├── dmnt2_gdb_server_impl.hpp │ │ │ ├── dmnt2_gdb_signal.hpp │ │ │ ├── dmnt2_hardware_breakpoint.cpp │ │ │ ├── dmnt2_hardware_breakpoint.hpp │ │ │ ├── dmnt2_hardware_watchpoint.cpp │ │ │ ├── dmnt2_hardware_watchpoint.hpp │ │ │ ├── dmnt2_main.cpp │ │ │ ├── dmnt2_module_definition.hpp │ │ │ ├── dmnt2_software_breakpoint.cpp │ │ │ ├── dmnt2_software_breakpoint.hpp │ │ │ ├── dmnt2_transport_layer.cpp │ │ │ ├── dmnt2_transport_layer.hpp │ │ │ ├── dmnt2_transport_receive_buffer.cpp │ │ │ ├── dmnt2_transport_receive_buffer.hpp │ │ │ ├── dmnt2_transport_session.cpp │ │ │ └── dmnt2_transport_session.hpp │ │ └── system_module.mk │ ├── eclct.stub/ │ │ ├── Makefile │ │ ├── eclct.stub.json │ │ ├── source/ │ │ │ └── eclct_stub.cpp │ │ └── system_module.mk │ ├── erpt/ │ │ ├── Makefile │ │ ├── erpt.json │ │ ├── source/ │ │ │ └── erpt_main.cpp │ │ └── system_module.mk │ ├── fatal/ │ │ ├── Makefile │ │ ├── fatal.json │ │ ├── source/ │ │ │ ├── fatal_ams_logo.inc │ │ │ ├── fatal_config.cpp │ │ │ ├── fatal_config.hpp │ │ │ ├── fatal_debug.cpp │ │ │ ├── fatal_debug.hpp │ │ │ ├── fatal_event_manager.cpp │ │ │ ├── fatal_event_manager.hpp │ │ │ ├── fatal_font.cpp │ │ │ ├── fatal_font.hpp │ │ │ ├── fatal_main.cpp │ │ │ ├── fatal_repair.cpp │ │ │ ├── fatal_repair.hpp │ │ │ ├── fatal_scoped_file.cpp │ │ │ ├── fatal_scoped_file.hpp │ │ │ ├── fatal_service.cpp │ │ │ ├── fatal_service.hpp │ │ │ ├── fatal_service_for_self.hpp │ │ │ ├── fatal_task.cpp │ │ │ ├── fatal_task.hpp │ │ │ ├── fatal_task_clock.cpp │ │ │ ├── fatal_task_clock.hpp │ │ │ ├── fatal_task_error_report.cpp │ │ │ ├── fatal_task_error_report.hpp │ │ │ ├── fatal_task_power.cpp │ │ │ ├── fatal_task_power.hpp │ │ │ ├── fatal_task_screen.cpp │ │ │ ├── fatal_task_screen.hpp │ │ │ ├── fatal_task_sound.cpp │ │ │ ├── fatal_task_sound.hpp │ │ │ └── stb_truetype.h │ │ └── system_module.mk │ ├── fs/ │ │ ├── Makefile │ │ ├── fs.json │ │ ├── source/ │ │ │ └── fs_main.cpp │ │ └── system_module.mk │ ├── htc/ │ │ ├── Makefile │ │ ├── htc.json │ │ ├── source/ │ │ │ └── htc_main.cpp │ │ └── system_module.mk │ ├── jpegdec/ │ │ ├── Makefile │ │ ├── jpegdec.json │ │ ├── source/ │ │ │ ├── jpegdec_environment.cpp │ │ │ ├── jpegdec_main.cpp │ │ │ ├── jpegdec_memory_management.cpp │ │ │ └── jpegdec_memory_management.hpp │ │ └── system_module.mk │ ├── loader/ │ │ ├── Makefile │ │ ├── loader.json │ │ ├── source/ │ │ │ ├── ldr_argument_store.cpp │ │ │ ├── ldr_argument_store.hpp │ │ │ ├── ldr_capabilities.cpp │ │ │ ├── ldr_capabilities.hpp │ │ │ ├── ldr_content_management.cpp │ │ │ ├── ldr_content_management.hpp │ │ │ ├── ldr_development_manager.cpp │ │ │ ├── ldr_development_manager.hpp │ │ │ ├── ldr_embedded_usb_patches.inc │ │ │ ├── ldr_launch_record.cpp │ │ │ ├── ldr_launch_record.hpp │ │ │ ├── ldr_loader_service.cpp │ │ │ ├── ldr_loader_service.hpp │ │ │ ├── ldr_main.cpp │ │ │ ├── ldr_meta.cpp │ │ │ ├── ldr_meta.hpp │ │ │ ├── ldr_patcher.cpp │ │ │ ├── ldr_patcher.hpp │ │ │ ├── ldr_process_creation.cpp │ │ │ ├── ldr_process_creation.hpp │ │ │ ├── ldr_ro_manager.cpp │ │ │ └── ldr_ro_manager.hpp │ │ └── system_module.mk │ ├── memlet/ │ │ ├── Makefile │ │ ├── memlet.json │ │ ├── source/ │ │ │ ├── memlet_main.cpp │ │ │ ├── memlet_service.cpp │ │ │ └── memlet_service.hpp │ │ └── system_module.mk │ ├── ncm/ │ │ ├── Makefile │ │ ├── ncm.json │ │ ├── source/ │ │ │ └── ncm_main.cpp │ │ └── system_module.mk │ ├── pgl/ │ │ ├── Makefile │ │ ├── pgl.json │ │ ├── source/ │ │ │ └── pgl_main.cpp │ │ └── system_module.mk │ ├── pm/ │ │ ├── Makefile │ │ ├── pm.json │ │ ├── source/ │ │ │ ├── impl/ │ │ │ │ ├── pm_process_attributes.hpp │ │ │ │ ├── pm_process_info.cpp │ │ │ │ ├── pm_process_info.hpp │ │ │ │ ├── pm_process_manager.cpp │ │ │ │ ├── pm_process_manager.hpp │ │ │ │ ├── pm_process_tracker.cpp │ │ │ │ ├── pm_process_tracker.hpp │ │ │ │ ├── pm_spec.cpp │ │ │ │ └── pm_spec.hpp │ │ │ ├── pm_boot_mode_service.cpp │ │ │ ├── pm_boot_mode_service.hpp │ │ │ ├── pm_debug_monitor_service.cpp │ │ │ ├── pm_debug_monitor_service.hpp │ │ │ ├── pm_info_service.cpp │ │ │ ├── pm_info_service.hpp │ │ │ ├── pm_main.cpp │ │ │ ├── pm_shell_service.cpp │ │ │ └── pm_shell_service.hpp │ │ └── system_module.mk │ ├── ro/ │ │ ├── Makefile │ │ ├── ro.json │ │ ├── source/ │ │ │ ├── impl/ │ │ │ │ ├── ro_nro_utils.cpp │ │ │ │ ├── ro_nro_utils.hpp │ │ │ │ ├── ro_nrr_utils.cpp │ │ │ │ ├── ro_nrr_utils.hpp │ │ │ │ ├── ro_patcher.cpp │ │ │ │ ├── ro_patcher.hpp │ │ │ │ ├── ro_random.cpp │ │ │ │ ├── ro_random.hpp │ │ │ │ ├── ro_service_impl.cpp │ │ │ │ └── ro_service_impl.hpp │ │ │ ├── ro_debug_monitor_service.cpp │ │ │ ├── ro_debug_monitor_service.hpp │ │ │ ├── ro_main.cpp │ │ │ ├── ro_ro_service.cpp │ │ │ └── ro_ro_service.hpp │ │ └── system_module.mk │ ├── sm/ │ │ ├── Makefile │ │ ├── sm.json │ │ ├── source/ │ │ │ ├── impl/ │ │ │ │ ├── sm_service_manager.cpp │ │ │ │ └── sm_service_manager.hpp │ │ │ ├── sm_main.cpp │ │ │ ├── sm_manager_service.hpp │ │ │ ├── sm_tipc_server.cpp │ │ │ ├── sm_tipc_server.hpp │ │ │ ├── sm_user_service.cpp │ │ │ ├── sm_user_service.hpp │ │ │ └── sm_wait_list.hpp │ │ └── system_module.mk │ ├── spl/ │ │ ├── Makefile │ │ ├── source/ │ │ │ ├── spl_crypto_service.hpp │ │ │ ├── spl_deprecated_service.hpp │ │ │ ├── spl_device_unique_data_service.hpp │ │ │ ├── spl_es_service.hpp │ │ │ ├── spl_fs_service.hpp │ │ │ ├── spl_general_service.hpp │ │ │ ├── spl_main.cpp │ │ │ ├── spl_manu_service.hpp │ │ │ ├── spl_random_service.hpp │ │ │ ├── spl_secure_monitor_manager.cpp │ │ │ ├── spl_secure_monitor_manager.hpp │ │ │ └── spl_ssl_service.hpp │ │ ├── spl.json │ │ └── system_module.mk │ └── stratosphere.mk ├── tests/ │ ├── Licensing/ │ │ └── Catch2-LICENSE.txt │ ├── TestFs/ │ │ ├── Makefile │ │ ├── source/ │ │ │ └── test.cpp │ │ └── unit_test.mk │ ├── TestOsEvents/ │ │ ├── Makefile │ │ ├── source/ │ │ │ └── test.cpp │ │ └── unit_test.mk │ ├── TestSocket/ │ │ ├── Makefile │ │ ├── source/ │ │ │ └── test.cpp │ │ └── unit_test.mk │ ├── TestStack/ │ │ ├── Makefile │ │ ├── source/ │ │ │ └── test.cpp │ │ └── unit_test.mk │ └── TestSvc/ │ ├── Makefile │ ├── TestSvc.json │ ├── TestSvc.npdm.json │ └── source/ │ ├── doctest.h │ ├── test_main.cpp │ ├── test_preemption_priority.cpp │ ├── test_set_heap_size.cpp │ ├── test_set_memory_permission.cpp │ ├── test_sleep_thread.cpp │ ├── test_thread_creation.arch.arm64.s │ ├── test_thread_creation.cpp │ ├── test_thread_pinning.cpp │ ├── util_check_memory.hpp │ ├── util_common.hpp │ ├── util_scoped_heap.hpp │ └── util_test_framework.hpp ├── thermosphere/ │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── linker.ld │ ├── linker.specs │ └── src/ │ ├── exceptions.c │ ├── exceptions.h │ ├── main.c │ ├── regs.h │ └── start.s ├── troposphere/ │ ├── Makefile │ ├── daybreak/ │ │ ├── Makefile │ │ ├── nanovg/ │ │ │ ├── .gitignore │ │ │ ├── .gitrepo │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── include/ │ │ │ │ ├── nanovg/ │ │ │ │ │ ├── dk_renderer.hpp │ │ │ │ │ ├── fontstash.h │ │ │ │ │ ├── framework/ │ │ │ │ │ │ ├── CApplication.h │ │ │ │ │ │ ├── CCmdMemRing.h │ │ │ │ │ │ ├── CDescriptorSet.h │ │ │ │ │ │ ├── CExternalImage.h │ │ │ │ │ │ ├── CIntrusiveList.h │ │ │ │ │ │ ├── CIntrusiveTree.h │ │ │ │ │ │ ├── CMemPool.h │ │ │ │ │ │ ├── CShader.h │ │ │ │ │ │ ├── FileLoader.h │ │ │ │ │ │ └── common.h │ │ │ │ │ ├── nanovg_gl_utils.h │ │ │ │ │ ├── stb_image.h │ │ │ │ │ └── stb_truetype.h │ │ │ │ ├── nanovg.h │ │ │ │ ├── nanovg_dk.h │ │ │ │ └── nanovg_gl.h │ │ │ ├── shaders/ │ │ │ │ ├── fill_aa_fsh.glsl │ │ │ │ ├── fill_fsh.glsl │ │ │ │ └── fill_vsh.glsl │ │ │ └── source/ │ │ │ ├── dk_renderer.cpp │ │ │ ├── framework/ │ │ │ │ ├── CApplication.cpp │ │ │ │ ├── CExternalImage.cpp │ │ │ │ ├── CIntrusiveTree.cpp │ │ │ │ ├── CMemPool.cpp │ │ │ │ ├── CShader.cpp │ │ │ │ ├── FileLoader.cpp │ │ │ │ └── LICENSE │ │ │ └── nanovg.c │ │ └── source/ │ │ ├── ams_su.c │ │ ├── ams_su.h │ │ ├── assert.hpp │ │ ├── main.cpp │ │ ├── service_guard.h │ │ ├── ui.cpp │ │ ├── ui.hpp │ │ ├── ui_util.cpp │ │ └── ui_util.hpp │ ├── haze/ │ │ ├── Makefile │ │ ├── include/ │ │ │ ├── haze/ │ │ │ │ ├── assert.hpp │ │ │ │ ├── async_usb_server.hpp │ │ │ │ ├── common.hpp │ │ │ │ ├── console_main_loop.hpp │ │ │ │ ├── device_properties.hpp │ │ │ │ ├── event_reactor.hpp │ │ │ │ ├── file_system_proxy.hpp │ │ │ │ ├── ptp.hpp │ │ │ │ ├── ptp_data_builder.hpp │ │ │ │ ├── ptp_data_parser.hpp │ │ │ │ ├── ptp_object_database.hpp │ │ │ │ ├── ptp_object_heap.hpp │ │ │ │ ├── ptp_responder.hpp │ │ │ │ ├── ptp_responder_types.hpp │ │ │ │ ├── results.hpp │ │ │ │ └── usb_session.hpp │ │ │ └── haze.hpp │ │ └── source/ │ │ ├── async_usb_server.cpp │ │ ├── console_fsh.glsl │ │ ├── console_vsh.glsl │ │ ├── device_properties.cpp │ │ ├── event_reactor.cpp │ │ ├── gpu_console.c │ │ ├── main.cpp │ │ ├── ptp_object_database.cpp │ │ ├── ptp_object_heap.cpp │ │ ├── ptp_responder.cpp │ │ ├── ptp_responder_android_operations.cpp │ │ ├── ptp_responder_mtp_operations.cpp │ │ ├── ptp_responder_ptp_operations.cpp │ │ └── usb_session.cpp │ └── reboot_to_payload/ │ ├── Makefile │ └── source/ │ ├── ams_bpc.c │ ├── ams_bpc.h │ ├── main.c │ └── service_guard.h └── utilities/ ├── erpt.py ├── insert_splash_screen.py └── nxo64.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ config_templates/hbl_html/accessible-urls/accessible-urls.txt text eol=lf # Mark C++ "include" files as C++ *.inc linguist-language=C++ # Mark RapidJSON include as vendored libraries/include/stratosphere/rapidjson/** linguist-vendored # Mark emummc as vendored emummc/** linguist-vendored # Mark fatfs as vendored exosphere/mariko_fatal/source/fatfs/** linguist-vendored fusee/program/source/fatfs/** linguist-vendored ================================================ FILE: .gitignore ================================================ # Prerequisites *.d # Object files *.o *.ko *.obj *.elf # Linker output *.ilk *.map *.exp *.lst # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.lz4 *.out *.app *.i*86 *.x86_64 *.hex # Deko3d shaders *.dksh # Switch Executables *.nso *.nro *.nacp *.npdm *.pfs0 *.nsp *.kip # Debug files *.dSYM/ *.su *.idb *.pdb # Kernel Module Compile Results *.mod* *.cmd .tmp_versions/ modules.order Module.symvers Mkfile.old dkms.conf # Distribution files *.tgz *.zip *.bz2 # IDA binaries *.id0 *.id1 *.id2 *.idb *.i64 *.nam *.til # Compiled python files. *.pyc .**/ # macOS horseshittery .DS_Store # NOTE: make sure to make exceptions to this pattern when needed! *.bin *.enc **/out **/build **/lib **/build_nintendo_nx_arm64 **/build_nintendo_nx_arm64_armv8a **/build_nintendo_nx_arm **/build_nintendo_nx_arm_armv8a **/build_nintendo_nx_arm_armv7a **/build_nintendo_nx_arm_armv4t **/build_nintendo_nx_x64 **/build_nintendo_nx_x86 tools/*/ package3 stratosphere/test/ ================================================ FILE: .gitmodules ================================================ ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release clean: clean-nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) clean-all: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean clean-all $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: README.md ================================================ ![Banner](img/banner.png?raw=true) ===== ![License](https://img.shields.io/badge/License-GPLv2-blue.svg) [![Chat on Discord](https://img.shields.io/badge/Discord-5865f2?logo=discord&logoColor=white)](https://discordapp.com/invite/ZdqEhed) ![Made with Notepad++](img/np++.png?raw=true) Atmosphère is a work-in-progress customized firmware for the Nintendo Switch. Components ===== Atmosphère consists of multiple components, each of which replaces/modifies a different component of the system: * Fusée: First-stage Loader, responsible for loading and validating stage 2 (custom TrustZone) plus package2 (Kernel/FIRM sysmodules), and patching them as needed. This replaces all functionality normally in Package1loader/NX Bootloader. * Exosphère: Customized TrustZone, to run a customized Secure Monitor * Thermosphère: EL2 EmuNAND support, i.e. backing up and using virtualized/redirected NAND images * Stratosphère: Custom Sysmodule(s), both Rosalina style to extend the kernel/provide new features, and of the loader reimplementation style to hook important system actions * Troposphère: Application-level Horizon OS patches, used to implement desirable CFW features Licensing ===== This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license. Credits ===== Atmosphère is currently being developed and maintained by __SciresM__, __TuxSH__, __hexkyz__, and __fincs__.
In no particular order, we credit the following for their invaluable contributions: * __switchbrew__ for the [libnx](https://github.com/switchbrew/libnx) project and the extensive [documentation, research and tool development](http://switchbrew.org) pertaining to the Nintendo Switch. * __devkitPro__ for the [devkitA64](https://devkitpro.org/) toolchain and libnx support. * __ReSwitched Team__ for additional [documentation, research and tool development](https://reswitched.github.io/) pertaining to the Nintendo Switch. * __ChaN__ for the [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) module. * __Marcus Geelnard__ for the [bcl-1.2.0](https://sourceforge.net/projects/bcl/files/bcl/bcl-1.2.0) library. * __naehrwert__ and __st4rk__ for the original [hekate](https://github.com/nwert/hekate) project and its hwinit code base. * __CTCaer__ for the continued [hekate](https://github.com/CTCaer/hekate) project's fork and the [minerva_tc](https://github.com/CTCaer/minerva_tc) project. * __m4xw__ for development of the [emuMMC](https://github.com/m4xw/emummc) project. * __Riley__ for suggesting "Atmosphere" as a Horizon OS reimplementation+customization project name. * __hedgeberg__ for research and hardware testing. * __lioncash__ for code cleanup and general improvements. * __jaames__ for designing and providing Atmosphère's graphical resources. * Everyone who submitted entries for Atmosphère's [splash design contest](https://github.com/Atmosphere-NX/Atmosphere-splashes). * _All those who actively contribute to the Atmosphère repository._ ================================================ FILE: atmosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/libraries/config/common.mk # Get Atmosphere version fields ATMOSPHERE_MAJOR_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MAJOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_MINOR_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MINOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_MICRO_VERSION := $(shell grep 'define ATMOSPHERE_RELEASE_VERSION_MICRO\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION := $(shell grep 'define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO\b' $(ATMOSPHERE_LIBRARIES_DIR)/libvapours/include/vapours/ams/ams_api_version.h | tr -s [:blank:] | cut -d' ' -f3) ATMOSPHERE_VERSION := $(ATMOSPHERE_MAJOR_VERSION).$(ATMOSPHERE_MINOR_VERSION).$(ATMOSPHERE_MICRO_VERSION)-$(ATMOSPHERE_GIT_REVISION) dist: dist-no-debug $(eval DIST_DIR = $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/atmosphere-$(ATMOSPHERE_VERSION)-debug) rm -rf $(DIST_DIR) mkdir $(DIST_DIR) cp $(CURRENT_DIRECTORY)/fusee/loader_stub/$(ATMOSPHERE_BOOT_OUT_DIR)/loader_stub.elf $(DIST_DIR)/fusee-loader-stub.elf cp $(CURRENT_DIRECTORY)/fusee/program/$(ATMOSPHERE_BOOT_OUT_DIR)/program.elf $(DIST_DIR)/fusee-program.elf cp $(CURRENT_DIRECTORY)/exosphere/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.elf $(DIST_DIR)/exosphere-loader-stub.elf cp $(CURRENT_DIRECTORY)/exosphere/program/$(ATMOSPHERE_OUT_DIR)/program.elf $(DIST_DIR)/exosphere-program.elf cp $(CURRENT_DIRECTORY)/exosphere/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.elf $(DIST_DIR)/exosphere-warmboot.elf cp $(CURRENT_DIRECTORY)/exosphere/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.elf $(DIST_DIR)/exosphere-mariko-fatal.elf cp $(CURRENT_DIRECTORY)/exosphere/program/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.elf $(DIST_DIR)/exosphere-sc7fw.elf cp $(CURRENT_DIRECTORY)/exosphere/program/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.elf $(DIST_DIR)/exosphere-rebootstub.elf cp $(CURRENT_DIRECTORY)/mesosphere/kernel_ldr/$(ATMOSPHERE_OUT_DIR)/kernel_ldr.elf $(DIST_DIR)/kernel_ldr.elf cp $(CURRENT_DIRECTORY)/mesosphere/kernel/$(ATMOSPHERE_OUT_DIR)/kernel.elf $(DIST_DIR)/kernel.elf cp $(CURRENT_DIRECTORY)/stratosphere/ams_mitm/$(ATMOSPHERE_OUT_DIR)/ams_mitm.elf $(DIST_DIR)/ams_mitm.elf cp $(CURRENT_DIRECTORY)/stratosphere/boot/$(ATMOSPHERE_OUT_DIR)/boot.elf $(DIST_DIR)/boot.elf cp $(CURRENT_DIRECTORY)/stratosphere/boot2/$(ATMOSPHERE_OUT_DIR)/boot2.elf $(DIST_DIR)/boot2.elf cp $(CURRENT_DIRECTORY)/stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.elf $(DIST_DIR)/creport.elf cp $(CURRENT_DIRECTORY)/stratosphere/cs/$(ATMOSPHERE_OUT_DIR)/cs.elf $(DIST_DIR)/cs.elf cp $(CURRENT_DIRECTORY)/stratosphere/dmnt/$(ATMOSPHERE_OUT_DIR)/dmnt.elf $(DIST_DIR)/dmnt.elf cp $(CURRENT_DIRECTORY)/stratosphere/dmnt.gen2/$(ATMOSPHERE_OUT_DIR)/dmnt.gen2.elf $(DIST_DIR)/dmnt.gen2.elf cp $(CURRENT_DIRECTORY)/stratosphere/eclct.stub/$(ATMOSPHERE_OUT_DIR)/eclct.stub.elf $(DIST_DIR)/eclct.stub.elf cp $(CURRENT_DIRECTORY)/stratosphere/erpt/$(ATMOSPHERE_OUT_DIR)/erpt.elf $(DIST_DIR)/erpt.elf cp $(CURRENT_DIRECTORY)/stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.elf $(DIST_DIR)/fatal.elf cp $(CURRENT_DIRECTORY)/stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.elf $(DIST_DIR)/htc.elf cp $(CURRENT_DIRECTORY)/stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.elf $(DIST_DIR)/jpegdec.elf cp $(CURRENT_DIRECTORY)/stratosphere/loader/$(ATMOSPHERE_OUT_DIR)/loader.elf $(DIST_DIR)/loader.elf cp $(CURRENT_DIRECTORY)/stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.elf $(DIST_DIR)/LogManager.elf cp $(CURRENT_DIRECTORY)/stratosphere/ncm/$(ATMOSPHERE_OUT_DIR)/ncm.elf $(DIST_DIR)/ncm.elf cp $(CURRENT_DIRECTORY)/stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.elf $(DIST_DIR)/pgl.elf cp $(CURRENT_DIRECTORY)/stratosphere/pm/$(ATMOSPHERE_OUT_DIR)/pm.elf $(DIST_DIR)/pm.elf cp $(CURRENT_DIRECTORY)/stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.elf $(DIST_DIR)/ro.elf cp $(CURRENT_DIRECTORY)/stratosphere/sm/$(ATMOSPHERE_OUT_DIR)/sm.elf $(DIST_DIR)/sm.elf cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf cp $(CURRENT_DIRECTORY)/stratosphere/memlet/$(ATMOSPHERE_OUT_DIR)/memlet.elf $(DIST_DIR)/memlet.elf cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../; rm -rf $(DIST_DIR) dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) $(eval DIST_DIR = $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/atmosphere-$(ATMOSPHERE_VERSION)) rm -rf $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/* rm -rf $(DIST_DIR) mkdir $(DIST_DIR) mkdir $(DIST_DIR)/atmosphere mkdir $(DIST_DIR)/switch mkdir -p $(DIST_DIR)/atmosphere/fatal_errors mkdir -p $(DIST_DIR)/atmosphere/config_templates mkdir -p $(DIST_DIR)/atmosphere/config mkdir -p $(DIST_DIR)/atmosphere/flags cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(DIST_DIR)/atmosphere/reboot_payload.bin cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/package3 $(DIST_DIR)/atmosphere/package3 cp config_templates/stratosphere.ini $(DIST_DIR)/atmosphere/config_templates/stratosphere.ini cp config_templates/override_config.ini $(DIST_DIR)/atmosphere/config_templates/override_config.ini cp config_templates/system_settings.ini $(DIST_DIR)/atmosphere/config_templates/system_settings.ini cp config_templates/exosphere.ini $(DIST_DIR)/atmosphere/config_templates/exosphere.ini mkdir -p config_templates/kip_patches cp -r config_templates/kip_patches $(DIST_DIR)/atmosphere/kip_patches cp -r config_templates/hbl_html $(DIST_DIR)/atmosphere/hbl_html mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000008 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000000d mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000017 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000002b mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000032 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037 #mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000421 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d609 mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d623 cp stratosphere/boot2/$(ATMOSPHERE_OUT_DIR)/boot2.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp cp stratosphere/dmnt/$(ATMOSPHERE_OUT_DIR)/dmnt.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000000d/exefs.nsp cp stratosphere/cs/$(ATMOSPHERE_OUT_DIR)/cs.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000017/exefs.nsp cp stratosphere/erpt/$(ATMOSPHERE_OUT_DIR)/erpt.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000002b/exefs.nsp cp stratosphere/eclct.stub/$(ATMOSPHERE_OUT_DIR)/eclct.stub.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000032/exefs.nsp cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp #cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c/exefs.nsp cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp cp stratosphere/dmnt.gen2/$(ATMOSPHERE_OUT_DIR)/dmnt.gen2.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d609/exefs.nsp cp stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000d623/exefs.nsp cp stratosphere/memlet/$(ATMOSPHERE_OUT_DIR)/memlet.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000421/exefs.nsp @PATH="$(DEVKITPRO)/tools/bin:$$PATH" build_romfs $(DIST_DIR)/stratosphere_romfs $(DIST_DIR)/atmosphere/stratosphere.romfs rm -r $(DIST_DIR)/stratosphere_romfs cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro cp troposphere/haze/haze.nro $(DIST_DIR)/switch/haze.nro cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../; rm -rf $(DIST_DIR) cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin package3: emummc fusee stratosphere mesosphere exosphere troposphere $(SILENTCMD)$(PYTHON) fusee/build_package3.py $(CURRENT_DIRECTORY) $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BOOT_OUT_DIR) $(ATMOSPHERE_GIT_HASH) $(ATMOSPHERE_MAJOR_VERSION) $(ATMOSPHERE_MINOR_VERSION) $(ATMOSPHERE_MICRO_VERSION) 0 $(ATMOSPHERE_SUPPORTED_HOS_MAJOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MINOR_VERSION) $(ATMOSPHERE_SUPPORTED_HOS_MICRO_VERSION) 0 @echo "Built package3!" emummc: $(MAKE) -C $(CURRENT_DIRECTORY)/emummc all fusee: libexosphere_boot @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/fusee -f $(CURRENT_DIRECTORY)/fusee/fusee.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" exosphere: libexosphere libexosphere_boot @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/exosphere -f $(CURRENT_DIRECTORY)/exosphere/exosphere.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 stratosphere: fusee libstratosphere @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/stratosphere -f $(CURRENT_DIRECTORY)/stratosphere/stratosphere.mk ATMOSPHERE_CHECKED_LIBSTRATOSPHERE=1 ATMOSPHERE_CHECKED_FUSEE=1 mesosphere: libmesosphere @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mesosphere -f $(CURRENT_DIRECTORY)/mesosphere/mesosphere.mk ATMOSPHERE_CHECKED_LIBMESOSPHERE=1 troposphere: $(MAKE) -C $(CURRENT_DIRECTORY)/troposphere all libexosphere: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) libexosphere_boot: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" else libexosphere_boot: libexosphere endif libmesosphere: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk libstratosphere: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk clean: $(MAKE) -C $(CURRENT_DIRECTORY)/fusee -f $(CURRENT_DIRECTORY)/fusee/fusee.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" $(MAKE) -C $(CURRENT_DIRECTORY)/emummc clean $(MAKE) -C $(CURRENT_DIRECTORY)/exosphere -f $(CURRENT_DIRECTORY)/exosphere/exosphere.mk clean $(MAKE) -C $(CURRENT_DIRECTORY)/mesosphere -f $(CURRENT_DIRECTORY)/mesosphere/mesosphere.mk clean $(MAKE) -C $(CURRENT_DIRECTORY)/stratosphere -f $(CURRENT_DIRECTORY)/stratosphere/stratosphere.mk clean $(MAKE) -C $(CURRENT_DIRECTORY)/troposphere clean $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/libstratosphere.mk clean $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/libmesosphere.mk clean $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean $(MAKE) -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" rm -rf $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) $(CURRENT_DIRECTORY)/$(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ .PHONY: dist dist-no-debug clean package3 emummc fusee stratosphere mesosphere exosphere troposphere ================================================ FILE: config_templates/exosphere.ini ================================================ # Key: debugmode, default: 1. # Desc: Controls whether kernel is debug mode. # Disabling this will break Atmosphere. # Key: debugmode_user, default: 0. # Desc: Controls whether userland is debug mode. # Key: disable_user_exception_handlers, default: 0. # Desc: Controls whether user exception handlers are executed on error. # NOTE: This will cause atmosphere to not fail gracefully. # Support may not be provided to users tho disable these. # If you do not know what you are doing, leave them on. # Key: enable_user_pmu_access, default: 0. # Desc: Controls whether userland has access to the PMU registers. # NOTE: It is unknown what effects this has on official code. # Key: blank_prodinfo_sysmmc, default: 0. # Desc: Controls whether PRODINFO should be blanked in sysmmc. # This will cause the system to see dummied out keys and # serial number information. # NOTE: This is not known to be safe, as data may be # cached elsewhere in the system. Usage is not encouraged. # Key: blank_prodinfo_emummc, default: 0. # Desc: Controls whether PRODINFO should be blanked in emummc. # NOTE: This is not known to be safe, as data may be # cached elsewhere in the system. Usage is not encouraged. # Key: allow_writing_to_cal_sysmmc, default: 0. # Desc: Controls whether PRODINFO can be written by homebrew in sysmmc. # NOTE: Usage of this setting is strongly discouraged without # a safe backup elsewhere. Turning this on will also cause Atmosphere # to ensure a safe backup of calibration data is stored in unused # mmc space, encrypted to prevent detection. This backup can be used # to prevent unrecoverable edits in emergencies. # Key: log_port, default: 0. # Desc: Controls what uart port exosphere will set up for logging. # NOTE: 0 = UART-A, 1 = UART-B, 2 = UART-C, 3 = UART-D # Key: log_baud_rate, default: 115200 # Desc: Controls the baud rate exosphere will set up for logging. # NOTE: 0 is treated as equivalent to 115200. # Key: log_inverted, default: 0. # Desc: Controls whether the logging uart port is inverted. [exosphere] debugmode=1 debugmode_user=0 disable_user_exception_handlers=0 enable_user_pmu_access=0 blank_prodinfo_sysmmc=0 blank_prodinfo_emummc=0 allow_writing_to_cal_sysmmc=0 log_port=0 log_baud_rate=115200 log_inverted=0 ================================================ FILE: config_templates/hbl_html/accessible-urls/accessible-urls.txt ================================================ ^http* ================================================ FILE: config_templates/override_config.ini ================================================ [hbl_config] ; Program Specific Config ; Up to 8 program-specific configurations can be set. ; These use `program_id_#`, `override_address_space_#`, and `override_key_#` ; where # is in range [0,7]. ; program_id_0=010000000000100D ; override_address_space=39_bit ; override_key_0=!R ; Any Application Config ; Note that this will only apply to program IDs that ; are both applications and not specified above ; by a program specific config. ; override_any_app=true ; override_any_app_key=R ; override_any_app_address_space=39_bit ; path=atmosphere/hbl.nsp [default_config] ; override_key=!L ; cheat_enable_key=!L ================================================ FILE: config_templates/stratosphere.ini ================================================ [stratosphere] ; To force-enable nogc, add nogc = 1 ; To force-disable nogc, add nogc = 0 ================================================ FILE: config_templates/system_settings.ini ================================================ [eupld] ; Disable uploading error reports to Nintendo ; upload_enabled = u8!0x0 [usb] ; Enable USB 3.0 superspeed for homebrew ; 0 = USB 3.0 support is system default (usually disabled), 1 = USB 3.0 support is enabled. ; usb30_force_enabled = u8!0x0 [ro] ; Control whether RO should ease its validation of NROs. ; (note: this is normally not necessary, and ips patches can be used.) ; ease_nro_restriction = u8!0x1 [lm] ; Control whether lm should log to the SD card. ; Note that this setting does nothing when log manager is not enabled. ; enable_sd_card_logging = u8!0x1 ; Control the output directory for SD card logs. ; Note that this setting does nothing when log manager is not enabled/sd card logging is not enabled. ; sd_card_log_output_directory = str!atmosphere/binlogs ; Atmosphere custom settings [erpt] ; Control whether erpt reports should always be preserved, instead of automatically cleaning periodically. ; disable_automatic_report_cleanup = u8!0x0 [atmosphere] ; Reboot from fatal automatically after some number of milliseconds. ; If field is not present or 0, fatal will wait indefinitely for user input. ; fatal_auto_reboot_interval = u64!0x0 ; Make the power menu's "reboot" button reboot to payload. ; Set to "normal" for normal reboot, "rcm" for rcm reboot. ; power_menu_reboot_function = str!payload ; Controls whether dmnt cheats should be toggled on or off by ; default. 1 = toggled on by default, 0 = toggled off by default. ; dmnt_cheats_enabled_by_default = u8!0x1 ; Controls whether dmnt should always save cheat toggle state ; for restoration on new game launch. 1 = always save toggles, ; 0 = only save toggles if toggle file exists. ; dmnt_always_save_cheat_toggles = u8!0x0 ; Enable writing to BIS partitions for HBL. ; This is probably undesirable for normal usage. ; enable_hbl_bis_write = u8!0x0 ; Enable reading the CAL0 partition for HBL. ; This is probably undesirable for normal usage. ; enable_hbl_cal_read = u8!0x0 ; Controls whether fs.mitm should redirect save files ; to directories on the sd card. ; 0 = Do not redirect, 1 = Redirect. ; NOTE: EXPERIMENTAL ; If you do not know what you are doing, do not touch this yet. ; fsmitm_redirect_saves_to_sd = u8!0x0 ; Controls whether am sees system settings "DebugModeFlag" as ; enabled or disabled. ; 0 = Disabled (not debug mode), 1 = Enabled (debug mode) ; enable_am_debug_mode = u8!0x0 ; Controls whether dns.mitm is enabled ; 0 = Disabled, 1 = Enabled ; enable_dns_mitm = u8!0x1 ; Controls whether dns.mitm uses the default redirections in addition to ; whatever is specified in the user's hosts file. ; 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents) ; add_defaults_to_dns_hosts = u8!0x1 ; Controls whether dns.mitm logs to the sd card for debugging ; 0 = Disabled, 1 = Enabled ; enable_dns_mitm_debug_log = u8!0x0 ; Controls whether htc is enabled ; 0 = Disabled, 1 = Enabled ; enable_htc = u8!0x0 ; Controls whether atmosphere's log manager is enabled ; Note that this setting is ignored (and treated as 1) when htc is enabled. ; 0 = Disabled, 1 = Enabled ; enable_log_manager = u8!0x0 ; Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs) ; NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database. ; 0 = Disabled, 1 = Enabled ; enable_external_bluetooth_db = u8!0x0 [hbloader] ; Controls the size of the homebrew heap when running as applet. ; If set to zero, all available applet memory is used as heap. ; The default is zero. ; applet_heap_size = u64!0x0 ; Controls the amount of memory to reserve when running as applet ; for usage by other applets. This setting has no effect if ; applet_heap_size is non-zero. The default is 0x8600000. ; applet_heap_reservation_size = u64!0x8600000 ================================================ FILE: docs/building.md ================================================ # Building Atmosphère Building Atmosphère is a very straightforward process that relies almost exclusively on tools provided by the [devkitPro](https://devkitpro.org) organization. ## Dependencies + [devkitA64](https://devkitpro.org) + [devkitARM](https://devkitpro.org) + [Python 2](https://www.python.org) (Python 3 may work as well, but this is not guaranteed) + [LZ4](https://pypi.org/project/lz4) + [PyCryptodome](https://pypi.org/project/pycryptodome) (optional) + [hactool](https://github.com/SciresM/hactool) ## Instructions 1. Follow the guide located [here](https://devkitpro.org/wiki/Getting_Started) to install and configure all the tools necessary for the build process. 2. Install the following packages via (dkp-)pacman: + `switch-dev` + `switch-glm` + `switch-libjpeg-turbo` + `devkitARM` + `devkitarm-rules` + `hactool` 3. Install the following library via python's package manager `pip`, required by [exosphere](components/exosphere.md): + `lz4` 4. Finally, clone the Atmosphère repository and run `make` under its root directory. ================================================ FILE: docs/changelog.md ================================================ # Changelog ## 1.10.2 + Basic support was added for 21.2.0. + General system stability improvements to enhance the user's experience. ## 1.10.1 + Basic support was added for 21.1.0. + A bug was fixed that caused some games (e.g. Tomb Raider definitive edition) to fail to launch. + General system stability improvements to enhance the user's experience. ## 1.10.0 + Basic support was added for 21.0.0. + The console should boot and atmosphère should be fully functional. + **Please note**: All homebrew software may need to be re-compiled with the latest libnx (>= 4.10.0), or else it may crash/experience memory corruption. + Nintendo broke the userland<->kernel TLS ABI in 21.0.0, by writing to previously reserved space. + Homebrew used this reserved space for its TLS slots, which means any homebrew software using TLS slots will experience memory corruption when running under Atmosphere 1.10.0. + This doesn't appear to impact everything, but a large portion of tested homebrew crashes (often on exit), and so will need re-compile for the new ABI. + For those technically inclined, while TLS slots are rarely used by developers, they're used to implement features like e.g. C++ exceptions under the hood, and so anything using those crashes, etc. + To help make this transition easier, hbmenu now shows a warning when selecting homebrew compiled with an older, incompatible ABI version. + I apologize for the hassle in general. + libnx has been updated so that its reserved space matches Nintendo's now -- this particular issue can never occur again, even if Nintendo touches more reserved space. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `loader` was updated to reflect the latest official behavior. + `pm` was updated to reflect the latest official behavior. + `erpt` was updated to reflect the latest official behavior. + `pgl` was updated to reflect the latest official behavior. + `fatal` was updated to reflect the latest official behavior. + Support was added for launching another game-which-has-too-many-files with romfs mods. + I rely on user reports for adding support/fixing these, and some of these games can be pretty obscure! + If you are affected by this, you will see "Data abort (0x101)" when trying to launch the game with mods. + Please reach out to `sciresm` on discord if this occurs to share your error report binary. + Although some games may be impossible to fix, I believe I can get almost everything working, so please let me try to help you (and improve atmosphère's support!) if you run into this! + General system stability improvements to enhance the user's experience. ## 1.9.5 + Basic support was added for 20.5.0. + General system stability improvements to enhance the user's experience. ## 1.9.4 + Basic support was added for 20.4.0. + An issue was fixed in `exosphère`'s register accessilibity tables (thanks @CTCaer). + I believe this had no impact on official code, though it would have prevented some homebrew from interacting correctly with the MC0/MC1 registers. + An issue was fixed that could cause a deadlock when building multiple romfs images simultaneously (thanks @Ereza). + This fixes support for certain mods, e.g. system language translations overriding content for both overlayDisp and qlaunch. + General system stability improvements to enhance the user's experience. ## 1.9.3 + Basic support was added for 20.3.0. + Compatibility was fixed for loading mods with KOTOR 2 (star wars). + General system stability improvements to enhance the user's experience. ## 1.9.2 + Basic support was added for 20.2.0. + USB 3.0 support force-enable was fixed for 20.1.0+. + General system stability improvements to enhance the user's experience. ## 1.9.1 + Basic support was added for 20.1.0. + General system stability improvements to enhance the user's experience. ## 1.9.0 + Basic support was added for 20.0.0. + The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes. + There shouldn't be anything user visible resulting from this, but it will be addressed in a future atmosphère update. + The same action item from 18.0.0 remains, and I believe in my heart of hearts that it will be addressed eventually. Someone has told me they're working on it. + There aren't (to my knowledge) outstanding 19.0.0 items any more. + **Please note**: As a result of changes made to nintendo's software in 20.0.0, there is roughly 10MB less memory available for custom system modules. + We can only steal a maximum of 14MB from the applet pool, down from 40MB. + To compensate for this, `ams.mitm`'s heap usage has been reduced by 20MB. + To facilitate this, a new helper module (`memlet`) was added, so that memory may be temporarily stolen during the romfs building process. + Hopefully, this results in relatively little breakage, however it is possible that user mods which replace extremely large numbers of files in The Legend of Zelda: Tears of the Kingdom may no longer function. + If you are affected by this, you will see "Data abort (0x101)" when trying to launch the game with mods. + Please reach out to `sciresm` on discord if this occurs to share your error report binary. However, some issues may be impossible to fix. + I apologize sincerely if the issue is impossible to resolve, but I have been forced unavoidably to make compromises here, and I think this is the best balance to be struck. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `loader` was updated to reflect the latest official behavior. + `pm` was updated to reflect the latest official behavior. + `ncm` was partially updated to reflect the latest official behavior. + `erpt` was updated to reflect the latest official behavior. + Atmosphère was updated to use GCC 15/newlib (latest devkitA64/devkitARM releases). + A number of improvements were made to the dmnt cheat engine. + New instructions were added, and instructions were updated for improved/new functionality. + Please see the documents for details -- thanks @tomvita! + General system stability improvements to enhance the user's experience. ## 1.8.0 + Basic support was added for 19.0.0. + The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes. + There shouldn't be anything user visible resulting from this, but it will be addressed in a future atmosphère update. There is still one action item from 18.0.0 to be addressed, as well. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `loader` was updated to reflect the latest official behavior. + `pm` was updated to reflect the latest official behavior. + `ro` was updated to reflect the latest official behavior. + `creport`'s file acces patterns were optimized, greatly improving performance when generating a crash report. + Atmosphère now uses `relr` relocations where possible. + This reduces the filesize of a number of atmosphère's modules. + A number of minor issues were fixed and improvements were made, including: + Support was fixed for running Atmosphère on newer units with specific Hynix/Micron DRAM chips. + General system stability improvements to enhance the user's experience. ## 1.7.1 + Support was added for 18.1.0. + Atmosphère was updated to use GCC 14/newlib (latest devkitA64/devkitARM releases). + Further changes were for 18.0.0: + `loader` was updated to reflect the latest official behavior. + General system stability improvements to enhance the user's experience. ## 1.7.0 + Basic support was added for 18.0.0. + The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes. + There shouldn't be anything user visible resulting from this, but it will be addressed in a future atmosphère update, once I am not traveling so much. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `spl` was updated to reflect the latest official behavior. + `fusee`'s no longer supports applying IPS patches to KIPs. + The only KIPs that are ever present are a) atmosphère modules, b) custom system modules, or c) FS. + The IPS subsystem was originally designed to make nogc patches work for FS, but these are now internal, and it appears the literal only kip patches that exist are for piracy. + I could not find any kip patches posted anywhere made for any other purpose. + It fundamentally does not make sense to slow down boot for every normal user for a feature that has no actual use-case, especially when `fusee` seeks to be a minimal bootloader. + Minor improvements were made to atmosphere's gdbstub, including: + Support was added for QStartNoAckMode. + An issue was fixed that could cause a fatal error when creating too many breakpoints. + A number of minor issues were fixed and improvements were made, including: + `pt-BR` (`PortugueseBr`) is now accepted as a valid language when overriding game locales. + A bug was fixed that could cause atmosphere to incorrectly serialize output object IDs over IPC when using domain objects. + A bug was fixed in `pm`'s resource limit boost logic that could potentially cause legitimate boosts to fail in certain circumstances. + `loader`/`ro` will now throw a fatal error when using invalid IPS patches that go out of bounds, instead of corrupting memory. + Support was fixed for booting using a memory configuration of half of the true available memory (e.g. forcing a 4GB configuration on an 8GB board). + General system stability improvements to enhance the user's experience. ## 1.6.2 + Support was finished for 17.0.0. + `erpt` was updated to support the latest official behavior. + `jpegdec` was updated to support the latest official behavior. + `pm` was updated to support the latest official behavior. + General system stability improvements to enhance the user's experience. ## 1.6.1 + An improved solution to [the problem that would cause consoles which had previously re-built their SYSTEM partition to brick on update-to-17.0.0](https://gist.github.com/SciresM/2ddb708c812ed585c4d99f54e25205ff) was added. + In particular, booting atmosphère will now automatically detect the problem and unbrick any consoles which have fallen into this state. + Some improvements were made to `haze`, including: + Performance was greatly improved: + Support was added for GetObjectPropList, which decreases the amount of requests made by ~8x. + Haze now performs rendering on the GPU, freeing up the CPU to respond to requests in a more timely manner. + An issue was fixed with how `haze` configures `bMaxPacketSize0` which improves support for USB3. + General system stability improvements to enhance the user's experience. ## 1.6.0 + Basic support was added for 17.0.0. + The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes. + There shouldn't be anything user visible resulting from this, but it will be addressed in a soon-to-come atmosphère update. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `ncm` was updated to reflect the latest official behavior. + `erpt` was partially updated to support the latest official behavior. + Atmosphere's gdbstub now supports waiting to attach to a specific program id on launch (as opposed to any application). + The monitor command for this is `monitor wait `, where program id can optionally have an `0x` prefix. + Support was added to `haze` for editing files in-place and performing 64-bit transfers (files larger than 4 GB). + `bpc.mitm` was enabled on Mariko units, and now triggers pmic-based shutdowns/reboots (thanks @CTCaer). + This should cause the console to no longer wake ~15 seconds after shutdown on Mariko. + A number of minor issues were fixed and improvements were made, including: + A workaround was added for a change in 17.0.0 that would cause consoles which had previously re-built their SYSTEM partition to brick on update-to-17.0.0. + General system stability improvements to enhance the user's experience. ## 1.5.5 + Support was added for 16.1.0. + General system stability improvements to enhance the user's experience. ## 1.5.4 + Experimental new functionality was implemented to prevent crashing when building romfs for certain games with obscene file counts. + This includes both Fire Emblem: Engage (~190000 files), and The Legend of Zelda: Tears of the Kingdom (~300000) files. + The solution involved adding functionality to ams.mitm/pm to dynamically steal memory from the application (and system) pool as needed when the games have romfs mods. + No memory is taken, and there is no cost to this functionality when playing without mods (or with overrides disabled). + The Legend of Zelda: Tears of the Kingdom is currently the absolute worst case game, requiring ~48 MB of memory to build a romfs image to play with mods. + Right now, the memory is sourced as follows: 32 MB (base ams.mitm heap), 10 MB (stolen from application pool), 8 MB (dynamically stolen from system pool). + This is 50 MB, which allows a little overhead in the worst case (prevents crashing due to exhausting the heap for other allocations in ams.mitm). + Zelda is remarkably sensitive to memory being stolen from the application pool, tolerating no more than 16 MB on 1.0.0 and 12 MB on 1.1.0. I have chosen to steal 10 MB, to be safe, for now. + This may break on a future game update, but I will fix it if and when that happens. There is no perfect solution; the game simply requires too much memory to support mods flawlessly, and I am forced to compromise. + As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`. "I am jinxing myself by saying this, but it's really hard to imagine any game being worse than The Legend of Zelda: Tears of the Kingdom, but if it happens again I will drop everything to fix it as usual". + General system stability improvements to enhance the user's experience. ## 1.5.3 + Support was added for 16.0.3. + Atmosphère was updated to use GCC 13/newlib (latest devkitA64/devkitARM releases). + **Please note**: This introduces a known issue, which is currently being worked on. + As you may recall from the 1.4.1 changelog, Fire Emblem: Engage requires enormous amounts of memory to support using layeredfs mods with the game. + Latest GCC/newlib slightly increases malloc overhead size, which makes the previous memory increase insufficient. + A general-case solution to this is in the works, which should hopefully fix the problem in a way that doesn't jinx me for the future. + A number of minor issues were fixed and improvements were made, including: + An issue was fixed that caused system font replacement to not work on 16.0.0+. + An minor accuracy issue was addressed in mesosphere's management of certain memory ranges; this issue would have had zero visible impact to the end-user. + General system stability improvements to enhance the user's experience. ## 1.5.2 + A homebrew application (`haze`) was added for performing USB file transfer (with thanks to @liamwhite for both design and implementation). + `haze` is included with atmosphère, and provides access to the SD card via the PTP/MTP protocol. + **Please note**: haze will show inside the homebrew menu under the name "USB File Transfer". + **Please note**: Atmosphère cannot be updated at runtime, and trying to install an atmosphère update via haze will fail as usual. + General system stability improvements to enhance the user's experience. ## 1.5.1 + `fatal` was updated to reduce memory footprint. + Starting in 16.0.0, official `fatal` has no framebuffer or rendering logic, and instead calls other system service commands to draw the screen. + However, these commands aren't usable by atmosphère (too small rendering window, bad color support). + To reduce the relative memory footprint differential between atmosphère and official code, the framebuffer (2 MB) is now dynamically allocated when needed. + This will try to allocate from multiple pools (preferring System > System_NonSecure > Application). + This technically requires that 2 MB be available in at least one of these pools for the fatal screen to render (otherwise, a reboot-to-black-and-white-fatal will occur), but this should be a non-issue in almost all cases. + A feature was added to optionally mirror the bluetooth pairing database to the SD card (thanks @ndeadly). + This allows device pairings to be automatically kept in-sync across sysmmc/all emummcs. + This is opt-in, and can be controlled by setting `atmosphere!enable_external_bluetooth_db = u8!0x1`. + When enabled, the pairing database will be synchronized to `/atmosphere/bluetooth_devices.db`. + General system stability improvements to enhance the user's experience. ## 1.5.0 + Support was added for 16.0.0 + `mesosphère` was updated to reflect the latest official kernel behavior. + `ncm` was updated to reflect the latest official behavior. + Many FS apis were updated under the hood to reflect the latest official behavior. + **Please Note**: 16.0.0 made breaking changes to a number of system APIs, including in FS/NCM/Shared Font commands that some homebrew programs may use. + These programs may encounter strange errors, and may need to be recompiled with a libnx updated to support 16.0.0's changes to function properly. + A number of minor issues were fixed and improvements were made, including: + An issue was fixed that could cause GPIO outputs to be misconfigured under certain circumstances. + General system stability improvements to enhance the user's experience. ## 1.4.1 + A number of minor issues were fixed and improvements were made, including: + `dmnt` cheat toggle files are no longer ignored when they are missing a trailing newline. + The mechanism for automatically cleaning up `erpt_reports` added in 1.3.0 was fixed. + This was actually just very fundamentally broken and has never worked, but it is verified working now. + Minor fixes were made in `mesosphère` to match official kernel behavior (spin lock assembly was corrected, wrong result on failure in in GetProcessId was corrected). + A missing call to GetSdStatus when initializing SD cards at non uhs-i mode was added in the sdmmc driver. + `ams.mitm`'s memory usage was increased by 16 MB, to prevent crashing when building romfs for games with obscene file counts. + To quote the changelog for 1.2.3: "Animal Crossing's 2.0.0 update contains >99000 files [...] It's really hard to imagine any game being worse than Animal Crossing". + As it turns out, Fire Emblem: Engage has ~186000 files, and is approximately twice as bad as animal crossing. + The additional memory here is taken from the applet pool; no issues are expected to arise from this, but please report anything you may run into. + As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`. + I am jinxing myself by saying this, but it's really hard to imagine any game being worse than Fire Emblem: Engage, but if it happens again I will drop everything to fix it as usual. + General system stability improvements to enhance the user's experience. ## 1.4.0 + Support was added for 15.0.0. + `mesosphère` was updated to reflect the latest official kernel behavior. + `ncm` was updated to reflect the latest official behavior. + A number of minor issues were fixed and improvements were made, including: + The capacity limit on registered add-on contents was fixed in NCM to reflect the increase that occurred in 12.0.0. + An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual. + dmnt.gen2's gdbstub now sanitizes thread names to prevent invalid characters from breaking gdb. + dmnt.gen2's gdbstub now reports the architecture tag correctly when attached to 32-bit processes. + Support for program-specific html manual content overrides was added for non-hbl takeover context. + A bug was fixed in how emummc constructed the alternate Nintendo directory path. + Previously, this was using `/*/Nintendo/Nintendo` instead of `/*/Nintendo`. + Code was added to automatically move the old folders to the new ones when booting into emummc. + A bug was fixed in boot that caused an incorrectly low input voltage limit to be set. + General system stability improvements to enhance the user's experience. ## 1.3.2 + Support was improved for 14.0.0+. + `loader` was updated to reflect the latest official behaviors. + `ro` was updated to reflect the latest official behaviors. + A number of minor issues were fixed and improvements were made, including: + A memory leak was fixed in filesystem path management; this could cause a crash when launching games ~100 times, or when deleting/re-downloading games. + A bug was fixed that could cause threads to not see a newly signaled semaphore. + A number of minor inaccuracies were fixed in the updated FileSystem APIs. + General system stability improvements to enhance the user's experience. ## 1.3.1 + Support was added for 14.1.0. + A number of minor under the hood improvements to accuracy were made to better reflect latest official system module behavior, particularly around FS apis. + General system stability improvements to enhance the user's experience. ## 1.3.0 + Support was added for 14.0.0. + `mesosphère` was updated to reflect the latest official kernel behavior. + `erpt` was updated to reflect the latest official behaviors. + `pm` was updated to reflect the latest official behaviors. + `fatal` was updated to reflect the latest official behaviors. + A mechanism for automatically cleaning up `erpt_reports` was added. + When booting, if the console has more than 1000 reports inside `/atmosphere/erpt_reports`, the folder will be cleaned to empty. + This behavior can be disabled by setting `erpt!disable_automatic_report_cleanup` = u8!0x1 in system_settings.ini. + Atmosphère's build system was re-written, and now allows globally building for various builds/configs. + All boards now automatically support release/debugging/auditing targets; it is now possible to build a full debugging/auditing build of atmosphère for the first time. + Support was added for compiling libstratosphère to run on PC. + The currently implemented/tested targets are Windows (x64), Linux (x64, arm64), macOS (x64, arm64). + If you are a developer interested in adding support for another target, please reach out to `SciresM#0524` on discord. + This is intended to finally allow sanely testing Atmosphère's code, by allowing most of it to run on a PC (with access to a debugger) instead of on game console hardware. + In addition, this will allow making PC tools which reuse code written for Atmosphère directly.. + **Please Note**: This has no relation to interacting with official software on PC whatsoever. This really allows for making tests and self-contained atmosphère-based command-line tools; the Atmosphère project continues to have zero interest in attempting to run official software of any kind. + In the course of adding this support (and working on tooling using it), a number of fairly major revisions were made to stratosphere (particularly surrounding filesystem code). + **Please Note**: A number of changes made for this (and ones necessary in the process of adding support for 14.0.0) are api-breaking. + If you're a developer and any of this caused your code to break, please feel free to contact `SciresM#0524` for help updating your program. + General system stability improvements to enhance the user's experience. ## 1.2.6 + Support was added for 13.2.1. + A number of minor issues were fixed and improvements were made, including: + A minor performance improvement was implemented in service table dispatch by sorting and binary-searching the service command table instead of using linear search. + Static initialization logic in Atmosphere was made much more regular. + General system stability improvements to enhance the user's experience. ## 1.2.5 + Support was added for 13.2.0. + A number of minor issues were fixed and improvements were made, including: + A bug was fixed that caused `mesosphère` to underreport the total memory size by 8MB for certain games which use newer system-resource-size memory management. + This caused FIFA 19 to crash, and possibly other issues. + Memory management changes were made to `sm` that save 0x5000 of memory. + A microoptimization was made to the way `mesosphère` manages updating the debug register for hardware single-step support. + Support was fixed for enabling `usb!usb30_force_enabled` on 13.0.0+. + The work-in-progress unit testing framework was updated to use doctest instead of catch2. + General system stability improvements to enhance the user's experience. ## 1.2.4 + Changes were made to the way fs.mitm builds images when providing a layeredfs romfs. + Cache management (to avoid unnecessary rebuild) was revised, to add a grace period of ~500ms-1s between process closing romfs image and ams.mitm needing to rebuild if romfs is re-opened. + This makes our cache much more effective, previously we were re-building romfs several times. + RomFS image ownership was overhauled, with a new reference-counting implementation added (used to implement the above grace period). + Certain games (e.g. Puyo Puyo Tetris 2, probably others) were sensitive to this timing, and could use access patterns which would trigger creation of romfs image while previous romfs image was in the middle of destructor. + This could cause a fatal error, because the destructor for the old image could run simultaneously with building the new image. + This also provides a speedup versus the 1.2.3 code, with Animal Crossing now taking ~8 fewer seconds to get past the Nintendo Switch logo. + General system stability improvements to enhance the user's experience. ## 1.2.3 + Because ams.TMA is taking longer to develop than expected, experimental support for Atmosphère's gdbstub as a standalone is now available. + To enable it, set `atmosphere!enable_standalone_gdbstub` = u8!0x1 in system_settings.ini. + The standalone also requires `atmosphere!enable_htc` = u8!0x0, but this should be the case for everyone since ams.TMA isn't actually usable yet. + Once enabled, open the devkitPro provided-gdb (`aarch64-none-elf-gdb` for 64-bit or `arm-none-eabi-gdb` for 32-bit). + The standalone stub exposes itself on port 22225 -- so the command to connect is `target extended-remote :22225`. + Type `info os processes` to get a list of process IDs that can be attached to. + The stub should work on both system programs, games, and homebrew -- but please note that debugging certain processes (like sockets) can cause hang due to the stub using them itself. + Software break-points, hardware break-points, hardware watch-points, and hardware single-step are all supported/implemented. + The following monitor commands are currently supported: + `monitor get info`: Get process info, address space layout, and information on modules. + `monitor get mappings`: Get all memory mappings. + `monitor get mapping `: Get the memory mapping for a specific address. + `monitor wait application`: Causes the stub to wait for an application to be launched. The next application will be started suspended. + User is expected to send `attach ` after launching, which will cause attach-on-first-instruction. Failure to attach may cause system instability, this probably needs work. + **Please Note**: The GDBstub is new and may have bugs/need work. If you find issues, please report them to SciresM#0524 -- all help finding/fixing bugs is appreciated, here. + Generally speaking, if you would like to report information about fixes needed/discuss development of the gdbstub, join ReSwitched's #dev-support channel. + Changes were made to the way fs.mitm builds images when providing a layeredfs romfs. + Animal Crossing's 2.0.0 update contains >99000 files, and has tables so big that we ran out of memory even after the optimizations made in 0.10.5. + Previously, we used fixed-sized 0x40000 work buffers for file/directory tables and simultaneously built hash/content tables in one loop over files/directories. + We now iterate over the file/directory tables multiple times, first once to determine the hash table indices, then repeatedly to build hash tables, then once to build content tables. + We also now allow smaller-than-0x40000 work buffers, trying half-as-big buffers until allocation succeeds (or work buffer would be <0x4000, which is a safeguard against truly horrible performance). + There is a slight speed penalty to these changes, but it's on the order of seconds for the worst case (Animal Crossing) and trivial for most games with reasonable tables. + If you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`. + It's really hard to imagine any game being worse than Animal Crossing, but if it happens again I will drop everything to fix it as usual. + `creport` now attempts to parse symbol tables if present. + If a game executable has a symbol for a given address, the function-relative-offset will now be printed after the module-relative-offset. + General system stability improvements to enhance the user's experience. ## 1.2.2 + A number of fixes were made to Atmosphère's implementation of the new "sprofile" service added in 13.0.0. + Nintendo is finally transmitting data over the internet to certain consoles, which has allowed for validating our service implementation. + Unfortunately, there were several problems, and if your console began trying to use the new services atmosphere would show a fatal error with code 0xCAF6 (sprofile::ResultInvalidState()). + With actual test data in hand, a test program was written and it was verified that our implementation can successfully import/access profile data now. + Hopefully there are no more issues, and I sincerely apologize for anyone who got an 0xCAF6 fatal due to this. + A number of minor improvements were made to `mesosphère`, including: + KThread::GetContextForSchedulerLoop was implemented in assembly (using static assertions to verify offset-of-context-in-struct is correct). + This saves an unnecessary function call in the middle of the scheduler hot loop, replacing it with an addition instruction, which should improve microperformance. + Mesosphere's hardware maintenance instructions were audited via a script and now directly match Nintendo's kernels. + Notably, this inserts a missing instruction synchronization barrier when validating that slab heaps may be constructed. + This missing ISB could cause an abort on certain (see: particularly sensitive) hardware on boot if the relevant codepath was speculatively executed (it normally only executes on game launch...) + The SVC handlers for performing light IPC (normally unused) from 32-bit process were fixed in Mesosphere. + A bug was fixed that would cause the register x27 to be overwritten with the contents of x26 when returning from a user exception handler. + A bug was fixed that would cause the kernel to use the userland stack pointer instead of the kernel stack pointer while generating an error report for a kernel abort. + General system stability improvements to enhance the user's experience. ## 1.2.1 + Support was implemented for 13.1.0. + `mesosphère` was updated to reflect the kernel behavioral changes made in 13.1.0. + KScheduler now issues a data memory barrier when unlocking the scheduler lock and when early-returning due to top-thread-is-current during scheduling. + `erpt` was updated to reflect the latest official behaviors. + The new service added in 13.0.0 ("sprofile") was revised, and the data formats it expects was changed. + This still appears to be (possibly(?)) untestable due to data not being transmitted yet, but I have greater confidence things will go smoothly than I did when 1.1.0 released. + A number of improvements were made to `mesosphère`, including: + A build target was created to build targeting the qemu `virt` board. + This facilitates writing unit tests for the kernel (and other atmosphere components) and running them under PC. + **Please Note**: Official system software will not work at all under this, and the Atmosphère project has zero interest in attempting to run official software of any kind. This is unit testing machinery, and explicitly not more than that. + This should hopefully allow us to have greater confidence that all of atmosphere's components work the way they're theoretically supposed to in the future. + **Please Note**: If you are a developer who is familiar with the Horizon operating system (or capable of becoming familiar), I would greatly appreciate help writing tests and improving the testing framework. + Please contact `SciresM#0524` if you are capable and interested. + Really, if you are actually a developer who would like to help me get this off the ground, I would deeply appreciate it. + That said, if you are not a developer but want to be one, this probably isn't the best opportunity; I expect it to be highly technical. + Consider the ReSwitched discord's #hack-n-all channel for your educational purposes. + We are (at least for now) using [catch2](https://github.com/catchorg/Catch2) for unit tests. + Almost all virtual calls in the kernel are now resolved statically. + This eliminates substantial virtual call overhead, and should lead to improved kernel microperformance in pretty much every function. + The remaining red black tree find operations which weren't using the optimized "find key" variant are now using the optimized version. + Custom assembly was written to improve tick-to-timespan conversion. + This works around gcc emitting suboptimal assembly at -Os (it emits good assembly at -O3, clang is fine at both -O3 and -Os). + KThread and KSession structures were updated to optimize member layout, saving 0x10 bytes per KThread/KSession object. + Rather than unnecessarily zero-ing all data in kernel objects only to overwrite members later, we now only initialize the members we need to in kernel object constructors. + This is what Nintendo was doing already. + A set of custom optimized atomic primitives were implemented and are used in place of std::atomic<> + This works around a gcc bug which downgrades specified memory order to seq_cst, and introduces clrex in places where it is appropriate. + This should strictly improve microperformance of many system calls. + An compile-time toggleable extension was added to support 40-bit physical addresses in MapRange capabilities (using currently reserved bits). + A number of minor bugs were fixed, including: + Initial cache management now better reflects official behavior. + This fixes an issue that caused certain hardware with cache sensitivity to produce cryptic kernel panics during boot. + Incorrect logic when checking thread priority capabilities was fixed to reflect official behavior. + The scheduler was updated to reflect latest official behavior, and a number of minor bugs involving clz/ctz were fixed. + Accesses to the processes local region were fixed to properly use kernel linear region, not userland pointers. + The cache SVCs exposed for 32-bit processes now better reflect official core mask request semantics. + A bug was fixed that could cause a kernel panic if SvcArbitrateLock was called on a thread with exactly one reference in the middle of handling a user-mode exception. + General system stability improvements to enhance the user's experience. ## 1.2.0 + `boot` was updated to reflect the latest official behavior for display/battery management. + This should fix any issues that might result from running older releases on the OLED model, if you're somehow in a position to do so. + The "target firmware" system was changed to allow the bootloader to specify an approximation, rather than the true target firmware. + Previously we expected compliant bootloaders to inspect SYSTEM:/ to determine the specific target firmware. + Now, we only require an approximate version, with major version == true major version and approximate version <= true version. + This greatly simplifies bootloader requirements, and correspondingly all code for accessing SYSTEM has been removed from fusee. + This should result in a substantial speedup when booting emummc with fusee, as SYSTEM accesses were the most expensive thing done previously. + This should resolve any inconsistency in firmware detection when booting via fusee vs hekate. + This should also improve our compatibility with micro firmware releases, making it more likely that atmosphere "just works" if nothing important has changed. + Dynamic resource limit determination logic was implemented in `pm` to match latest official behavior. + This greatly simplifies/makes consistent the resource limits on older firmwares, as well. + An enormous amount of refactoring was performed under the hood, including: + **Please Note**: If you are a developer who uses Atmosphere-libs, a number of changes here are breaking. + Feel free to contact SciresM#0524 for help updating your program. + The OS namespace had many primitives implemented/made more accurate. + Since mesosphere is now always-on, os::LightEvent (which required newer SVCs) is now globally usable (and used by stratosphere where relevant). + Assertions are now true no-ops when building for release. + Stratosphere is now built with -Wextra/-Werror. + Most "common" logic in system module main.cpp files was moved into libstratosphere. + **Please Note**: main.cpp files for prior atmosphere-libs will no longer work, for a really large number of reasons. + A number of longstanding code style issues were corrected. + Mesosphere now uses util::BitFlagSet for SVC permissions. + Mesosphere now puts its relocation table inside .bss, which allows that memory to be reclaimed after relocations are performed. + These changes save ~16KB of memory in the kernel, all said and done. + A number of locations in stratosphere where memory could be saved were spotted and taken advantage of, leading to ~150-200KB of saved memory. + The `spl` and `loader` system module was refactored to better reflect official logic. + `sf` ipc server code was updated to only emit mitm/defer logic when that logic is actually required somewhere in process. + `tipc` ipc server code was updated to reflect changes to official logic made in 13.0.0. + Many, many other minor changes, please talk to SciresM#0524 or read the relevant commits if you want to know more. + A number of minor issues were fixed, including: + Mesosphere's handling of SVC permissions on thread pin/unpin was updated to reflect official kernel behavior. + util::CountTrailingZeros() was fixed to calculate the correct value when used at compile-time. + General system stability improvements to enhance the user's experience. ## 1.1.1 + A bug was fixed which caused some memory to leak when launching a game with mods enabled, eventually causing a crash after enough game launches without rebooting. + General system stability improvements to enhance the user's experience. ## 1.1.0 + Support was implemented for 13.0.0. + `mesosphère` was updated to reflect the latest official kernel behavior. + `ncm` was updated to reflect the latest official behaviors. + `erpt` was updated to reflect the latest official behaviors. + Two new services ("sprofile") were added to `erpt`, and have been fully reimplemented. + **Please Note**: These services provide a way for settings to be pushed to consoles over the internet without system update. + Because there appear to be no settings pushed out yet, this implementation fundamentally cannot be fully tested right now, but hopefully there are no issues once settings begin being distributed. + The `LogManager` system module was reimplemented. + This system module provides services that some games use for logging. + Atmosphere's reimplementation supports logging to the SD card (if `lm!enable_sd_card_logging` is true) and to ams.TMA. + To control the directory where logs are saved, modify the `lm!sd_card_log_output_directory` setting. + Atmosphere's reimplementation is disabled by default (in order to save memory), but can be enabled by setting `lm!enable_log_manager` to true. + This will allow reading over logs from games which use the services (or potentially logging from homebrew in the future), which can be useful to developers. + Please note that when TMA is fully implemented in the future, enabling TMA will forcibly enable `LogManager`. + General system stability improvements to enhance the user's experience. ## 1.0.0 + `fusee` was completely re-written in C++ to use the same atmosphere-libs APIs as the rest of atmosphere's code. + The rewrite was performed with a big emphasis on ensuring a good boot speed, and generally boot should be much faster than it was previously. + Depending on SD card/environment, boot speed may now be slightly faster than, roughly the same as, or slightly slower than when booting with hekate. + The obvious low-hanging fruit for performance improvements has been picked, so hopefully the improved performance is to everybody's liking. + SD card compatibility was improved: fusee should now have SD card compatibility identical to the official OS driver. + **Please Note**: various components were renamed (fusee-primary.bin -> fusee.bin, fusee-secondary.bin -> package3). + If you use another bootloader (like hekate), you may need to update your configuration to use the new layout. + **Please Note**: BCT.ini no longer exists, nogc configuration has been moved to `/atmosphere/stratosphere.ini`. + If you rely on custom nogc configuration, please be sure to update accordingly. + Custom splash screen BMP parsing is no longer supported (as it slows down boot for 99% of users). + To compensate for this, a script to insert a custom splash screen into a `package3` binary has been added to the `utilities` folder of the atmosphere repository. + The release build should be equivalent to running the following command from the root of the atmosphere repository: `python utilities/insert_splash_screen.py img/splash.png fusee/package3` + A number of pending changes were made, following the end of the relevant testing periods: + `mesosphere` is no longer opt-out, and stratosphere code will begin depending on its being present/in use. + `NCM` is no longer opt-out. + The cleanup to ease the transition from < 0.19.0 to 0.19.0 has been removed. + General system stability improvements to enhance the user's experience. ## 0.20.1 + An issue was fixed that caused severely degraded performance after wake-from-sleep on Mariko hardware. + This was due to Mariko MTC resulting in a frequency of 1599.999MHz instead of 1600MHz. + Due to this off-by-one, Nintendo's EMC management code failed to initialize/take over, and after wake from sleep RAM would be in a strange state. + General system stability improvements to enhance the user's experience. ## 0.20.0 + DRAM training (MTC) was implemented for Mariko hardware, increasing RAM speed from 204MHz to 1600MHz. + This significantly optimizes Mariko boot speed, cutting boot time roughly in half. + Typical boot time reductions (measured as "select fusee" to "home menu visible"): + Normal (Iowa): ~35 seconds -> ~18 seconds. + Lite (Hoag): ~65 seconds -> ~30 seconds. + NOTE: Work is being started on a re-written `fusee` component, with an eye specifically towards ensuring a good boot speed. + With any luck, boot will be much much faster on all units (Mariko and Erista) in an upcoming release. + Sept was replaced, and deleted from the repository. + Erista units now use a custom TSEC firmware to manage key derivation. + For more details, contact SciresM#0524 on discord. + This has a number of benefits, including: + This greatly simplifies key derivation logic by making it consistent on all firmwares. + Fusee no longer accesses/uses keyblobs at all, so units which have accidentally destroyed/lost keyblobs can boot without them. + This greatly increases stability (sept was the biggest source of boot failures). + This improves boot speed (sept rebooted multiple times, performed hardware init multiple times, and was generally very slow). + Atmosphère build process is now much saner. + A number of improvements were made to the dmnt cheat engine. + Cheats which take in a memory region operand may now use types "2" or "3" to perform accesses relative to the alias/aslr regions, respectively. + Support was added for an "else" opcode in the cheat engine, to make writing certain conditional logic more natural. + Support was added for a cheat orchestrator homebrew (like edizon) to detach from a cheat process/set the master cheat programmatically. + Daybreak now provides a warning when attempting to install a firmware newer than the highest version atmosphère knows it supports. + To facilitate this, exosphere now exposes the supported HOS version via an extension ConfigItem. + A number of minor issues were fixed, including: + Several mesosphere debug SVC implementations were updated to reflect the semantics of the latest kernel. + Support was fixed for deriving BIS encryption keys on certain prototype hardware. + General system stability improvements to enhance the user's experience. ## 0.19.5 + Support was added for 12.1.0. + LayeredFS support was added for OpenDataStorageWithProgramIndex commands. + Certain games using newer (7.0.0+ APIs) which include multiple programs under a single title previously could not be modified. + These are now supported as normal, and LayeredFS should have 100% compatibility again. + A number of minor issues were fixed, including: + The Reboot to Payload NRO was updated to allow the OS to save state prior to rebooting (thanks @AuroraWright)! + An issue was fixed that could cause dns.mitm to fail when games requested resolution of an empty string. + An issue was fixed that caused a memory leak in the erpt system module. + This would eventually cause a system crash after ~540 reports were generated without rebooting. + A number of minor improvements were made to improve mesosphere's accuracy. + General system stability improvements to enhance the user's experience. ## 0.19.4 + Support was added for 12.0.3. + A number of minor issues were fixed, including: + An issue was fixed that could cause heap memory corruption when allocation was highly contended. + An issue was fixed that could cause sleep to fail under certain conditions. + An issue was fixed that could cause a scheduler slow path to be taken more often than necessary. + General system stability improvements to enhance the user's experience. ## 0.19.3 + Support was added for 12.0.2. + A number of minor issues were fixed, including: + An issue was fixed in dns.mitm that caused a crash when games attempted to resolve the IP address of nullptr. + An issue was fixed in erpt that would cause an abort when booting without having ever booted stock previously. + An issue was fixed in (file-based) emummc that caused an error on system format/downloading certain games. + General system stability improvements to enhance the user's experience. ## 0.19.2 + Atmosphère's components were further updated to reflect latest official behaviors as of 12.0.0. + Notably, `erpt` was updated to implement the new forced shutdown detection feature. + When a forced-shutdown occurs, an erpt_report will be generated and saved to the SD card on the next boot. + Atmosphere-libs was updated to use GCC 11 (latest devkitA64/devkitARM releases). + Initial inspections show mild-to-moderate optimizer improvements in several important places (kernel is 0x3000 smaller). + General system stability improvements to enhance the user's experience. + A number of minor issues were fixed, including: + A bug was fixed that caused a black screen when attempting to boot firmware versions 2.0.0-4.1.0. + A bug was fixed that caused sm to abort when at the session limit, rather than returning error codes. + A bug was fixed that allowed for resource exhaustion on 12.0.0, under certain circumstances. + Several issues were fixed, and usability and stability were improved. ## 0.19.1 + An issue was fixed that caused a fatal error when using official `migration` services to transfer data between consoles. + An issue was fixed in `ncm` that caused an error when the OS tried to enumerate installed SD card content. + Several issues were fixed, and usability and stability were improved. ## 0.19.0 + Support was added for 12.0.0. + `mesosphère` was updated to reflect the latest official kernel behavior. + `sm`, `boot2`, `pgl` were updated to reflect the latest official behaviors. + **Please Note**: 12.0.0 added a new protocol for IPC ("tipc"), which has been freshly reimplemented in its entirety. + It is possible there may be as of yet unfound issues; if there are, please send the appropriate crash reports to SciresM (SciresM#0524 on discord). + Homebrew which uses atmosphere extensions (including the mitm API) will need to be re-compiled in order to function on 0.19.0. + I apologize for this, but it's unavoidable for technical reasons. If you're affected by this and mad about it, please contact SciresM to complain. + `erpt` was partially updated to reflect the latest official behaviors. + New features were added to erpt to track the activity of running applets, and to detect when a forced shutdown occurs. + These behaviors have been temporarily stubbed, as they are not necessary for 12.0.0 to run (and their outputs won't be saved anywhere). + A future atmosphère update will implement these behaviors, in the interest of reflecting official logic as faithfully as we can. + Atmosphère no longer uses the /contents/ folder for its own programs. + Atmosphère's system modules are now bundled together in the single file "stratosphere.romfs". + For those working on developing for atmosphère, executables inside the /contents/ directory will be preferred to those in "stratosphere.romfs". + **Please Note**: In order to facilitate this change (and the desired behavior), the first time you boot after extracting a release zip, atmosphère system modules inside /contents/ will be deleted. + This will have no impact on user programs (it only removes programs with specific program ids). + Improvements were made to mesosphere, including: + An extension InfoType was added for getting the current process handle, without having to spawn a thread and do IPC with oneself. + An issue was fixed in SvcSetDebugThreadContext. + An issue was fixed when doing IPC with user buffers. + Support was fixed for toggling the custom setting `usb!usb30_force_enabled` on 9.0.0+. + This was broken by Nintendo's introducing a dependency that made USB a requirement to launch before custom settings are parsed. + Since the fix, you can now toggle the setting (as you could prior to atmosphère 0.9.4), and it will work as expected. + **Please Note**: Enabling USB 3.0 often severely impacts wireless communications. + Because of this, the setting will default to off. If you experience issues with it enabled, consider disabling it. + A warning was added to daybreak when resetting the console to factory settings. + Substantial work was completed towards atmosphere's upcoming implementation of the host target connection protocol. + Once completed, users will be able to interact with a Switch running atmosphère via a PC application ("Starlink") currently under development. + Planned eventual features for connected consoles include a gdbstub, interacting with memory (for cheat development), streaming gameplay audio and video, and accessing the Switch's SD card filesystem. + Switch homebrew will also have access to a (configurable and sandboxed) filesystem on the host PC, while connected. + Towards this end, the following was accomplished: + The "htc" system module was reimplemented completely. + The system module which provides remote access to the SD card was reimplemented completely. + This is currently the active focus of atmosphère's development. + **Please Note**: Support is not yet completed, and users are disadvised from interacting with the related settings for the time being, unless they particularly know what they're doing. + A number of minor issues were fixed, including: + A bug was fixed in `dmnt` that could cause a fatal when launching certain games with cheats active. + An issue was fixed that could cause an abort in `sm` when using a large number of custom system modules. + An issue was fixed that prevented launching gamecards on 1.0.0. + Minor issues were fixed in the cheat virtual machine's behavior. + Several issues were fixed, and usability and stability were improved. ## 0.18.1 + A number of minor issues were fixed, including: + The new `dns.mitm` module added in 0.18.0 no longer fatal errors when receiving port=nullptr. + This fixes youtube ad-blocking, and possibly other usecases. + A bug was fixed that caused ams.mitm to incorrectly cache data storages. + This potentially broke DLC when using romfs mods, and could have caused other issues (e.g. with custom themes, and maybe other cases). + A bug was fixed in power state control module registration. + This might fix a weird edge case with system module dependencies on sleep/wake, but probably nobody should notice any differences. + A bug was fixed where mesosphere sometimes treated virtual core IDs as though they were physical core IDs. + This had zero impact, because for Switch virtual core == physical core, but it could have affected future platforms if it had remained unresolved. + Several issues were fixed, and usability and stability were improved. ## 0.18.0 + A new mitm module was added (`dns.mitm`). + This provides a highly configurable mechanism for redirecting DNS resolution requests. + By default atmosphère redirects resolution requests for official telemetry servers to a loopback address. + Documentation on how to configure `dns.mitm` to meet your more specific needs may be found [here](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/features/dns_mitm.md). + The service framework API (`sf`) was refactored to be more accurate to official logic and greatly reduce memory requirements. + The comparison of atmosphère module memory usage versus Nintendo's found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons) was updated to reflect this. + **Please Note**: If you are a developer using the libstratosphere service APIs, some updating may be required. Contact SciresM#0524 on discord for assistance if required. + A number of deprecations were removed, following a general codebase cleanup: + The `sm` extension to not unregister services on connection close was superseded by official opt-in logic in 11.0.0, and has been removed in favor of official logic. + This should have zero impact on users. + The temporary `hid-mitm` added in 0.9.0 has finally been removed, following over a year of deprecation. + There shouldn't be any homebrew in use still affected by this, but the situation will be monitored. + If this is somehow still a real issue, an unaffiliated hid mitm sysmodule providing the same functionality can be created and released, separate from atmosphère itself. + Several issues were fixed, and usability and stability were improved. ## 0.17.1 + A number of atmosphère's modules were using more memory than their Nintendo equivalent's in 0.17.0; a number of code generatio tweaks have been applied to fix this across the board. + A detailed comparison of atmosphère module memory usage versus Nintendo's was made and can be found [here](https://github.com/Atmosphere-NX/Atmosphere/wiki/Memory-Comparisons). + Several minor bugs were fixed, including: + A bug was fixed in mesosphère that caused games which attempt to map more memory than the Switch has to fail. + This affected "Piczle Lines DX 500 More Puzzles!", and possibly other games. + Enabling configuration to "blank" PRODINFO no longer causes a hang on Mariko devices (or any devices with newer format). + Several issues were fixed, and usability and stability were improved. ## 0.17.0 + fusee was heavily rewritten in order to add support for Mariko hardware. + **Please Note**: Mariko hardware currently has no (and may not ever have any) software exploits; fusee works when loaded from bootloader context with the right keys in the security engine. No means of getting the system into this state is provided. + An issue was fixed in the way shutdown was performed on Erista hardware. + This fixes an issue that caused OFW to black screen on boot after power off from atmosphere without first doing a reboot. + This also substantially improves power drain when the system is shut off; consoles powered off from Atmosphere should now drain battery at the same reduced rate as original firmware. + A number of minor changes were made, including: + A number of inconsistencies in the build system were fixed. + For those building atmosphère at home, the `boot` sysmodule will no longer rebuild every time make is invoked. + This substantially improves build times during development iteration. + `sm` was updated to more accurately reflect how official code manages request deferral. + `mesosphère` was updated to more accurately reflect official kernel management of the trace buffer. + `mesosphère` was updated to improve kernel loader's logic by taking advantage of the assumption that we only boot our kernel, not Nintendo's. + As it has been a few months with zero reported issues, `mesosphère` is now opt-out. + Users who wish to begin using or continue using mesosphere should use the standard/cool kids zip ("atmosphere-"). + Users who wish to opt-out of mesosphere should download and extract the opt-out zip ("atmosphere-WITHOUT_MESOSPHERE-"). + Several issues were fixed, and usability and stability were improved. ## 0.16.2 + Atmosphère release zips no longer bundle BCT.ini, instead relying on defaults in code. + This means atmosphere updates should no longer overwrite any user configuration at all. + If you wish to modify BCT.ini config, copy the template from /config_templates/ as with other configuration. + `pgl` and `creport` were further updated to reflect differences in official behavior in 11.0.0. + An issue was fixed that caused creport to be launched multiple times on process crash. + This fixes the "duplicate reports" issue that sometimes plagued people. + A new system setting (`atmosphere!enable_am_debug_mode`) configuring am to use debug mode. + If you are not a developer or don't see a clear use for this, leave it configured to the default (off). + Reboot to payload NRO was updated to fix support with certain payloads. + Support was fixed for atmosphere's extension to support homebrew use of new (8.0.0+) kernel mappings. + In particular, when running tracing debug builds of `mesosphère`, hbloader now has access to the kernel trace buffer. + Several issues were fixed, and usability and stability were improved. ## 0.16.1 + Support was added for 11.0.1. + `mesosphère` was updated to reflect the latest official kernel behavior. + A new svc::InfoType added in 11.0.0 was implemented (it wasn't discovered before 0.16.0 released). + The new Control Flow Integrity (CFI) logic added in 11.0.0 kernel was implemented. + `fs` logic was refactored and cleaned up to reflect some newer sysmodule behavioral and structural changes. + `exosphère` was updated to allow dynamic control of what uart port is used for logging. + This can be controlled by editing the `log_port`, `log_baud_rate`, and `log_inverted` fields in `exosphere.ini`. + `mesosphère` was updated to improve debugging capabilities. + This is still a work in progress, but developers may be interested. + A bug was fixed that caused `fatal` to fatal error if the fatal process was already being debugged. + Several issues were fixed, and usability and stability were improved. ## 0.16.0 + Support was added for 11.0.0. + `exosphère` was updated to reflect the latest official secure monitor behavior. + `mesosphère` was updated to reflect the latest official kernel behavior. + `loader`, `sm`, `boot`, `pgl` were updated to reflect the latest official behaviors. + **Please Note**: 11.0.0 implements an opt-in version of the atmosphère `sm` extension that allows for closing session without unregistering services. + Correspondingly, the extension will be deprecated in favor of the new official opt-in command. In 0.17.0, it will be removed entirely. + If your custom system module relies on this extension (however unlikely that seems to me), please update it accordingly. + `erpt` was partially updated to provide compatibility with 11.0.0. + The latest firmware attaches additional fields and context information to logs. + A future atmosphère update will implement this logic, so that users who are interested can also get the new information when examining their logs. + **Please Note**: 11.0.0 introduced breaking changes to the `usb` system module's `usb:ds` API. + Homebrew which uses the `usb:ds` service should rebuild with the latest libnx version to support running on 11.0.0. + The `boot` system module was rewritten to reflect the huge driver changes introduced in 8.0.0. + This includes a number of improvements to both logo display and battery management logic. + Support was added for configuring the address space width for `hbl`. + The `hbl_config!override_address_space_(#)` and `hbl_config!override_any_app_address_space` can now be set to `39_bit`, `36_bit`, or `32_bit` to control the address space for hbl on a per-override basis. + If a configuration has not been set, hbl will now default to 39-bit address space. + Previously, a legacy 36-bit address space was always used to maintain compatibility with 1.0.0. + A new loader extension was added to support 39-bit whenever possible (including mesosphere-on-1.0.0), with fallback to 36-bit when unavailable. + Support was added to a number of components for running on Mariko hardware. + The `boot` system module can now safely be run on mariko hardware, performing correct hardware initialization. + Daybreak (and generally, system update logic) were updated to be usable on Mariko. + Boot0 protection/management logic was updated to perform correct actions on Mariko. + Reboot to payload does not and cannot work on Mariko. Correspondingly, A "fatal error" handler was written, to display and save fatal errors from within TrustZone. + **Please Note:** Atmosphere is still not properly usable on Mariko hardware. + In particular, wake-from-sleep will not properly function (the magic numbers aren't set correctly), among a few other minor issues. + `exosphère` received support for building under debug configuration. + A small (otherwise unused) portion of IRAM is now reserved for debug-only exosphere code (this region is unused/untouched under release config). + This enables logging (including printf) to uart from the secure monitor, for those interested. + A number of bugs were fixed, including: + Minor issues in a number of filesystem related code were fixed. + An issue was fixed that could cause NCM to abort on consoles which came with 3.0.x and were never updated. + Several issues were fixed, and usability and stability were improved. ## 0.15.0 + fusee-primary's panic display was updated to automatically identify and give suggestions to resolve many of the most common errors users encounter. + Having been tested as well as I can alone, `mesosphere` (atmosphère's reimplementation of the Nintendo Switch kernel) is now available for users interested in trying it. + Beginning in this release and until it is stable and well-tested, atmosphère will distribute two zips. + Users who wish to opt-in to mesosphere should download and extract the "cool kids" zip ("atmosphere-EXPERIMENTAL-"). + Users who do not wish to use mesosphere should continue using the normal zip ("atmosphere-"). + Users may detect whether mesosphere is active in system settings. + When mesosphere is active, the system version string will display "M.15.0" rather than "0.15.0", and so on for future releases. + Crash reports and the like will contain information on whether or not the user is using mesosphere, as well. + There are "probably" no material user-facing benefits to using mesosphere at this time. + Developers may be interested in the fact that mesosphere provides many newer SVC APIs even when on lower firmware versions. + The primary benefit to using mesosphere is that any issues you may encounter and report to me will be fixed. + All users who choose to opt in to using mesosphere have my deepest gratitude. + **Note:** If using hekate instead of fusee-primary, you will have to wait for the next hekate release for mesosphere to function, as hekate's support has not yet been included in an official release build. + This will be updated in the release notes when hekate provides a new release. + As mentioned in previous release notes, when mesosphere is stable and well-tested, it will be enabled by default and atmosphère's version will transition to 1.0.0. + Having been tested sufficiently over the last half-year, Atmosphere's NCM implementation is now opt-out, rather than opt in. + In the unlikely event that any issues are encountered, please report them to @SciresM. + Users interested in opting out of using our implementation should set `stratosphere!disable_ncm = 1` in BCT.ini. + The NCM implementation will stop being opt-out in a future update, probably around the same time that mesosphere becomes opt-out instead of opt-in. + Several bugs were fixed, including: + Loader now sets HBL's thread priority to a higher value when loading it in applet mode. + This fixes an extremely-slow launch ("hang") when using applet-HBL with certain games that do not suspend while inactive (e.g. Super Mario Sunshine). + set.mitm now caches user language configuration much more heavily. + This severely reduces lag in certain games which misuse the "nn::oe::GetDesiredLanguage()" API. + A bug was fixed that could cause erpt to fatal when loading an official save file that had error report attachments in it. + General system stability improvements to enhance the user's experience. ## 0.14.4 + Several bugs were fixed involving the official jit sysmodule added in 10.0.0. + A Process handle leak was fixed when JitPlugin NRRs were registered with the `ro` sysmodule. + This prevented processes using jit from being able to exit, causing a full system freeze. + The `sm` atmosphere extension to not unregister services when the server's connection is closed was special-case disabled for `jit:u`. + This extension is normally desirable in order to allow more concurrent processes to exist (as only 0x40 sm connections may ever be concurrently open), but official jit sysmodule relies on the behavior. + This would cause crashes on attempts to launch a program using jit services more than once per reboot. + General system stability improvements to enhance the user's experience. ## 0.14.3 + Support was added for 10.2.0. + General system stability improvements to enhance the user's experience. ## 0.14.2 + A bug was fixed that could cause a deadlock when installing mitm services. + Fixing this required a breaking change to the client behavior when installing a mitm service, and so custom sysmodules which use mitm will need to be re-compiled to function properly. + A bug was fixed that caused atmosphere sysmodules to respond incorrectly when receiving invalid messages. + A bug was fixed that caused fatal auto-reboot timing to work improperly. + Support was added to fusee for loading binaries for `mesosphere`, atmosphère's reimplementation of the Nintendo Switch kernel. + 0.14.2 does not include mesosphere, but those who are especially interested can build and test mesosphere themselves. + In the future, to enable a sufficient testing period Atmosphère releases will distribute two zips for some time. + One zip will use mesosphere, and the other will not. + This will allow users who are interested to opt-in to mesosphere usage before it has been tested to be stable. + When mesosphere is stable and well-tested, it will be enabled by default and Atmosphère's version will transition to 1.0.0. + General system stability improvements to enhance the user's experience. ## 0.14.1 + An issue was fixed in 0.14.0 that would cause a black screen on boot when the INI1's size was not aligned to 8 bytes. + General system stability improvements to enhance the user's experience. ## 0.14.0 + An API (`ams:su`) was added to allow homebrew to safely install system upgrades or downgrades. + This is a re-implementation of the logic that `ns` uses to install gamecard system updates. + Nintendo (and now atmosphère) uses an installation process that can recover no matter where a failure occurs, which should significantly improve the safety of custom system update installation. + Support was added to `exosphère` for running on Mariko hardware. + **Please note**: Atmosphère still does not support Mariko, and should not be run on Mariko yet. + Certain stratosphere components do not handle mariko-specific logic fully correctly yet, and may initialize or interact with hardware incorrectly. + This will be fixed and support will be added over the remainder of the Summer. + A homebrew application (`daybreak`) was added that uses the system updater API (with thanks to @Adubbz for both design and implementation). + `daybreak` is included with atmosphère, and functions as a safer/more accurate equivalent to e.g. ChoiDujourNX. + Upgrades/downgrades can be installed from a folder containing the update NCAs on the SD card. + Because the update logic functions identically to Nintendo's, `daybreak` will be safe to use on Mariko when the rest of atmosphère has support. + **Please note**: Daybreak requires that meta (.cnmt) NCAs have the correct extension `.cnmt.nca`. + This is because gamecard system update logic uses extension to determine whether to mount the content. + [Several](https://gist.github.com/HookedBehemoth/df36b5970e1c5b1b512ec7bdd9043c6e) [scripts](https://gist.github.com/antiKk/279966c27fdfd9c7fe63b4ae410f89c4) have been made by community members to automatically rename folders with incorrect extensions. + A bug was fixed that would cause file-based emummc to throw an error (showing a hexdump) on boot. + Major thanks to @hexkyz for tracking down and resolving this. + A number of minor issues were resolved, including: + fusee now prints information to the screen when an error occurs, instead of getting stuck trying to initialize the display. + A race condition in Horizon was worked around that could prevent boot under certain circumstances. + A bug was fixed that would cause atmosphère modules to open ten copies of certain filesystems instead of one. + This could cause object exhaustion under certain circumstances. + For those interested in atmosphère's future development plans, the project's [roadmap](https://github.com/Atmosphere-NX/Atmosphere/blob/ac9832c5ce7be5832f6d29f6564a9c03e7efd22f/docs/roadmap.md) was updated. + General system stability improvements to enhance the user's experience. ## 0.13.0 + `exosphère`, atmosphère's secure monitor re-implementation, was completely re-written. + `exosphère` was the first component authored for the project in early 2018. It is written in C, and in a style very different from the rest of atmosphère's code. + This has made the codebase difficult to maintain as time has gone on. + `exosphère` was also written to conform to constraints and assumptions that simply no longer apply when cfw is not launched from the web browser, and when warmboothax is possible. + Even beyond these issues, `exosphère` used all but 1KB of the 64KB of space available to it. This was a problem for a few reasons: + Each new system update added requires additional space to support (to add new keys and reflect various changes); 10.0.0 support used up 3 of the 4KB we had left. + atmosphère will want to have software support for mariko hardware, and this is not possible to fit in 1 KB. + The `exosphère` rewrite (which was codenamed `exosphère2` during development) solves these problems. + The new codebase is C++20 written in atmosphère's style. + This solves the maintainability problem, and should make understanding how the secure monitor works *much* easier for those interested in using the code as a reference implementation. + In addition, the new implementation currently uses ~59.5 of the 64KB available. + Several potential code changes are planned that can save/grant access to an additional ~2-3 KB if needed. + Unlike the first codebase, the new `exosphère` actually already has space allocated for future keys/etc. It is currently expected that the reserved space will never be required. + The previous implementation chose not to implement a number of "unimportant" secure monitor functions due to space concerns. The new code has enough breathing room that it can implement them without worries. :) + Finally, the groundwork for mariko support has been laid -- there are only a few minor changes needed for the new secure monitor implementation to work on both erista and mariko hardware. + **Please note**: `exosphère` is only one of many components, and many more need changes to support running on mariko hardware. + Software-side support for executing on mariko hardware is expected some time during Summer 2020, though it should also be noted that this is not a hard deadline. + **Please note**: The new `exosphère` binary is not abi-compatible with the old one. Users who boot using hekate should wait for it to update before running 0.13.0 (or boot fusee-primary via hekate). + atmosphère's api for target firmware was changed. All minor/micro system versions are now recognized, instead of only major versions. + This was required in order to support firmware version 5.1.0, which made breaking changes to certain IPC APIs that caused atmosphère 0.12.0 to abort. + **Please note**: this is (unavoidably) a breaking change. System modules using atmosphere-libs will need to update to understand what firmware version they are running. + `emummc` was updated to include the new changes. + `emummc` now uses an updated/improved/faster SDMMC driver. + File-based emummc is now almost as fast as raw partition-based emummc. + For those interested in atmosphère's future development plans, the project's [roadmap](https://github.com/Atmosphere-NX/Atmosphere/blob/f68d33b70aed8954cc2c539e5934bcaf37ba51da/docs/roadmap.md) was updated. + General system stability improvements to enhance the user's experience. ## 0.12.0 + Configuration for exosphere was moved to sd:/exosphere.ini. + This is to facilitate BIS protection changes described below. + Hopefully having this outside of the Atmosphere folder will prevent accidental deletion, since this now contains important settings. + Atmosphere's bis protection policy for the PRODINFO partition was substantially reworked. + Support was added for "automatically" performing a "blanking" operation to PRODINFO without actually modifying NAND. + This is equivalent to using the "incognito" homebrew tool, but NAND is never actually modified. + This can be turned on in sysmmc by setting `blank_prodinfo_sysmmc=1` in exosphere.ini, and in emummc by setting `blank_prodinfo_emummc=1` in exosphere.ini. + **Please note**: This is not known to be safe. There is a lack of research on whether the information blanked out is cached elsewhere in the system. + Usage of this option is not encouraged for this reason. + Support was added for writing to the PRODINFO partition, if a verified encrypted backup has been made. + PRODINFO is the only system data that cannot be recovered if not backed up, and thus Atmosphere has backed it up to the SD card on boot for some time now. + Users who wish to modify their calibration data may now do so unconditionally in emummc, and in sysmmc if `allow_writing_to_cal_sysmmc=1` is set in exosphere.ini. + **Please note**: This is heavily discouraged, and the typical user will almost never want to do this. + Setting this option will cause Atmosphere to attempt to verify (or create) an encrypted backup of the PRODINFO data to an unused region in the partition. + The backup is encrypted with per-console keys that Atmosphere's developers do not know. + If the backup is not verified or created, writes will not work. Users who have corrupted their PRODINFO in the past are encouraged to flash a good backup to allow use of this setting. + Reads and writes to the region used for the securely encrypted backup will appear to succeed, but will actually read/write from a buffer filled with garbage in memory. + Support will be investigated in the future for supporting booting with fully blanked calibration. + This is desirable to allow boot to succeed for users who lost their calibration data due to bricking homebrew before bis protection was implemented. + `creport` has been updated to use the new screenshot APIs added in 9.0.0+. + On 10.0.0+, if a crash occurs in an application (not applet or sysmodule) a screenshot will now be automatically saved to the SD card. + If the user applies a patch to vi on 9.0.0 (as the command this uses was previously for dev-units only), this can also work on 9.0.0. + The new sysmodule `pgl` added in 10.0.0 was reimplemented. + `pgl` ("Program Launcher", probably) is responsible for managing launched user-processes, previously this was handled by NS. + The most exciting thing about pgl is that it finally provides an API for multiple clients to subscribe to process events. + Using these new APIs, system modules / other homebrew can subscribe to be notified whenever a process event occurs. + This means action can be taken on process launch, process exit, process crash, etc. + A slight concern with Nintendo's implementation is that each subscriber object uses 0x448 bytes of memory, and N only reserves 8KB for all allocations in pgl. + Atmosphere's implementation uses a 32KB heap, which should not be exhaustible. + Atmosphere's implementation has a total memory footprint roughly 0x28000 bytes smaller than Nintendo's. + A reimplementation was added for the `jpegdec` system module (thanks @HookedBehemoth)! + This allows two sessions instead of 1, so homebrew can now use it for software jpeg decoding in addition to the OS itself. + As usual the implementation has a very slightly smaller memory footprint than Nintendo's. + `dmnt`'s Cheat VM was extended to add three new opcodes. + The first new opcode, "ReadWriteStaticRegister", allows for cheats to read from a bank of 128 read-only static registers, and write to a bank of 128 write-only static registers. + This can be used in concert with new IPC commands that allow a cheat manager to read or write the value of these static registers to have "dynamic" cheats. + As an example, a cheat manager could write a value to a static register that a cheat to control how many of an item to give in a game. + As another example, a cheat manager could read a static register that a cheat writes to to learn how many items a player has. + The second and third opcodes are a pair, "PauseProcess" and "ResumeProcess". + Executing pause process in a cheat will pause the game (it will be frozen) until a resume process opcode is used. + These are also available over IPC, for cheat managers or system modules that want to pause or resume the attached cheat process. + This allows a cheat to know that the game won't modify or access data the cheat is accessing. + For example, this can be used to prevent Pokemon from seeing a pokemon a cheat is in the middle of injecting and turning it into a bad egg. + A bug was fixed that would cause the console to crash when connected to Wi-Fi on versions between 3.0.0 and 4.1.0 inclusive. + A bug was fixed that could cause boot to fail sporadically due to cache/tlb mismanagement when doing physical ASLR of the kernel. + A number of other minor issues were addressed (and more of Atmosphere was updated to reflect other changes in 10.0.x). + General system stability improvements to enhance the user's experience. ## 0.11.1 + A bug was fixed that could cause owls to flicker under certain circumstances. + For those interested in technical details, in 10.0.0 kernelldr/kernel no longer set cpuactlr_el1, assuming that it was set correctly by the secure monitor. + However, exosphere did not set cpuactlr_el1. This meant that the register held the reset value going into boot. + This caused a variety of highly erratic symptoms, including causing basically any game to crash seemingly randomly. + A number of other major inaccuracies in exosphere were corrected. + General system stability improvements to enhance the user's experience. ## 0.11.0 + Support was added for 10.0.0. + Exosphere has been updated to reflect the new key import semantics in 10.0.0. + kernel_ldr now implements physical ASLR for the kernel's backing pages. + Loader, NCM, and PM have been updated to reflect the changes Nintendo made in 10.0.0. + Creport was updated to use the new `pgl` service to terminate processes instead of `ns:dev`. + A reimplementation of the `erpt` (error reports) system module was added. + In previous versions of Atmosphere, a majority of error reports were prevented via a combination of custom creport, fatal, and stubbed eclct. + However, error reports were still generated via some system actions. + Most notably, any time the error applet appeared, an error report was generated. + By default, atmosphere disabled the *uploading* of error reports, but going online in OFW after an error report occurred in Atmosphere could lead to undesirable telemetry. + Atmosphere's `erpt` reimplementation allows the system to interact with existing error reports as expected. + However, all new error reports are instead saved to the sd card (`/atmosphere/erpt_reports`), and are not committed to the system savegame. + Users curious about what kind of telemetry is being prevented can view the reports as they're generated in there. + Reports are saved as msgpack (as this is what Nintendo uses). + Please note, not all telemetry is disabled. Play reports and System reports will continue to function unmodified. + With atmosphere's `erpt` implementation, homebrew can now use the native error applet to display errors without worrying about generating undesirable telemetry. + libstratosphere and libvapours received a number of improvements. + With thanks to @Adubbz for his work, the NCM namespace now has client code. + This lays the groundwork for first-class system update/downgrade homebrew support in the near future. + In particular, code implementing the os namespace is significantly more accurate. + In addition, Nintendo's allocators were implemented, allowing for identical memory efficiency versus Nintendo's implementations. + General system stability improvements to enhance the user's experience. ## 0.10.5 + Changes were made to the way fs.mitm builds images when providing a layeredfs romfs. + Building romfs metadata previously had a memory cost of about ~4-5x the file table size. + This caused games that have particularly enormous file metadata tables (> 4 MB) to exhaust fs.mitm's 16 MB memory pool. + The code that creates romfs images was thus changed to be significantly more memory efficient, again. + Memory requirements have been lowered from ~4x file table size to ~2x file table size + 0.5 MB. + There is a slight speed penalty to this, but testing on Football Manager 2020 only took an extra ~1.5 seconds for the game to boot with many modded files. + This shouldn't be noticeable thanks to the async changes made in 0.10.2. + If you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact SciresM. + Romfs building can be made even more memory efficient, but unless games show up with even more absurdly huge file tables it seems not worth the speed trade-off. + A bug was fixed that caused Atmosphere's fatal error context to not dump TLS for certain processes. + General system stability improvements to enhance the user's experience. ## 0.10.4 + With major thanks to @Adubbz for his work, the NCM system module has now been re-implemented. + This was a major stepping stone towards the goal of having implementations everything in the Switch's package1/package2 firmware. + This also lays the groundwork for libstratosphere providing bindings for changing the installed version of the Switch's OS. + **Please Note**: The NCM implementation will initially be opt-in. + The Atmosphere team is confident in our NCM implementation (and we have tested it on every firmware version). + That said, this is our first system module that manages NAND savegames -- and caution is a habit. + We do not anticipate any issues that didn't come up in testing, so this is just our being particularly careful. + Users interested in opting in to using our implementation should set `stratosphere!ncm_enabled = 1` in BCT.ini. + In the unlikely event that any issues are encountered, please report them to @SciresM. + The NCM implementation will stop being opt-in in a future update, after thorough testing has been done in practice. + A bug was fixed in emummc that caused Nintendo path to be corrupted on 1.0.0. + This manifested as the emummc folder being created inside the virtual NAND instead of the SD card. + It's unlikely there are any negative consequences to this in practice. + If you want to be truly sure, you can re-clone sysmmc before updating a 1.0.0 emummc to latest firmware. + Stratosphere system modules now use new Nintendo-style FS bindings instead of stdio. + This saves a modest amount of memory due to leaner code, and greatly increases the accuracy of several components. + These bindings will make it easier for other system modules using libstratosphere to interact with the filesystem. + This also lays the groundwork for changes necessary to support per-emummc Atmosphere folders in a future update. + Atmosphere's fatal error context now dumps 0x100 of TLS. + This will make it much easier to fix bugs when an error report is dumped for whatever caused the crash. + General system stability improvements to enhance the user's experience. ## 0.10.3 + Support was added for 9.2.0. + Support was added for redirecting manual html content for games. + This works like normal layeredfs, replacing content placed in `/atmosphere/contents//manual_html/`. + This allows for game mods/translations to provide custom manual content, if they so choose. + A number of improvements were made to Atmosphere's memory usage, including: + `fatal` now uses STB instead of freetype for rendering. + This saves around 1 MB of memory, and makes our fatal substantially leaner than Nintendo's. + `sm` no longer wastes 2 MiB unnecessarily. + fusee/sept's sdmmc access now better matches official behavior. + This improves compatibility with some SD cards. + `ro` has been updated to reflect changes made in 9.1.0. + The temporary auto-migration added in 0.10.0 has been removed, since the transitionary period is well over. + General system stability improvements to enhance the user's experience. ## 0.10.2 + hbl configuration was made more flexible. + Up to eight specific program ids can now be specified to have their own override keys. + This allows designating both the album applet and a specific game as hbl by default as desired. + Configuration targeting a specific program is now mutually exclusive with override-any-app for that program. + This fixes unintuitive behavior when override key differed for an application specific program. + Loader's external content fileystem support was fixed (thanks @misson20000!). + KernelLdr was reimplemented. + This is the first step towards developing mesosphere, Atmosphere's planned reimplementation of the Switch's Kernel. + The typical user won't notice anything different, as there are no extensions, but a lot of groundwork was laid for future development. + Improvements were made to the way Atmosphere's buildsystem detects source code files. + This significantly reduces compilation time (saving >30 seconds) on the machine that builds official releases. + Certain device code was cleaned up and made more correct in fusee/sept/exosphere (thanks @hexkyz!). + A number of changes were made to the way fs.mitm builds images when providing a layeredfs romfs. + Some games (Resident Evil 6, Football Manager 2020 Touch, possibly others) have enormous numbers of files. + Attempting to create a layeredfs mod for these games actually caused fs.mitm to run out of memory, causing a fatal error. + The code that creates these images was changed to be significantly more memory efficient. + However, these changes also cause a significant slowdown in the romfs building code (~2-5x). + This introduced a noticeable stutter when launching a game, because the UI thread would block on the romfs creation. + To solve this, fs.mitm now lazily initializes the image in a background thread. + This fixes stutter issues, however some games may be slightly slower (~1-2s in the worst cases) to transition from the "loading" GIF to gameplay now. + Please note: the slowdown is not noticeable in the common case where games don't have tons of files (typical is ~0.1-0.2 seconds). + Once the image has been built, there is no further speed penalty at runtime -- only when the game is launched. + A number of other bugs were fixed, including: + Several minor logic inversions that could have caused fatal errors when modding games. + Atmosphere's new-ipc code did not handle "automatic" recvlist buffers correctly, so some non-libnx homebrew could crash. + fs.mitm now correctly mitms sdb, which makes redirection of certain system data archives work again. + In 0.10.0/0.10.1, changing the system font/language did not work correctly due to this. + A bug was fixed in process cleanup that caused the system to hang on < 5.0.0. + The temporary hid-mitm added in Atmosphere 0.9.0 was disabled by default. + Please ensure your homebrew is updated. + For now, users may re-enable this mitm by use of a custom setting (`atmosphere!enable_deprecated_hid_mitm`) to ease the transition process some. + Please note: support for this setting may be removed to save memory in a future atmosphere release. + General system stability improvements to enhance the user's experience. ## 0.10.1 + A bug was fixed that caused memory reallocation to the system pool to work improperly on firmware 5.0.0 and above. + Atmosphere was always trying to deallocate memory away from the applet pool and towards the system pool. + The intent of this is to facilitate running more custom sysmodules/atmosphere binaries. + However, while memory was always successfully taken away from the applet pool, on 5.0.0+ granting it to the system pool did not work for technical reasons. + If you are interested in the technical details, talk to SciresM. + This has now been fixed by adding new kernel patches, and memory is correctly granted to the system pool as intended. + Atmosphere's library system has been overhauled: + libstratosphere's repository has been rebranded, more generally, to "Atmosphere-libs". + In addition to libstratosphere, a new general library for not-stratosphere-specific code has been added. + This is currently named `libvapours`. + In the future, kernel functionality will be available as `libmesosphere`. + The build system for stratosphere system modules has been similarly overhauled. + A number of other bugs were fixed, including: + A bug was fixed that could cause memory corruption when redirecting certain Romfs content. + A bug was fixed that could cause an infinite loop when redirecting certain Romfs content. + A bug was fixed that could cause certain NROs to fail to load. + This caused the latest version of Super Smash Bros to display "An error has occurred" on launch. + A bug was fixed that caused input/output array sizes for certain circumstances to be calculated incorrectly. + This caused cheats to fail to function properly. + C++ exception code is now more thoroughly removed from stratosphere executables. + This saves a minor amount of memory. + A number of minor logic inversions were fixed in libstratosphere. + These did not affect any code currently used by released Atmosphere binaries. + *Please note**: Because this update is releasing so soon after 0.10.0, the removal of the temporary hid-mitm has been postponed to 0.10.2. + Please ensure your homebrew is updated. + Random number generation now uses TinyMT instead of XorShift. + General system stability improvements to enhance the user's experience. ## 0.10.0 + Support was added for 9.1.0 + **Please note**: The temporary hid-mitm added in Atmosphere 0.9.0 will be removed in Atmosphere 0.10.1. + Please ensure your homebrew is updated. + The Stratosphere rewrite was completed. + libstratosphere was rewritten as part of Stratosphere's refactor. + Code responsible for providing and managing IPC services was greatly improved. + The new code is significantly more accurate (it is bug-for-bug compatible with Nintendo's code), and significantly faster. + ams.mitm was rewritten as part of Stratosphere's refactor. + Saves redirected to the SD card are now separated for sysmmc vs emummc. + **Please note**: If you find any bugs, please report them so they can be fixed. + Thanks to the rewrite, Atmosphere now uses significantly less memory. + Roughly 10 additional megabytes are now available for custom system modules to use. + This means you can potentially run more custom system modules simultaneously. + If system modules are incompatible, please ask their authors to reduce their memory footprints. + Atmosphere's configuration layout has had major changes. + Configuration now lives inside /atmosphere/config/. + Atmosphere code now knows what default values should be, and includes them in code. + It is no longer an error if configuration inis are not present. + Correspondingly, Atmosphere no longer distributes default configuration inis. + Templates are provided in /atmosphere/config_templates. + loader.ini was renamed to override_config.ini. + This fixes the longstanding problem that atmosphere updates overwrote user configuration when extracted. + Atmosphere's process override layout was changed. + Atmosphere now uses the /atmosphere/contents directory, instead of /atmosphere/titles. + This goes along with a refactoring to remove all reference to "title id" from code, as Nintendo does not use the term. + To make this transition easier, a temporary functionality has been added that migrates folders to the new directory. + When booting into 0.10.0, Atmosphere will rename /atmosphere/titles/`` to /atmosphere/contents/``. + This functionality may or may not be removed in some future update. + This should solve any transition difficulties for the typical user. + Please make sure that any future mods you install extract to the correct directory. + Support for configuring override keys for hbl was improved. + The key used to override applications versus a specific program can now be different. + The key to override a specific program can be managed via override_key. + The key to override any app can be managed via override_any_app_key. + Default override behavior was changed. + By default, atmosphere will now override the album applet with hbl unless R is held. + By default, atmosphere will now override any application with hbl only if R is held. + The default amount of applet memory reserved has been slightly increased. + This allows the profile selector applet to work by default in applet mode. + The way process override status is captured was changed. + Process override keys are now captured exactly once, when the process is created. + This fixes the longstanding issue where letting go of the override button partway into the process launch could cause problems. + The Mitm API was changed to pass around override status. + Mitm services now know what keys were held when the client was created, as well as whether the client is HBL/should override contents. + An extension was added to pm:info to allow querying a process's override status. + Thanks to process override capture improvements, hbl html behavior has been greatly improved. + Web applets launched by hbl will now always see the /atmosphere/hbl_html filesystem + Support was added to exosphere for enabling usermode access to the PMU registers. + This can be controlled via exosphere!enable_user_pmu_access in BCT.ini. + An enormous number of minor bugs were fixed. + dmnt's cheat VM had a fix for an inversion in opcode behavior. + An issue was fixed in fs.mitm's management of domain object IDs that could lead to system corruption in rare cases. + The Mitm API no longer silently fails when attempting to handle commands passing C descriptors. + On previous atmosphere versions, certain commands to FS would silently fail due to this... + No users reported any visible errors, but it was definitely a problem behind the scenes. + These commands are now handled correctly. + Atmosphere can now display a fatal error screen significantly earlier in the boot process, if things go wrong early on. + The temporary hid mitm will no longer sometimes cause games to fail to detect input. + Mitm Domain object ID management no longer desynchronizes from the host process. + An issue was fixed that could cause service acquisition to hang forever if certain sm commands were called in a precise order. + An off-by-one was fixed that could cause memory corruption in server memory management. + ... and too many more bugs fixed to reasonably list them all :) + General system stability improvements to enhance the user's experience. ## 0.9.4 + Support was added for 9.0.0. + **Please note**: 9.0.0 made a number of changes that may cause some issues with homebrew. Details: + 9.0.0 changed HID in a way that causes libnx to be unable to detect button input. + Homebrew should be recompiled with newest libnx to fix this. + Atmosphere now provides a temporary hid-mitm that will cause homebrew to continue to work as expected. + This mitm will be removed in a future Atmosphere revision once homebrew has been updated, to allow users to use a custom hid mitm again if they desire. + 9.0.0 introduced an dependency in FS on the USB system module in order to launch the SD card. + This means the USB system module must now be launched before the SD card is initialized. + Correspondingly, the USB system module can no longer be IPS patched, and its settings cannot be reliably mitm'd. + We know this is frustrating, so we'll be looking into whether there is some way of addressing this in the future. + An off-by-one error was fixed in `boot` system module's pinmux initialization. + This could theoretically have caused issues with HdmiCec communication. + No users reported issues, so it's unclear if this was a problem in practice. + A bug was fixed that could cause webapplet launching homebrew to improperly set the accessible url whitelist. + BIS key generation has been fixed for newer hardware. + Newer hardware uses new, per-firmware device key to generate BIS keys instead of the first device key, so previously the wrong keys were generated as backup. + This only affects units manufactured after ~5.0.0. + General system stability improvements to enhance the user's experience. ## 0.9.3 + Thanks to hexkyz, fusee's boot sequence has been greatly optimized. + Memory training is now managed by a separate binary (`fusee-mtc`, loaded by fusee-primary before fusee-secondary). + Unnecessarily long splash screen display times were reduced. + The end result is that Atmosphere now boots *significantly* faster. :) + **Note:** This means fusee-primary must be updated for Atmosphere to boot successfully. + The version string was adjusted, and now informs users whether or not they are using emummc. + Atmosphere now automatically backs up the user's BIS keys on boot. + This should prevent a user from corrupting nand without access to a copy of the keys needed to fix it. + This is especially relevant on ipatched units, where the RCM vulnerability is not an option for addressing bricks. + The `pm` system module was rewritten as part of Stratosphere's ongoing refactor. + Support was added for forward-declaring a mitm'd service before a custom user sysmodule is launched. + This should help resolve dependency issues with service registration times. + SM is now informed of every process's title id, including built-in system modules. + The `creport` system module was rewritten as part of Stratosphere's ongoing refactor. + creport now dumps up to 0x100 of stack from each thread in the target process. + A few bugs were fixed, including one that caused creport to incorrectly dump process dying messages. + Defaults were added to `system_settings.ini` for controlling hbloader's memory usage in applet mode. + These defaults reserve enough memory so that homebrew can launch swkbd while in applet mode. + The `fatal` system module was rewritten as part of Stratosphere's ongoing refactor. + Incorrect display output ("2000-0000") has been fixed. Fatal will now correctly show 2162-0002 when this occurs. + A longstanding bug in how fatal manages the displays has been fixed, and official display init behavior is now matched precisely. + General system stability improvements to enhance the user's experience. ## 0.9.2 + A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes: + Support for file-based emummc instances was fixed. + Please note: file-based emummc is still unoptimized, and so may be much slower than partition-based. + This speed differential should hopefully be made better in a future emummc update. + The way emummc handles power management was completely overhauled. + Emummc now properly handles init/de-init, and now supports low voltage mode. + Much better support for shutdown was added, which should assuage corruption/synchronization problems. + This should also improve support for more types of SD cards. + A bug was fixed that caused emummc to not work on lower system versions due to missing SVC access. + **Please note**: The configuration entries used for emummc have been changed. + `emummc_` prefixes have been removed, since they are superfluous given the `emummc` category they are under. + As an example, `emummc!emummc_enabled` is now `emummc!enabled`. + INI configurations made by @CTCaer's [tool](https://github.com/ctcaer/hekate/releases/latest) (which is the recommended way to manage emummc) should automatically work as expected/be corrected. + **If you do not wish to use the above, you will need to manually correct your configuration file**. + General system stability improvements to enhance the user's experience. + Stratosphere is currently in the process of being re-written/refactored. + Stratosphere was my (SciresM's) first C++ project, ever -- the code written for it a year ago when I was learning C++ is/was of much lower quality than code written more recently. + Code is thus being re-rwitten for clarity/stlye/to de-duplicate functionality, with much being moved into libstratosphere. + Stratosphere will, after the rewrite, globally use the `sts::` namespace -- this should greatly enhancing libstratosphere's ability to provide functionality for system modules. + The rewritten modules consistently have lower memory footprints, and should be easier to maintain going forwards. + The `sm`, `boot`, `spl`, `ro`, and `loader` modules have been tackled so far. + General system stability improvements to enhance the user's experience. ## 0.9.1 + Support was added for 8.1.0. + Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :) + General system stability improvements to enhance the user's experience. ## 0.9.0 + Creport output was improved significantly. + Thread names are now dumped on crash in addition to 0x100 of TLS from each thread. + This significantly aids debugging efforts for crashes. + Support was added for 32-bit stackframes, so reports can now be generated for 32-bit games. + `dmnt`'s Cheat VM was extended to add a new debug opcode. + With thanks to/collaboration with @m4xw and @CTCaer, support was added for redirecting NAND to the SD card (emummc). + Please note, this support is very much **beta/experimental**. + It is quite likely we have not identified all bugs -- those will be fixed as they are reported over the next few days/weeks. + In addition, some niceties (e.g. having a separate Atmosphere folder per emummc instance) still need some thought put in before they can be implemented in a way that makes everyone happy. + If you are not an advanced user, you may wish to think about waiting for the inevitable 0.9.1 bugfix update before using emummc as your default boot option. + You may especially wish to consider waiting if you are using Atmosphere on a unit with the RCM bug patched. + Emummc is managed by editing the emummc section of "emummc/emummc.ini". + To enable emummc, set `emummc!emummc_enabled` = 1. + Support is included for redirecting NAND to a partition on the SD card. + This can be done by setting `emummc!emummc_sector` to the start sector of your partition (e.g., `emummc_sector = 0x1A010000`). + Support is also included for redirecting NAND to a collection of loose files on the SD card. + This can be done by setting `emummc!emummc_path` to the folder (with archive bit set) containing the NAND boot partitions' files "boot0" and "boot1", and the raw NAND image files "00", "01", "02", etc. (single "00" file with the whole NAND image requires exFAT mode while multipart NAND can be used in both exFAT and FAT32 modes). + The `Nintendo` contents directory can be redirected arbitrarily. + By default, it will be redirected to `emummc/Nintendo_XXXX`, where `XXXX` is the hexadecimal representation of the emummc's ID. + The current emummc ID may be selected by changing `emummc!emummc_id` in emummc.ini. + This can be set to any arbitrary directory by setting `emummc!emummc_nintendo_path`. + To create a backup usable for emummc, users may use tools provided by the [hekate](https://github.com/CTCaer/hekate) project. + If, when using emummc, you encounter a bug, *please be sure to report it* -- that's the only way we can fix it. :) ## 0.8.10 + A bug was fixed that could cause incorrect system memory allocation on 5.0.0. + 5.0.0 should now correctly have an additional 12 MiB allocated for sysmodules. + Atmosphère features which check button presses now consider all controllers, isntead of just P1. + Support was added for configuring language/region on a per-game basis. + This is managed by editing `atmosphere/titles//config.ini` for the game. + To edit title language, edit `override_config!override_language`. + The languages supported are `ja`, `en-US`, `fr`, `de`, `it`, `es`, `zh-CN`, `ko`, `nl`, `pt`, `ru`, `zh-TW`, `en-GB`, `fr-CA`, `es-419`, `zh-Hans`, `zh-Hant`. + To edit title region, edit `override_config!override_region`. + The regions supported are `jpn`, `usa`, `eur`, `aus`, `chn`, `kor`, `twn`. + Atmosphère now provides a reimplementation of the `boot` system module. + `boot` is responsible for performing hardware initialization, showing the Nintendo logo, and repairing NAND on system update failure. + Atmosphère's `boot` implementation preserves AutoRCM during NAND repair. + NAND repair occurs when an unexpected shutdown or error happens during a system update. + This fixes a final edge case where AutoRCM might be removed by HOS, which could cause a user to burn fuses. + General system stability improvements to enhance the user's experience. ## 0.8.9 + A number of bugs were fixed, including: + A data abort was fixed when mounting certain partitions on NAND. + All Stratosphère system modules now only maintain a connection to `sm` when actively using it. + This helps mitigate the scenario where sm hits the limit of 64 active connections and crashes. + This sometimes caused crashes when custom non-Atmosphère sysmodules were active and the user played certain games (ex: Smash's Stage Builder). + fatal now uses the 8.0.0 clkrst API, instead of silently failing to adjust clock rates on that firmware version. + A wait loop is now performed when trying to get a session to `sm`, in the case where `sm:` is not yet registered. + This fixes a race condition that could cause a failure to boot under certain circumstances. + libstratosphere's handling of domain object closing has been improved. + Previously, this code could cause crashes/extremely odd behavior (misinterpreting what object a service is) under certain circumstances. + An optional automatic reboot timer was added to fatal. + By setting the system setting `atmosphere!fatal_auto_reboot_interval` to a non-zero u64 value, fatal can be made to automatically reboot after a certain number of milliseconds. + If the setting is zero or not present, fatal will wait for user input as usual. + Atmosphère now provides a reimplementation of the `ro` system module. + `ro` is responsible for loading dynamic libraries (NROs) on 3.0.0+. + On 1.0.0-2.3.0, this is handled by `loader`. + Atmosphere's `ro` provides this functionality (`ldr:ro`, `ro:dmnt`) on all firmware versions. + An extension was implemented to provide support for applying IPS patches to NROs. + All patches at paths like /atmosphere/nro_patches/<user-defined patch name>/<Hex Build-ID for NRO to patch>.ips will be applied, allowing for easy distribution of patches. + Both the IPS and IPS32 formats are supported. + Atmosphère now provides a reimplementation of the `spl` system module. + `spl` (Secure Platform Services) is responsible for cryptographic operations, including all communications with the secure monitor (exosphère). + In the future, this may be used to provide extensions to the API for interacting with exosphère from userland. + General system stability improvements to enhance the user's experience. ## 0.8.8 + Support was added for firmware version 8.0.0. + Custom exception handlers were added to stratosphere modules. + If a crash happens in a core atmosphere module now, instead of silently failing a reboot will occur to log the information to the SD card. + A bug was fixed in creport that caused games to hang when crashing under certain circumstances. + A bug was fixed that prevented maintenance mode from booting on 7.0.0+. + General system stability improvements to enhance the user's experience. ## 0.8.7 + A few bugs were fixed that could cause fatal to fail to show an error under certain circumstances. + A bug was fixed that caused an error when launching certain games (e.g. Hellblade: Senua's Sacrifice). + Loader had support added in ams-0.8.4 for a new (7.0.0+) flag bit in NPDMs during process creation, but forgot to allow this bit to be set when validating the NPDM. + dmnt's cheat virtual machine received new instructions. + These allow for saving, restoring, or clearing registers to a secondary bank, effectively doubling the number of values that can be stored. + SHA256 code has been swapped from linux code to libnx's new hw-accelerated cryptography API. + Extensions were added to smcGetInfo: + A ConfigItem was added to detect whether the current unit has the RCM bug patched. + A ConfigItem was added to retrieve the current Atmosphère build hash. + Exosphère now tells the kernel to enable user-mode exception handlers, which should allow for better crash reporting/detection from Atmosphère's modules in the future.. + Opt-in support was added for redirecting game save files to directories on the SD card. + Please note, this feature is **experimental**, and may cause problems. Please use at your own risk (and back up your saves before enabling it), as it still needs testing. + This can be enabled by setting `atmosphere!fsmitm_redirect_saves_to_sd` to 1 in `system_settings.ini`. + General system stability improvements to enhance the user's experience. ## 0.8.6 + A number of bugs were fixed, including: + A case of inverted logic was fixed in fs.mitm which prevented the flags system from working correctly. + Time service access was corrected in both creport/fatal. + This fixes the timestamps used in fatal/crash report filenames. + A coherency issue was fixed in exosphère's Security Engine driver. + This fixes some instability issues encountered when overclocking the CPU. + Loader now unmaps NROs correctly, when ldr:ro is used. + This fixes a crash when repeatedly launching the web applet on < 3.0.0. + Usage of hidKeysDown was corrected to hidKeysHeld in several modules. + This fixes a rare issue where keypresses may have been incorrectly detected. + An issue with code filesystem unmounting was fixed in loader. + This issue could occasionally cause a fatal error 0x1015 to be thrown on boot. + Two bugs were fixed in the implementations of dmnt's cheat virtual machine. + These could cause cheats to work incorrectly under certain circumstances. + PM now uses a static buffer instead of a dynamically allocated one during process launch. + This fixes a memory exhaustion problem when building with gcc 8.3.0. + A workaround for a deadlock bug in Horizon's kernel on >= 6.0.0 was added in dmnt. + This prevents a system hang when booting certain titles with cheats enabled (ex: Mario Kart 8 Deluxe). + set.mitm now reads the system firmware version directly from the system version archive, instead of calling into set:sys. + This fixes compatibility with 1.0.0, which now successfully boots again. + dmnt's cheat virtual machine had some instruction set changes. + A new opcode was added for beginning conditional blocks based on register contents. + More addressing modes were added to the StoreRegisterToAddress opcode. + These should allow for more complex cheats to be implemented. + A new system for saving the state of cheat toggles between game boots was added. + Toggles are now saved to `atmosphere/titles/<title id>/cheats/toggles.txt` when either toggles were successfully loaded from that file or the system setting `atmosphere!dmnt_always_save_cheat_toggles` is non-zero. + This removes the need for manually setting cheats from all-on or all-off to the desired state on each game boot. + The default behavior for loader's HBL support was changed. + Instead of launching HBL when album is launched without R held, loader now launches HBL when album or any game is launched with R held. + Loader will now override any app in addition to a specific title id when `hbl_config!override_any_app` is true in `loader.ini`. + Accordingly, the `hbl_config!title_id=app` setting was deprecated. Support will be removed in Atmosphère 0.9.0. + First-class support was added to loader and fs.mitm for enabling homebrew to launch web applets. + Loader will now cause the "HtmlDocument" NCA path to resolve for whatever title HBL is taking over, even if it would not normally do so. + fs.mitm will also now cause requests to mount the HtmlDocument content for HBL's title to open the `sdmc:/atmosphere/hbl_html` folder. + By default, this just contains a URL whitelist. + General system stability improvements to enhance the user's experience. ## 0.8.5 + Support was added for overriding content on a per-title basis, separate from HBL override. + This allows for using mods on the same title that one uses to launch HBL. + By default, `!L` is used for title content override (this is configurable by editing `default_config!override_key` in `loader.ini`) + This key combination can be set on a per-title basis by creating a `atmosphere/titles/<title id>/config.ini`, and editing `override_config!override_key`. + Content headers were added for the embedded files inside of fusee-secondary. + This will allow non-fusee bootloaders (like `hekate`) to extract the components bundled inside release binaries. + This should greatly simplify the update process in the future, for users who do not launch Atmosphère using fusee. + Support for cheat codes was added. + These are handled by a new `dmnt` sysmodule, which will also reimplement Nintendo's Debug Monitor in the future. + Cheat codes can be enabled/disabled at application launch via a per-title key combination. + For details, please see the [cheat loading documentation](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/cheats.md#cheat-loating-process). + Cheat codes are fully backwards compatible with the pre-existing format, although a number of bugs have been fixed and some new features have been added. + For details, please see [the compatibility documentation](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/cheats.md#cheat-code-compatibility). + An HIPC service API was added (`dmnt:cht`), that will allow user homebrew to interface with and control Atmosphère's cheat manager. + Please see [the relevant documentation](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/modules/dmnt.md). + Full client code can be found in [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere/blob/master/include/stratosphere/services/dmntcht.h). + Users interested in interfacing should see [EdiZon](https://github.com/WerWolv/EdiZon), which should have support for interfacing with Atmosphère's API shortly after 0.8.5 releases. + A bug was fixed that would cause Atmosphère's fatal screen to not show on 1.0.0-2.3.0. + A bug was fixed that caused Atmosphère's automatic ProdInfo backups to be corrupt. + General system stability improvements to enhance the user's experience. ## 0.8.4 + Support for 7.0.0/7.0.1 was added. + This is facilitated through a new payload, `sept`, which can be signed, encrypted, and then loaded by Nintendo's TSEC firmware. + `sept` will derive the keys needed to boot new firmware, and then load `sept/payload.bin` off the SD card and jump to it. + Recognition of applications for override/mitm has been improved. + Nintendo's official Title ID range (`0x0100000000000000`-`0x01FFFFFFFFFFFFFF`) is now enforced. + A deadlock condition was fixed involving libstratosphere mitm sysmodules. + Kernel patches for JIT support were added (Thanks, @m4xw!). + These loosen restrictions on caller process in svcControlCodeMemory. + `set.mitm` and `fs.mitm` were merged into a single `ams_mitm` sysmodule. + This saves a process ID, allowing users to run one additional process up to the 0x40 process limit. + A `bpc.mitm` component was added, performing custom behavior on shutdown/reboot requests from `am` or applications. + Performing a reboot from the reboot menu now reboots to atmosphere. This can be configured via `system_settings.ini`. + Performing a shutdown from the reboot menu now works properly with AutoRCM, and does a real shutdown. + General system stability improvements to enhance the user's experience. ## 0.8.3 + A custom warmboot firmware was implemented, which does not perform anti-downgrade fuse checks. + This fixes sleep mode when using a downgraded NAND. + This also removes Atmosphère's final dependency on Nintendo's encrypted PK11 binary; all components are now re-implemented. + The ExternalContentSource API was changed to not clear on failure. + Content override now supports an "app" setting, that causes all applications to be overridden with HBL instead of a specific title. + Note: because override keys are system-wide, using this setting will prevent using mods in games (as every game will be HBL). + A bug was fixed causing incorrect fatal-error output when svcBreak was called on 5.0.0+. + An extension was added to set.mitm to support customization of system settings. + These are controlled by `atmosphere/system_settings.ini`, see [here](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/modules/set_mitm.md) for documentation. + An extension was added to sm, adding a new `sm:dmnt` service. + This can be used by a debug monitor in order to debug the registration state of various other services. + A bug was fixed in the MitM API that could sometimes cause a system hang during boot. + A change was made to the MitM API: in cases where sm would have returned 0xE15 when installing a mitm service, it now defers the result (following GetService semantics). + Support for booting into maintenance mode by holding +/- was added to PM. + An extension was added to exosphere, adding a custom SMC that allows for DMA to IRAM. + In addition, smcGetConfig was extended to reboot to a payload in IRAM at 0x40010000 when ConfigItem 65001 is set to 2. + Fatal will now use this to reboot to sdmc:/atmosphere/reboot_payload.bin if present, when a vol button is pressed. + An example homebrew ("reboot_to_payload") was also written and is now included with Atmosphère. + General system stability improvements to enhance the user's experience. ## 0.8.2 + A number of bugs were fixed causing users to sometimes see `Key Derivation Failed!`. + KFUSE clock enable timings have been adjusted to allow time to stabilize before TSEC is granted access. + A race condition was fixed that could cause wrong key data to be used on 6.2.0 + The TSEC firmware is now retried on failure, fixing a failure affecting ~1/50 boots on 6.2.0. + A bug was fixed causing some modules to not work on firmware 1.0.0. + A bug was fixed causing sleep mode to not work with debugmode enabled. + As a result, debugmode is now enabled in the default BCT.ini. + General system stability improvements to enhance the user's experience. ## 0.8.1 + A bug was fixed causing users to see `Failed to enable SMMU!` if fusee had previously rebooted. + This message will still occur sporadically if fusee is not launched from coldboot, but it can never happen twice in a row. + A race condition was fixed in Atmosphere `bis_protect` functionality that could cause NS to be able to overwrite BCT public keys. + This sometimes broke AutoRCM protection, the current fix has been tested on hardware and verified to work. + Support was added for enabling `debugmode` based on the `exosphere` section of `BCT.ini`: + Setting `debugmode = 1` will cause exosphere to tell the kernel that debugmode is active. + Setting `debugmode_user = 1` will cause exosphere to tell userland that debugmode is active. + These are completely independent of one another, allowing fine control of system behavior. + Support was added for `nogc` functionality; thanks to @rajkosto for the patches. + By default, `nogc` patches will automatically apply if the user is booting into 4.0.0+ with fuses from <= 3.0.2. + Users can override this functionality via the `nogc` entry in the `stratosphere` section of `BCT.ini`: + Setting `nogc = 1` will force enable `nogc` patches. + Setting `nogc = 0` will force disable `nogc` patches. + If patches are enabled but not found for the booting system, a fatal error will be thrown. + This should prevent running FS without `nogc` patches after updating to an unsupported system version. + An extension was added to `exosphere` allowing userland applications to cause the system to reboot into RCM: + This is done by calling smcSetConfig(id=65001, value=<nonzero>); user homebrew can use splSetConfig for this. + On fatal error, the user can now choose to perform a standard reboot via the power button, or a reboot into RCM via either volume button. + A custom message was added to `fatal` for when an Atmosphère API version mismatch is detected (2495-1623). + General system stability improvements to enhance the user's experience. ## 0.8.0 + A custom `fatal` system module was added. + This re-implements and extends Nintendo's fatal module, with the following features: + Atmosphère's `fatal` does not create error reports. + Atmosphère's `fatal` draws a custom error screen, showing registers and a backtrace. + Atmosphère's `fatal` attempts to gather debugging info for all crashes, and not just ones that include info. + Atmosphère's `fatal` will attempt saving reports to the SD, if a crash report was not generated by `creport`. + Title flag handling was changed to prevent folder clutter. + Instead of living in `atmosphere/titles/<tid>/%s.flag`, flags are now located in `atmosphere/titles/<tid>/flags/%s.flag` + The old format will continue to be supported for some time, but is deprecated. + Flags can now be applied to HBL by placing them at `atmosphere/flags/hbl_%s.flag`. + Changes were made to the mitm API, greatly improving caller semantics. + `sm` now informs mitm services of a new session's process id, enabling custom handling based on title id/process id. + smhax is no longer enabled, because it is no longer needed and breaks significant functionality. + Users with updated HBL/homebrew should see no observable differences due to this change. + Functionality was added implementing basic protections for NAND from userland homebrew: + BOOT0 now has write protection for the BCT public key and keyblob regions. + The `ns` sysmodule is no longer allowed to write the BCT public keys; all other processes can. + This should prevent system updates from removing AutoRCM. + No processes should be allowed to write to the keyblob region. + By default, BIS partitions other than BOOT0 are now read-only, and CAL0 is neither readable nor writable. + Adding a `bis_write` flag for a title will allow it to write to BIS. + Adding a `cal_read` flag for a title will allow it to read CAL0. + An automatic backup is now made of CAL0 on boot. + `fs.mitm` maintains a file handle to this backup, so userland software cannot read it. + To facilitate this, `fs.mitm` now mitms all sessions for non-system modules; content overriding has been made separate from service interception. + Please note: these protections are basic, and sufficiently malicious homebrew ++can defeat them++. + Please be careful to only run homebrew software from sources that you trust. + A bug involving HDCP titles crashing on newer firmwares was fixed. + Support was added for system version 6.2.0; our thanks to @motezazer for his invaluable help. + By default, new keys will automatically be derived without user input. + Support is also present for loading new keys from `atmosphere/prod.keys` or `atmosphere/dev.keys` + General system stability improvements to enhance the user's experience. ## 0.7.5 + DRAM training was added to fusee-secondary, courtesy @hexkyz. + This greatly improves the speed of memory accesses during boot, resulting in a boot time that is ~200-400% faster. + creport has had its code region detection improved. + Instead of only checking one of the crashing thread's PC/LR for code region presence, creport now checks both + every address in the stacktrace. This is also now done for every thread. + This matches the improvement Nintendo added to official creport in 6.1.0. + The code region detection heuristic was further improved by checking whether an address points to .rodata or .rwdata, instead of just .text. + This means that a crash appears in a loaded NRO (or otherwise discontiguous) code region, creport will be able to detect all active code regions, and not just that one. ## 0.7.4 + [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere) has been completely refactored/rewritten, and split into its own, separate submodule. + While this is mostly "under the hood" for end-users, the refactor is faster (improving both boot-time and runtime performance), more accurate (many of the internal IPC structures are now bug-for-bug compatible with Nintendo's implementations), and significantly more stable (it fixes a large number of bugs present in the old library). + The refactored API is significantly cleaner and easier to write system module code for, which should improve/speed up development of stratosphere. + Developers looking to write their own custom system modules for the Switch can now easily include libstratosphere as a submodule in their projects. + Loader was extended to add a new generic way to redirect content (ExternalContentSources), courtesy @misson20000: + A new command was added to ldr:shel, taking in a tid to redirect and returning a session handle. + When the requested TID is loading, Loader will query the handle as though it were an IFileSystem. + This allows clients to generically define their own filesystems, and override content with them in loader. + fs.mitm has gotten several optimizations that should improve its performance and stability: + RomFS redirection now only occurs when there is content to redirect, even if the title is being mitm'd elsewhere. + A cache is now maintained of the active data storage, if any, for all opened title IDs. This means if two processes both try to open the same archive, fs.mitm won't duplicate any of its work. + RomFS metadata is now cached to the SD card on build instead of being persisted in memory -- this greatly reduces memory footprint and allows fs.mitm to redirect more titles simultaneously than before. + A number of bugs were fixed, including: + A resource leak was fixed in process creation. This fixes crashes that occur when a large number (>32) games have been launched since the last reboot. + fs.mitm no longer errors when receiving a zero-sized buffer. This fixes crashes in some games, including The Messenger. + Multi-threaded server semantics should no longer cause deadlocks in certain circumstances. This fixes crashes in some games, including NES Classics. + PM now only gives full FS permissions to the active KIPs. This fixes a potential crash where new processes might be unable to be registered with FS. + The `make dist` target now includes the branch in the generated zip name. + General system stability improvements to enhance the user's experience. ## 0.7.3 + Loader and fs.mitm now try to reload loader.ini before reading it. This allows for changing the override button combination/HBL title id at runtime. + Added a MitM between set:sys and qlaunch, used to override the system version string displayed in system settings. + The displayed system version will now display `<Actual version> (AMS <x>.<y>.<z>)`. + General system stability improvements to enhance the user's experience. ## 0.7.2 + Fixed a bug in fs.mitm's LayeredFS read implementation that caused some games to crash when trying to read files. + Fixed a bug affecting 1.0.0 that caused games to crash with fatal error 2001-0106 on boot. + Improved filenames output by the make dist target. + General system stability improvements to enhance the user's experience. ## 0.7.1 + Fixed a bug preventing consoles on 4.0.0-4.1.0 from going to sleep and waking back up. + Fixed a bug preventing consoles on < 4.0.0 from booting without specific KIPs on the SD card. + An API was added to Atmosphère's Service Manager for deferring acquisition of all handles for specific services until after early initialization is completed. + General system stability improvements to enhance the user's experience. ## 0.7.0 + First official release of Atmosphère. + Supports the following featureset: + Fusée, a custom bootloader. + Supports loading/customizing of arbitrary KIPs from the SD card. + Supports loading a custom kernel from the SD card ("/atmosphere/kernel.bin"). + Supports compile-time defined kernel patches on a per-firmware basis. + All patches at paths like /atmosphere/kip_patches/<user-defined patch name>/<SHA256 of KIP>.ips will be applied to the relevant KIPs, allowing for easy distribution of patches supporting multiple versions. + Both the IPS and IPS32 formats are supported. + All patches at paths like /atmosphere/kernel_patches/<user-defined patch name>/<SHA256 of Kernel>.ips will be applied to the kernel, allowing for easy distribution of patches supporting multiple versions. + Both the IPS and IPS32 formats are supported. + Configurable by editing BCT.ini on the SD card. + Atmosphère should also be launchable by the alternative hekate bootloader, for those who prefer it. + Exosphère, a fully-featured custom secure monitor. + Exosphere is a re-implementation of Nintendo's TrustZone firmware, fully replicating all of its features. + In addition, it has been extended to provide information on current Atmosphere API version, for homebrew wishing to make use of it. + Stratosphère, a set of custom system modules. This includes: + A loader system module. + Reimplementation of Nintendo's loader, fully replicating all original functionality. + Configurable by editing /atmosphere/loader.ini + First class support for the Homebrew Loader. + An exefs NSP (default "/atmosphere/hbl.nsp") will be used in place of the victim title's exefs. + By default, HBL will replace the album applet, but any application should also be supported. + Extended to support arbitrary redirection of executable content to the SD card. + Files will be preferentially loaded from /atmosphere/titles/<titleid>/exefs/, if present. + Files present in the original exefs a user wants to mark as not present may be "stubbed" by creating a .stub file on the SD. + If present, a PFS0 at /atmosphere/titles/<titleid>/exefs.nsp will fully replace the original exefs. + Redirection is optionally toggleable by holding down certain buttons (by default, holding R disables redirection). + Full support for patching NSO content is implemented. + All patches at paths like /atmosphere/exefs_patches/<user-defined patch name>/<Hex Build-ID for NSO to patch>.ips will be applied, allowing for easy distribution of patches supporting multiple firmware versions and/or titles. + Both the IPS and IPS32 formats are supported. + Extended to support launching content from loose executable files on the SD card, without requiring any official installation. + This is done by specifying FsStorageId_None on launch. + A service manager system module. + Reimplementation of Nintendo's service manager, fully replicating all original functionality. + Compile-time support for reintroduction of "smhax", allowing clients to optionally skip service access verification by skipping initialization. + Extended to allow homebrew to acquire more handles to privileged services than Nintendo natively allows. + Extended to add a new API for installing Man-In-The-Middle listeners for arbitrary services. + API can additionally be used to safely detect whether a service has been registered in a non-blocking way with no side-effects. + Full API documentation to come. + A process manager system module. + Reimplementation of Nintendo's process manager, fully replicating all original functionality. + Extended to allow homebrew to acquire handles to arbitrary processes, and thus read/modify system memory without blocking execution. + Extended to allow homebrew to retrieve information about system resource limits. + Extended by embedding a full, extended implementation of Nintendo's boot2 system module. + Title launch order has been optimized in order to grant access to the SD card faster. + The error-collection system module is intentionally not launched, preventing many system telemetry error reports from being generated at all. + Users may place their own custom sysmodules on the SD card and flag them for automatic boot2 launch by creating a /atmosphere/titles/<title ID>/boot2.flag file on their SD card. + A custom fs.mitm system module. + Uses Atmosphère's MitM API in order to provide an easy means for users to modify game content. + Intercepts all FS commands sent by games, with special handling for commands used to mount RomFS/DLC content to enable easy creation and distribution of game/DLC mods. + fs.mitm will parse the base RomFS image for a game, a RomFS image located at /atmosphere/titles/<title ID>/romfs.bin, and all loose files in /atmosphere/titles/<title ID>/romfs/, and merge them together into a single RomFS image. + When merging, loose files are preferred to content in the SD card romfs.bin image, and files from the SD card image are preferred to those in the base image. + Can additionally be used to intercept commands sent by arbitrary system titles (excepting those launched before SD card is active), by creating a /atmosphere/titles/<title ID>/fsmitm.flag file on the SD card. + Can be forcibly disabled for any title, by creating a /atmosphere/titles/<title ID>/fsmitm_disable.flag file on the SD card. + Redirection is optionally toggleable by holding down certain buttons (by default, holding R disables redirection). + A custom crash report system module. + Serves as a drop-in replacement for Nintendo's own creport system module. + Generates detailed, human-readable reports on system crashes, saving to /atmosphere/crash_reports/<timestamp>_<title ID>.log. + Because reports are not sent to the erpt sysmodule, this disables all crash report related telemetry. + General system stability improvements to enhance the user's experience. ================================================ FILE: docs/components/detail/exosphere_memory_layout.txt ================================================ exosphere, storage requirements: Nonvolatile memory: 0xE000 Volatile memory: 0x2000 Physical Address Space: -0x7C010000-0x7C012000 - boot code/volatile memory -0x7C012000-0x7C01E000 - program region -0x7C01E000-0x7C01F000 - global data/context -0x7C01F000-0x7C020000 - L2/L3 page table -0x7C020000-0x7C040000 - Mariko-only program region -0x7C040000-0x7C048000 - Mariko-only program stack -0x7C048000-0x7C050000 - Reserved Mariko TZRAM (SE context carveouts, etc) Virtual Address Space: L1: 0x40 bytes. L1 Entries: -0 (0x000000000-0x040000000): Empty -1 (0x040000000-0x080000000): Identity Mapping/Empty -2 (0x080000000-0x0C0000000): DRAM Mapping/Empty -3 (0x0C0000000-0x100000000): DRAM Mapping/Empty -4 (0x100000000-0x140000000): Empty -5 (0x140000000-0x180000000): Empty -6 (0x180000000-0x1C0000000): Empty -7 (0x1C0000000-0x200000000): Virtual Region L2 Page and L3 page are both0x7C01F000 L2 Entries: -0x040000000 (Identity IRAM Table) - Entry Used: 0x000 -0x07C000000 (Identity TZRAM Table) - Entry Used: 0x1E0 -0x1F0000000 (Virtual Region Table) - Entry Used: 0x180 L3 Entries: - Identity TZRAM mapping (0x7C010000-0x7C020000) - Entry Used: 0x010-0x01F - Identity IRAM mapping (0x40020000-0x40040000) - Entry Used: 0x020-0x03F - Virtual Device region (0x1F0040000-0x1F0080000) - Entry Used: 0x040-0x07F - Read Only TZRAM Alias (0x1F00A0000-0x1F00B0000) - Entry Used: 0x0A0-0x0AF - Program region (0x1F00C0000-0x1F00CC000) - Entry Used: 0x0C0-0x0CB - Mariko Program region (0x1F00D0000-0x1F00F0000) - Entry Used: 0x0D0-0x0EF - Mariko Program stack (0x1F00F4000-0x1F00FC000) - Entry Used: 0x0F4-0x0FB - Secure DRAM Storage (0x1F0100000-0x1F0110000) - Entry Used: 0x100-0x10F - Debug DRAM Storage (0x1F0110000-0x1F0114000) - Entry Used: 0x110-0x113 - SC7 IRAM Work Space (0x1F0120000-0x1F0130000) - Entry Used: 0x120-0x12F - SC7 IRAM Firmware (0x1F0140000-0x1F0141000) - Entry Used: 0x140-0x140 - Debug Code (0x1F0150000-0x1F0154000) - Entry Used: 0x150-0x153 - Reserved For Debug (0x1F0160000-0x1F0170000) - Entry Used: 0x160-0x16F - Boot Code (0x1F01C0000-0x1F01C2000) - Entry Used: 0x1C0-0x1C1 - AMS IRAM Page (0x1F01F2000-0x1F01F2000) - Entry Used: 0x1F2-0x1F2 - AMS User Page (0x1F01F4000-0x1F01F4000) - Entry Used: 0x1F4-0x1F4 - SMC User Page (0x1F01F6000-0x1F01F6000) - Entry Used: 0x1F6-0x1F6 - Volatile (Data) (0x1F01F8000-0x1F01F9000) - Entry Used: 0x1F8-0x1F8 - Volatile (Stacks) (0x1F01FA000-0x1F01FB000) - Entry Used: 0x1FA-0x1FA - Global Data (0x1F01FC000-0x1F01FD000) NV Global Data needs: Exosphere + Emummc Config (<=0x200) Boot Config[0x400] RSA Context(0x100) Old Device Keys[0x20][0x10]; Old Master Keys[0x20][0x10]; Imported Rsa Keys[4][0x200]; CPU Ctx[4][0x100]; Total: 0x1700 Global Data Page (accessible via X18): 0x000-0x200: Exosphere Config 0x200-0x400: Emummc Config 0x400-0x800: Sealed AES Keys 0x800-0xC00: Boot Config 0xC00-0xFFF: CPU contexts. Can be replaced, but this fits exactly so minimizes program space waste. Volatile Global Data needs: Random Cache 0x400 bytes ================================================ FILE: docs/components/emummc.md ================================================ # emummc emummc is a collaborative project that provides eMMC storage emulation. Please refer to the project's repository [here](https://github.com/m4xw/emuMMC) for detailed instructions and documentation. ================================================ FILE: docs/components/exosphere.md ================================================ # exosphère exosphère is a customized reimplementation of the Horizon OS's Secure Monitor. The Secure Monitor follows the same design principle as Arm's TrustZone and both terms can be used interchangeably in this context. It runs at the highest privilege mode (EL3) available to the main processor and is responsible for all the sensitive cryptographic operations needed by the system as well as power management for each CPU. ## Extensions exosphère expands the original Secure Monitor design by providing custom SMCs (Secure Monitor Calls) necessary to the homebrew ecosystem. Currently, these are: ``` uint32_t smc_ams_iram_copy(smc_args_t *args); uint32_t smc_ams_write_address(smc_args_t *args); uint32_t smc_ams_get_emummc_config(smc_args_t *args); ``` Additionally, exosphère expands the functionality of two SMCs provided by the Horizon OS for getting/setting configuration items. The following custom configuration items are provided by exosphère: ``` CONFIGITEM_EXOSPHERE_VERSION = 65000, CONFIGITEM_NEEDS_REBOOT = 65001, CONFIGITEM_NEEDS_SHUTDOWN = 65002, CONFIGITEM_EXOSPHERE_VERHASH = 65003, CONFIGITEM_HAS_RCM_BUG_PATCH = 65004, CONFIGITEM_SHOULD_BLANK_PRODINFO = 65005, CONFIGITEM_ALLOW_CAL_WRITES = 65006, ``` ### smc_ams_iram_copy This function implements a copy of up to one page between DRAM and IRAM. Its arguments are: ``` args->X[1] = DRAM address (translated by kernel), must be 4-byte aligned. args->X[2] = IRAM address, must be 4-byte aligned. args->X[3] = Size (must be <= 0x1000 and 4-byte aligned). args->X[4] = 0 for read, 1 for write. ``` ### smc_ams_write_address This function implements a write to a DRAM page. Its arguments are: ``` args->X[1] = Virtual address, must be size-bytes aligned and readable by EL0. args->X[2] = Value. args->X[3] = Size (must be 1, 2, 4, or 8). ``` ### smc_ams_get_emummc_config This function retrieves configuration for the current [emummc](emummc.md) context. Its arguments are: ``` args->X[1] = MMC id, must be size-bytes aligned and readable by EL0. args->X[2] = Pointer to output (for paths for filebased + nintendo dir), must be at least 0x100 bytes. ``` ### CONFIGITEM_EXOSPHERE_VERSION This custom configuration item gets information about the current exosphere version. ### CONFIGITEM_NEEDS_REBOOT This custom configuration item is used to issue a system reboot into RCM or into a warmboot payload leveraging a secondary vulnerability to achieve code execution from warm booting. ### CONFIGITEM_NEEDS_SHUTDOWN This custom configuration item is used to issue a system shutdown with a warmboot payload leveraging a secondary vulnerability to achieve code execution from warm booting. ### CONFIGITEM_EXOSPHERE_VERHASH This custom configuration item gets information about the current exosphere git commit hash. ### CONFIGITEM_HAS_RCM_BUG_PATCH This custom configuration item gets whether the unit has the CVE-2018-6242 vulnerability patched. ### CONFIGITEM_SHOULD_BLANK_PRODINFO This custom configuration item gets whether the unit should simulate a "blanked" PRODINFO. See [here](../features/configurations.md) for more information. ### CONFIGITEM_ALLOW_CAL_WRITES This custom configuration item gets whether the unit should allow writing to the calibration partition. ## lp0fw This is a small, built-in payload that is responsible for waking up the system during a warm boot. ## sc7fw This is a small, built-in payload that is responsible for putting the system to sleep during a warm boot. ## rebootstub This is a small, built-in payload that provides functionality to reboot the system into any payload of choice. ================================================ FILE: docs/components/fusee.md ================================================ # fusée fusée is a custom bootloader used to start the Atmosphère environment. ## fusée fusée is the first piece of Atmosphère's code that runs on the hardware. It is distributed as a standalone payload designed to be launched via RCM by abusing the CVE-2018-6242 vulnerability. This payload is responsible for all the low-level hardware initialization required by the Nintendo Switch, setting up the cryptosystem, mounting/emulating the eMMC, injecting/patching system modules, and launching the exosphère component. ================================================ FILE: docs/components/libraries.md ================================================ # libraries This is a collection of libraries for doing operating system development for the Nintendo Switch. ## libmesosphere libmesosphere is a work-in-progress C++ library implementing functionality for the Horizon Kernel. ## libstratosphere libstratosphere is a work-in-progress C++ library for development of system modules for the Nintendo Switch. ## libvapours Common boilerplate code for various purposes. ================================================ FILE: docs/components/mesosphere.md ================================================ # mesosphère mesosphère is a work in progress customized kernel reimplementation. The Horizon OS's kernel follows microkernel design principles and runs at the EL1 level. It is currently subdivided into a loader (kernel_ldr) and the main kernel code. ================================================ FILE: docs/components/modules/ams_mitm.md ================================================ # ams_mitm This module provides methods to intercept services provided by other system modules. It is further sub-divided according to the service it targets. ## bpc_mitm bpc_mitm enables intercepting requests to power control services. It currently intercepts: + `am` system module (to intercept the Reboot/Power buttons in the overlay menu) + `fatal` system module (to simplify payload reboot logic significantly) + [nx-hbloader](https://github.com/switchbrew/nx-hbloader) (to allow homebrew to take advantage of the feature) ## fs_mitm fs_mitm enables intercepting file system operations. It can deny, delay, replace, or redirect any request made to the file system. It enables LayeredFS to function, which allows for replacement of game assets. ## hid_mitm hid_mitm enables intercepting requests to controller device services. It is currently disabled by default. If enabled, it intercepts: + [nx-hbloader](https://github.com/switchbrew/nx-hbloader) (to help homebrew not need to be recompiled due to a breaking change introduced in the past) Note that hid_mitm is currently deprecated and might be removed entirely in the future. ## ns_mitm ns_mitm enables intercepting requests to application control services. It currently intercepts: + Web Applets (to facilitate nx-hbloader web browser launching) ## set_mitm set_mitm enables intercepting requests to the system settings service. It currently intercepts: + `ns` system module and games (to allow for overriding game locales) + All firmware debug settings requests (to allow modification of system settings not directly exposed to the user) ### Firmware Version set_mitm intercepts the `GetFirmwareVersion` command, if the requester is `qlaunch` or `maintenance`. It modifies the `display_version` field of the returned system version, causing the version to display in settings as `#.#.#|AMS #.#.#|?` with `? = S` when running under system eMMC or `? = E` when running under emulated eMMC. This allows users to easily verify what version of Atmosphère and what eMMC environment they are running. ### System Settings set_mitm intercepts the `GetSettingsItemValueSize` and `GetSettingsItemValue` commands for all requesters. It does so in order to enable user configuration of system settings, which are parsed from `/atmosphere/system_settings.ini` on boot. See [here](../../features/configurations.md) for more information on the system settings format. ## dns_mitm dns_mitm enables intercepting requests to dns resolution services, to enable redirecting requests for specified hostnames. For documentation, see [here](../../features/dns_mitm.md). ================================================ FILE: docs/components/modules/boot.md ================================================ # boot This module is a reimplementation of the Horizon OS's `boot` system module, which is responsible for initializing and configuring hardware. Atmosphère's reimplementation displays its own black and white splash screen and battery icons as replacements for the original assets used during display initialization. ================================================ FILE: docs/components/modules/boot2.md ================================================ # boot2 This module is a reimplementation of the Horizon OS's `boot2` system module, which is responsible for launching all the other necessary system modules. Atmosphère's reimplementation allows launching user provided system modules from the SD card. See [here](../../features/configurations.md) for more information. ================================================ FILE: docs/components/modules/creport.md ================================================ # creport This module is a reimplementation of the Horizon OS's `creport` system module, which is responsible for managing crash reports. Atmosphère's reimplementation redirects writing of generated crash reports to the SD card under the folder `/atmosphere/crash_reports/`. It also prevents the automatic uploading of said crash reports. ================================================ FILE: docs/components/modules/dmnt.md ================================================ # dmnt This module is a reimplementation of the Horizon OS's `dmnt` system module, which provides a debug monitor. ## Extensions Atmosphère implements an extension to provide cheat code functionality. ### Cheat Service A HIPC service API is provided for interacting with the cheat code manager through the service `dmnt:cht`. See [here](../../features/cheats.md) for more information on the cheat code format. The SwIPC definition for `dmnt:cht` follows: ``` interface ams::dmnt::cheat::CheatService is dmnt:cht { [65000] HasCheatProcess() -> sf::Out<bool> out; [65001] GetCheatProcessEvent() -> sf::OutCopyHandle out_event; [65002] GetCheatProcessMetadata() -> sf::Out<CheatProcessMetadata> out_metadata; [65003] ForceOpenCheatProcess(); [65004] PauseCheatProcess(); [65005] ResumeCheatProcess(); [65100] GetCheatProcessMappingCount() -> sf::Out<u64> out_count; [65101] GetCheatProcessMappings(u64 offset) -> sf::OutArray<MemoryInfo> &mappings, sf::Out<u64> out_count; [65102] ReadCheatProcessMemory(u64 address, u64 out_size) -> sf::OutBuffer &buffer; [65103] WriteCheatProcessMemory(sf::InBuffer &buffer, u64 address, u64 in_size); [65104] QueryCheatProcessMemory(u64 address) -> sf::Out<MemoryInfo> mapping; [65200] GetCheatCount() -> sf::Out<u64> out_count; [65201] GetCheats(u64 offset) -> sf::OutArray<CheatEntry> &cheats, sf::Out<u64> out_count; [65202] GetCheatById(u32 cheat_id) -> sf::Out<CheatEntry> cheat; [65203] ToggleCheat(u32 cheat_id); [65204] AddCheat(CheatDefinition &cheat, bool enabled) -> sf::Out<u32> out_cheat_id; [65205] RemoveCheat(u32 cheat_id); [65206] ReadStaticRegister(u8 which) -> sf::Out<u64> out; [65207] WriteStaticRegister(u8 which, u64 value); [65208] ResetStaticRegisters(); [65300] GetFrozenAddressCount() -> sf::Out<u64> out_count; [65301] GetFrozenAddresses(u64 offset) ->sf::OutArray<FrozenAddressEntry> &addresses, sf::Out<u64> out_count; [65302] GetFrozenAddress(u64 address) -> sf::Out<FrozenAddressEntry> entry; [65303] EnableFrozenAddress(u64 address, u64 width) -> sf::Out<u64> out_value; [65304] DisableFrozenAddress(u64 address); } ``` ================================================ FILE: docs/components/modules/eclct.stub.md ================================================ # eclct.stub This module is a reimplementation of the Horizon OS's `eclct` system module, which collects error reports. Atmosphère's reimplementation is a stub to remove any and all functionality pertaining to error report collection. ================================================ FILE: docs/components/modules/erpt.md ================================================ # erpt This module is a reimplementation of the Horizon OS's `erpt` system module, which is responsible for managing error reports. Atmosphère's reimplementation redirects writing of generated error reports to the SD card under the folder `/atmosphere/erpt_reports/`. ================================================ FILE: docs/components/modules/fatal.md ================================================ # fatal This module is a reimplementation of the Horizon OS's `fatal` system module, which is responsible for managing fatal reports. Atmosphère's reimplementation prevents error report creation and draws a custom error screen, showing registers and a backtrace. It also attempts to gather debugging info for any and all crashes and tries to save reports to the SD card under the folder `/atmosphere/fatal_reports/`. ================================================ FILE: docs/components/modules/jpegdec.md ================================================ # jpegdec This module is a reimplementation of the Horizon OS's `jpegdec` system module, which is responsible for JPEG format decoding. Atmosphère's reimplementation allows two sessions instead of 1, so homebrew can use it for software JPEG decoding in addition to the OS itself. ================================================ FILE: docs/components/modules/loader.md ================================================ # loader This module is a reimplementation of the Horizon OS's `ldr` system module, which is responsible for creating processes from executable NSO images and registering their access control. ## Extensions Atmosphère extends this module to allow executables to be replaced or patched by files stored on the SD card. Note that a few services are required for SD card access and therefore cannot be replaced or patched in this manner. ### Exefs Replacement Atmosphère's reimplementation allows replacing executable files in the file system. #### Partition Replacement It is possible to replace the full exefs partition at once with a PFS0 file. In that case, Atmosphère will load the following file: ``` /atmosphere/contents/<program id>/exefs.nsp ``` #### File Replacement When a process is created, loader will search for several NSO filenames in the program's exefs directory. These filenames are, in this order: - rtld - main - subsdk0 - subsdk1 - ... - subsdk9 - sdk Each NSO that is found will be loaded into the process contiguously. The process's entrypoint is at the first NSO to be loaded, usually `rtld` or `main`. Additionally, when a process is loaded, loader will search for a `main.npdm` file in the exefs directory specifying the program's permissions. Atmosphère extends this functionality by also searching for these files on the SD card. When searching for a file, loader will first check if it exists on the SD card. If it does, that file will be used instead. Otherwise, it will use the copy located in the exefs, if that is present. The following directory will be searched: ``` /atmosphere/contents/<program id>/exefs/ ``` This allows the replacement of applets, system modules, or even games with homebrew versions. ##### File Stubbing In order to prevent an NSO from being loaded even if it exists in the exefs, loader will also check if a stub file exists. If such a file exists, the NSO will not be loaded. The files should be named like `rtld.stub`, `main.stub`, etc. and may be empty. ##### Technical Semantics loader's semantics for content override can (as you may observe from reading the above) be complicated to understand. The following is an abbreviated description of the very technical semantics by which loader decides what content to read when trying to read a file for a program id. * If an external content filesystem exists for the program id, the external content filesystem is used directly with no further redirection. * Otherwise, if the program ID is being overridden with [nx-hbloader](https://github.com/switchbrew/nx-hbloader/releases) (see Homebrew Support below), the nsp filesystem for hbl is used directly with no further redirection. * Otherwise, if content redirection is enabled for the program ID (controlled by a configurable button combination) and a loose file exists on the SD card, the loose file is used. * Otherwise, if a stub file exists, a "Not Found" error is returned. * Otherwise, if an SD card executable filesystem ("exefs.nsp") exists, it is used without further redirection. * Finally, the "real"/base code file system is used without further redirection. In addition, there are a few other technical details relevant to Atmosphere's redirection: * When overriding with nx-hbloader, the real code filesystem must exist. When "main.npdm" (a program capabilities descriptor file) is read, the content from the real code filesystem is read in order to determine whether an applet or an application is being overridden. This allows nx-hbloader to automatically support both applet and application environments. * When overriding applications, the real code filesystem must exist and contain valid content. This is required to perform accurate-to-Nintendo content verification procedures. * When programs are launched, both a program id and a "storage id" are specified by the launch requester. When the storage id specified is "none" (normally always invalid), Atmosphere assumes that a custom system module is attempting to be launched. This removes the aforementioned requirement on base content validity; the above procedure is still used to determine how to redirect content, however reads to the "real"/base code file system may return "Not Found" errors if the real/base code file system does not exist. ### NSO Patching When an NSO is loaded, Atmosphère's reimplementation will search for IPS patch files on the SD card in the following locations. ``` /atmosphere/exefs_patches/<patchset name>/<nso build id>.ips ``` This organization allows patch sets affecting multiple NSOs to be distributed as a single directory and also allows patches from multiple patch sets to be stacked. Patches will be searched for in each patch set directory. The name of each patch file should match the hexadecimal build ID of the NSO to affect, except that trailing zero bytes may be left off. Because the NSO build ID is unique for every NSO, this means patches will only apply to the files they are meant to apply to. Patch files are accepted in either IPS format or IPS32 format. Because NSO files are compressed, patch files are not made between the original version of a compressed NSO and the modified version of such an NSO. Instead, they are made between the uncompressed version of an NSO and the modified (and still uncompressed) version of that NSO. This also means that a patch file cannot be manually applied to the compressed version of an NSO; it must be applied to the uncompressed version. Atmosphère's reimplementation will correctly apply these patches while loading the process regardless of whether the NSO it finds is compressed or not. When authoring patches, [hactool](https://github.com/SciresM/hactool) can be used to find an NSO's build ID and to uncompress NSOs. Recent versions of the [ReSwitched IDA loaders](https://github.com/reswitched/loaders) can be used to load uncompressed NSOs into IDA in such a way that you can [apply patches to the input file](https://www.hex-rays.com/products/ida/support/idadoc/1618.shtml). From there, any IPS tool can be used to create the patch between the original NSO and the patched NSO. Note that if the NSO you are patching is larger than 16 MiB, you will have to use a tool that supports IPS32. ### Homebrew Support Atmosphère provides first class support for [nx-hbloader](https://github.com/switchbrew/nx-hbloader/releases) and [nx-hbmenu](https://github.com/switchbrew/nx-hbmenu/releases). Launching of the nx-hbloader process is controlled by configurable button inputs. See [here](../../features/configurations.md) for more detailed information. In addition, loader has extensions to enable homebrew to launch web applets. This normally requires the application launching the applet to have HTML Manual content inside an installed NCA. Atmosphère's reimplementation will automatically ensure that the commands used to check this succeed, and will redirect the relevant file system to the `/atmosphere/hbl_html/` subdirectory. ### IPC Commands Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands. The SwIPC definition for the `ldr:pm` extension commands follows: ``` interface ams::ldr::pm::ProcessManagerInterface is ldr:pm { ... [65000] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out; [65001] AtmosphereGetProgramInfo(ncm::ProgramLocation &loc) -> sf::Out<ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status; [65002] AtmospherePinProgram(ncm::ProgramLocation &loc, cfg::OverrideStatus &override_status) -> sf::Out<PinId> out_id; } ``` The SwIPC definition for the `ldr:dmnt` extension commands follows: ``` interface ams::ldr::dmnt::DebugMonitorInterface is ldr:dmnt { ... [65000] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out; } ``` The SwIPC definition for the `ldr:shel` extension commands follows: ``` interface ams::ldr::shell::ShellInterface is ldr:shel { ... [65000] AtmosphereRegisterExternalCode(ncm::ProgramId program_id) -> sf::OutMoveHandle out; [65001] AtmosphereUnregisterExternalCode(ncm::ProgramId program_id); } ``` ================================================ FILE: docs/components/modules/ncm.md ================================================ # ncm This module is a reimplementation of the Horizon OS's `ncm` system module, which is responsible for content management. Atmosphère's reimplementation is currently opt-in only. See [here](../../features/configurations.md) for more information. ================================================ FILE: docs/components/modules/pgl.md ================================================ # pgl This module is a reimplementation of the Horizon OS's `pgl` system module, which is responsible for launching programs and was introduced by firmware version `10.0.0`. Currently, Atmosphère's reimplementation doesn't backport this module's functionalities to firmware versions lower than `10.0.0`. ================================================ FILE: docs/components/modules/pm.md ================================================ # pm This module is a reimplementation of the Horizon OS's `pm` system module, which is responsible for tracking running processes on the system, and managing resource limits. ## Extensions Atmosphère extends this module with extra IPC commands and memory restriction changes. ### IPC Commands Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands. The SwIPC definition for the `pm:dmnt` extension commands follows: ``` interface ams::pm::dmnt::DebugMonitorServiceBase is pm:dmnt { ... [65000] AtmosphereGetProcessInfo(os::ProcessId process_id) -> sf::OutCopyHandle out_process_handle, sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status; [65001] AtmosphereGetCurrentLimitInfo(u32 group, u32 resource) -> sf::Out<s64> out_cur_val, sf::Out<s64> out_lim_val; } ``` The SwIPC definition for the `pm:info` extension commands follows: ``` interface ams::pm::info::InformationService is pm:info { ... [65000] AtmosphereGetProcessId(ncm::ProgramId program_id) -> sf::Out<os::ProcessId> out; [65001] AtmosphereHasLaunchedProgram(ncm::ProgramId program_id) -> sf::Out<bool> out; [65002] AtmosphereGetProcessInfo(os::ProcessId process_id) -> sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status; } ``` ### Extra System Memory Atmosphère's reimplementation shrinks the APPLET memory pool by 24 MiB by default, giving this memory to the SYSTEM pool. This allows custom system modules to use more memory without hitting the SYSTEM memory limit. ================================================ FILE: docs/components/modules/ro.md ================================================ # ro This module is a reimplementation of the Horizon OS's `ro` system module, which is responsible for loading dynamic libraries and was introduced by firmware version `3.0.0`. Atmosphère's reimplementation backports this module's functionalities to firmware versions lower than `3.0.0` where said functionalities were provided by the `ldr` system module instead. ## Extensions Atmosphère extends this module to allow libraries to be patched by files stored on the SD card. ### NRO Patching When an NRO is loaded, Atmosphère's reimplementation will search for IPS patch files on the SD card in the following locations. ``` /atmosphere/nro_patches/<patchset name>/<nro build id>.ips ``` This organization allows patch sets affecting multiple NROs to be distributed as a single directory. Patches will be searched for in each patch set directory. The name of each patch file should match the hexadecimal build ID of the NRO to affect, except that trailing zero bytes may be left off. Because the NRO build ID is unique for every NRO, this means patches will only apply to the files they are meant to apply to. Patch files are accepted in either IPS format or IPS32 format. ================================================ FILE: docs/components/modules/sm.md ================================================ # sm This module is a reimplementation of the Horizon OS's `sm` system module, which is responsible for service management. ## Extensions Atmosphère extends this module with extra IPC commands and new services. ### Debug Monitor Atmosphère's reimplementation provides an interface `sm:dmnt` to allow a debug monitor to query the service manager's state. The SwIPC definition for `sm:dmnt` follows: ``` interface ams::sm::DmntService is sm:dmnt { [65000] AtmosphereGetRecord(ServiceName service) -> sf::Out<ServiceRecord> record; [65001] AtmosphereListRecords(u64 offset) -> sf::OutArray<ServiceRecord> &records, sf::Out<u64> out_count; [65002] AtmosphereGetRecordSize() -> sf::Out<u64> record_size; } ``` ### IPC Commands Atmosphère's reimplementation extends the HIPC loader services' API with several custom commands. The SwIPC definition for the `sm:` extension commands follows: ``` interface ams::sm::UserService is sm: { ... [65000] AtmosphereInstallMitm(ServiceName service) -> sf::OutMoveHandle srv_h, sf::OutMoveHandle qry_h; [65001] AtmosphereUninstallMitm(ServiceName service); [65002] Deprecated_AtmosphereAssociatePidTidForMitm(); [65003] AtmosphereAcknowledgeMitmSession(ServiceName service) -> sf::Out<MitmProcessInfo> client_info, sf::OutMoveHandle fwd_h; [65004] AtmosphereHasMitm(ServiceName service) -> sf::Out<bool> out; [65005] AtmosphereWaitMitm(ServiceName service); [65006] AtmosphereDeclareFutureMitm(ServiceName service); [65100] AtmosphereHasService(ServiceName service) -> sf::Out<bool> out; [65101] AtmosphereWaitService(ServiceName service); } ``` The SwIPC definition for the `sm:m` extension commands follows: ``` interface ams::sm::ManagerService is sm:m { ... [65000] AtmosphereEndInitDefers(os::ProcessId process_id, sf::InBuffer &acid_sac, sf::InBuffer &aci_sac); [65001] AtmosphereHasMitm(ServiceName service) -> sf::Out<bool> out; [65002] AtmosphereRegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, sf::InBuffer &acid_sac, sf::InBuffer &aci_sac); } ``` ================================================ FILE: docs/components/modules/spl.md ================================================ # spl This module is a reimplementation of the Horizon OS's `spl` system module, which is responsible for providing secure platform services such as cryptographic operations. ================================================ FILE: docs/components/stratosphere.md ================================================ # stratosphère stratosphère provides customization of the Horizon OS at the system level. This includes a reimplementation of several system modules and additional, custom system modules that extend or add a variety of features. ## Modules The modules currently provided by stratosphère are: + [ams_mitm](modules/ams_mitm.md) + [boot](modules/boot.md) + [boot2](modules/boot2.md) + [creport](modules/creport.md) + [dmnt](modules/dmnt.md) + [eclct.stub](modules/eclct.stub.md) + [erpt](modules/erpt.md) + [fatal](modules/fatal.md) + [jpegdec](modules/jpegdec.md) + [loader](modules/loader.md) + [ncm](modules/ncm.md) + [pgl](modules/pgl.md) + [pm](modules/pm.md) + [ro](modules/ro.md) + [sm](modules/sm.md) + [spl](modules/spl.md) ================================================ FILE: docs/components/thermosphere.md ================================================ # thermosphère thermosphère is a work in progress hypervisor implementation. This aims to provide functionality at the EL2 level which remains unused by the Horizon OS. ================================================ FILE: docs/components/troposphere.md ================================================ # troposphère troposphère provides customization of the Horizon OS at the application level. ## reboot_to_payload Sample application to perform a system reboot into a payload of choice. ================================================ FILE: docs/faq.md ================================================ # Frequently Asked Questions This document serves as a place to store answers for common questions received about Atmosphère. ## What does "June 15th" mean? When Atmosphère began development in February 2018, "June 15" was given as the estimate/target date for a first release, to coincide with the planned disclosure of a vulnerability. This deadline was missed, hard. People made rather a lot of fun of me (SciresM) for this. Several months later, when the first Atmosphère release occurred, I captioned it "Happy June 15th!" and pretended like I hadn't missed the first deadline. This amused me a lot, and so the practice has been kept up for every single release since. Depending on who you ask, you may be told that this is a dumb joke and it is not funny. This is incorrect. It is definitely a dumb joke, but it is also hilarious. ================================================ FILE: docs/features/cheats.md ================================================ # Cheats Atmosphère supports Action-Replay style cheat codes, with cheats loaded off of the SD card. ## Cheat Loading Process By default, Atmosphère will do the following when deciding whether to attach to a new application process: + Retrieve information about the new application process from `pm` and `loader`. + Check whether a user-defined key combination is held, and stop if not. + This defaults to "L is not held", but can be configured with override keys. + The ini key to configure this is `cheat_enable_key`. + Check whether the process is a real application, and stop if not. + This guards against applying cheat codes to the Homebrew Loader. + Attempt to load cheats from `/atmosphere/contents/<program_id>/cheats/<build_id>.txt`, where `build_id` is the hexadecimal representation of the first 8 bytes of the application's main executable's build id. + If no cheats are found, then the cheat manager will stop. + Open a kernel debug session for the new application process. + Signal to a system event that a new cheat process has been attached to. This behavior ensures that cheat codes are only loaded when the user would want them to. In cases where `dmnt` has not activated the cheat manager, but the user wants to make it do so anyway, the cheat manager's service API provides a `ForceOpenCheatProcess` command that homebrew can use. This command will cause the cheat manager to try to force itself to attach to the process. In cases where `dmnt` has activated the cheat manager, but the user wants to use an alternate debugger, the cheat manager's service API provides a `ForceCloseCheatProcess` command that homebrew can use. This command will cause the cheat manager to detach itself from the process. By default, all cheat codes listed in the loaded .txt file will be toggled on. This is configurable by the user by editing the `atmosphere!dmnt_cheats_enabled_by_default` [system setting](configurations.md). Users may use homebrew programs to toggle cheats on and off at runtime via the cheat manager's service API. ## Cheat Code Compatibility Atmosphère manages cheat code through the execution of a small, custom virtual machine. Care has been taken to ensure that Atmosphère's cheat code format is fully backwards compatible with the pre-existing cheat code format, though new features have been added and bugs in the pre-existing cheat code applier have been fixed. Here is a short summary of the changes from the pre-existing format: + A number of bugs were fixed in the processing of conditional instructions. + The pre-existing implementation was fundamentally broken, and checked for the wrong value when detecting the end of a conditional block. + The pre-existing implementation also did not properly decode instructions, and instead linearly scanned for the terminator value. This caused problems if an instruction happened to encode a terminator inside its immediate values. + The pre-existing implementation did not bounds check, and thus certain conditional cheat codes could cause it to read out-of-bounds memory, and potentially crash due to a data abort. + Support was added for nesting conditional blocks. + An instruction was added to perform much more complex arbitrary arithmetic on two registers. + An instruction was added to allow writing the contents of register to a memory address specified by another register. + The pre-existing implementation did not correctly synchronize with the application process, and thus would cause heavy lag under certain circumstances (especially around loading screens). This has been fixed in Atmosphère's implementation. ## Cheat Code Format The following provides documentation of the instruction format for the virtual machine used to manage cheat codes. Typically, instruction type is encoded in the upper nybble of the first instruction u32. ### Code Type 0x0: Store Static Value to Memory Code type 0x0 allows writing a static value to a memory address. #### Encoding `0TMR00AA AAAAAAAA VVVVVVVV (VVVVVVVV)` + T: Width of memory write (1, 2, 4, or 8 bytes). + M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative). + R: Register to use as an offset from memory region base. + A: Immediate offset to use from memory region base. + V: Value to write. --- ### Code Type 0x1: Begin Conditional Block Code type 0x1 performs a comparison of the contents of memory to a static value. If the condition is not met, all instructions until the appropriate End or Else conditional block terminator are skipped. #### Encoding `1TMCXrAA AAAAAAAA VVVVVVVV (VVVVVVVV)` + T: Width of memory read (1, 2, 4, or 8 bytes). + M: Memory region to read from (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative). + C: Condition to use, see below. + X: Operand Type, see below. + r: Offset Register (operand types 1). + A: Immediate offset to use from memory region base. + V: Value to compare to. #### Conditions + 1: > + 2: >= + 3: < + 4: <= + 5: == + 6: != #### Operand Type + 0: Memory Base + Relative Offset + 1: Memory Base + Offset Register + Relative Offset --- ### Code Type 0x2: End Conditional Block Code type 0x2 marks the end of a conditional block (started by Code Type 0x1 or Code Type 0x8). When an Else is executed, all instructions until the appropriate End conditional block terminator are skipped. #### Encoding `2X000000` + X: End type (0 = End, 1 = Else). --- ### Code Type 0x3: Start/End Loop Code type 0x3 allows for iterating in a loop a fixed number of times. #### Start Loop Encoding `300R0000 VVVVVVVV` + R: Register to use as loop counter. + V: Number of iterations to loop. #### End Loop Encoding `310R0000` + R: Register to use as loop counter. --- ### Code Type 0x4: Load Register with Static Value Code type 0x4 allows setting a register to a constant value. #### Encoding `400R0000 VVVVVVVV VVVVVVVV` + R: Register to use. + V: Value to load. --- ### Code Type 0x5: Load Register with Memory Value Code type 0x5 allows loading a value from memory into a register, either using a fixed address or by dereferencing the destination register. #### Load From Fixed Address Encoding `5TMR00AA AAAAAAAA` + T: Width of memory read (1, 2, 4, or 8 bytes). + M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative). + R: Register to load value into. + A: Immediate offset to use from memory region base. #### Load from Register Address Encoding `5T0R10AA AAAAAAAA` + T: Width of memory read (1, 2, 4, or 8 bytes). + R: Register to load value into. (This register is also used as the base memory address). + A: Immediate offset to use from register R. #### Load from Register Address Encoding `5T0R2SAA AAAAAAAA` + T: Width of memory read (1, 2, 4, or 8 bytes). + R: Register to load value into. + S: Register to use as the base memory address. + A: Immediate offset to use from register R. #### Load From Fixed Address Encoding with offset register `5TMR3SAA AAAAAAAA` + T: Width of memory read (1, 2, 4, or 8 bytes). + M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative). + R: Register to load value into. + S: Register to use as offset register. + A: Immediate offset to use from memory region base. --- ### Code Type 0x6: Store Static Value to Register Memory Address Code type 0x6 allows writing a fixed value to a memory address specified by a register. #### Encoding `6T0RIor0 VVVVVVVV VVVVVVVV` + T: Width of memory write (1, 2, 4, or 8 bytes). + R: Register used as base memory address. + I: Increment register flag (0 = do not increment R, 1 = increment R by T). + o: Offset register enable flag (0 = do not add r to address, 1 = add r to address). + r: Register used as offset when o is 1. + V: Value to write to memory. --- ### Code Type 0x7: Legacy Arithmetic Code type 0x7 allows performing arithmetic on registers. However, it has been deprecated by Code type 0x9, and is only kept for backwards compatibility. #### Encoding `7T0RC000 VVVVVVVV` + T: Width of arithmetic operation (1, 2, 4, or 8 bytes). + R: Register to apply arithmetic to. + C: Arithmetic operation to apply, see below. + V: Value to use for arithmetic operation. #### Arithmetic Types + 0: Addition + 1: Subtraction + 2: Multiplication + 3: Left Shift + 4: Right Shift --- ### Code Type 0x8: Begin Keypress Conditional Block Code type 0x8 enters or skips a conditional block based on whether a key combination is pressed. #### Encoding `8kkkkkkk` + k: Keypad mask to check against, see below. Note that for multiple button combinations, the bitmasks should be ORd together. #### Keypad Values Note: This is the direct output of `hidKeysDown()`. + 0000001: A + 0000002: B + 0000004: X + 0000008: Y + 0000010: Left Stick Pressed + 0000020: Right Stick Pressed + 0000040: L + 0000080: R + 0000100: ZL + 0000200: ZR + 0000400: Plus + 0000800: Minus + 0001000: Left + 0002000: Up + 0004000: Right + 0008000: Down + 0010000: Left Stick Left + 0020000: Left Stick Up + 0040000: Left Stick Right + 0080000: Left Stick Down + 0100000: Right Stick Left + 0200000: Right Stick Up + 0400000: Right Stick Right + 0800000: Right Stick Down + 1000000: SL + 2000000: SR --- ### Code Type 0x9: Perform Arithmetic Code type 0x9 allows performing arithmetic on registers. #### Register Arithmetic Encoding `9TCRS0s0` + T: Width of arithmetic operation (1, 2, 4, or 8 bytes). + C: Arithmetic operation to apply, see below. + R: Register to store result in. + S: Register to use as left-hand operand. + s: Register to use as right-hand operand. #### Immediate Value Arithmetic Encoding `9TCRS100 VVVVVVVV (VVVVVVVV)` + T: Width of arithmetic operation (1, 2, 4, or 8 bytes). + C: Arithmetic operation to apply, see below. + R: Register to store result in. + S: Register to use as left-hand operand. + V: Value to use as right-hand operand. #### Arithmetic Types + 0: Addition + 1: Subtraction + 2: Multiplication + 3: Left Shift + 4: Right Shift + 5: Logical And + 6: Logical Or + 7: Logical Not (discards right-hand operand) + 8: Logical Xor + 9: None/Move (discards right-hand operand) + 10: Float Addition, T==4 single T==8 double + 11: Float Subtraction, T==4 single T==8 double + 12: Float Multiplication, T==4 single T==8 double + 13: Float Division, T==4 single T==8 double --- ### Code Type 0xA: Store Register to Memory Address Code type 0xA allows writing a register to memory. #### Encoding `ATSRIOxa (aaaaaaaa)` + T: Width of memory write (1, 2, 4, or 8 bytes). + S: Register to write to memory. + R: Register to use as base address. + I: Increment register flag (0 = do not increment R, 1 = increment R by T). + O: Offset type, see below. + x: Register used as offset when O is 1, Memory type when O is 3, 4 or 5. + a: Value used as offset when O is 2, 4 or 5. #### Offset Types + 0: No Offset + 1: Use Offset Register + 2: Use Fixed Offset + 3: Memory Region + Base Register + 4: Memory Region + Relative Address (ignore address register) + 5: Memory Region + Relative Address + Offset Register --- ### Code Type 0xB: Reserved Code Type 0xB is currently reserved for future use. --- ### Code Type 0xC-0xF: Extended-Width Instruction Code Types 0xC-0xF signal to the VM to treat the upper two nybbles of the first dword as instruction type, instead of just the upper nybble. This reserves an additional 64 opcodes for future use. --- ### Code Type 0xC0: Begin Register Conditional Block Code type 0xC0 performs a comparison of the contents of a register and another value. This code support multiple operand types, see below. If the condition is not met, all instructions until the appropriate conditional block terminator are skipped. #### Encoding ``` C0TcSX## C0TcS0Ma aaaaaaaa C0TcS1Mr C0TcS2Ra aaaaaaaa C0TcS3Rr C0TcS400 VVVVVVVV (VVVVVVVV) C0TcS5X0 ``` + T: Width of memory write (1, 2, 4, or 8 bytes). + c: Condition to use, see below. + S: Source Register. + X: Operand Type, see below. + M: Memory Type (operand types 0 and 1). + R: Address Register (operand types 2 and 3). + a: Relative Address (operand types 0 and 2). + r: Offset Register (operand types 1 and 3). + X: Other Register (operand type 5). + V: Value to compare to (operand type 4). #### Operand Type + 0: Memory Base + Relative Offset + 1: Memory Base + Offset Register + 2: Register + Relative Offset + 3: Register + Offset Register + 4: Static Value + 5: Other Register #### Conditions + 1: > + 2: >= + 3: < + 4: <= + 5: == + 6: != --- ### Code Type 0xC1: Save or Restore Register Code type 0xC1 performs saving or restoring of registers. #### Encoding `C10D0Sx0` + D: Destination index. + S: Source index. + x: Operand Type, see below. #### Operand Type + 0: Restore register + 1: Save register + 2: Clear saved value + 3: Clear register --- ### Code Type 0xC2: Save or Restore Register with Mask Code type 0xC2 performs saving or restoring of multiple registers using a bitmask. #### Encoding `C2x0XXXX` + x: Operand Type, see below. + X: 16-bit bitmask, bit i == save or restore register i. #### Operand Type + 0: Restore register + 1: Save register + 2: Clear saved value + 3: Clear register --- ### Code Type 0xC3: Read or Write Static Register Code type 0xC3 reads or writes a static register with a given register. #### Encoding `C3000XXx` + XX: Static register index, 0x00 to 0x7F for reading or 0x80 to 0xFF for writing. + x: Register index. --- ### Code Type 0xC4: Begin Extended Keypress Conditional Block Code type 0xC4 enters or skips a conditional block based on whether a key combination is pressed. #### Encoding `C4r00000 kkkkkkkk kkkkkkkk` + r: Auto-repeat, see below. + kkkkkkkkkk: Keypad mask to check against output of `hidKeysDown()`. Note that for multiple button combinations, the bitmasks should be OR'd together. #### Auto-repeat + 0: The conditional block executes only once when the keypad mask matches. The mask must stop matching to reset for the next trigger. + 1: The conditional block executes as long as the keypad mask matches. #### Keypad Values Note: This is the direct output of `hidKeysDown()`. + 00000000 00000001: A + 00000000 00000002: B + 00000000 00000004: X + 00000000 00000008: Y + 00000000 00000010: Left Stick Pressed + 00000000 00000020: Right Stick Pressed + 00000000 00000040: L + 00000000 00000080: R + 00000000 00000100: ZL + 00000000 00000200: ZR + 00000000 00000400: Plus + 00000000 00000800: Minus + 00000000 00001000: Left + 00000000 00002000: Up + 00000000 00004000: Right + 00000000 00008000: Down + 00000000 00010000: Left Stick Left + 00000000 00020000: Left Stick Up + 00000000 00040000: Left Stick Right + 00000000 00080000: Left Stick Down + 00000000 00100000: Right Stick Left + 00000000 00200000: Right Stick Up + 00000000 00400000: Right Stick Right + 00000000 00800000: Right Stick Down + 00000000 01000000: SL Left Joy-Con + 00000000 02000000: SR Left Joy-Con + 00000000 04000000: SL Right Joy-Con + 00000000 08000000: SR Right Joy-Con + 00000000 10000000: Top button on Poké Ball Plus (Palma) controller + 00000000 20000000: Verification + 00000000 40000000: B button on Left NES/HVC controller in Handheld mode + 00000000 80000000: Left C button in N64 controller + 00000001 00000000: Up C button in N64 controller + 00000002 00000000: Right C button in N64 controller + 00000004 00000000: Down C button in N64 controller ### Code Type 0xF0: Double Extended-Width Instruction Code Type 0xF0 signals to the VM to treat the upper three nybbles of the first dword as instruction type, instead of just the upper nybble. This reserves an additional 16 opcodes for future use. --- ### Code Type 0xFF0: Pause Process Code type 0xFF0 pauses the current process. #### Encoding `FF0?????` --- ### Code Type 0xFF1: Resume Process Code type 0xFF1 resumes the current process. #### Encoding `FF1?????` --- ### Code Type 0xFFF: Debug Log Code type 0xFFF writes a debug log to the SD card under the folder `/atmosphere/cheat_vm_logs/`. #### Encoding ``` FFFTIX## FFFTI0Ma aaaaaaaa FFFTI1Mr FFFTI2Ra aaaaaaaa FFFTI3Rr FFFTI4X0 ``` + T: Width of memory write (1, 2, 4, or 8 bytes). + I: Log id. + X: Operand Type, see below. + M: Memory Type (operand types 0 and 1). + R: Address Register (operand types 2 and 3). + a: Relative Address (operand types 0 and 2). + r: Offset Register (operand types 1 and 3). + X: Value Register (operand type 4). #### Operand Type + 0: Memory Base + Relative Offset + 1: Memory Base + Offset Register + 2: Register + Relative Offset + 3: Register + Offset Register + 4: Register Value ================================================ FILE: docs/features/configurations.md ================================================ # Configurations Atmosphère provides a variety of customizable configurations to better adjust to users' needs. ## stratosphere.ini This is the configuration file used by fusée for configuring user-space system modules. This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder. ### Configuring "nogc" Protection "nogc" is a feature provided by fusée-secondary which disables the Nintendo Switch's Game Card reader. Its purpose is to prevent the reader from being updated when the console has been updated, without burning fuses, from a lower firmware version. More specifically, from firmware versions 4.0.0 or 9.0.0 which introduced updates to the Game Card reader's firmware. By default, Atmosphère will protect the Game Card reader automatically, but you are free to change it. To change its functionality, add the following line to the `stratosphere` section and change the value of `X` according to the following list: ``` [stratosphere] nogc = X ``` ``` 1 = force-enable nogc, so Atmosphère will always disable the Game Card reader. 0 = force-disable nogc, so Atmosphère will always enable the Game Card reader. ``` ## Adding a Custom Boot Splashscreen Atmosphère provides its own default splashscreen which is displayed at boot time. However, this can be replaced at will. Boot splash screens must be 1280x720 resolution. A script can be found inside the source tree (`/utilities/insert_splash_screen.py`) for inserting a custom splash screen into a release binary. To do so, execute the following command on the script: `python insert_splash_screen.py <path to your splash screen image> <path to /atmosphere/package3 on your SD card>` ## emummc.ini This is the configuration file used for the [emummc](../components/emummc.md) component. This file is located under the `/emuMMC/` folder on your SD card. Please refer to the project's repository [here](https://github.com/m4xw/emuMMC) for detailed instructions and documentation. ## exosphere.ini This is the configuration file used by exosphère. This file is located in the root of your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder. ### Configuring Debugging Modes By default, Atmosphère signals to the Horizon kernel that debugging is enabled while leaving usermode debugging disabled, but this can cause undesirable side-effects. If you wish to change this behavior, go to the `exosphere` section and change the value of `X` according to the following list. ``` [exosphere] debugmode = X debugmode_user = X ``` ``` 1 = enable 0 = disable ``` ### Blanking PRODINFO Atmosphère provides a way for users to blank their factory installed calibration data (known as PRODINFO) in either emulated or system eMMC environments. You can find more detailed information on this inside the respective template file. Usage of this configuration is not encouraged. ## override_config.ini This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder. ### Overrides Format Overrides are parsed from the `/atmosphere/config/override_config.ini` file during the boot process. By default `override_config.ini` is not configured. It can be used to select the behavior of certain buttons and bind them to functionalities such as launching the Homebrew Menu or enabling the cheat code manager. You can modify the override_key entries in `override_config.ini` with this list of valid buttons: | Formal Name | .ini Name | | ----------- | --------- | | A Button | A | | B Button | B | | X Button | X | | Y Button | Y | | Left Stick | LS | | Right Stick | RS | | L Button | L | | R Button | R | | ZL Button | ZL | | ZR Button | ZR | | + Button | PLUS | | - Button | MINUS | | Left Dpad | DLEFT | | Up Dpad | DUP | | Right Dpad | DRIGHT | | Down Dpad | DDOWN | | SL Button | SL | | SR Button | SR | To invert the behavior of the override key, place an exclamation point in front of whatever button you wish to use. It will launch the actual game while holding down that button, instead of going into the Homebrew Menu. For example, `override_key=!R` will run the game only while holding down R when launching it, otherwise it will boot into the Homebrew Menu. Afterwards you may reinsert your SD card into your Switch and boot into Atmosphère as you normally would. You should now be able to boot into the Homebrew Menu by launching your designated program of choice. ## system_settings.ini This file is located under the `/atmosphere/config/` folder on your SD card and a default template can be found inside the `/atmosphere/config_templates/` folder. ### Settings Format Atmosphère provides a way to override the firmware debug settings used by the system. These can be parsed from the `/atmosphere/config/system_settings.ini` file during the boot process. This file is a normal ini file, with some specific interpretations. The standard representation of a setting's identifier takes the form `name!key`. This is represented within `system_settings.ini` as a section `name`, with an entry `key`. For example: ``` [name] key = ... ``` Settings can have variable types (strings, integral values, byte arrays, etc). To accommodate this, `system_settings.ini` must store values as a `type_identifier!value_store` pair. A number of different types are supported, with identifiers detailed below. Please note that a malformed value string will cause a fatal error to occur on boot. A full example of a custom setting is given below (setting `eupld!upload_enabled = 0`), for posterity: ``` [eupld] upload_enabled = u8!0x0 ``` #### Supported Types * Strings * Type identifiers: `str`, `string` * The value string is used directly as the setting, with null terminator appended. * Integral types * Type identifiers: `u8`, `u16`, `u32`, `u64` * The value string is parsed via a call to `strtoul(value, NULL, 0)`. * Setting bitwidth is determined by the identifier (8 for 1 byte, 16 for 2 bytes, and so on). * Raw bytes * Type identifiers: `hex`, `bytes` * The value string is parsed as a hexadecimal string. * The value string must be of even length, or a fatal error will be thrown on parse. ## Content Specific Flags Atmosphère supports customizing CFW behavior based on the presence of `flags` on the SD card. The following flags are supported on a per-program basis, by placing `<flag_name>.flag` inside `/atmosphere/contents/<program_id>/flags/`: + `boot2`, which indicates that the program should be launched during the `boot2` process. + `redirect_save`, which indicates that the program wants its savedata to be redirected to the SD card. ================================================ FILE: docs/features/dns_mitm.md ================================================ # DNS.mitm As of 0.18.0, atmosphère provides a mechanism for redirecting DNS resolution requests. By default, atmosphère redirects resolution requests for official telemetry servers, redirecting them to a loopback address. ## Hosts files DNS.mitm can be configured through the usage of a slightly-extended `hosts` file format, which is parsed only once on system startup. In particular, hosts files parsed by DNS.mitm have the following extensions to the usual format: + `*` is treated as a wildcard character, matching any collection of 0 or more characters wherever it occurs in a hostname. + `%` is treated as a stand-in for the value of `nsd!environment_identifier`. This is always `lp1`, on production devices. If multiple entries in a host file match a domain, the last-defined match is used. Please note that homebrew may trigger a hosts file re-parse by sending the extension IPC command 65000 ("AtmosphereReloadHostsFile") to a connected `sfdnsres` session. ### Hosts file selection Atmosphère will try to read hosts from the following file paths, in order, stopping once it successfully performs a file read: + (emummc only) `/atmosphere/hosts/emummc_%04lx.txt`, formatted with the emummc's id number (see `emummc.ini`). + (emummc only) `/atmosphere/hosts/emummc.txt`. + (sysmmc only) `/atmosphere/hosts/sysmmc.txt`. + `/atmosphere/hosts/default.txt` If `/atmosphere/hosts/default.txt` does not exist, atmosphère will create it to contain the defaults. ### Atmosphère defaults By default, atmosphère's default redirections are parsed **in addition to** the contents of the loaded hosts file. This is equivalent to thinking of the loaded hosts file as having the atmosphère defaults prepended to it. This setting is considered desirable, because it minimizes the telemetry risks if a user forgets to update a custom hosts file on a system update which changes the telemetry servers. This behavior can be opted-out from by setting `atmosphere!add_defaults_to_dns_hosts = u8!0x0` in `system_settings.ini`. The current default redirections are: ``` # Nintendo telemetry servers 127.0.0.1 receive-%.dg.srv.nintendo.net receive-%.er.srv.nintendo.net ``` ## Debugging On startup (or on hosts file re-parse), DNS.mitm will log both what hosts file it selected and the contents of all redirections it parses to `/atmosphere/logs/dns_mitm_startup.log`. In addition, if the user sets `atmosphere!enable_dns_mitm_debug_log = u8!0x1` in `system_settings.ini`, DNS.mitm will log all requests to GetHostByName/GetAddrInfo to `/atmosphere/logs/dns_mitm_debug.log`. All redirections will be noted when they occur. ## Opting-out of DNS.mitm entirely If you wish to disable DNS.mitm entirely, `system_settings.ini` can be edited to set `atmosphere!enable_dns_mitm = u8!0x0`. ================================================ FILE: docs/licensing_exemptions/MIT_LICENSE ================================================ MIT License Copyright (c) Atmosphère-NX Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: docs/main.md ================================================ # Atmosphère Atmosphère is a work-in-progress customized firmware for the Nintendo Switch. Its design principle consists of a multi-layered approach where each layer replaces/modifies a different component of the Nintendo Switch's system. ## Components Atmosphère provides six core components, mimicking to some degree the various layers of the Earth's atmosphere: + [fusée](components/fusee.md) + [exosphère](components/exosphere.md) + [thermosphère](components/thermosphere.md) + [mesosphère](components/mesosphere.md) + [stratosphère](components/stratosphere.md) + [troposphère](components/troposphere.md) Additionally, Atmosphère also provides the following secondary components: + [emummc](components/emummc.md) + [libraries](components/libraries.md) ## Features Atmosphère provides several original features which add or expand functionalities for the customized firmware environment: + [Cheats](features/cheats.md) + [Configurations](features/configurations.md) ## Building Atmosphère A guide to building Atmosphère can be found [here](building.md). ## Upcoming Features A list of planned features for Atmosphère can be found [here](roadmap.md). ## Release History A changelog of previous versions of Atmosphère can be found [here](changelog.md). ## Frequently Asked Questions Answers to one or more frequently asked questions may be found [here](faq.md). ================================================ FILE: docs/roadmap.md ================================================ # Planned Features atmosphère has a number of features that are either works-in-progress or planned. Please note that while time-estimates are given, they are loose, and things may be completed sooner or later than advertised. The following descriptions were last updated on January 14th, 2021 ## tma reimplementation * **Description** tma ("target manager agent") is a system module that manages communication between the Switch and a client PC. Atmosphere's implementation will allow homebrew on the switch to communicate with a connected PC to do various operations such as exchanging data or interacting with files. It will also serve as the communicator for Atmosphère's planned debugger. This will also include PC-side software for interacting with the Switch. * **Development Status**: Planned. Switch-side code is fully implemented but needs heavy refactoring/rebasing, as the code was originally authored in 2018. * **Estimated Time**: 2021-2022. ## dmnt.gen2 reimplementation * **Description**: A reimplementation of the Switch's debug monitor, dmnt will provide an interface for debugging applications or system modules running on the Switch. This will include a gdbstub for debugging actively-running system components or applications. * **Development Status**: Planned * **Estimated Time**: 2021-2022 ## fs reimplementation * **Description**: Following mesosphère's completion, atmosphère will have reimplemented all components of the BootImagePackage firmware except for the filesystem services system module. Reimplementing fs will allow for fixing Nintendo bugs (such as corruption when using exFAT filesystems and encoding inconsistencies with UTF-8 and Shift-JIS). * **Development Status**: Planned. * **Estimated Time**: 2021-2022. ## settings reimplementation * **Description**: A planned reimplementation of the settings system module, and with it a removal of the settings mitm. This will greatly simplify atmosphère's boot process, and will allow much more flexible control over the various system settings. * **Development Status**: Pending development by Adubbz. * **Estimated Time**: Unclear, pending developer availability. ## thermosphère * **Description**: A general-purpose hypervisor, thermosphère will enable the virtualization of the Switch's operating system; this is planned to enable debugging of the Switch's kernel. * **Development Status**: Pending development by TuxSH. * **Estimated Time**: Unclear, pending developer availability. ## other planned features * **Description**: General system stability improvements to enhance the user's experience. * **Development Status**: Undergoing active development by all members of the atmosphère team. * **Estimated Time**: June 15th. # Completed features The following features were previously included under the planned features section and are now complete. Please note that this is not an exhaustive list of features present in atmosphère, and only serves to indicate what from the above has been completed. ## system updater homebrew * **Description**: A user homebrew making use of the new system updater api, so that users can actually use the new api in practice. * **Completion Time**: July 2020 ## system updater api * **Description**: A planned extension api for stratosphere (tenatively `ams:su`), this will provide an interface for homebrew to safely install system upgrades or downgrades. This will allow for much more easily transitioning safely between different versions of the operating system. * **Completion Time**: June 2020 ## exosphere re-write * **Description**: exosphère, atmosphère's reimplementation of Horizon's Secure Monitor, was the first component authored for the project in early 2018. It is written in C, and in a style very different from the rest of atmosphère's code. In addition, exosphère was written to conform to constraints that no longer apply in an environment where it is not launched from the web browser, and where using a custom firmware image to orchestrate wake-from-sleep is possible. exosphère currently uses all but 1 KB of the space available to it, putting it at risk of breaking as future firmware updates are supported. A re-write will solve these issues. * **Completion Time**: June 2020 ## mesosphere * **Description**: mesosphère is a reimplementation of the Horizon operating system's Kernel. It aims to provide an open-source reference for Nintendo's code. * **Estimated Time**: September 2020 ## ams-on-mariko * **Description**: Atmosphere cannot run as-is on Mariko hardware. A large number of changes are needed in many components. Although secure monitor support is complete in exosphere, additional work is needed on the bootloader and stratosphere sides as well. Mariko support will also require further design thought; atmosphere's debugging design heavily relies on reboot-to-payload and (more generally) the ability to perform warmboot bootrom hax at will. This is not possible on Mariko, and will require a new design/software support for whatever solution is chosen. * **Completion Time**: January 2021 ================================================ FILE: emummc/.gitignore ================================================ *.kip *.data *.elf build .vscode/ipch .vscode/settings.json *.exe *.kip* emummc.caps ================================================ FILE: emummc/.gitrepo ================================================ ; DO NOT EDIT (unless you know what you are doing) ; ; This subdirectory is a git "subrepo", and this file is maintained by the ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme ; [subrepo] remote = https://github.com/m4xw/emummc branch = develop commit = 8ab963b0b1c24b68de8e0c98c62c7822a9765bf3 parent = 1e88f37892555da4c38ca6c95f43c56cc6bb87e6 method = merge cmdver = 0.4.1 ================================================ FILE: emummc/LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: emummc/Makefile ================================================ .SUFFIXES: ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif TARGET := emummc BUILD := build SOURCES := source/nx source source/utils source/emmc source/soc source/power source/emuMMC source/FS source/libs/fatfs DATA := data INCLUDES := include EXEFS_SRC := exefs_src ifneq ($(BUILD),$(notdir $(CURDIR))) EMUMMCDIR ?= $(CURDIR) else EMUMMCDIR ?= $(CURDIR)/../ endif include $(DEVKITPRO)/libnx/switch_rules ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE # Current max usage is 0x4600. (512 * 34 FatFS file objects + 1 fsync buffer). DEFINES := -DINNER_HEAP_SIZE=0x8000 CFLAGS := -Wall -O2 -ffunction-sections -fdata-sections -Wno-unused-function \ $(ARCH) $(DEFINES) CFLAGS += $(INCLUDE) -D__SWITCH__ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(EMUMMCDIR)/emummc.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) ifneq ($(BUILD),$(notdir $(CURDIR))) export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(EMUMMCDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) ifeq ($(strip $(CPPFILES)),) export LD := $(CC) else export LD := $(CXX) endif export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I$(CURDIR)/$(BUILD) export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) ifeq ($(strip $(CONFIG_JSON)),) jsons := $(wildcard *.json) ifneq (,$(findstring $(TARGET).json,$(jsons))) export APP_JSON := $(TOPDIR)/$(TARGET).json else ifneq (,$(findstring config.json,$(jsons))) export APP_JSON := $(TOPDIR)/config.json endif endif else export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) endif .PHONY: $(BUILD) clean all all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile clean: @echo clean ... @rm -fr $(BUILD) $(TARGET).elf $(TARGET).kip else .PHONY: all DEPENDS := $(OFILES:.o=.d) all : $(OUTPUT)_unpacked.kip $(OUTPUT)_unpacked.kip : $(OUTPUT).kip @hactool -t kip --uncompressed=$(OUTPUT)_unpacked.kip $(OUTPUT).kip $(OUTPUT).kip : $(OUTPUT).elf $(OUTPUT).elf : $(OFILES) $(OFILES_SRC) : $(HFILES_BIN) %.bin.o %_bin.h : %.bin @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) endif ================================================ FILE: emummc/README.md ================================================ # emuMMC *A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw*** ### Supported Horizon Versions **1.0.0 - 21.2.0** ## Features * Arbitrary SDMMC backend selection **This allows loading eMMC from SD or even SD from eMMC** * On the fly hooking / patching, fully self-infesting **Only one payload required for all versions!** * File-based SDMMC backend support (from SD) **This allows loading eMMC images from hekate-backups (split or not)** * SDMMC device based sector offset (*currently eMMC only*) **Raw partition support for eMMC from SD with less performance overhead** * Full support for `/Nintendo` folder redirection to a arbitrary path **No 8 char length restriction!** * exosphere based context configuration **This includes full support for multiple emuMMC images** ## Compiling ### hekate Run `./build.sh` and copy the produced kipm (Kernel Initial Process Modification) file to `/bootloader/sys/` ### Atmosphere Run `make`, the resulting kip can be used for code injection via fusee (place at `/atmosphere/emummc.kip`) ## License **emuMMC is released as GPLv2** ## Credits * **CTCaer** - The CTCaer hekate fork, file-based emuMMC support, SDMMC driver fixes among other things * **SciresM, hexkyz** - The Atmosphere project, FS offsets, additional research related to newer FS versions * **naehrwert** - The hekate project, its SDMMC driver and being very helpful in the early research phase * **jakibaki** - KIP Inject PoC, used in the early dev phase * **switchbrew/devkitPro** - devkitA64 and libnx sources ================================================ FILE: emummc/build.sh ================================================ #!/bin/bash set -e make clean make -j ./hactool.exe -t kip emummc.kip --uncompressed emummc_unpacked.kip python2.7 tools/kip1converter.py emummc_unpacked.kip emummc.data cat emummc.caps emummc.data > emummc.kipm ================================================ FILE: emummc/emummc.json ================================================ { "name": "FS", "title_id": "0x0100000000000000", "main_thread_stack_size": "0x00008000", "main_thread_priority": 45, "default_cpu_id": 3, "process_category": 1, "kernel_capabilities": [ { "type": "map_page", "value": "0x60006000" }, { "type": "map", "value": { "address": "0x6000D000", "size": "0x1000", "is_ro": false, "is_io": true } }, { "type": "map", "value": { "address": "0x700b0000", "is_ro": false, "size": "0x00005000", "is_io": true } }, { "type": "map", "value": { "address": "0x7000C000", "is_ro": false, "size": "0x00002000", "is_io": true } }, { "type": "map", "value": { "address": "0x70000000", "is_ro": false, "size": "0x00004000", "is_io": true } }, { "type": "handle_table_size", "value": 256 }, { "type": "irq_pair", "value": [ 46, 47 ] }, { "type": "irq_pair", "value": [ 51, 63 ] }, { "type": "syscalls", "value": { "svcSetHeapSize": "0x01", "svcSetMemoryPermission": "0x02", "svcSetMemoryAttribute": "0x03", "svcMapMemory": "0x04", "svcUnmapMemory": "0x05", "svcQueryMemory": "0x06", "svcExitProcess": "0x07", "svcCreateThread": "0x08", "svcStartThread": "0x09", "svcExitThread": "0x0a", "svcSleepThread": "0x0b", "svcGetThreadPriority": "0x0c", "svcSetThreadPriority": "0x0d", "svcGetThreadCoreMask": "0x0e", "svcSetThreadCoreMask": "0x0f", "svcGetCurrentProcessorNumber": "0x10", "svcSignalEvent": "0x11", "svcClearEvent": "0x12", "svcMapSharedMemory": "0x13", "svcUnmapSharedMemory": "0x14", "svcCreateTransferMemory": "0x15", "svcCloseHandle": "0x16", "svcResetSignal": "0x17", "svcWaitSynchronization": "0x18", "svcCancelSynchronization": "0x19", "svcArbitrateLock": "0x1a", "svcArbitrateUnlock": "0x1b", "svcWaitProcessWideKeyAtomic": "0x1c", "svcSignalProcessWideKey": "0x1d", "svcGetSystemTick": "0x1e", "svcConnectToNamedPort": "0x1f", "svcSendSyncRequestLight": "0x20", "svcSendSyncRequest": "0x21", "svcSendSyncRequestWithUserBuffer": "0x22", "svcSendAsyncRequestWithUserBuffer": "0x23", "svcGetProcessId": "0x24", "svcGetThreadId": "0x25", "svcBreak": "0x26", "svcOutputDebugString": "0x27", "svcReturnFromException": "0x28", "svcGetInfo": "0x29", "svcWaitForAddress": "0x34", "svcSignalToAddress": "0x35", "svcCreateSession": "0x40", "svcAcceptSession": "0x41", "svcReplyAndReceiveLight": "0x42", "svcReplyAndReceive": "0x43", "svcReplyAndReceiveWithUserBuffer": "0x44", "svcCreateEvent": "0x45", "svcReadWriteRegister": "0x4E", "svcMapTransferMemory": "0x51", "svcUnmapTransferMemory": "0x52", "svcCreateInterruptEvent": "0x53", "svcQueryIoMapping": "0x55", "svcCreateDeviceAddressSpace": "0x56", "svcAttachDeviceAddressSpace": "0x57", "svcDetachDeviceAddressSpace": "0x58", "svcMapDeviceAddressSpaceAligned": "0x5a", "svcUnmapDeviceAddressSpace": "0x5c", "svcGetSystemInfo": "0x6f", "svcSetProcessMemoryPermission": "0x73", "svcMapProcessMemory": "0x74", "svcUnmapProcessMemory": "0x75", "svcCallSecureMonitor": "0x7f" } } ] } ================================================ FILE: emummc/emummc.ld ================================================ OUTPUT_ARCH(aarch64) ENTRY(_start) PHDRS { code PT_LOAD FLAGS(5) /* Read | Execute */; rodata PT_LOAD FLAGS(4) /* Read */; data PT_LOAD FLAGS(6) /* Read | Write */; dyn PT_DYNAMIC; } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = 0x0); . = __start__; __code_start = . ; .crt0 : { KEEP (*(.crt0)) . = ALIGN(8); } :code .init : { KEEP( *(.init) ) . = ALIGN(8); } :code .plt : { *(.plt) *(.iplt) . = ALIGN(8); } :code .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } :code .fini : { KEEP( *(.fini) ) . = ALIGN(8); } :code /* =========== RODATA section =========== */ . = ALIGN(0x1000); __rodata_start = . ; .nx-module-name : { KEEP (*(.nx-module-name)) } :rodata .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } :rodata .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } :rodata .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } :rodata .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } :rodata .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata .dynamic : { *(.dynamic) } :rodata :dyn .dynsym : { *(.dynsym) } :rodata .dynstr : { *(.dynstr) } :rodata .rela.dyn : { *(.rela.*) } :rodata .interp : { *(.interp) } :rodata .hash : { *(.hash) } :rodata .gnu.hash : { *(.gnu.hash) } :rodata .gnu.version : { *(.gnu.version) } :rodata .gnu.version_d : { *(.gnu.version_d) } :rodata .gnu.version_r : { *(.gnu.version_r) } :rodata .note.gnu.build-id : { *(.note.gnu.build-id) } :rodata /* =========== DATA section =========== */ . = ALIGN(0x1000); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } :data .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } :data .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } : data .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } :data .tdata ALIGN(8) : { __tdata_lma = .; *(.tdata .tdata.* .gnu.linkonce.td.*) . = ALIGN(8); __tdata_lma_end = .; } :data .tbss ALIGN(8) : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) . = ALIGN(8); } :data .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } :data .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP( *(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)) ) KEEP( *(.init_array .ctors) ) PROVIDE (__init_array_end = .); } :data .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP( *(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)) ) KEEP( *(.fini_array .dtors) ) PROVIDE (__fini_array_end = .); } :data __got_start__ = .; .got : { *(.got) *(.igot) } :data .got.plt : { *(.got.plt) *(.igot.plt) } :data __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } :data __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(8); /* Reserve space for the TLS segment of the main thread */ __tls_start = .; . += + SIZEOF(.tdata) + SIZEOF(.tbss); __tls_end = .; } : data __bss_end__ = .; __end__ = ABSOLUTE(.) ; . = ALIGN(0x1000); __argdata__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: emummc/emummc.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(TOPDIR /emummc.ld) -pie --no-dynamic-linker --spare-dynamic-tags=0 --gc-sections -z text -z nodynamic-undefined-weak --build-id=sha1 --nx-module-name *startfile: crti%O%s crtbegin%O%s ================================================ FILE: emummc/source/FS/FS.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_H__ #define __FS_H__ // TODO #include "../emmc/sdmmc_t210.h" #include "FS_versions.h" #include "FS_offsets.h" #include "FS_structs.h" #define FS_SDMMC_EMMC 0 #define FS_SDMMC_SD 1 #define FS_SDMMC_GC 2 #define FS_EMMC_PARTITION_GPP 0 #define FS_EMMC_PARTITION_BOOT0 1 #define FS_EMMC_PARTITION_BOOT1 2 #define FS_EMMC_PARTITION_INVALID 3 #define BOOT_PARTITION_SIZE 0x2000 #define FS_READ_WRITE_ERROR 1048 #define NAND_PATROL_SECTOR 0xC20 #define NAND_PATROL_OFFSET 0x184000 typedef struct _fs_nand_patrol_t { uint8_t hmac[0x20]; unsigned int offset; unsigned int count; uint8_t rsvd[0x1D8]; } fs_nand_patrol_t; #endif /* __FS_H__ */ ================================================ FILE: emummc/source/FS/FS_offsets.c ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "FS_offsets.h" #include "offsets/100.h" #include "offsets/200.h" #include "offsets/200_exfat.h" #include "offsets/210.h" #include "offsets/210_exfat.h" #include "offsets/300.h" #include "offsets/300_exfat.h" #include "offsets/301.h" #include "offsets/301_exfat.h" #include "offsets/400.h" #include "offsets/400_exfat.h" #include "offsets/410.h" #include "offsets/410_exfat.h" #include "offsets/500.h" #include "offsets/500_exfat.h" #include "offsets/510.h" #include "offsets/510_exfat.h" #include "offsets/600.h" #include "offsets/600_exfat.h" #include "offsets/700.h" #include "offsets/700_exfat.h" #include "offsets/800.h" #include "offsets/800_exfat.h" #include "offsets/810.h" #include "offsets/810_exfat.h" #include "offsets/900.h" #include "offsets/900_exfat.h" #include "offsets/910.h" #include "offsets/910_exfat.h" #include "offsets/1000.h" #include "offsets/1000_exfat.h" #include "offsets/1020.h" #include "offsets/1020_exfat.h" #include "offsets/1100.h" #include "offsets/1100_exfat.h" #include "offsets/1200.h" #include "offsets/1200_exfat.h" #include "offsets/1203.h" #include "offsets/1203_exfat.h" #include "offsets/1300.h" #include "offsets/1300_exfat.h" #include "offsets/1310.h" #include "offsets/1310_exfat.h" #include "offsets/1400.h" #include "offsets/1400_exfat.h" #include "offsets/1500.h" #include "offsets/1500_exfat.h" #include "offsets/1600.h" #include "offsets/1600_exfat.h" #include "offsets/1603.h" #include "offsets/1603_exfat.h" #include "offsets/1700.h" #include "offsets/1700_exfat.h" #include "offsets/1800.h" #include "offsets/1800_exfat.h" #include "offsets/1810.h" #include "offsets/1810_exfat.h" #include "offsets/1900.h" #include "offsets/1900_exfat.h" #include "offsets/2000.h" #include "offsets/2000_exfat.h" #include "offsets/2010.h" #include "offsets/2010_exfat.h" #include "offsets/2100.h" #include "offsets/2100_exfat.h" #include "offsets/2120.h" #include "offsets/2120_exfat.h" #include "../utils/fatal.h" #define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers #define DEFINE_OFFSET_STRUCT(vers) \ static const fs_offsets_t GET_OFFSET_STRUCT_NAME(vers) = { \ .sdmmc_accessor_gc = FS_OFFSET##vers##_SDMMC_ACCESSOR_GC, \ .sdmmc_accessor_sd = FS_OFFSET##vers##_SDMMC_ACCESSOR_SD, \ .sdmmc_accessor_nand = FS_OFFSET##vers##_SDMMC_ACCESSOR_NAND, \ .sdmmc_wrapper_read = FS_OFFSET##vers##_SDMMC_WRAPPER_READ, \ .sdmmc_wrapper_write = FS_OFFSET##vers##_SDMMC_WRAPPER_WRITE, \ .clkrst_set_min_v_clock_rate = FS_OFFSET##vers##_CLKRST_SET_MIN_V_CLK_RATE, \ .rtld = FS_OFFSET##vers##_RTLD, \ .rtld_destination = FS_OFFSET##vers##_RTLD_DESTINATION, \ .lock_mutex = FS_OFFSET##vers##_LOCK_MUTEX, \ .unlock_mutex = FS_OFFSET##vers##_UNLOCK_MUTEX, \ .sd_mutex = FS_OFFSET##vers##_SD_MUTEX, \ .nand_mutex = FS_OFFSET##vers##_NAND_MUTEX, \ .active_partition = FS_OFFSET##vers##_ACTIVE_PARTITION, \ .sdmmc_das_handle = FS_OFFSET##vers##_SDMMC_DAS_HANDLE, \ .sdmmc_accessor_controller_open = FS_OFFSET##vers##_SDMMC_WRAPPER_CONTROLLER_OPEN, \ .sdmmc_accessor_controller_close = FS_OFFSET##vers##_SDMMC_WRAPPER_CONTROLLER_CLOSE, \ .sd_das_init = FS_OFFSET##vers##_SD_DAS_INIT, \ .nintendo_paths = FS_OFFSET##vers##_NINTENDO_PATHS, \ } // Actually define offset structs DEFINE_OFFSET_STRUCT(_100); DEFINE_OFFSET_STRUCT(_200); DEFINE_OFFSET_STRUCT(_200_EXFAT); DEFINE_OFFSET_STRUCT(_210); DEFINE_OFFSET_STRUCT(_210_EXFAT); DEFINE_OFFSET_STRUCT(_300); DEFINE_OFFSET_STRUCT(_300_EXFAT); DEFINE_OFFSET_STRUCT(_301); DEFINE_OFFSET_STRUCT(_301_EXFAT); DEFINE_OFFSET_STRUCT(_400); DEFINE_OFFSET_STRUCT(_400_EXFAT); DEFINE_OFFSET_STRUCT(_410); DEFINE_OFFSET_STRUCT(_410_EXFAT); DEFINE_OFFSET_STRUCT(_500); DEFINE_OFFSET_STRUCT(_500_EXFAT); DEFINE_OFFSET_STRUCT(_510); DEFINE_OFFSET_STRUCT(_510_EXFAT); DEFINE_OFFSET_STRUCT(_600); DEFINE_OFFSET_STRUCT(_600_EXFAT); DEFINE_OFFSET_STRUCT(_700); DEFINE_OFFSET_STRUCT(_700_EXFAT); DEFINE_OFFSET_STRUCT(_800); DEFINE_OFFSET_STRUCT(_800_EXFAT); DEFINE_OFFSET_STRUCT(_810); DEFINE_OFFSET_STRUCT(_810_EXFAT); DEFINE_OFFSET_STRUCT(_900); DEFINE_OFFSET_STRUCT(_900_EXFAT); DEFINE_OFFSET_STRUCT(_910); DEFINE_OFFSET_STRUCT(_910_EXFAT); DEFINE_OFFSET_STRUCT(_1000); DEFINE_OFFSET_STRUCT(_1000_EXFAT); DEFINE_OFFSET_STRUCT(_1020); DEFINE_OFFSET_STRUCT(_1020_EXFAT); DEFINE_OFFSET_STRUCT(_1100); DEFINE_OFFSET_STRUCT(_1100_EXFAT); DEFINE_OFFSET_STRUCT(_1200); DEFINE_OFFSET_STRUCT(_1200_EXFAT); DEFINE_OFFSET_STRUCT(_1203); DEFINE_OFFSET_STRUCT(_1203_EXFAT); DEFINE_OFFSET_STRUCT(_1300); DEFINE_OFFSET_STRUCT(_1300_EXFAT); DEFINE_OFFSET_STRUCT(_1310); DEFINE_OFFSET_STRUCT(_1310_EXFAT); DEFINE_OFFSET_STRUCT(_1400); DEFINE_OFFSET_STRUCT(_1400_EXFAT); DEFINE_OFFSET_STRUCT(_1500); DEFINE_OFFSET_STRUCT(_1500_EXFAT); DEFINE_OFFSET_STRUCT(_1600); DEFINE_OFFSET_STRUCT(_1600_EXFAT); DEFINE_OFFSET_STRUCT(_1603); DEFINE_OFFSET_STRUCT(_1603_EXFAT); DEFINE_OFFSET_STRUCT(_1700); DEFINE_OFFSET_STRUCT(_1700_EXFAT); DEFINE_OFFSET_STRUCT(_1800); DEFINE_OFFSET_STRUCT(_1800_EXFAT); DEFINE_OFFSET_STRUCT(_1810); DEFINE_OFFSET_STRUCT(_1810_EXFAT); DEFINE_OFFSET_STRUCT(_1900); DEFINE_OFFSET_STRUCT(_1900_EXFAT); DEFINE_OFFSET_STRUCT(_2000); DEFINE_OFFSET_STRUCT(_2000_EXFAT); DEFINE_OFFSET_STRUCT(_2010); DEFINE_OFFSET_STRUCT(_2010_EXFAT); DEFINE_OFFSET_STRUCT(_2100); DEFINE_OFFSET_STRUCT(_2100_EXFAT); DEFINE_OFFSET_STRUCT(_2120); DEFINE_OFFSET_STRUCT(_2120_EXFAT); const fs_offsets_t *get_fs_offsets(enum FS_VER version) { switch (version) { case FS_VER_1_0_0: return &(GET_OFFSET_STRUCT_NAME(_100)); case FS_VER_2_0_0: return &(GET_OFFSET_STRUCT_NAME(_200)); case FS_VER_2_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_200_EXFAT)); case FS_VER_2_1_0: return &(GET_OFFSET_STRUCT_NAME(_210)); case FS_VER_2_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_210_EXFAT)); case FS_VER_3_0_0: return &(GET_OFFSET_STRUCT_NAME(_300)); case FS_VER_3_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_300_EXFAT)); case FS_VER_3_0_1: return &(GET_OFFSET_STRUCT_NAME(_301)); case FS_VER_3_0_1_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_301_EXFAT)); case FS_VER_4_0_0: return &(GET_OFFSET_STRUCT_NAME(_400)); case FS_VER_4_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_400_EXFAT)); case FS_VER_4_1_0: return &(GET_OFFSET_STRUCT_NAME(_410)); case FS_VER_4_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_410_EXFAT)); case FS_VER_5_0_0: return &(GET_OFFSET_STRUCT_NAME(_500)); case FS_VER_5_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_500_EXFAT)); case FS_VER_5_1_0: return &(GET_OFFSET_STRUCT_NAME(_510)); case FS_VER_5_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_510_EXFAT)); case FS_VER_6_0_0: return &(GET_OFFSET_STRUCT_NAME(_600)); case FS_VER_6_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_600_EXFAT)); case FS_VER_7_0_0: return &(GET_OFFSET_STRUCT_NAME(_700)); case FS_VER_7_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_700_EXFAT)); case FS_VER_8_0_0: return &(GET_OFFSET_STRUCT_NAME(_800)); case FS_VER_8_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_800_EXFAT)); case FS_VER_8_1_0: return &(GET_OFFSET_STRUCT_NAME(_810)); case FS_VER_8_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT)); case FS_VER_9_0_0: return &(GET_OFFSET_STRUCT_NAME(_900)); case FS_VER_9_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_900_EXFAT)); case FS_VER_9_1_0: return &(GET_OFFSET_STRUCT_NAME(_910)); case FS_VER_9_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_910_EXFAT)); case FS_VER_10_0_0: return &(GET_OFFSET_STRUCT_NAME(_1000)); case FS_VER_10_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1000_EXFAT)); case FS_VER_10_2_0: return &(GET_OFFSET_STRUCT_NAME(_1020)); case FS_VER_10_2_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1020_EXFAT)); case FS_VER_11_0_0: return &(GET_OFFSET_STRUCT_NAME(_1100)); case FS_VER_11_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1100_EXFAT)); case FS_VER_12_0_0: return &(GET_OFFSET_STRUCT_NAME(_1200)); case FS_VER_12_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1200_EXFAT)); case FS_VER_12_0_3: return &(GET_OFFSET_STRUCT_NAME(_1203)); case FS_VER_12_0_3_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1203_EXFAT)); case FS_VER_13_0_0: return &(GET_OFFSET_STRUCT_NAME(_1300)); case FS_VER_13_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1300_EXFAT)); case FS_VER_13_1_0: return &(GET_OFFSET_STRUCT_NAME(_1310)); case FS_VER_13_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1310_EXFAT)); case FS_VER_14_0_0: return &(GET_OFFSET_STRUCT_NAME(_1400)); case FS_VER_14_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1400_EXFAT)); case FS_VER_15_0_0: return &(GET_OFFSET_STRUCT_NAME(_1500)); case FS_VER_15_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT)); case FS_VER_16_0_0: return &(GET_OFFSET_STRUCT_NAME(_1600)); case FS_VER_16_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1600_EXFAT)); case FS_VER_16_0_3: return &(GET_OFFSET_STRUCT_NAME(_1603)); case FS_VER_16_0_3_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1603_EXFAT)); case FS_VER_17_0_0: return &(GET_OFFSET_STRUCT_NAME(_1700)); case FS_VER_17_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1700_EXFAT)); case FS_VER_18_0_0: return &(GET_OFFSET_STRUCT_NAME(_1800)); case FS_VER_18_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1800_EXFAT)); case FS_VER_18_1_0: return &(GET_OFFSET_STRUCT_NAME(_1810)); case FS_VER_18_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1810_EXFAT)); case FS_VER_19_0_0: return &(GET_OFFSET_STRUCT_NAME(_1900)); case FS_VER_19_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_1900_EXFAT)); case FS_VER_20_0_0: return &(GET_OFFSET_STRUCT_NAME(_2000)); case FS_VER_20_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_2000_EXFAT)); case FS_VER_20_1_0: return &(GET_OFFSET_STRUCT_NAME(_2010)); case FS_VER_20_1_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_2010_EXFAT)); case FS_VER_21_0_0: return &(GET_OFFSET_STRUCT_NAME(_2100)); case FS_VER_21_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_2100_EXFAT)); case FS_VER_21_2_0: return &(GET_OFFSET_STRUCT_NAME(_2120)); case FS_VER_21_2_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_2120_EXFAT)); default: fatal_abort(Fatal_UnknownVersion); } } ================================================ FILE: emummc/source/FS/FS_offsets.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_OFFSETS_H__ #define __FS_OFFSETS_H__ #include <stdint.h> #include "FS_versions.h" typedef struct { int opcode_reg; uint32_t adrp_offset; uint32_t add_rel_offset; } fs_offsets_nintendo_path_t; typedef struct { // Accessor vtable getters uintptr_t sdmmc_accessor_gc; uintptr_t sdmmc_accessor_sd; uintptr_t sdmmc_accessor_nand; // Hooks uintptr_t sdmmc_wrapper_read; uintptr_t sdmmc_wrapper_write; uintptr_t rtld; uintptr_t rtld_destination; uintptr_t clkrst_set_min_v_clock_rate; // Misc funcs uintptr_t lock_mutex; uintptr_t unlock_mutex; uintptr_t sdmmc_accessor_controller_open; uintptr_t sdmmc_accessor_controller_close; // Misc data uintptr_t sd_mutex; uintptr_t nand_mutex; uintptr_t active_partition; uintptr_t sdmmc_das_handle; // NOPs uintptr_t sd_das_init; // Nintendo Paths fs_offsets_nintendo_path_t nintendo_paths[]; } fs_offsets_t; const fs_offsets_t *get_fs_offsets(enum FS_VER version); #endif // __FS_OFFSETS_H__ ================================================ FILE: emummc/source/FS/FS_structs.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_STRUCTS_H__ #define __FS_STRUCTS_H__ #include "../utils/types.h" typedef struct { char *device_addr_buffer; uint64_t device_addr_buffer_size; char *device_addr_buffer_masked; } sdmmc_dma_buffer_t; _Static_assert(__alignof(sdmmc_dma_buffer_t) == 8, "sdmmc_dma_buffer_t definition"); typedef struct sdmmc_accessor_vt { void *ctor; void *dtor; void *map_device_addr_space; void *unmap_device_addr_space; uint64_t (*sdmmc_accessor_controller_open)(void *); uint64_t (*sdmmc_accessor_controller_close)(void *); uint64_t (*read_write)(void *, uint64_t, uint64_t, void *, uint64_t, uint64_t); // More not included because we don't use it. } sdmmc_accessor_vt_t; _Static_assert(__alignof(sdmmc_accessor_vt_t) == 8, "sdmmc_accessor_vt_t definition"); typedef struct { void *vtab; t210_sdmmc_t *io_map; sdmmc_dma_buffer_t dmaBuffers[3]; // More not included because we don't use it. } mmc_obj_t; typedef struct { sdmmc_accessor_vt_t *vtab; mmc_obj_t *parent; // More not included because we don't use it. } sdmmc_accessor_t; #endif // __FS_STRUCTS_H__ ================================================ FILE: emummc/source/FS/FS_versions.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_VERSIONS_H__ #define __FS_VERSIONS_H__ // FS Version enum enum FS_VER { FS_VER_1_0_0 = 0, FS_VER_2_0_0, FS_VER_2_0_0_EXFAT, FS_VER_2_1_0, FS_VER_2_1_0_EXFAT, FS_VER_3_0_0, FS_VER_3_0_0_EXFAT, FS_VER_3_0_1, FS_VER_3_0_1_EXFAT, FS_VER_4_0_0, FS_VER_4_0_0_EXFAT, FS_VER_4_1_0, FS_VER_4_1_0_EXFAT, FS_VER_5_0_0, FS_VER_5_0_0_EXFAT, FS_VER_5_1_0, FS_VER_5_1_0_EXFAT, FS_VER_6_0_0, FS_VER_6_0_0_EXFAT, FS_VER_7_0_0, FS_VER_7_0_0_EXFAT, FS_VER_8_0_0, FS_VER_8_0_0_EXFAT, FS_VER_8_1_0, FS_VER_8_1_0_EXFAT, FS_VER_9_0_0, FS_VER_9_0_0_EXFAT, FS_VER_9_1_0, FS_VER_9_1_0_EXFAT, FS_VER_10_0_0, FS_VER_10_0_0_EXFAT, FS_VER_10_2_0, FS_VER_10_2_0_EXFAT, FS_VER_11_0_0, FS_VER_11_0_0_EXFAT, FS_VER_12_0_0, FS_VER_12_0_0_EXFAT, FS_VER_12_0_3, FS_VER_12_0_3_EXFAT, FS_VER_13_0_0, FS_VER_13_0_0_EXFAT, FS_VER_13_1_0, FS_VER_13_1_0_EXFAT, FS_VER_14_0_0, FS_VER_14_0_0_EXFAT, FS_VER_15_0_0, FS_VER_15_0_0_EXFAT, FS_VER_16_0_0, FS_VER_16_0_0_EXFAT, FS_VER_16_0_3, FS_VER_16_0_3_EXFAT, FS_VER_17_0_0, FS_VER_17_0_0_EXFAT, FS_VER_18_0_0, FS_VER_18_0_0_EXFAT, FS_VER_18_1_0, FS_VER_18_1_0_EXFAT, FS_VER_19_0_0, FS_VER_19_0_0_EXFAT, FS_VER_20_0_0, FS_VER_20_0_0_EXFAT, FS_VER_20_1_0, FS_VER_20_1_0_EXFAT, FS_VER_21_0_0, FS_VER_21_0_0_EXFAT, FS_VER_21_2_0, FS_VER_21_2_0_EXFAT, FS_VER_MAX, }; #endif // __FS_VERSIONS_H__ ================================================ FILE: emummc/source/FS/offsets/100.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_100_H__ #define __FS_100_H__ // Accessor vtable getters #define FS_OFFSET_100_SDMMC_ACCESSOR_GC 0x6F850 #define FS_OFFSET_100_SDMMC_ACCESSOR_SD 0x6F65C #define FS_OFFSET_100_SDMMC_ACCESSOR_NAND 0x6F230 // Hooks #define FS_OFFSET_100_SDMMC_WRAPPER_READ 0x6A930 #define FS_OFFSET_100_SDMMC_WRAPPER_WRITE 0x6A9F0 #define FS_OFFSET_100_RTLD 0x534 #define FS_OFFSET_100_RTLD_DESTINATION 0xA0 #define FS_OFFSET_100_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_100_LOCK_MUTEX 0x2884 #define FS_OFFSET_100_UNLOCK_MUTEX 0x28F0 #define FS_OFFSET_100_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x6A8AC // Misc Data #define FS_OFFSET_100_SD_MUTEX 0xE36058 #define FS_OFFSET_100_NAND_MUTEX 0xE30610 #define FS_OFFSET_100_ACTIVE_PARTITION 0xE30650 #define FS_OFFSET_100_SDMMC_DAS_HANDLE 0xE2F730 // NOPs #define FS_OFFSET_100_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_100_NINTENDO_PATHS \ { \ {.opcode_reg = 8, .adrp_offset = 0x00032C58, .add_rel_offset = 8}, \ {.opcode_reg = 9, .adrp_offset = 0x00032F40, .add_rel_offset = 8}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_100_H__ ================================================ FILE: emummc/source/FS/offsets/1000.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1000_H__ #define __FS_1000_H__ // Accessor vtable getters #define FS_OFFSET_1000_SDMMC_ACCESSOR_GC 0x14DC90 #define FS_OFFSET_1000_SDMMC_ACCESSOR_SD 0x14BDA0 #define FS_OFFSET_1000_SDMMC_ACCESSOR_NAND 0x146C20 // Hooks #define FS_OFFSET_1000_SDMMC_WRAPPER_READ 0x142380 #define FS_OFFSET_1000_SDMMC_WRAPPER_WRITE 0x142460 #define FS_OFFSET_1000_RTLD 0x634 #define FS_OFFSET_1000_RTLD_DESTINATION 0x9C #define FS_OFFSET_1000_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0 // Misc funcs #define FS_OFFSET_1000_LOCK_MUTEX 0x28910 #define FS_OFFSET_1000_UNLOCK_MUTEX 0x28960 #define FS_OFFSET_1000_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_1000_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0 // Misc Data #define FS_OFFSET_1000_SD_MUTEX 0xE273E8 #define FS_OFFSET_1000_NAND_MUTEX 0xE22DA0 #define FS_OFFSET_1000_ACTIVE_PARTITION 0xE22DE0 #define FS_OFFSET_1000_SDMMC_DAS_HANDLE 0xE0AB90 // NOPs #define FS_OFFSET_1000_SD_DAS_INIT 0x151CEC // Nintendo Paths #define FS_OFFSET_1000_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1000_H__ ================================================ FILE: emummc/source/FS/offsets/1000_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1000_EXFAT_H__ #define __FS_1000_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_GC 0x14DC90 #define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_SD 0x14BDA0 #define FS_OFFSET_1000_EXFAT_SDMMC_ACCESSOR_NAND 0x146C20 // Hooks #define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_READ 0x142380 #define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_WRITE 0x142460 #define FS_OFFSET_1000_EXFAT_RTLD 0x634 #define FS_OFFSET_1000_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_1000_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1415A0 // Misc funcs #define FS_OFFSET_1000_EXFAT_LOCK_MUTEX 0x28910 #define FS_OFFSET_1000_EXFAT_UNLOCK_MUTEX 0x28960 #define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_1000_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1422E0 // Misc Data #define FS_OFFSET_1000_EXFAT_SD_MUTEX 0xE353E8 #define FS_OFFSET_1000_EXFAT_NAND_MUTEX 0xE30DA0 #define FS_OFFSET_1000_EXFAT_ACTIVE_PARTITION 0xE30DE0 #define FS_OFFSET_1000_EXFAT_SDMMC_DAS_HANDLE 0xE18B90 // NOPs #define FS_OFFSET_1000_EXFAT_SD_DAS_INIT 0x151CEC // Nintendo Paths #define FS_OFFSET_1000_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1000_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1020.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1020_H__ #define __FS_1020_H__ // Accessor vtable getters #define FS_OFFSET_1020_SDMMC_ACCESSOR_GC 0x14E0F0 #define FS_OFFSET_1020_SDMMC_ACCESSOR_SD 0x14C200 #define FS_OFFSET_1020_SDMMC_ACCESSOR_NAND 0x147080 // Hooks #define FS_OFFSET_1020_SDMMC_WRAPPER_READ 0x1427E0 #define FS_OFFSET_1020_SDMMC_WRAPPER_WRITE 0x1428C0 #define FS_OFFSET_1020_RTLD 0x634 #define FS_OFFSET_1020_RTLD_DESTINATION 0x9C #define FS_OFFSET_1020_CLKRST_SET_MIN_V_CLK_RATE 0x141A00 // Misc funcs #define FS_OFFSET_1020_LOCK_MUTEX 0x28910 #define FS_OFFSET_1020_UNLOCK_MUTEX 0x28960 #define FS_OFFSET_1020_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_1020_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x142740 // Misc Data #define FS_OFFSET_1020_SD_MUTEX 0xE273E8 #define FS_OFFSET_1020_NAND_MUTEX 0xE22DA0 #define FS_OFFSET_1020_ACTIVE_PARTITION 0xE22DE0 #define FS_OFFSET_1020_SDMMC_DAS_HANDLE 0xE0AB90 // NOPs #define FS_OFFSET_1020_SD_DAS_INIT 0x15214C // Nintendo Paths #define FS_OFFSET_1020_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1020_H__ ================================================ FILE: emummc/source/FS/offsets/1020_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1020_EXFAT_H__ #define __FS_1020_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_GC 0x14E0F0 #define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_SD 0x14C200 #define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_NAND 0x147080 // Hooks #define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_READ 0x1427E0 #define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_WRITE 0x1428C0 #define FS_OFFSET_1020_EXFAT_RTLD 0x634 #define FS_OFFSET_1020_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_1020_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x141A00 // Misc funcs #define FS_OFFSET_1020_EXFAT_LOCK_MUTEX 0x28910 #define FS_OFFSET_1020_EXFAT_UNLOCK_MUTEX 0x28960 #define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x142740 // Misc Data #define FS_OFFSET_1020_EXFAT_SD_MUTEX 0xE353E8 #define FS_OFFSET_1020_EXFAT_NAND_MUTEX 0xE30DA0 #define FS_OFFSET_1020_EXFAT_ACTIVE_PARTITION 0xE30DE0 #define FS_OFFSET_1020_EXFAT_SDMMC_DAS_HANDLE 0xE18B90 // NOPs #define FS_OFFSET_1020_EXFAT_SD_DAS_INIT 0x15214C // Nintendo Paths #define FS_OFFSET_1020_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1020_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1100.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1100_H__ #define __FS_1100_H__ // Accessor vtable getters #define FS_OFFSET_1100_SDMMC_ACCESSOR_GC 0x156D90 #define FS_OFFSET_1100_SDMMC_ACCESSOR_SD 0x154F40 #define FS_OFFSET_1100_SDMMC_ACCESSOR_NAND 0x1500F0 // Hooks #define FS_OFFSET_1100_SDMMC_WRAPPER_READ 0x14B990 #define FS_OFFSET_1100_SDMMC_WRAPPER_WRITE 0x14BA70 #define FS_OFFSET_1100_RTLD 0x688 #define FS_OFFSET_1100_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1100_CLKRST_SET_MIN_V_CLK_RATE 0x14AC40 // Misc funcs #define FS_OFFSET_1100_LOCK_MUTEX 0x28FF0 #define FS_OFFSET_1100_UNLOCK_MUTEX 0x29040 #define FS_OFFSET_1100_SDMMC_WRAPPER_CONTROLLER_OPEN 0x14B840 #define FS_OFFSET_1100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14B8F0 // Misc Data #define FS_OFFSET_1100_SD_MUTEX 0xE323E8 #define FS_OFFSET_1100_NAND_MUTEX 0xE2D338 #define FS_OFFSET_1100_ACTIVE_PARTITION 0xE2D378 #define FS_OFFSET_1100_SDMMC_DAS_HANDLE 0xE15D40 // NOPs #define FS_OFFSET_1100_SD_DAS_INIT 0x273B4 // Nintendo Paths #define FS_OFFSET_1100_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006D944, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007A3C0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00080708, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092198, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1100_H__ ================================================ FILE: emummc/source/FS/offsets/1100_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1100_EXFAT_H__ #define __FS_1100_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_GC 0x156D90 #define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_SD 0x154F40 #define FS_OFFSET_1100_EXFAT_SDMMC_ACCESSOR_NAND 0x1500F0 // Hooks #define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_READ 0x14B990 #define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_WRITE 0x14BA70 #define FS_OFFSET_1100_EXFAT_RTLD 0x688 #define FS_OFFSET_1100_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1100_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14AC40 // Misc funcs #define FS_OFFSET_1100_EXFAT_LOCK_MUTEX 0x28FF0 #define FS_OFFSET_1100_EXFAT_UNLOCK_MUTEX 0x29040 #define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x14B840 #define FS_OFFSET_1100_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14B8F0 // Misc Data #define FS_OFFSET_1100_EXFAT_SD_MUTEX 0xE403E8 #define FS_OFFSET_1100_EXFAT_NAND_MUTEX 0xE3B338 #define FS_OFFSET_1100_EXFAT_ACTIVE_PARTITION 0xE3B378 #define FS_OFFSET_1100_EXFAT_SDMMC_DAS_HANDLE 0xE23D40 // NOPs #define FS_OFFSET_1100_EXFAT_SD_DAS_INIT 0x273B4 // Nintendo Paths #define FS_OFFSET_1100_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006D944, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007A3C0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00080708, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092198, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1100_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1200.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1200_H__ #define __FS_1200_H__ // Accessor vtable getters #define FS_OFFSET_1200_SDMMC_ACCESSOR_GC 0x154FD0 #define FS_OFFSET_1200_SDMMC_ACCESSOR_SD 0x156DE0 #define FS_OFFSET_1200_SDMMC_ACCESSOR_NAND 0x155500 // Hooks #define FS_OFFSET_1200_SDMMC_WRAPPER_READ 0x150970 #define FS_OFFSET_1200_SDMMC_WRAPPER_WRITE 0x150A30 #define FS_OFFSET_1200_RTLD 0x688 #define FS_OFFSET_1200_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1200_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0 // Misc funcs #define FS_OFFSET_1200_LOCK_MUTEX 0x29350 #define FS_OFFSET_1200_UNLOCK_MUTEX 0x293A0 #define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850 #define FS_OFFSET_1200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0 // Misc Data #define FS_OFFSET_1200_SD_MUTEX 0xE3D3E8 #define FS_OFFSET_1200_NAND_MUTEX 0xE38768 #define FS_OFFSET_1200_ACTIVE_PARTITION 0xE387A8 #define FS_OFFSET_1200_SDMMC_DAS_HANDLE 0xE20DB0 // NOPs #define FS_OFFSET_1200_SD_DAS_INIT 0x27244 // Nintendo Paths #define FS_OFFSET_1200_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1200_H__ ================================================ FILE: emummc/source/FS/offsets/1200_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1200_EXFAT_H__ #define __FS_1200_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_GC 0x154FD0 #define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_SD 0x156DE0 #define FS_OFFSET_1200_EXFAT_SDMMC_ACCESSOR_NAND 0x155500 // Hooks #define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_READ 0x150970 #define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_WRITE 0x150A30 #define FS_OFFSET_1200_EXFAT_RTLD 0x688 #define FS_OFFSET_1200_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14FCC0 // Misc funcs #define FS_OFFSET_1200_EXFAT_LOCK_MUTEX 0x29350 #define FS_OFFSET_1200_EXFAT_UNLOCK_MUTEX 0x293A0 #define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150850 #define FS_OFFSET_1200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1508E0 // Misc Data #define FS_OFFSET_1200_EXFAT_SD_MUTEX 0xE4B3E8 #define FS_OFFSET_1200_EXFAT_NAND_MUTEX 0xE46768 #define FS_OFFSET_1200_EXFAT_ACTIVE_PARTITION 0xE467A8 #define FS_OFFSET_1200_EXFAT_SDMMC_DAS_HANDLE 0xE2EDB0 // NOPs #define FS_OFFSET_1200_EXFAT_SD_DAS_INIT 0x27244 // Nintendo Paths #define FS_OFFSET_1200_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006E810, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AEC0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00081254, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092850, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1200_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1203.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * Copyright (c) 2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1203_H__ #define __FS_1203_H__ // Accessor vtable getters #define FS_OFFSET_1203_SDMMC_ACCESSOR_GC 0x1550E0 #define FS_OFFSET_1203_SDMMC_ACCESSOR_SD 0x156EF0 #define FS_OFFSET_1203_SDMMC_ACCESSOR_NAND 0x155610 // Hooks #define FS_OFFSET_1203_SDMMC_WRAPPER_READ 0x150A80 #define FS_OFFSET_1203_SDMMC_WRAPPER_WRITE 0x150B40 #define FS_OFFSET_1203_RTLD 0x688 #define FS_OFFSET_1203_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1203_CLKRST_SET_MIN_V_CLK_RATE 0x14FDD0 // Misc funcs #define FS_OFFSET_1203_LOCK_MUTEX 0x29350 #define FS_OFFSET_1203_UNLOCK_MUTEX 0x293A0 #define FS_OFFSET_1203_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150960 #define FS_OFFSET_1203_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1509F0 // Misc Data #define FS_OFFSET_1203_SD_MUTEX 0xE3D3E8 #define FS_OFFSET_1203_NAND_MUTEX 0xE38768 #define FS_OFFSET_1203_ACTIVE_PARTITION 0xE387A8 #define FS_OFFSET_1203_SDMMC_DAS_HANDLE 0xE20DB0 // NOPs #define FS_OFFSET_1203_SD_DAS_INIT 0x27244 // Nintendo Paths #define FS_OFFSET_1203_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006E920, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AFD0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00081364, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092960, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1203_H__ ================================================ FILE: emummc/source/FS/offsets/1203_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * Copyright (c) 2021 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1203_EXFAT_H__ #define __FS_1203_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1203_EXFAT_SDMMC_ACCESSOR_GC 0x1550E0 #define FS_OFFSET_1203_EXFAT_SDMMC_ACCESSOR_SD 0x156EF0 #define FS_OFFSET_1203_EXFAT_SDMMC_ACCESSOR_NAND 0x155610 // Hooks #define FS_OFFSET_1203_EXFAT_SDMMC_WRAPPER_READ 0x150A80 #define FS_OFFSET_1203_EXFAT_SDMMC_WRAPPER_WRITE 0x150B40 #define FS_OFFSET_1203_EXFAT_RTLD 0x688 #define FS_OFFSET_1203_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1203_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x14FDD0 // Misc funcs #define FS_OFFSET_1203_EXFAT_LOCK_MUTEX 0x29350 #define FS_OFFSET_1203_EXFAT_UNLOCK_MUTEX 0x293A0 #define FS_OFFSET_1203_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x150960 #define FS_OFFSET_1203_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1509F0 // Misc Data #define FS_OFFSET_1203_EXFAT_SD_MUTEX 0xE4B3E8 #define FS_OFFSET_1203_EXFAT_NAND_MUTEX 0xE46768 #define FS_OFFSET_1203_EXFAT_ACTIVE_PARTITION 0xE467A8 #define FS_OFFSET_1203_EXFAT_SDMMC_DAS_HANDLE 0xE2EDB0 // NOPs #define FS_OFFSET_1203_EXFAT_SD_DAS_INIT 0x27244 // Nintendo Paths #define FS_OFFSET_1203_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006E920, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AFD0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00081364, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092960, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1203_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1300.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1300_H__ #define __FS_1300_H__ // Accessor vtable getters #define FS_OFFSET_1300_SDMMC_ACCESSOR_GC 0x158C80 #define FS_OFFSET_1300_SDMMC_ACCESSOR_SD 0x15AA90 #define FS_OFFSET_1300_SDMMC_ACCESSOR_NAND 0x1591B0 // Hooks #define FS_OFFSET_1300_SDMMC_WRAPPER_READ 0x154620 #define FS_OFFSET_1300_SDMMC_WRAPPER_WRITE 0x1546E0 #define FS_OFFSET_1300_RTLD 0x688 #define FS_OFFSET_1300_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1300_CLKRST_SET_MIN_V_CLK_RATE 0x153820 // Misc funcs #define FS_OFFSET_1300_LOCK_MUTEX 0x29690 #define FS_OFFSET_1300_UNLOCK_MUTEX 0x296E0 #define FS_OFFSET_1300_SDMMC_WRAPPER_CONTROLLER_OPEN 0x154500 #define FS_OFFSET_1300_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154590 // Misc Data #define FS_OFFSET_1300_SD_MUTEX 0xE133E8 #define FS_OFFSET_1300_NAND_MUTEX 0xE0E768 #define FS_OFFSET_1300_ACTIVE_PARTITION 0xE0E7A8 #define FS_OFFSET_1300_SDMMC_DAS_HANDLE 0xDF6E18 // NOPs #define FS_OFFSET_1300_SD_DAS_INIT 0x27744 // Nintendo Paths #define FS_OFFSET_1300_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1300_H__ ================================================ FILE: emummc/source/FS/offsets/1300_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1300_EXFAT_H__ #define __FS_1300_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1300_EXFAT_SDMMC_ACCESSOR_GC 0x158C80 #define FS_OFFSET_1300_EXFAT_SDMMC_ACCESSOR_SD 0x15AA90 #define FS_OFFSET_1300_EXFAT_SDMMC_ACCESSOR_NAND 0x1591B0 // Hooks #define FS_OFFSET_1300_EXFAT_SDMMC_WRAPPER_READ 0x154620 #define FS_OFFSET_1300_EXFAT_SDMMC_WRAPPER_WRITE 0x1546E0 #define FS_OFFSET_1300_EXFAT_RTLD 0x688 #define FS_OFFSET_1300_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1300_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x153820 // Misc funcs #define FS_OFFSET_1300_EXFAT_LOCK_MUTEX 0x29690 #define FS_OFFSET_1300_EXFAT_UNLOCK_MUTEX 0x296E0 #define FS_OFFSET_1300_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x154500 #define FS_OFFSET_1300_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154590 // Misc Data #define FS_OFFSET_1300_EXFAT_SD_MUTEX 0xE203E8 #define FS_OFFSET_1300_EXFAT_NAND_MUTEX 0xE1B768 #define FS_OFFSET_1300_EXFAT_ACTIVE_PARTITION 0xE1B7A8 #define FS_OFFSET_1300_EXFAT_SDMMC_DAS_HANDLE 0xE03E18 // NOPs #define FS_OFFSET_1300_EXFAT_SD_DAS_INIT 0x27744 // Nintendo Paths #define FS_OFFSET_1300_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1300_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1310.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1310_H__ #define __FS_1310_H__ // Accessor vtable getters #define FS_OFFSET_1310_SDMMC_ACCESSOR_GC 0x158C20 #define FS_OFFSET_1310_SDMMC_ACCESSOR_SD 0x15AA30 #define FS_OFFSET_1310_SDMMC_ACCESSOR_NAND 0x159150 // Hooks #define FS_OFFSET_1310_SDMMC_WRAPPER_READ 0x1545C0 #define FS_OFFSET_1310_SDMMC_WRAPPER_WRITE 0x154680 #define FS_OFFSET_1310_RTLD 0x688 #define FS_OFFSET_1310_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1310_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0 // Misc funcs #define FS_OFFSET_1310_LOCK_MUTEX 0x29690 #define FS_OFFSET_1310_UNLOCK_MUTEX 0x296E0 #define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0 #define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530 // Misc Data #define FS_OFFSET_1310_SD_MUTEX 0xE133E8 #define FS_OFFSET_1310_NAND_MUTEX 0xE0E768 #define FS_OFFSET_1310_ACTIVE_PARTITION 0xE0E7A8 #define FS_OFFSET_1310_SDMMC_DAS_HANDLE 0xDF6E18 // NOPs #define FS_OFFSET_1310_SD_DAS_INIT 0x27744 // Nintendo Paths #define FS_OFFSET_1310_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1310_H__ ================================================ FILE: emummc/source/FS/offsets/1310_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1310_EXFAT_H__ #define __FS_1310_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_GC 0x158C20 #define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_SD 0x15AA30 #define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_NAND 0x159150 // Hooks #define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_READ 0x1545C0 #define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_WRITE 0x154680 #define FS_OFFSET_1310_EXFAT_RTLD 0x688 #define FS_OFFSET_1310_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1310_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0 // Misc funcs #define FS_OFFSET_1310_EXFAT_LOCK_MUTEX 0x29690 #define FS_OFFSET_1310_EXFAT_UNLOCK_MUTEX 0x296E0 #define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0 #define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530 // Misc Data #define FS_OFFSET_1310_EXFAT_SD_MUTEX 0xE203E8 #define FS_OFFSET_1310_EXFAT_NAND_MUTEX 0xE1B768 #define FS_OFFSET_1310_EXFAT_ACTIVE_PARTITION 0xE1B7A8 #define FS_OFFSET_1310_EXFAT_SDMMC_DAS_HANDLE 0xE03E18 // NOPs #define FS_OFFSET_1310_EXFAT_SD_DAS_INIT 0x27744 // Nintendo Paths #define FS_OFFSET_1310_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1310_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1400.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1400_H__ #define __FS_1400_H__ // Accessor vtable getters #define FS_OFFSET_1400_SDMMC_ACCESSOR_GC 0x189F50 #define FS_OFFSET_1400_SDMMC_ACCESSOR_SD 0x18BD60 #define FS_OFFSET_1400_SDMMC_ACCESSOR_NAND 0x18A480 // Hooks #define FS_OFFSET_1400_SDMMC_WRAPPER_READ 0x185AF0 #define FS_OFFSET_1400_SDMMC_WRAPPER_WRITE 0x185B50 #define FS_OFFSET_1400_RTLD 0x282B8 #define FS_OFFSET_1400_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1400_CLKRST_SET_MIN_V_CLK_RATE 0x1A5D90 // Misc funcs #define FS_OFFSET_1400_LOCK_MUTEX 0x17E9F0 #define FS_OFFSET_1400_UNLOCK_MUTEX 0x17EA40 #define FS_OFFSET_1400_SDMMC_WRAPPER_CONTROLLER_OPEN 0x185AA0 #define FS_OFFSET_1400_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x185AD0 // Misc Data #define FS_OFFSET_1400_SD_MUTEX 0xF2E3F0 #define FS_OFFSET_1400_NAND_MUTEX 0xF292F8 #define FS_OFFSET_1400_ACTIVE_PARTITION 0xF29338 #define FS_OFFSET_1400_SDMMC_DAS_HANDLE 0xDFE9C8 // NOPs #define FS_OFFSET_1400_SD_DAS_INIT 0x27004 // Nintendo Paths #define FS_OFFSET_1400_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006D9C0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AC24, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000813E8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009387C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1400_H__ ================================================ FILE: emummc/source/FS/offsets/1400_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1400_EXFAT_H__ #define __FS_1400_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1400_EXFAT_SDMMC_ACCESSOR_GC 0x1952D0 #define FS_OFFSET_1400_EXFAT_SDMMC_ACCESSOR_SD 0x1970E0 #define FS_OFFSET_1400_EXFAT_SDMMC_ACCESSOR_NAND 0x195800 // Hooks #define FS_OFFSET_1400_EXFAT_SDMMC_WRAPPER_READ 0x190E70 #define FS_OFFSET_1400_EXFAT_SDMMC_WRAPPER_WRITE 0x190ED0 #define FS_OFFSET_1400_EXFAT_RTLD 0x282B8 #define FS_OFFSET_1400_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1400_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B1110 // Misc funcs #define FS_OFFSET_1400_EXFAT_LOCK_MUTEX 0x189D70 #define FS_OFFSET_1400_EXFAT_UNLOCK_MUTEX 0x189DC0 #define FS_OFFSET_1400_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x190E20 #define FS_OFFSET_1400_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x190E50 // Misc Data #define FS_OFFSET_1400_EXFAT_SD_MUTEX 0x10123F0 #define FS_OFFSET_1400_EXFAT_NAND_MUTEX 0x100D2F8 #define FS_OFFSET_1400_EXFAT_ACTIVE_PARTITION 0x100D338 #define FS_OFFSET_1400_EXFAT_SDMMC_DAS_HANDLE 0xE0B9C8 // NOPs #define FS_OFFSET_1400_EXFAT_SD_DAS_INIT 0x27004 // Nintendo Paths #define FS_OFFSET_1400_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006D9C0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AC24, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000813E8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009387C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1400_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1500.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1500_H__ #define __FS_1500_H__ // Accessor vtable getters #define FS_OFFSET_1500_SDMMC_ACCESSOR_GC 0x183E20 #define FS_OFFSET_1500_SDMMC_ACCESSOR_SD 0x185AA0 #define FS_OFFSET_1500_SDMMC_ACCESSOR_NAND 0x1842E0 // Hooks #define FS_OFFSET_1500_SDMMC_WRAPPER_READ 0x17FCF0 #define FS_OFFSET_1500_SDMMC_WRAPPER_WRITE 0x17FD50 #define FS_OFFSET_1500_RTLD 0x26518 #define FS_OFFSET_1500_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1500_CLKRST_SET_MIN_V_CLK_RATE 0x1A0870 // Misc funcs #define FS_OFFSET_1500_LOCK_MUTEX 0x1791A0 #define FS_OFFSET_1500_UNLOCK_MUTEX 0x1791F0 #define FS_OFFSET_1500_SDMMC_WRAPPER_CONTROLLER_OPEN 0x17FCB0 #define FS_OFFSET_1500_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x17FCD0 // Misc Data #define FS_OFFSET_1500_SD_MUTEX 0xFF33F0 #define FS_OFFSET_1500_NAND_MUTEX 0xFEE2E8 #define FS_OFFSET_1500_ACTIVE_PARTITION 0xFEE328 #define FS_OFFSET_1500_SDMMC_DAS_HANDLE 0xFD38D8 // NOPs #define FS_OFFSET_1500_SD_DAS_INIT 0x25454 // Nintendo Paths #define FS_OFFSET_1500_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063050, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0006FDE8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000768D4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00089364, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1500_H__ ================================================ FILE: emummc/source/FS/offsets/1500_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1500_EXFAT_H__ #define __FS_1500_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_GC 0x18EDB0 #define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_SD 0x190A30 #define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_NAND 0x18F270 // Hooks #define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_READ 0x18AC80 #define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_WRITE 0x18ACE0 #define FS_OFFSET_1500_EXFAT_RTLD 0x26518 #define FS_OFFSET_1500_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1500_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1AB800 // Misc funcs #define FS_OFFSET_1500_EXFAT_LOCK_MUTEX 0x184130 #define FS_OFFSET_1500_EXFAT_UNLOCK_MUTEX 0x184180 #define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18AC40 #define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18AC60 // Misc Data #define FS_OFFSET_1500_EXFAT_SD_MUTEX 0x10053F0 #define FS_OFFSET_1500_EXFAT_NAND_MUTEX 0x10002E8 #define FS_OFFSET_1500_EXFAT_ACTIVE_PARTITION 0x1000328 #define FS_OFFSET_1500_EXFAT_SDMMC_DAS_HANDLE 0xFE08D8 // NOPs #define FS_OFFSET_1500_EXFAT_SD_DAS_INIT 0x25454 // Nintendo Paths #define FS_OFFSET_1500_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063050, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0006FDE8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000768D4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00089364, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1500_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1600.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1600_H__ #define __FS_1600_H__ // Accessor vtable getters #define FS_OFFSET_1600_SDMMC_ACCESSOR_GC 0x1862A0 #define FS_OFFSET_1600_SDMMC_ACCESSOR_SD 0x187F20 #define FS_OFFSET_1600_SDMMC_ACCESSOR_NAND 0x186760 // Hooks #define FS_OFFSET_1600_SDMMC_WRAPPER_READ 0x1821F0 #define FS_OFFSET_1600_SDMMC_WRAPPER_WRITE 0x182250 #define FS_OFFSET_1600_RTLD 0x269B0 #define FS_OFFSET_1600_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1600_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D30 // Misc funcs #define FS_OFFSET_1600_LOCK_MUTEX 0x17B730 #define FS_OFFSET_1600_UNLOCK_MUTEX 0x17B780 #define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1821B0 #define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1821D0 // Misc Data #define FS_OFFSET_1600_SD_MUTEX 0xFFB3F0 #define FS_OFFSET_1600_NAND_MUTEX 0xFF6B58 #define FS_OFFSET_1600_ACTIVE_PARTITION 0xFF6B98 #define FS_OFFSET_1600_SDMMC_DAS_HANDLE 0xFDC8B0 // NOPs #define FS_OFFSET_1600_SD_DAS_INIT 0x258D4 // Nintendo Paths #define FS_OFFSET_1600_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1600_H__ ================================================ FILE: emummc/source/FS/offsets/1600_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1600_EXFAT_H__ #define __FS_1600_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_GC 0x190F80 #define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_SD 0x192C00 #define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_NAND 0x191440 // Hooks #define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_READ 0x18CED0 #define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF30 #define FS_OFFSET_1600_EXFAT_RTLD 0x269B0 #define FS_OFFSET_1600_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1600_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA10 // Misc funcs #define FS_OFFSET_1600_EXFAT_LOCK_MUTEX 0x186410 #define FS_OFFSET_1600_EXFAT_UNLOCK_MUTEX 0x186460 #define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CE90 #define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CEB0 // Misc Data #define FS_OFFSET_1600_EXFAT_SD_MUTEX 0x100D3F0 #define FS_OFFSET_1600_EXFAT_NAND_MUTEX 0x1008B58 #define FS_OFFSET_1600_EXFAT_ACTIVE_PARTITION 0x1008B98 #define FS_OFFSET_1600_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0 // NOPs #define FS_OFFSET_1600_EXFAT_SD_DAS_INIT 0x258D4 // Nintendo Paths #define FS_OFFSET_1600_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1600_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1603.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1603_H__ #define __FS_1603_H__ // Accessor vtable getters #define FS_OFFSET_1603_SDMMC_ACCESSOR_GC 0x1862F0 #define FS_OFFSET_1603_SDMMC_ACCESSOR_SD 0x187F70 #define FS_OFFSET_1603_SDMMC_ACCESSOR_NAND 0x1867B0 // Hooks #define FS_OFFSET_1603_SDMMC_WRAPPER_READ 0x182240 #define FS_OFFSET_1603_SDMMC_WRAPPER_WRITE 0x1822A0 #define FS_OFFSET_1603_RTLD 0x269B0 #define FS_OFFSET_1603_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1603_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D80 // Misc funcs #define FS_OFFSET_1603_LOCK_MUTEX 0x17B780 #define FS_OFFSET_1603_UNLOCK_MUTEX 0x17B7D0 #define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_OPEN 0x182200 #define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x182220 // Misc Data #define FS_OFFSET_1603_SD_MUTEX 0xFFB3F0 #define FS_OFFSET_1603_NAND_MUTEX 0xFF6B58 #define FS_OFFSET_1603_ACTIVE_PARTITION 0xFF6B98 #define FS_OFFSET_1603_SDMMC_DAS_HANDLE 0xFDC8B0 // NOPs #define FS_OFFSET_1603_SD_DAS_INIT 0x258D4 // Nintendo Paths #define FS_OFFSET_1603_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1603_H__ ================================================ FILE: emummc/source/FS/offsets/1603_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1603_EXFAT_H__ #define __FS_1603_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_GC 0x190FD0 #define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_SD 0x192C50 #define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_NAND 0x191490 // Hooks #define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_READ 0x18CF20 #define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF80 #define FS_OFFSET_1603_EXFAT_RTLD 0x269B0 #define FS_OFFSET_1603_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1603_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA60 // Misc funcs #define FS_OFFSET_1603_EXFAT_LOCK_MUTEX 0x186460 #define FS_OFFSET_1603_EXFAT_UNLOCK_MUTEX 0x1864B0 #define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CEE0 #define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CF00 // Misc Data #define FS_OFFSET_1603_EXFAT_SD_MUTEX 0x100D3F0 #define FS_OFFSET_1603_EXFAT_NAND_MUTEX 0x1008B58 #define FS_OFFSET_1603_EXFAT_ACTIVE_PARTITION 0x1008B98 #define FS_OFFSET_1603_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0 // NOPs #define FS_OFFSET_1603_EXFAT_SD_DAS_INIT 0x258D4 // Nintendo Paths #define FS_OFFSET_1603_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1603_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1700.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1700_H__ #define __FS_1700_H__ // Accessor vtable getters #define FS_OFFSET_1700_SDMMC_ACCESSOR_GC 0x18AD00 #define FS_OFFSET_1700_SDMMC_ACCESSOR_SD 0x18C9D0 #define FS_OFFSET_1700_SDMMC_ACCESSOR_NAND 0x18B1D0 // Hooks #define FS_OFFSET_1700_SDMMC_WRAPPER_READ 0x186BC0 #define FS_OFFSET_1700_SDMMC_WRAPPER_WRITE 0x186C20 #define FS_OFFSET_1700_RTLD 0x29D10 #define FS_OFFSET_1700_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1700_CLKRST_SET_MIN_V_CLK_RATE 0x1A7B60 // Misc funcs #define FS_OFFSET_1700_LOCK_MUTEX 0x17FEA0 #define FS_OFFSET_1700_UNLOCK_MUTEX 0x17FEF0 #define FS_OFFSET_1700_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186B80 #define FS_OFFSET_1700_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186BA0 // Misc Data #define FS_OFFSET_1700_SD_MUTEX 0xFCE3F0 #define FS_OFFSET_1700_NAND_MUTEX 0xFC9B78 #define FS_OFFSET_1700_ACTIVE_PARTITION 0xFC9BB8 #define FS_OFFSET_1700_SDMMC_DAS_HANDLE 0xFAF840 // NOPs #define FS_OFFSET_1700_SD_DAS_INIT 0x28C64 // Nintendo Paths #define FS_OFFSET_1700_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068068, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007510C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007BEAC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008F674, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1700_H__ ================================================ FILE: emummc/source/FS/offsets/1700_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1700_EXFAT_H__ #define __FS_1700_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_GC 0x195B60 #define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_SD 0x197830 #define FS_OFFSET_1700_EXFAT_SDMMC_ACCESSOR_NAND 0x196030 // Hooks #define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_READ 0x191A20 #define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_WRITE 0x191A80 #define FS_OFFSET_1700_EXFAT_RTLD 0x29D10 #define FS_OFFSET_1700_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C))) #define FS_OFFSET_1700_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B29C0 // Misc funcs #define FS_OFFSET_1700_EXFAT_LOCK_MUTEX 0x18AD00 #define FS_OFFSET_1700_EXFAT_UNLOCK_MUTEX 0x18AD50 #define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1919E0 #define FS_OFFSET_1700_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191A00 // Misc Data #define FS_OFFSET_1700_EXFAT_SD_MUTEX 0xFE03F0 #define FS_OFFSET_1700_EXFAT_NAND_MUTEX 0xFDBB78 #define FS_OFFSET_1700_EXFAT_ACTIVE_PARTITION 0xFDBBB8 #define FS_OFFSET_1700_EXFAT_SDMMC_DAS_HANDLE 0xFBC840 // NOPs #define FS_OFFSET_1700_EXFAT_SD_DAS_INIT 0x28C64 // Nintendo Paths #define FS_OFFSET_1700_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068068, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007510C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007BEAC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008F674, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1700_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1800.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1800_H__ #define __FS_1800_H__ // Accessor vtable getters #define FS_OFFSET_1800_SDMMC_ACCESSOR_GC 0x18AB00 #define FS_OFFSET_1800_SDMMC_ACCESSOR_SD 0x18C800 #define FS_OFFSET_1800_SDMMC_ACCESSOR_NAND 0x18AFE0 // Hooks #define FS_OFFSET_1800_SDMMC_WRAPPER_READ 0x186A50 #define FS_OFFSET_1800_SDMMC_WRAPPER_WRITE 0x186AB0 #define FS_OFFSET_1800_RTLD 0x2A3A4 #define FS_OFFSET_1800_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44))) #define FS_OFFSET_1800_CLKRST_SET_MIN_V_CLK_RATE 0x1A77D0 // Misc funcs #define FS_OFFSET_1800_LOCK_MUTEX 0x17FCC0 #define FS_OFFSET_1800_UNLOCK_MUTEX 0x17FD10 #define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186A10 #define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186A30 // Misc Data #define FS_OFFSET_1800_SD_MUTEX 0xFD13F0 #define FS_OFFSET_1800_NAND_MUTEX 0xFCCB28 #define FS_OFFSET_1800_ACTIVE_PARTITION 0xFCCB68 #define FS_OFFSET_1800_SDMMC_DAS_HANDLE 0xFB1950 // NOPs #define FS_OFFSET_1800_SD_DAS_INIT 0x28F24 // Nintendo Paths #define FS_OFFSET_1800_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1800_H__ ================================================ FILE: emummc/source/FS/offsets/1800_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1800_EXFAT_H__ #define __FS_1800_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_GC 0x195B90 #define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_SD 0x197890 #define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_NAND 0x196070 // Hooks #define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_READ 0x191AE0 #define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_WRITE 0x191B40 #define FS_OFFSET_1800_EXFAT_RTLD 0x2A3A4 #define FS_OFFSET_1800_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44))) #define FS_OFFSET_1800_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B2860 // Misc funcs #define FS_OFFSET_1800_EXFAT_LOCK_MUTEX 0x18AD50 #define FS_OFFSET_1800_EXFAT_UNLOCK_MUTEX 0x18ADA0 #define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191AA0 #define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191AC0 // Misc Data #define FS_OFFSET_1800_EXFAT_SD_MUTEX 0xFE33F0 #define FS_OFFSET_1800_EXFAT_NAND_MUTEX 0xFDEB28 #define FS_OFFSET_1800_EXFAT_ACTIVE_PARTITION 0xFDEB68 #define FS_OFFSET_1800_EXFAT_SDMMC_DAS_HANDLE 0xFBE950 // NOPs #define FS_OFFSET_1800_EXFAT_SD_DAS_INIT 0x28F24 // Nintendo Paths #define FS_OFFSET_1800_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1800_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1810.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1810_H__ #define __FS_1810_H__ // Accessor vtable getters #define FS_OFFSET_1810_SDMMC_ACCESSOR_GC 0x18AB00 #define FS_OFFSET_1810_SDMMC_ACCESSOR_SD 0x18C800 #define FS_OFFSET_1810_SDMMC_ACCESSOR_NAND 0x18AFE0 // Hooks #define FS_OFFSET_1810_SDMMC_WRAPPER_READ 0x186A50 #define FS_OFFSET_1810_SDMMC_WRAPPER_WRITE 0x186AB0 #define FS_OFFSET_1810_RTLD 0x2A3A4 #define FS_OFFSET_1810_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44))) #define FS_OFFSET_1810_CLKRST_SET_MIN_V_CLK_RATE 0x1A77D0 // Misc funcs #define FS_OFFSET_1810_LOCK_MUTEX 0x17FCC0 #define FS_OFFSET_1810_UNLOCK_MUTEX 0x17FD10 #define FS_OFFSET_1810_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186A10 #define FS_OFFSET_1810_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186A30 // Misc Data #define FS_OFFSET_1810_SD_MUTEX 0xFD13F0 #define FS_OFFSET_1810_NAND_MUTEX 0xFCCB28 #define FS_OFFSET_1810_ACTIVE_PARTITION 0xFCCB68 #define FS_OFFSET_1810_SDMMC_DAS_HANDLE 0xFB1950 // NOPs #define FS_OFFSET_1810_SD_DAS_INIT 0x28F24 // Nintendo Paths #define FS_OFFSET_1810_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1810_H__ ================================================ FILE: emummc/source/FS/offsets/1810_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1810_EXFAT_H__ #define __FS_1810_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_GC 0x195B90 #define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_SD 0x197890 #define FS_OFFSET_1810_EXFAT_SDMMC_ACCESSOR_NAND 0x196070 // Hooks #define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_READ 0x191AE0 #define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_WRITE 0x191B40 #define FS_OFFSET_1810_EXFAT_RTLD 0x2A3A4 #define FS_OFFSET_1810_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44))) #define FS_OFFSET_1810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B2860 // Misc funcs #define FS_OFFSET_1810_EXFAT_LOCK_MUTEX 0x18AD50 #define FS_OFFSET_1810_EXFAT_UNLOCK_MUTEX 0x18ADA0 #define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191AA0 #define FS_OFFSET_1810_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191AC0 // Misc Data #define FS_OFFSET_1810_EXFAT_SD_MUTEX 0xFE33F0 #define FS_OFFSET_1810_EXFAT_NAND_MUTEX 0xFDEB28 #define FS_OFFSET_1810_EXFAT_ACTIVE_PARTITION 0xFDEB68 #define FS_OFFSET_1810_EXFAT_SDMMC_DAS_HANDLE 0xFBE950 // NOPs #define FS_OFFSET_1810_EXFAT_SD_DAS_INIT 0x28F24 // Nintendo Paths #define FS_OFFSET_1810_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1810_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/1900.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1900_H__ #define __FS_1900_H__ // Accessor vtable getters #define FS_OFFSET_1900_SDMMC_ACCESSOR_GC 0x195C00 #define FS_OFFSET_1900_SDMMC_ACCESSOR_SD 0x197F80 #define FS_OFFSET_1900_SDMMC_ACCESSOR_NAND 0x1963B0 // Hooks #define FS_OFFSET_1900_SDMMC_WRAPPER_READ 0x191A70 #define FS_OFFSET_1900_SDMMC_WRAPPER_WRITE 0x191AD0 #define FS_OFFSET_1900_RTLD 0x275F0 #define FS_OFFSET_1900_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x50))) #define FS_OFFSET_1900_CLKRST_SET_MIN_V_CLK_RATE 0x1B3880 // Misc funcs #define FS_OFFSET_1900_LOCK_MUTEX 0x18AC20 #define FS_OFFSET_1900_UNLOCK_MUTEX 0x18AC70 #define FS_OFFSET_1900_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191A30 #define FS_OFFSET_1900_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191A50 // Misc Data #define FS_OFFSET_1900_SD_MUTEX 0xFE1408 #define FS_OFFSET_1900_NAND_MUTEX 0xFDCB60 #define FS_OFFSET_1900_ACTIVE_PARTITION 0xFDCBA0 #define FS_OFFSET_1900_SDMMC_DAS_HANDLE 0xFC1908 // NOPs #define FS_OFFSET_1900_SD_DAS_INIT 0x260C4 // Nintendo Paths #define FS_OFFSET_1900_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00067FC8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00075D6C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007D1E8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092818, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1900_H__ ================================================ FILE: emummc/source/FS/offsets/1900_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_1900_EXFAT_H__ #define __FS_1900_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_GC 0x1A1430 #define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_SD 0x1A37B0 #define FS_OFFSET_1900_EXFAT_SDMMC_ACCESSOR_NAND 0x1A1BE0 // Hooks #define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_READ 0x19D2A0 #define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_WRITE 0x19D300 #define FS_OFFSET_1900_EXFAT_RTLD 0x275F0 #define FS_OFFSET_1900_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x50))) #define FS_OFFSET_1900_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1BF0B0 // Misc funcs #define FS_OFFSET_1900_EXFAT_LOCK_MUTEX 0x196450 #define FS_OFFSET_1900_EXFAT_UNLOCK_MUTEX 0x1964A0 #define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x19D260 #define FS_OFFSET_1900_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x19D280 // Misc Data #define FS_OFFSET_1900_EXFAT_SD_MUTEX 0xFF4408 #define FS_OFFSET_1900_EXFAT_NAND_MUTEX 0xFEFB60 #define FS_OFFSET_1900_EXFAT_ACTIVE_PARTITION 0xFEFBA0 #define FS_OFFSET_1900_EXFAT_SDMMC_DAS_HANDLE 0xFCF908 // NOPs #define FS_OFFSET_1900_EXFAT_SD_DAS_INIT 0x260C4 // Nintendo Paths #define FS_OFFSET_1900_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00067FC8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00075D6C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0007D1E8, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00092818, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_1900_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/200.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_200_H__ #define __FS_200_H__ // Accessor vtable getters #define FS_OFFSET_200_SDMMC_ACCESSOR_GC 0x78BAC #define FS_OFFSET_200_SDMMC_ACCESSOR_SD 0x7894C #define FS_OFFSET_200_SDMMC_ACCESSOR_NAND 0x784BC // Hooks #define FS_OFFSET_200_SDMMC_WRAPPER_READ 0x73478 #define FS_OFFSET_200_SDMMC_WRAPPER_WRITE 0x73538 #define FS_OFFSET_200_RTLD 0x500 #define FS_OFFSET_200_RTLD_DESTINATION 0x98 #define FS_OFFSET_200_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_200_LOCK_MUTEX 0x3264 #define FS_OFFSET_200_UNLOCK_MUTEX 0x32D0 #define FS_OFFSET_200_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x733F4 // Misc Data #define FS_OFFSET_200_SD_MUTEX 0xE42268 #define FS_OFFSET_200_NAND_MUTEX 0xE3CED0 #define FS_OFFSET_200_ACTIVE_PARTITION 0xE3CF10 #define FS_OFFSET_200_SDMMC_DAS_HANDLE 0xE3BDD0 // NOPs #define FS_OFFSET_200_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_200_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00033F08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00035084, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003537C, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_200_H__ ================================================ FILE: emummc/source/FS/offsets/2000.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2000_H__ #define __FS_2000_H__ // Accessor vtable getters #define FS_OFFSET_2000_SDMMC_ACCESSOR_GC 0x1A7DB0 #define FS_OFFSET_2000_SDMMC_ACCESSOR_SD 0x1AA130 #define FS_OFFSET_2000_SDMMC_ACCESSOR_NAND 0x1A8560 // Hooks #define FS_OFFSET_2000_SDMMC_WRAPPER_READ 0x1A3C20 #define FS_OFFSET_2000_SDMMC_WRAPPER_WRITE 0x1A3C80 #define FS_OFFSET_2000_RTLD 0x2B594 #define FS_OFFSET_2000_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2000_CLKRST_SET_MIN_V_CLK_RATE 0x1C6150 // Misc funcs #define FS_OFFSET_2000_LOCK_MUTEX 0x19CD80 #define FS_OFFSET_2000_UNLOCK_MUTEX 0x19CDD0 #define FS_OFFSET_2000_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A3BE0 #define FS_OFFSET_2000_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A3C00 // Misc Data #define FS_OFFSET_2000_SD_MUTEX 0xFF5408 #define FS_OFFSET_2000_NAND_MUTEX 0xFF0CF0 #define FS_OFFSET_2000_ACTIVE_PARTITION 0xFF0D30 #define FS_OFFSET_2000_SDMMC_DAS_HANDLE 0xFD2B08 // NOPs #define FS_OFFSET_2000_SD_DAS_INIT 0x289F4 // Nintendo Paths #define FS_OFFSET_2000_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2000_H__ ================================================ FILE: emummc/source/FS/offsets/2000_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2000_EXFAT_H__ #define __FS_2000_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_GC 0x1B36D0 #define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_SD 0x1B5A50 #define FS_OFFSET_2000_EXFAT_SDMMC_ACCESSOR_NAND 0x1B3E80 // Hooks #define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_READ 0x1AF540 #define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_WRITE 0x1AF5A0 #define FS_OFFSET_2000_EXFAT_RTLD 0x2B594 #define FS_OFFSET_2000_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2000_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D1A70 // Misc funcs #define FS_OFFSET_2000_EXFAT_LOCK_MUTEX 0x1A86A0 #define FS_OFFSET_2000_EXFAT_UNLOCK_MUTEX 0x1A86F0 #define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AF500 #define FS_OFFSET_2000_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AF520 // Misc Data #define FS_OFFSET_2000_EXFAT_SD_MUTEX 0x1006408 #define FS_OFFSET_2000_EXFAT_NAND_MUTEX 0x1001CF0 #define FS_OFFSET_2000_EXFAT_ACTIVE_PARTITION 0x1001D30 #define FS_OFFSET_2000_EXFAT_SDMMC_DAS_HANDLE 0xFDFB08 // NOPs #define FS_OFFSET_2000_EXFAT_SD_DAS_INIT 0x289F4 // Nintendo Paths #define FS_OFFSET_2000_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2000_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/200_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_200_EXFAT_H__ #define __FS_200_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_200_EXFAT_SDMMC_ACCESSOR_GC 0x78BAC #define FS_OFFSET_200_EXFAT_SDMMC_ACCESSOR_SD 0x7894C #define FS_OFFSET_200_EXFAT_SDMMC_ACCESSOR_NAND 0x784BC // Hooks #define FS_OFFSET_200_EXFAT_SDMMC_WRAPPER_READ 0x73478 #define FS_OFFSET_200_EXFAT_SDMMC_WRAPPER_WRITE 0x73538 #define FS_OFFSET_200_EXFAT_RTLD 0x500 #define FS_OFFSET_200_EXFAT_RTLD_DESTINATION 0x98 #define FS_OFFSET_200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_200_EXFAT_LOCK_MUTEX 0x3264 #define FS_OFFSET_200_EXFAT_UNLOCK_MUTEX 0x32D0 #define FS_OFFSET_200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x733F4 // Misc Data #define FS_OFFSET_200_EXFAT_SD_MUTEX 0xF22268 #define FS_OFFSET_200_EXFAT_NAND_MUTEX 0xF1CED0 #define FS_OFFSET_200_EXFAT_ACTIVE_PARTITION 0xF1CF10 #define FS_OFFSET_200_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0 // NOPs #define FS_OFFSET_200_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_200_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00033F08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00035084, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003537C, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_200_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/2010.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2010_H__ #define __FS_2010_H__ // Accessor vtable getters #define FS_OFFSET_2010_SDMMC_ACCESSOR_GC 0x1A7DB0 #define FS_OFFSET_2010_SDMMC_ACCESSOR_SD 0x1AA130 #define FS_OFFSET_2010_SDMMC_ACCESSOR_NAND 0x1A8560 // Hooks #define FS_OFFSET_2010_SDMMC_WRAPPER_READ 0x1A3C20 #define FS_OFFSET_2010_SDMMC_WRAPPER_WRITE 0x1A3C80 #define FS_OFFSET_2010_RTLD 0x2B594 #define FS_OFFSET_2010_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2010_CLKRST_SET_MIN_V_CLK_RATE 0x1C6150 // Misc funcs #define FS_OFFSET_2010_LOCK_MUTEX 0x19CD80 #define FS_OFFSET_2010_UNLOCK_MUTEX 0x19CDD0 #define FS_OFFSET_2010_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A3BE0 #define FS_OFFSET_2010_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A3C00 // Misc Data #define FS_OFFSET_2010_SD_MUTEX 0xFF5408 #define FS_OFFSET_2010_NAND_MUTEX 0xFF0CF0 #define FS_OFFSET_2010_ACTIVE_PARTITION 0xFF0D30 #define FS_OFFSET_2010_SDMMC_DAS_HANDLE 0xFD2B08 // NOPs #define FS_OFFSET_2010_SD_DAS_INIT 0x289F4 // Nintendo Paths #define FS_OFFSET_2010_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2010_H__ ================================================ FILE: emummc/source/FS/offsets/2010_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2010_EXFAT_H__ #define __FS_2010_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_GC 0x1B36D0 #define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_SD 0x1B5A50 #define FS_OFFSET_2010_EXFAT_SDMMC_ACCESSOR_NAND 0x1B3E80 // Hooks #define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_READ 0x1AF540 #define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_WRITE 0x1AF5A0 #define FS_OFFSET_2010_EXFAT_RTLD 0x2B594 #define FS_OFFSET_2010_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2010_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D1A70 // Misc funcs #define FS_OFFSET_2010_EXFAT_LOCK_MUTEX 0x1A86A0 #define FS_OFFSET_2010_EXFAT_UNLOCK_MUTEX 0x1A86F0 #define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AF500 #define FS_OFFSET_2010_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AF520 // Misc Data #define FS_OFFSET_2010_EXFAT_SD_MUTEX 0x1006408 #define FS_OFFSET_2010_EXFAT_NAND_MUTEX 0x1001CF0 #define FS_OFFSET_2010_EXFAT_ACTIVE_PARTITION 0x1001D30 #define FS_OFFSET_2010_EXFAT_SDMMC_DAS_HANDLE 0xFDFB08 // NOPs #define FS_OFFSET_2010_EXFAT_SD_DAS_INIT 0x289F4 // Nintendo Paths #define FS_OFFSET_2010_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0006DB14, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0007CE1C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x00084A08, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0009AE48, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2010_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/210.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_210_H__ #define __FS_210_H__ // Accessor vtable getters #define FS_OFFSET_210_SDMMC_ACCESSOR_GC 0x78F8C #define FS_OFFSET_210_SDMMC_ACCESSOR_SD 0x78D2C #define FS_OFFSET_210_SDMMC_ACCESSOR_NAND 0x7889C // Hooks #define FS_OFFSET_210_SDMMC_WRAPPER_READ 0x73858 #define FS_OFFSET_210_SDMMC_WRAPPER_WRITE 0x73918 #define FS_OFFSET_210_RTLD 0x500 #define FS_OFFSET_210_RTLD_DESTINATION 0x98 #define FS_OFFSET_210_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_210_LOCK_MUTEX 0x3264 #define FS_OFFSET_210_UNLOCK_MUTEX 0x32D0 #define FS_OFFSET_210_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_210_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x737D4 // Misc Data #define FS_OFFSET_210_SD_MUTEX 0xE43268 #define FS_OFFSET_210_NAND_MUTEX 0xE3DED0 #define FS_OFFSET_210_ACTIVE_PARTITION 0xE3DF10 #define FS_OFFSET_210_SDMMC_DAS_HANDLE 0xE3CDD0 // NOPs #define FS_OFFSET_210_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_210_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000342E0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003545C, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x00035754, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_210_H__ ================================================ FILE: emummc/source/FS/offsets/2100.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2100_H__ #define __FS_2100_H__ // Accessor vtable getters #define FS_OFFSET_2100_SDMMC_ACCESSOR_GC 0x1AC970 #define FS_OFFSET_2100_SDMMC_ACCESSOR_SD 0x1AE980 #define FS_OFFSET_2100_SDMMC_ACCESSOR_NAND 0x1ACFA0 // Hooks #define FS_OFFSET_2100_SDMMC_WRAPPER_READ 0x1A8850 #define FS_OFFSET_2100_SDMMC_WRAPPER_WRITE 0x1A88B0 #define FS_OFFSET_2100_RTLD 0x2E1C0 #define FS_OFFSET_2100_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2100_CLKRST_SET_MIN_V_CLK_RATE 0x1CB9B0 // Misc funcs #define FS_OFFSET_2100_LOCK_MUTEX 0x1A17D0 #define FS_OFFSET_2100_UNLOCK_MUTEX 0x1A1830 #define FS_OFFSET_2100_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A8810 #define FS_OFFSET_2100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A8830 // Misc Data #define FS_OFFSET_2100_SD_MUTEX 0xFEE408 #define FS_OFFSET_2100_NAND_MUTEX 0xFE9CF0 #define FS_OFFSET_2100_ACTIVE_PARTITION 0xFE9D30 #define FS_OFFSET_2100_SDMMC_DAS_HANDLE 0xFCBB18 // NOPs #define FS_OFFSET_2100_SD_DAS_INIT 0x2B5C8 // Nintendo Paths #define FS_OFFSET_2100_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2100_H__ ================================================ FILE: emummc/source/FS/offsets/2100_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2100_EXFAT_EXFAT_H__ #define __FS_2100_EXFAT_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_GC 0x1B7AD0 #define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_SD 0x1B9AE0 #define FS_OFFSET_2100_EXFAT_SDMMC_ACCESSOR_NAND 0x1B8100 // Hooks #define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_READ 0x1B39B0 #define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_WRITE 0x1B3A10 #define FS_OFFSET_2100_EXFAT_RTLD 0x2E1C0 #define FS_OFFSET_2100_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2100_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D6B10 // Misc funcs #define FS_OFFSET_2100_EXFAT_LOCK_MUTEX 0x1AC930 #define FS_OFFSET_2100_EXFAT_UNLOCK_MUTEX 0x1AC990 #define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B3970 #define FS_OFFSET_2100_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B3990 // Misc Data #define FS_OFFSET_2100_EXFAT_SD_MUTEX 0xFFF408 #define FS_OFFSET_2100_EXFAT_NAND_MUTEX 0xFFACF0 #define FS_OFFSET_2100_EXFAT_ACTIVE_PARTITION 0xFFAD30 #define FS_OFFSET_2100_EXFAT_SDMMC_DAS_HANDLE 0xFD8B18 // NOPs #define FS_OFFSET_2100_EXFAT_SD_DAS_INIT 0x2B5C8 // Nintendo Paths #define FS_OFFSET_2100_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2100_EXFAT_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/210_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_210_EXFAT_H__ #define __FS_210_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_210_EXFAT_SDMMC_ACCESSOR_GC 0x78F8C #define FS_OFFSET_210_EXFAT_SDMMC_ACCESSOR_SD 0x78D2C #define FS_OFFSET_210_EXFAT_SDMMC_ACCESSOR_NAND 0x7889C // Hooks #define FS_OFFSET_210_EXFAT_SDMMC_WRAPPER_READ 0x73858 #define FS_OFFSET_210_EXFAT_SDMMC_WRAPPER_WRITE 0x73918 #define FS_OFFSET_210_EXFAT_RTLD 0x500 #define FS_OFFSET_210_EXFAT_RTLD_DESTINATION 0x98 #define FS_OFFSET_210_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_210_EXFAT_LOCK_MUTEX 0x3264 #define FS_OFFSET_210_EXFAT_UNLOCK_MUTEX 0x32D0 #define FS_OFFSET_210_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_210_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x737D4 // Misc Data #define FS_OFFSET_210_EXFAT_SD_MUTEX 0xF22268 #define FS_OFFSET_210_EXFAT_NAND_MUTEX 0xF1CED0 #define FS_OFFSET_210_EXFAT_ACTIVE_PARTITION 0xF1CF10 #define FS_OFFSET_210_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0 // NOPs #define FS_OFFSET_210_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_210_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000342E0, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003545C, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x00035754, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_210_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/2120.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2120_H__ #define __FS_2120_H__ // Accessor vtable getters #define FS_OFFSET_2120_SDMMC_ACCESSOR_GC 0x1AC970 #define FS_OFFSET_2120_SDMMC_ACCESSOR_SD 0x1AE980 #define FS_OFFSET_2120_SDMMC_ACCESSOR_NAND 0x1ACFA0 // Hooks #define FS_OFFSET_2120_SDMMC_WRAPPER_READ 0x1A8850 #define FS_OFFSET_2120_SDMMC_WRAPPER_WRITE 0x1A88B0 #define FS_OFFSET_2120_RTLD 0x2E1C0 #define FS_OFFSET_2120_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2120_CLKRST_SET_MIN_V_CLK_RATE 0x1CB9B0 // Misc funcs #define FS_OFFSET_2120_LOCK_MUTEX 0x1A17D0 #define FS_OFFSET_2120_UNLOCK_MUTEX 0x1A1830 #define FS_OFFSET_2120_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1A8810 #define FS_OFFSET_2120_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1A8830 // Misc Data #define FS_OFFSET_2120_SD_MUTEX 0xFEE408 #define FS_OFFSET_2120_NAND_MUTEX 0xFE9CF0 #define FS_OFFSET_2120_ACTIVE_PARTITION 0xFE9D30 #define FS_OFFSET_2120_SDMMC_DAS_HANDLE 0xFCBB18 // NOPs #define FS_OFFSET_2120_SD_DAS_INIT 0x2B5C8 // Nintendo Paths #define FS_OFFSET_2120_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2120_H__ ================================================ FILE: emummc/source/FS/offsets/2120_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_2120_EXFAT_EXFAT_H__ #define __FS_2120_EXFAT_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_GC 0x1B7AD0 #define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_SD 0x1B9AE0 #define FS_OFFSET_2120_EXFAT_SDMMC_ACCESSOR_NAND 0x1B8100 // Hooks #define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_READ 0x1B39B0 #define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_WRITE 0x1B3A10 #define FS_OFFSET_2120_EXFAT_RTLD 0x2E1C0 #define FS_OFFSET_2120_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C))) #define FS_OFFSET_2120_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1D6B10 // Misc funcs #define FS_OFFSET_2120_EXFAT_LOCK_MUTEX 0x1AC930 #define FS_OFFSET_2120_EXFAT_UNLOCK_MUTEX 0x1AC990 #define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B3970 #define FS_OFFSET_2120_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B3990 // Misc Data #define FS_OFFSET_2120_EXFAT_SD_MUTEX 0xFFF408 #define FS_OFFSET_2120_EXFAT_NAND_MUTEX 0xFFACF0 #define FS_OFFSET_2120_EXFAT_ACTIVE_PARTITION 0xFFAD30 #define FS_OFFSET_2120_EXFAT_SDMMC_DAS_HANDLE 0xFD8B18 // NOPs #define FS_OFFSET_2120_EXFAT_SD_DAS_INIT 0x2B5C8 // Nintendo Paths #define FS_OFFSET_2120_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000718CC, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x000824F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008AF18, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x000A0B8C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_2120_EXFAT_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/300.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_300_H__ #define __FS_300_H__ // Accessor vtable getters #define FS_OFFSET_300_SDMMC_ACCESSOR_GC 0x8FAAC #define FS_OFFSET_300_SDMMC_ACCESSOR_SD 0x8F84C #define FS_OFFSET_300_SDMMC_ACCESSOR_NAND 0x8F3B8 // Hooks #define FS_OFFSET_300_SDMMC_WRAPPER_READ 0x8A2F4 #define FS_OFFSET_300_SDMMC_WRAPPER_WRITE 0x8A3B4 #define FS_OFFSET_300_RTLD 0x4E8 #define FS_OFFSET_300_RTLD_DESTINATION 0x8C #define FS_OFFSET_300_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_300_LOCK_MUTEX 0x35CC #define FS_OFFSET_300_UNLOCK_MUTEX 0x3638 #define FS_OFFSET_300_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_300_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A270 // Misc Data #define FS_OFFSET_300_SD_MUTEX 0xE69268 #define FS_OFFSET_300_NAND_MUTEX 0xE646F0 #define FS_OFFSET_300_ACTIVE_PARTITION 0xE64730 #define FS_OFFSET_300_SDMMC_DAS_HANDLE 0xE635A0 // NOPs #define FS_OFFSET_300_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_300_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000391F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A480, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A778, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_300_H__ ================================================ FILE: emummc/source/FS/offsets/300_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_300_EXFAT_H__ #define __FS_300_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_300_EXFAT_SDMMC_ACCESSOR_GC 0x8FAAC #define FS_OFFSET_300_EXFAT_SDMMC_ACCESSOR_SD 0x8F84C #define FS_OFFSET_300_EXFAT_SDMMC_ACCESSOR_NAND 0x8F3B8 // Hooks #define FS_OFFSET_300_EXFAT_SDMMC_WRAPPER_READ 0x8A2F4 #define FS_OFFSET_300_EXFAT_SDMMC_WRAPPER_WRITE 0x8A3B4 #define FS_OFFSET_300_EXFAT_RTLD 0x4E8 #define FS_OFFSET_300_EXFAT_RTLD_DESTINATION 0x8C #define FS_OFFSET_300_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_300_EXFAT_LOCK_MUTEX 0x35CC #define FS_OFFSET_300_EXFAT_UNLOCK_MUTEX 0x3638 #define FS_OFFSET_300_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_300_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A270 // Misc Data #define FS_OFFSET_300_EXFAT_SD_MUTEX 0xF4C268 #define FS_OFFSET_300_EXFAT_NAND_MUTEX 0xF476F0 #define FS_OFFSET_300_EXFAT_ACTIVE_PARTITION 0xF47730 #define FS_OFFSET_300_EXFAT_SDMMC_DAS_HANDLE 0xF465A0 // NOPs #define FS_OFFSET_300_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_300_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000391F4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A480, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A778, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_300_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/301.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_301_H__ #define __FS_301_H__ // Accessor vtable getters #define FS_OFFSET_301_SDMMC_ACCESSOR_GC 0x8FB68 #define FS_OFFSET_301_SDMMC_ACCESSOR_SD 0x8F908 #define FS_OFFSET_301_SDMMC_ACCESSOR_NAND 0x8F474 // Hooks #define FS_OFFSET_301_SDMMC_WRAPPER_READ 0x8A3B0 #define FS_OFFSET_301_SDMMC_WRAPPER_WRITE 0x8A470 #define FS_OFFSET_301_RTLD 0x4E8 #define FS_OFFSET_301_RTLD_DESTINATION 0x8C #define FS_OFFSET_301_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_301_LOCK_MUTEX 0x3638 #define FS_OFFSET_301_UNLOCK_MUTEX 0x36A4 #define FS_OFFSET_301_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_301_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A32C // Misc Data #define FS_OFFSET_301_SD_MUTEX 0xE69268 #define FS_OFFSET_301_NAND_MUTEX 0xE646F0 #define FS_OFFSET_301_ACTIVE_PARTITION 0xE64730 #define FS_OFFSET_301_SDMMC_DAS_HANDLE 0xE635A0 // NOPs #define FS_OFFSET_301_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_301_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00039260, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A4EC, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A7E4, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_301_H__ ================================================ FILE: emummc/source/FS/offsets/301_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_301_EXFAT_H__ #define __FS_301_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_301_EXFAT_SDMMC_ACCESSOR_GC 0x8FB68 #define FS_OFFSET_301_EXFAT_SDMMC_ACCESSOR_SD 0x8F908 #define FS_OFFSET_301_EXFAT_SDMMC_ACCESSOR_NAND 0x8F474 // Hooks #define FS_OFFSET_301_EXFAT_SDMMC_WRAPPER_READ 0x8A3B0 #define FS_OFFSET_301_EXFAT_SDMMC_WRAPPER_WRITE 0x8A470 #define FS_OFFSET_301_EXFAT_RTLD 0x4E8 #define FS_OFFSET_301_EXFAT_RTLD_DESTINATION 0x8C #define FS_OFFSET_301_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_301_EXFAT_LOCK_MUTEX 0x3638 #define FS_OFFSET_301_EXFAT_UNLOCK_MUTEX 0x36A4 #define FS_OFFSET_301_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_301_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A32C // Misc Data #define FS_OFFSET_301_EXFAT_SD_MUTEX 0xF4C268 #define FS_OFFSET_301_EXFAT_NAND_MUTEX 0xF476F0 #define FS_OFFSET_301_EXFAT_ACTIVE_PARTITION 0xF47730 #define FS_OFFSET_301_EXFAT_SDMMC_DAS_HANDLE 0xF465A0 // NOPs #define FS_OFFSET_301_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_301_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00039260, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A4EC, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x0003A7E4, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_301_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/400.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_400_H__ #define __FS_400_H__ // Accessor vtable getters #define FS_OFFSET_400_SDMMC_ACCESSOR_GC 0xA3374 #define FS_OFFSET_400_SDMMC_ACCESSOR_SD 0xA3114 #define FS_OFFSET_400_SDMMC_ACCESSOR_NAND 0xA2C80 // Hooks #define FS_OFFSET_400_SDMMC_WRAPPER_READ 0x9DBCC #define FS_OFFSET_400_SDMMC_WRAPPER_WRITE 0x9DC8C #define FS_OFFSET_400_RTLD 0x4DC #define FS_OFFSET_400_RTLD_DESTINATION 0x98 #define FS_OFFSET_400_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_400_LOCK_MUTEX 0x39A0 #define FS_OFFSET_400_UNLOCK_MUTEX 0x3A0C #define FS_OFFSET_400_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_400_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DB48 // Misc Data #define FS_OFFSET_400_SD_MUTEX 0xE80268 #define FS_OFFSET_400_NAND_MUTEX 0xE7BC60 #define FS_OFFSET_400_ACTIVE_PARTITION 0xE7BCA0 #define FS_OFFSET_400_SDMMC_DAS_HANDLE 0xE7ABF0 // NOPs #define FS_OFFSET_400_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_400_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_400_H__ ================================================ FILE: emummc/source/FS/offsets/400_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_400_EXFAT_H__ #define __FS_400_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_400_EXFAT_SDMMC_ACCESSOR_GC 0xA3374 #define FS_OFFSET_400_EXFAT_SDMMC_ACCESSOR_SD 0xA3114 #define FS_OFFSET_400_EXFAT_SDMMC_ACCESSOR_NAND 0xA2C80 // Hooks #define FS_OFFSET_400_EXFAT_SDMMC_WRAPPER_READ 0x9DBCC #define FS_OFFSET_400_EXFAT_SDMMC_WRAPPER_WRITE 0x9DC8C #define FS_OFFSET_400_EXFAT_RTLD 0x4DC #define FS_OFFSET_400_EXFAT_RTLD_DESTINATION 0x98 #define FS_OFFSET_400_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_400_EXFAT_LOCK_MUTEX 0x39A0 #define FS_OFFSET_400_EXFAT_UNLOCK_MUTEX 0x3A0C #define FS_OFFSET_400_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_400_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DB48 // Misc Data #define FS_OFFSET_400_EXFAT_SD_MUTEX 0xF63268 #define FS_OFFSET_400_EXFAT_NAND_MUTEX 0xF5EC60 #define FS_OFFSET_400_EXFAT_ACTIVE_PARTITION 0xF5ECA0 #define FS_OFFSET_400_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0 // NOPs #define FS_OFFSET_400_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_400_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_400_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/410.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_410_H__ #define __FS_410_H__ // Accessor vtable getters #define FS_OFFSET_410_SDMMC_ACCESSOR_GC 0xA33D8 #define FS_OFFSET_410_SDMMC_ACCESSOR_SD 0xA3178 #define FS_OFFSET_410_SDMMC_ACCESSOR_NAND 0xA2CE4 // Hooks #define FS_OFFSET_410_SDMMC_WRAPPER_READ 0x9DC30 #define FS_OFFSET_410_SDMMC_WRAPPER_WRITE 0x9DCF0 #define FS_OFFSET_410_RTLD 0x4DC #define FS_OFFSET_410_RTLD_DESTINATION 0x98 #define FS_OFFSET_410_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_410_LOCK_MUTEX 0x39A0 #define FS_OFFSET_410_UNLOCK_MUTEX 0x3A0C #define FS_OFFSET_410_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_410_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DBAC // Misc Data #define FS_OFFSET_410_SD_MUTEX 0xE80268 #define FS_OFFSET_410_NAND_MUTEX 0xE7BC60 #define FS_OFFSET_410_ACTIVE_PARTITION 0xE7BCA0 #define FS_OFFSET_410_SDMMC_DAS_HANDLE 0xE7ABF0 // NOPs #define FS_OFFSET_410_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_410_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_410_H__ ================================================ FILE: emummc/source/FS/offsets/410_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_410_EXFAT_H__ #define __FS_410_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_410_EXFAT_SDMMC_ACCESSOR_GC 0xA33D8 #define FS_OFFSET_410_EXFAT_SDMMC_ACCESSOR_SD 0xA3178 #define FS_OFFSET_410_EXFAT_SDMMC_ACCESSOR_NAND 0xA2CE4 // Hooks #define FS_OFFSET_410_EXFAT_SDMMC_WRAPPER_READ 0x9DC30 #define FS_OFFSET_410_EXFAT_SDMMC_WRAPPER_WRITE 0x9DCF0 #define FS_OFFSET_410_EXFAT_RTLD 0x4DC #define FS_OFFSET_410_EXFAT_RTLD_DESTINATION 0x98 #define FS_OFFSET_410_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_410_EXFAT_LOCK_MUTEX 0x39A0 #define FS_OFFSET_410_EXFAT_UNLOCK_MUTEX 0x3A0C #define FS_OFFSET_410_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_410_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DBAC // Misc Data #define FS_OFFSET_410_EXFAT_SD_MUTEX 0xF63268 #define FS_OFFSET_410_EXFAT_NAND_MUTEX 0xF5EC60 #define FS_OFFSET_410_EXFAT_ACTIVE_PARTITION 0xF5ECA0 #define FS_OFFSET_410_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0 // NOPs #define FS_OFFSET_410_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_410_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 12}, \ {.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 12}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_410_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/500.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_500_H__ #define __FS_500_H__ // Accessor vtable getters #define FS_OFFSET_500_SDMMC_ACCESSOR_GC 0xCF250 #define FS_OFFSET_500_SDMMC_ACCESSOR_SD 0xCEFD0 #define FS_OFFSET_500_SDMMC_ACCESSOR_NAND 0xCE990 // Hooks #define FS_OFFSET_500_SDMMC_WRAPPER_READ 0xC9420 #define FS_OFFSET_500_SDMMC_WRAPPER_WRITE 0xC9500 #define FS_OFFSET_500_RTLD 0x584 #define FS_OFFSET_500_RTLD_DESTINATION 0x94 #define FS_OFFSET_500_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_500_LOCK_MUTEX 0x4080 #define FS_OFFSET_500_UNLOCK_MUTEX 0x40D0 #define FS_OFFSET_500_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_500_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9380 // Misc Data #define FS_OFFSET_500_SD_MUTEX 0xEC3268 #define FS_OFFSET_500_NAND_MUTEX 0xEBDE58 #define FS_OFFSET_500_ACTIVE_PARTITION 0xEBDE98 #define FS_OFFSET_500_SDMMC_DAS_HANDLE 0xEBCE30 // NOPs #define FS_OFFSET_500_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_500_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00028980, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002ACE4, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002B220, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_500_H__ ================================================ FILE: emummc/source/FS/offsets/500_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_500_EXFAT_H__ #define __FS_500_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_500_EXFAT_SDMMC_ACCESSOR_GC 0xCF250 #define FS_OFFSET_500_EXFAT_SDMMC_ACCESSOR_SD 0xCEFD0 #define FS_OFFSET_500_EXFAT_SDMMC_ACCESSOR_NAND 0xCE990 // Hooks #define FS_OFFSET_500_EXFAT_SDMMC_WRAPPER_READ 0xC9420 #define FS_OFFSET_500_EXFAT_SDMMC_WRAPPER_WRITE 0xC9500 #define FS_OFFSET_500_EXFAT_RTLD 0x584 #define FS_OFFSET_500_EXFAT_RTLD_DESTINATION 0x94 #define FS_OFFSET_500_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_500_EXFAT_LOCK_MUTEX 0x4080 #define FS_OFFSET_500_EXFAT_UNLOCK_MUTEX 0x40D0 #define FS_OFFSET_500_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_500_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9380 // Misc Data #define FS_OFFSET_500_EXFAT_SD_MUTEX 0xFA8268 #define FS_OFFSET_500_EXFAT_NAND_MUTEX 0xFA2E58 #define FS_OFFSET_500_EXFAT_ACTIVE_PARTITION 0xFA2E98 #define FS_OFFSET_500_EXFAT_SDMMC_DAS_HANDLE 0xFA1E30 // NOPs #define FS_OFFSET_500_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_500_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00028980, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002ACE4, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002B220, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_500_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/510.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_510_H__ #define __FS_510_H__ // Accessor vtable getters #define FS_OFFSET_510_SDMMC_ACCESSOR_GC 0xCF620 #define FS_OFFSET_510_SDMMC_ACCESSOR_SD 0xCF3A0 #define FS_OFFSET_510_SDMMC_ACCESSOR_NAND 0xCED60 // Hooks #define FS_OFFSET_510_SDMMC_WRAPPER_READ 0xC97F0 #define FS_OFFSET_510_SDMMC_WRAPPER_WRITE 0xC98D0 #define FS_OFFSET_510_RTLD 0x584 #define FS_OFFSET_510_RTLD_DESTINATION 0x94 #define FS_OFFSET_510_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_510_LOCK_MUTEX 0x4080 #define FS_OFFSET_510_UNLOCK_MUTEX 0x40D0 #define FS_OFFSET_510_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_510_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9750 // Misc Data #define FS_OFFSET_510_SD_MUTEX 0xEC4268 #define FS_OFFSET_510_NAND_MUTEX 0xEBEE58 #define FS_OFFSET_510_ACTIVE_PARTITION 0xEBEE98 #define FS_OFFSET_510_SDMMC_DAS_HANDLE 0xEBDE30 // NOPs #define FS_OFFSET_510_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_510_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000289B0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002AD14, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002B250, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_510_H__ ================================================ FILE: emummc/source/FS/offsets/510_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_510_EXFAT_H__ #define __FS_510_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_510_EXFAT_SDMMC_ACCESSOR_GC 0xCF620 #define FS_OFFSET_510_EXFAT_SDMMC_ACCESSOR_SD 0xCF3A0 #define FS_OFFSET_510_EXFAT_SDMMC_ACCESSOR_NAND 0xCED60 // Hooks #define FS_OFFSET_510_EXFAT_SDMMC_WRAPPER_READ 0xC97F0 #define FS_OFFSET_510_EXFAT_SDMMC_WRAPPER_WRITE 0xC98D0 #define FS_OFFSET_510_EXFAT_RTLD 0x584 #define FS_OFFSET_510_EXFAT_RTLD_DESTINATION 0x94 #define FS_OFFSET_510_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_510_EXFAT_LOCK_MUTEX 0x4080 #define FS_OFFSET_510_EXFAT_UNLOCK_MUTEX 0x40D0 #define FS_OFFSET_510_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_510_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9750 // Misc Data #define FS_OFFSET_510_EXFAT_SD_MUTEX 0xFA9268 #define FS_OFFSET_510_EXFAT_NAND_MUTEX 0xFA3E58 #define FS_OFFSET_510_EXFAT_ACTIVE_PARTITION 0xFA3E98 #define FS_OFFSET_510_EXFAT_SDMMC_DAS_HANDLE 0xFA2E30 // NOPs #define FS_OFFSET_510_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_510_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000289B0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002AD14, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0002B250, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_510_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/600.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_600_H__ #define __FS_600_H__ // Accessor vtable getters #define FS_OFFSET_600_SDMMC_ACCESSOR_GC 0x153780 #define FS_OFFSET_600_SDMMC_ACCESSOR_SD 0x1534F0 #define FS_OFFSET_600_SDMMC_ACCESSOR_NAND 0x14F990 // Hooks #define FS_OFFSET_600_SDMMC_WRAPPER_READ 0x1485A0 #define FS_OFFSET_600_SDMMC_WRAPPER_WRITE 0x148680 #define FS_OFFSET_600_RTLD 0x5B0 #define FS_OFFSET_600_RTLD_DESTINATION 0x98 #define FS_OFFSET_600_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_600_LOCK_MUTEX 0x1412C0 #define FS_OFFSET_600_UNLOCK_MUTEX 0x141310 #define FS_OFFSET_600_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x148500 // Misc Data #define FS_OFFSET_600_SD_MUTEX 0xF06268 #define FS_OFFSET_600_NAND_MUTEX 0xF01BA0 #define FS_OFFSET_600_ACTIVE_PARTITION 0xF01BE0 #define FS_OFFSET_600_SDMMC_DAS_HANDLE 0xE01670 // NOPs #define FS_OFFSET_600_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_600_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000790DC, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007A924, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AB18, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007AEF4, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_600_H__ ================================================ FILE: emummc/source/FS/offsets/600_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_600_EXFAT_H__ #define __FS_600_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_600_EXFAT_SDMMC_ACCESSOR_GC 0x15EE80 #define FS_OFFSET_600_EXFAT_SDMMC_ACCESSOR_SD 0x15EBF0 #define FS_OFFSET_600_EXFAT_SDMMC_ACCESSOR_NAND 0x15B090 // Hooks #define FS_OFFSET_600_EXFAT_SDMMC_WRAPPER_READ 0x153CA0 #define FS_OFFSET_600_EXFAT_SDMMC_WRAPPER_WRITE 0x153D80 #define FS_OFFSET_600_EXFAT_RTLD 0x5B0 #define FS_OFFSET_600_EXFAT_RTLD_DESTINATION 0x98 #define FS_OFFSET_600_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_600_EXFAT_LOCK_MUTEX 0x14C9C0 #define FS_OFFSET_600_EXFAT_UNLOCK_MUTEX 0x14CA10 #define FS_OFFSET_600_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x153C00 // Misc Data #define FS_OFFSET_600_EXFAT_SD_MUTEX 0xFEB268 #define FS_OFFSET_600_EXFAT_NAND_MUTEX 0xFE6BA0 #define FS_OFFSET_600_EXFAT_ACTIVE_PARTITION 0xFE6BE0 #define FS_OFFSET_600_EXFAT_SDMMC_DAS_HANDLE 0xEE6670 // NOPs #define FS_OFFSET_600_EXFAT_SD_DAS_INIT 0x0 // Nintendo Paths #define FS_OFFSET_600_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x000847DC, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00086024, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00086218, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x000865F4, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_600_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/700.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_700_H__ #define __FS_700_H__ // Accessor vtable getters #define FS_OFFSET_700_SDMMC_ACCESSOR_GC 0x15BD90 #define FS_OFFSET_700_SDMMC_ACCESSOR_SD 0x15BB00 #define FS_OFFSET_700_SDMMC_ACCESSOR_NAND 0x157FF0 // Hooks #define FS_OFFSET_700_SDMMC_WRAPPER_READ 0x14FDF0 #define FS_OFFSET_700_SDMMC_WRAPPER_WRITE 0x14FED0 #define FS_OFFSET_700_RTLD 0x5B4 #define FS_OFFSET_700_RTLD_DESTINATION 0x9C #define FS_OFFSET_700_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_700_LOCK_MUTEX 0x148A90 #define FS_OFFSET_700_UNLOCK_MUTEX 0x148AE0 #define FS_OFFSET_700_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_700_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14FD50 // Misc Data #define FS_OFFSET_700_SD_MUTEX 0xF123E8 #define FS_OFFSET_700_NAND_MUTEX 0xF0DBE8 #define FS_OFFSET_700_ACTIVE_PARTITION 0xF0DC28 #define FS_OFFSET_700_SDMMC_DAS_HANDLE 0xE0E7A0 // NOPs #define FS_OFFSET_700_SD_DAS_INIT 0x85FE8 // Nintendo Paths #define FS_OFFSET_700_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0007DA90, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007F344, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007F538, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0007F914, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x0007FAD8, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_700_H__ ================================================ FILE: emummc/source/FS/offsets/700_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_700_EXFAT_H__ #define __FS_700_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_700_EXFAT_SDMMC_ACCESSOR_GC 0x167340 #define FS_OFFSET_700_EXFAT_SDMMC_ACCESSOR_SD 0x1670B0 #define FS_OFFSET_700_EXFAT_SDMMC_ACCESSOR_NAND 0x1635A0 // Hooks #define FS_OFFSET_700_EXFAT_SDMMC_WRAPPER_READ 0x15B3A0 #define FS_OFFSET_700_EXFAT_SDMMC_WRAPPER_WRITE 0x15B480 #define FS_OFFSET_700_EXFAT_RTLD 0x5B4 #define FS_OFFSET_700_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_700_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x0 // Misc funcs #define FS_OFFSET_700_EXFAT_LOCK_MUTEX 0x154040 #define FS_OFFSET_700_EXFAT_UNLOCK_MUTEX 0x154090 #define FS_OFFSET_700_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_700_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15B300 // Misc Data #define FS_OFFSET_700_EXFAT_SD_MUTEX 0xFF73E8 #define FS_OFFSET_700_EXFAT_NAND_MUTEX 0xFF2BE8 #define FS_OFFSET_700_EXFAT_ACTIVE_PARTITION 0xFF2C28 #define FS_OFFSET_700_EXFAT_SDMMC_DAS_HANDLE 0xEF3A00 // NOPs #define FS_OFFSET_700_EXFAT_SD_DAS_INIT 0x91598 // Nintendo Paths #define FS_OFFSET_700_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00089040, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008A8F4, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008AAE8, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008AEC4, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x0008B088, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_700_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/800.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_800_H__ #define __FS_800_H__ // Accessor vtable getters #define FS_OFFSET_800_SDMMC_ACCESSOR_GC 0x15EA20 #define FS_OFFSET_800_SDMMC_ACCESSOR_SD 0x15E790 #define FS_OFFSET_800_SDMMC_ACCESSOR_NAND 0x15AC80 // Hooks #define FS_OFFSET_800_SDMMC_WRAPPER_READ 0x152A80 #define FS_OFFSET_800_SDMMC_WRAPPER_WRITE 0x152B60 #define FS_OFFSET_800_RTLD 0x5B4 #define FS_OFFSET_800_RTLD_DESTINATION 0x9C #define FS_OFFSET_800_CLKRST_SET_MIN_V_CLK_RATE 0x16F370 // Misc funcs #define FS_OFFSET_800_LOCK_MUTEX 0x14B6D0 #define FS_OFFSET_800_UNLOCK_MUTEX 0x14B720 #define FS_OFFSET_800_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_800_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1529E0 // Misc Data #define FS_OFFSET_800_SD_MUTEX 0xF1A3E8 #define FS_OFFSET_800_NAND_MUTEX 0xF15BE8 #define FS_OFFSET_800_ACTIVE_PARTITION 0xF15C28 #define FS_OFFSET_800_SDMMC_DAS_HANDLE 0xE167C0 // NOPs #define FS_OFFSET_800_SD_DAS_INIT 0x87D58 // Nintendo Paths #define FS_OFFSET_800_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_800_H__ ================================================ FILE: emummc/source/FS/offsets/800_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_800_EXFAT_H__ #define __FS_800_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_800_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0 #define FS_OFFSET_800_EXFAT_SDMMC_ACCESSOR_SD 0x169D40 #define FS_OFFSET_800_EXFAT_SDMMC_ACCESSOR_NAND 0x166230 // Hooks #define FS_OFFSET_800_EXFAT_SDMMC_WRAPPER_READ 0x15E030 #define FS_OFFSET_800_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110 #define FS_OFFSET_800_EXFAT_RTLD 0x5B4 #define FS_OFFSET_800_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_800_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920 // Misc funcs #define FS_OFFSET_800_EXFAT_LOCK_MUTEX 0x156C80 #define FS_OFFSET_800_EXFAT_UNLOCK_MUTEX 0x156CD0 #define FS_OFFSET_800_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_800_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15DF90 // Misc Data #define FS_OFFSET_800_EXFAT_SD_MUTEX 0xFFE3E8 #define FS_OFFSET_800_EXFAT_NAND_MUTEX 0xFF9BE8 #define FS_OFFSET_800_EXFAT_ACTIVE_PARTITION 0xFF9C28 #define FS_OFFSET_800_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20 // NOPs #define FS_OFFSET_800_EXFAT_SD_DAS_INIT 0x93308 // Nintendo Paths #define FS_OFFSET_800_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_800_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/810.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_810_H__ #define __FS_810_H__ // Accessor vtable getters #define FS_OFFSET_810_SDMMC_ACCESSOR_GC 0x15EA20 #define FS_OFFSET_810_SDMMC_ACCESSOR_SD 0x15E790 #define FS_OFFSET_810_SDMMC_ACCESSOR_NAND 0x15AC80 // Hooks #define FS_OFFSET_810_SDMMC_WRAPPER_READ 0x152A80 #define FS_OFFSET_810_SDMMC_WRAPPER_WRITE 0x152B60 #define FS_OFFSET_810_RTLD 0x5B4 #define FS_OFFSET_810_RTLD_DESTINATION 0x9C #define FS_OFFSET_810_CLKRST_SET_MIN_V_CLK_RATE 0x16F370 // Misc funcs #define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0 #define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720 #define FS_OFFSET_810_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_810_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1529E0 // Misc Data #define FS_OFFSET_810_SD_MUTEX 0xF1A3E8 #define FS_OFFSET_810_NAND_MUTEX 0xF15BE8 #define FS_OFFSET_810_ACTIVE_PARTITION 0xF15C28 #define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0 // NOPs #define FS_OFFSET_810_SD_DAS_INIT 0x87D58 // Nintendo Paths #define FS_OFFSET_810_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_810_H__ ================================================ FILE: emummc/source/FS/offsets/810_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_810_EXFAT_H__ #define __FS_810_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0 #define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_SD 0x169D40 #define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_NAND 0x166230 // Hooks #define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_READ 0x15E030 #define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110 #define FS_OFFSET_810_EXFAT_RTLD 0x5B4 #define FS_OFFSET_810_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920 // Misc funcs #define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80 #define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0 #define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15DF90 // Misc Data #define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8 #define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8 #define FS_OFFSET_810_EXFAT_ACTIVE_PARTITION 0xFF9C28 #define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20 // NOPs #define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308 // Nintendo Paths #define FS_OFFSET_810_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \ {.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \ {.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ } #endif // __FS_810_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/900.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_900_H__ #define __FS_900_H__ // Accessor vtable getters #define FS_OFFSET_900_SDMMC_ACCESSOR_GC 0x1430F0 #define FS_OFFSET_900_SDMMC_ACCESSOR_SD 0x141200 #define FS_OFFSET_900_SDMMC_ACCESSOR_NAND 0x13C080 // Hooks #define FS_OFFSET_900_SDMMC_WRAPPER_READ 0x1377E0 #define FS_OFFSET_900_SDMMC_WRAPPER_WRITE 0x1378C0 #define FS_OFFSET_900_RTLD 0x454 #define FS_OFFSET_900_RTLD_DESTINATION 0x9C #define FS_OFFSET_900_CLKRST_SET_MIN_V_CLK_RATE 0x136A00 // Misc funcs #define FS_OFFSET_900_LOCK_MUTEX 0x25280 #define FS_OFFSET_900_UNLOCK_MUTEX 0x252D0 #define FS_OFFSET_900_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_900_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137740 // Misc Data #define FS_OFFSET_900_SD_MUTEX 0xE1D3E8 #define FS_OFFSET_900_NAND_MUTEX 0xE18258 #define FS_OFFSET_900_ACTIVE_PARTITION 0xE18298 #define FS_OFFSET_900_SDMMC_DAS_HANDLE 0xDFEFA0 // NOPs #define FS_OFFSET_900_SD_DAS_INIT 0x1472BC // Nintendo Paths #define FS_OFFSET_900_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068A60, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070A40, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081CB4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081EF4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008211C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_900_H__ ================================================ FILE: emummc/source/FS/offsets/900_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_900_EXFAT_H__ #define __FS_900_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_GC 0x1430F0 #define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_SD 0x141200 #define FS_OFFSET_900_EXFAT_SDMMC_ACCESSOR_NAND 0x13C080 // Hooks #define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_READ 0x1377E0 #define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_WRITE 0x1378C0 #define FS_OFFSET_900_EXFAT_RTLD 0x454 #define FS_OFFSET_900_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_900_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x136A00 // Misc funcs #define FS_OFFSET_900_EXFAT_LOCK_MUTEX 0x25280 #define FS_OFFSET_900_EXFAT_UNLOCK_MUTEX 0x252D0 #define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_900_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137740 // Misc Data #define FS_OFFSET_900_EXFAT_SD_MUTEX 0xE2B3E8 #define FS_OFFSET_900_EXFAT_NAND_MUTEX 0xE26258 #define FS_OFFSET_900_EXFAT_ACTIVE_PARTITION 0xE26298 #define FS_OFFSET_900_EXFAT_SDMMC_DAS_HANDLE 0xE0CFA0 // NOPs #define FS_OFFSET_900_EXFAT_SD_DAS_INIT 0x1472BC // Nintendo Paths #define FS_OFFSET_900_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068A60, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070A40, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081CB4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081EF4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008211C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_900_EXFAT_H__ ================================================ FILE: emummc/source/FS/offsets/910.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_910_H__ #define __FS_910_H__ // Accessor vtable getters #define FS_OFFSET_910_SDMMC_ACCESSOR_GC 0x143100 #define FS_OFFSET_910_SDMMC_ACCESSOR_SD 0x141210 #define FS_OFFSET_910_SDMMC_ACCESSOR_NAND 0x13C090 // Hooks #define FS_OFFSET_910_SDMMC_WRAPPER_READ 0x1377F0 #define FS_OFFSET_910_SDMMC_WRAPPER_WRITE 0x1378D0 #define FS_OFFSET_910_RTLD 0x454 #define FS_OFFSET_910_RTLD_DESTINATION 0x9C #define FS_OFFSET_910_CLKRST_SET_MIN_V_CLK_RATE 0x136A10 // Misc funcs #define FS_OFFSET_910_LOCK_MUTEX 0x25280 #define FS_OFFSET_910_UNLOCK_MUTEX 0x252D0 #define FS_OFFSET_910_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_910_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137750 // Misc Data #define FS_OFFSET_910_SD_MUTEX 0xE1D3E8 #define FS_OFFSET_910_NAND_MUTEX 0xE18258 #define FS_OFFSET_910_ACTIVE_PARTITION 0xE18298 #define FS_OFFSET_910_SDMMC_DAS_HANDLE 0xDFEFA0 // NOPs #define FS_OFFSET_910_SD_DAS_INIT 0x1472CC // Nintendo Paths #define FS_OFFSET_910_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068A70, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070A50, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081CC4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081F04, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008212C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_910_H__ ================================================ FILE: emummc/source/FS/offsets/910_exfat.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __FS_910_EXFAT_H__ #define __FS_910_EXFAT_H__ // Accessor vtable getters #define FS_OFFSET_910_EXFAT_SDMMC_ACCESSOR_GC 0x143100 #define FS_OFFSET_910_EXFAT_SDMMC_ACCESSOR_SD 0x141210 #define FS_OFFSET_910_EXFAT_SDMMC_ACCESSOR_NAND 0x13C090 // Hooks #define FS_OFFSET_910_EXFAT_SDMMC_WRAPPER_READ 0x1377F0 #define FS_OFFSET_910_EXFAT_SDMMC_WRAPPER_WRITE 0x1378D0 #define FS_OFFSET_910_EXFAT_RTLD 0x454 #define FS_OFFSET_910_EXFAT_RTLD_DESTINATION 0x9C #define FS_OFFSET_910_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x136A10 // Misc funcs #define FS_OFFSET_910_EXFAT_LOCK_MUTEX 0x25280 #define FS_OFFSET_910_EXFAT_UNLOCK_MUTEX 0x252D0 #define FS_OFFSET_910_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0 #define FS_OFFSET_910_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x137750 // Misc Data #define FS_OFFSET_910_EXFAT_SD_MUTEX 0xE2B3E8 #define FS_OFFSET_910_EXFAT_NAND_MUTEX 0xE26258 #define FS_OFFSET_910_EXFAT_ACTIVE_PARTITION 0xE26298 #define FS_OFFSET_910_EXFAT_SDMMC_DAS_HANDLE 0xE0CFA0 // NOPs #define FS_OFFSET_910_EXFAT_SD_DAS_INIT 0x1472CC // Nintendo Paths #define FS_OFFSET_910_EXFAT_NINTENDO_PATHS \ { \ {.opcode_reg = 3, .adrp_offset = 0x00068A70, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00070A50, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081CC4, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 3, .adrp_offset = 0x00081F04, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 4, .adrp_offset = 0x0008212C, .add_rel_offset = 0x00000004}, \ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \ } #endif // __FS_910_EXFAT_H__ ================================================ FILE: emummc/source/emmc/mmc.h ================================================ /* * Header for MultiMediaCard (MMC) * * Copyright 2002 Hewlett-Packard Company * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Based strongly on code by: * * Author: Yong-iL Joh <tolkien@mizi.com> * * Author: Andrew Christian * 15 May 2002 */ #ifndef LINUX_MMC_MMC_H #define LINUX_MMC_MMC_H /* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ #define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ #define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ #define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ #define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define MMC_BUS_TEST_R 14 /* adtc R1 */ #define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ #define MMC_BUS_TEST_W 19 /* adtc R1 */ #define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ #define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ /* class 2 */ #define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ #define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ /* class 3 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ /* class 4 */ #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ #define MMC_PROGRAM_CID 26 /* adtc R1 */ #define MMC_PROGRAM_CSD 27 /* adtc R1 */ /* class 6 */ #define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ #define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ #define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ /* class 5 */ #define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ #define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ #define MMC_ERASE 38 /* ac R1b */ /* class 9 */ #define MMC_FAST_IO 39 /* ac <Complex> R4 */ #define MMC_GO_IRQ_STATE 40 /* bcr R5 */ /* class 7 */ #define MMC_LOCK_UNLOCK 42 /* adtc R1b */ /* class 8 */ #define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ /* class 11 */ #define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */ #define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */ #define MMC_EXECUTE_READ_TASK 46 /* adtc [20:16] task id R1 */ #define MMC_EXECUTE_WRITE_TASK 47 /* adtc [20:16] task id R1 */ #define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */ /* * MMC_SWITCH argument format: * * [31:26] Always 0 * [25:24] Access Mode * [23:16] Location of target Byte in EXT_CSD * [15:08] Value Byte * [07:03] Always 0 * [02:00] Command Set */ /* MMC status in R1, for native mode (SPI bits are different) Type e : error bit s : status bit r : detected and set for the actual command response x : detected and set during command execution. the host must poll the card by sending status command in order to read these bits. Clear condition a : according to the card state b : always related to the previous command. Reception of a valid command will clear it (with a delay of one command) c : clear by read */ #define R1_OUT_OF_RANGE (1 << 31) /* er, c */ #define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ #define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ #define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ #define R1_ERASE_PARAM (1 << 27) /* ex, c */ #define R1_WP_VIOLATION (1 << 26) /* erx, c */ #define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ #define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ #define R1_COM_CRC_ERROR (1 << 23) /* er, b */ #define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ #define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ #define R1_CC_ERROR (1 << 20) /* erx, c */ #define R1_ERROR (1 << 19) /* erx, c */ #define R1_UNDERRUN (1 << 18) /* ex, c */ #define R1_OVERRUN (1 << 17) /* ex, c */ #define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ #define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ #define R1_ERASE_RESET (1 << 13) /* sr, c */ #define R1_STATUS(x) ((x) & 0xFFFFE000) #define R1_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9) /* sx, b (4 bits) */ #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ #define R1_STATE_IDLE 0 #define R1_STATE_READY 1 #define R1_STATE_IDENT 2 #define R1_STATE_STBY 3 #define R1_STATE_TRAN 4 #define R1_STATE_DATA 5 #define R1_STATE_RCV 6 #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 /* * MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS * R1 is the low order byte; R2 is the next highest byte, when present. */ #define R1_SPI_IDLE (1 << 0) #define R1_SPI_ERASE_RESET (1 << 1) #define R1_SPI_ILLEGAL_COMMAND (1 << 2) #define R1_SPI_COM_CRC (1 << 3) #define R1_SPI_ERASE_SEQ (1 << 4) #define R1_SPI_ADDRESS (1 << 5) #define R1_SPI_PARAMETER (1 << 6) /* R1 bit 7 is always zero */ #define R2_SPI_CARD_LOCKED (1 << 8) #define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ #define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP #define R2_SPI_ERROR (1 << 10) #define R2_SPI_CC_ERROR (1 << 11) #define R2_SPI_CARD_ECC_ERROR (1 << 12) #define R2_SPI_WP_VIOLATION (1 << 13) #define R2_SPI_ERASE_PARAM (1 << 14) #define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ #define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE /* * OCR bits are mostly in host.h */ #define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ /* * Card Command Classes (CCC) */ #define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ /* (and for SPI, CMD58,59) */ #define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ /* (CMD11) */ #define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ /* (CMD16,17,18) */ #define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */ /* (CMD20) */ #define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */ /* (CMD16,24,25,26,27) */ #define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */ /* (CMD32,33,34,35,36,37,38,39) */ #define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */ /* (CMD28,29,30) */ #define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */ /* (CMD16,CMD42) */ #define CCC_APP_SPEC (1<<8) /* (8) Application specific */ /* (CMD55,56,57,ACMD*) */ #define CCC_IO_MODE (1<<9) /* (9) I/O mode */ /* (CMD5,39,40,52,53) */ #define CCC_SWITCH (1<<10) /* (10) High speed switch */ /* (CMD6,34,35,36,37,50) */ /* (11) Reserved */ /* (CMD?) */ /* * CSD field definitions */ #define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ #define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ #define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ #define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ #define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ #define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ #define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ #define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ #define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ /* * EXT_CSD fields */ #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ #define EXT_CSD_FLUSH_CACHE 32 /* W */ #define EXT_CSD_CACHE_CTRL 33 /* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ #define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ #define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ #define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ #define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ #define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ #define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ #define EXT_CSD_HPI_MGMT 161 /* R/W */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ #define EXT_CSD_BKOPS_EN 163 /* R/W */ #define EXT_CSD_BKOPS_START 164 /* W */ #define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_WR_REL_PARAM 166 /* RO */ #define EXT_CSD_RPMB_MULT 168 /* RO */ #define EXT_CSD_FW_CONFIG 169 /* R/W */ #define EXT_CSD_BOOT_WP 173 /* R/W */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */ #define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ #define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_STROBE_SUPPORT 184 /* RO */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_POWER_CLASS 187 /* R/W */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_STRUCTURE 194 /* RO */ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_DRIVER_STRENGTH 197 /* RO */ #define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ #define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ #define EXT_CSD_PWR_CL_52_195 200 /* RO */ #define EXT_CSD_PWR_CL_26_195 201 /* RO */ #define EXT_CSD_PWR_CL_52_360 202 /* RO */ #define EXT_CSD_PWR_CL_26_360 203 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_S_A_TIMEOUT 217 /* RO */ #define EXT_CSD_REL_WR_SEC_C 222 /* RO */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_MULT 226 /* RO */ #define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ #define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ #define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ #define EXT_CSD_TRIM_MULT 232 /* RO */ #define EXT_CSD_PWR_CL_200_195 236 /* RO */ #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ #define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ #define EXT_CSD_BKOPS_STATUS 246 /* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ #define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ #define EXT_CSD_DEVICE_VERSION 262 /* RO, 2 bytes */ #define EXT_CSD_PRE_EOL_INFO 267 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ #define EXT_CSD_CMDQ_DEPTH 307 /* RO */ #define EXT_CSD_CMDQ_SUPPORT 308 /* RO */ #define EXT_CSD_SUPPORTED_MODE 493 /* RO */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ #define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ #define EXT_CSD_MAX_PACKED_READS 501 /* RO */ #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ #define EXT_CSD_HPI_FEATURES 503 /* RO */ /* * EXT_CSD field definitions */ #define EXT_CSD_WR_REL_PARAM_EN (1<<2) #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) #define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) #define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) #define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) #define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3) #define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4) #define EXT_CSD_PART_SETTING_COMPLETED (0x1) #define EXT_CSD_PART_SUPPORT_PART_EN (0x1) #define EXT_CSD_CMD_SET_NORMAL (1<<0) #define EXT_CSD_CMD_SET_SECURE (1<<1) #define EXT_CSD_CMD_SET_CPSECURE (1<<2) #define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */ #define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \ EXT_CSD_CARD_TYPE_HS_52) #define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */ /* DDR mode @1.8V or 3V I/O */ #define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */ /* DDR mode @1.2V I/O */ #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ | EXT_CSD_CARD_TYPE_DDR_1_2V) #define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */ #define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */ /* SDR mode @1.2V I/O */ #define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \ EXT_CSD_CARD_TYPE_HS200_1_2V) #define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */ #define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */ #define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \ EXT_CSD_CARD_TYPE_HS400_1_2V) #define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ #define EXT_CSD_BUS_WIDTH_STROBE (1<<7) /* Enhanced strobe mode */ #define EXT_CSD_TIMING_BC 0 /* Backwards compatility */ #define EXT_CSD_TIMING_HS 1 /* High speed */ #define EXT_CSD_TIMING_HS200 2 /* HS200 */ #define EXT_CSD_TIMING_HS400 3 /* HS400 */ #define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */ #define EXT_CSD_SEC_ER_EN (1<<0) #define EXT_CSD_SEC_BD_BLK_EN (1<<2) #define EXT_CSD_SEC_GB_CL_EN (1<<4) #define EXT_CSD_SEC_SANITIZE (1<<6) /* v4.5 only */ #define EXT_CSD_RST_N_EN_MASK 0x3 #define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */ #define EXT_CSD_NO_POWER_NOTIFICATION 0 #define EXT_CSD_POWER_ON 1 #define EXT_CSD_POWER_OFF_SHORT 2 #define EXT_CSD_POWER_OFF_LONG 3 #define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */ #define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */ #define EXT_CSD_PWR_CL_8BIT_SHIFT 4 #define EXT_CSD_PWR_CL_4BIT_SHIFT 0 #define EXT_CSD_PACKED_EVENT_EN (1<<3) /* * EXCEPTION_EVENT_STATUS field */ #define EXT_CSD_URGENT_BKOPS (1<<0) #define EXT_CSD_DYNCAP_NEEDED (1<<1) #define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2) #define EXT_CSD_PACKED_FAILURE (1<<3) #define EXT_CSD_PACKED_GENERIC_ERROR (1<<0) #define EXT_CSD_PACKED_INDEXED_ERROR (1<<1) /* * BKOPS status level */ #define EXT_CSD_BKOPS_LEVEL_2 0x2 /* * BKOPS modes */ #define EXT_CSD_MANUAL_BKOPS_MASK 0x01 #define EXT_CSD_AUTO_BKOPS_MASK 0x02 /* * Command Queue */ #define EXT_CSD_CMDQ_MODE_ENABLED (1<<0) #define EXT_CSD_CMDQ_DEPTH_MASK 0x1F #define EXT_CSD_CMDQ_SUPPORTED (1<<0) /* * MMC_SWITCH access modes */ #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ /* * Erase/trim/discard */ #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 #define MMC_TRIM_ARG 0x00000001 #define MMC_DISCARD_ARG 0x00000003 #define MMC_SECURE_TRIM1_ARG 0x80000001 #define MMC_SECURE_TRIM2_ARG 0x80008000 #define MMC_SECURE_ARGS 0x80000000 #define MMC_TRIM_ARGS 0x00008001 #endif /* LINUX_MMC_MMC_H */ ================================================ FILE: emummc/source/emmc/nx_emmc.c ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include "../utils/types.h" #include "nx_emmc.h" int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) { // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); } int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) { // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf); } ================================================ FILE: emummc/source/emmc/nx_emmc.h ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _NX_EMMC_H_ #define _NX_EMMC_H_ #include "../utils/types.h" #include "sdmmc.h" typedef struct _gpt_entry_t { u8 type_guid[0x10]; u8 part_guid[0x10]; u64 lba_start; u64 lba_end; u64 attrs; u16 name[36]; } gpt_entry_t; typedef struct _gpt_header_t { u64 signature; u32 revision; u32 size; u32 crc32; u32 res1; u64 my_lba; u64 alt_lba; u64 first_use_lba; u64 last_use_lba; u8 disk_guid[0x10]; u64 part_ent_lba; u32 num_part_ents; u32 part_ent_size; u32 part_ents_crc32; u8 res2[420]; } gpt_header_t; #define NX_GPT_FIRST_LBA 1 #define NX_GPT_NUM_BLOCKS 33 #define NX_EMMC_BLOCKSIZE 512 typedef struct _emmc_part_t { u32 lba_start; u32 lba_end; u64 attrs; s8 name[37]; } emmc_part_t; int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf); #endif ================================================ FILE: emummc/source/emmc/nx_sd.c ================================================ /* * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "nx_sd.h" #include "sdmmc.h" #include "sdmmc_driver.h" #include "../soc/gpio.h" #include "../libs/fatfs/ff.h" extern sdmmc_t sd_sdmmc; extern sdmmc_storage_t sd_storage; static u32 sd_mode = SD_UHS_SDR104; u32 nx_sd_mode_get() { return sd_mode; } int nx_sd_init_retry(bool power_cycle) { u32 bus_width = SDMMC_BUS_WIDTH_4; u32 type = SDHCI_TIMING_UHS_SDR104; // Power cycle SD card. if (power_cycle) { sd_mode--; sdmmc_storage_end(&sd_storage); } // Get init parameters. switch (sd_mode) { case SD_INIT_FAIL: // Reset to max. return 0; case SD_1BIT_HS25: bus_width = SDMMC_BUS_WIDTH_1; type = SDHCI_TIMING_SD_HS25; break; case SD_4BIT_HS25: type = SDHCI_TIMING_SD_HS25; break; case SD_UHS_SDR82: type = SDHCI_TIMING_UHS_SDR82; break; case SD_UHS_SDR104: type = SDHCI_TIMING_UHS_SDR104; break; default: sd_mode = SD_UHS_SDR104; } return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type); } bool nx_sd_initialize(bool power_cycle) { if (power_cycle) sdmmc_storage_end(&sd_storage); int res = !nx_sd_init_retry(false); while (true) { if (!res) return true; else { if (sd_mode == SD_INIT_FAIL) break; res = !nx_sd_init_retry(true); } } return false; } ================================================ FILE: emummc/source/emmc/nx_sd.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef NX_SD_H #define NX_SD_H #include "../utils/types.h" enum { SD_INIT_FAIL = 0, SD_1BIT_HS25 = 1, SD_4BIT_HS25 = 2, SD_UHS_SDR82 = 3, SD_UHS_SDR104 = 4 }; u32 nx_sd_get_mode(); int nx_sd_init_retry(bool power_cycle); bool nx_sd_initialize(bool power_cycle); #endif ================================================ FILE: emummc/source/emmc/sd.h ================================================ /* * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. */ #ifndef MMC_SD_H #define MMC_SD_H /* SD commands type argument response */ /* class 0 */ /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ #define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ #define SD_SWITCH_VOLTAGE 11 /* ac R1 */ /* class 10 */ #define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* class 5 */ #define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */ #define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */ /* Application commands */ #define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ #define SD_APP_SD_STATUS 13 /* adtc R1 */ #define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SET_CLR_CARD_DETECT 42 #define SD_APP_SEND_SCR 51 /* adtc R1 */ /* OCR bit definitions */ #define SD_OCR_S18R (1 << 24) /* 1.8V switching request */ #define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ #define SD_OCR_XPC (1 << 28) /* SDXC power control */ #define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ #define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ #define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ #define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ /* * SD_SWITCH argument format: * * [31] Check (0) or switch (1) * [30:24] Reserved (0) * [23:20] Function group 6 * [19:16] Function group 5 * [15:12] Function group 4 * [11:8] Function group 3 * [7:4] Function group 2 * [3:0] Function group 1 */ /* * SD_SEND_IF_COND argument format: * * [31:12] Reserved (0) * [11:8] Host Voltage Supply Flags * [7:0] Check Pattern (0xAA) */ /* * SCR field definitions */ #define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ #define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ #define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */ #define SD_SCR_BUS_WIDTH_1 (1<<0) #define SD_SCR_BUS_WIDTH_4 (1<<2) /* * SD bus widths */ #define SD_BUS_WIDTH_1 0 #define SD_BUS_WIDTH_4 2 /* * SD bus speeds */ #define UHS_SDR12_BUS_SPEED 0 #define HIGH_SPEED_BUS_SPEED 1 #define UHS_SDR25_BUS_SPEED 1 #define UHS_SDR50_BUS_SPEED 2 #define UHS_SDR104_BUS_SPEED 3 #define UHS_DDR50_BUS_SPEED 4 #define HS400_BUS_SPEED 5 #define SD_MODE_HIGH_SPEED (1 << HIGH_SPEED_BUS_SPEED) #define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED) #define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED) #define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED) #define SD_MODE_UHS_SDR104 (1 << UHS_SDR104_BUS_SPEED) #define SD_MODE_UHS_DDR50 (1 << UHS_DDR50_BUS_SPEED) #define SD_DRIVER_TYPE_B 0x01 #define SD_DRIVER_TYPE_A 0x02 #define SD_SET_CURRENT_LIMIT_200 0 #define SD_SET_CURRENT_LIMIT_400 1 #define SD_SET_CURRENT_LIMIT_600 2 #define SD_SET_CURRENT_LIMIT_800 3 #define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200) #define SD_MAX_CURRENT_400 (1 << SD_SET_CURRENT_LIMIT_400) #define SD_MAX_CURRENT_600 (1 << SD_SET_CURRENT_LIMIT_600) #define SD_MAX_CURRENT_800 (1 << SD_SET_CURRENT_LIMIT_800) /* * SD_SWITCH mode */ #define SD_SWITCH_CHECK 0 #define SD_SWITCH_SET 1 /* * SD_SWITCH function groups */ #define SD_SWITCH_GRP_ACCESS 0 /* * SD_SWITCH access modes */ #define SD_SWITCH_ACCESS_DEF 0 #define SD_SWITCH_ACCESS_HS 1 #endif /* LINUX_MMC_SD_H */ ================================================ FILE: emummc/source/emmc/sdmmc.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include <stdlib.h> #include <stdio.h> #include "sdmmc.h" #include "mmc.h" #include "nx_sd.h" #include "sd.h" #include "../utils/types.h" #include "../utils/util.h" #include "../utils/fatal.h" #include "../emuMMC/emummc.h" #define DPRINTF(...) //fprintf(stdout, __VA_ARGS__) sdmmc_accessor_t *_current_accessor = NULL; bool sdmmc_memcpy_buf = false; extern bool custom_driver; static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) { const u32 mask = (size < 32 ? 1 << size : 0) - 1; const u32 off = 3 - ((start) / 32); const u32 shft = (start) & 31; u32 res = resp[off] >> shft; if (size + shft > 32) res |= resp[off - 1] << ((32 - shft) % 32); return res & mask; } /* * Common functions for SD and MMC. */ // FS DMA calculations. intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors) { int dma_buf_idx = 0; char *_buf = (char *)buf; char *actual_buf_start = _buf; char *actual_buf_end = &_buf[512 * num_sectors]; char *dma_buffer_start = _this->parent->dmaBuffers[0].device_addr_buffer; if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[0].device_addr_buffer_size]) { dma_buf_idx = 0; } else { dma_buffer_start = _this->parent->dmaBuffers[1].device_addr_buffer; if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[1].device_addr_buffer_size]) { dma_buf_idx = 1; } else { dma_buffer_start = _this->parent->dmaBuffers[2].device_addr_buffer; if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[2].device_addr_buffer_size]) { dma_buf_idx = 2; } else { // If buffer is on a random heap return 0; } } } sdmmc_memcpy_buf = false; intptr_t admaaddr = (intptr_t)&_this->parent->dmaBuffers[dma_buf_idx].device_addr_buffer_masked[actual_buf_start - dma_buffer_start]; return admaaddr; } int sdmmc_calculate_dma_index(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors) { int dma_buf_idx = 0; char *_buf = (char *)buf; char *actual_buf_start = _buf; char *actual_buf_end = &_buf[512 * num_sectors]; char *dma_buffer_start = _this->parent->dmaBuffers[0].device_addr_buffer; if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[0].device_addr_buffer_size]) { dma_buf_idx = 0; } else { dma_buffer_start = _this->parent->dmaBuffers[1].device_addr_buffer; if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[1].device_addr_buffer_size]) { dma_buf_idx = 1; } else { dma_buffer_start = _this->parent->dmaBuffers[2].device_addr_buffer; if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[2].device_addr_buffer_size]) { dma_buf_idx = 2; } else { // If buffer is on a random heap return -1; } } } sdmmc_memcpy_buf = false; return dma_buf_idx; } int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors) { int dma_buf_idx = 0; int blkSize = num_sectors * 512; if (_this->parent->dmaBuffers[0].device_addr_buffer_size >= blkSize) { dma_buf_idx = 0; } else { if (_this->parent->dmaBuffers[1].device_addr_buffer_size >= blkSize) { dma_buf_idx = 1; } else { if (_this->parent->dmaBuffers[2].device_addr_buffer_size >= blkSize) { dma_buf_idx = 2; } else { // Can't find a fitting buffer return 0; } } } sdmmc_memcpy_buf = true; return dma_buf_idx; } static int _sdmmc_storage_check_result(u32 res) { //Error mask: //TODO: R1_SWITCH_ERROR can be skipped for certain card types. if (res & (R1_OUT_OF_RANGE | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR | R1_ERASE_SEQ_ERROR | R1_ERASE_PARAM | R1_WP_VIOLATION | R1_LOCK_UNLOCK_FAILED | R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND | R1_CARD_ECC_FAILED | R1_CC_ERROR | R1_ERROR | R1_CID_CSD_OVERWRITE | R1_WP_ERASE_SKIP | R1_ERASE_RESET | R1_SWITCH_ERROR)) return 0; // No errors. return 1; } static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state, u32 mask) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, cmd, arg, SDMMC_RSP_TYPE_1, check_busy); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 0; sdmmc_get_rsp(storage->sdmmc, resp, 4, SDMMC_RSP_TYPE_1); if (mask) *resp &= ~mask; if (_sdmmc_storage_check_result(*resp)) if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) return 1; return 0; } static int _sdmmc_storage_execute_cmd_type1(sdmmc_storage_t *storage, u32 cmd, u32 arg, u32 check_busy, u32 expected_state) { u32 tmp; return _sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, cmd, arg, check_busy, expected_state, 0); } static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) { sdmmc_cmd_t cmd; sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); } static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) { sdmmc_cmd_t cmd; sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) return 0; sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); return 1; } static int _sdmmc_storage_select_card(sdmmc_storage_t *storage) { return _sdmmc_storage_execute_cmd_type1(storage, MMC_SELECT_CARD, storage->rca << 16, 1, 0x10); } static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 0; sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); return 1; } static int _sdmmc_storage_set_blocklen(sdmmc_storage_t *storage, u32 blocklen) { return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_BLOCKLEN, blocklen, 0, R1_STATE_TRAN); } static int _sdmmc_storage_get_status(sdmmc_storage_t *storage, u32 *resp, u32 mask) { return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, MMC_SEND_STATUS, storage->rca << 16, 0, R1_STATE_TRAN, mask); } static int _sdmmc_storage_check_status(sdmmc_storage_t *storage) { u32 tmp; return _sdmmc_storage_get_status(storage, &tmp, 0); } static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write) { u32 tmp = 0; sdmmc_cmd_t cmdbuf; sdmmc_req_t reqbuf; sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0); reqbuf.buf = buf; reqbuf.num_sectors = num_sectors; reqbuf.blksize = 512; reqbuf.is_write = is_write; reqbuf.is_multi_block = 1; reqbuf.is_auto_cmd12 = 1; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out)) { sdmmc_stop_transmission(storage->sdmmc, &tmp); _sdmmc_storage_get_status(storage, &tmp, 0); return 0; } return 1; } int sdmmc_storage_end(sdmmc_storage_t *storage) { if (!_sdmmc_storage_go_idle_state(storage)) return 0; sdmmc_end(storage->sdmmc); storage->initialized = 0; return 1; } static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) { u8 *bbuf = (u8 *)buf; u32 sct_off = sector; u32 sct_total = num_sectors; bool first_reinit = true; // Exit if not initialized. if (!storage->initialized) return 0; while (sct_total) { u32 blkcnt = 0; // Retry 5 times if failed. u32 retries = 5; do { reinit_try: if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write)) goto out; else retries--; msleep(50); } while (retries); // Disk IO failure! Reinit SD Card to a lower speed. if (storage->sdmmc->id == SDMMC_1) { int res; if (first_reinit) res = nx_sd_initialize(true); else res = nx_sd_init_retry(true); // Reset values for a retry. blkcnt = 0; retries = 3; first_reinit = false; // If succesful reinit, restart xfer. if (res) { bbuf = (u8 *)buf; sct_off = sector; sct_total = num_sectors; goto reinit_try; } } // Failed. return 0; out: sct_off += blkcnt; sct_total -= blkcnt; bbuf += 512 * blkcnt; } return 1; } extern _sdmmc_accessor_sd sdmmc_accessor_sd; extern _sdmmc_accessor_nand sdmmc_accessor_nand; int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) { if (!custom_driver) { sdmmc_accessor_t *accessor_sd = sdmmc_accessor_sd(); sdmmc_accessor_t *accessor_nand = sdmmc_accessor_nand(); if (sdmmc_calculate_dma_addr(accessor_sd, buf, num_sectors)) { return !accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 1); } else { if (sdmmc_calculate_dma_addr(accessor_nand, buf, num_sectors)) { // buf is on the nand dma buffer int original_dma_idx = sdmmc_calculate_dma_index(accessor_nand, buf, num_sectors); sdmmc_dma_buffer_t *original_dma_buffer = &accessor_nand->parent->dmaBuffers[original_dma_idx]; // Next entry int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors) + 1; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = original_dma_buffer->device_addr_buffer; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = original_dma_buffer->device_addr_buffer_masked; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = original_dma_buffer->device_addr_buffer_size; u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 1); accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = 0; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = 0; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = 0; return !res; } else { // buf is on a heap int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors); void *dma_buf = &accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer[0]; u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, dma_buf, num_sectors * 512, 1); memcpy(buf, dma_buf, num_sectors * 512); return !res; } } } else { return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0); } } int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) { if (!custom_driver) { sdmmc_accessor_t *accessor_sd = sdmmc_accessor_sd(); sdmmc_accessor_t *accessor_nand = sdmmc_accessor_nand(); if (sdmmc_calculate_dma_addr(accessor_sd, buf, num_sectors)) { return !accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 0); } else { if (sdmmc_calculate_dma_addr(accessor_nand, buf, num_sectors)) { // buf is on the nand dma buffer int original_dma_idx = sdmmc_calculate_dma_index(accessor_nand, buf, num_sectors); sdmmc_dma_buffer_t *original_dma_buffer = &accessor_nand->parent->dmaBuffers[original_dma_idx]; // Next entry int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors) + 1; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = original_dma_buffer->device_addr_buffer; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = original_dma_buffer->device_addr_buffer_masked; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = original_dma_buffer->device_addr_buffer_size; u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 0); accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = 0; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = 0; accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = 0; return !res; } else { // buf is on a heap int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors); void *dma_buf = &accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer[0]; memcpy(dma_buf, buf, num_sectors * 512); u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, dma_buf, num_sectors * 512, 0); return !res; } } } else { return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1); } } /* * MMC specific functions. */ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u32 power) { sdmmc_cmd_t cmd; u32 arg = 0; switch (power) { case SDMMC_POWER_1_8: arg = SD_OCR_CCS | SD_OCR_VDD_18; break; case SDMMC_POWER_3_3: arg = SD_OCR_CCS | SD_OCR_VDD_27_34; break; default: return 0; } sdmmc_init_cmd(&cmd, MMC_SEND_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) return 0; return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3); } static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) { u64 timeout = get_tmr_ms() + 1500; while (1) { u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; if (cond & MMC_CARD_BUSY) { if (cond & SD_OCR_CCS) storage->has_sector_access = 1; return 1; } if (get_tmr_ms() > timeout) break; usleep(1000); } return 0; } static int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage) { return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, 0x10); } static void _mmc_storage_parse_cid(sdmmc_storage_t *storage) { u32 *raw_cid = (u32 *)&(storage->raw_cid); switch (storage->csd.mmca_vsn) { case 0: /* MMC v1.0 - v1.2 */ case 1: /* MMC v1.4 */ storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8); storage->cid.manfid = unstuff_bits(raw_cid, 104, 24); storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4); storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4); storage->cid.serial = unstuff_bits(raw_cid, 16, 24); break; case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2); storage->cid.oemid = unstuff_bits(raw_cid, 104, 8); storage->cid.prv = unstuff_bits(raw_cid, 48, 8); storage->cid.serial = unstuff_bits(raw_cid, 16, 32); break; default: break; } storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8); storage->cid.month = unstuff_bits(raw_cid, 12, 4); storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997; if (storage->ext_csd.rev >= 5) { if (storage->cid.year < 2010) storage->cid.year += 16; } } static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) { u32 *raw_csd = (u32 *)&(storage->raw_csd); storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); storage->csd.structure = unstuff_bits(raw_csd, 126, 2); storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); } static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) { storage->ext_csd.rev = buf[EXT_CSD_REV]; storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE]; storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE]; storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION]; storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT]; storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT]; storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT]; storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT]; storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN]; storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS]; storage->ext_csd.pre_eol_info = buf[EXT_CSD_PRE_EOL_INFO]; storage->ext_csd.dev_life_est_a = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; storage->ext_csd.dev_life_est_b = buf[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT]; } static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, MMC_SEND_EXT_CSD, 0, SDMMC_RSP_TYPE_1, 0); sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.blksize = 512; reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); _mmc_storage_parse_ext_csd(storage, buf); return _sdmmc_storage_check_result(tmp); } static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg) { return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, 0x10); } static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) { if (bus_width == SDMMC_BUS_WIDTH_1) return 1; u32 arg = 0; switch (bus_width) { case SDMMC_BUS_WIDTH_4: arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); break; case SDMMC_BUS_WIDTH_8: arg = SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8); break; } if (_mmc_storage_switch(storage, arg)) if (_sdmmc_storage_check_status(storage)) { sdmmc_set_bus_width(storage->sdmmc, bus_width); return 1; } return 0; } static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) return 0; if (check && !_sdmmc_storage_check_status(storage)) return 0; if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS52)) return 0; DPRINTF("[MMC] switched to HS\n"); storage->csd.busspeed = 52; if (check || _sdmmc_storage_check_status(storage)) return 1; return 0; } static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200))) return 0; if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS200)) return 0; if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS200, MMC_SEND_TUNING_BLOCK_HS200)) return 0; DPRINTF("[MMC] switched to HS200\n"); storage->csd.busspeed = 200; return _sdmmc_storage_check_status(storage); } static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) { if (!_mmc_storage_enable_HS200(storage)) return 0; sdmmc_save_tap_value(storage->sdmmc); if (!_mmc_storage_enable_HS(storage, 0)) return 0; if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8))) return 0; if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) return 0; if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_HS400)) return 0; DPRINTF("[MMC] switched to HS400\n"); storage->csd.busspeed = 400; return _sdmmc_storage_check_status(storage); } static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type) { if (sdmmc_get_io_power(storage->sdmmc) != SDMMC_POWER_1_8) goto out; if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == SDHCI_TIMING_MMC_HS400) return _mmc_storage_enable_HS400(storage); if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_4 && card_type & EXT_CSD_CARD_TYPE_HS200_1_8V && (type == SDHCI_TIMING_MMC_HS400 || type == SDHCI_TIMING_MMC_HS200))) return _mmc_storage_enable_HS200(storage); out: if (card_type & EXT_CSD_CARD_TYPE_HS_52) return _mmc_storage_enable_HS(storage, 1); return 1; } static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) return 0; return _sdmmc_storage_check_status(storage); } int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; storage->rca = 2; //TODO: this could be a config item. if (!sdmmc_init(sdmmc, SDMMC_4, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_MMC_ID, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[MMC] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; DPRINTF("[MMC] went to idle state\n"); if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8)) return 0; DPRINTF("[MMC] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; DPRINTF("[MMC] got cid\n"); if (!_mmc_storage_set_relative_addr(storage)) return 0; DPRINTF("[MMC] set relative addr\n"); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_MMC_LS26)) return 0; DPRINTF("[MMC] after setup clock\n"); if (!_sdmmc_storage_select_card(storage)) return 0; DPRINTF("[MMC] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; DPRINTF("[MMC] set blocklen to 512\n"); u32 *csd = (u32 *)storage->raw_csd; //Check system specification version, only version 4.0 and later support below features. if (unstuff_bits(csd, 122, 4) < CSD_SPEC_VER_4) { storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2); return 1; } if (!_mmc_storage_switch_buswidth(storage, bus_width)) return 0; DPRINTF("[MMC] switched buswidth\n"); u8 buf[512]; memset(buf, 0, sizeof(buf)); if (!_mmc_storage_get_ext_csd(storage, buf)) return 0; DPRINTF("[MMC] got ext_csd\n"); _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd /* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status. Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end(). Additionally this works only when we put the device in idle mode which we don't after enabling it. */ if (0 && storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2)) { _mmc_storage_enable_bkops(storage); DPRINTF("[MMC] BKOPS enabled\n"); } if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; DPRINTF("[MMC] succesfully switched to HS mode\n"); sdmmc_card_clock_powersave(storage->sdmmc, SDMMC_POWER_SAVE_ENABLE); storage->initialized = 1; return 1; } int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition))) return 0; if (!_sdmmc_storage_check_status(storage)) return 0; storage->partition = partition; return 1; } /* * SD specific functions. */ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_state, u32 mask, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) { u32 tmp; if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) return 0; return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); } static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp, u32 cmd, u32 arg, u32 check_busy, u32 expected_state) { if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN)) return 0; return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); } static int _sd_storage_send_if_cond(sdmmc_storage_t *storage) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, 0x1AA, SDMMC_RSP_TYPE_5, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 1; // The SD Card is version 1.X u32 resp = 0; if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5)) return 2; return (resp & 0xFF) == 0xAA ? 0 : 2; } static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int bus_low_voltage_support) { sdmmc_cmd_t cmdbuf; // Support for Current > 150mA u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0; // Support for handling block-addressed SDHC cards arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0; // Support for 1.8V arg |= (bus_low_voltage_support & ~is_version_1 & 1) ? SD_OCR_S18R : 0; // This is needed for most cards. Do not set bit7 even if 1.8V is supported. arg |= SD_OCR_VDD_32_33; sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) return 0; return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, int bus_low_voltage_support) { u64 timeout = get_tmr_ms() + 1500; while (1) { u32 cond = 0; if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, bus_low_voltage_support)) break; if (cond & MMC_CARD_BUSY) { DPRINTF("[SD] cond: %08X, lv: %d\n", cond, bus_low_voltage_support); if (cond & SD_OCR_CCS) storage->has_sector_access = 1; // Check if card supports 1.8V signaling. if (cond & SD_ROCR_S18A && bus_low_voltage_support) { //The low voltage regulator configuration is valid for SDMMC1 only. if (storage->sdmmc->id == SDMMC_1 && _sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) { if (!sdmmc_enable_low_voltage(storage->sdmmc)) return 0; storage->is_low_voltage = 1; DPRINTF("-> switched to low voltage\n"); } } else { DPRINTF("[SD] no low voltage support\n"); } return 1; } if (get_tmr_ms() > timeout) break; msleep(10); // Needs to be at least 10ms for some SD Cards } return 0; } static int _sd_storage_get_rca(sdmmc_storage_t *storage) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_SEND_RELATIVE_ADDR, 0, SDMMC_RSP_TYPE_4, 0); u64 timeout = get_tmr_ms() + 1500; while (1) { if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) break; u32 resp = 0; if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_4)) break; if (resp >> 16) { storage->rca = resp >> 16; return 1; } if (get_tmr_ms() > timeout) break; usleep(1000); } return 0; } static void _sd_storage_parse_scr(sdmmc_storage_t *storage) { // unstuff_bits can parse only 4 u32 u32 resp[4]; resp[3] = *(u32 *)&storage->raw_scr[4]; resp[2] = *(u32 *)&storage->raw_scr[0]; storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); storage->scr.bus_widths = unstuff_bits(resp, 48, 4); if (storage->scr.sda_vsn == SCR_SPEC_VER_2) /* Check if Physical Layer Spec v3.0 is supported */ storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); if (storage->scr.sda_spec3) storage->scr.cmds = unstuff_bits(resp, 32, 2); } int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_APP_SEND_SCR, 0, SDMMC_RSP_TYPE_1, 0); sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.blksize = 8; reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); //Prepare buffer for unstuff_bits for (int i = 0; i < 8; i+=4) { storage->raw_scr[i + 3] = buf[i]; storage->raw_scr[i + 2] = buf[i + 1]; storage->raw_scr[i + 1] = buf[i + 2]; storage->raw_scr[i] = buf[i + 3]; } _sd_storage_parse_scr(storage); return _sdmmc_storage_check_result(tmp); } int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) { sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, SD_SWITCH, 0xFFFFFF, SDMMC_RSP_TYPE_1, 0); sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.blksize = 64; reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_storage_check_result(tmp); } int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int group, u32 arg) { sdmmc_cmd_t cmdbuf; u32 switchcmd = mode << 31 | 0x00FFFFFF; switchcmd &= ~(0xF << (group * 4)); switchcmd |= arg << (group * 4); sdmmc_init_cmd(&cmdbuf, SD_SWITCH, switchcmd, SDMMC_RSP_TYPE_1, 0); sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.blksize = 64; reqbuf.num_sectors = 1; reqbuf.is_write = 0; reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) return 0; u32 tmp = 0; sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_storage_check_result(tmp); } void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u16 current_limit, u8 *buf) { u32 pwr = SD_SET_CURRENT_LIMIT_200; if (current_limit & SD_MAX_CURRENT_800) pwr = SD_SET_CURRENT_LIMIT_800; else if (current_limit & SD_MAX_CURRENT_600) pwr = SD_SET_CURRENT_LIMIT_600; else if (current_limit & SD_MAX_CURRENT_400) pwr = SD_SET_CURRENT_LIMIT_400; _sd_storage_switch(storage, buf, SD_SWITCH_SET, 3, pwr); if (((buf[15] >> 4) & 0x0F) == pwr) { switch (pwr) { case SD_SET_CURRENT_LIMIT_800: DPRINTF("[SD] power limit raised to 800mA\n"); break; case SD_SET_CURRENT_LIMIT_600: DPRINTF("[SD] power limit raised to 600mA\n"); break; case SD_SET_CURRENT_LIMIT_400: DPRINTF("[SD] power limit raised to 400mA\n"); break; default: case SD_SET_CURRENT_LIMIT_200: DPRINTF("[SD] power limit defaulted to 200mA\n"); break; } } } int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) return 0; DPRINTF("[SD] supports (U)HS mode: %d\n", buf[16] & 0xF); u32 type_out = buf[16] & 0xF; if (type_out != hs_type) return 0; DPRINTF("[SD] supports selected (U)HS mode\n"); u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; DPRINTF("[SD] total max current: %d\n", total_pwr_consumption); if (total_pwr_consumption <= 800) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_SET, 0, hs_type)) return 0; if (type_out != (buf[16] & 0xF)) return 0; return 1; } DPRINTF("[SD] card max current over limit\n"); return 0; } int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) { if (sdmmc_get_bus_width(storage->sdmmc) != SDMMC_BUS_WIDTH_4) return 0; if (!_sd_storage_switch_get(storage, buf)) return 0; //gfx_hexdump(0, (u8 *)buf, 64); u8 access_mode = buf[13]; u16 current_limit = buf[7] | buf[6] << 8; DPRINTF("[SD] access: %02X, current: %02X\n", access_mode, current_limit); // Try to raise the current limit to let the card perform better. _sd_storage_set_current_limit(storage, current_limit, buf); u32 hs_type = 0; switch (type) { case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR82: // Fall through if not supported. if (access_mode & SD_MODE_UHS_SDR104) { hs_type = UHS_SDR104_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR104\n"); switch (type) { case SDHCI_TIMING_UHS_SDR104: storage->csd.busspeed = 104; break; case SDHCI_TIMING_UHS_SDR82: storage->csd.busspeed = 82; break; } break; } case SDHCI_TIMING_UHS_SDR50: if (access_mode & SD_MODE_UHS_SDR50) { type = SDHCI_TIMING_UHS_SDR50; hs_type = UHS_SDR50_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } case SDHCI_TIMING_UHS_SDR25: if (access_mode & SD_MODE_UHS_SDR25) { type = SDHCI_TIMING_UHS_SDR25; hs_type = UHS_SDR25_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR25\n"); storage->csd.busspeed = 25; break; } case SDHCI_TIMING_UHS_SDR12: if (!(access_mode & SD_MODE_UHS_SDR12)) return 0; type = SDHCI_TIMING_UHS_SDR12; hs_type = UHS_SDR12_BUS_SPEED; DPRINTF("[SD] bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; default: return 0; break; } if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) return 0; DPRINTF("[SD] card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; DPRINTF("[SD] after setup clock\n"); if (!sdmmc_tuning_execute(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; DPRINTF("[SD] after tuning\n"); return _sdmmc_storage_check_status(storage); } int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) { if (!_sd_storage_switch_get(storage, buf)) return 0; //gfx_hexdump(0, (u8 *)buf, 64); u8 access_mode = buf[13]; u16 current_limit = buf[7] | buf[6] << 8; // Try to raise the current limit to let the card perform better. _sd_storage_set_current_limit(storage, current_limit, buf); if (!(access_mode & SD_MODE_HIGH_SPEED)) return 1; if (!_sd_storage_enable_highspeed(storage, HIGH_SPEED_BUS_SPEED, buf)) return 0; if (!_sdmmc_storage_check_status(storage)) return 0; return sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_HS25); } static void _sd_storage_parse_cid(sdmmc_storage_t *storage) { u32 *raw_cid = (u32 *)&(storage->raw_cid); storage->cid.manfid = unstuff_bits(raw_cid, 120, 8); storage->cid.oemid = unstuff_bits(raw_cid, 104, 16); storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8); storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8); storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8); storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8); storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8); storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4); storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4); storage->cid.serial = unstuff_bits(raw_cid, 24, 32); storage->cid.month = unstuff_bits(raw_cid, 8, 4); storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000; } static void _sd_storage_parse_csd(sdmmc_storage_t *storage) { u32 *raw_csd = (u32 *)&(storage->raw_csd); storage->csd.structure = unstuff_bits(raw_csd, 126, 2); storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); storage->csd.write_protect = unstuff_bits(raw_csd, 12, 2); switch(storage->csd.structure) { case 0: storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); break; case 1: storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22)); storage->csd.capacity = storage->csd.c_size << 10; storage->csd.read_blkbits = 9; break; } } static bool _sdmmc_storage_get_low_voltage_support(u32 bus_width, u32 type) { switch (type) { case SDHCI_TIMING_UHS_SDR12: case SDHCI_TIMING_UHS_SDR25: case SDHCI_TIMING_UHS_SDR50: case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR82: case SDHCI_TIMING_UHS_DDR50: if (bus_width == SDMMC_BUS_WIDTH_4) return true; default: return false; } } int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { u8 buf[512]; int is_version_1 = 0; memset(buf, 0, sizeof(buf)); memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; if (!sdmmc_init(sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[SD] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; DPRINTF("[SD] went to idle state\n"); is_version_1 = _sd_storage_send_if_cond(storage); if (is_version_1 == 2) return 0; DPRINTF("[SD] after send if cond\n"); bool bus_low_voltage_support = _sdmmc_storage_get_low_voltage_support(bus_width, type); if (!_sd_storage_get_op_cond(storage, is_version_1, bus_low_voltage_support)) return 0; DPRINTF("[SD] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; DPRINTF("[SD] got cid\n"); _sd_storage_parse_cid(storage); if (!_sd_storage_get_rca(storage)) return 0; DPRINTF("[SD] got rca (= %04X)\n", storage->rca); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; DPRINTF("[SD] got csd\n"); //Parse CSD. _sd_storage_parse_csd(storage); switch (storage->csd.structure) { case 0: storage->sec_cnt = storage->csd.capacity; break; case 1: storage->sec_cnt = storage->csd.c_size << 10; break; default: DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); break; } if (!storage->is_low_voltage) { if (!sdmmc_setup_clock(storage->sdmmc, SDHCI_TIMING_SD_DS12)) return 0; DPRINTF("[SD] after setup clock\n"); } if (!_sdmmc_storage_select_card(storage)) return 0; DPRINTF("[SD] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; DPRINTF("[SD] set blocklen to 512\n"); u32 tmp = 0; if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) return 0; DPRINTF("[SD] cleared card detect\n"); if (!_sd_storage_get_scr(storage, buf)) return 0; //gfx_hexdump(0, storage->raw_scr, 8); DPRINTF("[SD] got scr\n"); // Check if card supports a wider bus and if it's not SD Version 1.X if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) { if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) return 0; sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); DPRINTF("[SD] switched to wide bus width\n"); } else { DPRINTF("[SD] SD does not support wide bus width\n"); } if (storage->is_low_voltage) { if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) return 0; DPRINTF("[SD] enabled UHS\n"); sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); } else if (type != SDHCI_TIMING_SD_DS12 && (storage->scr.sda_vsn & 0xF) != 0) { if (!_sd_storage_enable_hs_high_volt(storage, buf)) return 0; DPRINTF("[SD] enabled HS\n"); switch (bus_width) { case SDMMC_BUS_WIDTH_4: storage->csd.busspeed = 25; break; case SDMMC_BUS_WIDTH_1: storage->csd.busspeed = 6; break; } } storage->initialized = 1; return 1; } /* * Gamecard specific functions. */ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) { u32 resp; sdmmc_cmd_t cmdbuf; sdmmc_init_cmd(&cmdbuf, 60, 0, SDMMC_RSP_TYPE_1, 1); sdmmc_req_t reqbuf; reqbuf.buf = buf; reqbuf.blksize = 64; reqbuf.num_sectors = 1; reqbuf.is_write = 1; reqbuf.is_multi_block = 0; reqbuf.is_auto_cmd12 = 0; if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, 0)) { sdmmc_stop_transmission(storage->sdmmc, &resp); return 0; } if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1)) return 0; if (!_sdmmc_storage_check_result(resp)) return 0; return _sdmmc_storage_check_status(storage); } int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) { memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS102, SDMMC_POWER_SAVE_DISABLE)) return 0; DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!sdmmc_tuning_execute(storage->sdmmc, SDHCI_TIMING_MMC_HS102, MMC_SEND_TUNING_BLOCK_HS200)) return 0; DPRINTF("[gc] after tuning\n"); sdmmc_card_clock_powersave(sdmmc, SDMMC_POWER_SAVE_ENABLE); storage->initialized = 1; return 1; } ================================================ FILE: emummc/source/emmc/sdmmc.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SDMMC_H_ #define _SDMMC_H_ #include "../utils/types.h" #include "../FS/FS.h" #include "sdmmc_driver.h" typedef struct _mmc_cid { u32 manfid; u8 prod_name[8]; u8 card_bga; u8 prv; u32 serial; u16 oemid; u16 year; u8 hwrev; u8 fwrev; u8 month; } mmc_cid_t; typedef struct _mmc_csd { u8 structure; u8 mmca_vsn; u16 cmdclass; u32 c_size; u32 r2w_factor; u32 max_dtr; u32 erase_size; /* In sectors */ u32 read_blkbits; u32 write_blkbits; u32 capacity; u8 write_protect; u16 busspeed; } mmc_csd_t; typedef struct _mmc_ext_csd { u32 sectors; int bkops; /* background support bit */ int bkops_en; /* manual bkops enable bit */ u8 rev; u8 ext_struct; /* 194 */ u8 card_type; /* 196 */ u8 bkops_status; /* 246 */ u8 pre_eol_info; u8 dev_life_est_a; u8 dev_life_est_b; u8 boot_mult; u8 rpmb_mult; u16 dev_version; } mmc_ext_csd_t; typedef struct _sd_scr { u8 sda_vsn; u8 sda_spec3; u8 bus_widths; u8 cmds; } sd_scr_t; typedef struct _sd_ssr { u8 bus_width; u8 speed_class; u8 uhs_grade; u8 video_class; u8 app_class; u32 protected_size; } sd_ssr_t; /*! SDMMC storage context. */ typedef struct _sdmmc_storage_t { sdmmc_t *sdmmc; u32 rca; int has_sector_access; u32 sec_cnt; int is_low_voltage; u32 partition; u8 raw_cid[0x10]; u8 raw_csd[0x10]; u8 raw_scr[8]; mmc_cid_t cid; mmc_csd_t csd; mmc_ext_csd_t ext_csd; sd_scr_t scr; int initialized; } sdmmc_storage_t; extern sdmmc_accessor_t *_current_accessor; extern bool sdmmc_memcpy_buf; int sdmmc_storage_end(sdmmc_storage_t *storage); int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type); int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors); int sdmmc_calculate_dma_index(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors); int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors); #endif ================================================ FILE: emummc/source/emmc/sdmmc_driver.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include "mmc.h" #include "sdmmc.h" #include "../nx/cache.h" #include "../power/max7762x.h" #include "../soc/clock.h" #include "../soc/gpio.h" #include "../soc/pinmux.h" #include "../soc/pmc.h" #include "../soc/t210.h" #include "../utils/fatal.h" #include "../utils/types.h" #include "../utils/util.h" #define DPRINTF(...) /*! SCMMC controller base addresses. */ static const u64 _sdmmc_bases[4] = { 0x700B0000, 0x700B0200, 0x700B0400, 0x700B0600, }; int sdmmc_get_io_power(sdmmc_t *sdmmc) { u32 p = sdmmc->regs->pwrcon; if (!(p & SDHCI_POWER_ON)) return SDMMC_POWER_OFF; if (p & SDHCI_POWER_180) return SDMMC_POWER_1_8; if (p & SDHCI_POWER_330) return SDMMC_POWER_3_3; return -1; } static int _sdmmc_set_io_power(sdmmc_t *sdmmc, u32 power) { switch (power) { case SDMMC_POWER_OFF: sdmmc->regs->pwrcon &= ~SDHCI_POWER_ON; break; case SDMMC_POWER_1_8: sdmmc->regs->pwrcon = SDHCI_POWER_180; break; case SDMMC_POWER_3_3: sdmmc->regs->pwrcon = SDHCI_POWER_330; break; default: return 0; } if (power != SDMMC_POWER_OFF) sdmmc->regs->pwrcon |= SDHCI_POWER_ON; return 1; } u32 sdmmc_get_bus_width(sdmmc_t *sdmmc) { u32 h = sdmmc->regs->hostctl; if (h & SDHCI_CTRL_8BITBUS) return SDMMC_BUS_WIDTH_8; if (h & SDHCI_CTRL_4BITBUS) return SDMMC_BUS_WIDTH_4; return SDMMC_BUS_WIDTH_1; } void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width) { u32 host_control = sdmmc->regs->hostctl & ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS); if (bus_width == SDMMC_BUS_WIDTH_1) sdmmc->regs->hostctl = host_control; else if (bus_width == SDMMC_BUS_WIDTH_4) sdmmc->regs->hostctl = host_control | SDHCI_CTRL_4BITBUS; else if (bus_width == SDMMC_BUS_WIDTH_8) sdmmc->regs->hostctl = host_control | SDHCI_CTRL_8BITBUS; } void sdmmc_save_tap_value(sdmmc_t *sdmmc) { sdmmc->venclkctl_tap = sdmmc->regs->venclkctl >> 16; sdmmc->venclkctl_set = 1; } static int _sdmmc_config_tap_val(sdmmc_t *sdmmc, u32 type) { const u32 dqs_trim_val = 0x28; const u32 tap_values_t210[] = { 4, 0, 3, 0 }; u32 tap_val = 0; if (type == SDHCI_TIMING_MMC_HS400) sdmmc->regs->vencapover = (sdmmc->regs->vencapover & 0xFFFFC0FF) | (dqs_trim_val << 8); sdmmc->regs->ventunctl0 &= ~TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; if (type == SDHCI_TIMING_MMC_HS400) { if (!sdmmc->venclkctl_set) return 0; tap_val = sdmmc->venclkctl_tap; } else tap_val = sdmmc->t210b01 ? 11 : tap_values_t210[sdmmc->id]; sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xFF00FFFF) | (tap_val << 16); return 1; } static int _sdmmc_commit_changes(sdmmc_t *sdmmc) { return sdmmc->regs->clkcon; } static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power) { _sdmmc_commit_changes(sdmmc); switch (sdmmc->id) { case SDMMC_1: // 33 Ohm 2X Driver. if (power == SDMMC_POWER_OFF) break; u32 sdmmc1_pad_cfg = APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xF8080FFF; if (sdmmc->t210b01) sdmmc1_pad_cfg |= (0x808 << 12); // Up: 8, Dn: 8. For 33 ohm. else if (power == SDMMC_POWER_1_8) sdmmc1_pad_cfg |= (0xB0F << 12); // Up: 11, Dn: 15. For 33 ohm. else if (power == SDMMC_POWER_3_3) sdmmc1_pad_cfg |= (0xC0C << 12); // Up: 12, Dn: 12. For 33 ohm. APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = sdmmc1_pad_cfg; (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. break; case SDMMC_2: if (sdmmc->t210b01) APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xF8080FFF) | 0xA0A000; else APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) & 0xFFFFC003) | 0x1040; // PU:16, PD:16. (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); break; case SDMMC_4: // 50 Ohm 2X Driver. PU:16, PD:16, B01: PU:10, PD:10. APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0xFFFFC003) | (sdmmc->t210b01 ? 0xA28 : 0x1040); (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. break; } } static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) { bool should_enable_sd_clock = false; if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) { should_enable_sd_clock = true; sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } // Enable E_INPUT power. if (!(sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD)) { sdmmc->regs->sdmemcmppadctl |= TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; _sdmmc_commit_changes(sdmmc); usleep(1); } // Enable auto calibration and start auto configuration. sdmmc->regs->autocalcfg |= TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE | TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START; _sdmmc_commit_changes(sdmmc); usleep(2); u64 timeout = get_tmr_ms() + 10; while (sdmmc->regs->autocalsts & TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE) { if (get_tmr_ms() > timeout) { timeout = 0; // Set timeout to 0 if we timed out. break; } } #if 0 // Check if Comp pad is open or short to ground. // SDMMC1: CZ pads - T210/T210B01: 7-bit/5-bit. SDMMC2/4: LV_CZ pads - 5-bit. u8 code_mask = (sdmmc->t210b01 || sdmmc->id != SDMMC_1) ? 0x1F : 0x7F; u8 autocal_pu_status = sdmmc->regs->autocalsts & code_mask; if (!autocal_pu_status) EPRINTF("SDMMC: Comp Pad short to gnd!"); else if (autocal_pu_status == code_mask) EPRINTF("SDMMC: Comp Pad open!"); #endif // In case auto calibration fails, we load suggested standard values. if (!timeout) { _sdmmc_pad_config_fallback(sdmmc, power); sdmmc->regs->autocalcfg &= ~TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE; } // Disable E_INPUT to conserve power. sdmmc->regs->sdmemcmppadctl &= ~TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD; if(should_enable_sd_clock) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } static int _sdmmc_dll_cal_execute(sdmmc_t *sdmmc) { int result = 1, should_disable_sd_clock = 0; if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) { should_disable_sd_clock = 1; sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } sdmmc->regs->vendllcalcfg |= TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE; _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 5; while (sdmmc->regs->vendllcalcfg & TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE) { if (get_tmr_ms() > timeout) { result = 0; goto out; } } timeout = get_tmr_ms() + 10; while (sdmmc->regs->vendllcalcfgsts & TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE) { if (get_tmr_ms() > timeout) { result = 0; goto out; } } out:; if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return result; } static void _sdmmc_reset(sdmmc_t *sdmmc) { sdmmc->regs->swrst |= SDHCI_RESET_CMD | SDHCI_RESET_DATA; _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 2000; while ((sdmmc->regs->swrst & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) && get_tmr_ms() < timeout) ; } static void _sdmmc_reset_all(sdmmc_t *sdmmc) { sdmmc->regs->swrst |= SDHCI_RESET_ALL; _sdmmc_commit_changes(sdmmc); u32 timeout = get_tmr_ms() + 2000;//100ms while ((sdmmc->regs->swrst & SDHCI_RESET_ALL) && get_tmr_ms() < timeout) ; } int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) { // Disable the SD clock if it was enabled, and reenable it later. bool should_enable_sd_clock = false; if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) { should_enable_sd_clock = true; sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } _sdmmc_config_tap_val(sdmmc, type); _sdmmc_reset(sdmmc); switch (type) { case SDHCI_TIMING_MMC_ID: case SDHCI_TIMING_MMC_LS26: case SDHCI_TIMING_SD_ID: case SDHCI_TIMING_SD_DS12: sdmmc->regs->hostctl &= ~SDHCI_CTRL_HISPD; sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; case SDHCI_TIMING_MMC_HS52: case SDHCI_TIMING_SD_HS25: sdmmc->regs->hostctl |= SDHCI_CTRL_HISPD; sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_VDD_180; break; case SDHCI_TIMING_MMC_HS200: case SDHCI_TIMING_UHS_SDR50: // T210 Errata for SDR50, the host must be set to SDR104. case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR82: case SDHCI_TIMING_UHS_DDR50: case SDHCI_TIMING_MMC_HS102: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case SDHCI_TIMING_MMC_HS400: // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case SDHCI_TIMING_UHS_SDR25: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR25_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case SDHCI_TIMING_UHS_SDR12: sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR12_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; } _sdmmc_commit_changes(sdmmc); u32 clock; u16 divisor; clock_sdmmc_get_card_clock_div(&clock, &divisor, type); clock_sdmmc_config_clock_source(&clock, sdmmc->id, clock); sdmmc->divisor = (clock + divisor - 1) / divisor; //if divisor != 1 && divisor << 31 -> error u16 div = divisor >> 1; divisor = 0; if (div > 0xFF) divisor = div >> SDHCI_DIVIDER_SHIFT; sdmmc->regs->clkcon = (sdmmc->regs->clkcon & ~(SDHCI_DIV_MASK | SDHCI_DIV_HI_MASK)) | (div << SDHCI_DIVIDER_SHIFT) | (divisor << SDHCI_DIVIDER_HI_SHIFT); // Enable the SD clock again. if (should_enable_sd_clock) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; if (type == SDHCI_TIMING_MMC_HS400) return _sdmmc_dll_cal_execute(sdmmc); return 1; } static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc) { // Recalibrate conditionally. if (sdmmc->manual_cal && !sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); if (!sdmmc->powersave_enabled) { if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } sdmmc->card_clock_enabled = 1; } static void _sdmmc_sd_clock_disable(sdmmc_t *sdmmc) { sdmmc->card_clock_enabled = 0; sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; } void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable) { // Recalibrate periodically for SDMMC1. if (sdmmc->manual_cal && !powersave_enable && sdmmc->card_clock_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); sdmmc->powersave_enabled = powersave_enable; if (powersave_enable) { if (sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return; } if (sdmmc->card_clock_enabled) if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; } static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) { switch (type) { case SDMMC_RSP_TYPE_1: case SDMMC_RSP_TYPE_3: case SDMMC_RSP_TYPE_4: case SDMMC_RSP_TYPE_5: if (size < 4) return 0; rsp[0] = sdmmc->regs->rspreg0; break; case SDMMC_RSP_TYPE_2: if (size < 0x10) return 0; // CRC is stripped, so shifting is needed. u32 tempreg; for (int i = 0; i < 4; i++) { switch(i) { case 0: tempreg = sdmmc->regs->rspreg3; break; case 1: tempreg = sdmmc->regs->rspreg2; break; case 2: tempreg = sdmmc->regs->rspreg1; break; case 3: tempreg = sdmmc->regs->rspreg0; break; } rsp[i] = tempreg << 8; if (i != 0) rsp[i - 1] |= (tempreg >> 24) & 0xFF; } break; default: return 0; } return 1; } int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type) { if (!rsp || sdmmc->expected_rsp_type != type) return 0; switch (type) { case SDMMC_RSP_TYPE_1: case SDMMC_RSP_TYPE_3: case SDMMC_RSP_TYPE_4: case SDMMC_RSP_TYPE_5: if (size < 4) return 0; rsp[0] = sdmmc->rsp[0]; break; case SDMMC_RSP_TYPE_2: if (size < 0x10) return 0; rsp[0] = sdmmc->rsp[0]; rsp[1] = sdmmc->rsp[1]; rsp[2] = sdmmc->rsp[2]; rsp[3] = sdmmc->rsp[3]; break; default: return 0; } return 1; } static int _sdmmc_wait_cmd_data_inhibit(sdmmc_t *sdmmc, bool wait_dat) { _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 2000; while(sdmmc->regs->prnsts & SDHCI_CMD_INHIBIT) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); return 0; } if (wait_dat) { timeout = get_tmr_ms() + 2000; while (sdmmc->regs->prnsts & SDHCI_DATA_INHIBIT) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); return 0; } } return 1; } static int _sdmmc_wait_card_busy(sdmmc_t *sdmmc) { _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 2000; while (!(sdmmc->regs->prnsts & SDHCI_DATA_0_LVL_MASK)) if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); return 0; } return 1; } static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc) { switch (sdmmc_get_bus_width(sdmmc)) { case SDMMC_BUS_WIDTH_1: return 0; case SDMMC_BUS_WIDTH_4: sdmmc->regs->blksize = 64; break; case SDMMC_BUS_WIDTH_8: sdmmc->regs->blksize = 128; break; } sdmmc->regs->blkcnt = 1; sdmmc->regs->trnmod = SDHCI_TRNS_READ; return 1; } static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present) { u16 cmdflags = 0; switch (cmd->rsp_type) { case SDMMC_RSP_TYPE_0: break; case SDMMC_RSP_TYPE_1: case SDMMC_RSP_TYPE_4: case SDMMC_RSP_TYPE_5: if (cmd->check_busy) cmdflags = SDHCI_CMD_RESP_LEN48_BUSY | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; else cmdflags = SDHCI_CMD_RESP_LEN48 | SDHCI_CMD_INDEX | SDHCI_CMD_CRC; break; case SDMMC_RSP_TYPE_2: cmdflags = SDHCI_CMD_RESP_LEN136 | SDHCI_CMD_CRC; break; case SDMMC_RSP_TYPE_3: cmdflags = SDHCI_CMD_RESP_LEN48; break; default: return 0; } if (is_data_present) cmdflags |= SDHCI_CMD_DATA; sdmmc->regs->argument = cmd->arg; sdmmc->regs->cmdreg = (cmd->cmd << 8) | cmdflags; return 1; } static void _sdmmc_send_tuning_cmd(sdmmc_t *sdmmc, u32 cmd) { sdmmc_cmd_t cmdbuf; cmdbuf.cmd = cmd; cmdbuf.arg = 0; cmdbuf.rsp_type = SDMMC_RSP_TYPE_1; cmdbuf.check_busy = 0; _sdmmc_send_cmd(sdmmc, &cmdbuf, true); } static int _sdmmc_tuning_execute_once(sdmmc_t *sdmmc, u32 cmd) { if (sdmmc->powersave_enabled) return 0; if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, true)) return 0; _sdmmc_setup_read_small_block(sdmmc); sdmmc->regs->norintstsen |= SDHCI_INT_DATA_AVAIL; sdmmc->regs->norintsts = sdmmc->regs->norintsts; sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; _sdmmc_send_tuning_cmd(sdmmc, cmd); _sdmmc_commit_changes(sdmmc); usleep(1); _sdmmc_reset(sdmmc); sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_us() + 5000; while (get_tmr_us() < timeout) { if (sdmmc->regs->norintsts & SDHCI_INT_DATA_AVAIL) { sdmmc->regs->norintsts = SDHCI_INT_DATA_AVAIL; sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; _sdmmc_commit_changes(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 1; } } _sdmmc_reset(sdmmc); sdmmc->regs->norintstsen &= ~SDHCI_INT_DATA_AVAIL; _sdmmc_commit_changes(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); return 0; } int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd) { u32 max = 0, flag = 0; switch (type) { case SDHCI_TIMING_MMC_HS200: case SDHCI_TIMING_MMC_HS400: case SDHCI_TIMING_UHS_SDR104: case SDHCI_TIMING_UHS_SDR82: max = 128; flag = (2 << 13); // 128 iterations. break; case SDHCI_TIMING_UHS_SDR50: case SDHCI_TIMING_UHS_DDR50: case SDHCI_TIMING_MMC_HS102: max = 256; flag = (4 << 13); // 256 iterations. break; case SDHCI_TIMING_UHS_SDR12: case SDHCI_TIMING_UHS_SDR25: return 1; default: return 0; } sdmmc->regs->ventunctl1 = 0; // step_size 1. sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | (1 << 6); // 1x Multiplier. sdmmc->regs->ventunctl0 |= TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW; sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; for (u32 i = 0; i < max; i++) { _sdmmc_tuning_execute_once(sdmmc, cmd); if (!(sdmmc->regs->hostctl2 & SDHCI_CTRL_EXEC_TUNING)) break; } if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) return 1; return 0; } static int _sdmmc_enable_internal_clock(sdmmc_t *sdmmc) { //Enable internal clock and wait till it is stable. sdmmc->regs->clkcon |= SDHCI_CLOCK_INT_EN; _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 2000; while (!(sdmmc->regs->clkcon & SDHCI_CLOCK_INT_STABLE)) { if (get_tmr_ms() > timeout) return 0; } sdmmc->regs->hostctl2 &= ~SDHCI_CTRL_PRESET_VAL_EN; sdmmc->regs->clkcon &= ~SDHCI_PROG_CLOCK_MODE; sdmmc->regs->hostctl2 |= SDHCI_HOST_VERSION_4_EN; if (!(sdmmc->regs->capareg & SDHCI_CAN_64BIT)) return 0; sdmmc->regs->hostctl2 |= SDHCI_ADDRESSING_64BIT_EN; sdmmc->regs->hostctl &= ~SDHCI_CTRL_DMA_MASK; sdmmc->regs->timeoutcon = (sdmmc->regs->timeoutcon & 0xF0) | 0xE; return 1; } static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power) { u32 off_pd = 0; u32 off_pu = 0; switch (sdmmc->id) { case SDMMC_2: case SDMMC_4: if (power != SDMMC_POWER_1_8) return 0; off_pd = 5; off_pu = 5; break; case SDMMC_1: if (power == SDMMC_POWER_1_8) { if (!sdmmc->t210b01) { off_pd = 123; off_pu = 123; } else { off_pd = 6; off_pu = 6; } } else if (power == SDMMC_POWER_3_3) { if (!sdmmc->t210b01) { off_pd = 125; off_pu = 0; } } else return 0; break; } sdmmc->regs->autocalcfg = (sdmmc->regs->autocalcfg & 0xFFFF8080) | (off_pd << 8) | off_pu; return 1; } static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc) { sdmmc->regs->norintstsen |= SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE; sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; sdmmc->regs->norintsts = sdmmc->regs->norintsts; sdmmc->regs->errintsts = sdmmc->regs->errintsts; } static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc) { sdmmc->regs->errintstsen &= ~SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR; sdmmc->regs->norintstsen &= ~(SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); } static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) { u16 norintsts = sdmmc->regs->norintsts; u16 errintsts = sdmmc->regs->errintsts; DPRINTF("norintsts %08X, errintsts %08X\n", norintsts, errintsts); if (pout) *pout = norintsts; // Check for error interrupt. if (norintsts & SDHCI_INT_ERROR) { sdmmc->regs->errintsts = errintsts; return SDMMC_MASKINT_ERROR; } else if (norintsts & mask) { sdmmc->regs->norintsts = norintsts & mask; return SDMMC_MASKINT_MASKED; } return SDMMC_MASKINT_NOERROR; } static int _sdmmc_wait_response(sdmmc_t *sdmmc) { _sdmmc_commit_changes(sdmmc); u64 timeout = get_tmr_ms() + 2000; while (true) { int result = _sdmmc_check_mask_interrupt(sdmmc, NULL, SDHCI_INT_RESPONSE); if (result == SDMMC_MASKINT_MASKED) break; if (result != SDMMC_MASKINT_NOERROR || get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); return 0; } } return 1; } static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) { sdmmc_cmd_t cmd; if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, false)) return 0; _sdmmc_enable_interrupts(sdmmc); cmd.cmd = MMC_STOP_TRANSMISSION; cmd.arg = 0; cmd.rsp_type = SDMMC_RSP_TYPE_1; cmd.check_busy = 1; _sdmmc_send_cmd(sdmmc, &cmd, false); int result = _sdmmc_wait_response(sdmmc); _sdmmc_mask_interrupts(sdmmc); if (!result) return 0; _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); return _sdmmc_wait_card_busy(sdmmc); } int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) { if (!sdmmc->card_clock_enabled) return 0; // Recalibrate periodically for SDMMC1. if (sdmmc->manual_cal && sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); bool should_disable_sd_clock = false; if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) { should_disable_sd_clock = true; sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_commit_changes(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } int result = _sdmmc_stop_transmission_inner(sdmmc, rsp); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return result; } static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) { if (!req->blksize || !req->num_sectors) return 0; u32 blkcnt = req->num_sectors; if (blkcnt >= 0xFFFF) blkcnt = 0xFFFF; u64 admaaddr = (u64)sdmmc_calculate_dma_addr(_current_accessor, req->buf, blkcnt); if (!admaaddr) { // buf is on a heap int dma_idx = sdmmc_calculate_fitting_dma_index(_current_accessor, blkcnt); admaaddr = (u64)&_current_accessor->parent->dmaBuffers[dma_idx].device_addr_buffer_masked[0]; sdmmc->last_dma_idx = dma_idx; } // Check alignment. if (admaaddr & 7) return 0; sdmmc->regs->admaaddr = admaaddr & 0xFFFFFFFFF; sdmmc->regs->admaaddr_hi = (admaaddr >> 32) & 0xFFFFFFFFF; sdmmc->dma_addr_next = (admaaddr + 0x80000) & 0xFFFFFFFFFFF80000; sdmmc->regs->blksize = req->blksize | 0x7000; // DMA 512KB (Detects A18 carry out). sdmmc->regs->blkcnt = blkcnt; if (blkcnt_out) *blkcnt_out = blkcnt; u32 trnmode = SDHCI_TRNS_DMA; if (req->is_multi_block) trnmode = SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DMA; if (!req->is_write) trnmode |= SDHCI_TRNS_READ; if (req->is_auto_cmd12) trnmode = (trnmode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23)) | SDHCI_TRNS_AUTO_CMD12; sdmmc->regs->trnmod = trnmode; return 1; } static int _sdmmc_update_dma(sdmmc_t *sdmmc) { u16 blkcnt = 0; do { blkcnt = sdmmc->regs->blkcnt; u64 timeout = get_tmr_ms() + 1500; do { int result = 0; while (true) { u16 intr = 0; result = _sdmmc_check_mask_interrupt(sdmmc, &intr, SDHCI_INT_DATA_END | SDHCI_INT_DMA_END); if (result < 0) break; if (intr & SDHCI_INT_DATA_END) return 1; // Transfer complete. if (intr & SDHCI_INT_DMA_END) { // Update DMA. sdmmc->regs->admaaddr = sdmmc->dma_addr_next & 0xFFFFFFFFF; sdmmc->regs->admaaddr_hi = (sdmmc->dma_addr_next >> 32) & 0xFFFFFFFFF; sdmmc->dma_addr_next += 0x80000; } } if (result != SDMMC_MASKINT_NOERROR) { _sdmmc_reset(sdmmc); return 0; } } while (get_tmr_ms() < timeout); } while (sdmmc->regs->blkcnt != blkcnt); _sdmmc_reset(sdmmc); return 0; } static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) { int has_req_or_check_busy = req || cmd->check_busy; if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy)) return 0; u32 blkcnt = 0; bool is_data_present = false; if (req) { if (!_sdmmc_config_dma(sdmmc, &blkcnt, req)) return 0; if(!sdmmc_memcpy_buf) { // Flush from/to phys armDCacheFlush(req->buf, req->blksize * blkcnt); } else { if(req->is_write) { void* dma_addr = &_current_accessor->parent->dmaBuffers[sdmmc->last_dma_idx].device_addr_buffer[0]; memcpy(dma_addr, req->buf, req->blksize * blkcnt); // Flush to phys armDCacheFlush(dma_addr, req->blksize * blkcnt); } } is_data_present = true; } _sdmmc_enable_interrupts(sdmmc); if (!_sdmmc_send_cmd(sdmmc, cmd, is_data_present)) return 0; int result = _sdmmc_wait_response(sdmmc); DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (result) { if (cmd->rsp_type) { sdmmc->expected_rsp_type = cmd->rsp_type; result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type); } if (req && result) result = _sdmmc_update_dma(sdmmc); } _sdmmc_mask_interrupts(sdmmc); if (result) { if (req) { if(!req->is_write) { if(!sdmmc_memcpy_buf) { // Flush from phys armDCacheFlush(req->buf, req->blksize * blkcnt); } else { void* dma_addr = &_current_accessor->parent->dmaBuffers[sdmmc->last_dma_idx].device_addr_buffer[0]; // Flush from phys armDCacheFlush(dma_addr, req->blksize * blkcnt); // Copy to buffer memcpy(req->buf, dma_addr, req->blksize * blkcnt); } } if (blkcnt_out) *blkcnt_out = blkcnt; if (req->is_auto_cmd12) sdmmc->rsp3 = sdmmc->regs->rspreg3; } if (cmd->check_busy || req) return _sdmmc_wait_card_busy(sdmmc); } return result; } int sdmmc_get_sd_power_enabled() { return gpio_read(GPIO_PORT_E, GPIO_PIN_4); } bool sdmmc_get_sd_inserted() { return (!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)); } static void _sdmmc_config_sdmmc1_schmitt() { PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; } static void _sdmmc_config_sdmmc2_schmitt() { PINMUX_AUX(PINMUX_AUX_SDMMC2_CLK) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_CMD) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT7) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT6) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT5) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT4) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT3) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT2) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT1) |= PINMUX_SCHMT; PINMUX_AUX(PINMUX_AUX_SDMMC2_DAT0) |= PINMUX_SCHMT; } static void _sdmmc_config_sdmmc1_pads(bool discharge) { u32 sdmmc1_pin_mask = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5; // Set values for Reset state. u32 function = GPIO_MODE_SPIO; u32 level = GPIO_LOW; u32 output = GPIO_OUTPUT_DISABLE; // Set values for dicharging. if (discharge) { function = GPIO_MODE_GPIO; level = GPIO_HIGH; output = GPIO_OUTPUT_ENABLE; } // Set all pads function. gpio_config(GPIO_PORT_M, sdmmc1_pin_mask, function); // Set all pads output level. gpio_write(GPIO_PORT_M, sdmmc1_pin_mask, level); // Set all pads output. gpio_output_enable(GPIO_PORT_M, sdmmc1_pin_mask, output); } static int _sdmmc_config_sdmmc1(bool t210b01) { // Configure SD card detect. PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 2; // GPIO control, pull up. APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); // Check if SD card is inserted. if(!sdmmc_get_sd_inserted()) return 0; /* * Pinmux config: * DRV_TYPE = DRIVE_2X (for 33 Ohm driver) * E_SCHMT = ENABLE (for 1.8V), DISABLE (for 3.3V) * E_INPUT = ENABLE * TRISTATE = PASSTHROUGH * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK */ // Enable deep loopback for SDMMC1 CLK pad. APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Configure SDMMC1 CLK pinmux, based on state and SoC type. if (PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) != (PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN)) // Check if CLK pad is already configured. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | (t210b01 ? PINMUX_PULL_NONE : PINMUX_PULL_DOWN); // Configure the reset of SDMMC1 pins pinmux. PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PULL_UP; // Force schmitt trigger for T210B01. if (t210b01) _sdmmc_config_sdmmc1_schmitt(); // Make sure the SDMMC1 controller is powered. smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, ~PMC_NO_IOPOWER_SDMMC1_IO_EN, PMC_NO_IOPOWER_SDMMC1_IO_EN); smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, 0, 0); // Commit write. // Inform IO pads that voltage is gonna be 3.3V. smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN); smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write. // Set enable SD card power. //PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2; // Proper pinmuxing. Breaks on HOS, takes over 1 minute to recover. PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; // Wrong but working pinmuxing. Instant take over by FS. gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_ENABLE); usleep(10000); // Enable SD card IO power. max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); max77620_regulator_enable(REGULATOR_LDO2, 1); usleep(1000); // Set pad slew codes to get good quality clock. if (!t210b01) { APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) & 0xFFFFFFF) | 0x50000000; (void)APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL); // Commit write. usleep(1000); } return 1; } static void _sdmmc_config_emmc(u32 id, bool t210b01) { switch (id) { case SDMMC_2: if (!t210b01) { // Unset park for pads. APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL) &= 0xF8003FFF; (void)APB_MISC(APB_MISC_GP_EMMC2_PAD_CFGPADCTRL); // Commit write. } else // Enable schmitt trigger for T210B01. _sdmmc_config_sdmmc2_schmitt(); break; case SDMMC_4: // Unset park for pads. APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) &= 0xF8003FFF; // Set default pad cfg. if (t210b01) APB_MISC(APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL) &= 0xFFBFFFF9; // Unset CMD/CLK/DQS powedown. // Enable schmitt trigger. APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) |= 1; (void)APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL); // Commit write. break; } } int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable) { u32 clock; u16 divisor; u8 vref_sel = 7; const u32 trim_values_t210[] = { 2, 8, 3, 8 }; const u32 trim_values_t210b01[] = { 14, 13, 15, 13 }; const u32 *trim_values = sdmmc->t210b01 ? trim_values_t210b01 : trim_values_t210; if (id > SDMMC_4 || id == SDMMC_3) return 0; memset(sdmmc, 0, sizeof(sdmmc_t)); sdmmc->regs = (t210_sdmmc_t *)QueryIoMapping(_sdmmc_bases[id], 0x200); sdmmc->id = id; sdmmc->clock_stopped = 1; sdmmc->t210b01 = splGetSocType() == SplSocType_Mariko; // Do specific SDMMC HW configuration. switch (id) { case SDMMC_1: if (!_sdmmc_config_sdmmc1(sdmmc->t210b01)) return 0; if (sdmmc->t210b01) vref_sel = 0; else sdmmc->manual_cal = 1; break; case SDMMC_2: case SDMMC_4: _sdmmc_config_emmc(id, sdmmc->t210b01); break; } // Disable clock if enabled. if (clock_sdmmc_is_not_reset_and_enabled(id)) { _sdmmc_sd_clock_disable(sdmmc); _sdmmc_commit_changes(sdmmc); } // Configure and enable selected clock. clock_sdmmc_get_card_clock_div(&clock, &divisor, type); clock_sdmmc_enable(id, clock); // Make sure all sdmmc registers are reset. _sdmmc_reset_all(sdmmc); sdmmc->clock_stopped = 0; // Set default pad IO trimming configuration. sdmmc->regs->iospare |= 0x80000; // Enable muxing. sdmmc->regs->veniotrimctl &= 0xFFFFFFFB; // Set Band Gap VREG to supply DLL. sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFB) | (trim_values[sdmmc->id] << 24); sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK) | vref_sel; // Configure auto calibration values. if (!_sdmmc_autocal_config_offset(sdmmc, power)) return 0; // Calibrate pads. _sdmmc_autocal_execute(sdmmc, power); // Enable internal clock and power. if (_sdmmc_enable_internal_clock(sdmmc)) { sdmmc_set_bus_width(sdmmc, bus_width); _sdmmc_set_io_power(sdmmc, power); if (sdmmc_setup_clock(sdmmc, type)) { sdmmc_card_clock_powersave(sdmmc, powersave_enable); _sdmmc_card_clock_enable(sdmmc); _sdmmc_commit_changes(sdmmc); return 1; } } return 0; } void sdmmc1_disable_power() { // Clear pull down from CLK pad. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) &= ~PINMUX_PULL_MASK; // Set pads to discharge state. _sdmmc_config_sdmmc1_pads(true); // Disable SD card IO power regulator. max77620_regulator_enable(REGULATOR_LDO2, 0); usleep(4000); // Disable SD card IO power pin. gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_LOW); // T210/T210B01 WAR: Set start timer for IO and Controller power discharge. msleep(239); // Disable SDMMC1 controller power. smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, PMC_NO_IOPOWER_SDMMC1_IO_EN, PMC_NO_IOPOWER_SDMMC1_IO_EN); smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, 0, 0); // Commit write. // Inform IO pads that next voltage might be 3.3V. smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN); smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write. // Set pads to reset state. _sdmmc_config_sdmmc1_pads(false); // Set pull down to CLK pad. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_PULL_DOWN; } void sdmmc_end(sdmmc_t *sdmmc) { if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); // Disable SDMMC power. _sdmmc_set_io_power(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. if (sdmmc->id == SDMMC_1) sdmmc1_disable_power(); _sdmmc_commit_changes(sdmmc); clock_sdmmc_disable(sdmmc->id); sdmmc->clock_stopped = 1; } } void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy) { cmdbuf->cmd = cmd; cmdbuf->arg = arg; cmdbuf->rsp_type = rsp_type; cmdbuf->check_busy = check_busy; } int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out) { if (!sdmmc->card_clock_enabled) return 0; // Recalibrate periodically for SDMMC1. if (sdmmc->manual_cal && sdmmc->powersave_enabled) _sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc)); int should_disable_sd_clock = 0; if (!(sdmmc->regs->clkcon & SDHCI_CLOCK_CARD_EN)) { should_disable_sd_clock = 1; sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_commit_changes(sdmmc); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); } int result = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~SDHCI_CLOCK_CARD_EN; return result; } int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) { if(sdmmc->id != SDMMC_1) return 0; if (!sdmmc_setup_clock(sdmmc, SDHCI_TIMING_UHS_SDR12)) return 0; _sdmmc_commit_changes(sdmmc); // Switch to 1.8V and wait for regulator to stabilize. Assume max possible wait needed. max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); usleep(150); // Inform IO pads that we switched to 1.8V. smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, ~PMC_PWR_DET_SDMMC1_IO_EN, PMC_PWR_DET_SDMMC1_IO_EN); smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, 0, 0); // Commit write. // Enable schmitt trigger for better duty cycle and low jitter clock. _sdmmc_config_sdmmc1_schmitt(); _sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8); _sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8); _sdmmc_set_io_power(sdmmc, SDMMC_POWER_1_8); _sdmmc_commit_changes(sdmmc); msleep(5); // Wait minimum 5ms before turning on the card clock. // Turn on SDCLK. if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN; _sdmmc_commit_changes(sdmmc); usleep(1000); if ((sdmmc->regs->prnsts & SDHCI_DATA_LVL_MASK) == SDHCI_DATA_LVL_MASK) return 1; } return 0; } ================================================ FILE: emummc/source/emmc/sdmmc_driver.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SDMMC_DRIVER_H_ #define _SDMMC_DRIVER_H_ #include "../utils/types.h" #include "sdmmc_t210.h" /*! SDMMC controller IDs. */ #define SDMMC_1 0 #define SDMMC_2 1 #define SDMMC_3 2 #define SDMMC_4 3 /*! SDMMC power types. */ #define SDMMC_POWER_OFF 0 #define SDMMC_POWER_1_8 1 #define SDMMC_POWER_3_3 2 /*! SDMMC bus widths. */ #define SDMMC_BUS_WIDTH_1 0 #define SDMMC_BUS_WIDTH_4 1 #define SDMMC_BUS_WIDTH_8 2 /*! SDMMC response types. */ #define SDMMC_RSP_TYPE_0 0 #define SDMMC_RSP_TYPE_1 1 #define SDMMC_RSP_TYPE_2 2 #define SDMMC_RSP_TYPE_3 3 #define SDMMC_RSP_TYPE_4 4 #define SDMMC_RSP_TYPE_5 5 /*! SDMMC mask interrupt status. */ #define SDMMC_MASKINT_MASKED 0 #define SDMMC_MASKINT_NOERROR -1 #define SDMMC_MASKINT_ERROR -2 /*! SDMMC present state. */ #define SDHCI_CMD_INHIBIT 0x1 #define SDHCI_DATA_INHIBIT 0x2 #define SDHCI_DOING_WRITE 0x100 #define SDHCI_DOING_READ 0x200 #define SDHCI_SPACE_AVAILABLE 0x400 #define SDHCI_DATA_AVAILABLE 0x800 #define SDHCI_CARD_PRESENT 0x10000 #define SDHCI_CD_STABLE 0x20000 #define SDHCI_CD_LVL 0x40000 #define SDHCI_WRITE_PROTECT 0x80000 #define SDHCI_DATA_LVL_MASK 0xF00000 #define SDHCI_DATA_0_LVL_MASK 0x100000 #define SDHCI_CMD_LVL 0x1000000 /*! SDMMC transfer mode. */ #define SDHCI_TRNS_DMA 0x01 #define SDHCI_TRNS_BLK_CNT_EN 0x02 #define SDHCI_TRNS_AUTO_CMD12 0x04 #define SDHCI_TRNS_AUTO_CMD23 0x08 #define SDHCI_TRNS_AUTO_SEL 0x0C #define SDHCI_TRNS_WRITE 0x00 #define SDHCI_TRNS_READ 0x10 #define SDHCI_TRNS_MULTI 0x20 /*! SDMMC command. */ #define SDHCI_CMD_RESP_MASK 0x3 #define SDHCI_CMD_RESP_NO_RESP 0x0 #define SDHCI_CMD_RESP_LEN136 0x1 #define SDHCI_CMD_RESP_LEN48 0x2 #define SDHCI_CMD_RESP_LEN48_BUSY 0x3 #define SDHCI_CMD_CRC 0x08 #define SDHCI_CMD_INDEX 0x10 #define SDHCI_CMD_DATA 0x20 #define SDHCI_CMD_ABORTCMD 0xC0 /*! SDMMC host control. */ #define SDHCI_CTRL_LED 0x01 #define SDHCI_CTRL_4BITBUS 0x02 #define SDHCI_CTRL_HISPD 0x04 #define SDHCI_CTRL_DMA_MASK 0x18 #define SDHCI_CTRL_SDMA 0x00 #define SDHCI_CTRL_ADMA1 0x08 #define SDHCI_CTRL_ADMA32 0x10 #define SDHCI_CTRL_ADMA64 0x18 #define SDHCI_CTRL_8BITBUS 0x20 #define SDHCI_CTRL_CDTEST_INS 0x40 #define SDHCI_CTRL_CDTEST_EN 0x80 /*! SDMMC host control 2. */ #define SDHCI_CTRL_UHS_MASK 0xFFF8 #define SDHCI_CTRL_VDD_180 8 #define SDHCI_CTRL_DRV_TYPE_B 0x00 #define SDHCI_CTRL_DRV_TYPE_A 0x10 #define SDHCI_CTRL_DRV_TYPE_C 0x20 #define SDHCI_CTRL_DRV_TYPE_D 0x30 #define SDHCI_CTRL_EXEC_TUNING 0x40 #define SDHCI_CTRL_TUNED_CLK 0x80 #define SDHCI_HOST_VERSION_4_EN 0x1000 #define SDHCI_ADDRESSING_64BIT_EN 0x2000 #define SDHCI_CTRL_PRESET_VAL_EN 0x8000 /*! SDMMC power control. */ #define SDHCI_POWER_ON 0x01 #define SDHCI_POWER_180 0x0A #define SDHCI_POWER_300 0x0C #define SDHCI_POWER_330 0x0E #define SDHCI_POWER_MASK 0xF1 // /*! SDMMC max current. */ // #define SDHCI_MAX_CURRENT_330_MASK 0xFF // #define SDHCI_MAX_CURRENT_180_MASK 0xFF0000 // #define SDHCI_MAX_CURRENT_MULTIPLIER 4 /*! SDMMC clock control. */ #define SDHCI_DIVIDER_SHIFT 8 #define SDHCI_DIVIDER_HI_SHIFT 6 #define SDHCI_DIV_MASK 0xFF00 #define SDHCI_DIV_HI_MASK 0xC0 #define SDHCI_PROG_CLOCK_MODE 0x20 #define SDHCI_CLOCK_CARD_EN 0x4 #define SDHCI_CLOCK_INT_STABLE 0x2 #define SDHCI_CLOCK_INT_EN 0x1 /*! SDMMC software reset. */ #define SDHCI_RESET_ALL 0x01 #define SDHCI_RESET_CMD 0x02 #define SDHCI_RESET_DATA 0x04 /*! SDMMC interrupt status and control. */ #define SDHCI_INT_RESPONSE 0x1 #define SDHCI_INT_DATA_END 0x2 #define SDHCI_INT_BLK_GAP 0x4 #define SDHCI_INT_DMA_END 0x8 #define SDHCI_INT_SPACE_AVAIL 0x10 #define SDHCI_INT_DATA_AVAIL 0x20 #define SDHCI_INT_CARD_INSERT 0x40 #define SDHCI_INT_CARD_REMOVE 0x80 #define SDHCI_INT_CARD_INT 0x100 #define SDHCI_INT_RETUNE 0x1000 #define SDHCI_INT_CQE 0x4000 #define SDHCI_INT_ERROR 0x8000 /*! SDMMC error interrupt status and control. */ #define SDHCI_ERR_INT_TIMEOUT 0x1 #define SDHCI_ERR_INT_CRC 0x2 #define SDHCI_ERR_INT_END_BIT 0x4 #define SDHCI_ERR_INT_INDEX 0x8 #define SDHCI_ERR_INT_DATA_TIMEOUT 0x10 #define SDHCI_ERR_INT_DATA_CRC 0x20 #define SDHCI_ERR_INT_DATA_END_BIT 0x40 #define SDHCI_ERR_INT_BUS_POWER 0x80 #define SDHCI_ERR_INT_AUTO_CMD_ERR 0x100 #define SDHCI_ERR_INT_ADMA_ERROR 0x200 #define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \ (SDHCI_ERR_INT_AUTO_CMD_ERR | SDHCI_ERR_INT_DATA_END_BIT | \ SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \ SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \ SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT) /*! SD bus speeds. */ #define UHS_SDR12_BUS_SPEED 0 #define HIGH_SPEED_BUS_SPEED 1 #define UHS_SDR25_BUS_SPEED 1 #define UHS_SDR50_BUS_SPEED 2 #define UHS_SDR104_BUS_SPEED 3 #define UHS_DDR50_BUS_SPEED 4 #define HS400_BUS_SPEED 5 /*! SDMMC timmings. */ #define SDHCI_TIMING_MMC_ID 0 #define SDHCI_TIMING_MMC_LS26 1 #define SDHCI_TIMING_MMC_HS52 2 #define SDHCI_TIMING_MMC_HS200 3 #define SDHCI_TIMING_MMC_HS400 4 #define SDHCI_TIMING_SD_ID 5 #define SDHCI_TIMING_SD_DS12 6 #define SDHCI_TIMING_SD_HS25 7 #define SDHCI_TIMING_UHS_SDR12 8 #define SDHCI_TIMING_UHS_SDR25 9 #define SDHCI_TIMING_UHS_SDR50 10 #define SDHCI_TIMING_UHS_SDR104 11 #define SDHCI_TIMING_UHS_SDR82 12 // SDR104 with a 163.2MHz -> 81.6MHz clock. #define SDHCI_TIMING_UHS_DDR50 13 #define SDHCI_TIMING_MMC_HS102 14 #define SDHCI_CAN_64BIT 0x10000000 /*! SDMMC Low power features. */ #define SDMMC_POWER_SAVE_DISABLE 0 #define SDMMC_POWER_SAVE_ENABLE 1 /*! Helper for SWITCH command argument. */ #define SDMMC_SWITCH(mode, index, value) (((mode) << 24) | ((index) << 16) | ((value) << 8)) /*! SDMMC controller context. */ typedef struct _sdmmc_t { t210_sdmmc_t *regs; u32 id; u32 divisor; u32 clock_stopped; int powersave_enabled; int manual_cal; int card_clock_enabled; int venclkctl_set; u32 venclkctl_tap; u32 expected_rsp_type; u64 last_dma_idx; u64 dma_addr_next; u32 rsp[4]; u32 rsp3; int t210b01; } sdmmc_t; /*! SDMMC command. */ typedef struct _sdmmc_cmd_t { u16 cmd; u32 arg; u32 rsp_type; u32 check_busy; } sdmmc_cmd_t; /*! SDMMC request. */ typedef struct _sdmmc_req_t { void *buf; u32 blksize; u32 num_sectors; int is_write; int is_multi_block; int is_auto_cmd12; } sdmmc_req_t; int sdmmc_get_io_power(sdmmc_t *sdmmc); u32 sdmmc_get_bus_width(sdmmc_t *sdmmc); void sdmmc_set_bus_width(sdmmc_t *sdmmc, u32 bus_width); void sdmmc_save_tap_value(sdmmc_t *sdmmc); int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type); void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable); int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type); int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd); int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp); int sdmmc_get_sd_power_enabled(); bool sdmmc_get_sd_inserted(); int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int powersave_enable); void sdmmc_end(sdmmc_t *sdmmc); void sdmmc_init_cmd(sdmmc_cmd_t *cmdbuf, u16 cmd, u32 arg, u32 rsp_type, u32 check_busy); int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out); int sdmmc_enable_low_voltage(sdmmc_t *sdmmc); #endif ================================================ FILE: emummc/source/emmc/sdmmc_t210.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SDMMC_T210_H_ #define _SDMMC_T210_H_ #include "../utils/types.h" #define TEGRA_MMC_VNDR_TUN_CTRL0_TAP_VAL_UPDATED_BY_HW 0x20000 #define TEGRA_MMC_DLLCAL_CFG_EN_CALIBRATE 0x80000000 #define TEGRA_MMC_DLLCAL_CFG_STATUS_DLL_ACTIVE 0x80000000 #define TEGRA_MMC_SDMEMCOMPPADCTRL_PAD_E_INPUT_PWRD 0x80000000 #define TEGRA_MMC_SDMEMCOMPPADCTRL_COMP_VREF_SEL_MASK 0xFFFFFFF0 #define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_ENABLE 0x20000000 #define TEGRA_MMC_AUTOCALCFG_AUTO_CAL_START 0x80000000 #define TEGRA_MMC_AUTOCALSTS_AUTO_CAL_ACTIVE 0x80000000 typedef struct _t210_sdmmc_t { vu32 sysad; vu16 blksize; vu16 blkcnt; vu32 argument; vu16 trnmod; vu16 cmdreg; vu32 rspreg0; vu32 rspreg1; vu32 rspreg2; vu32 rspreg3; vu32 bdata; vu32 prnsts; vu8 hostctl; vu8 pwrcon; vu8 blkgap; vu8 wakcon; vu16 clkcon; vu8 timeoutcon; vu8 swrst; vu16 norintsts; vu16 errintsts; vu16 norintstsen; // Enable irq status. vu16 errintstsen; // Enable irq status. vu16 norintsigen; // Enable irq signal to LIC/GIC. vu16 errintsigen; // Enable irq signal to LIC/GIC. vu16 acmd12errsts; vu16 hostctl2; vu32 capareg; vu32 capareg_1; vu32 maxcurr; vu8 rsvd0[4]; // 4C-4F reserved for more max current. vu16 setacmd12err; vu16 setinterr; vu8 admaerr; vu8 rsvd1[3]; // 55-57 reserved. vu32 admaaddr; vu32 admaaddr_hi; vu8 rsvd2[156]; // 60-FB reserved. vu16 slotintsts; vu16 hcver; vu32 venclkctl; vu32 vensysswctl; vu32 venerrintsts; vu32 vencapover; vu32 venbootctl; vu32 venbootacktout; vu32 venbootdattout; vu32 vendebouncecnt; vu32 venmiscctl; vu32 maxcurrover; vu32 maxcurrover_hi; vu32 unk0[32]; // 0x12C vu32 veniotrimctl; vu32 vendllcalcfg; vu32 vendllctl0; vu32 vendllctl1; vu32 vendllcalcfgsts; vu32 ventunctl0; vu32 ventunctl1; vu32 ventunsts0; vu32 ventunsts1; vu32 venclkgatehystcnt; vu32 venpresetval0; vu32 venpresetval1; vu32 venpresetval2; vu32 sdmemcmppadctl; vu32 autocalcfg; vu32 autocalintval; vu32 autocalsts; vu32 iospare; vu32 mcciffifoctl; vu32 timeoutwcoal; vu32 unk1; } t210_sdmmc_t; #endif ================================================ FILE: emummc/source/emuMMC/emummc.c ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include "emummc.h" #include "emummc_ctx.h" #include "../utils/fatal.h" #include "../libs/fatfs/diskio.h" static bool sdmmc_first_init = false; static bool storageSDinitialized = false; // hekate sdmmmc vars sdmmc_t sdmmc; sdmmc_storage_t storage; sdmmc_t sd_sdmmc; sdmmc_storage_t sd_storage; // init vars bool init_done = false; bool custom_driver = true; // FS funcs _sdmmc_accessor_gc sdmmc_accessor_gc; _sdmmc_accessor_sd sdmmc_accessor_sd; _sdmmc_accessor_nand sdmmc_accessor_nand; _lock_mutex lock_mutex; _unlock_mutex unlock_mutex; // FS misc void *sd_mutex; void *nand_mutex; volatile int *active_partition; volatile Handle *sdmmc_das_handle; // FatFS file_based_ctxt f_emu; static bool fat_mounted = false; static void _sdmmc_ensure_device_attached(void) { // This ensures that the sd device address space handle is always attached, // even if FS hasn't attached it static bool did_attach = false; if (!did_attach) { svcAttachDeviceAddressSpace(DeviceName_SDMMC1A, *sdmmc_das_handle); did_attach = true; } } static void _sdmmc_ensure_initialized(void) { // First Initial init if (!sdmmc_first_init) { sdmmc_initialize(); sdmmc_first_init = true; } else { // The boot sysmodule will eventually kill power to SD. // Detect this, and reinitialize when it happens. if (!init_done) { if (sdmmc_get_sd_power_enabled() == 0) { sdmmc_finalize(); sdmmc_initialize(); init_done = true; } } } } static void _file_based_update_filename(char *outFilename, unsigned int sd_path_len, unsigned int part_idx) { snprintf(outFilename + sd_path_len, 3, "%02d", part_idx); } static void _file_based_emmc_finalize(void) { if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && fat_mounted) { // Close all open handles. f_close(&f_emu.fp_boot0); f_close(&f_emu.fp_boot1); for (int i = 0; i < f_emu.parts; i++) f_close(&f_emu.fp_gpp[i]); // Force unmount FAT volume. f_mount(NULL, "", 1); fat_mounted = false; } } static void _nand_patrol_ensure_integrity(void) { fs_nand_patrol_t nand_patrol; static bool nand_patrol_checked = false; if (!nand_patrol_checked) { if (emuMMC_ctx.EMMC_Type == emuMMC_SD_Raw) { unsigned int nand_patrol_sector = emuMMC_ctx.EMMC_StoragePartitionOffset + NAND_PATROL_SECTOR; if (!sdmmc_storage_read(&sd_storage, nand_patrol_sector, 1, &nand_patrol)) goto out; // Clear nand patrol if last offset exceeds storage. if (nand_patrol.offset > sd_storage.sec_cnt) { memset(&nand_patrol, 0, sizeof(fs_nand_patrol_t)); sdmmc_storage_write(&sd_storage, nand_patrol_sector, 1, &nand_patrol); } } else if (emuMMC_ctx.EMMC_Type == emuMMC_SD_File && fat_mounted) { FIL *fp = &f_emu.fp_boot0; if (f_lseek(fp, NAND_PATROL_OFFSET) != FR_OK) goto out; if (f_read_fast(fp, &nand_patrol, sizeof(fs_nand_patrol_t)) != FR_OK) goto out; // Clear nand patrol if last offset exceeds total file based size. if (nand_patrol.offset > f_emu.total_sect) { memset(&nand_patrol, 0, sizeof(fs_nand_patrol_t)); if (f_lseek(fp, NAND_PATROL_OFFSET) != FR_OK) goto out; if (f_write_fast(fp, &nand_patrol, sizeof(fs_nand_patrol_t)) != FR_OK) goto out; f_sync(fp); } } out: nand_patrol_checked = true; } } void sdmmc_finalize(void) { if (!sdmmc_storage_end(&sd_storage)) fatal_abort(Fatal_InitSD); storageSDinitialized = false; } static void _file_based_emmc_initialize(void) { char path[sizeof(emuMMC_ctx.storagePath) + 0x20]; memset(&path, 0, sizeof(path)); memcpy(path, (void *)emuMMC_ctx.storagePath, sizeof(emuMMC_ctx.storagePath)); strcat(path, "/eMMC/"); int path_len = strlen(path); // Open BOOT0 physical partition. memcpy(path + path_len, "BOOT0", 6); if (f_open(&f_emu.fp_boot0, path, FA_READ | FA_WRITE) != FR_OK) fatal_abort(Fatal_FatfsFileOpen); if (!f_expand_cltbl(&f_emu.fp_boot0, EMUMMC_FP_CLMT_COUNT, f_emu.clmt_boot0, f_size(&f_emu.fp_boot0))) fatal_abort(Fatal_FatfsMemExhaustion); // Open BOOT1 physical partition. memcpy(path + path_len, "BOOT1", 6); if (f_open(&f_emu.fp_boot1, path, FA_READ | FA_WRITE) != FR_OK) fatal_abort(Fatal_FatfsFileOpen); if (!f_expand_cltbl(&f_emu.fp_boot1, EMUMMC_FP_CLMT_COUNT, f_emu.clmt_boot1, f_size(&f_emu.fp_boot1))) fatal_abort(Fatal_FatfsMemExhaustion); // Open handles for GPP physical partition files. _file_based_update_filename(path, path_len, 00); if (f_open(&f_emu.fp_gpp[0], path, FA_READ | FA_WRITE) != FR_OK) fatal_abort(Fatal_FatfsFileOpen); if (!f_expand_cltbl(&f_emu.fp_gpp[0], EMUMMC_FP_CLMT_COUNT, &f_emu.clmt_gpp[0], f_size(&f_emu.fp_gpp[0]))) fatal_abort(Fatal_FatfsMemExhaustion); f_emu.part_size = (uint64_t)f_size(&f_emu.fp_gpp[0]) >> 9; f_emu.total_sect = f_emu.part_size; // Iterate folder for split parts and stop if next doesn't exist. for (f_emu.parts = 1; f_emu.parts < EMUMMC_FILE_MAX_PARTS; f_emu.parts++) { _file_based_update_filename(path, path_len, f_emu.parts); if (f_open(&f_emu.fp_gpp[f_emu.parts], path, FA_READ | FA_WRITE) != FR_OK) { // Check if single file. if (f_emu.parts == 1) f_emu.parts = 0; return; } if (!f_expand_cltbl(&f_emu.fp_gpp[f_emu.parts], EMUMMC_FP_CLMT_COUNT, &f_emu.clmt_gpp[f_emu.parts * EMUMMC_FP_CLMT_COUNT], f_size(&f_emu.fp_gpp[f_emu.parts]))) { fatal_abort(Fatal_FatfsMemExhaustion); } f_emu.total_sect += (uint64_t)f_size(&f_emu.fp_gpp[f_emu.parts]) >> 9; } } bool sdmmc_initialize(void) { if (!storageSDinitialized) { int retries = 3; while (retries) { if (nx_sd_initialize(false)) { storageSDinitialized = true; // Init file based emummc. if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && !fat_mounted) { if (f_mount(&f_emu.sd_fs, "", 1) != FR_OK) fatal_abort(Fatal_InitSD); else fat_mounted = true; _file_based_emmc_initialize(); } // Check if nand patrol offset is inside limits. _nand_patrol_ensure_integrity(); break; } retries--; } if (!storageSDinitialized) fatal_abort(Fatal_InitSD); } return storageSDinitialized; } sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id) { sdmmc_accessor_t *_this; switch (mmc_id) { case FS_SDMMC_EMMC: _this = sdmmc_accessor_nand(); break; case FS_SDMMC_SD: _this = sdmmc_accessor_sd(); break; case FS_SDMMC_GC: _this = sdmmc_accessor_gc(); break; default: fatal_abort(Fatal_InvalidAccessor); } return _this; } void mutex_lock_handler(int mmc_id) { if (custom_driver) lock_mutex(sd_mutex); lock_mutex(nand_mutex); } void mutex_unlock_handler(int mmc_id) { unlock_mutex(nand_mutex); if (custom_driver) unlock_mutex(sd_mutex); } int sdmmc_nand_get_active_partition_index() { switch (*active_partition) { case FS_EMMC_PARTITION_GPP: return 2; case FS_EMMC_PARTITION_BOOT1: return 1; case FS_EMMC_PARTITION_BOOT0: return 0; } fatal_abort(Fatal_InvalidAccessor); } static uint64_t emummc_read_write_inner(void *buf, unsigned int sector, unsigned int num_sectors, bool is_write) { if (emuMMC_ctx.EMMC_Type == emuMMC_SD_Raw) { // raw partition sector offset: emuMMC_ctx.EMMC_StoragePartitionOffset. sector += emuMMC_ctx.EMMC_StoragePartitionOffset; // Set physical partition offset. sector += (sdmmc_nand_get_active_partition_index() * BOOT_PARTITION_SIZE); if (__builtin_expect(sector + num_sectors > sd_storage.sec_cnt, 0)) return 0; // Out of bounds. Can only happen with Nand Patrol if resized. if (!is_write) return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf); else return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf); } // File based emummc. FIL *fp = NULL; switch (*active_partition) { case FS_EMMC_PARTITION_GPP: if (f_emu.parts) { if (__builtin_expect(sector + num_sectors > f_emu.total_sect, 0)) return 0; // Out of bounds. Can only happen with Nand Patrol if resized. fp = &f_emu.fp_gpp[sector / f_emu.part_size]; sector = sector % f_emu.part_size; // Special handling for reads/writes which cross file-boundaries. if (__builtin_expect(sector + num_sectors > f_emu.part_size, 0)) { unsigned int remaining = num_sectors; while (remaining > 0) { const unsigned int cur_sectors = MIN(remaining, f_emu.part_size - sector); if (f_lseek(fp, (uint64_t)sector << 9) != FR_OK) return 0; // Out of bounds. if (!is_write) { if (f_read_fast(fp, buf, (uint64_t)cur_sectors << 9) != FR_OK) return 0; } else { if (f_write_fast(fp, buf, (uint64_t)cur_sectors << 9) != FR_OK) return 0; } buf = (char *)buf + ((uint64_t)cur_sectors << 9); remaining -= cur_sectors; sector = 0; ++fp; } return 1; } } else fp = &f_emu.fp_gpp[0]; break; case FS_EMMC_PARTITION_BOOT1: fp = &f_emu.fp_boot1; break; case FS_EMMC_PARTITION_BOOT0: fp = &f_emu.fp_boot0; break; } if (f_lseek(fp, (uint64_t)sector << 9) != FR_OK) return 0; // Out of bounds. Can only happen with Nand Patrol if resized. if (!is_write) return !f_read_fast(fp, buf, (uint64_t)num_sectors << 9); else return !f_write_fast(fp, buf, (uint64_t)num_sectors << 9); } // Controller open wrapper uint64_t sdmmc_wrapper_controller_open(int mmc_id) { uint64_t result; sdmmc_accessor_t *_this; _this = sdmmc_accessor_get(mmc_id); if (_this != NULL) { // Lock eMMC xfer while SD card is being initialized by FS. if (mmc_id == FS_SDMMC_SD) mutex_lock_handler(FS_SDMMC_EMMC); // Recursive Mutex, handler will lock SD as well if custom_driver result = _this->vtab->sdmmc_accessor_controller_open(_this); // Unlock eMMC. if (mmc_id == FS_SDMMC_SD) mutex_unlock_handler(FS_SDMMC_EMMC); return result; } fatal_abort(Fatal_OpenAccessor); } // Controller close wrapper uint64_t sdmmc_wrapper_controller_close(int mmc_id) { sdmmc_accessor_t *_this; _this = sdmmc_accessor_get(mmc_id); if (_this != NULL) { if (mmc_id == FS_SDMMC_SD) return 0; if (mmc_id == FS_SDMMC_EMMC) { // Close file handles and unmount _file_based_emmc_finalize(); // Close SD sdmmc_accessor_get(FS_SDMMC_SD)->vtab->sdmmc_accessor_controller_close(sdmmc_accessor_get(FS_SDMMC_SD)); // Close eMMC return _this->vtab->sdmmc_accessor_controller_close(_this); } return _this->vtab->sdmmc_accessor_controller_close(_this); } fatal_abort(Fatal_CloseAccessor); } // FS read wrapper. uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned int sector, unsigned int num_sectors) { sdmmc_accessor_t *_this; uint64_t read_res; _this = sdmmc_accessor_get(mmc_id); if (_this != NULL) { if (mmc_id == FS_SDMMC_EMMC || mmc_id == FS_SDMMC_SD) { mutex_lock_handler(mmc_id); // Assign FS accessor to the SDMMC driver _current_accessor = _this; // Make sure we're attached to the device address space. _sdmmc_ensure_device_attached(); // Make sure we're still initialized if boot killed sd card power. _sdmmc_ensure_initialized(); } if (mmc_id == FS_SDMMC_EMMC) { // Call hekates driver. if (emummc_read_write_inner(buf, sector, num_sectors, false)) { mutex_unlock_handler(mmc_id); return 0; } mutex_unlock_handler(mmc_id); return FS_READ_WRITE_ERROR; } if (mmc_id == FS_SDMMC_SD) { static bool first_sd_read = true; if (first_sd_read) { first_sd_read = false; if (emuMMC_ctx.EMMC_Type == emuMMC_SD_Raw) { // Because some SD cards have issues with emuMMC's driver // we currently swap to FS's driver after first SD read // for raw based emuMMC custom_driver = false; // FS will handle sd mutex w/o custom driver from here on unlock_mutex(sd_mutex); } } // Call hekate's driver. if (sdmmc_storage_read(&sd_storage, sector, num_sectors, buf)) { mutex_unlock_handler(mmc_id); return 0; } mutex_unlock_handler(mmc_id); return FS_READ_WRITE_ERROR; } read_res = _this->vtab->read_write(_this, sector, num_sectors, buf, bufSize, 1); return read_res; } fatal_abort(Fatal_ReadNoAccessor); } // FS write wrapper. uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_sectors, void *buf, uint64_t bufSize) { sdmmc_accessor_t *_this; uint64_t write_res; _this = sdmmc_accessor_get(mmc_id); if (_this != NULL) { if (mmc_id == FS_SDMMC_EMMC) { mutex_lock_handler(mmc_id); _current_accessor = _this; // Call hekates driver. if (emummc_read_write_inner(buf, sector, num_sectors, true)) { mutex_unlock_handler(mmc_id); return 0; } mutex_unlock_handler(mmc_id); return FS_READ_WRITE_ERROR; } if (mmc_id == FS_SDMMC_SD) { mutex_lock_handler(mmc_id); _current_accessor = _this; // Call hekates driver. if (sdmmc_storage_write(&sd_storage, sector, num_sectors, buf)) { mutex_unlock_handler(mmc_id); return 0; } mutex_unlock_handler(mmc_id); return FS_READ_WRITE_ERROR; } write_res = _this->vtab->read_write(_this, sector, num_sectors, buf, bufSize, 0); return write_res; } fatal_abort(Fatal_WriteNoAccessor); } ================================================ FILE: emummc/source/emuMMC/emummc.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __EMUMMC_H__ #define __EMUMMC_H__ #ifdef __cplusplus extern "C" { #endif #include <stdlib.h> #include <stdint.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include "../emmc/nx_sd.h" #include "../emmc/sdmmc.h" #include "../soc/i2c.h" #include "../soc/gpio.h" #include "../utils/util.h" #include "../FS/FS.h" #include "../libs/fatfs/ff.h" #define EMUMMC_FILE_MAX_PARTS 32 #define EMUMMC_FP_CLMT_COUNT 1024 // FS typedefs typedef sdmmc_accessor_t *(*_sdmmc_accessor_gc)(); typedef sdmmc_accessor_t *(*_sdmmc_accessor_sd)(); typedef sdmmc_accessor_t *(*_sdmmc_accessor_nand)(); typedef void (*_lock_mutex)(void *mtx); typedef void (*_unlock_mutex)(void *mtx); bool sdmmc_initialize(void); void sdmmc_finalize(void); int sdmmc_nand_get_active_partition_index(); sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id); void mutex_lock_handler(int mmc_id); void mutex_unlock_handler(int mmc_id); // Hooks uint64_t sdmmc_wrapper_controller_open(int mmc_id); uint64_t sdmmc_wrapper_controller_close(int mmc_id); uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned int sector, unsigned int num_sectors); uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_sectors, void *buf, uint64_t bufSize); typedef struct _file_based_ctxt { FATFS sd_fs; uint64_t parts; uint64_t part_size; FIL fp_boot0; DWORD clmt_boot0[EMUMMC_FP_CLMT_COUNT]; FIL fp_boot1; DWORD clmt_boot1[EMUMMC_FP_CLMT_COUNT]; FIL fp_gpp[EMUMMC_FILE_MAX_PARTS]; DWORD clmt_gpp[EMUMMC_FILE_MAX_PARTS * EMUMMC_FP_CLMT_COUNT]; uint64_t total_sect; } file_based_ctxt; #ifdef __cplusplus } #endif #endif /* __EMUMMC_H__ */ ================================================ FILE: emummc/source/emuMMC/emummc_ctx.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __EMUMMC_CTX_H__ #define __EMUMMC_CTX_H__ #include "../utils/types.h" #include "../FS/FS_versions.h" #define EMUMMC_STORAGE_MAGIC 0x30534645 /* EFS0, EmuFS0 */ #define EMUMMC_MAX_DIR_LENGTH 0x7F enum emuMMC_Type { // EMMC Device raw emuMMC_EMMC = 0, // SD Device raw emuMMC_SD_Raw, // SD Device File emuMMC_SD_File, emuMMC_MAX }; typedef struct _emuMMC_ctx_t { u32 magic; u32 id; enum FS_VER fs_ver; enum emuMMC_Type EMMC_Type; enum emuMMC_Type SD_Type; /* Partition based */ u64 EMMC_StoragePartitionOffset; u64 SD_StoragePartitionOffset; /* File-Based */ char storagePath[EMUMMC_MAX_DIR_LENGTH+1]; } emuMMC_ctx_t, *PemuMMC_ctx_t; #endif /* __EMUMMC_CTX_H__ */ ================================================ FILE: emummc/source/libs/fatfs/diskio.c ================================================ /*-----------------------------------------------------------------------*/ /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ /* This is an example of glue functions to attach various exsisting */ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ #include <string.h> #include "diskio.h" /* FatFs lower layer API */ #include "../../emmc/sdmmc.h" extern sdmmc_storage_t sd_storage; /*-----------------------------------------------------------------------*/ /* Get Drive Status */ /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return 0; } /*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return 0; } /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; } /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { return RES_OK; } ================================================ FILE: emummc/source/libs/fatfs/diskio.h ================================================ /*-----------------------------------------------------------------------/ / Low level disk interface modlue include file (C)ChaN, 2014 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED #define _DISKIO_DEFINED #ifdef __cplusplus extern "C" { #endif #include "../../utils/types.h" /* Status of Disk Functions */ typedef BYTE DSTATUS; /* Results of Disk Functions */ typedef enum { RES_OK = 0, /* 0: Successful */ RES_ERROR, /* 1: R/W Error */ RES_WRPRT, /* 2: Write Protected */ RES_NOTRDY, /* 3: Not Ready */ RES_PARERR /* 4: Invalid Parameter */ } DRESULT; /*---------------------------------------*/ /* Prototypes for disk control functions */ DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ #define STA_NODISK 0x02 /* No medium in the drive */ #define STA_PROTECT 0x04 /* Write protected */ /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_LOCK 6 /* Lock/Unlock media removal */ #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ #define MMC_GET_OCR 13 /* Get OCR */ #define MMC_GET_SDSTAT 14 /* Get SD status */ #define ISDIO_READ 55 /* Read data form SD iSDIO register */ #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ /* ATA/CF specific ioctl command */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ #ifdef __cplusplus } #endif #endif ================================================ FILE: emummc/source/libs/fatfs/ff.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem Module R0.13c (p4) / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ #define EFSPRINTF(text, ...) /*-------------------------------------------------------------------------- Module Private Definitions ---------------------------------------------------------------------------*/ #if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif /* Limits and boundaries */ #define MAX_DIR 0x200000 /* Max size of FAT directory */ #define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ /* Character code support macros */ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsDigit(c) ((c) >= '0' && (c) <= '9') #define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) /* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ /* Additional file attribute bits for internal use */ #define AM_VOL 0x08 /* Volume label */ #define AM_LFN 0x0F /* LFN entry */ #define AM_MASK 0x3F /* Mask of defined bits */ /* Name status flags in fn[11] */ #define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ #define NS_NOLFN 0x40 /* Do not find LFN */ #define NS_NONAME 0x80 /* Not followed */ /* exFAT directory entry types */ #define ET_BITMAP 0x81 /* Allocation bitmap */ #define ET_UPCASE 0x82 /* Up-case table */ #define ET_VLABEL 0x83 /* Volume label */ #define ET_FILEDIR 0x85 /* File and directory */ #define ET_STREAM 0xC0 /* Stream extension */ #define ET_FILENAME 0xC1 /* Name extension */ /* FatFs refers the FAT structure as simple byte array instead of structure member / because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ #define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ #define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ #define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ #define BS_NTres 37 /* WindowsNT error flag (BYTE) */ #define BS_BootSig 38 /* Extended boot signature (BYTE) */ #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ #define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ #define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ #define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ #define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ #define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ #define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ #define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ #define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ #define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ #define DIR_NTres 12 /* Lower case flag (BYTE) */ #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ #define DIR_CrtTime 14 /* Created time (DWORD) */ #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ #define DIR_ModTime 22 /* Modified time (DWORD) */ #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ #define DIR_FileSize 28 /* File size (DWORD) */ #define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ #define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ #define LDIR_Type 12 /* LFN: Entry type (BYTE) */ #define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ #define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ #define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ #define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ #define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ #define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ #define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ #define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ #define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ #define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ #define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ #define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ #define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ #define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ #define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ #define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ #define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ #define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ #define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ #define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ #define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ #define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ #define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ #define SZDIRE 32 /* Size of a directory entry */ #define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ #define PTE_Boot 0 /* MBR PTE: Boot indicator */ #define PTE_StHead 1 /* MBR PTE: Start head */ #define PTE_StSec 2 /* MBR PTE: Start sector */ #define PTE_StCyl 3 /* MBR PTE: Start cylinder */ #define PTE_System 4 /* MBR PTE: System ID */ #define PTE_EdHead 5 /* MBR PTE: End head */ #define PTE_EdSec 6 /* MBR PTE: End sector */ #define PTE_EdCyl 7 /* MBR PTE: End cylinder */ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ /* Post process on fatal error in the file operations */ #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } /* Re-entrancy related */ #if FF_FS_REENTRANT #if FF_USE_LFN == 1 #error Static LFN work area cannot be used at thread-safe configuration #endif #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif /* Definitions of volume - physical location conversion */ #if FF_MULTI_PARTITION #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif /* Definitions of sector size */ #if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) #error Wrong sector size configuration #endif #if FF_MAX_SS == FF_MIN_SS #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ #else #define SS(fs) ((fs)->ssize) /* Variable sector size */ #endif /* Timestamp */ #if FF_FS_NORTC == 1 #if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 #error Invalid FF_FS_NORTC settings #endif #define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) #else #define GET_FATTIME() get_fattime() #endif /* File lock controls */ #if FF_FS_LOCK != 0 #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif /* SBCS up-case tables (\x80-\xFF) */ #define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} #define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} #define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} #define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} /* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} #define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} /* Macros for table definitions */ #define MERGE_2STR(a, b) a ## b #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) /*-------------------------------------------------------------------------- Module Private Work Area ---------------------------------------------------------------------------*/ /* Remark: Variables defined here without initial value shall be guaranteed / zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ /*--------------------------------*/ /* File/Volume controls */ /*--------------------------------*/ #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 static BYTE CurrVol; /* Current drive */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif /*--------------------------------*/ /* LFN/Directory working buffer */ /*--------------------------------*/ #if FF_USE_LFN == 0 /* Non-LFN configuration */ #if FF_FS_EXFAT #error LFN must be enabled when enable exFAT #endif #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #else /* LFN configurations */ #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 #error Wrong setting of FF_MAX_LFN #endif #if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF #endif #if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 #error Wrong setting of FF_LFN_UNICODE #endif static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ #define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ #if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ #if FF_FS_EXFAT static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() #endif #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } #define MAX_MALLOC 0x4000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN #endif /* FF_USE_LFN == 1 */ #endif /* FF_USE_LFN == 0 */ /*--------------------------------*/ /* Code conversion tables */ /*--------------------------------*/ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct737[] = TBL_CT737; static const BYTE Ct771[] = TBL_CT771; static const BYTE Ct775[] = TBL_CT775; static const BYTE Ct850[] = TBL_CT850; static const BYTE Ct852[] = TBL_CT852; static const BYTE Ct855[] = TBL_CT855; static const BYTE Ct857[] = TBL_CT857; static const BYTE Ct860[] = TBL_CT860; static const BYTE Ct861[] = TBL_CT861; static const BYTE Ct862[] = TBL_CT862; static const BYTE Ct863[] = TBL_CT863; static const BYTE Ct864[] = TBL_CT864; static const BYTE Ct865[] = TBL_CT865; static const BYTE Ct866[] = TBL_CT866; static const BYTE Ct869[] = TBL_CT869; static const BYTE Dc932[] = TBL_DC932; static const BYTE Dc936[] = TBL_DC936; static const BYTE Dc949[] = TBL_DC949; static const BYTE Dc950[] = TBL_DC950; #elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); #else /* Static code page configuration (DBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); #endif /*-------------------------------------------------------------------------- Module Private Functions ---------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; rv = ptr[1]; rv = rv << 8 | ptr[0]; return rv; } static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; rv = ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #if FF_FS_EXFAT static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; rv = ptr[7]; rv = rv << 8 | ptr[6]; rv = rv << 8 | ptr[5]; rv = rv << 8 | ptr[4]; rv = rv << 8 | ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #endif #if !FF_FS_READONLY static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #if FF_FS_EXFAT static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #endif #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ /* Copy memory to memory */ static void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; if (cnt != 0) { do { *d++ = *s++; } while (--cnt); } } /* Fill memory block */ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; do { *d++ = (BYTE)val; } while (--cnt); } /* Compare memory block */ static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ { const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; do { r = *d++ - *s++; } while (--cnt && r == 0); return r; } /* Check if chr is contained in the string */ static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ { while (*str && *str != chr) str++; return *str; } /* Test if the character is DBC 1st byte */ static int dbc_1st (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } /* Test if the character is DBC 2nd byte */ static int dbc_2nd (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } #if FF_USE_LFN /* Get a character from TCHAR string in defined API encodeing */ static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ ) { DWORD uc; const TCHAR *p = *str; #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; uc = *p++; /* Get a unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ uc = uc << 16 | wc; } #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ BYTE b; int nf; uc = (BYTE)*p++; /* Get a unit */ if (uc & 0x80) { /* Multiple byte code? */ if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; } else { if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ uc &= 0x0F; nf = 2; } else { if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ uc &= 0x07; nf = 3; } else { /* Wrong sequence */ return 0xFFFFFFFF; } } } do { /* Get trailing bytes */ b = (BYTE)*p++; if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ uc = uc << 6 | (b & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ } #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ uc = (TCHAR)*p++; /* Get a unit */ if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ BYTE b; WCHAR wc; wc = (BYTE)*p++; /* Get a byte */ if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ b = (BYTE)*p++; /* Get 2nd byte */ if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ wc = (wc << 8) + b; /* Make a DBC */ } if (wc != 0) { wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ } uc = wc; #endif *str = p; /* Next read pointer */ return uc; } /* Output a TCHAR string in defined API encoding */ static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ ) { #if FF_LFN_UNICODE == 1 /* UTF-16 output */ WCHAR hs, wc; hs = (WCHAR)(chr >> 16); wc = (WCHAR)chr; if (hs == 0) { /* Single encoding unit? */ if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ *buf = wc; return 1; } if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ *buf++ = hs; *buf++ = wc; return 2; #elif FF_LFN_UNICODE == 2 /* UTF-8 output */ DWORD hc; if (chr < 0x80) { /* Single byte code? */ if (szb < 1) return 0; /* Buffer overflow? */ *buf = (TCHAR)chr; return 1; } if (chr < 0x800) { /* 2-byte sequence? */ if (szb < 2) return 0; /* Buffer overflow? */ *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 2; } if (chr < 0x10000) { /* 3-byte sequence? */ if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 3; } /* 4-byte sequence */ if (szb < 4) return 0; /* Buffer overflow? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 4; #elif FF_LFN_UNICODE == 3 /* UTF-32 output */ DWORD hc; if (szb < 1) return 0; /* Buffer overflow? */ if (chr >= 0x10000) { /* Out of BMP? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; } *buf++ = (TCHAR)chr; return 1; #else /* ANSI/OEM output */ WCHAR wc; wc = ff_uni2oem(chr, CODEPAGE); if (wc >= 0x100) { /* Is this a DBC? */ if (szb < 2) return 0; *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ return 2; } if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ *buf++ = (TCHAR)wc; /* Store the character */ return 1; #endif } #endif /* FF_USE_LFN */ #if FF_FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ static int lock_fs ( /* 1:Ok, 0:timeout */ FATFS* fs /* Filesystem object */ ) { return ff_req_grant(fs->sobj); } static void unlock_fs ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { ff_rel_grant(fs->sobj); } } #endif #if FF_FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ static FRESULT chk_lock ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) { UINT i, be; /* Search open object table for the object */ be = 0; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } if (i == FF_FS_LOCK) { /* The object has not been opened */ return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ } /* The object was opened. Reject any open against writing file and all write mode open */ return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; return (i == FF_FS_LOCK) ? 0 : 1; } static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ if (Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; Files[i].ofs = dp->dptr; Files[i].ctr = 0; } if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ return i + 1; /* Index number origin from 1 */ } static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { WORD n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { res = FR_INT_ERR; /* Invalid index nunber */ } return res; } static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs == fs) Files[i].fs = 0; } } #endif /* FF_FS_LOCK != 0 */ /*-----------------------------------------------------------------------*/ /* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res = FR_OK; if (fs->wflag) { /* Is the disk access window dirty */ if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ fs->wflag = 0; /* Clear window dirty flag */ if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } } else { res = FR_DISK_ERR; } } return res; } #endif static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs, /* Filesystem object */ DWORD sector /* Sector number to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; if (sector != fs->winsect) { /* Window offset changed? */ #if !FF_FS_READONLY res = sync_window(fs); /* Write-back changes */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) { sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sector; } } return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res; res = sync_window(fs); if (res == FR_OK) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); st_dword(fs->win + FSI_Free_Count, fs->free_clst); st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; disk_write(fs->pdrv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; } #endif /*-----------------------------------------------------------------------*/ /* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { clst -= 2; /* Cluster number is origin from 2 */ if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ return fs->database + fs->csize * clst; /* Start sector number of the cluster */ } /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; DWORD val; FATFS *fs = obj->fs; if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ val = 1; /* Internal error */ } else { val = 0xFFFFFFFF; /* Default value falls on disk error */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; #if FF_FS_EXFAT case FS_EXFAT : if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ break; } if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ if (obj->n_frag != 0) { /* Is it on the growing edge? */ val = 0x7FFFFFFF; /* Generate EOC */ } else { if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; } break; } } /* go to default */ #endif default: val = 1; /* Internal error */ } } return val; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) { UINT bc; BYTE *p; FRESULT res = FR_INT_ERR; if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ fs->wflag = 1; break; case FS_FAT16 : res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; case FS_FAT32 : #if FF_FS_EXFAT case FS_EXFAT : #endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } st_dword(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } } return res; } #endif /* !FF_FS_READONLY */ #if FF_FS_EXFAT && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ /*--------------------------------------*/ /* Find a contiguous free cluster block */ /*--------------------------------------*/ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ ) { BYTE bm, bv; UINT i; DWORD val, scl, ctr; clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ val = 0; bm = 0; i = SS(fs); } if (bv == 0) { /* Is it a free cluster? */ if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ } while (bm != 0); bm = 1; } while (++i < SS(fs)); } } /*----------------------------------------*/ /* Set/Clear a block of allocation bitmap */ /*----------------------------------------*/ static FRESULT change_bitmap ( FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ int bv /* bit value to be set (0 or 1) */ ) { BYTE bm; UINT i; DWORD sect; clst -= 2; /* The first bit corresponds to cluster #2 */ sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ i = clst / 8 % SS(fs); /* Byte offset in the sector */ bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { do { if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ fs->win[i] ^= bm; /* Flip the bit */ fs->wflag = 1; if (--ncl == 0) return FR_OK; /* All bits processed? */ } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ i = 0; } } /*---------------------------------------------*/ /* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_first_frag ( FFOBJID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; } obj->stat = 0; /* Change status 'FAT chain is valid' */ } return FR_OK; } /*---------------------------------------------*/ /* Fill the last fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_last_frag ( FFOBJID* obj, /* Pointer to the corresponding object */ DWORD lcl, /* Last cluster of the fragment */ DWORD term /* Value to set the last FAT entry */ ) { FRESULT res; while (obj->n_frag > 0) { /* Create the chain of last fragment */ res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); if (res != FR_OK) return res; obj->n_frag--; } return FR_OK; } #endif /* FF_FS_EXFAT && !FF_FS_READONLY */ #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; DWORD nxt; FATFS *fs = obj->fs; #if FF_FS_EXFAT || FF_USE_TRIM DWORD scl = clst, ecl = clst; #endif #if FF_USE_TRIM DWORD rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ /* Mark the previous cluster 'EOC' on the FAT if it exists */ if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { res = put_fat(fs, pclst, 0xFFFFFFFF); if (res != FR_OK) return res; } /* Remove the chain */ do { nxt = get_fat(obj, clst); /* Get cluster status */ if (nxt == 0) break; /* Empty cluster? */ if (nxt == 1) return FR_INT_ERR; /* Internal error? */ if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } #if FF_FS_EXFAT || FF_USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; } else { /* End of contiguous cluster block */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ if (res != FR_OK) return res; } #endif #if FF_USE_TRIM rt[0] = clst2sect(fs, scl); /* Start of data area freed */ rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ #endif scl = ecl = nxt; } #endif clst = nxt; /* Next cluster */ } while (clst < fs->n_fatent); /* Repeat while not the last link */ #if FF_FS_EXFAT /* Some post processes for chain status */ if (fs->fs_type == FS_EXFAT) { if (pclst == 0) { /* Has the entire chain been removed? */ obj->stat = 0; /* Change the chain status 'initial' */ } else { if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ while (clst != pclst) { nxt = get_fat(obj, clst); if (nxt < 2) return FR_INT_ERR; if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; if (nxt != clst + 1) break; /* Not contiguous? */ clst++; } if (clst == pclst) { /* Has the chain got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } else { if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } } } #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { DWORD cs, ncl, scl; FRESULT res; FATFS *fs = obj->fs; if (clst == 0) { /* Create a new chain */ scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ if (cs < 2) return 1; /* Test for insanity */ if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; /* Cluster to start to find */ } if (fs->free_clst == 0) return 0; /* No free cluster */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ obj->stat = 2; /* Set status 'contiguous' */ } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } if (obj->stat != 2) { /* Is the file non-contiguous? */ if (ncl == clst + 1) { /* Is the cluster next to previous one? */ obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ } else { /* New fragment */ if (obj->n_frag == 0) obj->n_frag = 1; res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ if (res == FR_OK) obj->n_frag = 1; } } } else #endif { /* On the FAT/FAT32 volume */ ncl = 0; if (scl == clst) { /* Stretching an existing chain? */ ncl = scl + 1; /* Test if next cluster is free */ if (ncl >= fs->n_fatent) ncl = 2; cs = get_fat(obj, ncl); /* Get next cluster status */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (cs != 0) { /* Not free? */ cs = fs->last_clst; /* Start at suggested cluster if it is valid */ if (cs >= 2 && cs < fs->n_fatent) scl = cs; ncl = 0; } } if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ if (ncl >= fs->n_fatent) { /* Check wrap-around */ ncl = 2; if (ncl > scl) return 0; /* No free cluster found? */ } cs = get_fat(obj, ncl); /* Get the cluster status */ if (cs == 0) break; /* Found a free cluster? */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (ncl == scl) return 0; /* No free cluster found? */ } } res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } #endif /* !FF_FS_READONLY */ #if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { DWORD cl, ncl, *tbl; FATFS *fs = fp->obj.fs; tbl = fp->cltbl + 1; /* Top of CLMT */ cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ for (;;) { ncl = *tbl++; /* Number of cluters in the fragment */ if (ncl == 0) return 0; /* End of table? (error) */ if (cl < ncl) break; /* In this fragment? */ cl -= ncl; tbl++; /* Next fragment */ } return cl + *tbl; /* Return the cluster number */ } #endif /* FF_USE_FASTSEEK */ /*-----------------------------------------------------------------------*/ /* Directory handling - Fill a cluster with zeros */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ FATFS *fs, /* Filesystem object */ DWORD clst /* Directory table to clear */ ) { DWORD sect; UINT n, szb; BYTE *ibuf; if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ sect = clst2sect(fs, clst); /* Top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */ mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ /* Allocate a temporary buffer */ for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; if (szb > SS(fs)) { /* Buffer allocated? */ mem_set(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ ff_memfree(ibuf); } else #endif { ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ } return (n == fs->csize) ? FR_OK : FR_DISK_ERR; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) { DWORD csz, clst; FATFS *fs = dp->obj.fs; if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; } dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ clst = fs->dirbase; if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } if (clst == 0) { /* Static table (root-directory on the FAT volume) */ if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ dp->sect = fs->dirbase; } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ while (ofs >= csz) { /* Follow cluster chain */ clst = get_fat(&dp->obj, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ ofs -= csz; } dp->sect = clst2sect(fs, clst); } dp->clust = clst; /* Current cluster# */ if (dp->sect == 0) return FR_INT_ERR; dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ return FR_OK; } /*-----------------------------------------------------------------------*/ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ DIR* dp, /* Pointer to the directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs; ofs = dp->dptr + SZDIRE; /* Next entry */ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ #if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ dp->sect = clst2sect(fs, clst); } } } dp->dptr = ofs; /* Current entry */ dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ return FR_OK; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to the directory object */ UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; UINT n; FATFS *fs = dp->obj.fs; res = dir_sdi(dp, 0); if (res == FR_OK) { n = 0; do { res = move_window(fs, dp->sect); if (res != FR_OK) break; #if FF_FS_EXFAT if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { #endif if (++n == nent) break; /* A block of contiguous free entries is found */ } else { n = 0; /* Not a blank entry. Restart to search */ } res = dir_next(dp, 1); } while (res == FR_OK); /* Next entry with table stretch enabled */ } if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ FATFS* fs, /* Pointer to the fs object */ const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; cl = ld_word(dir + DIR_FstClusLO); if (fs->fs_type == FS_FAT32) { cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; } return cl; } #if !FF_FS_READONLY static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ ) { st_word(dir + DIR_FstClusLO, (WORD)cl); if (fs->fs_type == FS_FAT32) { st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); } } #endif #if FF_USE_LFN /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ return 1; /* The part of LFN matched */ } #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } return 1; /* The part of LFN is valid */ } #endif #if !FF_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ BYTE sum /* Checksum of the corresponding SFN */ ) { UINT i, s; WCHAR wc; dir[LDIR_Chksum] = sum; /* Set checksum */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Type] = 0; st_word(dir + LDIR_FstClusLO, 0); i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ s = wc = 0; do { if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ st_word(dir + LfnOfs[s], wc); /* Put it */ if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ } while (++s < 13); if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LFN */ #if FF_USE_LFN && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ UINT seq /* Sequence number */ ) { BYTE ns[8], c; UINT i, j; WCHAR wc; DWORD sr; mem_cpy(dst, src, 11); if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sr = (sr << 1) + (wc & 1); wc >>= 1; if (sr & 0x10000) sr ^= 0x11021; } } seq = (UINT)sr; } /* itoa (hexdecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); if (c > '9') c += 7; ns[i--] = c; seq /= 16; } while (seq); ns[i] = '~'; /* Append the number to the SFN body */ for (j = 0; j < i && dst[j] != ' '; j++) { if (dbc_1st(dst[j])) { if (j == i - 1) break; j++; } } do { dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } #endif /* FF_USE_LFN && !FF_FS_READONLY */ #if FF_USE_LFN /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { BYTE sum = 0; UINT n = 11; do { sum = (sum >> 1) + (sum << 7) + *dir++; } while (--n); return sum; } #endif /* FF_USE_LFN */ #if FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { UINT i, szblk; WORD sum; szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; } } return sum; } static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { WCHAR chr; WORD sum = 0; while ((chr = *name++) != 0) { chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } return sum; } #if !FF_FS_READONLY && FF_USE_MKFS static DWORD xsum32 ( /* Returns 32-bit checksum */ BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; return sum; } #endif #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { WCHAR wc, hs; UINT di, si, nc; /* Get file name from the entry block */ si = SZDIRE * 2; /* 1st C1 entry */ nc = 0; hs = 0; di = 0; while (nc < dirb[XDIR_NumName]) { if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Load stream-extension entry */ res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Load file-name entries */ i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ if (i <= MAXDIRB(FF_MAX_LFN)) { if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; } return FR_OK; } /*------------------------------------------------------------------*/ /* exFAT: Initialize object allocation info with loaded entry block */ /*------------------------------------------------------------------*/ static void init_alloc_info ( FATFS* fs, /* Filesystem object */ FFOBJID* obj /* Object allocation information to be initialized */ ) { obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ obj->n_frag = 0; /* No last fragment info */ } #if !FF_FS_READONLY || FF_FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_xdir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ const FFOBJID* obj /* Object with its containing directory information */ ) { FRESULT res; /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } return res; } #endif #if !FF_FS_READONLY /*----------------------------------------*/ /* exFAT: Store the directory entry block */ /*----------------------------------------*/ static FRESULT store_xdir ( DIR* dp /* Pointer to the direcotry object */ ) { FRESULT res; UINT nent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; /* Store the direcotry entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; mem_cpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; if (--nent == 0) break; dirb += SZDIRE; res = dir_next(dp, 0); } return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; } /*-------------------------------------------*/ /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; BYTE nc1, nlen; WCHAR wc; /* Create file-directory and stream-extension entry */ mem_set(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; /* Create file-name entries */ i = SZDIRE * 2; /* Top of file_name entries */ nlen = nc1 = 0; wc = 1; do { dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ st_word(dirb + i, wc); /* Store it */ i += 2; } while (i % SZDIRE != 0); nc1++; } while (lfn[nlen]); /* Fill next entry if any char follows */ dirb[XDIR_NumName] = nlen; /* Set name length */ dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_EXFAT */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ #define DIR_READ_FILE(dp) dir_read(dp, 0) #define DIR_READ_LABEL(dp) dir_read(dp, 1) static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; BYTE attr, b; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; b = dp->dir[DIR_Name]; /* Test for the entry type */ if (b == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { if (b == ET_VLABEL) break; /* Volume label entry? */ } else { if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ } break; } } } else #endif { /* On the FAT/FAT32 volume */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { if (attr == AM_LFN) { /* An LFN entry is found */ if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } } #else /* Non LFN configuration */ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif } res = dir_next(dp, 0); /* Next entry */ if (res != FR_OK) break; } if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ return res; } #endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ /*-----------------------------------------------------------------------*/ /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; #if FF_USE_LFN BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } return res; } #endif /* On the FAT/FAT32 volume */ #if FF_USE_LFN ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ #if FF_USE_LFN /* LFN configuration */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ sum = dp->dir[LDIR_Chksum]; c &= (BYTE)~LLEF; ord = c; /* LFN start order */ dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ UINT n, nlen, nent; BYTE sn[12], sum; if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ dp->obj.stat &= ~4; res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ DIR dj; res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } } create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif /* On the FAT/FAT32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } if (n == 100) return FR_DENIED; /* Abort if too many collisions */ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ dp->fn[NSFLAG] = sn[NSFLAG]; } /* Create an SFN with/without LFNs. */ nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ res = dir_alloc(dp, nent); /* Allocate entries */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */ res = dir_sdi(dp, dp->dptr - nent * SZDIRE); if (res == FR_OK) { sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); } } #else /* Non LFN configuration */ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ #endif /* Set SFN entry */ if (res == FR_OK) { res = move_window(fs, dp->sect); if (res == FR_OK) { mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif fs->wflag = 1; } } return res; } #endif /* !FF_FS_READONLY */ #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ DWORD last = dp->dptr; res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { res = move_window(fs, dp->sect); if (res != FR_OK) break; if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ } else { /* On the FAT/FAT32 volume */ dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR; } #else /* Non LFN configuration */ res = move_window(fs, dp->sect); if (res == FR_OK) { dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ fs->wflag = 1; } #endif return res; } #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ static void get_fileinfo ( DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { UINT si, di; #if FF_USE_LFN BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else TCHAR c; #endif fno->fname[0] = 0; /* Invaidate file info */ if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ #if FF_USE_LFN /* LFN configuration */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ get_xfileinfo(fs->dirbuf, fno); return; } else #endif { /* On the FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ si = di = hs = 0; while (fs->lfnbuf[si] != 0) { wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ } } si = di = 0; while (si < 11) { /* Get SFN from SFN entry */ wc = dp->dir[si++]; /* Get a char */ if (wc == ' ') continue; /* Skip padding spaces */ if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ #if FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ if (wc == 0) { di = 0; break; } /* Buffer overflow? */ di += wc; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; if (wc == '.') lcf = NS_EXT; if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } fno->fname[di] = 0; /* Terminate the LFN */ if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ } #else /* Non-LFN configuration */ si = di = 0; while (si < 11) { /* Copy name body and extension */ c = (TCHAR)dp->dir[si++]; if (c == ' ') continue; /* Skip padding spaces */ if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ fno->fname[di++] = c; } fno->fname[di] = 0; #endif fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ static DWORD get_achar ( /* Get a character and advances ptr */ const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { DWORD chr; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ chr = tchar2uni(ptr); if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ chr = ff_wtoupper(chr); #else /* ANSI/OEM input */ chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ #if FF_CODE_PAGE == 0 if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #elif FF_CODE_PAGE < 900 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #endif #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; } #endif #endif return chr; } static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ int inf /* Infinite search (* specified) */ ) { const TCHAR *pp, *np; DWORD pc, nc; int nm, nx; while (skip--) { /* Pre-skip name chars */ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ } if (*pat == 0 && inf) return 1; /* (short circuit) */ do { pp = pat; np = nam; /* Top of pattern and name to match */ for (;;) { if (*pp == '?' || *pp == '*') { /* Wildcard? */ nm = nx = 0; do { /* Analyze the wildcard block */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ nc = *np; break; /* Branch mismatched */ } pc = get_achar(&pp); /* Get a pattern char */ nc = get_achar(&np); /* Get a name char */ if (pc != nc) break; /* Branch mismatched? */ if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ } get_achar(&nam); /* nam++ */ } while (inf && nc); /* Retry until end of name if infinite search is specified */ return 0; } #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ /*-----------------------------------------------------------------------*/ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ DIR* dp, /* Pointer to the directory object */ const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; WCHAR wc, *lfn; DWORD uc; UINT i, ni, si, di; const TCHAR *p; /* Create LFN into LFN working buffer */ p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { uc = tchar2uni(&p); /* Get a character */ if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ wc = (WCHAR)uc; if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ lfn[di++] = wc; /* Store the Unicode character */ } while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ *path = p; /* Return pointer to the next segment */ cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ #if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; } dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif while (di) { /* Snip off trailing spaces and dots if exist */ wc = lfn[di - 1]; if (wc != ' ' && wc != '.') break; di--; } lfn[di] = 0; /* LFN is created into the working buffer */ if (di == 0) return FR_INVALID_NAME; /* Reject null name */ /* Create SFN in directory form */ for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ mem_set(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { wc = lfn[si++]; /* Get an LFN character */ if (wc == 0) break; /* Break on end of the LFN */ if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ cf |= NS_LOSS | NS_LFN; continue; } if (i >= ni || si == di) { /* End of field? */ if (ni == 11) { /* Name extension overflow? */ cf |= NS_LOSS | NS_LFN; break; } if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ if (si > di) break; /* No name extension? */ si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ continue; } if (wc >= 0x80) { /* Is this a non-ASCII character? */ cf |= NS_LFN; /* LFN entry needs to be created */ #if FF_CODE_PAGE == 0 if (ExCvt) { /* At SBCS */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ } else { /* At DBCS */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ } #elif FF_CODE_PAGE < 900 /* SBCS cfg */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ #else /* DBCS cfg */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ #endif } if (wc >= 0x100) { /* Is this a DBC? */ if (i >= ni - 1) { /* Field overflow? */ cf |= NS_LOSS | NS_LFN; i = ni; continue; /* Next field */ } dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { if (IsUpper(wc)) { /* ASCII upper case? */ b |= 2; } if (IsLower(wc)) { /* ASCII lower case? */ b |= 1; wc -= 0x20; } } } dp->fn[i++] = (BYTE)wc; } if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ } dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ return FR_OK; #else /* FF_USE_LFN : Non-LFN configuration */ BYTE c, d, *sfn; UINT ni, si, i; const char *p; /* Create file name in directory form */ p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = 0; ni = 8; #if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; if (c != '.' || si >= 3) break; sfn[i++] = c; } if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } #endif for (;;) { c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (c == '/' || c == '\\') { /* Break if a separator is found */ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ i = 8; ni = 11; /* Enter file extension field */ continue; } #if FF_CODE_PAGE == 0 if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #elif FF_CODE_PAGE < 900 if (c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #endif if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ d = (BYTE)p[si++]; /* Get 2nd byte */ if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } *path = p + si; /* Return pointer to the next segment */ if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; #endif /* FF_USE_LFN */ } /*-----------------------------------------------------------------------*/ /* Follow a file path */ /*-----------------------------------------------------------------------*/ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ DIR* dp, /* Directory object to return last directory and found object */ const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; FATFS *fs = dp->obj.fs; #if FF_FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ dp->obj.sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ dp->obj.sclust = 0; /* Start from root directory */ } #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ #if FF_FS_RPATH != 0 if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ DIR dj; dp->obj.c_scl = fs->cdc_scl; dp->obj.c_size = fs->cdc_size; dp->obj.c_ofs = fs->cdc_ofs; res = load_obj_xdir(&dj, &dp->obj); if (res != FR_OK) return res; dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } #endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); } else { /* Follow path */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } } break; } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ dp->obj.c_scl = dp->obj.sclust; dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Open next directory */ } else #endif { dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } return res; } /*-----------------------------------------------------------------------*/ /* Get logical drive number from path name */ /*-----------------------------------------------------------------------*/ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ const TCHAR** path /* Pointer to pointer to the path name */ ) { const TCHAR *tp, *tt; TCHAR tc; int i, vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ const char *sp; char c; #endif tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ i = (int)*tp - '0'; /* Get the LD number */ } #if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ else { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *tp++; if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tt; /* Snip the drive prefix off */ } return vol; } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ if (*tp == '/') { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *(++tp); if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tp; /* Snip the drive prefix off */ return vol; } } #endif /* No drive prefix is found */ #if FF_FS_RPATH != 0 vol = CurrVol; /* Default drive is current drive */ #else vol = 0; /* Default drive is 0 */ #endif return vol; /* Return the default drive */ } /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ FATFS* fs, /* Filesystem object */ DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always here regardless of the sector size) */ #if FF_FS_EXFAT if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ #endif if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ } return 2; /* Valid BS but not FAT */ } /*-----------------------------------------------------------------------*/ /* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; int vol; DSTATUS stat; DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; WORD nrsv; FATFS *fs; UINT i; /* Get logical drive number */ *rfs = 0; vol = get_ldnumber(path); if (vol < 0) return FR_INVALID_DRIVE; /* Check if the filesystem object is valid or not */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ #endif *rfs = fs; /* Return pointer to the filesystem object */ mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type != 0) { /* If the volume has been mounted */ stat = disk_status(fs->pdrv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ EFSPRINTF("WPEN1"); return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is valid */ } } /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ EFSPRINTF("MDNR"); return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ EFSPRINTF("WPEN2"); return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + (MBR_Table + i * SZ_PTE); br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ if (i != 0) i--; do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) { EFSPRINTF("BRNL"); return FR_DISK_ERR; /* An error occured in the disk I/O layer */ } if (fmt >= 2) { EFSPRINTF("NOFAT"); return FR_NO_FILESYSTEM; /* No FAT volume is found */ } /* An FAT volume is found (bsect). Following code initializes the filesystem object */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; DWORD so, cv, bcl; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ EFSPRINTF("EXSPS"); return FR_NO_FILESYSTEM; } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) { EFSPRINTF("EXFNF"); return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ } fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ fs->n_fatent = nclst + 2; /* Boundaries and Limits */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ so = i = 0; for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ if (i == 0) { if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) { EFSPRINTF("EXBM1C"); return FR_DISK_ERR; } so++; } if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ if (bcl < 2 || bcl >= fs->n_fatent) { EFSPRINTF("EXBMM"); return FR_NO_FILESYSTEM; } fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ for (;;) { /* Check if bitmap is contiguous */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ if (cv != ++bcl) { EFSPRINTF("EXBMM"); return FR_NO_FILESYSTEM; /* Fragmented? */ } } #if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else #endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) { EFSPRINTF("32SPS"); return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ } fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ fasize *= fs->n_fats; /* Number of sectors for FAT area */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = 0; if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ fs->n_fatent = nclst + 2; /* Number of FAT entries */ fs->volbase = bsect; /* Volume start sector */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !FF_FS_READONLY /* Get FSInfo if available */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; #if (FF_FS_NOFSINFO & 3) != 3 if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) { #if (FF_FS_NOFSINFO & 1) == 0 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif #if (FF_FS_NOFSINFO & 2) == 0 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif } } #endif /* (FF_FS_NOFSINFO & 3) != 3 */ #endif /* !FF_FS_READONLY */ } fs->fs_type = fmt; /* FAT sub-type */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if FF_FS_EXFAT fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */ #endif #endif #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif #if FF_FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { FRESULT res = FR_INVALID_OBJECT; if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } else { unlock_fs(obj->fs, FR_OK); } } else { res = FR_TIMEOUT; } #else if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif } *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ return res; } /*--------------------------------------------------------------------------- Public Functions (FatFs API) ----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) { FATFS *cfs; int vol; FRESULT res; const TCHAR *rp = path; /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) { EFSPRINTF("IDRIVE!"); return FR_INVALID_DRIVE; } cfs = FatFs[vol]; /* Pointer to fs object */ if (cfs) { #if FF_FS_LOCK != 0 clear_lock(cfs); #endif #if FF_FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; #endif cfs->fs_type = 0; /* Clear old fs object */ } if (fs) { fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; #endif } FatFs[vol] = fs; /* Register new fs object */ if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ res = find_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Open or Create a File */ /*-----------------------------------------------------------------------*/ FRESULT f_open ( FIL* fp, /* Pointer to the blank file object */ const TCHAR* path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; DIR dj; FATFS *fs; #if !FF_FS_READONLY DWORD dw, cl, bcs, clst, sc; FSIZE_t ofs; #endif DEF_NAMBUF if (!fp) return FR_INVALID_OBJECT; /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = find_volume(&path, &fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } #if FF_FS_LOCK != 0 else { res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ #if FF_FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif } mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object with the same name is already existing */ if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ fp->obj.fs = fs; init_alloc_info(fs, &fp->obj); /* Set directory entry block initial state */ mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ } } else #endif { /* Set directory entry initial state */ cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ dw = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { res = move_window(fs, dw); fs->last_clst = cl - 1; /* Reuse the cluster hole */ } } } } } else { /* Open an existing file */ if (res == FR_OK) { /* Is the object exsiting? */ if (dj.obj.attr & AM_DIR) { /* File open against a directory */ res = FR_NO_FILE; } else { if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ res = FR_DENIED; } } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; #if FF_FS_LOCK != 0 fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; } else { if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ res = FR_NO_FILE; } } } #endif if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; init_alloc_info(fs, &fp->obj); } else #endif { fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif fp->obj.fs = fs; /* Validate the file object */ fp->obj.id = fs->id; fp->flag = mode; /* Set file access mode */ fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ clst = fp->obj.sclust; /* Follow the cluster chain */ for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { clst = get_fat(&fp->obj, clst); if (clst <= 1) res = FR_INT_ERR; if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ if ((sc = clst2sect(fs, clst)) == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } } } #endif } FREE_NAMBUF(); } if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Read File */ /*-----------------------------------------------------------------------*/ FRESULT f_read ( FIL* fp, /* Pointer to the file object */ void* buff, /* Pointer to data buffer */ UINT btr, /* Number of bytes to read */ UINT* br /* Pointer to number of bytes read */ ) { FRESULT res; FATFS *fs; DWORD clst, sect; FSIZE_t remain; UINT rcnt, cc, csect; BYTE *rbuff = (BYTE*)buff; UINT br_tmp; if (!br) br = &br_tmp; *br = 0; /* Clear read byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until btr bytes read */ btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ } } if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Update current cluster */ } sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Read maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) { EFSPRINTF("RLIO"); ABORT(fs, FR_DISK_ERR); } #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } #else if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); } #endif #endif rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if !FF_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { EFSPRINTF("RDC"); ABORT(fs, FR_DISK_ERR); } fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { EFSPRINTF("RSC"); ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } } #endif fp->sect = sect; } rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } LEAVE_FF(fs, FR_OK); } #ifdef FF_FASTFS /*-----------------------------------------------------------------------*/ /* Fast Read Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ #if FF_USE_FASTSEEK FRESULT f_read_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ UINT btr /* Number of bytes to read */ ) { FRESULT res; FATFS *fs; UINT csize_bytes; DWORD clst; DWORD wbytes; UINT count; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; BYTE *wbuff = (BYTE*)buff; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ FSIZE_t remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ csize_bytes = fs->csize * SS(fs); DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ /* If inside a cluster, read the sectors and align to cluster. */ if (csect) { wbytes = MIN(btr, (fs->csize - csect) * SS(fs)); f_read(fp, wbuff, wbytes, (void *)0); wbuff += wbytes; btr -= wbytes; if (!btr) goto out; } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ } else { if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } } if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ wbytes = MIN(btr, csize_bytes); sector_base = clst2sect(fs, fp->clust); count = wbytes / SS(fs); fp->fptr += wbytes; btr -= wbytes; if (!btr) { /* Final cluster/sectors read. */ if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); goto out; } while (btr) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; work_sector = clst2sect(fs, fp->clust); wbytes = MIN(btr, csize_bytes); if ((work_sector - sector_base) == count) count += wbytes / SS(fs); else { if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; count = wbytes / SS(fs); } fp->fptr += wbytes; btr -= wbytes; if (!btr) { /* Final cluster/sectors read. */ if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); } } out: LEAVE_FF(fs, FR_OK); } #endif #endif #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ FRESULT f_write ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write */ UINT* bw /* Pointer to number of bytes written */ ) { FRESULT res; FATFS *fs; DWORD clst, sect; UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; UINT bw_tmp; if (!bw) bw = &bw_tmp; *bw = 0; /* Clear write byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ if (clst == 0) { /* If no cluster is allocated, */ clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ } } else { /* On the middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ } } if (clst == 0) { EFSPRINTF("DSKFULL"); break; /* Could not allocate a new cluster (disk full) */ } if (clst == 1) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Update current cluster */ if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if FF_FS_TINY if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Write maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) { EFSPRINTF("WLIO"); ABORT(fs, FR_DISK_ERR); } #if FF_FS_MINIMIZE <= 2 #if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; } #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); fp->flag &= (BYTE)~FA_DIRTY; } #endif #endif wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if FF_FS_TINY if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; } #else if (fp->sect != sect && /* Fill sector cache with file data */ fp->fptr < fp->obj.objsize && disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { ABORT(fs, FR_DISK_ERR); } #endif fp->sect = sect; } wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; #else mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fp->flag |= FA_DIRTY; #endif } fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } #ifdef FF_FASTFS /*-----------------------------------------------------------------------*/ /* Fast Write Aligned Sized File Without a Cache */ /*-----------------------------------------------------------------------*/ #if FF_USE_FASTSEEK FRESULT f_write_fast ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ UINT btw /* Number of bytes to write */ ) { FRESULT res; FATFS *fs; UINT csize_bytes; DWORD clst; DWORD wbytes; UINT count; FSIZE_t work_sector = 0; FSIZE_t sector_base = 0; BYTE *wbuff = (BYTE*)buff; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) { EFSPRINTF("FOV"); LEAVE_FF(fs, res); /* Check validity */ } if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } csize_bytes = fs->csize * SS(fs); DWORD csect = (UINT)((fp->fptr / SS(fs)) & (fs->csize - 1)); /* Sector offset in the cluster */ /* If inside a cluster, write the sectors and align to cluster. */ if (csect) { wbytes = MIN(btw, (fs->csize - csect) * SS(fs)); f_write(fp, wbuff, wbytes, (void *)0); /* Ensure flushing of it. FatFS is not notified for next write if raw. */ f_sync(fp); wbuff += wbytes; btw -= wbytes; if (!btw) goto out; } if (!fp->fptr) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ } else { if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); } } if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; /* Set working cluster */ wbytes = MIN(btw, csize_bytes); sector_base = clst2sect(fs, fp->clust); count = wbytes / SS(fs); fp->fptr += wbytes; btw -= wbytes; if (!btw) { /* Final cluster/sectors write. */ if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; goto out; } while (btw) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); } else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); } fp->clust = clst; work_sector = clst2sect(fs, fp->clust); wbytes = MIN(btw, csize_bytes); if ((work_sector - sector_base) == count) count += wbytes / SS(fs); else { if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); wbuff += count * SS(fs); sector_base = work_sector; count = wbytes / SS(fs); } fp->fptr += wbytes; btw -= wbytes; if (!btw) { /* Final cluster/sectors write. */ if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } } out: fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } #endif #endif /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ FRESULT f_sync ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD tm; BYTE *dir; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ if (res == FR_OK) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } if (res == FR_OK) { DIR dj; DEF_NAMBUF INIT_NAMBUF(fs); res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; st_dword(fs->dirbuf + XDIR_AccTime, 0); res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); fp->flag &= (BYTE)~FA_MODIFIED; } } FREE_NAMBUF(); } } else #endif { res = move_window(fs, fp->dir_sect); if (res == FR_OK) { dir = fp->dir_ptr; dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); fs->wflag = 1; res = sync_fs(fs); /* Restore it to the directory */ fp->flag &= (BYTE)~FA_MODIFIED; } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Close File */ /*-----------------------------------------------------------------------*/ FRESULT f_close ( FIL* fp /* Pointer to the file object to be closed */ ) { FRESULT res; FATFS *fs; #if !FF_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { #if FF_FS_LOCK != 0 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } } return res; } #if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( const TCHAR* path /* Drive number to set */ ) { int vol; /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { #if FF_STR_VOLUME_ID == 2 UINT i; #endif FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; fs->cdc_size = dj.obj.c_size; fs->cdc_ofs = dj.obj.c_ofs; } #endif } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fs->cdc_ofs = dj.blk_ofs; } else #endif { fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ } } else { res = FR_NO_PATH; /* Reached but a file */ } } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; #if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ if (res == FR_OK) { for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; } #endif } LEAVE_FF(fs, res); } #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( TCHAR* buff, /* Pointer to the directory path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID const char *vp; #endif #endif FILINFO fno; DEF_NAMBUF /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; res = move_window(fs, dj.sect); if (res != FR_OK) break; dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ for (n = 0; fno.fname[n]; n++) ; /* Name length */ if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } if (res == FR_OK) { if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ #if FF_VOLUMES >= 2 /* Put drive prefix */ vl = 0; #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; if (i >= n + 2) { if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; vl++; } #else /* Numeric volume ID */ if (i >= 3) { *tp++ = (TCHAR)'0' + CurrVol; *tp++ = (TCHAR)':'; vl = 2; } #endif if (vl == 0) res = FR_NOT_ENOUGH_CORE; #endif /* Add current directory path */ if (res == FR_OK) { do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } FREE_NAMBUF(); } *tp = 0; LEAVE_FF(fs, res); } #endif /* FF_FS_RPATH >= 2 */ #endif /* FF_FS_RPATH >= 1 */ #if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File pointer from top of file */ ) { FRESULT res; FATFS *fs; DWORD clst, bcs, nsect; FSIZE_t ifptr; #if FF_USE_FASTSEEK DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) res = (FRESULT)fp->err; #if FF_FS_EXFAT && !FF_FS_READONLY if (res == FR_OK && fs->fs_type == FS_EXFAT) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } #endif if (res != FR_OK) LEAVE_FF(fs, res); #if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ cl = fp->obj.sclust; /* Origin of the chain */ if (cl != 0) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ do { pcl = cl; ncl++; cl = get_fat(&fp->obj, cl); if (cl <= 1) ABORT(fs, FR_INT_ERR); if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); } while (cl == pcl + 1); if (ulen <= tlen) { /* Store the length and top of the fragment */ *tbl++ = ncl; *tbl++ = tcl; } } while (cl < fs->n_fatent); /* Repeat until end of chain */ } *fp->cltbl = ulen; /* Number of items used */ if (ulen <= tlen) { *tbl = 0; /* Terminate table */ } else { res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ } } else { /* Fast seek */ if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ if (ofs > 0) { fp->clust = clmt_clust(fp, ofs - 1); dsc = clst2sect(fs, fp->clust); if (dsc == 0) ABORT(fs, FR_INT_ERR); dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } } } } else #endif /* Normal Seek */ { #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ #endif if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs > 0) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->obj.sclust; /* start from the first cluster */ #if !FF_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(&fp->obj, 0); if (clst == 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->obj.sclust = clst; } #endif fp->clust = clst; } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ ofs -= bcs; fp->fptr += bcs; #if !FF_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ if (clst == 0) { /* Clip file size in case of disk full */ ofs = 0; break; } } else #endif { clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ } if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; } fp->fptr += ofs; if (ofs % SS(fs)) { nsect = clst2sect(fs, clst); /* Current sector */ if (nsect == 0) ABORT(fs, FR_INT_ERR); nsect += (DWORD)(ofs / SS(fs)); } } } if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } } LEAVE_FF(fs, res); } #ifdef FF_FASTFS #if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ DWORD *f_expand_cltbl ( FIL* fp, /* Pointer to the file object */ UINT tblsz, /* Size of table */ DWORD *tbl, /* Table pointer */ FSIZE_t ofs /* File pointer from top of file */ ) { if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */ fp->cltbl = (DWORD *)tbl; fp->cltbl[0] = tblsz; if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */ fp->cltbl = (void *)0; EFSPRINTF("CLTBLSZ"); return (void *)0; } f_lseek(fp, 0); return fp->cltbl; } #endif #endif #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( DIR* dp, /* Pointer to directory object to create */ const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { dp->obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ } else #endif { dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; } } if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ #if FF_FS_LOCK != 0 if (res == FR_OK) { if (dp->obj.sclust != 0) { dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ } } #endif } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Close Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_closedir ( DIR *dp /* Pointer to the directory object to be closed */ ) { FRESULT res; FATFS *fs; res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { #if FF_FS_LOCK != 0 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } FREE_NAMBUF(); } } LEAVE_FF(fs, res); } #if FF_USE_FIND /*-----------------------------------------------------------------------*/ /* Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to the file information structure */ ) { FRESULT res; for (;;) { res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ #if FF_USE_LFN && FF_USE_FIND == 2 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( DIR* dp, /* Pointer to the blank directory object */ FILINFO* fno, /* Pointer to the file information structure */ const TCHAR* path, /* Pointer to the directory to open */ const TCHAR* pattern /* Pointer to the matching pattern */ ) { FRESULT res; dp->pat = pattern; /* Save pointer to pattern string */ res = f_opendir(dp, path); /* Open the target directory */ if (res == FR_OK) { res = f_findnext(dp, fno); /* Find the first item */ } return res; } #endif /* FF_USE_FIND */ #if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ FRESULT f_stat ( const TCHAR* path, /* Pointer to the file path */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; DIR dj; DEF_NAMBUF /* Get logical drive */ res = find_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ res = FR_INVALID_NAME; } else { /* Found an object */ if (fno) get_fileinfo(&dj, fno); } } FREE_NAMBUF(); } LEAVE_FF(dj.obj.fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( const TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ ) { FRESULT res; FATFS *fs; DWORD nfree, clst, sect, stat; UINT i; FFOBJID obj; /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { if (fatfs) *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { /* Scan FAT to obtain number of free clusters */ nfree = 0; if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ BYTE bm; UINT b; clst = fs->n_fatent - 2; /* Number of clusters */ sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { if (!(bm & 1)) nfree++; bm >>= 1; } i = (i + 1) % SS(fs); } while (clst); } else #endif { /* FAT16/32: Scan WORD/DWORD FAT entries */ clst = fs->n_fatent; /* Number of entries */ sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } if (fs->fs_type == FS_FAT16) { if (ld_word(fs->win + i) == 0) nfree++; i += 2; } else { if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; i += 4; } i %= SS(fs); } while (--clst); } } *nclst = nfree; /* Return the free clusters */ fs->free_clst = nfree; /* Now free_clst is valid */ fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ } } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Truncate File */ /*-----------------------------------------------------------------------*/ FRESULT f_truncate ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD ncl; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; } else { /* When truncate a part of the file, remove remaining clusters */ ncl = get_fat(&fp->obj, fp->clust); res = FR_OK; if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; if (ncl == 1) res = FR_INT_ERR; if (res == FR_OK && ncl < fs->n_fatent) { res = remove_chain(&fp->obj, ncl, fp->clust); } } fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ fp->flag |= FA_MODIFIED; #if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { fp->flag &= (BYTE)~FA_DIRTY; } } #endif if (res != FR_OK) ABORT(fs, res); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( const TCHAR* path /* Pointer to the file or directory path */ ) { FRESULT res; DIR dj, sdj; DWORD dclst = 0; FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif DEF_NAMBUF /* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } #if FF_FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { if (dj.obj.attr & AM_RDO) { res = FR_DENIED; /* Cannot remove R/O object */ } } if (res == FR_OK) { #if FF_FS_EXFAT obj.fs = fs; if (fs->fs_type == FS_EXFAT) { init_alloc_info(fs, &obj); dclst = obj.sclust; } else #endif { dclst = ld_clust(fs, dj.dir); } if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if FF_FS_RPATH != 0 if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { sdj.obj.objsize = obj.objsize; sdj.obj.stat = obj.stat; } #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } } if (res == FR_OK) { res = dir_remove(&dj); /* Remove the directory entry */ if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ #if FF_FS_EXFAT res = remove_chain(&obj, dclst, 0); #else res = remove_chain(&dj.obj, dclst, 0); #endif } if (res == FR_OK) res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Create a Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; DIR dj; FFOBJID sobj; FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Name collision? */ if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } if (res == FR_NO_FILE) { /* It is clear to create a new directory */ sobj.fs = fs; /* New object id to create a new chain */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); if (res == FR_OK) { res = dir_clear(fs, dcl); /* Clean up the new table */ if (res == FR_OK) { if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ fs->win[DIR_Name] = '.'; fs->win[DIR_Attr] = AM_DIR; st_dword(fs->win + DIR_ModTime, tm); st_clust(fs, fs->win, dcl); mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; st_clust(fs, fs->win + SZDIRE, pcl); fs->wflag = 1; } res = dir_register(&dj); /* Register the object to the parent directoy */ } } if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dj.dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } else { remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( const TCHAR* path_old, /* Pointer to the object name to be renamed */ const TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; DIR djo, djn; FATFS *fs; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; DWORD dw; DEF_NAMBUF get_ldnumber(&path_new); /* Snip the drive number of new name off */ res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if FF_FS_LOCK != 0 if (res == FR_OK) { res = chk_lock(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ mem_cpy(&djn, &djo, sizeof djo); res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ /* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } } else #endif { /* At FAT/FAT32 volume */ mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { dir = djn.dir; /* Copy directory entry of the object except name */ mem_cpy(dir + 13, buf + 13, SZDIRE - 13); dir[DIR_Attr] = buf[DIR_Attr]; if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ dw = clst2sect(fs, ld_clust(fs, dir)); if (dw == 0) { res = FR_INT_ERR; } else { /* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, dw); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); fs->wflag = 1; } } } } } } if (res == FR_OK) { res = dir_remove(&djo); /* Remove old entry */ if (res == FR_OK) { res = sync_fs(fs); } } /* End of the critical section */ } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_MINIMIZE == 0 */ #endif /* FF_FS_MINIMIZE <= 1 */ #endif /* FF_FS_MINIMIZE <= 2 */ #if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const TCHAR* path, /* Pointer to the file path */ BYTE attr, /* Attribute bits */ BYTE mask /* Attribute mask to change */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ res = store_xdir(&dj); } else #endif { dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( const TCHAR* path, /* Pointer to the file/directory name */ const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* FF_USE_CHMOD && !FF_FS_READONLY */ #if FF_USE_LABEL /*-----------------------------------------------------------------------*/ /* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( const TCHAR* path, /* Logical drive number */ TCHAR* label, /* Buffer to store the volume label */ DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; FATFS *fs; UINT si, di; WCHAR wc; /* Get logical drive */ res = find_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { WCHAR hs; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ wc = ld_word(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); if (wc == 0) { di = 0; break; } di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ label[di] = 0; } else #endif { si = di = 0; /* Extract volume label from AM_VOL entry */ while (si < 11) { wc = dj.dir[si++]; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ if (wc == 0) { di = 0; break; } di += wc; #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; #endif } do { /* Truncate trailing spaces */ label[di] = 0; if (di == 0) break; } while (label[--di] == ' '); } } } if (res == FR_NO_FILE) { /* No label entry and return nul string */ label[0] = 0; res = FR_OK; } } /* Get volume serial number */ if (res == FR_OK && vsn) { res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { case FS_EXFAT: di = BPB_VolIDEx; break; case FS_FAT32: di = BS_VolID32; break; default: di = BS_VolID; } *vsn = ld_dword(fs->win + di); } } LEAVE_FF(fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; FATFS *fs; BYTE dirvn[22]; UINT di; WCHAR wc; static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ #if FF_USE_LFN DWORD dc; #endif /* Get logical drive */ res = find_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ mem_set(dirvn, 0, 22); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ dc = tchar2uni(&label); /* Get a Unicode character */ if (dc >= 0x10000) { if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ dc = 0; } else { st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } st_word(dirvn + di * 2, (WCHAR)dc); di++; } } else #endif { /* On the FAT/FAT32 volume */ mem_set(dirvn, ' ', 11); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ #if FF_USE_LFN dc = tchar2uni(&label); wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; #else /* ANSI/OEM input */ wc = (BYTE)*label++; if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ #if FF_CODE_PAGE == 0 if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #elif FF_CODE_PAGE < 900 if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); dirvn[di++] = (BYTE)wc; } if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ } /* Set volume label */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { if (di != 0) { mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ } } fs->wflag = 1; res = sync_fs(fs); } else { /* No volume label entry or an error */ if (res == FR_NO_FILE) { res = FR_OK; if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ mem_cpy(dj.dir, dirvn, 11); } fs->wflag = 1; res = sync_fs(fs); } } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LABEL */ #if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ FRESULT f_expand ( FIL* fp, /* Pointer to the file object */ FSIZE_t fsz, /* File size to be expanded to */ BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ ) { FRESULT res; FATFS *fs; DWORD n, clst, stcl, scl, ncl, tcl, lclst; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif n = (DWORD)fs->csize * SS(fs); /* Cluster size */ tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } else #endif { scl = clst = stcl; ncl = 0; for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; if (n == 1) { res = FR_INT_ERR; break; } if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } } } LEAVE_FF(fs, res); } #endif /* FF_USE_EXPAND && !FF_FS_READONLY */ #if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ /* Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ UINT btf, /* Number of bytes to forward */ UINT* bf /* Pointer to number of bytes forwarded */ ) { FRESULT res; FATFS *fs; DWORD clst, sect; FSIZE_t remain; UINT rcnt, csect; BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ if (csect == 0) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ fp->obj.sclust : get_fat(&fp->obj, fp->clust); if (clst <= 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } } sect = clst2sect(fs, fp->clust); /* Get current data sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; #if FF_FS_TINY if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ dbuf = fs->win; #else if (fp->sect != sect) { /* Fill sector cache with file data */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); } dbuf = fp->buf; #endif fp->sect = sect; rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ if (rcnt == 0) ABORT(fs, FR_INT_ERR); } LEAVE_FF(fs, FR_OK); } #endif /* FF_USE_FORWARD */ #if FF_USE_MKFS && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ BYTE opt, /* Format option */ DWORD au, /* Size of allocation unit (cluster) [byte] */ void* work, /* Pointer to working buffer (null: use heap memory) */ UINT len /* Size of working buffer [byte] */ ) { const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ BYTE fmt, sys, *buf, *pte, pdrv, part; WORD ss; /* Sector size */ DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ UINT i; int vol; DSTATUS stat; #if FF_USE_TRIM || FF_FS_EXFAT DWORD tbl[3]; #endif /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ pdrv = LD2PD(vol); /* Physical drive */ part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ /* Check physical drive status */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ #if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ au /= ss; /* Cluster size in unit of sector */ /* Get working buffer */ #if FF_USE_LFN == 3 if (!work) { /* Use heap memory for working buffer */ for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ; sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ } else #endif { buf = (BYTE*)work; /* Working buffer */ sz_buf = len / ss; /* Size of working buffer (sector) */ szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ } if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ if (FF_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ pte = buf + (MBR_Table + (part - 1) * SZ_PTE); if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } else { /* Create a single-partition in this function */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ /* Pre-determine the FAT type */ do { if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ fmt = FS_EXFAT; break; } } if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ if (opt & FM_FAT32) { /* FAT32 possible? */ if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ fmt = FS_FAT32; break; } } if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ fmt = FS_FAT16; } while (0); #if FF_FS_EXFAT if (fmt == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nb, cl; WCHAR ch, si; UINT j, st; BYTE b; if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ #if FF_USE_TRIM tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif /* Determine FAT location, data location and number of clusters */ if (au == 0) { /* au auto-selection */ au = 8; if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ } b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ /* Create a compressed up-case table */ sect = b_data + au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ if (ch != si) { si++; break; /* Store the up-case char if exist */ } for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ if (j >= 128) { ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; default: ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ tbl[2] = 1; /* Number of root dir clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ do { mem_set(buf, 0, szb_buf); for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the FAT */ sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ j = nb = cl = 0; do { mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ if (cl == 0) { /* Set entry 0 and 1 */ st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ while (nb != 0 && i < szb_buf) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ } while (nb != 0 && i < szb_buf); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ mem_set(buf, 0, szb_buf); buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); /* Create two set of the exFAT VBR blocks */ sect = b_vol; for (n = 0; n < 2; n++) { /* Main record (+0) */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ mem_set(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ mem_set(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } } else #endif /* FF_FS_EXFAT */ { /* Create an FAT/FAT32 volume */ do { pau = au; /* Pre-determine number of clusters and FAT sub-type */ if (fmt == FS_FAT32) { /* FAT32 volume */ if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = sz_vol / pau; /* Number of clusters */ sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); } else { /* FAT volume */ if (pau == 0) { /* au auto-selection */ n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = sz_vol / pau; if (n_clst > MAX_FAT12) { n = n_clst * 2 + 4; /* FAT size [byte] */ } else { fmt = FS_FAT12; n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ /* Align data base to erase block boundary (for flash memory media) */ n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT size */ sz_fat += n / n_fats; } /* Determine number of clusters and final check of validity of the FAT sub-type */ if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; if (fmt == FS_FAT32) { if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fmt == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ if (au == 0 && (pau * 2) <= 64) { au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((opt & FM_FAT32)) { fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); #if FF_USE_TRIM tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif /* Create FAT VBR */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ if (sz_vol < 0x10000) { st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ } buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ if (fmt == FS_FAT32) { st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ if (fmt == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ mem_set(buf, 0, ss); st_dword(buf + FSI_LeadSig, 0x41615252); st_dword(buf + FSI_StrucSig, 0x61417272); st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ st_word(buf + BS_55AA, 0xAA55); disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } /* Initialize FAT area */ mem_set(buf, 0, (UINT)szb_buf); sect = b_fat; /* FAT start sector */ for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ if (fmt == FS_FAT32) { st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ } else { st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ } nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); } /* Initialize root directory (fill with zero) */ nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); } /* Determine system ID in the partition table */ if (FF_FS_EXFAT && fmt == FS_EXFAT) { sys = 0x07; /* HPFS/NTFS/exFAT */ } else { if (fmt == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { sys = 0x06; /* FAT12/16 (large) */ } else { sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } /* Update partition information */ if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } else { /* Created as a new single partition */ if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ mem_set(buf, 0, ss); st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ pte[PTE_Boot] = 0; /* Boot indicator */ pte[PTE_StHead] = 1; /* Start head */ pte[PTE_StSec] = 1; /* Start sector */ pte[PTE_StCyl] = 0; /* Start cylinder */ pte[PTE_System] = sys; /* System type */ n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ pte[PTE_EdHead] = 254; /* End head */ pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ } } if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); LEAVE_MKFS(FR_OK); } #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ /* Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ const DWORD* szt, /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer (null: use heap memory) */ ) { UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; DSTATUS stat; DWORD sz_disk, sz_part, s_part; FRESULT res; stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; buf = (BYTE*)work; #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; /* Determine the CHS without any consideration of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; e_hd = (BYTE)(n - 1); sz_cyl = 63 * n; tot_cyl = sz_disk / sz_cyl; /* Create partition table */ mem_set(buf, 0, FF_MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ if (p_cyl == 0) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; if (i == 0) { /* Exclude first track of cylinder 0 */ s_hd = 1; s_part += 63; sz_part -= 63; } else { s_hd = 0; } e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Set partition table */ p[1] = s_hd; /* Start head */ p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ p[3] = (BYTE)b_cyl; /* Start cylinder */ p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ st_dword(p + 12, sz_part); /* Number of sectors */ /* Next partition */ b_cyl += p_cyl; } st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ /* Write it to the MBR */ res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; LEAVE_MKFS(res); } #endif /* FF_MULTI_PARTITION */ #endif /* FF_USE_MKFS && !FF_FS_READONLY */ #if FF_USE_STRFUNC #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) #error Wrong FF_STRF_ENCODE setting #endif /*-----------------------------------------------------------------------*/ /* Get a String from the File */ /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( TCHAR* buff, /* Pointer to the string buffer to read */ int len, /* Size of string buffer (items) */ FIL* fp /* Pointer to the file object */ ) { int nc = 0; TCHAR *p = buff; BYTE s[4]; UINT rc; DWORD dc; #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 WCHAR wc; #endif #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 UINT ct; #endif #if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ /* Make a room for the character and terminator */ if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; if (FF_LFN_UNICODE == 3) len -= 1; while (nc < len) { #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ f_read(fp, s, 1, &rc); if (rc != 1) break; wc = s[0]; if (dbc_1st((BYTE)wc)) { f_read(fp, s, 1, &rc); if (rc != 1 || !dbc_2nd(s[0])) continue; wc = wc << 8 | s[0]; } dc = ff_oem2uni(wc, CODEPAGE); if (dc == 0) continue; #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ f_read(fp, s, 2, &rc); if (rc != 2) break; dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (IsSurrogateL(dc)) continue; if (IsSurrogateH(dc)) { f_read(fp, s, 2, &rc); if (rc != 2) break; wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (!IsSurrogateL(wc)) continue; dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); } #else /* Read a character in UTF-8 */ f_read(fp, s, 1, &rc); if (rc != 1) break; dc = s[0]; if (dc >= 0x80) { /* Multi-byte character? */ ct = 0; if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte? */ if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte? */ if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte? */ if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; rc = 0; do { /* Merge trailing bytes */ if ((s[rc] & 0xC0) != 0x80) break; dc = dc << 6 | (s[rc] & 0x3F); } while (++rc < ct); if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ } *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ #elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ if (dc < 0x80) { /* 1-byte */ *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ } else { if (dc < 0x800) { /* 2-byte */ *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; } else { if (dc < 0x10000) { /* 3-byte */ *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 3; } else { /* 4-byte */ *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 4; } } } #endif } #else /* Byte-by-byte without any conversion (ANSI/OEM API) */ len -= 1; /* Make a room for the terminator */ while (nc < len) { f_read(fp, s, 1, &rc); if (rc != 1) break; dc = s[0]; if (FF_USE_STRFUNC == 2 && dc == '\r') continue; *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; } #endif *p = 0; /* Terminate the string */ return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ } #if !FF_FS_READONLY #include <stdarg.h> /*-----------------------------------------------------------------------*/ /* Put a Character to the File */ /*-----------------------------------------------------------------------*/ typedef struct { /* Putchar output buffer and work area */ FIL *fp; /* Ptr to the writing file */ int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 WCHAR hs; #elif FF_USE_LFN && FF_LFN_UNICODE == 2 BYTE bs[4]; UINT wi, ct; #endif BYTE buf[64]; /* Write buffer */ } putbuff; static void putc_bfd ( /* Buffered write with code conversion */ putbuff* pb, TCHAR c ) { UINT n; int i, nc; #if FF_USE_LFN && FF_LFN_UNICODE WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; TCHAR *tp; #endif #endif if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ putc_bfd(pb, '\r'); } i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; nc = pb->nchr; /* Write unit counter */ #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ if (IsSurrogateH(c)) { pb->hs = c; return; } hs = pb->hs; pb->hs = 0; if (hs != 0) { if (!IsSurrogateL(c)) hs = 0; } else { if (IsSurrogateL(c)) return; } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ if ((BYTE)c < 0x80) break; /* 1-byte? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ return; } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ pb->ct = 0; continue; } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ if (--pb->ct == 0) break; /* End of multi-byte sequence? */ return; } } tp = (TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; if (c >= 0x10000) { hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ } else { hs = 0; wc = (WCHAR)c; } #endif #if FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ if (hs != 0) { st_word(&pb->buf[i], hs); i += 2; nc++; } st_word(&pb->buf[i], wc); i += 2; #elif FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ if (hs != 0) { pb->buf[i++] = (BYTE)(hs >> 8); pb->buf[i++] = (BYTE)hs; nc++; } pb->buf[i++] = (BYTE)(wc >> 8); pb->buf[i++] = (BYTE)wc; #elif FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ if (hs != 0) { /* 4-byte */ nc += 3; hs = (hs & 0x3FF) + 0x40; pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } else { if (wc < 0x80) { /* 1-byte */ pb->buf[i++] = (BYTE)wc; } else { if (wc < 0x800) { /* 2-byte */ nc += 1; pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); } else { /* 3-byte */ nc += 2; pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); } pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } } #else /* Write it in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ if (wc == 0) return; if (wc >= 0x100) { pb->buf[i++] = (BYTE)(wc >> 8); nc++; } pb->buf[i++] = (BYTE)wc; #endif #else /* ANSI/OEM input (without re-encode) */ pb->buf[i++] = (BYTE)c; #endif if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ f_write(pb->fp, pb->buf, (UINT)i, &n); i = (n == (UINT)i) ? 0 : -1; } pb->idx = i; pb->nchr = nc + 1; } static int putc_flush ( /* Flush left characters in the buffer */ putbuff* pb ) { UINT nw; if ( pb->idx >= 0 /* Flush buffered characters to the file */ && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK && (UINT)pb->idx == nw) return pb->nchr; return EOF; } static void putc_init ( /* Initialize write buffer */ putbuff* pb, FIL* fp ) { mem_set(pb, 0, sizeof (putbuff)); pb->fp = fp; } int f_putc ( TCHAR c, /* A character to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); putc_bfd(&pb, c); /* Put the character */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a String to the File */ /*-----------------------------------------------------------------------*/ int f_puts ( const TCHAR* str, /* Pointer to the string to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); while (*str) putc_bfd(&pb, *str++); /* Put the string */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a Formatted String to the File */ /*-----------------------------------------------------------------------*/ int f_printf ( FIL* fp, /* Pointer to the file object */ const TCHAR* fmt, /* Pointer to the format string */ ... /* Optional arguments... */ ) { va_list arp; putbuff pb; BYTE f, r; UINT i, j, w; DWORD v; TCHAR c, d, str[32], *p; putc_init(&pb, fp); va_start(arp, fmt); for (;;) { c = *fmt++; if (c == 0) break; /* End of string */ if (c != '%') { /* Non escape character */ putc_bfd(&pb, c); continue; } w = f = 0; c = *fmt++; if (c == '0') { /* Flag: '0' padding */ f = 1; c = *fmt++; } else { if (c == '-') { /* Flag: left justified */ f = 2; c = *fmt++; } } if (c == '*') { /* Minimum width by argument */ w = va_arg(arp, int); c = *fmt++; } else { while (IsDigit(c)) { /* Minimum width */ w = w * 10 + c - '0'; c = *fmt++; } } if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ f |= 4; c = *fmt++; } if (c == 0) break; d = c; if (IsLower(d)) d -= 0x20; switch (d) { /* Atgument type is... */ case 'S' : /* String */ p = va_arg(arp, TCHAR*); for (j = 0; p[j]; j++) ; if (!(f & 2)) { /* Right padded */ while (j++ < w) putc_bfd(&pb, ' ') ; } while (*p) putc_bfd(&pb, *p++) ; /* String body */ while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ continue; case 'C' : /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; case 'B' : /* Unsigned binary */ r = 2; break; case 'O' : /* Unsigned octal */ r = 8; break; case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; case 'X' : /* Unsigned hexdecimal */ r = 16; break; default: /* Unknown type (pass-through) */ putc_bfd(&pb, c); continue; } /* Get an argument and put it in numeral */ v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); if (d == 'D' && (v & 0x80000000)) { v = 0 - v; f |= 8; } i = 0; do { d = (TCHAR)(v % r); v /= r; if (d > 9) d += (c == 'x') ? 0x27 : 0x07; str[i++] = d + '0'; } while (v && i < sizeof str / sizeof *str); if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; if (!(f & 2)) { while (j++ < w) putc_bfd(&pb, d); /* Right pad */ } do { putc_bfd(&pb, str[--i]); /* Number body */ } while (i); while (j++ < w) putc_bfd(&pb, d); /* Left pad */ } va_end(arp); return putc_flush(&pb); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_STRFUNC */ #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ /* Set Active Codepage for the Path Name */ /*-----------------------------------------------------------------------*/ FRESULT f_setcp ( WORD cp /* Value to be set as active code page */ ) { static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ ExCvt = 0; DbcTbl = tables[i]; } else { /* SBCS */ ExCvt = tables[i]; DbcTbl = 0; } return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ ================================================ FILE: emummc/source/libs/fatfs/ff.h ================================================ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #ifndef FF_DEFINED #define FF_DEFINED 86604 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif #include "../../utils/types.h" /* Basic integer types */ #include "ffconf.h" /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif /* Definitions of volume management */ #if FF_MULTI_PARTITION /* Multiple partition configuration */ typedef struct { BYTE pd; /* Physical drive number */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ #endif #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ #endif #endif /* Type of path name strings on FatFs API */ #ifndef _INC_TCHAR #define _INC_TCHAR #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ typedef char TCHAR; #define _T(x) u8 ## x #define _TEXT(x) u8 ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ typedef DWORD TCHAR; #define _T(x) U ## x #define _TEXT(x) U ## x #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) #error Wrong FF_LFN_UNICODE setting #else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif #endif /* Type of file size variables */ #if FF_FS_EXFAT typedef QWORD FSIZE_t; #else typedef DWORD FSIZE_t; #endif /* Filesystem object structure (FATFS) */ typedef struct { BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif #if FF_FS_REENTRANT FF_SYNC_t sobj; /* Identifier of sync object */ #endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif #if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ #if FF_FS_EXFAT DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD fsize; /* Size of an FAT [sectors] */ DWORD volbase; /* Volume base sector */ DWORD fatbase; /* FAT base sector */ DWORD dirbase; /* Root directory base sector/cluster */ DWORD database; /* Data base sector */ #if FF_FS_EXFAT DWORD bitbase; /* Allocation bitmap base sector */ #endif DWORD winsect; /* Current sector appearing in the win[] */ } FATFS; /* Object ID and allocation information (FFOBJID) */ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ #endif #if FF_FS_LOCK UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; /* File object structure (FIL) */ typedef struct { #if !FF_FS_TINY BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif } FIL; /* Directory object structure (DIR) */ typedef struct { FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; /* File information structure (FILINFO) */ typedef struct { FSIZE_t fsize; /* File size */ WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ #endif } FILINFO; /* File function return code (FRESULT) */ typedef enum { FR_OK = 0, /* (0) Succeeded */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ FR_NOT_READY, /* (3) The physical drive cannot work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ FR_EXIST, /* (8) Access denied due to prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ #ifdef FF_FASTFS FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */ FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */ #else FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ #endif } FRESULT; /*--------------------------------------------------------------*/ /* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ #ifdef FF_FASTFS FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */ FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */ #endif FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ #ifdef FF_FASTFS DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, DWORD *tbl, FSIZE_t ofs); /* Expand file and populate cluster table */ #endif FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) #define f_rmdir(path) f_unlink(path) #define f_unmount(path) f_mount(0, path, 0) #ifndef EOF #define EOF (-1) #endif /*--------------------------------------------------------------*/ /* Additional user defined functions */ /* RTC function */ #if !FF_FS_READONLY && !FF_FS_NORTC DWORD get_fattime (void); #endif /* LFN support functions */ #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif #if FF_USE_LFN == 3 /* Dynamic memory allocation */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif /* Sync functions */ #if FF_FS_REENTRANT int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #endif /*--------------------------------------------------------------*/ /* Flags and offset address */ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 /* Fast seek controls (2nd argument of f_lseek) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) /* Format options (2nd argument of f_mkfs) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_EXFAT 0x04 #define FM_ANY 0x07 #define FM_SFD 0x08 /* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 #define FS_EXFAT 4 /* File attribute bits for directory entry (FILINFO.fattrib) */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ #ifdef __cplusplus } #endif #endif /* FF_DEFINED */ ================================================ FILE: emummc/source/libs/fatfs/ffconf.h ================================================ /*---------------------------------------------------------------------------/ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ #define FFCONF_DEF 86604 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ #define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ #define FF_FS_MINIMIZE 2 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ #define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ #define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ #define FF_FASTFS 1 #ifdef FF_FASTFS #define FF_USE_FASTSEEK 1 #else #define FF_USE_FASTSEEK 0 #endif /* This option switches fast seek function. (0:Disable or 1:Enable) */ #define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 0 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ #define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ #define FF_CODE_PAGE 850 /* This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / / 437 - U.S. / 720 - Arabic / 737 - Greek / 771 - KBL / 775 - Baltic / 850 - Latin 1 / 852 - Latin 2 / 855 - Cyrillic / 857 - Turkish / 860 - Portuguese / 861 - Icelandic / 862 - Hebrew / 863 - Canadian French / 864 - Arabic / 865 - Nordic / 866 - Russian / 869 - Greek 2 / 932 - Japanese (DBCS) / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) / 0 - Include all code pages above and configured by f_setcp() */ #define FF_USE_LFN 3 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can / be in range of 12 to 255. It is recommended to be set 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree() in ffsystem.c, need to be added to the project. */ #define FF_LFN_UNICODE 0 /* This option switches the character encoding on the API when LFN is enabled. / / 0: ANSI/OEM in current CP (TCHAR = char) / 1: Unicode in UTF-16 (TCHAR = WCHAR) / 2: Unicode in UTF-8 (TCHAR = char) / 3: Unicode in UTF-32 (TCHAR = DWORD) / / Also behavior of string I/O functions will be affected by this option. / When LFN is not enabled, this option has no effect. */ #define FF_LFN_BUF 255 #define FF_SFN_BUF 12 /* This set of options defines size of file name members in the FILINFO structure / which is used to read out directory items. These values should be suffcient for / the file names to read. The maximum possible length of the read file name depends / on character encoding. When LFN is not enabled, these options have no effect. */ #define FF_STRF_ENCODE 0 /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), / f_putc(), f_puts and f_printf() convert the character encoding in it. / This option selects assumption of character encoding ON THE FILE to be / read/written via those functions. / / 0: ANSI/OEM in current CP / 1: Unicode in UTF-16LE / 2: Unicode in UTF-16BE / 3: Unicode in UTF-8 */ #define FF_FS_RPATH 0 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. */ /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ #define FF_VOLUMES 1 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "sd" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ #define FF_MULTI_PARTITION 0 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ #define FF_MIN_SS 512 #define FF_MAX_SS 512 /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / for variable sector size mode and disk_ioctl() function needs to implement / GET_SECTOR_SIZE command. */ #define FF_USE_TRIM 0 /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. / bit0=1: Do not trust free cluster count in the FSINFO. / bit1=0: Use last allocated cluster number in the FSINFO if available. / bit1=1: Do not trust last allocated cluster number in the FSINFO. */ /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ #define FF_FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ #define FF_FS_EXFAT 1 /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2020 /* The option FF_FS_NORTC switches timestamp function. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. / These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ #define FF_FS_LOCK 0 /* The option FF_FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. / >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file / lock control is independent of re-entrancy. */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 #define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / / The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ /*--- End of configuration options ---*/ ================================================ FILE: emummc/source/libs/fatfs/ffsystem.c ================================================ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ /* (C) ChaN, 2018 */ /* (C) CTCaer, 2018 */ /*------------------------------------------------------------------------*/ #include "ff.h" #include "../../utils/types.h" #include <stdlib.h> #if FF_USE_LFN == 3 /* Dynamic memory allocation */ /*------------------------------------------------------------------------*/ /* Allocate a memory block */ /*------------------------------------------------------------------------*/ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { return malloc(msize); /* Allocate a new memory block with POSIX API */ } /*------------------------------------------------------------------------*/ /* Free a memory block */ /*------------------------------------------------------------------------*/ void ff_memfree ( void* mblock /* Pointer to the memory block to free (nothing to do if null) */ ) { free(mblock); /* Free the memory block with POSIX API */ } #endif ================================================ FILE: emummc/source/libs/fatfs/ffunicode.c ================================================ /*------------------------------------------------------------------------*/ /* Unicode handling functions for FatFs R0.13c */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / / utilitiy for the code conversion, this module should be modified to use / / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* / Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. */ #include "ff.h" #if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ #if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 }; #endif #if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 }; #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* SBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (oem < 0x100) c = p[oem - 0x80]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* DBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ uc = (WCHAR)uni; p = CVTBL(uni2oem, FF_CODE_PAGE); hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i = 0, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ p = CVTBL(oem2uni, FF_CODE_PAGE); hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for dynamic code page configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000) { /* Is it in BMP? */ uc = (WCHAR)uni; p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ p = cp_table[i]; if (p) { /* Is it valid code page ? */ for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ c = (c + 0x80) & 0xFF; } } else { /* DBCS */ switch (cp) { /* Get conversion table */ case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; } if (p) { /* Is it valid code page? */ li = 0; for (n = 16; n; n--) { /* Find OEM code */ i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ p = cp_table[i]; if (p) { /* Is it a valid CP ? */ if (oem < 0x100) c = p[oem - 0x80]; } } else { /* DBCS */ switch (cp) { case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; } if (p) { li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } return c; } #endif /*------------------------------------------------------------------------*/ /* Unicode up-case conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { const WORD *p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, /* Latin Extended-A */ 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, 0x0000 /* EOT */ }; static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ 0x1E00,0x0196, 0x1EA0,0x015A, /* Greek Extended */ 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ 0x2170,0x0210, 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ 0x24D0,0x051A, 0x2C30,0x042F, /* Latin Extended-C */ 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ 0x2D00,0x0826, /* Full-width */ 0xFF41,0x031A, 0x0000 /* EOT */ }; if (uni < 0x10000) { /* Is it in BMP? */ uc = (WORD)uni; p = uc < 0x1000 ? cvt1 : cvt2; for (;;) { bc = *p++; /* Get the block base */ if (bc == 0 || uc < bc) break; /* Not matched? */ nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ if (uc < bc + nc) { /* In the block? */ switch (cmd) { case 0: uc = p[uc - bc]; break; /* Table conversion */ case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ case 2: uc -= 16; break; /* Shift -16 */ case 3: uc -= 32; break; /* Shift -32 */ case 4: uc -= 48; break; /* Shift -48 */ case 5: uc -= 26; break; /* Shift -26 */ case 6: uc += 8; break; /* Shift +8 */ case 7: uc -= 80; break; /* Shift -80 */ case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ } break; } if (cmd == 0) p += nc; /* Skip table if needed */ } uni = uc; } return uni; } #endif /* #if FF_USE_LFN */ ================================================ FILE: emummc/source/main.c ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <stdint.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include "nx/svc.h" #include "nx/smc.h" #include "soc/clock.h" #include "soc/i2c.h" #include "emuMMC/emummc.h" #include "emuMMC/emummc_ctx.h" #include "FS/FS_offsets.h" #include "utils/fatal.h" // Prototypes void __init(); void __initheap(void); void setup_hooks(void); void __libc_init_array(void); void setup_nintendo_paths(void); void hook_function(uintptr_t source, uintptr_t target); void *__stack_top; uintptr_t text_base; size_t fs_code_size; u8 *fs_rw_mapping = NULL; Handle self_proc_handle = 0; char inner_heap[INNER_HEAP_SIZE]; size_t inner_heap_size = INNER_HEAP_SIZE; extern char _start; extern char __argdata__; // Nintendo Path static char nintendo_path[0x80] = "Nintendo"; // 1.0.0 requires special path handling because it has separate album and contents paths. #define FS_100_ALBUM_PATH 0 #define FS_100_CONTENTS_PATH 1 static char nintendo_path_album_100[0x100] = "/Nintendo/Album"; static char nintendo_path_contents_100[0x100] = "/Nintendo/Contents"; // FS offsets static const fs_offsets_t *fs_offsets; // Defined by linkerscript #define INJECTED_SIZE ((uintptr_t)&__argdata__ - (uintptr_t)&_start) #define INJECT_OFFSET(type, offset) (type)(text_base + INJECTED_SIZE + offset) #define FS_CODE_BASE INJECT_OFFSET(uintptr_t, 0) #define GENERATE_ADD(register, register_target, value) (0x91000000 | value << 10 | register << 5 | register_target) #define GENERATE_ADRP(register, page_addr) (0x90000000 | ((((page_addr) >> 12) & 0x3) << 29) | ((((page_addr) >> 12) & 0x1FFFFC) << 3) | ((register) & 0x1F)) #define GENERATE_BRANCH(source, destination) (0x14000000 | ((((destination) - (source)) >> 2) & 0x3FFFFFF)) #define GENERATE_NOP() (0xD503201F) #define INJECT_HOOK(offset, destination) hook_function(INJECT_OFFSET(uintptr_t, offset), (uintptr_t)&destination) #define INJECT_HOOK_RELATIVE(offset, relative_destination) hook_function(INJECT_OFFSET(uintptr_t, offset), INJECT_OFFSET(uintptr_t, offset) + relative_destination) #define INJECT_NOP(offset) write_nop(INJECT_OFFSET(uintptr_t, offset)) // emuMMC extern _sdmmc_accessor_gc sdmmc_accessor_gc; extern _sdmmc_accessor_sd sdmmc_accessor_sd; extern _sdmmc_accessor_nand sdmmc_accessor_nand; extern _lock_mutex lock_mutex; extern _unlock_mutex unlock_mutex; extern void *sd_mutex; extern void *nand_mutex; extern volatile int *active_partition; extern volatile Handle *sdmmc_das_handle; // Storage volatile __attribute__((aligned(0x1000))) emuMMC_ctx_t emuMMC_ctx = { .magic = EMUMMC_STORAGE_MAGIC, .id = 0, .fs_ver = FS_VER_MAX, // SD Default Metadata .SD_Type = emuMMC_SD_Raw, .SD_StoragePartitionOffset = 0, // EMMC Default Metadata .EMMC_Type = emuMMC_EMMC, .EMMC_StoragePartitionOffset = 0, // File Default Path .storagePath = "", }; // TODO: move into another file typedef struct { void *_0x0; void *_0x8; void *_0x10; void *_0x18; void *_0x20; void *_0x28; void *_0x30; void *_0x38; void *_0x40; Result (*set_min_v_clock_rate)(void *, uint32_t, uint32_t); } nn_clkrst_session_vt_t; typedef struct { nn_clkrst_session_vt_t *vt; } nn_clkrst_session_t; Result clkrst_set_min_v_clock_rate(nn_clkrst_session_t **_this, uint32_t clk_rate) { Result rc = (*_this)->vt->set_min_v_clock_rate((void *)*_this, clk_rate, clk_rate); if (rc == 0x6C0 || rc == 0) { // TODO #define return 0; } if (rc != 0xAC0) { // TODO #define fatal_abort(Fatal_BadResult); } return rc; } void __initheap(void) { void *addr = inner_heap; size_t size = inner_heap_size; /* Newlib Heap Management */ extern char *fake_heap_start; extern char *fake_heap_end; fake_heap_start = (char *)addr; fake_heap_end = (char *)addr + size; } static void _receive_process_handle_thread(void *_session_handle) { Result rc; // Convert the argument to a handle copy we can use. Handle session_handle = *(Handle*)_session_handle; // Receive the request from the client thread. memset(armGetTls(), 0, 0x10); s32 idx = 0; rc = svcReplyAndReceive(&idx, &session_handle, 1, INVALID_HANDLE, UINT64_MAX); if (rc != 0) { fatal_abort(Fatal_BadResult); } // Set the process handle. self_proc_handle = ((u32 *)armGetTls())[3]; // Close the session. svcCloseHandle(session_handle); // Terminate ourselves. svcExitThread(); // This code will never execute. while (true); } static void _init_process_handle(void) { Result rc; u8 temp_thread_stack[0x1000]; // Create a new session to transfer our process handle to ourself Handle server_handle, client_handle; rc = svcCreateSession(&server_handle, &client_handle, 0, 0); if (rc != 0) { fatal_abort(Fatal_BadResult); } // Create a new thread to receive our handle. Handle thread_handle; rc = svcCreateThread(&thread_handle, _receive_process_handle_thread, &server_handle, temp_thread_stack + sizeof(temp_thread_stack), 0x20, 3); if (rc != 0) { fatal_abort(Fatal_BadResult); } // Start the new thread. rc = svcStartThread(thread_handle); if (rc != 0) { fatal_abort(Fatal_BadResult); } // Send the message. static const u32 SendProcessHandleMessage[4] = { 0x00000000, 0x80000000, 0x00000002, CUR_PROCESS_HANDLE }; memcpy(armGetTls(), SendProcessHandleMessage, sizeof(SendProcessHandleMessage)); svcSendSyncRequest(client_handle); // Close the session handle. svcCloseHandle(client_handle); // Wait for the thread to be done. rc = svcWaitSynchronizationSingle(thread_handle, UINT64_MAX); if (rc != 0) { fatal_abort(Fatal_BadResult); } // Close the thread handle. svcCloseHandle(thread_handle); } static void _map_fs_rw(void) { Result rc; do { fs_rw_mapping = (u8 *)(smcGenerateRandomU64() & 0xFFFFFF000ull); rc = svcMapProcessMemory(fs_rw_mapping, self_proc_handle, FS_CODE_BASE, fs_code_size); } while (rc == 0xDC01 || rc == 0xD401); if (rc != 0) { fatal_abort(Fatal_BadResult); } } static void _unmap_fs_rw(void) { Result rc = svcUnmapProcessMemory(fs_rw_mapping, self_proc_handle, FS_CODE_BASE, fs_code_size); if (rc != 0) { fatal_abort(Fatal_BadResult); } fs_rw_mapping = NULL; } static void _write32(uintptr_t source, u32 value) { *((u32 *)(fs_rw_mapping + (source - FS_CODE_BASE))) = value; } void hook_function(uintptr_t source, uintptr_t target) { u32 branch_opcode = GENERATE_BRANCH(source, target); _write32(source, branch_opcode); } void write_nop(uintptr_t source) { _write32(source, GENERATE_NOP()); } void write_adrp_add(int reg, uintptr_t pc, uintptr_t add_rel_offset, intptr_t destination) { uintptr_t add_opcode_location = pc + add_rel_offset; intptr_t offset = (destination & 0xFFFFF000) - (pc & 0xFFFFF000); uint32_t opcode_adrp = GENERATE_ADRP(reg, offset); uint32_t opcode_add = GENERATE_ADD(reg, reg, (destination & 0x00000FFF)); _write32(pc, opcode_adrp); _write32(add_opcode_location, opcode_add); } void setup_hooks(void) { // rtld INJECT_HOOK_RELATIVE(fs_offsets->rtld, fs_offsets->rtld_destination); // sdmmc_wrapper_read hook INJECT_HOOK(fs_offsets->sdmmc_wrapper_read, sdmmc_wrapper_read); // sdmmc_wrapper_write hook INJECT_HOOK(fs_offsets->sdmmc_wrapper_write, sdmmc_wrapper_write); // sdmmc_wrapper_controller_open hook if (fs_offsets->sdmmc_accessor_controller_open) INJECT_HOOK(fs_offsets->sdmmc_accessor_controller_open, sdmmc_wrapper_controller_open); // sdmmc_wrapper_controller_close hook INJECT_HOOK(fs_offsets->sdmmc_accessor_controller_close, sdmmc_wrapper_controller_close); // On 8.0.0+, we need to hook the regulator setup, because // otherwise it will abort because we have already turned it on. if (emuMMC_ctx.fs_ver >= FS_VER_8_0_0) { INJECT_HOOK(fs_offsets->clkrst_set_min_v_clock_rate, clkrst_set_min_v_clock_rate); } } void populate_function_pointers(void) { // Accessor getters sdmmc_accessor_gc = INJECT_OFFSET(_sdmmc_accessor_gc, fs_offsets->sdmmc_accessor_gc); sdmmc_accessor_sd = INJECT_OFFSET(_sdmmc_accessor_sd, fs_offsets->sdmmc_accessor_sd); sdmmc_accessor_nand = INJECT_OFFSET(_sdmmc_accessor_nand, fs_offsets->sdmmc_accessor_nand); // MutexLock functions lock_mutex = INJECT_OFFSET(_lock_mutex, fs_offsets->lock_mutex); unlock_mutex = INJECT_OFFSET(_unlock_mutex, fs_offsets->unlock_mutex); // Other sd_mutex = INJECT_OFFSET(void *, fs_offsets->sd_mutex); nand_mutex = INJECT_OFFSET(void *, fs_offsets->nand_mutex); active_partition = INJECT_OFFSET(volatile int *, fs_offsets->active_partition); sdmmc_das_handle = INJECT_OFFSET(volatile Handle *, fs_offsets->sdmmc_das_handle); } void write_nops(void) { // On 7.0.0+, we need to attach to device address space ourselves. // This patches an abort that happens when Nintendo's code sees SD // is already attached if (emuMMC_ctx.fs_ver >= FS_VER_7_0_0) { INJECT_NOP(fs_offsets->sd_das_init); } } static void load_emummc_ctx(void) { exo_emummc_config_t config; static struct { char storage_path[sizeof(emuMMC_ctx.storagePath)]; char nintendo_path[sizeof(nintendo_path)]; } __attribute__((aligned(0x1000))) paths; int x = smcGetEmummcConfig(EXO_EMUMMC_MMC_NAND, &config, &paths); if (x != 0) { fatal_abort(Fatal_GetConfig); } if (config.base_cfg.magic == EMUMMC_STORAGE_MAGIC) { emuMMC_ctx.magic = config.base_cfg.magic; emuMMC_ctx.id = config.base_cfg.id; emuMMC_ctx.EMMC_Type = (enum emuMMC_Type)config.base_cfg.type; emuMMC_ctx.fs_ver = (enum FS_VER)config.base_cfg.fs_version; if (emuMMC_ctx.EMMC_Type == emuMMC_SD_Raw) { emuMMC_ctx.EMMC_StoragePartitionOffset = config.partition_cfg.start_sector; } else if (emuMMC_ctx.EMMC_Type == emuMMC_SD_File) { memcpy((void *)emuMMC_ctx.storagePath, paths.storage_path, sizeof(emuMMC_ctx.storagePath) - 1); emuMMC_ctx.storagePath[sizeof(emuMMC_ctx.storagePath) - 1] = 0; } memcpy(nintendo_path, paths.nintendo_path, sizeof(nintendo_path) - 1); nintendo_path[sizeof(nintendo_path) - 1] = 0; if (strcmp(nintendo_path, "") == 0) { snprintf(nintendo_path, sizeof(nintendo_path), "emummc/Nintendo_%04x", emuMMC_ctx.id); } } else { fatal_abort(Fatal_GetConfig); } } void setup_nintendo_paths(void) { if (emuMMC_ctx.fs_ver > FS_VER_1_0_0) { for (int i = 0; fs_offsets->nintendo_paths[i].adrp_offset; i++) { intptr_t nintendo_path_location = (intptr_t)&nintendo_path; uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[i].adrp_offset); write_adrp_add(fs_offsets->nintendo_paths[i].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[i].add_rel_offset, nintendo_path_location); } } else { // 1.0.0 needs special handling because it uses two paths. // Do album path { snprintf(nintendo_path_album_100, sizeof(nintendo_path_album_100), "/%s/Album", nintendo_path); intptr_t nintendo_album_path_location = (intptr_t)&nintendo_path_album_100; uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[FS_100_ALBUM_PATH].adrp_offset); write_adrp_add(fs_offsets->nintendo_paths[FS_100_ALBUM_PATH].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[FS_100_ALBUM_PATH].add_rel_offset, nintendo_album_path_location); } // Do contents path { snprintf(nintendo_path_contents_100, sizeof(nintendo_path_contents_100), "/%s/Contents", nintendo_path); intptr_t nintendo_contents_path_location = (intptr_t)&nintendo_path_contents_100; uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[FS_100_CONTENTS_PATH].adrp_offset); write_adrp_add(fs_offsets->nintendo_paths[FS_100_CONTENTS_PATH].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[FS_100_CONTENTS_PATH].add_rel_offset, nintendo_contents_path_location); } } } // inject main func void __init() { // Call constructors. __libc_init_array(); MemoryInfo meminfo; u32 pageinfo; svcQueryMemory(&meminfo, &pageinfo, (u64)&_start); text_base = meminfo.addr; // Get code size svcQueryMemory(&meminfo, &pageinfo, FS_CODE_BASE); fs_code_size = meminfo.size; load_emummc_ctx(); fs_offsets = get_fs_offsets(emuMMC_ctx.fs_ver); _init_process_handle(); _map_fs_rw(); setup_hooks(); populate_function_pointers(); write_nops(); setup_nintendo_paths(); _unmap_fs_rw(); clock_enable_i2c5(); i2c_init(); } ================================================ FILE: emummc/source/nx/cache.h ================================================ /** * @file cache.h * @brief AArch64 cache operations. * @author plutoo * @copyright libnx Authors */ #pragma once #include "../utils/types.h" /** * @brief Performs a data cache flush on the specified buffer. * @param addr Address of the buffer. * @param size Size of the buffer, in bytes. * @remarks Cache flush is defined as Clean + Invalidate. * @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register). */ void armDCacheFlush(void* addr, size_t size); /** * @brief Performs a data cache clean on the specified buffer. * @param addr Address of the buffer. * @param size Size of the buffer, in bytes. * @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register). */ void armDCacheClean(void* addr, size_t size); /** * @brief Performs an instruction cache invalidation clean on the specified buffer. * @param addr Address of the buffer. * @param size Size of the buffer, in bytes. * @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register). */ void armICacheInvalidate(void* addr, size_t size); /** * @brief Performs a data cache zeroing operation on the specified buffer. * @param addr Address of the buffer. * @param size Size of the buffer, in bytes. * @note The start and end addresses of the buffer are forcibly rounded to cache line boundaries (read from CTR_EL0 system register). */ void armDCacheZero(void* addr, size_t size); ================================================ FILE: emummc/source/nx/cache.s ================================================ /** * @file cache.s * @copyright libnx Authors */ .macro CODE_BEGIN name .section .text.\name, "ax", %progbits .global \name .type \name, %function .align 2 .cfi_startproc \name: .endm .macro CODE_END .cfi_endproc .endm CODE_BEGIN armDCacheFlush add x1, x1, x0 mrs x8, CTR_EL0 lsr x8, x8, #16 and x8, x8, #0xf mov x9, #4 lsl x9, x9, x8 sub x10, x9, #1 bic x8, x0, x10 mov x10, x1 mov w1, #1 mrs x0, tpidrro_el0 strb w1, [x0, #0x104] armDCacheFlush_L0: dc civac, x8 add x8, x8, x9 cmp x8, x10 bcc armDCacheFlush_L0 dsb sy strb wzr, [x0, #0x104] ret CODE_END CODE_BEGIN armDCacheClean add x1, x1, x0 mrs x8, CTR_EL0 lsr x8, x8, #16 and x8, x8, #0xf mov x9, #4 lsl x9, x9, x8 sub x10, x9, #1 bic x8, x0, x10 mov x10, x1 mov w1, #1 mrs x0, tpidrro_el0 strb w1, [x0, #0x104] armDCacheClean_L0: dc cvac, x8 add x8, x8, x9 cmp x8, x10 bcc armDCacheClean_L0 dsb sy strb wzr, [x0, #0x104] ret CODE_END CODE_BEGIN armICacheInvalidate add x1, x1, x0 mrs x8, CTR_EL0 and x8, x8, #0xf mov x9, #4 lsl x9, x9, x8 sub x10, x9, #1 bic x8, x0, x10 mov x10, x1 mov w1, #1 mrs x0, tpidrro_el0 strb w1, [x0, #0x104] armICacheInvalidate_L0: ic ivau, x8 add x8, x8, x9 cmp x8, x10 bcc armICacheInvalidate_L0 dsb sy strb wzr, [x0, #0x104] ret CODE_END CODE_BEGIN armDCacheZero add x1, x1, x0 mrs x8, CTR_EL0 lsr x8, x8, #16 and x8, x8, #0xf mov x9, #4 lsl x9, x9, x8 sub x10, x9, #1 bic x8, x0, x10 mov x10, x1 mov w1, #1 mrs x0, tpidrro_el0 strb w1, [x0, #0x104] armDCacheZero_L0: dc zva, x8 add x8, x8, x9 cmp x8, x10 bcc armDCacheZero_L0 dsb sy strb wzr, [x0, #0x104] ret CODE_END ================================================ FILE: emummc/source/nx/counter.h ================================================ /** * @file counter.h * @brief AArch64 system counter-timer. * @author fincs * @copyright libnx Authors */ #pragma once #include "../utils/types.h" /** * @brief Gets the current system tick. * @return The current system tick. */ static inline u64 armGetSystemTick(void) { u64 ret; __asm__ __volatile__ ("mrs %x[data], cntpct_el0" : [data] "=r" (ret)); return ret; } /** * @brief Gets the system counter-timer frequency * @return The system counter-timer frequency, in Hz. */ static inline u64 armGetSystemTickFreq(void) { u64 ret; __asm__ ("mrs %x[data], cntfrq_el0" : [data] "=r" (ret)); return ret; } /** * @brief Converts from nanoseconds to CPU ticks unit. * @param ns Time in nanoseconds. * @return Time in CPU ticks. */ static inline u64 armNsToTicks(u64 ns) { return (ns * 12) / 625; } /** * @brief Converts from CPU ticks unit to nanoseconds. * @param tick Time in ticks. * @return Time in nanoseconds. */ static inline u64 armTicksToNs(u64 tick) { return (tick * 625) / 12; } ================================================ FILE: emummc/source/nx/dynamic.c ================================================ /** * @file dynamic.c * @copyright libnx Authors */ #include <stddef.h> #include "../utils/types.h" #include <elf.h> void __nx_dynamic(uintptr_t base, const Elf64_Dyn* dyn) { const Elf64_Rela* rela = NULL; u64 relasz = 0; for (; dyn->d_tag != DT_NULL; dyn++) { switch (dyn->d_tag) { case DT_RELA: rela = (const Elf64_Rela*)(base + dyn->d_un.d_ptr); break; case DT_RELASZ: relasz = dyn->d_un.d_val / sizeof(Elf64_Rela); break; } } if (rela == NULL) { while(true) ; } for (; relasz--; rela++) { switch (ELF64_R_TYPE(rela->r_info)) { case R_AARCH64_RELATIVE: { u64* ptr = (u64*)(base + rela->r_offset); *ptr = base + rela->r_addend; break; } } } } ================================================ FILE: emummc/source/nx/smc.c ================================================ /** * @file smc.c * @copyright libnx Authors */ #include <stddef.h> #include <string.h> #include "smc.h" #include "../utils/fatal.h" void smcRebootToRcm(void) { SecmonArgs args; args.X[0] = 0xC3000401; /* smcSetConfig */ args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */ args.X[3] = 1; /* Perform reboot to RCM. */ svcCallSecureMonitor(&args); } void smcRebootToIramPayload(void) { SecmonArgs args; args.X[0] = 0xC3000401; /* smcSetConfig */ args.X[1] = SplConfigItem_NeedsReboot; /* Exosphere reboot */ args.X[3] = 2; /* Perform reboot to payload at 0x40010000 in IRAM. */ svcCallSecureMonitor(&args); } void smcPerformShutdown(void) { SecmonArgs args; args.X[0] = 0xC3000401; /* smcSetConfig */ args.X[1] = SplConfigItem_NeedsShutdown; /* Exosphere shutdown */ args.X[3] = 1; /* Perform shutdown. */ svcCallSecureMonitor(&args); } Result smcGetConfig(SplConfigItem config_item, u64 *out_config) { SecmonArgs args; args.X[0] = 0xC3000002; /* smcGetConfig */ args.X[1] = (u64)config_item; /* config item */ Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] == 0) { if (out_config) { *out_config = args.X[1]; } } else { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } } return rc; } SplHardwareType splGetHardwareType(void) { u64 value; Result rc = smcGetConfig(SplConfigItem_HardwareType, &value); if (rc != 0) { fatal_abort(Fatal_BadResult); } return (SplHardwareType)value; } SplSocType splGetSocType(void) { static SplSocType soc_type; static bool soc_type_set = false; if (soc_type_set) return soc_type; switch (splGetHardwareType()) { case SplHardwareType_Icosa: case SplHardwareType_Copper: soc_type = SplSocType_Erista; break; case SplHardwareType_Hoag: case SplHardwareType_Iowa: case SplHardwareType_Calcio: case SplHardwareType_Five: soc_type = SplSocType_Mariko; break; default: fatal_abort(Fatal_InvalidEnum); } soc_type_set = true; return soc_type; } Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size) { SecmonArgs args; args.X[0] = 0xF0000201; /* smcAmsIramCopy */ args.X[1] = (u64)src_addr; /* DRAM address */ args.X[2] = (u64)iram_addr; /* IRAM address */ args.X[3] = size; /* Amount to copy */ args.X[4] = 1; /* 1 = Write */ Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] != 0) { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } } return rc; } Result smcCopyFromIram(void *dst_addr, uintptr_t iram_addr, u32 size) { SecmonArgs args; args.X[0] = 0xF0000201; /* smcAmsIramCopy */ args.X[1] = (u64)dst_addr; /* DRAM address */ args.X[2] = (u64)iram_addr; /* IRAM address */ args.X[3] = size; /* Amount to copy */ args.X[4] = 0; /* 0 = Read */ Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] != 0) { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } } return rc; } Result smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask) { SecmonArgs args; args.X[0] = 0xF0000002; /* smcAmsReadWriteRegister */ args.X[1] = phys_addr; /* MMIO address */ args.X[2] = mask; /* mask */ args.X[3] = value; /* value */ Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] != 0) { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } } return rc; } Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg, void *out_paths) { SecmonArgs args; args.X[0] = 0xF0000404; /* smcAmsGetEmunandConfig */ args.X[1] = mmc_id; args.X[2] = (u64)out_paths; /* out path */ Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] != 0) { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } if (rc == 0) { memcpy(out_cfg, &args.X[1], sizeof(*out_cfg)); } } return rc; } Result smcGenerateRandomBytes(void *dst, u32 size) { SecmonArgs args; args.X[0] = 0xC3000006; /* smcGenerateRandomBytes */ args.X[1] = size; Result rc = svcCallSecureMonitor(&args); if (rc == 0) { if (args.X[0] != 0) { /* SPL result n = SMC result n */ rc = (26u | ((u32)args.X[0] << 9u)); } if (rc == 0) { memcpy(dst, &args.X[1], size); } } return rc; } u64 smcGenerateRandomU64(void) { u64 random; Result rc = smcGenerateRandomBytes(&random, sizeof(random)); if (rc != 0) { fatal_abort(Fatal_BadResult); } return random; } ================================================ FILE: emummc/source/nx/smc.h ================================================ /** * @file smc.h * @brief Wrappers for secure monitor calls. * @copyright libnx Authors */ #pragma once #include "../utils/types.h" #include "svc.h" #ifdef __cplusplus extern "C" { #endif typedef enum { SplConfigItem_DisableProgramVerification = 1, SplConfigItem_DramId = 2, SplConfigItem_SecurityEngineIrqNumber = 3, SplConfigItem_Version = 4, SplConfigItem_HardwareType = 5, SplConfigItem_IsRetail = 6, SplConfigItem_IsRecoveryBoot = 7, SplConfigItem_DeviceId = 8, SplConfigItem_BootReason = 9, SplConfigItem_MemoryArrange = 10, SplConfigItem_IsDebugMode = 11, SplConfigItem_KernelMemoryConfiguration = 12, SplConfigItem_IsChargerHiZModeEnabled = 13, SplConfigItem_IsKiosk = 14, SplConfigItem_NewHardwareType = 15, SplConfigItem_NewKeyGeneration = 16, SplConfigItem_Package2Hash = 17, SplConfigItem_ExosphereVersion = 65000, SplConfigItem_NeedsReboot = 65001, SplConfigItem_NeedsShutdown = 65002, SplConfigItem_ExosphereVerHash = 65003, SplConfigItem_HasRcmBugPatch = 65004, } SplConfigItem; typedef enum { SplSocType_Erista = 0, SplSocType_Mariko = 1, } SplSocType; typedef enum { SplHardwareType_Icosa = 0, SplHardwareType_Copper = 1, SplHardwareType_Hoag = 2, SplHardwareType_Iowa = 3, SplHardwareType_Calcio = 4, SplHardwareType_Five = 5, } SplHardwareType; typedef enum { EXO_EMUMMC_TYPE_NONE = 0, EXO_EMUMMC_TYPE_PARTITION = 1, EXO_EMUMMC_TYPE_FILES = 2, } exo_emummc_type_t; typedef enum { EXO_EMUMMC_MMC_NAND = 0, EXO_EMUMMC_MMC_SD = 1, EXO_EMUMMC_MMC_GC = 2, } exo_emummc_mmc_t; typedef struct { uint32_t magic; uint32_t type; uint32_t id; uint32_t fs_version; } exo_emummc_base_config_t; typedef struct { uint64_t start_sector; } exo_emummc_partition_config_t; typedef struct { exo_emummc_base_config_t base_cfg; union { exo_emummc_partition_config_t partition_cfg; }; } exo_emummc_config_t; Result smcGetConfig(SplConfigItem config_item, u64 *out_config); SplHardwareType splGetHardwareType(void); SplSocType splGetSocType(void); void smcRebootToRcm(void); void smcRebootToIramPayload(void); void smcPerformShutdown(void); Result smcCopyToIram(uintptr_t iram_addr, const void *src_addr, u32 size); Result smcCopyFromIram(void *dst_addr, uintptr_t iram_addr, u32 size); Result smcReadWriteRegister(u32 phys_addr, u32 value, u32 mask); Result smcGetEmummcConfig(exo_emummc_mmc_t mmc_id, exo_emummc_config_t *out_cfg, void *out_paths); Result smcGenerateRandomBytes(void *dst, u32 size); u64 smcGenerateRandomU64(void); #ifdef __cplusplus } #endif ================================================ FILE: emummc/source/nx/start.s ================================================ /** * @file start.s * @copyright libnx Authors */ .macro push_all SUB SP, SP, #0x100 STP X29, X30, [SP, #0x0] STP X27, X28, [SP, #0x10] STP X25, X26, [SP, #0x20] STP X23, X24, [SP, #0x30] STP X21, X22, [SP, #0x40] STP X19, X20, [SP, #0x50] STP X17, X18, [SP, #0x60] STP X15, X16, [SP, #0x70] STP X13, X14, [SP, #0x80] STP X11, X12, [SP, #0x90] STP X9, X10, [SP, #0xA0] STP X7, X8, [SP, #0xB0] STP X5, X6, [SP, #0xC0] STP X3, X4, [SP, #0xD0] STP X1, X2, [SP, #0xE0] STR X0, [SP, #0xF0] .endm .macro pop_all LDR X0, [SP, #0xF0] LDP X1, X2, [SP, #0xE0] LDP X3, X4, [SP, #0xD0] LDP X5, X6, [SP, #0xC0] LDP X7, X8, [SP, #0xB0] LDP X9, X10, [SP, #0xA0] LDP X11, X12, [SP, #0x90] LDP X13, X14, [SP, #0x80] LDP X15, X16, [SP, #0x70] LDP X17, X18, [SP, #0x60] LDP X19, X20, [SP, #0x50] LDP X21, X22, [SP, #0x40] LDP X23, X24, [SP, #0x30] LDP X25, X26, [SP, #0x20] LDP X27, X28, [SP, #0x10] LDP X29, X30, [SP, #0x0] ADD SP, SP, #0x100 .endm .section ".crt0","ax" .global _start _start: B startup .org _start+0xc B sdmmc_wrapper_read .org _start+0x18 B sdmmc_wrapper_write .org _start+0x80 .section ".crt0","ax" startup: # Save LR MOV X7, X30 # Retrieve ASLR Base BL +4 SUB X6, X30, #0x88 # Context Ptr and MainThread Handle MOV X5, X0 MOV X4, X1 # Inject start push_all MOV W0, #0xFFFF8001 ADR X1, __rodata_start ADR X2, __data_start SUB X2, X2, X1 MOV X3, #1 SVC 0x73 MOV W0, #0xFFFF8001 ADR X1, __data_start ADR X2, __argdata__ SUB X2, X2, X1 MOV X3, #3 SVC 0x73 pop_all MOV X27, X7 MOV X25, X5 MOV X26, X4 # Clear .bss ADRP X0, __bss_start__ ADRP X1, __bss_end__ ADD X0, X0, #:lo12:__bss_start__ ADD X1, X1, #:lo12:__bss_end__ SUB X1, X1, X0 ADD X1, X1, #7 BIC X1, X1, #7 bss_loop: STR XZR, [X0], #8 SUBS X1, X1, #8 BNE bss_loop # Store SP MOV X1, SP ADRP X0, __stack_top STR X1, [X0, #:lo12:__stack_top] # Process _DYNAMIC Section MOV X0, X6 ADRP X1, _DYNAMIC ADD X1, X1, #:lo12:_DYNAMIC BL __nx_dynamic # TODO: handle in code MOV X0, X25 MOV X1, X26 MOV X2, X27 BL __initheap BL __init MOV X0, X25 MOV X1, X26 MOV X30, X27 # FS main ADRP X16, __argdata__ BR X16 ================================================ FILE: emummc/source/nx/svc.h ================================================ /** * @file svc.h * @brief Wrappers for kernel syscalls. * @copyright libnx Authors */ #pragma once #include "../utils/types.h" /// Memory information structure. typedef struct { u64 addr; ///< Base address. u64 size; ///< Size. u32 type; ///< Memory type (see lower 8 bits of \ref MemoryState). u32 attr; ///< Memory attributes (see \ref MemoryAttribute). u32 perm; ///< Memory permissions (see \ref Permission). u32 device_refcount; ///< Device reference count. u32 ipc_refcount; ///< IPC reference count. u32 padding; ///< Padding. } MemoryInfo; /// Memory permission bitmasks. typedef enum { Perm_None = 0, ///< No permissions. Perm_R = BIT(0), ///< Read permission. Perm_W = BIT(1), ///< Write permission. Perm_X = BIT(2), ///< Execute permission. Perm_Rw = Perm_R | Perm_W, ///< Read/write permissions. Perm_Rx = Perm_R | Perm_X, ///< Read/execute permissions. Perm_DontCare = BIT(28), ///< Don't care } Permission; /// Secure monitor arguments. typedef struct { u64 X[8]; ///< Values of X0 through X7. } SecmonArgs; _Static_assert(sizeof(SecmonArgs) == 0x40, "SecmonArgs definition"); #define DeviceName_SDMMC1A 19 #define DeviceName_SDMMC2A 20 #define DeviceName_SDMMC3A 21 #define DeviceName_SDMMC4A 22 #ifdef __cplusplus extern "C" { #endif /** * @brief Returns a virtual address mapped to a given IO range. * @return Result code. * @note Syscall number 0x55. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. * @warning Only exists on [10.0.0+]. For older versions use \ref svcLegacyQueryIoMapping. */ Result svcQueryIoMapping(u64* virtaddr, u64* out_size, u64 physaddr, u64 size); /** * @brief Returns a virtual address mapped to a given IO range. * @return Result code. * @note Syscall number 0x55. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. * @warning Only exists on [1.0.0-9.2.0]. For newer versions use \ref svcQueryIoMapping. */ Result svcLegacyQueryIoMapping(u64* virtaddr, u64 physaddr, u64 size); /** * @brief Attaches a device address space to a device. * @return Result code. * @note Syscall number 0x57. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcAttachDeviceAddressSpace(u64 device, Handle handle); /** * @brief Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address. * @param[out] meminfo_ptr \ref MemoryInfo structure which will be filled in. * @param[out] pageinfo Page information which will be filled in. * @param[in] addr Address to query. * @return Result code. * @note Syscall number 0x06. */ Result svcQueryMemory(MemoryInfo* meminfo_ptr, u32 *pageinfo, u64 addr); /** * @brief Sets the memory permissions for the specified memory with the supplied process handle. * @param[in] proc Process handle. * @param[in] addr Address of the memory. * @param[in] size Size of the memory. * @param[in] perm Permissions (see \ref Permission). * @return Result code. * @remark This returns an error (0xD801) when \p perm is >0x5, hence -WX and RWX are not allowed. * @note Syscall number 0x73. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcSetProcessMemoryPermission(Handle proc, u64 addr, u64 size, u32 perm); /** * @brief Set the memory permissions of a (page-aligned) range of memory. * @param[in] addr Start address of the range. * @param[in] size Size of the range, in bytes. * @param[in] perm Permissions (see \ref Permission). * @return Result code. * @remark Perm_X is not allowed. Setting write-only is not allowed either (Perm_W). * This can be used to move back and forth between Perm_None, Perm_R and Perm_Rw. * @note Syscall number 0x01. */ Result svcSetMemoryPermission(void* addr, u64 size, u32 perm); /** * @brief Creates a thread. * @return Result code. * @note Syscall number 0x08. */ Result svcCreateThread(Handle* out, void* entry, void* arg, void* stack_top, int prio, int cpuid); /** * @brief Starts a freshly created thread. * @return Result code. * @note Syscall number 0x09. */ Result svcStartThread(Handle handle); /** * @brief Exits the current thread. * @note Syscall number 0x0A. */ void __attribute__((noreturn)) svcExitThread(void); /** * @brief Closes a handle, decrementing the reference count of the corresponding kernel object. * This might result in the kernel freeing the object. * @param handle Handle to close. * @return Result code. * @note Syscall number 0x16. */ Result svcCloseHandle(Handle handle); /** * @brief Waits on one or more synchronization objects, optionally with a timeout. * @return Result code. * @note Syscall number 0x18. * @note \p handleCount must not be greater than \ref MAX_WAIT_OBJECTS. This is a Horizon kernel limitation. * @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitHandles or \ref waitMultiHandle should normally be used instead. */ Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout); /** * @brief Waits on a single synchronization object, optionally with a timeout. * @return Result code. * @note Wrapper for \ref svcWaitSynchronization. * @note This is the raw syscall, which can be cancelled by \ref svcCancelSynchronization or other means. \ref waitSingleHandle should normally be used instead. */ static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) { s32 tmp; return svcWaitSynchronization(&tmp, &handle, 1, timeout); } /** * @brief Creates an IPC session. * @return Result code. * @note Syscall number 0x40. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcCreateSession(Handle *server_handle, Handle *client_handle, u32 unk0, u64 unk1);//unk* are normally 0? /** * @brief Sends an IPC synchronization request to a session. * @return Result code. * @note Syscall number 0x21. */ Result svcSendSyncRequest(Handle session); /** * @brief Performs IPC input/output. * @return Result code. * @note Syscall number 0x43. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcReplyAndReceive(s32* index, const Handle* handles, s32 handleCount, Handle replyTarget, u64 timeout); /** * @brief Maps the src address from the supplied process handle into the current process. * @param[in] dst Address to which map the memory in the current process. * @param[in] proc Process handle. * @param[in] src Source mapping address. * @param[in] size Size of the memory. * @return Result code. * @remark This allows mapping code and rodata with RW- permission. * @note Syscall number 0x74. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcMapProcessMemory(void* dst, Handle proc, u64 src, u64 size); /** * @brief Undoes the effects of \ref svcMapProcessMemory. * @param[in] dst Destination mapping address * @param[in] proc Process handle. * @param[in] src Address of the memory in the process. * @param[in] size Size of the memory. * @return Result code. * @remark This allows mapping code and rodata with RW- permission. * @note Syscall number 0x75. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ Result svcUnmapProcessMemory(void* dst, Handle proc, u64 src, u64 size); /** * @brief Calls a secure monitor function (TrustZone, EL3). * @param regs Arguments to pass to the secure monitor. * @return Return value from the secure monitor. * @note Syscall number 0x7F. * @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available. */ u64 svcCallSecureMonitor(SecmonArgs* regs); #ifdef __cplusplus } #endif ///@} ================================================ FILE: emummc/source/nx/svc.s ================================================ /** * @file svc.s * @copyright libnx Authors */ .macro SVC_BEGIN name .section .text.\name, "ax", %progbits .global \name .type \name, %function .align 2 .cfi_startproc \name: .endm .macro SVC_END .cfi_endproc .endm SVC_BEGIN svcQueryIoMapping STP X0, X1, [SP, #-16]! SVC 0x55 LDP X3, X4, [SP], #16 STR X1, [X3] STR X2, [X4] RET SVC_END SVC_BEGIN svcLegacyQueryIoMapping STR X0, [SP, #-16]! SVC 0x55 LDR X2, [SP], #16 STR X1, [X2] RET SVC_END SVC_BEGIN svcAttachDeviceAddressSpace SVC 0x57 RET SVC_END SVC_BEGIN svcQueryMemory STR X1, [SP, #-16]! SVC 0x6 LDR X2, [SP], #16 STR W1, [X2] RET SVC_END SVC_BEGIN svcSetMemoryPermission SVC 0x2 RET SVC_END SVC_BEGIN svcSetProcessMemoryPermission SVC 0x73 RET SVC_END SVC_BEGIN svcCreateThread STR X0, [SP, #-16]! SVC 0x8 LDR X2, [SP], #16 STR W1, [X2] RET SVC_END SVC_BEGIN svcStartThread SVC 0x9 RET SVC_END SVC_BEGIN svcExitThread SVC 0xA RET SVC_END SVC_BEGIN svcCloseHandle SVC 0x16 RET SVC_END SVC_BEGIN svcWaitSynchronization STR X0, [SP, #-16]! SVC 0x18 LDR X2, [SP], #16 STR W1, [X2] RET SVC_END SVC_BEGIN svcCreateSession STP X0, X1, [SP, #-16]! SVC 0x40 LDP X3, X4, [SP], #16 STR W1, [X3] STR W2, [X4] RET SVC_END SVC_BEGIN svcSendSyncRequest SVC 0x21 RET SVC_END SVC_BEGIN svcReplyAndReceive STR X0, [SP, #-16]! SVC 0x43 LDR X2, [SP], #16 STR W1, [X2] RET SVC_END SVC_BEGIN svcMapProcessMemory SVC 0x74 RET SVC_END SVC_BEGIN svcUnmapProcessMemory SVC 0x75 RET SVC_END SVC_BEGIN svcCallSecureMonitor STR X0, [SP, #-16]! MOV X8, X0 LDP X0, X1, [X8] LDP X2, X3, [X8, #0x10] LDP X4, X5, [X8, #0x20] LDP X6, X7, [X8, #0x30] SVC 0x7F LDR X8, [SP], #16 STP X0, X1, [X8] STP X2, X3, [X8, #0x10] STP X4, X5, [X8, #0x20] STP X6, X7, [X8, #0x30] RET SVC_END ================================================ FILE: emummc/source/power/max77620.h ================================================ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. */ #ifndef _MFD_MAX77620_H_ #define _MFD_MAX77620_H_ #define MAX77620_I2C_ADDR 0x3C /* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ #define MAX77620_REG_CNFGGLBL1 0x00 #define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) #define MAX77620_CNFGGLBL1_MPPLD (1 << 6) #define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) #define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) #define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) #define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) #define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) #define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E #define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) #define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) #define MAX77620_REG_CNFGGLBL2 0x01 #define MAX77620_REG_CNFGGLBL3 0x02 #define MAX77620_WDTC_MASK 0x3 #define MAX77620_WDTOFFC (1 << 4) #define MAX77620_WDTSLPC (1 << 3) #define MAX77620_WDTEN (1 << 2) #define MAX77620_TWD_MASK 0x3 #define MAX77620_TWD_2s 0x0 #define MAX77620_TWD_16s 0x1 #define MAX77620_TWD_64s 0x2 #define MAX77620_TWD_128s 0x3 #define MAX77620_REG_CNFG1_32K 0x03 #define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) #define MAX77620_REG_CNFGBBC 0x04 #define MAX77620_CNFGBBC_ENABLE (1 << 0) #define MAX77620_CNFGBBC_CURRENT_MASK 0x06 #define MAX77620_CNFGBBC_CURRENT_SHIFT 1 #define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 #define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 #define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) #define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 #define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 #define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_REG_IRQTOP 0x05 #define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) #define MAX77620_IRQ_TOP_SD_MASK (1 << 6) #define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) #define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) #define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) #define MAX77620_IRQ_TOP_32K_MASK (1 << 2) #define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) #define MAX77620_REG_INTLBT 0x06 #define MAX77620_REG_IRQTOPM 0x0D #define MAX77620_IRQ_LBM_MASK (1 << 3) #define MAX77620_IRQ_TJALRM1_MASK (1 << 2) #define MAX77620_IRQ_TJALRM2_MASK (1 << 1) #define MAX77620_REG_IRQSD 0x07 #define MAX77620_REG_IRQ_LVL2_L0_7 0x08 #define MAX77620_REG_IRQ_LVL2_L8 0x09 #define MAX77620_REG_IRQ_LVL2_GPIO 0x0A #define MAX77620_REG_ONOFFIRQ 0x0B #define MAX77620_REG_NVERC 0x0C #define MAX77620_REG_INTENLBT 0x0E #define MAX77620_GLBLM_MASK (1 << 0) #define MAX77620_REG_IRQMASKSD 0x0F #define MAX77620_REG_IRQ_MSK_L0_7 0x10 #define MAX77620_REG_IRQ_MSK_L8 0x11 #define MAX77620_REG_ONOFFIRQM 0x12 #define MAX77620_REG_STATLBT 0x13 #define MAX77620_REG_STATSD 0x14 #define MAX77620_REG_ONOFFSTAT 0x15 /* SD and LDO Registers */ #define MAX77620_REG_SD0 0x16 #define MAX77620_REG_SD1 0x17 #define MAX77620_REG_SD2 0x18 #define MAX77620_REG_SD3 0x19 #define MAX77620_REG_SD4 0x1A #define MAX77620_SDX_VOLT_MASK 0xFF #define MAX77620_SD0_VOLT_MASK 0x3F #define MAX77620_SD1_VOLT_MASK 0x7F #define MAX77620_LDO_VOLT_MASK 0x3F #define MAX77620_REG_DVSSD0 0x1B #define MAX77620_REG_DVSSD1 0x1C #define MAX77620_REG_SD0_CFG 0x1D #define MAX77620_REG_SD1_CFG 0x1E #define MAX77620_REG_SD2_CFG 0x1F #define MAX77620_REG_SD3_CFG 0x20 #define MAX77620_REG_SD4_CFG 0x21 #define MAX77620_REG_SD_CFG2 0x22 #define MAX77620_REG_LDO0_CFG 0x23 #define MAX77620_REG_LDO0_CFG2 0x24 #define MAX77620_REG_LDO1_CFG 0x25 #define MAX77620_REG_LDO1_CFG2 0x26 #define MAX77620_REG_LDO2_CFG 0x27 #define MAX77620_REG_LDO2_CFG2 0x28 #define MAX77620_REG_LDO3_CFG 0x29 #define MAX77620_REG_LDO3_CFG2 0x2A #define MAX77620_REG_LDO4_CFG 0x2B #define MAX77620_REG_LDO4_CFG2 0x2C #define MAX77620_REG_LDO5_CFG 0x2D #define MAX77620_REG_LDO5_CFG2 0x2E #define MAX77620_REG_LDO6_CFG 0x2F #define MAX77620_REG_LDO6_CFG2 0x30 #define MAX77620_REG_LDO7_CFG 0x31 #define MAX77620_REG_LDO7_CFG2 0x32 #define MAX77620_REG_LDO8_CFG 0x33 #define MAX77620_REG_LDO8_CFG2 0x34 #define MAX77620_LDO_POWER_MODE_MASK 0xC0 #define MAX77620_LDO_POWER_MODE_SHIFT 6 #define MAX77620_POWER_MODE_NORMAL 3 #define MAX77620_POWER_MODE_LPM 2 #define MAX77620_POWER_MODE_GLPM 1 #define MAX77620_POWER_MODE_DISABLE 0 #define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) #define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) #define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) #define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) #define MAX77620_LDO_CFG2_SS_MASK (1 << 0) #define MAX77620_LDO_CFG2_SS_FAST (1 << 0) #define MAX77620_LDO_CFG2_SS_SLOW 0 #define MAX77620_REG_LDO_CFG3 0x35 #define MAX77620_TRACK4_MASK (1 << 5) #define MAX77620_TRACK4_SHIFT 5 #define MAX77620_LDO_SLEW_RATE_MASK 0x1 #define MAX77620_REG_GPIO0 0x36 #define MAX77620_REG_GPIO1 0x37 #define MAX77620_REG_GPIO2 0x38 #define MAX77620_REG_GPIO3 0x39 #define MAX77620_REG_GPIO4 0x3A #define MAX77620_REG_GPIO5 0x3B #define MAX77620_REG_GPIO6 0x3C #define MAX77620_REG_GPIO7 0x3D #define MAX77620_REG_PUE_GPIO 0x3E #define MAX77620_REG_PDE_GPIO 0x3F #define MAX77620_REG_AME_GPIO 0x40 #define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) #define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) #define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) #define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) #define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) #define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) #define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) #define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) #define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) #define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) #define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) #define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) #define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) #define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) #define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) #define MAX77620_REG_ONOFFCNFG1 0x41 #define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) #define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 #define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 #define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) #define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) #define MAX20024_ONOFFCNFG1_CLRSE 0x18 #define MAX77620_REG_ONOFFCNFG2 0x42 #define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) #define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) #define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) #define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) #define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) /* FPS Registers */ #define MAX77620_REG_FPS_CFG0 0x43 #define MAX77620_REG_FPS_CFG1 0x44 #define MAX77620_REG_FPS_CFG2 0x45 #define MAX77620_REG_FPS_LDO0 0x46 #define MAX77620_REG_FPS_LDO1 0x47 #define MAX77620_REG_FPS_LDO2 0x48 #define MAX77620_REG_FPS_LDO3 0x49 #define MAX77620_REG_FPS_LDO4 0x4A #define MAX77620_REG_FPS_LDO5 0x4B #define MAX77620_REG_FPS_LDO6 0x4C #define MAX77620_REG_FPS_LDO7 0x4D #define MAX77620_REG_FPS_LDO8 0x4E #define MAX77620_REG_FPS_SD0 0x4F #define MAX77620_REG_FPS_SD1 0x50 #define MAX77620_REG_FPS_SD2 0x51 #define MAX77620_REG_FPS_SD3 0x52 #define MAX77620_REG_FPS_SD4 0x53 #define MAX77620_REG_FPS_NONE 0 #define MAX77620_FPS_SRC_MASK 0xC0 #define MAX77620_FPS_SRC_SHIFT 6 #define MAX77620_FPS_PU_PERIOD_MASK 0x38 #define MAX77620_FPS_PU_PERIOD_SHIFT 3 #define MAX77620_FPS_PD_PERIOD_MASK 0x07 #define MAX77620_FPS_PD_PERIOD_SHIFT 0 /* Minimum and maximum FPS period time (in microseconds) are * different for MAX77620 and Max20024. */ #define MAX77620_FPS_COUNT 3 #define MAX77620_FPS_PERIOD_MIN_US 40 #define MAX20024_FPS_PERIOD_MIN_US 20 #define MAX77620_FPS_PERIOD_MAX_US 2560 #define MAX20024_FPS_PERIOD_MAX_US 5120 #define MAX77620_REG_FPS_GPIO1 0x54 #define MAX77620_REG_FPS_GPIO2 0x55 #define MAX77620_REG_FPS_GPIO3 0x56 #define MAX77620_FPS_TIME_PERIOD_MASK 0x38 #define MAX77620_FPS_TIME_PERIOD_SHIFT 3 #define MAX77620_FPS_EN_SRC_MASK 0x06 #define MAX77620_FPS_EN_SRC_SHIFT 1 #define MAX77620_FPS_ENFPS_SW_MASK 0x01 #define MAX77620_FPS_ENFPS_SW 0x01 #define MAX77620_REG_FPS_RSO 0x57 #define MAX77620_REG_CID0 0x58 #define MAX77620_REG_CID1 0x59 #define MAX77620_REG_CID2 0x5A #define MAX77620_REG_CID3 0x5B #define MAX77620_REG_CID4 0x5C #define MAX77620_REG_CID5 0x5D #define MAX77620_REG_DVSSD4 0x5E #define MAX20024_REG_MAX_ADD 0x70 #define MAX77620_CID_DIDM_MASK 0xF0 #define MAX77620_CID_DIDM_SHIFT 4 /* CNCG2SD */ #define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) #define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) /* Device Identification Metal */ #define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) /* Device Indentification OTP */ #define MAX77620_CID5_DIDO(n) ((n) & 0xF) /* SD CNFG1 */ #define MAX77620_SD_SR_MASK 0xC0 #define MAX77620_SD_SR_SHIFT 6 #define MAX77620_SD_POWER_MODE_MASK 0x30 #define MAX77620_SD_POWER_MODE_SHIFT 4 #define MAX77620_SD_CFG1_ADE_MASK (1 << 3) #define MAX77620_SD_CFG1_ADE_DISABLE 0 #define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) #define MAX77620_SD_FPWM_MASK 0x04 #define MAX77620_SD_FPWM_SHIFT 2 #define MAX77620_SD_FSRADE_MASK 0x01 #define MAX77620_SD_FSRADE_SHIFT 0 #define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) #define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 #define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) #define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) #define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) #define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) #define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) #define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) #define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) #define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) #define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) /* Interrupts */ enum { MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ MAX77620_IRQ_TOP_SD, /* SD power fail */ MAX77620_IRQ_TOP_LDO, /* LDO power fail */ MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ MAX77620_IRQ_TOP_RTC, /* RTC */ MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ }; /* GPIOs */ enum { MAX77620_GPIO0, MAX77620_GPIO1, MAX77620_GPIO2, MAX77620_GPIO3, MAX77620_GPIO4, MAX77620_GPIO5, MAX77620_GPIO6, MAX77620_GPIO7, MAX77620_GPIO_NR, }; /* FPS Source */ enum max77620_fps_src { MAX77620_FPS_SRC_0, MAX77620_FPS_SRC_1, MAX77620_FPS_SRC_2, MAX77620_FPS_SRC_NONE, MAX77620_FPS_SRC_DEF, }; enum max77620_chip_id { MAX77620, MAX20024, }; #endif /* _MFD_MAX77620_H_ */ ================================================ FILE: emummc/source/power/max7762x.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "max7762x.h" #include "max77620.h" #include "../soc/i2c.h" #include "../utils/util.h" #define REGULATOR_SD 0 #define REGULATOR_LDO 1 typedef struct _max77620_regulator_t { u8 type; const char *name; u8 reg_sd; u32 mv_step; u32 mv_min; u32 mv_default; u32 mv_max; u8 volt_addr; u8 cfg_addr; u8 volt_mask; u8 enable_mask; u8 enable_shift; u8 status_mask; u8 fps_addr; u8 fps_src; u8 pd_period; u8 pu_period; } max77620_regulator_t; static const max77620_regulator_t _pmic_regulators[] = { { REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 }, { REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 }, { REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 }, { REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 }, { REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 }, { REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 }, { REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 }, { REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 }, { REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 }, { REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 }, { REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 }, { REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 }, { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } }; int max77620_regulator_get_status(u32 id) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; if (reg->type == REGULATOR_SD) return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_STATSD) & reg->status_mask) ? 0 : 1; return (i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->cfg_addr) & 8) ? 1 : 0; } int max77620_regulator_config_fps(u32 id) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); return 1; } int max77620_regulator_set_voltage(u32 id, u32 mv) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; if (mv < reg->mv_min || mv > reg->mv_max) return 0; u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); usleep(1000); return 1; } int max77620_regulator_enable(u32 id, int enable) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr; u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr); if (enable) val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); else val &= ~reg->enable_mask; i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val); usleep(1000); return 1; } int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) { if (id > REGULATOR_MAX) return 0; const max77620_regulator_t *reg = &_pmic_regulators[id]; if (mv < reg->mv_min || mv > reg->mv_max) return 0; u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); usleep(1000); return 1; } void max77620_config_default() { for (u32 i = 1; i <= REGULATOR_MAX; i++) { i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CID4); max77620_regulator_config_fps(i); max77620_regulator_set_voltage(i, _pmic_regulators[i].mv_default); if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) max77620_regulator_enable(i, 1); } i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4); } ================================================ FILE: emummc/source/power/max7762x.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _MAX7762X_H_ #define _MAX7762X_H_ #include "../utils/types.h" /* * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init *-------+---------------+---------+--------+------------+---------+------------------ * sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) * sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) * sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) * sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | * ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) * ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | * ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | */ /* * MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode * MAX77620_REG_GPIOx: 0x9 sets output and enable */ /*! MAX77620 partitions. */ #define REGULATOR_SD0 0 #define REGULATOR_SD1 1 #define REGULATOR_SD2 2 #define REGULATOR_SD3 3 #define REGULATOR_LDO0 4 #define REGULATOR_LDO1 5 #define REGULATOR_LDO2 6 #define REGULATOR_LDO3 7 #define REGULATOR_LDO4 8 #define REGULATOR_LDO5 9 #define REGULATOR_LDO6 10 #define REGULATOR_LDO7 11 #define REGULATOR_LDO8 12 #define REGULATOR_MAX 12 #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_VOUT_REG 0 #define MAX77621_VOUT_DVC_REG 1 #define MAX77621_CONTROL1_REG 2 #define MAX77621_CONTROL2_REG 3 /* MAX77621_VOUT */ #define MAX77621_VOUT_ENABLE (1 << 7) #define MAX77621_VOUT_MASK 0x7F #define MAX77621_VOUT_0_95V 0x37 #define MAX77621_VOUT_1_09V 0x4F /* MAX77621_VOUT_DVC_DVS */ #define MAX77621_DVS_VOUT_MASK 0x7F /* MAX77621_CONTROL1 */ #define MAX77621_SNS_ENABLE (1 << 7) #define MAX77621_FPWM_EN_M (1 << 6) #define MAX77621_NFSR_ENABLE (1 << 5) #define MAX77621_AD_ENABLE (1 << 4) #define MAX77621_BIAS_ENABLE (1 << 3) #define MAX77621_FREQSHIFT_9PER (1 << 2) #define MAX77621_RAMP_12mV_PER_US 0x0 #define MAX77621_RAMP_25mV_PER_US 0x1 #define MAX77621_RAMP_50mV_PER_US 0x2 #define MAX77621_RAMP_200mV_PER_US 0x3 #define MAX77621_RAMP_MASK 0x3 /* MAX77621_CONTROL2 */ #define MAX77621_WDTMR_ENABLE (1 << 6) #define MAX77621_DISCH_ENBABLE (1 << 5) #define MAX77621_FT_ENABLE (1 << 4) #define MAX77621_T_JUNCTION_120 (1 << 7) #define MAX77621_CKKADV_TRIP_DISABLE 0xC #define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 #define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 #define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 #define MAX77621_INDUCTOR_MIN_30_PER 0x0 #define MAX77621_INDUCTOR_NOMINAL 0x1 #define MAX77621_INDUCTOR_PLUS_30_PER 0x2 #define MAX77621_INDUCTOR_PLUS_60_PER 0x3 int max77620_regulator_get_status(u32 id); int max77620_regulator_config_fps(u32 id); int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); #endif ================================================ FILE: emummc/source/soc/clock.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "../soc/clock.h" #include "../soc/t210.h" #include "../utils/util.h" #include "../emmc/sdmmc.h" static const sclock_t _clock_i2c5 = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 0, 4 //81.6MHz -> 400KHz }; static sclock_t _clock_sdmmc_legacy_tm = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66 }; void clock_enable(const sclock_t *clk) { // Put clock into reset. CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); // Disable. CLOCK(clk->enable) &= ~(1 << clk->index); // Configure clock source if required. if (clk->source) CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); // Enable. CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); usleep(2); // Take clock off reset. CLOCK(clk->reset) &= ~(1 << clk->index); } void clock_disable(const sclock_t *clk) { // Put clock into reset. CLOCK(clk->reset) = (CLOCK(clk->reset) & ~(1 << clk->index)) | (1 << clk->index); // Disable. CLOCK(clk->enable) &= ~(1 << clk->index); } void clock_enable_i2c5() { clock_enable(&_clock_i2c5); } void clock_disable_i2c5() { clock_disable(&_clock_i2c5); } static void _clock_enable_pllc4() { if ((CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & (PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | 0xFFFFFF)) == (PLLCX_BASE_ENABLE | PLLCX_BASE_LOCK | (104 << 8) | 4)) return; // Enable Phase and Frequency lock detection. //CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; // Disable PLL and IDDQ in case they are on. CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLCX_BASE_ENABLE; CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLLC4_BASE_IDDQ; (void)CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE); usleep(10); // Set PLLC4 dividers. CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = (104 << 8) | 4; // DIVM: 4, DIVP: 1. // Enable PLLC4 and wait for Phase and Frequency lock. CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) |= PLLCX_BASE_ENABLE; (void)CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE); while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLCX_BASE_LOCK)) ; msleep(1); // Wait a bit for PLL to stabilize. } #define L_SWR_SDMMC1_RST (1 << 14) #define L_SWR_SDMMC2_RST (1 << 9) #define L_SWR_SDMMC4_RST (1 << 15) #define U_SWR_SDMMC3_RST (1 << 5) #define L_CLK_ENB_SDMMC1 (1 << 14) #define L_CLK_ENB_SDMMC2 (1 << 9) #define L_CLK_ENB_SDMMC4 (1 << 15) #define U_CLK_ENB_SDMMC3 (1 << 5) #define L_SET_SDMMC1_RST (1 << 14) #define L_SET_SDMMC2_RST (1 << 9) #define L_SET_SDMMC4_RST (1 << 15) #define U_SET_SDMMC3_RST (1 << 5) #define L_CLR_SDMMC1_RST (1 << 14) #define L_CLR_SDMMC2_RST (1 << 9) #define L_CLR_SDMMC4_RST (1 << 15) #define U_CLR_SDMMC3_RST (1 << 5) #define L_SET_CLK_ENB_SDMMC1 (1 << 14) #define L_SET_CLK_ENB_SDMMC2 (1 << 9) #define L_SET_CLK_ENB_SDMMC4 (1 << 15) #define U_SET_CLK_ENB_SDMMC3 (1 << 5) #define L_CLR_CLK_ENB_SDMMC1 (1 << 14) #define L_CLR_CLK_ENB_SDMMC2 (1 << 9) #define L_CLR_CLK_ENB_SDMMC4 (1 << 15) #define U_CLR_CLK_ENB_SDMMC3 (1 << 5) static int _clock_sdmmc_is_reset(u32 id) { switch (id) { case SDMMC_1: return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC1_RST; case SDMMC_2: return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC2_RST; case SDMMC_3: return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_U) & U_SWR_SDMMC3_RST; case SDMMC_4: return CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_L) & L_SWR_SDMMC4_RST; } return 0; } static void _clock_sdmmc_set_reset(u32 id) { switch (id) { case SDMMC_1: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST; break; case SDMMC_2: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST; break; case SDMMC_3: CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST; break; case SDMMC_4: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST; break; } } static void _clock_sdmmc_clear_reset(u32 id) { switch (id) { case SDMMC_1: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST; break; case SDMMC_2: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST; break; case SDMMC_3: CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST; break; case SDMMC_4: CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST; break; } } static int _clock_sdmmc_is_enabled(u32 id) { switch (id) { case SDMMC_1: return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC1; case SDMMC_2: return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC2; case SDMMC_3: return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) & U_CLK_ENB_SDMMC3; case SDMMC_4: return CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) & L_CLK_ENB_SDMMC4; } return 0; } static void _clock_sdmmc_set_enable(u32 id) { switch (id) { case SDMMC_1: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1; break; case SDMMC_2: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2; break; case SDMMC_3: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3; break; case SDMMC_4: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4; break; } } static void _clock_sdmmc_clear_enable(u32 id) { switch (id) { case SDMMC_1: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1; break; case SDMMC_2: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2; break; case SDMMC_3: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3; break; case SDMMC_4: CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4; break; } } static void _clock_sdmmc_config_legacy_tm() { sclock_t *clk = &_clock_sdmmc_legacy_tm; if (!(CLOCK(clk->enable) & (1 << clk->index))) clock_enable(clk); } typedef struct _clock_sdmmc_t { u32 clock; u32 real_clock; } clock_sdmmc_t; static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 }; #define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0 #define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3 #define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1 static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val) { u32 divisor = 0; u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0; if (id > SDMMC_4) return 0; // Get IO clock divisor. switch (val) { case 25000: *pclock = 24728; divisor = 31; // 16.5 div. break; case 26000: *pclock = 25500; divisor = 30; // 16 div. break; case 40800: *pclock = 40800; divisor = 18; // 10 div. break; case 50000: *pclock = 48000; divisor = 15; // 8.5 div. break; case 52000: *pclock = 51000; divisor = 14; // 8 div. break; case 100000: source = SDMMC_CLOCK_SRC_PLLC4_OUT2; *pclock = 99840; divisor = 2; // 2 div. break; case 164000: *pclock = 163200; divisor = 3; // 2.5 div. break; case 200000: switch (id) { case SDMMC_1: source = SDMMC_CLOCK_SRC_PLLC4_OUT2; break; case SDMMC_2: source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; break; case SDMMC_3: source = SDMMC_CLOCK_SRC_PLLC4_OUT2; break; case SDMMC_4: source = SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ; break; } *pclock = 199680; divisor = 0; // 1 div. break; default: *pclock = 24728; divisor = 31; // 16.5 div. } _clock_sdmmc_table[id].clock = val; _clock_sdmmc_table[id].real_clock = *pclock; // PLLC4 and LEGACY_TM clocks are already initialized, // because we init at the first eMMC read. // // Enable PLLC4 if in use by any SDMMC. // if (source) // _clock_enable_pllc4(); // // Set SDMMC legacy timeout clock. // _clock_sdmmc_config_legacy_tm(); // Set SDMMC clock. switch (id) { case SDMMC_1: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor; break; case SDMMC_2: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor; break; case SDMMC_3: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor; break; case SDMMC_4: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor; break; } return 1; } void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val) { if (_clock_sdmmc_table[id].clock == val) { *pclock = _clock_sdmmc_table[id].real_clock; } else { int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); _clock_sdmmc_config_clock_host(pclock, id, val); if (is_enabled) _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); } } void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type) { // Get Card clock divisor. switch (type) { case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz. *pclock = 26000; *pdivisor = 66; break; case SDHCI_TIMING_MMC_LS26: *pclock = 26000; *pdivisor = 1; break; case SDHCI_TIMING_MMC_HS52: *pclock = 52000; *pdivisor = 1; break; case SDHCI_TIMING_MMC_HS200: case SDHCI_TIMING_MMC_HS400: case SDHCI_TIMING_UHS_SDR104: *pclock = 200000; *pdivisor = 1; break; case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz. *pclock = 25000; *pdivisor = 64; break; case SDHCI_TIMING_SD_DS12: case SDHCI_TIMING_UHS_SDR12: *pclock = 25000; *pdivisor = 1; break; case SDHCI_TIMING_SD_HS25: case SDHCI_TIMING_UHS_SDR25: *pclock = 50000; *pdivisor = 1; break; case SDHCI_TIMING_UHS_SDR50: *pclock = 100000; *pdivisor = 1; break; case SDHCI_TIMING_UHS_SDR82: *pclock = 164000; *pdivisor = 1; break; case SDHCI_TIMING_UHS_DDR50: *pclock = 40800; *pdivisor = 1; break; case SDHCI_TIMING_MMC_HS102: // Actual IO Freq: 99.84 MHz. *pclock = 200000; *pdivisor = 2; break; } } int clock_sdmmc_is_not_reset_and_enabled(u32 id) { return !_clock_sdmmc_is_reset(id) && _clock_sdmmc_is_enabled(id); } void clock_sdmmc_enable(u32 id, u32 val) { u32 clock = 0; if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(id); _clock_sdmmc_set_reset(id); _clock_sdmmc_config_clock_host(&clock, id, val); _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); usleep((100000 + clock - 1) / clock); _clock_sdmmc_clear_reset(id); _clock_sdmmc_is_reset(id); } void clock_sdmmc_disable(u32 id) { _clock_sdmmc_set_reset(id); _clock_sdmmc_clear_enable(id); _clock_sdmmc_is_reset(id); } ================================================ FILE: emummc/source/soc/clock.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _CLOCK_H_ #define _CLOCK_H_ #include "../utils/types.h" /*! Clock registers. */ #define CLK_RST_CONTROLLER_RST_SOURCE 0x0 #define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 #define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 #define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC #define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18 #define CLK_RST_CONTROLLER_CCLK_BURST_POLICY 0x20 #define CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER 0x24 #define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28 #define CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2C #define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 #define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 #define CLK_RST_CONTROLLER_OSC_CTRL 0x50 #define CLK_RST_CONTROLLER_PLLC_BASE 0x80 #define CLK_RST_CONTROLLER_PLLC_OUT 0x84 #define CLK_RST_CONTROLLER_PLLC_MISC 0x88 #define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C #define CLK_RST_CONTROLLER_PLLM_BASE 0x90 #define CLK_RST_CONTROLLER_PLLM_MISC1 0x98 #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 #define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 #define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 #define CLK_RST_CONTROLLER_PLLD_MISC 0xDC #define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 #define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 #define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 #define CLK_RST_CONTROLLER_PLLE_MISC 0xEC #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC #define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 #define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 #define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 0x164 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C #define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 #define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 #define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 #define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 #define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288 #define CLK_RST_CONTROLLER_RST_DEVICES_X 0x28C #define CLK_RST_CONTROLLER_RST_DEV_X_SET 0x290 #define CLK_RST_CONTROLLER_RST_DEV_X_CLR 0x294 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_Y 0x298 #define CLK_RST_CONTROLLER_CLK_ENB_Y_SET 0x29C #define CLK_RST_CONTROLLER_CLK_ENB_Y_CLR 0x2A0 #define CLK_RST_CONTROLLER_RST_DEVICES_Y 0x2A4 #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2A8 #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2AC #define CLK_RST_CONTROLLER_RST_DEV_L_SET 0x300 #define CLK_RST_CONTROLLER_RST_DEV_L_CLR 0x304 #define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308 #define CLK_RST_CONTROLLER_RST_DEV_H_CLR 0x30C #define CLK_RST_CONTROLLER_RST_DEV_U_SET 0x310 #define CLK_RST_CONTROLLER_RST_DEV_U_CLR 0x314 #define CLK_RST_CONTROLLER_CLK_ENB_L_SET 0x320 #define CLK_RST_CONTROLLER_CLK_ENB_L_CLR 0x324 #define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328 #define CLK_RST_CONTROLLER_CLK_ENB_H_CLR 0x32C #define CLK_RST_CONTROLLER_CLK_ENB_U_SET 0x330 #define CLK_RST_CONTROLLER_CLK_ENB_U_CLR 0x334 #define CLK_RST_CONTROLLER_RST_DEVICES_V 0x358 #define CLK_RST_CONTROLLER_RST_DEVICES_W 0x35C #define CLK_RST_CONTROLLER_CLK_OUT_ENB_V 0x360 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_W 0x364 #define CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2 0x388 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 #define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 #define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 #define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 #define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C #define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 #define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 #define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 #define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 #define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454 #define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488 #define CLK_RST_CONTROLLER_PLLE_AUX 0x48C #define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0 #define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 #define CLK_RST_CONTROLLER_SPARE_REG0 0x55C #define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 #define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 #define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0 #define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 #define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 #define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 #define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 #define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 #define CLK_NO_SOURCE 0x0 /*! PLL control and status bits */ #define PLLCX_BASE_ENABLE (1 << 30) #define PLLCX_BASE_REF_DIS (1 << 29) #define PLLCX_BASE_LOCK (1 << 27) #define PLLC4_MISC_EN_LCKDET (1 << 30) #define PLLC4_BASE_IDDQ (1 << 18) #define PLLC4_OUT3_CLKEN (1 << 1) #define PLLC4_OUT3_RSTN_CLR (1 << 0) /*! Generic clock descriptor. */ typedef struct _sclock_t { u32 reset; u32 enable; u32 source; u8 index; u8 clk_src; u8 clk_div; } sclock_t; /*! Generic clock enable/disable. */ void clock_enable(const sclock_t *clk); void clock_disable(const sclock_t *clk); /*! Clock control for specific hardware portions. */ void clock_enable_i2c5(); void clock_disable_i2c5(); void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val); void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type); int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_disable(u32 id); #endif ================================================ FILE: emummc/source/soc/gpio.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "../soc/gpio.h" #include "../soc/t210.h" #define GPIO_BANK_IDX(port) ((port) >> 2) #define GPIO_CNF_OFFSET(port) (0x00 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OE_OFFSET(port) (0x10 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OUT_OFFSET(port) (0x20 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_IN_OFFSET(port) (0x30 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_STA_OFFSET(port) (0x40 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_ENB_OFFSET(port) (0x50 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_LVL_OFFSET(port) (0x60 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_CLR_OFFSET(port) (0x70 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_CNF_MASKED_OFFSET(port) (0x80 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OE_MASKED_OFFSET(port) (0x90 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_OUT_MASKED_OFFSET(port) (0xA0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_STA_MASKED_OFFSET(port) (0xC0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_ENB_MASKED_OFFSET(port) (0xD0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_INT_LVL_MASKED_OFFSET(port) (0xE0 + (((port) >> 2) << 8) + (((port) % 4) << 2)) #define GPIO_IRQ_BANK1 32 #define GPIO_IRQ_BANK2 33 #define GPIO_IRQ_BANK3 34 #define GPIO_IRQ_BANK4 35 #define GPIO_IRQ_BANK5 55 #define GPIO_IRQ_BANK6 87 #define GPIO_IRQ_BANK7 89 #define GPIO_IRQ_BANK8 125 static u8 gpio_bank_irq_ids[8] = { GPIO_IRQ_BANK1, GPIO_IRQ_BANK2, GPIO_IRQ_BANK3, GPIO_IRQ_BANK4, GPIO_IRQ_BANK5, GPIO_IRQ_BANK6, GPIO_IRQ_BANK7, GPIO_IRQ_BANK8 }; void gpio_config(u32 port, u32 pins, int mode) { u32 offset = GPIO_CNF_OFFSET(port); if (mode) GPIO(offset) |= pins; else GPIO(offset) &= ~pins; (void)GPIO(offset); // Commit the write. } void gpio_output_enable(u32 port, u32 pins, int enable) { u32 port_offset = GPIO_OE_OFFSET(port); if (enable) GPIO(port_offset) |= pins; else GPIO(port_offset) &= ~pins; (void)GPIO(port_offset); // Commit the write. } void gpio_write(u32 port, u32 pins, int high) { u32 port_offset = GPIO_OUT_OFFSET(port); if (high) GPIO(port_offset) |= pins; else GPIO(port_offset) &= ~pins; (void)GPIO(port_offset); // Commit the write. } int gpio_read(u32 port, u32 pins) { u32 port_offset = GPIO_IN_OFFSET(port); return (GPIO(port_offset) & pins) ? 1 : 0; } static void _gpio_interrupt_clear(u32 port, u32 pins) { u32 port_offset = GPIO_INT_CLR_OFFSET(port); GPIO(port_offset) |= pins; (void)GPIO(port_offset); // Commit the write. } int gpio_interrupt_status(u32 port, u32 pins) { u32 port_offset = GPIO_INT_STA_OFFSET(port); u32 enabled = GPIO(GPIO_INT_ENB_OFFSET(port)) & pins; int status = ((GPIO(port_offset) & pins) && enabled) ? 1 : 0; // Clear the interrupt status. if (status) _gpio_interrupt_clear(port, pins); return status; } void gpio_interrupt_enable(u32 port, u32 pins, int enable) { u32 port_offset = GPIO_INT_ENB_OFFSET(port); // Clear any possible stray interrupt. _gpio_interrupt_clear(port, pins); if (enable) GPIO(port_offset) |= pins; else GPIO(port_offset) &= ~pins; (void)GPIO(port_offset); // Commit the write. } void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta) { u32 port_offset = GPIO_INT_LVL_OFFSET(port); u32 val = GPIO(port_offset); if (high) val |= pins; else val &= ~pins; if (edge) val |= pins << 8; else val &= ~(pins << 8); if (delta) val |= pins << 16; else val &= ~(pins << 16); GPIO(port_offset) = val; (void)GPIO(port_offset); // Commit the write. // Clear any possible stray interrupt. _gpio_interrupt_clear(port, pins); } u32 gpio_get_bank_irq_id(u32 port) { u32 bank_idx = GPIO_BANK_IDX(port); return gpio_bank_irq_ids[bank_idx]; } ================================================ FILE: emummc/source/soc/gpio.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _GPIO_H_ #define _GPIO_H_ #include "../utils/types.h" #define GPIO_MODE_SPIO 0 #define GPIO_MODE_GPIO 1 #define GPIO_OUTPUT_DISABLE 0 #define GPIO_OUTPUT_ENABLE 1 #define GPIO_IRQ_DISABLE 0 #define GPIO_IRQ_ENABLE 1 #define GPIO_LOW 0 #define GPIO_HIGH 1 #define GPIO_FALLING 0 #define GPIO_RISING 1 #define GPIO_LEVEL 0 #define GPIO_EDGE 1 #define GPIO_CONFIGURED_EDGE 0 #define GPIO_ANY_EDGE_CHANGE 1 /*! GPIO pins (0-7 for each port). */ #define GPIO_PIN_0 (1 << 0) #define GPIO_PIN_1 (1 << 1) #define GPIO_PIN_2 (1 << 2) #define GPIO_PIN_3 (1 << 3) #define GPIO_PIN_4 (1 << 4) #define GPIO_PIN_5 (1 << 5) #define GPIO_PIN_6 (1 << 6) #define GPIO_PIN_7 (1 << 7) /*! GPIO ports (A-EE). */ #define GPIO_PORT_A 0 #define GPIO_PORT_B 1 #define GPIO_PORT_C 2 #define GPIO_PORT_D 3 #define GPIO_PORT_E 4 #define GPIO_PORT_F 5 #define GPIO_PORT_G 6 #define GPIO_PORT_H 7 #define GPIO_PORT_I 8 #define GPIO_PORT_J 9 #define GPIO_PORT_K 10 #define GPIO_PORT_L 11 #define GPIO_PORT_M 12 #define GPIO_PORT_N 13 #define GPIO_PORT_O 14 #define GPIO_PORT_P 15 #define GPIO_PORT_Q 16 #define GPIO_PORT_R 17 #define GPIO_PORT_S 18 #define GPIO_PORT_T 19 #define GPIO_PORT_U 20 #define GPIO_PORT_V 21 #define GPIO_PORT_W 22 #define GPIO_PORT_X 23 #define GPIO_PORT_Y 24 #define GPIO_PORT_Z 25 #define GPIO_PORT_AA 26 #define GPIO_PORT_BB 27 #define GPIO_PORT_CC 28 #define GPIO_PORT_DD 29 #define GPIO_PORT_EE 30 void gpio_config(u32 port, u32 pins, int mode); void gpio_output_enable(u32 port, u32 pins, int enable); void gpio_write(u32 port, u32 pins, int high); int gpio_read(u32 port, u32 pins); int gpio_interrupt_status(u32 port, u32 pins); void gpio_interrupt_enable(u32 port, u32 pins, int enable); void gpio_interrupt_level(u32 port, u32 pins, int high, int edge, int delta); u32 gpio_get_bank_irq_id(u32 port); #endif ================================================ FILE: emummc/source/soc/i2c.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include "i2c.h" #include "../utils/util.h" #include "t210.h" #define I2C_PACKET_PROT_I2C (1 << 4) #define I2C_HEADER_CONT_XFER (1 << 15) #define I2C_HEADER_REP_START (1 << 16) #define I2C_HEADER_IE_ENABLE (1 << 17) #define I2C_HEADER_READ (1 << 19) #define I2C_CNFG (0x00 / 4) #define CMD1_WRITE (0 << 6) #define CMD1_READ (1 << 6) #define NORMAL_MODE_GO (1 << 9) #define PACKET_MODE_GO (1 << 10) #define NEW_MASTER_FSM (1 << 11) #define DEBOUNCE_CNT_4T (2 << 12) #define I2C_CMD_ADDR0 (0x04 / 4) #define ADDR0_WRITE 0 #define ADDR0_READ 1 #define I2C_CMD_DATA1 (0x0C / 4) #define I2C_CMD_DATA2 (0x10 / 4) #define I2C_STATUS (0x1C / 4) #define I2C_STATUS_NOACK (0xF << 0) #define I2C_STATUS_BUSY (1 << 8) #define I2C_TX_FIFO (0x50 / 4) #define I2C_RX_FIFO (0x54 / 4) #define I2C_FIFO_CONTROL (0x5C / 4) #define RX_FIFO_FLUSH (1 << 0) #define TX_FIFO_FLUSH (1 << 1) #define I2C_FIFO_STATUS (0x60 / 4) #define RX_FIFO_FULL_CNT (0xF << 0) #define TX_FIFO_EMPTY_CNT (0xF << 4) #define I2C_INT_EN (0x64 / 4) #define I2C_INT_STATUS (0x68 / 4) #define I2C_INT_SOURCE (0x70 / 4) #define RX_FIFO_DATA_REQ (1 << 0) #define TX_FIFO_DATA_REQ (1 << 1) #define ARB_LOST (1 << 2) #define NO_ACK (1 << 3) #define RX_FIFO_UNDER (1 << 4) #define TX_FIFO_OVER (1 << 5) #define ALL_PACKETS_COMPLETE (1 << 6) #define PACKET_COMPLETE (1 << 7) #define BUS_CLEAR_DONE (1 << 11) #define I2C_CLK_DIVISOR (0x6C / 4) #define I2C_BUS_CLEAR_CONFIG (0x84 / 4) #define BC_ENABLE (1 << 0) #define BC_TERMINATE (1 << 1) #define I2C_BUS_CLEAR_STATUS (0x88 / 4) #define I2C_CONFIG_LOAD (0x8C / 4) #define MSTR_CONFIG_LOAD (1 << 0) #define TIMEOUT_CONFIG_LOAD (1 << 2) static const u64 i2c_addrs[] = { 0x7000C000, // I2C_1. 0x7000C400, // I2C_2. 0x7000C500, // I2C_3. 0x7000C700, // I2C_4. 0x7000D000, // I2C_5. 0x7000D100 // I2C_6. }; static void _i2c_load_cfg_wait(vu32 *base) { base[I2C_CONFIG_LOAD] = (1 << 5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD; for (u32 i = 0; i < 20; i++) { usleep(1); if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD)) break; } } static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size) { if (size > 4) return 0; u32 tmp = 0; memcpy(&tmp, buf, size); vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000); // Set device address and send mode. base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE; base[I2C_CMD_DATA1] = tmp; //Set value. // Set size and send mode. base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE; // Load configuration. _i2c_load_cfg_wait(base); // Initiate transaction on normal mode. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; u64 timeout = get_tmr_ms() + 100; while (base[I2C_STATUS] & I2C_STATUS_BUSY) { if (get_tmr_ms() > timeout) return 0; } if (base[I2C_STATUS] & I2C_STATUS_NOACK) return 0; return 1; } static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr) { if (size > 4) return 0; vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000); // Set device address and recv mode. base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ; // Set size and recv mode. base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ; // Load configuration. _i2c_load_cfg_wait(base); // Initiate transaction on normal mode. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO; u64 timeout = get_tmr_ms() + 100; while (base[I2C_STATUS] & I2C_STATUS_BUSY) { if (get_tmr_ms() > timeout) return 0; } if (base[I2C_STATUS] & I2C_STATUS_NOACK) return 0; u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. if (size > 4) { memcpy(buf, &tmp, 4); tmp = base[I2C_CMD_DATA2]; // Get MS value. memcpy(buf + 4, &tmp, size - 4); } else memcpy(buf, &tmp, size); return 1; } void i2c_init() { vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000); base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2. base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE; // Load configuration. _i2c_load_cfg_wait(base); for (u32 i = 0; i < 10; i++) { if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE) break; } (vu32)base[I2C_BUS_CLEAR_STATUS]; base[I2C_INT_STATUS] = base[I2C_INT_STATUS]; } int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size) { u8 tmp[4]; if (size > 3) return 0; tmp[0] = reg; memcpy(tmp + 1, buf, size); return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1); } int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg) { int res = _i2c_send_single(i2c_idx, dev_addr, (u8 *)®, 1); if (res) res = _i2c_recv_single(i2c_idx, buf, size, dev_addr); return res; } int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val) { return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1); } u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg) { u8 tmp = 0; i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg); return tmp; } ================================================ FILE: emummc/source/soc/i2c.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _I2C_H_ #define _I2C_H_ #include "../utils/types.h" #define I2C_1 0 #define I2C_2 1 #define I2C_3 2 #define I2C_4 3 #define I2C_5 4 #define I2C_6 5 void i2c_init(); int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size); int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg); int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val); u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg); #endif ================================================ FILE: emummc/source/soc/pinmux.c ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "../soc/pinmux.h" #include "../soc/t210.h" void pinmux_config_i2c(u32 idx) { PINMUX_AUX(PINMUX_AUX_X_I2C_SCL(idx)) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_X_I2C_SDA(idx)) = PINMUX_INPUT_ENABLE; } ================================================ FILE: emummc/source/soc/pinmux.h ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _PINMUX_H_ #define _PINMUX_H_ #include "../utils/types.h" /*! APB MISC registers. */ #define APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL 0x8D4 #define APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL 0x8D8 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 #define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 /*! Pinmux registers. */ #define PINMUX_AUX_SDMMC1_CLK 0x00 #define PINMUX_AUX_SDMMC1_CMD 0x04 #define PINMUX_AUX_SDMMC1_DAT3 0x08 #define PINMUX_AUX_SDMMC1_DAT2 0x0C #define PINMUX_AUX_SDMMC1_DAT1 0x10 #define PINMUX_AUX_SDMMC1_DAT0 0x14 #define PINMUX_AUX_SDMMC3_CLK 0x1C #define PINMUX_AUX_SDMMC3_CMD 0x20 #define PINMUX_AUX_SDMMC3_DAT0 0x24 #define PINMUX_AUX_SDMMC3_DAT1 0x28 #define PINMUX_AUX_SDMMC3_DAT2 0x2C #define PINMUX_AUX_SDMMC3_DAT3 0x30 #define PINMUX_AUX_DMIC3_CLK 0xB4 #define PINMUX_AUX_UART2_TX 0xF4 #define PINMUX_AUX_UART3_TX 0x104 #define PINMUX_AUX_WIFI_EN 0x1B4 #define PINMUX_AUX_WIFI_RST 0x1B8 #define PINMUX_AUX_NFC_EN 0x1D0 #define PINMUX_AUX_NFC_INT 0x1D4 #define PINMUX_AUX_LCD_BL_PWM 0x1FC #define PINMUX_AUX_LCD_BL_EN 0x200 #define PINMUX_AUX_LCD_RST 0x204 #define PINMUX_AUX_GPIO_PE6 0x248 #define PINMUX_AUX_GPIO_PH6 0x250 #define PINMUX_AUX_GPIO_PZ1 0x280 /* Only in T210B01 */ #define PINMUX_AUX_SDMMC2_DAT0 0x294 #define PINMUX_AUX_SDMMC2_DAT1 0x298 #define PINMUX_AUX_SDMMC2_DAT2 0x29C #define PINMUX_AUX_SDMMC2_DAT3 0x2A0 #define PINMUX_AUX_SDMMC2_DAT4 0x2A4 #define PINMUX_AUX_SDMMC2_DAT5 0x2A8 #define PINMUX_AUX_SDMMC2_DAT6 0x2AC #define PINMUX_AUX_SDMMC2_DAT7 0x2B0 #define PINMUX_AUX_SDMMC2_CLK 0x2B4 #define PINMUX_AUX_SDMMC2_CMD 0x2BC /*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ #define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RTS(x) (0xEC + 0x10 * (x)) #define PINMUX_AUX_UARTX_CTS(x) (0xF0 + 0x10 * (x)) /*! 0:GEN1, 1:GEN2, 2:GEN3, 3:CAM, 4:PWR */ #define PINMUX_AUX_X_I2C_SCL(x) (0xBC + 8 * (x)) #define PINMUX_AUX_X_I2C_SDA(x) (0xC0 + 8 * (x)) #define PINMUX_FUNC_MASK (3 << 0) #define PINMUX_PULL_MASK (3 << 2) #define PINMUX_PULL_NONE (0 << 2) #define PINMUX_PULL_DOWN (1 << 2) #define PINMUX_PULL_UP (2 << 2) #define PINMUX_TRISTATE (1 << 4) #define PINMUX_PARKED (1 << 5) #define PINMUX_INPUT_ENABLE (1 << 6) #define PINMUX_LOCK (1 << 7) #define PINMUX_LPDR (1 << 8) #define PINMUX_HSM (1 << 9) #define PINMUX_IO_HV (1 << 10) #define PINMUX_OPEN_DRAIN (1 << 11) #define PINMUX_SCHMT (1 << 12) #define PINMUX_DRIVE_MASK (3 << 13) #define PINMUX_DRIVE_1X (0 << 13) #define PINMUX_DRIVE_2X (1 << 13) #define PINMUX_DRIVE_3X (2 << 13) #define PINMUX_DRIVE_4X (3 << 13) void pinmux_config_i2c(u32 idx); #endif ================================================ FILE: emummc/source/soc/pmc.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 st4rk * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _PMC_H_ #define _PMC_H_ /*! PMC registers. */ #define APBDEV_PMC_CNTRL 0x0 #define PMC_CNTRL_MAIN_RST (1 << 4) #define APBDEV_PMC_SEC_DISABLE 0x4 #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #define APBDEV_PMC_NO_IOPOWER 0x44 #define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) #define APBDEV_PMC_SCRATCH0 0x50 #define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 #define APBDEV_PMC_PWR_DET_VAL 0xE4 #define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12) #define APBDEV_PMC_DDR_PWR 0xE8 #define APBDEV_PMC_CRYPTO_OP 0xF4 #define PMC_CRYPTO_OP_SE_ENABLE 0 #define PMC_CRYPTO_OP_SE_DISABLE 1 #define APBDEV_PMC_SCRATCH33 0x120 #define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 #define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 #define APBDEV_PMC_RST_STATUS 0x1B4 #define APBDEV_PMC_IO_DPD_REQ 0x1B8 #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 #define APBDEV_PMC_VDDP_SEL 0x1CC #define APBDEV_PMC_DDR_CFG 0x1D0 #define APBDEV_PMC_SCRATCH45 0x234 #define APBDEV_PMC_SCRATCH46 0x238 #define APBDEV_PMC_SCRATCH49 0x244 #define APBDEV_PMC_TSC_MULT 0x2B4 #define APBDEV_PMC_SEC_DISABLE2 0x2C4 #define APBDEV_PMC_WEAK_BIAS 0x2C8 #define APBDEV_PMC_REG_SHORT 0x2CC #define APBDEV_PMC_SEC_DISABLE3 0x2D8 #define APBDEV_PMC_SECURE_SCRATCH21 0x334 #define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 #define APBDEV_PMC_SECURE_SCRATCH32 0x360 #define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 #define APBDEV_PMC_CNTRL2 0x440 #define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 #define APBDEV_PMC_IO_DPD3_REQ 0x45C #define APBDEV_PMC_IO_DPD4_REQ 0x464 #define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 #define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC #define APBDEV_PMC_DDR_CNTRL 0x4E4 #define APBDEV_PMC_SEC_DISABLE4 0x5B0 #define APBDEV_PMC_SEC_DISABLE5 0x5B4 #define APBDEV_PMC_SEC_DISABLE6 0x5B8 #define APBDEV_PMC_SEC_DISABLE7 0x5BC #define APBDEV_PMC_SEC_DISABLE8 0x5C0 #define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH200 0x840 #endif ================================================ FILE: emummc/source/soc/pmc_lp0_t210.h ================================================ /* * Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #ifndef _TEGRA210_PMC_H_ #define _TEGRA210_PMC_H_ #include "../utils/types.h" struct tegra_pmc_regs { u32 cntrl; u32 sec_disable; u32 pmc_swrst; u32 wake_mask; u32 wake_lvl; u32 wake_status; u32 sw_wake_status; u32 dpd_pads_oride; u32 dpd_sample; u32 dpd_enable; u32 pwrgate_timer_off; u32 clamp_status; u32 pwrgate_toggle; u32 remove_clamping_cmd; u32 pwrgate_status; u32 pwrgood_timer; u32 blink_timer; u32 no_iopower; u32 pwr_det; u32 pwr_det_latch; u32 scratch0; u32 scratch1; u32 scratch2; u32 scratch3; u32 scratch4; u32 scratch5; u32 scratch6; u32 scratch7; u32 scratch8; u32 scratch9; u32 scratch10; u32 scratch11; u32 scratch12; u32 scratch13; u32 scratch14; u32 scratch15; u32 scratch16; u32 scratch17; u32 scratch18; u32 scratch19; u32 odmdata; u32 scratch21; u32 scratch22; u32 scratch23; u32 secure_scratch0; u32 secure_scratch1; u32 secure_scratch2; u32 secure_scratch3; u32 secure_scratch4; u32 secure_scratch5; u32 cpupwrgood_timer; u32 cpupwroff_timer; u32 pg_mask; u32 pg_mask_1; u32 auto_wake_lvl; u32 auto_wake_lvl_mask; u32 wake_delay; u32 pwr_det_val; u32 ddr_pwr; u32 usb_debounce_del; u32 usb_a0; u32 crypto_op; u32 pllp_wb0_override; u32 scratch24; u32 scratch25; u32 scratch26; u32 scratch27; u32 scratch28; u32 scratch29; u32 scratch30; u32 scratch31; u32 scratch32; u32 scratch33; u32 scratch34; u32 scratch35; u32 scratch36; u32 scratch37; u32 scratch38; u32 scratch39; u32 scratch40; u32 scratch41; u32 scratch42; u32 bondout_mirror[3]; u32 sys_33v_en; u32 bondout_mirror_access; u32 gate; u32 wake2_mask; u32 wake2_lvl; u32 wake2_status; u32 sw_wake2_status; u32 auto_wake2_lvl_mask; u32 pg_mask_2; u32 pg_mask_ce1; u32 pg_mask_ce2; u32 pg_mask_ce3; u32 pwrgate_timer_ce[7]; u32 pcx_edpd_cntrl; u32 osc_edpd_over; u32 clk_out_cntrl; u32 sata_pwrgt; u32 sensor_ctrl; u32 rst_status; u32 io_dpd_req; u32 io_dpd_status; u32 io_dpd2_req; u32 io_dpd2_status; u32 sel_dpd_tim; u32 vddp_sel; u32 ddr_cfg; u32 e_no_vttgen; u8 _rsv0[4]; u32 pllm_wb0_override_freq; u32 test_pwrgate; u32 pwrgate_timer_mult; u32 dis_sel_dpd; u32 utmip_uhsic_triggers; u32 utmip_uhsic_saved_state; u32 utmip_pad_cfg; u32 utmip_term_pad_cfg; u32 utmip_uhsic_sleep_cfg; u32 utmip_uhsic_sleepwalk_cfg; u32 utmip_sleepwalk_p[3]; u32 uhsic_sleepwalk_p0; u32 utmip_uhsic_status; u32 utmip_uhsic_fake; u32 bondout_mirror3[5 - 3]; u32 secure_scratch6; u32 secure_scratch7; u32 scratch43; u32 scratch44; u32 scratch45; u32 scratch46; u32 scratch47; u32 scratch48; u32 scratch49; u32 scratch50; u32 scratch51; u32 scratch52; u32 scratch53; u32 scratch54; u32 scratch55; u32 scratch0_eco; u32 por_dpd_ctrl; u32 scratch2_eco; u32 utmip_uhsic_line_wakeup; u32 utmip_bias_master_cntrl; u32 utmip_master_config; u32 td_pwrgate_inter_part_timer; u32 utmip_uhsic2_triggers; u32 utmip_uhsic2_saved_state; u32 utmip_uhsic2_sleep_cfg; u32 utmip_uhsic2_sleepwalk_cfg; u32 uhsic2_sleepwalk_p1; u32 utmip_uhsic2_status; u32 utmip_uhsic2_fake; u32 utmip_uhsic2_line_wakeup; u32 utmip_master2_config; u32 utmip_uhsic_rpd_cfg; u32 pg_mask_ce0; u32 pg_mask3[5 - 3]; u32 pllm_wb0_override2; u32 tsc_mult; u32 cpu_vsense_override; u32 glb_amap_cfg; u32 sticky_bits; u32 sec_disable2; u32 weak_bias; u32 reg_short; u32 pg_mask_andor; u8 _rsv1[0x2c]; u32 secure_scratch8; /* offset 0x300 */ u32 secure_scratch9; u32 secure_scratch10; u32 secure_scratch11; u32 secure_scratch12; u32 secure_scratch13; u32 secure_scratch14; u32 secure_scratch15; u32 secure_scratch16; u32 secure_scratch17; u32 secure_scratch18; u32 secure_scratch19; u32 secure_scratch20; u32 secure_scratch21; u32 secure_scratch22; u32 secure_scratch23; u32 secure_scratch24; u32 secure_scratch25; u32 secure_scratch26; u32 secure_scratch27; u32 secure_scratch28; u32 secure_scratch29; u32 secure_scratch30; u32 secure_scratch31; u32 secure_scratch32; u32 secure_scratch33; u32 secure_scratch34; u32 secure_scratch35; u32 secure_scratch36; u32 secure_scratch37; u32 secure_scratch38; u32 secure_scratch39; u32 secure_scratch40; u32 secure_scratch41; u32 secure_scratch42; u32 secure_scratch43; u32 secure_scratch44; u32 secure_scratch45; u32 secure_scratch46; u32 secure_scratch47; u32 secure_scratch48; u32 secure_scratch49; u32 secure_scratch50; u32 secure_scratch51; u32 secure_scratch52; u32 secure_scratch53; u32 secure_scratch54; u32 secure_scratch55; u32 secure_scratch56; u32 secure_scratch57; u32 secure_scratch58; u32 secure_scratch59; u32 secure_scratch60; u32 secure_scratch61; u32 secure_scratch62; u32 secure_scratch63; u32 secure_scratch64; u32 secure_scratch65; u32 secure_scratch66; u32 secure_scratch67; u32 secure_scratch68; u32 secure_scratch69; u32 secure_scratch70; u32 secure_scratch71; u32 secure_scratch72; u32 secure_scratch73; u32 secure_scratch74; u32 secure_scratch75; u32 secure_scratch76; u32 secure_scratch77; u32 secure_scratch78; u32 secure_scratch79; u32 _rsv0x420[8]; u32 cntrl2; /* 0x440 */ u32 _rsv0x444[2]; u32 event_counter; /* 0x44C */ u32 fuse_control; u32 scratch1_eco; u32 _rsv0x458[1]; u32 io_dpd3_req; /* 0x45C */ u32 io_dpd3_status; u32 io_dpd4_req; u32 io_dpd4_status; u32 _rsv0x46C[30]; u32 ddr_cntrl; /* 0x4E4 */ u32 _rsv0x4E8[70]; u32 scratch56; /* 0x600 */ u32 scratch57; u32 scratch58; u32 scratch59; u32 scratch60; u32 scratch61; u32 scratch62; u32 scratch63; u32 scratch64; u32 scratch65; u32 scratch66; u32 scratch67; u32 scratch68; u32 scratch69; u32 scratch70; u32 scratch71; u32 scratch72; u32 scratch73; u32 scratch74; u32 scratch75; u32 scratch76; u32 scratch77; u32 scratch78; u32 scratch79; u32 scratch80; u32 scratch81; u32 scratch82; u32 scratch83; u32 scratch84; u32 scratch85; u32 scratch86; u32 scratch87; u32 scratch88; u32 scratch89; u32 scratch90; u32 scratch91; u32 scratch92; u32 scratch93; u32 scratch94; u32 scratch95; u32 scratch96; u32 scratch97; u32 scratch98; u32 scratch99; u32 scratch100; u32 scratch101; u32 scratch102; u32 scratch103; u32 scratch104; u32 scratch105; u32 scratch106; u32 scratch107; u32 scratch108; u32 scratch109; u32 scratch110; u32 scratch111; u32 scratch112; u32 scratch113; u32 scratch114; u32 scratch115; u32 scratch116; u32 scratch117; u32 scratch118; u32 scratch119; u32 scratch120; /* 0x700 */ u32 scratch121; u32 scratch122; u32 scratch123; u32 scratch124; u32 scratch125; u32 scratch126; u32 scratch127; u32 scratch128; u32 scratch129; u32 scratch130; u32 scratch131; u32 scratch132; u32 scratch133; u32 scratch134; u32 scratch135; u32 scratch136; u32 scratch137; u32 scratch138; u32 scratch139; u32 scratch140; u32 scratch141; u32 scratch142; u32 scratch143; u32 scratch144; u32 scratch145; u32 scratch146; u32 scratch147; u32 scratch148; u32 scratch149; u32 scratch150; u32 scratch151; u32 scratch152; u32 scratch153; u32 scratch154; u32 scratch155; u32 scratch156; u32 scratch157; u32 scratch158; u32 scratch159; u32 scratch160; u32 scratch161; u32 scratch162; u32 scratch163; u32 scratch164; u32 scratch165; u32 scratch166; u32 scratch167; u32 scratch168; u32 scratch169; u32 scratch170; u32 scratch171; u32 scratch172; u32 scratch173; u32 scratch174; u32 scratch175; u32 scratch176; u32 scratch177; u32 scratch178; u32 scratch179; u32 scratch180; u32 scratch181; u32 scratch182; u32 scratch183; u32 scratch184; u32 scratch185; u32 scratch186; u32 scratch187; u32 scratch188; u32 scratch189; u32 scratch190; u32 scratch191; u32 scratch192; u32 scratch193; u32 scratch194; u32 scratch195; u32 scratch196; u32 scratch197; u32 scratch198; u32 scratch199; u32 scratch200; u32 scratch201; u32 scratch202; u32 scratch203; u32 scratch204; u32 scratch205; u32 scratch206; u32 scratch207; u32 scratch208; u32 scratch209; u32 scratch210; u32 scratch211; u32 scratch212; u32 scratch213; u32 scratch214; u32 scratch215; u32 scratch216; u32 scratch217; u32 scratch218; u32 scratch219; u32 scratch220; u32 scratch221; u32 scratch222; u32 scratch223; u32 scratch224; u32 scratch225; u32 scratch226; u32 scratch227; u32 scratch228; u32 scratch229; u32 scratch230; u32 scratch231; u32 scratch232; u32 scratch233; u32 scratch234; u32 scratch235; u32 scratch236; u32 scratch237; u32 scratch238; u32 scratch239; u32 scratch240; u32 scratch241; u32 scratch242; u32 scratch243; u32 scratch244; u32 scratch245; u32 scratch246; u32 scratch247; u32 scratch248; u32 scratch249; u32 scratch250; u32 scratch251; u32 scratch252; u32 scratch253; u32 scratch254; u32 scratch255; u32 scratch256; u32 scratch257; u32 scratch258; u32 scratch259; u32 scratch260; u32 scratch261; u32 scratch262; u32 scratch263; u32 scratch264; u32 scratch265; u32 scratch266; u32 scratch267; u32 scratch268; u32 scratch269; u32 scratch270; u32 scratch271; u32 scratch272; u32 scratch273; u32 scratch274; u32 scratch275; u32 scratch276; u32 scratch277; u32 scratch278; u32 scratch279; u32 scratch280; u32 scratch281; u32 scratch282; u32 scratch283; u32 scratch284; u32 scratch285; u32 scratch286; u32 scratch287; u32 scratch288; u32 scratch289; u32 scratch290; u32 scratch291; u32 scratch292; u32 scratch293; u32 scratch294; u32 scratch295; u32 scratch296; u32 scratch297; u32 scratch298; u32 scratch299; /* 0x9CC */ u32 _rsv0x9D0[50]; u32 secure_scratch80; /* 0xa98 */ u32 secure_scratch81; u32 secure_scratch82; u32 secure_scratch83; u32 secure_scratch84; u32 secure_scratch85; u32 secure_scratch86; u32 secure_scratch87; u32 secure_scratch88; u32 secure_scratch89; u32 secure_scratch90; u32 secure_scratch91; u32 secure_scratch92; u32 secure_scratch93; u32 secure_scratch94; u32 secure_scratch95; u32 secure_scratch96; u32 secure_scratch97; u32 secure_scratch98; u32 secure_scratch99; u32 secure_scratch100; u32 secure_scratch101; u32 secure_scratch102; u32 secure_scratch103; u32 secure_scratch104; u32 secure_scratch105; u32 secure_scratch106; u32 secure_scratch107; u32 secure_scratch108; u32 secure_scratch109; u32 secure_scratch110; u32 secure_scratch111; u32 secure_scratch112; u32 secure_scratch113; u32 secure_scratch114; u32 secure_scratch115; u32 secure_scratch116; u32 secure_scratch117; u32 secure_scratch118; u32 secure_scratch119; }; #endif /* _TEGRA210_PMC_H_ */ ================================================ FILE: emummc/source/soc/t210.h ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _T210_H_ #define _T210_H_ #include "../utils/types.h" intptr_t QueryIoMapping(u64 addr, u64 size); #define TMR_BASE 0x60005000 #define CLOCK_BASE 0x60006000 #define GPIO_BASE 0x6000D000 #define GPIO_1_BASE (GPIO_BASE) #define GPIO_2_BASE (GPIO_BASE + 0x100) #define GPIO_3_BASE (GPIO_BASE + 0x200) #define GPIO_4_BASE (GPIO_BASE + 0x300) #define GPIO_5_BASE (GPIO_BASE + 0x400) #define GPIO_6_BASE (GPIO_BASE + 0x500) #define GPIO_7_BASE (GPIO_BASE + 0x600) #define GPIO_8_BASE (GPIO_BASE + 0x700) #define APB_MISC_BASE 0x70000000 #define PINMUX_AUX_BASE 0x70003000 #define PWM_BASE 0x7000A000 #define RTC_BASE 0x7000E000 #define PMC_BASE 0x7000E400 #define _REG(base, off) *(vu32 *)(QueryIoMapping((u64)base, 0) + (off)) #define _REG_IO(base, off, size) *(vu32 *)(QueryIoMapping((u64)base, size) + (off)) #define RTC(off) _REG_IO(RTC_BASE, off, 0x4000) #define TMR(off) _REG_IO(TMR_BASE, off, 0x3FF) #define CLOCK(off) _REG_IO(CLOCK_BASE, off, 0x1000) #define PMC(off) _REG_IO(PMC_BASE, off, 0x1000) // ?????????? #define APB_MISC(off) _REG_IO(APB_MISC_BASE, off, 0x4000) #define PINMUX_AUX(off) _REG_IO(APB_MISC_BASE, off + (PINMUX_AUX_BASE - APB_MISC_BASE), 0x4000) #define GPIO(off) _REG_IO(GPIO_BASE, off, 0x1000) #define GPIO_1(off) _REG_IO(GPIO_BASE, off + (GPIO_1_BASE - GPIO_BASE), 0x1000) #define GPIO_2(off) _REG_IO(GPIO_BASE, off + (GPIO_2_BASE - GPIO_BASE), 0x1000) #define GPIO_3(off) _REG_IO(GPIO_BASE, off + (GPIO_3_BASE - GPIO_BASE), 0x1000) #define GPIO_4(off) _REG_IO(GPIO_BASE, off + (GPIO_4_BASE - GPIO_BASE), 0x1000) #define GPIO_5(off) _REG_IO(GPIO_BASE, off + (GPIO_5_BASE - GPIO_BASE), 0x1000) #define GPIO_6(off) _REG_IO(GPIO_BASE, off + (GPIO_6_BASE - GPIO_BASE), 0x1000) #define GPIO_7(off) _REG_IO(GPIO_BASE, off + (GPIO_7_BASE - GPIO_BASE), 0x1000) #define GPIO_8(off) _REG_IO(GPIO_BASE, off + (GPIO_8_BASE - GPIO_BASE), 0x1000) #define HOST1X(off) _REG(HOST1X_BASE, off) #define BPMP_CACHE_CTRL(off) _REG(BPMP_CACHE_BASE, off) #define DISPLAY_A(off) _REG(DISPLAY_A_BASE, off) #define DSI(off) _REG(DSI_BASE, off) #define VIC(off) _REG(VIC_BASE, off) #define TSEC(off) _REG(TSEC_BASE, off) #define SOR1(off) _REG(SOR1_BASE, off) #define FLOW_CTLR(off) _REG(FLOW_CTLR_BASE, off) #define SYSREG(off) _REG(SYSREG_BASE, off) #define SB(off) _REG(SB_BASE, off) #define EXCP_VEC(off) _REG(EXCP_VEC_BASE, off) #define PWM(off) _REG(PWM_BASE, off) #define SYSCTR0(off) _REG(SYSCTR0_BASE, off) #define FUSE(off) _REG(FUSE_BASE, off) #define KFUSE(off) _REG(KFUSE_BASE, off) #define SE(off) _REG(SE_BASE, off) #define MC(off) _REG(MC_BASE, off) #define EMC(off) _REG(EMC_BASE, off) #define MIPI_CAL(off) _REG(MIPI_CAL_BASE, off) #define I2S(off) _REG(I2S_BASE, off) #define CL_DVFS(off) _REG(CL_DVFS_BASE, off) #define TEST_REG(off) _REG(0x0, off) /*! Misc registers. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_PINMUX_GLOBAL 0x40 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 #define APB_MISC_GP_EMMC2_PAD_CFGPADCTRL 0xA9C #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 #define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 /*! System registers. */ #define AHB_ARBITRATION_XBAR_CTRL 0xE0 #define AHB_AHB_SPARE_REG 0x110 /*! RTC registers. */ #define APBDEV_RTC_SECONDS 0x8 #define APBDEV_RTC_SHADOW_SECONDS 0xC #define APBDEV_RTC_MILLI_SECONDS 0x10 /*! TMR registers. */ #define TIMERUS_CNTR_1US (0x10 + 0x0) #define TIMERUS_USEC_CFG (0x10 + 0x4) #define TIMER_TMR9_TMR_PTV 0x80 #define TIMER_EN (1 << 31) #define TIMER_PER_EN (1 << 30) #define TIMER_WDT4_CONFIG (0x100 + 0x80) #define TIMER_SRC(TMR) (TMR & 0xF) #define TIMER_PER(PER) ((PER & 0xFF) << 4) #define TIMER_SYSRESET_EN (1 << 14) #define TIMER_PMCRESET_EN (1 << 15) #define TIMER_WDT4_COMMAND (0x108 + 0x80) #define TIMER_START_CNT (1 << 0) #define TIMER_CNT_DISABLE (1 << 1) #define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80) #define TIMER_MAGIC_PTRN 0xC45A #endif ================================================ FILE: emummc/source/utils/fatal.c ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include "fatal.h" void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason) { atmosphere_fatal_error_ctx error_ctx; memset(&error_ctx, 0, sizeof(atmosphere_fatal_error_ctx)); // Basic error storage for Atmosphere // TODO: Maybe include a small reboot2payload stub? error_ctx.magic = ATMOSPHERE_REBOOT_TO_FATAL_MAGIC; error_ctx.title_id = 0x0100000000000000; // FS error_ctx.error_desc = abortReason; // Copy fatal context smcCopyToIram(ATMOSPHERE_FATAL_ERROR_ADDR, &error_ctx, sizeof(atmosphere_fatal_error_ctx)); // Reboot to RCM smcRebootToRcm(); while (true) ; // Should never be reached } ================================================ FILE: emummc/source/utils/fatal.h ================================================ /* * Copyright (c) 2019 m4xw <m4x@m4xw.net> * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include "../nx/smc.h" enum FatalReason { Fatal_InitMMC = 0, Fatal_InitSD, Fatal_InvalidAccessor, Fatal_ReadNoAccessor, Fatal_WriteNoAccessor, Fatal_IoMappingLegacy, Fatal_UnknownVersion, Fatal_BadResult, Fatal_GetConfig, Fatal_OpenAccessor, Fatal_CloseAccessor, Fatal_IoMapping, Fatal_FatfsMount, Fatal_FatfsFileOpen, Fatal_FatfsMemExhaustion, Fatal_InvalidEnum, Fatal_Max }; #define AMS_FATAL_ERROR_MAX_STACKTRACE 0x20 #define AMS_FATAL_ERROR_MAX_STACKDUMP 0x100 /* Atmosphere reboot-to-fatal-error. */ typedef struct { uint32_t magic; uint32_t error_desc; uint64_t title_id; union { uint64_t gprs[32]; struct { uint64_t _gprs[29]; uint64_t fp; uint64_t lr; uint64_t sp; }; }; uint64_t pc; uint64_t module_base; uint32_t pstate; uint32_t afsr0; uint32_t afsr1; uint32_t esr; uint64_t far; uint64_t report_identifier; /* Normally just system tick. */ uint64_t stack_trace_size; uint64_t stack_dump_size; uint64_t stack_trace[AMS_FATAL_ERROR_MAX_STACKTRACE]; uint8_t stack_dump[AMS_FATAL_ERROR_MAX_STACKDUMP]; } atmosphere_fatal_error_ctx; /* "AFE1" */ #define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC 0x31454641 /* "AFE0" */ #define ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0 0x30454641 #define ATMOSPHERE_FATAL_ERROR_ADDR 0x4003E000 #define ATMOSPHERE_FATAL_ERROR_CONTEXT ((volatile atmosphere_fatal_error_ctx *)(ATMOSPHERE_FATAL_ERROR_ADDR)) void __attribute__((noreturn)) fatal_abort(enum FatalReason abortReason); ================================================ FILE: emummc/source/utils/types.h ================================================ /* * Copyright (c) 2018 naehrwert * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _TYPES_H_ #define _TYPES_H_ #include <stdint.h> #include <stdbool.h> #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m) #define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn))) /// Creates a bitmask from a bit number. #ifndef BIT #define BIT(n) (1U<<(n)) #endif typedef int8_t s8; typedef int16_t s16; typedef int16_t SHORT; typedef int32_t s32; typedef int32_t INT; typedef int64_t LONG; typedef int64_t s64; typedef uint8_t u8; typedef uint8_t BYTE; typedef uint16_t u16; typedef uint16_t WORD; typedef uint16_t WCHAR; typedef uint32_t u32; typedef uint32_t UINT; typedef uint32_t DWORD; typedef uint64_t QWORD; typedef uint64_t u64; typedef volatile uint8_t vu8; typedef volatile uint16_t vu16; typedef volatile uint32_t vu32; typedef u32 Handle; ///< Kernel object handle. typedef u32 Result; ///< Function error code result type. #define INVALID_HANDLE ((Handle) 0) #define CUR_PROCESS_HANDLE ((Handle) 0xFFFF8001) #define BOOT_CFG_AUTOBOOT_EN (1 << 0) #define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_SEPT_RUN (1 << 7) #define EXTRA_CFG_KEYS (1 << 0) #define EXTRA_CFG_PAYLOAD (1 << 1) #define EXTRA_CFG_MODULE (1 << 2) typedef struct __attribute__((__packed__)) _boot_cfg_t { u8 boot_cfg; u8 autoboot; u8 autoboot_list; u8 extra_cfg; u8 rsvd[128]; } boot_cfg_t; typedef struct __attribute__((__packed__)) _ipl_ver_meta_t { u32 magic; u32 version; u16 rsvd0; u16 rsvd1; } ipl_ver_meta_t; typedef struct __attribute__((__packed__)) _reloc_meta_t { u32 start; u32 stack; u32 end; u32 ep; } reloc_meta_t; #endif ================================================ FILE: emummc/source/utils/util.c ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018 CTCaer * Copyright (C) 2019 M4xw * Copyright (c) 2019 Atmosphere-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "util.h" #include "fatal.h" #include "types.h" #include "../nx/counter.h" #include "../nx/svc.h" #include "../soc/t210.h" typedef struct _io_mapping_t { u64 phys; u64 virt; u64 size; } io_mapping_t; static io_mapping_t io_mapping_list[10] = {0}; // Max 10 Mappings #define IO_MAPPING_COUNT (sizeof(io_mapping_list) / sizeof(io_mapping_t)) static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size) { u64 vaddr; u64 aligned_addr = (io_addr & ~0xFFFul); u64 aligned_size = io_size + (io_addr - aligned_addr); if (emuMMC_ctx.fs_ver >= FS_VER_10_0_0) { u64 out_size; if (svcQueryIoMapping(&vaddr, &out_size, aligned_addr, aligned_size) != 0) { fatal_abort(Fatal_IoMapping); } } else { if (svcLegacyQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) { fatal_abort(Fatal_IoMappingLegacy); } } return (uintptr_t)(vaddr + (io_addr - aligned_addr)); } intptr_t QueryIoMapping(u64 addr, u64 size) { for (int i = 0; i < IO_MAPPING_COUNT; i++) { if (io_mapping_list[i].phys == addr && io_mapping_list[i].size == size) { return io_mapping_list[i].virt; } } u64 ioMap = _GetIoMapping(addr, size); for (int i = 0; i < IO_MAPPING_COUNT; i++) { if (io_mapping_list[i].phys == 0 && io_mapping_list[i].virt == 0 && io_mapping_list[i].size == 0) // First empty { io_mapping_list[i].virt = ioMap; io_mapping_list[i].phys = addr; io_mapping_list[i].size = size; break; } } return (intptr_t)ioMap; } u64 get_tmr_s() { return armTicksToNs(armGetSystemTick()) / 1e+9; } u64 get_tmr_ms() { return armTicksToNs(armGetSystemTick()) / 1000000; } u64 get_tmr_us() { return armTicksToNs(armGetSystemTick()) / 1000; } // TODO: Figure if Sleep or Busy loop void msleep(u64 milliseconds) { u64 now = get_tmr_ms(); while (((u64)get_tmr_ms() - now) < milliseconds) ; //svcSleepThread(1000000 * milliseconds); } // TODO: Figure if Sleep or Busy loop void usleep(u64 microseconds) { u64 now = get_tmr_us(); while (((u64)get_tmr_us() - now) < microseconds) ; //svcSleepThread(1000 * microseconds); } void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) { for (u32 i = 0; i < num_ops; i++) base[ops[i].off] = ops[i].val; } ================================================ FILE: emummc/source/utils/util.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _UTIL_H_ #define _UTIL_H_ #include "types.h" #include "../emuMMC/emummc_ctx.h" intptr_t QueryIoMapping(u64 addr, u64 size); #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) typedef struct _cfg_op_t { u32 off; u32 val; } cfg_op_t; u64 get_tmr_us(); u64 get_tmr_ms(); u64 get_tmr_s(); void usleep(u64 ticks); void msleep(u64 milliseconds); void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops); static inline void *armGetTls(void) { void *ret; __asm__ __volatile__("MRS %x[data], TPIDRRO_EL0" : [data]"=r"(ret)); return ret; } extern volatile emuMMC_ctx_t emuMMC_ctx; #endif ================================================ FILE: emummc/tools/fs_ida_nintendo_folder_xref_formatter.au3 ================================================ ParseClipboard() Func FormatLineData($sLineData, $sLineDataAdd) Local $lineData = StringReplace($sLineData, @TAB, " ") Local $lineDataADRP, $lineDataADD Local $isADRP = false $lineData = StringReplace($lineData, "Up o sub_71000" , "0x") $isADRP = StringInStr($lineData, "ADRP") Local $targetRegister = StringSplit(StringSplit($lineData, "X")[2], ",")[1] $lineData = StringSplit($lineData, " ")[1] $lineDataAddr = StringSplit($lineData, "+")[1] $lineDataAddition = StringSplit($lineData, "+")[2] $lineDataAddr = StringReplace($lineDataAddr, "0x" , "") $lineDataAddition = StringReplace($lineDataAddition, "0x" , "") $addrADRP = Dec($lineDataAddr) + Dec($lineDataAddition) $lineDataADRP = "0x" & Hex($addrADRP) Local $lineDataADD = StringReplace($sLineDataAdd, @TAB, " ") Local $isADD = false $lineDataADD = StringReplace($lineDataADD, "Up o sub_71000" , "0x") $isADD = StringInStr($lineData, "ADD") $lineDataADD = StringSplit($lineDataADD, " ")[1] $lineDataAddAddr = StringSplit($lineDataADD, "+")[1] $lineDataAddAddition = StringSplit($lineDataADD, "+")[2] $lineDataAddAddr = StringReplace($lineDataAddAddr, "0x" , "") $lineDataAddAddition = StringReplace($lineDataAddAddition, "0x" , "") $addrADD = Dec($lineDataAddAddr) + Dec($lineDataAddAddition) $addrADD = $addrADD - $addrADRP $lineDataADD = "0x" & Hex($addrADD) Return @TAB & "{.opcode_reg = " & $targetRegister & ", .adrp_offset = " & $lineDataADRP & ", .add_rel_offset = " & $lineDataADD & "}, \" & @LF EndFunc Func ParseClipboard() Local $sData = ClipGet() Local $oData = "" Local $sLineData = StringSplit(StringReplace($sData, @CRLF, @LF), @LF) For $i = 2 to UBound($sLineData) - 2 Step 2 Local $lineData = FormatLineData($sLineData[$i], $sLineData[$i+1]) ;ConsoleWrite($lineData) $oData = $oData & $lineData Next $oData = "{ \" & @LF & $oData & @TAB & "{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \" & @LF & "}" & @LF ;ConsoleWrite($oData) ClipPut($oData) EndFunc ================================================ FILE: emummc/tools/kip1converter.py ================================================ # Modified kip1 conversion script, originally by jakibaki # Used for dev purposes, will be replaced in the future from struct import pack, unpack from sys import argv f = open(argv[1], "rb") header_start = f.read(0x20) section_names = [".text", ".rodata", ".data", ".bss"] sections = [] for i in range(6): section_bytes = f.read(0x10) section = {} if i < len(section_names): section["Name"] = section_names[i] section["OutOffset"], section["DecompressedSize"], section["CompressedSize"], section["Attribute"] = unpack("IIII", section_bytes) sections.append(section) print(section) assert (sections[3]["OutOffset"] + sections[3]["DecompressedSize"]) % 0x1000 == 0 kernel_caps = [] for i in range(0x20): val, = unpack("I", f.read(4)) kernel_caps.append(val) f.seek(0x100) for i in range(3): section = sections[i] section["Buffer"] = f.read(section["DecompressedSize"]) print(f.read()) f.close() f = open(argv[2], "wb") for i in range(3): section = sections[i] f.seek(section["OutOffset"]) f.write(section["Buffer"]) f.seek(sections[3]["OutOffset"]) f.write(b'\0' * sections[3]["DecompressedSize"]) caps = open("emummc.caps", "wb") for i in range(0x20): caps.write(pack("I", kernel_caps[i])) ================================================ FILE: exosphere/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/exosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/exosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/exosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../libraries/config/common.mk all: $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin $(CURRENT_DIRECTORY)/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.bin $(CURRENT_DIRECTORY)/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin: $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) @cp $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin @printf LENY >> $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/exosphere.bin @echo "Built exosphere.bin..." $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin: check_loader_stub @$(SILENTCMD)echo "Checked loader stub." $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_program @$(SILENTCMD)echo "Checked program." $(CURRENT_DIRECTORY)/warmboot/$(ATMOSPHERE_BOOT_OUT_DIR)/warmboot.bin: check_warmboot @$(SILENTCMD)echo "Checked warmboot." $(CURRENT_DIRECTORY)/mariko_fatal/$(ATMOSPHERE_OUT_DIR)/mariko_fatal.bin: check_mariko_fatal @$(SILENTCMD)echo "Checked mariko fatal." $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a: check_boot_lib @$(SILENTCMD)echo "Checked boot library." endif check_loader_stub: $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.lz4 @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_EXOSPHERE_PROGRAM=1 check_program: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 check_mariko_fatal: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mariko_fatal -f $(CURRENT_DIRECTORY)/mariko_fatal/mariko_fatal.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 check_warmboot: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/warmboot -f $(CURRENT_DIRECTORY)/warmboot/warmboot.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif ifeq ($(ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE),1) check_boot_lib: else check_boot_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" endif $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR): @[ -d $@ ] || mkdir -p $@ clean: @echo clean ... @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk clean @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk clean @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/mariko_fatal -f $(CURRENT_DIRECTORY)/mariko_fatal/mariko_fatal.mk clean @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/warmboot -f $(CURRENT_DIRECTORY)/warmboot/warmboot.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" @rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) @for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done .PHONY: all clean check_lib check_boot_lib check_loader_stub check_program check_mariko_fatal check_warmboot ================================================ FILE: exosphere/loader_stub/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/loader_stub/loader_stub.ld ================================================ OUTPUT_ARCH(aarch64) ENTRY(_start) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K ldr_stub : ORIGIN = 0x040030000, LENGTH = 128K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = 0x040030000); . = __start__; __code_start = . ; .crt0 : { KEEP (*(.crt0 .crt0.*)) . = ALIGN(8); } >ldr_stub .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >ldr_stub .init : { KEEP( *(.init) ) . = ALIGN(8); } >ldr_stub .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >ldr_stub .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >ldr_stub /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >ldr_stub .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >ldr_stub .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ldr_stub .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >ldr_stub .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >ldr_stub .hash : { *(.hash) } >ldr_stub /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >ldr_stub .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >ldr_stub .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >ldr_stub .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >ldr_stub .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >ldr_stub .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >ldr_stub .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >ldr_stub .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >ldr_stub .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >ldr_stub __got_start__ = .; .got : { *(.got) *(.igot) } >ldr_stub .got.plt : { *(.got.plt) *(.igot.plt) } >ldr_stub __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >ldr_stub __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >ldr_stub __bss_end__ = .; __end__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/loader_stub/loader_stub.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib check_exo_program #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4 @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_exo_program @$(SILENTCMD)echo "Checked exosphere program." ifeq ($(ATMOSPHERE_CHECKED_EXOSPHERE_PROGRAM),1) check_exo_program: else check_exo_program: check_lib @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/../program -f $(CURRENT_DIRECTORY)/../program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 endif ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a secmon_loader_main.o: CXXFLAGS += --embed-dir="$(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/" %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(OFILES_BIN) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/loader_stub/loader_stub.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /loader_stub.ld) --gc-sections --nmagic ================================================ FILE: exosphere/loader_stub/source/secmon_loader_error.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_loader_error.hpp" namespace ams::diag { NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { AMS_UNUSED(expr, func, line, file); ams::secmon::loader::ErrorReboot(); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { AMS_UNUSED(expr, func, line, file, format); ams::secmon::loader::ErrorReboot(); } NORETURN void AbortImpl() { ams::secmon::loader::ErrorReboot(); } } namespace ams::secmon::loader { NORETURN void ErrorReboot() { /* Invalidate the security engine. */ /* TODO */ /* Reboot. */ while (true) { wdt::Reboot(); } } } ================================================ FILE: exosphere/loader_stub/source/secmon_loader_error.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::secmon::loader { NORETURN void ErrorReboot(); } ================================================ FILE: exosphere/loader_stub/source/secmon_loader_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_loader_uncompress.hpp" namespace ams::secmon::loader { namespace { constexpr const u8 SecmonProgramLz4[] = { #embed <program.lz4> }; constexpr const u8 SecmonBootCodeLz4[] = { #embed <boot_code.lz4> }; } NORETURN void UncompressAndExecute() { /* Uncompress the program image. */ Uncompress(secmon::MemoryRegionPhysicalTzramFullProgramImage.GetPointer(), secmon::MemoryRegionPhysicalTzramFullProgramImage.GetSize(), SecmonProgramLz4, sizeof(SecmonProgramLz4)); /* Copy the boot image to the end of IRAM */ u8 *relocated_boot_code = secmon::MemoryRegionPhysicalIramBootCodeImage.GetEndPointer<u8>() - sizeof(SecmonBootCodeLz4); std::memcpy(relocated_boot_code, SecmonBootCodeLz4, sizeof(SecmonBootCodeLz4)); /* Uncompress the boot image. */ Uncompress(secmon::MemoryRegionPhysicalIramBootCodeImage.GetPointer(), secmon::MemoryRegionPhysicalIramBootCodeImage.GetSize(), relocated_boot_code, sizeof(SecmonBootCodeLz4)); /* Jump to the boot image. */ reinterpret_cast<void (*)()>(secmon::MemoryRegionPhysicalIramBootCodeImage.GetAddress())(); /* We will never reach this point. */ __builtin_unreachable(); } } ================================================ FILE: exosphere/loader_stub/source/secmon_loader_uncompress.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_loader_uncompress.hpp" namespace ams::secmon::loader { namespace { class Lz4Uncompressor { private: const u8 *m_src; size_t m_src_size; size_t m_src_offset; u8 *m_dst; size_t m_dst_size; size_t m_dst_offset; public: Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) { /* ... */ } void Uncompress() { while (true) { /* Read a control byte. */ const u8 control = this->ReadByte(); /* Copy what it specifies we should copy. */ this->Copy(this->GetCopySize(control >> 4)); /* If we've exceeded size, we're done. */ if (m_src_offset >= m_src_size) { break; } /* Read the wide copy offset. */ u16 wide_offset = this->ReadByte(); AMS_ABORT_UNLESS(this->CanRead()); wide_offset |= (this->ReadByte() << 8); /* Determine the copy size. */ const size_t wide_copy_size = this->GetCopySize(control & 0xF); /* Copy bytes. */ const size_t end_offset = m_dst_offset + wide_copy_size + 4; for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) { AMS_ABORT_UNLESS(wide_offset <= cur_offset); m_dst[cur_offset] = m_dst[cur_offset - wide_offset]; } } } private: u8 ReadByte() { return m_src[m_src_offset++]; } bool CanRead() const { return m_src_offset < m_src_size; } size_t GetCopySize(u8 control) { size_t size = control; if (control >= 0xF) { do { AMS_ABORT_UNLESS(this->CanRead()); control = this->ReadByte(); size += control; } while (control == 0xFF); } return size; } void Copy(size_t size) { __builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size); m_dst_offset += size; m_src_offset += size; } }; } void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Create an execute a decompressor. */ Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress(); } } ================================================ FILE: exosphere/loader_stub/source/secmon_loader_uncompress.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::secmon::loader { void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size); } ================================================ FILE: exosphere/loader_stub/source/start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ #define cpuactlr_el1 s3_1_c15_c2_0 #define cpuectlr_el1 s3_1_c15_c2_1 .macro RESET_CORE mov x0, #(1 << 63) msr cpuactlr_el1, x0 /* disable regional clock gating */ isb mov x0, #3 msr rmr_el3, x0 isb dsb sy /* Nintendo forgot to copy-paste the branch instruction below. */ 1: wfi b 1b .endm .macro ERRATUM_INVALIDATE_BTB_AT_BOOT /* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */ /* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* The following comments are mine. */ /* Enable invalidates of branch target buffer, then flush the entire instruction cache at the local level, and with the reg change, the branch target buffer, then disable invalidates of the branch target buffer again. */ mrs x0, cpuactlr_el1 orr x0, x0, #1 msr cpuactlr_el1, x0 dsb sy isb ic iallu dsb sy isb mrs x0, cpuactlr_el1 bic x0, x0, #1 msr cpuactlr_el1, x0 .rept 7 nop /* wait long enough for the write to cpuactlr_el1 to have completed */ .endr /* if the OS lock is set, disable it and request a warm reset */ mrs x0, oslsr_el1 ands x0, x0, #2 b.eq 2f mov x0, xzr msr oslar_el1, x0 RESET_CORE .rept 65 nop /* guard against speculative excecution */ .endr 2: /* set the OS lock */ mov x0, #1 msr oslar_el1, x0 .endm .section .crt0.text.start, "ax", %progbits .align 6 .global _start _start: /* mask all interrupts */ msr daifset, #0xF /* Fixup hardware erratum */ ERRATUM_INVALIDATE_BTB_AT_BOOT /* Set the stack pointer to a temporary location. */ ldr x20, =0x7C020000 mov sp, x20 /* Uncompress the program and iram boot code images. */ b _ZN3ams6secmon6loader20UncompressAndExecuteEv ================================================ FILE: exosphere/mariko_fatal/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/mariko_fatal.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/mariko_fatal.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/mariko_fatal/mariko_fatal.ld ================================================ OUTPUT_ARCH(aarch64) ENTRY(_start) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K mariko_tzram : ORIGIN = 0x1F00D0000, LENGTH = 128K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(mariko_tzram)); . = __start__; __code_start = . ; .crt0 : { KEEP (*(.crt0 .crt0.*)) KEEP (fatal_crt0_cpp.o(.text*)) *(.crt0.rodata*) fatal_crt0_cpp.o(.rodata*) *(.crt0.data*) fatal_crt0_cpp.o(.data*) . = ALIGN(8); } >mariko_tzram .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >mariko_tzram .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >mariko_tzram .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >mariko_tzram .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >mariko_tzram .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >mariko_tzram .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >mariko_tzram .init : { KEEP( *(.init) ) . = ALIGN(8); } >mariko_tzram .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >mariko_tzram .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >mariko_tzram /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >mariko_tzram .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >mariko_tzram .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >mariko_tzram .hash : { *(.hash) } >mariko_tzram /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >mariko_tzram .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >mariko_tzram .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >mariko_tzram .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >mariko_tzram .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >mariko_tzram .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >mariko_tzram .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >mariko_tzram .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >mariko_tzram .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >mariko_tzram __got_start__ = .; .got : { *(.got) *(.igot) } >mariko_tzram .got.plt : { *(.got.plt) *(.igot.plt) } >mariko_tzram __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >mariko_tzram __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >mariko_tzram __bss_end__ = .; __end__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/mariko_fatal/mariko_fatal.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) diskio.o ff.o: CFLAGS += -Wno-error -Wno-unused-parameter -Wno-implicit-fallthrough #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/mariko_fatal/mariko_fatal.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /mariko_fatal.ld) --gc-sections --nmagic ================================================ FILE: exosphere/mariko_fatal/source/fatal_abort_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::diag { NORETURN void AbortImpl() { AMS_SECMON_LOG("AbortImpl was called\n"); AMS_LOG_FLUSH(); reg::Write(0x4, 0xAAAAAAAA); /* TODO: Reboot */ AMS_INFINITE_LOOP(); } #include <exosphere/diag/diag_detailed_assertion_impl.inc> } ================================================ FILE: exosphere/mariko_fatal/source/fatal_crt0.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .crt0.text.start, "ax", %progbits .align 6 .global _start _start: /* Set the stack pointer to a temporary location. */ ldr x20, =0x1F00FC000 mov sp, x20 /* Save any arguments we may have. */ stp x0, x1, [sp, #-16]! /* Initialize all memory to expected state. */ ldr x0, =__bss_start__ ldr x1, =__bss_end__ bl _ZN3ams6secmon5fatal10InitializeEmm /* Restore any arguments we may have. */ ldp x0, x1, [sp], #16 /* Jump to the fatal program. */ ldr x16, =_ZN3ams6secmon5fatal4MainEv br x16 ================================================ FILE: exosphere/mariko_fatal/source/fatal_crt0_cpp.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> extern "C" void __libc_init_array(); namespace ams::secmon::fatal { void Initialize(uintptr_t bss_start, size_t bss_end) { /* Clear bss. */ std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start); /* Call init array. */ __libc_init_array(); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_device_page_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::secmon::fatal { namespace { /* Definitions. */ constexpr size_t PageDirectorySize = mmu::PageSize; constexpr size_t PageTableSize = mmu::PageSize; static_assert(PageDirectorySize == mmu::PageSize); using DeviceVirtualAddress = u64; constexpr size_t AsidCount = 0x80; constexpr size_t PhysicalAddressBits = 34; constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul; constexpr size_t DeviceVirtualAddressBits = 34; constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul; constexpr size_t DevicePageBits = 12; constexpr size_t DevicePageSize = (1ul << DevicePageBits); static_assert(DevicePageSize == mmu::PageSize); constexpr size_t DeviceLargePageBits = 22; constexpr size_t DeviceLargePageSize = (1ul << DeviceLargePageBits); static_assert(DeviceLargePageSize % DevicePageSize == 0); constexpr size_t DeviceRegionBits = 32; constexpr size_t DeviceRegionSize = (1ul << DeviceRegionBits); static_assert(DeviceRegionSize % DeviceLargePageSize == 0); constexpr const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress(); constexpr size_t TableCount = (1ul << DeviceVirtualAddressBits) / DeviceRegionSize; consteval u32 EncodeAsidRegisterValue(u8 asid) { u32 value = 0x80000000u; for (size_t t = 0; t < TableCount; t++) { value |= (asid << (BITSIZEOF(u8) * t)); } return value; } constexpr u8 SdmmcAsid = 1; constexpr u8 DcAsid = 2; constexpr u32 SdmmcAsidRegisterValue = EncodeAsidRegisterValue(SdmmcAsid); constexpr u32 DcAsidRegisterValue = EncodeAsidRegisterValue(DcAsid); constexpr dd::PhysicalAddress DcL0PageTablePhysical = MemoryRegionPhysicalDramDcL0DevicePageTable.GetAddress(); constexpr dd::PhysicalAddress SdmmcL0PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L0DevicePageTable.GetAddress(); constexpr dd::PhysicalAddress SdmmcL1PageTablePhysical = MemoryRegionPhysicalDramSdmmc1L1DevicePageTable.GetAddress(); /* Types. */ class EntryBase { protected: enum Bit : u32 { Bit_Table = 28, Bit_NonSecure = 29, Bit_Writeable = 30, Bit_Readable = 31, }; private: u32 m_value; protected: constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const { return (m_value & (1u << n)); } constexpr ALWAYS_INLINE bool GetBit(Bit n) const { return this->SelectBit(n) != 0; } static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) { return en ? (1u << n) : 0; } static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, dd::PhysicalAddress addr, bool t) { return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast<u32>(addr >> DevicePageBits); } ALWAYS_INLINE void SetValue(u32 v) { /* Prevent re-ordering around entry modifications. */ __asm__ __volatile__("" ::: "memory"); m_value = v; __asm__ __volatile__("" ::: "memory"); } public: static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(dd::PhysicalAddress addr) { return EncodeValue(true, true, true, addr, false); } public: constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); } constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); } constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); } constexpr ALWAYS_INLINE bool IsValid() const { return this->IsWriteable() || this->IsReadable(); } constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); } constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; } ALWAYS_INLINE void Invalidate() { this->SetValue(0); } }; class PageDirectoryEntry : public EntryBase { public: constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); } ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, dd::PhysicalAddress addr) { AMS_ASSERT(util::IsAligned(addr, DevicePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, true)); } ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, dd::PhysicalAddress addr) { AMS_ASSERT(util::IsAligned(addr, DeviceLargePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, false)); } }; class PageTableEntry : public EntryBase { public: ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, dd::PhysicalAddress addr) { AMS_ASSERT(util::IsAligned(addr, DevicePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, true)); } }; /* Memory controller access functionality. */ void WriteMcRegister(size_t offset, u32 value) { reg::Write(MC + offset, value); } u32 ReadMcRegister(size_t offset) { return reg::Read(MC + offset); } /* Memory controller utilities. */ void SmmuSynchronizationBarrier() { ReadMcRegister(MC_SMMU_CONFIG); } void InvalidatePtc() { WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0); } void InvalidatePtc(dd::PhysicalAddress address) { WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(address) >> 32)); WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (address & 0xFFFFFFF0u) | 1u); } enum TlbFlushVaMatch : u32 { TlbFlushVaMatch_All = 0, TlbFlushVaMatch_Section = 2, TlbFlushVaMatch_Group = 3, }; static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, dd::PhysicalAddress address, TlbFlushVaMatch match) { return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match); } void InvalidateTlb() { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All)); } void InvalidateTlb(u8 asid) { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All)); } void InvalidateTlbSection(u8 asid, dd::PhysicalAddress address) { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section)); } void SetTable(u8 asid, dd::PhysicalAddress address) { /* Write the table address. */ { WriteMcRegister(MC_SMMU_PTB_ASID, asid); WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address)); SmmuSynchronizationBarrier(); } /* Ensure consistency. */ InvalidatePtc(); InvalidateTlb(asid); SmmuSynchronizationBarrier(); } void MapImpl(dd::PhysicalAddress phys_addr, size_t size, DeviceVirtualAddress address, u8 asid, void *l0_table, dd::PhysicalAddress l0_phys, void *l1_table, dd::PhysicalAddress l1_phys) { /* Validate L0. */ AMS_ABORT_UNLESS(l0_table != nullptr); AMS_ABORT_UNLESS(l0_phys != 0); /* Cache permissions. */ const bool read = true; const bool write = true; /* Walk the directory. */ u64 remaining = size; while (remaining > 0) { const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize; const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize; /* Get and validate l1. */ PageDirectoryEntry *l1 = static_cast<PageDirectoryEntry *>(l0_table); AMS_ASSERT(l1 != nullptr); /* Setup an l1 table/entry, if needed. */ if (!l1[l1_index].IsTable()) { /* Check that an entry doesn't already exist. */ AMS_ASSERT(!l1[l1_index].IsValid()); /* If we can make an l1 entry, do so. */ if (l2_index == 0 && util::IsAligned(phys_addr, DeviceLargePageSize) && remaining >= DeviceLargePageSize) { /* Set the large page. */ l1[l1_index].SetLargePage(read, write, true, phys_addr); hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)); /* Synchronize. */ InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry)); InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); /* Advance. */ phys_addr += DeviceLargePageSize; address += DeviceLargePageSize; remaining -= DeviceLargePageSize; continue; } else { /* Make an l1 table. */ AMS_ABORT_UNLESS(l1_table != nullptr); AMS_ABORT_UNLESS(l1_phys != 0); /* Clear the l1 table. */ std::memset(l1_table, 0, mmu::PageSize); hw::FlushDataCache(l1_table, mmu::PageSize); /* Set the l1 table. */ l1[l1_index].SetTable(true, true, true, l1_phys); hw::FlushDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry)); /* Synchronize. */ InvalidatePtc(l0_phys + l1_index * sizeof(PageDirectoryEntry)); InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); } } /* If we get to this point, l1 must be a table. */ AMS_ASSERT(l1[l1_index].IsTable()); AMS_ABORT_UNLESS(l1_table != nullptr); AMS_ABORT_UNLESS(l1_phys != 0); /* Map l2 entries. */ { PageTableEntry *l2 = static_cast<PageTableEntry *>(l1_table); const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); /* Set the entries. */ for (size_t i = 0; i < map_count; ++i) { AMS_ASSERT(!l2[l2_index + i].IsValid()); l2[l2_index + i].SetPage(read, write, true, phys_addr + DevicePageSize * i); } hw::FlushDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry)); /* Invalidate the page table cache. */ for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) { InvalidatePtc(l1_phys + i * sizeof(PageTableEntry)); } /* Synchronize. */ InvalidateTlbSection(asid, address); SmmuSynchronizationBarrier(); /* Advance. */ phys_addr += map_count * DevicePageSize; address += map_count * DevicePageSize; remaining -= map_count * DevicePageSize; } } } } void InitializeDevicePageTableForSdmmc1() { /* Configure sdmmc to use our new page table. */ WriteMcRegister(MC_SMMU_SDMMC1A_ASID, SdmmcAsidRegisterValue); SmmuSynchronizationBarrier(); /* Ensure consistency. */ InvalidatePtc(); InvalidateTlb(); SmmuSynchronizationBarrier(); /* Clear the L0 Page Table. */ std::memset(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize); hw::FlushDataCache(MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), mmu::PageSize); /* Set the page table for the sdmmc asid. */ SetTable(SdmmcAsid, SdmmcL0PageTablePhysical); /* Map the appropriate region into the asid. */ MapImpl(MemoryRegionPhysicalDramSdmmcMappedData.GetAddress(), MemoryRegionPhysicalDramSdmmcMappedData.GetSize(), MemoryRegionVirtualDramSdmmcMappedData.GetAddress(), SdmmcAsid, MemoryRegionVirtualDramSdmmc1L0DevicePageTable.GetPointer<void>(), SdmmcL0PageTablePhysical, MemoryRegionVirtualDramSdmmc1L1DevicePageTable.GetPointer<void>(), SdmmcL1PageTablePhysical); } void InitializeDevicePageTableForDc() { /* Configure dc to use our new page table. */ WriteMcRegister(MC_SMMU_DC_ASID, DcAsidRegisterValue); SmmuSynchronizationBarrier(); /* Ensure consistency. */ InvalidatePtc(); InvalidateTlb(); SmmuSynchronizationBarrier(); /* Clear the L0 Page Table. */ std::memset(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), 0, mmu::PageSize); hw::FlushDataCache(MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), mmu::PageSize); /* Set the page table for the dc asid. */ SetTable(DcAsid, DcL0PageTablePhysical); /* Map the appropriate region into the asid. */ static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetAddress(), DeviceLargePageSize)); static_assert(util::IsAligned(MemoryRegionDramDcFramebuffer.GetSize(), DeviceLargePageSize)); MapImpl(MemoryRegionDramDcFramebuffer.GetAddress(), MemoryRegionDramDcFramebuffer.GetSize(), MemoryRegionDramDcFramebuffer.GetAddress(), DcAsid, MemoryRegionVirtualDramDcL0DevicePageTable.GetPointer<void>(), DcL0PageTablePhysical, nullptr, 0); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_device_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { void InitializeDevicePageTableForSdmmc1(); void InitializeDevicePageTableForDc(); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_display.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_device_page_table.hpp" #include "fatal_registers_di.hpp" #include "fatal_display.hpp" #include "fatal_print.hpp" namespace ams::secmon::fatal { namespace { #include "fatal_display_config.inc" } namespace { /* Helpful defines. */ constexpr int DsiWaitForCommandMilliSecondsMax = 250; constexpr int DsiWaitForCommandCompletionMilliSeconds = 5; constexpr int DsiWaitForHostControlMilliSecondsMax = 150; constexpr inline int I2cAddressMax77620Pmic = 0x3C; constexpr size_t GPIO_PORT3_CNF_0 = 0x200; constexpr size_t GPIO_PORT3_OE_0 = 0x210; constexpr size_t GPIO_PORT3_OUT_0 = 0x220; constexpr size_t GPIO_PORT6_CNF_1 = 0x504; constexpr size_t GPIO_PORT6_OE_1 = 0x514; constexpr size_t GPIO_PORT6_OUT_1 = 0x524; /* Globals. */ constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc .GetAddress(); constexpr inline const uintptr_t g_disp1_regs = secmon::MemoryRegionVirtualDeviceDisp1 .GetAddress(); constexpr inline const uintptr_t g_dsi_regs = secmon::MemoryRegionVirtualDeviceDsi .GetAddress(); constexpr inline const uintptr_t g_clk_rst_regs = secmon::MemoryRegionVirtualDeviceClkRst .GetAddress(); constexpr inline const uintptr_t g_gpio_regs = secmon::MemoryRegionVirtualDeviceGpio .GetAddress(); constexpr inline const uintptr_t g_apb_misc_regs = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t g_mipi_cal_regs = secmon::MemoryRegionVirtualDeviceMipiCal.GetAddress(); constinit u32 *g_frame_buffer = nullptr; inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) { for (size_t i = 0; i < num_writes; i++) { reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value); } } inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) { switch (GetSocType()) { case fuse::SocType_Erista: DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista); break; case fuse::SocType_Mariko: DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } inline void DoSleepOrRegisterWrites(uintptr_t base_address, const SleepOrRegisterWrite *reg_writes, size_t num_writes) { for (size_t i = 0; i < num_writes; i++) { switch (reg_writes[i].kind) { case SleepOrRegisterWriteKind_Write: reg::Write(base_address + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value); break; case SleepOrRegisterWriteKind_Sleep: util::WaitMicroSeconds(reg_writes[i].offset * UINT64_C(1000)); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } } void WaitDsiTrigger() { const u32 timeout = util::GetMicroSeconds() + (DsiWaitForCommandMilliSecondsMax * 1000u); while (true) { if (util::GetMicroSeconds() >= timeout) { break; } if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) { break; } } util::WaitMicroSeconds(DsiWaitForCommandCompletionMilliSeconds * 1000u); } void WaitDsiHostControl() { const u32 timeout = util::GetMicroSeconds() + (DsiWaitForHostControlMilliSecondsMax * 1000u); while (true) { if (util::GetMicroSeconds() >= timeout) { break; } if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) { break; } } } void EnableBacklightForVendor2050ForAula(int brightness) { /* Enable FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 2); /* Configure DSI_LINE_TYPE as FOUR */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 9); /* Set and wait for FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ } /* Configure display brightness. */ const u32 brightness_val = ((0x7FF * brightness) / 100); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, (brightness_val & 0x700) | ((brightness_val & 0xFF) << 16) | 0x51); /* Set and wait for FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ } /* Set client sync point block reset. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 1); util::WaitMicroSeconds(300'000ul); /* Clear client sync point block resest. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 0); util::WaitMicroSeconds(300'000ul); /* Clear DSI_LINE_TYPE config. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0); /* Disable FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 0); reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); } void EnableBacklightForGeneric(int brightness) { AMS_UNUSED(brightness); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } #define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes)) #define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko)) #define DO_SLEEP_OR_REGISTER_WRITES(base_address, writes) DoSleepOrRegisterWrites(base_address, writes, util::size(writes)) void InitializeFrameBuffer() { if (g_frame_buffer != nullptr) { std::memset(g_frame_buffer, 0, FrameBufferSize); hw::FlushDataCache(g_frame_buffer, FrameBufferSize); } else { /* Clear the frame buffer. */ g_frame_buffer = secmon::MemoryRegionDramDcFramebuffer.GetPointer<u32>(); std::memset(g_frame_buffer, 0, FrameBufferSize); hw::FlushDataCache(g_frame_buffer, FrameBufferSize); /* Attach the frame buffer to DC. */ InitializeDevicePageTableForDc(); } } [[maybe_unused]] void FinalizeFrameBuffer() { /* We don't actually support finalizing the framebuffer, so do nothing here. */ } constexpr const char *GetErrorDescription(u32 error_desc) { switch (error_desc) { case 0x100: return "Instruction Abort"; case 0x101: return "Data Abort"; case 0x102: return "PC Misalignment"; case 0x103: return "SP Misalignment"; case 0x104: return "Trap"; case 0x106: return "SError"; case 0x301: return "Bad SVC"; case 0xF00: return "Kernel Panic"; case 0xFFD: return "Stack overflow"; case 0xFFE: return "std::abort() called"; default: return "Unknown"; } } void PrintSuggestedErrorFix(const ams::impl::FatalErrorContext *f_ctx) { /* Try to recognize certain errors automatically, and suggest fixes for them. */ const char *suggestion = nullptr; constexpr u64 ProgramIdAmsMitm = UINT64_C(0x010041544D530000); constexpr u64 ProgramIdBoot = UINT64_C(0x0100000000000005); if (f_ctx->error_desc == 0xFFE) { if (f_ctx->program_id == ProgramIdAmsMitm) { /* When a user has archive bits set improperly, attempting to create an automatic backup will fail */ /* to create the file path with error 0x202 */ if (f_ctx->gprs[0] == fs::ResultPathNotFound().GetValue()) { /* When the archive bit error is occurring, it manifests as failure to create automatic backup. */ /* Thus, we can search the stack for the automatic backups path. */ const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */; const int prefix_len = std::strlen(automatic_backups_prefix); for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) { if (std::memcmp(f_ctx->stack_dump + i, automatic_backups_prefix, prefix_len) == 0) { suggestion = "The atmosphere directory may improperly have archive bits set.\n" "Please try running an archive bit fixer tool (for example, the one in Hekate).\n"; break; } } } else if (f_ctx->gprs[0] == fs::ResultExFatUnavailable().GetValue()) { /* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */ /* be returned on attempt to access the SD card. */ suggestion = "Your console has non-exFAT firmware installed, but your SD card\n" "is formatted as exFAT. Format your SD card as FAT32, or manually\n" "flash exFAT firmware to package2.\n"; } } else if (f_ctx->program_id == ProgramIdBoot) { /* 9.x -> 10.x updated the API for SvcQueryIoMapping. */ /* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */ /* (older kernel in package2, for some reason). */ for (size_t i = 0; i < 8; ++i) { if (f_ctx->gprs[i] == svc::ResultNotFound().GetValue()) { suggestion = "A partial update may have been improperly performed.\n" "To fix, try manually flashing latest package2 to MMC.\n" "\n" "For help doing this, seek support in the ReSwitched or\n" "Nintendo Homebrew discord servers.\n"; break; } } } } else if (f_ctx->error_desc == 0xF00) { /* Kernel Panic */ suggestion = "Please contact SciresM#0524 on Discord, or create an issue on the Atmosphere\n" "GitHub issue tracker. Thank you very much for helping to test mesosphere.\n"; } /* If we found a suggestion, print it. */ if (suggestion != nullptr) { Print("%s", suggestion); } } void FinalizeDisplay() { /* TODO: What other configuration is needed, if any? */ /* Configure LCD pinmux tristate + passthrough. */ reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); if (fuse::GetHardwareType() == fuse::HardwareType_Aula) { /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4); } else { /* Configure LCD power, VDD. */ reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2); } /* Disable the LCD backlight. */ if (GetLcdVendor() == 0x2050) { /* TODO: We're not sure display is alive. How to manage this? */ /* This is probably incorrect backlight disable for hw-type 5. */ reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } else { reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } /* Disable backlight RST/Voltage. */ reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4); if (GetLcdVendor() == 0x2050) { util::WaitMicroSeconds(30'000ul); } else { util::WaitMicroSeconds(10'000ul); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); } /* Cut clock to DSI. */ reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_MIPI_CAL_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_DSI_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_MIPI_CAL, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_DSI, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_HOST1X_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_DISP1_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_HOST1X, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_DISP1, ENABLE)); reg::Write(g_dsi_regs + sizeof(u32) * DSI_PAD_CONTROL_0, (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF))); reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0); } } void InitializeDisplay() { /* Ensure that the display is finalized. */ FinalizeDisplay(); /* Setup the framebuffer. */ InitializeFrameBuffer(); /* Get the hardware type. */ const auto hw_type = fuse::GetHardwareType(); /* Turn on DSI/voltage rail. */ { if (GetSocType() == fuse::SocType_Mariko) { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A); } i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x23, 0xD0); } /* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */ reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_MIPI_CAL_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_DSI_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_MIPI_CAL, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_DSI, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_HOST1X_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_DISP1_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_HOST1X, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_DISP1, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_SET_SET_CLK_ENB_UART_FST_MIPI_CAL, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_DIVISOR, 10), CLK_RST_REG_BITS_ENUM (CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_SRC, PLLP_OUT3)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DSIA_LP, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_DIVISOR, 10), CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_SRC, PLLP_OUT0)); /* Set IO_DPD_REQ to DPD_OFF. */ reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD_REQ, PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_OFF)); reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD2_REQ, PMC_REG_BITS_ENUM(IO_DPD2_REQ_CODE, DPD_OFF)); /* Configure LCD pinmux tristate + passthrough. */ reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); if (hw_type == fuse::HardwareType_Aula) { /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4); } else { /* Configure LCD power, VDD. */ reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2); } /* Configure display interface and display. */ reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0); if (GetSocType() == fuse::SocType_Mariko) { reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0); reg::Write(g_apb_misc_regs + APB_MISC_GP_DSI_PAD_CONTROL, 0); } /* Execute configs. */ DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01); DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07); util::WaitMicroSeconds(10'000ul); /* Enable backlight reset. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4); util::WaitMicroSeconds(60'000ul); if (hw_type == fuse::HardwareType_Aula) { reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x40103); } else { reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204); } reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); WaitDsiTrigger(); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); WaitDsiTrigger(); reg::Write(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC); WaitDsiHostControl(); util::WaitMicroSeconds(5'000ul); /* Parse LCD vendor. */ { u32 host_response[3]; for (size_t i = 0; i < util::size(host_response); i++) { host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA); } /* The last word from host response is: Bits 0-7: FAB Bits 8-15: REV Bits 16-23: Minor REV */ u32 lcd_vendor; if ((host_response[2] & 0xFF) == 0x10) { lcd_vendor = 0; } else { lcd_vendor = (host_response[2] >> 8) & 0xFF00; } lcd_vendor = (lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF); AMS_ASSERT(lcd_vendor == GetLcdVendor()); } /* LCD vendor specific configuration. */ switch (GetLcdVendor()) { case 0x10: /* Japan Display Inc screens. */ DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificInit01); break; case 0xF20: /* Innolux first revision screens. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0xF30: /* AUO first revision screens. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0x2050: /* Unknown (hardware type 5) screen. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xA015); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x205315); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x51); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0x1020: /* Innolux second revision screen. */ case 0x1030: /* AUO second revision screen. */ case 0x1040: /* Unknown second revision screen. */ default: reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(120'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; } util::WaitMicroSeconds(20'000ul); DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09); reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4)); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10); util::WaitMicroSeconds(10'000ul); /* Configure MIPI CAL. */ DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03); DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04); if (GetSocType() == fuse::SocType_Mariko) { /* On Mariko the above configurations are executed twice, for some reason. */ DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03); DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04); } util::WaitMicroSeconds(10'000ul); /* Write DISP1, FrameBuffer config. */ DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02); DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer); if (GetLcdVendor() != 0x2050) { util::WaitMicroSeconds(35'000ul); } } void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) { /* Initialize the console. */ InitializeConsole(g_frame_buffer); { Print("%s\n", "A fatal error occurred when running Atmosph\xe8re."); Print("Program ID: %016" PRIx64 "\n", f_ctx->program_id); Print("Error Desc: %s (0x%x)\n", GetErrorDescription(f_ctx->error_desc), f_ctx->error_desc); Print("\n"); if (R_SUCCEEDED(save_result)) { Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin", f_ctx->report_identifier); } else { Print("Failed to save report to the SD card! (%08x)\n", save_result.GetValue()); } PrintSuggestedErrorFix(f_ctx); Print("\nPress POWER to reboot.\n"); } /* Ensure the device will see consistent data. */ hw::FlushDataCache(g_frame_buffer, FrameBufferSize); /* Enable backlight. */ constexpr auto DisplayBrightness = 100; if (GetLcdVendor() == 0x2050) { EnableBacklightForVendor2050ForAula(DisplayBrightness); } else { EnableBacklightForGeneric(DisplayBrightness); } } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_display.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { constexpr inline size_t FrameBufferHeight = 768; constexpr inline size_t FrameBufferWidth = 1280; constexpr inline size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); void InitializeDisplay(); void ShowDisplay(); void ShowDisplay(const ams::impl::FatalErrorContext *f_ctx, const Result save_result); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_display_config.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ struct RegisterWrite { u32 offset; u32 value; }; enum SleepOrRegisterWriteKind : u16 { SleepOrRegisterWriteKind_Write = 0, SleepOrRegisterWriteKind_Sleep = 1, }; struct SleepOrRegisterWrite { SleepOrRegisterWriteKind kind; u16 offset; u32 value; }; constexpr const RegisterWrite DisplayConfigPlld01Erista[] = { {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, }; constexpr const RegisterWrite DisplayConfigPlld01Mariko[] = { {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, }; constexpr const SleepOrRegisterWrite DisplayConfigDc01[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_REG_ACT_CONTROL, 0x54}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_DISP_DC_MCCIF_FIFOCTRL, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL}, {SleepOrRegisterWriteKind_Write, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0}, {SleepOrRegisterWriteKind_Write, 0x4E4, 0}, {SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} }; constexpr const RegisterWrite DisplayConfigDsi01Init01[] = { {sizeof(u32) * DSI_WR_DATA, 0x0}, {sizeof(u32) * DSI_INT_ENABLE, 0x0}, {sizeof(u32) * DSI_INT_STATUS, 0x0}, {sizeof(u32) * DSI_INT_MASK, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init02Erista[] = { {sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init02Mariko[] = { {sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init03[] = { {sizeof(u32) * DSI_DCS_CMDS, 0}, {sizeof(u32) * DSI_PKT_SEQ_0_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_1_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_2_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_3_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_4_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_5_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_0_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_1_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_2_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_3_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_4_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_5_HI, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init04Erista[] = { /* No register writes. */ }; constexpr const RegisterWrite DisplayConfigDsi01Init04Mariko[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0}, {sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init05[] = { {sizeof(u32) * DSI_PAD_CONTROL_CD, 0}, {sizeof(u32) * DSI_SOL_DELAY, 0x18}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}, {sizeof(u32) * DSI_PKT_LEN_0_1, 0}, {sizeof(u32) * DSI_PKT_LEN_2_3, 0}, {sizeof(u32) * DSI_PKT_LEN_4_5, 0}, {sizeof(u32) * DSI_PKT_LEN_6_7, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init06[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30109}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init07[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30118}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x40}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_TX_CRC, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} }; constexpr const RegisterWrite DisplayConfigDsiPhyTimingErista[] = { {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601}, }; constexpr const RegisterWrite DisplayConfigDsiPhyTimingMariko[] = { {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603}, }; constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Sleep, 180, 0}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, }; constexpr const RegisterWrite DisplayConfigPlld02Erista[] = { {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, }; constexpr const RegisterWrite DisplayConfigPlld02Mariko[] = { {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, }; constexpr const RegisterWrite DisplayConfigDsi01Init08[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const SleepOrRegisterWrite DisplayConfigDsi01Init09[] = { {SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_1, 0x40A0E05}, {SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_2, 0x30172}, {SleepOrRegisterWriteKind_Write, DSI_BTA_TIMING, 0x190A14}, {SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, {SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, {SleepOrRegisterWriteKind_Write, DSI_TO_TALLY, 0}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_0_LO, 0x40000208}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_2_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_4_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_1_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_LO, 0x3F3B2B08}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_HI, 0x2CC}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_LO, 0x3F3B2B08}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_HI, 0x2CC}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_0_1, 0xCE0000}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_2_3, 0x87001A2}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_4_5, 0x190}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_6_7, 0x190}, {SleepOrRegisterWriteKind_Write, DSI_HOST_CONTROL, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init10[] = { {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_CONTROL, 0}, {sizeof(u32) * DSI_SOL_DELAY, 6}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} }; constexpr const RegisterWrite DisplayConfigDsi01Init11Erista[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0} }; constexpr const RegisterWrite DisplayConfigDsi01Init11Mariko[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777}, {sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777}, {sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal01[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 1}, {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal02Erista[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300}, }; constexpr const RegisterWrite DisplayConfigMipiCal02Mariko[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal03Erista[] = { {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}, {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal03Mariko[] = { {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000}, {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal04[] = { {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001}, }; constexpr const SleepOrRegisterWrite DisplayConfigDc02[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0}, {SleepOrRegisterWriteKind_Write, 0x4E4, 0}, {SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, /* Set Display timings */ {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_TIMING_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1. {SleepOrRegisterWriteKind_Write, DC_DISP_SYNC_WIDTH, 0x10048}, {SleepOrRegisterWriteKind_Write, DC_DISP_BACK_PORCH, 0x90048}, {SleepOrRegisterWriteKind_Write, DC_DISP_ACTIVE, 0x50002D0}, {SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. /* End of Display timings */ {SleepOrRegisterWriteKind_Write, DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_ENABLE(1), 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX}, {SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0} }; constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000; constexpr const SleepOrRegisterWrite DisplayConfigFrameBuffer[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_POSITION, 0}, //(0,0) {SleepOrRegisterWriteKind_Write, DC_WIN_H_INITIAL_DDA, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_V_INITIAL_DDA, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. {SleepOrRegisterWriteKind_Write, DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, {SleepOrRegisterWriteKind_Write, DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. {SleepOrRegisterWriteKind_Write, DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {SleepOrRegisterWriteKind_Write, DC_WIN_BUFFER_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. {SleepOrRegisterWriteKind_Write, DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address. {SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_H_OFFSET, 0}, {SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_V_OFFSET, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD. {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. }; constexpr const RegisterWrite DisplayConfigDc01Fini01[] = { {sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088}, {sizeof(u32) * DC_CMD_INT_MASK, 0}, {sizeof(u32) * DC_CMD_STATE_ACCESS, 0}, {sizeof(u32) * DC_CMD_INT_ENABLE, 0}, {sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, 0}, {sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, }; constexpr const RegisterWrite DisplayConfigDsi01Fini01[] = { {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Fini02[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30118}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) }, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x40}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_TX_CRC, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} }; constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificFini01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2139}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x4F0F41B1}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF179A433}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2D81}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, }; constexpr const SleepOrRegisterWrite DisplayConfigAuoRev1SpecificFini01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D6}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x711148B1}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x71143209}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x114D31}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Sleep, 5, 0}, }; ================================================ FILE: exosphere/mariko_fatal/source/fatal_font.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * (C) Copyright 2000 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it * * SPDX-License-Identifier: GPL-2.0+ * * This file contains an 8x16 bitmap font for code page 437. */ constexpr inline const size_t FontWidth = 8; constexpr inline const size_t FontHeight = 16; constexpr inline const u8 FontData[] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 1 0x01 '^A' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x81, /* 10000001 */ 0xa5, /* 10100101 */ 0x81, /* 10000001 */ 0x81, /* 10000001 */ 0xbd, /* 10111101 */ 0x99, /* 10011001 */ 0x81, /* 10000001 */ 0x81, /* 10000001 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 2 0x02 '^B' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xff, /* 11111111 */ 0xdb, /* 11011011 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xc3, /* 11000011 */ 0xe7, /* 11100111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 3 0x03 '^C' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 4 0x04 '^D' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 5 0x05 '^E' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0xe7, /* 11100111 */ 0xe7, /* 11100111 */ 0xe7, /* 11100111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 6 0x06 '^F' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 7 0x07 '^G' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 8 0x08 '^H' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xe7, /* 11100111 */ 0xc3, /* 11000011 */ 0xc3, /* 11000011 */ 0xe7, /* 11100111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 9 0x09 '^I' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x42, /* 01000010 */ 0x42, /* 01000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 10 0x0a '^J' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xc3, /* 11000011 */ 0x99, /* 10011001 */ 0xbd, /* 10111101 */ 0xbd, /* 10111101 */ 0x99, /* 10011001 */ 0xc3, /* 11000011 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 11 0x0b '^K' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x0e, /* 00001110 */ 0x1a, /* 00011010 */ 0x32, /* 00110010 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 12 0x0c '^L' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 13 0x0d '^M' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x33, /* 00110011 */ 0x3f, /* 00111111 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x70, /* 01110000 */ 0xf0, /* 11110000 */ 0xe0, /* 11100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 14 0x0e '^N' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7f, /* 01111111 */ 0x63, /* 01100011 */ 0x7f, /* 01111111 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x67, /* 01100111 */ 0xe7, /* 11100111 */ 0xe6, /* 11100110 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 15 0x0f '^O' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xdb, /* 11011011 */ 0x3c, /* 00111100 */ 0xe7, /* 11100111 */ 0x3c, /* 00111100 */ 0xdb, /* 11011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 16 0x10 '^P' */ 0x00, /* 00000000 */ 0x80, /* 10000000 */ 0xc0, /* 11000000 */ 0xe0, /* 11100000 */ 0xf0, /* 11110000 */ 0xf8, /* 11111000 */ 0xfe, /* 11111110 */ 0xf8, /* 11111000 */ 0xf0, /* 11110000 */ 0xe0, /* 11100000 */ 0xc0, /* 11000000 */ 0x80, /* 10000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 17 0x11 '^Q' */ 0x00, /* 00000000 */ 0x02, /* 00000010 */ 0x06, /* 00000110 */ 0x0e, /* 00001110 */ 0x1e, /* 00011110 */ 0x3e, /* 00111110 */ 0xfe, /* 11111110 */ 0x3e, /* 00111110 */ 0x1e, /* 00011110 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x02, /* 00000010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 18 0x12 '^R' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 19 0x13 '^S' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 20 0x14 '^T' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7f, /* 01111111 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0x7b, /* 01111011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 21 0x15 '^U' */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 22 0x16 '^V' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 23 0x17 '^W' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 24 0x18 '^X' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 25 0x19 '^Y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 26 0x1a '^Z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0xfe, /* 11111110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 27 0x1b '^[' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xfe, /* 11111110 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 28 0x1c '^\' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 29 0x1d '^]' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x28, /* 00101000 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x28, /* 00101000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 30 0x1e '^^' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0x7c, /* 01111100 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 31 0x1f '^_' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 32 0x20 ' ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 33 0x21 '!' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 34 0x22 '"' */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x24, /* 00100100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 35 0x23 '#' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 36 0x24 '$' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0x7c, /* 01111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x86, /* 10000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 37 0x25 '%' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc2, /* 11000010 */ 0xc6, /* 11000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0x86, /* 10000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 38 0x26 '&' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 39 0x27 ''' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 40 0x28 '(' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 41 0x29 ')' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 42 0x2a '*' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0xff, /* 11111111 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 43 0x2b '+' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 44 0x2c ',' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 45 0x2d '-' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 46 0x2e '.' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 47 0x2f '/' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x02, /* 00000010 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x80, /* 10000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 48 0x30 '0' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 49 0x31 '1' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x38, /* 00111000 */ 0x78, /* 01111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 50 0x32 '2' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 51 0x33 '3' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x3c, /* 00111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 52 0x34 '4' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x1c, /* 00011100 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xfe, /* 11111110 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x1e, /* 00011110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 53 0x35 '5' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfc, /* 11111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 54 0x36 '6' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfc, /* 11111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 55 0x37 '7' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 56 0x38 '8' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 57 0x39 '9' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 58 0x3a ':' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 59 0x3b ';' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 60 0x3c '<' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 61 0x3d '=' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 62 0x3e '>' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 63 0x3f '?' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 64 0x40 '@' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xde, /* 11011110 */ 0xde, /* 11011110 */ 0xde, /* 11011110 */ 0xdc, /* 11011100 */ 0xc0, /* 11000000 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 65 0x41 'A' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 66 0x42 'B' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xfc, /* 11111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 67 0x43 'C' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc2, /* 11000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 68 0x44 'D' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 69 0x45 'E' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x60, /* 01100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 70 0x46 'F' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 71 0x47 'G' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xde, /* 11011110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x66, /* 01100110 */ 0x3a, /* 00111010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 72 0x48 'H' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 73 0x49 'I' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 74 0x4a 'J' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 75 0x4b 'K' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe6, /* 11100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x78, /* 01111000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 76 0x4c 'L' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf0, /* 11110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 77 0x4d 'M' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xee, /* 11101110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 78 0x4e 'N' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xe6, /* 11100110 */ 0xf6, /* 11110110 */ 0xfe, /* 11111110 */ 0xde, /* 11011110 */ 0xce, /* 11001110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 79 0x4f 'O' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 80 0x50 'P' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 81 0x51 'Q' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xde, /* 11011110 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0x0e, /* 00001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 82 0x52 'R' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 83 0x53 'S' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 84 0x54 'T' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x5a, /* 01011010 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 85 0x55 'U' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 86 0x56 'V' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 87 0x57 'W' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xfe, /* 11111110 */ 0xee, /* 11101110 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 88 0x58 'X' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 89 0x59 'Y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 90 0x5a 'Z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x86, /* 10000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc2, /* 11000010 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 91 0x5b '[' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 92 0x5c '\' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x80, /* 10000000 */ 0xc0, /* 11000000 */ 0xe0, /* 11100000 */ 0x70, /* 01110000 */ 0x38, /* 00111000 */ 0x1c, /* 00011100 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x02, /* 00000010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 93 0x5d ']' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 94 0x5e '^' */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 95 0x5f '_' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 96 0x60 '`' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 97 0x61 'a' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 98 0x62 'b' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 99 0x63 'c' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 100 0x64 'd' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 101 0x65 'e' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 102 0x66 'f' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x36, /* 00110110 */ 0x32, /* 00110010 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 103 0x67 'g' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ /* 104 0x68 'h' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x6c, /* 01101100 */ 0x76, /* 01110110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 105 0x69 'i' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 106 0x6a 'j' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ /* 107 0x6b 'k' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x78, /* 01111000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 108 0x6c 'l' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 109 0x6d 'm' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xec, /* 11101100 */ 0xfe, /* 11111110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 110 0x6e 'n' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 111 0x6f 'o' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 112 0x70 'p' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ /* 113 0x71 'q' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x1e, /* 00011110 */ 0x00, /* 00000000 */ /* 114 0x72 'r' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x76, /* 01110110 */ 0x66, /* 01100110 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 115 0x73 's' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 116 0x74 't' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0xfc, /* 11111100 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x36, /* 00110110 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 117 0x75 'u' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 118 0x76 'v' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 119 0x77 'w' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 120 0x78 'x' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 121 0x79 'y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ /* 122 0x7a 'z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xcc, /* 11001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 123 0x7b '{' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x0e, /* 00001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 124 0x7c '|' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 125 0x7d '}' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x70, /* 01110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x0e, /* 00001110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 126 0x7e '~' */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 127 0x7f '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 128 0x80 '€' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc2, /* 11000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 129 0x81 '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 130 0x82 '‚' */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 131 0x83 'ƒ' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 132 0x84 '„' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 133 0x85 '…' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 134 0x86 '†' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 135 0x87 '‡' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 136 0x88 'ˆ' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 137 0x89 '‰' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 138 0x8a 'Š' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 139 0x8b '‹' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 140 0x8c 'Œ' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 141 0x8d '' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 142 0x8e 'Ž' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 143 0x8f '' */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 144 0x90 '' */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 145 0x91 '‘' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xec, /* 11101100 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x7e, /* 01111110 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x6e, /* 01101110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 146 0x92 '’' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3e, /* 00111110 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xfe, /* 11111110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xce, /* 11001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 147 0x93 '“' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 148 0x94 '”' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 149 0x95 '•' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 150 0x96 '–' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 151 0x97 '—' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 152 0x98 '˜' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ /* 153 0x99 '™' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 154 0x9a 'š' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 155 0x9b '›' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 156 0x9c 'œ' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x64, /* 01100100 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xe6, /* 11100110 */ 0xfc, /* 11111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 157 0x9d '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 158 0x9e 'ž' */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xf8, /* 11111000 */ 0xc4, /* 11000100 */ 0xcc, /* 11001100 */ 0xde, /* 11011110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 159 0x9f 'Ÿ' */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x1b, /* 00011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 160 0xa0 ' ' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 161 0xa1 '¡' */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 162 0xa2 '¢' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 163 0xa3 '£' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 164 0xa4 '¤' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 165 0xa5 '¥' */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xe6, /* 11100110 */ 0xf6, /* 11110110 */ 0xfe, /* 11111110 */ 0xde, /* 11011110 */ 0xce, /* 11001110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 166 0xa6 '¦' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x3e, /* 00111110 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 167 0xa7 '§' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 168 0xa8 '¨' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 169 0xa9 '©' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 170 0xaa 'ª' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 171 0xab '«' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0xe0, /* 11100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xdc, /* 11011100 */ 0x86, /* 10000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x3e, /* 00111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 172 0xac '¬' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0xe0, /* 11100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x66, /* 01100110 */ 0xce, /* 11001110 */ 0x9a, /* 10011010 */ 0x3f, /* 00111111 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 173 0xad '­' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 174 0xae '®' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x36, /* 00110110 */ 0x6c, /* 01101100 */ 0xd8, /* 11011000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 175 0xaf '¯' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xd8, /* 11011000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x6c, /* 01101100 */ 0xd8, /* 11011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 176 0xb0 '°' */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ /* 177 0xb1 '±' */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ /* 178 0xb2 '²' */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ /* 179 0xb3 '³' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 180 0xb4 '´' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 181 0xb5 'µ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 182 0xb6 '¶' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 183 0xb7 '·' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 184 0xb8 '¸' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 185 0xb9 '¹' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x06, /* 00000110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 186 0xba 'º' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 187 0xbb '»' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x06, /* 00000110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 188 0xbc '¼' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x06, /* 00000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 189 0xbd '½' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 190 0xbe '¾' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 191 0xbf '¿' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 192 0xc0 'À' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 193 0xc1 'Á' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 194 0xc2 'Â' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 195 0xc3 'Ã' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 196 0xc4 'Ä' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 197 0xc5 'Å' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 198 0xc6 'Æ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 199 0xc7 'Ç' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 200 0xc8 'È' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x30, /* 00110000 */ 0x3f, /* 00111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 201 0xc9 'É' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x30, /* 00110000 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 202 0xca 'Ê' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf7, /* 11110111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 203 0xcb 'Ë' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xf7, /* 11110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 204 0xcc 'Ì' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x30, /* 00110000 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 205 0xcd 'Í' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 206 0xce 'Î' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf7, /* 11110111 */ 0x00, /* 00000000 */ 0xf7, /* 11110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 207 0xcf 'Ï' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 208 0xd0 'Ð' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 209 0xd1 'Ñ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 210 0xd2 'Ò' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 211 0xd3 'Ó' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x3f, /* 00111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 212 0xd4 'Ô' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 213 0xd5 'Õ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 214 0xd6 'Ö' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 215 0xd7 '×' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xff, /* 11111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 216 0xd8 'Ø' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 217 0xd9 'Ù' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 218 0xda 'Ú' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 219 0xdb 'Û' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 220 0xdc 'Ü' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 221 0xdd 'Ý' */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ /* 222 0xde 'Þ' */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ /* 223 0xdf 'ß' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 224 0xe0 'à' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xdc, /* 11011100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 225 0xe1 'á' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xd8, /* 11011000 */ 0xcc, /* 11001100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 226 0xe2 'â' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 227 0xe3 'ã' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 228 0xe4 'ä' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 229 0xe5 'å' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 230 0xe6 'æ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ /* 231 0xe7 'ç' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 232 0xe8 'è' */ 0x00, /* 00000000 */ 0x40, /* 01000000*/ 0xe0, /* 01110000 */ 0x1c, /* 00011100 */ 0x06, /* 00000110 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 233 0xe9 'é' */ 0x00, /* 00000000 */ 0x02, /* 00000010*/ 0x0e, /* 00001110 */ 0x78, /* 00111000 */ 0xc0, /* 01100000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 234 0xea 'ê' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xee, /* 11101110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 235 0xeb 'ë' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x3e, /* 00111110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 236 0xec 'ì' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 237 0xed 'í' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x03, /* 00000011 */ 0x06, /* 00000110 */ 0x7e, /* 01111110 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xf3, /* 11110011 */ 0x7e, /* 01111110 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 238 0xee 'î' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 239 0xef 'ï' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 240 0xf0 'ð' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 241 0xf1 'ñ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 242 0xf2 'ò' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 243 0xf3 'ó' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 244 0xf4 'ô' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 245 0xf5 'õ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 246 0xf6 'ö' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 247 0xf7 '÷' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 248 0xf8 'ø' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 249 0xf9 'ù' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 250 0xfa 'ú' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 251 0xfb 'û' */ 0x00, /* 00000000 */ 0x0f, /* 00001111 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0xec, /* 11101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x3c, /* 00111100 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 252 0xfc 'ü' */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 253 0xfd 'ý' */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x32, /* 00110010 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 254 0xfe 'þ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 255 0xff 'ÿ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ }; constexpr inline u32 FontDrawTable[16][4] = { { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x00000000, 0x00ffffff }, { 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 }, { 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff }, { 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 }, { 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff }, { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 }, { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff }, { 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 }, { 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff }, { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 }, { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff }, { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 }, { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff }, { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 }, { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff } }; ================================================ FILE: exosphere/mariko_fatal/source/fatal_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_sdmmc.hpp" #include "fatal_save_context.hpp" #include "fatal_sound.hpp" #include "fatal_display.hpp" namespace ams::secmon::fatal { namespace { constexpr inline int I2cAddressMax77620Pmic = 0x3C; ALWAYS_INLINE const ams::impl::FatalErrorContext *GetFatalErrorContext() { return MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<ams::impl::FatalErrorContext>(); } } void Main() { /* Set library register addresses. */ actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress()); flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress()); fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress()); gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress()); i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress()); i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress()); pinmux::SetRegisterAddress(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress()); pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress()); se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress(), MemoryRegionVirtualDeviceSecurityEngine2.GetAddress()); uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress()); wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress()); util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress()); /* Ensure that the log library is initialized. */ log::Initialize(); AMS_SECMON_LOG("%s\n", "Fatal start."); /* Save the fatal error context. */ const auto *f_ctx = GetFatalErrorContext(); Result result = SaveFatalErrorContext(f_ctx); if (R_SUCCEEDED(result)) { AMS_SECMON_LOG("Saved fatal error context to /atmosphere/fatal_reports/report_%016" PRIx64 ".bin!\n", f_ctx->report_identifier); } else { AMS_SECMON_LOG("Failed to save fatal error context: %08x\n", result.GetValue()); } /* Ensure that i2c-1/i2c-5 are usable for communicating with the audio device/pmic. */ clkrst::EnableI2c1Clock(); clkrst::EnableI2c5Clock(); i2c::Initialize(i2c::Port_1); i2c::Initialize(i2c::Port_5); /* Shut down audio. */ { StopSound(); } /* Display the fatal error. */ { AMS_SECMON_LOG("Showing Display, LCD Vendor = %04x\n", GetLcdVendor()); InitializeDisplay(); ShowDisplay(f_ctx, result); } /* Ensure we have nothing waiting to be logged. */ AMS_LOG_FLUSH(); /* Wait for power button to be pressed. */ while (!pmic::IsPowerButtonPressed()) { util::WaitMicroSeconds(100); } /* Reboot. */ pmic::ShutdownSystem(true); /* Wait for our reboot to complete. */ AMS_INFINITE_LOOP(); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_print.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_display.hpp" #include "fatal_print.hpp" namespace ams::secmon::fatal { namespace { #include "fatal_font.inc" constexpr inline const u32 TextColor = 0xFFA0A0A0; constexpr inline const size_t ConsoleWidth = FrameBufferWidth / FontWidth; constexpr inline const size_t ConsoleHeight = FrameBufferHeight / FontHeight; constinit u32 *g_frame_buffer = nullptr; constinit size_t g_col = 1; constinit size_t g_row = 0; void SetPixel(size_t x, size_t y, u32 color) { g_frame_buffer[(FrameBufferWidth - x) * FrameBufferHeight + y] = color; } void PutCarriageReturn() { g_col = 1; } void PutNewLine() { g_col = 1; ++g_row; /* TODO: Support scrolling? */ } void PutCharImpl(const char c) { /* Get the character data for the font. */ const u8 * cdata = FontData + c * (FontHeight * util::DivideUp(FontWidth, BITSIZEOF(u8))); /* Determine where to start drawing. */ const size_t x = g_col * FontWidth; const size_t y = g_row * FontHeight; for (size_t cur_y = 0; cur_y < FontHeight; ++cur_y) { size_t cur_x = 0; int wbits = FontWidth; while (wbits > 0) { const auto bits = *(cdata++); SetPixel(x + cur_x + 0, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][0] & TextColor); SetPixel(x + cur_x + 1, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][1] & TextColor); SetPixel(x + cur_x + 2, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][2] & TextColor); SetPixel(x + cur_x + 3, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][3] & TextColor); SetPixel(x + cur_x + 4, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][0] & TextColor); SetPixel(x + cur_x + 5, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][1] & TextColor); SetPixel(x + cur_x + 6, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][2] & TextColor); SetPixel(x + cur_x + 7, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][3] & TextColor); cur_x += BITSIZEOF(u8); wbits -= BITSIZEOF(u8); } } } void PutChar(const char c) { switch (c) { case '\r': PutCarriageReturn(); break; case '\n': PutNewLine(); break; default: PutCharImpl(c); if ((++g_col) >= ConsoleWidth) { PutNewLine(); } } } } void InitializeConsole(u32 *frame_buffer) { /* Setup the console variables. */ g_frame_buffer = frame_buffer; g_col = 1; g_row = 0; /* Clear the console. */ std::memset(g_frame_buffer, 0, FrameBufferSize); } void Print(const char *fmt, ...) { /* Generate the string. */ char log_str[1_KB]; { std::va_list vl; va_start(vl, fmt); util::TVSNPrintf(log_str, sizeof(log_str), fmt, vl); va_end(vl); } /* Print each character. */ const size_t len = std::strlen(log_str); for (size_t i = 0; i < len; ++i) { PutChar(log_str[i]); } /* Flush the console. */ hw::FlushDataCache(g_frame_buffer, FrameBufferSize); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_print.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { void InitializeConsole(u32 *frame_buffer); void Print(const char *fmt, ...) __attribute__((format(printf, 1, 2))); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_registers_di.hpp ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018 CTCaer * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 #define SYNCPT_CNTRL_NO_STALL (1 << 8) #define SYNCPT_CNTRL_SOFT_RESET (1 << 0) #define DC_CMD_CONT_SYNCPT_VSYNC 0x28 #define SYNCPT_VSYNC_ENABLE (1 << 8) #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 #define DC_CMD_DISPLAY_COMMAND 0x32 #define DISP_CTRL_MODE_STOP (0 << 5) #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) #define DISP_CTRL_MODE_MASK (3 << 5) #define DC_CMD_DISPLAY_POWER_CONTROL 0x36 #define PW0_ENABLE (1 << 0) #define PW1_ENABLE (1 << 2) #define PW2_ENABLE (1 << 4) #define PW3_ENABLE (1 << 6) #define PW4_ENABLE (1 << 8) #define PM0_ENABLE (1 << 16) #define PM1_ENABLE (1 << 18) #define DC_CMD_INT_STATUS 0x37 #define DC_CMD_INT_MASK 0x38 #define DC_CMD_INT_ENABLE 0x39 #define DC_CMD_STATE_ACCESS 0x40 #define READ_MUX (1 << 0) #define WRITE_MUX (1 << 2) #define DC_CMD_STATE_CONTROL 0x41 #define GENERAL_ACT_REQ (1 << 0) #define WIN_A_ACT_REQ (1 << 1) #define WIN_B_ACT_REQ (1 << 2) #define WIN_C_ACT_REQ (1 << 3) #define CURSOR_ACT_REQ (1 << 7) #define GENERAL_UPDATE (1 << 8) #define WIN_A_UPDATE (1 << 9) #define WIN_B_UPDATE (1 << 10) #define WIN_C_UPDATE (1 << 11) #define CURSOR_UPDATE (1 << 15) #define NC_HOST_TRIG (1 << 24) #define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 #define WINDOW_A_SELECT (1 << 4) #define WINDOW_B_SELECT (1 << 5) #define WINDOW_C_SELECT (1 << 6) #define DC_CMD_REG_ACT_CONTROL 0x043 #define DC_COM_CRC_CONTROL 0x300 #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) #define DC_COM_DSC_TOP_CTL 0x33E #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) #define DSI_ENABLE (1 << 29) #define SOR1_TIMING_CYA (1 << 27) #define SOR1_ENABLE (1 << 26) #define SOR_ENABLE (1 << 25) #define CURSOR_ENABLE (1 << 16) #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 #define DC_DISP_DISP_TIMING_OPTIONS 0x405 #define DC_DISP_REF_TO_SYNC 0x406 #define DC_DISP_SYNC_WIDTH 0x407 #define DC_DISP_BACK_PORCH 0x408 #define DC_DISP_ACTIVE 0x409 #define DC_DISP_FRONT_PORCH 0x40A #define DC_DISP_DISP_CLOCK_CONTROL 0x42E #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) #define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) #define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) #define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) #define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) #define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) #define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) #define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) #define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) #define DC_DISP_DISP_INTERFACE_CONTROL 0x42F #define DISP_DATA_FORMAT_DF1P1C (0 << 0) #define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) #define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) #define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) #define DISP_DATA_FORMAT_DF2S (4 << 0) #define DISP_DATA_FORMAT_DF3S (5 << 0) #define DISP_DATA_FORMAT_DFSPI (6 << 0) #define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) #define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) #define DISP_ALIGNMENT_MSB (0 << 8) #define DISP_ALIGNMENT_LSB (1 << 8) #define DISP_ORDER_RED_BLUE (0 << 9) #define DISP_ORDER_BLUE_RED (1 << 9) #define DC_DISP_DISP_COLOR_CONTROL 0x430 #define DITHER_CONTROL_MASK (3 << 8) #define DITHER_CONTROL_DISABLE (0 << 8) #define DITHER_CONTROL_ORDERED (2 << 8) #define DITHER_CONTROL_ERRDIFF (3 << 8) #define BASE_COLOR_SIZE_MASK (0xf << 0) #define BASE_COLOR_SIZE_666 (0 << 0) #define BASE_COLOR_SIZE_111 (1 << 0) #define BASE_COLOR_SIZE_222 (2 << 0) #define BASE_COLOR_SIZE_333 (3 << 0) #define BASE_COLOR_SIZE_444 (4 << 0) #define BASE_COLOR_SIZE_555 (5 << 0) #define BASE_COLOR_SIZE_565 (6 << 0) #define BASE_COLOR_SIZE_332 (7 << 0) #define BASE_COLOR_SIZE_888 (8 << 0) #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 #define SC1_H_QUALIFIER_NONE (1 << 16) #define SC0_H_QUALIFIER_NONE (1 << 0) #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 #define DE_SELECT_ACTIVE_BLANK (0 << 0) #define DE_SELECT_ACTIVE (1 << 0) #define DE_SELECT_ACTIVE_IS (2 << 0) #define DE_CONTROL_ONECLK (0 << 2) #define DE_CONTROL_NORMAL (1 << 2) #define DE_CONTROL_EARLY_EXT (2 << 2) #define DE_CONTROL_EARLY (3 << 2) #define DE_CONTROL_ACTIVE_BLANK (4 << 2) #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 #define DC_DISP_SD_BL_PARAMETERS 0x4D7 #define DC_DISP_SD_BL_CONTROL 0x4DC #define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_WIN_CSC_YOF 0x611 #define DC_WIN_CSC_KYRGB 0x612 #define DC_WIN_CSC_KUR 0x613 #define DC_WIN_CSC_KVR 0x614 #define DC_WIN_CSC_KUG 0x615 #define DC_WIN_CSC_KVG 0x616 #define DC_WIN_CSC_KUB 0x617 #define DC_WIN_CSC_KVB 0x618 #define DC_WIN_AD_WIN_OPTIONS 0xB80 #define DC_WIN_BD_WIN_OPTIONS 0xD80 #define DC_WIN_CD_WIN_OPTIONS 0xF80 // The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). #define DC_WIN_WIN_OPTIONS 0x700 #define H_DIRECTION (1 << 0) #define V_DIRECTION (1 << 2) #define SCAN_COLUMN (1 << 4) #define COLOR_EXPAND (1 << 6) #define CSC_ENABLE (1 << 18) #define WIN_ENABLE (1 << 30) #define DC_WIN_COLOR_DEPTH 0x703 #define WIN_COLOR_DEPTH_P1 0x0 #define WIN_COLOR_DEPTH_P2 0x1 #define WIN_COLOR_DEPTH_P4 0x2 #define WIN_COLOR_DEPTH_P8 0x3 #define WIN_COLOR_DEPTH_B4G4R4A4 0x4 #define WIN_COLOR_DEPTH_B5G5R5A 0x5 #define WIN_COLOR_DEPTH_B5G6R5 0x6 #define WIN_COLOR_DEPTH_AB5G5R5 0x7 #define WIN_COLOR_DEPTH_B8G8R8A8 0xC #define WIN_COLOR_DEPTH_R8G8B8A8 0xD #define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE #define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF #define WIN_COLOR_DEPTH_YCbCr422 0x10 #define WIN_COLOR_DEPTH_YUV422 0x11 #define WIN_COLOR_DEPTH_YCbCr420P 0x12 #define WIN_COLOR_DEPTH_YUV420P 0x13 #define WIN_COLOR_DEPTH_YCbCr422P 0x14 #define WIN_COLOR_DEPTH_YUV422P 0x15 #define WIN_COLOR_DEPTH_YCbCr422R 0x16 #define WIN_COLOR_DEPTH_YUV422R 0x17 #define WIN_COLOR_DEPTH_YCbCr422RA 0x18 #define WIN_COLOR_DEPTH_YUV422RA 0x19 #define DC_WIN_BUFFER_CONTROL 0x702 #define DC_WIN_POSITION 0x704 #define DC_WIN_SIZE 0x705 #define H_SIZE(x) (((x) & 0x1fff) << 0) #define V_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_PRESCALED_SIZE 0x706 #define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) #define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_H_INITIAL_DDA 0x707 #define DC_WIN_V_INITIAL_DDA 0x708 #define DC_WIN_DDA_INC 0x709 #define H_DDA_INC(x) (((x) & 0xffff) << 0) #define V_DDA_INC(x) (((x) & 0xffff) << 16) #define DC_WIN_LINE_STRIDE 0x70A #define LINE_STRIDE(x) (x) #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E // The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 #define DC_WINBUF_ADDR_V_OFFSET 0x808 #define DC_WINBUF_SURFACE_KIND 0x80B #define PITCH (0 << 0) #define TILED (1 << 0) #define BLOCK (2 << 0) #define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) /*! Display serial interface registers. */ #define _DSIREG(reg) ((reg) * 4) #define DSI_INCR_SYNCPT_CNTRL 0x1 #define DSI_RD_DATA 0x9 #define DSI_WR_DATA 0xA #define DSI_POWER_CONTROL 0xB #define DSI_POWER_CONTROL_ENABLE 1 #define DSI_INT_ENABLE 0xC #define DSI_INT_STATUS 0xD #define DSI_INT_MASK 0xE #define DSI_HOST_CONTROL 0xF #define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) #define DSI_HOST_CONTROL_CRC_RESET (1 << 20) #define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) #define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) #define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) #define DSI_HOST_CONTROL_RAW (1 << 6) #define DSI_HOST_CONTROL_HS (1 << 5) #define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) #define DSI_HOST_CONTROL_IMM_BTA (1 << 3) #define DSI_HOST_CONTROL_PKT_BTA (1 << 2) #define DSI_HOST_CONTROL_CS (1 << 1) #define DSI_HOST_CONTROL_ECC (1 << 0) #define DSI_CONTROL 0x10 #define DSI_CONTROL_HS_CLK_CTRL (1 << 20) #define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) #define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) #define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) #define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) #define DSI_CONTROL_DCS_ENABLE (1 << 3) #define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) #define DSI_CONTROL_VIDEO_ENABLE (1 << 1) #define DSI_CONTROL_HOST_ENABLE (1 << 0) #define DSI_SOL_DELAY 0x11 #define DSI_MAX_THRESHOLD 0x12 #define DSI_TRIGGER 0x13 #define DSI_TRIGGER_HOST (1 << 1) #define DSI_TRIGGER_VIDEO (1 << 0) #define DSI_TX_CRC 0x14 #define DSI_STATUS 0x15 #define DSI_INIT_SEQ_CONTROL 0x1A #define DSI_INIT_SEQ_DATA_0 0x1B #define DSI_INIT_SEQ_DATA_1 0x1C #define DSI_INIT_SEQ_DATA_2 0x1D #define DSI_INIT_SEQ_DATA_3 0x1E #define DSI_PKT_SEQ_0_LO 0x23 #define DSI_PKT_SEQ_0_HI 0x24 #define DSI_PKT_SEQ_1_LO 0x25 #define DSI_PKT_SEQ_1_HI 0x26 #define DSI_PKT_SEQ_2_LO 0x27 #define DSI_PKT_SEQ_2_HI 0x28 #define DSI_PKT_SEQ_3_LO 0x29 #define DSI_PKT_SEQ_3_HI 0x2A #define DSI_PKT_SEQ_4_LO 0x2B #define DSI_PKT_SEQ_4_HI 0x2C #define DSI_PKT_SEQ_5_LO 0x2D #define DSI_PKT_SEQ_5_HI 0x2E #define DSI_DCS_CMDS 0x33 #define DSI_PKT_LEN_0_1 0x34 #define DSI_PKT_LEN_2_3 0x35 #define DSI_PKT_LEN_4_5 0x36 #define DSI_PKT_LEN_6_7 0x37 #define DSI_PHY_TIMING_0 0x3C #define DSI_PHY_TIMING_1 0x3D #define DSI_PHY_TIMING_2 0x3E #define DSI_BTA_TIMING 0x3F #define DSI_TIMEOUT_0 0x44 #define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) #define DSI_TIMEOUT_1 0x45 #define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) #define DSI_TO_TALLY 0x46 #define DSI_PAD_CONTROL_0 0x4B #define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) #define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) #define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) #define DSI_PAD_CONTROL_CD 0x4c #define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_PAD_CONTROL_1 0x4F #define DSI_PAD_CONTROL_2 0x50 #define DSI_PAD_CONTROL_3 0x51 #define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) #define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) #define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) #define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) #define DSI_PAD_CONTROL_4 0x52 #define DSI_PAD_CONTROL_5_MARIKO 0x53 #define DSI_PAD_CONTROL_6_MARIKO 0x54 #define DSI_PAD_CONTROL_7_MARIKO 0x55 #define DSI_INIT_SEQ_DATA_15 0x5F #define DSI_INIT_SEQ_DATA_15_MARIKO 0x62 ================================================ FILE: exosphere/mariko_fatal/source/fatal_save_context.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_save_context.hpp" #include "fatal_sdmmc.hpp" #include "fs/fatal_fs_api.hpp" namespace ams::secmon::fatal { Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx) { /* Initialize the sdmmc driver. */ R_TRY(InitializeSdCard()); /* Get the connection status. */ #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) { sdmmc::SpeedMode speed_mode; sdmmc::BusWidth bus_width; R_TRY(CheckSdCardConnection(std::addressof(speed_mode), std::addressof(bus_width))); AMS_SECMON_LOG("Sd Card Connection:\n"); AMS_SECMON_LOG(" Speed Mode: %u\n", static_cast<u32>(speed_mode)); AMS_SECMON_LOG(" Bus Width: %u\n", static_cast<u32>(bus_width)); } #endif /* Mount the SD card. */ R_UNLESS(fs::MountSdCard(), fs::ResultPartitionNotFound()); /* Unmount the SD card once we're done. */ ON_SCOPE_EXIT { fs::UnmountSdCard(); }; /* Create and open the file. */ fs::FileHandle file; { /* Generate the file path. */ char path[0x40]; util::TSNPrintf(path, sizeof(path), "/atmosphere/fatal_errors/report_%016" PRIx64 ".bin", ctx->report_identifier); /* Create the file. */ R_TRY(fs::CreateFile(path, sizeof(*ctx))); /* Open the file. */ R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_ReadWrite)); } /* Ensure we close the file when done with it. */ ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Write the context to the file. */ R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush)); R_SUCCEED(); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_save_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_sdmmc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_device_page_table.hpp" namespace ams::secmon::fatal { namespace { constexpr inline auto Port = sdmmc::Port_SdCard0; ALWAYS_INLINE u8 *GetSdCardWorkBuffer() { return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>() + MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize; } ALWAYS_INLINE u8 *GetSdCardDmaBuffer() { return MemoryRegionVirtualDramSdmmcMappedData.GetPointer<u8>(); } constexpr inline size_t SdCardDmaBufferSize = MemoryRegionVirtualDramSdmmcMappedData.GetSize() - mmu::PageSize; constexpr inline size_t SdCardDmaBufferSectors = SdCardDmaBufferSize / sdmmc::SectorSize; static_assert(util::IsAligned(SdCardDmaBufferSize, sdmmc::SectorSize)); } Result InitializeSdCard() { /* Map main memory for the sdmmc device. */ InitializeDevicePageTableForSdmmc1(); /* Initialize sdmmc library. */ sdmmc::Initialize(Port); sdmmc::SetSdCardWorkBuffer(Port, GetSdCardWorkBuffer(), sdmmc::SdCardWorkBufferSize); //sdmmc::Deactivate(Port); R_TRY(sdmmc::Activate(Port)); R_SUCCEED(); } Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) { R_RETURN(sdmmc::CheckSdCardConnection(out_sm, out_bw, Port)); } Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) { /* Validate that our buffer is valid. */ AMS_ASSERT(size >= sector_count * sdmmc::SectorSize); AMS_UNUSED(size); /* Repeatedly read sectors. */ u8 *dst_u8 = static_cast<u8 *>(dst); void * const dma_buffer = GetSdCardDmaBuffer(); while (sector_count > 0) { /* Read sectors into the DMA buffer. */ const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors); const size_t cur_size = cur_sectors * sdmmc::SectorSize; R_TRY(sdmmc::Read(dma_buffer, cur_size, Port, sector_index, cur_sectors)); /* Copy data from the DMA buffer to the output. */ std::memcpy(dst_u8, dma_buffer, cur_size); /* Advance. */ dst_u8 += cur_size; sector_index += cur_sectors; sector_count -= cur_sectors; } R_SUCCEED(); } Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) { /* Validate that our buffer is valid. */ AMS_ASSERT(size >= sector_count * sdmmc::SectorSize); AMS_UNUSED(size); /* Repeatedly read sectors. */ const u8 *src_u8 = static_cast<const u8 *>(src); void * const dma_buffer = GetSdCardDmaBuffer(); while (sector_count > 0) { /* Copy sectors into the DMA buffer. */ const size_t cur_sectors = std::min(sector_count, SdCardDmaBufferSectors); const size_t cur_size = cur_sectors * sdmmc::SectorSize; std::memcpy(dma_buffer, src_u8, cur_size); /* Write sectors to the sd card. */ R_TRY(sdmmc::Write(Port, sector_index, cur_sectors, dma_buffer, cur_size)); /* Advance. */ src_u8 += cur_size; sector_index += cur_sectors; sector_count -= cur_sectors; } R_SUCCEED(); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_sdmmc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { Result InitializeSdCard(); Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw); Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count); Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_sdmmc_c.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_sdmmc_c.h" #include "fatal_sdmmc.hpp" bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) { return R_SUCCEEDED(ams::secmon::fatal::ReadSdCard(dst, size, sector_index, sector_count)); } bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size) { return R_SUCCEEDED(ams::secmon::fatal::WriteSdCard(sector_index, sector_count, src, size)); } ================================================ FILE: exosphere/mariko_fatal/source/fatal_sdmmc_c.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stdint.h> #ifdef __cplusplus extern "C" { #endif bool sdmmc_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count); bool sdmmc_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size); #ifdef __cplusplus } #endif ================================================ FILE: exosphere/mariko_fatal/source/fatal_sound.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fatal_sound.hpp" namespace ams::secmon::fatal { namespace { constexpr inline int I2cAddressMaxAlc5639 = 0x1C; constexpr inline uintptr_t GPIO = secmon::MemoryRegionVirtualDeviceGpio.GetAddress(); constexpr size_t GPIO_PORT7_CNF_1 = 0x604; constexpr size_t GPIO_PORT7_OE_1 = 0x614; constexpr size_t GPIO_PORT7_OUT_1 = 0x624; void WriteAlc5639Register(int r, u16 val) { i2c::Send(i2c::Port_1, I2cAddressMaxAlc5639, r, std::addressof(val), sizeof(val)); } } void StopSound() { /* Mute output to the speaker, setting left/right volume to 0 DB. */ WriteAlc5639Register(0x01, 0xC8C8); /* Mute output to headphones, setting left/right volume to 0 DB. */ WriteAlc5639Register(0x02, 0xC8C8); /* Clear all Power Management Control registers by writing 0x0000 to them. */ for (int r = 0x61; r <= 0x66; ++r) { WriteAlc5639Register(r, 0x0000); } /* Configure CodecLdoEn as GPIO. */ reg::SetBits(GPIO + GPIO_PORT7_CNF_1, (1u << 4)); /* Configure CodecLdoEn as Output. */ reg::SetBits(GPIO + GPIO_PORT7_OE_1, (1u << 4)); /* Wait 200 milliseconds for config to take effect. */ util::WaitMicroSeconds(200'000ul); /* Pull CodecLdoEn low. */ reg::ClearBits(GPIO + GPIO_PORT7_OUT_1, (1u << 4)); } } ================================================ FILE: exosphere/mariko_fatal/source/fatal_sound.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::fatal { void StopSound(); } ================================================ FILE: exosphere/mariko_fatal/source/fatfs/00history.txt ================================================ ---------------------------------------------------------------------------- Revision history of FatFs module ---------------------------------------------------------------------------- R0.00 (February 26, 2006) Prototype. R0.01 (April 29, 2006) The first release. R0.02 (June 01, 2006) Added FAT12 support. Removed unbuffered mode. Fixed a problem on small (<32M) partition. R0.02a (June 10, 2006) Added a configuration option (_FS_MINIMUM). R0.03 (September 22, 2006) Added f_rename(). Changed option _FS_MINIMUM to _FS_MINIMIZE. R0.03a (December 11, 2006) Improved cluster scan algorithm to write files fast. Fixed f_mkdir() creates incorrect directory on FAT32. R0.04 (February 04, 2007) Added f_mkfs(). Supported multiple drive system. Changed some interfaces for multiple drive system. Changed f_mountdrv() to f_mount(). R0.04a (April 01, 2007) Supported multiple partitions on a physical drive. Added a capability of extending file size to f_lseek(). Added minimization level 3. Fixed an endian sensitive code in f_mkfs(). R0.04b (May 05, 2007) Added a configuration option _USE_NTFLAG. Added FSINFO support. Fixed DBCS name can result FR_INVALID_NAME. Fixed short seek (<= csize) collapses the file object. R0.05 (August 25, 2007) Changed arguments of f_read(), f_write() and f_mkfs(). Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Fixed f_mkdir() on FAT32 creates incorrect directory. R0.05a (February 03, 2008) Added f_truncate() and f_utime(). Fixed off by one error at FAT sub-type determination. Fixed btr in f_read() can be mistruncated. Fixed cached sector is not flushed when create and close without write. R0.06 (April 01, 2008) Added fputc(), fputs(), fprintf() and fgets(). Improved performance of f_lseek() on moving to the same or following cluster. R0.07 (April 01, 2009) Merged Tiny-FatFs as a configuration option. (_FS_TINY) Added long file name feature. (_USE_LFN) Added multiple code page feature. (_CODE_PAGE) Added re-entrancy for multitask operation. (_FS_REENTRANT) Added auto cluster size selection to f_mkfs(). Added rewind option to f_readdir(). Changed result code of critical errors. Renamed string functions to avoid name collision. R0.07a (April 14, 2009) Septemberarated out OS dependent code on reentrant cfg. Added multiple sector size feature. R0.07c (June 21, 2009) Fixed f_unlink() can return FR_OK on error. Fixed wrong cache control in f_lseek(). Added relative path feature. Added f_chdir() and f_chdrive(). Added proper case conversion to extended character. R0.07e (November 03, 2009) Septemberarated out configuration options from ff.h to ffconf.h. Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Fixed name matching error on the 13 character boundary. Added a configuration option, _LFN_UNICODE. Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. R0.08 (May 15, 2010) Added a memory configuration option. (_USE_LFN = 3) Added file lock feature. (_FS_SHARE) Added fast seek feature. (_USE_FASTSEEK) Changed some types on the API, XCHAR->TCHAR. Changed .fname in the FILINFO structure on Unicode cfg. String functions support UTF-8 encoding files on Unicode cfg. R0.08a (August 16, 2010) Added f_getcwd(). (_FS_RPATH = 2) Added sector erase feature. (_USE_ERASE) Moved file lock semaphore table from fs object to the bss. Fixed f_mkfs() creates wrong FAT32 volume. R0.08b (January 15, 2011) Fast seek feature is also applied to f_read() and f_write(). f_lseek() reports required table size on creating CLMP. Extended format syntax of f_printf(). Ignores duplicated directory separators in given path name. R0.09 (September 06, 2011) f_mkfs() supports multiple partition to complete the multiple partition feature. Added f_fdisk(). R0.09a (August 27, 2012) Changed f_open() and f_opendir() reject null object pointer to avoid crash. Changed option name _FS_SHARE to _FS_LOCK. Fixed assertion failure due to OS/2 EA on FAT12/16 volume. R0.09b (January 24, 2013) Added f_setlabel() and f_getlabel(). R0.10 (October 02, 2013) Added selection of character encoding on the file. (_STRF_ENCODE) Added f_closedir(). Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) Added forced mount feature with changes of f_mount(). Improved behavior of volume auto detection. Improved write throughput of f_puts() and f_printf(). Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). Fixed f_write() can be truncated when the file size is close to 4GB. Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. R0.10a (January 15, 2014) Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) Added a configuration option of minimum sector size. (_MIN_SS) 2nd argument of f_rename() can have a drive number and it will be ignored. Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) Fixed f_close() invalidates the file object without volume lock. Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) R0.10b (May 19, 2014) Fixed a hard error in the disk I/O layer can collapse the directory entry. Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) R0.10c (November 09, 2014) Added a configuration option for the platforms without RTC. (_FS_NORTC) Changed option name _USE_ERASE to _USE_TRIM. Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) Fixed a potential problem of FAT access that can appear on disk error. Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) R0.11 (February 09, 2015) Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) R0.11a (September 05, 2015) Fixed wrong media change can lead a deadlock at thread-safe configuration. Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). Fixed errors in the case conversion teble of Unicode (cc*.c). R0.12 (April 12, 2016) Added support for exFAT file system. (_FS_EXFAT) Added f_expand(). (_USE_EXPAND) Changed some members in FINFO structure and behavior of f_readdir(). Added an option _USE_CHMOD. Removed an option _WORD_ACCESS. Fixed errors in the case conversion table of Unicode (cc*.c). R0.12a (July 10, 2016) Added support for creating exFAT volume with some changes of f_mkfs(). Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. f_forward() is available regardless of _FS_TINY. Fixed f_mkfs() creates wrong volume. (appeared at R0.12) Fixed wrong memory read in create_name(). (appeared at R0.12) Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. R0.12b (September 04, 2016) Made f_rename() be able to rename objects with the same name but case. Fixed an error in the case conversion teble of code page 866. (ff.c) Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) R0.12c (March 04, 2017) Improved write throughput at the fragmented file on the exFAT volume. Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) R0.13 (May 21, 2017) Changed heading character of configuration keywords "_" to "FF_". Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead. Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0) Improved cluster allocation time on stretch a deep buried cluster chain. Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3. Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous. Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12) Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) R0.13a (October 14, 2017) Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2) Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF). Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk(). Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09) Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c) Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) R0.13b (April 07, 2018) Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3) Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2) Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c) Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b) R0.13c (October 14, 2018) Supported stdint.h for C99 and later. (integer.h was included in ff.h) Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12) Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12) Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b) R0.14 (October 14, 2019) Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1) Changed some API functions, f_mkfs() and f_fdisk(). Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12) Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12) ================================================ FILE: exosphere/mariko_fatal/source/fatfs/00readme.txt ================================================ FatFs Module Source Files R0.14 FILES 00readme.txt This file. 00history.txt Revision history. ff.c FatFs module. ffconf.h Configuration file of FatFs module. ff.h Common include file for FatFs and application module. diskio.h Common include file for FatFs and disk I/O module. diskio.c An example of glue function to attach existing disk I/O module to FatFs. ffunicode.c Optional Unicode utility functions. ffsystem.c An example of optional O/S related functions. Low level disk I/O module is not included in this archive because the FatFs module is only a generic file system layer and it does not depend on any specific storage device. You need to provide a low level disk I/O module written to control the storage device that attached to the target system. ================================================ FILE: exosphere/mariko_fatal/source/fatfs/diskio.c ================================================ /*-----------------------------------------------------------------------*/ /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ /* This is an example of glue functions to attach various exsisting */ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ #include <stdbool.h> #include <string.h> #include "ff.h" /* Obtains integer types */ #include "diskio.h" /* Declarations of disk functions */ #include "ffconf.h" #include "../fatal_sdmmc_c.h" /*-----------------------------------------------------------------------*/ /* Get Drive Status */ /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return RES_OK; } /*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return RES_OK; } /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { switch (pdrv) { case 0: return sdmmc_read_sd_card(buff, count * 512, sector, count) ? RES_OK : RES_ERROR; default: return RES_PARERR; } } /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ #if FF_FS_READONLY == 0 DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { switch (pdrv) { case 0: return sdmmc_write_sd_card(sector, count, buff, count * 512) ? RES_OK : RES_ERROR; default: return RES_PARERR; } } #endif /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { return RES_OK; } ================================================ FILE: exosphere/mariko_fatal/source/fatfs/diskio.h ================================================ /*-----------------------------------------------------------------------/ / Low level disk interface modlue include file (C)ChaN, 2019 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED #define _DISKIO_DEFINED #ifdef __cplusplus extern "C" { #endif /* Status of Disk Functions */ typedef BYTE DSTATUS; /* Results of Disk Functions */ typedef enum { RES_OK = 0, /* 0: Successful */ RES_ERROR, /* 1: R/W Error */ RES_WRPRT, /* 2: Write Protected */ RES_NOTRDY, /* 3: Not Ready */ RES_PARERR /* 4: Invalid Parameter */ } DRESULT; /*---------------------------------------*/ /* Prototypes for disk control functions */ DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ #define STA_NODISK 0x02 /* No medium in the drive */ #define STA_PROTECT 0x04 /* Write protected */ /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_LOCK 6 /* Lock/Unlock media removal */ #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ #define MMC_GET_OCR 13 /* Get OCR */ #define MMC_GET_SDSTAT 14 /* Get SD status */ #define ISDIO_READ 55 /* Read data form SD iSDIO register */ #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ /* ATA/CF specific ioctl command */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ #ifdef __cplusplus } #endif #endif ================================================ FILE: exosphere/mariko_fatal/source/fatfs/ff.c ================================================ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem Module R0.14 / /-----------------------------------------------------------------------------/ / / Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- Module Private Definitions ---------------------------------------------------------------------------*/ #if FF_DEFINED != 86606 /* Revision ID */ #error Wrong include file (ff.h). #endif /* Limits and boundaries */ #define MAX_DIR 0x200000 /* Max size of FAT directory */ #define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ /* Character code support macros */ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsDigit(c) ((c) >= '0' && (c) <= '9') #define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) /* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ /* Additional file attribute bits for internal use */ #define AM_VOL 0x08 /* Volume label */ #define AM_LFN 0x0F /* LFN entry */ #define AM_MASK 0x3F /* Mask of defined bits */ /* Name status flags in fn[11] */ #define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ #define NS_NOLFN 0x40 /* Do not find LFN */ #define NS_NONAME 0x80 /* Not followed */ /* exFAT directory entry types */ #define ET_BITMAP 0x81 /* Allocation bitmap */ #define ET_UPCASE 0x82 /* Up-case table */ #define ET_VLABEL 0x83 /* Volume label */ #define ET_FILEDIR 0x85 /* File and directory */ #define ET_STREAM 0xC0 /* Stream extension */ #define ET_FILENAME 0xC1 /* Name extension */ /* FatFs refers the FAT structure as simple byte array instead of structure member / because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ #define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ #define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ #define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ #define BS_NTres 37 /* WindowsNT error flag (BYTE) */ #define BS_BootSig 38 /* Extended boot signature (BYTE) */ #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ #define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ #define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ #define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ #define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ #define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ #define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ #define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ #define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ #define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ #define DIR_NTres 12 /* Lower case flag (BYTE) */ #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ #define DIR_CrtTime 14 /* Created time (DWORD) */ #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ #define DIR_ModTime 22 /* Modified time (DWORD) */ #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ #define DIR_FileSize 28 /* File size (DWORD) */ #define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ #define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ #define LDIR_Type 12 /* LFN: Entry type (BYTE) */ #define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ #define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ #define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ #define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ #define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ #define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ #define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ #define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ #define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ #define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ #define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ #define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ #define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ #define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ #define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ #define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ #define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ #define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ #define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ #define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ #define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ #define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ #define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ #define SZDIRE 32 /* Size of a directory entry */ #define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ #define PTE_Boot 0 /* MBR PTE: Boot indicator */ #define PTE_StHead 1 /* MBR PTE: Start head */ #define PTE_StSec 2 /* MBR PTE: Start sector */ #define PTE_StCyl 3 /* MBR PTE: Start cylinder */ #define PTE_System 4 /* MBR PTE: System ID */ #define PTE_EdHead 5 /* MBR PTE: End head */ #define PTE_EdSec 6 /* MBR PTE: End sector */ #define PTE_EdCyl 7 /* MBR PTE: End cylinder */ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ #define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ #define GPTH_Rev 8 /* GPT: Revision (DWORD) */ #define GPTH_Size 12 /* GPT: Header size (DWORD) */ #define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ #define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ #define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ #define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ #define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ #define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ #define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ #define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ #define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ #define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ #define SZ_GPTE 128 /* GPT: Size of partition table entry */ #define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ #define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ #define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ #define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ #define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ #define GPTE_Name 56 /* GPT PTE: Name */ /* Post process on fatal error in the file operations */ #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } /* Re-entrancy related */ #if FF_FS_REENTRANT #if FF_USE_LFN == 1 #error Static LFN work area cannot be used at thread-safe configuration #endif #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif /* Definitions of logical drive - physical location conversion */ #if FF_MULTI_PARTITION #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif /* Definitions of sector size */ #if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) #error Wrong sector size configuration #endif #if FF_MAX_SS == FF_MIN_SS #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ #else #define SS(fs) ((fs)->ssize) /* Variable sector size */ #endif /* Timestamp */ #if FF_FS_NORTC == 1 #if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 #error Invalid FF_FS_NORTC settings #endif #define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) #else #define GET_FATTIME() get_fattime() #endif /* File lock controls */ #if FF_FS_LOCK != 0 #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif /* SBCS up-case tables (\x80-\xFF) */ #define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} #define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} #define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} #define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} /* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ /* <------> <------> <------> <------> <------> */ #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} #define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} /* Macros for table definitions */ #define MERGE_2STR(a, b) a ## b #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) /*-------------------------------------------------------------------------- Module Private Work Area ---------------------------------------------------------------------------*/ /* Remark: Variables defined here without initial value shall be guaranteed / zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ /*--------------------------------*/ /* File/Volume controls */ /*--------------------------------*/ #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 static BYTE CurrVol; /* Current drive */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif #if FF_LBA64 #if FF_MIN_GPT > 0x100000000 #error Wrong FF_MIN_GPT setting #endif static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7}; #endif /*--------------------------------*/ /* LFN/Directory working buffer */ /*--------------------------------*/ #if FF_USE_LFN == 0 /* Non-LFN configuration */ #if FF_FS_EXFAT #error LFN must be enabled when enable exFAT #endif #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #else /* LFN configurations */ #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 #error Wrong setting of FF_MAX_LFN #endif #if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF #endif #if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 #error Wrong setting of FF_LFN_UNICODE #endif static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ #define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ #if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ #if FF_FS_EXFAT static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() #endif #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } #define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN #endif /* FF_USE_LFN == 1 */ #endif /* FF_USE_LFN == 0 */ /*--------------------------------*/ /* Code conversion tables */ /*--------------------------------*/ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct737[] = TBL_CT737; static const BYTE Ct771[] = TBL_CT771; static const BYTE Ct775[] = TBL_CT775; static const BYTE Ct850[] = TBL_CT850; static const BYTE Ct852[] = TBL_CT852; static const BYTE Ct855[] = TBL_CT855; static const BYTE Ct857[] = TBL_CT857; static const BYTE Ct860[] = TBL_CT860; static const BYTE Ct861[] = TBL_CT861; static const BYTE Ct862[] = TBL_CT862; static const BYTE Ct863[] = TBL_CT863; static const BYTE Ct864[] = TBL_CT864; static const BYTE Ct865[] = TBL_CT865; static const BYTE Ct866[] = TBL_CT866; static const BYTE Ct869[] = TBL_CT869; static const BYTE Dc932[] = TBL_DC932; static const BYTE Dc936[] = TBL_DC936; static const BYTE Dc949[] = TBL_DC949; static const BYTE Dc950[] = TBL_DC950; #elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); #else /* Static code page configuration (DBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); #endif /*-------------------------------------------------------------------------- Module Private Functions ---------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; rv = ptr[1]; rv = rv << 8 | ptr[0]; return rv; } static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; rv = ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #if FF_FS_EXFAT static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; rv = ptr[7]; rv = rv << 8 | ptr[6]; rv = rv << 8 | ptr[5]; rv = rv << 8 | ptr[4]; rv = rv << 8 | ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #endif #if !FF_FS_READONLY static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #if FF_FS_EXFAT static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #endif #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ /* Copy memory to memory */ static void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; if (cnt != 0) { do { *d++ = *s++; } while (--cnt); } } /* Fill memory block */ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; do { *d++ = (BYTE)val; } while (--cnt); } /* Compare memory block */ static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ { const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; do { r = *d++ - *s++; } while (--cnt && r == 0); return r; } /* Check if chr is contained in the string */ static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ { while (*str && *str != chr) str++; return *str; } /* Test if the byte is DBC 1st byte */ static int dbc_1st (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } /* Test if the byte is DBC 2nd byte */ static int dbc_2nd (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } #if FF_USE_LFN /* Get a Unicode code point from the TCHAR string in defined API encodeing */ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */ const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ ) { DWORD uc; const TCHAR *p = *str; #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; uc = *p++; /* Get a unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ uc = uc << 16 | wc; } #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ BYTE b; int nf; uc = (BYTE)*p++; /* Get an encoding unit */ if (uc & 0x80) { /* Multiple byte code? */ if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; } else { if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ uc &= 0x0F; nf = 2; } else { if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ uc &= 0x07; nf = 3; } else { /* Wrong sequence */ return 0xFFFFFFFF; } } } do { /* Get trailing bytes */ b = (BYTE)*p++; if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ uc = uc << 6 | (b & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ } #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ uc = (TCHAR)*p++; /* Get a unit */ if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ BYTE b; WCHAR wc; wc = (BYTE)*p++; /* Get a byte */ if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ b = (BYTE)*p++; /* Get 2nd byte */ if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ wc = (wc << 8) + b; /* Make a DBC */ } if (wc != 0) { wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ } uc = wc; #endif *str = p; /* Next read pointer */ return uc; } /* Output a TCHAR string in defined API encoding */ static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ ) { #if FF_LFN_UNICODE == 1 /* UTF-16 output */ WCHAR hs, wc; hs = (WCHAR)(chr >> 16); wc = (WCHAR)chr; if (hs == 0) { /* Single encoding unit? */ if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ *buf = wc; return 1; } if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ *buf++ = hs; *buf++ = wc; return 2; #elif FF_LFN_UNICODE == 2 /* UTF-8 output */ DWORD hc; if (chr < 0x80) { /* Single byte code? */ if (szb < 1) return 0; /* Buffer overflow? */ *buf = (TCHAR)chr; return 1; } if (chr < 0x800) { /* 2-byte sequence? */ if (szb < 2) return 0; /* Buffer overflow? */ *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 2; } if (chr < 0x10000) { /* 3-byte sequence? */ if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 3; } /* 4-byte sequence */ if (szb < 4) return 0; /* Buffer overflow? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 4; #elif FF_LFN_UNICODE == 3 /* UTF-32 output */ DWORD hc; if (szb < 1) return 0; /* Buffer overflow? */ if (chr >= 0x10000) { /* Out of BMP? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; } *buf++ = (TCHAR)chr; return 1; #else /* ANSI/OEM output */ WCHAR wc; wc = ff_uni2oem(chr, CODEPAGE); if (wc >= 0x100) { /* Is this a DBC? */ if (szb < 2) return 0; *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ return 2; } if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ *buf++ = (TCHAR)wc; /* Store the character */ return 1; #endif } #endif /* FF_USE_LFN */ #if FF_FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ static int lock_fs ( /* 1:Ok, 0:timeout */ FATFS* fs /* Filesystem object */ ) { return ff_req_grant(fs->sobj); } static void unlock_fs ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { ff_rel_grant(fs->sobj); } } #endif #if FF_FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ static FRESULT chk_lock ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) { UINT i, be; /* Search open object table for the object */ be = 0; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } if (i == FF_FS_LOCK) { /* The object has not been opened */ return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ } /* The object was opened. Reject any open against writing file and all write mode open */ return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; return (i == FF_FS_LOCK) ? 0 : 1; } static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ if (Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; Files[i].ofs = dp->dptr; Files[i].ctr = 0; } if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ return i + 1; /* Index number origin from 1 */ } static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { WORD n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { res = FR_INT_ERR; /* Invalid index nunber */ } return res; } static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs == fs) Files[i].fs = 0; } } #endif /* FF_FS_LOCK != 0 */ /*-----------------------------------------------------------------------*/ /* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res = FR_OK; if (fs->wflag) { /* Is the disk access window dirty? */ if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write it back into the volume */ fs->wflag = 0; /* Clear window dirty flag */ if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } } else { res = FR_DISK_ERR; } } return res; } #endif static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector LBA to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; if (sect != fs->winsect) { /* Window offset changed? */ #if !FF_FS_READONLY res = sync_window(fs); /* Flush the window */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) { sect = (LBA_t)0 - 1; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sect; } } return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res; res = sync_window(fs); if (res == FR_OK) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); st_dword(fs->win + FSI_Free_Count, fs->free_clst); st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; disk_write(fs->pdrv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; } #endif /*-----------------------------------------------------------------------*/ /* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ static LBA_t clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { clst -= 2; /* Cluster number is origin from 2 */ if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ return fs->database + (LBA_t)fs->csize * clst; /* Start sector number of the cluster */ } /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; DWORD val; FATFS *fs = obj->fs; if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ val = 1; /* Internal error */ } else { val = 0xFFFFFFFF; /* Default value falls on disk error */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; #if FF_FS_EXFAT case FS_EXFAT : if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((LBA_t)((obj->objsize - 1) / SS(fs)) / fs->csize); /* Number of clusters - 1 */ if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ break; } if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ if (obj->n_frag != 0) { /* Is it on the growing edge? */ val = 0x7FFFFFFF; /* Generate EOC */ } else { if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; } break; } } /* go to default */ #endif default: val = 1; /* Internal error */ } } return val; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) { UINT bc; BYTE *p; FRESULT res = FR_INT_ERR; if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Update 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Update 2nd byte */ fs->wflag = 1; break; case FS_FAT16 : res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; case FS_FAT32 : #if FF_FS_EXFAT case FS_EXFAT : #endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } st_dword(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } } return res; } #endif /* !FF_FS_READONLY */ #if FF_FS_EXFAT && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ /*--------------------------------------*/ /* Find a contiguous free cluster block */ /*--------------------------------------*/ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ ) { BYTE bm, bv; UINT i; DWORD val, scl, ctr; clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ val = 0; bm = 0; i = SS(fs); } if (bv == 0) { /* Is it a free cluster? */ if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ } while (bm != 0); bm = 1; } while (++i < SS(fs)); } } /*----------------------------------------*/ /* Set/Clear a block of allocation bitmap */ /*----------------------------------------*/ static FRESULT change_bitmap ( FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ int bv /* bit value to be set (0 or 1) */ ) { BYTE bm; UINT i; LBA_t sect; clst -= 2; /* The first bit corresponds to cluster #2 */ sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ i = clst / 8 % SS(fs); /* Byte offset in the sector */ bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { do { if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ fs->win[i] ^= bm; /* Flip the bit */ fs->wflag = 1; if (--ncl == 0) return FR_OK; /* All bits processed? */ } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ i = 0; } } /*---------------------------------------------*/ /* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_first_frag ( FFOBJID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; } obj->stat = 0; /* Change status 'FAT chain is valid' */ } return FR_OK; } /*---------------------------------------------*/ /* Fill the last fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_last_frag ( FFOBJID* obj, /* Pointer to the corresponding object */ DWORD lcl, /* Last cluster of the fragment */ DWORD term /* Value to set the last FAT entry */ ) { FRESULT res; while (obj->n_frag > 0) { /* Create the chain of last fragment */ res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); if (res != FR_OK) return res; obj->n_frag--; } return FR_OK; } #endif /* FF_FS_EXFAT && !FF_FS_READONLY */ #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; DWORD nxt; FATFS *fs = obj->fs; #if FF_FS_EXFAT || FF_USE_TRIM DWORD scl = clst, ecl = clst; #endif #if FF_USE_TRIM LBA_t rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ /* Mark the previous cluster 'EOC' on the FAT if it exists */ if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { res = put_fat(fs, pclst, 0xFFFFFFFF); if (res != FR_OK) return res; } /* Remove the chain */ do { nxt = get_fat(obj, clst); /* Get cluster status */ if (nxt == 0) break; /* Empty cluster? */ if (nxt == 1) return FR_INT_ERR; /* Internal error? */ if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } #if FF_FS_EXFAT || FF_USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; } else { /* End of contiguous cluster block */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ if (res != FR_OK) return res; } #endif #if FF_USE_TRIM rt[0] = clst2sect(fs, scl); /* Start of data area to be freed */ rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area to be freed */ disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform storage device that the data in the block may be erased */ #endif scl = ecl = nxt; } #endif clst = nxt; /* Next cluster */ } while (clst < fs->n_fatent); /* Repeat while not the last link */ #if FF_FS_EXFAT /* Some post processes for chain status */ if (fs->fs_type == FS_EXFAT) { if (pclst == 0) { /* Has the entire chain been removed? */ obj->stat = 0; /* Change the chain status 'initial' */ } else { if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ while (clst != pclst) { nxt = get_fat(obj, clst); if (nxt < 2) return FR_INT_ERR; if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; if (nxt != clst + 1) break; /* Not contiguous? */ clst++; } if (clst == pclst) { /* Has the chain got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } else { if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } } } #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { DWORD cs, ncl, scl; FRESULT res; FATFS *fs = obj->fs; if (clst == 0) { /* Create a new chain */ scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ if (cs < 2) return 1; /* Test for insanity */ if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; /* Cluster to start to find */ } if (fs->free_clst == 0) return 0; /* No free cluster */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ obj->stat = 2; /* Set status 'contiguous' */ } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } if (obj->stat != 2) { /* Is the file non-contiguous? */ if (ncl == clst + 1) { /* Is the cluster next to previous one? */ obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ } else { /* New fragment */ if (obj->n_frag == 0) obj->n_frag = 1; res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ if (res == FR_OK) obj->n_frag = 1; } } } else #endif { /* On the FAT/FAT32 volume */ ncl = 0; if (scl == clst) { /* Stretching an existing chain? */ ncl = scl + 1; /* Test if next cluster is free */ if (ncl >= fs->n_fatent) ncl = 2; cs = get_fat(obj, ncl); /* Get next cluster status */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (cs != 0) { /* Not free? */ cs = fs->last_clst; /* Start at suggested cluster if it is valid */ if (cs >= 2 && cs < fs->n_fatent) scl = cs; ncl = 0; } } if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ if (ncl >= fs->n_fatent) { /* Check wrap-around */ ncl = 2; if (ncl > scl) return 0; /* No free cluster found? */ } cs = get_fat(obj, ncl); /* Get the cluster status */ if (cs == 0) break; /* Found a free cluster? */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (ncl == scl) return 0; /* No free cluster found? */ } } res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } #endif /* !FF_FS_READONLY */ #if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { DWORD cl, ncl, *tbl; FATFS *fs = fp->obj.fs; tbl = fp->cltbl + 1; /* Top of CLMT */ cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ for (;;) { ncl = *tbl++; /* Number of cluters in the fragment */ if (ncl == 0) return 0; /* End of table? (error) */ if (cl < ncl) break; /* In this fragment? */ cl -= ncl; tbl++; /* Next fragment */ } return cl + *tbl; /* Return the cluster number */ } #endif /* FF_USE_FASTSEEK */ /*-----------------------------------------------------------------------*/ /* Directory handling - Fill a cluster with zeros */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ FATFS *fs, /* Filesystem object */ DWORD clst /* Directory table to clear */ ) { LBA_t sect; UINT n, szb; BYTE *ibuf; if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ sect = clst2sect(fs, clst); /* Top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */ mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ /* Allocate a temporary buffer */ for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; if (szb > SS(fs)) { /* Buffer allocated? */ mem_set(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ ff_memfree(ibuf); } else #endif { ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ } return (n == fs->csize) ? FR_OK : FR_DISK_ERR; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) { DWORD csz, clst; FATFS *fs = dp->obj.fs; if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; } dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ clst = (DWORD)fs->dirbase; if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } if (clst == 0) { /* Static table (root-directory on the FAT volume) */ if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ dp->sect = fs->dirbase; } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ while (ofs >= csz) { /* Follow cluster chain */ clst = get_fat(&dp->obj, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ ofs -= csz; } dp->sect = clst2sect(fs, clst); } dp->clust = clst; /* Current cluster# */ if (dp->sect == 0) return FR_INT_ERR; dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ return FR_OK; } /*-----------------------------------------------------------------------*/ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ DIR* dp, /* Pointer to the directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs; ofs = dp->dptr + SZDIRE; /* Next entry */ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ #if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ dp->sect = clst2sect(fs, clst); } } } dp->dptr = ofs; /* Current entry */ dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ return FR_OK; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to the directory object */ UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; UINT n; FATFS *fs = dp->obj.fs; res = dir_sdi(dp, 0); if (res == FR_OK) { n = 0; do { res = move_window(fs, dp->sect); if (res != FR_OK) break; #if FF_FS_EXFAT if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { #endif if (++n == nent) break; /* A block of contiguous free entries is found */ } else { n = 0; /* Not a blank entry. Restart to search */ } res = dir_next(dp, 1); } while (res == FR_OK); /* Next entry with table stretch enabled */ } if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ FATFS* fs, /* Pointer to the fs object */ const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; cl = ld_word(dir + DIR_FstClusLO); if (fs->fs_type == FS_FAT32) { cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; } return cl; } #if !FF_FS_READONLY static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ ) { st_word(dir + DIR_FstClusLO, (WORD)cl); if (fs->fs_type == FS_FAT32) { st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); } } #endif #if FF_USE_LFN /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ return 1; /* The part of LFN matched */ } #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } return 1; /* The part of LFN is valid */ } #endif #if !FF_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ BYTE sum /* Checksum of the corresponding SFN */ ) { UINT i, s; WCHAR wc; dir[LDIR_Chksum] = sum; /* Set checksum */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Type] = 0; st_word(dir + LDIR_FstClusLO, 0); i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ s = wc = 0; do { if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ st_word(dir + LfnOfs[s], wc); /* Put it */ if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ } while (++s < 13); if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LFN */ #if FF_USE_LFN && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ UINT seq /* Sequence number */ ) { BYTE ns[8], c; UINT i, j; WCHAR wc; DWORD sreg; mem_cpy(dst, src, 11); if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sreg = seq; while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sreg = (sreg << 1) + (wc & 1); wc >>= 1; if (sreg & 0x10000) sreg ^= 0x11021; } } seq = (UINT)sreg; } /* itoa (hexdecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); if (c > '9') c += 7; ns[i--] = c; seq /= 16; } while (seq); ns[i] = '~'; /* Append the number to the SFN body */ for (j = 0; j < i && dst[j] != ' '; j++) { if (dbc_1st(dst[j])) { if (j == i - 1) break; j++; } } do { dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } #endif /* FF_USE_LFN && !FF_FS_READONLY */ #if FF_USE_LFN /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { BYTE sum = 0; UINT n = 11; do { sum = (sum >> 1) + (sum << 7) + *dir++; } while (--n); return sum; } #endif /* FF_USE_LFN */ #if FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { UINT i, szblk; WORD sum; szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; } } return sum; } static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { WCHAR chr; WORD sum = 0; while ((chr = *name++) != 0) { chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } return sum; } #if !FF_FS_READONLY && FF_USE_MKFS static DWORD xsum32 ( /* Returns 32-bit checksum */ BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; return sum; } #endif #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { WCHAR wc, hs; UINT di, si, nc; /* Get file name from the entry block */ si = SZDIRE * 2; /* 1st C1 entry */ nc = 0; hs = 0; di = 0; while (nc < dirb[XDIR_NumName]) { if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Load stream-extension entry */ res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Load file-name entries */ i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ if (i <= MAXDIRB(FF_MAX_LFN)) { if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; } return FR_OK; } /*------------------------------------------------------------------*/ /* exFAT: Initialize object allocation info with loaded entry block */ /*------------------------------------------------------------------*/ static void init_alloc_info ( FATFS* fs, /* Filesystem object */ FFOBJID* obj /* Object allocation information to be initialized */ ) { obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ obj->n_frag = 0; /* No last fragment info */ } #if !FF_FS_READONLY || FF_FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_xdir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ const FFOBJID* obj /* Object with its containing directory information */ ) { FRESULT res; /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } return res; } #endif #if !FF_FS_READONLY /*----------------------------------------*/ /* exFAT: Store the directory entry block */ /*----------------------------------------*/ static FRESULT store_xdir ( DIR* dp /* Pointer to the direcotry object */ ) { FRESULT res; UINT nent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; /* Store the direcotry entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; mem_cpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; if (--nent == 0) break; dirb += SZDIRE; res = dir_next(dp, 0); } return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; } /*-------------------------------------------*/ /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; BYTE nc1, nlen; WCHAR wc; /* Create file-directory and stream-extension entry */ mem_set(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; /* Create file-name entries */ i = SZDIRE * 2; /* Top of file_name entries */ nlen = nc1 = 0; wc = 1; do { dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ st_word(dirb + i, wc); /* Store it */ i += 2; } while (i % SZDIRE != 0); nc1++; } while (lfn[nlen]); /* Fill next entry if any char follows */ dirb[XDIR_NumName] = nlen; /* Set name length */ dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_EXFAT */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ #define DIR_READ_FILE(dp) dir_read(dp, 0) #define DIR_READ_LABEL(dp) dir_read(dp, 1) static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; BYTE attr, b; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; b = dp->dir[DIR_Name]; /* Test for the entry type */ if (b == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { if (b == ET_VLABEL) break; /* Volume label entry? */ } else { if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ } break; } } } else #endif { /* On the FAT/FAT32 volume */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { if (attr == AM_LFN) { /* An LFN entry is found */ if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } } #else /* Non LFN configuration */ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif } res = dir_next(dp, 0); /* Next entry */ if (res != FR_OK) break; } if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ return res; } #endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ /*-----------------------------------------------------------------------*/ /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; #if FF_USE_LFN BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } return res; } #endif /* On the FAT/FAT32 volume */ #if FF_USE_LFN ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ #if FF_USE_LFN /* LFN configuration */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ sum = dp->dir[LDIR_Chksum]; c &= (BYTE)~LLEF; ord = c; /* LFN start order */ dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ UINT n, nlen, nent; BYTE sn[12], sum; if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ dp->obj.stat &= ~4; res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ DIR dj; res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } } create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif /* On the FAT/FAT32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } if (n == 100) return FR_DENIED; /* Abort if too many collisions */ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ dp->fn[NSFLAG] = sn[NSFLAG]; } /* Create an SFN with/without LFNs. */ nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ res = dir_alloc(dp, nent); /* Allocate entries */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */ res = dir_sdi(dp, dp->dptr - nent * SZDIRE); if (res == FR_OK) { sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); } } #else /* Non LFN configuration */ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ #endif /* Set SFN entry */ if (res == FR_OK) { res = move_window(fs, dp->sect); if (res == FR_OK) { mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif fs->wflag = 1; } } return res; } #endif /* !FF_FS_READONLY */ #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ DWORD last = dp->dptr; res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { res = move_window(fs, dp->sect); if (res != FR_OK) break; if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ } else { /* On the FAT/FAT32 volume */ dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR; } #else /* Non LFN configuration */ res = move_window(fs, dp->sect); if (res == FR_OK) { dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ fs->wflag = 1; } #endif return res; } #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ static void get_fileinfo ( DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { UINT si, di; #if FF_USE_LFN BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else TCHAR c; #endif fno->fname[0] = 0; /* Invaidate file info */ if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ #if FF_USE_LFN /* LFN configuration */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ get_xfileinfo(fs->dirbuf, fno); return; } else #endif { /* On the FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ si = di = hs = 0; while (fs->lfnbuf[si] != 0) { wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ } } si = di = 0; while (si < 11) { /* Get SFN from SFN entry */ wc = dp->dir[si++]; /* Get a char */ if (wc == ' ') continue; /* Skip padding spaces */ if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ #if FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ if (wc == 0) { di = 0; break; } /* Buffer overflow? */ di += wc; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; if (wc == '.') lcf = NS_EXT; if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } fno->fname[di] = 0; /* Terminate the LFN */ if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ } #else /* Non-LFN configuration */ si = di = 0; while (si < 11) { /* Copy name body and extension */ c = (TCHAR)dp->dir[si++]; if (c == ' ') continue; /* Skip padding spaces */ if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ fno->fname[di++] = c; } fno->fname[di] = 0; #endif fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ static DWORD get_achar ( /* Get a character and advances ptr */ const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { DWORD chr; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ chr = tchar2uni(ptr); if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ chr = ff_wtoupper(chr); #else /* ANSI/OEM input */ chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ #if FF_CODE_PAGE == 0 if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #elif FF_CODE_PAGE < 900 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #endif #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; } #endif #endif return chr; } static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ int inf /* Infinite search (* specified) */ ) { const TCHAR *pp, *np; DWORD pc, nc; int nm, nx; while (skip--) { /* Pre-skip name chars */ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ } if (*pat == 0 && inf) return 1; /* (short circuit) */ do { pp = pat; np = nam; /* Top of pattern and name to match */ for (;;) { if (*pp == '?' || *pp == '*') { /* Wildcard? */ nm = nx = 0; do { /* Analyze the wildcard block */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ nc = *np; break; /* Branch mismatched */ } pc = get_achar(&pp); /* Get a pattern char */ nc = get_achar(&np); /* Get a name char */ if (pc != nc) break; /* Branch mismatched? */ if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ } get_achar(&nam); /* nam++ */ } while (inf && nc); /* Retry until end of name if infinite search is specified */ return 0; } #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ /*-----------------------------------------------------------------------*/ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ DIR* dp, /* Pointer to the directory object */ const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; WCHAR wc, *lfn; DWORD uc; UINT i, ni, si, di; const TCHAR *p; /* Create LFN into LFN working buffer */ p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { uc = tchar2uni(&p); /* Get a character */ if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ wc = (WCHAR)uc; if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ lfn[di++] = wc; /* Store the Unicode character */ } if (wc < ' ') { /* End of path? */ cf = NS_LAST; /* Set last segment flag */ } else { cf = 0; /* Next segment follows */ while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ } *path = p; /* Return pointer to the next segment */ #if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; } dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif while (di) { /* Snip off trailing spaces and dots if exist */ wc = lfn[di - 1]; if (wc != ' ' && wc != '.') break; di--; } lfn[di] = 0; /* LFN is created into the working buffer */ if (di == 0) return FR_INVALID_NAME; /* Reject null name */ /* Create SFN in directory form */ for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ mem_set(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { wc = lfn[si++]; /* Get an LFN character */ if (wc == 0) break; /* Break on end of the LFN */ if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ cf |= NS_LOSS | NS_LFN; continue; } if (i >= ni || si == di) { /* End of field? */ if (ni == 11) { /* Name extension overflow? */ cf |= NS_LOSS | NS_LFN; break; } if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ if (si > di) break; /* No name extension? */ si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ continue; } if (wc >= 0x80) { /* Is this a non-ASCII character? */ cf |= NS_LFN; /* LFN entry needs to be created */ #if FF_CODE_PAGE == 0 if (ExCvt) { /* At SBCS */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ } else { /* At DBCS */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ } #elif FF_CODE_PAGE < 900 /* SBCS cfg */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ #else /* DBCS cfg */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ #endif } if (wc >= 0x100) { /* Is this a DBC? */ if (i >= ni - 1) { /* Field overflow? */ cf |= NS_LOSS | NS_LFN; i = ni; continue; /* Next field */ } dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { if (IsUpper(wc)) { /* ASCII upper case? */ b |= 2; } if (IsLower(wc)) { /* ASCII lower case? */ b |= 1; wc -= 0x20; } } } dp->fn[i++] = (BYTE)wc; } if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ } dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ return FR_OK; #else /* FF_USE_LFN : Non-LFN configuration */ BYTE c, d, *sfn; UINT ni, si, i; const char *p; /* Create file name in directory form */ p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = 0; ni = 8; #if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; if (c != '.' || si >= 3) break; sfn[i++] = c; } if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } #endif for (;;) { c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (c == '/' || c == '\\') { /* Break if a separator is found */ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ i = 8; ni = 11; /* Enter file extension field */ continue; } #if FF_CODE_PAGE == 0 if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #elif FF_CODE_PAGE < 900 if (c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #endif if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ d = (BYTE)p[si++]; /* Get 2nd byte */ if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } *path = p + si; /* Return pointer to the next segment */ if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; #endif /* FF_USE_LFN */ } /*-----------------------------------------------------------------------*/ /* Follow a file path */ /*-----------------------------------------------------------------------*/ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ DIR* dp, /* Directory object to return last directory and found object */ const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; FATFS *fs = dp->obj.fs; #if FF_FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ dp->obj.sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ dp->obj.sclust = 0; /* Start from root directory */ } #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ #if FF_FS_RPATH != 0 if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ DIR dj; dp->obj.c_scl = fs->cdc_scl; dp->obj.c_size = fs->cdc_size; dp->obj.c_ofs = fs->cdc_ofs; res = load_obj_xdir(&dj, &dp->obj); if (res != FR_OK) return res; dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } #endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); } else { /* Follow path */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } } break; } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ dp->obj.c_scl = dp->obj.sclust; dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Open next directory */ } else #endif { dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } return res; } /*-----------------------------------------------------------------------*/ /* Get logical drive number from path name */ /*-----------------------------------------------------------------------*/ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ const TCHAR** path /* Pointer to pointer to the path name */ ) { const TCHAR *tp, *tt; TCHAR tc; int i, vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ const char *sp; char c; #endif tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ i = (int)*tp - '0'; /* Get the LD number */ } #if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ else { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *tp++; if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tt; /* Snip the drive prefix off */ } return vol; } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ if (*tp == '/') { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *(++tp); if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tp; /* Snip the drive prefix off */ return vol; } } #endif /* No drive prefix is found */ #if FF_FS_RPATH != 0 vol = CurrVol; /* Default drive is current drive */ #else vol = 0; /* Default drive is 0 */ #endif return vol; /* Return the default drive */ } /*-----------------------------------------------------------------------*/ /* GPT support functions */ /*-----------------------------------------------------------------------*/ #if FF_LBA64 /* Calculate CRC32 in byte-by-byte */ static DWORD crc32 ( /* Returns next CRC value */ DWORD crc, /* Current CRC value */ BYTE d /* A byte to be processed */ ) { BYTE b; for (b = 1; b; b <<= 1) { crc ^= (d & b) ? 1 : 0; crc = (crc & 1) ? crc >> 1 ^ 0xEDB88320 : crc >> 1; } return crc; } /* Check validity of GPT header */ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ const BYTE* gpth /* Pointer to the GPT header */ ) { UINT i; DWORD bcc; if (mem_cmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ return 1; } #if !FF_FS_READONLY && FF_USE_MKFS /* Generate random value */ static DWORD make_rand ( DWORD seed, /* Seed value */ BYTE* buff, /* Output buffer */ UINT n /* Data length */ ) { UINT r; if (seed == 0) seed = 1; do { for (r = 0; r < 8; r++) seed = seed & 1 ? seed >> 1 ^ 0xA3000000 : seed >> 1; /* Shift 8 bits the 32-bit LFSR */ *buff++ = (BYTE)seed; } while (--n); return seed; } #endif #endif /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ /* Check what the sector is */ static UINT check_fs ( /* 0:FAT VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not FAT and invalid BS, 4:Disk error */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector to load and check if it is an FAT-VBR or not */ ) { WORD w, sign; BYTE b; fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ sign = ld_word(fs->win + BS_55AA); #if FF_FS_EXFAT if (sign == 0xAA55 && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ #endif b = fs->win[BS_JmpBoot]; if (b == 0xEB || b == 0xE9 || b == 0xE8) { /* Valid JumpBoot code? (short jump, near jump or near call) */ if (sign == 0xAA55 && !mem_cmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) return 0; /* It is an FAT32 VBR */ /* FAT volumes formatted with early MS-DOS lack boot signature and FAT string, so that we need to identify the FAT VBR without them. */ w = ld_word(fs->win + BPB_BytsPerSec); if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS) { /* Properness of sector size */ b = fs->win[BPB_SecPerClus]; if (b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size */ && (fs->win[BPB_NumFATs] == 1 || fs->win[BPB_NumFATs] == 2) /* Properness of number of FATs */ && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root entry count */ && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size */ return 0; /* Sector can be presumed an FAT VBR */ } } } return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ } /* Find an FAT volume */ /* (It supports only generic partitioning rules, MBR, GPT and SFD) */ static UINT find_volume ( /* Returns BS status found in the hosting drive */ FATFS* fs, /* Filesystem object */ UINT part /* Partition to fined = 0:auto, 1..:forced */ ) { UINT fmt, i; DWORD mbr_pt[4]; fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD */ if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is a FAT VBR as auto scan, not a BS or disk error */ /* Sector 0 is not an FAT VBR or forced partition number wants a partition */ #if FF_LBA64 if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, v_ent, ofs; QWORD pt_lba; if (move_window(fs, 1) != FR_OK) return 4; /* Load GPT header sector (next to MBR) */ if (!test_gpt_header(fs->win)) return 3; /* Check if GPT header is valid */ n_ent = ld_dword(fs->win + GPTH_PtNum); /* Number of entries */ pt_lba = ld_qword(fs->win + GPTH_PtOfs); /* Table location */ for (v_ent = i = 0; i < n_ent; i++) { /* Find FAT partition */ if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4; /* PT sector */ ofs = i * SZ_GPTE % SS(fs); /* Offset in the sector */ if (!mem_cmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ v_ent++; fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba)); /* Load VBR and check status */ if (part == 0 && fmt <= 1) return fmt; /* Auto search (valid FAT volume found first) */ if (part != 0 && v_ent == part) return fmt; /* Forced partition order (regardless of it is valid or not) */ } } return 3; /* Not found */ } #endif if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ for (i = 0; i < 4; i++) { /* Load partition offset in the MBR */ mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); } i = part ? part - 1 : 0; /* Table index to find first */ do { /* Find an FAT volume */ fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; /* Check if the partition is FAT */ } while (part == 0 && fmt >= 2 && ++i < 4); return fmt; } /*-----------------------------------------------------------------------*/ /* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ BYTE mode /* !=0: Check write protection for write access */ ) { int vol; DSTATUS stat; LBA_t bsect; DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; FATFS *fs; UINT fmt; /* Get logical drive number */ *rfs = 0; vol = get_ldnumber(path); if (vol < 0) return FR_INVALID_DRIVE; /* Check if the filesystem object is valid or not */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ #endif *rfs = fs; /* Return pointer to the filesystem object */ mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type != 0) { /* If the volume has been mounted */ stat = disk_status(fs->pdrv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is already valid */ } } /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find a FAT volume, analyze the BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif /* Find an FAT volume on the drive */ fmt = find_volume(fs, LD2PT(vol)); if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ bsect = fs->winsect; /* Volume location */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; DWORD so, cv, bcl, i; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ fs->n_fatent = nclst + 2; /* Boundaries and Limits */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ so = i = 0; for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ if (i == 0) { if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; so++; } if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ for (;;) { /* Check if bitmap is contiguous */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ } #if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else #endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ fasize *= fs->n_fats; /* Number of sectors for FAT area */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = 0; if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ fs->n_fatent = nclst + 2; /* Number of FAT entries */ fs->volbase = bsect; /* Volume start sector */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !FF_FS_READONLY /* Get FSInfo if available */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; #if (FF_FS_NOFSINFO & 3) != 3 if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) { #if (FF_FS_NOFSINFO & 1) == 0 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif #if (FF_FS_NOFSINFO & 2) == 0 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif } } #endif /* (FF_FS_NOFSINFO & 3) != 3 */ #endif /* !FF_FS_READONLY */ } fs->fs_type = (BYTE)fmt;/* FAT sub-type */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if FF_FS_EXFAT fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif #if FF_FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { FRESULT res = FR_INVALID_OBJECT; if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } else { unlock_fs(obj->fs, FR_OK); } } else { res = FR_TIMEOUT; } #else if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif } *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ return res; } /*--------------------------------------------------------------------------- Public Functions (FatFs API) ----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) { FATFS *cfs; int vol; FRESULT res; const TCHAR *rp = path; /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; cfs = FatFs[vol]; /* Pointer to fs object */ if (cfs) { #if FF_FS_LOCK != 0 clear_lock(cfs); #endif #if FF_FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; #endif cfs->fs_type = 0; /* Clear old fs object */ } if (fs) { fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; #endif } FatFs[vol] = fs; /* Register new fs object */ if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Open or Create a File */ /*-----------------------------------------------------------------------*/ FRESULT f_open ( FIL* fp, /* Pointer to the blank file object */ const TCHAR* path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; DIR dj; FATFS *fs; #if !FF_FS_READONLY DWORD cl, bcs, clst; LBA_t sc; FSIZE_t ofs; #endif DEF_NAMBUF if (!fp) return FR_INVALID_OBJECT; /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = mount_volume(&path, &fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } #if FF_FS_LOCK != 0 else { res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ #if FF_FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif } mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object with the same name is already existing */ if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ fp->obj.fs = fs; init_alloc_info(fs, &fp->obj); /* Set directory entry block initial state */ mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ } } else #endif { /* Set directory entry initial state */ cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ sc = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { res = move_window(fs, sc); fs->last_clst = cl - 1; /* Reuse the cluster hole */ } } } } } else { /* Open an existing file */ if (res == FR_OK) { /* Is the object exsiting? */ if (dj.obj.attr & AM_DIR) { /* File open against a directory */ res = FR_NO_FILE; } else { if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ res = FR_DENIED; } } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; #if FF_FS_LOCK != 0 fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; } else { if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ res = FR_NO_FILE; } } } #endif if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; init_alloc_info(fs, &fp->obj); } else #endif { fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif fp->obj.fs = fs; /* Validate the file object */ fp->obj.id = fs->id; fp->flag = mode; /* Set file access mode */ fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ clst = fp->obj.sclust; /* Follow the cluster chain */ for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { clst = get_fat(&fp->obj, clst); if (clst <= 1) res = FR_INT_ERR; if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ sc = clst2sect(fs, clst); if (sc == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } } } #endif } FREE_NAMBUF(); } if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Read File */ /*-----------------------------------------------------------------------*/ FRESULT f_read ( FIL* fp, /* Pointer to the file object */ void* buff, /* Pointer to data buffer */ UINT btr, /* Number of bytes to read */ UINT* br /* Pointer to number of bytes read */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, cc, csect; BYTE *rbuff = (BYTE*)buff; *br = 0; /* Clear read byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until btr bytes read */ btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ } } if (clst < 2) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Read maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } #else if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); } #endif #endif rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if !FF_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; } rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } LEAVE_FF(fs, FR_OK); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ FRESULT f_write ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write */ UINT* bw /* Pointer to number of bytes written */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; *bw = 0; /* Clear write byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ if (clst == 0) { /* If no cluster is allocated, */ clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ } } else { /* On the middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ } } if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ if (clst == 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if FF_FS_TINY if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Write maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if FF_FS_MINIMIZE <= 2 #if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; } #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); fp->flag &= (BYTE)~FA_DIRTY; } #endif #endif wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if FF_FS_TINY if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; } #else if (fp->sect != sect && /* Fill sector cache with file data */ fp->fptr < fp->obj.objsize && disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { ABORT(fs, FR_DISK_ERR); } #endif fp->sect = sect; } wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; #else mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fp->flag |= FA_DIRTY; #endif } fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ FRESULT f_sync ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD tm; BYTE *dir; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ if (res == FR_OK) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } if (res == FR_OK) { DIR dj; DEF_NAMBUF INIT_NAMBUF(fs); res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; st_dword(fs->dirbuf + XDIR_AccTime, 0); res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); fp->flag &= (BYTE)~FA_MODIFIED; } } FREE_NAMBUF(); } } else #endif { res = move_window(fs, fp->dir_sect); if (res == FR_OK) { dir = fp->dir_ptr; dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); fs->wflag = 1; res = sync_fs(fs); /* Restore it to the directory */ fp->flag &= (BYTE)~FA_MODIFIED; } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Close File */ /*-----------------------------------------------------------------------*/ FRESULT f_close ( FIL* fp /* Pointer to the file object to be closed */ ) { FRESULT res; FATFS *fs; #if !FF_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { #if FF_FS_LOCK != 0 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } } return res; } #if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( const TCHAR* path /* Drive number to set */ ) { int vol; /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { #if FF_STR_VOLUME_ID == 2 UINT i; #endif FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; fs->cdc_size = dj.obj.c_size; fs->cdc_ofs = dj.obj.c_ofs; } #endif } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fs->cdc_ofs = dj.blk_ofs; } else #endif { fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ } } else { res = FR_NO_PATH; /* Reached but a file */ } } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; #if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ if (res == FR_OK) { for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; } #endif } LEAVE_FF(fs, res); } #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( TCHAR* buff, /* Pointer to the directory path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID const char *vp; #endif #endif FILINFO fno; DEF_NAMBUF /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; res = move_window(fs, dj.sect); if (res != FR_OK) break; dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ for (n = 0; fno.fname[n]; n++) ; /* Name length */ if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } if (res == FR_OK) { if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ #if FF_VOLUMES >= 2 /* Put drive prefix */ vl = 0; #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; if (i >= n + 2) { if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; vl++; } #else /* Numeric volume ID */ if (i >= 3) { *tp++ = (TCHAR)'0' + CurrVol; *tp++ = (TCHAR)':'; vl = 2; } #endif if (vl == 0) res = FR_NOT_ENOUGH_CORE; #endif /* Add current directory path */ if (res == FR_OK) { do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } FREE_NAMBUF(); } *tp = 0; LEAVE_FF(fs, res); } #endif /* FF_FS_RPATH >= 2 */ #endif /* FF_FS_RPATH >= 1 */ #if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File pointer from top of file */ ) { FRESULT res; FATFS *fs; DWORD clst, bcs; LBA_t nsect; FSIZE_t ifptr; #if FF_USE_FASTSEEK DWORD cl, pcl, ncl, tcl, tlen, ulen, *tbl; LBA_t dsc; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) res = (FRESULT)fp->err; #if FF_FS_EXFAT && !FF_FS_READONLY if (res == FR_OK && fs->fs_type == FS_EXFAT) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } #endif if (res != FR_OK) LEAVE_FF(fs, res); #if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ cl = fp->obj.sclust; /* Origin of the chain */ if (cl != 0) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ do { pcl = cl; ncl++; cl = get_fat(&fp->obj, cl); if (cl <= 1) ABORT(fs, FR_INT_ERR); if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); } while (cl == pcl + 1); if (ulen <= tlen) { /* Store the length and top of the fragment */ *tbl++ = ncl; *tbl++ = tcl; } } while (cl < fs->n_fatent); /* Repeat until end of chain */ } *fp->cltbl = ulen; /* Number of items used */ if (ulen <= tlen) { *tbl = 0; /* Terminate table */ } else { res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ } } else { /* Fast seek */ if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ if (ofs > 0) { fp->clust = clmt_clust(fp, ofs - 1); dsc = clst2sect(fs, fp->clust); if (dsc == 0) ABORT(fs, FR_INT_ERR); dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } } } } else #endif /* Normal Seek */ { #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ #endif if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs > 0) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->obj.sclust; /* start from the first cluster */ #if !FF_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(&fp->obj, 0); if (clst == 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->obj.sclust = clst; } #endif fp->clust = clst; } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ ofs -= bcs; fp->fptr += bcs; #if !FF_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ if (clst == 0) { /* Clip file size in case of disk full */ ofs = 0; break; } } else #endif { clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ } if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; } fp->fptr += ofs; if (ofs % SS(fs)) { nsect = clst2sect(fs, clst); /* Current sector */ if (nsect == 0) ABORT(fs, FR_INT_ERR); nsect += (DWORD)(ofs / SS(fs)); } } } if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } } LEAVE_FF(fs, res); } #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( DIR* dp, /* Pointer to directory object to create */ const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dp->obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ } else #endif { dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; } } if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ #if FF_FS_LOCK != 0 if (res == FR_OK) { if (dp->obj.sclust != 0) { dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ } } #endif } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Close Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_closedir ( DIR *dp /* Pointer to the directory object to be closed */ ) { FRESULT res; FATFS *fs; res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { #if FF_FS_LOCK != 0 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } FREE_NAMBUF(); } } LEAVE_FF(fs, res); } #if FF_USE_FIND /*-----------------------------------------------------------------------*/ /* Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to the file information structure */ ) { FRESULT res; for (;;) { res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ #if FF_USE_LFN && FF_USE_FIND == 2 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( DIR* dp, /* Pointer to the blank directory object */ FILINFO* fno, /* Pointer to the file information structure */ const TCHAR* path, /* Pointer to the directory to open */ const TCHAR* pattern /* Pointer to the matching pattern */ ) { FRESULT res; dp->pat = pattern; /* Save pointer to pattern string */ res = f_opendir(dp, path); /* Open the target directory */ if (res == FR_OK) { res = f_findnext(dp, fno); /* Find the first item */ } return res; } #endif /* FF_USE_FIND */ #if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ FRESULT f_stat ( const TCHAR* path, /* Pointer to the file path */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; DIR dj; DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ res = FR_INVALID_NAME; } else { /* Found an object */ if (fno) get_fileinfo(&dj, fno); } } FREE_NAMBUF(); } LEAVE_FF(dj.obj.fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( const TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ ) { FRESULT res; FATFS *fs; DWORD nfree, clst, stat; LBA_t sect; UINT i; FFOBJID obj; /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { /* Scan FAT to obtain number of free clusters */ nfree = 0; if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ BYTE bm; UINT b; clst = fs->n_fatent - 2; /* Number of clusters */ sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { if (!(bm & 1)) nfree++; bm >>= 1; } i = (i + 1) % SS(fs); } while (clst); } else #endif { /* FAT16/32: Scan WORD/DWORD FAT entries */ clst = fs->n_fatent; /* Number of entries */ sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } if (fs->fs_type == FS_FAT16) { if (ld_word(fs->win + i) == 0) nfree++; i += 2; } else { if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; i += 4; } i %= SS(fs); } while (--clst); } } *nclst = nfree; /* Return the free clusters */ fs->free_clst = nfree; /* Now free_clst is valid */ fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ } } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Truncate File */ /*-----------------------------------------------------------------------*/ FRESULT f_truncate ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD ncl; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; } else { /* When truncate a part of the file, remove remaining clusters */ ncl = get_fat(&fp->obj, fp->clust); res = FR_OK; if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; if (ncl == 1) res = FR_INT_ERR; if (res == FR_OK && ncl < fs->n_fatent) { res = remove_chain(&fp->obj, ncl, fp->clust); } } fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ fp->flag |= FA_MODIFIED; #if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { fp->flag &= (BYTE)~FA_DIRTY; } } #endif if (res != FR_OK) ABORT(fs, res); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( const TCHAR* path /* Pointer to the file or directory path */ ) { FRESULT res; DIR dj, sdj; DWORD dclst = 0; FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } #if FF_FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { if (dj.obj.attr & AM_RDO) { res = FR_DENIED; /* Cannot remove R/O object */ } } if (res == FR_OK) { #if FF_FS_EXFAT obj.fs = fs; if (fs->fs_type == FS_EXFAT) { init_alloc_info(fs, &obj); dclst = obj.sclust; } else #endif { dclst = ld_clust(fs, dj.dir); } if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if FF_FS_RPATH != 0 if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { sdj.obj.objsize = obj.objsize; sdj.obj.stat = obj.stat; } #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } } if (res == FR_OK) { res = dir_remove(&dj); /* Remove the directory entry */ if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ #if FF_FS_EXFAT res = remove_chain(&obj, dclst, 0); #else res = remove_chain(&dj.obj, dclst, 0); #endif } if (res == FR_OK) res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Create a Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; DIR dj; FFOBJID sobj; FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Name collision? */ if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } if (res == FR_NO_FILE) { /* It is clear to create a new directory */ sobj.fs = fs; /* New object id to create a new chain */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); if (res == FR_OK) { res = dir_clear(fs, dcl); /* Clean up the new table */ if (res == FR_OK) { if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ fs->win[DIR_Name] = '.'; fs->win[DIR_Attr] = AM_DIR; st_dword(fs->win + DIR_ModTime, tm); st_clust(fs, fs->win, dcl); mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; st_clust(fs, fs->win + SZDIRE, pcl); fs->wflag = 1; } res = dir_register(&dj); /* Register the object to the parent directoy */ } } if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dj.dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } else { remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( const TCHAR* path_old, /* Pointer to the object name to be renamed */ const TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; DIR djo, djn; FATFS *fs; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; LBA_t sect; DEF_NAMBUF get_ldnumber(&path_new); /* Snip the drive number of new name off */ res = mount_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if FF_FS_LOCK != 0 if (res == FR_OK) { res = chk_lock(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ mem_cpy(&djn, &djo, sizeof djo); res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ /* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } } else #endif { /* At FAT/FAT32 volume */ mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { dir = djn.dir; /* Copy directory entry of the object except name */ mem_cpy(dir + 13, buf + 13, SZDIRE - 13); dir[DIR_Attr] = buf[DIR_Attr]; if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ sect = clst2sect(fs, ld_clust(fs, dir)); if (sect == 0) { res = FR_INT_ERR; } else { /* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, sect); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); fs->wflag = 1; } } } } } } if (res == FR_OK) { res = dir_remove(&djo); /* Remove old entry */ if (res == FR_OK) { res = sync_fs(fs); } } /* End of the critical section */ } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_MINIMIZE == 0 */ #endif /* FF_FS_MINIMIZE <= 1 */ #endif /* FF_FS_MINIMIZE <= 2 */ #if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const TCHAR* path, /* Pointer to the file path */ BYTE attr, /* Attribute bits */ BYTE mask /* Attribute mask to change */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ res = store_xdir(&dj); } else #endif { dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( const TCHAR* path, /* Pointer to the file/directory name */ const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* FF_USE_CHMOD && !FF_FS_READONLY */ #if FF_USE_LABEL /*-----------------------------------------------------------------------*/ /* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( const TCHAR* path, /* Logical drive number */ TCHAR* label, /* Buffer to store the volume label */ DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; FATFS *fs; UINT si, di; WCHAR wc; /* Get logical drive */ res = mount_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { WCHAR hs; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ wc = ld_word(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); if (wc == 0) { di = 0; break; } di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ label[di] = 0; } else #endif { si = di = 0; /* Extract volume label from AM_VOL entry */ while (si < 11) { wc = dj.dir[si++]; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ if (wc == 0) { di = 0; break; } di += wc; #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; #endif } do { /* Truncate trailing spaces */ label[di] = 0; if (di == 0) break; } while (label[--di] == ' '); } } } if (res == FR_NO_FILE) { /* No label entry and return nul string */ label[0] = 0; res = FR_OK; } } /* Get volume serial number */ if (res == FR_OK && vsn) { res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { case FS_EXFAT: di = BPB_VolIDEx; break; case FS_FAT32: di = BS_VolID32; break; default: di = BS_VolID; } *vsn = ld_dword(fs->win + di); } } LEAVE_FF(fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; FATFS *fs; BYTE dirvn[22]; UINT di; WCHAR wc; static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ #if FF_USE_LFN DWORD dc; #endif /* Get logical drive */ res = mount_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ mem_set(dirvn, 0, 22); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ dc = tchar2uni(&label); /* Get a Unicode character */ if (dc >= 0x10000) { if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ dc = 0; } else { st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } st_word(dirvn + di * 2, (WCHAR)dc); di++; } } else #endif { /* On the FAT/FAT32 volume */ mem_set(dirvn, ' ', 11); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ #if FF_USE_LFN dc = tchar2uni(&label); wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; #else /* ANSI/OEM input */ wc = (BYTE)*label++; if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ #if FF_CODE_PAGE == 0 if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #elif FF_CODE_PAGE < 900 if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); dirvn[di++] = (BYTE)wc; } if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ } /* Set volume label */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { if (di != 0) { mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ } } fs->wflag = 1; res = sync_fs(fs); } else { /* No volume label entry or an error */ if (res == FR_NO_FILE) { res = FR_OK; if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ mem_cpy(dj.dir, dirvn, 11); } fs->wflag = 1; res = sync_fs(fs); } } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LABEL */ #if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ FRESULT f_expand ( FIL* fp, /* Pointer to the file object */ FSIZE_t fsz, /* File size to be expanded to */ BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ ) { FRESULT res; FATFS *fs; DWORD n, clst, stcl, scl, ncl, tcl, lclst; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif n = (DWORD)fs->csize * SS(fs); /* Cluster size */ tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } else #endif { scl = clst = stcl; ncl = 0; for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; if (n == 1) { res = FR_INT_ERR; break; } if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } } } LEAVE_FF(fs, res); } #endif /* FF_USE_EXPAND && !FF_FS_READONLY */ #if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ /* Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ UINT btf, /* Number of bytes to forward */ UINT* bf /* Pointer to number of bytes forwarded */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, csect; BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ if (csect == 0) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ fp->obj.sclust : get_fat(&fp->obj, fp->clust); if (clst <= 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } } sect = clst2sect(fs, fp->clust); /* Get current data sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; #if FF_FS_TINY if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ dbuf = fs->win; #else if (fp->sect != sect) { /* Fill sector cache with file data */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); } dbuf = fp->buf; #endif fp->sect = sect; rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ if (rcnt == 0) ABORT(fs, FR_INT_ERR); } LEAVE_FF(fs, FR_OK); } #endif /* FF_USE_FORWARD */ #if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ /* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ #define N_SEC_TRACK 63 /* Sectors per track for determination of drive CHS */ #define GPT_ALIGN 0x100000 /* Alignment of partitions in GPT [byte] (>=128KB) */ #define GPT_ITEMS 128 /* Number of GPT table size (>=128, sector aligned) */ /* Create partitions on the physical drive */ static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ UINT sys, /* System ID (for only MBR, temp setting) and bit8:GPT */ BYTE* buf /* Working buffer for a sector */ ) { UINT i, cy; LBA_t sz_drv; DWORD sz_drv32, s_lba32, n_lba32; BYTE *pte, hd, n_hd, sc, n_sc; /* Get drive size */ if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR; #if FF_LBA64 if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT */ WORD ss; UINT sz_pt, pi, si, ofs; DWORD bcc, rnd, align; QWORD s_lba64, n_lba64, sz_pool, s_bpt; static const BYTE gpt_mbr[16] = {0x00, 0x00, 0x02, 0x00, 0xEE, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(drv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; /* Get sector size */ if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif rnd = GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment [sector] */ sz_pt = GPT_ITEMS * SZ_GPTE / ss; /* Size of PT [sector] */ s_bpt = sz_drv - sz_pt - 1; /* Backup PT start sector */ s_lba64 = 2 + sz_pt; /* First allocatable sector */ sz_pool = s_bpt - s_lba64; /* Size of allocatable area */ bcc = 0xFFFFFFFF; n_lba64 = 1; pi = si = 0; /* partition table index, size table index */ do { if (pi * SZ_GPTE % ss == 0) mem_set(buf, 0, ss); /* Clean the buffer if needed */ if (n_lba64 != 0) { /* Is the size table not termintated? */ s_lba64 = (s_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition start */ n_lba64 = plst[si++]; /* Get a partition size */ if (n_lba64 <= 100) { /* Is the size in percentage? */ n_lba64 = sz_pool * n_lba64 / 100; n_lba64 = (n_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ } if (s_lba64 + n_lba64 > s_bpt) { /* Clip at end of the pool */ n_lba64 = (s_lba64 < s_bpt) ? s_bpt - s_lba64 : 0; } } if (n_lba64 != 0) { /* Add a partition? */ ofs = pi * SZ_GPTE % ss; mem_cpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Partition GUID (Microsoft Basic Data) */ rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Unique partition GUID */ st_qword(buf + ofs + GPTE_FstLba, s_lba64); /* Partition start LBA */ st_qword(buf + ofs + GPTE_LstLba, s_lba64 + n_lba64 - 1); /* Partition end LBA */ s_lba64 += n_lba64; /* Next partition LBA */ } if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ for (i = 0; i < ss; bcc = crc32(bcc, buf[i++])) ; /* Calculate table check sum */ if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Primary table */ if (disk_write(drv, buf, s_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Secondary table */ } } while (++pi < GPT_ITEMS); /* Create primary GPT header */ mem_set(buf, 0, ss); mem_cpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of another header */ st_qword(buf + GPTH_FstLba, 2 + sz_pt); /* LBA of first allocatable sector */ st_qword(buf + GPTH_LstLba, s_bpt - 1); /* LBA of last allocatable sector */ st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ rnd = make_rand(rnd, buf + GPTH_DskGuid, 16); /* Disk GUID */ for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, 1, 1) != RES_OK) return FR_DISK_ERR; /* Create secondary GPT header */ st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ st_qword(buf + GPTH_BakLba, 1); /* LBA of another header */ st_qword(buf + GPTH_PtOfs, s_bpt); /* LBA of this table */ st_dword(buf + GPTH_Bcc, 0); for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, sz_drv - 1, 1) != RES_OK) return FR_DISK_ERR; /* Create protective MBR */ mem_set(buf, 0, ss); mem_cpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ st_word(buf + BS_55AA, 0xAA55); if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; } else #endif { /* Create partitions in MBR */ sz_drv32 = (DWORD)sz_drv; n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ; if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ mem_set(buf, 0, FF_MAX_SS); /* Clear MBR */ pte = buf + MBR_Table; /* Partition table in the MBR */ for (i = 0, s_lba32 = n_sc; i < 4 && s_lba32 != 0 && s_lba32 < sz_drv32; i++, s_lba32 += n_lba32) { n_lba32 = (DWORD)plst[i]; /* Get partition size */ if (n_lba32 <= 100) n_lba32 = (n_lba32 == 100) ? sz_drv32 : sz_drv32 / 100 * n_lba32; /* Size in percentage? */ if (s_lba32 + n_lba32 > sz_drv32 || s_lba32 + n_lba32 < s_lba32) n_lba32 = sz_drv32 - s_lba32; /* Clip at drive size */ if (n_lba32 == 0) break; /* End of table or no sector to allocate? */ st_dword(pte + PTE_StLba, s_lba32); /* Start LBA */ st_dword(pte + PTE_SizLba, n_lba32); /* Number of sectors */ pte[PTE_System] = (BYTE)sys; /* System type */ cy = (UINT)(s_lba32 / n_sc / n_hd); /* Start cylinder */ hd = (BYTE)(s_lba32 / n_sc % n_hd); /* Start head */ sc = (BYTE)(s_lba32 % n_sc + 1); /* Start sector */ pte[PTE_StHead] = hd; pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_StCyl] = (BYTE)cy; cy = (UINT)((s_lba32 + n_lba32 - 1) / n_sc / n_hd); /* End cylinder */ hd = (BYTE)((s_lba32 + n_lba32 - 1) / n_sc % n_hd); /* End head */ sc = (BYTE)((s_lba32 + n_lba32 - 1) % n_sc + 1); /* End sector */ pte[PTE_EdHead] = hd; pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_EdCyl] = (BYTE)cy; pte += SZ_PTE; /* Next entry */ } st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ } return FR_OK; } FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ void* work, /* Pointer to working buffer (null: use heap memory) */ UINT len /* Size of working buffer [byte] */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ LBA_t sect, lba[2]; DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; DSTATUS ds; FRESULT fr; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ pdrv = LD2PD(vol); /* Physical drive */ ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ if (!opt) opt = &defopt; /* Use default parameter if it is not given */ /* Get physical drive status (sz_drv, sz_blk, ss) */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; sz_blk = opt->align; if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif /* Options for FAT sub-type and FAT parameters */ fsopt = opt->fmt & (FM_ANY | FM_SFD); n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512; sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0; sz_au /= ss; /* Byte --> Sector */ /* Get working buffer */ sz_buf = len / ss; /* Size of working buffer [sector] */ if (sz_buf == 0) return FR_NOT_ENOUGH_CORE; buf = (BYTE*)work; /* Working buffer */ #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(sz_buf * ss); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ b_vol = sz_vol = 0; if (FF_MULTI_PARTITION && ipart != 0) { /* Is the volume associated with any specific partition? */ /* Get partition location from the existing partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ #if FF_LBA64 if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, ofs; QWORD pt_lba; /* Get the partition location from GPT */ if (disk_read(pdrv, buf, 1, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load GPT header sector (next to MBR) */ if (!test_gpt_header(buf)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if GPT header is valid */ n_ent = ld_dword(buf + GPTH_PtNum); /* Number of entries */ pt_lba = ld_qword(buf + GPTH_PtOfs); /* Table start sector */ ofs = i = 0; while (n_ent) { /* Find MS Basic partition with order of ipart */ if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */ if (!mem_cmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ b_vol = ld_qword(buf + ofs + GPTE_FstLba); sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1; break; } n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ } if (n_ent == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* Partition not found */ fsopt |= 0x80; /* Partitioning is in GPT */ } else #endif { /* Get the partition location from MBR partition table */ pte = buf + (MBR_Table + (ipart - 1) * SZ_PTE); if (ipart > 4 || pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } } else { /* The volume is associated with a physical drive */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); if (!(fsopt & FM_SFD)) { /* To be partitioned? */ /* Create a single-partition on the drive in this function */ #if FF_LBA64 if (sz_vol >= FF_MIN_GPT) { /* Which partition type to create, MBR or GPT? */ fsopt |= 0x80; /* Partitioning is in GPT */ b_vol = GPT_ALIGN / ss; sz_vol -= b_vol + GPT_ITEMS * SZ_GPTE / ss + 1; /* Estimated partition offset and size */ } else #endif { /* Partitioning is in MBR */ if (sz_vol > N_SEC_TRACK) { b_vol = N_SEC_TRACK; sz_vol -= b_vol; /* Estimated partition offset and size */ } } } } if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ /* Now start to create a FAT volume at b_vol and sz_vol */ do { /* Pre-determine the FAT type */ if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? */ if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64MS or sz_au > 128S ? */ fsty = FS_EXFAT; break; } } #if FF_LBA64 if (sz_vol >= 0x100000000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too large volume for FAT/FAT32 */ #endif if (sz_au > 128) sz_au = 128; /* Invalid AU for FAT/FAT32? */ if (fsopt & FM_FAT32) { /* FAT32 possible? */ if (!(fsopt & FM_FAT)) { /* no-FAT? */ fsty = FS_FAT32; break; } } if (!(fsopt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ fsty = FS_FAT16; } while (0); #if FF_FS_EXFAT if (fsty == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nb, cl, tbl[3]; WCHAR ch, si; UINT j, st; BYTE b; if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume for exFAT? */ #if FF_USE_TRIM lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Determine FAT location, data location and number of clusters */ if (sz_au == 0) { /* AU auto-selection */ sz_au = 8; if (sz_vol >= 0x80000) sz_au = 64; /* >= 512Ks */ if (sz_vol >= 0x4000000) sz_au = 256; /* >= 64Ms */ } b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ tbl[0] = (szb_bit + sz_au * ss - 1) / (sz_au * ss); /* Number of allocation bitmap clusters */ /* Create a compressed up-case table */ sect = b_data + sz_au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ if (ch != si) { si++; break; /* Store the up-case char if exist */ } for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ if (j >= 128) { ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; default: ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; if (si == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); tbl[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ tbl[2] = 1; /* Number of root dir clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ do { mem_set(buf, 0, sz_buf * ss); for (i = 0; nb >= 8 && i < sz_buf * ss; buf[i++] = 0xFF, nb -= 8) ; for (b = 1; nb != 0 && i < sz_buf * ss; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the FAT */ sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ j = nb = cl = 0; do { mem_set(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write index */ if (cl == 0) { /* Set FAT [0] and FAT[1] */ st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ while (nb != 0 && i < sz_buf * ss) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ } while (nb != 0 && i < sz_buf * ss); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ mem_set(buf, 0, sz_buf * ss); buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + sz_au * (tbl[0] + tbl[1]); nsect = sz_au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); /* Create two set of the exFAT VBR blocks */ sect = b_vol; for (n = 0; n < 2; n++) { /* Main record (+0) */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = sz_au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ mem_set(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ mem_set(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } } else #endif /* FF_FS_EXFAT */ { /* Create an FAT/FAT32 volume */ do { pau = sz_au; /* Pre-determine number of clusters and FAT sub-type */ if (fsty == FS_FAT32) { /* FAT32 volume */ if (pau == 0) { /* AU auto-selection */ n = (DWORD)sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = (DWORD)sz_vol / pau; /* Number of clusters */ sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); } else { /* FAT volume */ if (pau == 0) { /* au auto-selection */ n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = (DWORD)sz_vol / pau; if (n_clst > MAX_FAT12) { n = n_clst * 2 + 4; /* FAT size [byte] */ } else { fsty = FS_FAT12; n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ /* Align data area to erase block boundary (for flash memory media) */ n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base */ if (fsty == FS_FAT32) { /* FAT32: Move FAT */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT */ if (n % n_fat) { /* Adjust fractional error if needed */ n--; sz_rsv++; b_fat++; } sz_fat += n / n_fat; } /* Determine number of clusters and final check of validity of the FAT sub-type */ if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau; if (fsty == FS_FAT32) { if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */ if (sz_au == 0 && (sz_au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fsty == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ if (sz_au == 0 && (pau * 2) <= 64) { sz_au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((fsopt & FM_FAT32)) { fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fsty == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); #if FF_USE_TRIM lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Create FAT VBR */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ buf[BPB_NumFATs] = (BYTE)n_fat; /* Number of FATs */ st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries */ if (sz_vol < 0x10000) { st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ } buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ if (fsty == FS_FAT32) { st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ if (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ mem_set(buf, 0, ss); st_dword(buf + FSI_LeadSig, 0x41615252); st_dword(buf + FSI_StrucSig, 0x61417272); st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ st_word(buf + BS_55AA, 0xAA55); disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } /* Initialize FAT area */ mem_set(buf, 0, sz_buf * ss); sect = b_fat; /* FAT start sector */ for (i = 0; i < n_fat; i++) { /* Initialize FATs each */ if (fsty == FS_FAT32) { st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */ st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */ st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory) */ } else { st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ } nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); /* Rest of FAT all are cleared */ sect += n; nsect -= n; } while (nsect); } /* Initialize root directory (fill with zero) */ nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); } /* A FAT volume has been created here */ /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { sys = 0x07; /* exFAT */ } else { if (fsty == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { sys = 0x06; /* FAT12/16 (large) */ } else { sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ if (!FF_LBA64 || !(fsopt & 0x80)) { /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ lba[0] = sz_vol, lba[1] = 0; fr = create_partition(pdrv, lba, sys, buf); if (fr != FR_OK) LEAVE_MKFS(fr); } } if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); LEAVE_MKFS(FR_OK); } #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ /* Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ const LBA_t ptbl[], /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer (null: use heap memory) */ ) { BYTE *buf = (BYTE*)work; DSTATUS stat; stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); } #endif /* FF_MULTI_PARTITION */ #endif /* !FF_FS_READONLY && FF_USE_MKFS */ #if FF_USE_STRFUNC #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) #error Wrong FF_STRF_ENCODE setting #endif /*-----------------------------------------------------------------------*/ /* Get a String from the File */ /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( TCHAR* buff, /* Pointer to the buffer to store read string */ int len, /* Size of string buffer (items) */ FIL* fp /* Pointer to the file object */ ) { int nc = 0; TCHAR *p = buff; BYTE s[4]; UINT rc; DWORD dc; #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 WCHAR wc; #endif #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 UINT ct; #endif #if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ /* Make a room for the character and terminator */ if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; if (FF_LFN_UNICODE == 3) len -= 1; while (nc < len) { #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ f_read(fp, s, 1, &rc); /* Get a code unit */ if (rc != 1) break; /* EOF? */ wc = s[0]; if (dbc_1st((BYTE)wc)) { /* DBC 1st byte? */ f_read(fp, s, 1, &rc); /* Get DBC 2nd byte */ if (rc != 1 || !dbc_2nd(s[0])) continue; /* Wrong code? */ wc = wc << 8 | s[0]; } dc = ff_oem2uni(wc, CODEPAGE); /* OEM --> */ if (dc == 0) continue; #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ f_read(fp, s, 2, &rc); /* Get a code unit */ if (rc != 2) break; /* EOF? */ dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (IsSurrogateL(dc)) continue; /* Broken surrogate pair? */ if (IsSurrogateH(dc)) { /* High surrogate? */ f_read(fp, s, 2, &rc); /* Get low surrogate */ if (rc != 2) break; /* EOF? */ wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ } #else /* Read a character in UTF-8 */ f_read(fp, s, 1, &rc); /* Get a code unit */ if (rc != 1) break; /* EOF? */ dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; rc = 0; do { /* Merge the byte sequence */ if ((s[rc] & 0xC0) != 0x80) break; dc = dc << 6 | (s[rc] & 0x3F); } while (++rc < ct); if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif /* A code point is avaialble in dc to be output */ if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ } *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ #elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ if (dc < 0x80) { /* Single byte? */ *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ } else { if (dc < 0x800) { /* 2-byte sequence? */ *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; } else { if (dc < 0x10000) { /* 3-byte sequence? */ *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 3; } else { /* 4-byte sequence? */ *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 4; } } } #endif } #else /* Byte-by-byte read without any conversion (ANSI/OEM API) */ len -= 1; /* Make a room for the terminator */ while (nc < len) { f_read(fp, s, 1, &rc); /* Get a byte */ if (rc != 1) break; /* EOF? */ dc = s[0]; if (FF_USE_STRFUNC == 2 && dc == '\r') continue; *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; } #endif *p = 0; /* Terminate the string */ return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ } #if !FF_FS_READONLY #include <stdarg.h> /*-----------------------------------------------------------------------*/ /* Put a Character to the File (sub-functions) */ /*-----------------------------------------------------------------------*/ /* Putchar output buffer and work area */ typedef struct { FIL *fp; /* Ptr to the writing file */ int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 WCHAR hs; #elif FF_USE_LFN && FF_LFN_UNICODE == 2 BYTE bs[4]; UINT wi, ct; #endif BYTE buf[64]; /* Write buffer */ } putbuff; /* Buffered write with code conversion */ static void putc_bfd (putbuff* pb, TCHAR c) { UINT n; int i, nc; #if FF_USE_LFN && FF_LFN_UNICODE WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; TCHAR *tp; #endif #endif if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ putc_bfd(pb, '\r'); } i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; nc = pb->nchr; /* Write unit counter */ #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ if (IsSurrogateH(c)) { /* High surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; if (hs != 0) { /* There is a leading high surrogate */ if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ } else { if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ if ((BYTE)c < 0x80) break; /* Single byte? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ return; } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ pb->ct = 0; continue; } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ if (--pb->ct == 0) break; /* End of multi-byte sequence? */ return; } } tp = (TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ } else { hs = 0; wc = (WCHAR)c; } #endif /* A code point in UTF-16 is available in hs and wc */ #if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ if (hs != 0) { /* Surrogate pair? */ st_word(&pb->buf[i], hs); i += 2; nc++; } st_word(&pb->buf[i], wc); i += 2; #elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ if (hs != 0) { /* Surrogate pair? */ pb->buf[i++] = (BYTE)(hs >> 8); pb->buf[i++] = (BYTE)hs; nc++; } pb->buf[i++] = (BYTE)(wc >> 8); pb->buf[i++] = (BYTE)wc; #elif FF_STRF_ENCODE == 3 /* Write a code point in UTF-8 */ if (hs != 0) { /* 4-byte sequence? */ nc += 3; hs = (hs & 0x3FF) + 0x40; pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } else { if (wc < 0x80) { /* Single byte? */ pb->buf[i++] = (BYTE)wc; } else { if (wc < 0x800) { /* 2-byte sequence? */ nc += 1; pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); } else { /* 3-byte sequence */ nc += 2; pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); } pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } } #else /* Write a code point in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ if (wc == 0) return; if (wc >= 0x100) { pb->buf[i++] = (BYTE)(wc >> 8); nc++; } pb->buf[i++] = (BYTE)wc; #endif #else /* ANSI/OEM input (without re-encoding) */ pb->buf[i++] = (BYTE)c; #endif if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ f_write(pb->fp, pb->buf, (UINT)i, &n); i = (n == (UINT)i) ? 0 : -1; } pb->idx = i; pb->nchr = nc + 1; } /* Flush remaining characters in the buffer */ static int putc_flush (putbuff* pb) { UINT nw; if ( pb->idx >= 0 /* Flush buffered characters to the file */ && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK && (UINT)pb->idx == nw) return pb->nchr; return EOF; } /* Initialize write buffer */ static void putc_init (putbuff* pb, FIL* fp) { mem_set(pb, 0, sizeof (putbuff)); pb->fp = fp; } int f_putc ( TCHAR c, /* A character to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); putc_bfd(&pb, c); /* Put the character */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a String to the File */ /*-----------------------------------------------------------------------*/ int f_puts ( const TCHAR* str, /* Pointer to the string to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); while (*str) putc_bfd(&pb, *str++); /* Put the string */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a Formatted String to the File */ /*-----------------------------------------------------------------------*/ int f_printf ( FIL* fp, /* Pointer to the file object */ const TCHAR* fmt, /* Pointer to the format string */ ... /* Optional arguments... */ ) { va_list arp; putbuff pb; BYTE f, r; UINT i, j, w; DWORD v; TCHAR c, d, str[32], *p; putc_init(&pb, fp); va_start(arp, fmt); for (;;) { c = *fmt++; if (c == 0) break; /* End of string */ if (c != '%') { /* Non escape character */ putc_bfd(&pb, c); continue; } w = f = 0; c = *fmt++; if (c == '0') { /* Flag: '0' padding */ f = 1; c = *fmt++; } else { if (c == '-') { /* Flag: left justified */ f = 2; c = *fmt++; } } if (c == '*') { /* Minimum width by argument */ w = va_arg(arp, int); c = *fmt++; } else { while (IsDigit(c)) { /* Minimum width */ w = w * 10 + c - '0'; c = *fmt++; } } if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ f |= 4; c = *fmt++; } if (c == 0) break; d = c; if (IsLower(d)) d -= 0x20; switch (d) { /* Atgument type is... */ case 'S' : /* String */ p = va_arg(arp, TCHAR*); for (j = 0; p[j]; j++) ; if (!(f & 2)) { /* Right padded */ while (j++ < w) putc_bfd(&pb, ' ') ; } while (*p) putc_bfd(&pb, *p++) ; /* String body */ while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ continue; case 'C' : /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; case 'B' : /* Unsigned binary */ r = 2; break; case 'O' : /* Unsigned octal */ r = 8; break; case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; case 'X' : /* Unsigned hexdecimal */ r = 16; break; default: /* Unknown type (pass-through) */ putc_bfd(&pb, c); continue; } /* Get an argument and put it in numeral */ v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); if (d == 'D' && (v & 0x80000000)) { v = 0 - v; f |= 8; } i = 0; do { d = (TCHAR)(v % r); v /= r; if (d > 9) d += (c == 'x') ? 0x27 : 0x07; str[i++] = d + '0'; } while (v && i < sizeof str / sizeof *str); if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; if (!(f & 2)) { while (j++ < w) putc_bfd(&pb, d); /* Right pad */ } do { putc_bfd(&pb, str[--i]); /* Number body */ } while (i); while (j++ < w) putc_bfd(&pb, d); /* Left pad */ } va_end(arp); return putc_flush(&pb); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_STRFUNC */ #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ /* Set Active Codepage for the Path Name */ /*-----------------------------------------------------------------------*/ FRESULT f_setcp ( WORD cp /* Value to be set as active code page */ ) { static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ ExCvt = 0; DbcTbl = tables[i]; } else { /* SBCS */ ExCvt = tables[i]; DbcTbl = 0; } return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ ================================================ FILE: exosphere/mariko_fatal/source/fatfs/ff.h ================================================ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem module R0.14 / /-----------------------------------------------------------------------------/ / / Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #ifndef FF_DEFINED #define FF_DEFINED 86606 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif #include "ffconf.h" /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif /* Integer types used for FatFs API */ #if defined(_WIN32) /* Main development platform */ #define FF_INTDEF 2 #include <windows.h> typedef unsigned __int64 QWORD; #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ #define FF_INTDEF 2 #include <stdint.h> typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef uint16_t WORD; /* 16-bit unsigned integer */ typedef uint32_t DWORD; /* 32-bit unsigned integer */ typedef uint64_t QWORD; /* 64-bit unsigned integer */ typedef WORD WCHAR; /* UTF-16 character type */ #else /* Earlier than C99 */ #define FF_INTDEF 1 typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef unsigned short WORD; /* 16-bit unsigned integer */ typedef unsigned long DWORD; /* 32-bit unsigned integer */ typedef WORD WCHAR; /* UTF-16 character type */ #endif /* Definitions of volume management */ #if FF_MULTI_PARTITION /* Multiple partition configuration */ typedef struct { BYTE pd; /* Physical drive number */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ #endif #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ #endif #endif /* Type of path name strings on FatFs API */ #ifndef _INC_TCHAR #define _INC_TCHAR #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ typedef char TCHAR; #define _T(x) u8 ## x #define _TEXT(x) u8 ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ typedef DWORD TCHAR; #define _T(x) U ## x #define _TEXT(x) U ## x #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) #error Wrong FF_LFN_UNICODE setting #else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif #endif /* Type of file size and LBA variables */ #if FF_FS_EXFAT #if FF_INTDEF != 2 #error exFAT feature wants C99 or later #endif typedef QWORD FSIZE_t; #if FF_LBA64 typedef QWORD LBA_t; #else typedef DWORD LBA_t; #endif #else #if FF_LBA64 #error exFAT needs to be enabled when enable 64-bit LBA #endif typedef DWORD FSIZE_t; typedef DWORD LBA_t; #endif /* Filesystem object structure (FATFS) */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif #if FF_FS_REENTRANT FF_SYNC_t sobj; /* Identifier of sync object */ #endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif #if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ #if FF_FS_EXFAT DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD fsize; /* Size of an FAT [sectors] */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t database; /* Data base sector */ #if FF_FS_EXFAT LBA_t bitbase; /* Allocation bitmap base sector */ #endif LBA_t winsect; /* Current sector appearing in the win[] */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; /* Object ID and allocation information (FFOBJID) */ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ #endif #if FF_FS_LOCK UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; /* File object structure (FIL) */ typedef struct { FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !FF_FS_TINY BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif } FIL; /* Directory object structure (DIR) */ typedef struct { FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ LBA_t sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; /* File information structure (FILINFO) */ typedef struct { FSIZE_t fsize; /* File size */ WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ #endif } FILINFO; /* Format parameter structure (MKFS_PARM) */ typedef struct { BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ BYTE n_fat; /* Number of FATs */ UINT align; /* Data area alignment (sector) */ UINT n_root; /* Number of root directory entries */ DWORD au_size; /* Cluster size (byte) */ } MKFS_PARM; /* File function return code (FRESULT) */ typedef enum { FR_OK = 0, /* (0) Succeeded */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ FR_NOT_READY, /* (3) The physical drive cannot work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ FR_EXIST, /* (8) Access denied due to prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; /*--------------------------------------------------------------*/ /* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) #define f_rmdir(path) f_unlink(path) #define f_unmount(path) f_mount(0, path, 0) #ifndef EOF #define EOF (-1) #endif /*--------------------------------------------------------------*/ /* Additional user defined functions */ /* RTC function */ #if !FF_FS_READONLY && !FF_FS_NORTC DWORD get_fattime (void); #endif /* LFN support functions */ #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif #if FF_USE_LFN == 3 /* Dynamic memory allocation */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif /* Sync functions */ #if FF_FS_REENTRANT int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #endif /*--------------------------------------------------------------*/ /* Flags and offset address */ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 /* Fast seek controls (2nd argument of f_lseek) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) /* Format options (2nd argument of f_mkfs) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_EXFAT 0x04 #define FM_ANY 0x07 #define FM_SFD 0x08 /* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 #define FS_EXFAT 4 /* File attribute bits for directory entry (FILINFO.fattrib) */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ #ifdef __cplusplus } #endif #endif /* FF_DEFINED */ ================================================ FILE: exosphere/mariko_fatal/source/fatfs/ffconf.h ================================================ /*---------------------------------------------------------------------------/ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ #define FFCONF_DEF 86606 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ #define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ #define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ #define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ #define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ #define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ #define FF_USE_EXPAND 1 /* This option switches f_expand function. (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 0 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ #define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ #define FF_CODE_PAGE 850 /* This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / / 437 - U.S. / 720 - Arabic / 737 - Greek / 771 - KBL / 775 - Baltic / 850 - Latin 1 / 852 - Latin 2 / 855 - Cyrillic / 857 - Turkish / 860 - Portuguese / 861 - Icelandic / 862 - Hebrew / 863 - Canadian French / 864 - Arabic / 865 - Nordic / 866 - Russian / 869 - Greek 2 / 932 - Japanese (DBCS) / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) / 0 - Include all code pages above and configured by f_setcp() */ #define FF_USE_LFN 1 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ #define FF_LFN_UNICODE 2 /* This option switches the character encoding on the API when LFN is enabled. / / 0: ANSI/OEM in current CP (TCHAR = char) / 1: Unicode in UTF-16 (TCHAR = WCHAR) / 2: Unicode in UTF-8 (TCHAR = char) / 3: Unicode in UTF-32 (TCHAR = DWORD) / / Also behavior of string I/O functions will be affected by this option. / When LFN is not enabled, this option has no effect. */ #define FF_LFN_BUF 255 #define FF_SFN_BUF 12 /* This set of options defines size of file name members in the FILINFO structure / which is used to read out directory items. These values should be suffcient for / the file names to read. The maximum possible length of the read file name depends / on character encoding. When LFN is not enabled, these options have no effect. */ #define FF_STRF_ENCODE 3 /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), / f_putc(), f_puts and f_printf() convert the character encoding in it. / This option selects assumption of character encoding ON THE FILE to be / read/written via those functions. / / 0: ANSI/OEM in current CP / 1: Unicode in UTF-16LE / 2: Unicode in UTF-16BE / 3: Unicode in UTF-8 */ #define FF_FS_RPATH 0 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. */ /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ #define FF_VOLUMES 1 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "sdmc" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ #define FF_MULTI_PARTITION 0 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ #define FF_MIN_SS 512 #define FF_MAX_SS 512 /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / for variable sector size mode and disk_ioctl() function needs to implement / GET_SECTOR_SIZE command. */ #define FF_LBA64 0 /* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ #define FF_MIN_GPT 0x100000000 /* Minimum number of sectors to switch GPT format to create partition in f_mkfs and / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ #define FF_USE_TRIM 0 /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ #define FF_FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ #define FF_FS_EXFAT 1 /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2019 /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. / These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. / bit0=1: Do not trust free cluster count in the FSINFO. / bit1=0: Use last allocated cluster number in the FSINFO if available. / bit1=1: Do not trust last allocated cluster number in the FSINFO. */ #define FF_FS_LOCK 0 /* The option FF_FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. / >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file / lock control is independent of re-entrancy. */ /* #include <somertos.h> // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 #define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / / The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ /*--- End of configuration options ---*/ ================================================ FILE: exosphere/mariko_fatal/source/fatfs/ffsystem.c ================================================ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ /* (C)ChaN, 2018 */ /*------------------------------------------------------------------------*/ #include "ff.h" #if FF_USE_LFN == 3 /* Dynamic memory allocation */ /*------------------------------------------------------------------------*/ /* Allocate a memory block */ /*------------------------------------------------------------------------*/ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { return malloc(msize); /* Allocate a new memory block with POSIX API */ } /*------------------------------------------------------------------------*/ /* Free a memory block */ /*------------------------------------------------------------------------*/ void ff_memfree ( void* mblock /* Pointer to the memory block to free (nothing to do if null) */ ) { free(mblock); /* Free the memory block with POSIX API */ } #endif #if FF_FS_REENTRANT /* Mutal exclusion */ /*------------------------------------------------------------------------*/ /* Create a Synchronization Object */ /*------------------------------------------------------------------------*/ /* This function is called in f_mount() function to create a new / synchronization object for the volume, such as semaphore and mutex. / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. */ //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ BYTE vol, /* Corresponding volume (logical drive number) */ FF_SYNC_t* sobj /* Pointer to return the created sync object */ ) { /* Win32 */ *sobj = CreateMutex(NULL, FALSE, NULL); return (int)(*sobj != INVALID_HANDLE_VALUE); /* uITRON */ // T_CSEM csem = {TA_TPRI,1,1}; // *sobj = acre_sem(&csem); // return (int)(*sobj > 0); /* uC/OS-II */ // OS_ERR err; // *sobj = OSMutexCreate(0, &err); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // *sobj = xSemaphoreCreateMutex(); // return (int)(*sobj != NULL); /* CMSIS-RTOS */ // *sobj = osMutexCreate(&Mutex[vol]); // return (int)(*sobj != NULL); } /*------------------------------------------------------------------------*/ /* Delete a Synchronization Object */ /*------------------------------------------------------------------------*/ /* This function is called in f_mount() function to delete a synchronization / object that created with ff_cre_syncobj() function. When a 0 is returned, / the f_mount() function fails with FR_INT_ERR. */ int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ ) { /* Win32 */ return (int)CloseHandle(sobj); /* uITRON */ // return (int)(del_sem(sobj) == E_OK); /* uC/OS-II */ // OS_ERR err; // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // vSemaphoreDelete(sobj); // return 1; /* CMSIS-RTOS */ // return (int)(osMutexDelete(sobj) == osOK); } /*------------------------------------------------------------------------*/ /* Request Grant to Access the Volume */ /*------------------------------------------------------------------------*/ /* This function is called on entering file functions to lock the volume. / When a 0 is returned, the file function fails with FR_TIMEOUT. */ int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ FF_SYNC_t sobj /* Sync object to wait */ ) { /* Win32 */ return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); /* uITRON */ // return (int)(wai_sem(sobj) == E_OK); /* uC/OS-II */ // OS_ERR err; // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); /* CMSIS-RTOS */ // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); } /*------------------------------------------------------------------------*/ /* Release Grant to Access the Volume */ /*------------------------------------------------------------------------*/ /* This function is called on leaving file functions to unlock the volume. */ void ff_rel_grant ( FF_SYNC_t sobj /* Sync object to be signaled */ ) { /* Win32 */ ReleaseMutex(sobj); /* uITRON */ // sig_sem(sobj); /* uC/OS-II */ // OSMutexPost(sobj); /* FreeRTOS */ // xSemaphoreGive(sobj); /* CMSIS-RTOS */ // osMutexRelease(sobj); } #endif ================================================ FILE: exosphere/mariko_fatal/source/fatfs/ffunicode.c ================================================ /*------------------------------------------------------------------------*/ /* Unicode handling functions for FatFs R0.13+ */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / / utilitiy for the code conversion, this module should be modified to use / / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* / Copyright (C) 2014, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. */ #include "ff.h" #if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */ static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ 0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180, 0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6, 0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE, 0x03A1, 0x83AF, 0x03A3, 0x83B0, 0x03A4, 0x83B1, 0x03A5, 0x83B2, 0x03A6, 0x83B3, 0x03A7, 0x83B4, 0x03A8, 0x83B5, 0x03A9, 0x83B6, 0x03B1, 0x83BF, 0x03B2, 0x83C0, 0x03B3, 0x83C1, 0x03B4, 0x83C2, 0x03B5, 0x83C3, 0x03B6, 0x83C4, 0x03B7, 0x83C5, 0x03B8, 0x83C6, 0x03B9, 0x83C7, 0x03BA, 0x83C8, 0x03BB, 0x83C9, 0x03BC, 0x83CA, 0x03BD, 0x83CB, 0x03BE, 0x83CC, 0x03BF, 0x83CD, 0x03C0, 0x83CE, 0x03C1, 0x83CF, 0x03C3, 0x83D0, 0x03C4, 0x83D1, 0x03C5, 0x83D2, 0x03C6, 0x83D3, 0x03C7, 0x83D4, 0x03C8, 0x83D5, 0x03C9, 0x83D6, 0x0401, 0x8446, 0x0410, 0x8440, 0x0411, 0x8441, 0x0412, 0x8442, 0x0413, 0x8443, 0x0414, 0x8444, 0x0415, 0x8445, 0x0416, 0x8447, 0x0417, 0x8448, 0x0418, 0x8449, 0x0419, 0x844A, 0x041A, 0x844B, 0x041B, 0x844C, 0x041C, 0x844D, 0x041D, 0x844E, 0x041E, 0x844F, 0x041F, 0x8450, 0x0420, 0x8451, 0x0421, 0x8452, 0x0422, 0x8453, 0x0423, 0x8454, 0x0424, 0x8455, 0x0425, 0x8456, 0x0426, 0x8457, 0x0427, 0x8458, 0x0428, 0x8459, 0x0429, 0x845A, 0x042A, 0x845B, 0x042B, 0x845C, 0x042C, 0x845D, 0x042D, 0x845E, 0x042E, 0x845F, 0x042F, 0x8460, 0x0430, 0x8470, 0x0431, 0x8471, 0x0432, 0x8472, 0x0433, 0x8473, 0x0434, 0x8474, 0x0435, 0x8475, 0x0436, 0x8477, 0x0437, 0x8478, 0x0438, 0x8479, 0x0439, 0x847A, 0x043A, 0x847B, 0x043B, 0x847C, 0x043C, 0x847D, 0x043D, 0x847E, 0x043E, 0x8480, 0x043F, 0x8481, 0x0440, 0x8482, 0x0441, 0x8483, 0x0442, 0x8484, 0x0443, 0x8485, 0x0444, 0x8486, 0x0445, 0x8487, 0x0446, 0x8488, 0x0447, 0x8489, 0x0448, 0x848A, 0x0449, 0x848B, 0x044A, 0x848C, 0x044B, 0x848D, 0x044C, 0x848E, 0x044D, 0x848F, 0x044E, 0x8490, 0x044F, 0x8491, 0x0451, 0x8476, 0x2010, 0x815D, 0x2015, 0x815C, 0x2018, 0x8165, 0x2019, 0x8166, 0x201C, 0x8167, 0x201D, 0x8168, 0x2020, 0x81F5, 0x2021, 0x81F6, 0x2025, 0x8164, 0x2026, 0x8163, 0x2030, 0x81F1, 0x2032, 0x818C, 0x2033, 0x818D, 0x203B, 0x81A6, 0x2103, 0x818E, 0x2116, 0x8782, 0x2121, 0x8784, 0x212B, 0x81F0, 0x2160, 0x8754, 0x2161, 0x8755, 0x2162, 0x8756, 0x2163, 0x8757, 0x2164, 0x8758, 0x2165, 0x8759, 0x2166, 0x875A, 0x2167, 0x875B, 0x2168, 0x875C, 0x2169, 0x875D, 0x2170, 0xFA40, 0x2171, 0xFA41, 0x2172, 0xFA42, 0x2173, 0xFA43, 0x2174, 0xFA44, 0x2175, 0xFA45, 0x2176, 0xFA46, 0x2177, 0xFA47, 0x2178, 0xFA48, 0x2179, 0xFA49, 0x2190, 0x81A9, 0x2191, 0x81AA, 0x2192, 0x81A8, 0x2193, 0x81AB, 0x21D2, 0x81CB, 0x21D4, 0x81CC, 0x2200, 0x81CD, 0x2202, 0x81DD, 0x2203, 0x81CE, 0x2207, 0x81DE, 0x2208, 0x81B8, 0x220B, 0x81B9, 0x2211, 0x8794, 0x221A, 0x81E3, 0x221D, 0x81E5, 0x221E, 0x8187, 0x221F, 0x8798, 0x2220, 0x81DA, 0x2225, 0x8161, 0x2227, 0x81C8, 0x2228, 0x81C9, 0x2229, 0x81BF, 0x222A, 0x81BE, 0x222B, 0x81E7, 0x222C, 0x81E8, 0x222E, 0x8793, 0x2234, 0x8188, 0x2235, 0x81E6, 0x223D, 0x81E4, 0x2252, 0x81E0, 0x2260, 0x8182, 0x2261, 0x81DF, 0x2266, 0x8185, 0x2267, 0x8186, 0x226A, 0x81E1, 0x226B, 0x81E2, 0x2282, 0x81BC, 0x2283, 0x81BD, 0x2286, 0x81BA, 0x2287, 0x81BB, 0x22A5, 0x81DB, 0x22BF, 0x8799, 0x2312, 0x81DC, 0x2460, 0x8740, 0x2461, 0x8741, 0x2462, 0x8742, 0x2463, 0x8743, 0x2464, 0x8744, 0x2465, 0x8745, 0x2466, 0x8746, 0x2467, 0x8747, 0x2468, 0x8748, 0x2469, 0x8749, 0x246A, 0x874A, 0x246B, 0x874B, 0x246C, 0x874C, 0x246D, 0x874D, 0x246E, 0x874E, 0x246F, 0x874F, 0x2470, 0x8750, 0x2471, 0x8751, 0x2472, 0x8752, 0x2473, 0x8753, 0x2500, 0x849F, 0x2501, 0x84AA, 0x2502, 0x84A0, 0x2503, 0x84AB, 0x250C, 0x84A1, 0x250F, 0x84AC, 0x2510, 0x84A2, 0x2513, 0x84AD, 0x2514, 0x84A4, 0x2517, 0x84AF, 0x2518, 0x84A3, 0x251B, 0x84AE, 0x251C, 0x84A5, 0x251D, 0x84BA, 0x2520, 0x84B5, 0x2523, 0x84B0, 0x2524, 0x84A7, 0x2525, 0x84BC, 0x2528, 0x84B7, 0x252B, 0x84B2, 0x252C, 0x84A6, 0x252F, 0x84B6, 0x2530, 0x84BB, 0x2533, 0x84B1, 0x2534, 0x84A8, 0x2537, 0x84B8, 0x2538, 0x84BD, 0x253B, 0x84B3, 0x253C, 0x84A9, 0x253F, 0x84B9, 0x2542, 0x84BE, 0x254B, 0x84B4, 0x25A0, 0x81A1, 0x25A1, 0x81A0, 0x25B2, 0x81A3, 0x25B3, 0x81A2, 0x25BC, 0x81A5, 0x25BD, 0x81A4, 0x25C6, 0x819F, 0x25C7, 0x819E, 0x25CB, 0x819B, 0x25CE, 0x819D, 0x25CF, 0x819C, 0x25EF, 0x81FC, 0x2605, 0x819A, 0x2606, 0x8199, 0x2640, 0x818A, 0x2642, 0x8189, 0x266A, 0x81F4, 0x266D, 0x81F3, 0x266F, 0x81F2, 0x3000, 0x8140, 0x3001, 0x8141, 0x3002, 0x8142, 0x3003, 0x8156, 0x3005, 0x8158, 0x3006, 0x8159, 0x3007, 0x815A, 0x3008, 0x8171, 0x3009, 0x8172, 0x300A, 0x8173, 0x300B, 0x8174, 0x300C, 0x8175, 0x300D, 0x8176, 0x300E, 0x8177, 0x300F, 0x8178, 0x3010, 0x8179, 0x3011, 0x817A, 0x3012, 0x81A7, 0x3013, 0x81AC, 0x3014, 0x816B, 0x3015, 0x816C, 0x301D, 0x8780, 0x301F, 0x8781, 0x3041, 0x829F, 0x3042, 0x82A0, 0x3043, 0x82A1, 0x3044, 0x82A2, 0x3045, 0x82A3, 0x3046, 0x82A4, 0x3047, 0x82A5, 0x3048, 0x82A6, 0x3049, 0x82A7, 0x304A, 0x82A8, 0x304B, 0x82A9, 0x304C, 0x82AA, 0x304D, 0x82AB, 0x304E, 0x82AC, 0x304F, 0x82AD, 0x3050, 0x82AE, 0x3051, 0x82AF, 0x3052, 0x82B0, 0x3053, 0x82B1, 0x3054, 0x82B2, 0x3055, 0x82B3, 0x3056, 0x82B4, 0x3057, 0x82B5, 0x3058, 0x82B6, 0x3059, 0x82B7, 0x305A, 0x82B8, 0x305B, 0x82B9, 0x305C, 0x82BA, 0x305D, 0x82BB, 0x305E, 0x82BC, 0x305F, 0x82BD, 0x3060, 0x82BE, 0x3061, 0x82BF, 0x3062, 0x82C0, 0x3063, 0x82C1, 0x3064, 0x82C2, 0x3065, 0x82C3, 0x3066, 0x82C4, 0x3067, 0x82C5, 0x3068, 0x82C6, 0x3069, 0x82C7, 0x306A, 0x82C8, 0x306B, 0x82C9, 0x306C, 0x82CA, 0x306D, 0x82CB, 0x306E, 0x82CC, 0x306F, 0x82CD, 0x3070, 0x82CE, 0x3071, 0x82CF, 0x3072, 0x82D0, 0x3073, 0x82D1, 0x3074, 0x82D2, 0x3075, 0x82D3, 0x3076, 0x82D4, 0x3077, 0x82D5, 0x3078, 0x82D6, 0x3079, 0x82D7, 0x307A, 0x82D8, 0x307B, 0x82D9, 0x307C, 0x82DA, 0x307D, 0x82DB, 0x307E, 0x82DC, 0x307F, 0x82DD, 0x3080, 0x82DE, 0x3081, 0x82DF, 0x3082, 0x82E0, 0x3083, 0x82E1, 0x3084, 0x82E2, 0x3085, 0x82E3, 0x3086, 0x82E4, 0x3087, 0x82E5, 0x3088, 0x82E6, 0x3089, 0x82E7, 0x308A, 0x82E8, 0x308B, 0x82E9, 0x308C, 0x82EA, 0x308D, 0x82EB, 0x308E, 0x82EC, 0x308F, 0x82ED, 0x3090, 0x82EE, 0x3091, 0x82EF, 0x3092, 0x82F0, 0x3093, 0x82F1, 0x309B, 0x814A, 0x309C, 0x814B, 0x309D, 0x8154, 0x309E, 0x8155, 0x30A1, 0x8340, 0x30A2, 0x8341, 0x30A3, 0x8342, 0x30A4, 0x8343, 0x30A5, 0x8344, 0x30A6, 0x8345, 0x30A7, 0x8346, 0x30A8, 0x8347, 0x30A9, 0x8348, 0x30AA, 0x8349, 0x30AB, 0x834A, 0x30AC, 0x834B, 0x30AD, 0x834C, 0x30AE, 0x834D, 0x30AF, 0x834E, 0x30B0, 0x834F, 0x30B1, 0x8350, 0x30B2, 0x8351, 0x30B3, 0x8352, 0x30B4, 0x8353, 0x30B5, 0x8354, 0x30B6, 0x8355, 0x30B7, 0x8356, 0x30B8, 0x8357, 0x30B9, 0x8358, 0x30BA, 0x8359, 0x30BB, 0x835A, 0x30BC, 0x835B, 0x30BD, 0x835C, 0x30BE, 0x835D, 0x30BF, 0x835E, 0x30C0, 0x835F, 0x30C1, 0x8360, 0x30C2, 0x8361, 0x30C3, 0x8362, 0x30C4, 0x8363, 0x30C5, 0x8364, 0x30C6, 0x8365, 0x30C7, 0x8366, 0x30C8, 0x8367, 0x30C9, 0x8368, 0x30CA, 0x8369, 0x30CB, 0x836A, 0x30CC, 0x836B, 0x30CD, 0x836C, 0x30CE, 0x836D, 0x30CF, 0x836E, 0x30D0, 0x836F, 0x30D1, 0x8370, 0x30D2, 0x8371, 0x30D3, 0x8372, 0x30D4, 0x8373, 0x30D5, 0x8374, 0x30D6, 0x8375, 0x30D7, 0x8376, 0x30D8, 0x8377, 0x30D9, 0x8378, 0x30DA, 0x8379, 0x30DB, 0x837A, 0x30DC, 0x837B, 0x30DD, 0x837C, 0x30DE, 0x837D, 0x30DF, 0x837E, 0x30E0, 0x8380, 0x30E1, 0x8381, 0x30E2, 0x8382, 0x30E3, 0x8383, 0x30E4, 0x8384, 0x30E5, 0x8385, 0x30E6, 0x8386, 0x30E7, 0x8387, 0x30E8, 0x8388, 0x30E9, 0x8389, 0x30EA, 0x838A, 0x30EB, 0x838B, 0x30EC, 0x838C, 0x30ED, 0x838D, 0x30EE, 0x838E, 0x30EF, 0x838F, 0x30F0, 0x8390, 0x30F1, 0x8391, 0x30F2, 0x8392, 0x30F3, 0x8393, 0x30F4, 0x8394, 0x30F5, 0x8395, 0x30F6, 0x8396, 0x30FB, 0x8145, 0x30FC, 0x815B, 0x30FD, 0x8152, 0x30FE, 0x8153, 0x3231, 0x878A, 0x3232, 0x878B, 0x3239, 0x878C, 0x32A4, 0x8785, 0x32A5, 0x8786, 0x32A6, 0x8787, 0x32A7, 0x8788, 0x32A8, 0x8789, 0x3303, 0x8765, 0x330D, 0x8769, 0x3314, 0x8760, 0x3318, 0x8763, 0x3322, 0x8761, 0x3323, 0x876B, 0x3326, 0x876A, 0x3327, 0x8764, 0x332B, 0x876C, 0x3336, 0x8766, 0x333B, 0x876E, 0x3349, 0x875F, 0x334A, 0x876D, 0x334D, 0x8762, 0x3351, 0x8767, 0x3357, 0x8768, 0x337B, 0x877E, 0x337C, 0x878F, 0x337D, 0x878E, 0x337E, 0x878D, 0x338E, 0x8772, 0x338F, 0x8773, 0x339C, 0x876F, 0x339D, 0x8770, 0x339E, 0x8771, 0x33A1, 0x8775, 0x33C4, 0x8774, 0x33CD, 0x8783, 0x4E00, 0x88EA, 0x4E01, 0x929A, 0x4E03, 0x8EB5, 0x4E07, 0x969C, 0x4E08, 0x8FE4, 0x4E09, 0x8E4F, 0x4E0A, 0x8FE3, 0x4E0B, 0x89BA, 0x4E0D, 0x9573, 0x4E0E, 0x975E, 0x4E10, 0x98A0, 0x4E11, 0x894E, 0x4E14, 0x8A8E, 0x4E15, 0x98A1, 0x4E16, 0x90A2, 0x4E17, 0x99C0, 0x4E18, 0x8B75, 0x4E19, 0x95B8, 0x4E1E, 0x8FE5, 0x4E21, 0x97BC, 0x4E26, 0x95C0, 0x4E28, 0xFA68, 0x4E2A, 0x98A2, 0x4E2D, 0x9286, 0x4E31, 0x98A3, 0x4E32, 0x8BF8, 0x4E36, 0x98A4, 0x4E38, 0x8ADB, 0x4E39, 0x924F, 0x4E3B, 0x8EE5, 0x4E3C, 0x98A5, 0x4E3F, 0x98A6, 0x4E42, 0x98A7, 0x4E43, 0x9454, 0x4E45, 0x8B76, 0x4E4B, 0x9456, 0x4E4D, 0x93E1, 0x4E4E, 0x8CC1, 0x4E4F, 0x9652, 0x4E55, 0xE568, 0x4E56, 0x98A8, 0x4E57, 0x8FE6, 0x4E58, 0x98A9, 0x4E59, 0x89B3, 0x4E5D, 0x8BE3, 0x4E5E, 0x8CEE, 0x4E5F, 0x96E7, 0x4E62, 0x9BA4, 0x4E71, 0x9790, 0x4E73, 0x93FB, 0x4E7E, 0x8AA3, 0x4E80, 0x8B54, 0x4E82, 0x98AA, 0x4E85, 0x98AB, 0x4E86, 0x97B9, 0x4E88, 0x975C, 0x4E89, 0x9188, 0x4E8A, 0x98AD, 0x4E8B, 0x8E96, 0x4E8C, 0x93F1, 0x4E8E, 0x98B0, 0x4E91, 0x895D, 0x4E92, 0x8CDD, 0x4E94, 0x8CDC, 0x4E95, 0x88E4, 0x4E98, 0x986A, 0x4E99, 0x9869, 0x4E9B, 0x8DB1, 0x4E9C, 0x889F, 0x4E9E, 0x98B1, 0x4E9F, 0x98B2, 0x4EA0, 0x98B3, 0x4EA1, 0x9653, 0x4EA2, 0x98B4, 0x4EA4, 0x8CF0, 0x4EA5, 0x88E5, 0x4EA6, 0x9692, 0x4EA8, 0x8B9C, 0x4EAB, 0x8B9D, 0x4EAC, 0x8B9E, 0x4EAD, 0x92E0, 0x4EAE, 0x97BA, 0x4EB0, 0x98B5, 0x4EB3, 0x98B6, 0x4EB6, 0x98B7, 0x4EBA, 0x906C, 0x4EC0, 0x8F59, 0x4EC1, 0x906D, 0x4EC2, 0x98BC, 0x4EC4, 0x98BA, 0x4EC6, 0x98BB, 0x4EC7, 0x8B77, 0x4ECA, 0x8DA1, 0x4ECB, 0x89EE, 0x4ECD, 0x98B9, 0x4ECE, 0x98B8, 0x4ECF, 0x95A7, 0x4ED4, 0x8E65, 0x4ED5, 0x8E64, 0x4ED6, 0x91BC, 0x4ED7, 0x98BD, 0x4ED8, 0x9574, 0x4ED9, 0x90E5, 0x4EDD, 0x8157, 0x4EDE, 0x98BE, 0x4EDF, 0x98C0, 0x4EE1, 0xFA69, 0x4EE3, 0x91E3, 0x4EE4, 0x97DF, 0x4EE5, 0x88C8, 0x4EED, 0x98BF, 0x4EEE, 0x89BC, 0x4EF0, 0x8BC2, 0x4EF2, 0x9287, 0x4EF6, 0x8C8F, 0x4EF7, 0x98C1, 0x4EFB, 0x9443, 0x4EFC, 0xFA6A, 0x4F00, 0xFA6B, 0x4F01, 0x8AE9, 0x4F03, 0xFA6C, 0x4F09, 0x98C2, 0x4F0A, 0x88C9, 0x4F0D, 0x8CDE, 0x4F0E, 0x8AEA, 0x4F0F, 0x959A, 0x4F10, 0x94B0, 0x4F11, 0x8B78, 0x4F1A, 0x89EF, 0x4F1C, 0x98E5, 0x4F1D, 0x9360, 0x4F2F, 0x948C, 0x4F30, 0x98C4, 0x4F34, 0x94BA, 0x4F36, 0x97E0, 0x4F38, 0x904C, 0x4F39, 0xFA6D, 0x4F3A, 0x8E66, 0x4F3C, 0x8E97, 0x4F3D, 0x89BE, 0x4F43, 0x92CF, 0x4F46, 0x9241, 0x4F47, 0x98C8, 0x4F4D, 0x88CA, 0x4F4E, 0x92E1, 0x4F4F, 0x8F5A, 0x4F50, 0x8DB2, 0x4F51, 0x9743, 0x4F53, 0x91CC, 0x4F55, 0x89BD, 0x4F56, 0xFA6E, 0x4F57, 0x98C7, 0x4F59, 0x975D, 0x4F5A, 0x98C3, 0x4F5B, 0x98C5, 0x4F5C, 0x8DEC, 0x4F5D, 0x98C6, 0x4F5E, 0x9B43, 0x4F69, 0x98CE, 0x4F6F, 0x98D1, 0x4F70, 0x98CF, 0x4F73, 0x89C0, 0x4F75, 0x95B9, 0x4F76, 0x98C9, 0x4F7B, 0x98CD, 0x4F7C, 0x8CF1, 0x4F7F, 0x8E67, 0x4F83, 0x8AA4, 0x4F86, 0x98D2, 0x4F88, 0x98CA, 0x4F8A, 0xFA70, 0x4F8B, 0x97E1, 0x4F8D, 0x8E98, 0x4F8F, 0x98CB, 0x4F91, 0x98D0, 0x4F92, 0xFA6F, 0x4F94, 0xFA72, 0x4F96, 0x98D3, 0x4F98, 0x98CC, 0x4F9A, 0xFA71, 0x4F9B, 0x8B9F, 0x4F9D, 0x88CB, 0x4FA0, 0x8BA0, 0x4FA1, 0x89BF, 0x4FAB, 0x9B44, 0x4FAD, 0x9699, 0x4FAE, 0x958E, 0x4FAF, 0x8CF2, 0x4FB5, 0x904E, 0x4FB6, 0x97B5, 0x4FBF, 0x95D6, 0x4FC2, 0x8C57, 0x4FC3, 0x91A3, 0x4FC4, 0x89E2, 0x4FC9, 0xFA61, 0x4FCA, 0x8F72, 0x4FCD, 0xFA73, 0x4FCE, 0x98D7, 0x4FD0, 0x98DC, 0x4FD1, 0x98DA, 0x4FD4, 0x98D5, 0x4FD7, 0x91AD, 0x4FD8, 0x98D8, 0x4FDA, 0x98DB, 0x4FDB, 0x98D9, 0x4FDD, 0x95DB, 0x4FDF, 0x98D6, 0x4FE1, 0x904D, 0x4FE3, 0x9693, 0x4FE4, 0x98DD, 0x4FE5, 0x98DE, 0x4FEE, 0x8F43, 0x4FEF, 0x98EB, 0x4FF3, 0x946F, 0x4FF5, 0x9555, 0x4FF6, 0x98E6, 0x4FF8, 0x95EE, 0x4FFA, 0x89B4, 0x4FFE, 0x98EA, 0x4FFF, 0xFA76, 0x5005, 0x98E4, 0x5006, 0x98ED, 0x5009, 0x9171, 0x500B, 0x8CC2, 0x500D, 0x947B, 0x500F, 0xE0C5, 0x5011, 0x98EC, 0x5012, 0x937C, 0x5014, 0x98E1, 0x5016, 0x8CF4, 0x5019, 0x8CF3, 0x501A, 0x98DF, 0x501E, 0xFA77, 0x501F, 0x8ED8, 0x5021, 0x98E7, 0x5022, 0xFA75, 0x5023, 0x95ED, 0x5024, 0x926C, 0x5025, 0x98E3, 0x5026, 0x8C91, 0x5028, 0x98E0, 0x5029, 0x98E8, 0x502A, 0x98E2, 0x502B, 0x97CF, 0x502C, 0x98E9, 0x502D, 0x9860, 0x5036, 0x8BE4, 0x5039, 0x8C90, 0x5040, 0xFA74, 0x5042, 0xFA7A, 0x5043, 0x98EE, 0x5046, 0xFA78, 0x5047, 0x98EF, 0x5048, 0x98F3, 0x5049, 0x88CC, 0x504F, 0x95CE, 0x5050, 0x98F2, 0x5055, 0x98F1, 0x5056, 0x98F5, 0x505A, 0x98F4, 0x505C, 0x92E2, 0x5065, 0x8C92, 0x506C, 0x98F6, 0x5070, 0xFA79, 0x5072, 0x8EC3, 0x5074, 0x91A4, 0x5075, 0x92E3, 0x5076, 0x8BF4, 0x5078, 0x98F7, 0x507D, 0x8B55, 0x5080, 0x98F8, 0x5085, 0x98FA, 0x508D, 0x9654, 0x5091, 0x8C86, 0x5094, 0xFA7B, 0x5098, 0x8E50, 0x5099, 0x94F5, 0x509A, 0x98F9, 0x50AC, 0x8DC3, 0x50AD, 0x9762, 0x50B2, 0x98FC, 0x50B3, 0x9942, 0x50B4, 0x98FB, 0x50B5, 0x8DC2, 0x50B7, 0x8F9D, 0x50BE, 0x8C58, 0x50C2, 0x9943, 0x50C5, 0x8BCD, 0x50C9, 0x9940, 0x50CA, 0x9941, 0x50CD, 0x93AD, 0x50CF, 0x919C, 0x50D1, 0x8BA1, 0x50D5, 0x966C, 0x50D6, 0x9944, 0x50D8, 0xFA7D, 0x50DA, 0x97BB, 0x50DE, 0x9945, 0x50E3, 0x9948, 0x50E5, 0x9946, 0x50E7, 0x916D, 0x50ED, 0x9947, 0x50EE, 0x9949, 0x50F4, 0xFA7C, 0x50F5, 0x994B, 0x50F9, 0x994A, 0x50FB, 0x95C6, 0x5100, 0x8B56, 0x5101, 0x994D, 0x5102, 0x994E, 0x5104, 0x89AD, 0x5109, 0x994C, 0x5112, 0x8EF2, 0x5114, 0x9951, 0x5115, 0x9950, 0x5116, 0x994F, 0x5118, 0x98D4, 0x511A, 0x9952, 0x511F, 0x8F9E, 0x5121, 0x9953, 0x512A, 0x9744, 0x5132, 0x96D7, 0x5137, 0x9955, 0x513A, 0x9954, 0x513B, 0x9957, 0x513C, 0x9956, 0x513F, 0x9958, 0x5140, 0x9959, 0x5141, 0x88F2, 0x5143, 0x8CB3, 0x5144, 0x8C5A, 0x5145, 0x8F5B, 0x5146, 0x929B, 0x5147, 0x8BA2, 0x5148, 0x90E6, 0x5149, 0x8CF5, 0x514A, 0xFA7E, 0x514B, 0x8D8E, 0x514C, 0x995B, 0x514D, 0x96C6, 0x514E, 0x9365, 0x5150, 0x8E99, 0x5152, 0x995A, 0x5154, 0x995C, 0x515A, 0x937D, 0x515C, 0x8A95, 0x5162, 0x995D, 0x5164, 0xFA80, 0x5165, 0x93FC, 0x5168, 0x9153, 0x5169, 0x995F, 0x516A, 0x9960, 0x516B, 0x94AA, 0x516C, 0x8CF6, 0x516D, 0x985A, 0x516E, 0x9961, 0x5171, 0x8BA4, 0x5175, 0x95BA, 0x5176, 0x91B4, 0x5177, 0x8BEF, 0x5178, 0x9354, 0x517C, 0x8C93, 0x5180, 0x9962, 0x5182, 0x9963, 0x5185, 0x93E0, 0x5186, 0x897E, 0x5189, 0x9966, 0x518A, 0x8DFB, 0x518C, 0x9965, 0x518D, 0x8DC4, 0x518F, 0x9967, 0x5190, 0xE3EC, 0x5191, 0x9968, 0x5192, 0x9660, 0x5193, 0x9969, 0x5195, 0x996A, 0x5196, 0x996B, 0x5197, 0x8FE7, 0x5199, 0x8ECA, 0x519D, 0xFA81, 0x51A0, 0x8AA5, 0x51A2, 0x996E, 0x51A4, 0x996C, 0x51A5, 0x96BB, 0x51A6, 0x996D, 0x51A8, 0x9579, 0x51A9, 0x996F, 0x51AA, 0x9970, 0x51AB, 0x9971, 0x51AC, 0x937E, 0x51B0, 0x9975, 0x51B1, 0x9973, 0x51B2, 0x9974, 0x51B3, 0x9972, 0x51B4, 0x8DE1, 0x51B5, 0x9976, 0x51B6, 0x96E8, 0x51B7, 0x97E2, 0x51BD, 0x9977, 0x51BE, 0xFA82, 0x51C4, 0x90A6, 0x51C5, 0x9978, 0x51C6, 0x8F79, 0x51C9, 0x9979, 0x51CB, 0x929C, 0x51CC, 0x97BD, 0x51CD, 0x9380, 0x51D6, 0x99C3, 0x51DB, 0x997A, 0x51DC, 0xEAA3, 0x51DD, 0x8BC3, 0x51E0, 0x997B, 0x51E1, 0x967D, 0x51E6, 0x8F88, 0x51E7, 0x91FA, 0x51E9, 0x997D, 0x51EA, 0x93E2, 0x51EC, 0xFA83, 0x51ED, 0x997E, 0x51F0, 0x9980, 0x51F1, 0x8A4D, 0x51F5, 0x9981, 0x51F6, 0x8BA5, 0x51F8, 0x93CA, 0x51F9, 0x899A, 0x51FA, 0x8F6F, 0x51FD, 0x949F, 0x51FE, 0x9982, 0x5200, 0x9381, 0x5203, 0x906E, 0x5204, 0x9983, 0x5206, 0x95AA, 0x5207, 0x90D8, 0x5208, 0x8AA0, 0x520A, 0x8AA7, 0x520B, 0x9984, 0x520E, 0x9986, 0x5211, 0x8C59, 0x5214, 0x9985, 0x5215, 0xFA84, 0x5217, 0x97F1, 0x521D, 0x8F89, 0x5224, 0x94BB, 0x5225, 0x95CA, 0x5227, 0x9987, 0x5229, 0x9798, 0x522A, 0x9988, 0x522E, 0x9989, 0x5230, 0x939E, 0x5233, 0x998A, 0x5236, 0x90A7, 0x5237, 0x8DFC, 0x5238, 0x8C94, 0x5239, 0x998B, 0x523A, 0x8E68, 0x523B, 0x8D8F, 0x5243, 0x92E4, 0x5244, 0x998D, 0x5247, 0x91A5, 0x524A, 0x8DED, 0x524B, 0x998E, 0x524C, 0x998F, 0x524D, 0x914F, 0x524F, 0x998C, 0x5254, 0x9991, 0x5256, 0x9655, 0x525B, 0x8D84, 0x525E, 0x9990, 0x5263, 0x8C95, 0x5264, 0x8DDC, 0x5265, 0x948D, 0x5269, 0x9994, 0x526A, 0x9992, 0x526F, 0x959B, 0x5270, 0x8FE8, 0x5271, 0x999B, 0x5272, 0x8A84, 0x5273, 0x9995, 0x5274, 0x9993, 0x5275, 0x916E, 0x527D, 0x9997, 0x527F, 0x9996, 0x5283, 0x8A63, 0x5287, 0x8C80, 0x5288, 0x999C, 0x5289, 0x97AB, 0x528D, 0x9998, 0x5291, 0x999D, 0x5292, 0x999A, 0x5294, 0x9999, 0x529B, 0x97CD, 0x529C, 0xFA85, 0x529F, 0x8CF7, 0x52A0, 0x89C1, 0x52A3, 0x97F2, 0x52A6, 0xFA86, 0x52A9, 0x8F95, 0x52AA, 0x9377, 0x52AB, 0x8D85, 0x52AC, 0x99A0, 0x52AD, 0x99A1, 0x52AF, 0xFB77, 0x52B1, 0x97E3, 0x52B4, 0x984A, 0x52B5, 0x99A3, 0x52B9, 0x8CF8, 0x52BC, 0x99A2, 0x52BE, 0x8A4E, 0x52C0, 0xFA87, 0x52C1, 0x99A4, 0x52C3, 0x9675, 0x52C5, 0x92BA, 0x52C7, 0x9745, 0x52C9, 0x95D7, 0x52CD, 0x99A5, 0x52D2, 0xE8D3, 0x52D5, 0x93AE, 0x52D7, 0x99A6, 0x52D8, 0x8AA8, 0x52D9, 0x96B1, 0x52DB, 0xFA88, 0x52DD, 0x8F9F, 0x52DE, 0x99A7, 0x52DF, 0x95E5, 0x52E0, 0x99AB, 0x52E2, 0x90A8, 0x52E3, 0x99A8, 0x52E4, 0x8BCE, 0x52E6, 0x99A9, 0x52E7, 0x8AA9, 0x52F2, 0x8C4D, 0x52F3, 0x99AC, 0x52F5, 0x99AD, 0x52F8, 0x99AE, 0x52F9, 0x99AF, 0x52FA, 0x8ED9, 0x52FE, 0x8CF9, 0x52FF, 0x96DC, 0x5300, 0xFA89, 0x5301, 0x96E6, 0x5302, 0x93F5, 0x5305, 0x95EF, 0x5306, 0x99B0, 0x5307, 0xFA8A, 0x5308, 0x99B1, 0x530D, 0x99B3, 0x530F, 0x99B5, 0x5310, 0x99B4, 0x5315, 0x99B6, 0x5316, 0x89BB, 0x5317, 0x966B, 0x5319, 0x8DFA, 0x531A, 0x99B7, 0x531D, 0x9178, 0x5320, 0x8FA0, 0x5321, 0x8BA7, 0x5323, 0x99B8, 0x5324, 0xFA8B, 0x532A, 0x94D9, 0x532F, 0x99B9, 0x5331, 0x99BA, 0x5333, 0x99BB, 0x5338, 0x99BC, 0x5339, 0x9543, 0x533A, 0x8BE6, 0x533B, 0x88E3, 0x533F, 0x93BD, 0x5340, 0x99BD, 0x5341, 0x8F5C, 0x5343, 0x90E7, 0x5345, 0x99BF, 0x5346, 0x99BE, 0x5347, 0x8FA1, 0x5348, 0x8CDF, 0x5349, 0x99C1, 0x534A, 0x94BC, 0x534D, 0x99C2, 0x5351, 0x94DA, 0x5352, 0x91B2, 0x5353, 0x91EC, 0x5354, 0x8BA6, 0x5357, 0x93EC, 0x5358, 0x9250, 0x535A, 0x948E, 0x535C, 0x966D, 0x535E, 0x99C4, 0x5360, 0x90E8, 0x5366, 0x8C54, 0x5369, 0x99C5, 0x536E, 0x99C6, 0x536F, 0x894B, 0x5370, 0x88F3, 0x5371, 0x8AEB, 0x5372, 0xFA8C, 0x5373, 0x91A6, 0x5374, 0x8B70, 0x5375, 0x9791, 0x5377, 0x99C9, 0x5378, 0x89B5, 0x537B, 0x99C8, 0x537F, 0x8BA8, 0x5382, 0x99CA, 0x5384, 0x96EF, 0x5393, 0xFA8D, 0x5396, 0x99CB, 0x5398, 0x97D0, 0x539A, 0x8CFA, 0x539F, 0x8CB4, 0x53A0, 0x99CC, 0x53A5, 0x99CE, 0x53A6, 0x99CD, 0x53A8, 0x907E, 0x53A9, 0x8958, 0x53AD, 0x897D, 0x53AE, 0x99CF, 0x53B0, 0x99D0, 0x53B2, 0xFA8E, 0x53B3, 0x8CB5, 0x53B6, 0x99D1, 0x53BB, 0x8B8E, 0x53C2, 0x8E51, 0x53C3, 0x99D2, 0x53C8, 0x9694, 0x53C9, 0x8DB3, 0x53CA, 0x8B79, 0x53CB, 0x9746, 0x53CC, 0x916F, 0x53CD, 0x94BD, 0x53CE, 0x8EFB, 0x53D4, 0x8F66, 0x53D6, 0x8EE6, 0x53D7, 0x8EF3, 0x53D9, 0x8F96, 0x53DB, 0x94BE, 0x53DD, 0xFA8F, 0x53DF, 0x99D5, 0x53E1, 0x8962, 0x53E2, 0x9170, 0x53E3, 0x8CFB, 0x53E4, 0x8CC3, 0x53E5, 0x8BE5, 0x53E8, 0x99D9, 0x53E9, 0x9240, 0x53EA, 0x91FC, 0x53EB, 0x8BA9, 0x53EC, 0x8FA2, 0x53ED, 0x99DA, 0x53EE, 0x99D8, 0x53EF, 0x89C2, 0x53F0, 0x91E4, 0x53F1, 0x8EB6, 0x53F2, 0x8E6A, 0x53F3, 0x8945, 0x53F6, 0x8A90, 0x53F7, 0x8D86, 0x53F8, 0x8E69, 0x53FA, 0x99DB, 0x5401, 0x99DC, 0x5403, 0x8B68, 0x5404, 0x8A65, 0x5408, 0x8D87, 0x5409, 0x8B67, 0x540A, 0x92DD, 0x540B, 0x8944, 0x540C, 0x93AF, 0x540D, 0x96BC, 0x540E, 0x8D40, 0x540F, 0x9799, 0x5410, 0x9366, 0x5411, 0x8CFC, 0x541B, 0x8C4E, 0x541D, 0x99E5, 0x541F, 0x8BE1, 0x5420, 0x9669, 0x5426, 0x94DB, 0x5429, 0x99E4, 0x542B, 0x8ADC, 0x542C, 0x99DF, 0x542D, 0x99E0, 0x542E, 0x99E2, 0x5436, 0x99E3, 0x5438, 0x8B7A, 0x5439, 0x9081, 0x543B, 0x95AB, 0x543C, 0x99E1, 0x543D, 0x99DD, 0x543E, 0x8CE1, 0x5440, 0x99DE, 0x5442, 0x9843, 0x5446, 0x95F0, 0x5448, 0x92E6, 0x5449, 0x8CE0, 0x544A, 0x8D90, 0x544E, 0x99E6, 0x5451, 0x93DB, 0x545F, 0x99EA, 0x5468, 0x8EFC, 0x546A, 0x8EF4, 0x5470, 0x99ED, 0x5471, 0x99EB, 0x5473, 0x96A1, 0x5475, 0x99E8, 0x5476, 0x99F1, 0x5477, 0x99EC, 0x547B, 0x99EF, 0x547C, 0x8CC4, 0x547D, 0x96BD, 0x5480, 0x99F0, 0x5484, 0x99F2, 0x5486, 0x99F4, 0x548A, 0xFA92, 0x548B, 0x8DEE, 0x548C, 0x9861, 0x548E, 0x99E9, 0x548F, 0x99E7, 0x5490, 0x99F3, 0x5492, 0x99EE, 0x549C, 0xFA91, 0x54A2, 0x99F6, 0x54A4, 0x9A42, 0x54A5, 0x99F8, 0x54A8, 0x99FC, 0x54A9, 0xFA93, 0x54AB, 0x9A40, 0x54AC, 0x99F9, 0x54AF, 0x9A5D, 0x54B2, 0x8DE7, 0x54B3, 0x8A50, 0x54B8, 0x99F7, 0x54BC, 0x9A44, 0x54BD, 0x88F4, 0x54BE, 0x9A43, 0x54C0, 0x88A3, 0x54C1, 0x9569, 0x54C2, 0x9A41, 0x54C4, 0x99FA, 0x54C7, 0x99F5, 0x54C8, 0x99FB, 0x54C9, 0x8DC6, 0x54D8, 0x9A45, 0x54E1, 0x88F5, 0x54E2, 0x9A4E, 0x54E5, 0x9A46, 0x54E6, 0x9A47, 0x54E8, 0x8FA3, 0x54E9, 0x9689, 0x54ED, 0x9A4C, 0x54EE, 0x9A4B, 0x54F2, 0x934E, 0x54FA, 0x9A4D, 0x54FD, 0x9A4A, 0x54FF, 0xFA94, 0x5504, 0x8953, 0x5506, 0x8DB4, 0x5507, 0x904F, 0x550F, 0x9A48, 0x5510, 0x9382, 0x5514, 0x9A49, 0x5516, 0x88A0, 0x552E, 0x9A53, 0x552F, 0x9742, 0x5531, 0x8FA5, 0x5533, 0x9A59, 0x5538, 0x9A58, 0x5539, 0x9A4F, 0x553E, 0x91C1, 0x5540, 0x9A50, 0x5544, 0x91ED, 0x5545, 0x9A55, 0x5546, 0x8FA4, 0x554C, 0x9A52, 0x554F, 0x96E2, 0x5553, 0x8C5B, 0x5556, 0x9A56, 0x5557, 0x9A57, 0x555C, 0x9A54, 0x555D, 0x9A5A, 0x5563, 0x9A51, 0x557B, 0x9A60, 0x557C, 0x9A65, 0x557E, 0x9A61, 0x5580, 0x9A5C, 0x5583, 0x9A66, 0x5584, 0x9150, 0x5586, 0xFA95, 0x5587, 0x9A68, 0x5589, 0x8D41, 0x558A, 0x9A5E, 0x558B, 0x929D, 0x5598, 0x9A62, 0x5599, 0x9A5B, 0x559A, 0x8AAB, 0x559C, 0x8AEC, 0x559D, 0x8A85, 0x559E, 0x9A63, 0x559F, 0x9A5F, 0x55A7, 0x8C96, 0x55A8, 0x9A69, 0x55A9, 0x9A67, 0x55AA, 0x9172, 0x55AB, 0x8B69, 0x55AC, 0x8BAA, 0x55AE, 0x9A64, 0x55B0, 0x8BF2, 0x55B6, 0x8963, 0x55C4, 0x9A6D, 0x55C5, 0x9A6B, 0x55C7, 0x9AA5, 0x55D4, 0x9A70, 0x55DA, 0x9A6A, 0x55DC, 0x9A6E, 0x55DF, 0x9A6C, 0x55E3, 0x8E6B, 0x55E4, 0x9A6F, 0x55F7, 0x9A72, 0x55F9, 0x9A77, 0x55FD, 0x9A75, 0x55FE, 0x9A74, 0x5606, 0x9251, 0x5609, 0x89C3, 0x5614, 0x9A71, 0x5616, 0x9A73, 0x5617, 0x8FA6, 0x5618, 0x8952, 0x561B, 0x9A76, 0x5629, 0x89DC, 0x562F, 0x9A82, 0x5631, 0x8FFA, 0x5632, 0x9A7D, 0x5634, 0x9A7B, 0x5636, 0x9A7C, 0x5638, 0x9A7E, 0x5642, 0x895C, 0x564C, 0x9158, 0x564E, 0x9A78, 0x5650, 0x9A79, 0x565B, 0x8A9A, 0x5664, 0x9A81, 0x5668, 0x8AED, 0x566A, 0x9A84, 0x566B, 0x9A80, 0x566C, 0x9A83, 0x5674, 0x95AC, 0x5678, 0x93D3, 0x567A, 0x94B6, 0x5680, 0x9A86, 0x5686, 0x9A85, 0x5687, 0x8A64, 0x568A, 0x9A87, 0x568F, 0x9A8A, 0x5694, 0x9A89, 0x56A0, 0x9A88, 0x56A2, 0x9458, 0x56A5, 0x9A8B, 0x56AE, 0x9A8C, 0x56B4, 0x9A8E, 0x56B6, 0x9A8D, 0x56BC, 0x9A90, 0x56C0, 0x9A93, 0x56C1, 0x9A91, 0x56C2, 0x9A8F, 0x56C3, 0x9A92, 0x56C8, 0x9A94, 0x56CE, 0x9A95, 0x56D1, 0x9A96, 0x56D3, 0x9A97, 0x56D7, 0x9A98, 0x56D8, 0x9964, 0x56DA, 0x8EFA, 0x56DB, 0x8E6C, 0x56DE, 0x89F1, 0x56E0, 0x88F6, 0x56E3, 0x9263, 0x56EE, 0x9A99, 0x56F0, 0x8DA2, 0x56F2, 0x88CD, 0x56F3, 0x907D, 0x56F9, 0x9A9A, 0x56FA, 0x8CC5, 0x56FD, 0x8D91, 0x56FF, 0x9A9C, 0x5700, 0x9A9B, 0x5703, 0x95DE, 0x5704, 0x9A9D, 0x5708, 0x9A9F, 0x5709, 0x9A9E, 0x570B, 0x9AA0, 0x570D, 0x9AA1, 0x570F, 0x8C97, 0x5712, 0x8980, 0x5713, 0x9AA2, 0x5716, 0x9AA4, 0x5718, 0x9AA3, 0x571C, 0x9AA6, 0x571F, 0x9379, 0x5726, 0x9AA7, 0x5727, 0x88B3, 0x5728, 0x8DDD, 0x572D, 0x8C5C, 0x5730, 0x926E, 0x5737, 0x9AA8, 0x5738, 0x9AA9, 0x573B, 0x9AAB, 0x5740, 0x9AAC, 0x5742, 0x8DE2, 0x5747, 0x8BCF, 0x574A, 0x9656, 0x574E, 0x9AAA, 0x574F, 0x9AAD, 0x5750, 0x8DBF, 0x5751, 0x8D42, 0x5759, 0xFA96, 0x5761, 0x9AB1, 0x5764, 0x8DA3, 0x5765, 0xFA97, 0x5766, 0x9252, 0x5769, 0x9AAE, 0x576A, 0x92D8, 0x577F, 0x9AB2, 0x5782, 0x9082, 0x5788, 0x9AB0, 0x5789, 0x9AB3, 0x578B, 0x8C5E, 0x5793, 0x9AB4, 0x57A0, 0x9AB5, 0x57A2, 0x8D43, 0x57A3, 0x8A5F, 0x57A4, 0x9AB7, 0x57AA, 0x9AB8, 0x57AC, 0xFA98, 0x57B0, 0x9AB9, 0x57B3, 0x9AB6, 0x57C0, 0x9AAF, 0x57C3, 0x9ABA, 0x57C6, 0x9ABB, 0x57C7, 0xFA9A, 0x57C8, 0xFA99, 0x57CB, 0x9684, 0x57CE, 0x8FE9, 0x57D2, 0x9ABD, 0x57D3, 0x9ABE, 0x57D4, 0x9ABC, 0x57D6, 0x9AC0, 0x57DC, 0x9457, 0x57DF, 0x88E6, 0x57E0, 0x9575, 0x57E3, 0x9AC1, 0x57F4, 0x8FFB, 0x57F7, 0x8EB7, 0x57F9, 0x947C, 0x57FA, 0x8AEE, 0x57FC, 0x8DE9, 0x5800, 0x9678, 0x5802, 0x93B0, 0x5805, 0x8C98, 0x5806, 0x91CD, 0x580A, 0x9ABF, 0x580B, 0x9AC2, 0x5815, 0x91C2, 0x5819, 0x9AC3, 0x581D, 0x9AC4, 0x5821, 0x9AC6, 0x5824, 0x92E7, 0x582A, 0x8AAC, 0x582F, 0xEA9F, 0x5830, 0x8981, 0x5831, 0x95F1, 0x5834, 0x8FEA, 0x5835, 0x9367, 0x583A, 0x8DE4, 0x583D, 0x9ACC, 0x5840, 0x95BB, 0x5841, 0x97DB, 0x584A, 0x89F2, 0x584B, 0x9AC8, 0x5851, 0x9159, 0x5852, 0x9ACB, 0x5854, 0x9383, 0x5857, 0x9368, 0x5858, 0x9384, 0x5859, 0x94B7, 0x585A, 0x92CB, 0x585E, 0x8DC7, 0x5862, 0x9AC7, 0x5869, 0x8996, 0x586B, 0x9355, 0x5870, 0x9AC9, 0x5872, 0x9AC5, 0x5875, 0x906F, 0x5879, 0x9ACD, 0x587E, 0x8F6D, 0x5883, 0x8BAB, 0x5885, 0x9ACE, 0x5893, 0x95E6, 0x5897, 0x919D, 0x589C, 0x92C4, 0x589E, 0xFA9D, 0x589F, 0x9AD0, 0x58A8, 0x966E, 0x58AB, 0x9AD1, 0x58AE, 0x9AD6, 0x58B2, 0xFA9E, 0x58B3, 0x95AD, 0x58B8, 0x9AD5, 0x58B9, 0x9ACF, 0x58BA, 0x9AD2, 0x58BB, 0x9AD4, 0x58BE, 0x8DA4, 0x58C1, 0x95C7, 0x58C5, 0x9AD7, 0x58C7, 0x9264, 0x58CA, 0x89F3, 0x58CC, 0x8FEB, 0x58D1, 0x9AD9, 0x58D3, 0x9AD8, 0x58D5, 0x8D88, 0x58D7, 0x9ADA, 0x58D8, 0x9ADC, 0x58D9, 0x9ADB, 0x58DC, 0x9ADE, 0x58DE, 0x9AD3, 0x58DF, 0x9AE0, 0x58E4, 0x9ADF, 0x58E5, 0x9ADD, 0x58EB, 0x8E6D, 0x58EC, 0x9070, 0x58EE, 0x9173, 0x58EF, 0x9AE1, 0x58F0, 0x90BA, 0x58F1, 0x88EB, 0x58F2, 0x9484, 0x58F7, 0x92D9, 0x58F9, 0x9AE3, 0x58FA, 0x9AE2, 0x58FB, 0x9AE4, 0x58FC, 0x9AE5, 0x58FD, 0x9AE6, 0x5902, 0x9AE7, 0x5909, 0x95CF, 0x590A, 0x9AE8, 0x590B, 0xFA9F, 0x590F, 0x89C4, 0x5910, 0x9AE9, 0x5915, 0x975B, 0x5916, 0x8A4F, 0x5918, 0x99C7, 0x5919, 0x8F67, 0x591A, 0x91BD, 0x591B, 0x9AEA, 0x591C, 0x96E9, 0x5922, 0x96B2, 0x5925, 0x9AEC, 0x5927, 0x91E5, 0x5929, 0x9356, 0x592A, 0x91BE, 0x592B, 0x9576, 0x592C, 0x9AED, 0x592D, 0x9AEE, 0x592E, 0x899B, 0x5931, 0x8EB8, 0x5932, 0x9AEF, 0x5937, 0x88CE, 0x5938, 0x9AF0, 0x593E, 0x9AF1, 0x5944, 0x8982, 0x5947, 0x8AEF, 0x5948, 0x93DE, 0x5949, 0x95F2, 0x594E, 0x9AF5, 0x594F, 0x9174, 0x5950, 0x9AF4, 0x5951, 0x8C5F, 0x5953, 0xFAA0, 0x5954, 0x967A, 0x5955, 0x9AF3, 0x5957, 0x9385, 0x5958, 0x9AF7, 0x595A, 0x9AF6, 0x595B, 0xFAA1, 0x595D, 0xFAA2, 0x5960, 0x9AF9, 0x5962, 0x9AF8, 0x5963, 0xFAA3, 0x5965, 0x899C, 0x5967, 0x9AFA, 0x5968, 0x8FA7, 0x5969, 0x9AFC, 0x596A, 0x9244, 0x596C, 0x9AFB, 0x596E, 0x95B1, 0x5973, 0x8F97, 0x5974, 0x937A, 0x5978, 0x9B40, 0x597D, 0x8D44, 0x5981, 0x9B41, 0x5982, 0x9440, 0x5983, 0x94DC, 0x5984, 0x96CF, 0x598A, 0x9444, 0x598D, 0x9B4A, 0x5993, 0x8B57, 0x5996, 0x9764, 0x5999, 0x96AD, 0x599B, 0x9BAA, 0x599D, 0x9B42, 0x59A3, 0x9B45, 0x59A4, 0xFAA4, 0x59A5, 0x91C3, 0x59A8, 0x9657, 0x59AC, 0x9369, 0x59B2, 0x9B46, 0x59B9, 0x9685, 0x59BA, 0xFAA5, 0x59BB, 0x8DC8, 0x59BE, 0x8FA8, 0x59C6, 0x9B47, 0x59C9, 0x8E6F, 0x59CB, 0x8E6E, 0x59D0, 0x88B7, 0x59D1, 0x8CC6, 0x59D3, 0x90A9, 0x59D4, 0x88CF, 0x59D9, 0x9B4B, 0x59DA, 0x9B4C, 0x59DC, 0x9B49, 0x59E5, 0x8957, 0x59E6, 0x8AAD, 0x59E8, 0x9B48, 0x59EA, 0x96C3, 0x59EB, 0x9550, 0x59F6, 0x88A6, 0x59FB, 0x88F7, 0x59FF, 0x8E70, 0x5A01, 0x88D0, 0x5A03, 0x88A1, 0x5A09, 0x9B51, 0x5A11, 0x9B4F, 0x5A18, 0x96BA, 0x5A1A, 0x9B52, 0x5A1C, 0x9B50, 0x5A1F, 0x9B4E, 0x5A20, 0x9050, 0x5A25, 0x9B4D, 0x5A29, 0x95D8, 0x5A2F, 0x8CE2, 0x5A35, 0x9B56, 0x5A36, 0x9B57, 0x5A3C, 0x8FA9, 0x5A40, 0x9B53, 0x5A41, 0x984B, 0x5A46, 0x946B, 0x5A49, 0x9B55, 0x5A5A, 0x8DA5, 0x5A62, 0x9B58, 0x5A66, 0x9577, 0x5A6A, 0x9B59, 0x5A6C, 0x9B54, 0x5A7F, 0x96B9, 0x5A92, 0x947D, 0x5A9A, 0x9B5A, 0x5A9B, 0x9551, 0x5ABC, 0x9B5B, 0x5ABD, 0x9B5F, 0x5ABE, 0x9B5C, 0x5AC1, 0x89C5, 0x5AC2, 0x9B5E, 0x5AC9, 0x8EB9, 0x5ACB, 0x9B5D, 0x5ACC, 0x8C99, 0x5AD0, 0x9B6B, 0x5AD6, 0x9B64, 0x5AD7, 0x9B61, 0x5AE1, 0x9284, 0x5AE3, 0x9B60, 0x5AE6, 0x9B62, 0x5AE9, 0x9B63, 0x5AFA, 0x9B65, 0x5AFB, 0x9B66, 0x5B09, 0x8AF0, 0x5B0B, 0x9B68, 0x5B0C, 0x9B67, 0x5B16, 0x9B69, 0x5B22, 0x8FEC, 0x5B2A, 0x9B6C, 0x5B2C, 0x92DA, 0x5B30, 0x8964, 0x5B32, 0x9B6A, 0x5B36, 0x9B6D, 0x5B3E, 0x9B6E, 0x5B40, 0x9B71, 0x5B43, 0x9B6F, 0x5B45, 0x9B70, 0x5B50, 0x8E71, 0x5B51, 0x9B72, 0x5B54, 0x8D45, 0x5B55, 0x9B73, 0x5B56, 0xFAA6, 0x5B57, 0x8E9A, 0x5B58, 0x91B6, 0x5B5A, 0x9B74, 0x5B5B, 0x9B75, 0x5B5C, 0x8E79, 0x5B5D, 0x8D46, 0x5B5F, 0x96D0, 0x5B63, 0x8B47, 0x5B64, 0x8CC7, 0x5B65, 0x9B76, 0x5B66, 0x8A77, 0x5B69, 0x9B77, 0x5B6B, 0x91B7, 0x5B70, 0x9B78, 0x5B71, 0x9BA1, 0x5B73, 0x9B79, 0x5B75, 0x9B7A, 0x5B78, 0x9B7B, 0x5B7A, 0x9B7D, 0x5B80, 0x9B7E, 0x5B83, 0x9B80, 0x5B85, 0x91EE, 0x5B87, 0x8946, 0x5B88, 0x8EE7, 0x5B89, 0x88C0, 0x5B8B, 0x9176, 0x5B8C, 0x8AAE, 0x5B8D, 0x8EB3, 0x5B8F, 0x8D47, 0x5B95, 0x9386, 0x5B97, 0x8F40, 0x5B98, 0x8AAF, 0x5B99, 0x9288, 0x5B9A, 0x92E8, 0x5B9B, 0x88B6, 0x5B9C, 0x8B58, 0x5B9D, 0x95F3, 0x5B9F, 0x8EC0, 0x5BA2, 0x8B71, 0x5BA3, 0x90E9, 0x5BA4, 0x8EBA, 0x5BA5, 0x9747, 0x5BA6, 0x9B81, 0x5BAE, 0x8B7B, 0x5BB0, 0x8DC9, 0x5BB3, 0x8A51, 0x5BB4, 0x8983, 0x5BB5, 0x8FAA, 0x5BB6, 0x89C6, 0x5BB8, 0x9B82, 0x5BB9, 0x9765, 0x5BBF, 0x8F68, 0x5BC0, 0xFAA7, 0x5BC2, 0x8EE2, 0x5BC3, 0x9B83, 0x5BC4, 0x8AF1, 0x5BC5, 0x93D0, 0x5BC6, 0x96A7, 0x5BC7, 0x9B84, 0x5BC9, 0x9B85, 0x5BCC, 0x9578, 0x5BD0, 0x9B87, 0x5BD2, 0x8AA6, 0x5BD3, 0x8BF5, 0x5BD4, 0x9B86, 0x5BD8, 0xFAA9, 0x5BDB, 0x8AB0, 0x5BDD, 0x9051, 0x5BDE, 0x9B8B, 0x5BDF, 0x8E40, 0x5BE1, 0x89C7, 0x5BE2, 0x9B8A, 0x5BE4, 0x9B88, 0x5BE5, 0x9B8C, 0x5BE6, 0x9B89, 0x5BE7, 0x944A, 0x5BE8, 0x9ECB, 0x5BE9, 0x9052, 0x5BEB, 0x9B8D, 0x5BEC, 0xFAAA, 0x5BEE, 0x97BE, 0x5BF0, 0x9B8E, 0x5BF3, 0x9B90, 0x5BF5, 0x929E, 0x5BF6, 0x9B8F, 0x5BF8, 0x90A1, 0x5BFA, 0x8E9B, 0x5BFE, 0x91CE, 0x5BFF, 0x8EF5, 0x5C01, 0x9595, 0x5C02, 0x90EA, 0x5C04, 0x8ECB, 0x5C05, 0x9B91, 0x5C06, 0x8FAB, 0x5C07, 0x9B92, 0x5C08, 0x9B93, 0x5C09, 0x88D1, 0x5C0A, 0x91B8, 0x5C0B, 0x9071, 0x5C0D, 0x9B94, 0x5C0E, 0x93B1, 0x5C0F, 0x8FAC, 0x5C11, 0x8FAD, 0x5C13, 0x9B95, 0x5C16, 0x90EB, 0x5C1A, 0x8FAE, 0x5C1E, 0xFAAB, 0x5C20, 0x9B96, 0x5C22, 0x9B97, 0x5C24, 0x96DE, 0x5C28, 0x9B98, 0x5C2D, 0x8BC4, 0x5C31, 0x8F41, 0x5C38, 0x9B99, 0x5C39, 0x9B9A, 0x5C3A, 0x8EDA, 0x5C3B, 0x904B, 0x5C3C, 0x93F2, 0x5C3D, 0x9073, 0x5C3E, 0x94F6, 0x5C3F, 0x9441, 0x5C40, 0x8BC7, 0x5C41, 0x9B9B, 0x5C45, 0x8B8F, 0x5C46, 0x9B9C, 0x5C48, 0x8BFC, 0x5C4A, 0x93CD, 0x5C4B, 0x89AE, 0x5C4D, 0x8E72, 0x5C4E, 0x9B9D, 0x5C4F, 0x9BA0, 0x5C50, 0x9B9F, 0x5C51, 0x8BFB, 0x5C53, 0x9B9E, 0x5C55, 0x9357, 0x5C5E, 0x91AE, 0x5C60, 0x936A, 0x5C61, 0x8EC6, 0x5C64, 0x9177, 0x5C65, 0x979A, 0x5C6C, 0x9BA2, 0x5C6E, 0x9BA3, 0x5C6F, 0x93D4, 0x5C71, 0x8E52, 0x5C76, 0x9BA5, 0x5C79, 0x9BA6, 0x5C8C, 0x9BA7, 0x5C90, 0x8AF2, 0x5C91, 0x9BA8, 0x5C94, 0x9BA9, 0x5CA1, 0x89AA, 0x5CA6, 0xFAAC, 0x5CA8, 0x915A, 0x5CA9, 0x8AE2, 0x5CAB, 0x9BAB, 0x5CAC, 0x96A6, 0x5CB1, 0x91D0, 0x5CB3, 0x8A78, 0x5CB6, 0x9BAD, 0x5CB7, 0x9BAF, 0x5CB8, 0x8ADD, 0x5CBA, 0xFAAD, 0x5CBB, 0x9BAC, 0x5CBC, 0x9BAE, 0x5CBE, 0x9BB1, 0x5CC5, 0x9BB0, 0x5CC7, 0x9BB2, 0x5CD9, 0x9BB3, 0x5CE0, 0x93BB, 0x5CE1, 0x8BAC, 0x5CE8, 0x89E3, 0x5CE9, 0x9BB4, 0x5CEA, 0x9BB9, 0x5CED, 0x9BB7, 0x5CEF, 0x95F5, 0x5CF0, 0x95F4, 0x5CF5, 0xFAAE, 0x5CF6, 0x9387, 0x5CFA, 0x9BB6, 0x5CFB, 0x8F73, 0x5CFD, 0x9BB5, 0x5D07, 0x9092, 0x5D0B, 0x9BBA, 0x5D0E, 0x8DE8, 0x5D11, 0x9BC0, 0x5D14, 0x9BC1, 0x5D15, 0x9BBB, 0x5D16, 0x8A52, 0x5D17, 0x9BBC, 0x5D18, 0x9BC5, 0x5D19, 0x9BC4, 0x5D1A, 0x9BC3, 0x5D1B, 0x9BBF, 0x5D1F, 0x9BBE, 0x5D22, 0x9BC2, 0x5D27, 0xFAAF, 0x5D29, 0x95F6, 0x5D42, 0xFAB2, 0x5D4B, 0x9BC9, 0x5D4C, 0x9BC6, 0x5D4E, 0x9BC8, 0x5D50, 0x9792, 0x5D52, 0x9BC7, 0x5D53, 0xFAB0, 0x5D5C, 0x9BBD, 0x5D69, 0x9093, 0x5D6C, 0x9BCA, 0x5D6D, 0xFAB3, 0x5D6F, 0x8DB5, 0x5D73, 0x9BCB, 0x5D76, 0x9BCC, 0x5D82, 0x9BCF, 0x5D84, 0x9BCE, 0x5D87, 0x9BCD, 0x5D8B, 0x9388, 0x5D8C, 0x9BB8, 0x5D90, 0x9BD5, 0x5D9D, 0x9BD1, 0x5DA2, 0x9BD0, 0x5DAC, 0x9BD2, 0x5DAE, 0x9BD3, 0x5DB7, 0x9BD6, 0x5DB8, 0xFAB4, 0x5DB9, 0xFAB5, 0x5DBA, 0x97E4, 0x5DBC, 0x9BD7, 0x5DBD, 0x9BD4, 0x5DC9, 0x9BD8, 0x5DCC, 0x8ADE, 0x5DCD, 0x9BD9, 0x5DD0, 0xFAB6, 0x5DD2, 0x9BDB, 0x5DD3, 0x9BDA, 0x5DD6, 0x9BDC, 0x5DDB, 0x9BDD, 0x5DDD, 0x90EC, 0x5DDE, 0x8F42, 0x5DE1, 0x8F84, 0x5DE3, 0x9183, 0x5DE5, 0x8D48, 0x5DE6, 0x8DB6, 0x5DE7, 0x8D49, 0x5DE8, 0x8B90, 0x5DEB, 0x9BDE, 0x5DEE, 0x8DB7, 0x5DF1, 0x8CC8, 0x5DF2, 0x9BDF, 0x5DF3, 0x96A4, 0x5DF4, 0x9462, 0x5DF5, 0x9BE0, 0x5DF7, 0x8D4A, 0x5DFB, 0x8AAA, 0x5DFD, 0x9246, 0x5DFE, 0x8BD0, 0x5E02, 0x8E73, 0x5E03, 0x957A, 0x5E06, 0x94BF, 0x5E0B, 0x9BE1, 0x5E0C, 0x8AF3, 0x5E11, 0x9BE4, 0x5E16, 0x929F, 0x5E19, 0x9BE3, 0x5E1A, 0x9BE2, 0x5E1B, 0x9BE5, 0x5E1D, 0x92E9, 0x5E25, 0x9083, 0x5E2B, 0x8E74, 0x5E2D, 0x90C8, 0x5E2F, 0x91D1, 0x5E30, 0x8B41, 0x5E33, 0x92A0, 0x5E36, 0x9BE6, 0x5E37, 0x9BE7, 0x5E38, 0x8FED, 0x5E3D, 0x9658, 0x5E40, 0x9BEA, 0x5E43, 0x9BE9, 0x5E44, 0x9BE8, 0x5E45, 0x959D, 0x5E47, 0x9BF1, 0x5E4C, 0x9679, 0x5E4E, 0x9BEB, 0x5E54, 0x9BED, 0x5E55, 0x968B, 0x5E57, 0x9BEC, 0x5E5F, 0x9BEE, 0x5E61, 0x94A6, 0x5E62, 0x9BEF, 0x5E63, 0x95BC, 0x5E64, 0x9BF0, 0x5E72, 0x8AB1, 0x5E73, 0x95BD, 0x5E74, 0x944E, 0x5E75, 0x9BF2, 0x5E76, 0x9BF3, 0x5E78, 0x8D4B, 0x5E79, 0x8AB2, 0x5E7A, 0x9BF4, 0x5E7B, 0x8CB6, 0x5E7C, 0x9763, 0x5E7D, 0x9748, 0x5E7E, 0x8AF4, 0x5E7F, 0x9BF6, 0x5E81, 0x92A1, 0x5E83, 0x8D4C, 0x5E84, 0x8FAF, 0x5E87, 0x94DD, 0x5E8A, 0x8FB0, 0x5E8F, 0x8F98, 0x5E95, 0x92EA, 0x5E96, 0x95F7, 0x5E97, 0x9358, 0x5E9A, 0x8D4D, 0x5E9C, 0x957B, 0x5EA0, 0x9BF7, 0x5EA6, 0x9378, 0x5EA7, 0x8DC0, 0x5EAB, 0x8CC9, 0x5EAD, 0x92EB, 0x5EB5, 0x88C1, 0x5EB6, 0x8F8E, 0x5EB7, 0x8D4E, 0x5EB8, 0x9766, 0x5EC1, 0x9BF8, 0x5EC2, 0x9BF9, 0x5EC3, 0x9470, 0x5EC8, 0x9BFA, 0x5EC9, 0x97F5, 0x5ECA, 0x984C, 0x5ECF, 0x9BFC, 0x5ED0, 0x9BFB, 0x5ED3, 0x8A66, 0x5ED6, 0x9C40, 0x5EDA, 0x9C43, 0x5EDB, 0x9C44, 0x5EDD, 0x9C42, 0x5EDF, 0x955F, 0x5EE0, 0x8FB1, 0x5EE1, 0x9C46, 0x5EE2, 0x9C45, 0x5EE3, 0x9C41, 0x5EE8, 0x9C47, 0x5EE9, 0x9C48, 0x5EEC, 0x9C49, 0x5EF0, 0x9C4C, 0x5EF1, 0x9C4A, 0x5EF3, 0x9C4B, 0x5EF4, 0x9C4D, 0x5EF6, 0x8984, 0x5EF7, 0x92EC, 0x5EF8, 0x9C4E, 0x5EFA, 0x8C9A, 0x5EFB, 0x89F4, 0x5EFC, 0x9455, 0x5EFE, 0x9C4F, 0x5EFF, 0x93F9, 0x5F01, 0x95D9, 0x5F03, 0x9C50, 0x5F04, 0x984D, 0x5F09, 0x9C51, 0x5F0A, 0x95BE, 0x5F0B, 0x9C54, 0x5F0C, 0x989F, 0x5F0D, 0x98AF, 0x5F0F, 0x8EAE, 0x5F10, 0x93F3, 0x5F11, 0x9C55, 0x5F13, 0x8B7C, 0x5F14, 0x92A2, 0x5F15, 0x88F8, 0x5F16, 0x9C56, 0x5F17, 0x95A4, 0x5F18, 0x8D4F, 0x5F1B, 0x926F, 0x5F1F, 0x92ED, 0x5F21, 0xFAB7, 0x5F25, 0x96ED, 0x5F26, 0x8CB7, 0x5F27, 0x8CCA, 0x5F29, 0x9C57, 0x5F2D, 0x9C58, 0x5F2F, 0x9C5E, 0x5F31, 0x8EE3, 0x5F34, 0xFAB8, 0x5F35, 0x92A3, 0x5F37, 0x8BAD, 0x5F38, 0x9C59, 0x5F3C, 0x954A, 0x5F3E, 0x9265, 0x5F41, 0x9C5A, 0x5F45, 0xFA67, 0x5F48, 0x9C5B, 0x5F4A, 0x8BAE, 0x5F4C, 0x9C5C, 0x5F4E, 0x9C5D, 0x5F51, 0x9C5F, 0x5F53, 0x9396, 0x5F56, 0x9C60, 0x5F57, 0x9C61, 0x5F59, 0x9C62, 0x5F5C, 0x9C53, 0x5F5D, 0x9C52, 0x5F61, 0x9C63, 0x5F62, 0x8C60, 0x5F66, 0x9546, 0x5F67, 0xFAB9, 0x5F69, 0x8DCA, 0x5F6A, 0x9556, 0x5F6B, 0x92A4, 0x5F6C, 0x956A, 0x5F6D, 0x9C64, 0x5F70, 0x8FB2, 0x5F71, 0x8965, 0x5F73, 0x9C65, 0x5F77, 0x9C66, 0x5F79, 0x96F0, 0x5F7C, 0x94DE, 0x5F7F, 0x9C69, 0x5F80, 0x899D, 0x5F81, 0x90AA, 0x5F82, 0x9C68, 0x5F83, 0x9C67, 0x5F84, 0x8C61, 0x5F85, 0x91D2, 0x5F87, 0x9C6D, 0x5F88, 0x9C6B, 0x5F8A, 0x9C6A, 0x5F8B, 0x97A5, 0x5F8C, 0x8CE3, 0x5F90, 0x8F99, 0x5F91, 0x9C6C, 0x5F92, 0x936B, 0x5F93, 0x8F5D, 0x5F97, 0x93BE, 0x5F98, 0x9C70, 0x5F99, 0x9C6F, 0x5F9E, 0x9C6E, 0x5FA0, 0x9C71, 0x5FA1, 0x8CE4, 0x5FA8, 0x9C72, 0x5FA9, 0x959C, 0x5FAA, 0x8F7A, 0x5FAD, 0x9C73, 0x5FAE, 0x94F7, 0x5FB3, 0x93BF, 0x5FB4, 0x92A5, 0x5FB7, 0xFABA, 0x5FB9, 0x934F, 0x5FBC, 0x9C74, 0x5FBD, 0x8B4A, 0x5FC3, 0x9053, 0x5FC5, 0x954B, 0x5FCC, 0x8AF5, 0x5FCD, 0x9445, 0x5FD6, 0x9C75, 0x5FD7, 0x8E75, 0x5FD8, 0x9659, 0x5FD9, 0x965A, 0x5FDC, 0x899E, 0x5FDD, 0x9C7A, 0x5FDE, 0xFABB, 0x5FE0, 0x9289, 0x5FE4, 0x9C77, 0x5FEB, 0x89F5, 0x5FF0, 0x9CAB, 0x5FF1, 0x9C79, 0x5FF5, 0x944F, 0x5FF8, 0x9C78, 0x5FFB, 0x9C76, 0x5FFD, 0x8D9A, 0x5FFF, 0x9C7C, 0x600E, 0x9C83, 0x600F, 0x9C89, 0x6010, 0x9C81, 0x6012, 0x937B, 0x6015, 0x9C86, 0x6016, 0x957C, 0x6019, 0x9C80, 0x601B, 0x9C85, 0x601C, 0x97E5, 0x601D, 0x8E76, 0x6020, 0x91D3, 0x6021, 0x9C7D, 0x6025, 0x8B7D, 0x6026, 0x9C88, 0x6027, 0x90AB, 0x6028, 0x8985, 0x6029, 0x9C82, 0x602A, 0x89F6, 0x602B, 0x9C87, 0x602F, 0x8BAF, 0x6031, 0x9C84, 0x603A, 0x9C8A, 0x6041, 0x9C8C, 0x6042, 0x9C96, 0x6043, 0x9C94, 0x6046, 0x9C91, 0x604A, 0x9C90, 0x604B, 0x97F6, 0x604D, 0x9C92, 0x6050, 0x8BB0, 0x6052, 0x8D50, 0x6055, 0x8F9A, 0x6059, 0x9C99, 0x605A, 0x9C8B, 0x605D, 0xFABC, 0x605F, 0x9C8F, 0x6060, 0x9C7E, 0x6062, 0x89F8, 0x6063, 0x9C93, 0x6064, 0x9C95, 0x6065, 0x9270, 0x6068, 0x8DA6, 0x6069, 0x89B6, 0x606A, 0x9C8D, 0x606B, 0x9C98, 0x606C, 0x9C97, 0x606D, 0x8BB1, 0x606F, 0x91A7, 0x6070, 0x8A86, 0x6075, 0x8C62, 0x6077, 0x9C8E, 0x6081, 0x9C9A, 0x6083, 0x9C9D, 0x6084, 0x9C9F, 0x6085, 0xFABD, 0x6089, 0x8EBB, 0x608A, 0xFABE, 0x608B, 0x9CA5, 0x608C, 0x92EE, 0x608D, 0x9C9B, 0x6092, 0x9CA3, 0x6094, 0x89F7, 0x6096, 0x9CA1, 0x6097, 0x9CA2, 0x609A, 0x9C9E, 0x609B, 0x9CA0, 0x609F, 0x8CE5, 0x60A0, 0x9749, 0x60A3, 0x8AB3, 0x60A6, 0x8978, 0x60A7, 0x9CA4, 0x60A9, 0x9459, 0x60AA, 0x88AB, 0x60B2, 0x94DF, 0x60B3, 0x9C7B, 0x60B4, 0x9CAA, 0x60B5, 0x9CAE, 0x60B6, 0x96E3, 0x60B8, 0x9CA7, 0x60BC, 0x9389, 0x60BD, 0x9CAC, 0x60C5, 0x8FEE, 0x60C6, 0x9CAD, 0x60C7, 0x93D5, 0x60D1, 0x9866, 0x60D3, 0x9CA9, 0x60D5, 0xFAC0, 0x60D8, 0x9CAF, 0x60DA, 0x8D9B, 0x60DC, 0x90C9, 0x60DE, 0xFABF, 0x60DF, 0x88D2, 0x60E0, 0x9CA8, 0x60E1, 0x9CA6, 0x60E3, 0x9179, 0x60E7, 0x9C9C, 0x60E8, 0x8E53, 0x60F0, 0x91C4, 0x60F1, 0x9CBB, 0x60F2, 0xFAC2, 0x60F3, 0x917A, 0x60F4, 0x9CB6, 0x60F6, 0x9CB3, 0x60F7, 0x9CB4, 0x60F9, 0x8EE4, 0x60FA, 0x9CB7, 0x60FB, 0x9CBA, 0x6100, 0x9CB5, 0x6101, 0x8F44, 0x6103, 0x9CB8, 0x6106, 0x9CB2, 0x6108, 0x96FA, 0x6109, 0x96F9, 0x610D, 0x9CBC, 0x610E, 0x9CBD, 0x610F, 0x88D3, 0x6111, 0xFAC3, 0x6115, 0x9CB1, 0x611A, 0x8BF0, 0x611B, 0x88A4, 0x611F, 0x8AB4, 0x6120, 0xFAC1, 0x6121, 0x9CB9, 0x6127, 0x9CC1, 0x6128, 0x9CC0, 0x612C, 0x9CC5, 0x6130, 0xFAC5, 0x6134, 0x9CC6, 0x6137, 0xFAC4, 0x613C, 0x9CC4, 0x613D, 0x9CC7, 0x613E, 0x9CBF, 0x613F, 0x9CC3, 0x6142, 0x9CC8, 0x6144, 0x9CC9, 0x6147, 0x9CBE, 0x6148, 0x8E9C, 0x614A, 0x9CC2, 0x614B, 0x91D4, 0x614C, 0x8D51, 0x614D, 0x9CB0, 0x614E, 0x9054, 0x6153, 0x9CD6, 0x6155, 0x95E7, 0x6158, 0x9CCC, 0x6159, 0x9CCD, 0x615A, 0x9CCE, 0x615D, 0x9CD5, 0x615F, 0x9CD4, 0x6162, 0x969D, 0x6163, 0x8AB5, 0x6165, 0x9CD2, 0x6167, 0x8C64, 0x6168, 0x8A53, 0x616B, 0x9CCF, 0x616E, 0x97B6, 0x616F, 0x9CD1, 0x6170, 0x88D4, 0x6171, 0x9CD3, 0x6173, 0x9CCA, 0x6174, 0x9CD0, 0x6175, 0x9CD7, 0x6176, 0x8C63, 0x6177, 0x9CCB, 0x617E, 0x977C, 0x6182, 0x974A, 0x6187, 0x9CDA, 0x618A, 0x9CDE, 0x618E, 0x919E, 0x6190, 0x97F7, 0x6191, 0x9CDF, 0x6194, 0x9CDC, 0x6196, 0x9CD9, 0x6198, 0xFAC6, 0x6199, 0x9CD8, 0x619A, 0x9CDD, 0x61A4, 0x95AE, 0x61A7, 0x93B2, 0x61A9, 0x8C65, 0x61AB, 0x9CE0, 0x61AC, 0x9CDB, 0x61AE, 0x9CE1, 0x61B2, 0x8C9B, 0x61B6, 0x89AF, 0x61BA, 0x9CE9, 0x61BE, 0x8AB6, 0x61C3, 0x9CE7, 0x61C6, 0x9CE8, 0x61C7, 0x8DA7, 0x61C8, 0x9CE6, 0x61C9, 0x9CE4, 0x61CA, 0x9CE3, 0x61CB, 0x9CEA, 0x61CC, 0x9CE2, 0x61CD, 0x9CEC, 0x61D0, 0x89F9, 0x61E3, 0x9CEE, 0x61E6, 0x9CED, 0x61F2, 0x92A6, 0x61F4, 0x9CF1, 0x61F6, 0x9CEF, 0x61F7, 0x9CE5, 0x61F8, 0x8C9C, 0x61FA, 0x9CF0, 0x61FC, 0x9CF4, 0x61FD, 0x9CF3, 0x61FE, 0x9CF5, 0x61FF, 0x9CF2, 0x6200, 0x9CF6, 0x6208, 0x9CF7, 0x6209, 0x9CF8, 0x620A, 0x95E8, 0x620C, 0x9CFA, 0x620D, 0x9CF9, 0x620E, 0x8F5E, 0x6210, 0x90AC, 0x6211, 0x89E4, 0x6212, 0x89FA, 0x6213, 0xFAC7, 0x6214, 0x9CFB, 0x6216, 0x88BD, 0x621A, 0x90CA, 0x621B, 0x9CFC, 0x621D, 0xE6C1, 0x621E, 0x9D40, 0x621F, 0x8C81, 0x6221, 0x9D41, 0x6226, 0x90ED, 0x622A, 0x9D42, 0x622E, 0x9D43, 0x622F, 0x8B59, 0x6230, 0x9D44, 0x6232, 0x9D45, 0x6233, 0x9D46, 0x6234, 0x91D5, 0x6238, 0x8CCB, 0x623B, 0x96DF, 0x623F, 0x965B, 0x6240, 0x8F8A, 0x6241, 0x9D47, 0x6247, 0x90EE, 0x6248, 0xE7BB, 0x6249, 0x94E0, 0x624B, 0x8EE8, 0x624D, 0x8DCB, 0x624E, 0x9D48, 0x6253, 0x91C5, 0x6255, 0x95A5, 0x6258, 0x91EF, 0x625B, 0x9D4B, 0x625E, 0x9D49, 0x6260, 0x9D4C, 0x6263, 0x9D4A, 0x6268, 0x9D4D, 0x626E, 0x95AF, 0x6271, 0x88B5, 0x6276, 0x957D, 0x6279, 0x94E1, 0x627C, 0x9D4E, 0x627E, 0x9D51, 0x627F, 0x8FB3, 0x6280, 0x8B5A, 0x6282, 0x9D4F, 0x6283, 0x9D56, 0x6284, 0x8FB4, 0x6289, 0x9D50, 0x628A, 0x9463, 0x6291, 0x977D, 0x6292, 0x9D52, 0x6293, 0x9D53, 0x6294, 0x9D57, 0x6295, 0x938A, 0x6296, 0x9D54, 0x6297, 0x8D52, 0x6298, 0x90DC, 0x629B, 0x9D65, 0x629C, 0x94B2, 0x629E, 0x91F0, 0x62A6, 0xFAC8, 0x62AB, 0x94E2, 0x62AC, 0x9DAB, 0x62B1, 0x95F8, 0x62B5, 0x92EF, 0x62B9, 0x9695, 0x62BB, 0x9D5A, 0x62BC, 0x899F, 0x62BD, 0x928A, 0x62C2, 0x9D63, 0x62C5, 0x9253, 0x62C6, 0x9D5D, 0x62C7, 0x9D64, 0x62C8, 0x9D5F, 0x62C9, 0x9D66, 0x62CA, 0x9D62, 0x62CC, 0x9D61, 0x62CD, 0x948F, 0x62CF, 0x9D5B, 0x62D0, 0x89FB, 0x62D1, 0x9D59, 0x62D2, 0x8B91, 0x62D3, 0x91F1, 0x62D4, 0x9D55, 0x62D7, 0x9D58, 0x62D8, 0x8D53, 0x62D9, 0x90D9, 0x62DB, 0x8FB5, 0x62DC, 0x9D60, 0x62DD, 0x9471, 0x62E0, 0x8B92, 0x62E1, 0x8A67, 0x62EC, 0x8A87, 0x62ED, 0x9040, 0x62EE, 0x9D68, 0x62EF, 0x9D6D, 0x62F1, 0x9D69, 0x62F3, 0x8C9D, 0x62F5, 0x9D6E, 0x62F6, 0x8E41, 0x62F7, 0x8D89, 0x62FE, 0x8F45, 0x62FF, 0x9D5C, 0x6301, 0x8E9D, 0x6302, 0x9D6B, 0x6307, 0x8E77, 0x6308, 0x9D6C, 0x6309, 0x88C2, 0x630C, 0x9D67, 0x6311, 0x92A7, 0x6319, 0x8B93, 0x631F, 0x8BB2, 0x6327, 0x9D6A, 0x6328, 0x88A5, 0x632B, 0x8DC1, 0x632F, 0x9055, 0x633A, 0x92F0, 0x633D, 0x94D2, 0x633E, 0x9D70, 0x633F, 0x917D, 0x6349, 0x91A8, 0x634C, 0x8E4A, 0x634D, 0x9D71, 0x634F, 0x9D73, 0x6350, 0x9D6F, 0x6355, 0x95DF, 0x6357, 0x92BB, 0x635C, 0x917B, 0x6367, 0x95F9, 0x6368, 0x8ECC, 0x6369, 0x9D80, 0x636B, 0x9D7E, 0x636E, 0x9098, 0x6372, 0x8C9E, 0x6376, 0x9D78, 0x6377, 0x8FB7, 0x637A, 0x93E6, 0x637B, 0x9450, 0x6380, 0x9D76, 0x6383, 0x917C, 0x6388, 0x8EF6, 0x6389, 0x9D7B, 0x638C, 0x8FB6, 0x638E, 0x9D75, 0x638F, 0x9D7A, 0x6392, 0x9472, 0x6396, 0x9D74, 0x6398, 0x8C40, 0x639B, 0x8A7C, 0x639F, 0x9D7C, 0x63A0, 0x97A9, 0x63A1, 0x8DCC, 0x63A2, 0x9254, 0x63A3, 0x9D79, 0x63A5, 0x90DA, 0x63A7, 0x8D54, 0x63A8, 0x9084, 0x63A9, 0x8986, 0x63AA, 0x915B, 0x63AB, 0x9D77, 0x63AC, 0x8B64, 0x63B2, 0x8C66, 0x63B4, 0x92CD, 0x63B5, 0x9D7D, 0x63BB, 0x917E, 0x63BE, 0x9D81, 0x63C0, 0x9D83, 0x63C3, 0x91B5, 0x63C4, 0x9D89, 0x63C6, 0x9D84, 0x63C9, 0x9D86, 0x63CF, 0x9560, 0x63D0, 0x92F1, 0x63D2, 0x9D87, 0x63D6, 0x974B, 0x63DA, 0x9767, 0x63DB, 0x8AB7, 0x63E1, 0x88AC, 0x63E3, 0x9D85, 0x63E9, 0x9D82, 0x63EE, 0x8AF6, 0x63F4, 0x8987, 0x63F5, 0xFAC9, 0x63F6, 0x9D88, 0x63FA, 0x9768, 0x6406, 0x9D8C, 0x640D, 0x91B9, 0x640F, 0x9D93, 0x6413, 0x9D8D, 0x6416, 0x9D8A, 0x6417, 0x9D91, 0x641C, 0x9D72, 0x6426, 0x9D8E, 0x6428, 0x9D92, 0x642C, 0x94C0, 0x642D, 0x938B, 0x6434, 0x9D8B, 0x6436, 0x9D8F, 0x643A, 0x8C67, 0x643E, 0x8DEF, 0x6442, 0x90DB, 0x644E, 0x9D97, 0x6458, 0x9345, 0x6460, 0xFACA, 0x6467, 0x9D94, 0x6469, 0x9680, 0x646F, 0x9D95, 0x6476, 0x9D96, 0x6478, 0x96CC, 0x647A, 0x90A0, 0x6483, 0x8C82, 0x6488, 0x9D9D, 0x6492, 0x8E54, 0x6493, 0x9D9A, 0x6495, 0x9D99, 0x649A, 0x9451, 0x649D, 0xFACB, 0x649E, 0x93B3, 0x64A4, 0x9350, 0x64A5, 0x9D9B, 0x64A9, 0x9D9C, 0x64AB, 0x958F, 0x64AD, 0x9464, 0x64AE, 0x8E42, 0x64B0, 0x90EF, 0x64B2, 0x966F, 0x64B9, 0x8A68, 0x64BB, 0x9DA3, 0x64BC, 0x9D9E, 0x64C1, 0x9769, 0x64C2, 0x9DA5, 0x64C5, 0x9DA1, 0x64C7, 0x9DA2, 0x64CD, 0x9180, 0x64CE, 0xFACC, 0x64D2, 0x9DA0, 0x64D4, 0x9D5E, 0x64D8, 0x9DA4, 0x64DA, 0x9D9F, 0x64E0, 0x9DA9, 0x64E1, 0x9DAA, 0x64E2, 0x9346, 0x64E3, 0x9DAC, 0x64E6, 0x8E43, 0x64E7, 0x9DA7, 0x64EC, 0x8B5B, 0x64EF, 0x9DAD, 0x64F1, 0x9DA6, 0x64F2, 0x9DB1, 0x64F4, 0x9DB0, 0x64F6, 0x9DAF, 0x64FA, 0x9DB2, 0x64FD, 0x9DB4, 0x64FE, 0x8FEF, 0x6500, 0x9DB3, 0x6505, 0x9DB7, 0x6518, 0x9DB5, 0x651C, 0x9DB6, 0x651D, 0x9D90, 0x6523, 0x9DB9, 0x6524, 0x9DB8, 0x652A, 0x9D98, 0x652B, 0x9DBA, 0x652C, 0x9DAE, 0x652F, 0x8E78, 0x6534, 0x9DBB, 0x6535, 0x9DBC, 0x6536, 0x9DBE, 0x6537, 0x9DBD, 0x6538, 0x9DBF, 0x6539, 0x89FC, 0x653B, 0x8D55, 0x653E, 0x95FA, 0x653F, 0x90AD, 0x6545, 0x8CCC, 0x6548, 0x9DC1, 0x654D, 0x9DC4, 0x654E, 0xFACD, 0x654F, 0x9571, 0x6551, 0x8B7E, 0x6555, 0x9DC3, 0x6556, 0x9DC2, 0x6557, 0x9473, 0x6558, 0x9DC5, 0x6559, 0x8BB3, 0x655D, 0x9DC7, 0x655E, 0x9DC6, 0x6562, 0x8AB8, 0x6563, 0x8E55, 0x6566, 0x93D6, 0x656C, 0x8C68, 0x6570, 0x9094, 0x6572, 0x9DC8, 0x6574, 0x90AE, 0x6575, 0x9347, 0x6577, 0x957E, 0x6578, 0x9DC9, 0x6582, 0x9DCA, 0x6583, 0x9DCB, 0x6587, 0x95B6, 0x6588, 0x9B7C, 0x6589, 0x90C4, 0x658C, 0x956B, 0x658E, 0x8DD6, 0x6590, 0x94E3, 0x6591, 0x94C1, 0x6597, 0x936C, 0x6599, 0x97BF, 0x659B, 0x9DCD, 0x659C, 0x8ECE, 0x659F, 0x9DCE, 0x65A1, 0x88B4, 0x65A4, 0x8BD2, 0x65A5, 0x90CB, 0x65A7, 0x9580, 0x65AB, 0x9DCF, 0x65AC, 0x8E61, 0x65AD, 0x9266, 0x65AF, 0x8E7A, 0x65B0, 0x9056, 0x65B7, 0x9DD0, 0x65B9, 0x95FB, 0x65BC, 0x8997, 0x65BD, 0x8E7B, 0x65C1, 0x9DD3, 0x65C3, 0x9DD1, 0x65C4, 0x9DD4, 0x65C5, 0x97B7, 0x65C6, 0x9DD2, 0x65CB, 0x90F9, 0x65CC, 0x9DD5, 0x65CF, 0x91B0, 0x65D2, 0x9DD6, 0x65D7, 0x8AF8, 0x65D9, 0x9DD8, 0x65DB, 0x9DD7, 0x65E0, 0x9DD9, 0x65E1, 0x9DDA, 0x65E2, 0x8AF9, 0x65E5, 0x93FA, 0x65E6, 0x9255, 0x65E7, 0x8B8C, 0x65E8, 0x8E7C, 0x65E9, 0x9181, 0x65EC, 0x8F7B, 0x65ED, 0x88AE, 0x65F1, 0x9DDB, 0x65FA, 0x89A0, 0x65FB, 0x9DDF, 0x6600, 0xFACE, 0x6602, 0x8D56, 0x6603, 0x9DDE, 0x6606, 0x8DA9, 0x6607, 0x8FB8, 0x6609, 0xFAD1, 0x660A, 0x9DDD, 0x660C, 0x8FB9, 0x660E, 0x96BE, 0x660F, 0x8DA8, 0x6613, 0x88D5, 0x6614, 0x90CC, 0x6615, 0xFACF, 0x661C, 0x9DE4, 0x661E, 0xFAD3, 0x661F, 0x90AF, 0x6620, 0x8966, 0x6624, 0xFAD4, 0x6625, 0x8F74, 0x6627, 0x9686, 0x6628, 0x8DF0, 0x662D, 0x8FBA, 0x662E, 0xFAD2, 0x662F, 0x90A5, 0x6631, 0xFA63, 0x6634, 0x9DE3, 0x6635, 0x9DE1, 0x6636, 0x9DE2, 0x663B, 0xFAD0, 0x663C, 0x928B, 0x663F, 0x9E45, 0x6641, 0x9DE8, 0x6642, 0x8E9E, 0x6643, 0x8D57, 0x6644, 0x9DE6, 0x6649, 0x9DE7, 0x664B, 0x9057, 0x664F, 0x9DE5, 0x6652, 0x8E4E, 0x6657, 0xFAD6, 0x6659, 0xFAD7, 0x665D, 0x9DEA, 0x665E, 0x9DE9, 0x665F, 0x9DEE, 0x6662, 0x9DEF, 0x6664, 0x9DEB, 0x6665, 0xFAD5, 0x6666, 0x8A41, 0x6667, 0x9DEC, 0x6668, 0x9DED, 0x6669, 0x94D3, 0x666E, 0x9581, 0x666F, 0x8C69, 0x6670, 0x9DF0, 0x6673, 0xFAD9, 0x6674, 0x90B0, 0x6676, 0x8FBB, 0x667A, 0x9271, 0x6681, 0x8BC5, 0x6683, 0x9DF1, 0x6684, 0x9DF5, 0x6687, 0x89C9, 0x6688, 0x9DF2, 0x6689, 0x9DF4, 0x668E, 0x9DF3, 0x6691, 0x8F8B, 0x6696, 0x9267, 0x6697, 0x88C3, 0x6698, 0x9DF6, 0x6699, 0xFADA, 0x669D, 0x9DF7, 0x66A0, 0xFADB, 0x66A2, 0x92A8, 0x66A6, 0x97EF, 0x66AB, 0x8E62, 0x66AE, 0x95E9, 0x66B2, 0xFADC, 0x66B4, 0x965C, 0x66B8, 0x9E41, 0x66B9, 0x9DF9, 0x66BC, 0x9DFC, 0x66BE, 0x9DFB, 0x66BF, 0xFADD, 0x66C1, 0x9DF8, 0x66C4, 0x9E40, 0x66C7, 0x93DC, 0x66C9, 0x9DFA, 0x66D6, 0x9E42, 0x66D9, 0x8F8C, 0x66DA, 0x9E43, 0x66DC, 0x976A, 0x66DD, 0x9498, 0x66E0, 0x9E44, 0x66E6, 0x9E46, 0x66E9, 0x9E47, 0x66F0, 0x9E48, 0x66F2, 0x8BC8, 0x66F3, 0x8967, 0x66F4, 0x8D58, 0x66F5, 0x9E49, 0x66F7, 0x9E4A, 0x66F8, 0x8F91, 0x66F9, 0x9182, 0x66FA, 0xFADE, 0x66FB, 0xFA66, 0x66FC, 0x99D6, 0x66FD, 0x915D, 0x66FE, 0x915C, 0x66FF, 0x91D6, 0x6700, 0x8DC5, 0x6703, 0x98F0, 0x6708, 0x8C8E, 0x6709, 0x974C, 0x670B, 0x95FC, 0x670D, 0x959E, 0x670E, 0xFADF, 0x670F, 0x9E4B, 0x6714, 0x8DF1, 0x6715, 0x92BD, 0x6716, 0x9E4C, 0x6717, 0x984E, 0x671B, 0x965D, 0x671D, 0x92A9, 0x671E, 0x9E4D, 0x671F, 0x8AFA, 0x6726, 0x9E4E, 0x6727, 0x9E4F, 0x6728, 0x96D8, 0x672A, 0x96A2, 0x672B, 0x9696, 0x672C, 0x967B, 0x672D, 0x8E44, 0x672E, 0x9E51, 0x6731, 0x8EE9, 0x6734, 0x9670, 0x6736, 0x9E53, 0x6737, 0x9E56, 0x6738, 0x9E55, 0x673A, 0x8AF7, 0x673D, 0x8B80, 0x673F, 0x9E52, 0x6741, 0x9E54, 0x6746, 0x9E57, 0x6749, 0x9099, 0x674E, 0x979B, 0x674F, 0x88C7, 0x6750, 0x8DDE, 0x6751, 0x91BA, 0x6753, 0x8EDB, 0x6756, 0x8FF1, 0x6759, 0x9E5A, 0x675C, 0x936D, 0x675E, 0x9E58, 0x675F, 0x91A9, 0x6760, 0x9E59, 0x6761, 0x8FF0, 0x6762, 0x96DB, 0x6763, 0x9E5B, 0x6764, 0x9E5C, 0x6765, 0x9788, 0x6766, 0xFAE1, 0x676A, 0x9E61, 0x676D, 0x8D59, 0x676F, 0x9474, 0x6770, 0x9E5E, 0x6771, 0x938C, 0x6772, 0x9DDC, 0x6773, 0x9DE0, 0x6775, 0x8B6E, 0x6777, 0x9466, 0x677C, 0x9E60, 0x677E, 0x8FBC, 0x677F, 0x94C2, 0x6785, 0x9E66, 0x6787, 0x94F8, 0x6789, 0x9E5D, 0x678B, 0x9E63, 0x678C, 0x9E62, 0x6790, 0x90CD, 0x6795, 0x968D, 0x6797, 0x97D1, 0x679A, 0x9687, 0x679C, 0x89CA, 0x679D, 0x8E7D, 0x67A0, 0x9867, 0x67A1, 0x9E65, 0x67A2, 0x9095, 0x67A6, 0x9E64, 0x67A9, 0x9E5F, 0x67AF, 0x8CCD, 0x67B3, 0x9E6B, 0x67B4, 0x9E69, 0x67B6, 0x89CB, 0x67B7, 0x9E67, 0x67B8, 0x9E6D, 0x67B9, 0x9E73, 0x67BB, 0xFAE2, 0x67C0, 0xFAE4, 0x67C1, 0x91C6, 0x67C4, 0x95BF, 0x67C6, 0x9E75, 0x67CA, 0x9541, 0x67CE, 0x9E74, 0x67CF, 0x9490, 0x67D0, 0x965E, 0x67D1, 0x8AB9, 0x67D3, 0x90F5, 0x67D4, 0x8F5F, 0x67D8, 0x92D1, 0x67DA, 0x974D, 0x67DD, 0x9E70, 0x67DE, 0x9E6F, 0x67E2, 0x9E71, 0x67E4, 0x9E6E, 0x67E7, 0x9E76, 0x67E9, 0x9E6C, 0x67EC, 0x9E6A, 0x67EE, 0x9E72, 0x67EF, 0x9E68, 0x67F1, 0x928C, 0x67F3, 0x96F6, 0x67F4, 0x8EC4, 0x67F5, 0x8DF2, 0x67FB, 0x8DB8, 0x67FE, 0x968F, 0x67FF, 0x8A60, 0x6801, 0xFAE5, 0x6802, 0x92CC, 0x6803, 0x93C8, 0x6804, 0x8968, 0x6813, 0x90F0, 0x6816, 0x90B2, 0x6817, 0x8C49, 0x681E, 0x9E78, 0x6821, 0x8D5A, 0x6822, 0x8A9C, 0x6829, 0x9E7A, 0x682A, 0x8A94, 0x682B, 0x9E81, 0x6832, 0x9E7D, 0x6834, 0x90F1, 0x6838, 0x8A6A, 0x6839, 0x8DAA, 0x683C, 0x8A69, 0x683D, 0x8DCD, 0x6840, 0x9E7B, 0x6841, 0x8C85, 0x6842, 0x8C6A, 0x6843, 0x938D, 0x6844, 0xFAE6, 0x6846, 0x9E79, 0x6848, 0x88C4, 0x684D, 0x9E7C, 0x684E, 0x9E7E, 0x6850, 0x8BCB, 0x6851, 0x8C4B, 0x6852, 0xFAE3, 0x6853, 0x8ABA, 0x6854, 0x8B6A, 0x6859, 0x9E82, 0x685C, 0x8DF7, 0x685D, 0x9691, 0x685F, 0x8E56, 0x6863, 0x9E83, 0x6867, 0x954F, 0x6874, 0x9E8F, 0x6876, 0x89B1, 0x6877, 0x9E84, 0x687E, 0x9E95, 0x687F, 0x9E85, 0x6881, 0x97C0, 0x6883, 0x9E8C, 0x6885, 0x947E, 0x688D, 0x9E94, 0x688F, 0x9E87, 0x6893, 0x88B2, 0x6894, 0x9E89, 0x6897, 0x8D5B, 0x689B, 0x9E8B, 0x689D, 0x9E8A, 0x689F, 0x9E86, 0x68A0, 0x9E91, 0x68A2, 0x8FBD, 0x68A6, 0x9AEB, 0x68A7, 0x8CE6, 0x68A8, 0x979C, 0x68AD, 0x9E88, 0x68AF, 0x92F2, 0x68B0, 0x8A42, 0x68B1, 0x8DAB, 0x68B3, 0x9E80, 0x68B5, 0x9E90, 0x68B6, 0x8A81, 0x68B9, 0x9E8E, 0x68BA, 0x9E92, 0x68BC, 0x938E, 0x68C4, 0x8AFC, 0x68C6, 0x9EB0, 0x68C8, 0xFA64, 0x68C9, 0x96C7, 0x68CA, 0x9E97, 0x68CB, 0x8AFB, 0x68CD, 0x9E9E, 0x68CF, 0xFAE7, 0x68D2, 0x965F, 0x68D4, 0x9E9F, 0x68D5, 0x9EA1, 0x68D7, 0x9EA5, 0x68D8, 0x9E99, 0x68DA, 0x9249, 0x68DF, 0x938F, 0x68E0, 0x9EA9, 0x68E1, 0x9E9C, 0x68E3, 0x9EA6, 0x68E7, 0x9EA0, 0x68EE, 0x9058, 0x68EF, 0x9EAA, 0x68F2, 0x90B1, 0x68F9, 0x9EA8, 0x68FA, 0x8ABB, 0x6900, 0x986F, 0x6901, 0x9E96, 0x6904, 0x9EA4, 0x6905, 0x88D6, 0x6908, 0x9E98, 0x690B, 0x96B8, 0x690C, 0x9E9D, 0x690D, 0x9041, 0x690E, 0x92C5, 0x690F, 0x9E93, 0x6912, 0x9EA3, 0x6919, 0x909A, 0x691A, 0x9EAD, 0x691B, 0x8A91, 0x691C, 0x8C9F, 0x6921, 0x9EAF, 0x6922, 0x9E9A, 0x6923, 0x9EAE, 0x6925, 0x9EA7, 0x6926, 0x9E9B, 0x6928, 0x9EAB, 0x692A, 0x9EAC, 0x6930, 0x9EBD, 0x6934, 0x93CC, 0x6936, 0x9EA2, 0x6939, 0x9EB9, 0x693D, 0x9EBB, 0x693F, 0x92D6, 0x694A, 0x976B, 0x6953, 0x9596, 0x6954, 0x9EB6, 0x6955, 0x91C8, 0x6959, 0x9EBC, 0x695A, 0x915E, 0x695C, 0x9EB3, 0x695D, 0x9EC0, 0x695E, 0x9EBF, 0x6960, 0x93ED, 0x6961, 0x9EBE, 0x6962, 0x93E8, 0x6968, 0xFAE9, 0x696A, 0x9EC2, 0x696B, 0x9EB5, 0x696D, 0x8BC6, 0x696E, 0x9EB8, 0x696F, 0x8F7C, 0x6973, 0x9480, 0x6974, 0x9EBA, 0x6975, 0x8BC9, 0x6977, 0x9EB2, 0x6978, 0x9EB4, 0x6979, 0x9EB1, 0x697C, 0x984F, 0x697D, 0x8A79, 0x697E, 0x9EB7, 0x6981, 0x9EC1, 0x6982, 0x8A54, 0x698A, 0x8DE5, 0x698E, 0x897C, 0x6991, 0x9ED2, 0x6994, 0x9850, 0x6995, 0x9ED5, 0x6998, 0xFAEB, 0x699B, 0x9059, 0x699C, 0x9ED4, 0x69A0, 0x9ED3, 0x69A7, 0x9ED0, 0x69AE, 0x9EC4, 0x69B1, 0x9EE1, 0x69B2, 0x9EC3, 0x69B4, 0x9ED6, 0x69BB, 0x9ECE, 0x69BE, 0x9EC9, 0x69BF, 0x9EC6, 0x69C1, 0x9EC7, 0x69C3, 0x9ECF, 0x69C7, 0xEAA0, 0x69CA, 0x9ECC, 0x69CB, 0x8D5C, 0x69CC, 0x92C6, 0x69CD, 0x9184, 0x69CE, 0x9ECA, 0x69D0, 0x9EC5, 0x69D3, 0x9EC8, 0x69D8, 0x976C, 0x69D9, 0x968A, 0x69DD, 0x9ECD, 0x69DE, 0x9ED7, 0x69E2, 0xFAEC, 0x69E7, 0x9EDF, 0x69E8, 0x9ED8, 0x69EB, 0x9EE5, 0x69ED, 0x9EE3, 0x69F2, 0x9EDE, 0x69F9, 0x9EDD, 0x69FB, 0x92CE, 0x69FD, 0x9185, 0x69FF, 0x9EDB, 0x6A02, 0x9ED9, 0x6A05, 0x9EE0, 0x6A0A, 0x9EE6, 0x6A0B, 0x94F3, 0x6A0C, 0x9EEC, 0x6A12, 0x9EE7, 0x6A13, 0x9EEA, 0x6A14, 0x9EE4, 0x6A17, 0x9294, 0x6A19, 0x9557, 0x6A1B, 0x9EDA, 0x6A1E, 0x9EE2, 0x6A1F, 0x8FBE, 0x6A21, 0x96CD, 0x6A22, 0x9EF6, 0x6A23, 0x9EE9, 0x6A29, 0x8CA0, 0x6A2A, 0x89A1, 0x6A2B, 0x8A7E, 0x6A2E, 0x9ED1, 0x6A30, 0xFAED, 0x6A35, 0x8FBF, 0x6A36, 0x9EEE, 0x6A38, 0x9EF5, 0x6A39, 0x8EF7, 0x6A3A, 0x8A92, 0x6A3D, 0x924D, 0x6A44, 0x9EEB, 0x6A46, 0xFAEF, 0x6A47, 0x9EF0, 0x6A48, 0x9EF4, 0x6A4B, 0x8BB4, 0x6A58, 0x8B6B, 0x6A59, 0x9EF2, 0x6A5F, 0x8B40, 0x6A61, 0x93C9, 0x6A62, 0x9EF1, 0x6A66, 0x9EF3, 0x6A6B, 0xFAEE, 0x6A72, 0x9EED, 0x6A73, 0xFAF0, 0x6A78, 0x9EEF, 0x6A7E, 0xFAF1, 0x6A7F, 0x8A80, 0x6A80, 0x9268, 0x6A84, 0x9EFA, 0x6A8D, 0x9EF8, 0x6A8E, 0x8CE7, 0x6A90, 0x9EF7, 0x6A97, 0x9F40, 0x6A9C, 0x9E77, 0x6AA0, 0x9EF9, 0x6AA2, 0x9EFB, 0x6AA3, 0x9EFC, 0x6AAA, 0x9F4B, 0x6AAC, 0x9F47, 0x6AAE, 0x9E8D, 0x6AB3, 0x9F46, 0x6AB8, 0x9F45, 0x6ABB, 0x9F42, 0x6AC1, 0x9EE8, 0x6AC2, 0x9F44, 0x6AC3, 0x9F43, 0x6AD1, 0x9F49, 0x6AD3, 0x9845, 0x6ADA, 0x9F4C, 0x6ADB, 0x8BF9, 0x6ADE, 0x9F48, 0x6ADF, 0x9F4A, 0x6AE2, 0xFAF2, 0x6AE4, 0xFAF3, 0x6AE8, 0x94A5, 0x6AEA, 0x9F4D, 0x6AFA, 0x9F51, 0x6AFB, 0x9F4E, 0x6B04, 0x9793, 0x6B05, 0x9F4F, 0x6B0A, 0x9EDC, 0x6B12, 0x9F52, 0x6B16, 0x9F53, 0x6B1D, 0x8954, 0x6B1F, 0x9F55, 0x6B20, 0x8C87, 0x6B21, 0x8E9F, 0x6B23, 0x8BD3, 0x6B27, 0x89A2, 0x6B32, 0x977E, 0x6B37, 0x9F57, 0x6B38, 0x9F56, 0x6B39, 0x9F59, 0x6B3A, 0x8B5C, 0x6B3D, 0x8BD4, 0x6B3E, 0x8ABC, 0x6B43, 0x9F5C, 0x6B47, 0x9F5B, 0x6B49, 0x9F5D, 0x6B4C, 0x89CC, 0x6B4E, 0x9256, 0x6B50, 0x9F5E, 0x6B53, 0x8ABD, 0x6B54, 0x9F60, 0x6B59, 0x9F5F, 0x6B5B, 0x9F61, 0x6B5F, 0x9F62, 0x6B61, 0x9F63, 0x6B62, 0x8E7E, 0x6B63, 0x90B3, 0x6B64, 0x8D9F, 0x6B66, 0x9590, 0x6B69, 0x95E0, 0x6B6A, 0x9863, 0x6B6F, 0x8E95, 0x6B73, 0x8DCE, 0x6B74, 0x97F0, 0x6B78, 0x9F64, 0x6B79, 0x9F65, 0x6B7B, 0x8E80, 0x6B7F, 0x9F66, 0x6B80, 0x9F67, 0x6B83, 0x9F69, 0x6B84, 0x9F68, 0x6B86, 0x9677, 0x6B89, 0x8F7D, 0x6B8A, 0x8EEA, 0x6B8B, 0x8E63, 0x6B8D, 0x9F6A, 0x6B95, 0x9F6C, 0x6B96, 0x9042, 0x6B98, 0x9F6B, 0x6B9E, 0x9F6D, 0x6BA4, 0x9F6E, 0x6BAA, 0x9F6F, 0x6BAB, 0x9F70, 0x6BAF, 0x9F71, 0x6BB1, 0x9F73, 0x6BB2, 0x9F72, 0x6BB3, 0x9F74, 0x6BB4, 0x89A3, 0x6BB5, 0x9269, 0x6BB7, 0x9F75, 0x6BBA, 0x8E45, 0x6BBB, 0x8A6B, 0x6BBC, 0x9F76, 0x6BBF, 0x9361, 0x6BC0, 0x9ACA, 0x6BC5, 0x8B42, 0x6BC6, 0x9F77, 0x6BCB, 0x9F78, 0x6BCD, 0x95EA, 0x6BCE, 0x9688, 0x6BD2, 0x93C5, 0x6BD3, 0x9F79, 0x6BD4, 0x94E4, 0x6BD6, 0xFAF4, 0x6BD8, 0x94F9, 0x6BDB, 0x96D1, 0x6BDF, 0x9F7A, 0x6BEB, 0x9F7C, 0x6BEC, 0x9F7B, 0x6BEF, 0x9F7E, 0x6BF3, 0x9F7D, 0x6C08, 0x9F81, 0x6C0F, 0x8E81, 0x6C11, 0x96AF, 0x6C13, 0x9F82, 0x6C14, 0x9F83, 0x6C17, 0x8B43, 0x6C1B, 0x9F84, 0x6C23, 0x9F86, 0x6C24, 0x9F85, 0x6C34, 0x9085, 0x6C37, 0x9558, 0x6C38, 0x8969, 0x6C3E, 0x94C3, 0x6C3F, 0xFAF5, 0x6C40, 0x92F3, 0x6C41, 0x8F60, 0x6C42, 0x8B81, 0x6C4E, 0x94C4, 0x6C50, 0x8EAC, 0x6C55, 0x9F88, 0x6C57, 0x8ABE, 0x6C5A, 0x8998, 0x6C5C, 0xFAF6, 0x6C5D, 0x93F0, 0x6C5E, 0x9F87, 0x6C5F, 0x8D5D, 0x6C60, 0x9272, 0x6C62, 0x9F89, 0x6C68, 0x9F91, 0x6C6A, 0x9F8A, 0x6C6F, 0xFAF8, 0x6C70, 0x91BF, 0x6C72, 0x8B82, 0x6C73, 0x9F92, 0x6C7A, 0x8C88, 0x6C7D, 0x8B44, 0x6C7E, 0x9F90, 0x6C81, 0x9F8E, 0x6C82, 0x9F8B, 0x6C83, 0x9780, 0x6C86, 0xFAF7, 0x6C88, 0x92BE, 0x6C8C, 0x93D7, 0x6C8D, 0x9F8C, 0x6C90, 0x9F94, 0x6C92, 0x9F93, 0x6C93, 0x8C42, 0x6C96, 0x89AB, 0x6C99, 0x8DB9, 0x6C9A, 0x9F8D, 0x6C9B, 0x9F8F, 0x6CA1, 0x9676, 0x6CA2, 0x91F2, 0x6CAB, 0x9697, 0x6CAE, 0x9F9C, 0x6CB1, 0x9F9D, 0x6CB3, 0x89CD, 0x6CB8, 0x95A6, 0x6CB9, 0x96FB, 0x6CBA, 0x9F9F, 0x6CBB, 0x8EA1, 0x6CBC, 0x8FC0, 0x6CBD, 0x9F98, 0x6CBE, 0x9F9E, 0x6CBF, 0x8988, 0x6CC1, 0x8BB5, 0x6CC4, 0x9F95, 0x6CC5, 0x9F9A, 0x6CC9, 0x90F2, 0x6CCA, 0x9491, 0x6CCC, 0x94E5, 0x6CD3, 0x9F97, 0x6CD5, 0x9640, 0x6CD7, 0x9F99, 0x6CD9, 0x9FA2, 0x6CDA, 0xFAF9, 0x6CDB, 0x9FA0, 0x6CDD, 0x9F9B, 0x6CE1, 0x9641, 0x6CE2, 0x9467, 0x6CE3, 0x8B83, 0x6CE5, 0x9344, 0x6CE8, 0x928D, 0x6CEA, 0x9FA3, 0x6CEF, 0x9FA1, 0x6CF0, 0x91D7, 0x6CF1, 0x9F96, 0x6CF3, 0x896A, 0x6D04, 0xFAFA, 0x6D0B, 0x976D, 0x6D0C, 0x9FAE, 0x6D12, 0x9FAD, 0x6D17, 0x90F4, 0x6D19, 0x9FAA, 0x6D1B, 0x978C, 0x6D1E, 0x93B4, 0x6D1F, 0x9FA4, 0x6D25, 0x92C3, 0x6D29, 0x896B, 0x6D2A, 0x8D5E, 0x6D2B, 0x9FA7, 0x6D32, 0x8F46, 0x6D33, 0x9FAC, 0x6D35, 0x9FAB, 0x6D36, 0x9FA6, 0x6D38, 0x9FA9, 0x6D3B, 0x8A88, 0x6D3D, 0x9FA8, 0x6D3E, 0x9468, 0x6D41, 0x97AC, 0x6D44, 0x8FF2, 0x6D45, 0x90F3, 0x6D59, 0x9FB4, 0x6D5A, 0x9FB2, 0x6D5C, 0x956C, 0x6D63, 0x9FAF, 0x6D64, 0x9FB1, 0x6D66, 0x8959, 0x6D69, 0x8D5F, 0x6D6A, 0x9851, 0x6D6C, 0x8A5C, 0x6D6E, 0x9582, 0x6D6F, 0xFAFC, 0x6D74, 0x9781, 0x6D77, 0x8A43, 0x6D78, 0x905A, 0x6D79, 0x9FB3, 0x6D85, 0x9FB8, 0x6D87, 0xFAFB, 0x6D88, 0x8FC1, 0x6D8C, 0x974F, 0x6D8E, 0x9FB5, 0x6D93, 0x9FB0, 0x6D95, 0x9FB6, 0x6D96, 0xFB40, 0x6D99, 0x97DC, 0x6D9B, 0x9393, 0x6D9C, 0x93C0, 0x6DAC, 0xFB41, 0x6DAF, 0x8A55, 0x6DB2, 0x8974, 0x6DB5, 0x9FBC, 0x6DB8, 0x9FBF, 0x6DBC, 0x97C1, 0x6DC0, 0x9784, 0x6DC5, 0x9FC6, 0x6DC6, 0x9FC0, 0x6DC7, 0x9FBD, 0x6DCB, 0x97D2, 0x6DCC, 0x9FC3, 0x6DCF, 0xFB42, 0x6DD1, 0x8F69, 0x6DD2, 0x9FC5, 0x6DD5, 0x9FCA, 0x6DD8, 0x9391, 0x6DD9, 0x9FC8, 0x6DDE, 0x9FC2, 0x6DE1, 0x9257, 0x6DE4, 0x9FC9, 0x6DE6, 0x9FBE, 0x6DE8, 0x9FC4, 0x6DEA, 0x9FCB, 0x6DEB, 0x88FA, 0x6DEC, 0x9FC1, 0x6DEE, 0x9FCC, 0x6DF1, 0x905B, 0x6DF2, 0xFB44, 0x6DF3, 0x8F7E, 0x6DF5, 0x95A3, 0x6DF7, 0x8DAC, 0x6DF8, 0xFB43, 0x6DF9, 0x9FB9, 0x6DFA, 0x9FC7, 0x6DFB, 0x9359, 0x6DFC, 0xFB45, 0x6E05, 0x90B4, 0x6E07, 0x8A89, 0x6E08, 0x8DCF, 0x6E09, 0x8FC2, 0x6E0A, 0x9FBB, 0x6E0B, 0x8F61, 0x6E13, 0x8C6B, 0x6E15, 0x9FBA, 0x6E19, 0x9FD0, 0x6E1A, 0x8F8D, 0x6E1B, 0x8CB8, 0x6E1D, 0x9FDF, 0x6E1F, 0x9FD9, 0x6E20, 0x8B94, 0x6E21, 0x936E, 0x6E23, 0x9FD4, 0x6E24, 0x9FDD, 0x6E25, 0x88AD, 0x6E26, 0x8951, 0x6E27, 0xFB48, 0x6E29, 0x89B7, 0x6E2B, 0x9FD6, 0x6E2C, 0x91AA, 0x6E2D, 0x9FCD, 0x6E2E, 0x9FCF, 0x6E2F, 0x8D60, 0x6E38, 0x9FE0, 0x6E39, 0xFB46, 0x6E3A, 0x9FDB, 0x6E3C, 0xFB49, 0x6E3E, 0x9FD3, 0x6E43, 0x9FDA, 0x6E4A, 0x96A9, 0x6E4D, 0x9FD8, 0x6E4E, 0x9FDC, 0x6E56, 0x8CCE, 0x6E58, 0x8FC3, 0x6E5B, 0x9258, 0x6E5C, 0xFB47, 0x6E5F, 0x9FD2, 0x6E67, 0x974E, 0x6E6B, 0x9FD5, 0x6E6E, 0x9FCE, 0x6E6F, 0x9392, 0x6E72, 0x9FD1, 0x6E76, 0x9FD7, 0x6E7E, 0x9870, 0x6E7F, 0x8EBC, 0x6E80, 0x969E, 0x6E82, 0x9FE1, 0x6E8C, 0x94AC, 0x6E8F, 0x9FED, 0x6E90, 0x8CB9, 0x6E96, 0x8F80, 0x6E98, 0x9FE3, 0x6E9C, 0x97AD, 0x6E9D, 0x8D61, 0x6E9F, 0x9FF0, 0x6EA2, 0x88EC, 0x6EA5, 0x9FEE, 0x6EAA, 0x9FE2, 0x6EAF, 0x9FE8, 0x6EB2, 0x9FEA, 0x6EB6, 0x976E, 0x6EB7, 0x9FE5, 0x6EBA, 0x934D, 0x6EBD, 0x9FE7, 0x6EBF, 0xFB4A, 0x6EC2, 0x9FEF, 0x6EC4, 0x9FE9, 0x6EC5, 0x96C5, 0x6EC9, 0x9FE4, 0x6ECB, 0x8EA0, 0x6ECC, 0x9FFC, 0x6ED1, 0x8A8A, 0x6ED3, 0x9FE6, 0x6ED4, 0x9FEB, 0x6ED5, 0x9FEC, 0x6EDD, 0x91EA, 0x6EDE, 0x91D8, 0x6EEC, 0x9FF4, 0x6EEF, 0x9FFA, 0x6EF2, 0x9FF8, 0x6EF4, 0x9348, 0x6EF7, 0xE042, 0x6EF8, 0x9FF5, 0x6EFE, 0x9FF6, 0x6EFF, 0x9FDE, 0x6F01, 0x8B99, 0x6F02, 0x9559, 0x6F06, 0x8EBD, 0x6F09, 0x8D97, 0x6F0F, 0x9852, 0x6F11, 0x9FF2, 0x6F13, 0xE041, 0x6F14, 0x8989, 0x6F15, 0x9186, 0x6F20, 0x9499, 0x6F22, 0x8ABF, 0x6F23, 0x97F8, 0x6F2B, 0x969F, 0x6F2C, 0x92D0, 0x6F31, 0x9FF9, 0x6F32, 0x9FFB, 0x6F38, 0x9151, 0x6F3E, 0xE040, 0x6F3F, 0x9FF7, 0x6F41, 0x9FF1, 0x6F45, 0x8AC1, 0x6F54, 0x8C89, 0x6F58, 0xE04E, 0x6F5B, 0xE049, 0x6F5C, 0x90F6, 0x6F5F, 0x8A83, 0x6F64, 0x8F81, 0x6F66, 0xE052, 0x6F6D, 0xE04B, 0x6F6E, 0x92AA, 0x6F6F, 0xE048, 0x6F70, 0x92D7, 0x6F74, 0xE06B, 0x6F78, 0xE045, 0x6F7A, 0xE044, 0x6F7C, 0xE04D, 0x6F80, 0xE047, 0x6F81, 0xE046, 0x6F82, 0xE04C, 0x6F84, 0x909F, 0x6F86, 0xE043, 0x6F88, 0xFB4B, 0x6F8E, 0xE04F, 0x6F91, 0xE050, 0x6F97, 0x8AC0, 0x6FA1, 0xE055, 0x6FA3, 0xE054, 0x6FA4, 0xE056, 0x6FAA, 0xE059, 0x6FB1, 0x9362, 0x6FB3, 0xE053, 0x6FB5, 0xFB4C, 0x6FB9, 0xE057, 0x6FC0, 0x8C83, 0x6FC1, 0x91F7, 0x6FC2, 0xE051, 0x6FC3, 0x945A, 0x6FC6, 0xE058, 0x6FD4, 0xE05D, 0x6FD5, 0xE05B, 0x6FD8, 0xE05E, 0x6FDB, 0xE061, 0x6FDF, 0xE05A, 0x6FE0, 0x8D8A, 0x6FE1, 0x9447, 0x6FE4, 0x9FB7, 0x6FEB, 0x9794, 0x6FEC, 0xE05C, 0x6FEE, 0xE060, 0x6FEF, 0x91F3, 0x6FF1, 0xE05F, 0x6FF3, 0xE04A, 0x6FF5, 0xFB4D, 0x6FF6, 0xE889, 0x6FFA, 0xE064, 0x6FFE, 0xE068, 0x7001, 0xE066, 0x7005, 0xFB4E, 0x7007, 0xFB4F, 0x7009, 0xE062, 0x700B, 0xE063, 0x700F, 0xE067, 0x7011, 0xE065, 0x7015, 0x956D, 0x7018, 0xE06D, 0x701A, 0xE06A, 0x701B, 0xE069, 0x701D, 0xE06C, 0x701E, 0x93D2, 0x701F, 0xE06E, 0x7026, 0x9295, 0x7027, 0x91EB, 0x7028, 0xFB50, 0x702C, 0x90A3, 0x7030, 0xE06F, 0x7032, 0xE071, 0x703E, 0xE070, 0x704C, 0x9FF3, 0x7051, 0xE072, 0x7058, 0x93E5, 0x7063, 0xE073, 0x706B, 0x89CE, 0x706F, 0x9394, 0x7070, 0x8A44, 0x7078, 0x8B84, 0x707C, 0x8EDC, 0x707D, 0x8DD0, 0x7085, 0xFB51, 0x7089, 0x9846, 0x708A, 0x9086, 0x708E, 0x898A, 0x7092, 0xE075, 0x7099, 0xE074, 0x70AB, 0xFB52, 0x70AC, 0xE078, 0x70AD, 0x9259, 0x70AE, 0xE07B, 0x70AF, 0xE076, 0x70B3, 0xE07A, 0x70B8, 0xE079, 0x70B9, 0x935F, 0x70BA, 0x88D7, 0x70BB, 0xFA62, 0x70C8, 0x97F3, 0x70CB, 0xE07D, 0x70CF, 0x8947, 0x70D9, 0xE080, 0x70DD, 0xE07E, 0x70DF, 0xE07C, 0x70F1, 0xE077, 0x70F9, 0x9642, 0x70FD, 0xE082, 0x7104, 0xFB54, 0x7109, 0xE081, 0x710F, 0xFB53, 0x7114, 0x898B, 0x7119, 0xE084, 0x711A, 0x95B0, 0x711C, 0xE083, 0x7121, 0x96B3, 0x7126, 0x8FC5, 0x7136, 0x9152, 0x713C, 0x8FC4, 0x7146, 0xFB56, 0x7147, 0xFB57, 0x7149, 0x97F9, 0x714C, 0xE08A, 0x714E, 0x90F7, 0x7155, 0xE086, 0x7156, 0xE08B, 0x7159, 0x898C, 0x715C, 0xFB55, 0x7162, 0xE089, 0x7164, 0x9481, 0x7165, 0xE085, 0x7166, 0xE088, 0x7167, 0x8FC6, 0x7169, 0x94CF, 0x716C, 0xE08C, 0x716E, 0x8ECF, 0x717D, 0x90F8, 0x7184, 0xE08F, 0x7188, 0xE087, 0x718A, 0x8C46, 0x718F, 0xE08D, 0x7194, 0x976F, 0x7195, 0xE090, 0x7199, 0xEAA4, 0x719F, 0x8F6E, 0x71A8, 0xE091, 0x71AC, 0xE092, 0x71B1, 0x944D, 0x71B9, 0xE094, 0x71BE, 0xE095, 0x71C1, 0xFB59, 0x71C3, 0x9452, 0x71C8, 0x9395, 0x71C9, 0xE097, 0x71CE, 0xE099, 0x71D0, 0x97D3, 0x71D2, 0xE096, 0x71D4, 0xE098, 0x71D5, 0x898D, 0x71D7, 0xE093, 0x71DF, 0x9A7A, 0x71E0, 0xE09A, 0x71E5, 0x9187, 0x71E6, 0x8E57, 0x71E7, 0xE09C, 0x71EC, 0xE09B, 0x71ED, 0x9043, 0x71EE, 0x99D7, 0x71F5, 0xE09D, 0x71F9, 0xE09F, 0x71FB, 0xE08E, 0x71FC, 0xE09E, 0x71FE, 0xFB5A, 0x71FF, 0xE0A0, 0x7206, 0x949A, 0x720D, 0xE0A1, 0x7210, 0xE0A2, 0x721B, 0xE0A3, 0x7228, 0xE0A4, 0x722A, 0x92DC, 0x722C, 0xE0A6, 0x722D, 0xE0A5, 0x7230, 0xE0A7, 0x7232, 0xE0A8, 0x7235, 0x8EDD, 0x7236, 0x9583, 0x723A, 0x96EA, 0x723B, 0xE0A9, 0x723C, 0xE0AA, 0x723D, 0x9175, 0x723E, 0x8EA2, 0x723F, 0xE0AB, 0x7240, 0xE0AC, 0x7246, 0xE0AD, 0x7247, 0x95D0, 0x7248, 0x94C5, 0x724B, 0xE0AE, 0x724C, 0x9476, 0x7252, 0x92AB, 0x7258, 0xE0AF, 0x7259, 0x89E5, 0x725B, 0x8B8D, 0x725D, 0x96C4, 0x725F, 0x96B4, 0x7261, 0x89B2, 0x7262, 0x9853, 0x7267, 0x9671, 0x7269, 0x95A8, 0x7272, 0x90B5, 0x7274, 0xE0B0, 0x7279, 0x93C1, 0x727D, 0x8CA1, 0x727E, 0xE0B1, 0x7280, 0x8DD2, 0x7281, 0xE0B3, 0x7282, 0xE0B2, 0x7287, 0xE0B4, 0x7292, 0xE0B5, 0x7296, 0xE0B6, 0x72A0, 0x8B5D, 0x72A2, 0xE0B7, 0x72A7, 0xE0B8, 0x72AC, 0x8CA2, 0x72AF, 0x94C6, 0x72B1, 0xFB5B, 0x72B2, 0xE0BA, 0x72B6, 0x8FF3, 0x72B9, 0xE0B9, 0x72BE, 0xFB5C, 0x72C2, 0x8BB6, 0x72C3, 0xE0BB, 0x72C4, 0xE0BD, 0x72C6, 0xE0BC, 0x72CE, 0xE0BE, 0x72D0, 0x8CCF, 0x72D2, 0xE0BF, 0x72D7, 0x8BE7, 0x72D9, 0x915F, 0x72DB, 0x8D9D, 0x72E0, 0xE0C1, 0x72E1, 0xE0C2, 0x72E2, 0xE0C0, 0x72E9, 0x8EEB, 0x72EC, 0x93C6, 0x72ED, 0x8BB7, 0x72F7, 0xE0C4, 0x72F8, 0x924B, 0x72F9, 0xE0C3, 0x72FC, 0x9854, 0x72FD, 0x9482, 0x730A, 0xE0C7, 0x7316, 0xE0C9, 0x7317, 0xE0C6, 0x731B, 0x96D2, 0x731C, 0xE0C8, 0x731D, 0xE0CA, 0x731F, 0x97C2, 0x7324, 0xFB5D, 0x7325, 0xE0CE, 0x7329, 0xE0CD, 0x732A, 0x9296, 0x732B, 0x944C, 0x732E, 0x8CA3, 0x732F, 0xE0CC, 0x7334, 0xE0CB, 0x7336, 0x9750, 0x7337, 0x9751, 0x733E, 0xE0CF, 0x733F, 0x898E, 0x7344, 0x8D96, 0x7345, 0x8E82, 0x734E, 0xE0D0, 0x734F, 0xE0D1, 0x7357, 0xE0D3, 0x7363, 0x8F62, 0x7368, 0xE0D5, 0x736A, 0xE0D4, 0x7370, 0xE0D6, 0x7372, 0x8A6C, 0x7375, 0xE0D8, 0x7377, 0xFB5F, 0x7378, 0xE0D7, 0x737A, 0xE0DA, 0x737B, 0xE0D9, 0x7384, 0x8CBA, 0x7387, 0x97A6, 0x7389, 0x8BCA, 0x738B, 0x89A4, 0x7396, 0x8BE8, 0x73A9, 0x8ADF, 0x73B2, 0x97E6, 0x73B3, 0xE0DC, 0x73BB, 0xE0DE, 0x73BD, 0xFB60, 0x73C0, 0xE0DF, 0x73C2, 0x89CF, 0x73C8, 0xE0DB, 0x73C9, 0xFB61, 0x73CA, 0x8E58, 0x73CD, 0x92BF, 0x73CE, 0xE0DD, 0x73D2, 0xFB64, 0x73D6, 0xFB62, 0x73DE, 0xE0E2, 0x73E0, 0x8EEC, 0x73E3, 0xFB63, 0x73E5, 0xE0E0, 0x73EA, 0x8C5D, 0x73ED, 0x94C7, 0x73EE, 0xE0E1, 0x73F1, 0xE0FC, 0x73F5, 0xFB66, 0x73F8, 0xE0E7, 0x73FE, 0x8CBB, 0x7403, 0x8B85, 0x7405, 0xE0E4, 0x7406, 0x979D, 0x7407, 0xFB65, 0x7409, 0x97AE, 0x7422, 0x91F4, 0x7425, 0xE0E6, 0x7426, 0xFB67, 0x7429, 0xFB69, 0x742A, 0xFB68, 0x742E, 0xFB6A, 0x7432, 0xE0E8, 0x7433, 0x97D4, 0x7434, 0x8BD5, 0x7435, 0x94FA, 0x7436, 0x9469, 0x743A, 0xE0E9, 0x743F, 0xE0EB, 0x7441, 0xE0EE, 0x7455, 0xE0EA, 0x7459, 0xE0ED, 0x745A, 0x8CE8, 0x745B, 0x896C, 0x745C, 0xE0EF, 0x745E, 0x9090, 0x745F, 0xE0EC, 0x7460, 0x97DA, 0x7462, 0xFB6B, 0x7463, 0xE0F2, 0x7464, 0xEAA2, 0x7469, 0xE0F0, 0x746A, 0xE0F3, 0x746F, 0xE0E5, 0x7470, 0xE0F1, 0x7473, 0x8DBA, 0x7476, 0xE0F4, 0x747E, 0xE0F5, 0x7483, 0x979E, 0x7489, 0xFB6C, 0x748B, 0xE0F6, 0x749E, 0xE0F7, 0x749F, 0xFB6D, 0x74A2, 0xE0E3, 0x74A7, 0xE0F8, 0x74B0, 0x8AC2, 0x74BD, 0x8EA3, 0x74CA, 0xE0F9, 0x74CF, 0xE0FA, 0x74D4, 0xE0FB, 0x74DC, 0x895A, 0x74E0, 0xE140, 0x74E2, 0x955A, 0x74E3, 0xE141, 0x74E6, 0x8AA2, 0x74E7, 0xE142, 0x74E9, 0xE143, 0x74EE, 0xE144, 0x74F0, 0xE146, 0x74F1, 0xE147, 0x74F2, 0xE145, 0x74F6, 0x9572, 0x74F7, 0xE149, 0x74F8, 0xE148, 0x7501, 0xFB6E, 0x7503, 0xE14B, 0x7504, 0xE14A, 0x7505, 0xE14C, 0x750C, 0xE14D, 0x750D, 0xE14F, 0x750E, 0xE14E, 0x7511, 0x8D99, 0x7513, 0xE151, 0x7515, 0xE150, 0x7518, 0x8AC3, 0x751A, 0x9072, 0x751C, 0x935B, 0x751E, 0xE152, 0x751F, 0x90B6, 0x7523, 0x8E59, 0x7525, 0x8999, 0x7526, 0xE153, 0x7528, 0x9770, 0x752B, 0x95E1, 0x752C, 0xE154, 0x752F, 0xFAA8, 0x7530, 0x9363, 0x7531, 0x9752, 0x7532, 0x8D62, 0x7533, 0x905C, 0x7537, 0x926A, 0x7538, 0x99B2, 0x753A, 0x92AC, 0x753B, 0x89E6, 0x753C, 0xE155, 0x7544, 0xE156, 0x7546, 0xE15B, 0x7549, 0xE159, 0x754A, 0xE158, 0x754B, 0x9DC0, 0x754C, 0x8A45, 0x754D, 0xE157, 0x754F, 0x88D8, 0x7551, 0x94A8, 0x7554, 0x94C8, 0x7559, 0x97AF, 0x755A, 0xE15C, 0x755B, 0xE15A, 0x755C, 0x927B, 0x755D, 0x90A4, 0x7560, 0x94A9, 0x7562, 0x954C, 0x7564, 0xE15E, 0x7565, 0x97AA, 0x7566, 0x8C6C, 0x7567, 0xE15F, 0x7569, 0xE15D, 0x756A, 0x94D4, 0x756B, 0xE160, 0x756D, 0xE161, 0x756F, 0xFB6F, 0x7570, 0x88D9, 0x7573, 0x8FF4, 0x7574, 0xE166, 0x7576, 0xE163, 0x7577, 0x93EB, 0x7578, 0xE162, 0x757F, 0x8B45, 0x7582, 0xE169, 0x7586, 0xE164, 0x7587, 0xE165, 0x7589, 0xE168, 0x758A, 0xE167, 0x758B, 0x9544, 0x758E, 0x9161, 0x758F, 0x9160, 0x7591, 0x8B5E, 0x7594, 0xE16A, 0x759A, 0xE16B, 0x759D, 0xE16C, 0x75A3, 0xE16E, 0x75A5, 0xE16D, 0x75AB, 0x8975, 0x75B1, 0xE176, 0x75B2, 0x94E6, 0x75B3, 0xE170, 0x75B5, 0xE172, 0x75B8, 0xE174, 0x75B9, 0x905D, 0x75BC, 0xE175, 0x75BD, 0xE173, 0x75BE, 0x8EBE, 0x75C2, 0xE16F, 0x75C3, 0xE171, 0x75C5, 0x9561, 0x75C7, 0x8FC7, 0x75CA, 0xE178, 0x75CD, 0xE177, 0x75D2, 0xE179, 0x75D4, 0x8EA4, 0x75D5, 0x8DAD, 0x75D8, 0x9397, 0x75D9, 0xE17A, 0x75DB, 0x92C9, 0x75DE, 0xE17C, 0x75E2, 0x979F, 0x75E3, 0xE17B, 0x75E9, 0x9189, 0x75F0, 0xE182, 0x75F2, 0xE184, 0x75F3, 0xE185, 0x75F4, 0x9273, 0x75FA, 0xE183, 0x75FC, 0xE180, 0x75FE, 0xE17D, 0x75FF, 0xE17E, 0x7601, 0xE181, 0x7609, 0xE188, 0x760B, 0xE186, 0x760D, 0xE187, 0x761F, 0xE189, 0x7620, 0xE18B, 0x7621, 0xE18C, 0x7622, 0xE18D, 0x7624, 0xE18E, 0x7627, 0xE18A, 0x7630, 0xE190, 0x7634, 0xE18F, 0x763B, 0xE191, 0x7642, 0x97C3, 0x7646, 0xE194, 0x7647, 0xE192, 0x7648, 0xE193, 0x764C, 0x8AE0, 0x7652, 0x96FC, 0x7656, 0x95C8, 0x7658, 0xE196, 0x765C, 0xE195, 0x7661, 0xE197, 0x7662, 0xE198, 0x7667, 0xE19C, 0x7668, 0xE199, 0x7669, 0xE19A, 0x766A, 0xE19B, 0x766C, 0xE19D, 0x7670, 0xE19E, 0x7672, 0xE19F, 0x7676, 0xE1A0, 0x7678, 0xE1A1, 0x767A, 0x94AD, 0x767B, 0x936F, 0x767C, 0xE1A2, 0x767D, 0x9492, 0x767E, 0x9553, 0x7680, 0xE1A3, 0x7682, 0xFB70, 0x7683, 0xE1A4, 0x7684, 0x9349, 0x7686, 0x8A46, 0x7687, 0x8D63, 0x7688, 0xE1A5, 0x768B, 0xE1A6, 0x768E, 0xE1A7, 0x7690, 0x8E48, 0x7693, 0xE1A9, 0x7696, 0xE1A8, 0x7699, 0xE1AA, 0x769A, 0xE1AB, 0x769B, 0xFB73, 0x769C, 0xFB71, 0x769E, 0xFB72, 0x76A6, 0xFB74, 0x76AE, 0x94E7, 0x76B0, 0xE1AC, 0x76B4, 0xE1AD, 0x76B7, 0xEA89, 0x76B8, 0xE1AE, 0x76B9, 0xE1AF, 0x76BA, 0xE1B0, 0x76BF, 0x8E4D, 0x76C2, 0xE1B1, 0x76C3, 0x9475, 0x76C6, 0x967E, 0x76C8, 0x896D, 0x76CA, 0x8976, 0x76CD, 0xE1B2, 0x76D2, 0xE1B4, 0x76D6, 0xE1B3, 0x76D7, 0x9390, 0x76DB, 0x90B7, 0x76DC, 0x9F58, 0x76DE, 0xE1B5, 0x76DF, 0x96BF, 0x76E1, 0xE1B6, 0x76E3, 0x8AC4, 0x76E4, 0x94D5, 0x76E5, 0xE1B7, 0x76E7, 0xE1B8, 0x76EA, 0xE1B9, 0x76EE, 0x96DA, 0x76F2, 0x96D3, 0x76F4, 0x92BC, 0x76F8, 0x918A, 0x76FB, 0xE1BB, 0x76FE, 0x8F82, 0x7701, 0x8FC8, 0x7704, 0xE1BE, 0x7707, 0xE1BD, 0x7708, 0xE1BC, 0x7709, 0x94FB, 0x770B, 0x8AC5, 0x770C, 0x8CA7, 0x771B, 0xE1C4, 0x771E, 0xE1C1, 0x771F, 0x905E, 0x7720, 0x96B0, 0x7724, 0xE1C0, 0x7725, 0xE1C2, 0x7726, 0xE1C3, 0x7729, 0xE1BF, 0x7737, 0xE1C5, 0x7738, 0xE1C6, 0x773A, 0x92AD, 0x773C, 0x8AE1, 0x7740, 0x9285, 0x7746, 0xFB76, 0x7747, 0xE1C7, 0x775A, 0xE1C8, 0x775B, 0xE1CB, 0x7761, 0x9087, 0x7763, 0x93C2, 0x7765, 0xE1CC, 0x7766, 0x9672, 0x7768, 0xE1C9, 0x776B, 0xE1CA, 0x7779, 0xE1CF, 0x777E, 0xE1CE, 0x777F, 0xE1CD, 0x778B, 0xE1D1, 0x778E, 0xE1D0, 0x7791, 0xE1D2, 0x779E, 0xE1D4, 0x77A0, 0xE1D3, 0x77A5, 0x95CB, 0x77AC, 0x8F75, 0x77AD, 0x97C4, 0x77B0, 0xE1D5, 0x77B3, 0x93B5, 0x77B6, 0xE1D6, 0x77B9, 0xE1D7, 0x77BB, 0xE1DB, 0x77BC, 0xE1D9, 0x77BD, 0xE1DA, 0x77BF, 0xE1D8, 0x77C7, 0xE1DC, 0x77CD, 0xE1DD, 0x77D7, 0xE1DE, 0x77DA, 0xE1DF, 0x77DB, 0x96B5, 0x77DC, 0xE1E0, 0x77E2, 0x96EE, 0x77E3, 0xE1E1, 0x77E5, 0x926D, 0x77E7, 0x948A, 0x77E9, 0x8BE9, 0x77ED, 0x925A, 0x77EE, 0xE1E2, 0x77EF, 0x8BB8, 0x77F3, 0x90CE, 0x77FC, 0xE1E3, 0x7802, 0x8DBB, 0x780C, 0xE1E4, 0x7812, 0xE1E5, 0x7814, 0x8CA4, 0x7815, 0x8DD3, 0x7820, 0xE1E7, 0x7821, 0xFB78, 0x7825, 0x9375, 0x7826, 0x8DD4, 0x7827, 0x8B6D, 0x7832, 0x9643, 0x7834, 0x946A, 0x783A, 0x9376, 0x783F, 0x8D7B, 0x7845, 0xE1E9, 0x784E, 0xFB79, 0x785D, 0x8FC9, 0x7864, 0xFB7A, 0x786B, 0x97B0, 0x786C, 0x8D64, 0x786F, 0x8CA5, 0x7872, 0x94A1, 0x7874, 0xE1EB, 0x787A, 0xFB7B, 0x787C, 0xE1ED, 0x7881, 0x8CE9, 0x7886, 0xE1EC, 0x7887, 0x92F4, 0x788C, 0xE1EF, 0x788D, 0x8A56, 0x788E, 0xE1EA, 0x7891, 0x94E8, 0x7893, 0x894F, 0x7895, 0x8DEA, 0x7897, 0x9871, 0x789A, 0xE1EE, 0x78A3, 0xE1F0, 0x78A7, 0x95C9, 0x78A9, 0x90D7, 0x78AA, 0xE1F2, 0x78AF, 0xE1F3, 0x78B5, 0xE1F1, 0x78BA, 0x8A6D, 0x78BC, 0xE1F9, 0x78BE, 0xE1F8, 0x78C1, 0x8EA5, 0x78C5, 0xE1FA, 0x78C6, 0xE1F5, 0x78CA, 0xE1FB, 0x78CB, 0xE1F6, 0x78D0, 0x94D6, 0x78D1, 0xE1F4, 0x78D4, 0xE1F7, 0x78DA, 0xE241, 0x78E7, 0xE240, 0x78E8, 0x9681, 0x78EC, 0xE1FC, 0x78EF, 0x88E9, 0x78F4, 0xE243, 0x78FD, 0xE242, 0x7901, 0x8FCA, 0x7907, 0xE244, 0x790E, 0x9162, 0x7911, 0xE246, 0x7912, 0xE245, 0x7919, 0xE247, 0x7926, 0xE1E6, 0x792A, 0xE1E8, 0x792B, 0xE249, 0x792C, 0xE248, 0x7930, 0xFB7C, 0x793A, 0x8EA6, 0x793C, 0x97E7, 0x793E, 0x8ED0, 0x7940, 0xE24A, 0x7941, 0x8C56, 0x7947, 0x8B5F, 0x7948, 0x8B46, 0x7949, 0x8E83, 0x7950, 0x9753, 0x7953, 0xE250, 0x7955, 0xE24F, 0x7956, 0x9163, 0x7957, 0xE24C, 0x795A, 0xE24E, 0x795D, 0x8F6A, 0x795E, 0x905F, 0x795F, 0xE24D, 0x7960, 0xE24B, 0x7962, 0x9449, 0x7965, 0x8FCB, 0x7968, 0x955B, 0x796D, 0x8DD5, 0x7977, 0x9398, 0x797A, 0xE251, 0x797F, 0xE252, 0x7980, 0xE268, 0x7981, 0x8BD6, 0x7984, 0x985C, 0x7985, 0x9154, 0x798A, 0xE253, 0x798D, 0x89D0, 0x798E, 0x92F5, 0x798F, 0x959F, 0x7994, 0xFB81, 0x799B, 0xFB83, 0x799D, 0xE254, 0x79A6, 0x8B9A, 0x79A7, 0xE255, 0x79AA, 0xE257, 0x79AE, 0xE258, 0x79B0, 0x9448, 0x79B3, 0xE259, 0x79B9, 0xE25A, 0x79BA, 0xE25B, 0x79BD, 0x8BD7, 0x79BE, 0x89D1, 0x79BF, 0x93C3, 0x79C0, 0x8F47, 0x79C1, 0x8E84, 0x79C9, 0xE25C, 0x79CB, 0x8F48, 0x79D1, 0x89C8, 0x79D2, 0x9562, 0x79D5, 0xE25D, 0x79D8, 0x94E9, 0x79DF, 0x9164, 0x79E1, 0xE260, 0x79E3, 0xE261, 0x79E4, 0x9489, 0x79E6, 0x9060, 0x79E7, 0xE25E, 0x79E9, 0x9281, 0x79EC, 0xE25F, 0x79F0, 0x8FCC, 0x79FB, 0x88DA, 0x7A00, 0x8B48, 0x7A08, 0xE262, 0x7A0B, 0x92F6, 0x7A0D, 0xE263, 0x7A0E, 0x90C5, 0x7A14, 0x96AB, 0x7A17, 0x9542, 0x7A18, 0xE264, 0x7A19, 0xE265, 0x7A1A, 0x9274, 0x7A1C, 0x97C5, 0x7A1F, 0xE267, 0x7A20, 0xE266, 0x7A2E, 0x8EED, 0x7A31, 0xE269, 0x7A32, 0x88EE, 0x7A37, 0xE26C, 0x7A3B, 0xE26A, 0x7A3C, 0x89D2, 0x7A3D, 0x8C6D, 0x7A3E, 0xE26B, 0x7A3F, 0x8D65, 0x7A40, 0x8D92, 0x7A42, 0x95E4, 0x7A43, 0xE26D, 0x7A46, 0x9673, 0x7A49, 0xE26F, 0x7A4D, 0x90CF, 0x7A4E, 0x896E, 0x7A4F, 0x89B8, 0x7A50, 0x88AA, 0x7A57, 0xE26E, 0x7A61, 0xE270, 0x7A62, 0xE271, 0x7A63, 0x8FF5, 0x7A69, 0xE272, 0x7A6B, 0x8A6E, 0x7A70, 0xE274, 0x7A74, 0x8C8A, 0x7A76, 0x8B86, 0x7A79, 0xE275, 0x7A7A, 0x8BF3, 0x7A7D, 0xE276, 0x7A7F, 0x90FA, 0x7A81, 0x93CB, 0x7A83, 0x90DE, 0x7A84, 0x8DF3, 0x7A88, 0xE277, 0x7A92, 0x9282, 0x7A93, 0x918B, 0x7A95, 0xE279, 0x7A96, 0xE27B, 0x7A97, 0xE278, 0x7A98, 0xE27A, 0x7A9F, 0x8C41, 0x7AA9, 0xE27C, 0x7AAA, 0x8C45, 0x7AAE, 0x8B87, 0x7AAF, 0x9771, 0x7AB0, 0xE27E, 0x7AB6, 0xE280, 0x7ABA, 0x894D, 0x7ABF, 0xE283, 0x7AC3, 0x8A96, 0x7AC4, 0xE282, 0x7AC5, 0xE281, 0x7AC7, 0xE285, 0x7AC8, 0xE27D, 0x7ACA, 0xE286, 0x7ACB, 0x97A7, 0x7ACD, 0xE287, 0x7ACF, 0xE288, 0x7AD1, 0xFB84, 0x7AD2, 0x9AF2, 0x7AD3, 0xE28A, 0x7AD5, 0xE289, 0x7AD9, 0xE28B, 0x7ADA, 0xE28C, 0x7ADC, 0x97B3, 0x7ADD, 0xE28D, 0x7ADF, 0xE8ED, 0x7AE0, 0x8FCD, 0x7AE1, 0xE28E, 0x7AE2, 0xE28F, 0x7AE3, 0x8F76, 0x7AE5, 0x93B6, 0x7AE6, 0xE290, 0x7AE7, 0xFB85, 0x7AEA, 0x9247, 0x7AEB, 0xFB87, 0x7AED, 0xE291, 0x7AEF, 0x925B, 0x7AF0, 0xE292, 0x7AF6, 0x8BA3, 0x7AF8, 0x995E, 0x7AF9, 0x927C, 0x7AFA, 0x8EB1, 0x7AFF, 0x8AC6, 0x7B02, 0xE293, 0x7B04, 0xE2A0, 0x7B06, 0xE296, 0x7B08, 0x8B88, 0x7B0A, 0xE295, 0x7B0B, 0xE2A2, 0x7B0F, 0xE294, 0x7B11, 0x8FCE, 0x7B18, 0xE298, 0x7B19, 0xE299, 0x7B1B, 0x934A, 0x7B1E, 0xE29A, 0x7B20, 0x8A7D, 0x7B25, 0x9079, 0x7B26, 0x9584, 0x7B28, 0xE29C, 0x7B2C, 0x91E6, 0x7B33, 0xE297, 0x7B35, 0xE29B, 0x7B36, 0xE29D, 0x7B39, 0x8DF9, 0x7B45, 0xE2A4, 0x7B46, 0x954D, 0x7B48, 0x94A4, 0x7B49, 0x9399, 0x7B4B, 0x8BD8, 0x7B4C, 0xE2A3, 0x7B4D, 0xE2A1, 0x7B4F, 0x94B3, 0x7B50, 0xE29E, 0x7B51, 0x927D, 0x7B52, 0x939B, 0x7B54, 0x939A, 0x7B56, 0x8DF4, 0x7B5D, 0xE2B6, 0x7B65, 0xE2A6, 0x7B67, 0xE2A8, 0x7B6C, 0xE2AB, 0x7B6E, 0xE2AC, 0x7B70, 0xE2A9, 0x7B71, 0xE2AA, 0x7B74, 0xE2A7, 0x7B75, 0xE2A5, 0x7B7A, 0xE29F, 0x7B86, 0x95CD, 0x7B87, 0x89D3, 0x7B8B, 0xE2B3, 0x7B8D, 0xE2B0, 0x7B8F, 0xE2B5, 0x7B92, 0xE2B4, 0x7B94, 0x9493, 0x7B95, 0x96A5, 0x7B97, 0x8E5A, 0x7B98, 0xE2AE, 0x7B99, 0xE2B7, 0x7B9A, 0xE2B2, 0x7B9C, 0xE2B1, 0x7B9D, 0xE2AD, 0x7B9E, 0xFB88, 0x7B9F, 0xE2AF, 0x7BA1, 0x8AC7, 0x7BAA, 0x925C, 0x7BAD, 0x90FB, 0x7BB1, 0x94A0, 0x7BB4, 0xE2BC, 0x7BB8, 0x94A2, 0x7BC0, 0x90DF, 0x7BC1, 0xE2B9, 0x7BC4, 0x94CD, 0x7BC6, 0xE2BD, 0x7BC7, 0x95D1, 0x7BC9, 0x927A, 0x7BCB, 0xE2B8, 0x7BCC, 0xE2BA, 0x7BCF, 0xE2BB, 0x7BDD, 0xE2BE, 0x7BE0, 0x8EC2, 0x7BE4, 0x93C4, 0x7BE5, 0xE2C3, 0x7BE6, 0xE2C2, 0x7BE9, 0xE2BF, 0x7BED, 0x9855, 0x7BF3, 0xE2C8, 0x7BF6, 0xE2CC, 0x7BF7, 0xE2C9, 0x7C00, 0xE2C5, 0x7C07, 0xE2C6, 0x7C0D, 0xE2CB, 0x7C11, 0xE2C0, 0x7C12, 0x99D3, 0x7C13, 0xE2C7, 0x7C14, 0xE2C1, 0x7C17, 0xE2CA, 0x7C1F, 0xE2D0, 0x7C21, 0x8AC8, 0x7C23, 0xE2CD, 0x7C27, 0xE2CE, 0x7C2A, 0xE2CF, 0x7C2B, 0xE2D2, 0x7C37, 0xE2D1, 0x7C38, 0x94F4, 0x7C3D, 0xE2D3, 0x7C3E, 0x97FA, 0x7C3F, 0x95EB, 0x7C40, 0xE2D8, 0x7C43, 0xE2D5, 0x7C4C, 0xE2D4, 0x7C4D, 0x90D0, 0x7C4F, 0xE2D7, 0x7C50, 0xE2D9, 0x7C54, 0xE2D6, 0x7C56, 0xE2DD, 0x7C58, 0xE2DA, 0x7C5F, 0xE2DB, 0x7C60, 0xE2C4, 0x7C64, 0xE2DC, 0x7C65, 0xE2DE, 0x7C6C, 0xE2DF, 0x7C73, 0x95C4, 0x7C75, 0xE2E0, 0x7C7E, 0x96E0, 0x7C81, 0x8BCC, 0x7C82, 0x8C48, 0x7C83, 0xE2E1, 0x7C89, 0x95B2, 0x7C8B, 0x9088, 0x7C8D, 0x96AE, 0x7C90, 0xE2E2, 0x7C92, 0x97B1, 0x7C95, 0x9494, 0x7C97, 0x9165, 0x7C98, 0x9453, 0x7C9B, 0x8F6C, 0x7C9F, 0x88BE, 0x7CA1, 0xE2E7, 0x7CA2, 0xE2E5, 0x7CA4, 0xE2E3, 0x7CA5, 0x8A9F, 0x7CA7, 0x8FCF, 0x7CA8, 0xE2E8, 0x7CAB, 0xE2E6, 0x7CAD, 0xE2E4, 0x7CAE, 0xE2EC, 0x7CB1, 0xE2EB, 0x7CB2, 0xE2EA, 0x7CB3, 0xE2E9, 0x7CB9, 0xE2ED, 0x7CBD, 0xE2EE, 0x7CBE, 0x90B8, 0x7CC0, 0xE2EF, 0x7CC2, 0xE2F1, 0x7CC5, 0xE2F0, 0x7CCA, 0x8CD0, 0x7CCE, 0x9157, 0x7CD2, 0xE2F3, 0x7CD6, 0x939C, 0x7CD8, 0xE2F2, 0x7CDC, 0xE2F4, 0x7CDE, 0x95B3, 0x7CDF, 0x918C, 0x7CE0, 0x8D66, 0x7CE2, 0xE2F5, 0x7CE7, 0x97C6, 0x7CEF, 0xE2F7, 0x7CF2, 0xE2F8, 0x7CF4, 0xE2F9, 0x7CF6, 0xE2FA, 0x7CF8, 0x8E85, 0x7CFA, 0xE2FB, 0x7CFB, 0x8C6E, 0x7CFE, 0x8B8A, 0x7D00, 0x8B49, 0x7D02, 0xE340, 0x7D04, 0x96F1, 0x7D05, 0x8D67, 0x7D06, 0xE2FC, 0x7D0A, 0xE343, 0x7D0B, 0x96E4, 0x7D0D, 0x945B, 0x7D10, 0x9552, 0x7D14, 0x8F83, 0x7D15, 0xE342, 0x7D17, 0x8ED1, 0x7D18, 0x8D68, 0x7D19, 0x8E86, 0x7D1A, 0x8B89, 0x7D1B, 0x95B4, 0x7D1C, 0xE341, 0x7D20, 0x9166, 0x7D21, 0x9661, 0x7D22, 0x8DF5, 0x7D2B, 0x8E87, 0x7D2C, 0x92DB, 0x7D2E, 0xE346, 0x7D2F, 0x97DD, 0x7D30, 0x8DD7, 0x7D32, 0xE347, 0x7D33, 0x9061, 0x7D35, 0xE349, 0x7D39, 0x8FD0, 0x7D3A, 0x8DAE, 0x7D3F, 0xE348, 0x7D42, 0x8F49, 0x7D43, 0x8CBC, 0x7D44, 0x9167, 0x7D45, 0xE344, 0x7D46, 0xE34A, 0x7D48, 0xFB8A, 0x7D4B, 0xE345, 0x7D4C, 0x8C6F, 0x7D4E, 0xE34D, 0x7D4F, 0xE351, 0x7D50, 0x8C8B, 0x7D56, 0xE34C, 0x7D5B, 0xE355, 0x7D5C, 0xFB8B, 0x7D5E, 0x8D69, 0x7D61, 0x978D, 0x7D62, 0x88BA, 0x7D63, 0xE352, 0x7D66, 0x8B8B, 0x7D68, 0xE34F, 0x7D6E, 0xE350, 0x7D71, 0x939D, 0x7D72, 0xE34E, 0x7D73, 0xE34B, 0x7D75, 0x8A47, 0x7D76, 0x90E2, 0x7D79, 0x8CA6, 0x7D7D, 0xE357, 0x7D89, 0xE354, 0x7D8F, 0xE356, 0x7D93, 0xE353, 0x7D99, 0x8C70, 0x7D9A, 0x91B1, 0x7D9B, 0xE358, 0x7D9C, 0x918E, 0x7D9F, 0xE365, 0x7DA0, 0xFB8D, 0x7DA2, 0xE361, 0x7DA3, 0xE35B, 0x7DAB, 0xE35F, 0x7DAC, 0x8EF8, 0x7DAD, 0x88DB, 0x7DAE, 0xE35A, 0x7DAF, 0xE362, 0x7DB0, 0xE366, 0x7DB1, 0x8D6A, 0x7DB2, 0x96D4, 0x7DB4, 0x92D4, 0x7DB5, 0xE35C, 0x7DB7, 0xFB8C, 0x7DB8, 0xE364, 0x7DBA, 0xE359, 0x7DBB, 0x925D, 0x7DBD, 0xE35E, 0x7DBE, 0x88BB, 0x7DBF, 0x96C8, 0x7DC7, 0xE35D, 0x7DCA, 0x8BD9, 0x7DCB, 0x94EA, 0x7DCF, 0x918D, 0x7DD1, 0x97CE, 0x7DD2, 0x8F8F, 0x7DD5, 0xE38E, 0x7DD6, 0xFB8E, 0x7DD8, 0xE367, 0x7DDA, 0x90FC, 0x7DDC, 0xE363, 0x7DDD, 0xE368, 0x7DDE, 0xE36A, 0x7DE0, 0x92F7, 0x7DE1, 0xE36D, 0x7DE4, 0xE369, 0x7DE8, 0x95D2, 0x7DE9, 0x8AC9, 0x7DEC, 0x96C9, 0x7DEF, 0x88DC, 0x7DF2, 0xE36C, 0x7DF4, 0x97FB, 0x7DFB, 0xE36B, 0x7E01, 0x898F, 0x7E04, 0x93EA, 0x7E05, 0xE36E, 0x7E09, 0xE375, 0x7E0A, 0xE36F, 0x7E0B, 0xE376, 0x7E12, 0xE372, 0x7E1B, 0x949B, 0x7E1E, 0x8EC8, 0x7E1F, 0xE374, 0x7E21, 0xE371, 0x7E22, 0xE377, 0x7E23, 0xE370, 0x7E26, 0x8F63, 0x7E2B, 0x9644, 0x7E2E, 0x8F6B, 0x7E31, 0xE373, 0x7E32, 0xE380, 0x7E35, 0xE37B, 0x7E37, 0xE37E, 0x7E39, 0xE37C, 0x7E3A, 0xE381, 0x7E3B, 0xE37A, 0x7E3D, 0xE360, 0x7E3E, 0x90D1, 0x7E41, 0x94C9, 0x7E43, 0xE37D, 0x7E46, 0xE378, 0x7E4A, 0x9140, 0x7E4B, 0x8C71, 0x7E4D, 0x8F4A, 0x7E52, 0xFB8F, 0x7E54, 0x9044, 0x7E55, 0x9155, 0x7E56, 0xE384, 0x7E59, 0xE386, 0x7E5A, 0xE387, 0x7E5D, 0xE383, 0x7E5E, 0xE385, 0x7E66, 0xE379, 0x7E67, 0xE382, 0x7E69, 0xE38A, 0x7E6A, 0xE389, 0x7E6D, 0x969A, 0x7E70, 0x8C4A, 0x7E79, 0xE388, 0x7E7B, 0xE38C, 0x7E7C, 0xE38B, 0x7E7D, 0xE38F, 0x7E7F, 0xE391, 0x7E82, 0x8E5B, 0x7E83, 0xE38D, 0x7E88, 0xE392, 0x7E89, 0xE393, 0x7E8A, 0xFA5C, 0x7E8C, 0xE394, 0x7E8E, 0xE39A, 0x7E8F, 0x935A, 0x7E90, 0xE396, 0x7E92, 0xE395, 0x7E93, 0xE397, 0x7E94, 0xE398, 0x7E96, 0xE399, 0x7E9B, 0xE39B, 0x7E9C, 0xE39C, 0x7F36, 0x8ACA, 0x7F38, 0xE39D, 0x7F3A, 0xE39E, 0x7F45, 0xE39F, 0x7F47, 0xFB90, 0x7F4C, 0xE3A0, 0x7F4D, 0xE3A1, 0x7F4E, 0xE3A2, 0x7F50, 0xE3A3, 0x7F51, 0xE3A4, 0x7F54, 0xE3A6, 0x7F55, 0xE3A5, 0x7F58, 0xE3A7, 0x7F5F, 0xE3A8, 0x7F60, 0xE3A9, 0x7F67, 0xE3AC, 0x7F68, 0xE3AA, 0x7F69, 0xE3AB, 0x7F6A, 0x8DDF, 0x7F6B, 0x8C72, 0x7F6E, 0x9275, 0x7F70, 0x94B1, 0x7F72, 0x8F90, 0x7F75, 0x946C, 0x7F77, 0x94EB, 0x7F78, 0xE3AD, 0x7F79, 0x9CEB, 0x7F82, 0xE3AE, 0x7F83, 0xE3B0, 0x7F85, 0x9785, 0x7F86, 0xE3AF, 0x7F87, 0xE3B2, 0x7F88, 0xE3B1, 0x7F8A, 0x9772, 0x7F8C, 0xE3B3, 0x7F8E, 0x94FC, 0x7F94, 0xE3B4, 0x7F9A, 0xE3B7, 0x7F9D, 0xE3B6, 0x7F9E, 0xE3B5, 0x7FA1, 0xFB91, 0x7FA3, 0xE3B8, 0x7FA4, 0x8C51, 0x7FA8, 0x9141, 0x7FA9, 0x8B60, 0x7FAE, 0xE3BC, 0x7FAF, 0xE3B9, 0x7FB2, 0xE3BA, 0x7FB6, 0xE3BD, 0x7FB8, 0xE3BE, 0x7FB9, 0xE3BB, 0x7FBD, 0x8948, 0x7FC1, 0x89A5, 0x7FC5, 0xE3C0, 0x7FC6, 0xE3C1, 0x7FCA, 0xE3C2, 0x7FCC, 0x9782, 0x7FD2, 0x8F4B, 0x7FD4, 0xE3C4, 0x7FD5, 0xE3C3, 0x7FE0, 0x9089, 0x7FE1, 0xE3C5, 0x7FE6, 0xE3C6, 0x7FE9, 0xE3C7, 0x7FEB, 0x8AE3, 0x7FF0, 0x8ACB, 0x7FF3, 0xE3C8, 0x7FF9, 0xE3C9, 0x7FFB, 0x967C, 0x7FFC, 0x9783, 0x8000, 0x9773, 0x8001, 0x9856, 0x8003, 0x8D6C, 0x8004, 0xE3CC, 0x8005, 0x8ED2, 0x8006, 0xE3CB, 0x800B, 0xE3CD, 0x800C, 0x8EA7, 0x8010, 0x91CF, 0x8012, 0xE3CE, 0x8015, 0x8D6B, 0x8017, 0x96D5, 0x8018, 0xE3CF, 0x8019, 0xE3D0, 0x801C, 0xE3D1, 0x8021, 0xE3D2, 0x8028, 0xE3D3, 0x8033, 0x8EA8, 0x8036, 0x96EB, 0x803B, 0xE3D5, 0x803D, 0x925E, 0x803F, 0xE3D4, 0x8046, 0xE3D7, 0x804A, 0xE3D6, 0x8052, 0xE3D8, 0x8056, 0x90B9, 0x8058, 0xE3D9, 0x805A, 0xE3DA, 0x805E, 0x95B7, 0x805F, 0xE3DB, 0x8061, 0x918F, 0x8062, 0xE3DC, 0x8068, 0xE3DD, 0x806F, 0x97FC, 0x8070, 0xE3E0, 0x8072, 0xE3DF, 0x8073, 0xE3DE, 0x8074, 0x92AE, 0x8076, 0xE3E1, 0x8077, 0x9045, 0x8079, 0xE3E2, 0x807D, 0xE3E3, 0x807E, 0x9857, 0x807F, 0xE3E4, 0x8084, 0xE3E5, 0x8085, 0xE3E7, 0x8086, 0xE3E6, 0x8087, 0x94A3, 0x8089, 0x93F7, 0x808B, 0x985D, 0x808C, 0x94A7, 0x8093, 0xE3E9, 0x8096, 0x8FD1, 0x8098, 0x9549, 0x809A, 0xE3EA, 0x809B, 0xE3E8, 0x809D, 0x8ACC, 0x80A1, 0x8CD2, 0x80A2, 0x8E88, 0x80A5, 0x94EC, 0x80A9, 0x8CA8, 0x80AA, 0x9662, 0x80AC, 0xE3ED, 0x80AD, 0xE3EB, 0x80AF, 0x8D6D, 0x80B1, 0x8D6E, 0x80B2, 0x88E7, 0x80B4, 0x8DE6, 0x80BA, 0x9478, 0x80C3, 0x88DD, 0x80C4, 0xE3F2, 0x80C6, 0x925F, 0x80CC, 0x9477, 0x80CE, 0x91D9, 0x80D6, 0xE3F4, 0x80D9, 0xE3F0, 0x80DA, 0xE3F3, 0x80DB, 0xE3EE, 0x80DD, 0xE3F1, 0x80DE, 0x9645, 0x80E1, 0x8CD3, 0x80E4, 0x88FB, 0x80E5, 0xE3EF, 0x80EF, 0xE3F6, 0x80F1, 0xE3F7, 0x80F4, 0x93B7, 0x80F8, 0x8BB9, 0x80FC, 0xE445, 0x80FD, 0x945C, 0x8102, 0x8E89, 0x8105, 0x8BBA, 0x8106, 0x90C6, 0x8107, 0x9865, 0x8108, 0x96AC, 0x8109, 0xE3F5, 0x810A, 0x90D2, 0x811A, 0x8B72, 0x811B, 0xE3F8, 0x8123, 0xE3FA, 0x8129, 0xE3F9, 0x812F, 0xE3FB, 0x8131, 0x9245, 0x8133, 0x945D, 0x8139, 0x92AF, 0x813E, 0xE442, 0x8146, 0xE441, 0x814B, 0xE3FC, 0x814E, 0x9074, 0x8150, 0x9585, 0x8151, 0xE444, 0x8153, 0xE443, 0x8154, 0x8D6F, 0x8155, 0x9872, 0x815F, 0xE454, 0x8165, 0xE448, 0x8166, 0xE449, 0x816B, 0x8EEE, 0x816E, 0xE447, 0x8170, 0x8D98, 0x8171, 0xE446, 0x8174, 0xE44A, 0x8178, 0x92B0, 0x8179, 0x95A0, 0x817A, 0x9142, 0x817F, 0x91DA, 0x8180, 0xE44E, 0x8182, 0xE44F, 0x8183, 0xE44B, 0x8188, 0xE44C, 0x818A, 0xE44D, 0x818F, 0x8D70, 0x8193, 0xE455, 0x8195, 0xE451, 0x819A, 0x9586, 0x819C, 0x968C, 0x819D, 0x9547, 0x81A0, 0xE450, 0x81A3, 0xE453, 0x81A4, 0xE452, 0x81A8, 0x9663, 0x81A9, 0xE456, 0x81B0, 0xE457, 0x81B3, 0x9156, 0x81B5, 0xE458, 0x81B8, 0xE45A, 0x81BA, 0xE45E, 0x81BD, 0xE45B, 0x81BE, 0xE459, 0x81BF, 0x945E, 0x81C0, 0xE45C, 0x81C2, 0xE45D, 0x81C6, 0x89B0, 0x81C8, 0xE464, 0x81C9, 0xE45F, 0x81CD, 0xE460, 0x81D1, 0xE461, 0x81D3, 0x919F, 0x81D8, 0xE463, 0x81D9, 0xE462, 0x81DA, 0xE465, 0x81DF, 0xE466, 0x81E0, 0xE467, 0x81E3, 0x9062, 0x81E5, 0x89E7, 0x81E7, 0xE468, 0x81E8, 0x97D5, 0x81EA, 0x8EA9, 0x81ED, 0x8F4C, 0x81F3, 0x8E8A, 0x81F4, 0x9276, 0x81FA, 0xE469, 0x81FB, 0xE46A, 0x81FC, 0x8950, 0x81FE, 0xE46B, 0x8201, 0xE46C, 0x8202, 0xE46D, 0x8205, 0xE46E, 0x8207, 0xE46F, 0x8208, 0x8BBB, 0x8209, 0x9DA8, 0x820A, 0xE470, 0x820C, 0x90E3, 0x820D, 0xE471, 0x820E, 0x8EC9, 0x8210, 0xE472, 0x8212, 0x98AE, 0x8216, 0xE473, 0x8217, 0x95DC, 0x8218, 0x8ADA, 0x821B, 0x9143, 0x821C, 0x8F77, 0x821E, 0x9591, 0x821F, 0x8F4D, 0x8229, 0xE474, 0x822A, 0x8D71, 0x822B, 0xE475, 0x822C, 0x94CA, 0x822E, 0xE484, 0x8233, 0xE477, 0x8235, 0x91C7, 0x8236, 0x9495, 0x8237, 0x8CBD, 0x8238, 0xE476, 0x8239, 0x9144, 0x8240, 0xE478, 0x8247, 0x92F8, 0x8258, 0xE47A, 0x8259, 0xE479, 0x825A, 0xE47C, 0x825D, 0xE47B, 0x825F, 0xE47D, 0x8262, 0xE480, 0x8264, 0xE47E, 0x8266, 0x8ACD, 0x8268, 0xE481, 0x826A, 0xE482, 0x826B, 0xE483, 0x826E, 0x8DAF, 0x826F, 0x97C7, 0x8271, 0xE485, 0x8272, 0x9046, 0x8276, 0x8990, 0x8277, 0xE486, 0x8278, 0xE487, 0x827E, 0xE488, 0x828B, 0x88F0, 0x828D, 0xE489, 0x8292, 0xE48A, 0x8299, 0x9587, 0x829D, 0x8EC5, 0x829F, 0xE48C, 0x82A5, 0x8A48, 0x82A6, 0x88B0, 0x82AB, 0xE48B, 0x82AC, 0xE48E, 0x82AD, 0x946D, 0x82AF, 0x9063, 0x82B1, 0x89D4, 0x82B3, 0x9646, 0x82B8, 0x8C7C, 0x82B9, 0x8BDA, 0x82BB, 0xE48D, 0x82BD, 0x89E8, 0x82C5, 0x8AA1, 0x82D1, 0x8991, 0x82D2, 0xE492, 0x82D3, 0x97E8, 0x82D4, 0x91DB, 0x82D7, 0x9563, 0x82D9, 0xE49E, 0x82DB, 0x89D5, 0x82DC, 0xE49C, 0x82DE, 0xE49A, 0x82DF, 0xE491, 0x82E1, 0xE48F, 0x82E3, 0xE490, 0x82E5, 0x8EE1, 0x82E6, 0x8BEA, 0x82E7, 0x9297, 0x82EB, 0x93CF, 0x82F1, 0x8970, 0x82F3, 0xE494, 0x82F4, 0xE493, 0x82F9, 0xE499, 0x82FA, 0xE495, 0x82FB, 0xE498, 0x8301, 0xFB93, 0x8302, 0x96CE, 0x8303, 0xE497, 0x8304, 0x89D6, 0x8305, 0x8A9D, 0x8306, 0xE49B, 0x8309, 0xE49D, 0x830E, 0x8C73, 0x8316, 0xE4A1, 0x8317, 0xE4AA, 0x8318, 0xE4AB, 0x831C, 0x88A9, 0x8323, 0xE4B2, 0x8328, 0x88EF, 0x832B, 0xE4A9, 0x832F, 0xE4A8, 0x8331, 0xE4A3, 0x8332, 0xE4A2, 0x8334, 0xE4A0, 0x8335, 0xE49F, 0x8336, 0x9283, 0x8338, 0x91F9, 0x8339, 0xE4A5, 0x8340, 0xE4A4, 0x8345, 0xE4A7, 0x8349, 0x9190, 0x834A, 0x8C74, 0x834F, 0x8960, 0x8350, 0xE4A6, 0x8352, 0x8D72, 0x8358, 0x9191, 0x8362, 0xFB94, 0x8373, 0xE4B8, 0x8375, 0xE4B9, 0x8377, 0x89D7, 0x837B, 0x89AC, 0x837C, 0xE4B6, 0x837F, 0xFB95, 0x8385, 0xE4AC, 0x8387, 0xE4B4, 0x8389, 0xE4BB, 0x838A, 0xE4B5, 0x838E, 0xE4B3, 0x8393, 0xE496, 0x8396, 0xE4B1, 0x839A, 0xE4AD, 0x839E, 0x8ACE, 0x839F, 0xE4AF, 0x83A0, 0xE4BA, 0x83A2, 0xE4B0, 0x83A8, 0xE4BC, 0x83AA, 0xE4AE, 0x83AB, 0x949C, 0x83B1, 0x9789, 0x83B5, 0xE4B7, 0x83BD, 0xE4CD, 0x83C1, 0xE4C5, 0x83C5, 0x909B, 0x83C7, 0xFB96, 0x83CA, 0x8B65, 0x83CC, 0x8BDB, 0x83CE, 0xE4C0, 0x83D3, 0x89D9, 0x83D6, 0x8FD2, 0x83D8, 0xE4C3, 0x83DC, 0x8DD8, 0x83DF, 0x9370, 0x83E0, 0xE4C8, 0x83E9, 0x95EC, 0x83EB, 0xE4BF, 0x83EF, 0x89D8, 0x83F0, 0x8CD4, 0x83F1, 0x9548, 0x83F2, 0xE4C9, 0x83F4, 0xE4BD, 0x83F6, 0xFB97, 0x83F7, 0xE4C6, 0x83FB, 0xE4D0, 0x83FD, 0xE4C1, 0x8403, 0xE4C2, 0x8404, 0x93B8, 0x8407, 0xE4C7, 0x840B, 0xE4C4, 0x840C, 0x9647, 0x840D, 0xE4CA, 0x840E, 0x88DE, 0x8413, 0xE4BE, 0x8420, 0xE4CC, 0x8422, 0xE4CB, 0x8429, 0x948B, 0x842A, 0xE4D2, 0x842C, 0xE4DD, 0x8431, 0x8A9E, 0x8435, 0xE4E0, 0x8438, 0xE4CE, 0x843C, 0xE4D3, 0x843D, 0x978E, 0x8446, 0xE4DC, 0x8448, 0xFB98, 0x8449, 0x9774, 0x844E, 0x97A8, 0x8457, 0x9298, 0x845B, 0x8A8B, 0x8461, 0x9592, 0x8462, 0xE4E2, 0x8463, 0x939F, 0x8466, 0x88AF, 0x8469, 0xE4DB, 0x846B, 0xE4D7, 0x846C, 0x9192, 0x846D, 0xE4D1, 0x846E, 0xE4D9, 0x846F, 0xE4DE, 0x8471, 0x944B, 0x8475, 0x88A8, 0x8477, 0xE4D6, 0x8479, 0xE4DF, 0x847A, 0x9598, 0x8482, 0xE4DA, 0x8484, 0xE4D5, 0x848B, 0x8FD3, 0x8490, 0x8F4E, 0x8494, 0x8EAA, 0x8499, 0x96D6, 0x849C, 0x9566, 0x849F, 0xE4E5, 0x84A1, 0xE4EE, 0x84AD, 0xE4D8, 0x84B2, 0x8A97, 0x84B4, 0xFB99, 0x84B8, 0x8FF6, 0x84B9, 0xE4E3, 0x84BB, 0xE4E8, 0x84BC, 0x9193, 0x84BF, 0xE4E4, 0x84C1, 0xE4EB, 0x84C4, 0x927E, 0x84C6, 0xE4EC, 0x84C9, 0x9775, 0x84CA, 0xE4E1, 0x84CB, 0x8A57, 0x84CD, 0xE4E7, 0x84D0, 0xE4EA, 0x84D1, 0x96AA, 0x84D6, 0xE4ED, 0x84D9, 0xE4E6, 0x84DA, 0xE4E9, 0x84DC, 0xFA60, 0x84EC, 0x9648, 0x84EE, 0x9840, 0x84F4, 0xE4F1, 0x84FC, 0xE4F8, 0x84FF, 0xE4F0, 0x8500, 0x8EC1, 0x8506, 0xE4CF, 0x8511, 0x95CC, 0x8513, 0x96A0, 0x8514, 0xE4F7, 0x8515, 0xE4F6, 0x8517, 0xE4F2, 0x8518, 0xE4F3, 0x851A, 0x8955, 0x851F, 0xE4F5, 0x8521, 0xE4EF, 0x8526, 0x92D3, 0x852C, 0xE4F4, 0x852D, 0x88FC, 0x8535, 0x91A0, 0x853D, 0x95C1, 0x8540, 0xE4F9, 0x8541, 0xE540, 0x8543, 0x94D7, 0x8548, 0xE4FC, 0x8549, 0x8FD4, 0x854A, 0x8EC7, 0x854B, 0xE542, 0x854E, 0x8BBC, 0x8553, 0xFB9A, 0x8555, 0xE543, 0x8557, 0x9599, 0x8558, 0xE4FB, 0x8559, 0xFB9B, 0x855A, 0xE4D4, 0x8563, 0xE4FA, 0x8568, 0x986E, 0x8569, 0x93A0, 0x856A, 0x9593, 0x856B, 0xFB9C, 0x856D, 0xE54A, 0x8577, 0xE550, 0x857E, 0xE551, 0x8580, 0xE544, 0x8584, 0x9496, 0x8587, 0xE54E, 0x8588, 0xE546, 0x858A, 0xE548, 0x8590, 0xE552, 0x8591, 0xE547, 0x8594, 0xE54B, 0x8597, 0x8992, 0x8599, 0x93E3, 0x859B, 0xE54C, 0x859C, 0xE54F, 0x85A4, 0xE545, 0x85A6, 0x9145, 0x85A8, 0xE549, 0x85A9, 0x8E46, 0x85AA, 0x9064, 0x85AB, 0x8C4F, 0x85AC, 0x96F2, 0x85AE, 0x96F7, 0x85AF, 0x8F92, 0x85B0, 0xFB9E, 0x85B9, 0xE556, 0x85BA, 0xE554, 0x85C1, 0x986D, 0x85C9, 0xE553, 0x85CD, 0x9795, 0x85CF, 0xE555, 0x85D0, 0xE557, 0x85D5, 0xE558, 0x85DC, 0xE55B, 0x85DD, 0xE559, 0x85E4, 0x93A1, 0x85E5, 0xE55A, 0x85E9, 0x94CB, 0x85EA, 0xE54D, 0x85F7, 0x8F93, 0x85F9, 0xE55C, 0x85FA, 0xE561, 0x85FB, 0x9194, 0x85FE, 0xE560, 0x8602, 0xE541, 0x8606, 0xE562, 0x8607, 0x9168, 0x860A, 0xE55D, 0x860B, 0xE55F, 0x8613, 0xE55E, 0x8616, 0x9F50, 0x8617, 0x9F41, 0x861A, 0xE564, 0x8622, 0xE563, 0x862D, 0x9796, 0x862F, 0xE1BA, 0x8630, 0xE565, 0x863F, 0xE566, 0x864D, 0xE567, 0x864E, 0x8CD5, 0x8650, 0x8B73, 0x8654, 0xE569, 0x8655, 0x997C, 0x865A, 0x8B95, 0x865C, 0x97B8, 0x865E, 0x8BF1, 0x865F, 0xE56A, 0x8667, 0xE56B, 0x866B, 0x928E, 0x8671, 0xE56C, 0x8679, 0x93F8, 0x867B, 0x88B8, 0x868A, 0x89E1, 0x868B, 0xE571, 0x868C, 0xE572, 0x8693, 0xE56D, 0x8695, 0x8E5C, 0x86A3, 0xE56E, 0x86A4, 0x9461, 0x86A9, 0xE56F, 0x86AA, 0xE570, 0x86AB, 0xE57A, 0x86AF, 0xE574, 0x86B0, 0xE577, 0x86B6, 0xE573, 0x86C4, 0xE575, 0x86C6, 0xE576, 0x86C7, 0x8ED6, 0x86C9, 0xE578, 0x86CB, 0x9260, 0x86CD, 0x8C75, 0x86CE, 0x8A61, 0x86D4, 0xE57B, 0x86D9, 0x8A5E, 0x86DB, 0xE581, 0x86DE, 0xE57C, 0x86DF, 0xE580, 0x86E4, 0x94B8, 0x86E9, 0xE57D, 0x86EC, 0xE57E, 0x86ED, 0x9567, 0x86EE, 0x94D8, 0x86EF, 0xE582, 0x86F8, 0x91FB, 0x86F9, 0xE58C, 0x86FB, 0xE588, 0x86FE, 0x89E9, 0x8700, 0xE586, 0x8702, 0x9649, 0x8703, 0xE587, 0x8706, 0xE584, 0x8708, 0xE585, 0x8709, 0xE58A, 0x870A, 0xE58D, 0x870D, 0xE58B, 0x8711, 0xE589, 0x8712, 0xE583, 0x8718, 0x9277, 0x871A, 0xE594, 0x871C, 0x96A8, 0x8725, 0xE592, 0x8729, 0xE593, 0x8734, 0xE58E, 0x8737, 0xE590, 0x873B, 0xE591, 0x873F, 0xE58F, 0x8749, 0x90E4, 0x874B, 0x9858, 0x874C, 0xE598, 0x874E, 0xE599, 0x8753, 0xE59F, 0x8755, 0x9049, 0x8757, 0xE59B, 0x8759, 0xE59E, 0x875F, 0xE596, 0x8760, 0xE595, 0x8763, 0xE5A0, 0x8766, 0x89DA, 0x8768, 0xE59C, 0x876A, 0xE5A1, 0x876E, 0xE59D, 0x8774, 0xE59A, 0x8776, 0x92B1, 0x8778, 0xE597, 0x877F, 0x9488, 0x8782, 0xE5A5, 0x878D, 0x975A, 0x879F, 0xE5A4, 0x87A2, 0xE5A3, 0x87AB, 0xE5AC, 0x87AF, 0xE5A6, 0x87B3, 0xE5AE, 0x87BA, 0x9786, 0x87BB, 0xE5B1, 0x87BD, 0xE5A8, 0x87C0, 0xE5A9, 0x87C4, 0xE5AD, 0x87C6, 0xE5B0, 0x87C7, 0xE5AF, 0x87CB, 0xE5A7, 0x87D0, 0xE5AA, 0x87D2, 0xE5BB, 0x87E0, 0xE5B4, 0x87EF, 0xE5B2, 0x87F2, 0xE5B3, 0x87F6, 0xE5B8, 0x87F7, 0xE5B9, 0x87F9, 0x8A49, 0x87FB, 0x8B61, 0x87FE, 0xE5B7, 0x8805, 0xE5A2, 0x8807, 0xFBA1, 0x880D, 0xE5B6, 0x880E, 0xE5BA, 0x880F, 0xE5B5, 0x8811, 0xE5BC, 0x8815, 0xE5BE, 0x8816, 0xE5BD, 0x8821, 0xE5C0, 0x8822, 0xE5BF, 0x8823, 0xE579, 0x8827, 0xE5C4, 0x8831, 0xE5C1, 0x8836, 0xE5C2, 0x8839, 0xE5C3, 0x883B, 0xE5C5, 0x8840, 0x8C8C, 0x8842, 0xE5C7, 0x8844, 0xE5C6, 0x8846, 0x8F4F, 0x884C, 0x8D73, 0x884D, 0x9FA5, 0x8852, 0xE5C8, 0x8853, 0x8F70, 0x8857, 0x8A58, 0x8859, 0xE5C9, 0x885B, 0x8971, 0x885D, 0x8FD5, 0x885E, 0xE5CA, 0x8861, 0x8D74, 0x8862, 0xE5CB, 0x8863, 0x88DF, 0x8868, 0x955C, 0x886B, 0xE5CC, 0x8870, 0x908A, 0x8872, 0xE5D3, 0x8875, 0xE5D0, 0x8877, 0x928F, 0x887D, 0xE5D1, 0x887E, 0xE5CE, 0x887F, 0x8BDC, 0x8881, 0xE5CD, 0x8882, 0xE5D4, 0x8888, 0x8C55, 0x888B, 0x91DC, 0x888D, 0xE5DA, 0x8892, 0xE5D6, 0x8896, 0x91B3, 0x8897, 0xE5D5, 0x8899, 0xE5D8, 0x889E, 0xE5CF, 0x88A2, 0xE5D9, 0x88A4, 0xE5DB, 0x88AB, 0x94ED, 0x88AE, 0xE5D7, 0x88B0, 0xE5DC, 0x88B1, 0xE5DE, 0x88B4, 0x8CD1, 0x88B5, 0xE5D2, 0x88B7, 0x88BF, 0x88BF, 0xE5DD, 0x88C1, 0x8DD9, 0x88C2, 0x97F4, 0x88C3, 0xE5DF, 0x88C4, 0xE5E0, 0x88C5, 0x9195, 0x88CF, 0x97A0, 0x88D4, 0xE5E1, 0x88D5, 0x9754, 0x88D8, 0xE5E2, 0x88D9, 0xE5E3, 0x88DC, 0x95E2, 0x88DD, 0xE5E4, 0x88DF, 0x8DBE, 0x88E1, 0x97A1, 0x88E8, 0xE5E9, 0x88F2, 0xE5EA, 0x88F3, 0x8FD6, 0x88F4, 0xE5E8, 0x88F5, 0xFBA2, 0x88F8, 0x9787, 0x88F9, 0xE5E5, 0x88FC, 0xE5E7, 0x88FD, 0x90BB, 0x88FE, 0x909E, 0x8902, 0xE5E6, 0x8904, 0xE5EB, 0x8907, 0x95A1, 0x890A, 0xE5ED, 0x890C, 0xE5EC, 0x8910, 0x8A8C, 0x8912, 0x964A, 0x8913, 0xE5EE, 0x891C, 0xFA5D, 0x891D, 0xE5FA, 0x891E, 0xE5F0, 0x8925, 0xE5F1, 0x892A, 0xE5F2, 0x892B, 0xE5F3, 0x8936, 0xE5F7, 0x8938, 0xE5F8, 0x893B, 0xE5F6, 0x8941, 0xE5F4, 0x8943, 0xE5EF, 0x8944, 0xE5F5, 0x894C, 0xE5F9, 0x894D, 0xE8B5, 0x8956, 0x89A6, 0x895E, 0xE5FC, 0x895F, 0x8BDD, 0x8960, 0xE5FB, 0x8964, 0xE641, 0x8966, 0xE640, 0x896A, 0xE643, 0x896D, 0xE642, 0x896F, 0xE644, 0x8972, 0x8F50, 0x8974, 0xE645, 0x8977, 0xE646, 0x897E, 0xE647, 0x897F, 0x90BC, 0x8981, 0x9776, 0x8983, 0xE648, 0x8986, 0x95A2, 0x8987, 0x9465, 0x8988, 0xE649, 0x898A, 0xE64A, 0x898B, 0x8CA9, 0x898F, 0x8B4B, 0x8993, 0xE64B, 0x8996, 0x8E8B, 0x8997, 0x9460, 0x8998, 0xE64C, 0x899A, 0x8A6F, 0x89A1, 0xE64D, 0x89A6, 0xE64F, 0x89A7, 0x9797, 0x89A9, 0xE64E, 0x89AA, 0x9065, 0x89AC, 0xE650, 0x89AF, 0xE651, 0x89B2, 0xE652, 0x89B3, 0x8ACF, 0x89BA, 0xE653, 0x89BD, 0xE654, 0x89BF, 0xE655, 0x89C0, 0xE656, 0x89D2, 0x8A70, 0x89DA, 0xE657, 0x89DC, 0xE658, 0x89DD, 0xE659, 0x89E3, 0x89F0, 0x89E6, 0x9047, 0x89E7, 0xE65A, 0x89F4, 0xE65B, 0x89F8, 0xE65C, 0x8A00, 0x8CBE, 0x8A02, 0x92F9, 0x8A03, 0xE65D, 0x8A08, 0x8C76, 0x8A0A, 0x9075, 0x8A0C, 0xE660, 0x8A0E, 0x93A2, 0x8A10, 0xE65F, 0x8A12, 0xFBA3, 0x8A13, 0x8C50, 0x8A16, 0xE65E, 0x8A17, 0x91F5, 0x8A18, 0x8B4C, 0x8A1B, 0xE661, 0x8A1D, 0xE662, 0x8A1F, 0x8FD7, 0x8A23, 0x8C8D, 0x8A25, 0xE663, 0x8A2A, 0x964B, 0x8A2D, 0x90DD, 0x8A31, 0x8B96, 0x8A33, 0x96F3, 0x8A34, 0x9169, 0x8A36, 0xE664, 0x8A37, 0xFBA4, 0x8A3A, 0x9066, 0x8A3B, 0x9290, 0x8A3C, 0x8FD8, 0x8A41, 0xE665, 0x8A46, 0xE668, 0x8A48, 0xE669, 0x8A50, 0x8DBC, 0x8A51, 0x91C0, 0x8A52, 0xE667, 0x8A54, 0x8FD9, 0x8A55, 0x955D, 0x8A5B, 0xE666, 0x8A5E, 0x8E8C, 0x8A60, 0x8972, 0x8A62, 0xE66D, 0x8A63, 0x8C77, 0x8A66, 0x8E8E, 0x8A69, 0x8E8D, 0x8A6B, 0x986C, 0x8A6C, 0xE66C, 0x8A6D, 0xE66B, 0x8A6E, 0x9146, 0x8A70, 0x8B6C, 0x8A71, 0x9862, 0x8A72, 0x8A59, 0x8A73, 0x8FDA, 0x8A79, 0xFBA5, 0x8A7C, 0xE66A, 0x8A82, 0xE66F, 0x8A84, 0xE670, 0x8A85, 0xE66E, 0x8A87, 0x8CD6, 0x8A89, 0x975F, 0x8A8C, 0x8E8F, 0x8A8D, 0x9446, 0x8A91, 0xE673, 0x8A93, 0x90BE, 0x8A95, 0x9261, 0x8A98, 0x9755, 0x8A9A, 0xE676, 0x8A9E, 0x8CEA, 0x8AA0, 0x90BD, 0x8AA1, 0xE672, 0x8AA3, 0xE677, 0x8AA4, 0x8CEB, 0x8AA5, 0xE674, 0x8AA6, 0xE675, 0x8AA7, 0xFBA6, 0x8AA8, 0xE671, 0x8AAC, 0x90E0, 0x8AAD, 0x93C7, 0x8AB0, 0x924E, 0x8AB2, 0x89DB, 0x8AB9, 0x94EE, 0x8ABC, 0x8B62, 0x8ABE, 0xFBA7, 0x8ABF, 0x92B2, 0x8AC2, 0xE67A, 0x8AC4, 0xE678, 0x8AC7, 0x926B, 0x8ACB, 0x90BF, 0x8ACC, 0x8AD0, 0x8ACD, 0xE679, 0x8ACF, 0x907A, 0x8AD2, 0x97C8, 0x8AD6, 0x985F, 0x8ADA, 0xE67B, 0x8ADB, 0xE687, 0x8ADC, 0x92B3, 0x8ADE, 0xE686, 0x8ADF, 0xFBA8, 0x8AE0, 0xE683, 0x8AE1, 0xE68B, 0x8AE2, 0xE684, 0x8AE4, 0xE680, 0x8AE6, 0x92FA, 0x8AE7, 0xE67E, 0x8AEB, 0xE67C, 0x8AED, 0x9740, 0x8AEE, 0x8E90, 0x8AF1, 0xE681, 0x8AF3, 0xE67D, 0x8AF6, 0xFBAA, 0x8AF7, 0xE685, 0x8AF8, 0x8F94, 0x8AFA, 0x8CBF, 0x8AFE, 0x91F8, 0x8B00, 0x9664, 0x8B01, 0x8979, 0x8B02, 0x88E0, 0x8B04, 0x93A3, 0x8B07, 0xE689, 0x8B0C, 0xE688, 0x8B0E, 0x93E4, 0x8B10, 0xE68D, 0x8B14, 0xE682, 0x8B16, 0xE68C, 0x8B17, 0xE68E, 0x8B19, 0x8CAA, 0x8B1A, 0xE68A, 0x8B1B, 0x8D75, 0x8B1D, 0x8ED3, 0x8B20, 0xE68F, 0x8B21, 0x9777, 0x8B26, 0xE692, 0x8B28, 0xE695, 0x8B2B, 0xE693, 0x8B2C, 0x9554, 0x8B33, 0xE690, 0x8B39, 0x8BDE, 0x8B3E, 0xE694, 0x8B41, 0xE696, 0x8B49, 0xE69A, 0x8B4C, 0xE697, 0x8B4E, 0xE699, 0x8B4F, 0xE698, 0x8B53, 0xFBAB, 0x8B56, 0xE69B, 0x8B58, 0x8EAF, 0x8B5A, 0xE69D, 0x8B5B, 0xE69C, 0x8B5C, 0x9588, 0x8B5F, 0xE69F, 0x8B66, 0x8C78, 0x8B6B, 0xE69E, 0x8B6C, 0xE6A0, 0x8B6F, 0xE6A1, 0x8B70, 0x8B63, 0x8B71, 0xE3BF, 0x8B72, 0x8FF7, 0x8B74, 0xE6A2, 0x8B77, 0x8CEC, 0x8B7D, 0xE6A3, 0x8B7F, 0xFBAC, 0x8B80, 0xE6A4, 0x8B83, 0x8E5D, 0x8B8A, 0x9DCC, 0x8B8C, 0xE6A5, 0x8B8E, 0xE6A6, 0x8B90, 0x8F51, 0x8B92, 0xE6A7, 0x8B93, 0xE6A8, 0x8B96, 0xE6A9, 0x8B99, 0xE6AA, 0x8B9A, 0xE6AB, 0x8C37, 0x924A, 0x8C3A, 0xE6AC, 0x8C3F, 0xE6AE, 0x8C41, 0xE6AD, 0x8C46, 0x93A4, 0x8C48, 0xE6AF, 0x8C4A, 0x964C, 0x8C4C, 0xE6B0, 0x8C4E, 0xE6B1, 0x8C50, 0xE6B2, 0x8C55, 0xE6B3, 0x8C5A, 0x93D8, 0x8C61, 0x8FDB, 0x8C62, 0xE6B4, 0x8C6A, 0x8D8B, 0x8C6B, 0x98AC, 0x8C6C, 0xE6B5, 0x8C78, 0xE6B6, 0x8C79, 0x955E, 0x8C7A, 0xE6B7, 0x8C7C, 0xE6BF, 0x8C82, 0xE6B8, 0x8C85, 0xE6BA, 0x8C89, 0xE6B9, 0x8C8A, 0xE6BB, 0x8C8C, 0x9665, 0x8C8D, 0xE6BC, 0x8C8E, 0xE6BD, 0x8C94, 0xE6BE, 0x8C98, 0xE6C0, 0x8C9D, 0x8A4C, 0x8C9E, 0x92E5, 0x8CA0, 0x9589, 0x8CA1, 0x8DE0, 0x8CA2, 0x8D76, 0x8CA7, 0x956E, 0x8CA8, 0x89DD, 0x8CA9, 0x94CC, 0x8CAA, 0xE6C3, 0x8CAB, 0x8AD1, 0x8CAC, 0x90D3, 0x8CAD, 0xE6C2, 0x8CAE, 0xE6C7, 0x8CAF, 0x9299, 0x8CB0, 0x96E1, 0x8CB2, 0xE6C5, 0x8CB3, 0xE6C6, 0x8CB4, 0x8B4D, 0x8CB6, 0xE6C8, 0x8CB7, 0x9483, 0x8CB8, 0x91DD, 0x8CBB, 0x94EF, 0x8CBC, 0x935C, 0x8CBD, 0xE6C4, 0x8CBF, 0x9666, 0x8CC0, 0x89EA, 0x8CC1, 0xE6CA, 0x8CC2, 0x9847, 0x8CC3, 0x92C0, 0x8CC4, 0x9864, 0x8CC7, 0x8E91, 0x8CC8, 0xE6C9, 0x8CCA, 0x91AF, 0x8CCD, 0xE6DA, 0x8CCE, 0x9147, 0x8CD1, 0x93F6, 0x8CD3, 0x956F, 0x8CDA, 0xE6CD, 0x8CDB, 0x8E5E, 0x8CDC, 0x8E92, 0x8CDE, 0x8FDC, 0x8CE0, 0x9485, 0x8CE2, 0x8CAB, 0x8CE3, 0xE6CC, 0x8CE4, 0xE6CB, 0x8CE6, 0x958A, 0x8CEA, 0x8EBF, 0x8CED, 0x9371, 0x8CF0, 0xFBAD, 0x8CF4, 0xFBAE, 0x8CFA, 0xE6CF, 0x8CFB, 0xE6D0, 0x8CFC, 0x8D77, 0x8CFD, 0xE6CE, 0x8D04, 0xE6D1, 0x8D05, 0xE6D2, 0x8D07, 0xE6D4, 0x8D08, 0x91A1, 0x8D0A, 0xE6D3, 0x8D0B, 0x8AE4, 0x8D0D, 0xE6D6, 0x8D0F, 0xE6D5, 0x8D10, 0xE6D7, 0x8D12, 0xFBAF, 0x8D13, 0xE6D9, 0x8D14, 0xE6DB, 0x8D16, 0xE6DC, 0x8D64, 0x90D4, 0x8D66, 0x8ECD, 0x8D67, 0xE6DD, 0x8D6B, 0x8A71, 0x8D6D, 0xE6DE, 0x8D70, 0x9196, 0x8D71, 0xE6DF, 0x8D73, 0xE6E0, 0x8D74, 0x958B, 0x8D76, 0xFBB0, 0x8D77, 0x8B4E, 0x8D81, 0xE6E1, 0x8D85, 0x92B4, 0x8D8A, 0x897A, 0x8D99, 0xE6E2, 0x8DA3, 0x8EEF, 0x8DA8, 0x9096, 0x8DB3, 0x91AB, 0x8DBA, 0xE6E5, 0x8DBE, 0xE6E4, 0x8DC2, 0xE6E3, 0x8DCB, 0xE6EB, 0x8DCC, 0xE6E9, 0x8DCF, 0xE6E6, 0x8DD6, 0xE6E8, 0x8DDA, 0xE6E7, 0x8DDB, 0xE6EA, 0x8DDD, 0x8B97, 0x8DDF, 0xE6EE, 0x8DE1, 0x90D5, 0x8DE3, 0xE6EF, 0x8DE8, 0x8CD7, 0x8DEA, 0xE6EC, 0x8DEB, 0xE6ED, 0x8DEF, 0x9848, 0x8DF3, 0x92B5, 0x8DF5, 0x9148, 0x8DFC, 0xE6F0, 0x8DFF, 0xE6F3, 0x8E08, 0xE6F1, 0x8E09, 0xE6F2, 0x8E0A, 0x9778, 0x8E0F, 0x93A5, 0x8E10, 0xE6F6, 0x8E1D, 0xE6F4, 0x8E1E, 0xE6F5, 0x8E1F, 0xE6F7, 0x8E2A, 0xE748, 0x8E30, 0xE6FA, 0x8E34, 0xE6FB, 0x8E35, 0xE6F9, 0x8E42, 0xE6F8, 0x8E44, 0x92FB, 0x8E47, 0xE740, 0x8E48, 0xE744, 0x8E49, 0xE741, 0x8E4A, 0xE6FC, 0x8E4C, 0xE742, 0x8E50, 0xE743, 0x8E55, 0xE74A, 0x8E59, 0xE745, 0x8E5F, 0x90D6, 0x8E60, 0xE747, 0x8E63, 0xE749, 0x8E64, 0xE746, 0x8E72, 0xE74C, 0x8E74, 0x8F52, 0x8E76, 0xE74B, 0x8E7C, 0xE74D, 0x8E81, 0xE74E, 0x8E84, 0xE751, 0x8E85, 0xE750, 0x8E87, 0xE74F, 0x8E8A, 0xE753, 0x8E8B, 0xE752, 0x8E8D, 0x96F4, 0x8E91, 0xE755, 0x8E93, 0xE754, 0x8E94, 0xE756, 0x8E99, 0xE757, 0x8EA1, 0xE759, 0x8EAA, 0xE758, 0x8EAB, 0x9067, 0x8EAC, 0xE75A, 0x8EAF, 0x8BEB, 0x8EB0, 0xE75B, 0x8EB1, 0xE75D, 0x8EBE, 0xE75E, 0x8EC5, 0xE75F, 0x8EC6, 0xE75C, 0x8EC8, 0xE760, 0x8ECA, 0x8ED4, 0x8ECB, 0xE761, 0x8ECC, 0x8B4F, 0x8ECD, 0x8C52, 0x8ECF, 0xFBB2, 0x8ED2, 0x8CAC, 0x8EDB, 0xE762, 0x8EDF, 0x93EE, 0x8EE2, 0x935D, 0x8EE3, 0xE763, 0x8EEB, 0xE766, 0x8EF8, 0x8EB2, 0x8EFB, 0xE765, 0x8EFC, 0xE764, 0x8EFD, 0x8C79, 0x8EFE, 0xE767, 0x8F03, 0x8A72, 0x8F05, 0xE769, 0x8F09, 0x8DDA, 0x8F0A, 0xE768, 0x8F0C, 0xE771, 0x8F12, 0xE76B, 0x8F13, 0xE76D, 0x8F14, 0x95E3, 0x8F15, 0xE76A, 0x8F19, 0xE76C, 0x8F1B, 0xE770, 0x8F1C, 0xE76E, 0x8F1D, 0x8B50, 0x8F1F, 0xE76F, 0x8F26, 0xE772, 0x8F29, 0x9479, 0x8F2A, 0x97D6, 0x8F2F, 0x8F53, 0x8F33, 0xE773, 0x8F38, 0x9741, 0x8F39, 0xE775, 0x8F3B, 0xE774, 0x8F3E, 0xE778, 0x8F3F, 0x9760, 0x8F42, 0xE777, 0x8F44, 0x8A8D, 0x8F45, 0xE776, 0x8F46, 0xE77B, 0x8F49, 0xE77A, 0x8F4C, 0xE779, 0x8F4D, 0x9351, 0x8F4E, 0xE77C, 0x8F57, 0xE77D, 0x8F5C, 0xE77E, 0x8F5F, 0x8D8C, 0x8F61, 0x8C44, 0x8F62, 0xE780, 0x8F63, 0xE781, 0x8F64, 0xE782, 0x8F9B, 0x9068, 0x8F9C, 0xE783, 0x8F9E, 0x8EAB, 0x8F9F, 0xE784, 0x8FA3, 0xE785, 0x8FA7, 0x999F, 0x8FA8, 0x999E, 0x8FAD, 0xE786, 0x8FAE, 0xE390, 0x8FAF, 0xE787, 0x8FB0, 0x9243, 0x8FB1, 0x904A, 0x8FB2, 0x945F, 0x8FB7, 0xE788, 0x8FBA, 0x95D3, 0x8FBB, 0x92D2, 0x8FBC, 0x8D9E, 0x8FBF, 0x9248, 0x8FC2, 0x8949, 0x8FC4, 0x9698, 0x8FC5, 0x9076, 0x8FCE, 0x8C7D, 0x8FD1, 0x8BDF, 0x8FD4, 0x95D4, 0x8FDA, 0xE789, 0x8FE2, 0xE78B, 0x8FE5, 0xE78A, 0x8FE6, 0x89DE, 0x8FE9, 0x93F4, 0x8FEA, 0xE78C, 0x8FEB, 0x9497, 0x8FED, 0x9352, 0x8FEF, 0xE78D, 0x8FF0, 0x8F71, 0x8FF4, 0xE78F, 0x8FF7, 0x96C0, 0x8FF8, 0xE79E, 0x8FF9, 0xE791, 0x8FFA, 0xE792, 0x8FFD, 0x92C7, 0x9000, 0x91DE, 0x9001, 0x9197, 0x9003, 0x93A6, 0x9005, 0xE790, 0x9006, 0x8B74, 0x900B, 0xE799, 0x900D, 0xE796, 0x900E, 0xE7A3, 0x900F, 0x93A7, 0x9010, 0x9280, 0x9011, 0xE793, 0x9013, 0x92FC, 0x9014, 0x9372, 0x9015, 0xE794, 0x9016, 0xE798, 0x9017, 0x9080, 0x9019, 0x9487, 0x901A, 0x92CA, 0x901D, 0x90C0, 0x901E, 0xE797, 0x901F, 0x91AC, 0x9020, 0x91A2, 0x9021, 0xE795, 0x9022, 0x88A7, 0x9023, 0x9841, 0x9027, 0xE79A, 0x902E, 0x91DF, 0x9031, 0x8F54, 0x9032, 0x9069, 0x9035, 0xE79C, 0x9036, 0xE79B, 0x9038, 0x88ED, 0x9039, 0xE79D, 0x903C, 0x954E, 0x903E, 0xE7A5, 0x9041, 0x93D9, 0x9042, 0x908B, 0x9045, 0x9278, 0x9047, 0x8BF6, 0x9049, 0xE7A4, 0x904A, 0x9756, 0x904B, 0x895E, 0x904D, 0x95D5, 0x904E, 0x89DF, 0x904F, 0xE79F, 0x9050, 0xE7A0, 0x9051, 0xE7A1, 0x9052, 0xE7A2, 0x9053, 0x93B9, 0x9054, 0x9242, 0x9055, 0x88E1, 0x9056, 0xE7A6, 0x9058, 0xE7A7, 0x9059, 0xEAA1, 0x905C, 0x91BB, 0x905E, 0xE7A8, 0x9060, 0x8993, 0x9061, 0x916B, 0x9063, 0x8CAD, 0x9065, 0x9779, 0x9067, 0xFBB5, 0x9068, 0xE7A9, 0x9069, 0x934B, 0x906D, 0x9198, 0x906E, 0x8ED5, 0x906F, 0xE7AA, 0x9072, 0xE7AD, 0x9075, 0x8F85, 0x9076, 0xE7AB, 0x9077, 0x914A, 0x9078, 0x9149, 0x907A, 0x88E2, 0x907C, 0x97C9, 0x907D, 0xE7AF, 0x907F, 0x94F0, 0x9080, 0xE7B1, 0x9081, 0xE7B0, 0x9082, 0xE7AE, 0x9083, 0xE284, 0x9084, 0x8AD2, 0x9087, 0xE78E, 0x9089, 0xE7B3, 0x908A, 0xE7B2, 0x908F, 0xE7B4, 0x9091, 0x9757, 0x90A3, 0x93DF, 0x90A6, 0x964D, 0x90A8, 0xE7B5, 0x90AA, 0x8ED7, 0x90AF, 0xE7B6, 0x90B1, 0xE7B7, 0x90B5, 0xE7B8, 0x90B8, 0x9340, 0x90C1, 0x88E8, 0x90CA, 0x8D78, 0x90CE, 0x9859, 0x90DB, 0xE7BC, 0x90DE, 0xFBB6, 0x90E1, 0x8C53, 0x90E2, 0xE7B9, 0x90E4, 0xE7BA, 0x90E8, 0x9594, 0x90ED, 0x8A73, 0x90F5, 0x9758, 0x90F7, 0x8BBD, 0x90FD, 0x9373, 0x9102, 0xE7BD, 0x9112, 0xE7BE, 0x9115, 0xFBB8, 0x9119, 0xE7BF, 0x9127, 0xFBB9, 0x912D, 0x9341, 0x9130, 0xE7C1, 0x9132, 0xE7C0, 0x9149, 0x93D1, 0x914A, 0xE7C2, 0x914B, 0x8F55, 0x914C, 0x8EDE, 0x914D, 0x947A, 0x914E, 0x9291, 0x9152, 0x8EF0, 0x9154, 0x908C, 0x9156, 0xE7C3, 0x9158, 0xE7C4, 0x9162, 0x907C, 0x9163, 0xE7C5, 0x9165, 0xE7C6, 0x9169, 0xE7C7, 0x916A, 0x978F, 0x916C, 0x8F56, 0x9172, 0xE7C9, 0x9173, 0xE7C8, 0x9175, 0x8D79, 0x9177, 0x8D93, 0x9178, 0x8E5F, 0x9182, 0xE7CC, 0x9187, 0x8F86, 0x9189, 0xE7CB, 0x918B, 0xE7CA, 0x918D, 0x91E7, 0x9190, 0x8CED, 0x9192, 0x90C1, 0x9197, 0x94AE, 0x919C, 0x8F58, 0x91A2, 0xE7CD, 0x91A4, 0x8FDD, 0x91AA, 0xE7D0, 0x91AB, 0xE7CE, 0x91AF, 0xE7CF, 0x91B4, 0xE7D2, 0x91B5, 0xE7D1, 0x91B8, 0x8FF8, 0x91BA, 0xE7D3, 0x91C0, 0xE7D4, 0x91C1, 0xE7D5, 0x91C6, 0x94CE, 0x91C7, 0x8DD1, 0x91C8, 0x8EDF, 0x91C9, 0xE7D6, 0x91CB, 0xE7D7, 0x91CC, 0x97A2, 0x91CD, 0x8F64, 0x91CE, 0x96EC, 0x91CF, 0x97CA, 0x91D0, 0xE7D8, 0x91D1, 0x8BE0, 0x91D6, 0xE7D9, 0x91D7, 0xFBBB, 0x91D8, 0x9342, 0x91DA, 0xFBBA, 0x91DB, 0xE7DC, 0x91DC, 0x8A98, 0x91DD, 0x906A, 0x91DE, 0xFBBC, 0x91DF, 0xE7DA, 0x91E1, 0xE7DB, 0x91E3, 0x92DE, 0x91E4, 0xFBBF, 0x91E5, 0xFBC0, 0x91E6, 0x9674, 0x91E7, 0x8BFA, 0x91ED, 0xFBBD, 0x91EE, 0xFBBE, 0x91F5, 0xE7DE, 0x91F6, 0xE7DF, 0x91FC, 0xE7DD, 0x91FF, 0xE7E1, 0x9206, 0xFBC1, 0x920A, 0xFBC3, 0x920D, 0x93DD, 0x920E, 0x8A62, 0x9210, 0xFBC2, 0x9211, 0xE7E5, 0x9214, 0xE7E2, 0x9215, 0xE7E4, 0x921E, 0xE7E0, 0x9229, 0xE86E, 0x922C, 0xE7E3, 0x9234, 0x97E9, 0x9237, 0x8CD8, 0x9239, 0xFBCA, 0x923A, 0xFBC4, 0x923C, 0xFBC6, 0x923F, 0xE7ED, 0x9240, 0xFBC5, 0x9244, 0x9353, 0x9245, 0xE7E8, 0x9248, 0xE7EB, 0x9249, 0xE7E9, 0x924B, 0xE7EE, 0x924E, 0xFBC7, 0x9250, 0xE7EF, 0x9251, 0xFBC9, 0x9257, 0xE7E7, 0x9259, 0xFBC8, 0x925A, 0xE7F4, 0x925B, 0x8994, 0x925E, 0xE7E6, 0x9262, 0x94AB, 0x9264, 0xE7EA, 0x9266, 0x8FDE, 0x9267, 0xFBCB, 0x9271, 0x8D7A, 0x9277, 0xFBCD, 0x9278, 0xFBCE, 0x927E, 0x9667, 0x9280, 0x8BE2, 0x9283, 0x8F65, 0x9285, 0x93BA, 0x9288, 0xFA5F, 0x9291, 0x914C, 0x9293, 0xE7F2, 0x9295, 0xE7EC, 0x9296, 0xE7F1, 0x9298, 0x96C1, 0x929A, 0x92B6, 0x929B, 0xE7F3, 0x929C, 0xE7F0, 0x92A7, 0xFBCC, 0x92AD, 0x914B, 0x92B7, 0xE7F7, 0x92B9, 0xE7F6, 0x92CF, 0xE7F5, 0x92D0, 0xFBD2, 0x92D2, 0x964E, 0x92D3, 0xFBD6, 0x92D5, 0xFBD4, 0x92D7, 0xFBD0, 0x92D9, 0xFBD1, 0x92E0, 0xFBD5, 0x92E4, 0x8F9B, 0x92E7, 0xFBCF, 0x92E9, 0xE7F8, 0x92EA, 0x95DD, 0x92ED, 0x8973, 0x92F2, 0x9565, 0x92F3, 0x9292, 0x92F8, 0x8B98, 0x92F9, 0xFA65, 0x92FA, 0xE7FA, 0x92FB, 0xFBD9, 0x92FC, 0x8D7C, 0x92FF, 0xFBDC, 0x9302, 0xFBDE, 0x9306, 0x8E4B, 0x930F, 0xE7F9, 0x9310, 0x908D, 0x9318, 0x908E, 0x9319, 0xE840, 0x931A, 0xE842, 0x931D, 0xFBDD, 0x931E, 0xFBDB, 0x9320, 0x8FF9, 0x9321, 0xFBD8, 0x9322, 0xE841, 0x9323, 0xE843, 0x9325, 0xFBD7, 0x9326, 0x8BD1, 0x9328, 0x9564, 0x932B, 0x8EE0, 0x932C, 0x9842, 0x932E, 0xE7FC, 0x932F, 0x8DF6, 0x9332, 0x985E, 0x9335, 0xE845, 0x933A, 0xE844, 0x933B, 0xE846, 0x9344, 0xE7FB, 0x9348, 0xFA5E, 0x934B, 0x93E7, 0x934D, 0x9374, 0x9354, 0x92D5, 0x9356, 0xE84B, 0x9357, 0xFBE0, 0x935B, 0x9262, 0x935C, 0xE847, 0x9360, 0xE848, 0x936C, 0x8C4C, 0x936E, 0xE84A, 0x9370, 0xFBDF, 0x9375, 0x8CAE, 0x937C, 0xE849, 0x937E, 0x8FDF, 0x938C, 0x8A99, 0x9394, 0xE84F, 0x9396, 0x8DBD, 0x9397, 0x9199, 0x939A, 0x92C8, 0x93A4, 0xFBE1, 0x93A7, 0x8A5A, 0x93AC, 0xE84D, 0x93AD, 0xE84E, 0x93AE, 0x92C1, 0x93B0, 0xE84C, 0x93B9, 0xE850, 0x93C3, 0xE856, 0x93C6, 0xFBE2, 0x93C8, 0xE859, 0x93D0, 0xE858, 0x93D1, 0x934C, 0x93D6, 0xE851, 0x93D7, 0xE852, 0x93D8, 0xE855, 0x93DD, 0xE857, 0x93DE, 0xFBE3, 0x93E1, 0x8BBE, 0x93E4, 0xE85A, 0x93E5, 0xE854, 0x93E8, 0xE853, 0x93F8, 0xFBE4, 0x9403, 0xE85E, 0x9407, 0xE85F, 0x9410, 0xE860, 0x9413, 0xE85D, 0x9414, 0xE85C, 0x9418, 0x8FE0, 0x9419, 0x93A8, 0x941A, 0xE85B, 0x9421, 0xE864, 0x942B, 0xE862, 0x9431, 0xFBE5, 0x9435, 0xE863, 0x9436, 0xE861, 0x9438, 0x91F6, 0x943A, 0xE865, 0x9441, 0xE866, 0x9444, 0xE868, 0x9445, 0xFBE6, 0x9448, 0xFBE7, 0x9451, 0x8AD3, 0x9452, 0xE867, 0x9453, 0x96F8, 0x945A, 0xE873, 0x945B, 0xE869, 0x945E, 0xE86C, 0x9460, 0xE86A, 0x9462, 0xE86B, 0x946A, 0xE86D, 0x9470, 0xE86F, 0x9475, 0xE870, 0x9477, 0xE871, 0x947C, 0xE874, 0x947D, 0xE872, 0x947E, 0xE875, 0x947F, 0xE877, 0x9481, 0xE876, 0x9577, 0x92B7, 0x9580, 0x96E5, 0x9582, 0xE878, 0x9583, 0x914D, 0x9587, 0xE879, 0x9589, 0x95C2, 0x958A, 0xE87A, 0x958B, 0x8A4A, 0x958F, 0x895B, 0x9591, 0x8AD5, 0x9592, 0xFBE8, 0x9593, 0x8AD4, 0x9594, 0xE87B, 0x9596, 0xE87C, 0x9598, 0xE87D, 0x9599, 0xE87E, 0x95A0, 0xE880, 0x95A2, 0x8AD6, 0x95A3, 0x8A74, 0x95A4, 0x8D7D, 0x95A5, 0x94B4, 0x95A7, 0xE882, 0x95A8, 0xE881, 0x95AD, 0xE883, 0x95B2, 0x897B, 0x95B9, 0xE886, 0x95BB, 0xE885, 0x95BC, 0xE884, 0x95BE, 0xE887, 0x95C3, 0xE88A, 0x95C7, 0x88C5, 0x95CA, 0xE888, 0x95CC, 0xE88C, 0x95CD, 0xE88B, 0x95D4, 0xE88E, 0x95D5, 0xE88D, 0x95D6, 0xE88F, 0x95D8, 0x93AC, 0x95DC, 0xE890, 0x95E1, 0xE891, 0x95E2, 0xE893, 0x95E5, 0xE892, 0x961C, 0x958C, 0x9621, 0xE894, 0x9628, 0xE895, 0x962A, 0x8DE3, 0x962E, 0xE896, 0x962F, 0xE897, 0x9632, 0x9668, 0x963B, 0x916A, 0x963F, 0x88A2, 0x9640, 0x91C9, 0x9642, 0xE898, 0x9644, 0x958D, 0x964B, 0xE89B, 0x964C, 0xE899, 0x964D, 0x8D7E, 0x964F, 0xE89A, 0x9650, 0x8CC0, 0x965B, 0x95C3, 0x965C, 0xE89D, 0x965D, 0xE89F, 0x965E, 0xE89E, 0x965F, 0xE8A0, 0x9662, 0x8940, 0x9663, 0x9077, 0x9664, 0x8F9C, 0x9665, 0x8AD7, 0x9666, 0xE8A1, 0x966A, 0x9486, 0x966C, 0xE8A3, 0x9670, 0x8941, 0x9672, 0xE8A2, 0x9673, 0x92C2, 0x9675, 0x97CB, 0x9676, 0x93A9, 0x9677, 0xE89C, 0x9678, 0x97A4, 0x967A, 0x8CAF, 0x967D, 0x977A, 0x9685, 0x8BF7, 0x9686, 0x97B2, 0x9688, 0x8C47, 0x968A, 0x91E0, 0x968B, 0xE440, 0x968D, 0xE8A4, 0x968E, 0x8A4B, 0x968F, 0x908F, 0x9694, 0x8A75, 0x9695, 0xE8A6, 0x9697, 0xE8A7, 0x9698, 0xE8A5, 0x9699, 0x8C84, 0x969B, 0x8DDB, 0x969C, 0x8FE1, 0x969D, 0xFBEB, 0x96A0, 0x8942, 0x96A3, 0x97D7, 0x96A7, 0xE8A9, 0x96A8, 0xE7AC, 0x96AA, 0xE8A8, 0x96AF, 0xFBEC, 0x96B0, 0xE8AC, 0x96B1, 0xE8AA, 0x96B2, 0xE8AB, 0x96B4, 0xE8AD, 0x96B6, 0xE8AE, 0x96B7, 0x97EA, 0x96B8, 0xE8AF, 0x96B9, 0xE8B0, 0x96BB, 0x90C7, 0x96BC, 0x94B9, 0x96C0, 0x909D, 0x96C1, 0x8AE5, 0x96C4, 0x9759, 0x96C5, 0x89EB, 0x96C6, 0x8F57, 0x96C7, 0x8CD9, 0x96C9, 0xE8B3, 0x96CB, 0xE8B2, 0x96CC, 0x8E93, 0x96CD, 0xE8B4, 0x96CE, 0xE8B1, 0x96D1, 0x8E47, 0x96D5, 0xE8B8, 0x96D6, 0xE5AB, 0x96D9, 0x99D4, 0x96DB, 0x9097, 0x96DC, 0xE8B6, 0x96E2, 0x97A3, 0x96E3, 0x93EF, 0x96E8, 0x894A, 0x96EA, 0x90E1, 0x96EB, 0x8EB4, 0x96F0, 0x95B5, 0x96F2, 0x895F, 0x96F6, 0x97EB, 0x96F7, 0x978B, 0x96F9, 0xE8B9, 0x96FB, 0x9364, 0x9700, 0x8EF9, 0x9704, 0xE8BA, 0x9706, 0xE8BB, 0x9707, 0x906B, 0x9708, 0xE8BC, 0x970A, 0x97EC, 0x970D, 0xE8B7, 0x970E, 0xE8BE, 0x970F, 0xE8C0, 0x9711, 0xE8BF, 0x9713, 0xE8BD, 0x9716, 0xE8C1, 0x9719, 0xE8C2, 0x971C, 0x919A, 0x971E, 0x89E0, 0x9724, 0xE8C3, 0x9727, 0x96B6, 0x972A, 0xE8C4, 0x9730, 0xE8C5, 0x9732, 0x9849, 0x9733, 0xFBED, 0x9738, 0x9E50, 0x9739, 0xE8C6, 0x973B, 0xFBEE, 0x973D, 0xE8C7, 0x973E, 0xE8C8, 0x9742, 0xE8CC, 0x9743, 0xFBEF, 0x9744, 0xE8C9, 0x9746, 0xE8CA, 0x9748, 0xE8CB, 0x9749, 0xE8CD, 0x974D, 0xFBF0, 0x974F, 0xFBF1, 0x9751, 0xFBF2, 0x9752, 0x90C2, 0x9755, 0xFBF3, 0x9756, 0x96F5, 0x9759, 0x90C3, 0x975C, 0xE8CE, 0x975E, 0x94F1, 0x9760, 0xE8CF, 0x9761, 0xEA72, 0x9762, 0x96CA, 0x9764, 0xE8D0, 0x9766, 0xE8D1, 0x9768, 0xE8D2, 0x9769, 0x8A76, 0x976B, 0xE8D4, 0x976D, 0x9078, 0x9771, 0xE8D5, 0x9774, 0x8C43, 0x9779, 0xE8D6, 0x977A, 0xE8DA, 0x977C, 0xE8D8, 0x9781, 0xE8D9, 0x9784, 0x8A93, 0x9785, 0xE8D7, 0x9786, 0xE8DB, 0x978B, 0xE8DC, 0x978D, 0x88C6, 0x978F, 0xE8DD, 0x9790, 0xE8DE, 0x9798, 0x8FE2, 0x979C, 0xE8DF, 0x97A0, 0x8B66, 0x97A3, 0xE8E2, 0x97A6, 0xE8E1, 0x97A8, 0xE8E0, 0x97AB, 0xE691, 0x97AD, 0x95DA, 0x97B3, 0xE8E3, 0x97B4, 0xE8E4, 0x97C3, 0xE8E5, 0x97C6, 0xE8E6, 0x97C8, 0xE8E7, 0x97CB, 0xE8E8, 0x97D3, 0x8AD8, 0x97DC, 0xE8E9, 0x97ED, 0xE8EA, 0x97EE, 0x9442, 0x97F2, 0xE8EC, 0x97F3, 0x89B9, 0x97F5, 0xE8EF, 0x97F6, 0xE8EE, 0x97FB, 0x8943, 0x97FF, 0x8BBF, 0x9801, 0x95C5, 0x9802, 0x92B8, 0x9803, 0x8DA0, 0x9805, 0x8D80, 0x9806, 0x8F87, 0x9808, 0x907B, 0x980C, 0xE8F1, 0x980F, 0xE8F0, 0x9810, 0x9761, 0x9811, 0x8AE6, 0x9812, 0x94D0, 0x9813, 0x93DA, 0x9817, 0x909C, 0x9818, 0x97CC, 0x981A, 0x8C7A, 0x9821, 0xE8F4, 0x9824, 0xE8F3, 0x982C, 0x966A, 0x982D, 0x93AA, 0x9834, 0x896F, 0x9837, 0xE8F5, 0x9838, 0xE8F2, 0x983B, 0x9570, 0x983C, 0x978A, 0x983D, 0xE8F6, 0x9846, 0xE8F7, 0x984B, 0xE8F9, 0x984C, 0x91E8, 0x984D, 0x8A7A, 0x984E, 0x8A7B, 0x984F, 0xE8F8, 0x9854, 0x8AE7, 0x9855, 0x8CB0, 0x9857, 0xFBF4, 0x9858, 0x8AE8, 0x985B, 0x935E, 0x985E, 0x97DE, 0x9865, 0xFBF5, 0x9867, 0x8CDA, 0x986B, 0xE8FA, 0x986F, 0xE8FB, 0x9870, 0xE8FC, 0x9871, 0xE940, 0x9873, 0xE942, 0x9874, 0xE941, 0x98A8, 0x9597, 0x98AA, 0xE943, 0x98AF, 0xE944, 0x98B1, 0xE945, 0x98B6, 0xE946, 0x98C3, 0xE948, 0x98C4, 0xE947, 0x98C6, 0xE949, 0x98DB, 0x94F2, 0x98DC, 0xE3CA, 0x98DF, 0x9048, 0x98E2, 0x8B51, 0x98E9, 0xE94A, 0x98EB, 0xE94B, 0x98ED, 0x99AA, 0x98EE, 0x9F5A, 0x98EF, 0x94D1, 0x98F2, 0x88F9, 0x98F4, 0x88B9, 0x98FC, 0x8E94, 0x98FD, 0x964F, 0x98FE, 0x8FFC, 0x9903, 0xE94C, 0x9905, 0x96DD, 0x9909, 0xE94D, 0x990A, 0x977B, 0x990C, 0x8961, 0x9910, 0x8E60, 0x9912, 0xE94E, 0x9913, 0x89EC, 0x9914, 0xE94F, 0x9918, 0xE950, 0x991D, 0xE952, 0x991E, 0xE953, 0x9920, 0xE955, 0x9921, 0xE951, 0x9924, 0xE954, 0x9927, 0xFBF8, 0x9928, 0x8AD9, 0x992C, 0xE956, 0x992E, 0xE957, 0x993D, 0xE958, 0x993E, 0xE959, 0x9942, 0xE95A, 0x9945, 0xE95C, 0x9949, 0xE95B, 0x994B, 0xE95E, 0x994C, 0xE961, 0x9950, 0xE95D, 0x9951, 0xE95F, 0x9952, 0xE960, 0x9955, 0xE962, 0x9957, 0x8BC0, 0x9996, 0x8EF1, 0x9997, 0xE963, 0x9998, 0xE964, 0x9999, 0x8D81, 0x999E, 0xFBFA, 0x99A5, 0xE965, 0x99A8, 0x8A5D, 0x99AC, 0x946E, 0x99AD, 0xE966, 0x99AE, 0xE967, 0x99B3, 0x9279, 0x99B4, 0x93E9, 0x99BC, 0xE968, 0x99C1, 0x949D, 0x99C4, 0x91CA, 0x99C5, 0x8977, 0x99C6, 0x8BEC, 0x99C8, 0x8BED, 0x99D0, 0x9293, 0x99D1, 0xE96D, 0x99D2, 0x8BEE, 0x99D5, 0x89ED, 0x99D8, 0xE96C, 0x99DB, 0xE96A, 0x99DD, 0xE96B, 0x99DF, 0xE969, 0x99E2, 0xE977, 0x99ED, 0xE96E, 0x99EE, 0xE96F, 0x99F1, 0xE970, 0x99F2, 0xE971, 0x99F8, 0xE973, 0x99FB, 0xE972, 0x99FF, 0x8F78, 0x9A01, 0xE974, 0x9A05, 0xE976, 0x9A0E, 0x8B52, 0x9A0F, 0xE975, 0x9A12, 0x919B, 0x9A13, 0x8CB1, 0x9A19, 0xE978, 0x9A28, 0x91CB, 0x9A2B, 0xE979, 0x9A30, 0x93AB, 0x9A37, 0xE97A, 0x9A3E, 0xE980, 0x9A40, 0xE97D, 0x9A42, 0xE97C, 0x9A43, 0xE97E, 0x9A45, 0xE97B, 0x9A4D, 0xE982, 0x9A4E, 0xFBFB, 0x9A55, 0xE981, 0x9A57, 0xE984, 0x9A5A, 0x8BC1, 0x9A5B, 0xE983, 0x9A5F, 0xE985, 0x9A62, 0xE986, 0x9A64, 0xE988, 0x9A65, 0xE987, 0x9A69, 0xE989, 0x9A6A, 0xE98B, 0x9A6B, 0xE98A, 0x9AA8, 0x8D9C, 0x9AAD, 0xE98C, 0x9AB0, 0xE98D, 0x9AB8, 0x8A5B, 0x9ABC, 0xE98E, 0x9AC0, 0xE98F, 0x9AC4, 0x9091, 0x9ACF, 0xE990, 0x9AD1, 0xE991, 0x9AD3, 0xE992, 0x9AD4, 0xE993, 0x9AD8, 0x8D82, 0x9AD9, 0xFBFC, 0x9ADC, 0xFC40, 0x9ADE, 0xE994, 0x9ADF, 0xE995, 0x9AE2, 0xE996, 0x9AE3, 0xE997, 0x9AE6, 0xE998, 0x9AEA, 0x94AF, 0x9AEB, 0xE99A, 0x9AED, 0x9545, 0x9AEE, 0xE99B, 0x9AEF, 0xE999, 0x9AF1, 0xE99D, 0x9AF4, 0xE99C, 0x9AF7, 0xE99E, 0x9AFB, 0xE99F, 0x9B06, 0xE9A0, 0x9B18, 0xE9A1, 0x9B1A, 0xE9A2, 0x9B1F, 0xE9A3, 0x9B22, 0xE9A4, 0x9B23, 0xE9A5, 0x9B25, 0xE9A6, 0x9B27, 0xE9A7, 0x9B28, 0xE9A8, 0x9B29, 0xE9A9, 0x9B2A, 0xE9AA, 0x9B2E, 0xE9AB, 0x9B2F, 0xE9AC, 0x9B31, 0x9F54, 0x9B32, 0xE9AD, 0x9B3B, 0xE2F6, 0x9B3C, 0x8B53, 0x9B41, 0x8A40, 0x9B42, 0x8DB0, 0x9B43, 0xE9AF, 0x9B44, 0xE9AE, 0x9B45, 0x96A3, 0x9B4D, 0xE9B1, 0x9B4E, 0xE9B2, 0x9B4F, 0xE9B0, 0x9B51, 0xE9B3, 0x9B54, 0x9682, 0x9B58, 0xE9B4, 0x9B5A, 0x8B9B, 0x9B6F, 0x9844, 0x9B72, 0xFC42, 0x9B74, 0xE9B5, 0x9B75, 0xFC41, 0x9B83, 0xE9B7, 0x9B8E, 0x88BC, 0x9B8F, 0xFC43, 0x9B91, 0xE9B8, 0x9B92, 0x95A9, 0x9B93, 0xE9B6, 0x9B96, 0xE9B9, 0x9B97, 0xE9BA, 0x9B9F, 0xE9BB, 0x9BA0, 0xE9BC, 0x9BA8, 0xE9BD, 0x9BAA, 0x968E, 0x9BAB, 0x8E4C, 0x9BAD, 0x8DF8, 0x9BAE, 0x914E, 0x9BB1, 0xFC44, 0x9BB4, 0xE9BE, 0x9BB9, 0xE9C1, 0x9BBB, 0xFC45, 0x9BC0, 0xE9BF, 0x9BC6, 0xE9C2, 0x9BC9, 0x8CEF, 0x9BCA, 0xE9C0, 0x9BCF, 0xE9C3, 0x9BD1, 0xE9C4, 0x9BD2, 0xE9C5, 0x9BD4, 0xE9C9, 0x9BD6, 0x8E49, 0x9BDB, 0x91E2, 0x9BE1, 0xE9CA, 0x9BE2, 0xE9C7, 0x9BE3, 0xE9C6, 0x9BE4, 0xE9C8, 0x9BE8, 0x8C7E, 0x9BF0, 0xE9CE, 0x9BF1, 0xE9CD, 0x9BF2, 0xE9CC, 0x9BF5, 0x88B1, 0x9C00, 0xFC46, 0x9C04, 0xE9D8, 0x9C06, 0xE9D4, 0x9C08, 0xE9D5, 0x9C09, 0xE9D1, 0x9C0A, 0xE9D7, 0x9C0C, 0xE9D3, 0x9C0D, 0x8A82, 0x9C10, 0x986B, 0x9C12, 0xE9D6, 0x9C13, 0xE9D2, 0x9C14, 0xE9D0, 0x9C15, 0xE9CF, 0x9C1B, 0xE9DA, 0x9C21, 0xE9DD, 0x9C24, 0xE9DC, 0x9C25, 0xE9DB, 0x9C2D, 0x9568, 0x9C2E, 0xE9D9, 0x9C2F, 0x88F1, 0x9C30, 0xE9DE, 0x9C32, 0xE9E0, 0x9C39, 0x8A8F, 0x9C3A, 0xE9CB, 0x9C3B, 0x8956, 0x9C3E, 0xE9E2, 0x9C46, 0xE9E1, 0x9C47, 0xE9DF, 0x9C48, 0x924C, 0x9C52, 0x9690, 0x9C57, 0x97D8, 0x9C5A, 0xE9E3, 0x9C60, 0xE9E4, 0x9C67, 0xE9E5, 0x9C76, 0xE9E6, 0x9C78, 0xE9E7, 0x9CE5, 0x92B9, 0x9CE7, 0xE9E8, 0x9CE9, 0x94B5, 0x9CEB, 0xE9ED, 0x9CEC, 0xE9E9, 0x9CF0, 0xE9EA, 0x9CF3, 0x9650, 0x9CF4, 0x96C2, 0x9CF6, 0x93CE, 0x9D03, 0xE9EE, 0x9D06, 0xE9EF, 0x9D07, 0x93BC, 0x9D08, 0xE9EC, 0x9D09, 0xE9EB, 0x9D0E, 0x89A8, 0x9D12, 0xE9F7, 0x9D15, 0xE9F6, 0x9D1B, 0x8995, 0x9D1F, 0xE9F4, 0x9D23, 0xE9F3, 0x9D26, 0xE9F1, 0x9D28, 0x8A9B, 0x9D2A, 0xE9F0, 0x9D2B, 0x8EB0, 0x9D2C, 0x89A7, 0x9D3B, 0x8D83, 0x9D3E, 0xE9FA, 0x9D3F, 0xE9F9, 0x9D41, 0xE9F8, 0x9D44, 0xE9F5, 0x9D46, 0xE9FB, 0x9D48, 0xE9FC, 0x9D50, 0xEA44, 0x9D51, 0xEA43, 0x9D59, 0xEA45, 0x9D5C, 0x894C, 0x9D5D, 0xEA40, 0x9D5E, 0xEA41, 0x9D60, 0x8D94, 0x9D61, 0x96B7, 0x9D64, 0xEA42, 0x9D6B, 0xFC48, 0x9D6C, 0x9651, 0x9D6F, 0xEA4A, 0x9D70, 0xFC47, 0x9D72, 0xEA46, 0x9D7A, 0xEA4B, 0x9D87, 0xEA48, 0x9D89, 0xEA47, 0x9D8F, 0x8C7B, 0x9D9A, 0xEA4C, 0x9DA4, 0xEA4D, 0x9DA9, 0xEA4E, 0x9DAB, 0xEA49, 0x9DAF, 0xE9F2, 0x9DB2, 0xEA4F, 0x9DB4, 0x92DF, 0x9DB8, 0xEA53, 0x9DBA, 0xEA54, 0x9DBB, 0xEA52, 0x9DC1, 0xEA51, 0x9DC2, 0xEA57, 0x9DC4, 0xEA50, 0x9DC6, 0xEA55, 0x9DCF, 0xEA56, 0x9DD3, 0xEA59, 0x9DD9, 0xEA58, 0x9DE6, 0xEA5B, 0x9DED, 0xEA5C, 0x9DEF, 0xEA5D, 0x9DF2, 0x9868, 0x9DF8, 0xEA5A, 0x9DF9, 0x91E9, 0x9DFA, 0x8DEB, 0x9DFD, 0xEA5E, 0x9E19, 0xFC4A, 0x9E1A, 0xEA5F, 0x9E1B, 0xEA60, 0x9E1E, 0xEA61, 0x9E75, 0xEA62, 0x9E78, 0x8CB2, 0x9E79, 0xEA63, 0x9E7D, 0xEA64, 0x9E7F, 0x8EAD, 0x9E81, 0xEA65, 0x9E88, 0xEA66, 0x9E8B, 0xEA67, 0x9E8C, 0xEA68, 0x9E91, 0xEA6B, 0x9E92, 0xEA69, 0x9E93, 0x985B, 0x9E95, 0xEA6A, 0x9E97, 0x97ED, 0x9E9D, 0xEA6C, 0x9E9F, 0x97D9, 0x9EA5, 0xEA6D, 0x9EA6, 0x949E, 0x9EA9, 0xEA6E, 0x9EAA, 0xEA70, 0x9EAD, 0xEA71, 0x9EB8, 0xEA6F, 0x9EB9, 0x8D8D, 0x9EBA, 0x96CB, 0x9EBB, 0x9683, 0x9EBC, 0x9BF5, 0x9EBE, 0x9F80, 0x9EBF, 0x969B, 0x9EC4, 0x89A9, 0x9ECC, 0xEA73, 0x9ECD, 0x8B6F, 0x9ECE, 0xEA74, 0x9ECF, 0xEA75, 0x9ED0, 0xEA76, 0x9ED1, 0xFC4B, 0x9ED2, 0x8D95, 0x9ED4, 0xEA77, 0x9ED8, 0xE0D2, 0x9ED9, 0x96D9, 0x9EDB, 0x91E1, 0x9EDC, 0xEA78, 0x9EDD, 0xEA7A, 0x9EDE, 0xEA79, 0x9EE0, 0xEA7B, 0x9EE5, 0xEA7C, 0x9EE8, 0xEA7D, 0x9EEF, 0xEA7E, 0x9EF4, 0xEA80, 0x9EF6, 0xEA81, 0x9EF7, 0xEA82, 0x9EF9, 0xEA83, 0x9EFB, 0xEA84, 0x9EFC, 0xEA85, 0x9EFD, 0xEA86, 0x9F07, 0xEA87, 0x9F08, 0xEA88, 0x9F0E, 0x9343, 0x9F13, 0x8CDB, 0x9F15, 0xEA8A, 0x9F20, 0x916C, 0x9F21, 0xEA8B, 0x9F2C, 0xEA8C, 0x9F3B, 0x9540, 0x9F3E, 0xEA8D, 0x9F4A, 0xEA8E, 0x9F4B, 0xE256, 0x9F4E, 0xE6D8, 0x9F4F, 0xE8EB, 0x9F52, 0xEA8F, 0x9F54, 0xEA90, 0x9F5F, 0xEA92, 0x9F60, 0xEA93, 0x9F61, 0xEA94, 0x9F62, 0x97EE, 0x9F63, 0xEA91, 0x9F66, 0xEA95, 0x9F67, 0xEA96, 0x9F6A, 0xEA98, 0x9F6C, 0xEA97, 0x9F72, 0xEA9A, 0x9F76, 0xEA9B, 0x9F77, 0xEA99, 0x9F8D, 0x97B4, 0x9F95, 0xEA9C, 0x9F9C, 0xEA9D, 0x9F9D, 0xE273, 0x9FA0, 0xEA9E, 0xF929, 0xFAE0, 0xF9DC, 0xFBE9, 0xFA0E, 0xFA90, 0xFA0F, 0xFA9B, 0xFA10, 0xFA9C, 0xFA11, 0xFAB1, 0xFA12, 0xFAD8, 0xFA13, 0xFAE8, 0xFA14, 0xFAEA, 0xFA15, 0xFB58, 0xFA16, 0xFB5E, 0xFA17, 0xFB75, 0xFA18, 0xFB7D, 0xFA19, 0xFB7E, 0xFA1A, 0xFB80, 0xFA1B, 0xFB82, 0xFA1C, 0xFB86, 0xFA1D, 0xFB89, 0xFA1E, 0xFB92, 0xFA1F, 0xFB9D, 0xFA20, 0xFB9F, 0xFA21, 0xFBA0, 0xFA22, 0xFBA9, 0xFA23, 0xFBB1, 0xFA24, 0xFBB3, 0xFA25, 0xFBB4, 0xFA26, 0xFBB7, 0xFA27, 0xFBD3, 0xFA28, 0xFBDA, 0xFA29, 0xFBEA, 0xFA2A, 0xFBF6, 0xFA2B, 0xFBF7, 0xFA2C, 0xFBF9, 0xFA2D, 0xFC49, 0xFF01, 0x8149, 0xFF02, 0xFA57, 0xFF03, 0x8194, 0xFF04, 0x8190, 0xFF05, 0x8193, 0xFF06, 0x8195, 0xFF07, 0xFA56, 0xFF08, 0x8169, 0xFF09, 0x816A, 0xFF0A, 0x8196, 0xFF0B, 0x817B, 0xFF0C, 0x8143, 0xFF0D, 0x817C, 0xFF0E, 0x8144, 0xFF0F, 0x815E, 0xFF10, 0x824F, 0xFF11, 0x8250, 0xFF12, 0x8251, 0xFF13, 0x8252, 0xFF14, 0x8253, 0xFF15, 0x8254, 0xFF16, 0x8255, 0xFF17, 0x8256, 0xFF18, 0x8257, 0xFF19, 0x8258, 0xFF1A, 0x8146, 0xFF1B, 0x8147, 0xFF1C, 0x8183, 0xFF1D, 0x8181, 0xFF1E, 0x8184, 0xFF1F, 0x8148, 0xFF20, 0x8197, 0xFF21, 0x8260, 0xFF22, 0x8261, 0xFF23, 0x8262, 0xFF24, 0x8263, 0xFF25, 0x8264, 0xFF26, 0x8265, 0xFF27, 0x8266, 0xFF28, 0x8267, 0xFF29, 0x8268, 0xFF2A, 0x8269, 0xFF2B, 0x826A, 0xFF2C, 0x826B, 0xFF2D, 0x826C, 0xFF2E, 0x826D, 0xFF2F, 0x826E, 0xFF30, 0x826F, 0xFF31, 0x8270, 0xFF32, 0x8271, 0xFF33, 0x8272, 0xFF34, 0x8273, 0xFF35, 0x8274, 0xFF36, 0x8275, 0xFF37, 0x8276, 0xFF38, 0x8277, 0xFF39, 0x8278, 0xFF3A, 0x8279, 0xFF3B, 0x816D, 0xFF3C, 0x815F, 0xFF3D, 0x816E, 0xFF3E, 0x814F, 0xFF3F, 0x8151, 0xFF40, 0x814D, 0xFF41, 0x8281, 0xFF42, 0x8282, 0xFF43, 0x8283, 0xFF44, 0x8284, 0xFF45, 0x8285, 0xFF46, 0x8286, 0xFF47, 0x8287, 0xFF48, 0x8288, 0xFF49, 0x8289, 0xFF4A, 0x828A, 0xFF4B, 0x828B, 0xFF4C, 0x828C, 0xFF4D, 0x828D, 0xFF4E, 0x828E, 0xFF4F, 0x828F, 0xFF50, 0x8290, 0xFF51, 0x8291, 0xFF52, 0x8292, 0xFF53, 0x8293, 0xFF54, 0x8294, 0xFF55, 0x8295, 0xFF56, 0x8296, 0xFF57, 0x8297, 0xFF58, 0x8298, 0xFF59, 0x8299, 0xFF5A, 0x829A, 0xFF5B, 0x816F, 0xFF5C, 0x8162, 0xFF5D, 0x8170, 0xFF5E, 0x8160, 0xFF61, 0x00A1, 0xFF62, 0x00A2, 0xFF63, 0x00A3, 0xFF64, 0x00A4, 0xFF65, 0x00A5, 0xFF66, 0x00A6, 0xFF67, 0x00A7, 0xFF68, 0x00A8, 0xFF69, 0x00A9, 0xFF6A, 0x00AA, 0xFF6B, 0x00AB, 0xFF6C, 0x00AC, 0xFF6D, 0x00AD, 0xFF6E, 0x00AE, 0xFF6F, 0x00AF, 0xFF70, 0x00B0, 0xFF71, 0x00B1, 0xFF72, 0x00B2, 0xFF73, 0x00B3, 0xFF74, 0x00B4, 0xFF75, 0x00B5, 0xFF76, 0x00B6, 0xFF77, 0x00B7, 0xFF78, 0x00B8, 0xFF79, 0x00B9, 0xFF7A, 0x00BA, 0xFF7B, 0x00BB, 0xFF7C, 0x00BC, 0xFF7D, 0x00BD, 0xFF7E, 0x00BE, 0xFF7F, 0x00BF, 0xFF80, 0x00C0, 0xFF81, 0x00C1, 0xFF82, 0x00C2, 0xFF83, 0x00C3, 0xFF84, 0x00C4, 0xFF85, 0x00C5, 0xFF86, 0x00C6, 0xFF87, 0x00C7, 0xFF88, 0x00C8, 0xFF89, 0x00C9, 0xFF8A, 0x00CA, 0xFF8B, 0x00CB, 0xFF8C, 0x00CC, 0xFF8D, 0x00CD, 0xFF8E, 0x00CE, 0xFF8F, 0x00CF, 0xFF90, 0x00D0, 0xFF91, 0x00D1, 0xFF92, 0x00D2, 0xFF93, 0x00D3, 0xFF94, 0x00D4, 0xFF95, 0x00D5, 0xFF96, 0x00D6, 0xFF97, 0x00D7, 0xFF98, 0x00D8, 0xFF99, 0x00D9, 0xFF9A, 0x00DA, 0xFF9B, 0x00DB, 0xFF9C, 0x00DC, 0xFF9D, 0x00DD, 0xFF9E, 0x00DE, 0xFF9F, 0x00DF, 0xFFE0, 0x8191, 0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0 }; static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ 0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68, 0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70, 0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78, 0x00B9, 0xFF79, 0x00BA, 0xFF7A, 0x00BB, 0xFF7B, 0x00BC, 0xFF7C, 0x00BD, 0xFF7D, 0x00BE, 0xFF7E, 0x00BF, 0xFF7F, 0x00C0, 0xFF80, 0x00C1, 0xFF81, 0x00C2, 0xFF82, 0x00C3, 0xFF83, 0x00C4, 0xFF84, 0x00C5, 0xFF85, 0x00C6, 0xFF86, 0x00C7, 0xFF87, 0x00C8, 0xFF88, 0x00C9, 0xFF89, 0x00CA, 0xFF8A, 0x00CB, 0xFF8B, 0x00CC, 0xFF8C, 0x00CD, 0xFF8D, 0x00CE, 0xFF8E, 0x00CF, 0xFF8F, 0x00D0, 0xFF90, 0x00D1, 0xFF91, 0x00D2, 0xFF92, 0x00D3, 0xFF93, 0x00D4, 0xFF94, 0x00D5, 0xFF95, 0x00D6, 0xFF96, 0x00D7, 0xFF97, 0x00D8, 0xFF98, 0x00D9, 0xFF99, 0x00DA, 0xFF9A, 0x00DB, 0xFF9B, 0x00DC, 0xFF9C, 0x00DD, 0xFF9D, 0x00DE, 0xFF9E, 0x00DF, 0xFF9F, 0x8140, 0x3000, 0x8141, 0x3001, 0x8142, 0x3002, 0x8143, 0xFF0C, 0x8144, 0xFF0E, 0x8145, 0x30FB, 0x8146, 0xFF1A, 0x8147, 0xFF1B, 0x8148, 0xFF1F, 0x8149, 0xFF01, 0x814A, 0x309B, 0x814B, 0x309C, 0x814C, 0x00B4, 0x814D, 0xFF40, 0x814E, 0x00A8, 0x814F, 0xFF3E, 0x8150, 0xFFE3, 0x8151, 0xFF3F, 0x8152, 0x30FD, 0x8153, 0x30FE, 0x8154, 0x309D, 0x8155, 0x309E, 0x8156, 0x3003, 0x8157, 0x4EDD, 0x8158, 0x3005, 0x8159, 0x3006, 0x815A, 0x3007, 0x815B, 0x30FC, 0x815C, 0x2015, 0x815D, 0x2010, 0x815E, 0xFF0F, 0x815F, 0xFF3C, 0x8160, 0xFF5E, 0x8161, 0x2225, 0x8162, 0xFF5C, 0x8163, 0x2026, 0x8164, 0x2025, 0x8165, 0x2018, 0x8166, 0x2019, 0x8167, 0x201C, 0x8168, 0x201D, 0x8169, 0xFF08, 0x816A, 0xFF09, 0x816B, 0x3014, 0x816C, 0x3015, 0x816D, 0xFF3B, 0x816E, 0xFF3D, 0x816F, 0xFF5B, 0x8170, 0xFF5D, 0x8171, 0x3008, 0x8172, 0x3009, 0x8173, 0x300A, 0x8174, 0x300B, 0x8175, 0x300C, 0x8176, 0x300D, 0x8177, 0x300E, 0x8178, 0x300F, 0x8179, 0x3010, 0x817A, 0x3011, 0x817B, 0xFF0B, 0x817C, 0xFF0D, 0x817D, 0x00B1, 0x817E, 0x00D7, 0x8180, 0x00F7, 0x8181, 0xFF1D, 0x8182, 0x2260, 0x8183, 0xFF1C, 0x8184, 0xFF1E, 0x8185, 0x2266, 0x8186, 0x2267, 0x8187, 0x221E, 0x8188, 0x2234, 0x8189, 0x2642, 0x818A, 0x2640, 0x818B, 0x00B0, 0x818C, 0x2032, 0x818D, 0x2033, 0x818E, 0x2103, 0x818F, 0xFFE5, 0x8190, 0xFF04, 0x8191, 0xFFE0, 0x8192, 0xFFE1, 0x8193, 0xFF05, 0x8194, 0xFF03, 0x8195, 0xFF06, 0x8196, 0xFF0A, 0x8197, 0xFF20, 0x8198, 0x00A7, 0x8199, 0x2606, 0x819A, 0x2605, 0x819B, 0x25CB, 0x819C, 0x25CF, 0x819D, 0x25CE, 0x819E, 0x25C7, 0x819F, 0x25C6, 0x81A0, 0x25A1, 0x81A1, 0x25A0, 0x81A2, 0x25B3, 0x81A3, 0x25B2, 0x81A4, 0x25BD, 0x81A5, 0x25BC, 0x81A6, 0x203B, 0x81A7, 0x3012, 0x81A8, 0x2192, 0x81A9, 0x2190, 0x81AA, 0x2191, 0x81AB, 0x2193, 0x81AC, 0x3013, 0x81B8, 0x2208, 0x81B9, 0x220B, 0x81BA, 0x2286, 0x81BB, 0x2287, 0x81BC, 0x2282, 0x81BD, 0x2283, 0x81BE, 0x222A, 0x81BF, 0x2229, 0x81C8, 0x2227, 0x81C9, 0x2228, 0x81CA, 0xFFE2, 0x81CB, 0x21D2, 0x81CC, 0x21D4, 0x81CD, 0x2200, 0x81CE, 0x2203, 0x81DA, 0x2220, 0x81DB, 0x22A5, 0x81DC, 0x2312, 0x81DD, 0x2202, 0x81DE, 0x2207, 0x81DF, 0x2261, 0x81E0, 0x2252, 0x81E1, 0x226A, 0x81E2, 0x226B, 0x81E3, 0x221A, 0x81E4, 0x223D, 0x81E5, 0x221D, 0x81E6, 0x2235, 0x81E7, 0x222B, 0x81E8, 0x222C, 0x81F0, 0x212B, 0x81F1, 0x2030, 0x81F2, 0x266F, 0x81F3, 0x266D, 0x81F4, 0x266A, 0x81F5, 0x2020, 0x81F6, 0x2021, 0x81F7, 0x00B6, 0x81FC, 0x25EF, 0x824F, 0xFF10, 0x8250, 0xFF11, 0x8251, 0xFF12, 0x8252, 0xFF13, 0x8253, 0xFF14, 0x8254, 0xFF15, 0x8255, 0xFF16, 0x8256, 0xFF17, 0x8257, 0xFF18, 0x8258, 0xFF19, 0x8260, 0xFF21, 0x8261, 0xFF22, 0x8262, 0xFF23, 0x8263, 0xFF24, 0x8264, 0xFF25, 0x8265, 0xFF26, 0x8266, 0xFF27, 0x8267, 0xFF28, 0x8268, 0xFF29, 0x8269, 0xFF2A, 0x826A, 0xFF2B, 0x826B, 0xFF2C, 0x826C, 0xFF2D, 0x826D, 0xFF2E, 0x826E, 0xFF2F, 0x826F, 0xFF30, 0x8270, 0xFF31, 0x8271, 0xFF32, 0x8272, 0xFF33, 0x8273, 0xFF34, 0x8274, 0xFF35, 0x8275, 0xFF36, 0x8276, 0xFF37, 0x8277, 0xFF38, 0x8278, 0xFF39, 0x8279, 0xFF3A, 0x8281, 0xFF41, 0x8282, 0xFF42, 0x8283, 0xFF43, 0x8284, 0xFF44, 0x8285, 0xFF45, 0x8286, 0xFF46, 0x8287, 0xFF47, 0x8288, 0xFF48, 0x8289, 0xFF49, 0x828A, 0xFF4A, 0x828B, 0xFF4B, 0x828C, 0xFF4C, 0x828D, 0xFF4D, 0x828E, 0xFF4E, 0x828F, 0xFF4F, 0x8290, 0xFF50, 0x8291, 0xFF51, 0x8292, 0xFF52, 0x8293, 0xFF53, 0x8294, 0xFF54, 0x8295, 0xFF55, 0x8296, 0xFF56, 0x8297, 0xFF57, 0x8298, 0xFF58, 0x8299, 0xFF59, 0x829A, 0xFF5A, 0x829F, 0x3041, 0x82A0, 0x3042, 0x82A1, 0x3043, 0x82A2, 0x3044, 0x82A3, 0x3045, 0x82A4, 0x3046, 0x82A5, 0x3047, 0x82A6, 0x3048, 0x82A7, 0x3049, 0x82A8, 0x304A, 0x82A9, 0x304B, 0x82AA, 0x304C, 0x82AB, 0x304D, 0x82AC, 0x304E, 0x82AD, 0x304F, 0x82AE, 0x3050, 0x82AF, 0x3051, 0x82B0, 0x3052, 0x82B1, 0x3053, 0x82B2, 0x3054, 0x82B3, 0x3055, 0x82B4, 0x3056, 0x82B5, 0x3057, 0x82B6, 0x3058, 0x82B7, 0x3059, 0x82B8, 0x305A, 0x82B9, 0x305B, 0x82BA, 0x305C, 0x82BB, 0x305D, 0x82BC, 0x305E, 0x82BD, 0x305F, 0x82BE, 0x3060, 0x82BF, 0x3061, 0x82C0, 0x3062, 0x82C1, 0x3063, 0x82C2, 0x3064, 0x82C3, 0x3065, 0x82C4, 0x3066, 0x82C5, 0x3067, 0x82C6, 0x3068, 0x82C7, 0x3069, 0x82C8, 0x306A, 0x82C9, 0x306B, 0x82CA, 0x306C, 0x82CB, 0x306D, 0x82CC, 0x306E, 0x82CD, 0x306F, 0x82CE, 0x3070, 0x82CF, 0x3071, 0x82D0, 0x3072, 0x82D1, 0x3073, 0x82D2, 0x3074, 0x82D3, 0x3075, 0x82D4, 0x3076, 0x82D5, 0x3077, 0x82D6, 0x3078, 0x82D7, 0x3079, 0x82D8, 0x307A, 0x82D9, 0x307B, 0x82DA, 0x307C, 0x82DB, 0x307D, 0x82DC, 0x307E, 0x82DD, 0x307F, 0x82DE, 0x3080, 0x82DF, 0x3081, 0x82E0, 0x3082, 0x82E1, 0x3083, 0x82E2, 0x3084, 0x82E3, 0x3085, 0x82E4, 0x3086, 0x82E5, 0x3087, 0x82E6, 0x3088, 0x82E7, 0x3089, 0x82E8, 0x308A, 0x82E9, 0x308B, 0x82EA, 0x308C, 0x82EB, 0x308D, 0x82EC, 0x308E, 0x82ED, 0x308F, 0x82EE, 0x3090, 0x82EF, 0x3091, 0x82F0, 0x3092, 0x82F1, 0x3093, 0x8340, 0x30A1, 0x8341, 0x30A2, 0x8342, 0x30A3, 0x8343, 0x30A4, 0x8344, 0x30A5, 0x8345, 0x30A6, 0x8346, 0x30A7, 0x8347, 0x30A8, 0x8348, 0x30A9, 0x8349, 0x30AA, 0x834A, 0x30AB, 0x834B, 0x30AC, 0x834C, 0x30AD, 0x834D, 0x30AE, 0x834E, 0x30AF, 0x834F, 0x30B0, 0x8350, 0x30B1, 0x8351, 0x30B2, 0x8352, 0x30B3, 0x8353, 0x30B4, 0x8354, 0x30B5, 0x8355, 0x30B6, 0x8356, 0x30B7, 0x8357, 0x30B8, 0x8358, 0x30B9, 0x8359, 0x30BA, 0x835A, 0x30BB, 0x835B, 0x30BC, 0x835C, 0x30BD, 0x835D, 0x30BE, 0x835E, 0x30BF, 0x835F, 0x30C0, 0x8360, 0x30C1, 0x8361, 0x30C2, 0x8362, 0x30C3, 0x8363, 0x30C4, 0x8364, 0x30C5, 0x8365, 0x30C6, 0x8366, 0x30C7, 0x8367, 0x30C8, 0x8368, 0x30C9, 0x8369, 0x30CA, 0x836A, 0x30CB, 0x836B, 0x30CC, 0x836C, 0x30CD, 0x836D, 0x30CE, 0x836E, 0x30CF, 0x836F, 0x30D0, 0x8370, 0x30D1, 0x8371, 0x30D2, 0x8372, 0x30D3, 0x8373, 0x30D4, 0x8374, 0x30D5, 0x8375, 0x30D6, 0x8376, 0x30D7, 0x8377, 0x30D8, 0x8378, 0x30D9, 0x8379, 0x30DA, 0x837A, 0x30DB, 0x837B, 0x30DC, 0x837C, 0x30DD, 0x837D, 0x30DE, 0x837E, 0x30DF, 0x8380, 0x30E0, 0x8381, 0x30E1, 0x8382, 0x30E2, 0x8383, 0x30E3, 0x8384, 0x30E4, 0x8385, 0x30E5, 0x8386, 0x30E6, 0x8387, 0x30E7, 0x8388, 0x30E8, 0x8389, 0x30E9, 0x838A, 0x30EA, 0x838B, 0x30EB, 0x838C, 0x30EC, 0x838D, 0x30ED, 0x838E, 0x30EE, 0x838F, 0x30EF, 0x8390, 0x30F0, 0x8391, 0x30F1, 0x8392, 0x30F2, 0x8393, 0x30F3, 0x8394, 0x30F4, 0x8395, 0x30F5, 0x8396, 0x30F6, 0x839F, 0x0391, 0x83A0, 0x0392, 0x83A1, 0x0393, 0x83A2, 0x0394, 0x83A3, 0x0395, 0x83A4, 0x0396, 0x83A5, 0x0397, 0x83A6, 0x0398, 0x83A7, 0x0399, 0x83A8, 0x039A, 0x83A9, 0x039B, 0x83AA, 0x039C, 0x83AB, 0x039D, 0x83AC, 0x039E, 0x83AD, 0x039F, 0x83AE, 0x03A0, 0x83AF, 0x03A1, 0x83B0, 0x03A3, 0x83B1, 0x03A4, 0x83B2, 0x03A5, 0x83B3, 0x03A6, 0x83B4, 0x03A7, 0x83B5, 0x03A8, 0x83B6, 0x03A9, 0x83BF, 0x03B1, 0x83C0, 0x03B2, 0x83C1, 0x03B3, 0x83C2, 0x03B4, 0x83C3, 0x03B5, 0x83C4, 0x03B6, 0x83C5, 0x03B7, 0x83C6, 0x03B8, 0x83C7, 0x03B9, 0x83C8, 0x03BA, 0x83C9, 0x03BB, 0x83CA, 0x03BC, 0x83CB, 0x03BD, 0x83CC, 0x03BE, 0x83CD, 0x03BF, 0x83CE, 0x03C0, 0x83CF, 0x03C1, 0x83D0, 0x03C3, 0x83D1, 0x03C4, 0x83D2, 0x03C5, 0x83D3, 0x03C6, 0x83D4, 0x03C7, 0x83D5, 0x03C8, 0x83D6, 0x03C9, 0x8440, 0x0410, 0x8441, 0x0411, 0x8442, 0x0412, 0x8443, 0x0413, 0x8444, 0x0414, 0x8445, 0x0415, 0x8446, 0x0401, 0x8447, 0x0416, 0x8448, 0x0417, 0x8449, 0x0418, 0x844A, 0x0419, 0x844B, 0x041A, 0x844C, 0x041B, 0x844D, 0x041C, 0x844E, 0x041D, 0x844F, 0x041E, 0x8450, 0x041F, 0x8451, 0x0420, 0x8452, 0x0421, 0x8453, 0x0422, 0x8454, 0x0423, 0x8455, 0x0424, 0x8456, 0x0425, 0x8457, 0x0426, 0x8458, 0x0427, 0x8459, 0x0428, 0x845A, 0x0429, 0x845B, 0x042A, 0x845C, 0x042B, 0x845D, 0x042C, 0x845E, 0x042D, 0x845F, 0x042E, 0x8460, 0x042F, 0x8470, 0x0430, 0x8471, 0x0431, 0x8472, 0x0432, 0x8473, 0x0433, 0x8474, 0x0434, 0x8475, 0x0435, 0x8476, 0x0451, 0x8477, 0x0436, 0x8478, 0x0437, 0x8479, 0x0438, 0x847A, 0x0439, 0x847B, 0x043A, 0x847C, 0x043B, 0x847D, 0x043C, 0x847E, 0x043D, 0x8480, 0x043E, 0x8481, 0x043F, 0x8482, 0x0440, 0x8483, 0x0441, 0x8484, 0x0442, 0x8485, 0x0443, 0x8486, 0x0444, 0x8487, 0x0445, 0x8488, 0x0446, 0x8489, 0x0447, 0x848A, 0x0448, 0x848B, 0x0449, 0x848C, 0x044A, 0x848D, 0x044B, 0x848E, 0x044C, 0x848F, 0x044D, 0x8490, 0x044E, 0x8491, 0x044F, 0x849F, 0x2500, 0x84A0, 0x2502, 0x84A1, 0x250C, 0x84A2, 0x2510, 0x84A3, 0x2518, 0x84A4, 0x2514, 0x84A5, 0x251C, 0x84A6, 0x252C, 0x84A7, 0x2524, 0x84A8, 0x2534, 0x84A9, 0x253C, 0x84AA, 0x2501, 0x84AB, 0x2503, 0x84AC, 0x250F, 0x84AD, 0x2513, 0x84AE, 0x251B, 0x84AF, 0x2517, 0x84B0, 0x2523, 0x84B1, 0x2533, 0x84B2, 0x252B, 0x84B3, 0x253B, 0x84B4, 0x254B, 0x84B5, 0x2520, 0x84B6, 0x252F, 0x84B7, 0x2528, 0x84B8, 0x2537, 0x84B9, 0x253F, 0x84BA, 0x251D, 0x84BB, 0x2530, 0x84BC, 0x2525, 0x84BD, 0x2538, 0x84BE, 0x2542, 0x8740, 0x2460, 0x8741, 0x2461, 0x8742, 0x2462, 0x8743, 0x2463, 0x8744, 0x2464, 0x8745, 0x2465, 0x8746, 0x2466, 0x8747, 0x2467, 0x8748, 0x2468, 0x8749, 0x2469, 0x874A, 0x246A, 0x874B, 0x246B, 0x874C, 0x246C, 0x874D, 0x246D, 0x874E, 0x246E, 0x874F, 0x246F, 0x8750, 0x2470, 0x8751, 0x2471, 0x8752, 0x2472, 0x8753, 0x2473, 0x8754, 0x2160, 0x8755, 0x2161, 0x8756, 0x2162, 0x8757, 0x2163, 0x8758, 0x2164, 0x8759, 0x2165, 0x875A, 0x2166, 0x875B, 0x2167, 0x875C, 0x2168, 0x875D, 0x2169, 0x875F, 0x3349, 0x8760, 0x3314, 0x8761, 0x3322, 0x8762, 0x334D, 0x8763, 0x3318, 0x8764, 0x3327, 0x8765, 0x3303, 0x8766, 0x3336, 0x8767, 0x3351, 0x8768, 0x3357, 0x8769, 0x330D, 0x876A, 0x3326, 0x876B, 0x3323, 0x876C, 0x332B, 0x876D, 0x334A, 0x876E, 0x333B, 0x876F, 0x339C, 0x8770, 0x339D, 0x8771, 0x339E, 0x8772, 0x338E, 0x8773, 0x338F, 0x8774, 0x33C4, 0x8775, 0x33A1, 0x877E, 0x337B, 0x8780, 0x301D, 0x8781, 0x301F, 0x8782, 0x2116, 0x8783, 0x33CD, 0x8784, 0x2121, 0x8785, 0x32A4, 0x8786, 0x32A5, 0x8787, 0x32A6, 0x8788, 0x32A7, 0x8789, 0x32A8, 0x878A, 0x3231, 0x878B, 0x3232, 0x878C, 0x3239, 0x878D, 0x337E, 0x878E, 0x337D, 0x878F, 0x337C, 0x8793, 0x222E, 0x8794, 0x2211, 0x8798, 0x221F, 0x8799, 0x22BF, 0x889F, 0x4E9C, 0x88A0, 0x5516, 0x88A1, 0x5A03, 0x88A2, 0x963F, 0x88A3, 0x54C0, 0x88A4, 0x611B, 0x88A5, 0x6328, 0x88A6, 0x59F6, 0x88A7, 0x9022, 0x88A8, 0x8475, 0x88A9, 0x831C, 0x88AA, 0x7A50, 0x88AB, 0x60AA, 0x88AC, 0x63E1, 0x88AD, 0x6E25, 0x88AE, 0x65ED, 0x88AF, 0x8466, 0x88B0, 0x82A6, 0x88B1, 0x9BF5, 0x88B2, 0x6893, 0x88B3, 0x5727, 0x88B4, 0x65A1, 0x88B5, 0x6271, 0x88B6, 0x5B9B, 0x88B7, 0x59D0, 0x88B8, 0x867B, 0x88B9, 0x98F4, 0x88BA, 0x7D62, 0x88BB, 0x7DBE, 0x88BC, 0x9B8E, 0x88BD, 0x6216, 0x88BE, 0x7C9F, 0x88BF, 0x88B7, 0x88C0, 0x5B89, 0x88C1, 0x5EB5, 0x88C2, 0x6309, 0x88C3, 0x6697, 0x88C4, 0x6848, 0x88C5, 0x95C7, 0x88C6, 0x978D, 0x88C7, 0x674F, 0x88C8, 0x4EE5, 0x88C9, 0x4F0A, 0x88CA, 0x4F4D, 0x88CB, 0x4F9D, 0x88CC, 0x5049, 0x88CD, 0x56F2, 0x88CE, 0x5937, 0x88CF, 0x59D4, 0x88D0, 0x5A01, 0x88D1, 0x5C09, 0x88D2, 0x60DF, 0x88D3, 0x610F, 0x88D4, 0x6170, 0x88D5, 0x6613, 0x88D6, 0x6905, 0x88D7, 0x70BA, 0x88D8, 0x754F, 0x88D9, 0x7570, 0x88DA, 0x79FB, 0x88DB, 0x7DAD, 0x88DC, 0x7DEF, 0x88DD, 0x80C3, 0x88DE, 0x840E, 0x88DF, 0x8863, 0x88E0, 0x8B02, 0x88E1, 0x9055, 0x88E2, 0x907A, 0x88E3, 0x533B, 0x88E4, 0x4E95, 0x88E5, 0x4EA5, 0x88E6, 0x57DF, 0x88E7, 0x80B2, 0x88E8, 0x90C1, 0x88E9, 0x78EF, 0x88EA, 0x4E00, 0x88EB, 0x58F1, 0x88EC, 0x6EA2, 0x88ED, 0x9038, 0x88EE, 0x7A32, 0x88EF, 0x8328, 0x88F0, 0x828B, 0x88F1, 0x9C2F, 0x88F2, 0x5141, 0x88F3, 0x5370, 0x88F4, 0x54BD, 0x88F5, 0x54E1, 0x88F6, 0x56E0, 0x88F7, 0x59FB, 0x88F8, 0x5F15, 0x88F9, 0x98F2, 0x88FA, 0x6DEB, 0x88FB, 0x80E4, 0x88FC, 0x852D, 0x8940, 0x9662, 0x8941, 0x9670, 0x8942, 0x96A0, 0x8943, 0x97FB, 0x8944, 0x540B, 0x8945, 0x53F3, 0x8946, 0x5B87, 0x8947, 0x70CF, 0x8948, 0x7FBD, 0x8949, 0x8FC2, 0x894A, 0x96E8, 0x894B, 0x536F, 0x894C, 0x9D5C, 0x894D, 0x7ABA, 0x894E, 0x4E11, 0x894F, 0x7893, 0x8950, 0x81FC, 0x8951, 0x6E26, 0x8952, 0x5618, 0x8953, 0x5504, 0x8954, 0x6B1D, 0x8955, 0x851A, 0x8956, 0x9C3B, 0x8957, 0x59E5, 0x8958, 0x53A9, 0x8959, 0x6D66, 0x895A, 0x74DC, 0x895B, 0x958F, 0x895C, 0x5642, 0x895D, 0x4E91, 0x895E, 0x904B, 0x895F, 0x96F2, 0x8960, 0x834F, 0x8961, 0x990C, 0x8962, 0x53E1, 0x8963, 0x55B6, 0x8964, 0x5B30, 0x8965, 0x5F71, 0x8966, 0x6620, 0x8967, 0x66F3, 0x8968, 0x6804, 0x8969, 0x6C38, 0x896A, 0x6CF3, 0x896B, 0x6D29, 0x896C, 0x745B, 0x896D, 0x76C8, 0x896E, 0x7A4E, 0x896F, 0x9834, 0x8970, 0x82F1, 0x8971, 0x885B, 0x8972, 0x8A60, 0x8973, 0x92ED, 0x8974, 0x6DB2, 0x8975, 0x75AB, 0x8976, 0x76CA, 0x8977, 0x99C5, 0x8978, 0x60A6, 0x8979, 0x8B01, 0x897A, 0x8D8A, 0x897B, 0x95B2, 0x897C, 0x698E, 0x897D, 0x53AD, 0x897E, 0x5186, 0x8980, 0x5712, 0x8981, 0x5830, 0x8982, 0x5944, 0x8983, 0x5BB4, 0x8984, 0x5EF6, 0x8985, 0x6028, 0x8986, 0x63A9, 0x8987, 0x63F4, 0x8988, 0x6CBF, 0x8989, 0x6F14, 0x898A, 0x708E, 0x898B, 0x7114, 0x898C, 0x7159, 0x898D, 0x71D5, 0x898E, 0x733F, 0x898F, 0x7E01, 0x8990, 0x8276, 0x8991, 0x82D1, 0x8992, 0x8597, 0x8993, 0x9060, 0x8994, 0x925B, 0x8995, 0x9D1B, 0x8996, 0x5869, 0x8997, 0x65BC, 0x8998, 0x6C5A, 0x8999, 0x7525, 0x899A, 0x51F9, 0x899B, 0x592E, 0x899C, 0x5965, 0x899D, 0x5F80, 0x899E, 0x5FDC, 0x899F, 0x62BC, 0x89A0, 0x65FA, 0x89A1, 0x6A2A, 0x89A2, 0x6B27, 0x89A3, 0x6BB4, 0x89A4, 0x738B, 0x89A5, 0x7FC1, 0x89A6, 0x8956, 0x89A7, 0x9D2C, 0x89A8, 0x9D0E, 0x89A9, 0x9EC4, 0x89AA, 0x5CA1, 0x89AB, 0x6C96, 0x89AC, 0x837B, 0x89AD, 0x5104, 0x89AE, 0x5C4B, 0x89AF, 0x61B6, 0x89B0, 0x81C6, 0x89B1, 0x6876, 0x89B2, 0x7261, 0x89B3, 0x4E59, 0x89B4, 0x4FFA, 0x89B5, 0x5378, 0x89B6, 0x6069, 0x89B7, 0x6E29, 0x89B8, 0x7A4F, 0x89B9, 0x97F3, 0x89BA, 0x4E0B, 0x89BB, 0x5316, 0x89BC, 0x4EEE, 0x89BD, 0x4F55, 0x89BE, 0x4F3D, 0x89BF, 0x4FA1, 0x89C0, 0x4F73, 0x89C1, 0x52A0, 0x89C2, 0x53EF, 0x89C3, 0x5609, 0x89C4, 0x590F, 0x89C5, 0x5AC1, 0x89C6, 0x5BB6, 0x89C7, 0x5BE1, 0x89C8, 0x79D1, 0x89C9, 0x6687, 0x89CA, 0x679C, 0x89CB, 0x67B6, 0x89CC, 0x6B4C, 0x89CD, 0x6CB3, 0x89CE, 0x706B, 0x89CF, 0x73C2, 0x89D0, 0x798D, 0x89D1, 0x79BE, 0x89D2, 0x7A3C, 0x89D3, 0x7B87, 0x89D4, 0x82B1, 0x89D5, 0x82DB, 0x89D6, 0x8304, 0x89D7, 0x8377, 0x89D8, 0x83EF, 0x89D9, 0x83D3, 0x89DA, 0x8766, 0x89DB, 0x8AB2, 0x89DC, 0x5629, 0x89DD, 0x8CA8, 0x89DE, 0x8FE6, 0x89DF, 0x904E, 0x89E0, 0x971E, 0x89E1, 0x868A, 0x89E2, 0x4FC4, 0x89E3, 0x5CE8, 0x89E4, 0x6211, 0x89E5, 0x7259, 0x89E6, 0x753B, 0x89E7, 0x81E5, 0x89E8, 0x82BD, 0x89E9, 0x86FE, 0x89EA, 0x8CC0, 0x89EB, 0x96C5, 0x89EC, 0x9913, 0x89ED, 0x99D5, 0x89EE, 0x4ECB, 0x89EF, 0x4F1A, 0x89F0, 0x89E3, 0x89F1, 0x56DE, 0x89F2, 0x584A, 0x89F3, 0x58CA, 0x89F4, 0x5EFB, 0x89F5, 0x5FEB, 0x89F6, 0x602A, 0x89F7, 0x6094, 0x89F8, 0x6062, 0x89F9, 0x61D0, 0x89FA, 0x6212, 0x89FB, 0x62D0, 0x89FC, 0x6539, 0x8A40, 0x9B41, 0x8A41, 0x6666, 0x8A42, 0x68B0, 0x8A43, 0x6D77, 0x8A44, 0x7070, 0x8A45, 0x754C, 0x8A46, 0x7686, 0x8A47, 0x7D75, 0x8A48, 0x82A5, 0x8A49, 0x87F9, 0x8A4A, 0x958B, 0x8A4B, 0x968E, 0x8A4C, 0x8C9D, 0x8A4D, 0x51F1, 0x8A4E, 0x52BE, 0x8A4F, 0x5916, 0x8A50, 0x54B3, 0x8A51, 0x5BB3, 0x8A52, 0x5D16, 0x8A53, 0x6168, 0x8A54, 0x6982, 0x8A55, 0x6DAF, 0x8A56, 0x788D, 0x8A57, 0x84CB, 0x8A58, 0x8857, 0x8A59, 0x8A72, 0x8A5A, 0x93A7, 0x8A5B, 0x9AB8, 0x8A5C, 0x6D6C, 0x8A5D, 0x99A8, 0x8A5E, 0x86D9, 0x8A5F, 0x57A3, 0x8A60, 0x67FF, 0x8A61, 0x86CE, 0x8A62, 0x920E, 0x8A63, 0x5283, 0x8A64, 0x5687, 0x8A65, 0x5404, 0x8A66, 0x5ED3, 0x8A67, 0x62E1, 0x8A68, 0x64B9, 0x8A69, 0x683C, 0x8A6A, 0x6838, 0x8A6B, 0x6BBB, 0x8A6C, 0x7372, 0x8A6D, 0x78BA, 0x8A6E, 0x7A6B, 0x8A6F, 0x899A, 0x8A70, 0x89D2, 0x8A71, 0x8D6B, 0x8A72, 0x8F03, 0x8A73, 0x90ED, 0x8A74, 0x95A3, 0x8A75, 0x9694, 0x8A76, 0x9769, 0x8A77, 0x5B66, 0x8A78, 0x5CB3, 0x8A79, 0x697D, 0x8A7A, 0x984D, 0x8A7B, 0x984E, 0x8A7C, 0x639B, 0x8A7D, 0x7B20, 0x8A7E, 0x6A2B, 0x8A80, 0x6A7F, 0x8A81, 0x68B6, 0x8A82, 0x9C0D, 0x8A83, 0x6F5F, 0x8A84, 0x5272, 0x8A85, 0x559D, 0x8A86, 0x6070, 0x8A87, 0x62EC, 0x8A88, 0x6D3B, 0x8A89, 0x6E07, 0x8A8A, 0x6ED1, 0x8A8B, 0x845B, 0x8A8C, 0x8910, 0x8A8D, 0x8F44, 0x8A8E, 0x4E14, 0x8A8F, 0x9C39, 0x8A90, 0x53F6, 0x8A91, 0x691B, 0x8A92, 0x6A3A, 0x8A93, 0x9784, 0x8A94, 0x682A, 0x8A95, 0x515C, 0x8A96, 0x7AC3, 0x8A97, 0x84B2, 0x8A98, 0x91DC, 0x8A99, 0x938C, 0x8A9A, 0x565B, 0x8A9B, 0x9D28, 0x8A9C, 0x6822, 0x8A9D, 0x8305, 0x8A9E, 0x8431, 0x8A9F, 0x7CA5, 0x8AA0, 0x5208, 0x8AA1, 0x82C5, 0x8AA2, 0x74E6, 0x8AA3, 0x4E7E, 0x8AA4, 0x4F83, 0x8AA5, 0x51A0, 0x8AA6, 0x5BD2, 0x8AA7, 0x520A, 0x8AA8, 0x52D8, 0x8AA9, 0x52E7, 0x8AAA, 0x5DFB, 0x8AAB, 0x559A, 0x8AAC, 0x582A, 0x8AAD, 0x59E6, 0x8AAE, 0x5B8C, 0x8AAF, 0x5B98, 0x8AB0, 0x5BDB, 0x8AB1, 0x5E72, 0x8AB2, 0x5E79, 0x8AB3, 0x60A3, 0x8AB4, 0x611F, 0x8AB5, 0x6163, 0x8AB6, 0x61BE, 0x8AB7, 0x63DB, 0x8AB8, 0x6562, 0x8AB9, 0x67D1, 0x8ABA, 0x6853, 0x8ABB, 0x68FA, 0x8ABC, 0x6B3E, 0x8ABD, 0x6B53, 0x8ABE, 0x6C57, 0x8ABF, 0x6F22, 0x8AC0, 0x6F97, 0x8AC1, 0x6F45, 0x8AC2, 0x74B0, 0x8AC3, 0x7518, 0x8AC4, 0x76E3, 0x8AC5, 0x770B, 0x8AC6, 0x7AFF, 0x8AC7, 0x7BA1, 0x8AC8, 0x7C21, 0x8AC9, 0x7DE9, 0x8ACA, 0x7F36, 0x8ACB, 0x7FF0, 0x8ACC, 0x809D, 0x8ACD, 0x8266, 0x8ACE, 0x839E, 0x8ACF, 0x89B3, 0x8AD0, 0x8ACC, 0x8AD1, 0x8CAB, 0x8AD2, 0x9084, 0x8AD3, 0x9451, 0x8AD4, 0x9593, 0x8AD5, 0x9591, 0x8AD6, 0x95A2, 0x8AD7, 0x9665, 0x8AD8, 0x97D3, 0x8AD9, 0x9928, 0x8ADA, 0x8218, 0x8ADB, 0x4E38, 0x8ADC, 0x542B, 0x8ADD, 0x5CB8, 0x8ADE, 0x5DCC, 0x8ADF, 0x73A9, 0x8AE0, 0x764C, 0x8AE1, 0x773C, 0x8AE2, 0x5CA9, 0x8AE3, 0x7FEB, 0x8AE4, 0x8D0B, 0x8AE5, 0x96C1, 0x8AE6, 0x9811, 0x8AE7, 0x9854, 0x8AE8, 0x9858, 0x8AE9, 0x4F01, 0x8AEA, 0x4F0E, 0x8AEB, 0x5371, 0x8AEC, 0x559C, 0x8AED, 0x5668, 0x8AEE, 0x57FA, 0x8AEF, 0x5947, 0x8AF0, 0x5B09, 0x8AF1, 0x5BC4, 0x8AF2, 0x5C90, 0x8AF3, 0x5E0C, 0x8AF4, 0x5E7E, 0x8AF5, 0x5FCC, 0x8AF6, 0x63EE, 0x8AF7, 0x673A, 0x8AF8, 0x65D7, 0x8AF9, 0x65E2, 0x8AFA, 0x671F, 0x8AFB, 0x68CB, 0x8AFC, 0x68C4, 0x8B40, 0x6A5F, 0x8B41, 0x5E30, 0x8B42, 0x6BC5, 0x8B43, 0x6C17, 0x8B44, 0x6C7D, 0x8B45, 0x757F, 0x8B46, 0x7948, 0x8B47, 0x5B63, 0x8B48, 0x7A00, 0x8B49, 0x7D00, 0x8B4A, 0x5FBD, 0x8B4B, 0x898F, 0x8B4C, 0x8A18, 0x8B4D, 0x8CB4, 0x8B4E, 0x8D77, 0x8B4F, 0x8ECC, 0x8B50, 0x8F1D, 0x8B51, 0x98E2, 0x8B52, 0x9A0E, 0x8B53, 0x9B3C, 0x8B54, 0x4E80, 0x8B55, 0x507D, 0x8B56, 0x5100, 0x8B57, 0x5993, 0x8B58, 0x5B9C, 0x8B59, 0x622F, 0x8B5A, 0x6280, 0x8B5B, 0x64EC, 0x8B5C, 0x6B3A, 0x8B5D, 0x72A0, 0x8B5E, 0x7591, 0x8B5F, 0x7947, 0x8B60, 0x7FA9, 0x8B61, 0x87FB, 0x8B62, 0x8ABC, 0x8B63, 0x8B70, 0x8B64, 0x63AC, 0x8B65, 0x83CA, 0x8B66, 0x97A0, 0x8B67, 0x5409, 0x8B68, 0x5403, 0x8B69, 0x55AB, 0x8B6A, 0x6854, 0x8B6B, 0x6A58, 0x8B6C, 0x8A70, 0x8B6D, 0x7827, 0x8B6E, 0x6775, 0x8B6F, 0x9ECD, 0x8B70, 0x5374, 0x8B71, 0x5BA2, 0x8B72, 0x811A, 0x8B73, 0x8650, 0x8B74, 0x9006, 0x8B75, 0x4E18, 0x8B76, 0x4E45, 0x8B77, 0x4EC7, 0x8B78, 0x4F11, 0x8B79, 0x53CA, 0x8B7A, 0x5438, 0x8B7B, 0x5BAE, 0x8B7C, 0x5F13, 0x8B7D, 0x6025, 0x8B7E, 0x6551, 0x8B80, 0x673D, 0x8B81, 0x6C42, 0x8B82, 0x6C72, 0x8B83, 0x6CE3, 0x8B84, 0x7078, 0x8B85, 0x7403, 0x8B86, 0x7A76, 0x8B87, 0x7AAE, 0x8B88, 0x7B08, 0x8B89, 0x7D1A, 0x8B8A, 0x7CFE, 0x8B8B, 0x7D66, 0x8B8C, 0x65E7, 0x8B8D, 0x725B, 0x8B8E, 0x53BB, 0x8B8F, 0x5C45, 0x8B90, 0x5DE8, 0x8B91, 0x62D2, 0x8B92, 0x62E0, 0x8B93, 0x6319, 0x8B94, 0x6E20, 0x8B95, 0x865A, 0x8B96, 0x8A31, 0x8B97, 0x8DDD, 0x8B98, 0x92F8, 0x8B99, 0x6F01, 0x8B9A, 0x79A6, 0x8B9B, 0x9B5A, 0x8B9C, 0x4EA8, 0x8B9D, 0x4EAB, 0x8B9E, 0x4EAC, 0x8B9F, 0x4F9B, 0x8BA0, 0x4FA0, 0x8BA1, 0x50D1, 0x8BA2, 0x5147, 0x8BA3, 0x7AF6, 0x8BA4, 0x5171, 0x8BA5, 0x51F6, 0x8BA6, 0x5354, 0x8BA7, 0x5321, 0x8BA8, 0x537F, 0x8BA9, 0x53EB, 0x8BAA, 0x55AC, 0x8BAB, 0x5883, 0x8BAC, 0x5CE1, 0x8BAD, 0x5F37, 0x8BAE, 0x5F4A, 0x8BAF, 0x602F, 0x8BB0, 0x6050, 0x8BB1, 0x606D, 0x8BB2, 0x631F, 0x8BB3, 0x6559, 0x8BB4, 0x6A4B, 0x8BB5, 0x6CC1, 0x8BB6, 0x72C2, 0x8BB7, 0x72ED, 0x8BB8, 0x77EF, 0x8BB9, 0x80F8, 0x8BBA, 0x8105, 0x8BBB, 0x8208, 0x8BBC, 0x854E, 0x8BBD, 0x90F7, 0x8BBE, 0x93E1, 0x8BBF, 0x97FF, 0x8BC0, 0x9957, 0x8BC1, 0x9A5A, 0x8BC2, 0x4EF0, 0x8BC3, 0x51DD, 0x8BC4, 0x5C2D, 0x8BC5, 0x6681, 0x8BC6, 0x696D, 0x8BC7, 0x5C40, 0x8BC8, 0x66F2, 0x8BC9, 0x6975, 0x8BCA, 0x7389, 0x8BCB, 0x6850, 0x8BCC, 0x7C81, 0x8BCD, 0x50C5, 0x8BCE, 0x52E4, 0x8BCF, 0x5747, 0x8BD0, 0x5DFE, 0x8BD1, 0x9326, 0x8BD2, 0x65A4, 0x8BD3, 0x6B23, 0x8BD4, 0x6B3D, 0x8BD5, 0x7434, 0x8BD6, 0x7981, 0x8BD7, 0x79BD, 0x8BD8, 0x7B4B, 0x8BD9, 0x7DCA, 0x8BDA, 0x82B9, 0x8BDB, 0x83CC, 0x8BDC, 0x887F, 0x8BDD, 0x895F, 0x8BDE, 0x8B39, 0x8BDF, 0x8FD1, 0x8BE0, 0x91D1, 0x8BE1, 0x541F, 0x8BE2, 0x9280, 0x8BE3, 0x4E5D, 0x8BE4, 0x5036, 0x8BE5, 0x53E5, 0x8BE6, 0x533A, 0x8BE7, 0x72D7, 0x8BE8, 0x7396, 0x8BE9, 0x77E9, 0x8BEA, 0x82E6, 0x8BEB, 0x8EAF, 0x8BEC, 0x99C6, 0x8BED, 0x99C8, 0x8BEE, 0x99D2, 0x8BEF, 0x5177, 0x8BF0, 0x611A, 0x8BF1, 0x865E, 0x8BF2, 0x55B0, 0x8BF3, 0x7A7A, 0x8BF4, 0x5076, 0x8BF5, 0x5BD3, 0x8BF6, 0x9047, 0x8BF7, 0x9685, 0x8BF8, 0x4E32, 0x8BF9, 0x6ADB, 0x8BFA, 0x91E7, 0x8BFB, 0x5C51, 0x8BFC, 0x5C48, 0x8C40, 0x6398, 0x8C41, 0x7A9F, 0x8C42, 0x6C93, 0x8C43, 0x9774, 0x8C44, 0x8F61, 0x8C45, 0x7AAA, 0x8C46, 0x718A, 0x8C47, 0x9688, 0x8C48, 0x7C82, 0x8C49, 0x6817, 0x8C4A, 0x7E70, 0x8C4B, 0x6851, 0x8C4C, 0x936C, 0x8C4D, 0x52F2, 0x8C4E, 0x541B, 0x8C4F, 0x85AB, 0x8C50, 0x8A13, 0x8C51, 0x7FA4, 0x8C52, 0x8ECD, 0x8C53, 0x90E1, 0x8C54, 0x5366, 0x8C55, 0x8888, 0x8C56, 0x7941, 0x8C57, 0x4FC2, 0x8C58, 0x50BE, 0x8C59, 0x5211, 0x8C5A, 0x5144, 0x8C5B, 0x5553, 0x8C5C, 0x572D, 0x8C5D, 0x73EA, 0x8C5E, 0x578B, 0x8C5F, 0x5951, 0x8C60, 0x5F62, 0x8C61, 0x5F84, 0x8C62, 0x6075, 0x8C63, 0x6176, 0x8C64, 0x6167, 0x8C65, 0x61A9, 0x8C66, 0x63B2, 0x8C67, 0x643A, 0x8C68, 0x656C, 0x8C69, 0x666F, 0x8C6A, 0x6842, 0x8C6B, 0x6E13, 0x8C6C, 0x7566, 0x8C6D, 0x7A3D, 0x8C6E, 0x7CFB, 0x8C6F, 0x7D4C, 0x8C70, 0x7D99, 0x8C71, 0x7E4B, 0x8C72, 0x7F6B, 0x8C73, 0x830E, 0x8C74, 0x834A, 0x8C75, 0x86CD, 0x8C76, 0x8A08, 0x8C77, 0x8A63, 0x8C78, 0x8B66, 0x8C79, 0x8EFD, 0x8C7A, 0x981A, 0x8C7B, 0x9D8F, 0x8C7C, 0x82B8, 0x8C7D, 0x8FCE, 0x8C7E, 0x9BE8, 0x8C80, 0x5287, 0x8C81, 0x621F, 0x8C82, 0x6483, 0x8C83, 0x6FC0, 0x8C84, 0x9699, 0x8C85, 0x6841, 0x8C86, 0x5091, 0x8C87, 0x6B20, 0x8C88, 0x6C7A, 0x8C89, 0x6F54, 0x8C8A, 0x7A74, 0x8C8B, 0x7D50, 0x8C8C, 0x8840, 0x8C8D, 0x8A23, 0x8C8E, 0x6708, 0x8C8F, 0x4EF6, 0x8C90, 0x5039, 0x8C91, 0x5026, 0x8C92, 0x5065, 0x8C93, 0x517C, 0x8C94, 0x5238, 0x8C95, 0x5263, 0x8C96, 0x55A7, 0x8C97, 0x570F, 0x8C98, 0x5805, 0x8C99, 0x5ACC, 0x8C9A, 0x5EFA, 0x8C9B, 0x61B2, 0x8C9C, 0x61F8, 0x8C9D, 0x62F3, 0x8C9E, 0x6372, 0x8C9F, 0x691C, 0x8CA0, 0x6A29, 0x8CA1, 0x727D, 0x8CA2, 0x72AC, 0x8CA3, 0x732E, 0x8CA4, 0x7814, 0x8CA5, 0x786F, 0x8CA6, 0x7D79, 0x8CA7, 0x770C, 0x8CA8, 0x80A9, 0x8CA9, 0x898B, 0x8CAA, 0x8B19, 0x8CAB, 0x8CE2, 0x8CAC, 0x8ED2, 0x8CAD, 0x9063, 0x8CAE, 0x9375, 0x8CAF, 0x967A, 0x8CB0, 0x9855, 0x8CB1, 0x9A13, 0x8CB2, 0x9E78, 0x8CB3, 0x5143, 0x8CB4, 0x539F, 0x8CB5, 0x53B3, 0x8CB6, 0x5E7B, 0x8CB7, 0x5F26, 0x8CB8, 0x6E1B, 0x8CB9, 0x6E90, 0x8CBA, 0x7384, 0x8CBB, 0x73FE, 0x8CBC, 0x7D43, 0x8CBD, 0x8237, 0x8CBE, 0x8A00, 0x8CBF, 0x8AFA, 0x8CC0, 0x9650, 0x8CC1, 0x4E4E, 0x8CC2, 0x500B, 0x8CC3, 0x53E4, 0x8CC4, 0x547C, 0x8CC5, 0x56FA, 0x8CC6, 0x59D1, 0x8CC7, 0x5B64, 0x8CC8, 0x5DF1, 0x8CC9, 0x5EAB, 0x8CCA, 0x5F27, 0x8CCB, 0x6238, 0x8CCC, 0x6545, 0x8CCD, 0x67AF, 0x8CCE, 0x6E56, 0x8CCF, 0x72D0, 0x8CD0, 0x7CCA, 0x8CD1, 0x88B4, 0x8CD2, 0x80A1, 0x8CD3, 0x80E1, 0x8CD4, 0x83F0, 0x8CD5, 0x864E, 0x8CD6, 0x8A87, 0x8CD7, 0x8DE8, 0x8CD8, 0x9237, 0x8CD9, 0x96C7, 0x8CDA, 0x9867, 0x8CDB, 0x9F13, 0x8CDC, 0x4E94, 0x8CDD, 0x4E92, 0x8CDE, 0x4F0D, 0x8CDF, 0x5348, 0x8CE0, 0x5449, 0x8CE1, 0x543E, 0x8CE2, 0x5A2F, 0x8CE3, 0x5F8C, 0x8CE4, 0x5FA1, 0x8CE5, 0x609F, 0x8CE6, 0x68A7, 0x8CE7, 0x6A8E, 0x8CE8, 0x745A, 0x8CE9, 0x7881, 0x8CEA, 0x8A9E, 0x8CEB, 0x8AA4, 0x8CEC, 0x8B77, 0x8CED, 0x9190, 0x8CEE, 0x4E5E, 0x8CEF, 0x9BC9, 0x8CF0, 0x4EA4, 0x8CF1, 0x4F7C, 0x8CF2, 0x4FAF, 0x8CF3, 0x5019, 0x8CF4, 0x5016, 0x8CF5, 0x5149, 0x8CF6, 0x516C, 0x8CF7, 0x529F, 0x8CF8, 0x52B9, 0x8CF9, 0x52FE, 0x8CFA, 0x539A, 0x8CFB, 0x53E3, 0x8CFC, 0x5411, 0x8D40, 0x540E, 0x8D41, 0x5589, 0x8D42, 0x5751, 0x8D43, 0x57A2, 0x8D44, 0x597D, 0x8D45, 0x5B54, 0x8D46, 0x5B5D, 0x8D47, 0x5B8F, 0x8D48, 0x5DE5, 0x8D49, 0x5DE7, 0x8D4A, 0x5DF7, 0x8D4B, 0x5E78, 0x8D4C, 0x5E83, 0x8D4D, 0x5E9A, 0x8D4E, 0x5EB7, 0x8D4F, 0x5F18, 0x8D50, 0x6052, 0x8D51, 0x614C, 0x8D52, 0x6297, 0x8D53, 0x62D8, 0x8D54, 0x63A7, 0x8D55, 0x653B, 0x8D56, 0x6602, 0x8D57, 0x6643, 0x8D58, 0x66F4, 0x8D59, 0x676D, 0x8D5A, 0x6821, 0x8D5B, 0x6897, 0x8D5C, 0x69CB, 0x8D5D, 0x6C5F, 0x8D5E, 0x6D2A, 0x8D5F, 0x6D69, 0x8D60, 0x6E2F, 0x8D61, 0x6E9D, 0x8D62, 0x7532, 0x8D63, 0x7687, 0x8D64, 0x786C, 0x8D65, 0x7A3F, 0x8D66, 0x7CE0, 0x8D67, 0x7D05, 0x8D68, 0x7D18, 0x8D69, 0x7D5E, 0x8D6A, 0x7DB1, 0x8D6B, 0x8015, 0x8D6C, 0x8003, 0x8D6D, 0x80AF, 0x8D6E, 0x80B1, 0x8D6F, 0x8154, 0x8D70, 0x818F, 0x8D71, 0x822A, 0x8D72, 0x8352, 0x8D73, 0x884C, 0x8D74, 0x8861, 0x8D75, 0x8B1B, 0x8D76, 0x8CA2, 0x8D77, 0x8CFC, 0x8D78, 0x90CA, 0x8D79, 0x9175, 0x8D7A, 0x9271, 0x8D7B, 0x783F, 0x8D7C, 0x92FC, 0x8D7D, 0x95A4, 0x8D7E, 0x964D, 0x8D80, 0x9805, 0x8D81, 0x9999, 0x8D82, 0x9AD8, 0x8D83, 0x9D3B, 0x8D84, 0x525B, 0x8D85, 0x52AB, 0x8D86, 0x53F7, 0x8D87, 0x5408, 0x8D88, 0x58D5, 0x8D89, 0x62F7, 0x8D8A, 0x6FE0, 0x8D8B, 0x8C6A, 0x8D8C, 0x8F5F, 0x8D8D, 0x9EB9, 0x8D8E, 0x514B, 0x8D8F, 0x523B, 0x8D90, 0x544A, 0x8D91, 0x56FD, 0x8D92, 0x7A40, 0x8D93, 0x9177, 0x8D94, 0x9D60, 0x8D95, 0x9ED2, 0x8D96, 0x7344, 0x8D97, 0x6F09, 0x8D98, 0x8170, 0x8D99, 0x7511, 0x8D9A, 0x5FFD, 0x8D9B, 0x60DA, 0x8D9C, 0x9AA8, 0x8D9D, 0x72DB, 0x8D9E, 0x8FBC, 0x8D9F, 0x6B64, 0x8DA0, 0x9803, 0x8DA1, 0x4ECA, 0x8DA2, 0x56F0, 0x8DA3, 0x5764, 0x8DA4, 0x58BE, 0x8DA5, 0x5A5A, 0x8DA6, 0x6068, 0x8DA7, 0x61C7, 0x8DA8, 0x660F, 0x8DA9, 0x6606, 0x8DAA, 0x6839, 0x8DAB, 0x68B1, 0x8DAC, 0x6DF7, 0x8DAD, 0x75D5, 0x8DAE, 0x7D3A, 0x8DAF, 0x826E, 0x8DB0, 0x9B42, 0x8DB1, 0x4E9B, 0x8DB2, 0x4F50, 0x8DB3, 0x53C9, 0x8DB4, 0x5506, 0x8DB5, 0x5D6F, 0x8DB6, 0x5DE6, 0x8DB7, 0x5DEE, 0x8DB8, 0x67FB, 0x8DB9, 0x6C99, 0x8DBA, 0x7473, 0x8DBB, 0x7802, 0x8DBC, 0x8A50, 0x8DBD, 0x9396, 0x8DBE, 0x88DF, 0x8DBF, 0x5750, 0x8DC0, 0x5EA7, 0x8DC1, 0x632B, 0x8DC2, 0x50B5, 0x8DC3, 0x50AC, 0x8DC4, 0x518D, 0x8DC5, 0x6700, 0x8DC6, 0x54C9, 0x8DC7, 0x585E, 0x8DC8, 0x59BB, 0x8DC9, 0x5BB0, 0x8DCA, 0x5F69, 0x8DCB, 0x624D, 0x8DCC, 0x63A1, 0x8DCD, 0x683D, 0x8DCE, 0x6B73, 0x8DCF, 0x6E08, 0x8DD0, 0x707D, 0x8DD1, 0x91C7, 0x8DD2, 0x7280, 0x8DD3, 0x7815, 0x8DD4, 0x7826, 0x8DD5, 0x796D, 0x8DD6, 0x658E, 0x8DD7, 0x7D30, 0x8DD8, 0x83DC, 0x8DD9, 0x88C1, 0x8DDA, 0x8F09, 0x8DDB, 0x969B, 0x8DDC, 0x5264, 0x8DDD, 0x5728, 0x8DDE, 0x6750, 0x8DDF, 0x7F6A, 0x8DE0, 0x8CA1, 0x8DE1, 0x51B4, 0x8DE2, 0x5742, 0x8DE3, 0x962A, 0x8DE4, 0x583A, 0x8DE5, 0x698A, 0x8DE6, 0x80B4, 0x8DE7, 0x54B2, 0x8DE8, 0x5D0E, 0x8DE9, 0x57FC, 0x8DEA, 0x7895, 0x8DEB, 0x9DFA, 0x8DEC, 0x4F5C, 0x8DED, 0x524A, 0x8DEE, 0x548B, 0x8DEF, 0x643E, 0x8DF0, 0x6628, 0x8DF1, 0x6714, 0x8DF2, 0x67F5, 0x8DF3, 0x7A84, 0x8DF4, 0x7B56, 0x8DF5, 0x7D22, 0x8DF6, 0x932F, 0x8DF7, 0x685C, 0x8DF8, 0x9BAD, 0x8DF9, 0x7B39, 0x8DFA, 0x5319, 0x8DFB, 0x518A, 0x8DFC, 0x5237, 0x8E40, 0x5BDF, 0x8E41, 0x62F6, 0x8E42, 0x64AE, 0x8E43, 0x64E6, 0x8E44, 0x672D, 0x8E45, 0x6BBA, 0x8E46, 0x85A9, 0x8E47, 0x96D1, 0x8E48, 0x7690, 0x8E49, 0x9BD6, 0x8E4A, 0x634C, 0x8E4B, 0x9306, 0x8E4C, 0x9BAB, 0x8E4D, 0x76BF, 0x8E4E, 0x6652, 0x8E4F, 0x4E09, 0x8E50, 0x5098, 0x8E51, 0x53C2, 0x8E52, 0x5C71, 0x8E53, 0x60E8, 0x8E54, 0x6492, 0x8E55, 0x6563, 0x8E56, 0x685F, 0x8E57, 0x71E6, 0x8E58, 0x73CA, 0x8E59, 0x7523, 0x8E5A, 0x7B97, 0x8E5B, 0x7E82, 0x8E5C, 0x8695, 0x8E5D, 0x8B83, 0x8E5E, 0x8CDB, 0x8E5F, 0x9178, 0x8E60, 0x9910, 0x8E61, 0x65AC, 0x8E62, 0x66AB, 0x8E63, 0x6B8B, 0x8E64, 0x4ED5, 0x8E65, 0x4ED4, 0x8E66, 0x4F3A, 0x8E67, 0x4F7F, 0x8E68, 0x523A, 0x8E69, 0x53F8, 0x8E6A, 0x53F2, 0x8E6B, 0x55E3, 0x8E6C, 0x56DB, 0x8E6D, 0x58EB, 0x8E6E, 0x59CB, 0x8E6F, 0x59C9, 0x8E70, 0x59FF, 0x8E71, 0x5B50, 0x8E72, 0x5C4D, 0x8E73, 0x5E02, 0x8E74, 0x5E2B, 0x8E75, 0x5FD7, 0x8E76, 0x601D, 0x8E77, 0x6307, 0x8E78, 0x652F, 0x8E79, 0x5B5C, 0x8E7A, 0x65AF, 0x8E7B, 0x65BD, 0x8E7C, 0x65E8, 0x8E7D, 0x679D, 0x8E7E, 0x6B62, 0x8E80, 0x6B7B, 0x8E81, 0x6C0F, 0x8E82, 0x7345, 0x8E83, 0x7949, 0x8E84, 0x79C1, 0x8E85, 0x7CF8, 0x8E86, 0x7D19, 0x8E87, 0x7D2B, 0x8E88, 0x80A2, 0x8E89, 0x8102, 0x8E8A, 0x81F3, 0x8E8B, 0x8996, 0x8E8C, 0x8A5E, 0x8E8D, 0x8A69, 0x8E8E, 0x8A66, 0x8E8F, 0x8A8C, 0x8E90, 0x8AEE, 0x8E91, 0x8CC7, 0x8E92, 0x8CDC, 0x8E93, 0x96CC, 0x8E94, 0x98FC, 0x8E95, 0x6B6F, 0x8E96, 0x4E8B, 0x8E97, 0x4F3C, 0x8E98, 0x4F8D, 0x8E99, 0x5150, 0x8E9A, 0x5B57, 0x8E9B, 0x5BFA, 0x8E9C, 0x6148, 0x8E9D, 0x6301, 0x8E9E, 0x6642, 0x8E9F, 0x6B21, 0x8EA0, 0x6ECB, 0x8EA1, 0x6CBB, 0x8EA2, 0x723E, 0x8EA3, 0x74BD, 0x8EA4, 0x75D4, 0x8EA5, 0x78C1, 0x8EA6, 0x793A, 0x8EA7, 0x800C, 0x8EA8, 0x8033, 0x8EA9, 0x81EA, 0x8EAA, 0x8494, 0x8EAB, 0x8F9E, 0x8EAC, 0x6C50, 0x8EAD, 0x9E7F, 0x8EAE, 0x5F0F, 0x8EAF, 0x8B58, 0x8EB0, 0x9D2B, 0x8EB1, 0x7AFA, 0x8EB2, 0x8EF8, 0x8EB3, 0x5B8D, 0x8EB4, 0x96EB, 0x8EB5, 0x4E03, 0x8EB6, 0x53F1, 0x8EB7, 0x57F7, 0x8EB8, 0x5931, 0x8EB9, 0x5AC9, 0x8EBA, 0x5BA4, 0x8EBB, 0x6089, 0x8EBC, 0x6E7F, 0x8EBD, 0x6F06, 0x8EBE, 0x75BE, 0x8EBF, 0x8CEA, 0x8EC0, 0x5B9F, 0x8EC1, 0x8500, 0x8EC2, 0x7BE0, 0x8EC3, 0x5072, 0x8EC4, 0x67F4, 0x8EC5, 0x829D, 0x8EC6, 0x5C61, 0x8EC7, 0x854A, 0x8EC8, 0x7E1E, 0x8EC9, 0x820E, 0x8ECA, 0x5199, 0x8ECB, 0x5C04, 0x8ECC, 0x6368, 0x8ECD, 0x8D66, 0x8ECE, 0x659C, 0x8ECF, 0x716E, 0x8ED0, 0x793E, 0x8ED1, 0x7D17, 0x8ED2, 0x8005, 0x8ED3, 0x8B1D, 0x8ED4, 0x8ECA, 0x8ED5, 0x906E, 0x8ED6, 0x86C7, 0x8ED7, 0x90AA, 0x8ED8, 0x501F, 0x8ED9, 0x52FA, 0x8EDA, 0x5C3A, 0x8EDB, 0x6753, 0x8EDC, 0x707C, 0x8EDD, 0x7235, 0x8EDE, 0x914C, 0x8EDF, 0x91C8, 0x8EE0, 0x932B, 0x8EE1, 0x82E5, 0x8EE2, 0x5BC2, 0x8EE3, 0x5F31, 0x8EE4, 0x60F9, 0x8EE5, 0x4E3B, 0x8EE6, 0x53D6, 0x8EE7, 0x5B88, 0x8EE8, 0x624B, 0x8EE9, 0x6731, 0x8EEA, 0x6B8A, 0x8EEB, 0x72E9, 0x8EEC, 0x73E0, 0x8EED, 0x7A2E, 0x8EEE, 0x816B, 0x8EEF, 0x8DA3, 0x8EF0, 0x9152, 0x8EF1, 0x9996, 0x8EF2, 0x5112, 0x8EF3, 0x53D7, 0x8EF4, 0x546A, 0x8EF5, 0x5BFF, 0x8EF6, 0x6388, 0x8EF7, 0x6A39, 0x8EF8, 0x7DAC, 0x8EF9, 0x9700, 0x8EFA, 0x56DA, 0x8EFB, 0x53CE, 0x8EFC, 0x5468, 0x8F40, 0x5B97, 0x8F41, 0x5C31, 0x8F42, 0x5DDE, 0x8F43, 0x4FEE, 0x8F44, 0x6101, 0x8F45, 0x62FE, 0x8F46, 0x6D32, 0x8F47, 0x79C0, 0x8F48, 0x79CB, 0x8F49, 0x7D42, 0x8F4A, 0x7E4D, 0x8F4B, 0x7FD2, 0x8F4C, 0x81ED, 0x8F4D, 0x821F, 0x8F4E, 0x8490, 0x8F4F, 0x8846, 0x8F50, 0x8972, 0x8F51, 0x8B90, 0x8F52, 0x8E74, 0x8F53, 0x8F2F, 0x8F54, 0x9031, 0x8F55, 0x914B, 0x8F56, 0x916C, 0x8F57, 0x96C6, 0x8F58, 0x919C, 0x8F59, 0x4EC0, 0x8F5A, 0x4F4F, 0x8F5B, 0x5145, 0x8F5C, 0x5341, 0x8F5D, 0x5F93, 0x8F5E, 0x620E, 0x8F5F, 0x67D4, 0x8F60, 0x6C41, 0x8F61, 0x6E0B, 0x8F62, 0x7363, 0x8F63, 0x7E26, 0x8F64, 0x91CD, 0x8F65, 0x9283, 0x8F66, 0x53D4, 0x8F67, 0x5919, 0x8F68, 0x5BBF, 0x8F69, 0x6DD1, 0x8F6A, 0x795D, 0x8F6B, 0x7E2E, 0x8F6C, 0x7C9B, 0x8F6D, 0x587E, 0x8F6E, 0x719F, 0x8F6F, 0x51FA, 0x8F70, 0x8853, 0x8F71, 0x8FF0, 0x8F72, 0x4FCA, 0x8F73, 0x5CFB, 0x8F74, 0x6625, 0x8F75, 0x77AC, 0x8F76, 0x7AE3, 0x8F77, 0x821C, 0x8F78, 0x99FF, 0x8F79, 0x51C6, 0x8F7A, 0x5FAA, 0x8F7B, 0x65EC, 0x8F7C, 0x696F, 0x8F7D, 0x6B89, 0x8F7E, 0x6DF3, 0x8F80, 0x6E96, 0x8F81, 0x6F64, 0x8F82, 0x76FE, 0x8F83, 0x7D14, 0x8F84, 0x5DE1, 0x8F85, 0x9075, 0x8F86, 0x9187, 0x8F87, 0x9806, 0x8F88, 0x51E6, 0x8F89, 0x521D, 0x8F8A, 0x6240, 0x8F8B, 0x6691, 0x8F8C, 0x66D9, 0x8F8D, 0x6E1A, 0x8F8E, 0x5EB6, 0x8F8F, 0x7DD2, 0x8F90, 0x7F72, 0x8F91, 0x66F8, 0x8F92, 0x85AF, 0x8F93, 0x85F7, 0x8F94, 0x8AF8, 0x8F95, 0x52A9, 0x8F96, 0x53D9, 0x8F97, 0x5973, 0x8F98, 0x5E8F, 0x8F99, 0x5F90, 0x8F9A, 0x6055, 0x8F9B, 0x92E4, 0x8F9C, 0x9664, 0x8F9D, 0x50B7, 0x8F9E, 0x511F, 0x8F9F, 0x52DD, 0x8FA0, 0x5320, 0x8FA1, 0x5347, 0x8FA2, 0x53EC, 0x8FA3, 0x54E8, 0x8FA4, 0x5546, 0x8FA5, 0x5531, 0x8FA6, 0x5617, 0x8FA7, 0x5968, 0x8FA8, 0x59BE, 0x8FA9, 0x5A3C, 0x8FAA, 0x5BB5, 0x8FAB, 0x5C06, 0x8FAC, 0x5C0F, 0x8FAD, 0x5C11, 0x8FAE, 0x5C1A, 0x8FAF, 0x5E84, 0x8FB0, 0x5E8A, 0x8FB1, 0x5EE0, 0x8FB2, 0x5F70, 0x8FB3, 0x627F, 0x8FB4, 0x6284, 0x8FB5, 0x62DB, 0x8FB6, 0x638C, 0x8FB7, 0x6377, 0x8FB8, 0x6607, 0x8FB9, 0x660C, 0x8FBA, 0x662D, 0x8FBB, 0x6676, 0x8FBC, 0x677E, 0x8FBD, 0x68A2, 0x8FBE, 0x6A1F, 0x8FBF, 0x6A35, 0x8FC0, 0x6CBC, 0x8FC1, 0x6D88, 0x8FC2, 0x6E09, 0x8FC3, 0x6E58, 0x8FC4, 0x713C, 0x8FC5, 0x7126, 0x8FC6, 0x7167, 0x8FC7, 0x75C7, 0x8FC8, 0x7701, 0x8FC9, 0x785D, 0x8FCA, 0x7901, 0x8FCB, 0x7965, 0x8FCC, 0x79F0, 0x8FCD, 0x7AE0, 0x8FCE, 0x7B11, 0x8FCF, 0x7CA7, 0x8FD0, 0x7D39, 0x8FD1, 0x8096, 0x8FD2, 0x83D6, 0x8FD3, 0x848B, 0x8FD4, 0x8549, 0x8FD5, 0x885D, 0x8FD6, 0x88F3, 0x8FD7, 0x8A1F, 0x8FD8, 0x8A3C, 0x8FD9, 0x8A54, 0x8FDA, 0x8A73, 0x8FDB, 0x8C61, 0x8FDC, 0x8CDE, 0x8FDD, 0x91A4, 0x8FDE, 0x9266, 0x8FDF, 0x937E, 0x8FE0, 0x9418, 0x8FE1, 0x969C, 0x8FE2, 0x9798, 0x8FE3, 0x4E0A, 0x8FE4, 0x4E08, 0x8FE5, 0x4E1E, 0x8FE6, 0x4E57, 0x8FE7, 0x5197, 0x8FE8, 0x5270, 0x8FE9, 0x57CE, 0x8FEA, 0x5834, 0x8FEB, 0x58CC, 0x8FEC, 0x5B22, 0x8FED, 0x5E38, 0x8FEE, 0x60C5, 0x8FEF, 0x64FE, 0x8FF0, 0x6761, 0x8FF1, 0x6756, 0x8FF2, 0x6D44, 0x8FF3, 0x72B6, 0x8FF4, 0x7573, 0x8FF5, 0x7A63, 0x8FF6, 0x84B8, 0x8FF7, 0x8B72, 0x8FF8, 0x91B8, 0x8FF9, 0x9320, 0x8FFA, 0x5631, 0x8FFB, 0x57F4, 0x8FFC, 0x98FE, 0x9040, 0x62ED, 0x9041, 0x690D, 0x9042, 0x6B96, 0x9043, 0x71ED, 0x9044, 0x7E54, 0x9045, 0x8077, 0x9046, 0x8272, 0x9047, 0x89E6, 0x9048, 0x98DF, 0x9049, 0x8755, 0x904A, 0x8FB1, 0x904B, 0x5C3B, 0x904C, 0x4F38, 0x904D, 0x4FE1, 0x904E, 0x4FB5, 0x904F, 0x5507, 0x9050, 0x5A20, 0x9051, 0x5BDD, 0x9052, 0x5BE9, 0x9053, 0x5FC3, 0x9054, 0x614E, 0x9055, 0x632F, 0x9056, 0x65B0, 0x9057, 0x664B, 0x9058, 0x68EE, 0x9059, 0x699B, 0x905A, 0x6D78, 0x905B, 0x6DF1, 0x905C, 0x7533, 0x905D, 0x75B9, 0x905E, 0x771F, 0x905F, 0x795E, 0x9060, 0x79E6, 0x9061, 0x7D33, 0x9062, 0x81E3, 0x9063, 0x82AF, 0x9064, 0x85AA, 0x9065, 0x89AA, 0x9066, 0x8A3A, 0x9067, 0x8EAB, 0x9068, 0x8F9B, 0x9069, 0x9032, 0x906A, 0x91DD, 0x906B, 0x9707, 0x906C, 0x4EBA, 0x906D, 0x4EC1, 0x906E, 0x5203, 0x906F, 0x5875, 0x9070, 0x58EC, 0x9071, 0x5C0B, 0x9072, 0x751A, 0x9073, 0x5C3D, 0x9074, 0x814E, 0x9075, 0x8A0A, 0x9076, 0x8FC5, 0x9077, 0x9663, 0x9078, 0x976D, 0x9079, 0x7B25, 0x907A, 0x8ACF, 0x907B, 0x9808, 0x907C, 0x9162, 0x907D, 0x56F3, 0x907E, 0x53A8, 0x9080, 0x9017, 0x9081, 0x5439, 0x9082, 0x5782, 0x9083, 0x5E25, 0x9084, 0x63A8, 0x9085, 0x6C34, 0x9086, 0x708A, 0x9087, 0x7761, 0x9088, 0x7C8B, 0x9089, 0x7FE0, 0x908A, 0x8870, 0x908B, 0x9042, 0x908C, 0x9154, 0x908D, 0x9310, 0x908E, 0x9318, 0x908F, 0x968F, 0x9090, 0x745E, 0x9091, 0x9AC4, 0x9092, 0x5D07, 0x9093, 0x5D69, 0x9094, 0x6570, 0x9095, 0x67A2, 0x9096, 0x8DA8, 0x9097, 0x96DB, 0x9098, 0x636E, 0x9099, 0x6749, 0x909A, 0x6919, 0x909B, 0x83C5, 0x909C, 0x9817, 0x909D, 0x96C0, 0x909E, 0x88FE, 0x909F, 0x6F84, 0x90A0, 0x647A, 0x90A1, 0x5BF8, 0x90A2, 0x4E16, 0x90A3, 0x702C, 0x90A4, 0x755D, 0x90A5, 0x662F, 0x90A6, 0x51C4, 0x90A7, 0x5236, 0x90A8, 0x52E2, 0x90A9, 0x59D3, 0x90AA, 0x5F81, 0x90AB, 0x6027, 0x90AC, 0x6210, 0x90AD, 0x653F, 0x90AE, 0x6574, 0x90AF, 0x661F, 0x90B0, 0x6674, 0x90B1, 0x68F2, 0x90B2, 0x6816, 0x90B3, 0x6B63, 0x90B4, 0x6E05, 0x90B5, 0x7272, 0x90B6, 0x751F, 0x90B7, 0x76DB, 0x90B8, 0x7CBE, 0x90B9, 0x8056, 0x90BA, 0x58F0, 0x90BB, 0x88FD, 0x90BC, 0x897F, 0x90BD, 0x8AA0, 0x90BE, 0x8A93, 0x90BF, 0x8ACB, 0x90C0, 0x901D, 0x90C1, 0x9192, 0x90C2, 0x9752, 0x90C3, 0x9759, 0x90C4, 0x6589, 0x90C5, 0x7A0E, 0x90C6, 0x8106, 0x90C7, 0x96BB, 0x90C8, 0x5E2D, 0x90C9, 0x60DC, 0x90CA, 0x621A, 0x90CB, 0x65A5, 0x90CC, 0x6614, 0x90CD, 0x6790, 0x90CE, 0x77F3, 0x90CF, 0x7A4D, 0x90D0, 0x7C4D, 0x90D1, 0x7E3E, 0x90D2, 0x810A, 0x90D3, 0x8CAC, 0x90D4, 0x8D64, 0x90D5, 0x8DE1, 0x90D6, 0x8E5F, 0x90D7, 0x78A9, 0x90D8, 0x5207, 0x90D9, 0x62D9, 0x90DA, 0x63A5, 0x90DB, 0x6442, 0x90DC, 0x6298, 0x90DD, 0x8A2D, 0x90DE, 0x7A83, 0x90DF, 0x7BC0, 0x90E0, 0x8AAC, 0x90E1, 0x96EA, 0x90E2, 0x7D76, 0x90E3, 0x820C, 0x90E4, 0x8749, 0x90E5, 0x4ED9, 0x90E6, 0x5148, 0x90E7, 0x5343, 0x90E8, 0x5360, 0x90E9, 0x5BA3, 0x90EA, 0x5C02, 0x90EB, 0x5C16, 0x90EC, 0x5DDD, 0x90ED, 0x6226, 0x90EE, 0x6247, 0x90EF, 0x64B0, 0x90F0, 0x6813, 0x90F1, 0x6834, 0x90F2, 0x6CC9, 0x90F3, 0x6D45, 0x90F4, 0x6D17, 0x90F5, 0x67D3, 0x90F6, 0x6F5C, 0x90F7, 0x714E, 0x90F8, 0x717D, 0x90F9, 0x65CB, 0x90FA, 0x7A7F, 0x90FB, 0x7BAD, 0x90FC, 0x7DDA, 0x9140, 0x7E4A, 0x9141, 0x7FA8, 0x9142, 0x817A, 0x9143, 0x821B, 0x9144, 0x8239, 0x9145, 0x85A6, 0x9146, 0x8A6E, 0x9147, 0x8CCE, 0x9148, 0x8DF5, 0x9149, 0x9078, 0x914A, 0x9077, 0x914B, 0x92AD, 0x914C, 0x9291, 0x914D, 0x9583, 0x914E, 0x9BAE, 0x914F, 0x524D, 0x9150, 0x5584, 0x9151, 0x6F38, 0x9152, 0x7136, 0x9153, 0x5168, 0x9154, 0x7985, 0x9155, 0x7E55, 0x9156, 0x81B3, 0x9157, 0x7CCE, 0x9158, 0x564C, 0x9159, 0x5851, 0x915A, 0x5CA8, 0x915B, 0x63AA, 0x915C, 0x66FE, 0x915D, 0x66FD, 0x915E, 0x695A, 0x915F, 0x72D9, 0x9160, 0x758F, 0x9161, 0x758E, 0x9162, 0x790E, 0x9163, 0x7956, 0x9164, 0x79DF, 0x9165, 0x7C97, 0x9166, 0x7D20, 0x9167, 0x7D44, 0x9168, 0x8607, 0x9169, 0x8A34, 0x916A, 0x963B, 0x916B, 0x9061, 0x916C, 0x9F20, 0x916D, 0x50E7, 0x916E, 0x5275, 0x916F, 0x53CC, 0x9170, 0x53E2, 0x9171, 0x5009, 0x9172, 0x55AA, 0x9173, 0x58EE, 0x9174, 0x594F, 0x9175, 0x723D, 0x9176, 0x5B8B, 0x9177, 0x5C64, 0x9178, 0x531D, 0x9179, 0x60E3, 0x917A, 0x60F3, 0x917B, 0x635C, 0x917C, 0x6383, 0x917D, 0x633F, 0x917E, 0x63BB, 0x9180, 0x64CD, 0x9181, 0x65E9, 0x9182, 0x66F9, 0x9183, 0x5DE3, 0x9184, 0x69CD, 0x9185, 0x69FD, 0x9186, 0x6F15, 0x9187, 0x71E5, 0x9188, 0x4E89, 0x9189, 0x75E9, 0x918A, 0x76F8, 0x918B, 0x7A93, 0x918C, 0x7CDF, 0x918D, 0x7DCF, 0x918E, 0x7D9C, 0x918F, 0x8061, 0x9190, 0x8349, 0x9191, 0x8358, 0x9192, 0x846C, 0x9193, 0x84BC, 0x9194, 0x85FB, 0x9195, 0x88C5, 0x9196, 0x8D70, 0x9197, 0x9001, 0x9198, 0x906D, 0x9199, 0x9397, 0x919A, 0x971C, 0x919B, 0x9A12, 0x919C, 0x50CF, 0x919D, 0x5897, 0x919E, 0x618E, 0x919F, 0x81D3, 0x91A0, 0x8535, 0x91A1, 0x8D08, 0x91A2, 0x9020, 0x91A3, 0x4FC3, 0x91A4, 0x5074, 0x91A5, 0x5247, 0x91A6, 0x5373, 0x91A7, 0x606F, 0x91A8, 0x6349, 0x91A9, 0x675F, 0x91AA, 0x6E2C, 0x91AB, 0x8DB3, 0x91AC, 0x901F, 0x91AD, 0x4FD7, 0x91AE, 0x5C5E, 0x91AF, 0x8CCA, 0x91B0, 0x65CF, 0x91B1, 0x7D9A, 0x91B2, 0x5352, 0x91B3, 0x8896, 0x91B4, 0x5176, 0x91B5, 0x63C3, 0x91B6, 0x5B58, 0x91B7, 0x5B6B, 0x91B8, 0x5C0A, 0x91B9, 0x640D, 0x91BA, 0x6751, 0x91BB, 0x905C, 0x91BC, 0x4ED6, 0x91BD, 0x591A, 0x91BE, 0x592A, 0x91BF, 0x6C70, 0x91C0, 0x8A51, 0x91C1, 0x553E, 0x91C2, 0x5815, 0x91C3, 0x59A5, 0x91C4, 0x60F0, 0x91C5, 0x6253, 0x91C6, 0x67C1, 0x91C7, 0x8235, 0x91C8, 0x6955, 0x91C9, 0x9640, 0x91CA, 0x99C4, 0x91CB, 0x9A28, 0x91CC, 0x4F53, 0x91CD, 0x5806, 0x91CE, 0x5BFE, 0x91CF, 0x8010, 0x91D0, 0x5CB1, 0x91D1, 0x5E2F, 0x91D2, 0x5F85, 0x91D3, 0x6020, 0x91D4, 0x614B, 0x91D5, 0x6234, 0x91D6, 0x66FF, 0x91D7, 0x6CF0, 0x91D8, 0x6EDE, 0x91D9, 0x80CE, 0x91DA, 0x817F, 0x91DB, 0x82D4, 0x91DC, 0x888B, 0x91DD, 0x8CB8, 0x91DE, 0x9000, 0x91DF, 0x902E, 0x91E0, 0x968A, 0x91E1, 0x9EDB, 0x91E2, 0x9BDB, 0x91E3, 0x4EE3, 0x91E4, 0x53F0, 0x91E5, 0x5927, 0x91E6, 0x7B2C, 0x91E7, 0x918D, 0x91E8, 0x984C, 0x91E9, 0x9DF9, 0x91EA, 0x6EDD, 0x91EB, 0x7027, 0x91EC, 0x5353, 0x91ED, 0x5544, 0x91EE, 0x5B85, 0x91EF, 0x6258, 0x91F0, 0x629E, 0x91F1, 0x62D3, 0x91F2, 0x6CA2, 0x91F3, 0x6FEF, 0x91F4, 0x7422, 0x91F5, 0x8A17, 0x91F6, 0x9438, 0x91F7, 0x6FC1, 0x91F8, 0x8AFE, 0x91F9, 0x8338, 0x91FA, 0x51E7, 0x91FB, 0x86F8, 0x91FC, 0x53EA, 0x9240, 0x53E9, 0x9241, 0x4F46, 0x9242, 0x9054, 0x9243, 0x8FB0, 0x9244, 0x596A, 0x9245, 0x8131, 0x9246, 0x5DFD, 0x9247, 0x7AEA, 0x9248, 0x8FBF, 0x9249, 0x68DA, 0x924A, 0x8C37, 0x924B, 0x72F8, 0x924C, 0x9C48, 0x924D, 0x6A3D, 0x924E, 0x8AB0, 0x924F, 0x4E39, 0x9250, 0x5358, 0x9251, 0x5606, 0x9252, 0x5766, 0x9253, 0x62C5, 0x9254, 0x63A2, 0x9255, 0x65E6, 0x9256, 0x6B4E, 0x9257, 0x6DE1, 0x9258, 0x6E5B, 0x9259, 0x70AD, 0x925A, 0x77ED, 0x925B, 0x7AEF, 0x925C, 0x7BAA, 0x925D, 0x7DBB, 0x925E, 0x803D, 0x925F, 0x80C6, 0x9260, 0x86CB, 0x9261, 0x8A95, 0x9262, 0x935B, 0x9263, 0x56E3, 0x9264, 0x58C7, 0x9265, 0x5F3E, 0x9266, 0x65AD, 0x9267, 0x6696, 0x9268, 0x6A80, 0x9269, 0x6BB5, 0x926A, 0x7537, 0x926B, 0x8AC7, 0x926C, 0x5024, 0x926D, 0x77E5, 0x926E, 0x5730, 0x926F, 0x5F1B, 0x9270, 0x6065, 0x9271, 0x667A, 0x9272, 0x6C60, 0x9273, 0x75F4, 0x9274, 0x7A1A, 0x9275, 0x7F6E, 0x9276, 0x81F4, 0x9277, 0x8718, 0x9278, 0x9045, 0x9279, 0x99B3, 0x927A, 0x7BC9, 0x927B, 0x755C, 0x927C, 0x7AF9, 0x927D, 0x7B51, 0x927E, 0x84C4, 0x9280, 0x9010, 0x9281, 0x79E9, 0x9282, 0x7A92, 0x9283, 0x8336, 0x9284, 0x5AE1, 0x9285, 0x7740, 0x9286, 0x4E2D, 0x9287, 0x4EF2, 0x9288, 0x5B99, 0x9289, 0x5FE0, 0x928A, 0x62BD, 0x928B, 0x663C, 0x928C, 0x67F1, 0x928D, 0x6CE8, 0x928E, 0x866B, 0x928F, 0x8877, 0x9290, 0x8A3B, 0x9291, 0x914E, 0x9292, 0x92F3, 0x9293, 0x99D0, 0x9294, 0x6A17, 0x9295, 0x7026, 0x9296, 0x732A, 0x9297, 0x82E7, 0x9298, 0x8457, 0x9299, 0x8CAF, 0x929A, 0x4E01, 0x929B, 0x5146, 0x929C, 0x51CB, 0x929D, 0x558B, 0x929E, 0x5BF5, 0x929F, 0x5E16, 0x92A0, 0x5E33, 0x92A1, 0x5E81, 0x92A2, 0x5F14, 0x92A3, 0x5F35, 0x92A4, 0x5F6B, 0x92A5, 0x5FB4, 0x92A6, 0x61F2, 0x92A7, 0x6311, 0x92A8, 0x66A2, 0x92A9, 0x671D, 0x92AA, 0x6F6E, 0x92AB, 0x7252, 0x92AC, 0x753A, 0x92AD, 0x773A, 0x92AE, 0x8074, 0x92AF, 0x8139, 0x92B0, 0x8178, 0x92B1, 0x8776, 0x92B2, 0x8ABF, 0x92B3, 0x8ADC, 0x92B4, 0x8D85, 0x92B5, 0x8DF3, 0x92B6, 0x929A, 0x92B7, 0x9577, 0x92B8, 0x9802, 0x92B9, 0x9CE5, 0x92BA, 0x52C5, 0x92BB, 0x6357, 0x92BC, 0x76F4, 0x92BD, 0x6715, 0x92BE, 0x6C88, 0x92BF, 0x73CD, 0x92C0, 0x8CC3, 0x92C1, 0x93AE, 0x92C2, 0x9673, 0x92C3, 0x6D25, 0x92C4, 0x589C, 0x92C5, 0x690E, 0x92C6, 0x69CC, 0x92C7, 0x8FFD, 0x92C8, 0x939A, 0x92C9, 0x75DB, 0x92CA, 0x901A, 0x92CB, 0x585A, 0x92CC, 0x6802, 0x92CD, 0x63B4, 0x92CE, 0x69FB, 0x92CF, 0x4F43, 0x92D0, 0x6F2C, 0x92D1, 0x67D8, 0x92D2, 0x8FBB, 0x92D3, 0x8526, 0x92D4, 0x7DB4, 0x92D5, 0x9354, 0x92D6, 0x693F, 0x92D7, 0x6F70, 0x92D8, 0x576A, 0x92D9, 0x58F7, 0x92DA, 0x5B2C, 0x92DB, 0x7D2C, 0x92DC, 0x722A, 0x92DD, 0x540A, 0x92DE, 0x91E3, 0x92DF, 0x9DB4, 0x92E0, 0x4EAD, 0x92E1, 0x4F4E, 0x92E2, 0x505C, 0x92E3, 0x5075, 0x92E4, 0x5243, 0x92E5, 0x8C9E, 0x92E6, 0x5448, 0x92E7, 0x5824, 0x92E8, 0x5B9A, 0x92E9, 0x5E1D, 0x92EA, 0x5E95, 0x92EB, 0x5EAD, 0x92EC, 0x5EF7, 0x92ED, 0x5F1F, 0x92EE, 0x608C, 0x92EF, 0x62B5, 0x92F0, 0x633A, 0x92F1, 0x63D0, 0x92F2, 0x68AF, 0x92F3, 0x6C40, 0x92F4, 0x7887, 0x92F5, 0x798E, 0x92F6, 0x7A0B, 0x92F7, 0x7DE0, 0x92F8, 0x8247, 0x92F9, 0x8A02, 0x92FA, 0x8AE6, 0x92FB, 0x8E44, 0x92FC, 0x9013, 0x9340, 0x90B8, 0x9341, 0x912D, 0x9342, 0x91D8, 0x9343, 0x9F0E, 0x9344, 0x6CE5, 0x9345, 0x6458, 0x9346, 0x64E2, 0x9347, 0x6575, 0x9348, 0x6EF4, 0x9349, 0x7684, 0x934A, 0x7B1B, 0x934B, 0x9069, 0x934C, 0x93D1, 0x934D, 0x6EBA, 0x934E, 0x54F2, 0x934F, 0x5FB9, 0x9350, 0x64A4, 0x9351, 0x8F4D, 0x9352, 0x8FED, 0x9353, 0x9244, 0x9354, 0x5178, 0x9355, 0x586B, 0x9356, 0x5929, 0x9357, 0x5C55, 0x9358, 0x5E97, 0x9359, 0x6DFB, 0x935A, 0x7E8F, 0x935B, 0x751C, 0x935C, 0x8CBC, 0x935D, 0x8EE2, 0x935E, 0x985B, 0x935F, 0x70B9, 0x9360, 0x4F1D, 0x9361, 0x6BBF, 0x9362, 0x6FB1, 0x9363, 0x7530, 0x9364, 0x96FB, 0x9365, 0x514E, 0x9366, 0x5410, 0x9367, 0x5835, 0x9368, 0x5857, 0x9369, 0x59AC, 0x936A, 0x5C60, 0x936B, 0x5F92, 0x936C, 0x6597, 0x936D, 0x675C, 0x936E, 0x6E21, 0x936F, 0x767B, 0x9370, 0x83DF, 0x9371, 0x8CED, 0x9372, 0x9014, 0x9373, 0x90FD, 0x9374, 0x934D, 0x9375, 0x7825, 0x9376, 0x783A, 0x9377, 0x52AA, 0x9378, 0x5EA6, 0x9379, 0x571F, 0x937A, 0x5974, 0x937B, 0x6012, 0x937C, 0x5012, 0x937D, 0x515A, 0x937E, 0x51AC, 0x9380, 0x51CD, 0x9381, 0x5200, 0x9382, 0x5510, 0x9383, 0x5854, 0x9384, 0x5858, 0x9385, 0x5957, 0x9386, 0x5B95, 0x9387, 0x5CF6, 0x9388, 0x5D8B, 0x9389, 0x60BC, 0x938A, 0x6295, 0x938B, 0x642D, 0x938C, 0x6771, 0x938D, 0x6843, 0x938E, 0x68BC, 0x938F, 0x68DF, 0x9390, 0x76D7, 0x9391, 0x6DD8, 0x9392, 0x6E6F, 0x9393, 0x6D9B, 0x9394, 0x706F, 0x9395, 0x71C8, 0x9396, 0x5F53, 0x9397, 0x75D8, 0x9398, 0x7977, 0x9399, 0x7B49, 0x939A, 0x7B54, 0x939B, 0x7B52, 0x939C, 0x7CD6, 0x939D, 0x7D71, 0x939E, 0x5230, 0x939F, 0x8463, 0x93A0, 0x8569, 0x93A1, 0x85E4, 0x93A2, 0x8A0E, 0x93A3, 0x8B04, 0x93A4, 0x8C46, 0x93A5, 0x8E0F, 0x93A6, 0x9003, 0x93A7, 0x900F, 0x93A8, 0x9419, 0x93A9, 0x9676, 0x93AA, 0x982D, 0x93AB, 0x9A30, 0x93AC, 0x95D8, 0x93AD, 0x50CD, 0x93AE, 0x52D5, 0x93AF, 0x540C, 0x93B0, 0x5802, 0x93B1, 0x5C0E, 0x93B2, 0x61A7, 0x93B3, 0x649E, 0x93B4, 0x6D1E, 0x93B5, 0x77B3, 0x93B6, 0x7AE5, 0x93B7, 0x80F4, 0x93B8, 0x8404, 0x93B9, 0x9053, 0x93BA, 0x9285, 0x93BB, 0x5CE0, 0x93BC, 0x9D07, 0x93BD, 0x533F, 0x93BE, 0x5F97, 0x93BF, 0x5FB3, 0x93C0, 0x6D9C, 0x93C1, 0x7279, 0x93C2, 0x7763, 0x93C3, 0x79BF, 0x93C4, 0x7BE4, 0x93C5, 0x6BD2, 0x93C6, 0x72EC, 0x93C7, 0x8AAD, 0x93C8, 0x6803, 0x93C9, 0x6A61, 0x93CA, 0x51F8, 0x93CB, 0x7A81, 0x93CC, 0x6934, 0x93CD, 0x5C4A, 0x93CE, 0x9CF6, 0x93CF, 0x82EB, 0x93D0, 0x5BC5, 0x93D1, 0x9149, 0x93D2, 0x701E, 0x93D3, 0x5678, 0x93D4, 0x5C6F, 0x93D5, 0x60C7, 0x93D6, 0x6566, 0x93D7, 0x6C8C, 0x93D8, 0x8C5A, 0x93D9, 0x9041, 0x93DA, 0x9813, 0x93DB, 0x5451, 0x93DC, 0x66C7, 0x93DD, 0x920D, 0x93DE, 0x5948, 0x93DF, 0x90A3, 0x93E0, 0x5185, 0x93E1, 0x4E4D, 0x93E2, 0x51EA, 0x93E3, 0x8599, 0x93E4, 0x8B0E, 0x93E5, 0x7058, 0x93E6, 0x637A, 0x93E7, 0x934B, 0x93E8, 0x6962, 0x93E9, 0x99B4, 0x93EA, 0x7E04, 0x93EB, 0x7577, 0x93EC, 0x5357, 0x93ED, 0x6960, 0x93EE, 0x8EDF, 0x93EF, 0x96E3, 0x93F0, 0x6C5D, 0x93F1, 0x4E8C, 0x93F2, 0x5C3C, 0x93F3, 0x5F10, 0x93F4, 0x8FE9, 0x93F5, 0x5302, 0x93F6, 0x8CD1, 0x93F7, 0x8089, 0x93F8, 0x8679, 0x93F9, 0x5EFF, 0x93FA, 0x65E5, 0x93FB, 0x4E73, 0x93FC, 0x5165, 0x9440, 0x5982, 0x9441, 0x5C3F, 0x9442, 0x97EE, 0x9443, 0x4EFB, 0x9444, 0x598A, 0x9445, 0x5FCD, 0x9446, 0x8A8D, 0x9447, 0x6FE1, 0x9448, 0x79B0, 0x9449, 0x7962, 0x944A, 0x5BE7, 0x944B, 0x8471, 0x944C, 0x732B, 0x944D, 0x71B1, 0x944E, 0x5E74, 0x944F, 0x5FF5, 0x9450, 0x637B, 0x9451, 0x649A, 0x9452, 0x71C3, 0x9453, 0x7C98, 0x9454, 0x4E43, 0x9455, 0x5EFC, 0x9456, 0x4E4B, 0x9457, 0x57DC, 0x9458, 0x56A2, 0x9459, 0x60A9, 0x945A, 0x6FC3, 0x945B, 0x7D0D, 0x945C, 0x80FD, 0x945D, 0x8133, 0x945E, 0x81BF, 0x945F, 0x8FB2, 0x9460, 0x8997, 0x9461, 0x86A4, 0x9462, 0x5DF4, 0x9463, 0x628A, 0x9464, 0x64AD, 0x9465, 0x8987, 0x9466, 0x6777, 0x9467, 0x6CE2, 0x9468, 0x6D3E, 0x9469, 0x7436, 0x946A, 0x7834, 0x946B, 0x5A46, 0x946C, 0x7F75, 0x946D, 0x82AD, 0x946E, 0x99AC, 0x946F, 0x4FF3, 0x9470, 0x5EC3, 0x9471, 0x62DD, 0x9472, 0x6392, 0x9473, 0x6557, 0x9474, 0x676F, 0x9475, 0x76C3, 0x9476, 0x724C, 0x9477, 0x80CC, 0x9478, 0x80BA, 0x9479, 0x8F29, 0x947A, 0x914D, 0x947B, 0x500D, 0x947C, 0x57F9, 0x947D, 0x5A92, 0x947E, 0x6885, 0x9480, 0x6973, 0x9481, 0x7164, 0x9482, 0x72FD, 0x9483, 0x8CB7, 0x9484, 0x58F2, 0x9485, 0x8CE0, 0x9486, 0x966A, 0x9487, 0x9019, 0x9488, 0x877F, 0x9489, 0x79E4, 0x948A, 0x77E7, 0x948B, 0x8429, 0x948C, 0x4F2F, 0x948D, 0x5265, 0x948E, 0x535A, 0x948F, 0x62CD, 0x9490, 0x67CF, 0x9491, 0x6CCA, 0x9492, 0x767D, 0x9493, 0x7B94, 0x9494, 0x7C95, 0x9495, 0x8236, 0x9496, 0x8584, 0x9497, 0x8FEB, 0x9498, 0x66DD, 0x9499, 0x6F20, 0x949A, 0x7206, 0x949B, 0x7E1B, 0x949C, 0x83AB, 0x949D, 0x99C1, 0x949E, 0x9EA6, 0x949F, 0x51FD, 0x94A0, 0x7BB1, 0x94A1, 0x7872, 0x94A2, 0x7BB8, 0x94A3, 0x8087, 0x94A4, 0x7B48, 0x94A5, 0x6AE8, 0x94A6, 0x5E61, 0x94A7, 0x808C, 0x94A8, 0x7551, 0x94A9, 0x7560, 0x94AA, 0x516B, 0x94AB, 0x9262, 0x94AC, 0x6E8C, 0x94AD, 0x767A, 0x94AE, 0x9197, 0x94AF, 0x9AEA, 0x94B0, 0x4F10, 0x94B1, 0x7F70, 0x94B2, 0x629C, 0x94B3, 0x7B4F, 0x94B4, 0x95A5, 0x94B5, 0x9CE9, 0x94B6, 0x567A, 0x94B7, 0x5859, 0x94B8, 0x86E4, 0x94B9, 0x96BC, 0x94BA, 0x4F34, 0x94BB, 0x5224, 0x94BC, 0x534A, 0x94BD, 0x53CD, 0x94BE, 0x53DB, 0x94BF, 0x5E06, 0x94C0, 0x642C, 0x94C1, 0x6591, 0x94C2, 0x677F, 0x94C3, 0x6C3E, 0x94C4, 0x6C4E, 0x94C5, 0x7248, 0x94C6, 0x72AF, 0x94C7, 0x73ED, 0x94C8, 0x7554, 0x94C9, 0x7E41, 0x94CA, 0x822C, 0x94CB, 0x85E9, 0x94CC, 0x8CA9, 0x94CD, 0x7BC4, 0x94CE, 0x91C6, 0x94CF, 0x7169, 0x94D0, 0x9812, 0x94D1, 0x98EF, 0x94D2, 0x633D, 0x94D3, 0x6669, 0x94D4, 0x756A, 0x94D5, 0x76E4, 0x94D6, 0x78D0, 0x94D7, 0x8543, 0x94D8, 0x86EE, 0x94D9, 0x532A, 0x94DA, 0x5351, 0x94DB, 0x5426, 0x94DC, 0x5983, 0x94DD, 0x5E87, 0x94DE, 0x5F7C, 0x94DF, 0x60B2, 0x94E0, 0x6249, 0x94E1, 0x6279, 0x94E2, 0x62AB, 0x94E3, 0x6590, 0x94E4, 0x6BD4, 0x94E5, 0x6CCC, 0x94E6, 0x75B2, 0x94E7, 0x76AE, 0x94E8, 0x7891, 0x94E9, 0x79D8, 0x94EA, 0x7DCB, 0x94EB, 0x7F77, 0x94EC, 0x80A5, 0x94ED, 0x88AB, 0x94EE, 0x8AB9, 0x94EF, 0x8CBB, 0x94F0, 0x907F, 0x94F1, 0x975E, 0x94F2, 0x98DB, 0x94F3, 0x6A0B, 0x94F4, 0x7C38, 0x94F5, 0x5099, 0x94F6, 0x5C3E, 0x94F7, 0x5FAE, 0x94F8, 0x6787, 0x94F9, 0x6BD8, 0x94FA, 0x7435, 0x94FB, 0x7709, 0x94FC, 0x7F8E, 0x9540, 0x9F3B, 0x9541, 0x67CA, 0x9542, 0x7A17, 0x9543, 0x5339, 0x9544, 0x758B, 0x9545, 0x9AED, 0x9546, 0x5F66, 0x9547, 0x819D, 0x9548, 0x83F1, 0x9549, 0x8098, 0x954A, 0x5F3C, 0x954B, 0x5FC5, 0x954C, 0x7562, 0x954D, 0x7B46, 0x954E, 0x903C, 0x954F, 0x6867, 0x9550, 0x59EB, 0x9551, 0x5A9B, 0x9552, 0x7D10, 0x9553, 0x767E, 0x9554, 0x8B2C, 0x9555, 0x4FF5, 0x9556, 0x5F6A, 0x9557, 0x6A19, 0x9558, 0x6C37, 0x9559, 0x6F02, 0x955A, 0x74E2, 0x955B, 0x7968, 0x955C, 0x8868, 0x955D, 0x8A55, 0x955E, 0x8C79, 0x955F, 0x5EDF, 0x9560, 0x63CF, 0x9561, 0x75C5, 0x9562, 0x79D2, 0x9563, 0x82D7, 0x9564, 0x9328, 0x9565, 0x92F2, 0x9566, 0x849C, 0x9567, 0x86ED, 0x9568, 0x9C2D, 0x9569, 0x54C1, 0x956A, 0x5F6C, 0x956B, 0x658C, 0x956C, 0x6D5C, 0x956D, 0x7015, 0x956E, 0x8CA7, 0x956F, 0x8CD3, 0x9570, 0x983B, 0x9571, 0x654F, 0x9572, 0x74F6, 0x9573, 0x4E0D, 0x9574, 0x4ED8, 0x9575, 0x57E0, 0x9576, 0x592B, 0x9577, 0x5A66, 0x9578, 0x5BCC, 0x9579, 0x51A8, 0x957A, 0x5E03, 0x957B, 0x5E9C, 0x957C, 0x6016, 0x957D, 0x6276, 0x957E, 0x6577, 0x9580, 0x65A7, 0x9581, 0x666E, 0x9582, 0x6D6E, 0x9583, 0x7236, 0x9584, 0x7B26, 0x9585, 0x8150, 0x9586, 0x819A, 0x9587, 0x8299, 0x9588, 0x8B5C, 0x9589, 0x8CA0, 0x958A, 0x8CE6, 0x958B, 0x8D74, 0x958C, 0x961C, 0x958D, 0x9644, 0x958E, 0x4FAE, 0x958F, 0x64AB, 0x9590, 0x6B66, 0x9591, 0x821E, 0x9592, 0x8461, 0x9593, 0x856A, 0x9594, 0x90E8, 0x9595, 0x5C01, 0x9596, 0x6953, 0x9597, 0x98A8, 0x9598, 0x847A, 0x9599, 0x8557, 0x959A, 0x4F0F, 0x959B, 0x526F, 0x959C, 0x5FA9, 0x959D, 0x5E45, 0x959E, 0x670D, 0x959F, 0x798F, 0x95A0, 0x8179, 0x95A1, 0x8907, 0x95A2, 0x8986, 0x95A3, 0x6DF5, 0x95A4, 0x5F17, 0x95A5, 0x6255, 0x95A6, 0x6CB8, 0x95A7, 0x4ECF, 0x95A8, 0x7269, 0x95A9, 0x9B92, 0x95AA, 0x5206, 0x95AB, 0x543B, 0x95AC, 0x5674, 0x95AD, 0x58B3, 0x95AE, 0x61A4, 0x95AF, 0x626E, 0x95B0, 0x711A, 0x95B1, 0x596E, 0x95B2, 0x7C89, 0x95B3, 0x7CDE, 0x95B4, 0x7D1B, 0x95B5, 0x96F0, 0x95B6, 0x6587, 0x95B7, 0x805E, 0x95B8, 0x4E19, 0x95B9, 0x4F75, 0x95BA, 0x5175, 0x95BB, 0x5840, 0x95BC, 0x5E63, 0x95BD, 0x5E73, 0x95BE, 0x5F0A, 0x95BF, 0x67C4, 0x95C0, 0x4E26, 0x95C1, 0x853D, 0x95C2, 0x9589, 0x95C3, 0x965B, 0x95C4, 0x7C73, 0x95C5, 0x9801, 0x95C6, 0x50FB, 0x95C7, 0x58C1, 0x95C8, 0x7656, 0x95C9, 0x78A7, 0x95CA, 0x5225, 0x95CB, 0x77A5, 0x95CC, 0x8511, 0x95CD, 0x7B86, 0x95CE, 0x504F, 0x95CF, 0x5909, 0x95D0, 0x7247, 0x95D1, 0x7BC7, 0x95D2, 0x7DE8, 0x95D3, 0x8FBA, 0x95D4, 0x8FD4, 0x95D5, 0x904D, 0x95D6, 0x4FBF, 0x95D7, 0x52C9, 0x95D8, 0x5A29, 0x95D9, 0x5F01, 0x95DA, 0x97AD, 0x95DB, 0x4FDD, 0x95DC, 0x8217, 0x95DD, 0x92EA, 0x95DE, 0x5703, 0x95DF, 0x6355, 0x95E0, 0x6B69, 0x95E1, 0x752B, 0x95E2, 0x88DC, 0x95E3, 0x8F14, 0x95E4, 0x7A42, 0x95E5, 0x52DF, 0x95E6, 0x5893, 0x95E7, 0x6155, 0x95E8, 0x620A, 0x95E9, 0x66AE, 0x95EA, 0x6BCD, 0x95EB, 0x7C3F, 0x95EC, 0x83E9, 0x95ED, 0x5023, 0x95EE, 0x4FF8, 0x95EF, 0x5305, 0x95F0, 0x5446, 0x95F1, 0x5831, 0x95F2, 0x5949, 0x95F3, 0x5B9D, 0x95F4, 0x5CF0, 0x95F5, 0x5CEF, 0x95F6, 0x5D29, 0x95F7, 0x5E96, 0x95F8, 0x62B1, 0x95F9, 0x6367, 0x95FA, 0x653E, 0x95FB, 0x65B9, 0x95FC, 0x670B, 0x9640, 0x6CD5, 0x9641, 0x6CE1, 0x9642, 0x70F9, 0x9643, 0x7832, 0x9644, 0x7E2B, 0x9645, 0x80DE, 0x9646, 0x82B3, 0x9647, 0x840C, 0x9648, 0x84EC, 0x9649, 0x8702, 0x964A, 0x8912, 0x964B, 0x8A2A, 0x964C, 0x8C4A, 0x964D, 0x90A6, 0x964E, 0x92D2, 0x964F, 0x98FD, 0x9650, 0x9CF3, 0x9651, 0x9D6C, 0x9652, 0x4E4F, 0x9653, 0x4EA1, 0x9654, 0x508D, 0x9655, 0x5256, 0x9656, 0x574A, 0x9657, 0x59A8, 0x9658, 0x5E3D, 0x9659, 0x5FD8, 0x965A, 0x5FD9, 0x965B, 0x623F, 0x965C, 0x66B4, 0x965D, 0x671B, 0x965E, 0x67D0, 0x965F, 0x68D2, 0x9660, 0x5192, 0x9661, 0x7D21, 0x9662, 0x80AA, 0x9663, 0x81A8, 0x9664, 0x8B00, 0x9665, 0x8C8C, 0x9666, 0x8CBF, 0x9667, 0x927E, 0x9668, 0x9632, 0x9669, 0x5420, 0x966A, 0x982C, 0x966B, 0x5317, 0x966C, 0x50D5, 0x966D, 0x535C, 0x966E, 0x58A8, 0x966F, 0x64B2, 0x9670, 0x6734, 0x9671, 0x7267, 0x9672, 0x7766, 0x9673, 0x7A46, 0x9674, 0x91E6, 0x9675, 0x52C3, 0x9676, 0x6CA1, 0x9677, 0x6B86, 0x9678, 0x5800, 0x9679, 0x5E4C, 0x967A, 0x5954, 0x967B, 0x672C, 0x967C, 0x7FFB, 0x967D, 0x51E1, 0x967E, 0x76C6, 0x9680, 0x6469, 0x9681, 0x78E8, 0x9682, 0x9B54, 0x9683, 0x9EBB, 0x9684, 0x57CB, 0x9685, 0x59B9, 0x9686, 0x6627, 0x9687, 0x679A, 0x9688, 0x6BCE, 0x9689, 0x54E9, 0x968A, 0x69D9, 0x968B, 0x5E55, 0x968C, 0x819C, 0x968D, 0x6795, 0x968E, 0x9BAA, 0x968F, 0x67FE, 0x9690, 0x9C52, 0x9691, 0x685D, 0x9692, 0x4EA6, 0x9693, 0x4FE3, 0x9694, 0x53C8, 0x9695, 0x62B9, 0x9696, 0x672B, 0x9697, 0x6CAB, 0x9698, 0x8FC4, 0x9699, 0x4FAD, 0x969A, 0x7E6D, 0x969B, 0x9EBF, 0x969C, 0x4E07, 0x969D, 0x6162, 0x969E, 0x6E80, 0x969F, 0x6F2B, 0x96A0, 0x8513, 0x96A1, 0x5473, 0x96A2, 0x672A, 0x96A3, 0x9B45, 0x96A4, 0x5DF3, 0x96A5, 0x7B95, 0x96A6, 0x5CAC, 0x96A7, 0x5BC6, 0x96A8, 0x871C, 0x96A9, 0x6E4A, 0x96AA, 0x84D1, 0x96AB, 0x7A14, 0x96AC, 0x8108, 0x96AD, 0x5999, 0x96AE, 0x7C8D, 0x96AF, 0x6C11, 0x96B0, 0x7720, 0x96B1, 0x52D9, 0x96B2, 0x5922, 0x96B3, 0x7121, 0x96B4, 0x725F, 0x96B5, 0x77DB, 0x96B6, 0x9727, 0x96B7, 0x9D61, 0x96B8, 0x690B, 0x96B9, 0x5A7F, 0x96BA, 0x5A18, 0x96BB, 0x51A5, 0x96BC, 0x540D, 0x96BD, 0x547D, 0x96BE, 0x660E, 0x96BF, 0x76DF, 0x96C0, 0x8FF7, 0x96C1, 0x9298, 0x96C2, 0x9CF4, 0x96C3, 0x59EA, 0x96C4, 0x725D, 0x96C5, 0x6EC5, 0x96C6, 0x514D, 0x96C7, 0x68C9, 0x96C8, 0x7DBF, 0x96C9, 0x7DEC, 0x96CA, 0x9762, 0x96CB, 0x9EBA, 0x96CC, 0x6478, 0x96CD, 0x6A21, 0x96CE, 0x8302, 0x96CF, 0x5984, 0x96D0, 0x5B5F, 0x96D1, 0x6BDB, 0x96D2, 0x731B, 0x96D3, 0x76F2, 0x96D4, 0x7DB2, 0x96D5, 0x8017, 0x96D6, 0x8499, 0x96D7, 0x5132, 0x96D8, 0x6728, 0x96D9, 0x9ED9, 0x96DA, 0x76EE, 0x96DB, 0x6762, 0x96DC, 0x52FF, 0x96DD, 0x9905, 0x96DE, 0x5C24, 0x96DF, 0x623B, 0x96E0, 0x7C7E, 0x96E1, 0x8CB0, 0x96E2, 0x554F, 0x96E3, 0x60B6, 0x96E4, 0x7D0B, 0x96E5, 0x9580, 0x96E6, 0x5301, 0x96E7, 0x4E5F, 0x96E8, 0x51B6, 0x96E9, 0x591C, 0x96EA, 0x723A, 0x96EB, 0x8036, 0x96EC, 0x91CE, 0x96ED, 0x5F25, 0x96EE, 0x77E2, 0x96EF, 0x5384, 0x96F0, 0x5F79, 0x96F1, 0x7D04, 0x96F2, 0x85AC, 0x96F3, 0x8A33, 0x96F4, 0x8E8D, 0x96F5, 0x9756, 0x96F6, 0x67F3, 0x96F7, 0x85AE, 0x96F8, 0x9453, 0x96F9, 0x6109, 0x96FA, 0x6108, 0x96FB, 0x6CB9, 0x96FC, 0x7652, 0x9740, 0x8AED, 0x9741, 0x8F38, 0x9742, 0x552F, 0x9743, 0x4F51, 0x9744, 0x512A, 0x9745, 0x52C7, 0x9746, 0x53CB, 0x9747, 0x5BA5, 0x9748, 0x5E7D, 0x9749, 0x60A0, 0x974A, 0x6182, 0x974B, 0x63D6, 0x974C, 0x6709, 0x974D, 0x67DA, 0x974E, 0x6E67, 0x974F, 0x6D8C, 0x9750, 0x7336, 0x9751, 0x7337, 0x9752, 0x7531, 0x9753, 0x7950, 0x9754, 0x88D5, 0x9755, 0x8A98, 0x9756, 0x904A, 0x9757, 0x9091, 0x9758, 0x90F5, 0x9759, 0x96C4, 0x975A, 0x878D, 0x975B, 0x5915, 0x975C, 0x4E88, 0x975D, 0x4F59, 0x975E, 0x4E0E, 0x975F, 0x8A89, 0x9760, 0x8F3F, 0x9761, 0x9810, 0x9762, 0x50AD, 0x9763, 0x5E7C, 0x9764, 0x5996, 0x9765, 0x5BB9, 0x9766, 0x5EB8, 0x9767, 0x63DA, 0x9768, 0x63FA, 0x9769, 0x64C1, 0x976A, 0x66DC, 0x976B, 0x694A, 0x976C, 0x69D8, 0x976D, 0x6D0B, 0x976E, 0x6EB6, 0x976F, 0x7194, 0x9770, 0x7528, 0x9771, 0x7AAF, 0x9772, 0x7F8A, 0x9773, 0x8000, 0x9774, 0x8449, 0x9775, 0x84C9, 0x9776, 0x8981, 0x9777, 0x8B21, 0x9778, 0x8E0A, 0x9779, 0x9065, 0x977A, 0x967D, 0x977B, 0x990A, 0x977C, 0x617E, 0x977D, 0x6291, 0x977E, 0x6B32, 0x9780, 0x6C83, 0x9781, 0x6D74, 0x9782, 0x7FCC, 0x9783, 0x7FFC, 0x9784, 0x6DC0, 0x9785, 0x7F85, 0x9786, 0x87BA, 0x9787, 0x88F8, 0x9788, 0x6765, 0x9789, 0x83B1, 0x978A, 0x983C, 0x978B, 0x96F7, 0x978C, 0x6D1B, 0x978D, 0x7D61, 0x978E, 0x843D, 0x978F, 0x916A, 0x9790, 0x4E71, 0x9791, 0x5375, 0x9792, 0x5D50, 0x9793, 0x6B04, 0x9794, 0x6FEB, 0x9795, 0x85CD, 0x9796, 0x862D, 0x9797, 0x89A7, 0x9798, 0x5229, 0x9799, 0x540F, 0x979A, 0x5C65, 0x979B, 0x674E, 0x979C, 0x68A8, 0x979D, 0x7406, 0x979E, 0x7483, 0x979F, 0x75E2, 0x97A0, 0x88CF, 0x97A1, 0x88E1, 0x97A2, 0x91CC, 0x97A3, 0x96E2, 0x97A4, 0x9678, 0x97A5, 0x5F8B, 0x97A6, 0x7387, 0x97A7, 0x7ACB, 0x97A8, 0x844E, 0x97A9, 0x63A0, 0x97AA, 0x7565, 0x97AB, 0x5289, 0x97AC, 0x6D41, 0x97AD, 0x6E9C, 0x97AE, 0x7409, 0x97AF, 0x7559, 0x97B0, 0x786B, 0x97B1, 0x7C92, 0x97B2, 0x9686, 0x97B3, 0x7ADC, 0x97B4, 0x9F8D, 0x97B5, 0x4FB6, 0x97B6, 0x616E, 0x97B7, 0x65C5, 0x97B8, 0x865C, 0x97B9, 0x4E86, 0x97BA, 0x4EAE, 0x97BB, 0x50DA, 0x97BC, 0x4E21, 0x97BD, 0x51CC, 0x97BE, 0x5BEE, 0x97BF, 0x6599, 0x97C0, 0x6881, 0x97C1, 0x6DBC, 0x97C2, 0x731F, 0x97C3, 0x7642, 0x97C4, 0x77AD, 0x97C5, 0x7A1C, 0x97C6, 0x7CE7, 0x97C7, 0x826F, 0x97C8, 0x8AD2, 0x97C9, 0x907C, 0x97CA, 0x91CF, 0x97CB, 0x9675, 0x97CC, 0x9818, 0x97CD, 0x529B, 0x97CE, 0x7DD1, 0x97CF, 0x502B, 0x97D0, 0x5398, 0x97D1, 0x6797, 0x97D2, 0x6DCB, 0x97D3, 0x71D0, 0x97D4, 0x7433, 0x97D5, 0x81E8, 0x97D6, 0x8F2A, 0x97D7, 0x96A3, 0x97D8, 0x9C57, 0x97D9, 0x9E9F, 0x97DA, 0x7460, 0x97DB, 0x5841, 0x97DC, 0x6D99, 0x97DD, 0x7D2F, 0x97DE, 0x985E, 0x97DF, 0x4EE4, 0x97E0, 0x4F36, 0x97E1, 0x4F8B, 0x97E2, 0x51B7, 0x97E3, 0x52B1, 0x97E4, 0x5DBA, 0x97E5, 0x601C, 0x97E6, 0x73B2, 0x97E7, 0x793C, 0x97E8, 0x82D3, 0x97E9, 0x9234, 0x97EA, 0x96B7, 0x97EB, 0x96F6, 0x97EC, 0x970A, 0x97ED, 0x9E97, 0x97EE, 0x9F62, 0x97EF, 0x66A6, 0x97F0, 0x6B74, 0x97F1, 0x5217, 0x97F2, 0x52A3, 0x97F3, 0x70C8, 0x97F4, 0x88C2, 0x97F5, 0x5EC9, 0x97F6, 0x604B, 0x97F7, 0x6190, 0x97F8, 0x6F23, 0x97F9, 0x7149, 0x97FA, 0x7C3E, 0x97FB, 0x7DF4, 0x97FC, 0x806F, 0x9840, 0x84EE, 0x9841, 0x9023, 0x9842, 0x932C, 0x9843, 0x5442, 0x9844, 0x9B6F, 0x9845, 0x6AD3, 0x9846, 0x7089, 0x9847, 0x8CC2, 0x9848, 0x8DEF, 0x9849, 0x9732, 0x984A, 0x52B4, 0x984B, 0x5A41, 0x984C, 0x5ECA, 0x984D, 0x5F04, 0x984E, 0x6717, 0x984F, 0x697C, 0x9850, 0x6994, 0x9851, 0x6D6A, 0x9852, 0x6F0F, 0x9853, 0x7262, 0x9854, 0x72FC, 0x9855, 0x7BED, 0x9856, 0x8001, 0x9857, 0x807E, 0x9858, 0x874B, 0x9859, 0x90CE, 0x985A, 0x516D, 0x985B, 0x9E93, 0x985C, 0x7984, 0x985D, 0x808B, 0x985E, 0x9332, 0x985F, 0x8AD6, 0x9860, 0x502D, 0x9861, 0x548C, 0x9862, 0x8A71, 0x9863, 0x6B6A, 0x9864, 0x8CC4, 0x9865, 0x8107, 0x9866, 0x60D1, 0x9867, 0x67A0, 0x9868, 0x9DF2, 0x9869, 0x4E99, 0x986A, 0x4E98, 0x986B, 0x9C10, 0x986C, 0x8A6B, 0x986D, 0x85C1, 0x986E, 0x8568, 0x986F, 0x6900, 0x9870, 0x6E7E, 0x9871, 0x7897, 0x9872, 0x8155, 0x989F, 0x5F0C, 0x98A0, 0x4E10, 0x98A1, 0x4E15, 0x98A2, 0x4E2A, 0x98A3, 0x4E31, 0x98A4, 0x4E36, 0x98A5, 0x4E3C, 0x98A6, 0x4E3F, 0x98A7, 0x4E42, 0x98A8, 0x4E56, 0x98A9, 0x4E58, 0x98AA, 0x4E82, 0x98AB, 0x4E85, 0x98AC, 0x8C6B, 0x98AD, 0x4E8A, 0x98AE, 0x8212, 0x98AF, 0x5F0D, 0x98B0, 0x4E8E, 0x98B1, 0x4E9E, 0x98B2, 0x4E9F, 0x98B3, 0x4EA0, 0x98B4, 0x4EA2, 0x98B5, 0x4EB0, 0x98B6, 0x4EB3, 0x98B7, 0x4EB6, 0x98B8, 0x4ECE, 0x98B9, 0x4ECD, 0x98BA, 0x4EC4, 0x98BB, 0x4EC6, 0x98BC, 0x4EC2, 0x98BD, 0x4ED7, 0x98BE, 0x4EDE, 0x98BF, 0x4EED, 0x98C0, 0x4EDF, 0x98C1, 0x4EF7, 0x98C2, 0x4F09, 0x98C3, 0x4F5A, 0x98C4, 0x4F30, 0x98C5, 0x4F5B, 0x98C6, 0x4F5D, 0x98C7, 0x4F57, 0x98C8, 0x4F47, 0x98C9, 0x4F76, 0x98CA, 0x4F88, 0x98CB, 0x4F8F, 0x98CC, 0x4F98, 0x98CD, 0x4F7B, 0x98CE, 0x4F69, 0x98CF, 0x4F70, 0x98D0, 0x4F91, 0x98D1, 0x4F6F, 0x98D2, 0x4F86, 0x98D3, 0x4F96, 0x98D4, 0x5118, 0x98D5, 0x4FD4, 0x98D6, 0x4FDF, 0x98D7, 0x4FCE, 0x98D8, 0x4FD8, 0x98D9, 0x4FDB, 0x98DA, 0x4FD1, 0x98DB, 0x4FDA, 0x98DC, 0x4FD0, 0x98DD, 0x4FE4, 0x98DE, 0x4FE5, 0x98DF, 0x501A, 0x98E0, 0x5028, 0x98E1, 0x5014, 0x98E2, 0x502A, 0x98E3, 0x5025, 0x98E4, 0x5005, 0x98E5, 0x4F1C, 0x98E6, 0x4FF6, 0x98E7, 0x5021, 0x98E8, 0x5029, 0x98E9, 0x502C, 0x98EA, 0x4FFE, 0x98EB, 0x4FEF, 0x98EC, 0x5011, 0x98ED, 0x5006, 0x98EE, 0x5043, 0x98EF, 0x5047, 0x98F0, 0x6703, 0x98F1, 0x5055, 0x98F2, 0x5050, 0x98F3, 0x5048, 0x98F4, 0x505A, 0x98F5, 0x5056, 0x98F6, 0x506C, 0x98F7, 0x5078, 0x98F8, 0x5080, 0x98F9, 0x509A, 0x98FA, 0x5085, 0x98FB, 0x50B4, 0x98FC, 0x50B2, 0x9940, 0x50C9, 0x9941, 0x50CA, 0x9942, 0x50B3, 0x9943, 0x50C2, 0x9944, 0x50D6, 0x9945, 0x50DE, 0x9946, 0x50E5, 0x9947, 0x50ED, 0x9948, 0x50E3, 0x9949, 0x50EE, 0x994A, 0x50F9, 0x994B, 0x50F5, 0x994C, 0x5109, 0x994D, 0x5101, 0x994E, 0x5102, 0x994F, 0x5116, 0x9950, 0x5115, 0x9951, 0x5114, 0x9952, 0x511A, 0x9953, 0x5121, 0x9954, 0x513A, 0x9955, 0x5137, 0x9956, 0x513C, 0x9957, 0x513B, 0x9958, 0x513F, 0x9959, 0x5140, 0x995A, 0x5152, 0x995B, 0x514C, 0x995C, 0x5154, 0x995D, 0x5162, 0x995E, 0x7AF8, 0x995F, 0x5169, 0x9960, 0x516A, 0x9961, 0x516E, 0x9962, 0x5180, 0x9963, 0x5182, 0x9964, 0x56D8, 0x9965, 0x518C, 0x9966, 0x5189, 0x9967, 0x518F, 0x9968, 0x5191, 0x9969, 0x5193, 0x996A, 0x5195, 0x996B, 0x5196, 0x996C, 0x51A4, 0x996D, 0x51A6, 0x996E, 0x51A2, 0x996F, 0x51A9, 0x9970, 0x51AA, 0x9971, 0x51AB, 0x9972, 0x51B3, 0x9973, 0x51B1, 0x9974, 0x51B2, 0x9975, 0x51B0, 0x9976, 0x51B5, 0x9977, 0x51BD, 0x9978, 0x51C5, 0x9979, 0x51C9, 0x997A, 0x51DB, 0x997B, 0x51E0, 0x997C, 0x8655, 0x997D, 0x51E9, 0x997E, 0x51ED, 0x9980, 0x51F0, 0x9981, 0x51F5, 0x9982, 0x51FE, 0x9983, 0x5204, 0x9984, 0x520B, 0x9985, 0x5214, 0x9986, 0x520E, 0x9987, 0x5227, 0x9988, 0x522A, 0x9989, 0x522E, 0x998A, 0x5233, 0x998B, 0x5239, 0x998C, 0x524F, 0x998D, 0x5244, 0x998E, 0x524B, 0x998F, 0x524C, 0x9990, 0x525E, 0x9991, 0x5254, 0x9992, 0x526A, 0x9993, 0x5274, 0x9994, 0x5269, 0x9995, 0x5273, 0x9996, 0x527F, 0x9997, 0x527D, 0x9998, 0x528D, 0x9999, 0x5294, 0x999A, 0x5292, 0x999B, 0x5271, 0x999C, 0x5288, 0x999D, 0x5291, 0x999E, 0x8FA8, 0x999F, 0x8FA7, 0x99A0, 0x52AC, 0x99A1, 0x52AD, 0x99A2, 0x52BC, 0x99A3, 0x52B5, 0x99A4, 0x52C1, 0x99A5, 0x52CD, 0x99A6, 0x52D7, 0x99A7, 0x52DE, 0x99A8, 0x52E3, 0x99A9, 0x52E6, 0x99AA, 0x98ED, 0x99AB, 0x52E0, 0x99AC, 0x52F3, 0x99AD, 0x52F5, 0x99AE, 0x52F8, 0x99AF, 0x52F9, 0x99B0, 0x5306, 0x99B1, 0x5308, 0x99B2, 0x7538, 0x99B3, 0x530D, 0x99B4, 0x5310, 0x99B5, 0x530F, 0x99B6, 0x5315, 0x99B7, 0x531A, 0x99B8, 0x5323, 0x99B9, 0x532F, 0x99BA, 0x5331, 0x99BB, 0x5333, 0x99BC, 0x5338, 0x99BD, 0x5340, 0x99BE, 0x5346, 0x99BF, 0x5345, 0x99C0, 0x4E17, 0x99C1, 0x5349, 0x99C2, 0x534D, 0x99C3, 0x51D6, 0x99C4, 0x535E, 0x99C5, 0x5369, 0x99C6, 0x536E, 0x99C7, 0x5918, 0x99C8, 0x537B, 0x99C9, 0x5377, 0x99CA, 0x5382, 0x99CB, 0x5396, 0x99CC, 0x53A0, 0x99CD, 0x53A6, 0x99CE, 0x53A5, 0x99CF, 0x53AE, 0x99D0, 0x53B0, 0x99D1, 0x53B6, 0x99D2, 0x53C3, 0x99D3, 0x7C12, 0x99D4, 0x96D9, 0x99D5, 0x53DF, 0x99D6, 0x66FC, 0x99D7, 0x71EE, 0x99D8, 0x53EE, 0x99D9, 0x53E8, 0x99DA, 0x53ED, 0x99DB, 0x53FA, 0x99DC, 0x5401, 0x99DD, 0x543D, 0x99DE, 0x5440, 0x99DF, 0x542C, 0x99E0, 0x542D, 0x99E1, 0x543C, 0x99E2, 0x542E, 0x99E3, 0x5436, 0x99E4, 0x5429, 0x99E5, 0x541D, 0x99E6, 0x544E, 0x99E7, 0x548F, 0x99E8, 0x5475, 0x99E9, 0x548E, 0x99EA, 0x545F, 0x99EB, 0x5471, 0x99EC, 0x5477, 0x99ED, 0x5470, 0x99EE, 0x5492, 0x99EF, 0x547B, 0x99F0, 0x5480, 0x99F1, 0x5476, 0x99F2, 0x5484, 0x99F3, 0x5490, 0x99F4, 0x5486, 0x99F5, 0x54C7, 0x99F6, 0x54A2, 0x99F7, 0x54B8, 0x99F8, 0x54A5, 0x99F9, 0x54AC, 0x99FA, 0x54C4, 0x99FB, 0x54C8, 0x99FC, 0x54A8, 0x9A40, 0x54AB, 0x9A41, 0x54C2, 0x9A42, 0x54A4, 0x9A43, 0x54BE, 0x9A44, 0x54BC, 0x9A45, 0x54D8, 0x9A46, 0x54E5, 0x9A47, 0x54E6, 0x9A48, 0x550F, 0x9A49, 0x5514, 0x9A4A, 0x54FD, 0x9A4B, 0x54EE, 0x9A4C, 0x54ED, 0x9A4D, 0x54FA, 0x9A4E, 0x54E2, 0x9A4F, 0x5539, 0x9A50, 0x5540, 0x9A51, 0x5563, 0x9A52, 0x554C, 0x9A53, 0x552E, 0x9A54, 0x555C, 0x9A55, 0x5545, 0x9A56, 0x5556, 0x9A57, 0x5557, 0x9A58, 0x5538, 0x9A59, 0x5533, 0x9A5A, 0x555D, 0x9A5B, 0x5599, 0x9A5C, 0x5580, 0x9A5D, 0x54AF, 0x9A5E, 0x558A, 0x9A5F, 0x559F, 0x9A60, 0x557B, 0x9A61, 0x557E, 0x9A62, 0x5598, 0x9A63, 0x559E, 0x9A64, 0x55AE, 0x9A65, 0x557C, 0x9A66, 0x5583, 0x9A67, 0x55A9, 0x9A68, 0x5587, 0x9A69, 0x55A8, 0x9A6A, 0x55DA, 0x9A6B, 0x55C5, 0x9A6C, 0x55DF, 0x9A6D, 0x55C4, 0x9A6E, 0x55DC, 0x9A6F, 0x55E4, 0x9A70, 0x55D4, 0x9A71, 0x5614, 0x9A72, 0x55F7, 0x9A73, 0x5616, 0x9A74, 0x55FE, 0x9A75, 0x55FD, 0x9A76, 0x561B, 0x9A77, 0x55F9, 0x9A78, 0x564E, 0x9A79, 0x5650, 0x9A7A, 0x71DF, 0x9A7B, 0x5634, 0x9A7C, 0x5636, 0x9A7D, 0x5632, 0x9A7E, 0x5638, 0x9A80, 0x566B, 0x9A81, 0x5664, 0x9A82, 0x562F, 0x9A83, 0x566C, 0x9A84, 0x566A, 0x9A85, 0x5686, 0x9A86, 0x5680, 0x9A87, 0x568A, 0x9A88, 0x56A0, 0x9A89, 0x5694, 0x9A8A, 0x568F, 0x9A8B, 0x56A5, 0x9A8C, 0x56AE, 0x9A8D, 0x56B6, 0x9A8E, 0x56B4, 0x9A8F, 0x56C2, 0x9A90, 0x56BC, 0x9A91, 0x56C1, 0x9A92, 0x56C3, 0x9A93, 0x56C0, 0x9A94, 0x56C8, 0x9A95, 0x56CE, 0x9A96, 0x56D1, 0x9A97, 0x56D3, 0x9A98, 0x56D7, 0x9A99, 0x56EE, 0x9A9A, 0x56F9, 0x9A9B, 0x5700, 0x9A9C, 0x56FF, 0x9A9D, 0x5704, 0x9A9E, 0x5709, 0x9A9F, 0x5708, 0x9AA0, 0x570B, 0x9AA1, 0x570D, 0x9AA2, 0x5713, 0x9AA3, 0x5718, 0x9AA4, 0x5716, 0x9AA5, 0x55C7, 0x9AA6, 0x571C, 0x9AA7, 0x5726, 0x9AA8, 0x5737, 0x9AA9, 0x5738, 0x9AAA, 0x574E, 0x9AAB, 0x573B, 0x9AAC, 0x5740, 0x9AAD, 0x574F, 0x9AAE, 0x5769, 0x9AAF, 0x57C0, 0x9AB0, 0x5788, 0x9AB1, 0x5761, 0x9AB2, 0x577F, 0x9AB3, 0x5789, 0x9AB4, 0x5793, 0x9AB5, 0x57A0, 0x9AB6, 0x57B3, 0x9AB7, 0x57A4, 0x9AB8, 0x57AA, 0x9AB9, 0x57B0, 0x9ABA, 0x57C3, 0x9ABB, 0x57C6, 0x9ABC, 0x57D4, 0x9ABD, 0x57D2, 0x9ABE, 0x57D3, 0x9ABF, 0x580A, 0x9AC0, 0x57D6, 0x9AC1, 0x57E3, 0x9AC2, 0x580B, 0x9AC3, 0x5819, 0x9AC4, 0x581D, 0x9AC5, 0x5872, 0x9AC6, 0x5821, 0x9AC7, 0x5862, 0x9AC8, 0x584B, 0x9AC9, 0x5870, 0x9ACA, 0x6BC0, 0x9ACB, 0x5852, 0x9ACC, 0x583D, 0x9ACD, 0x5879, 0x9ACE, 0x5885, 0x9ACF, 0x58B9, 0x9AD0, 0x589F, 0x9AD1, 0x58AB, 0x9AD2, 0x58BA, 0x9AD3, 0x58DE, 0x9AD4, 0x58BB, 0x9AD5, 0x58B8, 0x9AD6, 0x58AE, 0x9AD7, 0x58C5, 0x9AD8, 0x58D3, 0x9AD9, 0x58D1, 0x9ADA, 0x58D7, 0x9ADB, 0x58D9, 0x9ADC, 0x58D8, 0x9ADD, 0x58E5, 0x9ADE, 0x58DC, 0x9ADF, 0x58E4, 0x9AE0, 0x58DF, 0x9AE1, 0x58EF, 0x9AE2, 0x58FA, 0x9AE3, 0x58F9, 0x9AE4, 0x58FB, 0x9AE5, 0x58FC, 0x9AE6, 0x58FD, 0x9AE7, 0x5902, 0x9AE8, 0x590A, 0x9AE9, 0x5910, 0x9AEA, 0x591B, 0x9AEB, 0x68A6, 0x9AEC, 0x5925, 0x9AED, 0x592C, 0x9AEE, 0x592D, 0x9AEF, 0x5932, 0x9AF0, 0x5938, 0x9AF1, 0x593E, 0x9AF2, 0x7AD2, 0x9AF3, 0x5955, 0x9AF4, 0x5950, 0x9AF5, 0x594E, 0x9AF6, 0x595A, 0x9AF7, 0x5958, 0x9AF8, 0x5962, 0x9AF9, 0x5960, 0x9AFA, 0x5967, 0x9AFB, 0x596C, 0x9AFC, 0x5969, 0x9B40, 0x5978, 0x9B41, 0x5981, 0x9B42, 0x599D, 0x9B43, 0x4F5E, 0x9B44, 0x4FAB, 0x9B45, 0x59A3, 0x9B46, 0x59B2, 0x9B47, 0x59C6, 0x9B48, 0x59E8, 0x9B49, 0x59DC, 0x9B4A, 0x598D, 0x9B4B, 0x59D9, 0x9B4C, 0x59DA, 0x9B4D, 0x5A25, 0x9B4E, 0x5A1F, 0x9B4F, 0x5A11, 0x9B50, 0x5A1C, 0x9B51, 0x5A09, 0x9B52, 0x5A1A, 0x9B53, 0x5A40, 0x9B54, 0x5A6C, 0x9B55, 0x5A49, 0x9B56, 0x5A35, 0x9B57, 0x5A36, 0x9B58, 0x5A62, 0x9B59, 0x5A6A, 0x9B5A, 0x5A9A, 0x9B5B, 0x5ABC, 0x9B5C, 0x5ABE, 0x9B5D, 0x5ACB, 0x9B5E, 0x5AC2, 0x9B5F, 0x5ABD, 0x9B60, 0x5AE3, 0x9B61, 0x5AD7, 0x9B62, 0x5AE6, 0x9B63, 0x5AE9, 0x9B64, 0x5AD6, 0x9B65, 0x5AFA, 0x9B66, 0x5AFB, 0x9B67, 0x5B0C, 0x9B68, 0x5B0B, 0x9B69, 0x5B16, 0x9B6A, 0x5B32, 0x9B6B, 0x5AD0, 0x9B6C, 0x5B2A, 0x9B6D, 0x5B36, 0x9B6E, 0x5B3E, 0x9B6F, 0x5B43, 0x9B70, 0x5B45, 0x9B71, 0x5B40, 0x9B72, 0x5B51, 0x9B73, 0x5B55, 0x9B74, 0x5B5A, 0x9B75, 0x5B5B, 0x9B76, 0x5B65, 0x9B77, 0x5B69, 0x9B78, 0x5B70, 0x9B79, 0x5B73, 0x9B7A, 0x5B75, 0x9B7B, 0x5B78, 0x9B7C, 0x6588, 0x9B7D, 0x5B7A, 0x9B7E, 0x5B80, 0x9B80, 0x5B83, 0x9B81, 0x5BA6, 0x9B82, 0x5BB8, 0x9B83, 0x5BC3, 0x9B84, 0x5BC7, 0x9B85, 0x5BC9, 0x9B86, 0x5BD4, 0x9B87, 0x5BD0, 0x9B88, 0x5BE4, 0x9B89, 0x5BE6, 0x9B8A, 0x5BE2, 0x9B8B, 0x5BDE, 0x9B8C, 0x5BE5, 0x9B8D, 0x5BEB, 0x9B8E, 0x5BF0, 0x9B8F, 0x5BF6, 0x9B90, 0x5BF3, 0x9B91, 0x5C05, 0x9B92, 0x5C07, 0x9B93, 0x5C08, 0x9B94, 0x5C0D, 0x9B95, 0x5C13, 0x9B96, 0x5C20, 0x9B97, 0x5C22, 0x9B98, 0x5C28, 0x9B99, 0x5C38, 0x9B9A, 0x5C39, 0x9B9B, 0x5C41, 0x9B9C, 0x5C46, 0x9B9D, 0x5C4E, 0x9B9E, 0x5C53, 0x9B9F, 0x5C50, 0x9BA0, 0x5C4F, 0x9BA1, 0x5B71, 0x9BA2, 0x5C6C, 0x9BA3, 0x5C6E, 0x9BA4, 0x4E62, 0x9BA5, 0x5C76, 0x9BA6, 0x5C79, 0x9BA7, 0x5C8C, 0x9BA8, 0x5C91, 0x9BA9, 0x5C94, 0x9BAA, 0x599B, 0x9BAB, 0x5CAB, 0x9BAC, 0x5CBB, 0x9BAD, 0x5CB6, 0x9BAE, 0x5CBC, 0x9BAF, 0x5CB7, 0x9BB0, 0x5CC5, 0x9BB1, 0x5CBE, 0x9BB2, 0x5CC7, 0x9BB3, 0x5CD9, 0x9BB4, 0x5CE9, 0x9BB5, 0x5CFD, 0x9BB6, 0x5CFA, 0x9BB7, 0x5CED, 0x9BB8, 0x5D8C, 0x9BB9, 0x5CEA, 0x9BBA, 0x5D0B, 0x9BBB, 0x5D15, 0x9BBC, 0x5D17, 0x9BBD, 0x5D5C, 0x9BBE, 0x5D1F, 0x9BBF, 0x5D1B, 0x9BC0, 0x5D11, 0x9BC1, 0x5D14, 0x9BC2, 0x5D22, 0x9BC3, 0x5D1A, 0x9BC4, 0x5D19, 0x9BC5, 0x5D18, 0x9BC6, 0x5D4C, 0x9BC7, 0x5D52, 0x9BC8, 0x5D4E, 0x9BC9, 0x5D4B, 0x9BCA, 0x5D6C, 0x9BCB, 0x5D73, 0x9BCC, 0x5D76, 0x9BCD, 0x5D87, 0x9BCE, 0x5D84, 0x9BCF, 0x5D82, 0x9BD0, 0x5DA2, 0x9BD1, 0x5D9D, 0x9BD2, 0x5DAC, 0x9BD3, 0x5DAE, 0x9BD4, 0x5DBD, 0x9BD5, 0x5D90, 0x9BD6, 0x5DB7, 0x9BD7, 0x5DBC, 0x9BD8, 0x5DC9, 0x9BD9, 0x5DCD, 0x9BDA, 0x5DD3, 0x9BDB, 0x5DD2, 0x9BDC, 0x5DD6, 0x9BDD, 0x5DDB, 0x9BDE, 0x5DEB, 0x9BDF, 0x5DF2, 0x9BE0, 0x5DF5, 0x9BE1, 0x5E0B, 0x9BE2, 0x5E1A, 0x9BE3, 0x5E19, 0x9BE4, 0x5E11, 0x9BE5, 0x5E1B, 0x9BE6, 0x5E36, 0x9BE7, 0x5E37, 0x9BE8, 0x5E44, 0x9BE9, 0x5E43, 0x9BEA, 0x5E40, 0x9BEB, 0x5E4E, 0x9BEC, 0x5E57, 0x9BED, 0x5E54, 0x9BEE, 0x5E5F, 0x9BEF, 0x5E62, 0x9BF0, 0x5E64, 0x9BF1, 0x5E47, 0x9BF2, 0x5E75, 0x9BF3, 0x5E76, 0x9BF4, 0x5E7A, 0x9BF5, 0x9EBC, 0x9BF6, 0x5E7F, 0x9BF7, 0x5EA0, 0x9BF8, 0x5EC1, 0x9BF9, 0x5EC2, 0x9BFA, 0x5EC8, 0x9BFB, 0x5ED0, 0x9BFC, 0x5ECF, 0x9C40, 0x5ED6, 0x9C41, 0x5EE3, 0x9C42, 0x5EDD, 0x9C43, 0x5EDA, 0x9C44, 0x5EDB, 0x9C45, 0x5EE2, 0x9C46, 0x5EE1, 0x9C47, 0x5EE8, 0x9C48, 0x5EE9, 0x9C49, 0x5EEC, 0x9C4A, 0x5EF1, 0x9C4B, 0x5EF3, 0x9C4C, 0x5EF0, 0x9C4D, 0x5EF4, 0x9C4E, 0x5EF8, 0x9C4F, 0x5EFE, 0x9C50, 0x5F03, 0x9C51, 0x5F09, 0x9C52, 0x5F5D, 0x9C53, 0x5F5C, 0x9C54, 0x5F0B, 0x9C55, 0x5F11, 0x9C56, 0x5F16, 0x9C57, 0x5F29, 0x9C58, 0x5F2D, 0x9C59, 0x5F38, 0x9C5A, 0x5F41, 0x9C5B, 0x5F48, 0x9C5C, 0x5F4C, 0x9C5D, 0x5F4E, 0x9C5E, 0x5F2F, 0x9C5F, 0x5F51, 0x9C60, 0x5F56, 0x9C61, 0x5F57, 0x9C62, 0x5F59, 0x9C63, 0x5F61, 0x9C64, 0x5F6D, 0x9C65, 0x5F73, 0x9C66, 0x5F77, 0x9C67, 0x5F83, 0x9C68, 0x5F82, 0x9C69, 0x5F7F, 0x9C6A, 0x5F8A, 0x9C6B, 0x5F88, 0x9C6C, 0x5F91, 0x9C6D, 0x5F87, 0x9C6E, 0x5F9E, 0x9C6F, 0x5F99, 0x9C70, 0x5F98, 0x9C71, 0x5FA0, 0x9C72, 0x5FA8, 0x9C73, 0x5FAD, 0x9C74, 0x5FBC, 0x9C75, 0x5FD6, 0x9C76, 0x5FFB, 0x9C77, 0x5FE4, 0x9C78, 0x5FF8, 0x9C79, 0x5FF1, 0x9C7A, 0x5FDD, 0x9C7B, 0x60B3, 0x9C7C, 0x5FFF, 0x9C7D, 0x6021, 0x9C7E, 0x6060, 0x9C80, 0x6019, 0x9C81, 0x6010, 0x9C82, 0x6029, 0x9C83, 0x600E, 0x9C84, 0x6031, 0x9C85, 0x601B, 0x9C86, 0x6015, 0x9C87, 0x602B, 0x9C88, 0x6026, 0x9C89, 0x600F, 0x9C8A, 0x603A, 0x9C8B, 0x605A, 0x9C8C, 0x6041, 0x9C8D, 0x606A, 0x9C8E, 0x6077, 0x9C8F, 0x605F, 0x9C90, 0x604A, 0x9C91, 0x6046, 0x9C92, 0x604D, 0x9C93, 0x6063, 0x9C94, 0x6043, 0x9C95, 0x6064, 0x9C96, 0x6042, 0x9C97, 0x606C, 0x9C98, 0x606B, 0x9C99, 0x6059, 0x9C9A, 0x6081, 0x9C9B, 0x608D, 0x9C9C, 0x60E7, 0x9C9D, 0x6083, 0x9C9E, 0x609A, 0x9C9F, 0x6084, 0x9CA0, 0x609B, 0x9CA1, 0x6096, 0x9CA2, 0x6097, 0x9CA3, 0x6092, 0x9CA4, 0x60A7, 0x9CA5, 0x608B, 0x9CA6, 0x60E1, 0x9CA7, 0x60B8, 0x9CA8, 0x60E0, 0x9CA9, 0x60D3, 0x9CAA, 0x60B4, 0x9CAB, 0x5FF0, 0x9CAC, 0x60BD, 0x9CAD, 0x60C6, 0x9CAE, 0x60B5, 0x9CAF, 0x60D8, 0x9CB0, 0x614D, 0x9CB1, 0x6115, 0x9CB2, 0x6106, 0x9CB3, 0x60F6, 0x9CB4, 0x60F7, 0x9CB5, 0x6100, 0x9CB6, 0x60F4, 0x9CB7, 0x60FA, 0x9CB8, 0x6103, 0x9CB9, 0x6121, 0x9CBA, 0x60FB, 0x9CBB, 0x60F1, 0x9CBC, 0x610D, 0x9CBD, 0x610E, 0x9CBE, 0x6147, 0x9CBF, 0x613E, 0x9CC0, 0x6128, 0x9CC1, 0x6127, 0x9CC2, 0x614A, 0x9CC3, 0x613F, 0x9CC4, 0x613C, 0x9CC5, 0x612C, 0x9CC6, 0x6134, 0x9CC7, 0x613D, 0x9CC8, 0x6142, 0x9CC9, 0x6144, 0x9CCA, 0x6173, 0x9CCB, 0x6177, 0x9CCC, 0x6158, 0x9CCD, 0x6159, 0x9CCE, 0x615A, 0x9CCF, 0x616B, 0x9CD0, 0x6174, 0x9CD1, 0x616F, 0x9CD2, 0x6165, 0x9CD3, 0x6171, 0x9CD4, 0x615F, 0x9CD5, 0x615D, 0x9CD6, 0x6153, 0x9CD7, 0x6175, 0x9CD8, 0x6199, 0x9CD9, 0x6196, 0x9CDA, 0x6187, 0x9CDB, 0x61AC, 0x9CDC, 0x6194, 0x9CDD, 0x619A, 0x9CDE, 0x618A, 0x9CDF, 0x6191, 0x9CE0, 0x61AB, 0x9CE1, 0x61AE, 0x9CE2, 0x61CC, 0x9CE3, 0x61CA, 0x9CE4, 0x61C9, 0x9CE5, 0x61F7, 0x9CE6, 0x61C8, 0x9CE7, 0x61C3, 0x9CE8, 0x61C6, 0x9CE9, 0x61BA, 0x9CEA, 0x61CB, 0x9CEB, 0x7F79, 0x9CEC, 0x61CD, 0x9CED, 0x61E6, 0x9CEE, 0x61E3, 0x9CEF, 0x61F6, 0x9CF0, 0x61FA, 0x9CF1, 0x61F4, 0x9CF2, 0x61FF, 0x9CF3, 0x61FD, 0x9CF4, 0x61FC, 0x9CF5, 0x61FE, 0x9CF6, 0x6200, 0x9CF7, 0x6208, 0x9CF8, 0x6209, 0x9CF9, 0x620D, 0x9CFA, 0x620C, 0x9CFB, 0x6214, 0x9CFC, 0x621B, 0x9D40, 0x621E, 0x9D41, 0x6221, 0x9D42, 0x622A, 0x9D43, 0x622E, 0x9D44, 0x6230, 0x9D45, 0x6232, 0x9D46, 0x6233, 0x9D47, 0x6241, 0x9D48, 0x624E, 0x9D49, 0x625E, 0x9D4A, 0x6263, 0x9D4B, 0x625B, 0x9D4C, 0x6260, 0x9D4D, 0x6268, 0x9D4E, 0x627C, 0x9D4F, 0x6282, 0x9D50, 0x6289, 0x9D51, 0x627E, 0x9D52, 0x6292, 0x9D53, 0x6293, 0x9D54, 0x6296, 0x9D55, 0x62D4, 0x9D56, 0x6283, 0x9D57, 0x6294, 0x9D58, 0x62D7, 0x9D59, 0x62D1, 0x9D5A, 0x62BB, 0x9D5B, 0x62CF, 0x9D5C, 0x62FF, 0x9D5D, 0x62C6, 0x9D5E, 0x64D4, 0x9D5F, 0x62C8, 0x9D60, 0x62DC, 0x9D61, 0x62CC, 0x9D62, 0x62CA, 0x9D63, 0x62C2, 0x9D64, 0x62C7, 0x9D65, 0x629B, 0x9D66, 0x62C9, 0x9D67, 0x630C, 0x9D68, 0x62EE, 0x9D69, 0x62F1, 0x9D6A, 0x6327, 0x9D6B, 0x6302, 0x9D6C, 0x6308, 0x9D6D, 0x62EF, 0x9D6E, 0x62F5, 0x9D6F, 0x6350, 0x9D70, 0x633E, 0x9D71, 0x634D, 0x9D72, 0x641C, 0x9D73, 0x634F, 0x9D74, 0x6396, 0x9D75, 0x638E, 0x9D76, 0x6380, 0x9D77, 0x63AB, 0x9D78, 0x6376, 0x9D79, 0x63A3, 0x9D7A, 0x638F, 0x9D7B, 0x6389, 0x9D7C, 0x639F, 0x9D7D, 0x63B5, 0x9D7E, 0x636B, 0x9D80, 0x6369, 0x9D81, 0x63BE, 0x9D82, 0x63E9, 0x9D83, 0x63C0, 0x9D84, 0x63C6, 0x9D85, 0x63E3, 0x9D86, 0x63C9, 0x9D87, 0x63D2, 0x9D88, 0x63F6, 0x9D89, 0x63C4, 0x9D8A, 0x6416, 0x9D8B, 0x6434, 0x9D8C, 0x6406, 0x9D8D, 0x6413, 0x9D8E, 0x6426, 0x9D8F, 0x6436, 0x9D90, 0x651D, 0x9D91, 0x6417, 0x9D92, 0x6428, 0x9D93, 0x640F, 0x9D94, 0x6467, 0x9D95, 0x646F, 0x9D96, 0x6476, 0x9D97, 0x644E, 0x9D98, 0x652A, 0x9D99, 0x6495, 0x9D9A, 0x6493, 0x9D9B, 0x64A5, 0x9D9C, 0x64A9, 0x9D9D, 0x6488, 0x9D9E, 0x64BC, 0x9D9F, 0x64DA, 0x9DA0, 0x64D2, 0x9DA1, 0x64C5, 0x9DA2, 0x64C7, 0x9DA3, 0x64BB, 0x9DA4, 0x64D8, 0x9DA5, 0x64C2, 0x9DA6, 0x64F1, 0x9DA7, 0x64E7, 0x9DA8, 0x8209, 0x9DA9, 0x64E0, 0x9DAA, 0x64E1, 0x9DAB, 0x62AC, 0x9DAC, 0x64E3, 0x9DAD, 0x64EF, 0x9DAE, 0x652C, 0x9DAF, 0x64F6, 0x9DB0, 0x64F4, 0x9DB1, 0x64F2, 0x9DB2, 0x64FA, 0x9DB3, 0x6500, 0x9DB4, 0x64FD, 0x9DB5, 0x6518, 0x9DB6, 0x651C, 0x9DB7, 0x6505, 0x9DB8, 0x6524, 0x9DB9, 0x6523, 0x9DBA, 0x652B, 0x9DBB, 0x6534, 0x9DBC, 0x6535, 0x9DBD, 0x6537, 0x9DBE, 0x6536, 0x9DBF, 0x6538, 0x9DC0, 0x754B, 0x9DC1, 0x6548, 0x9DC2, 0x6556, 0x9DC3, 0x6555, 0x9DC4, 0x654D, 0x9DC5, 0x6558, 0x9DC6, 0x655E, 0x9DC7, 0x655D, 0x9DC8, 0x6572, 0x9DC9, 0x6578, 0x9DCA, 0x6582, 0x9DCB, 0x6583, 0x9DCC, 0x8B8A, 0x9DCD, 0x659B, 0x9DCE, 0x659F, 0x9DCF, 0x65AB, 0x9DD0, 0x65B7, 0x9DD1, 0x65C3, 0x9DD2, 0x65C6, 0x9DD3, 0x65C1, 0x9DD4, 0x65C4, 0x9DD5, 0x65CC, 0x9DD6, 0x65D2, 0x9DD7, 0x65DB, 0x9DD8, 0x65D9, 0x9DD9, 0x65E0, 0x9DDA, 0x65E1, 0x9DDB, 0x65F1, 0x9DDC, 0x6772, 0x9DDD, 0x660A, 0x9DDE, 0x6603, 0x9DDF, 0x65FB, 0x9DE0, 0x6773, 0x9DE1, 0x6635, 0x9DE2, 0x6636, 0x9DE3, 0x6634, 0x9DE4, 0x661C, 0x9DE5, 0x664F, 0x9DE6, 0x6644, 0x9DE7, 0x6649, 0x9DE8, 0x6641, 0x9DE9, 0x665E, 0x9DEA, 0x665D, 0x9DEB, 0x6664, 0x9DEC, 0x6667, 0x9DED, 0x6668, 0x9DEE, 0x665F, 0x9DEF, 0x6662, 0x9DF0, 0x6670, 0x9DF1, 0x6683, 0x9DF2, 0x6688, 0x9DF3, 0x668E, 0x9DF4, 0x6689, 0x9DF5, 0x6684, 0x9DF6, 0x6698, 0x9DF7, 0x669D, 0x9DF8, 0x66C1, 0x9DF9, 0x66B9, 0x9DFA, 0x66C9, 0x9DFB, 0x66BE, 0x9DFC, 0x66BC, 0x9E40, 0x66C4, 0x9E41, 0x66B8, 0x9E42, 0x66D6, 0x9E43, 0x66DA, 0x9E44, 0x66E0, 0x9E45, 0x663F, 0x9E46, 0x66E6, 0x9E47, 0x66E9, 0x9E48, 0x66F0, 0x9E49, 0x66F5, 0x9E4A, 0x66F7, 0x9E4B, 0x670F, 0x9E4C, 0x6716, 0x9E4D, 0x671E, 0x9E4E, 0x6726, 0x9E4F, 0x6727, 0x9E50, 0x9738, 0x9E51, 0x672E, 0x9E52, 0x673F, 0x9E53, 0x6736, 0x9E54, 0x6741, 0x9E55, 0x6738, 0x9E56, 0x6737, 0x9E57, 0x6746, 0x9E58, 0x675E, 0x9E59, 0x6760, 0x9E5A, 0x6759, 0x9E5B, 0x6763, 0x9E5C, 0x6764, 0x9E5D, 0x6789, 0x9E5E, 0x6770, 0x9E5F, 0x67A9, 0x9E60, 0x677C, 0x9E61, 0x676A, 0x9E62, 0x678C, 0x9E63, 0x678B, 0x9E64, 0x67A6, 0x9E65, 0x67A1, 0x9E66, 0x6785, 0x9E67, 0x67B7, 0x9E68, 0x67EF, 0x9E69, 0x67B4, 0x9E6A, 0x67EC, 0x9E6B, 0x67B3, 0x9E6C, 0x67E9, 0x9E6D, 0x67B8, 0x9E6E, 0x67E4, 0x9E6F, 0x67DE, 0x9E70, 0x67DD, 0x9E71, 0x67E2, 0x9E72, 0x67EE, 0x9E73, 0x67B9, 0x9E74, 0x67CE, 0x9E75, 0x67C6, 0x9E76, 0x67E7, 0x9E77, 0x6A9C, 0x9E78, 0x681E, 0x9E79, 0x6846, 0x9E7A, 0x6829, 0x9E7B, 0x6840, 0x9E7C, 0x684D, 0x9E7D, 0x6832, 0x9E7E, 0x684E, 0x9E80, 0x68B3, 0x9E81, 0x682B, 0x9E82, 0x6859, 0x9E83, 0x6863, 0x9E84, 0x6877, 0x9E85, 0x687F, 0x9E86, 0x689F, 0x9E87, 0x688F, 0x9E88, 0x68AD, 0x9E89, 0x6894, 0x9E8A, 0x689D, 0x9E8B, 0x689B, 0x9E8C, 0x6883, 0x9E8D, 0x6AAE, 0x9E8E, 0x68B9, 0x9E8F, 0x6874, 0x9E90, 0x68B5, 0x9E91, 0x68A0, 0x9E92, 0x68BA, 0x9E93, 0x690F, 0x9E94, 0x688D, 0x9E95, 0x687E, 0x9E96, 0x6901, 0x9E97, 0x68CA, 0x9E98, 0x6908, 0x9E99, 0x68D8, 0x9E9A, 0x6922, 0x9E9B, 0x6926, 0x9E9C, 0x68E1, 0x9E9D, 0x690C, 0x9E9E, 0x68CD, 0x9E9F, 0x68D4, 0x9EA0, 0x68E7, 0x9EA1, 0x68D5, 0x9EA2, 0x6936, 0x9EA3, 0x6912, 0x9EA4, 0x6904, 0x9EA5, 0x68D7, 0x9EA6, 0x68E3, 0x9EA7, 0x6925, 0x9EA8, 0x68F9, 0x9EA9, 0x68E0, 0x9EAA, 0x68EF, 0x9EAB, 0x6928, 0x9EAC, 0x692A, 0x9EAD, 0x691A, 0x9EAE, 0x6923, 0x9EAF, 0x6921, 0x9EB0, 0x68C6, 0x9EB1, 0x6979, 0x9EB2, 0x6977, 0x9EB3, 0x695C, 0x9EB4, 0x6978, 0x9EB5, 0x696B, 0x9EB6, 0x6954, 0x9EB7, 0x697E, 0x9EB8, 0x696E, 0x9EB9, 0x6939, 0x9EBA, 0x6974, 0x9EBB, 0x693D, 0x9EBC, 0x6959, 0x9EBD, 0x6930, 0x9EBE, 0x6961, 0x9EBF, 0x695E, 0x9EC0, 0x695D, 0x9EC1, 0x6981, 0x9EC2, 0x696A, 0x9EC3, 0x69B2, 0x9EC4, 0x69AE, 0x9EC5, 0x69D0, 0x9EC6, 0x69BF, 0x9EC7, 0x69C1, 0x9EC8, 0x69D3, 0x9EC9, 0x69BE, 0x9ECA, 0x69CE, 0x9ECB, 0x5BE8, 0x9ECC, 0x69CA, 0x9ECD, 0x69DD, 0x9ECE, 0x69BB, 0x9ECF, 0x69C3, 0x9ED0, 0x69A7, 0x9ED1, 0x6A2E, 0x9ED2, 0x6991, 0x9ED3, 0x69A0, 0x9ED4, 0x699C, 0x9ED5, 0x6995, 0x9ED6, 0x69B4, 0x9ED7, 0x69DE, 0x9ED8, 0x69E8, 0x9ED9, 0x6A02, 0x9EDA, 0x6A1B, 0x9EDB, 0x69FF, 0x9EDC, 0x6B0A, 0x9EDD, 0x69F9, 0x9EDE, 0x69F2, 0x9EDF, 0x69E7, 0x9EE0, 0x6A05, 0x9EE1, 0x69B1, 0x9EE2, 0x6A1E, 0x9EE3, 0x69ED, 0x9EE4, 0x6A14, 0x9EE5, 0x69EB, 0x9EE6, 0x6A0A, 0x9EE7, 0x6A12, 0x9EE8, 0x6AC1, 0x9EE9, 0x6A23, 0x9EEA, 0x6A13, 0x9EEB, 0x6A44, 0x9EEC, 0x6A0C, 0x9EED, 0x6A72, 0x9EEE, 0x6A36, 0x9EEF, 0x6A78, 0x9EF0, 0x6A47, 0x9EF1, 0x6A62, 0x9EF2, 0x6A59, 0x9EF3, 0x6A66, 0x9EF4, 0x6A48, 0x9EF5, 0x6A38, 0x9EF6, 0x6A22, 0x9EF7, 0x6A90, 0x9EF8, 0x6A8D, 0x9EF9, 0x6AA0, 0x9EFA, 0x6A84, 0x9EFB, 0x6AA2, 0x9EFC, 0x6AA3, 0x9F40, 0x6A97, 0x9F41, 0x8617, 0x9F42, 0x6ABB, 0x9F43, 0x6AC3, 0x9F44, 0x6AC2, 0x9F45, 0x6AB8, 0x9F46, 0x6AB3, 0x9F47, 0x6AAC, 0x9F48, 0x6ADE, 0x9F49, 0x6AD1, 0x9F4A, 0x6ADF, 0x9F4B, 0x6AAA, 0x9F4C, 0x6ADA, 0x9F4D, 0x6AEA, 0x9F4E, 0x6AFB, 0x9F4F, 0x6B05, 0x9F50, 0x8616, 0x9F51, 0x6AFA, 0x9F52, 0x6B12, 0x9F53, 0x6B16, 0x9F54, 0x9B31, 0x9F55, 0x6B1F, 0x9F56, 0x6B38, 0x9F57, 0x6B37, 0x9F58, 0x76DC, 0x9F59, 0x6B39, 0x9F5A, 0x98EE, 0x9F5B, 0x6B47, 0x9F5C, 0x6B43, 0x9F5D, 0x6B49, 0x9F5E, 0x6B50, 0x9F5F, 0x6B59, 0x9F60, 0x6B54, 0x9F61, 0x6B5B, 0x9F62, 0x6B5F, 0x9F63, 0x6B61, 0x9F64, 0x6B78, 0x9F65, 0x6B79, 0x9F66, 0x6B7F, 0x9F67, 0x6B80, 0x9F68, 0x6B84, 0x9F69, 0x6B83, 0x9F6A, 0x6B8D, 0x9F6B, 0x6B98, 0x9F6C, 0x6B95, 0x9F6D, 0x6B9E, 0x9F6E, 0x6BA4, 0x9F6F, 0x6BAA, 0x9F70, 0x6BAB, 0x9F71, 0x6BAF, 0x9F72, 0x6BB2, 0x9F73, 0x6BB1, 0x9F74, 0x6BB3, 0x9F75, 0x6BB7, 0x9F76, 0x6BBC, 0x9F77, 0x6BC6, 0x9F78, 0x6BCB, 0x9F79, 0x6BD3, 0x9F7A, 0x6BDF, 0x9F7B, 0x6BEC, 0x9F7C, 0x6BEB, 0x9F7D, 0x6BF3, 0x9F7E, 0x6BEF, 0x9F80, 0x9EBE, 0x9F81, 0x6C08, 0x9F82, 0x6C13, 0x9F83, 0x6C14, 0x9F84, 0x6C1B, 0x9F85, 0x6C24, 0x9F86, 0x6C23, 0x9F87, 0x6C5E, 0x9F88, 0x6C55, 0x9F89, 0x6C62, 0x9F8A, 0x6C6A, 0x9F8B, 0x6C82, 0x9F8C, 0x6C8D, 0x9F8D, 0x6C9A, 0x9F8E, 0x6C81, 0x9F8F, 0x6C9B, 0x9F90, 0x6C7E, 0x9F91, 0x6C68, 0x9F92, 0x6C73, 0x9F93, 0x6C92, 0x9F94, 0x6C90, 0x9F95, 0x6CC4, 0x9F96, 0x6CF1, 0x9F97, 0x6CD3, 0x9F98, 0x6CBD, 0x9F99, 0x6CD7, 0x9F9A, 0x6CC5, 0x9F9B, 0x6CDD, 0x9F9C, 0x6CAE, 0x9F9D, 0x6CB1, 0x9F9E, 0x6CBE, 0x9F9F, 0x6CBA, 0x9FA0, 0x6CDB, 0x9FA1, 0x6CEF, 0x9FA2, 0x6CD9, 0x9FA3, 0x6CEA, 0x9FA4, 0x6D1F, 0x9FA5, 0x884D, 0x9FA6, 0x6D36, 0x9FA7, 0x6D2B, 0x9FA8, 0x6D3D, 0x9FA9, 0x6D38, 0x9FAA, 0x6D19, 0x9FAB, 0x6D35, 0x9FAC, 0x6D33, 0x9FAD, 0x6D12, 0x9FAE, 0x6D0C, 0x9FAF, 0x6D63, 0x9FB0, 0x6D93, 0x9FB1, 0x6D64, 0x9FB2, 0x6D5A, 0x9FB3, 0x6D79, 0x9FB4, 0x6D59, 0x9FB5, 0x6D8E, 0x9FB6, 0x6D95, 0x9FB7, 0x6FE4, 0x9FB8, 0x6D85, 0x9FB9, 0x6DF9, 0x9FBA, 0x6E15, 0x9FBB, 0x6E0A, 0x9FBC, 0x6DB5, 0x9FBD, 0x6DC7, 0x9FBE, 0x6DE6, 0x9FBF, 0x6DB8, 0x9FC0, 0x6DC6, 0x9FC1, 0x6DEC, 0x9FC2, 0x6DDE, 0x9FC3, 0x6DCC, 0x9FC4, 0x6DE8, 0x9FC5, 0x6DD2, 0x9FC6, 0x6DC5, 0x9FC7, 0x6DFA, 0x9FC8, 0x6DD9, 0x9FC9, 0x6DE4, 0x9FCA, 0x6DD5, 0x9FCB, 0x6DEA, 0x9FCC, 0x6DEE, 0x9FCD, 0x6E2D, 0x9FCE, 0x6E6E, 0x9FCF, 0x6E2E, 0x9FD0, 0x6E19, 0x9FD1, 0x6E72, 0x9FD2, 0x6E5F, 0x9FD3, 0x6E3E, 0x9FD4, 0x6E23, 0x9FD5, 0x6E6B, 0x9FD6, 0x6E2B, 0x9FD7, 0x6E76, 0x9FD8, 0x6E4D, 0x9FD9, 0x6E1F, 0x9FDA, 0x6E43, 0x9FDB, 0x6E3A, 0x9FDC, 0x6E4E, 0x9FDD, 0x6E24, 0x9FDE, 0x6EFF, 0x9FDF, 0x6E1D, 0x9FE0, 0x6E38, 0x9FE1, 0x6E82, 0x9FE2, 0x6EAA, 0x9FE3, 0x6E98, 0x9FE4, 0x6EC9, 0x9FE5, 0x6EB7, 0x9FE6, 0x6ED3, 0x9FE7, 0x6EBD, 0x9FE8, 0x6EAF, 0x9FE9, 0x6EC4, 0x9FEA, 0x6EB2, 0x9FEB, 0x6ED4, 0x9FEC, 0x6ED5, 0x9FED, 0x6E8F, 0x9FEE, 0x6EA5, 0x9FEF, 0x6EC2, 0x9FF0, 0x6E9F, 0x9FF1, 0x6F41, 0x9FF2, 0x6F11, 0x9FF3, 0x704C, 0x9FF4, 0x6EEC, 0x9FF5, 0x6EF8, 0x9FF6, 0x6EFE, 0x9FF7, 0x6F3F, 0x9FF8, 0x6EF2, 0x9FF9, 0x6F31, 0x9FFA, 0x6EEF, 0x9FFB, 0x6F32, 0x9FFC, 0x6ECC, 0xE040, 0x6F3E, 0xE041, 0x6F13, 0xE042, 0x6EF7, 0xE043, 0x6F86, 0xE044, 0x6F7A, 0xE045, 0x6F78, 0xE046, 0x6F81, 0xE047, 0x6F80, 0xE048, 0x6F6F, 0xE049, 0x6F5B, 0xE04A, 0x6FF3, 0xE04B, 0x6F6D, 0xE04C, 0x6F82, 0xE04D, 0x6F7C, 0xE04E, 0x6F58, 0xE04F, 0x6F8E, 0xE050, 0x6F91, 0xE051, 0x6FC2, 0xE052, 0x6F66, 0xE053, 0x6FB3, 0xE054, 0x6FA3, 0xE055, 0x6FA1, 0xE056, 0x6FA4, 0xE057, 0x6FB9, 0xE058, 0x6FC6, 0xE059, 0x6FAA, 0xE05A, 0x6FDF, 0xE05B, 0x6FD5, 0xE05C, 0x6FEC, 0xE05D, 0x6FD4, 0xE05E, 0x6FD8, 0xE05F, 0x6FF1, 0xE060, 0x6FEE, 0xE061, 0x6FDB, 0xE062, 0x7009, 0xE063, 0x700B, 0xE064, 0x6FFA, 0xE065, 0x7011, 0xE066, 0x7001, 0xE067, 0x700F, 0xE068, 0x6FFE, 0xE069, 0x701B, 0xE06A, 0x701A, 0xE06B, 0x6F74, 0xE06C, 0x701D, 0xE06D, 0x7018, 0xE06E, 0x701F, 0xE06F, 0x7030, 0xE070, 0x703E, 0xE071, 0x7032, 0xE072, 0x7051, 0xE073, 0x7063, 0xE074, 0x7099, 0xE075, 0x7092, 0xE076, 0x70AF, 0xE077, 0x70F1, 0xE078, 0x70AC, 0xE079, 0x70B8, 0xE07A, 0x70B3, 0xE07B, 0x70AE, 0xE07C, 0x70DF, 0xE07D, 0x70CB, 0xE07E, 0x70DD, 0xE080, 0x70D9, 0xE081, 0x7109, 0xE082, 0x70FD, 0xE083, 0x711C, 0xE084, 0x7119, 0xE085, 0x7165, 0xE086, 0x7155, 0xE087, 0x7188, 0xE088, 0x7166, 0xE089, 0x7162, 0xE08A, 0x714C, 0xE08B, 0x7156, 0xE08C, 0x716C, 0xE08D, 0x718F, 0xE08E, 0x71FB, 0xE08F, 0x7184, 0xE090, 0x7195, 0xE091, 0x71A8, 0xE092, 0x71AC, 0xE093, 0x71D7, 0xE094, 0x71B9, 0xE095, 0x71BE, 0xE096, 0x71D2, 0xE097, 0x71C9, 0xE098, 0x71D4, 0xE099, 0x71CE, 0xE09A, 0x71E0, 0xE09B, 0x71EC, 0xE09C, 0x71E7, 0xE09D, 0x71F5, 0xE09E, 0x71FC, 0xE09F, 0x71F9, 0xE0A0, 0x71FF, 0xE0A1, 0x720D, 0xE0A2, 0x7210, 0xE0A3, 0x721B, 0xE0A4, 0x7228, 0xE0A5, 0x722D, 0xE0A6, 0x722C, 0xE0A7, 0x7230, 0xE0A8, 0x7232, 0xE0A9, 0x723B, 0xE0AA, 0x723C, 0xE0AB, 0x723F, 0xE0AC, 0x7240, 0xE0AD, 0x7246, 0xE0AE, 0x724B, 0xE0AF, 0x7258, 0xE0B0, 0x7274, 0xE0B1, 0x727E, 0xE0B2, 0x7282, 0xE0B3, 0x7281, 0xE0B4, 0x7287, 0xE0B5, 0x7292, 0xE0B6, 0x7296, 0xE0B7, 0x72A2, 0xE0B8, 0x72A7, 0xE0B9, 0x72B9, 0xE0BA, 0x72B2, 0xE0BB, 0x72C3, 0xE0BC, 0x72C6, 0xE0BD, 0x72C4, 0xE0BE, 0x72CE, 0xE0BF, 0x72D2, 0xE0C0, 0x72E2, 0xE0C1, 0x72E0, 0xE0C2, 0x72E1, 0xE0C3, 0x72F9, 0xE0C4, 0x72F7, 0xE0C5, 0x500F, 0xE0C6, 0x7317, 0xE0C7, 0x730A, 0xE0C8, 0x731C, 0xE0C9, 0x7316, 0xE0CA, 0x731D, 0xE0CB, 0x7334, 0xE0CC, 0x732F, 0xE0CD, 0x7329, 0xE0CE, 0x7325, 0xE0CF, 0x733E, 0xE0D0, 0x734E, 0xE0D1, 0x734F, 0xE0D2, 0x9ED8, 0xE0D3, 0x7357, 0xE0D4, 0x736A, 0xE0D5, 0x7368, 0xE0D6, 0x7370, 0xE0D7, 0x7378, 0xE0D8, 0x7375, 0xE0D9, 0x737B, 0xE0DA, 0x737A, 0xE0DB, 0x73C8, 0xE0DC, 0x73B3, 0xE0DD, 0x73CE, 0xE0DE, 0x73BB, 0xE0DF, 0x73C0, 0xE0E0, 0x73E5, 0xE0E1, 0x73EE, 0xE0E2, 0x73DE, 0xE0E3, 0x74A2, 0xE0E4, 0x7405, 0xE0E5, 0x746F, 0xE0E6, 0x7425, 0xE0E7, 0x73F8, 0xE0E8, 0x7432, 0xE0E9, 0x743A, 0xE0EA, 0x7455, 0xE0EB, 0x743F, 0xE0EC, 0x745F, 0xE0ED, 0x7459, 0xE0EE, 0x7441, 0xE0EF, 0x745C, 0xE0F0, 0x7469, 0xE0F1, 0x7470, 0xE0F2, 0x7463, 0xE0F3, 0x746A, 0xE0F4, 0x7476, 0xE0F5, 0x747E, 0xE0F6, 0x748B, 0xE0F7, 0x749E, 0xE0F8, 0x74A7, 0xE0F9, 0x74CA, 0xE0FA, 0x74CF, 0xE0FB, 0x74D4, 0xE0FC, 0x73F1, 0xE140, 0x74E0, 0xE141, 0x74E3, 0xE142, 0x74E7, 0xE143, 0x74E9, 0xE144, 0x74EE, 0xE145, 0x74F2, 0xE146, 0x74F0, 0xE147, 0x74F1, 0xE148, 0x74F8, 0xE149, 0x74F7, 0xE14A, 0x7504, 0xE14B, 0x7503, 0xE14C, 0x7505, 0xE14D, 0x750C, 0xE14E, 0x750E, 0xE14F, 0x750D, 0xE150, 0x7515, 0xE151, 0x7513, 0xE152, 0x751E, 0xE153, 0x7526, 0xE154, 0x752C, 0xE155, 0x753C, 0xE156, 0x7544, 0xE157, 0x754D, 0xE158, 0x754A, 0xE159, 0x7549, 0xE15A, 0x755B, 0xE15B, 0x7546, 0xE15C, 0x755A, 0xE15D, 0x7569, 0xE15E, 0x7564, 0xE15F, 0x7567, 0xE160, 0x756B, 0xE161, 0x756D, 0xE162, 0x7578, 0xE163, 0x7576, 0xE164, 0x7586, 0xE165, 0x7587, 0xE166, 0x7574, 0xE167, 0x758A, 0xE168, 0x7589, 0xE169, 0x7582, 0xE16A, 0x7594, 0xE16B, 0x759A, 0xE16C, 0x759D, 0xE16D, 0x75A5, 0xE16E, 0x75A3, 0xE16F, 0x75C2, 0xE170, 0x75B3, 0xE171, 0x75C3, 0xE172, 0x75B5, 0xE173, 0x75BD, 0xE174, 0x75B8, 0xE175, 0x75BC, 0xE176, 0x75B1, 0xE177, 0x75CD, 0xE178, 0x75CA, 0xE179, 0x75D2, 0xE17A, 0x75D9, 0xE17B, 0x75E3, 0xE17C, 0x75DE, 0xE17D, 0x75FE, 0xE17E, 0x75FF, 0xE180, 0x75FC, 0xE181, 0x7601, 0xE182, 0x75F0, 0xE183, 0x75FA, 0xE184, 0x75F2, 0xE185, 0x75F3, 0xE186, 0x760B, 0xE187, 0x760D, 0xE188, 0x7609, 0xE189, 0x761F, 0xE18A, 0x7627, 0xE18B, 0x7620, 0xE18C, 0x7621, 0xE18D, 0x7622, 0xE18E, 0x7624, 0xE18F, 0x7634, 0xE190, 0x7630, 0xE191, 0x763B, 0xE192, 0x7647, 0xE193, 0x7648, 0xE194, 0x7646, 0xE195, 0x765C, 0xE196, 0x7658, 0xE197, 0x7661, 0xE198, 0x7662, 0xE199, 0x7668, 0xE19A, 0x7669, 0xE19B, 0x766A, 0xE19C, 0x7667, 0xE19D, 0x766C, 0xE19E, 0x7670, 0xE19F, 0x7672, 0xE1A0, 0x7676, 0xE1A1, 0x7678, 0xE1A2, 0x767C, 0xE1A3, 0x7680, 0xE1A4, 0x7683, 0xE1A5, 0x7688, 0xE1A6, 0x768B, 0xE1A7, 0x768E, 0xE1A8, 0x7696, 0xE1A9, 0x7693, 0xE1AA, 0x7699, 0xE1AB, 0x769A, 0xE1AC, 0x76B0, 0xE1AD, 0x76B4, 0xE1AE, 0x76B8, 0xE1AF, 0x76B9, 0xE1B0, 0x76BA, 0xE1B1, 0x76C2, 0xE1B2, 0x76CD, 0xE1B3, 0x76D6, 0xE1B4, 0x76D2, 0xE1B5, 0x76DE, 0xE1B6, 0x76E1, 0xE1B7, 0x76E5, 0xE1B8, 0x76E7, 0xE1B9, 0x76EA, 0xE1BA, 0x862F, 0xE1BB, 0x76FB, 0xE1BC, 0x7708, 0xE1BD, 0x7707, 0xE1BE, 0x7704, 0xE1BF, 0x7729, 0xE1C0, 0x7724, 0xE1C1, 0x771E, 0xE1C2, 0x7725, 0xE1C3, 0x7726, 0xE1C4, 0x771B, 0xE1C5, 0x7737, 0xE1C6, 0x7738, 0xE1C7, 0x7747, 0xE1C8, 0x775A, 0xE1C9, 0x7768, 0xE1CA, 0x776B, 0xE1CB, 0x775B, 0xE1CC, 0x7765, 0xE1CD, 0x777F, 0xE1CE, 0x777E, 0xE1CF, 0x7779, 0xE1D0, 0x778E, 0xE1D1, 0x778B, 0xE1D2, 0x7791, 0xE1D3, 0x77A0, 0xE1D4, 0x779E, 0xE1D5, 0x77B0, 0xE1D6, 0x77B6, 0xE1D7, 0x77B9, 0xE1D8, 0x77BF, 0xE1D9, 0x77BC, 0xE1DA, 0x77BD, 0xE1DB, 0x77BB, 0xE1DC, 0x77C7, 0xE1DD, 0x77CD, 0xE1DE, 0x77D7, 0xE1DF, 0x77DA, 0xE1E0, 0x77DC, 0xE1E1, 0x77E3, 0xE1E2, 0x77EE, 0xE1E3, 0x77FC, 0xE1E4, 0x780C, 0xE1E5, 0x7812, 0xE1E6, 0x7926, 0xE1E7, 0x7820, 0xE1E8, 0x792A, 0xE1E9, 0x7845, 0xE1EA, 0x788E, 0xE1EB, 0x7874, 0xE1EC, 0x7886, 0xE1ED, 0x787C, 0xE1EE, 0x789A, 0xE1EF, 0x788C, 0xE1F0, 0x78A3, 0xE1F1, 0x78B5, 0xE1F2, 0x78AA, 0xE1F3, 0x78AF, 0xE1F4, 0x78D1, 0xE1F5, 0x78C6, 0xE1F6, 0x78CB, 0xE1F7, 0x78D4, 0xE1F8, 0x78BE, 0xE1F9, 0x78BC, 0xE1FA, 0x78C5, 0xE1FB, 0x78CA, 0xE1FC, 0x78EC, 0xE240, 0x78E7, 0xE241, 0x78DA, 0xE242, 0x78FD, 0xE243, 0x78F4, 0xE244, 0x7907, 0xE245, 0x7912, 0xE246, 0x7911, 0xE247, 0x7919, 0xE248, 0x792C, 0xE249, 0x792B, 0xE24A, 0x7940, 0xE24B, 0x7960, 0xE24C, 0x7957, 0xE24D, 0x795F, 0xE24E, 0x795A, 0xE24F, 0x7955, 0xE250, 0x7953, 0xE251, 0x797A, 0xE252, 0x797F, 0xE253, 0x798A, 0xE254, 0x799D, 0xE255, 0x79A7, 0xE256, 0x9F4B, 0xE257, 0x79AA, 0xE258, 0x79AE, 0xE259, 0x79B3, 0xE25A, 0x79B9, 0xE25B, 0x79BA, 0xE25C, 0x79C9, 0xE25D, 0x79D5, 0xE25E, 0x79E7, 0xE25F, 0x79EC, 0xE260, 0x79E1, 0xE261, 0x79E3, 0xE262, 0x7A08, 0xE263, 0x7A0D, 0xE264, 0x7A18, 0xE265, 0x7A19, 0xE266, 0x7A20, 0xE267, 0x7A1F, 0xE268, 0x7980, 0xE269, 0x7A31, 0xE26A, 0x7A3B, 0xE26B, 0x7A3E, 0xE26C, 0x7A37, 0xE26D, 0x7A43, 0xE26E, 0x7A57, 0xE26F, 0x7A49, 0xE270, 0x7A61, 0xE271, 0x7A62, 0xE272, 0x7A69, 0xE273, 0x9F9D, 0xE274, 0x7A70, 0xE275, 0x7A79, 0xE276, 0x7A7D, 0xE277, 0x7A88, 0xE278, 0x7A97, 0xE279, 0x7A95, 0xE27A, 0x7A98, 0xE27B, 0x7A96, 0xE27C, 0x7AA9, 0xE27D, 0x7AC8, 0xE27E, 0x7AB0, 0xE280, 0x7AB6, 0xE281, 0x7AC5, 0xE282, 0x7AC4, 0xE283, 0x7ABF, 0xE284, 0x9083, 0xE285, 0x7AC7, 0xE286, 0x7ACA, 0xE287, 0x7ACD, 0xE288, 0x7ACF, 0xE289, 0x7AD5, 0xE28A, 0x7AD3, 0xE28B, 0x7AD9, 0xE28C, 0x7ADA, 0xE28D, 0x7ADD, 0xE28E, 0x7AE1, 0xE28F, 0x7AE2, 0xE290, 0x7AE6, 0xE291, 0x7AED, 0xE292, 0x7AF0, 0xE293, 0x7B02, 0xE294, 0x7B0F, 0xE295, 0x7B0A, 0xE296, 0x7B06, 0xE297, 0x7B33, 0xE298, 0x7B18, 0xE299, 0x7B19, 0xE29A, 0x7B1E, 0xE29B, 0x7B35, 0xE29C, 0x7B28, 0xE29D, 0x7B36, 0xE29E, 0x7B50, 0xE29F, 0x7B7A, 0xE2A0, 0x7B04, 0xE2A1, 0x7B4D, 0xE2A2, 0x7B0B, 0xE2A3, 0x7B4C, 0xE2A4, 0x7B45, 0xE2A5, 0x7B75, 0xE2A6, 0x7B65, 0xE2A7, 0x7B74, 0xE2A8, 0x7B67, 0xE2A9, 0x7B70, 0xE2AA, 0x7B71, 0xE2AB, 0x7B6C, 0xE2AC, 0x7B6E, 0xE2AD, 0x7B9D, 0xE2AE, 0x7B98, 0xE2AF, 0x7B9F, 0xE2B0, 0x7B8D, 0xE2B1, 0x7B9C, 0xE2B2, 0x7B9A, 0xE2B3, 0x7B8B, 0xE2B4, 0x7B92, 0xE2B5, 0x7B8F, 0xE2B6, 0x7B5D, 0xE2B7, 0x7B99, 0xE2B8, 0x7BCB, 0xE2B9, 0x7BC1, 0xE2BA, 0x7BCC, 0xE2BB, 0x7BCF, 0xE2BC, 0x7BB4, 0xE2BD, 0x7BC6, 0xE2BE, 0x7BDD, 0xE2BF, 0x7BE9, 0xE2C0, 0x7C11, 0xE2C1, 0x7C14, 0xE2C2, 0x7BE6, 0xE2C3, 0x7BE5, 0xE2C4, 0x7C60, 0xE2C5, 0x7C00, 0xE2C6, 0x7C07, 0xE2C7, 0x7C13, 0xE2C8, 0x7BF3, 0xE2C9, 0x7BF7, 0xE2CA, 0x7C17, 0xE2CB, 0x7C0D, 0xE2CC, 0x7BF6, 0xE2CD, 0x7C23, 0xE2CE, 0x7C27, 0xE2CF, 0x7C2A, 0xE2D0, 0x7C1F, 0xE2D1, 0x7C37, 0xE2D2, 0x7C2B, 0xE2D3, 0x7C3D, 0xE2D4, 0x7C4C, 0xE2D5, 0x7C43, 0xE2D6, 0x7C54, 0xE2D7, 0x7C4F, 0xE2D8, 0x7C40, 0xE2D9, 0x7C50, 0xE2DA, 0x7C58, 0xE2DB, 0x7C5F, 0xE2DC, 0x7C64, 0xE2DD, 0x7C56, 0xE2DE, 0x7C65, 0xE2DF, 0x7C6C, 0xE2E0, 0x7C75, 0xE2E1, 0x7C83, 0xE2E2, 0x7C90, 0xE2E3, 0x7CA4, 0xE2E4, 0x7CAD, 0xE2E5, 0x7CA2, 0xE2E6, 0x7CAB, 0xE2E7, 0x7CA1, 0xE2E8, 0x7CA8, 0xE2E9, 0x7CB3, 0xE2EA, 0x7CB2, 0xE2EB, 0x7CB1, 0xE2EC, 0x7CAE, 0xE2ED, 0x7CB9, 0xE2EE, 0x7CBD, 0xE2EF, 0x7CC0, 0xE2F0, 0x7CC5, 0xE2F1, 0x7CC2, 0xE2F2, 0x7CD8, 0xE2F3, 0x7CD2, 0xE2F4, 0x7CDC, 0xE2F5, 0x7CE2, 0xE2F6, 0x9B3B, 0xE2F7, 0x7CEF, 0xE2F8, 0x7CF2, 0xE2F9, 0x7CF4, 0xE2FA, 0x7CF6, 0xE2FB, 0x7CFA, 0xE2FC, 0x7D06, 0xE340, 0x7D02, 0xE341, 0x7D1C, 0xE342, 0x7D15, 0xE343, 0x7D0A, 0xE344, 0x7D45, 0xE345, 0x7D4B, 0xE346, 0x7D2E, 0xE347, 0x7D32, 0xE348, 0x7D3F, 0xE349, 0x7D35, 0xE34A, 0x7D46, 0xE34B, 0x7D73, 0xE34C, 0x7D56, 0xE34D, 0x7D4E, 0xE34E, 0x7D72, 0xE34F, 0x7D68, 0xE350, 0x7D6E, 0xE351, 0x7D4F, 0xE352, 0x7D63, 0xE353, 0x7D93, 0xE354, 0x7D89, 0xE355, 0x7D5B, 0xE356, 0x7D8F, 0xE357, 0x7D7D, 0xE358, 0x7D9B, 0xE359, 0x7DBA, 0xE35A, 0x7DAE, 0xE35B, 0x7DA3, 0xE35C, 0x7DB5, 0xE35D, 0x7DC7, 0xE35E, 0x7DBD, 0xE35F, 0x7DAB, 0xE360, 0x7E3D, 0xE361, 0x7DA2, 0xE362, 0x7DAF, 0xE363, 0x7DDC, 0xE364, 0x7DB8, 0xE365, 0x7D9F, 0xE366, 0x7DB0, 0xE367, 0x7DD8, 0xE368, 0x7DDD, 0xE369, 0x7DE4, 0xE36A, 0x7DDE, 0xE36B, 0x7DFB, 0xE36C, 0x7DF2, 0xE36D, 0x7DE1, 0xE36E, 0x7E05, 0xE36F, 0x7E0A, 0xE370, 0x7E23, 0xE371, 0x7E21, 0xE372, 0x7E12, 0xE373, 0x7E31, 0xE374, 0x7E1F, 0xE375, 0x7E09, 0xE376, 0x7E0B, 0xE377, 0x7E22, 0xE378, 0x7E46, 0xE379, 0x7E66, 0xE37A, 0x7E3B, 0xE37B, 0x7E35, 0xE37C, 0x7E39, 0xE37D, 0x7E43, 0xE37E, 0x7E37, 0xE380, 0x7E32, 0xE381, 0x7E3A, 0xE382, 0x7E67, 0xE383, 0x7E5D, 0xE384, 0x7E56, 0xE385, 0x7E5E, 0xE386, 0x7E59, 0xE387, 0x7E5A, 0xE388, 0x7E79, 0xE389, 0x7E6A, 0xE38A, 0x7E69, 0xE38B, 0x7E7C, 0xE38C, 0x7E7B, 0xE38D, 0x7E83, 0xE38E, 0x7DD5, 0xE38F, 0x7E7D, 0xE390, 0x8FAE, 0xE391, 0x7E7F, 0xE392, 0x7E88, 0xE393, 0x7E89, 0xE394, 0x7E8C, 0xE395, 0x7E92, 0xE396, 0x7E90, 0xE397, 0x7E93, 0xE398, 0x7E94, 0xE399, 0x7E96, 0xE39A, 0x7E8E, 0xE39B, 0x7E9B, 0xE39C, 0x7E9C, 0xE39D, 0x7F38, 0xE39E, 0x7F3A, 0xE39F, 0x7F45, 0xE3A0, 0x7F4C, 0xE3A1, 0x7F4D, 0xE3A2, 0x7F4E, 0xE3A3, 0x7F50, 0xE3A4, 0x7F51, 0xE3A5, 0x7F55, 0xE3A6, 0x7F54, 0xE3A7, 0x7F58, 0xE3A8, 0x7F5F, 0xE3A9, 0x7F60, 0xE3AA, 0x7F68, 0xE3AB, 0x7F69, 0xE3AC, 0x7F67, 0xE3AD, 0x7F78, 0xE3AE, 0x7F82, 0xE3AF, 0x7F86, 0xE3B0, 0x7F83, 0xE3B1, 0x7F88, 0xE3B2, 0x7F87, 0xE3B3, 0x7F8C, 0xE3B4, 0x7F94, 0xE3B5, 0x7F9E, 0xE3B6, 0x7F9D, 0xE3B7, 0x7F9A, 0xE3B8, 0x7FA3, 0xE3B9, 0x7FAF, 0xE3BA, 0x7FB2, 0xE3BB, 0x7FB9, 0xE3BC, 0x7FAE, 0xE3BD, 0x7FB6, 0xE3BE, 0x7FB8, 0xE3BF, 0x8B71, 0xE3C0, 0x7FC5, 0xE3C1, 0x7FC6, 0xE3C2, 0x7FCA, 0xE3C3, 0x7FD5, 0xE3C4, 0x7FD4, 0xE3C5, 0x7FE1, 0xE3C6, 0x7FE6, 0xE3C7, 0x7FE9, 0xE3C8, 0x7FF3, 0xE3C9, 0x7FF9, 0xE3CA, 0x98DC, 0xE3CB, 0x8006, 0xE3CC, 0x8004, 0xE3CD, 0x800B, 0xE3CE, 0x8012, 0xE3CF, 0x8018, 0xE3D0, 0x8019, 0xE3D1, 0x801C, 0xE3D2, 0x8021, 0xE3D3, 0x8028, 0xE3D4, 0x803F, 0xE3D5, 0x803B, 0xE3D6, 0x804A, 0xE3D7, 0x8046, 0xE3D8, 0x8052, 0xE3D9, 0x8058, 0xE3DA, 0x805A, 0xE3DB, 0x805F, 0xE3DC, 0x8062, 0xE3DD, 0x8068, 0xE3DE, 0x8073, 0xE3DF, 0x8072, 0xE3E0, 0x8070, 0xE3E1, 0x8076, 0xE3E2, 0x8079, 0xE3E3, 0x807D, 0xE3E4, 0x807F, 0xE3E5, 0x8084, 0xE3E6, 0x8086, 0xE3E7, 0x8085, 0xE3E8, 0x809B, 0xE3E9, 0x8093, 0xE3EA, 0x809A, 0xE3EB, 0x80AD, 0xE3EC, 0x5190, 0xE3ED, 0x80AC, 0xE3EE, 0x80DB, 0xE3EF, 0x80E5, 0xE3F0, 0x80D9, 0xE3F1, 0x80DD, 0xE3F2, 0x80C4, 0xE3F3, 0x80DA, 0xE3F4, 0x80D6, 0xE3F5, 0x8109, 0xE3F6, 0x80EF, 0xE3F7, 0x80F1, 0xE3F8, 0x811B, 0xE3F9, 0x8129, 0xE3FA, 0x8123, 0xE3FB, 0x812F, 0xE3FC, 0x814B, 0xE440, 0x968B, 0xE441, 0x8146, 0xE442, 0x813E, 0xE443, 0x8153, 0xE444, 0x8151, 0xE445, 0x80FC, 0xE446, 0x8171, 0xE447, 0x816E, 0xE448, 0x8165, 0xE449, 0x8166, 0xE44A, 0x8174, 0xE44B, 0x8183, 0xE44C, 0x8188, 0xE44D, 0x818A, 0xE44E, 0x8180, 0xE44F, 0x8182, 0xE450, 0x81A0, 0xE451, 0x8195, 0xE452, 0x81A4, 0xE453, 0x81A3, 0xE454, 0x815F, 0xE455, 0x8193, 0xE456, 0x81A9, 0xE457, 0x81B0, 0xE458, 0x81B5, 0xE459, 0x81BE, 0xE45A, 0x81B8, 0xE45B, 0x81BD, 0xE45C, 0x81C0, 0xE45D, 0x81C2, 0xE45E, 0x81BA, 0xE45F, 0x81C9, 0xE460, 0x81CD, 0xE461, 0x81D1, 0xE462, 0x81D9, 0xE463, 0x81D8, 0xE464, 0x81C8, 0xE465, 0x81DA, 0xE466, 0x81DF, 0xE467, 0x81E0, 0xE468, 0x81E7, 0xE469, 0x81FA, 0xE46A, 0x81FB, 0xE46B, 0x81FE, 0xE46C, 0x8201, 0xE46D, 0x8202, 0xE46E, 0x8205, 0xE46F, 0x8207, 0xE470, 0x820A, 0xE471, 0x820D, 0xE472, 0x8210, 0xE473, 0x8216, 0xE474, 0x8229, 0xE475, 0x822B, 0xE476, 0x8238, 0xE477, 0x8233, 0xE478, 0x8240, 0xE479, 0x8259, 0xE47A, 0x8258, 0xE47B, 0x825D, 0xE47C, 0x825A, 0xE47D, 0x825F, 0xE47E, 0x8264, 0xE480, 0x8262, 0xE481, 0x8268, 0xE482, 0x826A, 0xE483, 0x826B, 0xE484, 0x822E, 0xE485, 0x8271, 0xE486, 0x8277, 0xE487, 0x8278, 0xE488, 0x827E, 0xE489, 0x828D, 0xE48A, 0x8292, 0xE48B, 0x82AB, 0xE48C, 0x829F, 0xE48D, 0x82BB, 0xE48E, 0x82AC, 0xE48F, 0x82E1, 0xE490, 0x82E3, 0xE491, 0x82DF, 0xE492, 0x82D2, 0xE493, 0x82F4, 0xE494, 0x82F3, 0xE495, 0x82FA, 0xE496, 0x8393, 0xE497, 0x8303, 0xE498, 0x82FB, 0xE499, 0x82F9, 0xE49A, 0x82DE, 0xE49B, 0x8306, 0xE49C, 0x82DC, 0xE49D, 0x8309, 0xE49E, 0x82D9, 0xE49F, 0x8335, 0xE4A0, 0x8334, 0xE4A1, 0x8316, 0xE4A2, 0x8332, 0xE4A3, 0x8331, 0xE4A4, 0x8340, 0xE4A5, 0x8339, 0xE4A6, 0x8350, 0xE4A7, 0x8345, 0xE4A8, 0x832F, 0xE4A9, 0x832B, 0xE4AA, 0x8317, 0xE4AB, 0x8318, 0xE4AC, 0x8385, 0xE4AD, 0x839A, 0xE4AE, 0x83AA, 0xE4AF, 0x839F, 0xE4B0, 0x83A2, 0xE4B1, 0x8396, 0xE4B2, 0x8323, 0xE4B3, 0x838E, 0xE4B4, 0x8387, 0xE4B5, 0x838A, 0xE4B6, 0x837C, 0xE4B7, 0x83B5, 0xE4B8, 0x8373, 0xE4B9, 0x8375, 0xE4BA, 0x83A0, 0xE4BB, 0x8389, 0xE4BC, 0x83A8, 0xE4BD, 0x83F4, 0xE4BE, 0x8413, 0xE4BF, 0x83EB, 0xE4C0, 0x83CE, 0xE4C1, 0x83FD, 0xE4C2, 0x8403, 0xE4C3, 0x83D8, 0xE4C4, 0x840B, 0xE4C5, 0x83C1, 0xE4C6, 0x83F7, 0xE4C7, 0x8407, 0xE4C8, 0x83E0, 0xE4C9, 0x83F2, 0xE4CA, 0x840D, 0xE4CB, 0x8422, 0xE4CC, 0x8420, 0xE4CD, 0x83BD, 0xE4CE, 0x8438, 0xE4CF, 0x8506, 0xE4D0, 0x83FB, 0xE4D1, 0x846D, 0xE4D2, 0x842A, 0xE4D3, 0x843C, 0xE4D4, 0x855A, 0xE4D5, 0x8484, 0xE4D6, 0x8477, 0xE4D7, 0x846B, 0xE4D8, 0x84AD, 0xE4D9, 0x846E, 0xE4DA, 0x8482, 0xE4DB, 0x8469, 0xE4DC, 0x8446, 0xE4DD, 0x842C, 0xE4DE, 0x846F, 0xE4DF, 0x8479, 0xE4E0, 0x8435, 0xE4E1, 0x84CA, 0xE4E2, 0x8462, 0xE4E3, 0x84B9, 0xE4E4, 0x84BF, 0xE4E5, 0x849F, 0xE4E6, 0x84D9, 0xE4E7, 0x84CD, 0xE4E8, 0x84BB, 0xE4E9, 0x84DA, 0xE4EA, 0x84D0, 0xE4EB, 0x84C1, 0xE4EC, 0x84C6, 0xE4ED, 0x84D6, 0xE4EE, 0x84A1, 0xE4EF, 0x8521, 0xE4F0, 0x84FF, 0xE4F1, 0x84F4, 0xE4F2, 0x8517, 0xE4F3, 0x8518, 0xE4F4, 0x852C, 0xE4F5, 0x851F, 0xE4F6, 0x8515, 0xE4F7, 0x8514, 0xE4F8, 0x84FC, 0xE4F9, 0x8540, 0xE4FA, 0x8563, 0xE4FB, 0x8558, 0xE4FC, 0x8548, 0xE540, 0x8541, 0xE541, 0x8602, 0xE542, 0x854B, 0xE543, 0x8555, 0xE544, 0x8580, 0xE545, 0x85A4, 0xE546, 0x8588, 0xE547, 0x8591, 0xE548, 0x858A, 0xE549, 0x85A8, 0xE54A, 0x856D, 0xE54B, 0x8594, 0xE54C, 0x859B, 0xE54D, 0x85EA, 0xE54E, 0x8587, 0xE54F, 0x859C, 0xE550, 0x8577, 0xE551, 0x857E, 0xE552, 0x8590, 0xE553, 0x85C9, 0xE554, 0x85BA, 0xE555, 0x85CF, 0xE556, 0x85B9, 0xE557, 0x85D0, 0xE558, 0x85D5, 0xE559, 0x85DD, 0xE55A, 0x85E5, 0xE55B, 0x85DC, 0xE55C, 0x85F9, 0xE55D, 0x860A, 0xE55E, 0x8613, 0xE55F, 0x860B, 0xE560, 0x85FE, 0xE561, 0x85FA, 0xE562, 0x8606, 0xE563, 0x8622, 0xE564, 0x861A, 0xE565, 0x8630, 0xE566, 0x863F, 0xE567, 0x864D, 0xE568, 0x4E55, 0xE569, 0x8654, 0xE56A, 0x865F, 0xE56B, 0x8667, 0xE56C, 0x8671, 0xE56D, 0x8693, 0xE56E, 0x86A3, 0xE56F, 0x86A9, 0xE570, 0x86AA, 0xE571, 0x868B, 0xE572, 0x868C, 0xE573, 0x86B6, 0xE574, 0x86AF, 0xE575, 0x86C4, 0xE576, 0x86C6, 0xE577, 0x86B0, 0xE578, 0x86C9, 0xE579, 0x8823, 0xE57A, 0x86AB, 0xE57B, 0x86D4, 0xE57C, 0x86DE, 0xE57D, 0x86E9, 0xE57E, 0x86EC, 0xE580, 0x86DF, 0xE581, 0x86DB, 0xE582, 0x86EF, 0xE583, 0x8712, 0xE584, 0x8706, 0xE585, 0x8708, 0xE586, 0x8700, 0xE587, 0x8703, 0xE588, 0x86FB, 0xE589, 0x8711, 0xE58A, 0x8709, 0xE58B, 0x870D, 0xE58C, 0x86F9, 0xE58D, 0x870A, 0xE58E, 0x8734, 0xE58F, 0x873F, 0xE590, 0x8737, 0xE591, 0x873B, 0xE592, 0x8725, 0xE593, 0x8729, 0xE594, 0x871A, 0xE595, 0x8760, 0xE596, 0x875F, 0xE597, 0x8778, 0xE598, 0x874C, 0xE599, 0x874E, 0xE59A, 0x8774, 0xE59B, 0x8757, 0xE59C, 0x8768, 0xE59D, 0x876E, 0xE59E, 0x8759, 0xE59F, 0x8753, 0xE5A0, 0x8763, 0xE5A1, 0x876A, 0xE5A2, 0x8805, 0xE5A3, 0x87A2, 0xE5A4, 0x879F, 0xE5A5, 0x8782, 0xE5A6, 0x87AF, 0xE5A7, 0x87CB, 0xE5A8, 0x87BD, 0xE5A9, 0x87C0, 0xE5AA, 0x87D0, 0xE5AB, 0x96D6, 0xE5AC, 0x87AB, 0xE5AD, 0x87C4, 0xE5AE, 0x87B3, 0xE5AF, 0x87C7, 0xE5B0, 0x87C6, 0xE5B1, 0x87BB, 0xE5B2, 0x87EF, 0xE5B3, 0x87F2, 0xE5B4, 0x87E0, 0xE5B5, 0x880F, 0xE5B6, 0x880D, 0xE5B7, 0x87FE, 0xE5B8, 0x87F6, 0xE5B9, 0x87F7, 0xE5BA, 0x880E, 0xE5BB, 0x87D2, 0xE5BC, 0x8811, 0xE5BD, 0x8816, 0xE5BE, 0x8815, 0xE5BF, 0x8822, 0xE5C0, 0x8821, 0xE5C1, 0x8831, 0xE5C2, 0x8836, 0xE5C3, 0x8839, 0xE5C4, 0x8827, 0xE5C5, 0x883B, 0xE5C6, 0x8844, 0xE5C7, 0x8842, 0xE5C8, 0x8852, 0xE5C9, 0x8859, 0xE5CA, 0x885E, 0xE5CB, 0x8862, 0xE5CC, 0x886B, 0xE5CD, 0x8881, 0xE5CE, 0x887E, 0xE5CF, 0x889E, 0xE5D0, 0x8875, 0xE5D1, 0x887D, 0xE5D2, 0x88B5, 0xE5D3, 0x8872, 0xE5D4, 0x8882, 0xE5D5, 0x8897, 0xE5D6, 0x8892, 0xE5D7, 0x88AE, 0xE5D8, 0x8899, 0xE5D9, 0x88A2, 0xE5DA, 0x888D, 0xE5DB, 0x88A4, 0xE5DC, 0x88B0, 0xE5DD, 0x88BF, 0xE5DE, 0x88B1, 0xE5DF, 0x88C3, 0xE5E0, 0x88C4, 0xE5E1, 0x88D4, 0xE5E2, 0x88D8, 0xE5E3, 0x88D9, 0xE5E4, 0x88DD, 0xE5E5, 0x88F9, 0xE5E6, 0x8902, 0xE5E7, 0x88FC, 0xE5E8, 0x88F4, 0xE5E9, 0x88E8, 0xE5EA, 0x88F2, 0xE5EB, 0x8904, 0xE5EC, 0x890C, 0xE5ED, 0x890A, 0xE5EE, 0x8913, 0xE5EF, 0x8943, 0xE5F0, 0x891E, 0xE5F1, 0x8925, 0xE5F2, 0x892A, 0xE5F3, 0x892B, 0xE5F4, 0x8941, 0xE5F5, 0x8944, 0xE5F6, 0x893B, 0xE5F7, 0x8936, 0xE5F8, 0x8938, 0xE5F9, 0x894C, 0xE5FA, 0x891D, 0xE5FB, 0x8960, 0xE5FC, 0x895E, 0xE640, 0x8966, 0xE641, 0x8964, 0xE642, 0x896D, 0xE643, 0x896A, 0xE644, 0x896F, 0xE645, 0x8974, 0xE646, 0x8977, 0xE647, 0x897E, 0xE648, 0x8983, 0xE649, 0x8988, 0xE64A, 0x898A, 0xE64B, 0x8993, 0xE64C, 0x8998, 0xE64D, 0x89A1, 0xE64E, 0x89A9, 0xE64F, 0x89A6, 0xE650, 0x89AC, 0xE651, 0x89AF, 0xE652, 0x89B2, 0xE653, 0x89BA, 0xE654, 0x89BD, 0xE655, 0x89BF, 0xE656, 0x89C0, 0xE657, 0x89DA, 0xE658, 0x89DC, 0xE659, 0x89DD, 0xE65A, 0x89E7, 0xE65B, 0x89F4, 0xE65C, 0x89F8, 0xE65D, 0x8A03, 0xE65E, 0x8A16, 0xE65F, 0x8A10, 0xE660, 0x8A0C, 0xE661, 0x8A1B, 0xE662, 0x8A1D, 0xE663, 0x8A25, 0xE664, 0x8A36, 0xE665, 0x8A41, 0xE666, 0x8A5B, 0xE667, 0x8A52, 0xE668, 0x8A46, 0xE669, 0x8A48, 0xE66A, 0x8A7C, 0xE66B, 0x8A6D, 0xE66C, 0x8A6C, 0xE66D, 0x8A62, 0xE66E, 0x8A85, 0xE66F, 0x8A82, 0xE670, 0x8A84, 0xE671, 0x8AA8, 0xE672, 0x8AA1, 0xE673, 0x8A91, 0xE674, 0x8AA5, 0xE675, 0x8AA6, 0xE676, 0x8A9A, 0xE677, 0x8AA3, 0xE678, 0x8AC4, 0xE679, 0x8ACD, 0xE67A, 0x8AC2, 0xE67B, 0x8ADA, 0xE67C, 0x8AEB, 0xE67D, 0x8AF3, 0xE67E, 0x8AE7, 0xE680, 0x8AE4, 0xE681, 0x8AF1, 0xE682, 0x8B14, 0xE683, 0x8AE0, 0xE684, 0x8AE2, 0xE685, 0x8AF7, 0xE686, 0x8ADE, 0xE687, 0x8ADB, 0xE688, 0x8B0C, 0xE689, 0x8B07, 0xE68A, 0x8B1A, 0xE68B, 0x8AE1, 0xE68C, 0x8B16, 0xE68D, 0x8B10, 0xE68E, 0x8B17, 0xE68F, 0x8B20, 0xE690, 0x8B33, 0xE691, 0x97AB, 0xE692, 0x8B26, 0xE693, 0x8B2B, 0xE694, 0x8B3E, 0xE695, 0x8B28, 0xE696, 0x8B41, 0xE697, 0x8B4C, 0xE698, 0x8B4F, 0xE699, 0x8B4E, 0xE69A, 0x8B49, 0xE69B, 0x8B56, 0xE69C, 0x8B5B, 0xE69D, 0x8B5A, 0xE69E, 0x8B6B, 0xE69F, 0x8B5F, 0xE6A0, 0x8B6C, 0xE6A1, 0x8B6F, 0xE6A2, 0x8B74, 0xE6A3, 0x8B7D, 0xE6A4, 0x8B80, 0xE6A5, 0x8B8C, 0xE6A6, 0x8B8E, 0xE6A7, 0x8B92, 0xE6A8, 0x8B93, 0xE6A9, 0x8B96, 0xE6AA, 0x8B99, 0xE6AB, 0x8B9A, 0xE6AC, 0x8C3A, 0xE6AD, 0x8C41, 0xE6AE, 0x8C3F, 0xE6AF, 0x8C48, 0xE6B0, 0x8C4C, 0xE6B1, 0x8C4E, 0xE6B2, 0x8C50, 0xE6B3, 0x8C55, 0xE6B4, 0x8C62, 0xE6B5, 0x8C6C, 0xE6B6, 0x8C78, 0xE6B7, 0x8C7A, 0xE6B8, 0x8C82, 0xE6B9, 0x8C89, 0xE6BA, 0x8C85, 0xE6BB, 0x8C8A, 0xE6BC, 0x8C8D, 0xE6BD, 0x8C8E, 0xE6BE, 0x8C94, 0xE6BF, 0x8C7C, 0xE6C0, 0x8C98, 0xE6C1, 0x621D, 0xE6C2, 0x8CAD, 0xE6C3, 0x8CAA, 0xE6C4, 0x8CBD, 0xE6C5, 0x8CB2, 0xE6C6, 0x8CB3, 0xE6C7, 0x8CAE, 0xE6C8, 0x8CB6, 0xE6C9, 0x8CC8, 0xE6CA, 0x8CC1, 0xE6CB, 0x8CE4, 0xE6CC, 0x8CE3, 0xE6CD, 0x8CDA, 0xE6CE, 0x8CFD, 0xE6CF, 0x8CFA, 0xE6D0, 0x8CFB, 0xE6D1, 0x8D04, 0xE6D2, 0x8D05, 0xE6D3, 0x8D0A, 0xE6D4, 0x8D07, 0xE6D5, 0x8D0F, 0xE6D6, 0x8D0D, 0xE6D7, 0x8D10, 0xE6D8, 0x9F4E, 0xE6D9, 0x8D13, 0xE6DA, 0x8CCD, 0xE6DB, 0x8D14, 0xE6DC, 0x8D16, 0xE6DD, 0x8D67, 0xE6DE, 0x8D6D, 0xE6DF, 0x8D71, 0xE6E0, 0x8D73, 0xE6E1, 0x8D81, 0xE6E2, 0x8D99, 0xE6E3, 0x8DC2, 0xE6E4, 0x8DBE, 0xE6E5, 0x8DBA, 0xE6E6, 0x8DCF, 0xE6E7, 0x8DDA, 0xE6E8, 0x8DD6, 0xE6E9, 0x8DCC, 0xE6EA, 0x8DDB, 0xE6EB, 0x8DCB, 0xE6EC, 0x8DEA, 0xE6ED, 0x8DEB, 0xE6EE, 0x8DDF, 0xE6EF, 0x8DE3, 0xE6F0, 0x8DFC, 0xE6F1, 0x8E08, 0xE6F2, 0x8E09, 0xE6F3, 0x8DFF, 0xE6F4, 0x8E1D, 0xE6F5, 0x8E1E, 0xE6F6, 0x8E10, 0xE6F7, 0x8E1F, 0xE6F8, 0x8E42, 0xE6F9, 0x8E35, 0xE6FA, 0x8E30, 0xE6FB, 0x8E34, 0xE6FC, 0x8E4A, 0xE740, 0x8E47, 0xE741, 0x8E49, 0xE742, 0x8E4C, 0xE743, 0x8E50, 0xE744, 0x8E48, 0xE745, 0x8E59, 0xE746, 0x8E64, 0xE747, 0x8E60, 0xE748, 0x8E2A, 0xE749, 0x8E63, 0xE74A, 0x8E55, 0xE74B, 0x8E76, 0xE74C, 0x8E72, 0xE74D, 0x8E7C, 0xE74E, 0x8E81, 0xE74F, 0x8E87, 0xE750, 0x8E85, 0xE751, 0x8E84, 0xE752, 0x8E8B, 0xE753, 0x8E8A, 0xE754, 0x8E93, 0xE755, 0x8E91, 0xE756, 0x8E94, 0xE757, 0x8E99, 0xE758, 0x8EAA, 0xE759, 0x8EA1, 0xE75A, 0x8EAC, 0xE75B, 0x8EB0, 0xE75C, 0x8EC6, 0xE75D, 0x8EB1, 0xE75E, 0x8EBE, 0xE75F, 0x8EC5, 0xE760, 0x8EC8, 0xE761, 0x8ECB, 0xE762, 0x8EDB, 0xE763, 0x8EE3, 0xE764, 0x8EFC, 0xE765, 0x8EFB, 0xE766, 0x8EEB, 0xE767, 0x8EFE, 0xE768, 0x8F0A, 0xE769, 0x8F05, 0xE76A, 0x8F15, 0xE76B, 0x8F12, 0xE76C, 0x8F19, 0xE76D, 0x8F13, 0xE76E, 0x8F1C, 0xE76F, 0x8F1F, 0xE770, 0x8F1B, 0xE771, 0x8F0C, 0xE772, 0x8F26, 0xE773, 0x8F33, 0xE774, 0x8F3B, 0xE775, 0x8F39, 0xE776, 0x8F45, 0xE777, 0x8F42, 0xE778, 0x8F3E, 0xE779, 0x8F4C, 0xE77A, 0x8F49, 0xE77B, 0x8F46, 0xE77C, 0x8F4E, 0xE77D, 0x8F57, 0xE77E, 0x8F5C, 0xE780, 0x8F62, 0xE781, 0x8F63, 0xE782, 0x8F64, 0xE783, 0x8F9C, 0xE784, 0x8F9F, 0xE785, 0x8FA3, 0xE786, 0x8FAD, 0xE787, 0x8FAF, 0xE788, 0x8FB7, 0xE789, 0x8FDA, 0xE78A, 0x8FE5, 0xE78B, 0x8FE2, 0xE78C, 0x8FEA, 0xE78D, 0x8FEF, 0xE78E, 0x9087, 0xE78F, 0x8FF4, 0xE790, 0x9005, 0xE791, 0x8FF9, 0xE792, 0x8FFA, 0xE793, 0x9011, 0xE794, 0x9015, 0xE795, 0x9021, 0xE796, 0x900D, 0xE797, 0x901E, 0xE798, 0x9016, 0xE799, 0x900B, 0xE79A, 0x9027, 0xE79B, 0x9036, 0xE79C, 0x9035, 0xE79D, 0x9039, 0xE79E, 0x8FF8, 0xE79F, 0x904F, 0xE7A0, 0x9050, 0xE7A1, 0x9051, 0xE7A2, 0x9052, 0xE7A3, 0x900E, 0xE7A4, 0x9049, 0xE7A5, 0x903E, 0xE7A6, 0x9056, 0xE7A7, 0x9058, 0xE7A8, 0x905E, 0xE7A9, 0x9068, 0xE7AA, 0x906F, 0xE7AB, 0x9076, 0xE7AC, 0x96A8, 0xE7AD, 0x9072, 0xE7AE, 0x9082, 0xE7AF, 0x907D, 0xE7B0, 0x9081, 0xE7B1, 0x9080, 0xE7B2, 0x908A, 0xE7B3, 0x9089, 0xE7B4, 0x908F, 0xE7B5, 0x90A8, 0xE7B6, 0x90AF, 0xE7B7, 0x90B1, 0xE7B8, 0x90B5, 0xE7B9, 0x90E2, 0xE7BA, 0x90E4, 0xE7BB, 0x6248, 0xE7BC, 0x90DB, 0xE7BD, 0x9102, 0xE7BE, 0x9112, 0xE7BF, 0x9119, 0xE7C0, 0x9132, 0xE7C1, 0x9130, 0xE7C2, 0x914A, 0xE7C3, 0x9156, 0xE7C4, 0x9158, 0xE7C5, 0x9163, 0xE7C6, 0x9165, 0xE7C7, 0x9169, 0xE7C8, 0x9173, 0xE7C9, 0x9172, 0xE7CA, 0x918B, 0xE7CB, 0x9189, 0xE7CC, 0x9182, 0xE7CD, 0x91A2, 0xE7CE, 0x91AB, 0xE7CF, 0x91AF, 0xE7D0, 0x91AA, 0xE7D1, 0x91B5, 0xE7D2, 0x91B4, 0xE7D3, 0x91BA, 0xE7D4, 0x91C0, 0xE7D5, 0x91C1, 0xE7D6, 0x91C9, 0xE7D7, 0x91CB, 0xE7D8, 0x91D0, 0xE7D9, 0x91D6, 0xE7DA, 0x91DF, 0xE7DB, 0x91E1, 0xE7DC, 0x91DB, 0xE7DD, 0x91FC, 0xE7DE, 0x91F5, 0xE7DF, 0x91F6, 0xE7E0, 0x921E, 0xE7E1, 0x91FF, 0xE7E2, 0x9214, 0xE7E3, 0x922C, 0xE7E4, 0x9215, 0xE7E5, 0x9211, 0xE7E6, 0x925E, 0xE7E7, 0x9257, 0xE7E8, 0x9245, 0xE7E9, 0x9249, 0xE7EA, 0x9264, 0xE7EB, 0x9248, 0xE7EC, 0x9295, 0xE7ED, 0x923F, 0xE7EE, 0x924B, 0xE7EF, 0x9250, 0xE7F0, 0x929C, 0xE7F1, 0x9296, 0xE7F2, 0x9293, 0xE7F3, 0x929B, 0xE7F4, 0x925A, 0xE7F5, 0x92CF, 0xE7F6, 0x92B9, 0xE7F7, 0x92B7, 0xE7F8, 0x92E9, 0xE7F9, 0x930F, 0xE7FA, 0x92FA, 0xE7FB, 0x9344, 0xE7FC, 0x932E, 0xE840, 0x9319, 0xE841, 0x9322, 0xE842, 0x931A, 0xE843, 0x9323, 0xE844, 0x933A, 0xE845, 0x9335, 0xE846, 0x933B, 0xE847, 0x935C, 0xE848, 0x9360, 0xE849, 0x937C, 0xE84A, 0x936E, 0xE84B, 0x9356, 0xE84C, 0x93B0, 0xE84D, 0x93AC, 0xE84E, 0x93AD, 0xE84F, 0x9394, 0xE850, 0x93B9, 0xE851, 0x93D6, 0xE852, 0x93D7, 0xE853, 0x93E8, 0xE854, 0x93E5, 0xE855, 0x93D8, 0xE856, 0x93C3, 0xE857, 0x93DD, 0xE858, 0x93D0, 0xE859, 0x93C8, 0xE85A, 0x93E4, 0xE85B, 0x941A, 0xE85C, 0x9414, 0xE85D, 0x9413, 0xE85E, 0x9403, 0xE85F, 0x9407, 0xE860, 0x9410, 0xE861, 0x9436, 0xE862, 0x942B, 0xE863, 0x9435, 0xE864, 0x9421, 0xE865, 0x943A, 0xE866, 0x9441, 0xE867, 0x9452, 0xE868, 0x9444, 0xE869, 0x945B, 0xE86A, 0x9460, 0xE86B, 0x9462, 0xE86C, 0x945E, 0xE86D, 0x946A, 0xE86E, 0x9229, 0xE86F, 0x9470, 0xE870, 0x9475, 0xE871, 0x9477, 0xE872, 0x947D, 0xE873, 0x945A, 0xE874, 0x947C, 0xE875, 0x947E, 0xE876, 0x9481, 0xE877, 0x947F, 0xE878, 0x9582, 0xE879, 0x9587, 0xE87A, 0x958A, 0xE87B, 0x9594, 0xE87C, 0x9596, 0xE87D, 0x9598, 0xE87E, 0x9599, 0xE880, 0x95A0, 0xE881, 0x95A8, 0xE882, 0x95A7, 0xE883, 0x95AD, 0xE884, 0x95BC, 0xE885, 0x95BB, 0xE886, 0x95B9, 0xE887, 0x95BE, 0xE888, 0x95CA, 0xE889, 0x6FF6, 0xE88A, 0x95C3, 0xE88B, 0x95CD, 0xE88C, 0x95CC, 0xE88D, 0x95D5, 0xE88E, 0x95D4, 0xE88F, 0x95D6, 0xE890, 0x95DC, 0xE891, 0x95E1, 0xE892, 0x95E5, 0xE893, 0x95E2, 0xE894, 0x9621, 0xE895, 0x9628, 0xE896, 0x962E, 0xE897, 0x962F, 0xE898, 0x9642, 0xE899, 0x964C, 0xE89A, 0x964F, 0xE89B, 0x964B, 0xE89C, 0x9677, 0xE89D, 0x965C, 0xE89E, 0x965E, 0xE89F, 0x965D, 0xE8A0, 0x965F, 0xE8A1, 0x9666, 0xE8A2, 0x9672, 0xE8A3, 0x966C, 0xE8A4, 0x968D, 0xE8A5, 0x9698, 0xE8A6, 0x9695, 0xE8A7, 0x9697, 0xE8A8, 0x96AA, 0xE8A9, 0x96A7, 0xE8AA, 0x96B1, 0xE8AB, 0x96B2, 0xE8AC, 0x96B0, 0xE8AD, 0x96B4, 0xE8AE, 0x96B6, 0xE8AF, 0x96B8, 0xE8B0, 0x96B9, 0xE8B1, 0x96CE, 0xE8B2, 0x96CB, 0xE8B3, 0x96C9, 0xE8B4, 0x96CD, 0xE8B5, 0x894D, 0xE8B6, 0x96DC, 0xE8B7, 0x970D, 0xE8B8, 0x96D5, 0xE8B9, 0x96F9, 0xE8BA, 0x9704, 0xE8BB, 0x9706, 0xE8BC, 0x9708, 0xE8BD, 0x9713, 0xE8BE, 0x970E, 0xE8BF, 0x9711, 0xE8C0, 0x970F, 0xE8C1, 0x9716, 0xE8C2, 0x9719, 0xE8C3, 0x9724, 0xE8C4, 0x972A, 0xE8C5, 0x9730, 0xE8C6, 0x9739, 0xE8C7, 0x973D, 0xE8C8, 0x973E, 0xE8C9, 0x9744, 0xE8CA, 0x9746, 0xE8CB, 0x9748, 0xE8CC, 0x9742, 0xE8CD, 0x9749, 0xE8CE, 0x975C, 0xE8CF, 0x9760, 0xE8D0, 0x9764, 0xE8D1, 0x9766, 0xE8D2, 0x9768, 0xE8D3, 0x52D2, 0xE8D4, 0x976B, 0xE8D5, 0x9771, 0xE8D6, 0x9779, 0xE8D7, 0x9785, 0xE8D8, 0x977C, 0xE8D9, 0x9781, 0xE8DA, 0x977A, 0xE8DB, 0x9786, 0xE8DC, 0x978B, 0xE8DD, 0x978F, 0xE8DE, 0x9790, 0xE8DF, 0x979C, 0xE8E0, 0x97A8, 0xE8E1, 0x97A6, 0xE8E2, 0x97A3, 0xE8E3, 0x97B3, 0xE8E4, 0x97B4, 0xE8E5, 0x97C3, 0xE8E6, 0x97C6, 0xE8E7, 0x97C8, 0xE8E8, 0x97CB, 0xE8E9, 0x97DC, 0xE8EA, 0x97ED, 0xE8EB, 0x9F4F, 0xE8EC, 0x97F2, 0xE8ED, 0x7ADF, 0xE8EE, 0x97F6, 0xE8EF, 0x97F5, 0xE8F0, 0x980F, 0xE8F1, 0x980C, 0xE8F2, 0x9838, 0xE8F3, 0x9824, 0xE8F4, 0x9821, 0xE8F5, 0x9837, 0xE8F6, 0x983D, 0xE8F7, 0x9846, 0xE8F8, 0x984F, 0xE8F9, 0x984B, 0xE8FA, 0x986B, 0xE8FB, 0x986F, 0xE8FC, 0x9870, 0xE940, 0x9871, 0xE941, 0x9874, 0xE942, 0x9873, 0xE943, 0x98AA, 0xE944, 0x98AF, 0xE945, 0x98B1, 0xE946, 0x98B6, 0xE947, 0x98C4, 0xE948, 0x98C3, 0xE949, 0x98C6, 0xE94A, 0x98E9, 0xE94B, 0x98EB, 0xE94C, 0x9903, 0xE94D, 0x9909, 0xE94E, 0x9912, 0xE94F, 0x9914, 0xE950, 0x9918, 0xE951, 0x9921, 0xE952, 0x991D, 0xE953, 0x991E, 0xE954, 0x9924, 0xE955, 0x9920, 0xE956, 0x992C, 0xE957, 0x992E, 0xE958, 0x993D, 0xE959, 0x993E, 0xE95A, 0x9942, 0xE95B, 0x9949, 0xE95C, 0x9945, 0xE95D, 0x9950, 0xE95E, 0x994B, 0xE95F, 0x9951, 0xE960, 0x9952, 0xE961, 0x994C, 0xE962, 0x9955, 0xE963, 0x9997, 0xE964, 0x9998, 0xE965, 0x99A5, 0xE966, 0x99AD, 0xE967, 0x99AE, 0xE968, 0x99BC, 0xE969, 0x99DF, 0xE96A, 0x99DB, 0xE96B, 0x99DD, 0xE96C, 0x99D8, 0xE96D, 0x99D1, 0xE96E, 0x99ED, 0xE96F, 0x99EE, 0xE970, 0x99F1, 0xE971, 0x99F2, 0xE972, 0x99FB, 0xE973, 0x99F8, 0xE974, 0x9A01, 0xE975, 0x9A0F, 0xE976, 0x9A05, 0xE977, 0x99E2, 0xE978, 0x9A19, 0xE979, 0x9A2B, 0xE97A, 0x9A37, 0xE97B, 0x9A45, 0xE97C, 0x9A42, 0xE97D, 0x9A40, 0xE97E, 0x9A43, 0xE980, 0x9A3E, 0xE981, 0x9A55, 0xE982, 0x9A4D, 0xE983, 0x9A5B, 0xE984, 0x9A57, 0xE985, 0x9A5F, 0xE986, 0x9A62, 0xE987, 0x9A65, 0xE988, 0x9A64, 0xE989, 0x9A69, 0xE98A, 0x9A6B, 0xE98B, 0x9A6A, 0xE98C, 0x9AAD, 0xE98D, 0x9AB0, 0xE98E, 0x9ABC, 0xE98F, 0x9AC0, 0xE990, 0x9ACF, 0xE991, 0x9AD1, 0xE992, 0x9AD3, 0xE993, 0x9AD4, 0xE994, 0x9ADE, 0xE995, 0x9ADF, 0xE996, 0x9AE2, 0xE997, 0x9AE3, 0xE998, 0x9AE6, 0xE999, 0x9AEF, 0xE99A, 0x9AEB, 0xE99B, 0x9AEE, 0xE99C, 0x9AF4, 0xE99D, 0x9AF1, 0xE99E, 0x9AF7, 0xE99F, 0x9AFB, 0xE9A0, 0x9B06, 0xE9A1, 0x9B18, 0xE9A2, 0x9B1A, 0xE9A3, 0x9B1F, 0xE9A4, 0x9B22, 0xE9A5, 0x9B23, 0xE9A6, 0x9B25, 0xE9A7, 0x9B27, 0xE9A8, 0x9B28, 0xE9A9, 0x9B29, 0xE9AA, 0x9B2A, 0xE9AB, 0x9B2E, 0xE9AC, 0x9B2F, 0xE9AD, 0x9B32, 0xE9AE, 0x9B44, 0xE9AF, 0x9B43, 0xE9B0, 0x9B4F, 0xE9B1, 0x9B4D, 0xE9B2, 0x9B4E, 0xE9B3, 0x9B51, 0xE9B4, 0x9B58, 0xE9B5, 0x9B74, 0xE9B6, 0x9B93, 0xE9B7, 0x9B83, 0xE9B8, 0x9B91, 0xE9B9, 0x9B96, 0xE9BA, 0x9B97, 0xE9BB, 0x9B9F, 0xE9BC, 0x9BA0, 0xE9BD, 0x9BA8, 0xE9BE, 0x9BB4, 0xE9BF, 0x9BC0, 0xE9C0, 0x9BCA, 0xE9C1, 0x9BB9, 0xE9C2, 0x9BC6, 0xE9C3, 0x9BCF, 0xE9C4, 0x9BD1, 0xE9C5, 0x9BD2, 0xE9C6, 0x9BE3, 0xE9C7, 0x9BE2, 0xE9C8, 0x9BE4, 0xE9C9, 0x9BD4, 0xE9CA, 0x9BE1, 0xE9CB, 0x9C3A, 0xE9CC, 0x9BF2, 0xE9CD, 0x9BF1, 0xE9CE, 0x9BF0, 0xE9CF, 0x9C15, 0xE9D0, 0x9C14, 0xE9D1, 0x9C09, 0xE9D2, 0x9C13, 0xE9D3, 0x9C0C, 0xE9D4, 0x9C06, 0xE9D5, 0x9C08, 0xE9D6, 0x9C12, 0xE9D7, 0x9C0A, 0xE9D8, 0x9C04, 0xE9D9, 0x9C2E, 0xE9DA, 0x9C1B, 0xE9DB, 0x9C25, 0xE9DC, 0x9C24, 0xE9DD, 0x9C21, 0xE9DE, 0x9C30, 0xE9DF, 0x9C47, 0xE9E0, 0x9C32, 0xE9E1, 0x9C46, 0xE9E2, 0x9C3E, 0xE9E3, 0x9C5A, 0xE9E4, 0x9C60, 0xE9E5, 0x9C67, 0xE9E6, 0x9C76, 0xE9E7, 0x9C78, 0xE9E8, 0x9CE7, 0xE9E9, 0x9CEC, 0xE9EA, 0x9CF0, 0xE9EB, 0x9D09, 0xE9EC, 0x9D08, 0xE9ED, 0x9CEB, 0xE9EE, 0x9D03, 0xE9EF, 0x9D06, 0xE9F0, 0x9D2A, 0xE9F1, 0x9D26, 0xE9F2, 0x9DAF, 0xE9F3, 0x9D23, 0xE9F4, 0x9D1F, 0xE9F5, 0x9D44, 0xE9F6, 0x9D15, 0xE9F7, 0x9D12, 0xE9F8, 0x9D41, 0xE9F9, 0x9D3F, 0xE9FA, 0x9D3E, 0xE9FB, 0x9D46, 0xE9FC, 0x9D48, 0xEA40, 0x9D5D, 0xEA41, 0x9D5E, 0xEA42, 0x9D64, 0xEA43, 0x9D51, 0xEA44, 0x9D50, 0xEA45, 0x9D59, 0xEA46, 0x9D72, 0xEA47, 0x9D89, 0xEA48, 0x9D87, 0xEA49, 0x9DAB, 0xEA4A, 0x9D6F, 0xEA4B, 0x9D7A, 0xEA4C, 0x9D9A, 0xEA4D, 0x9DA4, 0xEA4E, 0x9DA9, 0xEA4F, 0x9DB2, 0xEA50, 0x9DC4, 0xEA51, 0x9DC1, 0xEA52, 0x9DBB, 0xEA53, 0x9DB8, 0xEA54, 0x9DBA, 0xEA55, 0x9DC6, 0xEA56, 0x9DCF, 0xEA57, 0x9DC2, 0xEA58, 0x9DD9, 0xEA59, 0x9DD3, 0xEA5A, 0x9DF8, 0xEA5B, 0x9DE6, 0xEA5C, 0x9DED, 0xEA5D, 0x9DEF, 0xEA5E, 0x9DFD, 0xEA5F, 0x9E1A, 0xEA60, 0x9E1B, 0xEA61, 0x9E1E, 0xEA62, 0x9E75, 0xEA63, 0x9E79, 0xEA64, 0x9E7D, 0xEA65, 0x9E81, 0xEA66, 0x9E88, 0xEA67, 0x9E8B, 0xEA68, 0x9E8C, 0xEA69, 0x9E92, 0xEA6A, 0x9E95, 0xEA6B, 0x9E91, 0xEA6C, 0x9E9D, 0xEA6D, 0x9EA5, 0xEA6E, 0x9EA9, 0xEA6F, 0x9EB8, 0xEA70, 0x9EAA, 0xEA71, 0x9EAD, 0xEA72, 0x9761, 0xEA73, 0x9ECC, 0xEA74, 0x9ECE, 0xEA75, 0x9ECF, 0xEA76, 0x9ED0, 0xEA77, 0x9ED4, 0xEA78, 0x9EDC, 0xEA79, 0x9EDE, 0xEA7A, 0x9EDD, 0xEA7B, 0x9EE0, 0xEA7C, 0x9EE5, 0xEA7D, 0x9EE8, 0xEA7E, 0x9EEF, 0xEA80, 0x9EF4, 0xEA81, 0x9EF6, 0xEA82, 0x9EF7, 0xEA83, 0x9EF9, 0xEA84, 0x9EFB, 0xEA85, 0x9EFC, 0xEA86, 0x9EFD, 0xEA87, 0x9F07, 0xEA88, 0x9F08, 0xEA89, 0x76B7, 0xEA8A, 0x9F15, 0xEA8B, 0x9F21, 0xEA8C, 0x9F2C, 0xEA8D, 0x9F3E, 0xEA8E, 0x9F4A, 0xEA8F, 0x9F52, 0xEA90, 0x9F54, 0xEA91, 0x9F63, 0xEA92, 0x9F5F, 0xEA93, 0x9F60, 0xEA94, 0x9F61, 0xEA95, 0x9F66, 0xEA96, 0x9F67, 0xEA97, 0x9F6C, 0xEA98, 0x9F6A, 0xEA99, 0x9F77, 0xEA9A, 0x9F72, 0xEA9B, 0x9F76, 0xEA9C, 0x9F95, 0xEA9D, 0x9F9C, 0xEA9E, 0x9FA0, 0xEA9F, 0x582F, 0xEAA0, 0x69C7, 0xEAA1, 0x9059, 0xEAA2, 0x7464, 0xEAA3, 0x51DC, 0xEAA4, 0x7199, 0xFA40, 0x2170, 0xFA41, 0x2171, 0xFA42, 0x2172, 0xFA43, 0x2173, 0xFA44, 0x2174, 0xFA45, 0x2175, 0xFA46, 0x2176, 0xFA47, 0x2177, 0xFA48, 0x2178, 0xFA49, 0x2179, 0xFA55, 0xFFE4, 0xFA56, 0xFF07, 0xFA57, 0xFF02, 0xFA5C, 0x7E8A, 0xFA5D, 0x891C, 0xFA5E, 0x9348, 0xFA5F, 0x9288, 0xFA60, 0x84DC, 0xFA61, 0x4FC9, 0xFA62, 0x70BB, 0xFA63, 0x6631, 0xFA64, 0x68C8, 0xFA65, 0x92F9, 0xFA66, 0x66FB, 0xFA67, 0x5F45, 0xFA68, 0x4E28, 0xFA69, 0x4EE1, 0xFA6A, 0x4EFC, 0xFA6B, 0x4F00, 0xFA6C, 0x4F03, 0xFA6D, 0x4F39, 0xFA6E, 0x4F56, 0xFA6F, 0x4F92, 0xFA70, 0x4F8A, 0xFA71, 0x4F9A, 0xFA72, 0x4F94, 0xFA73, 0x4FCD, 0xFA74, 0x5040, 0xFA75, 0x5022, 0xFA76, 0x4FFF, 0xFA77, 0x501E, 0xFA78, 0x5046, 0xFA79, 0x5070, 0xFA7A, 0x5042, 0xFA7B, 0x5094, 0xFA7C, 0x50F4, 0xFA7D, 0x50D8, 0xFA7E, 0x514A, 0xFA80, 0x5164, 0xFA81, 0x519D, 0xFA82, 0x51BE, 0xFA83, 0x51EC, 0xFA84, 0x5215, 0xFA85, 0x529C, 0xFA86, 0x52A6, 0xFA87, 0x52C0, 0xFA88, 0x52DB, 0xFA89, 0x5300, 0xFA8A, 0x5307, 0xFA8B, 0x5324, 0xFA8C, 0x5372, 0xFA8D, 0x5393, 0xFA8E, 0x53B2, 0xFA8F, 0x53DD, 0xFA90, 0xFA0E, 0xFA91, 0x549C, 0xFA92, 0x548A, 0xFA93, 0x54A9, 0xFA94, 0x54FF, 0xFA95, 0x5586, 0xFA96, 0x5759, 0xFA97, 0x5765, 0xFA98, 0x57AC, 0xFA99, 0x57C8, 0xFA9A, 0x57C7, 0xFA9B, 0xFA0F, 0xFA9C, 0xFA10, 0xFA9D, 0x589E, 0xFA9E, 0x58B2, 0xFA9F, 0x590B, 0xFAA0, 0x5953, 0xFAA1, 0x595B, 0xFAA2, 0x595D, 0xFAA3, 0x5963, 0xFAA4, 0x59A4, 0xFAA5, 0x59BA, 0xFAA6, 0x5B56, 0xFAA7, 0x5BC0, 0xFAA8, 0x752F, 0xFAA9, 0x5BD8, 0xFAAA, 0x5BEC, 0xFAAB, 0x5C1E, 0xFAAC, 0x5CA6, 0xFAAD, 0x5CBA, 0xFAAE, 0x5CF5, 0xFAAF, 0x5D27, 0xFAB0, 0x5D53, 0xFAB1, 0xFA11, 0xFAB2, 0x5D42, 0xFAB3, 0x5D6D, 0xFAB4, 0x5DB8, 0xFAB5, 0x5DB9, 0xFAB6, 0x5DD0, 0xFAB7, 0x5F21, 0xFAB8, 0x5F34, 0xFAB9, 0x5F67, 0xFABA, 0x5FB7, 0xFABB, 0x5FDE, 0xFABC, 0x605D, 0xFABD, 0x6085, 0xFABE, 0x608A, 0xFABF, 0x60DE, 0xFAC0, 0x60D5, 0xFAC1, 0x6120, 0xFAC2, 0x60F2, 0xFAC3, 0x6111, 0xFAC4, 0x6137, 0xFAC5, 0x6130, 0xFAC6, 0x6198, 0xFAC7, 0x6213, 0xFAC8, 0x62A6, 0xFAC9, 0x63F5, 0xFACA, 0x6460, 0xFACB, 0x649D, 0xFACC, 0x64CE, 0xFACD, 0x654E, 0xFACE, 0x6600, 0xFACF, 0x6615, 0xFAD0, 0x663B, 0xFAD1, 0x6609, 0xFAD2, 0x662E, 0xFAD3, 0x661E, 0xFAD4, 0x6624, 0xFAD5, 0x6665, 0xFAD6, 0x6657, 0xFAD7, 0x6659, 0xFAD8, 0xFA12, 0xFAD9, 0x6673, 0xFADA, 0x6699, 0xFADB, 0x66A0, 0xFADC, 0x66B2, 0xFADD, 0x66BF, 0xFADE, 0x66FA, 0xFADF, 0x670E, 0xFAE0, 0xF929, 0xFAE1, 0x6766, 0xFAE2, 0x67BB, 0xFAE3, 0x6852, 0xFAE4, 0x67C0, 0xFAE5, 0x6801, 0xFAE6, 0x6844, 0xFAE7, 0x68CF, 0xFAE8, 0xFA13, 0xFAE9, 0x6968, 0xFAEA, 0xFA14, 0xFAEB, 0x6998, 0xFAEC, 0x69E2, 0xFAED, 0x6A30, 0xFAEE, 0x6A6B, 0xFAEF, 0x6A46, 0xFAF0, 0x6A73, 0xFAF1, 0x6A7E, 0xFAF2, 0x6AE2, 0xFAF3, 0x6AE4, 0xFAF4, 0x6BD6, 0xFAF5, 0x6C3F, 0xFAF6, 0x6C5C, 0xFAF7, 0x6C86, 0xFAF8, 0x6C6F, 0xFAF9, 0x6CDA, 0xFAFA, 0x6D04, 0xFAFB, 0x6D87, 0xFAFC, 0x6D6F, 0xFB40, 0x6D96, 0xFB41, 0x6DAC, 0xFB42, 0x6DCF, 0xFB43, 0x6DF8, 0xFB44, 0x6DF2, 0xFB45, 0x6DFC, 0xFB46, 0x6E39, 0xFB47, 0x6E5C, 0xFB48, 0x6E27, 0xFB49, 0x6E3C, 0xFB4A, 0x6EBF, 0xFB4B, 0x6F88, 0xFB4C, 0x6FB5, 0xFB4D, 0x6FF5, 0xFB4E, 0x7005, 0xFB4F, 0x7007, 0xFB50, 0x7028, 0xFB51, 0x7085, 0xFB52, 0x70AB, 0xFB53, 0x710F, 0xFB54, 0x7104, 0xFB55, 0x715C, 0xFB56, 0x7146, 0xFB57, 0x7147, 0xFB58, 0xFA15, 0xFB59, 0x71C1, 0xFB5A, 0x71FE, 0xFB5B, 0x72B1, 0xFB5C, 0x72BE, 0xFB5D, 0x7324, 0xFB5E, 0xFA16, 0xFB5F, 0x7377, 0xFB60, 0x73BD, 0xFB61, 0x73C9, 0xFB62, 0x73D6, 0xFB63, 0x73E3, 0xFB64, 0x73D2, 0xFB65, 0x7407, 0xFB66, 0x73F5, 0xFB67, 0x7426, 0xFB68, 0x742A, 0xFB69, 0x7429, 0xFB6A, 0x742E, 0xFB6B, 0x7462, 0xFB6C, 0x7489, 0xFB6D, 0x749F, 0xFB6E, 0x7501, 0xFB6F, 0x756F, 0xFB70, 0x7682, 0xFB71, 0x769C, 0xFB72, 0x769E, 0xFB73, 0x769B, 0xFB74, 0x76A6, 0xFB75, 0xFA17, 0xFB76, 0x7746, 0xFB77, 0x52AF, 0xFB78, 0x7821, 0xFB79, 0x784E, 0xFB7A, 0x7864, 0xFB7B, 0x787A, 0xFB7C, 0x7930, 0xFB7D, 0xFA18, 0xFB7E, 0xFA19, 0xFB80, 0xFA1A, 0xFB81, 0x7994, 0xFB82, 0xFA1B, 0xFB83, 0x799B, 0xFB84, 0x7AD1, 0xFB85, 0x7AE7, 0xFB86, 0xFA1C, 0xFB87, 0x7AEB, 0xFB88, 0x7B9E, 0xFB89, 0xFA1D, 0xFB8A, 0x7D48, 0xFB8B, 0x7D5C, 0xFB8C, 0x7DB7, 0xFB8D, 0x7DA0, 0xFB8E, 0x7DD6, 0xFB8F, 0x7E52, 0xFB90, 0x7F47, 0xFB91, 0x7FA1, 0xFB92, 0xFA1E, 0xFB93, 0x8301, 0xFB94, 0x8362, 0xFB95, 0x837F, 0xFB96, 0x83C7, 0xFB97, 0x83F6, 0xFB98, 0x8448, 0xFB99, 0x84B4, 0xFB9A, 0x8553, 0xFB9B, 0x8559, 0xFB9C, 0x856B, 0xFB9D, 0xFA1F, 0xFB9E, 0x85B0, 0xFB9F, 0xFA20, 0xFBA0, 0xFA21, 0xFBA1, 0x8807, 0xFBA2, 0x88F5, 0xFBA3, 0x8A12, 0xFBA4, 0x8A37, 0xFBA5, 0x8A79, 0xFBA6, 0x8AA7, 0xFBA7, 0x8ABE, 0xFBA8, 0x8ADF, 0xFBA9, 0xFA22, 0xFBAA, 0x8AF6, 0xFBAB, 0x8B53, 0xFBAC, 0x8B7F, 0xFBAD, 0x8CF0, 0xFBAE, 0x8CF4, 0xFBAF, 0x8D12, 0xFBB0, 0x8D76, 0xFBB1, 0xFA23, 0xFBB2, 0x8ECF, 0xFBB3, 0xFA24, 0xFBB4, 0xFA25, 0xFBB5, 0x9067, 0xFBB6, 0x90DE, 0xFBB7, 0xFA26, 0xFBB8, 0x9115, 0xFBB9, 0x9127, 0xFBBA, 0x91DA, 0xFBBB, 0x91D7, 0xFBBC, 0x91DE, 0xFBBD, 0x91ED, 0xFBBE, 0x91EE, 0xFBBF, 0x91E4, 0xFBC0, 0x91E5, 0xFBC1, 0x9206, 0xFBC2, 0x9210, 0xFBC3, 0x920A, 0xFBC4, 0x923A, 0xFBC5, 0x9240, 0xFBC6, 0x923C, 0xFBC7, 0x924E, 0xFBC8, 0x9259, 0xFBC9, 0x9251, 0xFBCA, 0x9239, 0xFBCB, 0x9267, 0xFBCC, 0x92A7, 0xFBCD, 0x9277, 0xFBCE, 0x9278, 0xFBCF, 0x92E7, 0xFBD0, 0x92D7, 0xFBD1, 0x92D9, 0xFBD2, 0x92D0, 0xFBD3, 0xFA27, 0xFBD4, 0x92D5, 0xFBD5, 0x92E0, 0xFBD6, 0x92D3, 0xFBD7, 0x9325, 0xFBD8, 0x9321, 0xFBD9, 0x92FB, 0xFBDA, 0xFA28, 0xFBDB, 0x931E, 0xFBDC, 0x92FF, 0xFBDD, 0x931D, 0xFBDE, 0x9302, 0xFBDF, 0x9370, 0xFBE0, 0x9357, 0xFBE1, 0x93A4, 0xFBE2, 0x93C6, 0xFBE3, 0x93DE, 0xFBE4, 0x93F8, 0xFBE5, 0x9431, 0xFBE6, 0x9445, 0xFBE7, 0x9448, 0xFBE8, 0x9592, 0xFBE9, 0xF9DC, 0xFBEA, 0xFA29, 0xFBEB, 0x969D, 0xFBEC, 0x96AF, 0xFBED, 0x9733, 0xFBEE, 0x973B, 0xFBEF, 0x9743, 0xFBF0, 0x974D, 0xFBF1, 0x974F, 0xFBF2, 0x9751, 0xFBF3, 0x9755, 0xFBF4, 0x9857, 0xFBF5, 0x9865, 0xFBF6, 0xFA2A, 0xFBF7, 0xFA2B, 0xFBF8, 0x9927, 0xFBF9, 0xFA2C, 0xFBFA, 0x999E, 0xFBFB, 0x9A4E, 0xFBFC, 0x9AD9, 0xFC40, 0x9ADC, 0xFC41, 0x9B75, 0xFC42, 0x9B72, 0xFC43, 0x9B8F, 0xFC44, 0x9BB1, 0xFC45, 0x9BBB, 0xFC46, 0x9C00, 0xFC47, 0x9D70, 0xFC48, 0x9D6B, 0xFC49, 0xFA2D, 0xFC4A, 0x9E19, 0xFC4B, 0x9ED1, 0, 0 }; #endif #if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */ static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ 0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4, 0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE, 0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9, 0x0144, 0xA8BD, 0x0148, 0xA8BE, 0x014D, 0xA8AD, 0x016B, 0xA8B1, 0x01CE, 0xA8A3, 0x01D0, 0xA8AB, 0x01D2, 0xA8AF, 0x01D4, 0xA8B3, 0x01D6, 0xA8B5, 0x01D8, 0xA8B6, 0x01DA, 0xA8B7, 0x01DC, 0xA8B8, 0x0251, 0xA8BB, 0x0261, 0xA8C0, 0x02C7, 0xA1A6, 0x02C9, 0xA1A5, 0x02CA, 0xA840, 0x02CB, 0xA841, 0x02D9, 0xA842, 0x0391, 0xA6A1, 0x0392, 0xA6A2, 0x0393, 0xA6A3, 0x0394, 0xA6A4, 0x0395, 0xA6A5, 0x0396, 0xA6A6, 0x0397, 0xA6A7, 0x0398, 0xA6A8, 0x0399, 0xA6A9, 0x039A, 0xA6AA, 0x039B, 0xA6AB, 0x039C, 0xA6AC, 0x039D, 0xA6AD, 0x039E, 0xA6AE, 0x039F, 0xA6AF, 0x03A0, 0xA6B0, 0x03A1, 0xA6B1, 0x03A3, 0xA6B2, 0x03A4, 0xA6B3, 0x03A5, 0xA6B4, 0x03A6, 0xA6B5, 0x03A7, 0xA6B6, 0x03A8, 0xA6B7, 0x03A9, 0xA6B8, 0x03B1, 0xA6C1, 0x03B2, 0xA6C2, 0x03B3, 0xA6C3, 0x03B4, 0xA6C4, 0x03B5, 0xA6C5, 0x03B6, 0xA6C6, 0x03B7, 0xA6C7, 0x03B8, 0xA6C8, 0x03B9, 0xA6C9, 0x03BA, 0xA6CA, 0x03BB, 0xA6CB, 0x03BC, 0xA6CC, 0x03BD, 0xA6CD, 0x03BE, 0xA6CE, 0x03BF, 0xA6CF, 0x03C0, 0xA6D0, 0x03C1, 0xA6D1, 0x03C3, 0xA6D2, 0x03C4, 0xA6D3, 0x03C5, 0xA6D4, 0x03C6, 0xA6D5, 0x03C7, 0xA6D6, 0x03C8, 0xA6D7, 0x03C9, 0xA6D8, 0x0401, 0xA7A7, 0x0410, 0xA7A1, 0x0411, 0xA7A2, 0x0412, 0xA7A3, 0x0413, 0xA7A4, 0x0414, 0xA7A5, 0x0415, 0xA7A6, 0x0416, 0xA7A8, 0x0417, 0xA7A9, 0x0418, 0xA7AA, 0x0419, 0xA7AB, 0x041A, 0xA7AC, 0x041B, 0xA7AD, 0x041C, 0xA7AE, 0x041D, 0xA7AF, 0x041E, 0xA7B0, 0x041F, 0xA7B1, 0x0420, 0xA7B2, 0x0421, 0xA7B3, 0x0422, 0xA7B4, 0x0423, 0xA7B5, 0x0424, 0xA7B6, 0x0425, 0xA7B7, 0x0426, 0xA7B8, 0x0427, 0xA7B9, 0x0428, 0xA7BA, 0x0429, 0xA7BB, 0x042A, 0xA7BC, 0x042B, 0xA7BD, 0x042C, 0xA7BE, 0x042D, 0xA7BF, 0x042E, 0xA7C0, 0x042F, 0xA7C1, 0x0430, 0xA7D1, 0x0431, 0xA7D2, 0x0432, 0xA7D3, 0x0433, 0xA7D4, 0x0434, 0xA7D5, 0x0435, 0xA7D6, 0x0436, 0xA7D8, 0x0437, 0xA7D9, 0x0438, 0xA7DA, 0x0439, 0xA7DB, 0x043A, 0xA7DC, 0x043B, 0xA7DD, 0x043C, 0xA7DE, 0x043D, 0xA7DF, 0x043E, 0xA7E0, 0x043F, 0xA7E1, 0x0440, 0xA7E2, 0x0441, 0xA7E3, 0x0442, 0xA7E4, 0x0443, 0xA7E5, 0x0444, 0xA7E6, 0x0445, 0xA7E7, 0x0446, 0xA7E8, 0x0447, 0xA7E9, 0x0448, 0xA7EA, 0x0449, 0xA7EB, 0x044A, 0xA7EC, 0x044B, 0xA7ED, 0x044C, 0xA7EE, 0x044D, 0xA7EF, 0x044E, 0xA7F0, 0x044F, 0xA7F1, 0x0451, 0xA7D7, 0x2010, 0xA95C, 0x2013, 0xA843, 0x2014, 0xA1AA, 0x2015, 0xA844, 0x2016, 0xA1AC, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, 0x2025, 0xA845, 0x2026, 0xA1AD, 0x2030, 0xA1EB, 0x2032, 0xA1E4, 0x2033, 0xA1E5, 0x2035, 0xA846, 0x203B, 0xA1F9, 0x20AC, 0x0080, 0x2103, 0xA1E6, 0x2105, 0xA847, 0x2109, 0xA848, 0x2116, 0xA1ED, 0x2121, 0xA959, 0x2160, 0xA2F1, 0x2161, 0xA2F2, 0x2162, 0xA2F3, 0x2163, 0xA2F4, 0x2164, 0xA2F5, 0x2165, 0xA2F6, 0x2166, 0xA2F7, 0x2167, 0xA2F8, 0x2168, 0xA2F9, 0x2169, 0xA2FA, 0x216A, 0xA2FB, 0x216B, 0xA2FC, 0x2170, 0xA2A1, 0x2171, 0xA2A2, 0x2172, 0xA2A3, 0x2173, 0xA2A4, 0x2174, 0xA2A5, 0x2175, 0xA2A6, 0x2176, 0xA2A7, 0x2177, 0xA2A8, 0x2178, 0xA2A9, 0x2179, 0xA2AA, 0x2190, 0xA1FB, 0x2191, 0xA1FC, 0x2192, 0xA1FA, 0x2193, 0xA1FD, 0x2196, 0xA849, 0x2197, 0xA84A, 0x2198, 0xA84B, 0x2199, 0xA84C, 0x2208, 0xA1CA, 0x220F, 0xA1C7, 0x2211, 0xA1C6, 0x2215, 0xA84D, 0x221A, 0xA1CC, 0x221D, 0xA1D8, 0x221E, 0xA1DE, 0x221F, 0xA84E, 0x2220, 0xA1CF, 0x2223, 0xA84F, 0x2225, 0xA1CE, 0x2227, 0xA1C4, 0x2228, 0xA1C5, 0x2229, 0xA1C9, 0x222A, 0xA1C8, 0x222B, 0xA1D2, 0x222E, 0xA1D3, 0x2234, 0xA1E0, 0x2235, 0xA1DF, 0x2236, 0xA1C3, 0x2237, 0xA1CB, 0x223D, 0xA1D7, 0x2248, 0xA1D6, 0x224C, 0xA1D5, 0x2252, 0xA850, 0x2260, 0xA1D9, 0x2261, 0xA1D4, 0x2264, 0xA1DC, 0x2265, 0xA1DD, 0x2266, 0xA851, 0x2267, 0xA852, 0x226E, 0xA1DA, 0x226F, 0xA1DB, 0x2295, 0xA892, 0x2299, 0xA1D1, 0x22A5, 0xA1CD, 0x22BF, 0xA853, 0x2312, 0xA1D0, 0x2460, 0xA2D9, 0x2461, 0xA2DA, 0x2462, 0xA2DB, 0x2463, 0xA2DC, 0x2464, 0xA2DD, 0x2465, 0xA2DE, 0x2466, 0xA2DF, 0x2467, 0xA2E0, 0x2468, 0xA2E1, 0x2469, 0xA2E2, 0x2474, 0xA2C5, 0x2475, 0xA2C6, 0x2476, 0xA2C7, 0x2477, 0xA2C8, 0x2478, 0xA2C9, 0x2479, 0xA2CA, 0x247A, 0xA2CB, 0x247B, 0xA2CC, 0x247C, 0xA2CD, 0x247D, 0xA2CE, 0x247E, 0xA2CF, 0x247F, 0xA2D0, 0x2480, 0xA2D1, 0x2481, 0xA2D2, 0x2482, 0xA2D3, 0x2483, 0xA2D4, 0x2484, 0xA2D5, 0x2485, 0xA2D6, 0x2486, 0xA2D7, 0x2487, 0xA2D8, 0x2488, 0xA2B1, 0x2489, 0xA2B2, 0x248A, 0xA2B3, 0x248B, 0xA2B4, 0x248C, 0xA2B5, 0x248D, 0xA2B6, 0x248E, 0xA2B7, 0x248F, 0xA2B8, 0x2490, 0xA2B9, 0x2491, 0xA2BA, 0x2492, 0xA2BB, 0x2493, 0xA2BC, 0x2494, 0xA2BD, 0x2495, 0xA2BE, 0x2496, 0xA2BF, 0x2497, 0xA2C0, 0x2498, 0xA2C1, 0x2499, 0xA2C2, 0x249A, 0xA2C3, 0x249B, 0xA2C4, 0x2500, 0xA9A4, 0x2501, 0xA9A5, 0x2502, 0xA9A6, 0x2503, 0xA9A7, 0x2504, 0xA9A8, 0x2505, 0xA9A9, 0x2506, 0xA9AA, 0x2507, 0xA9AB, 0x2508, 0xA9AC, 0x2509, 0xA9AD, 0x250A, 0xA9AE, 0x250B, 0xA9AF, 0x250C, 0xA9B0, 0x250D, 0xA9B1, 0x250E, 0xA9B2, 0x250F, 0xA9B3, 0x2510, 0xA9B4, 0x2511, 0xA9B5, 0x2512, 0xA9B6, 0x2513, 0xA9B7, 0x2514, 0xA9B8, 0x2515, 0xA9B9, 0x2516, 0xA9BA, 0x2517, 0xA9BB, 0x2518, 0xA9BC, 0x2519, 0xA9BD, 0x251A, 0xA9BE, 0x251B, 0xA9BF, 0x251C, 0xA9C0, 0x251D, 0xA9C1, 0x251E, 0xA9C2, 0x251F, 0xA9C3, 0x2520, 0xA9C4, 0x2521, 0xA9C5, 0x2522, 0xA9C6, 0x2523, 0xA9C7, 0x2524, 0xA9C8, 0x2525, 0xA9C9, 0x2526, 0xA9CA, 0x2527, 0xA9CB, 0x2528, 0xA9CC, 0x2529, 0xA9CD, 0x252A, 0xA9CE, 0x252B, 0xA9CF, 0x252C, 0xA9D0, 0x252D, 0xA9D1, 0x252E, 0xA9D2, 0x252F, 0xA9D3, 0x2530, 0xA9D4, 0x2531, 0xA9D5, 0x2532, 0xA9D6, 0x2533, 0xA9D7, 0x2534, 0xA9D8, 0x2535, 0xA9D9, 0x2536, 0xA9DA, 0x2537, 0xA9DB, 0x2538, 0xA9DC, 0x2539, 0xA9DD, 0x253A, 0xA9DE, 0x253B, 0xA9DF, 0x253C, 0xA9E0, 0x253D, 0xA9E1, 0x253E, 0xA9E2, 0x253F, 0xA9E3, 0x2540, 0xA9E4, 0x2541, 0xA9E5, 0x2542, 0xA9E6, 0x2543, 0xA9E7, 0x2544, 0xA9E8, 0x2545, 0xA9E9, 0x2546, 0xA9EA, 0x2547, 0xA9EB, 0x2548, 0xA9EC, 0x2549, 0xA9ED, 0x254A, 0xA9EE, 0x254B, 0xA9EF, 0x2550, 0xA854, 0x2551, 0xA855, 0x2552, 0xA856, 0x2553, 0xA857, 0x2554, 0xA858, 0x2555, 0xA859, 0x2556, 0xA85A, 0x2557, 0xA85B, 0x2558, 0xA85C, 0x2559, 0xA85D, 0x255A, 0xA85E, 0x255B, 0xA85F, 0x255C, 0xA860, 0x255D, 0xA861, 0x255E, 0xA862, 0x255F, 0xA863, 0x2560, 0xA864, 0x2561, 0xA865, 0x2562, 0xA866, 0x2563, 0xA867, 0x2564, 0xA868, 0x2565, 0xA869, 0x2566, 0xA86A, 0x2567, 0xA86B, 0x2568, 0xA86C, 0x2569, 0xA86D, 0x256A, 0xA86E, 0x256B, 0xA86F, 0x256C, 0xA870, 0x256D, 0xA871, 0x256E, 0xA872, 0x256F, 0xA873, 0x2570, 0xA874, 0x2571, 0xA875, 0x2572, 0xA876, 0x2573, 0xA877, 0x2581, 0xA878, 0x2582, 0xA879, 0x2583, 0xA87A, 0x2584, 0xA87B, 0x2585, 0xA87C, 0x2586, 0xA87D, 0x2587, 0xA87E, 0x2588, 0xA880, 0x2589, 0xA881, 0x258A, 0xA882, 0x258B, 0xA883, 0x258C, 0xA884, 0x258D, 0xA885, 0x258E, 0xA886, 0x258F, 0xA887, 0x2593, 0xA888, 0x2594, 0xA889, 0x2595, 0xA88A, 0x25A0, 0xA1F6, 0x25A1, 0xA1F5, 0x25B2, 0xA1F8, 0x25B3, 0xA1F7, 0x25BC, 0xA88B, 0x25BD, 0xA88C, 0x25C6, 0xA1F4, 0x25C7, 0xA1F3, 0x25CB, 0xA1F0, 0x25CE, 0xA1F2, 0x25CF, 0xA1F1, 0x25E2, 0xA88D, 0x25E3, 0xA88E, 0x25E4, 0xA88F, 0x25E5, 0xA890, 0x2605, 0xA1EF, 0x2606, 0xA1EE, 0x2609, 0xA891, 0x2640, 0xA1E2, 0x2642, 0xA1E1, 0x3000, 0xA1A1, 0x3001, 0xA1A2, 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3005, 0xA1A9, 0x3006, 0xA965, 0x3007, 0xA996, 0x3008, 0xA1B4, 0x3009, 0xA1B5, 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BE, 0x3011, 0xA1BF, 0x3012, 0xA893, 0x3013, 0xA1FE, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3016, 0xA1BC, 0x3017, 0xA1BD, 0x301D, 0xA894, 0x301E, 0xA895, 0x3021, 0xA940, 0x3022, 0xA941, 0x3023, 0xA942, 0x3024, 0xA943, 0x3025, 0xA944, 0x3026, 0xA945, 0x3027, 0xA946, 0x3028, 0xA947, 0x3029, 0xA948, 0x3041, 0xA4A1, 0x3042, 0xA4A2, 0x3043, 0xA4A3, 0x3044, 0xA4A4, 0x3045, 0xA4A5, 0x3046, 0xA4A6, 0x3047, 0xA4A7, 0x3048, 0xA4A8, 0x3049, 0xA4A9, 0x304A, 0xA4AA, 0x304B, 0xA4AB, 0x304C, 0xA4AC, 0x304D, 0xA4AD, 0x304E, 0xA4AE, 0x304F, 0xA4AF, 0x3050, 0xA4B0, 0x3051, 0xA4B1, 0x3052, 0xA4B2, 0x3053, 0xA4B3, 0x3054, 0xA4B4, 0x3055, 0xA4B5, 0x3056, 0xA4B6, 0x3057, 0xA4B7, 0x3058, 0xA4B8, 0x3059, 0xA4B9, 0x305A, 0xA4BA, 0x305B, 0xA4BB, 0x305C, 0xA4BC, 0x305D, 0xA4BD, 0x305E, 0xA4BE, 0x305F, 0xA4BF, 0x3060, 0xA4C0, 0x3061, 0xA4C1, 0x3062, 0xA4C2, 0x3063, 0xA4C3, 0x3064, 0xA4C4, 0x3065, 0xA4C5, 0x3066, 0xA4C6, 0x3067, 0xA4C7, 0x3068, 0xA4C8, 0x3069, 0xA4C9, 0x306A, 0xA4CA, 0x306B, 0xA4CB, 0x306C, 0xA4CC, 0x306D, 0xA4CD, 0x306E, 0xA4CE, 0x306F, 0xA4CF, 0x3070, 0xA4D0, 0x3071, 0xA4D1, 0x3072, 0xA4D2, 0x3073, 0xA4D3, 0x3074, 0xA4D4, 0x3075, 0xA4D5, 0x3076, 0xA4D6, 0x3077, 0xA4D7, 0x3078, 0xA4D8, 0x3079, 0xA4D9, 0x307A, 0xA4DA, 0x307B, 0xA4DB, 0x307C, 0xA4DC, 0x307D, 0xA4DD, 0x307E, 0xA4DE, 0x307F, 0xA4DF, 0x3080, 0xA4E0, 0x3081, 0xA4E1, 0x3082, 0xA4E2, 0x3083, 0xA4E3, 0x3084, 0xA4E4, 0x3085, 0xA4E5, 0x3086, 0xA4E6, 0x3087, 0xA4E7, 0x3088, 0xA4E8, 0x3089, 0xA4E9, 0x308A, 0xA4EA, 0x308B, 0xA4EB, 0x308C, 0xA4EC, 0x308D, 0xA4ED, 0x308E, 0xA4EE, 0x308F, 0xA4EF, 0x3090, 0xA4F0, 0x3091, 0xA4F1, 0x3092, 0xA4F2, 0x3093, 0xA4F3, 0x309B, 0xA961, 0x309C, 0xA962, 0x309D, 0xA966, 0x309E, 0xA967, 0x30A1, 0xA5A1, 0x30A2, 0xA5A2, 0x30A3, 0xA5A3, 0x30A4, 0xA5A4, 0x30A5, 0xA5A5, 0x30A6, 0xA5A6, 0x30A7, 0xA5A7, 0x30A8, 0xA5A8, 0x30A9, 0xA5A9, 0x30AA, 0xA5AA, 0x30AB, 0xA5AB, 0x30AC, 0xA5AC, 0x30AD, 0xA5AD, 0x30AE, 0xA5AE, 0x30AF, 0xA5AF, 0x30B0, 0xA5B0, 0x30B1, 0xA5B1, 0x30B2, 0xA5B2, 0x30B3, 0xA5B3, 0x30B4, 0xA5B4, 0x30B5, 0xA5B5, 0x30B6, 0xA5B6, 0x30B7, 0xA5B7, 0x30B8, 0xA5B8, 0x30B9, 0xA5B9, 0x30BA, 0xA5BA, 0x30BB, 0xA5BB, 0x30BC, 0xA5BC, 0x30BD, 0xA5BD, 0x30BE, 0xA5BE, 0x30BF, 0xA5BF, 0x30C0, 0xA5C0, 0x30C1, 0xA5C1, 0x30C2, 0xA5C2, 0x30C3, 0xA5C3, 0x30C4, 0xA5C4, 0x30C5, 0xA5C5, 0x30C6, 0xA5C6, 0x30C7, 0xA5C7, 0x30C8, 0xA5C8, 0x30C9, 0xA5C9, 0x30CA, 0xA5CA, 0x30CB, 0xA5CB, 0x30CC, 0xA5CC, 0x30CD, 0xA5CD, 0x30CE, 0xA5CE, 0x30CF, 0xA5CF, 0x30D0, 0xA5D0, 0x30D1, 0xA5D1, 0x30D2, 0xA5D2, 0x30D3, 0xA5D3, 0x30D4, 0xA5D4, 0x30D5, 0xA5D5, 0x30D6, 0xA5D6, 0x30D7, 0xA5D7, 0x30D8, 0xA5D8, 0x30D9, 0xA5D9, 0x30DA, 0xA5DA, 0x30DB, 0xA5DB, 0x30DC, 0xA5DC, 0x30DD, 0xA5DD, 0x30DE, 0xA5DE, 0x30DF, 0xA5DF, 0x30E0, 0xA5E0, 0x30E1, 0xA5E1, 0x30E2, 0xA5E2, 0x30E3, 0xA5E3, 0x30E4, 0xA5E4, 0x30E5, 0xA5E5, 0x30E6, 0xA5E6, 0x30E7, 0xA5E7, 0x30E8, 0xA5E8, 0x30E9, 0xA5E9, 0x30EA, 0xA5EA, 0x30EB, 0xA5EB, 0x30EC, 0xA5EC, 0x30ED, 0xA5ED, 0x30EE, 0xA5EE, 0x30EF, 0xA5EF, 0x30F0, 0xA5F0, 0x30F1, 0xA5F1, 0x30F2, 0xA5F2, 0x30F3, 0xA5F3, 0x30F4, 0xA5F4, 0x30F5, 0xA5F5, 0x30F6, 0xA5F6, 0x30FC, 0xA960, 0x30FD, 0xA963, 0x30FE, 0xA964, 0x3105, 0xA8C5, 0x3106, 0xA8C6, 0x3107, 0xA8C7, 0x3108, 0xA8C8, 0x3109, 0xA8C9, 0x310A, 0xA8CA, 0x310B, 0xA8CB, 0x310C, 0xA8CC, 0x310D, 0xA8CD, 0x310E, 0xA8CE, 0x310F, 0xA8CF, 0x3110, 0xA8D0, 0x3111, 0xA8D1, 0x3112, 0xA8D2, 0x3113, 0xA8D3, 0x3114, 0xA8D4, 0x3115, 0xA8D5, 0x3116, 0xA8D6, 0x3117, 0xA8D7, 0x3118, 0xA8D8, 0x3119, 0xA8D9, 0x311A, 0xA8DA, 0x311B, 0xA8DB, 0x311C, 0xA8DC, 0x311D, 0xA8DD, 0x311E, 0xA8DE, 0x311F, 0xA8DF, 0x3120, 0xA8E0, 0x3121, 0xA8E1, 0x3122, 0xA8E2, 0x3123, 0xA8E3, 0x3124, 0xA8E4, 0x3125, 0xA8E5, 0x3126, 0xA8E6, 0x3127, 0xA8E7, 0x3128, 0xA8E8, 0x3129, 0xA8E9, 0x3220, 0xA2E5, 0x3221, 0xA2E6, 0x3222, 0xA2E7, 0x3223, 0xA2E8, 0x3224, 0xA2E9, 0x3225, 0xA2EA, 0x3226, 0xA2EB, 0x3227, 0xA2EC, 0x3228, 0xA2ED, 0x3229, 0xA2EE, 0x3231, 0xA95A, 0x32A3, 0xA949, 0x338E, 0xA94A, 0x338F, 0xA94B, 0x339C, 0xA94C, 0x339D, 0xA94D, 0x339E, 0xA94E, 0x33A1, 0xA94F, 0x33C4, 0xA950, 0x33CE, 0xA951, 0x33D1, 0xA952, 0x33D2, 0xA953, 0x33D5, 0xA954, 0x4E00, 0xD2BB, 0x4E01, 0xB6A1, 0x4E02, 0x8140, 0x4E03, 0xC6DF, 0x4E04, 0x8141, 0x4E05, 0x8142, 0x4E06, 0x8143, 0x4E07, 0xCDF2, 0x4E08, 0xD5C9, 0x4E09, 0xC8FD, 0x4E0A, 0xC9CF, 0x4E0B, 0xCFC2, 0x4E0C, 0xD8A2, 0x4E0D, 0xB2BB, 0x4E0E, 0xD3EB, 0x4E0F, 0x8144, 0x4E10, 0xD8A4, 0x4E11, 0xB3F3, 0x4E12, 0x8145, 0x4E13, 0xD7A8, 0x4E14, 0xC7D2, 0x4E15, 0xD8A7, 0x4E16, 0xCAC0, 0x4E17, 0x8146, 0x4E18, 0xC7F0, 0x4E19, 0xB1FB, 0x4E1A, 0xD2B5, 0x4E1B, 0xB4D4, 0x4E1C, 0xB6AB, 0x4E1D, 0xCBBF, 0x4E1E, 0xD8A9, 0x4E1F, 0x8147, 0x4E20, 0x8148, 0x4E21, 0x8149, 0x4E22, 0xB6AA, 0x4E23, 0x814A, 0x4E24, 0xC1BD, 0x4E25, 0xD1CF, 0x4E26, 0x814B, 0x4E27, 0xC9A5, 0x4E28, 0xD8AD, 0x4E29, 0x814C, 0x4E2A, 0xB8F6, 0x4E2B, 0xD1BE, 0x4E2C, 0xE3DC, 0x4E2D, 0xD6D0, 0x4E2E, 0x814D, 0x4E2F, 0x814E, 0x4E30, 0xB7E1, 0x4E31, 0x814F, 0x4E32, 0xB4AE, 0x4E33, 0x8150, 0x4E34, 0xC1D9, 0x4E35, 0x8151, 0x4E36, 0xD8BC, 0x4E37, 0x8152, 0x4E38, 0xCDE8, 0x4E39, 0xB5A4, 0x4E3A, 0xCEAA, 0x4E3B, 0xD6F7, 0x4E3C, 0x8153, 0x4E3D, 0xC0F6, 0x4E3E, 0xBED9, 0x4E3F, 0xD8AF, 0x4E40, 0x8154, 0x4E41, 0x8155, 0x4E42, 0x8156, 0x4E43, 0xC4CB, 0x4E44, 0x8157, 0x4E45, 0xBEC3, 0x4E46, 0x8158, 0x4E47, 0xD8B1, 0x4E48, 0xC3B4, 0x4E49, 0xD2E5, 0x4E4A, 0x8159, 0x4E4B, 0xD6AE, 0x4E4C, 0xCEDA, 0x4E4D, 0xD5A7, 0x4E4E, 0xBAF5, 0x4E4F, 0xB7A6, 0x4E50, 0xC0D6, 0x4E51, 0x815A, 0x4E52, 0xC6B9, 0x4E53, 0xC5D2, 0x4E54, 0xC7C7, 0x4E55, 0x815B, 0x4E56, 0xB9D4, 0x4E57, 0x815C, 0x4E58, 0xB3CB, 0x4E59, 0xD2D2, 0x4E5A, 0x815D, 0x4E5B, 0x815E, 0x4E5C, 0xD8BF, 0x4E5D, 0xBEC5, 0x4E5E, 0xC6F2, 0x4E5F, 0xD2B2, 0x4E60, 0xCFB0, 0x4E61, 0xCFE7, 0x4E62, 0x815F, 0x4E63, 0x8160, 0x4E64, 0x8161, 0x4E65, 0x8162, 0x4E66, 0xCAE9, 0x4E67, 0x8163, 0x4E68, 0x8164, 0x4E69, 0xD8C0, 0x4E6A, 0x8165, 0x4E6B, 0x8166, 0x4E6C, 0x8167, 0x4E6D, 0x8168, 0x4E6E, 0x8169, 0x4E6F, 0x816A, 0x4E70, 0xC2F2, 0x4E71, 0xC2D2, 0x4E72, 0x816B, 0x4E73, 0xC8E9, 0x4E74, 0x816C, 0x4E75, 0x816D, 0x4E76, 0x816E, 0x4E77, 0x816F, 0x4E78, 0x8170, 0x4E79, 0x8171, 0x4E7A, 0x8172, 0x4E7B, 0x8173, 0x4E7C, 0x8174, 0x4E7D, 0x8175, 0x4E7E, 0xC7AC, 0x4E7F, 0x8176, 0x4E80, 0x8177, 0x4E81, 0x8178, 0x4E82, 0x8179, 0x4E83, 0x817A, 0x4E84, 0x817B, 0x4E85, 0x817C, 0x4E86, 0xC1CB, 0x4E87, 0x817D, 0x4E88, 0xD3E8, 0x4E89, 0xD5F9, 0x4E8A, 0x817E, 0x4E8B, 0xCAC2, 0x4E8C, 0xB6FE, 0x4E8D, 0xD8A1, 0x4E8E, 0xD3DA, 0x4E8F, 0xBFF7, 0x4E90, 0x8180, 0x4E91, 0xD4C6, 0x4E92, 0xBBA5, 0x4E93, 0xD8C1, 0x4E94, 0xCEE5, 0x4E95, 0xBEAE, 0x4E96, 0x8181, 0x4E97, 0x8182, 0x4E98, 0xD8A8, 0x4E99, 0x8183, 0x4E9A, 0xD1C7, 0x4E9B, 0xD0A9, 0x4E9C, 0x8184, 0x4E9D, 0x8185, 0x4E9E, 0x8186, 0x4E9F, 0xD8BD, 0x4EA0, 0xD9EF, 0x4EA1, 0xCDF6, 0x4EA2, 0xBFBA, 0x4EA3, 0x8187, 0x4EA4, 0xBDBB, 0x4EA5, 0xBAA5, 0x4EA6, 0xD2E0, 0x4EA7, 0xB2FA, 0x4EA8, 0xBAE0, 0x4EA9, 0xC4B6, 0x4EAA, 0x8188, 0x4EAB, 0xCFED, 0x4EAC, 0xBEA9, 0x4EAD, 0xCDA4, 0x4EAE, 0xC1C1, 0x4EAF, 0x8189, 0x4EB0, 0x818A, 0x4EB1, 0x818B, 0x4EB2, 0xC7D7, 0x4EB3, 0xD9F1, 0x4EB4, 0x818C, 0x4EB5, 0xD9F4, 0x4EB6, 0x818D, 0x4EB7, 0x818E, 0x4EB8, 0x818F, 0x4EB9, 0x8190, 0x4EBA, 0xC8CB, 0x4EBB, 0xD8E9, 0x4EBC, 0x8191, 0x4EBD, 0x8192, 0x4EBE, 0x8193, 0x4EBF, 0xD2DA, 0x4EC0, 0xCAB2, 0x4EC1, 0xC8CA, 0x4EC2, 0xD8EC, 0x4EC3, 0xD8EA, 0x4EC4, 0xD8C6, 0x4EC5, 0xBDF6, 0x4EC6, 0xC6CD, 0x4EC7, 0xB3F0, 0x4EC8, 0x8194, 0x4EC9, 0xD8EB, 0x4ECA, 0xBDF1, 0x4ECB, 0xBDE9, 0x4ECC, 0x8195, 0x4ECD, 0xC8D4, 0x4ECE, 0xB4D3, 0x4ECF, 0x8196, 0x4ED0, 0x8197, 0x4ED1, 0xC2D8, 0x4ED2, 0x8198, 0x4ED3, 0xB2D6, 0x4ED4, 0xD7D0, 0x4ED5, 0xCACB, 0x4ED6, 0xCBFB, 0x4ED7, 0xD5CC, 0x4ED8, 0xB8B6, 0x4ED9, 0xCFC9, 0x4EDA, 0x8199, 0x4EDB, 0x819A, 0x4EDC, 0x819B, 0x4EDD, 0xD9DA, 0x4EDE, 0xD8F0, 0x4EDF, 0xC7AA, 0x4EE0, 0x819C, 0x4EE1, 0xD8EE, 0x4EE2, 0x819D, 0x4EE3, 0xB4FA, 0x4EE4, 0xC1EE, 0x4EE5, 0xD2D4, 0x4EE6, 0x819E, 0x4EE7, 0x819F, 0x4EE8, 0xD8ED, 0x4EE9, 0x81A0, 0x4EEA, 0xD2C7, 0x4EEB, 0xD8EF, 0x4EEC, 0xC3C7, 0x4EED, 0x81A1, 0x4EEE, 0x81A2, 0x4EEF, 0x81A3, 0x4EF0, 0xD1F6, 0x4EF1, 0x81A4, 0x4EF2, 0xD6D9, 0x4EF3, 0xD8F2, 0x4EF4, 0x81A5, 0x4EF5, 0xD8F5, 0x4EF6, 0xBCFE, 0x4EF7, 0xBCDB, 0x4EF8, 0x81A6, 0x4EF9, 0x81A7, 0x4EFA, 0x81A8, 0x4EFB, 0xC8CE, 0x4EFC, 0x81A9, 0x4EFD, 0xB7DD, 0x4EFE, 0x81AA, 0x4EFF, 0xB7C2, 0x4F00, 0x81AB, 0x4F01, 0xC6F3, 0x4F02, 0x81AC, 0x4F03, 0x81AD, 0x4F04, 0x81AE, 0x4F05, 0x81AF, 0x4F06, 0x81B0, 0x4F07, 0x81B1, 0x4F08, 0x81B2, 0x4F09, 0xD8F8, 0x4F0A, 0xD2C1, 0x4F0B, 0x81B3, 0x4F0C, 0x81B4, 0x4F0D, 0xCEE9, 0x4F0E, 0xBCBF, 0x4F0F, 0xB7FC, 0x4F10, 0xB7A5, 0x4F11, 0xD0DD, 0x4F12, 0x81B5, 0x4F13, 0x81B6, 0x4F14, 0x81B7, 0x4F15, 0x81B8, 0x4F16, 0x81B9, 0x4F17, 0xD6DA, 0x4F18, 0xD3C5, 0x4F19, 0xBBEF, 0x4F1A, 0xBBE1, 0x4F1B, 0xD8F1, 0x4F1C, 0x81BA, 0x4F1D, 0x81BB, 0x4F1E, 0xC9A1, 0x4F1F, 0xCEB0, 0x4F20, 0xB4AB, 0x4F21, 0x81BC, 0x4F22, 0xD8F3, 0x4F23, 0x81BD, 0x4F24, 0xC9CB, 0x4F25, 0xD8F6, 0x4F26, 0xC2D7, 0x4F27, 0xD8F7, 0x4F28, 0x81BE, 0x4F29, 0x81BF, 0x4F2A, 0xCEB1, 0x4F2B, 0xD8F9, 0x4F2C, 0x81C0, 0x4F2D, 0x81C1, 0x4F2E, 0x81C2, 0x4F2F, 0xB2AE, 0x4F30, 0xB9C0, 0x4F31, 0x81C3, 0x4F32, 0xD9A3, 0x4F33, 0x81C4, 0x4F34, 0xB0E9, 0x4F35, 0x81C5, 0x4F36, 0xC1E6, 0x4F37, 0x81C6, 0x4F38, 0xC9EC, 0x4F39, 0x81C7, 0x4F3A, 0xCBC5, 0x4F3B, 0x81C8, 0x4F3C, 0xCBC6, 0x4F3D, 0xD9A4, 0x4F3E, 0x81C9, 0x4F3F, 0x81CA, 0x4F40, 0x81CB, 0x4F41, 0x81CC, 0x4F42, 0x81CD, 0x4F43, 0xB5E8, 0x4F44, 0x81CE, 0x4F45, 0x81CF, 0x4F46, 0xB5AB, 0x4F47, 0x81D0, 0x4F48, 0x81D1, 0x4F49, 0x81D2, 0x4F4A, 0x81D3, 0x4F4B, 0x81D4, 0x4F4C, 0x81D5, 0x4F4D, 0xCEBB, 0x4F4E, 0xB5CD, 0x4F4F, 0xD7A1, 0x4F50, 0xD7F4, 0x4F51, 0xD3D3, 0x4F52, 0x81D6, 0x4F53, 0xCCE5, 0x4F54, 0x81D7, 0x4F55, 0xBACE, 0x4F56, 0x81D8, 0x4F57, 0xD9A2, 0x4F58, 0xD9DC, 0x4F59, 0xD3E0, 0x4F5A, 0xD8FD, 0x4F5B, 0xB7F0, 0x4F5C, 0xD7F7, 0x4F5D, 0xD8FE, 0x4F5E, 0xD8FA, 0x4F5F, 0xD9A1, 0x4F60, 0xC4E3, 0x4F61, 0x81D9, 0x4F62, 0x81DA, 0x4F63, 0xD3B6, 0x4F64, 0xD8F4, 0x4F65, 0xD9DD, 0x4F66, 0x81DB, 0x4F67, 0xD8FB, 0x4F68, 0x81DC, 0x4F69, 0xC5E5, 0x4F6A, 0x81DD, 0x4F6B, 0x81DE, 0x4F6C, 0xC0D0, 0x4F6D, 0x81DF, 0x4F6E, 0x81E0, 0x4F6F, 0xD1F0, 0x4F70, 0xB0DB, 0x4F71, 0x81E1, 0x4F72, 0x81E2, 0x4F73, 0xBCD1, 0x4F74, 0xD9A6, 0x4F75, 0x81E3, 0x4F76, 0xD9A5, 0x4F77, 0x81E4, 0x4F78, 0x81E5, 0x4F79, 0x81E6, 0x4F7A, 0x81E7, 0x4F7B, 0xD9AC, 0x4F7C, 0xD9AE, 0x4F7D, 0x81E8, 0x4F7E, 0xD9AB, 0x4F7F, 0xCAB9, 0x4F80, 0x81E9, 0x4F81, 0x81EA, 0x4F82, 0x81EB, 0x4F83, 0xD9A9, 0x4F84, 0xD6B6, 0x4F85, 0x81EC, 0x4F86, 0x81ED, 0x4F87, 0x81EE, 0x4F88, 0xB3DE, 0x4F89, 0xD9A8, 0x4F8A, 0x81EF, 0x4F8B, 0xC0FD, 0x4F8C, 0x81F0, 0x4F8D, 0xCACC, 0x4F8E, 0x81F1, 0x4F8F, 0xD9AA, 0x4F90, 0x81F2, 0x4F91, 0xD9A7, 0x4F92, 0x81F3, 0x4F93, 0x81F4, 0x4F94, 0xD9B0, 0x4F95, 0x81F5, 0x4F96, 0x81F6, 0x4F97, 0xB6B1, 0x4F98, 0x81F7, 0x4F99, 0x81F8, 0x4F9A, 0x81F9, 0x4F9B, 0xB9A9, 0x4F9C, 0x81FA, 0x4F9D, 0xD2C0, 0x4F9E, 0x81FB, 0x4F9F, 0x81FC, 0x4FA0, 0xCFC0, 0x4FA1, 0x81FD, 0x4FA2, 0x81FE, 0x4FA3, 0xC2C2, 0x4FA4, 0x8240, 0x4FA5, 0xBDC4, 0x4FA6, 0xD5EC, 0x4FA7, 0xB2E0, 0x4FA8, 0xC7C8, 0x4FA9, 0xBFEB, 0x4FAA, 0xD9AD, 0x4FAB, 0x8241, 0x4FAC, 0xD9AF, 0x4FAD, 0x8242, 0x4FAE, 0xCEEA, 0x4FAF, 0xBAEE, 0x4FB0, 0x8243, 0x4FB1, 0x8244, 0x4FB2, 0x8245, 0x4FB3, 0x8246, 0x4FB4, 0x8247, 0x4FB5, 0xC7D6, 0x4FB6, 0x8248, 0x4FB7, 0x8249, 0x4FB8, 0x824A, 0x4FB9, 0x824B, 0x4FBA, 0x824C, 0x4FBB, 0x824D, 0x4FBC, 0x824E, 0x4FBD, 0x824F, 0x4FBE, 0x8250, 0x4FBF, 0xB1E3, 0x4FC0, 0x8251, 0x4FC1, 0x8252, 0x4FC2, 0x8253, 0x4FC3, 0xB4D9, 0x4FC4, 0xB6ED, 0x4FC5, 0xD9B4, 0x4FC6, 0x8254, 0x4FC7, 0x8255, 0x4FC8, 0x8256, 0x4FC9, 0x8257, 0x4FCA, 0xBFA1, 0x4FCB, 0x8258, 0x4FCC, 0x8259, 0x4FCD, 0x825A, 0x4FCE, 0xD9DE, 0x4FCF, 0xC7CE, 0x4FD0, 0xC0FE, 0x4FD1, 0xD9B8, 0x4FD2, 0x825B, 0x4FD3, 0x825C, 0x4FD4, 0x825D, 0x4FD5, 0x825E, 0x4FD6, 0x825F, 0x4FD7, 0xCBD7, 0x4FD8, 0xB7FD, 0x4FD9, 0x8260, 0x4FDA, 0xD9B5, 0x4FDB, 0x8261, 0x4FDC, 0xD9B7, 0x4FDD, 0xB1A3, 0x4FDE, 0xD3E1, 0x4FDF, 0xD9B9, 0x4FE0, 0x8262, 0x4FE1, 0xD0C5, 0x4FE2, 0x8263, 0x4FE3, 0xD9B6, 0x4FE4, 0x8264, 0x4FE5, 0x8265, 0x4FE6, 0xD9B1, 0x4FE7, 0x8266, 0x4FE8, 0xD9B2, 0x4FE9, 0xC1A9, 0x4FEA, 0xD9B3, 0x4FEB, 0x8267, 0x4FEC, 0x8268, 0x4FED, 0xBCF3, 0x4FEE, 0xD0DE, 0x4FEF, 0xB8A9, 0x4FF0, 0x8269, 0x4FF1, 0xBEE3, 0x4FF2, 0x826A, 0x4FF3, 0xD9BD, 0x4FF4, 0x826B, 0x4FF5, 0x826C, 0x4FF6, 0x826D, 0x4FF7, 0x826E, 0x4FF8, 0xD9BA, 0x4FF9, 0x826F, 0x4FFA, 0xB0B3, 0x4FFB, 0x8270, 0x4FFC, 0x8271, 0x4FFD, 0x8272, 0x4FFE, 0xD9C2, 0x4FFF, 0x8273, 0x5000, 0x8274, 0x5001, 0x8275, 0x5002, 0x8276, 0x5003, 0x8277, 0x5004, 0x8278, 0x5005, 0x8279, 0x5006, 0x827A, 0x5007, 0x827B, 0x5008, 0x827C, 0x5009, 0x827D, 0x500A, 0x827E, 0x500B, 0x8280, 0x500C, 0xD9C4, 0x500D, 0xB1B6, 0x500E, 0x8281, 0x500F, 0xD9BF, 0x5010, 0x8282, 0x5011, 0x8283, 0x5012, 0xB5B9, 0x5013, 0x8284, 0x5014, 0xBEF3, 0x5015, 0x8285, 0x5016, 0x8286, 0x5017, 0x8287, 0x5018, 0xCCC8, 0x5019, 0xBAF2, 0x501A, 0xD2D0, 0x501B, 0x8288, 0x501C, 0xD9C3, 0x501D, 0x8289, 0x501E, 0x828A, 0x501F, 0xBDE8, 0x5020, 0x828B, 0x5021, 0xB3AB, 0x5022, 0x828C, 0x5023, 0x828D, 0x5024, 0x828E, 0x5025, 0xD9C5, 0x5026, 0xBEEB, 0x5027, 0x828F, 0x5028, 0xD9C6, 0x5029, 0xD9BB, 0x502A, 0xC4DF, 0x502B, 0x8290, 0x502C, 0xD9BE, 0x502D, 0xD9C1, 0x502E, 0xD9C0, 0x502F, 0x8291, 0x5030, 0x8292, 0x5031, 0x8293, 0x5032, 0x8294, 0x5033, 0x8295, 0x5034, 0x8296, 0x5035, 0x8297, 0x5036, 0x8298, 0x5037, 0x8299, 0x5038, 0x829A, 0x5039, 0x829B, 0x503A, 0xD5AE, 0x503B, 0x829C, 0x503C, 0xD6B5, 0x503D, 0x829D, 0x503E, 0xC7E3, 0x503F, 0x829E, 0x5040, 0x829F, 0x5041, 0x82A0, 0x5042, 0x82A1, 0x5043, 0xD9C8, 0x5044, 0x82A2, 0x5045, 0x82A3, 0x5046, 0x82A4, 0x5047, 0xBCD9, 0x5048, 0xD9CA, 0x5049, 0x82A5, 0x504A, 0x82A6, 0x504B, 0x82A7, 0x504C, 0xD9BC, 0x504D, 0x82A8, 0x504E, 0xD9CB, 0x504F, 0xC6AB, 0x5050, 0x82A9, 0x5051, 0x82AA, 0x5052, 0x82AB, 0x5053, 0x82AC, 0x5054, 0x82AD, 0x5055, 0xD9C9, 0x5056, 0x82AE, 0x5057, 0x82AF, 0x5058, 0x82B0, 0x5059, 0x82B1, 0x505A, 0xD7F6, 0x505B, 0x82B2, 0x505C, 0xCDA3, 0x505D, 0x82B3, 0x505E, 0x82B4, 0x505F, 0x82B5, 0x5060, 0x82B6, 0x5061, 0x82B7, 0x5062, 0x82B8, 0x5063, 0x82B9, 0x5064, 0x82BA, 0x5065, 0xBDA1, 0x5066, 0x82BB, 0x5067, 0x82BC, 0x5068, 0x82BD, 0x5069, 0x82BE, 0x506A, 0x82BF, 0x506B, 0x82C0, 0x506C, 0xD9CC, 0x506D, 0x82C1, 0x506E, 0x82C2, 0x506F, 0x82C3, 0x5070, 0x82C4, 0x5071, 0x82C5, 0x5072, 0x82C6, 0x5073, 0x82C7, 0x5074, 0x82C8, 0x5075, 0x82C9, 0x5076, 0xC5BC, 0x5077, 0xCDB5, 0x5078, 0x82CA, 0x5079, 0x82CB, 0x507A, 0x82CC, 0x507B, 0xD9CD, 0x507C, 0x82CD, 0x507D, 0x82CE, 0x507E, 0xD9C7, 0x507F, 0xB3A5, 0x5080, 0xBFFE, 0x5081, 0x82CF, 0x5082, 0x82D0, 0x5083, 0x82D1, 0x5084, 0x82D2, 0x5085, 0xB8B5, 0x5086, 0x82D3, 0x5087, 0x82D4, 0x5088, 0xC0FC, 0x5089, 0x82D5, 0x508A, 0x82D6, 0x508B, 0x82D7, 0x508C, 0x82D8, 0x508D, 0xB0F8, 0x508E, 0x82D9, 0x508F, 0x82DA, 0x5090, 0x82DB, 0x5091, 0x82DC, 0x5092, 0x82DD, 0x5093, 0x82DE, 0x5094, 0x82DF, 0x5095, 0x82E0, 0x5096, 0x82E1, 0x5097, 0x82E2, 0x5098, 0x82E3, 0x5099, 0x82E4, 0x509A, 0x82E5, 0x509B, 0x82E6, 0x509C, 0x82E7, 0x509D, 0x82E8, 0x509E, 0x82E9, 0x509F, 0x82EA, 0x50A0, 0x82EB, 0x50A1, 0x82EC, 0x50A2, 0x82ED, 0x50A3, 0xB4F6, 0x50A4, 0x82EE, 0x50A5, 0xD9CE, 0x50A6, 0x82EF, 0x50A7, 0xD9CF, 0x50A8, 0xB4A2, 0x50A9, 0xD9D0, 0x50AA, 0x82F0, 0x50AB, 0x82F1, 0x50AC, 0xB4DF, 0x50AD, 0x82F2, 0x50AE, 0x82F3, 0x50AF, 0x82F4, 0x50B0, 0x82F5, 0x50B1, 0x82F6, 0x50B2, 0xB0C1, 0x50B3, 0x82F7, 0x50B4, 0x82F8, 0x50B5, 0x82F9, 0x50B6, 0x82FA, 0x50B7, 0x82FB, 0x50B8, 0x82FC, 0x50B9, 0x82FD, 0x50BA, 0xD9D1, 0x50BB, 0xC9B5, 0x50BC, 0x82FE, 0x50BD, 0x8340, 0x50BE, 0x8341, 0x50BF, 0x8342, 0x50C0, 0x8343, 0x50C1, 0x8344, 0x50C2, 0x8345, 0x50C3, 0x8346, 0x50C4, 0x8347, 0x50C5, 0x8348, 0x50C6, 0x8349, 0x50C7, 0x834A, 0x50C8, 0x834B, 0x50C9, 0x834C, 0x50CA, 0x834D, 0x50CB, 0x834E, 0x50CC, 0x834F, 0x50CD, 0x8350, 0x50CE, 0x8351, 0x50CF, 0xCFF1, 0x50D0, 0x8352, 0x50D1, 0x8353, 0x50D2, 0x8354, 0x50D3, 0x8355, 0x50D4, 0x8356, 0x50D5, 0x8357, 0x50D6, 0xD9D2, 0x50D7, 0x8358, 0x50D8, 0x8359, 0x50D9, 0x835A, 0x50DA, 0xC1C5, 0x50DB, 0x835B, 0x50DC, 0x835C, 0x50DD, 0x835D, 0x50DE, 0x835E, 0x50DF, 0x835F, 0x50E0, 0x8360, 0x50E1, 0x8361, 0x50E2, 0x8362, 0x50E3, 0x8363, 0x50E4, 0x8364, 0x50E5, 0x8365, 0x50E6, 0xD9D6, 0x50E7, 0xC9AE, 0x50E8, 0x8366, 0x50E9, 0x8367, 0x50EA, 0x8368, 0x50EB, 0x8369, 0x50EC, 0xD9D5, 0x50ED, 0xD9D4, 0x50EE, 0xD9D7, 0x50EF, 0x836A, 0x50F0, 0x836B, 0x50F1, 0x836C, 0x50F2, 0x836D, 0x50F3, 0xCBDB, 0x50F4, 0x836E, 0x50F5, 0xBDA9, 0x50F6, 0x836F, 0x50F7, 0x8370, 0x50F8, 0x8371, 0x50F9, 0x8372, 0x50FA, 0x8373, 0x50FB, 0xC6A7, 0x50FC, 0x8374, 0x50FD, 0x8375, 0x50FE, 0x8376, 0x50FF, 0x8377, 0x5100, 0x8378, 0x5101, 0x8379, 0x5102, 0x837A, 0x5103, 0x837B, 0x5104, 0x837C, 0x5105, 0x837D, 0x5106, 0xD9D3, 0x5107, 0xD9D8, 0x5108, 0x837E, 0x5109, 0x8380, 0x510A, 0x8381, 0x510B, 0xD9D9, 0x510C, 0x8382, 0x510D, 0x8383, 0x510E, 0x8384, 0x510F, 0x8385, 0x5110, 0x8386, 0x5111, 0x8387, 0x5112, 0xC8E5, 0x5113, 0x8388, 0x5114, 0x8389, 0x5115, 0x838A, 0x5116, 0x838B, 0x5117, 0x838C, 0x5118, 0x838D, 0x5119, 0x838E, 0x511A, 0x838F, 0x511B, 0x8390, 0x511C, 0x8391, 0x511D, 0x8392, 0x511E, 0x8393, 0x511F, 0x8394, 0x5120, 0x8395, 0x5121, 0xC0DC, 0x5122, 0x8396, 0x5123, 0x8397, 0x5124, 0x8398, 0x5125, 0x8399, 0x5126, 0x839A, 0x5127, 0x839B, 0x5128, 0x839C, 0x5129, 0x839D, 0x512A, 0x839E, 0x512B, 0x839F, 0x512C, 0x83A0, 0x512D, 0x83A1, 0x512E, 0x83A2, 0x512F, 0x83A3, 0x5130, 0x83A4, 0x5131, 0x83A5, 0x5132, 0x83A6, 0x5133, 0x83A7, 0x5134, 0x83A8, 0x5135, 0x83A9, 0x5136, 0x83AA, 0x5137, 0x83AB, 0x5138, 0x83AC, 0x5139, 0x83AD, 0x513A, 0x83AE, 0x513B, 0x83AF, 0x513C, 0x83B0, 0x513D, 0x83B1, 0x513E, 0x83B2, 0x513F, 0xB6F9, 0x5140, 0xD8A3, 0x5141, 0xD4CA, 0x5142, 0x83B3, 0x5143, 0xD4AA, 0x5144, 0xD0D6, 0x5145, 0xB3E4, 0x5146, 0xD5D7, 0x5147, 0x83B4, 0x5148, 0xCFC8, 0x5149, 0xB9E2, 0x514A, 0x83B5, 0x514B, 0xBFCB, 0x514C, 0x83B6, 0x514D, 0xC3E2, 0x514E, 0x83B7, 0x514F, 0x83B8, 0x5150, 0x83B9, 0x5151, 0xB6D2, 0x5152, 0x83BA, 0x5153, 0x83BB, 0x5154, 0xCDC3, 0x5155, 0xD9EE, 0x5156, 0xD9F0, 0x5157, 0x83BC, 0x5158, 0x83BD, 0x5159, 0x83BE, 0x515A, 0xB5B3, 0x515B, 0x83BF, 0x515C, 0xB6B5, 0x515D, 0x83C0, 0x515E, 0x83C1, 0x515F, 0x83C2, 0x5160, 0x83C3, 0x5161, 0x83C4, 0x5162, 0xBEA4, 0x5163, 0x83C5, 0x5164, 0x83C6, 0x5165, 0xC8EB, 0x5166, 0x83C7, 0x5167, 0x83C8, 0x5168, 0xC8AB, 0x5169, 0x83C9, 0x516A, 0x83CA, 0x516B, 0xB0CB, 0x516C, 0xB9AB, 0x516D, 0xC1F9, 0x516E, 0xD9E2, 0x516F, 0x83CB, 0x5170, 0xC0BC, 0x5171, 0xB9B2, 0x5172, 0x83CC, 0x5173, 0xB9D8, 0x5174, 0xD0CB, 0x5175, 0xB1F8, 0x5176, 0xC6E4, 0x5177, 0xBEDF, 0x5178, 0xB5E4, 0x5179, 0xD7C8, 0x517A, 0x83CD, 0x517B, 0xD1F8, 0x517C, 0xBCE6, 0x517D, 0xCADE, 0x517E, 0x83CE, 0x517F, 0x83CF, 0x5180, 0xBCBD, 0x5181, 0xD9E6, 0x5182, 0xD8E7, 0x5183, 0x83D0, 0x5184, 0x83D1, 0x5185, 0xC4DA, 0x5186, 0x83D2, 0x5187, 0x83D3, 0x5188, 0xB8D4, 0x5189, 0xC8BD, 0x518A, 0x83D4, 0x518B, 0x83D5, 0x518C, 0xB2E1, 0x518D, 0xD4D9, 0x518E, 0x83D6, 0x518F, 0x83D7, 0x5190, 0x83D8, 0x5191, 0x83D9, 0x5192, 0xC3B0, 0x5193, 0x83DA, 0x5194, 0x83DB, 0x5195, 0xC3E1, 0x5196, 0xDAA2, 0x5197, 0xC8DF, 0x5198, 0x83DC, 0x5199, 0xD0B4, 0x519A, 0x83DD, 0x519B, 0xBEFC, 0x519C, 0xC5A9, 0x519D, 0x83DE, 0x519E, 0x83DF, 0x519F, 0x83E0, 0x51A0, 0xB9DA, 0x51A1, 0x83E1, 0x51A2, 0xDAA3, 0x51A3, 0x83E2, 0x51A4, 0xD4A9, 0x51A5, 0xDAA4, 0x51A6, 0x83E3, 0x51A7, 0x83E4, 0x51A8, 0x83E5, 0x51A9, 0x83E6, 0x51AA, 0x83E7, 0x51AB, 0xD9FB, 0x51AC, 0xB6AC, 0x51AD, 0x83E8, 0x51AE, 0x83E9, 0x51AF, 0xB7EB, 0x51B0, 0xB1F9, 0x51B1, 0xD9FC, 0x51B2, 0xB3E5, 0x51B3, 0xBEF6, 0x51B4, 0x83EA, 0x51B5, 0xBFF6, 0x51B6, 0xD2B1, 0x51B7, 0xC0E4, 0x51B8, 0x83EB, 0x51B9, 0x83EC, 0x51BA, 0x83ED, 0x51BB, 0xB6B3, 0x51BC, 0xD9FE, 0x51BD, 0xD9FD, 0x51BE, 0x83EE, 0x51BF, 0x83EF, 0x51C0, 0xBEBB, 0x51C1, 0x83F0, 0x51C2, 0x83F1, 0x51C3, 0x83F2, 0x51C4, 0xC6E0, 0x51C5, 0x83F3, 0x51C6, 0xD7BC, 0x51C7, 0xDAA1, 0x51C8, 0x83F4, 0x51C9, 0xC1B9, 0x51CA, 0x83F5, 0x51CB, 0xB5F2, 0x51CC, 0xC1E8, 0x51CD, 0x83F6, 0x51CE, 0x83F7, 0x51CF, 0xBCF5, 0x51D0, 0x83F8, 0x51D1, 0xB4D5, 0x51D2, 0x83F9, 0x51D3, 0x83FA, 0x51D4, 0x83FB, 0x51D5, 0x83FC, 0x51D6, 0x83FD, 0x51D7, 0x83FE, 0x51D8, 0x8440, 0x51D9, 0x8441, 0x51DA, 0x8442, 0x51DB, 0xC1DD, 0x51DC, 0x8443, 0x51DD, 0xC4FD, 0x51DE, 0x8444, 0x51DF, 0x8445, 0x51E0, 0xBCB8, 0x51E1, 0xB7B2, 0x51E2, 0x8446, 0x51E3, 0x8447, 0x51E4, 0xB7EF, 0x51E5, 0x8448, 0x51E6, 0x8449, 0x51E7, 0x844A, 0x51E8, 0x844B, 0x51E9, 0x844C, 0x51EA, 0x844D, 0x51EB, 0xD9EC, 0x51EC, 0x844E, 0x51ED, 0xC6BE, 0x51EE, 0x844F, 0x51EF, 0xBFAD, 0x51F0, 0xBBCB, 0x51F1, 0x8450, 0x51F2, 0x8451, 0x51F3, 0xB5CA, 0x51F4, 0x8452, 0x51F5, 0xDBC9, 0x51F6, 0xD0D7, 0x51F7, 0x8453, 0x51F8, 0xCDB9, 0x51F9, 0xB0BC, 0x51FA, 0xB3F6, 0x51FB, 0xBBF7, 0x51FC, 0xDBCA, 0x51FD, 0xBAAF, 0x51FE, 0x8454, 0x51FF, 0xD4E4, 0x5200, 0xB5B6, 0x5201, 0xB5F3, 0x5202, 0xD8D6, 0x5203, 0xC8D0, 0x5204, 0x8455, 0x5205, 0x8456, 0x5206, 0xB7D6, 0x5207, 0xC7D0, 0x5208, 0xD8D7, 0x5209, 0x8457, 0x520A, 0xBFAF, 0x520B, 0x8458, 0x520C, 0x8459, 0x520D, 0xDBBB, 0x520E, 0xD8D8, 0x520F, 0x845A, 0x5210, 0x845B, 0x5211, 0xD0CC, 0x5212, 0xBBAE, 0x5213, 0x845C, 0x5214, 0x845D, 0x5215, 0x845E, 0x5216, 0xEBBE, 0x5217, 0xC1D0, 0x5218, 0xC1F5, 0x5219, 0xD4F2, 0x521A, 0xB8D5, 0x521B, 0xB4B4, 0x521C, 0x845F, 0x521D, 0xB3F5, 0x521E, 0x8460, 0x521F, 0x8461, 0x5220, 0xC9BE, 0x5221, 0x8462, 0x5222, 0x8463, 0x5223, 0x8464, 0x5224, 0xC5D0, 0x5225, 0x8465, 0x5226, 0x8466, 0x5227, 0x8467, 0x5228, 0xC5D9, 0x5229, 0xC0FB, 0x522A, 0x8468, 0x522B, 0xB1F0, 0x522C, 0x8469, 0x522D, 0xD8D9, 0x522E, 0xB9CE, 0x522F, 0x846A, 0x5230, 0xB5BD, 0x5231, 0x846B, 0x5232, 0x846C, 0x5233, 0xD8DA, 0x5234, 0x846D, 0x5235, 0x846E, 0x5236, 0xD6C6, 0x5237, 0xCBA2, 0x5238, 0xC8AF, 0x5239, 0xC9B2, 0x523A, 0xB4CC, 0x523B, 0xBFCC, 0x523C, 0x846F, 0x523D, 0xB9F4, 0x523E, 0x8470, 0x523F, 0xD8DB, 0x5240, 0xD8DC, 0x5241, 0xB6E7, 0x5242, 0xBCC1, 0x5243, 0xCCEA, 0x5244, 0x8471, 0x5245, 0x8472, 0x5246, 0x8473, 0x5247, 0x8474, 0x5248, 0x8475, 0x5249, 0x8476, 0x524A, 0xCFF7, 0x524B, 0x8477, 0x524C, 0xD8DD, 0x524D, 0xC7B0, 0x524E, 0x8478, 0x524F, 0x8479, 0x5250, 0xB9D0, 0x5251, 0xBDA3, 0x5252, 0x847A, 0x5253, 0x847B, 0x5254, 0xCCDE, 0x5255, 0x847C, 0x5256, 0xC6CA, 0x5257, 0x847D, 0x5258, 0x847E, 0x5259, 0x8480, 0x525A, 0x8481, 0x525B, 0x8482, 0x525C, 0xD8E0, 0x525D, 0x8483, 0x525E, 0xD8DE, 0x525F, 0x8484, 0x5260, 0x8485, 0x5261, 0xD8DF, 0x5262, 0x8486, 0x5263, 0x8487, 0x5264, 0x8488, 0x5265, 0xB0FE, 0x5266, 0x8489, 0x5267, 0xBEE7, 0x5268, 0x848A, 0x5269, 0xCAA3, 0x526A, 0xBCF4, 0x526B, 0x848B, 0x526C, 0x848C, 0x526D, 0x848D, 0x526E, 0x848E, 0x526F, 0xB8B1, 0x5270, 0x848F, 0x5271, 0x8490, 0x5272, 0xB8EE, 0x5273, 0x8491, 0x5274, 0x8492, 0x5275, 0x8493, 0x5276, 0x8494, 0x5277, 0x8495, 0x5278, 0x8496, 0x5279, 0x8497, 0x527A, 0x8498, 0x527B, 0x8499, 0x527C, 0x849A, 0x527D, 0xD8E2, 0x527E, 0x849B, 0x527F, 0xBDCB, 0x5280, 0x849C, 0x5281, 0xD8E4, 0x5282, 0xD8E3, 0x5283, 0x849D, 0x5284, 0x849E, 0x5285, 0x849F, 0x5286, 0x84A0, 0x5287, 0x84A1, 0x5288, 0xC5FC, 0x5289, 0x84A2, 0x528A, 0x84A3, 0x528B, 0x84A4, 0x528C, 0x84A5, 0x528D, 0x84A6, 0x528E, 0x84A7, 0x528F, 0x84A8, 0x5290, 0xD8E5, 0x5291, 0x84A9, 0x5292, 0x84AA, 0x5293, 0xD8E6, 0x5294, 0x84AB, 0x5295, 0x84AC, 0x5296, 0x84AD, 0x5297, 0x84AE, 0x5298, 0x84AF, 0x5299, 0x84B0, 0x529A, 0x84B1, 0x529B, 0xC1A6, 0x529C, 0x84B2, 0x529D, 0xC8B0, 0x529E, 0xB0EC, 0x529F, 0xB9A6, 0x52A0, 0xBCD3, 0x52A1, 0xCEF1, 0x52A2, 0xDBBD, 0x52A3, 0xC1D3, 0x52A4, 0x84B3, 0x52A5, 0x84B4, 0x52A6, 0x84B5, 0x52A7, 0x84B6, 0x52A8, 0xB6AF, 0x52A9, 0xD6FA, 0x52AA, 0xC5AC, 0x52AB, 0xBDD9, 0x52AC, 0xDBBE, 0x52AD, 0xDBBF, 0x52AE, 0x84B7, 0x52AF, 0x84B8, 0x52B0, 0x84B9, 0x52B1, 0xC0F8, 0x52B2, 0xBEA2, 0x52B3, 0xC0CD, 0x52B4, 0x84BA, 0x52B5, 0x84BB, 0x52B6, 0x84BC, 0x52B7, 0x84BD, 0x52B8, 0x84BE, 0x52B9, 0x84BF, 0x52BA, 0x84C0, 0x52BB, 0x84C1, 0x52BC, 0x84C2, 0x52BD, 0x84C3, 0x52BE, 0xDBC0, 0x52BF, 0xCAC6, 0x52C0, 0x84C4, 0x52C1, 0x84C5, 0x52C2, 0x84C6, 0x52C3, 0xB2AA, 0x52C4, 0x84C7, 0x52C5, 0x84C8, 0x52C6, 0x84C9, 0x52C7, 0xD3C2, 0x52C8, 0x84CA, 0x52C9, 0xC3E3, 0x52CA, 0x84CB, 0x52CB, 0xD1AB, 0x52CC, 0x84CC, 0x52CD, 0x84CD, 0x52CE, 0x84CE, 0x52CF, 0x84CF, 0x52D0, 0xDBC2, 0x52D1, 0x84D0, 0x52D2, 0xC0D5, 0x52D3, 0x84D1, 0x52D4, 0x84D2, 0x52D5, 0x84D3, 0x52D6, 0xDBC3, 0x52D7, 0x84D4, 0x52D8, 0xBFB1, 0x52D9, 0x84D5, 0x52DA, 0x84D6, 0x52DB, 0x84D7, 0x52DC, 0x84D8, 0x52DD, 0x84D9, 0x52DE, 0x84DA, 0x52DF, 0xC4BC, 0x52E0, 0x84DB, 0x52E1, 0x84DC, 0x52E2, 0x84DD, 0x52E3, 0x84DE, 0x52E4, 0xC7DA, 0x52E5, 0x84DF, 0x52E6, 0x84E0, 0x52E7, 0x84E1, 0x52E8, 0x84E2, 0x52E9, 0x84E3, 0x52EA, 0x84E4, 0x52EB, 0x84E5, 0x52EC, 0x84E6, 0x52ED, 0x84E7, 0x52EE, 0x84E8, 0x52EF, 0x84E9, 0x52F0, 0xDBC4, 0x52F1, 0x84EA, 0x52F2, 0x84EB, 0x52F3, 0x84EC, 0x52F4, 0x84ED, 0x52F5, 0x84EE, 0x52F6, 0x84EF, 0x52F7, 0x84F0, 0x52F8, 0x84F1, 0x52F9, 0xD9E8, 0x52FA, 0xC9D7, 0x52FB, 0x84F2, 0x52FC, 0x84F3, 0x52FD, 0x84F4, 0x52FE, 0xB9B4, 0x52FF, 0xCEF0, 0x5300, 0xD4C8, 0x5301, 0x84F5, 0x5302, 0x84F6, 0x5303, 0x84F7, 0x5304, 0x84F8, 0x5305, 0xB0FC, 0x5306, 0xB4D2, 0x5307, 0x84F9, 0x5308, 0xD0D9, 0x5309, 0x84FA, 0x530A, 0x84FB, 0x530B, 0x84FC, 0x530C, 0x84FD, 0x530D, 0xD9E9, 0x530E, 0x84FE, 0x530F, 0xDECB, 0x5310, 0xD9EB, 0x5311, 0x8540, 0x5312, 0x8541, 0x5313, 0x8542, 0x5314, 0x8543, 0x5315, 0xD8B0, 0x5316, 0xBBAF, 0x5317, 0xB1B1, 0x5318, 0x8544, 0x5319, 0xB3D7, 0x531A, 0xD8CE, 0x531B, 0x8545, 0x531C, 0x8546, 0x531D, 0xD4D1, 0x531E, 0x8547, 0x531F, 0x8548, 0x5320, 0xBDB3, 0x5321, 0xBFEF, 0x5322, 0x8549, 0x5323, 0xCFBB, 0x5324, 0x854A, 0x5325, 0x854B, 0x5326, 0xD8D0, 0x5327, 0x854C, 0x5328, 0x854D, 0x5329, 0x854E, 0x532A, 0xB7CB, 0x532B, 0x854F, 0x532C, 0x8550, 0x532D, 0x8551, 0x532E, 0xD8D1, 0x532F, 0x8552, 0x5330, 0x8553, 0x5331, 0x8554, 0x5332, 0x8555, 0x5333, 0x8556, 0x5334, 0x8557, 0x5335, 0x8558, 0x5336, 0x8559, 0x5337, 0x855A, 0x5338, 0x855B, 0x5339, 0xC6A5, 0x533A, 0xC7F8, 0x533B, 0xD2BD, 0x533C, 0x855C, 0x533D, 0x855D, 0x533E, 0xD8D2, 0x533F, 0xC4E4, 0x5340, 0x855E, 0x5341, 0xCAAE, 0x5342, 0x855F, 0x5343, 0xC7A7, 0x5344, 0x8560, 0x5345, 0xD8A6, 0x5346, 0x8561, 0x5347, 0xC9FD, 0x5348, 0xCEE7, 0x5349, 0xBBDC, 0x534A, 0xB0EB, 0x534B, 0x8562, 0x534C, 0x8563, 0x534D, 0x8564, 0x534E, 0xBBAA, 0x534F, 0xD0AD, 0x5350, 0x8565, 0x5351, 0xB1B0, 0x5352, 0xD7E4, 0x5353, 0xD7BF, 0x5354, 0x8566, 0x5355, 0xB5A5, 0x5356, 0xC2F4, 0x5357, 0xC4CF, 0x5358, 0x8567, 0x5359, 0x8568, 0x535A, 0xB2A9, 0x535B, 0x8569, 0x535C, 0xB2B7, 0x535D, 0x856A, 0x535E, 0xB1E5, 0x535F, 0xDFB2, 0x5360, 0xD5BC, 0x5361, 0xBFA8, 0x5362, 0xC2AC, 0x5363, 0xD8D5, 0x5364, 0xC2B1, 0x5365, 0x856B, 0x5366, 0xD8D4, 0x5367, 0xCED4, 0x5368, 0x856C, 0x5369, 0xDAE0, 0x536A, 0x856D, 0x536B, 0xCEC0, 0x536C, 0x856E, 0x536D, 0x856F, 0x536E, 0xD8B4, 0x536F, 0xC3AE, 0x5370, 0xD3A1, 0x5371, 0xCEA3, 0x5372, 0x8570, 0x5373, 0xBCB4, 0x5374, 0xC8B4, 0x5375, 0xC2D1, 0x5376, 0x8571, 0x5377, 0xBEED, 0x5378, 0xD0B6, 0x5379, 0x8572, 0x537A, 0xDAE1, 0x537B, 0x8573, 0x537C, 0x8574, 0x537D, 0x8575, 0x537E, 0x8576, 0x537F, 0xC7E4, 0x5380, 0x8577, 0x5381, 0x8578, 0x5382, 0xB3A7, 0x5383, 0x8579, 0x5384, 0xB6F2, 0x5385, 0xCCFC, 0x5386, 0xC0FA, 0x5387, 0x857A, 0x5388, 0x857B, 0x5389, 0xC0F7, 0x538A, 0x857C, 0x538B, 0xD1B9, 0x538C, 0xD1E1, 0x538D, 0xD8C7, 0x538E, 0x857D, 0x538F, 0x857E, 0x5390, 0x8580, 0x5391, 0x8581, 0x5392, 0x8582, 0x5393, 0x8583, 0x5394, 0x8584, 0x5395, 0xB2DE, 0x5396, 0x8585, 0x5397, 0x8586, 0x5398, 0xC0E5, 0x5399, 0x8587, 0x539A, 0xBAF1, 0x539B, 0x8588, 0x539C, 0x8589, 0x539D, 0xD8C8, 0x539E, 0x858A, 0x539F, 0xD4AD, 0x53A0, 0x858B, 0x53A1, 0x858C, 0x53A2, 0xCFE1, 0x53A3, 0xD8C9, 0x53A4, 0x858D, 0x53A5, 0xD8CA, 0x53A6, 0xCFC3, 0x53A7, 0x858E, 0x53A8, 0xB3F8, 0x53A9, 0xBEC7, 0x53AA, 0x858F, 0x53AB, 0x8590, 0x53AC, 0x8591, 0x53AD, 0x8592, 0x53AE, 0xD8CB, 0x53AF, 0x8593, 0x53B0, 0x8594, 0x53B1, 0x8595, 0x53B2, 0x8596, 0x53B3, 0x8597, 0x53B4, 0x8598, 0x53B5, 0x8599, 0x53B6, 0xDBCC, 0x53B7, 0x859A, 0x53B8, 0x859B, 0x53B9, 0x859C, 0x53BA, 0x859D, 0x53BB, 0xC8A5, 0x53BC, 0x859E, 0x53BD, 0x859F, 0x53BE, 0x85A0, 0x53BF, 0xCFD8, 0x53C0, 0x85A1, 0x53C1, 0xC8FE, 0x53C2, 0xB2CE, 0x53C3, 0x85A2, 0x53C4, 0x85A3, 0x53C5, 0x85A4, 0x53C6, 0x85A5, 0x53C7, 0x85A6, 0x53C8, 0xD3D6, 0x53C9, 0xB2E6, 0x53CA, 0xBCB0, 0x53CB, 0xD3D1, 0x53CC, 0xCBAB, 0x53CD, 0xB7B4, 0x53CE, 0x85A7, 0x53CF, 0x85A8, 0x53D0, 0x85A9, 0x53D1, 0xB7A2, 0x53D2, 0x85AA, 0x53D3, 0x85AB, 0x53D4, 0xCAE5, 0x53D5, 0x85AC, 0x53D6, 0xC8A1, 0x53D7, 0xCADC, 0x53D8, 0xB1E4, 0x53D9, 0xD0F0, 0x53DA, 0x85AD, 0x53DB, 0xC5D1, 0x53DC, 0x85AE, 0x53DD, 0x85AF, 0x53DE, 0x85B0, 0x53DF, 0xDBC5, 0x53E0, 0xB5FE, 0x53E1, 0x85B1, 0x53E2, 0x85B2, 0x53E3, 0xBFDA, 0x53E4, 0xB9C5, 0x53E5, 0xBEE4, 0x53E6, 0xC1ED, 0x53E7, 0x85B3, 0x53E8, 0xDFB6, 0x53E9, 0xDFB5, 0x53EA, 0xD6BB, 0x53EB, 0xBDD0, 0x53EC, 0xD5D9, 0x53ED, 0xB0C8, 0x53EE, 0xB6A3, 0x53EF, 0xBFC9, 0x53F0, 0xCCA8, 0x53F1, 0xDFB3, 0x53F2, 0xCAB7, 0x53F3, 0xD3D2, 0x53F4, 0x85B4, 0x53F5, 0xD8CF, 0x53F6, 0xD2B6, 0x53F7, 0xBAC5, 0x53F8, 0xCBBE, 0x53F9, 0xCCBE, 0x53FA, 0x85B5, 0x53FB, 0xDFB7, 0x53FC, 0xB5F0, 0x53FD, 0xDFB4, 0x53FE, 0x85B6, 0x53FF, 0x85B7, 0x5400, 0x85B8, 0x5401, 0xD3F5, 0x5402, 0x85B9, 0x5403, 0xB3D4, 0x5404, 0xB8F7, 0x5405, 0x85BA, 0x5406, 0xDFBA, 0x5407, 0x85BB, 0x5408, 0xBACF, 0x5409, 0xBCAA, 0x540A, 0xB5F5, 0x540B, 0x85BC, 0x540C, 0xCDAC, 0x540D, 0xC3FB, 0x540E, 0xBAF3, 0x540F, 0xC0F4, 0x5410, 0xCDC2, 0x5411, 0xCFF2, 0x5412, 0xDFB8, 0x5413, 0xCFC5, 0x5414, 0x85BD, 0x5415, 0xC2C0, 0x5416, 0xDFB9, 0x5417, 0xC2F0, 0x5418, 0x85BE, 0x5419, 0x85BF, 0x541A, 0x85C0, 0x541B, 0xBEFD, 0x541C, 0x85C1, 0x541D, 0xC1DF, 0x541E, 0xCDCC, 0x541F, 0xD2F7, 0x5420, 0xB7CD, 0x5421, 0xDFC1, 0x5422, 0x85C2, 0x5423, 0xDFC4, 0x5424, 0x85C3, 0x5425, 0x85C4, 0x5426, 0xB7F1, 0x5427, 0xB0C9, 0x5428, 0xB6D6, 0x5429, 0xB7D4, 0x542A, 0x85C5, 0x542B, 0xBAAC, 0x542C, 0xCCFD, 0x542D, 0xBFD4, 0x542E, 0xCBB1, 0x542F, 0xC6F4, 0x5430, 0x85C6, 0x5431, 0xD6A8, 0x5432, 0xDFC5, 0x5433, 0x85C7, 0x5434, 0xCEE2, 0x5435, 0xB3B3, 0x5436, 0x85C8, 0x5437, 0x85C9, 0x5438, 0xCEFC, 0x5439, 0xB4B5, 0x543A, 0x85CA, 0x543B, 0xCEC7, 0x543C, 0xBAF0, 0x543D, 0x85CB, 0x543E, 0xCEE1, 0x543F, 0x85CC, 0x5440, 0xD1BD, 0x5441, 0x85CD, 0x5442, 0x85CE, 0x5443, 0xDFC0, 0x5444, 0x85CF, 0x5445, 0x85D0, 0x5446, 0xB4F4, 0x5447, 0x85D1, 0x5448, 0xB3CA, 0x5449, 0x85D2, 0x544A, 0xB8E6, 0x544B, 0xDFBB, 0x544C, 0x85D3, 0x544D, 0x85D4, 0x544E, 0x85D5, 0x544F, 0x85D6, 0x5450, 0xC4C5, 0x5451, 0x85D7, 0x5452, 0xDFBC, 0x5453, 0xDFBD, 0x5454, 0xDFBE, 0x5455, 0xC5BB, 0x5456, 0xDFBF, 0x5457, 0xDFC2, 0x5458, 0xD4B1, 0x5459, 0xDFC3, 0x545A, 0x85D8, 0x545B, 0xC7BA, 0x545C, 0xCED8, 0x545D, 0x85D9, 0x545E, 0x85DA, 0x545F, 0x85DB, 0x5460, 0x85DC, 0x5461, 0x85DD, 0x5462, 0xC4D8, 0x5463, 0x85DE, 0x5464, 0xDFCA, 0x5465, 0x85DF, 0x5466, 0xDFCF, 0x5467, 0x85E0, 0x5468, 0xD6DC, 0x5469, 0x85E1, 0x546A, 0x85E2, 0x546B, 0x85E3, 0x546C, 0x85E4, 0x546D, 0x85E5, 0x546E, 0x85E6, 0x546F, 0x85E7, 0x5470, 0x85E8, 0x5471, 0xDFC9, 0x5472, 0xDFDA, 0x5473, 0xCEB6, 0x5474, 0x85E9, 0x5475, 0xBAC7, 0x5476, 0xDFCE, 0x5477, 0xDFC8, 0x5478, 0xC5DE, 0x5479, 0x85EA, 0x547A, 0x85EB, 0x547B, 0xC9EB, 0x547C, 0xBAF4, 0x547D, 0xC3FC, 0x547E, 0x85EC, 0x547F, 0x85ED, 0x5480, 0xBED7, 0x5481, 0x85EE, 0x5482, 0xDFC6, 0x5483, 0x85EF, 0x5484, 0xDFCD, 0x5485, 0x85F0, 0x5486, 0xC5D8, 0x5487, 0x85F1, 0x5488, 0x85F2, 0x5489, 0x85F3, 0x548A, 0x85F4, 0x548B, 0xD5A6, 0x548C, 0xBACD, 0x548D, 0x85F5, 0x548E, 0xBECC, 0x548F, 0xD3BD, 0x5490, 0xB8C0, 0x5491, 0x85F6, 0x5492, 0xD6E4, 0x5493, 0x85F7, 0x5494, 0xDFC7, 0x5495, 0xB9BE, 0x5496, 0xBFA7, 0x5497, 0x85F8, 0x5498, 0x85F9, 0x5499, 0xC1FC, 0x549A, 0xDFCB, 0x549B, 0xDFCC, 0x549C, 0x85FA, 0x549D, 0xDFD0, 0x549E, 0x85FB, 0x549F, 0x85FC, 0x54A0, 0x85FD, 0x54A1, 0x85FE, 0x54A2, 0x8640, 0x54A3, 0xDFDB, 0x54A4, 0xDFE5, 0x54A5, 0x8641, 0x54A6, 0xDFD7, 0x54A7, 0xDFD6, 0x54A8, 0xD7C9, 0x54A9, 0xDFE3, 0x54AA, 0xDFE4, 0x54AB, 0xE5EB, 0x54AC, 0xD2A7, 0x54AD, 0xDFD2, 0x54AE, 0x8642, 0x54AF, 0xBFA9, 0x54B0, 0x8643, 0x54B1, 0xD4DB, 0x54B2, 0x8644, 0x54B3, 0xBFC8, 0x54B4, 0xDFD4, 0x54B5, 0x8645, 0x54B6, 0x8646, 0x54B7, 0x8647, 0x54B8, 0xCFCC, 0x54B9, 0x8648, 0x54BA, 0x8649, 0x54BB, 0xDFDD, 0x54BC, 0x864A, 0x54BD, 0xD1CA, 0x54BE, 0x864B, 0x54BF, 0xDFDE, 0x54C0, 0xB0A7, 0x54C1, 0xC6B7, 0x54C2, 0xDFD3, 0x54C3, 0x864C, 0x54C4, 0xBAE5, 0x54C5, 0x864D, 0x54C6, 0xB6DF, 0x54C7, 0xCDDB, 0x54C8, 0xB9FE, 0x54C9, 0xD4D5, 0x54CA, 0x864E, 0x54CB, 0x864F, 0x54CC, 0xDFDF, 0x54CD, 0xCFEC, 0x54CE, 0xB0A5, 0x54CF, 0xDFE7, 0x54D0, 0xDFD1, 0x54D1, 0xD1C6, 0x54D2, 0xDFD5, 0x54D3, 0xDFD8, 0x54D4, 0xDFD9, 0x54D5, 0xDFDC, 0x54D6, 0x8650, 0x54D7, 0xBBA9, 0x54D8, 0x8651, 0x54D9, 0xDFE0, 0x54DA, 0xDFE1, 0x54DB, 0x8652, 0x54DC, 0xDFE2, 0x54DD, 0xDFE6, 0x54DE, 0xDFE8, 0x54DF, 0xD3B4, 0x54E0, 0x8653, 0x54E1, 0x8654, 0x54E2, 0x8655, 0x54E3, 0x8656, 0x54E4, 0x8657, 0x54E5, 0xB8E7, 0x54E6, 0xC5B6, 0x54E7, 0xDFEA, 0x54E8, 0xC9DA, 0x54E9, 0xC1A8, 0x54EA, 0xC4C4, 0x54EB, 0x8658, 0x54EC, 0x8659, 0x54ED, 0xBFDE, 0x54EE, 0xCFF8, 0x54EF, 0x865A, 0x54F0, 0x865B, 0x54F1, 0x865C, 0x54F2, 0xD5DC, 0x54F3, 0xDFEE, 0x54F4, 0x865D, 0x54F5, 0x865E, 0x54F6, 0x865F, 0x54F7, 0x8660, 0x54F8, 0x8661, 0x54F9, 0x8662, 0x54FA, 0xB2B8, 0x54FB, 0x8663, 0x54FC, 0xBADF, 0x54FD, 0xDFEC, 0x54FE, 0x8664, 0x54FF, 0xDBC1, 0x5500, 0x8665, 0x5501, 0xD1E4, 0x5502, 0x8666, 0x5503, 0x8667, 0x5504, 0x8668, 0x5505, 0x8669, 0x5506, 0xCBF4, 0x5507, 0xB4BD, 0x5508, 0x866A, 0x5509, 0xB0A6, 0x550A, 0x866B, 0x550B, 0x866C, 0x550C, 0x866D, 0x550D, 0x866E, 0x550E, 0x866F, 0x550F, 0xDFF1, 0x5510, 0xCCC6, 0x5511, 0xDFF2, 0x5512, 0x8670, 0x5513, 0x8671, 0x5514, 0xDFED, 0x5515, 0x8672, 0x5516, 0x8673, 0x5517, 0x8674, 0x5518, 0x8675, 0x5519, 0x8676, 0x551A, 0x8677, 0x551B, 0xDFE9, 0x551C, 0x8678, 0x551D, 0x8679, 0x551E, 0x867A, 0x551F, 0x867B, 0x5520, 0xDFEB, 0x5521, 0x867C, 0x5522, 0xDFEF, 0x5523, 0xDFF0, 0x5524, 0xBBBD, 0x5525, 0x867D, 0x5526, 0x867E, 0x5527, 0xDFF3, 0x5528, 0x8680, 0x5529, 0x8681, 0x552A, 0xDFF4, 0x552B, 0x8682, 0x552C, 0xBBA3, 0x552D, 0x8683, 0x552E, 0xCADB, 0x552F, 0xCEA8, 0x5530, 0xE0A7, 0x5531, 0xB3AA, 0x5532, 0x8684, 0x5533, 0xE0A6, 0x5534, 0x8685, 0x5535, 0x8686, 0x5536, 0x8687, 0x5537, 0xE0A1, 0x5538, 0x8688, 0x5539, 0x8689, 0x553A, 0x868A, 0x553B, 0x868B, 0x553C, 0xDFFE, 0x553D, 0x868C, 0x553E, 0xCDD9, 0x553F, 0xDFFC, 0x5540, 0x868D, 0x5541, 0xDFFA, 0x5542, 0x868E, 0x5543, 0xBFD0, 0x5544, 0xD7C4, 0x5545, 0x868F, 0x5546, 0xC9CC, 0x5547, 0x8690, 0x5548, 0x8691, 0x5549, 0xDFF8, 0x554A, 0xB0A1, 0x554B, 0x8692, 0x554C, 0x8693, 0x554D, 0x8694, 0x554E, 0x8695, 0x554F, 0x8696, 0x5550, 0xDFFD, 0x5551, 0x8697, 0x5552, 0x8698, 0x5553, 0x8699, 0x5554, 0x869A, 0x5555, 0xDFFB, 0x5556, 0xE0A2, 0x5557, 0x869B, 0x5558, 0x869C, 0x5559, 0x869D, 0x555A, 0x869E, 0x555B, 0x869F, 0x555C, 0xE0A8, 0x555D, 0x86A0, 0x555E, 0x86A1, 0x555F, 0x86A2, 0x5560, 0x86A3, 0x5561, 0xB7C8, 0x5562, 0x86A4, 0x5563, 0x86A5, 0x5564, 0xC6A1, 0x5565, 0xC9B6, 0x5566, 0xC0B2, 0x5567, 0xDFF5, 0x5568, 0x86A6, 0x5569, 0x86A7, 0x556A, 0xC5BE, 0x556B, 0x86A8, 0x556C, 0xD8C4, 0x556D, 0xDFF9, 0x556E, 0xC4F6, 0x556F, 0x86A9, 0x5570, 0x86AA, 0x5571, 0x86AB, 0x5572, 0x86AC, 0x5573, 0x86AD, 0x5574, 0x86AE, 0x5575, 0xE0A3, 0x5576, 0xE0A4, 0x5577, 0xE0A5, 0x5578, 0xD0A5, 0x5579, 0x86AF, 0x557A, 0x86B0, 0x557B, 0xE0B4, 0x557C, 0xCCE4, 0x557D, 0x86B1, 0x557E, 0xE0B1, 0x557F, 0x86B2, 0x5580, 0xBFA6, 0x5581, 0xE0AF, 0x5582, 0xCEB9, 0x5583, 0xE0AB, 0x5584, 0xC9C6, 0x5585, 0x86B3, 0x5586, 0x86B4, 0x5587, 0xC0AE, 0x5588, 0xE0AE, 0x5589, 0xBAED, 0x558A, 0xBAB0, 0x558B, 0xE0A9, 0x558C, 0x86B5, 0x558D, 0x86B6, 0x558E, 0x86B7, 0x558F, 0xDFF6, 0x5590, 0x86B8, 0x5591, 0xE0B3, 0x5592, 0x86B9, 0x5593, 0x86BA, 0x5594, 0xE0B8, 0x5595, 0x86BB, 0x5596, 0x86BC, 0x5597, 0x86BD, 0x5598, 0xB4AD, 0x5599, 0xE0B9, 0x559A, 0x86BE, 0x559B, 0x86BF, 0x559C, 0xCFB2, 0x559D, 0xBAC8, 0x559E, 0x86C0, 0x559F, 0xE0B0, 0x55A0, 0x86C1, 0x55A1, 0x86C2, 0x55A2, 0x86C3, 0x55A3, 0x86C4, 0x55A4, 0x86C5, 0x55A5, 0x86C6, 0x55A6, 0x86C7, 0x55A7, 0xD0FA, 0x55A8, 0x86C8, 0x55A9, 0x86C9, 0x55AA, 0x86CA, 0x55AB, 0x86CB, 0x55AC, 0x86CC, 0x55AD, 0x86CD, 0x55AE, 0x86CE, 0x55AF, 0x86CF, 0x55B0, 0x86D0, 0x55B1, 0xE0AC, 0x55B2, 0x86D1, 0x55B3, 0xD4FB, 0x55B4, 0x86D2, 0x55B5, 0xDFF7, 0x55B6, 0x86D3, 0x55B7, 0xC5E7, 0x55B8, 0x86D4, 0x55B9, 0xE0AD, 0x55BA, 0x86D5, 0x55BB, 0xD3F7, 0x55BC, 0x86D6, 0x55BD, 0xE0B6, 0x55BE, 0xE0B7, 0x55BF, 0x86D7, 0x55C0, 0x86D8, 0x55C1, 0x86D9, 0x55C2, 0x86DA, 0x55C3, 0x86DB, 0x55C4, 0xE0C4, 0x55C5, 0xD0E1, 0x55C6, 0x86DC, 0x55C7, 0x86DD, 0x55C8, 0x86DE, 0x55C9, 0xE0BC, 0x55CA, 0x86DF, 0x55CB, 0x86E0, 0x55CC, 0xE0C9, 0x55CD, 0xE0CA, 0x55CE, 0x86E1, 0x55CF, 0x86E2, 0x55D0, 0x86E3, 0x55D1, 0xE0BE, 0x55D2, 0xE0AA, 0x55D3, 0xC9A4, 0x55D4, 0xE0C1, 0x55D5, 0x86E4, 0x55D6, 0xE0B2, 0x55D7, 0x86E5, 0x55D8, 0x86E6, 0x55D9, 0x86E7, 0x55DA, 0x86E8, 0x55DB, 0x86E9, 0x55DC, 0xCAC8, 0x55DD, 0xE0C3, 0x55DE, 0x86EA, 0x55DF, 0xE0B5, 0x55E0, 0x86EB, 0x55E1, 0xCECB, 0x55E2, 0x86EC, 0x55E3, 0xCBC3, 0x55E4, 0xE0CD, 0x55E5, 0xE0C6, 0x55E6, 0xE0C2, 0x55E7, 0x86ED, 0x55E8, 0xE0CB, 0x55E9, 0x86EE, 0x55EA, 0xE0BA, 0x55EB, 0xE0BF, 0x55EC, 0xE0C0, 0x55ED, 0x86EF, 0x55EE, 0x86F0, 0x55EF, 0xE0C5, 0x55F0, 0x86F1, 0x55F1, 0x86F2, 0x55F2, 0xE0C7, 0x55F3, 0xE0C8, 0x55F4, 0x86F3, 0x55F5, 0xE0CC, 0x55F6, 0x86F4, 0x55F7, 0xE0BB, 0x55F8, 0x86F5, 0x55F9, 0x86F6, 0x55FA, 0x86F7, 0x55FB, 0x86F8, 0x55FC, 0x86F9, 0x55FD, 0xCBD4, 0x55FE, 0xE0D5, 0x55FF, 0x86FA, 0x5600, 0xE0D6, 0x5601, 0xE0D2, 0x5602, 0x86FB, 0x5603, 0x86FC, 0x5604, 0x86FD, 0x5605, 0x86FE, 0x5606, 0x8740, 0x5607, 0x8741, 0x5608, 0xE0D0, 0x5609, 0xBCCE, 0x560A, 0x8742, 0x560B, 0x8743, 0x560C, 0xE0D1, 0x560D, 0x8744, 0x560E, 0xB8C2, 0x560F, 0xD8C5, 0x5610, 0x8745, 0x5611, 0x8746, 0x5612, 0x8747, 0x5613, 0x8748, 0x5614, 0x8749, 0x5615, 0x874A, 0x5616, 0x874B, 0x5617, 0x874C, 0x5618, 0xD0EA, 0x5619, 0x874D, 0x561A, 0x874E, 0x561B, 0xC2EF, 0x561C, 0x874F, 0x561D, 0x8750, 0x561E, 0xE0CF, 0x561F, 0xE0BD, 0x5620, 0x8751, 0x5621, 0x8752, 0x5622, 0x8753, 0x5623, 0xE0D4, 0x5624, 0xE0D3, 0x5625, 0x8754, 0x5626, 0x8755, 0x5627, 0xE0D7, 0x5628, 0x8756, 0x5629, 0x8757, 0x562A, 0x8758, 0x562B, 0x8759, 0x562C, 0xE0DC, 0x562D, 0xE0D8, 0x562E, 0x875A, 0x562F, 0x875B, 0x5630, 0x875C, 0x5631, 0xD6F6, 0x5632, 0xB3B0, 0x5633, 0x875D, 0x5634, 0xD7EC, 0x5635, 0x875E, 0x5636, 0xCBBB, 0x5637, 0x875F, 0x5638, 0x8760, 0x5639, 0xE0DA, 0x563A, 0x8761, 0x563B, 0xCEFB, 0x563C, 0x8762, 0x563D, 0x8763, 0x563E, 0x8764, 0x563F, 0xBAD9, 0x5640, 0x8765, 0x5641, 0x8766, 0x5642, 0x8767, 0x5643, 0x8768, 0x5644, 0x8769, 0x5645, 0x876A, 0x5646, 0x876B, 0x5647, 0x876C, 0x5648, 0x876D, 0x5649, 0x876E, 0x564A, 0x876F, 0x564B, 0x8770, 0x564C, 0xE0E1, 0x564D, 0xE0DD, 0x564E, 0xD2AD, 0x564F, 0x8771, 0x5650, 0x8772, 0x5651, 0x8773, 0x5652, 0x8774, 0x5653, 0x8775, 0x5654, 0xE0E2, 0x5655, 0x8776, 0x5656, 0x8777, 0x5657, 0xE0DB, 0x5658, 0xE0D9, 0x5659, 0xE0DF, 0x565A, 0x8778, 0x565B, 0x8779, 0x565C, 0xE0E0, 0x565D, 0x877A, 0x565E, 0x877B, 0x565F, 0x877C, 0x5660, 0x877D, 0x5661, 0x877E, 0x5662, 0xE0DE, 0x5663, 0x8780, 0x5664, 0xE0E4, 0x5665, 0x8781, 0x5666, 0x8782, 0x5667, 0x8783, 0x5668, 0xC6F7, 0x5669, 0xD8AC, 0x566A, 0xD4EB, 0x566B, 0xE0E6, 0x566C, 0xCAC9, 0x566D, 0x8784, 0x566E, 0x8785, 0x566F, 0x8786, 0x5670, 0x8787, 0x5671, 0xE0E5, 0x5672, 0x8788, 0x5673, 0x8789, 0x5674, 0x878A, 0x5675, 0x878B, 0x5676, 0xB8C1, 0x5677, 0x878C, 0x5678, 0x878D, 0x5679, 0x878E, 0x567A, 0x878F, 0x567B, 0xE0E7, 0x567C, 0xE0E8, 0x567D, 0x8790, 0x567E, 0x8791, 0x567F, 0x8792, 0x5680, 0x8793, 0x5681, 0x8794, 0x5682, 0x8795, 0x5683, 0x8796, 0x5684, 0x8797, 0x5685, 0xE0E9, 0x5686, 0xE0E3, 0x5687, 0x8798, 0x5688, 0x8799, 0x5689, 0x879A, 0x568A, 0x879B, 0x568B, 0x879C, 0x568C, 0x879D, 0x568D, 0x879E, 0x568E, 0xBABF, 0x568F, 0xCCE7, 0x5690, 0x879F, 0x5691, 0x87A0, 0x5692, 0x87A1, 0x5693, 0xE0EA, 0x5694, 0x87A2, 0x5695, 0x87A3, 0x5696, 0x87A4, 0x5697, 0x87A5, 0x5698, 0x87A6, 0x5699, 0x87A7, 0x569A, 0x87A8, 0x569B, 0x87A9, 0x569C, 0x87AA, 0x569D, 0x87AB, 0x569E, 0x87AC, 0x569F, 0x87AD, 0x56A0, 0x87AE, 0x56A1, 0x87AF, 0x56A2, 0x87B0, 0x56A3, 0xCFF9, 0x56A4, 0x87B1, 0x56A5, 0x87B2, 0x56A6, 0x87B3, 0x56A7, 0x87B4, 0x56A8, 0x87B5, 0x56A9, 0x87B6, 0x56AA, 0x87B7, 0x56AB, 0x87B8, 0x56AC, 0x87B9, 0x56AD, 0x87BA, 0x56AE, 0x87BB, 0x56AF, 0xE0EB, 0x56B0, 0x87BC, 0x56B1, 0x87BD, 0x56B2, 0x87BE, 0x56B3, 0x87BF, 0x56B4, 0x87C0, 0x56B5, 0x87C1, 0x56B6, 0x87C2, 0x56B7, 0xC8C2, 0x56B8, 0x87C3, 0x56B9, 0x87C4, 0x56BA, 0x87C5, 0x56BB, 0x87C6, 0x56BC, 0xBDC0, 0x56BD, 0x87C7, 0x56BE, 0x87C8, 0x56BF, 0x87C9, 0x56C0, 0x87CA, 0x56C1, 0x87CB, 0x56C2, 0x87CC, 0x56C3, 0x87CD, 0x56C4, 0x87CE, 0x56C5, 0x87CF, 0x56C6, 0x87D0, 0x56C7, 0x87D1, 0x56C8, 0x87D2, 0x56C9, 0x87D3, 0x56CA, 0xC4D2, 0x56CB, 0x87D4, 0x56CC, 0x87D5, 0x56CD, 0x87D6, 0x56CE, 0x87D7, 0x56CF, 0x87D8, 0x56D0, 0x87D9, 0x56D1, 0x87DA, 0x56D2, 0x87DB, 0x56D3, 0x87DC, 0x56D4, 0xE0EC, 0x56D5, 0x87DD, 0x56D6, 0x87DE, 0x56D7, 0xE0ED, 0x56D8, 0x87DF, 0x56D9, 0x87E0, 0x56DA, 0xC7F4, 0x56DB, 0xCBC4, 0x56DC, 0x87E1, 0x56DD, 0xE0EE, 0x56DE, 0xBBD8, 0x56DF, 0xD8B6, 0x56E0, 0xD2F2, 0x56E1, 0xE0EF, 0x56E2, 0xCDC5, 0x56E3, 0x87E2, 0x56E4, 0xB6DA, 0x56E5, 0x87E3, 0x56E6, 0x87E4, 0x56E7, 0x87E5, 0x56E8, 0x87E6, 0x56E9, 0x87E7, 0x56EA, 0x87E8, 0x56EB, 0xE0F1, 0x56EC, 0x87E9, 0x56ED, 0xD4B0, 0x56EE, 0x87EA, 0x56EF, 0x87EB, 0x56F0, 0xC0A7, 0x56F1, 0xB4D1, 0x56F2, 0x87EC, 0x56F3, 0x87ED, 0x56F4, 0xCEA7, 0x56F5, 0xE0F0, 0x56F6, 0x87EE, 0x56F7, 0x87EF, 0x56F8, 0x87F0, 0x56F9, 0xE0F2, 0x56FA, 0xB9CC, 0x56FB, 0x87F1, 0x56FC, 0x87F2, 0x56FD, 0xB9FA, 0x56FE, 0xCDBC, 0x56FF, 0xE0F3, 0x5700, 0x87F3, 0x5701, 0x87F4, 0x5702, 0x87F5, 0x5703, 0xC6D4, 0x5704, 0xE0F4, 0x5705, 0x87F6, 0x5706, 0xD4B2, 0x5707, 0x87F7, 0x5708, 0xC8A6, 0x5709, 0xE0F6, 0x570A, 0xE0F5, 0x570B, 0x87F8, 0x570C, 0x87F9, 0x570D, 0x87FA, 0x570E, 0x87FB, 0x570F, 0x87FC, 0x5710, 0x87FD, 0x5711, 0x87FE, 0x5712, 0x8840, 0x5713, 0x8841, 0x5714, 0x8842, 0x5715, 0x8843, 0x5716, 0x8844, 0x5717, 0x8845, 0x5718, 0x8846, 0x5719, 0x8847, 0x571A, 0x8848, 0x571B, 0x8849, 0x571C, 0xE0F7, 0x571D, 0x884A, 0x571E, 0x884B, 0x571F, 0xCDC1, 0x5720, 0x884C, 0x5721, 0x884D, 0x5722, 0x884E, 0x5723, 0xCAA5, 0x5724, 0x884F, 0x5725, 0x8850, 0x5726, 0x8851, 0x5727, 0x8852, 0x5728, 0xD4DA, 0x5729, 0xDBD7, 0x572A, 0xDBD9, 0x572B, 0x8853, 0x572C, 0xDBD8, 0x572D, 0xB9E7, 0x572E, 0xDBDC, 0x572F, 0xDBDD, 0x5730, 0xB5D8, 0x5731, 0x8854, 0x5732, 0x8855, 0x5733, 0xDBDA, 0x5734, 0x8856, 0x5735, 0x8857, 0x5736, 0x8858, 0x5737, 0x8859, 0x5738, 0x885A, 0x5739, 0xDBDB, 0x573A, 0xB3A1, 0x573B, 0xDBDF, 0x573C, 0x885B, 0x573D, 0x885C, 0x573E, 0xBBF8, 0x573F, 0x885D, 0x5740, 0xD6B7, 0x5741, 0x885E, 0x5742, 0xDBE0, 0x5743, 0x885F, 0x5744, 0x8860, 0x5745, 0x8861, 0x5746, 0x8862, 0x5747, 0xBEF9, 0x5748, 0x8863, 0x5749, 0x8864, 0x574A, 0xB7BB, 0x574B, 0x8865, 0x574C, 0xDBD0, 0x574D, 0xCCAE, 0x574E, 0xBFB2, 0x574F, 0xBBB5, 0x5750, 0xD7F8, 0x5751, 0xBFD3, 0x5752, 0x8866, 0x5753, 0x8867, 0x5754, 0x8868, 0x5755, 0x8869, 0x5756, 0x886A, 0x5757, 0xBFE9, 0x5758, 0x886B, 0x5759, 0x886C, 0x575A, 0xBCE1, 0x575B, 0xCCB3, 0x575C, 0xDBDE, 0x575D, 0xB0D3, 0x575E, 0xCEEB, 0x575F, 0xB7D8, 0x5760, 0xD7B9, 0x5761, 0xC6C2, 0x5762, 0x886D, 0x5763, 0x886E, 0x5764, 0xC0A4, 0x5765, 0x886F, 0x5766, 0xCCB9, 0x5767, 0x8870, 0x5768, 0xDBE7, 0x5769, 0xDBE1, 0x576A, 0xC6BA, 0x576B, 0xDBE3, 0x576C, 0x8871, 0x576D, 0xDBE8, 0x576E, 0x8872, 0x576F, 0xC5F7, 0x5770, 0x8873, 0x5771, 0x8874, 0x5772, 0x8875, 0x5773, 0xDBEA, 0x5774, 0x8876, 0x5775, 0x8877, 0x5776, 0xDBE9, 0x5777, 0xBFC0, 0x5778, 0x8878, 0x5779, 0x8879, 0x577A, 0x887A, 0x577B, 0xDBE6, 0x577C, 0xDBE5, 0x577D, 0x887B, 0x577E, 0x887C, 0x577F, 0x887D, 0x5780, 0x887E, 0x5781, 0x8880, 0x5782, 0xB4B9, 0x5783, 0xC0AC, 0x5784, 0xC2A2, 0x5785, 0xDBE2, 0x5786, 0xDBE4, 0x5787, 0x8881, 0x5788, 0x8882, 0x5789, 0x8883, 0x578A, 0x8884, 0x578B, 0xD0CD, 0x578C, 0xDBED, 0x578D, 0x8885, 0x578E, 0x8886, 0x578F, 0x8887, 0x5790, 0x8888, 0x5791, 0x8889, 0x5792, 0xC0DD, 0x5793, 0xDBF2, 0x5794, 0x888A, 0x5795, 0x888B, 0x5796, 0x888C, 0x5797, 0x888D, 0x5798, 0x888E, 0x5799, 0x888F, 0x579A, 0x8890, 0x579B, 0xB6E2, 0x579C, 0x8891, 0x579D, 0x8892, 0x579E, 0x8893, 0x579F, 0x8894, 0x57A0, 0xDBF3, 0x57A1, 0xDBD2, 0x57A2, 0xB9B8, 0x57A3, 0xD4AB, 0x57A4, 0xDBEC, 0x57A5, 0x8895, 0x57A6, 0xBFD1, 0x57A7, 0xDBF0, 0x57A8, 0x8896, 0x57A9, 0xDBD1, 0x57AA, 0x8897, 0x57AB, 0xB5E6, 0x57AC, 0x8898, 0x57AD, 0xDBEB, 0x57AE, 0xBFE5, 0x57AF, 0x8899, 0x57B0, 0x889A, 0x57B1, 0x889B, 0x57B2, 0xDBEE, 0x57B3, 0x889C, 0x57B4, 0xDBF1, 0x57B5, 0x889D, 0x57B6, 0x889E, 0x57B7, 0x889F, 0x57B8, 0xDBF9, 0x57B9, 0x88A0, 0x57BA, 0x88A1, 0x57BB, 0x88A2, 0x57BC, 0x88A3, 0x57BD, 0x88A4, 0x57BE, 0x88A5, 0x57BF, 0x88A6, 0x57C0, 0x88A7, 0x57C1, 0x88A8, 0x57C2, 0xB9A1, 0x57C3, 0xB0A3, 0x57C4, 0x88A9, 0x57C5, 0x88AA, 0x57C6, 0x88AB, 0x57C7, 0x88AC, 0x57C8, 0x88AD, 0x57C9, 0x88AE, 0x57CA, 0x88AF, 0x57CB, 0xC2F1, 0x57CC, 0x88B0, 0x57CD, 0x88B1, 0x57CE, 0xB3C7, 0x57CF, 0xDBEF, 0x57D0, 0x88B2, 0x57D1, 0x88B3, 0x57D2, 0xDBF8, 0x57D3, 0x88B4, 0x57D4, 0xC6D2, 0x57D5, 0xDBF4, 0x57D6, 0x88B5, 0x57D7, 0x88B6, 0x57D8, 0xDBF5, 0x57D9, 0xDBF7, 0x57DA, 0xDBF6, 0x57DB, 0x88B7, 0x57DC, 0x88B8, 0x57DD, 0xDBFE, 0x57DE, 0x88B9, 0x57DF, 0xD3F2, 0x57E0, 0xB2BA, 0x57E1, 0x88BA, 0x57E2, 0x88BB, 0x57E3, 0x88BC, 0x57E4, 0xDBFD, 0x57E5, 0x88BD, 0x57E6, 0x88BE, 0x57E7, 0x88BF, 0x57E8, 0x88C0, 0x57E9, 0x88C1, 0x57EA, 0x88C2, 0x57EB, 0x88C3, 0x57EC, 0x88C4, 0x57ED, 0xDCA4, 0x57EE, 0x88C5, 0x57EF, 0xDBFB, 0x57F0, 0x88C6, 0x57F1, 0x88C7, 0x57F2, 0x88C8, 0x57F3, 0x88C9, 0x57F4, 0xDBFA, 0x57F5, 0x88CA, 0x57F6, 0x88CB, 0x57F7, 0x88CC, 0x57F8, 0xDBFC, 0x57F9, 0xC5E0, 0x57FA, 0xBBF9, 0x57FB, 0x88CD, 0x57FC, 0x88CE, 0x57FD, 0xDCA3, 0x57FE, 0x88CF, 0x57FF, 0x88D0, 0x5800, 0xDCA5, 0x5801, 0x88D1, 0x5802, 0xCCC3, 0x5803, 0x88D2, 0x5804, 0x88D3, 0x5805, 0x88D4, 0x5806, 0xB6D1, 0x5807, 0xDDC0, 0x5808, 0x88D5, 0x5809, 0x88D6, 0x580A, 0x88D7, 0x580B, 0xDCA1, 0x580C, 0x88D8, 0x580D, 0xDCA2, 0x580E, 0x88D9, 0x580F, 0x88DA, 0x5810, 0x88DB, 0x5811, 0xC7B5, 0x5812, 0x88DC, 0x5813, 0x88DD, 0x5814, 0x88DE, 0x5815, 0xB6E9, 0x5816, 0x88DF, 0x5817, 0x88E0, 0x5818, 0x88E1, 0x5819, 0xDCA7, 0x581A, 0x88E2, 0x581B, 0x88E3, 0x581C, 0x88E4, 0x581D, 0x88E5, 0x581E, 0xDCA6, 0x581F, 0x88E6, 0x5820, 0xDCA9, 0x5821, 0xB1A4, 0x5822, 0x88E7, 0x5823, 0x88E8, 0x5824, 0xB5CC, 0x5825, 0x88E9, 0x5826, 0x88EA, 0x5827, 0x88EB, 0x5828, 0x88EC, 0x5829, 0x88ED, 0x582A, 0xBFB0, 0x582B, 0x88EE, 0x582C, 0x88EF, 0x582D, 0x88F0, 0x582E, 0x88F1, 0x582F, 0x88F2, 0x5830, 0xD1DF, 0x5831, 0x88F3, 0x5832, 0x88F4, 0x5833, 0x88F5, 0x5834, 0x88F6, 0x5835, 0xB6C2, 0x5836, 0x88F7, 0x5837, 0x88F8, 0x5838, 0x88F9, 0x5839, 0x88FA, 0x583A, 0x88FB, 0x583B, 0x88FC, 0x583C, 0x88FD, 0x583D, 0x88FE, 0x583E, 0x8940, 0x583F, 0x8941, 0x5840, 0x8942, 0x5841, 0x8943, 0x5842, 0x8944, 0x5843, 0x8945, 0x5844, 0xDCA8, 0x5845, 0x8946, 0x5846, 0x8947, 0x5847, 0x8948, 0x5848, 0x8949, 0x5849, 0x894A, 0x584A, 0x894B, 0x584B, 0x894C, 0x584C, 0xCBFA, 0x584D, 0xEBF3, 0x584E, 0x894D, 0x584F, 0x894E, 0x5850, 0x894F, 0x5851, 0xCBDC, 0x5852, 0x8950, 0x5853, 0x8951, 0x5854, 0xCBFE, 0x5855, 0x8952, 0x5856, 0x8953, 0x5857, 0x8954, 0x5858, 0xCCC1, 0x5859, 0x8955, 0x585A, 0x8956, 0x585B, 0x8957, 0x585C, 0x8958, 0x585D, 0x8959, 0x585E, 0xC8FB, 0x585F, 0x895A, 0x5860, 0x895B, 0x5861, 0x895C, 0x5862, 0x895D, 0x5863, 0x895E, 0x5864, 0x895F, 0x5865, 0xDCAA, 0x5866, 0x8960, 0x5867, 0x8961, 0x5868, 0x8962, 0x5869, 0x8963, 0x586A, 0x8964, 0x586B, 0xCCEE, 0x586C, 0xDCAB, 0x586D, 0x8965, 0x586E, 0x8966, 0x586F, 0x8967, 0x5870, 0x8968, 0x5871, 0x8969, 0x5872, 0x896A, 0x5873, 0x896B, 0x5874, 0x896C, 0x5875, 0x896D, 0x5876, 0x896E, 0x5877, 0x896F, 0x5878, 0x8970, 0x5879, 0x8971, 0x587A, 0x8972, 0x587B, 0x8973, 0x587C, 0x8974, 0x587D, 0x8975, 0x587E, 0xDBD3, 0x587F, 0x8976, 0x5880, 0xDCAF, 0x5881, 0xDCAC, 0x5882, 0x8977, 0x5883, 0xBEB3, 0x5884, 0x8978, 0x5885, 0xCAFB, 0x5886, 0x8979, 0x5887, 0x897A, 0x5888, 0x897B, 0x5889, 0xDCAD, 0x588A, 0x897C, 0x588B, 0x897D, 0x588C, 0x897E, 0x588D, 0x8980, 0x588E, 0x8981, 0x588F, 0x8982, 0x5890, 0x8983, 0x5891, 0x8984, 0x5892, 0xC9CA, 0x5893, 0xC4B9, 0x5894, 0x8985, 0x5895, 0x8986, 0x5896, 0x8987, 0x5897, 0x8988, 0x5898, 0x8989, 0x5899, 0xC7BD, 0x589A, 0xDCAE, 0x589B, 0x898A, 0x589C, 0x898B, 0x589D, 0x898C, 0x589E, 0xD4F6, 0x589F, 0xD0E6, 0x58A0, 0x898D, 0x58A1, 0x898E, 0x58A2, 0x898F, 0x58A3, 0x8990, 0x58A4, 0x8991, 0x58A5, 0x8992, 0x58A6, 0x8993, 0x58A7, 0x8994, 0x58A8, 0xC4AB, 0x58A9, 0xB6D5, 0x58AA, 0x8995, 0x58AB, 0x8996, 0x58AC, 0x8997, 0x58AD, 0x8998, 0x58AE, 0x8999, 0x58AF, 0x899A, 0x58B0, 0x899B, 0x58B1, 0x899C, 0x58B2, 0x899D, 0x58B3, 0x899E, 0x58B4, 0x899F, 0x58B5, 0x89A0, 0x58B6, 0x89A1, 0x58B7, 0x89A2, 0x58B8, 0x89A3, 0x58B9, 0x89A4, 0x58BA, 0x89A5, 0x58BB, 0x89A6, 0x58BC, 0xDBD4, 0x58BD, 0x89A7, 0x58BE, 0x89A8, 0x58BF, 0x89A9, 0x58C0, 0x89AA, 0x58C1, 0xB1DA, 0x58C2, 0x89AB, 0x58C3, 0x89AC, 0x58C4, 0x89AD, 0x58C5, 0xDBD5, 0x58C6, 0x89AE, 0x58C7, 0x89AF, 0x58C8, 0x89B0, 0x58C9, 0x89B1, 0x58CA, 0x89B2, 0x58CB, 0x89B3, 0x58CC, 0x89B4, 0x58CD, 0x89B5, 0x58CE, 0x89B6, 0x58CF, 0x89B7, 0x58D0, 0x89B8, 0x58D1, 0xDBD6, 0x58D2, 0x89B9, 0x58D3, 0x89BA, 0x58D4, 0x89BB, 0x58D5, 0xBABE, 0x58D6, 0x89BC, 0x58D7, 0x89BD, 0x58D8, 0x89BE, 0x58D9, 0x89BF, 0x58DA, 0x89C0, 0x58DB, 0x89C1, 0x58DC, 0x89C2, 0x58DD, 0x89C3, 0x58DE, 0x89C4, 0x58DF, 0x89C5, 0x58E0, 0x89C6, 0x58E1, 0x89C7, 0x58E2, 0x89C8, 0x58E3, 0x89C9, 0x58E4, 0xC8C0, 0x58E5, 0x89CA, 0x58E6, 0x89CB, 0x58E7, 0x89CC, 0x58E8, 0x89CD, 0x58E9, 0x89CE, 0x58EA, 0x89CF, 0x58EB, 0xCABF, 0x58EC, 0xC8C9, 0x58ED, 0x89D0, 0x58EE, 0xD7B3, 0x58EF, 0x89D1, 0x58F0, 0xC9F9, 0x58F1, 0x89D2, 0x58F2, 0x89D3, 0x58F3, 0xBFC7, 0x58F4, 0x89D4, 0x58F5, 0x89D5, 0x58F6, 0xBAF8, 0x58F7, 0x89D6, 0x58F8, 0x89D7, 0x58F9, 0xD2BC, 0x58FA, 0x89D8, 0x58FB, 0x89D9, 0x58FC, 0x89DA, 0x58FD, 0x89DB, 0x58FE, 0x89DC, 0x58FF, 0x89DD, 0x5900, 0x89DE, 0x5901, 0x89DF, 0x5902, 0xE2BA, 0x5903, 0x89E0, 0x5904, 0xB4A6, 0x5905, 0x89E1, 0x5906, 0x89E2, 0x5907, 0xB1B8, 0x5908, 0x89E3, 0x5909, 0x89E4, 0x590A, 0x89E5, 0x590B, 0x89E6, 0x590C, 0x89E7, 0x590D, 0xB8B4, 0x590E, 0x89E8, 0x590F, 0xCFC4, 0x5910, 0x89E9, 0x5911, 0x89EA, 0x5912, 0x89EB, 0x5913, 0x89EC, 0x5914, 0xD9E7, 0x5915, 0xCFA6, 0x5916, 0xCDE2, 0x5917, 0x89ED, 0x5918, 0x89EE, 0x5919, 0xD9ED, 0x591A, 0xB6E0, 0x591B, 0x89EF, 0x591C, 0xD2B9, 0x591D, 0x89F0, 0x591E, 0x89F1, 0x591F, 0xB9BB, 0x5920, 0x89F2, 0x5921, 0x89F3, 0x5922, 0x89F4, 0x5923, 0x89F5, 0x5924, 0xE2B9, 0x5925, 0xE2B7, 0x5926, 0x89F6, 0x5927, 0xB4F3, 0x5928, 0x89F7, 0x5929, 0xCCEC, 0x592A, 0xCCAB, 0x592B, 0xB7F2, 0x592C, 0x89F8, 0x592D, 0xD8B2, 0x592E, 0xD1EB, 0x592F, 0xBABB, 0x5930, 0x89F9, 0x5931, 0xCAA7, 0x5932, 0x89FA, 0x5933, 0x89FB, 0x5934, 0xCDB7, 0x5935, 0x89FC, 0x5936, 0x89FD, 0x5937, 0xD2C4, 0x5938, 0xBFE4, 0x5939, 0xBCD0, 0x593A, 0xB6E1, 0x593B, 0x89FE, 0x593C, 0xDEC5, 0x593D, 0x8A40, 0x593E, 0x8A41, 0x593F, 0x8A42, 0x5940, 0x8A43, 0x5941, 0xDEC6, 0x5942, 0xDBBC, 0x5943, 0x8A44, 0x5944, 0xD1D9, 0x5945, 0x8A45, 0x5946, 0x8A46, 0x5947, 0xC6E6, 0x5948, 0xC4CE, 0x5949, 0xB7EE, 0x594A, 0x8A47, 0x594B, 0xB7DC, 0x594C, 0x8A48, 0x594D, 0x8A49, 0x594E, 0xBFFC, 0x594F, 0xD7E0, 0x5950, 0x8A4A, 0x5951, 0xC6F5, 0x5952, 0x8A4B, 0x5953, 0x8A4C, 0x5954, 0xB1BC, 0x5955, 0xDEC8, 0x5956, 0xBDB1, 0x5957, 0xCCD7, 0x5958, 0xDECA, 0x5959, 0x8A4D, 0x595A, 0xDEC9, 0x595B, 0x8A4E, 0x595C, 0x8A4F, 0x595D, 0x8A50, 0x595E, 0x8A51, 0x595F, 0x8A52, 0x5960, 0xB5EC, 0x5961, 0x8A53, 0x5962, 0xC9DD, 0x5963, 0x8A54, 0x5964, 0x8A55, 0x5965, 0xB0C2, 0x5966, 0x8A56, 0x5967, 0x8A57, 0x5968, 0x8A58, 0x5969, 0x8A59, 0x596A, 0x8A5A, 0x596B, 0x8A5B, 0x596C, 0x8A5C, 0x596D, 0x8A5D, 0x596E, 0x8A5E, 0x596F, 0x8A5F, 0x5970, 0x8A60, 0x5971, 0x8A61, 0x5972, 0x8A62, 0x5973, 0xC5AE, 0x5974, 0xC5AB, 0x5975, 0x8A63, 0x5976, 0xC4CC, 0x5977, 0x8A64, 0x5978, 0xBCE9, 0x5979, 0xCBFD, 0x597A, 0x8A65, 0x597B, 0x8A66, 0x597C, 0x8A67, 0x597D, 0xBAC3, 0x597E, 0x8A68, 0x597F, 0x8A69, 0x5980, 0x8A6A, 0x5981, 0xE5F9, 0x5982, 0xC8E7, 0x5983, 0xE5FA, 0x5984, 0xCDFD, 0x5985, 0x8A6B, 0x5986, 0xD7B1, 0x5987, 0xB8BE, 0x5988, 0xC2E8, 0x5989, 0x8A6C, 0x598A, 0xC8D1, 0x598B, 0x8A6D, 0x598C, 0x8A6E, 0x598D, 0xE5FB, 0x598E, 0x8A6F, 0x598F, 0x8A70, 0x5990, 0x8A71, 0x5991, 0x8A72, 0x5992, 0xB6CA, 0x5993, 0xBCCB, 0x5994, 0x8A73, 0x5995, 0x8A74, 0x5996, 0xD1FD, 0x5997, 0xE6A1, 0x5998, 0x8A75, 0x5999, 0xC3EE, 0x599A, 0x8A76, 0x599B, 0x8A77, 0x599C, 0x8A78, 0x599D, 0x8A79, 0x599E, 0xE6A4, 0x599F, 0x8A7A, 0x59A0, 0x8A7B, 0x59A1, 0x8A7C, 0x59A2, 0x8A7D, 0x59A3, 0xE5FE, 0x59A4, 0xE6A5, 0x59A5, 0xCDD7, 0x59A6, 0x8A7E, 0x59A7, 0x8A80, 0x59A8, 0xB7C1, 0x59A9, 0xE5FC, 0x59AA, 0xE5FD, 0x59AB, 0xE6A3, 0x59AC, 0x8A81, 0x59AD, 0x8A82, 0x59AE, 0xC4DD, 0x59AF, 0xE6A8, 0x59B0, 0x8A83, 0x59B1, 0x8A84, 0x59B2, 0xE6A7, 0x59B3, 0x8A85, 0x59B4, 0x8A86, 0x59B5, 0x8A87, 0x59B6, 0x8A88, 0x59B7, 0x8A89, 0x59B8, 0x8A8A, 0x59B9, 0xC3C3, 0x59BA, 0x8A8B, 0x59BB, 0xC6DE, 0x59BC, 0x8A8C, 0x59BD, 0x8A8D, 0x59BE, 0xE6AA, 0x59BF, 0x8A8E, 0x59C0, 0x8A8F, 0x59C1, 0x8A90, 0x59C2, 0x8A91, 0x59C3, 0x8A92, 0x59C4, 0x8A93, 0x59C5, 0x8A94, 0x59C6, 0xC4B7, 0x59C7, 0x8A95, 0x59C8, 0x8A96, 0x59C9, 0x8A97, 0x59CA, 0xE6A2, 0x59CB, 0xCABC, 0x59CC, 0x8A98, 0x59CD, 0x8A99, 0x59CE, 0x8A9A, 0x59CF, 0x8A9B, 0x59D0, 0xBDE3, 0x59D1, 0xB9C3, 0x59D2, 0xE6A6, 0x59D3, 0xD0D5, 0x59D4, 0xCEAF, 0x59D5, 0x8A9C, 0x59D6, 0x8A9D, 0x59D7, 0xE6A9, 0x59D8, 0xE6B0, 0x59D9, 0x8A9E, 0x59DA, 0xD2A6, 0x59DB, 0x8A9F, 0x59DC, 0xBDAA, 0x59DD, 0xE6AD, 0x59DE, 0x8AA0, 0x59DF, 0x8AA1, 0x59E0, 0x8AA2, 0x59E1, 0x8AA3, 0x59E2, 0x8AA4, 0x59E3, 0xE6AF, 0x59E4, 0x8AA5, 0x59E5, 0xC0D1, 0x59E6, 0x8AA6, 0x59E7, 0x8AA7, 0x59E8, 0xD2CC, 0x59E9, 0x8AA8, 0x59EA, 0x8AA9, 0x59EB, 0x8AAA, 0x59EC, 0xBCA7, 0x59ED, 0x8AAB, 0x59EE, 0x8AAC, 0x59EF, 0x8AAD, 0x59F0, 0x8AAE, 0x59F1, 0x8AAF, 0x59F2, 0x8AB0, 0x59F3, 0x8AB1, 0x59F4, 0x8AB2, 0x59F5, 0x8AB3, 0x59F6, 0x8AB4, 0x59F7, 0x8AB5, 0x59F8, 0x8AB6, 0x59F9, 0xE6B1, 0x59FA, 0x8AB7, 0x59FB, 0xD2F6, 0x59FC, 0x8AB8, 0x59FD, 0x8AB9, 0x59FE, 0x8ABA, 0x59FF, 0xD7CB, 0x5A00, 0x8ABB, 0x5A01, 0xCDFE, 0x5A02, 0x8ABC, 0x5A03, 0xCDDE, 0x5A04, 0xC2A6, 0x5A05, 0xE6AB, 0x5A06, 0xE6AC, 0x5A07, 0xBDBF, 0x5A08, 0xE6AE, 0x5A09, 0xE6B3, 0x5A0A, 0x8ABD, 0x5A0B, 0x8ABE, 0x5A0C, 0xE6B2, 0x5A0D, 0x8ABF, 0x5A0E, 0x8AC0, 0x5A0F, 0x8AC1, 0x5A10, 0x8AC2, 0x5A11, 0xE6B6, 0x5A12, 0x8AC3, 0x5A13, 0xE6B8, 0x5A14, 0x8AC4, 0x5A15, 0x8AC5, 0x5A16, 0x8AC6, 0x5A17, 0x8AC7, 0x5A18, 0xC4EF, 0x5A19, 0x8AC8, 0x5A1A, 0x8AC9, 0x5A1B, 0x8ACA, 0x5A1C, 0xC4C8, 0x5A1D, 0x8ACB, 0x5A1E, 0x8ACC, 0x5A1F, 0xBEEA, 0x5A20, 0xC9EF, 0x5A21, 0x8ACD, 0x5A22, 0x8ACE, 0x5A23, 0xE6B7, 0x5A24, 0x8ACF, 0x5A25, 0xB6F0, 0x5A26, 0x8AD0, 0x5A27, 0x8AD1, 0x5A28, 0x8AD2, 0x5A29, 0xC3E4, 0x5A2A, 0x8AD3, 0x5A2B, 0x8AD4, 0x5A2C, 0x8AD5, 0x5A2D, 0x8AD6, 0x5A2E, 0x8AD7, 0x5A2F, 0x8AD8, 0x5A30, 0x8AD9, 0x5A31, 0xD3E9, 0x5A32, 0xE6B4, 0x5A33, 0x8ADA, 0x5A34, 0xE6B5, 0x5A35, 0x8ADB, 0x5A36, 0xC8A2, 0x5A37, 0x8ADC, 0x5A38, 0x8ADD, 0x5A39, 0x8ADE, 0x5A3A, 0x8ADF, 0x5A3B, 0x8AE0, 0x5A3C, 0xE6BD, 0x5A3D, 0x8AE1, 0x5A3E, 0x8AE2, 0x5A3F, 0x8AE3, 0x5A40, 0xE6B9, 0x5A41, 0x8AE4, 0x5A42, 0x8AE5, 0x5A43, 0x8AE6, 0x5A44, 0x8AE7, 0x5A45, 0x8AE8, 0x5A46, 0xC6C5, 0x5A47, 0x8AE9, 0x5A48, 0x8AEA, 0x5A49, 0xCDF1, 0x5A4A, 0xE6BB, 0x5A4B, 0x8AEB, 0x5A4C, 0x8AEC, 0x5A4D, 0x8AED, 0x5A4E, 0x8AEE, 0x5A4F, 0x8AEF, 0x5A50, 0x8AF0, 0x5A51, 0x8AF1, 0x5A52, 0x8AF2, 0x5A53, 0x8AF3, 0x5A54, 0x8AF4, 0x5A55, 0xE6BC, 0x5A56, 0x8AF5, 0x5A57, 0x8AF6, 0x5A58, 0x8AF7, 0x5A59, 0x8AF8, 0x5A5A, 0xBBE9, 0x5A5B, 0x8AF9, 0x5A5C, 0x8AFA, 0x5A5D, 0x8AFB, 0x5A5E, 0x8AFC, 0x5A5F, 0x8AFD, 0x5A60, 0x8AFE, 0x5A61, 0x8B40, 0x5A62, 0xE6BE, 0x5A63, 0x8B41, 0x5A64, 0x8B42, 0x5A65, 0x8B43, 0x5A66, 0x8B44, 0x5A67, 0xE6BA, 0x5A68, 0x8B45, 0x5A69, 0x8B46, 0x5A6A, 0xC0B7, 0x5A6B, 0x8B47, 0x5A6C, 0x8B48, 0x5A6D, 0x8B49, 0x5A6E, 0x8B4A, 0x5A6F, 0x8B4B, 0x5A70, 0x8B4C, 0x5A71, 0x8B4D, 0x5A72, 0x8B4E, 0x5A73, 0x8B4F, 0x5A74, 0xD3A4, 0x5A75, 0xE6BF, 0x5A76, 0xC9F4, 0x5A77, 0xE6C3, 0x5A78, 0x8B50, 0x5A79, 0x8B51, 0x5A7A, 0xE6C4, 0x5A7B, 0x8B52, 0x5A7C, 0x8B53, 0x5A7D, 0x8B54, 0x5A7E, 0x8B55, 0x5A7F, 0xD0F6, 0x5A80, 0x8B56, 0x5A81, 0x8B57, 0x5A82, 0x8B58, 0x5A83, 0x8B59, 0x5A84, 0x8B5A, 0x5A85, 0x8B5B, 0x5A86, 0x8B5C, 0x5A87, 0x8B5D, 0x5A88, 0x8B5E, 0x5A89, 0x8B5F, 0x5A8A, 0x8B60, 0x5A8B, 0x8B61, 0x5A8C, 0x8B62, 0x5A8D, 0x8B63, 0x5A8E, 0x8B64, 0x5A8F, 0x8B65, 0x5A90, 0x8B66, 0x5A91, 0x8B67, 0x5A92, 0xC3BD, 0x5A93, 0x8B68, 0x5A94, 0x8B69, 0x5A95, 0x8B6A, 0x5A96, 0x8B6B, 0x5A97, 0x8B6C, 0x5A98, 0x8B6D, 0x5A99, 0x8B6E, 0x5A9A, 0xC3C4, 0x5A9B, 0xE6C2, 0x5A9C, 0x8B6F, 0x5A9D, 0x8B70, 0x5A9E, 0x8B71, 0x5A9F, 0x8B72, 0x5AA0, 0x8B73, 0x5AA1, 0x8B74, 0x5AA2, 0x8B75, 0x5AA3, 0x8B76, 0x5AA4, 0x8B77, 0x5AA5, 0x8B78, 0x5AA6, 0x8B79, 0x5AA7, 0x8B7A, 0x5AA8, 0x8B7B, 0x5AA9, 0x8B7C, 0x5AAA, 0xE6C1, 0x5AAB, 0x8B7D, 0x5AAC, 0x8B7E, 0x5AAD, 0x8B80, 0x5AAE, 0x8B81, 0x5AAF, 0x8B82, 0x5AB0, 0x8B83, 0x5AB1, 0x8B84, 0x5AB2, 0xE6C7, 0x5AB3, 0xCFB1, 0x5AB4, 0x8B85, 0x5AB5, 0xEBF4, 0x5AB6, 0x8B86, 0x5AB7, 0x8B87, 0x5AB8, 0xE6CA, 0x5AB9, 0x8B88, 0x5ABA, 0x8B89, 0x5ABB, 0x8B8A, 0x5ABC, 0x8B8B, 0x5ABD, 0x8B8C, 0x5ABE, 0xE6C5, 0x5ABF, 0x8B8D, 0x5AC0, 0x8B8E, 0x5AC1, 0xBCDE, 0x5AC2, 0xC9A9, 0x5AC3, 0x8B8F, 0x5AC4, 0x8B90, 0x5AC5, 0x8B91, 0x5AC6, 0x8B92, 0x5AC7, 0x8B93, 0x5AC8, 0x8B94, 0x5AC9, 0xBCB5, 0x5ACA, 0x8B95, 0x5ACB, 0x8B96, 0x5ACC, 0xCFD3, 0x5ACD, 0x8B97, 0x5ACE, 0x8B98, 0x5ACF, 0x8B99, 0x5AD0, 0x8B9A, 0x5AD1, 0x8B9B, 0x5AD2, 0xE6C8, 0x5AD3, 0x8B9C, 0x5AD4, 0xE6C9, 0x5AD5, 0x8B9D, 0x5AD6, 0xE6CE, 0x5AD7, 0x8B9E, 0x5AD8, 0xE6D0, 0x5AD9, 0x8B9F, 0x5ADA, 0x8BA0, 0x5ADB, 0x8BA1, 0x5ADC, 0xE6D1, 0x5ADD, 0x8BA2, 0x5ADE, 0x8BA3, 0x5ADF, 0x8BA4, 0x5AE0, 0xE6CB, 0x5AE1, 0xB5D5, 0x5AE2, 0x8BA5, 0x5AE3, 0xE6CC, 0x5AE4, 0x8BA6, 0x5AE5, 0x8BA7, 0x5AE6, 0xE6CF, 0x5AE7, 0x8BA8, 0x5AE8, 0x8BA9, 0x5AE9, 0xC4DB, 0x5AEA, 0x8BAA, 0x5AEB, 0xE6C6, 0x5AEC, 0x8BAB, 0x5AED, 0x8BAC, 0x5AEE, 0x8BAD, 0x5AEF, 0x8BAE, 0x5AF0, 0x8BAF, 0x5AF1, 0xE6CD, 0x5AF2, 0x8BB0, 0x5AF3, 0x8BB1, 0x5AF4, 0x8BB2, 0x5AF5, 0x8BB3, 0x5AF6, 0x8BB4, 0x5AF7, 0x8BB5, 0x5AF8, 0x8BB6, 0x5AF9, 0x8BB7, 0x5AFA, 0x8BB8, 0x5AFB, 0x8BB9, 0x5AFC, 0x8BBA, 0x5AFD, 0x8BBB, 0x5AFE, 0x8BBC, 0x5AFF, 0x8BBD, 0x5B00, 0x8BBE, 0x5B01, 0x8BBF, 0x5B02, 0x8BC0, 0x5B03, 0x8BC1, 0x5B04, 0x8BC2, 0x5B05, 0x8BC3, 0x5B06, 0x8BC4, 0x5B07, 0x8BC5, 0x5B08, 0x8BC6, 0x5B09, 0xE6D2, 0x5B0A, 0x8BC7, 0x5B0B, 0x8BC8, 0x5B0C, 0x8BC9, 0x5B0D, 0x8BCA, 0x5B0E, 0x8BCB, 0x5B0F, 0x8BCC, 0x5B10, 0x8BCD, 0x5B11, 0x8BCE, 0x5B12, 0x8BCF, 0x5B13, 0x8BD0, 0x5B14, 0x8BD1, 0x5B15, 0x8BD2, 0x5B16, 0xE6D4, 0x5B17, 0xE6D3, 0x5B18, 0x8BD3, 0x5B19, 0x8BD4, 0x5B1A, 0x8BD5, 0x5B1B, 0x8BD6, 0x5B1C, 0x8BD7, 0x5B1D, 0x8BD8, 0x5B1E, 0x8BD9, 0x5B1F, 0x8BDA, 0x5B20, 0x8BDB, 0x5B21, 0x8BDC, 0x5B22, 0x8BDD, 0x5B23, 0x8BDE, 0x5B24, 0x8BDF, 0x5B25, 0x8BE0, 0x5B26, 0x8BE1, 0x5B27, 0x8BE2, 0x5B28, 0x8BE3, 0x5B29, 0x8BE4, 0x5B2A, 0x8BE5, 0x5B2B, 0x8BE6, 0x5B2C, 0x8BE7, 0x5B2D, 0x8BE8, 0x5B2E, 0x8BE9, 0x5B2F, 0x8BEA, 0x5B30, 0x8BEB, 0x5B31, 0x8BEC, 0x5B32, 0xE6D5, 0x5B33, 0x8BED, 0x5B34, 0xD9F8, 0x5B35, 0x8BEE, 0x5B36, 0x8BEF, 0x5B37, 0xE6D6, 0x5B38, 0x8BF0, 0x5B39, 0x8BF1, 0x5B3A, 0x8BF2, 0x5B3B, 0x8BF3, 0x5B3C, 0x8BF4, 0x5B3D, 0x8BF5, 0x5B3E, 0x8BF6, 0x5B3F, 0x8BF7, 0x5B40, 0xE6D7, 0x5B41, 0x8BF8, 0x5B42, 0x8BF9, 0x5B43, 0x8BFA, 0x5B44, 0x8BFB, 0x5B45, 0x8BFC, 0x5B46, 0x8BFD, 0x5B47, 0x8BFE, 0x5B48, 0x8C40, 0x5B49, 0x8C41, 0x5B4A, 0x8C42, 0x5B4B, 0x8C43, 0x5B4C, 0x8C44, 0x5B4D, 0x8C45, 0x5B4E, 0x8C46, 0x5B4F, 0x8C47, 0x5B50, 0xD7D3, 0x5B51, 0xE6DD, 0x5B52, 0x8C48, 0x5B53, 0xE6DE, 0x5B54, 0xBFD7, 0x5B55, 0xD4D0, 0x5B56, 0x8C49, 0x5B57, 0xD7D6, 0x5B58, 0xB4E6, 0x5B59, 0xCBEF, 0x5B5A, 0xE6DA, 0x5B5B, 0xD8C3, 0x5B5C, 0xD7CE, 0x5B5D, 0xD0A2, 0x5B5E, 0x8C4A, 0x5B5F, 0xC3CF, 0x5B60, 0x8C4B, 0x5B61, 0x8C4C, 0x5B62, 0xE6DF, 0x5B63, 0xBCBE, 0x5B64, 0xB9C2, 0x5B65, 0xE6DB, 0x5B66, 0xD1A7, 0x5B67, 0x8C4D, 0x5B68, 0x8C4E, 0x5B69, 0xBAA2, 0x5B6A, 0xC2CF, 0x5B6B, 0x8C4F, 0x5B6C, 0xD8AB, 0x5B6D, 0x8C50, 0x5B6E, 0x8C51, 0x5B6F, 0x8C52, 0x5B70, 0xCAEB, 0x5B71, 0xE5EE, 0x5B72, 0x8C53, 0x5B73, 0xE6DC, 0x5B74, 0x8C54, 0x5B75, 0xB7F5, 0x5B76, 0x8C55, 0x5B77, 0x8C56, 0x5B78, 0x8C57, 0x5B79, 0x8C58, 0x5B7A, 0xC8E6, 0x5B7B, 0x8C59, 0x5B7C, 0x8C5A, 0x5B7D, 0xC4F5, 0x5B7E, 0x8C5B, 0x5B7F, 0x8C5C, 0x5B80, 0xE5B2, 0x5B81, 0xC4FE, 0x5B82, 0x8C5D, 0x5B83, 0xCBFC, 0x5B84, 0xE5B3, 0x5B85, 0xD5AC, 0x5B86, 0x8C5E, 0x5B87, 0xD3EE, 0x5B88, 0xCAD8, 0x5B89, 0xB0B2, 0x5B8A, 0x8C5F, 0x5B8B, 0xCBCE, 0x5B8C, 0xCDEA, 0x5B8D, 0x8C60, 0x5B8E, 0x8C61, 0x5B8F, 0xBAEA, 0x5B90, 0x8C62, 0x5B91, 0x8C63, 0x5B92, 0x8C64, 0x5B93, 0xE5B5, 0x5B94, 0x8C65, 0x5B95, 0xE5B4, 0x5B96, 0x8C66, 0x5B97, 0xD7DA, 0x5B98, 0xB9D9, 0x5B99, 0xD6E6, 0x5B9A, 0xB6A8, 0x5B9B, 0xCDF0, 0x5B9C, 0xD2CB, 0x5B9D, 0xB1A6, 0x5B9E, 0xCAB5, 0x5B9F, 0x8C67, 0x5BA0, 0xB3E8, 0x5BA1, 0xC9F3, 0x5BA2, 0xBFCD, 0x5BA3, 0xD0FB, 0x5BA4, 0xCAD2, 0x5BA5, 0xE5B6, 0x5BA6, 0xBBC2, 0x5BA7, 0x8C68, 0x5BA8, 0x8C69, 0x5BA9, 0x8C6A, 0x5BAA, 0xCFDC, 0x5BAB, 0xB9AC, 0x5BAC, 0x8C6B, 0x5BAD, 0x8C6C, 0x5BAE, 0x8C6D, 0x5BAF, 0x8C6E, 0x5BB0, 0xD4D7, 0x5BB1, 0x8C6F, 0x5BB2, 0x8C70, 0x5BB3, 0xBAA6, 0x5BB4, 0xD1E7, 0x5BB5, 0xCFFC, 0x5BB6, 0xBCD2, 0x5BB7, 0x8C71, 0x5BB8, 0xE5B7, 0x5BB9, 0xC8DD, 0x5BBA, 0x8C72, 0x5BBB, 0x8C73, 0x5BBC, 0x8C74, 0x5BBD, 0xBFED, 0x5BBE, 0xB1F6, 0x5BBF, 0xCBDE, 0x5BC0, 0x8C75, 0x5BC1, 0x8C76, 0x5BC2, 0xBCC5, 0x5BC3, 0x8C77, 0x5BC4, 0xBCC4, 0x5BC5, 0xD2FA, 0x5BC6, 0xC3DC, 0x5BC7, 0xBFDC, 0x5BC8, 0x8C78, 0x5BC9, 0x8C79, 0x5BCA, 0x8C7A, 0x5BCB, 0x8C7B, 0x5BCC, 0xB8BB, 0x5BCD, 0x8C7C, 0x5BCE, 0x8C7D, 0x5BCF, 0x8C7E, 0x5BD0, 0xC3C2, 0x5BD1, 0x8C80, 0x5BD2, 0xBAAE, 0x5BD3, 0xD4A2, 0x5BD4, 0x8C81, 0x5BD5, 0x8C82, 0x5BD6, 0x8C83, 0x5BD7, 0x8C84, 0x5BD8, 0x8C85, 0x5BD9, 0x8C86, 0x5BDA, 0x8C87, 0x5BDB, 0x8C88, 0x5BDC, 0x8C89, 0x5BDD, 0xC7DE, 0x5BDE, 0xC4AF, 0x5BDF, 0xB2EC, 0x5BE0, 0x8C8A, 0x5BE1, 0xB9D1, 0x5BE2, 0x8C8B, 0x5BE3, 0x8C8C, 0x5BE4, 0xE5BB, 0x5BE5, 0xC1C8, 0x5BE6, 0x8C8D, 0x5BE7, 0x8C8E, 0x5BE8, 0xD5AF, 0x5BE9, 0x8C8F, 0x5BEA, 0x8C90, 0x5BEB, 0x8C91, 0x5BEC, 0x8C92, 0x5BED, 0x8C93, 0x5BEE, 0xE5BC, 0x5BEF, 0x8C94, 0x5BF0, 0xE5BE, 0x5BF1, 0x8C95, 0x5BF2, 0x8C96, 0x5BF3, 0x8C97, 0x5BF4, 0x8C98, 0x5BF5, 0x8C99, 0x5BF6, 0x8C9A, 0x5BF7, 0x8C9B, 0x5BF8, 0xB4E7, 0x5BF9, 0xB6D4, 0x5BFA, 0xCBC2, 0x5BFB, 0xD1B0, 0x5BFC, 0xB5BC, 0x5BFD, 0x8C9C, 0x5BFE, 0x8C9D, 0x5BFF, 0xCAD9, 0x5C00, 0x8C9E, 0x5C01, 0xB7E2, 0x5C02, 0x8C9F, 0x5C03, 0x8CA0, 0x5C04, 0xC9E4, 0x5C05, 0x8CA1, 0x5C06, 0xBDAB, 0x5C07, 0x8CA2, 0x5C08, 0x8CA3, 0x5C09, 0xCEBE, 0x5C0A, 0xD7F0, 0x5C0B, 0x8CA4, 0x5C0C, 0x8CA5, 0x5C0D, 0x8CA6, 0x5C0E, 0x8CA7, 0x5C0F, 0xD0A1, 0x5C10, 0x8CA8, 0x5C11, 0xC9D9, 0x5C12, 0x8CA9, 0x5C13, 0x8CAA, 0x5C14, 0xB6FB, 0x5C15, 0xE6D8, 0x5C16, 0xBCE2, 0x5C17, 0x8CAB, 0x5C18, 0xB3BE, 0x5C19, 0x8CAC, 0x5C1A, 0xC9D0, 0x5C1B, 0x8CAD, 0x5C1C, 0xE6D9, 0x5C1D, 0xB3A2, 0x5C1E, 0x8CAE, 0x5C1F, 0x8CAF, 0x5C20, 0x8CB0, 0x5C21, 0x8CB1, 0x5C22, 0xDECC, 0x5C23, 0x8CB2, 0x5C24, 0xD3C8, 0x5C25, 0xDECD, 0x5C26, 0x8CB3, 0x5C27, 0xD2A2, 0x5C28, 0x8CB4, 0x5C29, 0x8CB5, 0x5C2A, 0x8CB6, 0x5C2B, 0x8CB7, 0x5C2C, 0xDECE, 0x5C2D, 0x8CB8, 0x5C2E, 0x8CB9, 0x5C2F, 0x8CBA, 0x5C30, 0x8CBB, 0x5C31, 0xBECD, 0x5C32, 0x8CBC, 0x5C33, 0x8CBD, 0x5C34, 0xDECF, 0x5C35, 0x8CBE, 0x5C36, 0x8CBF, 0x5C37, 0x8CC0, 0x5C38, 0xCAAC, 0x5C39, 0xD2FC, 0x5C3A, 0xB3DF, 0x5C3B, 0xE5EA, 0x5C3C, 0xC4E1, 0x5C3D, 0xBEA1, 0x5C3E, 0xCEB2, 0x5C3F, 0xC4F2, 0x5C40, 0xBED6, 0x5C41, 0xC6A8, 0x5C42, 0xB2E3, 0x5C43, 0x8CC1, 0x5C44, 0x8CC2, 0x5C45, 0xBED3, 0x5C46, 0x8CC3, 0x5C47, 0x8CC4, 0x5C48, 0xC7FC, 0x5C49, 0xCCEB, 0x5C4A, 0xBDEC, 0x5C4B, 0xCEDD, 0x5C4C, 0x8CC5, 0x5C4D, 0x8CC6, 0x5C4E, 0xCABA, 0x5C4F, 0xC6C1, 0x5C50, 0xE5EC, 0x5C51, 0xD0BC, 0x5C52, 0x8CC7, 0x5C53, 0x8CC8, 0x5C54, 0x8CC9, 0x5C55, 0xD5B9, 0x5C56, 0x8CCA, 0x5C57, 0x8CCB, 0x5C58, 0x8CCC, 0x5C59, 0xE5ED, 0x5C5A, 0x8CCD, 0x5C5B, 0x8CCE, 0x5C5C, 0x8CCF, 0x5C5D, 0x8CD0, 0x5C5E, 0xCAF4, 0x5C5F, 0x8CD1, 0x5C60, 0xCDC0, 0x5C61, 0xC2C5, 0x5C62, 0x8CD2, 0x5C63, 0xE5EF, 0x5C64, 0x8CD3, 0x5C65, 0xC2C4, 0x5C66, 0xE5F0, 0x5C67, 0x8CD4, 0x5C68, 0x8CD5, 0x5C69, 0x8CD6, 0x5C6A, 0x8CD7, 0x5C6B, 0x8CD8, 0x5C6C, 0x8CD9, 0x5C6D, 0x8CDA, 0x5C6E, 0xE5F8, 0x5C6F, 0xCDCD, 0x5C70, 0x8CDB, 0x5C71, 0xC9BD, 0x5C72, 0x8CDC, 0x5C73, 0x8CDD, 0x5C74, 0x8CDE, 0x5C75, 0x8CDF, 0x5C76, 0x8CE0, 0x5C77, 0x8CE1, 0x5C78, 0x8CE2, 0x5C79, 0xD2D9, 0x5C7A, 0xE1A8, 0x5C7B, 0x8CE3, 0x5C7C, 0x8CE4, 0x5C7D, 0x8CE5, 0x5C7E, 0x8CE6, 0x5C7F, 0xD3EC, 0x5C80, 0x8CE7, 0x5C81, 0xCBEA, 0x5C82, 0xC6F1, 0x5C83, 0x8CE8, 0x5C84, 0x8CE9, 0x5C85, 0x8CEA, 0x5C86, 0x8CEB, 0x5C87, 0x8CEC, 0x5C88, 0xE1AC, 0x5C89, 0x8CED, 0x5C8A, 0x8CEE, 0x5C8B, 0x8CEF, 0x5C8C, 0xE1A7, 0x5C8D, 0xE1A9, 0x5C8E, 0x8CF0, 0x5C8F, 0x8CF1, 0x5C90, 0xE1AA, 0x5C91, 0xE1AF, 0x5C92, 0x8CF2, 0x5C93, 0x8CF3, 0x5C94, 0xB2ED, 0x5C95, 0x8CF4, 0x5C96, 0xE1AB, 0x5C97, 0xB8DA, 0x5C98, 0xE1AD, 0x5C99, 0xE1AE, 0x5C9A, 0xE1B0, 0x5C9B, 0xB5BA, 0x5C9C, 0xE1B1, 0x5C9D, 0x8CF5, 0x5C9E, 0x8CF6, 0x5C9F, 0x8CF7, 0x5CA0, 0x8CF8, 0x5CA1, 0x8CF9, 0x5CA2, 0xE1B3, 0x5CA3, 0xE1B8, 0x5CA4, 0x8CFA, 0x5CA5, 0x8CFB, 0x5CA6, 0x8CFC, 0x5CA7, 0x8CFD, 0x5CA8, 0x8CFE, 0x5CA9, 0xD1D2, 0x5CAA, 0x8D40, 0x5CAB, 0xE1B6, 0x5CAC, 0xE1B5, 0x5CAD, 0xC1EB, 0x5CAE, 0x8D41, 0x5CAF, 0x8D42, 0x5CB0, 0x8D43, 0x5CB1, 0xE1B7, 0x5CB2, 0x8D44, 0x5CB3, 0xD4C0, 0x5CB4, 0x8D45, 0x5CB5, 0xE1B2, 0x5CB6, 0x8D46, 0x5CB7, 0xE1BA, 0x5CB8, 0xB0B6, 0x5CB9, 0x8D47, 0x5CBA, 0x8D48, 0x5CBB, 0x8D49, 0x5CBC, 0x8D4A, 0x5CBD, 0xE1B4, 0x5CBE, 0x8D4B, 0x5CBF, 0xBFF9, 0x5CC0, 0x8D4C, 0x5CC1, 0xE1B9, 0x5CC2, 0x8D4D, 0x5CC3, 0x8D4E, 0x5CC4, 0xE1BB, 0x5CC5, 0x8D4F, 0x5CC6, 0x8D50, 0x5CC7, 0x8D51, 0x5CC8, 0x8D52, 0x5CC9, 0x8D53, 0x5CCA, 0x8D54, 0x5CCB, 0xE1BE, 0x5CCC, 0x8D55, 0x5CCD, 0x8D56, 0x5CCE, 0x8D57, 0x5CCF, 0x8D58, 0x5CD0, 0x8D59, 0x5CD1, 0x8D5A, 0x5CD2, 0xE1BC, 0x5CD3, 0x8D5B, 0x5CD4, 0x8D5C, 0x5CD5, 0x8D5D, 0x5CD6, 0x8D5E, 0x5CD7, 0x8D5F, 0x5CD8, 0x8D60, 0x5CD9, 0xD6C5, 0x5CDA, 0x8D61, 0x5CDB, 0x8D62, 0x5CDC, 0x8D63, 0x5CDD, 0x8D64, 0x5CDE, 0x8D65, 0x5CDF, 0x8D66, 0x5CE0, 0x8D67, 0x5CE1, 0xCFBF, 0x5CE2, 0x8D68, 0x5CE3, 0x8D69, 0x5CE4, 0xE1BD, 0x5CE5, 0xE1BF, 0x5CE6, 0xC2CD, 0x5CE7, 0x8D6A, 0x5CE8, 0xB6EB, 0x5CE9, 0x8D6B, 0x5CEA, 0xD3F8, 0x5CEB, 0x8D6C, 0x5CEC, 0x8D6D, 0x5CED, 0xC7CD, 0x5CEE, 0x8D6E, 0x5CEF, 0x8D6F, 0x5CF0, 0xB7E5, 0x5CF1, 0x8D70, 0x5CF2, 0x8D71, 0x5CF3, 0x8D72, 0x5CF4, 0x8D73, 0x5CF5, 0x8D74, 0x5CF6, 0x8D75, 0x5CF7, 0x8D76, 0x5CF8, 0x8D77, 0x5CF9, 0x8D78, 0x5CFA, 0x8D79, 0x5CFB, 0xBEFE, 0x5CFC, 0x8D7A, 0x5CFD, 0x8D7B, 0x5CFE, 0x8D7C, 0x5CFF, 0x8D7D, 0x5D00, 0x8D7E, 0x5D01, 0x8D80, 0x5D02, 0xE1C0, 0x5D03, 0xE1C1, 0x5D04, 0x8D81, 0x5D05, 0x8D82, 0x5D06, 0xE1C7, 0x5D07, 0xB3E7, 0x5D08, 0x8D83, 0x5D09, 0x8D84, 0x5D0A, 0x8D85, 0x5D0B, 0x8D86, 0x5D0C, 0x8D87, 0x5D0D, 0x8D88, 0x5D0E, 0xC6E9, 0x5D0F, 0x8D89, 0x5D10, 0x8D8A, 0x5D11, 0x8D8B, 0x5D12, 0x8D8C, 0x5D13, 0x8D8D, 0x5D14, 0xB4DE, 0x5D15, 0x8D8E, 0x5D16, 0xD1C2, 0x5D17, 0x8D8F, 0x5D18, 0x8D90, 0x5D19, 0x8D91, 0x5D1A, 0x8D92, 0x5D1B, 0xE1C8, 0x5D1C, 0x8D93, 0x5D1D, 0x8D94, 0x5D1E, 0xE1C6, 0x5D1F, 0x8D95, 0x5D20, 0x8D96, 0x5D21, 0x8D97, 0x5D22, 0x8D98, 0x5D23, 0x8D99, 0x5D24, 0xE1C5, 0x5D25, 0x8D9A, 0x5D26, 0xE1C3, 0x5D27, 0xE1C2, 0x5D28, 0x8D9B, 0x5D29, 0xB1C0, 0x5D2A, 0x8D9C, 0x5D2B, 0x8D9D, 0x5D2C, 0x8D9E, 0x5D2D, 0xD5B8, 0x5D2E, 0xE1C4, 0x5D2F, 0x8D9F, 0x5D30, 0x8DA0, 0x5D31, 0x8DA1, 0x5D32, 0x8DA2, 0x5D33, 0x8DA3, 0x5D34, 0xE1CB, 0x5D35, 0x8DA4, 0x5D36, 0x8DA5, 0x5D37, 0x8DA6, 0x5D38, 0x8DA7, 0x5D39, 0x8DA8, 0x5D3A, 0x8DA9, 0x5D3B, 0x8DAA, 0x5D3C, 0x8DAB, 0x5D3D, 0xE1CC, 0x5D3E, 0xE1CA, 0x5D3F, 0x8DAC, 0x5D40, 0x8DAD, 0x5D41, 0x8DAE, 0x5D42, 0x8DAF, 0x5D43, 0x8DB0, 0x5D44, 0x8DB1, 0x5D45, 0x8DB2, 0x5D46, 0x8DB3, 0x5D47, 0xEFFA, 0x5D48, 0x8DB4, 0x5D49, 0x8DB5, 0x5D4A, 0xE1D3, 0x5D4B, 0xE1D2, 0x5D4C, 0xC7B6, 0x5D4D, 0x8DB6, 0x5D4E, 0x8DB7, 0x5D4F, 0x8DB8, 0x5D50, 0x8DB9, 0x5D51, 0x8DBA, 0x5D52, 0x8DBB, 0x5D53, 0x8DBC, 0x5D54, 0x8DBD, 0x5D55, 0x8DBE, 0x5D56, 0x8DBF, 0x5D57, 0x8DC0, 0x5D58, 0xE1C9, 0x5D59, 0x8DC1, 0x5D5A, 0x8DC2, 0x5D5B, 0xE1CE, 0x5D5C, 0x8DC3, 0x5D5D, 0xE1D0, 0x5D5E, 0x8DC4, 0x5D5F, 0x8DC5, 0x5D60, 0x8DC6, 0x5D61, 0x8DC7, 0x5D62, 0x8DC8, 0x5D63, 0x8DC9, 0x5D64, 0x8DCA, 0x5D65, 0x8DCB, 0x5D66, 0x8DCC, 0x5D67, 0x8DCD, 0x5D68, 0x8DCE, 0x5D69, 0xE1D4, 0x5D6A, 0x8DCF, 0x5D6B, 0xE1D1, 0x5D6C, 0xE1CD, 0x5D6D, 0x8DD0, 0x5D6E, 0x8DD1, 0x5D6F, 0xE1CF, 0x5D70, 0x8DD2, 0x5D71, 0x8DD3, 0x5D72, 0x8DD4, 0x5D73, 0x8DD5, 0x5D74, 0xE1D5, 0x5D75, 0x8DD6, 0x5D76, 0x8DD7, 0x5D77, 0x8DD8, 0x5D78, 0x8DD9, 0x5D79, 0x8DDA, 0x5D7A, 0x8DDB, 0x5D7B, 0x8DDC, 0x5D7C, 0x8DDD, 0x5D7D, 0x8DDE, 0x5D7E, 0x8DDF, 0x5D7F, 0x8DE0, 0x5D80, 0x8DE1, 0x5D81, 0x8DE2, 0x5D82, 0xE1D6, 0x5D83, 0x8DE3, 0x5D84, 0x8DE4, 0x5D85, 0x8DE5, 0x5D86, 0x8DE6, 0x5D87, 0x8DE7, 0x5D88, 0x8DE8, 0x5D89, 0x8DE9, 0x5D8A, 0x8DEA, 0x5D8B, 0x8DEB, 0x5D8C, 0x8DEC, 0x5D8D, 0x8DED, 0x5D8E, 0x8DEE, 0x5D8F, 0x8DEF, 0x5D90, 0x8DF0, 0x5D91, 0x8DF1, 0x5D92, 0x8DF2, 0x5D93, 0x8DF3, 0x5D94, 0x8DF4, 0x5D95, 0x8DF5, 0x5D96, 0x8DF6, 0x5D97, 0x8DF7, 0x5D98, 0x8DF8, 0x5D99, 0xE1D7, 0x5D9A, 0x8DF9, 0x5D9B, 0x8DFA, 0x5D9C, 0x8DFB, 0x5D9D, 0xE1D8, 0x5D9E, 0x8DFC, 0x5D9F, 0x8DFD, 0x5DA0, 0x8DFE, 0x5DA1, 0x8E40, 0x5DA2, 0x8E41, 0x5DA3, 0x8E42, 0x5DA4, 0x8E43, 0x5DA5, 0x8E44, 0x5DA6, 0x8E45, 0x5DA7, 0x8E46, 0x5DA8, 0x8E47, 0x5DA9, 0x8E48, 0x5DAA, 0x8E49, 0x5DAB, 0x8E4A, 0x5DAC, 0x8E4B, 0x5DAD, 0x8E4C, 0x5DAE, 0x8E4D, 0x5DAF, 0x8E4E, 0x5DB0, 0x8E4F, 0x5DB1, 0x8E50, 0x5DB2, 0x8E51, 0x5DB3, 0x8E52, 0x5DB4, 0x8E53, 0x5DB5, 0x8E54, 0x5DB6, 0x8E55, 0x5DB7, 0xE1DA, 0x5DB8, 0x8E56, 0x5DB9, 0x8E57, 0x5DBA, 0x8E58, 0x5DBB, 0x8E59, 0x5DBC, 0x8E5A, 0x5DBD, 0x8E5B, 0x5DBE, 0x8E5C, 0x5DBF, 0x8E5D, 0x5DC0, 0x8E5E, 0x5DC1, 0x8E5F, 0x5DC2, 0x8E60, 0x5DC3, 0x8E61, 0x5DC4, 0x8E62, 0x5DC5, 0xE1DB, 0x5DC6, 0x8E63, 0x5DC7, 0x8E64, 0x5DC8, 0x8E65, 0x5DC9, 0x8E66, 0x5DCA, 0x8E67, 0x5DCB, 0x8E68, 0x5DCC, 0x8E69, 0x5DCD, 0xCEA1, 0x5DCE, 0x8E6A, 0x5DCF, 0x8E6B, 0x5DD0, 0x8E6C, 0x5DD1, 0x8E6D, 0x5DD2, 0x8E6E, 0x5DD3, 0x8E6F, 0x5DD4, 0x8E70, 0x5DD5, 0x8E71, 0x5DD6, 0x8E72, 0x5DD7, 0x8E73, 0x5DD8, 0x8E74, 0x5DD9, 0x8E75, 0x5DDA, 0x8E76, 0x5DDB, 0xE7DD, 0x5DDC, 0x8E77, 0x5DDD, 0xB4A8, 0x5DDE, 0xD6DD, 0x5DDF, 0x8E78, 0x5DE0, 0x8E79, 0x5DE1, 0xD1B2, 0x5DE2, 0xB3B2, 0x5DE3, 0x8E7A, 0x5DE4, 0x8E7B, 0x5DE5, 0xB9A4, 0x5DE6, 0xD7F3, 0x5DE7, 0xC7C9, 0x5DE8, 0xBEDE, 0x5DE9, 0xB9AE, 0x5DEA, 0x8E7C, 0x5DEB, 0xCED7, 0x5DEC, 0x8E7D, 0x5DED, 0x8E7E, 0x5DEE, 0xB2EE, 0x5DEF, 0xDBCF, 0x5DF0, 0x8E80, 0x5DF1, 0xBCBA, 0x5DF2, 0xD2D1, 0x5DF3, 0xCBC8, 0x5DF4, 0xB0CD, 0x5DF5, 0x8E81, 0x5DF6, 0x8E82, 0x5DF7, 0xCFEF, 0x5DF8, 0x8E83, 0x5DF9, 0x8E84, 0x5DFA, 0x8E85, 0x5DFB, 0x8E86, 0x5DFC, 0x8E87, 0x5DFD, 0xD9E3, 0x5DFE, 0xBDED, 0x5DFF, 0x8E88, 0x5E00, 0x8E89, 0x5E01, 0xB1D2, 0x5E02, 0xCAD0, 0x5E03, 0xB2BC, 0x5E04, 0x8E8A, 0x5E05, 0xCBA7, 0x5E06, 0xB7AB, 0x5E07, 0x8E8B, 0x5E08, 0xCAA6, 0x5E09, 0x8E8C, 0x5E0A, 0x8E8D, 0x5E0B, 0x8E8E, 0x5E0C, 0xCFA3, 0x5E0D, 0x8E8F, 0x5E0E, 0x8E90, 0x5E0F, 0xE0F8, 0x5E10, 0xD5CA, 0x5E11, 0xE0FB, 0x5E12, 0x8E91, 0x5E13, 0x8E92, 0x5E14, 0xE0FA, 0x5E15, 0xC5C1, 0x5E16, 0xCCFB, 0x5E17, 0x8E93, 0x5E18, 0xC1B1, 0x5E19, 0xE0F9, 0x5E1A, 0xD6E3, 0x5E1B, 0xB2AF, 0x5E1C, 0xD6C4, 0x5E1D, 0xB5DB, 0x5E1E, 0x8E94, 0x5E1F, 0x8E95, 0x5E20, 0x8E96, 0x5E21, 0x8E97, 0x5E22, 0x8E98, 0x5E23, 0x8E99, 0x5E24, 0x8E9A, 0x5E25, 0x8E9B, 0x5E26, 0xB4F8, 0x5E27, 0xD6A1, 0x5E28, 0x8E9C, 0x5E29, 0x8E9D, 0x5E2A, 0x8E9E, 0x5E2B, 0x8E9F, 0x5E2C, 0x8EA0, 0x5E2D, 0xCFAF, 0x5E2E, 0xB0EF, 0x5E2F, 0x8EA1, 0x5E30, 0x8EA2, 0x5E31, 0xE0FC, 0x5E32, 0x8EA3, 0x5E33, 0x8EA4, 0x5E34, 0x8EA5, 0x5E35, 0x8EA6, 0x5E36, 0x8EA7, 0x5E37, 0xE1A1, 0x5E38, 0xB3A3, 0x5E39, 0x8EA8, 0x5E3A, 0x8EA9, 0x5E3B, 0xE0FD, 0x5E3C, 0xE0FE, 0x5E3D, 0xC3B1, 0x5E3E, 0x8EAA, 0x5E3F, 0x8EAB, 0x5E40, 0x8EAC, 0x5E41, 0x8EAD, 0x5E42, 0xC3DD, 0x5E43, 0x8EAE, 0x5E44, 0xE1A2, 0x5E45, 0xB7F9, 0x5E46, 0x8EAF, 0x5E47, 0x8EB0, 0x5E48, 0x8EB1, 0x5E49, 0x8EB2, 0x5E4A, 0x8EB3, 0x5E4B, 0x8EB4, 0x5E4C, 0xBBCF, 0x5E4D, 0x8EB5, 0x5E4E, 0x8EB6, 0x5E4F, 0x8EB7, 0x5E50, 0x8EB8, 0x5E51, 0x8EB9, 0x5E52, 0x8EBA, 0x5E53, 0x8EBB, 0x5E54, 0xE1A3, 0x5E55, 0xC4BB, 0x5E56, 0x8EBC, 0x5E57, 0x8EBD, 0x5E58, 0x8EBE, 0x5E59, 0x8EBF, 0x5E5A, 0x8EC0, 0x5E5B, 0xE1A4, 0x5E5C, 0x8EC1, 0x5E5D, 0x8EC2, 0x5E5E, 0xE1A5, 0x5E5F, 0x8EC3, 0x5E60, 0x8EC4, 0x5E61, 0xE1A6, 0x5E62, 0xB4B1, 0x5E63, 0x8EC5, 0x5E64, 0x8EC6, 0x5E65, 0x8EC7, 0x5E66, 0x8EC8, 0x5E67, 0x8EC9, 0x5E68, 0x8ECA, 0x5E69, 0x8ECB, 0x5E6A, 0x8ECC, 0x5E6B, 0x8ECD, 0x5E6C, 0x8ECE, 0x5E6D, 0x8ECF, 0x5E6E, 0x8ED0, 0x5E6F, 0x8ED1, 0x5E70, 0x8ED2, 0x5E71, 0x8ED3, 0x5E72, 0xB8C9, 0x5E73, 0xC6BD, 0x5E74, 0xC4EA, 0x5E75, 0x8ED4, 0x5E76, 0xB2A2, 0x5E77, 0x8ED5, 0x5E78, 0xD0D2, 0x5E79, 0x8ED6, 0x5E7A, 0xE7DB, 0x5E7B, 0xBBC3, 0x5E7C, 0xD3D7, 0x5E7D, 0xD3C4, 0x5E7E, 0x8ED7, 0x5E7F, 0xB9E3, 0x5E80, 0xE2CF, 0x5E81, 0x8ED8, 0x5E82, 0x8ED9, 0x5E83, 0x8EDA, 0x5E84, 0xD7AF, 0x5E85, 0x8EDB, 0x5E86, 0xC7EC, 0x5E87, 0xB1D3, 0x5E88, 0x8EDC, 0x5E89, 0x8EDD, 0x5E8A, 0xB4B2, 0x5E8B, 0xE2D1, 0x5E8C, 0x8EDE, 0x5E8D, 0x8EDF, 0x5E8E, 0x8EE0, 0x5E8F, 0xD0F2, 0x5E90, 0xC2AE, 0x5E91, 0xE2D0, 0x5E92, 0x8EE1, 0x5E93, 0xBFE2, 0x5E94, 0xD3A6, 0x5E95, 0xB5D7, 0x5E96, 0xE2D2, 0x5E97, 0xB5EA, 0x5E98, 0x8EE2, 0x5E99, 0xC3ED, 0x5E9A, 0xB8FD, 0x5E9B, 0x8EE3, 0x5E9C, 0xB8AE, 0x5E9D, 0x8EE4, 0x5E9E, 0xC5D3, 0x5E9F, 0xB7CF, 0x5EA0, 0xE2D4, 0x5EA1, 0x8EE5, 0x5EA2, 0x8EE6, 0x5EA3, 0x8EE7, 0x5EA4, 0x8EE8, 0x5EA5, 0xE2D3, 0x5EA6, 0xB6C8, 0x5EA7, 0xD7F9, 0x5EA8, 0x8EE9, 0x5EA9, 0x8EEA, 0x5EAA, 0x8EEB, 0x5EAB, 0x8EEC, 0x5EAC, 0x8EED, 0x5EAD, 0xCDA5, 0x5EAE, 0x8EEE, 0x5EAF, 0x8EEF, 0x5EB0, 0x8EF0, 0x5EB1, 0x8EF1, 0x5EB2, 0x8EF2, 0x5EB3, 0xE2D8, 0x5EB4, 0x8EF3, 0x5EB5, 0xE2D6, 0x5EB6, 0xCAFC, 0x5EB7, 0xBFB5, 0x5EB8, 0xD3B9, 0x5EB9, 0xE2D5, 0x5EBA, 0x8EF4, 0x5EBB, 0x8EF5, 0x5EBC, 0x8EF6, 0x5EBD, 0x8EF7, 0x5EBE, 0xE2D7, 0x5EBF, 0x8EF8, 0x5EC0, 0x8EF9, 0x5EC1, 0x8EFA, 0x5EC2, 0x8EFB, 0x5EC3, 0x8EFC, 0x5EC4, 0x8EFD, 0x5EC5, 0x8EFE, 0x5EC6, 0x8F40, 0x5EC7, 0x8F41, 0x5EC8, 0x8F42, 0x5EC9, 0xC1AE, 0x5ECA, 0xC0C8, 0x5ECB, 0x8F43, 0x5ECC, 0x8F44, 0x5ECD, 0x8F45, 0x5ECE, 0x8F46, 0x5ECF, 0x8F47, 0x5ED0, 0x8F48, 0x5ED1, 0xE2DB, 0x5ED2, 0xE2DA, 0x5ED3, 0xC0AA, 0x5ED4, 0x8F49, 0x5ED5, 0x8F4A, 0x5ED6, 0xC1CE, 0x5ED7, 0x8F4B, 0x5ED8, 0x8F4C, 0x5ED9, 0x8F4D, 0x5EDA, 0x8F4E, 0x5EDB, 0xE2DC, 0x5EDC, 0x8F4F, 0x5EDD, 0x8F50, 0x5EDE, 0x8F51, 0x5EDF, 0x8F52, 0x5EE0, 0x8F53, 0x5EE1, 0x8F54, 0x5EE2, 0x8F55, 0x5EE3, 0x8F56, 0x5EE4, 0x8F57, 0x5EE5, 0x8F58, 0x5EE6, 0x8F59, 0x5EE7, 0x8F5A, 0x5EE8, 0xE2DD, 0x5EE9, 0x8F5B, 0x5EEA, 0xE2DE, 0x5EEB, 0x8F5C, 0x5EEC, 0x8F5D, 0x5EED, 0x8F5E, 0x5EEE, 0x8F5F, 0x5EEF, 0x8F60, 0x5EF0, 0x8F61, 0x5EF1, 0x8F62, 0x5EF2, 0x8F63, 0x5EF3, 0x8F64, 0x5EF4, 0xDBC8, 0x5EF5, 0x8F65, 0x5EF6, 0xD1D3, 0x5EF7, 0xCDA2, 0x5EF8, 0x8F66, 0x5EF9, 0x8F67, 0x5EFA, 0xBDA8, 0x5EFB, 0x8F68, 0x5EFC, 0x8F69, 0x5EFD, 0x8F6A, 0x5EFE, 0xDEC3, 0x5EFF, 0xD8A5, 0x5F00, 0xBFAA, 0x5F01, 0xDBCD, 0x5F02, 0xD2EC, 0x5F03, 0xC6FA, 0x5F04, 0xC5AA, 0x5F05, 0x8F6B, 0x5F06, 0x8F6C, 0x5F07, 0x8F6D, 0x5F08, 0xDEC4, 0x5F09, 0x8F6E, 0x5F0A, 0xB1D7, 0x5F0B, 0xDFAE, 0x5F0C, 0x8F6F, 0x5F0D, 0x8F70, 0x5F0E, 0x8F71, 0x5F0F, 0xCABD, 0x5F10, 0x8F72, 0x5F11, 0xDFB1, 0x5F12, 0x8F73, 0x5F13, 0xB9AD, 0x5F14, 0x8F74, 0x5F15, 0xD2FD, 0x5F16, 0x8F75, 0x5F17, 0xB8A5, 0x5F18, 0xBAEB, 0x5F19, 0x8F76, 0x5F1A, 0x8F77, 0x5F1B, 0xB3DA, 0x5F1C, 0x8F78, 0x5F1D, 0x8F79, 0x5F1E, 0x8F7A, 0x5F1F, 0xB5DC, 0x5F20, 0xD5C5, 0x5F21, 0x8F7B, 0x5F22, 0x8F7C, 0x5F23, 0x8F7D, 0x5F24, 0x8F7E, 0x5F25, 0xC3D6, 0x5F26, 0xCFD2, 0x5F27, 0xBBA1, 0x5F28, 0x8F80, 0x5F29, 0xE5F3, 0x5F2A, 0xE5F2, 0x5F2B, 0x8F81, 0x5F2C, 0x8F82, 0x5F2D, 0xE5F4, 0x5F2E, 0x8F83, 0x5F2F, 0xCDE4, 0x5F30, 0x8F84, 0x5F31, 0xC8F5, 0x5F32, 0x8F85, 0x5F33, 0x8F86, 0x5F34, 0x8F87, 0x5F35, 0x8F88, 0x5F36, 0x8F89, 0x5F37, 0x8F8A, 0x5F38, 0x8F8B, 0x5F39, 0xB5AF, 0x5F3A, 0xC7BF, 0x5F3B, 0x8F8C, 0x5F3C, 0xE5F6, 0x5F3D, 0x8F8D, 0x5F3E, 0x8F8E, 0x5F3F, 0x8F8F, 0x5F40, 0xECB0, 0x5F41, 0x8F90, 0x5F42, 0x8F91, 0x5F43, 0x8F92, 0x5F44, 0x8F93, 0x5F45, 0x8F94, 0x5F46, 0x8F95, 0x5F47, 0x8F96, 0x5F48, 0x8F97, 0x5F49, 0x8F98, 0x5F4A, 0x8F99, 0x5F4B, 0x8F9A, 0x5F4C, 0x8F9B, 0x5F4D, 0x8F9C, 0x5F4E, 0x8F9D, 0x5F4F, 0x8F9E, 0x5F50, 0xE5E6, 0x5F51, 0x8F9F, 0x5F52, 0xB9E9, 0x5F53, 0xB5B1, 0x5F54, 0x8FA0, 0x5F55, 0xC2BC, 0x5F56, 0xE5E8, 0x5F57, 0xE5E7, 0x5F58, 0xE5E9, 0x5F59, 0x8FA1, 0x5F5A, 0x8FA2, 0x5F5B, 0x8FA3, 0x5F5C, 0x8FA4, 0x5F5D, 0xD2CD, 0x5F5E, 0x8FA5, 0x5F5F, 0x8FA6, 0x5F60, 0x8FA7, 0x5F61, 0xE1EA, 0x5F62, 0xD0CE, 0x5F63, 0x8FA8, 0x5F64, 0xCDAE, 0x5F65, 0x8FA9, 0x5F66, 0xD1E5, 0x5F67, 0x8FAA, 0x5F68, 0x8FAB, 0x5F69, 0xB2CA, 0x5F6A, 0xB1EB, 0x5F6B, 0x8FAC, 0x5F6C, 0xB1F2, 0x5F6D, 0xC5ED, 0x5F6E, 0x8FAD, 0x5F6F, 0x8FAE, 0x5F70, 0xD5C3, 0x5F71, 0xD3B0, 0x5F72, 0x8FAF, 0x5F73, 0xE1DC, 0x5F74, 0x8FB0, 0x5F75, 0x8FB1, 0x5F76, 0x8FB2, 0x5F77, 0xE1DD, 0x5F78, 0x8FB3, 0x5F79, 0xD2DB, 0x5F7A, 0x8FB4, 0x5F7B, 0xB3B9, 0x5F7C, 0xB1CB, 0x5F7D, 0x8FB5, 0x5F7E, 0x8FB6, 0x5F7F, 0x8FB7, 0x5F80, 0xCDF9, 0x5F81, 0xD5F7, 0x5F82, 0xE1DE, 0x5F83, 0x8FB8, 0x5F84, 0xBEB6, 0x5F85, 0xB4FD, 0x5F86, 0x8FB9, 0x5F87, 0xE1DF, 0x5F88, 0xBADC, 0x5F89, 0xE1E0, 0x5F8A, 0xBBB2, 0x5F8B, 0xC2C9, 0x5F8C, 0xE1E1, 0x5F8D, 0x8FBA, 0x5F8E, 0x8FBB, 0x5F8F, 0x8FBC, 0x5F90, 0xD0EC, 0x5F91, 0x8FBD, 0x5F92, 0xCDBD, 0x5F93, 0x8FBE, 0x5F94, 0x8FBF, 0x5F95, 0xE1E2, 0x5F96, 0x8FC0, 0x5F97, 0xB5C3, 0x5F98, 0xC5C7, 0x5F99, 0xE1E3, 0x5F9A, 0x8FC1, 0x5F9B, 0x8FC2, 0x5F9C, 0xE1E4, 0x5F9D, 0x8FC3, 0x5F9E, 0x8FC4, 0x5F9F, 0x8FC5, 0x5FA0, 0x8FC6, 0x5FA1, 0xD3F9, 0x5FA2, 0x8FC7, 0x5FA3, 0x8FC8, 0x5FA4, 0x8FC9, 0x5FA5, 0x8FCA, 0x5FA6, 0x8FCB, 0x5FA7, 0x8FCC, 0x5FA8, 0xE1E5, 0x5FA9, 0x8FCD, 0x5FAA, 0xD1AD, 0x5FAB, 0x8FCE, 0x5FAC, 0x8FCF, 0x5FAD, 0xE1E6, 0x5FAE, 0xCEA2, 0x5FAF, 0x8FD0, 0x5FB0, 0x8FD1, 0x5FB1, 0x8FD2, 0x5FB2, 0x8FD3, 0x5FB3, 0x8FD4, 0x5FB4, 0x8FD5, 0x5FB5, 0xE1E7, 0x5FB6, 0x8FD6, 0x5FB7, 0xB5C2, 0x5FB8, 0x8FD7, 0x5FB9, 0x8FD8, 0x5FBA, 0x8FD9, 0x5FBB, 0x8FDA, 0x5FBC, 0xE1E8, 0x5FBD, 0xBBD5, 0x5FBE, 0x8FDB, 0x5FBF, 0x8FDC, 0x5FC0, 0x8FDD, 0x5FC1, 0x8FDE, 0x5FC2, 0x8FDF, 0x5FC3, 0xD0C4, 0x5FC4, 0xE2E0, 0x5FC5, 0xB1D8, 0x5FC6, 0xD2E4, 0x5FC7, 0x8FE0, 0x5FC8, 0x8FE1, 0x5FC9, 0xE2E1, 0x5FCA, 0x8FE2, 0x5FCB, 0x8FE3, 0x5FCC, 0xBCC9, 0x5FCD, 0xC8CC, 0x5FCE, 0x8FE4, 0x5FCF, 0xE2E3, 0x5FD0, 0xECFE, 0x5FD1, 0xECFD, 0x5FD2, 0xDFAF, 0x5FD3, 0x8FE5, 0x5FD4, 0x8FE6, 0x5FD5, 0x8FE7, 0x5FD6, 0xE2E2, 0x5FD7, 0xD6BE, 0x5FD8, 0xCDFC, 0x5FD9, 0xC3A6, 0x5FDA, 0x8FE8, 0x5FDB, 0x8FE9, 0x5FDC, 0x8FEA, 0x5FDD, 0xE3C3, 0x5FDE, 0x8FEB, 0x5FDF, 0x8FEC, 0x5FE0, 0xD6D2, 0x5FE1, 0xE2E7, 0x5FE2, 0x8FED, 0x5FE3, 0x8FEE, 0x5FE4, 0xE2E8, 0x5FE5, 0x8FEF, 0x5FE6, 0x8FF0, 0x5FE7, 0xD3C7, 0x5FE8, 0x8FF1, 0x5FE9, 0x8FF2, 0x5FEA, 0xE2EC, 0x5FEB, 0xBFEC, 0x5FEC, 0x8FF3, 0x5FED, 0xE2ED, 0x5FEE, 0xE2E5, 0x5FEF, 0x8FF4, 0x5FF0, 0x8FF5, 0x5FF1, 0xB3C0, 0x5FF2, 0x8FF6, 0x5FF3, 0x8FF7, 0x5FF4, 0x8FF8, 0x5FF5, 0xC4EE, 0x5FF6, 0x8FF9, 0x5FF7, 0x8FFA, 0x5FF8, 0xE2EE, 0x5FF9, 0x8FFB, 0x5FFA, 0x8FFC, 0x5FFB, 0xD0C3, 0x5FFC, 0x8FFD, 0x5FFD, 0xBAF6, 0x5FFE, 0xE2E9, 0x5FFF, 0xB7DE, 0x6000, 0xBBB3, 0x6001, 0xCCAC, 0x6002, 0xCBCB, 0x6003, 0xE2E4, 0x6004, 0xE2E6, 0x6005, 0xE2EA, 0x6006, 0xE2EB, 0x6007, 0x8FFE, 0x6008, 0x9040, 0x6009, 0x9041, 0x600A, 0xE2F7, 0x600B, 0x9042, 0x600C, 0x9043, 0x600D, 0xE2F4, 0x600E, 0xD4F5, 0x600F, 0xE2F3, 0x6010, 0x9044, 0x6011, 0x9045, 0x6012, 0xC5AD, 0x6013, 0x9046, 0x6014, 0xD5FA, 0x6015, 0xC5C2, 0x6016, 0xB2C0, 0x6017, 0x9047, 0x6018, 0x9048, 0x6019, 0xE2EF, 0x601A, 0x9049, 0x601B, 0xE2F2, 0x601C, 0xC1AF, 0x601D, 0xCBBC, 0x601E, 0x904A, 0x601F, 0x904B, 0x6020, 0xB5A1, 0x6021, 0xE2F9, 0x6022, 0x904C, 0x6023, 0x904D, 0x6024, 0x904E, 0x6025, 0xBCB1, 0x6026, 0xE2F1, 0x6027, 0xD0D4, 0x6028, 0xD4B9, 0x6029, 0xE2F5, 0x602A, 0xB9D6, 0x602B, 0xE2F6, 0x602C, 0x904F, 0x602D, 0x9050, 0x602E, 0x9051, 0x602F, 0xC7D3, 0x6030, 0x9052, 0x6031, 0x9053, 0x6032, 0x9054, 0x6033, 0x9055, 0x6034, 0x9056, 0x6035, 0xE2F0, 0x6036, 0x9057, 0x6037, 0x9058, 0x6038, 0x9059, 0x6039, 0x905A, 0x603A, 0x905B, 0x603B, 0xD7DC, 0x603C, 0xEDA1, 0x603D, 0x905C, 0x603E, 0x905D, 0x603F, 0xE2F8, 0x6040, 0x905E, 0x6041, 0xEDA5, 0x6042, 0xE2FE, 0x6043, 0xCAD1, 0x6044, 0x905F, 0x6045, 0x9060, 0x6046, 0x9061, 0x6047, 0x9062, 0x6048, 0x9063, 0x6049, 0x9064, 0x604A, 0x9065, 0x604B, 0xC1B5, 0x604C, 0x9066, 0x604D, 0xBBD0, 0x604E, 0x9067, 0x604F, 0x9068, 0x6050, 0xBFD6, 0x6051, 0x9069, 0x6052, 0xBAE3, 0x6053, 0x906A, 0x6054, 0x906B, 0x6055, 0xCBA1, 0x6056, 0x906C, 0x6057, 0x906D, 0x6058, 0x906E, 0x6059, 0xEDA6, 0x605A, 0xEDA3, 0x605B, 0x906F, 0x605C, 0x9070, 0x605D, 0xEDA2, 0x605E, 0x9071, 0x605F, 0x9072, 0x6060, 0x9073, 0x6061, 0x9074, 0x6062, 0xBBD6, 0x6063, 0xEDA7, 0x6064, 0xD0F4, 0x6065, 0x9075, 0x6066, 0x9076, 0x6067, 0xEDA4, 0x6068, 0xBADE, 0x6069, 0xB6F7, 0x606A, 0xE3A1, 0x606B, 0xB6B2, 0x606C, 0xCCF1, 0x606D, 0xB9A7, 0x606E, 0x9077, 0x606F, 0xCFA2, 0x6070, 0xC7A1, 0x6071, 0x9078, 0x6072, 0x9079, 0x6073, 0xBFD2, 0x6074, 0x907A, 0x6075, 0x907B, 0x6076, 0xB6F1, 0x6077, 0x907C, 0x6078, 0xE2FA, 0x6079, 0xE2FB, 0x607A, 0xE2FD, 0x607B, 0xE2FC, 0x607C, 0xC4D5, 0x607D, 0xE3A2, 0x607E, 0x907D, 0x607F, 0xD3C1, 0x6080, 0x907E, 0x6081, 0x9080, 0x6082, 0x9081, 0x6083, 0xE3A7, 0x6084, 0xC7C4, 0x6085, 0x9082, 0x6086, 0x9083, 0x6087, 0x9084, 0x6088, 0x9085, 0x6089, 0xCFA4, 0x608A, 0x9086, 0x608B, 0x9087, 0x608C, 0xE3A9, 0x608D, 0xBAB7, 0x608E, 0x9088, 0x608F, 0x9089, 0x6090, 0x908A, 0x6091, 0x908B, 0x6092, 0xE3A8, 0x6093, 0x908C, 0x6094, 0xBBDA, 0x6095, 0x908D, 0x6096, 0xE3A3, 0x6097, 0x908E, 0x6098, 0x908F, 0x6099, 0x9090, 0x609A, 0xE3A4, 0x609B, 0xE3AA, 0x609C, 0x9091, 0x609D, 0xE3A6, 0x609E, 0x9092, 0x609F, 0xCEF2, 0x60A0, 0xD3C6, 0x60A1, 0x9093, 0x60A2, 0x9094, 0x60A3, 0xBBBC, 0x60A4, 0x9095, 0x60A5, 0x9096, 0x60A6, 0xD4C3, 0x60A7, 0x9097, 0x60A8, 0xC4FA, 0x60A9, 0x9098, 0x60AA, 0x9099, 0x60AB, 0xEDA8, 0x60AC, 0xD0FC, 0x60AD, 0xE3A5, 0x60AE, 0x909A, 0x60AF, 0xC3F5, 0x60B0, 0x909B, 0x60B1, 0xE3AD, 0x60B2, 0xB1AF, 0x60B3, 0x909C, 0x60B4, 0xE3B2, 0x60B5, 0x909D, 0x60B6, 0x909E, 0x60B7, 0x909F, 0x60B8, 0xBCC2, 0x60B9, 0x90A0, 0x60BA, 0x90A1, 0x60BB, 0xE3AC, 0x60BC, 0xB5BF, 0x60BD, 0x90A2, 0x60BE, 0x90A3, 0x60BF, 0x90A4, 0x60C0, 0x90A5, 0x60C1, 0x90A6, 0x60C2, 0x90A7, 0x60C3, 0x90A8, 0x60C4, 0x90A9, 0x60C5, 0xC7E9, 0x60C6, 0xE3B0, 0x60C7, 0x90AA, 0x60C8, 0x90AB, 0x60C9, 0x90AC, 0x60CA, 0xBEAA, 0x60CB, 0xCDEF, 0x60CC, 0x90AD, 0x60CD, 0x90AE, 0x60CE, 0x90AF, 0x60CF, 0x90B0, 0x60D0, 0x90B1, 0x60D1, 0xBBF3, 0x60D2, 0x90B2, 0x60D3, 0x90B3, 0x60D4, 0x90B4, 0x60D5, 0xCCE8, 0x60D6, 0x90B5, 0x60D7, 0x90B6, 0x60D8, 0xE3AF, 0x60D9, 0x90B7, 0x60DA, 0xE3B1, 0x60DB, 0x90B8, 0x60DC, 0xCFA7, 0x60DD, 0xE3AE, 0x60DE, 0x90B9, 0x60DF, 0xCEA9, 0x60E0, 0xBBDD, 0x60E1, 0x90BA, 0x60E2, 0x90BB, 0x60E3, 0x90BC, 0x60E4, 0x90BD, 0x60E5, 0x90BE, 0x60E6, 0xB5EB, 0x60E7, 0xBEE5, 0x60E8, 0xB2D2, 0x60E9, 0xB3CD, 0x60EA, 0x90BF, 0x60EB, 0xB1B9, 0x60EC, 0xE3AB, 0x60ED, 0xB2D1, 0x60EE, 0xB5AC, 0x60EF, 0xB9DF, 0x60F0, 0xB6E8, 0x60F1, 0x90C0, 0x60F2, 0x90C1, 0x60F3, 0xCFEB, 0x60F4, 0xE3B7, 0x60F5, 0x90C2, 0x60F6, 0xBBCC, 0x60F7, 0x90C3, 0x60F8, 0x90C4, 0x60F9, 0xC8C7, 0x60FA, 0xD0CA, 0x60FB, 0x90C5, 0x60FC, 0x90C6, 0x60FD, 0x90C7, 0x60FE, 0x90C8, 0x60FF, 0x90C9, 0x6100, 0xE3B8, 0x6101, 0xB3EE, 0x6102, 0x90CA, 0x6103, 0x90CB, 0x6104, 0x90CC, 0x6105, 0x90CD, 0x6106, 0xEDA9, 0x6107, 0x90CE, 0x6108, 0xD3FA, 0x6109, 0xD3E4, 0x610A, 0x90CF, 0x610B, 0x90D0, 0x610C, 0x90D1, 0x610D, 0xEDAA, 0x610E, 0xE3B9, 0x610F, 0xD2E2, 0x6110, 0x90D2, 0x6111, 0x90D3, 0x6112, 0x90D4, 0x6113, 0x90D5, 0x6114, 0x90D6, 0x6115, 0xE3B5, 0x6116, 0x90D7, 0x6117, 0x90D8, 0x6118, 0x90D9, 0x6119, 0x90DA, 0x611A, 0xD3DE, 0x611B, 0x90DB, 0x611C, 0x90DC, 0x611D, 0x90DD, 0x611E, 0x90DE, 0x611F, 0xB8D0, 0x6120, 0xE3B3, 0x6121, 0x90DF, 0x6122, 0x90E0, 0x6123, 0xE3B6, 0x6124, 0xB7DF, 0x6125, 0x90E1, 0x6126, 0xE3B4, 0x6127, 0xC0A2, 0x6128, 0x90E2, 0x6129, 0x90E3, 0x612A, 0x90E4, 0x612B, 0xE3BA, 0x612C, 0x90E5, 0x612D, 0x90E6, 0x612E, 0x90E7, 0x612F, 0x90E8, 0x6130, 0x90E9, 0x6131, 0x90EA, 0x6132, 0x90EB, 0x6133, 0x90EC, 0x6134, 0x90ED, 0x6135, 0x90EE, 0x6136, 0x90EF, 0x6137, 0x90F0, 0x6138, 0x90F1, 0x6139, 0x90F2, 0x613A, 0x90F3, 0x613B, 0x90F4, 0x613C, 0x90F5, 0x613D, 0x90F6, 0x613E, 0x90F7, 0x613F, 0xD4B8, 0x6140, 0x90F8, 0x6141, 0x90F9, 0x6142, 0x90FA, 0x6143, 0x90FB, 0x6144, 0x90FC, 0x6145, 0x90FD, 0x6146, 0x90FE, 0x6147, 0x9140, 0x6148, 0xB4C8, 0x6149, 0x9141, 0x614A, 0xE3BB, 0x614B, 0x9142, 0x614C, 0xBBC5, 0x614D, 0x9143, 0x614E, 0xC9F7, 0x614F, 0x9144, 0x6150, 0x9145, 0x6151, 0xC9E5, 0x6152, 0x9146, 0x6153, 0x9147, 0x6154, 0x9148, 0x6155, 0xC4BD, 0x6156, 0x9149, 0x6157, 0x914A, 0x6158, 0x914B, 0x6159, 0x914C, 0x615A, 0x914D, 0x615B, 0x914E, 0x615C, 0x914F, 0x615D, 0xEDAB, 0x615E, 0x9150, 0x615F, 0x9151, 0x6160, 0x9152, 0x6161, 0x9153, 0x6162, 0xC2FD, 0x6163, 0x9154, 0x6164, 0x9155, 0x6165, 0x9156, 0x6166, 0x9157, 0x6167, 0xBBDB, 0x6168, 0xBFAE, 0x6169, 0x9158, 0x616A, 0x9159, 0x616B, 0x915A, 0x616C, 0x915B, 0x616D, 0x915C, 0x616E, 0x915D, 0x616F, 0x915E, 0x6170, 0xCEBF, 0x6171, 0x915F, 0x6172, 0x9160, 0x6173, 0x9161, 0x6174, 0x9162, 0x6175, 0xE3BC, 0x6176, 0x9163, 0x6177, 0xBFB6, 0x6178, 0x9164, 0x6179, 0x9165, 0x617A, 0x9166, 0x617B, 0x9167, 0x617C, 0x9168, 0x617D, 0x9169, 0x617E, 0x916A, 0x617F, 0x916B, 0x6180, 0x916C, 0x6181, 0x916D, 0x6182, 0x916E, 0x6183, 0x916F, 0x6184, 0x9170, 0x6185, 0x9171, 0x6186, 0x9172, 0x6187, 0x9173, 0x6188, 0x9174, 0x6189, 0x9175, 0x618A, 0x9176, 0x618B, 0xB1EF, 0x618C, 0x9177, 0x618D, 0x9178, 0x618E, 0xD4F7, 0x618F, 0x9179, 0x6190, 0x917A, 0x6191, 0x917B, 0x6192, 0x917C, 0x6193, 0x917D, 0x6194, 0xE3BE, 0x6195, 0x917E, 0x6196, 0x9180, 0x6197, 0x9181, 0x6198, 0x9182, 0x6199, 0x9183, 0x619A, 0x9184, 0x619B, 0x9185, 0x619C, 0x9186, 0x619D, 0xEDAD, 0x619E, 0x9187, 0x619F, 0x9188, 0x61A0, 0x9189, 0x61A1, 0x918A, 0x61A2, 0x918B, 0x61A3, 0x918C, 0x61A4, 0x918D, 0x61A5, 0x918E, 0x61A6, 0x918F, 0x61A7, 0xE3BF, 0x61A8, 0xBAA9, 0x61A9, 0xEDAC, 0x61AA, 0x9190, 0x61AB, 0x9191, 0x61AC, 0xE3BD, 0x61AD, 0x9192, 0x61AE, 0x9193, 0x61AF, 0x9194, 0x61B0, 0x9195, 0x61B1, 0x9196, 0x61B2, 0x9197, 0x61B3, 0x9198, 0x61B4, 0x9199, 0x61B5, 0x919A, 0x61B6, 0x919B, 0x61B7, 0xE3C0, 0x61B8, 0x919C, 0x61B9, 0x919D, 0x61BA, 0x919E, 0x61BB, 0x919F, 0x61BC, 0x91A0, 0x61BD, 0x91A1, 0x61BE, 0xBAB6, 0x61BF, 0x91A2, 0x61C0, 0x91A3, 0x61C1, 0x91A4, 0x61C2, 0xB6AE, 0x61C3, 0x91A5, 0x61C4, 0x91A6, 0x61C5, 0x91A7, 0x61C6, 0x91A8, 0x61C7, 0x91A9, 0x61C8, 0xD0B8, 0x61C9, 0x91AA, 0x61CA, 0xB0C3, 0x61CB, 0xEDAE, 0x61CC, 0x91AB, 0x61CD, 0x91AC, 0x61CE, 0x91AD, 0x61CF, 0x91AE, 0x61D0, 0x91AF, 0x61D1, 0xEDAF, 0x61D2, 0xC0C1, 0x61D3, 0x91B0, 0x61D4, 0xE3C1, 0x61D5, 0x91B1, 0x61D6, 0x91B2, 0x61D7, 0x91B3, 0x61D8, 0x91B4, 0x61D9, 0x91B5, 0x61DA, 0x91B6, 0x61DB, 0x91B7, 0x61DC, 0x91B8, 0x61DD, 0x91B9, 0x61DE, 0x91BA, 0x61DF, 0x91BB, 0x61E0, 0x91BC, 0x61E1, 0x91BD, 0x61E2, 0x91BE, 0x61E3, 0x91BF, 0x61E4, 0x91C0, 0x61E5, 0x91C1, 0x61E6, 0xC5B3, 0x61E7, 0x91C2, 0x61E8, 0x91C3, 0x61E9, 0x91C4, 0x61EA, 0x91C5, 0x61EB, 0x91C6, 0x61EC, 0x91C7, 0x61ED, 0x91C8, 0x61EE, 0x91C9, 0x61EF, 0x91CA, 0x61F0, 0x91CB, 0x61F1, 0x91CC, 0x61F2, 0x91CD, 0x61F3, 0x91CE, 0x61F4, 0x91CF, 0x61F5, 0xE3C2, 0x61F6, 0x91D0, 0x61F7, 0x91D1, 0x61F8, 0x91D2, 0x61F9, 0x91D3, 0x61FA, 0x91D4, 0x61FB, 0x91D5, 0x61FC, 0x91D6, 0x61FD, 0x91D7, 0x61FE, 0x91D8, 0x61FF, 0xDCB2, 0x6200, 0x91D9, 0x6201, 0x91DA, 0x6202, 0x91DB, 0x6203, 0x91DC, 0x6204, 0x91DD, 0x6205, 0x91DE, 0x6206, 0xEDB0, 0x6207, 0x91DF, 0x6208, 0xB8EA, 0x6209, 0x91E0, 0x620A, 0xCEEC, 0x620B, 0xEAA7, 0x620C, 0xD0E7, 0x620D, 0xCAF9, 0x620E, 0xC8D6, 0x620F, 0xCFB7, 0x6210, 0xB3C9, 0x6211, 0xCED2, 0x6212, 0xBDE4, 0x6213, 0x91E1, 0x6214, 0x91E2, 0x6215, 0xE3DE, 0x6216, 0xBBF2, 0x6217, 0xEAA8, 0x6218, 0xD5BD, 0x6219, 0x91E3, 0x621A, 0xC6DD, 0x621B, 0xEAA9, 0x621C, 0x91E4, 0x621D, 0x91E5, 0x621E, 0x91E6, 0x621F, 0xEAAA, 0x6220, 0x91E7, 0x6221, 0xEAAC, 0x6222, 0xEAAB, 0x6223, 0x91E8, 0x6224, 0xEAAE, 0x6225, 0xEAAD, 0x6226, 0x91E9, 0x6227, 0x91EA, 0x6228, 0x91EB, 0x6229, 0x91EC, 0x622A, 0xBDD8, 0x622B, 0x91ED, 0x622C, 0xEAAF, 0x622D, 0x91EE, 0x622E, 0xC2BE, 0x622F, 0x91EF, 0x6230, 0x91F0, 0x6231, 0x91F1, 0x6232, 0x91F2, 0x6233, 0xB4C1, 0x6234, 0xB4F7, 0x6235, 0x91F3, 0x6236, 0x91F4, 0x6237, 0xBBA7, 0x6238, 0x91F5, 0x6239, 0x91F6, 0x623A, 0x91F7, 0x623B, 0x91F8, 0x623C, 0x91F9, 0x623D, 0xECE6, 0x623E, 0xECE5, 0x623F, 0xB7BF, 0x6240, 0xCBF9, 0x6241, 0xB1E2, 0x6242, 0x91FA, 0x6243, 0xECE7, 0x6244, 0x91FB, 0x6245, 0x91FC, 0x6246, 0x91FD, 0x6247, 0xC9C8, 0x6248, 0xECE8, 0x6249, 0xECE9, 0x624A, 0x91FE, 0x624B, 0xCAD6, 0x624C, 0xDED0, 0x624D, 0xB2C5, 0x624E, 0xD4FA, 0x624F, 0x9240, 0x6250, 0x9241, 0x6251, 0xC6CB, 0x6252, 0xB0C7, 0x6253, 0xB4F2, 0x6254, 0xC8D3, 0x6255, 0x9242, 0x6256, 0x9243, 0x6257, 0x9244, 0x6258, 0xCDD0, 0x6259, 0x9245, 0x625A, 0x9246, 0x625B, 0xBFB8, 0x625C, 0x9247, 0x625D, 0x9248, 0x625E, 0x9249, 0x625F, 0x924A, 0x6260, 0x924B, 0x6261, 0x924C, 0x6262, 0x924D, 0x6263, 0xBFDB, 0x6264, 0x924E, 0x6265, 0x924F, 0x6266, 0xC7A4, 0x6267, 0xD6B4, 0x6268, 0x9250, 0x6269, 0xC0A9, 0x626A, 0xDED1, 0x626B, 0xC9A8, 0x626C, 0xD1EF, 0x626D, 0xC5A4, 0x626E, 0xB0E7, 0x626F, 0xB3B6, 0x6270, 0xC8C5, 0x6271, 0x9251, 0x6272, 0x9252, 0x6273, 0xB0E2, 0x6274, 0x9253, 0x6275, 0x9254, 0x6276, 0xB7F6, 0x6277, 0x9255, 0x6278, 0x9256, 0x6279, 0xC5FA, 0x627A, 0x9257, 0x627B, 0x9258, 0x627C, 0xB6F3, 0x627D, 0x9259, 0x627E, 0xD5D2, 0x627F, 0xB3D0, 0x6280, 0xBCBC, 0x6281, 0x925A, 0x6282, 0x925B, 0x6283, 0x925C, 0x6284, 0xB3AD, 0x6285, 0x925D, 0x6286, 0x925E, 0x6287, 0x925F, 0x6288, 0x9260, 0x6289, 0xBEF1, 0x628A, 0xB0D1, 0x628B, 0x9261, 0x628C, 0x9262, 0x628D, 0x9263, 0x628E, 0x9264, 0x628F, 0x9265, 0x6290, 0x9266, 0x6291, 0xD2D6, 0x6292, 0xCAE3, 0x6293, 0xD7A5, 0x6294, 0x9267, 0x6295, 0xCDB6, 0x6296, 0xB6B6, 0x6297, 0xBFB9, 0x6298, 0xD5DB, 0x6299, 0x9268, 0x629A, 0xB8A7, 0x629B, 0xC5D7, 0x629C, 0x9269, 0x629D, 0x926A, 0x629E, 0x926B, 0x629F, 0xDED2, 0x62A0, 0xBFD9, 0x62A1, 0xC2D5, 0x62A2, 0xC7C0, 0x62A3, 0x926C, 0x62A4, 0xBBA4, 0x62A5, 0xB1A8, 0x62A6, 0x926D, 0x62A7, 0x926E, 0x62A8, 0xC5EA, 0x62A9, 0x926F, 0x62AA, 0x9270, 0x62AB, 0xC5FB, 0x62AC, 0xCCA7, 0x62AD, 0x9271, 0x62AE, 0x9272, 0x62AF, 0x9273, 0x62B0, 0x9274, 0x62B1, 0xB1A7, 0x62B2, 0x9275, 0x62B3, 0x9276, 0x62B4, 0x9277, 0x62B5, 0xB5D6, 0x62B6, 0x9278, 0x62B7, 0x9279, 0x62B8, 0x927A, 0x62B9, 0xC4A8, 0x62BA, 0x927B, 0x62BB, 0xDED3, 0x62BC, 0xD1BA, 0x62BD, 0xB3E9, 0x62BE, 0x927C, 0x62BF, 0xC3F2, 0x62C0, 0x927D, 0x62C1, 0x927E, 0x62C2, 0xB7F7, 0x62C3, 0x9280, 0x62C4, 0xD6F4, 0x62C5, 0xB5A3, 0x62C6, 0xB2F0, 0x62C7, 0xC4B4, 0x62C8, 0xC4E9, 0x62C9, 0xC0AD, 0x62CA, 0xDED4, 0x62CB, 0x9281, 0x62CC, 0xB0E8, 0x62CD, 0xC5C4, 0x62CE, 0xC1E0, 0x62CF, 0x9282, 0x62D0, 0xB9D5, 0x62D1, 0x9283, 0x62D2, 0xBEDC, 0x62D3, 0xCDD8, 0x62D4, 0xB0CE, 0x62D5, 0x9284, 0x62D6, 0xCDCF, 0x62D7, 0xDED6, 0x62D8, 0xBED0, 0x62D9, 0xD7BE, 0x62DA, 0xDED5, 0x62DB, 0xD5D0, 0x62DC, 0xB0DD, 0x62DD, 0x9285, 0x62DE, 0x9286, 0x62DF, 0xC4E2, 0x62E0, 0x9287, 0x62E1, 0x9288, 0x62E2, 0xC2A3, 0x62E3, 0xBCF0, 0x62E4, 0x9289, 0x62E5, 0xD3B5, 0x62E6, 0xC0B9, 0x62E7, 0xC5A1, 0x62E8, 0xB2A6, 0x62E9, 0xD4F1, 0x62EA, 0x928A, 0x62EB, 0x928B, 0x62EC, 0xC0A8, 0x62ED, 0xCAC3, 0x62EE, 0xDED7, 0x62EF, 0xD5FC, 0x62F0, 0x928C, 0x62F1, 0xB9B0, 0x62F2, 0x928D, 0x62F3, 0xC8AD, 0x62F4, 0xCBA9, 0x62F5, 0x928E, 0x62F6, 0xDED9, 0x62F7, 0xBFBD, 0x62F8, 0x928F, 0x62F9, 0x9290, 0x62FA, 0x9291, 0x62FB, 0x9292, 0x62FC, 0xC6B4, 0x62FD, 0xD7A7, 0x62FE, 0xCAB0, 0x62FF, 0xC4C3, 0x6300, 0x9293, 0x6301, 0xB3D6, 0x6302, 0xB9D2, 0x6303, 0x9294, 0x6304, 0x9295, 0x6305, 0x9296, 0x6306, 0x9297, 0x6307, 0xD6B8, 0x6308, 0xEAFC, 0x6309, 0xB0B4, 0x630A, 0x9298, 0x630B, 0x9299, 0x630C, 0x929A, 0x630D, 0x929B, 0x630E, 0xBFE6, 0x630F, 0x929C, 0x6310, 0x929D, 0x6311, 0xCCF4, 0x6312, 0x929E, 0x6313, 0x929F, 0x6314, 0x92A0, 0x6315, 0x92A1, 0x6316, 0xCDDA, 0x6317, 0x92A2, 0x6318, 0x92A3, 0x6319, 0x92A4, 0x631A, 0xD6BF, 0x631B, 0xC2CE, 0x631C, 0x92A5, 0x631D, 0xCECE, 0x631E, 0xCCA2, 0x631F, 0xD0AE, 0x6320, 0xC4D3, 0x6321, 0xB5B2, 0x6322, 0xDED8, 0x6323, 0xD5F5, 0x6324, 0xBCB7, 0x6325, 0xBBD3, 0x6326, 0x92A6, 0x6327, 0x92A7, 0x6328, 0xB0A4, 0x6329, 0x92A8, 0x632A, 0xC5B2, 0x632B, 0xB4EC, 0x632C, 0x92A9, 0x632D, 0x92AA, 0x632E, 0x92AB, 0x632F, 0xD5F1, 0x6330, 0x92AC, 0x6331, 0x92AD, 0x6332, 0xEAFD, 0x6333, 0x92AE, 0x6334, 0x92AF, 0x6335, 0x92B0, 0x6336, 0x92B1, 0x6337, 0x92B2, 0x6338, 0x92B3, 0x6339, 0xDEDA, 0x633A, 0xCDA6, 0x633B, 0x92B4, 0x633C, 0x92B5, 0x633D, 0xCDEC, 0x633E, 0x92B6, 0x633F, 0x92B7, 0x6340, 0x92B8, 0x6341, 0x92B9, 0x6342, 0xCEE6, 0x6343, 0xDEDC, 0x6344, 0x92BA, 0x6345, 0xCDB1, 0x6346, 0xC0A6, 0x6347, 0x92BB, 0x6348, 0x92BC, 0x6349, 0xD7BD, 0x634A, 0x92BD, 0x634B, 0xDEDB, 0x634C, 0xB0C6, 0x634D, 0xBAB4, 0x634E, 0xC9D3, 0x634F, 0xC4F3, 0x6350, 0xBEE8, 0x6351, 0x92BE, 0x6352, 0x92BF, 0x6353, 0x92C0, 0x6354, 0x92C1, 0x6355, 0xB2B6, 0x6356, 0x92C2, 0x6357, 0x92C3, 0x6358, 0x92C4, 0x6359, 0x92C5, 0x635A, 0x92C6, 0x635B, 0x92C7, 0x635C, 0x92C8, 0x635D, 0x92C9, 0x635E, 0xC0CC, 0x635F, 0xCBF0, 0x6360, 0x92CA, 0x6361, 0xBCF1, 0x6362, 0xBBBB, 0x6363, 0xB5B7, 0x6364, 0x92CB, 0x6365, 0x92CC, 0x6366, 0x92CD, 0x6367, 0xC5F5, 0x6368, 0x92CE, 0x6369, 0xDEE6, 0x636A, 0x92CF, 0x636B, 0x92D0, 0x636C, 0x92D1, 0x636D, 0xDEE3, 0x636E, 0xBEDD, 0x636F, 0x92D2, 0x6370, 0x92D3, 0x6371, 0xDEDF, 0x6372, 0x92D4, 0x6373, 0x92D5, 0x6374, 0x92D6, 0x6375, 0x92D7, 0x6376, 0xB4B7, 0x6377, 0xBDDD, 0x6378, 0x92D8, 0x6379, 0x92D9, 0x637A, 0xDEE0, 0x637B, 0xC4ED, 0x637C, 0x92DA, 0x637D, 0x92DB, 0x637E, 0x92DC, 0x637F, 0x92DD, 0x6380, 0xCFC6, 0x6381, 0x92DE, 0x6382, 0xB5E0, 0x6383, 0x92DF, 0x6384, 0x92E0, 0x6385, 0x92E1, 0x6386, 0x92E2, 0x6387, 0xB6DE, 0x6388, 0xCADA, 0x6389, 0xB5F4, 0x638A, 0xDEE5, 0x638B, 0x92E3, 0x638C, 0xD5C6, 0x638D, 0x92E4, 0x638E, 0xDEE1, 0x638F, 0xCCCD, 0x6390, 0xC6FE, 0x6391, 0x92E5, 0x6392, 0xC5C5, 0x6393, 0x92E6, 0x6394, 0x92E7, 0x6395, 0x92E8, 0x6396, 0xD2B4, 0x6397, 0x92E9, 0x6398, 0xBEF2, 0x6399, 0x92EA, 0x639A, 0x92EB, 0x639B, 0x92EC, 0x639C, 0x92ED, 0x639D, 0x92EE, 0x639E, 0x92EF, 0x639F, 0x92F0, 0x63A0, 0xC2D3, 0x63A1, 0x92F1, 0x63A2, 0xCCBD, 0x63A3, 0xB3B8, 0x63A4, 0x92F2, 0x63A5, 0xBDD3, 0x63A6, 0x92F3, 0x63A7, 0xBFD8, 0x63A8, 0xCDC6, 0x63A9, 0xD1DA, 0x63AA, 0xB4EB, 0x63AB, 0x92F4, 0x63AC, 0xDEE4, 0x63AD, 0xDEDD, 0x63AE, 0xDEE7, 0x63AF, 0x92F5, 0x63B0, 0xEAFE, 0x63B1, 0x92F6, 0x63B2, 0x92F7, 0x63B3, 0xC2B0, 0x63B4, 0xDEE2, 0x63B5, 0x92F8, 0x63B6, 0x92F9, 0x63B7, 0xD6C0, 0x63B8, 0xB5A7, 0x63B9, 0x92FA, 0x63BA, 0xB2F4, 0x63BB, 0x92FB, 0x63BC, 0xDEE8, 0x63BD, 0x92FC, 0x63BE, 0xDEF2, 0x63BF, 0x92FD, 0x63C0, 0x92FE, 0x63C1, 0x9340, 0x63C2, 0x9341, 0x63C3, 0x9342, 0x63C4, 0xDEED, 0x63C5, 0x9343, 0x63C6, 0xDEF1, 0x63C7, 0x9344, 0x63C8, 0x9345, 0x63C9, 0xC8E0, 0x63CA, 0x9346, 0x63CB, 0x9347, 0x63CC, 0x9348, 0x63CD, 0xD7E1, 0x63CE, 0xDEEF, 0x63CF, 0xC3E8, 0x63D0, 0xCCE1, 0x63D1, 0x9349, 0x63D2, 0xB2E5, 0x63D3, 0x934A, 0x63D4, 0x934B, 0x63D5, 0x934C, 0x63D6, 0xD2BE, 0x63D7, 0x934D, 0x63D8, 0x934E, 0x63D9, 0x934F, 0x63DA, 0x9350, 0x63DB, 0x9351, 0x63DC, 0x9352, 0x63DD, 0x9353, 0x63DE, 0xDEEE, 0x63DF, 0x9354, 0x63E0, 0xDEEB, 0x63E1, 0xCED5, 0x63E2, 0x9355, 0x63E3, 0xB4A7, 0x63E4, 0x9356, 0x63E5, 0x9357, 0x63E6, 0x9358, 0x63E7, 0x9359, 0x63E8, 0x935A, 0x63E9, 0xBFAB, 0x63EA, 0xBEBE, 0x63EB, 0x935B, 0x63EC, 0x935C, 0x63ED, 0xBDD2, 0x63EE, 0x935D, 0x63EF, 0x935E, 0x63F0, 0x935F, 0x63F1, 0x9360, 0x63F2, 0xDEE9, 0x63F3, 0x9361, 0x63F4, 0xD4AE, 0x63F5, 0x9362, 0x63F6, 0xDEDE, 0x63F7, 0x9363, 0x63F8, 0xDEEA, 0x63F9, 0x9364, 0x63FA, 0x9365, 0x63FB, 0x9366, 0x63FC, 0x9367, 0x63FD, 0xC0BF, 0x63FE, 0x9368, 0x63FF, 0xDEEC, 0x6400, 0xB2F3, 0x6401, 0xB8E9, 0x6402, 0xC2A7, 0x6403, 0x9369, 0x6404, 0x936A, 0x6405, 0xBDC1, 0x6406, 0x936B, 0x6407, 0x936C, 0x6408, 0x936D, 0x6409, 0x936E, 0x640A, 0x936F, 0x640B, 0xDEF5, 0x640C, 0xDEF8, 0x640D, 0x9370, 0x640E, 0x9371, 0x640F, 0xB2AB, 0x6410, 0xB4A4, 0x6411, 0x9372, 0x6412, 0x9373, 0x6413, 0xB4EA, 0x6414, 0xC9A6, 0x6415, 0x9374, 0x6416, 0x9375, 0x6417, 0x9376, 0x6418, 0x9377, 0x6419, 0x9378, 0x641A, 0x9379, 0x641B, 0xDEF6, 0x641C, 0xCBD1, 0x641D, 0x937A, 0x641E, 0xB8E3, 0x641F, 0x937B, 0x6420, 0xDEF7, 0x6421, 0xDEFA, 0x6422, 0x937C, 0x6423, 0x937D, 0x6424, 0x937E, 0x6425, 0x9380, 0x6426, 0xDEF9, 0x6427, 0x9381, 0x6428, 0x9382, 0x6429, 0x9383, 0x642A, 0xCCC2, 0x642B, 0x9384, 0x642C, 0xB0E1, 0x642D, 0xB4EE, 0x642E, 0x9385, 0x642F, 0x9386, 0x6430, 0x9387, 0x6431, 0x9388, 0x6432, 0x9389, 0x6433, 0x938A, 0x6434, 0xE5BA, 0x6435, 0x938B, 0x6436, 0x938C, 0x6437, 0x938D, 0x6438, 0x938E, 0x6439, 0x938F, 0x643A, 0xD0AF, 0x643B, 0x9390, 0x643C, 0x9391, 0x643D, 0xB2EB, 0x643E, 0x9392, 0x643F, 0xEBA1, 0x6440, 0x9393, 0x6441, 0xDEF4, 0x6442, 0x9394, 0x6443, 0x9395, 0x6444, 0xC9E3, 0x6445, 0xDEF3, 0x6446, 0xB0DA, 0x6447, 0xD2A1, 0x6448, 0xB1F7, 0x6449, 0x9396, 0x644A, 0xCCAF, 0x644B, 0x9397, 0x644C, 0x9398, 0x644D, 0x9399, 0x644E, 0x939A, 0x644F, 0x939B, 0x6450, 0x939C, 0x6451, 0x939D, 0x6452, 0xDEF0, 0x6453, 0x939E, 0x6454, 0xCBA4, 0x6455, 0x939F, 0x6456, 0x93A0, 0x6457, 0x93A1, 0x6458, 0xD5AA, 0x6459, 0x93A2, 0x645A, 0x93A3, 0x645B, 0x93A4, 0x645C, 0x93A5, 0x645D, 0x93A6, 0x645E, 0xDEFB, 0x645F, 0x93A7, 0x6460, 0x93A8, 0x6461, 0x93A9, 0x6462, 0x93AA, 0x6463, 0x93AB, 0x6464, 0x93AC, 0x6465, 0x93AD, 0x6466, 0x93AE, 0x6467, 0xB4DD, 0x6468, 0x93AF, 0x6469, 0xC4A6, 0x646A, 0x93B0, 0x646B, 0x93B1, 0x646C, 0x93B2, 0x646D, 0xDEFD, 0x646E, 0x93B3, 0x646F, 0x93B4, 0x6470, 0x93B5, 0x6471, 0x93B6, 0x6472, 0x93B7, 0x6473, 0x93B8, 0x6474, 0x93B9, 0x6475, 0x93BA, 0x6476, 0x93BB, 0x6477, 0x93BC, 0x6478, 0xC3FE, 0x6479, 0xC4A1, 0x647A, 0xDFA1, 0x647B, 0x93BD, 0x647C, 0x93BE, 0x647D, 0x93BF, 0x647E, 0x93C0, 0x647F, 0x93C1, 0x6480, 0x93C2, 0x6481, 0x93C3, 0x6482, 0xC1CC, 0x6483, 0x93C4, 0x6484, 0xDEFC, 0x6485, 0xBEEF, 0x6486, 0x93C5, 0x6487, 0xC6B2, 0x6488, 0x93C6, 0x6489, 0x93C7, 0x648A, 0x93C8, 0x648B, 0x93C9, 0x648C, 0x93CA, 0x648D, 0x93CB, 0x648E, 0x93CC, 0x648F, 0x93CD, 0x6490, 0x93CE, 0x6491, 0xB3C5, 0x6492, 0xC8F6, 0x6493, 0x93CF, 0x6494, 0x93D0, 0x6495, 0xCBBA, 0x6496, 0xDEFE, 0x6497, 0x93D1, 0x6498, 0x93D2, 0x6499, 0xDFA4, 0x649A, 0x93D3, 0x649B, 0x93D4, 0x649C, 0x93D5, 0x649D, 0x93D6, 0x649E, 0xD7B2, 0x649F, 0x93D7, 0x64A0, 0x93D8, 0x64A1, 0x93D9, 0x64A2, 0x93DA, 0x64A3, 0x93DB, 0x64A4, 0xB3B7, 0x64A5, 0x93DC, 0x64A6, 0x93DD, 0x64A7, 0x93DE, 0x64A8, 0x93DF, 0x64A9, 0xC1C3, 0x64AA, 0x93E0, 0x64AB, 0x93E1, 0x64AC, 0xC7CB, 0x64AD, 0xB2A5, 0x64AE, 0xB4E9, 0x64AF, 0x93E2, 0x64B0, 0xD7AB, 0x64B1, 0x93E3, 0x64B2, 0x93E4, 0x64B3, 0x93E5, 0x64B4, 0x93E6, 0x64B5, 0xC4EC, 0x64B6, 0x93E7, 0x64B7, 0xDFA2, 0x64B8, 0xDFA3, 0x64B9, 0x93E8, 0x64BA, 0xDFA5, 0x64BB, 0x93E9, 0x64BC, 0xBAB3, 0x64BD, 0x93EA, 0x64BE, 0x93EB, 0x64BF, 0x93EC, 0x64C0, 0xDFA6, 0x64C1, 0x93ED, 0x64C2, 0xC0DE, 0x64C3, 0x93EE, 0x64C4, 0x93EF, 0x64C5, 0xC9C3, 0x64C6, 0x93F0, 0x64C7, 0x93F1, 0x64C8, 0x93F2, 0x64C9, 0x93F3, 0x64CA, 0x93F4, 0x64CB, 0x93F5, 0x64CC, 0x93F6, 0x64CD, 0xB2D9, 0x64CE, 0xC7E6, 0x64CF, 0x93F7, 0x64D0, 0xDFA7, 0x64D1, 0x93F8, 0x64D2, 0xC7DC, 0x64D3, 0x93F9, 0x64D4, 0x93FA, 0x64D5, 0x93FB, 0x64D6, 0x93FC, 0x64D7, 0xDFA8, 0x64D8, 0xEBA2, 0x64D9, 0x93FD, 0x64DA, 0x93FE, 0x64DB, 0x9440, 0x64DC, 0x9441, 0x64DD, 0x9442, 0x64DE, 0xCBD3, 0x64DF, 0x9443, 0x64E0, 0x9444, 0x64E1, 0x9445, 0x64E2, 0xDFAA, 0x64E3, 0x9446, 0x64E4, 0xDFA9, 0x64E5, 0x9447, 0x64E6, 0xB2C1, 0x64E7, 0x9448, 0x64E8, 0x9449, 0x64E9, 0x944A, 0x64EA, 0x944B, 0x64EB, 0x944C, 0x64EC, 0x944D, 0x64ED, 0x944E, 0x64EE, 0x944F, 0x64EF, 0x9450, 0x64F0, 0x9451, 0x64F1, 0x9452, 0x64F2, 0x9453, 0x64F3, 0x9454, 0x64F4, 0x9455, 0x64F5, 0x9456, 0x64F6, 0x9457, 0x64F7, 0x9458, 0x64F8, 0x9459, 0x64F9, 0x945A, 0x64FA, 0x945B, 0x64FB, 0x945C, 0x64FC, 0x945D, 0x64FD, 0x945E, 0x64FE, 0x945F, 0x64FF, 0x9460, 0x6500, 0xC5CA, 0x6501, 0x9461, 0x6502, 0x9462, 0x6503, 0x9463, 0x6504, 0x9464, 0x6505, 0x9465, 0x6506, 0x9466, 0x6507, 0x9467, 0x6508, 0x9468, 0x6509, 0xDFAB, 0x650A, 0x9469, 0x650B, 0x946A, 0x650C, 0x946B, 0x650D, 0x946C, 0x650E, 0x946D, 0x650F, 0x946E, 0x6510, 0x946F, 0x6511, 0x9470, 0x6512, 0xD4DC, 0x6513, 0x9471, 0x6514, 0x9472, 0x6515, 0x9473, 0x6516, 0x9474, 0x6517, 0x9475, 0x6518, 0xC8C1, 0x6519, 0x9476, 0x651A, 0x9477, 0x651B, 0x9478, 0x651C, 0x9479, 0x651D, 0x947A, 0x651E, 0x947B, 0x651F, 0x947C, 0x6520, 0x947D, 0x6521, 0x947E, 0x6522, 0x9480, 0x6523, 0x9481, 0x6524, 0x9482, 0x6525, 0xDFAC, 0x6526, 0x9483, 0x6527, 0x9484, 0x6528, 0x9485, 0x6529, 0x9486, 0x652A, 0x9487, 0x652B, 0xBEF0, 0x652C, 0x9488, 0x652D, 0x9489, 0x652E, 0xDFAD, 0x652F, 0xD6A7, 0x6530, 0x948A, 0x6531, 0x948B, 0x6532, 0x948C, 0x6533, 0x948D, 0x6534, 0xEAB7, 0x6535, 0xEBB6, 0x6536, 0xCAD5, 0x6537, 0x948E, 0x6538, 0xD8FC, 0x6539, 0xB8C4, 0x653A, 0x948F, 0x653B, 0xB9A5, 0x653C, 0x9490, 0x653D, 0x9491, 0x653E, 0xB7C5, 0x653F, 0xD5FE, 0x6540, 0x9492, 0x6541, 0x9493, 0x6542, 0x9494, 0x6543, 0x9495, 0x6544, 0x9496, 0x6545, 0xB9CA, 0x6546, 0x9497, 0x6547, 0x9498, 0x6548, 0xD0A7, 0x6549, 0xF4CD, 0x654A, 0x9499, 0x654B, 0x949A, 0x654C, 0xB5D0, 0x654D, 0x949B, 0x654E, 0x949C, 0x654F, 0xC3F4, 0x6550, 0x949D, 0x6551, 0xBEC8, 0x6552, 0x949E, 0x6553, 0x949F, 0x6554, 0x94A0, 0x6555, 0xEBB7, 0x6556, 0xB0BD, 0x6557, 0x94A1, 0x6558, 0x94A2, 0x6559, 0xBDCC, 0x655A, 0x94A3, 0x655B, 0xC1B2, 0x655C, 0x94A4, 0x655D, 0xB1D6, 0x655E, 0xB3A8, 0x655F, 0x94A5, 0x6560, 0x94A6, 0x6561, 0x94A7, 0x6562, 0xB8D2, 0x6563, 0xC9A2, 0x6564, 0x94A8, 0x6565, 0x94A9, 0x6566, 0xB6D8, 0x6567, 0x94AA, 0x6568, 0x94AB, 0x6569, 0x94AC, 0x656A, 0x94AD, 0x656B, 0xEBB8, 0x656C, 0xBEB4, 0x656D, 0x94AE, 0x656E, 0x94AF, 0x656F, 0x94B0, 0x6570, 0xCAFD, 0x6571, 0x94B1, 0x6572, 0xC7C3, 0x6573, 0x94B2, 0x6574, 0xD5FB, 0x6575, 0x94B3, 0x6576, 0x94B4, 0x6577, 0xB7F3, 0x6578, 0x94B5, 0x6579, 0x94B6, 0x657A, 0x94B7, 0x657B, 0x94B8, 0x657C, 0x94B9, 0x657D, 0x94BA, 0x657E, 0x94BB, 0x657F, 0x94BC, 0x6580, 0x94BD, 0x6581, 0x94BE, 0x6582, 0x94BF, 0x6583, 0x94C0, 0x6584, 0x94C1, 0x6585, 0x94C2, 0x6586, 0x94C3, 0x6587, 0xCEC4, 0x6588, 0x94C4, 0x6589, 0x94C5, 0x658A, 0x94C6, 0x658B, 0xD5AB, 0x658C, 0xB1F3, 0x658D, 0x94C7, 0x658E, 0x94C8, 0x658F, 0x94C9, 0x6590, 0xECB3, 0x6591, 0xB0DF, 0x6592, 0x94CA, 0x6593, 0xECB5, 0x6594, 0x94CB, 0x6595, 0x94CC, 0x6596, 0x94CD, 0x6597, 0xB6B7, 0x6598, 0x94CE, 0x6599, 0xC1CF, 0x659A, 0x94CF, 0x659B, 0xF5FA, 0x659C, 0xD0B1, 0x659D, 0x94D0, 0x659E, 0x94D1, 0x659F, 0xD5E5, 0x65A0, 0x94D2, 0x65A1, 0xCED3, 0x65A2, 0x94D3, 0x65A3, 0x94D4, 0x65A4, 0xBDEF, 0x65A5, 0xB3E2, 0x65A6, 0x94D5, 0x65A7, 0xB8AB, 0x65A8, 0x94D6, 0x65A9, 0xD5B6, 0x65AA, 0x94D7, 0x65AB, 0xEDBD, 0x65AC, 0x94D8, 0x65AD, 0xB6CF, 0x65AE, 0x94D9, 0x65AF, 0xCBB9, 0x65B0, 0xD0C2, 0x65B1, 0x94DA, 0x65B2, 0x94DB, 0x65B3, 0x94DC, 0x65B4, 0x94DD, 0x65B5, 0x94DE, 0x65B6, 0x94DF, 0x65B7, 0x94E0, 0x65B8, 0x94E1, 0x65B9, 0xB7BD, 0x65BA, 0x94E2, 0x65BB, 0x94E3, 0x65BC, 0xECB6, 0x65BD, 0xCAA9, 0x65BE, 0x94E4, 0x65BF, 0x94E5, 0x65C0, 0x94E6, 0x65C1, 0xC5D4, 0x65C2, 0x94E7, 0x65C3, 0xECB9, 0x65C4, 0xECB8, 0x65C5, 0xC2C3, 0x65C6, 0xECB7, 0x65C7, 0x94E8, 0x65C8, 0x94E9, 0x65C9, 0x94EA, 0x65CA, 0x94EB, 0x65CB, 0xD0FD, 0x65CC, 0xECBA, 0x65CD, 0x94EC, 0x65CE, 0xECBB, 0x65CF, 0xD7E5, 0x65D0, 0x94ED, 0x65D1, 0x94EE, 0x65D2, 0xECBC, 0x65D3, 0x94EF, 0x65D4, 0x94F0, 0x65D5, 0x94F1, 0x65D6, 0xECBD, 0x65D7, 0xC6EC, 0x65D8, 0x94F2, 0x65D9, 0x94F3, 0x65DA, 0x94F4, 0x65DB, 0x94F5, 0x65DC, 0x94F6, 0x65DD, 0x94F7, 0x65DE, 0x94F8, 0x65DF, 0x94F9, 0x65E0, 0xCEDE, 0x65E1, 0x94FA, 0x65E2, 0xBCC8, 0x65E3, 0x94FB, 0x65E4, 0x94FC, 0x65E5, 0xC8D5, 0x65E6, 0xB5A9, 0x65E7, 0xBEC9, 0x65E8, 0xD6BC, 0x65E9, 0xD4E7, 0x65EA, 0x94FD, 0x65EB, 0x94FE, 0x65EC, 0xD1AE, 0x65ED, 0xD0F1, 0x65EE, 0xEAB8, 0x65EF, 0xEAB9, 0x65F0, 0xEABA, 0x65F1, 0xBAB5, 0x65F2, 0x9540, 0x65F3, 0x9541, 0x65F4, 0x9542, 0x65F5, 0x9543, 0x65F6, 0xCAB1, 0x65F7, 0xBFF5, 0x65F8, 0x9544, 0x65F9, 0x9545, 0x65FA, 0xCDFA, 0x65FB, 0x9546, 0x65FC, 0x9547, 0x65FD, 0x9548, 0x65FE, 0x9549, 0x65FF, 0x954A, 0x6600, 0xEAC0, 0x6601, 0x954B, 0x6602, 0xB0BA, 0x6603, 0xEABE, 0x6604, 0x954C, 0x6605, 0x954D, 0x6606, 0xC0A5, 0x6607, 0x954E, 0x6608, 0x954F, 0x6609, 0x9550, 0x660A, 0xEABB, 0x660B, 0x9551, 0x660C, 0xB2FD, 0x660D, 0x9552, 0x660E, 0xC3F7, 0x660F, 0xBBE8, 0x6610, 0x9553, 0x6611, 0x9554, 0x6612, 0x9555, 0x6613, 0xD2D7, 0x6614, 0xCEF4, 0x6615, 0xEABF, 0x6616, 0x9556, 0x6617, 0x9557, 0x6618, 0x9558, 0x6619, 0xEABC, 0x661A, 0x9559, 0x661B, 0x955A, 0x661C, 0x955B, 0x661D, 0xEAC3, 0x661E, 0x955C, 0x661F, 0xD0C7, 0x6620, 0xD3B3, 0x6621, 0x955D, 0x6622, 0x955E, 0x6623, 0x955F, 0x6624, 0x9560, 0x6625, 0xB4BA, 0x6626, 0x9561, 0x6627, 0xC3C1, 0x6628, 0xD7F2, 0x6629, 0x9562, 0x662A, 0x9563, 0x662B, 0x9564, 0x662C, 0x9565, 0x662D, 0xD5D1, 0x662E, 0x9566, 0x662F, 0xCAC7, 0x6630, 0x9567, 0x6631, 0xEAC5, 0x6632, 0x9568, 0x6633, 0x9569, 0x6634, 0xEAC4, 0x6635, 0xEAC7, 0x6636, 0xEAC6, 0x6637, 0x956A, 0x6638, 0x956B, 0x6639, 0x956C, 0x663A, 0x956D, 0x663B, 0x956E, 0x663C, 0xD6E7, 0x663D, 0x956F, 0x663E, 0xCFD4, 0x663F, 0x9570, 0x6640, 0x9571, 0x6641, 0xEACB, 0x6642, 0x9572, 0x6643, 0xBBCE, 0x6644, 0x9573, 0x6645, 0x9574, 0x6646, 0x9575, 0x6647, 0x9576, 0x6648, 0x9577, 0x6649, 0x9578, 0x664A, 0x9579, 0x664B, 0xBDFA, 0x664C, 0xC9CE, 0x664D, 0x957A, 0x664E, 0x957B, 0x664F, 0xEACC, 0x6650, 0x957C, 0x6651, 0x957D, 0x6652, 0xC9B9, 0x6653, 0xCFFE, 0x6654, 0xEACA, 0x6655, 0xD4CE, 0x6656, 0xEACD, 0x6657, 0xEACF, 0x6658, 0x957E, 0x6659, 0x9580, 0x665A, 0xCDED, 0x665B, 0x9581, 0x665C, 0x9582, 0x665D, 0x9583, 0x665E, 0x9584, 0x665F, 0xEAC9, 0x6660, 0x9585, 0x6661, 0xEACE, 0x6662, 0x9586, 0x6663, 0x9587, 0x6664, 0xCEEE, 0x6665, 0x9588, 0x6666, 0xBBDE, 0x6667, 0x9589, 0x6668, 0xB3BF, 0x6669, 0x958A, 0x666A, 0x958B, 0x666B, 0x958C, 0x666C, 0x958D, 0x666D, 0x958E, 0x666E, 0xC6D5, 0x666F, 0xBEB0, 0x6670, 0xCEFA, 0x6671, 0x958F, 0x6672, 0x9590, 0x6673, 0x9591, 0x6674, 0xC7E7, 0x6675, 0x9592, 0x6676, 0xBEA7, 0x6677, 0xEAD0, 0x6678, 0x9593, 0x6679, 0x9594, 0x667A, 0xD6C7, 0x667B, 0x9595, 0x667C, 0x9596, 0x667D, 0x9597, 0x667E, 0xC1C0, 0x667F, 0x9598, 0x6680, 0x9599, 0x6681, 0x959A, 0x6682, 0xD4DD, 0x6683, 0x959B, 0x6684, 0xEAD1, 0x6685, 0x959C, 0x6686, 0x959D, 0x6687, 0xCFBE, 0x6688, 0x959E, 0x6689, 0x959F, 0x668A, 0x95A0, 0x668B, 0x95A1, 0x668C, 0xEAD2, 0x668D, 0x95A2, 0x668E, 0x95A3, 0x668F, 0x95A4, 0x6690, 0x95A5, 0x6691, 0xCAEE, 0x6692, 0x95A6, 0x6693, 0x95A7, 0x6694, 0x95A8, 0x6695, 0x95A9, 0x6696, 0xC5AF, 0x6697, 0xB0B5, 0x6698, 0x95AA, 0x6699, 0x95AB, 0x669A, 0x95AC, 0x669B, 0x95AD, 0x669C, 0x95AE, 0x669D, 0xEAD4, 0x669E, 0x95AF, 0x669F, 0x95B0, 0x66A0, 0x95B1, 0x66A1, 0x95B2, 0x66A2, 0x95B3, 0x66A3, 0x95B4, 0x66A4, 0x95B5, 0x66A5, 0x95B6, 0x66A6, 0x95B7, 0x66A7, 0xEAD3, 0x66A8, 0xF4DF, 0x66A9, 0x95B8, 0x66AA, 0x95B9, 0x66AB, 0x95BA, 0x66AC, 0x95BB, 0x66AD, 0x95BC, 0x66AE, 0xC4BA, 0x66AF, 0x95BD, 0x66B0, 0x95BE, 0x66B1, 0x95BF, 0x66B2, 0x95C0, 0x66B3, 0x95C1, 0x66B4, 0xB1A9, 0x66B5, 0x95C2, 0x66B6, 0x95C3, 0x66B7, 0x95C4, 0x66B8, 0x95C5, 0x66B9, 0xE5DF, 0x66BA, 0x95C6, 0x66BB, 0x95C7, 0x66BC, 0x95C8, 0x66BD, 0x95C9, 0x66BE, 0xEAD5, 0x66BF, 0x95CA, 0x66C0, 0x95CB, 0x66C1, 0x95CC, 0x66C2, 0x95CD, 0x66C3, 0x95CE, 0x66C4, 0x95CF, 0x66C5, 0x95D0, 0x66C6, 0x95D1, 0x66C7, 0x95D2, 0x66C8, 0x95D3, 0x66C9, 0x95D4, 0x66CA, 0x95D5, 0x66CB, 0x95D6, 0x66CC, 0x95D7, 0x66CD, 0x95D8, 0x66CE, 0x95D9, 0x66CF, 0x95DA, 0x66D0, 0x95DB, 0x66D1, 0x95DC, 0x66D2, 0x95DD, 0x66D3, 0x95DE, 0x66D4, 0x95DF, 0x66D5, 0x95E0, 0x66D6, 0x95E1, 0x66D7, 0x95E2, 0x66D8, 0x95E3, 0x66D9, 0xCAEF, 0x66DA, 0x95E4, 0x66DB, 0xEAD6, 0x66DC, 0xEAD7, 0x66DD, 0xC6D8, 0x66DE, 0x95E5, 0x66DF, 0x95E6, 0x66E0, 0x95E7, 0x66E1, 0x95E8, 0x66E2, 0x95E9, 0x66E3, 0x95EA, 0x66E4, 0x95EB, 0x66E5, 0x95EC, 0x66E6, 0xEAD8, 0x66E7, 0x95ED, 0x66E8, 0x95EE, 0x66E9, 0xEAD9, 0x66EA, 0x95EF, 0x66EB, 0x95F0, 0x66EC, 0x95F1, 0x66ED, 0x95F2, 0x66EE, 0x95F3, 0x66EF, 0x95F4, 0x66F0, 0xD4BB, 0x66F1, 0x95F5, 0x66F2, 0xC7FA, 0x66F3, 0xD2B7, 0x66F4, 0xB8FC, 0x66F5, 0x95F6, 0x66F6, 0x95F7, 0x66F7, 0xEAC2, 0x66F8, 0x95F8, 0x66F9, 0xB2DC, 0x66FA, 0x95F9, 0x66FB, 0x95FA, 0x66FC, 0xC2FC, 0x66FD, 0x95FB, 0x66FE, 0xD4F8, 0x66FF, 0xCCE6, 0x6700, 0xD7EE, 0x6701, 0x95FC, 0x6702, 0x95FD, 0x6703, 0x95FE, 0x6704, 0x9640, 0x6705, 0x9641, 0x6706, 0x9642, 0x6707, 0x9643, 0x6708, 0xD4C2, 0x6709, 0xD3D0, 0x670A, 0xEBC3, 0x670B, 0xC5F3, 0x670C, 0x9644, 0x670D, 0xB7FE, 0x670E, 0x9645, 0x670F, 0x9646, 0x6710, 0xEBD4, 0x6711, 0x9647, 0x6712, 0x9648, 0x6713, 0x9649, 0x6714, 0xCBB7, 0x6715, 0xEBDE, 0x6716, 0x964A, 0x6717, 0xC0CA, 0x6718, 0x964B, 0x6719, 0x964C, 0x671A, 0x964D, 0x671B, 0xCDFB, 0x671C, 0x964E, 0x671D, 0xB3AF, 0x671E, 0x964F, 0x671F, 0xC6DA, 0x6720, 0x9650, 0x6721, 0x9651, 0x6722, 0x9652, 0x6723, 0x9653, 0x6724, 0x9654, 0x6725, 0x9655, 0x6726, 0xEBFC, 0x6727, 0x9656, 0x6728, 0xC4BE, 0x6729, 0x9657, 0x672A, 0xCEB4, 0x672B, 0xC4A9, 0x672C, 0xB1BE, 0x672D, 0xD4FD, 0x672E, 0x9658, 0x672F, 0xCAF5, 0x6730, 0x9659, 0x6731, 0xD6EC, 0x6732, 0x965A, 0x6733, 0x965B, 0x6734, 0xC6D3, 0x6735, 0xB6E4, 0x6736, 0x965C, 0x6737, 0x965D, 0x6738, 0x965E, 0x6739, 0x965F, 0x673A, 0xBBFA, 0x673B, 0x9660, 0x673C, 0x9661, 0x673D, 0xD0E0, 0x673E, 0x9662, 0x673F, 0x9663, 0x6740, 0xC9B1, 0x6741, 0x9664, 0x6742, 0xD4D3, 0x6743, 0xC8A8, 0x6744, 0x9665, 0x6745, 0x9666, 0x6746, 0xB8CB, 0x6747, 0x9667, 0x6748, 0xE8BE, 0x6749, 0xC9BC, 0x674A, 0x9668, 0x674B, 0x9669, 0x674C, 0xE8BB, 0x674D, 0x966A, 0x674E, 0xC0EE, 0x674F, 0xD0D3, 0x6750, 0xB2C4, 0x6751, 0xB4E5, 0x6752, 0x966B, 0x6753, 0xE8BC, 0x6754, 0x966C, 0x6755, 0x966D, 0x6756, 0xD5C8, 0x6757, 0x966E, 0x6758, 0x966F, 0x6759, 0x9670, 0x675A, 0x9671, 0x675B, 0x9672, 0x675C, 0xB6C5, 0x675D, 0x9673, 0x675E, 0xE8BD, 0x675F, 0xCAF8, 0x6760, 0xB8DC, 0x6761, 0xCCF5, 0x6762, 0x9674, 0x6763, 0x9675, 0x6764, 0x9676, 0x6765, 0xC0B4, 0x6766, 0x9677, 0x6767, 0x9678, 0x6768, 0xD1EE, 0x6769, 0xE8BF, 0x676A, 0xE8C2, 0x676B, 0x9679, 0x676C, 0x967A, 0x676D, 0xBABC, 0x676E, 0x967B, 0x676F, 0xB1AD, 0x6770, 0xBDDC, 0x6771, 0x967C, 0x6772, 0xEABD, 0x6773, 0xE8C3, 0x6774, 0x967D, 0x6775, 0xE8C6, 0x6776, 0x967E, 0x6777, 0xE8CB, 0x6778, 0x9680, 0x6779, 0x9681, 0x677A, 0x9682, 0x677B, 0x9683, 0x677C, 0xE8CC, 0x677D, 0x9684, 0x677E, 0xCBC9, 0x677F, 0xB0E5, 0x6780, 0x9685, 0x6781, 0xBCAB, 0x6782, 0x9686, 0x6783, 0x9687, 0x6784, 0xB9B9, 0x6785, 0x9688, 0x6786, 0x9689, 0x6787, 0xE8C1, 0x6788, 0x968A, 0x6789, 0xCDF7, 0x678A, 0x968B, 0x678B, 0xE8CA, 0x678C, 0x968C, 0x678D, 0x968D, 0x678E, 0x968E, 0x678F, 0x968F, 0x6790, 0xCEF6, 0x6791, 0x9690, 0x6792, 0x9691, 0x6793, 0x9692, 0x6794, 0x9693, 0x6795, 0xD5ED, 0x6796, 0x9694, 0x6797, 0xC1D6, 0x6798, 0xE8C4, 0x6799, 0x9695, 0x679A, 0xC3B6, 0x679B, 0x9696, 0x679C, 0xB9FB, 0x679D, 0xD6A6, 0x679E, 0xE8C8, 0x679F, 0x9697, 0x67A0, 0x9698, 0x67A1, 0x9699, 0x67A2, 0xCAE0, 0x67A3, 0xD4E6, 0x67A4, 0x969A, 0x67A5, 0xE8C0, 0x67A6, 0x969B, 0x67A7, 0xE8C5, 0x67A8, 0xE8C7, 0x67A9, 0x969C, 0x67AA, 0xC7B9, 0x67AB, 0xB7E3, 0x67AC, 0x969D, 0x67AD, 0xE8C9, 0x67AE, 0x969E, 0x67AF, 0xBFDD, 0x67B0, 0xE8D2, 0x67B1, 0x969F, 0x67B2, 0x96A0, 0x67B3, 0xE8D7, 0x67B4, 0x96A1, 0x67B5, 0xE8D5, 0x67B6, 0xBCDC, 0x67B7, 0xBCCF, 0x67B8, 0xE8DB, 0x67B9, 0x96A2, 0x67BA, 0x96A3, 0x67BB, 0x96A4, 0x67BC, 0x96A5, 0x67BD, 0x96A6, 0x67BE, 0x96A7, 0x67BF, 0x96A8, 0x67C0, 0x96A9, 0x67C1, 0xE8DE, 0x67C2, 0x96AA, 0x67C3, 0xE8DA, 0x67C4, 0xB1FA, 0x67C5, 0x96AB, 0x67C6, 0x96AC, 0x67C7, 0x96AD, 0x67C8, 0x96AE, 0x67C9, 0x96AF, 0x67CA, 0x96B0, 0x67CB, 0x96B1, 0x67CC, 0x96B2, 0x67CD, 0x96B3, 0x67CE, 0x96B4, 0x67CF, 0xB0D8, 0x67D0, 0xC4B3, 0x67D1, 0xB8CC, 0x67D2, 0xC6E2, 0x67D3, 0xC8BE, 0x67D4, 0xC8E1, 0x67D5, 0x96B5, 0x67D6, 0x96B6, 0x67D7, 0x96B7, 0x67D8, 0xE8CF, 0x67D9, 0xE8D4, 0x67DA, 0xE8D6, 0x67DB, 0x96B8, 0x67DC, 0xB9F1, 0x67DD, 0xE8D8, 0x67DE, 0xD7F5, 0x67DF, 0x96B9, 0x67E0, 0xC4FB, 0x67E1, 0x96BA, 0x67E2, 0xE8DC, 0x67E3, 0x96BB, 0x67E4, 0x96BC, 0x67E5, 0xB2E9, 0x67E6, 0x96BD, 0x67E7, 0x96BE, 0x67E8, 0x96BF, 0x67E9, 0xE8D1, 0x67EA, 0x96C0, 0x67EB, 0x96C1, 0x67EC, 0xBCED, 0x67ED, 0x96C2, 0x67EE, 0x96C3, 0x67EF, 0xBFC2, 0x67F0, 0xE8CD, 0x67F1, 0xD6F9, 0x67F2, 0x96C4, 0x67F3, 0xC1F8, 0x67F4, 0xB2F1, 0x67F5, 0x96C5, 0x67F6, 0x96C6, 0x67F7, 0x96C7, 0x67F8, 0x96C8, 0x67F9, 0x96C9, 0x67FA, 0x96CA, 0x67FB, 0x96CB, 0x67FC, 0x96CC, 0x67FD, 0xE8DF, 0x67FE, 0x96CD, 0x67FF, 0xCAC1, 0x6800, 0xE8D9, 0x6801, 0x96CE, 0x6802, 0x96CF, 0x6803, 0x96D0, 0x6804, 0x96D1, 0x6805, 0xD5A4, 0x6806, 0x96D2, 0x6807, 0xB1EA, 0x6808, 0xD5BB, 0x6809, 0xE8CE, 0x680A, 0xE8D0, 0x680B, 0xB6B0, 0x680C, 0xE8D3, 0x680D, 0x96D3, 0x680E, 0xE8DD, 0x680F, 0xC0B8, 0x6810, 0x96D4, 0x6811, 0xCAF7, 0x6812, 0x96D5, 0x6813, 0xCBA8, 0x6814, 0x96D6, 0x6815, 0x96D7, 0x6816, 0xC6DC, 0x6817, 0xC0F5, 0x6818, 0x96D8, 0x6819, 0x96D9, 0x681A, 0x96DA, 0x681B, 0x96DB, 0x681C, 0x96DC, 0x681D, 0xE8E9, 0x681E, 0x96DD, 0x681F, 0x96DE, 0x6820, 0x96DF, 0x6821, 0xD0A3, 0x6822, 0x96E0, 0x6823, 0x96E1, 0x6824, 0x96E2, 0x6825, 0x96E3, 0x6826, 0x96E4, 0x6827, 0x96E5, 0x6828, 0x96E6, 0x6829, 0xE8F2, 0x682A, 0xD6EA, 0x682B, 0x96E7, 0x682C, 0x96E8, 0x682D, 0x96E9, 0x682E, 0x96EA, 0x682F, 0x96EB, 0x6830, 0x96EC, 0x6831, 0x96ED, 0x6832, 0xE8E0, 0x6833, 0xE8E1, 0x6834, 0x96EE, 0x6835, 0x96EF, 0x6836, 0x96F0, 0x6837, 0xD1F9, 0x6838, 0xBACB, 0x6839, 0xB8F9, 0x683A, 0x96F1, 0x683B, 0x96F2, 0x683C, 0xB8F1, 0x683D, 0xD4D4, 0x683E, 0xE8EF, 0x683F, 0x96F3, 0x6840, 0xE8EE, 0x6841, 0xE8EC, 0x6842, 0xB9F0, 0x6843, 0xCCD2, 0x6844, 0xE8E6, 0x6845, 0xCEA6, 0x6846, 0xBFF2, 0x6847, 0x96F4, 0x6848, 0xB0B8, 0x6849, 0xE8F1, 0x684A, 0xE8F0, 0x684B, 0x96F5, 0x684C, 0xD7C0, 0x684D, 0x96F6, 0x684E, 0xE8E4, 0x684F, 0x96F7, 0x6850, 0xCDA9, 0x6851, 0xC9A3, 0x6852, 0x96F8, 0x6853, 0xBBB8, 0x6854, 0xBDDB, 0x6855, 0xE8EA, 0x6856, 0x96F9, 0x6857, 0x96FA, 0x6858, 0x96FB, 0x6859, 0x96FC, 0x685A, 0x96FD, 0x685B, 0x96FE, 0x685C, 0x9740, 0x685D, 0x9741, 0x685E, 0x9742, 0x685F, 0x9743, 0x6860, 0xE8E2, 0x6861, 0xE8E3, 0x6862, 0xE8E5, 0x6863, 0xB5B5, 0x6864, 0xE8E7, 0x6865, 0xC7C5, 0x6866, 0xE8EB, 0x6867, 0xE8ED, 0x6868, 0xBDB0, 0x6869, 0xD7AE, 0x686A, 0x9744, 0x686B, 0xE8F8, 0x686C, 0x9745, 0x686D, 0x9746, 0x686E, 0x9747, 0x686F, 0x9748, 0x6870, 0x9749, 0x6871, 0x974A, 0x6872, 0x974B, 0x6873, 0x974C, 0x6874, 0xE8F5, 0x6875, 0x974D, 0x6876, 0xCDB0, 0x6877, 0xE8F6, 0x6878, 0x974E, 0x6879, 0x974F, 0x687A, 0x9750, 0x687B, 0x9751, 0x687C, 0x9752, 0x687D, 0x9753, 0x687E, 0x9754, 0x687F, 0x9755, 0x6880, 0x9756, 0x6881, 0xC1BA, 0x6882, 0x9757, 0x6883, 0xE8E8, 0x6884, 0x9758, 0x6885, 0xC3B7, 0x6886, 0xB0F0, 0x6887, 0x9759, 0x6888, 0x975A, 0x6889, 0x975B, 0x688A, 0x975C, 0x688B, 0x975D, 0x688C, 0x975E, 0x688D, 0x975F, 0x688E, 0x9760, 0x688F, 0xE8F4, 0x6890, 0x9761, 0x6891, 0x9762, 0x6892, 0x9763, 0x6893, 0xE8F7, 0x6894, 0x9764, 0x6895, 0x9765, 0x6896, 0x9766, 0x6897, 0xB9A3, 0x6898, 0x9767, 0x6899, 0x9768, 0x689A, 0x9769, 0x689B, 0x976A, 0x689C, 0x976B, 0x689D, 0x976C, 0x689E, 0x976D, 0x689F, 0x976E, 0x68A0, 0x976F, 0x68A1, 0x9770, 0x68A2, 0xC9D2, 0x68A3, 0x9771, 0x68A4, 0x9772, 0x68A5, 0x9773, 0x68A6, 0xC3CE, 0x68A7, 0xCEE0, 0x68A8, 0xC0E6, 0x68A9, 0x9774, 0x68AA, 0x9775, 0x68AB, 0x9776, 0x68AC, 0x9777, 0x68AD, 0xCBF3, 0x68AE, 0x9778, 0x68AF, 0xCCDD, 0x68B0, 0xD0B5, 0x68B1, 0x9779, 0x68B2, 0x977A, 0x68B3, 0xCAE1, 0x68B4, 0x977B, 0x68B5, 0xE8F3, 0x68B6, 0x977C, 0x68B7, 0x977D, 0x68B8, 0x977E, 0x68B9, 0x9780, 0x68BA, 0x9781, 0x68BB, 0x9782, 0x68BC, 0x9783, 0x68BD, 0x9784, 0x68BE, 0x9785, 0x68BF, 0x9786, 0x68C0, 0xBCEC, 0x68C1, 0x9787, 0x68C2, 0xE8F9, 0x68C3, 0x9788, 0x68C4, 0x9789, 0x68C5, 0x978A, 0x68C6, 0x978B, 0x68C7, 0x978C, 0x68C8, 0x978D, 0x68C9, 0xC3DE, 0x68CA, 0x978E, 0x68CB, 0xC6E5, 0x68CC, 0x978F, 0x68CD, 0xB9F7, 0x68CE, 0x9790, 0x68CF, 0x9791, 0x68D0, 0x9792, 0x68D1, 0x9793, 0x68D2, 0xB0F4, 0x68D3, 0x9794, 0x68D4, 0x9795, 0x68D5, 0xD7D8, 0x68D6, 0x9796, 0x68D7, 0x9797, 0x68D8, 0xBCAC, 0x68D9, 0x9798, 0x68DA, 0xC5EF, 0x68DB, 0x9799, 0x68DC, 0x979A, 0x68DD, 0x979B, 0x68DE, 0x979C, 0x68DF, 0x979D, 0x68E0, 0xCCC4, 0x68E1, 0x979E, 0x68E2, 0x979F, 0x68E3, 0xE9A6, 0x68E4, 0x97A0, 0x68E5, 0x97A1, 0x68E6, 0x97A2, 0x68E7, 0x97A3, 0x68E8, 0x97A4, 0x68E9, 0x97A5, 0x68EA, 0x97A6, 0x68EB, 0x97A7, 0x68EC, 0x97A8, 0x68ED, 0x97A9, 0x68EE, 0xC9AD, 0x68EF, 0x97AA, 0x68F0, 0xE9A2, 0x68F1, 0xC0E2, 0x68F2, 0x97AB, 0x68F3, 0x97AC, 0x68F4, 0x97AD, 0x68F5, 0xBFC3, 0x68F6, 0x97AE, 0x68F7, 0x97AF, 0x68F8, 0x97B0, 0x68F9, 0xE8FE, 0x68FA, 0xB9D7, 0x68FB, 0x97B1, 0x68FC, 0xE8FB, 0x68FD, 0x97B2, 0x68FE, 0x97B3, 0x68FF, 0x97B4, 0x6900, 0x97B5, 0x6901, 0xE9A4, 0x6902, 0x97B6, 0x6903, 0x97B7, 0x6904, 0x97B8, 0x6905, 0xD2CE, 0x6906, 0x97B9, 0x6907, 0x97BA, 0x6908, 0x97BB, 0x6909, 0x97BC, 0x690A, 0x97BD, 0x690B, 0xE9A3, 0x690C, 0x97BE, 0x690D, 0xD6B2, 0x690E, 0xD7B5, 0x690F, 0x97BF, 0x6910, 0xE9A7, 0x6911, 0x97C0, 0x6912, 0xBDB7, 0x6913, 0x97C1, 0x6914, 0x97C2, 0x6915, 0x97C3, 0x6916, 0x97C4, 0x6917, 0x97C5, 0x6918, 0x97C6, 0x6919, 0x97C7, 0x691A, 0x97C8, 0x691B, 0x97C9, 0x691C, 0x97CA, 0x691D, 0x97CB, 0x691E, 0x97CC, 0x691F, 0xE8FC, 0x6920, 0xE8FD, 0x6921, 0x97CD, 0x6922, 0x97CE, 0x6923, 0x97CF, 0x6924, 0xE9A1, 0x6925, 0x97D0, 0x6926, 0x97D1, 0x6927, 0x97D2, 0x6928, 0x97D3, 0x6929, 0x97D4, 0x692A, 0x97D5, 0x692B, 0x97D6, 0x692C, 0x97D7, 0x692D, 0xCDD6, 0x692E, 0x97D8, 0x692F, 0x97D9, 0x6930, 0xD2AC, 0x6931, 0x97DA, 0x6932, 0x97DB, 0x6933, 0x97DC, 0x6934, 0xE9B2, 0x6935, 0x97DD, 0x6936, 0x97DE, 0x6937, 0x97DF, 0x6938, 0x97E0, 0x6939, 0xE9A9, 0x693A, 0x97E1, 0x693B, 0x97E2, 0x693C, 0x97E3, 0x693D, 0xB4AA, 0x693E, 0x97E4, 0x693F, 0xB4BB, 0x6940, 0x97E5, 0x6941, 0x97E6, 0x6942, 0xE9AB, 0x6943, 0x97E7, 0x6944, 0x97E8, 0x6945, 0x97E9, 0x6946, 0x97EA, 0x6947, 0x97EB, 0x6948, 0x97EC, 0x6949, 0x97ED, 0x694A, 0x97EE, 0x694B, 0x97EF, 0x694C, 0x97F0, 0x694D, 0x97F1, 0x694E, 0x97F2, 0x694F, 0x97F3, 0x6950, 0x97F4, 0x6951, 0x97F5, 0x6952, 0x97F6, 0x6953, 0x97F7, 0x6954, 0xD0A8, 0x6955, 0x97F8, 0x6956, 0x97F9, 0x6957, 0xE9A5, 0x6958, 0x97FA, 0x6959, 0x97FB, 0x695A, 0xB3FE, 0x695B, 0x97FC, 0x695C, 0x97FD, 0x695D, 0xE9AC, 0x695E, 0xC0E3, 0x695F, 0x97FE, 0x6960, 0xE9AA, 0x6961, 0x9840, 0x6962, 0x9841, 0x6963, 0xE9B9, 0x6964, 0x9842, 0x6965, 0x9843, 0x6966, 0xE9B8, 0x6967, 0x9844, 0x6968, 0x9845, 0x6969, 0x9846, 0x696A, 0x9847, 0x696B, 0xE9AE, 0x696C, 0x9848, 0x696D, 0x9849, 0x696E, 0xE8FA, 0x696F, 0x984A, 0x6970, 0x984B, 0x6971, 0xE9A8, 0x6972, 0x984C, 0x6973, 0x984D, 0x6974, 0x984E, 0x6975, 0x984F, 0x6976, 0x9850, 0x6977, 0xBFAC, 0x6978, 0xE9B1, 0x6979, 0xE9BA, 0x697A, 0x9851, 0x697B, 0x9852, 0x697C, 0xC2A5, 0x697D, 0x9853, 0x697E, 0x9854, 0x697F, 0x9855, 0x6980, 0xE9AF, 0x6981, 0x9856, 0x6982, 0xB8C5, 0x6983, 0x9857, 0x6984, 0xE9AD, 0x6985, 0x9858, 0x6986, 0xD3DC, 0x6987, 0xE9B4, 0x6988, 0xE9B5, 0x6989, 0xE9B7, 0x698A, 0x9859, 0x698B, 0x985A, 0x698C, 0x985B, 0x698D, 0xE9C7, 0x698E, 0x985C, 0x698F, 0x985D, 0x6990, 0x985E, 0x6991, 0x985F, 0x6992, 0x9860, 0x6993, 0x9861, 0x6994, 0xC0C6, 0x6995, 0xE9C5, 0x6996, 0x9862, 0x6997, 0x9863, 0x6998, 0xE9B0, 0x6999, 0x9864, 0x699A, 0x9865, 0x699B, 0xE9BB, 0x699C, 0xB0F1, 0x699D, 0x9866, 0x699E, 0x9867, 0x699F, 0x9868, 0x69A0, 0x9869, 0x69A1, 0x986A, 0x69A2, 0x986B, 0x69A3, 0x986C, 0x69A4, 0x986D, 0x69A5, 0x986E, 0x69A6, 0x986F, 0x69A7, 0xE9BC, 0x69A8, 0xD5A5, 0x69A9, 0x9870, 0x69AA, 0x9871, 0x69AB, 0xE9BE, 0x69AC, 0x9872, 0x69AD, 0xE9BF, 0x69AE, 0x9873, 0x69AF, 0x9874, 0x69B0, 0x9875, 0x69B1, 0xE9C1, 0x69B2, 0x9876, 0x69B3, 0x9877, 0x69B4, 0xC1F1, 0x69B5, 0x9878, 0x69B6, 0x9879, 0x69B7, 0xC8B6, 0x69B8, 0x987A, 0x69B9, 0x987B, 0x69BA, 0x987C, 0x69BB, 0xE9BD, 0x69BC, 0x987D, 0x69BD, 0x987E, 0x69BE, 0x9880, 0x69BF, 0x9881, 0x69C0, 0x9882, 0x69C1, 0xE9C2, 0x69C2, 0x9883, 0x69C3, 0x9884, 0x69C4, 0x9885, 0x69C5, 0x9886, 0x69C6, 0x9887, 0x69C7, 0x9888, 0x69C8, 0x9889, 0x69C9, 0x988A, 0x69CA, 0xE9C3, 0x69CB, 0x988B, 0x69CC, 0xE9B3, 0x69CD, 0x988C, 0x69CE, 0xE9B6, 0x69CF, 0x988D, 0x69D0, 0xBBB1, 0x69D1, 0x988E, 0x69D2, 0x988F, 0x69D3, 0x9890, 0x69D4, 0xE9C0, 0x69D5, 0x9891, 0x69D6, 0x9892, 0x69D7, 0x9893, 0x69D8, 0x9894, 0x69D9, 0x9895, 0x69DA, 0x9896, 0x69DB, 0xBCF7, 0x69DC, 0x9897, 0x69DD, 0x9898, 0x69DE, 0x9899, 0x69DF, 0xE9C4, 0x69E0, 0xE9C6, 0x69E1, 0x989A, 0x69E2, 0x989B, 0x69E3, 0x989C, 0x69E4, 0x989D, 0x69E5, 0x989E, 0x69E6, 0x989F, 0x69E7, 0x98A0, 0x69E8, 0x98A1, 0x69E9, 0x98A2, 0x69EA, 0x98A3, 0x69EB, 0x98A4, 0x69EC, 0x98A5, 0x69ED, 0xE9CA, 0x69EE, 0x98A6, 0x69EF, 0x98A7, 0x69F0, 0x98A8, 0x69F1, 0x98A9, 0x69F2, 0xE9CE, 0x69F3, 0x98AA, 0x69F4, 0x98AB, 0x69F5, 0x98AC, 0x69F6, 0x98AD, 0x69F7, 0x98AE, 0x69F8, 0x98AF, 0x69F9, 0x98B0, 0x69FA, 0x98B1, 0x69FB, 0x98B2, 0x69FC, 0x98B3, 0x69FD, 0xB2DB, 0x69FE, 0x98B4, 0x69FF, 0xE9C8, 0x6A00, 0x98B5, 0x6A01, 0x98B6, 0x6A02, 0x98B7, 0x6A03, 0x98B8, 0x6A04, 0x98B9, 0x6A05, 0x98BA, 0x6A06, 0x98BB, 0x6A07, 0x98BC, 0x6A08, 0x98BD, 0x6A09, 0x98BE, 0x6A0A, 0xB7AE, 0x6A0B, 0x98BF, 0x6A0C, 0x98C0, 0x6A0D, 0x98C1, 0x6A0E, 0x98C2, 0x6A0F, 0x98C3, 0x6A10, 0x98C4, 0x6A11, 0x98C5, 0x6A12, 0x98C6, 0x6A13, 0x98C7, 0x6A14, 0x98C8, 0x6A15, 0x98C9, 0x6A16, 0x98CA, 0x6A17, 0xE9CB, 0x6A18, 0xE9CC, 0x6A19, 0x98CB, 0x6A1A, 0x98CC, 0x6A1B, 0x98CD, 0x6A1C, 0x98CE, 0x6A1D, 0x98CF, 0x6A1E, 0x98D0, 0x6A1F, 0xD5C1, 0x6A20, 0x98D1, 0x6A21, 0xC4A3, 0x6A22, 0x98D2, 0x6A23, 0x98D3, 0x6A24, 0x98D4, 0x6A25, 0x98D5, 0x6A26, 0x98D6, 0x6A27, 0x98D7, 0x6A28, 0xE9D8, 0x6A29, 0x98D8, 0x6A2A, 0xBAE1, 0x6A2B, 0x98D9, 0x6A2C, 0x98DA, 0x6A2D, 0x98DB, 0x6A2E, 0x98DC, 0x6A2F, 0xE9C9, 0x6A30, 0x98DD, 0x6A31, 0xD3A3, 0x6A32, 0x98DE, 0x6A33, 0x98DF, 0x6A34, 0x98E0, 0x6A35, 0xE9D4, 0x6A36, 0x98E1, 0x6A37, 0x98E2, 0x6A38, 0x98E3, 0x6A39, 0x98E4, 0x6A3A, 0x98E5, 0x6A3B, 0x98E6, 0x6A3C, 0x98E7, 0x6A3D, 0xE9D7, 0x6A3E, 0xE9D0, 0x6A3F, 0x98E8, 0x6A40, 0x98E9, 0x6A41, 0x98EA, 0x6A42, 0x98EB, 0x6A43, 0x98EC, 0x6A44, 0xE9CF, 0x6A45, 0x98ED, 0x6A46, 0x98EE, 0x6A47, 0xC7C1, 0x6A48, 0x98EF, 0x6A49, 0x98F0, 0x6A4A, 0x98F1, 0x6A4B, 0x98F2, 0x6A4C, 0x98F3, 0x6A4D, 0x98F4, 0x6A4E, 0x98F5, 0x6A4F, 0x98F6, 0x6A50, 0xE9D2, 0x6A51, 0x98F7, 0x6A52, 0x98F8, 0x6A53, 0x98F9, 0x6A54, 0x98FA, 0x6A55, 0x98FB, 0x6A56, 0x98FC, 0x6A57, 0x98FD, 0x6A58, 0xE9D9, 0x6A59, 0xB3C8, 0x6A5A, 0x98FE, 0x6A5B, 0xE9D3, 0x6A5C, 0x9940, 0x6A5D, 0x9941, 0x6A5E, 0x9942, 0x6A5F, 0x9943, 0x6A60, 0x9944, 0x6A61, 0xCFF0, 0x6A62, 0x9945, 0x6A63, 0x9946, 0x6A64, 0x9947, 0x6A65, 0xE9CD, 0x6A66, 0x9948, 0x6A67, 0x9949, 0x6A68, 0x994A, 0x6A69, 0x994B, 0x6A6A, 0x994C, 0x6A6B, 0x994D, 0x6A6C, 0x994E, 0x6A6D, 0x994F, 0x6A6E, 0x9950, 0x6A6F, 0x9951, 0x6A70, 0x9952, 0x6A71, 0xB3F7, 0x6A72, 0x9953, 0x6A73, 0x9954, 0x6A74, 0x9955, 0x6A75, 0x9956, 0x6A76, 0x9957, 0x6A77, 0x9958, 0x6A78, 0x9959, 0x6A79, 0xE9D6, 0x6A7A, 0x995A, 0x6A7B, 0x995B, 0x6A7C, 0xE9DA, 0x6A7D, 0x995C, 0x6A7E, 0x995D, 0x6A7F, 0x995E, 0x6A80, 0xCCB4, 0x6A81, 0x995F, 0x6A82, 0x9960, 0x6A83, 0x9961, 0x6A84, 0xCFAD, 0x6A85, 0x9962, 0x6A86, 0x9963, 0x6A87, 0x9964, 0x6A88, 0x9965, 0x6A89, 0x9966, 0x6A8A, 0x9967, 0x6A8B, 0x9968, 0x6A8C, 0x9969, 0x6A8D, 0x996A, 0x6A8E, 0xE9D5, 0x6A8F, 0x996B, 0x6A90, 0xE9DC, 0x6A91, 0xE9DB, 0x6A92, 0x996C, 0x6A93, 0x996D, 0x6A94, 0x996E, 0x6A95, 0x996F, 0x6A96, 0x9970, 0x6A97, 0xE9DE, 0x6A98, 0x9971, 0x6A99, 0x9972, 0x6A9A, 0x9973, 0x6A9B, 0x9974, 0x6A9C, 0x9975, 0x6A9D, 0x9976, 0x6A9E, 0x9977, 0x6A9F, 0x9978, 0x6AA0, 0xE9D1, 0x6AA1, 0x9979, 0x6AA2, 0x997A, 0x6AA3, 0x997B, 0x6AA4, 0x997C, 0x6AA5, 0x997D, 0x6AA6, 0x997E, 0x6AA7, 0x9980, 0x6AA8, 0x9981, 0x6AA9, 0xE9DD, 0x6AAA, 0x9982, 0x6AAB, 0xE9DF, 0x6AAC, 0xC3CA, 0x6AAD, 0x9983, 0x6AAE, 0x9984, 0x6AAF, 0x9985, 0x6AB0, 0x9986, 0x6AB1, 0x9987, 0x6AB2, 0x9988, 0x6AB3, 0x9989, 0x6AB4, 0x998A, 0x6AB5, 0x998B, 0x6AB6, 0x998C, 0x6AB7, 0x998D, 0x6AB8, 0x998E, 0x6AB9, 0x998F, 0x6ABA, 0x9990, 0x6ABB, 0x9991, 0x6ABC, 0x9992, 0x6ABD, 0x9993, 0x6ABE, 0x9994, 0x6ABF, 0x9995, 0x6AC0, 0x9996, 0x6AC1, 0x9997, 0x6AC2, 0x9998, 0x6AC3, 0x9999, 0x6AC4, 0x999A, 0x6AC5, 0x999B, 0x6AC6, 0x999C, 0x6AC7, 0x999D, 0x6AC8, 0x999E, 0x6AC9, 0x999F, 0x6ACA, 0x99A0, 0x6ACB, 0x99A1, 0x6ACC, 0x99A2, 0x6ACD, 0x99A3, 0x6ACE, 0x99A4, 0x6ACF, 0x99A5, 0x6AD0, 0x99A6, 0x6AD1, 0x99A7, 0x6AD2, 0x99A8, 0x6AD3, 0x99A9, 0x6AD4, 0x99AA, 0x6AD5, 0x99AB, 0x6AD6, 0x99AC, 0x6AD7, 0x99AD, 0x6AD8, 0x99AE, 0x6AD9, 0x99AF, 0x6ADA, 0x99B0, 0x6ADB, 0x99B1, 0x6ADC, 0x99B2, 0x6ADD, 0x99B3, 0x6ADE, 0x99B4, 0x6ADF, 0x99B5, 0x6AE0, 0x99B6, 0x6AE1, 0x99B7, 0x6AE2, 0x99B8, 0x6AE3, 0x99B9, 0x6AE4, 0x99BA, 0x6AE5, 0x99BB, 0x6AE6, 0x99BC, 0x6AE7, 0x99BD, 0x6AE8, 0x99BE, 0x6AE9, 0x99BF, 0x6AEA, 0x99C0, 0x6AEB, 0x99C1, 0x6AEC, 0x99C2, 0x6AED, 0x99C3, 0x6AEE, 0x99C4, 0x6AEF, 0x99C5, 0x6AF0, 0x99C6, 0x6AF1, 0x99C7, 0x6AF2, 0x99C8, 0x6AF3, 0x99C9, 0x6AF4, 0x99CA, 0x6AF5, 0x99CB, 0x6AF6, 0x99CC, 0x6AF7, 0x99CD, 0x6AF8, 0x99CE, 0x6AF9, 0x99CF, 0x6AFA, 0x99D0, 0x6AFB, 0x99D1, 0x6AFC, 0x99D2, 0x6AFD, 0x99D3, 0x6AFE, 0x99D4, 0x6AFF, 0x99D5, 0x6B00, 0x99D6, 0x6B01, 0x99D7, 0x6B02, 0x99D8, 0x6B03, 0x99D9, 0x6B04, 0x99DA, 0x6B05, 0x99DB, 0x6B06, 0x99DC, 0x6B07, 0x99DD, 0x6B08, 0x99DE, 0x6B09, 0x99DF, 0x6B0A, 0x99E0, 0x6B0B, 0x99E1, 0x6B0C, 0x99E2, 0x6B0D, 0x99E3, 0x6B0E, 0x99E4, 0x6B0F, 0x99E5, 0x6B10, 0x99E6, 0x6B11, 0x99E7, 0x6B12, 0x99E8, 0x6B13, 0x99E9, 0x6B14, 0x99EA, 0x6B15, 0x99EB, 0x6B16, 0x99EC, 0x6B17, 0x99ED, 0x6B18, 0x99EE, 0x6B19, 0x99EF, 0x6B1A, 0x99F0, 0x6B1B, 0x99F1, 0x6B1C, 0x99F2, 0x6B1D, 0x99F3, 0x6B1E, 0x99F4, 0x6B1F, 0x99F5, 0x6B20, 0xC7B7, 0x6B21, 0xB4CE, 0x6B22, 0xBBB6, 0x6B23, 0xD0C0, 0x6B24, 0xECA3, 0x6B25, 0x99F6, 0x6B26, 0x99F7, 0x6B27, 0xC5B7, 0x6B28, 0x99F8, 0x6B29, 0x99F9, 0x6B2A, 0x99FA, 0x6B2B, 0x99FB, 0x6B2C, 0x99FC, 0x6B2D, 0x99FD, 0x6B2E, 0x99FE, 0x6B2F, 0x9A40, 0x6B30, 0x9A41, 0x6B31, 0x9A42, 0x6B32, 0xD3FB, 0x6B33, 0x9A43, 0x6B34, 0x9A44, 0x6B35, 0x9A45, 0x6B36, 0x9A46, 0x6B37, 0xECA4, 0x6B38, 0x9A47, 0x6B39, 0xECA5, 0x6B3A, 0xC6DB, 0x6B3B, 0x9A48, 0x6B3C, 0x9A49, 0x6B3D, 0x9A4A, 0x6B3E, 0xBFEE, 0x6B3F, 0x9A4B, 0x6B40, 0x9A4C, 0x6B41, 0x9A4D, 0x6B42, 0x9A4E, 0x6B43, 0xECA6, 0x6B44, 0x9A4F, 0x6B45, 0x9A50, 0x6B46, 0xECA7, 0x6B47, 0xD0AA, 0x6B48, 0x9A51, 0x6B49, 0xC7B8, 0x6B4A, 0x9A52, 0x6B4B, 0x9A53, 0x6B4C, 0xB8E8, 0x6B4D, 0x9A54, 0x6B4E, 0x9A55, 0x6B4F, 0x9A56, 0x6B50, 0x9A57, 0x6B51, 0x9A58, 0x6B52, 0x9A59, 0x6B53, 0x9A5A, 0x6B54, 0x9A5B, 0x6B55, 0x9A5C, 0x6B56, 0x9A5D, 0x6B57, 0x9A5E, 0x6B58, 0x9A5F, 0x6B59, 0xECA8, 0x6B5A, 0x9A60, 0x6B5B, 0x9A61, 0x6B5C, 0x9A62, 0x6B5D, 0x9A63, 0x6B5E, 0x9A64, 0x6B5F, 0x9A65, 0x6B60, 0x9A66, 0x6B61, 0x9A67, 0x6B62, 0xD6B9, 0x6B63, 0xD5FD, 0x6B64, 0xB4CB, 0x6B65, 0xB2BD, 0x6B66, 0xCEE4, 0x6B67, 0xC6E7, 0x6B68, 0x9A68, 0x6B69, 0x9A69, 0x6B6A, 0xCDE1, 0x6B6B, 0x9A6A, 0x6B6C, 0x9A6B, 0x6B6D, 0x9A6C, 0x6B6E, 0x9A6D, 0x6B6F, 0x9A6E, 0x6B70, 0x9A6F, 0x6B71, 0x9A70, 0x6B72, 0x9A71, 0x6B73, 0x9A72, 0x6B74, 0x9A73, 0x6B75, 0x9A74, 0x6B76, 0x9A75, 0x6B77, 0x9A76, 0x6B78, 0x9A77, 0x6B79, 0xB4F5, 0x6B7A, 0x9A78, 0x6B7B, 0xCBC0, 0x6B7C, 0xBCDF, 0x6B7D, 0x9A79, 0x6B7E, 0x9A7A, 0x6B7F, 0x9A7B, 0x6B80, 0x9A7C, 0x6B81, 0xE9E2, 0x6B82, 0xE9E3, 0x6B83, 0xD1EA, 0x6B84, 0xE9E5, 0x6B85, 0x9A7D, 0x6B86, 0xB4F9, 0x6B87, 0xE9E4, 0x6B88, 0x9A7E, 0x6B89, 0xD1B3, 0x6B8A, 0xCAE2, 0x6B8B, 0xB2D0, 0x6B8C, 0x9A80, 0x6B8D, 0xE9E8, 0x6B8E, 0x9A81, 0x6B8F, 0x9A82, 0x6B90, 0x9A83, 0x6B91, 0x9A84, 0x6B92, 0xE9E6, 0x6B93, 0xE9E7, 0x6B94, 0x9A85, 0x6B95, 0x9A86, 0x6B96, 0xD6B3, 0x6B97, 0x9A87, 0x6B98, 0x9A88, 0x6B99, 0x9A89, 0x6B9A, 0xE9E9, 0x6B9B, 0xE9EA, 0x6B9C, 0x9A8A, 0x6B9D, 0x9A8B, 0x6B9E, 0x9A8C, 0x6B9F, 0x9A8D, 0x6BA0, 0x9A8E, 0x6BA1, 0xE9EB, 0x6BA2, 0x9A8F, 0x6BA3, 0x9A90, 0x6BA4, 0x9A91, 0x6BA5, 0x9A92, 0x6BA6, 0x9A93, 0x6BA7, 0x9A94, 0x6BA8, 0x9A95, 0x6BA9, 0x9A96, 0x6BAA, 0xE9EC, 0x6BAB, 0x9A97, 0x6BAC, 0x9A98, 0x6BAD, 0x9A99, 0x6BAE, 0x9A9A, 0x6BAF, 0x9A9B, 0x6BB0, 0x9A9C, 0x6BB1, 0x9A9D, 0x6BB2, 0x9A9E, 0x6BB3, 0xECAF, 0x6BB4, 0xC5B9, 0x6BB5, 0xB6CE, 0x6BB6, 0x9A9F, 0x6BB7, 0xD2F3, 0x6BB8, 0x9AA0, 0x6BB9, 0x9AA1, 0x6BBA, 0x9AA2, 0x6BBB, 0x9AA3, 0x6BBC, 0x9AA4, 0x6BBD, 0x9AA5, 0x6BBE, 0x9AA6, 0x6BBF, 0xB5EE, 0x6BC0, 0x9AA7, 0x6BC1, 0xBBD9, 0x6BC2, 0xECB1, 0x6BC3, 0x9AA8, 0x6BC4, 0x9AA9, 0x6BC5, 0xD2E3, 0x6BC6, 0x9AAA, 0x6BC7, 0x9AAB, 0x6BC8, 0x9AAC, 0x6BC9, 0x9AAD, 0x6BCA, 0x9AAE, 0x6BCB, 0xCEE3, 0x6BCC, 0x9AAF, 0x6BCD, 0xC4B8, 0x6BCE, 0x9AB0, 0x6BCF, 0xC3BF, 0x6BD0, 0x9AB1, 0x6BD1, 0x9AB2, 0x6BD2, 0xB6BE, 0x6BD3, 0xD8B9, 0x6BD4, 0xB1C8, 0x6BD5, 0xB1CF, 0x6BD6, 0xB1D1, 0x6BD7, 0xC5FE, 0x6BD8, 0x9AB3, 0x6BD9, 0xB1D0, 0x6BDA, 0x9AB4, 0x6BDB, 0xC3AB, 0x6BDC, 0x9AB5, 0x6BDD, 0x9AB6, 0x6BDE, 0x9AB7, 0x6BDF, 0x9AB8, 0x6BE0, 0x9AB9, 0x6BE1, 0xD5B1, 0x6BE2, 0x9ABA, 0x6BE3, 0x9ABB, 0x6BE4, 0x9ABC, 0x6BE5, 0x9ABD, 0x6BE6, 0x9ABE, 0x6BE7, 0x9ABF, 0x6BE8, 0x9AC0, 0x6BE9, 0x9AC1, 0x6BEA, 0xEBA4, 0x6BEB, 0xBAC1, 0x6BEC, 0x9AC2, 0x6BED, 0x9AC3, 0x6BEE, 0x9AC4, 0x6BEF, 0xCCBA, 0x6BF0, 0x9AC5, 0x6BF1, 0x9AC6, 0x6BF2, 0x9AC7, 0x6BF3, 0xEBA5, 0x6BF4, 0x9AC8, 0x6BF5, 0xEBA7, 0x6BF6, 0x9AC9, 0x6BF7, 0x9ACA, 0x6BF8, 0x9ACB, 0x6BF9, 0xEBA8, 0x6BFA, 0x9ACC, 0x6BFB, 0x9ACD, 0x6BFC, 0x9ACE, 0x6BFD, 0xEBA6, 0x6BFE, 0x9ACF, 0x6BFF, 0x9AD0, 0x6C00, 0x9AD1, 0x6C01, 0x9AD2, 0x6C02, 0x9AD3, 0x6C03, 0x9AD4, 0x6C04, 0x9AD5, 0x6C05, 0xEBA9, 0x6C06, 0xEBAB, 0x6C07, 0xEBAA, 0x6C08, 0x9AD6, 0x6C09, 0x9AD7, 0x6C0A, 0x9AD8, 0x6C0B, 0x9AD9, 0x6C0C, 0x9ADA, 0x6C0D, 0xEBAC, 0x6C0E, 0x9ADB, 0x6C0F, 0xCACF, 0x6C10, 0xD8B5, 0x6C11, 0xC3F1, 0x6C12, 0x9ADC, 0x6C13, 0xC3A5, 0x6C14, 0xC6F8, 0x6C15, 0xEBAD, 0x6C16, 0xC4CA, 0x6C17, 0x9ADD, 0x6C18, 0xEBAE, 0x6C19, 0xEBAF, 0x6C1A, 0xEBB0, 0x6C1B, 0xB7D5, 0x6C1C, 0x9ADE, 0x6C1D, 0x9ADF, 0x6C1E, 0x9AE0, 0x6C1F, 0xB7FA, 0x6C20, 0x9AE1, 0x6C21, 0xEBB1, 0x6C22, 0xC7E2, 0x6C23, 0x9AE2, 0x6C24, 0xEBB3, 0x6C25, 0x9AE3, 0x6C26, 0xBAA4, 0x6C27, 0xD1F5, 0x6C28, 0xB0B1, 0x6C29, 0xEBB2, 0x6C2A, 0xEBB4, 0x6C2B, 0x9AE4, 0x6C2C, 0x9AE5, 0x6C2D, 0x9AE6, 0x6C2E, 0xB5AA, 0x6C2F, 0xC2C8, 0x6C30, 0xC7E8, 0x6C31, 0x9AE7, 0x6C32, 0xEBB5, 0x6C33, 0x9AE8, 0x6C34, 0xCBAE, 0x6C35, 0xE3DF, 0x6C36, 0x9AE9, 0x6C37, 0x9AEA, 0x6C38, 0xD3C0, 0x6C39, 0x9AEB, 0x6C3A, 0x9AEC, 0x6C3B, 0x9AED, 0x6C3C, 0x9AEE, 0x6C3D, 0xD9DB, 0x6C3E, 0x9AEF, 0x6C3F, 0x9AF0, 0x6C40, 0xCDA1, 0x6C41, 0xD6AD, 0x6C42, 0xC7F3, 0x6C43, 0x9AF1, 0x6C44, 0x9AF2, 0x6C45, 0x9AF3, 0x6C46, 0xD9E0, 0x6C47, 0xBBE3, 0x6C48, 0x9AF4, 0x6C49, 0xBABA, 0x6C4A, 0xE3E2, 0x6C4B, 0x9AF5, 0x6C4C, 0x9AF6, 0x6C4D, 0x9AF7, 0x6C4E, 0x9AF8, 0x6C4F, 0x9AF9, 0x6C50, 0xCFAB, 0x6C51, 0x9AFA, 0x6C52, 0x9AFB, 0x6C53, 0x9AFC, 0x6C54, 0xE3E0, 0x6C55, 0xC9C7, 0x6C56, 0x9AFD, 0x6C57, 0xBAB9, 0x6C58, 0x9AFE, 0x6C59, 0x9B40, 0x6C5A, 0x9B41, 0x6C5B, 0xD1B4, 0x6C5C, 0xE3E1, 0x6C5D, 0xC8EA, 0x6C5E, 0xB9AF, 0x6C5F, 0xBDAD, 0x6C60, 0xB3D8, 0x6C61, 0xCEDB, 0x6C62, 0x9B42, 0x6C63, 0x9B43, 0x6C64, 0xCCC0, 0x6C65, 0x9B44, 0x6C66, 0x9B45, 0x6C67, 0x9B46, 0x6C68, 0xE3E8, 0x6C69, 0xE3E9, 0x6C6A, 0xCDF4, 0x6C6B, 0x9B47, 0x6C6C, 0x9B48, 0x6C6D, 0x9B49, 0x6C6E, 0x9B4A, 0x6C6F, 0x9B4B, 0x6C70, 0xCCAD, 0x6C71, 0x9B4C, 0x6C72, 0xBCB3, 0x6C73, 0x9B4D, 0x6C74, 0xE3EA, 0x6C75, 0x9B4E, 0x6C76, 0xE3EB, 0x6C77, 0x9B4F, 0x6C78, 0x9B50, 0x6C79, 0xD0DA, 0x6C7A, 0x9B51, 0x6C7B, 0x9B52, 0x6C7C, 0x9B53, 0x6C7D, 0xC6FB, 0x6C7E, 0xB7DA, 0x6C7F, 0x9B54, 0x6C80, 0x9B55, 0x6C81, 0xC7DF, 0x6C82, 0xD2CA, 0x6C83, 0xCED6, 0x6C84, 0x9B56, 0x6C85, 0xE3E4, 0x6C86, 0xE3EC, 0x6C87, 0x9B57, 0x6C88, 0xC9F2, 0x6C89, 0xB3C1, 0x6C8A, 0x9B58, 0x6C8B, 0x9B59, 0x6C8C, 0xE3E7, 0x6C8D, 0x9B5A, 0x6C8E, 0x9B5B, 0x6C8F, 0xC6E3, 0x6C90, 0xE3E5, 0x6C91, 0x9B5C, 0x6C92, 0x9B5D, 0x6C93, 0xEDB3, 0x6C94, 0xE3E6, 0x6C95, 0x9B5E, 0x6C96, 0x9B5F, 0x6C97, 0x9B60, 0x6C98, 0x9B61, 0x6C99, 0xC9B3, 0x6C9A, 0x9B62, 0x6C9B, 0xC5E6, 0x6C9C, 0x9B63, 0x6C9D, 0x9B64, 0x6C9E, 0x9B65, 0x6C9F, 0xB9B5, 0x6CA0, 0x9B66, 0x6CA1, 0xC3BB, 0x6CA2, 0x9B67, 0x6CA3, 0xE3E3, 0x6CA4, 0xC5BD, 0x6CA5, 0xC1A4, 0x6CA6, 0xC2D9, 0x6CA7, 0xB2D7, 0x6CA8, 0x9B68, 0x6CA9, 0xE3ED, 0x6CAA, 0xBBA6, 0x6CAB, 0xC4AD, 0x6CAC, 0x9B69, 0x6CAD, 0xE3F0, 0x6CAE, 0xBEDA, 0x6CAF, 0x9B6A, 0x6CB0, 0x9B6B, 0x6CB1, 0xE3FB, 0x6CB2, 0xE3F5, 0x6CB3, 0xBAD3, 0x6CB4, 0x9B6C, 0x6CB5, 0x9B6D, 0x6CB6, 0x9B6E, 0x6CB7, 0x9B6F, 0x6CB8, 0xB7D0, 0x6CB9, 0xD3CD, 0x6CBA, 0x9B70, 0x6CBB, 0xD6CE, 0x6CBC, 0xD5D3, 0x6CBD, 0xB9C1, 0x6CBE, 0xD5B4, 0x6CBF, 0xD1D8, 0x6CC0, 0x9B71, 0x6CC1, 0x9B72, 0x6CC2, 0x9B73, 0x6CC3, 0x9B74, 0x6CC4, 0xD0B9, 0x6CC5, 0xC7F6, 0x6CC6, 0x9B75, 0x6CC7, 0x9B76, 0x6CC8, 0x9B77, 0x6CC9, 0xC8AA, 0x6CCA, 0xB2B4, 0x6CCB, 0x9B78, 0x6CCC, 0xC3DA, 0x6CCD, 0x9B79, 0x6CCE, 0x9B7A, 0x6CCF, 0x9B7B, 0x6CD0, 0xE3EE, 0x6CD1, 0x9B7C, 0x6CD2, 0x9B7D, 0x6CD3, 0xE3FC, 0x6CD4, 0xE3EF, 0x6CD5, 0xB7A8, 0x6CD6, 0xE3F7, 0x6CD7, 0xE3F4, 0x6CD8, 0x9B7E, 0x6CD9, 0x9B80, 0x6CDA, 0x9B81, 0x6CDB, 0xB7BA, 0x6CDC, 0x9B82, 0x6CDD, 0x9B83, 0x6CDE, 0xC5A2, 0x6CDF, 0x9B84, 0x6CE0, 0xE3F6, 0x6CE1, 0xC5DD, 0x6CE2, 0xB2A8, 0x6CE3, 0xC6FC, 0x6CE4, 0x9B85, 0x6CE5, 0xC4E0, 0x6CE6, 0x9B86, 0x6CE7, 0x9B87, 0x6CE8, 0xD7A2, 0x6CE9, 0x9B88, 0x6CEA, 0xC0E1, 0x6CEB, 0xE3F9, 0x6CEC, 0x9B89, 0x6CED, 0x9B8A, 0x6CEE, 0xE3FA, 0x6CEF, 0xE3FD, 0x6CF0, 0xCCA9, 0x6CF1, 0xE3F3, 0x6CF2, 0x9B8B, 0x6CF3, 0xD3BE, 0x6CF4, 0x9B8C, 0x6CF5, 0xB1C3, 0x6CF6, 0xEDB4, 0x6CF7, 0xE3F1, 0x6CF8, 0xE3F2, 0x6CF9, 0x9B8D, 0x6CFA, 0xE3F8, 0x6CFB, 0xD0BA, 0x6CFC, 0xC6C3, 0x6CFD, 0xD4F3, 0x6CFE, 0xE3FE, 0x6CFF, 0x9B8E, 0x6D00, 0x9B8F, 0x6D01, 0xBDE0, 0x6D02, 0x9B90, 0x6D03, 0x9B91, 0x6D04, 0xE4A7, 0x6D05, 0x9B92, 0x6D06, 0x9B93, 0x6D07, 0xE4A6, 0x6D08, 0x9B94, 0x6D09, 0x9B95, 0x6D0A, 0x9B96, 0x6D0B, 0xD1F3, 0x6D0C, 0xE4A3, 0x6D0D, 0x9B97, 0x6D0E, 0xE4A9, 0x6D0F, 0x9B98, 0x6D10, 0x9B99, 0x6D11, 0x9B9A, 0x6D12, 0xC8F7, 0x6D13, 0x9B9B, 0x6D14, 0x9B9C, 0x6D15, 0x9B9D, 0x6D16, 0x9B9E, 0x6D17, 0xCFB4, 0x6D18, 0x9B9F, 0x6D19, 0xE4A8, 0x6D1A, 0xE4AE, 0x6D1B, 0xC2E5, 0x6D1C, 0x9BA0, 0x6D1D, 0x9BA1, 0x6D1E, 0xB6B4, 0x6D1F, 0x9BA2, 0x6D20, 0x9BA3, 0x6D21, 0x9BA4, 0x6D22, 0x9BA5, 0x6D23, 0x9BA6, 0x6D24, 0x9BA7, 0x6D25, 0xBDF2, 0x6D26, 0x9BA8, 0x6D27, 0xE4A2, 0x6D28, 0x9BA9, 0x6D29, 0x9BAA, 0x6D2A, 0xBAE9, 0x6D2B, 0xE4AA, 0x6D2C, 0x9BAB, 0x6D2D, 0x9BAC, 0x6D2E, 0xE4AC, 0x6D2F, 0x9BAD, 0x6D30, 0x9BAE, 0x6D31, 0xB6FD, 0x6D32, 0xD6DE, 0x6D33, 0xE4B2, 0x6D34, 0x9BAF, 0x6D35, 0xE4AD, 0x6D36, 0x9BB0, 0x6D37, 0x9BB1, 0x6D38, 0x9BB2, 0x6D39, 0xE4A1, 0x6D3A, 0x9BB3, 0x6D3B, 0xBBEE, 0x6D3C, 0xCDDD, 0x6D3D, 0xC7A2, 0x6D3E, 0xC5C9, 0x6D3F, 0x9BB4, 0x6D40, 0x9BB5, 0x6D41, 0xC1F7, 0x6D42, 0x9BB6, 0x6D43, 0xE4A4, 0x6D44, 0x9BB7, 0x6D45, 0xC7B3, 0x6D46, 0xBDAC, 0x6D47, 0xBDBD, 0x6D48, 0xE4A5, 0x6D49, 0x9BB8, 0x6D4A, 0xD7C7, 0x6D4B, 0xB2E2, 0x6D4C, 0x9BB9, 0x6D4D, 0xE4AB, 0x6D4E, 0xBCC3, 0x6D4F, 0xE4AF, 0x6D50, 0x9BBA, 0x6D51, 0xBBEB, 0x6D52, 0xE4B0, 0x6D53, 0xC5A8, 0x6D54, 0xE4B1, 0x6D55, 0x9BBB, 0x6D56, 0x9BBC, 0x6D57, 0x9BBD, 0x6D58, 0x9BBE, 0x6D59, 0xD5E3, 0x6D5A, 0xBFA3, 0x6D5B, 0x9BBF, 0x6D5C, 0xE4BA, 0x6D5D, 0x9BC0, 0x6D5E, 0xE4B7, 0x6D5F, 0x9BC1, 0x6D60, 0xE4BB, 0x6D61, 0x9BC2, 0x6D62, 0x9BC3, 0x6D63, 0xE4BD, 0x6D64, 0x9BC4, 0x6D65, 0x9BC5, 0x6D66, 0xC6D6, 0x6D67, 0x9BC6, 0x6D68, 0x9BC7, 0x6D69, 0xBAC6, 0x6D6A, 0xC0CB, 0x6D6B, 0x9BC8, 0x6D6C, 0x9BC9, 0x6D6D, 0x9BCA, 0x6D6E, 0xB8A1, 0x6D6F, 0xE4B4, 0x6D70, 0x9BCB, 0x6D71, 0x9BCC, 0x6D72, 0x9BCD, 0x6D73, 0x9BCE, 0x6D74, 0xD4A1, 0x6D75, 0x9BCF, 0x6D76, 0x9BD0, 0x6D77, 0xBAA3, 0x6D78, 0xBDFE, 0x6D79, 0x9BD1, 0x6D7A, 0x9BD2, 0x6D7B, 0x9BD3, 0x6D7C, 0xE4BC, 0x6D7D, 0x9BD4, 0x6D7E, 0x9BD5, 0x6D7F, 0x9BD6, 0x6D80, 0x9BD7, 0x6D81, 0x9BD8, 0x6D82, 0xCDBF, 0x6D83, 0x9BD9, 0x6D84, 0x9BDA, 0x6D85, 0xC4F9, 0x6D86, 0x9BDB, 0x6D87, 0x9BDC, 0x6D88, 0xCFFB, 0x6D89, 0xC9E6, 0x6D8A, 0x9BDD, 0x6D8B, 0x9BDE, 0x6D8C, 0xD3BF, 0x6D8D, 0x9BDF, 0x6D8E, 0xCFD1, 0x6D8F, 0x9BE0, 0x6D90, 0x9BE1, 0x6D91, 0xE4B3, 0x6D92, 0x9BE2, 0x6D93, 0xE4B8, 0x6D94, 0xE4B9, 0x6D95, 0xCCE9, 0x6D96, 0x9BE3, 0x6D97, 0x9BE4, 0x6D98, 0x9BE5, 0x6D99, 0x9BE6, 0x6D9A, 0x9BE7, 0x6D9B, 0xCCCE, 0x6D9C, 0x9BE8, 0x6D9D, 0xC0D4, 0x6D9E, 0xE4B5, 0x6D9F, 0xC1B0, 0x6DA0, 0xE4B6, 0x6DA1, 0xCED0, 0x6DA2, 0x9BE9, 0x6DA3, 0xBBC1, 0x6DA4, 0xB5D3, 0x6DA5, 0x9BEA, 0x6DA6, 0xC8F3, 0x6DA7, 0xBDA7, 0x6DA8, 0xD5C7, 0x6DA9, 0xC9AC, 0x6DAA, 0xB8A2, 0x6DAB, 0xE4CA, 0x6DAC, 0x9BEB, 0x6DAD, 0x9BEC, 0x6DAE, 0xE4CC, 0x6DAF, 0xD1C4, 0x6DB0, 0x9BED, 0x6DB1, 0x9BEE, 0x6DB2, 0xD2BA, 0x6DB3, 0x9BEF, 0x6DB4, 0x9BF0, 0x6DB5, 0xBAAD, 0x6DB6, 0x9BF1, 0x6DB7, 0x9BF2, 0x6DB8, 0xBAD4, 0x6DB9, 0x9BF3, 0x6DBA, 0x9BF4, 0x6DBB, 0x9BF5, 0x6DBC, 0x9BF6, 0x6DBD, 0x9BF7, 0x6DBE, 0x9BF8, 0x6DBF, 0xE4C3, 0x6DC0, 0xB5ED, 0x6DC1, 0x9BF9, 0x6DC2, 0x9BFA, 0x6DC3, 0x9BFB, 0x6DC4, 0xD7CD, 0x6DC5, 0xE4C0, 0x6DC6, 0xCFFD, 0x6DC7, 0xE4BF, 0x6DC8, 0x9BFC, 0x6DC9, 0x9BFD, 0x6DCA, 0x9BFE, 0x6DCB, 0xC1DC, 0x6DCC, 0xCCCA, 0x6DCD, 0x9C40, 0x6DCE, 0x9C41, 0x6DCF, 0x9C42, 0x6DD0, 0x9C43, 0x6DD1, 0xCAE7, 0x6DD2, 0x9C44, 0x6DD3, 0x9C45, 0x6DD4, 0x9C46, 0x6DD5, 0x9C47, 0x6DD6, 0xC4D7, 0x6DD7, 0x9C48, 0x6DD8, 0xCCD4, 0x6DD9, 0xE4C8, 0x6DDA, 0x9C49, 0x6DDB, 0x9C4A, 0x6DDC, 0x9C4B, 0x6DDD, 0xE4C7, 0x6DDE, 0xE4C1, 0x6DDF, 0x9C4C, 0x6DE0, 0xE4C4, 0x6DE1, 0xB5AD, 0x6DE2, 0x9C4D, 0x6DE3, 0x9C4E, 0x6DE4, 0xD3D9, 0x6DE5, 0x9C4F, 0x6DE6, 0xE4C6, 0x6DE7, 0x9C50, 0x6DE8, 0x9C51, 0x6DE9, 0x9C52, 0x6DEA, 0x9C53, 0x6DEB, 0xD2F9, 0x6DEC, 0xB4E3, 0x6DED, 0x9C54, 0x6DEE, 0xBBB4, 0x6DEF, 0x9C55, 0x6DF0, 0x9C56, 0x6DF1, 0xC9EE, 0x6DF2, 0x9C57, 0x6DF3, 0xB4BE, 0x6DF4, 0x9C58, 0x6DF5, 0x9C59, 0x6DF6, 0x9C5A, 0x6DF7, 0xBBEC, 0x6DF8, 0x9C5B, 0x6DF9, 0xD1CD, 0x6DFA, 0x9C5C, 0x6DFB, 0xCCED, 0x6DFC, 0xEDB5, 0x6DFD, 0x9C5D, 0x6DFE, 0x9C5E, 0x6DFF, 0x9C5F, 0x6E00, 0x9C60, 0x6E01, 0x9C61, 0x6E02, 0x9C62, 0x6E03, 0x9C63, 0x6E04, 0x9C64, 0x6E05, 0xC7E5, 0x6E06, 0x9C65, 0x6E07, 0x9C66, 0x6E08, 0x9C67, 0x6E09, 0x9C68, 0x6E0A, 0xD4A8, 0x6E0B, 0x9C69, 0x6E0C, 0xE4CB, 0x6E0D, 0xD7D5, 0x6E0E, 0xE4C2, 0x6E0F, 0x9C6A, 0x6E10, 0xBDA5, 0x6E11, 0xE4C5, 0x6E12, 0x9C6B, 0x6E13, 0x9C6C, 0x6E14, 0xD3E6, 0x6E15, 0x9C6D, 0x6E16, 0xE4C9, 0x6E17, 0xC9F8, 0x6E18, 0x9C6E, 0x6E19, 0x9C6F, 0x6E1A, 0xE4BE, 0x6E1B, 0x9C70, 0x6E1C, 0x9C71, 0x6E1D, 0xD3E5, 0x6E1E, 0x9C72, 0x6E1F, 0x9C73, 0x6E20, 0xC7FE, 0x6E21, 0xB6C9, 0x6E22, 0x9C74, 0x6E23, 0xD4FC, 0x6E24, 0xB2B3, 0x6E25, 0xE4D7, 0x6E26, 0x9C75, 0x6E27, 0x9C76, 0x6E28, 0x9C77, 0x6E29, 0xCEC2, 0x6E2A, 0x9C78, 0x6E2B, 0xE4CD, 0x6E2C, 0x9C79, 0x6E2D, 0xCEBC, 0x6E2E, 0x9C7A, 0x6E2F, 0xB8DB, 0x6E30, 0x9C7B, 0x6E31, 0x9C7C, 0x6E32, 0xE4D6, 0x6E33, 0x9C7D, 0x6E34, 0xBFCA, 0x6E35, 0x9C7E, 0x6E36, 0x9C80, 0x6E37, 0x9C81, 0x6E38, 0xD3CE, 0x6E39, 0x9C82, 0x6E3A, 0xC3EC, 0x6E3B, 0x9C83, 0x6E3C, 0x9C84, 0x6E3D, 0x9C85, 0x6E3E, 0x9C86, 0x6E3F, 0x9C87, 0x6E40, 0x9C88, 0x6E41, 0x9C89, 0x6E42, 0x9C8A, 0x6E43, 0xC5C8, 0x6E44, 0xE4D8, 0x6E45, 0x9C8B, 0x6E46, 0x9C8C, 0x6E47, 0x9C8D, 0x6E48, 0x9C8E, 0x6E49, 0x9C8F, 0x6E4A, 0x9C90, 0x6E4B, 0x9C91, 0x6E4C, 0x9C92, 0x6E4D, 0xCDC4, 0x6E4E, 0xE4CF, 0x6E4F, 0x9C93, 0x6E50, 0x9C94, 0x6E51, 0x9C95, 0x6E52, 0x9C96, 0x6E53, 0xE4D4, 0x6E54, 0xE4D5, 0x6E55, 0x9C97, 0x6E56, 0xBAFE, 0x6E57, 0x9C98, 0x6E58, 0xCFE6, 0x6E59, 0x9C99, 0x6E5A, 0x9C9A, 0x6E5B, 0xD5BF, 0x6E5C, 0x9C9B, 0x6E5D, 0x9C9C, 0x6E5E, 0x9C9D, 0x6E5F, 0xE4D2, 0x6E60, 0x9C9E, 0x6E61, 0x9C9F, 0x6E62, 0x9CA0, 0x6E63, 0x9CA1, 0x6E64, 0x9CA2, 0x6E65, 0x9CA3, 0x6E66, 0x9CA4, 0x6E67, 0x9CA5, 0x6E68, 0x9CA6, 0x6E69, 0x9CA7, 0x6E6A, 0x9CA8, 0x6E6B, 0xE4D0, 0x6E6C, 0x9CA9, 0x6E6D, 0x9CAA, 0x6E6E, 0xE4CE, 0x6E6F, 0x9CAB, 0x6E70, 0x9CAC, 0x6E71, 0x9CAD, 0x6E72, 0x9CAE, 0x6E73, 0x9CAF, 0x6E74, 0x9CB0, 0x6E75, 0x9CB1, 0x6E76, 0x9CB2, 0x6E77, 0x9CB3, 0x6E78, 0x9CB4, 0x6E79, 0x9CB5, 0x6E7A, 0x9CB6, 0x6E7B, 0x9CB7, 0x6E7C, 0x9CB8, 0x6E7D, 0x9CB9, 0x6E7E, 0xCDE5, 0x6E7F, 0xCAAA, 0x6E80, 0x9CBA, 0x6E81, 0x9CBB, 0x6E82, 0x9CBC, 0x6E83, 0xC0A3, 0x6E84, 0x9CBD, 0x6E85, 0xBDA6, 0x6E86, 0xE4D3, 0x6E87, 0x9CBE, 0x6E88, 0x9CBF, 0x6E89, 0xB8C8, 0x6E8A, 0x9CC0, 0x6E8B, 0x9CC1, 0x6E8C, 0x9CC2, 0x6E8D, 0x9CC3, 0x6E8E, 0x9CC4, 0x6E8F, 0xE4E7, 0x6E90, 0xD4B4, 0x6E91, 0x9CC5, 0x6E92, 0x9CC6, 0x6E93, 0x9CC7, 0x6E94, 0x9CC8, 0x6E95, 0x9CC9, 0x6E96, 0x9CCA, 0x6E97, 0x9CCB, 0x6E98, 0xE4DB, 0x6E99, 0x9CCC, 0x6E9A, 0x9CCD, 0x6E9B, 0x9CCE, 0x6E9C, 0xC1EF, 0x6E9D, 0x9CCF, 0x6E9E, 0x9CD0, 0x6E9F, 0xE4E9, 0x6EA0, 0x9CD1, 0x6EA1, 0x9CD2, 0x6EA2, 0xD2E7, 0x6EA3, 0x9CD3, 0x6EA4, 0x9CD4, 0x6EA5, 0xE4DF, 0x6EA6, 0x9CD5, 0x6EA7, 0xE4E0, 0x6EA8, 0x9CD6, 0x6EA9, 0x9CD7, 0x6EAA, 0xCFAA, 0x6EAB, 0x9CD8, 0x6EAC, 0x9CD9, 0x6EAD, 0x9CDA, 0x6EAE, 0x9CDB, 0x6EAF, 0xCBDD, 0x6EB0, 0x9CDC, 0x6EB1, 0xE4DA, 0x6EB2, 0xE4D1, 0x6EB3, 0x9CDD, 0x6EB4, 0xE4E5, 0x6EB5, 0x9CDE, 0x6EB6, 0xC8DC, 0x6EB7, 0xE4E3, 0x6EB8, 0x9CDF, 0x6EB9, 0x9CE0, 0x6EBA, 0xC4E7, 0x6EBB, 0xE4E2, 0x6EBC, 0x9CE1, 0x6EBD, 0xE4E1, 0x6EBE, 0x9CE2, 0x6EBF, 0x9CE3, 0x6EC0, 0x9CE4, 0x6EC1, 0xB3FC, 0x6EC2, 0xE4E8, 0x6EC3, 0x9CE5, 0x6EC4, 0x9CE6, 0x6EC5, 0x9CE7, 0x6EC6, 0x9CE8, 0x6EC7, 0xB5E1, 0x6EC8, 0x9CE9, 0x6EC9, 0x9CEA, 0x6ECA, 0x9CEB, 0x6ECB, 0xD7CC, 0x6ECC, 0x9CEC, 0x6ECD, 0x9CED, 0x6ECE, 0x9CEE, 0x6ECF, 0xE4E6, 0x6ED0, 0x9CEF, 0x6ED1, 0xBBAC, 0x6ED2, 0x9CF0, 0x6ED3, 0xD7D2, 0x6ED4, 0xCCCF, 0x6ED5, 0xEBF8, 0x6ED6, 0x9CF1, 0x6ED7, 0xE4E4, 0x6ED8, 0x9CF2, 0x6ED9, 0x9CF3, 0x6EDA, 0xB9F6, 0x6EDB, 0x9CF4, 0x6EDC, 0x9CF5, 0x6EDD, 0x9CF6, 0x6EDE, 0xD6CD, 0x6EDF, 0xE4D9, 0x6EE0, 0xE4DC, 0x6EE1, 0xC2FA, 0x6EE2, 0xE4DE, 0x6EE3, 0x9CF7, 0x6EE4, 0xC2CB, 0x6EE5, 0xC0C4, 0x6EE6, 0xC2D0, 0x6EE7, 0x9CF8, 0x6EE8, 0xB1F5, 0x6EE9, 0xCCB2, 0x6EEA, 0x9CF9, 0x6EEB, 0x9CFA, 0x6EEC, 0x9CFB, 0x6EED, 0x9CFC, 0x6EEE, 0x9CFD, 0x6EEF, 0x9CFE, 0x6EF0, 0x9D40, 0x6EF1, 0x9D41, 0x6EF2, 0x9D42, 0x6EF3, 0x9D43, 0x6EF4, 0xB5CE, 0x6EF5, 0x9D44, 0x6EF6, 0x9D45, 0x6EF7, 0x9D46, 0x6EF8, 0x9D47, 0x6EF9, 0xE4EF, 0x6EFA, 0x9D48, 0x6EFB, 0x9D49, 0x6EFC, 0x9D4A, 0x6EFD, 0x9D4B, 0x6EFE, 0x9D4C, 0x6EFF, 0x9D4D, 0x6F00, 0x9D4E, 0x6F01, 0x9D4F, 0x6F02, 0xC6AF, 0x6F03, 0x9D50, 0x6F04, 0x9D51, 0x6F05, 0x9D52, 0x6F06, 0xC6E1, 0x6F07, 0x9D53, 0x6F08, 0x9D54, 0x6F09, 0xE4F5, 0x6F0A, 0x9D55, 0x6F0B, 0x9D56, 0x6F0C, 0x9D57, 0x6F0D, 0x9D58, 0x6F0E, 0x9D59, 0x6F0F, 0xC2A9, 0x6F10, 0x9D5A, 0x6F11, 0x9D5B, 0x6F12, 0x9D5C, 0x6F13, 0xC0EC, 0x6F14, 0xD1DD, 0x6F15, 0xE4EE, 0x6F16, 0x9D5D, 0x6F17, 0x9D5E, 0x6F18, 0x9D5F, 0x6F19, 0x9D60, 0x6F1A, 0x9D61, 0x6F1B, 0x9D62, 0x6F1C, 0x9D63, 0x6F1D, 0x9D64, 0x6F1E, 0x9D65, 0x6F1F, 0x9D66, 0x6F20, 0xC4AE, 0x6F21, 0x9D67, 0x6F22, 0x9D68, 0x6F23, 0x9D69, 0x6F24, 0xE4ED, 0x6F25, 0x9D6A, 0x6F26, 0x9D6B, 0x6F27, 0x9D6C, 0x6F28, 0x9D6D, 0x6F29, 0xE4F6, 0x6F2A, 0xE4F4, 0x6F2B, 0xC2FE, 0x6F2C, 0x9D6E, 0x6F2D, 0xE4DD, 0x6F2E, 0x9D6F, 0x6F2F, 0xE4F0, 0x6F30, 0x9D70, 0x6F31, 0xCAFE, 0x6F32, 0x9D71, 0x6F33, 0xD5C4, 0x6F34, 0x9D72, 0x6F35, 0x9D73, 0x6F36, 0xE4F1, 0x6F37, 0x9D74, 0x6F38, 0x9D75, 0x6F39, 0x9D76, 0x6F3A, 0x9D77, 0x6F3B, 0x9D78, 0x6F3C, 0x9D79, 0x6F3D, 0x9D7A, 0x6F3E, 0xD1FA, 0x6F3F, 0x9D7B, 0x6F40, 0x9D7C, 0x6F41, 0x9D7D, 0x6F42, 0x9D7E, 0x6F43, 0x9D80, 0x6F44, 0x9D81, 0x6F45, 0x9D82, 0x6F46, 0xE4EB, 0x6F47, 0xE4EC, 0x6F48, 0x9D83, 0x6F49, 0x9D84, 0x6F4A, 0x9D85, 0x6F4B, 0xE4F2, 0x6F4C, 0x9D86, 0x6F4D, 0xCEAB, 0x6F4E, 0x9D87, 0x6F4F, 0x9D88, 0x6F50, 0x9D89, 0x6F51, 0x9D8A, 0x6F52, 0x9D8B, 0x6F53, 0x9D8C, 0x6F54, 0x9D8D, 0x6F55, 0x9D8E, 0x6F56, 0x9D8F, 0x6F57, 0x9D90, 0x6F58, 0xC5CB, 0x6F59, 0x9D91, 0x6F5A, 0x9D92, 0x6F5B, 0x9D93, 0x6F5C, 0xC7B1, 0x6F5D, 0x9D94, 0x6F5E, 0xC2BA, 0x6F5F, 0x9D95, 0x6F60, 0x9D96, 0x6F61, 0x9D97, 0x6F62, 0xE4EA, 0x6F63, 0x9D98, 0x6F64, 0x9D99, 0x6F65, 0x9D9A, 0x6F66, 0xC1CA, 0x6F67, 0x9D9B, 0x6F68, 0x9D9C, 0x6F69, 0x9D9D, 0x6F6A, 0x9D9E, 0x6F6B, 0x9D9F, 0x6F6C, 0x9DA0, 0x6F6D, 0xCCB6, 0x6F6E, 0xB3B1, 0x6F6F, 0x9DA1, 0x6F70, 0x9DA2, 0x6F71, 0x9DA3, 0x6F72, 0xE4FB, 0x6F73, 0x9DA4, 0x6F74, 0xE4F3, 0x6F75, 0x9DA5, 0x6F76, 0x9DA6, 0x6F77, 0x9DA7, 0x6F78, 0xE4FA, 0x6F79, 0x9DA8, 0x6F7A, 0xE4FD, 0x6F7B, 0x9DA9, 0x6F7C, 0xE4FC, 0x6F7D, 0x9DAA, 0x6F7E, 0x9DAB, 0x6F7F, 0x9DAC, 0x6F80, 0x9DAD, 0x6F81, 0x9DAE, 0x6F82, 0x9DAF, 0x6F83, 0x9DB0, 0x6F84, 0xB3CE, 0x6F85, 0x9DB1, 0x6F86, 0x9DB2, 0x6F87, 0x9DB3, 0x6F88, 0xB3BA, 0x6F89, 0xE4F7, 0x6F8A, 0x9DB4, 0x6F8B, 0x9DB5, 0x6F8C, 0xE4F9, 0x6F8D, 0xE4F8, 0x6F8E, 0xC5EC, 0x6F8F, 0x9DB6, 0x6F90, 0x9DB7, 0x6F91, 0x9DB8, 0x6F92, 0x9DB9, 0x6F93, 0x9DBA, 0x6F94, 0x9DBB, 0x6F95, 0x9DBC, 0x6F96, 0x9DBD, 0x6F97, 0x9DBE, 0x6F98, 0x9DBF, 0x6F99, 0x9DC0, 0x6F9A, 0x9DC1, 0x6F9B, 0x9DC2, 0x6F9C, 0xC0BD, 0x6F9D, 0x9DC3, 0x6F9E, 0x9DC4, 0x6F9F, 0x9DC5, 0x6FA0, 0x9DC6, 0x6FA1, 0xD4E8, 0x6FA2, 0x9DC7, 0x6FA3, 0x9DC8, 0x6FA4, 0x9DC9, 0x6FA5, 0x9DCA, 0x6FA6, 0x9DCB, 0x6FA7, 0xE5A2, 0x6FA8, 0x9DCC, 0x6FA9, 0x9DCD, 0x6FAA, 0x9DCE, 0x6FAB, 0x9DCF, 0x6FAC, 0x9DD0, 0x6FAD, 0x9DD1, 0x6FAE, 0x9DD2, 0x6FAF, 0x9DD3, 0x6FB0, 0x9DD4, 0x6FB1, 0x9DD5, 0x6FB2, 0x9DD6, 0x6FB3, 0xB0C4, 0x6FB4, 0x9DD7, 0x6FB5, 0x9DD8, 0x6FB6, 0xE5A4, 0x6FB7, 0x9DD9, 0x6FB8, 0x9DDA, 0x6FB9, 0xE5A3, 0x6FBA, 0x9DDB, 0x6FBB, 0x9DDC, 0x6FBC, 0x9DDD, 0x6FBD, 0x9DDE, 0x6FBE, 0x9DDF, 0x6FBF, 0x9DE0, 0x6FC0, 0xBCA4, 0x6FC1, 0x9DE1, 0x6FC2, 0xE5A5, 0x6FC3, 0x9DE2, 0x6FC4, 0x9DE3, 0x6FC5, 0x9DE4, 0x6FC6, 0x9DE5, 0x6FC7, 0x9DE6, 0x6FC8, 0x9DE7, 0x6FC9, 0xE5A1, 0x6FCA, 0x9DE8, 0x6FCB, 0x9DE9, 0x6FCC, 0x9DEA, 0x6FCD, 0x9DEB, 0x6FCE, 0x9DEC, 0x6FCF, 0x9DED, 0x6FD0, 0x9DEE, 0x6FD1, 0xE4FE, 0x6FD2, 0xB1F4, 0x6FD3, 0x9DEF, 0x6FD4, 0x9DF0, 0x6FD5, 0x9DF1, 0x6FD6, 0x9DF2, 0x6FD7, 0x9DF3, 0x6FD8, 0x9DF4, 0x6FD9, 0x9DF5, 0x6FDA, 0x9DF6, 0x6FDB, 0x9DF7, 0x6FDC, 0x9DF8, 0x6FDD, 0x9DF9, 0x6FDE, 0xE5A8, 0x6FDF, 0x9DFA, 0x6FE0, 0xE5A9, 0x6FE1, 0xE5A6, 0x6FE2, 0x9DFB, 0x6FE3, 0x9DFC, 0x6FE4, 0x9DFD, 0x6FE5, 0x9DFE, 0x6FE6, 0x9E40, 0x6FE7, 0x9E41, 0x6FE8, 0x9E42, 0x6FE9, 0x9E43, 0x6FEA, 0x9E44, 0x6FEB, 0x9E45, 0x6FEC, 0x9E46, 0x6FED, 0x9E47, 0x6FEE, 0xE5A7, 0x6FEF, 0xE5AA, 0x6FF0, 0x9E48, 0x6FF1, 0x9E49, 0x6FF2, 0x9E4A, 0x6FF3, 0x9E4B, 0x6FF4, 0x9E4C, 0x6FF5, 0x9E4D, 0x6FF6, 0x9E4E, 0x6FF7, 0x9E4F, 0x6FF8, 0x9E50, 0x6FF9, 0x9E51, 0x6FFA, 0x9E52, 0x6FFB, 0x9E53, 0x6FFC, 0x9E54, 0x6FFD, 0x9E55, 0x6FFE, 0x9E56, 0x6FFF, 0x9E57, 0x7000, 0x9E58, 0x7001, 0x9E59, 0x7002, 0x9E5A, 0x7003, 0x9E5B, 0x7004, 0x9E5C, 0x7005, 0x9E5D, 0x7006, 0x9E5E, 0x7007, 0x9E5F, 0x7008, 0x9E60, 0x7009, 0x9E61, 0x700A, 0x9E62, 0x700B, 0x9E63, 0x700C, 0x9E64, 0x700D, 0x9E65, 0x700E, 0x9E66, 0x700F, 0x9E67, 0x7010, 0x9E68, 0x7011, 0xC6D9, 0x7012, 0x9E69, 0x7013, 0x9E6A, 0x7014, 0x9E6B, 0x7015, 0x9E6C, 0x7016, 0x9E6D, 0x7017, 0x9E6E, 0x7018, 0x9E6F, 0x7019, 0x9E70, 0x701A, 0xE5AB, 0x701B, 0xE5AD, 0x701C, 0x9E71, 0x701D, 0x9E72, 0x701E, 0x9E73, 0x701F, 0x9E74, 0x7020, 0x9E75, 0x7021, 0x9E76, 0x7022, 0x9E77, 0x7023, 0xE5AC, 0x7024, 0x9E78, 0x7025, 0x9E79, 0x7026, 0x9E7A, 0x7027, 0x9E7B, 0x7028, 0x9E7C, 0x7029, 0x9E7D, 0x702A, 0x9E7E, 0x702B, 0x9E80, 0x702C, 0x9E81, 0x702D, 0x9E82, 0x702E, 0x9E83, 0x702F, 0x9E84, 0x7030, 0x9E85, 0x7031, 0x9E86, 0x7032, 0x9E87, 0x7033, 0x9E88, 0x7034, 0x9E89, 0x7035, 0xE5AF, 0x7036, 0x9E8A, 0x7037, 0x9E8B, 0x7038, 0x9E8C, 0x7039, 0xE5AE, 0x703A, 0x9E8D, 0x703B, 0x9E8E, 0x703C, 0x9E8F, 0x703D, 0x9E90, 0x703E, 0x9E91, 0x703F, 0x9E92, 0x7040, 0x9E93, 0x7041, 0x9E94, 0x7042, 0x9E95, 0x7043, 0x9E96, 0x7044, 0x9E97, 0x7045, 0x9E98, 0x7046, 0x9E99, 0x7047, 0x9E9A, 0x7048, 0x9E9B, 0x7049, 0x9E9C, 0x704A, 0x9E9D, 0x704B, 0x9E9E, 0x704C, 0xB9E0, 0x704D, 0x9E9F, 0x704E, 0x9EA0, 0x704F, 0xE5B0, 0x7050, 0x9EA1, 0x7051, 0x9EA2, 0x7052, 0x9EA3, 0x7053, 0x9EA4, 0x7054, 0x9EA5, 0x7055, 0x9EA6, 0x7056, 0x9EA7, 0x7057, 0x9EA8, 0x7058, 0x9EA9, 0x7059, 0x9EAA, 0x705A, 0x9EAB, 0x705B, 0x9EAC, 0x705C, 0x9EAD, 0x705D, 0x9EAE, 0x705E, 0xE5B1, 0x705F, 0x9EAF, 0x7060, 0x9EB0, 0x7061, 0x9EB1, 0x7062, 0x9EB2, 0x7063, 0x9EB3, 0x7064, 0x9EB4, 0x7065, 0x9EB5, 0x7066, 0x9EB6, 0x7067, 0x9EB7, 0x7068, 0x9EB8, 0x7069, 0x9EB9, 0x706A, 0x9EBA, 0x706B, 0xBBF0, 0x706C, 0xECE1, 0x706D, 0xC3F0, 0x706E, 0x9EBB, 0x706F, 0xB5C6, 0x7070, 0xBBD2, 0x7071, 0x9EBC, 0x7072, 0x9EBD, 0x7073, 0x9EBE, 0x7074, 0x9EBF, 0x7075, 0xC1E9, 0x7076, 0xD4EE, 0x7077, 0x9EC0, 0x7078, 0xBEC4, 0x7079, 0x9EC1, 0x707A, 0x9EC2, 0x707B, 0x9EC3, 0x707C, 0xD7C6, 0x707D, 0x9EC4, 0x707E, 0xD4D6, 0x707F, 0xB2D3, 0x7080, 0xECBE, 0x7081, 0x9EC5, 0x7082, 0x9EC6, 0x7083, 0x9EC7, 0x7084, 0x9EC8, 0x7085, 0xEAC1, 0x7086, 0x9EC9, 0x7087, 0x9ECA, 0x7088, 0x9ECB, 0x7089, 0xC2AF, 0x708A, 0xB4B6, 0x708B, 0x9ECC, 0x708C, 0x9ECD, 0x708D, 0x9ECE, 0x708E, 0xD1D7, 0x708F, 0x9ECF, 0x7090, 0x9ED0, 0x7091, 0x9ED1, 0x7092, 0xB3B4, 0x7093, 0x9ED2, 0x7094, 0xC8B2, 0x7095, 0xBFBB, 0x7096, 0xECC0, 0x7097, 0x9ED3, 0x7098, 0x9ED4, 0x7099, 0xD6CB, 0x709A, 0x9ED5, 0x709B, 0x9ED6, 0x709C, 0xECBF, 0x709D, 0xECC1, 0x709E, 0x9ED7, 0x709F, 0x9ED8, 0x70A0, 0x9ED9, 0x70A1, 0x9EDA, 0x70A2, 0x9EDB, 0x70A3, 0x9EDC, 0x70A4, 0x9EDD, 0x70A5, 0x9EDE, 0x70A6, 0x9EDF, 0x70A7, 0x9EE0, 0x70A8, 0x9EE1, 0x70A9, 0x9EE2, 0x70AA, 0x9EE3, 0x70AB, 0xECC5, 0x70AC, 0xBEE6, 0x70AD, 0xCCBF, 0x70AE, 0xC5DA, 0x70AF, 0xBEBC, 0x70B0, 0x9EE4, 0x70B1, 0xECC6, 0x70B2, 0x9EE5, 0x70B3, 0xB1FE, 0x70B4, 0x9EE6, 0x70B5, 0x9EE7, 0x70B6, 0x9EE8, 0x70B7, 0xECC4, 0x70B8, 0xD5A8, 0x70B9, 0xB5E3, 0x70BA, 0x9EE9, 0x70BB, 0xECC2, 0x70BC, 0xC1B6, 0x70BD, 0xB3E3, 0x70BE, 0x9EEA, 0x70BF, 0x9EEB, 0x70C0, 0xECC3, 0x70C1, 0xCBB8, 0x70C2, 0xC0C3, 0x70C3, 0xCCFE, 0x70C4, 0x9EEC, 0x70C5, 0x9EED, 0x70C6, 0x9EEE, 0x70C7, 0x9EEF, 0x70C8, 0xC1D2, 0x70C9, 0x9EF0, 0x70CA, 0xECC8, 0x70CB, 0x9EF1, 0x70CC, 0x9EF2, 0x70CD, 0x9EF3, 0x70CE, 0x9EF4, 0x70CF, 0x9EF5, 0x70D0, 0x9EF6, 0x70D1, 0x9EF7, 0x70D2, 0x9EF8, 0x70D3, 0x9EF9, 0x70D4, 0x9EFA, 0x70D5, 0x9EFB, 0x70D6, 0x9EFC, 0x70D7, 0x9EFD, 0x70D8, 0xBAE6, 0x70D9, 0xC0D3, 0x70DA, 0x9EFE, 0x70DB, 0xD6F2, 0x70DC, 0x9F40, 0x70DD, 0x9F41, 0x70DE, 0x9F42, 0x70DF, 0xD1CC, 0x70E0, 0x9F43, 0x70E1, 0x9F44, 0x70E2, 0x9F45, 0x70E3, 0x9F46, 0x70E4, 0xBFBE, 0x70E5, 0x9F47, 0x70E6, 0xB7B3, 0x70E7, 0xC9D5, 0x70E8, 0xECC7, 0x70E9, 0xBBE2, 0x70EA, 0x9F48, 0x70EB, 0xCCCC, 0x70EC, 0xBDFD, 0x70ED, 0xC8C8, 0x70EE, 0x9F49, 0x70EF, 0xCFA9, 0x70F0, 0x9F4A, 0x70F1, 0x9F4B, 0x70F2, 0x9F4C, 0x70F3, 0x9F4D, 0x70F4, 0x9F4E, 0x70F5, 0x9F4F, 0x70F6, 0x9F50, 0x70F7, 0xCDE9, 0x70F8, 0x9F51, 0x70F9, 0xC5EB, 0x70FA, 0x9F52, 0x70FB, 0x9F53, 0x70FC, 0x9F54, 0x70FD, 0xB7E9, 0x70FE, 0x9F55, 0x70FF, 0x9F56, 0x7100, 0x9F57, 0x7101, 0x9F58, 0x7102, 0x9F59, 0x7103, 0x9F5A, 0x7104, 0x9F5B, 0x7105, 0x9F5C, 0x7106, 0x9F5D, 0x7107, 0x9F5E, 0x7108, 0x9F5F, 0x7109, 0xD1C9, 0x710A, 0xBAB8, 0x710B, 0x9F60, 0x710C, 0x9F61, 0x710D, 0x9F62, 0x710E, 0x9F63, 0x710F, 0x9F64, 0x7110, 0xECC9, 0x7111, 0x9F65, 0x7112, 0x9F66, 0x7113, 0xECCA, 0x7114, 0x9F67, 0x7115, 0xBBC0, 0x7116, 0xECCB, 0x7117, 0x9F68, 0x7118, 0xECE2, 0x7119, 0xB1BA, 0x711A, 0xB7D9, 0x711B, 0x9F69, 0x711C, 0x9F6A, 0x711D, 0x9F6B, 0x711E, 0x9F6C, 0x711F, 0x9F6D, 0x7120, 0x9F6E, 0x7121, 0x9F6F, 0x7122, 0x9F70, 0x7123, 0x9F71, 0x7124, 0x9F72, 0x7125, 0x9F73, 0x7126, 0xBDB9, 0x7127, 0x9F74, 0x7128, 0x9F75, 0x7129, 0x9F76, 0x712A, 0x9F77, 0x712B, 0x9F78, 0x712C, 0x9F79, 0x712D, 0x9F7A, 0x712E, 0x9F7B, 0x712F, 0xECCC, 0x7130, 0xD1E6, 0x7131, 0xECCD, 0x7132, 0x9F7C, 0x7133, 0x9F7D, 0x7134, 0x9F7E, 0x7135, 0x9F80, 0x7136, 0xC8BB, 0x7137, 0x9F81, 0x7138, 0x9F82, 0x7139, 0x9F83, 0x713A, 0x9F84, 0x713B, 0x9F85, 0x713C, 0x9F86, 0x713D, 0x9F87, 0x713E, 0x9F88, 0x713F, 0x9F89, 0x7140, 0x9F8A, 0x7141, 0x9F8B, 0x7142, 0x9F8C, 0x7143, 0x9F8D, 0x7144, 0x9F8E, 0x7145, 0xECD1, 0x7146, 0x9F8F, 0x7147, 0x9F90, 0x7148, 0x9F91, 0x7149, 0x9F92, 0x714A, 0xECD3, 0x714B, 0x9F93, 0x714C, 0xBBCD, 0x714D, 0x9F94, 0x714E, 0xBCE5, 0x714F, 0x9F95, 0x7150, 0x9F96, 0x7151, 0x9F97, 0x7152, 0x9F98, 0x7153, 0x9F99, 0x7154, 0x9F9A, 0x7155, 0x9F9B, 0x7156, 0x9F9C, 0x7157, 0x9F9D, 0x7158, 0x9F9E, 0x7159, 0x9F9F, 0x715A, 0x9FA0, 0x715B, 0x9FA1, 0x715C, 0xECCF, 0x715D, 0x9FA2, 0x715E, 0xC9B7, 0x715F, 0x9FA3, 0x7160, 0x9FA4, 0x7161, 0x9FA5, 0x7162, 0x9FA6, 0x7163, 0x9FA7, 0x7164, 0xC3BA, 0x7165, 0x9FA8, 0x7166, 0xECE3, 0x7167, 0xD5D5, 0x7168, 0xECD0, 0x7169, 0x9FA9, 0x716A, 0x9FAA, 0x716B, 0x9FAB, 0x716C, 0x9FAC, 0x716D, 0x9FAD, 0x716E, 0xD6F3, 0x716F, 0x9FAE, 0x7170, 0x9FAF, 0x7171, 0x9FB0, 0x7172, 0xECD2, 0x7173, 0xECCE, 0x7174, 0x9FB1, 0x7175, 0x9FB2, 0x7176, 0x9FB3, 0x7177, 0x9FB4, 0x7178, 0xECD4, 0x7179, 0x9FB5, 0x717A, 0xECD5, 0x717B, 0x9FB6, 0x717C, 0x9FB7, 0x717D, 0xC9BF, 0x717E, 0x9FB8, 0x717F, 0x9FB9, 0x7180, 0x9FBA, 0x7181, 0x9FBB, 0x7182, 0x9FBC, 0x7183, 0x9FBD, 0x7184, 0xCFA8, 0x7185, 0x9FBE, 0x7186, 0x9FBF, 0x7187, 0x9FC0, 0x7188, 0x9FC1, 0x7189, 0x9FC2, 0x718A, 0xD0DC, 0x718B, 0x9FC3, 0x718C, 0x9FC4, 0x718D, 0x9FC5, 0x718E, 0x9FC6, 0x718F, 0xD1AC, 0x7190, 0x9FC7, 0x7191, 0x9FC8, 0x7192, 0x9FC9, 0x7193, 0x9FCA, 0x7194, 0xC8DB, 0x7195, 0x9FCB, 0x7196, 0x9FCC, 0x7197, 0x9FCD, 0x7198, 0xECD6, 0x7199, 0xCEF5, 0x719A, 0x9FCE, 0x719B, 0x9FCF, 0x719C, 0x9FD0, 0x719D, 0x9FD1, 0x719E, 0x9FD2, 0x719F, 0xCAEC, 0x71A0, 0xECDA, 0x71A1, 0x9FD3, 0x71A2, 0x9FD4, 0x71A3, 0x9FD5, 0x71A4, 0x9FD6, 0x71A5, 0x9FD7, 0x71A6, 0x9FD8, 0x71A7, 0x9FD9, 0x71A8, 0xECD9, 0x71A9, 0x9FDA, 0x71AA, 0x9FDB, 0x71AB, 0x9FDC, 0x71AC, 0xB0BE, 0x71AD, 0x9FDD, 0x71AE, 0x9FDE, 0x71AF, 0x9FDF, 0x71B0, 0x9FE0, 0x71B1, 0x9FE1, 0x71B2, 0x9FE2, 0x71B3, 0xECD7, 0x71B4, 0x9FE3, 0x71B5, 0xECD8, 0x71B6, 0x9FE4, 0x71B7, 0x9FE5, 0x71B8, 0x9FE6, 0x71B9, 0xECE4, 0x71BA, 0x9FE7, 0x71BB, 0x9FE8, 0x71BC, 0x9FE9, 0x71BD, 0x9FEA, 0x71BE, 0x9FEB, 0x71BF, 0x9FEC, 0x71C0, 0x9FED, 0x71C1, 0x9FEE, 0x71C2, 0x9FEF, 0x71C3, 0xC8BC, 0x71C4, 0x9FF0, 0x71C5, 0x9FF1, 0x71C6, 0x9FF2, 0x71C7, 0x9FF3, 0x71C8, 0x9FF4, 0x71C9, 0x9FF5, 0x71CA, 0x9FF6, 0x71CB, 0x9FF7, 0x71CC, 0x9FF8, 0x71CD, 0x9FF9, 0x71CE, 0xC1C7, 0x71CF, 0x9FFA, 0x71D0, 0x9FFB, 0x71D1, 0x9FFC, 0x71D2, 0x9FFD, 0x71D3, 0x9FFE, 0x71D4, 0xECDC, 0x71D5, 0xD1E0, 0x71D6, 0xA040, 0x71D7, 0xA041, 0x71D8, 0xA042, 0x71D9, 0xA043, 0x71DA, 0xA044, 0x71DB, 0xA045, 0x71DC, 0xA046, 0x71DD, 0xA047, 0x71DE, 0xA048, 0x71DF, 0xA049, 0x71E0, 0xECDB, 0x71E1, 0xA04A, 0x71E2, 0xA04B, 0x71E3, 0xA04C, 0x71E4, 0xA04D, 0x71E5, 0xD4EF, 0x71E6, 0xA04E, 0x71E7, 0xECDD, 0x71E8, 0xA04F, 0x71E9, 0xA050, 0x71EA, 0xA051, 0x71EB, 0xA052, 0x71EC, 0xA053, 0x71ED, 0xA054, 0x71EE, 0xDBC6, 0x71EF, 0xA055, 0x71F0, 0xA056, 0x71F1, 0xA057, 0x71F2, 0xA058, 0x71F3, 0xA059, 0x71F4, 0xA05A, 0x71F5, 0xA05B, 0x71F6, 0xA05C, 0x71F7, 0xA05D, 0x71F8, 0xA05E, 0x71F9, 0xECDE, 0x71FA, 0xA05F, 0x71FB, 0xA060, 0x71FC, 0xA061, 0x71FD, 0xA062, 0x71FE, 0xA063, 0x71FF, 0xA064, 0x7200, 0xA065, 0x7201, 0xA066, 0x7202, 0xA067, 0x7203, 0xA068, 0x7204, 0xA069, 0x7205, 0xA06A, 0x7206, 0xB1AC, 0x7207, 0xA06B, 0x7208, 0xA06C, 0x7209, 0xA06D, 0x720A, 0xA06E, 0x720B, 0xA06F, 0x720C, 0xA070, 0x720D, 0xA071, 0x720E, 0xA072, 0x720F, 0xA073, 0x7210, 0xA074, 0x7211, 0xA075, 0x7212, 0xA076, 0x7213, 0xA077, 0x7214, 0xA078, 0x7215, 0xA079, 0x7216, 0xA07A, 0x7217, 0xA07B, 0x7218, 0xA07C, 0x7219, 0xA07D, 0x721A, 0xA07E, 0x721B, 0xA080, 0x721C, 0xA081, 0x721D, 0xECDF, 0x721E, 0xA082, 0x721F, 0xA083, 0x7220, 0xA084, 0x7221, 0xA085, 0x7222, 0xA086, 0x7223, 0xA087, 0x7224, 0xA088, 0x7225, 0xA089, 0x7226, 0xA08A, 0x7227, 0xA08B, 0x7228, 0xECE0, 0x7229, 0xA08C, 0x722A, 0xD7A6, 0x722B, 0xA08D, 0x722C, 0xC5C0, 0x722D, 0xA08E, 0x722E, 0xA08F, 0x722F, 0xA090, 0x7230, 0xEBBC, 0x7231, 0xB0AE, 0x7232, 0xA091, 0x7233, 0xA092, 0x7234, 0xA093, 0x7235, 0xBEF4, 0x7236, 0xB8B8, 0x7237, 0xD2AF, 0x7238, 0xB0D6, 0x7239, 0xB5F9, 0x723A, 0xA094, 0x723B, 0xD8B3, 0x723C, 0xA095, 0x723D, 0xCBAC, 0x723E, 0xA096, 0x723F, 0xE3DD, 0x7240, 0xA097, 0x7241, 0xA098, 0x7242, 0xA099, 0x7243, 0xA09A, 0x7244, 0xA09B, 0x7245, 0xA09C, 0x7246, 0xA09D, 0x7247, 0xC6AC, 0x7248, 0xB0E6, 0x7249, 0xA09E, 0x724A, 0xA09F, 0x724B, 0xA0A0, 0x724C, 0xC5C6, 0x724D, 0xEBB9, 0x724E, 0xA0A1, 0x724F, 0xA0A2, 0x7250, 0xA0A3, 0x7251, 0xA0A4, 0x7252, 0xEBBA, 0x7253, 0xA0A5, 0x7254, 0xA0A6, 0x7255, 0xA0A7, 0x7256, 0xEBBB, 0x7257, 0xA0A8, 0x7258, 0xA0A9, 0x7259, 0xD1C0, 0x725A, 0xA0AA, 0x725B, 0xC5A3, 0x725C, 0xA0AB, 0x725D, 0xEAF2, 0x725E, 0xA0AC, 0x725F, 0xC4B2, 0x7260, 0xA0AD, 0x7261, 0xC4B5, 0x7262, 0xC0CE, 0x7263, 0xA0AE, 0x7264, 0xA0AF, 0x7265, 0xA0B0, 0x7266, 0xEAF3, 0x7267, 0xC4C1, 0x7268, 0xA0B1, 0x7269, 0xCEEF, 0x726A, 0xA0B2, 0x726B, 0xA0B3, 0x726C, 0xA0B4, 0x726D, 0xA0B5, 0x726E, 0xEAF0, 0x726F, 0xEAF4, 0x7270, 0xA0B6, 0x7271, 0xA0B7, 0x7272, 0xC9FC, 0x7273, 0xA0B8, 0x7274, 0xA0B9, 0x7275, 0xC7A3, 0x7276, 0xA0BA, 0x7277, 0xA0BB, 0x7278, 0xA0BC, 0x7279, 0xCCD8, 0x727A, 0xCEFE, 0x727B, 0xA0BD, 0x727C, 0xA0BE, 0x727D, 0xA0BF, 0x727E, 0xEAF5, 0x727F, 0xEAF6, 0x7280, 0xCFAC, 0x7281, 0xC0E7, 0x7282, 0xA0C0, 0x7283, 0xA0C1, 0x7284, 0xEAF7, 0x7285, 0xA0C2, 0x7286, 0xA0C3, 0x7287, 0xA0C4, 0x7288, 0xA0C5, 0x7289, 0xA0C6, 0x728A, 0xB6BF, 0x728B, 0xEAF8, 0x728C, 0xA0C7, 0x728D, 0xEAF9, 0x728E, 0xA0C8, 0x728F, 0xEAFA, 0x7290, 0xA0C9, 0x7291, 0xA0CA, 0x7292, 0xEAFB, 0x7293, 0xA0CB, 0x7294, 0xA0CC, 0x7295, 0xA0CD, 0x7296, 0xA0CE, 0x7297, 0xA0CF, 0x7298, 0xA0D0, 0x7299, 0xA0D1, 0x729A, 0xA0D2, 0x729B, 0xA0D3, 0x729C, 0xA0D4, 0x729D, 0xA0D5, 0x729E, 0xA0D6, 0x729F, 0xEAF1, 0x72A0, 0xA0D7, 0x72A1, 0xA0D8, 0x72A2, 0xA0D9, 0x72A3, 0xA0DA, 0x72A4, 0xA0DB, 0x72A5, 0xA0DC, 0x72A6, 0xA0DD, 0x72A7, 0xA0DE, 0x72A8, 0xA0DF, 0x72A9, 0xA0E0, 0x72AA, 0xA0E1, 0x72AB, 0xA0E2, 0x72AC, 0xC8AE, 0x72AD, 0xE1EB, 0x72AE, 0xA0E3, 0x72AF, 0xB7B8, 0x72B0, 0xE1EC, 0x72B1, 0xA0E4, 0x72B2, 0xA0E5, 0x72B3, 0xA0E6, 0x72B4, 0xE1ED, 0x72B5, 0xA0E7, 0x72B6, 0xD7B4, 0x72B7, 0xE1EE, 0x72B8, 0xE1EF, 0x72B9, 0xD3CC, 0x72BA, 0xA0E8, 0x72BB, 0xA0E9, 0x72BC, 0xA0EA, 0x72BD, 0xA0EB, 0x72BE, 0xA0EC, 0x72BF, 0xA0ED, 0x72C0, 0xA0EE, 0x72C1, 0xE1F1, 0x72C2, 0xBFF1, 0x72C3, 0xE1F0, 0x72C4, 0xB5D2, 0x72C5, 0xA0EF, 0x72C6, 0xA0F0, 0x72C7, 0xA0F1, 0x72C8, 0xB1B7, 0x72C9, 0xA0F2, 0x72CA, 0xA0F3, 0x72CB, 0xA0F4, 0x72CC, 0xA0F5, 0x72CD, 0xE1F3, 0x72CE, 0xE1F2, 0x72CF, 0xA0F6, 0x72D0, 0xBAFC, 0x72D1, 0xA0F7, 0x72D2, 0xE1F4, 0x72D3, 0xA0F8, 0x72D4, 0xA0F9, 0x72D5, 0xA0FA, 0x72D6, 0xA0FB, 0x72D7, 0xB9B7, 0x72D8, 0xA0FC, 0x72D9, 0xBED1, 0x72DA, 0xA0FD, 0x72DB, 0xA0FE, 0x72DC, 0xAA40, 0x72DD, 0xAA41, 0x72DE, 0xC4FC, 0x72DF, 0xAA42, 0x72E0, 0xBADD, 0x72E1, 0xBDC6, 0x72E2, 0xAA43, 0x72E3, 0xAA44, 0x72E4, 0xAA45, 0x72E5, 0xAA46, 0x72E6, 0xAA47, 0x72E7, 0xAA48, 0x72E8, 0xE1F5, 0x72E9, 0xE1F7, 0x72EA, 0xAA49, 0x72EB, 0xAA4A, 0x72EC, 0xB6C0, 0x72ED, 0xCFC1, 0x72EE, 0xCAA8, 0x72EF, 0xE1F6, 0x72F0, 0xD5F8, 0x72F1, 0xD3FC, 0x72F2, 0xE1F8, 0x72F3, 0xE1FC, 0x72F4, 0xE1F9, 0x72F5, 0xAA4B, 0x72F6, 0xAA4C, 0x72F7, 0xE1FA, 0x72F8, 0xC0EA, 0x72F9, 0xAA4D, 0x72FA, 0xE1FE, 0x72FB, 0xE2A1, 0x72FC, 0xC0C7, 0x72FD, 0xAA4E, 0x72FE, 0xAA4F, 0x72FF, 0xAA50, 0x7300, 0xAA51, 0x7301, 0xE1FB, 0x7302, 0xAA52, 0x7303, 0xE1FD, 0x7304, 0xAA53, 0x7305, 0xAA54, 0x7306, 0xAA55, 0x7307, 0xAA56, 0x7308, 0xAA57, 0x7309, 0xAA58, 0x730A, 0xE2A5, 0x730B, 0xAA59, 0x730C, 0xAA5A, 0x730D, 0xAA5B, 0x730E, 0xC1D4, 0x730F, 0xAA5C, 0x7310, 0xAA5D, 0x7311, 0xAA5E, 0x7312, 0xAA5F, 0x7313, 0xE2A3, 0x7314, 0xAA60, 0x7315, 0xE2A8, 0x7316, 0xB2FE, 0x7317, 0xE2A2, 0x7318, 0xAA61, 0x7319, 0xAA62, 0x731A, 0xAA63, 0x731B, 0xC3CD, 0x731C, 0xB2C2, 0x731D, 0xE2A7, 0x731E, 0xE2A6, 0x731F, 0xAA64, 0x7320, 0xAA65, 0x7321, 0xE2A4, 0x7322, 0xE2A9, 0x7323, 0xAA66, 0x7324, 0xAA67, 0x7325, 0xE2AB, 0x7326, 0xAA68, 0x7327, 0xAA69, 0x7328, 0xAA6A, 0x7329, 0xD0C9, 0x732A, 0xD6ED, 0x732B, 0xC3A8, 0x732C, 0xE2AC, 0x732D, 0xAA6B, 0x732E, 0xCFD7, 0x732F, 0xAA6C, 0x7330, 0xAA6D, 0x7331, 0xE2AE, 0x7332, 0xAA6E, 0x7333, 0xAA6F, 0x7334, 0xBAEF, 0x7335, 0xAA70, 0x7336, 0xAA71, 0x7337, 0xE9E0, 0x7338, 0xE2AD, 0x7339, 0xE2AA, 0x733A, 0xAA72, 0x733B, 0xAA73, 0x733C, 0xAA74, 0x733D, 0xAA75, 0x733E, 0xBBAB, 0x733F, 0xD4B3, 0x7340, 0xAA76, 0x7341, 0xAA77, 0x7342, 0xAA78, 0x7343, 0xAA79, 0x7344, 0xAA7A, 0x7345, 0xAA7B, 0x7346, 0xAA7C, 0x7347, 0xAA7D, 0x7348, 0xAA7E, 0x7349, 0xAA80, 0x734A, 0xAA81, 0x734B, 0xAA82, 0x734C, 0xAA83, 0x734D, 0xE2B0, 0x734E, 0xAA84, 0x734F, 0xAA85, 0x7350, 0xE2AF, 0x7351, 0xAA86, 0x7352, 0xE9E1, 0x7353, 0xAA87, 0x7354, 0xAA88, 0x7355, 0xAA89, 0x7356, 0xAA8A, 0x7357, 0xE2B1, 0x7358, 0xAA8B, 0x7359, 0xAA8C, 0x735A, 0xAA8D, 0x735B, 0xAA8E, 0x735C, 0xAA8F, 0x735D, 0xAA90, 0x735E, 0xAA91, 0x735F, 0xAA92, 0x7360, 0xE2B2, 0x7361, 0xAA93, 0x7362, 0xAA94, 0x7363, 0xAA95, 0x7364, 0xAA96, 0x7365, 0xAA97, 0x7366, 0xAA98, 0x7367, 0xAA99, 0x7368, 0xAA9A, 0x7369, 0xAA9B, 0x736A, 0xAA9C, 0x736B, 0xAA9D, 0x736C, 0xE2B3, 0x736D, 0xCCA1, 0x736E, 0xAA9E, 0x736F, 0xE2B4, 0x7370, 0xAA9F, 0x7371, 0xAAA0, 0x7372, 0xAB40, 0x7373, 0xAB41, 0x7374, 0xAB42, 0x7375, 0xAB43, 0x7376, 0xAB44, 0x7377, 0xAB45, 0x7378, 0xAB46, 0x7379, 0xAB47, 0x737A, 0xAB48, 0x737B, 0xAB49, 0x737C, 0xAB4A, 0x737D, 0xAB4B, 0x737E, 0xE2B5, 0x737F, 0xAB4C, 0x7380, 0xAB4D, 0x7381, 0xAB4E, 0x7382, 0xAB4F, 0x7383, 0xAB50, 0x7384, 0xD0FE, 0x7385, 0xAB51, 0x7386, 0xAB52, 0x7387, 0xC2CA, 0x7388, 0xAB53, 0x7389, 0xD3F1, 0x738A, 0xAB54, 0x738B, 0xCDF5, 0x738C, 0xAB55, 0x738D, 0xAB56, 0x738E, 0xE7E0, 0x738F, 0xAB57, 0x7390, 0xAB58, 0x7391, 0xE7E1, 0x7392, 0xAB59, 0x7393, 0xAB5A, 0x7394, 0xAB5B, 0x7395, 0xAB5C, 0x7396, 0xBEC1, 0x7397, 0xAB5D, 0x7398, 0xAB5E, 0x7399, 0xAB5F, 0x739A, 0xAB60, 0x739B, 0xC2EA, 0x739C, 0xAB61, 0x739D, 0xAB62, 0x739E, 0xAB63, 0x739F, 0xE7E4, 0x73A0, 0xAB64, 0x73A1, 0xAB65, 0x73A2, 0xE7E3, 0x73A3, 0xAB66, 0x73A4, 0xAB67, 0x73A5, 0xAB68, 0x73A6, 0xAB69, 0x73A7, 0xAB6A, 0x73A8, 0xAB6B, 0x73A9, 0xCDE6, 0x73AA, 0xAB6C, 0x73AB, 0xC3B5, 0x73AC, 0xAB6D, 0x73AD, 0xAB6E, 0x73AE, 0xE7E2, 0x73AF, 0xBBB7, 0x73B0, 0xCFD6, 0x73B1, 0xAB6F, 0x73B2, 0xC1E1, 0x73B3, 0xE7E9, 0x73B4, 0xAB70, 0x73B5, 0xAB71, 0x73B6, 0xAB72, 0x73B7, 0xE7E8, 0x73B8, 0xAB73, 0x73B9, 0xAB74, 0x73BA, 0xE7F4, 0x73BB, 0xB2A3, 0x73BC, 0xAB75, 0x73BD, 0xAB76, 0x73BE, 0xAB77, 0x73BF, 0xAB78, 0x73C0, 0xE7EA, 0x73C1, 0xAB79, 0x73C2, 0xE7E6, 0x73C3, 0xAB7A, 0x73C4, 0xAB7B, 0x73C5, 0xAB7C, 0x73C6, 0xAB7D, 0x73C7, 0xAB7E, 0x73C8, 0xE7EC, 0x73C9, 0xE7EB, 0x73CA, 0xC9BA, 0x73CB, 0xAB80, 0x73CC, 0xAB81, 0x73CD, 0xD5E4, 0x73CE, 0xAB82, 0x73CF, 0xE7E5, 0x73D0, 0xB7A9, 0x73D1, 0xE7E7, 0x73D2, 0xAB83, 0x73D3, 0xAB84, 0x73D4, 0xAB85, 0x73D5, 0xAB86, 0x73D6, 0xAB87, 0x73D7, 0xAB88, 0x73D8, 0xAB89, 0x73D9, 0xE7EE, 0x73DA, 0xAB8A, 0x73DB, 0xAB8B, 0x73DC, 0xAB8C, 0x73DD, 0xAB8D, 0x73DE, 0xE7F3, 0x73DF, 0xAB8E, 0x73E0, 0xD6E9, 0x73E1, 0xAB8F, 0x73E2, 0xAB90, 0x73E3, 0xAB91, 0x73E4, 0xAB92, 0x73E5, 0xE7ED, 0x73E6, 0xAB93, 0x73E7, 0xE7F2, 0x73E8, 0xAB94, 0x73E9, 0xE7F1, 0x73EA, 0xAB95, 0x73EB, 0xAB96, 0x73EC, 0xAB97, 0x73ED, 0xB0E0, 0x73EE, 0xAB98, 0x73EF, 0xAB99, 0x73F0, 0xAB9A, 0x73F1, 0xAB9B, 0x73F2, 0xE7F5, 0x73F3, 0xAB9C, 0x73F4, 0xAB9D, 0x73F5, 0xAB9E, 0x73F6, 0xAB9F, 0x73F7, 0xABA0, 0x73F8, 0xAC40, 0x73F9, 0xAC41, 0x73FA, 0xAC42, 0x73FB, 0xAC43, 0x73FC, 0xAC44, 0x73FD, 0xAC45, 0x73FE, 0xAC46, 0x73FF, 0xAC47, 0x7400, 0xAC48, 0x7401, 0xAC49, 0x7402, 0xAC4A, 0x7403, 0xC7F2, 0x7404, 0xAC4B, 0x7405, 0xC0C5, 0x7406, 0xC0ED, 0x7407, 0xAC4C, 0x7408, 0xAC4D, 0x7409, 0xC1F0, 0x740A, 0xE7F0, 0x740B, 0xAC4E, 0x740C, 0xAC4F, 0x740D, 0xAC50, 0x740E, 0xAC51, 0x740F, 0xE7F6, 0x7410, 0xCBF6, 0x7411, 0xAC52, 0x7412, 0xAC53, 0x7413, 0xAC54, 0x7414, 0xAC55, 0x7415, 0xAC56, 0x7416, 0xAC57, 0x7417, 0xAC58, 0x7418, 0xAC59, 0x7419, 0xAC5A, 0x741A, 0xE8A2, 0x741B, 0xE8A1, 0x741C, 0xAC5B, 0x741D, 0xAC5C, 0x741E, 0xAC5D, 0x741F, 0xAC5E, 0x7420, 0xAC5F, 0x7421, 0xAC60, 0x7422, 0xD7C1, 0x7423, 0xAC61, 0x7424, 0xAC62, 0x7425, 0xE7FA, 0x7426, 0xE7F9, 0x7427, 0xAC63, 0x7428, 0xE7FB, 0x7429, 0xAC64, 0x742A, 0xE7F7, 0x742B, 0xAC65, 0x742C, 0xE7FE, 0x742D, 0xAC66, 0x742E, 0xE7FD, 0x742F, 0xAC67, 0x7430, 0xE7FC, 0x7431, 0xAC68, 0x7432, 0xAC69, 0x7433, 0xC1D5, 0x7434, 0xC7D9, 0x7435, 0xC5FD, 0x7436, 0xC5C3, 0x7437, 0xAC6A, 0x7438, 0xAC6B, 0x7439, 0xAC6C, 0x743A, 0xAC6D, 0x743B, 0xAC6E, 0x743C, 0xC7ED, 0x743D, 0xAC6F, 0x743E, 0xAC70, 0x743F, 0xAC71, 0x7440, 0xAC72, 0x7441, 0xE8A3, 0x7442, 0xAC73, 0x7443, 0xAC74, 0x7444, 0xAC75, 0x7445, 0xAC76, 0x7446, 0xAC77, 0x7447, 0xAC78, 0x7448, 0xAC79, 0x7449, 0xAC7A, 0x744A, 0xAC7B, 0x744B, 0xAC7C, 0x744C, 0xAC7D, 0x744D, 0xAC7E, 0x744E, 0xAC80, 0x744F, 0xAC81, 0x7450, 0xAC82, 0x7451, 0xAC83, 0x7452, 0xAC84, 0x7453, 0xAC85, 0x7454, 0xAC86, 0x7455, 0xE8A6, 0x7456, 0xAC87, 0x7457, 0xE8A5, 0x7458, 0xAC88, 0x7459, 0xE8A7, 0x745A, 0xBAF7, 0x745B, 0xE7F8, 0x745C, 0xE8A4, 0x745D, 0xAC89, 0x745E, 0xC8F0, 0x745F, 0xC9AA, 0x7460, 0xAC8A, 0x7461, 0xAC8B, 0x7462, 0xAC8C, 0x7463, 0xAC8D, 0x7464, 0xAC8E, 0x7465, 0xAC8F, 0x7466, 0xAC90, 0x7467, 0xAC91, 0x7468, 0xAC92, 0x7469, 0xAC93, 0x746A, 0xAC94, 0x746B, 0xAC95, 0x746C, 0xAC96, 0x746D, 0xE8A9, 0x746E, 0xAC97, 0x746F, 0xAC98, 0x7470, 0xB9E5, 0x7471, 0xAC99, 0x7472, 0xAC9A, 0x7473, 0xAC9B, 0x7474, 0xAC9C, 0x7475, 0xAC9D, 0x7476, 0xD1FE, 0x7477, 0xE8A8, 0x7478, 0xAC9E, 0x7479, 0xAC9F, 0x747A, 0xACA0, 0x747B, 0xAD40, 0x747C, 0xAD41, 0x747D, 0xAD42, 0x747E, 0xE8AA, 0x747F, 0xAD43, 0x7480, 0xE8AD, 0x7481, 0xE8AE, 0x7482, 0xAD44, 0x7483, 0xC1A7, 0x7484, 0xAD45, 0x7485, 0xAD46, 0x7486, 0xAD47, 0x7487, 0xE8AF, 0x7488, 0xAD48, 0x7489, 0xAD49, 0x748A, 0xAD4A, 0x748B, 0xE8B0, 0x748C, 0xAD4B, 0x748D, 0xAD4C, 0x748E, 0xE8AC, 0x748F, 0xAD4D, 0x7490, 0xE8B4, 0x7491, 0xAD4E, 0x7492, 0xAD4F, 0x7493, 0xAD50, 0x7494, 0xAD51, 0x7495, 0xAD52, 0x7496, 0xAD53, 0x7497, 0xAD54, 0x7498, 0xAD55, 0x7499, 0xAD56, 0x749A, 0xAD57, 0x749B, 0xAD58, 0x749C, 0xE8AB, 0x749D, 0xAD59, 0x749E, 0xE8B1, 0x749F, 0xAD5A, 0x74A0, 0xAD5B, 0x74A1, 0xAD5C, 0x74A2, 0xAD5D, 0x74A3, 0xAD5E, 0x74A4, 0xAD5F, 0x74A5, 0xAD60, 0x74A6, 0xAD61, 0x74A7, 0xE8B5, 0x74A8, 0xE8B2, 0x74A9, 0xE8B3, 0x74AA, 0xAD62, 0x74AB, 0xAD63, 0x74AC, 0xAD64, 0x74AD, 0xAD65, 0x74AE, 0xAD66, 0x74AF, 0xAD67, 0x74B0, 0xAD68, 0x74B1, 0xAD69, 0x74B2, 0xAD6A, 0x74B3, 0xAD6B, 0x74B4, 0xAD6C, 0x74B5, 0xAD6D, 0x74B6, 0xAD6E, 0x74B7, 0xAD6F, 0x74B8, 0xAD70, 0x74B9, 0xAD71, 0x74BA, 0xE8B7, 0x74BB, 0xAD72, 0x74BC, 0xAD73, 0x74BD, 0xAD74, 0x74BE, 0xAD75, 0x74BF, 0xAD76, 0x74C0, 0xAD77, 0x74C1, 0xAD78, 0x74C2, 0xAD79, 0x74C3, 0xAD7A, 0x74C4, 0xAD7B, 0x74C5, 0xAD7C, 0x74C6, 0xAD7D, 0x74C7, 0xAD7E, 0x74C8, 0xAD80, 0x74C9, 0xAD81, 0x74CA, 0xAD82, 0x74CB, 0xAD83, 0x74CC, 0xAD84, 0x74CD, 0xAD85, 0x74CE, 0xAD86, 0x74CF, 0xAD87, 0x74D0, 0xAD88, 0x74D1, 0xAD89, 0x74D2, 0xE8B6, 0x74D3, 0xAD8A, 0x74D4, 0xAD8B, 0x74D5, 0xAD8C, 0x74D6, 0xAD8D, 0x74D7, 0xAD8E, 0x74D8, 0xAD8F, 0x74D9, 0xAD90, 0x74DA, 0xAD91, 0x74DB, 0xAD92, 0x74DC, 0xB9CF, 0x74DD, 0xAD93, 0x74DE, 0xF0AC, 0x74DF, 0xAD94, 0x74E0, 0xF0AD, 0x74E1, 0xAD95, 0x74E2, 0xC6B0, 0x74E3, 0xB0EA, 0x74E4, 0xC8BF, 0x74E5, 0xAD96, 0x74E6, 0xCDDF, 0x74E7, 0xAD97, 0x74E8, 0xAD98, 0x74E9, 0xAD99, 0x74EA, 0xAD9A, 0x74EB, 0xAD9B, 0x74EC, 0xAD9C, 0x74ED, 0xAD9D, 0x74EE, 0xCECD, 0x74EF, 0xEAB1, 0x74F0, 0xAD9E, 0x74F1, 0xAD9F, 0x74F2, 0xADA0, 0x74F3, 0xAE40, 0x74F4, 0xEAB2, 0x74F5, 0xAE41, 0x74F6, 0xC6BF, 0x74F7, 0xB4C9, 0x74F8, 0xAE42, 0x74F9, 0xAE43, 0x74FA, 0xAE44, 0x74FB, 0xAE45, 0x74FC, 0xAE46, 0x74FD, 0xAE47, 0x74FE, 0xAE48, 0x74FF, 0xEAB3, 0x7500, 0xAE49, 0x7501, 0xAE4A, 0x7502, 0xAE4B, 0x7503, 0xAE4C, 0x7504, 0xD5E7, 0x7505, 0xAE4D, 0x7506, 0xAE4E, 0x7507, 0xAE4F, 0x7508, 0xAE50, 0x7509, 0xAE51, 0x750A, 0xAE52, 0x750B, 0xAE53, 0x750C, 0xAE54, 0x750D, 0xDDF9, 0x750E, 0xAE55, 0x750F, 0xEAB4, 0x7510, 0xAE56, 0x7511, 0xEAB5, 0x7512, 0xAE57, 0x7513, 0xEAB6, 0x7514, 0xAE58, 0x7515, 0xAE59, 0x7516, 0xAE5A, 0x7517, 0xAE5B, 0x7518, 0xB8CA, 0x7519, 0xDFB0, 0x751A, 0xC9F5, 0x751B, 0xAE5C, 0x751C, 0xCCF0, 0x751D, 0xAE5D, 0x751E, 0xAE5E, 0x751F, 0xC9FA, 0x7520, 0xAE5F, 0x7521, 0xAE60, 0x7522, 0xAE61, 0x7523, 0xAE62, 0x7524, 0xAE63, 0x7525, 0xC9FB, 0x7526, 0xAE64, 0x7527, 0xAE65, 0x7528, 0xD3C3, 0x7529, 0xCBA6, 0x752A, 0xAE66, 0x752B, 0xB8A6, 0x752C, 0xF0AE, 0x752D, 0xB1C2, 0x752E, 0xAE67, 0x752F, 0xE5B8, 0x7530, 0xCCEF, 0x7531, 0xD3C9, 0x7532, 0xBCD7, 0x7533, 0xC9EA, 0x7534, 0xAE68, 0x7535, 0xB5E7, 0x7536, 0xAE69, 0x7537, 0xC4D0, 0x7538, 0xB5E9, 0x7539, 0xAE6A, 0x753A, 0xEEAE, 0x753B, 0xBBAD, 0x753C, 0xAE6B, 0x753D, 0xAE6C, 0x753E, 0xE7DE, 0x753F, 0xAE6D, 0x7540, 0xEEAF, 0x7541, 0xAE6E, 0x7542, 0xAE6F, 0x7543, 0xAE70, 0x7544, 0xAE71, 0x7545, 0xB3A9, 0x7546, 0xAE72, 0x7547, 0xAE73, 0x7548, 0xEEB2, 0x7549, 0xAE74, 0x754A, 0xAE75, 0x754B, 0xEEB1, 0x754C, 0xBDE7, 0x754D, 0xAE76, 0x754E, 0xEEB0, 0x754F, 0xCEB7, 0x7550, 0xAE77, 0x7551, 0xAE78, 0x7552, 0xAE79, 0x7553, 0xAE7A, 0x7554, 0xC5CF, 0x7555, 0xAE7B, 0x7556, 0xAE7C, 0x7557, 0xAE7D, 0x7558, 0xAE7E, 0x7559, 0xC1F4, 0x755A, 0xDBCE, 0x755B, 0xEEB3, 0x755C, 0xD0F3, 0x755D, 0xAE80, 0x755E, 0xAE81, 0x755F, 0xAE82, 0x7560, 0xAE83, 0x7561, 0xAE84, 0x7562, 0xAE85, 0x7563, 0xAE86, 0x7564, 0xAE87, 0x7565, 0xC2D4, 0x7566, 0xC6E8, 0x7567, 0xAE88, 0x7568, 0xAE89, 0x7569, 0xAE8A, 0x756A, 0xB7AC, 0x756B, 0xAE8B, 0x756C, 0xAE8C, 0x756D, 0xAE8D, 0x756E, 0xAE8E, 0x756F, 0xAE8F, 0x7570, 0xAE90, 0x7571, 0xAE91, 0x7572, 0xEEB4, 0x7573, 0xAE92, 0x7574, 0xB3EB, 0x7575, 0xAE93, 0x7576, 0xAE94, 0x7577, 0xAE95, 0x7578, 0xBBFB, 0x7579, 0xEEB5, 0x757A, 0xAE96, 0x757B, 0xAE97, 0x757C, 0xAE98, 0x757D, 0xAE99, 0x757E, 0xAE9A, 0x757F, 0xE7DC, 0x7580, 0xAE9B, 0x7581, 0xAE9C, 0x7582, 0xAE9D, 0x7583, 0xEEB6, 0x7584, 0xAE9E, 0x7585, 0xAE9F, 0x7586, 0xBDAE, 0x7587, 0xAEA0, 0x7588, 0xAF40, 0x7589, 0xAF41, 0x758A, 0xAF42, 0x758B, 0xF1E2, 0x758C, 0xAF43, 0x758D, 0xAF44, 0x758E, 0xAF45, 0x758F, 0xCAE8, 0x7590, 0xAF46, 0x7591, 0xD2C9, 0x7592, 0xF0DA, 0x7593, 0xAF47, 0x7594, 0xF0DB, 0x7595, 0xAF48, 0x7596, 0xF0DC, 0x7597, 0xC1C6, 0x7598, 0xAF49, 0x7599, 0xB8ED, 0x759A, 0xBECE, 0x759B, 0xAF4A, 0x759C, 0xAF4B, 0x759D, 0xF0DE, 0x759E, 0xAF4C, 0x759F, 0xC5B1, 0x75A0, 0xF0DD, 0x75A1, 0xD1F1, 0x75A2, 0xAF4D, 0x75A3, 0xF0E0, 0x75A4, 0xB0CC, 0x75A5, 0xBDEA, 0x75A6, 0xAF4E, 0x75A7, 0xAF4F, 0x75A8, 0xAF50, 0x75A9, 0xAF51, 0x75AA, 0xAF52, 0x75AB, 0xD2DF, 0x75AC, 0xF0DF, 0x75AD, 0xAF53, 0x75AE, 0xB4AF, 0x75AF, 0xB7E8, 0x75B0, 0xF0E6, 0x75B1, 0xF0E5, 0x75B2, 0xC6A3, 0x75B3, 0xF0E1, 0x75B4, 0xF0E2, 0x75B5, 0xB4C3, 0x75B6, 0xAF54, 0x75B7, 0xAF55, 0x75B8, 0xF0E3, 0x75B9, 0xD5EE, 0x75BA, 0xAF56, 0x75BB, 0xAF57, 0x75BC, 0xCCDB, 0x75BD, 0xBED2, 0x75BE, 0xBCB2, 0x75BF, 0xAF58, 0x75C0, 0xAF59, 0x75C1, 0xAF5A, 0x75C2, 0xF0E8, 0x75C3, 0xF0E7, 0x75C4, 0xF0E4, 0x75C5, 0xB2A1, 0x75C6, 0xAF5B, 0x75C7, 0xD6A2, 0x75C8, 0xD3B8, 0x75C9, 0xBEB7, 0x75CA, 0xC8AC, 0x75CB, 0xAF5C, 0x75CC, 0xAF5D, 0x75CD, 0xF0EA, 0x75CE, 0xAF5E, 0x75CF, 0xAF5F, 0x75D0, 0xAF60, 0x75D1, 0xAF61, 0x75D2, 0xD1F7, 0x75D3, 0xAF62, 0x75D4, 0xD6CC, 0x75D5, 0xBADB, 0x75D6, 0xF0E9, 0x75D7, 0xAF63, 0x75D8, 0xB6BB, 0x75D9, 0xAF64, 0x75DA, 0xAF65, 0x75DB, 0xCDB4, 0x75DC, 0xAF66, 0x75DD, 0xAF67, 0x75DE, 0xC6A6, 0x75DF, 0xAF68, 0x75E0, 0xAF69, 0x75E1, 0xAF6A, 0x75E2, 0xC1A1, 0x75E3, 0xF0EB, 0x75E4, 0xF0EE, 0x75E5, 0xAF6B, 0x75E6, 0xF0ED, 0x75E7, 0xF0F0, 0x75E8, 0xF0EC, 0x75E9, 0xAF6C, 0x75EA, 0xBBBE, 0x75EB, 0xF0EF, 0x75EC, 0xAF6D, 0x75ED, 0xAF6E, 0x75EE, 0xAF6F, 0x75EF, 0xAF70, 0x75F0, 0xCCB5, 0x75F1, 0xF0F2, 0x75F2, 0xAF71, 0x75F3, 0xAF72, 0x75F4, 0xB3D5, 0x75F5, 0xAF73, 0x75F6, 0xAF74, 0x75F7, 0xAF75, 0x75F8, 0xAF76, 0x75F9, 0xB1D4, 0x75FA, 0xAF77, 0x75FB, 0xAF78, 0x75FC, 0xF0F3, 0x75FD, 0xAF79, 0x75FE, 0xAF7A, 0x75FF, 0xF0F4, 0x7600, 0xF0F6, 0x7601, 0xB4E1, 0x7602, 0xAF7B, 0x7603, 0xF0F1, 0x7604, 0xAF7C, 0x7605, 0xF0F7, 0x7606, 0xAF7D, 0x7607, 0xAF7E, 0x7608, 0xAF80, 0x7609, 0xAF81, 0x760A, 0xF0FA, 0x760B, 0xAF82, 0x760C, 0xF0F8, 0x760D, 0xAF83, 0x760E, 0xAF84, 0x760F, 0xAF85, 0x7610, 0xF0F5, 0x7611, 0xAF86, 0x7612, 0xAF87, 0x7613, 0xAF88, 0x7614, 0xAF89, 0x7615, 0xF0FD, 0x7616, 0xAF8A, 0x7617, 0xF0F9, 0x7618, 0xF0FC, 0x7619, 0xF0FE, 0x761A, 0xAF8B, 0x761B, 0xF1A1, 0x761C, 0xAF8C, 0x761D, 0xAF8D, 0x761E, 0xAF8E, 0x761F, 0xCEC1, 0x7620, 0xF1A4, 0x7621, 0xAF8F, 0x7622, 0xF1A3, 0x7623, 0xAF90, 0x7624, 0xC1F6, 0x7625, 0xF0FB, 0x7626, 0xCADD, 0x7627, 0xAF91, 0x7628, 0xAF92, 0x7629, 0xB4F1, 0x762A, 0xB1F1, 0x762B, 0xCCB1, 0x762C, 0xAF93, 0x762D, 0xF1A6, 0x762E, 0xAF94, 0x762F, 0xAF95, 0x7630, 0xF1A7, 0x7631, 0xAF96, 0x7632, 0xAF97, 0x7633, 0xF1AC, 0x7634, 0xD5CE, 0x7635, 0xF1A9, 0x7636, 0xAF98, 0x7637, 0xAF99, 0x7638, 0xC8B3, 0x7639, 0xAF9A, 0x763A, 0xAF9B, 0x763B, 0xAF9C, 0x763C, 0xF1A2, 0x763D, 0xAF9D, 0x763E, 0xF1AB, 0x763F, 0xF1A8, 0x7640, 0xF1A5, 0x7641, 0xAF9E, 0x7642, 0xAF9F, 0x7643, 0xF1AA, 0x7644, 0xAFA0, 0x7645, 0xB040, 0x7646, 0xB041, 0x7647, 0xB042, 0x7648, 0xB043, 0x7649, 0xB044, 0x764A, 0xB045, 0x764B, 0xB046, 0x764C, 0xB0A9, 0x764D, 0xF1AD, 0x764E, 0xB047, 0x764F, 0xB048, 0x7650, 0xB049, 0x7651, 0xB04A, 0x7652, 0xB04B, 0x7653, 0xB04C, 0x7654, 0xF1AF, 0x7655, 0xB04D, 0x7656, 0xF1B1, 0x7657, 0xB04E, 0x7658, 0xB04F, 0x7659, 0xB050, 0x765A, 0xB051, 0x765B, 0xB052, 0x765C, 0xF1B0, 0x765D, 0xB053, 0x765E, 0xF1AE, 0x765F, 0xB054, 0x7660, 0xB055, 0x7661, 0xB056, 0x7662, 0xB057, 0x7663, 0xD1A2, 0x7664, 0xB058, 0x7665, 0xB059, 0x7666, 0xB05A, 0x7667, 0xB05B, 0x7668, 0xB05C, 0x7669, 0xB05D, 0x766A, 0xB05E, 0x766B, 0xF1B2, 0x766C, 0xB05F, 0x766D, 0xB060, 0x766E, 0xB061, 0x766F, 0xF1B3, 0x7670, 0xB062, 0x7671, 0xB063, 0x7672, 0xB064, 0x7673, 0xB065, 0x7674, 0xB066, 0x7675, 0xB067, 0x7676, 0xB068, 0x7677, 0xB069, 0x7678, 0xB9EF, 0x7679, 0xB06A, 0x767A, 0xB06B, 0x767B, 0xB5C7, 0x767C, 0xB06C, 0x767D, 0xB0D7, 0x767E, 0xB0D9, 0x767F, 0xB06D, 0x7680, 0xB06E, 0x7681, 0xB06F, 0x7682, 0xD4ED, 0x7683, 0xB070, 0x7684, 0xB5C4, 0x7685, 0xB071, 0x7686, 0xBDD4, 0x7687, 0xBBCA, 0x7688, 0xF0A7, 0x7689, 0xB072, 0x768A, 0xB073, 0x768B, 0xB8DE, 0x768C, 0xB074, 0x768D, 0xB075, 0x768E, 0xF0A8, 0x768F, 0xB076, 0x7690, 0xB077, 0x7691, 0xB0A8, 0x7692, 0xB078, 0x7693, 0xF0A9, 0x7694, 0xB079, 0x7695, 0xB07A, 0x7696, 0xCDEE, 0x7697, 0xB07B, 0x7698, 0xB07C, 0x7699, 0xF0AA, 0x769A, 0xB07D, 0x769B, 0xB07E, 0x769C, 0xB080, 0x769D, 0xB081, 0x769E, 0xB082, 0x769F, 0xB083, 0x76A0, 0xB084, 0x76A1, 0xB085, 0x76A2, 0xB086, 0x76A3, 0xB087, 0x76A4, 0xF0AB, 0x76A5, 0xB088, 0x76A6, 0xB089, 0x76A7, 0xB08A, 0x76A8, 0xB08B, 0x76A9, 0xB08C, 0x76AA, 0xB08D, 0x76AB, 0xB08E, 0x76AC, 0xB08F, 0x76AD, 0xB090, 0x76AE, 0xC6A4, 0x76AF, 0xB091, 0x76B0, 0xB092, 0x76B1, 0xD6E5, 0x76B2, 0xF1E4, 0x76B3, 0xB093, 0x76B4, 0xF1E5, 0x76B5, 0xB094, 0x76B6, 0xB095, 0x76B7, 0xB096, 0x76B8, 0xB097, 0x76B9, 0xB098, 0x76BA, 0xB099, 0x76BB, 0xB09A, 0x76BC, 0xB09B, 0x76BD, 0xB09C, 0x76BE, 0xB09D, 0x76BF, 0xC3F3, 0x76C0, 0xB09E, 0x76C1, 0xB09F, 0x76C2, 0xD3DB, 0x76C3, 0xB0A0, 0x76C4, 0xB140, 0x76C5, 0xD6D1, 0x76C6, 0xC5E8, 0x76C7, 0xB141, 0x76C8, 0xD3AF, 0x76C9, 0xB142, 0x76CA, 0xD2E6, 0x76CB, 0xB143, 0x76CC, 0xB144, 0x76CD, 0xEEC1, 0x76CE, 0xB0BB, 0x76CF, 0xD5B5, 0x76D0, 0xD1CE, 0x76D1, 0xBCE0, 0x76D2, 0xBAD0, 0x76D3, 0xB145, 0x76D4, 0xBFF8, 0x76D5, 0xB146, 0x76D6, 0xB8C7, 0x76D7, 0xB5C1, 0x76D8, 0xC5CC, 0x76D9, 0xB147, 0x76DA, 0xB148, 0x76DB, 0xCAA2, 0x76DC, 0xB149, 0x76DD, 0xB14A, 0x76DE, 0xB14B, 0x76DF, 0xC3CB, 0x76E0, 0xB14C, 0x76E1, 0xB14D, 0x76E2, 0xB14E, 0x76E3, 0xB14F, 0x76E4, 0xB150, 0x76E5, 0xEEC2, 0x76E6, 0xB151, 0x76E7, 0xB152, 0x76E8, 0xB153, 0x76E9, 0xB154, 0x76EA, 0xB155, 0x76EB, 0xB156, 0x76EC, 0xB157, 0x76ED, 0xB158, 0x76EE, 0xC4BF, 0x76EF, 0xB6A2, 0x76F0, 0xB159, 0x76F1, 0xEDEC, 0x76F2, 0xC3A4, 0x76F3, 0xB15A, 0x76F4, 0xD6B1, 0x76F5, 0xB15B, 0x76F6, 0xB15C, 0x76F7, 0xB15D, 0x76F8, 0xCFE0, 0x76F9, 0xEDEF, 0x76FA, 0xB15E, 0x76FB, 0xB15F, 0x76FC, 0xC5CE, 0x76FD, 0xB160, 0x76FE, 0xB6DC, 0x76FF, 0xB161, 0x7700, 0xB162, 0x7701, 0xCAA1, 0x7702, 0xB163, 0x7703, 0xB164, 0x7704, 0xEDED, 0x7705, 0xB165, 0x7706, 0xB166, 0x7707, 0xEDF0, 0x7708, 0xEDF1, 0x7709, 0xC3BC, 0x770A, 0xB167, 0x770B, 0xBFB4, 0x770C, 0xB168, 0x770D, 0xEDEE, 0x770E, 0xB169, 0x770F, 0xB16A, 0x7710, 0xB16B, 0x7711, 0xB16C, 0x7712, 0xB16D, 0x7713, 0xB16E, 0x7714, 0xB16F, 0x7715, 0xB170, 0x7716, 0xB171, 0x7717, 0xB172, 0x7718, 0xB173, 0x7719, 0xEDF4, 0x771A, 0xEDF2, 0x771B, 0xB174, 0x771C, 0xB175, 0x771D, 0xB176, 0x771E, 0xB177, 0x771F, 0xD5E6, 0x7720, 0xC3DF, 0x7721, 0xB178, 0x7722, 0xEDF3, 0x7723, 0xB179, 0x7724, 0xB17A, 0x7725, 0xB17B, 0x7726, 0xEDF6, 0x7727, 0xB17C, 0x7728, 0xD5A3, 0x7729, 0xD1A3, 0x772A, 0xB17D, 0x772B, 0xB17E, 0x772C, 0xB180, 0x772D, 0xEDF5, 0x772E, 0xB181, 0x772F, 0xC3D0, 0x7730, 0xB182, 0x7731, 0xB183, 0x7732, 0xB184, 0x7733, 0xB185, 0x7734, 0xB186, 0x7735, 0xEDF7, 0x7736, 0xBFF4, 0x7737, 0xBEEC, 0x7738, 0xEDF8, 0x7739, 0xB187, 0x773A, 0xCCF7, 0x773B, 0xB188, 0x773C, 0xD1DB, 0x773D, 0xB189, 0x773E, 0xB18A, 0x773F, 0xB18B, 0x7740, 0xD7C5, 0x7741, 0xD5F6, 0x7742, 0xB18C, 0x7743, 0xEDFC, 0x7744, 0xB18D, 0x7745, 0xB18E, 0x7746, 0xB18F, 0x7747, 0xEDFB, 0x7748, 0xB190, 0x7749, 0xB191, 0x774A, 0xB192, 0x774B, 0xB193, 0x774C, 0xB194, 0x774D, 0xB195, 0x774E, 0xB196, 0x774F, 0xB197, 0x7750, 0xEDF9, 0x7751, 0xEDFA, 0x7752, 0xB198, 0x7753, 0xB199, 0x7754, 0xB19A, 0x7755, 0xB19B, 0x7756, 0xB19C, 0x7757, 0xB19D, 0x7758, 0xB19E, 0x7759, 0xB19F, 0x775A, 0xEDFD, 0x775B, 0xBEA6, 0x775C, 0xB1A0, 0x775D, 0xB240, 0x775E, 0xB241, 0x775F, 0xB242, 0x7760, 0xB243, 0x7761, 0xCBAF, 0x7762, 0xEEA1, 0x7763, 0xB6BD, 0x7764, 0xB244, 0x7765, 0xEEA2, 0x7766, 0xC4C0, 0x7767, 0xB245, 0x7768, 0xEDFE, 0x7769, 0xB246, 0x776A, 0xB247, 0x776B, 0xBDDE, 0x776C, 0xB2C7, 0x776D, 0xB248, 0x776E, 0xB249, 0x776F, 0xB24A, 0x7770, 0xB24B, 0x7771, 0xB24C, 0x7772, 0xB24D, 0x7773, 0xB24E, 0x7774, 0xB24F, 0x7775, 0xB250, 0x7776, 0xB251, 0x7777, 0xB252, 0x7778, 0xB253, 0x7779, 0xB6C3, 0x777A, 0xB254, 0x777B, 0xB255, 0x777C, 0xB256, 0x777D, 0xEEA5, 0x777E, 0xD8BA, 0x777F, 0xEEA3, 0x7780, 0xEEA6, 0x7781, 0xB257, 0x7782, 0xB258, 0x7783, 0xB259, 0x7784, 0xC3E9, 0x7785, 0xB3F2, 0x7786, 0xB25A, 0x7787, 0xB25B, 0x7788, 0xB25C, 0x7789, 0xB25D, 0x778A, 0xB25E, 0x778B, 0xB25F, 0x778C, 0xEEA7, 0x778D, 0xEEA4, 0x778E, 0xCFB9, 0x778F, 0xB260, 0x7790, 0xB261, 0x7791, 0xEEA8, 0x7792, 0xC2F7, 0x7793, 0xB262, 0x7794, 0xB263, 0x7795, 0xB264, 0x7796, 0xB265, 0x7797, 0xB266, 0x7798, 0xB267, 0x7799, 0xB268, 0x779A, 0xB269, 0x779B, 0xB26A, 0x779C, 0xB26B, 0x779D, 0xB26C, 0x779E, 0xB26D, 0x779F, 0xEEA9, 0x77A0, 0xEEAA, 0x77A1, 0xB26E, 0x77A2, 0xDEAB, 0x77A3, 0xB26F, 0x77A4, 0xB270, 0x77A5, 0xC6B3, 0x77A6, 0xB271, 0x77A7, 0xC7C6, 0x77A8, 0xB272, 0x77A9, 0xD6F5, 0x77AA, 0xB5C9, 0x77AB, 0xB273, 0x77AC, 0xCBB2, 0x77AD, 0xB274, 0x77AE, 0xB275, 0x77AF, 0xB276, 0x77B0, 0xEEAB, 0x77B1, 0xB277, 0x77B2, 0xB278, 0x77B3, 0xCDAB, 0x77B4, 0xB279, 0x77B5, 0xEEAC, 0x77B6, 0xB27A, 0x77B7, 0xB27B, 0x77B8, 0xB27C, 0x77B9, 0xB27D, 0x77BA, 0xB27E, 0x77BB, 0xD5B0, 0x77BC, 0xB280, 0x77BD, 0xEEAD, 0x77BE, 0xB281, 0x77BF, 0xF6C4, 0x77C0, 0xB282, 0x77C1, 0xB283, 0x77C2, 0xB284, 0x77C3, 0xB285, 0x77C4, 0xB286, 0x77C5, 0xB287, 0x77C6, 0xB288, 0x77C7, 0xB289, 0x77C8, 0xB28A, 0x77C9, 0xB28B, 0x77CA, 0xB28C, 0x77CB, 0xB28D, 0x77CC, 0xB28E, 0x77CD, 0xDBC7, 0x77CE, 0xB28F, 0x77CF, 0xB290, 0x77D0, 0xB291, 0x77D1, 0xB292, 0x77D2, 0xB293, 0x77D3, 0xB294, 0x77D4, 0xB295, 0x77D5, 0xB296, 0x77D6, 0xB297, 0x77D7, 0xB4A3, 0x77D8, 0xB298, 0x77D9, 0xB299, 0x77DA, 0xB29A, 0x77DB, 0xC3AC, 0x77DC, 0xF1E6, 0x77DD, 0xB29B, 0x77DE, 0xB29C, 0x77DF, 0xB29D, 0x77E0, 0xB29E, 0x77E1, 0xB29F, 0x77E2, 0xCAB8, 0x77E3, 0xD2D3, 0x77E4, 0xB2A0, 0x77E5, 0xD6AA, 0x77E6, 0xB340, 0x77E7, 0xEFF2, 0x77E8, 0xB341, 0x77E9, 0xBED8, 0x77EA, 0xB342, 0x77EB, 0xBDC3, 0x77EC, 0xEFF3, 0x77ED, 0xB6CC, 0x77EE, 0xB0AB, 0x77EF, 0xB343, 0x77F0, 0xB344, 0x77F1, 0xB345, 0x77F2, 0xB346, 0x77F3, 0xCAAF, 0x77F4, 0xB347, 0x77F5, 0xB348, 0x77F6, 0xEDB6, 0x77F7, 0xB349, 0x77F8, 0xEDB7, 0x77F9, 0xB34A, 0x77FA, 0xB34B, 0x77FB, 0xB34C, 0x77FC, 0xB34D, 0x77FD, 0xCEF9, 0x77FE, 0xB7AF, 0x77FF, 0xBFF3, 0x7800, 0xEDB8, 0x7801, 0xC2EB, 0x7802, 0xC9B0, 0x7803, 0xB34E, 0x7804, 0xB34F, 0x7805, 0xB350, 0x7806, 0xB351, 0x7807, 0xB352, 0x7808, 0xB353, 0x7809, 0xEDB9, 0x780A, 0xB354, 0x780B, 0xB355, 0x780C, 0xC6F6, 0x780D, 0xBFB3, 0x780E, 0xB356, 0x780F, 0xB357, 0x7810, 0xB358, 0x7811, 0xEDBC, 0x7812, 0xC5F8, 0x7813, 0xB359, 0x7814, 0xD1D0, 0x7815, 0xB35A, 0x7816, 0xD7A9, 0x7817, 0xEDBA, 0x7818, 0xEDBB, 0x7819, 0xB35B, 0x781A, 0xD1E2, 0x781B, 0xB35C, 0x781C, 0xEDBF, 0x781D, 0xEDC0, 0x781E, 0xB35D, 0x781F, 0xEDC4, 0x7820, 0xB35E, 0x7821, 0xB35F, 0x7822, 0xB360, 0x7823, 0xEDC8, 0x7824, 0xB361, 0x7825, 0xEDC6, 0x7826, 0xEDCE, 0x7827, 0xD5E8, 0x7828, 0xB362, 0x7829, 0xEDC9, 0x782A, 0xB363, 0x782B, 0xB364, 0x782C, 0xEDC7, 0x782D, 0xEDBE, 0x782E, 0xB365, 0x782F, 0xB366, 0x7830, 0xC5E9, 0x7831, 0xB367, 0x7832, 0xB368, 0x7833, 0xB369, 0x7834, 0xC6C6, 0x7835, 0xB36A, 0x7836, 0xB36B, 0x7837, 0xC9E9, 0x7838, 0xD4D2, 0x7839, 0xEDC1, 0x783A, 0xEDC2, 0x783B, 0xEDC3, 0x783C, 0xEDC5, 0x783D, 0xB36C, 0x783E, 0xC0F9, 0x783F, 0xB36D, 0x7840, 0xB4A1, 0x7841, 0xB36E, 0x7842, 0xB36F, 0x7843, 0xB370, 0x7844, 0xB371, 0x7845, 0xB9E8, 0x7846, 0xB372, 0x7847, 0xEDD0, 0x7848, 0xB373, 0x7849, 0xB374, 0x784A, 0xB375, 0x784B, 0xB376, 0x784C, 0xEDD1, 0x784D, 0xB377, 0x784E, 0xEDCA, 0x784F, 0xB378, 0x7850, 0xEDCF, 0x7851, 0xB379, 0x7852, 0xCEF8, 0x7853, 0xB37A, 0x7854, 0xB37B, 0x7855, 0xCBB6, 0x7856, 0xEDCC, 0x7857, 0xEDCD, 0x7858, 0xB37C, 0x7859, 0xB37D, 0x785A, 0xB37E, 0x785B, 0xB380, 0x785C, 0xB381, 0x785D, 0xCFF5, 0x785E, 0xB382, 0x785F, 0xB383, 0x7860, 0xB384, 0x7861, 0xB385, 0x7862, 0xB386, 0x7863, 0xB387, 0x7864, 0xB388, 0x7865, 0xB389, 0x7866, 0xB38A, 0x7867, 0xB38B, 0x7868, 0xB38C, 0x7869, 0xB38D, 0x786A, 0xEDD2, 0x786B, 0xC1F2, 0x786C, 0xD3B2, 0x786D, 0xEDCB, 0x786E, 0xC8B7, 0x786F, 0xB38E, 0x7870, 0xB38F, 0x7871, 0xB390, 0x7872, 0xB391, 0x7873, 0xB392, 0x7874, 0xB393, 0x7875, 0xB394, 0x7876, 0xB395, 0x7877, 0xBCEF, 0x7878, 0xB396, 0x7879, 0xB397, 0x787A, 0xB398, 0x787B, 0xB399, 0x787C, 0xC5F0, 0x787D, 0xB39A, 0x787E, 0xB39B, 0x787F, 0xB39C, 0x7880, 0xB39D, 0x7881, 0xB39E, 0x7882, 0xB39F, 0x7883, 0xB3A0, 0x7884, 0xB440, 0x7885, 0xB441, 0x7886, 0xB442, 0x7887, 0xEDD6, 0x7888, 0xB443, 0x7889, 0xB5EF, 0x788A, 0xB444, 0x788B, 0xB445, 0x788C, 0xC2B5, 0x788D, 0xB0AD, 0x788E, 0xCBE9, 0x788F, 0xB446, 0x7890, 0xB447, 0x7891, 0xB1AE, 0x7892, 0xB448, 0x7893, 0xEDD4, 0x7894, 0xB449, 0x7895, 0xB44A, 0x7896, 0xB44B, 0x7897, 0xCDEB, 0x7898, 0xB5E2, 0x7899, 0xB44C, 0x789A, 0xEDD5, 0x789B, 0xEDD3, 0x789C, 0xEDD7, 0x789D, 0xB44D, 0x789E, 0xB44E, 0x789F, 0xB5FA, 0x78A0, 0xB44F, 0x78A1, 0xEDD8, 0x78A2, 0xB450, 0x78A3, 0xEDD9, 0x78A4, 0xB451, 0x78A5, 0xEDDC, 0x78A6, 0xB452, 0x78A7, 0xB1CC, 0x78A8, 0xB453, 0x78A9, 0xB454, 0x78AA, 0xB455, 0x78AB, 0xB456, 0x78AC, 0xB457, 0x78AD, 0xB458, 0x78AE, 0xB459, 0x78AF, 0xB45A, 0x78B0, 0xC5F6, 0x78B1, 0xBCEE, 0x78B2, 0xEDDA, 0x78B3, 0xCCBC, 0x78B4, 0xB2EA, 0x78B5, 0xB45B, 0x78B6, 0xB45C, 0x78B7, 0xB45D, 0x78B8, 0xB45E, 0x78B9, 0xEDDB, 0x78BA, 0xB45F, 0x78BB, 0xB460, 0x78BC, 0xB461, 0x78BD, 0xB462, 0x78BE, 0xC4EB, 0x78BF, 0xB463, 0x78C0, 0xB464, 0x78C1, 0xB4C5, 0x78C2, 0xB465, 0x78C3, 0xB466, 0x78C4, 0xB467, 0x78C5, 0xB0F5, 0x78C6, 0xB468, 0x78C7, 0xB469, 0x78C8, 0xB46A, 0x78C9, 0xEDDF, 0x78CA, 0xC0DA, 0x78CB, 0xB4E8, 0x78CC, 0xB46B, 0x78CD, 0xB46C, 0x78CE, 0xB46D, 0x78CF, 0xB46E, 0x78D0, 0xC5CD, 0x78D1, 0xB46F, 0x78D2, 0xB470, 0x78D3, 0xB471, 0x78D4, 0xEDDD, 0x78D5, 0xBFC4, 0x78D6, 0xB472, 0x78D7, 0xB473, 0x78D8, 0xB474, 0x78D9, 0xEDDE, 0x78DA, 0xB475, 0x78DB, 0xB476, 0x78DC, 0xB477, 0x78DD, 0xB478, 0x78DE, 0xB479, 0x78DF, 0xB47A, 0x78E0, 0xB47B, 0x78E1, 0xB47C, 0x78E2, 0xB47D, 0x78E3, 0xB47E, 0x78E4, 0xB480, 0x78E5, 0xB481, 0x78E6, 0xB482, 0x78E7, 0xB483, 0x78E8, 0xC4A5, 0x78E9, 0xB484, 0x78EA, 0xB485, 0x78EB, 0xB486, 0x78EC, 0xEDE0, 0x78ED, 0xB487, 0x78EE, 0xB488, 0x78EF, 0xB489, 0x78F0, 0xB48A, 0x78F1, 0xB48B, 0x78F2, 0xEDE1, 0x78F3, 0xB48C, 0x78F4, 0xEDE3, 0x78F5, 0xB48D, 0x78F6, 0xB48E, 0x78F7, 0xC1D7, 0x78F8, 0xB48F, 0x78F9, 0xB490, 0x78FA, 0xBBC7, 0x78FB, 0xB491, 0x78FC, 0xB492, 0x78FD, 0xB493, 0x78FE, 0xB494, 0x78FF, 0xB495, 0x7900, 0xB496, 0x7901, 0xBDB8, 0x7902, 0xB497, 0x7903, 0xB498, 0x7904, 0xB499, 0x7905, 0xEDE2, 0x7906, 0xB49A, 0x7907, 0xB49B, 0x7908, 0xB49C, 0x7909, 0xB49D, 0x790A, 0xB49E, 0x790B, 0xB49F, 0x790C, 0xB4A0, 0x790D, 0xB540, 0x790E, 0xB541, 0x790F, 0xB542, 0x7910, 0xB543, 0x7911, 0xB544, 0x7912, 0xB545, 0x7913, 0xEDE4, 0x7914, 0xB546, 0x7915, 0xB547, 0x7916, 0xB548, 0x7917, 0xB549, 0x7918, 0xB54A, 0x7919, 0xB54B, 0x791A, 0xB54C, 0x791B, 0xB54D, 0x791C, 0xB54E, 0x791D, 0xB54F, 0x791E, 0xEDE6, 0x791F, 0xB550, 0x7920, 0xB551, 0x7921, 0xB552, 0x7922, 0xB553, 0x7923, 0xB554, 0x7924, 0xEDE5, 0x7925, 0xB555, 0x7926, 0xB556, 0x7927, 0xB557, 0x7928, 0xB558, 0x7929, 0xB559, 0x792A, 0xB55A, 0x792B, 0xB55B, 0x792C, 0xB55C, 0x792D, 0xB55D, 0x792E, 0xB55E, 0x792F, 0xB55F, 0x7930, 0xB560, 0x7931, 0xB561, 0x7932, 0xB562, 0x7933, 0xB563, 0x7934, 0xEDE7, 0x7935, 0xB564, 0x7936, 0xB565, 0x7937, 0xB566, 0x7938, 0xB567, 0x7939, 0xB568, 0x793A, 0xCABE, 0x793B, 0xECEA, 0x793C, 0xC0F1, 0x793D, 0xB569, 0x793E, 0xC9E7, 0x793F, 0xB56A, 0x7940, 0xECEB, 0x7941, 0xC6EE, 0x7942, 0xB56B, 0x7943, 0xB56C, 0x7944, 0xB56D, 0x7945, 0xB56E, 0x7946, 0xECEC, 0x7947, 0xB56F, 0x7948, 0xC6ED, 0x7949, 0xECED, 0x794A, 0xB570, 0x794B, 0xB571, 0x794C, 0xB572, 0x794D, 0xB573, 0x794E, 0xB574, 0x794F, 0xB575, 0x7950, 0xB576, 0x7951, 0xB577, 0x7952, 0xB578, 0x7953, 0xECF0, 0x7954, 0xB579, 0x7955, 0xB57A, 0x7956, 0xD7E6, 0x7957, 0xECF3, 0x7958, 0xB57B, 0x7959, 0xB57C, 0x795A, 0xECF1, 0x795B, 0xECEE, 0x795C, 0xECEF, 0x795D, 0xD7A3, 0x795E, 0xC9F1, 0x795F, 0xCBEE, 0x7960, 0xECF4, 0x7961, 0xB57D, 0x7962, 0xECF2, 0x7963, 0xB57E, 0x7964, 0xB580, 0x7965, 0xCFE9, 0x7966, 0xB581, 0x7967, 0xECF6, 0x7968, 0xC6B1, 0x7969, 0xB582, 0x796A, 0xB583, 0x796B, 0xB584, 0x796C, 0xB585, 0x796D, 0xBCC0, 0x796E, 0xB586, 0x796F, 0xECF5, 0x7970, 0xB587, 0x7971, 0xB588, 0x7972, 0xB589, 0x7973, 0xB58A, 0x7974, 0xB58B, 0x7975, 0xB58C, 0x7976, 0xB58D, 0x7977, 0xB5BB, 0x7978, 0xBBF6, 0x7979, 0xB58E, 0x797A, 0xECF7, 0x797B, 0xB58F, 0x797C, 0xB590, 0x797D, 0xB591, 0x797E, 0xB592, 0x797F, 0xB593, 0x7980, 0xD9F7, 0x7981, 0xBDFB, 0x7982, 0xB594, 0x7983, 0xB595, 0x7984, 0xC2BB, 0x7985, 0xECF8, 0x7986, 0xB596, 0x7987, 0xB597, 0x7988, 0xB598, 0x7989, 0xB599, 0x798A, 0xECF9, 0x798B, 0xB59A, 0x798C, 0xB59B, 0x798D, 0xB59C, 0x798E, 0xB59D, 0x798F, 0xB8A3, 0x7990, 0xB59E, 0x7991, 0xB59F, 0x7992, 0xB5A0, 0x7993, 0xB640, 0x7994, 0xB641, 0x7995, 0xB642, 0x7996, 0xB643, 0x7997, 0xB644, 0x7998, 0xB645, 0x7999, 0xB646, 0x799A, 0xECFA, 0x799B, 0xB647, 0x799C, 0xB648, 0x799D, 0xB649, 0x799E, 0xB64A, 0x799F, 0xB64B, 0x79A0, 0xB64C, 0x79A1, 0xB64D, 0x79A2, 0xB64E, 0x79A3, 0xB64F, 0x79A4, 0xB650, 0x79A5, 0xB651, 0x79A6, 0xB652, 0x79A7, 0xECFB, 0x79A8, 0xB653, 0x79A9, 0xB654, 0x79AA, 0xB655, 0x79AB, 0xB656, 0x79AC, 0xB657, 0x79AD, 0xB658, 0x79AE, 0xB659, 0x79AF, 0xB65A, 0x79B0, 0xB65B, 0x79B1, 0xB65C, 0x79B2, 0xB65D, 0x79B3, 0xECFC, 0x79B4, 0xB65E, 0x79B5, 0xB65F, 0x79B6, 0xB660, 0x79B7, 0xB661, 0x79B8, 0xB662, 0x79B9, 0xD3ED, 0x79BA, 0xD8AE, 0x79BB, 0xC0EB, 0x79BC, 0xB663, 0x79BD, 0xC7DD, 0x79BE, 0xBACC, 0x79BF, 0xB664, 0x79C0, 0xD0E3, 0x79C1, 0xCBBD, 0x79C2, 0xB665, 0x79C3, 0xCDBA, 0x79C4, 0xB666, 0x79C5, 0xB667, 0x79C6, 0xB8D1, 0x79C7, 0xB668, 0x79C8, 0xB669, 0x79C9, 0xB1FC, 0x79CA, 0xB66A, 0x79CB, 0xC7EF, 0x79CC, 0xB66B, 0x79CD, 0xD6D6, 0x79CE, 0xB66C, 0x79CF, 0xB66D, 0x79D0, 0xB66E, 0x79D1, 0xBFC6, 0x79D2, 0xC3EB, 0x79D3, 0xB66F, 0x79D4, 0xB670, 0x79D5, 0xEFF5, 0x79D6, 0xB671, 0x79D7, 0xB672, 0x79D8, 0xC3D8, 0x79D9, 0xB673, 0x79DA, 0xB674, 0x79DB, 0xB675, 0x79DC, 0xB676, 0x79DD, 0xB677, 0x79DE, 0xB678, 0x79DF, 0xD7E2, 0x79E0, 0xB679, 0x79E1, 0xB67A, 0x79E2, 0xB67B, 0x79E3, 0xEFF7, 0x79E4, 0xB3D3, 0x79E5, 0xB67C, 0x79E6, 0xC7D8, 0x79E7, 0xD1ED, 0x79E8, 0xB67D, 0x79E9, 0xD6C8, 0x79EA, 0xB67E, 0x79EB, 0xEFF8, 0x79EC, 0xB680, 0x79ED, 0xEFF6, 0x79EE, 0xB681, 0x79EF, 0xBBFD, 0x79F0, 0xB3C6, 0x79F1, 0xB682, 0x79F2, 0xB683, 0x79F3, 0xB684, 0x79F4, 0xB685, 0x79F5, 0xB686, 0x79F6, 0xB687, 0x79F7, 0xB688, 0x79F8, 0xBDD5, 0x79F9, 0xB689, 0x79FA, 0xB68A, 0x79FB, 0xD2C6, 0x79FC, 0xB68B, 0x79FD, 0xBBE0, 0x79FE, 0xB68C, 0x79FF, 0xB68D, 0x7A00, 0xCFA1, 0x7A01, 0xB68E, 0x7A02, 0xEFFC, 0x7A03, 0xEFFB, 0x7A04, 0xB68F, 0x7A05, 0xB690, 0x7A06, 0xEFF9, 0x7A07, 0xB691, 0x7A08, 0xB692, 0x7A09, 0xB693, 0x7A0A, 0xB694, 0x7A0B, 0xB3CC, 0x7A0C, 0xB695, 0x7A0D, 0xC9D4, 0x7A0E, 0xCBB0, 0x7A0F, 0xB696, 0x7A10, 0xB697, 0x7A11, 0xB698, 0x7A12, 0xB699, 0x7A13, 0xB69A, 0x7A14, 0xEFFE, 0x7A15, 0xB69B, 0x7A16, 0xB69C, 0x7A17, 0xB0DE, 0x7A18, 0xB69D, 0x7A19, 0xB69E, 0x7A1A, 0xD6C9, 0x7A1B, 0xB69F, 0x7A1C, 0xB6A0, 0x7A1D, 0xB740, 0x7A1E, 0xEFFD, 0x7A1F, 0xB741, 0x7A20, 0xB3ED, 0x7A21, 0xB742, 0x7A22, 0xB743, 0x7A23, 0xF6D5, 0x7A24, 0xB744, 0x7A25, 0xB745, 0x7A26, 0xB746, 0x7A27, 0xB747, 0x7A28, 0xB748, 0x7A29, 0xB749, 0x7A2A, 0xB74A, 0x7A2B, 0xB74B, 0x7A2C, 0xB74C, 0x7A2D, 0xB74D, 0x7A2E, 0xB74E, 0x7A2F, 0xB74F, 0x7A30, 0xB750, 0x7A31, 0xB751, 0x7A32, 0xB752, 0x7A33, 0xCEC8, 0x7A34, 0xB753, 0x7A35, 0xB754, 0x7A36, 0xB755, 0x7A37, 0xF0A2, 0x7A38, 0xB756, 0x7A39, 0xF0A1, 0x7A3A, 0xB757, 0x7A3B, 0xB5BE, 0x7A3C, 0xBCDA, 0x7A3D, 0xBBFC, 0x7A3E, 0xB758, 0x7A3F, 0xB8E5, 0x7A40, 0xB759, 0x7A41, 0xB75A, 0x7A42, 0xB75B, 0x7A43, 0xB75C, 0x7A44, 0xB75D, 0x7A45, 0xB75E, 0x7A46, 0xC4C2, 0x7A47, 0xB75F, 0x7A48, 0xB760, 0x7A49, 0xB761, 0x7A4A, 0xB762, 0x7A4B, 0xB763, 0x7A4C, 0xB764, 0x7A4D, 0xB765, 0x7A4E, 0xB766, 0x7A4F, 0xB767, 0x7A50, 0xB768, 0x7A51, 0xF0A3, 0x7A52, 0xB769, 0x7A53, 0xB76A, 0x7A54, 0xB76B, 0x7A55, 0xB76C, 0x7A56, 0xB76D, 0x7A57, 0xCBEB, 0x7A58, 0xB76E, 0x7A59, 0xB76F, 0x7A5A, 0xB770, 0x7A5B, 0xB771, 0x7A5C, 0xB772, 0x7A5D, 0xB773, 0x7A5E, 0xB774, 0x7A5F, 0xB775, 0x7A60, 0xB776, 0x7A61, 0xB777, 0x7A62, 0xB778, 0x7A63, 0xB779, 0x7A64, 0xB77A, 0x7A65, 0xB77B, 0x7A66, 0xB77C, 0x7A67, 0xB77D, 0x7A68, 0xB77E, 0x7A69, 0xB780, 0x7A6A, 0xB781, 0x7A6B, 0xB782, 0x7A6C, 0xB783, 0x7A6D, 0xB784, 0x7A6E, 0xB785, 0x7A6F, 0xB786, 0x7A70, 0xF0A6, 0x7A71, 0xB787, 0x7A72, 0xB788, 0x7A73, 0xB789, 0x7A74, 0xD1A8, 0x7A75, 0xB78A, 0x7A76, 0xBEBF, 0x7A77, 0xC7EE, 0x7A78, 0xF1B6, 0x7A79, 0xF1B7, 0x7A7A, 0xBFD5, 0x7A7B, 0xB78B, 0x7A7C, 0xB78C, 0x7A7D, 0xB78D, 0x7A7E, 0xB78E, 0x7A7F, 0xB4A9, 0x7A80, 0xF1B8, 0x7A81, 0xCDBB, 0x7A82, 0xB78F, 0x7A83, 0xC7D4, 0x7A84, 0xD5AD, 0x7A85, 0xB790, 0x7A86, 0xF1B9, 0x7A87, 0xB791, 0x7A88, 0xF1BA, 0x7A89, 0xB792, 0x7A8A, 0xB793, 0x7A8B, 0xB794, 0x7A8C, 0xB795, 0x7A8D, 0xC7CF, 0x7A8E, 0xB796, 0x7A8F, 0xB797, 0x7A90, 0xB798, 0x7A91, 0xD2A4, 0x7A92, 0xD6CF, 0x7A93, 0xB799, 0x7A94, 0xB79A, 0x7A95, 0xF1BB, 0x7A96, 0xBDD1, 0x7A97, 0xB4B0, 0x7A98, 0xBEBD, 0x7A99, 0xB79B, 0x7A9A, 0xB79C, 0x7A9B, 0xB79D, 0x7A9C, 0xB4DC, 0x7A9D, 0xCED1, 0x7A9E, 0xB79E, 0x7A9F, 0xBFDF, 0x7AA0, 0xF1BD, 0x7AA1, 0xB79F, 0x7AA2, 0xB7A0, 0x7AA3, 0xB840, 0x7AA4, 0xB841, 0x7AA5, 0xBFFA, 0x7AA6, 0xF1BC, 0x7AA7, 0xB842, 0x7AA8, 0xF1BF, 0x7AA9, 0xB843, 0x7AAA, 0xB844, 0x7AAB, 0xB845, 0x7AAC, 0xF1BE, 0x7AAD, 0xF1C0, 0x7AAE, 0xB846, 0x7AAF, 0xB847, 0x7AB0, 0xB848, 0x7AB1, 0xB849, 0x7AB2, 0xB84A, 0x7AB3, 0xF1C1, 0x7AB4, 0xB84B, 0x7AB5, 0xB84C, 0x7AB6, 0xB84D, 0x7AB7, 0xB84E, 0x7AB8, 0xB84F, 0x7AB9, 0xB850, 0x7ABA, 0xB851, 0x7ABB, 0xB852, 0x7ABC, 0xB853, 0x7ABD, 0xB854, 0x7ABE, 0xB855, 0x7ABF, 0xC1FE, 0x7AC0, 0xB856, 0x7AC1, 0xB857, 0x7AC2, 0xB858, 0x7AC3, 0xB859, 0x7AC4, 0xB85A, 0x7AC5, 0xB85B, 0x7AC6, 0xB85C, 0x7AC7, 0xB85D, 0x7AC8, 0xB85E, 0x7AC9, 0xB85F, 0x7ACA, 0xB860, 0x7ACB, 0xC1A2, 0x7ACC, 0xB861, 0x7ACD, 0xB862, 0x7ACE, 0xB863, 0x7ACF, 0xB864, 0x7AD0, 0xB865, 0x7AD1, 0xB866, 0x7AD2, 0xB867, 0x7AD3, 0xB868, 0x7AD4, 0xB869, 0x7AD5, 0xB86A, 0x7AD6, 0xCAFA, 0x7AD7, 0xB86B, 0x7AD8, 0xB86C, 0x7AD9, 0xD5BE, 0x7ADA, 0xB86D, 0x7ADB, 0xB86E, 0x7ADC, 0xB86F, 0x7ADD, 0xB870, 0x7ADE, 0xBEBA, 0x7ADF, 0xBEB9, 0x7AE0, 0xD5C2, 0x7AE1, 0xB871, 0x7AE2, 0xB872, 0x7AE3, 0xBFA2, 0x7AE4, 0xB873, 0x7AE5, 0xCDAF, 0x7AE6, 0xF1B5, 0x7AE7, 0xB874, 0x7AE8, 0xB875, 0x7AE9, 0xB876, 0x7AEA, 0xB877, 0x7AEB, 0xB878, 0x7AEC, 0xB879, 0x7AED, 0xBDDF, 0x7AEE, 0xB87A, 0x7AEF, 0xB6CB, 0x7AF0, 0xB87B, 0x7AF1, 0xB87C, 0x7AF2, 0xB87D, 0x7AF3, 0xB87E, 0x7AF4, 0xB880, 0x7AF5, 0xB881, 0x7AF6, 0xB882, 0x7AF7, 0xB883, 0x7AF8, 0xB884, 0x7AF9, 0xD6F1, 0x7AFA, 0xF3C3, 0x7AFB, 0xB885, 0x7AFC, 0xB886, 0x7AFD, 0xF3C4, 0x7AFE, 0xB887, 0x7AFF, 0xB8CD, 0x7B00, 0xB888, 0x7B01, 0xB889, 0x7B02, 0xB88A, 0x7B03, 0xF3C6, 0x7B04, 0xF3C7, 0x7B05, 0xB88B, 0x7B06, 0xB0CA, 0x7B07, 0xB88C, 0x7B08, 0xF3C5, 0x7B09, 0xB88D, 0x7B0A, 0xF3C9, 0x7B0B, 0xCBF1, 0x7B0C, 0xB88E, 0x7B0D, 0xB88F, 0x7B0E, 0xB890, 0x7B0F, 0xF3CB, 0x7B10, 0xB891, 0x7B11, 0xD0A6, 0x7B12, 0xB892, 0x7B13, 0xB893, 0x7B14, 0xB1CA, 0x7B15, 0xF3C8, 0x7B16, 0xB894, 0x7B17, 0xB895, 0x7B18, 0xB896, 0x7B19, 0xF3CF, 0x7B1A, 0xB897, 0x7B1B, 0xB5D1, 0x7B1C, 0xB898, 0x7B1D, 0xB899, 0x7B1E, 0xF3D7, 0x7B1F, 0xB89A, 0x7B20, 0xF3D2, 0x7B21, 0xB89B, 0x7B22, 0xB89C, 0x7B23, 0xB89D, 0x7B24, 0xF3D4, 0x7B25, 0xF3D3, 0x7B26, 0xB7FB, 0x7B27, 0xB89E, 0x7B28, 0xB1BF, 0x7B29, 0xB89F, 0x7B2A, 0xF3CE, 0x7B2B, 0xF3CA, 0x7B2C, 0xB5DA, 0x7B2D, 0xB8A0, 0x7B2E, 0xF3D0, 0x7B2F, 0xB940, 0x7B30, 0xB941, 0x7B31, 0xF3D1, 0x7B32, 0xB942, 0x7B33, 0xF3D5, 0x7B34, 0xB943, 0x7B35, 0xB944, 0x7B36, 0xB945, 0x7B37, 0xB946, 0x7B38, 0xF3CD, 0x7B39, 0xB947, 0x7B3A, 0xBCE3, 0x7B3B, 0xB948, 0x7B3C, 0xC1FD, 0x7B3D, 0xB949, 0x7B3E, 0xF3D6, 0x7B3F, 0xB94A, 0x7B40, 0xB94B, 0x7B41, 0xB94C, 0x7B42, 0xB94D, 0x7B43, 0xB94E, 0x7B44, 0xB94F, 0x7B45, 0xF3DA, 0x7B46, 0xB950, 0x7B47, 0xF3CC, 0x7B48, 0xB951, 0x7B49, 0xB5C8, 0x7B4A, 0xB952, 0x7B4B, 0xBDEE, 0x7B4C, 0xF3DC, 0x7B4D, 0xB953, 0x7B4E, 0xB954, 0x7B4F, 0xB7A4, 0x7B50, 0xBFF0, 0x7B51, 0xD6FE, 0x7B52, 0xCDB2, 0x7B53, 0xB955, 0x7B54, 0xB4F0, 0x7B55, 0xB956, 0x7B56, 0xB2DF, 0x7B57, 0xB957, 0x7B58, 0xF3D8, 0x7B59, 0xB958, 0x7B5A, 0xF3D9, 0x7B5B, 0xC9B8, 0x7B5C, 0xB959, 0x7B5D, 0xF3DD, 0x7B5E, 0xB95A, 0x7B5F, 0xB95B, 0x7B60, 0xF3DE, 0x7B61, 0xB95C, 0x7B62, 0xF3E1, 0x7B63, 0xB95D, 0x7B64, 0xB95E, 0x7B65, 0xB95F, 0x7B66, 0xB960, 0x7B67, 0xB961, 0x7B68, 0xB962, 0x7B69, 0xB963, 0x7B6A, 0xB964, 0x7B6B, 0xB965, 0x7B6C, 0xB966, 0x7B6D, 0xB967, 0x7B6E, 0xF3DF, 0x7B6F, 0xB968, 0x7B70, 0xB969, 0x7B71, 0xF3E3, 0x7B72, 0xF3E2, 0x7B73, 0xB96A, 0x7B74, 0xB96B, 0x7B75, 0xF3DB, 0x7B76, 0xB96C, 0x7B77, 0xBFEA, 0x7B78, 0xB96D, 0x7B79, 0xB3EF, 0x7B7A, 0xB96E, 0x7B7B, 0xF3E0, 0x7B7C, 0xB96F, 0x7B7D, 0xB970, 0x7B7E, 0xC7A9, 0x7B7F, 0xB971, 0x7B80, 0xBCF2, 0x7B81, 0xB972, 0x7B82, 0xB973, 0x7B83, 0xB974, 0x7B84, 0xB975, 0x7B85, 0xF3EB, 0x7B86, 0xB976, 0x7B87, 0xB977, 0x7B88, 0xB978, 0x7B89, 0xB979, 0x7B8A, 0xB97A, 0x7B8B, 0xB97B, 0x7B8C, 0xB97C, 0x7B8D, 0xB9BF, 0x7B8E, 0xB97D, 0x7B8F, 0xB97E, 0x7B90, 0xF3E4, 0x7B91, 0xB980, 0x7B92, 0xB981, 0x7B93, 0xB982, 0x7B94, 0xB2AD, 0x7B95, 0xBBFE, 0x7B96, 0xB983, 0x7B97, 0xCBE3, 0x7B98, 0xB984, 0x7B99, 0xB985, 0x7B9A, 0xB986, 0x7B9B, 0xB987, 0x7B9C, 0xF3ED, 0x7B9D, 0xF3E9, 0x7B9E, 0xB988, 0x7B9F, 0xB989, 0x7BA0, 0xB98A, 0x7BA1, 0xB9DC, 0x7BA2, 0xF3EE, 0x7BA3, 0xB98B, 0x7BA4, 0xB98C, 0x7BA5, 0xB98D, 0x7BA6, 0xF3E5, 0x7BA7, 0xF3E6, 0x7BA8, 0xF3EA, 0x7BA9, 0xC2E1, 0x7BAA, 0xF3EC, 0x7BAB, 0xF3EF, 0x7BAC, 0xF3E8, 0x7BAD, 0xBCFD, 0x7BAE, 0xB98E, 0x7BAF, 0xB98F, 0x7BB0, 0xB990, 0x7BB1, 0xCFE4, 0x7BB2, 0xB991, 0x7BB3, 0xB992, 0x7BB4, 0xF3F0, 0x7BB5, 0xB993, 0x7BB6, 0xB994, 0x7BB7, 0xB995, 0x7BB8, 0xF3E7, 0x7BB9, 0xB996, 0x7BBA, 0xB997, 0x7BBB, 0xB998, 0x7BBC, 0xB999, 0x7BBD, 0xB99A, 0x7BBE, 0xB99B, 0x7BBF, 0xB99C, 0x7BC0, 0xB99D, 0x7BC1, 0xF3F2, 0x7BC2, 0xB99E, 0x7BC3, 0xB99F, 0x7BC4, 0xB9A0, 0x7BC5, 0xBA40, 0x7BC6, 0xD7AD, 0x7BC7, 0xC6AA, 0x7BC8, 0xBA41, 0x7BC9, 0xBA42, 0x7BCA, 0xBA43, 0x7BCB, 0xBA44, 0x7BCC, 0xF3F3, 0x7BCD, 0xBA45, 0x7BCE, 0xBA46, 0x7BCF, 0xBA47, 0x7BD0, 0xBA48, 0x7BD1, 0xF3F1, 0x7BD2, 0xBA49, 0x7BD3, 0xC2A8, 0x7BD4, 0xBA4A, 0x7BD5, 0xBA4B, 0x7BD6, 0xBA4C, 0x7BD7, 0xBA4D, 0x7BD8, 0xBA4E, 0x7BD9, 0xB8DD, 0x7BDA, 0xF3F5, 0x7BDB, 0xBA4F, 0x7BDC, 0xBA50, 0x7BDD, 0xF3F4, 0x7BDE, 0xBA51, 0x7BDF, 0xBA52, 0x7BE0, 0xBA53, 0x7BE1, 0xB4DB, 0x7BE2, 0xBA54, 0x7BE3, 0xBA55, 0x7BE4, 0xBA56, 0x7BE5, 0xF3F6, 0x7BE6, 0xF3F7, 0x7BE7, 0xBA57, 0x7BE8, 0xBA58, 0x7BE9, 0xBA59, 0x7BEA, 0xF3F8, 0x7BEB, 0xBA5A, 0x7BEC, 0xBA5B, 0x7BED, 0xBA5C, 0x7BEE, 0xC0BA, 0x7BEF, 0xBA5D, 0x7BF0, 0xBA5E, 0x7BF1, 0xC0E9, 0x7BF2, 0xBA5F, 0x7BF3, 0xBA60, 0x7BF4, 0xBA61, 0x7BF5, 0xBA62, 0x7BF6, 0xBA63, 0x7BF7, 0xC5F1, 0x7BF8, 0xBA64, 0x7BF9, 0xBA65, 0x7BFA, 0xBA66, 0x7BFB, 0xBA67, 0x7BFC, 0xF3FB, 0x7BFD, 0xBA68, 0x7BFE, 0xF3FA, 0x7BFF, 0xBA69, 0x7C00, 0xBA6A, 0x7C01, 0xBA6B, 0x7C02, 0xBA6C, 0x7C03, 0xBA6D, 0x7C04, 0xBA6E, 0x7C05, 0xBA6F, 0x7C06, 0xBA70, 0x7C07, 0xB4D8, 0x7C08, 0xBA71, 0x7C09, 0xBA72, 0x7C0A, 0xBA73, 0x7C0B, 0xF3FE, 0x7C0C, 0xF3F9, 0x7C0D, 0xBA74, 0x7C0E, 0xBA75, 0x7C0F, 0xF3FC, 0x7C10, 0xBA76, 0x7C11, 0xBA77, 0x7C12, 0xBA78, 0x7C13, 0xBA79, 0x7C14, 0xBA7A, 0x7C15, 0xBA7B, 0x7C16, 0xF3FD, 0x7C17, 0xBA7C, 0x7C18, 0xBA7D, 0x7C19, 0xBA7E, 0x7C1A, 0xBA80, 0x7C1B, 0xBA81, 0x7C1C, 0xBA82, 0x7C1D, 0xBA83, 0x7C1E, 0xBA84, 0x7C1F, 0xF4A1, 0x7C20, 0xBA85, 0x7C21, 0xBA86, 0x7C22, 0xBA87, 0x7C23, 0xBA88, 0x7C24, 0xBA89, 0x7C25, 0xBA8A, 0x7C26, 0xF4A3, 0x7C27, 0xBBC9, 0x7C28, 0xBA8B, 0x7C29, 0xBA8C, 0x7C2A, 0xF4A2, 0x7C2B, 0xBA8D, 0x7C2C, 0xBA8E, 0x7C2D, 0xBA8F, 0x7C2E, 0xBA90, 0x7C2F, 0xBA91, 0x7C30, 0xBA92, 0x7C31, 0xBA93, 0x7C32, 0xBA94, 0x7C33, 0xBA95, 0x7C34, 0xBA96, 0x7C35, 0xBA97, 0x7C36, 0xBA98, 0x7C37, 0xBA99, 0x7C38, 0xF4A4, 0x7C39, 0xBA9A, 0x7C3A, 0xBA9B, 0x7C3B, 0xBA9C, 0x7C3C, 0xBA9D, 0x7C3D, 0xBA9E, 0x7C3E, 0xBA9F, 0x7C3F, 0xB2BE, 0x7C40, 0xF4A6, 0x7C41, 0xF4A5, 0x7C42, 0xBAA0, 0x7C43, 0xBB40, 0x7C44, 0xBB41, 0x7C45, 0xBB42, 0x7C46, 0xBB43, 0x7C47, 0xBB44, 0x7C48, 0xBB45, 0x7C49, 0xBB46, 0x7C4A, 0xBB47, 0x7C4B, 0xBB48, 0x7C4C, 0xBB49, 0x7C4D, 0xBCAE, 0x7C4E, 0xBB4A, 0x7C4F, 0xBB4B, 0x7C50, 0xBB4C, 0x7C51, 0xBB4D, 0x7C52, 0xBB4E, 0x7C53, 0xBB4F, 0x7C54, 0xBB50, 0x7C55, 0xBB51, 0x7C56, 0xBB52, 0x7C57, 0xBB53, 0x7C58, 0xBB54, 0x7C59, 0xBB55, 0x7C5A, 0xBB56, 0x7C5B, 0xBB57, 0x7C5C, 0xBB58, 0x7C5D, 0xBB59, 0x7C5E, 0xBB5A, 0x7C5F, 0xBB5B, 0x7C60, 0xBB5C, 0x7C61, 0xBB5D, 0x7C62, 0xBB5E, 0x7C63, 0xBB5F, 0x7C64, 0xBB60, 0x7C65, 0xBB61, 0x7C66, 0xBB62, 0x7C67, 0xBB63, 0x7C68, 0xBB64, 0x7C69, 0xBB65, 0x7C6A, 0xBB66, 0x7C6B, 0xBB67, 0x7C6C, 0xBB68, 0x7C6D, 0xBB69, 0x7C6E, 0xBB6A, 0x7C6F, 0xBB6B, 0x7C70, 0xBB6C, 0x7C71, 0xBB6D, 0x7C72, 0xBB6E, 0x7C73, 0xC3D7, 0x7C74, 0xD9E1, 0x7C75, 0xBB6F, 0x7C76, 0xBB70, 0x7C77, 0xBB71, 0x7C78, 0xBB72, 0x7C79, 0xBB73, 0x7C7A, 0xBB74, 0x7C7B, 0xC0E0, 0x7C7C, 0xF4CC, 0x7C7D, 0xD7D1, 0x7C7E, 0xBB75, 0x7C7F, 0xBB76, 0x7C80, 0xBB77, 0x7C81, 0xBB78, 0x7C82, 0xBB79, 0x7C83, 0xBB7A, 0x7C84, 0xBB7B, 0x7C85, 0xBB7C, 0x7C86, 0xBB7D, 0x7C87, 0xBB7E, 0x7C88, 0xBB80, 0x7C89, 0xB7DB, 0x7C8A, 0xBB81, 0x7C8B, 0xBB82, 0x7C8C, 0xBB83, 0x7C8D, 0xBB84, 0x7C8E, 0xBB85, 0x7C8F, 0xBB86, 0x7C90, 0xBB87, 0x7C91, 0xF4CE, 0x7C92, 0xC1A3, 0x7C93, 0xBB88, 0x7C94, 0xBB89, 0x7C95, 0xC6C9, 0x7C96, 0xBB8A, 0x7C97, 0xB4D6, 0x7C98, 0xD5B3, 0x7C99, 0xBB8B, 0x7C9A, 0xBB8C, 0x7C9B, 0xBB8D, 0x7C9C, 0xF4D0, 0x7C9D, 0xF4CF, 0x7C9E, 0xF4D1, 0x7C9F, 0xCBDA, 0x7CA0, 0xBB8E, 0x7CA1, 0xBB8F, 0x7CA2, 0xF4D2, 0x7CA3, 0xBB90, 0x7CA4, 0xD4C1, 0x7CA5, 0xD6E0, 0x7CA6, 0xBB91, 0x7CA7, 0xBB92, 0x7CA8, 0xBB93, 0x7CA9, 0xBB94, 0x7CAA, 0xB7E0, 0x7CAB, 0xBB95, 0x7CAC, 0xBB96, 0x7CAD, 0xBB97, 0x7CAE, 0xC1B8, 0x7CAF, 0xBB98, 0x7CB0, 0xBB99, 0x7CB1, 0xC1BB, 0x7CB2, 0xF4D3, 0x7CB3, 0xBEAC, 0x7CB4, 0xBB9A, 0x7CB5, 0xBB9B, 0x7CB6, 0xBB9C, 0x7CB7, 0xBB9D, 0x7CB8, 0xBB9E, 0x7CB9, 0xB4E2, 0x7CBA, 0xBB9F, 0x7CBB, 0xBBA0, 0x7CBC, 0xF4D4, 0x7CBD, 0xF4D5, 0x7CBE, 0xBEAB, 0x7CBF, 0xBC40, 0x7CC0, 0xBC41, 0x7CC1, 0xF4D6, 0x7CC2, 0xBC42, 0x7CC3, 0xBC43, 0x7CC4, 0xBC44, 0x7CC5, 0xF4DB, 0x7CC6, 0xBC45, 0x7CC7, 0xF4D7, 0x7CC8, 0xF4DA, 0x7CC9, 0xBC46, 0x7CCA, 0xBAFD, 0x7CCB, 0xBC47, 0x7CCC, 0xF4D8, 0x7CCD, 0xF4D9, 0x7CCE, 0xBC48, 0x7CCF, 0xBC49, 0x7CD0, 0xBC4A, 0x7CD1, 0xBC4B, 0x7CD2, 0xBC4C, 0x7CD3, 0xBC4D, 0x7CD4, 0xBC4E, 0x7CD5, 0xB8E2, 0x7CD6, 0xCCC7, 0x7CD7, 0xF4DC, 0x7CD8, 0xBC4F, 0x7CD9, 0xB2DA, 0x7CDA, 0xBC50, 0x7CDB, 0xBC51, 0x7CDC, 0xC3D3, 0x7CDD, 0xBC52, 0x7CDE, 0xBC53, 0x7CDF, 0xD4E3, 0x7CE0, 0xBFB7, 0x7CE1, 0xBC54, 0x7CE2, 0xBC55, 0x7CE3, 0xBC56, 0x7CE4, 0xBC57, 0x7CE5, 0xBC58, 0x7CE6, 0xBC59, 0x7CE7, 0xBC5A, 0x7CE8, 0xF4DD, 0x7CE9, 0xBC5B, 0x7CEA, 0xBC5C, 0x7CEB, 0xBC5D, 0x7CEC, 0xBC5E, 0x7CED, 0xBC5F, 0x7CEE, 0xBC60, 0x7CEF, 0xC5B4, 0x7CF0, 0xBC61, 0x7CF1, 0xBC62, 0x7CF2, 0xBC63, 0x7CF3, 0xBC64, 0x7CF4, 0xBC65, 0x7CF5, 0xBC66, 0x7CF6, 0xBC67, 0x7CF7, 0xBC68, 0x7CF8, 0xF4E9, 0x7CF9, 0xBC69, 0x7CFA, 0xBC6A, 0x7CFB, 0xCFB5, 0x7CFC, 0xBC6B, 0x7CFD, 0xBC6C, 0x7CFE, 0xBC6D, 0x7CFF, 0xBC6E, 0x7D00, 0xBC6F, 0x7D01, 0xBC70, 0x7D02, 0xBC71, 0x7D03, 0xBC72, 0x7D04, 0xBC73, 0x7D05, 0xBC74, 0x7D06, 0xBC75, 0x7D07, 0xBC76, 0x7D08, 0xBC77, 0x7D09, 0xBC78, 0x7D0A, 0xCEC9, 0x7D0B, 0xBC79, 0x7D0C, 0xBC7A, 0x7D0D, 0xBC7B, 0x7D0E, 0xBC7C, 0x7D0F, 0xBC7D, 0x7D10, 0xBC7E, 0x7D11, 0xBC80, 0x7D12, 0xBC81, 0x7D13, 0xBC82, 0x7D14, 0xBC83, 0x7D15, 0xBC84, 0x7D16, 0xBC85, 0x7D17, 0xBC86, 0x7D18, 0xBC87, 0x7D19, 0xBC88, 0x7D1A, 0xBC89, 0x7D1B, 0xBC8A, 0x7D1C, 0xBC8B, 0x7D1D, 0xBC8C, 0x7D1E, 0xBC8D, 0x7D1F, 0xBC8E, 0x7D20, 0xCBD8, 0x7D21, 0xBC8F, 0x7D22, 0xCBF7, 0x7D23, 0xBC90, 0x7D24, 0xBC91, 0x7D25, 0xBC92, 0x7D26, 0xBC93, 0x7D27, 0xBDF4, 0x7D28, 0xBC94, 0x7D29, 0xBC95, 0x7D2A, 0xBC96, 0x7D2B, 0xD7CF, 0x7D2C, 0xBC97, 0x7D2D, 0xBC98, 0x7D2E, 0xBC99, 0x7D2F, 0xC0DB, 0x7D30, 0xBC9A, 0x7D31, 0xBC9B, 0x7D32, 0xBC9C, 0x7D33, 0xBC9D, 0x7D34, 0xBC9E, 0x7D35, 0xBC9F, 0x7D36, 0xBCA0, 0x7D37, 0xBD40, 0x7D38, 0xBD41, 0x7D39, 0xBD42, 0x7D3A, 0xBD43, 0x7D3B, 0xBD44, 0x7D3C, 0xBD45, 0x7D3D, 0xBD46, 0x7D3E, 0xBD47, 0x7D3F, 0xBD48, 0x7D40, 0xBD49, 0x7D41, 0xBD4A, 0x7D42, 0xBD4B, 0x7D43, 0xBD4C, 0x7D44, 0xBD4D, 0x7D45, 0xBD4E, 0x7D46, 0xBD4F, 0x7D47, 0xBD50, 0x7D48, 0xBD51, 0x7D49, 0xBD52, 0x7D4A, 0xBD53, 0x7D4B, 0xBD54, 0x7D4C, 0xBD55, 0x7D4D, 0xBD56, 0x7D4E, 0xBD57, 0x7D4F, 0xBD58, 0x7D50, 0xBD59, 0x7D51, 0xBD5A, 0x7D52, 0xBD5B, 0x7D53, 0xBD5C, 0x7D54, 0xBD5D, 0x7D55, 0xBD5E, 0x7D56, 0xBD5F, 0x7D57, 0xBD60, 0x7D58, 0xBD61, 0x7D59, 0xBD62, 0x7D5A, 0xBD63, 0x7D5B, 0xBD64, 0x7D5C, 0xBD65, 0x7D5D, 0xBD66, 0x7D5E, 0xBD67, 0x7D5F, 0xBD68, 0x7D60, 0xBD69, 0x7D61, 0xBD6A, 0x7D62, 0xBD6B, 0x7D63, 0xBD6C, 0x7D64, 0xBD6D, 0x7D65, 0xBD6E, 0x7D66, 0xBD6F, 0x7D67, 0xBD70, 0x7D68, 0xBD71, 0x7D69, 0xBD72, 0x7D6A, 0xBD73, 0x7D6B, 0xBD74, 0x7D6C, 0xBD75, 0x7D6D, 0xBD76, 0x7D6E, 0xD0F5, 0x7D6F, 0xBD77, 0x7D70, 0xBD78, 0x7D71, 0xBD79, 0x7D72, 0xBD7A, 0x7D73, 0xBD7B, 0x7D74, 0xBD7C, 0x7D75, 0xBD7D, 0x7D76, 0xBD7E, 0x7D77, 0xF4EA, 0x7D78, 0xBD80, 0x7D79, 0xBD81, 0x7D7A, 0xBD82, 0x7D7B, 0xBD83, 0x7D7C, 0xBD84, 0x7D7D, 0xBD85, 0x7D7E, 0xBD86, 0x7D7F, 0xBD87, 0x7D80, 0xBD88, 0x7D81, 0xBD89, 0x7D82, 0xBD8A, 0x7D83, 0xBD8B, 0x7D84, 0xBD8C, 0x7D85, 0xBD8D, 0x7D86, 0xBD8E, 0x7D87, 0xBD8F, 0x7D88, 0xBD90, 0x7D89, 0xBD91, 0x7D8A, 0xBD92, 0x7D8B, 0xBD93, 0x7D8C, 0xBD94, 0x7D8D, 0xBD95, 0x7D8E, 0xBD96, 0x7D8F, 0xBD97, 0x7D90, 0xBD98, 0x7D91, 0xBD99, 0x7D92, 0xBD9A, 0x7D93, 0xBD9B, 0x7D94, 0xBD9C, 0x7D95, 0xBD9D, 0x7D96, 0xBD9E, 0x7D97, 0xBD9F, 0x7D98, 0xBDA0, 0x7D99, 0xBE40, 0x7D9A, 0xBE41, 0x7D9B, 0xBE42, 0x7D9C, 0xBE43, 0x7D9D, 0xBE44, 0x7D9E, 0xBE45, 0x7D9F, 0xBE46, 0x7DA0, 0xBE47, 0x7DA1, 0xBE48, 0x7DA2, 0xBE49, 0x7DA3, 0xBE4A, 0x7DA4, 0xBE4B, 0x7DA5, 0xBE4C, 0x7DA6, 0xF4EB, 0x7DA7, 0xBE4D, 0x7DA8, 0xBE4E, 0x7DA9, 0xBE4F, 0x7DAA, 0xBE50, 0x7DAB, 0xBE51, 0x7DAC, 0xBE52, 0x7DAD, 0xBE53, 0x7DAE, 0xF4EC, 0x7DAF, 0xBE54, 0x7DB0, 0xBE55, 0x7DB1, 0xBE56, 0x7DB2, 0xBE57, 0x7DB3, 0xBE58, 0x7DB4, 0xBE59, 0x7DB5, 0xBE5A, 0x7DB6, 0xBE5B, 0x7DB7, 0xBE5C, 0x7DB8, 0xBE5D, 0x7DB9, 0xBE5E, 0x7DBA, 0xBE5F, 0x7DBB, 0xBE60, 0x7DBC, 0xBE61, 0x7DBD, 0xBE62, 0x7DBE, 0xBE63, 0x7DBF, 0xBE64, 0x7DC0, 0xBE65, 0x7DC1, 0xBE66, 0x7DC2, 0xBE67, 0x7DC3, 0xBE68, 0x7DC4, 0xBE69, 0x7DC5, 0xBE6A, 0x7DC6, 0xBE6B, 0x7DC7, 0xBE6C, 0x7DC8, 0xBE6D, 0x7DC9, 0xBE6E, 0x7DCA, 0xBE6F, 0x7DCB, 0xBE70, 0x7DCC, 0xBE71, 0x7DCD, 0xBE72, 0x7DCE, 0xBE73, 0x7DCF, 0xBE74, 0x7DD0, 0xBE75, 0x7DD1, 0xBE76, 0x7DD2, 0xBE77, 0x7DD3, 0xBE78, 0x7DD4, 0xBE79, 0x7DD5, 0xBE7A, 0x7DD6, 0xBE7B, 0x7DD7, 0xBE7C, 0x7DD8, 0xBE7D, 0x7DD9, 0xBE7E, 0x7DDA, 0xBE80, 0x7DDB, 0xBE81, 0x7DDC, 0xBE82, 0x7DDD, 0xBE83, 0x7DDE, 0xBE84, 0x7DDF, 0xBE85, 0x7DE0, 0xBE86, 0x7DE1, 0xBE87, 0x7DE2, 0xBE88, 0x7DE3, 0xBE89, 0x7DE4, 0xBE8A, 0x7DE5, 0xBE8B, 0x7DE6, 0xBE8C, 0x7DE7, 0xBE8D, 0x7DE8, 0xBE8E, 0x7DE9, 0xBE8F, 0x7DEA, 0xBE90, 0x7DEB, 0xBE91, 0x7DEC, 0xBE92, 0x7DED, 0xBE93, 0x7DEE, 0xBE94, 0x7DEF, 0xBE95, 0x7DF0, 0xBE96, 0x7DF1, 0xBE97, 0x7DF2, 0xBE98, 0x7DF3, 0xBE99, 0x7DF4, 0xBE9A, 0x7DF5, 0xBE9B, 0x7DF6, 0xBE9C, 0x7DF7, 0xBE9D, 0x7DF8, 0xBE9E, 0x7DF9, 0xBE9F, 0x7DFA, 0xBEA0, 0x7DFB, 0xBF40, 0x7DFC, 0xBF41, 0x7DFD, 0xBF42, 0x7DFE, 0xBF43, 0x7DFF, 0xBF44, 0x7E00, 0xBF45, 0x7E01, 0xBF46, 0x7E02, 0xBF47, 0x7E03, 0xBF48, 0x7E04, 0xBF49, 0x7E05, 0xBF4A, 0x7E06, 0xBF4B, 0x7E07, 0xBF4C, 0x7E08, 0xBF4D, 0x7E09, 0xBF4E, 0x7E0A, 0xBF4F, 0x7E0B, 0xBF50, 0x7E0C, 0xBF51, 0x7E0D, 0xBF52, 0x7E0E, 0xBF53, 0x7E0F, 0xBF54, 0x7E10, 0xBF55, 0x7E11, 0xBF56, 0x7E12, 0xBF57, 0x7E13, 0xBF58, 0x7E14, 0xBF59, 0x7E15, 0xBF5A, 0x7E16, 0xBF5B, 0x7E17, 0xBF5C, 0x7E18, 0xBF5D, 0x7E19, 0xBF5E, 0x7E1A, 0xBF5F, 0x7E1B, 0xBF60, 0x7E1C, 0xBF61, 0x7E1D, 0xBF62, 0x7E1E, 0xBF63, 0x7E1F, 0xBF64, 0x7E20, 0xBF65, 0x7E21, 0xBF66, 0x7E22, 0xBF67, 0x7E23, 0xBF68, 0x7E24, 0xBF69, 0x7E25, 0xBF6A, 0x7E26, 0xBF6B, 0x7E27, 0xBF6C, 0x7E28, 0xBF6D, 0x7E29, 0xBF6E, 0x7E2A, 0xBF6F, 0x7E2B, 0xBF70, 0x7E2C, 0xBF71, 0x7E2D, 0xBF72, 0x7E2E, 0xBF73, 0x7E2F, 0xBF74, 0x7E30, 0xBF75, 0x7E31, 0xBF76, 0x7E32, 0xBF77, 0x7E33, 0xBF78, 0x7E34, 0xBF79, 0x7E35, 0xBF7A, 0x7E36, 0xBF7B, 0x7E37, 0xBF7C, 0x7E38, 0xBF7D, 0x7E39, 0xBF7E, 0x7E3A, 0xBF80, 0x7E3B, 0xF7E3, 0x7E3C, 0xBF81, 0x7E3D, 0xBF82, 0x7E3E, 0xBF83, 0x7E3F, 0xBF84, 0x7E40, 0xBF85, 0x7E41, 0xB7B1, 0x7E42, 0xBF86, 0x7E43, 0xBF87, 0x7E44, 0xBF88, 0x7E45, 0xBF89, 0x7E46, 0xBF8A, 0x7E47, 0xF4ED, 0x7E48, 0xBF8B, 0x7E49, 0xBF8C, 0x7E4A, 0xBF8D, 0x7E4B, 0xBF8E, 0x7E4C, 0xBF8F, 0x7E4D, 0xBF90, 0x7E4E, 0xBF91, 0x7E4F, 0xBF92, 0x7E50, 0xBF93, 0x7E51, 0xBF94, 0x7E52, 0xBF95, 0x7E53, 0xBF96, 0x7E54, 0xBF97, 0x7E55, 0xBF98, 0x7E56, 0xBF99, 0x7E57, 0xBF9A, 0x7E58, 0xBF9B, 0x7E59, 0xBF9C, 0x7E5A, 0xBF9D, 0x7E5B, 0xBF9E, 0x7E5C, 0xBF9F, 0x7E5D, 0xBFA0, 0x7E5E, 0xC040, 0x7E5F, 0xC041, 0x7E60, 0xC042, 0x7E61, 0xC043, 0x7E62, 0xC044, 0x7E63, 0xC045, 0x7E64, 0xC046, 0x7E65, 0xC047, 0x7E66, 0xC048, 0x7E67, 0xC049, 0x7E68, 0xC04A, 0x7E69, 0xC04B, 0x7E6A, 0xC04C, 0x7E6B, 0xC04D, 0x7E6C, 0xC04E, 0x7E6D, 0xC04F, 0x7E6E, 0xC050, 0x7E6F, 0xC051, 0x7E70, 0xC052, 0x7E71, 0xC053, 0x7E72, 0xC054, 0x7E73, 0xC055, 0x7E74, 0xC056, 0x7E75, 0xC057, 0x7E76, 0xC058, 0x7E77, 0xC059, 0x7E78, 0xC05A, 0x7E79, 0xC05B, 0x7E7A, 0xC05C, 0x7E7B, 0xC05D, 0x7E7C, 0xC05E, 0x7E7D, 0xC05F, 0x7E7E, 0xC060, 0x7E7F, 0xC061, 0x7E80, 0xC062, 0x7E81, 0xC063, 0x7E82, 0xD7EB, 0x7E83, 0xC064, 0x7E84, 0xC065, 0x7E85, 0xC066, 0x7E86, 0xC067, 0x7E87, 0xC068, 0x7E88, 0xC069, 0x7E89, 0xC06A, 0x7E8A, 0xC06B, 0x7E8B, 0xC06C, 0x7E8C, 0xC06D, 0x7E8D, 0xC06E, 0x7E8E, 0xC06F, 0x7E8F, 0xC070, 0x7E90, 0xC071, 0x7E91, 0xC072, 0x7E92, 0xC073, 0x7E93, 0xC074, 0x7E94, 0xC075, 0x7E95, 0xC076, 0x7E96, 0xC077, 0x7E97, 0xC078, 0x7E98, 0xC079, 0x7E99, 0xC07A, 0x7E9A, 0xC07B, 0x7E9B, 0xF4EE, 0x7E9C, 0xC07C, 0x7E9D, 0xC07D, 0x7E9E, 0xC07E, 0x7E9F, 0xE6F9, 0x7EA0, 0xBEC0, 0x7EA1, 0xE6FA, 0x7EA2, 0xBAEC, 0x7EA3, 0xE6FB, 0x7EA4, 0xCFCB, 0x7EA5, 0xE6FC, 0x7EA6, 0xD4BC, 0x7EA7, 0xBCB6, 0x7EA8, 0xE6FD, 0x7EA9, 0xE6FE, 0x7EAA, 0xBCCD, 0x7EAB, 0xC8D2, 0x7EAC, 0xCEB3, 0x7EAD, 0xE7A1, 0x7EAE, 0xC080, 0x7EAF, 0xB4BF, 0x7EB0, 0xE7A2, 0x7EB1, 0xC9B4, 0x7EB2, 0xB8D9, 0x7EB3, 0xC4C9, 0x7EB4, 0xC081, 0x7EB5, 0xD7DD, 0x7EB6, 0xC2DA, 0x7EB7, 0xB7D7, 0x7EB8, 0xD6BD, 0x7EB9, 0xCEC6, 0x7EBA, 0xB7C4, 0x7EBB, 0xC082, 0x7EBC, 0xC083, 0x7EBD, 0xC5A6, 0x7EBE, 0xE7A3, 0x7EBF, 0xCFDF, 0x7EC0, 0xE7A4, 0x7EC1, 0xE7A5, 0x7EC2, 0xE7A6, 0x7EC3, 0xC1B7, 0x7EC4, 0xD7E9, 0x7EC5, 0xC9F0, 0x7EC6, 0xCFB8, 0x7EC7, 0xD6AF, 0x7EC8, 0xD6D5, 0x7EC9, 0xE7A7, 0x7ECA, 0xB0ED, 0x7ECB, 0xE7A8, 0x7ECC, 0xE7A9, 0x7ECD, 0xC9DC, 0x7ECE, 0xD2EF, 0x7ECF, 0xBEAD, 0x7ED0, 0xE7AA, 0x7ED1, 0xB0F3, 0x7ED2, 0xC8DE, 0x7ED3, 0xBDE1, 0x7ED4, 0xE7AB, 0x7ED5, 0xC8C6, 0x7ED6, 0xC084, 0x7ED7, 0xE7AC, 0x7ED8, 0xBBE6, 0x7ED9, 0xB8F8, 0x7EDA, 0xD1A4, 0x7EDB, 0xE7AD, 0x7EDC, 0xC2E7, 0x7EDD, 0xBEF8, 0x7EDE, 0xBDCA, 0x7EDF, 0xCDB3, 0x7EE0, 0xE7AE, 0x7EE1, 0xE7AF, 0x7EE2, 0xBEEE, 0x7EE3, 0xD0E5, 0x7EE4, 0xC085, 0x7EE5, 0xCBE7, 0x7EE6, 0xCCD0, 0x7EE7, 0xBCCC, 0x7EE8, 0xE7B0, 0x7EE9, 0xBCA8, 0x7EEA, 0xD0F7, 0x7EEB, 0xE7B1, 0x7EEC, 0xC086, 0x7EED, 0xD0F8, 0x7EEE, 0xE7B2, 0x7EEF, 0xE7B3, 0x7EF0, 0xB4C2, 0x7EF1, 0xE7B4, 0x7EF2, 0xE7B5, 0x7EF3, 0xC9FE, 0x7EF4, 0xCEAC, 0x7EF5, 0xC3E0, 0x7EF6, 0xE7B7, 0x7EF7, 0xB1C1, 0x7EF8, 0xB3F1, 0x7EF9, 0xC087, 0x7EFA, 0xE7B8, 0x7EFB, 0xE7B9, 0x7EFC, 0xD7DB, 0x7EFD, 0xD5C0, 0x7EFE, 0xE7BA, 0x7EFF, 0xC2CC, 0x7F00, 0xD7BA, 0x7F01, 0xE7BB, 0x7F02, 0xE7BC, 0x7F03, 0xE7BD, 0x7F04, 0xBCEA, 0x7F05, 0xC3E5, 0x7F06, 0xC0C2, 0x7F07, 0xE7BE, 0x7F08, 0xE7BF, 0x7F09, 0xBCA9, 0x7F0A, 0xC088, 0x7F0B, 0xE7C0, 0x7F0C, 0xE7C1, 0x7F0D, 0xE7B6, 0x7F0E, 0xB6D0, 0x7F0F, 0xE7C2, 0x7F10, 0xC089, 0x7F11, 0xE7C3, 0x7F12, 0xE7C4, 0x7F13, 0xBBBA, 0x7F14, 0xB5DE, 0x7F15, 0xC2C6, 0x7F16, 0xB1E0, 0x7F17, 0xE7C5, 0x7F18, 0xD4B5, 0x7F19, 0xE7C6, 0x7F1A, 0xB8BF, 0x7F1B, 0xE7C8, 0x7F1C, 0xE7C7, 0x7F1D, 0xB7EC, 0x7F1E, 0xC08A, 0x7F1F, 0xE7C9, 0x7F20, 0xB2F8, 0x7F21, 0xE7CA, 0x7F22, 0xE7CB, 0x7F23, 0xE7CC, 0x7F24, 0xE7CD, 0x7F25, 0xE7CE, 0x7F26, 0xE7CF, 0x7F27, 0xE7D0, 0x7F28, 0xD3A7, 0x7F29, 0xCBF5, 0x7F2A, 0xE7D1, 0x7F2B, 0xE7D2, 0x7F2C, 0xE7D3, 0x7F2D, 0xE7D4, 0x7F2E, 0xC9C9, 0x7F2F, 0xE7D5, 0x7F30, 0xE7D6, 0x7F31, 0xE7D7, 0x7F32, 0xE7D8, 0x7F33, 0xE7D9, 0x7F34, 0xBDC9, 0x7F35, 0xE7DA, 0x7F36, 0xF3BE, 0x7F37, 0xC08B, 0x7F38, 0xB8D7, 0x7F39, 0xC08C, 0x7F3A, 0xC8B1, 0x7F3B, 0xC08D, 0x7F3C, 0xC08E, 0x7F3D, 0xC08F, 0x7F3E, 0xC090, 0x7F3F, 0xC091, 0x7F40, 0xC092, 0x7F41, 0xC093, 0x7F42, 0xF3BF, 0x7F43, 0xC094, 0x7F44, 0xF3C0, 0x7F45, 0xF3C1, 0x7F46, 0xC095, 0x7F47, 0xC096, 0x7F48, 0xC097, 0x7F49, 0xC098, 0x7F4A, 0xC099, 0x7F4B, 0xC09A, 0x7F4C, 0xC09B, 0x7F4D, 0xC09C, 0x7F4E, 0xC09D, 0x7F4F, 0xC09E, 0x7F50, 0xB9DE, 0x7F51, 0xCDF8, 0x7F52, 0xC09F, 0x7F53, 0xC0A0, 0x7F54, 0xD8E8, 0x7F55, 0xBAB1, 0x7F56, 0xC140, 0x7F57, 0xC2DE, 0x7F58, 0xEEB7, 0x7F59, 0xC141, 0x7F5A, 0xB7A3, 0x7F5B, 0xC142, 0x7F5C, 0xC143, 0x7F5D, 0xC144, 0x7F5E, 0xC145, 0x7F5F, 0xEEB9, 0x7F60, 0xC146, 0x7F61, 0xEEB8, 0x7F62, 0xB0D5, 0x7F63, 0xC147, 0x7F64, 0xC148, 0x7F65, 0xC149, 0x7F66, 0xC14A, 0x7F67, 0xC14B, 0x7F68, 0xEEBB, 0x7F69, 0xD5D6, 0x7F6A, 0xD7EF, 0x7F6B, 0xC14C, 0x7F6C, 0xC14D, 0x7F6D, 0xC14E, 0x7F6E, 0xD6C3, 0x7F6F, 0xC14F, 0x7F70, 0xC150, 0x7F71, 0xEEBD, 0x7F72, 0xCAF0, 0x7F73, 0xC151, 0x7F74, 0xEEBC, 0x7F75, 0xC152, 0x7F76, 0xC153, 0x7F77, 0xC154, 0x7F78, 0xC155, 0x7F79, 0xEEBE, 0x7F7A, 0xC156, 0x7F7B, 0xC157, 0x7F7C, 0xC158, 0x7F7D, 0xC159, 0x7F7E, 0xEEC0, 0x7F7F, 0xC15A, 0x7F80, 0xC15B, 0x7F81, 0xEEBF, 0x7F82, 0xC15C, 0x7F83, 0xC15D, 0x7F84, 0xC15E, 0x7F85, 0xC15F, 0x7F86, 0xC160, 0x7F87, 0xC161, 0x7F88, 0xC162, 0x7F89, 0xC163, 0x7F8A, 0xD1F2, 0x7F8B, 0xC164, 0x7F8C, 0xC7BC, 0x7F8D, 0xC165, 0x7F8E, 0xC3C0, 0x7F8F, 0xC166, 0x7F90, 0xC167, 0x7F91, 0xC168, 0x7F92, 0xC169, 0x7F93, 0xC16A, 0x7F94, 0xB8E1, 0x7F95, 0xC16B, 0x7F96, 0xC16C, 0x7F97, 0xC16D, 0x7F98, 0xC16E, 0x7F99, 0xC16F, 0x7F9A, 0xC1E7, 0x7F9B, 0xC170, 0x7F9C, 0xC171, 0x7F9D, 0xF4C6, 0x7F9E, 0xD0DF, 0x7F9F, 0xF4C7, 0x7FA0, 0xC172, 0x7FA1, 0xCFDB, 0x7FA2, 0xC173, 0x7FA3, 0xC174, 0x7FA4, 0xC8BA, 0x7FA5, 0xC175, 0x7FA6, 0xC176, 0x7FA7, 0xF4C8, 0x7FA8, 0xC177, 0x7FA9, 0xC178, 0x7FAA, 0xC179, 0x7FAB, 0xC17A, 0x7FAC, 0xC17B, 0x7FAD, 0xC17C, 0x7FAE, 0xC17D, 0x7FAF, 0xF4C9, 0x7FB0, 0xF4CA, 0x7FB1, 0xC17E, 0x7FB2, 0xF4CB, 0x7FB3, 0xC180, 0x7FB4, 0xC181, 0x7FB5, 0xC182, 0x7FB6, 0xC183, 0x7FB7, 0xC184, 0x7FB8, 0xD9FA, 0x7FB9, 0xB8FE, 0x7FBA, 0xC185, 0x7FBB, 0xC186, 0x7FBC, 0xE5F1, 0x7FBD, 0xD3F0, 0x7FBE, 0xC187, 0x7FBF, 0xF4E0, 0x7FC0, 0xC188, 0x7FC1, 0xCECC, 0x7FC2, 0xC189, 0x7FC3, 0xC18A, 0x7FC4, 0xC18B, 0x7FC5, 0xB3E1, 0x7FC6, 0xC18C, 0x7FC7, 0xC18D, 0x7FC8, 0xC18E, 0x7FC9, 0xC18F, 0x7FCA, 0xF1B4, 0x7FCB, 0xC190, 0x7FCC, 0xD2EE, 0x7FCD, 0xC191, 0x7FCE, 0xF4E1, 0x7FCF, 0xC192, 0x7FD0, 0xC193, 0x7FD1, 0xC194, 0x7FD2, 0xC195, 0x7FD3, 0xC196, 0x7FD4, 0xCFE8, 0x7FD5, 0xF4E2, 0x7FD6, 0xC197, 0x7FD7, 0xC198, 0x7FD8, 0xC7CC, 0x7FD9, 0xC199, 0x7FDA, 0xC19A, 0x7FDB, 0xC19B, 0x7FDC, 0xC19C, 0x7FDD, 0xC19D, 0x7FDE, 0xC19E, 0x7FDF, 0xB5D4, 0x7FE0, 0xB4E4, 0x7FE1, 0xF4E4, 0x7FE2, 0xC19F, 0x7FE3, 0xC1A0, 0x7FE4, 0xC240, 0x7FE5, 0xF4E3, 0x7FE6, 0xF4E5, 0x7FE7, 0xC241, 0x7FE8, 0xC242, 0x7FE9, 0xF4E6, 0x7FEA, 0xC243, 0x7FEB, 0xC244, 0x7FEC, 0xC245, 0x7FED, 0xC246, 0x7FEE, 0xF4E7, 0x7FEF, 0xC247, 0x7FF0, 0xBAB2, 0x7FF1, 0xB0BF, 0x7FF2, 0xC248, 0x7FF3, 0xF4E8, 0x7FF4, 0xC249, 0x7FF5, 0xC24A, 0x7FF6, 0xC24B, 0x7FF7, 0xC24C, 0x7FF8, 0xC24D, 0x7FF9, 0xC24E, 0x7FFA, 0xC24F, 0x7FFB, 0xB7AD, 0x7FFC, 0xD2ED, 0x7FFD, 0xC250, 0x7FFE, 0xC251, 0x7FFF, 0xC252, 0x8000, 0xD2AB, 0x8001, 0xC0CF, 0x8002, 0xC253, 0x8003, 0xBFBC, 0x8004, 0xEBA3, 0x8005, 0xD5DF, 0x8006, 0xEAC8, 0x8007, 0xC254, 0x8008, 0xC255, 0x8009, 0xC256, 0x800A, 0xC257, 0x800B, 0xF1F3, 0x800C, 0xB6F8, 0x800D, 0xCBA3, 0x800E, 0xC258, 0x800F, 0xC259, 0x8010, 0xC4CD, 0x8011, 0xC25A, 0x8012, 0xF1E7, 0x8013, 0xC25B, 0x8014, 0xF1E8, 0x8015, 0xB8FB, 0x8016, 0xF1E9, 0x8017, 0xBAC4, 0x8018, 0xD4C5, 0x8019, 0xB0D2, 0x801A, 0xC25C, 0x801B, 0xC25D, 0x801C, 0xF1EA, 0x801D, 0xC25E, 0x801E, 0xC25F, 0x801F, 0xC260, 0x8020, 0xF1EB, 0x8021, 0xC261, 0x8022, 0xF1EC, 0x8023, 0xC262, 0x8024, 0xC263, 0x8025, 0xF1ED, 0x8026, 0xF1EE, 0x8027, 0xF1EF, 0x8028, 0xF1F1, 0x8029, 0xF1F0, 0x802A, 0xC5D5, 0x802B, 0xC264, 0x802C, 0xC265, 0x802D, 0xC266, 0x802E, 0xC267, 0x802F, 0xC268, 0x8030, 0xC269, 0x8031, 0xF1F2, 0x8032, 0xC26A, 0x8033, 0xB6FA, 0x8034, 0xC26B, 0x8035, 0xF1F4, 0x8036, 0xD2AE, 0x8037, 0xDEC7, 0x8038, 0xCBCA, 0x8039, 0xC26C, 0x803A, 0xC26D, 0x803B, 0xB3DC, 0x803C, 0xC26E, 0x803D, 0xB5A2, 0x803E, 0xC26F, 0x803F, 0xB9A2, 0x8040, 0xC270, 0x8041, 0xC271, 0x8042, 0xC4F4, 0x8043, 0xF1F5, 0x8044, 0xC272, 0x8045, 0xC273, 0x8046, 0xF1F6, 0x8047, 0xC274, 0x8048, 0xC275, 0x8049, 0xC276, 0x804A, 0xC1C4, 0x804B, 0xC1FB, 0x804C, 0xD6B0, 0x804D, 0xF1F7, 0x804E, 0xC277, 0x804F, 0xC278, 0x8050, 0xC279, 0x8051, 0xC27A, 0x8052, 0xF1F8, 0x8053, 0xC27B, 0x8054, 0xC1AA, 0x8055, 0xC27C, 0x8056, 0xC27D, 0x8057, 0xC27E, 0x8058, 0xC6B8, 0x8059, 0xC280, 0x805A, 0xBEDB, 0x805B, 0xC281, 0x805C, 0xC282, 0x805D, 0xC283, 0x805E, 0xC284, 0x805F, 0xC285, 0x8060, 0xC286, 0x8061, 0xC287, 0x8062, 0xC288, 0x8063, 0xC289, 0x8064, 0xC28A, 0x8065, 0xC28B, 0x8066, 0xC28C, 0x8067, 0xC28D, 0x8068, 0xC28E, 0x8069, 0xF1F9, 0x806A, 0xB4CF, 0x806B, 0xC28F, 0x806C, 0xC290, 0x806D, 0xC291, 0x806E, 0xC292, 0x806F, 0xC293, 0x8070, 0xC294, 0x8071, 0xF1FA, 0x8072, 0xC295, 0x8073, 0xC296, 0x8074, 0xC297, 0x8075, 0xC298, 0x8076, 0xC299, 0x8077, 0xC29A, 0x8078, 0xC29B, 0x8079, 0xC29C, 0x807A, 0xC29D, 0x807B, 0xC29E, 0x807C, 0xC29F, 0x807D, 0xC2A0, 0x807E, 0xC340, 0x807F, 0xEDB2, 0x8080, 0xEDB1, 0x8081, 0xC341, 0x8082, 0xC342, 0x8083, 0xCBE0, 0x8084, 0xD2DE, 0x8085, 0xC343, 0x8086, 0xCBC1, 0x8087, 0xD5D8, 0x8088, 0xC344, 0x8089, 0xC8E2, 0x808A, 0xC345, 0x808B, 0xC0DF, 0x808C, 0xBCA1, 0x808D, 0xC346, 0x808E, 0xC347, 0x808F, 0xC348, 0x8090, 0xC349, 0x8091, 0xC34A, 0x8092, 0xC34B, 0x8093, 0xEBC1, 0x8094, 0xC34C, 0x8095, 0xC34D, 0x8096, 0xD0A4, 0x8097, 0xC34E, 0x8098, 0xD6E2, 0x8099, 0xC34F, 0x809A, 0xB6C7, 0x809B, 0xB8D8, 0x809C, 0xEBC0, 0x809D, 0xB8CE, 0x809E, 0xC350, 0x809F, 0xEBBF, 0x80A0, 0xB3A6, 0x80A1, 0xB9C9, 0x80A2, 0xD6AB, 0x80A3, 0xC351, 0x80A4, 0xB7F4, 0x80A5, 0xB7CA, 0x80A6, 0xC352, 0x80A7, 0xC353, 0x80A8, 0xC354, 0x80A9, 0xBCE7, 0x80AA, 0xB7BE, 0x80AB, 0xEBC6, 0x80AC, 0xC355, 0x80AD, 0xEBC7, 0x80AE, 0xB0B9, 0x80AF, 0xBFCF, 0x80B0, 0xC356, 0x80B1, 0xEBC5, 0x80B2, 0xD3FD, 0x80B3, 0xC357, 0x80B4, 0xEBC8, 0x80B5, 0xC358, 0x80B6, 0xC359, 0x80B7, 0xEBC9, 0x80B8, 0xC35A, 0x80B9, 0xC35B, 0x80BA, 0xB7CE, 0x80BB, 0xC35C, 0x80BC, 0xEBC2, 0x80BD, 0xEBC4, 0x80BE, 0xC9F6, 0x80BF, 0xD6D7, 0x80C0, 0xD5CD, 0x80C1, 0xD0B2, 0x80C2, 0xEBCF, 0x80C3, 0xCEB8, 0x80C4, 0xEBD0, 0x80C5, 0xC35D, 0x80C6, 0xB5A8, 0x80C7, 0xC35E, 0x80C8, 0xC35F, 0x80C9, 0xC360, 0x80CA, 0xC361, 0x80CB, 0xC362, 0x80CC, 0xB1B3, 0x80CD, 0xEBD2, 0x80CE, 0xCCA5, 0x80CF, 0xC363, 0x80D0, 0xC364, 0x80D1, 0xC365, 0x80D2, 0xC366, 0x80D3, 0xC367, 0x80D4, 0xC368, 0x80D5, 0xC369, 0x80D6, 0xC5D6, 0x80D7, 0xEBD3, 0x80D8, 0xC36A, 0x80D9, 0xEBD1, 0x80DA, 0xC5DF, 0x80DB, 0xEBCE, 0x80DC, 0xCAA4, 0x80DD, 0xEBD5, 0x80DE, 0xB0FB, 0x80DF, 0xC36B, 0x80E0, 0xC36C, 0x80E1, 0xBAFA, 0x80E2, 0xC36D, 0x80E3, 0xC36E, 0x80E4, 0xD8B7, 0x80E5, 0xF1E3, 0x80E6, 0xC36F, 0x80E7, 0xEBCA, 0x80E8, 0xEBCB, 0x80E9, 0xEBCC, 0x80EA, 0xEBCD, 0x80EB, 0xEBD6, 0x80EC, 0xE6C0, 0x80ED, 0xEBD9, 0x80EE, 0xC370, 0x80EF, 0xBFE8, 0x80F0, 0xD2C8, 0x80F1, 0xEBD7, 0x80F2, 0xEBDC, 0x80F3, 0xB8EC, 0x80F4, 0xEBD8, 0x80F5, 0xC371, 0x80F6, 0xBDBA, 0x80F7, 0xC372, 0x80F8, 0xD0D8, 0x80F9, 0xC373, 0x80FA, 0xB0B7, 0x80FB, 0xC374, 0x80FC, 0xEBDD, 0x80FD, 0xC4DC, 0x80FE, 0xC375, 0x80FF, 0xC376, 0x8100, 0xC377, 0x8101, 0xC378, 0x8102, 0xD6AC, 0x8103, 0xC379, 0x8104, 0xC37A, 0x8105, 0xC37B, 0x8106, 0xB4E0, 0x8107, 0xC37C, 0x8108, 0xC37D, 0x8109, 0xC2F6, 0x810A, 0xBCB9, 0x810B, 0xC37E, 0x810C, 0xC380, 0x810D, 0xEBDA, 0x810E, 0xEBDB, 0x810F, 0xD4E0, 0x8110, 0xC6EA, 0x8111, 0xC4D4, 0x8112, 0xEBDF, 0x8113, 0xC5A7, 0x8114, 0xD9F5, 0x8115, 0xC381, 0x8116, 0xB2B1, 0x8117, 0xC382, 0x8118, 0xEBE4, 0x8119, 0xC383, 0x811A, 0xBDC5, 0x811B, 0xC384, 0x811C, 0xC385, 0x811D, 0xC386, 0x811E, 0xEBE2, 0x811F, 0xC387, 0x8120, 0xC388, 0x8121, 0xC389, 0x8122, 0xC38A, 0x8123, 0xC38B, 0x8124, 0xC38C, 0x8125, 0xC38D, 0x8126, 0xC38E, 0x8127, 0xC38F, 0x8128, 0xC390, 0x8129, 0xC391, 0x812A, 0xC392, 0x812B, 0xC393, 0x812C, 0xEBE3, 0x812D, 0xC394, 0x812E, 0xC395, 0x812F, 0xB8AC, 0x8130, 0xC396, 0x8131, 0xCDD1, 0x8132, 0xEBE5, 0x8133, 0xC397, 0x8134, 0xC398, 0x8135, 0xC399, 0x8136, 0xEBE1, 0x8137, 0xC39A, 0x8138, 0xC1B3, 0x8139, 0xC39B, 0x813A, 0xC39C, 0x813B, 0xC39D, 0x813C, 0xC39E, 0x813D, 0xC39F, 0x813E, 0xC6A2, 0x813F, 0xC3A0, 0x8140, 0xC440, 0x8141, 0xC441, 0x8142, 0xC442, 0x8143, 0xC443, 0x8144, 0xC444, 0x8145, 0xC445, 0x8146, 0xCCF3, 0x8147, 0xC446, 0x8148, 0xEBE6, 0x8149, 0xC447, 0x814A, 0xC0B0, 0x814B, 0xD2B8, 0x814C, 0xEBE7, 0x814D, 0xC448, 0x814E, 0xC449, 0x814F, 0xC44A, 0x8150, 0xB8AF, 0x8151, 0xB8AD, 0x8152, 0xC44B, 0x8153, 0xEBE8, 0x8154, 0xC7BB, 0x8155, 0xCDF3, 0x8156, 0xC44C, 0x8157, 0xC44D, 0x8158, 0xC44E, 0x8159, 0xEBEA, 0x815A, 0xEBEB, 0x815B, 0xC44F, 0x815C, 0xC450, 0x815D, 0xC451, 0x815E, 0xC452, 0x815F, 0xC453, 0x8160, 0xEBED, 0x8161, 0xC454, 0x8162, 0xC455, 0x8163, 0xC456, 0x8164, 0xC457, 0x8165, 0xD0C8, 0x8166, 0xC458, 0x8167, 0xEBF2, 0x8168, 0xC459, 0x8169, 0xEBEE, 0x816A, 0xC45A, 0x816B, 0xC45B, 0x816C, 0xC45C, 0x816D, 0xEBF1, 0x816E, 0xC8F9, 0x816F, 0xC45D, 0x8170, 0xD1FC, 0x8171, 0xEBEC, 0x8172, 0xC45E, 0x8173, 0xC45F, 0x8174, 0xEBE9, 0x8175, 0xC460, 0x8176, 0xC461, 0x8177, 0xC462, 0x8178, 0xC463, 0x8179, 0xB8B9, 0x817A, 0xCFD9, 0x817B, 0xC4E5, 0x817C, 0xEBEF, 0x817D, 0xEBF0, 0x817E, 0xCCDA, 0x817F, 0xCDC8, 0x8180, 0xB0F2, 0x8181, 0xC464, 0x8182, 0xEBF6, 0x8183, 0xC465, 0x8184, 0xC466, 0x8185, 0xC467, 0x8186, 0xC468, 0x8187, 0xC469, 0x8188, 0xEBF5, 0x8189, 0xC46A, 0x818A, 0xB2B2, 0x818B, 0xC46B, 0x818C, 0xC46C, 0x818D, 0xC46D, 0x818E, 0xC46E, 0x818F, 0xB8E0, 0x8190, 0xC46F, 0x8191, 0xEBF7, 0x8192, 0xC470, 0x8193, 0xC471, 0x8194, 0xC472, 0x8195, 0xC473, 0x8196, 0xC474, 0x8197, 0xC475, 0x8198, 0xB1EC, 0x8199, 0xC476, 0x819A, 0xC477, 0x819B, 0xCCC5, 0x819C, 0xC4A4, 0x819D, 0xCFA5, 0x819E, 0xC478, 0x819F, 0xC479, 0x81A0, 0xC47A, 0x81A1, 0xC47B, 0x81A2, 0xC47C, 0x81A3, 0xEBF9, 0x81A4, 0xC47D, 0x81A5, 0xC47E, 0x81A6, 0xECA2, 0x81A7, 0xC480, 0x81A8, 0xC5F2, 0x81A9, 0xC481, 0x81AA, 0xEBFA, 0x81AB, 0xC482, 0x81AC, 0xC483, 0x81AD, 0xC484, 0x81AE, 0xC485, 0x81AF, 0xC486, 0x81B0, 0xC487, 0x81B1, 0xC488, 0x81B2, 0xC489, 0x81B3, 0xC9C5, 0x81B4, 0xC48A, 0x81B5, 0xC48B, 0x81B6, 0xC48C, 0x81B7, 0xC48D, 0x81B8, 0xC48E, 0x81B9, 0xC48F, 0x81BA, 0xE2DF, 0x81BB, 0xEBFE, 0x81BC, 0xC490, 0x81BD, 0xC491, 0x81BE, 0xC492, 0x81BF, 0xC493, 0x81C0, 0xCDCE, 0x81C1, 0xECA1, 0x81C2, 0xB1DB, 0x81C3, 0xD3B7, 0x81C4, 0xC494, 0x81C5, 0xC495, 0x81C6, 0xD2DC, 0x81C7, 0xC496, 0x81C8, 0xC497, 0x81C9, 0xC498, 0x81CA, 0xEBFD, 0x81CB, 0xC499, 0x81CC, 0xEBFB, 0x81CD, 0xC49A, 0x81CE, 0xC49B, 0x81CF, 0xC49C, 0x81D0, 0xC49D, 0x81D1, 0xC49E, 0x81D2, 0xC49F, 0x81D3, 0xC4A0, 0x81D4, 0xC540, 0x81D5, 0xC541, 0x81D6, 0xC542, 0x81D7, 0xC543, 0x81D8, 0xC544, 0x81D9, 0xC545, 0x81DA, 0xC546, 0x81DB, 0xC547, 0x81DC, 0xC548, 0x81DD, 0xC549, 0x81DE, 0xC54A, 0x81DF, 0xC54B, 0x81E0, 0xC54C, 0x81E1, 0xC54D, 0x81E2, 0xC54E, 0x81E3, 0xB3BC, 0x81E4, 0xC54F, 0x81E5, 0xC550, 0x81E6, 0xC551, 0x81E7, 0xEAB0, 0x81E8, 0xC552, 0x81E9, 0xC553, 0x81EA, 0xD7D4, 0x81EB, 0xC554, 0x81EC, 0xF4AB, 0x81ED, 0xB3F4, 0x81EE, 0xC555, 0x81EF, 0xC556, 0x81F0, 0xC557, 0x81F1, 0xC558, 0x81F2, 0xC559, 0x81F3, 0xD6C1, 0x81F4, 0xD6C2, 0x81F5, 0xC55A, 0x81F6, 0xC55B, 0x81F7, 0xC55C, 0x81F8, 0xC55D, 0x81F9, 0xC55E, 0x81FA, 0xC55F, 0x81FB, 0xD5E9, 0x81FC, 0xBECA, 0x81FD, 0xC560, 0x81FE, 0xF4A7, 0x81FF, 0xC561, 0x8200, 0xD2A8, 0x8201, 0xF4A8, 0x8202, 0xF4A9, 0x8203, 0xC562, 0x8204, 0xF4AA, 0x8205, 0xBECB, 0x8206, 0xD3DF, 0x8207, 0xC563, 0x8208, 0xC564, 0x8209, 0xC565, 0x820A, 0xC566, 0x820B, 0xC567, 0x820C, 0xC9E0, 0x820D, 0xC9E1, 0x820E, 0xC568, 0x820F, 0xC569, 0x8210, 0xF3C2, 0x8211, 0xC56A, 0x8212, 0xCAE6, 0x8213, 0xC56B, 0x8214, 0xCCF2, 0x8215, 0xC56C, 0x8216, 0xC56D, 0x8217, 0xC56E, 0x8218, 0xC56F, 0x8219, 0xC570, 0x821A, 0xC571, 0x821B, 0xE2B6, 0x821C, 0xCBB4, 0x821D, 0xC572, 0x821E, 0xCEE8, 0x821F, 0xD6DB, 0x8220, 0xC573, 0x8221, 0xF4AD, 0x8222, 0xF4AE, 0x8223, 0xF4AF, 0x8224, 0xC574, 0x8225, 0xC575, 0x8226, 0xC576, 0x8227, 0xC577, 0x8228, 0xF4B2, 0x8229, 0xC578, 0x822A, 0xBABD, 0x822B, 0xF4B3, 0x822C, 0xB0E3, 0x822D, 0xF4B0, 0x822E, 0xC579, 0x822F, 0xF4B1, 0x8230, 0xBDA2, 0x8231, 0xB2D5, 0x8232, 0xC57A, 0x8233, 0xF4B6, 0x8234, 0xF4B7, 0x8235, 0xB6E6, 0x8236, 0xB2B0, 0x8237, 0xCFCF, 0x8238, 0xF4B4, 0x8239, 0xB4AC, 0x823A, 0xC57B, 0x823B, 0xF4B5, 0x823C, 0xC57C, 0x823D, 0xC57D, 0x823E, 0xF4B8, 0x823F, 0xC57E, 0x8240, 0xC580, 0x8241, 0xC581, 0x8242, 0xC582, 0x8243, 0xC583, 0x8244, 0xF4B9, 0x8245, 0xC584, 0x8246, 0xC585, 0x8247, 0xCDA7, 0x8248, 0xC586, 0x8249, 0xF4BA, 0x824A, 0xC587, 0x824B, 0xF4BB, 0x824C, 0xC588, 0x824D, 0xC589, 0x824E, 0xC58A, 0x824F, 0xF4BC, 0x8250, 0xC58B, 0x8251, 0xC58C, 0x8252, 0xC58D, 0x8253, 0xC58E, 0x8254, 0xC58F, 0x8255, 0xC590, 0x8256, 0xC591, 0x8257, 0xC592, 0x8258, 0xCBD2, 0x8259, 0xC593, 0x825A, 0xF4BD, 0x825B, 0xC594, 0x825C, 0xC595, 0x825D, 0xC596, 0x825E, 0xC597, 0x825F, 0xF4BE, 0x8260, 0xC598, 0x8261, 0xC599, 0x8262, 0xC59A, 0x8263, 0xC59B, 0x8264, 0xC59C, 0x8265, 0xC59D, 0x8266, 0xC59E, 0x8267, 0xC59F, 0x8268, 0xF4BF, 0x8269, 0xC5A0, 0x826A, 0xC640, 0x826B, 0xC641, 0x826C, 0xC642, 0x826D, 0xC643, 0x826E, 0xF4DE, 0x826F, 0xC1BC, 0x8270, 0xBCE8, 0x8271, 0xC644, 0x8272, 0xC9AB, 0x8273, 0xD1DE, 0x8274, 0xE5F5, 0x8275, 0xC645, 0x8276, 0xC646, 0x8277, 0xC647, 0x8278, 0xC648, 0x8279, 0xDCB3, 0x827A, 0xD2D5, 0x827B, 0xC649, 0x827C, 0xC64A, 0x827D, 0xDCB4, 0x827E, 0xB0AC, 0x827F, 0xDCB5, 0x8280, 0xC64B, 0x8281, 0xC64C, 0x8282, 0xBDDA, 0x8283, 0xC64D, 0x8284, 0xDCB9, 0x8285, 0xC64E, 0x8286, 0xC64F, 0x8287, 0xC650, 0x8288, 0xD8C2, 0x8289, 0xC651, 0x828A, 0xDCB7, 0x828B, 0xD3F3, 0x828C, 0xC652, 0x828D, 0xC9D6, 0x828E, 0xDCBA, 0x828F, 0xDCB6, 0x8290, 0xC653, 0x8291, 0xDCBB, 0x8292, 0xC3A2, 0x8293, 0xC654, 0x8294, 0xC655, 0x8295, 0xC656, 0x8296, 0xC657, 0x8297, 0xDCBC, 0x8298, 0xDCC5, 0x8299, 0xDCBD, 0x829A, 0xC658, 0x829B, 0xC659, 0x829C, 0xCEDF, 0x829D, 0xD6A5, 0x829E, 0xC65A, 0x829F, 0xDCCF, 0x82A0, 0xC65B, 0x82A1, 0xDCCD, 0x82A2, 0xC65C, 0x82A3, 0xC65D, 0x82A4, 0xDCD2, 0x82A5, 0xBDE6, 0x82A6, 0xC2AB, 0x82A7, 0xC65E, 0x82A8, 0xDCB8, 0x82A9, 0xDCCB, 0x82AA, 0xDCCE, 0x82AB, 0xDCBE, 0x82AC, 0xB7D2, 0x82AD, 0xB0C5, 0x82AE, 0xDCC7, 0x82AF, 0xD0BE, 0x82B0, 0xDCC1, 0x82B1, 0xBBA8, 0x82B2, 0xC65F, 0x82B3, 0xB7BC, 0x82B4, 0xDCCC, 0x82B5, 0xC660, 0x82B6, 0xC661, 0x82B7, 0xDCC6, 0x82B8, 0xDCBF, 0x82B9, 0xC7DB, 0x82BA, 0xC662, 0x82BB, 0xC663, 0x82BC, 0xC664, 0x82BD, 0xD1BF, 0x82BE, 0xDCC0, 0x82BF, 0xC665, 0x82C0, 0xC666, 0x82C1, 0xDCCA, 0x82C2, 0xC667, 0x82C3, 0xC668, 0x82C4, 0xDCD0, 0x82C5, 0xC669, 0x82C6, 0xC66A, 0x82C7, 0xCEAD, 0x82C8, 0xDCC2, 0x82C9, 0xC66B, 0x82CA, 0xDCC3, 0x82CB, 0xDCC8, 0x82CC, 0xDCC9, 0x82CD, 0xB2D4, 0x82CE, 0xDCD1, 0x82CF, 0xCBD5, 0x82D0, 0xC66C, 0x82D1, 0xD4B7, 0x82D2, 0xDCDB, 0x82D3, 0xDCDF, 0x82D4, 0xCCA6, 0x82D5, 0xDCE6, 0x82D6, 0xC66D, 0x82D7, 0xC3E7, 0x82D8, 0xDCDC, 0x82D9, 0xC66E, 0x82DA, 0xC66F, 0x82DB, 0xBFC1, 0x82DC, 0xDCD9, 0x82DD, 0xC670, 0x82DE, 0xB0FA, 0x82DF, 0xB9B6, 0x82E0, 0xDCE5, 0x82E1, 0xDCD3, 0x82E2, 0xC671, 0x82E3, 0xDCC4, 0x82E4, 0xDCD6, 0x82E5, 0xC8F4, 0x82E6, 0xBFE0, 0x82E7, 0xC672, 0x82E8, 0xC673, 0x82E9, 0xC674, 0x82EA, 0xC675, 0x82EB, 0xC9BB, 0x82EC, 0xC676, 0x82ED, 0xC677, 0x82EE, 0xC678, 0x82EF, 0xB1BD, 0x82F0, 0xC679, 0x82F1, 0xD3A2, 0x82F2, 0xC67A, 0x82F3, 0xC67B, 0x82F4, 0xDCDA, 0x82F5, 0xC67C, 0x82F6, 0xC67D, 0x82F7, 0xDCD5, 0x82F8, 0xC67E, 0x82F9, 0xC6BB, 0x82FA, 0xC680, 0x82FB, 0xDCDE, 0x82FC, 0xC681, 0x82FD, 0xC682, 0x82FE, 0xC683, 0x82FF, 0xC684, 0x8300, 0xC685, 0x8301, 0xD7C2, 0x8302, 0xC3AF, 0x8303, 0xB7B6, 0x8304, 0xC7D1, 0x8305, 0xC3A9, 0x8306, 0xDCE2, 0x8307, 0xDCD8, 0x8308, 0xDCEB, 0x8309, 0xDCD4, 0x830A, 0xC686, 0x830B, 0xC687, 0x830C, 0xDCDD, 0x830D, 0xC688, 0x830E, 0xBEA5, 0x830F, 0xDCD7, 0x8310, 0xC689, 0x8311, 0xDCE0, 0x8312, 0xC68A, 0x8313, 0xC68B, 0x8314, 0xDCE3, 0x8315, 0xDCE4, 0x8316, 0xC68C, 0x8317, 0xDCF8, 0x8318, 0xC68D, 0x8319, 0xC68E, 0x831A, 0xDCE1, 0x831B, 0xDDA2, 0x831C, 0xDCE7, 0x831D, 0xC68F, 0x831E, 0xC690, 0x831F, 0xC691, 0x8320, 0xC692, 0x8321, 0xC693, 0x8322, 0xC694, 0x8323, 0xC695, 0x8324, 0xC696, 0x8325, 0xC697, 0x8326, 0xC698, 0x8327, 0xBCEB, 0x8328, 0xB4C4, 0x8329, 0xC699, 0x832A, 0xC69A, 0x832B, 0xC3A3, 0x832C, 0xB2E7, 0x832D, 0xDCFA, 0x832E, 0xC69B, 0x832F, 0xDCF2, 0x8330, 0xC69C, 0x8331, 0xDCEF, 0x8332, 0xC69D, 0x8333, 0xDCFC, 0x8334, 0xDCEE, 0x8335, 0xD2F0, 0x8336, 0xB2E8, 0x8337, 0xC69E, 0x8338, 0xC8D7, 0x8339, 0xC8E3, 0x833A, 0xDCFB, 0x833B, 0xC69F, 0x833C, 0xDCED, 0x833D, 0xC6A0, 0x833E, 0xC740, 0x833F, 0xC741, 0x8340, 0xDCF7, 0x8341, 0xC742, 0x8342, 0xC743, 0x8343, 0xDCF5, 0x8344, 0xC744, 0x8345, 0xC745, 0x8346, 0xBEA3, 0x8347, 0xDCF4, 0x8348, 0xC746, 0x8349, 0xB2DD, 0x834A, 0xC747, 0x834B, 0xC748, 0x834C, 0xC749, 0x834D, 0xC74A, 0x834E, 0xC74B, 0x834F, 0xDCF3, 0x8350, 0xBCF6, 0x8351, 0xDCE8, 0x8352, 0xBBC4, 0x8353, 0xC74C, 0x8354, 0xC0F3, 0x8355, 0xC74D, 0x8356, 0xC74E, 0x8357, 0xC74F, 0x8358, 0xC750, 0x8359, 0xC751, 0x835A, 0xBCD4, 0x835B, 0xDCE9, 0x835C, 0xDCEA, 0x835D, 0xC752, 0x835E, 0xDCF1, 0x835F, 0xDCF6, 0x8360, 0xDCF9, 0x8361, 0xB5B4, 0x8362, 0xC753, 0x8363, 0xC8D9, 0x8364, 0xBBE7, 0x8365, 0xDCFE, 0x8366, 0xDCFD, 0x8367, 0xD3AB, 0x8368, 0xDDA1, 0x8369, 0xDDA3, 0x836A, 0xDDA5, 0x836B, 0xD2F1, 0x836C, 0xDDA4, 0x836D, 0xDDA6, 0x836E, 0xDDA7, 0x836F, 0xD2A9, 0x8370, 0xC754, 0x8371, 0xC755, 0x8372, 0xC756, 0x8373, 0xC757, 0x8374, 0xC758, 0x8375, 0xC759, 0x8376, 0xC75A, 0x8377, 0xBAC9, 0x8378, 0xDDA9, 0x8379, 0xC75B, 0x837A, 0xC75C, 0x837B, 0xDDB6, 0x837C, 0xDDB1, 0x837D, 0xDDB4, 0x837E, 0xC75D, 0x837F, 0xC75E, 0x8380, 0xC75F, 0x8381, 0xC760, 0x8382, 0xC761, 0x8383, 0xC762, 0x8384, 0xC763, 0x8385, 0xDDB0, 0x8386, 0xC6CE, 0x8387, 0xC764, 0x8388, 0xC765, 0x8389, 0xC0F2, 0x838A, 0xC766, 0x838B, 0xC767, 0x838C, 0xC768, 0x838D, 0xC769, 0x838E, 0xC9AF, 0x838F, 0xC76A, 0x8390, 0xC76B, 0x8391, 0xC76C, 0x8392, 0xDCEC, 0x8393, 0xDDAE, 0x8394, 0xC76D, 0x8395, 0xC76E, 0x8396, 0xC76F, 0x8397, 0xC770, 0x8398, 0xDDB7, 0x8399, 0xC771, 0x839A, 0xC772, 0x839B, 0xDCF0, 0x839C, 0xDDAF, 0x839D, 0xC773, 0x839E, 0xDDB8, 0x839F, 0xC774, 0x83A0, 0xDDAC, 0x83A1, 0xC775, 0x83A2, 0xC776, 0x83A3, 0xC777, 0x83A4, 0xC778, 0x83A5, 0xC779, 0x83A6, 0xC77A, 0x83A7, 0xC77B, 0x83A8, 0xDDB9, 0x83A9, 0xDDB3, 0x83AA, 0xDDAD, 0x83AB, 0xC4AA, 0x83AC, 0xC77C, 0x83AD, 0xC77D, 0x83AE, 0xC77E, 0x83AF, 0xC780, 0x83B0, 0xDDA8, 0x83B1, 0xC0B3, 0x83B2, 0xC1AB, 0x83B3, 0xDDAA, 0x83B4, 0xDDAB, 0x83B5, 0xC781, 0x83B6, 0xDDB2, 0x83B7, 0xBBF1, 0x83B8, 0xDDB5, 0x83B9, 0xD3A8, 0x83BA, 0xDDBA, 0x83BB, 0xC782, 0x83BC, 0xDDBB, 0x83BD, 0xC3A7, 0x83BE, 0xC783, 0x83BF, 0xC784, 0x83C0, 0xDDD2, 0x83C1, 0xDDBC, 0x83C2, 0xC785, 0x83C3, 0xC786, 0x83C4, 0xC787, 0x83C5, 0xDDD1, 0x83C6, 0xC788, 0x83C7, 0xB9BD, 0x83C8, 0xC789, 0x83C9, 0xC78A, 0x83CA, 0xBED5, 0x83CB, 0xC78B, 0x83CC, 0xBEFA, 0x83CD, 0xC78C, 0x83CE, 0xC78D, 0x83CF, 0xBACA, 0x83D0, 0xC78E, 0x83D1, 0xC78F, 0x83D2, 0xC790, 0x83D3, 0xC791, 0x83D4, 0xDDCA, 0x83D5, 0xC792, 0x83D6, 0xDDC5, 0x83D7, 0xC793, 0x83D8, 0xDDBF, 0x83D9, 0xC794, 0x83DA, 0xC795, 0x83DB, 0xC796, 0x83DC, 0xB2CB, 0x83DD, 0xDDC3, 0x83DE, 0xC797, 0x83DF, 0xDDCB, 0x83E0, 0xB2A4, 0x83E1, 0xDDD5, 0x83E2, 0xC798, 0x83E3, 0xC799, 0x83E4, 0xC79A, 0x83E5, 0xDDBE, 0x83E6, 0xC79B, 0x83E7, 0xC79C, 0x83E8, 0xC79D, 0x83E9, 0xC6D0, 0x83EA, 0xDDD0, 0x83EB, 0xC79E, 0x83EC, 0xC79F, 0x83ED, 0xC7A0, 0x83EE, 0xC840, 0x83EF, 0xC841, 0x83F0, 0xDDD4, 0x83F1, 0xC1E2, 0x83F2, 0xB7C6, 0x83F3, 0xC842, 0x83F4, 0xC843, 0x83F5, 0xC844, 0x83F6, 0xC845, 0x83F7, 0xC846, 0x83F8, 0xDDCE, 0x83F9, 0xDDCF, 0x83FA, 0xC847, 0x83FB, 0xC848, 0x83FC, 0xC849, 0x83FD, 0xDDC4, 0x83FE, 0xC84A, 0x83FF, 0xC84B, 0x8400, 0xC84C, 0x8401, 0xDDBD, 0x8402, 0xC84D, 0x8403, 0xDDCD, 0x8404, 0xCCD1, 0x8405, 0xC84E, 0x8406, 0xDDC9, 0x8407, 0xC84F, 0x8408, 0xC850, 0x8409, 0xC851, 0x840A, 0xC852, 0x840B, 0xDDC2, 0x840C, 0xC3C8, 0x840D, 0xC6BC, 0x840E, 0xCEAE, 0x840F, 0xDDCC, 0x8410, 0xC853, 0x8411, 0xDDC8, 0x8412, 0xC854, 0x8413, 0xC855, 0x8414, 0xC856, 0x8415, 0xC857, 0x8416, 0xC858, 0x8417, 0xC859, 0x8418, 0xDDC1, 0x8419, 0xC85A, 0x841A, 0xC85B, 0x841B, 0xC85C, 0x841C, 0xDDC6, 0x841D, 0xC2DC, 0x841E, 0xC85D, 0x841F, 0xC85E, 0x8420, 0xC85F, 0x8421, 0xC860, 0x8422, 0xC861, 0x8423, 0xC862, 0x8424, 0xD3A9, 0x8425, 0xD3AA, 0x8426, 0xDDD3, 0x8427, 0xCFF4, 0x8428, 0xC8F8, 0x8429, 0xC863, 0x842A, 0xC864, 0x842B, 0xC865, 0x842C, 0xC866, 0x842D, 0xC867, 0x842E, 0xC868, 0x842F, 0xC869, 0x8430, 0xC86A, 0x8431, 0xDDE6, 0x8432, 0xC86B, 0x8433, 0xC86C, 0x8434, 0xC86D, 0x8435, 0xC86E, 0x8436, 0xC86F, 0x8437, 0xC870, 0x8438, 0xDDC7, 0x8439, 0xC871, 0x843A, 0xC872, 0x843B, 0xC873, 0x843C, 0xDDE0, 0x843D, 0xC2E4, 0x843E, 0xC874, 0x843F, 0xC875, 0x8440, 0xC876, 0x8441, 0xC877, 0x8442, 0xC878, 0x8443, 0xC879, 0x8444, 0xC87A, 0x8445, 0xC87B, 0x8446, 0xDDE1, 0x8447, 0xC87C, 0x8448, 0xC87D, 0x8449, 0xC87E, 0x844A, 0xC880, 0x844B, 0xC881, 0x844C, 0xC882, 0x844D, 0xC883, 0x844E, 0xC884, 0x844F, 0xC885, 0x8450, 0xC886, 0x8451, 0xDDD7, 0x8452, 0xC887, 0x8453, 0xC888, 0x8454, 0xC889, 0x8455, 0xC88A, 0x8456, 0xC88B, 0x8457, 0xD6F8, 0x8458, 0xC88C, 0x8459, 0xDDD9, 0x845A, 0xDDD8, 0x845B, 0xB8F0, 0x845C, 0xDDD6, 0x845D, 0xC88D, 0x845E, 0xC88E, 0x845F, 0xC88F, 0x8460, 0xC890, 0x8461, 0xC6CF, 0x8462, 0xC891, 0x8463, 0xB6AD, 0x8464, 0xC892, 0x8465, 0xC893, 0x8466, 0xC894, 0x8467, 0xC895, 0x8468, 0xC896, 0x8469, 0xDDE2, 0x846A, 0xC897, 0x846B, 0xBAF9, 0x846C, 0xD4E1, 0x846D, 0xDDE7, 0x846E, 0xC898, 0x846F, 0xC899, 0x8470, 0xC89A, 0x8471, 0xB4D0, 0x8472, 0xC89B, 0x8473, 0xDDDA, 0x8474, 0xC89C, 0x8475, 0xBFFB, 0x8476, 0xDDE3, 0x8477, 0xC89D, 0x8478, 0xDDDF, 0x8479, 0xC89E, 0x847A, 0xDDDD, 0x847B, 0xC89F, 0x847C, 0xC8A0, 0x847D, 0xC940, 0x847E, 0xC941, 0x847F, 0xC942, 0x8480, 0xC943, 0x8481, 0xC944, 0x8482, 0xB5D9, 0x8483, 0xC945, 0x8484, 0xC946, 0x8485, 0xC947, 0x8486, 0xC948, 0x8487, 0xDDDB, 0x8488, 0xDDDC, 0x8489, 0xDDDE, 0x848A, 0xC949, 0x848B, 0xBDAF, 0x848C, 0xDDE4, 0x848D, 0xC94A, 0x848E, 0xDDE5, 0x848F, 0xC94B, 0x8490, 0xC94C, 0x8491, 0xC94D, 0x8492, 0xC94E, 0x8493, 0xC94F, 0x8494, 0xC950, 0x8495, 0xC951, 0x8496, 0xC952, 0x8497, 0xDDF5, 0x8498, 0xC953, 0x8499, 0xC3C9, 0x849A, 0xC954, 0x849B, 0xC955, 0x849C, 0xCBE2, 0x849D, 0xC956, 0x849E, 0xC957, 0x849F, 0xC958, 0x84A0, 0xC959, 0x84A1, 0xDDF2, 0x84A2, 0xC95A, 0x84A3, 0xC95B, 0x84A4, 0xC95C, 0x84A5, 0xC95D, 0x84A6, 0xC95E, 0x84A7, 0xC95F, 0x84A8, 0xC960, 0x84A9, 0xC961, 0x84AA, 0xC962, 0x84AB, 0xC963, 0x84AC, 0xC964, 0x84AD, 0xC965, 0x84AE, 0xC966, 0x84AF, 0xD8E1, 0x84B0, 0xC967, 0x84B1, 0xC968, 0x84B2, 0xC6D1, 0x84B3, 0xC969, 0x84B4, 0xDDF4, 0x84B5, 0xC96A, 0x84B6, 0xC96B, 0x84B7, 0xC96C, 0x84B8, 0xD5F4, 0x84B9, 0xDDF3, 0x84BA, 0xDDF0, 0x84BB, 0xC96D, 0x84BC, 0xC96E, 0x84BD, 0xDDEC, 0x84BE, 0xC96F, 0x84BF, 0xDDEF, 0x84C0, 0xC970, 0x84C1, 0xDDE8, 0x84C2, 0xC971, 0x84C3, 0xC972, 0x84C4, 0xD0EE, 0x84C5, 0xC973, 0x84C6, 0xC974, 0x84C7, 0xC975, 0x84C8, 0xC976, 0x84C9, 0xC8D8, 0x84CA, 0xDDEE, 0x84CB, 0xC977, 0x84CC, 0xC978, 0x84CD, 0xDDE9, 0x84CE, 0xC979, 0x84CF, 0xC97A, 0x84D0, 0xDDEA, 0x84D1, 0xCBF2, 0x84D2, 0xC97B, 0x84D3, 0xDDED, 0x84D4, 0xC97C, 0x84D5, 0xC97D, 0x84D6, 0xB1CD, 0x84D7, 0xC97E, 0x84D8, 0xC980, 0x84D9, 0xC981, 0x84DA, 0xC982, 0x84DB, 0xC983, 0x84DC, 0xC984, 0x84DD, 0xC0B6, 0x84DE, 0xC985, 0x84DF, 0xBCBB, 0x84E0, 0xDDF1, 0x84E1, 0xC986, 0x84E2, 0xC987, 0x84E3, 0xDDF7, 0x84E4, 0xC988, 0x84E5, 0xDDF6, 0x84E6, 0xDDEB, 0x84E7, 0xC989, 0x84E8, 0xC98A, 0x84E9, 0xC98B, 0x84EA, 0xC98C, 0x84EB, 0xC98D, 0x84EC, 0xC5EE, 0x84ED, 0xC98E, 0x84EE, 0xC98F, 0x84EF, 0xC990, 0x84F0, 0xDDFB, 0x84F1, 0xC991, 0x84F2, 0xC992, 0x84F3, 0xC993, 0x84F4, 0xC994, 0x84F5, 0xC995, 0x84F6, 0xC996, 0x84F7, 0xC997, 0x84F8, 0xC998, 0x84F9, 0xC999, 0x84FA, 0xC99A, 0x84FB, 0xC99B, 0x84FC, 0xDEA4, 0x84FD, 0xC99C, 0x84FE, 0xC99D, 0x84FF, 0xDEA3, 0x8500, 0xC99E, 0x8501, 0xC99F, 0x8502, 0xC9A0, 0x8503, 0xCA40, 0x8504, 0xCA41, 0x8505, 0xCA42, 0x8506, 0xCA43, 0x8507, 0xCA44, 0x8508, 0xCA45, 0x8509, 0xCA46, 0x850A, 0xCA47, 0x850B, 0xCA48, 0x850C, 0xDDF8, 0x850D, 0xCA49, 0x850E, 0xCA4A, 0x850F, 0xCA4B, 0x8510, 0xCA4C, 0x8511, 0xC3EF, 0x8512, 0xCA4D, 0x8513, 0xC2FB, 0x8514, 0xCA4E, 0x8515, 0xCA4F, 0x8516, 0xCA50, 0x8517, 0xD5E1, 0x8518, 0xCA51, 0x8519, 0xCA52, 0x851A, 0xCEB5, 0x851B, 0xCA53, 0x851C, 0xCA54, 0x851D, 0xCA55, 0x851E, 0xCA56, 0x851F, 0xDDFD, 0x8520, 0xCA57, 0x8521, 0xB2CC, 0x8522, 0xCA58, 0x8523, 0xCA59, 0x8524, 0xCA5A, 0x8525, 0xCA5B, 0x8526, 0xCA5C, 0x8527, 0xCA5D, 0x8528, 0xCA5E, 0x8529, 0xCA5F, 0x852A, 0xCA60, 0x852B, 0xC4E8, 0x852C, 0xCADF, 0x852D, 0xCA61, 0x852E, 0xCA62, 0x852F, 0xCA63, 0x8530, 0xCA64, 0x8531, 0xCA65, 0x8532, 0xCA66, 0x8533, 0xCA67, 0x8534, 0xCA68, 0x8535, 0xCA69, 0x8536, 0xCA6A, 0x8537, 0xC7BE, 0x8538, 0xDDFA, 0x8539, 0xDDFC, 0x853A, 0xDDFE, 0x853B, 0xDEA2, 0x853C, 0xB0AA, 0x853D, 0xB1CE, 0x853E, 0xCA6B, 0x853F, 0xCA6C, 0x8540, 0xCA6D, 0x8541, 0xCA6E, 0x8542, 0xCA6F, 0x8543, 0xDEAC, 0x8544, 0xCA70, 0x8545, 0xCA71, 0x8546, 0xCA72, 0x8547, 0xCA73, 0x8548, 0xDEA6, 0x8549, 0xBDB6, 0x854A, 0xC8EF, 0x854B, 0xCA74, 0x854C, 0xCA75, 0x854D, 0xCA76, 0x854E, 0xCA77, 0x854F, 0xCA78, 0x8550, 0xCA79, 0x8551, 0xCA7A, 0x8552, 0xCA7B, 0x8553, 0xCA7C, 0x8554, 0xCA7D, 0x8555, 0xCA7E, 0x8556, 0xDEA1, 0x8557, 0xCA80, 0x8558, 0xCA81, 0x8559, 0xDEA5, 0x855A, 0xCA82, 0x855B, 0xCA83, 0x855C, 0xCA84, 0x855D, 0xCA85, 0x855E, 0xDEA9, 0x855F, 0xCA86, 0x8560, 0xCA87, 0x8561, 0xCA88, 0x8562, 0xCA89, 0x8563, 0xCA8A, 0x8564, 0xDEA8, 0x8565, 0xCA8B, 0x8566, 0xCA8C, 0x8567, 0xCA8D, 0x8568, 0xDEA7, 0x8569, 0xCA8E, 0x856A, 0xCA8F, 0x856B, 0xCA90, 0x856C, 0xCA91, 0x856D, 0xCA92, 0x856E, 0xCA93, 0x856F, 0xCA94, 0x8570, 0xCA95, 0x8571, 0xCA96, 0x8572, 0xDEAD, 0x8573, 0xCA97, 0x8574, 0xD4CC, 0x8575, 0xCA98, 0x8576, 0xCA99, 0x8577, 0xCA9A, 0x8578, 0xCA9B, 0x8579, 0xDEB3, 0x857A, 0xDEAA, 0x857B, 0xDEAE, 0x857C, 0xCA9C, 0x857D, 0xCA9D, 0x857E, 0xC0D9, 0x857F, 0xCA9E, 0x8580, 0xCA9F, 0x8581, 0xCAA0, 0x8582, 0xCB40, 0x8583, 0xCB41, 0x8584, 0xB1A1, 0x8585, 0xDEB6, 0x8586, 0xCB42, 0x8587, 0xDEB1, 0x8588, 0xCB43, 0x8589, 0xCB44, 0x858A, 0xCB45, 0x858B, 0xCB46, 0x858C, 0xCB47, 0x858D, 0xCB48, 0x858E, 0xCB49, 0x858F, 0xDEB2, 0x8590, 0xCB4A, 0x8591, 0xCB4B, 0x8592, 0xCB4C, 0x8593, 0xCB4D, 0x8594, 0xCB4E, 0x8595, 0xCB4F, 0x8596, 0xCB50, 0x8597, 0xCB51, 0x8598, 0xCB52, 0x8599, 0xCB53, 0x859A, 0xCB54, 0x859B, 0xD1A6, 0x859C, 0xDEB5, 0x859D, 0xCB55, 0x859E, 0xCB56, 0x859F, 0xCB57, 0x85A0, 0xCB58, 0x85A1, 0xCB59, 0x85A2, 0xCB5A, 0x85A3, 0xCB5B, 0x85A4, 0xDEAF, 0x85A5, 0xCB5C, 0x85A6, 0xCB5D, 0x85A7, 0xCB5E, 0x85A8, 0xDEB0, 0x85A9, 0xCB5F, 0x85AA, 0xD0BD, 0x85AB, 0xCB60, 0x85AC, 0xCB61, 0x85AD, 0xCB62, 0x85AE, 0xDEB4, 0x85AF, 0xCAED, 0x85B0, 0xDEB9, 0x85B1, 0xCB63, 0x85B2, 0xCB64, 0x85B3, 0xCB65, 0x85B4, 0xCB66, 0x85B5, 0xCB67, 0x85B6, 0xCB68, 0x85B7, 0xDEB8, 0x85B8, 0xCB69, 0x85B9, 0xDEB7, 0x85BA, 0xCB6A, 0x85BB, 0xCB6B, 0x85BC, 0xCB6C, 0x85BD, 0xCB6D, 0x85BE, 0xCB6E, 0x85BF, 0xCB6F, 0x85C0, 0xCB70, 0x85C1, 0xDEBB, 0x85C2, 0xCB71, 0x85C3, 0xCB72, 0x85C4, 0xCB73, 0x85C5, 0xCB74, 0x85C6, 0xCB75, 0x85C7, 0xCB76, 0x85C8, 0xCB77, 0x85C9, 0xBDE5, 0x85CA, 0xCB78, 0x85CB, 0xCB79, 0x85CC, 0xCB7A, 0x85CD, 0xCB7B, 0x85CE, 0xCB7C, 0x85CF, 0xB2D8, 0x85D0, 0xC3EA, 0x85D1, 0xCB7D, 0x85D2, 0xCB7E, 0x85D3, 0xDEBA, 0x85D4, 0xCB80, 0x85D5, 0xC5BA, 0x85D6, 0xCB81, 0x85D7, 0xCB82, 0x85D8, 0xCB83, 0x85D9, 0xCB84, 0x85DA, 0xCB85, 0x85DB, 0xCB86, 0x85DC, 0xDEBC, 0x85DD, 0xCB87, 0x85DE, 0xCB88, 0x85DF, 0xCB89, 0x85E0, 0xCB8A, 0x85E1, 0xCB8B, 0x85E2, 0xCB8C, 0x85E3, 0xCB8D, 0x85E4, 0xCCD9, 0x85E5, 0xCB8E, 0x85E6, 0xCB8F, 0x85E7, 0xCB90, 0x85E8, 0xCB91, 0x85E9, 0xB7AA, 0x85EA, 0xCB92, 0x85EB, 0xCB93, 0x85EC, 0xCB94, 0x85ED, 0xCB95, 0x85EE, 0xCB96, 0x85EF, 0xCB97, 0x85F0, 0xCB98, 0x85F1, 0xCB99, 0x85F2, 0xCB9A, 0x85F3, 0xCB9B, 0x85F4, 0xCB9C, 0x85F5, 0xCB9D, 0x85F6, 0xCB9E, 0x85F7, 0xCB9F, 0x85F8, 0xCBA0, 0x85F9, 0xCC40, 0x85FA, 0xCC41, 0x85FB, 0xD4E5, 0x85FC, 0xCC42, 0x85FD, 0xCC43, 0x85FE, 0xCC44, 0x85FF, 0xDEBD, 0x8600, 0xCC45, 0x8601, 0xCC46, 0x8602, 0xCC47, 0x8603, 0xCC48, 0x8604, 0xCC49, 0x8605, 0xDEBF, 0x8606, 0xCC4A, 0x8607, 0xCC4B, 0x8608, 0xCC4C, 0x8609, 0xCC4D, 0x860A, 0xCC4E, 0x860B, 0xCC4F, 0x860C, 0xCC50, 0x860D, 0xCC51, 0x860E, 0xCC52, 0x860F, 0xCC53, 0x8610, 0xCC54, 0x8611, 0xC4A2, 0x8612, 0xCC55, 0x8613, 0xCC56, 0x8614, 0xCC57, 0x8615, 0xCC58, 0x8616, 0xDEC1, 0x8617, 0xCC59, 0x8618, 0xCC5A, 0x8619, 0xCC5B, 0x861A, 0xCC5C, 0x861B, 0xCC5D, 0x861C, 0xCC5E, 0x861D, 0xCC5F, 0x861E, 0xCC60, 0x861F, 0xCC61, 0x8620, 0xCC62, 0x8621, 0xCC63, 0x8622, 0xCC64, 0x8623, 0xCC65, 0x8624, 0xCC66, 0x8625, 0xCC67, 0x8626, 0xCC68, 0x8627, 0xDEBE, 0x8628, 0xCC69, 0x8629, 0xDEC0, 0x862A, 0xCC6A, 0x862B, 0xCC6B, 0x862C, 0xCC6C, 0x862D, 0xCC6D, 0x862E, 0xCC6E, 0x862F, 0xCC6F, 0x8630, 0xCC70, 0x8631, 0xCC71, 0x8632, 0xCC72, 0x8633, 0xCC73, 0x8634, 0xCC74, 0x8635, 0xCC75, 0x8636, 0xCC76, 0x8637, 0xCC77, 0x8638, 0xD5BA, 0x8639, 0xCC78, 0x863A, 0xCC79, 0x863B, 0xCC7A, 0x863C, 0xDEC2, 0x863D, 0xCC7B, 0x863E, 0xCC7C, 0x863F, 0xCC7D, 0x8640, 0xCC7E, 0x8641, 0xCC80, 0x8642, 0xCC81, 0x8643, 0xCC82, 0x8644, 0xCC83, 0x8645, 0xCC84, 0x8646, 0xCC85, 0x8647, 0xCC86, 0x8648, 0xCC87, 0x8649, 0xCC88, 0x864A, 0xCC89, 0x864B, 0xCC8A, 0x864C, 0xCC8B, 0x864D, 0xF2AE, 0x864E, 0xBBA2, 0x864F, 0xC2B2, 0x8650, 0xC5B0, 0x8651, 0xC2C7, 0x8652, 0xCC8C, 0x8653, 0xCC8D, 0x8654, 0xF2AF, 0x8655, 0xCC8E, 0x8656, 0xCC8F, 0x8657, 0xCC90, 0x8658, 0xCC91, 0x8659, 0xCC92, 0x865A, 0xD0E9, 0x865B, 0xCC93, 0x865C, 0xCC94, 0x865D, 0xCC95, 0x865E, 0xD3DD, 0x865F, 0xCC96, 0x8660, 0xCC97, 0x8661, 0xCC98, 0x8662, 0xEBBD, 0x8663, 0xCC99, 0x8664, 0xCC9A, 0x8665, 0xCC9B, 0x8666, 0xCC9C, 0x8667, 0xCC9D, 0x8668, 0xCC9E, 0x8669, 0xCC9F, 0x866A, 0xCCA0, 0x866B, 0xB3E6, 0x866C, 0xF2B0, 0x866D, 0xCD40, 0x866E, 0xF2B1, 0x866F, 0xCD41, 0x8670, 0xCD42, 0x8671, 0xCAAD, 0x8672, 0xCD43, 0x8673, 0xCD44, 0x8674, 0xCD45, 0x8675, 0xCD46, 0x8676, 0xCD47, 0x8677, 0xCD48, 0x8678, 0xCD49, 0x8679, 0xBAE7, 0x867A, 0xF2B3, 0x867B, 0xF2B5, 0x867C, 0xF2B4, 0x867D, 0xCBE4, 0x867E, 0xCFBA, 0x867F, 0xF2B2, 0x8680, 0xCAB4, 0x8681, 0xD2CF, 0x8682, 0xC2EC, 0x8683, 0xCD4A, 0x8684, 0xCD4B, 0x8685, 0xCD4C, 0x8686, 0xCD4D, 0x8687, 0xCD4E, 0x8688, 0xCD4F, 0x8689, 0xCD50, 0x868A, 0xCEC3, 0x868B, 0xF2B8, 0x868C, 0xB0F6, 0x868D, 0xF2B7, 0x868E, 0xCD51, 0x868F, 0xCD52, 0x8690, 0xCD53, 0x8691, 0xCD54, 0x8692, 0xCD55, 0x8693, 0xF2BE, 0x8694, 0xCD56, 0x8695, 0xB2CF, 0x8696, 0xCD57, 0x8697, 0xCD58, 0x8698, 0xCD59, 0x8699, 0xCD5A, 0x869A, 0xCD5B, 0x869B, 0xCD5C, 0x869C, 0xD1C1, 0x869D, 0xF2BA, 0x869E, 0xCD5D, 0x869F, 0xCD5E, 0x86A0, 0xCD5F, 0x86A1, 0xCD60, 0x86A2, 0xCD61, 0x86A3, 0xF2BC, 0x86A4, 0xD4E9, 0x86A5, 0xCD62, 0x86A6, 0xCD63, 0x86A7, 0xF2BB, 0x86A8, 0xF2B6, 0x86A9, 0xF2BF, 0x86AA, 0xF2BD, 0x86AB, 0xCD64, 0x86AC, 0xF2B9, 0x86AD, 0xCD65, 0x86AE, 0xCD66, 0x86AF, 0xF2C7, 0x86B0, 0xF2C4, 0x86B1, 0xF2C6, 0x86B2, 0xCD67, 0x86B3, 0xCD68, 0x86B4, 0xF2CA, 0x86B5, 0xF2C2, 0x86B6, 0xF2C0, 0x86B7, 0xCD69, 0x86B8, 0xCD6A, 0x86B9, 0xCD6B, 0x86BA, 0xF2C5, 0x86BB, 0xCD6C, 0x86BC, 0xCD6D, 0x86BD, 0xCD6E, 0x86BE, 0xCD6F, 0x86BF, 0xCD70, 0x86C0, 0xD6FB, 0x86C1, 0xCD71, 0x86C2, 0xCD72, 0x86C3, 0xCD73, 0x86C4, 0xF2C1, 0x86C5, 0xCD74, 0x86C6, 0xC7F9, 0x86C7, 0xC9DF, 0x86C8, 0xCD75, 0x86C9, 0xF2C8, 0x86CA, 0xB9C6, 0x86CB, 0xB5B0, 0x86CC, 0xCD76, 0x86CD, 0xCD77, 0x86CE, 0xF2C3, 0x86CF, 0xF2C9, 0x86D0, 0xF2D0, 0x86D1, 0xF2D6, 0x86D2, 0xCD78, 0x86D3, 0xCD79, 0x86D4, 0xBBD7, 0x86D5, 0xCD7A, 0x86D6, 0xCD7B, 0x86D7, 0xCD7C, 0x86D8, 0xF2D5, 0x86D9, 0xCDDC, 0x86DA, 0xCD7D, 0x86DB, 0xD6EB, 0x86DC, 0xCD7E, 0x86DD, 0xCD80, 0x86DE, 0xF2D2, 0x86DF, 0xF2D4, 0x86E0, 0xCD81, 0x86E1, 0xCD82, 0x86E2, 0xCD83, 0x86E3, 0xCD84, 0x86E4, 0xB8F2, 0x86E5, 0xCD85, 0x86E6, 0xCD86, 0x86E7, 0xCD87, 0x86E8, 0xCD88, 0x86E9, 0xF2CB, 0x86EA, 0xCD89, 0x86EB, 0xCD8A, 0x86EC, 0xCD8B, 0x86ED, 0xF2CE, 0x86EE, 0xC2F9, 0x86EF, 0xCD8C, 0x86F0, 0xD5DD, 0x86F1, 0xF2CC, 0x86F2, 0xF2CD, 0x86F3, 0xF2CF, 0x86F4, 0xF2D3, 0x86F5, 0xCD8D, 0x86F6, 0xCD8E, 0x86F7, 0xCD8F, 0x86F8, 0xF2D9, 0x86F9, 0xD3BC, 0x86FA, 0xCD90, 0x86FB, 0xCD91, 0x86FC, 0xCD92, 0x86FD, 0xCD93, 0x86FE, 0xB6EA, 0x86FF, 0xCD94, 0x8700, 0xCAF1, 0x8701, 0xCD95, 0x8702, 0xB7E4, 0x8703, 0xF2D7, 0x8704, 0xCD96, 0x8705, 0xCD97, 0x8706, 0xCD98, 0x8707, 0xF2D8, 0x8708, 0xF2DA, 0x8709, 0xF2DD, 0x870A, 0xF2DB, 0x870B, 0xCD99, 0x870C, 0xCD9A, 0x870D, 0xF2DC, 0x870E, 0xCD9B, 0x870F, 0xCD9C, 0x8710, 0xCD9D, 0x8711, 0xCD9E, 0x8712, 0xD1D1, 0x8713, 0xF2D1, 0x8714, 0xCD9F, 0x8715, 0xCDC9, 0x8716, 0xCDA0, 0x8717, 0xCECF, 0x8718, 0xD6A9, 0x8719, 0xCE40, 0x871A, 0xF2E3, 0x871B, 0xCE41, 0x871C, 0xC3DB, 0x871D, 0xCE42, 0x871E, 0xF2E0, 0x871F, 0xCE43, 0x8720, 0xCE44, 0x8721, 0xC0AF, 0x8722, 0xF2EC, 0x8723, 0xF2DE, 0x8724, 0xCE45, 0x8725, 0xF2E1, 0x8726, 0xCE46, 0x8727, 0xCE47, 0x8728, 0xCE48, 0x8729, 0xF2E8, 0x872A, 0xCE49, 0x872B, 0xCE4A, 0x872C, 0xCE4B, 0x872D, 0xCE4C, 0x872E, 0xF2E2, 0x872F, 0xCE4D, 0x8730, 0xCE4E, 0x8731, 0xF2E7, 0x8732, 0xCE4F, 0x8733, 0xCE50, 0x8734, 0xF2E6, 0x8735, 0xCE51, 0x8736, 0xCE52, 0x8737, 0xF2E9, 0x8738, 0xCE53, 0x8739, 0xCE54, 0x873A, 0xCE55, 0x873B, 0xF2DF, 0x873C, 0xCE56, 0x873D, 0xCE57, 0x873E, 0xF2E4, 0x873F, 0xF2EA, 0x8740, 0xCE58, 0x8741, 0xCE59, 0x8742, 0xCE5A, 0x8743, 0xCE5B, 0x8744, 0xCE5C, 0x8745, 0xCE5D, 0x8746, 0xCE5E, 0x8747, 0xD3AC, 0x8748, 0xF2E5, 0x8749, 0xB2F5, 0x874A, 0xCE5F, 0x874B, 0xCE60, 0x874C, 0xF2F2, 0x874D, 0xCE61, 0x874E, 0xD0AB, 0x874F, 0xCE62, 0x8750, 0xCE63, 0x8751, 0xCE64, 0x8752, 0xCE65, 0x8753, 0xF2F5, 0x8754, 0xCE66, 0x8755, 0xCE67, 0x8756, 0xCE68, 0x8757, 0xBBC8, 0x8758, 0xCE69, 0x8759, 0xF2F9, 0x875A, 0xCE6A, 0x875B, 0xCE6B, 0x875C, 0xCE6C, 0x875D, 0xCE6D, 0x875E, 0xCE6E, 0x875F, 0xCE6F, 0x8760, 0xF2F0, 0x8761, 0xCE70, 0x8762, 0xCE71, 0x8763, 0xF2F6, 0x8764, 0xF2F8, 0x8765, 0xF2FA, 0x8766, 0xCE72, 0x8767, 0xCE73, 0x8768, 0xCE74, 0x8769, 0xCE75, 0x876A, 0xCE76, 0x876B, 0xCE77, 0x876C, 0xCE78, 0x876D, 0xCE79, 0x876E, 0xF2F3, 0x876F, 0xCE7A, 0x8770, 0xF2F1, 0x8771, 0xCE7B, 0x8772, 0xCE7C, 0x8773, 0xCE7D, 0x8774, 0xBAFB, 0x8775, 0xCE7E, 0x8776, 0xB5FB, 0x8777, 0xCE80, 0x8778, 0xCE81, 0x8779, 0xCE82, 0x877A, 0xCE83, 0x877B, 0xF2EF, 0x877C, 0xF2F7, 0x877D, 0xF2ED, 0x877E, 0xF2EE, 0x877F, 0xCE84, 0x8780, 0xCE85, 0x8781, 0xCE86, 0x8782, 0xF2EB, 0x8783, 0xF3A6, 0x8784, 0xCE87, 0x8785, 0xF3A3, 0x8786, 0xCE88, 0x8787, 0xCE89, 0x8788, 0xF3A2, 0x8789, 0xCE8A, 0x878A, 0xCE8B, 0x878B, 0xF2F4, 0x878C, 0xCE8C, 0x878D, 0xC8DA, 0x878E, 0xCE8D, 0x878F, 0xCE8E, 0x8790, 0xCE8F, 0x8791, 0xCE90, 0x8792, 0xCE91, 0x8793, 0xF2FB, 0x8794, 0xCE92, 0x8795, 0xCE93, 0x8796, 0xCE94, 0x8797, 0xF3A5, 0x8798, 0xCE95, 0x8799, 0xCE96, 0x879A, 0xCE97, 0x879B, 0xCE98, 0x879C, 0xCE99, 0x879D, 0xCE9A, 0x879E, 0xCE9B, 0x879F, 0xC3F8, 0x87A0, 0xCE9C, 0x87A1, 0xCE9D, 0x87A2, 0xCE9E, 0x87A3, 0xCE9F, 0x87A4, 0xCEA0, 0x87A5, 0xCF40, 0x87A6, 0xCF41, 0x87A7, 0xCF42, 0x87A8, 0xF2FD, 0x87A9, 0xCF43, 0x87AA, 0xCF44, 0x87AB, 0xF3A7, 0x87AC, 0xF3A9, 0x87AD, 0xF3A4, 0x87AE, 0xCF45, 0x87AF, 0xF2FC, 0x87B0, 0xCF46, 0x87B1, 0xCF47, 0x87B2, 0xCF48, 0x87B3, 0xF3AB, 0x87B4, 0xCF49, 0x87B5, 0xF3AA, 0x87B6, 0xCF4A, 0x87B7, 0xCF4B, 0x87B8, 0xCF4C, 0x87B9, 0xCF4D, 0x87BA, 0xC2DD, 0x87BB, 0xCF4E, 0x87BC, 0xCF4F, 0x87BD, 0xF3AE, 0x87BE, 0xCF50, 0x87BF, 0xCF51, 0x87C0, 0xF3B0, 0x87C1, 0xCF52, 0x87C2, 0xCF53, 0x87C3, 0xCF54, 0x87C4, 0xCF55, 0x87C5, 0xCF56, 0x87C6, 0xF3A1, 0x87C7, 0xCF57, 0x87C8, 0xCF58, 0x87C9, 0xCF59, 0x87CA, 0xF3B1, 0x87CB, 0xF3AC, 0x87CC, 0xCF5A, 0x87CD, 0xCF5B, 0x87CE, 0xCF5C, 0x87CF, 0xCF5D, 0x87D0, 0xCF5E, 0x87D1, 0xF3AF, 0x87D2, 0xF2FE, 0x87D3, 0xF3AD, 0x87D4, 0xCF5F, 0x87D5, 0xCF60, 0x87D6, 0xCF61, 0x87D7, 0xCF62, 0x87D8, 0xCF63, 0x87D9, 0xCF64, 0x87DA, 0xCF65, 0x87DB, 0xF3B2, 0x87DC, 0xCF66, 0x87DD, 0xCF67, 0x87DE, 0xCF68, 0x87DF, 0xCF69, 0x87E0, 0xF3B4, 0x87E1, 0xCF6A, 0x87E2, 0xCF6B, 0x87E3, 0xCF6C, 0x87E4, 0xCF6D, 0x87E5, 0xF3A8, 0x87E6, 0xCF6E, 0x87E7, 0xCF6F, 0x87E8, 0xCF70, 0x87E9, 0xCF71, 0x87EA, 0xF3B3, 0x87EB, 0xCF72, 0x87EC, 0xCF73, 0x87ED, 0xCF74, 0x87EE, 0xF3B5, 0x87EF, 0xCF75, 0x87F0, 0xCF76, 0x87F1, 0xCF77, 0x87F2, 0xCF78, 0x87F3, 0xCF79, 0x87F4, 0xCF7A, 0x87F5, 0xCF7B, 0x87F6, 0xCF7C, 0x87F7, 0xCF7D, 0x87F8, 0xCF7E, 0x87F9, 0xD0B7, 0x87FA, 0xCF80, 0x87FB, 0xCF81, 0x87FC, 0xCF82, 0x87FD, 0xCF83, 0x87FE, 0xF3B8, 0x87FF, 0xCF84, 0x8800, 0xCF85, 0x8801, 0xCF86, 0x8802, 0xCF87, 0x8803, 0xD9F9, 0x8804, 0xCF88, 0x8805, 0xCF89, 0x8806, 0xCF8A, 0x8807, 0xCF8B, 0x8808, 0xCF8C, 0x8809, 0xCF8D, 0x880A, 0xF3B9, 0x880B, 0xCF8E, 0x880C, 0xCF8F, 0x880D, 0xCF90, 0x880E, 0xCF91, 0x880F, 0xCF92, 0x8810, 0xCF93, 0x8811, 0xCF94, 0x8812, 0xCF95, 0x8813, 0xF3B7, 0x8814, 0xCF96, 0x8815, 0xC8E4, 0x8816, 0xF3B6, 0x8817, 0xCF97, 0x8818, 0xCF98, 0x8819, 0xCF99, 0x881A, 0xCF9A, 0x881B, 0xF3BA, 0x881C, 0xCF9B, 0x881D, 0xCF9C, 0x881E, 0xCF9D, 0x881F, 0xCF9E, 0x8820, 0xCF9F, 0x8821, 0xF3BB, 0x8822, 0xB4C0, 0x8823, 0xCFA0, 0x8824, 0xD040, 0x8825, 0xD041, 0x8826, 0xD042, 0x8827, 0xD043, 0x8828, 0xD044, 0x8829, 0xD045, 0x882A, 0xD046, 0x882B, 0xD047, 0x882C, 0xD048, 0x882D, 0xD049, 0x882E, 0xD04A, 0x882F, 0xD04B, 0x8830, 0xD04C, 0x8831, 0xD04D, 0x8832, 0xEEC3, 0x8833, 0xD04E, 0x8834, 0xD04F, 0x8835, 0xD050, 0x8836, 0xD051, 0x8837, 0xD052, 0x8838, 0xD053, 0x8839, 0xF3BC, 0x883A, 0xD054, 0x883B, 0xD055, 0x883C, 0xF3BD, 0x883D, 0xD056, 0x883E, 0xD057, 0x883F, 0xD058, 0x8840, 0xD1AA, 0x8841, 0xD059, 0x8842, 0xD05A, 0x8843, 0xD05B, 0x8844, 0xF4AC, 0x8845, 0xD0C6, 0x8846, 0xD05C, 0x8847, 0xD05D, 0x8848, 0xD05E, 0x8849, 0xD05F, 0x884A, 0xD060, 0x884B, 0xD061, 0x884C, 0xD0D0, 0x884D, 0xD1DC, 0x884E, 0xD062, 0x884F, 0xD063, 0x8850, 0xD064, 0x8851, 0xD065, 0x8852, 0xD066, 0x8853, 0xD067, 0x8854, 0xCFCE, 0x8855, 0xD068, 0x8856, 0xD069, 0x8857, 0xBDD6, 0x8858, 0xD06A, 0x8859, 0xD1C3, 0x885A, 0xD06B, 0x885B, 0xD06C, 0x885C, 0xD06D, 0x885D, 0xD06E, 0x885E, 0xD06F, 0x885F, 0xD070, 0x8860, 0xD071, 0x8861, 0xBAE2, 0x8862, 0xE1E9, 0x8863, 0xD2C2, 0x8864, 0xF1C2, 0x8865, 0xB2B9, 0x8866, 0xD072, 0x8867, 0xD073, 0x8868, 0xB1ED, 0x8869, 0xF1C3, 0x886A, 0xD074, 0x886B, 0xC9C0, 0x886C, 0xB3C4, 0x886D, 0xD075, 0x886E, 0xD9F2, 0x886F, 0xD076, 0x8870, 0xCBA5, 0x8871, 0xD077, 0x8872, 0xF1C4, 0x8873, 0xD078, 0x8874, 0xD079, 0x8875, 0xD07A, 0x8876, 0xD07B, 0x8877, 0xD6D4, 0x8878, 0xD07C, 0x8879, 0xD07D, 0x887A, 0xD07E, 0x887B, 0xD080, 0x887C, 0xD081, 0x887D, 0xF1C5, 0x887E, 0xF4C0, 0x887F, 0xF1C6, 0x8880, 0xD082, 0x8881, 0xD4AC, 0x8882, 0xF1C7, 0x8883, 0xD083, 0x8884, 0xB0C0, 0x8885, 0xF4C1, 0x8886, 0xD084, 0x8887, 0xD085, 0x8888, 0xF4C2, 0x8889, 0xD086, 0x888A, 0xD087, 0x888B, 0xB4FC, 0x888C, 0xD088, 0x888D, 0xC5DB, 0x888E, 0xD089, 0x888F, 0xD08A, 0x8890, 0xD08B, 0x8891, 0xD08C, 0x8892, 0xCCBB, 0x8893, 0xD08D, 0x8894, 0xD08E, 0x8895, 0xD08F, 0x8896, 0xD0E4, 0x8897, 0xD090, 0x8898, 0xD091, 0x8899, 0xD092, 0x889A, 0xD093, 0x889B, 0xD094, 0x889C, 0xCDE0, 0x889D, 0xD095, 0x889E, 0xD096, 0x889F, 0xD097, 0x88A0, 0xD098, 0x88A1, 0xD099, 0x88A2, 0xF1C8, 0x88A3, 0xD09A, 0x88A4, 0xD9F3, 0x88A5, 0xD09B, 0x88A6, 0xD09C, 0x88A7, 0xD09D, 0x88A8, 0xD09E, 0x88A9, 0xD09F, 0x88AA, 0xD0A0, 0x88AB, 0xB1BB, 0x88AC, 0xD140, 0x88AD, 0xCFAE, 0x88AE, 0xD141, 0x88AF, 0xD142, 0x88B0, 0xD143, 0x88B1, 0xB8A4, 0x88B2, 0xD144, 0x88B3, 0xD145, 0x88B4, 0xD146, 0x88B5, 0xD147, 0x88B6, 0xD148, 0x88B7, 0xF1CA, 0x88B8, 0xD149, 0x88B9, 0xD14A, 0x88BA, 0xD14B, 0x88BB, 0xD14C, 0x88BC, 0xF1CB, 0x88BD, 0xD14D, 0x88BE, 0xD14E, 0x88BF, 0xD14F, 0x88C0, 0xD150, 0x88C1, 0xB2C3, 0x88C2, 0xC1D1, 0x88C3, 0xD151, 0x88C4, 0xD152, 0x88C5, 0xD7B0, 0x88C6, 0xF1C9, 0x88C7, 0xD153, 0x88C8, 0xD154, 0x88C9, 0xF1CC, 0x88CA, 0xD155, 0x88CB, 0xD156, 0x88CC, 0xD157, 0x88CD, 0xD158, 0x88CE, 0xF1CE, 0x88CF, 0xD159, 0x88D0, 0xD15A, 0x88D1, 0xD15B, 0x88D2, 0xD9F6, 0x88D3, 0xD15C, 0x88D4, 0xD2E1, 0x88D5, 0xD4A3, 0x88D6, 0xD15D, 0x88D7, 0xD15E, 0x88D8, 0xF4C3, 0x88D9, 0xC8B9, 0x88DA, 0xD15F, 0x88DB, 0xD160, 0x88DC, 0xD161, 0x88DD, 0xD162, 0x88DE, 0xD163, 0x88DF, 0xF4C4, 0x88E0, 0xD164, 0x88E1, 0xD165, 0x88E2, 0xF1CD, 0x88E3, 0xF1CF, 0x88E4, 0xBFE3, 0x88E5, 0xF1D0, 0x88E6, 0xD166, 0x88E7, 0xD167, 0x88E8, 0xF1D4, 0x88E9, 0xD168, 0x88EA, 0xD169, 0x88EB, 0xD16A, 0x88EC, 0xD16B, 0x88ED, 0xD16C, 0x88EE, 0xD16D, 0x88EF, 0xD16E, 0x88F0, 0xF1D6, 0x88F1, 0xF1D1, 0x88F2, 0xD16F, 0x88F3, 0xC9D1, 0x88F4, 0xC5E1, 0x88F5, 0xD170, 0x88F6, 0xD171, 0x88F7, 0xD172, 0x88F8, 0xC2E3, 0x88F9, 0xB9FC, 0x88FA, 0xD173, 0x88FB, 0xD174, 0x88FC, 0xF1D3, 0x88FD, 0xD175, 0x88FE, 0xF1D5, 0x88FF, 0xD176, 0x8900, 0xD177, 0x8901, 0xD178, 0x8902, 0xB9D3, 0x8903, 0xD179, 0x8904, 0xD17A, 0x8905, 0xD17B, 0x8906, 0xD17C, 0x8907, 0xD17D, 0x8908, 0xD17E, 0x8909, 0xD180, 0x890A, 0xF1DB, 0x890B, 0xD181, 0x890C, 0xD182, 0x890D, 0xD183, 0x890E, 0xD184, 0x890F, 0xD185, 0x8910, 0xBAD6, 0x8911, 0xD186, 0x8912, 0xB0FD, 0x8913, 0xF1D9, 0x8914, 0xD187, 0x8915, 0xD188, 0x8916, 0xD189, 0x8917, 0xD18A, 0x8918, 0xD18B, 0x8919, 0xF1D8, 0x891A, 0xF1D2, 0x891B, 0xF1DA, 0x891C, 0xD18C, 0x891D, 0xD18D, 0x891E, 0xD18E, 0x891F, 0xD18F, 0x8920, 0xD190, 0x8921, 0xF1D7, 0x8922, 0xD191, 0x8923, 0xD192, 0x8924, 0xD193, 0x8925, 0xC8EC, 0x8926, 0xD194, 0x8927, 0xD195, 0x8928, 0xD196, 0x8929, 0xD197, 0x892A, 0xCDCA, 0x892B, 0xF1DD, 0x892C, 0xD198, 0x892D, 0xD199, 0x892E, 0xD19A, 0x892F, 0xD19B, 0x8930, 0xE5BD, 0x8931, 0xD19C, 0x8932, 0xD19D, 0x8933, 0xD19E, 0x8934, 0xF1DC, 0x8935, 0xD19F, 0x8936, 0xF1DE, 0x8937, 0xD1A0, 0x8938, 0xD240, 0x8939, 0xD241, 0x893A, 0xD242, 0x893B, 0xD243, 0x893C, 0xD244, 0x893D, 0xD245, 0x893E, 0xD246, 0x893F, 0xD247, 0x8940, 0xD248, 0x8941, 0xF1DF, 0x8942, 0xD249, 0x8943, 0xD24A, 0x8944, 0xCFE5, 0x8945, 0xD24B, 0x8946, 0xD24C, 0x8947, 0xD24D, 0x8948, 0xD24E, 0x8949, 0xD24F, 0x894A, 0xD250, 0x894B, 0xD251, 0x894C, 0xD252, 0x894D, 0xD253, 0x894E, 0xD254, 0x894F, 0xD255, 0x8950, 0xD256, 0x8951, 0xD257, 0x8952, 0xD258, 0x8953, 0xD259, 0x8954, 0xD25A, 0x8955, 0xD25B, 0x8956, 0xD25C, 0x8957, 0xD25D, 0x8958, 0xD25E, 0x8959, 0xD25F, 0x895A, 0xD260, 0x895B, 0xD261, 0x895C, 0xD262, 0x895D, 0xD263, 0x895E, 0xF4C5, 0x895F, 0xBDF3, 0x8960, 0xD264, 0x8961, 0xD265, 0x8962, 0xD266, 0x8963, 0xD267, 0x8964, 0xD268, 0x8965, 0xD269, 0x8966, 0xF1E0, 0x8967, 0xD26A, 0x8968, 0xD26B, 0x8969, 0xD26C, 0x896A, 0xD26D, 0x896B, 0xD26E, 0x896C, 0xD26F, 0x896D, 0xD270, 0x896E, 0xD271, 0x896F, 0xD272, 0x8970, 0xD273, 0x8971, 0xD274, 0x8972, 0xD275, 0x8973, 0xD276, 0x8974, 0xD277, 0x8975, 0xD278, 0x8976, 0xD279, 0x8977, 0xD27A, 0x8978, 0xD27B, 0x8979, 0xD27C, 0x897A, 0xD27D, 0x897B, 0xF1E1, 0x897C, 0xD27E, 0x897D, 0xD280, 0x897E, 0xD281, 0x897F, 0xCEF7, 0x8980, 0xD282, 0x8981, 0xD2AA, 0x8982, 0xD283, 0x8983, 0xF1FB, 0x8984, 0xD284, 0x8985, 0xD285, 0x8986, 0xB8B2, 0x8987, 0xD286, 0x8988, 0xD287, 0x8989, 0xD288, 0x898A, 0xD289, 0x898B, 0xD28A, 0x898C, 0xD28B, 0x898D, 0xD28C, 0x898E, 0xD28D, 0x898F, 0xD28E, 0x8990, 0xD28F, 0x8991, 0xD290, 0x8992, 0xD291, 0x8993, 0xD292, 0x8994, 0xD293, 0x8995, 0xD294, 0x8996, 0xD295, 0x8997, 0xD296, 0x8998, 0xD297, 0x8999, 0xD298, 0x899A, 0xD299, 0x899B, 0xD29A, 0x899C, 0xD29B, 0x899D, 0xD29C, 0x899E, 0xD29D, 0x899F, 0xD29E, 0x89A0, 0xD29F, 0x89A1, 0xD2A0, 0x89A2, 0xD340, 0x89A3, 0xD341, 0x89A4, 0xD342, 0x89A5, 0xD343, 0x89A6, 0xD344, 0x89A7, 0xD345, 0x89A8, 0xD346, 0x89A9, 0xD347, 0x89AA, 0xD348, 0x89AB, 0xD349, 0x89AC, 0xD34A, 0x89AD, 0xD34B, 0x89AE, 0xD34C, 0x89AF, 0xD34D, 0x89B0, 0xD34E, 0x89B1, 0xD34F, 0x89B2, 0xD350, 0x89B3, 0xD351, 0x89B4, 0xD352, 0x89B5, 0xD353, 0x89B6, 0xD354, 0x89B7, 0xD355, 0x89B8, 0xD356, 0x89B9, 0xD357, 0x89BA, 0xD358, 0x89BB, 0xD359, 0x89BC, 0xD35A, 0x89BD, 0xD35B, 0x89BE, 0xD35C, 0x89BF, 0xD35D, 0x89C0, 0xD35E, 0x89C1, 0xBCFB, 0x89C2, 0xB9DB, 0x89C3, 0xD35F, 0x89C4, 0xB9E6, 0x89C5, 0xC3D9, 0x89C6, 0xCAD3, 0x89C7, 0xEAE8, 0x89C8, 0xC0C0, 0x89C9, 0xBEF5, 0x89CA, 0xEAE9, 0x89CB, 0xEAEA, 0x89CC, 0xEAEB, 0x89CD, 0xD360, 0x89CE, 0xEAEC, 0x89CF, 0xEAED, 0x89D0, 0xEAEE, 0x89D1, 0xEAEF, 0x89D2, 0xBDC7, 0x89D3, 0xD361, 0x89D4, 0xD362, 0x89D5, 0xD363, 0x89D6, 0xF5FB, 0x89D7, 0xD364, 0x89D8, 0xD365, 0x89D9, 0xD366, 0x89DA, 0xF5FD, 0x89DB, 0xD367, 0x89DC, 0xF5FE, 0x89DD, 0xD368, 0x89DE, 0xF5FC, 0x89DF, 0xD369, 0x89E0, 0xD36A, 0x89E1, 0xD36B, 0x89E2, 0xD36C, 0x89E3, 0xBDE2, 0x89E4, 0xD36D, 0x89E5, 0xF6A1, 0x89E6, 0xB4A5, 0x89E7, 0xD36E, 0x89E8, 0xD36F, 0x89E9, 0xD370, 0x89EA, 0xD371, 0x89EB, 0xF6A2, 0x89EC, 0xD372, 0x89ED, 0xD373, 0x89EE, 0xD374, 0x89EF, 0xF6A3, 0x89F0, 0xD375, 0x89F1, 0xD376, 0x89F2, 0xD377, 0x89F3, 0xECB2, 0x89F4, 0xD378, 0x89F5, 0xD379, 0x89F6, 0xD37A, 0x89F7, 0xD37B, 0x89F8, 0xD37C, 0x89F9, 0xD37D, 0x89FA, 0xD37E, 0x89FB, 0xD380, 0x89FC, 0xD381, 0x89FD, 0xD382, 0x89FE, 0xD383, 0x89FF, 0xD384, 0x8A00, 0xD1D4, 0x8A01, 0xD385, 0x8A02, 0xD386, 0x8A03, 0xD387, 0x8A04, 0xD388, 0x8A05, 0xD389, 0x8A06, 0xD38A, 0x8A07, 0xD9EA, 0x8A08, 0xD38B, 0x8A09, 0xD38C, 0x8A0A, 0xD38D, 0x8A0B, 0xD38E, 0x8A0C, 0xD38F, 0x8A0D, 0xD390, 0x8A0E, 0xD391, 0x8A0F, 0xD392, 0x8A10, 0xD393, 0x8A11, 0xD394, 0x8A12, 0xD395, 0x8A13, 0xD396, 0x8A14, 0xD397, 0x8A15, 0xD398, 0x8A16, 0xD399, 0x8A17, 0xD39A, 0x8A18, 0xD39B, 0x8A19, 0xD39C, 0x8A1A, 0xD39D, 0x8A1B, 0xD39E, 0x8A1C, 0xD39F, 0x8A1D, 0xD3A0, 0x8A1E, 0xD440, 0x8A1F, 0xD441, 0x8A20, 0xD442, 0x8A21, 0xD443, 0x8A22, 0xD444, 0x8A23, 0xD445, 0x8A24, 0xD446, 0x8A25, 0xD447, 0x8A26, 0xD448, 0x8A27, 0xD449, 0x8A28, 0xD44A, 0x8A29, 0xD44B, 0x8A2A, 0xD44C, 0x8A2B, 0xD44D, 0x8A2C, 0xD44E, 0x8A2D, 0xD44F, 0x8A2E, 0xD450, 0x8A2F, 0xD451, 0x8A30, 0xD452, 0x8A31, 0xD453, 0x8A32, 0xD454, 0x8A33, 0xD455, 0x8A34, 0xD456, 0x8A35, 0xD457, 0x8A36, 0xD458, 0x8A37, 0xD459, 0x8A38, 0xD45A, 0x8A39, 0xD45B, 0x8A3A, 0xD45C, 0x8A3B, 0xD45D, 0x8A3C, 0xD45E, 0x8A3D, 0xD45F, 0x8A3E, 0xF6A4, 0x8A3F, 0xD460, 0x8A40, 0xD461, 0x8A41, 0xD462, 0x8A42, 0xD463, 0x8A43, 0xD464, 0x8A44, 0xD465, 0x8A45, 0xD466, 0x8A46, 0xD467, 0x8A47, 0xD468, 0x8A48, 0xEEBA, 0x8A49, 0xD469, 0x8A4A, 0xD46A, 0x8A4B, 0xD46B, 0x8A4C, 0xD46C, 0x8A4D, 0xD46D, 0x8A4E, 0xD46E, 0x8A4F, 0xD46F, 0x8A50, 0xD470, 0x8A51, 0xD471, 0x8A52, 0xD472, 0x8A53, 0xD473, 0x8A54, 0xD474, 0x8A55, 0xD475, 0x8A56, 0xD476, 0x8A57, 0xD477, 0x8A58, 0xD478, 0x8A59, 0xD479, 0x8A5A, 0xD47A, 0x8A5B, 0xD47B, 0x8A5C, 0xD47C, 0x8A5D, 0xD47D, 0x8A5E, 0xD47E, 0x8A5F, 0xD480, 0x8A60, 0xD481, 0x8A61, 0xD482, 0x8A62, 0xD483, 0x8A63, 0xD484, 0x8A64, 0xD485, 0x8A65, 0xD486, 0x8A66, 0xD487, 0x8A67, 0xD488, 0x8A68, 0xD489, 0x8A69, 0xD48A, 0x8A6A, 0xD48B, 0x8A6B, 0xD48C, 0x8A6C, 0xD48D, 0x8A6D, 0xD48E, 0x8A6E, 0xD48F, 0x8A6F, 0xD490, 0x8A70, 0xD491, 0x8A71, 0xD492, 0x8A72, 0xD493, 0x8A73, 0xD494, 0x8A74, 0xD495, 0x8A75, 0xD496, 0x8A76, 0xD497, 0x8A77, 0xD498, 0x8A78, 0xD499, 0x8A79, 0xD5B2, 0x8A7A, 0xD49A, 0x8A7B, 0xD49B, 0x8A7C, 0xD49C, 0x8A7D, 0xD49D, 0x8A7E, 0xD49E, 0x8A7F, 0xD49F, 0x8A80, 0xD4A0, 0x8A81, 0xD540, 0x8A82, 0xD541, 0x8A83, 0xD542, 0x8A84, 0xD543, 0x8A85, 0xD544, 0x8A86, 0xD545, 0x8A87, 0xD546, 0x8A88, 0xD547, 0x8A89, 0xD3FE, 0x8A8A, 0xCCDC, 0x8A8B, 0xD548, 0x8A8C, 0xD549, 0x8A8D, 0xD54A, 0x8A8E, 0xD54B, 0x8A8F, 0xD54C, 0x8A90, 0xD54D, 0x8A91, 0xD54E, 0x8A92, 0xD54F, 0x8A93, 0xCAC4, 0x8A94, 0xD550, 0x8A95, 0xD551, 0x8A96, 0xD552, 0x8A97, 0xD553, 0x8A98, 0xD554, 0x8A99, 0xD555, 0x8A9A, 0xD556, 0x8A9B, 0xD557, 0x8A9C, 0xD558, 0x8A9D, 0xD559, 0x8A9E, 0xD55A, 0x8A9F, 0xD55B, 0x8AA0, 0xD55C, 0x8AA1, 0xD55D, 0x8AA2, 0xD55E, 0x8AA3, 0xD55F, 0x8AA4, 0xD560, 0x8AA5, 0xD561, 0x8AA6, 0xD562, 0x8AA7, 0xD563, 0x8AA8, 0xD564, 0x8AA9, 0xD565, 0x8AAA, 0xD566, 0x8AAB, 0xD567, 0x8AAC, 0xD568, 0x8AAD, 0xD569, 0x8AAE, 0xD56A, 0x8AAF, 0xD56B, 0x8AB0, 0xD56C, 0x8AB1, 0xD56D, 0x8AB2, 0xD56E, 0x8AB3, 0xD56F, 0x8AB4, 0xD570, 0x8AB5, 0xD571, 0x8AB6, 0xD572, 0x8AB7, 0xD573, 0x8AB8, 0xD574, 0x8AB9, 0xD575, 0x8ABA, 0xD576, 0x8ABB, 0xD577, 0x8ABC, 0xD578, 0x8ABD, 0xD579, 0x8ABE, 0xD57A, 0x8ABF, 0xD57B, 0x8AC0, 0xD57C, 0x8AC1, 0xD57D, 0x8AC2, 0xD57E, 0x8AC3, 0xD580, 0x8AC4, 0xD581, 0x8AC5, 0xD582, 0x8AC6, 0xD583, 0x8AC7, 0xD584, 0x8AC8, 0xD585, 0x8AC9, 0xD586, 0x8ACA, 0xD587, 0x8ACB, 0xD588, 0x8ACC, 0xD589, 0x8ACD, 0xD58A, 0x8ACE, 0xD58B, 0x8ACF, 0xD58C, 0x8AD0, 0xD58D, 0x8AD1, 0xD58E, 0x8AD2, 0xD58F, 0x8AD3, 0xD590, 0x8AD4, 0xD591, 0x8AD5, 0xD592, 0x8AD6, 0xD593, 0x8AD7, 0xD594, 0x8AD8, 0xD595, 0x8AD9, 0xD596, 0x8ADA, 0xD597, 0x8ADB, 0xD598, 0x8ADC, 0xD599, 0x8ADD, 0xD59A, 0x8ADE, 0xD59B, 0x8ADF, 0xD59C, 0x8AE0, 0xD59D, 0x8AE1, 0xD59E, 0x8AE2, 0xD59F, 0x8AE3, 0xD5A0, 0x8AE4, 0xD640, 0x8AE5, 0xD641, 0x8AE6, 0xD642, 0x8AE7, 0xD643, 0x8AE8, 0xD644, 0x8AE9, 0xD645, 0x8AEA, 0xD646, 0x8AEB, 0xD647, 0x8AEC, 0xD648, 0x8AED, 0xD649, 0x8AEE, 0xD64A, 0x8AEF, 0xD64B, 0x8AF0, 0xD64C, 0x8AF1, 0xD64D, 0x8AF2, 0xD64E, 0x8AF3, 0xD64F, 0x8AF4, 0xD650, 0x8AF5, 0xD651, 0x8AF6, 0xD652, 0x8AF7, 0xD653, 0x8AF8, 0xD654, 0x8AF9, 0xD655, 0x8AFA, 0xD656, 0x8AFB, 0xD657, 0x8AFC, 0xD658, 0x8AFD, 0xD659, 0x8AFE, 0xD65A, 0x8AFF, 0xD65B, 0x8B00, 0xD65C, 0x8B01, 0xD65D, 0x8B02, 0xD65E, 0x8B03, 0xD65F, 0x8B04, 0xD660, 0x8B05, 0xD661, 0x8B06, 0xD662, 0x8B07, 0xE5C0, 0x8B08, 0xD663, 0x8B09, 0xD664, 0x8B0A, 0xD665, 0x8B0B, 0xD666, 0x8B0C, 0xD667, 0x8B0D, 0xD668, 0x8B0E, 0xD669, 0x8B0F, 0xD66A, 0x8B10, 0xD66B, 0x8B11, 0xD66C, 0x8B12, 0xD66D, 0x8B13, 0xD66E, 0x8B14, 0xD66F, 0x8B15, 0xD670, 0x8B16, 0xD671, 0x8B17, 0xD672, 0x8B18, 0xD673, 0x8B19, 0xD674, 0x8B1A, 0xD675, 0x8B1B, 0xD676, 0x8B1C, 0xD677, 0x8B1D, 0xD678, 0x8B1E, 0xD679, 0x8B1F, 0xD67A, 0x8B20, 0xD67B, 0x8B21, 0xD67C, 0x8B22, 0xD67D, 0x8B23, 0xD67E, 0x8B24, 0xD680, 0x8B25, 0xD681, 0x8B26, 0xF6A5, 0x8B27, 0xD682, 0x8B28, 0xD683, 0x8B29, 0xD684, 0x8B2A, 0xD685, 0x8B2B, 0xD686, 0x8B2C, 0xD687, 0x8B2D, 0xD688, 0x8B2E, 0xD689, 0x8B2F, 0xD68A, 0x8B30, 0xD68B, 0x8B31, 0xD68C, 0x8B32, 0xD68D, 0x8B33, 0xD68E, 0x8B34, 0xD68F, 0x8B35, 0xD690, 0x8B36, 0xD691, 0x8B37, 0xD692, 0x8B38, 0xD693, 0x8B39, 0xD694, 0x8B3A, 0xD695, 0x8B3B, 0xD696, 0x8B3C, 0xD697, 0x8B3D, 0xD698, 0x8B3E, 0xD699, 0x8B3F, 0xD69A, 0x8B40, 0xD69B, 0x8B41, 0xD69C, 0x8B42, 0xD69D, 0x8B43, 0xD69E, 0x8B44, 0xD69F, 0x8B45, 0xD6A0, 0x8B46, 0xD740, 0x8B47, 0xD741, 0x8B48, 0xD742, 0x8B49, 0xD743, 0x8B4A, 0xD744, 0x8B4B, 0xD745, 0x8B4C, 0xD746, 0x8B4D, 0xD747, 0x8B4E, 0xD748, 0x8B4F, 0xD749, 0x8B50, 0xD74A, 0x8B51, 0xD74B, 0x8B52, 0xD74C, 0x8B53, 0xD74D, 0x8B54, 0xD74E, 0x8B55, 0xD74F, 0x8B56, 0xD750, 0x8B57, 0xD751, 0x8B58, 0xD752, 0x8B59, 0xD753, 0x8B5A, 0xD754, 0x8B5B, 0xD755, 0x8B5C, 0xD756, 0x8B5D, 0xD757, 0x8B5E, 0xD758, 0x8B5F, 0xD759, 0x8B60, 0xD75A, 0x8B61, 0xD75B, 0x8B62, 0xD75C, 0x8B63, 0xD75D, 0x8B64, 0xD75E, 0x8B65, 0xD75F, 0x8B66, 0xBEAF, 0x8B67, 0xD760, 0x8B68, 0xD761, 0x8B69, 0xD762, 0x8B6A, 0xD763, 0x8B6B, 0xD764, 0x8B6C, 0xC6A9, 0x8B6D, 0xD765, 0x8B6E, 0xD766, 0x8B6F, 0xD767, 0x8B70, 0xD768, 0x8B71, 0xD769, 0x8B72, 0xD76A, 0x8B73, 0xD76B, 0x8B74, 0xD76C, 0x8B75, 0xD76D, 0x8B76, 0xD76E, 0x8B77, 0xD76F, 0x8B78, 0xD770, 0x8B79, 0xD771, 0x8B7A, 0xD772, 0x8B7B, 0xD773, 0x8B7C, 0xD774, 0x8B7D, 0xD775, 0x8B7E, 0xD776, 0x8B7F, 0xD777, 0x8B80, 0xD778, 0x8B81, 0xD779, 0x8B82, 0xD77A, 0x8B83, 0xD77B, 0x8B84, 0xD77C, 0x8B85, 0xD77D, 0x8B86, 0xD77E, 0x8B87, 0xD780, 0x8B88, 0xD781, 0x8B89, 0xD782, 0x8B8A, 0xD783, 0x8B8B, 0xD784, 0x8B8C, 0xD785, 0x8B8D, 0xD786, 0x8B8E, 0xD787, 0x8B8F, 0xD788, 0x8B90, 0xD789, 0x8B91, 0xD78A, 0x8B92, 0xD78B, 0x8B93, 0xD78C, 0x8B94, 0xD78D, 0x8B95, 0xD78E, 0x8B96, 0xD78F, 0x8B97, 0xD790, 0x8B98, 0xD791, 0x8B99, 0xD792, 0x8B9A, 0xD793, 0x8B9B, 0xD794, 0x8B9C, 0xD795, 0x8B9D, 0xD796, 0x8B9E, 0xD797, 0x8B9F, 0xD798, 0x8BA0, 0xDAA5, 0x8BA1, 0xBCC6, 0x8BA2, 0xB6A9, 0x8BA3, 0xB8BC, 0x8BA4, 0xC8CF, 0x8BA5, 0xBCA5, 0x8BA6, 0xDAA6, 0x8BA7, 0xDAA7, 0x8BA8, 0xCCD6, 0x8BA9, 0xC8C3, 0x8BAA, 0xDAA8, 0x8BAB, 0xC6FD, 0x8BAC, 0xD799, 0x8BAD, 0xD1B5, 0x8BAE, 0xD2E9, 0x8BAF, 0xD1B6, 0x8BB0, 0xBCC7, 0x8BB1, 0xD79A, 0x8BB2, 0xBDB2, 0x8BB3, 0xBBE4, 0x8BB4, 0xDAA9, 0x8BB5, 0xDAAA, 0x8BB6, 0xD1C8, 0x8BB7, 0xDAAB, 0x8BB8, 0xD0ED, 0x8BB9, 0xB6EF, 0x8BBA, 0xC2DB, 0x8BBB, 0xD79B, 0x8BBC, 0xCBCF, 0x8BBD, 0xB7ED, 0x8BBE, 0xC9E8, 0x8BBF, 0xB7C3, 0x8BC0, 0xBEF7, 0x8BC1, 0xD6A4, 0x8BC2, 0xDAAC, 0x8BC3, 0xDAAD, 0x8BC4, 0xC6C0, 0x8BC5, 0xD7E7, 0x8BC6, 0xCAB6, 0x8BC7, 0xD79C, 0x8BC8, 0xD5A9, 0x8BC9, 0xCBDF, 0x8BCA, 0xD5EF, 0x8BCB, 0xDAAE, 0x8BCC, 0xD6DF, 0x8BCD, 0xB4CA, 0x8BCE, 0xDAB0, 0x8BCF, 0xDAAF, 0x8BD0, 0xD79D, 0x8BD1, 0xD2EB, 0x8BD2, 0xDAB1, 0x8BD3, 0xDAB2, 0x8BD4, 0xDAB3, 0x8BD5, 0xCAD4, 0x8BD6, 0xDAB4, 0x8BD7, 0xCAAB, 0x8BD8, 0xDAB5, 0x8BD9, 0xDAB6, 0x8BDA, 0xB3CF, 0x8BDB, 0xD6EF, 0x8BDC, 0xDAB7, 0x8BDD, 0xBBB0, 0x8BDE, 0xB5AE, 0x8BDF, 0xDAB8, 0x8BE0, 0xDAB9, 0x8BE1, 0xB9EE, 0x8BE2, 0xD1AF, 0x8BE3, 0xD2E8, 0x8BE4, 0xDABA, 0x8BE5, 0xB8C3, 0x8BE6, 0xCFEA, 0x8BE7, 0xB2EF, 0x8BE8, 0xDABB, 0x8BE9, 0xDABC, 0x8BEA, 0xD79E, 0x8BEB, 0xBDEB, 0x8BEC, 0xCEDC, 0x8BED, 0xD3EF, 0x8BEE, 0xDABD, 0x8BEF, 0xCEF3, 0x8BF0, 0xDABE, 0x8BF1, 0xD3D5, 0x8BF2, 0xBBE5, 0x8BF3, 0xDABF, 0x8BF4, 0xCBB5, 0x8BF5, 0xCBD0, 0x8BF6, 0xDAC0, 0x8BF7, 0xC7EB, 0x8BF8, 0xD6EE, 0x8BF9, 0xDAC1, 0x8BFA, 0xC5B5, 0x8BFB, 0xB6C1, 0x8BFC, 0xDAC2, 0x8BFD, 0xB7CC, 0x8BFE, 0xBFCE, 0x8BFF, 0xDAC3, 0x8C00, 0xDAC4, 0x8C01, 0xCBAD, 0x8C02, 0xDAC5, 0x8C03, 0xB5F7, 0x8C04, 0xDAC6, 0x8C05, 0xC1C2, 0x8C06, 0xD7BB, 0x8C07, 0xDAC7, 0x8C08, 0xCCB8, 0x8C09, 0xD79F, 0x8C0A, 0xD2EA, 0x8C0B, 0xC4B1, 0x8C0C, 0xDAC8, 0x8C0D, 0xB5FD, 0x8C0E, 0xBBD1, 0x8C0F, 0xDAC9, 0x8C10, 0xD0B3, 0x8C11, 0xDACA, 0x8C12, 0xDACB, 0x8C13, 0xCEBD, 0x8C14, 0xDACC, 0x8C15, 0xDACD, 0x8C16, 0xDACE, 0x8C17, 0xB2F7, 0x8C18, 0xDAD1, 0x8C19, 0xDACF, 0x8C1A, 0xD1E8, 0x8C1B, 0xDAD0, 0x8C1C, 0xC3D5, 0x8C1D, 0xDAD2, 0x8C1E, 0xD7A0, 0x8C1F, 0xDAD3, 0x8C20, 0xDAD4, 0x8C21, 0xDAD5, 0x8C22, 0xD0BB, 0x8C23, 0xD2A5, 0x8C24, 0xB0F9, 0x8C25, 0xDAD6, 0x8C26, 0xC7AB, 0x8C27, 0xDAD7, 0x8C28, 0xBDF7, 0x8C29, 0xC3A1, 0x8C2A, 0xDAD8, 0x8C2B, 0xDAD9, 0x8C2C, 0xC3FD, 0x8C2D, 0xCCB7, 0x8C2E, 0xDADA, 0x8C2F, 0xDADB, 0x8C30, 0xC0BE, 0x8C31, 0xC6D7, 0x8C32, 0xDADC, 0x8C33, 0xDADD, 0x8C34, 0xC7B4, 0x8C35, 0xDADE, 0x8C36, 0xDADF, 0x8C37, 0xB9C8, 0x8C38, 0xD840, 0x8C39, 0xD841, 0x8C3A, 0xD842, 0x8C3B, 0xD843, 0x8C3C, 0xD844, 0x8C3D, 0xD845, 0x8C3E, 0xD846, 0x8C3F, 0xD847, 0x8C40, 0xD848, 0x8C41, 0xBBED, 0x8C42, 0xD849, 0x8C43, 0xD84A, 0x8C44, 0xD84B, 0x8C45, 0xD84C, 0x8C46, 0xB6B9, 0x8C47, 0xF4F8, 0x8C48, 0xD84D, 0x8C49, 0xF4F9, 0x8C4A, 0xD84E, 0x8C4B, 0xD84F, 0x8C4C, 0xCDE3, 0x8C4D, 0xD850, 0x8C4E, 0xD851, 0x8C4F, 0xD852, 0x8C50, 0xD853, 0x8C51, 0xD854, 0x8C52, 0xD855, 0x8C53, 0xD856, 0x8C54, 0xD857, 0x8C55, 0xF5B9, 0x8C56, 0xD858, 0x8C57, 0xD859, 0x8C58, 0xD85A, 0x8C59, 0xD85B, 0x8C5A, 0xEBE0, 0x8C5B, 0xD85C, 0x8C5C, 0xD85D, 0x8C5D, 0xD85E, 0x8C5E, 0xD85F, 0x8C5F, 0xD860, 0x8C60, 0xD861, 0x8C61, 0xCFF3, 0x8C62, 0xBBBF, 0x8C63, 0xD862, 0x8C64, 0xD863, 0x8C65, 0xD864, 0x8C66, 0xD865, 0x8C67, 0xD866, 0x8C68, 0xD867, 0x8C69, 0xD868, 0x8C6A, 0xBAC0, 0x8C6B, 0xD4A5, 0x8C6C, 0xD869, 0x8C6D, 0xD86A, 0x8C6E, 0xD86B, 0x8C6F, 0xD86C, 0x8C70, 0xD86D, 0x8C71, 0xD86E, 0x8C72, 0xD86F, 0x8C73, 0xE1D9, 0x8C74, 0xD870, 0x8C75, 0xD871, 0x8C76, 0xD872, 0x8C77, 0xD873, 0x8C78, 0xF5F4, 0x8C79, 0xB1AA, 0x8C7A, 0xB2F2, 0x8C7B, 0xD874, 0x8C7C, 0xD875, 0x8C7D, 0xD876, 0x8C7E, 0xD877, 0x8C7F, 0xD878, 0x8C80, 0xD879, 0x8C81, 0xD87A, 0x8C82, 0xF5F5, 0x8C83, 0xD87B, 0x8C84, 0xD87C, 0x8C85, 0xF5F7, 0x8C86, 0xD87D, 0x8C87, 0xD87E, 0x8C88, 0xD880, 0x8C89, 0xBAD1, 0x8C8A, 0xF5F6, 0x8C8B, 0xD881, 0x8C8C, 0xC3B2, 0x8C8D, 0xD882, 0x8C8E, 0xD883, 0x8C8F, 0xD884, 0x8C90, 0xD885, 0x8C91, 0xD886, 0x8C92, 0xD887, 0x8C93, 0xD888, 0x8C94, 0xF5F9, 0x8C95, 0xD889, 0x8C96, 0xD88A, 0x8C97, 0xD88B, 0x8C98, 0xF5F8, 0x8C99, 0xD88C, 0x8C9A, 0xD88D, 0x8C9B, 0xD88E, 0x8C9C, 0xD88F, 0x8C9D, 0xD890, 0x8C9E, 0xD891, 0x8C9F, 0xD892, 0x8CA0, 0xD893, 0x8CA1, 0xD894, 0x8CA2, 0xD895, 0x8CA3, 0xD896, 0x8CA4, 0xD897, 0x8CA5, 0xD898, 0x8CA6, 0xD899, 0x8CA7, 0xD89A, 0x8CA8, 0xD89B, 0x8CA9, 0xD89C, 0x8CAA, 0xD89D, 0x8CAB, 0xD89E, 0x8CAC, 0xD89F, 0x8CAD, 0xD8A0, 0x8CAE, 0xD940, 0x8CAF, 0xD941, 0x8CB0, 0xD942, 0x8CB1, 0xD943, 0x8CB2, 0xD944, 0x8CB3, 0xD945, 0x8CB4, 0xD946, 0x8CB5, 0xD947, 0x8CB6, 0xD948, 0x8CB7, 0xD949, 0x8CB8, 0xD94A, 0x8CB9, 0xD94B, 0x8CBA, 0xD94C, 0x8CBB, 0xD94D, 0x8CBC, 0xD94E, 0x8CBD, 0xD94F, 0x8CBE, 0xD950, 0x8CBF, 0xD951, 0x8CC0, 0xD952, 0x8CC1, 0xD953, 0x8CC2, 0xD954, 0x8CC3, 0xD955, 0x8CC4, 0xD956, 0x8CC5, 0xD957, 0x8CC6, 0xD958, 0x8CC7, 0xD959, 0x8CC8, 0xD95A, 0x8CC9, 0xD95B, 0x8CCA, 0xD95C, 0x8CCB, 0xD95D, 0x8CCC, 0xD95E, 0x8CCD, 0xD95F, 0x8CCE, 0xD960, 0x8CCF, 0xD961, 0x8CD0, 0xD962, 0x8CD1, 0xD963, 0x8CD2, 0xD964, 0x8CD3, 0xD965, 0x8CD4, 0xD966, 0x8CD5, 0xD967, 0x8CD6, 0xD968, 0x8CD7, 0xD969, 0x8CD8, 0xD96A, 0x8CD9, 0xD96B, 0x8CDA, 0xD96C, 0x8CDB, 0xD96D, 0x8CDC, 0xD96E, 0x8CDD, 0xD96F, 0x8CDE, 0xD970, 0x8CDF, 0xD971, 0x8CE0, 0xD972, 0x8CE1, 0xD973, 0x8CE2, 0xD974, 0x8CE3, 0xD975, 0x8CE4, 0xD976, 0x8CE5, 0xD977, 0x8CE6, 0xD978, 0x8CE7, 0xD979, 0x8CE8, 0xD97A, 0x8CE9, 0xD97B, 0x8CEA, 0xD97C, 0x8CEB, 0xD97D, 0x8CEC, 0xD97E, 0x8CED, 0xD980, 0x8CEE, 0xD981, 0x8CEF, 0xD982, 0x8CF0, 0xD983, 0x8CF1, 0xD984, 0x8CF2, 0xD985, 0x8CF3, 0xD986, 0x8CF4, 0xD987, 0x8CF5, 0xD988, 0x8CF6, 0xD989, 0x8CF7, 0xD98A, 0x8CF8, 0xD98B, 0x8CF9, 0xD98C, 0x8CFA, 0xD98D, 0x8CFB, 0xD98E, 0x8CFC, 0xD98F, 0x8CFD, 0xD990, 0x8CFE, 0xD991, 0x8CFF, 0xD992, 0x8D00, 0xD993, 0x8D01, 0xD994, 0x8D02, 0xD995, 0x8D03, 0xD996, 0x8D04, 0xD997, 0x8D05, 0xD998, 0x8D06, 0xD999, 0x8D07, 0xD99A, 0x8D08, 0xD99B, 0x8D09, 0xD99C, 0x8D0A, 0xD99D, 0x8D0B, 0xD99E, 0x8D0C, 0xD99F, 0x8D0D, 0xD9A0, 0x8D0E, 0xDA40, 0x8D0F, 0xDA41, 0x8D10, 0xDA42, 0x8D11, 0xDA43, 0x8D12, 0xDA44, 0x8D13, 0xDA45, 0x8D14, 0xDA46, 0x8D15, 0xDA47, 0x8D16, 0xDA48, 0x8D17, 0xDA49, 0x8D18, 0xDA4A, 0x8D19, 0xDA4B, 0x8D1A, 0xDA4C, 0x8D1B, 0xDA4D, 0x8D1C, 0xDA4E, 0x8D1D, 0xB1B4, 0x8D1E, 0xD5EA, 0x8D1F, 0xB8BA, 0x8D20, 0xDA4F, 0x8D21, 0xB9B1, 0x8D22, 0xB2C6, 0x8D23, 0xD4F0, 0x8D24, 0xCFCD, 0x8D25, 0xB0DC, 0x8D26, 0xD5CB, 0x8D27, 0xBBF5, 0x8D28, 0xD6CA, 0x8D29, 0xB7B7, 0x8D2A, 0xCCB0, 0x8D2B, 0xC6B6, 0x8D2C, 0xB1E1, 0x8D2D, 0xB9BA, 0x8D2E, 0xD6FC, 0x8D2F, 0xB9E1, 0x8D30, 0xB7A1, 0x8D31, 0xBCFA, 0x8D32, 0xEADA, 0x8D33, 0xEADB, 0x8D34, 0xCCF9, 0x8D35, 0xB9F3, 0x8D36, 0xEADC, 0x8D37, 0xB4FB, 0x8D38, 0xC3B3, 0x8D39, 0xB7D1, 0x8D3A, 0xBAD8, 0x8D3B, 0xEADD, 0x8D3C, 0xD4F4, 0x8D3D, 0xEADE, 0x8D3E, 0xBCD6, 0x8D3F, 0xBBDF, 0x8D40, 0xEADF, 0x8D41, 0xC1DE, 0x8D42, 0xC2B8, 0x8D43, 0xD4DF, 0x8D44, 0xD7CA, 0x8D45, 0xEAE0, 0x8D46, 0xEAE1, 0x8D47, 0xEAE4, 0x8D48, 0xEAE2, 0x8D49, 0xEAE3, 0x8D4A, 0xC9DE, 0x8D4B, 0xB8B3, 0x8D4C, 0xB6C4, 0x8D4D, 0xEAE5, 0x8D4E, 0xCAEA, 0x8D4F, 0xC9CD, 0x8D50, 0xB4CD, 0x8D51, 0xDA50, 0x8D52, 0xDA51, 0x8D53, 0xE2D9, 0x8D54, 0xC5E2, 0x8D55, 0xEAE6, 0x8D56, 0xC0B5, 0x8D57, 0xDA52, 0x8D58, 0xD7B8, 0x8D59, 0xEAE7, 0x8D5A, 0xD7AC, 0x8D5B, 0xC8FC, 0x8D5C, 0xD8D3, 0x8D5D, 0xD8CD, 0x8D5E, 0xD4DE, 0x8D5F, 0xDA53, 0x8D60, 0xD4F9, 0x8D61, 0xC9C4, 0x8D62, 0xD3AE, 0x8D63, 0xB8D3, 0x8D64, 0xB3E0, 0x8D65, 0xDA54, 0x8D66, 0xC9E2, 0x8D67, 0xF4F6, 0x8D68, 0xDA55, 0x8D69, 0xDA56, 0x8D6A, 0xDA57, 0x8D6B, 0xBAD5, 0x8D6C, 0xDA58, 0x8D6D, 0xF4F7, 0x8D6E, 0xDA59, 0x8D6F, 0xDA5A, 0x8D70, 0xD7DF, 0x8D71, 0xDA5B, 0x8D72, 0xDA5C, 0x8D73, 0xF4F1, 0x8D74, 0xB8B0, 0x8D75, 0xD5D4, 0x8D76, 0xB8CF, 0x8D77, 0xC6F0, 0x8D78, 0xDA5D, 0x8D79, 0xDA5E, 0x8D7A, 0xDA5F, 0x8D7B, 0xDA60, 0x8D7C, 0xDA61, 0x8D7D, 0xDA62, 0x8D7E, 0xDA63, 0x8D7F, 0xDA64, 0x8D80, 0xDA65, 0x8D81, 0xB3C3, 0x8D82, 0xDA66, 0x8D83, 0xDA67, 0x8D84, 0xF4F2, 0x8D85, 0xB3AC, 0x8D86, 0xDA68, 0x8D87, 0xDA69, 0x8D88, 0xDA6A, 0x8D89, 0xDA6B, 0x8D8A, 0xD4BD, 0x8D8B, 0xC7F7, 0x8D8C, 0xDA6C, 0x8D8D, 0xDA6D, 0x8D8E, 0xDA6E, 0x8D8F, 0xDA6F, 0x8D90, 0xDA70, 0x8D91, 0xF4F4, 0x8D92, 0xDA71, 0x8D93, 0xDA72, 0x8D94, 0xF4F3, 0x8D95, 0xDA73, 0x8D96, 0xDA74, 0x8D97, 0xDA75, 0x8D98, 0xDA76, 0x8D99, 0xDA77, 0x8D9A, 0xDA78, 0x8D9B, 0xDA79, 0x8D9C, 0xDA7A, 0x8D9D, 0xDA7B, 0x8D9E, 0xDA7C, 0x8D9F, 0xCCCB, 0x8DA0, 0xDA7D, 0x8DA1, 0xDA7E, 0x8DA2, 0xDA80, 0x8DA3, 0xC8A4, 0x8DA4, 0xDA81, 0x8DA5, 0xDA82, 0x8DA6, 0xDA83, 0x8DA7, 0xDA84, 0x8DA8, 0xDA85, 0x8DA9, 0xDA86, 0x8DAA, 0xDA87, 0x8DAB, 0xDA88, 0x8DAC, 0xDA89, 0x8DAD, 0xDA8A, 0x8DAE, 0xDA8B, 0x8DAF, 0xDA8C, 0x8DB0, 0xDA8D, 0x8DB1, 0xF4F5, 0x8DB2, 0xDA8E, 0x8DB3, 0xD7E3, 0x8DB4, 0xC5BF, 0x8DB5, 0xF5C0, 0x8DB6, 0xDA8F, 0x8DB7, 0xDA90, 0x8DB8, 0xF5BB, 0x8DB9, 0xDA91, 0x8DBA, 0xF5C3, 0x8DBB, 0xDA92, 0x8DBC, 0xF5C2, 0x8DBD, 0xDA93, 0x8DBE, 0xD6BA, 0x8DBF, 0xF5C1, 0x8DC0, 0xDA94, 0x8DC1, 0xDA95, 0x8DC2, 0xDA96, 0x8DC3, 0xD4BE, 0x8DC4, 0xF5C4, 0x8DC5, 0xDA97, 0x8DC6, 0xF5CC, 0x8DC7, 0xDA98, 0x8DC8, 0xDA99, 0x8DC9, 0xDA9A, 0x8DCA, 0xDA9B, 0x8DCB, 0xB0CF, 0x8DCC, 0xB5F8, 0x8DCD, 0xDA9C, 0x8DCE, 0xF5C9, 0x8DCF, 0xF5CA, 0x8DD0, 0xDA9D, 0x8DD1, 0xC5DC, 0x8DD2, 0xDA9E, 0x8DD3, 0xDA9F, 0x8DD4, 0xDAA0, 0x8DD5, 0xDB40, 0x8DD6, 0xF5C5, 0x8DD7, 0xF5C6, 0x8DD8, 0xDB41, 0x8DD9, 0xDB42, 0x8DDA, 0xF5C7, 0x8DDB, 0xF5CB, 0x8DDC, 0xDB43, 0x8DDD, 0xBEE0, 0x8DDE, 0xF5C8, 0x8DDF, 0xB8FA, 0x8DE0, 0xDB44, 0x8DE1, 0xDB45, 0x8DE2, 0xDB46, 0x8DE3, 0xF5D0, 0x8DE4, 0xF5D3, 0x8DE5, 0xDB47, 0x8DE6, 0xDB48, 0x8DE7, 0xDB49, 0x8DE8, 0xBFE7, 0x8DE9, 0xDB4A, 0x8DEA, 0xB9F2, 0x8DEB, 0xF5BC, 0x8DEC, 0xF5CD, 0x8DED, 0xDB4B, 0x8DEE, 0xDB4C, 0x8DEF, 0xC2B7, 0x8DF0, 0xDB4D, 0x8DF1, 0xDB4E, 0x8DF2, 0xDB4F, 0x8DF3, 0xCCF8, 0x8DF4, 0xDB50, 0x8DF5, 0xBCF9, 0x8DF6, 0xDB51, 0x8DF7, 0xF5CE, 0x8DF8, 0xF5CF, 0x8DF9, 0xF5D1, 0x8DFA, 0xB6E5, 0x8DFB, 0xF5D2, 0x8DFC, 0xDB52, 0x8DFD, 0xF5D5, 0x8DFE, 0xDB53, 0x8DFF, 0xDB54, 0x8E00, 0xDB55, 0x8E01, 0xDB56, 0x8E02, 0xDB57, 0x8E03, 0xDB58, 0x8E04, 0xDB59, 0x8E05, 0xF5BD, 0x8E06, 0xDB5A, 0x8E07, 0xDB5B, 0x8E08, 0xDB5C, 0x8E09, 0xF5D4, 0x8E0A, 0xD3BB, 0x8E0B, 0xDB5D, 0x8E0C, 0xB3EC, 0x8E0D, 0xDB5E, 0x8E0E, 0xDB5F, 0x8E0F, 0xCCA4, 0x8E10, 0xDB60, 0x8E11, 0xDB61, 0x8E12, 0xDB62, 0x8E13, 0xDB63, 0x8E14, 0xF5D6, 0x8E15, 0xDB64, 0x8E16, 0xDB65, 0x8E17, 0xDB66, 0x8E18, 0xDB67, 0x8E19, 0xDB68, 0x8E1A, 0xDB69, 0x8E1B, 0xDB6A, 0x8E1C, 0xDB6B, 0x8E1D, 0xF5D7, 0x8E1E, 0xBEE1, 0x8E1F, 0xF5D8, 0x8E20, 0xDB6C, 0x8E21, 0xDB6D, 0x8E22, 0xCCDF, 0x8E23, 0xF5DB, 0x8E24, 0xDB6E, 0x8E25, 0xDB6F, 0x8E26, 0xDB70, 0x8E27, 0xDB71, 0x8E28, 0xDB72, 0x8E29, 0xB2C8, 0x8E2A, 0xD7D9, 0x8E2B, 0xDB73, 0x8E2C, 0xF5D9, 0x8E2D, 0xDB74, 0x8E2E, 0xF5DA, 0x8E2F, 0xF5DC, 0x8E30, 0xDB75, 0x8E31, 0xF5E2, 0x8E32, 0xDB76, 0x8E33, 0xDB77, 0x8E34, 0xDB78, 0x8E35, 0xF5E0, 0x8E36, 0xDB79, 0x8E37, 0xDB7A, 0x8E38, 0xDB7B, 0x8E39, 0xF5DF, 0x8E3A, 0xF5DD, 0x8E3B, 0xDB7C, 0x8E3C, 0xDB7D, 0x8E3D, 0xF5E1, 0x8E3E, 0xDB7E, 0x8E3F, 0xDB80, 0x8E40, 0xF5DE, 0x8E41, 0xF5E4, 0x8E42, 0xF5E5, 0x8E43, 0xDB81, 0x8E44, 0xCCE3, 0x8E45, 0xDB82, 0x8E46, 0xDB83, 0x8E47, 0xE5BF, 0x8E48, 0xB5B8, 0x8E49, 0xF5E3, 0x8E4A, 0xF5E8, 0x8E4B, 0xCCA3, 0x8E4C, 0xDB84, 0x8E4D, 0xDB85, 0x8E4E, 0xDB86, 0x8E4F, 0xDB87, 0x8E50, 0xDB88, 0x8E51, 0xF5E6, 0x8E52, 0xF5E7, 0x8E53, 0xDB89, 0x8E54, 0xDB8A, 0x8E55, 0xDB8B, 0x8E56, 0xDB8C, 0x8E57, 0xDB8D, 0x8E58, 0xDB8E, 0x8E59, 0xF5BE, 0x8E5A, 0xDB8F, 0x8E5B, 0xDB90, 0x8E5C, 0xDB91, 0x8E5D, 0xDB92, 0x8E5E, 0xDB93, 0x8E5F, 0xDB94, 0x8E60, 0xDB95, 0x8E61, 0xDB96, 0x8E62, 0xDB97, 0x8E63, 0xDB98, 0x8E64, 0xDB99, 0x8E65, 0xDB9A, 0x8E66, 0xB1C4, 0x8E67, 0xDB9B, 0x8E68, 0xDB9C, 0x8E69, 0xF5BF, 0x8E6A, 0xDB9D, 0x8E6B, 0xDB9E, 0x8E6C, 0xB5C5, 0x8E6D, 0xB2E4, 0x8E6E, 0xDB9F, 0x8E6F, 0xF5EC, 0x8E70, 0xF5E9, 0x8E71, 0xDBA0, 0x8E72, 0xB6D7, 0x8E73, 0xDC40, 0x8E74, 0xF5ED, 0x8E75, 0xDC41, 0x8E76, 0xF5EA, 0x8E77, 0xDC42, 0x8E78, 0xDC43, 0x8E79, 0xDC44, 0x8E7A, 0xDC45, 0x8E7B, 0xDC46, 0x8E7C, 0xF5EB, 0x8E7D, 0xDC47, 0x8E7E, 0xDC48, 0x8E7F, 0xB4DA, 0x8E80, 0xDC49, 0x8E81, 0xD4EA, 0x8E82, 0xDC4A, 0x8E83, 0xDC4B, 0x8E84, 0xDC4C, 0x8E85, 0xF5EE, 0x8E86, 0xDC4D, 0x8E87, 0xB3F9, 0x8E88, 0xDC4E, 0x8E89, 0xDC4F, 0x8E8A, 0xDC50, 0x8E8B, 0xDC51, 0x8E8C, 0xDC52, 0x8E8D, 0xDC53, 0x8E8E, 0xDC54, 0x8E8F, 0xF5EF, 0x8E90, 0xF5F1, 0x8E91, 0xDC55, 0x8E92, 0xDC56, 0x8E93, 0xDC57, 0x8E94, 0xF5F0, 0x8E95, 0xDC58, 0x8E96, 0xDC59, 0x8E97, 0xDC5A, 0x8E98, 0xDC5B, 0x8E99, 0xDC5C, 0x8E9A, 0xDC5D, 0x8E9B, 0xDC5E, 0x8E9C, 0xF5F2, 0x8E9D, 0xDC5F, 0x8E9E, 0xF5F3, 0x8E9F, 0xDC60, 0x8EA0, 0xDC61, 0x8EA1, 0xDC62, 0x8EA2, 0xDC63, 0x8EA3, 0xDC64, 0x8EA4, 0xDC65, 0x8EA5, 0xDC66, 0x8EA6, 0xDC67, 0x8EA7, 0xDC68, 0x8EA8, 0xDC69, 0x8EA9, 0xDC6A, 0x8EAA, 0xDC6B, 0x8EAB, 0xC9ED, 0x8EAC, 0xB9AA, 0x8EAD, 0xDC6C, 0x8EAE, 0xDC6D, 0x8EAF, 0xC7FB, 0x8EB0, 0xDC6E, 0x8EB1, 0xDC6F, 0x8EB2, 0xB6E3, 0x8EB3, 0xDC70, 0x8EB4, 0xDC71, 0x8EB5, 0xDC72, 0x8EB6, 0xDC73, 0x8EB7, 0xDC74, 0x8EB8, 0xDC75, 0x8EB9, 0xDC76, 0x8EBA, 0xCCC9, 0x8EBB, 0xDC77, 0x8EBC, 0xDC78, 0x8EBD, 0xDC79, 0x8EBE, 0xDC7A, 0x8EBF, 0xDC7B, 0x8EC0, 0xDC7C, 0x8EC1, 0xDC7D, 0x8EC2, 0xDC7E, 0x8EC3, 0xDC80, 0x8EC4, 0xDC81, 0x8EC5, 0xDC82, 0x8EC6, 0xDC83, 0x8EC7, 0xDC84, 0x8EC8, 0xDC85, 0x8EC9, 0xDC86, 0x8ECA, 0xDC87, 0x8ECB, 0xDC88, 0x8ECC, 0xDC89, 0x8ECD, 0xDC8A, 0x8ECE, 0xEAA6, 0x8ECF, 0xDC8B, 0x8ED0, 0xDC8C, 0x8ED1, 0xDC8D, 0x8ED2, 0xDC8E, 0x8ED3, 0xDC8F, 0x8ED4, 0xDC90, 0x8ED5, 0xDC91, 0x8ED6, 0xDC92, 0x8ED7, 0xDC93, 0x8ED8, 0xDC94, 0x8ED9, 0xDC95, 0x8EDA, 0xDC96, 0x8EDB, 0xDC97, 0x8EDC, 0xDC98, 0x8EDD, 0xDC99, 0x8EDE, 0xDC9A, 0x8EDF, 0xDC9B, 0x8EE0, 0xDC9C, 0x8EE1, 0xDC9D, 0x8EE2, 0xDC9E, 0x8EE3, 0xDC9F, 0x8EE4, 0xDCA0, 0x8EE5, 0xDD40, 0x8EE6, 0xDD41, 0x8EE7, 0xDD42, 0x8EE8, 0xDD43, 0x8EE9, 0xDD44, 0x8EEA, 0xDD45, 0x8EEB, 0xDD46, 0x8EEC, 0xDD47, 0x8EED, 0xDD48, 0x8EEE, 0xDD49, 0x8EEF, 0xDD4A, 0x8EF0, 0xDD4B, 0x8EF1, 0xDD4C, 0x8EF2, 0xDD4D, 0x8EF3, 0xDD4E, 0x8EF4, 0xDD4F, 0x8EF5, 0xDD50, 0x8EF6, 0xDD51, 0x8EF7, 0xDD52, 0x8EF8, 0xDD53, 0x8EF9, 0xDD54, 0x8EFA, 0xDD55, 0x8EFB, 0xDD56, 0x8EFC, 0xDD57, 0x8EFD, 0xDD58, 0x8EFE, 0xDD59, 0x8EFF, 0xDD5A, 0x8F00, 0xDD5B, 0x8F01, 0xDD5C, 0x8F02, 0xDD5D, 0x8F03, 0xDD5E, 0x8F04, 0xDD5F, 0x8F05, 0xDD60, 0x8F06, 0xDD61, 0x8F07, 0xDD62, 0x8F08, 0xDD63, 0x8F09, 0xDD64, 0x8F0A, 0xDD65, 0x8F0B, 0xDD66, 0x8F0C, 0xDD67, 0x8F0D, 0xDD68, 0x8F0E, 0xDD69, 0x8F0F, 0xDD6A, 0x8F10, 0xDD6B, 0x8F11, 0xDD6C, 0x8F12, 0xDD6D, 0x8F13, 0xDD6E, 0x8F14, 0xDD6F, 0x8F15, 0xDD70, 0x8F16, 0xDD71, 0x8F17, 0xDD72, 0x8F18, 0xDD73, 0x8F19, 0xDD74, 0x8F1A, 0xDD75, 0x8F1B, 0xDD76, 0x8F1C, 0xDD77, 0x8F1D, 0xDD78, 0x8F1E, 0xDD79, 0x8F1F, 0xDD7A, 0x8F20, 0xDD7B, 0x8F21, 0xDD7C, 0x8F22, 0xDD7D, 0x8F23, 0xDD7E, 0x8F24, 0xDD80, 0x8F25, 0xDD81, 0x8F26, 0xDD82, 0x8F27, 0xDD83, 0x8F28, 0xDD84, 0x8F29, 0xDD85, 0x8F2A, 0xDD86, 0x8F2B, 0xDD87, 0x8F2C, 0xDD88, 0x8F2D, 0xDD89, 0x8F2E, 0xDD8A, 0x8F2F, 0xDD8B, 0x8F30, 0xDD8C, 0x8F31, 0xDD8D, 0x8F32, 0xDD8E, 0x8F33, 0xDD8F, 0x8F34, 0xDD90, 0x8F35, 0xDD91, 0x8F36, 0xDD92, 0x8F37, 0xDD93, 0x8F38, 0xDD94, 0x8F39, 0xDD95, 0x8F3A, 0xDD96, 0x8F3B, 0xDD97, 0x8F3C, 0xDD98, 0x8F3D, 0xDD99, 0x8F3E, 0xDD9A, 0x8F3F, 0xDD9B, 0x8F40, 0xDD9C, 0x8F41, 0xDD9D, 0x8F42, 0xDD9E, 0x8F43, 0xDD9F, 0x8F44, 0xDDA0, 0x8F45, 0xDE40, 0x8F46, 0xDE41, 0x8F47, 0xDE42, 0x8F48, 0xDE43, 0x8F49, 0xDE44, 0x8F4A, 0xDE45, 0x8F4B, 0xDE46, 0x8F4C, 0xDE47, 0x8F4D, 0xDE48, 0x8F4E, 0xDE49, 0x8F4F, 0xDE4A, 0x8F50, 0xDE4B, 0x8F51, 0xDE4C, 0x8F52, 0xDE4D, 0x8F53, 0xDE4E, 0x8F54, 0xDE4F, 0x8F55, 0xDE50, 0x8F56, 0xDE51, 0x8F57, 0xDE52, 0x8F58, 0xDE53, 0x8F59, 0xDE54, 0x8F5A, 0xDE55, 0x8F5B, 0xDE56, 0x8F5C, 0xDE57, 0x8F5D, 0xDE58, 0x8F5E, 0xDE59, 0x8F5F, 0xDE5A, 0x8F60, 0xDE5B, 0x8F61, 0xDE5C, 0x8F62, 0xDE5D, 0x8F63, 0xDE5E, 0x8F64, 0xDE5F, 0x8F65, 0xDE60, 0x8F66, 0xB3B5, 0x8F67, 0xD4FE, 0x8F68, 0xB9EC, 0x8F69, 0xD0F9, 0x8F6A, 0xDE61, 0x8F6B, 0xE9ED, 0x8F6C, 0xD7AA, 0x8F6D, 0xE9EE, 0x8F6E, 0xC2D6, 0x8F6F, 0xC8ED, 0x8F70, 0xBAE4, 0x8F71, 0xE9EF, 0x8F72, 0xE9F0, 0x8F73, 0xE9F1, 0x8F74, 0xD6E1, 0x8F75, 0xE9F2, 0x8F76, 0xE9F3, 0x8F77, 0xE9F5, 0x8F78, 0xE9F4, 0x8F79, 0xE9F6, 0x8F7A, 0xE9F7, 0x8F7B, 0xC7E1, 0x8F7C, 0xE9F8, 0x8F7D, 0xD4D8, 0x8F7E, 0xE9F9, 0x8F7F, 0xBDCE, 0x8F80, 0xDE62, 0x8F81, 0xE9FA, 0x8F82, 0xE9FB, 0x8F83, 0xBDCF, 0x8F84, 0xE9FC, 0x8F85, 0xB8A8, 0x8F86, 0xC1BE, 0x8F87, 0xE9FD, 0x8F88, 0xB1B2, 0x8F89, 0xBBD4, 0x8F8A, 0xB9F5, 0x8F8B, 0xE9FE, 0x8F8C, 0xDE63, 0x8F8D, 0xEAA1, 0x8F8E, 0xEAA2, 0x8F8F, 0xEAA3, 0x8F90, 0xB7F8, 0x8F91, 0xBCAD, 0x8F92, 0xDE64, 0x8F93, 0xCAE4, 0x8F94, 0xE0CE, 0x8F95, 0xD4AF, 0x8F96, 0xCFBD, 0x8F97, 0xD5B7, 0x8F98, 0xEAA4, 0x8F99, 0xD5DE, 0x8F9A, 0xEAA5, 0x8F9B, 0xD0C1, 0x8F9C, 0xB9BC, 0x8F9D, 0xDE65, 0x8F9E, 0xB4C7, 0x8F9F, 0xB1D9, 0x8FA0, 0xDE66, 0x8FA1, 0xDE67, 0x8FA2, 0xDE68, 0x8FA3, 0xC0B1, 0x8FA4, 0xDE69, 0x8FA5, 0xDE6A, 0x8FA6, 0xDE6B, 0x8FA7, 0xDE6C, 0x8FA8, 0xB1E6, 0x8FA9, 0xB1E7, 0x8FAA, 0xDE6D, 0x8FAB, 0xB1E8, 0x8FAC, 0xDE6E, 0x8FAD, 0xDE6F, 0x8FAE, 0xDE70, 0x8FAF, 0xDE71, 0x8FB0, 0xB3BD, 0x8FB1, 0xC8E8, 0x8FB2, 0xDE72, 0x8FB3, 0xDE73, 0x8FB4, 0xDE74, 0x8FB5, 0xDE75, 0x8FB6, 0xE5C1, 0x8FB7, 0xDE76, 0x8FB8, 0xDE77, 0x8FB9, 0xB1DF, 0x8FBA, 0xDE78, 0x8FBB, 0xDE79, 0x8FBC, 0xDE7A, 0x8FBD, 0xC1C9, 0x8FBE, 0xB4EF, 0x8FBF, 0xDE7B, 0x8FC0, 0xDE7C, 0x8FC1, 0xC7A8, 0x8FC2, 0xD3D8, 0x8FC3, 0xDE7D, 0x8FC4, 0xC6F9, 0x8FC5, 0xD1B8, 0x8FC6, 0xDE7E, 0x8FC7, 0xB9FD, 0x8FC8, 0xC2F5, 0x8FC9, 0xDE80, 0x8FCA, 0xDE81, 0x8FCB, 0xDE82, 0x8FCC, 0xDE83, 0x8FCD, 0xDE84, 0x8FCE, 0xD3AD, 0x8FCF, 0xDE85, 0x8FD0, 0xD4CB, 0x8FD1, 0xBDFC, 0x8FD2, 0xDE86, 0x8FD3, 0xE5C2, 0x8FD4, 0xB7B5, 0x8FD5, 0xE5C3, 0x8FD6, 0xDE87, 0x8FD7, 0xDE88, 0x8FD8, 0xBBB9, 0x8FD9, 0xD5E2, 0x8FDA, 0xDE89, 0x8FDB, 0xBDF8, 0x8FDC, 0xD4B6, 0x8FDD, 0xCEA5, 0x8FDE, 0xC1AC, 0x8FDF, 0xB3D9, 0x8FE0, 0xDE8A, 0x8FE1, 0xDE8B, 0x8FE2, 0xCCF6, 0x8FE3, 0xDE8C, 0x8FE4, 0xE5C6, 0x8FE5, 0xE5C4, 0x8FE6, 0xE5C8, 0x8FE7, 0xDE8D, 0x8FE8, 0xE5CA, 0x8FE9, 0xE5C7, 0x8FEA, 0xB5CF, 0x8FEB, 0xC6C8, 0x8FEC, 0xDE8E, 0x8FED, 0xB5FC, 0x8FEE, 0xE5C5, 0x8FEF, 0xDE8F, 0x8FF0, 0xCAF6, 0x8FF1, 0xDE90, 0x8FF2, 0xDE91, 0x8FF3, 0xE5C9, 0x8FF4, 0xDE92, 0x8FF5, 0xDE93, 0x8FF6, 0xDE94, 0x8FF7, 0xC3D4, 0x8FF8, 0xB1C5, 0x8FF9, 0xBCA3, 0x8FFA, 0xDE95, 0x8FFB, 0xDE96, 0x8FFC, 0xDE97, 0x8FFD, 0xD7B7, 0x8FFE, 0xDE98, 0x8FFF, 0xDE99, 0x9000, 0xCDCB, 0x9001, 0xCBCD, 0x9002, 0xCACA, 0x9003, 0xCCD3, 0x9004, 0xE5CC, 0x9005, 0xE5CB, 0x9006, 0xC4E6, 0x9007, 0xDE9A, 0x9008, 0xDE9B, 0x9009, 0xD1A1, 0x900A, 0xD1B7, 0x900B, 0xE5CD, 0x900C, 0xDE9C, 0x900D, 0xE5D0, 0x900E, 0xDE9D, 0x900F, 0xCDB8, 0x9010, 0xD6F0, 0x9011, 0xE5CF, 0x9012, 0xB5DD, 0x9013, 0xDE9E, 0x9014, 0xCDBE, 0x9015, 0xDE9F, 0x9016, 0xE5D1, 0x9017, 0xB6BA, 0x9018, 0xDEA0, 0x9019, 0xDF40, 0x901A, 0xCDA8, 0x901B, 0xB9E4, 0x901C, 0xDF41, 0x901D, 0xCAC5, 0x901E, 0xB3D1, 0x901F, 0xCBD9, 0x9020, 0xD4EC, 0x9021, 0xE5D2, 0x9022, 0xB7EA, 0x9023, 0xDF42, 0x9024, 0xDF43, 0x9025, 0xDF44, 0x9026, 0xE5CE, 0x9027, 0xDF45, 0x9028, 0xDF46, 0x9029, 0xDF47, 0x902A, 0xDF48, 0x902B, 0xDF49, 0x902C, 0xDF4A, 0x902D, 0xE5D5, 0x902E, 0xB4FE, 0x902F, 0xE5D6, 0x9030, 0xDF4B, 0x9031, 0xDF4C, 0x9032, 0xDF4D, 0x9033, 0xDF4E, 0x9034, 0xDF4F, 0x9035, 0xE5D3, 0x9036, 0xE5D4, 0x9037, 0xDF50, 0x9038, 0xD2DD, 0x9039, 0xDF51, 0x903A, 0xDF52, 0x903B, 0xC2DF, 0x903C, 0xB1C6, 0x903D, 0xDF53, 0x903E, 0xD3E2, 0x903F, 0xDF54, 0x9040, 0xDF55, 0x9041, 0xB6DD, 0x9042, 0xCBEC, 0x9043, 0xDF56, 0x9044, 0xE5D7, 0x9045, 0xDF57, 0x9046, 0xDF58, 0x9047, 0xD3F6, 0x9048, 0xDF59, 0x9049, 0xDF5A, 0x904A, 0xDF5B, 0x904B, 0xDF5C, 0x904C, 0xDF5D, 0x904D, 0xB1E9, 0x904E, 0xDF5E, 0x904F, 0xB6F4, 0x9050, 0xE5DA, 0x9051, 0xE5D8, 0x9052, 0xE5D9, 0x9053, 0xB5C0, 0x9054, 0xDF5F, 0x9055, 0xDF60, 0x9056, 0xDF61, 0x9057, 0xD2C5, 0x9058, 0xE5DC, 0x9059, 0xDF62, 0x905A, 0xDF63, 0x905B, 0xE5DE, 0x905C, 0xDF64, 0x905D, 0xDF65, 0x905E, 0xDF66, 0x905F, 0xDF67, 0x9060, 0xDF68, 0x9061, 0xDF69, 0x9062, 0xE5DD, 0x9063, 0xC7B2, 0x9064, 0xDF6A, 0x9065, 0xD2A3, 0x9066, 0xDF6B, 0x9067, 0xDF6C, 0x9068, 0xE5DB, 0x9069, 0xDF6D, 0x906A, 0xDF6E, 0x906B, 0xDF6F, 0x906C, 0xDF70, 0x906D, 0xD4E2, 0x906E, 0xD5DA, 0x906F, 0xDF71, 0x9070, 0xDF72, 0x9071, 0xDF73, 0x9072, 0xDF74, 0x9073, 0xDF75, 0x9074, 0xE5E0, 0x9075, 0xD7F1, 0x9076, 0xDF76, 0x9077, 0xDF77, 0x9078, 0xDF78, 0x9079, 0xDF79, 0x907A, 0xDF7A, 0x907B, 0xDF7B, 0x907C, 0xDF7C, 0x907D, 0xE5E1, 0x907E, 0xDF7D, 0x907F, 0xB1DC, 0x9080, 0xD1FB, 0x9081, 0xDF7E, 0x9082, 0xE5E2, 0x9083, 0xE5E4, 0x9084, 0xDF80, 0x9085, 0xDF81, 0x9086, 0xDF82, 0x9087, 0xDF83, 0x9088, 0xE5E3, 0x9089, 0xDF84, 0x908A, 0xDF85, 0x908B, 0xE5E5, 0x908C, 0xDF86, 0x908D, 0xDF87, 0x908E, 0xDF88, 0x908F, 0xDF89, 0x9090, 0xDF8A, 0x9091, 0xD2D8, 0x9092, 0xDF8B, 0x9093, 0xB5CB, 0x9094, 0xDF8C, 0x9095, 0xE7DF, 0x9096, 0xDF8D, 0x9097, 0xDAF5, 0x9098, 0xDF8E, 0x9099, 0xDAF8, 0x909A, 0xDF8F, 0x909B, 0xDAF6, 0x909C, 0xDF90, 0x909D, 0xDAF7, 0x909E, 0xDF91, 0x909F, 0xDF92, 0x90A0, 0xDF93, 0x90A1, 0xDAFA, 0x90A2, 0xD0CF, 0x90A3, 0xC4C7, 0x90A4, 0xDF94, 0x90A5, 0xDF95, 0x90A6, 0xB0EE, 0x90A7, 0xDF96, 0x90A8, 0xDF97, 0x90A9, 0xDF98, 0x90AA, 0xD0B0, 0x90AB, 0xDF99, 0x90AC, 0xDAF9, 0x90AD, 0xDF9A, 0x90AE, 0xD3CA, 0x90AF, 0xBAAA, 0x90B0, 0xDBA2, 0x90B1, 0xC7F1, 0x90B2, 0xDF9B, 0x90B3, 0xDAFC, 0x90B4, 0xDAFB, 0x90B5, 0xC9DB, 0x90B6, 0xDAFD, 0x90B7, 0xDF9C, 0x90B8, 0xDBA1, 0x90B9, 0xD7DE, 0x90BA, 0xDAFE, 0x90BB, 0xC1DA, 0x90BC, 0xDF9D, 0x90BD, 0xDF9E, 0x90BE, 0xDBA5, 0x90BF, 0xDF9F, 0x90C0, 0xDFA0, 0x90C1, 0xD3F4, 0x90C2, 0xE040, 0x90C3, 0xE041, 0x90C4, 0xDBA7, 0x90C5, 0xDBA4, 0x90C6, 0xE042, 0x90C7, 0xDBA8, 0x90C8, 0xE043, 0x90C9, 0xE044, 0x90CA, 0xBDBC, 0x90CB, 0xE045, 0x90CC, 0xE046, 0x90CD, 0xE047, 0x90CE, 0xC0C9, 0x90CF, 0xDBA3, 0x90D0, 0xDBA6, 0x90D1, 0xD6A3, 0x90D2, 0xE048, 0x90D3, 0xDBA9, 0x90D4, 0xE049, 0x90D5, 0xE04A, 0x90D6, 0xE04B, 0x90D7, 0xDBAD, 0x90D8, 0xE04C, 0x90D9, 0xE04D, 0x90DA, 0xE04E, 0x90DB, 0xDBAE, 0x90DC, 0xDBAC, 0x90DD, 0xBAC2, 0x90DE, 0xE04F, 0x90DF, 0xE050, 0x90E0, 0xE051, 0x90E1, 0xBFA4, 0x90E2, 0xDBAB, 0x90E3, 0xE052, 0x90E4, 0xE053, 0x90E5, 0xE054, 0x90E6, 0xDBAA, 0x90E7, 0xD4C7, 0x90E8, 0xB2BF, 0x90E9, 0xE055, 0x90EA, 0xE056, 0x90EB, 0xDBAF, 0x90EC, 0xE057, 0x90ED, 0xB9F9, 0x90EE, 0xE058, 0x90EF, 0xDBB0, 0x90F0, 0xE059, 0x90F1, 0xE05A, 0x90F2, 0xE05B, 0x90F3, 0xE05C, 0x90F4, 0xB3BB, 0x90F5, 0xE05D, 0x90F6, 0xE05E, 0x90F7, 0xE05F, 0x90F8, 0xB5A6, 0x90F9, 0xE060, 0x90FA, 0xE061, 0x90FB, 0xE062, 0x90FC, 0xE063, 0x90FD, 0xB6BC, 0x90FE, 0xDBB1, 0x90FF, 0xE064, 0x9100, 0xE065, 0x9101, 0xE066, 0x9102, 0xB6F5, 0x9103, 0xE067, 0x9104, 0xDBB2, 0x9105, 0xE068, 0x9106, 0xE069, 0x9107, 0xE06A, 0x9108, 0xE06B, 0x9109, 0xE06C, 0x910A, 0xE06D, 0x910B, 0xE06E, 0x910C, 0xE06F, 0x910D, 0xE070, 0x910E, 0xE071, 0x910F, 0xE072, 0x9110, 0xE073, 0x9111, 0xE074, 0x9112, 0xE075, 0x9113, 0xE076, 0x9114, 0xE077, 0x9115, 0xE078, 0x9116, 0xE079, 0x9117, 0xE07A, 0x9118, 0xE07B, 0x9119, 0xB1C9, 0x911A, 0xE07C, 0x911B, 0xE07D, 0x911C, 0xE07E, 0x911D, 0xE080, 0x911E, 0xDBB4, 0x911F, 0xE081, 0x9120, 0xE082, 0x9121, 0xE083, 0x9122, 0xDBB3, 0x9123, 0xDBB5, 0x9124, 0xE084, 0x9125, 0xE085, 0x9126, 0xE086, 0x9127, 0xE087, 0x9128, 0xE088, 0x9129, 0xE089, 0x912A, 0xE08A, 0x912B, 0xE08B, 0x912C, 0xE08C, 0x912D, 0xE08D, 0x912E, 0xE08E, 0x912F, 0xDBB7, 0x9130, 0xE08F, 0x9131, 0xDBB6, 0x9132, 0xE090, 0x9133, 0xE091, 0x9134, 0xE092, 0x9135, 0xE093, 0x9136, 0xE094, 0x9137, 0xE095, 0x9138, 0xE096, 0x9139, 0xDBB8, 0x913A, 0xE097, 0x913B, 0xE098, 0x913C, 0xE099, 0x913D, 0xE09A, 0x913E, 0xE09B, 0x913F, 0xE09C, 0x9140, 0xE09D, 0x9141, 0xE09E, 0x9142, 0xE09F, 0x9143, 0xDBB9, 0x9144, 0xE0A0, 0x9145, 0xE140, 0x9146, 0xDBBA, 0x9147, 0xE141, 0x9148, 0xE142, 0x9149, 0xD3CF, 0x914A, 0xF4FA, 0x914B, 0xC7F5, 0x914C, 0xD7C3, 0x914D, 0xC5E4, 0x914E, 0xF4FC, 0x914F, 0xF4FD, 0x9150, 0xF4FB, 0x9151, 0xE143, 0x9152, 0xBEC6, 0x9153, 0xE144, 0x9154, 0xE145, 0x9155, 0xE146, 0x9156, 0xE147, 0x9157, 0xD0EF, 0x9158, 0xE148, 0x9159, 0xE149, 0x915A, 0xB7D3, 0x915B, 0xE14A, 0x915C, 0xE14B, 0x915D, 0xD4CD, 0x915E, 0xCCAA, 0x915F, 0xE14C, 0x9160, 0xE14D, 0x9161, 0xF5A2, 0x9162, 0xF5A1, 0x9163, 0xBAA8, 0x9164, 0xF4FE, 0x9165, 0xCBD6, 0x9166, 0xE14E, 0x9167, 0xE14F, 0x9168, 0xE150, 0x9169, 0xF5A4, 0x916A, 0xC0D2, 0x916B, 0xE151, 0x916C, 0xB3EA, 0x916D, 0xE152, 0x916E, 0xCDAA, 0x916F, 0xF5A5, 0x9170, 0xF5A3, 0x9171, 0xBDB4, 0x9172, 0xF5A8, 0x9173, 0xE153, 0x9174, 0xF5A9, 0x9175, 0xBDCD, 0x9176, 0xC3B8, 0x9177, 0xBFE1, 0x9178, 0xCBE1, 0x9179, 0xF5AA, 0x917A, 0xE154, 0x917B, 0xE155, 0x917C, 0xE156, 0x917D, 0xF5A6, 0x917E, 0xF5A7, 0x917F, 0xC4F0, 0x9180, 0xE157, 0x9181, 0xE158, 0x9182, 0xE159, 0x9183, 0xE15A, 0x9184, 0xE15B, 0x9185, 0xF5AC, 0x9186, 0xE15C, 0x9187, 0xB4BC, 0x9188, 0xE15D, 0x9189, 0xD7ED, 0x918A, 0xE15E, 0x918B, 0xB4D7, 0x918C, 0xF5AB, 0x918D, 0xF5AE, 0x918E, 0xE15F, 0x918F, 0xE160, 0x9190, 0xF5AD, 0x9191, 0xF5AF, 0x9192, 0xD0D1, 0x9193, 0xE161, 0x9194, 0xE162, 0x9195, 0xE163, 0x9196, 0xE164, 0x9197, 0xE165, 0x9198, 0xE166, 0x9199, 0xE167, 0x919A, 0xC3D1, 0x919B, 0xC8A9, 0x919C, 0xE168, 0x919D, 0xE169, 0x919E, 0xE16A, 0x919F, 0xE16B, 0x91A0, 0xE16C, 0x91A1, 0xE16D, 0x91A2, 0xF5B0, 0x91A3, 0xF5B1, 0x91A4, 0xE16E, 0x91A5, 0xE16F, 0x91A6, 0xE170, 0x91A7, 0xE171, 0x91A8, 0xE172, 0x91A9, 0xE173, 0x91AA, 0xF5B2, 0x91AB, 0xE174, 0x91AC, 0xE175, 0x91AD, 0xF5B3, 0x91AE, 0xF5B4, 0x91AF, 0xF5B5, 0x91B0, 0xE176, 0x91B1, 0xE177, 0x91B2, 0xE178, 0x91B3, 0xE179, 0x91B4, 0xF5B7, 0x91B5, 0xF5B6, 0x91B6, 0xE17A, 0x91B7, 0xE17B, 0x91B8, 0xE17C, 0x91B9, 0xE17D, 0x91BA, 0xF5B8, 0x91BB, 0xE17E, 0x91BC, 0xE180, 0x91BD, 0xE181, 0x91BE, 0xE182, 0x91BF, 0xE183, 0x91C0, 0xE184, 0x91C1, 0xE185, 0x91C2, 0xE186, 0x91C3, 0xE187, 0x91C4, 0xE188, 0x91C5, 0xE189, 0x91C6, 0xE18A, 0x91C7, 0xB2C9, 0x91C8, 0xE18B, 0x91C9, 0xD3D4, 0x91CA, 0xCACD, 0x91CB, 0xE18C, 0x91CC, 0xC0EF, 0x91CD, 0xD6D8, 0x91CE, 0xD2B0, 0x91CF, 0xC1BF, 0x91D0, 0xE18D, 0x91D1, 0xBDF0, 0x91D2, 0xE18E, 0x91D3, 0xE18F, 0x91D4, 0xE190, 0x91D5, 0xE191, 0x91D6, 0xE192, 0x91D7, 0xE193, 0x91D8, 0xE194, 0x91D9, 0xE195, 0x91DA, 0xE196, 0x91DB, 0xE197, 0x91DC, 0xB8AA, 0x91DD, 0xE198, 0x91DE, 0xE199, 0x91DF, 0xE19A, 0x91E0, 0xE19B, 0x91E1, 0xE19C, 0x91E2, 0xE19D, 0x91E3, 0xE19E, 0x91E4, 0xE19F, 0x91E5, 0xE1A0, 0x91E6, 0xE240, 0x91E7, 0xE241, 0x91E8, 0xE242, 0x91E9, 0xE243, 0x91EA, 0xE244, 0x91EB, 0xE245, 0x91EC, 0xE246, 0x91ED, 0xE247, 0x91EE, 0xE248, 0x91EF, 0xE249, 0x91F0, 0xE24A, 0x91F1, 0xE24B, 0x91F2, 0xE24C, 0x91F3, 0xE24D, 0x91F4, 0xE24E, 0x91F5, 0xE24F, 0x91F6, 0xE250, 0x91F7, 0xE251, 0x91F8, 0xE252, 0x91F9, 0xE253, 0x91FA, 0xE254, 0x91FB, 0xE255, 0x91FC, 0xE256, 0x91FD, 0xE257, 0x91FE, 0xE258, 0x91FF, 0xE259, 0x9200, 0xE25A, 0x9201, 0xE25B, 0x9202, 0xE25C, 0x9203, 0xE25D, 0x9204, 0xE25E, 0x9205, 0xE25F, 0x9206, 0xE260, 0x9207, 0xE261, 0x9208, 0xE262, 0x9209, 0xE263, 0x920A, 0xE264, 0x920B, 0xE265, 0x920C, 0xE266, 0x920D, 0xE267, 0x920E, 0xE268, 0x920F, 0xE269, 0x9210, 0xE26A, 0x9211, 0xE26B, 0x9212, 0xE26C, 0x9213, 0xE26D, 0x9214, 0xE26E, 0x9215, 0xE26F, 0x9216, 0xE270, 0x9217, 0xE271, 0x9218, 0xE272, 0x9219, 0xE273, 0x921A, 0xE274, 0x921B, 0xE275, 0x921C, 0xE276, 0x921D, 0xE277, 0x921E, 0xE278, 0x921F, 0xE279, 0x9220, 0xE27A, 0x9221, 0xE27B, 0x9222, 0xE27C, 0x9223, 0xE27D, 0x9224, 0xE27E, 0x9225, 0xE280, 0x9226, 0xE281, 0x9227, 0xE282, 0x9228, 0xE283, 0x9229, 0xE284, 0x922A, 0xE285, 0x922B, 0xE286, 0x922C, 0xE287, 0x922D, 0xE288, 0x922E, 0xE289, 0x922F, 0xE28A, 0x9230, 0xE28B, 0x9231, 0xE28C, 0x9232, 0xE28D, 0x9233, 0xE28E, 0x9234, 0xE28F, 0x9235, 0xE290, 0x9236, 0xE291, 0x9237, 0xE292, 0x9238, 0xE293, 0x9239, 0xE294, 0x923A, 0xE295, 0x923B, 0xE296, 0x923C, 0xE297, 0x923D, 0xE298, 0x923E, 0xE299, 0x923F, 0xE29A, 0x9240, 0xE29B, 0x9241, 0xE29C, 0x9242, 0xE29D, 0x9243, 0xE29E, 0x9244, 0xE29F, 0x9245, 0xE2A0, 0x9246, 0xE340, 0x9247, 0xE341, 0x9248, 0xE342, 0x9249, 0xE343, 0x924A, 0xE344, 0x924B, 0xE345, 0x924C, 0xE346, 0x924D, 0xE347, 0x924E, 0xE348, 0x924F, 0xE349, 0x9250, 0xE34A, 0x9251, 0xE34B, 0x9252, 0xE34C, 0x9253, 0xE34D, 0x9254, 0xE34E, 0x9255, 0xE34F, 0x9256, 0xE350, 0x9257, 0xE351, 0x9258, 0xE352, 0x9259, 0xE353, 0x925A, 0xE354, 0x925B, 0xE355, 0x925C, 0xE356, 0x925D, 0xE357, 0x925E, 0xE358, 0x925F, 0xE359, 0x9260, 0xE35A, 0x9261, 0xE35B, 0x9262, 0xE35C, 0x9263, 0xE35D, 0x9264, 0xE35E, 0x9265, 0xE35F, 0x9266, 0xE360, 0x9267, 0xE361, 0x9268, 0xE362, 0x9269, 0xE363, 0x926A, 0xE364, 0x926B, 0xE365, 0x926C, 0xE366, 0x926D, 0xE367, 0x926E, 0xE368, 0x926F, 0xE369, 0x9270, 0xE36A, 0x9271, 0xE36B, 0x9272, 0xE36C, 0x9273, 0xE36D, 0x9274, 0xBCF8, 0x9275, 0xE36E, 0x9276, 0xE36F, 0x9277, 0xE370, 0x9278, 0xE371, 0x9279, 0xE372, 0x927A, 0xE373, 0x927B, 0xE374, 0x927C, 0xE375, 0x927D, 0xE376, 0x927E, 0xE377, 0x927F, 0xE378, 0x9280, 0xE379, 0x9281, 0xE37A, 0x9282, 0xE37B, 0x9283, 0xE37C, 0x9284, 0xE37D, 0x9285, 0xE37E, 0x9286, 0xE380, 0x9287, 0xE381, 0x9288, 0xE382, 0x9289, 0xE383, 0x928A, 0xE384, 0x928B, 0xE385, 0x928C, 0xE386, 0x928D, 0xE387, 0x928E, 0xF6C6, 0x928F, 0xE388, 0x9290, 0xE389, 0x9291, 0xE38A, 0x9292, 0xE38B, 0x9293, 0xE38C, 0x9294, 0xE38D, 0x9295, 0xE38E, 0x9296, 0xE38F, 0x9297, 0xE390, 0x9298, 0xE391, 0x9299, 0xE392, 0x929A, 0xE393, 0x929B, 0xE394, 0x929C, 0xE395, 0x929D, 0xE396, 0x929E, 0xE397, 0x929F, 0xE398, 0x92A0, 0xE399, 0x92A1, 0xE39A, 0x92A2, 0xE39B, 0x92A3, 0xE39C, 0x92A4, 0xE39D, 0x92A5, 0xE39E, 0x92A6, 0xE39F, 0x92A7, 0xE3A0, 0x92A8, 0xE440, 0x92A9, 0xE441, 0x92AA, 0xE442, 0x92AB, 0xE443, 0x92AC, 0xE444, 0x92AD, 0xE445, 0x92AE, 0xF6C7, 0x92AF, 0xE446, 0x92B0, 0xE447, 0x92B1, 0xE448, 0x92B2, 0xE449, 0x92B3, 0xE44A, 0x92B4, 0xE44B, 0x92B5, 0xE44C, 0x92B6, 0xE44D, 0x92B7, 0xE44E, 0x92B8, 0xE44F, 0x92B9, 0xE450, 0x92BA, 0xE451, 0x92BB, 0xE452, 0x92BC, 0xE453, 0x92BD, 0xE454, 0x92BE, 0xE455, 0x92BF, 0xE456, 0x92C0, 0xE457, 0x92C1, 0xE458, 0x92C2, 0xE459, 0x92C3, 0xE45A, 0x92C4, 0xE45B, 0x92C5, 0xE45C, 0x92C6, 0xE45D, 0x92C7, 0xE45E, 0x92C8, 0xF6C8, 0x92C9, 0xE45F, 0x92CA, 0xE460, 0x92CB, 0xE461, 0x92CC, 0xE462, 0x92CD, 0xE463, 0x92CE, 0xE464, 0x92CF, 0xE465, 0x92D0, 0xE466, 0x92D1, 0xE467, 0x92D2, 0xE468, 0x92D3, 0xE469, 0x92D4, 0xE46A, 0x92D5, 0xE46B, 0x92D6, 0xE46C, 0x92D7, 0xE46D, 0x92D8, 0xE46E, 0x92D9, 0xE46F, 0x92DA, 0xE470, 0x92DB, 0xE471, 0x92DC, 0xE472, 0x92DD, 0xE473, 0x92DE, 0xE474, 0x92DF, 0xE475, 0x92E0, 0xE476, 0x92E1, 0xE477, 0x92E2, 0xE478, 0x92E3, 0xE479, 0x92E4, 0xE47A, 0x92E5, 0xE47B, 0x92E6, 0xE47C, 0x92E7, 0xE47D, 0x92E8, 0xE47E, 0x92E9, 0xE480, 0x92EA, 0xE481, 0x92EB, 0xE482, 0x92EC, 0xE483, 0x92ED, 0xE484, 0x92EE, 0xE485, 0x92EF, 0xE486, 0x92F0, 0xE487, 0x92F1, 0xE488, 0x92F2, 0xE489, 0x92F3, 0xE48A, 0x92F4, 0xE48B, 0x92F5, 0xE48C, 0x92F6, 0xE48D, 0x92F7, 0xE48E, 0x92F8, 0xE48F, 0x92F9, 0xE490, 0x92FA, 0xE491, 0x92FB, 0xE492, 0x92FC, 0xE493, 0x92FD, 0xE494, 0x92FE, 0xE495, 0x92FF, 0xE496, 0x9300, 0xE497, 0x9301, 0xE498, 0x9302, 0xE499, 0x9303, 0xE49A, 0x9304, 0xE49B, 0x9305, 0xE49C, 0x9306, 0xE49D, 0x9307, 0xE49E, 0x9308, 0xE49F, 0x9309, 0xE4A0, 0x930A, 0xE540, 0x930B, 0xE541, 0x930C, 0xE542, 0x930D, 0xE543, 0x930E, 0xE544, 0x930F, 0xE545, 0x9310, 0xE546, 0x9311, 0xE547, 0x9312, 0xE548, 0x9313, 0xE549, 0x9314, 0xE54A, 0x9315, 0xE54B, 0x9316, 0xE54C, 0x9317, 0xE54D, 0x9318, 0xE54E, 0x9319, 0xE54F, 0x931A, 0xE550, 0x931B, 0xE551, 0x931C, 0xE552, 0x931D, 0xE553, 0x931E, 0xE554, 0x931F, 0xE555, 0x9320, 0xE556, 0x9321, 0xE557, 0x9322, 0xE558, 0x9323, 0xE559, 0x9324, 0xE55A, 0x9325, 0xE55B, 0x9326, 0xE55C, 0x9327, 0xE55D, 0x9328, 0xE55E, 0x9329, 0xE55F, 0x932A, 0xE560, 0x932B, 0xE561, 0x932C, 0xE562, 0x932D, 0xE563, 0x932E, 0xE564, 0x932F, 0xE565, 0x9330, 0xE566, 0x9331, 0xE567, 0x9332, 0xE568, 0x9333, 0xE569, 0x9334, 0xE56A, 0x9335, 0xE56B, 0x9336, 0xE56C, 0x9337, 0xE56D, 0x9338, 0xE56E, 0x9339, 0xE56F, 0x933A, 0xE570, 0x933B, 0xE571, 0x933C, 0xE572, 0x933D, 0xE573, 0x933E, 0xF6C9, 0x933F, 0xE574, 0x9340, 0xE575, 0x9341, 0xE576, 0x9342, 0xE577, 0x9343, 0xE578, 0x9344, 0xE579, 0x9345, 0xE57A, 0x9346, 0xE57B, 0x9347, 0xE57C, 0x9348, 0xE57D, 0x9349, 0xE57E, 0x934A, 0xE580, 0x934B, 0xE581, 0x934C, 0xE582, 0x934D, 0xE583, 0x934E, 0xE584, 0x934F, 0xE585, 0x9350, 0xE586, 0x9351, 0xE587, 0x9352, 0xE588, 0x9353, 0xE589, 0x9354, 0xE58A, 0x9355, 0xE58B, 0x9356, 0xE58C, 0x9357, 0xE58D, 0x9358, 0xE58E, 0x9359, 0xE58F, 0x935A, 0xE590, 0x935B, 0xE591, 0x935C, 0xE592, 0x935D, 0xE593, 0x935E, 0xE594, 0x935F, 0xE595, 0x9360, 0xE596, 0x9361, 0xE597, 0x9362, 0xE598, 0x9363, 0xE599, 0x9364, 0xE59A, 0x9365, 0xE59B, 0x9366, 0xE59C, 0x9367, 0xE59D, 0x9368, 0xE59E, 0x9369, 0xE59F, 0x936A, 0xF6CA, 0x936B, 0xE5A0, 0x936C, 0xE640, 0x936D, 0xE641, 0x936E, 0xE642, 0x936F, 0xE643, 0x9370, 0xE644, 0x9371, 0xE645, 0x9372, 0xE646, 0x9373, 0xE647, 0x9374, 0xE648, 0x9375, 0xE649, 0x9376, 0xE64A, 0x9377, 0xE64B, 0x9378, 0xE64C, 0x9379, 0xE64D, 0x937A, 0xE64E, 0x937B, 0xE64F, 0x937C, 0xE650, 0x937D, 0xE651, 0x937E, 0xE652, 0x937F, 0xE653, 0x9380, 0xE654, 0x9381, 0xE655, 0x9382, 0xE656, 0x9383, 0xE657, 0x9384, 0xE658, 0x9385, 0xE659, 0x9386, 0xE65A, 0x9387, 0xE65B, 0x9388, 0xE65C, 0x9389, 0xE65D, 0x938A, 0xE65E, 0x938B, 0xE65F, 0x938C, 0xE660, 0x938D, 0xE661, 0x938E, 0xE662, 0x938F, 0xF6CC, 0x9390, 0xE663, 0x9391, 0xE664, 0x9392, 0xE665, 0x9393, 0xE666, 0x9394, 0xE667, 0x9395, 0xE668, 0x9396, 0xE669, 0x9397, 0xE66A, 0x9398, 0xE66B, 0x9399, 0xE66C, 0x939A, 0xE66D, 0x939B, 0xE66E, 0x939C, 0xE66F, 0x939D, 0xE670, 0x939E, 0xE671, 0x939F, 0xE672, 0x93A0, 0xE673, 0x93A1, 0xE674, 0x93A2, 0xE675, 0x93A3, 0xE676, 0x93A4, 0xE677, 0x93A5, 0xE678, 0x93A6, 0xE679, 0x93A7, 0xE67A, 0x93A8, 0xE67B, 0x93A9, 0xE67C, 0x93AA, 0xE67D, 0x93AB, 0xE67E, 0x93AC, 0xE680, 0x93AD, 0xE681, 0x93AE, 0xE682, 0x93AF, 0xE683, 0x93B0, 0xE684, 0x93B1, 0xE685, 0x93B2, 0xE686, 0x93B3, 0xE687, 0x93B4, 0xE688, 0x93B5, 0xE689, 0x93B6, 0xE68A, 0x93B7, 0xE68B, 0x93B8, 0xE68C, 0x93B9, 0xE68D, 0x93BA, 0xE68E, 0x93BB, 0xE68F, 0x93BC, 0xE690, 0x93BD, 0xE691, 0x93BE, 0xE692, 0x93BF, 0xE693, 0x93C0, 0xE694, 0x93C1, 0xE695, 0x93C2, 0xE696, 0x93C3, 0xE697, 0x93C4, 0xE698, 0x93C5, 0xE699, 0x93C6, 0xE69A, 0x93C7, 0xE69B, 0x93C8, 0xE69C, 0x93C9, 0xE69D, 0x93CA, 0xF6CB, 0x93CB, 0xE69E, 0x93CC, 0xE69F, 0x93CD, 0xE6A0, 0x93CE, 0xE740, 0x93CF, 0xE741, 0x93D0, 0xE742, 0x93D1, 0xE743, 0x93D2, 0xE744, 0x93D3, 0xE745, 0x93D4, 0xE746, 0x93D5, 0xE747, 0x93D6, 0xF7E9, 0x93D7, 0xE748, 0x93D8, 0xE749, 0x93D9, 0xE74A, 0x93DA, 0xE74B, 0x93DB, 0xE74C, 0x93DC, 0xE74D, 0x93DD, 0xE74E, 0x93DE, 0xE74F, 0x93DF, 0xE750, 0x93E0, 0xE751, 0x93E1, 0xE752, 0x93E2, 0xE753, 0x93E3, 0xE754, 0x93E4, 0xE755, 0x93E5, 0xE756, 0x93E6, 0xE757, 0x93E7, 0xE758, 0x93E8, 0xE759, 0x93E9, 0xE75A, 0x93EA, 0xE75B, 0x93EB, 0xE75C, 0x93EC, 0xE75D, 0x93ED, 0xE75E, 0x93EE, 0xE75F, 0x93EF, 0xE760, 0x93F0, 0xE761, 0x93F1, 0xE762, 0x93F2, 0xE763, 0x93F3, 0xE764, 0x93F4, 0xE765, 0x93F5, 0xE766, 0x93F6, 0xE767, 0x93F7, 0xE768, 0x93F8, 0xE769, 0x93F9, 0xE76A, 0x93FA, 0xE76B, 0x93FB, 0xE76C, 0x93FC, 0xE76D, 0x93FD, 0xE76E, 0x93FE, 0xE76F, 0x93FF, 0xE770, 0x9400, 0xE771, 0x9401, 0xE772, 0x9402, 0xE773, 0x9403, 0xE774, 0x9404, 0xE775, 0x9405, 0xE776, 0x9406, 0xE777, 0x9407, 0xE778, 0x9408, 0xE779, 0x9409, 0xE77A, 0x940A, 0xE77B, 0x940B, 0xE77C, 0x940C, 0xE77D, 0x940D, 0xE77E, 0x940E, 0xE780, 0x940F, 0xE781, 0x9410, 0xE782, 0x9411, 0xE783, 0x9412, 0xE784, 0x9413, 0xE785, 0x9414, 0xE786, 0x9415, 0xE787, 0x9416, 0xE788, 0x9417, 0xE789, 0x9418, 0xE78A, 0x9419, 0xE78B, 0x941A, 0xE78C, 0x941B, 0xE78D, 0x941C, 0xE78E, 0x941D, 0xE78F, 0x941E, 0xE790, 0x941F, 0xE791, 0x9420, 0xE792, 0x9421, 0xE793, 0x9422, 0xE794, 0x9423, 0xE795, 0x9424, 0xE796, 0x9425, 0xE797, 0x9426, 0xE798, 0x9427, 0xE799, 0x9428, 0xE79A, 0x9429, 0xE79B, 0x942A, 0xE79C, 0x942B, 0xE79D, 0x942C, 0xE79E, 0x942D, 0xE79F, 0x942E, 0xE7A0, 0x942F, 0xE840, 0x9430, 0xE841, 0x9431, 0xE842, 0x9432, 0xE843, 0x9433, 0xE844, 0x9434, 0xE845, 0x9435, 0xE846, 0x9436, 0xE847, 0x9437, 0xE848, 0x9438, 0xE849, 0x9439, 0xE84A, 0x943A, 0xE84B, 0x943B, 0xE84C, 0x943C, 0xE84D, 0x943D, 0xE84E, 0x943E, 0xF6CD, 0x943F, 0xE84F, 0x9440, 0xE850, 0x9441, 0xE851, 0x9442, 0xE852, 0x9443, 0xE853, 0x9444, 0xE854, 0x9445, 0xE855, 0x9446, 0xE856, 0x9447, 0xE857, 0x9448, 0xE858, 0x9449, 0xE859, 0x944A, 0xE85A, 0x944B, 0xE85B, 0x944C, 0xE85C, 0x944D, 0xE85D, 0x944E, 0xE85E, 0x944F, 0xE85F, 0x9450, 0xE860, 0x9451, 0xE861, 0x9452, 0xE862, 0x9453, 0xE863, 0x9454, 0xE864, 0x9455, 0xE865, 0x9456, 0xE866, 0x9457, 0xE867, 0x9458, 0xE868, 0x9459, 0xE869, 0x945A, 0xE86A, 0x945B, 0xE86B, 0x945C, 0xE86C, 0x945D, 0xE86D, 0x945E, 0xE86E, 0x945F, 0xE86F, 0x9460, 0xE870, 0x9461, 0xE871, 0x9462, 0xE872, 0x9463, 0xE873, 0x9464, 0xE874, 0x9465, 0xE875, 0x9466, 0xE876, 0x9467, 0xE877, 0x9468, 0xE878, 0x9469, 0xE879, 0x946A, 0xE87A, 0x946B, 0xF6CE, 0x946C, 0xE87B, 0x946D, 0xE87C, 0x946E, 0xE87D, 0x946F, 0xE87E, 0x9470, 0xE880, 0x9471, 0xE881, 0x9472, 0xE882, 0x9473, 0xE883, 0x9474, 0xE884, 0x9475, 0xE885, 0x9476, 0xE886, 0x9477, 0xE887, 0x9478, 0xE888, 0x9479, 0xE889, 0x947A, 0xE88A, 0x947B, 0xE88B, 0x947C, 0xE88C, 0x947D, 0xE88D, 0x947E, 0xE88E, 0x947F, 0xE88F, 0x9480, 0xE890, 0x9481, 0xE891, 0x9482, 0xE892, 0x9483, 0xE893, 0x9484, 0xE894, 0x9485, 0xEEC4, 0x9486, 0xEEC5, 0x9487, 0xEEC6, 0x9488, 0xD5EB, 0x9489, 0xB6A4, 0x948A, 0xEEC8, 0x948B, 0xEEC7, 0x948C, 0xEEC9, 0x948D, 0xEECA, 0x948E, 0xC7A5, 0x948F, 0xEECB, 0x9490, 0xEECC, 0x9491, 0xE895, 0x9492, 0xB7B0, 0x9493, 0xB5F6, 0x9494, 0xEECD, 0x9495, 0xEECF, 0x9496, 0xE896, 0x9497, 0xEECE, 0x9498, 0xE897, 0x9499, 0xB8C6, 0x949A, 0xEED0, 0x949B, 0xEED1, 0x949C, 0xEED2, 0x949D, 0xB6DB, 0x949E, 0xB3AE, 0x949F, 0xD6D3, 0x94A0, 0xC4C6, 0x94A1, 0xB1B5, 0x94A2, 0xB8D6, 0x94A3, 0xEED3, 0x94A4, 0xEED4, 0x94A5, 0xD4BF, 0x94A6, 0xC7D5, 0x94A7, 0xBEFB, 0x94A8, 0xCED9, 0x94A9, 0xB9B3, 0x94AA, 0xEED6, 0x94AB, 0xEED5, 0x94AC, 0xEED8, 0x94AD, 0xEED7, 0x94AE, 0xC5A5, 0x94AF, 0xEED9, 0x94B0, 0xEEDA, 0x94B1, 0xC7AE, 0x94B2, 0xEEDB, 0x94B3, 0xC7AF, 0x94B4, 0xEEDC, 0x94B5, 0xB2A7, 0x94B6, 0xEEDD, 0x94B7, 0xEEDE, 0x94B8, 0xEEDF, 0x94B9, 0xEEE0, 0x94BA, 0xEEE1, 0x94BB, 0xD7EA, 0x94BC, 0xEEE2, 0x94BD, 0xEEE3, 0x94BE, 0xBCD8, 0x94BF, 0xEEE4, 0x94C0, 0xD3CB, 0x94C1, 0xCCFA, 0x94C2, 0xB2AC, 0x94C3, 0xC1E5, 0x94C4, 0xEEE5, 0x94C5, 0xC7A6, 0x94C6, 0xC3AD, 0x94C7, 0xE898, 0x94C8, 0xEEE6, 0x94C9, 0xEEE7, 0x94CA, 0xEEE8, 0x94CB, 0xEEE9, 0x94CC, 0xEEEA, 0x94CD, 0xEEEB, 0x94CE, 0xEEEC, 0x94CF, 0xE899, 0x94D0, 0xEEED, 0x94D1, 0xEEEE, 0x94D2, 0xEEEF, 0x94D3, 0xE89A, 0x94D4, 0xE89B, 0x94D5, 0xEEF0, 0x94D6, 0xEEF1, 0x94D7, 0xEEF2, 0x94D8, 0xEEF4, 0x94D9, 0xEEF3, 0x94DA, 0xE89C, 0x94DB, 0xEEF5, 0x94DC, 0xCDAD, 0x94DD, 0xC2C1, 0x94DE, 0xEEF6, 0x94DF, 0xEEF7, 0x94E0, 0xEEF8, 0x94E1, 0xD5A1, 0x94E2, 0xEEF9, 0x94E3, 0xCFB3, 0x94E4, 0xEEFA, 0x94E5, 0xEEFB, 0x94E6, 0xE89D, 0x94E7, 0xEEFC, 0x94E8, 0xEEFD, 0x94E9, 0xEFA1, 0x94EA, 0xEEFE, 0x94EB, 0xEFA2, 0x94EC, 0xB8F5, 0x94ED, 0xC3FA, 0x94EE, 0xEFA3, 0x94EF, 0xEFA4, 0x94F0, 0xBDC2, 0x94F1, 0xD2BF, 0x94F2, 0xB2F9, 0x94F3, 0xEFA5, 0x94F4, 0xEFA6, 0x94F5, 0xEFA7, 0x94F6, 0xD2F8, 0x94F7, 0xEFA8, 0x94F8, 0xD6FD, 0x94F9, 0xEFA9, 0x94FA, 0xC6CC, 0x94FB, 0xE89E, 0x94FC, 0xEFAA, 0x94FD, 0xEFAB, 0x94FE, 0xC1B4, 0x94FF, 0xEFAC, 0x9500, 0xCFFA, 0x9501, 0xCBF8, 0x9502, 0xEFAE, 0x9503, 0xEFAD, 0x9504, 0xB3FA, 0x9505, 0xB9F8, 0x9506, 0xEFAF, 0x9507, 0xEFB0, 0x9508, 0xD0E2, 0x9509, 0xEFB1, 0x950A, 0xEFB2, 0x950B, 0xB7E6, 0x950C, 0xD0BF, 0x950D, 0xEFB3, 0x950E, 0xEFB4, 0x950F, 0xEFB5, 0x9510, 0xC8F1, 0x9511, 0xCCE0, 0x9512, 0xEFB6, 0x9513, 0xEFB7, 0x9514, 0xEFB8, 0x9515, 0xEFB9, 0x9516, 0xEFBA, 0x9517, 0xD5E0, 0x9518, 0xEFBB, 0x9519, 0xB4ED, 0x951A, 0xC3AA, 0x951B, 0xEFBC, 0x951C, 0xE89F, 0x951D, 0xEFBD, 0x951E, 0xEFBE, 0x951F, 0xEFBF, 0x9520, 0xE8A0, 0x9521, 0xCEFD, 0x9522, 0xEFC0, 0x9523, 0xC2E0, 0x9524, 0xB4B8, 0x9525, 0xD7B6, 0x9526, 0xBDF5, 0x9527, 0xE940, 0x9528, 0xCFC7, 0x9529, 0xEFC3, 0x952A, 0xEFC1, 0x952B, 0xEFC2, 0x952C, 0xEFC4, 0x952D, 0xB6A7, 0x952E, 0xBCFC, 0x952F, 0xBEE2, 0x9530, 0xC3CC, 0x9531, 0xEFC5, 0x9532, 0xEFC6, 0x9533, 0xE941, 0x9534, 0xEFC7, 0x9535, 0xEFCF, 0x9536, 0xEFC8, 0x9537, 0xEFC9, 0x9538, 0xEFCA, 0x9539, 0xC7C2, 0x953A, 0xEFF1, 0x953B, 0xB6CD, 0x953C, 0xEFCB, 0x953D, 0xE942, 0x953E, 0xEFCC, 0x953F, 0xEFCD, 0x9540, 0xB6C6, 0x9541, 0xC3BE, 0x9542, 0xEFCE, 0x9543, 0xE943, 0x9544, 0xEFD0, 0x9545, 0xEFD1, 0x9546, 0xEFD2, 0x9547, 0xD5F2, 0x9548, 0xE944, 0x9549, 0xEFD3, 0x954A, 0xC4F7, 0x954B, 0xE945, 0x954C, 0xEFD4, 0x954D, 0xC4F8, 0x954E, 0xEFD5, 0x954F, 0xEFD6, 0x9550, 0xB8E4, 0x9551, 0xB0F7, 0x9552, 0xEFD7, 0x9553, 0xEFD8, 0x9554, 0xEFD9, 0x9555, 0xE946, 0x9556, 0xEFDA, 0x9557, 0xEFDB, 0x9558, 0xEFDC, 0x9559, 0xEFDD, 0x955A, 0xE947, 0x955B, 0xEFDE, 0x955C, 0xBEB5, 0x955D, 0xEFE1, 0x955E, 0xEFDF, 0x955F, 0xEFE0, 0x9560, 0xE948, 0x9561, 0xEFE2, 0x9562, 0xEFE3, 0x9563, 0xC1CD, 0x9564, 0xEFE4, 0x9565, 0xEFE5, 0x9566, 0xEFE6, 0x9567, 0xEFE7, 0x9568, 0xEFE8, 0x9569, 0xEFE9, 0x956A, 0xEFEA, 0x956B, 0xEFEB, 0x956C, 0xEFEC, 0x956D, 0xC0D8, 0x956E, 0xE949, 0x956F, 0xEFED, 0x9570, 0xC1AD, 0x9571, 0xEFEE, 0x9572, 0xEFEF, 0x9573, 0xEFF0, 0x9574, 0xE94A, 0x9575, 0xE94B, 0x9576, 0xCFE2, 0x9577, 0xE94C, 0x9578, 0xE94D, 0x9579, 0xE94E, 0x957A, 0xE94F, 0x957B, 0xE950, 0x957C, 0xE951, 0x957D, 0xE952, 0x957E, 0xE953, 0x957F, 0xB3A4, 0x9580, 0xE954, 0x9581, 0xE955, 0x9582, 0xE956, 0x9583, 0xE957, 0x9584, 0xE958, 0x9585, 0xE959, 0x9586, 0xE95A, 0x9587, 0xE95B, 0x9588, 0xE95C, 0x9589, 0xE95D, 0x958A, 0xE95E, 0x958B, 0xE95F, 0x958C, 0xE960, 0x958D, 0xE961, 0x958E, 0xE962, 0x958F, 0xE963, 0x9590, 0xE964, 0x9591, 0xE965, 0x9592, 0xE966, 0x9593, 0xE967, 0x9594, 0xE968, 0x9595, 0xE969, 0x9596, 0xE96A, 0x9597, 0xE96B, 0x9598, 0xE96C, 0x9599, 0xE96D, 0x959A, 0xE96E, 0x959B, 0xE96F, 0x959C, 0xE970, 0x959D, 0xE971, 0x959E, 0xE972, 0x959F, 0xE973, 0x95A0, 0xE974, 0x95A1, 0xE975, 0x95A2, 0xE976, 0x95A3, 0xE977, 0x95A4, 0xE978, 0x95A5, 0xE979, 0x95A6, 0xE97A, 0x95A7, 0xE97B, 0x95A8, 0xE97C, 0x95A9, 0xE97D, 0x95AA, 0xE97E, 0x95AB, 0xE980, 0x95AC, 0xE981, 0x95AD, 0xE982, 0x95AE, 0xE983, 0x95AF, 0xE984, 0x95B0, 0xE985, 0x95B1, 0xE986, 0x95B2, 0xE987, 0x95B3, 0xE988, 0x95B4, 0xE989, 0x95B5, 0xE98A, 0x95B6, 0xE98B, 0x95B7, 0xE98C, 0x95B8, 0xE98D, 0x95B9, 0xE98E, 0x95BA, 0xE98F, 0x95BB, 0xE990, 0x95BC, 0xE991, 0x95BD, 0xE992, 0x95BE, 0xE993, 0x95BF, 0xE994, 0x95C0, 0xE995, 0x95C1, 0xE996, 0x95C2, 0xE997, 0x95C3, 0xE998, 0x95C4, 0xE999, 0x95C5, 0xE99A, 0x95C6, 0xE99B, 0x95C7, 0xE99C, 0x95C8, 0xE99D, 0x95C9, 0xE99E, 0x95CA, 0xE99F, 0x95CB, 0xE9A0, 0x95CC, 0xEA40, 0x95CD, 0xEA41, 0x95CE, 0xEA42, 0x95CF, 0xEA43, 0x95D0, 0xEA44, 0x95D1, 0xEA45, 0x95D2, 0xEA46, 0x95D3, 0xEA47, 0x95D4, 0xEA48, 0x95D5, 0xEA49, 0x95D6, 0xEA4A, 0x95D7, 0xEA4B, 0x95D8, 0xEA4C, 0x95D9, 0xEA4D, 0x95DA, 0xEA4E, 0x95DB, 0xEA4F, 0x95DC, 0xEA50, 0x95DD, 0xEA51, 0x95DE, 0xEA52, 0x95DF, 0xEA53, 0x95E0, 0xEA54, 0x95E1, 0xEA55, 0x95E2, 0xEA56, 0x95E3, 0xEA57, 0x95E4, 0xEA58, 0x95E5, 0xEA59, 0x95E6, 0xEA5A, 0x95E7, 0xEA5B, 0x95E8, 0xC3C5, 0x95E9, 0xE3C5, 0x95EA, 0xC9C1, 0x95EB, 0xE3C6, 0x95EC, 0xEA5C, 0x95ED, 0xB1D5, 0x95EE, 0xCECA, 0x95EF, 0xB4B3, 0x95F0, 0xC8F2, 0x95F1, 0xE3C7, 0x95F2, 0xCFD0, 0x95F3, 0xE3C8, 0x95F4, 0xBCE4, 0x95F5, 0xE3C9, 0x95F6, 0xE3CA, 0x95F7, 0xC3C6, 0x95F8, 0xD5A2, 0x95F9, 0xC4D6, 0x95FA, 0xB9EB, 0x95FB, 0xCEC5, 0x95FC, 0xE3CB, 0x95FD, 0xC3F6, 0x95FE, 0xE3CC, 0x95FF, 0xEA5D, 0x9600, 0xB7A7, 0x9601, 0xB8F3, 0x9602, 0xBAD2, 0x9603, 0xE3CD, 0x9604, 0xE3CE, 0x9605, 0xD4C4, 0x9606, 0xE3CF, 0x9607, 0xEA5E, 0x9608, 0xE3D0, 0x9609, 0xD1CB, 0x960A, 0xE3D1, 0x960B, 0xE3D2, 0x960C, 0xE3D3, 0x960D, 0xE3D4, 0x960E, 0xD1D6, 0x960F, 0xE3D5, 0x9610, 0xB2FB, 0x9611, 0xC0BB, 0x9612, 0xE3D6, 0x9613, 0xEA5F, 0x9614, 0xC0AB, 0x9615, 0xE3D7, 0x9616, 0xE3D8, 0x9617, 0xE3D9, 0x9618, 0xEA60, 0x9619, 0xE3DA, 0x961A, 0xE3DB, 0x961B, 0xEA61, 0x961C, 0xB8B7, 0x961D, 0xDAE2, 0x961E, 0xEA62, 0x961F, 0xB6D3, 0x9620, 0xEA63, 0x9621, 0xDAE4, 0x9622, 0xDAE3, 0x9623, 0xEA64, 0x9624, 0xEA65, 0x9625, 0xEA66, 0x9626, 0xEA67, 0x9627, 0xEA68, 0x9628, 0xEA69, 0x9629, 0xEA6A, 0x962A, 0xDAE6, 0x962B, 0xEA6B, 0x962C, 0xEA6C, 0x962D, 0xEA6D, 0x962E, 0xC8EE, 0x962F, 0xEA6E, 0x9630, 0xEA6F, 0x9631, 0xDAE5, 0x9632, 0xB7C0, 0x9633, 0xD1F4, 0x9634, 0xD2F5, 0x9635, 0xD5F3, 0x9636, 0xBDD7, 0x9637, 0xEA70, 0x9638, 0xEA71, 0x9639, 0xEA72, 0x963A, 0xEA73, 0x963B, 0xD7E8, 0x963C, 0xDAE8, 0x963D, 0xDAE7, 0x963E, 0xEA74, 0x963F, 0xB0A2, 0x9640, 0xCDD3, 0x9641, 0xEA75, 0x9642, 0xDAE9, 0x9643, 0xEA76, 0x9644, 0xB8BD, 0x9645, 0xBCCA, 0x9646, 0xC2BD, 0x9647, 0xC2A4, 0x9648, 0xB3C2, 0x9649, 0xDAEA, 0x964A, 0xEA77, 0x964B, 0xC2AA, 0x964C, 0xC4B0, 0x964D, 0xBDB5, 0x964E, 0xEA78, 0x964F, 0xEA79, 0x9650, 0xCFDE, 0x9651, 0xEA7A, 0x9652, 0xEA7B, 0x9653, 0xEA7C, 0x9654, 0xDAEB, 0x9655, 0xC9C2, 0x9656, 0xEA7D, 0x9657, 0xEA7E, 0x9658, 0xEA80, 0x9659, 0xEA81, 0x965A, 0xEA82, 0x965B, 0xB1DD, 0x965C, 0xEA83, 0x965D, 0xEA84, 0x965E, 0xEA85, 0x965F, 0xDAEC, 0x9660, 0xEA86, 0x9661, 0xB6B8, 0x9662, 0xD4BA, 0x9663, 0xEA87, 0x9664, 0xB3FD, 0x9665, 0xEA88, 0x9666, 0xEA89, 0x9667, 0xDAED, 0x9668, 0xD4C9, 0x9669, 0xCFD5, 0x966A, 0xC5E3, 0x966B, 0xEA8A, 0x966C, 0xDAEE, 0x966D, 0xEA8B, 0x966E, 0xEA8C, 0x966F, 0xEA8D, 0x9670, 0xEA8E, 0x9671, 0xEA8F, 0x9672, 0xDAEF, 0x9673, 0xEA90, 0x9674, 0xDAF0, 0x9675, 0xC1EA, 0x9676, 0xCCD5, 0x9677, 0xCFDD, 0x9678, 0xEA91, 0x9679, 0xEA92, 0x967A, 0xEA93, 0x967B, 0xEA94, 0x967C, 0xEA95, 0x967D, 0xEA96, 0x967E, 0xEA97, 0x967F, 0xEA98, 0x9680, 0xEA99, 0x9681, 0xEA9A, 0x9682, 0xEA9B, 0x9683, 0xEA9C, 0x9684, 0xEA9D, 0x9685, 0xD3E7, 0x9686, 0xC2A1, 0x9687, 0xEA9E, 0x9688, 0xDAF1, 0x9689, 0xEA9F, 0x968A, 0xEAA0, 0x968B, 0xCBE5, 0x968C, 0xEB40, 0x968D, 0xDAF2, 0x968E, 0xEB41, 0x968F, 0xCBE6, 0x9690, 0xD2FE, 0x9691, 0xEB42, 0x9692, 0xEB43, 0x9693, 0xEB44, 0x9694, 0xB8F4, 0x9695, 0xEB45, 0x9696, 0xEB46, 0x9697, 0xDAF3, 0x9698, 0xB0AF, 0x9699, 0xCFB6, 0x969A, 0xEB47, 0x969B, 0xEB48, 0x969C, 0xD5CF, 0x969D, 0xEB49, 0x969E, 0xEB4A, 0x969F, 0xEB4B, 0x96A0, 0xEB4C, 0x96A1, 0xEB4D, 0x96A2, 0xEB4E, 0x96A3, 0xEB4F, 0x96A4, 0xEB50, 0x96A5, 0xEB51, 0x96A6, 0xEB52, 0x96A7, 0xCBED, 0x96A8, 0xEB53, 0x96A9, 0xEB54, 0x96AA, 0xEB55, 0x96AB, 0xEB56, 0x96AC, 0xEB57, 0x96AD, 0xEB58, 0x96AE, 0xEB59, 0x96AF, 0xEB5A, 0x96B0, 0xDAF4, 0x96B1, 0xEB5B, 0x96B2, 0xEB5C, 0x96B3, 0xE3C4, 0x96B4, 0xEB5D, 0x96B5, 0xEB5E, 0x96B6, 0xC1A5, 0x96B7, 0xEB5F, 0x96B8, 0xEB60, 0x96B9, 0xF6BF, 0x96BA, 0xEB61, 0x96BB, 0xEB62, 0x96BC, 0xF6C0, 0x96BD, 0xF6C1, 0x96BE, 0xC4D1, 0x96BF, 0xEB63, 0x96C0, 0xC8B8, 0x96C1, 0xD1E3, 0x96C2, 0xEB64, 0x96C3, 0xEB65, 0x96C4, 0xD0DB, 0x96C5, 0xD1C5, 0x96C6, 0xBCAF, 0x96C7, 0xB9CD, 0x96C8, 0xEB66, 0x96C9, 0xEFF4, 0x96CA, 0xEB67, 0x96CB, 0xEB68, 0x96CC, 0xB4C6, 0x96CD, 0xD3BA, 0x96CE, 0xF6C2, 0x96CF, 0xB3FB, 0x96D0, 0xEB69, 0x96D1, 0xEB6A, 0x96D2, 0xF6C3, 0x96D3, 0xEB6B, 0x96D4, 0xEB6C, 0x96D5, 0xB5F1, 0x96D6, 0xEB6D, 0x96D7, 0xEB6E, 0x96D8, 0xEB6F, 0x96D9, 0xEB70, 0x96DA, 0xEB71, 0x96DB, 0xEB72, 0x96DC, 0xEB73, 0x96DD, 0xEB74, 0x96DE, 0xEB75, 0x96DF, 0xEB76, 0x96E0, 0xF6C5, 0x96E1, 0xEB77, 0x96E2, 0xEB78, 0x96E3, 0xEB79, 0x96E4, 0xEB7A, 0x96E5, 0xEB7B, 0x96E6, 0xEB7C, 0x96E7, 0xEB7D, 0x96E8, 0xD3EA, 0x96E9, 0xF6A7, 0x96EA, 0xD1A9, 0x96EB, 0xEB7E, 0x96EC, 0xEB80, 0x96ED, 0xEB81, 0x96EE, 0xEB82, 0x96EF, 0xF6A9, 0x96F0, 0xEB83, 0x96F1, 0xEB84, 0x96F2, 0xEB85, 0x96F3, 0xF6A8, 0x96F4, 0xEB86, 0x96F5, 0xEB87, 0x96F6, 0xC1E3, 0x96F7, 0xC0D7, 0x96F8, 0xEB88, 0x96F9, 0xB1A2, 0x96FA, 0xEB89, 0x96FB, 0xEB8A, 0x96FC, 0xEB8B, 0x96FD, 0xEB8C, 0x96FE, 0xCEED, 0x96FF, 0xEB8D, 0x9700, 0xD0E8, 0x9701, 0xF6AB, 0x9702, 0xEB8E, 0x9703, 0xEB8F, 0x9704, 0xCFF6, 0x9705, 0xEB90, 0x9706, 0xF6AA, 0x9707, 0xD5F0, 0x9708, 0xF6AC, 0x9709, 0xC3B9, 0x970A, 0xEB91, 0x970B, 0xEB92, 0x970C, 0xEB93, 0x970D, 0xBBF4, 0x970E, 0xF6AE, 0x970F, 0xF6AD, 0x9710, 0xEB94, 0x9711, 0xEB95, 0x9712, 0xEB96, 0x9713, 0xC4DE, 0x9714, 0xEB97, 0x9715, 0xEB98, 0x9716, 0xC1D8, 0x9717, 0xEB99, 0x9718, 0xEB9A, 0x9719, 0xEB9B, 0x971A, 0xEB9C, 0x971B, 0xEB9D, 0x971C, 0xCBAA, 0x971D, 0xEB9E, 0x971E, 0xCFBC, 0x971F, 0xEB9F, 0x9720, 0xEBA0, 0x9721, 0xEC40, 0x9722, 0xEC41, 0x9723, 0xEC42, 0x9724, 0xEC43, 0x9725, 0xEC44, 0x9726, 0xEC45, 0x9727, 0xEC46, 0x9728, 0xEC47, 0x9729, 0xEC48, 0x972A, 0xF6AF, 0x972B, 0xEC49, 0x972C, 0xEC4A, 0x972D, 0xF6B0, 0x972E, 0xEC4B, 0x972F, 0xEC4C, 0x9730, 0xF6B1, 0x9731, 0xEC4D, 0x9732, 0xC2B6, 0x9733, 0xEC4E, 0x9734, 0xEC4F, 0x9735, 0xEC50, 0x9736, 0xEC51, 0x9737, 0xEC52, 0x9738, 0xB0D4, 0x9739, 0xC5F9, 0x973A, 0xEC53, 0x973B, 0xEC54, 0x973C, 0xEC55, 0x973D, 0xEC56, 0x973E, 0xF6B2, 0x973F, 0xEC57, 0x9740, 0xEC58, 0x9741, 0xEC59, 0x9742, 0xEC5A, 0x9743, 0xEC5B, 0x9744, 0xEC5C, 0x9745, 0xEC5D, 0x9746, 0xEC5E, 0x9747, 0xEC5F, 0x9748, 0xEC60, 0x9749, 0xEC61, 0x974A, 0xEC62, 0x974B, 0xEC63, 0x974C, 0xEC64, 0x974D, 0xEC65, 0x974E, 0xEC66, 0x974F, 0xEC67, 0x9750, 0xEC68, 0x9751, 0xEC69, 0x9752, 0xC7E0, 0x9753, 0xF6A6, 0x9754, 0xEC6A, 0x9755, 0xEC6B, 0x9756, 0xBEB8, 0x9757, 0xEC6C, 0x9758, 0xEC6D, 0x9759, 0xBEB2, 0x975A, 0xEC6E, 0x975B, 0xB5E5, 0x975C, 0xEC6F, 0x975D, 0xEC70, 0x975E, 0xB7C7, 0x975F, 0xEC71, 0x9760, 0xBFBF, 0x9761, 0xC3D2, 0x9762, 0xC3E6, 0x9763, 0xEC72, 0x9764, 0xEC73, 0x9765, 0xD8CC, 0x9766, 0xEC74, 0x9767, 0xEC75, 0x9768, 0xEC76, 0x9769, 0xB8EF, 0x976A, 0xEC77, 0x976B, 0xEC78, 0x976C, 0xEC79, 0x976D, 0xEC7A, 0x976E, 0xEC7B, 0x976F, 0xEC7C, 0x9770, 0xEC7D, 0x9771, 0xEC7E, 0x9772, 0xEC80, 0x9773, 0xBDF9, 0x9774, 0xD1A5, 0x9775, 0xEC81, 0x9776, 0xB0D0, 0x9777, 0xEC82, 0x9778, 0xEC83, 0x9779, 0xEC84, 0x977A, 0xEC85, 0x977B, 0xEC86, 0x977C, 0xF7B0, 0x977D, 0xEC87, 0x977E, 0xEC88, 0x977F, 0xEC89, 0x9780, 0xEC8A, 0x9781, 0xEC8B, 0x9782, 0xEC8C, 0x9783, 0xEC8D, 0x9784, 0xEC8E, 0x9785, 0xF7B1, 0x9786, 0xEC8F, 0x9787, 0xEC90, 0x9788, 0xEC91, 0x9789, 0xEC92, 0x978A, 0xEC93, 0x978B, 0xD0AC, 0x978C, 0xEC94, 0x978D, 0xB0B0, 0x978E, 0xEC95, 0x978F, 0xEC96, 0x9790, 0xEC97, 0x9791, 0xF7B2, 0x9792, 0xF7B3, 0x9793, 0xEC98, 0x9794, 0xF7B4, 0x9795, 0xEC99, 0x9796, 0xEC9A, 0x9797, 0xEC9B, 0x9798, 0xC7CA, 0x9799, 0xEC9C, 0x979A, 0xEC9D, 0x979B, 0xEC9E, 0x979C, 0xEC9F, 0x979D, 0xECA0, 0x979E, 0xED40, 0x979F, 0xED41, 0x97A0, 0xBECF, 0x97A1, 0xED42, 0x97A2, 0xED43, 0x97A3, 0xF7B7, 0x97A4, 0xED44, 0x97A5, 0xED45, 0x97A6, 0xED46, 0x97A7, 0xED47, 0x97A8, 0xED48, 0x97A9, 0xED49, 0x97AA, 0xED4A, 0x97AB, 0xF7B6, 0x97AC, 0xED4B, 0x97AD, 0xB1DE, 0x97AE, 0xED4C, 0x97AF, 0xF7B5, 0x97B0, 0xED4D, 0x97B1, 0xED4E, 0x97B2, 0xF7B8, 0x97B3, 0xED4F, 0x97B4, 0xF7B9, 0x97B5, 0xED50, 0x97B6, 0xED51, 0x97B7, 0xED52, 0x97B8, 0xED53, 0x97B9, 0xED54, 0x97BA, 0xED55, 0x97BB, 0xED56, 0x97BC, 0xED57, 0x97BD, 0xED58, 0x97BE, 0xED59, 0x97BF, 0xED5A, 0x97C0, 0xED5B, 0x97C1, 0xED5C, 0x97C2, 0xED5D, 0x97C3, 0xED5E, 0x97C4, 0xED5F, 0x97C5, 0xED60, 0x97C6, 0xED61, 0x97C7, 0xED62, 0x97C8, 0xED63, 0x97C9, 0xED64, 0x97CA, 0xED65, 0x97CB, 0xED66, 0x97CC, 0xED67, 0x97CD, 0xED68, 0x97CE, 0xED69, 0x97CF, 0xED6A, 0x97D0, 0xED6B, 0x97D1, 0xED6C, 0x97D2, 0xED6D, 0x97D3, 0xED6E, 0x97D4, 0xED6F, 0x97D5, 0xED70, 0x97D6, 0xED71, 0x97D7, 0xED72, 0x97D8, 0xED73, 0x97D9, 0xED74, 0x97DA, 0xED75, 0x97DB, 0xED76, 0x97DC, 0xED77, 0x97DD, 0xED78, 0x97DE, 0xED79, 0x97DF, 0xED7A, 0x97E0, 0xED7B, 0x97E1, 0xED7C, 0x97E2, 0xED7D, 0x97E3, 0xED7E, 0x97E4, 0xED80, 0x97E5, 0xED81, 0x97E6, 0xCEA4, 0x97E7, 0xC8CD, 0x97E8, 0xED82, 0x97E9, 0xBAAB, 0x97EA, 0xE8B8, 0x97EB, 0xE8B9, 0x97EC, 0xE8BA, 0x97ED, 0xBEC2, 0x97EE, 0xED83, 0x97EF, 0xED84, 0x97F0, 0xED85, 0x97F1, 0xED86, 0x97F2, 0xED87, 0x97F3, 0xD2F4, 0x97F4, 0xED88, 0x97F5, 0xD4CF, 0x97F6, 0xC9D8, 0x97F7, 0xED89, 0x97F8, 0xED8A, 0x97F9, 0xED8B, 0x97FA, 0xED8C, 0x97FB, 0xED8D, 0x97FC, 0xED8E, 0x97FD, 0xED8F, 0x97FE, 0xED90, 0x97FF, 0xED91, 0x9800, 0xED92, 0x9801, 0xED93, 0x9802, 0xED94, 0x9803, 0xED95, 0x9804, 0xED96, 0x9805, 0xED97, 0x9806, 0xED98, 0x9807, 0xED99, 0x9808, 0xED9A, 0x9809, 0xED9B, 0x980A, 0xED9C, 0x980B, 0xED9D, 0x980C, 0xED9E, 0x980D, 0xED9F, 0x980E, 0xEDA0, 0x980F, 0xEE40, 0x9810, 0xEE41, 0x9811, 0xEE42, 0x9812, 0xEE43, 0x9813, 0xEE44, 0x9814, 0xEE45, 0x9815, 0xEE46, 0x9816, 0xEE47, 0x9817, 0xEE48, 0x9818, 0xEE49, 0x9819, 0xEE4A, 0x981A, 0xEE4B, 0x981B, 0xEE4C, 0x981C, 0xEE4D, 0x981D, 0xEE4E, 0x981E, 0xEE4F, 0x981F, 0xEE50, 0x9820, 0xEE51, 0x9821, 0xEE52, 0x9822, 0xEE53, 0x9823, 0xEE54, 0x9824, 0xEE55, 0x9825, 0xEE56, 0x9826, 0xEE57, 0x9827, 0xEE58, 0x9828, 0xEE59, 0x9829, 0xEE5A, 0x982A, 0xEE5B, 0x982B, 0xEE5C, 0x982C, 0xEE5D, 0x982D, 0xEE5E, 0x982E, 0xEE5F, 0x982F, 0xEE60, 0x9830, 0xEE61, 0x9831, 0xEE62, 0x9832, 0xEE63, 0x9833, 0xEE64, 0x9834, 0xEE65, 0x9835, 0xEE66, 0x9836, 0xEE67, 0x9837, 0xEE68, 0x9838, 0xEE69, 0x9839, 0xEE6A, 0x983A, 0xEE6B, 0x983B, 0xEE6C, 0x983C, 0xEE6D, 0x983D, 0xEE6E, 0x983E, 0xEE6F, 0x983F, 0xEE70, 0x9840, 0xEE71, 0x9841, 0xEE72, 0x9842, 0xEE73, 0x9843, 0xEE74, 0x9844, 0xEE75, 0x9845, 0xEE76, 0x9846, 0xEE77, 0x9847, 0xEE78, 0x9848, 0xEE79, 0x9849, 0xEE7A, 0x984A, 0xEE7B, 0x984B, 0xEE7C, 0x984C, 0xEE7D, 0x984D, 0xEE7E, 0x984E, 0xEE80, 0x984F, 0xEE81, 0x9850, 0xEE82, 0x9851, 0xEE83, 0x9852, 0xEE84, 0x9853, 0xEE85, 0x9854, 0xEE86, 0x9855, 0xEE87, 0x9856, 0xEE88, 0x9857, 0xEE89, 0x9858, 0xEE8A, 0x9859, 0xEE8B, 0x985A, 0xEE8C, 0x985B, 0xEE8D, 0x985C, 0xEE8E, 0x985D, 0xEE8F, 0x985E, 0xEE90, 0x985F, 0xEE91, 0x9860, 0xEE92, 0x9861, 0xEE93, 0x9862, 0xEE94, 0x9863, 0xEE95, 0x9864, 0xEE96, 0x9865, 0xEE97, 0x9866, 0xEE98, 0x9867, 0xEE99, 0x9868, 0xEE9A, 0x9869, 0xEE9B, 0x986A, 0xEE9C, 0x986B, 0xEE9D, 0x986C, 0xEE9E, 0x986D, 0xEE9F, 0x986E, 0xEEA0, 0x986F, 0xEF40, 0x9870, 0xEF41, 0x9871, 0xEF42, 0x9872, 0xEF43, 0x9873, 0xEF44, 0x9874, 0xEF45, 0x9875, 0xD2B3, 0x9876, 0xB6A5, 0x9877, 0xC7EA, 0x9878, 0xF1FC, 0x9879, 0xCFEE, 0x987A, 0xCBB3, 0x987B, 0xD0EB, 0x987C, 0xE7EF, 0x987D, 0xCDE7, 0x987E, 0xB9CB, 0x987F, 0xB6D9, 0x9880, 0xF1FD, 0x9881, 0xB0E4, 0x9882, 0xCBCC, 0x9883, 0xF1FE, 0x9884, 0xD4A4, 0x9885, 0xC2AD, 0x9886, 0xC1EC, 0x9887, 0xC6C4, 0x9888, 0xBEB1, 0x9889, 0xF2A1, 0x988A, 0xBCD5, 0x988B, 0xEF46, 0x988C, 0xF2A2, 0x988D, 0xF2A3, 0x988E, 0xEF47, 0x988F, 0xF2A4, 0x9890, 0xD2C3, 0x9891, 0xC6B5, 0x9892, 0xEF48, 0x9893, 0xCDC7, 0x9894, 0xF2A5, 0x9895, 0xEF49, 0x9896, 0xD3B1, 0x9897, 0xBFC5, 0x9898, 0xCCE2, 0x9899, 0xEF4A, 0x989A, 0xF2A6, 0x989B, 0xF2A7, 0x989C, 0xD1D5, 0x989D, 0xB6EE, 0x989E, 0xF2A8, 0x989F, 0xF2A9, 0x98A0, 0xB5DF, 0x98A1, 0xF2AA, 0x98A2, 0xF2AB, 0x98A3, 0xEF4B, 0x98A4, 0xB2FC, 0x98A5, 0xF2AC, 0x98A6, 0xF2AD, 0x98A7, 0xC8A7, 0x98A8, 0xEF4C, 0x98A9, 0xEF4D, 0x98AA, 0xEF4E, 0x98AB, 0xEF4F, 0x98AC, 0xEF50, 0x98AD, 0xEF51, 0x98AE, 0xEF52, 0x98AF, 0xEF53, 0x98B0, 0xEF54, 0x98B1, 0xEF55, 0x98B2, 0xEF56, 0x98B3, 0xEF57, 0x98B4, 0xEF58, 0x98B5, 0xEF59, 0x98B6, 0xEF5A, 0x98B7, 0xEF5B, 0x98B8, 0xEF5C, 0x98B9, 0xEF5D, 0x98BA, 0xEF5E, 0x98BB, 0xEF5F, 0x98BC, 0xEF60, 0x98BD, 0xEF61, 0x98BE, 0xEF62, 0x98BF, 0xEF63, 0x98C0, 0xEF64, 0x98C1, 0xEF65, 0x98C2, 0xEF66, 0x98C3, 0xEF67, 0x98C4, 0xEF68, 0x98C5, 0xEF69, 0x98C6, 0xEF6A, 0x98C7, 0xEF6B, 0x98C8, 0xEF6C, 0x98C9, 0xEF6D, 0x98CA, 0xEF6E, 0x98CB, 0xEF6F, 0x98CC, 0xEF70, 0x98CD, 0xEF71, 0x98CE, 0xB7E7, 0x98CF, 0xEF72, 0x98D0, 0xEF73, 0x98D1, 0xECA9, 0x98D2, 0xECAA, 0x98D3, 0xECAB, 0x98D4, 0xEF74, 0x98D5, 0xECAC, 0x98D6, 0xEF75, 0x98D7, 0xEF76, 0x98D8, 0xC6AE, 0x98D9, 0xECAD, 0x98DA, 0xECAE, 0x98DB, 0xEF77, 0x98DC, 0xEF78, 0x98DD, 0xEF79, 0x98DE, 0xB7C9, 0x98DF, 0xCAB3, 0x98E0, 0xEF7A, 0x98E1, 0xEF7B, 0x98E2, 0xEF7C, 0x98E3, 0xEF7D, 0x98E4, 0xEF7E, 0x98E5, 0xEF80, 0x98E6, 0xEF81, 0x98E7, 0xE2B8, 0x98E8, 0xF7CF, 0x98E9, 0xEF82, 0x98EA, 0xEF83, 0x98EB, 0xEF84, 0x98EC, 0xEF85, 0x98ED, 0xEF86, 0x98EE, 0xEF87, 0x98EF, 0xEF88, 0x98F0, 0xEF89, 0x98F1, 0xEF8A, 0x98F2, 0xEF8B, 0x98F3, 0xEF8C, 0x98F4, 0xEF8D, 0x98F5, 0xEF8E, 0x98F6, 0xEF8F, 0x98F7, 0xEF90, 0x98F8, 0xEF91, 0x98F9, 0xEF92, 0x98FA, 0xEF93, 0x98FB, 0xEF94, 0x98FC, 0xEF95, 0x98FD, 0xEF96, 0x98FE, 0xEF97, 0x98FF, 0xEF98, 0x9900, 0xEF99, 0x9901, 0xEF9A, 0x9902, 0xEF9B, 0x9903, 0xEF9C, 0x9904, 0xEF9D, 0x9905, 0xEF9E, 0x9906, 0xEF9F, 0x9907, 0xEFA0, 0x9908, 0xF040, 0x9909, 0xF041, 0x990A, 0xF042, 0x990B, 0xF043, 0x990C, 0xF044, 0x990D, 0xF7D0, 0x990E, 0xF045, 0x990F, 0xF046, 0x9910, 0xB2CD, 0x9911, 0xF047, 0x9912, 0xF048, 0x9913, 0xF049, 0x9914, 0xF04A, 0x9915, 0xF04B, 0x9916, 0xF04C, 0x9917, 0xF04D, 0x9918, 0xF04E, 0x9919, 0xF04F, 0x991A, 0xF050, 0x991B, 0xF051, 0x991C, 0xF052, 0x991D, 0xF053, 0x991E, 0xF054, 0x991F, 0xF055, 0x9920, 0xF056, 0x9921, 0xF057, 0x9922, 0xF058, 0x9923, 0xF059, 0x9924, 0xF05A, 0x9925, 0xF05B, 0x9926, 0xF05C, 0x9927, 0xF05D, 0x9928, 0xF05E, 0x9929, 0xF05F, 0x992A, 0xF060, 0x992B, 0xF061, 0x992C, 0xF062, 0x992D, 0xF063, 0x992E, 0xF7D1, 0x992F, 0xF064, 0x9930, 0xF065, 0x9931, 0xF066, 0x9932, 0xF067, 0x9933, 0xF068, 0x9934, 0xF069, 0x9935, 0xF06A, 0x9936, 0xF06B, 0x9937, 0xF06C, 0x9938, 0xF06D, 0x9939, 0xF06E, 0x993A, 0xF06F, 0x993B, 0xF070, 0x993C, 0xF071, 0x993D, 0xF072, 0x993E, 0xF073, 0x993F, 0xF074, 0x9940, 0xF075, 0x9941, 0xF076, 0x9942, 0xF077, 0x9943, 0xF078, 0x9944, 0xF079, 0x9945, 0xF07A, 0x9946, 0xF07B, 0x9947, 0xF07C, 0x9948, 0xF07D, 0x9949, 0xF07E, 0x994A, 0xF080, 0x994B, 0xF081, 0x994C, 0xF082, 0x994D, 0xF083, 0x994E, 0xF084, 0x994F, 0xF085, 0x9950, 0xF086, 0x9951, 0xF087, 0x9952, 0xF088, 0x9953, 0xF089, 0x9954, 0xF7D3, 0x9955, 0xF7D2, 0x9956, 0xF08A, 0x9957, 0xF08B, 0x9958, 0xF08C, 0x9959, 0xF08D, 0x995A, 0xF08E, 0x995B, 0xF08F, 0x995C, 0xF090, 0x995D, 0xF091, 0x995E, 0xF092, 0x995F, 0xF093, 0x9960, 0xF094, 0x9961, 0xF095, 0x9962, 0xF096, 0x9963, 0xE2BB, 0x9964, 0xF097, 0x9965, 0xBCA2, 0x9966, 0xF098, 0x9967, 0xE2BC, 0x9968, 0xE2BD, 0x9969, 0xE2BE, 0x996A, 0xE2BF, 0x996B, 0xE2C0, 0x996C, 0xE2C1, 0x996D, 0xB7B9, 0x996E, 0xD2FB, 0x996F, 0xBDA4, 0x9970, 0xCACE, 0x9971, 0xB1A5, 0x9972, 0xCBC7, 0x9973, 0xF099, 0x9974, 0xE2C2, 0x9975, 0xB6FC, 0x9976, 0xC8C4, 0x9977, 0xE2C3, 0x9978, 0xF09A, 0x9979, 0xF09B, 0x997A, 0xBDC8, 0x997B, 0xF09C, 0x997C, 0xB1FD, 0x997D, 0xE2C4, 0x997E, 0xF09D, 0x997F, 0xB6F6, 0x9980, 0xE2C5, 0x9981, 0xC4D9, 0x9982, 0xF09E, 0x9983, 0xF09F, 0x9984, 0xE2C6, 0x9985, 0xCFDA, 0x9986, 0xB9DD, 0x9987, 0xE2C7, 0x9988, 0xC0A1, 0x9989, 0xF0A0, 0x998A, 0xE2C8, 0x998B, 0xB2F6, 0x998C, 0xF140, 0x998D, 0xE2C9, 0x998E, 0xF141, 0x998F, 0xC1F3, 0x9990, 0xE2CA, 0x9991, 0xE2CB, 0x9992, 0xC2F8, 0x9993, 0xE2CC, 0x9994, 0xE2CD, 0x9995, 0xE2CE, 0x9996, 0xCAD7, 0x9997, 0xD8B8, 0x9998, 0xD9E5, 0x9999, 0xCFE3, 0x999A, 0xF142, 0x999B, 0xF143, 0x999C, 0xF144, 0x999D, 0xF145, 0x999E, 0xF146, 0x999F, 0xF147, 0x99A0, 0xF148, 0x99A1, 0xF149, 0x99A2, 0xF14A, 0x99A3, 0xF14B, 0x99A4, 0xF14C, 0x99A5, 0xF0A5, 0x99A6, 0xF14D, 0x99A7, 0xF14E, 0x99A8, 0xDCB0, 0x99A9, 0xF14F, 0x99AA, 0xF150, 0x99AB, 0xF151, 0x99AC, 0xF152, 0x99AD, 0xF153, 0x99AE, 0xF154, 0x99AF, 0xF155, 0x99B0, 0xF156, 0x99B1, 0xF157, 0x99B2, 0xF158, 0x99B3, 0xF159, 0x99B4, 0xF15A, 0x99B5, 0xF15B, 0x99B6, 0xF15C, 0x99B7, 0xF15D, 0x99B8, 0xF15E, 0x99B9, 0xF15F, 0x99BA, 0xF160, 0x99BB, 0xF161, 0x99BC, 0xF162, 0x99BD, 0xF163, 0x99BE, 0xF164, 0x99BF, 0xF165, 0x99C0, 0xF166, 0x99C1, 0xF167, 0x99C2, 0xF168, 0x99C3, 0xF169, 0x99C4, 0xF16A, 0x99C5, 0xF16B, 0x99C6, 0xF16C, 0x99C7, 0xF16D, 0x99C8, 0xF16E, 0x99C9, 0xF16F, 0x99CA, 0xF170, 0x99CB, 0xF171, 0x99CC, 0xF172, 0x99CD, 0xF173, 0x99CE, 0xF174, 0x99CF, 0xF175, 0x99D0, 0xF176, 0x99D1, 0xF177, 0x99D2, 0xF178, 0x99D3, 0xF179, 0x99D4, 0xF17A, 0x99D5, 0xF17B, 0x99D6, 0xF17C, 0x99D7, 0xF17D, 0x99D8, 0xF17E, 0x99D9, 0xF180, 0x99DA, 0xF181, 0x99DB, 0xF182, 0x99DC, 0xF183, 0x99DD, 0xF184, 0x99DE, 0xF185, 0x99DF, 0xF186, 0x99E0, 0xF187, 0x99E1, 0xF188, 0x99E2, 0xF189, 0x99E3, 0xF18A, 0x99E4, 0xF18B, 0x99E5, 0xF18C, 0x99E6, 0xF18D, 0x99E7, 0xF18E, 0x99E8, 0xF18F, 0x99E9, 0xF190, 0x99EA, 0xF191, 0x99EB, 0xF192, 0x99EC, 0xF193, 0x99ED, 0xF194, 0x99EE, 0xF195, 0x99EF, 0xF196, 0x99F0, 0xF197, 0x99F1, 0xF198, 0x99F2, 0xF199, 0x99F3, 0xF19A, 0x99F4, 0xF19B, 0x99F5, 0xF19C, 0x99F6, 0xF19D, 0x99F7, 0xF19E, 0x99F8, 0xF19F, 0x99F9, 0xF1A0, 0x99FA, 0xF240, 0x99FB, 0xF241, 0x99FC, 0xF242, 0x99FD, 0xF243, 0x99FE, 0xF244, 0x99FF, 0xF245, 0x9A00, 0xF246, 0x9A01, 0xF247, 0x9A02, 0xF248, 0x9A03, 0xF249, 0x9A04, 0xF24A, 0x9A05, 0xF24B, 0x9A06, 0xF24C, 0x9A07, 0xF24D, 0x9A08, 0xF24E, 0x9A09, 0xF24F, 0x9A0A, 0xF250, 0x9A0B, 0xF251, 0x9A0C, 0xF252, 0x9A0D, 0xF253, 0x9A0E, 0xF254, 0x9A0F, 0xF255, 0x9A10, 0xF256, 0x9A11, 0xF257, 0x9A12, 0xF258, 0x9A13, 0xF259, 0x9A14, 0xF25A, 0x9A15, 0xF25B, 0x9A16, 0xF25C, 0x9A17, 0xF25D, 0x9A18, 0xF25E, 0x9A19, 0xF25F, 0x9A1A, 0xF260, 0x9A1B, 0xF261, 0x9A1C, 0xF262, 0x9A1D, 0xF263, 0x9A1E, 0xF264, 0x9A1F, 0xF265, 0x9A20, 0xF266, 0x9A21, 0xF267, 0x9A22, 0xF268, 0x9A23, 0xF269, 0x9A24, 0xF26A, 0x9A25, 0xF26B, 0x9A26, 0xF26C, 0x9A27, 0xF26D, 0x9A28, 0xF26E, 0x9A29, 0xF26F, 0x9A2A, 0xF270, 0x9A2B, 0xF271, 0x9A2C, 0xF272, 0x9A2D, 0xF273, 0x9A2E, 0xF274, 0x9A2F, 0xF275, 0x9A30, 0xF276, 0x9A31, 0xF277, 0x9A32, 0xF278, 0x9A33, 0xF279, 0x9A34, 0xF27A, 0x9A35, 0xF27B, 0x9A36, 0xF27C, 0x9A37, 0xF27D, 0x9A38, 0xF27E, 0x9A39, 0xF280, 0x9A3A, 0xF281, 0x9A3B, 0xF282, 0x9A3C, 0xF283, 0x9A3D, 0xF284, 0x9A3E, 0xF285, 0x9A3F, 0xF286, 0x9A40, 0xF287, 0x9A41, 0xF288, 0x9A42, 0xF289, 0x9A43, 0xF28A, 0x9A44, 0xF28B, 0x9A45, 0xF28C, 0x9A46, 0xF28D, 0x9A47, 0xF28E, 0x9A48, 0xF28F, 0x9A49, 0xF290, 0x9A4A, 0xF291, 0x9A4B, 0xF292, 0x9A4C, 0xF293, 0x9A4D, 0xF294, 0x9A4E, 0xF295, 0x9A4F, 0xF296, 0x9A50, 0xF297, 0x9A51, 0xF298, 0x9A52, 0xF299, 0x9A53, 0xF29A, 0x9A54, 0xF29B, 0x9A55, 0xF29C, 0x9A56, 0xF29D, 0x9A57, 0xF29E, 0x9A58, 0xF29F, 0x9A59, 0xF2A0, 0x9A5A, 0xF340, 0x9A5B, 0xF341, 0x9A5C, 0xF342, 0x9A5D, 0xF343, 0x9A5E, 0xF344, 0x9A5F, 0xF345, 0x9A60, 0xF346, 0x9A61, 0xF347, 0x9A62, 0xF348, 0x9A63, 0xF349, 0x9A64, 0xF34A, 0x9A65, 0xF34B, 0x9A66, 0xF34C, 0x9A67, 0xF34D, 0x9A68, 0xF34E, 0x9A69, 0xF34F, 0x9A6A, 0xF350, 0x9A6B, 0xF351, 0x9A6C, 0xC2ED, 0x9A6D, 0xD4A6, 0x9A6E, 0xCDD4, 0x9A6F, 0xD1B1, 0x9A70, 0xB3DB, 0x9A71, 0xC7FD, 0x9A72, 0xF352, 0x9A73, 0xB2B5, 0x9A74, 0xC2BF, 0x9A75, 0xE6E0, 0x9A76, 0xCABB, 0x9A77, 0xE6E1, 0x9A78, 0xE6E2, 0x9A79, 0xBED4, 0x9A7A, 0xE6E3, 0x9A7B, 0xD7A4, 0x9A7C, 0xCDD5, 0x9A7D, 0xE6E5, 0x9A7E, 0xBCDD, 0x9A7F, 0xE6E4, 0x9A80, 0xE6E6, 0x9A81, 0xE6E7, 0x9A82, 0xC2EE, 0x9A83, 0xF353, 0x9A84, 0xBDBE, 0x9A85, 0xE6E8, 0x9A86, 0xC2E6, 0x9A87, 0xBAA7, 0x9A88, 0xE6E9, 0x9A89, 0xF354, 0x9A8A, 0xE6EA, 0x9A8B, 0xB3D2, 0x9A8C, 0xD1E9, 0x9A8D, 0xF355, 0x9A8E, 0xF356, 0x9A8F, 0xBFA5, 0x9A90, 0xE6EB, 0x9A91, 0xC6EF, 0x9A92, 0xE6EC, 0x9A93, 0xE6ED, 0x9A94, 0xF357, 0x9A95, 0xF358, 0x9A96, 0xE6EE, 0x9A97, 0xC6AD, 0x9A98, 0xE6EF, 0x9A99, 0xF359, 0x9A9A, 0xC9A7, 0x9A9B, 0xE6F0, 0x9A9C, 0xE6F1, 0x9A9D, 0xE6F2, 0x9A9E, 0xE5B9, 0x9A9F, 0xE6F3, 0x9AA0, 0xE6F4, 0x9AA1, 0xC2E2, 0x9AA2, 0xE6F5, 0x9AA3, 0xE6F6, 0x9AA4, 0xD6E8, 0x9AA5, 0xE6F7, 0x9AA6, 0xF35A, 0x9AA7, 0xE6F8, 0x9AA8, 0xB9C7, 0x9AA9, 0xF35B, 0x9AAA, 0xF35C, 0x9AAB, 0xF35D, 0x9AAC, 0xF35E, 0x9AAD, 0xF35F, 0x9AAE, 0xF360, 0x9AAF, 0xF361, 0x9AB0, 0xF7BB, 0x9AB1, 0xF7BA, 0x9AB2, 0xF362, 0x9AB3, 0xF363, 0x9AB4, 0xF364, 0x9AB5, 0xF365, 0x9AB6, 0xF7BE, 0x9AB7, 0xF7BC, 0x9AB8, 0xBAA1, 0x9AB9, 0xF366, 0x9ABA, 0xF7BF, 0x9ABB, 0xF367, 0x9ABC, 0xF7C0, 0x9ABD, 0xF368, 0x9ABE, 0xF369, 0x9ABF, 0xF36A, 0x9AC0, 0xF7C2, 0x9AC1, 0xF7C1, 0x9AC2, 0xF7C4, 0x9AC3, 0xF36B, 0x9AC4, 0xF36C, 0x9AC5, 0xF7C3, 0x9AC6, 0xF36D, 0x9AC7, 0xF36E, 0x9AC8, 0xF36F, 0x9AC9, 0xF370, 0x9ACA, 0xF371, 0x9ACB, 0xF7C5, 0x9ACC, 0xF7C6, 0x9ACD, 0xF372, 0x9ACE, 0xF373, 0x9ACF, 0xF374, 0x9AD0, 0xF375, 0x9AD1, 0xF7C7, 0x9AD2, 0xF376, 0x9AD3, 0xCBE8, 0x9AD4, 0xF377, 0x9AD5, 0xF378, 0x9AD6, 0xF379, 0x9AD7, 0xF37A, 0x9AD8, 0xB8DF, 0x9AD9, 0xF37B, 0x9ADA, 0xF37C, 0x9ADB, 0xF37D, 0x9ADC, 0xF37E, 0x9ADD, 0xF380, 0x9ADE, 0xF381, 0x9ADF, 0xF7D4, 0x9AE0, 0xF382, 0x9AE1, 0xF7D5, 0x9AE2, 0xF383, 0x9AE3, 0xF384, 0x9AE4, 0xF385, 0x9AE5, 0xF386, 0x9AE6, 0xF7D6, 0x9AE7, 0xF387, 0x9AE8, 0xF388, 0x9AE9, 0xF389, 0x9AEA, 0xF38A, 0x9AEB, 0xF7D8, 0x9AEC, 0xF38B, 0x9AED, 0xF7DA, 0x9AEE, 0xF38C, 0x9AEF, 0xF7D7, 0x9AF0, 0xF38D, 0x9AF1, 0xF38E, 0x9AF2, 0xF38F, 0x9AF3, 0xF390, 0x9AF4, 0xF391, 0x9AF5, 0xF392, 0x9AF6, 0xF393, 0x9AF7, 0xF394, 0x9AF8, 0xF395, 0x9AF9, 0xF7DB, 0x9AFA, 0xF396, 0x9AFB, 0xF7D9, 0x9AFC, 0xF397, 0x9AFD, 0xF398, 0x9AFE, 0xF399, 0x9AFF, 0xF39A, 0x9B00, 0xF39B, 0x9B01, 0xF39C, 0x9B02, 0xF39D, 0x9B03, 0xD7D7, 0x9B04, 0xF39E, 0x9B05, 0xF39F, 0x9B06, 0xF3A0, 0x9B07, 0xF440, 0x9B08, 0xF7DC, 0x9B09, 0xF441, 0x9B0A, 0xF442, 0x9B0B, 0xF443, 0x9B0C, 0xF444, 0x9B0D, 0xF445, 0x9B0E, 0xF446, 0x9B0F, 0xF7DD, 0x9B10, 0xF447, 0x9B11, 0xF448, 0x9B12, 0xF449, 0x9B13, 0xF7DE, 0x9B14, 0xF44A, 0x9B15, 0xF44B, 0x9B16, 0xF44C, 0x9B17, 0xF44D, 0x9B18, 0xF44E, 0x9B19, 0xF44F, 0x9B1A, 0xF450, 0x9B1B, 0xF451, 0x9B1C, 0xF452, 0x9B1D, 0xF453, 0x9B1E, 0xF454, 0x9B1F, 0xF7DF, 0x9B20, 0xF455, 0x9B21, 0xF456, 0x9B22, 0xF457, 0x9B23, 0xF7E0, 0x9B24, 0xF458, 0x9B25, 0xF459, 0x9B26, 0xF45A, 0x9B27, 0xF45B, 0x9B28, 0xF45C, 0x9B29, 0xF45D, 0x9B2A, 0xF45E, 0x9B2B, 0xF45F, 0x9B2C, 0xF460, 0x9B2D, 0xF461, 0x9B2E, 0xF462, 0x9B2F, 0xDBCB, 0x9B30, 0xF463, 0x9B31, 0xF464, 0x9B32, 0xD8AA, 0x9B33, 0xF465, 0x9B34, 0xF466, 0x9B35, 0xF467, 0x9B36, 0xF468, 0x9B37, 0xF469, 0x9B38, 0xF46A, 0x9B39, 0xF46B, 0x9B3A, 0xF46C, 0x9B3B, 0xE5F7, 0x9B3C, 0xB9ED, 0x9B3D, 0xF46D, 0x9B3E, 0xF46E, 0x9B3F, 0xF46F, 0x9B40, 0xF470, 0x9B41, 0xBFFD, 0x9B42, 0xBBEA, 0x9B43, 0xF7C9, 0x9B44, 0xC6C7, 0x9B45, 0xF7C8, 0x9B46, 0xF471, 0x9B47, 0xF7CA, 0x9B48, 0xF7CC, 0x9B49, 0xF7CB, 0x9B4A, 0xF472, 0x9B4B, 0xF473, 0x9B4C, 0xF474, 0x9B4D, 0xF7CD, 0x9B4E, 0xF475, 0x9B4F, 0xCEBA, 0x9B50, 0xF476, 0x9B51, 0xF7CE, 0x9B52, 0xF477, 0x9B53, 0xF478, 0x9B54, 0xC4A7, 0x9B55, 0xF479, 0x9B56, 0xF47A, 0x9B57, 0xF47B, 0x9B58, 0xF47C, 0x9B59, 0xF47D, 0x9B5A, 0xF47E, 0x9B5B, 0xF480, 0x9B5C, 0xF481, 0x9B5D, 0xF482, 0x9B5E, 0xF483, 0x9B5F, 0xF484, 0x9B60, 0xF485, 0x9B61, 0xF486, 0x9B62, 0xF487, 0x9B63, 0xF488, 0x9B64, 0xF489, 0x9B65, 0xF48A, 0x9B66, 0xF48B, 0x9B67, 0xF48C, 0x9B68, 0xF48D, 0x9B69, 0xF48E, 0x9B6A, 0xF48F, 0x9B6B, 0xF490, 0x9B6C, 0xF491, 0x9B6D, 0xF492, 0x9B6E, 0xF493, 0x9B6F, 0xF494, 0x9B70, 0xF495, 0x9B71, 0xF496, 0x9B72, 0xF497, 0x9B73, 0xF498, 0x9B74, 0xF499, 0x9B75, 0xF49A, 0x9B76, 0xF49B, 0x9B77, 0xF49C, 0x9B78, 0xF49D, 0x9B79, 0xF49E, 0x9B7A, 0xF49F, 0x9B7B, 0xF4A0, 0x9B7C, 0xF540, 0x9B7D, 0xF541, 0x9B7E, 0xF542, 0x9B7F, 0xF543, 0x9B80, 0xF544, 0x9B81, 0xF545, 0x9B82, 0xF546, 0x9B83, 0xF547, 0x9B84, 0xF548, 0x9B85, 0xF549, 0x9B86, 0xF54A, 0x9B87, 0xF54B, 0x9B88, 0xF54C, 0x9B89, 0xF54D, 0x9B8A, 0xF54E, 0x9B8B, 0xF54F, 0x9B8C, 0xF550, 0x9B8D, 0xF551, 0x9B8E, 0xF552, 0x9B8F, 0xF553, 0x9B90, 0xF554, 0x9B91, 0xF555, 0x9B92, 0xF556, 0x9B93, 0xF557, 0x9B94, 0xF558, 0x9B95, 0xF559, 0x9B96, 0xF55A, 0x9B97, 0xF55B, 0x9B98, 0xF55C, 0x9B99, 0xF55D, 0x9B9A, 0xF55E, 0x9B9B, 0xF55F, 0x9B9C, 0xF560, 0x9B9D, 0xF561, 0x9B9E, 0xF562, 0x9B9F, 0xF563, 0x9BA0, 0xF564, 0x9BA1, 0xF565, 0x9BA2, 0xF566, 0x9BA3, 0xF567, 0x9BA4, 0xF568, 0x9BA5, 0xF569, 0x9BA6, 0xF56A, 0x9BA7, 0xF56B, 0x9BA8, 0xF56C, 0x9BA9, 0xF56D, 0x9BAA, 0xF56E, 0x9BAB, 0xF56F, 0x9BAC, 0xF570, 0x9BAD, 0xF571, 0x9BAE, 0xF572, 0x9BAF, 0xF573, 0x9BB0, 0xF574, 0x9BB1, 0xF575, 0x9BB2, 0xF576, 0x9BB3, 0xF577, 0x9BB4, 0xF578, 0x9BB5, 0xF579, 0x9BB6, 0xF57A, 0x9BB7, 0xF57B, 0x9BB8, 0xF57C, 0x9BB9, 0xF57D, 0x9BBA, 0xF57E, 0x9BBB, 0xF580, 0x9BBC, 0xF581, 0x9BBD, 0xF582, 0x9BBE, 0xF583, 0x9BBF, 0xF584, 0x9BC0, 0xF585, 0x9BC1, 0xF586, 0x9BC2, 0xF587, 0x9BC3, 0xF588, 0x9BC4, 0xF589, 0x9BC5, 0xF58A, 0x9BC6, 0xF58B, 0x9BC7, 0xF58C, 0x9BC8, 0xF58D, 0x9BC9, 0xF58E, 0x9BCA, 0xF58F, 0x9BCB, 0xF590, 0x9BCC, 0xF591, 0x9BCD, 0xF592, 0x9BCE, 0xF593, 0x9BCF, 0xF594, 0x9BD0, 0xF595, 0x9BD1, 0xF596, 0x9BD2, 0xF597, 0x9BD3, 0xF598, 0x9BD4, 0xF599, 0x9BD5, 0xF59A, 0x9BD6, 0xF59B, 0x9BD7, 0xF59C, 0x9BD8, 0xF59D, 0x9BD9, 0xF59E, 0x9BDA, 0xF59F, 0x9BDB, 0xF5A0, 0x9BDC, 0xF640, 0x9BDD, 0xF641, 0x9BDE, 0xF642, 0x9BDF, 0xF643, 0x9BE0, 0xF644, 0x9BE1, 0xF645, 0x9BE2, 0xF646, 0x9BE3, 0xF647, 0x9BE4, 0xF648, 0x9BE5, 0xF649, 0x9BE6, 0xF64A, 0x9BE7, 0xF64B, 0x9BE8, 0xF64C, 0x9BE9, 0xF64D, 0x9BEA, 0xF64E, 0x9BEB, 0xF64F, 0x9BEC, 0xF650, 0x9BED, 0xF651, 0x9BEE, 0xF652, 0x9BEF, 0xF653, 0x9BF0, 0xF654, 0x9BF1, 0xF655, 0x9BF2, 0xF656, 0x9BF3, 0xF657, 0x9BF4, 0xF658, 0x9BF5, 0xF659, 0x9BF6, 0xF65A, 0x9BF7, 0xF65B, 0x9BF8, 0xF65C, 0x9BF9, 0xF65D, 0x9BFA, 0xF65E, 0x9BFB, 0xF65F, 0x9BFC, 0xF660, 0x9BFD, 0xF661, 0x9BFE, 0xF662, 0x9BFF, 0xF663, 0x9C00, 0xF664, 0x9C01, 0xF665, 0x9C02, 0xF666, 0x9C03, 0xF667, 0x9C04, 0xF668, 0x9C05, 0xF669, 0x9C06, 0xF66A, 0x9C07, 0xF66B, 0x9C08, 0xF66C, 0x9C09, 0xF66D, 0x9C0A, 0xF66E, 0x9C0B, 0xF66F, 0x9C0C, 0xF670, 0x9C0D, 0xF671, 0x9C0E, 0xF672, 0x9C0F, 0xF673, 0x9C10, 0xF674, 0x9C11, 0xF675, 0x9C12, 0xF676, 0x9C13, 0xF677, 0x9C14, 0xF678, 0x9C15, 0xF679, 0x9C16, 0xF67A, 0x9C17, 0xF67B, 0x9C18, 0xF67C, 0x9C19, 0xF67D, 0x9C1A, 0xF67E, 0x9C1B, 0xF680, 0x9C1C, 0xF681, 0x9C1D, 0xF682, 0x9C1E, 0xF683, 0x9C1F, 0xF684, 0x9C20, 0xF685, 0x9C21, 0xF686, 0x9C22, 0xF687, 0x9C23, 0xF688, 0x9C24, 0xF689, 0x9C25, 0xF68A, 0x9C26, 0xF68B, 0x9C27, 0xF68C, 0x9C28, 0xF68D, 0x9C29, 0xF68E, 0x9C2A, 0xF68F, 0x9C2B, 0xF690, 0x9C2C, 0xF691, 0x9C2D, 0xF692, 0x9C2E, 0xF693, 0x9C2F, 0xF694, 0x9C30, 0xF695, 0x9C31, 0xF696, 0x9C32, 0xF697, 0x9C33, 0xF698, 0x9C34, 0xF699, 0x9C35, 0xF69A, 0x9C36, 0xF69B, 0x9C37, 0xF69C, 0x9C38, 0xF69D, 0x9C39, 0xF69E, 0x9C3A, 0xF69F, 0x9C3B, 0xF6A0, 0x9C3C, 0xF740, 0x9C3D, 0xF741, 0x9C3E, 0xF742, 0x9C3F, 0xF743, 0x9C40, 0xF744, 0x9C41, 0xF745, 0x9C42, 0xF746, 0x9C43, 0xF747, 0x9C44, 0xF748, 0x9C45, 0xF749, 0x9C46, 0xF74A, 0x9C47, 0xF74B, 0x9C48, 0xF74C, 0x9C49, 0xF74D, 0x9C4A, 0xF74E, 0x9C4B, 0xF74F, 0x9C4C, 0xF750, 0x9C4D, 0xF751, 0x9C4E, 0xF752, 0x9C4F, 0xF753, 0x9C50, 0xF754, 0x9C51, 0xF755, 0x9C52, 0xF756, 0x9C53, 0xF757, 0x9C54, 0xF758, 0x9C55, 0xF759, 0x9C56, 0xF75A, 0x9C57, 0xF75B, 0x9C58, 0xF75C, 0x9C59, 0xF75D, 0x9C5A, 0xF75E, 0x9C5B, 0xF75F, 0x9C5C, 0xF760, 0x9C5D, 0xF761, 0x9C5E, 0xF762, 0x9C5F, 0xF763, 0x9C60, 0xF764, 0x9C61, 0xF765, 0x9C62, 0xF766, 0x9C63, 0xF767, 0x9C64, 0xF768, 0x9C65, 0xF769, 0x9C66, 0xF76A, 0x9C67, 0xF76B, 0x9C68, 0xF76C, 0x9C69, 0xF76D, 0x9C6A, 0xF76E, 0x9C6B, 0xF76F, 0x9C6C, 0xF770, 0x9C6D, 0xF771, 0x9C6E, 0xF772, 0x9C6F, 0xF773, 0x9C70, 0xF774, 0x9C71, 0xF775, 0x9C72, 0xF776, 0x9C73, 0xF777, 0x9C74, 0xF778, 0x9C75, 0xF779, 0x9C76, 0xF77A, 0x9C77, 0xF77B, 0x9C78, 0xF77C, 0x9C79, 0xF77D, 0x9C7A, 0xF77E, 0x9C7B, 0xF780, 0x9C7C, 0xD3E3, 0x9C7D, 0xF781, 0x9C7E, 0xF782, 0x9C7F, 0xF6CF, 0x9C80, 0xF783, 0x9C81, 0xC2B3, 0x9C82, 0xF6D0, 0x9C83, 0xF784, 0x9C84, 0xF785, 0x9C85, 0xF6D1, 0x9C86, 0xF6D2, 0x9C87, 0xF6D3, 0x9C88, 0xF6D4, 0x9C89, 0xF786, 0x9C8A, 0xF787, 0x9C8B, 0xF6D6, 0x9C8C, 0xF788, 0x9C8D, 0xB1AB, 0x9C8E, 0xF6D7, 0x9C8F, 0xF789, 0x9C90, 0xF6D8, 0x9C91, 0xF6D9, 0x9C92, 0xF6DA, 0x9C93, 0xF78A, 0x9C94, 0xF6DB, 0x9C95, 0xF6DC, 0x9C96, 0xF78B, 0x9C97, 0xF78C, 0x9C98, 0xF78D, 0x9C99, 0xF78E, 0x9C9A, 0xF6DD, 0x9C9B, 0xF6DE, 0x9C9C, 0xCFCA, 0x9C9D, 0xF78F, 0x9C9E, 0xF6DF, 0x9C9F, 0xF6E0, 0x9CA0, 0xF6E1, 0x9CA1, 0xF6E2, 0x9CA2, 0xF6E3, 0x9CA3, 0xF6E4, 0x9CA4, 0xC0F0, 0x9CA5, 0xF6E5, 0x9CA6, 0xF6E6, 0x9CA7, 0xF6E7, 0x9CA8, 0xF6E8, 0x9CA9, 0xF6E9, 0x9CAA, 0xF790, 0x9CAB, 0xF6EA, 0x9CAC, 0xF791, 0x9CAD, 0xF6EB, 0x9CAE, 0xF6EC, 0x9CAF, 0xF792, 0x9CB0, 0xF6ED, 0x9CB1, 0xF6EE, 0x9CB2, 0xF6EF, 0x9CB3, 0xF6F0, 0x9CB4, 0xF6F1, 0x9CB5, 0xF6F2, 0x9CB6, 0xF6F3, 0x9CB7, 0xF6F4, 0x9CB8, 0xBEA8, 0x9CB9, 0xF793, 0x9CBA, 0xF6F5, 0x9CBB, 0xF6F6, 0x9CBC, 0xF6F7, 0x9CBD, 0xF6F8, 0x9CBE, 0xF794, 0x9CBF, 0xF795, 0x9CC0, 0xF796, 0x9CC1, 0xF797, 0x9CC2, 0xF798, 0x9CC3, 0xC8FA, 0x9CC4, 0xF6F9, 0x9CC5, 0xF6FA, 0x9CC6, 0xF6FB, 0x9CC7, 0xF6FC, 0x9CC8, 0xF799, 0x9CC9, 0xF79A, 0x9CCA, 0xF6FD, 0x9CCB, 0xF6FE, 0x9CCC, 0xF7A1, 0x9CCD, 0xF7A2, 0x9CCE, 0xF7A3, 0x9CCF, 0xF7A4, 0x9CD0, 0xF7A5, 0x9CD1, 0xF79B, 0x9CD2, 0xF79C, 0x9CD3, 0xF7A6, 0x9CD4, 0xF7A7, 0x9CD5, 0xF7A8, 0x9CD6, 0xB1EE, 0x9CD7, 0xF7A9, 0x9CD8, 0xF7AA, 0x9CD9, 0xF7AB, 0x9CDA, 0xF79D, 0x9CDB, 0xF79E, 0x9CDC, 0xF7AC, 0x9CDD, 0xF7AD, 0x9CDE, 0xC1DB, 0x9CDF, 0xF7AE, 0x9CE0, 0xF79F, 0x9CE1, 0xF7A0, 0x9CE2, 0xF7AF, 0x9CE3, 0xF840, 0x9CE4, 0xF841, 0x9CE5, 0xF842, 0x9CE6, 0xF843, 0x9CE7, 0xF844, 0x9CE8, 0xF845, 0x9CE9, 0xF846, 0x9CEA, 0xF847, 0x9CEB, 0xF848, 0x9CEC, 0xF849, 0x9CED, 0xF84A, 0x9CEE, 0xF84B, 0x9CEF, 0xF84C, 0x9CF0, 0xF84D, 0x9CF1, 0xF84E, 0x9CF2, 0xF84F, 0x9CF3, 0xF850, 0x9CF4, 0xF851, 0x9CF5, 0xF852, 0x9CF6, 0xF853, 0x9CF7, 0xF854, 0x9CF8, 0xF855, 0x9CF9, 0xF856, 0x9CFA, 0xF857, 0x9CFB, 0xF858, 0x9CFC, 0xF859, 0x9CFD, 0xF85A, 0x9CFE, 0xF85B, 0x9CFF, 0xF85C, 0x9D00, 0xF85D, 0x9D01, 0xF85E, 0x9D02, 0xF85F, 0x9D03, 0xF860, 0x9D04, 0xF861, 0x9D05, 0xF862, 0x9D06, 0xF863, 0x9D07, 0xF864, 0x9D08, 0xF865, 0x9D09, 0xF866, 0x9D0A, 0xF867, 0x9D0B, 0xF868, 0x9D0C, 0xF869, 0x9D0D, 0xF86A, 0x9D0E, 0xF86B, 0x9D0F, 0xF86C, 0x9D10, 0xF86D, 0x9D11, 0xF86E, 0x9D12, 0xF86F, 0x9D13, 0xF870, 0x9D14, 0xF871, 0x9D15, 0xF872, 0x9D16, 0xF873, 0x9D17, 0xF874, 0x9D18, 0xF875, 0x9D19, 0xF876, 0x9D1A, 0xF877, 0x9D1B, 0xF878, 0x9D1C, 0xF879, 0x9D1D, 0xF87A, 0x9D1E, 0xF87B, 0x9D1F, 0xF87C, 0x9D20, 0xF87D, 0x9D21, 0xF87E, 0x9D22, 0xF880, 0x9D23, 0xF881, 0x9D24, 0xF882, 0x9D25, 0xF883, 0x9D26, 0xF884, 0x9D27, 0xF885, 0x9D28, 0xF886, 0x9D29, 0xF887, 0x9D2A, 0xF888, 0x9D2B, 0xF889, 0x9D2C, 0xF88A, 0x9D2D, 0xF88B, 0x9D2E, 0xF88C, 0x9D2F, 0xF88D, 0x9D30, 0xF88E, 0x9D31, 0xF88F, 0x9D32, 0xF890, 0x9D33, 0xF891, 0x9D34, 0xF892, 0x9D35, 0xF893, 0x9D36, 0xF894, 0x9D37, 0xF895, 0x9D38, 0xF896, 0x9D39, 0xF897, 0x9D3A, 0xF898, 0x9D3B, 0xF899, 0x9D3C, 0xF89A, 0x9D3D, 0xF89B, 0x9D3E, 0xF89C, 0x9D3F, 0xF89D, 0x9D40, 0xF89E, 0x9D41, 0xF89F, 0x9D42, 0xF8A0, 0x9D43, 0xF940, 0x9D44, 0xF941, 0x9D45, 0xF942, 0x9D46, 0xF943, 0x9D47, 0xF944, 0x9D48, 0xF945, 0x9D49, 0xF946, 0x9D4A, 0xF947, 0x9D4B, 0xF948, 0x9D4C, 0xF949, 0x9D4D, 0xF94A, 0x9D4E, 0xF94B, 0x9D4F, 0xF94C, 0x9D50, 0xF94D, 0x9D51, 0xF94E, 0x9D52, 0xF94F, 0x9D53, 0xF950, 0x9D54, 0xF951, 0x9D55, 0xF952, 0x9D56, 0xF953, 0x9D57, 0xF954, 0x9D58, 0xF955, 0x9D59, 0xF956, 0x9D5A, 0xF957, 0x9D5B, 0xF958, 0x9D5C, 0xF959, 0x9D5D, 0xF95A, 0x9D5E, 0xF95B, 0x9D5F, 0xF95C, 0x9D60, 0xF95D, 0x9D61, 0xF95E, 0x9D62, 0xF95F, 0x9D63, 0xF960, 0x9D64, 0xF961, 0x9D65, 0xF962, 0x9D66, 0xF963, 0x9D67, 0xF964, 0x9D68, 0xF965, 0x9D69, 0xF966, 0x9D6A, 0xF967, 0x9D6B, 0xF968, 0x9D6C, 0xF969, 0x9D6D, 0xF96A, 0x9D6E, 0xF96B, 0x9D6F, 0xF96C, 0x9D70, 0xF96D, 0x9D71, 0xF96E, 0x9D72, 0xF96F, 0x9D73, 0xF970, 0x9D74, 0xF971, 0x9D75, 0xF972, 0x9D76, 0xF973, 0x9D77, 0xF974, 0x9D78, 0xF975, 0x9D79, 0xF976, 0x9D7A, 0xF977, 0x9D7B, 0xF978, 0x9D7C, 0xF979, 0x9D7D, 0xF97A, 0x9D7E, 0xF97B, 0x9D7F, 0xF97C, 0x9D80, 0xF97D, 0x9D81, 0xF97E, 0x9D82, 0xF980, 0x9D83, 0xF981, 0x9D84, 0xF982, 0x9D85, 0xF983, 0x9D86, 0xF984, 0x9D87, 0xF985, 0x9D88, 0xF986, 0x9D89, 0xF987, 0x9D8A, 0xF988, 0x9D8B, 0xF989, 0x9D8C, 0xF98A, 0x9D8D, 0xF98B, 0x9D8E, 0xF98C, 0x9D8F, 0xF98D, 0x9D90, 0xF98E, 0x9D91, 0xF98F, 0x9D92, 0xF990, 0x9D93, 0xF991, 0x9D94, 0xF992, 0x9D95, 0xF993, 0x9D96, 0xF994, 0x9D97, 0xF995, 0x9D98, 0xF996, 0x9D99, 0xF997, 0x9D9A, 0xF998, 0x9D9B, 0xF999, 0x9D9C, 0xF99A, 0x9D9D, 0xF99B, 0x9D9E, 0xF99C, 0x9D9F, 0xF99D, 0x9DA0, 0xF99E, 0x9DA1, 0xF99F, 0x9DA2, 0xF9A0, 0x9DA3, 0xFA40, 0x9DA4, 0xFA41, 0x9DA5, 0xFA42, 0x9DA6, 0xFA43, 0x9DA7, 0xFA44, 0x9DA8, 0xFA45, 0x9DA9, 0xFA46, 0x9DAA, 0xFA47, 0x9DAB, 0xFA48, 0x9DAC, 0xFA49, 0x9DAD, 0xFA4A, 0x9DAE, 0xFA4B, 0x9DAF, 0xFA4C, 0x9DB0, 0xFA4D, 0x9DB1, 0xFA4E, 0x9DB2, 0xFA4F, 0x9DB3, 0xFA50, 0x9DB4, 0xFA51, 0x9DB5, 0xFA52, 0x9DB6, 0xFA53, 0x9DB7, 0xFA54, 0x9DB8, 0xFA55, 0x9DB9, 0xFA56, 0x9DBA, 0xFA57, 0x9DBB, 0xFA58, 0x9DBC, 0xFA59, 0x9DBD, 0xFA5A, 0x9DBE, 0xFA5B, 0x9DBF, 0xFA5C, 0x9DC0, 0xFA5D, 0x9DC1, 0xFA5E, 0x9DC2, 0xFA5F, 0x9DC3, 0xFA60, 0x9DC4, 0xFA61, 0x9DC5, 0xFA62, 0x9DC6, 0xFA63, 0x9DC7, 0xFA64, 0x9DC8, 0xFA65, 0x9DC9, 0xFA66, 0x9DCA, 0xFA67, 0x9DCB, 0xFA68, 0x9DCC, 0xFA69, 0x9DCD, 0xFA6A, 0x9DCE, 0xFA6B, 0x9DCF, 0xFA6C, 0x9DD0, 0xFA6D, 0x9DD1, 0xFA6E, 0x9DD2, 0xFA6F, 0x9DD3, 0xFA70, 0x9DD4, 0xFA71, 0x9DD5, 0xFA72, 0x9DD6, 0xFA73, 0x9DD7, 0xFA74, 0x9DD8, 0xFA75, 0x9DD9, 0xFA76, 0x9DDA, 0xFA77, 0x9DDB, 0xFA78, 0x9DDC, 0xFA79, 0x9DDD, 0xFA7A, 0x9DDE, 0xFA7B, 0x9DDF, 0xFA7C, 0x9DE0, 0xFA7D, 0x9DE1, 0xFA7E, 0x9DE2, 0xFA80, 0x9DE3, 0xFA81, 0x9DE4, 0xFA82, 0x9DE5, 0xFA83, 0x9DE6, 0xFA84, 0x9DE7, 0xFA85, 0x9DE8, 0xFA86, 0x9DE9, 0xFA87, 0x9DEA, 0xFA88, 0x9DEB, 0xFA89, 0x9DEC, 0xFA8A, 0x9DED, 0xFA8B, 0x9DEE, 0xFA8C, 0x9DEF, 0xFA8D, 0x9DF0, 0xFA8E, 0x9DF1, 0xFA8F, 0x9DF2, 0xFA90, 0x9DF3, 0xFA91, 0x9DF4, 0xFA92, 0x9DF5, 0xFA93, 0x9DF6, 0xFA94, 0x9DF7, 0xFA95, 0x9DF8, 0xFA96, 0x9DF9, 0xFA97, 0x9DFA, 0xFA98, 0x9DFB, 0xFA99, 0x9DFC, 0xFA9A, 0x9DFD, 0xFA9B, 0x9DFE, 0xFA9C, 0x9DFF, 0xFA9D, 0x9E00, 0xFA9E, 0x9E01, 0xFA9F, 0x9E02, 0xFAA0, 0x9E03, 0xFB40, 0x9E04, 0xFB41, 0x9E05, 0xFB42, 0x9E06, 0xFB43, 0x9E07, 0xFB44, 0x9E08, 0xFB45, 0x9E09, 0xFB46, 0x9E0A, 0xFB47, 0x9E0B, 0xFB48, 0x9E0C, 0xFB49, 0x9E0D, 0xFB4A, 0x9E0E, 0xFB4B, 0x9E0F, 0xFB4C, 0x9E10, 0xFB4D, 0x9E11, 0xFB4E, 0x9E12, 0xFB4F, 0x9E13, 0xFB50, 0x9E14, 0xFB51, 0x9E15, 0xFB52, 0x9E16, 0xFB53, 0x9E17, 0xFB54, 0x9E18, 0xFB55, 0x9E19, 0xFB56, 0x9E1A, 0xFB57, 0x9E1B, 0xFB58, 0x9E1C, 0xFB59, 0x9E1D, 0xFB5A, 0x9E1E, 0xFB5B, 0x9E1F, 0xC4F1, 0x9E20, 0xF0AF, 0x9E21, 0xBCA6, 0x9E22, 0xF0B0, 0x9E23, 0xC3F9, 0x9E24, 0xFB5C, 0x9E25, 0xC5B8, 0x9E26, 0xD1BB, 0x9E27, 0xFB5D, 0x9E28, 0xF0B1, 0x9E29, 0xF0B2, 0x9E2A, 0xF0B3, 0x9E2B, 0xF0B4, 0x9E2C, 0xF0B5, 0x9E2D, 0xD1BC, 0x9E2E, 0xFB5E, 0x9E2F, 0xD1EC, 0x9E30, 0xFB5F, 0x9E31, 0xF0B7, 0x9E32, 0xF0B6, 0x9E33, 0xD4A7, 0x9E34, 0xFB60, 0x9E35, 0xCDD2, 0x9E36, 0xF0B8, 0x9E37, 0xF0BA, 0x9E38, 0xF0B9, 0x9E39, 0xF0BB, 0x9E3A, 0xF0BC, 0x9E3B, 0xFB61, 0x9E3C, 0xFB62, 0x9E3D, 0xB8EB, 0x9E3E, 0xF0BD, 0x9E3F, 0xBAE8, 0x9E40, 0xFB63, 0x9E41, 0xF0BE, 0x9E42, 0xF0BF, 0x9E43, 0xBEE9, 0x9E44, 0xF0C0, 0x9E45, 0xB6EC, 0x9E46, 0xF0C1, 0x9E47, 0xF0C2, 0x9E48, 0xF0C3, 0x9E49, 0xF0C4, 0x9E4A, 0xC8B5, 0x9E4B, 0xF0C5, 0x9E4C, 0xF0C6, 0x9E4D, 0xFB64, 0x9E4E, 0xF0C7, 0x9E4F, 0xC5F4, 0x9E50, 0xFB65, 0x9E51, 0xF0C8, 0x9E52, 0xFB66, 0x9E53, 0xFB67, 0x9E54, 0xFB68, 0x9E55, 0xF0C9, 0x9E56, 0xFB69, 0x9E57, 0xF0CA, 0x9E58, 0xF7BD, 0x9E59, 0xFB6A, 0x9E5A, 0xF0CB, 0x9E5B, 0xF0CC, 0x9E5C, 0xF0CD, 0x9E5D, 0xFB6B, 0x9E5E, 0xF0CE, 0x9E5F, 0xFB6C, 0x9E60, 0xFB6D, 0x9E61, 0xFB6E, 0x9E62, 0xFB6F, 0x9E63, 0xF0CF, 0x9E64, 0xBAD7, 0x9E65, 0xFB70, 0x9E66, 0xF0D0, 0x9E67, 0xF0D1, 0x9E68, 0xF0D2, 0x9E69, 0xF0D3, 0x9E6A, 0xF0D4, 0x9E6B, 0xF0D5, 0x9E6C, 0xF0D6, 0x9E6D, 0xF0D8, 0x9E6E, 0xFB71, 0x9E6F, 0xFB72, 0x9E70, 0xD3A5, 0x9E71, 0xF0D7, 0x9E72, 0xFB73, 0x9E73, 0xF0D9, 0x9E74, 0xFB74, 0x9E75, 0xFB75, 0x9E76, 0xFB76, 0x9E77, 0xFB77, 0x9E78, 0xFB78, 0x9E79, 0xFB79, 0x9E7A, 0xFB7A, 0x9E7B, 0xFB7B, 0x9E7C, 0xFB7C, 0x9E7D, 0xFB7D, 0x9E7E, 0xF5BA, 0x9E7F, 0xC2B9, 0x9E80, 0xFB7E, 0x9E81, 0xFB80, 0x9E82, 0xF7E4, 0x9E83, 0xFB81, 0x9E84, 0xFB82, 0x9E85, 0xFB83, 0x9E86, 0xFB84, 0x9E87, 0xF7E5, 0x9E88, 0xF7E6, 0x9E89, 0xFB85, 0x9E8A, 0xFB86, 0x9E8B, 0xF7E7, 0x9E8C, 0xFB87, 0x9E8D, 0xFB88, 0x9E8E, 0xFB89, 0x9E8F, 0xFB8A, 0x9E90, 0xFB8B, 0x9E91, 0xFB8C, 0x9E92, 0xF7E8, 0x9E93, 0xC2B4, 0x9E94, 0xFB8D, 0x9E95, 0xFB8E, 0x9E96, 0xFB8F, 0x9E97, 0xFB90, 0x9E98, 0xFB91, 0x9E99, 0xFB92, 0x9E9A, 0xFB93, 0x9E9B, 0xFB94, 0x9E9C, 0xFB95, 0x9E9D, 0xF7EA, 0x9E9E, 0xFB96, 0x9E9F, 0xF7EB, 0x9EA0, 0xFB97, 0x9EA1, 0xFB98, 0x9EA2, 0xFB99, 0x9EA3, 0xFB9A, 0x9EA4, 0xFB9B, 0x9EA5, 0xFB9C, 0x9EA6, 0xC2F3, 0x9EA7, 0xFB9D, 0x9EA8, 0xFB9E, 0x9EA9, 0xFB9F, 0x9EAA, 0xFBA0, 0x9EAB, 0xFC40, 0x9EAC, 0xFC41, 0x9EAD, 0xFC42, 0x9EAE, 0xFC43, 0x9EAF, 0xFC44, 0x9EB0, 0xFC45, 0x9EB1, 0xFC46, 0x9EB2, 0xFC47, 0x9EB3, 0xFC48, 0x9EB4, 0xF4F0, 0x9EB5, 0xFC49, 0x9EB6, 0xFC4A, 0x9EB7, 0xFC4B, 0x9EB8, 0xF4EF, 0x9EB9, 0xFC4C, 0x9EBA, 0xFC4D, 0x9EBB, 0xC2E9, 0x9EBC, 0xFC4E, 0x9EBD, 0xF7E1, 0x9EBE, 0xF7E2, 0x9EBF, 0xFC4F, 0x9EC0, 0xFC50, 0x9EC1, 0xFC51, 0x9EC2, 0xFC52, 0x9EC3, 0xFC53, 0x9EC4, 0xBBC6, 0x9EC5, 0xFC54, 0x9EC6, 0xFC55, 0x9EC7, 0xFC56, 0x9EC8, 0xFC57, 0x9EC9, 0xD9E4, 0x9ECA, 0xFC58, 0x9ECB, 0xFC59, 0x9ECC, 0xFC5A, 0x9ECD, 0xCAF2, 0x9ECE, 0xC0E8, 0x9ECF, 0xF0A4, 0x9ED0, 0xFC5B, 0x9ED1, 0xBADA, 0x9ED2, 0xFC5C, 0x9ED3, 0xFC5D, 0x9ED4, 0xC7AD, 0x9ED5, 0xFC5E, 0x9ED6, 0xFC5F, 0x9ED7, 0xFC60, 0x9ED8, 0xC4AC, 0x9ED9, 0xFC61, 0x9EDA, 0xFC62, 0x9EDB, 0xF7EC, 0x9EDC, 0xF7ED, 0x9EDD, 0xF7EE, 0x9EDE, 0xFC63, 0x9EDF, 0xF7F0, 0x9EE0, 0xF7EF, 0x9EE1, 0xFC64, 0x9EE2, 0xF7F1, 0x9EE3, 0xFC65, 0x9EE4, 0xFC66, 0x9EE5, 0xF7F4, 0x9EE6, 0xFC67, 0x9EE7, 0xF7F3, 0x9EE8, 0xFC68, 0x9EE9, 0xF7F2, 0x9EEA, 0xF7F5, 0x9EEB, 0xFC69, 0x9EEC, 0xFC6A, 0x9EED, 0xFC6B, 0x9EEE, 0xFC6C, 0x9EEF, 0xF7F6, 0x9EF0, 0xFC6D, 0x9EF1, 0xFC6E, 0x9EF2, 0xFC6F, 0x9EF3, 0xFC70, 0x9EF4, 0xFC71, 0x9EF5, 0xFC72, 0x9EF6, 0xFC73, 0x9EF7, 0xFC74, 0x9EF8, 0xFC75, 0x9EF9, 0xEDE9, 0x9EFA, 0xFC76, 0x9EFB, 0xEDEA, 0x9EFC, 0xEDEB, 0x9EFD, 0xFC77, 0x9EFE, 0xF6BC, 0x9EFF, 0xFC78, 0x9F00, 0xFC79, 0x9F01, 0xFC7A, 0x9F02, 0xFC7B, 0x9F03, 0xFC7C, 0x9F04, 0xFC7D, 0x9F05, 0xFC7E, 0x9F06, 0xFC80, 0x9F07, 0xFC81, 0x9F08, 0xFC82, 0x9F09, 0xFC83, 0x9F0A, 0xFC84, 0x9F0B, 0xF6BD, 0x9F0C, 0xFC85, 0x9F0D, 0xF6BE, 0x9F0E, 0xB6A6, 0x9F0F, 0xFC86, 0x9F10, 0xD8BE, 0x9F11, 0xFC87, 0x9F12, 0xFC88, 0x9F13, 0xB9C4, 0x9F14, 0xFC89, 0x9F15, 0xFC8A, 0x9F16, 0xFC8B, 0x9F17, 0xD8BB, 0x9F18, 0xFC8C, 0x9F19, 0xDCB1, 0x9F1A, 0xFC8D, 0x9F1B, 0xFC8E, 0x9F1C, 0xFC8F, 0x9F1D, 0xFC90, 0x9F1E, 0xFC91, 0x9F1F, 0xFC92, 0x9F20, 0xCAF3, 0x9F21, 0xFC93, 0x9F22, 0xF7F7, 0x9F23, 0xFC94, 0x9F24, 0xFC95, 0x9F25, 0xFC96, 0x9F26, 0xFC97, 0x9F27, 0xFC98, 0x9F28, 0xFC99, 0x9F29, 0xFC9A, 0x9F2A, 0xFC9B, 0x9F2B, 0xFC9C, 0x9F2C, 0xF7F8, 0x9F2D, 0xFC9D, 0x9F2E, 0xFC9E, 0x9F2F, 0xF7F9, 0x9F30, 0xFC9F, 0x9F31, 0xFCA0, 0x9F32, 0xFD40, 0x9F33, 0xFD41, 0x9F34, 0xFD42, 0x9F35, 0xFD43, 0x9F36, 0xFD44, 0x9F37, 0xF7FB, 0x9F38, 0xFD45, 0x9F39, 0xF7FA, 0x9F3A, 0xFD46, 0x9F3B, 0xB1C7, 0x9F3C, 0xFD47, 0x9F3D, 0xF7FC, 0x9F3E, 0xF7FD, 0x9F3F, 0xFD48, 0x9F40, 0xFD49, 0x9F41, 0xFD4A, 0x9F42, 0xFD4B, 0x9F43, 0xFD4C, 0x9F44, 0xF7FE, 0x9F45, 0xFD4D, 0x9F46, 0xFD4E, 0x9F47, 0xFD4F, 0x9F48, 0xFD50, 0x9F49, 0xFD51, 0x9F4A, 0xFD52, 0x9F4B, 0xFD53, 0x9F4C, 0xFD54, 0x9F4D, 0xFD55, 0x9F4E, 0xFD56, 0x9F4F, 0xFD57, 0x9F50, 0xC6EB, 0x9F51, 0xECB4, 0x9F52, 0xFD58, 0x9F53, 0xFD59, 0x9F54, 0xFD5A, 0x9F55, 0xFD5B, 0x9F56, 0xFD5C, 0x9F57, 0xFD5D, 0x9F58, 0xFD5E, 0x9F59, 0xFD5F, 0x9F5A, 0xFD60, 0x9F5B, 0xFD61, 0x9F5C, 0xFD62, 0x9F5D, 0xFD63, 0x9F5E, 0xFD64, 0x9F5F, 0xFD65, 0x9F60, 0xFD66, 0x9F61, 0xFD67, 0x9F62, 0xFD68, 0x9F63, 0xFD69, 0x9F64, 0xFD6A, 0x9F65, 0xFD6B, 0x9F66, 0xFD6C, 0x9F67, 0xFD6D, 0x9F68, 0xFD6E, 0x9F69, 0xFD6F, 0x9F6A, 0xFD70, 0x9F6B, 0xFD71, 0x9F6C, 0xFD72, 0x9F6D, 0xFD73, 0x9F6E, 0xFD74, 0x9F6F, 0xFD75, 0x9F70, 0xFD76, 0x9F71, 0xFD77, 0x9F72, 0xFD78, 0x9F73, 0xFD79, 0x9F74, 0xFD7A, 0x9F75, 0xFD7B, 0x9F76, 0xFD7C, 0x9F77, 0xFD7D, 0x9F78, 0xFD7E, 0x9F79, 0xFD80, 0x9F7A, 0xFD81, 0x9F7B, 0xFD82, 0x9F7C, 0xFD83, 0x9F7D, 0xFD84, 0x9F7E, 0xFD85, 0x9F7F, 0xB3DD, 0x9F80, 0xF6B3, 0x9F81, 0xFD86, 0x9F82, 0xFD87, 0x9F83, 0xF6B4, 0x9F84, 0xC1E4, 0x9F85, 0xF6B5, 0x9F86, 0xF6B6, 0x9F87, 0xF6B7, 0x9F88, 0xF6B8, 0x9F89, 0xF6B9, 0x9F8A, 0xF6BA, 0x9F8B, 0xC8A3, 0x9F8C, 0xF6BB, 0x9F8D, 0xFD88, 0x9F8E, 0xFD89, 0x9F8F, 0xFD8A, 0x9F90, 0xFD8B, 0x9F91, 0xFD8C, 0x9F92, 0xFD8D, 0x9F93, 0xFD8E, 0x9F94, 0xFD8F, 0x9F95, 0xFD90, 0x9F96, 0xFD91, 0x9F97, 0xFD92, 0x9F98, 0xFD93, 0x9F99, 0xC1FA, 0x9F9A, 0xB9A8, 0x9F9B, 0xEDE8, 0x9F9C, 0xFD94, 0x9F9D, 0xFD95, 0x9F9E, 0xFD96, 0x9F9F, 0xB9EA, 0x9FA0, 0xD9DF, 0x9FA1, 0xFD97, 0x9FA2, 0xFD98, 0x9FA3, 0xFD99, 0x9FA4, 0xFD9A, 0x9FA5, 0xFD9B, 0xF92C, 0xFD9C, 0xF979, 0xFD9D, 0xF995, 0xFD9E, 0xF9E7, 0xFD9F, 0xF9F1, 0xFDA0, 0xFA0C, 0xFE40, 0xFA0D, 0xFE41, 0xFA0E, 0xFE42, 0xFA0F, 0xFE43, 0xFA11, 0xFE44, 0xFA13, 0xFE45, 0xFA14, 0xFE46, 0xFA18, 0xFE47, 0xFA1F, 0xFE48, 0xFA20, 0xFE49, 0xFA21, 0xFE4A, 0xFA23, 0xFE4B, 0xFA24, 0xFE4C, 0xFA27, 0xFE4D, 0xFA28, 0xFE4E, 0xFA29, 0xFE4F, 0xFE30, 0xA955, 0xFE31, 0xA6F2, 0xFE33, 0xA6F4, 0xFE34, 0xA6F5, 0xFE35, 0xA6E0, 0xFE36, 0xA6E1, 0xFE37, 0xA6F0, 0xFE38, 0xA6F1, 0xFE39, 0xA6E2, 0xFE3A, 0xA6E3, 0xFE3B, 0xA6EE, 0xFE3C, 0xA6EF, 0xFE3D, 0xA6E6, 0xFE3E, 0xA6E7, 0xFE3F, 0xA6E4, 0xFE40, 0xA6E5, 0xFE41, 0xA6E8, 0xFE42, 0xA6E9, 0xFE43, 0xA6EA, 0xFE44, 0xA6EB, 0xFE49, 0xA968, 0xFE4A, 0xA969, 0xFE4B, 0xA96A, 0xFE4C, 0xA96B, 0xFE4D, 0xA96C, 0xFE4E, 0xA96D, 0xFE4F, 0xA96E, 0xFE50, 0xA96F, 0xFE51, 0xA970, 0xFE52, 0xA971, 0xFE54, 0xA972, 0xFE55, 0xA973, 0xFE56, 0xA974, 0xFE57, 0xA975, 0xFE59, 0xA976, 0xFE5A, 0xA977, 0xFE5B, 0xA978, 0xFE5C, 0xA979, 0xFE5D, 0xA97A, 0xFE5E, 0xA97B, 0xFE5F, 0xA97C, 0xFE60, 0xA97D, 0xFE61, 0xA97E, 0xFE62, 0xA980, 0xFE63, 0xA981, 0xFE64, 0xA982, 0xFE65, 0xA983, 0xFE66, 0xA984, 0xFE68, 0xA985, 0xFE69, 0xA986, 0xFE6A, 0xA987, 0xFE6B, 0xA988, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA1E7, 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA3DC, 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, 0xFF5D, 0xA3FD, 0xFF5E, 0xA1AB, 0xFFE0, 0xA1E9, 0xFFE1, 0xA1EA, 0xFFE2, 0xA956, 0xFFE3, 0xA3FE, 0xFFE4, 0xA957, 0xFFE5, 0xA3A4, 0, 0 }; static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ 0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17, 0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F, 0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42, 0x8157, 0x4E44, 0x8158, 0x4E46, 0x8159, 0x4E4A, 0x815A, 0x4E51, 0x815B, 0x4E55, 0x815C, 0x4E57, 0x815D, 0x4E5A, 0x815E, 0x4E5B, 0x815F, 0x4E62, 0x8160, 0x4E63, 0x8161, 0x4E64, 0x8162, 0x4E65, 0x8163, 0x4E67, 0x8164, 0x4E68, 0x8165, 0x4E6A, 0x8166, 0x4E6B, 0x8167, 0x4E6C, 0x8168, 0x4E6D, 0x8169, 0x4E6E, 0x816A, 0x4E6F, 0x816B, 0x4E72, 0x816C, 0x4E74, 0x816D, 0x4E75, 0x816E, 0x4E76, 0x816F, 0x4E77, 0x8170, 0x4E78, 0x8171, 0x4E79, 0x8172, 0x4E7A, 0x8173, 0x4E7B, 0x8174, 0x4E7C, 0x8175, 0x4E7D, 0x8176, 0x4E7F, 0x8177, 0x4E80, 0x8178, 0x4E81, 0x8179, 0x4E82, 0x817A, 0x4E83, 0x817B, 0x4E84, 0x817C, 0x4E85, 0x817D, 0x4E87, 0x817E, 0x4E8A, 0x8180, 0x4E90, 0x8181, 0x4E96, 0x8182, 0x4E97, 0x8183, 0x4E99, 0x8184, 0x4E9C, 0x8185, 0x4E9D, 0x8186, 0x4E9E, 0x8187, 0x4EA3, 0x8188, 0x4EAA, 0x8189, 0x4EAF, 0x818A, 0x4EB0, 0x818B, 0x4EB1, 0x818C, 0x4EB4, 0x818D, 0x4EB6, 0x818E, 0x4EB7, 0x818F, 0x4EB8, 0x8190, 0x4EB9, 0x8191, 0x4EBC, 0x8192, 0x4EBD, 0x8193, 0x4EBE, 0x8194, 0x4EC8, 0x8195, 0x4ECC, 0x8196, 0x4ECF, 0x8197, 0x4ED0, 0x8198, 0x4ED2, 0x8199, 0x4EDA, 0x819A, 0x4EDB, 0x819B, 0x4EDC, 0x819C, 0x4EE0, 0x819D, 0x4EE2, 0x819E, 0x4EE6, 0x819F, 0x4EE7, 0x81A0, 0x4EE9, 0x81A1, 0x4EED, 0x81A2, 0x4EEE, 0x81A3, 0x4EEF, 0x81A4, 0x4EF1, 0x81A5, 0x4EF4, 0x81A6, 0x4EF8, 0x81A7, 0x4EF9, 0x81A8, 0x4EFA, 0x81A9, 0x4EFC, 0x81AA, 0x4EFE, 0x81AB, 0x4F00, 0x81AC, 0x4F02, 0x81AD, 0x4F03, 0x81AE, 0x4F04, 0x81AF, 0x4F05, 0x81B0, 0x4F06, 0x81B1, 0x4F07, 0x81B2, 0x4F08, 0x81B3, 0x4F0B, 0x81B4, 0x4F0C, 0x81B5, 0x4F12, 0x81B6, 0x4F13, 0x81B7, 0x4F14, 0x81B8, 0x4F15, 0x81B9, 0x4F16, 0x81BA, 0x4F1C, 0x81BB, 0x4F1D, 0x81BC, 0x4F21, 0x81BD, 0x4F23, 0x81BE, 0x4F28, 0x81BF, 0x4F29, 0x81C0, 0x4F2C, 0x81C1, 0x4F2D, 0x81C2, 0x4F2E, 0x81C3, 0x4F31, 0x81C4, 0x4F33, 0x81C5, 0x4F35, 0x81C6, 0x4F37, 0x81C7, 0x4F39, 0x81C8, 0x4F3B, 0x81C9, 0x4F3E, 0x81CA, 0x4F3F, 0x81CB, 0x4F40, 0x81CC, 0x4F41, 0x81CD, 0x4F42, 0x81CE, 0x4F44, 0x81CF, 0x4F45, 0x81D0, 0x4F47, 0x81D1, 0x4F48, 0x81D2, 0x4F49, 0x81D3, 0x4F4A, 0x81D4, 0x4F4B, 0x81D5, 0x4F4C, 0x81D6, 0x4F52, 0x81D7, 0x4F54, 0x81D8, 0x4F56, 0x81D9, 0x4F61, 0x81DA, 0x4F62, 0x81DB, 0x4F66, 0x81DC, 0x4F68, 0x81DD, 0x4F6A, 0x81DE, 0x4F6B, 0x81DF, 0x4F6D, 0x81E0, 0x4F6E, 0x81E1, 0x4F71, 0x81E2, 0x4F72, 0x81E3, 0x4F75, 0x81E4, 0x4F77, 0x81E5, 0x4F78, 0x81E6, 0x4F79, 0x81E7, 0x4F7A, 0x81E8, 0x4F7D, 0x81E9, 0x4F80, 0x81EA, 0x4F81, 0x81EB, 0x4F82, 0x81EC, 0x4F85, 0x81ED, 0x4F86, 0x81EE, 0x4F87, 0x81EF, 0x4F8A, 0x81F0, 0x4F8C, 0x81F1, 0x4F8E, 0x81F2, 0x4F90, 0x81F3, 0x4F92, 0x81F4, 0x4F93, 0x81F5, 0x4F95, 0x81F6, 0x4F96, 0x81F7, 0x4F98, 0x81F8, 0x4F99, 0x81F9, 0x4F9A, 0x81FA, 0x4F9C, 0x81FB, 0x4F9E, 0x81FC, 0x4F9F, 0x81FD, 0x4FA1, 0x81FE, 0x4FA2, 0x8240, 0x4FA4, 0x8241, 0x4FAB, 0x8242, 0x4FAD, 0x8243, 0x4FB0, 0x8244, 0x4FB1, 0x8245, 0x4FB2, 0x8246, 0x4FB3, 0x8247, 0x4FB4, 0x8248, 0x4FB6, 0x8249, 0x4FB7, 0x824A, 0x4FB8, 0x824B, 0x4FB9, 0x824C, 0x4FBA, 0x824D, 0x4FBB, 0x824E, 0x4FBC, 0x824F, 0x4FBD, 0x8250, 0x4FBE, 0x8251, 0x4FC0, 0x8252, 0x4FC1, 0x8253, 0x4FC2, 0x8254, 0x4FC6, 0x8255, 0x4FC7, 0x8256, 0x4FC8, 0x8257, 0x4FC9, 0x8258, 0x4FCB, 0x8259, 0x4FCC, 0x825A, 0x4FCD, 0x825B, 0x4FD2, 0x825C, 0x4FD3, 0x825D, 0x4FD4, 0x825E, 0x4FD5, 0x825F, 0x4FD6, 0x8260, 0x4FD9, 0x8261, 0x4FDB, 0x8262, 0x4FE0, 0x8263, 0x4FE2, 0x8264, 0x4FE4, 0x8265, 0x4FE5, 0x8266, 0x4FE7, 0x8267, 0x4FEB, 0x8268, 0x4FEC, 0x8269, 0x4FF0, 0x826A, 0x4FF2, 0x826B, 0x4FF4, 0x826C, 0x4FF5, 0x826D, 0x4FF6, 0x826E, 0x4FF7, 0x826F, 0x4FF9, 0x8270, 0x4FFB, 0x8271, 0x4FFC, 0x8272, 0x4FFD, 0x8273, 0x4FFF, 0x8274, 0x5000, 0x8275, 0x5001, 0x8276, 0x5002, 0x8277, 0x5003, 0x8278, 0x5004, 0x8279, 0x5005, 0x827A, 0x5006, 0x827B, 0x5007, 0x827C, 0x5008, 0x827D, 0x5009, 0x827E, 0x500A, 0x8280, 0x500B, 0x8281, 0x500E, 0x8282, 0x5010, 0x8283, 0x5011, 0x8284, 0x5013, 0x8285, 0x5015, 0x8286, 0x5016, 0x8287, 0x5017, 0x8288, 0x501B, 0x8289, 0x501D, 0x828A, 0x501E, 0x828B, 0x5020, 0x828C, 0x5022, 0x828D, 0x5023, 0x828E, 0x5024, 0x828F, 0x5027, 0x8290, 0x502B, 0x8291, 0x502F, 0x8292, 0x5030, 0x8293, 0x5031, 0x8294, 0x5032, 0x8295, 0x5033, 0x8296, 0x5034, 0x8297, 0x5035, 0x8298, 0x5036, 0x8299, 0x5037, 0x829A, 0x5038, 0x829B, 0x5039, 0x829C, 0x503B, 0x829D, 0x503D, 0x829E, 0x503F, 0x829F, 0x5040, 0x82A0, 0x5041, 0x82A1, 0x5042, 0x82A2, 0x5044, 0x82A3, 0x5045, 0x82A4, 0x5046, 0x82A5, 0x5049, 0x82A6, 0x504A, 0x82A7, 0x504B, 0x82A8, 0x504D, 0x82A9, 0x5050, 0x82AA, 0x5051, 0x82AB, 0x5052, 0x82AC, 0x5053, 0x82AD, 0x5054, 0x82AE, 0x5056, 0x82AF, 0x5057, 0x82B0, 0x5058, 0x82B1, 0x5059, 0x82B2, 0x505B, 0x82B3, 0x505D, 0x82B4, 0x505E, 0x82B5, 0x505F, 0x82B6, 0x5060, 0x82B7, 0x5061, 0x82B8, 0x5062, 0x82B9, 0x5063, 0x82BA, 0x5064, 0x82BB, 0x5066, 0x82BC, 0x5067, 0x82BD, 0x5068, 0x82BE, 0x5069, 0x82BF, 0x506A, 0x82C0, 0x506B, 0x82C1, 0x506D, 0x82C2, 0x506E, 0x82C3, 0x506F, 0x82C4, 0x5070, 0x82C5, 0x5071, 0x82C6, 0x5072, 0x82C7, 0x5073, 0x82C8, 0x5074, 0x82C9, 0x5075, 0x82CA, 0x5078, 0x82CB, 0x5079, 0x82CC, 0x507A, 0x82CD, 0x507C, 0x82CE, 0x507D, 0x82CF, 0x5081, 0x82D0, 0x5082, 0x82D1, 0x5083, 0x82D2, 0x5084, 0x82D3, 0x5086, 0x82D4, 0x5087, 0x82D5, 0x5089, 0x82D6, 0x508A, 0x82D7, 0x508B, 0x82D8, 0x508C, 0x82D9, 0x508E, 0x82DA, 0x508F, 0x82DB, 0x5090, 0x82DC, 0x5091, 0x82DD, 0x5092, 0x82DE, 0x5093, 0x82DF, 0x5094, 0x82E0, 0x5095, 0x82E1, 0x5096, 0x82E2, 0x5097, 0x82E3, 0x5098, 0x82E4, 0x5099, 0x82E5, 0x509A, 0x82E6, 0x509B, 0x82E7, 0x509C, 0x82E8, 0x509D, 0x82E9, 0x509E, 0x82EA, 0x509F, 0x82EB, 0x50A0, 0x82EC, 0x50A1, 0x82ED, 0x50A2, 0x82EE, 0x50A4, 0x82EF, 0x50A6, 0x82F0, 0x50AA, 0x82F1, 0x50AB, 0x82F2, 0x50AD, 0x82F3, 0x50AE, 0x82F4, 0x50AF, 0x82F5, 0x50B0, 0x82F6, 0x50B1, 0x82F7, 0x50B3, 0x82F8, 0x50B4, 0x82F9, 0x50B5, 0x82FA, 0x50B6, 0x82FB, 0x50B7, 0x82FC, 0x50B8, 0x82FD, 0x50B9, 0x82FE, 0x50BC, 0x8340, 0x50BD, 0x8341, 0x50BE, 0x8342, 0x50BF, 0x8343, 0x50C0, 0x8344, 0x50C1, 0x8345, 0x50C2, 0x8346, 0x50C3, 0x8347, 0x50C4, 0x8348, 0x50C5, 0x8349, 0x50C6, 0x834A, 0x50C7, 0x834B, 0x50C8, 0x834C, 0x50C9, 0x834D, 0x50CA, 0x834E, 0x50CB, 0x834F, 0x50CC, 0x8350, 0x50CD, 0x8351, 0x50CE, 0x8352, 0x50D0, 0x8353, 0x50D1, 0x8354, 0x50D2, 0x8355, 0x50D3, 0x8356, 0x50D4, 0x8357, 0x50D5, 0x8358, 0x50D7, 0x8359, 0x50D8, 0x835A, 0x50D9, 0x835B, 0x50DB, 0x835C, 0x50DC, 0x835D, 0x50DD, 0x835E, 0x50DE, 0x835F, 0x50DF, 0x8360, 0x50E0, 0x8361, 0x50E1, 0x8362, 0x50E2, 0x8363, 0x50E3, 0x8364, 0x50E4, 0x8365, 0x50E5, 0x8366, 0x50E8, 0x8367, 0x50E9, 0x8368, 0x50EA, 0x8369, 0x50EB, 0x836A, 0x50EF, 0x836B, 0x50F0, 0x836C, 0x50F1, 0x836D, 0x50F2, 0x836E, 0x50F4, 0x836F, 0x50F6, 0x8370, 0x50F7, 0x8371, 0x50F8, 0x8372, 0x50F9, 0x8373, 0x50FA, 0x8374, 0x50FC, 0x8375, 0x50FD, 0x8376, 0x50FE, 0x8377, 0x50FF, 0x8378, 0x5100, 0x8379, 0x5101, 0x837A, 0x5102, 0x837B, 0x5103, 0x837C, 0x5104, 0x837D, 0x5105, 0x837E, 0x5108, 0x8380, 0x5109, 0x8381, 0x510A, 0x8382, 0x510C, 0x8383, 0x510D, 0x8384, 0x510E, 0x8385, 0x510F, 0x8386, 0x5110, 0x8387, 0x5111, 0x8388, 0x5113, 0x8389, 0x5114, 0x838A, 0x5115, 0x838B, 0x5116, 0x838C, 0x5117, 0x838D, 0x5118, 0x838E, 0x5119, 0x838F, 0x511A, 0x8390, 0x511B, 0x8391, 0x511C, 0x8392, 0x511D, 0x8393, 0x511E, 0x8394, 0x511F, 0x8395, 0x5120, 0x8396, 0x5122, 0x8397, 0x5123, 0x8398, 0x5124, 0x8399, 0x5125, 0x839A, 0x5126, 0x839B, 0x5127, 0x839C, 0x5128, 0x839D, 0x5129, 0x839E, 0x512A, 0x839F, 0x512B, 0x83A0, 0x512C, 0x83A1, 0x512D, 0x83A2, 0x512E, 0x83A3, 0x512F, 0x83A4, 0x5130, 0x83A5, 0x5131, 0x83A6, 0x5132, 0x83A7, 0x5133, 0x83A8, 0x5134, 0x83A9, 0x5135, 0x83AA, 0x5136, 0x83AB, 0x5137, 0x83AC, 0x5138, 0x83AD, 0x5139, 0x83AE, 0x513A, 0x83AF, 0x513B, 0x83B0, 0x513C, 0x83B1, 0x513D, 0x83B2, 0x513E, 0x83B3, 0x5142, 0x83B4, 0x5147, 0x83B5, 0x514A, 0x83B6, 0x514C, 0x83B7, 0x514E, 0x83B8, 0x514F, 0x83B9, 0x5150, 0x83BA, 0x5152, 0x83BB, 0x5153, 0x83BC, 0x5157, 0x83BD, 0x5158, 0x83BE, 0x5159, 0x83BF, 0x515B, 0x83C0, 0x515D, 0x83C1, 0x515E, 0x83C2, 0x515F, 0x83C3, 0x5160, 0x83C4, 0x5161, 0x83C5, 0x5163, 0x83C6, 0x5164, 0x83C7, 0x5166, 0x83C8, 0x5167, 0x83C9, 0x5169, 0x83CA, 0x516A, 0x83CB, 0x516F, 0x83CC, 0x5172, 0x83CD, 0x517A, 0x83CE, 0x517E, 0x83CF, 0x517F, 0x83D0, 0x5183, 0x83D1, 0x5184, 0x83D2, 0x5186, 0x83D3, 0x5187, 0x83D4, 0x518A, 0x83D5, 0x518B, 0x83D6, 0x518E, 0x83D7, 0x518F, 0x83D8, 0x5190, 0x83D9, 0x5191, 0x83DA, 0x5193, 0x83DB, 0x5194, 0x83DC, 0x5198, 0x83DD, 0x519A, 0x83DE, 0x519D, 0x83DF, 0x519E, 0x83E0, 0x519F, 0x83E1, 0x51A1, 0x83E2, 0x51A3, 0x83E3, 0x51A6, 0x83E4, 0x51A7, 0x83E5, 0x51A8, 0x83E6, 0x51A9, 0x83E7, 0x51AA, 0x83E8, 0x51AD, 0x83E9, 0x51AE, 0x83EA, 0x51B4, 0x83EB, 0x51B8, 0x83EC, 0x51B9, 0x83ED, 0x51BA, 0x83EE, 0x51BE, 0x83EF, 0x51BF, 0x83F0, 0x51C1, 0x83F1, 0x51C2, 0x83F2, 0x51C3, 0x83F3, 0x51C5, 0x83F4, 0x51C8, 0x83F5, 0x51CA, 0x83F6, 0x51CD, 0x83F7, 0x51CE, 0x83F8, 0x51D0, 0x83F9, 0x51D2, 0x83FA, 0x51D3, 0x83FB, 0x51D4, 0x83FC, 0x51D5, 0x83FD, 0x51D6, 0x83FE, 0x51D7, 0x8440, 0x51D8, 0x8441, 0x51D9, 0x8442, 0x51DA, 0x8443, 0x51DC, 0x8444, 0x51DE, 0x8445, 0x51DF, 0x8446, 0x51E2, 0x8447, 0x51E3, 0x8448, 0x51E5, 0x8449, 0x51E6, 0x844A, 0x51E7, 0x844B, 0x51E8, 0x844C, 0x51E9, 0x844D, 0x51EA, 0x844E, 0x51EC, 0x844F, 0x51EE, 0x8450, 0x51F1, 0x8451, 0x51F2, 0x8452, 0x51F4, 0x8453, 0x51F7, 0x8454, 0x51FE, 0x8455, 0x5204, 0x8456, 0x5205, 0x8457, 0x5209, 0x8458, 0x520B, 0x8459, 0x520C, 0x845A, 0x520F, 0x845B, 0x5210, 0x845C, 0x5213, 0x845D, 0x5214, 0x845E, 0x5215, 0x845F, 0x521C, 0x8460, 0x521E, 0x8461, 0x521F, 0x8462, 0x5221, 0x8463, 0x5222, 0x8464, 0x5223, 0x8465, 0x5225, 0x8466, 0x5226, 0x8467, 0x5227, 0x8468, 0x522A, 0x8469, 0x522C, 0x846A, 0x522F, 0x846B, 0x5231, 0x846C, 0x5232, 0x846D, 0x5234, 0x846E, 0x5235, 0x846F, 0x523C, 0x8470, 0x523E, 0x8471, 0x5244, 0x8472, 0x5245, 0x8473, 0x5246, 0x8474, 0x5247, 0x8475, 0x5248, 0x8476, 0x5249, 0x8477, 0x524B, 0x8478, 0x524E, 0x8479, 0x524F, 0x847A, 0x5252, 0x847B, 0x5253, 0x847C, 0x5255, 0x847D, 0x5257, 0x847E, 0x5258, 0x8480, 0x5259, 0x8481, 0x525A, 0x8482, 0x525B, 0x8483, 0x525D, 0x8484, 0x525F, 0x8485, 0x5260, 0x8486, 0x5262, 0x8487, 0x5263, 0x8488, 0x5264, 0x8489, 0x5266, 0x848A, 0x5268, 0x848B, 0x526B, 0x848C, 0x526C, 0x848D, 0x526D, 0x848E, 0x526E, 0x848F, 0x5270, 0x8490, 0x5271, 0x8491, 0x5273, 0x8492, 0x5274, 0x8493, 0x5275, 0x8494, 0x5276, 0x8495, 0x5277, 0x8496, 0x5278, 0x8497, 0x5279, 0x8498, 0x527A, 0x8499, 0x527B, 0x849A, 0x527C, 0x849B, 0x527E, 0x849C, 0x5280, 0x849D, 0x5283, 0x849E, 0x5284, 0x849F, 0x5285, 0x84A0, 0x5286, 0x84A1, 0x5287, 0x84A2, 0x5289, 0x84A3, 0x528A, 0x84A4, 0x528B, 0x84A5, 0x528C, 0x84A6, 0x528D, 0x84A7, 0x528E, 0x84A8, 0x528F, 0x84A9, 0x5291, 0x84AA, 0x5292, 0x84AB, 0x5294, 0x84AC, 0x5295, 0x84AD, 0x5296, 0x84AE, 0x5297, 0x84AF, 0x5298, 0x84B0, 0x5299, 0x84B1, 0x529A, 0x84B2, 0x529C, 0x84B3, 0x52A4, 0x84B4, 0x52A5, 0x84B5, 0x52A6, 0x84B6, 0x52A7, 0x84B7, 0x52AE, 0x84B8, 0x52AF, 0x84B9, 0x52B0, 0x84BA, 0x52B4, 0x84BB, 0x52B5, 0x84BC, 0x52B6, 0x84BD, 0x52B7, 0x84BE, 0x52B8, 0x84BF, 0x52B9, 0x84C0, 0x52BA, 0x84C1, 0x52BB, 0x84C2, 0x52BC, 0x84C3, 0x52BD, 0x84C4, 0x52C0, 0x84C5, 0x52C1, 0x84C6, 0x52C2, 0x84C7, 0x52C4, 0x84C8, 0x52C5, 0x84C9, 0x52C6, 0x84CA, 0x52C8, 0x84CB, 0x52CA, 0x84CC, 0x52CC, 0x84CD, 0x52CD, 0x84CE, 0x52CE, 0x84CF, 0x52CF, 0x84D0, 0x52D1, 0x84D1, 0x52D3, 0x84D2, 0x52D4, 0x84D3, 0x52D5, 0x84D4, 0x52D7, 0x84D5, 0x52D9, 0x84D6, 0x52DA, 0x84D7, 0x52DB, 0x84D8, 0x52DC, 0x84D9, 0x52DD, 0x84DA, 0x52DE, 0x84DB, 0x52E0, 0x84DC, 0x52E1, 0x84DD, 0x52E2, 0x84DE, 0x52E3, 0x84DF, 0x52E5, 0x84E0, 0x52E6, 0x84E1, 0x52E7, 0x84E2, 0x52E8, 0x84E3, 0x52E9, 0x84E4, 0x52EA, 0x84E5, 0x52EB, 0x84E6, 0x52EC, 0x84E7, 0x52ED, 0x84E8, 0x52EE, 0x84E9, 0x52EF, 0x84EA, 0x52F1, 0x84EB, 0x52F2, 0x84EC, 0x52F3, 0x84ED, 0x52F4, 0x84EE, 0x52F5, 0x84EF, 0x52F6, 0x84F0, 0x52F7, 0x84F1, 0x52F8, 0x84F2, 0x52FB, 0x84F3, 0x52FC, 0x84F4, 0x52FD, 0x84F5, 0x5301, 0x84F6, 0x5302, 0x84F7, 0x5303, 0x84F8, 0x5304, 0x84F9, 0x5307, 0x84FA, 0x5309, 0x84FB, 0x530A, 0x84FC, 0x530B, 0x84FD, 0x530C, 0x84FE, 0x530E, 0x8540, 0x5311, 0x8541, 0x5312, 0x8542, 0x5313, 0x8543, 0x5314, 0x8544, 0x5318, 0x8545, 0x531B, 0x8546, 0x531C, 0x8547, 0x531E, 0x8548, 0x531F, 0x8549, 0x5322, 0x854A, 0x5324, 0x854B, 0x5325, 0x854C, 0x5327, 0x854D, 0x5328, 0x854E, 0x5329, 0x854F, 0x532B, 0x8550, 0x532C, 0x8551, 0x532D, 0x8552, 0x532F, 0x8553, 0x5330, 0x8554, 0x5331, 0x8555, 0x5332, 0x8556, 0x5333, 0x8557, 0x5334, 0x8558, 0x5335, 0x8559, 0x5336, 0x855A, 0x5337, 0x855B, 0x5338, 0x855C, 0x533C, 0x855D, 0x533D, 0x855E, 0x5340, 0x855F, 0x5342, 0x8560, 0x5344, 0x8561, 0x5346, 0x8562, 0x534B, 0x8563, 0x534C, 0x8564, 0x534D, 0x8565, 0x5350, 0x8566, 0x5354, 0x8567, 0x5358, 0x8568, 0x5359, 0x8569, 0x535B, 0x856A, 0x535D, 0x856B, 0x5365, 0x856C, 0x5368, 0x856D, 0x536A, 0x856E, 0x536C, 0x856F, 0x536D, 0x8570, 0x5372, 0x8571, 0x5376, 0x8572, 0x5379, 0x8573, 0x537B, 0x8574, 0x537C, 0x8575, 0x537D, 0x8576, 0x537E, 0x8577, 0x5380, 0x8578, 0x5381, 0x8579, 0x5383, 0x857A, 0x5387, 0x857B, 0x5388, 0x857C, 0x538A, 0x857D, 0x538E, 0x857E, 0x538F, 0x8580, 0x5390, 0x8581, 0x5391, 0x8582, 0x5392, 0x8583, 0x5393, 0x8584, 0x5394, 0x8585, 0x5396, 0x8586, 0x5397, 0x8587, 0x5399, 0x8588, 0x539B, 0x8589, 0x539C, 0x858A, 0x539E, 0x858B, 0x53A0, 0x858C, 0x53A1, 0x858D, 0x53A4, 0x858E, 0x53A7, 0x858F, 0x53AA, 0x8590, 0x53AB, 0x8591, 0x53AC, 0x8592, 0x53AD, 0x8593, 0x53AF, 0x8594, 0x53B0, 0x8595, 0x53B1, 0x8596, 0x53B2, 0x8597, 0x53B3, 0x8598, 0x53B4, 0x8599, 0x53B5, 0x859A, 0x53B7, 0x859B, 0x53B8, 0x859C, 0x53B9, 0x859D, 0x53BA, 0x859E, 0x53BC, 0x859F, 0x53BD, 0x85A0, 0x53BE, 0x85A1, 0x53C0, 0x85A2, 0x53C3, 0x85A3, 0x53C4, 0x85A4, 0x53C5, 0x85A5, 0x53C6, 0x85A6, 0x53C7, 0x85A7, 0x53CE, 0x85A8, 0x53CF, 0x85A9, 0x53D0, 0x85AA, 0x53D2, 0x85AB, 0x53D3, 0x85AC, 0x53D5, 0x85AD, 0x53DA, 0x85AE, 0x53DC, 0x85AF, 0x53DD, 0x85B0, 0x53DE, 0x85B1, 0x53E1, 0x85B2, 0x53E2, 0x85B3, 0x53E7, 0x85B4, 0x53F4, 0x85B5, 0x53FA, 0x85B6, 0x53FE, 0x85B7, 0x53FF, 0x85B8, 0x5400, 0x85B9, 0x5402, 0x85BA, 0x5405, 0x85BB, 0x5407, 0x85BC, 0x540B, 0x85BD, 0x5414, 0x85BE, 0x5418, 0x85BF, 0x5419, 0x85C0, 0x541A, 0x85C1, 0x541C, 0x85C2, 0x5422, 0x85C3, 0x5424, 0x85C4, 0x5425, 0x85C5, 0x542A, 0x85C6, 0x5430, 0x85C7, 0x5433, 0x85C8, 0x5436, 0x85C9, 0x5437, 0x85CA, 0x543A, 0x85CB, 0x543D, 0x85CC, 0x543F, 0x85CD, 0x5441, 0x85CE, 0x5442, 0x85CF, 0x5444, 0x85D0, 0x5445, 0x85D1, 0x5447, 0x85D2, 0x5449, 0x85D3, 0x544C, 0x85D4, 0x544D, 0x85D5, 0x544E, 0x85D6, 0x544F, 0x85D7, 0x5451, 0x85D8, 0x545A, 0x85D9, 0x545D, 0x85DA, 0x545E, 0x85DB, 0x545F, 0x85DC, 0x5460, 0x85DD, 0x5461, 0x85DE, 0x5463, 0x85DF, 0x5465, 0x85E0, 0x5467, 0x85E1, 0x5469, 0x85E2, 0x546A, 0x85E3, 0x546B, 0x85E4, 0x546C, 0x85E5, 0x546D, 0x85E6, 0x546E, 0x85E7, 0x546F, 0x85E8, 0x5470, 0x85E9, 0x5474, 0x85EA, 0x5479, 0x85EB, 0x547A, 0x85EC, 0x547E, 0x85ED, 0x547F, 0x85EE, 0x5481, 0x85EF, 0x5483, 0x85F0, 0x5485, 0x85F1, 0x5487, 0x85F2, 0x5488, 0x85F3, 0x5489, 0x85F4, 0x548A, 0x85F5, 0x548D, 0x85F6, 0x5491, 0x85F7, 0x5493, 0x85F8, 0x5497, 0x85F9, 0x5498, 0x85FA, 0x549C, 0x85FB, 0x549E, 0x85FC, 0x549F, 0x85FD, 0x54A0, 0x85FE, 0x54A1, 0x8640, 0x54A2, 0x8641, 0x54A5, 0x8642, 0x54AE, 0x8643, 0x54B0, 0x8644, 0x54B2, 0x8645, 0x54B5, 0x8646, 0x54B6, 0x8647, 0x54B7, 0x8648, 0x54B9, 0x8649, 0x54BA, 0x864A, 0x54BC, 0x864B, 0x54BE, 0x864C, 0x54C3, 0x864D, 0x54C5, 0x864E, 0x54CA, 0x864F, 0x54CB, 0x8650, 0x54D6, 0x8651, 0x54D8, 0x8652, 0x54DB, 0x8653, 0x54E0, 0x8654, 0x54E1, 0x8655, 0x54E2, 0x8656, 0x54E3, 0x8657, 0x54E4, 0x8658, 0x54EB, 0x8659, 0x54EC, 0x865A, 0x54EF, 0x865B, 0x54F0, 0x865C, 0x54F1, 0x865D, 0x54F4, 0x865E, 0x54F5, 0x865F, 0x54F6, 0x8660, 0x54F7, 0x8661, 0x54F8, 0x8662, 0x54F9, 0x8663, 0x54FB, 0x8664, 0x54FE, 0x8665, 0x5500, 0x8666, 0x5502, 0x8667, 0x5503, 0x8668, 0x5504, 0x8669, 0x5505, 0x866A, 0x5508, 0x866B, 0x550A, 0x866C, 0x550B, 0x866D, 0x550C, 0x866E, 0x550D, 0x866F, 0x550E, 0x8670, 0x5512, 0x8671, 0x5513, 0x8672, 0x5515, 0x8673, 0x5516, 0x8674, 0x5517, 0x8675, 0x5518, 0x8676, 0x5519, 0x8677, 0x551A, 0x8678, 0x551C, 0x8679, 0x551D, 0x867A, 0x551E, 0x867B, 0x551F, 0x867C, 0x5521, 0x867D, 0x5525, 0x867E, 0x5526, 0x8680, 0x5528, 0x8681, 0x5529, 0x8682, 0x552B, 0x8683, 0x552D, 0x8684, 0x5532, 0x8685, 0x5534, 0x8686, 0x5535, 0x8687, 0x5536, 0x8688, 0x5538, 0x8689, 0x5539, 0x868A, 0x553A, 0x868B, 0x553B, 0x868C, 0x553D, 0x868D, 0x5540, 0x868E, 0x5542, 0x868F, 0x5545, 0x8690, 0x5547, 0x8691, 0x5548, 0x8692, 0x554B, 0x8693, 0x554C, 0x8694, 0x554D, 0x8695, 0x554E, 0x8696, 0x554F, 0x8697, 0x5551, 0x8698, 0x5552, 0x8699, 0x5553, 0x869A, 0x5554, 0x869B, 0x5557, 0x869C, 0x5558, 0x869D, 0x5559, 0x869E, 0x555A, 0x869F, 0x555B, 0x86A0, 0x555D, 0x86A1, 0x555E, 0x86A2, 0x555F, 0x86A3, 0x5560, 0x86A4, 0x5562, 0x86A5, 0x5563, 0x86A6, 0x5568, 0x86A7, 0x5569, 0x86A8, 0x556B, 0x86A9, 0x556F, 0x86AA, 0x5570, 0x86AB, 0x5571, 0x86AC, 0x5572, 0x86AD, 0x5573, 0x86AE, 0x5574, 0x86AF, 0x5579, 0x86B0, 0x557A, 0x86B1, 0x557D, 0x86B2, 0x557F, 0x86B3, 0x5585, 0x86B4, 0x5586, 0x86B5, 0x558C, 0x86B6, 0x558D, 0x86B7, 0x558E, 0x86B8, 0x5590, 0x86B9, 0x5592, 0x86BA, 0x5593, 0x86BB, 0x5595, 0x86BC, 0x5596, 0x86BD, 0x5597, 0x86BE, 0x559A, 0x86BF, 0x559B, 0x86C0, 0x559E, 0x86C1, 0x55A0, 0x86C2, 0x55A1, 0x86C3, 0x55A2, 0x86C4, 0x55A3, 0x86C5, 0x55A4, 0x86C6, 0x55A5, 0x86C7, 0x55A6, 0x86C8, 0x55A8, 0x86C9, 0x55A9, 0x86CA, 0x55AA, 0x86CB, 0x55AB, 0x86CC, 0x55AC, 0x86CD, 0x55AD, 0x86CE, 0x55AE, 0x86CF, 0x55AF, 0x86D0, 0x55B0, 0x86D1, 0x55B2, 0x86D2, 0x55B4, 0x86D3, 0x55B6, 0x86D4, 0x55B8, 0x86D5, 0x55BA, 0x86D6, 0x55BC, 0x86D7, 0x55BF, 0x86D8, 0x55C0, 0x86D9, 0x55C1, 0x86DA, 0x55C2, 0x86DB, 0x55C3, 0x86DC, 0x55C6, 0x86DD, 0x55C7, 0x86DE, 0x55C8, 0x86DF, 0x55CA, 0x86E0, 0x55CB, 0x86E1, 0x55CE, 0x86E2, 0x55CF, 0x86E3, 0x55D0, 0x86E4, 0x55D5, 0x86E5, 0x55D7, 0x86E6, 0x55D8, 0x86E7, 0x55D9, 0x86E8, 0x55DA, 0x86E9, 0x55DB, 0x86EA, 0x55DE, 0x86EB, 0x55E0, 0x86EC, 0x55E2, 0x86ED, 0x55E7, 0x86EE, 0x55E9, 0x86EF, 0x55ED, 0x86F0, 0x55EE, 0x86F1, 0x55F0, 0x86F2, 0x55F1, 0x86F3, 0x55F4, 0x86F4, 0x55F6, 0x86F5, 0x55F8, 0x86F6, 0x55F9, 0x86F7, 0x55FA, 0x86F8, 0x55FB, 0x86F9, 0x55FC, 0x86FA, 0x55FF, 0x86FB, 0x5602, 0x86FC, 0x5603, 0x86FD, 0x5604, 0x86FE, 0x5605, 0x8740, 0x5606, 0x8741, 0x5607, 0x8742, 0x560A, 0x8743, 0x560B, 0x8744, 0x560D, 0x8745, 0x5610, 0x8746, 0x5611, 0x8747, 0x5612, 0x8748, 0x5613, 0x8749, 0x5614, 0x874A, 0x5615, 0x874B, 0x5616, 0x874C, 0x5617, 0x874D, 0x5619, 0x874E, 0x561A, 0x874F, 0x561C, 0x8750, 0x561D, 0x8751, 0x5620, 0x8752, 0x5621, 0x8753, 0x5622, 0x8754, 0x5625, 0x8755, 0x5626, 0x8756, 0x5628, 0x8757, 0x5629, 0x8758, 0x562A, 0x8759, 0x562B, 0x875A, 0x562E, 0x875B, 0x562F, 0x875C, 0x5630, 0x875D, 0x5633, 0x875E, 0x5635, 0x875F, 0x5637, 0x8760, 0x5638, 0x8761, 0x563A, 0x8762, 0x563C, 0x8763, 0x563D, 0x8764, 0x563E, 0x8765, 0x5640, 0x8766, 0x5641, 0x8767, 0x5642, 0x8768, 0x5643, 0x8769, 0x5644, 0x876A, 0x5645, 0x876B, 0x5646, 0x876C, 0x5647, 0x876D, 0x5648, 0x876E, 0x5649, 0x876F, 0x564A, 0x8770, 0x564B, 0x8771, 0x564F, 0x8772, 0x5650, 0x8773, 0x5651, 0x8774, 0x5652, 0x8775, 0x5653, 0x8776, 0x5655, 0x8777, 0x5656, 0x8778, 0x565A, 0x8779, 0x565B, 0x877A, 0x565D, 0x877B, 0x565E, 0x877C, 0x565F, 0x877D, 0x5660, 0x877E, 0x5661, 0x8780, 0x5663, 0x8781, 0x5665, 0x8782, 0x5666, 0x8783, 0x5667, 0x8784, 0x566D, 0x8785, 0x566E, 0x8786, 0x566F, 0x8787, 0x5670, 0x8788, 0x5672, 0x8789, 0x5673, 0x878A, 0x5674, 0x878B, 0x5675, 0x878C, 0x5677, 0x878D, 0x5678, 0x878E, 0x5679, 0x878F, 0x567A, 0x8790, 0x567D, 0x8791, 0x567E, 0x8792, 0x567F, 0x8793, 0x5680, 0x8794, 0x5681, 0x8795, 0x5682, 0x8796, 0x5683, 0x8797, 0x5684, 0x8798, 0x5687, 0x8799, 0x5688, 0x879A, 0x5689, 0x879B, 0x568A, 0x879C, 0x568B, 0x879D, 0x568C, 0x879E, 0x568D, 0x879F, 0x5690, 0x87A0, 0x5691, 0x87A1, 0x5692, 0x87A2, 0x5694, 0x87A3, 0x5695, 0x87A4, 0x5696, 0x87A5, 0x5697, 0x87A6, 0x5698, 0x87A7, 0x5699, 0x87A8, 0x569A, 0x87A9, 0x569B, 0x87AA, 0x569C, 0x87AB, 0x569D, 0x87AC, 0x569E, 0x87AD, 0x569F, 0x87AE, 0x56A0, 0x87AF, 0x56A1, 0x87B0, 0x56A2, 0x87B1, 0x56A4, 0x87B2, 0x56A5, 0x87B3, 0x56A6, 0x87B4, 0x56A7, 0x87B5, 0x56A8, 0x87B6, 0x56A9, 0x87B7, 0x56AA, 0x87B8, 0x56AB, 0x87B9, 0x56AC, 0x87BA, 0x56AD, 0x87BB, 0x56AE, 0x87BC, 0x56B0, 0x87BD, 0x56B1, 0x87BE, 0x56B2, 0x87BF, 0x56B3, 0x87C0, 0x56B4, 0x87C1, 0x56B5, 0x87C2, 0x56B6, 0x87C3, 0x56B8, 0x87C4, 0x56B9, 0x87C5, 0x56BA, 0x87C6, 0x56BB, 0x87C7, 0x56BD, 0x87C8, 0x56BE, 0x87C9, 0x56BF, 0x87CA, 0x56C0, 0x87CB, 0x56C1, 0x87CC, 0x56C2, 0x87CD, 0x56C3, 0x87CE, 0x56C4, 0x87CF, 0x56C5, 0x87D0, 0x56C6, 0x87D1, 0x56C7, 0x87D2, 0x56C8, 0x87D3, 0x56C9, 0x87D4, 0x56CB, 0x87D5, 0x56CC, 0x87D6, 0x56CD, 0x87D7, 0x56CE, 0x87D8, 0x56CF, 0x87D9, 0x56D0, 0x87DA, 0x56D1, 0x87DB, 0x56D2, 0x87DC, 0x56D3, 0x87DD, 0x56D5, 0x87DE, 0x56D6, 0x87DF, 0x56D8, 0x87E0, 0x56D9, 0x87E1, 0x56DC, 0x87E2, 0x56E3, 0x87E3, 0x56E5, 0x87E4, 0x56E6, 0x87E5, 0x56E7, 0x87E6, 0x56E8, 0x87E7, 0x56E9, 0x87E8, 0x56EA, 0x87E9, 0x56EC, 0x87EA, 0x56EE, 0x87EB, 0x56EF, 0x87EC, 0x56F2, 0x87ED, 0x56F3, 0x87EE, 0x56F6, 0x87EF, 0x56F7, 0x87F0, 0x56F8, 0x87F1, 0x56FB, 0x87F2, 0x56FC, 0x87F3, 0x5700, 0x87F4, 0x5701, 0x87F5, 0x5702, 0x87F6, 0x5705, 0x87F7, 0x5707, 0x87F8, 0x570B, 0x87F9, 0x570C, 0x87FA, 0x570D, 0x87FB, 0x570E, 0x87FC, 0x570F, 0x87FD, 0x5710, 0x87FE, 0x5711, 0x8840, 0x5712, 0x8841, 0x5713, 0x8842, 0x5714, 0x8843, 0x5715, 0x8844, 0x5716, 0x8845, 0x5717, 0x8846, 0x5718, 0x8847, 0x5719, 0x8848, 0x571A, 0x8849, 0x571B, 0x884A, 0x571D, 0x884B, 0x571E, 0x884C, 0x5720, 0x884D, 0x5721, 0x884E, 0x5722, 0x884F, 0x5724, 0x8850, 0x5725, 0x8851, 0x5726, 0x8852, 0x5727, 0x8853, 0x572B, 0x8854, 0x5731, 0x8855, 0x5732, 0x8856, 0x5734, 0x8857, 0x5735, 0x8858, 0x5736, 0x8859, 0x5737, 0x885A, 0x5738, 0x885B, 0x573C, 0x885C, 0x573D, 0x885D, 0x573F, 0x885E, 0x5741, 0x885F, 0x5743, 0x8860, 0x5744, 0x8861, 0x5745, 0x8862, 0x5746, 0x8863, 0x5748, 0x8864, 0x5749, 0x8865, 0x574B, 0x8866, 0x5752, 0x8867, 0x5753, 0x8868, 0x5754, 0x8869, 0x5755, 0x886A, 0x5756, 0x886B, 0x5758, 0x886C, 0x5759, 0x886D, 0x5762, 0x886E, 0x5763, 0x886F, 0x5765, 0x8870, 0x5767, 0x8871, 0x576C, 0x8872, 0x576E, 0x8873, 0x5770, 0x8874, 0x5771, 0x8875, 0x5772, 0x8876, 0x5774, 0x8877, 0x5775, 0x8878, 0x5778, 0x8879, 0x5779, 0x887A, 0x577A, 0x887B, 0x577D, 0x887C, 0x577E, 0x887D, 0x577F, 0x887E, 0x5780, 0x8880, 0x5781, 0x8881, 0x5787, 0x8882, 0x5788, 0x8883, 0x5789, 0x8884, 0x578A, 0x8885, 0x578D, 0x8886, 0x578E, 0x8887, 0x578F, 0x8888, 0x5790, 0x8889, 0x5791, 0x888A, 0x5794, 0x888B, 0x5795, 0x888C, 0x5796, 0x888D, 0x5797, 0x888E, 0x5798, 0x888F, 0x5799, 0x8890, 0x579A, 0x8891, 0x579C, 0x8892, 0x579D, 0x8893, 0x579E, 0x8894, 0x579F, 0x8895, 0x57A5, 0x8896, 0x57A8, 0x8897, 0x57AA, 0x8898, 0x57AC, 0x8899, 0x57AF, 0x889A, 0x57B0, 0x889B, 0x57B1, 0x889C, 0x57B3, 0x889D, 0x57B5, 0x889E, 0x57B6, 0x889F, 0x57B7, 0x88A0, 0x57B9, 0x88A1, 0x57BA, 0x88A2, 0x57BB, 0x88A3, 0x57BC, 0x88A4, 0x57BD, 0x88A5, 0x57BE, 0x88A6, 0x57BF, 0x88A7, 0x57C0, 0x88A8, 0x57C1, 0x88A9, 0x57C4, 0x88AA, 0x57C5, 0x88AB, 0x57C6, 0x88AC, 0x57C7, 0x88AD, 0x57C8, 0x88AE, 0x57C9, 0x88AF, 0x57CA, 0x88B0, 0x57CC, 0x88B1, 0x57CD, 0x88B2, 0x57D0, 0x88B3, 0x57D1, 0x88B4, 0x57D3, 0x88B5, 0x57D6, 0x88B6, 0x57D7, 0x88B7, 0x57DB, 0x88B8, 0x57DC, 0x88B9, 0x57DE, 0x88BA, 0x57E1, 0x88BB, 0x57E2, 0x88BC, 0x57E3, 0x88BD, 0x57E5, 0x88BE, 0x57E6, 0x88BF, 0x57E7, 0x88C0, 0x57E8, 0x88C1, 0x57E9, 0x88C2, 0x57EA, 0x88C3, 0x57EB, 0x88C4, 0x57EC, 0x88C5, 0x57EE, 0x88C6, 0x57F0, 0x88C7, 0x57F1, 0x88C8, 0x57F2, 0x88C9, 0x57F3, 0x88CA, 0x57F5, 0x88CB, 0x57F6, 0x88CC, 0x57F7, 0x88CD, 0x57FB, 0x88CE, 0x57FC, 0x88CF, 0x57FE, 0x88D0, 0x57FF, 0x88D1, 0x5801, 0x88D2, 0x5803, 0x88D3, 0x5804, 0x88D4, 0x5805, 0x88D5, 0x5808, 0x88D6, 0x5809, 0x88D7, 0x580A, 0x88D8, 0x580C, 0x88D9, 0x580E, 0x88DA, 0x580F, 0x88DB, 0x5810, 0x88DC, 0x5812, 0x88DD, 0x5813, 0x88DE, 0x5814, 0x88DF, 0x5816, 0x88E0, 0x5817, 0x88E1, 0x5818, 0x88E2, 0x581A, 0x88E3, 0x581B, 0x88E4, 0x581C, 0x88E5, 0x581D, 0x88E6, 0x581F, 0x88E7, 0x5822, 0x88E8, 0x5823, 0x88E9, 0x5825, 0x88EA, 0x5826, 0x88EB, 0x5827, 0x88EC, 0x5828, 0x88ED, 0x5829, 0x88EE, 0x582B, 0x88EF, 0x582C, 0x88F0, 0x582D, 0x88F1, 0x582E, 0x88F2, 0x582F, 0x88F3, 0x5831, 0x88F4, 0x5832, 0x88F5, 0x5833, 0x88F6, 0x5834, 0x88F7, 0x5836, 0x88F8, 0x5837, 0x88F9, 0x5838, 0x88FA, 0x5839, 0x88FB, 0x583A, 0x88FC, 0x583B, 0x88FD, 0x583C, 0x88FE, 0x583D, 0x8940, 0x583E, 0x8941, 0x583F, 0x8942, 0x5840, 0x8943, 0x5841, 0x8944, 0x5842, 0x8945, 0x5843, 0x8946, 0x5845, 0x8947, 0x5846, 0x8948, 0x5847, 0x8949, 0x5848, 0x894A, 0x5849, 0x894B, 0x584A, 0x894C, 0x584B, 0x894D, 0x584E, 0x894E, 0x584F, 0x894F, 0x5850, 0x8950, 0x5852, 0x8951, 0x5853, 0x8952, 0x5855, 0x8953, 0x5856, 0x8954, 0x5857, 0x8955, 0x5859, 0x8956, 0x585A, 0x8957, 0x585B, 0x8958, 0x585C, 0x8959, 0x585D, 0x895A, 0x585F, 0x895B, 0x5860, 0x895C, 0x5861, 0x895D, 0x5862, 0x895E, 0x5863, 0x895F, 0x5864, 0x8960, 0x5866, 0x8961, 0x5867, 0x8962, 0x5868, 0x8963, 0x5869, 0x8964, 0x586A, 0x8965, 0x586D, 0x8966, 0x586E, 0x8967, 0x586F, 0x8968, 0x5870, 0x8969, 0x5871, 0x896A, 0x5872, 0x896B, 0x5873, 0x896C, 0x5874, 0x896D, 0x5875, 0x896E, 0x5876, 0x896F, 0x5877, 0x8970, 0x5878, 0x8971, 0x5879, 0x8972, 0x587A, 0x8973, 0x587B, 0x8974, 0x587C, 0x8975, 0x587D, 0x8976, 0x587F, 0x8977, 0x5882, 0x8978, 0x5884, 0x8979, 0x5886, 0x897A, 0x5887, 0x897B, 0x5888, 0x897C, 0x588A, 0x897D, 0x588B, 0x897E, 0x588C, 0x8980, 0x588D, 0x8981, 0x588E, 0x8982, 0x588F, 0x8983, 0x5890, 0x8984, 0x5891, 0x8985, 0x5894, 0x8986, 0x5895, 0x8987, 0x5896, 0x8988, 0x5897, 0x8989, 0x5898, 0x898A, 0x589B, 0x898B, 0x589C, 0x898C, 0x589D, 0x898D, 0x58A0, 0x898E, 0x58A1, 0x898F, 0x58A2, 0x8990, 0x58A3, 0x8991, 0x58A4, 0x8992, 0x58A5, 0x8993, 0x58A6, 0x8994, 0x58A7, 0x8995, 0x58AA, 0x8996, 0x58AB, 0x8997, 0x58AC, 0x8998, 0x58AD, 0x8999, 0x58AE, 0x899A, 0x58AF, 0x899B, 0x58B0, 0x899C, 0x58B1, 0x899D, 0x58B2, 0x899E, 0x58B3, 0x899F, 0x58B4, 0x89A0, 0x58B5, 0x89A1, 0x58B6, 0x89A2, 0x58B7, 0x89A3, 0x58B8, 0x89A4, 0x58B9, 0x89A5, 0x58BA, 0x89A6, 0x58BB, 0x89A7, 0x58BD, 0x89A8, 0x58BE, 0x89A9, 0x58BF, 0x89AA, 0x58C0, 0x89AB, 0x58C2, 0x89AC, 0x58C3, 0x89AD, 0x58C4, 0x89AE, 0x58C6, 0x89AF, 0x58C7, 0x89B0, 0x58C8, 0x89B1, 0x58C9, 0x89B2, 0x58CA, 0x89B3, 0x58CB, 0x89B4, 0x58CC, 0x89B5, 0x58CD, 0x89B6, 0x58CE, 0x89B7, 0x58CF, 0x89B8, 0x58D0, 0x89B9, 0x58D2, 0x89BA, 0x58D3, 0x89BB, 0x58D4, 0x89BC, 0x58D6, 0x89BD, 0x58D7, 0x89BE, 0x58D8, 0x89BF, 0x58D9, 0x89C0, 0x58DA, 0x89C1, 0x58DB, 0x89C2, 0x58DC, 0x89C3, 0x58DD, 0x89C4, 0x58DE, 0x89C5, 0x58DF, 0x89C6, 0x58E0, 0x89C7, 0x58E1, 0x89C8, 0x58E2, 0x89C9, 0x58E3, 0x89CA, 0x58E5, 0x89CB, 0x58E6, 0x89CC, 0x58E7, 0x89CD, 0x58E8, 0x89CE, 0x58E9, 0x89CF, 0x58EA, 0x89D0, 0x58ED, 0x89D1, 0x58EF, 0x89D2, 0x58F1, 0x89D3, 0x58F2, 0x89D4, 0x58F4, 0x89D5, 0x58F5, 0x89D6, 0x58F7, 0x89D7, 0x58F8, 0x89D8, 0x58FA, 0x89D9, 0x58FB, 0x89DA, 0x58FC, 0x89DB, 0x58FD, 0x89DC, 0x58FE, 0x89DD, 0x58FF, 0x89DE, 0x5900, 0x89DF, 0x5901, 0x89E0, 0x5903, 0x89E1, 0x5905, 0x89E2, 0x5906, 0x89E3, 0x5908, 0x89E4, 0x5909, 0x89E5, 0x590A, 0x89E6, 0x590B, 0x89E7, 0x590C, 0x89E8, 0x590E, 0x89E9, 0x5910, 0x89EA, 0x5911, 0x89EB, 0x5912, 0x89EC, 0x5913, 0x89ED, 0x5917, 0x89EE, 0x5918, 0x89EF, 0x591B, 0x89F0, 0x591D, 0x89F1, 0x591E, 0x89F2, 0x5920, 0x89F3, 0x5921, 0x89F4, 0x5922, 0x89F5, 0x5923, 0x89F6, 0x5926, 0x89F7, 0x5928, 0x89F8, 0x592C, 0x89F9, 0x5930, 0x89FA, 0x5932, 0x89FB, 0x5933, 0x89FC, 0x5935, 0x89FD, 0x5936, 0x89FE, 0x593B, 0x8A40, 0x593D, 0x8A41, 0x593E, 0x8A42, 0x593F, 0x8A43, 0x5940, 0x8A44, 0x5943, 0x8A45, 0x5945, 0x8A46, 0x5946, 0x8A47, 0x594A, 0x8A48, 0x594C, 0x8A49, 0x594D, 0x8A4A, 0x5950, 0x8A4B, 0x5952, 0x8A4C, 0x5953, 0x8A4D, 0x5959, 0x8A4E, 0x595B, 0x8A4F, 0x595C, 0x8A50, 0x595D, 0x8A51, 0x595E, 0x8A52, 0x595F, 0x8A53, 0x5961, 0x8A54, 0x5963, 0x8A55, 0x5964, 0x8A56, 0x5966, 0x8A57, 0x5967, 0x8A58, 0x5968, 0x8A59, 0x5969, 0x8A5A, 0x596A, 0x8A5B, 0x596B, 0x8A5C, 0x596C, 0x8A5D, 0x596D, 0x8A5E, 0x596E, 0x8A5F, 0x596F, 0x8A60, 0x5970, 0x8A61, 0x5971, 0x8A62, 0x5972, 0x8A63, 0x5975, 0x8A64, 0x5977, 0x8A65, 0x597A, 0x8A66, 0x597B, 0x8A67, 0x597C, 0x8A68, 0x597E, 0x8A69, 0x597F, 0x8A6A, 0x5980, 0x8A6B, 0x5985, 0x8A6C, 0x5989, 0x8A6D, 0x598B, 0x8A6E, 0x598C, 0x8A6F, 0x598E, 0x8A70, 0x598F, 0x8A71, 0x5990, 0x8A72, 0x5991, 0x8A73, 0x5994, 0x8A74, 0x5995, 0x8A75, 0x5998, 0x8A76, 0x599A, 0x8A77, 0x599B, 0x8A78, 0x599C, 0x8A79, 0x599D, 0x8A7A, 0x599F, 0x8A7B, 0x59A0, 0x8A7C, 0x59A1, 0x8A7D, 0x59A2, 0x8A7E, 0x59A6, 0x8A80, 0x59A7, 0x8A81, 0x59AC, 0x8A82, 0x59AD, 0x8A83, 0x59B0, 0x8A84, 0x59B1, 0x8A85, 0x59B3, 0x8A86, 0x59B4, 0x8A87, 0x59B5, 0x8A88, 0x59B6, 0x8A89, 0x59B7, 0x8A8A, 0x59B8, 0x8A8B, 0x59BA, 0x8A8C, 0x59BC, 0x8A8D, 0x59BD, 0x8A8E, 0x59BF, 0x8A8F, 0x59C0, 0x8A90, 0x59C1, 0x8A91, 0x59C2, 0x8A92, 0x59C3, 0x8A93, 0x59C4, 0x8A94, 0x59C5, 0x8A95, 0x59C7, 0x8A96, 0x59C8, 0x8A97, 0x59C9, 0x8A98, 0x59CC, 0x8A99, 0x59CD, 0x8A9A, 0x59CE, 0x8A9B, 0x59CF, 0x8A9C, 0x59D5, 0x8A9D, 0x59D6, 0x8A9E, 0x59D9, 0x8A9F, 0x59DB, 0x8AA0, 0x59DE, 0x8AA1, 0x59DF, 0x8AA2, 0x59E0, 0x8AA3, 0x59E1, 0x8AA4, 0x59E2, 0x8AA5, 0x59E4, 0x8AA6, 0x59E6, 0x8AA7, 0x59E7, 0x8AA8, 0x59E9, 0x8AA9, 0x59EA, 0x8AAA, 0x59EB, 0x8AAB, 0x59ED, 0x8AAC, 0x59EE, 0x8AAD, 0x59EF, 0x8AAE, 0x59F0, 0x8AAF, 0x59F1, 0x8AB0, 0x59F2, 0x8AB1, 0x59F3, 0x8AB2, 0x59F4, 0x8AB3, 0x59F5, 0x8AB4, 0x59F6, 0x8AB5, 0x59F7, 0x8AB6, 0x59F8, 0x8AB7, 0x59FA, 0x8AB8, 0x59FC, 0x8AB9, 0x59FD, 0x8ABA, 0x59FE, 0x8ABB, 0x5A00, 0x8ABC, 0x5A02, 0x8ABD, 0x5A0A, 0x8ABE, 0x5A0B, 0x8ABF, 0x5A0D, 0x8AC0, 0x5A0E, 0x8AC1, 0x5A0F, 0x8AC2, 0x5A10, 0x8AC3, 0x5A12, 0x8AC4, 0x5A14, 0x8AC5, 0x5A15, 0x8AC6, 0x5A16, 0x8AC7, 0x5A17, 0x8AC8, 0x5A19, 0x8AC9, 0x5A1A, 0x8ACA, 0x5A1B, 0x8ACB, 0x5A1D, 0x8ACC, 0x5A1E, 0x8ACD, 0x5A21, 0x8ACE, 0x5A22, 0x8ACF, 0x5A24, 0x8AD0, 0x5A26, 0x8AD1, 0x5A27, 0x8AD2, 0x5A28, 0x8AD3, 0x5A2A, 0x8AD4, 0x5A2B, 0x8AD5, 0x5A2C, 0x8AD6, 0x5A2D, 0x8AD7, 0x5A2E, 0x8AD8, 0x5A2F, 0x8AD9, 0x5A30, 0x8ADA, 0x5A33, 0x8ADB, 0x5A35, 0x8ADC, 0x5A37, 0x8ADD, 0x5A38, 0x8ADE, 0x5A39, 0x8ADF, 0x5A3A, 0x8AE0, 0x5A3B, 0x8AE1, 0x5A3D, 0x8AE2, 0x5A3E, 0x8AE3, 0x5A3F, 0x8AE4, 0x5A41, 0x8AE5, 0x5A42, 0x8AE6, 0x5A43, 0x8AE7, 0x5A44, 0x8AE8, 0x5A45, 0x8AE9, 0x5A47, 0x8AEA, 0x5A48, 0x8AEB, 0x5A4B, 0x8AEC, 0x5A4C, 0x8AED, 0x5A4D, 0x8AEE, 0x5A4E, 0x8AEF, 0x5A4F, 0x8AF0, 0x5A50, 0x8AF1, 0x5A51, 0x8AF2, 0x5A52, 0x8AF3, 0x5A53, 0x8AF4, 0x5A54, 0x8AF5, 0x5A56, 0x8AF6, 0x5A57, 0x8AF7, 0x5A58, 0x8AF8, 0x5A59, 0x8AF9, 0x5A5B, 0x8AFA, 0x5A5C, 0x8AFB, 0x5A5D, 0x8AFC, 0x5A5E, 0x8AFD, 0x5A5F, 0x8AFE, 0x5A60, 0x8B40, 0x5A61, 0x8B41, 0x5A63, 0x8B42, 0x5A64, 0x8B43, 0x5A65, 0x8B44, 0x5A66, 0x8B45, 0x5A68, 0x8B46, 0x5A69, 0x8B47, 0x5A6B, 0x8B48, 0x5A6C, 0x8B49, 0x5A6D, 0x8B4A, 0x5A6E, 0x8B4B, 0x5A6F, 0x8B4C, 0x5A70, 0x8B4D, 0x5A71, 0x8B4E, 0x5A72, 0x8B4F, 0x5A73, 0x8B50, 0x5A78, 0x8B51, 0x5A79, 0x8B52, 0x5A7B, 0x8B53, 0x5A7C, 0x8B54, 0x5A7D, 0x8B55, 0x5A7E, 0x8B56, 0x5A80, 0x8B57, 0x5A81, 0x8B58, 0x5A82, 0x8B59, 0x5A83, 0x8B5A, 0x5A84, 0x8B5B, 0x5A85, 0x8B5C, 0x5A86, 0x8B5D, 0x5A87, 0x8B5E, 0x5A88, 0x8B5F, 0x5A89, 0x8B60, 0x5A8A, 0x8B61, 0x5A8B, 0x8B62, 0x5A8C, 0x8B63, 0x5A8D, 0x8B64, 0x5A8E, 0x8B65, 0x5A8F, 0x8B66, 0x5A90, 0x8B67, 0x5A91, 0x8B68, 0x5A93, 0x8B69, 0x5A94, 0x8B6A, 0x5A95, 0x8B6B, 0x5A96, 0x8B6C, 0x5A97, 0x8B6D, 0x5A98, 0x8B6E, 0x5A99, 0x8B6F, 0x5A9C, 0x8B70, 0x5A9D, 0x8B71, 0x5A9E, 0x8B72, 0x5A9F, 0x8B73, 0x5AA0, 0x8B74, 0x5AA1, 0x8B75, 0x5AA2, 0x8B76, 0x5AA3, 0x8B77, 0x5AA4, 0x8B78, 0x5AA5, 0x8B79, 0x5AA6, 0x8B7A, 0x5AA7, 0x8B7B, 0x5AA8, 0x8B7C, 0x5AA9, 0x8B7D, 0x5AAB, 0x8B7E, 0x5AAC, 0x8B80, 0x5AAD, 0x8B81, 0x5AAE, 0x8B82, 0x5AAF, 0x8B83, 0x5AB0, 0x8B84, 0x5AB1, 0x8B85, 0x5AB4, 0x8B86, 0x5AB6, 0x8B87, 0x5AB7, 0x8B88, 0x5AB9, 0x8B89, 0x5ABA, 0x8B8A, 0x5ABB, 0x8B8B, 0x5ABC, 0x8B8C, 0x5ABD, 0x8B8D, 0x5ABF, 0x8B8E, 0x5AC0, 0x8B8F, 0x5AC3, 0x8B90, 0x5AC4, 0x8B91, 0x5AC5, 0x8B92, 0x5AC6, 0x8B93, 0x5AC7, 0x8B94, 0x5AC8, 0x8B95, 0x5ACA, 0x8B96, 0x5ACB, 0x8B97, 0x5ACD, 0x8B98, 0x5ACE, 0x8B99, 0x5ACF, 0x8B9A, 0x5AD0, 0x8B9B, 0x5AD1, 0x8B9C, 0x5AD3, 0x8B9D, 0x5AD5, 0x8B9E, 0x5AD7, 0x8B9F, 0x5AD9, 0x8BA0, 0x5ADA, 0x8BA1, 0x5ADB, 0x8BA2, 0x5ADD, 0x8BA3, 0x5ADE, 0x8BA4, 0x5ADF, 0x8BA5, 0x5AE2, 0x8BA6, 0x5AE4, 0x8BA7, 0x5AE5, 0x8BA8, 0x5AE7, 0x8BA9, 0x5AE8, 0x8BAA, 0x5AEA, 0x8BAB, 0x5AEC, 0x8BAC, 0x5AED, 0x8BAD, 0x5AEE, 0x8BAE, 0x5AEF, 0x8BAF, 0x5AF0, 0x8BB0, 0x5AF2, 0x8BB1, 0x5AF3, 0x8BB2, 0x5AF4, 0x8BB3, 0x5AF5, 0x8BB4, 0x5AF6, 0x8BB5, 0x5AF7, 0x8BB6, 0x5AF8, 0x8BB7, 0x5AF9, 0x8BB8, 0x5AFA, 0x8BB9, 0x5AFB, 0x8BBA, 0x5AFC, 0x8BBB, 0x5AFD, 0x8BBC, 0x5AFE, 0x8BBD, 0x5AFF, 0x8BBE, 0x5B00, 0x8BBF, 0x5B01, 0x8BC0, 0x5B02, 0x8BC1, 0x5B03, 0x8BC2, 0x5B04, 0x8BC3, 0x5B05, 0x8BC4, 0x5B06, 0x8BC5, 0x5B07, 0x8BC6, 0x5B08, 0x8BC7, 0x5B0A, 0x8BC8, 0x5B0B, 0x8BC9, 0x5B0C, 0x8BCA, 0x5B0D, 0x8BCB, 0x5B0E, 0x8BCC, 0x5B0F, 0x8BCD, 0x5B10, 0x8BCE, 0x5B11, 0x8BCF, 0x5B12, 0x8BD0, 0x5B13, 0x8BD1, 0x5B14, 0x8BD2, 0x5B15, 0x8BD3, 0x5B18, 0x8BD4, 0x5B19, 0x8BD5, 0x5B1A, 0x8BD6, 0x5B1B, 0x8BD7, 0x5B1C, 0x8BD8, 0x5B1D, 0x8BD9, 0x5B1E, 0x8BDA, 0x5B1F, 0x8BDB, 0x5B20, 0x8BDC, 0x5B21, 0x8BDD, 0x5B22, 0x8BDE, 0x5B23, 0x8BDF, 0x5B24, 0x8BE0, 0x5B25, 0x8BE1, 0x5B26, 0x8BE2, 0x5B27, 0x8BE3, 0x5B28, 0x8BE4, 0x5B29, 0x8BE5, 0x5B2A, 0x8BE6, 0x5B2B, 0x8BE7, 0x5B2C, 0x8BE8, 0x5B2D, 0x8BE9, 0x5B2E, 0x8BEA, 0x5B2F, 0x8BEB, 0x5B30, 0x8BEC, 0x5B31, 0x8BED, 0x5B33, 0x8BEE, 0x5B35, 0x8BEF, 0x5B36, 0x8BF0, 0x5B38, 0x8BF1, 0x5B39, 0x8BF2, 0x5B3A, 0x8BF3, 0x5B3B, 0x8BF4, 0x5B3C, 0x8BF5, 0x5B3D, 0x8BF6, 0x5B3E, 0x8BF7, 0x5B3F, 0x8BF8, 0x5B41, 0x8BF9, 0x5B42, 0x8BFA, 0x5B43, 0x8BFB, 0x5B44, 0x8BFC, 0x5B45, 0x8BFD, 0x5B46, 0x8BFE, 0x5B47, 0x8C40, 0x5B48, 0x8C41, 0x5B49, 0x8C42, 0x5B4A, 0x8C43, 0x5B4B, 0x8C44, 0x5B4C, 0x8C45, 0x5B4D, 0x8C46, 0x5B4E, 0x8C47, 0x5B4F, 0x8C48, 0x5B52, 0x8C49, 0x5B56, 0x8C4A, 0x5B5E, 0x8C4B, 0x5B60, 0x8C4C, 0x5B61, 0x8C4D, 0x5B67, 0x8C4E, 0x5B68, 0x8C4F, 0x5B6B, 0x8C50, 0x5B6D, 0x8C51, 0x5B6E, 0x8C52, 0x5B6F, 0x8C53, 0x5B72, 0x8C54, 0x5B74, 0x8C55, 0x5B76, 0x8C56, 0x5B77, 0x8C57, 0x5B78, 0x8C58, 0x5B79, 0x8C59, 0x5B7B, 0x8C5A, 0x5B7C, 0x8C5B, 0x5B7E, 0x8C5C, 0x5B7F, 0x8C5D, 0x5B82, 0x8C5E, 0x5B86, 0x8C5F, 0x5B8A, 0x8C60, 0x5B8D, 0x8C61, 0x5B8E, 0x8C62, 0x5B90, 0x8C63, 0x5B91, 0x8C64, 0x5B92, 0x8C65, 0x5B94, 0x8C66, 0x5B96, 0x8C67, 0x5B9F, 0x8C68, 0x5BA7, 0x8C69, 0x5BA8, 0x8C6A, 0x5BA9, 0x8C6B, 0x5BAC, 0x8C6C, 0x5BAD, 0x8C6D, 0x5BAE, 0x8C6E, 0x5BAF, 0x8C6F, 0x5BB1, 0x8C70, 0x5BB2, 0x8C71, 0x5BB7, 0x8C72, 0x5BBA, 0x8C73, 0x5BBB, 0x8C74, 0x5BBC, 0x8C75, 0x5BC0, 0x8C76, 0x5BC1, 0x8C77, 0x5BC3, 0x8C78, 0x5BC8, 0x8C79, 0x5BC9, 0x8C7A, 0x5BCA, 0x8C7B, 0x5BCB, 0x8C7C, 0x5BCD, 0x8C7D, 0x5BCE, 0x8C7E, 0x5BCF, 0x8C80, 0x5BD1, 0x8C81, 0x5BD4, 0x8C82, 0x5BD5, 0x8C83, 0x5BD6, 0x8C84, 0x5BD7, 0x8C85, 0x5BD8, 0x8C86, 0x5BD9, 0x8C87, 0x5BDA, 0x8C88, 0x5BDB, 0x8C89, 0x5BDC, 0x8C8A, 0x5BE0, 0x8C8B, 0x5BE2, 0x8C8C, 0x5BE3, 0x8C8D, 0x5BE6, 0x8C8E, 0x5BE7, 0x8C8F, 0x5BE9, 0x8C90, 0x5BEA, 0x8C91, 0x5BEB, 0x8C92, 0x5BEC, 0x8C93, 0x5BED, 0x8C94, 0x5BEF, 0x8C95, 0x5BF1, 0x8C96, 0x5BF2, 0x8C97, 0x5BF3, 0x8C98, 0x5BF4, 0x8C99, 0x5BF5, 0x8C9A, 0x5BF6, 0x8C9B, 0x5BF7, 0x8C9C, 0x5BFD, 0x8C9D, 0x5BFE, 0x8C9E, 0x5C00, 0x8C9F, 0x5C02, 0x8CA0, 0x5C03, 0x8CA1, 0x5C05, 0x8CA2, 0x5C07, 0x8CA3, 0x5C08, 0x8CA4, 0x5C0B, 0x8CA5, 0x5C0C, 0x8CA6, 0x5C0D, 0x8CA7, 0x5C0E, 0x8CA8, 0x5C10, 0x8CA9, 0x5C12, 0x8CAA, 0x5C13, 0x8CAB, 0x5C17, 0x8CAC, 0x5C19, 0x8CAD, 0x5C1B, 0x8CAE, 0x5C1E, 0x8CAF, 0x5C1F, 0x8CB0, 0x5C20, 0x8CB1, 0x5C21, 0x8CB2, 0x5C23, 0x8CB3, 0x5C26, 0x8CB4, 0x5C28, 0x8CB5, 0x5C29, 0x8CB6, 0x5C2A, 0x8CB7, 0x5C2B, 0x8CB8, 0x5C2D, 0x8CB9, 0x5C2E, 0x8CBA, 0x5C2F, 0x8CBB, 0x5C30, 0x8CBC, 0x5C32, 0x8CBD, 0x5C33, 0x8CBE, 0x5C35, 0x8CBF, 0x5C36, 0x8CC0, 0x5C37, 0x8CC1, 0x5C43, 0x8CC2, 0x5C44, 0x8CC3, 0x5C46, 0x8CC4, 0x5C47, 0x8CC5, 0x5C4C, 0x8CC6, 0x5C4D, 0x8CC7, 0x5C52, 0x8CC8, 0x5C53, 0x8CC9, 0x5C54, 0x8CCA, 0x5C56, 0x8CCB, 0x5C57, 0x8CCC, 0x5C58, 0x8CCD, 0x5C5A, 0x8CCE, 0x5C5B, 0x8CCF, 0x5C5C, 0x8CD0, 0x5C5D, 0x8CD1, 0x5C5F, 0x8CD2, 0x5C62, 0x8CD3, 0x5C64, 0x8CD4, 0x5C67, 0x8CD5, 0x5C68, 0x8CD6, 0x5C69, 0x8CD7, 0x5C6A, 0x8CD8, 0x5C6B, 0x8CD9, 0x5C6C, 0x8CDA, 0x5C6D, 0x8CDB, 0x5C70, 0x8CDC, 0x5C72, 0x8CDD, 0x5C73, 0x8CDE, 0x5C74, 0x8CDF, 0x5C75, 0x8CE0, 0x5C76, 0x8CE1, 0x5C77, 0x8CE2, 0x5C78, 0x8CE3, 0x5C7B, 0x8CE4, 0x5C7C, 0x8CE5, 0x5C7D, 0x8CE6, 0x5C7E, 0x8CE7, 0x5C80, 0x8CE8, 0x5C83, 0x8CE9, 0x5C84, 0x8CEA, 0x5C85, 0x8CEB, 0x5C86, 0x8CEC, 0x5C87, 0x8CED, 0x5C89, 0x8CEE, 0x5C8A, 0x8CEF, 0x5C8B, 0x8CF0, 0x5C8E, 0x8CF1, 0x5C8F, 0x8CF2, 0x5C92, 0x8CF3, 0x5C93, 0x8CF4, 0x5C95, 0x8CF5, 0x5C9D, 0x8CF6, 0x5C9E, 0x8CF7, 0x5C9F, 0x8CF8, 0x5CA0, 0x8CF9, 0x5CA1, 0x8CFA, 0x5CA4, 0x8CFB, 0x5CA5, 0x8CFC, 0x5CA6, 0x8CFD, 0x5CA7, 0x8CFE, 0x5CA8, 0x8D40, 0x5CAA, 0x8D41, 0x5CAE, 0x8D42, 0x5CAF, 0x8D43, 0x5CB0, 0x8D44, 0x5CB2, 0x8D45, 0x5CB4, 0x8D46, 0x5CB6, 0x8D47, 0x5CB9, 0x8D48, 0x5CBA, 0x8D49, 0x5CBB, 0x8D4A, 0x5CBC, 0x8D4B, 0x5CBE, 0x8D4C, 0x5CC0, 0x8D4D, 0x5CC2, 0x8D4E, 0x5CC3, 0x8D4F, 0x5CC5, 0x8D50, 0x5CC6, 0x8D51, 0x5CC7, 0x8D52, 0x5CC8, 0x8D53, 0x5CC9, 0x8D54, 0x5CCA, 0x8D55, 0x5CCC, 0x8D56, 0x5CCD, 0x8D57, 0x5CCE, 0x8D58, 0x5CCF, 0x8D59, 0x5CD0, 0x8D5A, 0x5CD1, 0x8D5B, 0x5CD3, 0x8D5C, 0x5CD4, 0x8D5D, 0x5CD5, 0x8D5E, 0x5CD6, 0x8D5F, 0x5CD7, 0x8D60, 0x5CD8, 0x8D61, 0x5CDA, 0x8D62, 0x5CDB, 0x8D63, 0x5CDC, 0x8D64, 0x5CDD, 0x8D65, 0x5CDE, 0x8D66, 0x5CDF, 0x8D67, 0x5CE0, 0x8D68, 0x5CE2, 0x8D69, 0x5CE3, 0x8D6A, 0x5CE7, 0x8D6B, 0x5CE9, 0x8D6C, 0x5CEB, 0x8D6D, 0x5CEC, 0x8D6E, 0x5CEE, 0x8D6F, 0x5CEF, 0x8D70, 0x5CF1, 0x8D71, 0x5CF2, 0x8D72, 0x5CF3, 0x8D73, 0x5CF4, 0x8D74, 0x5CF5, 0x8D75, 0x5CF6, 0x8D76, 0x5CF7, 0x8D77, 0x5CF8, 0x8D78, 0x5CF9, 0x8D79, 0x5CFA, 0x8D7A, 0x5CFC, 0x8D7B, 0x5CFD, 0x8D7C, 0x5CFE, 0x8D7D, 0x5CFF, 0x8D7E, 0x5D00, 0x8D80, 0x5D01, 0x8D81, 0x5D04, 0x8D82, 0x5D05, 0x8D83, 0x5D08, 0x8D84, 0x5D09, 0x8D85, 0x5D0A, 0x8D86, 0x5D0B, 0x8D87, 0x5D0C, 0x8D88, 0x5D0D, 0x8D89, 0x5D0F, 0x8D8A, 0x5D10, 0x8D8B, 0x5D11, 0x8D8C, 0x5D12, 0x8D8D, 0x5D13, 0x8D8E, 0x5D15, 0x8D8F, 0x5D17, 0x8D90, 0x5D18, 0x8D91, 0x5D19, 0x8D92, 0x5D1A, 0x8D93, 0x5D1C, 0x8D94, 0x5D1D, 0x8D95, 0x5D1F, 0x8D96, 0x5D20, 0x8D97, 0x5D21, 0x8D98, 0x5D22, 0x8D99, 0x5D23, 0x8D9A, 0x5D25, 0x8D9B, 0x5D28, 0x8D9C, 0x5D2A, 0x8D9D, 0x5D2B, 0x8D9E, 0x5D2C, 0x8D9F, 0x5D2F, 0x8DA0, 0x5D30, 0x8DA1, 0x5D31, 0x8DA2, 0x5D32, 0x8DA3, 0x5D33, 0x8DA4, 0x5D35, 0x8DA5, 0x5D36, 0x8DA6, 0x5D37, 0x8DA7, 0x5D38, 0x8DA8, 0x5D39, 0x8DA9, 0x5D3A, 0x8DAA, 0x5D3B, 0x8DAB, 0x5D3C, 0x8DAC, 0x5D3F, 0x8DAD, 0x5D40, 0x8DAE, 0x5D41, 0x8DAF, 0x5D42, 0x8DB0, 0x5D43, 0x8DB1, 0x5D44, 0x8DB2, 0x5D45, 0x8DB3, 0x5D46, 0x8DB4, 0x5D48, 0x8DB5, 0x5D49, 0x8DB6, 0x5D4D, 0x8DB7, 0x5D4E, 0x8DB8, 0x5D4F, 0x8DB9, 0x5D50, 0x8DBA, 0x5D51, 0x8DBB, 0x5D52, 0x8DBC, 0x5D53, 0x8DBD, 0x5D54, 0x8DBE, 0x5D55, 0x8DBF, 0x5D56, 0x8DC0, 0x5D57, 0x8DC1, 0x5D59, 0x8DC2, 0x5D5A, 0x8DC3, 0x5D5C, 0x8DC4, 0x5D5E, 0x8DC5, 0x5D5F, 0x8DC6, 0x5D60, 0x8DC7, 0x5D61, 0x8DC8, 0x5D62, 0x8DC9, 0x5D63, 0x8DCA, 0x5D64, 0x8DCB, 0x5D65, 0x8DCC, 0x5D66, 0x8DCD, 0x5D67, 0x8DCE, 0x5D68, 0x8DCF, 0x5D6A, 0x8DD0, 0x5D6D, 0x8DD1, 0x5D6E, 0x8DD2, 0x5D70, 0x8DD3, 0x5D71, 0x8DD4, 0x5D72, 0x8DD5, 0x5D73, 0x8DD6, 0x5D75, 0x8DD7, 0x5D76, 0x8DD8, 0x5D77, 0x8DD9, 0x5D78, 0x8DDA, 0x5D79, 0x8DDB, 0x5D7A, 0x8DDC, 0x5D7B, 0x8DDD, 0x5D7C, 0x8DDE, 0x5D7D, 0x8DDF, 0x5D7E, 0x8DE0, 0x5D7F, 0x8DE1, 0x5D80, 0x8DE2, 0x5D81, 0x8DE3, 0x5D83, 0x8DE4, 0x5D84, 0x8DE5, 0x5D85, 0x8DE6, 0x5D86, 0x8DE7, 0x5D87, 0x8DE8, 0x5D88, 0x8DE9, 0x5D89, 0x8DEA, 0x5D8A, 0x8DEB, 0x5D8B, 0x8DEC, 0x5D8C, 0x8DED, 0x5D8D, 0x8DEE, 0x5D8E, 0x8DEF, 0x5D8F, 0x8DF0, 0x5D90, 0x8DF1, 0x5D91, 0x8DF2, 0x5D92, 0x8DF3, 0x5D93, 0x8DF4, 0x5D94, 0x8DF5, 0x5D95, 0x8DF6, 0x5D96, 0x8DF7, 0x5D97, 0x8DF8, 0x5D98, 0x8DF9, 0x5D9A, 0x8DFA, 0x5D9B, 0x8DFB, 0x5D9C, 0x8DFC, 0x5D9E, 0x8DFD, 0x5D9F, 0x8DFE, 0x5DA0, 0x8E40, 0x5DA1, 0x8E41, 0x5DA2, 0x8E42, 0x5DA3, 0x8E43, 0x5DA4, 0x8E44, 0x5DA5, 0x8E45, 0x5DA6, 0x8E46, 0x5DA7, 0x8E47, 0x5DA8, 0x8E48, 0x5DA9, 0x8E49, 0x5DAA, 0x8E4A, 0x5DAB, 0x8E4B, 0x5DAC, 0x8E4C, 0x5DAD, 0x8E4D, 0x5DAE, 0x8E4E, 0x5DAF, 0x8E4F, 0x5DB0, 0x8E50, 0x5DB1, 0x8E51, 0x5DB2, 0x8E52, 0x5DB3, 0x8E53, 0x5DB4, 0x8E54, 0x5DB5, 0x8E55, 0x5DB6, 0x8E56, 0x5DB8, 0x8E57, 0x5DB9, 0x8E58, 0x5DBA, 0x8E59, 0x5DBB, 0x8E5A, 0x5DBC, 0x8E5B, 0x5DBD, 0x8E5C, 0x5DBE, 0x8E5D, 0x5DBF, 0x8E5E, 0x5DC0, 0x8E5F, 0x5DC1, 0x8E60, 0x5DC2, 0x8E61, 0x5DC3, 0x8E62, 0x5DC4, 0x8E63, 0x5DC6, 0x8E64, 0x5DC7, 0x8E65, 0x5DC8, 0x8E66, 0x5DC9, 0x8E67, 0x5DCA, 0x8E68, 0x5DCB, 0x8E69, 0x5DCC, 0x8E6A, 0x5DCE, 0x8E6B, 0x5DCF, 0x8E6C, 0x5DD0, 0x8E6D, 0x5DD1, 0x8E6E, 0x5DD2, 0x8E6F, 0x5DD3, 0x8E70, 0x5DD4, 0x8E71, 0x5DD5, 0x8E72, 0x5DD6, 0x8E73, 0x5DD7, 0x8E74, 0x5DD8, 0x8E75, 0x5DD9, 0x8E76, 0x5DDA, 0x8E77, 0x5DDC, 0x8E78, 0x5DDF, 0x8E79, 0x5DE0, 0x8E7A, 0x5DE3, 0x8E7B, 0x5DE4, 0x8E7C, 0x5DEA, 0x8E7D, 0x5DEC, 0x8E7E, 0x5DED, 0x8E80, 0x5DF0, 0x8E81, 0x5DF5, 0x8E82, 0x5DF6, 0x8E83, 0x5DF8, 0x8E84, 0x5DF9, 0x8E85, 0x5DFA, 0x8E86, 0x5DFB, 0x8E87, 0x5DFC, 0x8E88, 0x5DFF, 0x8E89, 0x5E00, 0x8E8A, 0x5E04, 0x8E8B, 0x5E07, 0x8E8C, 0x5E09, 0x8E8D, 0x5E0A, 0x8E8E, 0x5E0B, 0x8E8F, 0x5E0D, 0x8E90, 0x5E0E, 0x8E91, 0x5E12, 0x8E92, 0x5E13, 0x8E93, 0x5E17, 0x8E94, 0x5E1E, 0x8E95, 0x5E1F, 0x8E96, 0x5E20, 0x8E97, 0x5E21, 0x8E98, 0x5E22, 0x8E99, 0x5E23, 0x8E9A, 0x5E24, 0x8E9B, 0x5E25, 0x8E9C, 0x5E28, 0x8E9D, 0x5E29, 0x8E9E, 0x5E2A, 0x8E9F, 0x5E2B, 0x8EA0, 0x5E2C, 0x8EA1, 0x5E2F, 0x8EA2, 0x5E30, 0x8EA3, 0x5E32, 0x8EA4, 0x5E33, 0x8EA5, 0x5E34, 0x8EA6, 0x5E35, 0x8EA7, 0x5E36, 0x8EA8, 0x5E39, 0x8EA9, 0x5E3A, 0x8EAA, 0x5E3E, 0x8EAB, 0x5E3F, 0x8EAC, 0x5E40, 0x8EAD, 0x5E41, 0x8EAE, 0x5E43, 0x8EAF, 0x5E46, 0x8EB0, 0x5E47, 0x8EB1, 0x5E48, 0x8EB2, 0x5E49, 0x8EB3, 0x5E4A, 0x8EB4, 0x5E4B, 0x8EB5, 0x5E4D, 0x8EB6, 0x5E4E, 0x8EB7, 0x5E4F, 0x8EB8, 0x5E50, 0x8EB9, 0x5E51, 0x8EBA, 0x5E52, 0x8EBB, 0x5E53, 0x8EBC, 0x5E56, 0x8EBD, 0x5E57, 0x8EBE, 0x5E58, 0x8EBF, 0x5E59, 0x8EC0, 0x5E5A, 0x8EC1, 0x5E5C, 0x8EC2, 0x5E5D, 0x8EC3, 0x5E5F, 0x8EC4, 0x5E60, 0x8EC5, 0x5E63, 0x8EC6, 0x5E64, 0x8EC7, 0x5E65, 0x8EC8, 0x5E66, 0x8EC9, 0x5E67, 0x8ECA, 0x5E68, 0x8ECB, 0x5E69, 0x8ECC, 0x5E6A, 0x8ECD, 0x5E6B, 0x8ECE, 0x5E6C, 0x8ECF, 0x5E6D, 0x8ED0, 0x5E6E, 0x8ED1, 0x5E6F, 0x8ED2, 0x5E70, 0x8ED3, 0x5E71, 0x8ED4, 0x5E75, 0x8ED5, 0x5E77, 0x8ED6, 0x5E79, 0x8ED7, 0x5E7E, 0x8ED8, 0x5E81, 0x8ED9, 0x5E82, 0x8EDA, 0x5E83, 0x8EDB, 0x5E85, 0x8EDC, 0x5E88, 0x8EDD, 0x5E89, 0x8EDE, 0x5E8C, 0x8EDF, 0x5E8D, 0x8EE0, 0x5E8E, 0x8EE1, 0x5E92, 0x8EE2, 0x5E98, 0x8EE3, 0x5E9B, 0x8EE4, 0x5E9D, 0x8EE5, 0x5EA1, 0x8EE6, 0x5EA2, 0x8EE7, 0x5EA3, 0x8EE8, 0x5EA4, 0x8EE9, 0x5EA8, 0x8EEA, 0x5EA9, 0x8EEB, 0x5EAA, 0x8EEC, 0x5EAB, 0x8EED, 0x5EAC, 0x8EEE, 0x5EAE, 0x8EEF, 0x5EAF, 0x8EF0, 0x5EB0, 0x8EF1, 0x5EB1, 0x8EF2, 0x5EB2, 0x8EF3, 0x5EB4, 0x8EF4, 0x5EBA, 0x8EF5, 0x5EBB, 0x8EF6, 0x5EBC, 0x8EF7, 0x5EBD, 0x8EF8, 0x5EBF, 0x8EF9, 0x5EC0, 0x8EFA, 0x5EC1, 0x8EFB, 0x5EC2, 0x8EFC, 0x5EC3, 0x8EFD, 0x5EC4, 0x8EFE, 0x5EC5, 0x8F40, 0x5EC6, 0x8F41, 0x5EC7, 0x8F42, 0x5EC8, 0x8F43, 0x5ECB, 0x8F44, 0x5ECC, 0x8F45, 0x5ECD, 0x8F46, 0x5ECE, 0x8F47, 0x5ECF, 0x8F48, 0x5ED0, 0x8F49, 0x5ED4, 0x8F4A, 0x5ED5, 0x8F4B, 0x5ED7, 0x8F4C, 0x5ED8, 0x8F4D, 0x5ED9, 0x8F4E, 0x5EDA, 0x8F4F, 0x5EDC, 0x8F50, 0x5EDD, 0x8F51, 0x5EDE, 0x8F52, 0x5EDF, 0x8F53, 0x5EE0, 0x8F54, 0x5EE1, 0x8F55, 0x5EE2, 0x8F56, 0x5EE3, 0x8F57, 0x5EE4, 0x8F58, 0x5EE5, 0x8F59, 0x5EE6, 0x8F5A, 0x5EE7, 0x8F5B, 0x5EE9, 0x8F5C, 0x5EEB, 0x8F5D, 0x5EEC, 0x8F5E, 0x5EED, 0x8F5F, 0x5EEE, 0x8F60, 0x5EEF, 0x8F61, 0x5EF0, 0x8F62, 0x5EF1, 0x8F63, 0x5EF2, 0x8F64, 0x5EF3, 0x8F65, 0x5EF5, 0x8F66, 0x5EF8, 0x8F67, 0x5EF9, 0x8F68, 0x5EFB, 0x8F69, 0x5EFC, 0x8F6A, 0x5EFD, 0x8F6B, 0x5F05, 0x8F6C, 0x5F06, 0x8F6D, 0x5F07, 0x8F6E, 0x5F09, 0x8F6F, 0x5F0C, 0x8F70, 0x5F0D, 0x8F71, 0x5F0E, 0x8F72, 0x5F10, 0x8F73, 0x5F12, 0x8F74, 0x5F14, 0x8F75, 0x5F16, 0x8F76, 0x5F19, 0x8F77, 0x5F1A, 0x8F78, 0x5F1C, 0x8F79, 0x5F1D, 0x8F7A, 0x5F1E, 0x8F7B, 0x5F21, 0x8F7C, 0x5F22, 0x8F7D, 0x5F23, 0x8F7E, 0x5F24, 0x8F80, 0x5F28, 0x8F81, 0x5F2B, 0x8F82, 0x5F2C, 0x8F83, 0x5F2E, 0x8F84, 0x5F30, 0x8F85, 0x5F32, 0x8F86, 0x5F33, 0x8F87, 0x5F34, 0x8F88, 0x5F35, 0x8F89, 0x5F36, 0x8F8A, 0x5F37, 0x8F8B, 0x5F38, 0x8F8C, 0x5F3B, 0x8F8D, 0x5F3D, 0x8F8E, 0x5F3E, 0x8F8F, 0x5F3F, 0x8F90, 0x5F41, 0x8F91, 0x5F42, 0x8F92, 0x5F43, 0x8F93, 0x5F44, 0x8F94, 0x5F45, 0x8F95, 0x5F46, 0x8F96, 0x5F47, 0x8F97, 0x5F48, 0x8F98, 0x5F49, 0x8F99, 0x5F4A, 0x8F9A, 0x5F4B, 0x8F9B, 0x5F4C, 0x8F9C, 0x5F4D, 0x8F9D, 0x5F4E, 0x8F9E, 0x5F4F, 0x8F9F, 0x5F51, 0x8FA0, 0x5F54, 0x8FA1, 0x5F59, 0x8FA2, 0x5F5A, 0x8FA3, 0x5F5B, 0x8FA4, 0x5F5C, 0x8FA5, 0x5F5E, 0x8FA6, 0x5F5F, 0x8FA7, 0x5F60, 0x8FA8, 0x5F63, 0x8FA9, 0x5F65, 0x8FAA, 0x5F67, 0x8FAB, 0x5F68, 0x8FAC, 0x5F6B, 0x8FAD, 0x5F6E, 0x8FAE, 0x5F6F, 0x8FAF, 0x5F72, 0x8FB0, 0x5F74, 0x8FB1, 0x5F75, 0x8FB2, 0x5F76, 0x8FB3, 0x5F78, 0x8FB4, 0x5F7A, 0x8FB5, 0x5F7D, 0x8FB6, 0x5F7E, 0x8FB7, 0x5F7F, 0x8FB8, 0x5F83, 0x8FB9, 0x5F86, 0x8FBA, 0x5F8D, 0x8FBB, 0x5F8E, 0x8FBC, 0x5F8F, 0x8FBD, 0x5F91, 0x8FBE, 0x5F93, 0x8FBF, 0x5F94, 0x8FC0, 0x5F96, 0x8FC1, 0x5F9A, 0x8FC2, 0x5F9B, 0x8FC3, 0x5F9D, 0x8FC4, 0x5F9E, 0x8FC5, 0x5F9F, 0x8FC6, 0x5FA0, 0x8FC7, 0x5FA2, 0x8FC8, 0x5FA3, 0x8FC9, 0x5FA4, 0x8FCA, 0x5FA5, 0x8FCB, 0x5FA6, 0x8FCC, 0x5FA7, 0x8FCD, 0x5FA9, 0x8FCE, 0x5FAB, 0x8FCF, 0x5FAC, 0x8FD0, 0x5FAF, 0x8FD1, 0x5FB0, 0x8FD2, 0x5FB1, 0x8FD3, 0x5FB2, 0x8FD4, 0x5FB3, 0x8FD5, 0x5FB4, 0x8FD6, 0x5FB6, 0x8FD7, 0x5FB8, 0x8FD8, 0x5FB9, 0x8FD9, 0x5FBA, 0x8FDA, 0x5FBB, 0x8FDB, 0x5FBE, 0x8FDC, 0x5FBF, 0x8FDD, 0x5FC0, 0x8FDE, 0x5FC1, 0x8FDF, 0x5FC2, 0x8FE0, 0x5FC7, 0x8FE1, 0x5FC8, 0x8FE2, 0x5FCA, 0x8FE3, 0x5FCB, 0x8FE4, 0x5FCE, 0x8FE5, 0x5FD3, 0x8FE6, 0x5FD4, 0x8FE7, 0x5FD5, 0x8FE8, 0x5FDA, 0x8FE9, 0x5FDB, 0x8FEA, 0x5FDC, 0x8FEB, 0x5FDE, 0x8FEC, 0x5FDF, 0x8FED, 0x5FE2, 0x8FEE, 0x5FE3, 0x8FEF, 0x5FE5, 0x8FF0, 0x5FE6, 0x8FF1, 0x5FE8, 0x8FF2, 0x5FE9, 0x8FF3, 0x5FEC, 0x8FF4, 0x5FEF, 0x8FF5, 0x5FF0, 0x8FF6, 0x5FF2, 0x8FF7, 0x5FF3, 0x8FF8, 0x5FF4, 0x8FF9, 0x5FF6, 0x8FFA, 0x5FF7, 0x8FFB, 0x5FF9, 0x8FFC, 0x5FFA, 0x8FFD, 0x5FFC, 0x8FFE, 0x6007, 0x9040, 0x6008, 0x9041, 0x6009, 0x9042, 0x600B, 0x9043, 0x600C, 0x9044, 0x6010, 0x9045, 0x6011, 0x9046, 0x6013, 0x9047, 0x6017, 0x9048, 0x6018, 0x9049, 0x601A, 0x904A, 0x601E, 0x904B, 0x601F, 0x904C, 0x6022, 0x904D, 0x6023, 0x904E, 0x6024, 0x904F, 0x602C, 0x9050, 0x602D, 0x9051, 0x602E, 0x9052, 0x6030, 0x9053, 0x6031, 0x9054, 0x6032, 0x9055, 0x6033, 0x9056, 0x6034, 0x9057, 0x6036, 0x9058, 0x6037, 0x9059, 0x6038, 0x905A, 0x6039, 0x905B, 0x603A, 0x905C, 0x603D, 0x905D, 0x603E, 0x905E, 0x6040, 0x905F, 0x6044, 0x9060, 0x6045, 0x9061, 0x6046, 0x9062, 0x6047, 0x9063, 0x6048, 0x9064, 0x6049, 0x9065, 0x604A, 0x9066, 0x604C, 0x9067, 0x604E, 0x9068, 0x604F, 0x9069, 0x6051, 0x906A, 0x6053, 0x906B, 0x6054, 0x906C, 0x6056, 0x906D, 0x6057, 0x906E, 0x6058, 0x906F, 0x605B, 0x9070, 0x605C, 0x9071, 0x605E, 0x9072, 0x605F, 0x9073, 0x6060, 0x9074, 0x6061, 0x9075, 0x6065, 0x9076, 0x6066, 0x9077, 0x606E, 0x9078, 0x6071, 0x9079, 0x6072, 0x907A, 0x6074, 0x907B, 0x6075, 0x907C, 0x6077, 0x907D, 0x607E, 0x907E, 0x6080, 0x9080, 0x6081, 0x9081, 0x6082, 0x9082, 0x6085, 0x9083, 0x6086, 0x9084, 0x6087, 0x9085, 0x6088, 0x9086, 0x608A, 0x9087, 0x608B, 0x9088, 0x608E, 0x9089, 0x608F, 0x908A, 0x6090, 0x908B, 0x6091, 0x908C, 0x6093, 0x908D, 0x6095, 0x908E, 0x6097, 0x908F, 0x6098, 0x9090, 0x6099, 0x9091, 0x609C, 0x9092, 0x609E, 0x9093, 0x60A1, 0x9094, 0x60A2, 0x9095, 0x60A4, 0x9096, 0x60A5, 0x9097, 0x60A7, 0x9098, 0x60A9, 0x9099, 0x60AA, 0x909A, 0x60AE, 0x909B, 0x60B0, 0x909C, 0x60B3, 0x909D, 0x60B5, 0x909E, 0x60B6, 0x909F, 0x60B7, 0x90A0, 0x60B9, 0x90A1, 0x60BA, 0x90A2, 0x60BD, 0x90A3, 0x60BE, 0x90A4, 0x60BF, 0x90A5, 0x60C0, 0x90A6, 0x60C1, 0x90A7, 0x60C2, 0x90A8, 0x60C3, 0x90A9, 0x60C4, 0x90AA, 0x60C7, 0x90AB, 0x60C8, 0x90AC, 0x60C9, 0x90AD, 0x60CC, 0x90AE, 0x60CD, 0x90AF, 0x60CE, 0x90B0, 0x60CF, 0x90B1, 0x60D0, 0x90B2, 0x60D2, 0x90B3, 0x60D3, 0x90B4, 0x60D4, 0x90B5, 0x60D6, 0x90B6, 0x60D7, 0x90B7, 0x60D9, 0x90B8, 0x60DB, 0x90B9, 0x60DE, 0x90BA, 0x60E1, 0x90BB, 0x60E2, 0x90BC, 0x60E3, 0x90BD, 0x60E4, 0x90BE, 0x60E5, 0x90BF, 0x60EA, 0x90C0, 0x60F1, 0x90C1, 0x60F2, 0x90C2, 0x60F5, 0x90C3, 0x60F7, 0x90C4, 0x60F8, 0x90C5, 0x60FB, 0x90C6, 0x60FC, 0x90C7, 0x60FD, 0x90C8, 0x60FE, 0x90C9, 0x60FF, 0x90CA, 0x6102, 0x90CB, 0x6103, 0x90CC, 0x6104, 0x90CD, 0x6105, 0x90CE, 0x6107, 0x90CF, 0x610A, 0x90D0, 0x610B, 0x90D1, 0x610C, 0x90D2, 0x6110, 0x90D3, 0x6111, 0x90D4, 0x6112, 0x90D5, 0x6113, 0x90D6, 0x6114, 0x90D7, 0x6116, 0x90D8, 0x6117, 0x90D9, 0x6118, 0x90DA, 0x6119, 0x90DB, 0x611B, 0x90DC, 0x611C, 0x90DD, 0x611D, 0x90DE, 0x611E, 0x90DF, 0x6121, 0x90E0, 0x6122, 0x90E1, 0x6125, 0x90E2, 0x6128, 0x90E3, 0x6129, 0x90E4, 0x612A, 0x90E5, 0x612C, 0x90E6, 0x612D, 0x90E7, 0x612E, 0x90E8, 0x612F, 0x90E9, 0x6130, 0x90EA, 0x6131, 0x90EB, 0x6132, 0x90EC, 0x6133, 0x90ED, 0x6134, 0x90EE, 0x6135, 0x90EF, 0x6136, 0x90F0, 0x6137, 0x90F1, 0x6138, 0x90F2, 0x6139, 0x90F3, 0x613A, 0x90F4, 0x613B, 0x90F5, 0x613C, 0x90F6, 0x613D, 0x90F7, 0x613E, 0x90F8, 0x6140, 0x90F9, 0x6141, 0x90FA, 0x6142, 0x90FB, 0x6143, 0x90FC, 0x6144, 0x90FD, 0x6145, 0x90FE, 0x6146, 0x9140, 0x6147, 0x9141, 0x6149, 0x9142, 0x614B, 0x9143, 0x614D, 0x9144, 0x614F, 0x9145, 0x6150, 0x9146, 0x6152, 0x9147, 0x6153, 0x9148, 0x6154, 0x9149, 0x6156, 0x914A, 0x6157, 0x914B, 0x6158, 0x914C, 0x6159, 0x914D, 0x615A, 0x914E, 0x615B, 0x914F, 0x615C, 0x9150, 0x615E, 0x9151, 0x615F, 0x9152, 0x6160, 0x9153, 0x6161, 0x9154, 0x6163, 0x9155, 0x6164, 0x9156, 0x6165, 0x9157, 0x6166, 0x9158, 0x6169, 0x9159, 0x616A, 0x915A, 0x616B, 0x915B, 0x616C, 0x915C, 0x616D, 0x915D, 0x616E, 0x915E, 0x616F, 0x915F, 0x6171, 0x9160, 0x6172, 0x9161, 0x6173, 0x9162, 0x6174, 0x9163, 0x6176, 0x9164, 0x6178, 0x9165, 0x6179, 0x9166, 0x617A, 0x9167, 0x617B, 0x9168, 0x617C, 0x9169, 0x617D, 0x916A, 0x617E, 0x916B, 0x617F, 0x916C, 0x6180, 0x916D, 0x6181, 0x916E, 0x6182, 0x916F, 0x6183, 0x9170, 0x6184, 0x9171, 0x6185, 0x9172, 0x6186, 0x9173, 0x6187, 0x9174, 0x6188, 0x9175, 0x6189, 0x9176, 0x618A, 0x9177, 0x618C, 0x9178, 0x618D, 0x9179, 0x618F, 0x917A, 0x6190, 0x917B, 0x6191, 0x917C, 0x6192, 0x917D, 0x6193, 0x917E, 0x6195, 0x9180, 0x6196, 0x9181, 0x6197, 0x9182, 0x6198, 0x9183, 0x6199, 0x9184, 0x619A, 0x9185, 0x619B, 0x9186, 0x619C, 0x9187, 0x619E, 0x9188, 0x619F, 0x9189, 0x61A0, 0x918A, 0x61A1, 0x918B, 0x61A2, 0x918C, 0x61A3, 0x918D, 0x61A4, 0x918E, 0x61A5, 0x918F, 0x61A6, 0x9190, 0x61AA, 0x9191, 0x61AB, 0x9192, 0x61AD, 0x9193, 0x61AE, 0x9194, 0x61AF, 0x9195, 0x61B0, 0x9196, 0x61B1, 0x9197, 0x61B2, 0x9198, 0x61B3, 0x9199, 0x61B4, 0x919A, 0x61B5, 0x919B, 0x61B6, 0x919C, 0x61B8, 0x919D, 0x61B9, 0x919E, 0x61BA, 0x919F, 0x61BB, 0x91A0, 0x61BC, 0x91A1, 0x61BD, 0x91A2, 0x61BF, 0x91A3, 0x61C0, 0x91A4, 0x61C1, 0x91A5, 0x61C3, 0x91A6, 0x61C4, 0x91A7, 0x61C5, 0x91A8, 0x61C6, 0x91A9, 0x61C7, 0x91AA, 0x61C9, 0x91AB, 0x61CC, 0x91AC, 0x61CD, 0x91AD, 0x61CE, 0x91AE, 0x61CF, 0x91AF, 0x61D0, 0x91B0, 0x61D3, 0x91B1, 0x61D5, 0x91B2, 0x61D6, 0x91B3, 0x61D7, 0x91B4, 0x61D8, 0x91B5, 0x61D9, 0x91B6, 0x61DA, 0x91B7, 0x61DB, 0x91B8, 0x61DC, 0x91B9, 0x61DD, 0x91BA, 0x61DE, 0x91BB, 0x61DF, 0x91BC, 0x61E0, 0x91BD, 0x61E1, 0x91BE, 0x61E2, 0x91BF, 0x61E3, 0x91C0, 0x61E4, 0x91C1, 0x61E5, 0x91C2, 0x61E7, 0x91C3, 0x61E8, 0x91C4, 0x61E9, 0x91C5, 0x61EA, 0x91C6, 0x61EB, 0x91C7, 0x61EC, 0x91C8, 0x61ED, 0x91C9, 0x61EE, 0x91CA, 0x61EF, 0x91CB, 0x61F0, 0x91CC, 0x61F1, 0x91CD, 0x61F2, 0x91CE, 0x61F3, 0x91CF, 0x61F4, 0x91D0, 0x61F6, 0x91D1, 0x61F7, 0x91D2, 0x61F8, 0x91D3, 0x61F9, 0x91D4, 0x61FA, 0x91D5, 0x61FB, 0x91D6, 0x61FC, 0x91D7, 0x61FD, 0x91D8, 0x61FE, 0x91D9, 0x6200, 0x91DA, 0x6201, 0x91DB, 0x6202, 0x91DC, 0x6203, 0x91DD, 0x6204, 0x91DE, 0x6205, 0x91DF, 0x6207, 0x91E0, 0x6209, 0x91E1, 0x6213, 0x91E2, 0x6214, 0x91E3, 0x6219, 0x91E4, 0x621C, 0x91E5, 0x621D, 0x91E6, 0x621E, 0x91E7, 0x6220, 0x91E8, 0x6223, 0x91E9, 0x6226, 0x91EA, 0x6227, 0x91EB, 0x6228, 0x91EC, 0x6229, 0x91ED, 0x622B, 0x91EE, 0x622D, 0x91EF, 0x622F, 0x91F0, 0x6230, 0x91F1, 0x6231, 0x91F2, 0x6232, 0x91F3, 0x6235, 0x91F4, 0x6236, 0x91F5, 0x6238, 0x91F6, 0x6239, 0x91F7, 0x623A, 0x91F8, 0x623B, 0x91F9, 0x623C, 0x91FA, 0x6242, 0x91FB, 0x6244, 0x91FC, 0x6245, 0x91FD, 0x6246, 0x91FE, 0x624A, 0x9240, 0x624F, 0x9241, 0x6250, 0x9242, 0x6255, 0x9243, 0x6256, 0x9244, 0x6257, 0x9245, 0x6259, 0x9246, 0x625A, 0x9247, 0x625C, 0x9248, 0x625D, 0x9249, 0x625E, 0x924A, 0x625F, 0x924B, 0x6260, 0x924C, 0x6261, 0x924D, 0x6262, 0x924E, 0x6264, 0x924F, 0x6265, 0x9250, 0x6268, 0x9251, 0x6271, 0x9252, 0x6272, 0x9253, 0x6274, 0x9254, 0x6275, 0x9255, 0x6277, 0x9256, 0x6278, 0x9257, 0x627A, 0x9258, 0x627B, 0x9259, 0x627D, 0x925A, 0x6281, 0x925B, 0x6282, 0x925C, 0x6283, 0x925D, 0x6285, 0x925E, 0x6286, 0x925F, 0x6287, 0x9260, 0x6288, 0x9261, 0x628B, 0x9262, 0x628C, 0x9263, 0x628D, 0x9264, 0x628E, 0x9265, 0x628F, 0x9266, 0x6290, 0x9267, 0x6294, 0x9268, 0x6299, 0x9269, 0x629C, 0x926A, 0x629D, 0x926B, 0x629E, 0x926C, 0x62A3, 0x926D, 0x62A6, 0x926E, 0x62A7, 0x926F, 0x62A9, 0x9270, 0x62AA, 0x9271, 0x62AD, 0x9272, 0x62AE, 0x9273, 0x62AF, 0x9274, 0x62B0, 0x9275, 0x62B2, 0x9276, 0x62B3, 0x9277, 0x62B4, 0x9278, 0x62B6, 0x9279, 0x62B7, 0x927A, 0x62B8, 0x927B, 0x62BA, 0x927C, 0x62BE, 0x927D, 0x62C0, 0x927E, 0x62C1, 0x9280, 0x62C3, 0x9281, 0x62CB, 0x9282, 0x62CF, 0x9283, 0x62D1, 0x9284, 0x62D5, 0x9285, 0x62DD, 0x9286, 0x62DE, 0x9287, 0x62E0, 0x9288, 0x62E1, 0x9289, 0x62E4, 0x928A, 0x62EA, 0x928B, 0x62EB, 0x928C, 0x62F0, 0x928D, 0x62F2, 0x928E, 0x62F5, 0x928F, 0x62F8, 0x9290, 0x62F9, 0x9291, 0x62FA, 0x9292, 0x62FB, 0x9293, 0x6300, 0x9294, 0x6303, 0x9295, 0x6304, 0x9296, 0x6305, 0x9297, 0x6306, 0x9298, 0x630A, 0x9299, 0x630B, 0x929A, 0x630C, 0x929B, 0x630D, 0x929C, 0x630F, 0x929D, 0x6310, 0x929E, 0x6312, 0x929F, 0x6313, 0x92A0, 0x6314, 0x92A1, 0x6315, 0x92A2, 0x6317, 0x92A3, 0x6318, 0x92A4, 0x6319, 0x92A5, 0x631C, 0x92A6, 0x6326, 0x92A7, 0x6327, 0x92A8, 0x6329, 0x92A9, 0x632C, 0x92AA, 0x632D, 0x92AB, 0x632E, 0x92AC, 0x6330, 0x92AD, 0x6331, 0x92AE, 0x6333, 0x92AF, 0x6334, 0x92B0, 0x6335, 0x92B1, 0x6336, 0x92B2, 0x6337, 0x92B3, 0x6338, 0x92B4, 0x633B, 0x92B5, 0x633C, 0x92B6, 0x633E, 0x92B7, 0x633F, 0x92B8, 0x6340, 0x92B9, 0x6341, 0x92BA, 0x6344, 0x92BB, 0x6347, 0x92BC, 0x6348, 0x92BD, 0x634A, 0x92BE, 0x6351, 0x92BF, 0x6352, 0x92C0, 0x6353, 0x92C1, 0x6354, 0x92C2, 0x6356, 0x92C3, 0x6357, 0x92C4, 0x6358, 0x92C5, 0x6359, 0x92C6, 0x635A, 0x92C7, 0x635B, 0x92C8, 0x635C, 0x92C9, 0x635D, 0x92CA, 0x6360, 0x92CB, 0x6364, 0x92CC, 0x6365, 0x92CD, 0x6366, 0x92CE, 0x6368, 0x92CF, 0x636A, 0x92D0, 0x636B, 0x92D1, 0x636C, 0x92D2, 0x636F, 0x92D3, 0x6370, 0x92D4, 0x6372, 0x92D5, 0x6373, 0x92D6, 0x6374, 0x92D7, 0x6375, 0x92D8, 0x6378, 0x92D9, 0x6379, 0x92DA, 0x637C, 0x92DB, 0x637D, 0x92DC, 0x637E, 0x92DD, 0x637F, 0x92DE, 0x6381, 0x92DF, 0x6383, 0x92E0, 0x6384, 0x92E1, 0x6385, 0x92E2, 0x6386, 0x92E3, 0x638B, 0x92E4, 0x638D, 0x92E5, 0x6391, 0x92E6, 0x6393, 0x92E7, 0x6394, 0x92E8, 0x6395, 0x92E9, 0x6397, 0x92EA, 0x6399, 0x92EB, 0x639A, 0x92EC, 0x639B, 0x92ED, 0x639C, 0x92EE, 0x639D, 0x92EF, 0x639E, 0x92F0, 0x639F, 0x92F1, 0x63A1, 0x92F2, 0x63A4, 0x92F3, 0x63A6, 0x92F4, 0x63AB, 0x92F5, 0x63AF, 0x92F6, 0x63B1, 0x92F7, 0x63B2, 0x92F8, 0x63B5, 0x92F9, 0x63B6, 0x92FA, 0x63B9, 0x92FB, 0x63BB, 0x92FC, 0x63BD, 0x92FD, 0x63BF, 0x92FE, 0x63C0, 0x9340, 0x63C1, 0x9341, 0x63C2, 0x9342, 0x63C3, 0x9343, 0x63C5, 0x9344, 0x63C7, 0x9345, 0x63C8, 0x9346, 0x63CA, 0x9347, 0x63CB, 0x9348, 0x63CC, 0x9349, 0x63D1, 0x934A, 0x63D3, 0x934B, 0x63D4, 0x934C, 0x63D5, 0x934D, 0x63D7, 0x934E, 0x63D8, 0x934F, 0x63D9, 0x9350, 0x63DA, 0x9351, 0x63DB, 0x9352, 0x63DC, 0x9353, 0x63DD, 0x9354, 0x63DF, 0x9355, 0x63E2, 0x9356, 0x63E4, 0x9357, 0x63E5, 0x9358, 0x63E6, 0x9359, 0x63E7, 0x935A, 0x63E8, 0x935B, 0x63EB, 0x935C, 0x63EC, 0x935D, 0x63EE, 0x935E, 0x63EF, 0x935F, 0x63F0, 0x9360, 0x63F1, 0x9361, 0x63F3, 0x9362, 0x63F5, 0x9363, 0x63F7, 0x9364, 0x63F9, 0x9365, 0x63FA, 0x9366, 0x63FB, 0x9367, 0x63FC, 0x9368, 0x63FE, 0x9369, 0x6403, 0x936A, 0x6404, 0x936B, 0x6406, 0x936C, 0x6407, 0x936D, 0x6408, 0x936E, 0x6409, 0x936F, 0x640A, 0x9370, 0x640D, 0x9371, 0x640E, 0x9372, 0x6411, 0x9373, 0x6412, 0x9374, 0x6415, 0x9375, 0x6416, 0x9376, 0x6417, 0x9377, 0x6418, 0x9378, 0x6419, 0x9379, 0x641A, 0x937A, 0x641D, 0x937B, 0x641F, 0x937C, 0x6422, 0x937D, 0x6423, 0x937E, 0x6424, 0x9380, 0x6425, 0x9381, 0x6427, 0x9382, 0x6428, 0x9383, 0x6429, 0x9384, 0x642B, 0x9385, 0x642E, 0x9386, 0x642F, 0x9387, 0x6430, 0x9388, 0x6431, 0x9389, 0x6432, 0x938A, 0x6433, 0x938B, 0x6435, 0x938C, 0x6436, 0x938D, 0x6437, 0x938E, 0x6438, 0x938F, 0x6439, 0x9390, 0x643B, 0x9391, 0x643C, 0x9392, 0x643E, 0x9393, 0x6440, 0x9394, 0x6442, 0x9395, 0x6443, 0x9396, 0x6449, 0x9397, 0x644B, 0x9398, 0x644C, 0x9399, 0x644D, 0x939A, 0x644E, 0x939B, 0x644F, 0x939C, 0x6450, 0x939D, 0x6451, 0x939E, 0x6453, 0x939F, 0x6455, 0x93A0, 0x6456, 0x93A1, 0x6457, 0x93A2, 0x6459, 0x93A3, 0x645A, 0x93A4, 0x645B, 0x93A5, 0x645C, 0x93A6, 0x645D, 0x93A7, 0x645F, 0x93A8, 0x6460, 0x93A9, 0x6461, 0x93AA, 0x6462, 0x93AB, 0x6463, 0x93AC, 0x6464, 0x93AD, 0x6465, 0x93AE, 0x6466, 0x93AF, 0x6468, 0x93B0, 0x646A, 0x93B1, 0x646B, 0x93B2, 0x646C, 0x93B3, 0x646E, 0x93B4, 0x646F, 0x93B5, 0x6470, 0x93B6, 0x6471, 0x93B7, 0x6472, 0x93B8, 0x6473, 0x93B9, 0x6474, 0x93BA, 0x6475, 0x93BB, 0x6476, 0x93BC, 0x6477, 0x93BD, 0x647B, 0x93BE, 0x647C, 0x93BF, 0x647D, 0x93C0, 0x647E, 0x93C1, 0x647F, 0x93C2, 0x6480, 0x93C3, 0x6481, 0x93C4, 0x6483, 0x93C5, 0x6486, 0x93C6, 0x6488, 0x93C7, 0x6489, 0x93C8, 0x648A, 0x93C9, 0x648B, 0x93CA, 0x648C, 0x93CB, 0x648D, 0x93CC, 0x648E, 0x93CD, 0x648F, 0x93CE, 0x6490, 0x93CF, 0x6493, 0x93D0, 0x6494, 0x93D1, 0x6497, 0x93D2, 0x6498, 0x93D3, 0x649A, 0x93D4, 0x649B, 0x93D5, 0x649C, 0x93D6, 0x649D, 0x93D7, 0x649F, 0x93D8, 0x64A0, 0x93D9, 0x64A1, 0x93DA, 0x64A2, 0x93DB, 0x64A3, 0x93DC, 0x64A5, 0x93DD, 0x64A6, 0x93DE, 0x64A7, 0x93DF, 0x64A8, 0x93E0, 0x64AA, 0x93E1, 0x64AB, 0x93E2, 0x64AF, 0x93E3, 0x64B1, 0x93E4, 0x64B2, 0x93E5, 0x64B3, 0x93E6, 0x64B4, 0x93E7, 0x64B6, 0x93E8, 0x64B9, 0x93E9, 0x64BB, 0x93EA, 0x64BD, 0x93EB, 0x64BE, 0x93EC, 0x64BF, 0x93ED, 0x64C1, 0x93EE, 0x64C3, 0x93EF, 0x64C4, 0x93F0, 0x64C6, 0x93F1, 0x64C7, 0x93F2, 0x64C8, 0x93F3, 0x64C9, 0x93F4, 0x64CA, 0x93F5, 0x64CB, 0x93F6, 0x64CC, 0x93F7, 0x64CF, 0x93F8, 0x64D1, 0x93F9, 0x64D3, 0x93FA, 0x64D4, 0x93FB, 0x64D5, 0x93FC, 0x64D6, 0x93FD, 0x64D9, 0x93FE, 0x64DA, 0x9440, 0x64DB, 0x9441, 0x64DC, 0x9442, 0x64DD, 0x9443, 0x64DF, 0x9444, 0x64E0, 0x9445, 0x64E1, 0x9446, 0x64E3, 0x9447, 0x64E5, 0x9448, 0x64E7, 0x9449, 0x64E8, 0x944A, 0x64E9, 0x944B, 0x64EA, 0x944C, 0x64EB, 0x944D, 0x64EC, 0x944E, 0x64ED, 0x944F, 0x64EE, 0x9450, 0x64EF, 0x9451, 0x64F0, 0x9452, 0x64F1, 0x9453, 0x64F2, 0x9454, 0x64F3, 0x9455, 0x64F4, 0x9456, 0x64F5, 0x9457, 0x64F6, 0x9458, 0x64F7, 0x9459, 0x64F8, 0x945A, 0x64F9, 0x945B, 0x64FA, 0x945C, 0x64FB, 0x945D, 0x64FC, 0x945E, 0x64FD, 0x945F, 0x64FE, 0x9460, 0x64FF, 0x9461, 0x6501, 0x9462, 0x6502, 0x9463, 0x6503, 0x9464, 0x6504, 0x9465, 0x6505, 0x9466, 0x6506, 0x9467, 0x6507, 0x9468, 0x6508, 0x9469, 0x650A, 0x946A, 0x650B, 0x946B, 0x650C, 0x946C, 0x650D, 0x946D, 0x650E, 0x946E, 0x650F, 0x946F, 0x6510, 0x9470, 0x6511, 0x9471, 0x6513, 0x9472, 0x6514, 0x9473, 0x6515, 0x9474, 0x6516, 0x9475, 0x6517, 0x9476, 0x6519, 0x9477, 0x651A, 0x9478, 0x651B, 0x9479, 0x651C, 0x947A, 0x651D, 0x947B, 0x651E, 0x947C, 0x651F, 0x947D, 0x6520, 0x947E, 0x6521, 0x9480, 0x6522, 0x9481, 0x6523, 0x9482, 0x6524, 0x9483, 0x6526, 0x9484, 0x6527, 0x9485, 0x6528, 0x9486, 0x6529, 0x9487, 0x652A, 0x9488, 0x652C, 0x9489, 0x652D, 0x948A, 0x6530, 0x948B, 0x6531, 0x948C, 0x6532, 0x948D, 0x6533, 0x948E, 0x6537, 0x948F, 0x653A, 0x9490, 0x653C, 0x9491, 0x653D, 0x9492, 0x6540, 0x9493, 0x6541, 0x9494, 0x6542, 0x9495, 0x6543, 0x9496, 0x6544, 0x9497, 0x6546, 0x9498, 0x6547, 0x9499, 0x654A, 0x949A, 0x654B, 0x949B, 0x654D, 0x949C, 0x654E, 0x949D, 0x6550, 0x949E, 0x6552, 0x949F, 0x6553, 0x94A0, 0x6554, 0x94A1, 0x6557, 0x94A2, 0x6558, 0x94A3, 0x655A, 0x94A4, 0x655C, 0x94A5, 0x655F, 0x94A6, 0x6560, 0x94A7, 0x6561, 0x94A8, 0x6564, 0x94A9, 0x6565, 0x94AA, 0x6567, 0x94AB, 0x6568, 0x94AC, 0x6569, 0x94AD, 0x656A, 0x94AE, 0x656D, 0x94AF, 0x656E, 0x94B0, 0x656F, 0x94B1, 0x6571, 0x94B2, 0x6573, 0x94B3, 0x6575, 0x94B4, 0x6576, 0x94B5, 0x6578, 0x94B6, 0x6579, 0x94B7, 0x657A, 0x94B8, 0x657B, 0x94B9, 0x657C, 0x94BA, 0x657D, 0x94BB, 0x657E, 0x94BC, 0x657F, 0x94BD, 0x6580, 0x94BE, 0x6581, 0x94BF, 0x6582, 0x94C0, 0x6583, 0x94C1, 0x6584, 0x94C2, 0x6585, 0x94C3, 0x6586, 0x94C4, 0x6588, 0x94C5, 0x6589, 0x94C6, 0x658A, 0x94C7, 0x658D, 0x94C8, 0x658E, 0x94C9, 0x658F, 0x94CA, 0x6592, 0x94CB, 0x6594, 0x94CC, 0x6595, 0x94CD, 0x6596, 0x94CE, 0x6598, 0x94CF, 0x659A, 0x94D0, 0x659D, 0x94D1, 0x659E, 0x94D2, 0x65A0, 0x94D3, 0x65A2, 0x94D4, 0x65A3, 0x94D5, 0x65A6, 0x94D6, 0x65A8, 0x94D7, 0x65AA, 0x94D8, 0x65AC, 0x94D9, 0x65AE, 0x94DA, 0x65B1, 0x94DB, 0x65B2, 0x94DC, 0x65B3, 0x94DD, 0x65B4, 0x94DE, 0x65B5, 0x94DF, 0x65B6, 0x94E0, 0x65B7, 0x94E1, 0x65B8, 0x94E2, 0x65BA, 0x94E3, 0x65BB, 0x94E4, 0x65BE, 0x94E5, 0x65BF, 0x94E6, 0x65C0, 0x94E7, 0x65C2, 0x94E8, 0x65C7, 0x94E9, 0x65C8, 0x94EA, 0x65C9, 0x94EB, 0x65CA, 0x94EC, 0x65CD, 0x94ED, 0x65D0, 0x94EE, 0x65D1, 0x94EF, 0x65D3, 0x94F0, 0x65D4, 0x94F1, 0x65D5, 0x94F2, 0x65D8, 0x94F3, 0x65D9, 0x94F4, 0x65DA, 0x94F5, 0x65DB, 0x94F6, 0x65DC, 0x94F7, 0x65DD, 0x94F8, 0x65DE, 0x94F9, 0x65DF, 0x94FA, 0x65E1, 0x94FB, 0x65E3, 0x94FC, 0x65E4, 0x94FD, 0x65EA, 0x94FE, 0x65EB, 0x9540, 0x65F2, 0x9541, 0x65F3, 0x9542, 0x65F4, 0x9543, 0x65F5, 0x9544, 0x65F8, 0x9545, 0x65F9, 0x9546, 0x65FB, 0x9547, 0x65FC, 0x9548, 0x65FD, 0x9549, 0x65FE, 0x954A, 0x65FF, 0x954B, 0x6601, 0x954C, 0x6604, 0x954D, 0x6605, 0x954E, 0x6607, 0x954F, 0x6608, 0x9550, 0x6609, 0x9551, 0x660B, 0x9552, 0x660D, 0x9553, 0x6610, 0x9554, 0x6611, 0x9555, 0x6612, 0x9556, 0x6616, 0x9557, 0x6617, 0x9558, 0x6618, 0x9559, 0x661A, 0x955A, 0x661B, 0x955B, 0x661C, 0x955C, 0x661E, 0x955D, 0x6621, 0x955E, 0x6622, 0x955F, 0x6623, 0x9560, 0x6624, 0x9561, 0x6626, 0x9562, 0x6629, 0x9563, 0x662A, 0x9564, 0x662B, 0x9565, 0x662C, 0x9566, 0x662E, 0x9567, 0x6630, 0x9568, 0x6632, 0x9569, 0x6633, 0x956A, 0x6637, 0x956B, 0x6638, 0x956C, 0x6639, 0x956D, 0x663A, 0x956E, 0x663B, 0x956F, 0x663D, 0x9570, 0x663F, 0x9571, 0x6640, 0x9572, 0x6642, 0x9573, 0x6644, 0x9574, 0x6645, 0x9575, 0x6646, 0x9576, 0x6647, 0x9577, 0x6648, 0x9578, 0x6649, 0x9579, 0x664A, 0x957A, 0x664D, 0x957B, 0x664E, 0x957C, 0x6650, 0x957D, 0x6651, 0x957E, 0x6658, 0x9580, 0x6659, 0x9581, 0x665B, 0x9582, 0x665C, 0x9583, 0x665D, 0x9584, 0x665E, 0x9585, 0x6660, 0x9586, 0x6662, 0x9587, 0x6663, 0x9588, 0x6665, 0x9589, 0x6667, 0x958A, 0x6669, 0x958B, 0x666A, 0x958C, 0x666B, 0x958D, 0x666C, 0x958E, 0x666D, 0x958F, 0x6671, 0x9590, 0x6672, 0x9591, 0x6673, 0x9592, 0x6675, 0x9593, 0x6678, 0x9594, 0x6679, 0x9595, 0x667B, 0x9596, 0x667C, 0x9597, 0x667D, 0x9598, 0x667F, 0x9599, 0x6680, 0x959A, 0x6681, 0x959B, 0x6683, 0x959C, 0x6685, 0x959D, 0x6686, 0x959E, 0x6688, 0x959F, 0x6689, 0x95A0, 0x668A, 0x95A1, 0x668B, 0x95A2, 0x668D, 0x95A3, 0x668E, 0x95A4, 0x668F, 0x95A5, 0x6690, 0x95A6, 0x6692, 0x95A7, 0x6693, 0x95A8, 0x6694, 0x95A9, 0x6695, 0x95AA, 0x6698, 0x95AB, 0x6699, 0x95AC, 0x669A, 0x95AD, 0x669B, 0x95AE, 0x669C, 0x95AF, 0x669E, 0x95B0, 0x669F, 0x95B1, 0x66A0, 0x95B2, 0x66A1, 0x95B3, 0x66A2, 0x95B4, 0x66A3, 0x95B5, 0x66A4, 0x95B6, 0x66A5, 0x95B7, 0x66A6, 0x95B8, 0x66A9, 0x95B9, 0x66AA, 0x95BA, 0x66AB, 0x95BB, 0x66AC, 0x95BC, 0x66AD, 0x95BD, 0x66AF, 0x95BE, 0x66B0, 0x95BF, 0x66B1, 0x95C0, 0x66B2, 0x95C1, 0x66B3, 0x95C2, 0x66B5, 0x95C3, 0x66B6, 0x95C4, 0x66B7, 0x95C5, 0x66B8, 0x95C6, 0x66BA, 0x95C7, 0x66BB, 0x95C8, 0x66BC, 0x95C9, 0x66BD, 0x95CA, 0x66BF, 0x95CB, 0x66C0, 0x95CC, 0x66C1, 0x95CD, 0x66C2, 0x95CE, 0x66C3, 0x95CF, 0x66C4, 0x95D0, 0x66C5, 0x95D1, 0x66C6, 0x95D2, 0x66C7, 0x95D3, 0x66C8, 0x95D4, 0x66C9, 0x95D5, 0x66CA, 0x95D6, 0x66CB, 0x95D7, 0x66CC, 0x95D8, 0x66CD, 0x95D9, 0x66CE, 0x95DA, 0x66CF, 0x95DB, 0x66D0, 0x95DC, 0x66D1, 0x95DD, 0x66D2, 0x95DE, 0x66D3, 0x95DF, 0x66D4, 0x95E0, 0x66D5, 0x95E1, 0x66D6, 0x95E2, 0x66D7, 0x95E3, 0x66D8, 0x95E4, 0x66DA, 0x95E5, 0x66DE, 0x95E6, 0x66DF, 0x95E7, 0x66E0, 0x95E8, 0x66E1, 0x95E9, 0x66E2, 0x95EA, 0x66E3, 0x95EB, 0x66E4, 0x95EC, 0x66E5, 0x95ED, 0x66E7, 0x95EE, 0x66E8, 0x95EF, 0x66EA, 0x95F0, 0x66EB, 0x95F1, 0x66EC, 0x95F2, 0x66ED, 0x95F3, 0x66EE, 0x95F4, 0x66EF, 0x95F5, 0x66F1, 0x95F6, 0x66F5, 0x95F7, 0x66F6, 0x95F8, 0x66F8, 0x95F9, 0x66FA, 0x95FA, 0x66FB, 0x95FB, 0x66FD, 0x95FC, 0x6701, 0x95FD, 0x6702, 0x95FE, 0x6703, 0x9640, 0x6704, 0x9641, 0x6705, 0x9642, 0x6706, 0x9643, 0x6707, 0x9644, 0x670C, 0x9645, 0x670E, 0x9646, 0x670F, 0x9647, 0x6711, 0x9648, 0x6712, 0x9649, 0x6713, 0x964A, 0x6716, 0x964B, 0x6718, 0x964C, 0x6719, 0x964D, 0x671A, 0x964E, 0x671C, 0x964F, 0x671E, 0x9650, 0x6720, 0x9651, 0x6721, 0x9652, 0x6722, 0x9653, 0x6723, 0x9654, 0x6724, 0x9655, 0x6725, 0x9656, 0x6727, 0x9657, 0x6729, 0x9658, 0x672E, 0x9659, 0x6730, 0x965A, 0x6732, 0x965B, 0x6733, 0x965C, 0x6736, 0x965D, 0x6737, 0x965E, 0x6738, 0x965F, 0x6739, 0x9660, 0x673B, 0x9661, 0x673C, 0x9662, 0x673E, 0x9663, 0x673F, 0x9664, 0x6741, 0x9665, 0x6744, 0x9666, 0x6745, 0x9667, 0x6747, 0x9668, 0x674A, 0x9669, 0x674B, 0x966A, 0x674D, 0x966B, 0x6752, 0x966C, 0x6754, 0x966D, 0x6755, 0x966E, 0x6757, 0x966F, 0x6758, 0x9670, 0x6759, 0x9671, 0x675A, 0x9672, 0x675B, 0x9673, 0x675D, 0x9674, 0x6762, 0x9675, 0x6763, 0x9676, 0x6764, 0x9677, 0x6766, 0x9678, 0x6767, 0x9679, 0x676B, 0x967A, 0x676C, 0x967B, 0x676E, 0x967C, 0x6771, 0x967D, 0x6774, 0x967E, 0x6776, 0x9680, 0x6778, 0x9681, 0x6779, 0x9682, 0x677A, 0x9683, 0x677B, 0x9684, 0x677D, 0x9685, 0x6780, 0x9686, 0x6782, 0x9687, 0x6783, 0x9688, 0x6785, 0x9689, 0x6786, 0x968A, 0x6788, 0x968B, 0x678A, 0x968C, 0x678C, 0x968D, 0x678D, 0x968E, 0x678E, 0x968F, 0x678F, 0x9690, 0x6791, 0x9691, 0x6792, 0x9692, 0x6793, 0x9693, 0x6794, 0x9694, 0x6796, 0x9695, 0x6799, 0x9696, 0x679B, 0x9697, 0x679F, 0x9698, 0x67A0, 0x9699, 0x67A1, 0x969A, 0x67A4, 0x969B, 0x67A6, 0x969C, 0x67A9, 0x969D, 0x67AC, 0x969E, 0x67AE, 0x969F, 0x67B1, 0x96A0, 0x67B2, 0x96A1, 0x67B4, 0x96A2, 0x67B9, 0x96A3, 0x67BA, 0x96A4, 0x67BB, 0x96A5, 0x67BC, 0x96A6, 0x67BD, 0x96A7, 0x67BE, 0x96A8, 0x67BF, 0x96A9, 0x67C0, 0x96AA, 0x67C2, 0x96AB, 0x67C5, 0x96AC, 0x67C6, 0x96AD, 0x67C7, 0x96AE, 0x67C8, 0x96AF, 0x67C9, 0x96B0, 0x67CA, 0x96B1, 0x67CB, 0x96B2, 0x67CC, 0x96B3, 0x67CD, 0x96B4, 0x67CE, 0x96B5, 0x67D5, 0x96B6, 0x67D6, 0x96B7, 0x67D7, 0x96B8, 0x67DB, 0x96B9, 0x67DF, 0x96BA, 0x67E1, 0x96BB, 0x67E3, 0x96BC, 0x67E4, 0x96BD, 0x67E6, 0x96BE, 0x67E7, 0x96BF, 0x67E8, 0x96C0, 0x67EA, 0x96C1, 0x67EB, 0x96C2, 0x67ED, 0x96C3, 0x67EE, 0x96C4, 0x67F2, 0x96C5, 0x67F5, 0x96C6, 0x67F6, 0x96C7, 0x67F7, 0x96C8, 0x67F8, 0x96C9, 0x67F9, 0x96CA, 0x67FA, 0x96CB, 0x67FB, 0x96CC, 0x67FC, 0x96CD, 0x67FE, 0x96CE, 0x6801, 0x96CF, 0x6802, 0x96D0, 0x6803, 0x96D1, 0x6804, 0x96D2, 0x6806, 0x96D3, 0x680D, 0x96D4, 0x6810, 0x96D5, 0x6812, 0x96D6, 0x6814, 0x96D7, 0x6815, 0x96D8, 0x6818, 0x96D9, 0x6819, 0x96DA, 0x681A, 0x96DB, 0x681B, 0x96DC, 0x681C, 0x96DD, 0x681E, 0x96DE, 0x681F, 0x96DF, 0x6820, 0x96E0, 0x6822, 0x96E1, 0x6823, 0x96E2, 0x6824, 0x96E3, 0x6825, 0x96E4, 0x6826, 0x96E5, 0x6827, 0x96E6, 0x6828, 0x96E7, 0x682B, 0x96E8, 0x682C, 0x96E9, 0x682D, 0x96EA, 0x682E, 0x96EB, 0x682F, 0x96EC, 0x6830, 0x96ED, 0x6831, 0x96EE, 0x6834, 0x96EF, 0x6835, 0x96F0, 0x6836, 0x96F1, 0x683A, 0x96F2, 0x683B, 0x96F3, 0x683F, 0x96F4, 0x6847, 0x96F5, 0x684B, 0x96F6, 0x684D, 0x96F7, 0x684F, 0x96F8, 0x6852, 0x96F9, 0x6856, 0x96FA, 0x6857, 0x96FB, 0x6858, 0x96FC, 0x6859, 0x96FD, 0x685A, 0x96FE, 0x685B, 0x9740, 0x685C, 0x9741, 0x685D, 0x9742, 0x685E, 0x9743, 0x685F, 0x9744, 0x686A, 0x9745, 0x686C, 0x9746, 0x686D, 0x9747, 0x686E, 0x9748, 0x686F, 0x9749, 0x6870, 0x974A, 0x6871, 0x974B, 0x6872, 0x974C, 0x6873, 0x974D, 0x6875, 0x974E, 0x6878, 0x974F, 0x6879, 0x9750, 0x687A, 0x9751, 0x687B, 0x9752, 0x687C, 0x9753, 0x687D, 0x9754, 0x687E, 0x9755, 0x687F, 0x9756, 0x6880, 0x9757, 0x6882, 0x9758, 0x6884, 0x9759, 0x6887, 0x975A, 0x6888, 0x975B, 0x6889, 0x975C, 0x688A, 0x975D, 0x688B, 0x975E, 0x688C, 0x975F, 0x688D, 0x9760, 0x688E, 0x9761, 0x6890, 0x9762, 0x6891, 0x9763, 0x6892, 0x9764, 0x6894, 0x9765, 0x6895, 0x9766, 0x6896, 0x9767, 0x6898, 0x9768, 0x6899, 0x9769, 0x689A, 0x976A, 0x689B, 0x976B, 0x689C, 0x976C, 0x689D, 0x976D, 0x689E, 0x976E, 0x689F, 0x976F, 0x68A0, 0x9770, 0x68A1, 0x9771, 0x68A3, 0x9772, 0x68A4, 0x9773, 0x68A5, 0x9774, 0x68A9, 0x9775, 0x68AA, 0x9776, 0x68AB, 0x9777, 0x68AC, 0x9778, 0x68AE, 0x9779, 0x68B1, 0x977A, 0x68B2, 0x977B, 0x68B4, 0x977C, 0x68B6, 0x977D, 0x68B7, 0x977E, 0x68B8, 0x9780, 0x68B9, 0x9781, 0x68BA, 0x9782, 0x68BB, 0x9783, 0x68BC, 0x9784, 0x68BD, 0x9785, 0x68BE, 0x9786, 0x68BF, 0x9787, 0x68C1, 0x9788, 0x68C3, 0x9789, 0x68C4, 0x978A, 0x68C5, 0x978B, 0x68C6, 0x978C, 0x68C7, 0x978D, 0x68C8, 0x978E, 0x68CA, 0x978F, 0x68CC, 0x9790, 0x68CE, 0x9791, 0x68CF, 0x9792, 0x68D0, 0x9793, 0x68D1, 0x9794, 0x68D3, 0x9795, 0x68D4, 0x9796, 0x68D6, 0x9797, 0x68D7, 0x9798, 0x68D9, 0x9799, 0x68DB, 0x979A, 0x68DC, 0x979B, 0x68DD, 0x979C, 0x68DE, 0x979D, 0x68DF, 0x979E, 0x68E1, 0x979F, 0x68E2, 0x97A0, 0x68E4, 0x97A1, 0x68E5, 0x97A2, 0x68E6, 0x97A3, 0x68E7, 0x97A4, 0x68E8, 0x97A5, 0x68E9, 0x97A6, 0x68EA, 0x97A7, 0x68EB, 0x97A8, 0x68EC, 0x97A9, 0x68ED, 0x97AA, 0x68EF, 0x97AB, 0x68F2, 0x97AC, 0x68F3, 0x97AD, 0x68F4, 0x97AE, 0x68F6, 0x97AF, 0x68F7, 0x97B0, 0x68F8, 0x97B1, 0x68FB, 0x97B2, 0x68FD, 0x97B3, 0x68FE, 0x97B4, 0x68FF, 0x97B5, 0x6900, 0x97B6, 0x6902, 0x97B7, 0x6903, 0x97B8, 0x6904, 0x97B9, 0x6906, 0x97BA, 0x6907, 0x97BB, 0x6908, 0x97BC, 0x6909, 0x97BD, 0x690A, 0x97BE, 0x690C, 0x97BF, 0x690F, 0x97C0, 0x6911, 0x97C1, 0x6913, 0x97C2, 0x6914, 0x97C3, 0x6915, 0x97C4, 0x6916, 0x97C5, 0x6917, 0x97C6, 0x6918, 0x97C7, 0x6919, 0x97C8, 0x691A, 0x97C9, 0x691B, 0x97CA, 0x691C, 0x97CB, 0x691D, 0x97CC, 0x691E, 0x97CD, 0x6921, 0x97CE, 0x6922, 0x97CF, 0x6923, 0x97D0, 0x6925, 0x97D1, 0x6926, 0x97D2, 0x6927, 0x97D3, 0x6928, 0x97D4, 0x6929, 0x97D5, 0x692A, 0x97D6, 0x692B, 0x97D7, 0x692C, 0x97D8, 0x692E, 0x97D9, 0x692F, 0x97DA, 0x6931, 0x97DB, 0x6932, 0x97DC, 0x6933, 0x97DD, 0x6935, 0x97DE, 0x6936, 0x97DF, 0x6937, 0x97E0, 0x6938, 0x97E1, 0x693A, 0x97E2, 0x693B, 0x97E3, 0x693C, 0x97E4, 0x693E, 0x97E5, 0x6940, 0x97E6, 0x6941, 0x97E7, 0x6943, 0x97E8, 0x6944, 0x97E9, 0x6945, 0x97EA, 0x6946, 0x97EB, 0x6947, 0x97EC, 0x6948, 0x97ED, 0x6949, 0x97EE, 0x694A, 0x97EF, 0x694B, 0x97F0, 0x694C, 0x97F1, 0x694D, 0x97F2, 0x694E, 0x97F3, 0x694F, 0x97F4, 0x6950, 0x97F5, 0x6951, 0x97F6, 0x6952, 0x97F7, 0x6953, 0x97F8, 0x6955, 0x97F9, 0x6956, 0x97FA, 0x6958, 0x97FB, 0x6959, 0x97FC, 0x695B, 0x97FD, 0x695C, 0x97FE, 0x695F, 0x9840, 0x6961, 0x9841, 0x6962, 0x9842, 0x6964, 0x9843, 0x6965, 0x9844, 0x6967, 0x9845, 0x6968, 0x9846, 0x6969, 0x9847, 0x696A, 0x9848, 0x696C, 0x9849, 0x696D, 0x984A, 0x696F, 0x984B, 0x6970, 0x984C, 0x6972, 0x984D, 0x6973, 0x984E, 0x6974, 0x984F, 0x6975, 0x9850, 0x6976, 0x9851, 0x697A, 0x9852, 0x697B, 0x9853, 0x697D, 0x9854, 0x697E, 0x9855, 0x697F, 0x9856, 0x6981, 0x9857, 0x6983, 0x9858, 0x6985, 0x9859, 0x698A, 0x985A, 0x698B, 0x985B, 0x698C, 0x985C, 0x698E, 0x985D, 0x698F, 0x985E, 0x6990, 0x985F, 0x6991, 0x9860, 0x6992, 0x9861, 0x6993, 0x9862, 0x6996, 0x9863, 0x6997, 0x9864, 0x6999, 0x9865, 0x699A, 0x9866, 0x699D, 0x9867, 0x699E, 0x9868, 0x699F, 0x9869, 0x69A0, 0x986A, 0x69A1, 0x986B, 0x69A2, 0x986C, 0x69A3, 0x986D, 0x69A4, 0x986E, 0x69A5, 0x986F, 0x69A6, 0x9870, 0x69A9, 0x9871, 0x69AA, 0x9872, 0x69AC, 0x9873, 0x69AE, 0x9874, 0x69AF, 0x9875, 0x69B0, 0x9876, 0x69B2, 0x9877, 0x69B3, 0x9878, 0x69B5, 0x9879, 0x69B6, 0x987A, 0x69B8, 0x987B, 0x69B9, 0x987C, 0x69BA, 0x987D, 0x69BC, 0x987E, 0x69BD, 0x9880, 0x69BE, 0x9881, 0x69BF, 0x9882, 0x69C0, 0x9883, 0x69C2, 0x9884, 0x69C3, 0x9885, 0x69C4, 0x9886, 0x69C5, 0x9887, 0x69C6, 0x9888, 0x69C7, 0x9889, 0x69C8, 0x988A, 0x69C9, 0x988B, 0x69CB, 0x988C, 0x69CD, 0x988D, 0x69CF, 0x988E, 0x69D1, 0x988F, 0x69D2, 0x9890, 0x69D3, 0x9891, 0x69D5, 0x9892, 0x69D6, 0x9893, 0x69D7, 0x9894, 0x69D8, 0x9895, 0x69D9, 0x9896, 0x69DA, 0x9897, 0x69DC, 0x9898, 0x69DD, 0x9899, 0x69DE, 0x989A, 0x69E1, 0x989B, 0x69E2, 0x989C, 0x69E3, 0x989D, 0x69E4, 0x989E, 0x69E5, 0x989F, 0x69E6, 0x98A0, 0x69E7, 0x98A1, 0x69E8, 0x98A2, 0x69E9, 0x98A3, 0x69EA, 0x98A4, 0x69EB, 0x98A5, 0x69EC, 0x98A6, 0x69EE, 0x98A7, 0x69EF, 0x98A8, 0x69F0, 0x98A9, 0x69F1, 0x98AA, 0x69F3, 0x98AB, 0x69F4, 0x98AC, 0x69F5, 0x98AD, 0x69F6, 0x98AE, 0x69F7, 0x98AF, 0x69F8, 0x98B0, 0x69F9, 0x98B1, 0x69FA, 0x98B2, 0x69FB, 0x98B3, 0x69FC, 0x98B4, 0x69FE, 0x98B5, 0x6A00, 0x98B6, 0x6A01, 0x98B7, 0x6A02, 0x98B8, 0x6A03, 0x98B9, 0x6A04, 0x98BA, 0x6A05, 0x98BB, 0x6A06, 0x98BC, 0x6A07, 0x98BD, 0x6A08, 0x98BE, 0x6A09, 0x98BF, 0x6A0B, 0x98C0, 0x6A0C, 0x98C1, 0x6A0D, 0x98C2, 0x6A0E, 0x98C3, 0x6A0F, 0x98C4, 0x6A10, 0x98C5, 0x6A11, 0x98C6, 0x6A12, 0x98C7, 0x6A13, 0x98C8, 0x6A14, 0x98C9, 0x6A15, 0x98CA, 0x6A16, 0x98CB, 0x6A19, 0x98CC, 0x6A1A, 0x98CD, 0x6A1B, 0x98CE, 0x6A1C, 0x98CF, 0x6A1D, 0x98D0, 0x6A1E, 0x98D1, 0x6A20, 0x98D2, 0x6A22, 0x98D3, 0x6A23, 0x98D4, 0x6A24, 0x98D5, 0x6A25, 0x98D6, 0x6A26, 0x98D7, 0x6A27, 0x98D8, 0x6A29, 0x98D9, 0x6A2B, 0x98DA, 0x6A2C, 0x98DB, 0x6A2D, 0x98DC, 0x6A2E, 0x98DD, 0x6A30, 0x98DE, 0x6A32, 0x98DF, 0x6A33, 0x98E0, 0x6A34, 0x98E1, 0x6A36, 0x98E2, 0x6A37, 0x98E3, 0x6A38, 0x98E4, 0x6A39, 0x98E5, 0x6A3A, 0x98E6, 0x6A3B, 0x98E7, 0x6A3C, 0x98E8, 0x6A3F, 0x98E9, 0x6A40, 0x98EA, 0x6A41, 0x98EB, 0x6A42, 0x98EC, 0x6A43, 0x98ED, 0x6A45, 0x98EE, 0x6A46, 0x98EF, 0x6A48, 0x98F0, 0x6A49, 0x98F1, 0x6A4A, 0x98F2, 0x6A4B, 0x98F3, 0x6A4C, 0x98F4, 0x6A4D, 0x98F5, 0x6A4E, 0x98F6, 0x6A4F, 0x98F7, 0x6A51, 0x98F8, 0x6A52, 0x98F9, 0x6A53, 0x98FA, 0x6A54, 0x98FB, 0x6A55, 0x98FC, 0x6A56, 0x98FD, 0x6A57, 0x98FE, 0x6A5A, 0x9940, 0x6A5C, 0x9941, 0x6A5D, 0x9942, 0x6A5E, 0x9943, 0x6A5F, 0x9944, 0x6A60, 0x9945, 0x6A62, 0x9946, 0x6A63, 0x9947, 0x6A64, 0x9948, 0x6A66, 0x9949, 0x6A67, 0x994A, 0x6A68, 0x994B, 0x6A69, 0x994C, 0x6A6A, 0x994D, 0x6A6B, 0x994E, 0x6A6C, 0x994F, 0x6A6D, 0x9950, 0x6A6E, 0x9951, 0x6A6F, 0x9952, 0x6A70, 0x9953, 0x6A72, 0x9954, 0x6A73, 0x9955, 0x6A74, 0x9956, 0x6A75, 0x9957, 0x6A76, 0x9958, 0x6A77, 0x9959, 0x6A78, 0x995A, 0x6A7A, 0x995B, 0x6A7B, 0x995C, 0x6A7D, 0x995D, 0x6A7E, 0x995E, 0x6A7F, 0x995F, 0x6A81, 0x9960, 0x6A82, 0x9961, 0x6A83, 0x9962, 0x6A85, 0x9963, 0x6A86, 0x9964, 0x6A87, 0x9965, 0x6A88, 0x9966, 0x6A89, 0x9967, 0x6A8A, 0x9968, 0x6A8B, 0x9969, 0x6A8C, 0x996A, 0x6A8D, 0x996B, 0x6A8F, 0x996C, 0x6A92, 0x996D, 0x6A93, 0x996E, 0x6A94, 0x996F, 0x6A95, 0x9970, 0x6A96, 0x9971, 0x6A98, 0x9972, 0x6A99, 0x9973, 0x6A9A, 0x9974, 0x6A9B, 0x9975, 0x6A9C, 0x9976, 0x6A9D, 0x9977, 0x6A9E, 0x9978, 0x6A9F, 0x9979, 0x6AA1, 0x997A, 0x6AA2, 0x997B, 0x6AA3, 0x997C, 0x6AA4, 0x997D, 0x6AA5, 0x997E, 0x6AA6, 0x9980, 0x6AA7, 0x9981, 0x6AA8, 0x9982, 0x6AAA, 0x9983, 0x6AAD, 0x9984, 0x6AAE, 0x9985, 0x6AAF, 0x9986, 0x6AB0, 0x9987, 0x6AB1, 0x9988, 0x6AB2, 0x9989, 0x6AB3, 0x998A, 0x6AB4, 0x998B, 0x6AB5, 0x998C, 0x6AB6, 0x998D, 0x6AB7, 0x998E, 0x6AB8, 0x998F, 0x6AB9, 0x9990, 0x6ABA, 0x9991, 0x6ABB, 0x9992, 0x6ABC, 0x9993, 0x6ABD, 0x9994, 0x6ABE, 0x9995, 0x6ABF, 0x9996, 0x6AC0, 0x9997, 0x6AC1, 0x9998, 0x6AC2, 0x9999, 0x6AC3, 0x999A, 0x6AC4, 0x999B, 0x6AC5, 0x999C, 0x6AC6, 0x999D, 0x6AC7, 0x999E, 0x6AC8, 0x999F, 0x6AC9, 0x99A0, 0x6ACA, 0x99A1, 0x6ACB, 0x99A2, 0x6ACC, 0x99A3, 0x6ACD, 0x99A4, 0x6ACE, 0x99A5, 0x6ACF, 0x99A6, 0x6AD0, 0x99A7, 0x6AD1, 0x99A8, 0x6AD2, 0x99A9, 0x6AD3, 0x99AA, 0x6AD4, 0x99AB, 0x6AD5, 0x99AC, 0x6AD6, 0x99AD, 0x6AD7, 0x99AE, 0x6AD8, 0x99AF, 0x6AD9, 0x99B0, 0x6ADA, 0x99B1, 0x6ADB, 0x99B2, 0x6ADC, 0x99B3, 0x6ADD, 0x99B4, 0x6ADE, 0x99B5, 0x6ADF, 0x99B6, 0x6AE0, 0x99B7, 0x6AE1, 0x99B8, 0x6AE2, 0x99B9, 0x6AE3, 0x99BA, 0x6AE4, 0x99BB, 0x6AE5, 0x99BC, 0x6AE6, 0x99BD, 0x6AE7, 0x99BE, 0x6AE8, 0x99BF, 0x6AE9, 0x99C0, 0x6AEA, 0x99C1, 0x6AEB, 0x99C2, 0x6AEC, 0x99C3, 0x6AED, 0x99C4, 0x6AEE, 0x99C5, 0x6AEF, 0x99C6, 0x6AF0, 0x99C7, 0x6AF1, 0x99C8, 0x6AF2, 0x99C9, 0x6AF3, 0x99CA, 0x6AF4, 0x99CB, 0x6AF5, 0x99CC, 0x6AF6, 0x99CD, 0x6AF7, 0x99CE, 0x6AF8, 0x99CF, 0x6AF9, 0x99D0, 0x6AFA, 0x99D1, 0x6AFB, 0x99D2, 0x6AFC, 0x99D3, 0x6AFD, 0x99D4, 0x6AFE, 0x99D5, 0x6AFF, 0x99D6, 0x6B00, 0x99D7, 0x6B01, 0x99D8, 0x6B02, 0x99D9, 0x6B03, 0x99DA, 0x6B04, 0x99DB, 0x6B05, 0x99DC, 0x6B06, 0x99DD, 0x6B07, 0x99DE, 0x6B08, 0x99DF, 0x6B09, 0x99E0, 0x6B0A, 0x99E1, 0x6B0B, 0x99E2, 0x6B0C, 0x99E3, 0x6B0D, 0x99E4, 0x6B0E, 0x99E5, 0x6B0F, 0x99E6, 0x6B10, 0x99E7, 0x6B11, 0x99E8, 0x6B12, 0x99E9, 0x6B13, 0x99EA, 0x6B14, 0x99EB, 0x6B15, 0x99EC, 0x6B16, 0x99ED, 0x6B17, 0x99EE, 0x6B18, 0x99EF, 0x6B19, 0x99F0, 0x6B1A, 0x99F1, 0x6B1B, 0x99F2, 0x6B1C, 0x99F3, 0x6B1D, 0x99F4, 0x6B1E, 0x99F5, 0x6B1F, 0x99F6, 0x6B25, 0x99F7, 0x6B26, 0x99F8, 0x6B28, 0x99F9, 0x6B29, 0x99FA, 0x6B2A, 0x99FB, 0x6B2B, 0x99FC, 0x6B2C, 0x99FD, 0x6B2D, 0x99FE, 0x6B2E, 0x9A40, 0x6B2F, 0x9A41, 0x6B30, 0x9A42, 0x6B31, 0x9A43, 0x6B33, 0x9A44, 0x6B34, 0x9A45, 0x6B35, 0x9A46, 0x6B36, 0x9A47, 0x6B38, 0x9A48, 0x6B3B, 0x9A49, 0x6B3C, 0x9A4A, 0x6B3D, 0x9A4B, 0x6B3F, 0x9A4C, 0x6B40, 0x9A4D, 0x6B41, 0x9A4E, 0x6B42, 0x9A4F, 0x6B44, 0x9A50, 0x6B45, 0x9A51, 0x6B48, 0x9A52, 0x6B4A, 0x9A53, 0x6B4B, 0x9A54, 0x6B4D, 0x9A55, 0x6B4E, 0x9A56, 0x6B4F, 0x9A57, 0x6B50, 0x9A58, 0x6B51, 0x9A59, 0x6B52, 0x9A5A, 0x6B53, 0x9A5B, 0x6B54, 0x9A5C, 0x6B55, 0x9A5D, 0x6B56, 0x9A5E, 0x6B57, 0x9A5F, 0x6B58, 0x9A60, 0x6B5A, 0x9A61, 0x6B5B, 0x9A62, 0x6B5C, 0x9A63, 0x6B5D, 0x9A64, 0x6B5E, 0x9A65, 0x6B5F, 0x9A66, 0x6B60, 0x9A67, 0x6B61, 0x9A68, 0x6B68, 0x9A69, 0x6B69, 0x9A6A, 0x6B6B, 0x9A6B, 0x6B6C, 0x9A6C, 0x6B6D, 0x9A6D, 0x6B6E, 0x9A6E, 0x6B6F, 0x9A6F, 0x6B70, 0x9A70, 0x6B71, 0x9A71, 0x6B72, 0x9A72, 0x6B73, 0x9A73, 0x6B74, 0x9A74, 0x6B75, 0x9A75, 0x6B76, 0x9A76, 0x6B77, 0x9A77, 0x6B78, 0x9A78, 0x6B7A, 0x9A79, 0x6B7D, 0x9A7A, 0x6B7E, 0x9A7B, 0x6B7F, 0x9A7C, 0x6B80, 0x9A7D, 0x6B85, 0x9A7E, 0x6B88, 0x9A80, 0x6B8C, 0x9A81, 0x6B8E, 0x9A82, 0x6B8F, 0x9A83, 0x6B90, 0x9A84, 0x6B91, 0x9A85, 0x6B94, 0x9A86, 0x6B95, 0x9A87, 0x6B97, 0x9A88, 0x6B98, 0x9A89, 0x6B99, 0x9A8A, 0x6B9C, 0x9A8B, 0x6B9D, 0x9A8C, 0x6B9E, 0x9A8D, 0x6B9F, 0x9A8E, 0x6BA0, 0x9A8F, 0x6BA2, 0x9A90, 0x6BA3, 0x9A91, 0x6BA4, 0x9A92, 0x6BA5, 0x9A93, 0x6BA6, 0x9A94, 0x6BA7, 0x9A95, 0x6BA8, 0x9A96, 0x6BA9, 0x9A97, 0x6BAB, 0x9A98, 0x6BAC, 0x9A99, 0x6BAD, 0x9A9A, 0x6BAE, 0x9A9B, 0x6BAF, 0x9A9C, 0x6BB0, 0x9A9D, 0x6BB1, 0x9A9E, 0x6BB2, 0x9A9F, 0x6BB6, 0x9AA0, 0x6BB8, 0x9AA1, 0x6BB9, 0x9AA2, 0x6BBA, 0x9AA3, 0x6BBB, 0x9AA4, 0x6BBC, 0x9AA5, 0x6BBD, 0x9AA6, 0x6BBE, 0x9AA7, 0x6BC0, 0x9AA8, 0x6BC3, 0x9AA9, 0x6BC4, 0x9AAA, 0x6BC6, 0x9AAB, 0x6BC7, 0x9AAC, 0x6BC8, 0x9AAD, 0x6BC9, 0x9AAE, 0x6BCA, 0x9AAF, 0x6BCC, 0x9AB0, 0x6BCE, 0x9AB1, 0x6BD0, 0x9AB2, 0x6BD1, 0x9AB3, 0x6BD8, 0x9AB4, 0x6BDA, 0x9AB5, 0x6BDC, 0x9AB6, 0x6BDD, 0x9AB7, 0x6BDE, 0x9AB8, 0x6BDF, 0x9AB9, 0x6BE0, 0x9ABA, 0x6BE2, 0x9ABB, 0x6BE3, 0x9ABC, 0x6BE4, 0x9ABD, 0x6BE5, 0x9ABE, 0x6BE6, 0x9ABF, 0x6BE7, 0x9AC0, 0x6BE8, 0x9AC1, 0x6BE9, 0x9AC2, 0x6BEC, 0x9AC3, 0x6BED, 0x9AC4, 0x6BEE, 0x9AC5, 0x6BF0, 0x9AC6, 0x6BF1, 0x9AC7, 0x6BF2, 0x9AC8, 0x6BF4, 0x9AC9, 0x6BF6, 0x9ACA, 0x6BF7, 0x9ACB, 0x6BF8, 0x9ACC, 0x6BFA, 0x9ACD, 0x6BFB, 0x9ACE, 0x6BFC, 0x9ACF, 0x6BFE, 0x9AD0, 0x6BFF, 0x9AD1, 0x6C00, 0x9AD2, 0x6C01, 0x9AD3, 0x6C02, 0x9AD4, 0x6C03, 0x9AD5, 0x6C04, 0x9AD6, 0x6C08, 0x9AD7, 0x6C09, 0x9AD8, 0x6C0A, 0x9AD9, 0x6C0B, 0x9ADA, 0x6C0C, 0x9ADB, 0x6C0E, 0x9ADC, 0x6C12, 0x9ADD, 0x6C17, 0x9ADE, 0x6C1C, 0x9ADF, 0x6C1D, 0x9AE0, 0x6C1E, 0x9AE1, 0x6C20, 0x9AE2, 0x6C23, 0x9AE3, 0x6C25, 0x9AE4, 0x6C2B, 0x9AE5, 0x6C2C, 0x9AE6, 0x6C2D, 0x9AE7, 0x6C31, 0x9AE8, 0x6C33, 0x9AE9, 0x6C36, 0x9AEA, 0x6C37, 0x9AEB, 0x6C39, 0x9AEC, 0x6C3A, 0x9AED, 0x6C3B, 0x9AEE, 0x6C3C, 0x9AEF, 0x6C3E, 0x9AF0, 0x6C3F, 0x9AF1, 0x6C43, 0x9AF2, 0x6C44, 0x9AF3, 0x6C45, 0x9AF4, 0x6C48, 0x9AF5, 0x6C4B, 0x9AF6, 0x6C4C, 0x9AF7, 0x6C4D, 0x9AF8, 0x6C4E, 0x9AF9, 0x6C4F, 0x9AFA, 0x6C51, 0x9AFB, 0x6C52, 0x9AFC, 0x6C53, 0x9AFD, 0x6C56, 0x9AFE, 0x6C58, 0x9B40, 0x6C59, 0x9B41, 0x6C5A, 0x9B42, 0x6C62, 0x9B43, 0x6C63, 0x9B44, 0x6C65, 0x9B45, 0x6C66, 0x9B46, 0x6C67, 0x9B47, 0x6C6B, 0x9B48, 0x6C6C, 0x9B49, 0x6C6D, 0x9B4A, 0x6C6E, 0x9B4B, 0x6C6F, 0x9B4C, 0x6C71, 0x9B4D, 0x6C73, 0x9B4E, 0x6C75, 0x9B4F, 0x6C77, 0x9B50, 0x6C78, 0x9B51, 0x6C7A, 0x9B52, 0x6C7B, 0x9B53, 0x6C7C, 0x9B54, 0x6C7F, 0x9B55, 0x6C80, 0x9B56, 0x6C84, 0x9B57, 0x6C87, 0x9B58, 0x6C8A, 0x9B59, 0x6C8B, 0x9B5A, 0x6C8D, 0x9B5B, 0x6C8E, 0x9B5C, 0x6C91, 0x9B5D, 0x6C92, 0x9B5E, 0x6C95, 0x9B5F, 0x6C96, 0x9B60, 0x6C97, 0x9B61, 0x6C98, 0x9B62, 0x6C9A, 0x9B63, 0x6C9C, 0x9B64, 0x6C9D, 0x9B65, 0x6C9E, 0x9B66, 0x6CA0, 0x9B67, 0x6CA2, 0x9B68, 0x6CA8, 0x9B69, 0x6CAC, 0x9B6A, 0x6CAF, 0x9B6B, 0x6CB0, 0x9B6C, 0x6CB4, 0x9B6D, 0x6CB5, 0x9B6E, 0x6CB6, 0x9B6F, 0x6CB7, 0x9B70, 0x6CBA, 0x9B71, 0x6CC0, 0x9B72, 0x6CC1, 0x9B73, 0x6CC2, 0x9B74, 0x6CC3, 0x9B75, 0x6CC6, 0x9B76, 0x6CC7, 0x9B77, 0x6CC8, 0x9B78, 0x6CCB, 0x9B79, 0x6CCD, 0x9B7A, 0x6CCE, 0x9B7B, 0x6CCF, 0x9B7C, 0x6CD1, 0x9B7D, 0x6CD2, 0x9B7E, 0x6CD8, 0x9B80, 0x6CD9, 0x9B81, 0x6CDA, 0x9B82, 0x6CDC, 0x9B83, 0x6CDD, 0x9B84, 0x6CDF, 0x9B85, 0x6CE4, 0x9B86, 0x6CE6, 0x9B87, 0x6CE7, 0x9B88, 0x6CE9, 0x9B89, 0x6CEC, 0x9B8A, 0x6CED, 0x9B8B, 0x6CF2, 0x9B8C, 0x6CF4, 0x9B8D, 0x6CF9, 0x9B8E, 0x6CFF, 0x9B8F, 0x6D00, 0x9B90, 0x6D02, 0x9B91, 0x6D03, 0x9B92, 0x6D05, 0x9B93, 0x6D06, 0x9B94, 0x6D08, 0x9B95, 0x6D09, 0x9B96, 0x6D0A, 0x9B97, 0x6D0D, 0x9B98, 0x6D0F, 0x9B99, 0x6D10, 0x9B9A, 0x6D11, 0x9B9B, 0x6D13, 0x9B9C, 0x6D14, 0x9B9D, 0x6D15, 0x9B9E, 0x6D16, 0x9B9F, 0x6D18, 0x9BA0, 0x6D1C, 0x9BA1, 0x6D1D, 0x9BA2, 0x6D1F, 0x9BA3, 0x6D20, 0x9BA4, 0x6D21, 0x9BA5, 0x6D22, 0x9BA6, 0x6D23, 0x9BA7, 0x6D24, 0x9BA8, 0x6D26, 0x9BA9, 0x6D28, 0x9BAA, 0x6D29, 0x9BAB, 0x6D2C, 0x9BAC, 0x6D2D, 0x9BAD, 0x6D2F, 0x9BAE, 0x6D30, 0x9BAF, 0x6D34, 0x9BB0, 0x6D36, 0x9BB1, 0x6D37, 0x9BB2, 0x6D38, 0x9BB3, 0x6D3A, 0x9BB4, 0x6D3F, 0x9BB5, 0x6D40, 0x9BB6, 0x6D42, 0x9BB7, 0x6D44, 0x9BB8, 0x6D49, 0x9BB9, 0x6D4C, 0x9BBA, 0x6D50, 0x9BBB, 0x6D55, 0x9BBC, 0x6D56, 0x9BBD, 0x6D57, 0x9BBE, 0x6D58, 0x9BBF, 0x6D5B, 0x9BC0, 0x6D5D, 0x9BC1, 0x6D5F, 0x9BC2, 0x6D61, 0x9BC3, 0x6D62, 0x9BC4, 0x6D64, 0x9BC5, 0x6D65, 0x9BC6, 0x6D67, 0x9BC7, 0x6D68, 0x9BC8, 0x6D6B, 0x9BC9, 0x6D6C, 0x9BCA, 0x6D6D, 0x9BCB, 0x6D70, 0x9BCC, 0x6D71, 0x9BCD, 0x6D72, 0x9BCE, 0x6D73, 0x9BCF, 0x6D75, 0x9BD0, 0x6D76, 0x9BD1, 0x6D79, 0x9BD2, 0x6D7A, 0x9BD3, 0x6D7B, 0x9BD4, 0x6D7D, 0x9BD5, 0x6D7E, 0x9BD6, 0x6D7F, 0x9BD7, 0x6D80, 0x9BD8, 0x6D81, 0x9BD9, 0x6D83, 0x9BDA, 0x6D84, 0x9BDB, 0x6D86, 0x9BDC, 0x6D87, 0x9BDD, 0x6D8A, 0x9BDE, 0x6D8B, 0x9BDF, 0x6D8D, 0x9BE0, 0x6D8F, 0x9BE1, 0x6D90, 0x9BE2, 0x6D92, 0x9BE3, 0x6D96, 0x9BE4, 0x6D97, 0x9BE5, 0x6D98, 0x9BE6, 0x6D99, 0x9BE7, 0x6D9A, 0x9BE8, 0x6D9C, 0x9BE9, 0x6DA2, 0x9BEA, 0x6DA5, 0x9BEB, 0x6DAC, 0x9BEC, 0x6DAD, 0x9BED, 0x6DB0, 0x9BEE, 0x6DB1, 0x9BEF, 0x6DB3, 0x9BF0, 0x6DB4, 0x9BF1, 0x6DB6, 0x9BF2, 0x6DB7, 0x9BF3, 0x6DB9, 0x9BF4, 0x6DBA, 0x9BF5, 0x6DBB, 0x9BF6, 0x6DBC, 0x9BF7, 0x6DBD, 0x9BF8, 0x6DBE, 0x9BF9, 0x6DC1, 0x9BFA, 0x6DC2, 0x9BFB, 0x6DC3, 0x9BFC, 0x6DC8, 0x9BFD, 0x6DC9, 0x9BFE, 0x6DCA, 0x9C40, 0x6DCD, 0x9C41, 0x6DCE, 0x9C42, 0x6DCF, 0x9C43, 0x6DD0, 0x9C44, 0x6DD2, 0x9C45, 0x6DD3, 0x9C46, 0x6DD4, 0x9C47, 0x6DD5, 0x9C48, 0x6DD7, 0x9C49, 0x6DDA, 0x9C4A, 0x6DDB, 0x9C4B, 0x6DDC, 0x9C4C, 0x6DDF, 0x9C4D, 0x6DE2, 0x9C4E, 0x6DE3, 0x9C4F, 0x6DE5, 0x9C50, 0x6DE7, 0x9C51, 0x6DE8, 0x9C52, 0x6DE9, 0x9C53, 0x6DEA, 0x9C54, 0x6DED, 0x9C55, 0x6DEF, 0x9C56, 0x6DF0, 0x9C57, 0x6DF2, 0x9C58, 0x6DF4, 0x9C59, 0x6DF5, 0x9C5A, 0x6DF6, 0x9C5B, 0x6DF8, 0x9C5C, 0x6DFA, 0x9C5D, 0x6DFD, 0x9C5E, 0x6DFE, 0x9C5F, 0x6DFF, 0x9C60, 0x6E00, 0x9C61, 0x6E01, 0x9C62, 0x6E02, 0x9C63, 0x6E03, 0x9C64, 0x6E04, 0x9C65, 0x6E06, 0x9C66, 0x6E07, 0x9C67, 0x6E08, 0x9C68, 0x6E09, 0x9C69, 0x6E0B, 0x9C6A, 0x6E0F, 0x9C6B, 0x6E12, 0x9C6C, 0x6E13, 0x9C6D, 0x6E15, 0x9C6E, 0x6E18, 0x9C6F, 0x6E19, 0x9C70, 0x6E1B, 0x9C71, 0x6E1C, 0x9C72, 0x6E1E, 0x9C73, 0x6E1F, 0x9C74, 0x6E22, 0x9C75, 0x6E26, 0x9C76, 0x6E27, 0x9C77, 0x6E28, 0x9C78, 0x6E2A, 0x9C79, 0x6E2C, 0x9C7A, 0x6E2E, 0x9C7B, 0x6E30, 0x9C7C, 0x6E31, 0x9C7D, 0x6E33, 0x9C7E, 0x6E35, 0x9C80, 0x6E36, 0x9C81, 0x6E37, 0x9C82, 0x6E39, 0x9C83, 0x6E3B, 0x9C84, 0x6E3C, 0x9C85, 0x6E3D, 0x9C86, 0x6E3E, 0x9C87, 0x6E3F, 0x9C88, 0x6E40, 0x9C89, 0x6E41, 0x9C8A, 0x6E42, 0x9C8B, 0x6E45, 0x9C8C, 0x6E46, 0x9C8D, 0x6E47, 0x9C8E, 0x6E48, 0x9C8F, 0x6E49, 0x9C90, 0x6E4A, 0x9C91, 0x6E4B, 0x9C92, 0x6E4C, 0x9C93, 0x6E4F, 0x9C94, 0x6E50, 0x9C95, 0x6E51, 0x9C96, 0x6E52, 0x9C97, 0x6E55, 0x9C98, 0x6E57, 0x9C99, 0x6E59, 0x9C9A, 0x6E5A, 0x9C9B, 0x6E5C, 0x9C9C, 0x6E5D, 0x9C9D, 0x6E5E, 0x9C9E, 0x6E60, 0x9C9F, 0x6E61, 0x9CA0, 0x6E62, 0x9CA1, 0x6E63, 0x9CA2, 0x6E64, 0x9CA3, 0x6E65, 0x9CA4, 0x6E66, 0x9CA5, 0x6E67, 0x9CA6, 0x6E68, 0x9CA7, 0x6E69, 0x9CA8, 0x6E6A, 0x9CA9, 0x6E6C, 0x9CAA, 0x6E6D, 0x9CAB, 0x6E6F, 0x9CAC, 0x6E70, 0x9CAD, 0x6E71, 0x9CAE, 0x6E72, 0x9CAF, 0x6E73, 0x9CB0, 0x6E74, 0x9CB1, 0x6E75, 0x9CB2, 0x6E76, 0x9CB3, 0x6E77, 0x9CB4, 0x6E78, 0x9CB5, 0x6E79, 0x9CB6, 0x6E7A, 0x9CB7, 0x6E7B, 0x9CB8, 0x6E7C, 0x9CB9, 0x6E7D, 0x9CBA, 0x6E80, 0x9CBB, 0x6E81, 0x9CBC, 0x6E82, 0x9CBD, 0x6E84, 0x9CBE, 0x6E87, 0x9CBF, 0x6E88, 0x9CC0, 0x6E8A, 0x9CC1, 0x6E8B, 0x9CC2, 0x6E8C, 0x9CC3, 0x6E8D, 0x9CC4, 0x6E8E, 0x9CC5, 0x6E91, 0x9CC6, 0x6E92, 0x9CC7, 0x6E93, 0x9CC8, 0x6E94, 0x9CC9, 0x6E95, 0x9CCA, 0x6E96, 0x9CCB, 0x6E97, 0x9CCC, 0x6E99, 0x9CCD, 0x6E9A, 0x9CCE, 0x6E9B, 0x9CCF, 0x6E9D, 0x9CD0, 0x6E9E, 0x9CD1, 0x6EA0, 0x9CD2, 0x6EA1, 0x9CD3, 0x6EA3, 0x9CD4, 0x6EA4, 0x9CD5, 0x6EA6, 0x9CD6, 0x6EA8, 0x9CD7, 0x6EA9, 0x9CD8, 0x6EAB, 0x9CD9, 0x6EAC, 0x9CDA, 0x6EAD, 0x9CDB, 0x6EAE, 0x9CDC, 0x6EB0, 0x9CDD, 0x6EB3, 0x9CDE, 0x6EB5, 0x9CDF, 0x6EB8, 0x9CE0, 0x6EB9, 0x9CE1, 0x6EBC, 0x9CE2, 0x6EBE, 0x9CE3, 0x6EBF, 0x9CE4, 0x6EC0, 0x9CE5, 0x6EC3, 0x9CE6, 0x6EC4, 0x9CE7, 0x6EC5, 0x9CE8, 0x6EC6, 0x9CE9, 0x6EC8, 0x9CEA, 0x6EC9, 0x9CEB, 0x6ECA, 0x9CEC, 0x6ECC, 0x9CED, 0x6ECD, 0x9CEE, 0x6ECE, 0x9CEF, 0x6ED0, 0x9CF0, 0x6ED2, 0x9CF1, 0x6ED6, 0x9CF2, 0x6ED8, 0x9CF3, 0x6ED9, 0x9CF4, 0x6EDB, 0x9CF5, 0x6EDC, 0x9CF6, 0x6EDD, 0x9CF7, 0x6EE3, 0x9CF8, 0x6EE7, 0x9CF9, 0x6EEA, 0x9CFA, 0x6EEB, 0x9CFB, 0x6EEC, 0x9CFC, 0x6EED, 0x9CFD, 0x6EEE, 0x9CFE, 0x6EEF, 0x9D40, 0x6EF0, 0x9D41, 0x6EF1, 0x9D42, 0x6EF2, 0x9D43, 0x6EF3, 0x9D44, 0x6EF5, 0x9D45, 0x6EF6, 0x9D46, 0x6EF7, 0x9D47, 0x6EF8, 0x9D48, 0x6EFA, 0x9D49, 0x6EFB, 0x9D4A, 0x6EFC, 0x9D4B, 0x6EFD, 0x9D4C, 0x6EFE, 0x9D4D, 0x6EFF, 0x9D4E, 0x6F00, 0x9D4F, 0x6F01, 0x9D50, 0x6F03, 0x9D51, 0x6F04, 0x9D52, 0x6F05, 0x9D53, 0x6F07, 0x9D54, 0x6F08, 0x9D55, 0x6F0A, 0x9D56, 0x6F0B, 0x9D57, 0x6F0C, 0x9D58, 0x6F0D, 0x9D59, 0x6F0E, 0x9D5A, 0x6F10, 0x9D5B, 0x6F11, 0x9D5C, 0x6F12, 0x9D5D, 0x6F16, 0x9D5E, 0x6F17, 0x9D5F, 0x6F18, 0x9D60, 0x6F19, 0x9D61, 0x6F1A, 0x9D62, 0x6F1B, 0x9D63, 0x6F1C, 0x9D64, 0x6F1D, 0x9D65, 0x6F1E, 0x9D66, 0x6F1F, 0x9D67, 0x6F21, 0x9D68, 0x6F22, 0x9D69, 0x6F23, 0x9D6A, 0x6F25, 0x9D6B, 0x6F26, 0x9D6C, 0x6F27, 0x9D6D, 0x6F28, 0x9D6E, 0x6F2C, 0x9D6F, 0x6F2E, 0x9D70, 0x6F30, 0x9D71, 0x6F32, 0x9D72, 0x6F34, 0x9D73, 0x6F35, 0x9D74, 0x6F37, 0x9D75, 0x6F38, 0x9D76, 0x6F39, 0x9D77, 0x6F3A, 0x9D78, 0x6F3B, 0x9D79, 0x6F3C, 0x9D7A, 0x6F3D, 0x9D7B, 0x6F3F, 0x9D7C, 0x6F40, 0x9D7D, 0x6F41, 0x9D7E, 0x6F42, 0x9D80, 0x6F43, 0x9D81, 0x6F44, 0x9D82, 0x6F45, 0x9D83, 0x6F48, 0x9D84, 0x6F49, 0x9D85, 0x6F4A, 0x9D86, 0x6F4C, 0x9D87, 0x6F4E, 0x9D88, 0x6F4F, 0x9D89, 0x6F50, 0x9D8A, 0x6F51, 0x9D8B, 0x6F52, 0x9D8C, 0x6F53, 0x9D8D, 0x6F54, 0x9D8E, 0x6F55, 0x9D8F, 0x6F56, 0x9D90, 0x6F57, 0x9D91, 0x6F59, 0x9D92, 0x6F5A, 0x9D93, 0x6F5B, 0x9D94, 0x6F5D, 0x9D95, 0x6F5F, 0x9D96, 0x6F60, 0x9D97, 0x6F61, 0x9D98, 0x6F63, 0x9D99, 0x6F64, 0x9D9A, 0x6F65, 0x9D9B, 0x6F67, 0x9D9C, 0x6F68, 0x9D9D, 0x6F69, 0x9D9E, 0x6F6A, 0x9D9F, 0x6F6B, 0x9DA0, 0x6F6C, 0x9DA1, 0x6F6F, 0x9DA2, 0x6F70, 0x9DA3, 0x6F71, 0x9DA4, 0x6F73, 0x9DA5, 0x6F75, 0x9DA6, 0x6F76, 0x9DA7, 0x6F77, 0x9DA8, 0x6F79, 0x9DA9, 0x6F7B, 0x9DAA, 0x6F7D, 0x9DAB, 0x6F7E, 0x9DAC, 0x6F7F, 0x9DAD, 0x6F80, 0x9DAE, 0x6F81, 0x9DAF, 0x6F82, 0x9DB0, 0x6F83, 0x9DB1, 0x6F85, 0x9DB2, 0x6F86, 0x9DB3, 0x6F87, 0x9DB4, 0x6F8A, 0x9DB5, 0x6F8B, 0x9DB6, 0x6F8F, 0x9DB7, 0x6F90, 0x9DB8, 0x6F91, 0x9DB9, 0x6F92, 0x9DBA, 0x6F93, 0x9DBB, 0x6F94, 0x9DBC, 0x6F95, 0x9DBD, 0x6F96, 0x9DBE, 0x6F97, 0x9DBF, 0x6F98, 0x9DC0, 0x6F99, 0x9DC1, 0x6F9A, 0x9DC2, 0x6F9B, 0x9DC3, 0x6F9D, 0x9DC4, 0x6F9E, 0x9DC5, 0x6F9F, 0x9DC6, 0x6FA0, 0x9DC7, 0x6FA2, 0x9DC8, 0x6FA3, 0x9DC9, 0x6FA4, 0x9DCA, 0x6FA5, 0x9DCB, 0x6FA6, 0x9DCC, 0x6FA8, 0x9DCD, 0x6FA9, 0x9DCE, 0x6FAA, 0x9DCF, 0x6FAB, 0x9DD0, 0x6FAC, 0x9DD1, 0x6FAD, 0x9DD2, 0x6FAE, 0x9DD3, 0x6FAF, 0x9DD4, 0x6FB0, 0x9DD5, 0x6FB1, 0x9DD6, 0x6FB2, 0x9DD7, 0x6FB4, 0x9DD8, 0x6FB5, 0x9DD9, 0x6FB7, 0x9DDA, 0x6FB8, 0x9DDB, 0x6FBA, 0x9DDC, 0x6FBB, 0x9DDD, 0x6FBC, 0x9DDE, 0x6FBD, 0x9DDF, 0x6FBE, 0x9DE0, 0x6FBF, 0x9DE1, 0x6FC1, 0x9DE2, 0x6FC3, 0x9DE3, 0x6FC4, 0x9DE4, 0x6FC5, 0x9DE5, 0x6FC6, 0x9DE6, 0x6FC7, 0x9DE7, 0x6FC8, 0x9DE8, 0x6FCA, 0x9DE9, 0x6FCB, 0x9DEA, 0x6FCC, 0x9DEB, 0x6FCD, 0x9DEC, 0x6FCE, 0x9DED, 0x6FCF, 0x9DEE, 0x6FD0, 0x9DEF, 0x6FD3, 0x9DF0, 0x6FD4, 0x9DF1, 0x6FD5, 0x9DF2, 0x6FD6, 0x9DF3, 0x6FD7, 0x9DF4, 0x6FD8, 0x9DF5, 0x6FD9, 0x9DF6, 0x6FDA, 0x9DF7, 0x6FDB, 0x9DF8, 0x6FDC, 0x9DF9, 0x6FDD, 0x9DFA, 0x6FDF, 0x9DFB, 0x6FE2, 0x9DFC, 0x6FE3, 0x9DFD, 0x6FE4, 0x9DFE, 0x6FE5, 0x9E40, 0x6FE6, 0x9E41, 0x6FE7, 0x9E42, 0x6FE8, 0x9E43, 0x6FE9, 0x9E44, 0x6FEA, 0x9E45, 0x6FEB, 0x9E46, 0x6FEC, 0x9E47, 0x6FED, 0x9E48, 0x6FF0, 0x9E49, 0x6FF1, 0x9E4A, 0x6FF2, 0x9E4B, 0x6FF3, 0x9E4C, 0x6FF4, 0x9E4D, 0x6FF5, 0x9E4E, 0x6FF6, 0x9E4F, 0x6FF7, 0x9E50, 0x6FF8, 0x9E51, 0x6FF9, 0x9E52, 0x6FFA, 0x9E53, 0x6FFB, 0x9E54, 0x6FFC, 0x9E55, 0x6FFD, 0x9E56, 0x6FFE, 0x9E57, 0x6FFF, 0x9E58, 0x7000, 0x9E59, 0x7001, 0x9E5A, 0x7002, 0x9E5B, 0x7003, 0x9E5C, 0x7004, 0x9E5D, 0x7005, 0x9E5E, 0x7006, 0x9E5F, 0x7007, 0x9E60, 0x7008, 0x9E61, 0x7009, 0x9E62, 0x700A, 0x9E63, 0x700B, 0x9E64, 0x700C, 0x9E65, 0x700D, 0x9E66, 0x700E, 0x9E67, 0x700F, 0x9E68, 0x7010, 0x9E69, 0x7012, 0x9E6A, 0x7013, 0x9E6B, 0x7014, 0x9E6C, 0x7015, 0x9E6D, 0x7016, 0x9E6E, 0x7017, 0x9E6F, 0x7018, 0x9E70, 0x7019, 0x9E71, 0x701C, 0x9E72, 0x701D, 0x9E73, 0x701E, 0x9E74, 0x701F, 0x9E75, 0x7020, 0x9E76, 0x7021, 0x9E77, 0x7022, 0x9E78, 0x7024, 0x9E79, 0x7025, 0x9E7A, 0x7026, 0x9E7B, 0x7027, 0x9E7C, 0x7028, 0x9E7D, 0x7029, 0x9E7E, 0x702A, 0x9E80, 0x702B, 0x9E81, 0x702C, 0x9E82, 0x702D, 0x9E83, 0x702E, 0x9E84, 0x702F, 0x9E85, 0x7030, 0x9E86, 0x7031, 0x9E87, 0x7032, 0x9E88, 0x7033, 0x9E89, 0x7034, 0x9E8A, 0x7036, 0x9E8B, 0x7037, 0x9E8C, 0x7038, 0x9E8D, 0x703A, 0x9E8E, 0x703B, 0x9E8F, 0x703C, 0x9E90, 0x703D, 0x9E91, 0x703E, 0x9E92, 0x703F, 0x9E93, 0x7040, 0x9E94, 0x7041, 0x9E95, 0x7042, 0x9E96, 0x7043, 0x9E97, 0x7044, 0x9E98, 0x7045, 0x9E99, 0x7046, 0x9E9A, 0x7047, 0x9E9B, 0x7048, 0x9E9C, 0x7049, 0x9E9D, 0x704A, 0x9E9E, 0x704B, 0x9E9F, 0x704D, 0x9EA0, 0x704E, 0x9EA1, 0x7050, 0x9EA2, 0x7051, 0x9EA3, 0x7052, 0x9EA4, 0x7053, 0x9EA5, 0x7054, 0x9EA6, 0x7055, 0x9EA7, 0x7056, 0x9EA8, 0x7057, 0x9EA9, 0x7058, 0x9EAA, 0x7059, 0x9EAB, 0x705A, 0x9EAC, 0x705B, 0x9EAD, 0x705C, 0x9EAE, 0x705D, 0x9EAF, 0x705F, 0x9EB0, 0x7060, 0x9EB1, 0x7061, 0x9EB2, 0x7062, 0x9EB3, 0x7063, 0x9EB4, 0x7064, 0x9EB5, 0x7065, 0x9EB6, 0x7066, 0x9EB7, 0x7067, 0x9EB8, 0x7068, 0x9EB9, 0x7069, 0x9EBA, 0x706A, 0x9EBB, 0x706E, 0x9EBC, 0x7071, 0x9EBD, 0x7072, 0x9EBE, 0x7073, 0x9EBF, 0x7074, 0x9EC0, 0x7077, 0x9EC1, 0x7079, 0x9EC2, 0x707A, 0x9EC3, 0x707B, 0x9EC4, 0x707D, 0x9EC5, 0x7081, 0x9EC6, 0x7082, 0x9EC7, 0x7083, 0x9EC8, 0x7084, 0x9EC9, 0x7086, 0x9ECA, 0x7087, 0x9ECB, 0x7088, 0x9ECC, 0x708B, 0x9ECD, 0x708C, 0x9ECE, 0x708D, 0x9ECF, 0x708F, 0x9ED0, 0x7090, 0x9ED1, 0x7091, 0x9ED2, 0x7093, 0x9ED3, 0x7097, 0x9ED4, 0x7098, 0x9ED5, 0x709A, 0x9ED6, 0x709B, 0x9ED7, 0x709E, 0x9ED8, 0x709F, 0x9ED9, 0x70A0, 0x9EDA, 0x70A1, 0x9EDB, 0x70A2, 0x9EDC, 0x70A3, 0x9EDD, 0x70A4, 0x9EDE, 0x70A5, 0x9EDF, 0x70A6, 0x9EE0, 0x70A7, 0x9EE1, 0x70A8, 0x9EE2, 0x70A9, 0x9EE3, 0x70AA, 0x9EE4, 0x70B0, 0x9EE5, 0x70B2, 0x9EE6, 0x70B4, 0x9EE7, 0x70B5, 0x9EE8, 0x70B6, 0x9EE9, 0x70BA, 0x9EEA, 0x70BE, 0x9EEB, 0x70BF, 0x9EEC, 0x70C4, 0x9EED, 0x70C5, 0x9EEE, 0x70C6, 0x9EEF, 0x70C7, 0x9EF0, 0x70C9, 0x9EF1, 0x70CB, 0x9EF2, 0x70CC, 0x9EF3, 0x70CD, 0x9EF4, 0x70CE, 0x9EF5, 0x70CF, 0x9EF6, 0x70D0, 0x9EF7, 0x70D1, 0x9EF8, 0x70D2, 0x9EF9, 0x70D3, 0x9EFA, 0x70D4, 0x9EFB, 0x70D5, 0x9EFC, 0x70D6, 0x9EFD, 0x70D7, 0x9EFE, 0x70DA, 0x9F40, 0x70DC, 0x9F41, 0x70DD, 0x9F42, 0x70DE, 0x9F43, 0x70E0, 0x9F44, 0x70E1, 0x9F45, 0x70E2, 0x9F46, 0x70E3, 0x9F47, 0x70E5, 0x9F48, 0x70EA, 0x9F49, 0x70EE, 0x9F4A, 0x70F0, 0x9F4B, 0x70F1, 0x9F4C, 0x70F2, 0x9F4D, 0x70F3, 0x9F4E, 0x70F4, 0x9F4F, 0x70F5, 0x9F50, 0x70F6, 0x9F51, 0x70F8, 0x9F52, 0x70FA, 0x9F53, 0x70FB, 0x9F54, 0x70FC, 0x9F55, 0x70FE, 0x9F56, 0x70FF, 0x9F57, 0x7100, 0x9F58, 0x7101, 0x9F59, 0x7102, 0x9F5A, 0x7103, 0x9F5B, 0x7104, 0x9F5C, 0x7105, 0x9F5D, 0x7106, 0x9F5E, 0x7107, 0x9F5F, 0x7108, 0x9F60, 0x710B, 0x9F61, 0x710C, 0x9F62, 0x710D, 0x9F63, 0x710E, 0x9F64, 0x710F, 0x9F65, 0x7111, 0x9F66, 0x7112, 0x9F67, 0x7114, 0x9F68, 0x7117, 0x9F69, 0x711B, 0x9F6A, 0x711C, 0x9F6B, 0x711D, 0x9F6C, 0x711E, 0x9F6D, 0x711F, 0x9F6E, 0x7120, 0x9F6F, 0x7121, 0x9F70, 0x7122, 0x9F71, 0x7123, 0x9F72, 0x7124, 0x9F73, 0x7125, 0x9F74, 0x7127, 0x9F75, 0x7128, 0x9F76, 0x7129, 0x9F77, 0x712A, 0x9F78, 0x712B, 0x9F79, 0x712C, 0x9F7A, 0x712D, 0x9F7B, 0x712E, 0x9F7C, 0x7132, 0x9F7D, 0x7133, 0x9F7E, 0x7134, 0x9F80, 0x7135, 0x9F81, 0x7137, 0x9F82, 0x7138, 0x9F83, 0x7139, 0x9F84, 0x713A, 0x9F85, 0x713B, 0x9F86, 0x713C, 0x9F87, 0x713D, 0x9F88, 0x713E, 0x9F89, 0x713F, 0x9F8A, 0x7140, 0x9F8B, 0x7141, 0x9F8C, 0x7142, 0x9F8D, 0x7143, 0x9F8E, 0x7144, 0x9F8F, 0x7146, 0x9F90, 0x7147, 0x9F91, 0x7148, 0x9F92, 0x7149, 0x9F93, 0x714B, 0x9F94, 0x714D, 0x9F95, 0x714F, 0x9F96, 0x7150, 0x9F97, 0x7151, 0x9F98, 0x7152, 0x9F99, 0x7153, 0x9F9A, 0x7154, 0x9F9B, 0x7155, 0x9F9C, 0x7156, 0x9F9D, 0x7157, 0x9F9E, 0x7158, 0x9F9F, 0x7159, 0x9FA0, 0x715A, 0x9FA1, 0x715B, 0x9FA2, 0x715D, 0x9FA3, 0x715F, 0x9FA4, 0x7160, 0x9FA5, 0x7161, 0x9FA6, 0x7162, 0x9FA7, 0x7163, 0x9FA8, 0x7165, 0x9FA9, 0x7169, 0x9FAA, 0x716A, 0x9FAB, 0x716B, 0x9FAC, 0x716C, 0x9FAD, 0x716D, 0x9FAE, 0x716F, 0x9FAF, 0x7170, 0x9FB0, 0x7171, 0x9FB1, 0x7174, 0x9FB2, 0x7175, 0x9FB3, 0x7176, 0x9FB4, 0x7177, 0x9FB5, 0x7179, 0x9FB6, 0x717B, 0x9FB7, 0x717C, 0x9FB8, 0x717E, 0x9FB9, 0x717F, 0x9FBA, 0x7180, 0x9FBB, 0x7181, 0x9FBC, 0x7182, 0x9FBD, 0x7183, 0x9FBE, 0x7185, 0x9FBF, 0x7186, 0x9FC0, 0x7187, 0x9FC1, 0x7188, 0x9FC2, 0x7189, 0x9FC3, 0x718B, 0x9FC4, 0x718C, 0x9FC5, 0x718D, 0x9FC6, 0x718E, 0x9FC7, 0x7190, 0x9FC8, 0x7191, 0x9FC9, 0x7192, 0x9FCA, 0x7193, 0x9FCB, 0x7195, 0x9FCC, 0x7196, 0x9FCD, 0x7197, 0x9FCE, 0x719A, 0x9FCF, 0x719B, 0x9FD0, 0x719C, 0x9FD1, 0x719D, 0x9FD2, 0x719E, 0x9FD3, 0x71A1, 0x9FD4, 0x71A2, 0x9FD5, 0x71A3, 0x9FD6, 0x71A4, 0x9FD7, 0x71A5, 0x9FD8, 0x71A6, 0x9FD9, 0x71A7, 0x9FDA, 0x71A9, 0x9FDB, 0x71AA, 0x9FDC, 0x71AB, 0x9FDD, 0x71AD, 0x9FDE, 0x71AE, 0x9FDF, 0x71AF, 0x9FE0, 0x71B0, 0x9FE1, 0x71B1, 0x9FE2, 0x71B2, 0x9FE3, 0x71B4, 0x9FE4, 0x71B6, 0x9FE5, 0x71B7, 0x9FE6, 0x71B8, 0x9FE7, 0x71BA, 0x9FE8, 0x71BB, 0x9FE9, 0x71BC, 0x9FEA, 0x71BD, 0x9FEB, 0x71BE, 0x9FEC, 0x71BF, 0x9FED, 0x71C0, 0x9FEE, 0x71C1, 0x9FEF, 0x71C2, 0x9FF0, 0x71C4, 0x9FF1, 0x71C5, 0x9FF2, 0x71C6, 0x9FF3, 0x71C7, 0x9FF4, 0x71C8, 0x9FF5, 0x71C9, 0x9FF6, 0x71CA, 0x9FF7, 0x71CB, 0x9FF8, 0x71CC, 0x9FF9, 0x71CD, 0x9FFA, 0x71CF, 0x9FFB, 0x71D0, 0x9FFC, 0x71D1, 0x9FFD, 0x71D2, 0x9FFE, 0x71D3, 0xA040, 0x71D6, 0xA041, 0x71D7, 0xA042, 0x71D8, 0xA043, 0x71D9, 0xA044, 0x71DA, 0xA045, 0x71DB, 0xA046, 0x71DC, 0xA047, 0x71DD, 0xA048, 0x71DE, 0xA049, 0x71DF, 0xA04A, 0x71E1, 0xA04B, 0x71E2, 0xA04C, 0x71E3, 0xA04D, 0x71E4, 0xA04E, 0x71E6, 0xA04F, 0x71E8, 0xA050, 0x71E9, 0xA051, 0x71EA, 0xA052, 0x71EB, 0xA053, 0x71EC, 0xA054, 0x71ED, 0xA055, 0x71EF, 0xA056, 0x71F0, 0xA057, 0x71F1, 0xA058, 0x71F2, 0xA059, 0x71F3, 0xA05A, 0x71F4, 0xA05B, 0x71F5, 0xA05C, 0x71F6, 0xA05D, 0x71F7, 0xA05E, 0x71F8, 0xA05F, 0x71FA, 0xA060, 0x71FB, 0xA061, 0x71FC, 0xA062, 0x71FD, 0xA063, 0x71FE, 0xA064, 0x71FF, 0xA065, 0x7200, 0xA066, 0x7201, 0xA067, 0x7202, 0xA068, 0x7203, 0xA069, 0x7204, 0xA06A, 0x7205, 0xA06B, 0x7207, 0xA06C, 0x7208, 0xA06D, 0x7209, 0xA06E, 0x720A, 0xA06F, 0x720B, 0xA070, 0x720C, 0xA071, 0x720D, 0xA072, 0x720E, 0xA073, 0x720F, 0xA074, 0x7210, 0xA075, 0x7211, 0xA076, 0x7212, 0xA077, 0x7213, 0xA078, 0x7214, 0xA079, 0x7215, 0xA07A, 0x7216, 0xA07B, 0x7217, 0xA07C, 0x7218, 0xA07D, 0x7219, 0xA07E, 0x721A, 0xA080, 0x721B, 0xA081, 0x721C, 0xA082, 0x721E, 0xA083, 0x721F, 0xA084, 0x7220, 0xA085, 0x7221, 0xA086, 0x7222, 0xA087, 0x7223, 0xA088, 0x7224, 0xA089, 0x7225, 0xA08A, 0x7226, 0xA08B, 0x7227, 0xA08C, 0x7229, 0xA08D, 0x722B, 0xA08E, 0x722D, 0xA08F, 0x722E, 0xA090, 0x722F, 0xA091, 0x7232, 0xA092, 0x7233, 0xA093, 0x7234, 0xA094, 0x723A, 0xA095, 0x723C, 0xA096, 0x723E, 0xA097, 0x7240, 0xA098, 0x7241, 0xA099, 0x7242, 0xA09A, 0x7243, 0xA09B, 0x7244, 0xA09C, 0x7245, 0xA09D, 0x7246, 0xA09E, 0x7249, 0xA09F, 0x724A, 0xA0A0, 0x724B, 0xA0A1, 0x724E, 0xA0A2, 0x724F, 0xA0A3, 0x7250, 0xA0A4, 0x7251, 0xA0A5, 0x7253, 0xA0A6, 0x7254, 0xA0A7, 0x7255, 0xA0A8, 0x7257, 0xA0A9, 0x7258, 0xA0AA, 0x725A, 0xA0AB, 0x725C, 0xA0AC, 0x725E, 0xA0AD, 0x7260, 0xA0AE, 0x7263, 0xA0AF, 0x7264, 0xA0B0, 0x7265, 0xA0B1, 0x7268, 0xA0B2, 0x726A, 0xA0B3, 0x726B, 0xA0B4, 0x726C, 0xA0B5, 0x726D, 0xA0B6, 0x7270, 0xA0B7, 0x7271, 0xA0B8, 0x7273, 0xA0B9, 0x7274, 0xA0BA, 0x7276, 0xA0BB, 0x7277, 0xA0BC, 0x7278, 0xA0BD, 0x727B, 0xA0BE, 0x727C, 0xA0BF, 0x727D, 0xA0C0, 0x7282, 0xA0C1, 0x7283, 0xA0C2, 0x7285, 0xA0C3, 0x7286, 0xA0C4, 0x7287, 0xA0C5, 0x7288, 0xA0C6, 0x7289, 0xA0C7, 0x728C, 0xA0C8, 0x728E, 0xA0C9, 0x7290, 0xA0CA, 0x7291, 0xA0CB, 0x7293, 0xA0CC, 0x7294, 0xA0CD, 0x7295, 0xA0CE, 0x7296, 0xA0CF, 0x7297, 0xA0D0, 0x7298, 0xA0D1, 0x7299, 0xA0D2, 0x729A, 0xA0D3, 0x729B, 0xA0D4, 0x729C, 0xA0D5, 0x729D, 0xA0D6, 0x729E, 0xA0D7, 0x72A0, 0xA0D8, 0x72A1, 0xA0D9, 0x72A2, 0xA0DA, 0x72A3, 0xA0DB, 0x72A4, 0xA0DC, 0x72A5, 0xA0DD, 0x72A6, 0xA0DE, 0x72A7, 0xA0DF, 0x72A8, 0xA0E0, 0x72A9, 0xA0E1, 0x72AA, 0xA0E2, 0x72AB, 0xA0E3, 0x72AE, 0xA0E4, 0x72B1, 0xA0E5, 0x72B2, 0xA0E6, 0x72B3, 0xA0E7, 0x72B5, 0xA0E8, 0x72BA, 0xA0E9, 0x72BB, 0xA0EA, 0x72BC, 0xA0EB, 0x72BD, 0xA0EC, 0x72BE, 0xA0ED, 0x72BF, 0xA0EE, 0x72C0, 0xA0EF, 0x72C5, 0xA0F0, 0x72C6, 0xA0F1, 0x72C7, 0xA0F2, 0x72C9, 0xA0F3, 0x72CA, 0xA0F4, 0x72CB, 0xA0F5, 0x72CC, 0xA0F6, 0x72CF, 0xA0F7, 0x72D1, 0xA0F8, 0x72D3, 0xA0F9, 0x72D4, 0xA0FA, 0x72D5, 0xA0FB, 0x72D6, 0xA0FC, 0x72D8, 0xA0FD, 0x72DA, 0xA0FE, 0x72DB, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, 0xA1A5, 0x02C9, 0xA1A6, 0x02C7, 0xA1A7, 0x00A8, 0xA1A8, 0x3003, 0xA1A9, 0x3005, 0xA1AA, 0x2014, 0xA1AB, 0xFF5E, 0xA1AC, 0x2016, 0xA1AD, 0x2026, 0xA1AE, 0x2018, 0xA1AF, 0x2019, 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3016, 0xA1BD, 0x3017, 0xA1BE, 0x3010, 0xA1BF, 0x3011, 0xA1C0, 0x00B1, 0xA1C1, 0x00D7, 0xA1C2, 0x00F7, 0xA1C3, 0x2236, 0xA1C4, 0x2227, 0xA1C5, 0x2228, 0xA1C6, 0x2211, 0xA1C7, 0x220F, 0xA1C8, 0x222A, 0xA1C9, 0x2229, 0xA1CA, 0x2208, 0xA1CB, 0x2237, 0xA1CC, 0x221A, 0xA1CD, 0x22A5, 0xA1CE, 0x2225, 0xA1CF, 0x2220, 0xA1D0, 0x2312, 0xA1D1, 0x2299, 0xA1D2, 0x222B, 0xA1D3, 0x222E, 0xA1D4, 0x2261, 0xA1D5, 0x224C, 0xA1D6, 0x2248, 0xA1D7, 0x223D, 0xA1D8, 0x221D, 0xA1D9, 0x2260, 0xA1DA, 0x226E, 0xA1DB, 0x226F, 0xA1DC, 0x2264, 0xA1DD, 0x2265, 0xA1DE, 0x221E, 0xA1DF, 0x2235, 0xA1E0, 0x2234, 0xA1E1, 0x2642, 0xA1E2, 0x2640, 0xA1E3, 0x00B0, 0xA1E4, 0x2032, 0xA1E5, 0x2033, 0xA1E6, 0x2103, 0xA1E7, 0xFF04, 0xA1E8, 0x00A4, 0xA1E9, 0xFFE0, 0xA1EA, 0xFFE1, 0xA1EB, 0x2030, 0xA1EC, 0x00A7, 0xA1ED, 0x2116, 0xA1EE, 0x2606, 0xA1EF, 0x2605, 0xA1F0, 0x25CB, 0xA1F1, 0x25CF, 0xA1F2, 0x25CE, 0xA1F3, 0x25C7, 0xA1F4, 0x25C6, 0xA1F5, 0x25A1, 0xA1F6, 0x25A0, 0xA1F7, 0x25B3, 0xA1F8, 0x25B2, 0xA1F9, 0x203B, 0xA1FA, 0x2192, 0xA1FB, 0x2190, 0xA1FC, 0x2191, 0xA1FD, 0x2193, 0xA1FE, 0x3013, 0xA2A1, 0x2170, 0xA2A2, 0x2171, 0xA2A3, 0x2172, 0xA2A4, 0x2173, 0xA2A5, 0x2174, 0xA2A6, 0x2175, 0xA2A7, 0x2176, 0xA2A8, 0x2177, 0xA2A9, 0x2178, 0xA2AA, 0x2179, 0xA2B1, 0x2488, 0xA2B2, 0x2489, 0xA2B3, 0x248A, 0xA2B4, 0x248B, 0xA2B5, 0x248C, 0xA2B6, 0x248D, 0xA2B7, 0x248E, 0xA2B8, 0x248F, 0xA2B9, 0x2490, 0xA2BA, 0x2491, 0xA2BB, 0x2492, 0xA2BC, 0x2493, 0xA2BD, 0x2494, 0xA2BE, 0x2495, 0xA2BF, 0x2496, 0xA2C0, 0x2497, 0xA2C1, 0x2498, 0xA2C2, 0x2499, 0xA2C3, 0x249A, 0xA2C4, 0x249B, 0xA2C5, 0x2474, 0xA2C6, 0x2475, 0xA2C7, 0x2476, 0xA2C8, 0x2477, 0xA2C9, 0x2478, 0xA2CA, 0x2479, 0xA2CB, 0x247A, 0xA2CC, 0x247B, 0xA2CD, 0x247C, 0xA2CE, 0x247D, 0xA2CF, 0x247E, 0xA2D0, 0x247F, 0xA2D1, 0x2480, 0xA2D2, 0x2481, 0xA2D3, 0x2482, 0xA2D4, 0x2483, 0xA2D5, 0x2484, 0xA2D6, 0x2485, 0xA2D7, 0x2486, 0xA2D8, 0x2487, 0xA2D9, 0x2460, 0xA2DA, 0x2461, 0xA2DB, 0x2462, 0xA2DC, 0x2463, 0xA2DD, 0x2464, 0xA2DE, 0x2465, 0xA2DF, 0x2466, 0xA2E0, 0x2467, 0xA2E1, 0x2468, 0xA2E2, 0x2469, 0xA2E5, 0x3220, 0xA2E6, 0x3221, 0xA2E7, 0x3222, 0xA2E8, 0x3223, 0xA2E9, 0x3224, 0xA2EA, 0x3225, 0xA2EB, 0x3226, 0xA2EC, 0x3227, 0xA2ED, 0x3228, 0xA2EE, 0x3229, 0xA2F1, 0x2160, 0xA2F2, 0x2161, 0xA2F3, 0x2162, 0xA2F4, 0x2163, 0xA2F5, 0x2164, 0xA2F6, 0x2165, 0xA2F7, 0x2166, 0xA2F8, 0x2167, 0xA2F9, 0x2168, 0xA2FA, 0x2169, 0xA2FB, 0x216A, 0xA2FC, 0x216B, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFFE5, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFF3C, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA4A1, 0x3041, 0xA4A2, 0x3042, 0xA4A3, 0x3043, 0xA4A4, 0x3044, 0xA4A5, 0x3045, 0xA4A6, 0x3046, 0xA4A7, 0x3047, 0xA4A8, 0x3048, 0xA4A9, 0x3049, 0xA4AA, 0x304A, 0xA4AB, 0x304B, 0xA4AC, 0x304C, 0xA4AD, 0x304D, 0xA4AE, 0x304E, 0xA4AF, 0x304F, 0xA4B0, 0x3050, 0xA4B1, 0x3051, 0xA4B2, 0x3052, 0xA4B3, 0x3053, 0xA4B4, 0x3054, 0xA4B5, 0x3055, 0xA4B6, 0x3056, 0xA4B7, 0x3057, 0xA4B8, 0x3058, 0xA4B9, 0x3059, 0xA4BA, 0x305A, 0xA4BB, 0x305B, 0xA4BC, 0x305C, 0xA4BD, 0x305D, 0xA4BE, 0x305E, 0xA4BF, 0x305F, 0xA4C0, 0x3060, 0xA4C1, 0x3061, 0xA4C2, 0x3062, 0xA4C3, 0x3063, 0xA4C4, 0x3064, 0xA4C5, 0x3065, 0xA4C6, 0x3066, 0xA4C7, 0x3067, 0xA4C8, 0x3068, 0xA4C9, 0x3069, 0xA4CA, 0x306A, 0xA4CB, 0x306B, 0xA4CC, 0x306C, 0xA4CD, 0x306D, 0xA4CE, 0x306E, 0xA4CF, 0x306F, 0xA4D0, 0x3070, 0xA4D1, 0x3071, 0xA4D2, 0x3072, 0xA4D3, 0x3073, 0xA4D4, 0x3074, 0xA4D5, 0x3075, 0xA4D6, 0x3076, 0xA4D7, 0x3077, 0xA4D8, 0x3078, 0xA4D9, 0x3079, 0xA4DA, 0x307A, 0xA4DB, 0x307B, 0xA4DC, 0x307C, 0xA4DD, 0x307D, 0xA4DE, 0x307E, 0xA4DF, 0x307F, 0xA4E0, 0x3080, 0xA4E1, 0x3081, 0xA4E2, 0x3082, 0xA4E3, 0x3083, 0xA4E4, 0x3084, 0xA4E5, 0x3085, 0xA4E6, 0x3086, 0xA4E7, 0x3087, 0xA4E8, 0x3088, 0xA4E9, 0x3089, 0xA4EA, 0x308A, 0xA4EB, 0x308B, 0xA4EC, 0x308C, 0xA4ED, 0x308D, 0xA4EE, 0x308E, 0xA4EF, 0x308F, 0xA4F0, 0x3090, 0xA4F1, 0x3091, 0xA4F2, 0x3092, 0xA4F3, 0x3093, 0xA5A1, 0x30A1, 0xA5A2, 0x30A2, 0xA5A3, 0x30A3, 0xA5A4, 0x30A4, 0xA5A5, 0x30A5, 0xA5A6, 0x30A6, 0xA5A7, 0x30A7, 0xA5A8, 0x30A8, 0xA5A9, 0x30A9, 0xA5AA, 0x30AA, 0xA5AB, 0x30AB, 0xA5AC, 0x30AC, 0xA5AD, 0x30AD, 0xA5AE, 0x30AE, 0xA5AF, 0x30AF, 0xA5B0, 0x30B0, 0xA5B1, 0x30B1, 0xA5B2, 0x30B2, 0xA5B3, 0x30B3, 0xA5B4, 0x30B4, 0xA5B5, 0x30B5, 0xA5B6, 0x30B6, 0xA5B7, 0x30B7, 0xA5B8, 0x30B8, 0xA5B9, 0x30B9, 0xA5BA, 0x30BA, 0xA5BB, 0x30BB, 0xA5BC, 0x30BC, 0xA5BD, 0x30BD, 0xA5BE, 0x30BE, 0xA5BF, 0x30BF, 0xA5C0, 0x30C0, 0xA5C1, 0x30C1, 0xA5C2, 0x30C2, 0xA5C3, 0x30C3, 0xA5C4, 0x30C4, 0xA5C5, 0x30C5, 0xA5C6, 0x30C6, 0xA5C7, 0x30C7, 0xA5C8, 0x30C8, 0xA5C9, 0x30C9, 0xA5CA, 0x30CA, 0xA5CB, 0x30CB, 0xA5CC, 0x30CC, 0xA5CD, 0x30CD, 0xA5CE, 0x30CE, 0xA5CF, 0x30CF, 0xA5D0, 0x30D0, 0xA5D1, 0x30D1, 0xA5D2, 0x30D2, 0xA5D3, 0x30D3, 0xA5D4, 0x30D4, 0xA5D5, 0x30D5, 0xA5D6, 0x30D6, 0xA5D7, 0x30D7, 0xA5D8, 0x30D8, 0xA5D9, 0x30D9, 0xA5DA, 0x30DA, 0xA5DB, 0x30DB, 0xA5DC, 0x30DC, 0xA5DD, 0x30DD, 0xA5DE, 0x30DE, 0xA5DF, 0x30DF, 0xA5E0, 0x30E0, 0xA5E1, 0x30E1, 0xA5E2, 0x30E2, 0xA5E3, 0x30E3, 0xA5E4, 0x30E4, 0xA5E5, 0x30E5, 0xA5E6, 0x30E6, 0xA5E7, 0x30E7, 0xA5E8, 0x30E8, 0xA5E9, 0x30E9, 0xA5EA, 0x30EA, 0xA5EB, 0x30EB, 0xA5EC, 0x30EC, 0xA5ED, 0x30ED, 0xA5EE, 0x30EE, 0xA5EF, 0x30EF, 0xA5F0, 0x30F0, 0xA5F1, 0x30F1, 0xA5F2, 0x30F2, 0xA5F3, 0x30F3, 0xA5F4, 0x30F4, 0xA5F5, 0x30F5, 0xA5F6, 0x30F6, 0xA6A1, 0x0391, 0xA6A2, 0x0392, 0xA6A3, 0x0393, 0xA6A4, 0x0394, 0xA6A5, 0x0395, 0xA6A6, 0x0396, 0xA6A7, 0x0397, 0xA6A8, 0x0398, 0xA6A9, 0x0399, 0xA6AA, 0x039A, 0xA6AB, 0x039B, 0xA6AC, 0x039C, 0xA6AD, 0x039D, 0xA6AE, 0x039E, 0xA6AF, 0x039F, 0xA6B0, 0x03A0, 0xA6B1, 0x03A1, 0xA6B2, 0x03A3, 0xA6B3, 0x03A4, 0xA6B4, 0x03A5, 0xA6B5, 0x03A6, 0xA6B6, 0x03A7, 0xA6B7, 0x03A8, 0xA6B8, 0x03A9, 0xA6C1, 0x03B1, 0xA6C2, 0x03B2, 0xA6C3, 0x03B3, 0xA6C4, 0x03B4, 0xA6C5, 0x03B5, 0xA6C6, 0x03B6, 0xA6C7, 0x03B7, 0xA6C8, 0x03B8, 0xA6C9, 0x03B9, 0xA6CA, 0x03BA, 0xA6CB, 0x03BB, 0xA6CC, 0x03BC, 0xA6CD, 0x03BD, 0xA6CE, 0x03BE, 0xA6CF, 0x03BF, 0xA6D0, 0x03C0, 0xA6D1, 0x03C1, 0xA6D2, 0x03C3, 0xA6D3, 0x03C4, 0xA6D4, 0x03C5, 0xA6D5, 0x03C6, 0xA6D6, 0x03C7, 0xA6D7, 0x03C8, 0xA6D8, 0x03C9, 0xA6E0, 0xFE35, 0xA6E1, 0xFE36, 0xA6E2, 0xFE39, 0xA6E3, 0xFE3A, 0xA6E4, 0xFE3F, 0xA6E5, 0xFE40, 0xA6E6, 0xFE3D, 0xA6E7, 0xFE3E, 0xA6E8, 0xFE41, 0xA6E9, 0xFE42, 0xA6EA, 0xFE43, 0xA6EB, 0xFE44, 0xA6EE, 0xFE3B, 0xA6EF, 0xFE3C, 0xA6F0, 0xFE37, 0xA6F1, 0xFE38, 0xA6F2, 0xFE31, 0xA6F4, 0xFE33, 0xA6F5, 0xFE34, 0xA7A1, 0x0410, 0xA7A2, 0x0411, 0xA7A3, 0x0412, 0xA7A4, 0x0413, 0xA7A5, 0x0414, 0xA7A6, 0x0415, 0xA7A7, 0x0401, 0xA7A8, 0x0416, 0xA7A9, 0x0417, 0xA7AA, 0x0418, 0xA7AB, 0x0419, 0xA7AC, 0x041A, 0xA7AD, 0x041B, 0xA7AE, 0x041C, 0xA7AF, 0x041D, 0xA7B0, 0x041E, 0xA7B1, 0x041F, 0xA7B2, 0x0420, 0xA7B3, 0x0421, 0xA7B4, 0x0422, 0xA7B5, 0x0423, 0xA7B6, 0x0424, 0xA7B7, 0x0425, 0xA7B8, 0x0426, 0xA7B9, 0x0427, 0xA7BA, 0x0428, 0xA7BB, 0x0429, 0xA7BC, 0x042A, 0xA7BD, 0x042B, 0xA7BE, 0x042C, 0xA7BF, 0x042D, 0xA7C0, 0x042E, 0xA7C1, 0x042F, 0xA7D1, 0x0430, 0xA7D2, 0x0431, 0xA7D3, 0x0432, 0xA7D4, 0x0433, 0xA7D5, 0x0434, 0xA7D6, 0x0435, 0xA7D7, 0x0451, 0xA7D8, 0x0436, 0xA7D9, 0x0437, 0xA7DA, 0x0438, 0xA7DB, 0x0439, 0xA7DC, 0x043A, 0xA7DD, 0x043B, 0xA7DE, 0x043C, 0xA7DF, 0x043D, 0xA7E0, 0x043E, 0xA7E1, 0x043F, 0xA7E2, 0x0440, 0xA7E3, 0x0441, 0xA7E4, 0x0442, 0xA7E5, 0x0443, 0xA7E6, 0x0444, 0xA7E7, 0x0445, 0xA7E8, 0x0446, 0xA7E9, 0x0447, 0xA7EA, 0x0448, 0xA7EB, 0x0449, 0xA7EC, 0x044A, 0xA7ED, 0x044B, 0xA7EE, 0x044C, 0xA7EF, 0x044D, 0xA7F0, 0x044E, 0xA7F1, 0x044F, 0xA840, 0x02CA, 0xA841, 0x02CB, 0xA842, 0x02D9, 0xA843, 0x2013, 0xA844, 0x2015, 0xA845, 0x2025, 0xA846, 0x2035, 0xA847, 0x2105, 0xA848, 0x2109, 0xA849, 0x2196, 0xA84A, 0x2197, 0xA84B, 0x2198, 0xA84C, 0x2199, 0xA84D, 0x2215, 0xA84E, 0x221F, 0xA84F, 0x2223, 0xA850, 0x2252, 0xA851, 0x2266, 0xA852, 0x2267, 0xA853, 0x22BF, 0xA854, 0x2550, 0xA855, 0x2551, 0xA856, 0x2552, 0xA857, 0x2553, 0xA858, 0x2554, 0xA859, 0x2555, 0xA85A, 0x2556, 0xA85B, 0x2557, 0xA85C, 0x2558, 0xA85D, 0x2559, 0xA85E, 0x255A, 0xA85F, 0x255B, 0xA860, 0x255C, 0xA861, 0x255D, 0xA862, 0x255E, 0xA863, 0x255F, 0xA864, 0x2560, 0xA865, 0x2561, 0xA866, 0x2562, 0xA867, 0x2563, 0xA868, 0x2564, 0xA869, 0x2565, 0xA86A, 0x2566, 0xA86B, 0x2567, 0xA86C, 0x2568, 0xA86D, 0x2569, 0xA86E, 0x256A, 0xA86F, 0x256B, 0xA870, 0x256C, 0xA871, 0x256D, 0xA872, 0x256E, 0xA873, 0x256F, 0xA874, 0x2570, 0xA875, 0x2571, 0xA876, 0x2572, 0xA877, 0x2573, 0xA878, 0x2581, 0xA879, 0x2582, 0xA87A, 0x2583, 0xA87B, 0x2584, 0xA87C, 0x2585, 0xA87D, 0x2586, 0xA87E, 0x2587, 0xA880, 0x2588, 0xA881, 0x2589, 0xA882, 0x258A, 0xA883, 0x258B, 0xA884, 0x258C, 0xA885, 0x258D, 0xA886, 0x258E, 0xA887, 0x258F, 0xA888, 0x2593, 0xA889, 0x2594, 0xA88A, 0x2595, 0xA88B, 0x25BC, 0xA88C, 0x25BD, 0xA88D, 0x25E2, 0xA88E, 0x25E3, 0xA88F, 0x25E4, 0xA890, 0x25E5, 0xA891, 0x2609, 0xA892, 0x2295, 0xA893, 0x3012, 0xA894, 0x301D, 0xA895, 0x301E, 0xA8A1, 0x0101, 0xA8A2, 0x00E1, 0xA8A3, 0x01CE, 0xA8A4, 0x00E0, 0xA8A5, 0x0113, 0xA8A6, 0x00E9, 0xA8A7, 0x011B, 0xA8A8, 0x00E8, 0xA8A9, 0x012B, 0xA8AA, 0x00ED, 0xA8AB, 0x01D0, 0xA8AC, 0x00EC, 0xA8AD, 0x014D, 0xA8AE, 0x00F3, 0xA8AF, 0x01D2, 0xA8B0, 0x00F2, 0xA8B1, 0x016B, 0xA8B2, 0x00FA, 0xA8B3, 0x01D4, 0xA8B4, 0x00F9, 0xA8B5, 0x01D6, 0xA8B6, 0x01D8, 0xA8B7, 0x01DA, 0xA8B8, 0x01DC, 0xA8B9, 0x00FC, 0xA8BA, 0x00EA, 0xA8BB, 0x0251, 0xA8BD, 0x0144, 0xA8BE, 0x0148, 0xA8C0, 0x0261, 0xA8C5, 0x3105, 0xA8C6, 0x3106, 0xA8C7, 0x3107, 0xA8C8, 0x3108, 0xA8C9, 0x3109, 0xA8CA, 0x310A, 0xA8CB, 0x310B, 0xA8CC, 0x310C, 0xA8CD, 0x310D, 0xA8CE, 0x310E, 0xA8CF, 0x310F, 0xA8D0, 0x3110, 0xA8D1, 0x3111, 0xA8D2, 0x3112, 0xA8D3, 0x3113, 0xA8D4, 0x3114, 0xA8D5, 0x3115, 0xA8D6, 0x3116, 0xA8D7, 0x3117, 0xA8D8, 0x3118, 0xA8D9, 0x3119, 0xA8DA, 0x311A, 0xA8DB, 0x311B, 0xA8DC, 0x311C, 0xA8DD, 0x311D, 0xA8DE, 0x311E, 0xA8DF, 0x311F, 0xA8E0, 0x3120, 0xA8E1, 0x3121, 0xA8E2, 0x3122, 0xA8E3, 0x3123, 0xA8E4, 0x3124, 0xA8E5, 0x3125, 0xA8E6, 0x3126, 0xA8E7, 0x3127, 0xA8E8, 0x3128, 0xA8E9, 0x3129, 0xA940, 0x3021, 0xA941, 0x3022, 0xA942, 0x3023, 0xA943, 0x3024, 0xA944, 0x3025, 0xA945, 0x3026, 0xA946, 0x3027, 0xA947, 0x3028, 0xA948, 0x3029, 0xA949, 0x32A3, 0xA94A, 0x338E, 0xA94B, 0x338F, 0xA94C, 0x339C, 0xA94D, 0x339D, 0xA94E, 0x339E, 0xA94F, 0x33A1, 0xA950, 0x33C4, 0xA951, 0x33CE, 0xA952, 0x33D1, 0xA953, 0x33D2, 0xA954, 0x33D5, 0xA955, 0xFE30, 0xA956, 0xFFE2, 0xA957, 0xFFE4, 0xA959, 0x2121, 0xA95A, 0x3231, 0xA95C, 0x2010, 0xA960, 0x30FC, 0xA961, 0x309B, 0xA962, 0x309C, 0xA963, 0x30FD, 0xA964, 0x30FE, 0xA965, 0x3006, 0xA966, 0x309D, 0xA967, 0x309E, 0xA968, 0xFE49, 0xA969, 0xFE4A, 0xA96A, 0xFE4B, 0xA96B, 0xFE4C, 0xA96C, 0xFE4D, 0xA96D, 0xFE4E, 0xA96E, 0xFE4F, 0xA96F, 0xFE50, 0xA970, 0xFE51, 0xA971, 0xFE52, 0xA972, 0xFE54, 0xA973, 0xFE55, 0xA974, 0xFE56, 0xA975, 0xFE57, 0xA976, 0xFE59, 0xA977, 0xFE5A, 0xA978, 0xFE5B, 0xA979, 0xFE5C, 0xA97A, 0xFE5D, 0xA97B, 0xFE5E, 0xA97C, 0xFE5F, 0xA97D, 0xFE60, 0xA97E, 0xFE61, 0xA980, 0xFE62, 0xA981, 0xFE63, 0xA982, 0xFE64, 0xA983, 0xFE65, 0xA984, 0xFE66, 0xA985, 0xFE68, 0xA986, 0xFE69, 0xA987, 0xFE6A, 0xA988, 0xFE6B, 0xA996, 0x3007, 0xA9A4, 0x2500, 0xA9A5, 0x2501, 0xA9A6, 0x2502, 0xA9A7, 0x2503, 0xA9A8, 0x2504, 0xA9A9, 0x2505, 0xA9AA, 0x2506, 0xA9AB, 0x2507, 0xA9AC, 0x2508, 0xA9AD, 0x2509, 0xA9AE, 0x250A, 0xA9AF, 0x250B, 0xA9B0, 0x250C, 0xA9B1, 0x250D, 0xA9B2, 0x250E, 0xA9B3, 0x250F, 0xA9B4, 0x2510, 0xA9B5, 0x2511, 0xA9B6, 0x2512, 0xA9B7, 0x2513, 0xA9B8, 0x2514, 0xA9B9, 0x2515, 0xA9BA, 0x2516, 0xA9BB, 0x2517, 0xA9BC, 0x2518, 0xA9BD, 0x2519, 0xA9BE, 0x251A, 0xA9BF, 0x251B, 0xA9C0, 0x251C, 0xA9C1, 0x251D, 0xA9C2, 0x251E, 0xA9C3, 0x251F, 0xA9C4, 0x2520, 0xA9C5, 0x2521, 0xA9C6, 0x2522, 0xA9C7, 0x2523, 0xA9C8, 0x2524, 0xA9C9, 0x2525, 0xA9CA, 0x2526, 0xA9CB, 0x2527, 0xA9CC, 0x2528, 0xA9CD, 0x2529, 0xA9CE, 0x252A, 0xA9CF, 0x252B, 0xA9D0, 0x252C, 0xA9D1, 0x252D, 0xA9D2, 0x252E, 0xA9D3, 0x252F, 0xA9D4, 0x2530, 0xA9D5, 0x2531, 0xA9D6, 0x2532, 0xA9D7, 0x2533, 0xA9D8, 0x2534, 0xA9D9, 0x2535, 0xA9DA, 0x2536, 0xA9DB, 0x2537, 0xA9DC, 0x2538, 0xA9DD, 0x2539, 0xA9DE, 0x253A, 0xA9DF, 0x253B, 0xA9E0, 0x253C, 0xA9E1, 0x253D, 0xA9E2, 0x253E, 0xA9E3, 0x253F, 0xA9E4, 0x2540, 0xA9E5, 0x2541, 0xA9E6, 0x2542, 0xA9E7, 0x2543, 0xA9E8, 0x2544, 0xA9E9, 0x2545, 0xA9EA, 0x2546, 0xA9EB, 0x2547, 0xA9EC, 0x2548, 0xA9ED, 0x2549, 0xA9EE, 0x254A, 0xA9EF, 0x254B, 0xAA40, 0x72DC, 0xAA41, 0x72DD, 0xAA42, 0x72DF, 0xAA43, 0x72E2, 0xAA44, 0x72E3, 0xAA45, 0x72E4, 0xAA46, 0x72E5, 0xAA47, 0x72E6, 0xAA48, 0x72E7, 0xAA49, 0x72EA, 0xAA4A, 0x72EB, 0xAA4B, 0x72F5, 0xAA4C, 0x72F6, 0xAA4D, 0x72F9, 0xAA4E, 0x72FD, 0xAA4F, 0x72FE, 0xAA50, 0x72FF, 0xAA51, 0x7300, 0xAA52, 0x7302, 0xAA53, 0x7304, 0xAA54, 0x7305, 0xAA55, 0x7306, 0xAA56, 0x7307, 0xAA57, 0x7308, 0xAA58, 0x7309, 0xAA59, 0x730B, 0xAA5A, 0x730C, 0xAA5B, 0x730D, 0xAA5C, 0x730F, 0xAA5D, 0x7310, 0xAA5E, 0x7311, 0xAA5F, 0x7312, 0xAA60, 0x7314, 0xAA61, 0x7318, 0xAA62, 0x7319, 0xAA63, 0x731A, 0xAA64, 0x731F, 0xAA65, 0x7320, 0xAA66, 0x7323, 0xAA67, 0x7324, 0xAA68, 0x7326, 0xAA69, 0x7327, 0xAA6A, 0x7328, 0xAA6B, 0x732D, 0xAA6C, 0x732F, 0xAA6D, 0x7330, 0xAA6E, 0x7332, 0xAA6F, 0x7333, 0xAA70, 0x7335, 0xAA71, 0x7336, 0xAA72, 0x733A, 0xAA73, 0x733B, 0xAA74, 0x733C, 0xAA75, 0x733D, 0xAA76, 0x7340, 0xAA77, 0x7341, 0xAA78, 0x7342, 0xAA79, 0x7343, 0xAA7A, 0x7344, 0xAA7B, 0x7345, 0xAA7C, 0x7346, 0xAA7D, 0x7347, 0xAA7E, 0x7348, 0xAA80, 0x7349, 0xAA81, 0x734A, 0xAA82, 0x734B, 0xAA83, 0x734C, 0xAA84, 0x734E, 0xAA85, 0x734F, 0xAA86, 0x7351, 0xAA87, 0x7353, 0xAA88, 0x7354, 0xAA89, 0x7355, 0xAA8A, 0x7356, 0xAA8B, 0x7358, 0xAA8C, 0x7359, 0xAA8D, 0x735A, 0xAA8E, 0x735B, 0xAA8F, 0x735C, 0xAA90, 0x735D, 0xAA91, 0x735E, 0xAA92, 0x735F, 0xAA93, 0x7361, 0xAA94, 0x7362, 0xAA95, 0x7363, 0xAA96, 0x7364, 0xAA97, 0x7365, 0xAA98, 0x7366, 0xAA99, 0x7367, 0xAA9A, 0x7368, 0xAA9B, 0x7369, 0xAA9C, 0x736A, 0xAA9D, 0x736B, 0xAA9E, 0x736E, 0xAA9F, 0x7370, 0xAAA0, 0x7371, 0xAB40, 0x7372, 0xAB41, 0x7373, 0xAB42, 0x7374, 0xAB43, 0x7375, 0xAB44, 0x7376, 0xAB45, 0x7377, 0xAB46, 0x7378, 0xAB47, 0x7379, 0xAB48, 0x737A, 0xAB49, 0x737B, 0xAB4A, 0x737C, 0xAB4B, 0x737D, 0xAB4C, 0x737F, 0xAB4D, 0x7380, 0xAB4E, 0x7381, 0xAB4F, 0x7382, 0xAB50, 0x7383, 0xAB51, 0x7385, 0xAB52, 0x7386, 0xAB53, 0x7388, 0xAB54, 0x738A, 0xAB55, 0x738C, 0xAB56, 0x738D, 0xAB57, 0x738F, 0xAB58, 0x7390, 0xAB59, 0x7392, 0xAB5A, 0x7393, 0xAB5B, 0x7394, 0xAB5C, 0x7395, 0xAB5D, 0x7397, 0xAB5E, 0x7398, 0xAB5F, 0x7399, 0xAB60, 0x739A, 0xAB61, 0x739C, 0xAB62, 0x739D, 0xAB63, 0x739E, 0xAB64, 0x73A0, 0xAB65, 0x73A1, 0xAB66, 0x73A3, 0xAB67, 0x73A4, 0xAB68, 0x73A5, 0xAB69, 0x73A6, 0xAB6A, 0x73A7, 0xAB6B, 0x73A8, 0xAB6C, 0x73AA, 0xAB6D, 0x73AC, 0xAB6E, 0x73AD, 0xAB6F, 0x73B1, 0xAB70, 0x73B4, 0xAB71, 0x73B5, 0xAB72, 0x73B6, 0xAB73, 0x73B8, 0xAB74, 0x73B9, 0xAB75, 0x73BC, 0xAB76, 0x73BD, 0xAB77, 0x73BE, 0xAB78, 0x73BF, 0xAB79, 0x73C1, 0xAB7A, 0x73C3, 0xAB7B, 0x73C4, 0xAB7C, 0x73C5, 0xAB7D, 0x73C6, 0xAB7E, 0x73C7, 0xAB80, 0x73CB, 0xAB81, 0x73CC, 0xAB82, 0x73CE, 0xAB83, 0x73D2, 0xAB84, 0x73D3, 0xAB85, 0x73D4, 0xAB86, 0x73D5, 0xAB87, 0x73D6, 0xAB88, 0x73D7, 0xAB89, 0x73D8, 0xAB8A, 0x73DA, 0xAB8B, 0x73DB, 0xAB8C, 0x73DC, 0xAB8D, 0x73DD, 0xAB8E, 0x73DF, 0xAB8F, 0x73E1, 0xAB90, 0x73E2, 0xAB91, 0x73E3, 0xAB92, 0x73E4, 0xAB93, 0x73E6, 0xAB94, 0x73E8, 0xAB95, 0x73EA, 0xAB96, 0x73EB, 0xAB97, 0x73EC, 0xAB98, 0x73EE, 0xAB99, 0x73EF, 0xAB9A, 0x73F0, 0xAB9B, 0x73F1, 0xAB9C, 0x73F3, 0xAB9D, 0x73F4, 0xAB9E, 0x73F5, 0xAB9F, 0x73F6, 0xABA0, 0x73F7, 0xAC40, 0x73F8, 0xAC41, 0x73F9, 0xAC42, 0x73FA, 0xAC43, 0x73FB, 0xAC44, 0x73FC, 0xAC45, 0x73FD, 0xAC46, 0x73FE, 0xAC47, 0x73FF, 0xAC48, 0x7400, 0xAC49, 0x7401, 0xAC4A, 0x7402, 0xAC4B, 0x7404, 0xAC4C, 0x7407, 0xAC4D, 0x7408, 0xAC4E, 0x740B, 0xAC4F, 0x740C, 0xAC50, 0x740D, 0xAC51, 0x740E, 0xAC52, 0x7411, 0xAC53, 0x7412, 0xAC54, 0x7413, 0xAC55, 0x7414, 0xAC56, 0x7415, 0xAC57, 0x7416, 0xAC58, 0x7417, 0xAC59, 0x7418, 0xAC5A, 0x7419, 0xAC5B, 0x741C, 0xAC5C, 0x741D, 0xAC5D, 0x741E, 0xAC5E, 0x741F, 0xAC5F, 0x7420, 0xAC60, 0x7421, 0xAC61, 0x7423, 0xAC62, 0x7424, 0xAC63, 0x7427, 0xAC64, 0x7429, 0xAC65, 0x742B, 0xAC66, 0x742D, 0xAC67, 0x742F, 0xAC68, 0x7431, 0xAC69, 0x7432, 0xAC6A, 0x7437, 0xAC6B, 0x7438, 0xAC6C, 0x7439, 0xAC6D, 0x743A, 0xAC6E, 0x743B, 0xAC6F, 0x743D, 0xAC70, 0x743E, 0xAC71, 0x743F, 0xAC72, 0x7440, 0xAC73, 0x7442, 0xAC74, 0x7443, 0xAC75, 0x7444, 0xAC76, 0x7445, 0xAC77, 0x7446, 0xAC78, 0x7447, 0xAC79, 0x7448, 0xAC7A, 0x7449, 0xAC7B, 0x744A, 0xAC7C, 0x744B, 0xAC7D, 0x744C, 0xAC7E, 0x744D, 0xAC80, 0x744E, 0xAC81, 0x744F, 0xAC82, 0x7450, 0xAC83, 0x7451, 0xAC84, 0x7452, 0xAC85, 0x7453, 0xAC86, 0x7454, 0xAC87, 0x7456, 0xAC88, 0x7458, 0xAC89, 0x745D, 0xAC8A, 0x7460, 0xAC8B, 0x7461, 0xAC8C, 0x7462, 0xAC8D, 0x7463, 0xAC8E, 0x7464, 0xAC8F, 0x7465, 0xAC90, 0x7466, 0xAC91, 0x7467, 0xAC92, 0x7468, 0xAC93, 0x7469, 0xAC94, 0x746A, 0xAC95, 0x746B, 0xAC96, 0x746C, 0xAC97, 0x746E, 0xAC98, 0x746F, 0xAC99, 0x7471, 0xAC9A, 0x7472, 0xAC9B, 0x7473, 0xAC9C, 0x7474, 0xAC9D, 0x7475, 0xAC9E, 0x7478, 0xAC9F, 0x7479, 0xACA0, 0x747A, 0xAD40, 0x747B, 0xAD41, 0x747C, 0xAD42, 0x747D, 0xAD43, 0x747F, 0xAD44, 0x7482, 0xAD45, 0x7484, 0xAD46, 0x7485, 0xAD47, 0x7486, 0xAD48, 0x7488, 0xAD49, 0x7489, 0xAD4A, 0x748A, 0xAD4B, 0x748C, 0xAD4C, 0x748D, 0xAD4D, 0x748F, 0xAD4E, 0x7491, 0xAD4F, 0x7492, 0xAD50, 0x7493, 0xAD51, 0x7494, 0xAD52, 0x7495, 0xAD53, 0x7496, 0xAD54, 0x7497, 0xAD55, 0x7498, 0xAD56, 0x7499, 0xAD57, 0x749A, 0xAD58, 0x749B, 0xAD59, 0x749D, 0xAD5A, 0x749F, 0xAD5B, 0x74A0, 0xAD5C, 0x74A1, 0xAD5D, 0x74A2, 0xAD5E, 0x74A3, 0xAD5F, 0x74A4, 0xAD60, 0x74A5, 0xAD61, 0x74A6, 0xAD62, 0x74AA, 0xAD63, 0x74AB, 0xAD64, 0x74AC, 0xAD65, 0x74AD, 0xAD66, 0x74AE, 0xAD67, 0x74AF, 0xAD68, 0x74B0, 0xAD69, 0x74B1, 0xAD6A, 0x74B2, 0xAD6B, 0x74B3, 0xAD6C, 0x74B4, 0xAD6D, 0x74B5, 0xAD6E, 0x74B6, 0xAD6F, 0x74B7, 0xAD70, 0x74B8, 0xAD71, 0x74B9, 0xAD72, 0x74BB, 0xAD73, 0x74BC, 0xAD74, 0x74BD, 0xAD75, 0x74BE, 0xAD76, 0x74BF, 0xAD77, 0x74C0, 0xAD78, 0x74C1, 0xAD79, 0x74C2, 0xAD7A, 0x74C3, 0xAD7B, 0x74C4, 0xAD7C, 0x74C5, 0xAD7D, 0x74C6, 0xAD7E, 0x74C7, 0xAD80, 0x74C8, 0xAD81, 0x74C9, 0xAD82, 0x74CA, 0xAD83, 0x74CB, 0xAD84, 0x74CC, 0xAD85, 0x74CD, 0xAD86, 0x74CE, 0xAD87, 0x74CF, 0xAD88, 0x74D0, 0xAD89, 0x74D1, 0xAD8A, 0x74D3, 0xAD8B, 0x74D4, 0xAD8C, 0x74D5, 0xAD8D, 0x74D6, 0xAD8E, 0x74D7, 0xAD8F, 0x74D8, 0xAD90, 0x74D9, 0xAD91, 0x74DA, 0xAD92, 0x74DB, 0xAD93, 0x74DD, 0xAD94, 0x74DF, 0xAD95, 0x74E1, 0xAD96, 0x74E5, 0xAD97, 0x74E7, 0xAD98, 0x74E8, 0xAD99, 0x74E9, 0xAD9A, 0x74EA, 0xAD9B, 0x74EB, 0xAD9C, 0x74EC, 0xAD9D, 0x74ED, 0xAD9E, 0x74F0, 0xAD9F, 0x74F1, 0xADA0, 0x74F2, 0xAE40, 0x74F3, 0xAE41, 0x74F5, 0xAE42, 0x74F8, 0xAE43, 0x74F9, 0xAE44, 0x74FA, 0xAE45, 0x74FB, 0xAE46, 0x74FC, 0xAE47, 0x74FD, 0xAE48, 0x74FE, 0xAE49, 0x7500, 0xAE4A, 0x7501, 0xAE4B, 0x7502, 0xAE4C, 0x7503, 0xAE4D, 0x7505, 0xAE4E, 0x7506, 0xAE4F, 0x7507, 0xAE50, 0x7508, 0xAE51, 0x7509, 0xAE52, 0x750A, 0xAE53, 0x750B, 0xAE54, 0x750C, 0xAE55, 0x750E, 0xAE56, 0x7510, 0xAE57, 0x7512, 0xAE58, 0x7514, 0xAE59, 0x7515, 0xAE5A, 0x7516, 0xAE5B, 0x7517, 0xAE5C, 0x751B, 0xAE5D, 0x751D, 0xAE5E, 0x751E, 0xAE5F, 0x7520, 0xAE60, 0x7521, 0xAE61, 0x7522, 0xAE62, 0x7523, 0xAE63, 0x7524, 0xAE64, 0x7526, 0xAE65, 0x7527, 0xAE66, 0x752A, 0xAE67, 0x752E, 0xAE68, 0x7534, 0xAE69, 0x7536, 0xAE6A, 0x7539, 0xAE6B, 0x753C, 0xAE6C, 0x753D, 0xAE6D, 0x753F, 0xAE6E, 0x7541, 0xAE6F, 0x7542, 0xAE70, 0x7543, 0xAE71, 0x7544, 0xAE72, 0x7546, 0xAE73, 0x7547, 0xAE74, 0x7549, 0xAE75, 0x754A, 0xAE76, 0x754D, 0xAE77, 0x7550, 0xAE78, 0x7551, 0xAE79, 0x7552, 0xAE7A, 0x7553, 0xAE7B, 0x7555, 0xAE7C, 0x7556, 0xAE7D, 0x7557, 0xAE7E, 0x7558, 0xAE80, 0x755D, 0xAE81, 0x755E, 0xAE82, 0x755F, 0xAE83, 0x7560, 0xAE84, 0x7561, 0xAE85, 0x7562, 0xAE86, 0x7563, 0xAE87, 0x7564, 0xAE88, 0x7567, 0xAE89, 0x7568, 0xAE8A, 0x7569, 0xAE8B, 0x756B, 0xAE8C, 0x756C, 0xAE8D, 0x756D, 0xAE8E, 0x756E, 0xAE8F, 0x756F, 0xAE90, 0x7570, 0xAE91, 0x7571, 0xAE92, 0x7573, 0xAE93, 0x7575, 0xAE94, 0x7576, 0xAE95, 0x7577, 0xAE96, 0x757A, 0xAE97, 0x757B, 0xAE98, 0x757C, 0xAE99, 0x757D, 0xAE9A, 0x757E, 0xAE9B, 0x7580, 0xAE9C, 0x7581, 0xAE9D, 0x7582, 0xAE9E, 0x7584, 0xAE9F, 0x7585, 0xAEA0, 0x7587, 0xAF40, 0x7588, 0xAF41, 0x7589, 0xAF42, 0x758A, 0xAF43, 0x758C, 0xAF44, 0x758D, 0xAF45, 0x758E, 0xAF46, 0x7590, 0xAF47, 0x7593, 0xAF48, 0x7595, 0xAF49, 0x7598, 0xAF4A, 0x759B, 0xAF4B, 0x759C, 0xAF4C, 0x759E, 0xAF4D, 0x75A2, 0xAF4E, 0x75A6, 0xAF4F, 0x75A7, 0xAF50, 0x75A8, 0xAF51, 0x75A9, 0xAF52, 0x75AA, 0xAF53, 0x75AD, 0xAF54, 0x75B6, 0xAF55, 0x75B7, 0xAF56, 0x75BA, 0xAF57, 0x75BB, 0xAF58, 0x75BF, 0xAF59, 0x75C0, 0xAF5A, 0x75C1, 0xAF5B, 0x75C6, 0xAF5C, 0x75CB, 0xAF5D, 0x75CC, 0xAF5E, 0x75CE, 0xAF5F, 0x75CF, 0xAF60, 0x75D0, 0xAF61, 0x75D1, 0xAF62, 0x75D3, 0xAF63, 0x75D7, 0xAF64, 0x75D9, 0xAF65, 0x75DA, 0xAF66, 0x75DC, 0xAF67, 0x75DD, 0xAF68, 0x75DF, 0xAF69, 0x75E0, 0xAF6A, 0x75E1, 0xAF6B, 0x75E5, 0xAF6C, 0x75E9, 0xAF6D, 0x75EC, 0xAF6E, 0x75ED, 0xAF6F, 0x75EE, 0xAF70, 0x75EF, 0xAF71, 0x75F2, 0xAF72, 0x75F3, 0xAF73, 0x75F5, 0xAF74, 0x75F6, 0xAF75, 0x75F7, 0xAF76, 0x75F8, 0xAF77, 0x75FA, 0xAF78, 0x75FB, 0xAF79, 0x75FD, 0xAF7A, 0x75FE, 0xAF7B, 0x7602, 0xAF7C, 0x7604, 0xAF7D, 0x7606, 0xAF7E, 0x7607, 0xAF80, 0x7608, 0xAF81, 0x7609, 0xAF82, 0x760B, 0xAF83, 0x760D, 0xAF84, 0x760E, 0xAF85, 0x760F, 0xAF86, 0x7611, 0xAF87, 0x7612, 0xAF88, 0x7613, 0xAF89, 0x7614, 0xAF8A, 0x7616, 0xAF8B, 0x761A, 0xAF8C, 0x761C, 0xAF8D, 0x761D, 0xAF8E, 0x761E, 0xAF8F, 0x7621, 0xAF90, 0x7623, 0xAF91, 0x7627, 0xAF92, 0x7628, 0xAF93, 0x762C, 0xAF94, 0x762E, 0xAF95, 0x762F, 0xAF96, 0x7631, 0xAF97, 0x7632, 0xAF98, 0x7636, 0xAF99, 0x7637, 0xAF9A, 0x7639, 0xAF9B, 0x763A, 0xAF9C, 0x763B, 0xAF9D, 0x763D, 0xAF9E, 0x7641, 0xAF9F, 0x7642, 0xAFA0, 0x7644, 0xB040, 0x7645, 0xB041, 0x7646, 0xB042, 0x7647, 0xB043, 0x7648, 0xB044, 0x7649, 0xB045, 0x764A, 0xB046, 0x764B, 0xB047, 0x764E, 0xB048, 0x764F, 0xB049, 0x7650, 0xB04A, 0x7651, 0xB04B, 0x7652, 0xB04C, 0x7653, 0xB04D, 0x7655, 0xB04E, 0x7657, 0xB04F, 0x7658, 0xB050, 0x7659, 0xB051, 0x765A, 0xB052, 0x765B, 0xB053, 0x765D, 0xB054, 0x765F, 0xB055, 0x7660, 0xB056, 0x7661, 0xB057, 0x7662, 0xB058, 0x7664, 0xB059, 0x7665, 0xB05A, 0x7666, 0xB05B, 0x7667, 0xB05C, 0x7668, 0xB05D, 0x7669, 0xB05E, 0x766A, 0xB05F, 0x766C, 0xB060, 0x766D, 0xB061, 0x766E, 0xB062, 0x7670, 0xB063, 0x7671, 0xB064, 0x7672, 0xB065, 0x7673, 0xB066, 0x7674, 0xB067, 0x7675, 0xB068, 0x7676, 0xB069, 0x7677, 0xB06A, 0x7679, 0xB06B, 0x767A, 0xB06C, 0x767C, 0xB06D, 0x767F, 0xB06E, 0x7680, 0xB06F, 0x7681, 0xB070, 0x7683, 0xB071, 0x7685, 0xB072, 0x7689, 0xB073, 0x768A, 0xB074, 0x768C, 0xB075, 0x768D, 0xB076, 0x768F, 0xB077, 0x7690, 0xB078, 0x7692, 0xB079, 0x7694, 0xB07A, 0x7695, 0xB07B, 0x7697, 0xB07C, 0x7698, 0xB07D, 0x769A, 0xB07E, 0x769B, 0xB080, 0x769C, 0xB081, 0x769D, 0xB082, 0x769E, 0xB083, 0x769F, 0xB084, 0x76A0, 0xB085, 0x76A1, 0xB086, 0x76A2, 0xB087, 0x76A3, 0xB088, 0x76A5, 0xB089, 0x76A6, 0xB08A, 0x76A7, 0xB08B, 0x76A8, 0xB08C, 0x76A9, 0xB08D, 0x76AA, 0xB08E, 0x76AB, 0xB08F, 0x76AC, 0xB090, 0x76AD, 0xB091, 0x76AF, 0xB092, 0x76B0, 0xB093, 0x76B3, 0xB094, 0x76B5, 0xB095, 0x76B6, 0xB096, 0x76B7, 0xB097, 0x76B8, 0xB098, 0x76B9, 0xB099, 0x76BA, 0xB09A, 0x76BB, 0xB09B, 0x76BC, 0xB09C, 0x76BD, 0xB09D, 0x76BE, 0xB09E, 0x76C0, 0xB09F, 0x76C1, 0xB0A0, 0x76C3, 0xB0A1, 0x554A, 0xB0A2, 0x963F, 0xB0A3, 0x57C3, 0xB0A4, 0x6328, 0xB0A5, 0x54CE, 0xB0A6, 0x5509, 0xB0A7, 0x54C0, 0xB0A8, 0x7691, 0xB0A9, 0x764C, 0xB0AA, 0x853C, 0xB0AB, 0x77EE, 0xB0AC, 0x827E, 0xB0AD, 0x788D, 0xB0AE, 0x7231, 0xB0AF, 0x9698, 0xB0B0, 0x978D, 0xB0B1, 0x6C28, 0xB0B2, 0x5B89, 0xB0B3, 0x4FFA, 0xB0B4, 0x6309, 0xB0B5, 0x6697, 0xB0B6, 0x5CB8, 0xB0B7, 0x80FA, 0xB0B8, 0x6848, 0xB0B9, 0x80AE, 0xB0BA, 0x6602, 0xB0BB, 0x76CE, 0xB0BC, 0x51F9, 0xB0BD, 0x6556, 0xB0BE, 0x71AC, 0xB0BF, 0x7FF1, 0xB0C0, 0x8884, 0xB0C1, 0x50B2, 0xB0C2, 0x5965, 0xB0C3, 0x61CA, 0xB0C4, 0x6FB3, 0xB0C5, 0x82AD, 0xB0C6, 0x634C, 0xB0C7, 0x6252, 0xB0C8, 0x53ED, 0xB0C9, 0x5427, 0xB0CA, 0x7B06, 0xB0CB, 0x516B, 0xB0CC, 0x75A4, 0xB0CD, 0x5DF4, 0xB0CE, 0x62D4, 0xB0CF, 0x8DCB, 0xB0D0, 0x9776, 0xB0D1, 0x628A, 0xB0D2, 0x8019, 0xB0D3, 0x575D, 0xB0D4, 0x9738, 0xB0D5, 0x7F62, 0xB0D6, 0x7238, 0xB0D7, 0x767D, 0xB0D8, 0x67CF, 0xB0D9, 0x767E, 0xB0DA, 0x6446, 0xB0DB, 0x4F70, 0xB0DC, 0x8D25, 0xB0DD, 0x62DC, 0xB0DE, 0x7A17, 0xB0DF, 0x6591, 0xB0E0, 0x73ED, 0xB0E1, 0x642C, 0xB0E2, 0x6273, 0xB0E3, 0x822C, 0xB0E4, 0x9881, 0xB0E5, 0x677F, 0xB0E6, 0x7248, 0xB0E7, 0x626E, 0xB0E8, 0x62CC, 0xB0E9, 0x4F34, 0xB0EA, 0x74E3, 0xB0EB, 0x534A, 0xB0EC, 0x529E, 0xB0ED, 0x7ECA, 0xB0EE, 0x90A6, 0xB0EF, 0x5E2E, 0xB0F0, 0x6886, 0xB0F1, 0x699C, 0xB0F2, 0x8180, 0xB0F3, 0x7ED1, 0xB0F4, 0x68D2, 0xB0F5, 0x78C5, 0xB0F6, 0x868C, 0xB0F7, 0x9551, 0xB0F8, 0x508D, 0xB0F9, 0x8C24, 0xB0FA, 0x82DE, 0xB0FB, 0x80DE, 0xB0FC, 0x5305, 0xB0FD, 0x8912, 0xB0FE, 0x5265, 0xB140, 0x76C4, 0xB141, 0x76C7, 0xB142, 0x76C9, 0xB143, 0x76CB, 0xB144, 0x76CC, 0xB145, 0x76D3, 0xB146, 0x76D5, 0xB147, 0x76D9, 0xB148, 0x76DA, 0xB149, 0x76DC, 0xB14A, 0x76DD, 0xB14B, 0x76DE, 0xB14C, 0x76E0, 0xB14D, 0x76E1, 0xB14E, 0x76E2, 0xB14F, 0x76E3, 0xB150, 0x76E4, 0xB151, 0x76E6, 0xB152, 0x76E7, 0xB153, 0x76E8, 0xB154, 0x76E9, 0xB155, 0x76EA, 0xB156, 0x76EB, 0xB157, 0x76EC, 0xB158, 0x76ED, 0xB159, 0x76F0, 0xB15A, 0x76F3, 0xB15B, 0x76F5, 0xB15C, 0x76F6, 0xB15D, 0x76F7, 0xB15E, 0x76FA, 0xB15F, 0x76FB, 0xB160, 0x76FD, 0xB161, 0x76FF, 0xB162, 0x7700, 0xB163, 0x7702, 0xB164, 0x7703, 0xB165, 0x7705, 0xB166, 0x7706, 0xB167, 0x770A, 0xB168, 0x770C, 0xB169, 0x770E, 0xB16A, 0x770F, 0xB16B, 0x7710, 0xB16C, 0x7711, 0xB16D, 0x7712, 0xB16E, 0x7713, 0xB16F, 0x7714, 0xB170, 0x7715, 0xB171, 0x7716, 0xB172, 0x7717, 0xB173, 0x7718, 0xB174, 0x771B, 0xB175, 0x771C, 0xB176, 0x771D, 0xB177, 0x771E, 0xB178, 0x7721, 0xB179, 0x7723, 0xB17A, 0x7724, 0xB17B, 0x7725, 0xB17C, 0x7727, 0xB17D, 0x772A, 0xB17E, 0x772B, 0xB180, 0x772C, 0xB181, 0x772E, 0xB182, 0x7730, 0xB183, 0x7731, 0xB184, 0x7732, 0xB185, 0x7733, 0xB186, 0x7734, 0xB187, 0x7739, 0xB188, 0x773B, 0xB189, 0x773D, 0xB18A, 0x773E, 0xB18B, 0x773F, 0xB18C, 0x7742, 0xB18D, 0x7744, 0xB18E, 0x7745, 0xB18F, 0x7746, 0xB190, 0x7748, 0xB191, 0x7749, 0xB192, 0x774A, 0xB193, 0x774B, 0xB194, 0x774C, 0xB195, 0x774D, 0xB196, 0x774E, 0xB197, 0x774F, 0xB198, 0x7752, 0xB199, 0x7753, 0xB19A, 0x7754, 0xB19B, 0x7755, 0xB19C, 0x7756, 0xB19D, 0x7757, 0xB19E, 0x7758, 0xB19F, 0x7759, 0xB1A0, 0x775C, 0xB1A1, 0x8584, 0xB1A2, 0x96F9, 0xB1A3, 0x4FDD, 0xB1A4, 0x5821, 0xB1A5, 0x9971, 0xB1A6, 0x5B9D, 0xB1A7, 0x62B1, 0xB1A8, 0x62A5, 0xB1A9, 0x66B4, 0xB1AA, 0x8C79, 0xB1AB, 0x9C8D, 0xB1AC, 0x7206, 0xB1AD, 0x676F, 0xB1AE, 0x7891, 0xB1AF, 0x60B2, 0xB1B0, 0x5351, 0xB1B1, 0x5317, 0xB1B2, 0x8F88, 0xB1B3, 0x80CC, 0xB1B4, 0x8D1D, 0xB1B5, 0x94A1, 0xB1B6, 0x500D, 0xB1B7, 0x72C8, 0xB1B8, 0x5907, 0xB1B9, 0x60EB, 0xB1BA, 0x7119, 0xB1BB, 0x88AB, 0xB1BC, 0x5954, 0xB1BD, 0x82EF, 0xB1BE, 0x672C, 0xB1BF, 0x7B28, 0xB1C0, 0x5D29, 0xB1C1, 0x7EF7, 0xB1C2, 0x752D, 0xB1C3, 0x6CF5, 0xB1C4, 0x8E66, 0xB1C5, 0x8FF8, 0xB1C6, 0x903C, 0xB1C7, 0x9F3B, 0xB1C8, 0x6BD4, 0xB1C9, 0x9119, 0xB1CA, 0x7B14, 0xB1CB, 0x5F7C, 0xB1CC, 0x78A7, 0xB1CD, 0x84D6, 0xB1CE, 0x853D, 0xB1CF, 0x6BD5, 0xB1D0, 0x6BD9, 0xB1D1, 0x6BD6, 0xB1D2, 0x5E01, 0xB1D3, 0x5E87, 0xB1D4, 0x75F9, 0xB1D5, 0x95ED, 0xB1D6, 0x655D, 0xB1D7, 0x5F0A, 0xB1D8, 0x5FC5, 0xB1D9, 0x8F9F, 0xB1DA, 0x58C1, 0xB1DB, 0x81C2, 0xB1DC, 0x907F, 0xB1DD, 0x965B, 0xB1DE, 0x97AD, 0xB1DF, 0x8FB9, 0xB1E0, 0x7F16, 0xB1E1, 0x8D2C, 0xB1E2, 0x6241, 0xB1E3, 0x4FBF, 0xB1E4, 0x53D8, 0xB1E5, 0x535E, 0xB1E6, 0x8FA8, 0xB1E7, 0x8FA9, 0xB1E8, 0x8FAB, 0xB1E9, 0x904D, 0xB1EA, 0x6807, 0xB1EB, 0x5F6A, 0xB1EC, 0x8198, 0xB1ED, 0x8868, 0xB1EE, 0x9CD6, 0xB1EF, 0x618B, 0xB1F0, 0x522B, 0xB1F1, 0x762A, 0xB1F2, 0x5F6C, 0xB1F3, 0x658C, 0xB1F4, 0x6FD2, 0xB1F5, 0x6EE8, 0xB1F6, 0x5BBE, 0xB1F7, 0x6448, 0xB1F8, 0x5175, 0xB1F9, 0x51B0, 0xB1FA, 0x67C4, 0xB1FB, 0x4E19, 0xB1FC, 0x79C9, 0xB1FD, 0x997C, 0xB1FE, 0x70B3, 0xB240, 0x775D, 0xB241, 0x775E, 0xB242, 0x775F, 0xB243, 0x7760, 0xB244, 0x7764, 0xB245, 0x7767, 0xB246, 0x7769, 0xB247, 0x776A, 0xB248, 0x776D, 0xB249, 0x776E, 0xB24A, 0x776F, 0xB24B, 0x7770, 0xB24C, 0x7771, 0xB24D, 0x7772, 0xB24E, 0x7773, 0xB24F, 0x7774, 0xB250, 0x7775, 0xB251, 0x7776, 0xB252, 0x7777, 0xB253, 0x7778, 0xB254, 0x777A, 0xB255, 0x777B, 0xB256, 0x777C, 0xB257, 0x7781, 0xB258, 0x7782, 0xB259, 0x7783, 0xB25A, 0x7786, 0xB25B, 0x7787, 0xB25C, 0x7788, 0xB25D, 0x7789, 0xB25E, 0x778A, 0xB25F, 0x778B, 0xB260, 0x778F, 0xB261, 0x7790, 0xB262, 0x7793, 0xB263, 0x7794, 0xB264, 0x7795, 0xB265, 0x7796, 0xB266, 0x7797, 0xB267, 0x7798, 0xB268, 0x7799, 0xB269, 0x779A, 0xB26A, 0x779B, 0xB26B, 0x779C, 0xB26C, 0x779D, 0xB26D, 0x779E, 0xB26E, 0x77A1, 0xB26F, 0x77A3, 0xB270, 0x77A4, 0xB271, 0x77A6, 0xB272, 0x77A8, 0xB273, 0x77AB, 0xB274, 0x77AD, 0xB275, 0x77AE, 0xB276, 0x77AF, 0xB277, 0x77B1, 0xB278, 0x77B2, 0xB279, 0x77B4, 0xB27A, 0x77B6, 0xB27B, 0x77B7, 0xB27C, 0x77B8, 0xB27D, 0x77B9, 0xB27E, 0x77BA, 0xB280, 0x77BC, 0xB281, 0x77BE, 0xB282, 0x77C0, 0xB283, 0x77C1, 0xB284, 0x77C2, 0xB285, 0x77C3, 0xB286, 0x77C4, 0xB287, 0x77C5, 0xB288, 0x77C6, 0xB289, 0x77C7, 0xB28A, 0x77C8, 0xB28B, 0x77C9, 0xB28C, 0x77CA, 0xB28D, 0x77CB, 0xB28E, 0x77CC, 0xB28F, 0x77CE, 0xB290, 0x77CF, 0xB291, 0x77D0, 0xB292, 0x77D1, 0xB293, 0x77D2, 0xB294, 0x77D3, 0xB295, 0x77D4, 0xB296, 0x77D5, 0xB297, 0x77D6, 0xB298, 0x77D8, 0xB299, 0x77D9, 0xB29A, 0x77DA, 0xB29B, 0x77DD, 0xB29C, 0x77DE, 0xB29D, 0x77DF, 0xB29E, 0x77E0, 0xB29F, 0x77E1, 0xB2A0, 0x77E4, 0xB2A1, 0x75C5, 0xB2A2, 0x5E76, 0xB2A3, 0x73BB, 0xB2A4, 0x83E0, 0xB2A5, 0x64AD, 0xB2A6, 0x62E8, 0xB2A7, 0x94B5, 0xB2A8, 0x6CE2, 0xB2A9, 0x535A, 0xB2AA, 0x52C3, 0xB2AB, 0x640F, 0xB2AC, 0x94C2, 0xB2AD, 0x7B94, 0xB2AE, 0x4F2F, 0xB2AF, 0x5E1B, 0xB2B0, 0x8236, 0xB2B1, 0x8116, 0xB2B2, 0x818A, 0xB2B3, 0x6E24, 0xB2B4, 0x6CCA, 0xB2B5, 0x9A73, 0xB2B6, 0x6355, 0xB2B7, 0x535C, 0xB2B8, 0x54FA, 0xB2B9, 0x8865, 0xB2BA, 0x57E0, 0xB2BB, 0x4E0D, 0xB2BC, 0x5E03, 0xB2BD, 0x6B65, 0xB2BE, 0x7C3F, 0xB2BF, 0x90E8, 0xB2C0, 0x6016, 0xB2C1, 0x64E6, 0xB2C2, 0x731C, 0xB2C3, 0x88C1, 0xB2C4, 0x6750, 0xB2C5, 0x624D, 0xB2C6, 0x8D22, 0xB2C7, 0x776C, 0xB2C8, 0x8E29, 0xB2C9, 0x91C7, 0xB2CA, 0x5F69, 0xB2CB, 0x83DC, 0xB2CC, 0x8521, 0xB2CD, 0x9910, 0xB2CE, 0x53C2, 0xB2CF, 0x8695, 0xB2D0, 0x6B8B, 0xB2D1, 0x60ED, 0xB2D2, 0x60E8, 0xB2D3, 0x707F, 0xB2D4, 0x82CD, 0xB2D5, 0x8231, 0xB2D6, 0x4ED3, 0xB2D7, 0x6CA7, 0xB2D8, 0x85CF, 0xB2D9, 0x64CD, 0xB2DA, 0x7CD9, 0xB2DB, 0x69FD, 0xB2DC, 0x66F9, 0xB2DD, 0x8349, 0xB2DE, 0x5395, 0xB2DF, 0x7B56, 0xB2E0, 0x4FA7, 0xB2E1, 0x518C, 0xB2E2, 0x6D4B, 0xB2E3, 0x5C42, 0xB2E4, 0x8E6D, 0xB2E5, 0x63D2, 0xB2E6, 0x53C9, 0xB2E7, 0x832C, 0xB2E8, 0x8336, 0xB2E9, 0x67E5, 0xB2EA, 0x78B4, 0xB2EB, 0x643D, 0xB2EC, 0x5BDF, 0xB2ED, 0x5C94, 0xB2EE, 0x5DEE, 0xB2EF, 0x8BE7, 0xB2F0, 0x62C6, 0xB2F1, 0x67F4, 0xB2F2, 0x8C7A, 0xB2F3, 0x6400, 0xB2F4, 0x63BA, 0xB2F5, 0x8749, 0xB2F6, 0x998B, 0xB2F7, 0x8C17, 0xB2F8, 0x7F20, 0xB2F9, 0x94F2, 0xB2FA, 0x4EA7, 0xB2FB, 0x9610, 0xB2FC, 0x98A4, 0xB2FD, 0x660C, 0xB2FE, 0x7316, 0xB340, 0x77E6, 0xB341, 0x77E8, 0xB342, 0x77EA, 0xB343, 0x77EF, 0xB344, 0x77F0, 0xB345, 0x77F1, 0xB346, 0x77F2, 0xB347, 0x77F4, 0xB348, 0x77F5, 0xB349, 0x77F7, 0xB34A, 0x77F9, 0xB34B, 0x77FA, 0xB34C, 0x77FB, 0xB34D, 0x77FC, 0xB34E, 0x7803, 0xB34F, 0x7804, 0xB350, 0x7805, 0xB351, 0x7806, 0xB352, 0x7807, 0xB353, 0x7808, 0xB354, 0x780A, 0xB355, 0x780B, 0xB356, 0x780E, 0xB357, 0x780F, 0xB358, 0x7810, 0xB359, 0x7813, 0xB35A, 0x7815, 0xB35B, 0x7819, 0xB35C, 0x781B, 0xB35D, 0x781E, 0xB35E, 0x7820, 0xB35F, 0x7821, 0xB360, 0x7822, 0xB361, 0x7824, 0xB362, 0x7828, 0xB363, 0x782A, 0xB364, 0x782B, 0xB365, 0x782E, 0xB366, 0x782F, 0xB367, 0x7831, 0xB368, 0x7832, 0xB369, 0x7833, 0xB36A, 0x7835, 0xB36B, 0x7836, 0xB36C, 0x783D, 0xB36D, 0x783F, 0xB36E, 0x7841, 0xB36F, 0x7842, 0xB370, 0x7843, 0xB371, 0x7844, 0xB372, 0x7846, 0xB373, 0x7848, 0xB374, 0x7849, 0xB375, 0x784A, 0xB376, 0x784B, 0xB377, 0x784D, 0xB378, 0x784F, 0xB379, 0x7851, 0xB37A, 0x7853, 0xB37B, 0x7854, 0xB37C, 0x7858, 0xB37D, 0x7859, 0xB37E, 0x785A, 0xB380, 0x785B, 0xB381, 0x785C, 0xB382, 0x785E, 0xB383, 0x785F, 0xB384, 0x7860, 0xB385, 0x7861, 0xB386, 0x7862, 0xB387, 0x7863, 0xB388, 0x7864, 0xB389, 0x7865, 0xB38A, 0x7866, 0xB38B, 0x7867, 0xB38C, 0x7868, 0xB38D, 0x7869, 0xB38E, 0x786F, 0xB38F, 0x7870, 0xB390, 0x7871, 0xB391, 0x7872, 0xB392, 0x7873, 0xB393, 0x7874, 0xB394, 0x7875, 0xB395, 0x7876, 0xB396, 0x7878, 0xB397, 0x7879, 0xB398, 0x787A, 0xB399, 0x787B, 0xB39A, 0x787D, 0xB39B, 0x787E, 0xB39C, 0x787F, 0xB39D, 0x7880, 0xB39E, 0x7881, 0xB39F, 0x7882, 0xB3A0, 0x7883, 0xB3A1, 0x573A, 0xB3A2, 0x5C1D, 0xB3A3, 0x5E38, 0xB3A4, 0x957F, 0xB3A5, 0x507F, 0xB3A6, 0x80A0, 0xB3A7, 0x5382, 0xB3A8, 0x655E, 0xB3A9, 0x7545, 0xB3AA, 0x5531, 0xB3AB, 0x5021, 0xB3AC, 0x8D85, 0xB3AD, 0x6284, 0xB3AE, 0x949E, 0xB3AF, 0x671D, 0xB3B0, 0x5632, 0xB3B1, 0x6F6E, 0xB3B2, 0x5DE2, 0xB3B3, 0x5435, 0xB3B4, 0x7092, 0xB3B5, 0x8F66, 0xB3B6, 0x626F, 0xB3B7, 0x64A4, 0xB3B8, 0x63A3, 0xB3B9, 0x5F7B, 0xB3BA, 0x6F88, 0xB3BB, 0x90F4, 0xB3BC, 0x81E3, 0xB3BD, 0x8FB0, 0xB3BE, 0x5C18, 0xB3BF, 0x6668, 0xB3C0, 0x5FF1, 0xB3C1, 0x6C89, 0xB3C2, 0x9648, 0xB3C3, 0x8D81, 0xB3C4, 0x886C, 0xB3C5, 0x6491, 0xB3C6, 0x79F0, 0xB3C7, 0x57CE, 0xB3C8, 0x6A59, 0xB3C9, 0x6210, 0xB3CA, 0x5448, 0xB3CB, 0x4E58, 0xB3CC, 0x7A0B, 0xB3CD, 0x60E9, 0xB3CE, 0x6F84, 0xB3CF, 0x8BDA, 0xB3D0, 0x627F, 0xB3D1, 0x901E, 0xB3D2, 0x9A8B, 0xB3D3, 0x79E4, 0xB3D4, 0x5403, 0xB3D5, 0x75F4, 0xB3D6, 0x6301, 0xB3D7, 0x5319, 0xB3D8, 0x6C60, 0xB3D9, 0x8FDF, 0xB3DA, 0x5F1B, 0xB3DB, 0x9A70, 0xB3DC, 0x803B, 0xB3DD, 0x9F7F, 0xB3DE, 0x4F88, 0xB3DF, 0x5C3A, 0xB3E0, 0x8D64, 0xB3E1, 0x7FC5, 0xB3E2, 0x65A5, 0xB3E3, 0x70BD, 0xB3E4, 0x5145, 0xB3E5, 0x51B2, 0xB3E6, 0x866B, 0xB3E7, 0x5D07, 0xB3E8, 0x5BA0, 0xB3E9, 0x62BD, 0xB3EA, 0x916C, 0xB3EB, 0x7574, 0xB3EC, 0x8E0C, 0xB3ED, 0x7A20, 0xB3EE, 0x6101, 0xB3EF, 0x7B79, 0xB3F0, 0x4EC7, 0xB3F1, 0x7EF8, 0xB3F2, 0x7785, 0xB3F3, 0x4E11, 0xB3F4, 0x81ED, 0xB3F5, 0x521D, 0xB3F6, 0x51FA, 0xB3F7, 0x6A71, 0xB3F8, 0x53A8, 0xB3F9, 0x8E87, 0xB3FA, 0x9504, 0xB3FB, 0x96CF, 0xB3FC, 0x6EC1, 0xB3FD, 0x9664, 0xB3FE, 0x695A, 0xB440, 0x7884, 0xB441, 0x7885, 0xB442, 0x7886, 0xB443, 0x7888, 0xB444, 0x788A, 0xB445, 0x788B, 0xB446, 0x788F, 0xB447, 0x7890, 0xB448, 0x7892, 0xB449, 0x7894, 0xB44A, 0x7895, 0xB44B, 0x7896, 0xB44C, 0x7899, 0xB44D, 0x789D, 0xB44E, 0x789E, 0xB44F, 0x78A0, 0xB450, 0x78A2, 0xB451, 0x78A4, 0xB452, 0x78A6, 0xB453, 0x78A8, 0xB454, 0x78A9, 0xB455, 0x78AA, 0xB456, 0x78AB, 0xB457, 0x78AC, 0xB458, 0x78AD, 0xB459, 0x78AE, 0xB45A, 0x78AF, 0xB45B, 0x78B5, 0xB45C, 0x78B6, 0xB45D, 0x78B7, 0xB45E, 0x78B8, 0xB45F, 0x78BA, 0xB460, 0x78BB, 0xB461, 0x78BC, 0xB462, 0x78BD, 0xB463, 0x78BF, 0xB464, 0x78C0, 0xB465, 0x78C2, 0xB466, 0x78C3, 0xB467, 0x78C4, 0xB468, 0x78C6, 0xB469, 0x78C7, 0xB46A, 0x78C8, 0xB46B, 0x78CC, 0xB46C, 0x78CD, 0xB46D, 0x78CE, 0xB46E, 0x78CF, 0xB46F, 0x78D1, 0xB470, 0x78D2, 0xB471, 0x78D3, 0xB472, 0x78D6, 0xB473, 0x78D7, 0xB474, 0x78D8, 0xB475, 0x78DA, 0xB476, 0x78DB, 0xB477, 0x78DC, 0xB478, 0x78DD, 0xB479, 0x78DE, 0xB47A, 0x78DF, 0xB47B, 0x78E0, 0xB47C, 0x78E1, 0xB47D, 0x78E2, 0xB47E, 0x78E3, 0xB480, 0x78E4, 0xB481, 0x78E5, 0xB482, 0x78E6, 0xB483, 0x78E7, 0xB484, 0x78E9, 0xB485, 0x78EA, 0xB486, 0x78EB, 0xB487, 0x78ED, 0xB488, 0x78EE, 0xB489, 0x78EF, 0xB48A, 0x78F0, 0xB48B, 0x78F1, 0xB48C, 0x78F3, 0xB48D, 0x78F5, 0xB48E, 0x78F6, 0xB48F, 0x78F8, 0xB490, 0x78F9, 0xB491, 0x78FB, 0xB492, 0x78FC, 0xB493, 0x78FD, 0xB494, 0x78FE, 0xB495, 0x78FF, 0xB496, 0x7900, 0xB497, 0x7902, 0xB498, 0x7903, 0xB499, 0x7904, 0xB49A, 0x7906, 0xB49B, 0x7907, 0xB49C, 0x7908, 0xB49D, 0x7909, 0xB49E, 0x790A, 0xB49F, 0x790B, 0xB4A0, 0x790C, 0xB4A1, 0x7840, 0xB4A2, 0x50A8, 0xB4A3, 0x77D7, 0xB4A4, 0x6410, 0xB4A5, 0x89E6, 0xB4A6, 0x5904, 0xB4A7, 0x63E3, 0xB4A8, 0x5DDD, 0xB4A9, 0x7A7F, 0xB4AA, 0x693D, 0xB4AB, 0x4F20, 0xB4AC, 0x8239, 0xB4AD, 0x5598, 0xB4AE, 0x4E32, 0xB4AF, 0x75AE, 0xB4B0, 0x7A97, 0xB4B1, 0x5E62, 0xB4B2, 0x5E8A, 0xB4B3, 0x95EF, 0xB4B4, 0x521B, 0xB4B5, 0x5439, 0xB4B6, 0x708A, 0xB4B7, 0x6376, 0xB4B8, 0x9524, 0xB4B9, 0x5782, 0xB4BA, 0x6625, 0xB4BB, 0x693F, 0xB4BC, 0x9187, 0xB4BD, 0x5507, 0xB4BE, 0x6DF3, 0xB4BF, 0x7EAF, 0xB4C0, 0x8822, 0xB4C1, 0x6233, 0xB4C2, 0x7EF0, 0xB4C3, 0x75B5, 0xB4C4, 0x8328, 0xB4C5, 0x78C1, 0xB4C6, 0x96CC, 0xB4C7, 0x8F9E, 0xB4C8, 0x6148, 0xB4C9, 0x74F7, 0xB4CA, 0x8BCD, 0xB4CB, 0x6B64, 0xB4CC, 0x523A, 0xB4CD, 0x8D50, 0xB4CE, 0x6B21, 0xB4CF, 0x806A, 0xB4D0, 0x8471, 0xB4D1, 0x56F1, 0xB4D2, 0x5306, 0xB4D3, 0x4ECE, 0xB4D4, 0x4E1B, 0xB4D5, 0x51D1, 0xB4D6, 0x7C97, 0xB4D7, 0x918B, 0xB4D8, 0x7C07, 0xB4D9, 0x4FC3, 0xB4DA, 0x8E7F, 0xB4DB, 0x7BE1, 0xB4DC, 0x7A9C, 0xB4DD, 0x6467, 0xB4DE, 0x5D14, 0xB4DF, 0x50AC, 0xB4E0, 0x8106, 0xB4E1, 0x7601, 0xB4E2, 0x7CB9, 0xB4E3, 0x6DEC, 0xB4E4, 0x7FE0, 0xB4E5, 0x6751, 0xB4E6, 0x5B58, 0xB4E7, 0x5BF8, 0xB4E8, 0x78CB, 0xB4E9, 0x64AE, 0xB4EA, 0x6413, 0xB4EB, 0x63AA, 0xB4EC, 0x632B, 0xB4ED, 0x9519, 0xB4EE, 0x642D, 0xB4EF, 0x8FBE, 0xB4F0, 0x7B54, 0xB4F1, 0x7629, 0xB4F2, 0x6253, 0xB4F3, 0x5927, 0xB4F4, 0x5446, 0xB4F5, 0x6B79, 0xB4F6, 0x50A3, 0xB4F7, 0x6234, 0xB4F8, 0x5E26, 0xB4F9, 0x6B86, 0xB4FA, 0x4EE3, 0xB4FB, 0x8D37, 0xB4FC, 0x888B, 0xB4FD, 0x5F85, 0xB4FE, 0x902E, 0xB540, 0x790D, 0xB541, 0x790E, 0xB542, 0x790F, 0xB543, 0x7910, 0xB544, 0x7911, 0xB545, 0x7912, 0xB546, 0x7914, 0xB547, 0x7915, 0xB548, 0x7916, 0xB549, 0x7917, 0xB54A, 0x7918, 0xB54B, 0x7919, 0xB54C, 0x791A, 0xB54D, 0x791B, 0xB54E, 0x791C, 0xB54F, 0x791D, 0xB550, 0x791F, 0xB551, 0x7920, 0xB552, 0x7921, 0xB553, 0x7922, 0xB554, 0x7923, 0xB555, 0x7925, 0xB556, 0x7926, 0xB557, 0x7927, 0xB558, 0x7928, 0xB559, 0x7929, 0xB55A, 0x792A, 0xB55B, 0x792B, 0xB55C, 0x792C, 0xB55D, 0x792D, 0xB55E, 0x792E, 0xB55F, 0x792F, 0xB560, 0x7930, 0xB561, 0x7931, 0xB562, 0x7932, 0xB563, 0x7933, 0xB564, 0x7935, 0xB565, 0x7936, 0xB566, 0x7937, 0xB567, 0x7938, 0xB568, 0x7939, 0xB569, 0x793D, 0xB56A, 0x793F, 0xB56B, 0x7942, 0xB56C, 0x7943, 0xB56D, 0x7944, 0xB56E, 0x7945, 0xB56F, 0x7947, 0xB570, 0x794A, 0xB571, 0x794B, 0xB572, 0x794C, 0xB573, 0x794D, 0xB574, 0x794E, 0xB575, 0x794F, 0xB576, 0x7950, 0xB577, 0x7951, 0xB578, 0x7952, 0xB579, 0x7954, 0xB57A, 0x7955, 0xB57B, 0x7958, 0xB57C, 0x7959, 0xB57D, 0x7961, 0xB57E, 0x7963, 0xB580, 0x7964, 0xB581, 0x7966, 0xB582, 0x7969, 0xB583, 0x796A, 0xB584, 0x796B, 0xB585, 0x796C, 0xB586, 0x796E, 0xB587, 0x7970, 0xB588, 0x7971, 0xB589, 0x7972, 0xB58A, 0x7973, 0xB58B, 0x7974, 0xB58C, 0x7975, 0xB58D, 0x7976, 0xB58E, 0x7979, 0xB58F, 0x797B, 0xB590, 0x797C, 0xB591, 0x797D, 0xB592, 0x797E, 0xB593, 0x797F, 0xB594, 0x7982, 0xB595, 0x7983, 0xB596, 0x7986, 0xB597, 0x7987, 0xB598, 0x7988, 0xB599, 0x7989, 0xB59A, 0x798B, 0xB59B, 0x798C, 0xB59C, 0x798D, 0xB59D, 0x798E, 0xB59E, 0x7990, 0xB59F, 0x7991, 0xB5A0, 0x7992, 0xB5A1, 0x6020, 0xB5A2, 0x803D, 0xB5A3, 0x62C5, 0xB5A4, 0x4E39, 0xB5A5, 0x5355, 0xB5A6, 0x90F8, 0xB5A7, 0x63B8, 0xB5A8, 0x80C6, 0xB5A9, 0x65E6, 0xB5AA, 0x6C2E, 0xB5AB, 0x4F46, 0xB5AC, 0x60EE, 0xB5AD, 0x6DE1, 0xB5AE, 0x8BDE, 0xB5AF, 0x5F39, 0xB5B0, 0x86CB, 0xB5B1, 0x5F53, 0xB5B2, 0x6321, 0xB5B3, 0x515A, 0xB5B4, 0x8361, 0xB5B5, 0x6863, 0xB5B6, 0x5200, 0xB5B7, 0x6363, 0xB5B8, 0x8E48, 0xB5B9, 0x5012, 0xB5BA, 0x5C9B, 0xB5BB, 0x7977, 0xB5BC, 0x5BFC, 0xB5BD, 0x5230, 0xB5BE, 0x7A3B, 0xB5BF, 0x60BC, 0xB5C0, 0x9053, 0xB5C1, 0x76D7, 0xB5C2, 0x5FB7, 0xB5C3, 0x5F97, 0xB5C4, 0x7684, 0xB5C5, 0x8E6C, 0xB5C6, 0x706F, 0xB5C7, 0x767B, 0xB5C8, 0x7B49, 0xB5C9, 0x77AA, 0xB5CA, 0x51F3, 0xB5CB, 0x9093, 0xB5CC, 0x5824, 0xB5CD, 0x4F4E, 0xB5CE, 0x6EF4, 0xB5CF, 0x8FEA, 0xB5D0, 0x654C, 0xB5D1, 0x7B1B, 0xB5D2, 0x72C4, 0xB5D3, 0x6DA4, 0xB5D4, 0x7FDF, 0xB5D5, 0x5AE1, 0xB5D6, 0x62B5, 0xB5D7, 0x5E95, 0xB5D8, 0x5730, 0xB5D9, 0x8482, 0xB5DA, 0x7B2C, 0xB5DB, 0x5E1D, 0xB5DC, 0x5F1F, 0xB5DD, 0x9012, 0xB5DE, 0x7F14, 0xB5DF, 0x98A0, 0xB5E0, 0x6382, 0xB5E1, 0x6EC7, 0xB5E2, 0x7898, 0xB5E3, 0x70B9, 0xB5E4, 0x5178, 0xB5E5, 0x975B, 0xB5E6, 0x57AB, 0xB5E7, 0x7535, 0xB5E8, 0x4F43, 0xB5E9, 0x7538, 0xB5EA, 0x5E97, 0xB5EB, 0x60E6, 0xB5EC, 0x5960, 0xB5ED, 0x6DC0, 0xB5EE, 0x6BBF, 0xB5EF, 0x7889, 0xB5F0, 0x53FC, 0xB5F1, 0x96D5, 0xB5F2, 0x51CB, 0xB5F3, 0x5201, 0xB5F4, 0x6389, 0xB5F5, 0x540A, 0xB5F6, 0x9493, 0xB5F7, 0x8C03, 0xB5F8, 0x8DCC, 0xB5F9, 0x7239, 0xB5FA, 0x789F, 0xB5FB, 0x8776, 0xB5FC, 0x8FED, 0xB5FD, 0x8C0D, 0xB5FE, 0x53E0, 0xB640, 0x7993, 0xB641, 0x7994, 0xB642, 0x7995, 0xB643, 0x7996, 0xB644, 0x7997, 0xB645, 0x7998, 0xB646, 0x7999, 0xB647, 0x799B, 0xB648, 0x799C, 0xB649, 0x799D, 0xB64A, 0x799E, 0xB64B, 0x799F, 0xB64C, 0x79A0, 0xB64D, 0x79A1, 0xB64E, 0x79A2, 0xB64F, 0x79A3, 0xB650, 0x79A4, 0xB651, 0x79A5, 0xB652, 0x79A6, 0xB653, 0x79A8, 0xB654, 0x79A9, 0xB655, 0x79AA, 0xB656, 0x79AB, 0xB657, 0x79AC, 0xB658, 0x79AD, 0xB659, 0x79AE, 0xB65A, 0x79AF, 0xB65B, 0x79B0, 0xB65C, 0x79B1, 0xB65D, 0x79B2, 0xB65E, 0x79B4, 0xB65F, 0x79B5, 0xB660, 0x79B6, 0xB661, 0x79B7, 0xB662, 0x79B8, 0xB663, 0x79BC, 0xB664, 0x79BF, 0xB665, 0x79C2, 0xB666, 0x79C4, 0xB667, 0x79C5, 0xB668, 0x79C7, 0xB669, 0x79C8, 0xB66A, 0x79CA, 0xB66B, 0x79CC, 0xB66C, 0x79CE, 0xB66D, 0x79CF, 0xB66E, 0x79D0, 0xB66F, 0x79D3, 0xB670, 0x79D4, 0xB671, 0x79D6, 0xB672, 0x79D7, 0xB673, 0x79D9, 0xB674, 0x79DA, 0xB675, 0x79DB, 0xB676, 0x79DC, 0xB677, 0x79DD, 0xB678, 0x79DE, 0xB679, 0x79E0, 0xB67A, 0x79E1, 0xB67B, 0x79E2, 0xB67C, 0x79E5, 0xB67D, 0x79E8, 0xB67E, 0x79EA, 0xB680, 0x79EC, 0xB681, 0x79EE, 0xB682, 0x79F1, 0xB683, 0x79F2, 0xB684, 0x79F3, 0xB685, 0x79F4, 0xB686, 0x79F5, 0xB687, 0x79F6, 0xB688, 0x79F7, 0xB689, 0x79F9, 0xB68A, 0x79FA, 0xB68B, 0x79FC, 0xB68C, 0x79FE, 0xB68D, 0x79FF, 0xB68E, 0x7A01, 0xB68F, 0x7A04, 0xB690, 0x7A05, 0xB691, 0x7A07, 0xB692, 0x7A08, 0xB693, 0x7A09, 0xB694, 0x7A0A, 0xB695, 0x7A0C, 0xB696, 0x7A0F, 0xB697, 0x7A10, 0xB698, 0x7A11, 0xB699, 0x7A12, 0xB69A, 0x7A13, 0xB69B, 0x7A15, 0xB69C, 0x7A16, 0xB69D, 0x7A18, 0xB69E, 0x7A19, 0xB69F, 0x7A1B, 0xB6A0, 0x7A1C, 0xB6A1, 0x4E01, 0xB6A2, 0x76EF, 0xB6A3, 0x53EE, 0xB6A4, 0x9489, 0xB6A5, 0x9876, 0xB6A6, 0x9F0E, 0xB6A7, 0x952D, 0xB6A8, 0x5B9A, 0xB6A9, 0x8BA2, 0xB6AA, 0x4E22, 0xB6AB, 0x4E1C, 0xB6AC, 0x51AC, 0xB6AD, 0x8463, 0xB6AE, 0x61C2, 0xB6AF, 0x52A8, 0xB6B0, 0x680B, 0xB6B1, 0x4F97, 0xB6B2, 0x606B, 0xB6B3, 0x51BB, 0xB6B4, 0x6D1E, 0xB6B5, 0x515C, 0xB6B6, 0x6296, 0xB6B7, 0x6597, 0xB6B8, 0x9661, 0xB6B9, 0x8C46, 0xB6BA, 0x9017, 0xB6BB, 0x75D8, 0xB6BC, 0x90FD, 0xB6BD, 0x7763, 0xB6BE, 0x6BD2, 0xB6BF, 0x728A, 0xB6C0, 0x72EC, 0xB6C1, 0x8BFB, 0xB6C2, 0x5835, 0xB6C3, 0x7779, 0xB6C4, 0x8D4C, 0xB6C5, 0x675C, 0xB6C6, 0x9540, 0xB6C7, 0x809A, 0xB6C8, 0x5EA6, 0xB6C9, 0x6E21, 0xB6CA, 0x5992, 0xB6CB, 0x7AEF, 0xB6CC, 0x77ED, 0xB6CD, 0x953B, 0xB6CE, 0x6BB5, 0xB6CF, 0x65AD, 0xB6D0, 0x7F0E, 0xB6D1, 0x5806, 0xB6D2, 0x5151, 0xB6D3, 0x961F, 0xB6D4, 0x5BF9, 0xB6D5, 0x58A9, 0xB6D6, 0x5428, 0xB6D7, 0x8E72, 0xB6D8, 0x6566, 0xB6D9, 0x987F, 0xB6DA, 0x56E4, 0xB6DB, 0x949D, 0xB6DC, 0x76FE, 0xB6DD, 0x9041, 0xB6DE, 0x6387, 0xB6DF, 0x54C6, 0xB6E0, 0x591A, 0xB6E1, 0x593A, 0xB6E2, 0x579B, 0xB6E3, 0x8EB2, 0xB6E4, 0x6735, 0xB6E5, 0x8DFA, 0xB6E6, 0x8235, 0xB6E7, 0x5241, 0xB6E8, 0x60F0, 0xB6E9, 0x5815, 0xB6EA, 0x86FE, 0xB6EB, 0x5CE8, 0xB6EC, 0x9E45, 0xB6ED, 0x4FC4, 0xB6EE, 0x989D, 0xB6EF, 0x8BB9, 0xB6F0, 0x5A25, 0xB6F1, 0x6076, 0xB6F2, 0x5384, 0xB6F3, 0x627C, 0xB6F4, 0x904F, 0xB6F5, 0x9102, 0xB6F6, 0x997F, 0xB6F7, 0x6069, 0xB6F8, 0x800C, 0xB6F9, 0x513F, 0xB6FA, 0x8033, 0xB6FB, 0x5C14, 0xB6FC, 0x9975, 0xB6FD, 0x6D31, 0xB6FE, 0x4E8C, 0xB740, 0x7A1D, 0xB741, 0x7A1F, 0xB742, 0x7A21, 0xB743, 0x7A22, 0xB744, 0x7A24, 0xB745, 0x7A25, 0xB746, 0x7A26, 0xB747, 0x7A27, 0xB748, 0x7A28, 0xB749, 0x7A29, 0xB74A, 0x7A2A, 0xB74B, 0x7A2B, 0xB74C, 0x7A2C, 0xB74D, 0x7A2D, 0xB74E, 0x7A2E, 0xB74F, 0x7A2F, 0xB750, 0x7A30, 0xB751, 0x7A31, 0xB752, 0x7A32, 0xB753, 0x7A34, 0xB754, 0x7A35, 0xB755, 0x7A36, 0xB756, 0x7A38, 0xB757, 0x7A3A, 0xB758, 0x7A3E, 0xB759, 0x7A40, 0xB75A, 0x7A41, 0xB75B, 0x7A42, 0xB75C, 0x7A43, 0xB75D, 0x7A44, 0xB75E, 0x7A45, 0xB75F, 0x7A47, 0xB760, 0x7A48, 0xB761, 0x7A49, 0xB762, 0x7A4A, 0xB763, 0x7A4B, 0xB764, 0x7A4C, 0xB765, 0x7A4D, 0xB766, 0x7A4E, 0xB767, 0x7A4F, 0xB768, 0x7A50, 0xB769, 0x7A52, 0xB76A, 0x7A53, 0xB76B, 0x7A54, 0xB76C, 0x7A55, 0xB76D, 0x7A56, 0xB76E, 0x7A58, 0xB76F, 0x7A59, 0xB770, 0x7A5A, 0xB771, 0x7A5B, 0xB772, 0x7A5C, 0xB773, 0x7A5D, 0xB774, 0x7A5E, 0xB775, 0x7A5F, 0xB776, 0x7A60, 0xB777, 0x7A61, 0xB778, 0x7A62, 0xB779, 0x7A63, 0xB77A, 0x7A64, 0xB77B, 0x7A65, 0xB77C, 0x7A66, 0xB77D, 0x7A67, 0xB77E, 0x7A68, 0xB780, 0x7A69, 0xB781, 0x7A6A, 0xB782, 0x7A6B, 0xB783, 0x7A6C, 0xB784, 0x7A6D, 0xB785, 0x7A6E, 0xB786, 0x7A6F, 0xB787, 0x7A71, 0xB788, 0x7A72, 0xB789, 0x7A73, 0xB78A, 0x7A75, 0xB78B, 0x7A7B, 0xB78C, 0x7A7C, 0xB78D, 0x7A7D, 0xB78E, 0x7A7E, 0xB78F, 0x7A82, 0xB790, 0x7A85, 0xB791, 0x7A87, 0xB792, 0x7A89, 0xB793, 0x7A8A, 0xB794, 0x7A8B, 0xB795, 0x7A8C, 0xB796, 0x7A8E, 0xB797, 0x7A8F, 0xB798, 0x7A90, 0xB799, 0x7A93, 0xB79A, 0x7A94, 0xB79B, 0x7A99, 0xB79C, 0x7A9A, 0xB79D, 0x7A9B, 0xB79E, 0x7A9E, 0xB79F, 0x7AA1, 0xB7A0, 0x7AA2, 0xB7A1, 0x8D30, 0xB7A2, 0x53D1, 0xB7A3, 0x7F5A, 0xB7A4, 0x7B4F, 0xB7A5, 0x4F10, 0xB7A6, 0x4E4F, 0xB7A7, 0x9600, 0xB7A8, 0x6CD5, 0xB7A9, 0x73D0, 0xB7AA, 0x85E9, 0xB7AB, 0x5E06, 0xB7AC, 0x756A, 0xB7AD, 0x7FFB, 0xB7AE, 0x6A0A, 0xB7AF, 0x77FE, 0xB7B0, 0x9492, 0xB7B1, 0x7E41, 0xB7B2, 0x51E1, 0xB7B3, 0x70E6, 0xB7B4, 0x53CD, 0xB7B5, 0x8FD4, 0xB7B6, 0x8303, 0xB7B7, 0x8D29, 0xB7B8, 0x72AF, 0xB7B9, 0x996D, 0xB7BA, 0x6CDB, 0xB7BB, 0x574A, 0xB7BC, 0x82B3, 0xB7BD, 0x65B9, 0xB7BE, 0x80AA, 0xB7BF, 0x623F, 0xB7C0, 0x9632, 0xB7C1, 0x59A8, 0xB7C2, 0x4EFF, 0xB7C3, 0x8BBF, 0xB7C4, 0x7EBA, 0xB7C5, 0x653E, 0xB7C6, 0x83F2, 0xB7C7, 0x975E, 0xB7C8, 0x5561, 0xB7C9, 0x98DE, 0xB7CA, 0x80A5, 0xB7CB, 0x532A, 0xB7CC, 0x8BFD, 0xB7CD, 0x5420, 0xB7CE, 0x80BA, 0xB7CF, 0x5E9F, 0xB7D0, 0x6CB8, 0xB7D1, 0x8D39, 0xB7D2, 0x82AC, 0xB7D3, 0x915A, 0xB7D4, 0x5429, 0xB7D5, 0x6C1B, 0xB7D6, 0x5206, 0xB7D7, 0x7EB7, 0xB7D8, 0x575F, 0xB7D9, 0x711A, 0xB7DA, 0x6C7E, 0xB7DB, 0x7C89, 0xB7DC, 0x594B, 0xB7DD, 0x4EFD, 0xB7DE, 0x5FFF, 0xB7DF, 0x6124, 0xB7E0, 0x7CAA, 0xB7E1, 0x4E30, 0xB7E2, 0x5C01, 0xB7E3, 0x67AB, 0xB7E4, 0x8702, 0xB7E5, 0x5CF0, 0xB7E6, 0x950B, 0xB7E7, 0x98CE, 0xB7E8, 0x75AF, 0xB7E9, 0x70FD, 0xB7EA, 0x9022, 0xB7EB, 0x51AF, 0xB7EC, 0x7F1D, 0xB7ED, 0x8BBD, 0xB7EE, 0x5949, 0xB7EF, 0x51E4, 0xB7F0, 0x4F5B, 0xB7F1, 0x5426, 0xB7F2, 0x592B, 0xB7F3, 0x6577, 0xB7F4, 0x80A4, 0xB7F5, 0x5B75, 0xB7F6, 0x6276, 0xB7F7, 0x62C2, 0xB7F8, 0x8F90, 0xB7F9, 0x5E45, 0xB7FA, 0x6C1F, 0xB7FB, 0x7B26, 0xB7FC, 0x4F0F, 0xB7FD, 0x4FD8, 0xB7FE, 0x670D, 0xB840, 0x7AA3, 0xB841, 0x7AA4, 0xB842, 0x7AA7, 0xB843, 0x7AA9, 0xB844, 0x7AAA, 0xB845, 0x7AAB, 0xB846, 0x7AAE, 0xB847, 0x7AAF, 0xB848, 0x7AB0, 0xB849, 0x7AB1, 0xB84A, 0x7AB2, 0xB84B, 0x7AB4, 0xB84C, 0x7AB5, 0xB84D, 0x7AB6, 0xB84E, 0x7AB7, 0xB84F, 0x7AB8, 0xB850, 0x7AB9, 0xB851, 0x7ABA, 0xB852, 0x7ABB, 0xB853, 0x7ABC, 0xB854, 0x7ABD, 0xB855, 0x7ABE, 0xB856, 0x7AC0, 0xB857, 0x7AC1, 0xB858, 0x7AC2, 0xB859, 0x7AC3, 0xB85A, 0x7AC4, 0xB85B, 0x7AC5, 0xB85C, 0x7AC6, 0xB85D, 0x7AC7, 0xB85E, 0x7AC8, 0xB85F, 0x7AC9, 0xB860, 0x7ACA, 0xB861, 0x7ACC, 0xB862, 0x7ACD, 0xB863, 0x7ACE, 0xB864, 0x7ACF, 0xB865, 0x7AD0, 0xB866, 0x7AD1, 0xB867, 0x7AD2, 0xB868, 0x7AD3, 0xB869, 0x7AD4, 0xB86A, 0x7AD5, 0xB86B, 0x7AD7, 0xB86C, 0x7AD8, 0xB86D, 0x7ADA, 0xB86E, 0x7ADB, 0xB86F, 0x7ADC, 0xB870, 0x7ADD, 0xB871, 0x7AE1, 0xB872, 0x7AE2, 0xB873, 0x7AE4, 0xB874, 0x7AE7, 0xB875, 0x7AE8, 0xB876, 0x7AE9, 0xB877, 0x7AEA, 0xB878, 0x7AEB, 0xB879, 0x7AEC, 0xB87A, 0x7AEE, 0xB87B, 0x7AF0, 0xB87C, 0x7AF1, 0xB87D, 0x7AF2, 0xB87E, 0x7AF3, 0xB880, 0x7AF4, 0xB881, 0x7AF5, 0xB882, 0x7AF6, 0xB883, 0x7AF7, 0xB884, 0x7AF8, 0xB885, 0x7AFB, 0xB886, 0x7AFC, 0xB887, 0x7AFE, 0xB888, 0x7B00, 0xB889, 0x7B01, 0xB88A, 0x7B02, 0xB88B, 0x7B05, 0xB88C, 0x7B07, 0xB88D, 0x7B09, 0xB88E, 0x7B0C, 0xB88F, 0x7B0D, 0xB890, 0x7B0E, 0xB891, 0x7B10, 0xB892, 0x7B12, 0xB893, 0x7B13, 0xB894, 0x7B16, 0xB895, 0x7B17, 0xB896, 0x7B18, 0xB897, 0x7B1A, 0xB898, 0x7B1C, 0xB899, 0x7B1D, 0xB89A, 0x7B1F, 0xB89B, 0x7B21, 0xB89C, 0x7B22, 0xB89D, 0x7B23, 0xB89E, 0x7B27, 0xB89F, 0x7B29, 0xB8A0, 0x7B2D, 0xB8A1, 0x6D6E, 0xB8A2, 0x6DAA, 0xB8A3, 0x798F, 0xB8A4, 0x88B1, 0xB8A5, 0x5F17, 0xB8A6, 0x752B, 0xB8A7, 0x629A, 0xB8A8, 0x8F85, 0xB8A9, 0x4FEF, 0xB8AA, 0x91DC, 0xB8AB, 0x65A7, 0xB8AC, 0x812F, 0xB8AD, 0x8151, 0xB8AE, 0x5E9C, 0xB8AF, 0x8150, 0xB8B0, 0x8D74, 0xB8B1, 0x526F, 0xB8B2, 0x8986, 0xB8B3, 0x8D4B, 0xB8B4, 0x590D, 0xB8B5, 0x5085, 0xB8B6, 0x4ED8, 0xB8B7, 0x961C, 0xB8B8, 0x7236, 0xB8B9, 0x8179, 0xB8BA, 0x8D1F, 0xB8BB, 0x5BCC, 0xB8BC, 0x8BA3, 0xB8BD, 0x9644, 0xB8BE, 0x5987, 0xB8BF, 0x7F1A, 0xB8C0, 0x5490, 0xB8C1, 0x5676, 0xB8C2, 0x560E, 0xB8C3, 0x8BE5, 0xB8C4, 0x6539, 0xB8C5, 0x6982, 0xB8C6, 0x9499, 0xB8C7, 0x76D6, 0xB8C8, 0x6E89, 0xB8C9, 0x5E72, 0xB8CA, 0x7518, 0xB8CB, 0x6746, 0xB8CC, 0x67D1, 0xB8CD, 0x7AFF, 0xB8CE, 0x809D, 0xB8CF, 0x8D76, 0xB8D0, 0x611F, 0xB8D1, 0x79C6, 0xB8D2, 0x6562, 0xB8D3, 0x8D63, 0xB8D4, 0x5188, 0xB8D5, 0x521A, 0xB8D6, 0x94A2, 0xB8D7, 0x7F38, 0xB8D8, 0x809B, 0xB8D9, 0x7EB2, 0xB8DA, 0x5C97, 0xB8DB, 0x6E2F, 0xB8DC, 0x6760, 0xB8DD, 0x7BD9, 0xB8DE, 0x768B, 0xB8DF, 0x9AD8, 0xB8E0, 0x818F, 0xB8E1, 0x7F94, 0xB8E2, 0x7CD5, 0xB8E3, 0x641E, 0xB8E4, 0x9550, 0xB8E5, 0x7A3F, 0xB8E6, 0x544A, 0xB8E7, 0x54E5, 0xB8E8, 0x6B4C, 0xB8E9, 0x6401, 0xB8EA, 0x6208, 0xB8EB, 0x9E3D, 0xB8EC, 0x80F3, 0xB8ED, 0x7599, 0xB8EE, 0x5272, 0xB8EF, 0x9769, 0xB8F0, 0x845B, 0xB8F1, 0x683C, 0xB8F2, 0x86E4, 0xB8F3, 0x9601, 0xB8F4, 0x9694, 0xB8F5, 0x94EC, 0xB8F6, 0x4E2A, 0xB8F7, 0x5404, 0xB8F8, 0x7ED9, 0xB8F9, 0x6839, 0xB8FA, 0x8DDF, 0xB8FB, 0x8015, 0xB8FC, 0x66F4, 0xB8FD, 0x5E9A, 0xB8FE, 0x7FB9, 0xB940, 0x7B2F, 0xB941, 0x7B30, 0xB942, 0x7B32, 0xB943, 0x7B34, 0xB944, 0x7B35, 0xB945, 0x7B36, 0xB946, 0x7B37, 0xB947, 0x7B39, 0xB948, 0x7B3B, 0xB949, 0x7B3D, 0xB94A, 0x7B3F, 0xB94B, 0x7B40, 0xB94C, 0x7B41, 0xB94D, 0x7B42, 0xB94E, 0x7B43, 0xB94F, 0x7B44, 0xB950, 0x7B46, 0xB951, 0x7B48, 0xB952, 0x7B4A, 0xB953, 0x7B4D, 0xB954, 0x7B4E, 0xB955, 0x7B53, 0xB956, 0x7B55, 0xB957, 0x7B57, 0xB958, 0x7B59, 0xB959, 0x7B5C, 0xB95A, 0x7B5E, 0xB95B, 0x7B5F, 0xB95C, 0x7B61, 0xB95D, 0x7B63, 0xB95E, 0x7B64, 0xB95F, 0x7B65, 0xB960, 0x7B66, 0xB961, 0x7B67, 0xB962, 0x7B68, 0xB963, 0x7B69, 0xB964, 0x7B6A, 0xB965, 0x7B6B, 0xB966, 0x7B6C, 0xB967, 0x7B6D, 0xB968, 0x7B6F, 0xB969, 0x7B70, 0xB96A, 0x7B73, 0xB96B, 0x7B74, 0xB96C, 0x7B76, 0xB96D, 0x7B78, 0xB96E, 0x7B7A, 0xB96F, 0x7B7C, 0xB970, 0x7B7D, 0xB971, 0x7B7F, 0xB972, 0x7B81, 0xB973, 0x7B82, 0xB974, 0x7B83, 0xB975, 0x7B84, 0xB976, 0x7B86, 0xB977, 0x7B87, 0xB978, 0x7B88, 0xB979, 0x7B89, 0xB97A, 0x7B8A, 0xB97B, 0x7B8B, 0xB97C, 0x7B8C, 0xB97D, 0x7B8E, 0xB97E, 0x7B8F, 0xB980, 0x7B91, 0xB981, 0x7B92, 0xB982, 0x7B93, 0xB983, 0x7B96, 0xB984, 0x7B98, 0xB985, 0x7B99, 0xB986, 0x7B9A, 0xB987, 0x7B9B, 0xB988, 0x7B9E, 0xB989, 0x7B9F, 0xB98A, 0x7BA0, 0xB98B, 0x7BA3, 0xB98C, 0x7BA4, 0xB98D, 0x7BA5, 0xB98E, 0x7BAE, 0xB98F, 0x7BAF, 0xB990, 0x7BB0, 0xB991, 0x7BB2, 0xB992, 0x7BB3, 0xB993, 0x7BB5, 0xB994, 0x7BB6, 0xB995, 0x7BB7, 0xB996, 0x7BB9, 0xB997, 0x7BBA, 0xB998, 0x7BBB, 0xB999, 0x7BBC, 0xB99A, 0x7BBD, 0xB99B, 0x7BBE, 0xB99C, 0x7BBF, 0xB99D, 0x7BC0, 0xB99E, 0x7BC2, 0xB99F, 0x7BC3, 0xB9A0, 0x7BC4, 0xB9A1, 0x57C2, 0xB9A2, 0x803F, 0xB9A3, 0x6897, 0xB9A4, 0x5DE5, 0xB9A5, 0x653B, 0xB9A6, 0x529F, 0xB9A7, 0x606D, 0xB9A8, 0x9F9A, 0xB9A9, 0x4F9B, 0xB9AA, 0x8EAC, 0xB9AB, 0x516C, 0xB9AC, 0x5BAB, 0xB9AD, 0x5F13, 0xB9AE, 0x5DE9, 0xB9AF, 0x6C5E, 0xB9B0, 0x62F1, 0xB9B1, 0x8D21, 0xB9B2, 0x5171, 0xB9B3, 0x94A9, 0xB9B4, 0x52FE, 0xB9B5, 0x6C9F, 0xB9B6, 0x82DF, 0xB9B7, 0x72D7, 0xB9B8, 0x57A2, 0xB9B9, 0x6784, 0xB9BA, 0x8D2D, 0xB9BB, 0x591F, 0xB9BC, 0x8F9C, 0xB9BD, 0x83C7, 0xB9BE, 0x5495, 0xB9BF, 0x7B8D, 0xB9C0, 0x4F30, 0xB9C1, 0x6CBD, 0xB9C2, 0x5B64, 0xB9C3, 0x59D1, 0xB9C4, 0x9F13, 0xB9C5, 0x53E4, 0xB9C6, 0x86CA, 0xB9C7, 0x9AA8, 0xB9C8, 0x8C37, 0xB9C9, 0x80A1, 0xB9CA, 0x6545, 0xB9CB, 0x987E, 0xB9CC, 0x56FA, 0xB9CD, 0x96C7, 0xB9CE, 0x522E, 0xB9CF, 0x74DC, 0xB9D0, 0x5250, 0xB9D1, 0x5BE1, 0xB9D2, 0x6302, 0xB9D3, 0x8902, 0xB9D4, 0x4E56, 0xB9D5, 0x62D0, 0xB9D6, 0x602A, 0xB9D7, 0x68FA, 0xB9D8, 0x5173, 0xB9D9, 0x5B98, 0xB9DA, 0x51A0, 0xB9DB, 0x89C2, 0xB9DC, 0x7BA1, 0xB9DD, 0x9986, 0xB9DE, 0x7F50, 0xB9DF, 0x60EF, 0xB9E0, 0x704C, 0xB9E1, 0x8D2F, 0xB9E2, 0x5149, 0xB9E3, 0x5E7F, 0xB9E4, 0x901B, 0xB9E5, 0x7470, 0xB9E6, 0x89C4, 0xB9E7, 0x572D, 0xB9E8, 0x7845, 0xB9E9, 0x5F52, 0xB9EA, 0x9F9F, 0xB9EB, 0x95FA, 0xB9EC, 0x8F68, 0xB9ED, 0x9B3C, 0xB9EE, 0x8BE1, 0xB9EF, 0x7678, 0xB9F0, 0x6842, 0xB9F1, 0x67DC, 0xB9F2, 0x8DEA, 0xB9F3, 0x8D35, 0xB9F4, 0x523D, 0xB9F5, 0x8F8A, 0xB9F6, 0x6EDA, 0xB9F7, 0x68CD, 0xB9F8, 0x9505, 0xB9F9, 0x90ED, 0xB9FA, 0x56FD, 0xB9FB, 0x679C, 0xB9FC, 0x88F9, 0xB9FD, 0x8FC7, 0xB9FE, 0x54C8, 0xBA40, 0x7BC5, 0xBA41, 0x7BC8, 0xBA42, 0x7BC9, 0xBA43, 0x7BCA, 0xBA44, 0x7BCB, 0xBA45, 0x7BCD, 0xBA46, 0x7BCE, 0xBA47, 0x7BCF, 0xBA48, 0x7BD0, 0xBA49, 0x7BD2, 0xBA4A, 0x7BD4, 0xBA4B, 0x7BD5, 0xBA4C, 0x7BD6, 0xBA4D, 0x7BD7, 0xBA4E, 0x7BD8, 0xBA4F, 0x7BDB, 0xBA50, 0x7BDC, 0xBA51, 0x7BDE, 0xBA52, 0x7BDF, 0xBA53, 0x7BE0, 0xBA54, 0x7BE2, 0xBA55, 0x7BE3, 0xBA56, 0x7BE4, 0xBA57, 0x7BE7, 0xBA58, 0x7BE8, 0xBA59, 0x7BE9, 0xBA5A, 0x7BEB, 0xBA5B, 0x7BEC, 0xBA5C, 0x7BED, 0xBA5D, 0x7BEF, 0xBA5E, 0x7BF0, 0xBA5F, 0x7BF2, 0xBA60, 0x7BF3, 0xBA61, 0x7BF4, 0xBA62, 0x7BF5, 0xBA63, 0x7BF6, 0xBA64, 0x7BF8, 0xBA65, 0x7BF9, 0xBA66, 0x7BFA, 0xBA67, 0x7BFB, 0xBA68, 0x7BFD, 0xBA69, 0x7BFF, 0xBA6A, 0x7C00, 0xBA6B, 0x7C01, 0xBA6C, 0x7C02, 0xBA6D, 0x7C03, 0xBA6E, 0x7C04, 0xBA6F, 0x7C05, 0xBA70, 0x7C06, 0xBA71, 0x7C08, 0xBA72, 0x7C09, 0xBA73, 0x7C0A, 0xBA74, 0x7C0D, 0xBA75, 0x7C0E, 0xBA76, 0x7C10, 0xBA77, 0x7C11, 0xBA78, 0x7C12, 0xBA79, 0x7C13, 0xBA7A, 0x7C14, 0xBA7B, 0x7C15, 0xBA7C, 0x7C17, 0xBA7D, 0x7C18, 0xBA7E, 0x7C19, 0xBA80, 0x7C1A, 0xBA81, 0x7C1B, 0xBA82, 0x7C1C, 0xBA83, 0x7C1D, 0xBA84, 0x7C1E, 0xBA85, 0x7C20, 0xBA86, 0x7C21, 0xBA87, 0x7C22, 0xBA88, 0x7C23, 0xBA89, 0x7C24, 0xBA8A, 0x7C25, 0xBA8B, 0x7C28, 0xBA8C, 0x7C29, 0xBA8D, 0x7C2B, 0xBA8E, 0x7C2C, 0xBA8F, 0x7C2D, 0xBA90, 0x7C2E, 0xBA91, 0x7C2F, 0xBA92, 0x7C30, 0xBA93, 0x7C31, 0xBA94, 0x7C32, 0xBA95, 0x7C33, 0xBA96, 0x7C34, 0xBA97, 0x7C35, 0xBA98, 0x7C36, 0xBA99, 0x7C37, 0xBA9A, 0x7C39, 0xBA9B, 0x7C3A, 0xBA9C, 0x7C3B, 0xBA9D, 0x7C3C, 0xBA9E, 0x7C3D, 0xBA9F, 0x7C3E, 0xBAA0, 0x7C42, 0xBAA1, 0x9AB8, 0xBAA2, 0x5B69, 0xBAA3, 0x6D77, 0xBAA4, 0x6C26, 0xBAA5, 0x4EA5, 0xBAA6, 0x5BB3, 0xBAA7, 0x9A87, 0xBAA8, 0x9163, 0xBAA9, 0x61A8, 0xBAAA, 0x90AF, 0xBAAB, 0x97E9, 0xBAAC, 0x542B, 0xBAAD, 0x6DB5, 0xBAAE, 0x5BD2, 0xBAAF, 0x51FD, 0xBAB0, 0x558A, 0xBAB1, 0x7F55, 0xBAB2, 0x7FF0, 0xBAB3, 0x64BC, 0xBAB4, 0x634D, 0xBAB5, 0x65F1, 0xBAB6, 0x61BE, 0xBAB7, 0x608D, 0xBAB8, 0x710A, 0xBAB9, 0x6C57, 0xBABA, 0x6C49, 0xBABB, 0x592F, 0xBABC, 0x676D, 0xBABD, 0x822A, 0xBABE, 0x58D5, 0xBABF, 0x568E, 0xBAC0, 0x8C6A, 0xBAC1, 0x6BEB, 0xBAC2, 0x90DD, 0xBAC3, 0x597D, 0xBAC4, 0x8017, 0xBAC5, 0x53F7, 0xBAC6, 0x6D69, 0xBAC7, 0x5475, 0xBAC8, 0x559D, 0xBAC9, 0x8377, 0xBACA, 0x83CF, 0xBACB, 0x6838, 0xBACC, 0x79BE, 0xBACD, 0x548C, 0xBACE, 0x4F55, 0xBACF, 0x5408, 0xBAD0, 0x76D2, 0xBAD1, 0x8C89, 0xBAD2, 0x9602, 0xBAD3, 0x6CB3, 0xBAD4, 0x6DB8, 0xBAD5, 0x8D6B, 0xBAD6, 0x8910, 0xBAD7, 0x9E64, 0xBAD8, 0x8D3A, 0xBAD9, 0x563F, 0xBADA, 0x9ED1, 0xBADB, 0x75D5, 0xBADC, 0x5F88, 0xBADD, 0x72E0, 0xBADE, 0x6068, 0xBADF, 0x54FC, 0xBAE0, 0x4EA8, 0xBAE1, 0x6A2A, 0xBAE2, 0x8861, 0xBAE3, 0x6052, 0xBAE4, 0x8F70, 0xBAE5, 0x54C4, 0xBAE6, 0x70D8, 0xBAE7, 0x8679, 0xBAE8, 0x9E3F, 0xBAE9, 0x6D2A, 0xBAEA, 0x5B8F, 0xBAEB, 0x5F18, 0xBAEC, 0x7EA2, 0xBAED, 0x5589, 0xBAEE, 0x4FAF, 0xBAEF, 0x7334, 0xBAF0, 0x543C, 0xBAF1, 0x539A, 0xBAF2, 0x5019, 0xBAF3, 0x540E, 0xBAF4, 0x547C, 0xBAF5, 0x4E4E, 0xBAF6, 0x5FFD, 0xBAF7, 0x745A, 0xBAF8, 0x58F6, 0xBAF9, 0x846B, 0xBAFA, 0x80E1, 0xBAFB, 0x8774, 0xBAFC, 0x72D0, 0xBAFD, 0x7CCA, 0xBAFE, 0x6E56, 0xBB40, 0x7C43, 0xBB41, 0x7C44, 0xBB42, 0x7C45, 0xBB43, 0x7C46, 0xBB44, 0x7C47, 0xBB45, 0x7C48, 0xBB46, 0x7C49, 0xBB47, 0x7C4A, 0xBB48, 0x7C4B, 0xBB49, 0x7C4C, 0xBB4A, 0x7C4E, 0xBB4B, 0x7C4F, 0xBB4C, 0x7C50, 0xBB4D, 0x7C51, 0xBB4E, 0x7C52, 0xBB4F, 0x7C53, 0xBB50, 0x7C54, 0xBB51, 0x7C55, 0xBB52, 0x7C56, 0xBB53, 0x7C57, 0xBB54, 0x7C58, 0xBB55, 0x7C59, 0xBB56, 0x7C5A, 0xBB57, 0x7C5B, 0xBB58, 0x7C5C, 0xBB59, 0x7C5D, 0xBB5A, 0x7C5E, 0xBB5B, 0x7C5F, 0xBB5C, 0x7C60, 0xBB5D, 0x7C61, 0xBB5E, 0x7C62, 0xBB5F, 0x7C63, 0xBB60, 0x7C64, 0xBB61, 0x7C65, 0xBB62, 0x7C66, 0xBB63, 0x7C67, 0xBB64, 0x7C68, 0xBB65, 0x7C69, 0xBB66, 0x7C6A, 0xBB67, 0x7C6B, 0xBB68, 0x7C6C, 0xBB69, 0x7C6D, 0xBB6A, 0x7C6E, 0xBB6B, 0x7C6F, 0xBB6C, 0x7C70, 0xBB6D, 0x7C71, 0xBB6E, 0x7C72, 0xBB6F, 0x7C75, 0xBB70, 0x7C76, 0xBB71, 0x7C77, 0xBB72, 0x7C78, 0xBB73, 0x7C79, 0xBB74, 0x7C7A, 0xBB75, 0x7C7E, 0xBB76, 0x7C7F, 0xBB77, 0x7C80, 0xBB78, 0x7C81, 0xBB79, 0x7C82, 0xBB7A, 0x7C83, 0xBB7B, 0x7C84, 0xBB7C, 0x7C85, 0xBB7D, 0x7C86, 0xBB7E, 0x7C87, 0xBB80, 0x7C88, 0xBB81, 0x7C8A, 0xBB82, 0x7C8B, 0xBB83, 0x7C8C, 0xBB84, 0x7C8D, 0xBB85, 0x7C8E, 0xBB86, 0x7C8F, 0xBB87, 0x7C90, 0xBB88, 0x7C93, 0xBB89, 0x7C94, 0xBB8A, 0x7C96, 0xBB8B, 0x7C99, 0xBB8C, 0x7C9A, 0xBB8D, 0x7C9B, 0xBB8E, 0x7CA0, 0xBB8F, 0x7CA1, 0xBB90, 0x7CA3, 0xBB91, 0x7CA6, 0xBB92, 0x7CA7, 0xBB93, 0x7CA8, 0xBB94, 0x7CA9, 0xBB95, 0x7CAB, 0xBB96, 0x7CAC, 0xBB97, 0x7CAD, 0xBB98, 0x7CAF, 0xBB99, 0x7CB0, 0xBB9A, 0x7CB4, 0xBB9B, 0x7CB5, 0xBB9C, 0x7CB6, 0xBB9D, 0x7CB7, 0xBB9E, 0x7CB8, 0xBB9F, 0x7CBA, 0xBBA0, 0x7CBB, 0xBBA1, 0x5F27, 0xBBA2, 0x864E, 0xBBA3, 0x552C, 0xBBA4, 0x62A4, 0xBBA5, 0x4E92, 0xBBA6, 0x6CAA, 0xBBA7, 0x6237, 0xBBA8, 0x82B1, 0xBBA9, 0x54D7, 0xBBAA, 0x534E, 0xBBAB, 0x733E, 0xBBAC, 0x6ED1, 0xBBAD, 0x753B, 0xBBAE, 0x5212, 0xBBAF, 0x5316, 0xBBB0, 0x8BDD, 0xBBB1, 0x69D0, 0xBBB2, 0x5F8A, 0xBBB3, 0x6000, 0xBBB4, 0x6DEE, 0xBBB5, 0x574F, 0xBBB6, 0x6B22, 0xBBB7, 0x73AF, 0xBBB8, 0x6853, 0xBBB9, 0x8FD8, 0xBBBA, 0x7F13, 0xBBBB, 0x6362, 0xBBBC, 0x60A3, 0xBBBD, 0x5524, 0xBBBE, 0x75EA, 0xBBBF, 0x8C62, 0xBBC0, 0x7115, 0xBBC1, 0x6DA3, 0xBBC2, 0x5BA6, 0xBBC3, 0x5E7B, 0xBBC4, 0x8352, 0xBBC5, 0x614C, 0xBBC6, 0x9EC4, 0xBBC7, 0x78FA, 0xBBC8, 0x8757, 0xBBC9, 0x7C27, 0xBBCA, 0x7687, 0xBBCB, 0x51F0, 0xBBCC, 0x60F6, 0xBBCD, 0x714C, 0xBBCE, 0x6643, 0xBBCF, 0x5E4C, 0xBBD0, 0x604D, 0xBBD1, 0x8C0E, 0xBBD2, 0x7070, 0xBBD3, 0x6325, 0xBBD4, 0x8F89, 0xBBD5, 0x5FBD, 0xBBD6, 0x6062, 0xBBD7, 0x86D4, 0xBBD8, 0x56DE, 0xBBD9, 0x6BC1, 0xBBDA, 0x6094, 0xBBDB, 0x6167, 0xBBDC, 0x5349, 0xBBDD, 0x60E0, 0xBBDE, 0x6666, 0xBBDF, 0x8D3F, 0xBBE0, 0x79FD, 0xBBE1, 0x4F1A, 0xBBE2, 0x70E9, 0xBBE3, 0x6C47, 0xBBE4, 0x8BB3, 0xBBE5, 0x8BF2, 0xBBE6, 0x7ED8, 0xBBE7, 0x8364, 0xBBE8, 0x660F, 0xBBE9, 0x5A5A, 0xBBEA, 0x9B42, 0xBBEB, 0x6D51, 0xBBEC, 0x6DF7, 0xBBED, 0x8C41, 0xBBEE, 0x6D3B, 0xBBEF, 0x4F19, 0xBBF0, 0x706B, 0xBBF1, 0x83B7, 0xBBF2, 0x6216, 0xBBF3, 0x60D1, 0xBBF4, 0x970D, 0xBBF5, 0x8D27, 0xBBF6, 0x7978, 0xBBF7, 0x51FB, 0xBBF8, 0x573E, 0xBBF9, 0x57FA, 0xBBFA, 0x673A, 0xBBFB, 0x7578, 0xBBFC, 0x7A3D, 0xBBFD, 0x79EF, 0xBBFE, 0x7B95, 0xBC40, 0x7CBF, 0xBC41, 0x7CC0, 0xBC42, 0x7CC2, 0xBC43, 0x7CC3, 0xBC44, 0x7CC4, 0xBC45, 0x7CC6, 0xBC46, 0x7CC9, 0xBC47, 0x7CCB, 0xBC48, 0x7CCE, 0xBC49, 0x7CCF, 0xBC4A, 0x7CD0, 0xBC4B, 0x7CD1, 0xBC4C, 0x7CD2, 0xBC4D, 0x7CD3, 0xBC4E, 0x7CD4, 0xBC4F, 0x7CD8, 0xBC50, 0x7CDA, 0xBC51, 0x7CDB, 0xBC52, 0x7CDD, 0xBC53, 0x7CDE, 0xBC54, 0x7CE1, 0xBC55, 0x7CE2, 0xBC56, 0x7CE3, 0xBC57, 0x7CE4, 0xBC58, 0x7CE5, 0xBC59, 0x7CE6, 0xBC5A, 0x7CE7, 0xBC5B, 0x7CE9, 0xBC5C, 0x7CEA, 0xBC5D, 0x7CEB, 0xBC5E, 0x7CEC, 0xBC5F, 0x7CED, 0xBC60, 0x7CEE, 0xBC61, 0x7CF0, 0xBC62, 0x7CF1, 0xBC63, 0x7CF2, 0xBC64, 0x7CF3, 0xBC65, 0x7CF4, 0xBC66, 0x7CF5, 0xBC67, 0x7CF6, 0xBC68, 0x7CF7, 0xBC69, 0x7CF9, 0xBC6A, 0x7CFA, 0xBC6B, 0x7CFC, 0xBC6C, 0x7CFD, 0xBC6D, 0x7CFE, 0xBC6E, 0x7CFF, 0xBC6F, 0x7D00, 0xBC70, 0x7D01, 0xBC71, 0x7D02, 0xBC72, 0x7D03, 0xBC73, 0x7D04, 0xBC74, 0x7D05, 0xBC75, 0x7D06, 0xBC76, 0x7D07, 0xBC77, 0x7D08, 0xBC78, 0x7D09, 0xBC79, 0x7D0B, 0xBC7A, 0x7D0C, 0xBC7B, 0x7D0D, 0xBC7C, 0x7D0E, 0xBC7D, 0x7D0F, 0xBC7E, 0x7D10, 0xBC80, 0x7D11, 0xBC81, 0x7D12, 0xBC82, 0x7D13, 0xBC83, 0x7D14, 0xBC84, 0x7D15, 0xBC85, 0x7D16, 0xBC86, 0x7D17, 0xBC87, 0x7D18, 0xBC88, 0x7D19, 0xBC89, 0x7D1A, 0xBC8A, 0x7D1B, 0xBC8B, 0x7D1C, 0xBC8C, 0x7D1D, 0xBC8D, 0x7D1E, 0xBC8E, 0x7D1F, 0xBC8F, 0x7D21, 0xBC90, 0x7D23, 0xBC91, 0x7D24, 0xBC92, 0x7D25, 0xBC93, 0x7D26, 0xBC94, 0x7D28, 0xBC95, 0x7D29, 0xBC96, 0x7D2A, 0xBC97, 0x7D2C, 0xBC98, 0x7D2D, 0xBC99, 0x7D2E, 0xBC9A, 0x7D30, 0xBC9B, 0x7D31, 0xBC9C, 0x7D32, 0xBC9D, 0x7D33, 0xBC9E, 0x7D34, 0xBC9F, 0x7D35, 0xBCA0, 0x7D36, 0xBCA1, 0x808C, 0xBCA2, 0x9965, 0xBCA3, 0x8FF9, 0xBCA4, 0x6FC0, 0xBCA5, 0x8BA5, 0xBCA6, 0x9E21, 0xBCA7, 0x59EC, 0xBCA8, 0x7EE9, 0xBCA9, 0x7F09, 0xBCAA, 0x5409, 0xBCAB, 0x6781, 0xBCAC, 0x68D8, 0xBCAD, 0x8F91, 0xBCAE, 0x7C4D, 0xBCAF, 0x96C6, 0xBCB0, 0x53CA, 0xBCB1, 0x6025, 0xBCB2, 0x75BE, 0xBCB3, 0x6C72, 0xBCB4, 0x5373, 0xBCB5, 0x5AC9, 0xBCB6, 0x7EA7, 0xBCB7, 0x6324, 0xBCB8, 0x51E0, 0xBCB9, 0x810A, 0xBCBA, 0x5DF1, 0xBCBB, 0x84DF, 0xBCBC, 0x6280, 0xBCBD, 0x5180, 0xBCBE, 0x5B63, 0xBCBF, 0x4F0E, 0xBCC0, 0x796D, 0xBCC1, 0x5242, 0xBCC2, 0x60B8, 0xBCC3, 0x6D4E, 0xBCC4, 0x5BC4, 0xBCC5, 0x5BC2, 0xBCC6, 0x8BA1, 0xBCC7, 0x8BB0, 0xBCC8, 0x65E2, 0xBCC9, 0x5FCC, 0xBCCA, 0x9645, 0xBCCB, 0x5993, 0xBCCC, 0x7EE7, 0xBCCD, 0x7EAA, 0xBCCE, 0x5609, 0xBCCF, 0x67B7, 0xBCD0, 0x5939, 0xBCD1, 0x4F73, 0xBCD2, 0x5BB6, 0xBCD3, 0x52A0, 0xBCD4, 0x835A, 0xBCD5, 0x988A, 0xBCD6, 0x8D3E, 0xBCD7, 0x7532, 0xBCD8, 0x94BE, 0xBCD9, 0x5047, 0xBCDA, 0x7A3C, 0xBCDB, 0x4EF7, 0xBCDC, 0x67B6, 0xBCDD, 0x9A7E, 0xBCDE, 0x5AC1, 0xBCDF, 0x6B7C, 0xBCE0, 0x76D1, 0xBCE1, 0x575A, 0xBCE2, 0x5C16, 0xBCE3, 0x7B3A, 0xBCE4, 0x95F4, 0xBCE5, 0x714E, 0xBCE6, 0x517C, 0xBCE7, 0x80A9, 0xBCE8, 0x8270, 0xBCE9, 0x5978, 0xBCEA, 0x7F04, 0xBCEB, 0x8327, 0xBCEC, 0x68C0, 0xBCED, 0x67EC, 0xBCEE, 0x78B1, 0xBCEF, 0x7877, 0xBCF0, 0x62E3, 0xBCF1, 0x6361, 0xBCF2, 0x7B80, 0xBCF3, 0x4FED, 0xBCF4, 0x526A, 0xBCF5, 0x51CF, 0xBCF6, 0x8350, 0xBCF7, 0x69DB, 0xBCF8, 0x9274, 0xBCF9, 0x8DF5, 0xBCFA, 0x8D31, 0xBCFB, 0x89C1, 0xBCFC, 0x952E, 0xBCFD, 0x7BAD, 0xBCFE, 0x4EF6, 0xBD40, 0x7D37, 0xBD41, 0x7D38, 0xBD42, 0x7D39, 0xBD43, 0x7D3A, 0xBD44, 0x7D3B, 0xBD45, 0x7D3C, 0xBD46, 0x7D3D, 0xBD47, 0x7D3E, 0xBD48, 0x7D3F, 0xBD49, 0x7D40, 0xBD4A, 0x7D41, 0xBD4B, 0x7D42, 0xBD4C, 0x7D43, 0xBD4D, 0x7D44, 0xBD4E, 0x7D45, 0xBD4F, 0x7D46, 0xBD50, 0x7D47, 0xBD51, 0x7D48, 0xBD52, 0x7D49, 0xBD53, 0x7D4A, 0xBD54, 0x7D4B, 0xBD55, 0x7D4C, 0xBD56, 0x7D4D, 0xBD57, 0x7D4E, 0xBD58, 0x7D4F, 0xBD59, 0x7D50, 0xBD5A, 0x7D51, 0xBD5B, 0x7D52, 0xBD5C, 0x7D53, 0xBD5D, 0x7D54, 0xBD5E, 0x7D55, 0xBD5F, 0x7D56, 0xBD60, 0x7D57, 0xBD61, 0x7D58, 0xBD62, 0x7D59, 0xBD63, 0x7D5A, 0xBD64, 0x7D5B, 0xBD65, 0x7D5C, 0xBD66, 0x7D5D, 0xBD67, 0x7D5E, 0xBD68, 0x7D5F, 0xBD69, 0x7D60, 0xBD6A, 0x7D61, 0xBD6B, 0x7D62, 0xBD6C, 0x7D63, 0xBD6D, 0x7D64, 0xBD6E, 0x7D65, 0xBD6F, 0x7D66, 0xBD70, 0x7D67, 0xBD71, 0x7D68, 0xBD72, 0x7D69, 0xBD73, 0x7D6A, 0xBD74, 0x7D6B, 0xBD75, 0x7D6C, 0xBD76, 0x7D6D, 0xBD77, 0x7D6F, 0xBD78, 0x7D70, 0xBD79, 0x7D71, 0xBD7A, 0x7D72, 0xBD7B, 0x7D73, 0xBD7C, 0x7D74, 0xBD7D, 0x7D75, 0xBD7E, 0x7D76, 0xBD80, 0x7D78, 0xBD81, 0x7D79, 0xBD82, 0x7D7A, 0xBD83, 0x7D7B, 0xBD84, 0x7D7C, 0xBD85, 0x7D7D, 0xBD86, 0x7D7E, 0xBD87, 0x7D7F, 0xBD88, 0x7D80, 0xBD89, 0x7D81, 0xBD8A, 0x7D82, 0xBD8B, 0x7D83, 0xBD8C, 0x7D84, 0xBD8D, 0x7D85, 0xBD8E, 0x7D86, 0xBD8F, 0x7D87, 0xBD90, 0x7D88, 0xBD91, 0x7D89, 0xBD92, 0x7D8A, 0xBD93, 0x7D8B, 0xBD94, 0x7D8C, 0xBD95, 0x7D8D, 0xBD96, 0x7D8E, 0xBD97, 0x7D8F, 0xBD98, 0x7D90, 0xBD99, 0x7D91, 0xBD9A, 0x7D92, 0xBD9B, 0x7D93, 0xBD9C, 0x7D94, 0xBD9D, 0x7D95, 0xBD9E, 0x7D96, 0xBD9F, 0x7D97, 0xBDA0, 0x7D98, 0xBDA1, 0x5065, 0xBDA2, 0x8230, 0xBDA3, 0x5251, 0xBDA4, 0x996F, 0xBDA5, 0x6E10, 0xBDA6, 0x6E85, 0xBDA7, 0x6DA7, 0xBDA8, 0x5EFA, 0xBDA9, 0x50F5, 0xBDAA, 0x59DC, 0xBDAB, 0x5C06, 0xBDAC, 0x6D46, 0xBDAD, 0x6C5F, 0xBDAE, 0x7586, 0xBDAF, 0x848B, 0xBDB0, 0x6868, 0xBDB1, 0x5956, 0xBDB2, 0x8BB2, 0xBDB3, 0x5320, 0xBDB4, 0x9171, 0xBDB5, 0x964D, 0xBDB6, 0x8549, 0xBDB7, 0x6912, 0xBDB8, 0x7901, 0xBDB9, 0x7126, 0xBDBA, 0x80F6, 0xBDBB, 0x4EA4, 0xBDBC, 0x90CA, 0xBDBD, 0x6D47, 0xBDBE, 0x9A84, 0xBDBF, 0x5A07, 0xBDC0, 0x56BC, 0xBDC1, 0x6405, 0xBDC2, 0x94F0, 0xBDC3, 0x77EB, 0xBDC4, 0x4FA5, 0xBDC5, 0x811A, 0xBDC6, 0x72E1, 0xBDC7, 0x89D2, 0xBDC8, 0x997A, 0xBDC9, 0x7F34, 0xBDCA, 0x7EDE, 0xBDCB, 0x527F, 0xBDCC, 0x6559, 0xBDCD, 0x9175, 0xBDCE, 0x8F7F, 0xBDCF, 0x8F83, 0xBDD0, 0x53EB, 0xBDD1, 0x7A96, 0xBDD2, 0x63ED, 0xBDD3, 0x63A5, 0xBDD4, 0x7686, 0xBDD5, 0x79F8, 0xBDD6, 0x8857, 0xBDD7, 0x9636, 0xBDD8, 0x622A, 0xBDD9, 0x52AB, 0xBDDA, 0x8282, 0xBDDB, 0x6854, 0xBDDC, 0x6770, 0xBDDD, 0x6377, 0xBDDE, 0x776B, 0xBDDF, 0x7AED, 0xBDE0, 0x6D01, 0xBDE1, 0x7ED3, 0xBDE2, 0x89E3, 0xBDE3, 0x59D0, 0xBDE4, 0x6212, 0xBDE5, 0x85C9, 0xBDE6, 0x82A5, 0xBDE7, 0x754C, 0xBDE8, 0x501F, 0xBDE9, 0x4ECB, 0xBDEA, 0x75A5, 0xBDEB, 0x8BEB, 0xBDEC, 0x5C4A, 0xBDED, 0x5DFE, 0xBDEE, 0x7B4B, 0xBDEF, 0x65A4, 0xBDF0, 0x91D1, 0xBDF1, 0x4ECA, 0xBDF2, 0x6D25, 0xBDF3, 0x895F, 0xBDF4, 0x7D27, 0xBDF5, 0x9526, 0xBDF6, 0x4EC5, 0xBDF7, 0x8C28, 0xBDF8, 0x8FDB, 0xBDF9, 0x9773, 0xBDFA, 0x664B, 0xBDFB, 0x7981, 0xBDFC, 0x8FD1, 0xBDFD, 0x70EC, 0xBDFE, 0x6D78, 0xBE40, 0x7D99, 0xBE41, 0x7D9A, 0xBE42, 0x7D9B, 0xBE43, 0x7D9C, 0xBE44, 0x7D9D, 0xBE45, 0x7D9E, 0xBE46, 0x7D9F, 0xBE47, 0x7DA0, 0xBE48, 0x7DA1, 0xBE49, 0x7DA2, 0xBE4A, 0x7DA3, 0xBE4B, 0x7DA4, 0xBE4C, 0x7DA5, 0xBE4D, 0x7DA7, 0xBE4E, 0x7DA8, 0xBE4F, 0x7DA9, 0xBE50, 0x7DAA, 0xBE51, 0x7DAB, 0xBE52, 0x7DAC, 0xBE53, 0x7DAD, 0xBE54, 0x7DAF, 0xBE55, 0x7DB0, 0xBE56, 0x7DB1, 0xBE57, 0x7DB2, 0xBE58, 0x7DB3, 0xBE59, 0x7DB4, 0xBE5A, 0x7DB5, 0xBE5B, 0x7DB6, 0xBE5C, 0x7DB7, 0xBE5D, 0x7DB8, 0xBE5E, 0x7DB9, 0xBE5F, 0x7DBA, 0xBE60, 0x7DBB, 0xBE61, 0x7DBC, 0xBE62, 0x7DBD, 0xBE63, 0x7DBE, 0xBE64, 0x7DBF, 0xBE65, 0x7DC0, 0xBE66, 0x7DC1, 0xBE67, 0x7DC2, 0xBE68, 0x7DC3, 0xBE69, 0x7DC4, 0xBE6A, 0x7DC5, 0xBE6B, 0x7DC6, 0xBE6C, 0x7DC7, 0xBE6D, 0x7DC8, 0xBE6E, 0x7DC9, 0xBE6F, 0x7DCA, 0xBE70, 0x7DCB, 0xBE71, 0x7DCC, 0xBE72, 0x7DCD, 0xBE73, 0x7DCE, 0xBE74, 0x7DCF, 0xBE75, 0x7DD0, 0xBE76, 0x7DD1, 0xBE77, 0x7DD2, 0xBE78, 0x7DD3, 0xBE79, 0x7DD4, 0xBE7A, 0x7DD5, 0xBE7B, 0x7DD6, 0xBE7C, 0x7DD7, 0xBE7D, 0x7DD8, 0xBE7E, 0x7DD9, 0xBE80, 0x7DDA, 0xBE81, 0x7DDB, 0xBE82, 0x7DDC, 0xBE83, 0x7DDD, 0xBE84, 0x7DDE, 0xBE85, 0x7DDF, 0xBE86, 0x7DE0, 0xBE87, 0x7DE1, 0xBE88, 0x7DE2, 0xBE89, 0x7DE3, 0xBE8A, 0x7DE4, 0xBE8B, 0x7DE5, 0xBE8C, 0x7DE6, 0xBE8D, 0x7DE7, 0xBE8E, 0x7DE8, 0xBE8F, 0x7DE9, 0xBE90, 0x7DEA, 0xBE91, 0x7DEB, 0xBE92, 0x7DEC, 0xBE93, 0x7DED, 0xBE94, 0x7DEE, 0xBE95, 0x7DEF, 0xBE96, 0x7DF0, 0xBE97, 0x7DF1, 0xBE98, 0x7DF2, 0xBE99, 0x7DF3, 0xBE9A, 0x7DF4, 0xBE9B, 0x7DF5, 0xBE9C, 0x7DF6, 0xBE9D, 0x7DF7, 0xBE9E, 0x7DF8, 0xBE9F, 0x7DF9, 0xBEA0, 0x7DFA, 0xBEA1, 0x5C3D, 0xBEA2, 0x52B2, 0xBEA3, 0x8346, 0xBEA4, 0x5162, 0xBEA5, 0x830E, 0xBEA6, 0x775B, 0xBEA7, 0x6676, 0xBEA8, 0x9CB8, 0xBEA9, 0x4EAC, 0xBEAA, 0x60CA, 0xBEAB, 0x7CBE, 0xBEAC, 0x7CB3, 0xBEAD, 0x7ECF, 0xBEAE, 0x4E95, 0xBEAF, 0x8B66, 0xBEB0, 0x666F, 0xBEB1, 0x9888, 0xBEB2, 0x9759, 0xBEB3, 0x5883, 0xBEB4, 0x656C, 0xBEB5, 0x955C, 0xBEB6, 0x5F84, 0xBEB7, 0x75C9, 0xBEB8, 0x9756, 0xBEB9, 0x7ADF, 0xBEBA, 0x7ADE, 0xBEBB, 0x51C0, 0xBEBC, 0x70AF, 0xBEBD, 0x7A98, 0xBEBE, 0x63EA, 0xBEBF, 0x7A76, 0xBEC0, 0x7EA0, 0xBEC1, 0x7396, 0xBEC2, 0x97ED, 0xBEC3, 0x4E45, 0xBEC4, 0x7078, 0xBEC5, 0x4E5D, 0xBEC6, 0x9152, 0xBEC7, 0x53A9, 0xBEC8, 0x6551, 0xBEC9, 0x65E7, 0xBECA, 0x81FC, 0xBECB, 0x8205, 0xBECC, 0x548E, 0xBECD, 0x5C31, 0xBECE, 0x759A, 0xBECF, 0x97A0, 0xBED0, 0x62D8, 0xBED1, 0x72D9, 0xBED2, 0x75BD, 0xBED3, 0x5C45, 0xBED4, 0x9A79, 0xBED5, 0x83CA, 0xBED6, 0x5C40, 0xBED7, 0x5480, 0xBED8, 0x77E9, 0xBED9, 0x4E3E, 0xBEDA, 0x6CAE, 0xBEDB, 0x805A, 0xBEDC, 0x62D2, 0xBEDD, 0x636E, 0xBEDE, 0x5DE8, 0xBEDF, 0x5177, 0xBEE0, 0x8DDD, 0xBEE1, 0x8E1E, 0xBEE2, 0x952F, 0xBEE3, 0x4FF1, 0xBEE4, 0x53E5, 0xBEE5, 0x60E7, 0xBEE6, 0x70AC, 0xBEE7, 0x5267, 0xBEE8, 0x6350, 0xBEE9, 0x9E43, 0xBEEA, 0x5A1F, 0xBEEB, 0x5026, 0xBEEC, 0x7737, 0xBEED, 0x5377, 0xBEEE, 0x7EE2, 0xBEEF, 0x6485, 0xBEF0, 0x652B, 0xBEF1, 0x6289, 0xBEF2, 0x6398, 0xBEF3, 0x5014, 0xBEF4, 0x7235, 0xBEF5, 0x89C9, 0xBEF6, 0x51B3, 0xBEF7, 0x8BC0, 0xBEF8, 0x7EDD, 0xBEF9, 0x5747, 0xBEFA, 0x83CC, 0xBEFB, 0x94A7, 0xBEFC, 0x519B, 0xBEFD, 0x541B, 0xBEFE, 0x5CFB, 0xBF40, 0x7DFB, 0xBF41, 0x7DFC, 0xBF42, 0x7DFD, 0xBF43, 0x7DFE, 0xBF44, 0x7DFF, 0xBF45, 0x7E00, 0xBF46, 0x7E01, 0xBF47, 0x7E02, 0xBF48, 0x7E03, 0xBF49, 0x7E04, 0xBF4A, 0x7E05, 0xBF4B, 0x7E06, 0xBF4C, 0x7E07, 0xBF4D, 0x7E08, 0xBF4E, 0x7E09, 0xBF4F, 0x7E0A, 0xBF50, 0x7E0B, 0xBF51, 0x7E0C, 0xBF52, 0x7E0D, 0xBF53, 0x7E0E, 0xBF54, 0x7E0F, 0xBF55, 0x7E10, 0xBF56, 0x7E11, 0xBF57, 0x7E12, 0xBF58, 0x7E13, 0xBF59, 0x7E14, 0xBF5A, 0x7E15, 0xBF5B, 0x7E16, 0xBF5C, 0x7E17, 0xBF5D, 0x7E18, 0xBF5E, 0x7E19, 0xBF5F, 0x7E1A, 0xBF60, 0x7E1B, 0xBF61, 0x7E1C, 0xBF62, 0x7E1D, 0xBF63, 0x7E1E, 0xBF64, 0x7E1F, 0xBF65, 0x7E20, 0xBF66, 0x7E21, 0xBF67, 0x7E22, 0xBF68, 0x7E23, 0xBF69, 0x7E24, 0xBF6A, 0x7E25, 0xBF6B, 0x7E26, 0xBF6C, 0x7E27, 0xBF6D, 0x7E28, 0xBF6E, 0x7E29, 0xBF6F, 0x7E2A, 0xBF70, 0x7E2B, 0xBF71, 0x7E2C, 0xBF72, 0x7E2D, 0xBF73, 0x7E2E, 0xBF74, 0x7E2F, 0xBF75, 0x7E30, 0xBF76, 0x7E31, 0xBF77, 0x7E32, 0xBF78, 0x7E33, 0xBF79, 0x7E34, 0xBF7A, 0x7E35, 0xBF7B, 0x7E36, 0xBF7C, 0x7E37, 0xBF7D, 0x7E38, 0xBF7E, 0x7E39, 0xBF80, 0x7E3A, 0xBF81, 0x7E3C, 0xBF82, 0x7E3D, 0xBF83, 0x7E3E, 0xBF84, 0x7E3F, 0xBF85, 0x7E40, 0xBF86, 0x7E42, 0xBF87, 0x7E43, 0xBF88, 0x7E44, 0xBF89, 0x7E45, 0xBF8A, 0x7E46, 0xBF8B, 0x7E48, 0xBF8C, 0x7E49, 0xBF8D, 0x7E4A, 0xBF8E, 0x7E4B, 0xBF8F, 0x7E4C, 0xBF90, 0x7E4D, 0xBF91, 0x7E4E, 0xBF92, 0x7E4F, 0xBF93, 0x7E50, 0xBF94, 0x7E51, 0xBF95, 0x7E52, 0xBF96, 0x7E53, 0xBF97, 0x7E54, 0xBF98, 0x7E55, 0xBF99, 0x7E56, 0xBF9A, 0x7E57, 0xBF9B, 0x7E58, 0xBF9C, 0x7E59, 0xBF9D, 0x7E5A, 0xBF9E, 0x7E5B, 0xBF9F, 0x7E5C, 0xBFA0, 0x7E5D, 0xBFA1, 0x4FCA, 0xBFA2, 0x7AE3, 0xBFA3, 0x6D5A, 0xBFA4, 0x90E1, 0xBFA5, 0x9A8F, 0xBFA6, 0x5580, 0xBFA7, 0x5496, 0xBFA8, 0x5361, 0xBFA9, 0x54AF, 0xBFAA, 0x5F00, 0xBFAB, 0x63E9, 0xBFAC, 0x6977, 0xBFAD, 0x51EF, 0xBFAE, 0x6168, 0xBFAF, 0x520A, 0xBFB0, 0x582A, 0xBFB1, 0x52D8, 0xBFB2, 0x574E, 0xBFB3, 0x780D, 0xBFB4, 0x770B, 0xBFB5, 0x5EB7, 0xBFB6, 0x6177, 0xBFB7, 0x7CE0, 0xBFB8, 0x625B, 0xBFB9, 0x6297, 0xBFBA, 0x4EA2, 0xBFBB, 0x7095, 0xBFBC, 0x8003, 0xBFBD, 0x62F7, 0xBFBE, 0x70E4, 0xBFBF, 0x9760, 0xBFC0, 0x5777, 0xBFC1, 0x82DB, 0xBFC2, 0x67EF, 0xBFC3, 0x68F5, 0xBFC4, 0x78D5, 0xBFC5, 0x9897, 0xBFC6, 0x79D1, 0xBFC7, 0x58F3, 0xBFC8, 0x54B3, 0xBFC9, 0x53EF, 0xBFCA, 0x6E34, 0xBFCB, 0x514B, 0xBFCC, 0x523B, 0xBFCD, 0x5BA2, 0xBFCE, 0x8BFE, 0xBFCF, 0x80AF, 0xBFD0, 0x5543, 0xBFD1, 0x57A6, 0xBFD2, 0x6073, 0xBFD3, 0x5751, 0xBFD4, 0x542D, 0xBFD5, 0x7A7A, 0xBFD6, 0x6050, 0xBFD7, 0x5B54, 0xBFD8, 0x63A7, 0xBFD9, 0x62A0, 0xBFDA, 0x53E3, 0xBFDB, 0x6263, 0xBFDC, 0x5BC7, 0xBFDD, 0x67AF, 0xBFDE, 0x54ED, 0xBFDF, 0x7A9F, 0xBFE0, 0x82E6, 0xBFE1, 0x9177, 0xBFE2, 0x5E93, 0xBFE3, 0x88E4, 0xBFE4, 0x5938, 0xBFE5, 0x57AE, 0xBFE6, 0x630E, 0xBFE7, 0x8DE8, 0xBFE8, 0x80EF, 0xBFE9, 0x5757, 0xBFEA, 0x7B77, 0xBFEB, 0x4FA9, 0xBFEC, 0x5FEB, 0xBFED, 0x5BBD, 0xBFEE, 0x6B3E, 0xBFEF, 0x5321, 0xBFF0, 0x7B50, 0xBFF1, 0x72C2, 0xBFF2, 0x6846, 0xBFF3, 0x77FF, 0xBFF4, 0x7736, 0xBFF5, 0x65F7, 0xBFF6, 0x51B5, 0xBFF7, 0x4E8F, 0xBFF8, 0x76D4, 0xBFF9, 0x5CBF, 0xBFFA, 0x7AA5, 0xBFFB, 0x8475, 0xBFFC, 0x594E, 0xBFFD, 0x9B41, 0xBFFE, 0x5080, 0xC040, 0x7E5E, 0xC041, 0x7E5F, 0xC042, 0x7E60, 0xC043, 0x7E61, 0xC044, 0x7E62, 0xC045, 0x7E63, 0xC046, 0x7E64, 0xC047, 0x7E65, 0xC048, 0x7E66, 0xC049, 0x7E67, 0xC04A, 0x7E68, 0xC04B, 0x7E69, 0xC04C, 0x7E6A, 0xC04D, 0x7E6B, 0xC04E, 0x7E6C, 0xC04F, 0x7E6D, 0xC050, 0x7E6E, 0xC051, 0x7E6F, 0xC052, 0x7E70, 0xC053, 0x7E71, 0xC054, 0x7E72, 0xC055, 0x7E73, 0xC056, 0x7E74, 0xC057, 0x7E75, 0xC058, 0x7E76, 0xC059, 0x7E77, 0xC05A, 0x7E78, 0xC05B, 0x7E79, 0xC05C, 0x7E7A, 0xC05D, 0x7E7B, 0xC05E, 0x7E7C, 0xC05F, 0x7E7D, 0xC060, 0x7E7E, 0xC061, 0x7E7F, 0xC062, 0x7E80, 0xC063, 0x7E81, 0xC064, 0x7E83, 0xC065, 0x7E84, 0xC066, 0x7E85, 0xC067, 0x7E86, 0xC068, 0x7E87, 0xC069, 0x7E88, 0xC06A, 0x7E89, 0xC06B, 0x7E8A, 0xC06C, 0x7E8B, 0xC06D, 0x7E8C, 0xC06E, 0x7E8D, 0xC06F, 0x7E8E, 0xC070, 0x7E8F, 0xC071, 0x7E90, 0xC072, 0x7E91, 0xC073, 0x7E92, 0xC074, 0x7E93, 0xC075, 0x7E94, 0xC076, 0x7E95, 0xC077, 0x7E96, 0xC078, 0x7E97, 0xC079, 0x7E98, 0xC07A, 0x7E99, 0xC07B, 0x7E9A, 0xC07C, 0x7E9C, 0xC07D, 0x7E9D, 0xC07E, 0x7E9E, 0xC080, 0x7EAE, 0xC081, 0x7EB4, 0xC082, 0x7EBB, 0xC083, 0x7EBC, 0xC084, 0x7ED6, 0xC085, 0x7EE4, 0xC086, 0x7EEC, 0xC087, 0x7EF9, 0xC088, 0x7F0A, 0xC089, 0x7F10, 0xC08A, 0x7F1E, 0xC08B, 0x7F37, 0xC08C, 0x7F39, 0xC08D, 0x7F3B, 0xC08E, 0x7F3C, 0xC08F, 0x7F3D, 0xC090, 0x7F3E, 0xC091, 0x7F3F, 0xC092, 0x7F40, 0xC093, 0x7F41, 0xC094, 0x7F43, 0xC095, 0x7F46, 0xC096, 0x7F47, 0xC097, 0x7F48, 0xC098, 0x7F49, 0xC099, 0x7F4A, 0xC09A, 0x7F4B, 0xC09B, 0x7F4C, 0xC09C, 0x7F4D, 0xC09D, 0x7F4E, 0xC09E, 0x7F4F, 0xC09F, 0x7F52, 0xC0A0, 0x7F53, 0xC0A1, 0x9988, 0xC0A2, 0x6127, 0xC0A3, 0x6E83, 0xC0A4, 0x5764, 0xC0A5, 0x6606, 0xC0A6, 0x6346, 0xC0A7, 0x56F0, 0xC0A8, 0x62EC, 0xC0A9, 0x6269, 0xC0AA, 0x5ED3, 0xC0AB, 0x9614, 0xC0AC, 0x5783, 0xC0AD, 0x62C9, 0xC0AE, 0x5587, 0xC0AF, 0x8721, 0xC0B0, 0x814A, 0xC0B1, 0x8FA3, 0xC0B2, 0x5566, 0xC0B3, 0x83B1, 0xC0B4, 0x6765, 0xC0B5, 0x8D56, 0xC0B6, 0x84DD, 0xC0B7, 0x5A6A, 0xC0B8, 0x680F, 0xC0B9, 0x62E6, 0xC0BA, 0x7BEE, 0xC0BB, 0x9611, 0xC0BC, 0x5170, 0xC0BD, 0x6F9C, 0xC0BE, 0x8C30, 0xC0BF, 0x63FD, 0xC0C0, 0x89C8, 0xC0C1, 0x61D2, 0xC0C2, 0x7F06, 0xC0C3, 0x70C2, 0xC0C4, 0x6EE5, 0xC0C5, 0x7405, 0xC0C6, 0x6994, 0xC0C7, 0x72FC, 0xC0C8, 0x5ECA, 0xC0C9, 0x90CE, 0xC0CA, 0x6717, 0xC0CB, 0x6D6A, 0xC0CC, 0x635E, 0xC0CD, 0x52B3, 0xC0CE, 0x7262, 0xC0CF, 0x8001, 0xC0D0, 0x4F6C, 0xC0D1, 0x59E5, 0xC0D2, 0x916A, 0xC0D3, 0x70D9, 0xC0D4, 0x6D9D, 0xC0D5, 0x52D2, 0xC0D6, 0x4E50, 0xC0D7, 0x96F7, 0xC0D8, 0x956D, 0xC0D9, 0x857E, 0xC0DA, 0x78CA, 0xC0DB, 0x7D2F, 0xC0DC, 0x5121, 0xC0DD, 0x5792, 0xC0DE, 0x64C2, 0xC0DF, 0x808B, 0xC0E0, 0x7C7B, 0xC0E1, 0x6CEA, 0xC0E2, 0x68F1, 0xC0E3, 0x695E, 0xC0E4, 0x51B7, 0xC0E5, 0x5398, 0xC0E6, 0x68A8, 0xC0E7, 0x7281, 0xC0E8, 0x9ECE, 0xC0E9, 0x7BF1, 0xC0EA, 0x72F8, 0xC0EB, 0x79BB, 0xC0EC, 0x6F13, 0xC0ED, 0x7406, 0xC0EE, 0x674E, 0xC0EF, 0x91CC, 0xC0F0, 0x9CA4, 0xC0F1, 0x793C, 0xC0F2, 0x8389, 0xC0F3, 0x8354, 0xC0F4, 0x540F, 0xC0F5, 0x6817, 0xC0F6, 0x4E3D, 0xC0F7, 0x5389, 0xC0F8, 0x52B1, 0xC0F9, 0x783E, 0xC0FA, 0x5386, 0xC0FB, 0x5229, 0xC0FC, 0x5088, 0xC0FD, 0x4F8B, 0xC0FE, 0x4FD0, 0xC140, 0x7F56, 0xC141, 0x7F59, 0xC142, 0x7F5B, 0xC143, 0x7F5C, 0xC144, 0x7F5D, 0xC145, 0x7F5E, 0xC146, 0x7F60, 0xC147, 0x7F63, 0xC148, 0x7F64, 0xC149, 0x7F65, 0xC14A, 0x7F66, 0xC14B, 0x7F67, 0xC14C, 0x7F6B, 0xC14D, 0x7F6C, 0xC14E, 0x7F6D, 0xC14F, 0x7F6F, 0xC150, 0x7F70, 0xC151, 0x7F73, 0xC152, 0x7F75, 0xC153, 0x7F76, 0xC154, 0x7F77, 0xC155, 0x7F78, 0xC156, 0x7F7A, 0xC157, 0x7F7B, 0xC158, 0x7F7C, 0xC159, 0x7F7D, 0xC15A, 0x7F7F, 0xC15B, 0x7F80, 0xC15C, 0x7F82, 0xC15D, 0x7F83, 0xC15E, 0x7F84, 0xC15F, 0x7F85, 0xC160, 0x7F86, 0xC161, 0x7F87, 0xC162, 0x7F88, 0xC163, 0x7F89, 0xC164, 0x7F8B, 0xC165, 0x7F8D, 0xC166, 0x7F8F, 0xC167, 0x7F90, 0xC168, 0x7F91, 0xC169, 0x7F92, 0xC16A, 0x7F93, 0xC16B, 0x7F95, 0xC16C, 0x7F96, 0xC16D, 0x7F97, 0xC16E, 0x7F98, 0xC16F, 0x7F99, 0xC170, 0x7F9B, 0xC171, 0x7F9C, 0xC172, 0x7FA0, 0xC173, 0x7FA2, 0xC174, 0x7FA3, 0xC175, 0x7FA5, 0xC176, 0x7FA6, 0xC177, 0x7FA8, 0xC178, 0x7FA9, 0xC179, 0x7FAA, 0xC17A, 0x7FAB, 0xC17B, 0x7FAC, 0xC17C, 0x7FAD, 0xC17D, 0x7FAE, 0xC17E, 0x7FB1, 0xC180, 0x7FB3, 0xC181, 0x7FB4, 0xC182, 0x7FB5, 0xC183, 0x7FB6, 0xC184, 0x7FB7, 0xC185, 0x7FBA, 0xC186, 0x7FBB, 0xC187, 0x7FBE, 0xC188, 0x7FC0, 0xC189, 0x7FC2, 0xC18A, 0x7FC3, 0xC18B, 0x7FC4, 0xC18C, 0x7FC6, 0xC18D, 0x7FC7, 0xC18E, 0x7FC8, 0xC18F, 0x7FC9, 0xC190, 0x7FCB, 0xC191, 0x7FCD, 0xC192, 0x7FCF, 0xC193, 0x7FD0, 0xC194, 0x7FD1, 0xC195, 0x7FD2, 0xC196, 0x7FD3, 0xC197, 0x7FD6, 0xC198, 0x7FD7, 0xC199, 0x7FD9, 0xC19A, 0x7FDA, 0xC19B, 0x7FDB, 0xC19C, 0x7FDC, 0xC19D, 0x7FDD, 0xC19E, 0x7FDE, 0xC19F, 0x7FE2, 0xC1A0, 0x7FE3, 0xC1A1, 0x75E2, 0xC1A2, 0x7ACB, 0xC1A3, 0x7C92, 0xC1A4, 0x6CA5, 0xC1A5, 0x96B6, 0xC1A6, 0x529B, 0xC1A7, 0x7483, 0xC1A8, 0x54E9, 0xC1A9, 0x4FE9, 0xC1AA, 0x8054, 0xC1AB, 0x83B2, 0xC1AC, 0x8FDE, 0xC1AD, 0x9570, 0xC1AE, 0x5EC9, 0xC1AF, 0x601C, 0xC1B0, 0x6D9F, 0xC1B1, 0x5E18, 0xC1B2, 0x655B, 0xC1B3, 0x8138, 0xC1B4, 0x94FE, 0xC1B5, 0x604B, 0xC1B6, 0x70BC, 0xC1B7, 0x7EC3, 0xC1B8, 0x7CAE, 0xC1B9, 0x51C9, 0xC1BA, 0x6881, 0xC1BB, 0x7CB1, 0xC1BC, 0x826F, 0xC1BD, 0x4E24, 0xC1BE, 0x8F86, 0xC1BF, 0x91CF, 0xC1C0, 0x667E, 0xC1C1, 0x4EAE, 0xC1C2, 0x8C05, 0xC1C3, 0x64A9, 0xC1C4, 0x804A, 0xC1C5, 0x50DA, 0xC1C6, 0x7597, 0xC1C7, 0x71CE, 0xC1C8, 0x5BE5, 0xC1C9, 0x8FBD, 0xC1CA, 0x6F66, 0xC1CB, 0x4E86, 0xC1CC, 0x6482, 0xC1CD, 0x9563, 0xC1CE, 0x5ED6, 0xC1CF, 0x6599, 0xC1D0, 0x5217, 0xC1D1, 0x88C2, 0xC1D2, 0x70C8, 0xC1D3, 0x52A3, 0xC1D4, 0x730E, 0xC1D5, 0x7433, 0xC1D6, 0x6797, 0xC1D7, 0x78F7, 0xC1D8, 0x9716, 0xC1D9, 0x4E34, 0xC1DA, 0x90BB, 0xC1DB, 0x9CDE, 0xC1DC, 0x6DCB, 0xC1DD, 0x51DB, 0xC1DE, 0x8D41, 0xC1DF, 0x541D, 0xC1E0, 0x62CE, 0xC1E1, 0x73B2, 0xC1E2, 0x83F1, 0xC1E3, 0x96F6, 0xC1E4, 0x9F84, 0xC1E5, 0x94C3, 0xC1E6, 0x4F36, 0xC1E7, 0x7F9A, 0xC1E8, 0x51CC, 0xC1E9, 0x7075, 0xC1EA, 0x9675, 0xC1EB, 0x5CAD, 0xC1EC, 0x9886, 0xC1ED, 0x53E6, 0xC1EE, 0x4EE4, 0xC1EF, 0x6E9C, 0xC1F0, 0x7409, 0xC1F1, 0x69B4, 0xC1F2, 0x786B, 0xC1F3, 0x998F, 0xC1F4, 0x7559, 0xC1F5, 0x5218, 0xC1F6, 0x7624, 0xC1F7, 0x6D41, 0xC1F8, 0x67F3, 0xC1F9, 0x516D, 0xC1FA, 0x9F99, 0xC1FB, 0x804B, 0xC1FC, 0x5499, 0xC1FD, 0x7B3C, 0xC1FE, 0x7ABF, 0xC240, 0x7FE4, 0xC241, 0x7FE7, 0xC242, 0x7FE8, 0xC243, 0x7FEA, 0xC244, 0x7FEB, 0xC245, 0x7FEC, 0xC246, 0x7FED, 0xC247, 0x7FEF, 0xC248, 0x7FF2, 0xC249, 0x7FF4, 0xC24A, 0x7FF5, 0xC24B, 0x7FF6, 0xC24C, 0x7FF7, 0xC24D, 0x7FF8, 0xC24E, 0x7FF9, 0xC24F, 0x7FFA, 0xC250, 0x7FFD, 0xC251, 0x7FFE, 0xC252, 0x7FFF, 0xC253, 0x8002, 0xC254, 0x8007, 0xC255, 0x8008, 0xC256, 0x8009, 0xC257, 0x800A, 0xC258, 0x800E, 0xC259, 0x800F, 0xC25A, 0x8011, 0xC25B, 0x8013, 0xC25C, 0x801A, 0xC25D, 0x801B, 0xC25E, 0x801D, 0xC25F, 0x801E, 0xC260, 0x801F, 0xC261, 0x8021, 0xC262, 0x8023, 0xC263, 0x8024, 0xC264, 0x802B, 0xC265, 0x802C, 0xC266, 0x802D, 0xC267, 0x802E, 0xC268, 0x802F, 0xC269, 0x8030, 0xC26A, 0x8032, 0xC26B, 0x8034, 0xC26C, 0x8039, 0xC26D, 0x803A, 0xC26E, 0x803C, 0xC26F, 0x803E, 0xC270, 0x8040, 0xC271, 0x8041, 0xC272, 0x8044, 0xC273, 0x8045, 0xC274, 0x8047, 0xC275, 0x8048, 0xC276, 0x8049, 0xC277, 0x804E, 0xC278, 0x804F, 0xC279, 0x8050, 0xC27A, 0x8051, 0xC27B, 0x8053, 0xC27C, 0x8055, 0xC27D, 0x8056, 0xC27E, 0x8057, 0xC280, 0x8059, 0xC281, 0x805B, 0xC282, 0x805C, 0xC283, 0x805D, 0xC284, 0x805E, 0xC285, 0x805F, 0xC286, 0x8060, 0xC287, 0x8061, 0xC288, 0x8062, 0xC289, 0x8063, 0xC28A, 0x8064, 0xC28B, 0x8065, 0xC28C, 0x8066, 0xC28D, 0x8067, 0xC28E, 0x8068, 0xC28F, 0x806B, 0xC290, 0x806C, 0xC291, 0x806D, 0xC292, 0x806E, 0xC293, 0x806F, 0xC294, 0x8070, 0xC295, 0x8072, 0xC296, 0x8073, 0xC297, 0x8074, 0xC298, 0x8075, 0xC299, 0x8076, 0xC29A, 0x8077, 0xC29B, 0x8078, 0xC29C, 0x8079, 0xC29D, 0x807A, 0xC29E, 0x807B, 0xC29F, 0x807C, 0xC2A0, 0x807D, 0xC2A1, 0x9686, 0xC2A2, 0x5784, 0xC2A3, 0x62E2, 0xC2A4, 0x9647, 0xC2A5, 0x697C, 0xC2A6, 0x5A04, 0xC2A7, 0x6402, 0xC2A8, 0x7BD3, 0xC2A9, 0x6F0F, 0xC2AA, 0x964B, 0xC2AB, 0x82A6, 0xC2AC, 0x5362, 0xC2AD, 0x9885, 0xC2AE, 0x5E90, 0xC2AF, 0x7089, 0xC2B0, 0x63B3, 0xC2B1, 0x5364, 0xC2B2, 0x864F, 0xC2B3, 0x9C81, 0xC2B4, 0x9E93, 0xC2B5, 0x788C, 0xC2B6, 0x9732, 0xC2B7, 0x8DEF, 0xC2B8, 0x8D42, 0xC2B9, 0x9E7F, 0xC2BA, 0x6F5E, 0xC2BB, 0x7984, 0xC2BC, 0x5F55, 0xC2BD, 0x9646, 0xC2BE, 0x622E, 0xC2BF, 0x9A74, 0xC2C0, 0x5415, 0xC2C1, 0x94DD, 0xC2C2, 0x4FA3, 0xC2C3, 0x65C5, 0xC2C4, 0x5C65, 0xC2C5, 0x5C61, 0xC2C6, 0x7F15, 0xC2C7, 0x8651, 0xC2C8, 0x6C2F, 0xC2C9, 0x5F8B, 0xC2CA, 0x7387, 0xC2CB, 0x6EE4, 0xC2CC, 0x7EFF, 0xC2CD, 0x5CE6, 0xC2CE, 0x631B, 0xC2CF, 0x5B6A, 0xC2D0, 0x6EE6, 0xC2D1, 0x5375, 0xC2D2, 0x4E71, 0xC2D3, 0x63A0, 0xC2D4, 0x7565, 0xC2D5, 0x62A1, 0xC2D6, 0x8F6E, 0xC2D7, 0x4F26, 0xC2D8, 0x4ED1, 0xC2D9, 0x6CA6, 0xC2DA, 0x7EB6, 0xC2DB, 0x8BBA, 0xC2DC, 0x841D, 0xC2DD, 0x87BA, 0xC2DE, 0x7F57, 0xC2DF, 0x903B, 0xC2E0, 0x9523, 0xC2E1, 0x7BA9, 0xC2E2, 0x9AA1, 0xC2E3, 0x88F8, 0xC2E4, 0x843D, 0xC2E5, 0x6D1B, 0xC2E6, 0x9A86, 0xC2E7, 0x7EDC, 0xC2E8, 0x5988, 0xC2E9, 0x9EBB, 0xC2EA, 0x739B, 0xC2EB, 0x7801, 0xC2EC, 0x8682, 0xC2ED, 0x9A6C, 0xC2EE, 0x9A82, 0xC2EF, 0x561B, 0xC2F0, 0x5417, 0xC2F1, 0x57CB, 0xC2F2, 0x4E70, 0xC2F3, 0x9EA6, 0xC2F4, 0x5356, 0xC2F5, 0x8FC8, 0xC2F6, 0x8109, 0xC2F7, 0x7792, 0xC2F8, 0x9992, 0xC2F9, 0x86EE, 0xC2FA, 0x6EE1, 0xC2FB, 0x8513, 0xC2FC, 0x66FC, 0xC2FD, 0x6162, 0xC2FE, 0x6F2B, 0xC340, 0x807E, 0xC341, 0x8081, 0xC342, 0x8082, 0xC343, 0x8085, 0xC344, 0x8088, 0xC345, 0x808A, 0xC346, 0x808D, 0xC347, 0x808E, 0xC348, 0x808F, 0xC349, 0x8090, 0xC34A, 0x8091, 0xC34B, 0x8092, 0xC34C, 0x8094, 0xC34D, 0x8095, 0xC34E, 0x8097, 0xC34F, 0x8099, 0xC350, 0x809E, 0xC351, 0x80A3, 0xC352, 0x80A6, 0xC353, 0x80A7, 0xC354, 0x80A8, 0xC355, 0x80AC, 0xC356, 0x80B0, 0xC357, 0x80B3, 0xC358, 0x80B5, 0xC359, 0x80B6, 0xC35A, 0x80B8, 0xC35B, 0x80B9, 0xC35C, 0x80BB, 0xC35D, 0x80C5, 0xC35E, 0x80C7, 0xC35F, 0x80C8, 0xC360, 0x80C9, 0xC361, 0x80CA, 0xC362, 0x80CB, 0xC363, 0x80CF, 0xC364, 0x80D0, 0xC365, 0x80D1, 0xC366, 0x80D2, 0xC367, 0x80D3, 0xC368, 0x80D4, 0xC369, 0x80D5, 0xC36A, 0x80D8, 0xC36B, 0x80DF, 0xC36C, 0x80E0, 0xC36D, 0x80E2, 0xC36E, 0x80E3, 0xC36F, 0x80E6, 0xC370, 0x80EE, 0xC371, 0x80F5, 0xC372, 0x80F7, 0xC373, 0x80F9, 0xC374, 0x80FB, 0xC375, 0x80FE, 0xC376, 0x80FF, 0xC377, 0x8100, 0xC378, 0x8101, 0xC379, 0x8103, 0xC37A, 0x8104, 0xC37B, 0x8105, 0xC37C, 0x8107, 0xC37D, 0x8108, 0xC37E, 0x810B, 0xC380, 0x810C, 0xC381, 0x8115, 0xC382, 0x8117, 0xC383, 0x8119, 0xC384, 0x811B, 0xC385, 0x811C, 0xC386, 0x811D, 0xC387, 0x811F, 0xC388, 0x8120, 0xC389, 0x8121, 0xC38A, 0x8122, 0xC38B, 0x8123, 0xC38C, 0x8124, 0xC38D, 0x8125, 0xC38E, 0x8126, 0xC38F, 0x8127, 0xC390, 0x8128, 0xC391, 0x8129, 0xC392, 0x812A, 0xC393, 0x812B, 0xC394, 0x812D, 0xC395, 0x812E, 0xC396, 0x8130, 0xC397, 0x8133, 0xC398, 0x8134, 0xC399, 0x8135, 0xC39A, 0x8137, 0xC39B, 0x8139, 0xC39C, 0x813A, 0xC39D, 0x813B, 0xC39E, 0x813C, 0xC39F, 0x813D, 0xC3A0, 0x813F, 0xC3A1, 0x8C29, 0xC3A2, 0x8292, 0xC3A3, 0x832B, 0xC3A4, 0x76F2, 0xC3A5, 0x6C13, 0xC3A6, 0x5FD9, 0xC3A7, 0x83BD, 0xC3A8, 0x732B, 0xC3A9, 0x8305, 0xC3AA, 0x951A, 0xC3AB, 0x6BDB, 0xC3AC, 0x77DB, 0xC3AD, 0x94C6, 0xC3AE, 0x536F, 0xC3AF, 0x8302, 0xC3B0, 0x5192, 0xC3B1, 0x5E3D, 0xC3B2, 0x8C8C, 0xC3B3, 0x8D38, 0xC3B4, 0x4E48, 0xC3B5, 0x73AB, 0xC3B6, 0x679A, 0xC3B7, 0x6885, 0xC3B8, 0x9176, 0xC3B9, 0x9709, 0xC3BA, 0x7164, 0xC3BB, 0x6CA1, 0xC3BC, 0x7709, 0xC3BD, 0x5A92, 0xC3BE, 0x9541, 0xC3BF, 0x6BCF, 0xC3C0, 0x7F8E, 0xC3C1, 0x6627, 0xC3C2, 0x5BD0, 0xC3C3, 0x59B9, 0xC3C4, 0x5A9A, 0xC3C5, 0x95E8, 0xC3C6, 0x95F7, 0xC3C7, 0x4EEC, 0xC3C8, 0x840C, 0xC3C9, 0x8499, 0xC3CA, 0x6AAC, 0xC3CB, 0x76DF, 0xC3CC, 0x9530, 0xC3CD, 0x731B, 0xC3CE, 0x68A6, 0xC3CF, 0x5B5F, 0xC3D0, 0x772F, 0xC3D1, 0x919A, 0xC3D2, 0x9761, 0xC3D3, 0x7CDC, 0xC3D4, 0x8FF7, 0xC3D5, 0x8C1C, 0xC3D6, 0x5F25, 0xC3D7, 0x7C73, 0xC3D8, 0x79D8, 0xC3D9, 0x89C5, 0xC3DA, 0x6CCC, 0xC3DB, 0x871C, 0xC3DC, 0x5BC6, 0xC3DD, 0x5E42, 0xC3DE, 0x68C9, 0xC3DF, 0x7720, 0xC3E0, 0x7EF5, 0xC3E1, 0x5195, 0xC3E2, 0x514D, 0xC3E3, 0x52C9, 0xC3E4, 0x5A29, 0xC3E5, 0x7F05, 0xC3E6, 0x9762, 0xC3E7, 0x82D7, 0xC3E8, 0x63CF, 0xC3E9, 0x7784, 0xC3EA, 0x85D0, 0xC3EB, 0x79D2, 0xC3EC, 0x6E3A, 0xC3ED, 0x5E99, 0xC3EE, 0x5999, 0xC3EF, 0x8511, 0xC3F0, 0x706D, 0xC3F1, 0x6C11, 0xC3F2, 0x62BF, 0xC3F3, 0x76BF, 0xC3F4, 0x654F, 0xC3F5, 0x60AF, 0xC3F6, 0x95FD, 0xC3F7, 0x660E, 0xC3F8, 0x879F, 0xC3F9, 0x9E23, 0xC3FA, 0x94ED, 0xC3FB, 0x540D, 0xC3FC, 0x547D, 0xC3FD, 0x8C2C, 0xC3FE, 0x6478, 0xC440, 0x8140, 0xC441, 0x8141, 0xC442, 0x8142, 0xC443, 0x8143, 0xC444, 0x8144, 0xC445, 0x8145, 0xC446, 0x8147, 0xC447, 0x8149, 0xC448, 0x814D, 0xC449, 0x814E, 0xC44A, 0x814F, 0xC44B, 0x8152, 0xC44C, 0x8156, 0xC44D, 0x8157, 0xC44E, 0x8158, 0xC44F, 0x815B, 0xC450, 0x815C, 0xC451, 0x815D, 0xC452, 0x815E, 0xC453, 0x815F, 0xC454, 0x8161, 0xC455, 0x8162, 0xC456, 0x8163, 0xC457, 0x8164, 0xC458, 0x8166, 0xC459, 0x8168, 0xC45A, 0x816A, 0xC45B, 0x816B, 0xC45C, 0x816C, 0xC45D, 0x816F, 0xC45E, 0x8172, 0xC45F, 0x8173, 0xC460, 0x8175, 0xC461, 0x8176, 0xC462, 0x8177, 0xC463, 0x8178, 0xC464, 0x8181, 0xC465, 0x8183, 0xC466, 0x8184, 0xC467, 0x8185, 0xC468, 0x8186, 0xC469, 0x8187, 0xC46A, 0x8189, 0xC46B, 0x818B, 0xC46C, 0x818C, 0xC46D, 0x818D, 0xC46E, 0x818E, 0xC46F, 0x8190, 0xC470, 0x8192, 0xC471, 0x8193, 0xC472, 0x8194, 0xC473, 0x8195, 0xC474, 0x8196, 0xC475, 0x8197, 0xC476, 0x8199, 0xC477, 0x819A, 0xC478, 0x819E, 0xC479, 0x819F, 0xC47A, 0x81A0, 0xC47B, 0x81A1, 0xC47C, 0x81A2, 0xC47D, 0x81A4, 0xC47E, 0x81A5, 0xC480, 0x81A7, 0xC481, 0x81A9, 0xC482, 0x81AB, 0xC483, 0x81AC, 0xC484, 0x81AD, 0xC485, 0x81AE, 0xC486, 0x81AF, 0xC487, 0x81B0, 0xC488, 0x81B1, 0xC489, 0x81B2, 0xC48A, 0x81B4, 0xC48B, 0x81B5, 0xC48C, 0x81B6, 0xC48D, 0x81B7, 0xC48E, 0x81B8, 0xC48F, 0x81B9, 0xC490, 0x81BC, 0xC491, 0x81BD, 0xC492, 0x81BE, 0xC493, 0x81BF, 0xC494, 0x81C4, 0xC495, 0x81C5, 0xC496, 0x81C7, 0xC497, 0x81C8, 0xC498, 0x81C9, 0xC499, 0x81CB, 0xC49A, 0x81CD, 0xC49B, 0x81CE, 0xC49C, 0x81CF, 0xC49D, 0x81D0, 0xC49E, 0x81D1, 0xC49F, 0x81D2, 0xC4A0, 0x81D3, 0xC4A1, 0x6479, 0xC4A2, 0x8611, 0xC4A3, 0x6A21, 0xC4A4, 0x819C, 0xC4A5, 0x78E8, 0xC4A6, 0x6469, 0xC4A7, 0x9B54, 0xC4A8, 0x62B9, 0xC4A9, 0x672B, 0xC4AA, 0x83AB, 0xC4AB, 0x58A8, 0xC4AC, 0x9ED8, 0xC4AD, 0x6CAB, 0xC4AE, 0x6F20, 0xC4AF, 0x5BDE, 0xC4B0, 0x964C, 0xC4B1, 0x8C0B, 0xC4B2, 0x725F, 0xC4B3, 0x67D0, 0xC4B4, 0x62C7, 0xC4B5, 0x7261, 0xC4B6, 0x4EA9, 0xC4B7, 0x59C6, 0xC4B8, 0x6BCD, 0xC4B9, 0x5893, 0xC4BA, 0x66AE, 0xC4BB, 0x5E55, 0xC4BC, 0x52DF, 0xC4BD, 0x6155, 0xC4BE, 0x6728, 0xC4BF, 0x76EE, 0xC4C0, 0x7766, 0xC4C1, 0x7267, 0xC4C2, 0x7A46, 0xC4C3, 0x62FF, 0xC4C4, 0x54EA, 0xC4C5, 0x5450, 0xC4C6, 0x94A0, 0xC4C7, 0x90A3, 0xC4C8, 0x5A1C, 0xC4C9, 0x7EB3, 0xC4CA, 0x6C16, 0xC4CB, 0x4E43, 0xC4CC, 0x5976, 0xC4CD, 0x8010, 0xC4CE, 0x5948, 0xC4CF, 0x5357, 0xC4D0, 0x7537, 0xC4D1, 0x96BE, 0xC4D2, 0x56CA, 0xC4D3, 0x6320, 0xC4D4, 0x8111, 0xC4D5, 0x607C, 0xC4D6, 0x95F9, 0xC4D7, 0x6DD6, 0xC4D8, 0x5462, 0xC4D9, 0x9981, 0xC4DA, 0x5185, 0xC4DB, 0x5AE9, 0xC4DC, 0x80FD, 0xC4DD, 0x59AE, 0xC4DE, 0x9713, 0xC4DF, 0x502A, 0xC4E0, 0x6CE5, 0xC4E1, 0x5C3C, 0xC4E2, 0x62DF, 0xC4E3, 0x4F60, 0xC4E4, 0x533F, 0xC4E5, 0x817B, 0xC4E6, 0x9006, 0xC4E7, 0x6EBA, 0xC4E8, 0x852B, 0xC4E9, 0x62C8, 0xC4EA, 0x5E74, 0xC4EB, 0x78BE, 0xC4EC, 0x64B5, 0xC4ED, 0x637B, 0xC4EE, 0x5FF5, 0xC4EF, 0x5A18, 0xC4F0, 0x917F, 0xC4F1, 0x9E1F, 0xC4F2, 0x5C3F, 0xC4F3, 0x634F, 0xC4F4, 0x8042, 0xC4F5, 0x5B7D, 0xC4F6, 0x556E, 0xC4F7, 0x954A, 0xC4F8, 0x954D, 0xC4F9, 0x6D85, 0xC4FA, 0x60A8, 0xC4FB, 0x67E0, 0xC4FC, 0x72DE, 0xC4FD, 0x51DD, 0xC4FE, 0x5B81, 0xC540, 0x81D4, 0xC541, 0x81D5, 0xC542, 0x81D6, 0xC543, 0x81D7, 0xC544, 0x81D8, 0xC545, 0x81D9, 0xC546, 0x81DA, 0xC547, 0x81DB, 0xC548, 0x81DC, 0xC549, 0x81DD, 0xC54A, 0x81DE, 0xC54B, 0x81DF, 0xC54C, 0x81E0, 0xC54D, 0x81E1, 0xC54E, 0x81E2, 0xC54F, 0x81E4, 0xC550, 0x81E5, 0xC551, 0x81E6, 0xC552, 0x81E8, 0xC553, 0x81E9, 0xC554, 0x81EB, 0xC555, 0x81EE, 0xC556, 0x81EF, 0xC557, 0x81F0, 0xC558, 0x81F1, 0xC559, 0x81F2, 0xC55A, 0x81F5, 0xC55B, 0x81F6, 0xC55C, 0x81F7, 0xC55D, 0x81F8, 0xC55E, 0x81F9, 0xC55F, 0x81FA, 0xC560, 0x81FD, 0xC561, 0x81FF, 0xC562, 0x8203, 0xC563, 0x8207, 0xC564, 0x8208, 0xC565, 0x8209, 0xC566, 0x820A, 0xC567, 0x820B, 0xC568, 0x820E, 0xC569, 0x820F, 0xC56A, 0x8211, 0xC56B, 0x8213, 0xC56C, 0x8215, 0xC56D, 0x8216, 0xC56E, 0x8217, 0xC56F, 0x8218, 0xC570, 0x8219, 0xC571, 0x821A, 0xC572, 0x821D, 0xC573, 0x8220, 0xC574, 0x8224, 0xC575, 0x8225, 0xC576, 0x8226, 0xC577, 0x8227, 0xC578, 0x8229, 0xC579, 0x822E, 0xC57A, 0x8232, 0xC57B, 0x823A, 0xC57C, 0x823C, 0xC57D, 0x823D, 0xC57E, 0x823F, 0xC580, 0x8240, 0xC581, 0x8241, 0xC582, 0x8242, 0xC583, 0x8243, 0xC584, 0x8245, 0xC585, 0x8246, 0xC586, 0x8248, 0xC587, 0x824A, 0xC588, 0x824C, 0xC589, 0x824D, 0xC58A, 0x824E, 0xC58B, 0x8250, 0xC58C, 0x8251, 0xC58D, 0x8252, 0xC58E, 0x8253, 0xC58F, 0x8254, 0xC590, 0x8255, 0xC591, 0x8256, 0xC592, 0x8257, 0xC593, 0x8259, 0xC594, 0x825B, 0xC595, 0x825C, 0xC596, 0x825D, 0xC597, 0x825E, 0xC598, 0x8260, 0xC599, 0x8261, 0xC59A, 0x8262, 0xC59B, 0x8263, 0xC59C, 0x8264, 0xC59D, 0x8265, 0xC59E, 0x8266, 0xC59F, 0x8267, 0xC5A0, 0x8269, 0xC5A1, 0x62E7, 0xC5A2, 0x6CDE, 0xC5A3, 0x725B, 0xC5A4, 0x626D, 0xC5A5, 0x94AE, 0xC5A6, 0x7EBD, 0xC5A7, 0x8113, 0xC5A8, 0x6D53, 0xC5A9, 0x519C, 0xC5AA, 0x5F04, 0xC5AB, 0x5974, 0xC5AC, 0x52AA, 0xC5AD, 0x6012, 0xC5AE, 0x5973, 0xC5AF, 0x6696, 0xC5B0, 0x8650, 0xC5B1, 0x759F, 0xC5B2, 0x632A, 0xC5B3, 0x61E6, 0xC5B4, 0x7CEF, 0xC5B5, 0x8BFA, 0xC5B6, 0x54E6, 0xC5B7, 0x6B27, 0xC5B8, 0x9E25, 0xC5B9, 0x6BB4, 0xC5BA, 0x85D5, 0xC5BB, 0x5455, 0xC5BC, 0x5076, 0xC5BD, 0x6CA4, 0xC5BE, 0x556A, 0xC5BF, 0x8DB4, 0xC5C0, 0x722C, 0xC5C1, 0x5E15, 0xC5C2, 0x6015, 0xC5C3, 0x7436, 0xC5C4, 0x62CD, 0xC5C5, 0x6392, 0xC5C6, 0x724C, 0xC5C7, 0x5F98, 0xC5C8, 0x6E43, 0xC5C9, 0x6D3E, 0xC5CA, 0x6500, 0xC5CB, 0x6F58, 0xC5CC, 0x76D8, 0xC5CD, 0x78D0, 0xC5CE, 0x76FC, 0xC5CF, 0x7554, 0xC5D0, 0x5224, 0xC5D1, 0x53DB, 0xC5D2, 0x4E53, 0xC5D3, 0x5E9E, 0xC5D4, 0x65C1, 0xC5D5, 0x802A, 0xC5D6, 0x80D6, 0xC5D7, 0x629B, 0xC5D8, 0x5486, 0xC5D9, 0x5228, 0xC5DA, 0x70AE, 0xC5DB, 0x888D, 0xC5DC, 0x8DD1, 0xC5DD, 0x6CE1, 0xC5DE, 0x5478, 0xC5DF, 0x80DA, 0xC5E0, 0x57F9, 0xC5E1, 0x88F4, 0xC5E2, 0x8D54, 0xC5E3, 0x966A, 0xC5E4, 0x914D, 0xC5E5, 0x4F69, 0xC5E6, 0x6C9B, 0xC5E7, 0x55B7, 0xC5E8, 0x76C6, 0xC5E9, 0x7830, 0xC5EA, 0x62A8, 0xC5EB, 0x70F9, 0xC5EC, 0x6F8E, 0xC5ED, 0x5F6D, 0xC5EE, 0x84EC, 0xC5EF, 0x68DA, 0xC5F0, 0x787C, 0xC5F1, 0x7BF7, 0xC5F2, 0x81A8, 0xC5F3, 0x670B, 0xC5F4, 0x9E4F, 0xC5F5, 0x6367, 0xC5F6, 0x78B0, 0xC5F7, 0x576F, 0xC5F8, 0x7812, 0xC5F9, 0x9739, 0xC5FA, 0x6279, 0xC5FB, 0x62AB, 0xC5FC, 0x5288, 0xC5FD, 0x7435, 0xC5FE, 0x6BD7, 0xC640, 0x826A, 0xC641, 0x826B, 0xC642, 0x826C, 0xC643, 0x826D, 0xC644, 0x8271, 0xC645, 0x8275, 0xC646, 0x8276, 0xC647, 0x8277, 0xC648, 0x8278, 0xC649, 0x827B, 0xC64A, 0x827C, 0xC64B, 0x8280, 0xC64C, 0x8281, 0xC64D, 0x8283, 0xC64E, 0x8285, 0xC64F, 0x8286, 0xC650, 0x8287, 0xC651, 0x8289, 0xC652, 0x828C, 0xC653, 0x8290, 0xC654, 0x8293, 0xC655, 0x8294, 0xC656, 0x8295, 0xC657, 0x8296, 0xC658, 0x829A, 0xC659, 0x829B, 0xC65A, 0x829E, 0xC65B, 0x82A0, 0xC65C, 0x82A2, 0xC65D, 0x82A3, 0xC65E, 0x82A7, 0xC65F, 0x82B2, 0xC660, 0x82B5, 0xC661, 0x82B6, 0xC662, 0x82BA, 0xC663, 0x82BB, 0xC664, 0x82BC, 0xC665, 0x82BF, 0xC666, 0x82C0, 0xC667, 0x82C2, 0xC668, 0x82C3, 0xC669, 0x82C5, 0xC66A, 0x82C6, 0xC66B, 0x82C9, 0xC66C, 0x82D0, 0xC66D, 0x82D6, 0xC66E, 0x82D9, 0xC66F, 0x82DA, 0xC670, 0x82DD, 0xC671, 0x82E2, 0xC672, 0x82E7, 0xC673, 0x82E8, 0xC674, 0x82E9, 0xC675, 0x82EA, 0xC676, 0x82EC, 0xC677, 0x82ED, 0xC678, 0x82EE, 0xC679, 0x82F0, 0xC67A, 0x82F2, 0xC67B, 0x82F3, 0xC67C, 0x82F5, 0xC67D, 0x82F6, 0xC67E, 0x82F8, 0xC680, 0x82FA, 0xC681, 0x82FC, 0xC682, 0x82FD, 0xC683, 0x82FE, 0xC684, 0x82FF, 0xC685, 0x8300, 0xC686, 0x830A, 0xC687, 0x830B, 0xC688, 0x830D, 0xC689, 0x8310, 0xC68A, 0x8312, 0xC68B, 0x8313, 0xC68C, 0x8316, 0xC68D, 0x8318, 0xC68E, 0x8319, 0xC68F, 0x831D, 0xC690, 0x831E, 0xC691, 0x831F, 0xC692, 0x8320, 0xC693, 0x8321, 0xC694, 0x8322, 0xC695, 0x8323, 0xC696, 0x8324, 0xC697, 0x8325, 0xC698, 0x8326, 0xC699, 0x8329, 0xC69A, 0x832A, 0xC69B, 0x832E, 0xC69C, 0x8330, 0xC69D, 0x8332, 0xC69E, 0x8337, 0xC69F, 0x833B, 0xC6A0, 0x833D, 0xC6A1, 0x5564, 0xC6A2, 0x813E, 0xC6A3, 0x75B2, 0xC6A4, 0x76AE, 0xC6A5, 0x5339, 0xC6A6, 0x75DE, 0xC6A7, 0x50FB, 0xC6A8, 0x5C41, 0xC6A9, 0x8B6C, 0xC6AA, 0x7BC7, 0xC6AB, 0x504F, 0xC6AC, 0x7247, 0xC6AD, 0x9A97, 0xC6AE, 0x98D8, 0xC6AF, 0x6F02, 0xC6B0, 0x74E2, 0xC6B1, 0x7968, 0xC6B2, 0x6487, 0xC6B3, 0x77A5, 0xC6B4, 0x62FC, 0xC6B5, 0x9891, 0xC6B6, 0x8D2B, 0xC6B7, 0x54C1, 0xC6B8, 0x8058, 0xC6B9, 0x4E52, 0xC6BA, 0x576A, 0xC6BB, 0x82F9, 0xC6BC, 0x840D, 0xC6BD, 0x5E73, 0xC6BE, 0x51ED, 0xC6BF, 0x74F6, 0xC6C0, 0x8BC4, 0xC6C1, 0x5C4F, 0xC6C2, 0x5761, 0xC6C3, 0x6CFC, 0xC6C4, 0x9887, 0xC6C5, 0x5A46, 0xC6C6, 0x7834, 0xC6C7, 0x9B44, 0xC6C8, 0x8FEB, 0xC6C9, 0x7C95, 0xC6CA, 0x5256, 0xC6CB, 0x6251, 0xC6CC, 0x94FA, 0xC6CD, 0x4EC6, 0xC6CE, 0x8386, 0xC6CF, 0x8461, 0xC6D0, 0x83E9, 0xC6D1, 0x84B2, 0xC6D2, 0x57D4, 0xC6D3, 0x6734, 0xC6D4, 0x5703, 0xC6D5, 0x666E, 0xC6D6, 0x6D66, 0xC6D7, 0x8C31, 0xC6D8, 0x66DD, 0xC6D9, 0x7011, 0xC6DA, 0x671F, 0xC6DB, 0x6B3A, 0xC6DC, 0x6816, 0xC6DD, 0x621A, 0xC6DE, 0x59BB, 0xC6DF, 0x4E03, 0xC6E0, 0x51C4, 0xC6E1, 0x6F06, 0xC6E2, 0x67D2, 0xC6E3, 0x6C8F, 0xC6E4, 0x5176, 0xC6E5, 0x68CB, 0xC6E6, 0x5947, 0xC6E7, 0x6B67, 0xC6E8, 0x7566, 0xC6E9, 0x5D0E, 0xC6EA, 0x8110, 0xC6EB, 0x9F50, 0xC6EC, 0x65D7, 0xC6ED, 0x7948, 0xC6EE, 0x7941, 0xC6EF, 0x9A91, 0xC6F0, 0x8D77, 0xC6F1, 0x5C82, 0xC6F2, 0x4E5E, 0xC6F3, 0x4F01, 0xC6F4, 0x542F, 0xC6F5, 0x5951, 0xC6F6, 0x780C, 0xC6F7, 0x5668, 0xC6F8, 0x6C14, 0xC6F9, 0x8FC4, 0xC6FA, 0x5F03, 0xC6FB, 0x6C7D, 0xC6FC, 0x6CE3, 0xC6FD, 0x8BAB, 0xC6FE, 0x6390, 0xC740, 0x833E, 0xC741, 0x833F, 0xC742, 0x8341, 0xC743, 0x8342, 0xC744, 0x8344, 0xC745, 0x8345, 0xC746, 0x8348, 0xC747, 0x834A, 0xC748, 0x834B, 0xC749, 0x834C, 0xC74A, 0x834D, 0xC74B, 0x834E, 0xC74C, 0x8353, 0xC74D, 0x8355, 0xC74E, 0x8356, 0xC74F, 0x8357, 0xC750, 0x8358, 0xC751, 0x8359, 0xC752, 0x835D, 0xC753, 0x8362, 0xC754, 0x8370, 0xC755, 0x8371, 0xC756, 0x8372, 0xC757, 0x8373, 0xC758, 0x8374, 0xC759, 0x8375, 0xC75A, 0x8376, 0xC75B, 0x8379, 0xC75C, 0x837A, 0xC75D, 0x837E, 0xC75E, 0x837F, 0xC75F, 0x8380, 0xC760, 0x8381, 0xC761, 0x8382, 0xC762, 0x8383, 0xC763, 0x8384, 0xC764, 0x8387, 0xC765, 0x8388, 0xC766, 0x838A, 0xC767, 0x838B, 0xC768, 0x838C, 0xC769, 0x838D, 0xC76A, 0x838F, 0xC76B, 0x8390, 0xC76C, 0x8391, 0xC76D, 0x8394, 0xC76E, 0x8395, 0xC76F, 0x8396, 0xC770, 0x8397, 0xC771, 0x8399, 0xC772, 0x839A, 0xC773, 0x839D, 0xC774, 0x839F, 0xC775, 0x83A1, 0xC776, 0x83A2, 0xC777, 0x83A3, 0xC778, 0x83A4, 0xC779, 0x83A5, 0xC77A, 0x83A6, 0xC77B, 0x83A7, 0xC77C, 0x83AC, 0xC77D, 0x83AD, 0xC77E, 0x83AE, 0xC780, 0x83AF, 0xC781, 0x83B5, 0xC782, 0x83BB, 0xC783, 0x83BE, 0xC784, 0x83BF, 0xC785, 0x83C2, 0xC786, 0x83C3, 0xC787, 0x83C4, 0xC788, 0x83C6, 0xC789, 0x83C8, 0xC78A, 0x83C9, 0xC78B, 0x83CB, 0xC78C, 0x83CD, 0xC78D, 0x83CE, 0xC78E, 0x83D0, 0xC78F, 0x83D1, 0xC790, 0x83D2, 0xC791, 0x83D3, 0xC792, 0x83D5, 0xC793, 0x83D7, 0xC794, 0x83D9, 0xC795, 0x83DA, 0xC796, 0x83DB, 0xC797, 0x83DE, 0xC798, 0x83E2, 0xC799, 0x83E3, 0xC79A, 0x83E4, 0xC79B, 0x83E6, 0xC79C, 0x83E7, 0xC79D, 0x83E8, 0xC79E, 0x83EB, 0xC79F, 0x83EC, 0xC7A0, 0x83ED, 0xC7A1, 0x6070, 0xC7A2, 0x6D3D, 0xC7A3, 0x7275, 0xC7A4, 0x6266, 0xC7A5, 0x948E, 0xC7A6, 0x94C5, 0xC7A7, 0x5343, 0xC7A8, 0x8FC1, 0xC7A9, 0x7B7E, 0xC7AA, 0x4EDF, 0xC7AB, 0x8C26, 0xC7AC, 0x4E7E, 0xC7AD, 0x9ED4, 0xC7AE, 0x94B1, 0xC7AF, 0x94B3, 0xC7B0, 0x524D, 0xC7B1, 0x6F5C, 0xC7B2, 0x9063, 0xC7B3, 0x6D45, 0xC7B4, 0x8C34, 0xC7B5, 0x5811, 0xC7B6, 0x5D4C, 0xC7B7, 0x6B20, 0xC7B8, 0x6B49, 0xC7B9, 0x67AA, 0xC7BA, 0x545B, 0xC7BB, 0x8154, 0xC7BC, 0x7F8C, 0xC7BD, 0x5899, 0xC7BE, 0x8537, 0xC7BF, 0x5F3A, 0xC7C0, 0x62A2, 0xC7C1, 0x6A47, 0xC7C2, 0x9539, 0xC7C3, 0x6572, 0xC7C4, 0x6084, 0xC7C5, 0x6865, 0xC7C6, 0x77A7, 0xC7C7, 0x4E54, 0xC7C8, 0x4FA8, 0xC7C9, 0x5DE7, 0xC7CA, 0x9798, 0xC7CB, 0x64AC, 0xC7CC, 0x7FD8, 0xC7CD, 0x5CED, 0xC7CE, 0x4FCF, 0xC7CF, 0x7A8D, 0xC7D0, 0x5207, 0xC7D1, 0x8304, 0xC7D2, 0x4E14, 0xC7D3, 0x602F, 0xC7D4, 0x7A83, 0xC7D5, 0x94A6, 0xC7D6, 0x4FB5, 0xC7D7, 0x4EB2, 0xC7D8, 0x79E6, 0xC7D9, 0x7434, 0xC7DA, 0x52E4, 0xC7DB, 0x82B9, 0xC7DC, 0x64D2, 0xC7DD, 0x79BD, 0xC7DE, 0x5BDD, 0xC7DF, 0x6C81, 0xC7E0, 0x9752, 0xC7E1, 0x8F7B, 0xC7E2, 0x6C22, 0xC7E3, 0x503E, 0xC7E4, 0x537F, 0xC7E5, 0x6E05, 0xC7E6, 0x64CE, 0xC7E7, 0x6674, 0xC7E8, 0x6C30, 0xC7E9, 0x60C5, 0xC7EA, 0x9877, 0xC7EB, 0x8BF7, 0xC7EC, 0x5E86, 0xC7ED, 0x743C, 0xC7EE, 0x7A77, 0xC7EF, 0x79CB, 0xC7F0, 0x4E18, 0xC7F1, 0x90B1, 0xC7F2, 0x7403, 0xC7F3, 0x6C42, 0xC7F4, 0x56DA, 0xC7F5, 0x914B, 0xC7F6, 0x6CC5, 0xC7F7, 0x8D8B, 0xC7F8, 0x533A, 0xC7F9, 0x86C6, 0xC7FA, 0x66F2, 0xC7FB, 0x8EAF, 0xC7FC, 0x5C48, 0xC7FD, 0x9A71, 0xC7FE, 0x6E20, 0xC840, 0x83EE, 0xC841, 0x83EF, 0xC842, 0x83F3, 0xC843, 0x83F4, 0xC844, 0x83F5, 0xC845, 0x83F6, 0xC846, 0x83F7, 0xC847, 0x83FA, 0xC848, 0x83FB, 0xC849, 0x83FC, 0xC84A, 0x83FE, 0xC84B, 0x83FF, 0xC84C, 0x8400, 0xC84D, 0x8402, 0xC84E, 0x8405, 0xC84F, 0x8407, 0xC850, 0x8408, 0xC851, 0x8409, 0xC852, 0x840A, 0xC853, 0x8410, 0xC854, 0x8412, 0xC855, 0x8413, 0xC856, 0x8414, 0xC857, 0x8415, 0xC858, 0x8416, 0xC859, 0x8417, 0xC85A, 0x8419, 0xC85B, 0x841A, 0xC85C, 0x841B, 0xC85D, 0x841E, 0xC85E, 0x841F, 0xC85F, 0x8420, 0xC860, 0x8421, 0xC861, 0x8422, 0xC862, 0x8423, 0xC863, 0x8429, 0xC864, 0x842A, 0xC865, 0x842B, 0xC866, 0x842C, 0xC867, 0x842D, 0xC868, 0x842E, 0xC869, 0x842F, 0xC86A, 0x8430, 0xC86B, 0x8432, 0xC86C, 0x8433, 0xC86D, 0x8434, 0xC86E, 0x8435, 0xC86F, 0x8436, 0xC870, 0x8437, 0xC871, 0x8439, 0xC872, 0x843A, 0xC873, 0x843B, 0xC874, 0x843E, 0xC875, 0x843F, 0xC876, 0x8440, 0xC877, 0x8441, 0xC878, 0x8442, 0xC879, 0x8443, 0xC87A, 0x8444, 0xC87B, 0x8445, 0xC87C, 0x8447, 0xC87D, 0x8448, 0xC87E, 0x8449, 0xC880, 0x844A, 0xC881, 0x844B, 0xC882, 0x844C, 0xC883, 0x844D, 0xC884, 0x844E, 0xC885, 0x844F, 0xC886, 0x8450, 0xC887, 0x8452, 0xC888, 0x8453, 0xC889, 0x8454, 0xC88A, 0x8455, 0xC88B, 0x8456, 0xC88C, 0x8458, 0xC88D, 0x845D, 0xC88E, 0x845E, 0xC88F, 0x845F, 0xC890, 0x8460, 0xC891, 0x8462, 0xC892, 0x8464, 0xC893, 0x8465, 0xC894, 0x8466, 0xC895, 0x8467, 0xC896, 0x8468, 0xC897, 0x846A, 0xC898, 0x846E, 0xC899, 0x846F, 0xC89A, 0x8470, 0xC89B, 0x8472, 0xC89C, 0x8474, 0xC89D, 0x8477, 0xC89E, 0x8479, 0xC89F, 0x847B, 0xC8A0, 0x847C, 0xC8A1, 0x53D6, 0xC8A2, 0x5A36, 0xC8A3, 0x9F8B, 0xC8A4, 0x8DA3, 0xC8A5, 0x53BB, 0xC8A6, 0x5708, 0xC8A7, 0x98A7, 0xC8A8, 0x6743, 0xC8A9, 0x919B, 0xC8AA, 0x6CC9, 0xC8AB, 0x5168, 0xC8AC, 0x75CA, 0xC8AD, 0x62F3, 0xC8AE, 0x72AC, 0xC8AF, 0x5238, 0xC8B0, 0x529D, 0xC8B1, 0x7F3A, 0xC8B2, 0x7094, 0xC8B3, 0x7638, 0xC8B4, 0x5374, 0xC8B5, 0x9E4A, 0xC8B6, 0x69B7, 0xC8B7, 0x786E, 0xC8B8, 0x96C0, 0xC8B9, 0x88D9, 0xC8BA, 0x7FA4, 0xC8BB, 0x7136, 0xC8BC, 0x71C3, 0xC8BD, 0x5189, 0xC8BE, 0x67D3, 0xC8BF, 0x74E4, 0xC8C0, 0x58E4, 0xC8C1, 0x6518, 0xC8C2, 0x56B7, 0xC8C3, 0x8BA9, 0xC8C4, 0x9976, 0xC8C5, 0x6270, 0xC8C6, 0x7ED5, 0xC8C7, 0x60F9, 0xC8C8, 0x70ED, 0xC8C9, 0x58EC, 0xC8CA, 0x4EC1, 0xC8CB, 0x4EBA, 0xC8CC, 0x5FCD, 0xC8CD, 0x97E7, 0xC8CE, 0x4EFB, 0xC8CF, 0x8BA4, 0xC8D0, 0x5203, 0xC8D1, 0x598A, 0xC8D2, 0x7EAB, 0xC8D3, 0x6254, 0xC8D4, 0x4ECD, 0xC8D5, 0x65E5, 0xC8D6, 0x620E, 0xC8D7, 0x8338, 0xC8D8, 0x84C9, 0xC8D9, 0x8363, 0xC8DA, 0x878D, 0xC8DB, 0x7194, 0xC8DC, 0x6EB6, 0xC8DD, 0x5BB9, 0xC8DE, 0x7ED2, 0xC8DF, 0x5197, 0xC8E0, 0x63C9, 0xC8E1, 0x67D4, 0xC8E2, 0x8089, 0xC8E3, 0x8339, 0xC8E4, 0x8815, 0xC8E5, 0x5112, 0xC8E6, 0x5B7A, 0xC8E7, 0x5982, 0xC8E8, 0x8FB1, 0xC8E9, 0x4E73, 0xC8EA, 0x6C5D, 0xC8EB, 0x5165, 0xC8EC, 0x8925, 0xC8ED, 0x8F6F, 0xC8EE, 0x962E, 0xC8EF, 0x854A, 0xC8F0, 0x745E, 0xC8F1, 0x9510, 0xC8F2, 0x95F0, 0xC8F3, 0x6DA6, 0xC8F4, 0x82E5, 0xC8F5, 0x5F31, 0xC8F6, 0x6492, 0xC8F7, 0x6D12, 0xC8F8, 0x8428, 0xC8F9, 0x816E, 0xC8FA, 0x9CC3, 0xC8FB, 0x585E, 0xC8FC, 0x8D5B, 0xC8FD, 0x4E09, 0xC8FE, 0x53C1, 0xC940, 0x847D, 0xC941, 0x847E, 0xC942, 0x847F, 0xC943, 0x8480, 0xC944, 0x8481, 0xC945, 0x8483, 0xC946, 0x8484, 0xC947, 0x8485, 0xC948, 0x8486, 0xC949, 0x848A, 0xC94A, 0x848D, 0xC94B, 0x848F, 0xC94C, 0x8490, 0xC94D, 0x8491, 0xC94E, 0x8492, 0xC94F, 0x8493, 0xC950, 0x8494, 0xC951, 0x8495, 0xC952, 0x8496, 0xC953, 0x8498, 0xC954, 0x849A, 0xC955, 0x849B, 0xC956, 0x849D, 0xC957, 0x849E, 0xC958, 0x849F, 0xC959, 0x84A0, 0xC95A, 0x84A2, 0xC95B, 0x84A3, 0xC95C, 0x84A4, 0xC95D, 0x84A5, 0xC95E, 0x84A6, 0xC95F, 0x84A7, 0xC960, 0x84A8, 0xC961, 0x84A9, 0xC962, 0x84AA, 0xC963, 0x84AB, 0xC964, 0x84AC, 0xC965, 0x84AD, 0xC966, 0x84AE, 0xC967, 0x84B0, 0xC968, 0x84B1, 0xC969, 0x84B3, 0xC96A, 0x84B5, 0xC96B, 0x84B6, 0xC96C, 0x84B7, 0xC96D, 0x84BB, 0xC96E, 0x84BC, 0xC96F, 0x84BE, 0xC970, 0x84C0, 0xC971, 0x84C2, 0xC972, 0x84C3, 0xC973, 0x84C5, 0xC974, 0x84C6, 0xC975, 0x84C7, 0xC976, 0x84C8, 0xC977, 0x84CB, 0xC978, 0x84CC, 0xC979, 0x84CE, 0xC97A, 0x84CF, 0xC97B, 0x84D2, 0xC97C, 0x84D4, 0xC97D, 0x84D5, 0xC97E, 0x84D7, 0xC980, 0x84D8, 0xC981, 0x84D9, 0xC982, 0x84DA, 0xC983, 0x84DB, 0xC984, 0x84DC, 0xC985, 0x84DE, 0xC986, 0x84E1, 0xC987, 0x84E2, 0xC988, 0x84E4, 0xC989, 0x84E7, 0xC98A, 0x84E8, 0xC98B, 0x84E9, 0xC98C, 0x84EA, 0xC98D, 0x84EB, 0xC98E, 0x84ED, 0xC98F, 0x84EE, 0xC990, 0x84EF, 0xC991, 0x84F1, 0xC992, 0x84F2, 0xC993, 0x84F3, 0xC994, 0x84F4, 0xC995, 0x84F5, 0xC996, 0x84F6, 0xC997, 0x84F7, 0xC998, 0x84F8, 0xC999, 0x84F9, 0xC99A, 0x84FA, 0xC99B, 0x84FB, 0xC99C, 0x84FD, 0xC99D, 0x84FE, 0xC99E, 0x8500, 0xC99F, 0x8501, 0xC9A0, 0x8502, 0xC9A1, 0x4F1E, 0xC9A2, 0x6563, 0xC9A3, 0x6851, 0xC9A4, 0x55D3, 0xC9A5, 0x4E27, 0xC9A6, 0x6414, 0xC9A7, 0x9A9A, 0xC9A8, 0x626B, 0xC9A9, 0x5AC2, 0xC9AA, 0x745F, 0xC9AB, 0x8272, 0xC9AC, 0x6DA9, 0xC9AD, 0x68EE, 0xC9AE, 0x50E7, 0xC9AF, 0x838E, 0xC9B0, 0x7802, 0xC9B1, 0x6740, 0xC9B2, 0x5239, 0xC9B3, 0x6C99, 0xC9B4, 0x7EB1, 0xC9B5, 0x50BB, 0xC9B6, 0x5565, 0xC9B7, 0x715E, 0xC9B8, 0x7B5B, 0xC9B9, 0x6652, 0xC9BA, 0x73CA, 0xC9BB, 0x82EB, 0xC9BC, 0x6749, 0xC9BD, 0x5C71, 0xC9BE, 0x5220, 0xC9BF, 0x717D, 0xC9C0, 0x886B, 0xC9C1, 0x95EA, 0xC9C2, 0x9655, 0xC9C3, 0x64C5, 0xC9C4, 0x8D61, 0xC9C5, 0x81B3, 0xC9C6, 0x5584, 0xC9C7, 0x6C55, 0xC9C8, 0x6247, 0xC9C9, 0x7F2E, 0xC9CA, 0x5892, 0xC9CB, 0x4F24, 0xC9CC, 0x5546, 0xC9CD, 0x8D4F, 0xC9CE, 0x664C, 0xC9CF, 0x4E0A, 0xC9D0, 0x5C1A, 0xC9D1, 0x88F3, 0xC9D2, 0x68A2, 0xC9D3, 0x634E, 0xC9D4, 0x7A0D, 0xC9D5, 0x70E7, 0xC9D6, 0x828D, 0xC9D7, 0x52FA, 0xC9D8, 0x97F6, 0xC9D9, 0x5C11, 0xC9DA, 0x54E8, 0xC9DB, 0x90B5, 0xC9DC, 0x7ECD, 0xC9DD, 0x5962, 0xC9DE, 0x8D4A, 0xC9DF, 0x86C7, 0xC9E0, 0x820C, 0xC9E1, 0x820D, 0xC9E2, 0x8D66, 0xC9E3, 0x6444, 0xC9E4, 0x5C04, 0xC9E5, 0x6151, 0xC9E6, 0x6D89, 0xC9E7, 0x793E, 0xC9E8, 0x8BBE, 0xC9E9, 0x7837, 0xC9EA, 0x7533, 0xC9EB, 0x547B, 0xC9EC, 0x4F38, 0xC9ED, 0x8EAB, 0xC9EE, 0x6DF1, 0xC9EF, 0x5A20, 0xC9F0, 0x7EC5, 0xC9F1, 0x795E, 0xC9F2, 0x6C88, 0xC9F3, 0x5BA1, 0xC9F4, 0x5A76, 0xC9F5, 0x751A, 0xC9F6, 0x80BE, 0xC9F7, 0x614E, 0xC9F8, 0x6E17, 0xC9F9, 0x58F0, 0xC9FA, 0x751F, 0xC9FB, 0x7525, 0xC9FC, 0x7272, 0xC9FD, 0x5347, 0xC9FE, 0x7EF3, 0xCA40, 0x8503, 0xCA41, 0x8504, 0xCA42, 0x8505, 0xCA43, 0x8506, 0xCA44, 0x8507, 0xCA45, 0x8508, 0xCA46, 0x8509, 0xCA47, 0x850A, 0xCA48, 0x850B, 0xCA49, 0x850D, 0xCA4A, 0x850E, 0xCA4B, 0x850F, 0xCA4C, 0x8510, 0xCA4D, 0x8512, 0xCA4E, 0x8514, 0xCA4F, 0x8515, 0xCA50, 0x8516, 0xCA51, 0x8518, 0xCA52, 0x8519, 0xCA53, 0x851B, 0xCA54, 0x851C, 0xCA55, 0x851D, 0xCA56, 0x851E, 0xCA57, 0x8520, 0xCA58, 0x8522, 0xCA59, 0x8523, 0xCA5A, 0x8524, 0xCA5B, 0x8525, 0xCA5C, 0x8526, 0xCA5D, 0x8527, 0xCA5E, 0x8528, 0xCA5F, 0x8529, 0xCA60, 0x852A, 0xCA61, 0x852D, 0xCA62, 0x852E, 0xCA63, 0x852F, 0xCA64, 0x8530, 0xCA65, 0x8531, 0xCA66, 0x8532, 0xCA67, 0x8533, 0xCA68, 0x8534, 0xCA69, 0x8535, 0xCA6A, 0x8536, 0xCA6B, 0x853E, 0xCA6C, 0x853F, 0xCA6D, 0x8540, 0xCA6E, 0x8541, 0xCA6F, 0x8542, 0xCA70, 0x8544, 0xCA71, 0x8545, 0xCA72, 0x8546, 0xCA73, 0x8547, 0xCA74, 0x854B, 0xCA75, 0x854C, 0xCA76, 0x854D, 0xCA77, 0x854E, 0xCA78, 0x854F, 0xCA79, 0x8550, 0xCA7A, 0x8551, 0xCA7B, 0x8552, 0xCA7C, 0x8553, 0xCA7D, 0x8554, 0xCA7E, 0x8555, 0xCA80, 0x8557, 0xCA81, 0x8558, 0xCA82, 0x855A, 0xCA83, 0x855B, 0xCA84, 0x855C, 0xCA85, 0x855D, 0xCA86, 0x855F, 0xCA87, 0x8560, 0xCA88, 0x8561, 0xCA89, 0x8562, 0xCA8A, 0x8563, 0xCA8B, 0x8565, 0xCA8C, 0x8566, 0xCA8D, 0x8567, 0xCA8E, 0x8569, 0xCA8F, 0x856A, 0xCA90, 0x856B, 0xCA91, 0x856C, 0xCA92, 0x856D, 0xCA93, 0x856E, 0xCA94, 0x856F, 0xCA95, 0x8570, 0xCA96, 0x8571, 0xCA97, 0x8573, 0xCA98, 0x8575, 0xCA99, 0x8576, 0xCA9A, 0x8577, 0xCA9B, 0x8578, 0xCA9C, 0x857C, 0xCA9D, 0x857D, 0xCA9E, 0x857F, 0xCA9F, 0x8580, 0xCAA0, 0x8581, 0xCAA1, 0x7701, 0xCAA2, 0x76DB, 0xCAA3, 0x5269, 0xCAA4, 0x80DC, 0xCAA5, 0x5723, 0xCAA6, 0x5E08, 0xCAA7, 0x5931, 0xCAA8, 0x72EE, 0xCAA9, 0x65BD, 0xCAAA, 0x6E7F, 0xCAAB, 0x8BD7, 0xCAAC, 0x5C38, 0xCAAD, 0x8671, 0xCAAE, 0x5341, 0xCAAF, 0x77F3, 0xCAB0, 0x62FE, 0xCAB1, 0x65F6, 0xCAB2, 0x4EC0, 0xCAB3, 0x98DF, 0xCAB4, 0x8680, 0xCAB5, 0x5B9E, 0xCAB6, 0x8BC6, 0xCAB7, 0x53F2, 0xCAB8, 0x77E2, 0xCAB9, 0x4F7F, 0xCABA, 0x5C4E, 0xCABB, 0x9A76, 0xCABC, 0x59CB, 0xCABD, 0x5F0F, 0xCABE, 0x793A, 0xCABF, 0x58EB, 0xCAC0, 0x4E16, 0xCAC1, 0x67FF, 0xCAC2, 0x4E8B, 0xCAC3, 0x62ED, 0xCAC4, 0x8A93, 0xCAC5, 0x901D, 0xCAC6, 0x52BF, 0xCAC7, 0x662F, 0xCAC8, 0x55DC, 0xCAC9, 0x566C, 0xCACA, 0x9002, 0xCACB, 0x4ED5, 0xCACC, 0x4F8D, 0xCACD, 0x91CA, 0xCACE, 0x9970, 0xCACF, 0x6C0F, 0xCAD0, 0x5E02, 0xCAD1, 0x6043, 0xCAD2, 0x5BA4, 0xCAD3, 0x89C6, 0xCAD4, 0x8BD5, 0xCAD5, 0x6536, 0xCAD6, 0x624B, 0xCAD7, 0x9996, 0xCAD8, 0x5B88, 0xCAD9, 0x5BFF, 0xCADA, 0x6388, 0xCADB, 0x552E, 0xCADC, 0x53D7, 0xCADD, 0x7626, 0xCADE, 0x517D, 0xCADF, 0x852C, 0xCAE0, 0x67A2, 0xCAE1, 0x68B3, 0xCAE2, 0x6B8A, 0xCAE3, 0x6292, 0xCAE4, 0x8F93, 0xCAE5, 0x53D4, 0xCAE6, 0x8212, 0xCAE7, 0x6DD1, 0xCAE8, 0x758F, 0xCAE9, 0x4E66, 0xCAEA, 0x8D4E, 0xCAEB, 0x5B70, 0xCAEC, 0x719F, 0xCAED, 0x85AF, 0xCAEE, 0x6691, 0xCAEF, 0x66D9, 0xCAF0, 0x7F72, 0xCAF1, 0x8700, 0xCAF2, 0x9ECD, 0xCAF3, 0x9F20, 0xCAF4, 0x5C5E, 0xCAF5, 0x672F, 0xCAF6, 0x8FF0, 0xCAF7, 0x6811, 0xCAF8, 0x675F, 0xCAF9, 0x620D, 0xCAFA, 0x7AD6, 0xCAFB, 0x5885, 0xCAFC, 0x5EB6, 0xCAFD, 0x6570, 0xCAFE, 0x6F31, 0xCB40, 0x8582, 0xCB41, 0x8583, 0xCB42, 0x8586, 0xCB43, 0x8588, 0xCB44, 0x8589, 0xCB45, 0x858A, 0xCB46, 0x858B, 0xCB47, 0x858C, 0xCB48, 0x858D, 0xCB49, 0x858E, 0xCB4A, 0x8590, 0xCB4B, 0x8591, 0xCB4C, 0x8592, 0xCB4D, 0x8593, 0xCB4E, 0x8594, 0xCB4F, 0x8595, 0xCB50, 0x8596, 0xCB51, 0x8597, 0xCB52, 0x8598, 0xCB53, 0x8599, 0xCB54, 0x859A, 0xCB55, 0x859D, 0xCB56, 0x859E, 0xCB57, 0x859F, 0xCB58, 0x85A0, 0xCB59, 0x85A1, 0xCB5A, 0x85A2, 0xCB5B, 0x85A3, 0xCB5C, 0x85A5, 0xCB5D, 0x85A6, 0xCB5E, 0x85A7, 0xCB5F, 0x85A9, 0xCB60, 0x85AB, 0xCB61, 0x85AC, 0xCB62, 0x85AD, 0xCB63, 0x85B1, 0xCB64, 0x85B2, 0xCB65, 0x85B3, 0xCB66, 0x85B4, 0xCB67, 0x85B5, 0xCB68, 0x85B6, 0xCB69, 0x85B8, 0xCB6A, 0x85BA, 0xCB6B, 0x85BB, 0xCB6C, 0x85BC, 0xCB6D, 0x85BD, 0xCB6E, 0x85BE, 0xCB6F, 0x85BF, 0xCB70, 0x85C0, 0xCB71, 0x85C2, 0xCB72, 0x85C3, 0xCB73, 0x85C4, 0xCB74, 0x85C5, 0xCB75, 0x85C6, 0xCB76, 0x85C7, 0xCB77, 0x85C8, 0xCB78, 0x85CA, 0xCB79, 0x85CB, 0xCB7A, 0x85CC, 0xCB7B, 0x85CD, 0xCB7C, 0x85CE, 0xCB7D, 0x85D1, 0xCB7E, 0x85D2, 0xCB80, 0x85D4, 0xCB81, 0x85D6, 0xCB82, 0x85D7, 0xCB83, 0x85D8, 0xCB84, 0x85D9, 0xCB85, 0x85DA, 0xCB86, 0x85DB, 0xCB87, 0x85DD, 0xCB88, 0x85DE, 0xCB89, 0x85DF, 0xCB8A, 0x85E0, 0xCB8B, 0x85E1, 0xCB8C, 0x85E2, 0xCB8D, 0x85E3, 0xCB8E, 0x85E5, 0xCB8F, 0x85E6, 0xCB90, 0x85E7, 0xCB91, 0x85E8, 0xCB92, 0x85EA, 0xCB93, 0x85EB, 0xCB94, 0x85EC, 0xCB95, 0x85ED, 0xCB96, 0x85EE, 0xCB97, 0x85EF, 0xCB98, 0x85F0, 0xCB99, 0x85F1, 0xCB9A, 0x85F2, 0xCB9B, 0x85F3, 0xCB9C, 0x85F4, 0xCB9D, 0x85F5, 0xCB9E, 0x85F6, 0xCB9F, 0x85F7, 0xCBA0, 0x85F8, 0xCBA1, 0x6055, 0xCBA2, 0x5237, 0xCBA3, 0x800D, 0xCBA4, 0x6454, 0xCBA5, 0x8870, 0xCBA6, 0x7529, 0xCBA7, 0x5E05, 0xCBA8, 0x6813, 0xCBA9, 0x62F4, 0xCBAA, 0x971C, 0xCBAB, 0x53CC, 0xCBAC, 0x723D, 0xCBAD, 0x8C01, 0xCBAE, 0x6C34, 0xCBAF, 0x7761, 0xCBB0, 0x7A0E, 0xCBB1, 0x542E, 0xCBB2, 0x77AC, 0xCBB3, 0x987A, 0xCBB4, 0x821C, 0xCBB5, 0x8BF4, 0xCBB6, 0x7855, 0xCBB7, 0x6714, 0xCBB8, 0x70C1, 0xCBB9, 0x65AF, 0xCBBA, 0x6495, 0xCBBB, 0x5636, 0xCBBC, 0x601D, 0xCBBD, 0x79C1, 0xCBBE, 0x53F8, 0xCBBF, 0x4E1D, 0xCBC0, 0x6B7B, 0xCBC1, 0x8086, 0xCBC2, 0x5BFA, 0xCBC3, 0x55E3, 0xCBC4, 0x56DB, 0xCBC5, 0x4F3A, 0xCBC6, 0x4F3C, 0xCBC7, 0x9972, 0xCBC8, 0x5DF3, 0xCBC9, 0x677E, 0xCBCA, 0x8038, 0xCBCB, 0x6002, 0xCBCC, 0x9882, 0xCBCD, 0x9001, 0xCBCE, 0x5B8B, 0xCBCF, 0x8BBC, 0xCBD0, 0x8BF5, 0xCBD1, 0x641C, 0xCBD2, 0x8258, 0xCBD3, 0x64DE, 0xCBD4, 0x55FD, 0xCBD5, 0x82CF, 0xCBD6, 0x9165, 0xCBD7, 0x4FD7, 0xCBD8, 0x7D20, 0xCBD9, 0x901F, 0xCBDA, 0x7C9F, 0xCBDB, 0x50F3, 0xCBDC, 0x5851, 0xCBDD, 0x6EAF, 0xCBDE, 0x5BBF, 0xCBDF, 0x8BC9, 0xCBE0, 0x8083, 0xCBE1, 0x9178, 0xCBE2, 0x849C, 0xCBE3, 0x7B97, 0xCBE4, 0x867D, 0xCBE5, 0x968B, 0xCBE6, 0x968F, 0xCBE7, 0x7EE5, 0xCBE8, 0x9AD3, 0xCBE9, 0x788E, 0xCBEA, 0x5C81, 0xCBEB, 0x7A57, 0xCBEC, 0x9042, 0xCBED, 0x96A7, 0xCBEE, 0x795F, 0xCBEF, 0x5B59, 0xCBF0, 0x635F, 0xCBF1, 0x7B0B, 0xCBF2, 0x84D1, 0xCBF3, 0x68AD, 0xCBF4, 0x5506, 0xCBF5, 0x7F29, 0xCBF6, 0x7410, 0xCBF7, 0x7D22, 0xCBF8, 0x9501, 0xCBF9, 0x6240, 0xCBFA, 0x584C, 0xCBFB, 0x4ED6, 0xCBFC, 0x5B83, 0xCBFD, 0x5979, 0xCBFE, 0x5854, 0xCC40, 0x85F9, 0xCC41, 0x85FA, 0xCC42, 0x85FC, 0xCC43, 0x85FD, 0xCC44, 0x85FE, 0xCC45, 0x8600, 0xCC46, 0x8601, 0xCC47, 0x8602, 0xCC48, 0x8603, 0xCC49, 0x8604, 0xCC4A, 0x8606, 0xCC4B, 0x8607, 0xCC4C, 0x8608, 0xCC4D, 0x8609, 0xCC4E, 0x860A, 0xCC4F, 0x860B, 0xCC50, 0x860C, 0xCC51, 0x860D, 0xCC52, 0x860E, 0xCC53, 0x860F, 0xCC54, 0x8610, 0xCC55, 0x8612, 0xCC56, 0x8613, 0xCC57, 0x8614, 0xCC58, 0x8615, 0xCC59, 0x8617, 0xCC5A, 0x8618, 0xCC5B, 0x8619, 0xCC5C, 0x861A, 0xCC5D, 0x861B, 0xCC5E, 0x861C, 0xCC5F, 0x861D, 0xCC60, 0x861E, 0xCC61, 0x861F, 0xCC62, 0x8620, 0xCC63, 0x8621, 0xCC64, 0x8622, 0xCC65, 0x8623, 0xCC66, 0x8624, 0xCC67, 0x8625, 0xCC68, 0x8626, 0xCC69, 0x8628, 0xCC6A, 0x862A, 0xCC6B, 0x862B, 0xCC6C, 0x862C, 0xCC6D, 0x862D, 0xCC6E, 0x862E, 0xCC6F, 0x862F, 0xCC70, 0x8630, 0xCC71, 0x8631, 0xCC72, 0x8632, 0xCC73, 0x8633, 0xCC74, 0x8634, 0xCC75, 0x8635, 0xCC76, 0x8636, 0xCC77, 0x8637, 0xCC78, 0x8639, 0xCC79, 0x863A, 0xCC7A, 0x863B, 0xCC7B, 0x863D, 0xCC7C, 0x863E, 0xCC7D, 0x863F, 0xCC7E, 0x8640, 0xCC80, 0x8641, 0xCC81, 0x8642, 0xCC82, 0x8643, 0xCC83, 0x8644, 0xCC84, 0x8645, 0xCC85, 0x8646, 0xCC86, 0x8647, 0xCC87, 0x8648, 0xCC88, 0x8649, 0xCC89, 0x864A, 0xCC8A, 0x864B, 0xCC8B, 0x864C, 0xCC8C, 0x8652, 0xCC8D, 0x8653, 0xCC8E, 0x8655, 0xCC8F, 0x8656, 0xCC90, 0x8657, 0xCC91, 0x8658, 0xCC92, 0x8659, 0xCC93, 0x865B, 0xCC94, 0x865C, 0xCC95, 0x865D, 0xCC96, 0x865F, 0xCC97, 0x8660, 0xCC98, 0x8661, 0xCC99, 0x8663, 0xCC9A, 0x8664, 0xCC9B, 0x8665, 0xCC9C, 0x8666, 0xCC9D, 0x8667, 0xCC9E, 0x8668, 0xCC9F, 0x8669, 0xCCA0, 0x866A, 0xCCA1, 0x736D, 0xCCA2, 0x631E, 0xCCA3, 0x8E4B, 0xCCA4, 0x8E0F, 0xCCA5, 0x80CE, 0xCCA6, 0x82D4, 0xCCA7, 0x62AC, 0xCCA8, 0x53F0, 0xCCA9, 0x6CF0, 0xCCAA, 0x915E, 0xCCAB, 0x592A, 0xCCAC, 0x6001, 0xCCAD, 0x6C70, 0xCCAE, 0x574D, 0xCCAF, 0x644A, 0xCCB0, 0x8D2A, 0xCCB1, 0x762B, 0xCCB2, 0x6EE9, 0xCCB3, 0x575B, 0xCCB4, 0x6A80, 0xCCB5, 0x75F0, 0xCCB6, 0x6F6D, 0xCCB7, 0x8C2D, 0xCCB8, 0x8C08, 0xCCB9, 0x5766, 0xCCBA, 0x6BEF, 0xCCBB, 0x8892, 0xCCBC, 0x78B3, 0xCCBD, 0x63A2, 0xCCBE, 0x53F9, 0xCCBF, 0x70AD, 0xCCC0, 0x6C64, 0xCCC1, 0x5858, 0xCCC2, 0x642A, 0xCCC3, 0x5802, 0xCCC4, 0x68E0, 0xCCC5, 0x819B, 0xCCC6, 0x5510, 0xCCC7, 0x7CD6, 0xCCC8, 0x5018, 0xCCC9, 0x8EBA, 0xCCCA, 0x6DCC, 0xCCCB, 0x8D9F, 0xCCCC, 0x70EB, 0xCCCD, 0x638F, 0xCCCE, 0x6D9B, 0xCCCF, 0x6ED4, 0xCCD0, 0x7EE6, 0xCCD1, 0x8404, 0xCCD2, 0x6843, 0xCCD3, 0x9003, 0xCCD4, 0x6DD8, 0xCCD5, 0x9676, 0xCCD6, 0x8BA8, 0xCCD7, 0x5957, 0xCCD8, 0x7279, 0xCCD9, 0x85E4, 0xCCDA, 0x817E, 0xCCDB, 0x75BC, 0xCCDC, 0x8A8A, 0xCCDD, 0x68AF, 0xCCDE, 0x5254, 0xCCDF, 0x8E22, 0xCCE0, 0x9511, 0xCCE1, 0x63D0, 0xCCE2, 0x9898, 0xCCE3, 0x8E44, 0xCCE4, 0x557C, 0xCCE5, 0x4F53, 0xCCE6, 0x66FF, 0xCCE7, 0x568F, 0xCCE8, 0x60D5, 0xCCE9, 0x6D95, 0xCCEA, 0x5243, 0xCCEB, 0x5C49, 0xCCEC, 0x5929, 0xCCED, 0x6DFB, 0xCCEE, 0x586B, 0xCCEF, 0x7530, 0xCCF0, 0x751C, 0xCCF1, 0x606C, 0xCCF2, 0x8214, 0xCCF3, 0x8146, 0xCCF4, 0x6311, 0xCCF5, 0x6761, 0xCCF6, 0x8FE2, 0xCCF7, 0x773A, 0xCCF8, 0x8DF3, 0xCCF9, 0x8D34, 0xCCFA, 0x94C1, 0xCCFB, 0x5E16, 0xCCFC, 0x5385, 0xCCFD, 0x542C, 0xCCFE, 0x70C3, 0xCD40, 0x866D, 0xCD41, 0x866F, 0xCD42, 0x8670, 0xCD43, 0x8672, 0xCD44, 0x8673, 0xCD45, 0x8674, 0xCD46, 0x8675, 0xCD47, 0x8676, 0xCD48, 0x8677, 0xCD49, 0x8678, 0xCD4A, 0x8683, 0xCD4B, 0x8684, 0xCD4C, 0x8685, 0xCD4D, 0x8686, 0xCD4E, 0x8687, 0xCD4F, 0x8688, 0xCD50, 0x8689, 0xCD51, 0x868E, 0xCD52, 0x868F, 0xCD53, 0x8690, 0xCD54, 0x8691, 0xCD55, 0x8692, 0xCD56, 0x8694, 0xCD57, 0x8696, 0xCD58, 0x8697, 0xCD59, 0x8698, 0xCD5A, 0x8699, 0xCD5B, 0x869A, 0xCD5C, 0x869B, 0xCD5D, 0x869E, 0xCD5E, 0x869F, 0xCD5F, 0x86A0, 0xCD60, 0x86A1, 0xCD61, 0x86A2, 0xCD62, 0x86A5, 0xCD63, 0x86A6, 0xCD64, 0x86AB, 0xCD65, 0x86AD, 0xCD66, 0x86AE, 0xCD67, 0x86B2, 0xCD68, 0x86B3, 0xCD69, 0x86B7, 0xCD6A, 0x86B8, 0xCD6B, 0x86B9, 0xCD6C, 0x86BB, 0xCD6D, 0x86BC, 0xCD6E, 0x86BD, 0xCD6F, 0x86BE, 0xCD70, 0x86BF, 0xCD71, 0x86C1, 0xCD72, 0x86C2, 0xCD73, 0x86C3, 0xCD74, 0x86C5, 0xCD75, 0x86C8, 0xCD76, 0x86CC, 0xCD77, 0x86CD, 0xCD78, 0x86D2, 0xCD79, 0x86D3, 0xCD7A, 0x86D5, 0xCD7B, 0x86D6, 0xCD7C, 0x86D7, 0xCD7D, 0x86DA, 0xCD7E, 0x86DC, 0xCD80, 0x86DD, 0xCD81, 0x86E0, 0xCD82, 0x86E1, 0xCD83, 0x86E2, 0xCD84, 0x86E3, 0xCD85, 0x86E5, 0xCD86, 0x86E6, 0xCD87, 0x86E7, 0xCD88, 0x86E8, 0xCD89, 0x86EA, 0xCD8A, 0x86EB, 0xCD8B, 0x86EC, 0xCD8C, 0x86EF, 0xCD8D, 0x86F5, 0xCD8E, 0x86F6, 0xCD8F, 0x86F7, 0xCD90, 0x86FA, 0xCD91, 0x86FB, 0xCD92, 0x86FC, 0xCD93, 0x86FD, 0xCD94, 0x86FF, 0xCD95, 0x8701, 0xCD96, 0x8704, 0xCD97, 0x8705, 0xCD98, 0x8706, 0xCD99, 0x870B, 0xCD9A, 0x870C, 0xCD9B, 0x870E, 0xCD9C, 0x870F, 0xCD9D, 0x8710, 0xCD9E, 0x8711, 0xCD9F, 0x8714, 0xCDA0, 0x8716, 0xCDA1, 0x6C40, 0xCDA2, 0x5EF7, 0xCDA3, 0x505C, 0xCDA4, 0x4EAD, 0xCDA5, 0x5EAD, 0xCDA6, 0x633A, 0xCDA7, 0x8247, 0xCDA8, 0x901A, 0xCDA9, 0x6850, 0xCDAA, 0x916E, 0xCDAB, 0x77B3, 0xCDAC, 0x540C, 0xCDAD, 0x94DC, 0xCDAE, 0x5F64, 0xCDAF, 0x7AE5, 0xCDB0, 0x6876, 0xCDB1, 0x6345, 0xCDB2, 0x7B52, 0xCDB3, 0x7EDF, 0xCDB4, 0x75DB, 0xCDB5, 0x5077, 0xCDB6, 0x6295, 0xCDB7, 0x5934, 0xCDB8, 0x900F, 0xCDB9, 0x51F8, 0xCDBA, 0x79C3, 0xCDBB, 0x7A81, 0xCDBC, 0x56FE, 0xCDBD, 0x5F92, 0xCDBE, 0x9014, 0xCDBF, 0x6D82, 0xCDC0, 0x5C60, 0xCDC1, 0x571F, 0xCDC2, 0x5410, 0xCDC3, 0x5154, 0xCDC4, 0x6E4D, 0xCDC5, 0x56E2, 0xCDC6, 0x63A8, 0xCDC7, 0x9893, 0xCDC8, 0x817F, 0xCDC9, 0x8715, 0xCDCA, 0x892A, 0xCDCB, 0x9000, 0xCDCC, 0x541E, 0xCDCD, 0x5C6F, 0xCDCE, 0x81C0, 0xCDCF, 0x62D6, 0xCDD0, 0x6258, 0xCDD1, 0x8131, 0xCDD2, 0x9E35, 0xCDD3, 0x9640, 0xCDD4, 0x9A6E, 0xCDD5, 0x9A7C, 0xCDD6, 0x692D, 0xCDD7, 0x59A5, 0xCDD8, 0x62D3, 0xCDD9, 0x553E, 0xCDDA, 0x6316, 0xCDDB, 0x54C7, 0xCDDC, 0x86D9, 0xCDDD, 0x6D3C, 0xCDDE, 0x5A03, 0xCDDF, 0x74E6, 0xCDE0, 0x889C, 0xCDE1, 0x6B6A, 0xCDE2, 0x5916, 0xCDE3, 0x8C4C, 0xCDE4, 0x5F2F, 0xCDE5, 0x6E7E, 0xCDE6, 0x73A9, 0xCDE7, 0x987D, 0xCDE8, 0x4E38, 0xCDE9, 0x70F7, 0xCDEA, 0x5B8C, 0xCDEB, 0x7897, 0xCDEC, 0x633D, 0xCDED, 0x665A, 0xCDEE, 0x7696, 0xCDEF, 0x60CB, 0xCDF0, 0x5B9B, 0xCDF1, 0x5A49, 0xCDF2, 0x4E07, 0xCDF3, 0x8155, 0xCDF4, 0x6C6A, 0xCDF5, 0x738B, 0xCDF6, 0x4EA1, 0xCDF7, 0x6789, 0xCDF8, 0x7F51, 0xCDF9, 0x5F80, 0xCDFA, 0x65FA, 0xCDFB, 0x671B, 0xCDFC, 0x5FD8, 0xCDFD, 0x5984, 0xCDFE, 0x5A01, 0xCE40, 0x8719, 0xCE41, 0x871B, 0xCE42, 0x871D, 0xCE43, 0x871F, 0xCE44, 0x8720, 0xCE45, 0x8724, 0xCE46, 0x8726, 0xCE47, 0x8727, 0xCE48, 0x8728, 0xCE49, 0x872A, 0xCE4A, 0x872B, 0xCE4B, 0x872C, 0xCE4C, 0x872D, 0xCE4D, 0x872F, 0xCE4E, 0x8730, 0xCE4F, 0x8732, 0xCE50, 0x8733, 0xCE51, 0x8735, 0xCE52, 0x8736, 0xCE53, 0x8738, 0xCE54, 0x8739, 0xCE55, 0x873A, 0xCE56, 0x873C, 0xCE57, 0x873D, 0xCE58, 0x8740, 0xCE59, 0x8741, 0xCE5A, 0x8742, 0xCE5B, 0x8743, 0xCE5C, 0x8744, 0xCE5D, 0x8745, 0xCE5E, 0x8746, 0xCE5F, 0x874A, 0xCE60, 0x874B, 0xCE61, 0x874D, 0xCE62, 0x874F, 0xCE63, 0x8750, 0xCE64, 0x8751, 0xCE65, 0x8752, 0xCE66, 0x8754, 0xCE67, 0x8755, 0xCE68, 0x8756, 0xCE69, 0x8758, 0xCE6A, 0x875A, 0xCE6B, 0x875B, 0xCE6C, 0x875C, 0xCE6D, 0x875D, 0xCE6E, 0x875E, 0xCE6F, 0x875F, 0xCE70, 0x8761, 0xCE71, 0x8762, 0xCE72, 0x8766, 0xCE73, 0x8767, 0xCE74, 0x8768, 0xCE75, 0x8769, 0xCE76, 0x876A, 0xCE77, 0x876B, 0xCE78, 0x876C, 0xCE79, 0x876D, 0xCE7A, 0x876F, 0xCE7B, 0x8771, 0xCE7C, 0x8772, 0xCE7D, 0x8773, 0xCE7E, 0x8775, 0xCE80, 0x8777, 0xCE81, 0x8778, 0xCE82, 0x8779, 0xCE83, 0x877A, 0xCE84, 0x877F, 0xCE85, 0x8780, 0xCE86, 0x8781, 0xCE87, 0x8784, 0xCE88, 0x8786, 0xCE89, 0x8787, 0xCE8A, 0x8789, 0xCE8B, 0x878A, 0xCE8C, 0x878C, 0xCE8D, 0x878E, 0xCE8E, 0x878F, 0xCE8F, 0x8790, 0xCE90, 0x8791, 0xCE91, 0x8792, 0xCE92, 0x8794, 0xCE93, 0x8795, 0xCE94, 0x8796, 0xCE95, 0x8798, 0xCE96, 0x8799, 0xCE97, 0x879A, 0xCE98, 0x879B, 0xCE99, 0x879C, 0xCE9A, 0x879D, 0xCE9B, 0x879E, 0xCE9C, 0x87A0, 0xCE9D, 0x87A1, 0xCE9E, 0x87A2, 0xCE9F, 0x87A3, 0xCEA0, 0x87A4, 0xCEA1, 0x5DCD, 0xCEA2, 0x5FAE, 0xCEA3, 0x5371, 0xCEA4, 0x97E6, 0xCEA5, 0x8FDD, 0xCEA6, 0x6845, 0xCEA7, 0x56F4, 0xCEA8, 0x552F, 0xCEA9, 0x60DF, 0xCEAA, 0x4E3A, 0xCEAB, 0x6F4D, 0xCEAC, 0x7EF4, 0xCEAD, 0x82C7, 0xCEAE, 0x840E, 0xCEAF, 0x59D4, 0xCEB0, 0x4F1F, 0xCEB1, 0x4F2A, 0xCEB2, 0x5C3E, 0xCEB3, 0x7EAC, 0xCEB4, 0x672A, 0xCEB5, 0x851A, 0xCEB6, 0x5473, 0xCEB7, 0x754F, 0xCEB8, 0x80C3, 0xCEB9, 0x5582, 0xCEBA, 0x9B4F, 0xCEBB, 0x4F4D, 0xCEBC, 0x6E2D, 0xCEBD, 0x8C13, 0xCEBE, 0x5C09, 0xCEBF, 0x6170, 0xCEC0, 0x536B, 0xCEC1, 0x761F, 0xCEC2, 0x6E29, 0xCEC3, 0x868A, 0xCEC4, 0x6587, 0xCEC5, 0x95FB, 0xCEC6, 0x7EB9, 0xCEC7, 0x543B, 0xCEC8, 0x7A33, 0xCEC9, 0x7D0A, 0xCECA, 0x95EE, 0xCECB, 0x55E1, 0xCECC, 0x7FC1, 0xCECD, 0x74EE, 0xCECE, 0x631D, 0xCECF, 0x8717, 0xCED0, 0x6DA1, 0xCED1, 0x7A9D, 0xCED2, 0x6211, 0xCED3, 0x65A1, 0xCED4, 0x5367, 0xCED5, 0x63E1, 0xCED6, 0x6C83, 0xCED7, 0x5DEB, 0xCED8, 0x545C, 0xCED9, 0x94A8, 0xCEDA, 0x4E4C, 0xCEDB, 0x6C61, 0xCEDC, 0x8BEC, 0xCEDD, 0x5C4B, 0xCEDE, 0x65E0, 0xCEDF, 0x829C, 0xCEE0, 0x68A7, 0xCEE1, 0x543E, 0xCEE2, 0x5434, 0xCEE3, 0x6BCB, 0xCEE4, 0x6B66, 0xCEE5, 0x4E94, 0xCEE6, 0x6342, 0xCEE7, 0x5348, 0xCEE8, 0x821E, 0xCEE9, 0x4F0D, 0xCEEA, 0x4FAE, 0xCEEB, 0x575E, 0xCEEC, 0x620A, 0xCEED, 0x96FE, 0xCEEE, 0x6664, 0xCEEF, 0x7269, 0xCEF0, 0x52FF, 0xCEF1, 0x52A1, 0xCEF2, 0x609F, 0xCEF3, 0x8BEF, 0xCEF4, 0x6614, 0xCEF5, 0x7199, 0xCEF6, 0x6790, 0xCEF7, 0x897F, 0xCEF8, 0x7852, 0xCEF9, 0x77FD, 0xCEFA, 0x6670, 0xCEFB, 0x563B, 0xCEFC, 0x5438, 0xCEFD, 0x9521, 0xCEFE, 0x727A, 0xCF40, 0x87A5, 0xCF41, 0x87A6, 0xCF42, 0x87A7, 0xCF43, 0x87A9, 0xCF44, 0x87AA, 0xCF45, 0x87AE, 0xCF46, 0x87B0, 0xCF47, 0x87B1, 0xCF48, 0x87B2, 0xCF49, 0x87B4, 0xCF4A, 0x87B6, 0xCF4B, 0x87B7, 0xCF4C, 0x87B8, 0xCF4D, 0x87B9, 0xCF4E, 0x87BB, 0xCF4F, 0x87BC, 0xCF50, 0x87BE, 0xCF51, 0x87BF, 0xCF52, 0x87C1, 0xCF53, 0x87C2, 0xCF54, 0x87C3, 0xCF55, 0x87C4, 0xCF56, 0x87C5, 0xCF57, 0x87C7, 0xCF58, 0x87C8, 0xCF59, 0x87C9, 0xCF5A, 0x87CC, 0xCF5B, 0x87CD, 0xCF5C, 0x87CE, 0xCF5D, 0x87CF, 0xCF5E, 0x87D0, 0xCF5F, 0x87D4, 0xCF60, 0x87D5, 0xCF61, 0x87D6, 0xCF62, 0x87D7, 0xCF63, 0x87D8, 0xCF64, 0x87D9, 0xCF65, 0x87DA, 0xCF66, 0x87DC, 0xCF67, 0x87DD, 0xCF68, 0x87DE, 0xCF69, 0x87DF, 0xCF6A, 0x87E1, 0xCF6B, 0x87E2, 0xCF6C, 0x87E3, 0xCF6D, 0x87E4, 0xCF6E, 0x87E6, 0xCF6F, 0x87E7, 0xCF70, 0x87E8, 0xCF71, 0x87E9, 0xCF72, 0x87EB, 0xCF73, 0x87EC, 0xCF74, 0x87ED, 0xCF75, 0x87EF, 0xCF76, 0x87F0, 0xCF77, 0x87F1, 0xCF78, 0x87F2, 0xCF79, 0x87F3, 0xCF7A, 0x87F4, 0xCF7B, 0x87F5, 0xCF7C, 0x87F6, 0xCF7D, 0x87F7, 0xCF7E, 0x87F8, 0xCF80, 0x87FA, 0xCF81, 0x87FB, 0xCF82, 0x87FC, 0xCF83, 0x87FD, 0xCF84, 0x87FF, 0xCF85, 0x8800, 0xCF86, 0x8801, 0xCF87, 0x8802, 0xCF88, 0x8804, 0xCF89, 0x8805, 0xCF8A, 0x8806, 0xCF8B, 0x8807, 0xCF8C, 0x8808, 0xCF8D, 0x8809, 0xCF8E, 0x880B, 0xCF8F, 0x880C, 0xCF90, 0x880D, 0xCF91, 0x880E, 0xCF92, 0x880F, 0xCF93, 0x8810, 0xCF94, 0x8811, 0xCF95, 0x8812, 0xCF96, 0x8814, 0xCF97, 0x8817, 0xCF98, 0x8818, 0xCF99, 0x8819, 0xCF9A, 0x881A, 0xCF9B, 0x881C, 0xCF9C, 0x881D, 0xCF9D, 0x881E, 0xCF9E, 0x881F, 0xCF9F, 0x8820, 0xCFA0, 0x8823, 0xCFA1, 0x7A00, 0xCFA2, 0x606F, 0xCFA3, 0x5E0C, 0xCFA4, 0x6089, 0xCFA5, 0x819D, 0xCFA6, 0x5915, 0xCFA7, 0x60DC, 0xCFA8, 0x7184, 0xCFA9, 0x70EF, 0xCFAA, 0x6EAA, 0xCFAB, 0x6C50, 0xCFAC, 0x7280, 0xCFAD, 0x6A84, 0xCFAE, 0x88AD, 0xCFAF, 0x5E2D, 0xCFB0, 0x4E60, 0xCFB1, 0x5AB3, 0xCFB2, 0x559C, 0xCFB3, 0x94E3, 0xCFB4, 0x6D17, 0xCFB5, 0x7CFB, 0xCFB6, 0x9699, 0xCFB7, 0x620F, 0xCFB8, 0x7EC6, 0xCFB9, 0x778E, 0xCFBA, 0x867E, 0xCFBB, 0x5323, 0xCFBC, 0x971E, 0xCFBD, 0x8F96, 0xCFBE, 0x6687, 0xCFBF, 0x5CE1, 0xCFC0, 0x4FA0, 0xCFC1, 0x72ED, 0xCFC2, 0x4E0B, 0xCFC3, 0x53A6, 0xCFC4, 0x590F, 0xCFC5, 0x5413, 0xCFC6, 0x6380, 0xCFC7, 0x9528, 0xCFC8, 0x5148, 0xCFC9, 0x4ED9, 0xCFCA, 0x9C9C, 0xCFCB, 0x7EA4, 0xCFCC, 0x54B8, 0xCFCD, 0x8D24, 0xCFCE, 0x8854, 0xCFCF, 0x8237, 0xCFD0, 0x95F2, 0xCFD1, 0x6D8E, 0xCFD2, 0x5F26, 0xCFD3, 0x5ACC, 0xCFD4, 0x663E, 0xCFD5, 0x9669, 0xCFD6, 0x73B0, 0xCFD7, 0x732E, 0xCFD8, 0x53BF, 0xCFD9, 0x817A, 0xCFDA, 0x9985, 0xCFDB, 0x7FA1, 0xCFDC, 0x5BAA, 0xCFDD, 0x9677, 0xCFDE, 0x9650, 0xCFDF, 0x7EBF, 0xCFE0, 0x76F8, 0xCFE1, 0x53A2, 0xCFE2, 0x9576, 0xCFE3, 0x9999, 0xCFE4, 0x7BB1, 0xCFE5, 0x8944, 0xCFE6, 0x6E58, 0xCFE7, 0x4E61, 0xCFE8, 0x7FD4, 0xCFE9, 0x7965, 0xCFEA, 0x8BE6, 0xCFEB, 0x60F3, 0xCFEC, 0x54CD, 0xCFED, 0x4EAB, 0xCFEE, 0x9879, 0xCFEF, 0x5DF7, 0xCFF0, 0x6A61, 0xCFF1, 0x50CF, 0xCFF2, 0x5411, 0xCFF3, 0x8C61, 0xCFF4, 0x8427, 0xCFF5, 0x785D, 0xCFF6, 0x9704, 0xCFF7, 0x524A, 0xCFF8, 0x54EE, 0xCFF9, 0x56A3, 0xCFFA, 0x9500, 0xCFFB, 0x6D88, 0xCFFC, 0x5BB5, 0xCFFD, 0x6DC6, 0xCFFE, 0x6653, 0xD040, 0x8824, 0xD041, 0x8825, 0xD042, 0x8826, 0xD043, 0x8827, 0xD044, 0x8828, 0xD045, 0x8829, 0xD046, 0x882A, 0xD047, 0x882B, 0xD048, 0x882C, 0xD049, 0x882D, 0xD04A, 0x882E, 0xD04B, 0x882F, 0xD04C, 0x8830, 0xD04D, 0x8831, 0xD04E, 0x8833, 0xD04F, 0x8834, 0xD050, 0x8835, 0xD051, 0x8836, 0xD052, 0x8837, 0xD053, 0x8838, 0xD054, 0x883A, 0xD055, 0x883B, 0xD056, 0x883D, 0xD057, 0x883E, 0xD058, 0x883F, 0xD059, 0x8841, 0xD05A, 0x8842, 0xD05B, 0x8843, 0xD05C, 0x8846, 0xD05D, 0x8847, 0xD05E, 0x8848, 0xD05F, 0x8849, 0xD060, 0x884A, 0xD061, 0x884B, 0xD062, 0x884E, 0xD063, 0x884F, 0xD064, 0x8850, 0xD065, 0x8851, 0xD066, 0x8852, 0xD067, 0x8853, 0xD068, 0x8855, 0xD069, 0x8856, 0xD06A, 0x8858, 0xD06B, 0x885A, 0xD06C, 0x885B, 0xD06D, 0x885C, 0xD06E, 0x885D, 0xD06F, 0x885E, 0xD070, 0x885F, 0xD071, 0x8860, 0xD072, 0x8866, 0xD073, 0x8867, 0xD074, 0x886A, 0xD075, 0x886D, 0xD076, 0x886F, 0xD077, 0x8871, 0xD078, 0x8873, 0xD079, 0x8874, 0xD07A, 0x8875, 0xD07B, 0x8876, 0xD07C, 0x8878, 0xD07D, 0x8879, 0xD07E, 0x887A, 0xD080, 0x887B, 0xD081, 0x887C, 0xD082, 0x8880, 0xD083, 0x8883, 0xD084, 0x8886, 0xD085, 0x8887, 0xD086, 0x8889, 0xD087, 0x888A, 0xD088, 0x888C, 0xD089, 0x888E, 0xD08A, 0x888F, 0xD08B, 0x8890, 0xD08C, 0x8891, 0xD08D, 0x8893, 0xD08E, 0x8894, 0xD08F, 0x8895, 0xD090, 0x8897, 0xD091, 0x8898, 0xD092, 0x8899, 0xD093, 0x889A, 0xD094, 0x889B, 0xD095, 0x889D, 0xD096, 0x889E, 0xD097, 0x889F, 0xD098, 0x88A0, 0xD099, 0x88A1, 0xD09A, 0x88A3, 0xD09B, 0x88A5, 0xD09C, 0x88A6, 0xD09D, 0x88A7, 0xD09E, 0x88A8, 0xD09F, 0x88A9, 0xD0A0, 0x88AA, 0xD0A1, 0x5C0F, 0xD0A2, 0x5B5D, 0xD0A3, 0x6821, 0xD0A4, 0x8096, 0xD0A5, 0x5578, 0xD0A6, 0x7B11, 0xD0A7, 0x6548, 0xD0A8, 0x6954, 0xD0A9, 0x4E9B, 0xD0AA, 0x6B47, 0xD0AB, 0x874E, 0xD0AC, 0x978B, 0xD0AD, 0x534F, 0xD0AE, 0x631F, 0xD0AF, 0x643A, 0xD0B0, 0x90AA, 0xD0B1, 0x659C, 0xD0B2, 0x80C1, 0xD0B3, 0x8C10, 0xD0B4, 0x5199, 0xD0B5, 0x68B0, 0xD0B6, 0x5378, 0xD0B7, 0x87F9, 0xD0B8, 0x61C8, 0xD0B9, 0x6CC4, 0xD0BA, 0x6CFB, 0xD0BB, 0x8C22, 0xD0BC, 0x5C51, 0xD0BD, 0x85AA, 0xD0BE, 0x82AF, 0xD0BF, 0x950C, 0xD0C0, 0x6B23, 0xD0C1, 0x8F9B, 0xD0C2, 0x65B0, 0xD0C3, 0x5FFB, 0xD0C4, 0x5FC3, 0xD0C5, 0x4FE1, 0xD0C6, 0x8845, 0xD0C7, 0x661F, 0xD0C8, 0x8165, 0xD0C9, 0x7329, 0xD0CA, 0x60FA, 0xD0CB, 0x5174, 0xD0CC, 0x5211, 0xD0CD, 0x578B, 0xD0CE, 0x5F62, 0xD0CF, 0x90A2, 0xD0D0, 0x884C, 0xD0D1, 0x9192, 0xD0D2, 0x5E78, 0xD0D3, 0x674F, 0xD0D4, 0x6027, 0xD0D5, 0x59D3, 0xD0D6, 0x5144, 0xD0D7, 0x51F6, 0xD0D8, 0x80F8, 0xD0D9, 0x5308, 0xD0DA, 0x6C79, 0xD0DB, 0x96C4, 0xD0DC, 0x718A, 0xD0DD, 0x4F11, 0xD0DE, 0x4FEE, 0xD0DF, 0x7F9E, 0xD0E0, 0x673D, 0xD0E1, 0x55C5, 0xD0E2, 0x9508, 0xD0E3, 0x79C0, 0xD0E4, 0x8896, 0xD0E5, 0x7EE3, 0xD0E6, 0x589F, 0xD0E7, 0x620C, 0xD0E8, 0x9700, 0xD0E9, 0x865A, 0xD0EA, 0x5618, 0xD0EB, 0x987B, 0xD0EC, 0x5F90, 0xD0ED, 0x8BB8, 0xD0EE, 0x84C4, 0xD0EF, 0x9157, 0xD0F0, 0x53D9, 0xD0F1, 0x65ED, 0xD0F2, 0x5E8F, 0xD0F3, 0x755C, 0xD0F4, 0x6064, 0xD0F5, 0x7D6E, 0xD0F6, 0x5A7F, 0xD0F7, 0x7EEA, 0xD0F8, 0x7EED, 0xD0F9, 0x8F69, 0xD0FA, 0x55A7, 0xD0FB, 0x5BA3, 0xD0FC, 0x60AC, 0xD0FD, 0x65CB, 0xD0FE, 0x7384, 0xD140, 0x88AC, 0xD141, 0x88AE, 0xD142, 0x88AF, 0xD143, 0x88B0, 0xD144, 0x88B2, 0xD145, 0x88B3, 0xD146, 0x88B4, 0xD147, 0x88B5, 0xD148, 0x88B6, 0xD149, 0x88B8, 0xD14A, 0x88B9, 0xD14B, 0x88BA, 0xD14C, 0x88BB, 0xD14D, 0x88BD, 0xD14E, 0x88BE, 0xD14F, 0x88BF, 0xD150, 0x88C0, 0xD151, 0x88C3, 0xD152, 0x88C4, 0xD153, 0x88C7, 0xD154, 0x88C8, 0xD155, 0x88CA, 0xD156, 0x88CB, 0xD157, 0x88CC, 0xD158, 0x88CD, 0xD159, 0x88CF, 0xD15A, 0x88D0, 0xD15B, 0x88D1, 0xD15C, 0x88D3, 0xD15D, 0x88D6, 0xD15E, 0x88D7, 0xD15F, 0x88DA, 0xD160, 0x88DB, 0xD161, 0x88DC, 0xD162, 0x88DD, 0xD163, 0x88DE, 0xD164, 0x88E0, 0xD165, 0x88E1, 0xD166, 0x88E6, 0xD167, 0x88E7, 0xD168, 0x88E9, 0xD169, 0x88EA, 0xD16A, 0x88EB, 0xD16B, 0x88EC, 0xD16C, 0x88ED, 0xD16D, 0x88EE, 0xD16E, 0x88EF, 0xD16F, 0x88F2, 0xD170, 0x88F5, 0xD171, 0x88F6, 0xD172, 0x88F7, 0xD173, 0x88FA, 0xD174, 0x88FB, 0xD175, 0x88FD, 0xD176, 0x88FF, 0xD177, 0x8900, 0xD178, 0x8901, 0xD179, 0x8903, 0xD17A, 0x8904, 0xD17B, 0x8905, 0xD17C, 0x8906, 0xD17D, 0x8907, 0xD17E, 0x8908, 0xD180, 0x8909, 0xD181, 0x890B, 0xD182, 0x890C, 0xD183, 0x890D, 0xD184, 0x890E, 0xD185, 0x890F, 0xD186, 0x8911, 0xD187, 0x8914, 0xD188, 0x8915, 0xD189, 0x8916, 0xD18A, 0x8917, 0xD18B, 0x8918, 0xD18C, 0x891C, 0xD18D, 0x891D, 0xD18E, 0x891E, 0xD18F, 0x891F, 0xD190, 0x8920, 0xD191, 0x8922, 0xD192, 0x8923, 0xD193, 0x8924, 0xD194, 0x8926, 0xD195, 0x8927, 0xD196, 0x8928, 0xD197, 0x8929, 0xD198, 0x892C, 0xD199, 0x892D, 0xD19A, 0x892E, 0xD19B, 0x892F, 0xD19C, 0x8931, 0xD19D, 0x8932, 0xD19E, 0x8933, 0xD19F, 0x8935, 0xD1A0, 0x8937, 0xD1A1, 0x9009, 0xD1A2, 0x7663, 0xD1A3, 0x7729, 0xD1A4, 0x7EDA, 0xD1A5, 0x9774, 0xD1A6, 0x859B, 0xD1A7, 0x5B66, 0xD1A8, 0x7A74, 0xD1A9, 0x96EA, 0xD1AA, 0x8840, 0xD1AB, 0x52CB, 0xD1AC, 0x718F, 0xD1AD, 0x5FAA, 0xD1AE, 0x65EC, 0xD1AF, 0x8BE2, 0xD1B0, 0x5BFB, 0xD1B1, 0x9A6F, 0xD1B2, 0x5DE1, 0xD1B3, 0x6B89, 0xD1B4, 0x6C5B, 0xD1B5, 0x8BAD, 0xD1B6, 0x8BAF, 0xD1B7, 0x900A, 0xD1B8, 0x8FC5, 0xD1B9, 0x538B, 0xD1BA, 0x62BC, 0xD1BB, 0x9E26, 0xD1BC, 0x9E2D, 0xD1BD, 0x5440, 0xD1BE, 0x4E2B, 0xD1BF, 0x82BD, 0xD1C0, 0x7259, 0xD1C1, 0x869C, 0xD1C2, 0x5D16, 0xD1C3, 0x8859, 0xD1C4, 0x6DAF, 0xD1C5, 0x96C5, 0xD1C6, 0x54D1, 0xD1C7, 0x4E9A, 0xD1C8, 0x8BB6, 0xD1C9, 0x7109, 0xD1CA, 0x54BD, 0xD1CB, 0x9609, 0xD1CC, 0x70DF, 0xD1CD, 0x6DF9, 0xD1CE, 0x76D0, 0xD1CF, 0x4E25, 0xD1D0, 0x7814, 0xD1D1, 0x8712, 0xD1D2, 0x5CA9, 0xD1D3, 0x5EF6, 0xD1D4, 0x8A00, 0xD1D5, 0x989C, 0xD1D6, 0x960E, 0xD1D7, 0x708E, 0xD1D8, 0x6CBF, 0xD1D9, 0x5944, 0xD1DA, 0x63A9, 0xD1DB, 0x773C, 0xD1DC, 0x884D, 0xD1DD, 0x6F14, 0xD1DE, 0x8273, 0xD1DF, 0x5830, 0xD1E0, 0x71D5, 0xD1E1, 0x538C, 0xD1E2, 0x781A, 0xD1E3, 0x96C1, 0xD1E4, 0x5501, 0xD1E5, 0x5F66, 0xD1E6, 0x7130, 0xD1E7, 0x5BB4, 0xD1E8, 0x8C1A, 0xD1E9, 0x9A8C, 0xD1EA, 0x6B83, 0xD1EB, 0x592E, 0xD1EC, 0x9E2F, 0xD1ED, 0x79E7, 0xD1EE, 0x6768, 0xD1EF, 0x626C, 0xD1F0, 0x4F6F, 0xD1F1, 0x75A1, 0xD1F2, 0x7F8A, 0xD1F3, 0x6D0B, 0xD1F4, 0x9633, 0xD1F5, 0x6C27, 0xD1F6, 0x4EF0, 0xD1F7, 0x75D2, 0xD1F8, 0x517B, 0xD1F9, 0x6837, 0xD1FA, 0x6F3E, 0xD1FB, 0x9080, 0xD1FC, 0x8170, 0xD1FD, 0x5996, 0xD1FE, 0x7476, 0xD240, 0x8938, 0xD241, 0x8939, 0xD242, 0x893A, 0xD243, 0x893B, 0xD244, 0x893C, 0xD245, 0x893D, 0xD246, 0x893E, 0xD247, 0x893F, 0xD248, 0x8940, 0xD249, 0x8942, 0xD24A, 0x8943, 0xD24B, 0x8945, 0xD24C, 0x8946, 0xD24D, 0x8947, 0xD24E, 0x8948, 0xD24F, 0x8949, 0xD250, 0x894A, 0xD251, 0x894B, 0xD252, 0x894C, 0xD253, 0x894D, 0xD254, 0x894E, 0xD255, 0x894F, 0xD256, 0x8950, 0xD257, 0x8951, 0xD258, 0x8952, 0xD259, 0x8953, 0xD25A, 0x8954, 0xD25B, 0x8955, 0xD25C, 0x8956, 0xD25D, 0x8957, 0xD25E, 0x8958, 0xD25F, 0x8959, 0xD260, 0x895A, 0xD261, 0x895B, 0xD262, 0x895C, 0xD263, 0x895D, 0xD264, 0x8960, 0xD265, 0x8961, 0xD266, 0x8962, 0xD267, 0x8963, 0xD268, 0x8964, 0xD269, 0x8965, 0xD26A, 0x8967, 0xD26B, 0x8968, 0xD26C, 0x8969, 0xD26D, 0x896A, 0xD26E, 0x896B, 0xD26F, 0x896C, 0xD270, 0x896D, 0xD271, 0x896E, 0xD272, 0x896F, 0xD273, 0x8970, 0xD274, 0x8971, 0xD275, 0x8972, 0xD276, 0x8973, 0xD277, 0x8974, 0xD278, 0x8975, 0xD279, 0x8976, 0xD27A, 0x8977, 0xD27B, 0x8978, 0xD27C, 0x8979, 0xD27D, 0x897A, 0xD27E, 0x897C, 0xD280, 0x897D, 0xD281, 0x897E, 0xD282, 0x8980, 0xD283, 0x8982, 0xD284, 0x8984, 0xD285, 0x8985, 0xD286, 0x8987, 0xD287, 0x8988, 0xD288, 0x8989, 0xD289, 0x898A, 0xD28A, 0x898B, 0xD28B, 0x898C, 0xD28C, 0x898D, 0xD28D, 0x898E, 0xD28E, 0x898F, 0xD28F, 0x8990, 0xD290, 0x8991, 0xD291, 0x8992, 0xD292, 0x8993, 0xD293, 0x8994, 0xD294, 0x8995, 0xD295, 0x8996, 0xD296, 0x8997, 0xD297, 0x8998, 0xD298, 0x8999, 0xD299, 0x899A, 0xD29A, 0x899B, 0xD29B, 0x899C, 0xD29C, 0x899D, 0xD29D, 0x899E, 0xD29E, 0x899F, 0xD29F, 0x89A0, 0xD2A0, 0x89A1, 0xD2A1, 0x6447, 0xD2A2, 0x5C27, 0xD2A3, 0x9065, 0xD2A4, 0x7A91, 0xD2A5, 0x8C23, 0xD2A6, 0x59DA, 0xD2A7, 0x54AC, 0xD2A8, 0x8200, 0xD2A9, 0x836F, 0xD2AA, 0x8981, 0xD2AB, 0x8000, 0xD2AC, 0x6930, 0xD2AD, 0x564E, 0xD2AE, 0x8036, 0xD2AF, 0x7237, 0xD2B0, 0x91CE, 0xD2B1, 0x51B6, 0xD2B2, 0x4E5F, 0xD2B3, 0x9875, 0xD2B4, 0x6396, 0xD2B5, 0x4E1A, 0xD2B6, 0x53F6, 0xD2B7, 0x66F3, 0xD2B8, 0x814B, 0xD2B9, 0x591C, 0xD2BA, 0x6DB2, 0xD2BB, 0x4E00, 0xD2BC, 0x58F9, 0xD2BD, 0x533B, 0xD2BE, 0x63D6, 0xD2BF, 0x94F1, 0xD2C0, 0x4F9D, 0xD2C1, 0x4F0A, 0xD2C2, 0x8863, 0xD2C3, 0x9890, 0xD2C4, 0x5937, 0xD2C5, 0x9057, 0xD2C6, 0x79FB, 0xD2C7, 0x4EEA, 0xD2C8, 0x80F0, 0xD2C9, 0x7591, 0xD2CA, 0x6C82, 0xD2CB, 0x5B9C, 0xD2CC, 0x59E8, 0xD2CD, 0x5F5D, 0xD2CE, 0x6905, 0xD2CF, 0x8681, 0xD2D0, 0x501A, 0xD2D1, 0x5DF2, 0xD2D2, 0x4E59, 0xD2D3, 0x77E3, 0xD2D4, 0x4EE5, 0xD2D5, 0x827A, 0xD2D6, 0x6291, 0xD2D7, 0x6613, 0xD2D8, 0x9091, 0xD2D9, 0x5C79, 0xD2DA, 0x4EBF, 0xD2DB, 0x5F79, 0xD2DC, 0x81C6, 0xD2DD, 0x9038, 0xD2DE, 0x8084, 0xD2DF, 0x75AB, 0xD2E0, 0x4EA6, 0xD2E1, 0x88D4, 0xD2E2, 0x610F, 0xD2E3, 0x6BC5, 0xD2E4, 0x5FC6, 0xD2E5, 0x4E49, 0xD2E6, 0x76CA, 0xD2E7, 0x6EA2, 0xD2E8, 0x8BE3, 0xD2E9, 0x8BAE, 0xD2EA, 0x8C0A, 0xD2EB, 0x8BD1, 0xD2EC, 0x5F02, 0xD2ED, 0x7FFC, 0xD2EE, 0x7FCC, 0xD2EF, 0x7ECE, 0xD2F0, 0x8335, 0xD2F1, 0x836B, 0xD2F2, 0x56E0, 0xD2F3, 0x6BB7, 0xD2F4, 0x97F3, 0xD2F5, 0x9634, 0xD2F6, 0x59FB, 0xD2F7, 0x541F, 0xD2F8, 0x94F6, 0xD2F9, 0x6DEB, 0xD2FA, 0x5BC5, 0xD2FB, 0x996E, 0xD2FC, 0x5C39, 0xD2FD, 0x5F15, 0xD2FE, 0x9690, 0xD340, 0x89A2, 0xD341, 0x89A3, 0xD342, 0x89A4, 0xD343, 0x89A5, 0xD344, 0x89A6, 0xD345, 0x89A7, 0xD346, 0x89A8, 0xD347, 0x89A9, 0xD348, 0x89AA, 0xD349, 0x89AB, 0xD34A, 0x89AC, 0xD34B, 0x89AD, 0xD34C, 0x89AE, 0xD34D, 0x89AF, 0xD34E, 0x89B0, 0xD34F, 0x89B1, 0xD350, 0x89B2, 0xD351, 0x89B3, 0xD352, 0x89B4, 0xD353, 0x89B5, 0xD354, 0x89B6, 0xD355, 0x89B7, 0xD356, 0x89B8, 0xD357, 0x89B9, 0xD358, 0x89BA, 0xD359, 0x89BB, 0xD35A, 0x89BC, 0xD35B, 0x89BD, 0xD35C, 0x89BE, 0xD35D, 0x89BF, 0xD35E, 0x89C0, 0xD35F, 0x89C3, 0xD360, 0x89CD, 0xD361, 0x89D3, 0xD362, 0x89D4, 0xD363, 0x89D5, 0xD364, 0x89D7, 0xD365, 0x89D8, 0xD366, 0x89D9, 0xD367, 0x89DB, 0xD368, 0x89DD, 0xD369, 0x89DF, 0xD36A, 0x89E0, 0xD36B, 0x89E1, 0xD36C, 0x89E2, 0xD36D, 0x89E4, 0xD36E, 0x89E7, 0xD36F, 0x89E8, 0xD370, 0x89E9, 0xD371, 0x89EA, 0xD372, 0x89EC, 0xD373, 0x89ED, 0xD374, 0x89EE, 0xD375, 0x89F0, 0xD376, 0x89F1, 0xD377, 0x89F2, 0xD378, 0x89F4, 0xD379, 0x89F5, 0xD37A, 0x89F6, 0xD37B, 0x89F7, 0xD37C, 0x89F8, 0xD37D, 0x89F9, 0xD37E, 0x89FA, 0xD380, 0x89FB, 0xD381, 0x89FC, 0xD382, 0x89FD, 0xD383, 0x89FE, 0xD384, 0x89FF, 0xD385, 0x8A01, 0xD386, 0x8A02, 0xD387, 0x8A03, 0xD388, 0x8A04, 0xD389, 0x8A05, 0xD38A, 0x8A06, 0xD38B, 0x8A08, 0xD38C, 0x8A09, 0xD38D, 0x8A0A, 0xD38E, 0x8A0B, 0xD38F, 0x8A0C, 0xD390, 0x8A0D, 0xD391, 0x8A0E, 0xD392, 0x8A0F, 0xD393, 0x8A10, 0xD394, 0x8A11, 0xD395, 0x8A12, 0xD396, 0x8A13, 0xD397, 0x8A14, 0xD398, 0x8A15, 0xD399, 0x8A16, 0xD39A, 0x8A17, 0xD39B, 0x8A18, 0xD39C, 0x8A19, 0xD39D, 0x8A1A, 0xD39E, 0x8A1B, 0xD39F, 0x8A1C, 0xD3A0, 0x8A1D, 0xD3A1, 0x5370, 0xD3A2, 0x82F1, 0xD3A3, 0x6A31, 0xD3A4, 0x5A74, 0xD3A5, 0x9E70, 0xD3A6, 0x5E94, 0xD3A7, 0x7F28, 0xD3A8, 0x83B9, 0xD3A9, 0x8424, 0xD3AA, 0x8425, 0xD3AB, 0x8367, 0xD3AC, 0x8747, 0xD3AD, 0x8FCE, 0xD3AE, 0x8D62, 0xD3AF, 0x76C8, 0xD3B0, 0x5F71, 0xD3B1, 0x9896, 0xD3B2, 0x786C, 0xD3B3, 0x6620, 0xD3B4, 0x54DF, 0xD3B5, 0x62E5, 0xD3B6, 0x4F63, 0xD3B7, 0x81C3, 0xD3B8, 0x75C8, 0xD3B9, 0x5EB8, 0xD3BA, 0x96CD, 0xD3BB, 0x8E0A, 0xD3BC, 0x86F9, 0xD3BD, 0x548F, 0xD3BE, 0x6CF3, 0xD3BF, 0x6D8C, 0xD3C0, 0x6C38, 0xD3C1, 0x607F, 0xD3C2, 0x52C7, 0xD3C3, 0x7528, 0xD3C4, 0x5E7D, 0xD3C5, 0x4F18, 0xD3C6, 0x60A0, 0xD3C7, 0x5FE7, 0xD3C8, 0x5C24, 0xD3C9, 0x7531, 0xD3CA, 0x90AE, 0xD3CB, 0x94C0, 0xD3CC, 0x72B9, 0xD3CD, 0x6CB9, 0xD3CE, 0x6E38, 0xD3CF, 0x9149, 0xD3D0, 0x6709, 0xD3D1, 0x53CB, 0xD3D2, 0x53F3, 0xD3D3, 0x4F51, 0xD3D4, 0x91C9, 0xD3D5, 0x8BF1, 0xD3D6, 0x53C8, 0xD3D7, 0x5E7C, 0xD3D8, 0x8FC2, 0xD3D9, 0x6DE4, 0xD3DA, 0x4E8E, 0xD3DB, 0x76C2, 0xD3DC, 0x6986, 0xD3DD, 0x865E, 0xD3DE, 0x611A, 0xD3DF, 0x8206, 0xD3E0, 0x4F59, 0xD3E1, 0x4FDE, 0xD3E2, 0x903E, 0xD3E3, 0x9C7C, 0xD3E4, 0x6109, 0xD3E5, 0x6E1D, 0xD3E6, 0x6E14, 0xD3E7, 0x9685, 0xD3E8, 0x4E88, 0xD3E9, 0x5A31, 0xD3EA, 0x96E8, 0xD3EB, 0x4E0E, 0xD3EC, 0x5C7F, 0xD3ED, 0x79B9, 0xD3EE, 0x5B87, 0xD3EF, 0x8BED, 0xD3F0, 0x7FBD, 0xD3F1, 0x7389, 0xD3F2, 0x57DF, 0xD3F3, 0x828B, 0xD3F4, 0x90C1, 0xD3F5, 0x5401, 0xD3F6, 0x9047, 0xD3F7, 0x55BB, 0xD3F8, 0x5CEA, 0xD3F9, 0x5FA1, 0xD3FA, 0x6108, 0xD3FB, 0x6B32, 0xD3FC, 0x72F1, 0xD3FD, 0x80B2, 0xD3FE, 0x8A89, 0xD440, 0x8A1E, 0xD441, 0x8A1F, 0xD442, 0x8A20, 0xD443, 0x8A21, 0xD444, 0x8A22, 0xD445, 0x8A23, 0xD446, 0x8A24, 0xD447, 0x8A25, 0xD448, 0x8A26, 0xD449, 0x8A27, 0xD44A, 0x8A28, 0xD44B, 0x8A29, 0xD44C, 0x8A2A, 0xD44D, 0x8A2B, 0xD44E, 0x8A2C, 0xD44F, 0x8A2D, 0xD450, 0x8A2E, 0xD451, 0x8A2F, 0xD452, 0x8A30, 0xD453, 0x8A31, 0xD454, 0x8A32, 0xD455, 0x8A33, 0xD456, 0x8A34, 0xD457, 0x8A35, 0xD458, 0x8A36, 0xD459, 0x8A37, 0xD45A, 0x8A38, 0xD45B, 0x8A39, 0xD45C, 0x8A3A, 0xD45D, 0x8A3B, 0xD45E, 0x8A3C, 0xD45F, 0x8A3D, 0xD460, 0x8A3F, 0xD461, 0x8A40, 0xD462, 0x8A41, 0xD463, 0x8A42, 0xD464, 0x8A43, 0xD465, 0x8A44, 0xD466, 0x8A45, 0xD467, 0x8A46, 0xD468, 0x8A47, 0xD469, 0x8A49, 0xD46A, 0x8A4A, 0xD46B, 0x8A4B, 0xD46C, 0x8A4C, 0xD46D, 0x8A4D, 0xD46E, 0x8A4E, 0xD46F, 0x8A4F, 0xD470, 0x8A50, 0xD471, 0x8A51, 0xD472, 0x8A52, 0xD473, 0x8A53, 0xD474, 0x8A54, 0xD475, 0x8A55, 0xD476, 0x8A56, 0xD477, 0x8A57, 0xD478, 0x8A58, 0xD479, 0x8A59, 0xD47A, 0x8A5A, 0xD47B, 0x8A5B, 0xD47C, 0x8A5C, 0xD47D, 0x8A5D, 0xD47E, 0x8A5E, 0xD480, 0x8A5F, 0xD481, 0x8A60, 0xD482, 0x8A61, 0xD483, 0x8A62, 0xD484, 0x8A63, 0xD485, 0x8A64, 0xD486, 0x8A65, 0xD487, 0x8A66, 0xD488, 0x8A67, 0xD489, 0x8A68, 0xD48A, 0x8A69, 0xD48B, 0x8A6A, 0xD48C, 0x8A6B, 0xD48D, 0x8A6C, 0xD48E, 0x8A6D, 0xD48F, 0x8A6E, 0xD490, 0x8A6F, 0xD491, 0x8A70, 0xD492, 0x8A71, 0xD493, 0x8A72, 0xD494, 0x8A73, 0xD495, 0x8A74, 0xD496, 0x8A75, 0xD497, 0x8A76, 0xD498, 0x8A77, 0xD499, 0x8A78, 0xD49A, 0x8A7A, 0xD49B, 0x8A7B, 0xD49C, 0x8A7C, 0xD49D, 0x8A7D, 0xD49E, 0x8A7E, 0xD49F, 0x8A7F, 0xD4A0, 0x8A80, 0xD4A1, 0x6D74, 0xD4A2, 0x5BD3, 0xD4A3, 0x88D5, 0xD4A4, 0x9884, 0xD4A5, 0x8C6B, 0xD4A6, 0x9A6D, 0xD4A7, 0x9E33, 0xD4A8, 0x6E0A, 0xD4A9, 0x51A4, 0xD4AA, 0x5143, 0xD4AB, 0x57A3, 0xD4AC, 0x8881, 0xD4AD, 0x539F, 0xD4AE, 0x63F4, 0xD4AF, 0x8F95, 0xD4B0, 0x56ED, 0xD4B1, 0x5458, 0xD4B2, 0x5706, 0xD4B3, 0x733F, 0xD4B4, 0x6E90, 0xD4B5, 0x7F18, 0xD4B6, 0x8FDC, 0xD4B7, 0x82D1, 0xD4B8, 0x613F, 0xD4B9, 0x6028, 0xD4BA, 0x9662, 0xD4BB, 0x66F0, 0xD4BC, 0x7EA6, 0xD4BD, 0x8D8A, 0xD4BE, 0x8DC3, 0xD4BF, 0x94A5, 0xD4C0, 0x5CB3, 0xD4C1, 0x7CA4, 0xD4C2, 0x6708, 0xD4C3, 0x60A6, 0xD4C4, 0x9605, 0xD4C5, 0x8018, 0xD4C6, 0x4E91, 0xD4C7, 0x90E7, 0xD4C8, 0x5300, 0xD4C9, 0x9668, 0xD4CA, 0x5141, 0xD4CB, 0x8FD0, 0xD4CC, 0x8574, 0xD4CD, 0x915D, 0xD4CE, 0x6655, 0xD4CF, 0x97F5, 0xD4D0, 0x5B55, 0xD4D1, 0x531D, 0xD4D2, 0x7838, 0xD4D3, 0x6742, 0xD4D4, 0x683D, 0xD4D5, 0x54C9, 0xD4D6, 0x707E, 0xD4D7, 0x5BB0, 0xD4D8, 0x8F7D, 0xD4D9, 0x518D, 0xD4DA, 0x5728, 0xD4DB, 0x54B1, 0xD4DC, 0x6512, 0xD4DD, 0x6682, 0xD4DE, 0x8D5E, 0xD4DF, 0x8D43, 0xD4E0, 0x810F, 0xD4E1, 0x846C, 0xD4E2, 0x906D, 0xD4E3, 0x7CDF, 0xD4E4, 0x51FF, 0xD4E5, 0x85FB, 0xD4E6, 0x67A3, 0xD4E7, 0x65E9, 0xD4E8, 0x6FA1, 0xD4E9, 0x86A4, 0xD4EA, 0x8E81, 0xD4EB, 0x566A, 0xD4EC, 0x9020, 0xD4ED, 0x7682, 0xD4EE, 0x7076, 0xD4EF, 0x71E5, 0xD4F0, 0x8D23, 0xD4F1, 0x62E9, 0xD4F2, 0x5219, 0xD4F3, 0x6CFD, 0xD4F4, 0x8D3C, 0xD4F5, 0x600E, 0xD4F6, 0x589E, 0xD4F7, 0x618E, 0xD4F8, 0x66FE, 0xD4F9, 0x8D60, 0xD4FA, 0x624E, 0xD4FB, 0x55B3, 0xD4FC, 0x6E23, 0xD4FD, 0x672D, 0xD4FE, 0x8F67, 0xD540, 0x8A81, 0xD541, 0x8A82, 0xD542, 0x8A83, 0xD543, 0x8A84, 0xD544, 0x8A85, 0xD545, 0x8A86, 0xD546, 0x8A87, 0xD547, 0x8A88, 0xD548, 0x8A8B, 0xD549, 0x8A8C, 0xD54A, 0x8A8D, 0xD54B, 0x8A8E, 0xD54C, 0x8A8F, 0xD54D, 0x8A90, 0xD54E, 0x8A91, 0xD54F, 0x8A92, 0xD550, 0x8A94, 0xD551, 0x8A95, 0xD552, 0x8A96, 0xD553, 0x8A97, 0xD554, 0x8A98, 0xD555, 0x8A99, 0xD556, 0x8A9A, 0xD557, 0x8A9B, 0xD558, 0x8A9C, 0xD559, 0x8A9D, 0xD55A, 0x8A9E, 0xD55B, 0x8A9F, 0xD55C, 0x8AA0, 0xD55D, 0x8AA1, 0xD55E, 0x8AA2, 0xD55F, 0x8AA3, 0xD560, 0x8AA4, 0xD561, 0x8AA5, 0xD562, 0x8AA6, 0xD563, 0x8AA7, 0xD564, 0x8AA8, 0xD565, 0x8AA9, 0xD566, 0x8AAA, 0xD567, 0x8AAB, 0xD568, 0x8AAC, 0xD569, 0x8AAD, 0xD56A, 0x8AAE, 0xD56B, 0x8AAF, 0xD56C, 0x8AB0, 0xD56D, 0x8AB1, 0xD56E, 0x8AB2, 0xD56F, 0x8AB3, 0xD570, 0x8AB4, 0xD571, 0x8AB5, 0xD572, 0x8AB6, 0xD573, 0x8AB7, 0xD574, 0x8AB8, 0xD575, 0x8AB9, 0xD576, 0x8ABA, 0xD577, 0x8ABB, 0xD578, 0x8ABC, 0xD579, 0x8ABD, 0xD57A, 0x8ABE, 0xD57B, 0x8ABF, 0xD57C, 0x8AC0, 0xD57D, 0x8AC1, 0xD57E, 0x8AC2, 0xD580, 0x8AC3, 0xD581, 0x8AC4, 0xD582, 0x8AC5, 0xD583, 0x8AC6, 0xD584, 0x8AC7, 0xD585, 0x8AC8, 0xD586, 0x8AC9, 0xD587, 0x8ACA, 0xD588, 0x8ACB, 0xD589, 0x8ACC, 0xD58A, 0x8ACD, 0xD58B, 0x8ACE, 0xD58C, 0x8ACF, 0xD58D, 0x8AD0, 0xD58E, 0x8AD1, 0xD58F, 0x8AD2, 0xD590, 0x8AD3, 0xD591, 0x8AD4, 0xD592, 0x8AD5, 0xD593, 0x8AD6, 0xD594, 0x8AD7, 0xD595, 0x8AD8, 0xD596, 0x8AD9, 0xD597, 0x8ADA, 0xD598, 0x8ADB, 0xD599, 0x8ADC, 0xD59A, 0x8ADD, 0xD59B, 0x8ADE, 0xD59C, 0x8ADF, 0xD59D, 0x8AE0, 0xD59E, 0x8AE1, 0xD59F, 0x8AE2, 0xD5A0, 0x8AE3, 0xD5A1, 0x94E1, 0xD5A2, 0x95F8, 0xD5A3, 0x7728, 0xD5A4, 0x6805, 0xD5A5, 0x69A8, 0xD5A6, 0x548B, 0xD5A7, 0x4E4D, 0xD5A8, 0x70B8, 0xD5A9, 0x8BC8, 0xD5AA, 0x6458, 0xD5AB, 0x658B, 0xD5AC, 0x5B85, 0xD5AD, 0x7A84, 0xD5AE, 0x503A, 0xD5AF, 0x5BE8, 0xD5B0, 0x77BB, 0xD5B1, 0x6BE1, 0xD5B2, 0x8A79, 0xD5B3, 0x7C98, 0xD5B4, 0x6CBE, 0xD5B5, 0x76CF, 0xD5B6, 0x65A9, 0xD5B7, 0x8F97, 0xD5B8, 0x5D2D, 0xD5B9, 0x5C55, 0xD5BA, 0x8638, 0xD5BB, 0x6808, 0xD5BC, 0x5360, 0xD5BD, 0x6218, 0xD5BE, 0x7AD9, 0xD5BF, 0x6E5B, 0xD5C0, 0x7EFD, 0xD5C1, 0x6A1F, 0xD5C2, 0x7AE0, 0xD5C3, 0x5F70, 0xD5C4, 0x6F33, 0xD5C5, 0x5F20, 0xD5C6, 0x638C, 0xD5C7, 0x6DA8, 0xD5C8, 0x6756, 0xD5C9, 0x4E08, 0xD5CA, 0x5E10, 0xD5CB, 0x8D26, 0xD5CC, 0x4ED7, 0xD5CD, 0x80C0, 0xD5CE, 0x7634, 0xD5CF, 0x969C, 0xD5D0, 0x62DB, 0xD5D1, 0x662D, 0xD5D2, 0x627E, 0xD5D3, 0x6CBC, 0xD5D4, 0x8D75, 0xD5D5, 0x7167, 0xD5D6, 0x7F69, 0xD5D7, 0x5146, 0xD5D8, 0x8087, 0xD5D9, 0x53EC, 0xD5DA, 0x906E, 0xD5DB, 0x6298, 0xD5DC, 0x54F2, 0xD5DD, 0x86F0, 0xD5DE, 0x8F99, 0xD5DF, 0x8005, 0xD5E0, 0x9517, 0xD5E1, 0x8517, 0xD5E2, 0x8FD9, 0xD5E3, 0x6D59, 0xD5E4, 0x73CD, 0xD5E5, 0x659F, 0xD5E6, 0x771F, 0xD5E7, 0x7504, 0xD5E8, 0x7827, 0xD5E9, 0x81FB, 0xD5EA, 0x8D1E, 0xD5EB, 0x9488, 0xD5EC, 0x4FA6, 0xD5ED, 0x6795, 0xD5EE, 0x75B9, 0xD5EF, 0x8BCA, 0xD5F0, 0x9707, 0xD5F1, 0x632F, 0xD5F2, 0x9547, 0xD5F3, 0x9635, 0xD5F4, 0x84B8, 0xD5F5, 0x6323, 0xD5F6, 0x7741, 0xD5F7, 0x5F81, 0xD5F8, 0x72F0, 0xD5F9, 0x4E89, 0xD5FA, 0x6014, 0xD5FB, 0x6574, 0xD5FC, 0x62EF, 0xD5FD, 0x6B63, 0xD5FE, 0x653F, 0xD640, 0x8AE4, 0xD641, 0x8AE5, 0xD642, 0x8AE6, 0xD643, 0x8AE7, 0xD644, 0x8AE8, 0xD645, 0x8AE9, 0xD646, 0x8AEA, 0xD647, 0x8AEB, 0xD648, 0x8AEC, 0xD649, 0x8AED, 0xD64A, 0x8AEE, 0xD64B, 0x8AEF, 0xD64C, 0x8AF0, 0xD64D, 0x8AF1, 0xD64E, 0x8AF2, 0xD64F, 0x8AF3, 0xD650, 0x8AF4, 0xD651, 0x8AF5, 0xD652, 0x8AF6, 0xD653, 0x8AF7, 0xD654, 0x8AF8, 0xD655, 0x8AF9, 0xD656, 0x8AFA, 0xD657, 0x8AFB, 0xD658, 0x8AFC, 0xD659, 0x8AFD, 0xD65A, 0x8AFE, 0xD65B, 0x8AFF, 0xD65C, 0x8B00, 0xD65D, 0x8B01, 0xD65E, 0x8B02, 0xD65F, 0x8B03, 0xD660, 0x8B04, 0xD661, 0x8B05, 0xD662, 0x8B06, 0xD663, 0x8B08, 0xD664, 0x8B09, 0xD665, 0x8B0A, 0xD666, 0x8B0B, 0xD667, 0x8B0C, 0xD668, 0x8B0D, 0xD669, 0x8B0E, 0xD66A, 0x8B0F, 0xD66B, 0x8B10, 0xD66C, 0x8B11, 0xD66D, 0x8B12, 0xD66E, 0x8B13, 0xD66F, 0x8B14, 0xD670, 0x8B15, 0xD671, 0x8B16, 0xD672, 0x8B17, 0xD673, 0x8B18, 0xD674, 0x8B19, 0xD675, 0x8B1A, 0xD676, 0x8B1B, 0xD677, 0x8B1C, 0xD678, 0x8B1D, 0xD679, 0x8B1E, 0xD67A, 0x8B1F, 0xD67B, 0x8B20, 0xD67C, 0x8B21, 0xD67D, 0x8B22, 0xD67E, 0x8B23, 0xD680, 0x8B24, 0xD681, 0x8B25, 0xD682, 0x8B27, 0xD683, 0x8B28, 0xD684, 0x8B29, 0xD685, 0x8B2A, 0xD686, 0x8B2B, 0xD687, 0x8B2C, 0xD688, 0x8B2D, 0xD689, 0x8B2E, 0xD68A, 0x8B2F, 0xD68B, 0x8B30, 0xD68C, 0x8B31, 0xD68D, 0x8B32, 0xD68E, 0x8B33, 0xD68F, 0x8B34, 0xD690, 0x8B35, 0xD691, 0x8B36, 0xD692, 0x8B37, 0xD693, 0x8B38, 0xD694, 0x8B39, 0xD695, 0x8B3A, 0xD696, 0x8B3B, 0xD697, 0x8B3C, 0xD698, 0x8B3D, 0xD699, 0x8B3E, 0xD69A, 0x8B3F, 0xD69B, 0x8B40, 0xD69C, 0x8B41, 0xD69D, 0x8B42, 0xD69E, 0x8B43, 0xD69F, 0x8B44, 0xD6A0, 0x8B45, 0xD6A1, 0x5E27, 0xD6A2, 0x75C7, 0xD6A3, 0x90D1, 0xD6A4, 0x8BC1, 0xD6A5, 0x829D, 0xD6A6, 0x679D, 0xD6A7, 0x652F, 0xD6A8, 0x5431, 0xD6A9, 0x8718, 0xD6AA, 0x77E5, 0xD6AB, 0x80A2, 0xD6AC, 0x8102, 0xD6AD, 0x6C41, 0xD6AE, 0x4E4B, 0xD6AF, 0x7EC7, 0xD6B0, 0x804C, 0xD6B1, 0x76F4, 0xD6B2, 0x690D, 0xD6B3, 0x6B96, 0xD6B4, 0x6267, 0xD6B5, 0x503C, 0xD6B6, 0x4F84, 0xD6B7, 0x5740, 0xD6B8, 0x6307, 0xD6B9, 0x6B62, 0xD6BA, 0x8DBE, 0xD6BB, 0x53EA, 0xD6BC, 0x65E8, 0xD6BD, 0x7EB8, 0xD6BE, 0x5FD7, 0xD6BF, 0x631A, 0xD6C0, 0x63B7, 0xD6C1, 0x81F3, 0xD6C2, 0x81F4, 0xD6C3, 0x7F6E, 0xD6C4, 0x5E1C, 0xD6C5, 0x5CD9, 0xD6C6, 0x5236, 0xD6C7, 0x667A, 0xD6C8, 0x79E9, 0xD6C9, 0x7A1A, 0xD6CA, 0x8D28, 0xD6CB, 0x7099, 0xD6CC, 0x75D4, 0xD6CD, 0x6EDE, 0xD6CE, 0x6CBB, 0xD6CF, 0x7A92, 0xD6D0, 0x4E2D, 0xD6D1, 0x76C5, 0xD6D2, 0x5FE0, 0xD6D3, 0x949F, 0xD6D4, 0x8877, 0xD6D5, 0x7EC8, 0xD6D6, 0x79CD, 0xD6D7, 0x80BF, 0xD6D8, 0x91CD, 0xD6D9, 0x4EF2, 0xD6DA, 0x4F17, 0xD6DB, 0x821F, 0xD6DC, 0x5468, 0xD6DD, 0x5DDE, 0xD6DE, 0x6D32, 0xD6DF, 0x8BCC, 0xD6E0, 0x7CA5, 0xD6E1, 0x8F74, 0xD6E2, 0x8098, 0xD6E3, 0x5E1A, 0xD6E4, 0x5492, 0xD6E5, 0x76B1, 0xD6E6, 0x5B99, 0xD6E7, 0x663C, 0xD6E8, 0x9AA4, 0xD6E9, 0x73E0, 0xD6EA, 0x682A, 0xD6EB, 0x86DB, 0xD6EC, 0x6731, 0xD6ED, 0x732A, 0xD6EE, 0x8BF8, 0xD6EF, 0x8BDB, 0xD6F0, 0x9010, 0xD6F1, 0x7AF9, 0xD6F2, 0x70DB, 0xD6F3, 0x716E, 0xD6F4, 0x62C4, 0xD6F5, 0x77A9, 0xD6F6, 0x5631, 0xD6F7, 0x4E3B, 0xD6F8, 0x8457, 0xD6F9, 0x67F1, 0xD6FA, 0x52A9, 0xD6FB, 0x86C0, 0xD6FC, 0x8D2E, 0xD6FD, 0x94F8, 0xD6FE, 0x7B51, 0xD740, 0x8B46, 0xD741, 0x8B47, 0xD742, 0x8B48, 0xD743, 0x8B49, 0xD744, 0x8B4A, 0xD745, 0x8B4B, 0xD746, 0x8B4C, 0xD747, 0x8B4D, 0xD748, 0x8B4E, 0xD749, 0x8B4F, 0xD74A, 0x8B50, 0xD74B, 0x8B51, 0xD74C, 0x8B52, 0xD74D, 0x8B53, 0xD74E, 0x8B54, 0xD74F, 0x8B55, 0xD750, 0x8B56, 0xD751, 0x8B57, 0xD752, 0x8B58, 0xD753, 0x8B59, 0xD754, 0x8B5A, 0xD755, 0x8B5B, 0xD756, 0x8B5C, 0xD757, 0x8B5D, 0xD758, 0x8B5E, 0xD759, 0x8B5F, 0xD75A, 0x8B60, 0xD75B, 0x8B61, 0xD75C, 0x8B62, 0xD75D, 0x8B63, 0xD75E, 0x8B64, 0xD75F, 0x8B65, 0xD760, 0x8B67, 0xD761, 0x8B68, 0xD762, 0x8B69, 0xD763, 0x8B6A, 0xD764, 0x8B6B, 0xD765, 0x8B6D, 0xD766, 0x8B6E, 0xD767, 0x8B6F, 0xD768, 0x8B70, 0xD769, 0x8B71, 0xD76A, 0x8B72, 0xD76B, 0x8B73, 0xD76C, 0x8B74, 0xD76D, 0x8B75, 0xD76E, 0x8B76, 0xD76F, 0x8B77, 0xD770, 0x8B78, 0xD771, 0x8B79, 0xD772, 0x8B7A, 0xD773, 0x8B7B, 0xD774, 0x8B7C, 0xD775, 0x8B7D, 0xD776, 0x8B7E, 0xD777, 0x8B7F, 0xD778, 0x8B80, 0xD779, 0x8B81, 0xD77A, 0x8B82, 0xD77B, 0x8B83, 0xD77C, 0x8B84, 0xD77D, 0x8B85, 0xD77E, 0x8B86, 0xD780, 0x8B87, 0xD781, 0x8B88, 0xD782, 0x8B89, 0xD783, 0x8B8A, 0xD784, 0x8B8B, 0xD785, 0x8B8C, 0xD786, 0x8B8D, 0xD787, 0x8B8E, 0xD788, 0x8B8F, 0xD789, 0x8B90, 0xD78A, 0x8B91, 0xD78B, 0x8B92, 0xD78C, 0x8B93, 0xD78D, 0x8B94, 0xD78E, 0x8B95, 0xD78F, 0x8B96, 0xD790, 0x8B97, 0xD791, 0x8B98, 0xD792, 0x8B99, 0xD793, 0x8B9A, 0xD794, 0x8B9B, 0xD795, 0x8B9C, 0xD796, 0x8B9D, 0xD797, 0x8B9E, 0xD798, 0x8B9F, 0xD799, 0x8BAC, 0xD79A, 0x8BB1, 0xD79B, 0x8BBB, 0xD79C, 0x8BC7, 0xD79D, 0x8BD0, 0xD79E, 0x8BEA, 0xD79F, 0x8C09, 0xD7A0, 0x8C1E, 0xD7A1, 0x4F4F, 0xD7A2, 0x6CE8, 0xD7A3, 0x795D, 0xD7A4, 0x9A7B, 0xD7A5, 0x6293, 0xD7A6, 0x722A, 0xD7A7, 0x62FD, 0xD7A8, 0x4E13, 0xD7A9, 0x7816, 0xD7AA, 0x8F6C, 0xD7AB, 0x64B0, 0xD7AC, 0x8D5A, 0xD7AD, 0x7BC6, 0xD7AE, 0x6869, 0xD7AF, 0x5E84, 0xD7B0, 0x88C5, 0xD7B1, 0x5986, 0xD7B2, 0x649E, 0xD7B3, 0x58EE, 0xD7B4, 0x72B6, 0xD7B5, 0x690E, 0xD7B6, 0x9525, 0xD7B7, 0x8FFD, 0xD7B8, 0x8D58, 0xD7B9, 0x5760, 0xD7BA, 0x7F00, 0xD7BB, 0x8C06, 0xD7BC, 0x51C6, 0xD7BD, 0x6349, 0xD7BE, 0x62D9, 0xD7BF, 0x5353, 0xD7C0, 0x684C, 0xD7C1, 0x7422, 0xD7C2, 0x8301, 0xD7C3, 0x914C, 0xD7C4, 0x5544, 0xD7C5, 0x7740, 0xD7C6, 0x707C, 0xD7C7, 0x6D4A, 0xD7C8, 0x5179, 0xD7C9, 0x54A8, 0xD7CA, 0x8D44, 0xD7CB, 0x59FF, 0xD7CC, 0x6ECB, 0xD7CD, 0x6DC4, 0xD7CE, 0x5B5C, 0xD7CF, 0x7D2B, 0xD7D0, 0x4ED4, 0xD7D1, 0x7C7D, 0xD7D2, 0x6ED3, 0xD7D3, 0x5B50, 0xD7D4, 0x81EA, 0xD7D5, 0x6E0D, 0xD7D6, 0x5B57, 0xD7D7, 0x9B03, 0xD7D8, 0x68D5, 0xD7D9, 0x8E2A, 0xD7DA, 0x5B97, 0xD7DB, 0x7EFC, 0xD7DC, 0x603B, 0xD7DD, 0x7EB5, 0xD7DE, 0x90B9, 0xD7DF, 0x8D70, 0xD7E0, 0x594F, 0xD7E1, 0x63CD, 0xD7E2, 0x79DF, 0xD7E3, 0x8DB3, 0xD7E4, 0x5352, 0xD7E5, 0x65CF, 0xD7E6, 0x7956, 0xD7E7, 0x8BC5, 0xD7E8, 0x963B, 0xD7E9, 0x7EC4, 0xD7EA, 0x94BB, 0xD7EB, 0x7E82, 0xD7EC, 0x5634, 0xD7ED, 0x9189, 0xD7EE, 0x6700, 0xD7EF, 0x7F6A, 0xD7F0, 0x5C0A, 0xD7F1, 0x9075, 0xD7F2, 0x6628, 0xD7F3, 0x5DE6, 0xD7F4, 0x4F50, 0xD7F5, 0x67DE, 0xD7F6, 0x505A, 0xD7F7, 0x4F5C, 0xD7F8, 0x5750, 0xD7F9, 0x5EA7, 0xD840, 0x8C38, 0xD841, 0x8C39, 0xD842, 0x8C3A, 0xD843, 0x8C3B, 0xD844, 0x8C3C, 0xD845, 0x8C3D, 0xD846, 0x8C3E, 0xD847, 0x8C3F, 0xD848, 0x8C40, 0xD849, 0x8C42, 0xD84A, 0x8C43, 0xD84B, 0x8C44, 0xD84C, 0x8C45, 0xD84D, 0x8C48, 0xD84E, 0x8C4A, 0xD84F, 0x8C4B, 0xD850, 0x8C4D, 0xD851, 0x8C4E, 0xD852, 0x8C4F, 0xD853, 0x8C50, 0xD854, 0x8C51, 0xD855, 0x8C52, 0xD856, 0x8C53, 0xD857, 0x8C54, 0xD858, 0x8C56, 0xD859, 0x8C57, 0xD85A, 0x8C58, 0xD85B, 0x8C59, 0xD85C, 0x8C5B, 0xD85D, 0x8C5C, 0xD85E, 0x8C5D, 0xD85F, 0x8C5E, 0xD860, 0x8C5F, 0xD861, 0x8C60, 0xD862, 0x8C63, 0xD863, 0x8C64, 0xD864, 0x8C65, 0xD865, 0x8C66, 0xD866, 0x8C67, 0xD867, 0x8C68, 0xD868, 0x8C69, 0xD869, 0x8C6C, 0xD86A, 0x8C6D, 0xD86B, 0x8C6E, 0xD86C, 0x8C6F, 0xD86D, 0x8C70, 0xD86E, 0x8C71, 0xD86F, 0x8C72, 0xD870, 0x8C74, 0xD871, 0x8C75, 0xD872, 0x8C76, 0xD873, 0x8C77, 0xD874, 0x8C7B, 0xD875, 0x8C7C, 0xD876, 0x8C7D, 0xD877, 0x8C7E, 0xD878, 0x8C7F, 0xD879, 0x8C80, 0xD87A, 0x8C81, 0xD87B, 0x8C83, 0xD87C, 0x8C84, 0xD87D, 0x8C86, 0xD87E, 0x8C87, 0xD880, 0x8C88, 0xD881, 0x8C8B, 0xD882, 0x8C8D, 0xD883, 0x8C8E, 0xD884, 0x8C8F, 0xD885, 0x8C90, 0xD886, 0x8C91, 0xD887, 0x8C92, 0xD888, 0x8C93, 0xD889, 0x8C95, 0xD88A, 0x8C96, 0xD88B, 0x8C97, 0xD88C, 0x8C99, 0xD88D, 0x8C9A, 0xD88E, 0x8C9B, 0xD88F, 0x8C9C, 0xD890, 0x8C9D, 0xD891, 0x8C9E, 0xD892, 0x8C9F, 0xD893, 0x8CA0, 0xD894, 0x8CA1, 0xD895, 0x8CA2, 0xD896, 0x8CA3, 0xD897, 0x8CA4, 0xD898, 0x8CA5, 0xD899, 0x8CA6, 0xD89A, 0x8CA7, 0xD89B, 0x8CA8, 0xD89C, 0x8CA9, 0xD89D, 0x8CAA, 0xD89E, 0x8CAB, 0xD89F, 0x8CAC, 0xD8A0, 0x8CAD, 0xD8A1, 0x4E8D, 0xD8A2, 0x4E0C, 0xD8A3, 0x5140, 0xD8A4, 0x4E10, 0xD8A5, 0x5EFF, 0xD8A6, 0x5345, 0xD8A7, 0x4E15, 0xD8A8, 0x4E98, 0xD8A9, 0x4E1E, 0xD8AA, 0x9B32, 0xD8AB, 0x5B6C, 0xD8AC, 0x5669, 0xD8AD, 0x4E28, 0xD8AE, 0x79BA, 0xD8AF, 0x4E3F, 0xD8B0, 0x5315, 0xD8B1, 0x4E47, 0xD8B2, 0x592D, 0xD8B3, 0x723B, 0xD8B4, 0x536E, 0xD8B5, 0x6C10, 0xD8B6, 0x56DF, 0xD8B7, 0x80E4, 0xD8B8, 0x9997, 0xD8B9, 0x6BD3, 0xD8BA, 0x777E, 0xD8BB, 0x9F17, 0xD8BC, 0x4E36, 0xD8BD, 0x4E9F, 0xD8BE, 0x9F10, 0xD8BF, 0x4E5C, 0xD8C0, 0x4E69, 0xD8C1, 0x4E93, 0xD8C2, 0x8288, 0xD8C3, 0x5B5B, 0xD8C4, 0x556C, 0xD8C5, 0x560F, 0xD8C6, 0x4EC4, 0xD8C7, 0x538D, 0xD8C8, 0x539D, 0xD8C9, 0x53A3, 0xD8CA, 0x53A5, 0xD8CB, 0x53AE, 0xD8CC, 0x9765, 0xD8CD, 0x8D5D, 0xD8CE, 0x531A, 0xD8CF, 0x53F5, 0xD8D0, 0x5326, 0xD8D1, 0x532E, 0xD8D2, 0x533E, 0xD8D3, 0x8D5C, 0xD8D4, 0x5366, 0xD8D5, 0x5363, 0xD8D6, 0x5202, 0xD8D7, 0x5208, 0xD8D8, 0x520E, 0xD8D9, 0x522D, 0xD8DA, 0x5233, 0xD8DB, 0x523F, 0xD8DC, 0x5240, 0xD8DD, 0x524C, 0xD8DE, 0x525E, 0xD8DF, 0x5261, 0xD8E0, 0x525C, 0xD8E1, 0x84AF, 0xD8E2, 0x527D, 0xD8E3, 0x5282, 0xD8E4, 0x5281, 0xD8E5, 0x5290, 0xD8E6, 0x5293, 0xD8E7, 0x5182, 0xD8E8, 0x7F54, 0xD8E9, 0x4EBB, 0xD8EA, 0x4EC3, 0xD8EB, 0x4EC9, 0xD8EC, 0x4EC2, 0xD8ED, 0x4EE8, 0xD8EE, 0x4EE1, 0xD8EF, 0x4EEB, 0xD8F0, 0x4EDE, 0xD8F1, 0x4F1B, 0xD8F2, 0x4EF3, 0xD8F3, 0x4F22, 0xD8F4, 0x4F64, 0xD8F5, 0x4EF5, 0xD8F6, 0x4F25, 0xD8F7, 0x4F27, 0xD8F8, 0x4F09, 0xD8F9, 0x4F2B, 0xD8FA, 0x4F5E, 0xD8FB, 0x4F67, 0xD8FC, 0x6538, 0xD8FD, 0x4F5A, 0xD8FE, 0x4F5D, 0xD940, 0x8CAE, 0xD941, 0x8CAF, 0xD942, 0x8CB0, 0xD943, 0x8CB1, 0xD944, 0x8CB2, 0xD945, 0x8CB3, 0xD946, 0x8CB4, 0xD947, 0x8CB5, 0xD948, 0x8CB6, 0xD949, 0x8CB7, 0xD94A, 0x8CB8, 0xD94B, 0x8CB9, 0xD94C, 0x8CBA, 0xD94D, 0x8CBB, 0xD94E, 0x8CBC, 0xD94F, 0x8CBD, 0xD950, 0x8CBE, 0xD951, 0x8CBF, 0xD952, 0x8CC0, 0xD953, 0x8CC1, 0xD954, 0x8CC2, 0xD955, 0x8CC3, 0xD956, 0x8CC4, 0xD957, 0x8CC5, 0xD958, 0x8CC6, 0xD959, 0x8CC7, 0xD95A, 0x8CC8, 0xD95B, 0x8CC9, 0xD95C, 0x8CCA, 0xD95D, 0x8CCB, 0xD95E, 0x8CCC, 0xD95F, 0x8CCD, 0xD960, 0x8CCE, 0xD961, 0x8CCF, 0xD962, 0x8CD0, 0xD963, 0x8CD1, 0xD964, 0x8CD2, 0xD965, 0x8CD3, 0xD966, 0x8CD4, 0xD967, 0x8CD5, 0xD968, 0x8CD6, 0xD969, 0x8CD7, 0xD96A, 0x8CD8, 0xD96B, 0x8CD9, 0xD96C, 0x8CDA, 0xD96D, 0x8CDB, 0xD96E, 0x8CDC, 0xD96F, 0x8CDD, 0xD970, 0x8CDE, 0xD971, 0x8CDF, 0xD972, 0x8CE0, 0xD973, 0x8CE1, 0xD974, 0x8CE2, 0xD975, 0x8CE3, 0xD976, 0x8CE4, 0xD977, 0x8CE5, 0xD978, 0x8CE6, 0xD979, 0x8CE7, 0xD97A, 0x8CE8, 0xD97B, 0x8CE9, 0xD97C, 0x8CEA, 0xD97D, 0x8CEB, 0xD97E, 0x8CEC, 0xD980, 0x8CED, 0xD981, 0x8CEE, 0xD982, 0x8CEF, 0xD983, 0x8CF0, 0xD984, 0x8CF1, 0xD985, 0x8CF2, 0xD986, 0x8CF3, 0xD987, 0x8CF4, 0xD988, 0x8CF5, 0xD989, 0x8CF6, 0xD98A, 0x8CF7, 0xD98B, 0x8CF8, 0xD98C, 0x8CF9, 0xD98D, 0x8CFA, 0xD98E, 0x8CFB, 0xD98F, 0x8CFC, 0xD990, 0x8CFD, 0xD991, 0x8CFE, 0xD992, 0x8CFF, 0xD993, 0x8D00, 0xD994, 0x8D01, 0xD995, 0x8D02, 0xD996, 0x8D03, 0xD997, 0x8D04, 0xD998, 0x8D05, 0xD999, 0x8D06, 0xD99A, 0x8D07, 0xD99B, 0x8D08, 0xD99C, 0x8D09, 0xD99D, 0x8D0A, 0xD99E, 0x8D0B, 0xD99F, 0x8D0C, 0xD9A0, 0x8D0D, 0xD9A1, 0x4F5F, 0xD9A2, 0x4F57, 0xD9A3, 0x4F32, 0xD9A4, 0x4F3D, 0xD9A5, 0x4F76, 0xD9A6, 0x4F74, 0xD9A7, 0x4F91, 0xD9A8, 0x4F89, 0xD9A9, 0x4F83, 0xD9AA, 0x4F8F, 0xD9AB, 0x4F7E, 0xD9AC, 0x4F7B, 0xD9AD, 0x4FAA, 0xD9AE, 0x4F7C, 0xD9AF, 0x4FAC, 0xD9B0, 0x4F94, 0xD9B1, 0x4FE6, 0xD9B2, 0x4FE8, 0xD9B3, 0x4FEA, 0xD9B4, 0x4FC5, 0xD9B5, 0x4FDA, 0xD9B6, 0x4FE3, 0xD9B7, 0x4FDC, 0xD9B8, 0x4FD1, 0xD9B9, 0x4FDF, 0xD9BA, 0x4FF8, 0xD9BB, 0x5029, 0xD9BC, 0x504C, 0xD9BD, 0x4FF3, 0xD9BE, 0x502C, 0xD9BF, 0x500F, 0xD9C0, 0x502E, 0xD9C1, 0x502D, 0xD9C2, 0x4FFE, 0xD9C3, 0x501C, 0xD9C4, 0x500C, 0xD9C5, 0x5025, 0xD9C6, 0x5028, 0xD9C7, 0x507E, 0xD9C8, 0x5043, 0xD9C9, 0x5055, 0xD9CA, 0x5048, 0xD9CB, 0x504E, 0xD9CC, 0x506C, 0xD9CD, 0x507B, 0xD9CE, 0x50A5, 0xD9CF, 0x50A7, 0xD9D0, 0x50A9, 0xD9D1, 0x50BA, 0xD9D2, 0x50D6, 0xD9D3, 0x5106, 0xD9D4, 0x50ED, 0xD9D5, 0x50EC, 0xD9D6, 0x50E6, 0xD9D7, 0x50EE, 0xD9D8, 0x5107, 0xD9D9, 0x510B, 0xD9DA, 0x4EDD, 0xD9DB, 0x6C3D, 0xD9DC, 0x4F58, 0xD9DD, 0x4F65, 0xD9DE, 0x4FCE, 0xD9DF, 0x9FA0, 0xD9E0, 0x6C46, 0xD9E1, 0x7C74, 0xD9E2, 0x516E, 0xD9E3, 0x5DFD, 0xD9E4, 0x9EC9, 0xD9E5, 0x9998, 0xD9E6, 0x5181, 0xD9E7, 0x5914, 0xD9E8, 0x52F9, 0xD9E9, 0x530D, 0xD9EA, 0x8A07, 0xD9EB, 0x5310, 0xD9EC, 0x51EB, 0xD9ED, 0x5919, 0xD9EE, 0x5155, 0xD9EF, 0x4EA0, 0xD9F0, 0x5156, 0xD9F1, 0x4EB3, 0xD9F2, 0x886E, 0xD9F3, 0x88A4, 0xD9F4, 0x4EB5, 0xD9F5, 0x8114, 0xD9F6, 0x88D2, 0xD9F7, 0x7980, 0xD9F8, 0x5B34, 0xD9F9, 0x8803, 0xD9FA, 0x7FB8, 0xD9FB, 0x51AB, 0xD9FC, 0x51B1, 0xD9FD, 0x51BD, 0xD9FE, 0x51BC, 0xDA40, 0x8D0E, 0xDA41, 0x8D0F, 0xDA42, 0x8D10, 0xDA43, 0x8D11, 0xDA44, 0x8D12, 0xDA45, 0x8D13, 0xDA46, 0x8D14, 0xDA47, 0x8D15, 0xDA48, 0x8D16, 0xDA49, 0x8D17, 0xDA4A, 0x8D18, 0xDA4B, 0x8D19, 0xDA4C, 0x8D1A, 0xDA4D, 0x8D1B, 0xDA4E, 0x8D1C, 0xDA4F, 0x8D20, 0xDA50, 0x8D51, 0xDA51, 0x8D52, 0xDA52, 0x8D57, 0xDA53, 0x8D5F, 0xDA54, 0x8D65, 0xDA55, 0x8D68, 0xDA56, 0x8D69, 0xDA57, 0x8D6A, 0xDA58, 0x8D6C, 0xDA59, 0x8D6E, 0xDA5A, 0x8D6F, 0xDA5B, 0x8D71, 0xDA5C, 0x8D72, 0xDA5D, 0x8D78, 0xDA5E, 0x8D79, 0xDA5F, 0x8D7A, 0xDA60, 0x8D7B, 0xDA61, 0x8D7C, 0xDA62, 0x8D7D, 0xDA63, 0x8D7E, 0xDA64, 0x8D7F, 0xDA65, 0x8D80, 0xDA66, 0x8D82, 0xDA67, 0x8D83, 0xDA68, 0x8D86, 0xDA69, 0x8D87, 0xDA6A, 0x8D88, 0xDA6B, 0x8D89, 0xDA6C, 0x8D8C, 0xDA6D, 0x8D8D, 0xDA6E, 0x8D8E, 0xDA6F, 0x8D8F, 0xDA70, 0x8D90, 0xDA71, 0x8D92, 0xDA72, 0x8D93, 0xDA73, 0x8D95, 0xDA74, 0x8D96, 0xDA75, 0x8D97, 0xDA76, 0x8D98, 0xDA77, 0x8D99, 0xDA78, 0x8D9A, 0xDA79, 0x8D9B, 0xDA7A, 0x8D9C, 0xDA7B, 0x8D9D, 0xDA7C, 0x8D9E, 0xDA7D, 0x8DA0, 0xDA7E, 0x8DA1, 0xDA80, 0x8DA2, 0xDA81, 0x8DA4, 0xDA82, 0x8DA5, 0xDA83, 0x8DA6, 0xDA84, 0x8DA7, 0xDA85, 0x8DA8, 0xDA86, 0x8DA9, 0xDA87, 0x8DAA, 0xDA88, 0x8DAB, 0xDA89, 0x8DAC, 0xDA8A, 0x8DAD, 0xDA8B, 0x8DAE, 0xDA8C, 0x8DAF, 0xDA8D, 0x8DB0, 0xDA8E, 0x8DB2, 0xDA8F, 0x8DB6, 0xDA90, 0x8DB7, 0xDA91, 0x8DB9, 0xDA92, 0x8DBB, 0xDA93, 0x8DBD, 0xDA94, 0x8DC0, 0xDA95, 0x8DC1, 0xDA96, 0x8DC2, 0xDA97, 0x8DC5, 0xDA98, 0x8DC7, 0xDA99, 0x8DC8, 0xDA9A, 0x8DC9, 0xDA9B, 0x8DCA, 0xDA9C, 0x8DCD, 0xDA9D, 0x8DD0, 0xDA9E, 0x8DD2, 0xDA9F, 0x8DD3, 0xDAA0, 0x8DD4, 0xDAA1, 0x51C7, 0xDAA2, 0x5196, 0xDAA3, 0x51A2, 0xDAA4, 0x51A5, 0xDAA5, 0x8BA0, 0xDAA6, 0x8BA6, 0xDAA7, 0x8BA7, 0xDAA8, 0x8BAA, 0xDAA9, 0x8BB4, 0xDAAA, 0x8BB5, 0xDAAB, 0x8BB7, 0xDAAC, 0x8BC2, 0xDAAD, 0x8BC3, 0xDAAE, 0x8BCB, 0xDAAF, 0x8BCF, 0xDAB0, 0x8BCE, 0xDAB1, 0x8BD2, 0xDAB2, 0x8BD3, 0xDAB3, 0x8BD4, 0xDAB4, 0x8BD6, 0xDAB5, 0x8BD8, 0xDAB6, 0x8BD9, 0xDAB7, 0x8BDC, 0xDAB8, 0x8BDF, 0xDAB9, 0x8BE0, 0xDABA, 0x8BE4, 0xDABB, 0x8BE8, 0xDABC, 0x8BE9, 0xDABD, 0x8BEE, 0xDABE, 0x8BF0, 0xDABF, 0x8BF3, 0xDAC0, 0x8BF6, 0xDAC1, 0x8BF9, 0xDAC2, 0x8BFC, 0xDAC3, 0x8BFF, 0xDAC4, 0x8C00, 0xDAC5, 0x8C02, 0xDAC6, 0x8C04, 0xDAC7, 0x8C07, 0xDAC8, 0x8C0C, 0xDAC9, 0x8C0F, 0xDACA, 0x8C11, 0xDACB, 0x8C12, 0xDACC, 0x8C14, 0xDACD, 0x8C15, 0xDACE, 0x8C16, 0xDACF, 0x8C19, 0xDAD0, 0x8C1B, 0xDAD1, 0x8C18, 0xDAD2, 0x8C1D, 0xDAD3, 0x8C1F, 0xDAD4, 0x8C20, 0xDAD5, 0x8C21, 0xDAD6, 0x8C25, 0xDAD7, 0x8C27, 0xDAD8, 0x8C2A, 0xDAD9, 0x8C2B, 0xDADA, 0x8C2E, 0xDADB, 0x8C2F, 0xDADC, 0x8C32, 0xDADD, 0x8C33, 0xDADE, 0x8C35, 0xDADF, 0x8C36, 0xDAE0, 0x5369, 0xDAE1, 0x537A, 0xDAE2, 0x961D, 0xDAE3, 0x9622, 0xDAE4, 0x9621, 0xDAE5, 0x9631, 0xDAE6, 0x962A, 0xDAE7, 0x963D, 0xDAE8, 0x963C, 0xDAE9, 0x9642, 0xDAEA, 0x9649, 0xDAEB, 0x9654, 0xDAEC, 0x965F, 0xDAED, 0x9667, 0xDAEE, 0x966C, 0xDAEF, 0x9672, 0xDAF0, 0x9674, 0xDAF1, 0x9688, 0xDAF2, 0x968D, 0xDAF3, 0x9697, 0xDAF4, 0x96B0, 0xDAF5, 0x9097, 0xDAF6, 0x909B, 0xDAF7, 0x909D, 0xDAF8, 0x9099, 0xDAF9, 0x90AC, 0xDAFA, 0x90A1, 0xDAFB, 0x90B4, 0xDAFC, 0x90B3, 0xDAFD, 0x90B6, 0xDAFE, 0x90BA, 0xDB40, 0x8DD5, 0xDB41, 0x8DD8, 0xDB42, 0x8DD9, 0xDB43, 0x8DDC, 0xDB44, 0x8DE0, 0xDB45, 0x8DE1, 0xDB46, 0x8DE2, 0xDB47, 0x8DE5, 0xDB48, 0x8DE6, 0xDB49, 0x8DE7, 0xDB4A, 0x8DE9, 0xDB4B, 0x8DED, 0xDB4C, 0x8DEE, 0xDB4D, 0x8DF0, 0xDB4E, 0x8DF1, 0xDB4F, 0x8DF2, 0xDB50, 0x8DF4, 0xDB51, 0x8DF6, 0xDB52, 0x8DFC, 0xDB53, 0x8DFE, 0xDB54, 0x8DFF, 0xDB55, 0x8E00, 0xDB56, 0x8E01, 0xDB57, 0x8E02, 0xDB58, 0x8E03, 0xDB59, 0x8E04, 0xDB5A, 0x8E06, 0xDB5B, 0x8E07, 0xDB5C, 0x8E08, 0xDB5D, 0x8E0B, 0xDB5E, 0x8E0D, 0xDB5F, 0x8E0E, 0xDB60, 0x8E10, 0xDB61, 0x8E11, 0xDB62, 0x8E12, 0xDB63, 0x8E13, 0xDB64, 0x8E15, 0xDB65, 0x8E16, 0xDB66, 0x8E17, 0xDB67, 0x8E18, 0xDB68, 0x8E19, 0xDB69, 0x8E1A, 0xDB6A, 0x8E1B, 0xDB6B, 0x8E1C, 0xDB6C, 0x8E20, 0xDB6D, 0x8E21, 0xDB6E, 0x8E24, 0xDB6F, 0x8E25, 0xDB70, 0x8E26, 0xDB71, 0x8E27, 0xDB72, 0x8E28, 0xDB73, 0x8E2B, 0xDB74, 0x8E2D, 0xDB75, 0x8E30, 0xDB76, 0x8E32, 0xDB77, 0x8E33, 0xDB78, 0x8E34, 0xDB79, 0x8E36, 0xDB7A, 0x8E37, 0xDB7B, 0x8E38, 0xDB7C, 0x8E3B, 0xDB7D, 0x8E3C, 0xDB7E, 0x8E3E, 0xDB80, 0x8E3F, 0xDB81, 0x8E43, 0xDB82, 0x8E45, 0xDB83, 0x8E46, 0xDB84, 0x8E4C, 0xDB85, 0x8E4D, 0xDB86, 0x8E4E, 0xDB87, 0x8E4F, 0xDB88, 0x8E50, 0xDB89, 0x8E53, 0xDB8A, 0x8E54, 0xDB8B, 0x8E55, 0xDB8C, 0x8E56, 0xDB8D, 0x8E57, 0xDB8E, 0x8E58, 0xDB8F, 0x8E5A, 0xDB90, 0x8E5B, 0xDB91, 0x8E5C, 0xDB92, 0x8E5D, 0xDB93, 0x8E5E, 0xDB94, 0x8E5F, 0xDB95, 0x8E60, 0xDB96, 0x8E61, 0xDB97, 0x8E62, 0xDB98, 0x8E63, 0xDB99, 0x8E64, 0xDB9A, 0x8E65, 0xDB9B, 0x8E67, 0xDB9C, 0x8E68, 0xDB9D, 0x8E6A, 0xDB9E, 0x8E6B, 0xDB9F, 0x8E6E, 0xDBA0, 0x8E71, 0xDBA1, 0x90B8, 0xDBA2, 0x90B0, 0xDBA3, 0x90CF, 0xDBA4, 0x90C5, 0xDBA5, 0x90BE, 0xDBA6, 0x90D0, 0xDBA7, 0x90C4, 0xDBA8, 0x90C7, 0xDBA9, 0x90D3, 0xDBAA, 0x90E6, 0xDBAB, 0x90E2, 0xDBAC, 0x90DC, 0xDBAD, 0x90D7, 0xDBAE, 0x90DB, 0xDBAF, 0x90EB, 0xDBB0, 0x90EF, 0xDBB1, 0x90FE, 0xDBB2, 0x9104, 0xDBB3, 0x9122, 0xDBB4, 0x911E, 0xDBB5, 0x9123, 0xDBB6, 0x9131, 0xDBB7, 0x912F, 0xDBB8, 0x9139, 0xDBB9, 0x9143, 0xDBBA, 0x9146, 0xDBBB, 0x520D, 0xDBBC, 0x5942, 0xDBBD, 0x52A2, 0xDBBE, 0x52AC, 0xDBBF, 0x52AD, 0xDBC0, 0x52BE, 0xDBC1, 0x54FF, 0xDBC2, 0x52D0, 0xDBC3, 0x52D6, 0xDBC4, 0x52F0, 0xDBC5, 0x53DF, 0xDBC6, 0x71EE, 0xDBC7, 0x77CD, 0xDBC8, 0x5EF4, 0xDBC9, 0x51F5, 0xDBCA, 0x51FC, 0xDBCB, 0x9B2F, 0xDBCC, 0x53B6, 0xDBCD, 0x5F01, 0xDBCE, 0x755A, 0xDBCF, 0x5DEF, 0xDBD0, 0x574C, 0xDBD1, 0x57A9, 0xDBD2, 0x57A1, 0xDBD3, 0x587E, 0xDBD4, 0x58BC, 0xDBD5, 0x58C5, 0xDBD6, 0x58D1, 0xDBD7, 0x5729, 0xDBD8, 0x572C, 0xDBD9, 0x572A, 0xDBDA, 0x5733, 0xDBDB, 0x5739, 0xDBDC, 0x572E, 0xDBDD, 0x572F, 0xDBDE, 0x575C, 0xDBDF, 0x573B, 0xDBE0, 0x5742, 0xDBE1, 0x5769, 0xDBE2, 0x5785, 0xDBE3, 0x576B, 0xDBE4, 0x5786, 0xDBE5, 0x577C, 0xDBE6, 0x577B, 0xDBE7, 0x5768, 0xDBE8, 0x576D, 0xDBE9, 0x5776, 0xDBEA, 0x5773, 0xDBEB, 0x57AD, 0xDBEC, 0x57A4, 0xDBED, 0x578C, 0xDBEE, 0x57B2, 0xDBEF, 0x57CF, 0xDBF0, 0x57A7, 0xDBF1, 0x57B4, 0xDBF2, 0x5793, 0xDBF3, 0x57A0, 0xDBF4, 0x57D5, 0xDBF5, 0x57D8, 0xDBF6, 0x57DA, 0xDBF7, 0x57D9, 0xDBF8, 0x57D2, 0xDBF9, 0x57B8, 0xDBFA, 0x57F4, 0xDBFB, 0x57EF, 0xDBFC, 0x57F8, 0xDBFD, 0x57E4, 0xDBFE, 0x57DD, 0xDC40, 0x8E73, 0xDC41, 0x8E75, 0xDC42, 0x8E77, 0xDC43, 0x8E78, 0xDC44, 0x8E79, 0xDC45, 0x8E7A, 0xDC46, 0x8E7B, 0xDC47, 0x8E7D, 0xDC48, 0x8E7E, 0xDC49, 0x8E80, 0xDC4A, 0x8E82, 0xDC4B, 0x8E83, 0xDC4C, 0x8E84, 0xDC4D, 0x8E86, 0xDC4E, 0x8E88, 0xDC4F, 0x8E89, 0xDC50, 0x8E8A, 0xDC51, 0x8E8B, 0xDC52, 0x8E8C, 0xDC53, 0x8E8D, 0xDC54, 0x8E8E, 0xDC55, 0x8E91, 0xDC56, 0x8E92, 0xDC57, 0x8E93, 0xDC58, 0x8E95, 0xDC59, 0x8E96, 0xDC5A, 0x8E97, 0xDC5B, 0x8E98, 0xDC5C, 0x8E99, 0xDC5D, 0x8E9A, 0xDC5E, 0x8E9B, 0xDC5F, 0x8E9D, 0xDC60, 0x8E9F, 0xDC61, 0x8EA0, 0xDC62, 0x8EA1, 0xDC63, 0x8EA2, 0xDC64, 0x8EA3, 0xDC65, 0x8EA4, 0xDC66, 0x8EA5, 0xDC67, 0x8EA6, 0xDC68, 0x8EA7, 0xDC69, 0x8EA8, 0xDC6A, 0x8EA9, 0xDC6B, 0x8EAA, 0xDC6C, 0x8EAD, 0xDC6D, 0x8EAE, 0xDC6E, 0x8EB0, 0xDC6F, 0x8EB1, 0xDC70, 0x8EB3, 0xDC71, 0x8EB4, 0xDC72, 0x8EB5, 0xDC73, 0x8EB6, 0xDC74, 0x8EB7, 0xDC75, 0x8EB8, 0xDC76, 0x8EB9, 0xDC77, 0x8EBB, 0xDC78, 0x8EBC, 0xDC79, 0x8EBD, 0xDC7A, 0x8EBE, 0xDC7B, 0x8EBF, 0xDC7C, 0x8EC0, 0xDC7D, 0x8EC1, 0xDC7E, 0x8EC2, 0xDC80, 0x8EC3, 0xDC81, 0x8EC4, 0xDC82, 0x8EC5, 0xDC83, 0x8EC6, 0xDC84, 0x8EC7, 0xDC85, 0x8EC8, 0xDC86, 0x8EC9, 0xDC87, 0x8ECA, 0xDC88, 0x8ECB, 0xDC89, 0x8ECC, 0xDC8A, 0x8ECD, 0xDC8B, 0x8ECF, 0xDC8C, 0x8ED0, 0xDC8D, 0x8ED1, 0xDC8E, 0x8ED2, 0xDC8F, 0x8ED3, 0xDC90, 0x8ED4, 0xDC91, 0x8ED5, 0xDC92, 0x8ED6, 0xDC93, 0x8ED7, 0xDC94, 0x8ED8, 0xDC95, 0x8ED9, 0xDC96, 0x8EDA, 0xDC97, 0x8EDB, 0xDC98, 0x8EDC, 0xDC99, 0x8EDD, 0xDC9A, 0x8EDE, 0xDC9B, 0x8EDF, 0xDC9C, 0x8EE0, 0xDC9D, 0x8EE1, 0xDC9E, 0x8EE2, 0xDC9F, 0x8EE3, 0xDCA0, 0x8EE4, 0xDCA1, 0x580B, 0xDCA2, 0x580D, 0xDCA3, 0x57FD, 0xDCA4, 0x57ED, 0xDCA5, 0x5800, 0xDCA6, 0x581E, 0xDCA7, 0x5819, 0xDCA8, 0x5844, 0xDCA9, 0x5820, 0xDCAA, 0x5865, 0xDCAB, 0x586C, 0xDCAC, 0x5881, 0xDCAD, 0x5889, 0xDCAE, 0x589A, 0xDCAF, 0x5880, 0xDCB0, 0x99A8, 0xDCB1, 0x9F19, 0xDCB2, 0x61FF, 0xDCB3, 0x8279, 0xDCB4, 0x827D, 0xDCB5, 0x827F, 0xDCB6, 0x828F, 0xDCB7, 0x828A, 0xDCB8, 0x82A8, 0xDCB9, 0x8284, 0xDCBA, 0x828E, 0xDCBB, 0x8291, 0xDCBC, 0x8297, 0xDCBD, 0x8299, 0xDCBE, 0x82AB, 0xDCBF, 0x82B8, 0xDCC0, 0x82BE, 0xDCC1, 0x82B0, 0xDCC2, 0x82C8, 0xDCC3, 0x82CA, 0xDCC4, 0x82E3, 0xDCC5, 0x8298, 0xDCC6, 0x82B7, 0xDCC7, 0x82AE, 0xDCC8, 0x82CB, 0xDCC9, 0x82CC, 0xDCCA, 0x82C1, 0xDCCB, 0x82A9, 0xDCCC, 0x82B4, 0xDCCD, 0x82A1, 0xDCCE, 0x82AA, 0xDCCF, 0x829F, 0xDCD0, 0x82C4, 0xDCD1, 0x82CE, 0xDCD2, 0x82A4, 0xDCD3, 0x82E1, 0xDCD4, 0x8309, 0xDCD5, 0x82F7, 0xDCD6, 0x82E4, 0xDCD7, 0x830F, 0xDCD8, 0x8307, 0xDCD9, 0x82DC, 0xDCDA, 0x82F4, 0xDCDB, 0x82D2, 0xDCDC, 0x82D8, 0xDCDD, 0x830C, 0xDCDE, 0x82FB, 0xDCDF, 0x82D3, 0xDCE0, 0x8311, 0xDCE1, 0x831A, 0xDCE2, 0x8306, 0xDCE3, 0x8314, 0xDCE4, 0x8315, 0xDCE5, 0x82E0, 0xDCE6, 0x82D5, 0xDCE7, 0x831C, 0xDCE8, 0x8351, 0xDCE9, 0x835B, 0xDCEA, 0x835C, 0xDCEB, 0x8308, 0xDCEC, 0x8392, 0xDCED, 0x833C, 0xDCEE, 0x8334, 0xDCEF, 0x8331, 0xDCF0, 0x839B, 0xDCF1, 0x835E, 0xDCF2, 0x832F, 0xDCF3, 0x834F, 0xDCF4, 0x8347, 0xDCF5, 0x8343, 0xDCF6, 0x835F, 0xDCF7, 0x8340, 0xDCF8, 0x8317, 0xDCF9, 0x8360, 0xDCFA, 0x832D, 0xDCFB, 0x833A, 0xDCFC, 0x8333, 0xDCFD, 0x8366, 0xDCFE, 0x8365, 0xDD40, 0x8EE5, 0xDD41, 0x8EE6, 0xDD42, 0x8EE7, 0xDD43, 0x8EE8, 0xDD44, 0x8EE9, 0xDD45, 0x8EEA, 0xDD46, 0x8EEB, 0xDD47, 0x8EEC, 0xDD48, 0x8EED, 0xDD49, 0x8EEE, 0xDD4A, 0x8EEF, 0xDD4B, 0x8EF0, 0xDD4C, 0x8EF1, 0xDD4D, 0x8EF2, 0xDD4E, 0x8EF3, 0xDD4F, 0x8EF4, 0xDD50, 0x8EF5, 0xDD51, 0x8EF6, 0xDD52, 0x8EF7, 0xDD53, 0x8EF8, 0xDD54, 0x8EF9, 0xDD55, 0x8EFA, 0xDD56, 0x8EFB, 0xDD57, 0x8EFC, 0xDD58, 0x8EFD, 0xDD59, 0x8EFE, 0xDD5A, 0x8EFF, 0xDD5B, 0x8F00, 0xDD5C, 0x8F01, 0xDD5D, 0x8F02, 0xDD5E, 0x8F03, 0xDD5F, 0x8F04, 0xDD60, 0x8F05, 0xDD61, 0x8F06, 0xDD62, 0x8F07, 0xDD63, 0x8F08, 0xDD64, 0x8F09, 0xDD65, 0x8F0A, 0xDD66, 0x8F0B, 0xDD67, 0x8F0C, 0xDD68, 0x8F0D, 0xDD69, 0x8F0E, 0xDD6A, 0x8F0F, 0xDD6B, 0x8F10, 0xDD6C, 0x8F11, 0xDD6D, 0x8F12, 0xDD6E, 0x8F13, 0xDD6F, 0x8F14, 0xDD70, 0x8F15, 0xDD71, 0x8F16, 0xDD72, 0x8F17, 0xDD73, 0x8F18, 0xDD74, 0x8F19, 0xDD75, 0x8F1A, 0xDD76, 0x8F1B, 0xDD77, 0x8F1C, 0xDD78, 0x8F1D, 0xDD79, 0x8F1E, 0xDD7A, 0x8F1F, 0xDD7B, 0x8F20, 0xDD7C, 0x8F21, 0xDD7D, 0x8F22, 0xDD7E, 0x8F23, 0xDD80, 0x8F24, 0xDD81, 0x8F25, 0xDD82, 0x8F26, 0xDD83, 0x8F27, 0xDD84, 0x8F28, 0xDD85, 0x8F29, 0xDD86, 0x8F2A, 0xDD87, 0x8F2B, 0xDD88, 0x8F2C, 0xDD89, 0x8F2D, 0xDD8A, 0x8F2E, 0xDD8B, 0x8F2F, 0xDD8C, 0x8F30, 0xDD8D, 0x8F31, 0xDD8E, 0x8F32, 0xDD8F, 0x8F33, 0xDD90, 0x8F34, 0xDD91, 0x8F35, 0xDD92, 0x8F36, 0xDD93, 0x8F37, 0xDD94, 0x8F38, 0xDD95, 0x8F39, 0xDD96, 0x8F3A, 0xDD97, 0x8F3B, 0xDD98, 0x8F3C, 0xDD99, 0x8F3D, 0xDD9A, 0x8F3E, 0xDD9B, 0x8F3F, 0xDD9C, 0x8F40, 0xDD9D, 0x8F41, 0xDD9E, 0x8F42, 0xDD9F, 0x8F43, 0xDDA0, 0x8F44, 0xDDA1, 0x8368, 0xDDA2, 0x831B, 0xDDA3, 0x8369, 0xDDA4, 0x836C, 0xDDA5, 0x836A, 0xDDA6, 0x836D, 0xDDA7, 0x836E, 0xDDA8, 0x83B0, 0xDDA9, 0x8378, 0xDDAA, 0x83B3, 0xDDAB, 0x83B4, 0xDDAC, 0x83A0, 0xDDAD, 0x83AA, 0xDDAE, 0x8393, 0xDDAF, 0x839C, 0xDDB0, 0x8385, 0xDDB1, 0x837C, 0xDDB2, 0x83B6, 0xDDB3, 0x83A9, 0xDDB4, 0x837D, 0xDDB5, 0x83B8, 0xDDB6, 0x837B, 0xDDB7, 0x8398, 0xDDB8, 0x839E, 0xDDB9, 0x83A8, 0xDDBA, 0x83BA, 0xDDBB, 0x83BC, 0xDDBC, 0x83C1, 0xDDBD, 0x8401, 0xDDBE, 0x83E5, 0xDDBF, 0x83D8, 0xDDC0, 0x5807, 0xDDC1, 0x8418, 0xDDC2, 0x840B, 0xDDC3, 0x83DD, 0xDDC4, 0x83FD, 0xDDC5, 0x83D6, 0xDDC6, 0x841C, 0xDDC7, 0x8438, 0xDDC8, 0x8411, 0xDDC9, 0x8406, 0xDDCA, 0x83D4, 0xDDCB, 0x83DF, 0xDDCC, 0x840F, 0xDDCD, 0x8403, 0xDDCE, 0x83F8, 0xDDCF, 0x83F9, 0xDDD0, 0x83EA, 0xDDD1, 0x83C5, 0xDDD2, 0x83C0, 0xDDD3, 0x8426, 0xDDD4, 0x83F0, 0xDDD5, 0x83E1, 0xDDD6, 0x845C, 0xDDD7, 0x8451, 0xDDD8, 0x845A, 0xDDD9, 0x8459, 0xDDDA, 0x8473, 0xDDDB, 0x8487, 0xDDDC, 0x8488, 0xDDDD, 0x847A, 0xDDDE, 0x8489, 0xDDDF, 0x8478, 0xDDE0, 0x843C, 0xDDE1, 0x8446, 0xDDE2, 0x8469, 0xDDE3, 0x8476, 0xDDE4, 0x848C, 0xDDE5, 0x848E, 0xDDE6, 0x8431, 0xDDE7, 0x846D, 0xDDE8, 0x84C1, 0xDDE9, 0x84CD, 0xDDEA, 0x84D0, 0xDDEB, 0x84E6, 0xDDEC, 0x84BD, 0xDDED, 0x84D3, 0xDDEE, 0x84CA, 0xDDEF, 0x84BF, 0xDDF0, 0x84BA, 0xDDF1, 0x84E0, 0xDDF2, 0x84A1, 0xDDF3, 0x84B9, 0xDDF4, 0x84B4, 0xDDF5, 0x8497, 0xDDF6, 0x84E5, 0xDDF7, 0x84E3, 0xDDF8, 0x850C, 0xDDF9, 0x750D, 0xDDFA, 0x8538, 0xDDFB, 0x84F0, 0xDDFC, 0x8539, 0xDDFD, 0x851F, 0xDDFE, 0x853A, 0xDE40, 0x8F45, 0xDE41, 0x8F46, 0xDE42, 0x8F47, 0xDE43, 0x8F48, 0xDE44, 0x8F49, 0xDE45, 0x8F4A, 0xDE46, 0x8F4B, 0xDE47, 0x8F4C, 0xDE48, 0x8F4D, 0xDE49, 0x8F4E, 0xDE4A, 0x8F4F, 0xDE4B, 0x8F50, 0xDE4C, 0x8F51, 0xDE4D, 0x8F52, 0xDE4E, 0x8F53, 0xDE4F, 0x8F54, 0xDE50, 0x8F55, 0xDE51, 0x8F56, 0xDE52, 0x8F57, 0xDE53, 0x8F58, 0xDE54, 0x8F59, 0xDE55, 0x8F5A, 0xDE56, 0x8F5B, 0xDE57, 0x8F5C, 0xDE58, 0x8F5D, 0xDE59, 0x8F5E, 0xDE5A, 0x8F5F, 0xDE5B, 0x8F60, 0xDE5C, 0x8F61, 0xDE5D, 0x8F62, 0xDE5E, 0x8F63, 0xDE5F, 0x8F64, 0xDE60, 0x8F65, 0xDE61, 0x8F6A, 0xDE62, 0x8F80, 0xDE63, 0x8F8C, 0xDE64, 0x8F92, 0xDE65, 0x8F9D, 0xDE66, 0x8FA0, 0xDE67, 0x8FA1, 0xDE68, 0x8FA2, 0xDE69, 0x8FA4, 0xDE6A, 0x8FA5, 0xDE6B, 0x8FA6, 0xDE6C, 0x8FA7, 0xDE6D, 0x8FAA, 0xDE6E, 0x8FAC, 0xDE6F, 0x8FAD, 0xDE70, 0x8FAE, 0xDE71, 0x8FAF, 0xDE72, 0x8FB2, 0xDE73, 0x8FB3, 0xDE74, 0x8FB4, 0xDE75, 0x8FB5, 0xDE76, 0x8FB7, 0xDE77, 0x8FB8, 0xDE78, 0x8FBA, 0xDE79, 0x8FBB, 0xDE7A, 0x8FBC, 0xDE7B, 0x8FBF, 0xDE7C, 0x8FC0, 0xDE7D, 0x8FC3, 0xDE7E, 0x8FC6, 0xDE80, 0x8FC9, 0xDE81, 0x8FCA, 0xDE82, 0x8FCB, 0xDE83, 0x8FCC, 0xDE84, 0x8FCD, 0xDE85, 0x8FCF, 0xDE86, 0x8FD2, 0xDE87, 0x8FD6, 0xDE88, 0x8FD7, 0xDE89, 0x8FDA, 0xDE8A, 0x8FE0, 0xDE8B, 0x8FE1, 0xDE8C, 0x8FE3, 0xDE8D, 0x8FE7, 0xDE8E, 0x8FEC, 0xDE8F, 0x8FEF, 0xDE90, 0x8FF1, 0xDE91, 0x8FF2, 0xDE92, 0x8FF4, 0xDE93, 0x8FF5, 0xDE94, 0x8FF6, 0xDE95, 0x8FFA, 0xDE96, 0x8FFB, 0xDE97, 0x8FFC, 0xDE98, 0x8FFE, 0xDE99, 0x8FFF, 0xDE9A, 0x9007, 0xDE9B, 0x9008, 0xDE9C, 0x900C, 0xDE9D, 0x900E, 0xDE9E, 0x9013, 0xDE9F, 0x9015, 0xDEA0, 0x9018, 0xDEA1, 0x8556, 0xDEA2, 0x853B, 0xDEA3, 0x84FF, 0xDEA4, 0x84FC, 0xDEA5, 0x8559, 0xDEA6, 0x8548, 0xDEA7, 0x8568, 0xDEA8, 0x8564, 0xDEA9, 0x855E, 0xDEAA, 0x857A, 0xDEAB, 0x77A2, 0xDEAC, 0x8543, 0xDEAD, 0x8572, 0xDEAE, 0x857B, 0xDEAF, 0x85A4, 0xDEB0, 0x85A8, 0xDEB1, 0x8587, 0xDEB2, 0x858F, 0xDEB3, 0x8579, 0xDEB4, 0x85AE, 0xDEB5, 0x859C, 0xDEB6, 0x8585, 0xDEB7, 0x85B9, 0xDEB8, 0x85B7, 0xDEB9, 0x85B0, 0xDEBA, 0x85D3, 0xDEBB, 0x85C1, 0xDEBC, 0x85DC, 0xDEBD, 0x85FF, 0xDEBE, 0x8627, 0xDEBF, 0x8605, 0xDEC0, 0x8629, 0xDEC1, 0x8616, 0xDEC2, 0x863C, 0xDEC3, 0x5EFE, 0xDEC4, 0x5F08, 0xDEC5, 0x593C, 0xDEC6, 0x5941, 0xDEC7, 0x8037, 0xDEC8, 0x5955, 0xDEC9, 0x595A, 0xDECA, 0x5958, 0xDECB, 0x530F, 0xDECC, 0x5C22, 0xDECD, 0x5C25, 0xDECE, 0x5C2C, 0xDECF, 0x5C34, 0xDED0, 0x624C, 0xDED1, 0x626A, 0xDED2, 0x629F, 0xDED3, 0x62BB, 0xDED4, 0x62CA, 0xDED5, 0x62DA, 0xDED6, 0x62D7, 0xDED7, 0x62EE, 0xDED8, 0x6322, 0xDED9, 0x62F6, 0xDEDA, 0x6339, 0xDEDB, 0x634B, 0xDEDC, 0x6343, 0xDEDD, 0x63AD, 0xDEDE, 0x63F6, 0xDEDF, 0x6371, 0xDEE0, 0x637A, 0xDEE1, 0x638E, 0xDEE2, 0x63B4, 0xDEE3, 0x636D, 0xDEE4, 0x63AC, 0xDEE5, 0x638A, 0xDEE6, 0x6369, 0xDEE7, 0x63AE, 0xDEE8, 0x63BC, 0xDEE9, 0x63F2, 0xDEEA, 0x63F8, 0xDEEB, 0x63E0, 0xDEEC, 0x63FF, 0xDEED, 0x63C4, 0xDEEE, 0x63DE, 0xDEEF, 0x63CE, 0xDEF0, 0x6452, 0xDEF1, 0x63C6, 0xDEF2, 0x63BE, 0xDEF3, 0x6445, 0xDEF4, 0x6441, 0xDEF5, 0x640B, 0xDEF6, 0x641B, 0xDEF7, 0x6420, 0xDEF8, 0x640C, 0xDEF9, 0x6426, 0xDEFA, 0x6421, 0xDEFB, 0x645E, 0xDEFC, 0x6484, 0xDEFD, 0x646D, 0xDEFE, 0x6496, 0xDF40, 0x9019, 0xDF41, 0x901C, 0xDF42, 0x9023, 0xDF43, 0x9024, 0xDF44, 0x9025, 0xDF45, 0x9027, 0xDF46, 0x9028, 0xDF47, 0x9029, 0xDF48, 0x902A, 0xDF49, 0x902B, 0xDF4A, 0x902C, 0xDF4B, 0x9030, 0xDF4C, 0x9031, 0xDF4D, 0x9032, 0xDF4E, 0x9033, 0xDF4F, 0x9034, 0xDF50, 0x9037, 0xDF51, 0x9039, 0xDF52, 0x903A, 0xDF53, 0x903D, 0xDF54, 0x903F, 0xDF55, 0x9040, 0xDF56, 0x9043, 0xDF57, 0x9045, 0xDF58, 0x9046, 0xDF59, 0x9048, 0xDF5A, 0x9049, 0xDF5B, 0x904A, 0xDF5C, 0x904B, 0xDF5D, 0x904C, 0xDF5E, 0x904E, 0xDF5F, 0x9054, 0xDF60, 0x9055, 0xDF61, 0x9056, 0xDF62, 0x9059, 0xDF63, 0x905A, 0xDF64, 0x905C, 0xDF65, 0x905D, 0xDF66, 0x905E, 0xDF67, 0x905F, 0xDF68, 0x9060, 0xDF69, 0x9061, 0xDF6A, 0x9064, 0xDF6B, 0x9066, 0xDF6C, 0x9067, 0xDF6D, 0x9069, 0xDF6E, 0x906A, 0xDF6F, 0x906B, 0xDF70, 0x906C, 0xDF71, 0x906F, 0xDF72, 0x9070, 0xDF73, 0x9071, 0xDF74, 0x9072, 0xDF75, 0x9073, 0xDF76, 0x9076, 0xDF77, 0x9077, 0xDF78, 0x9078, 0xDF79, 0x9079, 0xDF7A, 0x907A, 0xDF7B, 0x907B, 0xDF7C, 0x907C, 0xDF7D, 0x907E, 0xDF7E, 0x9081, 0xDF80, 0x9084, 0xDF81, 0x9085, 0xDF82, 0x9086, 0xDF83, 0x9087, 0xDF84, 0x9089, 0xDF85, 0x908A, 0xDF86, 0x908C, 0xDF87, 0x908D, 0xDF88, 0x908E, 0xDF89, 0x908F, 0xDF8A, 0x9090, 0xDF8B, 0x9092, 0xDF8C, 0x9094, 0xDF8D, 0x9096, 0xDF8E, 0x9098, 0xDF8F, 0x909A, 0xDF90, 0x909C, 0xDF91, 0x909E, 0xDF92, 0x909F, 0xDF93, 0x90A0, 0xDF94, 0x90A4, 0xDF95, 0x90A5, 0xDF96, 0x90A7, 0xDF97, 0x90A8, 0xDF98, 0x90A9, 0xDF99, 0x90AB, 0xDF9A, 0x90AD, 0xDF9B, 0x90B2, 0xDF9C, 0x90B7, 0xDF9D, 0x90BC, 0xDF9E, 0x90BD, 0xDF9F, 0x90BF, 0xDFA0, 0x90C0, 0xDFA1, 0x647A, 0xDFA2, 0x64B7, 0xDFA3, 0x64B8, 0xDFA4, 0x6499, 0xDFA5, 0x64BA, 0xDFA6, 0x64C0, 0xDFA7, 0x64D0, 0xDFA8, 0x64D7, 0xDFA9, 0x64E4, 0xDFAA, 0x64E2, 0xDFAB, 0x6509, 0xDFAC, 0x6525, 0xDFAD, 0x652E, 0xDFAE, 0x5F0B, 0xDFAF, 0x5FD2, 0xDFB0, 0x7519, 0xDFB1, 0x5F11, 0xDFB2, 0x535F, 0xDFB3, 0x53F1, 0xDFB4, 0x53FD, 0xDFB5, 0x53E9, 0xDFB6, 0x53E8, 0xDFB7, 0x53FB, 0xDFB8, 0x5412, 0xDFB9, 0x5416, 0xDFBA, 0x5406, 0xDFBB, 0x544B, 0xDFBC, 0x5452, 0xDFBD, 0x5453, 0xDFBE, 0x5454, 0xDFBF, 0x5456, 0xDFC0, 0x5443, 0xDFC1, 0x5421, 0xDFC2, 0x5457, 0xDFC3, 0x5459, 0xDFC4, 0x5423, 0xDFC5, 0x5432, 0xDFC6, 0x5482, 0xDFC7, 0x5494, 0xDFC8, 0x5477, 0xDFC9, 0x5471, 0xDFCA, 0x5464, 0xDFCB, 0x549A, 0xDFCC, 0x549B, 0xDFCD, 0x5484, 0xDFCE, 0x5476, 0xDFCF, 0x5466, 0xDFD0, 0x549D, 0xDFD1, 0x54D0, 0xDFD2, 0x54AD, 0xDFD3, 0x54C2, 0xDFD4, 0x54B4, 0xDFD5, 0x54D2, 0xDFD6, 0x54A7, 0xDFD7, 0x54A6, 0xDFD8, 0x54D3, 0xDFD9, 0x54D4, 0xDFDA, 0x5472, 0xDFDB, 0x54A3, 0xDFDC, 0x54D5, 0xDFDD, 0x54BB, 0xDFDE, 0x54BF, 0xDFDF, 0x54CC, 0xDFE0, 0x54D9, 0xDFE1, 0x54DA, 0xDFE2, 0x54DC, 0xDFE3, 0x54A9, 0xDFE4, 0x54AA, 0xDFE5, 0x54A4, 0xDFE6, 0x54DD, 0xDFE7, 0x54CF, 0xDFE8, 0x54DE, 0xDFE9, 0x551B, 0xDFEA, 0x54E7, 0xDFEB, 0x5520, 0xDFEC, 0x54FD, 0xDFED, 0x5514, 0xDFEE, 0x54F3, 0xDFEF, 0x5522, 0xDFF0, 0x5523, 0xDFF1, 0x550F, 0xDFF2, 0x5511, 0xDFF3, 0x5527, 0xDFF4, 0x552A, 0xDFF5, 0x5567, 0xDFF6, 0x558F, 0xDFF7, 0x55B5, 0xDFF8, 0x5549, 0xDFF9, 0x556D, 0xDFFA, 0x5541, 0xDFFB, 0x5555, 0xDFFC, 0x553F, 0xDFFD, 0x5550, 0xDFFE, 0x553C, 0xE040, 0x90C2, 0xE041, 0x90C3, 0xE042, 0x90C6, 0xE043, 0x90C8, 0xE044, 0x90C9, 0xE045, 0x90CB, 0xE046, 0x90CC, 0xE047, 0x90CD, 0xE048, 0x90D2, 0xE049, 0x90D4, 0xE04A, 0x90D5, 0xE04B, 0x90D6, 0xE04C, 0x90D8, 0xE04D, 0x90D9, 0xE04E, 0x90DA, 0xE04F, 0x90DE, 0xE050, 0x90DF, 0xE051, 0x90E0, 0xE052, 0x90E3, 0xE053, 0x90E4, 0xE054, 0x90E5, 0xE055, 0x90E9, 0xE056, 0x90EA, 0xE057, 0x90EC, 0xE058, 0x90EE, 0xE059, 0x90F0, 0xE05A, 0x90F1, 0xE05B, 0x90F2, 0xE05C, 0x90F3, 0xE05D, 0x90F5, 0xE05E, 0x90F6, 0xE05F, 0x90F7, 0xE060, 0x90F9, 0xE061, 0x90FA, 0xE062, 0x90FB, 0xE063, 0x90FC, 0xE064, 0x90FF, 0xE065, 0x9100, 0xE066, 0x9101, 0xE067, 0x9103, 0xE068, 0x9105, 0xE069, 0x9106, 0xE06A, 0x9107, 0xE06B, 0x9108, 0xE06C, 0x9109, 0xE06D, 0x910A, 0xE06E, 0x910B, 0xE06F, 0x910C, 0xE070, 0x910D, 0xE071, 0x910E, 0xE072, 0x910F, 0xE073, 0x9110, 0xE074, 0x9111, 0xE075, 0x9112, 0xE076, 0x9113, 0xE077, 0x9114, 0xE078, 0x9115, 0xE079, 0x9116, 0xE07A, 0x9117, 0xE07B, 0x9118, 0xE07C, 0x911A, 0xE07D, 0x911B, 0xE07E, 0x911C, 0xE080, 0x911D, 0xE081, 0x911F, 0xE082, 0x9120, 0xE083, 0x9121, 0xE084, 0x9124, 0xE085, 0x9125, 0xE086, 0x9126, 0xE087, 0x9127, 0xE088, 0x9128, 0xE089, 0x9129, 0xE08A, 0x912A, 0xE08B, 0x912B, 0xE08C, 0x912C, 0xE08D, 0x912D, 0xE08E, 0x912E, 0xE08F, 0x9130, 0xE090, 0x9132, 0xE091, 0x9133, 0xE092, 0x9134, 0xE093, 0x9135, 0xE094, 0x9136, 0xE095, 0x9137, 0xE096, 0x9138, 0xE097, 0x913A, 0xE098, 0x913B, 0xE099, 0x913C, 0xE09A, 0x913D, 0xE09B, 0x913E, 0xE09C, 0x913F, 0xE09D, 0x9140, 0xE09E, 0x9141, 0xE09F, 0x9142, 0xE0A0, 0x9144, 0xE0A1, 0x5537, 0xE0A2, 0x5556, 0xE0A3, 0x5575, 0xE0A4, 0x5576, 0xE0A5, 0x5577, 0xE0A6, 0x5533, 0xE0A7, 0x5530, 0xE0A8, 0x555C, 0xE0A9, 0x558B, 0xE0AA, 0x55D2, 0xE0AB, 0x5583, 0xE0AC, 0x55B1, 0xE0AD, 0x55B9, 0xE0AE, 0x5588, 0xE0AF, 0x5581, 0xE0B0, 0x559F, 0xE0B1, 0x557E, 0xE0B2, 0x55D6, 0xE0B3, 0x5591, 0xE0B4, 0x557B, 0xE0B5, 0x55DF, 0xE0B6, 0x55BD, 0xE0B7, 0x55BE, 0xE0B8, 0x5594, 0xE0B9, 0x5599, 0xE0BA, 0x55EA, 0xE0BB, 0x55F7, 0xE0BC, 0x55C9, 0xE0BD, 0x561F, 0xE0BE, 0x55D1, 0xE0BF, 0x55EB, 0xE0C0, 0x55EC, 0xE0C1, 0x55D4, 0xE0C2, 0x55E6, 0xE0C3, 0x55DD, 0xE0C4, 0x55C4, 0xE0C5, 0x55EF, 0xE0C6, 0x55E5, 0xE0C7, 0x55F2, 0xE0C8, 0x55F3, 0xE0C9, 0x55CC, 0xE0CA, 0x55CD, 0xE0CB, 0x55E8, 0xE0CC, 0x55F5, 0xE0CD, 0x55E4, 0xE0CE, 0x8F94, 0xE0CF, 0x561E, 0xE0D0, 0x5608, 0xE0D1, 0x560C, 0xE0D2, 0x5601, 0xE0D3, 0x5624, 0xE0D4, 0x5623, 0xE0D5, 0x55FE, 0xE0D6, 0x5600, 0xE0D7, 0x5627, 0xE0D8, 0x562D, 0xE0D9, 0x5658, 0xE0DA, 0x5639, 0xE0DB, 0x5657, 0xE0DC, 0x562C, 0xE0DD, 0x564D, 0xE0DE, 0x5662, 0xE0DF, 0x5659, 0xE0E0, 0x565C, 0xE0E1, 0x564C, 0xE0E2, 0x5654, 0xE0E3, 0x5686, 0xE0E4, 0x5664, 0xE0E5, 0x5671, 0xE0E6, 0x566B, 0xE0E7, 0x567B, 0xE0E8, 0x567C, 0xE0E9, 0x5685, 0xE0EA, 0x5693, 0xE0EB, 0x56AF, 0xE0EC, 0x56D4, 0xE0ED, 0x56D7, 0xE0EE, 0x56DD, 0xE0EF, 0x56E1, 0xE0F0, 0x56F5, 0xE0F1, 0x56EB, 0xE0F2, 0x56F9, 0xE0F3, 0x56FF, 0xE0F4, 0x5704, 0xE0F5, 0x570A, 0xE0F6, 0x5709, 0xE0F7, 0x571C, 0xE0F8, 0x5E0F, 0xE0F9, 0x5E19, 0xE0FA, 0x5E14, 0xE0FB, 0x5E11, 0xE0FC, 0x5E31, 0xE0FD, 0x5E3B, 0xE0FE, 0x5E3C, 0xE140, 0x9145, 0xE141, 0x9147, 0xE142, 0x9148, 0xE143, 0x9151, 0xE144, 0x9153, 0xE145, 0x9154, 0xE146, 0x9155, 0xE147, 0x9156, 0xE148, 0x9158, 0xE149, 0x9159, 0xE14A, 0x915B, 0xE14B, 0x915C, 0xE14C, 0x915F, 0xE14D, 0x9160, 0xE14E, 0x9166, 0xE14F, 0x9167, 0xE150, 0x9168, 0xE151, 0x916B, 0xE152, 0x916D, 0xE153, 0x9173, 0xE154, 0x917A, 0xE155, 0x917B, 0xE156, 0x917C, 0xE157, 0x9180, 0xE158, 0x9181, 0xE159, 0x9182, 0xE15A, 0x9183, 0xE15B, 0x9184, 0xE15C, 0x9186, 0xE15D, 0x9188, 0xE15E, 0x918A, 0xE15F, 0x918E, 0xE160, 0x918F, 0xE161, 0x9193, 0xE162, 0x9194, 0xE163, 0x9195, 0xE164, 0x9196, 0xE165, 0x9197, 0xE166, 0x9198, 0xE167, 0x9199, 0xE168, 0x919C, 0xE169, 0x919D, 0xE16A, 0x919E, 0xE16B, 0x919F, 0xE16C, 0x91A0, 0xE16D, 0x91A1, 0xE16E, 0x91A4, 0xE16F, 0x91A5, 0xE170, 0x91A6, 0xE171, 0x91A7, 0xE172, 0x91A8, 0xE173, 0x91A9, 0xE174, 0x91AB, 0xE175, 0x91AC, 0xE176, 0x91B0, 0xE177, 0x91B1, 0xE178, 0x91B2, 0xE179, 0x91B3, 0xE17A, 0x91B6, 0xE17B, 0x91B7, 0xE17C, 0x91B8, 0xE17D, 0x91B9, 0xE17E, 0x91BB, 0xE180, 0x91BC, 0xE181, 0x91BD, 0xE182, 0x91BE, 0xE183, 0x91BF, 0xE184, 0x91C0, 0xE185, 0x91C1, 0xE186, 0x91C2, 0xE187, 0x91C3, 0xE188, 0x91C4, 0xE189, 0x91C5, 0xE18A, 0x91C6, 0xE18B, 0x91C8, 0xE18C, 0x91CB, 0xE18D, 0x91D0, 0xE18E, 0x91D2, 0xE18F, 0x91D3, 0xE190, 0x91D4, 0xE191, 0x91D5, 0xE192, 0x91D6, 0xE193, 0x91D7, 0xE194, 0x91D8, 0xE195, 0x91D9, 0xE196, 0x91DA, 0xE197, 0x91DB, 0xE198, 0x91DD, 0xE199, 0x91DE, 0xE19A, 0x91DF, 0xE19B, 0x91E0, 0xE19C, 0x91E1, 0xE19D, 0x91E2, 0xE19E, 0x91E3, 0xE19F, 0x91E4, 0xE1A0, 0x91E5, 0xE1A1, 0x5E37, 0xE1A2, 0x5E44, 0xE1A3, 0x5E54, 0xE1A4, 0x5E5B, 0xE1A5, 0x5E5E, 0xE1A6, 0x5E61, 0xE1A7, 0x5C8C, 0xE1A8, 0x5C7A, 0xE1A9, 0x5C8D, 0xE1AA, 0x5C90, 0xE1AB, 0x5C96, 0xE1AC, 0x5C88, 0xE1AD, 0x5C98, 0xE1AE, 0x5C99, 0xE1AF, 0x5C91, 0xE1B0, 0x5C9A, 0xE1B1, 0x5C9C, 0xE1B2, 0x5CB5, 0xE1B3, 0x5CA2, 0xE1B4, 0x5CBD, 0xE1B5, 0x5CAC, 0xE1B6, 0x5CAB, 0xE1B7, 0x5CB1, 0xE1B8, 0x5CA3, 0xE1B9, 0x5CC1, 0xE1BA, 0x5CB7, 0xE1BB, 0x5CC4, 0xE1BC, 0x5CD2, 0xE1BD, 0x5CE4, 0xE1BE, 0x5CCB, 0xE1BF, 0x5CE5, 0xE1C0, 0x5D02, 0xE1C1, 0x5D03, 0xE1C2, 0x5D27, 0xE1C3, 0x5D26, 0xE1C4, 0x5D2E, 0xE1C5, 0x5D24, 0xE1C6, 0x5D1E, 0xE1C7, 0x5D06, 0xE1C8, 0x5D1B, 0xE1C9, 0x5D58, 0xE1CA, 0x5D3E, 0xE1CB, 0x5D34, 0xE1CC, 0x5D3D, 0xE1CD, 0x5D6C, 0xE1CE, 0x5D5B, 0xE1CF, 0x5D6F, 0xE1D0, 0x5D5D, 0xE1D1, 0x5D6B, 0xE1D2, 0x5D4B, 0xE1D3, 0x5D4A, 0xE1D4, 0x5D69, 0xE1D5, 0x5D74, 0xE1D6, 0x5D82, 0xE1D7, 0x5D99, 0xE1D8, 0x5D9D, 0xE1D9, 0x8C73, 0xE1DA, 0x5DB7, 0xE1DB, 0x5DC5, 0xE1DC, 0x5F73, 0xE1DD, 0x5F77, 0xE1DE, 0x5F82, 0xE1DF, 0x5F87, 0xE1E0, 0x5F89, 0xE1E1, 0x5F8C, 0xE1E2, 0x5F95, 0xE1E3, 0x5F99, 0xE1E4, 0x5F9C, 0xE1E5, 0x5FA8, 0xE1E6, 0x5FAD, 0xE1E7, 0x5FB5, 0xE1E8, 0x5FBC, 0xE1E9, 0x8862, 0xE1EA, 0x5F61, 0xE1EB, 0x72AD, 0xE1EC, 0x72B0, 0xE1ED, 0x72B4, 0xE1EE, 0x72B7, 0xE1EF, 0x72B8, 0xE1F0, 0x72C3, 0xE1F1, 0x72C1, 0xE1F2, 0x72CE, 0xE1F3, 0x72CD, 0xE1F4, 0x72D2, 0xE1F5, 0x72E8, 0xE1F6, 0x72EF, 0xE1F7, 0x72E9, 0xE1F8, 0x72F2, 0xE1F9, 0x72F4, 0xE1FA, 0x72F7, 0xE1FB, 0x7301, 0xE1FC, 0x72F3, 0xE1FD, 0x7303, 0xE1FE, 0x72FA, 0xE240, 0x91E6, 0xE241, 0x91E7, 0xE242, 0x91E8, 0xE243, 0x91E9, 0xE244, 0x91EA, 0xE245, 0x91EB, 0xE246, 0x91EC, 0xE247, 0x91ED, 0xE248, 0x91EE, 0xE249, 0x91EF, 0xE24A, 0x91F0, 0xE24B, 0x91F1, 0xE24C, 0x91F2, 0xE24D, 0x91F3, 0xE24E, 0x91F4, 0xE24F, 0x91F5, 0xE250, 0x91F6, 0xE251, 0x91F7, 0xE252, 0x91F8, 0xE253, 0x91F9, 0xE254, 0x91FA, 0xE255, 0x91FB, 0xE256, 0x91FC, 0xE257, 0x91FD, 0xE258, 0x91FE, 0xE259, 0x91FF, 0xE25A, 0x9200, 0xE25B, 0x9201, 0xE25C, 0x9202, 0xE25D, 0x9203, 0xE25E, 0x9204, 0xE25F, 0x9205, 0xE260, 0x9206, 0xE261, 0x9207, 0xE262, 0x9208, 0xE263, 0x9209, 0xE264, 0x920A, 0xE265, 0x920B, 0xE266, 0x920C, 0xE267, 0x920D, 0xE268, 0x920E, 0xE269, 0x920F, 0xE26A, 0x9210, 0xE26B, 0x9211, 0xE26C, 0x9212, 0xE26D, 0x9213, 0xE26E, 0x9214, 0xE26F, 0x9215, 0xE270, 0x9216, 0xE271, 0x9217, 0xE272, 0x9218, 0xE273, 0x9219, 0xE274, 0x921A, 0xE275, 0x921B, 0xE276, 0x921C, 0xE277, 0x921D, 0xE278, 0x921E, 0xE279, 0x921F, 0xE27A, 0x9220, 0xE27B, 0x9221, 0xE27C, 0x9222, 0xE27D, 0x9223, 0xE27E, 0x9224, 0xE280, 0x9225, 0xE281, 0x9226, 0xE282, 0x9227, 0xE283, 0x9228, 0xE284, 0x9229, 0xE285, 0x922A, 0xE286, 0x922B, 0xE287, 0x922C, 0xE288, 0x922D, 0xE289, 0x922E, 0xE28A, 0x922F, 0xE28B, 0x9230, 0xE28C, 0x9231, 0xE28D, 0x9232, 0xE28E, 0x9233, 0xE28F, 0x9234, 0xE290, 0x9235, 0xE291, 0x9236, 0xE292, 0x9237, 0xE293, 0x9238, 0xE294, 0x9239, 0xE295, 0x923A, 0xE296, 0x923B, 0xE297, 0x923C, 0xE298, 0x923D, 0xE299, 0x923E, 0xE29A, 0x923F, 0xE29B, 0x9240, 0xE29C, 0x9241, 0xE29D, 0x9242, 0xE29E, 0x9243, 0xE29F, 0x9244, 0xE2A0, 0x9245, 0xE2A1, 0x72FB, 0xE2A2, 0x7317, 0xE2A3, 0x7313, 0xE2A4, 0x7321, 0xE2A5, 0x730A, 0xE2A6, 0x731E, 0xE2A7, 0x731D, 0xE2A8, 0x7315, 0xE2A9, 0x7322, 0xE2AA, 0x7339, 0xE2AB, 0x7325, 0xE2AC, 0x732C, 0xE2AD, 0x7338, 0xE2AE, 0x7331, 0xE2AF, 0x7350, 0xE2B0, 0x734D, 0xE2B1, 0x7357, 0xE2B2, 0x7360, 0xE2B3, 0x736C, 0xE2B4, 0x736F, 0xE2B5, 0x737E, 0xE2B6, 0x821B, 0xE2B7, 0x5925, 0xE2B8, 0x98E7, 0xE2B9, 0x5924, 0xE2BA, 0x5902, 0xE2BB, 0x9963, 0xE2BC, 0x9967, 0xE2BD, 0x9968, 0xE2BE, 0x9969, 0xE2BF, 0x996A, 0xE2C0, 0x996B, 0xE2C1, 0x996C, 0xE2C2, 0x9974, 0xE2C3, 0x9977, 0xE2C4, 0x997D, 0xE2C5, 0x9980, 0xE2C6, 0x9984, 0xE2C7, 0x9987, 0xE2C8, 0x998A, 0xE2C9, 0x998D, 0xE2CA, 0x9990, 0xE2CB, 0x9991, 0xE2CC, 0x9993, 0xE2CD, 0x9994, 0xE2CE, 0x9995, 0xE2CF, 0x5E80, 0xE2D0, 0x5E91, 0xE2D1, 0x5E8B, 0xE2D2, 0x5E96, 0xE2D3, 0x5EA5, 0xE2D4, 0x5EA0, 0xE2D5, 0x5EB9, 0xE2D6, 0x5EB5, 0xE2D7, 0x5EBE, 0xE2D8, 0x5EB3, 0xE2D9, 0x8D53, 0xE2DA, 0x5ED2, 0xE2DB, 0x5ED1, 0xE2DC, 0x5EDB, 0xE2DD, 0x5EE8, 0xE2DE, 0x5EEA, 0xE2DF, 0x81BA, 0xE2E0, 0x5FC4, 0xE2E1, 0x5FC9, 0xE2E2, 0x5FD6, 0xE2E3, 0x5FCF, 0xE2E4, 0x6003, 0xE2E5, 0x5FEE, 0xE2E6, 0x6004, 0xE2E7, 0x5FE1, 0xE2E8, 0x5FE4, 0xE2E9, 0x5FFE, 0xE2EA, 0x6005, 0xE2EB, 0x6006, 0xE2EC, 0x5FEA, 0xE2ED, 0x5FED, 0xE2EE, 0x5FF8, 0xE2EF, 0x6019, 0xE2F0, 0x6035, 0xE2F1, 0x6026, 0xE2F2, 0x601B, 0xE2F3, 0x600F, 0xE2F4, 0x600D, 0xE2F5, 0x6029, 0xE2F6, 0x602B, 0xE2F7, 0x600A, 0xE2F8, 0x603F, 0xE2F9, 0x6021, 0xE2FA, 0x6078, 0xE2FB, 0x6079, 0xE2FC, 0x607B, 0xE2FD, 0x607A, 0xE2FE, 0x6042, 0xE340, 0x9246, 0xE341, 0x9247, 0xE342, 0x9248, 0xE343, 0x9249, 0xE344, 0x924A, 0xE345, 0x924B, 0xE346, 0x924C, 0xE347, 0x924D, 0xE348, 0x924E, 0xE349, 0x924F, 0xE34A, 0x9250, 0xE34B, 0x9251, 0xE34C, 0x9252, 0xE34D, 0x9253, 0xE34E, 0x9254, 0xE34F, 0x9255, 0xE350, 0x9256, 0xE351, 0x9257, 0xE352, 0x9258, 0xE353, 0x9259, 0xE354, 0x925A, 0xE355, 0x925B, 0xE356, 0x925C, 0xE357, 0x925D, 0xE358, 0x925E, 0xE359, 0x925F, 0xE35A, 0x9260, 0xE35B, 0x9261, 0xE35C, 0x9262, 0xE35D, 0x9263, 0xE35E, 0x9264, 0xE35F, 0x9265, 0xE360, 0x9266, 0xE361, 0x9267, 0xE362, 0x9268, 0xE363, 0x9269, 0xE364, 0x926A, 0xE365, 0x926B, 0xE366, 0x926C, 0xE367, 0x926D, 0xE368, 0x926E, 0xE369, 0x926F, 0xE36A, 0x9270, 0xE36B, 0x9271, 0xE36C, 0x9272, 0xE36D, 0x9273, 0xE36E, 0x9275, 0xE36F, 0x9276, 0xE370, 0x9277, 0xE371, 0x9278, 0xE372, 0x9279, 0xE373, 0x927A, 0xE374, 0x927B, 0xE375, 0x927C, 0xE376, 0x927D, 0xE377, 0x927E, 0xE378, 0x927F, 0xE379, 0x9280, 0xE37A, 0x9281, 0xE37B, 0x9282, 0xE37C, 0x9283, 0xE37D, 0x9284, 0xE37E, 0x9285, 0xE380, 0x9286, 0xE381, 0x9287, 0xE382, 0x9288, 0xE383, 0x9289, 0xE384, 0x928A, 0xE385, 0x928B, 0xE386, 0x928C, 0xE387, 0x928D, 0xE388, 0x928F, 0xE389, 0x9290, 0xE38A, 0x9291, 0xE38B, 0x9292, 0xE38C, 0x9293, 0xE38D, 0x9294, 0xE38E, 0x9295, 0xE38F, 0x9296, 0xE390, 0x9297, 0xE391, 0x9298, 0xE392, 0x9299, 0xE393, 0x929A, 0xE394, 0x929B, 0xE395, 0x929C, 0xE396, 0x929D, 0xE397, 0x929E, 0xE398, 0x929F, 0xE399, 0x92A0, 0xE39A, 0x92A1, 0xE39B, 0x92A2, 0xE39C, 0x92A3, 0xE39D, 0x92A4, 0xE39E, 0x92A5, 0xE39F, 0x92A6, 0xE3A0, 0x92A7, 0xE3A1, 0x606A, 0xE3A2, 0x607D, 0xE3A3, 0x6096, 0xE3A4, 0x609A, 0xE3A5, 0x60AD, 0xE3A6, 0x609D, 0xE3A7, 0x6083, 0xE3A8, 0x6092, 0xE3A9, 0x608C, 0xE3AA, 0x609B, 0xE3AB, 0x60EC, 0xE3AC, 0x60BB, 0xE3AD, 0x60B1, 0xE3AE, 0x60DD, 0xE3AF, 0x60D8, 0xE3B0, 0x60C6, 0xE3B1, 0x60DA, 0xE3B2, 0x60B4, 0xE3B3, 0x6120, 0xE3B4, 0x6126, 0xE3B5, 0x6115, 0xE3B6, 0x6123, 0xE3B7, 0x60F4, 0xE3B8, 0x6100, 0xE3B9, 0x610E, 0xE3BA, 0x612B, 0xE3BB, 0x614A, 0xE3BC, 0x6175, 0xE3BD, 0x61AC, 0xE3BE, 0x6194, 0xE3BF, 0x61A7, 0xE3C0, 0x61B7, 0xE3C1, 0x61D4, 0xE3C2, 0x61F5, 0xE3C3, 0x5FDD, 0xE3C4, 0x96B3, 0xE3C5, 0x95E9, 0xE3C6, 0x95EB, 0xE3C7, 0x95F1, 0xE3C8, 0x95F3, 0xE3C9, 0x95F5, 0xE3CA, 0x95F6, 0xE3CB, 0x95FC, 0xE3CC, 0x95FE, 0xE3CD, 0x9603, 0xE3CE, 0x9604, 0xE3CF, 0x9606, 0xE3D0, 0x9608, 0xE3D1, 0x960A, 0xE3D2, 0x960B, 0xE3D3, 0x960C, 0xE3D4, 0x960D, 0xE3D5, 0x960F, 0xE3D6, 0x9612, 0xE3D7, 0x9615, 0xE3D8, 0x9616, 0xE3D9, 0x9617, 0xE3DA, 0x9619, 0xE3DB, 0x961A, 0xE3DC, 0x4E2C, 0xE3DD, 0x723F, 0xE3DE, 0x6215, 0xE3DF, 0x6C35, 0xE3E0, 0x6C54, 0xE3E1, 0x6C5C, 0xE3E2, 0x6C4A, 0xE3E3, 0x6CA3, 0xE3E4, 0x6C85, 0xE3E5, 0x6C90, 0xE3E6, 0x6C94, 0xE3E7, 0x6C8C, 0xE3E8, 0x6C68, 0xE3E9, 0x6C69, 0xE3EA, 0x6C74, 0xE3EB, 0x6C76, 0xE3EC, 0x6C86, 0xE3ED, 0x6CA9, 0xE3EE, 0x6CD0, 0xE3EF, 0x6CD4, 0xE3F0, 0x6CAD, 0xE3F1, 0x6CF7, 0xE3F2, 0x6CF8, 0xE3F3, 0x6CF1, 0xE3F4, 0x6CD7, 0xE3F5, 0x6CB2, 0xE3F6, 0x6CE0, 0xE3F7, 0x6CD6, 0xE3F8, 0x6CFA, 0xE3F9, 0x6CEB, 0xE3FA, 0x6CEE, 0xE3FB, 0x6CB1, 0xE3FC, 0x6CD3, 0xE3FD, 0x6CEF, 0xE3FE, 0x6CFE, 0xE440, 0x92A8, 0xE441, 0x92A9, 0xE442, 0x92AA, 0xE443, 0x92AB, 0xE444, 0x92AC, 0xE445, 0x92AD, 0xE446, 0x92AF, 0xE447, 0x92B0, 0xE448, 0x92B1, 0xE449, 0x92B2, 0xE44A, 0x92B3, 0xE44B, 0x92B4, 0xE44C, 0x92B5, 0xE44D, 0x92B6, 0xE44E, 0x92B7, 0xE44F, 0x92B8, 0xE450, 0x92B9, 0xE451, 0x92BA, 0xE452, 0x92BB, 0xE453, 0x92BC, 0xE454, 0x92BD, 0xE455, 0x92BE, 0xE456, 0x92BF, 0xE457, 0x92C0, 0xE458, 0x92C1, 0xE459, 0x92C2, 0xE45A, 0x92C3, 0xE45B, 0x92C4, 0xE45C, 0x92C5, 0xE45D, 0x92C6, 0xE45E, 0x92C7, 0xE45F, 0x92C9, 0xE460, 0x92CA, 0xE461, 0x92CB, 0xE462, 0x92CC, 0xE463, 0x92CD, 0xE464, 0x92CE, 0xE465, 0x92CF, 0xE466, 0x92D0, 0xE467, 0x92D1, 0xE468, 0x92D2, 0xE469, 0x92D3, 0xE46A, 0x92D4, 0xE46B, 0x92D5, 0xE46C, 0x92D6, 0xE46D, 0x92D7, 0xE46E, 0x92D8, 0xE46F, 0x92D9, 0xE470, 0x92DA, 0xE471, 0x92DB, 0xE472, 0x92DC, 0xE473, 0x92DD, 0xE474, 0x92DE, 0xE475, 0x92DF, 0xE476, 0x92E0, 0xE477, 0x92E1, 0xE478, 0x92E2, 0xE479, 0x92E3, 0xE47A, 0x92E4, 0xE47B, 0x92E5, 0xE47C, 0x92E6, 0xE47D, 0x92E7, 0xE47E, 0x92E8, 0xE480, 0x92E9, 0xE481, 0x92EA, 0xE482, 0x92EB, 0xE483, 0x92EC, 0xE484, 0x92ED, 0xE485, 0x92EE, 0xE486, 0x92EF, 0xE487, 0x92F0, 0xE488, 0x92F1, 0xE489, 0x92F2, 0xE48A, 0x92F3, 0xE48B, 0x92F4, 0xE48C, 0x92F5, 0xE48D, 0x92F6, 0xE48E, 0x92F7, 0xE48F, 0x92F8, 0xE490, 0x92F9, 0xE491, 0x92FA, 0xE492, 0x92FB, 0xE493, 0x92FC, 0xE494, 0x92FD, 0xE495, 0x92FE, 0xE496, 0x92FF, 0xE497, 0x9300, 0xE498, 0x9301, 0xE499, 0x9302, 0xE49A, 0x9303, 0xE49B, 0x9304, 0xE49C, 0x9305, 0xE49D, 0x9306, 0xE49E, 0x9307, 0xE49F, 0x9308, 0xE4A0, 0x9309, 0xE4A1, 0x6D39, 0xE4A2, 0x6D27, 0xE4A3, 0x6D0C, 0xE4A4, 0x6D43, 0xE4A5, 0x6D48, 0xE4A6, 0x6D07, 0xE4A7, 0x6D04, 0xE4A8, 0x6D19, 0xE4A9, 0x6D0E, 0xE4AA, 0x6D2B, 0xE4AB, 0x6D4D, 0xE4AC, 0x6D2E, 0xE4AD, 0x6D35, 0xE4AE, 0x6D1A, 0xE4AF, 0x6D4F, 0xE4B0, 0x6D52, 0xE4B1, 0x6D54, 0xE4B2, 0x6D33, 0xE4B3, 0x6D91, 0xE4B4, 0x6D6F, 0xE4B5, 0x6D9E, 0xE4B6, 0x6DA0, 0xE4B7, 0x6D5E, 0xE4B8, 0x6D93, 0xE4B9, 0x6D94, 0xE4BA, 0x6D5C, 0xE4BB, 0x6D60, 0xE4BC, 0x6D7C, 0xE4BD, 0x6D63, 0xE4BE, 0x6E1A, 0xE4BF, 0x6DC7, 0xE4C0, 0x6DC5, 0xE4C1, 0x6DDE, 0xE4C2, 0x6E0E, 0xE4C3, 0x6DBF, 0xE4C4, 0x6DE0, 0xE4C5, 0x6E11, 0xE4C6, 0x6DE6, 0xE4C7, 0x6DDD, 0xE4C8, 0x6DD9, 0xE4C9, 0x6E16, 0xE4CA, 0x6DAB, 0xE4CB, 0x6E0C, 0xE4CC, 0x6DAE, 0xE4CD, 0x6E2B, 0xE4CE, 0x6E6E, 0xE4CF, 0x6E4E, 0xE4D0, 0x6E6B, 0xE4D1, 0x6EB2, 0xE4D2, 0x6E5F, 0xE4D3, 0x6E86, 0xE4D4, 0x6E53, 0xE4D5, 0x6E54, 0xE4D6, 0x6E32, 0xE4D7, 0x6E25, 0xE4D8, 0x6E44, 0xE4D9, 0x6EDF, 0xE4DA, 0x6EB1, 0xE4DB, 0x6E98, 0xE4DC, 0x6EE0, 0xE4DD, 0x6F2D, 0xE4DE, 0x6EE2, 0xE4DF, 0x6EA5, 0xE4E0, 0x6EA7, 0xE4E1, 0x6EBD, 0xE4E2, 0x6EBB, 0xE4E3, 0x6EB7, 0xE4E4, 0x6ED7, 0xE4E5, 0x6EB4, 0xE4E6, 0x6ECF, 0xE4E7, 0x6E8F, 0xE4E8, 0x6EC2, 0xE4E9, 0x6E9F, 0xE4EA, 0x6F62, 0xE4EB, 0x6F46, 0xE4EC, 0x6F47, 0xE4ED, 0x6F24, 0xE4EE, 0x6F15, 0xE4EF, 0x6EF9, 0xE4F0, 0x6F2F, 0xE4F1, 0x6F36, 0xE4F2, 0x6F4B, 0xE4F3, 0x6F74, 0xE4F4, 0x6F2A, 0xE4F5, 0x6F09, 0xE4F6, 0x6F29, 0xE4F7, 0x6F89, 0xE4F8, 0x6F8D, 0xE4F9, 0x6F8C, 0xE4FA, 0x6F78, 0xE4FB, 0x6F72, 0xE4FC, 0x6F7C, 0xE4FD, 0x6F7A, 0xE4FE, 0x6FD1, 0xE540, 0x930A, 0xE541, 0x930B, 0xE542, 0x930C, 0xE543, 0x930D, 0xE544, 0x930E, 0xE545, 0x930F, 0xE546, 0x9310, 0xE547, 0x9311, 0xE548, 0x9312, 0xE549, 0x9313, 0xE54A, 0x9314, 0xE54B, 0x9315, 0xE54C, 0x9316, 0xE54D, 0x9317, 0xE54E, 0x9318, 0xE54F, 0x9319, 0xE550, 0x931A, 0xE551, 0x931B, 0xE552, 0x931C, 0xE553, 0x931D, 0xE554, 0x931E, 0xE555, 0x931F, 0xE556, 0x9320, 0xE557, 0x9321, 0xE558, 0x9322, 0xE559, 0x9323, 0xE55A, 0x9324, 0xE55B, 0x9325, 0xE55C, 0x9326, 0xE55D, 0x9327, 0xE55E, 0x9328, 0xE55F, 0x9329, 0xE560, 0x932A, 0xE561, 0x932B, 0xE562, 0x932C, 0xE563, 0x932D, 0xE564, 0x932E, 0xE565, 0x932F, 0xE566, 0x9330, 0xE567, 0x9331, 0xE568, 0x9332, 0xE569, 0x9333, 0xE56A, 0x9334, 0xE56B, 0x9335, 0xE56C, 0x9336, 0xE56D, 0x9337, 0xE56E, 0x9338, 0xE56F, 0x9339, 0xE570, 0x933A, 0xE571, 0x933B, 0xE572, 0x933C, 0xE573, 0x933D, 0xE574, 0x933F, 0xE575, 0x9340, 0xE576, 0x9341, 0xE577, 0x9342, 0xE578, 0x9343, 0xE579, 0x9344, 0xE57A, 0x9345, 0xE57B, 0x9346, 0xE57C, 0x9347, 0xE57D, 0x9348, 0xE57E, 0x9349, 0xE580, 0x934A, 0xE581, 0x934B, 0xE582, 0x934C, 0xE583, 0x934D, 0xE584, 0x934E, 0xE585, 0x934F, 0xE586, 0x9350, 0xE587, 0x9351, 0xE588, 0x9352, 0xE589, 0x9353, 0xE58A, 0x9354, 0xE58B, 0x9355, 0xE58C, 0x9356, 0xE58D, 0x9357, 0xE58E, 0x9358, 0xE58F, 0x9359, 0xE590, 0x935A, 0xE591, 0x935B, 0xE592, 0x935C, 0xE593, 0x935D, 0xE594, 0x935E, 0xE595, 0x935F, 0xE596, 0x9360, 0xE597, 0x9361, 0xE598, 0x9362, 0xE599, 0x9363, 0xE59A, 0x9364, 0xE59B, 0x9365, 0xE59C, 0x9366, 0xE59D, 0x9367, 0xE59E, 0x9368, 0xE59F, 0x9369, 0xE5A0, 0x936B, 0xE5A1, 0x6FC9, 0xE5A2, 0x6FA7, 0xE5A3, 0x6FB9, 0xE5A4, 0x6FB6, 0xE5A5, 0x6FC2, 0xE5A6, 0x6FE1, 0xE5A7, 0x6FEE, 0xE5A8, 0x6FDE, 0xE5A9, 0x6FE0, 0xE5AA, 0x6FEF, 0xE5AB, 0x701A, 0xE5AC, 0x7023, 0xE5AD, 0x701B, 0xE5AE, 0x7039, 0xE5AF, 0x7035, 0xE5B0, 0x704F, 0xE5B1, 0x705E, 0xE5B2, 0x5B80, 0xE5B3, 0x5B84, 0xE5B4, 0x5B95, 0xE5B5, 0x5B93, 0xE5B6, 0x5BA5, 0xE5B7, 0x5BB8, 0xE5B8, 0x752F, 0xE5B9, 0x9A9E, 0xE5BA, 0x6434, 0xE5BB, 0x5BE4, 0xE5BC, 0x5BEE, 0xE5BD, 0x8930, 0xE5BE, 0x5BF0, 0xE5BF, 0x8E47, 0xE5C0, 0x8B07, 0xE5C1, 0x8FB6, 0xE5C2, 0x8FD3, 0xE5C3, 0x8FD5, 0xE5C4, 0x8FE5, 0xE5C5, 0x8FEE, 0xE5C6, 0x8FE4, 0xE5C7, 0x8FE9, 0xE5C8, 0x8FE6, 0xE5C9, 0x8FF3, 0xE5CA, 0x8FE8, 0xE5CB, 0x9005, 0xE5CC, 0x9004, 0xE5CD, 0x900B, 0xE5CE, 0x9026, 0xE5CF, 0x9011, 0xE5D0, 0x900D, 0xE5D1, 0x9016, 0xE5D2, 0x9021, 0xE5D3, 0x9035, 0xE5D4, 0x9036, 0xE5D5, 0x902D, 0xE5D6, 0x902F, 0xE5D7, 0x9044, 0xE5D8, 0x9051, 0xE5D9, 0x9052, 0xE5DA, 0x9050, 0xE5DB, 0x9068, 0xE5DC, 0x9058, 0xE5DD, 0x9062, 0xE5DE, 0x905B, 0xE5DF, 0x66B9, 0xE5E0, 0x9074, 0xE5E1, 0x907D, 0xE5E2, 0x9082, 0xE5E3, 0x9088, 0xE5E4, 0x9083, 0xE5E5, 0x908B, 0xE5E6, 0x5F50, 0xE5E7, 0x5F57, 0xE5E8, 0x5F56, 0xE5E9, 0x5F58, 0xE5EA, 0x5C3B, 0xE5EB, 0x54AB, 0xE5EC, 0x5C50, 0xE5ED, 0x5C59, 0xE5EE, 0x5B71, 0xE5EF, 0x5C63, 0xE5F0, 0x5C66, 0xE5F1, 0x7FBC, 0xE5F2, 0x5F2A, 0xE5F3, 0x5F29, 0xE5F4, 0x5F2D, 0xE5F5, 0x8274, 0xE5F6, 0x5F3C, 0xE5F7, 0x9B3B, 0xE5F8, 0x5C6E, 0xE5F9, 0x5981, 0xE5FA, 0x5983, 0xE5FB, 0x598D, 0xE5FC, 0x59A9, 0xE5FD, 0x59AA, 0xE5FE, 0x59A3, 0xE640, 0x936C, 0xE641, 0x936D, 0xE642, 0x936E, 0xE643, 0x936F, 0xE644, 0x9370, 0xE645, 0x9371, 0xE646, 0x9372, 0xE647, 0x9373, 0xE648, 0x9374, 0xE649, 0x9375, 0xE64A, 0x9376, 0xE64B, 0x9377, 0xE64C, 0x9378, 0xE64D, 0x9379, 0xE64E, 0x937A, 0xE64F, 0x937B, 0xE650, 0x937C, 0xE651, 0x937D, 0xE652, 0x937E, 0xE653, 0x937F, 0xE654, 0x9380, 0xE655, 0x9381, 0xE656, 0x9382, 0xE657, 0x9383, 0xE658, 0x9384, 0xE659, 0x9385, 0xE65A, 0x9386, 0xE65B, 0x9387, 0xE65C, 0x9388, 0xE65D, 0x9389, 0xE65E, 0x938A, 0xE65F, 0x938B, 0xE660, 0x938C, 0xE661, 0x938D, 0xE662, 0x938E, 0xE663, 0x9390, 0xE664, 0x9391, 0xE665, 0x9392, 0xE666, 0x9393, 0xE667, 0x9394, 0xE668, 0x9395, 0xE669, 0x9396, 0xE66A, 0x9397, 0xE66B, 0x9398, 0xE66C, 0x9399, 0xE66D, 0x939A, 0xE66E, 0x939B, 0xE66F, 0x939C, 0xE670, 0x939D, 0xE671, 0x939E, 0xE672, 0x939F, 0xE673, 0x93A0, 0xE674, 0x93A1, 0xE675, 0x93A2, 0xE676, 0x93A3, 0xE677, 0x93A4, 0xE678, 0x93A5, 0xE679, 0x93A6, 0xE67A, 0x93A7, 0xE67B, 0x93A8, 0xE67C, 0x93A9, 0xE67D, 0x93AA, 0xE67E, 0x93AB, 0xE680, 0x93AC, 0xE681, 0x93AD, 0xE682, 0x93AE, 0xE683, 0x93AF, 0xE684, 0x93B0, 0xE685, 0x93B1, 0xE686, 0x93B2, 0xE687, 0x93B3, 0xE688, 0x93B4, 0xE689, 0x93B5, 0xE68A, 0x93B6, 0xE68B, 0x93B7, 0xE68C, 0x93B8, 0xE68D, 0x93B9, 0xE68E, 0x93BA, 0xE68F, 0x93BB, 0xE690, 0x93BC, 0xE691, 0x93BD, 0xE692, 0x93BE, 0xE693, 0x93BF, 0xE694, 0x93C0, 0xE695, 0x93C1, 0xE696, 0x93C2, 0xE697, 0x93C3, 0xE698, 0x93C4, 0xE699, 0x93C5, 0xE69A, 0x93C6, 0xE69B, 0x93C7, 0xE69C, 0x93C8, 0xE69D, 0x93C9, 0xE69E, 0x93CB, 0xE69F, 0x93CC, 0xE6A0, 0x93CD, 0xE6A1, 0x5997, 0xE6A2, 0x59CA, 0xE6A3, 0x59AB, 0xE6A4, 0x599E, 0xE6A5, 0x59A4, 0xE6A6, 0x59D2, 0xE6A7, 0x59B2, 0xE6A8, 0x59AF, 0xE6A9, 0x59D7, 0xE6AA, 0x59BE, 0xE6AB, 0x5A05, 0xE6AC, 0x5A06, 0xE6AD, 0x59DD, 0xE6AE, 0x5A08, 0xE6AF, 0x59E3, 0xE6B0, 0x59D8, 0xE6B1, 0x59F9, 0xE6B2, 0x5A0C, 0xE6B3, 0x5A09, 0xE6B4, 0x5A32, 0xE6B5, 0x5A34, 0xE6B6, 0x5A11, 0xE6B7, 0x5A23, 0xE6B8, 0x5A13, 0xE6B9, 0x5A40, 0xE6BA, 0x5A67, 0xE6BB, 0x5A4A, 0xE6BC, 0x5A55, 0xE6BD, 0x5A3C, 0xE6BE, 0x5A62, 0xE6BF, 0x5A75, 0xE6C0, 0x80EC, 0xE6C1, 0x5AAA, 0xE6C2, 0x5A9B, 0xE6C3, 0x5A77, 0xE6C4, 0x5A7A, 0xE6C5, 0x5ABE, 0xE6C6, 0x5AEB, 0xE6C7, 0x5AB2, 0xE6C8, 0x5AD2, 0xE6C9, 0x5AD4, 0xE6CA, 0x5AB8, 0xE6CB, 0x5AE0, 0xE6CC, 0x5AE3, 0xE6CD, 0x5AF1, 0xE6CE, 0x5AD6, 0xE6CF, 0x5AE6, 0xE6D0, 0x5AD8, 0xE6D1, 0x5ADC, 0xE6D2, 0x5B09, 0xE6D3, 0x5B17, 0xE6D4, 0x5B16, 0xE6D5, 0x5B32, 0xE6D6, 0x5B37, 0xE6D7, 0x5B40, 0xE6D8, 0x5C15, 0xE6D9, 0x5C1C, 0xE6DA, 0x5B5A, 0xE6DB, 0x5B65, 0xE6DC, 0x5B73, 0xE6DD, 0x5B51, 0xE6DE, 0x5B53, 0xE6DF, 0x5B62, 0xE6E0, 0x9A75, 0xE6E1, 0x9A77, 0xE6E2, 0x9A78, 0xE6E3, 0x9A7A, 0xE6E4, 0x9A7F, 0xE6E5, 0x9A7D, 0xE6E6, 0x9A80, 0xE6E7, 0x9A81, 0xE6E8, 0x9A85, 0xE6E9, 0x9A88, 0xE6EA, 0x9A8A, 0xE6EB, 0x9A90, 0xE6EC, 0x9A92, 0xE6ED, 0x9A93, 0xE6EE, 0x9A96, 0xE6EF, 0x9A98, 0xE6F0, 0x9A9B, 0xE6F1, 0x9A9C, 0xE6F2, 0x9A9D, 0xE6F3, 0x9A9F, 0xE6F4, 0x9AA0, 0xE6F5, 0x9AA2, 0xE6F6, 0x9AA3, 0xE6F7, 0x9AA5, 0xE6F8, 0x9AA7, 0xE6F9, 0x7E9F, 0xE6FA, 0x7EA1, 0xE6FB, 0x7EA3, 0xE6FC, 0x7EA5, 0xE6FD, 0x7EA8, 0xE6FE, 0x7EA9, 0xE740, 0x93CE, 0xE741, 0x93CF, 0xE742, 0x93D0, 0xE743, 0x93D1, 0xE744, 0x93D2, 0xE745, 0x93D3, 0xE746, 0x93D4, 0xE747, 0x93D5, 0xE748, 0x93D7, 0xE749, 0x93D8, 0xE74A, 0x93D9, 0xE74B, 0x93DA, 0xE74C, 0x93DB, 0xE74D, 0x93DC, 0xE74E, 0x93DD, 0xE74F, 0x93DE, 0xE750, 0x93DF, 0xE751, 0x93E0, 0xE752, 0x93E1, 0xE753, 0x93E2, 0xE754, 0x93E3, 0xE755, 0x93E4, 0xE756, 0x93E5, 0xE757, 0x93E6, 0xE758, 0x93E7, 0xE759, 0x93E8, 0xE75A, 0x93E9, 0xE75B, 0x93EA, 0xE75C, 0x93EB, 0xE75D, 0x93EC, 0xE75E, 0x93ED, 0xE75F, 0x93EE, 0xE760, 0x93EF, 0xE761, 0x93F0, 0xE762, 0x93F1, 0xE763, 0x93F2, 0xE764, 0x93F3, 0xE765, 0x93F4, 0xE766, 0x93F5, 0xE767, 0x93F6, 0xE768, 0x93F7, 0xE769, 0x93F8, 0xE76A, 0x93F9, 0xE76B, 0x93FA, 0xE76C, 0x93FB, 0xE76D, 0x93FC, 0xE76E, 0x93FD, 0xE76F, 0x93FE, 0xE770, 0x93FF, 0xE771, 0x9400, 0xE772, 0x9401, 0xE773, 0x9402, 0xE774, 0x9403, 0xE775, 0x9404, 0xE776, 0x9405, 0xE777, 0x9406, 0xE778, 0x9407, 0xE779, 0x9408, 0xE77A, 0x9409, 0xE77B, 0x940A, 0xE77C, 0x940B, 0xE77D, 0x940C, 0xE77E, 0x940D, 0xE780, 0x940E, 0xE781, 0x940F, 0xE782, 0x9410, 0xE783, 0x9411, 0xE784, 0x9412, 0xE785, 0x9413, 0xE786, 0x9414, 0xE787, 0x9415, 0xE788, 0x9416, 0xE789, 0x9417, 0xE78A, 0x9418, 0xE78B, 0x9419, 0xE78C, 0x941A, 0xE78D, 0x941B, 0xE78E, 0x941C, 0xE78F, 0x941D, 0xE790, 0x941E, 0xE791, 0x941F, 0xE792, 0x9420, 0xE793, 0x9421, 0xE794, 0x9422, 0xE795, 0x9423, 0xE796, 0x9424, 0xE797, 0x9425, 0xE798, 0x9426, 0xE799, 0x9427, 0xE79A, 0x9428, 0xE79B, 0x9429, 0xE79C, 0x942A, 0xE79D, 0x942B, 0xE79E, 0x942C, 0xE79F, 0x942D, 0xE7A0, 0x942E, 0xE7A1, 0x7EAD, 0xE7A2, 0x7EB0, 0xE7A3, 0x7EBE, 0xE7A4, 0x7EC0, 0xE7A5, 0x7EC1, 0xE7A6, 0x7EC2, 0xE7A7, 0x7EC9, 0xE7A8, 0x7ECB, 0xE7A9, 0x7ECC, 0xE7AA, 0x7ED0, 0xE7AB, 0x7ED4, 0xE7AC, 0x7ED7, 0xE7AD, 0x7EDB, 0xE7AE, 0x7EE0, 0xE7AF, 0x7EE1, 0xE7B0, 0x7EE8, 0xE7B1, 0x7EEB, 0xE7B2, 0x7EEE, 0xE7B3, 0x7EEF, 0xE7B4, 0x7EF1, 0xE7B5, 0x7EF2, 0xE7B6, 0x7F0D, 0xE7B7, 0x7EF6, 0xE7B8, 0x7EFA, 0xE7B9, 0x7EFB, 0xE7BA, 0x7EFE, 0xE7BB, 0x7F01, 0xE7BC, 0x7F02, 0xE7BD, 0x7F03, 0xE7BE, 0x7F07, 0xE7BF, 0x7F08, 0xE7C0, 0x7F0B, 0xE7C1, 0x7F0C, 0xE7C2, 0x7F0F, 0xE7C3, 0x7F11, 0xE7C4, 0x7F12, 0xE7C5, 0x7F17, 0xE7C6, 0x7F19, 0xE7C7, 0x7F1C, 0xE7C8, 0x7F1B, 0xE7C9, 0x7F1F, 0xE7CA, 0x7F21, 0xE7CB, 0x7F22, 0xE7CC, 0x7F23, 0xE7CD, 0x7F24, 0xE7CE, 0x7F25, 0xE7CF, 0x7F26, 0xE7D0, 0x7F27, 0xE7D1, 0x7F2A, 0xE7D2, 0x7F2B, 0xE7D3, 0x7F2C, 0xE7D4, 0x7F2D, 0xE7D5, 0x7F2F, 0xE7D6, 0x7F30, 0xE7D7, 0x7F31, 0xE7D8, 0x7F32, 0xE7D9, 0x7F33, 0xE7DA, 0x7F35, 0xE7DB, 0x5E7A, 0xE7DC, 0x757F, 0xE7DD, 0x5DDB, 0xE7DE, 0x753E, 0xE7DF, 0x9095, 0xE7E0, 0x738E, 0xE7E1, 0x7391, 0xE7E2, 0x73AE, 0xE7E3, 0x73A2, 0xE7E4, 0x739F, 0xE7E5, 0x73CF, 0xE7E6, 0x73C2, 0xE7E7, 0x73D1, 0xE7E8, 0x73B7, 0xE7E9, 0x73B3, 0xE7EA, 0x73C0, 0xE7EB, 0x73C9, 0xE7EC, 0x73C8, 0xE7ED, 0x73E5, 0xE7EE, 0x73D9, 0xE7EF, 0x987C, 0xE7F0, 0x740A, 0xE7F1, 0x73E9, 0xE7F2, 0x73E7, 0xE7F3, 0x73DE, 0xE7F4, 0x73BA, 0xE7F5, 0x73F2, 0xE7F6, 0x740F, 0xE7F7, 0x742A, 0xE7F8, 0x745B, 0xE7F9, 0x7426, 0xE7FA, 0x7425, 0xE7FB, 0x7428, 0xE7FC, 0x7430, 0xE7FD, 0x742E, 0xE7FE, 0x742C, 0xE840, 0x942F, 0xE841, 0x9430, 0xE842, 0x9431, 0xE843, 0x9432, 0xE844, 0x9433, 0xE845, 0x9434, 0xE846, 0x9435, 0xE847, 0x9436, 0xE848, 0x9437, 0xE849, 0x9438, 0xE84A, 0x9439, 0xE84B, 0x943A, 0xE84C, 0x943B, 0xE84D, 0x943C, 0xE84E, 0x943D, 0xE84F, 0x943F, 0xE850, 0x9440, 0xE851, 0x9441, 0xE852, 0x9442, 0xE853, 0x9443, 0xE854, 0x9444, 0xE855, 0x9445, 0xE856, 0x9446, 0xE857, 0x9447, 0xE858, 0x9448, 0xE859, 0x9449, 0xE85A, 0x944A, 0xE85B, 0x944B, 0xE85C, 0x944C, 0xE85D, 0x944D, 0xE85E, 0x944E, 0xE85F, 0x944F, 0xE860, 0x9450, 0xE861, 0x9451, 0xE862, 0x9452, 0xE863, 0x9453, 0xE864, 0x9454, 0xE865, 0x9455, 0xE866, 0x9456, 0xE867, 0x9457, 0xE868, 0x9458, 0xE869, 0x9459, 0xE86A, 0x945A, 0xE86B, 0x945B, 0xE86C, 0x945C, 0xE86D, 0x945D, 0xE86E, 0x945E, 0xE86F, 0x945F, 0xE870, 0x9460, 0xE871, 0x9461, 0xE872, 0x9462, 0xE873, 0x9463, 0xE874, 0x9464, 0xE875, 0x9465, 0xE876, 0x9466, 0xE877, 0x9467, 0xE878, 0x9468, 0xE879, 0x9469, 0xE87A, 0x946A, 0xE87B, 0x946C, 0xE87C, 0x946D, 0xE87D, 0x946E, 0xE87E, 0x946F, 0xE880, 0x9470, 0xE881, 0x9471, 0xE882, 0x9472, 0xE883, 0x9473, 0xE884, 0x9474, 0xE885, 0x9475, 0xE886, 0x9476, 0xE887, 0x9477, 0xE888, 0x9478, 0xE889, 0x9479, 0xE88A, 0x947A, 0xE88B, 0x947B, 0xE88C, 0x947C, 0xE88D, 0x947D, 0xE88E, 0x947E, 0xE88F, 0x947F, 0xE890, 0x9480, 0xE891, 0x9481, 0xE892, 0x9482, 0xE893, 0x9483, 0xE894, 0x9484, 0xE895, 0x9491, 0xE896, 0x9496, 0xE897, 0x9498, 0xE898, 0x94C7, 0xE899, 0x94CF, 0xE89A, 0x94D3, 0xE89B, 0x94D4, 0xE89C, 0x94DA, 0xE89D, 0x94E6, 0xE89E, 0x94FB, 0xE89F, 0x951C, 0xE8A0, 0x9520, 0xE8A1, 0x741B, 0xE8A2, 0x741A, 0xE8A3, 0x7441, 0xE8A4, 0x745C, 0xE8A5, 0x7457, 0xE8A6, 0x7455, 0xE8A7, 0x7459, 0xE8A8, 0x7477, 0xE8A9, 0x746D, 0xE8AA, 0x747E, 0xE8AB, 0x749C, 0xE8AC, 0x748E, 0xE8AD, 0x7480, 0xE8AE, 0x7481, 0xE8AF, 0x7487, 0xE8B0, 0x748B, 0xE8B1, 0x749E, 0xE8B2, 0x74A8, 0xE8B3, 0x74A9, 0xE8B4, 0x7490, 0xE8B5, 0x74A7, 0xE8B6, 0x74D2, 0xE8B7, 0x74BA, 0xE8B8, 0x97EA, 0xE8B9, 0x97EB, 0xE8BA, 0x97EC, 0xE8BB, 0x674C, 0xE8BC, 0x6753, 0xE8BD, 0x675E, 0xE8BE, 0x6748, 0xE8BF, 0x6769, 0xE8C0, 0x67A5, 0xE8C1, 0x6787, 0xE8C2, 0x676A, 0xE8C3, 0x6773, 0xE8C4, 0x6798, 0xE8C5, 0x67A7, 0xE8C6, 0x6775, 0xE8C7, 0x67A8, 0xE8C8, 0x679E, 0xE8C9, 0x67AD, 0xE8CA, 0x678B, 0xE8CB, 0x6777, 0xE8CC, 0x677C, 0xE8CD, 0x67F0, 0xE8CE, 0x6809, 0xE8CF, 0x67D8, 0xE8D0, 0x680A, 0xE8D1, 0x67E9, 0xE8D2, 0x67B0, 0xE8D3, 0x680C, 0xE8D4, 0x67D9, 0xE8D5, 0x67B5, 0xE8D6, 0x67DA, 0xE8D7, 0x67B3, 0xE8D8, 0x67DD, 0xE8D9, 0x6800, 0xE8DA, 0x67C3, 0xE8DB, 0x67B8, 0xE8DC, 0x67E2, 0xE8DD, 0x680E, 0xE8DE, 0x67C1, 0xE8DF, 0x67FD, 0xE8E0, 0x6832, 0xE8E1, 0x6833, 0xE8E2, 0x6860, 0xE8E3, 0x6861, 0xE8E4, 0x684E, 0xE8E5, 0x6862, 0xE8E6, 0x6844, 0xE8E7, 0x6864, 0xE8E8, 0x6883, 0xE8E9, 0x681D, 0xE8EA, 0x6855, 0xE8EB, 0x6866, 0xE8EC, 0x6841, 0xE8ED, 0x6867, 0xE8EE, 0x6840, 0xE8EF, 0x683E, 0xE8F0, 0x684A, 0xE8F1, 0x6849, 0xE8F2, 0x6829, 0xE8F3, 0x68B5, 0xE8F4, 0x688F, 0xE8F5, 0x6874, 0xE8F6, 0x6877, 0xE8F7, 0x6893, 0xE8F8, 0x686B, 0xE8F9, 0x68C2, 0xE8FA, 0x696E, 0xE8FB, 0x68FC, 0xE8FC, 0x691F, 0xE8FD, 0x6920, 0xE8FE, 0x68F9, 0xE940, 0x9527, 0xE941, 0x9533, 0xE942, 0x953D, 0xE943, 0x9543, 0xE944, 0x9548, 0xE945, 0x954B, 0xE946, 0x9555, 0xE947, 0x955A, 0xE948, 0x9560, 0xE949, 0x956E, 0xE94A, 0x9574, 0xE94B, 0x9575, 0xE94C, 0x9577, 0xE94D, 0x9578, 0xE94E, 0x9579, 0xE94F, 0x957A, 0xE950, 0x957B, 0xE951, 0x957C, 0xE952, 0x957D, 0xE953, 0x957E, 0xE954, 0x9580, 0xE955, 0x9581, 0xE956, 0x9582, 0xE957, 0x9583, 0xE958, 0x9584, 0xE959, 0x9585, 0xE95A, 0x9586, 0xE95B, 0x9587, 0xE95C, 0x9588, 0xE95D, 0x9589, 0xE95E, 0x958A, 0xE95F, 0x958B, 0xE960, 0x958C, 0xE961, 0x958D, 0xE962, 0x958E, 0xE963, 0x958F, 0xE964, 0x9590, 0xE965, 0x9591, 0xE966, 0x9592, 0xE967, 0x9593, 0xE968, 0x9594, 0xE969, 0x9595, 0xE96A, 0x9596, 0xE96B, 0x9597, 0xE96C, 0x9598, 0xE96D, 0x9599, 0xE96E, 0x959A, 0xE96F, 0x959B, 0xE970, 0x959C, 0xE971, 0x959D, 0xE972, 0x959E, 0xE973, 0x959F, 0xE974, 0x95A0, 0xE975, 0x95A1, 0xE976, 0x95A2, 0xE977, 0x95A3, 0xE978, 0x95A4, 0xE979, 0x95A5, 0xE97A, 0x95A6, 0xE97B, 0x95A7, 0xE97C, 0x95A8, 0xE97D, 0x95A9, 0xE97E, 0x95AA, 0xE980, 0x95AB, 0xE981, 0x95AC, 0xE982, 0x95AD, 0xE983, 0x95AE, 0xE984, 0x95AF, 0xE985, 0x95B0, 0xE986, 0x95B1, 0xE987, 0x95B2, 0xE988, 0x95B3, 0xE989, 0x95B4, 0xE98A, 0x95B5, 0xE98B, 0x95B6, 0xE98C, 0x95B7, 0xE98D, 0x95B8, 0xE98E, 0x95B9, 0xE98F, 0x95BA, 0xE990, 0x95BB, 0xE991, 0x95BC, 0xE992, 0x95BD, 0xE993, 0x95BE, 0xE994, 0x95BF, 0xE995, 0x95C0, 0xE996, 0x95C1, 0xE997, 0x95C2, 0xE998, 0x95C3, 0xE999, 0x95C4, 0xE99A, 0x95C5, 0xE99B, 0x95C6, 0xE99C, 0x95C7, 0xE99D, 0x95C8, 0xE99E, 0x95C9, 0xE99F, 0x95CA, 0xE9A0, 0x95CB, 0xE9A1, 0x6924, 0xE9A2, 0x68F0, 0xE9A3, 0x690B, 0xE9A4, 0x6901, 0xE9A5, 0x6957, 0xE9A6, 0x68E3, 0xE9A7, 0x6910, 0xE9A8, 0x6971, 0xE9A9, 0x6939, 0xE9AA, 0x6960, 0xE9AB, 0x6942, 0xE9AC, 0x695D, 0xE9AD, 0x6984, 0xE9AE, 0x696B, 0xE9AF, 0x6980, 0xE9B0, 0x6998, 0xE9B1, 0x6978, 0xE9B2, 0x6934, 0xE9B3, 0x69CC, 0xE9B4, 0x6987, 0xE9B5, 0x6988, 0xE9B6, 0x69CE, 0xE9B7, 0x6989, 0xE9B8, 0x6966, 0xE9B9, 0x6963, 0xE9BA, 0x6979, 0xE9BB, 0x699B, 0xE9BC, 0x69A7, 0xE9BD, 0x69BB, 0xE9BE, 0x69AB, 0xE9BF, 0x69AD, 0xE9C0, 0x69D4, 0xE9C1, 0x69B1, 0xE9C2, 0x69C1, 0xE9C3, 0x69CA, 0xE9C4, 0x69DF, 0xE9C5, 0x6995, 0xE9C6, 0x69E0, 0xE9C7, 0x698D, 0xE9C8, 0x69FF, 0xE9C9, 0x6A2F, 0xE9CA, 0x69ED, 0xE9CB, 0x6A17, 0xE9CC, 0x6A18, 0xE9CD, 0x6A65, 0xE9CE, 0x69F2, 0xE9CF, 0x6A44, 0xE9D0, 0x6A3E, 0xE9D1, 0x6AA0, 0xE9D2, 0x6A50, 0xE9D3, 0x6A5B, 0xE9D4, 0x6A35, 0xE9D5, 0x6A8E, 0xE9D6, 0x6A79, 0xE9D7, 0x6A3D, 0xE9D8, 0x6A28, 0xE9D9, 0x6A58, 0xE9DA, 0x6A7C, 0xE9DB, 0x6A91, 0xE9DC, 0x6A90, 0xE9DD, 0x6AA9, 0xE9DE, 0x6A97, 0xE9DF, 0x6AAB, 0xE9E0, 0x7337, 0xE9E1, 0x7352, 0xE9E2, 0x6B81, 0xE9E3, 0x6B82, 0xE9E4, 0x6B87, 0xE9E5, 0x6B84, 0xE9E6, 0x6B92, 0xE9E7, 0x6B93, 0xE9E8, 0x6B8D, 0xE9E9, 0x6B9A, 0xE9EA, 0x6B9B, 0xE9EB, 0x6BA1, 0xE9EC, 0x6BAA, 0xE9ED, 0x8F6B, 0xE9EE, 0x8F6D, 0xE9EF, 0x8F71, 0xE9F0, 0x8F72, 0xE9F1, 0x8F73, 0xE9F2, 0x8F75, 0xE9F3, 0x8F76, 0xE9F4, 0x8F78, 0xE9F5, 0x8F77, 0xE9F6, 0x8F79, 0xE9F7, 0x8F7A, 0xE9F8, 0x8F7C, 0xE9F9, 0x8F7E, 0xE9FA, 0x8F81, 0xE9FB, 0x8F82, 0xE9FC, 0x8F84, 0xE9FD, 0x8F87, 0xE9FE, 0x8F8B, 0xEA40, 0x95CC, 0xEA41, 0x95CD, 0xEA42, 0x95CE, 0xEA43, 0x95CF, 0xEA44, 0x95D0, 0xEA45, 0x95D1, 0xEA46, 0x95D2, 0xEA47, 0x95D3, 0xEA48, 0x95D4, 0xEA49, 0x95D5, 0xEA4A, 0x95D6, 0xEA4B, 0x95D7, 0xEA4C, 0x95D8, 0xEA4D, 0x95D9, 0xEA4E, 0x95DA, 0xEA4F, 0x95DB, 0xEA50, 0x95DC, 0xEA51, 0x95DD, 0xEA52, 0x95DE, 0xEA53, 0x95DF, 0xEA54, 0x95E0, 0xEA55, 0x95E1, 0xEA56, 0x95E2, 0xEA57, 0x95E3, 0xEA58, 0x95E4, 0xEA59, 0x95E5, 0xEA5A, 0x95E6, 0xEA5B, 0x95E7, 0xEA5C, 0x95EC, 0xEA5D, 0x95FF, 0xEA5E, 0x9607, 0xEA5F, 0x9613, 0xEA60, 0x9618, 0xEA61, 0x961B, 0xEA62, 0x961E, 0xEA63, 0x9620, 0xEA64, 0x9623, 0xEA65, 0x9624, 0xEA66, 0x9625, 0xEA67, 0x9626, 0xEA68, 0x9627, 0xEA69, 0x9628, 0xEA6A, 0x9629, 0xEA6B, 0x962B, 0xEA6C, 0x962C, 0xEA6D, 0x962D, 0xEA6E, 0x962F, 0xEA6F, 0x9630, 0xEA70, 0x9637, 0xEA71, 0x9638, 0xEA72, 0x9639, 0xEA73, 0x963A, 0xEA74, 0x963E, 0xEA75, 0x9641, 0xEA76, 0x9643, 0xEA77, 0x964A, 0xEA78, 0x964E, 0xEA79, 0x964F, 0xEA7A, 0x9651, 0xEA7B, 0x9652, 0xEA7C, 0x9653, 0xEA7D, 0x9656, 0xEA7E, 0x9657, 0xEA80, 0x9658, 0xEA81, 0x9659, 0xEA82, 0x965A, 0xEA83, 0x965C, 0xEA84, 0x965D, 0xEA85, 0x965E, 0xEA86, 0x9660, 0xEA87, 0x9663, 0xEA88, 0x9665, 0xEA89, 0x9666, 0xEA8A, 0x966B, 0xEA8B, 0x966D, 0xEA8C, 0x966E, 0xEA8D, 0x966F, 0xEA8E, 0x9670, 0xEA8F, 0x9671, 0xEA90, 0x9673, 0xEA91, 0x9678, 0xEA92, 0x9679, 0xEA93, 0x967A, 0xEA94, 0x967B, 0xEA95, 0x967C, 0xEA96, 0x967D, 0xEA97, 0x967E, 0xEA98, 0x967F, 0xEA99, 0x9680, 0xEA9A, 0x9681, 0xEA9B, 0x9682, 0xEA9C, 0x9683, 0xEA9D, 0x9684, 0xEA9E, 0x9687, 0xEA9F, 0x9689, 0xEAA0, 0x968A, 0xEAA1, 0x8F8D, 0xEAA2, 0x8F8E, 0xEAA3, 0x8F8F, 0xEAA4, 0x8F98, 0xEAA5, 0x8F9A, 0xEAA6, 0x8ECE, 0xEAA7, 0x620B, 0xEAA8, 0x6217, 0xEAA9, 0x621B, 0xEAAA, 0x621F, 0xEAAB, 0x6222, 0xEAAC, 0x6221, 0xEAAD, 0x6225, 0xEAAE, 0x6224, 0xEAAF, 0x622C, 0xEAB0, 0x81E7, 0xEAB1, 0x74EF, 0xEAB2, 0x74F4, 0xEAB3, 0x74FF, 0xEAB4, 0x750F, 0xEAB5, 0x7511, 0xEAB6, 0x7513, 0xEAB7, 0x6534, 0xEAB8, 0x65EE, 0xEAB9, 0x65EF, 0xEABA, 0x65F0, 0xEABB, 0x660A, 0xEABC, 0x6619, 0xEABD, 0x6772, 0xEABE, 0x6603, 0xEABF, 0x6615, 0xEAC0, 0x6600, 0xEAC1, 0x7085, 0xEAC2, 0x66F7, 0xEAC3, 0x661D, 0xEAC4, 0x6634, 0xEAC5, 0x6631, 0xEAC6, 0x6636, 0xEAC7, 0x6635, 0xEAC8, 0x8006, 0xEAC9, 0x665F, 0xEACA, 0x6654, 0xEACB, 0x6641, 0xEACC, 0x664F, 0xEACD, 0x6656, 0xEACE, 0x6661, 0xEACF, 0x6657, 0xEAD0, 0x6677, 0xEAD1, 0x6684, 0xEAD2, 0x668C, 0xEAD3, 0x66A7, 0xEAD4, 0x669D, 0xEAD5, 0x66BE, 0xEAD6, 0x66DB, 0xEAD7, 0x66DC, 0xEAD8, 0x66E6, 0xEAD9, 0x66E9, 0xEADA, 0x8D32, 0xEADB, 0x8D33, 0xEADC, 0x8D36, 0xEADD, 0x8D3B, 0xEADE, 0x8D3D, 0xEADF, 0x8D40, 0xEAE0, 0x8D45, 0xEAE1, 0x8D46, 0xEAE2, 0x8D48, 0xEAE3, 0x8D49, 0xEAE4, 0x8D47, 0xEAE5, 0x8D4D, 0xEAE6, 0x8D55, 0xEAE7, 0x8D59, 0xEAE8, 0x89C7, 0xEAE9, 0x89CA, 0xEAEA, 0x89CB, 0xEAEB, 0x89CC, 0xEAEC, 0x89CE, 0xEAED, 0x89CF, 0xEAEE, 0x89D0, 0xEAEF, 0x89D1, 0xEAF0, 0x726E, 0xEAF1, 0x729F, 0xEAF2, 0x725D, 0xEAF3, 0x7266, 0xEAF4, 0x726F, 0xEAF5, 0x727E, 0xEAF6, 0x727F, 0xEAF7, 0x7284, 0xEAF8, 0x728B, 0xEAF9, 0x728D, 0xEAFA, 0x728F, 0xEAFB, 0x7292, 0xEAFC, 0x6308, 0xEAFD, 0x6332, 0xEAFE, 0x63B0, 0xEB40, 0x968C, 0xEB41, 0x968E, 0xEB42, 0x9691, 0xEB43, 0x9692, 0xEB44, 0x9693, 0xEB45, 0x9695, 0xEB46, 0x9696, 0xEB47, 0x969A, 0xEB48, 0x969B, 0xEB49, 0x969D, 0xEB4A, 0x969E, 0xEB4B, 0x969F, 0xEB4C, 0x96A0, 0xEB4D, 0x96A1, 0xEB4E, 0x96A2, 0xEB4F, 0x96A3, 0xEB50, 0x96A4, 0xEB51, 0x96A5, 0xEB52, 0x96A6, 0xEB53, 0x96A8, 0xEB54, 0x96A9, 0xEB55, 0x96AA, 0xEB56, 0x96AB, 0xEB57, 0x96AC, 0xEB58, 0x96AD, 0xEB59, 0x96AE, 0xEB5A, 0x96AF, 0xEB5B, 0x96B1, 0xEB5C, 0x96B2, 0xEB5D, 0x96B4, 0xEB5E, 0x96B5, 0xEB5F, 0x96B7, 0xEB60, 0x96B8, 0xEB61, 0x96BA, 0xEB62, 0x96BB, 0xEB63, 0x96BF, 0xEB64, 0x96C2, 0xEB65, 0x96C3, 0xEB66, 0x96C8, 0xEB67, 0x96CA, 0xEB68, 0x96CB, 0xEB69, 0x96D0, 0xEB6A, 0x96D1, 0xEB6B, 0x96D3, 0xEB6C, 0x96D4, 0xEB6D, 0x96D6, 0xEB6E, 0x96D7, 0xEB6F, 0x96D8, 0xEB70, 0x96D9, 0xEB71, 0x96DA, 0xEB72, 0x96DB, 0xEB73, 0x96DC, 0xEB74, 0x96DD, 0xEB75, 0x96DE, 0xEB76, 0x96DF, 0xEB77, 0x96E1, 0xEB78, 0x96E2, 0xEB79, 0x96E3, 0xEB7A, 0x96E4, 0xEB7B, 0x96E5, 0xEB7C, 0x96E6, 0xEB7D, 0x96E7, 0xEB7E, 0x96EB, 0xEB80, 0x96EC, 0xEB81, 0x96ED, 0xEB82, 0x96EE, 0xEB83, 0x96F0, 0xEB84, 0x96F1, 0xEB85, 0x96F2, 0xEB86, 0x96F4, 0xEB87, 0x96F5, 0xEB88, 0x96F8, 0xEB89, 0x96FA, 0xEB8A, 0x96FB, 0xEB8B, 0x96FC, 0xEB8C, 0x96FD, 0xEB8D, 0x96FF, 0xEB8E, 0x9702, 0xEB8F, 0x9703, 0xEB90, 0x9705, 0xEB91, 0x970A, 0xEB92, 0x970B, 0xEB93, 0x970C, 0xEB94, 0x9710, 0xEB95, 0x9711, 0xEB96, 0x9712, 0xEB97, 0x9714, 0xEB98, 0x9715, 0xEB99, 0x9717, 0xEB9A, 0x9718, 0xEB9B, 0x9719, 0xEB9C, 0x971A, 0xEB9D, 0x971B, 0xEB9E, 0x971D, 0xEB9F, 0x971F, 0xEBA0, 0x9720, 0xEBA1, 0x643F, 0xEBA2, 0x64D8, 0xEBA3, 0x8004, 0xEBA4, 0x6BEA, 0xEBA5, 0x6BF3, 0xEBA6, 0x6BFD, 0xEBA7, 0x6BF5, 0xEBA8, 0x6BF9, 0xEBA9, 0x6C05, 0xEBAA, 0x6C07, 0xEBAB, 0x6C06, 0xEBAC, 0x6C0D, 0xEBAD, 0x6C15, 0xEBAE, 0x6C18, 0xEBAF, 0x6C19, 0xEBB0, 0x6C1A, 0xEBB1, 0x6C21, 0xEBB2, 0x6C29, 0xEBB3, 0x6C24, 0xEBB4, 0x6C2A, 0xEBB5, 0x6C32, 0xEBB6, 0x6535, 0xEBB7, 0x6555, 0xEBB8, 0x656B, 0xEBB9, 0x724D, 0xEBBA, 0x7252, 0xEBBB, 0x7256, 0xEBBC, 0x7230, 0xEBBD, 0x8662, 0xEBBE, 0x5216, 0xEBBF, 0x809F, 0xEBC0, 0x809C, 0xEBC1, 0x8093, 0xEBC2, 0x80BC, 0xEBC3, 0x670A, 0xEBC4, 0x80BD, 0xEBC5, 0x80B1, 0xEBC6, 0x80AB, 0xEBC7, 0x80AD, 0xEBC8, 0x80B4, 0xEBC9, 0x80B7, 0xEBCA, 0x80E7, 0xEBCB, 0x80E8, 0xEBCC, 0x80E9, 0xEBCD, 0x80EA, 0xEBCE, 0x80DB, 0xEBCF, 0x80C2, 0xEBD0, 0x80C4, 0xEBD1, 0x80D9, 0xEBD2, 0x80CD, 0xEBD3, 0x80D7, 0xEBD4, 0x6710, 0xEBD5, 0x80DD, 0xEBD6, 0x80EB, 0xEBD7, 0x80F1, 0xEBD8, 0x80F4, 0xEBD9, 0x80ED, 0xEBDA, 0x810D, 0xEBDB, 0x810E, 0xEBDC, 0x80F2, 0xEBDD, 0x80FC, 0xEBDE, 0x6715, 0xEBDF, 0x8112, 0xEBE0, 0x8C5A, 0xEBE1, 0x8136, 0xEBE2, 0x811E, 0xEBE3, 0x812C, 0xEBE4, 0x8118, 0xEBE5, 0x8132, 0xEBE6, 0x8148, 0xEBE7, 0x814C, 0xEBE8, 0x8153, 0xEBE9, 0x8174, 0xEBEA, 0x8159, 0xEBEB, 0x815A, 0xEBEC, 0x8171, 0xEBED, 0x8160, 0xEBEE, 0x8169, 0xEBEF, 0x817C, 0xEBF0, 0x817D, 0xEBF1, 0x816D, 0xEBF2, 0x8167, 0xEBF3, 0x584D, 0xEBF4, 0x5AB5, 0xEBF5, 0x8188, 0xEBF6, 0x8182, 0xEBF7, 0x8191, 0xEBF8, 0x6ED5, 0xEBF9, 0x81A3, 0xEBFA, 0x81AA, 0xEBFB, 0x81CC, 0xEBFC, 0x6726, 0xEBFD, 0x81CA, 0xEBFE, 0x81BB, 0xEC40, 0x9721, 0xEC41, 0x9722, 0xEC42, 0x9723, 0xEC43, 0x9724, 0xEC44, 0x9725, 0xEC45, 0x9726, 0xEC46, 0x9727, 0xEC47, 0x9728, 0xEC48, 0x9729, 0xEC49, 0x972B, 0xEC4A, 0x972C, 0xEC4B, 0x972E, 0xEC4C, 0x972F, 0xEC4D, 0x9731, 0xEC4E, 0x9733, 0xEC4F, 0x9734, 0xEC50, 0x9735, 0xEC51, 0x9736, 0xEC52, 0x9737, 0xEC53, 0x973A, 0xEC54, 0x973B, 0xEC55, 0x973C, 0xEC56, 0x973D, 0xEC57, 0x973F, 0xEC58, 0x9740, 0xEC59, 0x9741, 0xEC5A, 0x9742, 0xEC5B, 0x9743, 0xEC5C, 0x9744, 0xEC5D, 0x9745, 0xEC5E, 0x9746, 0xEC5F, 0x9747, 0xEC60, 0x9748, 0xEC61, 0x9749, 0xEC62, 0x974A, 0xEC63, 0x974B, 0xEC64, 0x974C, 0xEC65, 0x974D, 0xEC66, 0x974E, 0xEC67, 0x974F, 0xEC68, 0x9750, 0xEC69, 0x9751, 0xEC6A, 0x9754, 0xEC6B, 0x9755, 0xEC6C, 0x9757, 0xEC6D, 0x9758, 0xEC6E, 0x975A, 0xEC6F, 0x975C, 0xEC70, 0x975D, 0xEC71, 0x975F, 0xEC72, 0x9763, 0xEC73, 0x9764, 0xEC74, 0x9766, 0xEC75, 0x9767, 0xEC76, 0x9768, 0xEC77, 0x976A, 0xEC78, 0x976B, 0xEC79, 0x976C, 0xEC7A, 0x976D, 0xEC7B, 0x976E, 0xEC7C, 0x976F, 0xEC7D, 0x9770, 0xEC7E, 0x9771, 0xEC80, 0x9772, 0xEC81, 0x9775, 0xEC82, 0x9777, 0xEC83, 0x9778, 0xEC84, 0x9779, 0xEC85, 0x977A, 0xEC86, 0x977B, 0xEC87, 0x977D, 0xEC88, 0x977E, 0xEC89, 0x977F, 0xEC8A, 0x9780, 0xEC8B, 0x9781, 0xEC8C, 0x9782, 0xEC8D, 0x9783, 0xEC8E, 0x9784, 0xEC8F, 0x9786, 0xEC90, 0x9787, 0xEC91, 0x9788, 0xEC92, 0x9789, 0xEC93, 0x978A, 0xEC94, 0x978C, 0xEC95, 0x978E, 0xEC96, 0x978F, 0xEC97, 0x9790, 0xEC98, 0x9793, 0xEC99, 0x9795, 0xEC9A, 0x9796, 0xEC9B, 0x9797, 0xEC9C, 0x9799, 0xEC9D, 0x979A, 0xEC9E, 0x979B, 0xEC9F, 0x979C, 0xECA0, 0x979D, 0xECA1, 0x81C1, 0xECA2, 0x81A6, 0xECA3, 0x6B24, 0xECA4, 0x6B37, 0xECA5, 0x6B39, 0xECA6, 0x6B43, 0xECA7, 0x6B46, 0xECA8, 0x6B59, 0xECA9, 0x98D1, 0xECAA, 0x98D2, 0xECAB, 0x98D3, 0xECAC, 0x98D5, 0xECAD, 0x98D9, 0xECAE, 0x98DA, 0xECAF, 0x6BB3, 0xECB0, 0x5F40, 0xECB1, 0x6BC2, 0xECB2, 0x89F3, 0xECB3, 0x6590, 0xECB4, 0x9F51, 0xECB5, 0x6593, 0xECB6, 0x65BC, 0xECB7, 0x65C6, 0xECB8, 0x65C4, 0xECB9, 0x65C3, 0xECBA, 0x65CC, 0xECBB, 0x65CE, 0xECBC, 0x65D2, 0xECBD, 0x65D6, 0xECBE, 0x7080, 0xECBF, 0x709C, 0xECC0, 0x7096, 0xECC1, 0x709D, 0xECC2, 0x70BB, 0xECC3, 0x70C0, 0xECC4, 0x70B7, 0xECC5, 0x70AB, 0xECC6, 0x70B1, 0xECC7, 0x70E8, 0xECC8, 0x70CA, 0xECC9, 0x7110, 0xECCA, 0x7113, 0xECCB, 0x7116, 0xECCC, 0x712F, 0xECCD, 0x7131, 0xECCE, 0x7173, 0xECCF, 0x715C, 0xECD0, 0x7168, 0xECD1, 0x7145, 0xECD2, 0x7172, 0xECD3, 0x714A, 0xECD4, 0x7178, 0xECD5, 0x717A, 0xECD6, 0x7198, 0xECD7, 0x71B3, 0xECD8, 0x71B5, 0xECD9, 0x71A8, 0xECDA, 0x71A0, 0xECDB, 0x71E0, 0xECDC, 0x71D4, 0xECDD, 0x71E7, 0xECDE, 0x71F9, 0xECDF, 0x721D, 0xECE0, 0x7228, 0xECE1, 0x706C, 0xECE2, 0x7118, 0xECE3, 0x7166, 0xECE4, 0x71B9, 0xECE5, 0x623E, 0xECE6, 0x623D, 0xECE7, 0x6243, 0xECE8, 0x6248, 0xECE9, 0x6249, 0xECEA, 0x793B, 0xECEB, 0x7940, 0xECEC, 0x7946, 0xECED, 0x7949, 0xECEE, 0x795B, 0xECEF, 0x795C, 0xECF0, 0x7953, 0xECF1, 0x795A, 0xECF2, 0x7962, 0xECF3, 0x7957, 0xECF4, 0x7960, 0xECF5, 0x796F, 0xECF6, 0x7967, 0xECF7, 0x797A, 0xECF8, 0x7985, 0xECF9, 0x798A, 0xECFA, 0x799A, 0xECFB, 0x79A7, 0xECFC, 0x79B3, 0xECFD, 0x5FD1, 0xECFE, 0x5FD0, 0xED40, 0x979E, 0xED41, 0x979F, 0xED42, 0x97A1, 0xED43, 0x97A2, 0xED44, 0x97A4, 0xED45, 0x97A5, 0xED46, 0x97A6, 0xED47, 0x97A7, 0xED48, 0x97A8, 0xED49, 0x97A9, 0xED4A, 0x97AA, 0xED4B, 0x97AC, 0xED4C, 0x97AE, 0xED4D, 0x97B0, 0xED4E, 0x97B1, 0xED4F, 0x97B3, 0xED50, 0x97B5, 0xED51, 0x97B6, 0xED52, 0x97B7, 0xED53, 0x97B8, 0xED54, 0x97B9, 0xED55, 0x97BA, 0xED56, 0x97BB, 0xED57, 0x97BC, 0xED58, 0x97BD, 0xED59, 0x97BE, 0xED5A, 0x97BF, 0xED5B, 0x97C0, 0xED5C, 0x97C1, 0xED5D, 0x97C2, 0xED5E, 0x97C3, 0xED5F, 0x97C4, 0xED60, 0x97C5, 0xED61, 0x97C6, 0xED62, 0x97C7, 0xED63, 0x97C8, 0xED64, 0x97C9, 0xED65, 0x97CA, 0xED66, 0x97CB, 0xED67, 0x97CC, 0xED68, 0x97CD, 0xED69, 0x97CE, 0xED6A, 0x97CF, 0xED6B, 0x97D0, 0xED6C, 0x97D1, 0xED6D, 0x97D2, 0xED6E, 0x97D3, 0xED6F, 0x97D4, 0xED70, 0x97D5, 0xED71, 0x97D6, 0xED72, 0x97D7, 0xED73, 0x97D8, 0xED74, 0x97D9, 0xED75, 0x97DA, 0xED76, 0x97DB, 0xED77, 0x97DC, 0xED78, 0x97DD, 0xED79, 0x97DE, 0xED7A, 0x97DF, 0xED7B, 0x97E0, 0xED7C, 0x97E1, 0xED7D, 0x97E2, 0xED7E, 0x97E3, 0xED80, 0x97E4, 0xED81, 0x97E5, 0xED82, 0x97E8, 0xED83, 0x97EE, 0xED84, 0x97EF, 0xED85, 0x97F0, 0xED86, 0x97F1, 0xED87, 0x97F2, 0xED88, 0x97F4, 0xED89, 0x97F7, 0xED8A, 0x97F8, 0xED8B, 0x97F9, 0xED8C, 0x97FA, 0xED8D, 0x97FB, 0xED8E, 0x97FC, 0xED8F, 0x97FD, 0xED90, 0x97FE, 0xED91, 0x97FF, 0xED92, 0x9800, 0xED93, 0x9801, 0xED94, 0x9802, 0xED95, 0x9803, 0xED96, 0x9804, 0xED97, 0x9805, 0xED98, 0x9806, 0xED99, 0x9807, 0xED9A, 0x9808, 0xED9B, 0x9809, 0xED9C, 0x980A, 0xED9D, 0x980B, 0xED9E, 0x980C, 0xED9F, 0x980D, 0xEDA0, 0x980E, 0xEDA1, 0x603C, 0xEDA2, 0x605D, 0xEDA3, 0x605A, 0xEDA4, 0x6067, 0xEDA5, 0x6041, 0xEDA6, 0x6059, 0xEDA7, 0x6063, 0xEDA8, 0x60AB, 0xEDA9, 0x6106, 0xEDAA, 0x610D, 0xEDAB, 0x615D, 0xEDAC, 0x61A9, 0xEDAD, 0x619D, 0xEDAE, 0x61CB, 0xEDAF, 0x61D1, 0xEDB0, 0x6206, 0xEDB1, 0x8080, 0xEDB2, 0x807F, 0xEDB3, 0x6C93, 0xEDB4, 0x6CF6, 0xEDB5, 0x6DFC, 0xEDB6, 0x77F6, 0xEDB7, 0x77F8, 0xEDB8, 0x7800, 0xEDB9, 0x7809, 0xEDBA, 0x7817, 0xEDBB, 0x7818, 0xEDBC, 0x7811, 0xEDBD, 0x65AB, 0xEDBE, 0x782D, 0xEDBF, 0x781C, 0xEDC0, 0x781D, 0xEDC1, 0x7839, 0xEDC2, 0x783A, 0xEDC3, 0x783B, 0xEDC4, 0x781F, 0xEDC5, 0x783C, 0xEDC6, 0x7825, 0xEDC7, 0x782C, 0xEDC8, 0x7823, 0xEDC9, 0x7829, 0xEDCA, 0x784E, 0xEDCB, 0x786D, 0xEDCC, 0x7856, 0xEDCD, 0x7857, 0xEDCE, 0x7826, 0xEDCF, 0x7850, 0xEDD0, 0x7847, 0xEDD1, 0x784C, 0xEDD2, 0x786A, 0xEDD3, 0x789B, 0xEDD4, 0x7893, 0xEDD5, 0x789A, 0xEDD6, 0x7887, 0xEDD7, 0x789C, 0xEDD8, 0x78A1, 0xEDD9, 0x78A3, 0xEDDA, 0x78B2, 0xEDDB, 0x78B9, 0xEDDC, 0x78A5, 0xEDDD, 0x78D4, 0xEDDE, 0x78D9, 0xEDDF, 0x78C9, 0xEDE0, 0x78EC, 0xEDE1, 0x78F2, 0xEDE2, 0x7905, 0xEDE3, 0x78F4, 0xEDE4, 0x7913, 0xEDE5, 0x7924, 0xEDE6, 0x791E, 0xEDE7, 0x7934, 0xEDE8, 0x9F9B, 0xEDE9, 0x9EF9, 0xEDEA, 0x9EFB, 0xEDEB, 0x9EFC, 0xEDEC, 0x76F1, 0xEDED, 0x7704, 0xEDEE, 0x770D, 0xEDEF, 0x76F9, 0xEDF0, 0x7707, 0xEDF1, 0x7708, 0xEDF2, 0x771A, 0xEDF3, 0x7722, 0xEDF4, 0x7719, 0xEDF5, 0x772D, 0xEDF6, 0x7726, 0xEDF7, 0x7735, 0xEDF8, 0x7738, 0xEDF9, 0x7750, 0xEDFA, 0x7751, 0xEDFB, 0x7747, 0xEDFC, 0x7743, 0xEDFD, 0x775A, 0xEDFE, 0x7768, 0xEE40, 0x980F, 0xEE41, 0x9810, 0xEE42, 0x9811, 0xEE43, 0x9812, 0xEE44, 0x9813, 0xEE45, 0x9814, 0xEE46, 0x9815, 0xEE47, 0x9816, 0xEE48, 0x9817, 0xEE49, 0x9818, 0xEE4A, 0x9819, 0xEE4B, 0x981A, 0xEE4C, 0x981B, 0xEE4D, 0x981C, 0xEE4E, 0x981D, 0xEE4F, 0x981E, 0xEE50, 0x981F, 0xEE51, 0x9820, 0xEE52, 0x9821, 0xEE53, 0x9822, 0xEE54, 0x9823, 0xEE55, 0x9824, 0xEE56, 0x9825, 0xEE57, 0x9826, 0xEE58, 0x9827, 0xEE59, 0x9828, 0xEE5A, 0x9829, 0xEE5B, 0x982A, 0xEE5C, 0x982B, 0xEE5D, 0x982C, 0xEE5E, 0x982D, 0xEE5F, 0x982E, 0xEE60, 0x982F, 0xEE61, 0x9830, 0xEE62, 0x9831, 0xEE63, 0x9832, 0xEE64, 0x9833, 0xEE65, 0x9834, 0xEE66, 0x9835, 0xEE67, 0x9836, 0xEE68, 0x9837, 0xEE69, 0x9838, 0xEE6A, 0x9839, 0xEE6B, 0x983A, 0xEE6C, 0x983B, 0xEE6D, 0x983C, 0xEE6E, 0x983D, 0xEE6F, 0x983E, 0xEE70, 0x983F, 0xEE71, 0x9840, 0xEE72, 0x9841, 0xEE73, 0x9842, 0xEE74, 0x9843, 0xEE75, 0x9844, 0xEE76, 0x9845, 0xEE77, 0x9846, 0xEE78, 0x9847, 0xEE79, 0x9848, 0xEE7A, 0x9849, 0xEE7B, 0x984A, 0xEE7C, 0x984B, 0xEE7D, 0x984C, 0xEE7E, 0x984D, 0xEE80, 0x984E, 0xEE81, 0x984F, 0xEE82, 0x9850, 0xEE83, 0x9851, 0xEE84, 0x9852, 0xEE85, 0x9853, 0xEE86, 0x9854, 0xEE87, 0x9855, 0xEE88, 0x9856, 0xEE89, 0x9857, 0xEE8A, 0x9858, 0xEE8B, 0x9859, 0xEE8C, 0x985A, 0xEE8D, 0x985B, 0xEE8E, 0x985C, 0xEE8F, 0x985D, 0xEE90, 0x985E, 0xEE91, 0x985F, 0xEE92, 0x9860, 0xEE93, 0x9861, 0xEE94, 0x9862, 0xEE95, 0x9863, 0xEE96, 0x9864, 0xEE97, 0x9865, 0xEE98, 0x9866, 0xEE99, 0x9867, 0xEE9A, 0x9868, 0xEE9B, 0x9869, 0xEE9C, 0x986A, 0xEE9D, 0x986B, 0xEE9E, 0x986C, 0xEE9F, 0x986D, 0xEEA0, 0x986E, 0xEEA1, 0x7762, 0xEEA2, 0x7765, 0xEEA3, 0x777F, 0xEEA4, 0x778D, 0xEEA5, 0x777D, 0xEEA6, 0x7780, 0xEEA7, 0x778C, 0xEEA8, 0x7791, 0xEEA9, 0x779F, 0xEEAA, 0x77A0, 0xEEAB, 0x77B0, 0xEEAC, 0x77B5, 0xEEAD, 0x77BD, 0xEEAE, 0x753A, 0xEEAF, 0x7540, 0xEEB0, 0x754E, 0xEEB1, 0x754B, 0xEEB2, 0x7548, 0xEEB3, 0x755B, 0xEEB4, 0x7572, 0xEEB5, 0x7579, 0xEEB6, 0x7583, 0xEEB7, 0x7F58, 0xEEB8, 0x7F61, 0xEEB9, 0x7F5F, 0xEEBA, 0x8A48, 0xEEBB, 0x7F68, 0xEEBC, 0x7F74, 0xEEBD, 0x7F71, 0xEEBE, 0x7F79, 0xEEBF, 0x7F81, 0xEEC0, 0x7F7E, 0xEEC1, 0x76CD, 0xEEC2, 0x76E5, 0xEEC3, 0x8832, 0xEEC4, 0x9485, 0xEEC5, 0x9486, 0xEEC6, 0x9487, 0xEEC7, 0x948B, 0xEEC8, 0x948A, 0xEEC9, 0x948C, 0xEECA, 0x948D, 0xEECB, 0x948F, 0xEECC, 0x9490, 0xEECD, 0x9494, 0xEECE, 0x9497, 0xEECF, 0x9495, 0xEED0, 0x949A, 0xEED1, 0x949B, 0xEED2, 0x949C, 0xEED3, 0x94A3, 0xEED4, 0x94A4, 0xEED5, 0x94AB, 0xEED6, 0x94AA, 0xEED7, 0x94AD, 0xEED8, 0x94AC, 0xEED9, 0x94AF, 0xEEDA, 0x94B0, 0xEEDB, 0x94B2, 0xEEDC, 0x94B4, 0xEEDD, 0x94B6, 0xEEDE, 0x94B7, 0xEEDF, 0x94B8, 0xEEE0, 0x94B9, 0xEEE1, 0x94BA, 0xEEE2, 0x94BC, 0xEEE3, 0x94BD, 0xEEE4, 0x94BF, 0xEEE5, 0x94C4, 0xEEE6, 0x94C8, 0xEEE7, 0x94C9, 0xEEE8, 0x94CA, 0xEEE9, 0x94CB, 0xEEEA, 0x94CC, 0xEEEB, 0x94CD, 0xEEEC, 0x94CE, 0xEEED, 0x94D0, 0xEEEE, 0x94D1, 0xEEEF, 0x94D2, 0xEEF0, 0x94D5, 0xEEF1, 0x94D6, 0xEEF2, 0x94D7, 0xEEF3, 0x94D9, 0xEEF4, 0x94D8, 0xEEF5, 0x94DB, 0xEEF6, 0x94DE, 0xEEF7, 0x94DF, 0xEEF8, 0x94E0, 0xEEF9, 0x94E2, 0xEEFA, 0x94E4, 0xEEFB, 0x94E5, 0xEEFC, 0x94E7, 0xEEFD, 0x94E8, 0xEEFE, 0x94EA, 0xEF40, 0x986F, 0xEF41, 0x9870, 0xEF42, 0x9871, 0xEF43, 0x9872, 0xEF44, 0x9873, 0xEF45, 0x9874, 0xEF46, 0x988B, 0xEF47, 0x988E, 0xEF48, 0x9892, 0xEF49, 0x9895, 0xEF4A, 0x9899, 0xEF4B, 0x98A3, 0xEF4C, 0x98A8, 0xEF4D, 0x98A9, 0xEF4E, 0x98AA, 0xEF4F, 0x98AB, 0xEF50, 0x98AC, 0xEF51, 0x98AD, 0xEF52, 0x98AE, 0xEF53, 0x98AF, 0xEF54, 0x98B0, 0xEF55, 0x98B1, 0xEF56, 0x98B2, 0xEF57, 0x98B3, 0xEF58, 0x98B4, 0xEF59, 0x98B5, 0xEF5A, 0x98B6, 0xEF5B, 0x98B7, 0xEF5C, 0x98B8, 0xEF5D, 0x98B9, 0xEF5E, 0x98BA, 0xEF5F, 0x98BB, 0xEF60, 0x98BC, 0xEF61, 0x98BD, 0xEF62, 0x98BE, 0xEF63, 0x98BF, 0xEF64, 0x98C0, 0xEF65, 0x98C1, 0xEF66, 0x98C2, 0xEF67, 0x98C3, 0xEF68, 0x98C4, 0xEF69, 0x98C5, 0xEF6A, 0x98C6, 0xEF6B, 0x98C7, 0xEF6C, 0x98C8, 0xEF6D, 0x98C9, 0xEF6E, 0x98CA, 0xEF6F, 0x98CB, 0xEF70, 0x98CC, 0xEF71, 0x98CD, 0xEF72, 0x98CF, 0xEF73, 0x98D0, 0xEF74, 0x98D4, 0xEF75, 0x98D6, 0xEF76, 0x98D7, 0xEF77, 0x98DB, 0xEF78, 0x98DC, 0xEF79, 0x98DD, 0xEF7A, 0x98E0, 0xEF7B, 0x98E1, 0xEF7C, 0x98E2, 0xEF7D, 0x98E3, 0xEF7E, 0x98E4, 0xEF80, 0x98E5, 0xEF81, 0x98E6, 0xEF82, 0x98E9, 0xEF83, 0x98EA, 0xEF84, 0x98EB, 0xEF85, 0x98EC, 0xEF86, 0x98ED, 0xEF87, 0x98EE, 0xEF88, 0x98EF, 0xEF89, 0x98F0, 0xEF8A, 0x98F1, 0xEF8B, 0x98F2, 0xEF8C, 0x98F3, 0xEF8D, 0x98F4, 0xEF8E, 0x98F5, 0xEF8F, 0x98F6, 0xEF90, 0x98F7, 0xEF91, 0x98F8, 0xEF92, 0x98F9, 0xEF93, 0x98FA, 0xEF94, 0x98FB, 0xEF95, 0x98FC, 0xEF96, 0x98FD, 0xEF97, 0x98FE, 0xEF98, 0x98FF, 0xEF99, 0x9900, 0xEF9A, 0x9901, 0xEF9B, 0x9902, 0xEF9C, 0x9903, 0xEF9D, 0x9904, 0xEF9E, 0x9905, 0xEF9F, 0x9906, 0xEFA0, 0x9907, 0xEFA1, 0x94E9, 0xEFA2, 0x94EB, 0xEFA3, 0x94EE, 0xEFA4, 0x94EF, 0xEFA5, 0x94F3, 0xEFA6, 0x94F4, 0xEFA7, 0x94F5, 0xEFA8, 0x94F7, 0xEFA9, 0x94F9, 0xEFAA, 0x94FC, 0xEFAB, 0x94FD, 0xEFAC, 0x94FF, 0xEFAD, 0x9503, 0xEFAE, 0x9502, 0xEFAF, 0x9506, 0xEFB0, 0x9507, 0xEFB1, 0x9509, 0xEFB2, 0x950A, 0xEFB3, 0x950D, 0xEFB4, 0x950E, 0xEFB5, 0x950F, 0xEFB6, 0x9512, 0xEFB7, 0x9513, 0xEFB8, 0x9514, 0xEFB9, 0x9515, 0xEFBA, 0x9516, 0xEFBB, 0x9518, 0xEFBC, 0x951B, 0xEFBD, 0x951D, 0xEFBE, 0x951E, 0xEFBF, 0x951F, 0xEFC0, 0x9522, 0xEFC1, 0x952A, 0xEFC2, 0x952B, 0xEFC3, 0x9529, 0xEFC4, 0x952C, 0xEFC5, 0x9531, 0xEFC6, 0x9532, 0xEFC7, 0x9534, 0xEFC8, 0x9536, 0xEFC9, 0x9537, 0xEFCA, 0x9538, 0xEFCB, 0x953C, 0xEFCC, 0x953E, 0xEFCD, 0x953F, 0xEFCE, 0x9542, 0xEFCF, 0x9535, 0xEFD0, 0x9544, 0xEFD1, 0x9545, 0xEFD2, 0x9546, 0xEFD3, 0x9549, 0xEFD4, 0x954C, 0xEFD5, 0x954E, 0xEFD6, 0x954F, 0xEFD7, 0x9552, 0xEFD8, 0x9553, 0xEFD9, 0x9554, 0xEFDA, 0x9556, 0xEFDB, 0x9557, 0xEFDC, 0x9558, 0xEFDD, 0x9559, 0xEFDE, 0x955B, 0xEFDF, 0x955E, 0xEFE0, 0x955F, 0xEFE1, 0x955D, 0xEFE2, 0x9561, 0xEFE3, 0x9562, 0xEFE4, 0x9564, 0xEFE5, 0x9565, 0xEFE6, 0x9566, 0xEFE7, 0x9567, 0xEFE8, 0x9568, 0xEFE9, 0x9569, 0xEFEA, 0x956A, 0xEFEB, 0x956B, 0xEFEC, 0x956C, 0xEFED, 0x956F, 0xEFEE, 0x9571, 0xEFEF, 0x9572, 0xEFF0, 0x9573, 0xEFF1, 0x953A, 0xEFF2, 0x77E7, 0xEFF3, 0x77EC, 0xEFF4, 0x96C9, 0xEFF5, 0x79D5, 0xEFF6, 0x79ED, 0xEFF7, 0x79E3, 0xEFF8, 0x79EB, 0xEFF9, 0x7A06, 0xEFFA, 0x5D47, 0xEFFB, 0x7A03, 0xEFFC, 0x7A02, 0xEFFD, 0x7A1E, 0xEFFE, 0x7A14, 0xF040, 0x9908, 0xF041, 0x9909, 0xF042, 0x990A, 0xF043, 0x990B, 0xF044, 0x990C, 0xF045, 0x990E, 0xF046, 0x990F, 0xF047, 0x9911, 0xF048, 0x9912, 0xF049, 0x9913, 0xF04A, 0x9914, 0xF04B, 0x9915, 0xF04C, 0x9916, 0xF04D, 0x9917, 0xF04E, 0x9918, 0xF04F, 0x9919, 0xF050, 0x991A, 0xF051, 0x991B, 0xF052, 0x991C, 0xF053, 0x991D, 0xF054, 0x991E, 0xF055, 0x991F, 0xF056, 0x9920, 0xF057, 0x9921, 0xF058, 0x9922, 0xF059, 0x9923, 0xF05A, 0x9924, 0xF05B, 0x9925, 0xF05C, 0x9926, 0xF05D, 0x9927, 0xF05E, 0x9928, 0xF05F, 0x9929, 0xF060, 0x992A, 0xF061, 0x992B, 0xF062, 0x992C, 0xF063, 0x992D, 0xF064, 0x992F, 0xF065, 0x9930, 0xF066, 0x9931, 0xF067, 0x9932, 0xF068, 0x9933, 0xF069, 0x9934, 0xF06A, 0x9935, 0xF06B, 0x9936, 0xF06C, 0x9937, 0xF06D, 0x9938, 0xF06E, 0x9939, 0xF06F, 0x993A, 0xF070, 0x993B, 0xF071, 0x993C, 0xF072, 0x993D, 0xF073, 0x993E, 0xF074, 0x993F, 0xF075, 0x9940, 0xF076, 0x9941, 0xF077, 0x9942, 0xF078, 0x9943, 0xF079, 0x9944, 0xF07A, 0x9945, 0xF07B, 0x9946, 0xF07C, 0x9947, 0xF07D, 0x9948, 0xF07E, 0x9949, 0xF080, 0x994A, 0xF081, 0x994B, 0xF082, 0x994C, 0xF083, 0x994D, 0xF084, 0x994E, 0xF085, 0x994F, 0xF086, 0x9950, 0xF087, 0x9951, 0xF088, 0x9952, 0xF089, 0x9953, 0xF08A, 0x9956, 0xF08B, 0x9957, 0xF08C, 0x9958, 0xF08D, 0x9959, 0xF08E, 0x995A, 0xF08F, 0x995B, 0xF090, 0x995C, 0xF091, 0x995D, 0xF092, 0x995E, 0xF093, 0x995F, 0xF094, 0x9960, 0xF095, 0x9961, 0xF096, 0x9962, 0xF097, 0x9964, 0xF098, 0x9966, 0xF099, 0x9973, 0xF09A, 0x9978, 0xF09B, 0x9979, 0xF09C, 0x997B, 0xF09D, 0x997E, 0xF09E, 0x9982, 0xF09F, 0x9983, 0xF0A0, 0x9989, 0xF0A1, 0x7A39, 0xF0A2, 0x7A37, 0xF0A3, 0x7A51, 0xF0A4, 0x9ECF, 0xF0A5, 0x99A5, 0xF0A6, 0x7A70, 0xF0A7, 0x7688, 0xF0A8, 0x768E, 0xF0A9, 0x7693, 0xF0AA, 0x7699, 0xF0AB, 0x76A4, 0xF0AC, 0x74DE, 0xF0AD, 0x74E0, 0xF0AE, 0x752C, 0xF0AF, 0x9E20, 0xF0B0, 0x9E22, 0xF0B1, 0x9E28, 0xF0B2, 0x9E29, 0xF0B3, 0x9E2A, 0xF0B4, 0x9E2B, 0xF0B5, 0x9E2C, 0xF0B6, 0x9E32, 0xF0B7, 0x9E31, 0xF0B8, 0x9E36, 0xF0B9, 0x9E38, 0xF0BA, 0x9E37, 0xF0BB, 0x9E39, 0xF0BC, 0x9E3A, 0xF0BD, 0x9E3E, 0xF0BE, 0x9E41, 0xF0BF, 0x9E42, 0xF0C0, 0x9E44, 0xF0C1, 0x9E46, 0xF0C2, 0x9E47, 0xF0C3, 0x9E48, 0xF0C4, 0x9E49, 0xF0C5, 0x9E4B, 0xF0C6, 0x9E4C, 0xF0C7, 0x9E4E, 0xF0C8, 0x9E51, 0xF0C9, 0x9E55, 0xF0CA, 0x9E57, 0xF0CB, 0x9E5A, 0xF0CC, 0x9E5B, 0xF0CD, 0x9E5C, 0xF0CE, 0x9E5E, 0xF0CF, 0x9E63, 0xF0D0, 0x9E66, 0xF0D1, 0x9E67, 0xF0D2, 0x9E68, 0xF0D3, 0x9E69, 0xF0D4, 0x9E6A, 0xF0D5, 0x9E6B, 0xF0D6, 0x9E6C, 0xF0D7, 0x9E71, 0xF0D8, 0x9E6D, 0xF0D9, 0x9E73, 0xF0DA, 0x7592, 0xF0DB, 0x7594, 0xF0DC, 0x7596, 0xF0DD, 0x75A0, 0xF0DE, 0x759D, 0xF0DF, 0x75AC, 0xF0E0, 0x75A3, 0xF0E1, 0x75B3, 0xF0E2, 0x75B4, 0xF0E3, 0x75B8, 0xF0E4, 0x75C4, 0xF0E5, 0x75B1, 0xF0E6, 0x75B0, 0xF0E7, 0x75C3, 0xF0E8, 0x75C2, 0xF0E9, 0x75D6, 0xF0EA, 0x75CD, 0xF0EB, 0x75E3, 0xF0EC, 0x75E8, 0xF0ED, 0x75E6, 0xF0EE, 0x75E4, 0xF0EF, 0x75EB, 0xF0F0, 0x75E7, 0xF0F1, 0x7603, 0xF0F2, 0x75F1, 0xF0F3, 0x75FC, 0xF0F4, 0x75FF, 0xF0F5, 0x7610, 0xF0F6, 0x7600, 0xF0F7, 0x7605, 0xF0F8, 0x760C, 0xF0F9, 0x7617, 0xF0FA, 0x760A, 0xF0FB, 0x7625, 0xF0FC, 0x7618, 0xF0FD, 0x7615, 0xF0FE, 0x7619, 0xF140, 0x998C, 0xF141, 0x998E, 0xF142, 0x999A, 0xF143, 0x999B, 0xF144, 0x999C, 0xF145, 0x999D, 0xF146, 0x999E, 0xF147, 0x999F, 0xF148, 0x99A0, 0xF149, 0x99A1, 0xF14A, 0x99A2, 0xF14B, 0x99A3, 0xF14C, 0x99A4, 0xF14D, 0x99A6, 0xF14E, 0x99A7, 0xF14F, 0x99A9, 0xF150, 0x99AA, 0xF151, 0x99AB, 0xF152, 0x99AC, 0xF153, 0x99AD, 0xF154, 0x99AE, 0xF155, 0x99AF, 0xF156, 0x99B0, 0xF157, 0x99B1, 0xF158, 0x99B2, 0xF159, 0x99B3, 0xF15A, 0x99B4, 0xF15B, 0x99B5, 0xF15C, 0x99B6, 0xF15D, 0x99B7, 0xF15E, 0x99B8, 0xF15F, 0x99B9, 0xF160, 0x99BA, 0xF161, 0x99BB, 0xF162, 0x99BC, 0xF163, 0x99BD, 0xF164, 0x99BE, 0xF165, 0x99BF, 0xF166, 0x99C0, 0xF167, 0x99C1, 0xF168, 0x99C2, 0xF169, 0x99C3, 0xF16A, 0x99C4, 0xF16B, 0x99C5, 0xF16C, 0x99C6, 0xF16D, 0x99C7, 0xF16E, 0x99C8, 0xF16F, 0x99C9, 0xF170, 0x99CA, 0xF171, 0x99CB, 0xF172, 0x99CC, 0xF173, 0x99CD, 0xF174, 0x99CE, 0xF175, 0x99CF, 0xF176, 0x99D0, 0xF177, 0x99D1, 0xF178, 0x99D2, 0xF179, 0x99D3, 0xF17A, 0x99D4, 0xF17B, 0x99D5, 0xF17C, 0x99D6, 0xF17D, 0x99D7, 0xF17E, 0x99D8, 0xF180, 0x99D9, 0xF181, 0x99DA, 0xF182, 0x99DB, 0xF183, 0x99DC, 0xF184, 0x99DD, 0xF185, 0x99DE, 0xF186, 0x99DF, 0xF187, 0x99E0, 0xF188, 0x99E1, 0xF189, 0x99E2, 0xF18A, 0x99E3, 0xF18B, 0x99E4, 0xF18C, 0x99E5, 0xF18D, 0x99E6, 0xF18E, 0x99E7, 0xF18F, 0x99E8, 0xF190, 0x99E9, 0xF191, 0x99EA, 0xF192, 0x99EB, 0xF193, 0x99EC, 0xF194, 0x99ED, 0xF195, 0x99EE, 0xF196, 0x99EF, 0xF197, 0x99F0, 0xF198, 0x99F1, 0xF199, 0x99F2, 0xF19A, 0x99F3, 0xF19B, 0x99F4, 0xF19C, 0x99F5, 0xF19D, 0x99F6, 0xF19E, 0x99F7, 0xF19F, 0x99F8, 0xF1A0, 0x99F9, 0xF1A1, 0x761B, 0xF1A2, 0x763C, 0xF1A3, 0x7622, 0xF1A4, 0x7620, 0xF1A5, 0x7640, 0xF1A6, 0x762D, 0xF1A7, 0x7630, 0xF1A8, 0x763F, 0xF1A9, 0x7635, 0xF1AA, 0x7643, 0xF1AB, 0x763E, 0xF1AC, 0x7633, 0xF1AD, 0x764D, 0xF1AE, 0x765E, 0xF1AF, 0x7654, 0xF1B0, 0x765C, 0xF1B1, 0x7656, 0xF1B2, 0x766B, 0xF1B3, 0x766F, 0xF1B4, 0x7FCA, 0xF1B5, 0x7AE6, 0xF1B6, 0x7A78, 0xF1B7, 0x7A79, 0xF1B8, 0x7A80, 0xF1B9, 0x7A86, 0xF1BA, 0x7A88, 0xF1BB, 0x7A95, 0xF1BC, 0x7AA6, 0xF1BD, 0x7AA0, 0xF1BE, 0x7AAC, 0xF1BF, 0x7AA8, 0xF1C0, 0x7AAD, 0xF1C1, 0x7AB3, 0xF1C2, 0x8864, 0xF1C3, 0x8869, 0xF1C4, 0x8872, 0xF1C5, 0x887D, 0xF1C6, 0x887F, 0xF1C7, 0x8882, 0xF1C8, 0x88A2, 0xF1C9, 0x88C6, 0xF1CA, 0x88B7, 0xF1CB, 0x88BC, 0xF1CC, 0x88C9, 0xF1CD, 0x88E2, 0xF1CE, 0x88CE, 0xF1CF, 0x88E3, 0xF1D0, 0x88E5, 0xF1D1, 0x88F1, 0xF1D2, 0x891A, 0xF1D3, 0x88FC, 0xF1D4, 0x88E8, 0xF1D5, 0x88FE, 0xF1D6, 0x88F0, 0xF1D7, 0x8921, 0xF1D8, 0x8919, 0xF1D9, 0x8913, 0xF1DA, 0x891B, 0xF1DB, 0x890A, 0xF1DC, 0x8934, 0xF1DD, 0x892B, 0xF1DE, 0x8936, 0xF1DF, 0x8941, 0xF1E0, 0x8966, 0xF1E1, 0x897B, 0xF1E2, 0x758B, 0xF1E3, 0x80E5, 0xF1E4, 0x76B2, 0xF1E5, 0x76B4, 0xF1E6, 0x77DC, 0xF1E7, 0x8012, 0xF1E8, 0x8014, 0xF1E9, 0x8016, 0xF1EA, 0x801C, 0xF1EB, 0x8020, 0xF1EC, 0x8022, 0xF1ED, 0x8025, 0xF1EE, 0x8026, 0xF1EF, 0x8027, 0xF1F0, 0x8029, 0xF1F1, 0x8028, 0xF1F2, 0x8031, 0xF1F3, 0x800B, 0xF1F4, 0x8035, 0xF1F5, 0x8043, 0xF1F6, 0x8046, 0xF1F7, 0x804D, 0xF1F8, 0x8052, 0xF1F9, 0x8069, 0xF1FA, 0x8071, 0xF1FB, 0x8983, 0xF1FC, 0x9878, 0xF1FD, 0x9880, 0xF1FE, 0x9883, 0xF240, 0x99FA, 0xF241, 0x99FB, 0xF242, 0x99FC, 0xF243, 0x99FD, 0xF244, 0x99FE, 0xF245, 0x99FF, 0xF246, 0x9A00, 0xF247, 0x9A01, 0xF248, 0x9A02, 0xF249, 0x9A03, 0xF24A, 0x9A04, 0xF24B, 0x9A05, 0xF24C, 0x9A06, 0xF24D, 0x9A07, 0xF24E, 0x9A08, 0xF24F, 0x9A09, 0xF250, 0x9A0A, 0xF251, 0x9A0B, 0xF252, 0x9A0C, 0xF253, 0x9A0D, 0xF254, 0x9A0E, 0xF255, 0x9A0F, 0xF256, 0x9A10, 0xF257, 0x9A11, 0xF258, 0x9A12, 0xF259, 0x9A13, 0xF25A, 0x9A14, 0xF25B, 0x9A15, 0xF25C, 0x9A16, 0xF25D, 0x9A17, 0xF25E, 0x9A18, 0xF25F, 0x9A19, 0xF260, 0x9A1A, 0xF261, 0x9A1B, 0xF262, 0x9A1C, 0xF263, 0x9A1D, 0xF264, 0x9A1E, 0xF265, 0x9A1F, 0xF266, 0x9A20, 0xF267, 0x9A21, 0xF268, 0x9A22, 0xF269, 0x9A23, 0xF26A, 0x9A24, 0xF26B, 0x9A25, 0xF26C, 0x9A26, 0xF26D, 0x9A27, 0xF26E, 0x9A28, 0xF26F, 0x9A29, 0xF270, 0x9A2A, 0xF271, 0x9A2B, 0xF272, 0x9A2C, 0xF273, 0x9A2D, 0xF274, 0x9A2E, 0xF275, 0x9A2F, 0xF276, 0x9A30, 0xF277, 0x9A31, 0xF278, 0x9A32, 0xF279, 0x9A33, 0xF27A, 0x9A34, 0xF27B, 0x9A35, 0xF27C, 0x9A36, 0xF27D, 0x9A37, 0xF27E, 0x9A38, 0xF280, 0x9A39, 0xF281, 0x9A3A, 0xF282, 0x9A3B, 0xF283, 0x9A3C, 0xF284, 0x9A3D, 0xF285, 0x9A3E, 0xF286, 0x9A3F, 0xF287, 0x9A40, 0xF288, 0x9A41, 0xF289, 0x9A42, 0xF28A, 0x9A43, 0xF28B, 0x9A44, 0xF28C, 0x9A45, 0xF28D, 0x9A46, 0xF28E, 0x9A47, 0xF28F, 0x9A48, 0xF290, 0x9A49, 0xF291, 0x9A4A, 0xF292, 0x9A4B, 0xF293, 0x9A4C, 0xF294, 0x9A4D, 0xF295, 0x9A4E, 0xF296, 0x9A4F, 0xF297, 0x9A50, 0xF298, 0x9A51, 0xF299, 0x9A52, 0xF29A, 0x9A53, 0xF29B, 0x9A54, 0xF29C, 0x9A55, 0xF29D, 0x9A56, 0xF29E, 0x9A57, 0xF29F, 0x9A58, 0xF2A0, 0x9A59, 0xF2A1, 0x9889, 0xF2A2, 0x988C, 0xF2A3, 0x988D, 0xF2A4, 0x988F, 0xF2A5, 0x9894, 0xF2A6, 0x989A, 0xF2A7, 0x989B, 0xF2A8, 0x989E, 0xF2A9, 0x989F, 0xF2AA, 0x98A1, 0xF2AB, 0x98A2, 0xF2AC, 0x98A5, 0xF2AD, 0x98A6, 0xF2AE, 0x864D, 0xF2AF, 0x8654, 0xF2B0, 0x866C, 0xF2B1, 0x866E, 0xF2B2, 0x867F, 0xF2B3, 0x867A, 0xF2B4, 0x867C, 0xF2B5, 0x867B, 0xF2B6, 0x86A8, 0xF2B7, 0x868D, 0xF2B8, 0x868B, 0xF2B9, 0x86AC, 0xF2BA, 0x869D, 0xF2BB, 0x86A7, 0xF2BC, 0x86A3, 0xF2BD, 0x86AA, 0xF2BE, 0x8693, 0xF2BF, 0x86A9, 0xF2C0, 0x86B6, 0xF2C1, 0x86C4, 0xF2C2, 0x86B5, 0xF2C3, 0x86CE, 0xF2C4, 0x86B0, 0xF2C5, 0x86BA, 0xF2C6, 0x86B1, 0xF2C7, 0x86AF, 0xF2C8, 0x86C9, 0xF2C9, 0x86CF, 0xF2CA, 0x86B4, 0xF2CB, 0x86E9, 0xF2CC, 0x86F1, 0xF2CD, 0x86F2, 0xF2CE, 0x86ED, 0xF2CF, 0x86F3, 0xF2D0, 0x86D0, 0xF2D1, 0x8713, 0xF2D2, 0x86DE, 0xF2D3, 0x86F4, 0xF2D4, 0x86DF, 0xF2D5, 0x86D8, 0xF2D6, 0x86D1, 0xF2D7, 0x8703, 0xF2D8, 0x8707, 0xF2D9, 0x86F8, 0xF2DA, 0x8708, 0xF2DB, 0x870A, 0xF2DC, 0x870D, 0xF2DD, 0x8709, 0xF2DE, 0x8723, 0xF2DF, 0x873B, 0xF2E0, 0x871E, 0xF2E1, 0x8725, 0xF2E2, 0x872E, 0xF2E3, 0x871A, 0xF2E4, 0x873E, 0xF2E5, 0x8748, 0xF2E6, 0x8734, 0xF2E7, 0x8731, 0xF2E8, 0x8729, 0xF2E9, 0x8737, 0xF2EA, 0x873F, 0xF2EB, 0x8782, 0xF2EC, 0x8722, 0xF2ED, 0x877D, 0xF2EE, 0x877E, 0xF2EF, 0x877B, 0xF2F0, 0x8760, 0xF2F1, 0x8770, 0xF2F2, 0x874C, 0xF2F3, 0x876E, 0xF2F4, 0x878B, 0xF2F5, 0x8753, 0xF2F6, 0x8763, 0xF2F7, 0x877C, 0xF2F8, 0x8764, 0xF2F9, 0x8759, 0xF2FA, 0x8765, 0xF2FB, 0x8793, 0xF2FC, 0x87AF, 0xF2FD, 0x87A8, 0xF2FE, 0x87D2, 0xF340, 0x9A5A, 0xF341, 0x9A5B, 0xF342, 0x9A5C, 0xF343, 0x9A5D, 0xF344, 0x9A5E, 0xF345, 0x9A5F, 0xF346, 0x9A60, 0xF347, 0x9A61, 0xF348, 0x9A62, 0xF349, 0x9A63, 0xF34A, 0x9A64, 0xF34B, 0x9A65, 0xF34C, 0x9A66, 0xF34D, 0x9A67, 0xF34E, 0x9A68, 0xF34F, 0x9A69, 0xF350, 0x9A6A, 0xF351, 0x9A6B, 0xF352, 0x9A72, 0xF353, 0x9A83, 0xF354, 0x9A89, 0xF355, 0x9A8D, 0xF356, 0x9A8E, 0xF357, 0x9A94, 0xF358, 0x9A95, 0xF359, 0x9A99, 0xF35A, 0x9AA6, 0xF35B, 0x9AA9, 0xF35C, 0x9AAA, 0xF35D, 0x9AAB, 0xF35E, 0x9AAC, 0xF35F, 0x9AAD, 0xF360, 0x9AAE, 0xF361, 0x9AAF, 0xF362, 0x9AB2, 0xF363, 0x9AB3, 0xF364, 0x9AB4, 0xF365, 0x9AB5, 0xF366, 0x9AB9, 0xF367, 0x9ABB, 0xF368, 0x9ABD, 0xF369, 0x9ABE, 0xF36A, 0x9ABF, 0xF36B, 0x9AC3, 0xF36C, 0x9AC4, 0xF36D, 0x9AC6, 0xF36E, 0x9AC7, 0xF36F, 0x9AC8, 0xF370, 0x9AC9, 0xF371, 0x9ACA, 0xF372, 0x9ACD, 0xF373, 0x9ACE, 0xF374, 0x9ACF, 0xF375, 0x9AD0, 0xF376, 0x9AD2, 0xF377, 0x9AD4, 0xF378, 0x9AD5, 0xF379, 0x9AD6, 0xF37A, 0x9AD7, 0xF37B, 0x9AD9, 0xF37C, 0x9ADA, 0xF37D, 0x9ADB, 0xF37E, 0x9ADC, 0xF380, 0x9ADD, 0xF381, 0x9ADE, 0xF382, 0x9AE0, 0xF383, 0x9AE2, 0xF384, 0x9AE3, 0xF385, 0x9AE4, 0xF386, 0x9AE5, 0xF387, 0x9AE7, 0xF388, 0x9AE8, 0xF389, 0x9AE9, 0xF38A, 0x9AEA, 0xF38B, 0x9AEC, 0xF38C, 0x9AEE, 0xF38D, 0x9AF0, 0xF38E, 0x9AF1, 0xF38F, 0x9AF2, 0xF390, 0x9AF3, 0xF391, 0x9AF4, 0xF392, 0x9AF5, 0xF393, 0x9AF6, 0xF394, 0x9AF7, 0xF395, 0x9AF8, 0xF396, 0x9AFA, 0xF397, 0x9AFC, 0xF398, 0x9AFD, 0xF399, 0x9AFE, 0xF39A, 0x9AFF, 0xF39B, 0x9B00, 0xF39C, 0x9B01, 0xF39D, 0x9B02, 0xF39E, 0x9B04, 0xF39F, 0x9B05, 0xF3A0, 0x9B06, 0xF3A1, 0x87C6, 0xF3A2, 0x8788, 0xF3A3, 0x8785, 0xF3A4, 0x87AD, 0xF3A5, 0x8797, 0xF3A6, 0x8783, 0xF3A7, 0x87AB, 0xF3A8, 0x87E5, 0xF3A9, 0x87AC, 0xF3AA, 0x87B5, 0xF3AB, 0x87B3, 0xF3AC, 0x87CB, 0xF3AD, 0x87D3, 0xF3AE, 0x87BD, 0xF3AF, 0x87D1, 0xF3B0, 0x87C0, 0xF3B1, 0x87CA, 0xF3B2, 0x87DB, 0xF3B3, 0x87EA, 0xF3B4, 0x87E0, 0xF3B5, 0x87EE, 0xF3B6, 0x8816, 0xF3B7, 0x8813, 0xF3B8, 0x87FE, 0xF3B9, 0x880A, 0xF3BA, 0x881B, 0xF3BB, 0x8821, 0xF3BC, 0x8839, 0xF3BD, 0x883C, 0xF3BE, 0x7F36, 0xF3BF, 0x7F42, 0xF3C0, 0x7F44, 0xF3C1, 0x7F45, 0xF3C2, 0x8210, 0xF3C3, 0x7AFA, 0xF3C4, 0x7AFD, 0xF3C5, 0x7B08, 0xF3C6, 0x7B03, 0xF3C7, 0x7B04, 0xF3C8, 0x7B15, 0xF3C9, 0x7B0A, 0xF3CA, 0x7B2B, 0xF3CB, 0x7B0F, 0xF3CC, 0x7B47, 0xF3CD, 0x7B38, 0xF3CE, 0x7B2A, 0xF3CF, 0x7B19, 0xF3D0, 0x7B2E, 0xF3D1, 0x7B31, 0xF3D2, 0x7B20, 0xF3D3, 0x7B25, 0xF3D4, 0x7B24, 0xF3D5, 0x7B33, 0xF3D6, 0x7B3E, 0xF3D7, 0x7B1E, 0xF3D8, 0x7B58, 0xF3D9, 0x7B5A, 0xF3DA, 0x7B45, 0xF3DB, 0x7B75, 0xF3DC, 0x7B4C, 0xF3DD, 0x7B5D, 0xF3DE, 0x7B60, 0xF3DF, 0x7B6E, 0xF3E0, 0x7B7B, 0xF3E1, 0x7B62, 0xF3E2, 0x7B72, 0xF3E3, 0x7B71, 0xF3E4, 0x7B90, 0xF3E5, 0x7BA6, 0xF3E6, 0x7BA7, 0xF3E7, 0x7BB8, 0xF3E8, 0x7BAC, 0xF3E9, 0x7B9D, 0xF3EA, 0x7BA8, 0xF3EB, 0x7B85, 0xF3EC, 0x7BAA, 0xF3ED, 0x7B9C, 0xF3EE, 0x7BA2, 0xF3EF, 0x7BAB, 0xF3F0, 0x7BB4, 0xF3F1, 0x7BD1, 0xF3F2, 0x7BC1, 0xF3F3, 0x7BCC, 0xF3F4, 0x7BDD, 0xF3F5, 0x7BDA, 0xF3F6, 0x7BE5, 0xF3F7, 0x7BE6, 0xF3F8, 0x7BEA, 0xF3F9, 0x7C0C, 0xF3FA, 0x7BFE, 0xF3FB, 0x7BFC, 0xF3FC, 0x7C0F, 0xF3FD, 0x7C16, 0xF3FE, 0x7C0B, 0xF440, 0x9B07, 0xF441, 0x9B09, 0xF442, 0x9B0A, 0xF443, 0x9B0B, 0xF444, 0x9B0C, 0xF445, 0x9B0D, 0xF446, 0x9B0E, 0xF447, 0x9B10, 0xF448, 0x9B11, 0xF449, 0x9B12, 0xF44A, 0x9B14, 0xF44B, 0x9B15, 0xF44C, 0x9B16, 0xF44D, 0x9B17, 0xF44E, 0x9B18, 0xF44F, 0x9B19, 0xF450, 0x9B1A, 0xF451, 0x9B1B, 0xF452, 0x9B1C, 0xF453, 0x9B1D, 0xF454, 0x9B1E, 0xF455, 0x9B20, 0xF456, 0x9B21, 0xF457, 0x9B22, 0xF458, 0x9B24, 0xF459, 0x9B25, 0xF45A, 0x9B26, 0xF45B, 0x9B27, 0xF45C, 0x9B28, 0xF45D, 0x9B29, 0xF45E, 0x9B2A, 0xF45F, 0x9B2B, 0xF460, 0x9B2C, 0xF461, 0x9B2D, 0xF462, 0x9B2E, 0xF463, 0x9B30, 0xF464, 0x9B31, 0xF465, 0x9B33, 0xF466, 0x9B34, 0xF467, 0x9B35, 0xF468, 0x9B36, 0xF469, 0x9B37, 0xF46A, 0x9B38, 0xF46B, 0x9B39, 0xF46C, 0x9B3A, 0xF46D, 0x9B3D, 0xF46E, 0x9B3E, 0xF46F, 0x9B3F, 0xF470, 0x9B40, 0xF471, 0x9B46, 0xF472, 0x9B4A, 0xF473, 0x9B4B, 0xF474, 0x9B4C, 0xF475, 0x9B4E, 0xF476, 0x9B50, 0xF477, 0x9B52, 0xF478, 0x9B53, 0xF479, 0x9B55, 0xF47A, 0x9B56, 0xF47B, 0x9B57, 0xF47C, 0x9B58, 0xF47D, 0x9B59, 0xF47E, 0x9B5A, 0xF480, 0x9B5B, 0xF481, 0x9B5C, 0xF482, 0x9B5D, 0xF483, 0x9B5E, 0xF484, 0x9B5F, 0xF485, 0x9B60, 0xF486, 0x9B61, 0xF487, 0x9B62, 0xF488, 0x9B63, 0xF489, 0x9B64, 0xF48A, 0x9B65, 0xF48B, 0x9B66, 0xF48C, 0x9B67, 0xF48D, 0x9B68, 0xF48E, 0x9B69, 0xF48F, 0x9B6A, 0xF490, 0x9B6B, 0xF491, 0x9B6C, 0xF492, 0x9B6D, 0xF493, 0x9B6E, 0xF494, 0x9B6F, 0xF495, 0x9B70, 0xF496, 0x9B71, 0xF497, 0x9B72, 0xF498, 0x9B73, 0xF499, 0x9B74, 0xF49A, 0x9B75, 0xF49B, 0x9B76, 0xF49C, 0x9B77, 0xF49D, 0x9B78, 0xF49E, 0x9B79, 0xF49F, 0x9B7A, 0xF4A0, 0x9B7B, 0xF4A1, 0x7C1F, 0xF4A2, 0x7C2A, 0xF4A3, 0x7C26, 0xF4A4, 0x7C38, 0xF4A5, 0x7C41, 0xF4A6, 0x7C40, 0xF4A7, 0x81FE, 0xF4A8, 0x8201, 0xF4A9, 0x8202, 0xF4AA, 0x8204, 0xF4AB, 0x81EC, 0xF4AC, 0x8844, 0xF4AD, 0x8221, 0xF4AE, 0x8222, 0xF4AF, 0x8223, 0xF4B0, 0x822D, 0xF4B1, 0x822F, 0xF4B2, 0x8228, 0xF4B3, 0x822B, 0xF4B4, 0x8238, 0xF4B5, 0x823B, 0xF4B6, 0x8233, 0xF4B7, 0x8234, 0xF4B8, 0x823E, 0xF4B9, 0x8244, 0xF4BA, 0x8249, 0xF4BB, 0x824B, 0xF4BC, 0x824F, 0xF4BD, 0x825A, 0xF4BE, 0x825F, 0xF4BF, 0x8268, 0xF4C0, 0x887E, 0xF4C1, 0x8885, 0xF4C2, 0x8888, 0xF4C3, 0x88D8, 0xF4C4, 0x88DF, 0xF4C5, 0x895E, 0xF4C6, 0x7F9D, 0xF4C7, 0x7F9F, 0xF4C8, 0x7FA7, 0xF4C9, 0x7FAF, 0xF4CA, 0x7FB0, 0xF4CB, 0x7FB2, 0xF4CC, 0x7C7C, 0xF4CD, 0x6549, 0xF4CE, 0x7C91, 0xF4CF, 0x7C9D, 0xF4D0, 0x7C9C, 0xF4D1, 0x7C9E, 0xF4D2, 0x7CA2, 0xF4D3, 0x7CB2, 0xF4D4, 0x7CBC, 0xF4D5, 0x7CBD, 0xF4D6, 0x7CC1, 0xF4D7, 0x7CC7, 0xF4D8, 0x7CCC, 0xF4D9, 0x7CCD, 0xF4DA, 0x7CC8, 0xF4DB, 0x7CC5, 0xF4DC, 0x7CD7, 0xF4DD, 0x7CE8, 0xF4DE, 0x826E, 0xF4DF, 0x66A8, 0xF4E0, 0x7FBF, 0xF4E1, 0x7FCE, 0xF4E2, 0x7FD5, 0xF4E3, 0x7FE5, 0xF4E4, 0x7FE1, 0xF4E5, 0x7FE6, 0xF4E6, 0x7FE9, 0xF4E7, 0x7FEE, 0xF4E8, 0x7FF3, 0xF4E9, 0x7CF8, 0xF4EA, 0x7D77, 0xF4EB, 0x7DA6, 0xF4EC, 0x7DAE, 0xF4ED, 0x7E47, 0xF4EE, 0x7E9B, 0xF4EF, 0x9EB8, 0xF4F0, 0x9EB4, 0xF4F1, 0x8D73, 0xF4F2, 0x8D84, 0xF4F3, 0x8D94, 0xF4F4, 0x8D91, 0xF4F5, 0x8DB1, 0xF4F6, 0x8D67, 0xF4F7, 0x8D6D, 0xF4F8, 0x8C47, 0xF4F9, 0x8C49, 0xF4FA, 0x914A, 0xF4FB, 0x9150, 0xF4FC, 0x914E, 0xF4FD, 0x914F, 0xF4FE, 0x9164, 0xF540, 0x9B7C, 0xF541, 0x9B7D, 0xF542, 0x9B7E, 0xF543, 0x9B7F, 0xF544, 0x9B80, 0xF545, 0x9B81, 0xF546, 0x9B82, 0xF547, 0x9B83, 0xF548, 0x9B84, 0xF549, 0x9B85, 0xF54A, 0x9B86, 0xF54B, 0x9B87, 0xF54C, 0x9B88, 0xF54D, 0x9B89, 0xF54E, 0x9B8A, 0xF54F, 0x9B8B, 0xF550, 0x9B8C, 0xF551, 0x9B8D, 0xF552, 0x9B8E, 0xF553, 0x9B8F, 0xF554, 0x9B90, 0xF555, 0x9B91, 0xF556, 0x9B92, 0xF557, 0x9B93, 0xF558, 0x9B94, 0xF559, 0x9B95, 0xF55A, 0x9B96, 0xF55B, 0x9B97, 0xF55C, 0x9B98, 0xF55D, 0x9B99, 0xF55E, 0x9B9A, 0xF55F, 0x9B9B, 0xF560, 0x9B9C, 0xF561, 0x9B9D, 0xF562, 0x9B9E, 0xF563, 0x9B9F, 0xF564, 0x9BA0, 0xF565, 0x9BA1, 0xF566, 0x9BA2, 0xF567, 0x9BA3, 0xF568, 0x9BA4, 0xF569, 0x9BA5, 0xF56A, 0x9BA6, 0xF56B, 0x9BA7, 0xF56C, 0x9BA8, 0xF56D, 0x9BA9, 0xF56E, 0x9BAA, 0xF56F, 0x9BAB, 0xF570, 0x9BAC, 0xF571, 0x9BAD, 0xF572, 0x9BAE, 0xF573, 0x9BAF, 0xF574, 0x9BB0, 0xF575, 0x9BB1, 0xF576, 0x9BB2, 0xF577, 0x9BB3, 0xF578, 0x9BB4, 0xF579, 0x9BB5, 0xF57A, 0x9BB6, 0xF57B, 0x9BB7, 0xF57C, 0x9BB8, 0xF57D, 0x9BB9, 0xF57E, 0x9BBA, 0xF580, 0x9BBB, 0xF581, 0x9BBC, 0xF582, 0x9BBD, 0xF583, 0x9BBE, 0xF584, 0x9BBF, 0xF585, 0x9BC0, 0xF586, 0x9BC1, 0xF587, 0x9BC2, 0xF588, 0x9BC3, 0xF589, 0x9BC4, 0xF58A, 0x9BC5, 0xF58B, 0x9BC6, 0xF58C, 0x9BC7, 0xF58D, 0x9BC8, 0xF58E, 0x9BC9, 0xF58F, 0x9BCA, 0xF590, 0x9BCB, 0xF591, 0x9BCC, 0xF592, 0x9BCD, 0xF593, 0x9BCE, 0xF594, 0x9BCF, 0xF595, 0x9BD0, 0xF596, 0x9BD1, 0xF597, 0x9BD2, 0xF598, 0x9BD3, 0xF599, 0x9BD4, 0xF59A, 0x9BD5, 0xF59B, 0x9BD6, 0xF59C, 0x9BD7, 0xF59D, 0x9BD8, 0xF59E, 0x9BD9, 0xF59F, 0x9BDA, 0xF5A0, 0x9BDB, 0xF5A1, 0x9162, 0xF5A2, 0x9161, 0xF5A3, 0x9170, 0xF5A4, 0x9169, 0xF5A5, 0x916F, 0xF5A6, 0x917D, 0xF5A7, 0x917E, 0xF5A8, 0x9172, 0xF5A9, 0x9174, 0xF5AA, 0x9179, 0xF5AB, 0x918C, 0xF5AC, 0x9185, 0xF5AD, 0x9190, 0xF5AE, 0x918D, 0xF5AF, 0x9191, 0xF5B0, 0x91A2, 0xF5B1, 0x91A3, 0xF5B2, 0x91AA, 0xF5B3, 0x91AD, 0xF5B4, 0x91AE, 0xF5B5, 0x91AF, 0xF5B6, 0x91B5, 0xF5B7, 0x91B4, 0xF5B8, 0x91BA, 0xF5B9, 0x8C55, 0xF5BA, 0x9E7E, 0xF5BB, 0x8DB8, 0xF5BC, 0x8DEB, 0xF5BD, 0x8E05, 0xF5BE, 0x8E59, 0xF5BF, 0x8E69, 0xF5C0, 0x8DB5, 0xF5C1, 0x8DBF, 0xF5C2, 0x8DBC, 0xF5C3, 0x8DBA, 0xF5C4, 0x8DC4, 0xF5C5, 0x8DD6, 0xF5C6, 0x8DD7, 0xF5C7, 0x8DDA, 0xF5C8, 0x8DDE, 0xF5C9, 0x8DCE, 0xF5CA, 0x8DCF, 0xF5CB, 0x8DDB, 0xF5CC, 0x8DC6, 0xF5CD, 0x8DEC, 0xF5CE, 0x8DF7, 0xF5CF, 0x8DF8, 0xF5D0, 0x8DE3, 0xF5D1, 0x8DF9, 0xF5D2, 0x8DFB, 0xF5D3, 0x8DE4, 0xF5D4, 0x8E09, 0xF5D5, 0x8DFD, 0xF5D6, 0x8E14, 0xF5D7, 0x8E1D, 0xF5D8, 0x8E1F, 0xF5D9, 0x8E2C, 0xF5DA, 0x8E2E, 0xF5DB, 0x8E23, 0xF5DC, 0x8E2F, 0xF5DD, 0x8E3A, 0xF5DE, 0x8E40, 0xF5DF, 0x8E39, 0xF5E0, 0x8E35, 0xF5E1, 0x8E3D, 0xF5E2, 0x8E31, 0xF5E3, 0x8E49, 0xF5E4, 0x8E41, 0xF5E5, 0x8E42, 0xF5E6, 0x8E51, 0xF5E7, 0x8E52, 0xF5E8, 0x8E4A, 0xF5E9, 0x8E70, 0xF5EA, 0x8E76, 0xF5EB, 0x8E7C, 0xF5EC, 0x8E6F, 0xF5ED, 0x8E74, 0xF5EE, 0x8E85, 0xF5EF, 0x8E8F, 0xF5F0, 0x8E94, 0xF5F1, 0x8E90, 0xF5F2, 0x8E9C, 0xF5F3, 0x8E9E, 0xF5F4, 0x8C78, 0xF5F5, 0x8C82, 0xF5F6, 0x8C8A, 0xF5F7, 0x8C85, 0xF5F8, 0x8C98, 0xF5F9, 0x8C94, 0xF5FA, 0x659B, 0xF5FB, 0x89D6, 0xF5FC, 0x89DE, 0xF5FD, 0x89DA, 0xF5FE, 0x89DC, 0xF640, 0x9BDC, 0xF641, 0x9BDD, 0xF642, 0x9BDE, 0xF643, 0x9BDF, 0xF644, 0x9BE0, 0xF645, 0x9BE1, 0xF646, 0x9BE2, 0xF647, 0x9BE3, 0xF648, 0x9BE4, 0xF649, 0x9BE5, 0xF64A, 0x9BE6, 0xF64B, 0x9BE7, 0xF64C, 0x9BE8, 0xF64D, 0x9BE9, 0xF64E, 0x9BEA, 0xF64F, 0x9BEB, 0xF650, 0x9BEC, 0xF651, 0x9BED, 0xF652, 0x9BEE, 0xF653, 0x9BEF, 0xF654, 0x9BF0, 0xF655, 0x9BF1, 0xF656, 0x9BF2, 0xF657, 0x9BF3, 0xF658, 0x9BF4, 0xF659, 0x9BF5, 0xF65A, 0x9BF6, 0xF65B, 0x9BF7, 0xF65C, 0x9BF8, 0xF65D, 0x9BF9, 0xF65E, 0x9BFA, 0xF65F, 0x9BFB, 0xF660, 0x9BFC, 0xF661, 0x9BFD, 0xF662, 0x9BFE, 0xF663, 0x9BFF, 0xF664, 0x9C00, 0xF665, 0x9C01, 0xF666, 0x9C02, 0xF667, 0x9C03, 0xF668, 0x9C04, 0xF669, 0x9C05, 0xF66A, 0x9C06, 0xF66B, 0x9C07, 0xF66C, 0x9C08, 0xF66D, 0x9C09, 0xF66E, 0x9C0A, 0xF66F, 0x9C0B, 0xF670, 0x9C0C, 0xF671, 0x9C0D, 0xF672, 0x9C0E, 0xF673, 0x9C0F, 0xF674, 0x9C10, 0xF675, 0x9C11, 0xF676, 0x9C12, 0xF677, 0x9C13, 0xF678, 0x9C14, 0xF679, 0x9C15, 0xF67A, 0x9C16, 0xF67B, 0x9C17, 0xF67C, 0x9C18, 0xF67D, 0x9C19, 0xF67E, 0x9C1A, 0xF680, 0x9C1B, 0xF681, 0x9C1C, 0xF682, 0x9C1D, 0xF683, 0x9C1E, 0xF684, 0x9C1F, 0xF685, 0x9C20, 0xF686, 0x9C21, 0xF687, 0x9C22, 0xF688, 0x9C23, 0xF689, 0x9C24, 0xF68A, 0x9C25, 0xF68B, 0x9C26, 0xF68C, 0x9C27, 0xF68D, 0x9C28, 0xF68E, 0x9C29, 0xF68F, 0x9C2A, 0xF690, 0x9C2B, 0xF691, 0x9C2C, 0xF692, 0x9C2D, 0xF693, 0x9C2E, 0xF694, 0x9C2F, 0xF695, 0x9C30, 0xF696, 0x9C31, 0xF697, 0x9C32, 0xF698, 0x9C33, 0xF699, 0x9C34, 0xF69A, 0x9C35, 0xF69B, 0x9C36, 0xF69C, 0x9C37, 0xF69D, 0x9C38, 0xF69E, 0x9C39, 0xF69F, 0x9C3A, 0xF6A0, 0x9C3B, 0xF6A1, 0x89E5, 0xF6A2, 0x89EB, 0xF6A3, 0x89EF, 0xF6A4, 0x8A3E, 0xF6A5, 0x8B26, 0xF6A6, 0x9753, 0xF6A7, 0x96E9, 0xF6A8, 0x96F3, 0xF6A9, 0x96EF, 0xF6AA, 0x9706, 0xF6AB, 0x9701, 0xF6AC, 0x9708, 0xF6AD, 0x970F, 0xF6AE, 0x970E, 0xF6AF, 0x972A, 0xF6B0, 0x972D, 0xF6B1, 0x9730, 0xF6B2, 0x973E, 0xF6B3, 0x9F80, 0xF6B4, 0x9F83, 0xF6B5, 0x9F85, 0xF6B6, 0x9F86, 0xF6B7, 0x9F87, 0xF6B8, 0x9F88, 0xF6B9, 0x9F89, 0xF6BA, 0x9F8A, 0xF6BB, 0x9F8C, 0xF6BC, 0x9EFE, 0xF6BD, 0x9F0B, 0xF6BE, 0x9F0D, 0xF6BF, 0x96B9, 0xF6C0, 0x96BC, 0xF6C1, 0x96BD, 0xF6C2, 0x96CE, 0xF6C3, 0x96D2, 0xF6C4, 0x77BF, 0xF6C5, 0x96E0, 0xF6C6, 0x928E, 0xF6C7, 0x92AE, 0xF6C8, 0x92C8, 0xF6C9, 0x933E, 0xF6CA, 0x936A, 0xF6CB, 0x93CA, 0xF6CC, 0x938F, 0xF6CD, 0x943E, 0xF6CE, 0x946B, 0xF6CF, 0x9C7F, 0xF6D0, 0x9C82, 0xF6D1, 0x9C85, 0xF6D2, 0x9C86, 0xF6D3, 0x9C87, 0xF6D4, 0x9C88, 0xF6D5, 0x7A23, 0xF6D6, 0x9C8B, 0xF6D7, 0x9C8E, 0xF6D8, 0x9C90, 0xF6D9, 0x9C91, 0xF6DA, 0x9C92, 0xF6DB, 0x9C94, 0xF6DC, 0x9C95, 0xF6DD, 0x9C9A, 0xF6DE, 0x9C9B, 0xF6DF, 0x9C9E, 0xF6E0, 0x9C9F, 0xF6E1, 0x9CA0, 0xF6E2, 0x9CA1, 0xF6E3, 0x9CA2, 0xF6E4, 0x9CA3, 0xF6E5, 0x9CA5, 0xF6E6, 0x9CA6, 0xF6E7, 0x9CA7, 0xF6E8, 0x9CA8, 0xF6E9, 0x9CA9, 0xF6EA, 0x9CAB, 0xF6EB, 0x9CAD, 0xF6EC, 0x9CAE, 0xF6ED, 0x9CB0, 0xF6EE, 0x9CB1, 0xF6EF, 0x9CB2, 0xF6F0, 0x9CB3, 0xF6F1, 0x9CB4, 0xF6F2, 0x9CB5, 0xF6F3, 0x9CB6, 0xF6F4, 0x9CB7, 0xF6F5, 0x9CBA, 0xF6F6, 0x9CBB, 0xF6F7, 0x9CBC, 0xF6F8, 0x9CBD, 0xF6F9, 0x9CC4, 0xF6FA, 0x9CC5, 0xF6FB, 0x9CC6, 0xF6FC, 0x9CC7, 0xF6FD, 0x9CCA, 0xF6FE, 0x9CCB, 0xF740, 0x9C3C, 0xF741, 0x9C3D, 0xF742, 0x9C3E, 0xF743, 0x9C3F, 0xF744, 0x9C40, 0xF745, 0x9C41, 0xF746, 0x9C42, 0xF747, 0x9C43, 0xF748, 0x9C44, 0xF749, 0x9C45, 0xF74A, 0x9C46, 0xF74B, 0x9C47, 0xF74C, 0x9C48, 0xF74D, 0x9C49, 0xF74E, 0x9C4A, 0xF74F, 0x9C4B, 0xF750, 0x9C4C, 0xF751, 0x9C4D, 0xF752, 0x9C4E, 0xF753, 0x9C4F, 0xF754, 0x9C50, 0xF755, 0x9C51, 0xF756, 0x9C52, 0xF757, 0x9C53, 0xF758, 0x9C54, 0xF759, 0x9C55, 0xF75A, 0x9C56, 0xF75B, 0x9C57, 0xF75C, 0x9C58, 0xF75D, 0x9C59, 0xF75E, 0x9C5A, 0xF75F, 0x9C5B, 0xF760, 0x9C5C, 0xF761, 0x9C5D, 0xF762, 0x9C5E, 0xF763, 0x9C5F, 0xF764, 0x9C60, 0xF765, 0x9C61, 0xF766, 0x9C62, 0xF767, 0x9C63, 0xF768, 0x9C64, 0xF769, 0x9C65, 0xF76A, 0x9C66, 0xF76B, 0x9C67, 0xF76C, 0x9C68, 0xF76D, 0x9C69, 0xF76E, 0x9C6A, 0xF76F, 0x9C6B, 0xF770, 0x9C6C, 0xF771, 0x9C6D, 0xF772, 0x9C6E, 0xF773, 0x9C6F, 0xF774, 0x9C70, 0xF775, 0x9C71, 0xF776, 0x9C72, 0xF777, 0x9C73, 0xF778, 0x9C74, 0xF779, 0x9C75, 0xF77A, 0x9C76, 0xF77B, 0x9C77, 0xF77C, 0x9C78, 0xF77D, 0x9C79, 0xF77E, 0x9C7A, 0xF780, 0x9C7B, 0xF781, 0x9C7D, 0xF782, 0x9C7E, 0xF783, 0x9C80, 0xF784, 0x9C83, 0xF785, 0x9C84, 0xF786, 0x9C89, 0xF787, 0x9C8A, 0xF788, 0x9C8C, 0xF789, 0x9C8F, 0xF78A, 0x9C93, 0xF78B, 0x9C96, 0xF78C, 0x9C97, 0xF78D, 0x9C98, 0xF78E, 0x9C99, 0xF78F, 0x9C9D, 0xF790, 0x9CAA, 0xF791, 0x9CAC, 0xF792, 0x9CAF, 0xF793, 0x9CB9, 0xF794, 0x9CBE, 0xF795, 0x9CBF, 0xF796, 0x9CC0, 0xF797, 0x9CC1, 0xF798, 0x9CC2, 0xF799, 0x9CC8, 0xF79A, 0x9CC9, 0xF79B, 0x9CD1, 0xF79C, 0x9CD2, 0xF79D, 0x9CDA, 0xF79E, 0x9CDB, 0xF79F, 0x9CE0, 0xF7A0, 0x9CE1, 0xF7A1, 0x9CCC, 0xF7A2, 0x9CCD, 0xF7A3, 0x9CCE, 0xF7A4, 0x9CCF, 0xF7A5, 0x9CD0, 0xF7A6, 0x9CD3, 0xF7A7, 0x9CD4, 0xF7A8, 0x9CD5, 0xF7A9, 0x9CD7, 0xF7AA, 0x9CD8, 0xF7AB, 0x9CD9, 0xF7AC, 0x9CDC, 0xF7AD, 0x9CDD, 0xF7AE, 0x9CDF, 0xF7AF, 0x9CE2, 0xF7B0, 0x977C, 0xF7B1, 0x9785, 0xF7B2, 0x9791, 0xF7B3, 0x9792, 0xF7B4, 0x9794, 0xF7B5, 0x97AF, 0xF7B6, 0x97AB, 0xF7B7, 0x97A3, 0xF7B8, 0x97B2, 0xF7B9, 0x97B4, 0xF7BA, 0x9AB1, 0xF7BB, 0x9AB0, 0xF7BC, 0x9AB7, 0xF7BD, 0x9E58, 0xF7BE, 0x9AB6, 0xF7BF, 0x9ABA, 0xF7C0, 0x9ABC, 0xF7C1, 0x9AC1, 0xF7C2, 0x9AC0, 0xF7C3, 0x9AC5, 0xF7C4, 0x9AC2, 0xF7C5, 0x9ACB, 0xF7C6, 0x9ACC, 0xF7C7, 0x9AD1, 0xF7C8, 0x9B45, 0xF7C9, 0x9B43, 0xF7CA, 0x9B47, 0xF7CB, 0x9B49, 0xF7CC, 0x9B48, 0xF7CD, 0x9B4D, 0xF7CE, 0x9B51, 0xF7CF, 0x98E8, 0xF7D0, 0x990D, 0xF7D1, 0x992E, 0xF7D2, 0x9955, 0xF7D3, 0x9954, 0xF7D4, 0x9ADF, 0xF7D5, 0x9AE1, 0xF7D6, 0x9AE6, 0xF7D7, 0x9AEF, 0xF7D8, 0x9AEB, 0xF7D9, 0x9AFB, 0xF7DA, 0x9AED, 0xF7DB, 0x9AF9, 0xF7DC, 0x9B08, 0xF7DD, 0x9B0F, 0xF7DE, 0x9B13, 0xF7DF, 0x9B1F, 0xF7E0, 0x9B23, 0xF7E1, 0x9EBD, 0xF7E2, 0x9EBE, 0xF7E3, 0x7E3B, 0xF7E4, 0x9E82, 0xF7E5, 0x9E87, 0xF7E6, 0x9E88, 0xF7E7, 0x9E8B, 0xF7E8, 0x9E92, 0xF7E9, 0x93D6, 0xF7EA, 0x9E9D, 0xF7EB, 0x9E9F, 0xF7EC, 0x9EDB, 0xF7ED, 0x9EDC, 0xF7EE, 0x9EDD, 0xF7EF, 0x9EE0, 0xF7F0, 0x9EDF, 0xF7F1, 0x9EE2, 0xF7F2, 0x9EE9, 0xF7F3, 0x9EE7, 0xF7F4, 0x9EE5, 0xF7F5, 0x9EEA, 0xF7F6, 0x9EEF, 0xF7F7, 0x9F22, 0xF7F8, 0x9F2C, 0xF7F9, 0x9F2F, 0xF7FA, 0x9F39, 0xF7FB, 0x9F37, 0xF7FC, 0x9F3D, 0xF7FD, 0x9F3E, 0xF7FE, 0x9F44, 0xF840, 0x9CE3, 0xF841, 0x9CE4, 0xF842, 0x9CE5, 0xF843, 0x9CE6, 0xF844, 0x9CE7, 0xF845, 0x9CE8, 0xF846, 0x9CE9, 0xF847, 0x9CEA, 0xF848, 0x9CEB, 0xF849, 0x9CEC, 0xF84A, 0x9CED, 0xF84B, 0x9CEE, 0xF84C, 0x9CEF, 0xF84D, 0x9CF0, 0xF84E, 0x9CF1, 0xF84F, 0x9CF2, 0xF850, 0x9CF3, 0xF851, 0x9CF4, 0xF852, 0x9CF5, 0xF853, 0x9CF6, 0xF854, 0x9CF7, 0xF855, 0x9CF8, 0xF856, 0x9CF9, 0xF857, 0x9CFA, 0xF858, 0x9CFB, 0xF859, 0x9CFC, 0xF85A, 0x9CFD, 0xF85B, 0x9CFE, 0xF85C, 0x9CFF, 0xF85D, 0x9D00, 0xF85E, 0x9D01, 0xF85F, 0x9D02, 0xF860, 0x9D03, 0xF861, 0x9D04, 0xF862, 0x9D05, 0xF863, 0x9D06, 0xF864, 0x9D07, 0xF865, 0x9D08, 0xF866, 0x9D09, 0xF867, 0x9D0A, 0xF868, 0x9D0B, 0xF869, 0x9D0C, 0xF86A, 0x9D0D, 0xF86B, 0x9D0E, 0xF86C, 0x9D0F, 0xF86D, 0x9D10, 0xF86E, 0x9D11, 0xF86F, 0x9D12, 0xF870, 0x9D13, 0xF871, 0x9D14, 0xF872, 0x9D15, 0xF873, 0x9D16, 0xF874, 0x9D17, 0xF875, 0x9D18, 0xF876, 0x9D19, 0xF877, 0x9D1A, 0xF878, 0x9D1B, 0xF879, 0x9D1C, 0xF87A, 0x9D1D, 0xF87B, 0x9D1E, 0xF87C, 0x9D1F, 0xF87D, 0x9D20, 0xF87E, 0x9D21, 0xF880, 0x9D22, 0xF881, 0x9D23, 0xF882, 0x9D24, 0xF883, 0x9D25, 0xF884, 0x9D26, 0xF885, 0x9D27, 0xF886, 0x9D28, 0xF887, 0x9D29, 0xF888, 0x9D2A, 0xF889, 0x9D2B, 0xF88A, 0x9D2C, 0xF88B, 0x9D2D, 0xF88C, 0x9D2E, 0xF88D, 0x9D2F, 0xF88E, 0x9D30, 0xF88F, 0x9D31, 0xF890, 0x9D32, 0xF891, 0x9D33, 0xF892, 0x9D34, 0xF893, 0x9D35, 0xF894, 0x9D36, 0xF895, 0x9D37, 0xF896, 0x9D38, 0xF897, 0x9D39, 0xF898, 0x9D3A, 0xF899, 0x9D3B, 0xF89A, 0x9D3C, 0xF89B, 0x9D3D, 0xF89C, 0x9D3E, 0xF89D, 0x9D3F, 0xF89E, 0x9D40, 0xF89F, 0x9D41, 0xF8A0, 0x9D42, 0xF940, 0x9D43, 0xF941, 0x9D44, 0xF942, 0x9D45, 0xF943, 0x9D46, 0xF944, 0x9D47, 0xF945, 0x9D48, 0xF946, 0x9D49, 0xF947, 0x9D4A, 0xF948, 0x9D4B, 0xF949, 0x9D4C, 0xF94A, 0x9D4D, 0xF94B, 0x9D4E, 0xF94C, 0x9D4F, 0xF94D, 0x9D50, 0xF94E, 0x9D51, 0xF94F, 0x9D52, 0xF950, 0x9D53, 0xF951, 0x9D54, 0xF952, 0x9D55, 0xF953, 0x9D56, 0xF954, 0x9D57, 0xF955, 0x9D58, 0xF956, 0x9D59, 0xF957, 0x9D5A, 0xF958, 0x9D5B, 0xF959, 0x9D5C, 0xF95A, 0x9D5D, 0xF95B, 0x9D5E, 0xF95C, 0x9D5F, 0xF95D, 0x9D60, 0xF95E, 0x9D61, 0xF95F, 0x9D62, 0xF960, 0x9D63, 0xF961, 0x9D64, 0xF962, 0x9D65, 0xF963, 0x9D66, 0xF964, 0x9D67, 0xF965, 0x9D68, 0xF966, 0x9D69, 0xF967, 0x9D6A, 0xF968, 0x9D6B, 0xF969, 0x9D6C, 0xF96A, 0x9D6D, 0xF96B, 0x9D6E, 0xF96C, 0x9D6F, 0xF96D, 0x9D70, 0xF96E, 0x9D71, 0xF96F, 0x9D72, 0xF970, 0x9D73, 0xF971, 0x9D74, 0xF972, 0x9D75, 0xF973, 0x9D76, 0xF974, 0x9D77, 0xF975, 0x9D78, 0xF976, 0x9D79, 0xF977, 0x9D7A, 0xF978, 0x9D7B, 0xF979, 0x9D7C, 0xF97A, 0x9D7D, 0xF97B, 0x9D7E, 0xF97C, 0x9D7F, 0xF97D, 0x9D80, 0xF97E, 0x9D81, 0xF980, 0x9D82, 0xF981, 0x9D83, 0xF982, 0x9D84, 0xF983, 0x9D85, 0xF984, 0x9D86, 0xF985, 0x9D87, 0xF986, 0x9D88, 0xF987, 0x9D89, 0xF988, 0x9D8A, 0xF989, 0x9D8B, 0xF98A, 0x9D8C, 0xF98B, 0x9D8D, 0xF98C, 0x9D8E, 0xF98D, 0x9D8F, 0xF98E, 0x9D90, 0xF98F, 0x9D91, 0xF990, 0x9D92, 0xF991, 0x9D93, 0xF992, 0x9D94, 0xF993, 0x9D95, 0xF994, 0x9D96, 0xF995, 0x9D97, 0xF996, 0x9D98, 0xF997, 0x9D99, 0xF998, 0x9D9A, 0xF999, 0x9D9B, 0xF99A, 0x9D9C, 0xF99B, 0x9D9D, 0xF99C, 0x9D9E, 0xF99D, 0x9D9F, 0xF99E, 0x9DA0, 0xF99F, 0x9DA1, 0xF9A0, 0x9DA2, 0xFA40, 0x9DA3, 0xFA41, 0x9DA4, 0xFA42, 0x9DA5, 0xFA43, 0x9DA6, 0xFA44, 0x9DA7, 0xFA45, 0x9DA8, 0xFA46, 0x9DA9, 0xFA47, 0x9DAA, 0xFA48, 0x9DAB, 0xFA49, 0x9DAC, 0xFA4A, 0x9DAD, 0xFA4B, 0x9DAE, 0xFA4C, 0x9DAF, 0xFA4D, 0x9DB0, 0xFA4E, 0x9DB1, 0xFA4F, 0x9DB2, 0xFA50, 0x9DB3, 0xFA51, 0x9DB4, 0xFA52, 0x9DB5, 0xFA53, 0x9DB6, 0xFA54, 0x9DB7, 0xFA55, 0x9DB8, 0xFA56, 0x9DB9, 0xFA57, 0x9DBA, 0xFA58, 0x9DBB, 0xFA59, 0x9DBC, 0xFA5A, 0x9DBD, 0xFA5B, 0x9DBE, 0xFA5C, 0x9DBF, 0xFA5D, 0x9DC0, 0xFA5E, 0x9DC1, 0xFA5F, 0x9DC2, 0xFA60, 0x9DC3, 0xFA61, 0x9DC4, 0xFA62, 0x9DC5, 0xFA63, 0x9DC6, 0xFA64, 0x9DC7, 0xFA65, 0x9DC8, 0xFA66, 0x9DC9, 0xFA67, 0x9DCA, 0xFA68, 0x9DCB, 0xFA69, 0x9DCC, 0xFA6A, 0x9DCD, 0xFA6B, 0x9DCE, 0xFA6C, 0x9DCF, 0xFA6D, 0x9DD0, 0xFA6E, 0x9DD1, 0xFA6F, 0x9DD2, 0xFA70, 0x9DD3, 0xFA71, 0x9DD4, 0xFA72, 0x9DD5, 0xFA73, 0x9DD6, 0xFA74, 0x9DD7, 0xFA75, 0x9DD8, 0xFA76, 0x9DD9, 0xFA77, 0x9DDA, 0xFA78, 0x9DDB, 0xFA79, 0x9DDC, 0xFA7A, 0x9DDD, 0xFA7B, 0x9DDE, 0xFA7C, 0x9DDF, 0xFA7D, 0x9DE0, 0xFA7E, 0x9DE1, 0xFA80, 0x9DE2, 0xFA81, 0x9DE3, 0xFA82, 0x9DE4, 0xFA83, 0x9DE5, 0xFA84, 0x9DE6, 0xFA85, 0x9DE7, 0xFA86, 0x9DE8, 0xFA87, 0x9DE9, 0xFA88, 0x9DEA, 0xFA89, 0x9DEB, 0xFA8A, 0x9DEC, 0xFA8B, 0x9DED, 0xFA8C, 0x9DEE, 0xFA8D, 0x9DEF, 0xFA8E, 0x9DF0, 0xFA8F, 0x9DF1, 0xFA90, 0x9DF2, 0xFA91, 0x9DF3, 0xFA92, 0x9DF4, 0xFA93, 0x9DF5, 0xFA94, 0x9DF6, 0xFA95, 0x9DF7, 0xFA96, 0x9DF8, 0xFA97, 0x9DF9, 0xFA98, 0x9DFA, 0xFA99, 0x9DFB, 0xFA9A, 0x9DFC, 0xFA9B, 0x9DFD, 0xFA9C, 0x9DFE, 0xFA9D, 0x9DFF, 0xFA9E, 0x9E00, 0xFA9F, 0x9E01, 0xFAA0, 0x9E02, 0xFB40, 0x9E03, 0xFB41, 0x9E04, 0xFB42, 0x9E05, 0xFB43, 0x9E06, 0xFB44, 0x9E07, 0xFB45, 0x9E08, 0xFB46, 0x9E09, 0xFB47, 0x9E0A, 0xFB48, 0x9E0B, 0xFB49, 0x9E0C, 0xFB4A, 0x9E0D, 0xFB4B, 0x9E0E, 0xFB4C, 0x9E0F, 0xFB4D, 0x9E10, 0xFB4E, 0x9E11, 0xFB4F, 0x9E12, 0xFB50, 0x9E13, 0xFB51, 0x9E14, 0xFB52, 0x9E15, 0xFB53, 0x9E16, 0xFB54, 0x9E17, 0xFB55, 0x9E18, 0xFB56, 0x9E19, 0xFB57, 0x9E1A, 0xFB58, 0x9E1B, 0xFB59, 0x9E1C, 0xFB5A, 0x9E1D, 0xFB5B, 0x9E1E, 0xFB5C, 0x9E24, 0xFB5D, 0x9E27, 0xFB5E, 0x9E2E, 0xFB5F, 0x9E30, 0xFB60, 0x9E34, 0xFB61, 0x9E3B, 0xFB62, 0x9E3C, 0xFB63, 0x9E40, 0xFB64, 0x9E4D, 0xFB65, 0x9E50, 0xFB66, 0x9E52, 0xFB67, 0x9E53, 0xFB68, 0x9E54, 0xFB69, 0x9E56, 0xFB6A, 0x9E59, 0xFB6B, 0x9E5D, 0xFB6C, 0x9E5F, 0xFB6D, 0x9E60, 0xFB6E, 0x9E61, 0xFB6F, 0x9E62, 0xFB70, 0x9E65, 0xFB71, 0x9E6E, 0xFB72, 0x9E6F, 0xFB73, 0x9E72, 0xFB74, 0x9E74, 0xFB75, 0x9E75, 0xFB76, 0x9E76, 0xFB77, 0x9E77, 0xFB78, 0x9E78, 0xFB79, 0x9E79, 0xFB7A, 0x9E7A, 0xFB7B, 0x9E7B, 0xFB7C, 0x9E7C, 0xFB7D, 0x9E7D, 0xFB7E, 0x9E80, 0xFB80, 0x9E81, 0xFB81, 0x9E83, 0xFB82, 0x9E84, 0xFB83, 0x9E85, 0xFB84, 0x9E86, 0xFB85, 0x9E89, 0xFB86, 0x9E8A, 0xFB87, 0x9E8C, 0xFB88, 0x9E8D, 0xFB89, 0x9E8E, 0xFB8A, 0x9E8F, 0xFB8B, 0x9E90, 0xFB8C, 0x9E91, 0xFB8D, 0x9E94, 0xFB8E, 0x9E95, 0xFB8F, 0x9E96, 0xFB90, 0x9E97, 0xFB91, 0x9E98, 0xFB92, 0x9E99, 0xFB93, 0x9E9A, 0xFB94, 0x9E9B, 0xFB95, 0x9E9C, 0xFB96, 0x9E9E, 0xFB97, 0x9EA0, 0xFB98, 0x9EA1, 0xFB99, 0x9EA2, 0xFB9A, 0x9EA3, 0xFB9B, 0x9EA4, 0xFB9C, 0x9EA5, 0xFB9D, 0x9EA7, 0xFB9E, 0x9EA8, 0xFB9F, 0x9EA9, 0xFBA0, 0x9EAA, 0xFC40, 0x9EAB, 0xFC41, 0x9EAC, 0xFC42, 0x9EAD, 0xFC43, 0x9EAE, 0xFC44, 0x9EAF, 0xFC45, 0x9EB0, 0xFC46, 0x9EB1, 0xFC47, 0x9EB2, 0xFC48, 0x9EB3, 0xFC49, 0x9EB5, 0xFC4A, 0x9EB6, 0xFC4B, 0x9EB7, 0xFC4C, 0x9EB9, 0xFC4D, 0x9EBA, 0xFC4E, 0x9EBC, 0xFC4F, 0x9EBF, 0xFC50, 0x9EC0, 0xFC51, 0x9EC1, 0xFC52, 0x9EC2, 0xFC53, 0x9EC3, 0xFC54, 0x9EC5, 0xFC55, 0x9EC6, 0xFC56, 0x9EC7, 0xFC57, 0x9EC8, 0xFC58, 0x9ECA, 0xFC59, 0x9ECB, 0xFC5A, 0x9ECC, 0xFC5B, 0x9ED0, 0xFC5C, 0x9ED2, 0xFC5D, 0x9ED3, 0xFC5E, 0x9ED5, 0xFC5F, 0x9ED6, 0xFC60, 0x9ED7, 0xFC61, 0x9ED9, 0xFC62, 0x9EDA, 0xFC63, 0x9EDE, 0xFC64, 0x9EE1, 0xFC65, 0x9EE3, 0xFC66, 0x9EE4, 0xFC67, 0x9EE6, 0xFC68, 0x9EE8, 0xFC69, 0x9EEB, 0xFC6A, 0x9EEC, 0xFC6B, 0x9EED, 0xFC6C, 0x9EEE, 0xFC6D, 0x9EF0, 0xFC6E, 0x9EF1, 0xFC6F, 0x9EF2, 0xFC70, 0x9EF3, 0xFC71, 0x9EF4, 0xFC72, 0x9EF5, 0xFC73, 0x9EF6, 0xFC74, 0x9EF7, 0xFC75, 0x9EF8, 0xFC76, 0x9EFA, 0xFC77, 0x9EFD, 0xFC78, 0x9EFF, 0xFC79, 0x9F00, 0xFC7A, 0x9F01, 0xFC7B, 0x9F02, 0xFC7C, 0x9F03, 0xFC7D, 0x9F04, 0xFC7E, 0x9F05, 0xFC80, 0x9F06, 0xFC81, 0x9F07, 0xFC82, 0x9F08, 0xFC83, 0x9F09, 0xFC84, 0x9F0A, 0xFC85, 0x9F0C, 0xFC86, 0x9F0F, 0xFC87, 0x9F11, 0xFC88, 0x9F12, 0xFC89, 0x9F14, 0xFC8A, 0x9F15, 0xFC8B, 0x9F16, 0xFC8C, 0x9F18, 0xFC8D, 0x9F1A, 0xFC8E, 0x9F1B, 0xFC8F, 0x9F1C, 0xFC90, 0x9F1D, 0xFC91, 0x9F1E, 0xFC92, 0x9F1F, 0xFC93, 0x9F21, 0xFC94, 0x9F23, 0xFC95, 0x9F24, 0xFC96, 0x9F25, 0xFC97, 0x9F26, 0xFC98, 0x9F27, 0xFC99, 0x9F28, 0xFC9A, 0x9F29, 0xFC9B, 0x9F2A, 0xFC9C, 0x9F2B, 0xFC9D, 0x9F2D, 0xFC9E, 0x9F2E, 0xFC9F, 0x9F30, 0xFCA0, 0x9F31, 0xFD40, 0x9F32, 0xFD41, 0x9F33, 0xFD42, 0x9F34, 0xFD43, 0x9F35, 0xFD44, 0x9F36, 0xFD45, 0x9F38, 0xFD46, 0x9F3A, 0xFD47, 0x9F3C, 0xFD48, 0x9F3F, 0xFD49, 0x9F40, 0xFD4A, 0x9F41, 0xFD4B, 0x9F42, 0xFD4C, 0x9F43, 0xFD4D, 0x9F45, 0xFD4E, 0x9F46, 0xFD4F, 0x9F47, 0xFD50, 0x9F48, 0xFD51, 0x9F49, 0xFD52, 0x9F4A, 0xFD53, 0x9F4B, 0xFD54, 0x9F4C, 0xFD55, 0x9F4D, 0xFD56, 0x9F4E, 0xFD57, 0x9F4F, 0xFD58, 0x9F52, 0xFD59, 0x9F53, 0xFD5A, 0x9F54, 0xFD5B, 0x9F55, 0xFD5C, 0x9F56, 0xFD5D, 0x9F57, 0xFD5E, 0x9F58, 0xFD5F, 0x9F59, 0xFD60, 0x9F5A, 0xFD61, 0x9F5B, 0xFD62, 0x9F5C, 0xFD63, 0x9F5D, 0xFD64, 0x9F5E, 0xFD65, 0x9F5F, 0xFD66, 0x9F60, 0xFD67, 0x9F61, 0xFD68, 0x9F62, 0xFD69, 0x9F63, 0xFD6A, 0x9F64, 0xFD6B, 0x9F65, 0xFD6C, 0x9F66, 0xFD6D, 0x9F67, 0xFD6E, 0x9F68, 0xFD6F, 0x9F69, 0xFD70, 0x9F6A, 0xFD71, 0x9F6B, 0xFD72, 0x9F6C, 0xFD73, 0x9F6D, 0xFD74, 0x9F6E, 0xFD75, 0x9F6F, 0xFD76, 0x9F70, 0xFD77, 0x9F71, 0xFD78, 0x9F72, 0xFD79, 0x9F73, 0xFD7A, 0x9F74, 0xFD7B, 0x9F75, 0xFD7C, 0x9F76, 0xFD7D, 0x9F77, 0xFD7E, 0x9F78, 0xFD80, 0x9F79, 0xFD81, 0x9F7A, 0xFD82, 0x9F7B, 0xFD83, 0x9F7C, 0xFD84, 0x9F7D, 0xFD85, 0x9F7E, 0xFD86, 0x9F81, 0xFD87, 0x9F82, 0xFD88, 0x9F8D, 0xFD89, 0x9F8E, 0xFD8A, 0x9F8F, 0xFD8B, 0x9F90, 0xFD8C, 0x9F91, 0xFD8D, 0x9F92, 0xFD8E, 0x9F93, 0xFD8F, 0x9F94, 0xFD90, 0x9F95, 0xFD91, 0x9F96, 0xFD92, 0x9F97, 0xFD93, 0x9F98, 0xFD94, 0x9F9C, 0xFD95, 0x9F9D, 0xFD96, 0x9F9E, 0xFD97, 0x9FA1, 0xFD98, 0x9FA2, 0xFD99, 0x9FA3, 0xFD9A, 0x9FA4, 0xFD9B, 0x9FA5, 0xFD9C, 0xF92C, 0xFD9D, 0xF979, 0xFD9E, 0xF995, 0xFD9F, 0xF9E7, 0xFDA0, 0xF9F1, 0xFE40, 0xFA0C, 0xFE41, 0xFA0D, 0xFE42, 0xFA0E, 0xFE43, 0xFA0F, 0xFE44, 0xFA11, 0xFE45, 0xFA13, 0xFE46, 0xFA14, 0xFE47, 0xFA18, 0xFE48, 0xFA1F, 0xFE49, 0xFA20, 0xFE4A, 0xFA21, 0xFE4B, 0xFA23, 0xFE4C, 0xFA24, 0xFE4D, 0xFA27, 0xFE4E, 0xFA28, 0xFE4F, 0xFA29, 0, 0 }; #endif #if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */ static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ 0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6, 0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6, 0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF, 0x00D8, 0xA8AA, 0x00DE, 0xA8AD, 0x00DF, 0xA9AC, 0x00E6, 0xA9A1, 0x00F0, 0xA9A3, 0x00F7, 0xA1C0, 0x00F8, 0xA9AA, 0x00FE, 0xA9AD, 0x0111, 0xA9A2, 0x0126, 0xA8A4, 0x0127, 0xA9A4, 0x0131, 0xA9A5, 0x0132, 0xA8A6, 0x0133, 0xA9A6, 0x0138, 0xA9A7, 0x013F, 0xA8A8, 0x0140, 0xA9A8, 0x0141, 0xA8A9, 0x0142, 0xA9A9, 0x0149, 0xA9B0, 0x014A, 0xA8AF, 0x014B, 0xA9AF, 0x0152, 0xA8AB, 0x0153, 0xA9AB, 0x0166, 0xA8AE, 0x0167, 0xA9AE, 0x02C7, 0xA2A7, 0x02D0, 0xA2B0, 0x02D8, 0xA2A8, 0x02D9, 0xA2AB, 0x02DA, 0xA2AA, 0x02DB, 0xA2AD, 0x02DD, 0xA2A9, 0x0391, 0xA5C1, 0x0392, 0xA5C2, 0x0393, 0xA5C3, 0x0394, 0xA5C4, 0x0395, 0xA5C5, 0x0396, 0xA5C6, 0x0397, 0xA5C7, 0x0398, 0xA5C8, 0x0399, 0xA5C9, 0x039A, 0xA5CA, 0x039B, 0xA5CB, 0x039C, 0xA5CC, 0x039D, 0xA5CD, 0x039E, 0xA5CE, 0x039F, 0xA5CF, 0x03A0, 0xA5D0, 0x03A1, 0xA5D1, 0x03A3, 0xA5D2, 0x03A4, 0xA5D3, 0x03A5, 0xA5D4, 0x03A6, 0xA5D5, 0x03A7, 0xA5D6, 0x03A8, 0xA5D7, 0x03A9, 0xA5D8, 0x03B1, 0xA5E1, 0x03B2, 0xA5E2, 0x03B3, 0xA5E3, 0x03B4, 0xA5E4, 0x03B5, 0xA5E5, 0x03B6, 0xA5E6, 0x03B7, 0xA5E7, 0x03B8, 0xA5E8, 0x03B9, 0xA5E9, 0x03BA, 0xA5EA, 0x03BB, 0xA5EB, 0x03BC, 0xA5EC, 0x03BD, 0xA5ED, 0x03BE, 0xA5EE, 0x03BF, 0xA5EF, 0x03C0, 0xA5F0, 0x03C1, 0xA5F1, 0x03C3, 0xA5F2, 0x03C4, 0xA5F3, 0x03C5, 0xA5F4, 0x03C6, 0xA5F5, 0x03C7, 0xA5F6, 0x03C8, 0xA5F7, 0x03C9, 0xA5F8, 0x0401, 0xACA7, 0x0410, 0xACA1, 0x0411, 0xACA2, 0x0412, 0xACA3, 0x0413, 0xACA4, 0x0414, 0xACA5, 0x0415, 0xACA6, 0x0416, 0xACA8, 0x0417, 0xACA9, 0x0418, 0xACAA, 0x0419, 0xACAB, 0x041A, 0xACAC, 0x041B, 0xACAD, 0x041C, 0xACAE, 0x041D, 0xACAF, 0x041E, 0xACB0, 0x041F, 0xACB1, 0x0420, 0xACB2, 0x0421, 0xACB3, 0x0422, 0xACB4, 0x0423, 0xACB5, 0x0424, 0xACB6, 0x0425, 0xACB7, 0x0426, 0xACB8, 0x0427, 0xACB9, 0x0428, 0xACBA, 0x0429, 0xACBB, 0x042A, 0xACBC, 0x042B, 0xACBD, 0x042C, 0xACBE, 0x042D, 0xACBF, 0x042E, 0xACC0, 0x042F, 0xACC1, 0x0430, 0xACD1, 0x0431, 0xACD2, 0x0432, 0xACD3, 0x0433, 0xACD4, 0x0434, 0xACD5, 0x0435, 0xACD6, 0x0436, 0xACD8, 0x0437, 0xACD9, 0x0438, 0xACDA, 0x0439, 0xACDB, 0x043A, 0xACDC, 0x043B, 0xACDD, 0x043C, 0xACDE, 0x043D, 0xACDF, 0x043E, 0xACE0, 0x043F, 0xACE1, 0x0440, 0xACE2, 0x0441, 0xACE3, 0x0442, 0xACE4, 0x0443, 0xACE5, 0x0444, 0xACE6, 0x0445, 0xACE7, 0x0446, 0xACE8, 0x0447, 0xACE9, 0x0448, 0xACEA, 0x0449, 0xACEB, 0x044A, 0xACEC, 0x044B, 0xACED, 0x044C, 0xACEE, 0x044D, 0xACEF, 0x044E, 0xACF0, 0x044F, 0xACF1, 0x0451, 0xACD7, 0x2015, 0xA1AA, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, 0x2020, 0xA2D3, 0x2021, 0xA2D4, 0x2025, 0xA1A5, 0x2026, 0xA1A6, 0x2030, 0xA2B6, 0x2032, 0xA1C7, 0x2033, 0xA1C8, 0x203B, 0xA1D8, 0x2074, 0xA9F9, 0x207F, 0xA9FA, 0x2081, 0xA9FB, 0x2082, 0xA9FC, 0x2083, 0xA9FD, 0x2084, 0xA9FE, 0x20AC, 0xA2E6, 0x2103, 0xA1C9, 0x2109, 0xA2B5, 0x2113, 0xA7A4, 0x2116, 0xA2E0, 0x2121, 0xA2E5, 0x2122, 0xA2E2, 0x2126, 0xA7D9, 0x212B, 0xA1CA, 0x2153, 0xA8F7, 0x2154, 0xA8F8, 0x215B, 0xA8FB, 0x215C, 0xA8FC, 0x215D, 0xA8FD, 0x215E, 0xA8FE, 0x2160, 0xA5B0, 0x2161, 0xA5B1, 0x2162, 0xA5B2, 0x2163, 0xA5B3, 0x2164, 0xA5B4, 0x2165, 0xA5B5, 0x2166, 0xA5B6, 0x2167, 0xA5B7, 0x2168, 0xA5B8, 0x2169, 0xA5B9, 0x2170, 0xA5A1, 0x2171, 0xA5A2, 0x2172, 0xA5A3, 0x2173, 0xA5A4, 0x2174, 0xA5A5, 0x2175, 0xA5A6, 0x2176, 0xA5A7, 0x2177, 0xA5A8, 0x2178, 0xA5A9, 0x2179, 0xA5AA, 0x2190, 0xA1E7, 0x2191, 0xA1E8, 0x2192, 0xA1E6, 0x2193, 0xA1E9, 0x2194, 0xA1EA, 0x2195, 0xA2D5, 0x2196, 0xA2D8, 0x2197, 0xA2D6, 0x2198, 0xA2D9, 0x2199, 0xA2D7, 0x21D2, 0xA2A1, 0x21D4, 0xA2A2, 0x2200, 0xA2A3, 0x2202, 0xA1D3, 0x2203, 0xA2A4, 0x2207, 0xA1D4, 0x2208, 0xA1F4, 0x220B, 0xA1F5, 0x220F, 0xA2B3, 0x2211, 0xA2B2, 0x221A, 0xA1EE, 0x221D, 0xA1F0, 0x221E, 0xA1C4, 0x2220, 0xA1D0, 0x2225, 0xA1AB, 0x2227, 0xA1FC, 0x2228, 0xA1FD, 0x2229, 0xA1FB, 0x222A, 0xA1FA, 0x222B, 0xA1F2, 0x222C, 0xA1F3, 0x222E, 0xA2B1, 0x2234, 0xA1C5, 0x2235, 0xA1F1, 0x223C, 0xA1AD, 0x223D, 0xA1EF, 0x2252, 0xA1D6, 0x2260, 0xA1C1, 0x2261, 0xA1D5, 0x2264, 0xA1C2, 0x2265, 0xA1C3, 0x226A, 0xA1EC, 0x226B, 0xA1ED, 0x2282, 0xA1F8, 0x2283, 0xA1F9, 0x2286, 0xA1F6, 0x2287, 0xA1F7, 0x2299, 0xA2C1, 0x22A5, 0xA1D1, 0x2312, 0xA1D2, 0x2460, 0xA8E7, 0x2461, 0xA8E8, 0x2462, 0xA8E9, 0x2463, 0xA8EA, 0x2464, 0xA8EB, 0x2465, 0xA8EC, 0x2466, 0xA8ED, 0x2467, 0xA8EE, 0x2468, 0xA8EF, 0x2469, 0xA8F0, 0x246A, 0xA8F1, 0x246B, 0xA8F2, 0x246C, 0xA8F3, 0x246D, 0xA8F4, 0x246E, 0xA8F5, 0x2474, 0xA9E7, 0x2475, 0xA9E8, 0x2476, 0xA9E9, 0x2477, 0xA9EA, 0x2478, 0xA9EB, 0x2479, 0xA9EC, 0x247A, 0xA9ED, 0x247B, 0xA9EE, 0x247C, 0xA9EF, 0x247D, 0xA9F0, 0x247E, 0xA9F1, 0x247F, 0xA9F2, 0x2480, 0xA9F3, 0x2481, 0xA9F4, 0x2482, 0xA9F5, 0x249C, 0xA9CD, 0x249D, 0xA9CE, 0x249E, 0xA9CF, 0x249F, 0xA9D0, 0x24A0, 0xA9D1, 0x24A1, 0xA9D2, 0x24A2, 0xA9D3, 0x24A3, 0xA9D4, 0x24A4, 0xA9D5, 0x24A5, 0xA9D6, 0x24A6, 0xA9D7, 0x24A7, 0xA9D8, 0x24A8, 0xA9D9, 0x24A9, 0xA9DA, 0x24AA, 0xA9DB, 0x24AB, 0xA9DC, 0x24AC, 0xA9DD, 0x24AD, 0xA9DE, 0x24AE, 0xA9DF, 0x24AF, 0xA9E0, 0x24B0, 0xA9E1, 0x24B1, 0xA9E2, 0x24B2, 0xA9E3, 0x24B3, 0xA9E4, 0x24B4, 0xA9E5, 0x24B5, 0xA9E6, 0x24D0, 0xA8CD, 0x24D1, 0xA8CE, 0x24D2, 0xA8CF, 0x24D3, 0xA8D0, 0x24D4, 0xA8D1, 0x24D5, 0xA8D2, 0x24D6, 0xA8D3, 0x24D7, 0xA8D4, 0x24D8, 0xA8D5, 0x24D9, 0xA8D6, 0x24DA, 0xA8D7, 0x24DB, 0xA8D8, 0x24DC, 0xA8D9, 0x24DD, 0xA8DA, 0x24DE, 0xA8DB, 0x24DF, 0xA8DC, 0x24E0, 0xA8DD, 0x24E1, 0xA8DE, 0x24E2, 0xA8DF, 0x24E3, 0xA8E0, 0x24E4, 0xA8E1, 0x24E5, 0xA8E2, 0x24E6, 0xA8E3, 0x24E7, 0xA8E4, 0x24E8, 0xA8E5, 0x24E9, 0xA8E6, 0x2500, 0xA6A1, 0x2501, 0xA6AC, 0x2502, 0xA6A2, 0x2503, 0xA6AD, 0x250C, 0xA6A3, 0x250D, 0xA6C8, 0x250E, 0xA6C7, 0x250F, 0xA6AE, 0x2510, 0xA6A4, 0x2511, 0xA6C2, 0x2512, 0xA6C1, 0x2513, 0xA6AF, 0x2514, 0xA6A6, 0x2515, 0xA6C6, 0x2516, 0xA6C5, 0x2517, 0xA6B1, 0x2518, 0xA6A5, 0x2519, 0xA6C4, 0x251A, 0xA6C3, 0x251B, 0xA6B0, 0x251C, 0xA6A7, 0x251D, 0xA6BC, 0x251E, 0xA6C9, 0x251F, 0xA6CA, 0x2520, 0xA6B7, 0x2521, 0xA6CB, 0x2522, 0xA6CC, 0x2523, 0xA6B2, 0x2524, 0xA6A9, 0x2525, 0xA6BE, 0x2526, 0xA6CD, 0x2527, 0xA6CE, 0x2528, 0xA6B9, 0x2529, 0xA6CF, 0x252A, 0xA6D0, 0x252B, 0xA6B4, 0x252C, 0xA6A8, 0x252D, 0xA6D1, 0x252E, 0xA6D2, 0x252F, 0xA6B8, 0x2530, 0xA6BD, 0x2531, 0xA6D3, 0x2532, 0xA6D4, 0x2533, 0xA6B3, 0x2534, 0xA6AA, 0x2535, 0xA6D5, 0x2536, 0xA6D6, 0x2537, 0xA6BA, 0x2538, 0xA6BF, 0x2539, 0xA6D7, 0x253A, 0xA6D8, 0x253B, 0xA6B5, 0x253C, 0xA6AB, 0x253D, 0xA6D9, 0x253E, 0xA6DA, 0x253F, 0xA6BB, 0x2540, 0xA6DB, 0x2541, 0xA6DC, 0x2542, 0xA6C0, 0x2543, 0xA6DD, 0x2544, 0xA6DE, 0x2545, 0xA6DF, 0x2546, 0xA6E0, 0x2547, 0xA6E1, 0x2548, 0xA6E2, 0x2549, 0xA6E3, 0x254A, 0xA6E4, 0x254B, 0xA6B6, 0x2592, 0xA2C6, 0x25A0, 0xA1E1, 0x25A1, 0xA1E0, 0x25A3, 0xA2C3, 0x25A4, 0xA2C7, 0x25A5, 0xA2C8, 0x25A6, 0xA2CB, 0x25A7, 0xA2CA, 0x25A8, 0xA2C9, 0x25A9, 0xA2CC, 0x25B2, 0xA1E3, 0x25B3, 0xA1E2, 0x25B6, 0xA2BA, 0x25B7, 0xA2B9, 0x25BC, 0xA1E5, 0x25BD, 0xA1E4, 0x25C0, 0xA2B8, 0x25C1, 0xA2B7, 0x25C6, 0xA1DF, 0x25C7, 0xA1DE, 0x25C8, 0xA2C2, 0x25CB, 0xA1DB, 0x25CE, 0xA1DD, 0x25CF, 0xA1DC, 0x25D0, 0xA2C4, 0x25D1, 0xA2C5, 0x2605, 0xA1DA, 0x2606, 0xA1D9, 0x260E, 0xA2CF, 0x260F, 0xA2CE, 0x261C, 0xA2D0, 0x261E, 0xA2D1, 0x2640, 0xA1CF, 0x2642, 0xA1CE, 0x2660, 0xA2BC, 0x2661, 0xA2BD, 0x2663, 0xA2C0, 0x2664, 0xA2BB, 0x2665, 0xA2BE, 0x2667, 0xA2BF, 0x2668, 0xA2CD, 0x2669, 0xA2DB, 0x266A, 0xA2DC, 0x266C, 0xA2DD, 0x266D, 0xA2DA, 0x3000, 0xA1A1, 0x3001, 0xA1A2, 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3008, 0xA1B4, 0x3009, 0xA1B5, 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BC, 0x3011, 0xA1BD, 0x3013, 0xA1EB, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3041, 0xAAA1, 0x3042, 0xAAA2, 0x3043, 0xAAA3, 0x3044, 0xAAA4, 0x3045, 0xAAA5, 0x3046, 0xAAA6, 0x3047, 0xAAA7, 0x3048, 0xAAA8, 0x3049, 0xAAA9, 0x304A, 0xAAAA, 0x304B, 0xAAAB, 0x304C, 0xAAAC, 0x304D, 0xAAAD, 0x304E, 0xAAAE, 0x304F, 0xAAAF, 0x3050, 0xAAB0, 0x3051, 0xAAB1, 0x3052, 0xAAB2, 0x3053, 0xAAB3, 0x3054, 0xAAB4, 0x3055, 0xAAB5, 0x3056, 0xAAB6, 0x3057, 0xAAB7, 0x3058, 0xAAB8, 0x3059, 0xAAB9, 0x305A, 0xAABA, 0x305B, 0xAABB, 0x305C, 0xAABC, 0x305D, 0xAABD, 0x305E, 0xAABE, 0x305F, 0xAABF, 0x3060, 0xAAC0, 0x3061, 0xAAC1, 0x3062, 0xAAC2, 0x3063, 0xAAC3, 0x3064, 0xAAC4, 0x3065, 0xAAC5, 0x3066, 0xAAC6, 0x3067, 0xAAC7, 0x3068, 0xAAC8, 0x3069, 0xAAC9, 0x306A, 0xAACA, 0x306B, 0xAACB, 0x306C, 0xAACC, 0x306D, 0xAACD, 0x306E, 0xAACE, 0x306F, 0xAACF, 0x3070, 0xAAD0, 0x3071, 0xAAD1, 0x3072, 0xAAD2, 0x3073, 0xAAD3, 0x3074, 0xAAD4, 0x3075, 0xAAD5, 0x3076, 0xAAD6, 0x3077, 0xAAD7, 0x3078, 0xAAD8, 0x3079, 0xAAD9, 0x307A, 0xAADA, 0x307B, 0xAADB, 0x307C, 0xAADC, 0x307D, 0xAADD, 0x307E, 0xAADE, 0x307F, 0xAADF, 0x3080, 0xAAE0, 0x3081, 0xAAE1, 0x3082, 0xAAE2, 0x3083, 0xAAE3, 0x3084, 0xAAE4, 0x3085, 0xAAE5, 0x3086, 0xAAE6, 0x3087, 0xAAE7, 0x3088, 0xAAE8, 0x3089, 0xAAE9, 0x308A, 0xAAEA, 0x308B, 0xAAEB, 0x308C, 0xAAEC, 0x308D, 0xAAED, 0x308E, 0xAAEE, 0x308F, 0xAAEF, 0x3090, 0xAAF0, 0x3091, 0xAAF1, 0x3092, 0xAAF2, 0x3093, 0xAAF3, 0x30A1, 0xABA1, 0x30A2, 0xABA2, 0x30A3, 0xABA3, 0x30A4, 0xABA4, 0x30A5, 0xABA5, 0x30A6, 0xABA6, 0x30A7, 0xABA7, 0x30A8, 0xABA8, 0x30A9, 0xABA9, 0x30AA, 0xABAA, 0x30AB, 0xABAB, 0x30AC, 0xABAC, 0x30AD, 0xABAD, 0x30AE, 0xABAE, 0x30AF, 0xABAF, 0x30B0, 0xABB0, 0x30B1, 0xABB1, 0x30B2, 0xABB2, 0x30B3, 0xABB3, 0x30B4, 0xABB4, 0x30B5, 0xABB5, 0x30B6, 0xABB6, 0x30B7, 0xABB7, 0x30B8, 0xABB8, 0x30B9, 0xABB9, 0x30BA, 0xABBA, 0x30BB, 0xABBB, 0x30BC, 0xABBC, 0x30BD, 0xABBD, 0x30BE, 0xABBE, 0x30BF, 0xABBF, 0x30C0, 0xABC0, 0x30C1, 0xABC1, 0x30C2, 0xABC2, 0x30C3, 0xABC3, 0x30C4, 0xABC4, 0x30C5, 0xABC5, 0x30C6, 0xABC6, 0x30C7, 0xABC7, 0x30C8, 0xABC8, 0x30C9, 0xABC9, 0x30CA, 0xABCA, 0x30CB, 0xABCB, 0x30CC, 0xABCC, 0x30CD, 0xABCD, 0x30CE, 0xABCE, 0x30CF, 0xABCF, 0x30D0, 0xABD0, 0x30D1, 0xABD1, 0x30D2, 0xABD2, 0x30D3, 0xABD3, 0x30D4, 0xABD4, 0x30D5, 0xABD5, 0x30D6, 0xABD6, 0x30D7, 0xABD7, 0x30D8, 0xABD8, 0x30D9, 0xABD9, 0x30DA, 0xABDA, 0x30DB, 0xABDB, 0x30DC, 0xABDC, 0x30DD, 0xABDD, 0x30DE, 0xABDE, 0x30DF, 0xABDF, 0x30E0, 0xABE0, 0x30E1, 0xABE1, 0x30E2, 0xABE2, 0x30E3, 0xABE3, 0x30E4, 0xABE4, 0x30E5, 0xABE5, 0x30E6, 0xABE6, 0x30E7, 0xABE7, 0x30E8, 0xABE8, 0x30E9, 0xABE9, 0x30EA, 0xABEA, 0x30EB, 0xABEB, 0x30EC, 0xABEC, 0x30ED, 0xABED, 0x30EE, 0xABEE, 0x30EF, 0xABEF, 0x30F0, 0xABF0, 0x30F1, 0xABF1, 0x30F2, 0xABF2, 0x30F3, 0xABF3, 0x30F4, 0xABF4, 0x30F5, 0xABF5, 0x30F6, 0xABF6, 0x3131, 0xA4A1, 0x3132, 0xA4A2, 0x3133, 0xA4A3, 0x3134, 0xA4A4, 0x3135, 0xA4A5, 0x3136, 0xA4A6, 0x3137, 0xA4A7, 0x3138, 0xA4A8, 0x3139, 0xA4A9, 0x313A, 0xA4AA, 0x313B, 0xA4AB, 0x313C, 0xA4AC, 0x313D, 0xA4AD, 0x313E, 0xA4AE, 0x313F, 0xA4AF, 0x3140, 0xA4B0, 0x3141, 0xA4B1, 0x3142, 0xA4B2, 0x3143, 0xA4B3, 0x3144, 0xA4B4, 0x3145, 0xA4B5, 0x3146, 0xA4B6, 0x3147, 0xA4B7, 0x3148, 0xA4B8, 0x3149, 0xA4B9, 0x314A, 0xA4BA, 0x314B, 0xA4BB, 0x314C, 0xA4BC, 0x314D, 0xA4BD, 0x314E, 0xA4BE, 0x314F, 0xA4BF, 0x3150, 0xA4C0, 0x3151, 0xA4C1, 0x3152, 0xA4C2, 0x3153, 0xA4C3, 0x3154, 0xA4C4, 0x3155, 0xA4C5, 0x3156, 0xA4C6, 0x3157, 0xA4C7, 0x3158, 0xA4C8, 0x3159, 0xA4C9, 0x315A, 0xA4CA, 0x315B, 0xA4CB, 0x315C, 0xA4CC, 0x315D, 0xA4CD, 0x315E, 0xA4CE, 0x315F, 0xA4CF, 0x3160, 0xA4D0, 0x3161, 0xA4D1, 0x3162, 0xA4D2, 0x3163, 0xA4D3, 0x3164, 0xA4D4, 0x3165, 0xA4D5, 0x3166, 0xA4D6, 0x3167, 0xA4D7, 0x3168, 0xA4D8, 0x3169, 0xA4D9, 0x316A, 0xA4DA, 0x316B, 0xA4DB, 0x316C, 0xA4DC, 0x316D, 0xA4DD, 0x316E, 0xA4DE, 0x316F, 0xA4DF, 0x3170, 0xA4E0, 0x3171, 0xA4E1, 0x3172, 0xA4E2, 0x3173, 0xA4E3, 0x3174, 0xA4E4, 0x3175, 0xA4E5, 0x3176, 0xA4E6, 0x3177, 0xA4E7, 0x3178, 0xA4E8, 0x3179, 0xA4E9, 0x317A, 0xA4EA, 0x317B, 0xA4EB, 0x317C, 0xA4EC, 0x317D, 0xA4ED, 0x317E, 0xA4EE, 0x317F, 0xA4EF, 0x3180, 0xA4F0, 0x3181, 0xA4F1, 0x3182, 0xA4F2, 0x3183, 0xA4F3, 0x3184, 0xA4F4, 0x3185, 0xA4F5, 0x3186, 0xA4F6, 0x3187, 0xA4F7, 0x3188, 0xA4F8, 0x3189, 0xA4F9, 0x318A, 0xA4FA, 0x318B, 0xA4FB, 0x318C, 0xA4FC, 0x318D, 0xA4FD, 0x318E, 0xA4FE, 0x3200, 0xA9B1, 0x3201, 0xA9B2, 0x3202, 0xA9B3, 0x3203, 0xA9B4, 0x3204, 0xA9B5, 0x3205, 0xA9B6, 0x3206, 0xA9B7, 0x3207, 0xA9B8, 0x3208, 0xA9B9, 0x3209, 0xA9BA, 0x320A, 0xA9BB, 0x320B, 0xA9BC, 0x320C, 0xA9BD, 0x320D, 0xA9BE, 0x320E, 0xA9BF, 0x320F, 0xA9C0, 0x3210, 0xA9C1, 0x3211, 0xA9C2, 0x3212, 0xA9C3, 0x3213, 0xA9C4, 0x3214, 0xA9C5, 0x3215, 0xA9C6, 0x3216, 0xA9C7, 0x3217, 0xA9C8, 0x3218, 0xA9C9, 0x3219, 0xA9CA, 0x321A, 0xA9CB, 0x321B, 0xA9CC, 0x321C, 0xA2DF, 0x3260, 0xA8B1, 0x3261, 0xA8B2, 0x3262, 0xA8B3, 0x3263, 0xA8B4, 0x3264, 0xA8B5, 0x3265, 0xA8B6, 0x3266, 0xA8B7, 0x3267, 0xA8B8, 0x3268, 0xA8B9, 0x3269, 0xA8BA, 0x326A, 0xA8BB, 0x326B, 0xA8BC, 0x326C, 0xA8BD, 0x326D, 0xA8BE, 0x326E, 0xA8BF, 0x326F, 0xA8C0, 0x3270, 0xA8C1, 0x3271, 0xA8C2, 0x3272, 0xA8C3, 0x3273, 0xA8C4, 0x3274, 0xA8C5, 0x3275, 0xA8C6, 0x3276, 0xA8C7, 0x3277, 0xA8C8, 0x3278, 0xA8C9, 0x3279, 0xA8CA, 0x327A, 0xA8CB, 0x327B, 0xA8CC, 0x327F, 0xA2DE, 0x3380, 0xA7C9, 0x3381, 0xA7CA, 0x3382, 0xA7CB, 0x3383, 0xA7CC, 0x3384, 0xA7CD, 0x3388, 0xA7BA, 0x3389, 0xA7BB, 0x338A, 0xA7DC, 0x338B, 0xA7DD, 0x338C, 0xA7DE, 0x338D, 0xA7B6, 0x338E, 0xA7B7, 0x338F, 0xA7B8, 0x3390, 0xA7D4, 0x3391, 0xA7D5, 0x3392, 0xA7D6, 0x3393, 0xA7D7, 0x3394, 0xA7D8, 0x3395, 0xA7A1, 0x3396, 0xA7A2, 0x3397, 0xA7A3, 0x3398, 0xA7A5, 0x3399, 0xA7AB, 0x339A, 0xA7AC, 0x339B, 0xA7AD, 0x339C, 0xA7AE, 0x339D, 0xA7AF, 0x339E, 0xA7B0, 0x339F, 0xA7B1, 0x33A0, 0xA7B2, 0x33A1, 0xA7B3, 0x33A2, 0xA7B4, 0x33A3, 0xA7A7, 0x33A4, 0xA7A8, 0x33A5, 0xA7A9, 0x33A6, 0xA7AA, 0x33A7, 0xA7BD, 0x33A8, 0xA7BE, 0x33A9, 0xA7E5, 0x33AA, 0xA7E6, 0x33AB, 0xA7E7, 0x33AC, 0xA7E8, 0x33AD, 0xA7E1, 0x33AE, 0xA7E2, 0x33AF, 0xA7E3, 0x33B0, 0xA7BF, 0x33B1, 0xA7C0, 0x33B2, 0xA7C1, 0x33B3, 0xA7C2, 0x33B4, 0xA7C3, 0x33B5, 0xA7C4, 0x33B6, 0xA7C5, 0x33B7, 0xA7C6, 0x33B8, 0xA7C7, 0x33B9, 0xA7C8, 0x33BA, 0xA7CE, 0x33BB, 0xA7CF, 0x33BC, 0xA7D0, 0x33BD, 0xA7D1, 0x33BE, 0xA7D2, 0x33BF, 0xA7D3, 0x33C0, 0xA7DA, 0x33C1, 0xA7DB, 0x33C2, 0xA2E3, 0x33C3, 0xA7EC, 0x33C4, 0xA7A6, 0x33C5, 0xA7E0, 0x33C6, 0xA7EF, 0x33C7, 0xA2E1, 0x33C8, 0xA7BC, 0x33C9, 0xA7ED, 0x33CA, 0xA7B5, 0x33CF, 0xA7B9, 0x33D0, 0xA7EA, 0x33D3, 0xA7EB, 0x33D6, 0xA7DF, 0x33D8, 0xA2E4, 0x33DB, 0xA7E4, 0x33DC, 0xA7EE, 0x33DD, 0xA7E9, 0x4E00, 0xECE9, 0x4E01, 0xEFCB, 0x4E03, 0xF6D2, 0x4E07, 0xD8B2, 0x4E08, 0xEDDB, 0x4E09, 0xDFB2, 0x4E0A, 0xDFBE, 0x4E0B, 0xF9BB, 0x4E0D, 0xDCF4, 0x4E11, 0xF5E4, 0x4E14, 0xF3A6, 0x4E15, 0xDDE0, 0x4E16, 0xE1A6, 0x4E18, 0xCEF8, 0x4E19, 0xDCB0, 0x4E1E, 0xE3AA, 0x4E2D, 0xF1E9, 0x4E32, 0xCDFA, 0x4E38, 0xFCAF, 0x4E39, 0xD3A1, 0x4E3B, 0xF1AB, 0x4E42, 0xE7D1, 0x4E43, 0xD2AC, 0x4E45, 0xCEF9, 0x4E4B, 0xF1FD, 0x4E4D, 0xDEBF, 0x4E4E, 0xFBBA, 0x4E4F, 0xF9B9, 0x4E56, 0xCED2, 0x4E58, 0xE3AB, 0x4E59, 0xEBE0, 0x4E5D, 0xCEFA, 0x4E5E, 0xCBF7, 0x4E5F, 0xE5A5, 0x4E6B, 0xCAE1, 0x4E6D, 0xD4CC, 0x4E73, 0xEAE1, 0x4E76, 0xDCE3, 0x4E77, 0xDFAD, 0x4E7E, 0xCBEB, 0x4E82, 0xD5AF, 0x4E86, 0xD6F5, 0x4E88, 0xE5F8, 0x4E8B, 0xDEC0, 0x4E8C, 0xECA3, 0x4E8E, 0xE9CD, 0x4E90, 0xEAA7, 0x4E91, 0xE9F6, 0x4E92, 0xFBBB, 0x4E94, 0xE7E9, 0x4E95, 0xEFCC, 0x4E98, 0xD0E6, 0x4E9B, 0xDEC1, 0x4E9E, 0xE4AC, 0x4EA1, 0xD8CC, 0x4EA2, 0xF9F1, 0x4EA4, 0xCEDF, 0x4EA5, 0xFAA4, 0x4EA6, 0xE6B2, 0x4EA8, 0xFAFB, 0x4EAB, 0xFABD, 0x4EAC, 0xCCC8, 0x4EAD, 0xEFCD, 0x4EAE, 0xD5D5, 0x4EB6, 0xD3A2, 0x4EBA, 0xECD1, 0x4EC0, 0xE4A7, 0x4EC1, 0xECD2, 0x4EC4, 0xF6B1, 0x4EC7, 0xCEFB, 0x4ECA, 0xD0D1, 0x4ECB, 0xCBBF, 0x4ECD, 0xEDA4, 0x4ED4, 0xEDA8, 0x4ED5, 0xDEC2, 0x4ED6, 0xF6E2, 0x4ED7, 0xEDDC, 0x4ED8, 0xDCF5, 0x4ED9, 0xE0B9, 0x4EDD, 0xD4CE, 0x4EDF, 0xF4B5, 0x4EE3, 0xD3DB, 0x4EE4, 0xD6B5, 0x4EE5, 0xECA4, 0x4EF0, 0xE4E6, 0x4EF2, 0xF1EA, 0x4EF6, 0xCBEC, 0x4EF7, 0xCBC0, 0x4EFB, 0xECF2, 0x4F01, 0xD0EA, 0x4F09, 0xF9F2, 0x4F0A, 0xECA5, 0x4F0B, 0xD0DF, 0x4F0D, 0xE7EA, 0x4F0E, 0xD0EB, 0x4F0F, 0xDCD1, 0x4F10, 0xDBE9, 0x4F11, 0xFDCC, 0x4F2F, 0xDBD7, 0x4F34, 0xDAE1, 0x4F36, 0xD6B6, 0x4F38, 0xE3DF, 0x4F3A, 0xDEC3, 0x4F3C, 0xDEC4, 0x4F3D, 0xCAA1, 0x4F43, 0xEEEC, 0x4F46, 0xD3A3, 0x4F47, 0xEEB7, 0x4F48, 0xF8CF, 0x4F4D, 0xEAC8, 0x4F4E, 0xEEB8, 0x4F4F, 0xF1AC, 0x4F50, 0xF1A5, 0x4F51, 0xE9CE, 0x4F55, 0xF9BC, 0x4F59, 0xE5F9, 0x4F5A, 0xECEA, 0x4F5B, 0xDDD6, 0x4F5C, 0xEDC2, 0x4F69, 0xF8A5, 0x4F6F, 0xE5BA, 0x4F70, 0xDBD8, 0x4F73, 0xCAA2, 0x4F76, 0xD1CD, 0x4F7A, 0xEEED, 0x4F7E, 0xECEB, 0x4F7F, 0xDEC5, 0x4F81, 0xE3E0, 0x4F83, 0xCAC9, 0x4F84, 0xF2E9, 0x4F86, 0xD5CE, 0x4F88, 0xF6B6, 0x4F8A, 0xCEC2, 0x4F8B, 0xD6C7, 0x4F8D, 0xE3B4, 0x4F8F, 0xF1AD, 0x4F91, 0xEAE2, 0x4F96, 0xD7C2, 0x4F98, 0xF3A7, 0x4F9B, 0xCDEA, 0x4F9D, 0xEBEE, 0x4FAE, 0xD9B2, 0x4FAF, 0xFDA5, 0x4FB5, 0xF6D5, 0x4FB6, 0xD5E2, 0x4FBF, 0xF8B5, 0x4FC2, 0xCCF5, 0x4FC3, 0xF5B5, 0x4FC4, 0xE4AD, 0x4FC9, 0xE7EB, 0x4FCA, 0xF1D5, 0x4FCE, 0xF0BB, 0x4FD1, 0xE9B5, 0x4FD3, 0xCCC9, 0x4FD4, 0xFAD5, 0x4FD7, 0xE1D4, 0x4FDA, 0xD7D6, 0x4FDD, 0xDCC1, 0x4FDF, 0xDEC6, 0x4FE0, 0xFAEF, 0x4FE1, 0xE3E1, 0x4FEE, 0xE1F3, 0x4FEF, 0xDCF6, 0x4FF1, 0xCEFC, 0x4FF3, 0xDBC4, 0x4FF5, 0xF8F1, 0x4FF8, 0xDCE4, 0x4FFA, 0xE5EF, 0x5002, 0xDCB1, 0x5006, 0xD5D6, 0x5009, 0xF3DA, 0x500B, 0xCBC1, 0x500D, 0xDBC3, 0x5011, 0xD9FA, 0x5012, 0xD3EE, 0x5016, 0xFAB8, 0x5019, 0xFDA6, 0x501A, 0xEBEF, 0x501C, 0xF4A6, 0x501E, 0xCCCA, 0x501F, 0xF3A8, 0x5021, 0xF3DB, 0x5023, 0xDBA7, 0x5024, 0xF6B7, 0x5026, 0xCFE6, 0x5027, 0xF0F2, 0x5028, 0xCBDA, 0x502A, 0xE7D2, 0x502B, 0xD7C3, 0x502C, 0xF6F0, 0x502D, 0xE8DE, 0x503B, 0xE5A6, 0x5043, 0xE5E7, 0x5047, 0xCAA3, 0x5048, 0xCCA7, 0x5049, 0xEAC9, 0x504F, 0xF8B6, 0x5055, 0xFAA5, 0x505A, 0xF1AE, 0x505C, 0xEFCE, 0x5065, 0xCBED, 0x5074, 0xF6B0, 0x5075, 0xEFCF, 0x5076, 0xE9CF, 0x5078, 0xF7DE, 0x5080, 0xCED3, 0x5085, 0xDCF7, 0x508D, 0xDBA8, 0x5091, 0xCBF8, 0x5098, 0xDFA1, 0x5099, 0xDDE1, 0x50AC, 0xF5CA, 0x50AD, 0xE9B6, 0x50B2, 0xE7EC, 0x50B3, 0xEEEE, 0x50B5, 0xF3F0, 0x50B7, 0xDFBF, 0x50BE, 0xCCCB, 0x50C5, 0xD0C1, 0x50C9, 0xF4D2, 0x50CA, 0xE0BA, 0x50CF, 0xDFC0, 0x50D1, 0xCEE0, 0x50D5, 0xDCD2, 0x50D6, 0xFDEA, 0x50DA, 0xD6F6, 0x50DE, 0xEACA, 0x50E5, 0xE8E9, 0x50E7, 0xE3AC, 0x50ED, 0xF3D0, 0x50F9, 0xCAA4, 0x50FB, 0xDBF8, 0x50FF, 0xDEC7, 0x5100, 0xEBF0, 0x5101, 0xF1D6, 0x5104, 0xE5E2, 0x5106, 0xCCCC, 0x5109, 0xCBFB, 0x5112, 0xEAE3, 0x511F, 0xDFC1, 0x5121, 0xD6ED, 0x512A, 0xE9D0, 0x5132, 0xEEB9, 0x5137, 0xD5E3, 0x513A, 0xD1D3, 0x513C, 0xE5F0, 0x5140, 0xE8B4, 0x5141, 0xEBC3, 0x5143, 0xEAAA, 0x5144, 0xFAFC, 0x5145, 0xF5F6, 0x5146, 0xF0BC, 0x5147, 0xFDD4, 0x5148, 0xE0BB, 0x5149, 0xCEC3, 0x514B, 0xD0BA, 0x514C, 0xF7BA, 0x514D, 0xD8F3, 0x514E, 0xF7CD, 0x5152, 0xE4AE, 0x515C, 0xD4DF, 0x5162, 0xD0E7, 0x5165, 0xECFD, 0x5167, 0xD2AE, 0x5168, 0xEEEF, 0x5169, 0xD5D7, 0x516A, 0xEAE4, 0x516B, 0xF8A2, 0x516C, 0xCDEB, 0x516D, 0xD7BF, 0x516E, 0xFBB1, 0x5171, 0xCDEC, 0x5175, 0xDCB2, 0x5176, 0xD0EC, 0x5177, 0xCEFD, 0x5178, 0xEEF0, 0x517C, 0xCCC2, 0x5180, 0xD0ED, 0x5186, 0xE5F7, 0x518A, 0xF3FC, 0x518D, 0xEEA2, 0x5192, 0xD9B3, 0x5195, 0xD8F4, 0x5197, 0xE9B7, 0x51A0, 0xCEAE, 0x51A5, 0xD9A2, 0x51AA, 0xD8F1, 0x51AC, 0xD4CF, 0x51B6, 0xE5A7, 0x51B7, 0xD5D2, 0x51BD, 0xD6A9, 0x51C4, 0xF4A2, 0x51C6, 0xF1D7, 0x51C9, 0xD5D8, 0x51CB, 0xF0BD, 0x51CC, 0xD7D0, 0x51CD, 0xD4D0, 0x51DC, 0xD7CF, 0x51DD, 0xEBEA, 0x51DE, 0xFDEB, 0x51E1, 0xDBED, 0x51F0, 0xFCC5, 0x51F1, 0xCBC2, 0x51F6, 0xFDD5, 0x51F8, 0xF4C8, 0x51F9, 0xE8EA, 0x51FA, 0xF5F3, 0x51FD, 0xF9DE, 0x5200, 0xD3EF, 0x5203, 0xECD3, 0x5206, 0xDDC2, 0x5207, 0xEFB7, 0x5208, 0xE7D4, 0x520A, 0xCACA, 0x520E, 0xD9FB, 0x5211, 0xFAFD, 0x5217, 0xD6AA, 0x521D, 0xF4F8, 0x5224, 0xF7F7, 0x5225, 0xDCAC, 0x5229, 0xD7D7, 0x522A, 0xDFA2, 0x522E, 0xCEBE, 0x5230, 0xD3F0, 0x5236, 0xF0A4, 0x5237, 0xE1EC, 0x5238, 0xCFE7, 0x5239, 0xF3CB, 0x523A, 0xEDA9, 0x523B, 0xCABE, 0x5243, 0xF4EF, 0x5247, 0xF6CE, 0x524A, 0xDEFB, 0x524B, 0xD0BB, 0x524C, 0xD5B7, 0x524D, 0xEEF1, 0x5254, 0xF4A8, 0x5256, 0xDCF8, 0x525B, 0xCBA7, 0x525D, 0xDACE, 0x5261, 0xE0E6, 0x5269, 0xEDA5, 0x526A, 0xEEF2, 0x526F, 0xDCF9, 0x5272, 0xF9DC, 0x5275, 0xF3DC, 0x527D, 0xF8F2, 0x527F, 0xF4F9, 0x5283, 0xFCF1, 0x5287, 0xD0BC, 0x5288, 0xDBF9, 0x5289, 0xD7B1, 0x528D, 0xCBFC, 0x5291, 0xF0A5, 0x5292, 0xCBFD, 0x529B, 0xD5F4, 0x529F, 0xCDED, 0x52A0, 0xCAA5, 0x52A3, 0xD6AB, 0x52A4, 0xD0C2, 0x52A9, 0xF0BE, 0x52AA, 0xD2BD, 0x52AB, 0xCCA4, 0x52BE, 0xFAB6, 0x52C1, 0xCCCD, 0x52C3, 0xDAFA, 0x52C5, 0xF6CF, 0x52C7, 0xE9B8, 0x52C9, 0xD8F5, 0x52CD, 0xCCCE, 0x52D2, 0xD7CD, 0x52D5, 0xD4D1, 0x52D6, 0xE9ED, 0x52D8, 0xCAEB, 0x52D9, 0xD9E2, 0x52DB, 0xFDB2, 0x52DD, 0xE3AD, 0x52DE, 0xD6CC, 0x52DF, 0xD9B4, 0x52E2, 0xE1A7, 0x52E3, 0xEED3, 0x52E4, 0xD0C3, 0x52F3, 0xFDB3, 0x52F5, 0xD5E4, 0x52F8, 0xCFE8, 0x52FA, 0xEDC3, 0x52FB, 0xD0B2, 0x52FE, 0xCEFE, 0x52FF, 0xDAA8, 0x5305, 0xF8D0, 0x5308, 0xFDD6, 0x530D, 0xF8D1, 0x530F, 0xF8D2, 0x5310, 0xDCD3, 0x5315, 0xDDE2, 0x5316, 0xFBF9, 0x5317, 0xDDC1, 0x5319, 0xE3B5, 0x5320, 0xEDDD, 0x5321, 0xCEC4, 0x5323, 0xCBA1, 0x532A, 0xDDE3, 0x532F, 0xFCDD, 0x5339, 0xF9AF, 0x533F, 0xD2FB, 0x5340, 0xCFA1, 0x5341, 0xE4A8, 0x5343, 0xF4B6, 0x5344, 0xECFE, 0x5347, 0xE3AE, 0x5348, 0xE7ED, 0x5349, 0xFDC1, 0x534A, 0xDAE2, 0x534D, 0xD8B3, 0x5351, 0xDDE4, 0x5352, 0xF0EF, 0x5353, 0xF6F1, 0x5354, 0xFAF0, 0x5357, 0xD1F5, 0x535A, 0xDACF, 0x535C, 0xDCD4, 0x535E, 0xDCA6, 0x5360, 0xEFBF, 0x5366, 0xCECF, 0x5368, 0xE0D9, 0x536F, 0xD9D6, 0x5370, 0xECD4, 0x5371, 0xEACB, 0x5374, 0xCABF, 0x5375, 0xD5B0, 0x5377, 0xCFE9, 0x537D, 0xF1ED, 0x537F, 0xCCCF, 0x5384, 0xE4F8, 0x5393, 0xE4ED, 0x5398, 0xD7D8, 0x539A, 0xFDA7, 0x539F, 0xEAAB, 0x53A0, 0xF6B2, 0x53A5, 0xCFF0, 0x53A6, 0xF9BD, 0x53AD, 0xE6F4, 0x53BB, 0xCBDB, 0x53C3, 0xF3D1, 0x53C8, 0xE9D1, 0x53C9, 0xF3A9, 0x53CA, 0xD0E0, 0x53CB, 0xE9D2, 0x53CD, 0xDAE3, 0x53D4, 0xE2D2, 0x53D6, 0xF6A2, 0x53D7, 0xE1F4, 0x53DB, 0xDAE4, 0x53E1, 0xE7D5, 0x53E2, 0xF5BF, 0x53E3, 0xCFA2, 0x53E4, 0xCDAF, 0x53E5, 0xCFA3, 0x53E9, 0xCDB0, 0x53EA, 0xF1FE, 0x53EB, 0xD0A3, 0x53EC, 0xE1AF, 0x53ED, 0xF8A3, 0x53EF, 0xCAA6, 0x53F0, 0xF7BB, 0x53F1, 0xF2EA, 0x53F2, 0xDEC8, 0x53F3, 0xE9D3, 0x53F8, 0xDEC9, 0x5403, 0xFDDE, 0x5404, 0xCAC0, 0x5408, 0xF9EA, 0x5409, 0xD1CE, 0x540A, 0xEED4, 0x540C, 0xD4D2, 0x540D, 0xD9A3, 0x540E, 0xFDA8, 0x540F, 0xD7D9, 0x5410, 0xF7CE, 0x5411, 0xFABE, 0x541B, 0xCFD6, 0x541D, 0xD7F0, 0x541F, 0xEBE1, 0x5420, 0xF8C5, 0x5426, 0xDCFA, 0x5429, 0xDDC3, 0x542B, 0xF9DF, 0x5433, 0xE7EF, 0x5438, 0xFDE5, 0x5439, 0xF6A3, 0x543B, 0xD9FC, 0x543C, 0xFDA9, 0x543E, 0xE7EE, 0x5442, 0xD5E5, 0x5448, 0xEFD0, 0x544A, 0xCDB1, 0x5451, 0xF7A2, 0x5468, 0xF1B2, 0x546A, 0xF1B1, 0x5471, 0xCDB2, 0x5473, 0xDAAB, 0x5475, 0xCAA7, 0x547B, 0xE3E2, 0x547C, 0xFBBC, 0x547D, 0xD9A4, 0x5480, 0xEEBA, 0x5486, 0xF8D3, 0x548C, 0xFBFA, 0x548E, 0xCFA4, 0x5490, 0xDCFB, 0x54A4, 0xF6E3, 0x54A8, 0xEDAA, 0x54AB, 0xF2A1, 0x54AC, 0xCEE1, 0x54B3, 0xFAA6, 0x54B8, 0xF9E0, 0x54BD, 0xECD6, 0x54C0, 0xE4EE, 0x54C1, 0xF9A1, 0x54C4, 0xFBEF, 0x54C8, 0xF9EB, 0x54C9, 0xEEA3, 0x54E1, 0xEAAC, 0x54E5, 0xCAA8, 0x54E8, 0xF4FA, 0x54ED, 0xCDD6, 0x54EE, 0xFCF6, 0x54F2, 0xF4C9, 0x54FA, 0xF8D4, 0x5504, 0xF8A6, 0x5506, 0xDECA, 0x5507, 0xF2C6, 0x550E, 0xD7DA, 0x5510, 0xD3D0, 0x551C, 0xD8C5, 0x552F, 0xEAE6, 0x5531, 0xF3DD, 0x5535, 0xE4DA, 0x553E, 0xF6E4, 0x5544, 0xF6F2, 0x5546, 0xDFC2, 0x554F, 0xD9FD, 0x5553, 0xCCF6, 0x5556, 0xD3BA, 0x555E, 0xE4AF, 0x5563, 0xF9E1, 0x557C, 0xF0A6, 0x5580, 0xCBD3, 0x5584, 0xE0BC, 0x5586, 0xF4CA, 0x5587, 0xD4FA, 0x5589, 0xFDAA, 0x558A, 0xF9E2, 0x5598, 0xF4B7, 0x5599, 0xFDC2, 0x559A, 0xFCB0, 0x559C, 0xFDEC, 0x559D, 0xCAE2, 0x55A7, 0xFDBD, 0x55A9, 0xEAE7, 0x55AA, 0xDFC3, 0x55AB, 0xD1D2, 0x55AC, 0xCEE2, 0x55AE, 0xD3A4, 0x55C5, 0xFDAB, 0x55C7, 0xDFE0, 0x55D4, 0xF2C7, 0x55DA, 0xE7F0, 0x55DC, 0xD0EE, 0x55DF, 0xF3AA, 0x55E3, 0xDECB, 0x55E4, 0xF6B8, 0x55FD, 0xE1F5, 0x55FE, 0xF1B3, 0x5606, 0xF7A3, 0x5609, 0xCAA9, 0x5614, 0xCFA5, 0x5617, 0xDFC4, 0x562F, 0xE1B0, 0x5632, 0xF0BF, 0x5634, 0xF6A4, 0x5636, 0xE3B6, 0x5653, 0xFAC6, 0x5668, 0xD0EF, 0x566B, 0xFDED, 0x5674, 0xDDC4, 0x5686, 0xFCF7, 0x56A5, 0xE6BF, 0x56AC, 0xDEAD, 0x56AE, 0xFABF, 0x56B4, 0xE5F1, 0x56BC, 0xEDC4, 0x56CA, 0xD2A5, 0x56CD, 0xFDEE, 0x56D1, 0xF5B6, 0x56DA, 0xE1F6, 0x56DB, 0xDECC, 0x56DE, 0xFCDE, 0x56E0, 0xECD7, 0x56F0, 0xCDDD, 0x56F9, 0xD6B7, 0x56FA, 0xCDB3, 0x5703, 0xF8D5, 0x5704, 0xE5D8, 0x5708, 0xCFEA, 0x570B, 0xCFD0, 0x570D, 0xEACC, 0x5712, 0xEAAE, 0x5713, 0xEAAD, 0x5716, 0xD3F1, 0x5718, 0xD3A5, 0x571F, 0xF7CF, 0x5728, 0xEEA4, 0x572D, 0xD0A4, 0x5730, 0xF2A2, 0x573B, 0xD0F0, 0x5740, 0xF2A3, 0x5742, 0xF7F8, 0x5747, 0xD0B3, 0x574A, 0xDBA9, 0x574D, 0xD3BB, 0x574E, 0xCAEC, 0x5750, 0xF1A6, 0x5751, 0xCBD5, 0x5761, 0xF7E7, 0x5764, 0xCDDE, 0x5766, 0xF7A4, 0x576A, 0xF8C0, 0x576E, 0xD3DD, 0x5770, 0xCCD0, 0x5775, 0xCFA6, 0x577C, 0xF6F3, 0x5782, 0xE1F7, 0x5788, 0xD3DC, 0x578B, 0xFAFE, 0x5793, 0xFAA7, 0x57A0, 0xEBD9, 0x57A2, 0xCFA7, 0x57A3, 0xEAAF, 0x57C3, 0xE4EF, 0x57C7, 0xE9B9, 0x57C8, 0xF1D8, 0x57CB, 0xD8D8, 0x57CE, 0xE0F2, 0x57DF, 0xE6B4, 0x57E0, 0xDCFC, 0x57F0, 0xF3F1, 0x57F4, 0xE3D0, 0x57F7, 0xF2FB, 0x57F9, 0xDBC6, 0x57FA, 0xD0F1, 0x57FC, 0xD0F2, 0x5800, 0xCFDC, 0x5802, 0xD3D1, 0x5805, 0xCCB1, 0x5806, 0xF7D8, 0x5808, 0xCBA8, 0x5809, 0xEBBC, 0x580A, 0xE4BE, 0x581E, 0xF4DC, 0x5821, 0xDCC2, 0x5824, 0xF0A7, 0x5827, 0xE6C0, 0x582A, 0xCAED, 0x582F, 0xE8EB, 0x5830, 0xE5E8, 0x5831, 0xDCC3, 0x5834, 0xEDDE, 0x5835, 0xD3F2, 0x583A, 0xCCF7, 0x584A, 0xCED4, 0x584B, 0xE7AB, 0x584F, 0xCBC3, 0x5851, 0xE1B1, 0x5854, 0xF7B2, 0x5857, 0xD3F3, 0x5858, 0xD3D2, 0x585A, 0xF5C0, 0x585E, 0xDFDD, 0x5861, 0xEEF3, 0x5862, 0xE7F1, 0x5864, 0xFDB4, 0x5875, 0xF2C8, 0x5879, 0xF3D2, 0x587C, 0xEEF4, 0x587E, 0xE2D3, 0x5883, 0xCCD1, 0x5885, 0xDFEA, 0x5889, 0xE9BA, 0x5893, 0xD9D7, 0x589C, 0xF5CD, 0x589E, 0xF1F2, 0x589F, 0xFAC7, 0x58A8, 0xD9F8, 0x58A9, 0xD4C2, 0x58AE, 0xF6E5, 0x58B3, 0xDDC5, 0x58BA, 0xE7F2, 0x58BB, 0xEDDF, 0x58BE, 0xCACB, 0x58C1, 0xDBFA, 0x58C5, 0xE8B5, 0x58C7, 0xD3A6, 0x58CE, 0xFDB5, 0x58D1, 0xF9C9, 0x58D3, 0xE4E2, 0x58D5, 0xFBBD, 0x58D8, 0xD7A4, 0x58D9, 0xCEC5, 0x58DE, 0xCED5, 0x58DF, 0xD6E6, 0x58E4, 0xE5BD, 0x58EB, 0xDECD, 0x58EC, 0xECF3, 0x58EF, 0xEDE0, 0x58F9, 0xECEC, 0x58FA, 0xFBBE, 0x58FB, 0xDFEB, 0x58FD, 0xE1F8, 0x590F, 0xF9BE, 0x5914, 0xD0F3, 0x5915, 0xE0AA, 0x5916, 0xE8E2, 0x5919, 0xE2D4, 0x591A, 0xD2FD, 0x591C, 0xE5A8, 0x5922, 0xD9D3, 0x5927, 0xD3DE, 0x5929, 0xF4B8, 0x592A, 0xF7BC, 0x592B, 0xDCFD, 0x592D, 0xE8EC, 0x592E, 0xE4E7, 0x5931, 0xE3F7, 0x5937, 0xECA8, 0x593E, 0xFAF1, 0x5944, 0xE5F2, 0x5947, 0xD0F4, 0x5948, 0xD2AF, 0x5949, 0xDCE5, 0x594E, 0xD0A5, 0x594F, 0xF1B4, 0x5950, 0xFCB1, 0x5951, 0xCCF8, 0x5954, 0xDDC6, 0x5955, 0xFAD1, 0x5957, 0xF7DF, 0x595A, 0xFAA8, 0x5960, 0xEEF5, 0x5962, 0xDECE, 0x5967, 0xE7F3, 0x596A, 0xF7AC, 0x596B, 0xEBC4, 0x596C, 0xEDE1, 0x596D, 0xE0AB, 0x596E, 0xDDC7, 0x5973, 0xD2B3, 0x5974, 0xD2BF, 0x5978, 0xCACC, 0x597D, 0xFBBF, 0x5982, 0xE5FD, 0x5983, 0xDDE5, 0x5984, 0xD8CD, 0x598A, 0xECF4, 0x5993, 0xD0F5, 0x5996, 0xE8ED, 0x5997, 0xD0D2, 0x5999, 0xD9D8, 0x59A5, 0xF6E6, 0x59A8, 0xDBAA, 0x59AC, 0xF7E0, 0x59B9, 0xD8D9, 0x59BB, 0xF4A3, 0x59BE, 0xF4DD, 0x59C3, 0xEFD1, 0x59C6, 0xD9B5, 0x59C9, 0xEDAB, 0x59CB, 0xE3B7, 0x59D0, 0xEEBB, 0x59D1, 0xCDB4, 0x59D3, 0xE0F3, 0x59D4, 0xEACD, 0x59D9, 0xECF5, 0x59DA, 0xE8EE, 0x59DC, 0xCBA9, 0x59DD, 0xF1AF, 0x59E6, 0xCACD, 0x59E8, 0xECA9, 0x59EA, 0xF2EB, 0x59EC, 0xFDEF, 0x59EE, 0xF9F3, 0x59F8, 0xE6C1, 0x59FB, 0xECD8, 0x59FF, 0xEDAC, 0x5A01, 0xEACE, 0x5A03, 0xE8DF, 0x5A11, 0xDECF, 0x5A18, 0xD2A6, 0x5A1B, 0xE7F4, 0x5A1C, 0xD1D6, 0x5A1F, 0xE6C2, 0x5A20, 0xE3E3, 0x5A25, 0xE4B0, 0x5A29, 0xD8B4, 0x5A36, 0xF6A5, 0x5A3C, 0xF3DE, 0x5A41, 0xD7A5, 0x5A46, 0xF7E8, 0x5A49, 0xE8C6, 0x5A5A, 0xFBE6, 0x5A62, 0xDDE6, 0x5A66, 0xDCFE, 0x5A92, 0xD8DA, 0x5A9A, 0xDAAC, 0x5A9B, 0xEAB0, 0x5AA4, 0xE3B8, 0x5AC1, 0xCAAA, 0x5AC2, 0xE1F9, 0x5AC4, 0xEAB1, 0x5AC9, 0xF2EC, 0x5ACC, 0xFAEE, 0x5AE1, 0xEED5, 0x5AE6, 0xF9F4, 0x5AE9, 0xD2EC, 0x5B05, 0xFBFB, 0x5B09, 0xFDF0, 0x5B0B, 0xE0BD, 0x5B0C, 0xCEE3, 0x5B16, 0xF8C6, 0x5B2A, 0xDEAE, 0x5B40, 0xDFC5, 0x5B43, 0xE5BE, 0x5B50, 0xEDAD, 0x5B51, 0xFAEA, 0x5B54, 0xCDEE, 0x5B55, 0xEDA6, 0x5B57, 0xEDAE, 0x5B58, 0xF0ED, 0x5B5A, 0xDDA1, 0x5B5C, 0xEDAF, 0x5B5D, 0xFCF8, 0x5B5F, 0xD8EB, 0x5B63, 0xCCF9, 0x5B64, 0xCDB5, 0x5B69, 0xFAA9, 0x5B6B, 0xE1DD, 0x5B70, 0xE2D5, 0x5B71, 0xEDCF, 0x5B75, 0xDDA2, 0x5B78, 0xF9CA, 0x5B7A, 0xEAE8, 0x5B7C, 0xE5ED, 0x5B85, 0xD3EB, 0x5B87, 0xE9D4, 0x5B88, 0xE1FA, 0x5B89, 0xE4CC, 0x5B8B, 0xE1E4, 0x5B8C, 0xE8C7, 0x5B8F, 0xCEDB, 0x5B93, 0xDCD5, 0x5B95, 0xF7B5, 0x5B96, 0xFCF3, 0x5B97, 0xF0F3, 0x5B98, 0xCEAF, 0x5B99, 0xF1B5, 0x5B9A, 0xEFD2, 0x5B9B, 0xE8C8, 0x5B9C, 0xEBF1, 0x5BA2, 0xCBD4, 0x5BA3, 0xE0BE, 0x5BA4, 0xE3F8, 0x5BA5, 0xEAE9, 0x5BA6, 0xFCB2, 0x5BAC, 0xE0F4, 0x5BAE, 0xCFE0, 0x5BB0, 0xEEA5, 0x5BB3, 0xFAAA, 0x5BB4, 0xE6C3, 0x5BB5, 0xE1B2, 0x5BB6, 0xCAAB, 0x5BB8, 0xE3E4, 0x5BB9, 0xE9BB, 0x5BBF, 0xE2D6, 0x5BC0, 0xF3F2, 0x5BC2, 0xEED6, 0x5BC3, 0xEAB2, 0x5BC4, 0xD0F6, 0x5BC5, 0xECD9, 0x5BC6, 0xDACB, 0x5BC7, 0xCFA8, 0x5BCC, 0xDDA3, 0x5BD0, 0xD8DB, 0x5BD2, 0xF9CE, 0x5BD3, 0xE9D5, 0x5BD4, 0xE3D1, 0x5BD7, 0xD2BC, 0x5BDE, 0xD8AC, 0x5BDF, 0xF3CC, 0x5BE1, 0xCDFB, 0x5BE2, 0xF6D6, 0x5BE4, 0xE7F5, 0x5BE5, 0xE8EF, 0x5BE6, 0xE3F9, 0x5BE7, 0xD2BB, 0x5BE8, 0xF3F3, 0x5BE9, 0xE3FB, 0x5BEB, 0xDED0, 0x5BEC, 0xCEB0, 0x5BEE, 0xD6F7, 0x5BEF, 0xF1D9, 0x5BF5, 0xF5C1, 0x5BF6, 0xDCC4, 0x5BF8, 0xF5BB, 0x5BFA, 0xDED1, 0x5C01, 0xDCE6, 0x5C04, 0xDED2, 0x5C07, 0xEDE2, 0x5C08, 0xEEF6, 0x5C09, 0xEACF, 0x5C0A, 0xF0EE, 0x5C0B, 0xE3FC, 0x5C0D, 0xD3DF, 0x5C0E, 0xD3F4, 0x5C0F, 0xE1B3, 0x5C11, 0xE1B4, 0x5C16, 0xF4D3, 0x5C19, 0xDFC6, 0x5C24, 0xE9D6, 0x5C28, 0xDBAB, 0x5C31, 0xF6A6, 0x5C38, 0xE3B9, 0x5C39, 0xEBC5, 0x5C3A, 0xF4A9, 0x5C3B, 0xCDB6, 0x5C3C, 0xD2F9, 0x5C3E, 0xDAAD, 0x5C3F, 0xD2E3, 0x5C40, 0xCFD1, 0x5C45, 0xCBDC, 0x5C46, 0xCCFA, 0x5C48, 0xCFDD, 0x5C4B, 0xE8A9, 0x5C4D, 0xE3BB, 0x5C4E, 0xE3BA, 0x5C51, 0xE0DA, 0x5C55, 0xEEF7, 0x5C5B, 0xDCB3, 0x5C60, 0xD3F5, 0x5C62, 0xD7A6, 0x5C64, 0xF6B5, 0x5C65, 0xD7DB, 0x5C6C, 0xE1D5, 0x5C6F, 0xD4EA, 0x5C71, 0xDFA3, 0x5C79, 0xFDDF, 0x5C90, 0xD0F7, 0x5C91, 0xEDD4, 0x5CA1, 0xCBAA, 0x5CA9, 0xE4DB, 0x5CAB, 0xE1FB, 0x5CAC, 0xCBA2, 0x5CB1, 0xD3E0, 0x5CB3, 0xE4BF, 0x5CB5, 0xFBC0, 0x5CB7, 0xDABE, 0x5CB8, 0xE4CD, 0x5CBA, 0xD6B9, 0x5CBE, 0xEFC0, 0x5CC0, 0xE1FC, 0x5CD9, 0xF6B9, 0x5CE0, 0xDFC7, 0x5CE8, 0xE4B1, 0x5CEF, 0xDCE7, 0x5CF0, 0xDCE8, 0x5CF4, 0xFAD6, 0x5CF6, 0xD3F6, 0x5CFB, 0xF1DA, 0x5CFD, 0xFAF2, 0x5D07, 0xE2FD, 0x5D0D, 0xD5CF, 0x5D0E, 0xD0F8, 0x5D11, 0xCDDF, 0x5D14, 0xF5CB, 0x5D16, 0xE4F0, 0x5D17, 0xCBAB, 0x5D19, 0xD7C4, 0x5D27, 0xE2FE, 0x5D29, 0xDDDA, 0x5D4B, 0xDAAE, 0x5D4C, 0xCAEE, 0x5D50, 0xD5B9, 0x5D69, 0xE3A1, 0x5D6C, 0xE8E3, 0x5D6F, 0xF3AB, 0x5D87, 0xCFA9, 0x5D8B, 0xD3F7, 0x5D9D, 0xD4F1, 0x5DA0, 0xCEE4, 0x5DA2, 0xE8F2, 0x5DAA, 0xE5F5, 0x5DB8, 0xE7AE, 0x5DBA, 0xD6BA, 0x5DBC, 0xDFEC, 0x5DBD, 0xE4C0, 0x5DCD, 0xE8E4, 0x5DD2, 0xD8B5, 0x5DD6, 0xE4DC, 0x5DDD, 0xF4B9, 0x5DDE, 0xF1B6, 0x5DE1, 0xE2DE, 0x5DE2, 0xE1B5, 0x5DE5, 0xCDEF, 0x5DE6, 0xF1A7, 0x5DE7, 0xCEE5, 0x5DE8, 0xCBDD, 0x5DEB, 0xD9E3, 0x5DEE, 0xF3AC, 0x5DF1, 0xD0F9, 0x5DF2, 0xECAB, 0x5DF3, 0xDED3, 0x5DF4, 0xF7E9, 0x5DF7, 0xF9F5, 0x5DFD, 0xE1DE, 0x5DFE, 0xCBEE, 0x5E02, 0xE3BC, 0x5E03, 0xF8D6, 0x5E06, 0xDBEE, 0x5E0C, 0xFDF1, 0x5E11, 0xF7B6, 0x5E16, 0xF4DE, 0x5E19, 0xF2ED, 0x5E1B, 0xDBD9, 0x5E1D, 0xF0A8, 0x5E25, 0xE1FD, 0x5E2B, 0xDED4, 0x5E2D, 0xE0AC, 0x5E33, 0xEDE3, 0x5E36, 0xD3E1, 0x5E38, 0xDFC8, 0x5E3D, 0xD9B6, 0x5E3F, 0xFDAC, 0x5E40, 0xEFD3, 0x5E44, 0xE4C1, 0x5E45, 0xF8EB, 0x5E47, 0xDBAC, 0x5E4C, 0xFCC6, 0x5E55, 0xD8AD, 0x5E5F, 0xF6BA, 0x5E61, 0xDBDF, 0x5E62, 0xD3D3, 0x5E63, 0xF8C7, 0x5E72, 0xCACE, 0x5E73, 0xF8C1, 0x5E74, 0xD2B4, 0x5E77, 0xDCB4, 0x5E78, 0xFAB9, 0x5E79, 0xCACF, 0x5E7B, 0xFCB3, 0x5E7C, 0xEAEA, 0x5E7D, 0xEAEB, 0x5E7E, 0xD0FA, 0x5E84, 0xEDE4, 0x5E87, 0xDDE7, 0x5E8A, 0xDFC9, 0x5E8F, 0xDFED, 0x5E95, 0xEEBC, 0x5E97, 0xEFC1, 0x5E9A, 0xCCD2, 0x5E9C, 0xDDA4, 0x5EA0, 0xDFCA, 0x5EA6, 0xD3F8, 0x5EA7, 0xF1A8, 0x5EAB, 0xCDB7, 0x5EAD, 0xEFD4, 0x5EB5, 0xE4DD, 0x5EB6, 0xDFEE, 0x5EB7, 0xCBAC, 0x5EB8, 0xE9BC, 0x5EBE, 0xEAEC, 0x5EC2, 0xDFCB, 0x5EC8, 0xF9BF, 0x5EC9, 0xD6AF, 0x5ECA, 0xD5C6, 0x5ED0, 0xCFAA, 0x5ED3, 0xCEA9, 0x5ED6, 0xD6F8, 0x5EDA, 0xF1B7, 0x5EDB, 0xEEF8, 0x5EDF, 0xD9D9, 0x5EE0, 0xF3DF, 0x5EE2, 0xF8C8, 0x5EE3, 0xCEC6, 0x5EEC, 0xD5E6, 0x5EF3, 0xF4E6, 0x5EF6, 0xE6C5, 0x5EF7, 0xEFD5, 0x5EFA, 0xCBEF, 0x5EFB, 0xFCDF, 0x5F01, 0xDCA7, 0x5F04, 0xD6E7, 0x5F0A, 0xF8C9, 0x5F0F, 0xE3D2, 0x5F11, 0xE3BD, 0x5F13, 0xCFE1, 0x5F14, 0xF0C0, 0x5F15, 0xECDA, 0x5F17, 0xDDD7, 0x5F18, 0xFBF0, 0x5F1B, 0xECAC, 0x5F1F, 0xF0A9, 0x5F26, 0xFAD7, 0x5F27, 0xFBC1, 0x5F29, 0xD2C0, 0x5F31, 0xE5B0, 0x5F35, 0xEDE5, 0x5F3A, 0xCBAD, 0x5F3C, 0xF9B0, 0x5F48, 0xF7A5, 0x5F4A, 0xCBAE, 0x5F4C, 0xDAAF, 0x5F4E, 0xD8B6, 0x5F56, 0xD3A7, 0x5F57, 0xFBB2, 0x5F59, 0xFDC4, 0x5F5B, 0xECAD, 0x5F62, 0xFBA1, 0x5F66, 0xE5E9, 0x5F67, 0xE9EE, 0x5F69, 0xF3F4, 0x5F6A, 0xF8F3, 0x5F6B, 0xF0C1, 0x5F6C, 0xDEAF, 0x5F6D, 0xF8B0, 0x5F70, 0xF3E0, 0x5F71, 0xE7AF, 0x5F77, 0xDBAD, 0x5F79, 0xE6B5, 0x5F7C, 0xF9A8, 0x5F7F, 0xDDD8, 0x5F80, 0xE8D9, 0x5F81, 0xEFD6, 0x5F85, 0xD3E2, 0x5F87, 0xE2DF, 0x5F8A, 0xFCE0, 0x5F8B, 0xD7C8, 0x5F8C, 0xFDAD, 0x5F90, 0xDFEF, 0x5F91, 0xCCD3, 0x5F92, 0xD3F9, 0x5F97, 0xD4F0, 0x5F98, 0xDBC7, 0x5F99, 0xDED5, 0x5F9E, 0xF0F4, 0x5FA0, 0xD5D0, 0x5FA1, 0xE5D9, 0x5FA8, 0xFCC7, 0x5FA9, 0xDCD6, 0x5FAA, 0xE2E0, 0x5FAE, 0xDAB0, 0x5FB5, 0xF3A3, 0x5FB7, 0xD3EC, 0x5FB9, 0xF4CB, 0x5FBD, 0xFDC5, 0x5FC3, 0xE3FD, 0x5FC5, 0xF9B1, 0x5FCC, 0xD0FB, 0x5FCD, 0xECDB, 0x5FD6, 0xF5BC, 0x5FD7, 0xF2A4, 0x5FD8, 0xD8CE, 0x5FD9, 0xD8CF, 0x5FE0, 0xF5F7, 0x5FEB, 0xF6E1, 0x5FF5, 0xD2B7, 0x5FFD, 0xFBEC, 0x5FFF, 0xDDC8, 0x600F, 0xE4E8, 0x6012, 0xD2C1, 0x6016, 0xF8D7, 0x601C, 0xD6BB, 0x601D, 0xDED6, 0x6020, 0xF7BD, 0x6021, 0xECAE, 0x6025, 0xD0E1, 0x6027, 0xE0F5, 0x6028, 0xEAB3, 0x602A, 0xCED6, 0x602F, 0xCCA5, 0x6041, 0xECF6, 0x6042, 0xE2E1, 0x6043, 0xE3BE, 0x604D, 0xFCC8, 0x6050, 0xCDF0, 0x6052, 0xF9F6, 0x6055, 0xDFF0, 0x6059, 0xE5BF, 0x605D, 0xCEBF, 0x6062, 0xFCE1, 0x6063, 0xEDB0, 0x6064, 0xFDD1, 0x6065, 0xF6BB, 0x6068, 0xF9CF, 0x6069, 0xEBDA, 0x606A, 0xCAC1, 0x606C, 0xD2B8, 0x606D, 0xCDF1, 0x606F, 0xE3D3, 0x6070, 0xFDE6, 0x6085, 0xE6ED, 0x6089, 0xE3FA, 0x608C, 0xF0AA, 0x608D, 0xF9D0, 0x6094, 0xFCE2, 0x6096, 0xF8A7, 0x609A, 0xE1E5, 0x609B, 0xEEF9, 0x609F, 0xE7F6, 0x60A0, 0xEAED, 0x60A3, 0xFCB4, 0x60A4, 0xF5C2, 0x60A7, 0xD7DC, 0x60B0, 0xF0F5, 0x60B2, 0xDDE8, 0x60B3, 0xD3ED, 0x60B4, 0xF5FC, 0x60B6, 0xDABF, 0x60B8, 0xCCFB, 0x60BC, 0xD3FA, 0x60BD, 0xF4A4, 0x60C5, 0xEFD7, 0x60C7, 0xD4C3, 0x60D1, 0xFBE3, 0x60DA, 0xFBED, 0x60DC, 0xE0AD, 0x60DF, 0xEAEE, 0x60E0, 0xFBB3, 0x60E1, 0xE4C2, 0x60F0, 0xF6E7, 0x60F1, 0xD2DD, 0x60F3, 0xDFCC, 0x60F6, 0xFCC9, 0x60F9, 0xE5A9, 0x60FA, 0xE0F6, 0x60FB, 0xF6B3, 0x6101, 0xE1FE, 0x6106, 0xCBF0, 0x6108, 0xEAEF, 0x6109, 0xEAF0, 0x610D, 0xDAC0, 0x610E, 0xF8B4, 0x610F, 0xEBF2, 0x6115, 0xE4C3, 0x611A, 0xE9D7, 0x611B, 0xE4F1, 0x611F, 0xCAEF, 0x6127, 0xCED7, 0x6130, 0xFCCA, 0x6134, 0xF3E1, 0x6137, 0xCBC4, 0x613C, 0xE3E5, 0x613E, 0xCBC5, 0x613F, 0xEAB4, 0x6142, 0xE9BD, 0x6144, 0xD7C9, 0x6147, 0xEBDB, 0x6148, 0xEDB1, 0x614A, 0xCCC3, 0x614B, 0xF7BE, 0x614C, 0xFCCB, 0x6153, 0xF8F4, 0x6155, 0xD9B7, 0x6158, 0xF3D3, 0x6159, 0xF3D4, 0x615D, 0xF7E4, 0x615F, 0xF7D1, 0x6162, 0xD8B7, 0x6163, 0xCEB1, 0x6164, 0xCAC2, 0x6167, 0xFBB4, 0x6168, 0xCBC6, 0x616B, 0xF0F6, 0x616E, 0xD5E7, 0x6170, 0xEAD0, 0x6176, 0xCCD4, 0x6177, 0xCBAF, 0x617D, 0xF4AA, 0x617E, 0xE9AF, 0x6181, 0xF5C3, 0x6182, 0xE9D8, 0x618A, 0xDDE9, 0x618E, 0xF1F3, 0x6190, 0xD5FB, 0x6191, 0xDEBB, 0x6194, 0xF4FB, 0x6198, 0xFDF3, 0x6199, 0xFDF2, 0x619A, 0xF7A6, 0x61A4, 0xDDC9, 0x61A7, 0xD4D3, 0x61A9, 0xCCA8, 0x61AB, 0xDAC1, 0x61AC, 0xCCD5, 0x61AE, 0xD9E4, 0x61B2, 0xFACA, 0x61B6, 0xE5E3, 0x61BA, 0xD3BC, 0x61BE, 0xCAF0, 0x61C3, 0xD0C4, 0x61C7, 0xCAD0, 0x61C8, 0xFAAB, 0x61C9, 0xEBEB, 0x61CA, 0xE7F8, 0x61CB, 0xD9E5, 0x61E6, 0xD1D7, 0x61F2, 0xF3A4, 0x61F6, 0xD4FB, 0x61F7, 0xFCE3, 0x61F8, 0xFAD8, 0x61FA, 0xF3D5, 0x61FC, 0xCFAB, 0x61FF, 0xEBF3, 0x6200, 0xD5FC, 0x6207, 0xD3D4, 0x6208, 0xCDFC, 0x620A, 0xD9E6, 0x620C, 0xE2F9, 0x620D, 0xE2A1, 0x620E, 0xEBD4, 0x6210, 0xE0F7, 0x6211, 0xE4B2, 0x6212, 0xCCFC, 0x6216, 0xFBE4, 0x621A, 0xF4AB, 0x621F, 0xD0BD, 0x6221, 0xCAF1, 0x622A, 0xEFB8, 0x622E, 0xD7C0, 0x6230, 0xEEFA, 0x6231, 0xFDF4, 0x6234, 0xD3E3, 0x6236, 0xFBC2, 0x623E, 0xD5E8, 0x623F, 0xDBAE, 0x6240, 0xE1B6, 0x6241, 0xF8B7, 0x6247, 0xE0BF, 0x6248, 0xFBC3, 0x6249, 0xDDEA, 0x624B, 0xE2A2, 0x624D, 0xEEA6, 0x6253, 0xF6E8, 0x6258, 0xF6F5, 0x626E, 0xDDCA, 0x6271, 0xD0E2, 0x6276, 0xDDA6, 0x6279, 0xDDEB, 0x627C, 0xE4F9, 0x627F, 0xE3AF, 0x6280, 0xD0FC, 0x6284, 0xF4FC, 0x6289, 0xCCBC, 0x628A, 0xF7EA, 0x6291, 0xE5E4, 0x6292, 0xDFF1, 0x6295, 0xF7E1, 0x6297, 0xF9F7, 0x6298, 0xEFB9, 0x629B, 0xF8D8, 0x62AB, 0xF9A9, 0x62B1, 0xF8D9, 0x62B5, 0xEEBD, 0x62B9, 0xD8C6, 0x62BC, 0xE4E3, 0x62BD, 0xF5CE, 0x62C2, 0xDDD9, 0x62C7, 0xD9E7, 0x62C8, 0xD2B9, 0x62C9, 0xD5C3, 0x62CC, 0xDAE5, 0x62CD, 0xDAD0, 0x62CF, 0xD1D9, 0x62D0, 0xCED8, 0x62D2, 0xCBDE, 0x62D3, 0xF4AC, 0x62D4, 0xDAFB, 0x62D6, 0xF6E9, 0x62D7, 0xE8F3, 0x62D8, 0xCFAC, 0x62D9, 0xF0F0, 0x62DB, 0xF4FD, 0x62DC, 0xDBC8, 0x62EC, 0xCEC0, 0x62ED, 0xE3D4, 0x62EE, 0xD1CF, 0x62EF, 0xF1F5, 0x62F1, 0xCDF2, 0x62F3, 0xCFEB, 0x62F7, 0xCDB8, 0x62FE, 0xE3A6, 0x62FF, 0xD1DA, 0x6301, 0xF2A5, 0x6307, 0xF2A6, 0x6309, 0xE4CE, 0x6311, 0xD3FB, 0x632B, 0xF1A9, 0x632F, 0xF2C9, 0x633A, 0xEFD8, 0x633B, 0xE6C9, 0x633D, 0xD8B8, 0x633E, 0xFAF3, 0x6349, 0xF3B5, 0x634C, 0xF8A4, 0x634F, 0xD1F3, 0x6350, 0xE6C8, 0x6355, 0xF8DA, 0x6367, 0xDCE9, 0x6368, 0xDED7, 0x636E, 0xCBDF, 0x6372, 0xCFEC, 0x6377, 0xF4DF, 0x637A, 0xD1F4, 0x637B, 0xD2BA, 0x637F, 0xDFF2, 0x6383, 0xE1B7, 0x6388, 0xE2A3, 0x6389, 0xD3FC, 0x638C, 0xEDE6, 0x6392, 0xDBC9, 0x6396, 0xE4FA, 0x6398, 0xCFDE, 0x639B, 0xCED0, 0x63A0, 0xD5D3, 0x63A1, 0xF3F5, 0x63A2, 0xF7AE, 0x63A5, 0xEFC8, 0x63A7, 0xCDF3, 0x63A8, 0xF5CF, 0x63A9, 0xE5F3, 0x63AA, 0xF0C2, 0x63C0, 0xCAD1, 0x63C4, 0xEAF1, 0x63C6, 0xD0A6, 0x63CF, 0xD9DA, 0x63D0, 0xF0AB, 0x63D6, 0xEBE7, 0x63DA, 0xE5C0, 0x63DB, 0xFCB5, 0x63E1, 0xE4C4, 0x63ED, 0xCCA9, 0x63EE, 0xFDC6, 0x63F4, 0xEAB5, 0x63F6, 0xE5AA, 0x63F7, 0xDFBA, 0x640D, 0xE1DF, 0x640F, 0xDAD1, 0x6414, 0xE1B8, 0x6416, 0xE8F4, 0x6417, 0xD3FD, 0x641C, 0xE2A4, 0x6422, 0xF2CA, 0x642C, 0xDAE6, 0x642D, 0xF7B3, 0x643A, 0xFDCD, 0x643E, 0xF3B6, 0x6458, 0xEED7, 0x6460, 0xF5C4, 0x6469, 0xD8A4, 0x646F, 0xF2A7, 0x6478, 0xD9B8, 0x6479, 0xD9B9, 0x647A, 0xEFC9, 0x6488, 0xD6CE, 0x6491, 0xF7CB, 0x6492, 0xDFAE, 0x6493, 0xE8F5, 0x649A, 0xD2B5, 0x649E, 0xD3D5, 0x64A4, 0xF4CC, 0x64A5, 0xDAFC, 0x64AB, 0xD9E8, 0x64AD, 0xF7EB, 0x64AE, 0xF5C9, 0x64B0, 0xF3BC, 0x64B2, 0xDAD2, 0x64BB, 0xD3B5, 0x64C1, 0xE8B6, 0x64C4, 0xD6CF, 0x64C5, 0xF4BA, 0x64C7, 0xF7C9, 0x64CA, 0xCCAA, 0x64CD, 0xF0C3, 0x64CE, 0xCCD6, 0x64D2, 0xD0D3, 0x64D4, 0xD3BD, 0x64D8, 0xDBFB, 0x64DA, 0xCBE0, 0x64E1, 0xD3E4, 0x64E2, 0xF6F7, 0x64E5, 0xD5BA, 0x64E6, 0xF3CD, 0x64E7, 0xCBE1, 0x64EC, 0xEBF4, 0x64F2, 0xF4AD, 0x64F4, 0xFCAA, 0x64FA, 0xF7EC, 0x64FE, 0xE8F6, 0x6500, 0xDAE7, 0x6504, 0xF7CC, 0x6518, 0xE5C1, 0x651D, 0xE0EE, 0x6523, 0xD5FD, 0x652A, 0xCEE6, 0x652B, 0xFCAB, 0x652C, 0xD5BB, 0x652F, 0xF2A8, 0x6536, 0xE2A5, 0x6537, 0xCDB9, 0x6538, 0xEAF2, 0x6539, 0xCBC7, 0x653B, 0xCDF4, 0x653E, 0xDBAF, 0x653F, 0xEFD9, 0x6545, 0xCDBA, 0x6548, 0xFCF9, 0x654D, 0xDFF3, 0x654E, 0xCEE7, 0x654F, 0xDAC2, 0x6551, 0xCFAD, 0x6556, 0xE7F9, 0x6557, 0xF8A8, 0x655E, 0xF3E2, 0x6562, 0xCAF2, 0x6563, 0xDFA4, 0x6566, 0xD4C4, 0x656C, 0xCCD7, 0x656D, 0xE5C2, 0x6572, 0xCDBB, 0x6574, 0xEFDA, 0x6575, 0xEED8, 0x6577, 0xDDA7, 0x6578, 0xE2A6, 0x657E, 0xE0C0, 0x6582, 0xD6B0, 0x6583, 0xF8CA, 0x6585, 0xFCFA, 0x6587, 0xD9FE, 0x658C, 0xDEB0, 0x6590, 0xDDEC, 0x6591, 0xDAE8, 0x6597, 0xD4E0, 0x6599, 0xD6F9, 0x659B, 0xCDD7, 0x659C, 0xDED8, 0x659F, 0xF2F8, 0x65A1, 0xE4D6, 0x65A4, 0xD0C5, 0x65A5, 0xF4AE, 0x65A7, 0xDDA8, 0x65AB, 0xEDC5, 0x65AC, 0xF3D6, 0x65AF, 0xDED9, 0x65B0, 0xE3E6, 0x65B7, 0xD3A8, 0x65B9, 0xDBB0, 0x65BC, 0xE5DA, 0x65BD, 0xE3BF, 0x65C1, 0xDBB1, 0x65C5, 0xD5E9, 0x65CB, 0xE0C1, 0x65CC, 0xEFDB, 0x65CF, 0xF0E9, 0x65D2, 0xD7B2, 0x65D7, 0xD0FD, 0x65E0, 0xD9E9, 0x65E3, 0xD0FE, 0x65E5, 0xECED, 0x65E6, 0xD3A9, 0x65E8, 0xF2A9, 0x65E9, 0xF0C4, 0x65EC, 0xE2E2, 0x65ED, 0xE9EF, 0x65F1, 0xF9D1, 0x65F4, 0xE9D9, 0x65FA, 0xE8DA, 0x65FB, 0xDAC3, 0x65FC, 0xDAC4, 0x65FD, 0xD4C5, 0x65FF, 0xE7FA, 0x6606, 0xCDE0, 0x6607, 0xE3B0, 0x6609, 0xDBB2, 0x660A, 0xFBC4, 0x660C, 0xF3E3, 0x660E, 0xD9A5, 0x660F, 0xFBE7, 0x6610, 0xDDCB, 0x6611, 0xD0D4, 0x6613, 0xE6B6, 0x6614, 0xE0AE, 0x6615, 0xFDDA, 0x661E, 0xDCB5, 0x661F, 0xE0F8, 0x6620, 0xE7B1, 0x6625, 0xF5F0, 0x6627, 0xD8DC, 0x6628, 0xEDC6, 0x662D, 0xE1B9, 0x662F, 0xE3C0, 0x6630, 0xF9C0, 0x6631, 0xE9F0, 0x6634, 0xD9DB, 0x6636, 0xF3E4, 0x663A, 0xDCB6, 0x663B, 0xE4E9, 0x6641, 0xF0C5, 0x6642, 0xE3C1, 0x6643, 0xFCCC, 0x6644, 0xFCCD, 0x6649, 0xF2CB, 0x664B, 0xF2CC, 0x664F, 0xE4CF, 0x6659, 0xF1DB, 0x665B, 0xFAD9, 0x665D, 0xF1B8, 0x665E, 0xFDF5, 0x665F, 0xE0F9, 0x6664, 0xE7FB, 0x6665, 0xFCB7, 0x6666, 0xFCE4, 0x6667, 0xFBC5, 0x6668, 0xE3E7, 0x6669, 0xD8B9, 0x666B, 0xF6F8, 0x666E, 0xDCC5, 0x666F, 0xCCD8, 0x6673, 0xE0AF, 0x6674, 0xF4E7, 0x6676, 0xEFDC, 0x6677, 0xCFFC, 0x6678, 0xEFDD, 0x667A, 0xF2AA, 0x6684, 0xFDBE, 0x6687, 0xCAAC, 0x6688, 0xFDBB, 0x6689, 0xFDC7, 0x668E, 0xE7B2, 0x6690, 0xEAD1, 0x6691, 0xDFF4, 0x6696, 0xD1EC, 0x6697, 0xE4DE, 0x6698, 0xE5C3, 0x669D, 0xD9A6, 0x66A0, 0xCDBC, 0x66A2, 0xF3E5, 0x66AB, 0xEDD5, 0x66AE, 0xD9BA, 0x66B2, 0xEDE7, 0x66B3, 0xFBB5, 0x66B4, 0xF8EC, 0x66B9, 0xE0E7, 0x66BB, 0xCCD9, 0x66BE, 0xD4C6, 0x66C4, 0xE7A5, 0x66C6, 0xD5F5, 0x66C7, 0xD3BE, 0x66C9, 0xFCFB, 0x66D6, 0xE4F2, 0x66D9, 0xDFF5, 0x66DC, 0xE8F8, 0x66DD, 0xF8ED, 0x66E0, 0xCEC7, 0x66E6, 0xFDF6, 0x66F0, 0xE8D8, 0x66F2, 0xCDD8, 0x66F3, 0xE7D6, 0x66F4, 0xCCDA, 0x66F7, 0xCAE3, 0x66F8, 0xDFF6, 0x66F9, 0xF0C7, 0x66FA, 0xF0C6, 0x66FC, 0xD8BA, 0x66FE, 0xF1F4, 0x66FF, 0xF4F0, 0x6700, 0xF5CC, 0x6703, 0xFCE5, 0x6708, 0xEAC5, 0x6709, 0xEAF3, 0x670B, 0xDDDB, 0x670D, 0xDCD7, 0x6714, 0xDEFD, 0x6715, 0xF2F9, 0x6717, 0xD5C7, 0x671B, 0xD8D0, 0x671D, 0xF0C8, 0x671E, 0xD1A1, 0x671F, 0xD1A2, 0x6726, 0xD9D4, 0x6727, 0xD6E8, 0x6728, 0xD9CA, 0x672A, 0xDAB1, 0x672B, 0xD8C7, 0x672C, 0xDCE2, 0x672D, 0xF3CE, 0x672E, 0xF5F4, 0x6731, 0xF1B9, 0x6734, 0xDAD3, 0x6736, 0xF6EA, 0x673A, 0xCFF5, 0x673D, 0xFDAE, 0x6746, 0xCAD2, 0x6749, 0xDFB4, 0x674E, 0xD7DD, 0x674F, 0xFABA, 0x6750, 0xEEA7, 0x6751, 0xF5BD, 0x6753, 0xF8F5, 0x6756, 0xEDE8, 0x675C, 0xD4E1, 0x675E, 0xD1A3, 0x675F, 0xE1D6, 0x676D, 0xF9F8, 0x676F, 0xDBCA, 0x6770, 0xCBF9, 0x6771, 0xD4D4, 0x6773, 0xD9DC, 0x6775, 0xEEBE, 0x6777, 0xF7ED, 0x677B, 0xD2EE, 0x677E, 0xE1E6, 0x677F, 0xF7F9, 0x6787, 0xDDED, 0x6789, 0xE8DB, 0x678B, 0xDBB3, 0x678F, 0xD1F7, 0x6790, 0xE0B0, 0x6793, 0xD4E2, 0x6795, 0xF6D7, 0x6797, 0xD7F9, 0x679A, 0xD8DD, 0x679C, 0xCDFD, 0x679D, 0xF2AB, 0x67AF, 0xCDBD, 0x67B0, 0xF8C2, 0x67B3, 0xF2AC, 0x67B6, 0xCAAD, 0x67B7, 0xCAAE, 0x67B8, 0xCFAE, 0x67BE, 0xE3C2, 0x67C4, 0xDCB7, 0x67CF, 0xDBDA, 0x67D0, 0xD9BB, 0x67D1, 0xCAF3, 0x67D2, 0xF6D3, 0x67D3, 0xE6F8, 0x67D4, 0xEAF5, 0x67DA, 0xEAF6, 0x67DD, 0xF6F9, 0x67E9, 0xCFAF, 0x67EC, 0xCAD3, 0x67EF, 0xCAAF, 0x67F0, 0xD2B0, 0x67F1, 0xF1BA, 0x67F3, 0xD7B3, 0x67F4, 0xE3C3, 0x67F5, 0xF3FD, 0x67F6, 0xDEDA, 0x67FB, 0xDEDB, 0x67FE, 0xEFDE, 0x6812, 0xE2E3, 0x6813, 0xEEFB, 0x6816, 0xDFF7, 0x6817, 0xD7CA, 0x6821, 0xCEE8, 0x6822, 0xDBDB, 0x682A, 0xF1BB, 0x682F, 0xE9F1, 0x6838, 0xFAB7, 0x6839, 0xD0C6, 0x683C, 0xCCAB, 0x683D, 0xEEA8, 0x6840, 0xCBFA, 0x6841, 0xF9F9, 0x6842, 0xCCFD, 0x6843, 0xD3FE, 0x6848, 0xE4D0, 0x684E, 0xF2EE, 0x6850, 0xD4D5, 0x6851, 0xDFCD, 0x6853, 0xFCB8, 0x6854, 0xD1D0, 0x686D, 0xF2CD, 0x6876, 0xF7D2, 0x687F, 0xCAD4, 0x6881, 0xD5D9, 0x6885, 0xD8DE, 0x688F, 0xCDD9, 0x6893, 0xEEA9, 0x6894, 0xF6BC, 0x6897, 0xCCDB, 0x689D, 0xF0C9, 0x689F, 0xFCFC, 0x68A1, 0xE8C9, 0x68A2, 0xF4FE, 0x68A7, 0xE7FC, 0x68A8, 0xD7DE, 0x68AD, 0xDEDC, 0x68AF, 0xF0AC, 0x68B0, 0xCCFE, 0x68B1, 0xCDE1, 0x68B3, 0xE1BA, 0x68B5, 0xDBEF, 0x68B6, 0xDAB2, 0x68C4, 0xD1A5, 0x68C5, 0xDCB8, 0x68C9, 0xD8F6, 0x68CB, 0xD1A4, 0x68CD, 0xCDE2, 0x68D2, 0xDCEA, 0x68D5, 0xF0F7, 0x68D7, 0xF0CA, 0x68D8, 0xD0BE, 0x68DA, 0xDDDC, 0x68DF, 0xD4D6, 0x68E0, 0xD3D6, 0x68E7, 0xEDD0, 0x68E8, 0xCDA1, 0x68EE, 0xDFB5, 0x68F2, 0xDFF8, 0x68F9, 0xD4A1, 0x68FA, 0xCEB2, 0x6900, 0xE8CA, 0x6905, 0xEBF5, 0x690D, 0xE3D5, 0x690E, 0xF5D0, 0x6912, 0xF5A1, 0x6927, 0xD9A7, 0x6930, 0xE5AB, 0x693D, 0xE6CB, 0x693F, 0xF5F1, 0x694A, 0xE5C5, 0x6953, 0xF9A3, 0x6954, 0xE0DB, 0x6955, 0xF6EB, 0x6957, 0xCBF1, 0x6959, 0xD9EA, 0x695A, 0xF5A2, 0x695E, 0xD7D1, 0x6960, 0xD1F8, 0x6961, 0xEAF8, 0x6962, 0xEAF9, 0x6963, 0xDAB3, 0x6968, 0xEFDF, 0x696B, 0xF1EF, 0x696D, 0xE5F6, 0x696E, 0xEEBF, 0x696F, 0xE2E4, 0x6975, 0xD0BF, 0x6977, 0xFAAC, 0x6978, 0xF5D1, 0x6979, 0xE7B3, 0x6995, 0xE9BE, 0x699B, 0xF2CE, 0x699C, 0xDBB4, 0x69A5, 0xFCCE, 0x69A7, 0xDDEE, 0x69AE, 0xE7B4, 0x69B4, 0xD7B4, 0x69BB, 0xF7B4, 0x69C1, 0xCDBE, 0x69C3, 0xDAE9, 0x69CB, 0xCFB0, 0x69CC, 0xF7D9, 0x69CD, 0xF3E6, 0x69D0, 0xCED9, 0x69E8, 0xCEAA, 0x69EA, 0xCBC8, 0x69FB, 0xD0A7, 0x69FD, 0xF0CB, 0x69FF, 0xD0C7, 0x6A02, 0xE4C5, 0x6A0A, 0xDBE0, 0x6A11, 0xD5DA, 0x6A13, 0xD7A7, 0x6A17, 0xEEC0, 0x6A19, 0xF8F6, 0x6A1E, 0xF5D2, 0x6A1F, 0xEDE9, 0x6A21, 0xD9BC, 0x6A23, 0xE5C6, 0x6A35, 0xF5A3, 0x6A38, 0xDAD4, 0x6A39, 0xE2A7, 0x6A3A, 0xFBFC, 0x6A3D, 0xF1DC, 0x6A44, 0xCAF4, 0x6A48, 0xE8FA, 0x6A4B, 0xCEE9, 0x6A52, 0xE9F8, 0x6A53, 0xE2E5, 0x6A58, 0xD0B9, 0x6A59, 0xD4F2, 0x6A5F, 0xD1A6, 0x6A61, 0xDFCE, 0x6A6B, 0xFCF4, 0x6A80, 0xD3AA, 0x6A84, 0xCCAC, 0x6A89, 0xEFE0, 0x6A8D, 0xE5E5, 0x6A8E, 0xD0D5, 0x6A97, 0xDBFC, 0x6A9C, 0xFCE6, 0x6AA2, 0xCBFE, 0x6AA3, 0xEDEA, 0x6AB3, 0xDEB1, 0x6ABB, 0xF9E3, 0x6AC2, 0xD4A2, 0x6AC3, 0xCFF6, 0x6AD3, 0xD6D0, 0x6ADA, 0xD5EA, 0x6ADB, 0xF1EE, 0x6AF6, 0xFACB, 0x6AFB, 0xE5A1, 0x6B04, 0xD5B1, 0x6B0A, 0xCFED, 0x6B0C, 0xEDEB, 0x6B12, 0xD5B2, 0x6B16, 0xD5BC, 0x6B20, 0xFDE2, 0x6B21, 0xF3AD, 0x6B23, 0xFDDB, 0x6B32, 0xE9B0, 0x6B3A, 0xD1A7, 0x6B3D, 0xFDE3, 0x6B3E, 0xCEB3, 0x6B46, 0xFDE4, 0x6B47, 0xFACE, 0x6B4C, 0xCAB0, 0x6B4E, 0xF7A7, 0x6B50, 0xCFB1, 0x6B5F, 0xE6A2, 0x6B61, 0xFCB6, 0x6B62, 0xF2AD, 0x6B63, 0xEFE1, 0x6B64, 0xF3AE, 0x6B65, 0xDCC6, 0x6B66, 0xD9EB, 0x6B6A, 0xE8E0, 0x6B72, 0xE1A8, 0x6B77, 0xD5F6, 0x6B78, 0xCFFD, 0x6B7B, 0xDEDD, 0x6B7F, 0xD9D1, 0x6B83, 0xE4EA, 0x6B84, 0xF2CF, 0x6B86, 0xF7BF, 0x6B89, 0xE2E6, 0x6B8A, 0xE2A8, 0x6B96, 0xE3D6, 0x6B98, 0xEDD1, 0x6B9E, 0xE9F9, 0x6BAE, 0xD6B1, 0x6BAF, 0xDEB2, 0x6BB2, 0xE0E8, 0x6BB5, 0xD3AB, 0x6BB7, 0xEBDC, 0x6BBA, 0xDFAF, 0x6BBC, 0xCAC3, 0x6BBF, 0xEEFC, 0x6BC1, 0xFDC3, 0x6BC5, 0xEBF6, 0x6BC6, 0xCFB2, 0x6BCB, 0xD9EC, 0x6BCD, 0xD9BD, 0x6BCF, 0xD8DF, 0x6BD2, 0xD4B8, 0x6BD3, 0xEBBE, 0x6BD4, 0xDDEF, 0x6BD6, 0xDDF0, 0x6BD7, 0xDDF1, 0x6BD8, 0xDDF2, 0x6BDB, 0xD9BE, 0x6BEB, 0xFBC6, 0x6BEC, 0xCFB3, 0x6C08, 0xEEFD, 0x6C0F, 0xE4AB, 0x6C11, 0xDAC5, 0x6C13, 0xD8EC, 0x6C23, 0xD1A8, 0x6C34, 0xE2A9, 0x6C37, 0xDEBC, 0x6C38, 0xE7B5, 0x6C3E, 0xDBF0, 0x6C40, 0xEFE2, 0x6C41, 0xF1F0, 0x6C42, 0xCFB4, 0x6C4E, 0xDBF1, 0x6C50, 0xE0B1, 0x6C55, 0xDFA5, 0x6C57, 0xF9D2, 0x6C5A, 0xE7FD, 0x6C5D, 0xE6A3, 0x6C5E, 0xFBF1, 0x6C5F, 0xCBB0, 0x6C60, 0xF2AE, 0x6C68, 0xCDE7, 0x6C6A, 0xE8DC, 0x6C6D, 0xE7D7, 0x6C70, 0xF7C0, 0x6C72, 0xD0E3, 0x6C76, 0xDAA1, 0x6C7A, 0xCCBD, 0x6C7D, 0xD1A9, 0x6C7E, 0xDDCC, 0x6C81, 0xE3FE, 0x6C82, 0xD1AA, 0x6C83, 0xE8AA, 0x6C85, 0xEAB6, 0x6C86, 0xF9FA, 0x6C87, 0xE6CC, 0x6C88, 0xF6D8, 0x6C8C, 0xD4C7, 0x6C90, 0xD9CB, 0x6C92, 0xD9D2, 0x6C93, 0xD3CB, 0x6C94, 0xD8F7, 0x6C95, 0xDAA9, 0x6C96, 0xF5F8, 0x6C99, 0xDEDE, 0x6C9A, 0xF2AF, 0x6C9B, 0xF8A9, 0x6CAB, 0xD8C8, 0x6CAE, 0xEEC1, 0x6CB3, 0xF9C1, 0x6CB8, 0xDDF3, 0x6CB9, 0xEAFA, 0x6CBB, 0xF6BD, 0x6CBC, 0xE1BB, 0x6CBD, 0xCDBF, 0x6CBE, 0xF4D4, 0x6CBF, 0xE6CD, 0x6CC1, 0xFCCF, 0x6CC2, 0xFBA2, 0x6CC4, 0xE0DC, 0x6CC9, 0xF4BB, 0x6CCA, 0xDAD5, 0x6CCC, 0xF9B2, 0x6CD3, 0xFBF2, 0x6CD5, 0xDBF6, 0x6CD7, 0xDEDF, 0x6CDB, 0xDBF2, 0x6CE1, 0xF8DC, 0x6CE2, 0xF7EE, 0x6CE3, 0xEBE8, 0x6CE5, 0xD2FA, 0x6CE8, 0xF1BC, 0x6CEB, 0xFADA, 0x6CEE, 0xDAEA, 0x6CEF, 0xDAC6, 0x6CF0, 0xF7C1, 0x6CF3, 0xE7B6, 0x6D0B, 0xE5C7, 0x6D0C, 0xD6AC, 0x6D11, 0xDCC7, 0x6D17, 0xE1A9, 0x6D19, 0xE2AA, 0x6D1B, 0xD5A6, 0x6D1E, 0xD4D7, 0x6D25, 0xF2D0, 0x6D27, 0xEAFB, 0x6D29, 0xE0DD, 0x6D2A, 0xFBF3, 0x6D32, 0xF1BD, 0x6D35, 0xE2E7, 0x6D36, 0xFDD7, 0x6D38, 0xCEC8, 0x6D39, 0xEAB7, 0x6D3B, 0xFCC0, 0x6D3D, 0xFDE7, 0x6D3E, 0xF7EF, 0x6D41, 0xD7B5, 0x6D59, 0xEFBA, 0x6D5A, 0xF1DD, 0x6D5C, 0xDEB3, 0x6D63, 0xE8CB, 0x6D66, 0xF8DD, 0x6D69, 0xFBC7, 0x6D6A, 0xD5C8, 0x6D6C, 0xD7DF, 0x6D6E, 0xDDA9, 0x6D74, 0xE9B1, 0x6D77, 0xFAAD, 0x6D78, 0xF6D9, 0x6D79, 0xFAF4, 0x6D7F, 0xF8AA, 0x6D85, 0xE6EE, 0x6D87, 0xCCDC, 0x6D88, 0xE1BC, 0x6D89, 0xE0EF, 0x6D8C, 0xE9BF, 0x6D8D, 0xFCFD, 0x6D8E, 0xE6CE, 0x6D91, 0xE1D7, 0x6D93, 0xE6CF, 0x6D95, 0xF4F1, 0x6DAF, 0xE4F3, 0x6DB2, 0xE4FB, 0x6DB5, 0xF9E4, 0x6DC0, 0xEFE3, 0x6DC3, 0xCFEE, 0x6DC4, 0xF6BE, 0x6DC5, 0xE0B2, 0x6DC6, 0xFCFE, 0x6DC7, 0xD1AB, 0x6DCB, 0xD7FA, 0x6DCF, 0xFBC8, 0x6DD1, 0xE2D7, 0x6DD8, 0xD4A3, 0x6DD9, 0xF0F8, 0x6DDA, 0xD7A8, 0x6DDE, 0xE1E7, 0x6DE1, 0xD3BF, 0x6DE8, 0xEFE4, 0x6DEA, 0xD7C5, 0x6DEB, 0xEBE2, 0x6DEE, 0xFCE7, 0x6DF1, 0xE4A2, 0x6DF3, 0xE2E8, 0x6DF5, 0xE6D0, 0x6DF7, 0xFBE8, 0x6DF8, 0xF4E8, 0x6DF9, 0xE5F4, 0x6DFA, 0xF4BC, 0x6DFB, 0xF4D5, 0x6E17, 0xDFB6, 0x6E19, 0xFCB9, 0x6E1A, 0xEEC2, 0x6E1B, 0xCAF5, 0x6E1F, 0xEFE5, 0x6E20, 0xCBE2, 0x6E21, 0xD4A4, 0x6E23, 0xDEE0, 0x6E24, 0xDAFD, 0x6E25, 0xE4C6, 0x6E26, 0xE8BE, 0x6E2B, 0xE0DE, 0x6E2C, 0xF6B4, 0x6E2D, 0xEAD2, 0x6E2F, 0xF9FB, 0x6E32, 0xE0C2, 0x6E34, 0xCAE4, 0x6E36, 0xE7B7, 0x6E38, 0xEAFD, 0x6E3A, 0xD9DD, 0x6E3C, 0xDAB4, 0x6E3D, 0xEEAA, 0x6E3E, 0xFBE9, 0x6E43, 0xDBCB, 0x6E44, 0xDAB5, 0x6E4A, 0xF1BE, 0x6E4D, 0xD3AC, 0x6E56, 0xFBC9, 0x6E58, 0xDFCF, 0x6E5B, 0xD3C0, 0x6E5C, 0xE3D7, 0x6E5E, 0xEFE6, 0x6E5F, 0xFCD0, 0x6E67, 0xE9C0, 0x6E6B, 0xF5D3, 0x6E6E, 0xECDC, 0x6E6F, 0xF7B7, 0x6E72, 0xEAB8, 0x6E73, 0xD1F9, 0x6E7A, 0xDCC8, 0x6E90, 0xEAB9, 0x6E96, 0xF1DE, 0x6E9C, 0xD7B6, 0x6E9D, 0xCFB5, 0x6E9F, 0xD9A8, 0x6EA2, 0xECEE, 0x6EA5, 0xDDAA, 0x6EAA, 0xCDA2, 0x6EAB, 0xE8AE, 0x6EAF, 0xE1BD, 0x6EB1, 0xF2D1, 0x6EB6, 0xE9C1, 0x6EBA, 0xD2FC, 0x6EC2, 0xDBB5, 0x6EC4, 0xF3E7, 0x6EC5, 0xD8FE, 0x6EC9, 0xFCD1, 0x6ECB, 0xEDB2, 0x6ECC, 0xF4AF, 0x6ECE, 0xFBA3, 0x6ED1, 0xFCC1, 0x6ED3, 0xEEAB, 0x6ED4, 0xD4A5, 0x6EEF, 0xF4F2, 0x6EF4, 0xEED9, 0x6EF8, 0xFBCA, 0x6EFE, 0xCDE3, 0x6EFF, 0xD8BB, 0x6F01, 0xE5DB, 0x6F02, 0xF8F7, 0x6F06, 0xF6D4, 0x6F0F, 0xD7A9, 0x6F11, 0xCBC9, 0x6F14, 0xE6D1, 0x6F15, 0xF0CC, 0x6F20, 0xD8AE, 0x6F22, 0xF9D3, 0x6F23, 0xD5FE, 0x6F2B, 0xD8BC, 0x6F2C, 0xF2B0, 0x6F31, 0xE2AB, 0x6F32, 0xF3E8, 0x6F38, 0xEFC2, 0x6F3F, 0xEDEC, 0x6F41, 0xE7B8, 0x6F51, 0xDAFE, 0x6F54, 0xCCBE, 0x6F57, 0xF2FC, 0x6F58, 0xDAEB, 0x6F5A, 0xE2D8, 0x6F5B, 0xEDD6, 0x6F5E, 0xD6D1, 0x6F5F, 0xE0B3, 0x6F62, 0xFCD2, 0x6F64, 0xEBC8, 0x6F6D, 0xD3C1, 0x6F6E, 0xF0CD, 0x6F70, 0xCFF7, 0x6F7A, 0xEDD2, 0x6F7C, 0xD4D8, 0x6F7D, 0xDCC9, 0x6F7E, 0xD7F1, 0x6F81, 0xDFBB, 0x6F84, 0xF3A5, 0x6F88, 0xF4CD, 0x6F8D, 0xF1BF, 0x6F8E, 0xF8B1, 0x6F90, 0xE9FA, 0x6F94, 0xFBCB, 0x6F97, 0xCAD5, 0x6FA3, 0xF9D4, 0x6FA4, 0xF7CA, 0x6FA7, 0xD6C8, 0x6FAE, 0xFCE8, 0x6FAF, 0xF3BD, 0x6FB1, 0xEEFE, 0x6FB3, 0xE7FE, 0x6FB9, 0xD3C2, 0x6FBE, 0xD3B6, 0x6FC0, 0xCCAD, 0x6FC1, 0xF6FA, 0x6FC2, 0xD6B2, 0x6FC3, 0xD2D8, 0x6FCA, 0xE7D8, 0x6FD5, 0xE3A5, 0x6FDA, 0xE7B9, 0x6FDF, 0xF0AD, 0x6FE0, 0xFBCC, 0x6FE1, 0xEBA1, 0x6FE4, 0xD4A6, 0x6FE9, 0xFBCD, 0x6FEB, 0xD5BD, 0x6FEC, 0xF1DF, 0x6FEF, 0xF6FB, 0x6FF1, 0xDEB4, 0x6FFE, 0xD5EB, 0x7001, 0xE5C8, 0x7005, 0xFBA4, 0x7006, 0xD4B9, 0x7009, 0xDEE1, 0x700B, 0xE4A3, 0x700F, 0xD7B7, 0x7011, 0xF8EE, 0x7015, 0xDEB5, 0x7018, 0xD6D2, 0x701A, 0xF9D5, 0x701B, 0xE7BA, 0x701C, 0xEBD5, 0x701D, 0xD5F7, 0x701E, 0xEFE7, 0x701F, 0xE1BE, 0x7023, 0xFAAE, 0x7027, 0xD6E9, 0x7028, 0xD6EE, 0x702F, 0xE7BB, 0x7037, 0xECCB, 0x703E, 0xD5B3, 0x704C, 0xCEB4, 0x7050, 0xFBA5, 0x7051, 0xE1EE, 0x7058, 0xF7A8, 0x705D, 0xFBCE, 0x7063, 0xD8BD, 0x706B, 0xFBFD, 0x7070, 0xFCE9, 0x7078, 0xCFB6, 0x707C, 0xEDC7, 0x707D, 0xEEAC, 0x7085, 0xCCDD, 0x708A, 0xF6A7, 0x708E, 0xE6FA, 0x7092, 0xF5A4, 0x7098, 0xFDDC, 0x7099, 0xEDB3, 0x709A, 0xCEC9, 0x70A1, 0xEFE8, 0x70A4, 0xE1BF, 0x70AB, 0xFADB, 0x70AC, 0xCBE3, 0x70AD, 0xF7A9, 0x70AF, 0xFBA6, 0x70B3, 0xDCB9, 0x70B7, 0xF1C0, 0x70B8, 0xEDC8, 0x70B9, 0xEFC3, 0x70C8, 0xD6AD, 0x70CB, 0xFDCE, 0x70CF, 0xE8A1, 0x70D8, 0xFBF4, 0x70D9, 0xD5A7, 0x70DD, 0xF1F6, 0x70DF, 0xE6D3, 0x70F1, 0xCCDE, 0x70F9, 0xF8B2, 0x70FD, 0xDCEB, 0x7104, 0xFDB6, 0x7109, 0xE5EA, 0x710C, 0xF1E0, 0x7119, 0xDBCC, 0x711A, 0xDDCD, 0x711E, 0xD4C8, 0x7121, 0xD9ED, 0x7126, 0xF5A5, 0x7130, 0xE6FB, 0x7136, 0xE6D4, 0x7147, 0xFDC8, 0x7149, 0xD6A1, 0x714A, 0xFDBF, 0x714C, 0xFCD3, 0x714E, 0xEFA1, 0x7150, 0xE7BC, 0x7156, 0xD1EE, 0x7159, 0xE6D5, 0x715C, 0xE9F2, 0x715E, 0xDFB0, 0x7164, 0xD8E0, 0x7165, 0xFCBA, 0x7166, 0xFDAF, 0x7167, 0xF0CE, 0x7169, 0xDBE1, 0x716C, 0xE5C9, 0x716E, 0xEDB4, 0x717D, 0xE0C3, 0x7184, 0xE3D8, 0x7189, 0xE9FB, 0x718A, 0xEAA8, 0x718F, 0xFDB7, 0x7192, 0xFBA7, 0x7194, 0xE9C2, 0x7199, 0xFDF7, 0x719F, 0xE2D9, 0x71A2, 0xDCEC, 0x71AC, 0xE8A2, 0x71B1, 0xE6F0, 0x71B9, 0xFDF8, 0x71BA, 0xFDF9, 0x71BE, 0xF6BF, 0x71C1, 0xE7A7, 0x71C3, 0xE6D7, 0x71C8, 0xD4F3, 0x71C9, 0xD4C9, 0x71CE, 0xD6FA, 0x71D0, 0xD7F2, 0x71D2, 0xE1C0, 0x71D4, 0xDBE2, 0x71D5, 0xE6D8, 0x71DF, 0xE7BD, 0x71E5, 0xF0CF, 0x71E6, 0xF3BE, 0x71E7, 0xE2AC, 0x71ED, 0xF5B7, 0x71EE, 0xE0F0, 0x71FB, 0xFDB8, 0x71FC, 0xE3E8, 0x71FE, 0xD4A7, 0x71FF, 0xE8FC, 0x7200, 0xFAD2, 0x7206, 0xF8EF, 0x7210, 0xD6D3, 0x721B, 0xD5B4, 0x722A, 0xF0D0, 0x722C, 0xF7F0, 0x722D, 0xEEB3, 0x7230, 0xEABA, 0x7232, 0xEAD3, 0x7235, 0xEDC9, 0x7236, 0xDDAB, 0x723A, 0xE5AC, 0x723B, 0xFDA1, 0x723D, 0xDFD0, 0x723E, 0xECB3, 0x7240, 0xDFD1, 0x7246, 0xEDED, 0x7247, 0xF8B8, 0x7248, 0xF7FA, 0x724C, 0xF8AB, 0x7252, 0xF4E0, 0x7258, 0xD4BA, 0x7259, 0xE4B3, 0x725B, 0xE9DA, 0x725D, 0xDEB6, 0x725F, 0xD9BF, 0x7261, 0xD9C0, 0x7262, 0xD6EF, 0x7267, 0xD9CC, 0x7269, 0xDAAA, 0x7272, 0xDFE5, 0x7279, 0xF7E5, 0x727D, 0xCCB2, 0x7280, 0xDFF9, 0x7281, 0xD7E0, 0x72A2, 0xD4BB, 0x72A7, 0xFDFA, 0x72AC, 0xCCB3, 0x72AF, 0xDBF3, 0x72C0, 0xDFD2, 0x72C2, 0xCECA, 0x72C4, 0xEEDA, 0x72CE, 0xE4E4, 0x72D0, 0xFBCF, 0x72D7, 0xCFB7, 0x72D9, 0xEEC3, 0x72E1, 0xCEEA, 0x72E9, 0xE2AD, 0x72F8, 0xD7E1, 0x72F9, 0xFAF5, 0x72FC, 0xD5C9, 0x72FD, 0xF8AC, 0x730A, 0xE7D9, 0x7316, 0xF3E9, 0x731B, 0xD8ED, 0x731C, 0xE3C4, 0x731D, 0xF0F1, 0x7325, 0xE8E5, 0x7329, 0xE0FA, 0x732A, 0xEEC4, 0x732B, 0xD9DE, 0x7336, 0xEBA2, 0x7337, 0xEBA3, 0x733E, 0xFCC2, 0x733F, 0xEABB, 0x7344, 0xE8AB, 0x7345, 0xDEE2, 0x7350, 0xEDEF, 0x7352, 0xE8A3, 0x7357, 0xCFF1, 0x7368, 0xD4BC, 0x736A, 0xFCEA, 0x7370, 0xE7BE, 0x7372, 0xFCF2, 0x7375, 0xD6B4, 0x7378, 0xE2AE, 0x737A, 0xD3B7, 0x737B, 0xFACC, 0x7384, 0xFADC, 0x7386, 0xEDB5, 0x7387, 0xE1E3, 0x7389, 0xE8AC, 0x738B, 0xE8DD, 0x738E, 0xEFE9, 0x7394, 0xF4BD, 0x7396, 0xCFB8, 0x7397, 0xE9DB, 0x7398, 0xD1AC, 0x739F, 0xDAC7, 0x73A7, 0xEBC9, 0x73A9, 0xE8CC, 0x73AD, 0xDEB7, 0x73B2, 0xD6BC, 0x73B3, 0xD3E5, 0x73B9, 0xFADD, 0x73C0, 0xDAD6, 0x73C2, 0xCAB1, 0x73C9, 0xDAC8, 0x73CA, 0xDFA6, 0x73CC, 0xF9B3, 0x73CD, 0xF2D2, 0x73CF, 0xCAC4, 0x73D6, 0xCECB, 0x73D9, 0xCDF5, 0x73DD, 0xFDB0, 0x73DE, 0xD5A8, 0x73E0, 0xF1C1, 0x73E3, 0xE2E9, 0x73E4, 0xDCCA, 0x73E5, 0xECB4, 0x73E6, 0xFAC0, 0x73E9, 0xFBA8, 0x73EA, 0xD0A8, 0x73ED, 0xDAEC, 0x73F7, 0xD9EE, 0x73F9, 0xE0FB, 0x73FD, 0xEFEA, 0x73FE, 0xFADE, 0x7401, 0xE0C4, 0x7403, 0xCFB9, 0x7405, 0xD5CA, 0x7406, 0xD7E2, 0x7407, 0xE2AF, 0x7409, 0xD7B8, 0x7413, 0xE8CD, 0x741B, 0xF6DA, 0x7420, 0xEFA2, 0x7421, 0xE2DA, 0x7422, 0xF6FC, 0x7425, 0xFBD0, 0x7426, 0xD1AD, 0x7428, 0xCDE4, 0x742A, 0xD1AE, 0x742B, 0xDCED, 0x742C, 0xE8CE, 0x742E, 0xF0F9, 0x742F, 0xCEB5, 0x7430, 0xE6FC, 0x7433, 0xD7FB, 0x7434, 0xD0D6, 0x7435, 0xDDF5, 0x7436, 0xF7F1, 0x7438, 0xF6FD, 0x743A, 0xDBF7, 0x743F, 0xFBEA, 0x7440, 0xE9DC, 0x7441, 0xD9C1, 0x7443, 0xF5F2, 0x7444, 0xE0C5, 0x744B, 0xEAD4, 0x7455, 0xF9C2, 0x7457, 0xEABC, 0x7459, 0xD2C5, 0x745A, 0xFBD1, 0x745B, 0xE7C0, 0x745C, 0xEBA5, 0x745E, 0xDFFA, 0x745F, 0xE3A2, 0x7460, 0xD7B9, 0x7462, 0xE9C3, 0x7464, 0xE8FD, 0x7465, 0xE8AF, 0x7468, 0xF2D3, 0x7469, 0xFBA9, 0x746A, 0xD8A5, 0x746F, 0xD5CB, 0x747E, 0xD0C8, 0x7482, 0xD1AF, 0x7483, 0xD7E3, 0x7487, 0xE0C6, 0x7489, 0xD6A2, 0x748B, 0xEDF0, 0x7498, 0xD7F3, 0x749C, 0xFCD4, 0x749E, 0xDAD7, 0x749F, 0xCCDF, 0x74A1, 0xF2D4, 0x74A3, 0xD1B0, 0x74A5, 0xCCE0, 0x74A7, 0xDBFD, 0x74A8, 0xF3BF, 0x74AA, 0xF0D1, 0x74B0, 0xFCBB, 0x74B2, 0xE2B0, 0x74B5, 0xE6A5, 0x74B9, 0xE2DB, 0x74BD, 0xDFDE, 0x74BF, 0xE0C7, 0x74C6, 0xF2EF, 0x74CA, 0xCCE1, 0x74CF, 0xD6EA, 0x74D4, 0xE7C2, 0x74D8, 0xCEB6, 0x74DA, 0xF3C0, 0x74DC, 0xCDFE, 0x74E0, 0xFBD2, 0x74E2, 0xF8F8, 0x74E3, 0xF7FB, 0x74E6, 0xE8BF, 0x74EE, 0xE8B7, 0x74F7, 0xEDB6, 0x7501, 0xDCBA, 0x7504, 0xCCB4, 0x7511, 0xF1F7, 0x7515, 0xE8B8, 0x7518, 0xCAF6, 0x751A, 0xE4A4, 0x751B, 0xF4D6, 0x751F, 0xDFE6, 0x7523, 0xDFA7, 0x7525, 0xDFE7, 0x7526, 0xE1C1, 0x7528, 0xE9C4, 0x752B, 0xDCCB, 0x752C, 0xE9C5, 0x7530, 0xEFA3, 0x7531, 0xEBA6, 0x7532, 0xCBA3, 0x7533, 0xE3E9, 0x7537, 0xD1FB, 0x7538, 0xEFA4, 0x753A, 0xEFEB, 0x7547, 0xD0B4, 0x754C, 0xCDA3, 0x754F, 0xE8E6, 0x7551, 0xEFA5, 0x7553, 0xD3CC, 0x7554, 0xDAED, 0x7559, 0xD7BA, 0x755B, 0xF2D5, 0x755C, 0xF5E5, 0x755D, 0xD9EF, 0x7562, 0xF9B4, 0x7565, 0xD5D4, 0x7566, 0xFDCF, 0x756A, 0xDBE3, 0x756F, 0xF1E1, 0x7570, 0xECB6, 0x7575, 0xFBFE, 0x7576, 0xD3D7, 0x7578, 0xD1B1, 0x757A, 0xCBB1, 0x757F, 0xD1B2, 0x7586, 0xCBB2, 0x7587, 0xF1C2, 0x758A, 0xF4E1, 0x758B, 0xF9B5, 0x758E, 0xE1C3, 0x758F, 0xE1C2, 0x7591, 0xEBF7, 0x759D, 0xDFA8, 0x75A5, 0xCBCA, 0x75AB, 0xE6B9, 0x75B1, 0xF8DE, 0x75B2, 0xF9AA, 0x75B3, 0xCAF7, 0x75B5, 0xEDB7, 0x75B8, 0xD3B8, 0x75B9, 0xF2D6, 0x75BC, 0xD4D9, 0x75BD, 0xEEC5, 0x75BE, 0xF2F0, 0x75C2, 0xCAB2, 0x75C5, 0xDCBB, 0x75C7, 0xF1F8, 0x75CD, 0xECB7, 0x75D2, 0xE5CA, 0x75D4, 0xF6C0, 0x75D5, 0xFDDD, 0x75D8, 0xD4E3, 0x75D9, 0xCCE2, 0x75DB, 0xF7D4, 0x75E2, 0xD7E5, 0x75F0, 0xD3C3, 0x75F2, 0xD8A6, 0x75F4, 0xF6C1, 0x75FA, 0xDDF6, 0x75FC, 0xCDC0, 0x7600, 0xE5DC, 0x760D, 0xE5CB, 0x7619, 0xE1C4, 0x761F, 0xE8B0, 0x7620, 0xF4B0, 0x7621, 0xF3EA, 0x7622, 0xDAEE, 0x7624, 0xD7BB, 0x7626, 0xE2B1, 0x763B, 0xD7AA, 0x7642, 0xD6FB, 0x764C, 0xE4DF, 0x764E, 0xCAD6, 0x7652, 0xEBA8, 0x7656, 0xDBFE, 0x7661, 0xF6C2, 0x7664, 0xEFBB, 0x7669, 0xD4FD, 0x766C, 0xE0C8, 0x7670, 0xE8B9, 0x7672, 0xEFA6, 0x7678, 0xCDA4, 0x767B, 0xD4F4, 0x767C, 0xDBA1, 0x767D, 0xDBDC, 0x767E, 0xDBDD, 0x7684, 0xEEDC, 0x7686, 0xCBCB, 0x7687, 0xFCD5, 0x768E, 0xCEEB, 0x7690, 0xCDC1, 0x7693, 0xFBD3, 0x76AE, 0xF9AB, 0x76BA, 0xF5D4, 0x76BF, 0xD9A9, 0x76C2, 0xE9DD, 0x76C3, 0xDBCD, 0x76C6, 0xDDCE, 0x76C8, 0xE7C3, 0x76CA, 0xECCC, 0x76D2, 0xF9EC, 0x76D6, 0xCBCC, 0x76DB, 0xE0FC, 0x76DC, 0xD4A8, 0x76DE, 0xEDD3, 0x76DF, 0xD8EF, 0x76E1, 0xF2D7, 0x76E3, 0xCAF8, 0x76E4, 0xDAEF, 0x76E7, 0xD6D4, 0x76EE, 0xD9CD, 0x76F2, 0xD8EE, 0x76F4, 0xF2C1, 0x76F8, 0xDFD3, 0x76FC, 0xDAF0, 0x76FE, 0xE2EA, 0x7701, 0xE0FD, 0x7704, 0xD8F8, 0x7708, 0xF7AF, 0x7709, 0xDAB6, 0x770B, 0xCAD7, 0x771E, 0xF2D8, 0x7720, 0xD8F9, 0x7729, 0xFADF, 0x7737, 0xCFEF, 0x7738, 0xD9C2, 0x773A, 0xF0D2, 0x773C, 0xE4D1, 0x7740, 0xF3B7, 0x774D, 0xFAE0, 0x775B, 0xEFEC, 0x7761, 0xE2B2, 0x7763, 0xD4BD, 0x7766, 0xD9CE, 0x776B, 0xF4E2, 0x7779, 0xD4A9, 0x777E, 0xCDC2, 0x777F, 0xE7DA, 0x778B, 0xF2D9, 0x7791, 0xD9AA, 0x779E, 0xD8BE, 0x77A5, 0xDCAD, 0x77AC, 0xE2EB, 0x77AD, 0xD6FC, 0x77B0, 0xCAF9, 0x77B3, 0xD4DA, 0x77BB, 0xF4D7, 0x77BC, 0xCCA1, 0x77BF, 0xCFBA, 0x77D7, 0xF5B8, 0x77DB, 0xD9C3, 0x77DC, 0xD0E8, 0x77E2, 0xE3C5, 0x77E3, 0xEBF8, 0x77E5, 0xF2B1, 0x77E9, 0xCFBB, 0x77ED, 0xD3AD, 0x77EE, 0xE8E1, 0x77EF, 0xCEEC, 0x77F3, 0xE0B4, 0x7802, 0xDEE3, 0x7812, 0xDDF7, 0x7825, 0xF2B2, 0x7826, 0xF3F6, 0x7827, 0xF6DB, 0x782C, 0xD7FE, 0x7832, 0xF8DF, 0x7834, 0xF7F2, 0x7845, 0xD0A9, 0x784F, 0xE6DA, 0x785D, 0xF5A6, 0x786B, 0xD7BC, 0x786C, 0xCCE3, 0x786F, 0xE6DB, 0x787C, 0xDDDD, 0x7881, 0xD1B3, 0x7887, 0xEFED, 0x788C, 0xD6DE, 0x788D, 0xE4F4, 0x788E, 0xE1EF, 0x7891, 0xDDF8, 0x7897, 0xE8CF, 0x78A3, 0xCAE5, 0x78A7, 0xDCA1, 0x78A9, 0xE0B5, 0x78BA, 0xFCAC, 0x78BB, 0xFCAD, 0x78BC, 0xD8A7, 0x78C1, 0xEDB8, 0x78C5, 0xDBB6, 0x78CA, 0xD6F0, 0x78CB, 0xF3AF, 0x78CE, 0xCDA5, 0x78D0, 0xDAF1, 0x78E8, 0xD8A8, 0x78EC, 0xCCE4, 0x78EF, 0xD1B4, 0x78F5, 0xCAD8, 0x78FB, 0xDAF2, 0x7901, 0xF5A7, 0x790E, 0xF5A8, 0x7916, 0xE6A6, 0x792A, 0xD5EC, 0x792B, 0xD5F8, 0x792C, 0xDAF3, 0x793A, 0xE3C6, 0x793E, 0xDEE4, 0x7940, 0xDEE5, 0x7941, 0xD1B5, 0x7947, 0xD1B6, 0x7948, 0xD1B7, 0x7949, 0xF2B3, 0x7950, 0xE9DE, 0x7956, 0xF0D3, 0x7957, 0xF2B4, 0x795A, 0xF0D4, 0x795B, 0xCBE4, 0x795C, 0xFBD4, 0x795D, 0xF5E6, 0x795E, 0xE3EA, 0x7960, 0xDEE6, 0x7965, 0xDFD4, 0x7968, 0xF8F9, 0x796D, 0xF0AE, 0x797A, 0xD1B8, 0x797F, 0xD6DF, 0x7981, 0xD0D7, 0x798D, 0xFCA1, 0x798E, 0xEFEE, 0x798F, 0xDCD8, 0x7991, 0xE9DF, 0x79A6, 0xE5DD, 0x79A7, 0xFDFB, 0x79AA, 0xE0C9, 0x79AE, 0xD6C9, 0x79B1, 0xD4AA, 0x79B3, 0xE5CC, 0x79B9, 0xE9E0, 0x79BD, 0xD0D8, 0x79BE, 0xFCA2, 0x79BF, 0xD4BE, 0x79C0, 0xE2B3, 0x79C1, 0xDEE7, 0x79C9, 0xDCBC, 0x79CA, 0xD2B6, 0x79CB, 0xF5D5, 0x79D1, 0xCEA1, 0x79D2, 0xF5A9, 0x79D5, 0xDDF9, 0x79D8, 0xDDFA, 0x79DF, 0xF0D5, 0x79E4, 0xF6DF, 0x79E6, 0xF2DA, 0x79E7, 0xE4EB, 0x79E9, 0xF2F1, 0x79FB, 0xECB9, 0x7A00, 0xFDFC, 0x7A05, 0xE1AA, 0x7A08, 0xCAD9, 0x7A0B, 0xEFEF, 0x7A0D, 0xF5AA, 0x7A14, 0xECF9, 0x7A17, 0xF8AD, 0x7A19, 0xF2C2, 0x7A1A, 0xF6C3, 0x7A1C, 0xD7D2, 0x7A1F, 0xF9A2, 0x7A20, 0xF0D6, 0x7A2E, 0xF0FA, 0x7A31, 0xF6E0, 0x7A36, 0xE9F3, 0x7A37, 0xF2C3, 0x7A3B, 0xD4AB, 0x7A3C, 0xCAB3, 0x7A3D, 0xCDA6, 0x7A3F, 0xCDC3, 0x7A40, 0xCDDA, 0x7A46, 0xD9CF, 0x7A49, 0xF6C4, 0x7A4D, 0xEEDD, 0x7A4E, 0xE7C4, 0x7A57, 0xE2B4, 0x7A61, 0xDFE2, 0x7A62, 0xE7DB, 0x7A69, 0xE8B1, 0x7A6B, 0xFCAE, 0x7A70, 0xE5CD, 0x7A74, 0xFAEB, 0x7A76, 0xCFBC, 0x7A79, 0xCFE2, 0x7A7A, 0xCDF6, 0x7A7D, 0xEFF0, 0x7A7F, 0xF4BE, 0x7A81, 0xD4CD, 0x7A84, 0xF3B8, 0x7A88, 0xE9A1, 0x7A92, 0xF2F2, 0x7A93, 0xF3EB, 0x7A95, 0xF0D7, 0x7A98, 0xCFD7, 0x7A9F, 0xCFDF, 0x7AA9, 0xE8C0, 0x7AAA, 0xE8C1, 0x7AAE, 0xCFE3, 0x7AAF, 0xE9A2, 0x7ABA, 0xD0AA, 0x7AC4, 0xF3C1, 0x7AC5, 0xD0AB, 0x7AC7, 0xD4E4, 0x7ACA, 0xEFBC, 0x7ACB, 0xD8A1, 0x7AD7, 0xD9DF, 0x7AD9, 0xF3D7, 0x7ADD, 0xDCBD, 0x7ADF, 0xCCE5, 0x7AE0, 0xEDF1, 0x7AE3, 0xF1E2, 0x7AE5, 0xD4DB, 0x7AEA, 0xE2B5, 0x7AED, 0xCAE6, 0x7AEF, 0xD3AE, 0x7AF6, 0xCCE6, 0x7AF9, 0xF1D3, 0x7AFA, 0xF5E7, 0x7AFF, 0xCADA, 0x7B0F, 0xFBEE, 0x7B11, 0xE1C5, 0x7B19, 0xDFE9, 0x7B1B, 0xEEDE, 0x7B1E, 0xF7C2, 0x7B20, 0xD8A2, 0x7B26, 0xDDAC, 0x7B2C, 0xF0AF, 0x7B2D, 0xD6BD, 0x7B39, 0xE1AB, 0x7B46, 0xF9B6, 0x7B49, 0xD4F5, 0x7B4B, 0xD0C9, 0x7B4C, 0xEFA7, 0x7B4D, 0xE2EC, 0x7B4F, 0xDBEA, 0x7B50, 0xCECC, 0x7B51, 0xF5E8, 0x7B52, 0xF7D5, 0x7B54, 0xD3CD, 0x7B56, 0xF3FE, 0x7B60, 0xD0B5, 0x7B6C, 0xE0FE, 0x7B6E, 0xDFFB, 0x7B75, 0xE6DD, 0x7B7D, 0xE8A4, 0x7B87, 0xCBCD, 0x7B8B, 0xEFA8, 0x7B8F, 0xEEB4, 0x7B94, 0xDAD8, 0x7B95, 0xD1B9, 0x7B97, 0xDFA9, 0x7B9A, 0xF3B0, 0x7B9D, 0xCCC4, 0x7BA1, 0xCEB7, 0x7BAD, 0xEFA9, 0x7BB1, 0xDFD5, 0x7BB4, 0xEDD7, 0x7BB8, 0xEEC6, 0x7BC0, 0xEFBD, 0x7BC1, 0xFCD6, 0x7BC4, 0xDBF4, 0x7BC6, 0xEFAA, 0x7BC7, 0xF8B9, 0x7BC9, 0xF5E9, 0x7BD2, 0xE3D9, 0x7BE0, 0xE1C6, 0x7BE4, 0xD4BF, 0x7BE9, 0xDEE8, 0x7C07, 0xF0EA, 0x7C12, 0xF3C2, 0x7C1E, 0xD3AF, 0x7C21, 0xCADB, 0x7C27, 0xFCD7, 0x7C2A, 0xEDD8, 0x7C2B, 0xE1C7, 0x7C3D, 0xF4D8, 0x7C3E, 0xD6B3, 0x7C3F, 0xDDAD, 0x7C43, 0xD5BE, 0x7C4C, 0xF1C3, 0x7C4D, 0xEEDF, 0x7C60, 0xD6EB, 0x7C64, 0xF4D9, 0x7C6C, 0xD7E6, 0x7C73, 0xDAB7, 0x7C83, 0xDDFB, 0x7C89, 0xDDCF, 0x7C92, 0xD8A3, 0x7C95, 0xDAD9, 0x7C97, 0xF0D8, 0x7C98, 0xEFC4, 0x7C9F, 0xE1D8, 0x7CA5, 0xF1D4, 0x7CA7, 0xEDF2, 0x7CAE, 0xD5DB, 0x7CB1, 0xD5DC, 0x7CB2, 0xF3C4, 0x7CB3, 0xCBD7, 0x7CB9, 0xE2B6, 0x7CBE, 0xEFF1, 0x7CCA, 0xFBD5, 0x7CD6, 0xD3D8, 0x7CDE, 0xDDD0, 0x7CDF, 0xF0D9, 0x7CE0, 0xCBB3, 0x7CE7, 0xD5DD, 0x7CFB, 0xCDA7, 0x7CFE, 0xD0AC, 0x7D00, 0xD1BA, 0x7D02, 0xF1C4, 0x7D04, 0xE5B3, 0x7D05, 0xFBF5, 0x7D06, 0xE9E1, 0x7D07, 0xFDE0, 0x7D08, 0xFCBC, 0x7D0A, 0xDAA2, 0x7D0B, 0xDAA3, 0x7D0D, 0xD2A1, 0x7D10, 0xD2EF, 0x7D14, 0xE2ED, 0x7D17, 0xDEE9, 0x7D18, 0xCEDC, 0x7D19, 0xF2B5, 0x7D1A, 0xD0E4, 0x7D1B, 0xDDD1, 0x7D20, 0xE1C8, 0x7D21, 0xDBB7, 0x7D22, 0xDFE3, 0x7D2B, 0xEDB9, 0x7D2C, 0xF1C5, 0x7D2E, 0xF3CF, 0x7D2F, 0xD7AB, 0x7D30, 0xE1AC, 0x7D33, 0xE3EB, 0x7D35, 0xEEC7, 0x7D39, 0xE1C9, 0x7D3A, 0xCAFA, 0x7D42, 0xF0FB, 0x7D43, 0xFAE1, 0x7D44, 0xF0DA, 0x7D45, 0xCCE7, 0x7D46, 0xDAF4, 0x7D50, 0xCCBF, 0x7D5E, 0xCEED, 0x7D61, 0xD5A9, 0x7D62, 0xFAE2, 0x7D66, 0xD0E5, 0x7D68, 0xEBD6, 0x7D6A, 0xECDF, 0x7D6E, 0xDFFC, 0x7D71, 0xF7D6, 0x7D72, 0xDEEA, 0x7D73, 0xCBB4, 0x7D76, 0xEFBE, 0x7D79, 0xCCB5, 0x7D7F, 0xCFBD, 0x7D8E, 0xEFF2, 0x7D8F, 0xE2B7, 0x7D93, 0xCCE8, 0x7D9C, 0xF0FC, 0x7DA0, 0xD6E0, 0x7DA2, 0xF1C6, 0x7DAC, 0xE2B8, 0x7DAD, 0xEBAB, 0x7DB1, 0xCBB5, 0x7DB2, 0xD8D1, 0x7DB4, 0xF4CE, 0x7DB5, 0xF3F7, 0x7DB8, 0xD7C6, 0x7DBA, 0xD1BB, 0x7DBB, 0xF7AA, 0x7DBD, 0xEDCA, 0x7DBE, 0xD7D3, 0x7DBF, 0xD8FA, 0x7DC7, 0xF6C5, 0x7DCA, 0xD1CC, 0x7DCB, 0xDDFC, 0x7DD6, 0xDFFD, 0x7DD8, 0xF9E5, 0x7DDA, 0xE0CA, 0x7DDD, 0xF2FD, 0x7DDE, 0xD3B0, 0x7DE0, 0xF4F3, 0x7DE1, 0xDAC9, 0x7DE3, 0xE6DE, 0x7DE8, 0xF8BA, 0x7DE9, 0xE8D0, 0x7DEC, 0xD8FB, 0x7DEF, 0xEAD5, 0x7DF4, 0xD6A3, 0x7DFB, 0xF6C6, 0x7E09, 0xF2DB, 0x7E0A, 0xE4FC, 0x7E15, 0xE8B2, 0x7E1B, 0xDADA, 0x7E1D, 0xF2DC, 0x7E1E, 0xFBD6, 0x7E1F, 0xE9B2, 0x7E21, 0xEEAD, 0x7E23, 0xFAE3, 0x7E2B, 0xDCEE, 0x7E2E, 0xF5EA, 0x7E2F, 0xE6E0, 0x7E31, 0xF0FD, 0x7E37, 0xD7AC, 0x7E3D, 0xF5C5, 0x7E3E, 0xEEE0, 0x7E41, 0xDBE5, 0x7E43, 0xDDDE, 0x7E46, 0xD9F0, 0x7E47, 0xE9A3, 0x7E52, 0xF1F9, 0x7E54, 0xF2C4, 0x7E55, 0xE0CB, 0x7E5E, 0xE9A4, 0x7E61, 0xE2B9, 0x7E69, 0xE3B1, 0x7E6A, 0xFCEB, 0x7E6B, 0xCDA8, 0x7E6D, 0xCCB6, 0x7E70, 0xF0DB, 0x7E79, 0xE6BA, 0x7E7C, 0xCDA9, 0x7E82, 0xF3C3, 0x7E8C, 0xE1D9, 0x7E8F, 0xEFAB, 0x7E93, 0xE7C5, 0x7E96, 0xE0E9, 0x7E98, 0xF3C5, 0x7E9B, 0xD4C0, 0x7E9C, 0xD5BF, 0x7F36, 0xDDAE, 0x7F38, 0xF9FC, 0x7F3A, 0xCCC0, 0x7F4C, 0xE5A2, 0x7F50, 0xCEB8, 0x7F54, 0xD8D2, 0x7F55, 0xF9D6, 0x7F6A, 0xF1AA, 0x7F6B, 0xCED1, 0x7F6E, 0xF6C7, 0x7F70, 0xDBEB, 0x7F72, 0xDFFE, 0x7F75, 0xD8E1, 0x7F77, 0xF7F3, 0x7F79, 0xD7E7, 0x7F85, 0xD4FE, 0x7F88, 0xD1BC, 0x7F8A, 0xE5CF, 0x7F8C, 0xCBB6, 0x7F8E, 0xDAB8, 0x7F94, 0xCDC4, 0x7F9A, 0xD6BE, 0x7F9E, 0xE2BA, 0x7FA4, 0xCFD8, 0x7FA8, 0xE0CC, 0x7FA9, 0xEBF9, 0x7FB2, 0xFDFD, 0x7FB8, 0xD7E8, 0x7FB9, 0xCBD8, 0x7FBD, 0xE9E2, 0x7FC1, 0xE8BA, 0x7FC5, 0xE3C7, 0x7FCA, 0xECCD, 0x7FCC, 0xECCE, 0x7FCE, 0xD6BF, 0x7FD2, 0xE3A7, 0x7FD4, 0xDFD6, 0x7FD5, 0xFDE8, 0x7FDF, 0xEEE1, 0x7FE0, 0xF6A8, 0x7FE1, 0xDDFD, 0x7FE9, 0xF8BB, 0x7FEB, 0xE8D1, 0x7FF0, 0xF9D7, 0x7FF9, 0xCEEE, 0x7FFC, 0xECCF, 0x8000, 0xE9A5, 0x8001, 0xD6D5, 0x8003, 0xCDC5, 0x8005, 0xEDBA, 0x8006, 0xD1BD, 0x8009, 0xCFBE, 0x800C, 0xECBB, 0x8010, 0xD2B1, 0x8015, 0xCCE9, 0x8017, 0xD9C4, 0x8018, 0xE9FC, 0x802D, 0xD1BE, 0x8033, 0xECBC, 0x8036, 0xE5AD, 0x803D, 0xF7B0, 0x803F, 0xCCEA, 0x8043, 0xD3C4, 0x8046, 0xD6C0, 0x804A, 0xD6FD, 0x8056, 0xE1A1, 0x8058, 0xDEBD, 0x805A, 0xF6A9, 0x805E, 0xDAA4, 0x806F, 0xD6A4, 0x8070, 0xF5C6, 0x8072, 0xE1A2, 0x8073, 0xE9C6, 0x8077, 0xF2C5, 0x807D, 0xF4E9, 0x807E, 0xD6EC, 0x807F, 0xEBD3, 0x8084, 0xECBD, 0x8085, 0xE2DC, 0x8086, 0xDEEB, 0x8087, 0xF0DC, 0x8089, 0xEBBF, 0x808B, 0xD7CE, 0x808C, 0xD1BF, 0x8096, 0xF5AB, 0x809B, 0xF9FD, 0x809D, 0xCADC, 0x80A1, 0xCDC6, 0x80A2, 0xF2B6, 0x80A5, 0xDDFE, 0x80A9, 0xCCB7, 0x80AA, 0xDBB8, 0x80AF, 0xD0E9, 0x80B1, 0xCEDD, 0x80B2, 0xEBC0, 0x80B4, 0xFDA2, 0x80BA, 0xF8CB, 0x80C3, 0xEAD6, 0x80C4, 0xF1B0, 0x80CC, 0xDBCE, 0x80CE, 0xF7C3, 0x80DA, 0xDBCF, 0x80DB, 0xCBA4, 0x80DE, 0xF8E0, 0x80E1, 0xFBD7, 0x80E4, 0xEBCA, 0x80E5, 0xE0A1, 0x80F1, 0xCECD, 0x80F4, 0xD4DC, 0x80F8, 0xFDD8, 0x80FD, 0xD2F6, 0x8102, 0xF2B7, 0x8105, 0xFAF6, 0x8106, 0xF6AA, 0x8107, 0xFAF7, 0x8108, 0xD8E6, 0x810A, 0xF4B1, 0x8118, 0xE8D2, 0x811A, 0xCAC5, 0x811B, 0xCCEB, 0x8123, 0xE2EE, 0x8129, 0xE2BB, 0x812B, 0xF7AD, 0x812F, 0xF8E1, 0x8139, 0xF3EC, 0x813E, 0xDEA1, 0x814B, 0xE4FD, 0x814E, 0xE3EC, 0x8150, 0xDDAF, 0x8151, 0xDDB0, 0x8154, 0xCBB7, 0x8155, 0xE8D3, 0x8165, 0xE1A3, 0x8166, 0xD2E0, 0x816B, 0xF0FE, 0x8170, 0xE9A6, 0x8171, 0xCBF2, 0x8178, 0xEDF3, 0x8179, 0xDCD9, 0x817A, 0xE0CD, 0x817F, 0xF7DA, 0x8180, 0xDBB9, 0x8188, 0xCCAE, 0x818A, 0xDADB, 0x818F, 0xCDC7, 0x819A, 0xDDB1, 0x819C, 0xD8AF, 0x819D, 0xE3A3, 0x81A0, 0xCEEF, 0x81A3, 0xF2F3, 0x81A8, 0xF8B3, 0x81B3, 0xE0CE, 0x81B5, 0xF5FD, 0x81BA, 0xEBEC, 0x81BD, 0xD3C5, 0x81BE, 0xFCEC, 0x81BF, 0xD2DB, 0x81C0, 0xD4EB, 0x81C2, 0xDEA2, 0x81C6, 0xE5E6, 0x81CD, 0xF0B0, 0x81D8, 0xD5C4, 0x81DF, 0xEDF4, 0x81E3, 0xE3ED, 0x81E5, 0xE8C2, 0x81E7, 0xEDF5, 0x81E8, 0xD7FC, 0x81EA, 0xEDBB, 0x81ED, 0xF6AB, 0x81F3, 0xF2B8, 0x81F4, 0xF6C8, 0x81FA, 0xD3E6, 0x81FB, 0xF2DD, 0x81FC, 0xCFBF, 0x81FE, 0xEBAC, 0x8205, 0xCFC0, 0x8207, 0xE6A8, 0x8208, 0xFDE9, 0x820A, 0xCFC1, 0x820C, 0xE0DF, 0x820D, 0xDEEC, 0x8212, 0xE0A2, 0x821B, 0xF4BF, 0x821C, 0xE2EF, 0x821E, 0xD9F1, 0x821F, 0xF1C7, 0x8221, 0xCBB8, 0x822A, 0xF9FE, 0x822B, 0xDBBA, 0x822C, 0xDAF5, 0x8235, 0xF6EC, 0x8236, 0xDADC, 0x8237, 0xFAE4, 0x8239, 0xE0CF, 0x8240, 0xDDB2, 0x8245, 0xE6A9, 0x8247, 0xEFF3, 0x8259, 0xF3ED, 0x8264, 0xEBFA, 0x8266, 0xF9E6, 0x826E, 0xCADD, 0x826F, 0xD5DE, 0x8271, 0xCADE, 0x8272, 0xDFE4, 0x8276, 0xE6FD, 0x8278, 0xF5AC, 0x827E, 0xE4F5, 0x828B, 0xE9E3, 0x828D, 0xEDCB, 0x828E, 0xCFE4, 0x8292, 0xD8D3, 0x8299, 0xDDB3, 0x829A, 0xD4EC, 0x829D, 0xF2B9, 0x829F, 0xDFB7, 0x82A5, 0xCBCE, 0x82A6, 0xFBD8, 0x82A9, 0xD0D9, 0x82AC, 0xDDD2, 0x82AD, 0xF7F4, 0x82AE, 0xE7DC, 0x82AF, 0xE4A5, 0x82B1, 0xFCA3, 0x82B3, 0xDBBB, 0x82B7, 0xF2BA, 0x82B8, 0xE9FD, 0x82B9, 0xD0CA, 0x82BB, 0xF5D6, 0x82BC, 0xD9C5, 0x82BD, 0xE4B4, 0x82BF, 0xEDA7, 0x82D1, 0xEABD, 0x82D2, 0xE6FE, 0x82D4, 0xF7C4, 0x82D5, 0xF5AD, 0x82D7, 0xD9E0, 0x82DB, 0xCAB4, 0x82DE, 0xF8E2, 0x82DF, 0xCFC2, 0x82E1, 0xECBE, 0x82E5, 0xE5B4, 0x82E6, 0xCDC8, 0x82E7, 0xEEC8, 0x82F1, 0xE7C8, 0x82FD, 0xCDC9, 0x82FE, 0xF9B7, 0x8301, 0xF1E8, 0x8302, 0xD9F2, 0x8303, 0xDBF5, 0x8304, 0xCAB5, 0x8305, 0xD9C6, 0x8309, 0xD8C9, 0x8317, 0xD9AB, 0x8328, 0xEDBC, 0x832B, 0xD8D4, 0x832F, 0xDCDA, 0x8331, 0xE2BC, 0x8334, 0xFCED, 0x8335, 0xECE0, 0x8336, 0xD2FE, 0x8338, 0xE9C7, 0x8339, 0xE6AA, 0x8340, 0xE2F0, 0x8347, 0xFABB, 0x8349, 0xF5AE, 0x834A, 0xFBAA, 0x834F, 0xECFB, 0x8351, 0xECBF, 0x8352, 0xFCD8, 0x8373, 0xD4E5, 0x8377, 0xF9C3, 0x837B, 0xEEE2, 0x8389, 0xD7E9, 0x838A, 0xEDF6, 0x838E, 0xDEED, 0x8396, 0xCCEC, 0x8398, 0xE3EE, 0x839E, 0xE8D4, 0x83A2, 0xFAF8, 0x83A9, 0xDDB4, 0x83AA, 0xE4B5, 0x83AB, 0xD8B0, 0x83BD, 0xD8D5, 0x83C1, 0xF4EA, 0x83C5, 0xCEB9, 0x83C9, 0xD6E1, 0x83CA, 0xCFD2, 0x83CC, 0xD0B6, 0x83D3, 0xCEA2, 0x83D6, 0xF3EE, 0x83DC, 0xF3F8, 0x83E9, 0xDCCC, 0x83EB, 0xD0CB, 0x83EF, 0xFCA4, 0x83F0, 0xCDCA, 0x83F1, 0xD7D4, 0x83F2, 0xDEA3, 0x83F4, 0xE4E0, 0x83F9, 0xEEC9, 0x83FD, 0xE2DD, 0x8403, 0xF5FE, 0x8404, 0xD4AC, 0x840A, 0xD5D1, 0x840C, 0xD8F0, 0x840D, 0xF8C3, 0x840E, 0xEAD7, 0x8429, 0xF5D7, 0x842C, 0xD8BF, 0x8431, 0xFDC0, 0x8438, 0xEBAD, 0x843D, 0xD5AA, 0x8449, 0xE7A8, 0x8457, 0xEECA, 0x845B, 0xCAE7, 0x8461, 0xF8E3, 0x8463, 0xD4DD, 0x8466, 0xEAD8, 0x846B, 0xFBD9, 0x846C, 0xEDF7, 0x846F, 0xE5B5, 0x8475, 0xD0AD, 0x847A, 0xF1F1, 0x8490, 0xE2BD, 0x8494, 0xE3C8, 0x8499, 0xD9D5, 0x849C, 0xDFAA, 0x84A1, 0xDBBC, 0x84B2, 0xF8E4, 0x84B8, 0xF1FA, 0x84BB, 0xE5B6, 0x84BC, 0xF3EF, 0x84BF, 0xFBDA, 0x84C0, 0xE1E0, 0x84C2, 0xD9AC, 0x84C4, 0xF5EB, 0x84C6, 0xE0B6, 0x84C9, 0xE9C8, 0x84CB, 0xCBCF, 0x84CD, 0xE3C9, 0x84D1, 0xDEEE, 0x84DA, 0xE2BE, 0x84EC, 0xDCEF, 0x84EE, 0xD6A5, 0x84F4, 0xE2F1, 0x84FC, 0xD6FE, 0x8511, 0xD9A1, 0x8513, 0xD8C0, 0x8514, 0xDCDB, 0x8517, 0xEDBD, 0x8518, 0xDFB8, 0x851A, 0xEAA5, 0x851E, 0xD7AD, 0x8521, 0xF3F9, 0x8523, 0xEDF8, 0x8525, 0xF5C7, 0x852C, 0xE1CA, 0x852D, 0xEBE3, 0x852F, 0xF2DE, 0x853D, 0xF8CC, 0x853F, 0xEAD9, 0x8541, 0xD3C6, 0x8543, 0xDBE6, 0x8549, 0xF5AF, 0x854E, 0xCEF0, 0x8553, 0xE9FE, 0x8559, 0xFBB6, 0x8563, 0xE2F2, 0x8568, 0xCFF2, 0x8569, 0xF7B9, 0x856A, 0xD9F3, 0x856D, 0xE1CB, 0x8584, 0xDADD, 0x8587, 0xDAB9, 0x858F, 0xEBFB, 0x8591, 0xCBB9, 0x8594, 0xEDF9, 0x859B, 0xE0E0, 0x85A6, 0xF4C0, 0x85A8, 0xFDBC, 0x85A9, 0xDFB1, 0x85AA, 0xE3EF, 0x85AF, 0xE0A3, 0x85B0, 0xFDB9, 0x85BA, 0xF0B1, 0x85C1, 0xCDCB, 0x85C9, 0xEDBE, 0x85CD, 0xD5C0, 0x85CE, 0xE3F0, 0x85CF, 0xEDFA, 0x85D5, 0xE9E4, 0x85DC, 0xD5ED, 0x85DD, 0xE7DD, 0x85E4, 0xD4F6, 0x85E5, 0xE5B7, 0x85E9, 0xDBE7, 0x85EA, 0xE2BF, 0x85F7, 0xEECB, 0x85FA, 0xD7F4, 0x85FB, 0xF0DD, 0x85FF, 0xCEAB, 0x8602, 0xE7DE, 0x8606, 0xD6D6, 0x8607, 0xE1CC, 0x860A, 0xE8B3, 0x8616, 0xE5EE, 0x8617, 0xDCA2, 0x861A, 0xE0D0, 0x862D, 0xD5B5, 0x863F, 0xD5A1, 0x864E, 0xFBDB, 0x8650, 0xF9CB, 0x8654, 0xCBF3, 0x8655, 0xF4A5, 0x865B, 0xFAC8, 0x865C, 0xD6D7, 0x865E, 0xE9E5, 0x865F, 0xFBDC, 0x8667, 0xFDD0, 0x8679, 0xFBF6, 0x868A, 0xDAA5, 0x868C, 0xDBBD, 0x8693, 0xECE2, 0x86A3, 0xCDF7, 0x86A4, 0xF0DE, 0x86A9, 0xF6C9, 0x86C7, 0xDEEF, 0x86CB, 0xD3B1, 0x86D4, 0xFCEE, 0x86D9, 0xE8C3, 0x86DB, 0xF1C8, 0x86DF, 0xCEF1, 0x86E4, 0xF9ED, 0x86ED, 0xF2F4, 0x86FE, 0xE4B6, 0x8700, 0xF5B9, 0x8702, 0xDCF0, 0x8703, 0xE3F1, 0x8708, 0xE8A5, 0x8718, 0xF2BB, 0x871A, 0xDEA4, 0x871C, 0xDACC, 0x874E, 0xCAE9, 0x8755, 0xE3DA, 0x8757, 0xFCD9, 0x875F, 0xEADA, 0x8766, 0xF9C4, 0x8768, 0xE3A4, 0x8774, 0xFBDD, 0x8776, 0xEFCA, 0x8778, 0xE8C4, 0x8782, 0xD5CC, 0x878D, 0xEBD7, 0x879F, 0xD9AD, 0x87A2, 0xFBAB, 0x87B3, 0xD3D9, 0x87BA, 0xD5A2, 0x87C4, 0xF6DE, 0x87E0, 0xDAF6, 0x87EC, 0xE0D1, 0x87EF, 0xE9A8, 0x87F2, 0xF5F9, 0x87F9, 0xFAAF, 0x87FB, 0xEBFC, 0x87FE, 0xE0EA, 0x8805, 0xE3B2, 0x881F, 0xD5C5, 0x8822, 0xF1E3, 0x8823, 0xD5EE, 0x8831, 0xCDCC, 0x8836, 0xEDD9, 0x883B, 0xD8C1, 0x8840, 0xFAEC, 0x8846, 0xF1EB, 0x884C, 0xFABC, 0x884D, 0xE6E2, 0x8852, 0xFAE5, 0x8853, 0xE2FA, 0x8857, 0xCAB6, 0x8859, 0xE4B7, 0x885B, 0xEADB, 0x885D, 0xF5FA, 0x8861, 0xFBAC, 0x8862, 0xCFC3, 0x8863, 0xEBFD, 0x8868, 0xF8FA, 0x886B, 0xDFB9, 0x8870, 0xE1F1, 0x8872, 0xD2A4, 0x8877, 0xF5FB, 0x887E, 0xD0DA, 0x887F, 0xD0DB, 0x8881, 0xEABE, 0x8882, 0xD9B1, 0x8888, 0xCAB7, 0x888B, 0xD3E7, 0x888D, 0xF8E5, 0x8892, 0xD3B2, 0x8896, 0xE2C0, 0x8897, 0xF2DF, 0x889E, 0xCDE5, 0x88AB, 0xF9AC, 0x88B4, 0xCDCD, 0x88C1, 0xEEAE, 0x88C2, 0xD6AE, 0x88CF, 0xD7EA, 0x88D4, 0xE7E0, 0x88D5, 0xEBAE, 0x88D9, 0xCFD9, 0x88DC, 0xDCCD, 0x88DD, 0xEDFB, 0x88DF, 0xDEF0, 0x88E1, 0xD7EB, 0x88E8, 0xDEA5, 0x88F3, 0xDFD7, 0x88F4, 0xDBD0, 0x88F5, 0xDBD1, 0x88F8, 0xD5A3, 0x88FD, 0xF0B2, 0x8907, 0xDCDC, 0x8910, 0xCAE8, 0x8912, 0xF8E6, 0x8913, 0xDCCE, 0x8918, 0xEADC, 0x8919, 0xDBD2, 0x8925, 0xE9B3, 0x892A, 0xF7DB, 0x8936, 0xE3A8, 0x8938, 0xD7AE, 0x893B, 0xE0E1, 0x8941, 0xCBBA, 0x8944, 0xE5D1, 0x895F, 0xD0DC, 0x8964, 0xD5C1, 0x896A, 0xD8CA, 0x8972, 0xE3A9, 0x897F, 0xE0A4, 0x8981, 0xE9A9, 0x8983, 0xD3C7, 0x8986, 0xDCDD, 0x8987, 0xF8AE, 0x898B, 0xCCB8, 0x898F, 0xD0AE, 0x8993, 0xD8F2, 0x8996, 0xE3CA, 0x89A1, 0xCCAF, 0x89A9, 0xD4AD, 0x89AA, 0xF6D1, 0x89B2, 0xD0CC, 0x89BA, 0xCAC6, 0x89BD, 0xD5C2, 0x89C0, 0xCEBA, 0x89D2, 0xCAC7, 0x89E3, 0xFAB0, 0x89F4, 0xDFD8, 0x89F8, 0xF5BA, 0x8A00, 0xE5EB, 0x8A02, 0xEFF4, 0x8A03, 0xDDB5, 0x8A08, 0xCDAA, 0x8A0A, 0xE3F2, 0x8A0C, 0xFBF7, 0x8A0E, 0xF7D0, 0x8A13, 0xFDBA, 0x8A16, 0xFDE1, 0x8A17, 0xF6FE, 0x8A18, 0xD1C0, 0x8A1B, 0xE8C5, 0x8A1D, 0xE4B8, 0x8A1F, 0xE1E8, 0x8A23, 0xCCC1, 0x8A25, 0xD2ED, 0x8A2A, 0xDBBE, 0x8A2D, 0xE0E2, 0x8A31, 0xFAC9, 0x8A34, 0xE1CD, 0x8A36, 0xCAB8, 0x8A3A, 0xF2E0, 0x8A3B, 0xF1C9, 0x8A50, 0xDEF1, 0x8A54, 0xF0DF, 0x8A55, 0xF8C4, 0x8A5B, 0xEECC, 0x8A5E, 0xDEF2, 0x8A60, 0xE7C9, 0x8A62, 0xE2F3, 0x8A63, 0xE7E1, 0x8A66, 0xE3CB, 0x8A69, 0xE3CC, 0x8A6D, 0xCFF8, 0x8A6E, 0xEFAC, 0x8A70, 0xFDFE, 0x8A71, 0xFCA5, 0x8A72, 0xFAB1, 0x8A73, 0xDFD9, 0x8A75, 0xE0D2, 0x8A79, 0xF4DA, 0x8A85, 0xF1CA, 0x8A87, 0xCEA3, 0x8A8C, 0xF2BC, 0x8A8D, 0xECE3, 0x8A93, 0xE0A5, 0x8A95, 0xF7AB, 0x8A98, 0xEBAF, 0x8A9E, 0xE5DE, 0x8AA0, 0xE1A4, 0x8AA1, 0xCDAB, 0x8AA3, 0xD9F4, 0x8AA4, 0xE8A6, 0x8AA5, 0xCDCE, 0x8AA6, 0xE1E9, 0x8AA8, 0xFCEF, 0x8AAA, 0xE0E3, 0x8AB0, 0xE2C1, 0x8AB2, 0xCEA4, 0x8AB9, 0xDEA6, 0x8ABC, 0xEBFE, 0x8ABE, 0xEBDD, 0x8ABF, 0xF0E0, 0x8AC2, 0xF4DB, 0x8AC4, 0xE2F4, 0x8AC7, 0xD3C8, 0x8ACB, 0xF4EB, 0x8ACD, 0xEEB5, 0x8ACF, 0xF5D8, 0x8AD2, 0xD5DF, 0x8AD6, 0xD6E5, 0x8ADB, 0xEBB0, 0x8ADC, 0xF4E3, 0x8AE1, 0xE3CD, 0x8AE6, 0xF4F4, 0x8AE7, 0xFAB2, 0x8AEA, 0xEFF5, 0x8AEB, 0xCADF, 0x8AED, 0xEBB1, 0x8AEE, 0xEDBF, 0x8AF1, 0xFDC9, 0x8AF6, 0xE4A6, 0x8AF7, 0xF9A4, 0x8AF8, 0xF0B3, 0x8AFA, 0xE5EC, 0x8AFE, 0xD1E7, 0x8B00, 0xD9C7, 0x8B01, 0xE4D7, 0x8B02, 0xEADD, 0x8B04, 0xD4F7, 0x8B0E, 0xDABA, 0x8B10, 0xDACD, 0x8B14, 0xF9CC, 0x8B16, 0xE1DA, 0x8B17, 0xDBBF, 0x8B19, 0xCCC5, 0x8B1A, 0xECD0, 0x8B1B, 0xCBBB, 0x8B1D, 0xDEF3, 0x8B20, 0xE9AA, 0x8B28, 0xD9C8, 0x8B2B, 0xEEE3, 0x8B2C, 0xD7BD, 0x8B33, 0xCFC4, 0x8B39, 0xD0CD, 0x8B41, 0xFCA6, 0x8B49, 0xF1FB, 0x8B4E, 0xFDD2, 0x8B4F, 0xD1C1, 0x8B58, 0xE3DB, 0x8B5A, 0xD3C9, 0x8B5C, 0xDCCF, 0x8B66, 0xCCED, 0x8B6C, 0xDEA7, 0x8B6F, 0xE6BB, 0x8B70, 0xECA1, 0x8B74, 0xCCB9, 0x8B77, 0xFBDE, 0x8B7D, 0xE7E2, 0x8B80, 0xD4C1, 0x8B8A, 0xDCA8, 0x8B90, 0xE2C2, 0x8B92, 0xF3D8, 0x8B93, 0xE5D3, 0x8B96, 0xF3D9, 0x8B9A, 0xF3C6, 0x8C37, 0xCDDB, 0x8C3F, 0xCDAC, 0x8C41, 0xFCC3, 0x8C46, 0xD4E7, 0x8C48, 0xD1C2, 0x8C4A, 0xF9A5, 0x8C4C, 0xE8D5, 0x8C55, 0xE3CE, 0x8C5A, 0xD4CA, 0x8C61, 0xDFDA, 0x8C6A, 0xFBDF, 0x8C6B, 0xE7E3, 0x8C79, 0xF8FB, 0x8C7A, 0xE3CF, 0x8C82, 0xF5B0, 0x8C8A, 0xD8E7, 0x8C8C, 0xD9C9, 0x8C9D, 0xF8AF, 0x8C9E, 0xEFF6, 0x8CA0, 0xDDB6, 0x8CA1, 0xEEAF, 0x8CA2, 0xCDF8, 0x8CA7, 0xDEB8, 0x8CA8, 0xFCA7, 0x8CA9, 0xF7FC, 0x8CAA, 0xF7B1, 0x8CAB, 0xCEBB, 0x8CAC, 0xF4A1, 0x8CAF, 0xEECD, 0x8CB0, 0xE1AE, 0x8CB3, 0xECC3, 0x8CB4, 0xCFFE, 0x8CB6, 0xF8BF, 0x8CB7, 0xD8E2, 0x8CB8, 0xD3E8, 0x8CBB, 0xDEA8, 0x8CBC, 0xF4E4, 0x8CBD, 0xECC2, 0x8CBF, 0xD9F5, 0x8CC0, 0xF9C5, 0x8CC1, 0xDDD3, 0x8CC2, 0xD6F1, 0x8CC3, 0xECFC, 0x8CC4, 0xFCF0, 0x8CC7, 0xEDC0, 0x8CC8, 0xCAB9, 0x8CCA, 0xEEE4, 0x8CD1, 0xF2E1, 0x8CD3, 0xDEB9, 0x8CDA, 0xD6F2, 0x8CDC, 0xDEF4, 0x8CDE, 0xDFDB, 0x8CE0, 0xDBD3, 0x8CE2, 0xFAE7, 0x8CE3, 0xD8E3, 0x8CE4, 0xF4C1, 0x8CE6, 0xDDB7, 0x8CEA, 0xF2F5, 0x8CED, 0xD4AE, 0x8CF4, 0xD6F3, 0x8CFB, 0xDDB8, 0x8CFC, 0xCFC5, 0x8CFD, 0xDFDF, 0x8D04, 0xF2BE, 0x8D05, 0xF6A1, 0x8D07, 0xEBCB, 0x8D08, 0xF1FC, 0x8D0A, 0xF3C7, 0x8D0D, 0xE0EB, 0x8D13, 0xEDFC, 0x8D16, 0xE1DB, 0x8D64, 0xEEE5, 0x8D66, 0xDEF5, 0x8D6B, 0xFAD3, 0x8D70, 0xF1CB, 0x8D73, 0xD0AF, 0x8D74, 0xDDB9, 0x8D77, 0xD1C3, 0x8D85, 0xF5B1, 0x8D8A, 0xEAC6, 0x8D99, 0xF0E1, 0x8DA3, 0xF6AC, 0x8DA8, 0xF5D9, 0x8DB3, 0xF0EB, 0x8DBA, 0xDDBA, 0x8DBE, 0xF2BF, 0x8DC6, 0xF7C5, 0x8DCB, 0xDBA2, 0x8DCC, 0xF2F6, 0x8DCF, 0xCABA, 0x8DDB, 0xF7F5, 0x8DDD, 0xCBE5, 0x8DE1, 0xEEE6, 0x8DE3, 0xE0D3, 0x8DE8, 0xCEA5, 0x8DEF, 0xD6D8, 0x8DF3, 0xD4AF, 0x8E0A, 0xE9C9, 0x8E0F, 0xD3CE, 0x8E10, 0xF4C2, 0x8E1E, 0xCBE6, 0x8E2A, 0xF1A1, 0x8E30, 0xEBB2, 0x8E35, 0xF1A2, 0x8E42, 0xEBB3, 0x8E44, 0xF0B4, 0x8E47, 0xCBF4, 0x8E48, 0xD4B0, 0x8E49, 0xF3B2, 0x8E4A, 0xFBB7, 0x8E59, 0xF5EC, 0x8E5F, 0xEEE7, 0x8E60, 0xF4B2, 0x8E74, 0xF5ED, 0x8E76, 0xCFF3, 0x8E81, 0xF0E2, 0x8E87, 0xEECE, 0x8E8A, 0xF1CC, 0x8E8D, 0xE5B8, 0x8EAA, 0xD7F5, 0x8EAB, 0xE3F3, 0x8EAC, 0xCFE5, 0x8EC0, 0xCFC6, 0x8ECA, 0xF3B3, 0x8ECB, 0xE4D8, 0x8ECC, 0xCFF9, 0x8ECD, 0xCFDA, 0x8ED2, 0xFACD, 0x8EDF, 0xE6E3, 0x8EEB, 0xF2E2, 0x8EF8, 0xF5EE, 0x8EFB, 0xCABB, 0x8EFE, 0xE3DC, 0x8F03, 0xCEF2, 0x8F05, 0xD6D9, 0x8F09, 0xEEB0, 0x8F12, 0xF4E5, 0x8F13, 0xD8C2, 0x8F14, 0xDCD0, 0x8F15, 0xCCEE, 0x8F1B, 0xD5E0, 0x8F1C, 0xF6CA, 0x8F1D, 0xFDCA, 0x8F1E, 0xD8D6, 0x8F1F, 0xF4CF, 0x8F26, 0xD6A6, 0x8F27, 0xDCBE, 0x8F29, 0xDBD4, 0x8F2A, 0xD7C7, 0x8F2F, 0xF2FE, 0x8F33, 0xF1CD, 0x8F38, 0xE2C3, 0x8F39, 0xDCDE, 0x8F3B, 0xDCDF, 0x8F3E, 0xEFAD, 0x8F3F, 0xE6AB, 0x8F44, 0xF9DD, 0x8F45, 0xEABF, 0x8F49, 0xEFAE, 0x8F4D, 0xF4D0, 0x8F4E, 0xCEF3, 0x8F5D, 0xE6AC, 0x8F5F, 0xCEDE, 0x8F62, 0xD5F9, 0x8F9B, 0xE3F4, 0x8F9C, 0xCDD0, 0x8FA3, 0xD5B8, 0x8FA6, 0xF7FD, 0x8FA8, 0xDCA9, 0x8FAD, 0xDEF6, 0x8FAF, 0xDCAA, 0x8FB0, 0xF2E3, 0x8FB1, 0xE9B4, 0x8FB2, 0xD2DC, 0x8FC2, 0xE9E6, 0x8FC5, 0xE3F6, 0x8FCE, 0xE7CA, 0x8FD1, 0xD0CE, 0x8FD4, 0xDAF7, 0x8FE6, 0xCABC, 0x8FEA, 0xEEE8, 0x8FEB, 0xDADE, 0x8FED, 0xF2F7, 0x8FF0, 0xE2FB, 0x8FF2, 0xCCA6, 0x8FF7, 0xDABB, 0x8FF9, 0xEEE9, 0x8FFD, 0xF5DA, 0x9000, 0xF7DC, 0x9001, 0xE1EA, 0x9002, 0xCEC1, 0x9003, 0xD4B1, 0x9005, 0xFDB1, 0x9006, 0xE6BD, 0x9008, 0xFBAD, 0x900B, 0xF8E7, 0x900D, 0xE1CE, 0x900F, 0xF7E2, 0x9010, 0xF5EF, 0x9011, 0xCFC7, 0x9014, 0xD4B2, 0x9015, 0xCCEF, 0x9017, 0xD4E8, 0x9019, 0xEECF, 0x901A, 0xF7D7, 0x901D, 0xE0A6, 0x901E, 0xD6C1, 0x901F, 0xE1DC, 0x9020, 0xF0E3, 0x9021, 0xF1E4, 0x9022, 0xDCF1, 0x9023, 0xD6A7, 0x902E, 0xF4F5, 0x9031, 0xF1CE, 0x9032, 0xF2E4, 0x9035, 0xD0B0, 0x9038, 0xECEF, 0x903C, 0xF9BA, 0x903E, 0xEBB5, 0x9041, 0xD4ED, 0x9042, 0xE2C4, 0x9047, 0xE9E7, 0x904A, 0xEBB4, 0x904B, 0xEAA1, 0x904D, 0xF8BC, 0x904E, 0xCEA6, 0x9050, 0xF9C6, 0x9051, 0xFCDA, 0x9053, 0xD4B3, 0x9054, 0xD3B9, 0x9055, 0xEADE, 0x9059, 0xE9AB, 0x905C, 0xE1E1, 0x905D, 0xD3CF, 0x905E, 0xF4F6, 0x9060, 0xEAC0, 0x9061, 0xE1CF, 0x9063, 0xCCBA, 0x9069, 0xEEEA, 0x906D, 0xF0E4, 0x906E, 0xF3B4, 0x906F, 0xD4EE, 0x9072, 0xF2C0, 0x9075, 0xF1E5, 0x9077, 0xF4C3, 0x9078, 0xE0D4, 0x907A, 0xEBB6, 0x907C, 0xD7A1, 0x907D, 0xCBE8, 0x907F, 0xF9AD, 0x9080, 0xE9AD, 0x9081, 0xD8E4, 0x9082, 0xFAB3, 0x9083, 0xE2C5, 0x9084, 0xFCBD, 0x9087, 0xECC4, 0x9088, 0xD8B1, 0x908A, 0xDCAB, 0x908F, 0xD5A4, 0x9091, 0xEBE9, 0x9095, 0xE8BB, 0x9099, 0xD8D7, 0x90A2, 0xFBAE, 0x90A3, 0xD1E1, 0x90A6, 0xDBC0, 0x90A8, 0xF5BE, 0x90AA, 0xDEF7, 0x90AF, 0xCAFB, 0x90B0, 0xF7C6, 0x90B1, 0xCFC8, 0x90B5, 0xE1D0, 0x90B8, 0xEED0, 0x90C1, 0xE9F4, 0x90CA, 0xCEF4, 0x90DE, 0xD5CD, 0x90E1, 0xCFDB, 0x90E8, 0xDDBB, 0x90ED, 0xCEAC, 0x90F5, 0xE9E8, 0x90FD, 0xD4B4, 0x9102, 0xE4C7, 0x9112, 0xF5DB, 0x9115, 0xFAC1, 0x9119, 0xDEA9, 0x9127, 0xD4F8, 0x912D, 0xEFF7, 0x9132, 0xD3B3, 0x9149, 0xEBB7, 0x914A, 0xEFF8, 0x914B, 0xF5DC, 0x914C, 0xEDCC, 0x914D, 0xDBD5, 0x914E, 0xF1CF, 0x9152, 0xF1D0, 0x9162, 0xF5B2, 0x9169, 0xD9AE, 0x916A, 0xD5AC, 0x916C, 0xE2C6, 0x9175, 0xFDA3, 0x9177, 0xFBE5, 0x9178, 0xDFAB, 0x9187, 0xE2F5, 0x9189, 0xF6AD, 0x918B, 0xF5B3, 0x918D, 0xF0B5, 0x9192, 0xE1A5, 0x919C, 0xF5DD, 0x91AB, 0xECA2, 0x91AC, 0xEDFD, 0x91AE, 0xF5B4, 0x91AF, 0xFBB8, 0x91B1, 0xDBA3, 0x91B4, 0xD6CA, 0x91B5, 0xCBD9, 0x91C0, 0xE5D4, 0x91C7, 0xF3FA, 0x91C9, 0xEBB8, 0x91CB, 0xE0B7, 0x91CC, 0xD7EC, 0x91CD, 0xF1EC, 0x91CE, 0xE5AF, 0x91CF, 0xD5E1, 0x91D0, 0xD7ED, 0x91D1, 0xD1D1, 0x91D7, 0xE1F2, 0x91D8, 0xEFF9, 0x91DC, 0xDDBC, 0x91DD, 0xF6DC, 0x91E3, 0xF0E5, 0x91E7, 0xF4C4, 0x91EA, 0xE9E9, 0x91F5, 0xF3FB, 0x920D, 0xD4EF, 0x9210, 0xCCA2, 0x9211, 0xF7FE, 0x9212, 0xDFBC, 0x9217, 0xEBCD, 0x921E, 0xD0B7, 0x9234, 0xD6C2, 0x923A, 0xE8AD, 0x923F, 0xEFAF, 0x9240, 0xCBA5, 0x9245, 0xCBE9, 0x9249, 0xFAE8, 0x9257, 0xCCC6, 0x925B, 0xE6E7, 0x925E, 0xEAC7, 0x9262, 0xDBA4, 0x9264, 0xCFC9, 0x9265, 0xE2FC, 0x9266, 0xEFFA, 0x9280, 0xEBDE, 0x9283, 0xF5C8, 0x9285, 0xD4DE, 0x9291, 0xE0D5, 0x9293, 0xEFB0, 0x9296, 0xE2C7, 0x9298, 0xD9AF, 0x929C, 0xF9E7, 0x92B3, 0xE7E5, 0x92B6, 0xCFCA, 0x92B7, 0xE1D1, 0x92B9, 0xE2C8, 0x92CC, 0xEFFB, 0x92CF, 0xFAF9, 0x92D2, 0xDCF2, 0x92E4, 0xE0A7, 0x92EA, 0xF8E8, 0x92F8, 0xCBEA, 0x92FC, 0xCBBC, 0x9304, 0xD6E2, 0x9310, 0xF5DE, 0x9318, 0xF5DF, 0x931A, 0xEEB6, 0x931E, 0xE2F6, 0x931F, 0xD3CA, 0x9320, 0xEFFC, 0x9321, 0xD1C4, 0x9322, 0xEFB1, 0x9324, 0xD1C5, 0x9326, 0xD0DE, 0x9328, 0xD9E1, 0x932B, 0xE0B8, 0x932E, 0xCDD1, 0x932F, 0xF3B9, 0x9348, 0xE7CC, 0x934A, 0xD6A8, 0x934B, 0xCEA7, 0x934D, 0xD4B5, 0x9354, 0xE4C8, 0x935B, 0xD3B4, 0x936E, 0xEBB9, 0x9375, 0xCBF5, 0x937C, 0xF6DD, 0x937E, 0xF1A3, 0x938C, 0xCCC7, 0x9394, 0xE9CA, 0x9396, 0xE1F0, 0x939A, 0xF5E0, 0x93A3, 0xFBAF, 0x93A7, 0xCBD1, 0x93AC, 0xFBE0, 0x93AD, 0xF2E5, 0x93B0, 0xECF0, 0x93C3, 0xF0EC, 0x93D1, 0xEEEB, 0x93DE, 0xE9CB, 0x93E1, 0xCCF0, 0x93E4, 0xD7AF, 0x93F6, 0xF3A1, 0x9404, 0xFCF5, 0x9418, 0xF1A4, 0x9425, 0xE0D6, 0x942B, 0xEFB2, 0x9435, 0xF4D1, 0x9438, 0xF7A1, 0x9444, 0xF1D1, 0x9451, 0xCAFC, 0x9452, 0xCAFD, 0x945B, 0xCECE, 0x947D, 0xF3C8, 0x947F, 0xF3BA, 0x9577, 0xEDFE, 0x9580, 0xDAA6, 0x9583, 0xE0EC, 0x9589, 0xF8CD, 0x958B, 0xCBD2, 0x958F, 0xEBCE, 0x9591, 0xF9D8, 0x9592, 0xF9D9, 0x9593, 0xCAE0, 0x9594, 0xDACA, 0x9598, 0xCBA6, 0x95A3, 0xCAC8, 0x95A4, 0xF9EE, 0x95A5, 0xDBEC, 0x95A8, 0xD0B1, 0x95AD, 0xD5EF, 0x95B1, 0xE6F3, 0x95BB, 0xE7A2, 0x95BC, 0xE4D9, 0x95C7, 0xE4E1, 0x95CA, 0xFCC4, 0x95D4, 0xF9EF, 0x95D5, 0xCFF4, 0x95D6, 0xF7E6, 0x95DC, 0xCEBC, 0x95E1, 0xF4C5, 0x95E2, 0xDCA3, 0x961C, 0xDDBD, 0x9621, 0xF4C6, 0x962A, 0xF8A1, 0x962E, 0xE8D6, 0x9632, 0xDBC1, 0x963B, 0xF0E6, 0x963F, 0xE4B9, 0x9640, 0xF6ED, 0x9642, 0xF9AE, 0x9644, 0xDDBE, 0x964B, 0xD7B0, 0x964C, 0xD8E8, 0x964D, 0xCBBD, 0x9650, 0xF9DA, 0x965B, 0xF8CE, 0x965C, 0xF9F0, 0x965D, 0xE0ED, 0x965E, 0xE3B3, 0x965F, 0xF4B3, 0x9662, 0xEAC2, 0x9663, 0xF2E6, 0x9664, 0xF0B6, 0x966A, 0xDBD6, 0x9670, 0xEBE4, 0x9673, 0xF2E7, 0x9675, 0xD7D5, 0x9676, 0xD4B6, 0x9677, 0xF9E8, 0x9678, 0xD7C1, 0x967D, 0xE5D5, 0x9685, 0xE9EA, 0x9686, 0xD7CC, 0x968A, 0xD3E9, 0x968B, 0xE2C9, 0x968D, 0xFCDB, 0x968E, 0xCDAD, 0x9694, 0xCCB0, 0x9695, 0xEAA2, 0x9698, 0xE4F6, 0x9699, 0xD0C0, 0x969B, 0xF0B7, 0x969C, 0xEEA1, 0x96A3, 0xD7F6, 0x96A7, 0xE2CA, 0x96A8, 0xE2CB, 0x96AA, 0xFACF, 0x96B1, 0xEBDF, 0x96B7, 0xD6CB, 0x96BB, 0xF4B4, 0x96C0, 0xEDCD, 0x96C1, 0xE4D2, 0x96C4, 0xEAA9, 0x96C5, 0xE4BA, 0x96C6, 0xF3A2, 0x96C7, 0xCDD2, 0x96C9, 0xF6CB, 0x96CB, 0xF1E6, 0x96CC, 0xEDC1, 0x96CD, 0xE8BC, 0x96CE, 0xEED1, 0x96D5, 0xF0E7, 0x96D6, 0xE2CC, 0x96D9, 0xE4AA, 0x96DB, 0xF5E1, 0x96DC, 0xEDDA, 0x96E2, 0xD7EE, 0x96E3, 0xD1F1, 0x96E8, 0xE9EB, 0x96E9, 0xE9EC, 0x96EA, 0xE0E4, 0x96EF, 0xDAA7, 0x96F0, 0xDDD4, 0x96F2, 0xEAA3, 0x96F6, 0xD6C3, 0x96F7, 0xD6F4, 0x96F9, 0xDADF, 0x96FB, 0xEFB3, 0x9700, 0xE2CD, 0x9706, 0xEFFD, 0x9707, 0xF2E8, 0x9711, 0xEFC5, 0x9713, 0xE7E7, 0x9716, 0xD7FD, 0x9719, 0xE7CE, 0x971C, 0xDFDC, 0x971E, 0xF9C7, 0x9727, 0xD9F6, 0x9730, 0xDFAC, 0x9732, 0xD6DA, 0x9739, 0xDCA4, 0x973D, 0xF0B8, 0x9742, 0xD5FA, 0x9744, 0xE4F7, 0x9748, 0xD6C4, 0x9751, 0xF4EC, 0x9756, 0xEFFE, 0x975C, 0xF0A1, 0x975E, 0xDEAA, 0x9761, 0xDABC, 0x9762, 0xD8FC, 0x9769, 0xFAD4, 0x976D, 0xECE5, 0x9774, 0xFCA8, 0x9777, 0xECE6, 0x977A, 0xD8CB, 0x978B, 0xFBB9, 0x978D, 0xE4D3, 0x978F, 0xCDF9, 0x97A0, 0xCFD3, 0x97A8, 0xCAEA, 0x97AB, 0xCFD4, 0x97AD, 0xF8BD, 0x97C6, 0xF4C7, 0x97CB, 0xEADF, 0x97D3, 0xF9DB, 0x97DC, 0xD4B7, 0x97F3, 0xEBE5, 0x97F6, 0xE1D2, 0x97FB, 0xEAA4, 0x97FF, 0xFAC2, 0x9800, 0xFBE1, 0x9801, 0xFAED, 0x9802, 0xF0A2, 0x9803, 0xCCF1, 0x9805, 0xFAA3, 0x9806, 0xE2F7, 0x9808, 0xE2CE, 0x980A, 0xE9F5, 0x980C, 0xE1EB, 0x9810, 0xE7E8, 0x9811, 0xE8D7, 0x9812, 0xDAF8, 0x9813, 0xD4CB, 0x9817, 0xF7F6, 0x9818, 0xD6C5, 0x982D, 0xD4E9, 0x9830, 0xFAFA, 0x9838, 0xCCF2, 0x9839, 0xF7DD, 0x983B, 0xDEBA, 0x9846, 0xCEA8, 0x984C, 0xF0B9, 0x984D, 0xE4FE, 0x984E, 0xE4C9, 0x9854, 0xE4D4, 0x9858, 0xEAC3, 0x985A, 0xEFB4, 0x985E, 0xD7BE, 0x9865, 0xFBE2, 0x9867, 0xCDD3, 0x986B, 0xEFB5, 0x986F, 0xFAE9, 0x98A8, 0xF9A6, 0x98AF, 0xDFBD, 0x98B1, 0xF7C7, 0x98C4, 0xF8FD, 0x98C7, 0xF8FC, 0x98DB, 0xDEAB, 0x98DC, 0xDBE8, 0x98DF, 0xE3DD, 0x98E1, 0xE1E2, 0x98E2, 0xD1C6, 0x98ED, 0xF6D0, 0x98EE, 0xEBE6, 0x98EF, 0xDAF9, 0x98F4, 0xECC7, 0x98FC, 0xDEF8, 0x98FD, 0xF8E9, 0x98FE, 0xE3DE, 0x9903, 0xCEF5, 0x9909, 0xFAC3, 0x990A, 0xE5D7, 0x990C, 0xECC8, 0x9910, 0xF3C9, 0x9913, 0xE4BB, 0x9918, 0xE6AE, 0x991E, 0xEFB6, 0x9920, 0xDCBF, 0x9928, 0xCEBD, 0x9945, 0xD8C3, 0x9949, 0xD0CF, 0x994B, 0xCFFA, 0x994C, 0xF3CA, 0x994D, 0xE0D7, 0x9951, 0xD1C7, 0x9952, 0xE9AE, 0x9954, 0xE8BD, 0x9957, 0xFAC4, 0x9996, 0xE2CF, 0x9999, 0xFAC5, 0x999D, 0xF9B8, 0x99A5, 0xDCE0, 0x99A8, 0xFBB0, 0x99AC, 0xD8A9, 0x99AD, 0xE5DF, 0x99AE, 0xF9A7, 0x99B1, 0xF6EE, 0x99B3, 0xF6CC, 0x99B4, 0xE2F8, 0x99B9, 0xECF1, 0x99C1, 0xDAE0, 0x99D0, 0xF1D2, 0x99D1, 0xD2CC, 0x99D2, 0xCFCB, 0x99D5, 0xCABD, 0x99D9, 0xDDBF, 0x99DD, 0xF6EF, 0x99DF, 0xDEF9, 0x99ED, 0xFAB4, 0x99F1, 0xD5AD, 0x99FF, 0xF1E7, 0x9A01, 0xDEBE, 0x9A08, 0xDCC0, 0x9A0E, 0xD1C8, 0x9A0F, 0xD1C9, 0x9A19, 0xF8BE, 0x9A2B, 0xCBF6, 0x9A30, 0xD4F9, 0x9A36, 0xF5E2, 0x9A37, 0xE1D3, 0x9A40, 0xD8E9, 0x9A43, 0xF8FE, 0x9A45, 0xCFCC, 0x9A4D, 0xFDA4, 0x9A55, 0xCEF6, 0x9A57, 0xFAD0, 0x9A5A, 0xCCF3, 0x9A5B, 0xE6BE, 0x9A5F, 0xF6AE, 0x9A62, 0xD5F0, 0x9A65, 0xD1CA, 0x9A69, 0xFCBE, 0x9A6A, 0xD5F1, 0x9AA8, 0xCDE9, 0x9AB8, 0xFAB5, 0x9AD3, 0xE2D0, 0x9AD4, 0xF4F7, 0x9AD8, 0xCDD4, 0x9AE5, 0xE7A3, 0x9AEE, 0xDBA5, 0x9B1A, 0xE2D1, 0x9B27, 0xD7A2, 0x9B2A, 0xF7E3, 0x9B31, 0xEAA6, 0x9B3C, 0xD0A1, 0x9B41, 0xCEDA, 0x9B42, 0xFBEB, 0x9B43, 0xDBA6, 0x9B44, 0xDBDE, 0x9B45, 0xD8E5, 0x9B4F, 0xEAE0, 0x9B54, 0xD8AA, 0x9B5A, 0xE5E0, 0x9B6F, 0xD6DB, 0x9B8E, 0xEFC6, 0x9B91, 0xF8EA, 0x9B9F, 0xE4D5, 0x9BAB, 0xCEF7, 0x9BAE, 0xE0D8, 0x9BC9, 0xD7EF, 0x9BD6, 0xF4ED, 0x9BE4, 0xCDE6, 0x9BE8, 0xCCF4, 0x9C0D, 0xF5E3, 0x9C10, 0xE4CA, 0x9C12, 0xDCE1, 0x9C15, 0xF9C8, 0x9C25, 0xFCBF, 0x9C32, 0xE8A7, 0x9C3B, 0xD8C4, 0x9C47, 0xCBBE, 0x9C49, 0xDCAE, 0x9C57, 0xD7F7, 0x9CE5, 0xF0E8, 0x9CE7, 0xDDC0, 0x9CE9, 0xCFCD, 0x9CF3, 0xDCF3, 0x9CF4, 0xD9B0, 0x9CF6, 0xE6E9, 0x9D09, 0xE4BC, 0x9D1B, 0xEAC4, 0x9D26, 0xE4EC, 0x9D28, 0xE4E5, 0x9D3B, 0xFBF8, 0x9D51, 0xCCBB, 0x9D5D, 0xE4BD, 0x9D60, 0xCDDC, 0x9D61, 0xD9F7, 0x9D6C, 0xDDDF, 0x9D72, 0xEDCE, 0x9DA9, 0xD9D0, 0x9DAF, 0xE5A3, 0x9DB4, 0xF9CD, 0x9DC4, 0xCDAE, 0x9DD7, 0xCFCE, 0x9DF2, 0xF6AF, 0x9DF8, 0xFDD3, 0x9DF9, 0xEBED, 0x9DFA, 0xD6DC, 0x9E1A, 0xE5A4, 0x9E1E, 0xD5B6, 0x9E75, 0xD6DD, 0x9E79, 0xF9E9, 0x9E7D, 0xE7A4, 0x9E7F, 0xD6E3, 0x9E92, 0xD1CB, 0x9E93, 0xD6E4, 0x9E97, 0xD5F2, 0x9E9D, 0xDEFA, 0x9E9F, 0xD7F8, 0x9EA5, 0xD8EA, 0x9EB4, 0xCFD5, 0x9EB5, 0xD8FD, 0x9EBB, 0xD8AB, 0x9EBE, 0xFDCB, 0x9EC3, 0xFCDC, 0x9ECD, 0xE0A8, 0x9ECE, 0xD5F3, 0x9ED1, 0xFDD9, 0x9ED4, 0xCCA3, 0x9ED8, 0xD9F9, 0x9EDB, 0xD3EA, 0x9EDC, 0xF5F5, 0x9EDE, 0xEFC7, 0x9EE8, 0xD3DA, 0x9EF4, 0xDABD, 0x9F07, 0xE8A8, 0x9F08, 0xDCAF, 0x9F0E, 0xF0A3, 0x9F13, 0xCDD5, 0x9F20, 0xE0A9, 0x9F3B, 0xDEAC, 0x9F4A, 0xF0BA, 0x9F4B, 0xEEB1, 0x9F4E, 0xEEB2, 0x9F52, 0xF6CD, 0x9F5F, 0xEED2, 0x9F61, 0xD6C6, 0x9F67, 0xE0E5, 0x9F6A, 0xF3BB, 0x9F6C, 0xE5E1, 0x9F77, 0xE4CB, 0x9F8D, 0xD7A3, 0x9F90, 0xDBC2, 0x9F95, 0xCAFE, 0x9F9C, 0xCFCF, 0xAC00, 0xB0A1, 0xAC01, 0xB0A2, 0xAC02, 0x8141, 0xAC03, 0x8142, 0xAC04, 0xB0A3, 0xAC05, 0x8143, 0xAC06, 0x8144, 0xAC07, 0xB0A4, 0xAC08, 0xB0A5, 0xAC09, 0xB0A6, 0xAC0A, 0xB0A7, 0xAC0B, 0x8145, 0xAC0C, 0x8146, 0xAC0D, 0x8147, 0xAC0E, 0x8148, 0xAC0F, 0x8149, 0xAC10, 0xB0A8, 0xAC11, 0xB0A9, 0xAC12, 0xB0AA, 0xAC13, 0xB0AB, 0xAC14, 0xB0AC, 0xAC15, 0xB0AD, 0xAC16, 0xB0AE, 0xAC17, 0xB0AF, 0xAC18, 0x814A, 0xAC19, 0xB0B0, 0xAC1A, 0xB0B1, 0xAC1B, 0xB0B2, 0xAC1C, 0xB0B3, 0xAC1D, 0xB0B4, 0xAC1E, 0x814B, 0xAC1F, 0x814C, 0xAC20, 0xB0B5, 0xAC21, 0x814D, 0xAC22, 0x814E, 0xAC23, 0x814F, 0xAC24, 0xB0B6, 0xAC25, 0x8150, 0xAC26, 0x8151, 0xAC27, 0x8152, 0xAC28, 0x8153, 0xAC29, 0x8154, 0xAC2A, 0x8155, 0xAC2B, 0x8156, 0xAC2C, 0xB0B7, 0xAC2D, 0xB0B8, 0xAC2E, 0x8157, 0xAC2F, 0xB0B9, 0xAC30, 0xB0BA, 0xAC31, 0xB0BB, 0xAC32, 0x8158, 0xAC33, 0x8159, 0xAC34, 0x815A, 0xAC35, 0x8161, 0xAC36, 0x8162, 0xAC37, 0x8163, 0xAC38, 0xB0BC, 0xAC39, 0xB0BD, 0xAC3A, 0x8164, 0xAC3B, 0x8165, 0xAC3C, 0xB0BE, 0xAC3D, 0x8166, 0xAC3E, 0x8167, 0xAC3F, 0x8168, 0xAC40, 0xB0BF, 0xAC41, 0x8169, 0xAC42, 0x816A, 0xAC43, 0x816B, 0xAC44, 0x816C, 0xAC45, 0x816D, 0xAC46, 0x816E, 0xAC47, 0x816F, 0xAC48, 0x8170, 0xAC49, 0x8171, 0xAC4A, 0x8172, 0xAC4B, 0xB0C0, 0xAC4C, 0x8173, 0xAC4D, 0xB0C1, 0xAC4E, 0x8174, 0xAC4F, 0x8175, 0xAC50, 0x8176, 0xAC51, 0x8177, 0xAC52, 0x8178, 0xAC53, 0x8179, 0xAC54, 0xB0C2, 0xAC55, 0x817A, 0xAC56, 0x8181, 0xAC57, 0x8182, 0xAC58, 0xB0C3, 0xAC59, 0x8183, 0xAC5A, 0x8184, 0xAC5B, 0x8185, 0xAC5C, 0xB0C4, 0xAC5D, 0x8186, 0xAC5E, 0x8187, 0xAC5F, 0x8188, 0xAC60, 0x8189, 0xAC61, 0x818A, 0xAC62, 0x818B, 0xAC63, 0x818C, 0xAC64, 0x818D, 0xAC65, 0x818E, 0xAC66, 0x818F, 0xAC67, 0x8190, 0xAC68, 0x8191, 0xAC69, 0x8192, 0xAC6A, 0x8193, 0xAC6B, 0x8194, 0xAC6C, 0x8195, 0xAC6D, 0x8196, 0xAC6E, 0x8197, 0xAC6F, 0x8198, 0xAC70, 0xB0C5, 0xAC71, 0xB0C6, 0xAC72, 0x8199, 0xAC73, 0x819A, 0xAC74, 0xB0C7, 0xAC75, 0x819B, 0xAC76, 0x819C, 0xAC77, 0xB0C8, 0xAC78, 0xB0C9, 0xAC79, 0x819D, 0xAC7A, 0xB0CA, 0xAC7B, 0x819E, 0xAC7C, 0x819F, 0xAC7D, 0x81A0, 0xAC7E, 0x81A1, 0xAC7F, 0x81A2, 0xAC80, 0xB0CB, 0xAC81, 0xB0CC, 0xAC82, 0x81A3, 0xAC83, 0xB0CD, 0xAC84, 0xB0CE, 0xAC85, 0xB0CF, 0xAC86, 0xB0D0, 0xAC87, 0x81A4, 0xAC88, 0x81A5, 0xAC89, 0xB0D1, 0xAC8A, 0xB0D2, 0xAC8B, 0xB0D3, 0xAC8C, 0xB0D4, 0xAC8D, 0x81A6, 0xAC8E, 0x81A7, 0xAC8F, 0x81A8, 0xAC90, 0xB0D5, 0xAC91, 0x81A9, 0xAC92, 0x81AA, 0xAC93, 0x81AB, 0xAC94, 0xB0D6, 0xAC95, 0x81AC, 0xAC96, 0x81AD, 0xAC97, 0x81AE, 0xAC98, 0x81AF, 0xAC99, 0x81B0, 0xAC9A, 0x81B1, 0xAC9B, 0x81B2, 0xAC9C, 0xB0D7, 0xAC9D, 0xB0D8, 0xAC9E, 0x81B3, 0xAC9F, 0xB0D9, 0xACA0, 0xB0DA, 0xACA1, 0xB0DB, 0xACA2, 0x81B4, 0xACA3, 0x81B5, 0xACA4, 0x81B6, 0xACA5, 0x81B7, 0xACA6, 0x81B8, 0xACA7, 0x81B9, 0xACA8, 0xB0DC, 0xACA9, 0xB0DD, 0xACAA, 0xB0DE, 0xACAB, 0x81BA, 0xACAC, 0xB0DF, 0xACAD, 0x81BB, 0xACAE, 0x81BC, 0xACAF, 0xB0E0, 0xACB0, 0xB0E1, 0xACB1, 0x81BD, 0xACB2, 0x81BE, 0xACB3, 0x81BF, 0xACB4, 0x81C0, 0xACB5, 0x81C1, 0xACB6, 0x81C2, 0xACB7, 0x81C3, 0xACB8, 0xB0E2, 0xACB9, 0xB0E3, 0xACBA, 0x81C4, 0xACBB, 0xB0E4, 0xACBC, 0xB0E5, 0xACBD, 0xB0E6, 0xACBE, 0x81C5, 0xACBF, 0x81C6, 0xACC0, 0x81C7, 0xACC1, 0xB0E7, 0xACC2, 0x81C8, 0xACC3, 0x81C9, 0xACC4, 0xB0E8, 0xACC5, 0x81CA, 0xACC6, 0x81CB, 0xACC7, 0x81CC, 0xACC8, 0xB0E9, 0xACC9, 0x81CD, 0xACCA, 0x81CE, 0xACCB, 0x81CF, 0xACCC, 0xB0EA, 0xACCD, 0x81D0, 0xACCE, 0x81D1, 0xACCF, 0x81D2, 0xACD0, 0x81D3, 0xACD1, 0x81D4, 0xACD2, 0x81D5, 0xACD3, 0x81D6, 0xACD4, 0x81D7, 0xACD5, 0xB0EB, 0xACD6, 0x81D8, 0xACD7, 0xB0EC, 0xACD8, 0x81D9, 0xACD9, 0x81DA, 0xACDA, 0x81DB, 0xACDB, 0x81DC, 0xACDC, 0x81DD, 0xACDD, 0x81DE, 0xACDE, 0x81DF, 0xACDF, 0x81E0, 0xACE0, 0xB0ED, 0xACE1, 0xB0EE, 0xACE2, 0x81E1, 0xACE3, 0x81E2, 0xACE4, 0xB0EF, 0xACE5, 0x81E3, 0xACE6, 0x81E4, 0xACE7, 0xB0F0, 0xACE8, 0xB0F1, 0xACE9, 0x81E5, 0xACEA, 0xB0F2, 0xACEB, 0x81E6, 0xACEC, 0xB0F3, 0xACED, 0x81E7, 0xACEE, 0x81E8, 0xACEF, 0xB0F4, 0xACF0, 0xB0F5, 0xACF1, 0xB0F6, 0xACF2, 0x81E9, 0xACF3, 0xB0F7, 0xACF4, 0x81EA, 0xACF5, 0xB0F8, 0xACF6, 0xB0F9, 0xACF7, 0x81EB, 0xACF8, 0x81EC, 0xACF9, 0x81ED, 0xACFA, 0x81EE, 0xACFB, 0x81EF, 0xACFC, 0xB0FA, 0xACFD, 0xB0FB, 0xACFE, 0x81F0, 0xACFF, 0x81F1, 0xAD00, 0xB0FC, 0xAD01, 0x81F2, 0xAD02, 0x81F3, 0xAD03, 0x81F4, 0xAD04, 0xB0FD, 0xAD05, 0x81F5, 0xAD06, 0xB0FE, 0xAD07, 0x81F6, 0xAD08, 0x81F7, 0xAD09, 0x81F8, 0xAD0A, 0x81F9, 0xAD0B, 0x81FA, 0xAD0C, 0xB1A1, 0xAD0D, 0xB1A2, 0xAD0E, 0x81FB, 0xAD0F, 0xB1A3, 0xAD10, 0x81FC, 0xAD11, 0xB1A4, 0xAD12, 0x81FD, 0xAD13, 0x81FE, 0xAD14, 0x8241, 0xAD15, 0x8242, 0xAD16, 0x8243, 0xAD17, 0x8244, 0xAD18, 0xB1A5, 0xAD19, 0x8245, 0xAD1A, 0x8246, 0xAD1B, 0x8247, 0xAD1C, 0xB1A6, 0xAD1D, 0x8248, 0xAD1E, 0x8249, 0xAD1F, 0x824A, 0xAD20, 0xB1A7, 0xAD21, 0x824B, 0xAD22, 0x824C, 0xAD23, 0x824D, 0xAD24, 0x824E, 0xAD25, 0x824F, 0xAD26, 0x8250, 0xAD27, 0x8251, 0xAD28, 0x8252, 0xAD29, 0xB1A8, 0xAD2A, 0x8253, 0xAD2B, 0x8254, 0xAD2C, 0xB1A9, 0xAD2D, 0xB1AA, 0xAD2E, 0x8255, 0xAD2F, 0x8256, 0xAD30, 0x8257, 0xAD31, 0x8258, 0xAD32, 0x8259, 0xAD33, 0x825A, 0xAD34, 0xB1AB, 0xAD35, 0xB1AC, 0xAD36, 0x8261, 0xAD37, 0x8262, 0xAD38, 0xB1AD, 0xAD39, 0x8263, 0xAD3A, 0x8264, 0xAD3B, 0x8265, 0xAD3C, 0xB1AE, 0xAD3D, 0x8266, 0xAD3E, 0x8267, 0xAD3F, 0x8268, 0xAD40, 0x8269, 0xAD41, 0x826A, 0xAD42, 0x826B, 0xAD43, 0x826C, 0xAD44, 0xB1AF, 0xAD45, 0xB1B0, 0xAD46, 0x826D, 0xAD47, 0xB1B1, 0xAD48, 0x826E, 0xAD49, 0xB1B2, 0xAD4A, 0x826F, 0xAD4B, 0x8270, 0xAD4C, 0x8271, 0xAD4D, 0x8272, 0xAD4E, 0x8273, 0xAD4F, 0x8274, 0xAD50, 0xB1B3, 0xAD51, 0x8275, 0xAD52, 0x8276, 0xAD53, 0x8277, 0xAD54, 0xB1B4, 0xAD55, 0x8278, 0xAD56, 0x8279, 0xAD57, 0x827A, 0xAD58, 0xB1B5, 0xAD59, 0x8281, 0xAD5A, 0x8282, 0xAD5B, 0x8283, 0xAD5C, 0x8284, 0xAD5D, 0x8285, 0xAD5E, 0x8286, 0xAD5F, 0x8287, 0xAD60, 0x8288, 0xAD61, 0xB1B6, 0xAD62, 0x8289, 0xAD63, 0xB1B7, 0xAD64, 0x828A, 0xAD65, 0x828B, 0xAD66, 0x828C, 0xAD67, 0x828D, 0xAD68, 0x828E, 0xAD69, 0x828F, 0xAD6A, 0x8290, 0xAD6B, 0x8291, 0xAD6C, 0xB1B8, 0xAD6D, 0xB1B9, 0xAD6E, 0x8292, 0xAD6F, 0x8293, 0xAD70, 0xB1BA, 0xAD71, 0x8294, 0xAD72, 0x8295, 0xAD73, 0xB1BB, 0xAD74, 0xB1BC, 0xAD75, 0xB1BD, 0xAD76, 0xB1BE, 0xAD77, 0x8296, 0xAD78, 0x8297, 0xAD79, 0x8298, 0xAD7A, 0x8299, 0xAD7B, 0xB1BF, 0xAD7C, 0xB1C0, 0xAD7D, 0xB1C1, 0xAD7E, 0x829A, 0xAD7F, 0xB1C2, 0xAD80, 0x829B, 0xAD81, 0xB1C3, 0xAD82, 0xB1C4, 0xAD83, 0x829C, 0xAD84, 0x829D, 0xAD85, 0x829E, 0xAD86, 0x829F, 0xAD87, 0x82A0, 0xAD88, 0xB1C5, 0xAD89, 0xB1C6, 0xAD8A, 0x82A1, 0xAD8B, 0x82A2, 0xAD8C, 0xB1C7, 0xAD8D, 0x82A3, 0xAD8E, 0x82A4, 0xAD8F, 0x82A5, 0xAD90, 0xB1C8, 0xAD91, 0x82A6, 0xAD92, 0x82A7, 0xAD93, 0x82A8, 0xAD94, 0x82A9, 0xAD95, 0x82AA, 0xAD96, 0x82AB, 0xAD97, 0x82AC, 0xAD98, 0x82AD, 0xAD99, 0x82AE, 0xAD9A, 0x82AF, 0xAD9B, 0x82B0, 0xAD9C, 0xB1C9, 0xAD9D, 0xB1CA, 0xAD9E, 0x82B1, 0xAD9F, 0x82B2, 0xADA0, 0x82B3, 0xADA1, 0x82B4, 0xADA2, 0x82B5, 0xADA3, 0x82B6, 0xADA4, 0xB1CB, 0xADA5, 0x82B7, 0xADA6, 0x82B8, 0xADA7, 0x82B9, 0xADA8, 0x82BA, 0xADA9, 0x82BB, 0xADAA, 0x82BC, 0xADAB, 0x82BD, 0xADAC, 0x82BE, 0xADAD, 0x82BF, 0xADAE, 0x82C0, 0xADAF, 0x82C1, 0xADB0, 0x82C2, 0xADB1, 0x82C3, 0xADB2, 0x82C4, 0xADB3, 0x82C5, 0xADB4, 0x82C6, 0xADB5, 0x82C7, 0xADB6, 0x82C8, 0xADB7, 0xB1CC, 0xADB8, 0x82C9, 0xADB9, 0x82CA, 0xADBA, 0x82CB, 0xADBB, 0x82CC, 0xADBC, 0x82CD, 0xADBD, 0x82CE, 0xADBE, 0x82CF, 0xADBF, 0x82D0, 0xADC0, 0xB1CD, 0xADC1, 0xB1CE, 0xADC2, 0x82D1, 0xADC3, 0x82D2, 0xADC4, 0xB1CF, 0xADC5, 0x82D3, 0xADC6, 0x82D4, 0xADC7, 0x82D5, 0xADC8, 0xB1D0, 0xADC9, 0x82D6, 0xADCA, 0x82D7, 0xADCB, 0x82D8, 0xADCC, 0x82D9, 0xADCD, 0x82DA, 0xADCE, 0x82DB, 0xADCF, 0x82DC, 0xADD0, 0xB1D1, 0xADD1, 0xB1D2, 0xADD2, 0x82DD, 0xADD3, 0xB1D3, 0xADD4, 0x82DE, 0xADD5, 0x82DF, 0xADD6, 0x82E0, 0xADD7, 0x82E1, 0xADD8, 0x82E2, 0xADD9, 0x82E3, 0xADDA, 0x82E4, 0xADDB, 0x82E5, 0xADDC, 0xB1D4, 0xADDD, 0x82E6, 0xADDE, 0x82E7, 0xADDF, 0x82E8, 0xADE0, 0xB1D5, 0xADE1, 0x82E9, 0xADE2, 0x82EA, 0xADE3, 0x82EB, 0xADE4, 0xB1D6, 0xADE5, 0x82EC, 0xADE6, 0x82ED, 0xADE7, 0x82EE, 0xADE8, 0x82EF, 0xADE9, 0x82F0, 0xADEA, 0x82F1, 0xADEB, 0x82F2, 0xADEC, 0x82F3, 0xADED, 0x82F4, 0xADEE, 0x82F5, 0xADEF, 0x82F6, 0xADF0, 0x82F7, 0xADF1, 0x82F8, 0xADF2, 0x82F9, 0xADF3, 0x82FA, 0xADF4, 0x82FB, 0xADF5, 0x82FC, 0xADF6, 0x82FD, 0xADF7, 0x82FE, 0xADF8, 0xB1D7, 0xADF9, 0xB1D8, 0xADFA, 0x8341, 0xADFB, 0x8342, 0xADFC, 0xB1D9, 0xADFD, 0x8343, 0xADFE, 0x8344, 0xADFF, 0xB1DA, 0xAE00, 0xB1DB, 0xAE01, 0xB1DC, 0xAE02, 0x8345, 0xAE03, 0x8346, 0xAE04, 0x8347, 0xAE05, 0x8348, 0xAE06, 0x8349, 0xAE07, 0x834A, 0xAE08, 0xB1DD, 0xAE09, 0xB1DE, 0xAE0A, 0x834B, 0xAE0B, 0xB1DF, 0xAE0C, 0x834C, 0xAE0D, 0xB1E0, 0xAE0E, 0x834D, 0xAE0F, 0x834E, 0xAE10, 0x834F, 0xAE11, 0x8350, 0xAE12, 0x8351, 0xAE13, 0x8352, 0xAE14, 0xB1E1, 0xAE15, 0x8353, 0xAE16, 0x8354, 0xAE17, 0x8355, 0xAE18, 0x8356, 0xAE19, 0x8357, 0xAE1A, 0x8358, 0xAE1B, 0x8359, 0xAE1C, 0x835A, 0xAE1D, 0x8361, 0xAE1E, 0x8362, 0xAE1F, 0x8363, 0xAE20, 0x8364, 0xAE21, 0x8365, 0xAE22, 0x8366, 0xAE23, 0x8367, 0xAE24, 0x8368, 0xAE25, 0x8369, 0xAE26, 0x836A, 0xAE27, 0x836B, 0xAE28, 0x836C, 0xAE29, 0x836D, 0xAE2A, 0x836E, 0xAE2B, 0x836F, 0xAE2C, 0x8370, 0xAE2D, 0x8371, 0xAE2E, 0x8372, 0xAE2F, 0x8373, 0xAE30, 0xB1E2, 0xAE31, 0xB1E3, 0xAE32, 0x8374, 0xAE33, 0x8375, 0xAE34, 0xB1E4, 0xAE35, 0x8376, 0xAE36, 0x8377, 0xAE37, 0xB1E5, 0xAE38, 0xB1E6, 0xAE39, 0x8378, 0xAE3A, 0xB1E7, 0xAE3B, 0x8379, 0xAE3C, 0x837A, 0xAE3D, 0x8381, 0xAE3E, 0x8382, 0xAE3F, 0x8383, 0xAE40, 0xB1E8, 0xAE41, 0xB1E9, 0xAE42, 0x8384, 0xAE43, 0xB1EA, 0xAE44, 0x8385, 0xAE45, 0xB1EB, 0xAE46, 0xB1EC, 0xAE47, 0x8386, 0xAE48, 0x8387, 0xAE49, 0x8388, 0xAE4A, 0xB1ED, 0xAE4B, 0x8389, 0xAE4C, 0xB1EE, 0xAE4D, 0xB1EF, 0xAE4E, 0xB1F0, 0xAE4F, 0x838A, 0xAE50, 0xB1F1, 0xAE51, 0x838B, 0xAE52, 0x838C, 0xAE53, 0x838D, 0xAE54, 0xB1F2, 0xAE55, 0x838E, 0xAE56, 0xB1F3, 0xAE57, 0x838F, 0xAE58, 0x8390, 0xAE59, 0x8391, 0xAE5A, 0x8392, 0xAE5B, 0x8393, 0xAE5C, 0xB1F4, 0xAE5D, 0xB1F5, 0xAE5E, 0x8394, 0xAE5F, 0xB1F6, 0xAE60, 0xB1F7, 0xAE61, 0xB1F8, 0xAE62, 0x8395, 0xAE63, 0x8396, 0xAE64, 0x8397, 0xAE65, 0xB1F9, 0xAE66, 0x8398, 0xAE67, 0x8399, 0xAE68, 0xB1FA, 0xAE69, 0xB1FB, 0xAE6A, 0x839A, 0xAE6B, 0x839B, 0xAE6C, 0xB1FC, 0xAE6D, 0x839C, 0xAE6E, 0x839D, 0xAE6F, 0x839E, 0xAE70, 0xB1FD, 0xAE71, 0x839F, 0xAE72, 0x83A0, 0xAE73, 0x83A1, 0xAE74, 0x83A2, 0xAE75, 0x83A3, 0xAE76, 0x83A4, 0xAE77, 0x83A5, 0xAE78, 0xB1FE, 0xAE79, 0xB2A1, 0xAE7A, 0x83A6, 0xAE7B, 0xB2A2, 0xAE7C, 0xB2A3, 0xAE7D, 0xB2A4, 0xAE7E, 0x83A7, 0xAE7F, 0x83A8, 0xAE80, 0x83A9, 0xAE81, 0x83AA, 0xAE82, 0x83AB, 0xAE83, 0x83AC, 0xAE84, 0xB2A5, 0xAE85, 0xB2A6, 0xAE86, 0x83AD, 0xAE87, 0x83AE, 0xAE88, 0x83AF, 0xAE89, 0x83B0, 0xAE8A, 0x83B1, 0xAE8B, 0x83B2, 0xAE8C, 0xB2A7, 0xAE8D, 0x83B3, 0xAE8E, 0x83B4, 0xAE8F, 0x83B5, 0xAE90, 0x83B6, 0xAE91, 0x83B7, 0xAE92, 0x83B8, 0xAE93, 0x83B9, 0xAE94, 0x83BA, 0xAE95, 0x83BB, 0xAE96, 0x83BC, 0xAE97, 0x83BD, 0xAE98, 0x83BE, 0xAE99, 0x83BF, 0xAE9A, 0x83C0, 0xAE9B, 0x83C1, 0xAE9C, 0x83C2, 0xAE9D, 0x83C3, 0xAE9E, 0x83C4, 0xAE9F, 0x83C5, 0xAEA0, 0x83C6, 0xAEA1, 0x83C7, 0xAEA2, 0x83C8, 0xAEA3, 0x83C9, 0xAEA4, 0x83CA, 0xAEA5, 0x83CB, 0xAEA6, 0x83CC, 0xAEA7, 0x83CD, 0xAEA8, 0x83CE, 0xAEA9, 0x83CF, 0xAEAA, 0x83D0, 0xAEAB, 0x83D1, 0xAEAC, 0x83D2, 0xAEAD, 0x83D3, 0xAEAE, 0x83D4, 0xAEAF, 0x83D5, 0xAEB0, 0x83D6, 0xAEB1, 0x83D7, 0xAEB2, 0x83D8, 0xAEB3, 0x83D9, 0xAEB4, 0x83DA, 0xAEB5, 0x83DB, 0xAEB6, 0x83DC, 0xAEB7, 0x83DD, 0xAEB8, 0x83DE, 0xAEB9, 0x83DF, 0xAEBA, 0x83E0, 0xAEBB, 0x83E1, 0xAEBC, 0xB2A8, 0xAEBD, 0xB2A9, 0xAEBE, 0xB2AA, 0xAEBF, 0x83E2, 0xAEC0, 0xB2AB, 0xAEC1, 0x83E3, 0xAEC2, 0x83E4, 0xAEC3, 0x83E5, 0xAEC4, 0xB2AC, 0xAEC5, 0x83E6, 0xAEC6, 0x83E7, 0xAEC7, 0x83E8, 0xAEC8, 0x83E9, 0xAEC9, 0x83EA, 0xAECA, 0x83EB, 0xAECB, 0x83EC, 0xAECC, 0xB2AD, 0xAECD, 0xB2AE, 0xAECE, 0x83ED, 0xAECF, 0xB2AF, 0xAED0, 0xB2B0, 0xAED1, 0xB2B1, 0xAED2, 0x83EE, 0xAED3, 0x83EF, 0xAED4, 0x83F0, 0xAED5, 0x83F1, 0xAED6, 0x83F2, 0xAED7, 0x83F3, 0xAED8, 0xB2B2, 0xAED9, 0xB2B3, 0xAEDA, 0x83F4, 0xAEDB, 0x83F5, 0xAEDC, 0xB2B4, 0xAEDD, 0x83F6, 0xAEDE, 0x83F7, 0xAEDF, 0x83F8, 0xAEE0, 0x83F9, 0xAEE1, 0x83FA, 0xAEE2, 0x83FB, 0xAEE3, 0x83FC, 0xAEE4, 0x83FD, 0xAEE5, 0x83FE, 0xAEE6, 0x8441, 0xAEE7, 0x8442, 0xAEE8, 0xB2B5, 0xAEE9, 0x8443, 0xAEEA, 0x8444, 0xAEEB, 0xB2B6, 0xAEEC, 0x8445, 0xAEED, 0xB2B7, 0xAEEE, 0x8446, 0xAEEF, 0x8447, 0xAEF0, 0x8448, 0xAEF1, 0x8449, 0xAEF2, 0x844A, 0xAEF3, 0x844B, 0xAEF4, 0xB2B8, 0xAEF5, 0x844C, 0xAEF6, 0x844D, 0xAEF7, 0x844E, 0xAEF8, 0xB2B9, 0xAEF9, 0x844F, 0xAEFA, 0x8450, 0xAEFB, 0x8451, 0xAEFC, 0xB2BA, 0xAEFD, 0x8452, 0xAEFE, 0x8453, 0xAEFF, 0x8454, 0xAF00, 0x8455, 0xAF01, 0x8456, 0xAF02, 0x8457, 0xAF03, 0x8458, 0xAF04, 0x8459, 0xAF05, 0x845A, 0xAF06, 0x8461, 0xAF07, 0xB2BB, 0xAF08, 0xB2BC, 0xAF09, 0x8462, 0xAF0A, 0x8463, 0xAF0B, 0x8464, 0xAF0C, 0x8465, 0xAF0D, 0xB2BD, 0xAF0E, 0x8466, 0xAF0F, 0x8467, 0xAF10, 0xB2BE, 0xAF11, 0x8468, 0xAF12, 0x8469, 0xAF13, 0x846A, 0xAF14, 0x846B, 0xAF15, 0x846C, 0xAF16, 0x846D, 0xAF17, 0x846E, 0xAF18, 0x846F, 0xAF19, 0x8470, 0xAF1A, 0x8471, 0xAF1B, 0x8472, 0xAF1C, 0x8473, 0xAF1D, 0x8474, 0xAF1E, 0x8475, 0xAF1F, 0x8476, 0xAF20, 0x8477, 0xAF21, 0x8478, 0xAF22, 0x8479, 0xAF23, 0x847A, 0xAF24, 0x8481, 0xAF25, 0x8482, 0xAF26, 0x8483, 0xAF27, 0x8484, 0xAF28, 0x8485, 0xAF29, 0x8486, 0xAF2A, 0x8487, 0xAF2B, 0x8488, 0xAF2C, 0xB2BF, 0xAF2D, 0xB2C0, 0xAF2E, 0x8489, 0xAF2F, 0x848A, 0xAF30, 0xB2C1, 0xAF31, 0x848B, 0xAF32, 0xB2C2, 0xAF33, 0x848C, 0xAF34, 0xB2C3, 0xAF35, 0x848D, 0xAF36, 0x848E, 0xAF37, 0x848F, 0xAF38, 0x8490, 0xAF39, 0x8491, 0xAF3A, 0x8492, 0xAF3B, 0x8493, 0xAF3C, 0xB2C4, 0xAF3D, 0xB2C5, 0xAF3E, 0x8494, 0xAF3F, 0xB2C6, 0xAF40, 0x8495, 0xAF41, 0xB2C7, 0xAF42, 0xB2C8, 0xAF43, 0xB2C9, 0xAF44, 0x8496, 0xAF45, 0x8497, 0xAF46, 0x8498, 0xAF47, 0x8499, 0xAF48, 0xB2CA, 0xAF49, 0xB2CB, 0xAF4A, 0x849A, 0xAF4B, 0x849B, 0xAF4C, 0x849C, 0xAF4D, 0x849D, 0xAF4E, 0x849E, 0xAF4F, 0x849F, 0xAF50, 0xB2CC, 0xAF51, 0x84A0, 0xAF52, 0x84A1, 0xAF53, 0x84A2, 0xAF54, 0x84A3, 0xAF55, 0x84A4, 0xAF56, 0x84A5, 0xAF57, 0x84A6, 0xAF58, 0x84A7, 0xAF59, 0x84A8, 0xAF5A, 0x84A9, 0xAF5B, 0x84AA, 0xAF5C, 0xB2CD, 0xAF5D, 0xB2CE, 0xAF5E, 0x84AB, 0xAF5F, 0x84AC, 0xAF60, 0x84AD, 0xAF61, 0x84AE, 0xAF62, 0x84AF, 0xAF63, 0x84B0, 0xAF64, 0xB2CF, 0xAF65, 0xB2D0, 0xAF66, 0x84B1, 0xAF67, 0x84B2, 0xAF68, 0x84B3, 0xAF69, 0x84B4, 0xAF6A, 0x84B5, 0xAF6B, 0x84B6, 0xAF6C, 0x84B7, 0xAF6D, 0x84B8, 0xAF6E, 0x84B9, 0xAF6F, 0x84BA, 0xAF70, 0x84BB, 0xAF71, 0x84BC, 0xAF72, 0x84BD, 0xAF73, 0x84BE, 0xAF74, 0x84BF, 0xAF75, 0x84C0, 0xAF76, 0x84C1, 0xAF77, 0x84C2, 0xAF78, 0x84C3, 0xAF79, 0xB2D1, 0xAF7A, 0x84C4, 0xAF7B, 0x84C5, 0xAF7C, 0x84C6, 0xAF7D, 0x84C7, 0xAF7E, 0x84C8, 0xAF7F, 0x84C9, 0xAF80, 0xB2D2, 0xAF81, 0x84CA, 0xAF82, 0x84CB, 0xAF83, 0x84CC, 0xAF84, 0xB2D3, 0xAF85, 0x84CD, 0xAF86, 0x84CE, 0xAF87, 0x84CF, 0xAF88, 0xB2D4, 0xAF89, 0x84D0, 0xAF8A, 0x84D1, 0xAF8B, 0x84D2, 0xAF8C, 0x84D3, 0xAF8D, 0x84D4, 0xAF8E, 0x84D5, 0xAF8F, 0x84D6, 0xAF90, 0xB2D5, 0xAF91, 0xB2D6, 0xAF92, 0x84D7, 0xAF93, 0x84D8, 0xAF94, 0x84D9, 0xAF95, 0xB2D7, 0xAF96, 0x84DA, 0xAF97, 0x84DB, 0xAF98, 0x84DC, 0xAF99, 0x84DD, 0xAF9A, 0x84DE, 0xAF9B, 0x84DF, 0xAF9C, 0xB2D8, 0xAF9D, 0x84E0, 0xAF9E, 0x84E1, 0xAF9F, 0x84E2, 0xAFA0, 0x84E3, 0xAFA1, 0x84E4, 0xAFA2, 0x84E5, 0xAFA3, 0x84E6, 0xAFA4, 0x84E7, 0xAFA5, 0x84E8, 0xAFA6, 0x84E9, 0xAFA7, 0x84EA, 0xAFA8, 0x84EB, 0xAFA9, 0x84EC, 0xAFAA, 0x84ED, 0xAFAB, 0x84EE, 0xAFAC, 0x84EF, 0xAFAD, 0x84F0, 0xAFAE, 0x84F1, 0xAFAF, 0x84F2, 0xAFB0, 0x84F3, 0xAFB1, 0x84F4, 0xAFB2, 0x84F5, 0xAFB3, 0x84F6, 0xAFB4, 0x84F7, 0xAFB5, 0x84F8, 0xAFB6, 0x84F9, 0xAFB7, 0x84FA, 0xAFB8, 0xB2D9, 0xAFB9, 0xB2DA, 0xAFBA, 0x84FB, 0xAFBB, 0x84FC, 0xAFBC, 0xB2DB, 0xAFBD, 0x84FD, 0xAFBE, 0x84FE, 0xAFBF, 0x8541, 0xAFC0, 0xB2DC, 0xAFC1, 0x8542, 0xAFC2, 0x8543, 0xAFC3, 0x8544, 0xAFC4, 0x8545, 0xAFC5, 0x8546, 0xAFC6, 0x8547, 0xAFC7, 0xB2DD, 0xAFC8, 0xB2DE, 0xAFC9, 0xB2DF, 0xAFCA, 0x8548, 0xAFCB, 0xB2E0, 0xAFCC, 0x8549, 0xAFCD, 0xB2E1, 0xAFCE, 0xB2E2, 0xAFCF, 0x854A, 0xAFD0, 0x854B, 0xAFD1, 0x854C, 0xAFD2, 0x854D, 0xAFD3, 0x854E, 0xAFD4, 0xB2E3, 0xAFD5, 0x854F, 0xAFD6, 0x8550, 0xAFD7, 0x8551, 0xAFD8, 0x8552, 0xAFD9, 0x8553, 0xAFDA, 0x8554, 0xAFDB, 0x8555, 0xAFDC, 0xB2E4, 0xAFDD, 0x8556, 0xAFDE, 0x8557, 0xAFDF, 0x8558, 0xAFE0, 0x8559, 0xAFE1, 0x855A, 0xAFE2, 0x8561, 0xAFE3, 0x8562, 0xAFE4, 0x8563, 0xAFE5, 0x8564, 0xAFE6, 0x8565, 0xAFE7, 0x8566, 0xAFE8, 0xB2E5, 0xAFE9, 0xB2E6, 0xAFEA, 0x8567, 0xAFEB, 0x8568, 0xAFEC, 0x8569, 0xAFED, 0x856A, 0xAFEE, 0x856B, 0xAFEF, 0x856C, 0xAFF0, 0xB2E7, 0xAFF1, 0xB2E8, 0xAFF2, 0x856D, 0xAFF3, 0x856E, 0xAFF4, 0xB2E9, 0xAFF5, 0x856F, 0xAFF6, 0x8570, 0xAFF7, 0x8571, 0xAFF8, 0xB2EA, 0xAFF9, 0x8572, 0xAFFA, 0x8573, 0xAFFB, 0x8574, 0xAFFC, 0x8575, 0xAFFD, 0x8576, 0xAFFE, 0x8577, 0xAFFF, 0x8578, 0xB000, 0xB2EB, 0xB001, 0xB2EC, 0xB002, 0x8579, 0xB003, 0x857A, 0xB004, 0xB2ED, 0xB005, 0x8581, 0xB006, 0x8582, 0xB007, 0x8583, 0xB008, 0x8584, 0xB009, 0x8585, 0xB00A, 0x8586, 0xB00B, 0x8587, 0xB00C, 0xB2EE, 0xB00D, 0x8588, 0xB00E, 0x8589, 0xB00F, 0x858A, 0xB010, 0xB2EF, 0xB011, 0x858B, 0xB012, 0x858C, 0xB013, 0x858D, 0xB014, 0xB2F0, 0xB015, 0x858E, 0xB016, 0x858F, 0xB017, 0x8590, 0xB018, 0x8591, 0xB019, 0x8592, 0xB01A, 0x8593, 0xB01B, 0x8594, 0xB01C, 0xB2F1, 0xB01D, 0xB2F2, 0xB01E, 0x8595, 0xB01F, 0x8596, 0xB020, 0x8597, 0xB021, 0x8598, 0xB022, 0x8599, 0xB023, 0x859A, 0xB024, 0x859B, 0xB025, 0x859C, 0xB026, 0x859D, 0xB027, 0x859E, 0xB028, 0xB2F3, 0xB029, 0x859F, 0xB02A, 0x85A0, 0xB02B, 0x85A1, 0xB02C, 0x85A2, 0xB02D, 0x85A3, 0xB02E, 0x85A4, 0xB02F, 0x85A5, 0xB030, 0x85A6, 0xB031, 0x85A7, 0xB032, 0x85A8, 0xB033, 0x85A9, 0xB034, 0x85AA, 0xB035, 0x85AB, 0xB036, 0x85AC, 0xB037, 0x85AD, 0xB038, 0x85AE, 0xB039, 0x85AF, 0xB03A, 0x85B0, 0xB03B, 0x85B1, 0xB03C, 0x85B2, 0xB03D, 0x85B3, 0xB03E, 0x85B4, 0xB03F, 0x85B5, 0xB040, 0x85B6, 0xB041, 0x85B7, 0xB042, 0x85B8, 0xB043, 0x85B9, 0xB044, 0xB2F4, 0xB045, 0xB2F5, 0xB046, 0x85BA, 0xB047, 0x85BB, 0xB048, 0xB2F6, 0xB049, 0x85BC, 0xB04A, 0xB2F7, 0xB04B, 0x85BD, 0xB04C, 0xB2F8, 0xB04D, 0x85BE, 0xB04E, 0xB2F9, 0xB04F, 0x85BF, 0xB050, 0x85C0, 0xB051, 0x85C1, 0xB052, 0x85C2, 0xB053, 0xB2FA, 0xB054, 0xB2FB, 0xB055, 0xB2FC, 0xB056, 0x85C3, 0xB057, 0xB2FD, 0xB058, 0x85C4, 0xB059, 0xB2FE, 0xB05A, 0x85C5, 0xB05B, 0x85C6, 0xB05C, 0x85C7, 0xB05D, 0xB3A1, 0xB05E, 0x85C8, 0xB05F, 0x85C9, 0xB060, 0x85CA, 0xB061, 0x85CB, 0xB062, 0x85CC, 0xB063, 0x85CD, 0xB064, 0x85CE, 0xB065, 0x85CF, 0xB066, 0x85D0, 0xB067, 0x85D1, 0xB068, 0x85D2, 0xB069, 0x85D3, 0xB06A, 0x85D4, 0xB06B, 0x85D5, 0xB06C, 0x85D6, 0xB06D, 0x85D7, 0xB06E, 0x85D8, 0xB06F, 0x85D9, 0xB070, 0x85DA, 0xB071, 0x85DB, 0xB072, 0x85DC, 0xB073, 0x85DD, 0xB074, 0x85DE, 0xB075, 0x85DF, 0xB076, 0x85E0, 0xB077, 0x85E1, 0xB078, 0x85E2, 0xB079, 0x85E3, 0xB07A, 0x85E4, 0xB07B, 0x85E5, 0xB07C, 0xB3A2, 0xB07D, 0xB3A3, 0xB07E, 0x85E6, 0xB07F, 0x85E7, 0xB080, 0xB3A4, 0xB081, 0x85E8, 0xB082, 0x85E9, 0xB083, 0x85EA, 0xB084, 0xB3A5, 0xB085, 0x85EB, 0xB086, 0x85EC, 0xB087, 0x85ED, 0xB088, 0x85EE, 0xB089, 0x85EF, 0xB08A, 0x85F0, 0xB08B, 0x85F1, 0xB08C, 0xB3A6, 0xB08D, 0xB3A7, 0xB08E, 0x85F2, 0xB08F, 0xB3A8, 0xB090, 0x85F3, 0xB091, 0xB3A9, 0xB092, 0x85F4, 0xB093, 0x85F5, 0xB094, 0x85F6, 0xB095, 0x85F7, 0xB096, 0x85F8, 0xB097, 0x85F9, 0xB098, 0xB3AA, 0xB099, 0xB3AB, 0xB09A, 0xB3AC, 0xB09B, 0x85FA, 0xB09C, 0xB3AD, 0xB09D, 0x85FB, 0xB09E, 0x85FC, 0xB09F, 0xB3AE, 0xB0A0, 0xB3AF, 0xB0A1, 0xB3B0, 0xB0A2, 0xB3B1, 0xB0A3, 0x85FD, 0xB0A4, 0x85FE, 0xB0A5, 0x8641, 0xB0A6, 0x8642, 0xB0A7, 0x8643, 0xB0A8, 0xB3B2, 0xB0A9, 0xB3B3, 0xB0AA, 0x8644, 0xB0AB, 0xB3B4, 0xB0AC, 0xB3B5, 0xB0AD, 0xB3B6, 0xB0AE, 0xB3B7, 0xB0AF, 0xB3B8, 0xB0B0, 0x8645, 0xB0B1, 0xB3B9, 0xB0B2, 0x8646, 0xB0B3, 0xB3BA, 0xB0B4, 0xB3BB, 0xB0B5, 0xB3BC, 0xB0B6, 0x8647, 0xB0B7, 0x8648, 0xB0B8, 0xB3BD, 0xB0B9, 0x8649, 0xB0BA, 0x864A, 0xB0BB, 0x864B, 0xB0BC, 0xB3BE, 0xB0BD, 0x864C, 0xB0BE, 0x864D, 0xB0BF, 0x864E, 0xB0C0, 0x864F, 0xB0C1, 0x8650, 0xB0C2, 0x8651, 0xB0C3, 0x8652, 0xB0C4, 0xB3BF, 0xB0C5, 0xB3C0, 0xB0C6, 0x8653, 0xB0C7, 0xB3C1, 0xB0C8, 0xB3C2, 0xB0C9, 0xB3C3, 0xB0CA, 0x8654, 0xB0CB, 0x8655, 0xB0CC, 0x8656, 0xB0CD, 0x8657, 0xB0CE, 0x8658, 0xB0CF, 0x8659, 0xB0D0, 0xB3C4, 0xB0D1, 0xB3C5, 0xB0D2, 0x865A, 0xB0D3, 0x8661, 0xB0D4, 0xB3C6, 0xB0D5, 0x8662, 0xB0D6, 0x8663, 0xB0D7, 0x8664, 0xB0D8, 0xB3C7, 0xB0D9, 0x8665, 0xB0DA, 0x8666, 0xB0DB, 0x8667, 0xB0DC, 0x8668, 0xB0DD, 0x8669, 0xB0DE, 0x866A, 0xB0DF, 0x866B, 0xB0E0, 0xB3C8, 0xB0E1, 0x866C, 0xB0E2, 0x866D, 0xB0E3, 0x866E, 0xB0E4, 0x866F, 0xB0E5, 0xB3C9, 0xB0E6, 0x8670, 0xB0E7, 0x8671, 0xB0E8, 0x8672, 0xB0E9, 0x8673, 0xB0EA, 0x8674, 0xB0EB, 0x8675, 0xB0EC, 0x8676, 0xB0ED, 0x8677, 0xB0EE, 0x8678, 0xB0EF, 0x8679, 0xB0F0, 0x867A, 0xB0F1, 0x8681, 0xB0F2, 0x8682, 0xB0F3, 0x8683, 0xB0F4, 0x8684, 0xB0F5, 0x8685, 0xB0F6, 0x8686, 0xB0F7, 0x8687, 0xB0F8, 0x8688, 0xB0F9, 0x8689, 0xB0FA, 0x868A, 0xB0FB, 0x868B, 0xB0FC, 0x868C, 0xB0FD, 0x868D, 0xB0FE, 0x868E, 0xB0FF, 0x868F, 0xB100, 0x8690, 0xB101, 0x8691, 0xB102, 0x8692, 0xB103, 0x8693, 0xB104, 0x8694, 0xB105, 0x8695, 0xB106, 0x8696, 0xB107, 0x8697, 0xB108, 0xB3CA, 0xB109, 0xB3CB, 0xB10A, 0x8698, 0xB10B, 0xB3CC, 0xB10C, 0xB3CD, 0xB10D, 0x8699, 0xB10E, 0x869A, 0xB10F, 0x869B, 0xB110, 0xB3CE, 0xB111, 0x869C, 0xB112, 0xB3CF, 0xB113, 0xB3D0, 0xB114, 0x869D, 0xB115, 0x869E, 0xB116, 0x869F, 0xB117, 0x86A0, 0xB118, 0xB3D1, 0xB119, 0xB3D2, 0xB11A, 0x86A1, 0xB11B, 0xB3D3, 0xB11C, 0xB3D4, 0xB11D, 0xB3D5, 0xB11E, 0x86A2, 0xB11F, 0x86A3, 0xB120, 0x86A4, 0xB121, 0x86A5, 0xB122, 0x86A6, 0xB123, 0xB3D6, 0xB124, 0xB3D7, 0xB125, 0xB3D8, 0xB126, 0x86A7, 0xB127, 0x86A8, 0xB128, 0xB3D9, 0xB129, 0x86A9, 0xB12A, 0x86AA, 0xB12B, 0x86AB, 0xB12C, 0xB3DA, 0xB12D, 0x86AC, 0xB12E, 0x86AD, 0xB12F, 0x86AE, 0xB130, 0x86AF, 0xB131, 0x86B0, 0xB132, 0x86B1, 0xB133, 0x86B2, 0xB134, 0xB3DB, 0xB135, 0xB3DC, 0xB136, 0x86B3, 0xB137, 0xB3DD, 0xB138, 0xB3DE, 0xB139, 0xB3DF, 0xB13A, 0x86B4, 0xB13B, 0x86B5, 0xB13C, 0x86B6, 0xB13D, 0x86B7, 0xB13E, 0x86B8, 0xB13F, 0x86B9, 0xB140, 0xB3E0, 0xB141, 0xB3E1, 0xB142, 0x86BA, 0xB143, 0x86BB, 0xB144, 0xB3E2, 0xB145, 0x86BC, 0xB146, 0x86BD, 0xB147, 0x86BE, 0xB148, 0xB3E3, 0xB149, 0x86BF, 0xB14A, 0x86C0, 0xB14B, 0x86C1, 0xB14C, 0x86C2, 0xB14D, 0x86C3, 0xB14E, 0x86C4, 0xB14F, 0x86C5, 0xB150, 0xB3E4, 0xB151, 0xB3E5, 0xB152, 0x86C6, 0xB153, 0x86C7, 0xB154, 0xB3E6, 0xB155, 0xB3E7, 0xB156, 0x86C8, 0xB157, 0x86C9, 0xB158, 0xB3E8, 0xB159, 0x86CA, 0xB15A, 0x86CB, 0xB15B, 0x86CC, 0xB15C, 0xB3E9, 0xB15D, 0x86CD, 0xB15E, 0x86CE, 0xB15F, 0x86CF, 0xB160, 0xB3EA, 0xB161, 0x86D0, 0xB162, 0x86D1, 0xB163, 0x86D2, 0xB164, 0x86D3, 0xB165, 0x86D4, 0xB166, 0x86D5, 0xB167, 0x86D6, 0xB168, 0x86D7, 0xB169, 0x86D8, 0xB16A, 0x86D9, 0xB16B, 0x86DA, 0xB16C, 0x86DB, 0xB16D, 0x86DC, 0xB16E, 0x86DD, 0xB16F, 0x86DE, 0xB170, 0x86DF, 0xB171, 0x86E0, 0xB172, 0x86E1, 0xB173, 0x86E2, 0xB174, 0x86E3, 0xB175, 0x86E4, 0xB176, 0x86E5, 0xB177, 0x86E6, 0xB178, 0xB3EB, 0xB179, 0xB3EC, 0xB17A, 0x86E7, 0xB17B, 0x86E8, 0xB17C, 0xB3ED, 0xB17D, 0x86E9, 0xB17E, 0x86EA, 0xB17F, 0x86EB, 0xB180, 0xB3EE, 0xB181, 0x86EC, 0xB182, 0xB3EF, 0xB183, 0x86ED, 0xB184, 0x86EE, 0xB185, 0x86EF, 0xB186, 0x86F0, 0xB187, 0x86F1, 0xB188, 0xB3F0, 0xB189, 0xB3F1, 0xB18A, 0x86F2, 0xB18B, 0xB3F2, 0xB18C, 0x86F3, 0xB18D, 0xB3F3, 0xB18E, 0x86F4, 0xB18F, 0x86F5, 0xB190, 0x86F6, 0xB191, 0x86F7, 0xB192, 0xB3F4, 0xB193, 0xB3F5, 0xB194, 0xB3F6, 0xB195, 0x86F8, 0xB196, 0x86F9, 0xB197, 0x86FA, 0xB198, 0xB3F7, 0xB199, 0x86FB, 0xB19A, 0x86FC, 0xB19B, 0x86FD, 0xB19C, 0xB3F8, 0xB19D, 0x86FE, 0xB19E, 0x8741, 0xB19F, 0x8742, 0xB1A0, 0x8743, 0xB1A1, 0x8744, 0xB1A2, 0x8745, 0xB1A3, 0x8746, 0xB1A4, 0x8747, 0xB1A5, 0x8748, 0xB1A6, 0x8749, 0xB1A7, 0x874A, 0xB1A8, 0xB3F9, 0xB1A9, 0x874B, 0xB1AA, 0x874C, 0xB1AB, 0x874D, 0xB1AC, 0x874E, 0xB1AD, 0x874F, 0xB1AE, 0x8750, 0xB1AF, 0x8751, 0xB1B0, 0x8752, 0xB1B1, 0x8753, 0xB1B2, 0x8754, 0xB1B3, 0x8755, 0xB1B4, 0x8756, 0xB1B5, 0x8757, 0xB1B6, 0x8758, 0xB1B7, 0x8759, 0xB1B8, 0x875A, 0xB1B9, 0x8761, 0xB1BA, 0x8762, 0xB1BB, 0x8763, 0xB1BC, 0x8764, 0xB1BD, 0x8765, 0xB1BE, 0x8766, 0xB1BF, 0x8767, 0xB1C0, 0x8768, 0xB1C1, 0x8769, 0xB1C2, 0x876A, 0xB1C3, 0x876B, 0xB1C4, 0x876C, 0xB1C5, 0x876D, 0xB1C6, 0x876E, 0xB1C7, 0x876F, 0xB1C8, 0x8770, 0xB1C9, 0x8771, 0xB1CA, 0x8772, 0xB1CB, 0x8773, 0xB1CC, 0xB3FA, 0xB1CD, 0x8774, 0xB1CE, 0x8775, 0xB1CF, 0x8776, 0xB1D0, 0xB3FB, 0xB1D1, 0x8777, 0xB1D2, 0x8778, 0xB1D3, 0x8779, 0xB1D4, 0xB3FC, 0xB1D5, 0x877A, 0xB1D6, 0x8781, 0xB1D7, 0x8782, 0xB1D8, 0x8783, 0xB1D9, 0x8784, 0xB1DA, 0x8785, 0xB1DB, 0x8786, 0xB1DC, 0xB3FD, 0xB1DD, 0xB3FE, 0xB1DE, 0x8787, 0xB1DF, 0xB4A1, 0xB1E0, 0x8788, 0xB1E1, 0x8789, 0xB1E2, 0x878A, 0xB1E3, 0x878B, 0xB1E4, 0x878C, 0xB1E5, 0x878D, 0xB1E6, 0x878E, 0xB1E7, 0x878F, 0xB1E8, 0xB4A2, 0xB1E9, 0xB4A3, 0xB1EA, 0x8790, 0xB1EB, 0x8791, 0xB1EC, 0xB4A4, 0xB1ED, 0x8792, 0xB1EE, 0x8793, 0xB1EF, 0x8794, 0xB1F0, 0xB4A5, 0xB1F1, 0x8795, 0xB1F2, 0x8796, 0xB1F3, 0x8797, 0xB1F4, 0x8798, 0xB1F5, 0x8799, 0xB1F6, 0x879A, 0xB1F7, 0x879B, 0xB1F8, 0x879C, 0xB1F9, 0xB4A6, 0xB1FA, 0x879D, 0xB1FB, 0xB4A7, 0xB1FC, 0x879E, 0xB1FD, 0xB4A8, 0xB1FE, 0x879F, 0xB1FF, 0x87A0, 0xB200, 0x87A1, 0xB201, 0x87A2, 0xB202, 0x87A3, 0xB203, 0x87A4, 0xB204, 0xB4A9, 0xB205, 0xB4AA, 0xB206, 0x87A5, 0xB207, 0x87A6, 0xB208, 0xB4AB, 0xB209, 0x87A7, 0xB20A, 0x87A8, 0xB20B, 0xB4AC, 0xB20C, 0xB4AD, 0xB20D, 0x87A9, 0xB20E, 0x87AA, 0xB20F, 0x87AB, 0xB210, 0x87AC, 0xB211, 0x87AD, 0xB212, 0x87AE, 0xB213, 0x87AF, 0xB214, 0xB4AE, 0xB215, 0xB4AF, 0xB216, 0x87B0, 0xB217, 0xB4B0, 0xB218, 0x87B1, 0xB219, 0xB4B1, 0xB21A, 0x87B2, 0xB21B, 0x87B3, 0xB21C, 0x87B4, 0xB21D, 0x87B5, 0xB21E, 0x87B6, 0xB21F, 0x87B7, 0xB220, 0xB4B2, 0xB221, 0x87B8, 0xB222, 0x87B9, 0xB223, 0x87BA, 0xB224, 0x87BB, 0xB225, 0x87BC, 0xB226, 0x87BD, 0xB227, 0x87BE, 0xB228, 0x87BF, 0xB229, 0x87C0, 0xB22A, 0x87C1, 0xB22B, 0x87C2, 0xB22C, 0x87C3, 0xB22D, 0x87C4, 0xB22E, 0x87C5, 0xB22F, 0x87C6, 0xB230, 0x87C7, 0xB231, 0x87C8, 0xB232, 0x87C9, 0xB233, 0x87CA, 0xB234, 0xB4B3, 0xB235, 0x87CB, 0xB236, 0x87CC, 0xB237, 0x87CD, 0xB238, 0x87CE, 0xB239, 0x87CF, 0xB23A, 0x87D0, 0xB23B, 0x87D1, 0xB23C, 0xB4B4, 0xB23D, 0x87D2, 0xB23E, 0x87D3, 0xB23F, 0x87D4, 0xB240, 0x87D5, 0xB241, 0x87D6, 0xB242, 0x87D7, 0xB243, 0x87D8, 0xB244, 0x87D9, 0xB245, 0x87DA, 0xB246, 0x87DB, 0xB247, 0x87DC, 0xB248, 0x87DD, 0xB249, 0x87DE, 0xB24A, 0x87DF, 0xB24B, 0x87E0, 0xB24C, 0x87E1, 0xB24D, 0x87E2, 0xB24E, 0x87E3, 0xB24F, 0x87E4, 0xB250, 0x87E5, 0xB251, 0x87E6, 0xB252, 0x87E7, 0xB253, 0x87E8, 0xB254, 0x87E9, 0xB255, 0x87EA, 0xB256, 0x87EB, 0xB257, 0x87EC, 0xB258, 0xB4B5, 0xB259, 0x87ED, 0xB25A, 0x87EE, 0xB25B, 0x87EF, 0xB25C, 0xB4B6, 0xB25D, 0x87F0, 0xB25E, 0x87F1, 0xB25F, 0x87F2, 0xB260, 0xB4B7, 0xB261, 0x87F3, 0xB262, 0x87F4, 0xB263, 0x87F5, 0xB264, 0x87F6, 0xB265, 0x87F7, 0xB266, 0x87F8, 0xB267, 0x87F9, 0xB268, 0xB4B8, 0xB269, 0xB4B9, 0xB26A, 0x87FA, 0xB26B, 0x87FB, 0xB26C, 0x87FC, 0xB26D, 0x87FD, 0xB26E, 0x87FE, 0xB26F, 0x8841, 0xB270, 0x8842, 0xB271, 0x8843, 0xB272, 0x8844, 0xB273, 0x8845, 0xB274, 0xB4BA, 0xB275, 0xB4BB, 0xB276, 0x8846, 0xB277, 0x8847, 0xB278, 0x8848, 0xB279, 0x8849, 0xB27A, 0x884A, 0xB27B, 0x884B, 0xB27C, 0xB4BC, 0xB27D, 0x884C, 0xB27E, 0x884D, 0xB27F, 0x884E, 0xB280, 0x884F, 0xB281, 0x8850, 0xB282, 0x8851, 0xB283, 0x8852, 0xB284, 0xB4BD, 0xB285, 0xB4BE, 0xB286, 0x8853, 0xB287, 0x8854, 0xB288, 0x8855, 0xB289, 0xB4BF, 0xB28A, 0x8856, 0xB28B, 0x8857, 0xB28C, 0x8858, 0xB28D, 0x8859, 0xB28E, 0x885A, 0xB28F, 0x8861, 0xB290, 0xB4C0, 0xB291, 0xB4C1, 0xB292, 0x8862, 0xB293, 0x8863, 0xB294, 0xB4C2, 0xB295, 0x8864, 0xB296, 0x8865, 0xB297, 0x8866, 0xB298, 0xB4C3, 0xB299, 0xB4C4, 0xB29A, 0xB4C5, 0xB29B, 0x8867, 0xB29C, 0x8868, 0xB29D, 0x8869, 0xB29E, 0x886A, 0xB29F, 0x886B, 0xB2A0, 0xB4C6, 0xB2A1, 0xB4C7, 0xB2A2, 0x886C, 0xB2A3, 0xB4C8, 0xB2A4, 0x886D, 0xB2A5, 0xB4C9, 0xB2A6, 0xB4CA, 0xB2A7, 0x886E, 0xB2A8, 0x886F, 0xB2A9, 0x8870, 0xB2AA, 0xB4CB, 0xB2AB, 0x8871, 0xB2AC, 0xB4CC, 0xB2AD, 0x8872, 0xB2AE, 0x8873, 0xB2AF, 0x8874, 0xB2B0, 0xB4CD, 0xB2B1, 0x8875, 0xB2B2, 0x8876, 0xB2B3, 0x8877, 0xB2B4, 0xB4CE, 0xB2B5, 0x8878, 0xB2B6, 0x8879, 0xB2B7, 0x887A, 0xB2B8, 0x8881, 0xB2B9, 0x8882, 0xB2BA, 0x8883, 0xB2BB, 0x8884, 0xB2BC, 0x8885, 0xB2BD, 0x8886, 0xB2BE, 0x8887, 0xB2BF, 0x8888, 0xB2C0, 0x8889, 0xB2C1, 0x888A, 0xB2C2, 0x888B, 0xB2C3, 0x888C, 0xB2C4, 0x888D, 0xB2C5, 0x888E, 0xB2C6, 0x888F, 0xB2C7, 0x8890, 0xB2C8, 0xB4CF, 0xB2C9, 0xB4D0, 0xB2CA, 0x8891, 0xB2CB, 0x8892, 0xB2CC, 0xB4D1, 0xB2CD, 0x8893, 0xB2CE, 0x8894, 0xB2CF, 0x8895, 0xB2D0, 0xB4D2, 0xB2D1, 0x8896, 0xB2D2, 0xB4D3, 0xB2D3, 0x8897, 0xB2D4, 0x8898, 0xB2D5, 0x8899, 0xB2D6, 0x889A, 0xB2D7, 0x889B, 0xB2D8, 0xB4D4, 0xB2D9, 0xB4D5, 0xB2DA, 0x889C, 0xB2DB, 0xB4D6, 0xB2DC, 0x889D, 0xB2DD, 0xB4D7, 0xB2DE, 0x889E, 0xB2DF, 0x889F, 0xB2E0, 0x88A0, 0xB2E1, 0x88A1, 0xB2E2, 0xB4D8, 0xB2E3, 0x88A2, 0xB2E4, 0xB4D9, 0xB2E5, 0xB4DA, 0xB2E6, 0xB4DB, 0xB2E7, 0x88A3, 0xB2E8, 0xB4DC, 0xB2E9, 0x88A4, 0xB2EA, 0x88A5, 0xB2EB, 0xB4DD, 0xB2EC, 0xB4DE, 0xB2ED, 0xB4DF, 0xB2EE, 0xB4E0, 0xB2EF, 0xB4E1, 0xB2F0, 0x88A6, 0xB2F1, 0x88A7, 0xB2F2, 0x88A8, 0xB2F3, 0xB4E2, 0xB2F4, 0xB4E3, 0xB2F5, 0xB4E4, 0xB2F6, 0x88A9, 0xB2F7, 0xB4E5, 0xB2F8, 0xB4E6, 0xB2F9, 0xB4E7, 0xB2FA, 0xB4E8, 0xB2FB, 0xB4E9, 0xB2FC, 0x88AA, 0xB2FD, 0x88AB, 0xB2FE, 0x88AC, 0xB2FF, 0xB4EA, 0xB300, 0xB4EB, 0xB301, 0xB4EC, 0xB302, 0x88AD, 0xB303, 0x88AE, 0xB304, 0xB4ED, 0xB305, 0x88AF, 0xB306, 0x88B0, 0xB307, 0x88B1, 0xB308, 0xB4EE, 0xB309, 0x88B2, 0xB30A, 0x88B3, 0xB30B, 0x88B4, 0xB30C, 0x88B5, 0xB30D, 0x88B6, 0xB30E, 0x88B7, 0xB30F, 0x88B8, 0xB310, 0xB4EF, 0xB311, 0xB4F0, 0xB312, 0x88B9, 0xB313, 0xB4F1, 0xB314, 0xB4F2, 0xB315, 0xB4F3, 0xB316, 0x88BA, 0xB317, 0x88BB, 0xB318, 0x88BC, 0xB319, 0x88BD, 0xB31A, 0x88BE, 0xB31B, 0x88BF, 0xB31C, 0xB4F4, 0xB31D, 0x88C0, 0xB31E, 0x88C1, 0xB31F, 0x88C2, 0xB320, 0x88C3, 0xB321, 0x88C4, 0xB322, 0x88C5, 0xB323, 0x88C6, 0xB324, 0x88C7, 0xB325, 0x88C8, 0xB326, 0x88C9, 0xB327, 0x88CA, 0xB328, 0x88CB, 0xB329, 0x88CC, 0xB32A, 0x88CD, 0xB32B, 0x88CE, 0xB32C, 0x88CF, 0xB32D, 0x88D0, 0xB32E, 0x88D1, 0xB32F, 0x88D2, 0xB330, 0x88D3, 0xB331, 0x88D4, 0xB332, 0x88D5, 0xB333, 0x88D6, 0xB334, 0x88D7, 0xB335, 0x88D8, 0xB336, 0x88D9, 0xB337, 0x88DA, 0xB338, 0x88DB, 0xB339, 0x88DC, 0xB33A, 0x88DD, 0xB33B, 0x88DE, 0xB33C, 0x88DF, 0xB33D, 0x88E0, 0xB33E, 0x88E1, 0xB33F, 0x88E2, 0xB340, 0x88E3, 0xB341, 0x88E4, 0xB342, 0x88E5, 0xB343, 0x88E6, 0xB344, 0x88E7, 0xB345, 0x88E8, 0xB346, 0x88E9, 0xB347, 0x88EA, 0xB348, 0x88EB, 0xB349, 0x88EC, 0xB34A, 0x88ED, 0xB34B, 0x88EE, 0xB34C, 0x88EF, 0xB34D, 0x88F0, 0xB34E, 0x88F1, 0xB34F, 0x88F2, 0xB350, 0x88F3, 0xB351, 0x88F4, 0xB352, 0x88F5, 0xB353, 0x88F6, 0xB354, 0xB4F5, 0xB355, 0xB4F6, 0xB356, 0xB4F7, 0xB357, 0x88F7, 0xB358, 0xB4F8, 0xB359, 0x88F8, 0xB35A, 0x88F9, 0xB35B, 0xB4F9, 0xB35C, 0xB4FA, 0xB35D, 0x88FA, 0xB35E, 0xB4FB, 0xB35F, 0xB4FC, 0xB360, 0x88FB, 0xB361, 0x88FC, 0xB362, 0x88FD, 0xB363, 0x88FE, 0xB364, 0xB4FD, 0xB365, 0xB4FE, 0xB366, 0x8941, 0xB367, 0xB5A1, 0xB368, 0x8942, 0xB369, 0xB5A2, 0xB36A, 0x8943, 0xB36B, 0xB5A3, 0xB36C, 0x8944, 0xB36D, 0x8945, 0xB36E, 0xB5A4, 0xB36F, 0x8946, 0xB370, 0xB5A5, 0xB371, 0xB5A6, 0xB372, 0x8947, 0xB373, 0x8948, 0xB374, 0xB5A7, 0xB375, 0x8949, 0xB376, 0x894A, 0xB377, 0x894B, 0xB378, 0xB5A8, 0xB379, 0x894C, 0xB37A, 0x894D, 0xB37B, 0x894E, 0xB37C, 0x894F, 0xB37D, 0x8950, 0xB37E, 0x8951, 0xB37F, 0x8952, 0xB380, 0xB5A9, 0xB381, 0xB5AA, 0xB382, 0x8953, 0xB383, 0xB5AB, 0xB384, 0xB5AC, 0xB385, 0xB5AD, 0xB386, 0x8954, 0xB387, 0x8955, 0xB388, 0x8956, 0xB389, 0x8957, 0xB38A, 0x8958, 0xB38B, 0x8959, 0xB38C, 0xB5AE, 0xB38D, 0x895A, 0xB38E, 0x8961, 0xB38F, 0x8962, 0xB390, 0xB5AF, 0xB391, 0x8963, 0xB392, 0x8964, 0xB393, 0x8965, 0xB394, 0xB5B0, 0xB395, 0x8966, 0xB396, 0x8967, 0xB397, 0x8968, 0xB398, 0x8969, 0xB399, 0x896A, 0xB39A, 0x896B, 0xB39B, 0x896C, 0xB39C, 0x896D, 0xB39D, 0x896E, 0xB39E, 0x896F, 0xB39F, 0x8970, 0xB3A0, 0xB5B1, 0xB3A1, 0xB5B2, 0xB3A2, 0x8971, 0xB3A3, 0x8972, 0xB3A4, 0x8973, 0xB3A5, 0x8974, 0xB3A6, 0x8975, 0xB3A7, 0x8976, 0xB3A8, 0xB5B3, 0xB3A9, 0x8977, 0xB3AA, 0x8978, 0xB3AB, 0x8979, 0xB3AC, 0xB5B4, 0xB3AD, 0x897A, 0xB3AE, 0x8981, 0xB3AF, 0x8982, 0xB3B0, 0x8983, 0xB3B1, 0x8984, 0xB3B2, 0x8985, 0xB3B3, 0x8986, 0xB3B4, 0x8987, 0xB3B5, 0x8988, 0xB3B6, 0x8989, 0xB3B7, 0x898A, 0xB3B8, 0x898B, 0xB3B9, 0x898C, 0xB3BA, 0x898D, 0xB3BB, 0x898E, 0xB3BC, 0x898F, 0xB3BD, 0x8990, 0xB3BE, 0x8991, 0xB3BF, 0x8992, 0xB3C0, 0x8993, 0xB3C1, 0x8994, 0xB3C2, 0x8995, 0xB3C3, 0x8996, 0xB3C4, 0xB5B5, 0xB3C5, 0xB5B6, 0xB3C6, 0x8997, 0xB3C7, 0x8998, 0xB3C8, 0xB5B7, 0xB3C9, 0x8999, 0xB3CA, 0x899A, 0xB3CB, 0xB5B8, 0xB3CC, 0xB5B9, 0xB3CD, 0x899B, 0xB3CE, 0xB5BA, 0xB3CF, 0x899C, 0xB3D0, 0xB5BB, 0xB3D1, 0x899D, 0xB3D2, 0x899E, 0xB3D3, 0x899F, 0xB3D4, 0xB5BC, 0xB3D5, 0xB5BD, 0xB3D6, 0x89A0, 0xB3D7, 0xB5BE, 0xB3D8, 0x89A1, 0xB3D9, 0xB5BF, 0xB3DA, 0x89A2, 0xB3DB, 0xB5C0, 0xB3DC, 0x89A3, 0xB3DD, 0xB5C1, 0xB3DE, 0x89A4, 0xB3DF, 0x89A5, 0xB3E0, 0xB5C2, 0xB3E1, 0x89A6, 0xB3E2, 0x89A7, 0xB3E3, 0x89A8, 0xB3E4, 0xB5C3, 0xB3E5, 0x89A9, 0xB3E6, 0x89AA, 0xB3E7, 0x89AB, 0xB3E8, 0xB5C4, 0xB3E9, 0x89AC, 0xB3EA, 0x89AD, 0xB3EB, 0x89AE, 0xB3EC, 0x89AF, 0xB3ED, 0x89B0, 0xB3EE, 0x89B1, 0xB3EF, 0x89B2, 0xB3F0, 0x89B3, 0xB3F1, 0x89B4, 0xB3F2, 0x89B5, 0xB3F3, 0x89B6, 0xB3F4, 0x89B7, 0xB3F5, 0x89B8, 0xB3F6, 0x89B9, 0xB3F7, 0x89BA, 0xB3F8, 0x89BB, 0xB3F9, 0x89BC, 0xB3FA, 0x89BD, 0xB3FB, 0x89BE, 0xB3FC, 0xB5C5, 0xB3FD, 0x89BF, 0xB3FE, 0x89C0, 0xB3FF, 0x89C1, 0xB400, 0x89C2, 0xB401, 0x89C3, 0xB402, 0x89C4, 0xB403, 0x89C5, 0xB404, 0x89C6, 0xB405, 0x89C7, 0xB406, 0x89C8, 0xB407, 0x89C9, 0xB408, 0x89CA, 0xB409, 0x89CB, 0xB40A, 0x89CC, 0xB40B, 0x89CD, 0xB40C, 0x89CE, 0xB40D, 0x89CF, 0xB40E, 0x89D0, 0xB40F, 0x89D1, 0xB410, 0xB5C6, 0xB411, 0x89D2, 0xB412, 0x89D3, 0xB413, 0x89D4, 0xB414, 0x89D5, 0xB415, 0x89D6, 0xB416, 0x89D7, 0xB417, 0x89D8, 0xB418, 0xB5C7, 0xB419, 0x89D9, 0xB41A, 0x89DA, 0xB41B, 0x89DB, 0xB41C, 0xB5C8, 0xB41D, 0x89DC, 0xB41E, 0x89DD, 0xB41F, 0x89DE, 0xB420, 0xB5C9, 0xB421, 0x89DF, 0xB422, 0x89E0, 0xB423, 0x89E1, 0xB424, 0x89E2, 0xB425, 0x89E3, 0xB426, 0x89E4, 0xB427, 0x89E5, 0xB428, 0xB5CA, 0xB429, 0xB5CB, 0xB42A, 0x89E6, 0xB42B, 0xB5CC, 0xB42C, 0x89E7, 0xB42D, 0x89E8, 0xB42E, 0x89E9, 0xB42F, 0x89EA, 0xB430, 0x89EB, 0xB431, 0x89EC, 0xB432, 0x89ED, 0xB433, 0x89EE, 0xB434, 0xB5CD, 0xB435, 0x89EF, 0xB436, 0x89F0, 0xB437, 0x89F1, 0xB438, 0x89F2, 0xB439, 0x89F3, 0xB43A, 0x89F4, 0xB43B, 0x89F5, 0xB43C, 0x89F6, 0xB43D, 0x89F7, 0xB43E, 0x89F8, 0xB43F, 0x89F9, 0xB440, 0x89FA, 0xB441, 0x89FB, 0xB442, 0x89FC, 0xB443, 0x89FD, 0xB444, 0x89FE, 0xB445, 0x8A41, 0xB446, 0x8A42, 0xB447, 0x8A43, 0xB448, 0x8A44, 0xB449, 0x8A45, 0xB44A, 0x8A46, 0xB44B, 0x8A47, 0xB44C, 0x8A48, 0xB44D, 0x8A49, 0xB44E, 0x8A4A, 0xB44F, 0x8A4B, 0xB450, 0xB5CE, 0xB451, 0xB5CF, 0xB452, 0x8A4C, 0xB453, 0x8A4D, 0xB454, 0xB5D0, 0xB455, 0x8A4E, 0xB456, 0x8A4F, 0xB457, 0x8A50, 0xB458, 0xB5D1, 0xB459, 0x8A51, 0xB45A, 0x8A52, 0xB45B, 0x8A53, 0xB45C, 0x8A54, 0xB45D, 0x8A55, 0xB45E, 0x8A56, 0xB45F, 0x8A57, 0xB460, 0xB5D2, 0xB461, 0xB5D3, 0xB462, 0x8A58, 0xB463, 0xB5D4, 0xB464, 0x8A59, 0xB465, 0xB5D5, 0xB466, 0x8A5A, 0xB467, 0x8A61, 0xB468, 0x8A62, 0xB469, 0x8A63, 0xB46A, 0x8A64, 0xB46B, 0x8A65, 0xB46C, 0xB5D6, 0xB46D, 0x8A66, 0xB46E, 0x8A67, 0xB46F, 0x8A68, 0xB470, 0x8A69, 0xB471, 0x8A6A, 0xB472, 0x8A6B, 0xB473, 0x8A6C, 0xB474, 0x8A6D, 0xB475, 0x8A6E, 0xB476, 0x8A6F, 0xB477, 0x8A70, 0xB478, 0x8A71, 0xB479, 0x8A72, 0xB47A, 0x8A73, 0xB47B, 0x8A74, 0xB47C, 0x8A75, 0xB47D, 0x8A76, 0xB47E, 0x8A77, 0xB47F, 0x8A78, 0xB480, 0xB5D7, 0xB481, 0x8A79, 0xB482, 0x8A7A, 0xB483, 0x8A81, 0xB484, 0x8A82, 0xB485, 0x8A83, 0xB486, 0x8A84, 0xB487, 0x8A85, 0xB488, 0xB5D8, 0xB489, 0x8A86, 0xB48A, 0x8A87, 0xB48B, 0x8A88, 0xB48C, 0x8A89, 0xB48D, 0x8A8A, 0xB48E, 0x8A8B, 0xB48F, 0x8A8C, 0xB490, 0x8A8D, 0xB491, 0x8A8E, 0xB492, 0x8A8F, 0xB493, 0x8A90, 0xB494, 0x8A91, 0xB495, 0x8A92, 0xB496, 0x8A93, 0xB497, 0x8A94, 0xB498, 0x8A95, 0xB499, 0x8A96, 0xB49A, 0x8A97, 0xB49B, 0x8A98, 0xB49C, 0x8A99, 0xB49D, 0xB5D9, 0xB49E, 0x8A9A, 0xB49F, 0x8A9B, 0xB4A0, 0x8A9C, 0xB4A1, 0x8A9D, 0xB4A2, 0x8A9E, 0xB4A3, 0x8A9F, 0xB4A4, 0xB5DA, 0xB4A5, 0x8AA0, 0xB4A6, 0x8AA1, 0xB4A7, 0x8AA2, 0xB4A8, 0xB5DB, 0xB4A9, 0x8AA3, 0xB4AA, 0x8AA4, 0xB4AB, 0x8AA5, 0xB4AC, 0xB5DC, 0xB4AD, 0x8AA6, 0xB4AE, 0x8AA7, 0xB4AF, 0x8AA8, 0xB4B0, 0x8AA9, 0xB4B1, 0x8AAA, 0xB4B2, 0x8AAB, 0xB4B3, 0x8AAC, 0xB4B4, 0x8AAD, 0xB4B5, 0xB5DD, 0xB4B6, 0x8AAE, 0xB4B7, 0xB5DE, 0xB4B8, 0x8AAF, 0xB4B9, 0xB5DF, 0xB4BA, 0x8AB0, 0xB4BB, 0x8AB1, 0xB4BC, 0x8AB2, 0xB4BD, 0x8AB3, 0xB4BE, 0x8AB4, 0xB4BF, 0x8AB5, 0xB4C0, 0xB5E0, 0xB4C1, 0x8AB6, 0xB4C2, 0x8AB7, 0xB4C3, 0x8AB8, 0xB4C4, 0xB5E1, 0xB4C5, 0x8AB9, 0xB4C6, 0x8ABA, 0xB4C7, 0x8ABB, 0xB4C8, 0xB5E2, 0xB4C9, 0x8ABC, 0xB4CA, 0x8ABD, 0xB4CB, 0x8ABE, 0xB4CC, 0x8ABF, 0xB4CD, 0x8AC0, 0xB4CE, 0x8AC1, 0xB4CF, 0x8AC2, 0xB4D0, 0xB5E3, 0xB4D1, 0x8AC3, 0xB4D2, 0x8AC4, 0xB4D3, 0x8AC5, 0xB4D4, 0x8AC6, 0xB4D5, 0xB5E4, 0xB4D6, 0x8AC7, 0xB4D7, 0x8AC8, 0xB4D8, 0x8AC9, 0xB4D9, 0x8ACA, 0xB4DA, 0x8ACB, 0xB4DB, 0x8ACC, 0xB4DC, 0xB5E5, 0xB4DD, 0xB5E6, 0xB4DE, 0x8ACD, 0xB4DF, 0x8ACE, 0xB4E0, 0xB5E7, 0xB4E1, 0x8ACF, 0xB4E2, 0x8AD0, 0xB4E3, 0xB5E8, 0xB4E4, 0xB5E9, 0xB4E5, 0x8AD1, 0xB4E6, 0xB5EA, 0xB4E7, 0x8AD2, 0xB4E8, 0x8AD3, 0xB4E9, 0x8AD4, 0xB4EA, 0x8AD5, 0xB4EB, 0x8AD6, 0xB4EC, 0xB5EB, 0xB4ED, 0xB5EC, 0xB4EE, 0x8AD7, 0xB4EF, 0xB5ED, 0xB4F0, 0x8AD8, 0xB4F1, 0xB5EE, 0xB4F2, 0x8AD9, 0xB4F3, 0x8ADA, 0xB4F4, 0x8ADB, 0xB4F5, 0x8ADC, 0xB4F6, 0x8ADD, 0xB4F7, 0x8ADE, 0xB4F8, 0xB5EF, 0xB4F9, 0x8ADF, 0xB4FA, 0x8AE0, 0xB4FB, 0x8AE1, 0xB4FC, 0x8AE2, 0xB4FD, 0x8AE3, 0xB4FE, 0x8AE4, 0xB4FF, 0x8AE5, 0xB500, 0x8AE6, 0xB501, 0x8AE7, 0xB502, 0x8AE8, 0xB503, 0x8AE9, 0xB504, 0x8AEA, 0xB505, 0x8AEB, 0xB506, 0x8AEC, 0xB507, 0x8AED, 0xB508, 0x8AEE, 0xB509, 0x8AEF, 0xB50A, 0x8AF0, 0xB50B, 0x8AF1, 0xB50C, 0x8AF2, 0xB50D, 0x8AF3, 0xB50E, 0x8AF4, 0xB50F, 0x8AF5, 0xB510, 0x8AF6, 0xB511, 0x8AF7, 0xB512, 0x8AF8, 0xB513, 0x8AF9, 0xB514, 0xB5F0, 0xB515, 0xB5F1, 0xB516, 0x8AFA, 0xB517, 0x8AFB, 0xB518, 0xB5F2, 0xB519, 0x8AFC, 0xB51A, 0x8AFD, 0xB51B, 0xB5F3, 0xB51C, 0xB5F4, 0xB51D, 0x8AFE, 0xB51E, 0x8B41, 0xB51F, 0x8B42, 0xB520, 0x8B43, 0xB521, 0x8B44, 0xB522, 0x8B45, 0xB523, 0x8B46, 0xB524, 0xB5F5, 0xB525, 0xB5F6, 0xB526, 0x8B47, 0xB527, 0xB5F7, 0xB528, 0xB5F8, 0xB529, 0xB5F9, 0xB52A, 0xB5FA, 0xB52B, 0x8B48, 0xB52C, 0x8B49, 0xB52D, 0x8B4A, 0xB52E, 0x8B4B, 0xB52F, 0x8B4C, 0xB530, 0xB5FB, 0xB531, 0xB5FC, 0xB532, 0x8B4D, 0xB533, 0x8B4E, 0xB534, 0xB5FD, 0xB535, 0x8B4F, 0xB536, 0x8B50, 0xB537, 0x8B51, 0xB538, 0xB5FE, 0xB539, 0x8B52, 0xB53A, 0x8B53, 0xB53B, 0x8B54, 0xB53C, 0x8B55, 0xB53D, 0x8B56, 0xB53E, 0x8B57, 0xB53F, 0x8B58, 0xB540, 0xB6A1, 0xB541, 0xB6A2, 0xB542, 0x8B59, 0xB543, 0xB6A3, 0xB544, 0xB6A4, 0xB545, 0xB6A5, 0xB546, 0x8B5A, 0xB547, 0x8B61, 0xB548, 0x8B62, 0xB549, 0x8B63, 0xB54A, 0x8B64, 0xB54B, 0xB6A6, 0xB54C, 0xB6A7, 0xB54D, 0xB6A8, 0xB54E, 0x8B65, 0xB54F, 0x8B66, 0xB550, 0xB6A9, 0xB551, 0x8B67, 0xB552, 0x8B68, 0xB553, 0x8B69, 0xB554, 0xB6AA, 0xB555, 0x8B6A, 0xB556, 0x8B6B, 0xB557, 0x8B6C, 0xB558, 0x8B6D, 0xB559, 0x8B6E, 0xB55A, 0x8B6F, 0xB55B, 0x8B70, 0xB55C, 0xB6AB, 0xB55D, 0xB6AC, 0xB55E, 0x8B71, 0xB55F, 0xB6AD, 0xB560, 0xB6AE, 0xB561, 0xB6AF, 0xB562, 0x8B72, 0xB563, 0x8B73, 0xB564, 0x8B74, 0xB565, 0x8B75, 0xB566, 0x8B76, 0xB567, 0x8B77, 0xB568, 0x8B78, 0xB569, 0x8B79, 0xB56A, 0x8B7A, 0xB56B, 0x8B81, 0xB56C, 0x8B82, 0xB56D, 0x8B83, 0xB56E, 0x8B84, 0xB56F, 0x8B85, 0xB570, 0x8B86, 0xB571, 0x8B87, 0xB572, 0x8B88, 0xB573, 0x8B89, 0xB574, 0x8B8A, 0xB575, 0x8B8B, 0xB576, 0x8B8C, 0xB577, 0x8B8D, 0xB578, 0x8B8E, 0xB579, 0x8B8F, 0xB57A, 0x8B90, 0xB57B, 0x8B91, 0xB57C, 0x8B92, 0xB57D, 0x8B93, 0xB57E, 0x8B94, 0xB57F, 0x8B95, 0xB580, 0x8B96, 0xB581, 0x8B97, 0xB582, 0x8B98, 0xB583, 0x8B99, 0xB584, 0x8B9A, 0xB585, 0x8B9B, 0xB586, 0x8B9C, 0xB587, 0x8B9D, 0xB588, 0x8B9E, 0xB589, 0x8B9F, 0xB58A, 0x8BA0, 0xB58B, 0x8BA1, 0xB58C, 0x8BA2, 0xB58D, 0x8BA3, 0xB58E, 0x8BA4, 0xB58F, 0x8BA5, 0xB590, 0x8BA6, 0xB591, 0x8BA7, 0xB592, 0x8BA8, 0xB593, 0x8BA9, 0xB594, 0x8BAA, 0xB595, 0x8BAB, 0xB596, 0x8BAC, 0xB597, 0x8BAD, 0xB598, 0x8BAE, 0xB599, 0x8BAF, 0xB59A, 0x8BB0, 0xB59B, 0x8BB1, 0xB59C, 0x8BB2, 0xB59D, 0x8BB3, 0xB59E, 0x8BB4, 0xB59F, 0x8BB5, 0xB5A0, 0xB6B0, 0xB5A1, 0xB6B1, 0xB5A2, 0x8BB6, 0xB5A3, 0x8BB7, 0xB5A4, 0xB6B2, 0xB5A5, 0x8BB8, 0xB5A6, 0x8BB9, 0xB5A7, 0x8BBA, 0xB5A8, 0xB6B3, 0xB5A9, 0x8BBB, 0xB5AA, 0xB6B4, 0xB5AB, 0xB6B5, 0xB5AC, 0x8BBC, 0xB5AD, 0x8BBD, 0xB5AE, 0x8BBE, 0xB5AF, 0x8BBF, 0xB5B0, 0xB6B6, 0xB5B1, 0xB6B7, 0xB5B2, 0x8BC0, 0xB5B3, 0xB6B8, 0xB5B4, 0xB6B9, 0xB5B5, 0xB6BA, 0xB5B6, 0x8BC1, 0xB5B7, 0x8BC2, 0xB5B8, 0x8BC3, 0xB5B9, 0x8BC4, 0xB5BA, 0x8BC5, 0xB5BB, 0xB6BB, 0xB5BC, 0xB6BC, 0xB5BD, 0xB6BD, 0xB5BE, 0x8BC6, 0xB5BF, 0x8BC7, 0xB5C0, 0xB6BE, 0xB5C1, 0x8BC8, 0xB5C2, 0x8BC9, 0xB5C3, 0x8BCA, 0xB5C4, 0xB6BF, 0xB5C5, 0x8BCB, 0xB5C6, 0x8BCC, 0xB5C7, 0x8BCD, 0xB5C8, 0x8BCE, 0xB5C9, 0x8BCF, 0xB5CA, 0x8BD0, 0xB5CB, 0x8BD1, 0xB5CC, 0xB6C0, 0xB5CD, 0xB6C1, 0xB5CE, 0x8BD2, 0xB5CF, 0xB6C2, 0xB5D0, 0xB6C3, 0xB5D1, 0xB6C4, 0xB5D2, 0x8BD3, 0xB5D3, 0x8BD4, 0xB5D4, 0x8BD5, 0xB5D5, 0x8BD6, 0xB5D6, 0x8BD7, 0xB5D7, 0x8BD8, 0xB5D8, 0xB6C5, 0xB5D9, 0x8BD9, 0xB5DA, 0x8BDA, 0xB5DB, 0x8BDB, 0xB5DC, 0x8BDC, 0xB5DD, 0x8BDD, 0xB5DE, 0x8BDE, 0xB5DF, 0x8BDF, 0xB5E0, 0x8BE0, 0xB5E1, 0x8BE1, 0xB5E2, 0x8BE2, 0xB5E3, 0x8BE3, 0xB5E4, 0x8BE4, 0xB5E5, 0x8BE5, 0xB5E6, 0x8BE6, 0xB5E7, 0x8BE7, 0xB5E8, 0x8BE8, 0xB5E9, 0x8BE9, 0xB5EA, 0x8BEA, 0xB5EB, 0x8BEB, 0xB5EC, 0xB6C6, 0xB5ED, 0x8BEC, 0xB5EE, 0x8BED, 0xB5EF, 0x8BEE, 0xB5F0, 0x8BEF, 0xB5F1, 0x8BF0, 0xB5F2, 0x8BF1, 0xB5F3, 0x8BF2, 0xB5F4, 0x8BF3, 0xB5F5, 0x8BF4, 0xB5F6, 0x8BF5, 0xB5F7, 0x8BF6, 0xB5F8, 0x8BF7, 0xB5F9, 0x8BF8, 0xB5FA, 0x8BF9, 0xB5FB, 0x8BFA, 0xB5FC, 0x8BFB, 0xB5FD, 0x8BFC, 0xB5FE, 0x8BFD, 0xB5FF, 0x8BFE, 0xB600, 0x8C41, 0xB601, 0x8C42, 0xB602, 0x8C43, 0xB603, 0x8C44, 0xB604, 0x8C45, 0xB605, 0x8C46, 0xB606, 0x8C47, 0xB607, 0x8C48, 0xB608, 0x8C49, 0xB609, 0x8C4A, 0xB60A, 0x8C4B, 0xB60B, 0x8C4C, 0xB60C, 0x8C4D, 0xB60D, 0x8C4E, 0xB60E, 0x8C4F, 0xB60F, 0x8C50, 0xB610, 0xB6C7, 0xB611, 0xB6C8, 0xB612, 0x8C51, 0xB613, 0x8C52, 0xB614, 0xB6C9, 0xB615, 0x8C53, 0xB616, 0x8C54, 0xB617, 0x8C55, 0xB618, 0xB6CA, 0xB619, 0x8C56, 0xB61A, 0x8C57, 0xB61B, 0x8C58, 0xB61C, 0x8C59, 0xB61D, 0x8C5A, 0xB61E, 0x8C61, 0xB61F, 0x8C62, 0xB620, 0x8C63, 0xB621, 0x8C64, 0xB622, 0x8C65, 0xB623, 0x8C66, 0xB624, 0x8C67, 0xB625, 0xB6CB, 0xB626, 0x8C68, 0xB627, 0x8C69, 0xB628, 0x8C6A, 0xB629, 0x8C6B, 0xB62A, 0x8C6C, 0xB62B, 0x8C6D, 0xB62C, 0xB6CC, 0xB62D, 0x8C6E, 0xB62E, 0x8C6F, 0xB62F, 0x8C70, 0xB630, 0x8C71, 0xB631, 0x8C72, 0xB632, 0x8C73, 0xB633, 0x8C74, 0xB634, 0xB6CD, 0xB635, 0x8C75, 0xB636, 0x8C76, 0xB637, 0x8C77, 0xB638, 0x8C78, 0xB639, 0x8C79, 0xB63A, 0x8C7A, 0xB63B, 0x8C81, 0xB63C, 0x8C82, 0xB63D, 0x8C83, 0xB63E, 0x8C84, 0xB63F, 0x8C85, 0xB640, 0x8C86, 0xB641, 0x8C87, 0xB642, 0x8C88, 0xB643, 0x8C89, 0xB644, 0x8C8A, 0xB645, 0x8C8B, 0xB646, 0x8C8C, 0xB647, 0x8C8D, 0xB648, 0xB6CE, 0xB649, 0x8C8E, 0xB64A, 0x8C8F, 0xB64B, 0x8C90, 0xB64C, 0x8C91, 0xB64D, 0x8C92, 0xB64E, 0x8C93, 0xB64F, 0x8C94, 0xB650, 0x8C95, 0xB651, 0x8C96, 0xB652, 0x8C97, 0xB653, 0x8C98, 0xB654, 0x8C99, 0xB655, 0x8C9A, 0xB656, 0x8C9B, 0xB657, 0x8C9C, 0xB658, 0x8C9D, 0xB659, 0x8C9E, 0xB65A, 0x8C9F, 0xB65B, 0x8CA0, 0xB65C, 0x8CA1, 0xB65D, 0x8CA2, 0xB65E, 0x8CA3, 0xB65F, 0x8CA4, 0xB660, 0x8CA5, 0xB661, 0x8CA6, 0xB662, 0x8CA7, 0xB663, 0x8CA8, 0xB664, 0xB6CF, 0xB665, 0x8CA9, 0xB666, 0x8CAA, 0xB667, 0x8CAB, 0xB668, 0xB6D0, 0xB669, 0x8CAC, 0xB66A, 0x8CAD, 0xB66B, 0x8CAE, 0xB66C, 0x8CAF, 0xB66D, 0x8CB0, 0xB66E, 0x8CB1, 0xB66F, 0x8CB2, 0xB670, 0x8CB3, 0xB671, 0x8CB4, 0xB672, 0x8CB5, 0xB673, 0x8CB6, 0xB674, 0x8CB7, 0xB675, 0x8CB8, 0xB676, 0x8CB9, 0xB677, 0x8CBA, 0xB678, 0x8CBB, 0xB679, 0x8CBC, 0xB67A, 0x8CBD, 0xB67B, 0x8CBE, 0xB67C, 0x8CBF, 0xB67D, 0x8CC0, 0xB67E, 0x8CC1, 0xB67F, 0x8CC2, 0xB680, 0x8CC3, 0xB681, 0x8CC4, 0xB682, 0x8CC5, 0xB683, 0x8CC6, 0xB684, 0x8CC7, 0xB685, 0x8CC8, 0xB686, 0x8CC9, 0xB687, 0x8CCA, 0xB688, 0x8CCB, 0xB689, 0x8CCC, 0xB68A, 0x8CCD, 0xB68B, 0x8CCE, 0xB68C, 0x8CCF, 0xB68D, 0x8CD0, 0xB68E, 0x8CD1, 0xB68F, 0x8CD2, 0xB690, 0x8CD3, 0xB691, 0x8CD4, 0xB692, 0x8CD5, 0xB693, 0x8CD6, 0xB694, 0x8CD7, 0xB695, 0x8CD8, 0xB696, 0x8CD9, 0xB697, 0x8CDA, 0xB698, 0x8CDB, 0xB699, 0x8CDC, 0xB69A, 0x8CDD, 0xB69B, 0x8CDE, 0xB69C, 0xB6D1, 0xB69D, 0xB6D2, 0xB69E, 0x8CDF, 0xB69F, 0x8CE0, 0xB6A0, 0xB6D3, 0xB6A1, 0x8CE1, 0xB6A2, 0x8CE2, 0xB6A3, 0x8CE3, 0xB6A4, 0xB6D4, 0xB6A5, 0x8CE4, 0xB6A6, 0x8CE5, 0xB6A7, 0x8CE6, 0xB6A8, 0x8CE7, 0xB6A9, 0x8CE8, 0xB6AA, 0x8CE9, 0xB6AB, 0xB6D5, 0xB6AC, 0xB6D6, 0xB6AD, 0x8CEA, 0xB6AE, 0x8CEB, 0xB6AF, 0x8CEC, 0xB6B0, 0x8CED, 0xB6B1, 0xB6D7, 0xB6B2, 0x8CEE, 0xB6B3, 0x8CEF, 0xB6B4, 0x8CF0, 0xB6B5, 0x8CF1, 0xB6B6, 0x8CF2, 0xB6B7, 0x8CF3, 0xB6B8, 0x8CF4, 0xB6B9, 0x8CF5, 0xB6BA, 0x8CF6, 0xB6BB, 0x8CF7, 0xB6BC, 0x8CF8, 0xB6BD, 0x8CF9, 0xB6BE, 0x8CFA, 0xB6BF, 0x8CFB, 0xB6C0, 0x8CFC, 0xB6C1, 0x8CFD, 0xB6C2, 0x8CFE, 0xB6C3, 0x8D41, 0xB6C4, 0x8D42, 0xB6C5, 0x8D43, 0xB6C6, 0x8D44, 0xB6C7, 0x8D45, 0xB6C8, 0x8D46, 0xB6C9, 0x8D47, 0xB6CA, 0x8D48, 0xB6CB, 0x8D49, 0xB6CC, 0x8D4A, 0xB6CD, 0x8D4B, 0xB6CE, 0x8D4C, 0xB6CF, 0x8D4D, 0xB6D0, 0x8D4E, 0xB6D1, 0x8D4F, 0xB6D2, 0x8D50, 0xB6D3, 0x8D51, 0xB6D4, 0xB6D8, 0xB6D5, 0x8D52, 0xB6D6, 0x8D53, 0xB6D7, 0x8D54, 0xB6D8, 0x8D55, 0xB6D9, 0x8D56, 0xB6DA, 0x8D57, 0xB6DB, 0x8D58, 0xB6DC, 0x8D59, 0xB6DD, 0x8D5A, 0xB6DE, 0x8D61, 0xB6DF, 0x8D62, 0xB6E0, 0x8D63, 0xB6E1, 0x8D64, 0xB6E2, 0x8D65, 0xB6E3, 0x8D66, 0xB6E4, 0x8D67, 0xB6E5, 0x8D68, 0xB6E6, 0x8D69, 0xB6E7, 0x8D6A, 0xB6E8, 0x8D6B, 0xB6E9, 0x8D6C, 0xB6EA, 0x8D6D, 0xB6EB, 0x8D6E, 0xB6EC, 0x8D6F, 0xB6ED, 0x8D70, 0xB6EE, 0x8D71, 0xB6EF, 0x8D72, 0xB6F0, 0xB6D9, 0xB6F1, 0x8D73, 0xB6F2, 0x8D74, 0xB6F3, 0x8D75, 0xB6F4, 0xB6DA, 0xB6F5, 0x8D76, 0xB6F6, 0x8D77, 0xB6F7, 0x8D78, 0xB6F8, 0xB6DB, 0xB6F9, 0x8D79, 0xB6FA, 0x8D7A, 0xB6FB, 0x8D81, 0xB6FC, 0x8D82, 0xB6FD, 0x8D83, 0xB6FE, 0x8D84, 0xB6FF, 0x8D85, 0xB700, 0xB6DC, 0xB701, 0xB6DD, 0xB702, 0x8D86, 0xB703, 0x8D87, 0xB704, 0x8D88, 0xB705, 0xB6DE, 0xB706, 0x8D89, 0xB707, 0x8D8A, 0xB708, 0x8D8B, 0xB709, 0x8D8C, 0xB70A, 0x8D8D, 0xB70B, 0x8D8E, 0xB70C, 0x8D8F, 0xB70D, 0x8D90, 0xB70E, 0x8D91, 0xB70F, 0x8D92, 0xB710, 0x8D93, 0xB711, 0x8D94, 0xB712, 0x8D95, 0xB713, 0x8D96, 0xB714, 0x8D97, 0xB715, 0x8D98, 0xB716, 0x8D99, 0xB717, 0x8D9A, 0xB718, 0x8D9B, 0xB719, 0x8D9C, 0xB71A, 0x8D9D, 0xB71B, 0x8D9E, 0xB71C, 0x8D9F, 0xB71D, 0x8DA0, 0xB71E, 0x8DA1, 0xB71F, 0x8DA2, 0xB720, 0x8DA3, 0xB721, 0x8DA4, 0xB722, 0x8DA5, 0xB723, 0x8DA6, 0xB724, 0x8DA7, 0xB725, 0x8DA8, 0xB726, 0x8DA9, 0xB727, 0x8DAA, 0xB728, 0xB6DF, 0xB729, 0xB6E0, 0xB72A, 0x8DAB, 0xB72B, 0x8DAC, 0xB72C, 0xB6E1, 0xB72D, 0x8DAD, 0xB72E, 0x8DAE, 0xB72F, 0xB6E2, 0xB730, 0xB6E3, 0xB731, 0x8DAF, 0xB732, 0x8DB0, 0xB733, 0x8DB1, 0xB734, 0x8DB2, 0xB735, 0x8DB3, 0xB736, 0x8DB4, 0xB737, 0x8DB5, 0xB738, 0xB6E4, 0xB739, 0xB6E5, 0xB73A, 0x8DB6, 0xB73B, 0xB6E6, 0xB73C, 0x8DB7, 0xB73D, 0x8DB8, 0xB73E, 0x8DB9, 0xB73F, 0x8DBA, 0xB740, 0x8DBB, 0xB741, 0x8DBC, 0xB742, 0x8DBD, 0xB743, 0x8DBE, 0xB744, 0xB6E7, 0xB745, 0x8DBF, 0xB746, 0x8DC0, 0xB747, 0x8DC1, 0xB748, 0xB6E8, 0xB749, 0x8DC2, 0xB74A, 0x8DC3, 0xB74B, 0x8DC4, 0xB74C, 0xB6E9, 0xB74D, 0x8DC5, 0xB74E, 0x8DC6, 0xB74F, 0x8DC7, 0xB750, 0x8DC8, 0xB751, 0x8DC9, 0xB752, 0x8DCA, 0xB753, 0x8DCB, 0xB754, 0xB6EA, 0xB755, 0xB6EB, 0xB756, 0x8DCC, 0xB757, 0x8DCD, 0xB758, 0x8DCE, 0xB759, 0x8DCF, 0xB75A, 0x8DD0, 0xB75B, 0x8DD1, 0xB75C, 0x8DD2, 0xB75D, 0x8DD3, 0xB75E, 0x8DD4, 0xB75F, 0x8DD5, 0xB760, 0xB6EC, 0xB761, 0x8DD6, 0xB762, 0x8DD7, 0xB763, 0x8DD8, 0xB764, 0xB6ED, 0xB765, 0x8DD9, 0xB766, 0x8DDA, 0xB767, 0x8DDB, 0xB768, 0xB6EE, 0xB769, 0x8DDC, 0xB76A, 0x8DDD, 0xB76B, 0x8DDE, 0xB76C, 0x8DDF, 0xB76D, 0x8DE0, 0xB76E, 0x8DE1, 0xB76F, 0x8DE2, 0xB770, 0xB6EF, 0xB771, 0xB6F0, 0xB772, 0x8DE3, 0xB773, 0xB6F1, 0xB774, 0x8DE4, 0xB775, 0xB6F2, 0xB776, 0x8DE5, 0xB777, 0x8DE6, 0xB778, 0x8DE7, 0xB779, 0x8DE8, 0xB77A, 0x8DE9, 0xB77B, 0x8DEA, 0xB77C, 0xB6F3, 0xB77D, 0xB6F4, 0xB77E, 0x8DEB, 0xB77F, 0x8DEC, 0xB780, 0xB6F5, 0xB781, 0x8DED, 0xB782, 0x8DEE, 0xB783, 0x8DEF, 0xB784, 0xB6F6, 0xB785, 0x8DF0, 0xB786, 0x8DF1, 0xB787, 0x8DF2, 0xB788, 0x8DF3, 0xB789, 0x8DF4, 0xB78A, 0x8DF5, 0xB78B, 0x8DF6, 0xB78C, 0xB6F7, 0xB78D, 0xB6F8, 0xB78E, 0x8DF7, 0xB78F, 0xB6F9, 0xB790, 0xB6FA, 0xB791, 0xB6FB, 0xB792, 0xB6FC, 0xB793, 0x8DF8, 0xB794, 0x8DF9, 0xB795, 0x8DFA, 0xB796, 0xB6FD, 0xB797, 0xB6FE, 0xB798, 0xB7A1, 0xB799, 0xB7A2, 0xB79A, 0x8DFB, 0xB79B, 0x8DFC, 0xB79C, 0xB7A3, 0xB79D, 0x8DFD, 0xB79E, 0x8DFE, 0xB79F, 0x8E41, 0xB7A0, 0xB7A4, 0xB7A1, 0x8E42, 0xB7A2, 0x8E43, 0xB7A3, 0x8E44, 0xB7A4, 0x8E45, 0xB7A5, 0x8E46, 0xB7A6, 0x8E47, 0xB7A7, 0x8E48, 0xB7A8, 0xB7A5, 0xB7A9, 0xB7A6, 0xB7AA, 0x8E49, 0xB7AB, 0xB7A7, 0xB7AC, 0xB7A8, 0xB7AD, 0xB7A9, 0xB7AE, 0x8E4A, 0xB7AF, 0x8E4B, 0xB7B0, 0x8E4C, 0xB7B1, 0x8E4D, 0xB7B2, 0x8E4E, 0xB7B3, 0x8E4F, 0xB7B4, 0xB7AA, 0xB7B5, 0xB7AB, 0xB7B6, 0x8E50, 0xB7B7, 0x8E51, 0xB7B8, 0xB7AC, 0xB7B9, 0x8E52, 0xB7BA, 0x8E53, 0xB7BB, 0x8E54, 0xB7BC, 0x8E55, 0xB7BD, 0x8E56, 0xB7BE, 0x8E57, 0xB7BF, 0x8E58, 0xB7C0, 0x8E59, 0xB7C1, 0x8E5A, 0xB7C2, 0x8E61, 0xB7C3, 0x8E62, 0xB7C4, 0x8E63, 0xB7C5, 0x8E64, 0xB7C6, 0x8E65, 0xB7C7, 0xB7AD, 0xB7C8, 0x8E66, 0xB7C9, 0xB7AE, 0xB7CA, 0x8E67, 0xB7CB, 0x8E68, 0xB7CC, 0x8E69, 0xB7CD, 0x8E6A, 0xB7CE, 0x8E6B, 0xB7CF, 0x8E6C, 0xB7D0, 0x8E6D, 0xB7D1, 0x8E6E, 0xB7D2, 0x8E6F, 0xB7D3, 0x8E70, 0xB7D4, 0x8E71, 0xB7D5, 0x8E72, 0xB7D6, 0x8E73, 0xB7D7, 0x8E74, 0xB7D8, 0x8E75, 0xB7D9, 0x8E76, 0xB7DA, 0x8E77, 0xB7DB, 0x8E78, 0xB7DC, 0x8E79, 0xB7DD, 0x8E7A, 0xB7DE, 0x8E81, 0xB7DF, 0x8E82, 0xB7E0, 0x8E83, 0xB7E1, 0x8E84, 0xB7E2, 0x8E85, 0xB7E3, 0x8E86, 0xB7E4, 0x8E87, 0xB7E5, 0x8E88, 0xB7E6, 0x8E89, 0xB7E7, 0x8E8A, 0xB7E8, 0x8E8B, 0xB7E9, 0x8E8C, 0xB7EA, 0x8E8D, 0xB7EB, 0x8E8E, 0xB7EC, 0xB7AF, 0xB7ED, 0xB7B0, 0xB7EE, 0x8E8F, 0xB7EF, 0x8E90, 0xB7F0, 0xB7B1, 0xB7F1, 0x8E91, 0xB7F2, 0x8E92, 0xB7F3, 0x8E93, 0xB7F4, 0xB7B2, 0xB7F5, 0x8E94, 0xB7F6, 0x8E95, 0xB7F7, 0x8E96, 0xB7F8, 0x8E97, 0xB7F9, 0x8E98, 0xB7FA, 0x8E99, 0xB7FB, 0x8E9A, 0xB7FC, 0xB7B3, 0xB7FD, 0xB7B4, 0xB7FE, 0x8E9B, 0xB7FF, 0xB7B5, 0xB800, 0xB7B6, 0xB801, 0xB7B7, 0xB802, 0x8E9C, 0xB803, 0x8E9D, 0xB804, 0x8E9E, 0xB805, 0x8E9F, 0xB806, 0x8EA0, 0xB807, 0xB7B8, 0xB808, 0xB7B9, 0xB809, 0xB7BA, 0xB80A, 0x8EA1, 0xB80B, 0x8EA2, 0xB80C, 0xB7BB, 0xB80D, 0x8EA3, 0xB80E, 0x8EA4, 0xB80F, 0x8EA5, 0xB810, 0xB7BC, 0xB811, 0x8EA6, 0xB812, 0x8EA7, 0xB813, 0x8EA8, 0xB814, 0x8EA9, 0xB815, 0x8EAA, 0xB816, 0x8EAB, 0xB817, 0x8EAC, 0xB818, 0xB7BD, 0xB819, 0xB7BE, 0xB81A, 0x8EAD, 0xB81B, 0xB7BF, 0xB81C, 0x8EAE, 0xB81D, 0xB7C0, 0xB81E, 0x8EAF, 0xB81F, 0x8EB0, 0xB820, 0x8EB1, 0xB821, 0x8EB2, 0xB822, 0x8EB3, 0xB823, 0x8EB4, 0xB824, 0xB7C1, 0xB825, 0xB7C2, 0xB826, 0x8EB5, 0xB827, 0x8EB6, 0xB828, 0xB7C3, 0xB829, 0x8EB7, 0xB82A, 0x8EB8, 0xB82B, 0x8EB9, 0xB82C, 0xB7C4, 0xB82D, 0x8EBA, 0xB82E, 0x8EBB, 0xB82F, 0x8EBC, 0xB830, 0x8EBD, 0xB831, 0x8EBE, 0xB832, 0x8EBF, 0xB833, 0x8EC0, 0xB834, 0xB7C5, 0xB835, 0xB7C6, 0xB836, 0x8EC1, 0xB837, 0xB7C7, 0xB838, 0xB7C8, 0xB839, 0xB7C9, 0xB83A, 0x8EC2, 0xB83B, 0x8EC3, 0xB83C, 0x8EC4, 0xB83D, 0x8EC5, 0xB83E, 0x8EC6, 0xB83F, 0x8EC7, 0xB840, 0xB7CA, 0xB841, 0x8EC8, 0xB842, 0x8EC9, 0xB843, 0x8ECA, 0xB844, 0xB7CB, 0xB845, 0x8ECB, 0xB846, 0x8ECC, 0xB847, 0x8ECD, 0xB848, 0x8ECE, 0xB849, 0x8ECF, 0xB84A, 0x8ED0, 0xB84B, 0x8ED1, 0xB84C, 0x8ED2, 0xB84D, 0x8ED3, 0xB84E, 0x8ED4, 0xB84F, 0x8ED5, 0xB850, 0x8ED6, 0xB851, 0xB7CC, 0xB852, 0x8ED7, 0xB853, 0xB7CD, 0xB854, 0x8ED8, 0xB855, 0x8ED9, 0xB856, 0x8EDA, 0xB857, 0x8EDB, 0xB858, 0x8EDC, 0xB859, 0x8EDD, 0xB85A, 0x8EDE, 0xB85B, 0x8EDF, 0xB85C, 0xB7CE, 0xB85D, 0xB7CF, 0xB85E, 0x8EE0, 0xB85F, 0x8EE1, 0xB860, 0xB7D0, 0xB861, 0x8EE2, 0xB862, 0x8EE3, 0xB863, 0x8EE4, 0xB864, 0xB7D1, 0xB865, 0x8EE5, 0xB866, 0x8EE6, 0xB867, 0x8EE7, 0xB868, 0x8EE8, 0xB869, 0x8EE9, 0xB86A, 0x8EEA, 0xB86B, 0x8EEB, 0xB86C, 0xB7D2, 0xB86D, 0xB7D3, 0xB86E, 0x8EEC, 0xB86F, 0xB7D4, 0xB870, 0x8EED, 0xB871, 0xB7D5, 0xB872, 0x8EEE, 0xB873, 0x8EEF, 0xB874, 0x8EF0, 0xB875, 0x8EF1, 0xB876, 0x8EF2, 0xB877, 0x8EF3, 0xB878, 0xB7D6, 0xB879, 0x8EF4, 0xB87A, 0x8EF5, 0xB87B, 0x8EF6, 0xB87C, 0xB7D7, 0xB87D, 0x8EF7, 0xB87E, 0x8EF8, 0xB87F, 0x8EF9, 0xB880, 0x8EFA, 0xB881, 0x8EFB, 0xB882, 0x8EFC, 0xB883, 0x8EFD, 0xB884, 0x8EFE, 0xB885, 0x8F41, 0xB886, 0x8F42, 0xB887, 0x8F43, 0xB888, 0x8F44, 0xB889, 0x8F45, 0xB88A, 0x8F46, 0xB88B, 0x8F47, 0xB88C, 0x8F48, 0xB88D, 0xB7D8, 0xB88E, 0x8F49, 0xB88F, 0x8F4A, 0xB890, 0x8F4B, 0xB891, 0x8F4C, 0xB892, 0x8F4D, 0xB893, 0x8F4E, 0xB894, 0x8F4F, 0xB895, 0x8F50, 0xB896, 0x8F51, 0xB897, 0x8F52, 0xB898, 0x8F53, 0xB899, 0x8F54, 0xB89A, 0x8F55, 0xB89B, 0x8F56, 0xB89C, 0x8F57, 0xB89D, 0x8F58, 0xB89E, 0x8F59, 0xB89F, 0x8F5A, 0xB8A0, 0x8F61, 0xB8A1, 0x8F62, 0xB8A2, 0x8F63, 0xB8A3, 0x8F64, 0xB8A4, 0x8F65, 0xB8A5, 0x8F66, 0xB8A6, 0x8F67, 0xB8A7, 0x8F68, 0xB8A8, 0xB7D9, 0xB8A9, 0x8F69, 0xB8AA, 0x8F6A, 0xB8AB, 0x8F6B, 0xB8AC, 0x8F6C, 0xB8AD, 0x8F6D, 0xB8AE, 0x8F6E, 0xB8AF, 0x8F6F, 0xB8B0, 0xB7DA, 0xB8B1, 0x8F70, 0xB8B2, 0x8F71, 0xB8B3, 0x8F72, 0xB8B4, 0xB7DB, 0xB8B5, 0x8F73, 0xB8B6, 0x8F74, 0xB8B7, 0x8F75, 0xB8B8, 0xB7DC, 0xB8B9, 0x8F76, 0xB8BA, 0x8F77, 0xB8BB, 0x8F78, 0xB8BC, 0x8F79, 0xB8BD, 0x8F7A, 0xB8BE, 0x8F81, 0xB8BF, 0x8F82, 0xB8C0, 0xB7DD, 0xB8C1, 0xB7DE, 0xB8C2, 0x8F83, 0xB8C3, 0xB7DF, 0xB8C4, 0x8F84, 0xB8C5, 0xB7E0, 0xB8C6, 0x8F85, 0xB8C7, 0x8F86, 0xB8C8, 0x8F87, 0xB8C9, 0x8F88, 0xB8CA, 0x8F89, 0xB8CB, 0x8F8A, 0xB8CC, 0xB7E1, 0xB8CD, 0x8F8B, 0xB8CE, 0x8F8C, 0xB8CF, 0x8F8D, 0xB8D0, 0xB7E2, 0xB8D1, 0x8F8E, 0xB8D2, 0x8F8F, 0xB8D3, 0x8F90, 0xB8D4, 0xB7E3, 0xB8D5, 0x8F91, 0xB8D6, 0x8F92, 0xB8D7, 0x8F93, 0xB8D8, 0x8F94, 0xB8D9, 0x8F95, 0xB8DA, 0x8F96, 0xB8DB, 0x8F97, 0xB8DC, 0x8F98, 0xB8DD, 0xB7E4, 0xB8DE, 0x8F99, 0xB8DF, 0xB7E5, 0xB8E0, 0x8F9A, 0xB8E1, 0xB7E6, 0xB8E2, 0x8F9B, 0xB8E3, 0x8F9C, 0xB8E4, 0x8F9D, 0xB8E5, 0x8F9E, 0xB8E6, 0x8F9F, 0xB8E7, 0x8FA0, 0xB8E8, 0xB7E7, 0xB8E9, 0xB7E8, 0xB8EA, 0x8FA1, 0xB8EB, 0x8FA2, 0xB8EC, 0xB7E9, 0xB8ED, 0x8FA3, 0xB8EE, 0x8FA4, 0xB8EF, 0x8FA5, 0xB8F0, 0xB7EA, 0xB8F1, 0x8FA6, 0xB8F2, 0x8FA7, 0xB8F3, 0x8FA8, 0xB8F4, 0x8FA9, 0xB8F5, 0x8FAA, 0xB8F6, 0x8FAB, 0xB8F7, 0x8FAC, 0xB8F8, 0xB7EB, 0xB8F9, 0xB7EC, 0xB8FA, 0x8FAD, 0xB8FB, 0xB7ED, 0xB8FC, 0x8FAE, 0xB8FD, 0xB7EE, 0xB8FE, 0x8FAF, 0xB8FF, 0x8FB0, 0xB900, 0x8FB1, 0xB901, 0x8FB2, 0xB902, 0x8FB3, 0xB903, 0x8FB4, 0xB904, 0xB7EF, 0xB905, 0x8FB5, 0xB906, 0x8FB6, 0xB907, 0x8FB7, 0xB908, 0x8FB8, 0xB909, 0x8FB9, 0xB90A, 0x8FBA, 0xB90B, 0x8FBB, 0xB90C, 0x8FBC, 0xB90D, 0x8FBD, 0xB90E, 0x8FBE, 0xB90F, 0x8FBF, 0xB910, 0x8FC0, 0xB911, 0x8FC1, 0xB912, 0x8FC2, 0xB913, 0x8FC3, 0xB914, 0x8FC4, 0xB915, 0x8FC5, 0xB916, 0x8FC6, 0xB917, 0x8FC7, 0xB918, 0xB7F0, 0xB919, 0x8FC8, 0xB91A, 0x8FC9, 0xB91B, 0x8FCA, 0xB91C, 0x8FCB, 0xB91D, 0x8FCC, 0xB91E, 0x8FCD, 0xB91F, 0x8FCE, 0xB920, 0xB7F1, 0xB921, 0x8FCF, 0xB922, 0x8FD0, 0xB923, 0x8FD1, 0xB924, 0x8FD2, 0xB925, 0x8FD3, 0xB926, 0x8FD4, 0xB927, 0x8FD5, 0xB928, 0x8FD6, 0xB929, 0x8FD7, 0xB92A, 0x8FD8, 0xB92B, 0x8FD9, 0xB92C, 0x8FDA, 0xB92D, 0x8FDB, 0xB92E, 0x8FDC, 0xB92F, 0x8FDD, 0xB930, 0x8FDE, 0xB931, 0x8FDF, 0xB932, 0x8FE0, 0xB933, 0x8FE1, 0xB934, 0x8FE2, 0xB935, 0x8FE3, 0xB936, 0x8FE4, 0xB937, 0x8FE5, 0xB938, 0x8FE6, 0xB939, 0x8FE7, 0xB93A, 0x8FE8, 0xB93B, 0x8FE9, 0xB93C, 0xB7F2, 0xB93D, 0xB7F3, 0xB93E, 0x8FEA, 0xB93F, 0x8FEB, 0xB940, 0xB7F4, 0xB941, 0x8FEC, 0xB942, 0x8FED, 0xB943, 0x8FEE, 0xB944, 0xB7F5, 0xB945, 0x8FEF, 0xB946, 0x8FF0, 0xB947, 0x8FF1, 0xB948, 0x8FF2, 0xB949, 0x8FF3, 0xB94A, 0x8FF4, 0xB94B, 0x8FF5, 0xB94C, 0xB7F6, 0xB94D, 0x8FF6, 0xB94E, 0x8FF7, 0xB94F, 0xB7F7, 0xB950, 0x8FF8, 0xB951, 0xB7F8, 0xB952, 0x8FF9, 0xB953, 0x8FFA, 0xB954, 0x8FFB, 0xB955, 0x8FFC, 0xB956, 0x8FFD, 0xB957, 0x8FFE, 0xB958, 0xB7F9, 0xB959, 0xB7FA, 0xB95A, 0x9041, 0xB95B, 0x9042, 0xB95C, 0xB7FB, 0xB95D, 0x9043, 0xB95E, 0x9044, 0xB95F, 0x9045, 0xB960, 0xB7FC, 0xB961, 0x9046, 0xB962, 0x9047, 0xB963, 0x9048, 0xB964, 0x9049, 0xB965, 0x904A, 0xB966, 0x904B, 0xB967, 0x904C, 0xB968, 0xB7FD, 0xB969, 0xB7FE, 0xB96A, 0x904D, 0xB96B, 0xB8A1, 0xB96C, 0x904E, 0xB96D, 0xB8A2, 0xB96E, 0x904F, 0xB96F, 0x9050, 0xB970, 0x9051, 0xB971, 0x9052, 0xB972, 0x9053, 0xB973, 0x9054, 0xB974, 0xB8A3, 0xB975, 0xB8A4, 0xB976, 0x9055, 0xB977, 0x9056, 0xB978, 0xB8A5, 0xB979, 0x9057, 0xB97A, 0x9058, 0xB97B, 0x9059, 0xB97C, 0xB8A6, 0xB97D, 0x905A, 0xB97E, 0x9061, 0xB97F, 0x9062, 0xB980, 0x9063, 0xB981, 0x9064, 0xB982, 0x9065, 0xB983, 0x9066, 0xB984, 0xB8A7, 0xB985, 0xB8A8, 0xB986, 0x9067, 0xB987, 0xB8A9, 0xB988, 0x9068, 0xB989, 0xB8AA, 0xB98A, 0xB8AB, 0xB98B, 0x9069, 0xB98C, 0x906A, 0xB98D, 0xB8AC, 0xB98E, 0xB8AD, 0xB98F, 0x906B, 0xB990, 0x906C, 0xB991, 0x906D, 0xB992, 0x906E, 0xB993, 0x906F, 0xB994, 0x9070, 0xB995, 0x9071, 0xB996, 0x9072, 0xB997, 0x9073, 0xB998, 0x9074, 0xB999, 0x9075, 0xB99A, 0x9076, 0xB99B, 0x9077, 0xB99C, 0x9078, 0xB99D, 0x9079, 0xB99E, 0x907A, 0xB99F, 0x9081, 0xB9A0, 0x9082, 0xB9A1, 0x9083, 0xB9A2, 0x9084, 0xB9A3, 0x9085, 0xB9A4, 0x9086, 0xB9A5, 0x9087, 0xB9A6, 0x9088, 0xB9A7, 0x9089, 0xB9A8, 0x908A, 0xB9A9, 0x908B, 0xB9AA, 0x908C, 0xB9AB, 0x908D, 0xB9AC, 0xB8AE, 0xB9AD, 0xB8AF, 0xB9AE, 0x908E, 0xB9AF, 0x908F, 0xB9B0, 0xB8B0, 0xB9B1, 0x9090, 0xB9B2, 0x9091, 0xB9B3, 0x9092, 0xB9B4, 0xB8B1, 0xB9B5, 0x9093, 0xB9B6, 0x9094, 0xB9B7, 0x9095, 0xB9B8, 0x9096, 0xB9B9, 0x9097, 0xB9BA, 0x9098, 0xB9BB, 0x9099, 0xB9BC, 0xB8B2, 0xB9BD, 0xB8B3, 0xB9BE, 0x909A, 0xB9BF, 0xB8B4, 0xB9C0, 0x909B, 0xB9C1, 0xB8B5, 0xB9C2, 0x909C, 0xB9C3, 0x909D, 0xB9C4, 0x909E, 0xB9C5, 0x909F, 0xB9C6, 0x90A0, 0xB9C7, 0x90A1, 0xB9C8, 0xB8B6, 0xB9C9, 0xB8B7, 0xB9CA, 0x90A2, 0xB9CB, 0x90A3, 0xB9CC, 0xB8B8, 0xB9CD, 0x90A4, 0xB9CE, 0xB8B9, 0xB9CF, 0xB8BA, 0xB9D0, 0xB8BB, 0xB9D1, 0xB8BC, 0xB9D2, 0xB8BD, 0xB9D3, 0x90A5, 0xB9D4, 0x90A6, 0xB9D5, 0x90A7, 0xB9D6, 0x90A8, 0xB9D7, 0x90A9, 0xB9D8, 0xB8BE, 0xB9D9, 0xB8BF, 0xB9DA, 0x90AA, 0xB9DB, 0xB8C0, 0xB9DC, 0x90AB, 0xB9DD, 0xB8C1, 0xB9DE, 0xB8C2, 0xB9DF, 0x90AC, 0xB9E0, 0x90AD, 0xB9E1, 0xB8C3, 0xB9E2, 0x90AE, 0xB9E3, 0xB8C4, 0xB9E4, 0xB8C5, 0xB9E5, 0xB8C6, 0xB9E6, 0x90AF, 0xB9E7, 0x90B0, 0xB9E8, 0xB8C7, 0xB9E9, 0x90B1, 0xB9EA, 0x90B2, 0xB9EB, 0x90B3, 0xB9EC, 0xB8C8, 0xB9ED, 0x90B4, 0xB9EE, 0x90B5, 0xB9EF, 0x90B6, 0xB9F0, 0x90B7, 0xB9F1, 0x90B8, 0xB9F2, 0x90B9, 0xB9F3, 0x90BA, 0xB9F4, 0xB8C9, 0xB9F5, 0xB8CA, 0xB9F6, 0x90BB, 0xB9F7, 0xB8CB, 0xB9F8, 0xB8CC, 0xB9F9, 0xB8CD, 0xB9FA, 0xB8CE, 0xB9FB, 0x90BC, 0xB9FC, 0x90BD, 0xB9FD, 0x90BE, 0xB9FE, 0x90BF, 0xB9FF, 0x90C0, 0xBA00, 0xB8CF, 0xBA01, 0xB8D0, 0xBA02, 0x90C1, 0xBA03, 0x90C2, 0xBA04, 0x90C3, 0xBA05, 0x90C4, 0xBA06, 0x90C5, 0xBA07, 0x90C6, 0xBA08, 0xB8D1, 0xBA09, 0x90C7, 0xBA0A, 0x90C8, 0xBA0B, 0x90C9, 0xBA0C, 0x90CA, 0xBA0D, 0x90CB, 0xBA0E, 0x90CC, 0xBA0F, 0x90CD, 0xBA10, 0x90CE, 0xBA11, 0x90CF, 0xBA12, 0x90D0, 0xBA13, 0x90D1, 0xBA14, 0x90D2, 0xBA15, 0xB8D2, 0xBA16, 0x90D3, 0xBA17, 0x90D4, 0xBA18, 0x90D5, 0xBA19, 0x90D6, 0xBA1A, 0x90D7, 0xBA1B, 0x90D8, 0xBA1C, 0x90D9, 0xBA1D, 0x90DA, 0xBA1E, 0x90DB, 0xBA1F, 0x90DC, 0xBA20, 0x90DD, 0xBA21, 0x90DE, 0xBA22, 0x90DF, 0xBA23, 0x90E0, 0xBA24, 0x90E1, 0xBA25, 0x90E2, 0xBA26, 0x90E3, 0xBA27, 0x90E4, 0xBA28, 0x90E5, 0xBA29, 0x90E6, 0xBA2A, 0x90E7, 0xBA2B, 0x90E8, 0xBA2C, 0x90E9, 0xBA2D, 0x90EA, 0xBA2E, 0x90EB, 0xBA2F, 0x90EC, 0xBA30, 0x90ED, 0xBA31, 0x90EE, 0xBA32, 0x90EF, 0xBA33, 0x90F0, 0xBA34, 0x90F1, 0xBA35, 0x90F2, 0xBA36, 0x90F3, 0xBA37, 0x90F4, 0xBA38, 0xB8D3, 0xBA39, 0xB8D4, 0xBA3A, 0x90F5, 0xBA3B, 0x90F6, 0xBA3C, 0xB8D5, 0xBA3D, 0x90F7, 0xBA3E, 0x90F8, 0xBA3F, 0x90F9, 0xBA40, 0xB8D6, 0xBA41, 0x90FA, 0xBA42, 0xB8D7, 0xBA43, 0x90FB, 0xBA44, 0x90FC, 0xBA45, 0x90FD, 0xBA46, 0x90FE, 0xBA47, 0x9141, 0xBA48, 0xB8D8, 0xBA49, 0xB8D9, 0xBA4A, 0x9142, 0xBA4B, 0xB8DA, 0xBA4C, 0x9143, 0xBA4D, 0xB8DB, 0xBA4E, 0xB8DC, 0xBA4F, 0x9144, 0xBA50, 0x9145, 0xBA51, 0x9146, 0xBA52, 0x9147, 0xBA53, 0xB8DD, 0xBA54, 0xB8DE, 0xBA55, 0xB8DF, 0xBA56, 0x9148, 0xBA57, 0x9149, 0xBA58, 0xB8E0, 0xBA59, 0x914A, 0xBA5A, 0x914B, 0xBA5B, 0x914C, 0xBA5C, 0xB8E1, 0xBA5D, 0x914D, 0xBA5E, 0x914E, 0xBA5F, 0x914F, 0xBA60, 0x9150, 0xBA61, 0x9151, 0xBA62, 0x9152, 0xBA63, 0x9153, 0xBA64, 0xB8E2, 0xBA65, 0xB8E3, 0xBA66, 0x9154, 0xBA67, 0xB8E4, 0xBA68, 0xB8E5, 0xBA69, 0xB8E6, 0xBA6A, 0x9155, 0xBA6B, 0x9156, 0xBA6C, 0x9157, 0xBA6D, 0x9158, 0xBA6E, 0x9159, 0xBA6F, 0x915A, 0xBA70, 0xB8E7, 0xBA71, 0xB8E8, 0xBA72, 0x9161, 0xBA73, 0x9162, 0xBA74, 0xB8E9, 0xBA75, 0x9163, 0xBA76, 0x9164, 0xBA77, 0x9165, 0xBA78, 0xB8EA, 0xBA79, 0x9166, 0xBA7A, 0x9167, 0xBA7B, 0x9168, 0xBA7C, 0x9169, 0xBA7D, 0x916A, 0xBA7E, 0x916B, 0xBA7F, 0x916C, 0xBA80, 0x916D, 0xBA81, 0x916E, 0xBA82, 0x916F, 0xBA83, 0xB8EB, 0xBA84, 0xB8EC, 0xBA85, 0xB8ED, 0xBA86, 0x9170, 0xBA87, 0xB8EE, 0xBA88, 0x9171, 0xBA89, 0x9172, 0xBA8A, 0x9173, 0xBA8B, 0x9174, 0xBA8C, 0xB8EF, 0xBA8D, 0x9175, 0xBA8E, 0x9176, 0xBA8F, 0x9177, 0xBA90, 0x9178, 0xBA91, 0x9179, 0xBA92, 0x917A, 0xBA93, 0x9181, 0xBA94, 0x9182, 0xBA95, 0x9183, 0xBA96, 0x9184, 0xBA97, 0x9185, 0xBA98, 0x9186, 0xBA99, 0x9187, 0xBA9A, 0x9188, 0xBA9B, 0x9189, 0xBA9C, 0x918A, 0xBA9D, 0x918B, 0xBA9E, 0x918C, 0xBA9F, 0x918D, 0xBAA0, 0x918E, 0xBAA1, 0x918F, 0xBAA2, 0x9190, 0xBAA3, 0x9191, 0xBAA4, 0x9192, 0xBAA5, 0x9193, 0xBAA6, 0x9194, 0xBAA7, 0x9195, 0xBAA8, 0xB8F0, 0xBAA9, 0xB8F1, 0xBAAA, 0x9196, 0xBAAB, 0xB8F2, 0xBAAC, 0xB8F3, 0xBAAD, 0x9197, 0xBAAE, 0x9198, 0xBAAF, 0x9199, 0xBAB0, 0xB8F4, 0xBAB1, 0x919A, 0xBAB2, 0xB8F5, 0xBAB3, 0x919B, 0xBAB4, 0x919C, 0xBAB5, 0x919D, 0xBAB6, 0x919E, 0xBAB7, 0x919F, 0xBAB8, 0xB8F6, 0xBAB9, 0xB8F7, 0xBABA, 0x91A0, 0xBABB, 0xB8F8, 0xBABC, 0x91A1, 0xBABD, 0xB8F9, 0xBABE, 0x91A2, 0xBABF, 0x91A3, 0xBAC0, 0x91A4, 0xBAC1, 0x91A5, 0xBAC2, 0x91A6, 0xBAC3, 0x91A7, 0xBAC4, 0xB8FA, 0xBAC5, 0x91A8, 0xBAC6, 0x91A9, 0xBAC7, 0x91AA, 0xBAC8, 0xB8FB, 0xBAC9, 0x91AB, 0xBACA, 0x91AC, 0xBACB, 0x91AD, 0xBACC, 0x91AE, 0xBACD, 0x91AF, 0xBACE, 0x91B0, 0xBACF, 0x91B1, 0xBAD0, 0x91B2, 0xBAD1, 0x91B3, 0xBAD2, 0x91B4, 0xBAD3, 0x91B5, 0xBAD4, 0x91B6, 0xBAD5, 0x91B7, 0xBAD6, 0x91B8, 0xBAD7, 0x91B9, 0xBAD8, 0xB8FC, 0xBAD9, 0xB8FD, 0xBADA, 0x91BA, 0xBADB, 0x91BB, 0xBADC, 0x91BC, 0xBADD, 0x91BD, 0xBADE, 0x91BE, 0xBADF, 0x91BF, 0xBAE0, 0x91C0, 0xBAE1, 0x91C1, 0xBAE2, 0x91C2, 0xBAE3, 0x91C3, 0xBAE4, 0x91C4, 0xBAE5, 0x91C5, 0xBAE6, 0x91C6, 0xBAE7, 0x91C7, 0xBAE8, 0x91C8, 0xBAE9, 0x91C9, 0xBAEA, 0x91CA, 0xBAEB, 0x91CB, 0xBAEC, 0x91CC, 0xBAED, 0x91CD, 0xBAEE, 0x91CE, 0xBAEF, 0x91CF, 0xBAF0, 0x91D0, 0xBAF1, 0x91D1, 0xBAF2, 0x91D2, 0xBAF3, 0x91D3, 0xBAF4, 0x91D4, 0xBAF5, 0x91D5, 0xBAF6, 0x91D6, 0xBAF7, 0x91D7, 0xBAF8, 0x91D8, 0xBAF9, 0x91D9, 0xBAFA, 0x91DA, 0xBAFB, 0x91DB, 0xBAFC, 0xB8FE, 0xBAFD, 0x91DC, 0xBAFE, 0x91DD, 0xBAFF, 0x91DE, 0xBB00, 0xB9A1, 0xBB01, 0x91DF, 0xBB02, 0x91E0, 0xBB03, 0x91E1, 0xBB04, 0xB9A2, 0xBB05, 0x91E2, 0xBB06, 0x91E3, 0xBB07, 0x91E4, 0xBB08, 0x91E5, 0xBB09, 0x91E6, 0xBB0A, 0x91E7, 0xBB0B, 0x91E8, 0xBB0C, 0x91E9, 0xBB0D, 0xB9A3, 0xBB0E, 0x91EA, 0xBB0F, 0xB9A4, 0xBB10, 0x91EB, 0xBB11, 0xB9A5, 0xBB12, 0x91EC, 0xBB13, 0x91ED, 0xBB14, 0x91EE, 0xBB15, 0x91EF, 0xBB16, 0x91F0, 0xBB17, 0x91F1, 0xBB18, 0xB9A6, 0xBB19, 0x91F2, 0xBB1A, 0x91F3, 0xBB1B, 0x91F4, 0xBB1C, 0xB9A7, 0xBB1D, 0x91F5, 0xBB1E, 0x91F6, 0xBB1F, 0x91F7, 0xBB20, 0xB9A8, 0xBB21, 0x91F8, 0xBB22, 0x91F9, 0xBB23, 0x91FA, 0xBB24, 0x91FB, 0xBB25, 0x91FC, 0xBB26, 0x91FD, 0xBB27, 0x91FE, 0xBB28, 0x9241, 0xBB29, 0xB9A9, 0xBB2A, 0x9242, 0xBB2B, 0xB9AA, 0xBB2C, 0x9243, 0xBB2D, 0x9244, 0xBB2E, 0x9245, 0xBB2F, 0x9246, 0xBB30, 0x9247, 0xBB31, 0x9248, 0xBB32, 0x9249, 0xBB33, 0x924A, 0xBB34, 0xB9AB, 0xBB35, 0xB9AC, 0xBB36, 0xB9AD, 0xBB37, 0x924B, 0xBB38, 0xB9AE, 0xBB39, 0x924C, 0xBB3A, 0x924D, 0xBB3B, 0xB9AF, 0xBB3C, 0xB9B0, 0xBB3D, 0xB9B1, 0xBB3E, 0xB9B2, 0xBB3F, 0x924E, 0xBB40, 0x924F, 0xBB41, 0x9250, 0xBB42, 0x9251, 0xBB43, 0x9252, 0xBB44, 0xB9B3, 0xBB45, 0xB9B4, 0xBB46, 0x9253, 0xBB47, 0xB9B5, 0xBB48, 0x9254, 0xBB49, 0xB9B6, 0xBB4A, 0x9255, 0xBB4B, 0x9256, 0xBB4C, 0x9257, 0xBB4D, 0xB9B7, 0xBB4E, 0x9258, 0xBB4F, 0xB9B8, 0xBB50, 0xB9B9, 0xBB51, 0x9259, 0xBB52, 0x925A, 0xBB53, 0x9261, 0xBB54, 0xB9BA, 0xBB55, 0x9262, 0xBB56, 0x9263, 0xBB57, 0x9264, 0xBB58, 0xB9BB, 0xBB59, 0x9265, 0xBB5A, 0x9266, 0xBB5B, 0x9267, 0xBB5C, 0x9268, 0xBB5D, 0x9269, 0xBB5E, 0x926A, 0xBB5F, 0x926B, 0xBB60, 0x926C, 0xBB61, 0xB9BC, 0xBB62, 0x926D, 0xBB63, 0xB9BD, 0xBB64, 0x926E, 0xBB65, 0x926F, 0xBB66, 0x9270, 0xBB67, 0x9271, 0xBB68, 0x9272, 0xBB69, 0x9273, 0xBB6A, 0x9274, 0xBB6B, 0x9275, 0xBB6C, 0xB9BE, 0xBB6D, 0x9276, 0xBB6E, 0x9277, 0xBB6F, 0x9278, 0xBB70, 0x9279, 0xBB71, 0x927A, 0xBB72, 0x9281, 0xBB73, 0x9282, 0xBB74, 0x9283, 0xBB75, 0x9284, 0xBB76, 0x9285, 0xBB77, 0x9286, 0xBB78, 0x9287, 0xBB79, 0x9288, 0xBB7A, 0x9289, 0xBB7B, 0x928A, 0xBB7C, 0x928B, 0xBB7D, 0x928C, 0xBB7E, 0x928D, 0xBB7F, 0x928E, 0xBB80, 0x928F, 0xBB81, 0x9290, 0xBB82, 0x9291, 0xBB83, 0x9292, 0xBB84, 0x9293, 0xBB85, 0x9294, 0xBB86, 0x9295, 0xBB87, 0x9296, 0xBB88, 0xB9BF, 0xBB89, 0x9297, 0xBB8A, 0x9298, 0xBB8B, 0x9299, 0xBB8C, 0xB9C0, 0xBB8D, 0x929A, 0xBB8E, 0x929B, 0xBB8F, 0x929C, 0xBB90, 0xB9C1, 0xBB91, 0x929D, 0xBB92, 0x929E, 0xBB93, 0x929F, 0xBB94, 0x92A0, 0xBB95, 0x92A1, 0xBB96, 0x92A2, 0xBB97, 0x92A3, 0xBB98, 0x92A4, 0xBB99, 0x92A5, 0xBB9A, 0x92A6, 0xBB9B, 0x92A7, 0xBB9C, 0x92A8, 0xBB9D, 0x92A9, 0xBB9E, 0x92AA, 0xBB9F, 0x92AB, 0xBBA0, 0x92AC, 0xBBA1, 0x92AD, 0xBBA2, 0x92AE, 0xBBA3, 0x92AF, 0xBBA4, 0xB9C2, 0xBBA5, 0x92B0, 0xBBA6, 0x92B1, 0xBBA7, 0x92B2, 0xBBA8, 0xB9C3, 0xBBA9, 0x92B3, 0xBBAA, 0x92B4, 0xBBAB, 0x92B5, 0xBBAC, 0xB9C4, 0xBBAD, 0x92B6, 0xBBAE, 0x92B7, 0xBBAF, 0x92B8, 0xBBB0, 0x92B9, 0xBBB1, 0x92BA, 0xBBB2, 0x92BB, 0xBBB3, 0x92BC, 0xBBB4, 0xB9C5, 0xBBB5, 0x92BD, 0xBBB6, 0x92BE, 0xBBB7, 0xB9C6, 0xBBB8, 0x92BF, 0xBBB9, 0x92C0, 0xBBBA, 0x92C1, 0xBBBB, 0x92C2, 0xBBBC, 0x92C3, 0xBBBD, 0x92C4, 0xBBBE, 0x92C5, 0xBBBF, 0x92C6, 0xBBC0, 0xB9C7, 0xBBC1, 0x92C7, 0xBBC2, 0x92C8, 0xBBC3, 0x92C9, 0xBBC4, 0xB9C8, 0xBBC5, 0x92CA, 0xBBC6, 0x92CB, 0xBBC7, 0x92CC, 0xBBC8, 0xB9C9, 0xBBC9, 0x92CD, 0xBBCA, 0x92CE, 0xBBCB, 0x92CF, 0xBBCC, 0x92D0, 0xBBCD, 0x92D1, 0xBBCE, 0x92D2, 0xBBCF, 0x92D3, 0xBBD0, 0xB9CA, 0xBBD1, 0x92D4, 0xBBD2, 0x92D5, 0xBBD3, 0xB9CB, 0xBBD4, 0x92D6, 0xBBD5, 0x92D7, 0xBBD6, 0x92D8, 0xBBD7, 0x92D9, 0xBBD8, 0x92DA, 0xBBD9, 0x92DB, 0xBBDA, 0x92DC, 0xBBDB, 0x92DD, 0xBBDC, 0x92DE, 0xBBDD, 0x92DF, 0xBBDE, 0x92E0, 0xBBDF, 0x92E1, 0xBBE0, 0x92E2, 0xBBE1, 0x92E3, 0xBBE2, 0x92E4, 0xBBE3, 0x92E5, 0xBBE4, 0x92E6, 0xBBE5, 0x92E7, 0xBBE6, 0x92E8, 0xBBE7, 0x92E9, 0xBBE8, 0x92EA, 0xBBE9, 0x92EB, 0xBBEA, 0x92EC, 0xBBEB, 0x92ED, 0xBBEC, 0x92EE, 0xBBED, 0x92EF, 0xBBEE, 0x92F0, 0xBBEF, 0x92F1, 0xBBF0, 0x92F2, 0xBBF1, 0x92F3, 0xBBF2, 0x92F4, 0xBBF3, 0x92F5, 0xBBF4, 0x92F6, 0xBBF5, 0x92F7, 0xBBF6, 0x92F8, 0xBBF7, 0x92F9, 0xBBF8, 0xB9CC, 0xBBF9, 0xB9CD, 0xBBFA, 0x92FA, 0xBBFB, 0x92FB, 0xBBFC, 0xB9CE, 0xBBFD, 0x92FC, 0xBBFE, 0x92FD, 0xBBFF, 0xB9CF, 0xBC00, 0xB9D0, 0xBC01, 0x92FE, 0xBC02, 0xB9D1, 0xBC03, 0x9341, 0xBC04, 0x9342, 0xBC05, 0x9343, 0xBC06, 0x9344, 0xBC07, 0x9345, 0xBC08, 0xB9D2, 0xBC09, 0xB9D3, 0xBC0A, 0x9346, 0xBC0B, 0xB9D4, 0xBC0C, 0xB9D5, 0xBC0D, 0xB9D6, 0xBC0E, 0x9347, 0xBC0F, 0xB9D7, 0xBC10, 0x9348, 0xBC11, 0xB9D8, 0xBC12, 0x9349, 0xBC13, 0x934A, 0xBC14, 0xB9D9, 0xBC15, 0xB9DA, 0xBC16, 0xB9DB, 0xBC17, 0xB9DC, 0xBC18, 0xB9DD, 0xBC19, 0x934B, 0xBC1A, 0x934C, 0xBC1B, 0xB9DE, 0xBC1C, 0xB9DF, 0xBC1D, 0xB9E0, 0xBC1E, 0xB9E1, 0xBC1F, 0xB9E2, 0xBC20, 0x934D, 0xBC21, 0x934E, 0xBC22, 0x934F, 0xBC23, 0x9350, 0xBC24, 0xB9E3, 0xBC25, 0xB9E4, 0xBC26, 0x9351, 0xBC27, 0xB9E5, 0xBC28, 0x9352, 0xBC29, 0xB9E6, 0xBC2A, 0x9353, 0xBC2B, 0x9354, 0xBC2C, 0x9355, 0xBC2D, 0xB9E7, 0xBC2E, 0x9356, 0xBC2F, 0x9357, 0xBC30, 0xB9E8, 0xBC31, 0xB9E9, 0xBC32, 0x9358, 0xBC33, 0x9359, 0xBC34, 0xB9EA, 0xBC35, 0x935A, 0xBC36, 0x9361, 0xBC37, 0x9362, 0xBC38, 0xB9EB, 0xBC39, 0x9363, 0xBC3A, 0x9364, 0xBC3B, 0x9365, 0xBC3C, 0x9366, 0xBC3D, 0x9367, 0xBC3E, 0x9368, 0xBC3F, 0x9369, 0xBC40, 0xB9EC, 0xBC41, 0xB9ED, 0xBC42, 0x936A, 0xBC43, 0xB9EE, 0xBC44, 0xB9EF, 0xBC45, 0xB9F0, 0xBC46, 0x936B, 0xBC47, 0x936C, 0xBC48, 0x936D, 0xBC49, 0xB9F1, 0xBC4A, 0x936E, 0xBC4B, 0x936F, 0xBC4C, 0xB9F2, 0xBC4D, 0xB9F3, 0xBC4E, 0x9370, 0xBC4F, 0x9371, 0xBC50, 0xB9F4, 0xBC51, 0x9372, 0xBC52, 0x9373, 0xBC53, 0x9374, 0xBC54, 0x9375, 0xBC55, 0x9376, 0xBC56, 0x9377, 0xBC57, 0x9378, 0xBC58, 0x9379, 0xBC59, 0x937A, 0xBC5A, 0x9381, 0xBC5B, 0x9382, 0xBC5C, 0x9383, 0xBC5D, 0xB9F5, 0xBC5E, 0x9384, 0xBC5F, 0x9385, 0xBC60, 0x9386, 0xBC61, 0x9387, 0xBC62, 0x9388, 0xBC63, 0x9389, 0xBC64, 0x938A, 0xBC65, 0x938B, 0xBC66, 0x938C, 0xBC67, 0x938D, 0xBC68, 0x938E, 0xBC69, 0x938F, 0xBC6A, 0x9390, 0xBC6B, 0x9391, 0xBC6C, 0x9392, 0xBC6D, 0x9393, 0xBC6E, 0x9394, 0xBC6F, 0x9395, 0xBC70, 0x9396, 0xBC71, 0x9397, 0xBC72, 0x9398, 0xBC73, 0x9399, 0xBC74, 0x939A, 0xBC75, 0x939B, 0xBC76, 0x939C, 0xBC77, 0x939D, 0xBC78, 0x939E, 0xBC79, 0x939F, 0xBC7A, 0x93A0, 0xBC7B, 0x93A1, 0xBC7C, 0x93A2, 0xBC7D, 0x93A3, 0xBC7E, 0x93A4, 0xBC7F, 0x93A5, 0xBC80, 0x93A6, 0xBC81, 0x93A7, 0xBC82, 0x93A8, 0xBC83, 0x93A9, 0xBC84, 0xB9F6, 0xBC85, 0xB9F7, 0xBC86, 0x93AA, 0xBC87, 0x93AB, 0xBC88, 0xB9F8, 0xBC89, 0x93AC, 0xBC8A, 0x93AD, 0xBC8B, 0xB9F9, 0xBC8C, 0xB9FA, 0xBC8D, 0x93AE, 0xBC8E, 0xB9FB, 0xBC8F, 0x93AF, 0xBC90, 0x93B0, 0xBC91, 0x93B1, 0xBC92, 0x93B2, 0xBC93, 0x93B3, 0xBC94, 0xB9FC, 0xBC95, 0xB9FD, 0xBC96, 0x93B4, 0xBC97, 0xB9FE, 0xBC98, 0x93B5, 0xBC99, 0xBAA1, 0xBC9A, 0xBAA2, 0xBC9B, 0x93B6, 0xBC9C, 0x93B7, 0xBC9D, 0x93B8, 0xBC9E, 0x93B9, 0xBC9F, 0x93BA, 0xBCA0, 0xBAA3, 0xBCA1, 0xBAA4, 0xBCA2, 0x93BB, 0xBCA3, 0x93BC, 0xBCA4, 0xBAA5, 0xBCA5, 0x93BD, 0xBCA6, 0x93BE, 0xBCA7, 0xBAA6, 0xBCA8, 0xBAA7, 0xBCA9, 0x93BF, 0xBCAA, 0x93C0, 0xBCAB, 0x93C1, 0xBCAC, 0x93C2, 0xBCAD, 0x93C3, 0xBCAE, 0x93C4, 0xBCAF, 0x93C5, 0xBCB0, 0xBAA8, 0xBCB1, 0xBAA9, 0xBCB2, 0x93C6, 0xBCB3, 0xBAAA, 0xBCB4, 0xBAAB, 0xBCB5, 0xBAAC, 0xBCB6, 0x93C7, 0xBCB7, 0x93C8, 0xBCB8, 0x93C9, 0xBCB9, 0x93CA, 0xBCBA, 0x93CB, 0xBCBB, 0x93CC, 0xBCBC, 0xBAAD, 0xBCBD, 0xBAAE, 0xBCBE, 0x93CD, 0xBCBF, 0x93CE, 0xBCC0, 0xBAAF, 0xBCC1, 0x93CF, 0xBCC2, 0x93D0, 0xBCC3, 0x93D1, 0xBCC4, 0xBAB0, 0xBCC5, 0x93D2, 0xBCC6, 0x93D3, 0xBCC7, 0x93D4, 0xBCC8, 0x93D5, 0xBCC9, 0x93D6, 0xBCCA, 0x93D7, 0xBCCB, 0x93D8, 0xBCCC, 0x93D9, 0xBCCD, 0xBAB1, 0xBCCE, 0x93DA, 0xBCCF, 0xBAB2, 0xBCD0, 0xBAB3, 0xBCD1, 0xBAB4, 0xBCD2, 0x93DB, 0xBCD3, 0x93DC, 0xBCD4, 0x93DD, 0xBCD5, 0xBAB5, 0xBCD6, 0x93DE, 0xBCD7, 0x93DF, 0xBCD8, 0xBAB6, 0xBCD9, 0x93E0, 0xBCDA, 0x93E1, 0xBCDB, 0x93E2, 0xBCDC, 0xBAB7, 0xBCDD, 0x93E3, 0xBCDE, 0x93E4, 0xBCDF, 0x93E5, 0xBCE0, 0x93E6, 0xBCE1, 0x93E7, 0xBCE2, 0x93E8, 0xBCE3, 0x93E9, 0xBCE4, 0x93EA, 0xBCE5, 0x93EB, 0xBCE6, 0x93EC, 0xBCE7, 0x93ED, 0xBCE8, 0x93EE, 0xBCE9, 0x93EF, 0xBCEA, 0x93F0, 0xBCEB, 0x93F1, 0xBCEC, 0x93F2, 0xBCED, 0x93F3, 0xBCEE, 0x93F4, 0xBCEF, 0x93F5, 0xBCF0, 0x93F6, 0xBCF1, 0x93F7, 0xBCF2, 0x93F8, 0xBCF3, 0x93F9, 0xBCF4, 0xBAB8, 0xBCF5, 0xBAB9, 0xBCF6, 0xBABA, 0xBCF7, 0x93FA, 0xBCF8, 0xBABB, 0xBCF9, 0x93FB, 0xBCFA, 0x93FC, 0xBCFB, 0x93FD, 0xBCFC, 0xBABC, 0xBCFD, 0x93FE, 0xBCFE, 0x9441, 0xBCFF, 0x9442, 0xBD00, 0x9443, 0xBD01, 0x9444, 0xBD02, 0x9445, 0xBD03, 0x9446, 0xBD04, 0xBABD, 0xBD05, 0xBABE, 0xBD06, 0x9447, 0xBD07, 0xBABF, 0xBD08, 0x9448, 0xBD09, 0xBAC0, 0xBD0A, 0x9449, 0xBD0B, 0x944A, 0xBD0C, 0x944B, 0xBD0D, 0x944C, 0xBD0E, 0x944D, 0xBD0F, 0x944E, 0xBD10, 0xBAC1, 0xBD11, 0x944F, 0xBD12, 0x9450, 0xBD13, 0x9451, 0xBD14, 0xBAC2, 0xBD15, 0x9452, 0xBD16, 0x9453, 0xBD17, 0x9454, 0xBD18, 0x9455, 0xBD19, 0x9456, 0xBD1A, 0x9457, 0xBD1B, 0x9458, 0xBD1C, 0x9459, 0xBD1D, 0x945A, 0xBD1E, 0x9461, 0xBD1F, 0x9462, 0xBD20, 0x9463, 0xBD21, 0x9464, 0xBD22, 0x9465, 0xBD23, 0x9466, 0xBD24, 0xBAC3, 0xBD25, 0x9467, 0xBD26, 0x9468, 0xBD27, 0x9469, 0xBD28, 0x946A, 0xBD29, 0x946B, 0xBD2A, 0x946C, 0xBD2B, 0x946D, 0xBD2C, 0xBAC4, 0xBD2D, 0x946E, 0xBD2E, 0x946F, 0xBD2F, 0x9470, 0xBD30, 0x9471, 0xBD31, 0x9472, 0xBD32, 0x9473, 0xBD33, 0x9474, 0xBD34, 0x9475, 0xBD35, 0x9476, 0xBD36, 0x9477, 0xBD37, 0x9478, 0xBD38, 0x9479, 0xBD39, 0x947A, 0xBD3A, 0x9481, 0xBD3B, 0x9482, 0xBD3C, 0x9483, 0xBD3D, 0x9484, 0xBD3E, 0x9485, 0xBD3F, 0x9486, 0xBD40, 0xBAC5, 0xBD41, 0x9487, 0xBD42, 0x9488, 0xBD43, 0x9489, 0xBD44, 0x948A, 0xBD45, 0x948B, 0xBD46, 0x948C, 0xBD47, 0x948D, 0xBD48, 0xBAC6, 0xBD49, 0xBAC7, 0xBD4A, 0x948E, 0xBD4B, 0x948F, 0xBD4C, 0xBAC8, 0xBD4D, 0x9490, 0xBD4E, 0x9491, 0xBD4F, 0x9492, 0xBD50, 0xBAC9, 0xBD51, 0x9493, 0xBD52, 0x9494, 0xBD53, 0x9495, 0xBD54, 0x9496, 0xBD55, 0x9497, 0xBD56, 0x9498, 0xBD57, 0x9499, 0xBD58, 0xBACA, 0xBD59, 0xBACB, 0xBD5A, 0x949A, 0xBD5B, 0x949B, 0xBD5C, 0x949C, 0xBD5D, 0x949D, 0xBD5E, 0x949E, 0xBD5F, 0x949F, 0xBD60, 0x94A0, 0xBD61, 0x94A1, 0xBD62, 0x94A2, 0xBD63, 0x94A3, 0xBD64, 0xBACC, 0xBD65, 0x94A4, 0xBD66, 0x94A5, 0xBD67, 0x94A6, 0xBD68, 0xBACD, 0xBD69, 0x94A7, 0xBD6A, 0x94A8, 0xBD6B, 0x94A9, 0xBD6C, 0x94AA, 0xBD6D, 0x94AB, 0xBD6E, 0x94AC, 0xBD6F, 0x94AD, 0xBD70, 0x94AE, 0xBD71, 0x94AF, 0xBD72, 0x94B0, 0xBD73, 0x94B1, 0xBD74, 0x94B2, 0xBD75, 0x94B3, 0xBD76, 0x94B4, 0xBD77, 0x94B5, 0xBD78, 0x94B6, 0xBD79, 0x94B7, 0xBD7A, 0x94B8, 0xBD7B, 0x94B9, 0xBD7C, 0x94BA, 0xBD7D, 0x94BB, 0xBD7E, 0x94BC, 0xBD7F, 0x94BD, 0xBD80, 0xBACE, 0xBD81, 0xBACF, 0xBD82, 0x94BE, 0xBD83, 0x94BF, 0xBD84, 0xBAD0, 0xBD85, 0x94C0, 0xBD86, 0x94C1, 0xBD87, 0xBAD1, 0xBD88, 0xBAD2, 0xBD89, 0xBAD3, 0xBD8A, 0xBAD4, 0xBD8B, 0x94C2, 0xBD8C, 0x94C3, 0xBD8D, 0x94C4, 0xBD8E, 0x94C5, 0xBD8F, 0x94C6, 0xBD90, 0xBAD5, 0xBD91, 0xBAD6, 0xBD92, 0x94C7, 0xBD93, 0xBAD7, 0xBD94, 0x94C8, 0xBD95, 0xBAD8, 0xBD96, 0x94C9, 0xBD97, 0x94CA, 0xBD98, 0x94CB, 0xBD99, 0xBAD9, 0xBD9A, 0xBADA, 0xBD9B, 0x94CC, 0xBD9C, 0xBADB, 0xBD9D, 0x94CD, 0xBD9E, 0x94CE, 0xBD9F, 0x94CF, 0xBDA0, 0x94D0, 0xBDA1, 0x94D1, 0xBDA2, 0x94D2, 0xBDA3, 0x94D3, 0xBDA4, 0xBADC, 0xBDA5, 0x94D4, 0xBDA6, 0x94D5, 0xBDA7, 0x94D6, 0xBDA8, 0x94D7, 0xBDA9, 0x94D8, 0xBDAA, 0x94D9, 0xBDAB, 0x94DA, 0xBDAC, 0x94DB, 0xBDAD, 0x94DC, 0xBDAE, 0x94DD, 0xBDAF, 0x94DE, 0xBDB0, 0xBADD, 0xBDB1, 0x94DF, 0xBDB2, 0x94E0, 0xBDB3, 0x94E1, 0xBDB4, 0x94E2, 0xBDB5, 0x94E3, 0xBDB6, 0x94E4, 0xBDB7, 0x94E5, 0xBDB8, 0xBADE, 0xBDB9, 0x94E6, 0xBDBA, 0x94E7, 0xBDBB, 0x94E8, 0xBDBC, 0x94E9, 0xBDBD, 0x94EA, 0xBDBE, 0x94EB, 0xBDBF, 0x94EC, 0xBDC0, 0x94ED, 0xBDC1, 0x94EE, 0xBDC2, 0x94EF, 0xBDC3, 0x94F0, 0xBDC4, 0x94F1, 0xBDC5, 0x94F2, 0xBDC6, 0x94F3, 0xBDC7, 0x94F4, 0xBDC8, 0x94F5, 0xBDC9, 0x94F6, 0xBDCA, 0x94F7, 0xBDCB, 0x94F8, 0xBDCC, 0x94F9, 0xBDCD, 0x94FA, 0xBDCE, 0x94FB, 0xBDCF, 0x94FC, 0xBDD0, 0x94FD, 0xBDD1, 0x94FE, 0xBDD2, 0x9541, 0xBDD3, 0x9542, 0xBDD4, 0xBADF, 0xBDD5, 0xBAE0, 0xBDD6, 0x9543, 0xBDD7, 0x9544, 0xBDD8, 0xBAE1, 0xBDD9, 0x9545, 0xBDDA, 0x9546, 0xBDDB, 0x9547, 0xBDDC, 0xBAE2, 0xBDDD, 0x9548, 0xBDDE, 0x9549, 0xBDDF, 0x954A, 0xBDE0, 0x954B, 0xBDE1, 0x954C, 0xBDE2, 0x954D, 0xBDE3, 0x954E, 0xBDE4, 0x954F, 0xBDE5, 0x9550, 0xBDE6, 0x9551, 0xBDE7, 0x9552, 0xBDE8, 0x9553, 0xBDE9, 0xBAE3, 0xBDEA, 0x9554, 0xBDEB, 0x9555, 0xBDEC, 0x9556, 0xBDED, 0x9557, 0xBDEE, 0x9558, 0xBDEF, 0x9559, 0xBDF0, 0xBAE4, 0xBDF1, 0x955A, 0xBDF2, 0x9561, 0xBDF3, 0x9562, 0xBDF4, 0xBAE5, 0xBDF5, 0x9563, 0xBDF6, 0x9564, 0xBDF7, 0x9565, 0xBDF8, 0xBAE6, 0xBDF9, 0x9566, 0xBDFA, 0x9567, 0xBDFB, 0x9568, 0xBDFC, 0x9569, 0xBDFD, 0x956A, 0xBDFE, 0x956B, 0xBDFF, 0x956C, 0xBE00, 0xBAE7, 0xBE01, 0x956D, 0xBE02, 0x956E, 0xBE03, 0xBAE8, 0xBE04, 0x956F, 0xBE05, 0xBAE9, 0xBE06, 0x9570, 0xBE07, 0x9571, 0xBE08, 0x9572, 0xBE09, 0x9573, 0xBE0A, 0x9574, 0xBE0B, 0x9575, 0xBE0C, 0xBAEA, 0xBE0D, 0xBAEB, 0xBE0E, 0x9576, 0xBE0F, 0x9577, 0xBE10, 0xBAEC, 0xBE11, 0x9578, 0xBE12, 0x9579, 0xBE13, 0x957A, 0xBE14, 0xBAED, 0xBE15, 0x9581, 0xBE16, 0x9582, 0xBE17, 0x9583, 0xBE18, 0x9584, 0xBE19, 0x9585, 0xBE1A, 0x9586, 0xBE1B, 0x9587, 0xBE1C, 0xBAEE, 0xBE1D, 0xBAEF, 0xBE1E, 0x9588, 0xBE1F, 0xBAF0, 0xBE20, 0x9589, 0xBE21, 0x958A, 0xBE22, 0x958B, 0xBE23, 0x958C, 0xBE24, 0x958D, 0xBE25, 0x958E, 0xBE26, 0x958F, 0xBE27, 0x9590, 0xBE28, 0x9591, 0xBE29, 0x9592, 0xBE2A, 0x9593, 0xBE2B, 0x9594, 0xBE2C, 0x9595, 0xBE2D, 0x9596, 0xBE2E, 0x9597, 0xBE2F, 0x9598, 0xBE30, 0x9599, 0xBE31, 0x959A, 0xBE32, 0x959B, 0xBE33, 0x959C, 0xBE34, 0x959D, 0xBE35, 0x959E, 0xBE36, 0x959F, 0xBE37, 0x95A0, 0xBE38, 0x95A1, 0xBE39, 0x95A2, 0xBE3A, 0x95A3, 0xBE3B, 0x95A4, 0xBE3C, 0x95A5, 0xBE3D, 0x95A6, 0xBE3E, 0x95A7, 0xBE3F, 0x95A8, 0xBE40, 0x95A9, 0xBE41, 0x95AA, 0xBE42, 0x95AB, 0xBE43, 0x95AC, 0xBE44, 0xBAF1, 0xBE45, 0xBAF2, 0xBE46, 0x95AD, 0xBE47, 0x95AE, 0xBE48, 0xBAF3, 0xBE49, 0x95AF, 0xBE4A, 0x95B0, 0xBE4B, 0x95B1, 0xBE4C, 0xBAF4, 0xBE4D, 0x95B2, 0xBE4E, 0xBAF5, 0xBE4F, 0x95B3, 0xBE50, 0x95B4, 0xBE51, 0x95B5, 0xBE52, 0x95B6, 0xBE53, 0x95B7, 0xBE54, 0xBAF6, 0xBE55, 0xBAF7, 0xBE56, 0x95B8, 0xBE57, 0xBAF8, 0xBE58, 0x95B9, 0xBE59, 0xBAF9, 0xBE5A, 0xBAFA, 0xBE5B, 0xBAFB, 0xBE5C, 0x95BA, 0xBE5D, 0x95BB, 0xBE5E, 0x95BC, 0xBE5F, 0x95BD, 0xBE60, 0xBAFC, 0xBE61, 0xBAFD, 0xBE62, 0x95BE, 0xBE63, 0x95BF, 0xBE64, 0xBAFE, 0xBE65, 0x95C0, 0xBE66, 0x95C1, 0xBE67, 0x95C2, 0xBE68, 0xBBA1, 0xBE69, 0x95C3, 0xBE6A, 0xBBA2, 0xBE6B, 0x95C4, 0xBE6C, 0x95C5, 0xBE6D, 0x95C6, 0xBE6E, 0x95C7, 0xBE6F, 0x95C8, 0xBE70, 0xBBA3, 0xBE71, 0xBBA4, 0xBE72, 0x95C9, 0xBE73, 0xBBA5, 0xBE74, 0xBBA6, 0xBE75, 0xBBA7, 0xBE76, 0x95CA, 0xBE77, 0x95CB, 0xBE78, 0x95CC, 0xBE79, 0x95CD, 0xBE7A, 0x95CE, 0xBE7B, 0xBBA8, 0xBE7C, 0xBBA9, 0xBE7D, 0xBBAA, 0xBE7E, 0x95CF, 0xBE7F, 0x95D0, 0xBE80, 0xBBAB, 0xBE81, 0x95D1, 0xBE82, 0x95D2, 0xBE83, 0x95D3, 0xBE84, 0xBBAC, 0xBE85, 0x95D4, 0xBE86, 0x95D5, 0xBE87, 0x95D6, 0xBE88, 0x95D7, 0xBE89, 0x95D8, 0xBE8A, 0x95D9, 0xBE8B, 0x95DA, 0xBE8C, 0xBBAD, 0xBE8D, 0xBBAE, 0xBE8E, 0x95DB, 0xBE8F, 0xBBAF, 0xBE90, 0xBBB0, 0xBE91, 0xBBB1, 0xBE92, 0x95DC, 0xBE93, 0x95DD, 0xBE94, 0x95DE, 0xBE95, 0x95DF, 0xBE96, 0x95E0, 0xBE97, 0x95E1, 0xBE98, 0xBBB2, 0xBE99, 0xBBB3, 0xBE9A, 0x95E2, 0xBE9B, 0x95E3, 0xBE9C, 0x95E4, 0xBE9D, 0x95E5, 0xBE9E, 0x95E6, 0xBE9F, 0x95E7, 0xBEA0, 0x95E8, 0xBEA1, 0x95E9, 0xBEA2, 0x95EA, 0xBEA3, 0x95EB, 0xBEA4, 0x95EC, 0xBEA5, 0x95ED, 0xBEA6, 0x95EE, 0xBEA7, 0x95EF, 0xBEA8, 0xBBB4, 0xBEA9, 0x95F0, 0xBEAA, 0x95F1, 0xBEAB, 0x95F2, 0xBEAC, 0x95F3, 0xBEAD, 0x95F4, 0xBEAE, 0x95F5, 0xBEAF, 0x95F6, 0xBEB0, 0x95F7, 0xBEB1, 0x95F8, 0xBEB2, 0x95F9, 0xBEB3, 0x95FA, 0xBEB4, 0x95FB, 0xBEB5, 0x95FC, 0xBEB6, 0x95FD, 0xBEB7, 0x95FE, 0xBEB8, 0x9641, 0xBEB9, 0x9642, 0xBEBA, 0x9643, 0xBEBB, 0x9644, 0xBEBC, 0x9645, 0xBEBD, 0x9646, 0xBEBE, 0x9647, 0xBEBF, 0x9648, 0xBEC0, 0x9649, 0xBEC1, 0x964A, 0xBEC2, 0x964B, 0xBEC3, 0x964C, 0xBEC4, 0x964D, 0xBEC5, 0x964E, 0xBEC6, 0x964F, 0xBEC7, 0x9650, 0xBEC8, 0x9651, 0xBEC9, 0x9652, 0xBECA, 0x9653, 0xBECB, 0x9654, 0xBECC, 0x9655, 0xBECD, 0x9656, 0xBECE, 0x9657, 0xBECF, 0x9658, 0xBED0, 0xBBB5, 0xBED1, 0xBBB6, 0xBED2, 0x9659, 0xBED3, 0x965A, 0xBED4, 0xBBB7, 0xBED5, 0x9661, 0xBED6, 0x9662, 0xBED7, 0xBBB8, 0xBED8, 0xBBB9, 0xBED9, 0x9663, 0xBEDA, 0x9664, 0xBEDB, 0x9665, 0xBEDC, 0x9666, 0xBEDD, 0x9667, 0xBEDE, 0x9668, 0xBEDF, 0x9669, 0xBEE0, 0xBBBA, 0xBEE1, 0x966A, 0xBEE2, 0x966B, 0xBEE3, 0xBBBB, 0xBEE4, 0xBBBC, 0xBEE5, 0xBBBD, 0xBEE6, 0x966C, 0xBEE7, 0x966D, 0xBEE8, 0x966E, 0xBEE9, 0x966F, 0xBEEA, 0x9670, 0xBEEB, 0x9671, 0xBEEC, 0xBBBE, 0xBEED, 0x9672, 0xBEEE, 0x9673, 0xBEEF, 0x9674, 0xBEF0, 0x9675, 0xBEF1, 0x9676, 0xBEF2, 0x9677, 0xBEF3, 0x9678, 0xBEF4, 0x9679, 0xBEF5, 0x967A, 0xBEF6, 0x9681, 0xBEF7, 0x9682, 0xBEF8, 0x9683, 0xBEF9, 0x9684, 0xBEFA, 0x9685, 0xBEFB, 0x9686, 0xBEFC, 0x9687, 0xBEFD, 0x9688, 0xBEFE, 0x9689, 0xBEFF, 0x968A, 0xBF00, 0x968B, 0xBF01, 0xBBBF, 0xBF02, 0x968C, 0xBF03, 0x968D, 0xBF04, 0x968E, 0xBF05, 0x968F, 0xBF06, 0x9690, 0xBF07, 0x9691, 0xBF08, 0xBBC0, 0xBF09, 0xBBC1, 0xBF0A, 0x9692, 0xBF0B, 0x9693, 0xBF0C, 0x9694, 0xBF0D, 0x9695, 0xBF0E, 0x9696, 0xBF0F, 0x9697, 0xBF10, 0x9698, 0xBF11, 0x9699, 0xBF12, 0x969A, 0xBF13, 0x969B, 0xBF14, 0x969C, 0xBF15, 0x969D, 0xBF16, 0x969E, 0xBF17, 0x969F, 0xBF18, 0xBBC2, 0xBF19, 0xBBC3, 0xBF1A, 0x96A0, 0xBF1B, 0xBBC4, 0xBF1C, 0xBBC5, 0xBF1D, 0xBBC6, 0xBF1E, 0x96A1, 0xBF1F, 0x96A2, 0xBF20, 0x96A3, 0xBF21, 0x96A4, 0xBF22, 0x96A5, 0xBF23, 0x96A6, 0xBF24, 0x96A7, 0xBF25, 0x96A8, 0xBF26, 0x96A9, 0xBF27, 0x96AA, 0xBF28, 0x96AB, 0xBF29, 0x96AC, 0xBF2A, 0x96AD, 0xBF2B, 0x96AE, 0xBF2C, 0x96AF, 0xBF2D, 0x96B0, 0xBF2E, 0x96B1, 0xBF2F, 0x96B2, 0xBF30, 0x96B3, 0xBF31, 0x96B4, 0xBF32, 0x96B5, 0xBF33, 0x96B6, 0xBF34, 0x96B7, 0xBF35, 0x96B8, 0xBF36, 0x96B9, 0xBF37, 0x96BA, 0xBF38, 0x96BB, 0xBF39, 0x96BC, 0xBF3A, 0x96BD, 0xBF3B, 0x96BE, 0xBF3C, 0x96BF, 0xBF3D, 0x96C0, 0xBF3E, 0x96C1, 0xBF3F, 0x96C2, 0xBF40, 0xBBC7, 0xBF41, 0xBBC8, 0xBF42, 0x96C3, 0xBF43, 0x96C4, 0xBF44, 0xBBC9, 0xBF45, 0x96C5, 0xBF46, 0x96C6, 0xBF47, 0x96C7, 0xBF48, 0xBBCA, 0xBF49, 0x96C8, 0xBF4A, 0x96C9, 0xBF4B, 0x96CA, 0xBF4C, 0x96CB, 0xBF4D, 0x96CC, 0xBF4E, 0x96CD, 0xBF4F, 0x96CE, 0xBF50, 0xBBCB, 0xBF51, 0xBBCC, 0xBF52, 0x96CF, 0xBF53, 0x96D0, 0xBF54, 0x96D1, 0xBF55, 0xBBCD, 0xBF56, 0x96D2, 0xBF57, 0x96D3, 0xBF58, 0x96D4, 0xBF59, 0x96D5, 0xBF5A, 0x96D6, 0xBF5B, 0x96D7, 0xBF5C, 0x96D8, 0xBF5D, 0x96D9, 0xBF5E, 0x96DA, 0xBF5F, 0x96DB, 0xBF60, 0x96DC, 0xBF61, 0x96DD, 0xBF62, 0x96DE, 0xBF63, 0x96DF, 0xBF64, 0x96E0, 0xBF65, 0x96E1, 0xBF66, 0x96E2, 0xBF67, 0x96E3, 0xBF68, 0x96E4, 0xBF69, 0x96E5, 0xBF6A, 0x96E6, 0xBF6B, 0x96E7, 0xBF6C, 0x96E8, 0xBF6D, 0x96E9, 0xBF6E, 0x96EA, 0xBF6F, 0x96EB, 0xBF70, 0x96EC, 0xBF71, 0x96ED, 0xBF72, 0x96EE, 0xBF73, 0x96EF, 0xBF74, 0x96F0, 0xBF75, 0x96F1, 0xBF76, 0x96F2, 0xBF77, 0x96F3, 0xBF78, 0x96F4, 0xBF79, 0x96F5, 0xBF7A, 0x96F6, 0xBF7B, 0x96F7, 0xBF7C, 0x96F8, 0xBF7D, 0x96F9, 0xBF7E, 0x96FA, 0xBF7F, 0x96FB, 0xBF80, 0x96FC, 0xBF81, 0x96FD, 0xBF82, 0x96FE, 0xBF83, 0x9741, 0xBF84, 0x9742, 0xBF85, 0x9743, 0xBF86, 0x9744, 0xBF87, 0x9745, 0xBF88, 0x9746, 0xBF89, 0x9747, 0xBF8A, 0x9748, 0xBF8B, 0x9749, 0xBF8C, 0x974A, 0xBF8D, 0x974B, 0xBF8E, 0x974C, 0xBF8F, 0x974D, 0xBF90, 0x974E, 0xBF91, 0x974F, 0xBF92, 0x9750, 0xBF93, 0x9751, 0xBF94, 0xBBCE, 0xBF95, 0x9752, 0xBF96, 0x9753, 0xBF97, 0x9754, 0xBF98, 0x9755, 0xBF99, 0x9756, 0xBF9A, 0x9757, 0xBF9B, 0x9758, 0xBF9C, 0x9759, 0xBF9D, 0x975A, 0xBF9E, 0x9761, 0xBF9F, 0x9762, 0xBFA0, 0x9763, 0xBFA1, 0x9764, 0xBFA2, 0x9765, 0xBFA3, 0x9766, 0xBFA4, 0x9767, 0xBFA5, 0x9768, 0xBFA6, 0x9769, 0xBFA7, 0x976A, 0xBFA8, 0x976B, 0xBFA9, 0x976C, 0xBFAA, 0x976D, 0xBFAB, 0x976E, 0xBFAC, 0x976F, 0xBFAD, 0x9770, 0xBFAE, 0x9771, 0xBFAF, 0x9772, 0xBFB0, 0xBBCF, 0xBFB1, 0x9773, 0xBFB2, 0x9774, 0xBFB3, 0x9775, 0xBFB4, 0x9776, 0xBFB5, 0x9777, 0xBFB6, 0x9778, 0xBFB7, 0x9779, 0xBFB8, 0x977A, 0xBFB9, 0x9781, 0xBFBA, 0x9782, 0xBFBB, 0x9783, 0xBFBC, 0x9784, 0xBFBD, 0x9785, 0xBFBE, 0x9786, 0xBFBF, 0x9787, 0xBFC0, 0x9788, 0xBFC1, 0x9789, 0xBFC2, 0x978A, 0xBFC3, 0x978B, 0xBFC4, 0x978C, 0xBFC5, 0xBBD0, 0xBFC6, 0x978D, 0xBFC7, 0x978E, 0xBFC8, 0x978F, 0xBFC9, 0x9790, 0xBFCA, 0x9791, 0xBFCB, 0x9792, 0xBFCC, 0xBBD1, 0xBFCD, 0xBBD2, 0xBFCE, 0x9793, 0xBFCF, 0x9794, 0xBFD0, 0xBBD3, 0xBFD1, 0x9795, 0xBFD2, 0x9796, 0xBFD3, 0x9797, 0xBFD4, 0xBBD4, 0xBFD5, 0x9798, 0xBFD6, 0x9799, 0xBFD7, 0x979A, 0xBFD8, 0x979B, 0xBFD9, 0x979C, 0xBFDA, 0x979D, 0xBFDB, 0x979E, 0xBFDC, 0xBBD5, 0xBFDD, 0x979F, 0xBFDE, 0x97A0, 0xBFDF, 0xBBD6, 0xBFE0, 0x97A1, 0xBFE1, 0xBBD7, 0xBFE2, 0x97A2, 0xBFE3, 0x97A3, 0xBFE4, 0x97A4, 0xBFE5, 0x97A5, 0xBFE6, 0x97A6, 0xBFE7, 0x97A7, 0xBFE8, 0x97A8, 0xBFE9, 0x97A9, 0xBFEA, 0x97AA, 0xBFEB, 0x97AB, 0xBFEC, 0x97AC, 0xBFED, 0x97AD, 0xBFEE, 0x97AE, 0xBFEF, 0x97AF, 0xBFF0, 0x97B0, 0xBFF1, 0x97B1, 0xBFF2, 0x97B2, 0xBFF3, 0x97B3, 0xBFF4, 0x97B4, 0xBFF5, 0x97B5, 0xBFF6, 0x97B6, 0xBFF7, 0x97B7, 0xBFF8, 0x97B8, 0xBFF9, 0x97B9, 0xBFFA, 0x97BA, 0xBFFB, 0x97BB, 0xBFFC, 0x97BC, 0xBFFD, 0x97BD, 0xBFFE, 0x97BE, 0xBFFF, 0x97BF, 0xC000, 0x97C0, 0xC001, 0x97C1, 0xC002, 0x97C2, 0xC003, 0x97C3, 0xC004, 0x97C4, 0xC005, 0x97C5, 0xC006, 0x97C6, 0xC007, 0x97C7, 0xC008, 0x97C8, 0xC009, 0x97C9, 0xC00A, 0x97CA, 0xC00B, 0x97CB, 0xC00C, 0x97CC, 0xC00D, 0x97CD, 0xC00E, 0x97CE, 0xC00F, 0x97CF, 0xC010, 0x97D0, 0xC011, 0x97D1, 0xC012, 0x97D2, 0xC013, 0x97D3, 0xC014, 0x97D4, 0xC015, 0x97D5, 0xC016, 0x97D6, 0xC017, 0x97D7, 0xC018, 0x97D8, 0xC019, 0x97D9, 0xC01A, 0x97DA, 0xC01B, 0x97DB, 0xC01C, 0x97DC, 0xC01D, 0x97DD, 0xC01E, 0x97DE, 0xC01F, 0x97DF, 0xC020, 0x97E0, 0xC021, 0x97E1, 0xC022, 0x97E2, 0xC023, 0x97E3, 0xC024, 0x97E4, 0xC025, 0x97E5, 0xC026, 0x97E6, 0xC027, 0x97E7, 0xC028, 0x97E8, 0xC029, 0x97E9, 0xC02A, 0x97EA, 0xC02B, 0x97EB, 0xC02C, 0x97EC, 0xC02D, 0x97ED, 0xC02E, 0x97EE, 0xC02F, 0x97EF, 0xC030, 0x97F0, 0xC031, 0x97F1, 0xC032, 0x97F2, 0xC033, 0x97F3, 0xC034, 0x97F4, 0xC035, 0x97F5, 0xC036, 0x97F6, 0xC037, 0x97F7, 0xC038, 0x97F8, 0xC039, 0x97F9, 0xC03A, 0x97FA, 0xC03B, 0x97FB, 0xC03C, 0xBBD8, 0xC03D, 0x97FC, 0xC03E, 0x97FD, 0xC03F, 0x97FE, 0xC040, 0x9841, 0xC041, 0x9842, 0xC042, 0x9843, 0xC043, 0x9844, 0xC044, 0x9845, 0xC045, 0x9846, 0xC046, 0x9847, 0xC047, 0x9848, 0xC048, 0x9849, 0xC049, 0x984A, 0xC04A, 0x984B, 0xC04B, 0x984C, 0xC04C, 0x984D, 0xC04D, 0x984E, 0xC04E, 0x984F, 0xC04F, 0x9850, 0xC050, 0x9851, 0xC051, 0xBBD9, 0xC052, 0x9852, 0xC053, 0x9853, 0xC054, 0x9854, 0xC055, 0x9855, 0xC056, 0x9856, 0xC057, 0x9857, 0xC058, 0xBBDA, 0xC059, 0x9858, 0xC05A, 0x9859, 0xC05B, 0x985A, 0xC05C, 0xBBDB, 0xC05D, 0x9861, 0xC05E, 0x9862, 0xC05F, 0x9863, 0xC060, 0xBBDC, 0xC061, 0x9864, 0xC062, 0x9865, 0xC063, 0x9866, 0xC064, 0x9867, 0xC065, 0x9868, 0xC066, 0x9869, 0xC067, 0x986A, 0xC068, 0xBBDD, 0xC069, 0xBBDE, 0xC06A, 0x986B, 0xC06B, 0x986C, 0xC06C, 0x986D, 0xC06D, 0x986E, 0xC06E, 0x986F, 0xC06F, 0x9870, 0xC070, 0x9871, 0xC071, 0x9872, 0xC072, 0x9873, 0xC073, 0x9874, 0xC074, 0x9875, 0xC075, 0x9876, 0xC076, 0x9877, 0xC077, 0x9878, 0xC078, 0x9879, 0xC079, 0x987A, 0xC07A, 0x9881, 0xC07B, 0x9882, 0xC07C, 0x9883, 0xC07D, 0x9884, 0xC07E, 0x9885, 0xC07F, 0x9886, 0xC080, 0x9887, 0xC081, 0x9888, 0xC082, 0x9889, 0xC083, 0x988A, 0xC084, 0x988B, 0xC085, 0x988C, 0xC086, 0x988D, 0xC087, 0x988E, 0xC088, 0x988F, 0xC089, 0x9890, 0xC08A, 0x9891, 0xC08B, 0x9892, 0xC08C, 0x9893, 0xC08D, 0x9894, 0xC08E, 0x9895, 0xC08F, 0x9896, 0xC090, 0xBBDF, 0xC091, 0xBBE0, 0xC092, 0x9897, 0xC093, 0x9898, 0xC094, 0xBBE1, 0xC095, 0x9899, 0xC096, 0x989A, 0xC097, 0x989B, 0xC098, 0xBBE2, 0xC099, 0x989C, 0xC09A, 0x989D, 0xC09B, 0x989E, 0xC09C, 0x989F, 0xC09D, 0x98A0, 0xC09E, 0x98A1, 0xC09F, 0x98A2, 0xC0A0, 0xBBE3, 0xC0A1, 0xBBE4, 0xC0A2, 0x98A3, 0xC0A3, 0xBBE5, 0xC0A4, 0x98A4, 0xC0A5, 0xBBE6, 0xC0A6, 0x98A5, 0xC0A7, 0x98A6, 0xC0A8, 0x98A7, 0xC0A9, 0x98A8, 0xC0AA, 0x98A9, 0xC0AB, 0x98AA, 0xC0AC, 0xBBE7, 0xC0AD, 0xBBE8, 0xC0AE, 0x98AB, 0xC0AF, 0xBBE9, 0xC0B0, 0xBBEA, 0xC0B1, 0x98AC, 0xC0B2, 0x98AD, 0xC0B3, 0xBBEB, 0xC0B4, 0xBBEC, 0xC0B5, 0xBBED, 0xC0B6, 0xBBEE, 0xC0B7, 0x98AE, 0xC0B8, 0x98AF, 0xC0B9, 0x98B0, 0xC0BA, 0x98B1, 0xC0BB, 0x98B2, 0xC0BC, 0xBBEF, 0xC0BD, 0xBBF0, 0xC0BE, 0x98B3, 0xC0BF, 0xBBF1, 0xC0C0, 0xBBF2, 0xC0C1, 0xBBF3, 0xC0C2, 0x98B4, 0xC0C3, 0x98B5, 0xC0C4, 0x98B6, 0xC0C5, 0xBBF4, 0xC0C6, 0x98B7, 0xC0C7, 0x98B8, 0xC0C8, 0xBBF5, 0xC0C9, 0xBBF6, 0xC0CA, 0x98B9, 0xC0CB, 0x98BA, 0xC0CC, 0xBBF7, 0xC0CD, 0x98BB, 0xC0CE, 0x98BC, 0xC0CF, 0x98BD, 0xC0D0, 0xBBF8, 0xC0D1, 0x98BE, 0xC0D2, 0x98BF, 0xC0D3, 0x98C0, 0xC0D4, 0x98C1, 0xC0D5, 0x98C2, 0xC0D6, 0x98C3, 0xC0D7, 0x98C4, 0xC0D8, 0xBBF9, 0xC0D9, 0xBBFA, 0xC0DA, 0x98C5, 0xC0DB, 0xBBFB, 0xC0DC, 0xBBFC, 0xC0DD, 0xBBFD, 0xC0DE, 0x98C6, 0xC0DF, 0x98C7, 0xC0E0, 0x98C8, 0xC0E1, 0x98C9, 0xC0E2, 0x98CA, 0xC0E3, 0x98CB, 0xC0E4, 0xBBFE, 0xC0E5, 0xBCA1, 0xC0E6, 0x98CC, 0xC0E7, 0x98CD, 0xC0E8, 0xBCA2, 0xC0E9, 0x98CE, 0xC0EA, 0x98CF, 0xC0EB, 0x98D0, 0xC0EC, 0xBCA3, 0xC0ED, 0x98D1, 0xC0EE, 0x98D2, 0xC0EF, 0x98D3, 0xC0F0, 0x98D4, 0xC0F1, 0x98D5, 0xC0F2, 0x98D6, 0xC0F3, 0x98D7, 0xC0F4, 0xBCA4, 0xC0F5, 0xBCA5, 0xC0F6, 0x98D8, 0xC0F7, 0xBCA6, 0xC0F8, 0x98D9, 0xC0F9, 0xBCA7, 0xC0FA, 0x98DA, 0xC0FB, 0x98DB, 0xC0FC, 0x98DC, 0xC0FD, 0x98DD, 0xC0FE, 0x98DE, 0xC0FF, 0x98DF, 0xC100, 0xBCA8, 0xC101, 0x98E0, 0xC102, 0x98E1, 0xC103, 0x98E2, 0xC104, 0xBCA9, 0xC105, 0x98E3, 0xC106, 0x98E4, 0xC107, 0x98E5, 0xC108, 0xBCAA, 0xC109, 0x98E6, 0xC10A, 0x98E7, 0xC10B, 0x98E8, 0xC10C, 0x98E9, 0xC10D, 0x98EA, 0xC10E, 0x98EB, 0xC10F, 0x98EC, 0xC110, 0xBCAB, 0xC111, 0x98ED, 0xC112, 0x98EE, 0xC113, 0x98EF, 0xC114, 0x98F0, 0xC115, 0xBCAC, 0xC116, 0x98F1, 0xC117, 0x98F2, 0xC118, 0x98F3, 0xC119, 0x98F4, 0xC11A, 0x98F5, 0xC11B, 0x98F6, 0xC11C, 0xBCAD, 0xC11D, 0xBCAE, 0xC11E, 0xBCAF, 0xC11F, 0xBCB0, 0xC120, 0xBCB1, 0xC121, 0x98F7, 0xC122, 0x98F8, 0xC123, 0xBCB2, 0xC124, 0xBCB3, 0xC125, 0x98F9, 0xC126, 0xBCB4, 0xC127, 0xBCB5, 0xC128, 0x98FA, 0xC129, 0x98FB, 0xC12A, 0x98FC, 0xC12B, 0x98FD, 0xC12C, 0xBCB6, 0xC12D, 0xBCB7, 0xC12E, 0x98FE, 0xC12F, 0xBCB8, 0xC130, 0xBCB9, 0xC131, 0xBCBA, 0xC132, 0x9941, 0xC133, 0x9942, 0xC134, 0x9943, 0xC135, 0x9944, 0xC136, 0xBCBB, 0xC137, 0x9945, 0xC138, 0xBCBC, 0xC139, 0xBCBD, 0xC13A, 0x9946, 0xC13B, 0x9947, 0xC13C, 0xBCBE, 0xC13D, 0x9948, 0xC13E, 0x9949, 0xC13F, 0x994A, 0xC140, 0xBCBF, 0xC141, 0x994B, 0xC142, 0x994C, 0xC143, 0x994D, 0xC144, 0x994E, 0xC145, 0x994F, 0xC146, 0x9950, 0xC147, 0x9951, 0xC148, 0xBCC0, 0xC149, 0xBCC1, 0xC14A, 0x9952, 0xC14B, 0xBCC2, 0xC14C, 0xBCC3, 0xC14D, 0xBCC4, 0xC14E, 0x9953, 0xC14F, 0x9954, 0xC150, 0x9955, 0xC151, 0x9956, 0xC152, 0x9957, 0xC153, 0x9958, 0xC154, 0xBCC5, 0xC155, 0xBCC6, 0xC156, 0x9959, 0xC157, 0x995A, 0xC158, 0xBCC7, 0xC159, 0x9961, 0xC15A, 0x9962, 0xC15B, 0x9963, 0xC15C, 0xBCC8, 0xC15D, 0x9964, 0xC15E, 0x9965, 0xC15F, 0x9966, 0xC160, 0x9967, 0xC161, 0x9968, 0xC162, 0x9969, 0xC163, 0x996A, 0xC164, 0xBCC9, 0xC165, 0xBCCA, 0xC166, 0x996B, 0xC167, 0xBCCB, 0xC168, 0xBCCC, 0xC169, 0xBCCD, 0xC16A, 0x996C, 0xC16B, 0x996D, 0xC16C, 0x996E, 0xC16D, 0x996F, 0xC16E, 0x9970, 0xC16F, 0x9971, 0xC170, 0xBCCE, 0xC171, 0x9972, 0xC172, 0x9973, 0xC173, 0x9974, 0xC174, 0xBCCF, 0xC175, 0x9975, 0xC176, 0x9976, 0xC177, 0x9977, 0xC178, 0xBCD0, 0xC179, 0x9978, 0xC17A, 0x9979, 0xC17B, 0x997A, 0xC17C, 0x9981, 0xC17D, 0x9982, 0xC17E, 0x9983, 0xC17F, 0x9984, 0xC180, 0x9985, 0xC181, 0x9986, 0xC182, 0x9987, 0xC183, 0x9988, 0xC184, 0x9989, 0xC185, 0xBCD1, 0xC186, 0x998A, 0xC187, 0x998B, 0xC188, 0x998C, 0xC189, 0x998D, 0xC18A, 0x998E, 0xC18B, 0x998F, 0xC18C, 0xBCD2, 0xC18D, 0xBCD3, 0xC18E, 0xBCD4, 0xC18F, 0x9990, 0xC190, 0xBCD5, 0xC191, 0x9991, 0xC192, 0x9992, 0xC193, 0x9993, 0xC194, 0xBCD6, 0xC195, 0x9994, 0xC196, 0xBCD7, 0xC197, 0x9995, 0xC198, 0x9996, 0xC199, 0x9997, 0xC19A, 0x9998, 0xC19B, 0x9999, 0xC19C, 0xBCD8, 0xC19D, 0xBCD9, 0xC19E, 0x999A, 0xC19F, 0xBCDA, 0xC1A0, 0x999B, 0xC1A1, 0xBCDB, 0xC1A2, 0x999C, 0xC1A3, 0x999D, 0xC1A4, 0x999E, 0xC1A5, 0xBCDC, 0xC1A6, 0x999F, 0xC1A7, 0x99A0, 0xC1A8, 0xBCDD, 0xC1A9, 0xBCDE, 0xC1AA, 0x99A1, 0xC1AB, 0x99A2, 0xC1AC, 0xBCDF, 0xC1AD, 0x99A3, 0xC1AE, 0x99A4, 0xC1AF, 0x99A5, 0xC1B0, 0xBCE0, 0xC1B1, 0x99A6, 0xC1B2, 0x99A7, 0xC1B3, 0x99A8, 0xC1B4, 0x99A9, 0xC1B5, 0x99AA, 0xC1B6, 0x99AB, 0xC1B7, 0x99AC, 0xC1B8, 0x99AD, 0xC1B9, 0x99AE, 0xC1BA, 0x99AF, 0xC1BB, 0x99B0, 0xC1BC, 0x99B1, 0xC1BD, 0xBCE1, 0xC1BE, 0x99B2, 0xC1BF, 0x99B3, 0xC1C0, 0x99B4, 0xC1C1, 0x99B5, 0xC1C2, 0x99B6, 0xC1C3, 0x99B7, 0xC1C4, 0xBCE2, 0xC1C5, 0x99B8, 0xC1C6, 0x99B9, 0xC1C7, 0x99BA, 0xC1C8, 0xBCE3, 0xC1C9, 0x99BB, 0xC1CA, 0x99BC, 0xC1CB, 0x99BD, 0xC1CC, 0xBCE4, 0xC1CD, 0x99BE, 0xC1CE, 0x99BF, 0xC1CF, 0x99C0, 0xC1D0, 0x99C1, 0xC1D1, 0x99C2, 0xC1D2, 0x99C3, 0xC1D3, 0x99C4, 0xC1D4, 0xBCE5, 0xC1D5, 0x99C5, 0xC1D6, 0x99C6, 0xC1D7, 0xBCE6, 0xC1D8, 0xBCE7, 0xC1D9, 0x99C7, 0xC1DA, 0x99C8, 0xC1DB, 0x99C9, 0xC1DC, 0x99CA, 0xC1DD, 0x99CB, 0xC1DE, 0x99CC, 0xC1DF, 0x99CD, 0xC1E0, 0xBCE8, 0xC1E1, 0x99CE, 0xC1E2, 0x99CF, 0xC1E3, 0x99D0, 0xC1E4, 0xBCE9, 0xC1E5, 0x99D1, 0xC1E6, 0x99D2, 0xC1E7, 0x99D3, 0xC1E8, 0xBCEA, 0xC1E9, 0x99D4, 0xC1EA, 0x99D5, 0xC1EB, 0x99D6, 0xC1EC, 0x99D7, 0xC1ED, 0x99D8, 0xC1EE, 0x99D9, 0xC1EF, 0x99DA, 0xC1F0, 0xBCEB, 0xC1F1, 0xBCEC, 0xC1F2, 0x99DB, 0xC1F3, 0xBCED, 0xC1F4, 0x99DC, 0xC1F5, 0x99DD, 0xC1F6, 0x99DE, 0xC1F7, 0x99DF, 0xC1F8, 0x99E0, 0xC1F9, 0x99E1, 0xC1FA, 0x99E2, 0xC1FB, 0x99E3, 0xC1FC, 0xBCEE, 0xC1FD, 0xBCEF, 0xC1FE, 0x99E4, 0xC1FF, 0x99E5, 0xC200, 0xBCF0, 0xC201, 0x99E6, 0xC202, 0x99E7, 0xC203, 0x99E8, 0xC204, 0xBCF1, 0xC205, 0x99E9, 0xC206, 0x99EA, 0xC207, 0x99EB, 0xC208, 0x99EC, 0xC209, 0x99ED, 0xC20A, 0x99EE, 0xC20B, 0x99EF, 0xC20C, 0xBCF2, 0xC20D, 0xBCF3, 0xC20E, 0x99F0, 0xC20F, 0xBCF4, 0xC210, 0x99F1, 0xC211, 0xBCF5, 0xC212, 0x99F2, 0xC213, 0x99F3, 0xC214, 0x99F4, 0xC215, 0x99F5, 0xC216, 0x99F6, 0xC217, 0x99F7, 0xC218, 0xBCF6, 0xC219, 0xBCF7, 0xC21A, 0x99F8, 0xC21B, 0x99F9, 0xC21C, 0xBCF8, 0xC21D, 0x99FA, 0xC21E, 0x99FB, 0xC21F, 0xBCF9, 0xC220, 0xBCFA, 0xC221, 0x99FC, 0xC222, 0x99FD, 0xC223, 0x99FE, 0xC224, 0x9A41, 0xC225, 0x9A42, 0xC226, 0x9A43, 0xC227, 0x9A44, 0xC228, 0xBCFB, 0xC229, 0xBCFC, 0xC22A, 0x9A45, 0xC22B, 0xBCFD, 0xC22C, 0x9A46, 0xC22D, 0xBCFE, 0xC22E, 0x9A47, 0xC22F, 0xBDA1, 0xC230, 0x9A48, 0xC231, 0xBDA2, 0xC232, 0xBDA3, 0xC233, 0x9A49, 0xC234, 0xBDA4, 0xC235, 0x9A4A, 0xC236, 0x9A4B, 0xC237, 0x9A4C, 0xC238, 0x9A4D, 0xC239, 0x9A4E, 0xC23A, 0x9A4F, 0xC23B, 0x9A50, 0xC23C, 0x9A51, 0xC23D, 0x9A52, 0xC23E, 0x9A53, 0xC23F, 0x9A54, 0xC240, 0x9A55, 0xC241, 0x9A56, 0xC242, 0x9A57, 0xC243, 0x9A58, 0xC244, 0x9A59, 0xC245, 0x9A5A, 0xC246, 0x9A61, 0xC247, 0x9A62, 0xC248, 0xBDA5, 0xC249, 0x9A63, 0xC24A, 0x9A64, 0xC24B, 0x9A65, 0xC24C, 0x9A66, 0xC24D, 0x9A67, 0xC24E, 0x9A68, 0xC24F, 0x9A69, 0xC250, 0xBDA6, 0xC251, 0xBDA7, 0xC252, 0x9A6A, 0xC253, 0x9A6B, 0xC254, 0xBDA8, 0xC255, 0x9A6C, 0xC256, 0x9A6D, 0xC257, 0x9A6E, 0xC258, 0xBDA9, 0xC259, 0x9A6F, 0xC25A, 0x9A70, 0xC25B, 0x9A71, 0xC25C, 0x9A72, 0xC25D, 0x9A73, 0xC25E, 0x9A74, 0xC25F, 0x9A75, 0xC260, 0xBDAA, 0xC261, 0x9A76, 0xC262, 0x9A77, 0xC263, 0x9A78, 0xC264, 0x9A79, 0xC265, 0xBDAB, 0xC266, 0x9A7A, 0xC267, 0x9A81, 0xC268, 0x9A82, 0xC269, 0x9A83, 0xC26A, 0x9A84, 0xC26B, 0x9A85, 0xC26C, 0xBDAC, 0xC26D, 0xBDAD, 0xC26E, 0x9A86, 0xC26F, 0x9A87, 0xC270, 0xBDAE, 0xC271, 0x9A88, 0xC272, 0x9A89, 0xC273, 0x9A8A, 0xC274, 0xBDAF, 0xC275, 0x9A8B, 0xC276, 0x9A8C, 0xC277, 0x9A8D, 0xC278, 0x9A8E, 0xC279, 0x9A8F, 0xC27A, 0x9A90, 0xC27B, 0x9A91, 0xC27C, 0xBDB0, 0xC27D, 0xBDB1, 0xC27E, 0x9A92, 0xC27F, 0xBDB2, 0xC280, 0x9A93, 0xC281, 0xBDB3, 0xC282, 0x9A94, 0xC283, 0x9A95, 0xC284, 0x9A96, 0xC285, 0x9A97, 0xC286, 0x9A98, 0xC287, 0x9A99, 0xC288, 0xBDB4, 0xC289, 0xBDB5, 0xC28A, 0x9A9A, 0xC28B, 0x9A9B, 0xC28C, 0x9A9C, 0xC28D, 0x9A9D, 0xC28E, 0x9A9E, 0xC28F, 0x9A9F, 0xC290, 0xBDB6, 0xC291, 0x9AA0, 0xC292, 0x9AA1, 0xC293, 0x9AA2, 0xC294, 0x9AA3, 0xC295, 0x9AA4, 0xC296, 0x9AA5, 0xC297, 0x9AA6, 0xC298, 0xBDB7, 0xC299, 0x9AA7, 0xC29A, 0x9AA8, 0xC29B, 0xBDB8, 0xC29C, 0x9AA9, 0xC29D, 0xBDB9, 0xC29E, 0x9AAA, 0xC29F, 0x9AAB, 0xC2A0, 0x9AAC, 0xC2A1, 0x9AAD, 0xC2A2, 0x9AAE, 0xC2A3, 0x9AAF, 0xC2A4, 0xBDBA, 0xC2A5, 0xBDBB, 0xC2A6, 0x9AB0, 0xC2A7, 0x9AB1, 0xC2A8, 0xBDBC, 0xC2A9, 0x9AB2, 0xC2AA, 0x9AB3, 0xC2AB, 0x9AB4, 0xC2AC, 0xBDBD, 0xC2AD, 0xBDBE, 0xC2AE, 0x9AB5, 0xC2AF, 0x9AB6, 0xC2B0, 0x9AB7, 0xC2B1, 0x9AB8, 0xC2B2, 0x9AB9, 0xC2B3, 0x9ABA, 0xC2B4, 0xBDBF, 0xC2B5, 0xBDC0, 0xC2B6, 0x9ABB, 0xC2B7, 0xBDC1, 0xC2B8, 0x9ABC, 0xC2B9, 0xBDC2, 0xC2BA, 0x9ABD, 0xC2BB, 0x9ABE, 0xC2BC, 0x9ABF, 0xC2BD, 0x9AC0, 0xC2BE, 0x9AC1, 0xC2BF, 0x9AC2, 0xC2C0, 0x9AC3, 0xC2C1, 0x9AC4, 0xC2C2, 0x9AC5, 0xC2C3, 0x9AC6, 0xC2C4, 0x9AC7, 0xC2C5, 0x9AC8, 0xC2C6, 0x9AC9, 0xC2C7, 0x9ACA, 0xC2C8, 0x9ACB, 0xC2C9, 0x9ACC, 0xC2CA, 0x9ACD, 0xC2CB, 0x9ACE, 0xC2CC, 0x9ACF, 0xC2CD, 0x9AD0, 0xC2CE, 0x9AD1, 0xC2CF, 0x9AD2, 0xC2D0, 0x9AD3, 0xC2D1, 0x9AD4, 0xC2D2, 0x9AD5, 0xC2D3, 0x9AD6, 0xC2D4, 0x9AD7, 0xC2D5, 0x9AD8, 0xC2D6, 0x9AD9, 0xC2D7, 0x9ADA, 0xC2D8, 0x9ADB, 0xC2D9, 0x9ADC, 0xC2DA, 0x9ADD, 0xC2DB, 0x9ADE, 0xC2DC, 0xBDC3, 0xC2DD, 0xBDC4, 0xC2DE, 0x9ADF, 0xC2DF, 0x9AE0, 0xC2E0, 0xBDC5, 0xC2E1, 0x9AE1, 0xC2E2, 0x9AE2, 0xC2E3, 0xBDC6, 0xC2E4, 0xBDC7, 0xC2E5, 0x9AE3, 0xC2E6, 0x9AE4, 0xC2E7, 0x9AE5, 0xC2E8, 0x9AE6, 0xC2E9, 0x9AE7, 0xC2EA, 0x9AE8, 0xC2EB, 0xBDC8, 0xC2EC, 0xBDC9, 0xC2ED, 0xBDCA, 0xC2EE, 0x9AE9, 0xC2EF, 0xBDCB, 0xC2F0, 0x9AEA, 0xC2F1, 0xBDCC, 0xC2F2, 0x9AEB, 0xC2F3, 0x9AEC, 0xC2F4, 0x9AED, 0xC2F5, 0x9AEE, 0xC2F6, 0xBDCD, 0xC2F7, 0x9AEF, 0xC2F8, 0xBDCE, 0xC2F9, 0xBDCF, 0xC2FA, 0x9AF0, 0xC2FB, 0xBDD0, 0xC2FC, 0xBDD1, 0xC2FD, 0x9AF1, 0xC2FE, 0x9AF2, 0xC2FF, 0x9AF3, 0xC300, 0xBDD2, 0xC301, 0x9AF4, 0xC302, 0x9AF5, 0xC303, 0x9AF6, 0xC304, 0x9AF7, 0xC305, 0x9AF8, 0xC306, 0x9AF9, 0xC307, 0x9AFA, 0xC308, 0xBDD3, 0xC309, 0xBDD4, 0xC30A, 0x9AFB, 0xC30B, 0x9AFC, 0xC30C, 0xBDD5, 0xC30D, 0xBDD6, 0xC30E, 0x9AFD, 0xC30F, 0x9AFE, 0xC310, 0x9B41, 0xC311, 0x9B42, 0xC312, 0x9B43, 0xC313, 0xBDD7, 0xC314, 0xBDD8, 0xC315, 0xBDD9, 0xC316, 0x9B44, 0xC317, 0x9B45, 0xC318, 0xBDDA, 0xC319, 0x9B46, 0xC31A, 0x9B47, 0xC31B, 0x9B48, 0xC31C, 0xBDDB, 0xC31D, 0x9B49, 0xC31E, 0x9B4A, 0xC31F, 0x9B4B, 0xC320, 0x9B4C, 0xC321, 0x9B4D, 0xC322, 0x9B4E, 0xC323, 0x9B4F, 0xC324, 0xBDDC, 0xC325, 0xBDDD, 0xC326, 0x9B50, 0xC327, 0x9B51, 0xC328, 0xBDDE, 0xC329, 0xBDDF, 0xC32A, 0x9B52, 0xC32B, 0x9B53, 0xC32C, 0x9B54, 0xC32D, 0x9B55, 0xC32E, 0x9B56, 0xC32F, 0x9B57, 0xC330, 0x9B58, 0xC331, 0x9B59, 0xC332, 0x9B5A, 0xC333, 0x9B61, 0xC334, 0x9B62, 0xC335, 0x9B63, 0xC336, 0x9B64, 0xC337, 0x9B65, 0xC338, 0x9B66, 0xC339, 0x9B67, 0xC33A, 0x9B68, 0xC33B, 0x9B69, 0xC33C, 0x9B6A, 0xC33D, 0x9B6B, 0xC33E, 0x9B6C, 0xC33F, 0x9B6D, 0xC340, 0x9B6E, 0xC341, 0x9B6F, 0xC342, 0x9B70, 0xC343, 0x9B71, 0xC344, 0x9B72, 0xC345, 0xBDE0, 0xC346, 0x9B73, 0xC347, 0x9B74, 0xC348, 0x9B75, 0xC349, 0x9B76, 0xC34A, 0x9B77, 0xC34B, 0x9B78, 0xC34C, 0x9B79, 0xC34D, 0x9B7A, 0xC34E, 0x9B81, 0xC34F, 0x9B82, 0xC350, 0x9B83, 0xC351, 0x9B84, 0xC352, 0x9B85, 0xC353, 0x9B86, 0xC354, 0x9B87, 0xC355, 0x9B88, 0xC356, 0x9B89, 0xC357, 0x9B8A, 0xC358, 0x9B8B, 0xC359, 0x9B8C, 0xC35A, 0x9B8D, 0xC35B, 0x9B8E, 0xC35C, 0x9B8F, 0xC35D, 0x9B90, 0xC35E, 0x9B91, 0xC35F, 0x9B92, 0xC360, 0x9B93, 0xC361, 0x9B94, 0xC362, 0x9B95, 0xC363, 0x9B96, 0xC364, 0x9B97, 0xC365, 0x9B98, 0xC366, 0x9B99, 0xC367, 0x9B9A, 0xC368, 0xBDE1, 0xC369, 0xBDE2, 0xC36A, 0x9B9B, 0xC36B, 0x9B9C, 0xC36C, 0xBDE3, 0xC36D, 0x9B9D, 0xC36E, 0x9B9E, 0xC36F, 0x9B9F, 0xC370, 0xBDE4, 0xC371, 0x9BA0, 0xC372, 0xBDE5, 0xC373, 0x9BA1, 0xC374, 0x9BA2, 0xC375, 0x9BA3, 0xC376, 0x9BA4, 0xC377, 0x9BA5, 0xC378, 0xBDE6, 0xC379, 0xBDE7, 0xC37A, 0x9BA6, 0xC37B, 0x9BA7, 0xC37C, 0xBDE8, 0xC37D, 0xBDE9, 0xC37E, 0x9BA8, 0xC37F, 0x9BA9, 0xC380, 0x9BAA, 0xC381, 0x9BAB, 0xC382, 0x9BAC, 0xC383, 0x9BAD, 0xC384, 0xBDEA, 0xC385, 0x9BAE, 0xC386, 0x9BAF, 0xC387, 0x9BB0, 0xC388, 0xBDEB, 0xC389, 0x9BB1, 0xC38A, 0x9BB2, 0xC38B, 0x9BB3, 0xC38C, 0xBDEC, 0xC38D, 0x9BB4, 0xC38E, 0x9BB5, 0xC38F, 0x9BB6, 0xC390, 0x9BB7, 0xC391, 0x9BB8, 0xC392, 0x9BB9, 0xC393, 0x9BBA, 0xC394, 0x9BBB, 0xC395, 0x9BBC, 0xC396, 0x9BBD, 0xC397, 0x9BBE, 0xC398, 0x9BBF, 0xC399, 0x9BC0, 0xC39A, 0x9BC1, 0xC39B, 0x9BC2, 0xC39C, 0x9BC3, 0xC39D, 0x9BC4, 0xC39E, 0x9BC5, 0xC39F, 0x9BC6, 0xC3A0, 0x9BC7, 0xC3A1, 0x9BC8, 0xC3A2, 0x9BC9, 0xC3A3, 0x9BCA, 0xC3A4, 0x9BCB, 0xC3A5, 0x9BCC, 0xC3A6, 0x9BCD, 0xC3A7, 0x9BCE, 0xC3A8, 0x9BCF, 0xC3A9, 0x9BD0, 0xC3AA, 0x9BD1, 0xC3AB, 0x9BD2, 0xC3AC, 0x9BD3, 0xC3AD, 0x9BD4, 0xC3AE, 0x9BD5, 0xC3AF, 0x9BD6, 0xC3B0, 0x9BD7, 0xC3B1, 0x9BD8, 0xC3B2, 0x9BD9, 0xC3B3, 0x9BDA, 0xC3B4, 0x9BDB, 0xC3B5, 0x9BDC, 0xC3B6, 0x9BDD, 0xC3B7, 0x9BDE, 0xC3B8, 0x9BDF, 0xC3B9, 0x9BE0, 0xC3BA, 0x9BE1, 0xC3BB, 0x9BE2, 0xC3BC, 0x9BE3, 0xC3BD, 0x9BE4, 0xC3BE, 0x9BE5, 0xC3BF, 0x9BE6, 0xC3C0, 0xBDED, 0xC3C1, 0x9BE7, 0xC3C2, 0x9BE8, 0xC3C3, 0x9BE9, 0xC3C4, 0x9BEA, 0xC3C5, 0x9BEB, 0xC3C6, 0x9BEC, 0xC3C7, 0x9BED, 0xC3C8, 0x9BEE, 0xC3C9, 0x9BEF, 0xC3CA, 0x9BF0, 0xC3CB, 0x9BF1, 0xC3CC, 0x9BF2, 0xC3CD, 0x9BF3, 0xC3CE, 0x9BF4, 0xC3CF, 0x9BF5, 0xC3D0, 0x9BF6, 0xC3D1, 0x9BF7, 0xC3D2, 0x9BF8, 0xC3D3, 0x9BF9, 0xC3D4, 0x9BFA, 0xC3D5, 0x9BFB, 0xC3D6, 0x9BFC, 0xC3D7, 0x9BFD, 0xC3D8, 0xBDEE, 0xC3D9, 0xBDEF, 0xC3DA, 0x9BFE, 0xC3DB, 0x9C41, 0xC3DC, 0xBDF0, 0xC3DD, 0x9C42, 0xC3DE, 0x9C43, 0xC3DF, 0xBDF1, 0xC3E0, 0xBDF2, 0xC3E1, 0x9C44, 0xC3E2, 0xBDF3, 0xC3E3, 0x9C45, 0xC3E4, 0x9C46, 0xC3E5, 0x9C47, 0xC3E6, 0x9C48, 0xC3E7, 0x9C49, 0xC3E8, 0xBDF4, 0xC3E9, 0xBDF5, 0xC3EA, 0x9C4A, 0xC3EB, 0x9C4B, 0xC3EC, 0x9C4C, 0xC3ED, 0xBDF6, 0xC3EE, 0x9C4D, 0xC3EF, 0x9C4E, 0xC3F0, 0x9C4F, 0xC3F1, 0x9C50, 0xC3F2, 0x9C51, 0xC3F3, 0x9C52, 0xC3F4, 0xBDF7, 0xC3F5, 0xBDF8, 0xC3F6, 0x9C53, 0xC3F7, 0x9C54, 0xC3F8, 0xBDF9, 0xC3F9, 0x9C55, 0xC3FA, 0x9C56, 0xC3FB, 0x9C57, 0xC3FC, 0x9C58, 0xC3FD, 0x9C59, 0xC3FE, 0x9C5A, 0xC3FF, 0x9C61, 0xC400, 0x9C62, 0xC401, 0x9C63, 0xC402, 0x9C64, 0xC403, 0x9C65, 0xC404, 0x9C66, 0xC405, 0x9C67, 0xC406, 0x9C68, 0xC407, 0x9C69, 0xC408, 0xBDFA, 0xC409, 0x9C6A, 0xC40A, 0x9C6B, 0xC40B, 0x9C6C, 0xC40C, 0x9C6D, 0xC40D, 0x9C6E, 0xC40E, 0x9C6F, 0xC40F, 0x9C70, 0xC410, 0xBDFB, 0xC411, 0x9C71, 0xC412, 0x9C72, 0xC413, 0x9C73, 0xC414, 0x9C74, 0xC415, 0x9C75, 0xC416, 0x9C76, 0xC417, 0x9C77, 0xC418, 0x9C78, 0xC419, 0x9C79, 0xC41A, 0x9C7A, 0xC41B, 0x9C81, 0xC41C, 0x9C82, 0xC41D, 0x9C83, 0xC41E, 0x9C84, 0xC41F, 0x9C85, 0xC420, 0x9C86, 0xC421, 0x9C87, 0xC422, 0x9C88, 0xC423, 0x9C89, 0xC424, 0xBDFC, 0xC425, 0x9C8A, 0xC426, 0x9C8B, 0xC427, 0x9C8C, 0xC428, 0x9C8D, 0xC429, 0x9C8E, 0xC42A, 0x9C8F, 0xC42B, 0x9C90, 0xC42C, 0xBDFD, 0xC42D, 0x9C91, 0xC42E, 0x9C92, 0xC42F, 0x9C93, 0xC430, 0xBDFE, 0xC431, 0x9C94, 0xC432, 0x9C95, 0xC433, 0x9C96, 0xC434, 0xBEA1, 0xC435, 0x9C97, 0xC436, 0x9C98, 0xC437, 0x9C99, 0xC438, 0x9C9A, 0xC439, 0x9C9B, 0xC43A, 0x9C9C, 0xC43B, 0x9C9D, 0xC43C, 0xBEA2, 0xC43D, 0xBEA3, 0xC43E, 0x9C9E, 0xC43F, 0x9C9F, 0xC440, 0x9CA0, 0xC441, 0x9CA1, 0xC442, 0x9CA2, 0xC443, 0x9CA3, 0xC444, 0x9CA4, 0xC445, 0x9CA5, 0xC446, 0x9CA6, 0xC447, 0x9CA7, 0xC448, 0xBEA4, 0xC449, 0x9CA8, 0xC44A, 0x9CA9, 0xC44B, 0x9CAA, 0xC44C, 0x9CAB, 0xC44D, 0x9CAC, 0xC44E, 0x9CAD, 0xC44F, 0x9CAE, 0xC450, 0x9CAF, 0xC451, 0x9CB0, 0xC452, 0x9CB1, 0xC453, 0x9CB2, 0xC454, 0x9CB3, 0xC455, 0x9CB4, 0xC456, 0x9CB5, 0xC457, 0x9CB6, 0xC458, 0x9CB7, 0xC459, 0x9CB8, 0xC45A, 0x9CB9, 0xC45B, 0x9CBA, 0xC45C, 0x9CBB, 0xC45D, 0x9CBC, 0xC45E, 0x9CBD, 0xC45F, 0x9CBE, 0xC460, 0x9CBF, 0xC461, 0x9CC0, 0xC462, 0x9CC1, 0xC463, 0x9CC2, 0xC464, 0xBEA5, 0xC465, 0xBEA6, 0xC466, 0x9CC3, 0xC467, 0x9CC4, 0xC468, 0xBEA7, 0xC469, 0x9CC5, 0xC46A, 0x9CC6, 0xC46B, 0x9CC7, 0xC46C, 0xBEA8, 0xC46D, 0x9CC8, 0xC46E, 0x9CC9, 0xC46F, 0x9CCA, 0xC470, 0x9CCB, 0xC471, 0x9CCC, 0xC472, 0x9CCD, 0xC473, 0x9CCE, 0xC474, 0xBEA9, 0xC475, 0xBEAA, 0xC476, 0x9CCF, 0xC477, 0x9CD0, 0xC478, 0x9CD1, 0xC479, 0xBEAB, 0xC47A, 0x9CD2, 0xC47B, 0x9CD3, 0xC47C, 0x9CD4, 0xC47D, 0x9CD5, 0xC47E, 0x9CD6, 0xC47F, 0x9CD7, 0xC480, 0xBEAC, 0xC481, 0x9CD8, 0xC482, 0x9CD9, 0xC483, 0x9CDA, 0xC484, 0x9CDB, 0xC485, 0x9CDC, 0xC486, 0x9CDD, 0xC487, 0x9CDE, 0xC488, 0x9CDF, 0xC489, 0x9CE0, 0xC48A, 0x9CE1, 0xC48B, 0x9CE2, 0xC48C, 0x9CE3, 0xC48D, 0x9CE4, 0xC48E, 0x9CE5, 0xC48F, 0x9CE6, 0xC490, 0x9CE7, 0xC491, 0x9CE8, 0xC492, 0x9CE9, 0xC493, 0x9CEA, 0xC494, 0xBEAD, 0xC495, 0x9CEB, 0xC496, 0x9CEC, 0xC497, 0x9CED, 0xC498, 0x9CEE, 0xC499, 0x9CEF, 0xC49A, 0x9CF0, 0xC49B, 0x9CF1, 0xC49C, 0xBEAE, 0xC49D, 0x9CF2, 0xC49E, 0x9CF3, 0xC49F, 0x9CF4, 0xC4A0, 0x9CF5, 0xC4A1, 0x9CF6, 0xC4A2, 0x9CF7, 0xC4A3, 0x9CF8, 0xC4A4, 0x9CF9, 0xC4A5, 0x9CFA, 0xC4A6, 0x9CFB, 0xC4A7, 0x9CFC, 0xC4A8, 0x9CFD, 0xC4A9, 0x9CFE, 0xC4AA, 0x9D41, 0xC4AB, 0x9D42, 0xC4AC, 0x9D43, 0xC4AD, 0x9D44, 0xC4AE, 0x9D45, 0xC4AF, 0x9D46, 0xC4B0, 0x9D47, 0xC4B1, 0x9D48, 0xC4B2, 0x9D49, 0xC4B3, 0x9D4A, 0xC4B4, 0x9D4B, 0xC4B5, 0x9D4C, 0xC4B6, 0x9D4D, 0xC4B7, 0x9D4E, 0xC4B8, 0xBEAF, 0xC4B9, 0x9D4F, 0xC4BA, 0x9D50, 0xC4BB, 0x9D51, 0xC4BC, 0xBEB0, 0xC4BD, 0x9D52, 0xC4BE, 0x9D53, 0xC4BF, 0x9D54, 0xC4C0, 0x9D55, 0xC4C1, 0x9D56, 0xC4C2, 0x9D57, 0xC4C3, 0x9D58, 0xC4C4, 0x9D59, 0xC4C5, 0x9D5A, 0xC4C6, 0x9D61, 0xC4C7, 0x9D62, 0xC4C8, 0x9D63, 0xC4C9, 0x9D64, 0xC4CA, 0x9D65, 0xC4CB, 0x9D66, 0xC4CC, 0x9D67, 0xC4CD, 0x9D68, 0xC4CE, 0x9D69, 0xC4CF, 0x9D6A, 0xC4D0, 0x9D6B, 0xC4D1, 0x9D6C, 0xC4D2, 0x9D6D, 0xC4D3, 0x9D6E, 0xC4D4, 0x9D6F, 0xC4D5, 0x9D70, 0xC4D6, 0x9D71, 0xC4D7, 0x9D72, 0xC4D8, 0x9D73, 0xC4D9, 0x9D74, 0xC4DA, 0x9D75, 0xC4DB, 0x9D76, 0xC4DC, 0x9D77, 0xC4DD, 0x9D78, 0xC4DE, 0x9D79, 0xC4DF, 0x9D7A, 0xC4E0, 0x9D81, 0xC4E1, 0x9D82, 0xC4E2, 0x9D83, 0xC4E3, 0x9D84, 0xC4E4, 0x9D85, 0xC4E5, 0x9D86, 0xC4E6, 0x9D87, 0xC4E7, 0x9D88, 0xC4E8, 0x9D89, 0xC4E9, 0xBEB1, 0xC4EA, 0x9D8A, 0xC4EB, 0x9D8B, 0xC4EC, 0x9D8C, 0xC4ED, 0x9D8D, 0xC4EE, 0x9D8E, 0xC4EF, 0x9D8F, 0xC4F0, 0xBEB2, 0xC4F1, 0xBEB3, 0xC4F2, 0x9D90, 0xC4F3, 0x9D91, 0xC4F4, 0xBEB4, 0xC4F5, 0x9D92, 0xC4F6, 0x9D93, 0xC4F7, 0x9D94, 0xC4F8, 0xBEB5, 0xC4F9, 0x9D95, 0xC4FA, 0xBEB6, 0xC4FB, 0x9D96, 0xC4FC, 0x9D97, 0xC4FD, 0x9D98, 0xC4FE, 0x9D99, 0xC4FF, 0xBEB7, 0xC500, 0xBEB8, 0xC501, 0xBEB9, 0xC502, 0x9D9A, 0xC503, 0x9D9B, 0xC504, 0x9D9C, 0xC505, 0x9D9D, 0xC506, 0x9D9E, 0xC507, 0x9D9F, 0xC508, 0x9DA0, 0xC509, 0x9DA1, 0xC50A, 0x9DA2, 0xC50B, 0x9DA3, 0xC50C, 0xBEBA, 0xC50D, 0x9DA4, 0xC50E, 0x9DA5, 0xC50F, 0x9DA6, 0xC510, 0xBEBB, 0xC511, 0x9DA7, 0xC512, 0x9DA8, 0xC513, 0x9DA9, 0xC514, 0xBEBC, 0xC515, 0x9DAA, 0xC516, 0x9DAB, 0xC517, 0x9DAC, 0xC518, 0x9DAD, 0xC519, 0x9DAE, 0xC51A, 0x9DAF, 0xC51B, 0x9DB0, 0xC51C, 0xBEBD, 0xC51D, 0x9DB1, 0xC51E, 0x9DB2, 0xC51F, 0x9DB3, 0xC520, 0x9DB4, 0xC521, 0x9DB5, 0xC522, 0x9DB6, 0xC523, 0x9DB7, 0xC524, 0x9DB8, 0xC525, 0x9DB9, 0xC526, 0x9DBA, 0xC527, 0x9DBB, 0xC528, 0xBEBE, 0xC529, 0xBEBF, 0xC52A, 0x9DBC, 0xC52B, 0x9DBD, 0xC52C, 0xBEC0, 0xC52D, 0x9DBE, 0xC52E, 0x9DBF, 0xC52F, 0x9DC0, 0xC530, 0xBEC1, 0xC531, 0x9DC1, 0xC532, 0x9DC2, 0xC533, 0x9DC3, 0xC534, 0x9DC4, 0xC535, 0x9DC5, 0xC536, 0x9DC6, 0xC537, 0x9DC7, 0xC538, 0xBEC2, 0xC539, 0xBEC3, 0xC53A, 0x9DC8, 0xC53B, 0xBEC4, 0xC53C, 0x9DC9, 0xC53D, 0xBEC5, 0xC53E, 0x9DCA, 0xC53F, 0x9DCB, 0xC540, 0x9DCC, 0xC541, 0x9DCD, 0xC542, 0x9DCE, 0xC543, 0x9DCF, 0xC544, 0xBEC6, 0xC545, 0xBEC7, 0xC546, 0x9DD0, 0xC547, 0x9DD1, 0xC548, 0xBEC8, 0xC549, 0xBEC9, 0xC54A, 0xBECA, 0xC54B, 0x9DD2, 0xC54C, 0xBECB, 0xC54D, 0xBECC, 0xC54E, 0xBECD, 0xC54F, 0x9DD3, 0xC550, 0x9DD4, 0xC551, 0x9DD5, 0xC552, 0x9DD6, 0xC553, 0xBECE, 0xC554, 0xBECF, 0xC555, 0xBED0, 0xC556, 0x9DD7, 0xC557, 0xBED1, 0xC558, 0xBED2, 0xC559, 0xBED3, 0xC55A, 0x9DD8, 0xC55B, 0x9DD9, 0xC55C, 0x9DDA, 0xC55D, 0xBED4, 0xC55E, 0xBED5, 0xC55F, 0x9DDB, 0xC560, 0xBED6, 0xC561, 0xBED7, 0xC562, 0x9DDC, 0xC563, 0x9DDD, 0xC564, 0xBED8, 0xC565, 0x9DDE, 0xC566, 0x9DDF, 0xC567, 0x9DE0, 0xC568, 0xBED9, 0xC569, 0x9DE1, 0xC56A, 0x9DE2, 0xC56B, 0x9DE3, 0xC56C, 0x9DE4, 0xC56D, 0x9DE5, 0xC56E, 0x9DE6, 0xC56F, 0x9DE7, 0xC570, 0xBEDA, 0xC571, 0xBEDB, 0xC572, 0x9DE8, 0xC573, 0xBEDC, 0xC574, 0xBEDD, 0xC575, 0xBEDE, 0xC576, 0x9DE9, 0xC577, 0x9DEA, 0xC578, 0x9DEB, 0xC579, 0x9DEC, 0xC57A, 0x9DED, 0xC57B, 0x9DEE, 0xC57C, 0xBEDF, 0xC57D, 0xBEE0, 0xC57E, 0x9DEF, 0xC57F, 0x9DF0, 0xC580, 0xBEE1, 0xC581, 0x9DF1, 0xC582, 0x9DF2, 0xC583, 0x9DF3, 0xC584, 0xBEE2, 0xC585, 0x9DF4, 0xC586, 0x9DF5, 0xC587, 0xBEE3, 0xC588, 0x9DF6, 0xC589, 0x9DF7, 0xC58A, 0x9DF8, 0xC58B, 0x9DF9, 0xC58C, 0xBEE4, 0xC58D, 0xBEE5, 0xC58E, 0x9DFA, 0xC58F, 0xBEE6, 0xC590, 0x9DFB, 0xC591, 0xBEE7, 0xC592, 0x9DFC, 0xC593, 0x9DFD, 0xC594, 0x9DFE, 0xC595, 0xBEE8, 0xC596, 0x9E41, 0xC597, 0xBEE9, 0xC598, 0xBEEA, 0xC599, 0x9E42, 0xC59A, 0x9E43, 0xC59B, 0x9E44, 0xC59C, 0xBEEB, 0xC59D, 0x9E45, 0xC59E, 0x9E46, 0xC59F, 0x9E47, 0xC5A0, 0xBEEC, 0xC5A1, 0x9E48, 0xC5A2, 0x9E49, 0xC5A3, 0x9E4A, 0xC5A4, 0x9E4B, 0xC5A5, 0x9E4C, 0xC5A6, 0x9E4D, 0xC5A7, 0x9E4E, 0xC5A8, 0x9E4F, 0xC5A9, 0xBEED, 0xC5AA, 0x9E50, 0xC5AB, 0x9E51, 0xC5AC, 0x9E52, 0xC5AD, 0x9E53, 0xC5AE, 0x9E54, 0xC5AF, 0x9E55, 0xC5B0, 0x9E56, 0xC5B1, 0x9E57, 0xC5B2, 0x9E58, 0xC5B3, 0x9E59, 0xC5B4, 0xBEEE, 0xC5B5, 0xBEEF, 0xC5B6, 0x9E5A, 0xC5B7, 0x9E61, 0xC5B8, 0xBEF0, 0xC5B9, 0xBEF1, 0xC5BA, 0x9E62, 0xC5BB, 0xBEF2, 0xC5BC, 0xBEF3, 0xC5BD, 0xBEF4, 0xC5BE, 0xBEF5, 0xC5BF, 0x9E63, 0xC5C0, 0x9E64, 0xC5C1, 0x9E65, 0xC5C2, 0x9E66, 0xC5C3, 0x9E67, 0xC5C4, 0xBEF6, 0xC5C5, 0xBEF7, 0xC5C6, 0xBEF8, 0xC5C7, 0xBEF9, 0xC5C8, 0xBEFA, 0xC5C9, 0xBEFB, 0xC5CA, 0xBEFC, 0xC5CB, 0x9E68, 0xC5CC, 0xBEFD, 0xC5CD, 0x9E69, 0xC5CE, 0xBEFE, 0xC5CF, 0x9E6A, 0xC5D0, 0xBFA1, 0xC5D1, 0xBFA2, 0xC5D2, 0x9E6B, 0xC5D3, 0x9E6C, 0xC5D4, 0xBFA3, 0xC5D5, 0x9E6D, 0xC5D6, 0x9E6E, 0xC5D7, 0x9E6F, 0xC5D8, 0xBFA4, 0xC5D9, 0x9E70, 0xC5DA, 0x9E71, 0xC5DB, 0x9E72, 0xC5DC, 0x9E73, 0xC5DD, 0x9E74, 0xC5DE, 0x9E75, 0xC5DF, 0x9E76, 0xC5E0, 0xBFA5, 0xC5E1, 0xBFA6, 0xC5E2, 0x9E77, 0xC5E3, 0xBFA7, 0xC5E4, 0x9E78, 0xC5E5, 0xBFA8, 0xC5E6, 0x9E79, 0xC5E7, 0x9E7A, 0xC5E8, 0x9E81, 0xC5E9, 0x9E82, 0xC5EA, 0x9E83, 0xC5EB, 0x9E84, 0xC5EC, 0xBFA9, 0xC5ED, 0xBFAA, 0xC5EE, 0xBFAB, 0xC5EF, 0x9E85, 0xC5F0, 0xBFAC, 0xC5F1, 0x9E86, 0xC5F2, 0x9E87, 0xC5F3, 0x9E88, 0xC5F4, 0xBFAD, 0xC5F5, 0x9E89, 0xC5F6, 0xBFAE, 0xC5F7, 0xBFAF, 0xC5F8, 0x9E8A, 0xC5F9, 0x9E8B, 0xC5FA, 0x9E8C, 0xC5FB, 0x9E8D, 0xC5FC, 0xBFB0, 0xC5FD, 0xBFB1, 0xC5FE, 0xBFB2, 0xC5FF, 0xBFB3, 0xC600, 0xBFB4, 0xC601, 0xBFB5, 0xC602, 0x9E8E, 0xC603, 0x9E8F, 0xC604, 0x9E90, 0xC605, 0xBFB6, 0xC606, 0xBFB7, 0xC607, 0xBFB8, 0xC608, 0xBFB9, 0xC609, 0x9E91, 0xC60A, 0x9E92, 0xC60B, 0x9E93, 0xC60C, 0xBFBA, 0xC60D, 0x9E94, 0xC60E, 0x9E95, 0xC60F, 0x9E96, 0xC610, 0xBFBB, 0xC611, 0x9E97, 0xC612, 0x9E98, 0xC613, 0x9E99, 0xC614, 0x9E9A, 0xC615, 0x9E9B, 0xC616, 0x9E9C, 0xC617, 0x9E9D, 0xC618, 0xBFBC, 0xC619, 0xBFBD, 0xC61A, 0x9E9E, 0xC61B, 0xBFBE, 0xC61C, 0xBFBF, 0xC61D, 0x9E9F, 0xC61E, 0x9EA0, 0xC61F, 0x9EA1, 0xC620, 0x9EA2, 0xC621, 0x9EA3, 0xC622, 0x9EA4, 0xC623, 0x9EA5, 0xC624, 0xBFC0, 0xC625, 0xBFC1, 0xC626, 0x9EA6, 0xC627, 0x9EA7, 0xC628, 0xBFC2, 0xC629, 0x9EA8, 0xC62A, 0x9EA9, 0xC62B, 0x9EAA, 0xC62C, 0xBFC3, 0xC62D, 0xBFC4, 0xC62E, 0xBFC5, 0xC62F, 0x9EAB, 0xC630, 0xBFC6, 0xC631, 0x9EAC, 0xC632, 0x9EAD, 0xC633, 0xBFC7, 0xC634, 0xBFC8, 0xC635, 0xBFC9, 0xC636, 0x9EAE, 0xC637, 0xBFCA, 0xC638, 0x9EAF, 0xC639, 0xBFCB, 0xC63A, 0x9EB0, 0xC63B, 0xBFCC, 0xC63C, 0x9EB1, 0xC63D, 0x9EB2, 0xC63E, 0x9EB3, 0xC63F, 0x9EB4, 0xC640, 0xBFCD, 0xC641, 0xBFCE, 0xC642, 0x9EB5, 0xC643, 0x9EB6, 0xC644, 0xBFCF, 0xC645, 0x9EB7, 0xC646, 0x9EB8, 0xC647, 0x9EB9, 0xC648, 0xBFD0, 0xC649, 0x9EBA, 0xC64A, 0x9EBB, 0xC64B, 0x9EBC, 0xC64C, 0x9EBD, 0xC64D, 0x9EBE, 0xC64E, 0x9EBF, 0xC64F, 0x9EC0, 0xC650, 0xBFD1, 0xC651, 0xBFD2, 0xC652, 0x9EC1, 0xC653, 0xBFD3, 0xC654, 0xBFD4, 0xC655, 0xBFD5, 0xC656, 0x9EC2, 0xC657, 0x9EC3, 0xC658, 0x9EC4, 0xC659, 0x9EC5, 0xC65A, 0x9EC6, 0xC65B, 0x9EC7, 0xC65C, 0xBFD6, 0xC65D, 0xBFD7, 0xC65E, 0x9EC8, 0xC65F, 0x9EC9, 0xC660, 0xBFD8, 0xC661, 0x9ECA, 0xC662, 0x9ECB, 0xC663, 0x9ECC, 0xC664, 0x9ECD, 0xC665, 0x9ECE, 0xC666, 0x9ECF, 0xC667, 0x9ED0, 0xC668, 0x9ED1, 0xC669, 0x9ED2, 0xC66A, 0x9ED3, 0xC66B, 0x9ED4, 0xC66C, 0xBFD9, 0xC66D, 0x9ED5, 0xC66E, 0x9ED6, 0xC66F, 0xBFDA, 0xC670, 0x9ED7, 0xC671, 0xBFDB, 0xC672, 0x9ED8, 0xC673, 0x9ED9, 0xC674, 0x9EDA, 0xC675, 0x9EDB, 0xC676, 0x9EDC, 0xC677, 0x9EDD, 0xC678, 0xBFDC, 0xC679, 0xBFDD, 0xC67A, 0x9EDE, 0xC67B, 0x9EDF, 0xC67C, 0xBFDE, 0xC67D, 0x9EE0, 0xC67E, 0x9EE1, 0xC67F, 0x9EE2, 0xC680, 0xBFDF, 0xC681, 0x9EE3, 0xC682, 0x9EE4, 0xC683, 0x9EE5, 0xC684, 0x9EE6, 0xC685, 0x9EE7, 0xC686, 0x9EE8, 0xC687, 0x9EE9, 0xC688, 0xBFE0, 0xC689, 0xBFE1, 0xC68A, 0x9EEA, 0xC68B, 0xBFE2, 0xC68C, 0x9EEB, 0xC68D, 0xBFE3, 0xC68E, 0x9EEC, 0xC68F, 0x9EED, 0xC690, 0x9EEE, 0xC691, 0x9EEF, 0xC692, 0x9EF0, 0xC693, 0x9EF1, 0xC694, 0xBFE4, 0xC695, 0xBFE5, 0xC696, 0x9EF2, 0xC697, 0x9EF3, 0xC698, 0xBFE6, 0xC699, 0x9EF4, 0xC69A, 0x9EF5, 0xC69B, 0x9EF6, 0xC69C, 0xBFE7, 0xC69D, 0x9EF7, 0xC69E, 0x9EF8, 0xC69F, 0x9EF9, 0xC6A0, 0x9EFA, 0xC6A1, 0x9EFB, 0xC6A2, 0x9EFC, 0xC6A3, 0x9EFD, 0xC6A4, 0xBFE8, 0xC6A5, 0xBFE9, 0xC6A6, 0x9EFE, 0xC6A7, 0xBFEA, 0xC6A8, 0x9F41, 0xC6A9, 0xBFEB, 0xC6AA, 0x9F42, 0xC6AB, 0x9F43, 0xC6AC, 0x9F44, 0xC6AD, 0x9F45, 0xC6AE, 0x9F46, 0xC6AF, 0x9F47, 0xC6B0, 0xBFEC, 0xC6B1, 0xBFED, 0xC6B2, 0x9F48, 0xC6B3, 0x9F49, 0xC6B4, 0xBFEE, 0xC6B5, 0x9F4A, 0xC6B6, 0x9F4B, 0xC6B7, 0x9F4C, 0xC6B8, 0xBFEF, 0xC6B9, 0xBFF0, 0xC6BA, 0xBFF1, 0xC6BB, 0x9F4D, 0xC6BC, 0x9F4E, 0xC6BD, 0x9F4F, 0xC6BE, 0x9F50, 0xC6BF, 0x9F51, 0xC6C0, 0xBFF2, 0xC6C1, 0xBFF3, 0xC6C2, 0x9F52, 0xC6C3, 0xBFF4, 0xC6C4, 0x9F53, 0xC6C5, 0xBFF5, 0xC6C6, 0x9F54, 0xC6C7, 0x9F55, 0xC6C8, 0x9F56, 0xC6C9, 0x9F57, 0xC6CA, 0x9F58, 0xC6CB, 0x9F59, 0xC6CC, 0xBFF6, 0xC6CD, 0xBFF7, 0xC6CE, 0x9F5A, 0xC6CF, 0x9F61, 0xC6D0, 0xBFF8, 0xC6D1, 0x9F62, 0xC6D2, 0x9F63, 0xC6D3, 0x9F64, 0xC6D4, 0xBFF9, 0xC6D5, 0x9F65, 0xC6D6, 0x9F66, 0xC6D7, 0x9F67, 0xC6D8, 0x9F68, 0xC6D9, 0x9F69, 0xC6DA, 0x9F6A, 0xC6DB, 0x9F6B, 0xC6DC, 0xBFFA, 0xC6DD, 0xBFFB, 0xC6DE, 0x9F6C, 0xC6DF, 0x9F6D, 0xC6E0, 0xBFFC, 0xC6E1, 0xBFFD, 0xC6E2, 0x9F6E, 0xC6E3, 0x9F6F, 0xC6E4, 0x9F70, 0xC6E5, 0x9F71, 0xC6E6, 0x9F72, 0xC6E7, 0x9F73, 0xC6E8, 0xBFFE, 0xC6E9, 0xC0A1, 0xC6EA, 0x9F74, 0xC6EB, 0x9F75, 0xC6EC, 0xC0A2, 0xC6ED, 0x9F76, 0xC6EE, 0x9F77, 0xC6EF, 0x9F78, 0xC6F0, 0xC0A3, 0xC6F1, 0x9F79, 0xC6F2, 0x9F7A, 0xC6F3, 0x9F81, 0xC6F4, 0x9F82, 0xC6F5, 0x9F83, 0xC6F6, 0x9F84, 0xC6F7, 0x9F85, 0xC6F8, 0xC0A4, 0xC6F9, 0xC0A5, 0xC6FA, 0x9F86, 0xC6FB, 0x9F87, 0xC6FC, 0x9F88, 0xC6FD, 0xC0A6, 0xC6FE, 0x9F89, 0xC6FF, 0x9F8A, 0xC700, 0x9F8B, 0xC701, 0x9F8C, 0xC702, 0x9F8D, 0xC703, 0x9F8E, 0xC704, 0xC0A7, 0xC705, 0xC0A8, 0xC706, 0x9F8F, 0xC707, 0x9F90, 0xC708, 0xC0A9, 0xC709, 0x9F91, 0xC70A, 0x9F92, 0xC70B, 0x9F93, 0xC70C, 0xC0AA, 0xC70D, 0x9F94, 0xC70E, 0x9F95, 0xC70F, 0x9F96, 0xC710, 0x9F97, 0xC711, 0x9F98, 0xC712, 0x9F99, 0xC713, 0x9F9A, 0xC714, 0xC0AB, 0xC715, 0xC0AC, 0xC716, 0x9F9B, 0xC717, 0xC0AD, 0xC718, 0x9F9C, 0xC719, 0xC0AE, 0xC71A, 0x9F9D, 0xC71B, 0x9F9E, 0xC71C, 0x9F9F, 0xC71D, 0x9FA0, 0xC71E, 0x9FA1, 0xC71F, 0x9FA2, 0xC720, 0xC0AF, 0xC721, 0xC0B0, 0xC722, 0x9FA3, 0xC723, 0x9FA4, 0xC724, 0xC0B1, 0xC725, 0x9FA5, 0xC726, 0x9FA6, 0xC727, 0x9FA7, 0xC728, 0xC0B2, 0xC729, 0x9FA8, 0xC72A, 0x9FA9, 0xC72B, 0x9FAA, 0xC72C, 0x9FAB, 0xC72D, 0x9FAC, 0xC72E, 0x9FAD, 0xC72F, 0x9FAE, 0xC730, 0xC0B3, 0xC731, 0xC0B4, 0xC732, 0x9FAF, 0xC733, 0xC0B5, 0xC734, 0x9FB0, 0xC735, 0xC0B6, 0xC736, 0x9FB1, 0xC737, 0xC0B7, 0xC738, 0x9FB2, 0xC739, 0x9FB3, 0xC73A, 0x9FB4, 0xC73B, 0x9FB5, 0xC73C, 0xC0B8, 0xC73D, 0xC0B9, 0xC73E, 0x9FB6, 0xC73F, 0x9FB7, 0xC740, 0xC0BA, 0xC741, 0x9FB8, 0xC742, 0x9FB9, 0xC743, 0x9FBA, 0xC744, 0xC0BB, 0xC745, 0x9FBB, 0xC746, 0x9FBC, 0xC747, 0x9FBD, 0xC748, 0x9FBE, 0xC749, 0x9FBF, 0xC74A, 0xC0BC, 0xC74B, 0x9FC0, 0xC74C, 0xC0BD, 0xC74D, 0xC0BE, 0xC74E, 0x9FC1, 0xC74F, 0xC0BF, 0xC750, 0x9FC2, 0xC751, 0xC0C0, 0xC752, 0xC0C1, 0xC753, 0xC0C2, 0xC754, 0xC0C3, 0xC755, 0xC0C4, 0xC756, 0xC0C5, 0xC757, 0xC0C6, 0xC758, 0xC0C7, 0xC759, 0x9FC3, 0xC75A, 0x9FC4, 0xC75B, 0x9FC5, 0xC75C, 0xC0C8, 0xC75D, 0x9FC6, 0xC75E, 0x9FC7, 0xC75F, 0x9FC8, 0xC760, 0xC0C9, 0xC761, 0x9FC9, 0xC762, 0x9FCA, 0xC763, 0x9FCB, 0xC764, 0x9FCC, 0xC765, 0x9FCD, 0xC766, 0x9FCE, 0xC767, 0x9FCF, 0xC768, 0xC0CA, 0xC769, 0x9FD0, 0xC76A, 0x9FD1, 0xC76B, 0xC0CB, 0xC76C, 0x9FD2, 0xC76D, 0x9FD3, 0xC76E, 0x9FD4, 0xC76F, 0x9FD5, 0xC770, 0x9FD6, 0xC771, 0x9FD7, 0xC772, 0x9FD8, 0xC773, 0x9FD9, 0xC774, 0xC0CC, 0xC775, 0xC0CD, 0xC776, 0x9FDA, 0xC777, 0x9FDB, 0xC778, 0xC0CE, 0xC779, 0x9FDC, 0xC77A, 0x9FDD, 0xC77B, 0x9FDE, 0xC77C, 0xC0CF, 0xC77D, 0xC0D0, 0xC77E, 0xC0D1, 0xC77F, 0x9FDF, 0xC780, 0x9FE0, 0xC781, 0x9FE1, 0xC782, 0x9FE2, 0xC783, 0xC0D2, 0xC784, 0xC0D3, 0xC785, 0xC0D4, 0xC786, 0x9FE3, 0xC787, 0xC0D5, 0xC788, 0xC0D6, 0xC789, 0xC0D7, 0xC78A, 0xC0D8, 0xC78B, 0x9FE4, 0xC78C, 0x9FE5, 0xC78D, 0x9FE6, 0xC78E, 0xC0D9, 0xC78F, 0x9FE7, 0xC790, 0xC0DA, 0xC791, 0xC0DB, 0xC792, 0x9FE8, 0xC793, 0x9FE9, 0xC794, 0xC0DC, 0xC795, 0x9FEA, 0xC796, 0xC0DD, 0xC797, 0xC0DE, 0xC798, 0xC0DF, 0xC799, 0x9FEB, 0xC79A, 0xC0E0, 0xC79B, 0x9FEC, 0xC79C, 0x9FED, 0xC79D, 0x9FEE, 0xC79E, 0x9FEF, 0xC79F, 0x9FF0, 0xC7A0, 0xC0E1, 0xC7A1, 0xC0E2, 0xC7A2, 0x9FF1, 0xC7A3, 0xC0E3, 0xC7A4, 0xC0E4, 0xC7A5, 0xC0E5, 0xC7A6, 0xC0E6, 0xC7A7, 0x9FF2, 0xC7A8, 0x9FF3, 0xC7A9, 0x9FF4, 0xC7AA, 0x9FF5, 0xC7AB, 0x9FF6, 0xC7AC, 0xC0E7, 0xC7AD, 0xC0E8, 0xC7AE, 0x9FF7, 0xC7AF, 0x9FF8, 0xC7B0, 0xC0E9, 0xC7B1, 0x9FF9, 0xC7B2, 0x9FFA, 0xC7B3, 0x9FFB, 0xC7B4, 0xC0EA, 0xC7B5, 0x9FFC, 0xC7B6, 0x9FFD, 0xC7B7, 0x9FFE, 0xC7B8, 0xA041, 0xC7B9, 0xA042, 0xC7BA, 0xA043, 0xC7BB, 0xA044, 0xC7BC, 0xC0EB, 0xC7BD, 0xC0EC, 0xC7BE, 0xA045, 0xC7BF, 0xC0ED, 0xC7C0, 0xC0EE, 0xC7C1, 0xC0EF, 0xC7C2, 0xA046, 0xC7C3, 0xA047, 0xC7C4, 0xA048, 0xC7C5, 0xA049, 0xC7C6, 0xA04A, 0xC7C7, 0xA04B, 0xC7C8, 0xC0F0, 0xC7C9, 0xC0F1, 0xC7CA, 0xA04C, 0xC7CB, 0xA04D, 0xC7CC, 0xC0F2, 0xC7CD, 0xA04E, 0xC7CE, 0xC0F3, 0xC7CF, 0xA04F, 0xC7D0, 0xC0F4, 0xC7D1, 0xA050, 0xC7D2, 0xA051, 0xC7D3, 0xA052, 0xC7D4, 0xA053, 0xC7D5, 0xA054, 0xC7D6, 0xA055, 0xC7D7, 0xA056, 0xC7D8, 0xC0F5, 0xC7D9, 0xA057, 0xC7DA, 0xA058, 0xC7DB, 0xA059, 0xC7DC, 0xA05A, 0xC7DD, 0xC0F6, 0xC7DE, 0xA061, 0xC7DF, 0xA062, 0xC7E0, 0xA063, 0xC7E1, 0xA064, 0xC7E2, 0xA065, 0xC7E3, 0xA066, 0xC7E4, 0xC0F7, 0xC7E5, 0xA067, 0xC7E6, 0xA068, 0xC7E7, 0xA069, 0xC7E8, 0xC0F8, 0xC7E9, 0xA06A, 0xC7EA, 0xA06B, 0xC7EB, 0xA06C, 0xC7EC, 0xC0F9, 0xC7ED, 0xA06D, 0xC7EE, 0xA06E, 0xC7EF, 0xA06F, 0xC7F0, 0xA070, 0xC7F1, 0xA071, 0xC7F2, 0xA072, 0xC7F3, 0xA073, 0xC7F4, 0xA074, 0xC7F5, 0xA075, 0xC7F6, 0xA076, 0xC7F7, 0xA077, 0xC7F8, 0xA078, 0xC7F9, 0xA079, 0xC7FA, 0xA07A, 0xC7FB, 0xA081, 0xC7FC, 0xA082, 0xC7FD, 0xA083, 0xC7FE, 0xA084, 0xC7FF, 0xA085, 0xC800, 0xC0FA, 0xC801, 0xC0FB, 0xC802, 0xA086, 0xC803, 0xA087, 0xC804, 0xC0FC, 0xC805, 0xA088, 0xC806, 0xA089, 0xC807, 0xA08A, 0xC808, 0xC0FD, 0xC809, 0xA08B, 0xC80A, 0xC0FE, 0xC80B, 0xA08C, 0xC80C, 0xA08D, 0xC80D, 0xA08E, 0xC80E, 0xA08F, 0xC80F, 0xA090, 0xC810, 0xC1A1, 0xC811, 0xC1A2, 0xC812, 0xA091, 0xC813, 0xC1A3, 0xC814, 0xA092, 0xC815, 0xC1A4, 0xC816, 0xC1A5, 0xC817, 0xA093, 0xC818, 0xA094, 0xC819, 0xA095, 0xC81A, 0xA096, 0xC81B, 0xA097, 0xC81C, 0xC1A6, 0xC81D, 0xC1A7, 0xC81E, 0xA098, 0xC81F, 0xA099, 0xC820, 0xC1A8, 0xC821, 0xA09A, 0xC822, 0xA09B, 0xC823, 0xA09C, 0xC824, 0xC1A9, 0xC825, 0xA09D, 0xC826, 0xA09E, 0xC827, 0xA09F, 0xC828, 0xA0A0, 0xC829, 0xA0A1, 0xC82A, 0xA0A2, 0xC82B, 0xA0A3, 0xC82C, 0xC1AA, 0xC82D, 0xC1AB, 0xC82E, 0xA0A4, 0xC82F, 0xC1AC, 0xC830, 0xA0A5, 0xC831, 0xC1AD, 0xC832, 0xA0A6, 0xC833, 0xA0A7, 0xC834, 0xA0A8, 0xC835, 0xA0A9, 0xC836, 0xA0AA, 0xC837, 0xA0AB, 0xC838, 0xC1AE, 0xC839, 0xA0AC, 0xC83A, 0xA0AD, 0xC83B, 0xA0AE, 0xC83C, 0xC1AF, 0xC83D, 0xA0AF, 0xC83E, 0xA0B0, 0xC83F, 0xA0B1, 0xC840, 0xC1B0, 0xC841, 0xA0B2, 0xC842, 0xA0B3, 0xC843, 0xA0B4, 0xC844, 0xA0B5, 0xC845, 0xA0B6, 0xC846, 0xA0B7, 0xC847, 0xA0B8, 0xC848, 0xC1B1, 0xC849, 0xC1B2, 0xC84A, 0xA0B9, 0xC84B, 0xA0BA, 0xC84C, 0xC1B3, 0xC84D, 0xC1B4, 0xC84E, 0xA0BB, 0xC84F, 0xA0BC, 0xC850, 0xA0BD, 0xC851, 0xA0BE, 0xC852, 0xA0BF, 0xC853, 0xA0C0, 0xC854, 0xC1B5, 0xC855, 0xA0C1, 0xC856, 0xA0C2, 0xC857, 0xA0C3, 0xC858, 0xA0C4, 0xC859, 0xA0C5, 0xC85A, 0xA0C6, 0xC85B, 0xA0C7, 0xC85C, 0xA0C8, 0xC85D, 0xA0C9, 0xC85E, 0xA0CA, 0xC85F, 0xA0CB, 0xC860, 0xA0CC, 0xC861, 0xA0CD, 0xC862, 0xA0CE, 0xC863, 0xA0CF, 0xC864, 0xA0D0, 0xC865, 0xA0D1, 0xC866, 0xA0D2, 0xC867, 0xA0D3, 0xC868, 0xA0D4, 0xC869, 0xA0D5, 0xC86A, 0xA0D6, 0xC86B, 0xA0D7, 0xC86C, 0xA0D8, 0xC86D, 0xA0D9, 0xC86E, 0xA0DA, 0xC86F, 0xA0DB, 0xC870, 0xC1B6, 0xC871, 0xC1B7, 0xC872, 0xA0DC, 0xC873, 0xA0DD, 0xC874, 0xC1B8, 0xC875, 0xA0DE, 0xC876, 0xA0DF, 0xC877, 0xA0E0, 0xC878, 0xC1B9, 0xC879, 0xA0E1, 0xC87A, 0xC1BA, 0xC87B, 0xA0E2, 0xC87C, 0xA0E3, 0xC87D, 0xA0E4, 0xC87E, 0xA0E5, 0xC87F, 0xA0E6, 0xC880, 0xC1BB, 0xC881, 0xC1BC, 0xC882, 0xA0E7, 0xC883, 0xC1BD, 0xC884, 0xA0E8, 0xC885, 0xC1BE, 0xC886, 0xC1BF, 0xC887, 0xC1C0, 0xC888, 0xA0E9, 0xC889, 0xA0EA, 0xC88A, 0xA0EB, 0xC88B, 0xC1C1, 0xC88C, 0xC1C2, 0xC88D, 0xC1C3, 0xC88E, 0xA0EC, 0xC88F, 0xA0ED, 0xC890, 0xA0EE, 0xC891, 0xA0EF, 0xC892, 0xA0F0, 0xC893, 0xA0F1, 0xC894, 0xC1C4, 0xC895, 0xA0F2, 0xC896, 0xA0F3, 0xC897, 0xA0F4, 0xC898, 0xA0F5, 0xC899, 0xA0F6, 0xC89A, 0xA0F7, 0xC89B, 0xA0F8, 0xC89C, 0xA0F9, 0xC89D, 0xC1C5, 0xC89E, 0xA0FA, 0xC89F, 0xC1C6, 0xC8A0, 0xA0FB, 0xC8A1, 0xC1C7, 0xC8A2, 0xA0FC, 0xC8A3, 0xA0FD, 0xC8A4, 0xA0FE, 0xC8A5, 0xA141, 0xC8A6, 0xA142, 0xC8A7, 0xA143, 0xC8A8, 0xC1C8, 0xC8A9, 0xA144, 0xC8AA, 0xA145, 0xC8AB, 0xA146, 0xC8AC, 0xA147, 0xC8AD, 0xA148, 0xC8AE, 0xA149, 0xC8AF, 0xA14A, 0xC8B0, 0xA14B, 0xC8B1, 0xA14C, 0xC8B2, 0xA14D, 0xC8B3, 0xA14E, 0xC8B4, 0xA14F, 0xC8B5, 0xA150, 0xC8B6, 0xA151, 0xC8B7, 0xA152, 0xC8B8, 0xA153, 0xC8B9, 0xA154, 0xC8BA, 0xA155, 0xC8BB, 0xA156, 0xC8BC, 0xC1C9, 0xC8BD, 0xC1CA, 0xC8BE, 0xA157, 0xC8BF, 0xA158, 0xC8C0, 0xA159, 0xC8C1, 0xA15A, 0xC8C2, 0xA161, 0xC8C3, 0xA162, 0xC8C4, 0xC1CB, 0xC8C5, 0xA163, 0xC8C6, 0xA164, 0xC8C7, 0xA165, 0xC8C8, 0xC1CC, 0xC8C9, 0xA166, 0xC8CA, 0xA167, 0xC8CB, 0xA168, 0xC8CC, 0xC1CD, 0xC8CD, 0xA169, 0xC8CE, 0xA16A, 0xC8CF, 0xA16B, 0xC8D0, 0xA16C, 0xC8D1, 0xA16D, 0xC8D2, 0xA16E, 0xC8D3, 0xA16F, 0xC8D4, 0xC1CE, 0xC8D5, 0xC1CF, 0xC8D6, 0xA170, 0xC8D7, 0xC1D0, 0xC8D8, 0xA171, 0xC8D9, 0xC1D1, 0xC8DA, 0xA172, 0xC8DB, 0xA173, 0xC8DC, 0xA174, 0xC8DD, 0xA175, 0xC8DE, 0xA176, 0xC8DF, 0xA177, 0xC8E0, 0xC1D2, 0xC8E1, 0xC1D3, 0xC8E2, 0xA178, 0xC8E3, 0xA179, 0xC8E4, 0xC1D4, 0xC8E5, 0xA17A, 0xC8E6, 0xA181, 0xC8E7, 0xA182, 0xC8E8, 0xA183, 0xC8E9, 0xA184, 0xC8EA, 0xA185, 0xC8EB, 0xA186, 0xC8EC, 0xA187, 0xC8ED, 0xA188, 0xC8EE, 0xA189, 0xC8EF, 0xA18A, 0xC8F0, 0xA18B, 0xC8F1, 0xA18C, 0xC8F2, 0xA18D, 0xC8F3, 0xA18E, 0xC8F4, 0xA18F, 0xC8F5, 0xC1D5, 0xC8F6, 0xA190, 0xC8F7, 0xA191, 0xC8F8, 0xA192, 0xC8F9, 0xA193, 0xC8FA, 0xA194, 0xC8FB, 0xA195, 0xC8FC, 0xC1D6, 0xC8FD, 0xC1D7, 0xC8FE, 0xA196, 0xC8FF, 0xA197, 0xC900, 0xC1D8, 0xC901, 0xA198, 0xC902, 0xA199, 0xC903, 0xA19A, 0xC904, 0xC1D9, 0xC905, 0xC1DA, 0xC906, 0xC1DB, 0xC907, 0xA19B, 0xC908, 0xA19C, 0xC909, 0xA19D, 0xC90A, 0xA19E, 0xC90B, 0xA19F, 0xC90C, 0xC1DC, 0xC90D, 0xC1DD, 0xC90E, 0xA1A0, 0xC90F, 0xC1DE, 0xC910, 0xA241, 0xC911, 0xC1DF, 0xC912, 0xA242, 0xC913, 0xA243, 0xC914, 0xA244, 0xC915, 0xA245, 0xC916, 0xA246, 0xC917, 0xA247, 0xC918, 0xC1E0, 0xC919, 0xA248, 0xC91A, 0xA249, 0xC91B, 0xA24A, 0xC91C, 0xA24B, 0xC91D, 0xA24C, 0xC91E, 0xA24D, 0xC91F, 0xA24E, 0xC920, 0xA24F, 0xC921, 0xA250, 0xC922, 0xA251, 0xC923, 0xA252, 0xC924, 0xA253, 0xC925, 0xA254, 0xC926, 0xA255, 0xC927, 0xA256, 0xC928, 0xA257, 0xC929, 0xA258, 0xC92A, 0xA259, 0xC92B, 0xA25A, 0xC92C, 0xC1E1, 0xC92D, 0xA261, 0xC92E, 0xA262, 0xC92F, 0xA263, 0xC930, 0xA264, 0xC931, 0xA265, 0xC932, 0xA266, 0xC933, 0xA267, 0xC934, 0xC1E2, 0xC935, 0xA268, 0xC936, 0xA269, 0xC937, 0xA26A, 0xC938, 0xA26B, 0xC939, 0xA26C, 0xC93A, 0xA26D, 0xC93B, 0xA26E, 0xC93C, 0xA26F, 0xC93D, 0xA270, 0xC93E, 0xA271, 0xC93F, 0xA272, 0xC940, 0xA273, 0xC941, 0xA274, 0xC942, 0xA275, 0xC943, 0xA276, 0xC944, 0xA277, 0xC945, 0xA278, 0xC946, 0xA279, 0xC947, 0xA27A, 0xC948, 0xA281, 0xC949, 0xA282, 0xC94A, 0xA283, 0xC94B, 0xA284, 0xC94C, 0xA285, 0xC94D, 0xA286, 0xC94E, 0xA287, 0xC94F, 0xA288, 0xC950, 0xC1E3, 0xC951, 0xC1E4, 0xC952, 0xA289, 0xC953, 0xA28A, 0xC954, 0xC1E5, 0xC955, 0xA28B, 0xC956, 0xA28C, 0xC957, 0xA28D, 0xC958, 0xC1E6, 0xC959, 0xA28E, 0xC95A, 0xA28F, 0xC95B, 0xA290, 0xC95C, 0xA291, 0xC95D, 0xA292, 0xC95E, 0xA293, 0xC95F, 0xA294, 0xC960, 0xC1E7, 0xC961, 0xC1E8, 0xC962, 0xA295, 0xC963, 0xC1E9, 0xC964, 0xA296, 0xC965, 0xA297, 0xC966, 0xA298, 0xC967, 0xA299, 0xC968, 0xA29A, 0xC969, 0xA29B, 0xC96A, 0xA29C, 0xC96B, 0xA29D, 0xC96C, 0xC1EA, 0xC96D, 0xA29E, 0xC96E, 0xA29F, 0xC96F, 0xA2A0, 0xC970, 0xC1EB, 0xC971, 0xA341, 0xC972, 0xA342, 0xC973, 0xA343, 0xC974, 0xC1EC, 0xC975, 0xA344, 0xC976, 0xA345, 0xC977, 0xA346, 0xC978, 0xA347, 0xC979, 0xA348, 0xC97A, 0xA349, 0xC97B, 0xA34A, 0xC97C, 0xC1ED, 0xC97D, 0xA34B, 0xC97E, 0xA34C, 0xC97F, 0xA34D, 0xC980, 0xA34E, 0xC981, 0xA34F, 0xC982, 0xA350, 0xC983, 0xA351, 0xC984, 0xA352, 0xC985, 0xA353, 0xC986, 0xA354, 0xC987, 0xA355, 0xC988, 0xC1EE, 0xC989, 0xC1EF, 0xC98A, 0xA356, 0xC98B, 0xA357, 0xC98C, 0xC1F0, 0xC98D, 0xA358, 0xC98E, 0xA359, 0xC98F, 0xA35A, 0xC990, 0xC1F1, 0xC991, 0xA361, 0xC992, 0xA362, 0xC993, 0xA363, 0xC994, 0xA364, 0xC995, 0xA365, 0xC996, 0xA366, 0xC997, 0xA367, 0xC998, 0xC1F2, 0xC999, 0xC1F3, 0xC99A, 0xA368, 0xC99B, 0xC1F4, 0xC99C, 0xA369, 0xC99D, 0xC1F5, 0xC99E, 0xA36A, 0xC99F, 0xA36B, 0xC9A0, 0xA36C, 0xC9A1, 0xA36D, 0xC9A2, 0xA36E, 0xC9A3, 0xA36F, 0xC9A4, 0xA370, 0xC9A5, 0xA371, 0xC9A6, 0xA372, 0xC9A7, 0xA373, 0xC9A8, 0xA374, 0xC9A9, 0xA375, 0xC9AA, 0xA376, 0xC9AB, 0xA377, 0xC9AC, 0xA378, 0xC9AD, 0xA379, 0xC9AE, 0xA37A, 0xC9AF, 0xA381, 0xC9B0, 0xA382, 0xC9B1, 0xA383, 0xC9B2, 0xA384, 0xC9B3, 0xA385, 0xC9B4, 0xA386, 0xC9B5, 0xA387, 0xC9B6, 0xA388, 0xC9B7, 0xA389, 0xC9B8, 0xA38A, 0xC9B9, 0xA38B, 0xC9BA, 0xA38C, 0xC9BB, 0xA38D, 0xC9BC, 0xA38E, 0xC9BD, 0xA38F, 0xC9BE, 0xA390, 0xC9BF, 0xA391, 0xC9C0, 0xC1F6, 0xC9C1, 0xC1F7, 0xC9C2, 0xA392, 0xC9C3, 0xA393, 0xC9C4, 0xC1F8, 0xC9C5, 0xA394, 0xC9C6, 0xA395, 0xC9C7, 0xC1F9, 0xC9C8, 0xC1FA, 0xC9C9, 0xA396, 0xC9CA, 0xC1FB, 0xC9CB, 0xA397, 0xC9CC, 0xA398, 0xC9CD, 0xA399, 0xC9CE, 0xA39A, 0xC9CF, 0xA39B, 0xC9D0, 0xC1FC, 0xC9D1, 0xC1FD, 0xC9D2, 0xA39C, 0xC9D3, 0xC1FE, 0xC9D4, 0xA39D, 0xC9D5, 0xC2A1, 0xC9D6, 0xC2A2, 0xC9D7, 0xA39E, 0xC9D8, 0xA39F, 0xC9D9, 0xC2A3, 0xC9DA, 0xC2A4, 0xC9DB, 0xA3A0, 0xC9DC, 0xC2A5, 0xC9DD, 0xC2A6, 0xC9DE, 0xA441, 0xC9DF, 0xA442, 0xC9E0, 0xC2A7, 0xC9E1, 0xA443, 0xC9E2, 0xC2A8, 0xC9E3, 0xA444, 0xC9E4, 0xC2A9, 0xC9E5, 0xA445, 0xC9E6, 0xA446, 0xC9E7, 0xC2AA, 0xC9E8, 0xA447, 0xC9E9, 0xA448, 0xC9EA, 0xA449, 0xC9EB, 0xA44A, 0xC9EC, 0xC2AB, 0xC9ED, 0xC2AC, 0xC9EE, 0xA44B, 0xC9EF, 0xC2AD, 0xC9F0, 0xC2AE, 0xC9F1, 0xC2AF, 0xC9F2, 0xA44C, 0xC9F3, 0xA44D, 0xC9F4, 0xA44E, 0xC9F5, 0xA44F, 0xC9F6, 0xA450, 0xC9F7, 0xA451, 0xC9F8, 0xC2B0, 0xC9F9, 0xC2B1, 0xC9FA, 0xA452, 0xC9FB, 0xA453, 0xC9FC, 0xC2B2, 0xC9FD, 0xA454, 0xC9FE, 0xA455, 0xC9FF, 0xA456, 0xCA00, 0xC2B3, 0xCA01, 0xA457, 0xCA02, 0xA458, 0xCA03, 0xA459, 0xCA04, 0xA45A, 0xCA05, 0xA461, 0xCA06, 0xA462, 0xCA07, 0xA463, 0xCA08, 0xC2B4, 0xCA09, 0xC2B5, 0xCA0A, 0xA464, 0xCA0B, 0xC2B6, 0xCA0C, 0xC2B7, 0xCA0D, 0xC2B8, 0xCA0E, 0xA465, 0xCA0F, 0xA466, 0xCA10, 0xA467, 0xCA11, 0xA468, 0xCA12, 0xA469, 0xCA13, 0xA46A, 0xCA14, 0xC2B9, 0xCA15, 0xA46B, 0xCA16, 0xA46C, 0xCA17, 0xA46D, 0xCA18, 0xC2BA, 0xCA19, 0xA46E, 0xCA1A, 0xA46F, 0xCA1B, 0xA470, 0xCA1C, 0xA471, 0xCA1D, 0xA472, 0xCA1E, 0xA473, 0xCA1F, 0xA474, 0xCA20, 0xA475, 0xCA21, 0xA476, 0xCA22, 0xA477, 0xCA23, 0xA478, 0xCA24, 0xA479, 0xCA25, 0xA47A, 0xCA26, 0xA481, 0xCA27, 0xA482, 0xCA28, 0xA483, 0xCA29, 0xC2BB, 0xCA2A, 0xA484, 0xCA2B, 0xA485, 0xCA2C, 0xA486, 0xCA2D, 0xA487, 0xCA2E, 0xA488, 0xCA2F, 0xA489, 0xCA30, 0xA48A, 0xCA31, 0xA48B, 0xCA32, 0xA48C, 0xCA33, 0xA48D, 0xCA34, 0xA48E, 0xCA35, 0xA48F, 0xCA36, 0xA490, 0xCA37, 0xA491, 0xCA38, 0xA492, 0xCA39, 0xA493, 0xCA3A, 0xA494, 0xCA3B, 0xA495, 0xCA3C, 0xA496, 0xCA3D, 0xA497, 0xCA3E, 0xA498, 0xCA3F, 0xA499, 0xCA40, 0xA49A, 0xCA41, 0xA49B, 0xCA42, 0xA49C, 0xCA43, 0xA49D, 0xCA44, 0xA49E, 0xCA45, 0xA49F, 0xCA46, 0xA4A0, 0xCA47, 0xA541, 0xCA48, 0xA542, 0xCA49, 0xA543, 0xCA4A, 0xA544, 0xCA4B, 0xA545, 0xCA4C, 0xC2BC, 0xCA4D, 0xC2BD, 0xCA4E, 0xA546, 0xCA4F, 0xA547, 0xCA50, 0xC2BE, 0xCA51, 0xA548, 0xCA52, 0xA549, 0xCA53, 0xA54A, 0xCA54, 0xC2BF, 0xCA55, 0xA54B, 0xCA56, 0xA54C, 0xCA57, 0xA54D, 0xCA58, 0xA54E, 0xCA59, 0xA54F, 0xCA5A, 0xA550, 0xCA5B, 0xA551, 0xCA5C, 0xC2C0, 0xCA5D, 0xC2C1, 0xCA5E, 0xA552, 0xCA5F, 0xC2C2, 0xCA60, 0xC2C3, 0xCA61, 0xC2C4, 0xCA62, 0xA553, 0xCA63, 0xA554, 0xCA64, 0xA555, 0xCA65, 0xA556, 0xCA66, 0xA557, 0xCA67, 0xA558, 0xCA68, 0xC2C5, 0xCA69, 0xA559, 0xCA6A, 0xA55A, 0xCA6B, 0xA561, 0xCA6C, 0xA562, 0xCA6D, 0xA563, 0xCA6E, 0xA564, 0xCA6F, 0xA565, 0xCA70, 0xA566, 0xCA71, 0xA567, 0xCA72, 0xA568, 0xCA73, 0xA569, 0xCA74, 0xA56A, 0xCA75, 0xA56B, 0xCA76, 0xA56C, 0xCA77, 0xA56D, 0xCA78, 0xA56E, 0xCA79, 0xA56F, 0xCA7A, 0xA570, 0xCA7B, 0xA571, 0xCA7C, 0xA572, 0xCA7D, 0xC2C6, 0xCA7E, 0xA573, 0xCA7F, 0xA574, 0xCA80, 0xA575, 0xCA81, 0xA576, 0xCA82, 0xA577, 0xCA83, 0xA578, 0xCA84, 0xC2C7, 0xCA85, 0xA579, 0xCA86, 0xA57A, 0xCA87, 0xA581, 0xCA88, 0xA582, 0xCA89, 0xA583, 0xCA8A, 0xA584, 0xCA8B, 0xA585, 0xCA8C, 0xA586, 0xCA8D, 0xA587, 0xCA8E, 0xA588, 0xCA8F, 0xA589, 0xCA90, 0xA58A, 0xCA91, 0xA58B, 0xCA92, 0xA58C, 0xCA93, 0xA58D, 0xCA94, 0xA58E, 0xCA95, 0xA58F, 0xCA96, 0xA590, 0xCA97, 0xA591, 0xCA98, 0xC2C8, 0xCA99, 0xA592, 0xCA9A, 0xA593, 0xCA9B, 0xA594, 0xCA9C, 0xA595, 0xCA9D, 0xA596, 0xCA9E, 0xA597, 0xCA9F, 0xA598, 0xCAA0, 0xA599, 0xCAA1, 0xA59A, 0xCAA2, 0xA59B, 0xCAA3, 0xA59C, 0xCAA4, 0xA59D, 0xCAA5, 0xA59E, 0xCAA6, 0xA59F, 0xCAA7, 0xA5A0, 0xCAA8, 0xA641, 0xCAA9, 0xA642, 0xCAAA, 0xA643, 0xCAAB, 0xA644, 0xCAAC, 0xA645, 0xCAAD, 0xA646, 0xCAAE, 0xA647, 0xCAAF, 0xA648, 0xCAB0, 0xA649, 0xCAB1, 0xA64A, 0xCAB2, 0xA64B, 0xCAB3, 0xA64C, 0xCAB4, 0xA64D, 0xCAB5, 0xA64E, 0xCAB6, 0xA64F, 0xCAB7, 0xA650, 0xCAB8, 0xA651, 0xCAB9, 0xA652, 0xCABA, 0xA653, 0xCABB, 0xA654, 0xCABC, 0xC2C9, 0xCABD, 0xC2CA, 0xCABE, 0xA655, 0xCABF, 0xA656, 0xCAC0, 0xC2CB, 0xCAC1, 0xA657, 0xCAC2, 0xA658, 0xCAC3, 0xA659, 0xCAC4, 0xC2CC, 0xCAC5, 0xA65A, 0xCAC6, 0xA661, 0xCAC7, 0xA662, 0xCAC8, 0xA663, 0xCAC9, 0xA664, 0xCACA, 0xA665, 0xCACB, 0xA666, 0xCACC, 0xC2CD, 0xCACD, 0xC2CE, 0xCACE, 0xA667, 0xCACF, 0xC2CF, 0xCAD0, 0xA668, 0xCAD1, 0xC2D0, 0xCAD2, 0xA669, 0xCAD3, 0xC2D1, 0xCAD4, 0xA66A, 0xCAD5, 0xA66B, 0xCAD6, 0xA66C, 0xCAD7, 0xA66D, 0xCAD8, 0xC2D2, 0xCAD9, 0xC2D3, 0xCADA, 0xA66E, 0xCADB, 0xA66F, 0xCADC, 0xA670, 0xCADD, 0xA671, 0xCADE, 0xA672, 0xCADF, 0xA673, 0xCAE0, 0xC2D4, 0xCAE1, 0xA674, 0xCAE2, 0xA675, 0xCAE3, 0xA676, 0xCAE4, 0xA677, 0xCAE5, 0xA678, 0xCAE6, 0xA679, 0xCAE7, 0xA67A, 0xCAE8, 0xA681, 0xCAE9, 0xA682, 0xCAEA, 0xA683, 0xCAEB, 0xA684, 0xCAEC, 0xC2D5, 0xCAED, 0xA685, 0xCAEE, 0xA686, 0xCAEF, 0xA687, 0xCAF0, 0xA688, 0xCAF1, 0xA689, 0xCAF2, 0xA68A, 0xCAF3, 0xA68B, 0xCAF4, 0xC2D6, 0xCAF5, 0xA68C, 0xCAF6, 0xA68D, 0xCAF7, 0xA68E, 0xCAF8, 0xA68F, 0xCAF9, 0xA690, 0xCAFA, 0xA691, 0xCAFB, 0xA692, 0xCAFC, 0xA693, 0xCAFD, 0xA694, 0xCAFE, 0xA695, 0xCAFF, 0xA696, 0xCB00, 0xA697, 0xCB01, 0xA698, 0xCB02, 0xA699, 0xCB03, 0xA69A, 0xCB04, 0xA69B, 0xCB05, 0xA69C, 0xCB06, 0xA69D, 0xCB07, 0xA69E, 0xCB08, 0xC2D7, 0xCB09, 0xA69F, 0xCB0A, 0xA6A0, 0xCB0B, 0xA741, 0xCB0C, 0xA742, 0xCB0D, 0xA743, 0xCB0E, 0xA744, 0xCB0F, 0xA745, 0xCB10, 0xC2D8, 0xCB11, 0xA746, 0xCB12, 0xA747, 0xCB13, 0xA748, 0xCB14, 0xC2D9, 0xCB15, 0xA749, 0xCB16, 0xA74A, 0xCB17, 0xA74B, 0xCB18, 0xC2DA, 0xCB19, 0xA74C, 0xCB1A, 0xA74D, 0xCB1B, 0xA74E, 0xCB1C, 0xA74F, 0xCB1D, 0xA750, 0xCB1E, 0xA751, 0xCB1F, 0xA752, 0xCB20, 0xC2DB, 0xCB21, 0xC2DC, 0xCB22, 0xA753, 0xCB23, 0xA754, 0xCB24, 0xA755, 0xCB25, 0xA756, 0xCB26, 0xA757, 0xCB27, 0xA758, 0xCB28, 0xA759, 0xCB29, 0xA75A, 0xCB2A, 0xA761, 0xCB2B, 0xA762, 0xCB2C, 0xA763, 0xCB2D, 0xA764, 0xCB2E, 0xA765, 0xCB2F, 0xA766, 0xCB30, 0xA767, 0xCB31, 0xA768, 0xCB32, 0xA769, 0xCB33, 0xA76A, 0xCB34, 0xA76B, 0xCB35, 0xA76C, 0xCB36, 0xA76D, 0xCB37, 0xA76E, 0xCB38, 0xA76F, 0xCB39, 0xA770, 0xCB3A, 0xA771, 0xCB3B, 0xA772, 0xCB3C, 0xA773, 0xCB3D, 0xA774, 0xCB3E, 0xA775, 0xCB3F, 0xA776, 0xCB40, 0xA777, 0xCB41, 0xC2DD, 0xCB42, 0xA778, 0xCB43, 0xA779, 0xCB44, 0xA77A, 0xCB45, 0xA781, 0xCB46, 0xA782, 0xCB47, 0xA783, 0xCB48, 0xC2DE, 0xCB49, 0xC2DF, 0xCB4A, 0xA784, 0xCB4B, 0xA785, 0xCB4C, 0xC2E0, 0xCB4D, 0xA786, 0xCB4E, 0xA787, 0xCB4F, 0xA788, 0xCB50, 0xC2E1, 0xCB51, 0xA789, 0xCB52, 0xA78A, 0xCB53, 0xA78B, 0xCB54, 0xA78C, 0xCB55, 0xA78D, 0xCB56, 0xA78E, 0xCB57, 0xA78F, 0xCB58, 0xC2E2, 0xCB59, 0xC2E3, 0xCB5A, 0xA790, 0xCB5B, 0xA791, 0xCB5C, 0xA792, 0xCB5D, 0xC2E4, 0xCB5E, 0xA793, 0xCB5F, 0xA794, 0xCB60, 0xA795, 0xCB61, 0xA796, 0xCB62, 0xA797, 0xCB63, 0xA798, 0xCB64, 0xC2E5, 0xCB65, 0xA799, 0xCB66, 0xA79A, 0xCB67, 0xA79B, 0xCB68, 0xA79C, 0xCB69, 0xA79D, 0xCB6A, 0xA79E, 0xCB6B, 0xA79F, 0xCB6C, 0xA7A0, 0xCB6D, 0xA841, 0xCB6E, 0xA842, 0xCB6F, 0xA843, 0xCB70, 0xA844, 0xCB71, 0xA845, 0xCB72, 0xA846, 0xCB73, 0xA847, 0xCB74, 0xA848, 0xCB75, 0xA849, 0xCB76, 0xA84A, 0xCB77, 0xA84B, 0xCB78, 0xC2E6, 0xCB79, 0xC2E7, 0xCB7A, 0xA84C, 0xCB7B, 0xA84D, 0xCB7C, 0xA84E, 0xCB7D, 0xA84F, 0xCB7E, 0xA850, 0xCB7F, 0xA851, 0xCB80, 0xA852, 0xCB81, 0xA853, 0xCB82, 0xA854, 0xCB83, 0xA855, 0xCB84, 0xA856, 0xCB85, 0xA857, 0xCB86, 0xA858, 0xCB87, 0xA859, 0xCB88, 0xA85A, 0xCB89, 0xA861, 0xCB8A, 0xA862, 0xCB8B, 0xA863, 0xCB8C, 0xA864, 0xCB8D, 0xA865, 0xCB8E, 0xA866, 0xCB8F, 0xA867, 0xCB90, 0xA868, 0xCB91, 0xA869, 0xCB92, 0xA86A, 0xCB93, 0xA86B, 0xCB94, 0xA86C, 0xCB95, 0xA86D, 0xCB96, 0xA86E, 0xCB97, 0xA86F, 0xCB98, 0xA870, 0xCB99, 0xA871, 0xCB9A, 0xA872, 0xCB9B, 0xA873, 0xCB9C, 0xC2E8, 0xCB9D, 0xA874, 0xCB9E, 0xA875, 0xCB9F, 0xA876, 0xCBA0, 0xA877, 0xCBA1, 0xA878, 0xCBA2, 0xA879, 0xCBA3, 0xA87A, 0xCBA4, 0xA881, 0xCBA5, 0xA882, 0xCBA6, 0xA883, 0xCBA7, 0xA884, 0xCBA8, 0xA885, 0xCBA9, 0xA886, 0xCBAA, 0xA887, 0xCBAB, 0xA888, 0xCBAC, 0xA889, 0xCBAD, 0xA88A, 0xCBAE, 0xA88B, 0xCBAF, 0xA88C, 0xCBB0, 0xA88D, 0xCBB1, 0xA88E, 0xCBB2, 0xA88F, 0xCBB3, 0xA890, 0xCBB4, 0xA891, 0xCBB5, 0xA892, 0xCBB6, 0xA893, 0xCBB7, 0xA894, 0xCBB8, 0xC2E9, 0xCBB9, 0xA895, 0xCBBA, 0xA896, 0xCBBB, 0xA897, 0xCBBC, 0xA898, 0xCBBD, 0xA899, 0xCBBE, 0xA89A, 0xCBBF, 0xA89B, 0xCBC0, 0xA89C, 0xCBC1, 0xA89D, 0xCBC2, 0xA89E, 0xCBC3, 0xA89F, 0xCBC4, 0xA8A0, 0xCBC5, 0xA941, 0xCBC6, 0xA942, 0xCBC7, 0xA943, 0xCBC8, 0xA944, 0xCBC9, 0xA945, 0xCBCA, 0xA946, 0xCBCB, 0xA947, 0xCBCC, 0xA948, 0xCBCD, 0xA949, 0xCBCE, 0xA94A, 0xCBCF, 0xA94B, 0xCBD0, 0xA94C, 0xCBD1, 0xA94D, 0xCBD2, 0xA94E, 0xCBD3, 0xA94F, 0xCBD4, 0xC2EA, 0xCBD5, 0xA950, 0xCBD6, 0xA951, 0xCBD7, 0xA952, 0xCBD8, 0xA953, 0xCBD9, 0xA954, 0xCBDA, 0xA955, 0xCBDB, 0xA956, 0xCBDC, 0xA957, 0xCBDD, 0xA958, 0xCBDE, 0xA959, 0xCBDF, 0xA95A, 0xCBE0, 0xA961, 0xCBE1, 0xA962, 0xCBE2, 0xA963, 0xCBE3, 0xA964, 0xCBE4, 0xC2EB, 0xCBE5, 0xA965, 0xCBE6, 0xA966, 0xCBE7, 0xC2EC, 0xCBE8, 0xA967, 0xCBE9, 0xC2ED, 0xCBEA, 0xA968, 0xCBEB, 0xA969, 0xCBEC, 0xA96A, 0xCBED, 0xA96B, 0xCBEE, 0xA96C, 0xCBEF, 0xA96D, 0xCBF0, 0xA96E, 0xCBF1, 0xA96F, 0xCBF2, 0xA970, 0xCBF3, 0xA971, 0xCBF4, 0xA972, 0xCBF5, 0xA973, 0xCBF6, 0xA974, 0xCBF7, 0xA975, 0xCBF8, 0xA976, 0xCBF9, 0xA977, 0xCBFA, 0xA978, 0xCBFB, 0xA979, 0xCBFC, 0xA97A, 0xCBFD, 0xA981, 0xCBFE, 0xA982, 0xCBFF, 0xA983, 0xCC00, 0xA984, 0xCC01, 0xA985, 0xCC02, 0xA986, 0xCC03, 0xA987, 0xCC04, 0xA988, 0xCC05, 0xA989, 0xCC06, 0xA98A, 0xCC07, 0xA98B, 0xCC08, 0xA98C, 0xCC09, 0xA98D, 0xCC0A, 0xA98E, 0xCC0B, 0xA98F, 0xCC0C, 0xC2EE, 0xCC0D, 0xC2EF, 0xCC0E, 0xA990, 0xCC0F, 0xA991, 0xCC10, 0xC2F0, 0xCC11, 0xA992, 0xCC12, 0xA993, 0xCC13, 0xA994, 0xCC14, 0xC2F1, 0xCC15, 0xA995, 0xCC16, 0xA996, 0xCC17, 0xA997, 0xCC18, 0xA998, 0xCC19, 0xA999, 0xCC1A, 0xA99A, 0xCC1B, 0xA99B, 0xCC1C, 0xC2F2, 0xCC1D, 0xC2F3, 0xCC1E, 0xA99C, 0xCC1F, 0xA99D, 0xCC20, 0xA99E, 0xCC21, 0xC2F4, 0xCC22, 0xC2F5, 0xCC23, 0xA99F, 0xCC24, 0xA9A0, 0xCC25, 0xAA41, 0xCC26, 0xAA42, 0xCC27, 0xC2F6, 0xCC28, 0xC2F7, 0xCC29, 0xC2F8, 0xCC2A, 0xAA43, 0xCC2B, 0xAA44, 0xCC2C, 0xC2F9, 0xCC2D, 0xAA45, 0xCC2E, 0xC2FA, 0xCC2F, 0xAA46, 0xCC30, 0xC2FB, 0xCC31, 0xAA47, 0xCC32, 0xAA48, 0xCC33, 0xAA49, 0xCC34, 0xAA4A, 0xCC35, 0xAA4B, 0xCC36, 0xAA4C, 0xCC37, 0xAA4D, 0xCC38, 0xC2FC, 0xCC39, 0xC2FD, 0xCC3A, 0xAA4E, 0xCC3B, 0xC2FE, 0xCC3C, 0xC3A1, 0xCC3D, 0xC3A2, 0xCC3E, 0xC3A3, 0xCC3F, 0xAA4F, 0xCC40, 0xAA50, 0xCC41, 0xAA51, 0xCC42, 0xAA52, 0xCC43, 0xAA53, 0xCC44, 0xC3A4, 0xCC45, 0xC3A5, 0xCC46, 0xAA54, 0xCC47, 0xAA55, 0xCC48, 0xC3A6, 0xCC49, 0xAA56, 0xCC4A, 0xAA57, 0xCC4B, 0xAA58, 0xCC4C, 0xC3A7, 0xCC4D, 0xAA59, 0xCC4E, 0xAA5A, 0xCC4F, 0xAA61, 0xCC50, 0xAA62, 0xCC51, 0xAA63, 0xCC52, 0xAA64, 0xCC53, 0xAA65, 0xCC54, 0xC3A8, 0xCC55, 0xC3A9, 0xCC56, 0xAA66, 0xCC57, 0xC3AA, 0xCC58, 0xC3AB, 0xCC59, 0xC3AC, 0xCC5A, 0xAA67, 0xCC5B, 0xAA68, 0xCC5C, 0xAA69, 0xCC5D, 0xAA6A, 0xCC5E, 0xAA6B, 0xCC5F, 0xAA6C, 0xCC60, 0xC3AD, 0xCC61, 0xAA6D, 0xCC62, 0xAA6E, 0xCC63, 0xAA6F, 0xCC64, 0xC3AE, 0xCC65, 0xAA70, 0xCC66, 0xC3AF, 0xCC67, 0xAA71, 0xCC68, 0xC3B0, 0xCC69, 0xAA72, 0xCC6A, 0xAA73, 0xCC6B, 0xAA74, 0xCC6C, 0xAA75, 0xCC6D, 0xAA76, 0xCC6E, 0xAA77, 0xCC6F, 0xAA78, 0xCC70, 0xC3B1, 0xCC71, 0xAA79, 0xCC72, 0xAA7A, 0xCC73, 0xAA81, 0xCC74, 0xAA82, 0xCC75, 0xC3B2, 0xCC76, 0xAA83, 0xCC77, 0xAA84, 0xCC78, 0xAA85, 0xCC79, 0xAA86, 0xCC7A, 0xAA87, 0xCC7B, 0xAA88, 0xCC7C, 0xAA89, 0xCC7D, 0xAA8A, 0xCC7E, 0xAA8B, 0xCC7F, 0xAA8C, 0xCC80, 0xAA8D, 0xCC81, 0xAA8E, 0xCC82, 0xAA8F, 0xCC83, 0xAA90, 0xCC84, 0xAA91, 0xCC85, 0xAA92, 0xCC86, 0xAA93, 0xCC87, 0xAA94, 0xCC88, 0xAA95, 0xCC89, 0xAA96, 0xCC8A, 0xAA97, 0xCC8B, 0xAA98, 0xCC8C, 0xAA99, 0xCC8D, 0xAA9A, 0xCC8E, 0xAA9B, 0xCC8F, 0xAA9C, 0xCC90, 0xAA9D, 0xCC91, 0xAA9E, 0xCC92, 0xAA9F, 0xCC93, 0xAAA0, 0xCC94, 0xAB41, 0xCC95, 0xAB42, 0xCC96, 0xAB43, 0xCC97, 0xAB44, 0xCC98, 0xC3B3, 0xCC99, 0xC3B4, 0xCC9A, 0xAB45, 0xCC9B, 0xAB46, 0xCC9C, 0xC3B5, 0xCC9D, 0xAB47, 0xCC9E, 0xAB48, 0xCC9F, 0xAB49, 0xCCA0, 0xC3B6, 0xCCA1, 0xAB4A, 0xCCA2, 0xAB4B, 0xCCA3, 0xAB4C, 0xCCA4, 0xAB4D, 0xCCA5, 0xAB4E, 0xCCA6, 0xAB4F, 0xCCA7, 0xAB50, 0xCCA8, 0xC3B7, 0xCCA9, 0xC3B8, 0xCCAA, 0xAB51, 0xCCAB, 0xC3B9, 0xCCAC, 0xC3BA, 0xCCAD, 0xC3BB, 0xCCAE, 0xAB52, 0xCCAF, 0xAB53, 0xCCB0, 0xAB54, 0xCCB1, 0xAB55, 0xCCB2, 0xAB56, 0xCCB3, 0xAB57, 0xCCB4, 0xC3BC, 0xCCB5, 0xC3BD, 0xCCB6, 0xAB58, 0xCCB7, 0xAB59, 0xCCB8, 0xC3BE, 0xCCB9, 0xAB5A, 0xCCBA, 0xAB61, 0xCCBB, 0xAB62, 0xCCBC, 0xC3BF, 0xCCBD, 0xAB63, 0xCCBE, 0xAB64, 0xCCBF, 0xAB65, 0xCCC0, 0xAB66, 0xCCC1, 0xAB67, 0xCCC2, 0xAB68, 0xCCC3, 0xAB69, 0xCCC4, 0xC3C0, 0xCCC5, 0xC3C1, 0xCCC6, 0xAB6A, 0xCCC7, 0xC3C2, 0xCCC8, 0xAB6B, 0xCCC9, 0xC3C3, 0xCCCA, 0xAB6C, 0xCCCB, 0xAB6D, 0xCCCC, 0xAB6E, 0xCCCD, 0xAB6F, 0xCCCE, 0xAB70, 0xCCCF, 0xAB71, 0xCCD0, 0xC3C4, 0xCCD1, 0xAB72, 0xCCD2, 0xAB73, 0xCCD3, 0xAB74, 0xCCD4, 0xC3C5, 0xCCD5, 0xAB75, 0xCCD6, 0xAB76, 0xCCD7, 0xAB77, 0xCCD8, 0xAB78, 0xCCD9, 0xAB79, 0xCCDA, 0xAB7A, 0xCCDB, 0xAB81, 0xCCDC, 0xAB82, 0xCCDD, 0xAB83, 0xCCDE, 0xAB84, 0xCCDF, 0xAB85, 0xCCE0, 0xAB86, 0xCCE1, 0xAB87, 0xCCE2, 0xAB88, 0xCCE3, 0xAB89, 0xCCE4, 0xC3C6, 0xCCE5, 0xAB8A, 0xCCE6, 0xAB8B, 0xCCE7, 0xAB8C, 0xCCE8, 0xAB8D, 0xCCE9, 0xAB8E, 0xCCEA, 0xAB8F, 0xCCEB, 0xAB90, 0xCCEC, 0xC3C7, 0xCCED, 0xAB91, 0xCCEE, 0xAB92, 0xCCEF, 0xAB93, 0xCCF0, 0xC3C8, 0xCCF1, 0xAB94, 0xCCF2, 0xAB95, 0xCCF3, 0xAB96, 0xCCF4, 0xAB97, 0xCCF5, 0xAB98, 0xCCF6, 0xAB99, 0xCCF7, 0xAB9A, 0xCCF8, 0xAB9B, 0xCCF9, 0xAB9C, 0xCCFA, 0xAB9D, 0xCCFB, 0xAB9E, 0xCCFC, 0xAB9F, 0xCCFD, 0xABA0, 0xCCFE, 0xAC41, 0xCCFF, 0xAC42, 0xCD00, 0xAC43, 0xCD01, 0xC3C9, 0xCD02, 0xAC44, 0xCD03, 0xAC45, 0xCD04, 0xAC46, 0xCD05, 0xAC47, 0xCD06, 0xAC48, 0xCD07, 0xAC49, 0xCD08, 0xC3CA, 0xCD09, 0xC3CB, 0xCD0A, 0xAC4A, 0xCD0B, 0xAC4B, 0xCD0C, 0xC3CC, 0xCD0D, 0xAC4C, 0xCD0E, 0xAC4D, 0xCD0F, 0xAC4E, 0xCD10, 0xC3CD, 0xCD11, 0xAC4F, 0xCD12, 0xAC50, 0xCD13, 0xAC51, 0xCD14, 0xAC52, 0xCD15, 0xAC53, 0xCD16, 0xAC54, 0xCD17, 0xAC55, 0xCD18, 0xC3CE, 0xCD19, 0xC3CF, 0xCD1A, 0xAC56, 0xCD1B, 0xC3D0, 0xCD1C, 0xAC57, 0xCD1D, 0xC3D1, 0xCD1E, 0xAC58, 0xCD1F, 0xAC59, 0xCD20, 0xAC5A, 0xCD21, 0xAC61, 0xCD22, 0xAC62, 0xCD23, 0xAC63, 0xCD24, 0xC3D2, 0xCD25, 0xAC64, 0xCD26, 0xAC65, 0xCD27, 0xAC66, 0xCD28, 0xC3D3, 0xCD29, 0xAC67, 0xCD2A, 0xAC68, 0xCD2B, 0xAC69, 0xCD2C, 0xC3D4, 0xCD2D, 0xAC6A, 0xCD2E, 0xAC6B, 0xCD2F, 0xAC6C, 0xCD30, 0xAC6D, 0xCD31, 0xAC6E, 0xCD32, 0xAC6F, 0xCD33, 0xAC70, 0xCD34, 0xAC71, 0xCD35, 0xAC72, 0xCD36, 0xAC73, 0xCD37, 0xAC74, 0xCD38, 0xAC75, 0xCD39, 0xC3D5, 0xCD3A, 0xAC76, 0xCD3B, 0xAC77, 0xCD3C, 0xAC78, 0xCD3D, 0xAC79, 0xCD3E, 0xAC7A, 0xCD3F, 0xAC81, 0xCD40, 0xAC82, 0xCD41, 0xAC83, 0xCD42, 0xAC84, 0xCD43, 0xAC85, 0xCD44, 0xAC86, 0xCD45, 0xAC87, 0xCD46, 0xAC88, 0xCD47, 0xAC89, 0xCD48, 0xAC8A, 0xCD49, 0xAC8B, 0xCD4A, 0xAC8C, 0xCD4B, 0xAC8D, 0xCD4C, 0xAC8E, 0xCD4D, 0xAC8F, 0xCD4E, 0xAC90, 0xCD4F, 0xAC91, 0xCD50, 0xAC92, 0xCD51, 0xAC93, 0xCD52, 0xAC94, 0xCD53, 0xAC95, 0xCD54, 0xAC96, 0xCD55, 0xAC97, 0xCD56, 0xAC98, 0xCD57, 0xAC99, 0xCD58, 0xAC9A, 0xCD59, 0xAC9B, 0xCD5A, 0xAC9C, 0xCD5B, 0xAC9D, 0xCD5C, 0xC3D6, 0xCD5D, 0xAC9E, 0xCD5E, 0xAC9F, 0xCD5F, 0xACA0, 0xCD60, 0xC3D7, 0xCD61, 0xAD41, 0xCD62, 0xAD42, 0xCD63, 0xAD43, 0xCD64, 0xC3D8, 0xCD65, 0xAD44, 0xCD66, 0xAD45, 0xCD67, 0xAD46, 0xCD68, 0xAD47, 0xCD69, 0xAD48, 0xCD6A, 0xAD49, 0xCD6B, 0xAD4A, 0xCD6C, 0xC3D9, 0xCD6D, 0xC3DA, 0xCD6E, 0xAD4B, 0xCD6F, 0xC3DB, 0xCD70, 0xAD4C, 0xCD71, 0xC3DC, 0xCD72, 0xAD4D, 0xCD73, 0xAD4E, 0xCD74, 0xAD4F, 0xCD75, 0xAD50, 0xCD76, 0xAD51, 0xCD77, 0xAD52, 0xCD78, 0xC3DD, 0xCD79, 0xAD53, 0xCD7A, 0xAD54, 0xCD7B, 0xAD55, 0xCD7C, 0xAD56, 0xCD7D, 0xAD57, 0xCD7E, 0xAD58, 0xCD7F, 0xAD59, 0xCD80, 0xAD5A, 0xCD81, 0xAD61, 0xCD82, 0xAD62, 0xCD83, 0xAD63, 0xCD84, 0xAD64, 0xCD85, 0xAD65, 0xCD86, 0xAD66, 0xCD87, 0xAD67, 0xCD88, 0xC3DE, 0xCD89, 0xAD68, 0xCD8A, 0xAD69, 0xCD8B, 0xAD6A, 0xCD8C, 0xAD6B, 0xCD8D, 0xAD6C, 0xCD8E, 0xAD6D, 0xCD8F, 0xAD6E, 0xCD90, 0xAD6F, 0xCD91, 0xAD70, 0xCD92, 0xAD71, 0xCD93, 0xAD72, 0xCD94, 0xC3DF, 0xCD95, 0xC3E0, 0xCD96, 0xAD73, 0xCD97, 0xAD74, 0xCD98, 0xC3E1, 0xCD99, 0xAD75, 0xCD9A, 0xAD76, 0xCD9B, 0xAD77, 0xCD9C, 0xC3E2, 0xCD9D, 0xAD78, 0xCD9E, 0xAD79, 0xCD9F, 0xAD7A, 0xCDA0, 0xAD81, 0xCDA1, 0xAD82, 0xCDA2, 0xAD83, 0xCDA3, 0xAD84, 0xCDA4, 0xC3E3, 0xCDA5, 0xC3E4, 0xCDA6, 0xAD85, 0xCDA7, 0xC3E5, 0xCDA8, 0xAD86, 0xCDA9, 0xC3E6, 0xCDAA, 0xAD87, 0xCDAB, 0xAD88, 0xCDAC, 0xAD89, 0xCDAD, 0xAD8A, 0xCDAE, 0xAD8B, 0xCDAF, 0xAD8C, 0xCDB0, 0xC3E7, 0xCDB1, 0xAD8D, 0xCDB2, 0xAD8E, 0xCDB3, 0xAD8F, 0xCDB4, 0xAD90, 0xCDB5, 0xAD91, 0xCDB6, 0xAD92, 0xCDB7, 0xAD93, 0xCDB8, 0xAD94, 0xCDB9, 0xAD95, 0xCDBA, 0xAD96, 0xCDBB, 0xAD97, 0xCDBC, 0xAD98, 0xCDBD, 0xAD99, 0xCDBE, 0xAD9A, 0xCDBF, 0xAD9B, 0xCDC0, 0xAD9C, 0xCDC1, 0xAD9D, 0xCDC2, 0xAD9E, 0xCDC3, 0xAD9F, 0xCDC4, 0xC3E8, 0xCDC5, 0xADA0, 0xCDC6, 0xAE41, 0xCDC7, 0xAE42, 0xCDC8, 0xAE43, 0xCDC9, 0xAE44, 0xCDCA, 0xAE45, 0xCDCB, 0xAE46, 0xCDCC, 0xC3E9, 0xCDCD, 0xAE47, 0xCDCE, 0xAE48, 0xCDCF, 0xAE49, 0xCDD0, 0xC3EA, 0xCDD1, 0xAE4A, 0xCDD2, 0xAE4B, 0xCDD3, 0xAE4C, 0xCDD4, 0xAE4D, 0xCDD5, 0xAE4E, 0xCDD6, 0xAE4F, 0xCDD7, 0xAE50, 0xCDD8, 0xAE51, 0xCDD9, 0xAE52, 0xCDDA, 0xAE53, 0xCDDB, 0xAE54, 0xCDDC, 0xAE55, 0xCDDD, 0xAE56, 0xCDDE, 0xAE57, 0xCDDF, 0xAE58, 0xCDE0, 0xAE59, 0xCDE1, 0xAE5A, 0xCDE2, 0xAE61, 0xCDE3, 0xAE62, 0xCDE4, 0xAE63, 0xCDE5, 0xAE64, 0xCDE6, 0xAE65, 0xCDE7, 0xAE66, 0xCDE8, 0xC3EB, 0xCDE9, 0xAE67, 0xCDEA, 0xAE68, 0xCDEB, 0xAE69, 0xCDEC, 0xC3EC, 0xCDED, 0xAE6A, 0xCDEE, 0xAE6B, 0xCDEF, 0xAE6C, 0xCDF0, 0xC3ED, 0xCDF1, 0xAE6D, 0xCDF2, 0xAE6E, 0xCDF3, 0xAE6F, 0xCDF4, 0xAE70, 0xCDF5, 0xAE71, 0xCDF6, 0xAE72, 0xCDF7, 0xAE73, 0xCDF8, 0xC3EE, 0xCDF9, 0xC3EF, 0xCDFA, 0xAE74, 0xCDFB, 0xC3F0, 0xCDFC, 0xAE75, 0xCDFD, 0xC3F1, 0xCDFE, 0xAE76, 0xCDFF, 0xAE77, 0xCE00, 0xAE78, 0xCE01, 0xAE79, 0xCE02, 0xAE7A, 0xCE03, 0xAE81, 0xCE04, 0xC3F2, 0xCE05, 0xAE82, 0xCE06, 0xAE83, 0xCE07, 0xAE84, 0xCE08, 0xC3F3, 0xCE09, 0xAE85, 0xCE0A, 0xAE86, 0xCE0B, 0xAE87, 0xCE0C, 0xC3F4, 0xCE0D, 0xAE88, 0xCE0E, 0xAE89, 0xCE0F, 0xAE8A, 0xCE10, 0xAE8B, 0xCE11, 0xAE8C, 0xCE12, 0xAE8D, 0xCE13, 0xAE8E, 0xCE14, 0xC3F5, 0xCE15, 0xAE8F, 0xCE16, 0xAE90, 0xCE17, 0xAE91, 0xCE18, 0xAE92, 0xCE19, 0xC3F6, 0xCE1A, 0xAE93, 0xCE1B, 0xAE94, 0xCE1C, 0xAE95, 0xCE1D, 0xAE96, 0xCE1E, 0xAE97, 0xCE1F, 0xAE98, 0xCE20, 0xC3F7, 0xCE21, 0xC3F8, 0xCE22, 0xAE99, 0xCE23, 0xAE9A, 0xCE24, 0xC3F9, 0xCE25, 0xAE9B, 0xCE26, 0xAE9C, 0xCE27, 0xAE9D, 0xCE28, 0xC3FA, 0xCE29, 0xAE9E, 0xCE2A, 0xAE9F, 0xCE2B, 0xAEA0, 0xCE2C, 0xAF41, 0xCE2D, 0xAF42, 0xCE2E, 0xAF43, 0xCE2F, 0xAF44, 0xCE30, 0xC3FB, 0xCE31, 0xC3FC, 0xCE32, 0xAF45, 0xCE33, 0xC3FD, 0xCE34, 0xAF46, 0xCE35, 0xC3FE, 0xCE36, 0xAF47, 0xCE37, 0xAF48, 0xCE38, 0xAF49, 0xCE39, 0xAF4A, 0xCE3A, 0xAF4B, 0xCE3B, 0xAF4C, 0xCE3C, 0xAF4D, 0xCE3D, 0xAF4E, 0xCE3E, 0xAF4F, 0xCE3F, 0xAF50, 0xCE40, 0xAF51, 0xCE41, 0xAF52, 0xCE42, 0xAF53, 0xCE43, 0xAF54, 0xCE44, 0xAF55, 0xCE45, 0xAF56, 0xCE46, 0xAF57, 0xCE47, 0xAF58, 0xCE48, 0xAF59, 0xCE49, 0xAF5A, 0xCE4A, 0xAF61, 0xCE4B, 0xAF62, 0xCE4C, 0xAF63, 0xCE4D, 0xAF64, 0xCE4E, 0xAF65, 0xCE4F, 0xAF66, 0xCE50, 0xAF67, 0xCE51, 0xAF68, 0xCE52, 0xAF69, 0xCE53, 0xAF6A, 0xCE54, 0xAF6B, 0xCE55, 0xAF6C, 0xCE56, 0xAF6D, 0xCE57, 0xAF6E, 0xCE58, 0xC4A1, 0xCE59, 0xC4A2, 0xCE5A, 0xAF6F, 0xCE5B, 0xAF70, 0xCE5C, 0xC4A3, 0xCE5D, 0xAF71, 0xCE5E, 0xAF72, 0xCE5F, 0xC4A4, 0xCE60, 0xC4A5, 0xCE61, 0xC4A6, 0xCE62, 0xAF73, 0xCE63, 0xAF74, 0xCE64, 0xAF75, 0xCE65, 0xAF76, 0xCE66, 0xAF77, 0xCE67, 0xAF78, 0xCE68, 0xC4A7, 0xCE69, 0xC4A8, 0xCE6A, 0xAF79, 0xCE6B, 0xC4A9, 0xCE6C, 0xAF7A, 0xCE6D, 0xC4AA, 0xCE6E, 0xAF81, 0xCE6F, 0xAF82, 0xCE70, 0xAF83, 0xCE71, 0xAF84, 0xCE72, 0xAF85, 0xCE73, 0xAF86, 0xCE74, 0xC4AB, 0xCE75, 0xC4AC, 0xCE76, 0xAF87, 0xCE77, 0xAF88, 0xCE78, 0xC4AD, 0xCE79, 0xAF89, 0xCE7A, 0xAF8A, 0xCE7B, 0xAF8B, 0xCE7C, 0xC4AE, 0xCE7D, 0xAF8C, 0xCE7E, 0xAF8D, 0xCE7F, 0xAF8E, 0xCE80, 0xAF8F, 0xCE81, 0xAF90, 0xCE82, 0xAF91, 0xCE83, 0xAF92, 0xCE84, 0xC4AF, 0xCE85, 0xC4B0, 0xCE86, 0xAF93, 0xCE87, 0xC4B1, 0xCE88, 0xAF94, 0xCE89, 0xC4B2, 0xCE8A, 0xAF95, 0xCE8B, 0xAF96, 0xCE8C, 0xAF97, 0xCE8D, 0xAF98, 0xCE8E, 0xAF99, 0xCE8F, 0xAF9A, 0xCE90, 0xC4B3, 0xCE91, 0xC4B4, 0xCE92, 0xAF9B, 0xCE93, 0xAF9C, 0xCE94, 0xC4B5, 0xCE95, 0xAF9D, 0xCE96, 0xAF9E, 0xCE97, 0xAF9F, 0xCE98, 0xC4B6, 0xCE99, 0xAFA0, 0xCE9A, 0xB041, 0xCE9B, 0xB042, 0xCE9C, 0xB043, 0xCE9D, 0xB044, 0xCE9E, 0xB045, 0xCE9F, 0xB046, 0xCEA0, 0xC4B7, 0xCEA1, 0xC4B8, 0xCEA2, 0xB047, 0xCEA3, 0xC4B9, 0xCEA4, 0xC4BA, 0xCEA5, 0xC4BB, 0xCEA6, 0xB048, 0xCEA7, 0xB049, 0xCEA8, 0xB04A, 0xCEA9, 0xB04B, 0xCEAA, 0xB04C, 0xCEAB, 0xB04D, 0xCEAC, 0xC4BC, 0xCEAD, 0xC4BD, 0xCEAE, 0xB04E, 0xCEAF, 0xB04F, 0xCEB0, 0xB050, 0xCEB1, 0xB051, 0xCEB2, 0xB052, 0xCEB3, 0xB053, 0xCEB4, 0xB054, 0xCEB5, 0xB055, 0xCEB6, 0xB056, 0xCEB7, 0xB057, 0xCEB8, 0xB058, 0xCEB9, 0xB059, 0xCEBA, 0xB05A, 0xCEBB, 0xB061, 0xCEBC, 0xB062, 0xCEBD, 0xB063, 0xCEBE, 0xB064, 0xCEBF, 0xB065, 0xCEC0, 0xB066, 0xCEC1, 0xC4BE, 0xCEC2, 0xB067, 0xCEC3, 0xB068, 0xCEC4, 0xB069, 0xCEC5, 0xB06A, 0xCEC6, 0xB06B, 0xCEC7, 0xB06C, 0xCEC8, 0xB06D, 0xCEC9, 0xB06E, 0xCECA, 0xB06F, 0xCECB, 0xB070, 0xCECC, 0xB071, 0xCECD, 0xB072, 0xCECE, 0xB073, 0xCECF, 0xB074, 0xCED0, 0xB075, 0xCED1, 0xB076, 0xCED2, 0xB077, 0xCED3, 0xB078, 0xCED4, 0xB079, 0xCED5, 0xB07A, 0xCED6, 0xB081, 0xCED7, 0xB082, 0xCED8, 0xB083, 0xCED9, 0xB084, 0xCEDA, 0xB085, 0xCEDB, 0xB086, 0xCEDC, 0xB087, 0xCEDD, 0xB088, 0xCEDE, 0xB089, 0xCEDF, 0xB08A, 0xCEE0, 0xB08B, 0xCEE1, 0xB08C, 0xCEE2, 0xB08D, 0xCEE3, 0xB08E, 0xCEE4, 0xC4BF, 0xCEE5, 0xC4C0, 0xCEE6, 0xB08F, 0xCEE7, 0xB090, 0xCEE8, 0xC4C1, 0xCEE9, 0xB091, 0xCEEA, 0xB092, 0xCEEB, 0xC4C2, 0xCEEC, 0xC4C3, 0xCEED, 0xB093, 0xCEEE, 0xB094, 0xCEEF, 0xB095, 0xCEF0, 0xB096, 0xCEF1, 0xB097, 0xCEF2, 0xB098, 0xCEF3, 0xB099, 0xCEF4, 0xC4C4, 0xCEF5, 0xC4C5, 0xCEF6, 0xB09A, 0xCEF7, 0xC4C6, 0xCEF8, 0xC4C7, 0xCEF9, 0xC4C8, 0xCEFA, 0xB09B, 0xCEFB, 0xB09C, 0xCEFC, 0xB09D, 0xCEFD, 0xB09E, 0xCEFE, 0xB09F, 0xCEFF, 0xB0A0, 0xCF00, 0xC4C9, 0xCF01, 0xC4CA, 0xCF02, 0xB141, 0xCF03, 0xB142, 0xCF04, 0xC4CB, 0xCF05, 0xB143, 0xCF06, 0xB144, 0xCF07, 0xB145, 0xCF08, 0xC4CC, 0xCF09, 0xB146, 0xCF0A, 0xB147, 0xCF0B, 0xB148, 0xCF0C, 0xB149, 0xCF0D, 0xB14A, 0xCF0E, 0xB14B, 0xCF0F, 0xB14C, 0xCF10, 0xC4CD, 0xCF11, 0xC4CE, 0xCF12, 0xB14D, 0xCF13, 0xC4CF, 0xCF14, 0xB14E, 0xCF15, 0xC4D0, 0xCF16, 0xB14F, 0xCF17, 0xB150, 0xCF18, 0xB151, 0xCF19, 0xB152, 0xCF1A, 0xB153, 0xCF1B, 0xB154, 0xCF1C, 0xC4D1, 0xCF1D, 0xB155, 0xCF1E, 0xB156, 0xCF1F, 0xB157, 0xCF20, 0xC4D2, 0xCF21, 0xB158, 0xCF22, 0xB159, 0xCF23, 0xB15A, 0xCF24, 0xC4D3, 0xCF25, 0xB161, 0xCF26, 0xB162, 0xCF27, 0xB163, 0xCF28, 0xB164, 0xCF29, 0xB165, 0xCF2A, 0xB166, 0xCF2B, 0xB167, 0xCF2C, 0xC4D4, 0xCF2D, 0xC4D5, 0xCF2E, 0xB168, 0xCF2F, 0xC4D6, 0xCF30, 0xC4D7, 0xCF31, 0xC4D8, 0xCF32, 0xB169, 0xCF33, 0xB16A, 0xCF34, 0xB16B, 0xCF35, 0xB16C, 0xCF36, 0xB16D, 0xCF37, 0xB16E, 0xCF38, 0xC4D9, 0xCF39, 0xB16F, 0xCF3A, 0xB170, 0xCF3B, 0xB171, 0xCF3C, 0xB172, 0xCF3D, 0xB173, 0xCF3E, 0xB174, 0xCF3F, 0xB175, 0xCF40, 0xB176, 0xCF41, 0xB177, 0xCF42, 0xB178, 0xCF43, 0xB179, 0xCF44, 0xB17A, 0xCF45, 0xB181, 0xCF46, 0xB182, 0xCF47, 0xB183, 0xCF48, 0xB184, 0xCF49, 0xB185, 0xCF4A, 0xB186, 0xCF4B, 0xB187, 0xCF4C, 0xB188, 0xCF4D, 0xB189, 0xCF4E, 0xB18A, 0xCF4F, 0xB18B, 0xCF50, 0xB18C, 0xCF51, 0xB18D, 0xCF52, 0xB18E, 0xCF53, 0xB18F, 0xCF54, 0xC4DA, 0xCF55, 0xC4DB, 0xCF56, 0xB190, 0xCF57, 0xB191, 0xCF58, 0xC4DC, 0xCF59, 0xB192, 0xCF5A, 0xB193, 0xCF5B, 0xB194, 0xCF5C, 0xC4DD, 0xCF5D, 0xB195, 0xCF5E, 0xB196, 0xCF5F, 0xB197, 0xCF60, 0xB198, 0xCF61, 0xB199, 0xCF62, 0xB19A, 0xCF63, 0xB19B, 0xCF64, 0xC4DE, 0xCF65, 0xC4DF, 0xCF66, 0xB19C, 0xCF67, 0xC4E0, 0xCF68, 0xB19D, 0xCF69, 0xC4E1, 0xCF6A, 0xB19E, 0xCF6B, 0xB19F, 0xCF6C, 0xB1A0, 0xCF6D, 0xB241, 0xCF6E, 0xB242, 0xCF6F, 0xB243, 0xCF70, 0xC4E2, 0xCF71, 0xC4E3, 0xCF72, 0xB244, 0xCF73, 0xB245, 0xCF74, 0xC4E4, 0xCF75, 0xB246, 0xCF76, 0xB247, 0xCF77, 0xB248, 0xCF78, 0xC4E5, 0xCF79, 0xB249, 0xCF7A, 0xB24A, 0xCF7B, 0xB24B, 0xCF7C, 0xB24C, 0xCF7D, 0xB24D, 0xCF7E, 0xB24E, 0xCF7F, 0xB24F, 0xCF80, 0xC4E6, 0xCF81, 0xB250, 0xCF82, 0xB251, 0xCF83, 0xB252, 0xCF84, 0xB253, 0xCF85, 0xC4E7, 0xCF86, 0xB254, 0xCF87, 0xB255, 0xCF88, 0xB256, 0xCF89, 0xB257, 0xCF8A, 0xB258, 0xCF8B, 0xB259, 0xCF8C, 0xC4E8, 0xCF8D, 0xB25A, 0xCF8E, 0xB261, 0xCF8F, 0xB262, 0xCF90, 0xB263, 0xCF91, 0xB264, 0xCF92, 0xB265, 0xCF93, 0xB266, 0xCF94, 0xB267, 0xCF95, 0xB268, 0xCF96, 0xB269, 0xCF97, 0xB26A, 0xCF98, 0xB26B, 0xCF99, 0xB26C, 0xCF9A, 0xB26D, 0xCF9B, 0xB26E, 0xCF9C, 0xB26F, 0xCF9D, 0xB270, 0xCF9E, 0xB271, 0xCF9F, 0xB272, 0xCFA0, 0xB273, 0xCFA1, 0xC4E9, 0xCFA2, 0xB274, 0xCFA3, 0xB275, 0xCFA4, 0xB276, 0xCFA5, 0xB277, 0xCFA6, 0xB278, 0xCFA7, 0xB279, 0xCFA8, 0xC4EA, 0xCFA9, 0xB27A, 0xCFAA, 0xB281, 0xCFAB, 0xB282, 0xCFAC, 0xB283, 0xCFAD, 0xB284, 0xCFAE, 0xB285, 0xCFAF, 0xB286, 0xCFB0, 0xC4EB, 0xCFB1, 0xB287, 0xCFB2, 0xB288, 0xCFB3, 0xB289, 0xCFB4, 0xB28A, 0xCFB5, 0xB28B, 0xCFB6, 0xB28C, 0xCFB7, 0xB28D, 0xCFB8, 0xB28E, 0xCFB9, 0xB28F, 0xCFBA, 0xB290, 0xCFBB, 0xB291, 0xCFBC, 0xB292, 0xCFBD, 0xB293, 0xCFBE, 0xB294, 0xCFBF, 0xB295, 0xCFC0, 0xB296, 0xCFC1, 0xB297, 0xCFC2, 0xB298, 0xCFC3, 0xB299, 0xCFC4, 0xC4EC, 0xCFC5, 0xB29A, 0xCFC6, 0xB29B, 0xCFC7, 0xB29C, 0xCFC8, 0xB29D, 0xCFC9, 0xB29E, 0xCFCA, 0xB29F, 0xCFCB, 0xB2A0, 0xCFCC, 0xB341, 0xCFCD, 0xB342, 0xCFCE, 0xB343, 0xCFCF, 0xB344, 0xCFD0, 0xB345, 0xCFD1, 0xB346, 0xCFD2, 0xB347, 0xCFD3, 0xB348, 0xCFD4, 0xB349, 0xCFD5, 0xB34A, 0xCFD6, 0xB34B, 0xCFD7, 0xB34C, 0xCFD8, 0xB34D, 0xCFD9, 0xB34E, 0xCFDA, 0xB34F, 0xCFDB, 0xB350, 0xCFDC, 0xB351, 0xCFDD, 0xB352, 0xCFDE, 0xB353, 0xCFDF, 0xB354, 0xCFE0, 0xC4ED, 0xCFE1, 0xC4EE, 0xCFE2, 0xB355, 0xCFE3, 0xB356, 0xCFE4, 0xC4EF, 0xCFE5, 0xB357, 0xCFE6, 0xB358, 0xCFE7, 0xB359, 0xCFE8, 0xC4F0, 0xCFE9, 0xB35A, 0xCFEA, 0xB361, 0xCFEB, 0xB362, 0xCFEC, 0xB363, 0xCFED, 0xB364, 0xCFEE, 0xB365, 0xCFEF, 0xB366, 0xCFF0, 0xC4F1, 0xCFF1, 0xC4F2, 0xCFF2, 0xB367, 0xCFF3, 0xC4F3, 0xCFF4, 0xB368, 0xCFF5, 0xC4F4, 0xCFF6, 0xB369, 0xCFF7, 0xB36A, 0xCFF8, 0xB36B, 0xCFF9, 0xB36C, 0xCFFA, 0xB36D, 0xCFFB, 0xB36E, 0xCFFC, 0xC4F5, 0xCFFD, 0xB36F, 0xCFFE, 0xB370, 0xCFFF, 0xB371, 0xD000, 0xC4F6, 0xD001, 0xB372, 0xD002, 0xB373, 0xD003, 0xB374, 0xD004, 0xC4F7, 0xD005, 0xB375, 0xD006, 0xB376, 0xD007, 0xB377, 0xD008, 0xB378, 0xD009, 0xB379, 0xD00A, 0xB37A, 0xD00B, 0xB381, 0xD00C, 0xB382, 0xD00D, 0xB383, 0xD00E, 0xB384, 0xD00F, 0xB385, 0xD010, 0xB386, 0xD011, 0xC4F8, 0xD012, 0xB387, 0xD013, 0xB388, 0xD014, 0xB389, 0xD015, 0xB38A, 0xD016, 0xB38B, 0xD017, 0xB38C, 0xD018, 0xC4F9, 0xD019, 0xB38D, 0xD01A, 0xB38E, 0xD01B, 0xB38F, 0xD01C, 0xB390, 0xD01D, 0xB391, 0xD01E, 0xB392, 0xD01F, 0xB393, 0xD020, 0xB394, 0xD021, 0xB395, 0xD022, 0xB396, 0xD023, 0xB397, 0xD024, 0xB398, 0xD025, 0xB399, 0xD026, 0xB39A, 0xD027, 0xB39B, 0xD028, 0xB39C, 0xD029, 0xB39D, 0xD02A, 0xB39E, 0xD02B, 0xB39F, 0xD02C, 0xB3A0, 0xD02D, 0xC4FA, 0xD02E, 0xB441, 0xD02F, 0xB442, 0xD030, 0xB443, 0xD031, 0xB444, 0xD032, 0xB445, 0xD033, 0xB446, 0xD034, 0xC4FB, 0xD035, 0xC4FC, 0xD036, 0xB447, 0xD037, 0xB448, 0xD038, 0xC4FD, 0xD039, 0xB449, 0xD03A, 0xB44A, 0xD03B, 0xB44B, 0xD03C, 0xC4FE, 0xD03D, 0xB44C, 0xD03E, 0xB44D, 0xD03F, 0xB44E, 0xD040, 0xB44F, 0xD041, 0xB450, 0xD042, 0xB451, 0xD043, 0xB452, 0xD044, 0xC5A1, 0xD045, 0xC5A2, 0xD046, 0xB453, 0xD047, 0xC5A3, 0xD048, 0xB454, 0xD049, 0xC5A4, 0xD04A, 0xB455, 0xD04B, 0xB456, 0xD04C, 0xB457, 0xD04D, 0xB458, 0xD04E, 0xB459, 0xD04F, 0xB45A, 0xD050, 0xC5A5, 0xD051, 0xB461, 0xD052, 0xB462, 0xD053, 0xB463, 0xD054, 0xC5A6, 0xD055, 0xB464, 0xD056, 0xB465, 0xD057, 0xB466, 0xD058, 0xC5A7, 0xD059, 0xB467, 0xD05A, 0xB468, 0xD05B, 0xB469, 0xD05C, 0xB46A, 0xD05D, 0xB46B, 0xD05E, 0xB46C, 0xD05F, 0xB46D, 0xD060, 0xC5A8, 0xD061, 0xB46E, 0xD062, 0xB46F, 0xD063, 0xB470, 0xD064, 0xB471, 0xD065, 0xB472, 0xD066, 0xB473, 0xD067, 0xB474, 0xD068, 0xB475, 0xD069, 0xB476, 0xD06A, 0xB477, 0xD06B, 0xB478, 0xD06C, 0xC5A9, 0xD06D, 0xC5AA, 0xD06E, 0xB479, 0xD06F, 0xB47A, 0xD070, 0xC5AB, 0xD071, 0xB481, 0xD072, 0xB482, 0xD073, 0xB483, 0xD074, 0xC5AC, 0xD075, 0xB484, 0xD076, 0xB485, 0xD077, 0xB486, 0xD078, 0xB487, 0xD079, 0xB488, 0xD07A, 0xB489, 0xD07B, 0xB48A, 0xD07C, 0xC5AD, 0xD07D, 0xC5AE, 0xD07E, 0xB48B, 0xD07F, 0xB48C, 0xD080, 0xB48D, 0xD081, 0xC5AF, 0xD082, 0xB48E, 0xD083, 0xB48F, 0xD084, 0xB490, 0xD085, 0xB491, 0xD086, 0xB492, 0xD087, 0xB493, 0xD088, 0xB494, 0xD089, 0xB495, 0xD08A, 0xB496, 0xD08B, 0xB497, 0xD08C, 0xB498, 0xD08D, 0xB499, 0xD08E, 0xB49A, 0xD08F, 0xB49B, 0xD090, 0xB49C, 0xD091, 0xB49D, 0xD092, 0xB49E, 0xD093, 0xB49F, 0xD094, 0xB4A0, 0xD095, 0xB541, 0xD096, 0xB542, 0xD097, 0xB543, 0xD098, 0xB544, 0xD099, 0xB545, 0xD09A, 0xB546, 0xD09B, 0xB547, 0xD09C, 0xB548, 0xD09D, 0xB549, 0xD09E, 0xB54A, 0xD09F, 0xB54B, 0xD0A0, 0xB54C, 0xD0A1, 0xB54D, 0xD0A2, 0xB54E, 0xD0A3, 0xB54F, 0xD0A4, 0xC5B0, 0xD0A5, 0xC5B1, 0xD0A6, 0xB550, 0xD0A7, 0xB551, 0xD0A8, 0xC5B2, 0xD0A9, 0xB552, 0xD0AA, 0xB553, 0xD0AB, 0xB554, 0xD0AC, 0xC5B3, 0xD0AD, 0xB555, 0xD0AE, 0xB556, 0xD0AF, 0xB557, 0xD0B0, 0xB558, 0xD0B1, 0xB559, 0xD0B2, 0xB55A, 0xD0B3, 0xB561, 0xD0B4, 0xC5B4, 0xD0B5, 0xC5B5, 0xD0B6, 0xB562, 0xD0B7, 0xC5B6, 0xD0B8, 0xB563, 0xD0B9, 0xC5B7, 0xD0BA, 0xB564, 0xD0BB, 0xB565, 0xD0BC, 0xB566, 0xD0BD, 0xB567, 0xD0BE, 0xB568, 0xD0BF, 0xB569, 0xD0C0, 0xC5B8, 0xD0C1, 0xC5B9, 0xD0C2, 0xB56A, 0xD0C3, 0xB56B, 0xD0C4, 0xC5BA, 0xD0C5, 0xB56C, 0xD0C6, 0xB56D, 0xD0C7, 0xB56E, 0xD0C8, 0xC5BB, 0xD0C9, 0xC5BC, 0xD0CA, 0xB56F, 0xD0CB, 0xB570, 0xD0CC, 0xB571, 0xD0CD, 0xB572, 0xD0CE, 0xB573, 0xD0CF, 0xB574, 0xD0D0, 0xC5BD, 0xD0D1, 0xC5BE, 0xD0D2, 0xB575, 0xD0D3, 0xC5BF, 0xD0D4, 0xC5C0, 0xD0D5, 0xC5C1, 0xD0D6, 0xB576, 0xD0D7, 0xB577, 0xD0D8, 0xB578, 0xD0D9, 0xB579, 0xD0DA, 0xB57A, 0xD0DB, 0xB581, 0xD0DC, 0xC5C2, 0xD0DD, 0xC5C3, 0xD0DE, 0xB582, 0xD0DF, 0xB583, 0xD0E0, 0xC5C4, 0xD0E1, 0xB584, 0xD0E2, 0xB585, 0xD0E3, 0xB586, 0xD0E4, 0xC5C5, 0xD0E5, 0xB587, 0xD0E6, 0xB588, 0xD0E7, 0xB589, 0xD0E8, 0xB58A, 0xD0E9, 0xB58B, 0xD0EA, 0xB58C, 0xD0EB, 0xB58D, 0xD0EC, 0xC5C6, 0xD0ED, 0xC5C7, 0xD0EE, 0xB58E, 0xD0EF, 0xC5C8, 0xD0F0, 0xC5C9, 0xD0F1, 0xC5CA, 0xD0F2, 0xB58F, 0xD0F3, 0xB590, 0xD0F4, 0xB591, 0xD0F5, 0xB592, 0xD0F6, 0xB593, 0xD0F7, 0xB594, 0xD0F8, 0xC5CB, 0xD0F9, 0xB595, 0xD0FA, 0xB596, 0xD0FB, 0xB597, 0xD0FC, 0xB598, 0xD0FD, 0xB599, 0xD0FE, 0xB59A, 0xD0FF, 0xB59B, 0xD100, 0xB59C, 0xD101, 0xB59D, 0xD102, 0xB59E, 0xD103, 0xB59F, 0xD104, 0xB5A0, 0xD105, 0xB641, 0xD106, 0xB642, 0xD107, 0xB643, 0xD108, 0xB644, 0xD109, 0xB645, 0xD10A, 0xB646, 0xD10B, 0xB647, 0xD10C, 0xB648, 0xD10D, 0xC5CC, 0xD10E, 0xB649, 0xD10F, 0xB64A, 0xD110, 0xB64B, 0xD111, 0xB64C, 0xD112, 0xB64D, 0xD113, 0xB64E, 0xD114, 0xB64F, 0xD115, 0xB650, 0xD116, 0xB651, 0xD117, 0xB652, 0xD118, 0xB653, 0xD119, 0xB654, 0xD11A, 0xB655, 0xD11B, 0xB656, 0xD11C, 0xB657, 0xD11D, 0xB658, 0xD11E, 0xB659, 0xD11F, 0xB65A, 0xD120, 0xB661, 0xD121, 0xB662, 0xD122, 0xB663, 0xD123, 0xB664, 0xD124, 0xB665, 0xD125, 0xB666, 0xD126, 0xB667, 0xD127, 0xB668, 0xD128, 0xB669, 0xD129, 0xB66A, 0xD12A, 0xB66B, 0xD12B, 0xB66C, 0xD12C, 0xB66D, 0xD12D, 0xB66E, 0xD12E, 0xB66F, 0xD12F, 0xB670, 0xD130, 0xC5CD, 0xD131, 0xC5CE, 0xD132, 0xB671, 0xD133, 0xB672, 0xD134, 0xC5CF, 0xD135, 0xB673, 0xD136, 0xB674, 0xD137, 0xB675, 0xD138, 0xC5D0, 0xD139, 0xB676, 0xD13A, 0xC5D1, 0xD13B, 0xB677, 0xD13C, 0xB678, 0xD13D, 0xB679, 0xD13E, 0xB67A, 0xD13F, 0xB681, 0xD140, 0xC5D2, 0xD141, 0xC5D3, 0xD142, 0xB682, 0xD143, 0xC5D4, 0xD144, 0xC5D5, 0xD145, 0xC5D6, 0xD146, 0xB683, 0xD147, 0xB684, 0xD148, 0xB685, 0xD149, 0xB686, 0xD14A, 0xB687, 0xD14B, 0xB688, 0xD14C, 0xC5D7, 0xD14D, 0xC5D8, 0xD14E, 0xB689, 0xD14F, 0xB68A, 0xD150, 0xC5D9, 0xD151, 0xB68B, 0xD152, 0xB68C, 0xD153, 0xB68D, 0xD154, 0xC5DA, 0xD155, 0xB68E, 0xD156, 0xB68F, 0xD157, 0xB690, 0xD158, 0xB691, 0xD159, 0xB692, 0xD15A, 0xB693, 0xD15B, 0xB694, 0xD15C, 0xC5DB, 0xD15D, 0xC5DC, 0xD15E, 0xB695, 0xD15F, 0xC5DD, 0xD160, 0xB696, 0xD161, 0xC5DE, 0xD162, 0xB697, 0xD163, 0xB698, 0xD164, 0xB699, 0xD165, 0xB69A, 0xD166, 0xB69B, 0xD167, 0xB69C, 0xD168, 0xC5DF, 0xD169, 0xB69D, 0xD16A, 0xB69E, 0xD16B, 0xB69F, 0xD16C, 0xC5E0, 0xD16D, 0xB6A0, 0xD16E, 0xB741, 0xD16F, 0xB742, 0xD170, 0xB743, 0xD171, 0xB744, 0xD172, 0xB745, 0xD173, 0xB746, 0xD174, 0xB747, 0xD175, 0xB748, 0xD176, 0xB749, 0xD177, 0xB74A, 0xD178, 0xB74B, 0xD179, 0xB74C, 0xD17A, 0xB74D, 0xD17B, 0xB74E, 0xD17C, 0xC5E1, 0xD17D, 0xB74F, 0xD17E, 0xB750, 0xD17F, 0xB751, 0xD180, 0xB752, 0xD181, 0xB753, 0xD182, 0xB754, 0xD183, 0xB755, 0xD184, 0xC5E2, 0xD185, 0xB756, 0xD186, 0xB757, 0xD187, 0xB758, 0xD188, 0xC5E3, 0xD189, 0xB759, 0xD18A, 0xB75A, 0xD18B, 0xB761, 0xD18C, 0xB762, 0xD18D, 0xB763, 0xD18E, 0xB764, 0xD18F, 0xB765, 0xD190, 0xB766, 0xD191, 0xB767, 0xD192, 0xB768, 0xD193, 0xB769, 0xD194, 0xB76A, 0xD195, 0xB76B, 0xD196, 0xB76C, 0xD197, 0xB76D, 0xD198, 0xB76E, 0xD199, 0xB76F, 0xD19A, 0xB770, 0xD19B, 0xB771, 0xD19C, 0xB772, 0xD19D, 0xB773, 0xD19E, 0xB774, 0xD19F, 0xB775, 0xD1A0, 0xC5E4, 0xD1A1, 0xC5E5, 0xD1A2, 0xB776, 0xD1A3, 0xB777, 0xD1A4, 0xC5E6, 0xD1A5, 0xB778, 0xD1A6, 0xB779, 0xD1A7, 0xB77A, 0xD1A8, 0xC5E7, 0xD1A9, 0xB781, 0xD1AA, 0xB782, 0xD1AB, 0xB783, 0xD1AC, 0xB784, 0xD1AD, 0xB785, 0xD1AE, 0xB786, 0xD1AF, 0xB787, 0xD1B0, 0xC5E8, 0xD1B1, 0xC5E9, 0xD1B2, 0xB788, 0xD1B3, 0xC5EA, 0xD1B4, 0xB789, 0xD1B5, 0xC5EB, 0xD1B6, 0xB78A, 0xD1B7, 0xB78B, 0xD1B8, 0xB78C, 0xD1B9, 0xB78D, 0xD1BA, 0xC5EC, 0xD1BB, 0xB78E, 0xD1BC, 0xC5ED, 0xD1BD, 0xB78F, 0xD1BE, 0xB790, 0xD1BF, 0xB791, 0xD1C0, 0xC5EE, 0xD1C1, 0xB792, 0xD1C2, 0xB793, 0xD1C3, 0xB794, 0xD1C4, 0xB795, 0xD1C5, 0xB796, 0xD1C6, 0xB797, 0xD1C7, 0xB798, 0xD1C8, 0xB799, 0xD1C9, 0xB79A, 0xD1CA, 0xB79B, 0xD1CB, 0xB79C, 0xD1CC, 0xB79D, 0xD1CD, 0xB79E, 0xD1CE, 0xB79F, 0xD1CF, 0xB7A0, 0xD1D0, 0xB841, 0xD1D1, 0xB842, 0xD1D2, 0xB843, 0xD1D3, 0xB844, 0xD1D4, 0xB845, 0xD1D5, 0xB846, 0xD1D6, 0xB847, 0xD1D7, 0xB848, 0xD1D8, 0xC5EF, 0xD1D9, 0xB849, 0xD1DA, 0xB84A, 0xD1DB, 0xB84B, 0xD1DC, 0xB84C, 0xD1DD, 0xB84D, 0xD1DE, 0xB84E, 0xD1DF, 0xB84F, 0xD1E0, 0xB850, 0xD1E1, 0xB851, 0xD1E2, 0xB852, 0xD1E3, 0xB853, 0xD1E4, 0xB854, 0xD1E5, 0xB855, 0xD1E6, 0xB856, 0xD1E7, 0xB857, 0xD1E8, 0xB858, 0xD1E9, 0xB859, 0xD1EA, 0xB85A, 0xD1EB, 0xB861, 0xD1EC, 0xB862, 0xD1ED, 0xB863, 0xD1EE, 0xB864, 0xD1EF, 0xB865, 0xD1F0, 0xB866, 0xD1F1, 0xB867, 0xD1F2, 0xB868, 0xD1F3, 0xB869, 0xD1F4, 0xC5F0, 0xD1F5, 0xB86A, 0xD1F6, 0xB86B, 0xD1F7, 0xB86C, 0xD1F8, 0xC5F1, 0xD1F9, 0xB86D, 0xD1FA, 0xB86E, 0xD1FB, 0xB86F, 0xD1FC, 0xB870, 0xD1FD, 0xB871, 0xD1FE, 0xB872, 0xD1FF, 0xB873, 0xD200, 0xB874, 0xD201, 0xB875, 0xD202, 0xB876, 0xD203, 0xB877, 0xD204, 0xB878, 0xD205, 0xB879, 0xD206, 0xB87A, 0xD207, 0xC5F2, 0xD208, 0xB881, 0xD209, 0xC5F3, 0xD20A, 0xB882, 0xD20B, 0xB883, 0xD20C, 0xB884, 0xD20D, 0xB885, 0xD20E, 0xB886, 0xD20F, 0xB887, 0xD210, 0xC5F4, 0xD211, 0xB888, 0xD212, 0xB889, 0xD213, 0xB88A, 0xD214, 0xB88B, 0xD215, 0xB88C, 0xD216, 0xB88D, 0xD217, 0xB88E, 0xD218, 0xB88F, 0xD219, 0xB890, 0xD21A, 0xB891, 0xD21B, 0xB892, 0xD21C, 0xB893, 0xD21D, 0xB894, 0xD21E, 0xB895, 0xD21F, 0xB896, 0xD220, 0xB897, 0xD221, 0xB898, 0xD222, 0xB899, 0xD223, 0xB89A, 0xD224, 0xB89B, 0xD225, 0xB89C, 0xD226, 0xB89D, 0xD227, 0xB89E, 0xD228, 0xB89F, 0xD229, 0xB8A0, 0xD22A, 0xB941, 0xD22B, 0xB942, 0xD22C, 0xC5F5, 0xD22D, 0xC5F6, 0xD22E, 0xB943, 0xD22F, 0xB944, 0xD230, 0xC5F7, 0xD231, 0xB945, 0xD232, 0xB946, 0xD233, 0xB947, 0xD234, 0xC5F8, 0xD235, 0xB948, 0xD236, 0xB949, 0xD237, 0xB94A, 0xD238, 0xB94B, 0xD239, 0xB94C, 0xD23A, 0xB94D, 0xD23B, 0xB94E, 0xD23C, 0xC5F9, 0xD23D, 0xC5FA, 0xD23E, 0xB94F, 0xD23F, 0xC5FB, 0xD240, 0xB950, 0xD241, 0xC5FC, 0xD242, 0xB951, 0xD243, 0xB952, 0xD244, 0xB953, 0xD245, 0xB954, 0xD246, 0xB955, 0xD247, 0xB956, 0xD248, 0xC5FD, 0xD249, 0xB957, 0xD24A, 0xB958, 0xD24B, 0xB959, 0xD24C, 0xB95A, 0xD24D, 0xB961, 0xD24E, 0xB962, 0xD24F, 0xB963, 0xD250, 0xB964, 0xD251, 0xB965, 0xD252, 0xB966, 0xD253, 0xB967, 0xD254, 0xB968, 0xD255, 0xB969, 0xD256, 0xB96A, 0xD257, 0xB96B, 0xD258, 0xB96C, 0xD259, 0xB96D, 0xD25A, 0xB96E, 0xD25B, 0xB96F, 0xD25C, 0xC5FE, 0xD25D, 0xB970, 0xD25E, 0xB971, 0xD25F, 0xB972, 0xD260, 0xB973, 0xD261, 0xB974, 0xD262, 0xB975, 0xD263, 0xB976, 0xD264, 0xC6A1, 0xD265, 0xB977, 0xD266, 0xB978, 0xD267, 0xB979, 0xD268, 0xB97A, 0xD269, 0xB981, 0xD26A, 0xB982, 0xD26B, 0xB983, 0xD26C, 0xB984, 0xD26D, 0xB985, 0xD26E, 0xB986, 0xD26F, 0xB987, 0xD270, 0xB988, 0xD271, 0xB989, 0xD272, 0xB98A, 0xD273, 0xB98B, 0xD274, 0xB98C, 0xD275, 0xB98D, 0xD276, 0xB98E, 0xD277, 0xB98F, 0xD278, 0xB990, 0xD279, 0xB991, 0xD27A, 0xB992, 0xD27B, 0xB993, 0xD27C, 0xB994, 0xD27D, 0xB995, 0xD27E, 0xB996, 0xD27F, 0xB997, 0xD280, 0xC6A2, 0xD281, 0xC6A3, 0xD282, 0xB998, 0xD283, 0xB999, 0xD284, 0xC6A4, 0xD285, 0xB99A, 0xD286, 0xB99B, 0xD287, 0xB99C, 0xD288, 0xC6A5, 0xD289, 0xB99D, 0xD28A, 0xB99E, 0xD28B, 0xB99F, 0xD28C, 0xB9A0, 0xD28D, 0xBA41, 0xD28E, 0xBA42, 0xD28F, 0xBA43, 0xD290, 0xC6A6, 0xD291, 0xC6A7, 0xD292, 0xBA44, 0xD293, 0xBA45, 0xD294, 0xBA46, 0xD295, 0xC6A8, 0xD296, 0xBA47, 0xD297, 0xBA48, 0xD298, 0xBA49, 0xD299, 0xBA4A, 0xD29A, 0xBA4B, 0xD29B, 0xBA4C, 0xD29C, 0xC6A9, 0xD29D, 0xBA4D, 0xD29E, 0xBA4E, 0xD29F, 0xBA4F, 0xD2A0, 0xC6AA, 0xD2A1, 0xBA50, 0xD2A2, 0xBA51, 0xD2A3, 0xBA52, 0xD2A4, 0xC6AB, 0xD2A5, 0xBA53, 0xD2A6, 0xBA54, 0xD2A7, 0xBA55, 0xD2A8, 0xBA56, 0xD2A9, 0xBA57, 0xD2AA, 0xBA58, 0xD2AB, 0xBA59, 0xD2AC, 0xC6AC, 0xD2AD, 0xBA5A, 0xD2AE, 0xBA61, 0xD2AF, 0xBA62, 0xD2B0, 0xBA63, 0xD2B1, 0xC6AD, 0xD2B2, 0xBA64, 0xD2B3, 0xBA65, 0xD2B4, 0xBA66, 0xD2B5, 0xBA67, 0xD2B6, 0xBA68, 0xD2B7, 0xBA69, 0xD2B8, 0xC6AE, 0xD2B9, 0xC6AF, 0xD2BA, 0xBA6A, 0xD2BB, 0xBA6B, 0xD2BC, 0xC6B0, 0xD2BD, 0xBA6C, 0xD2BE, 0xBA6D, 0xD2BF, 0xC6B1, 0xD2C0, 0xC6B2, 0xD2C1, 0xBA6E, 0xD2C2, 0xC6B3, 0xD2C3, 0xBA6F, 0xD2C4, 0xBA70, 0xD2C5, 0xBA71, 0xD2C6, 0xBA72, 0xD2C7, 0xBA73, 0xD2C8, 0xC6B4, 0xD2C9, 0xC6B5, 0xD2CA, 0xBA74, 0xD2CB, 0xC6B6, 0xD2CC, 0xBA75, 0xD2CD, 0xBA76, 0xD2CE, 0xBA77, 0xD2CF, 0xBA78, 0xD2D0, 0xBA79, 0xD2D1, 0xBA7A, 0xD2D2, 0xBA81, 0xD2D3, 0xBA82, 0xD2D4, 0xC6B7, 0xD2D5, 0xBA83, 0xD2D6, 0xBA84, 0xD2D7, 0xBA85, 0xD2D8, 0xC6B8, 0xD2D9, 0xBA86, 0xD2DA, 0xBA87, 0xD2DB, 0xBA88, 0xD2DC, 0xC6B9, 0xD2DD, 0xBA89, 0xD2DE, 0xBA8A, 0xD2DF, 0xBA8B, 0xD2E0, 0xBA8C, 0xD2E1, 0xBA8D, 0xD2E2, 0xBA8E, 0xD2E3, 0xBA8F, 0xD2E4, 0xC6BA, 0xD2E5, 0xC6BB, 0xD2E6, 0xBA90, 0xD2E7, 0xBA91, 0xD2E8, 0xBA92, 0xD2E9, 0xBA93, 0xD2EA, 0xBA94, 0xD2EB, 0xBA95, 0xD2EC, 0xBA96, 0xD2ED, 0xBA97, 0xD2EE, 0xBA98, 0xD2EF, 0xBA99, 0xD2F0, 0xC6BC, 0xD2F1, 0xC6BD, 0xD2F2, 0xBA9A, 0xD2F3, 0xBA9B, 0xD2F4, 0xC6BE, 0xD2F5, 0xBA9C, 0xD2F6, 0xBA9D, 0xD2F7, 0xBA9E, 0xD2F8, 0xC6BF, 0xD2F9, 0xBA9F, 0xD2FA, 0xBAA0, 0xD2FB, 0xBB41, 0xD2FC, 0xBB42, 0xD2FD, 0xBB43, 0xD2FE, 0xBB44, 0xD2FF, 0xBB45, 0xD300, 0xC6C0, 0xD301, 0xC6C1, 0xD302, 0xBB46, 0xD303, 0xC6C2, 0xD304, 0xBB47, 0xD305, 0xC6C3, 0xD306, 0xBB48, 0xD307, 0xBB49, 0xD308, 0xBB4A, 0xD309, 0xBB4B, 0xD30A, 0xBB4C, 0xD30B, 0xBB4D, 0xD30C, 0xC6C4, 0xD30D, 0xC6C5, 0xD30E, 0xC6C6, 0xD30F, 0xBB4E, 0xD310, 0xC6C7, 0xD311, 0xBB4F, 0xD312, 0xBB50, 0xD313, 0xBB51, 0xD314, 0xC6C8, 0xD315, 0xBB52, 0xD316, 0xC6C9, 0xD317, 0xBB53, 0xD318, 0xBB54, 0xD319, 0xBB55, 0xD31A, 0xBB56, 0xD31B, 0xBB57, 0xD31C, 0xC6CA, 0xD31D, 0xC6CB, 0xD31E, 0xBB58, 0xD31F, 0xC6CC, 0xD320, 0xC6CD, 0xD321, 0xC6CE, 0xD322, 0xBB59, 0xD323, 0xBB5A, 0xD324, 0xBB61, 0xD325, 0xC6CF, 0xD326, 0xBB62, 0xD327, 0xBB63, 0xD328, 0xC6D0, 0xD329, 0xC6D1, 0xD32A, 0xBB64, 0xD32B, 0xBB65, 0xD32C, 0xC6D2, 0xD32D, 0xBB66, 0xD32E, 0xBB67, 0xD32F, 0xBB68, 0xD330, 0xC6D3, 0xD331, 0xBB69, 0xD332, 0xBB6A, 0xD333, 0xBB6B, 0xD334, 0xBB6C, 0xD335, 0xBB6D, 0xD336, 0xBB6E, 0xD337, 0xBB6F, 0xD338, 0xC6D4, 0xD339, 0xC6D5, 0xD33A, 0xBB70, 0xD33B, 0xC6D6, 0xD33C, 0xC6D7, 0xD33D, 0xC6D8, 0xD33E, 0xBB71, 0xD33F, 0xBB72, 0xD340, 0xBB73, 0xD341, 0xBB74, 0xD342, 0xBB75, 0xD343, 0xBB76, 0xD344, 0xC6D9, 0xD345, 0xC6DA, 0xD346, 0xBB77, 0xD347, 0xBB78, 0xD348, 0xBB79, 0xD349, 0xBB7A, 0xD34A, 0xBB81, 0xD34B, 0xBB82, 0xD34C, 0xBB83, 0xD34D, 0xBB84, 0xD34E, 0xBB85, 0xD34F, 0xBB86, 0xD350, 0xBB87, 0xD351, 0xBB88, 0xD352, 0xBB89, 0xD353, 0xBB8A, 0xD354, 0xBB8B, 0xD355, 0xBB8C, 0xD356, 0xBB8D, 0xD357, 0xBB8E, 0xD358, 0xBB8F, 0xD359, 0xBB90, 0xD35A, 0xBB91, 0xD35B, 0xBB92, 0xD35C, 0xBB93, 0xD35D, 0xBB94, 0xD35E, 0xBB95, 0xD35F, 0xBB96, 0xD360, 0xBB97, 0xD361, 0xBB98, 0xD362, 0xBB99, 0xD363, 0xBB9A, 0xD364, 0xBB9B, 0xD365, 0xBB9C, 0xD366, 0xBB9D, 0xD367, 0xBB9E, 0xD368, 0xBB9F, 0xD369, 0xBBA0, 0xD36A, 0xBC41, 0xD36B, 0xBC42, 0xD36C, 0xBC43, 0xD36D, 0xBC44, 0xD36E, 0xBC45, 0xD36F, 0xBC46, 0xD370, 0xBC47, 0xD371, 0xBC48, 0xD372, 0xBC49, 0xD373, 0xBC4A, 0xD374, 0xBC4B, 0xD375, 0xBC4C, 0xD376, 0xBC4D, 0xD377, 0xBC4E, 0xD378, 0xBC4F, 0xD379, 0xBC50, 0xD37A, 0xBC51, 0xD37B, 0xBC52, 0xD37C, 0xC6DB, 0xD37D, 0xC6DC, 0xD37E, 0xBC53, 0xD37F, 0xBC54, 0xD380, 0xC6DD, 0xD381, 0xBC55, 0xD382, 0xBC56, 0xD383, 0xBC57, 0xD384, 0xC6DE, 0xD385, 0xBC58, 0xD386, 0xBC59, 0xD387, 0xBC5A, 0xD388, 0xBC61, 0xD389, 0xBC62, 0xD38A, 0xBC63, 0xD38B, 0xBC64, 0xD38C, 0xC6DF, 0xD38D, 0xC6E0, 0xD38E, 0xBC65, 0xD38F, 0xC6E1, 0xD390, 0xC6E2, 0xD391, 0xC6E3, 0xD392, 0xBC66, 0xD393, 0xBC67, 0xD394, 0xBC68, 0xD395, 0xBC69, 0xD396, 0xBC6A, 0xD397, 0xBC6B, 0xD398, 0xC6E4, 0xD399, 0xC6E5, 0xD39A, 0xBC6C, 0xD39B, 0xBC6D, 0xD39C, 0xC6E6, 0xD39D, 0xBC6E, 0xD39E, 0xBC6F, 0xD39F, 0xBC70, 0xD3A0, 0xC6E7, 0xD3A1, 0xBC71, 0xD3A2, 0xBC72, 0xD3A3, 0xBC73, 0xD3A4, 0xBC74, 0xD3A5, 0xBC75, 0xD3A6, 0xBC76, 0xD3A7, 0xBC77, 0xD3A8, 0xC6E8, 0xD3A9, 0xC6E9, 0xD3AA, 0xBC78, 0xD3AB, 0xC6EA, 0xD3AC, 0xBC79, 0xD3AD, 0xC6EB, 0xD3AE, 0xBC7A, 0xD3AF, 0xBC81, 0xD3B0, 0xBC82, 0xD3B1, 0xBC83, 0xD3B2, 0xBC84, 0xD3B3, 0xBC85, 0xD3B4, 0xC6EC, 0xD3B5, 0xBC86, 0xD3B6, 0xBC87, 0xD3B7, 0xBC88, 0xD3B8, 0xC6ED, 0xD3B9, 0xBC89, 0xD3BA, 0xBC8A, 0xD3BB, 0xBC8B, 0xD3BC, 0xC6EE, 0xD3BD, 0xBC8C, 0xD3BE, 0xBC8D, 0xD3BF, 0xBC8E, 0xD3C0, 0xBC8F, 0xD3C1, 0xBC90, 0xD3C2, 0xBC91, 0xD3C3, 0xBC92, 0xD3C4, 0xC6EF, 0xD3C5, 0xC6F0, 0xD3C6, 0xBC93, 0xD3C7, 0xBC94, 0xD3C8, 0xC6F1, 0xD3C9, 0xC6F2, 0xD3CA, 0xBC95, 0xD3CB, 0xBC96, 0xD3CC, 0xBC97, 0xD3CD, 0xBC98, 0xD3CE, 0xBC99, 0xD3CF, 0xBC9A, 0xD3D0, 0xC6F3, 0xD3D1, 0xBC9B, 0xD3D2, 0xBC9C, 0xD3D3, 0xBC9D, 0xD3D4, 0xBC9E, 0xD3D5, 0xBC9F, 0xD3D6, 0xBCA0, 0xD3D7, 0xBD41, 0xD3D8, 0xC6F4, 0xD3D9, 0xBD42, 0xD3DA, 0xBD43, 0xD3DB, 0xBD44, 0xD3DC, 0xBD45, 0xD3DD, 0xBD46, 0xD3DE, 0xBD47, 0xD3DF, 0xBD48, 0xD3E0, 0xBD49, 0xD3E1, 0xC6F5, 0xD3E2, 0xBD4A, 0xD3E3, 0xC6F6, 0xD3E4, 0xBD4B, 0xD3E5, 0xBD4C, 0xD3E6, 0xBD4D, 0xD3E7, 0xBD4E, 0xD3E8, 0xBD4F, 0xD3E9, 0xBD50, 0xD3EA, 0xBD51, 0xD3EB, 0xBD52, 0xD3EC, 0xC6F7, 0xD3ED, 0xC6F8, 0xD3EE, 0xBD53, 0xD3EF, 0xBD54, 0xD3F0, 0xC6F9, 0xD3F1, 0xBD55, 0xD3F2, 0xBD56, 0xD3F3, 0xBD57, 0xD3F4, 0xC6FA, 0xD3F5, 0xBD58, 0xD3F6, 0xBD59, 0xD3F7, 0xBD5A, 0xD3F8, 0xBD61, 0xD3F9, 0xBD62, 0xD3FA, 0xBD63, 0xD3FB, 0xBD64, 0xD3FC, 0xC6FB, 0xD3FD, 0xC6FC, 0xD3FE, 0xBD65, 0xD3FF, 0xC6FD, 0xD400, 0xBD66, 0xD401, 0xC6FE, 0xD402, 0xBD67, 0xD403, 0xBD68, 0xD404, 0xBD69, 0xD405, 0xBD6A, 0xD406, 0xBD6B, 0xD407, 0xBD6C, 0xD408, 0xC7A1, 0xD409, 0xBD6D, 0xD40A, 0xBD6E, 0xD40B, 0xBD6F, 0xD40C, 0xBD70, 0xD40D, 0xBD71, 0xD40E, 0xBD72, 0xD40F, 0xBD73, 0xD410, 0xBD74, 0xD411, 0xBD75, 0xD412, 0xBD76, 0xD413, 0xBD77, 0xD414, 0xBD78, 0xD415, 0xBD79, 0xD416, 0xBD7A, 0xD417, 0xBD81, 0xD418, 0xBD82, 0xD419, 0xBD83, 0xD41A, 0xBD84, 0xD41B, 0xBD85, 0xD41C, 0xBD86, 0xD41D, 0xC7A2, 0xD41E, 0xBD87, 0xD41F, 0xBD88, 0xD420, 0xBD89, 0xD421, 0xBD8A, 0xD422, 0xBD8B, 0xD423, 0xBD8C, 0xD424, 0xBD8D, 0xD425, 0xBD8E, 0xD426, 0xBD8F, 0xD427, 0xBD90, 0xD428, 0xBD91, 0xD429, 0xBD92, 0xD42A, 0xBD93, 0xD42B, 0xBD94, 0xD42C, 0xBD95, 0xD42D, 0xBD96, 0xD42E, 0xBD97, 0xD42F, 0xBD98, 0xD430, 0xBD99, 0xD431, 0xBD9A, 0xD432, 0xBD9B, 0xD433, 0xBD9C, 0xD434, 0xBD9D, 0xD435, 0xBD9E, 0xD436, 0xBD9F, 0xD437, 0xBDA0, 0xD438, 0xBE41, 0xD439, 0xBE42, 0xD43A, 0xBE43, 0xD43B, 0xBE44, 0xD43C, 0xBE45, 0xD43D, 0xBE46, 0xD43E, 0xBE47, 0xD43F, 0xBE48, 0xD440, 0xC7A3, 0xD441, 0xBE49, 0xD442, 0xBE4A, 0xD443, 0xBE4B, 0xD444, 0xC7A4, 0xD445, 0xBE4C, 0xD446, 0xBE4D, 0xD447, 0xBE4E, 0xD448, 0xBE4F, 0xD449, 0xBE50, 0xD44A, 0xBE51, 0xD44B, 0xBE52, 0xD44C, 0xBE53, 0xD44D, 0xBE54, 0xD44E, 0xBE55, 0xD44F, 0xBE56, 0xD450, 0xBE57, 0xD451, 0xBE58, 0xD452, 0xBE59, 0xD453, 0xBE5A, 0xD454, 0xBE61, 0xD455, 0xBE62, 0xD456, 0xBE63, 0xD457, 0xBE64, 0xD458, 0xBE65, 0xD459, 0xBE66, 0xD45A, 0xBE67, 0xD45B, 0xBE68, 0xD45C, 0xC7A5, 0xD45D, 0xBE69, 0xD45E, 0xBE6A, 0xD45F, 0xBE6B, 0xD460, 0xC7A6, 0xD461, 0xBE6C, 0xD462, 0xBE6D, 0xD463, 0xBE6E, 0xD464, 0xC7A7, 0xD465, 0xBE6F, 0xD466, 0xBE70, 0xD467, 0xBE71, 0xD468, 0xBE72, 0xD469, 0xBE73, 0xD46A, 0xBE74, 0xD46B, 0xBE75, 0xD46C, 0xBE76, 0xD46D, 0xC7A8, 0xD46E, 0xBE77, 0xD46F, 0xC7A9, 0xD470, 0xBE78, 0xD471, 0xBE79, 0xD472, 0xBE7A, 0xD473, 0xBE81, 0xD474, 0xBE82, 0xD475, 0xBE83, 0xD476, 0xBE84, 0xD477, 0xBE85, 0xD478, 0xC7AA, 0xD479, 0xC7AB, 0xD47A, 0xBE86, 0xD47B, 0xBE87, 0xD47C, 0xC7AC, 0xD47D, 0xBE88, 0xD47E, 0xBE89, 0xD47F, 0xC7AD, 0xD480, 0xC7AE, 0xD481, 0xBE8A, 0xD482, 0xC7AF, 0xD483, 0xBE8B, 0xD484, 0xBE8C, 0xD485, 0xBE8D, 0xD486, 0xBE8E, 0xD487, 0xBE8F, 0xD488, 0xC7B0, 0xD489, 0xC7B1, 0xD48A, 0xBE90, 0xD48B, 0xC7B2, 0xD48C, 0xBE91, 0xD48D, 0xC7B3, 0xD48E, 0xBE92, 0xD48F, 0xBE93, 0xD490, 0xBE94, 0xD491, 0xBE95, 0xD492, 0xBE96, 0xD493, 0xBE97, 0xD494, 0xC7B4, 0xD495, 0xBE98, 0xD496, 0xBE99, 0xD497, 0xBE9A, 0xD498, 0xBE9B, 0xD499, 0xBE9C, 0xD49A, 0xBE9D, 0xD49B, 0xBE9E, 0xD49C, 0xBE9F, 0xD49D, 0xBEA0, 0xD49E, 0xBF41, 0xD49F, 0xBF42, 0xD4A0, 0xBF43, 0xD4A1, 0xBF44, 0xD4A2, 0xBF45, 0xD4A3, 0xBF46, 0xD4A4, 0xBF47, 0xD4A5, 0xBF48, 0xD4A6, 0xBF49, 0xD4A7, 0xBF4A, 0xD4A8, 0xBF4B, 0xD4A9, 0xC7B5, 0xD4AA, 0xBF4C, 0xD4AB, 0xBF4D, 0xD4AC, 0xBF4E, 0xD4AD, 0xBF4F, 0xD4AE, 0xBF50, 0xD4AF, 0xBF51, 0xD4B0, 0xBF52, 0xD4B1, 0xBF53, 0xD4B2, 0xBF54, 0xD4B3, 0xBF55, 0xD4B4, 0xBF56, 0xD4B5, 0xBF57, 0xD4B6, 0xBF58, 0xD4B7, 0xBF59, 0xD4B8, 0xBF5A, 0xD4B9, 0xBF61, 0xD4BA, 0xBF62, 0xD4BB, 0xBF63, 0xD4BC, 0xBF64, 0xD4BD, 0xBF65, 0xD4BE, 0xBF66, 0xD4BF, 0xBF67, 0xD4C0, 0xBF68, 0xD4C1, 0xBF69, 0xD4C2, 0xBF6A, 0xD4C3, 0xBF6B, 0xD4C4, 0xBF6C, 0xD4C5, 0xBF6D, 0xD4C6, 0xBF6E, 0xD4C7, 0xBF6F, 0xD4C8, 0xBF70, 0xD4C9, 0xBF71, 0xD4CA, 0xBF72, 0xD4CB, 0xBF73, 0xD4CC, 0xC7B6, 0xD4CD, 0xBF74, 0xD4CE, 0xBF75, 0xD4CF, 0xBF76, 0xD4D0, 0xC7B7, 0xD4D1, 0xBF77, 0xD4D2, 0xBF78, 0xD4D3, 0xBF79, 0xD4D4, 0xC7B8, 0xD4D5, 0xBF7A, 0xD4D6, 0xBF81, 0xD4D7, 0xBF82, 0xD4D8, 0xBF83, 0xD4D9, 0xBF84, 0xD4DA, 0xBF85, 0xD4DB, 0xBF86, 0xD4DC, 0xC7B9, 0xD4DD, 0xBF87, 0xD4DE, 0xBF88, 0xD4DF, 0xC7BA, 0xD4E0, 0xBF89, 0xD4E1, 0xBF8A, 0xD4E2, 0xBF8B, 0xD4E3, 0xBF8C, 0xD4E4, 0xBF8D, 0xD4E5, 0xBF8E, 0xD4E6, 0xBF8F, 0xD4E7, 0xBF90, 0xD4E8, 0xC7BB, 0xD4E9, 0xBF91, 0xD4EA, 0xBF92, 0xD4EB, 0xBF93, 0xD4EC, 0xC7BC, 0xD4ED, 0xBF94, 0xD4EE, 0xBF95, 0xD4EF, 0xBF96, 0xD4F0, 0xC7BD, 0xD4F1, 0xBF97, 0xD4F2, 0xBF98, 0xD4F3, 0xBF99, 0xD4F4, 0xBF9A, 0xD4F5, 0xBF9B, 0xD4F6, 0xBF9C, 0xD4F7, 0xBF9D, 0xD4F8, 0xC7BE, 0xD4F9, 0xBF9E, 0xD4FA, 0xBF9F, 0xD4FB, 0xC7BF, 0xD4FC, 0xBFA0, 0xD4FD, 0xC7C0, 0xD4FE, 0xC041, 0xD4FF, 0xC042, 0xD500, 0xC043, 0xD501, 0xC044, 0xD502, 0xC045, 0xD503, 0xC046, 0xD504, 0xC7C1, 0xD505, 0xC047, 0xD506, 0xC048, 0xD507, 0xC049, 0xD508, 0xC7C2, 0xD509, 0xC04A, 0xD50A, 0xC04B, 0xD50B, 0xC04C, 0xD50C, 0xC7C3, 0xD50D, 0xC04D, 0xD50E, 0xC04E, 0xD50F, 0xC04F, 0xD510, 0xC050, 0xD511, 0xC051, 0xD512, 0xC052, 0xD513, 0xC053, 0xD514, 0xC7C4, 0xD515, 0xC7C5, 0xD516, 0xC054, 0xD517, 0xC7C6, 0xD518, 0xC055, 0xD519, 0xC056, 0xD51A, 0xC057, 0xD51B, 0xC058, 0xD51C, 0xC059, 0xD51D, 0xC05A, 0xD51E, 0xC061, 0xD51F, 0xC062, 0xD520, 0xC063, 0xD521, 0xC064, 0xD522, 0xC065, 0xD523, 0xC066, 0xD524, 0xC067, 0xD525, 0xC068, 0xD526, 0xC069, 0xD527, 0xC06A, 0xD528, 0xC06B, 0xD529, 0xC06C, 0xD52A, 0xC06D, 0xD52B, 0xC06E, 0xD52C, 0xC06F, 0xD52D, 0xC070, 0xD52E, 0xC071, 0xD52F, 0xC072, 0xD530, 0xC073, 0xD531, 0xC074, 0xD532, 0xC075, 0xD533, 0xC076, 0xD534, 0xC077, 0xD535, 0xC078, 0xD536, 0xC079, 0xD537, 0xC07A, 0xD538, 0xC081, 0xD539, 0xC082, 0xD53A, 0xC083, 0xD53B, 0xC084, 0xD53C, 0xC7C7, 0xD53D, 0xC7C8, 0xD53E, 0xC085, 0xD53F, 0xC086, 0xD540, 0xC7C9, 0xD541, 0xC087, 0xD542, 0xC088, 0xD543, 0xC089, 0xD544, 0xC7CA, 0xD545, 0xC08A, 0xD546, 0xC08B, 0xD547, 0xC08C, 0xD548, 0xC08D, 0xD549, 0xC08E, 0xD54A, 0xC08F, 0xD54B, 0xC090, 0xD54C, 0xC7CB, 0xD54D, 0xC7CC, 0xD54E, 0xC091, 0xD54F, 0xC7CD, 0xD550, 0xC092, 0xD551, 0xC7CE, 0xD552, 0xC093, 0xD553, 0xC094, 0xD554, 0xC095, 0xD555, 0xC096, 0xD556, 0xC097, 0xD557, 0xC098, 0xD558, 0xC7CF, 0xD559, 0xC7D0, 0xD55A, 0xC099, 0xD55B, 0xC09A, 0xD55C, 0xC7D1, 0xD55D, 0xC09B, 0xD55E, 0xC09C, 0xD55F, 0xC09D, 0xD560, 0xC7D2, 0xD561, 0xC09E, 0xD562, 0xC09F, 0xD563, 0xC0A0, 0xD564, 0xC141, 0xD565, 0xC7D3, 0xD566, 0xC142, 0xD567, 0xC143, 0xD568, 0xC7D4, 0xD569, 0xC7D5, 0xD56A, 0xC144, 0xD56B, 0xC7D6, 0xD56C, 0xC145, 0xD56D, 0xC7D7, 0xD56E, 0xC146, 0xD56F, 0xC147, 0xD570, 0xC148, 0xD571, 0xC149, 0xD572, 0xC14A, 0xD573, 0xC14B, 0xD574, 0xC7D8, 0xD575, 0xC7D9, 0xD576, 0xC14C, 0xD577, 0xC14D, 0xD578, 0xC7DA, 0xD579, 0xC14E, 0xD57A, 0xC14F, 0xD57B, 0xC150, 0xD57C, 0xC7DB, 0xD57D, 0xC151, 0xD57E, 0xC152, 0xD57F, 0xC153, 0xD580, 0xC154, 0xD581, 0xC155, 0xD582, 0xC156, 0xD583, 0xC157, 0xD584, 0xC7DC, 0xD585, 0xC7DD, 0xD586, 0xC158, 0xD587, 0xC7DE, 0xD588, 0xC7DF, 0xD589, 0xC7E0, 0xD58A, 0xC159, 0xD58B, 0xC15A, 0xD58C, 0xC161, 0xD58D, 0xC162, 0xD58E, 0xC163, 0xD58F, 0xC164, 0xD590, 0xC7E1, 0xD591, 0xC165, 0xD592, 0xC166, 0xD593, 0xC167, 0xD594, 0xC168, 0xD595, 0xC169, 0xD596, 0xC16A, 0xD597, 0xC16B, 0xD598, 0xC16C, 0xD599, 0xC16D, 0xD59A, 0xC16E, 0xD59B, 0xC16F, 0xD59C, 0xC170, 0xD59D, 0xC171, 0xD59E, 0xC172, 0xD59F, 0xC173, 0xD5A0, 0xC174, 0xD5A1, 0xC175, 0xD5A2, 0xC176, 0xD5A3, 0xC177, 0xD5A4, 0xC178, 0xD5A5, 0xC7E2, 0xD5A6, 0xC179, 0xD5A7, 0xC17A, 0xD5A8, 0xC181, 0xD5A9, 0xC182, 0xD5AA, 0xC183, 0xD5AB, 0xC184, 0xD5AC, 0xC185, 0xD5AD, 0xC186, 0xD5AE, 0xC187, 0xD5AF, 0xC188, 0xD5B0, 0xC189, 0xD5B1, 0xC18A, 0xD5B2, 0xC18B, 0xD5B3, 0xC18C, 0xD5B4, 0xC18D, 0xD5B5, 0xC18E, 0xD5B6, 0xC18F, 0xD5B7, 0xC190, 0xD5B8, 0xC191, 0xD5B9, 0xC192, 0xD5BA, 0xC193, 0xD5BB, 0xC194, 0xD5BC, 0xC195, 0xD5BD, 0xC196, 0xD5BE, 0xC197, 0xD5BF, 0xC198, 0xD5C0, 0xC199, 0xD5C1, 0xC19A, 0xD5C2, 0xC19B, 0xD5C3, 0xC19C, 0xD5C4, 0xC19D, 0xD5C5, 0xC19E, 0xD5C6, 0xC19F, 0xD5C7, 0xC1A0, 0xD5C8, 0xC7E3, 0xD5C9, 0xC7E4, 0xD5CA, 0xC241, 0xD5CB, 0xC242, 0xD5CC, 0xC7E5, 0xD5CD, 0xC243, 0xD5CE, 0xC244, 0xD5CF, 0xC245, 0xD5D0, 0xC7E6, 0xD5D1, 0xC246, 0xD5D2, 0xC7E7, 0xD5D3, 0xC247, 0xD5D4, 0xC248, 0xD5D5, 0xC249, 0xD5D6, 0xC24A, 0xD5D7, 0xC24B, 0xD5D8, 0xC7E8, 0xD5D9, 0xC7E9, 0xD5DA, 0xC24C, 0xD5DB, 0xC7EA, 0xD5DC, 0xC24D, 0xD5DD, 0xC7EB, 0xD5DE, 0xC24E, 0xD5DF, 0xC24F, 0xD5E0, 0xC250, 0xD5E1, 0xC251, 0xD5E2, 0xC252, 0xD5E3, 0xC253, 0xD5E4, 0xC7EC, 0xD5E5, 0xC7ED, 0xD5E6, 0xC254, 0xD5E7, 0xC255, 0xD5E8, 0xC7EE, 0xD5E9, 0xC256, 0xD5EA, 0xC257, 0xD5EB, 0xC258, 0xD5EC, 0xC7EF, 0xD5ED, 0xC259, 0xD5EE, 0xC25A, 0xD5EF, 0xC261, 0xD5F0, 0xC262, 0xD5F1, 0xC263, 0xD5F2, 0xC264, 0xD5F3, 0xC265, 0xD5F4, 0xC7F0, 0xD5F5, 0xC7F1, 0xD5F6, 0xC266, 0xD5F7, 0xC7F2, 0xD5F8, 0xC267, 0xD5F9, 0xC7F3, 0xD5FA, 0xC268, 0xD5FB, 0xC269, 0xD5FC, 0xC26A, 0xD5FD, 0xC26B, 0xD5FE, 0xC26C, 0xD5FF, 0xC26D, 0xD600, 0xC7F4, 0xD601, 0xC7F5, 0xD602, 0xC26E, 0xD603, 0xC26F, 0xD604, 0xC7F6, 0xD605, 0xC270, 0xD606, 0xC271, 0xD607, 0xC272, 0xD608, 0xC7F7, 0xD609, 0xC273, 0xD60A, 0xC274, 0xD60B, 0xC275, 0xD60C, 0xC276, 0xD60D, 0xC277, 0xD60E, 0xC278, 0xD60F, 0xC279, 0xD610, 0xC7F8, 0xD611, 0xC7F9, 0xD612, 0xC27A, 0xD613, 0xC7FA, 0xD614, 0xC7FB, 0xD615, 0xC7FC, 0xD616, 0xC281, 0xD617, 0xC282, 0xD618, 0xC283, 0xD619, 0xC284, 0xD61A, 0xC285, 0xD61B, 0xC286, 0xD61C, 0xC7FD, 0xD61D, 0xC287, 0xD61E, 0xC288, 0xD61F, 0xC289, 0xD620, 0xC7FE, 0xD621, 0xC28A, 0xD622, 0xC28B, 0xD623, 0xC28C, 0xD624, 0xC8A1, 0xD625, 0xC28D, 0xD626, 0xC28E, 0xD627, 0xC28F, 0xD628, 0xC290, 0xD629, 0xC291, 0xD62A, 0xC292, 0xD62B, 0xC293, 0xD62C, 0xC294, 0xD62D, 0xC8A2, 0xD62E, 0xC295, 0xD62F, 0xC296, 0xD630, 0xC297, 0xD631, 0xC298, 0xD632, 0xC299, 0xD633, 0xC29A, 0xD634, 0xC29B, 0xD635, 0xC29C, 0xD636, 0xC29D, 0xD637, 0xC29E, 0xD638, 0xC8A3, 0xD639, 0xC8A4, 0xD63A, 0xC29F, 0xD63B, 0xC2A0, 0xD63C, 0xC8A5, 0xD63D, 0xC341, 0xD63E, 0xC342, 0xD63F, 0xC343, 0xD640, 0xC8A6, 0xD641, 0xC344, 0xD642, 0xC345, 0xD643, 0xC346, 0xD644, 0xC347, 0xD645, 0xC8A7, 0xD646, 0xC348, 0xD647, 0xC349, 0xD648, 0xC8A8, 0xD649, 0xC8A9, 0xD64A, 0xC34A, 0xD64B, 0xC8AA, 0xD64C, 0xC34B, 0xD64D, 0xC8AB, 0xD64E, 0xC34C, 0xD64F, 0xC34D, 0xD650, 0xC34E, 0xD651, 0xC8AC, 0xD652, 0xC34F, 0xD653, 0xC350, 0xD654, 0xC8AD, 0xD655, 0xC8AE, 0xD656, 0xC351, 0xD657, 0xC352, 0xD658, 0xC8AF, 0xD659, 0xC353, 0xD65A, 0xC354, 0xD65B, 0xC355, 0xD65C, 0xC8B0, 0xD65D, 0xC356, 0xD65E, 0xC357, 0xD65F, 0xC358, 0xD660, 0xC359, 0xD661, 0xC35A, 0xD662, 0xC361, 0xD663, 0xC362, 0xD664, 0xC363, 0xD665, 0xC364, 0xD666, 0xC365, 0xD667, 0xC8B1, 0xD668, 0xC366, 0xD669, 0xC8B2, 0xD66A, 0xC367, 0xD66B, 0xC368, 0xD66C, 0xC369, 0xD66D, 0xC36A, 0xD66E, 0xC36B, 0xD66F, 0xC36C, 0xD670, 0xC8B3, 0xD671, 0xC8B4, 0xD672, 0xC36D, 0xD673, 0xC36E, 0xD674, 0xC8B5, 0xD675, 0xC36F, 0xD676, 0xC370, 0xD677, 0xC371, 0xD678, 0xC372, 0xD679, 0xC373, 0xD67A, 0xC374, 0xD67B, 0xC375, 0xD67C, 0xC376, 0xD67D, 0xC377, 0xD67E, 0xC378, 0xD67F, 0xC379, 0xD680, 0xC37A, 0xD681, 0xC381, 0xD682, 0xC382, 0xD683, 0xC8B6, 0xD684, 0xC383, 0xD685, 0xC8B7, 0xD686, 0xC384, 0xD687, 0xC385, 0xD688, 0xC386, 0xD689, 0xC387, 0xD68A, 0xC388, 0xD68B, 0xC389, 0xD68C, 0xC8B8, 0xD68D, 0xC8B9, 0xD68E, 0xC38A, 0xD68F, 0xC38B, 0xD690, 0xC8BA, 0xD691, 0xC38C, 0xD692, 0xC38D, 0xD693, 0xC38E, 0xD694, 0xC8BB, 0xD695, 0xC38F, 0xD696, 0xC390, 0xD697, 0xC391, 0xD698, 0xC392, 0xD699, 0xC393, 0xD69A, 0xC394, 0xD69B, 0xC395, 0xD69C, 0xC396, 0xD69D, 0xC8BC, 0xD69E, 0xC397, 0xD69F, 0xC8BD, 0xD6A0, 0xC398, 0xD6A1, 0xC8BE, 0xD6A2, 0xC399, 0xD6A3, 0xC39A, 0xD6A4, 0xC39B, 0xD6A5, 0xC39C, 0xD6A6, 0xC39D, 0xD6A7, 0xC39E, 0xD6A8, 0xC8BF, 0xD6A9, 0xC39F, 0xD6AA, 0xC3A0, 0xD6AB, 0xC441, 0xD6AC, 0xC8C0, 0xD6AD, 0xC442, 0xD6AE, 0xC443, 0xD6AF, 0xC444, 0xD6B0, 0xC8C1, 0xD6B1, 0xC445, 0xD6B2, 0xC446, 0xD6B3, 0xC447, 0xD6B4, 0xC448, 0xD6B5, 0xC449, 0xD6B6, 0xC44A, 0xD6B7, 0xC44B, 0xD6B8, 0xC44C, 0xD6B9, 0xC8C2, 0xD6BA, 0xC44D, 0xD6BB, 0xC8C3, 0xD6BC, 0xC44E, 0xD6BD, 0xC44F, 0xD6BE, 0xC450, 0xD6BF, 0xC451, 0xD6C0, 0xC452, 0xD6C1, 0xC453, 0xD6C2, 0xC454, 0xD6C3, 0xC455, 0xD6C4, 0xC8C4, 0xD6C5, 0xC8C5, 0xD6C6, 0xC456, 0xD6C7, 0xC457, 0xD6C8, 0xC8C6, 0xD6C9, 0xC458, 0xD6CA, 0xC459, 0xD6CB, 0xC45A, 0xD6CC, 0xC8C7, 0xD6CD, 0xC461, 0xD6CE, 0xC462, 0xD6CF, 0xC463, 0xD6D0, 0xC464, 0xD6D1, 0xC8C8, 0xD6D2, 0xC465, 0xD6D3, 0xC466, 0xD6D4, 0xC8C9, 0xD6D5, 0xC467, 0xD6D6, 0xC468, 0xD6D7, 0xC8CA, 0xD6D8, 0xC469, 0xD6D9, 0xC8CB, 0xD6DA, 0xC46A, 0xD6DB, 0xC46B, 0xD6DC, 0xC46C, 0xD6DD, 0xC46D, 0xD6DE, 0xC46E, 0xD6DF, 0xC46F, 0xD6E0, 0xC8CC, 0xD6E1, 0xC470, 0xD6E2, 0xC471, 0xD6E3, 0xC472, 0xD6E4, 0xC8CD, 0xD6E5, 0xC473, 0xD6E6, 0xC474, 0xD6E7, 0xC475, 0xD6E8, 0xC8CE, 0xD6E9, 0xC476, 0xD6EA, 0xC477, 0xD6EB, 0xC478, 0xD6EC, 0xC479, 0xD6ED, 0xC47A, 0xD6EE, 0xC481, 0xD6EF, 0xC482, 0xD6F0, 0xC8CF, 0xD6F1, 0xC483, 0xD6F2, 0xC484, 0xD6F3, 0xC485, 0xD6F4, 0xC486, 0xD6F5, 0xC8D0, 0xD6F6, 0xC487, 0xD6F7, 0xC488, 0xD6F8, 0xC489, 0xD6F9, 0xC48A, 0xD6FA, 0xC48B, 0xD6FB, 0xC48C, 0xD6FC, 0xC8D1, 0xD6FD, 0xC8D2, 0xD6FE, 0xC48D, 0xD6FF, 0xC48E, 0xD700, 0xC8D3, 0xD701, 0xC48F, 0xD702, 0xC490, 0xD703, 0xC491, 0xD704, 0xC8D4, 0xD705, 0xC492, 0xD706, 0xC493, 0xD707, 0xC494, 0xD708, 0xC495, 0xD709, 0xC496, 0xD70A, 0xC497, 0xD70B, 0xC498, 0xD70C, 0xC499, 0xD70D, 0xC49A, 0xD70E, 0xC49B, 0xD70F, 0xC49C, 0xD710, 0xC49D, 0xD711, 0xC8D5, 0xD712, 0xC49E, 0xD713, 0xC49F, 0xD714, 0xC4A0, 0xD715, 0xC541, 0xD716, 0xC542, 0xD717, 0xC543, 0xD718, 0xC8D6, 0xD719, 0xC8D7, 0xD71A, 0xC544, 0xD71B, 0xC545, 0xD71C, 0xC8D8, 0xD71D, 0xC546, 0xD71E, 0xC547, 0xD71F, 0xC548, 0xD720, 0xC8D9, 0xD721, 0xC549, 0xD722, 0xC54A, 0xD723, 0xC54B, 0xD724, 0xC54C, 0xD725, 0xC54D, 0xD726, 0xC54E, 0xD727, 0xC54F, 0xD728, 0xC8DA, 0xD729, 0xC8DB, 0xD72A, 0xC550, 0xD72B, 0xC8DC, 0xD72C, 0xC551, 0xD72D, 0xC8DD, 0xD72E, 0xC552, 0xD72F, 0xC553, 0xD730, 0xC554, 0xD731, 0xC555, 0xD732, 0xC556, 0xD733, 0xC557, 0xD734, 0xC8DE, 0xD735, 0xC8DF, 0xD736, 0xC558, 0xD737, 0xC559, 0xD738, 0xC8E0, 0xD739, 0xC55A, 0xD73A, 0xC561, 0xD73B, 0xC562, 0xD73C, 0xC8E1, 0xD73D, 0xC563, 0xD73E, 0xC564, 0xD73F, 0xC565, 0xD740, 0xC566, 0xD741, 0xC567, 0xD742, 0xC568, 0xD743, 0xC569, 0xD744, 0xC8E2, 0xD745, 0xC56A, 0xD746, 0xC56B, 0xD747, 0xC8E3, 0xD748, 0xC56C, 0xD749, 0xC8E4, 0xD74A, 0xC56D, 0xD74B, 0xC56E, 0xD74C, 0xC56F, 0xD74D, 0xC570, 0xD74E, 0xC571, 0xD74F, 0xC572, 0xD750, 0xC8E5, 0xD751, 0xC8E6, 0xD752, 0xC573, 0xD753, 0xC574, 0xD754, 0xC8E7, 0xD755, 0xC575, 0xD756, 0xC8E8, 0xD757, 0xC8E9, 0xD758, 0xC8EA, 0xD759, 0xC8EB, 0xD75A, 0xC576, 0xD75B, 0xC577, 0xD75C, 0xC578, 0xD75D, 0xC579, 0xD75E, 0xC57A, 0xD75F, 0xC581, 0xD760, 0xC8EC, 0xD761, 0xC8ED, 0xD762, 0xC582, 0xD763, 0xC8EE, 0xD764, 0xC583, 0xD765, 0xC8EF, 0xD766, 0xC584, 0xD767, 0xC585, 0xD768, 0xC586, 0xD769, 0xC8F0, 0xD76A, 0xC587, 0xD76B, 0xC588, 0xD76C, 0xC8F1, 0xD76D, 0xC589, 0xD76E, 0xC58A, 0xD76F, 0xC58B, 0xD770, 0xC8F2, 0xD771, 0xC58C, 0xD772, 0xC58D, 0xD773, 0xC58E, 0xD774, 0xC8F3, 0xD775, 0xC58F, 0xD776, 0xC590, 0xD777, 0xC591, 0xD778, 0xC592, 0xD779, 0xC593, 0xD77A, 0xC594, 0xD77B, 0xC595, 0xD77C, 0xC8F4, 0xD77D, 0xC8F5, 0xD77E, 0xC596, 0xD77F, 0xC597, 0xD780, 0xC598, 0xD781, 0xC8F6, 0xD782, 0xC599, 0xD783, 0xC59A, 0xD784, 0xC59B, 0xD785, 0xC59C, 0xD786, 0xC59D, 0xD787, 0xC59E, 0xD788, 0xC8F7, 0xD789, 0xC8F8, 0xD78A, 0xC59F, 0xD78B, 0xC5A0, 0xD78C, 0xC8F9, 0xD78D, 0xC641, 0xD78E, 0xC642, 0xD78F, 0xC643, 0xD790, 0xC8FA, 0xD791, 0xC644, 0xD792, 0xC645, 0xD793, 0xC646, 0xD794, 0xC647, 0xD795, 0xC648, 0xD796, 0xC649, 0xD797, 0xC64A, 0xD798, 0xC8FB, 0xD799, 0xC8FC, 0xD79A, 0xC64B, 0xD79B, 0xC8FD, 0xD79C, 0xC64C, 0xD79D, 0xC8FE, 0xD79E, 0xC64D, 0xD79F, 0xC64E, 0xD7A0, 0xC64F, 0xD7A1, 0xC650, 0xD7A2, 0xC651, 0xD7A3, 0xC652, 0xF900, 0xCBD0, 0xF901, 0xCBD6, 0xF902, 0xCBE7, 0xF903, 0xCDCF, 0xF904, 0xCDE8, 0xF905, 0xCEAD, 0xF906, 0xCFFB, 0xF907, 0xD0A2, 0xF908, 0xD0B8, 0xF909, 0xD0D0, 0xF90A, 0xD0DD, 0xF90B, 0xD1D4, 0xF90C, 0xD1D5, 0xF90D, 0xD1D8, 0xF90E, 0xD1DB, 0xF90F, 0xD1DC, 0xF910, 0xD1DD, 0xF911, 0xD1DE, 0xF912, 0xD1DF, 0xF913, 0xD1E0, 0xF914, 0xD1E2, 0xF915, 0xD1E3, 0xF916, 0xD1E4, 0xF917, 0xD1E5, 0xF918, 0xD1E6, 0xF919, 0xD1E8, 0xF91A, 0xD1E9, 0xF91B, 0xD1EA, 0xF91C, 0xD1EB, 0xF91D, 0xD1ED, 0xF91E, 0xD1EF, 0xF91F, 0xD1F0, 0xF920, 0xD1F2, 0xF921, 0xD1F6, 0xF922, 0xD1FA, 0xF923, 0xD1FC, 0xF924, 0xD1FD, 0xF925, 0xD1FE, 0xF926, 0xD2A2, 0xF927, 0xD2A3, 0xF928, 0xD2A7, 0xF929, 0xD2A8, 0xF92A, 0xD2A9, 0xF92B, 0xD2AA, 0xF92C, 0xD2AB, 0xF92D, 0xD2AD, 0xF92E, 0xD2B2, 0xF92F, 0xD2BE, 0xF930, 0xD2C2, 0xF931, 0xD2C3, 0xF932, 0xD2C4, 0xF933, 0xD2C6, 0xF934, 0xD2C7, 0xF935, 0xD2C8, 0xF936, 0xD2C9, 0xF937, 0xD2CA, 0xF938, 0xD2CB, 0xF939, 0xD2CD, 0xF93A, 0xD2CE, 0xF93B, 0xD2CF, 0xF93C, 0xD2D0, 0xF93D, 0xD2D1, 0xF93E, 0xD2D2, 0xF93F, 0xD2D3, 0xF940, 0xD2D4, 0xF941, 0xD2D5, 0xF942, 0xD2D6, 0xF943, 0xD2D7, 0xF944, 0xD2D9, 0xF945, 0xD2DA, 0xF946, 0xD2DE, 0xF947, 0xD2DF, 0xF948, 0xD2E1, 0xF949, 0xD2E2, 0xF94A, 0xD2E4, 0xF94B, 0xD2E5, 0xF94C, 0xD2E6, 0xF94D, 0xD2E7, 0xF94E, 0xD2E8, 0xF94F, 0xD2E9, 0xF950, 0xD2EA, 0xF951, 0xD2EB, 0xF952, 0xD2F0, 0xF953, 0xD2F1, 0xF954, 0xD2F2, 0xF955, 0xD2F3, 0xF956, 0xD2F4, 0xF957, 0xD2F5, 0xF958, 0xD2F7, 0xF959, 0xD2F8, 0xF95A, 0xD4E6, 0xF95B, 0xD4FC, 0xF95C, 0xD5A5, 0xF95D, 0xD5AB, 0xF95E, 0xD5AE, 0xF95F, 0xD6B8, 0xF960, 0xD6CD, 0xF961, 0xD7CB, 0xF962, 0xD7E4, 0xF963, 0xDBC5, 0xF964, 0xDBE4, 0xF965, 0xDCA5, 0xF966, 0xDDA5, 0xF967, 0xDDD5, 0xF968, 0xDDF4, 0xF969, 0xDEFC, 0xF96A, 0xDEFE, 0xF96B, 0xDFB3, 0xF96C, 0xDFE1, 0xF96D, 0xDFE8, 0xF96E, 0xE0F1, 0xF96F, 0xE1AD, 0xF970, 0xE1ED, 0xF971, 0xE3F5, 0xF972, 0xE4A1, 0xF973, 0xE4A9, 0xF974, 0xE5AE, 0xF975, 0xE5B1, 0xF976, 0xE5B2, 0xF977, 0xE5B9, 0xF978, 0xE5BB, 0xF979, 0xE5BC, 0xF97A, 0xE5C4, 0xF97B, 0xE5CE, 0xF97C, 0xE5D0, 0xF97D, 0xE5D2, 0xF97E, 0xE5D6, 0xF97F, 0xE5FA, 0xF980, 0xE5FB, 0xF981, 0xE5FC, 0xF982, 0xE5FE, 0xF983, 0xE6A1, 0xF984, 0xE6A4, 0xF985, 0xE6A7, 0xF986, 0xE6AD, 0xF987, 0xE6AF, 0xF988, 0xE6B0, 0xF989, 0xE6B1, 0xF98A, 0xE6B3, 0xF98B, 0xE6B7, 0xF98C, 0xE6B8, 0xF98D, 0xE6BC, 0xF98E, 0xE6C4, 0xF98F, 0xE6C6, 0xF990, 0xE6C7, 0xF991, 0xE6CA, 0xF992, 0xE6D2, 0xF993, 0xE6D6, 0xF994, 0xE6D9, 0xF995, 0xE6DC, 0xF996, 0xE6DF, 0xF997, 0xE6E1, 0xF998, 0xE6E4, 0xF999, 0xE6E5, 0xF99A, 0xE6E6, 0xF99B, 0xE6E8, 0xF99C, 0xE6EA, 0xF99D, 0xE6EB, 0xF99E, 0xE6EC, 0xF99F, 0xE6EF, 0xF9A0, 0xE6F1, 0xF9A1, 0xE6F2, 0xF9A2, 0xE6F5, 0xF9A3, 0xE6F6, 0xF9A4, 0xE6F7, 0xF9A5, 0xE6F9, 0xF9A6, 0xE7A1, 0xF9A7, 0xE7A6, 0xF9A8, 0xE7A9, 0xF9A9, 0xE7AA, 0xF9AA, 0xE7AC, 0xF9AB, 0xE7AD, 0xF9AC, 0xE7B0, 0xF9AD, 0xE7BF, 0xF9AE, 0xE7C1, 0xF9AF, 0xE7C6, 0xF9B0, 0xE7C7, 0xF9B1, 0xE7CB, 0xF9B2, 0xE7CD, 0xF9B3, 0xE7CF, 0xF9B4, 0xE7D0, 0xF9B5, 0xE7D3, 0xF9B6, 0xE7DF, 0xF9B7, 0xE7E4, 0xF9B8, 0xE7E6, 0xF9B9, 0xE7F7, 0xF9BA, 0xE8E7, 0xF9BB, 0xE8E8, 0xF9BC, 0xE8F0, 0xF9BD, 0xE8F1, 0xF9BE, 0xE8F7, 0xF9BF, 0xE8F9, 0xF9C0, 0xE8FB, 0xF9C1, 0xE8FE, 0xF9C2, 0xE9A7, 0xF9C3, 0xE9AC, 0xF9C4, 0xE9CC, 0xF9C5, 0xE9F7, 0xF9C6, 0xEAC1, 0xF9C7, 0xEAE5, 0xF9C8, 0xEAF4, 0xF9C9, 0xEAF7, 0xF9CA, 0xEAFC, 0xF9CB, 0xEAFE, 0xF9CC, 0xEBA4, 0xF9CD, 0xEBA7, 0xF9CE, 0xEBA9, 0xF9CF, 0xEBAA, 0xF9D0, 0xEBBA, 0xF9D1, 0xEBBB, 0xF9D2, 0xEBBD, 0xF9D3, 0xEBC1, 0xF9D4, 0xEBC2, 0xF9D5, 0xEBC6, 0xF9D6, 0xEBC7, 0xF9D7, 0xEBCC, 0xF9D8, 0xEBCF, 0xF9D9, 0xEBD0, 0xF9DA, 0xEBD1, 0xF9DB, 0xEBD2, 0xF9DC, 0xEBD8, 0xF9DD, 0xECA6, 0xF9DE, 0xECA7, 0xF9DF, 0xECAA, 0xF9E0, 0xECAF, 0xF9E1, 0xECB0, 0xF9E2, 0xECB1, 0xF9E3, 0xECB2, 0xF9E4, 0xECB5, 0xF9E5, 0xECB8, 0xF9E6, 0xECBA, 0xF9E7, 0xECC0, 0xF9E8, 0xECC1, 0xF9E9, 0xECC5, 0xF9EA, 0xECC6, 0xF9EB, 0xECC9, 0xF9EC, 0xECCA, 0xF9ED, 0xECD5, 0xF9EE, 0xECDD, 0xF9EF, 0xECDE, 0xF9F0, 0xECE1, 0xF9F1, 0xECE4, 0xF9F2, 0xECE7, 0xF9F3, 0xECE8, 0xF9F4, 0xECF7, 0xF9F5, 0xECF8, 0xF9F6, 0xECFA, 0xF9F7, 0xEDA1, 0xF9F8, 0xEDA2, 0xF9F9, 0xEDA3, 0xF9FA, 0xEDEE, 0xF9FB, 0xEEDB, 0xF9FC, 0xF2BD, 0xF9FD, 0xF2FA, 0xF9FE, 0xF3B1, 0xF9FF, 0xF4A7, 0xFA00, 0xF4EE, 0xFA01, 0xF6F4, 0xFA02, 0xF6F6, 0xFA03, 0xF7B8, 0xFA04, 0xF7C8, 0xFA05, 0xF7D3, 0xFA06, 0xF8DB, 0xFA07, 0xF8F0, 0xFA08, 0xFAA1, 0xFA09, 0xFAA2, 0xFA0A, 0xFAE6, 0xFA0B, 0xFCA9, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA3A4, 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA1AC, 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, 0xFF5D, 0xA3FD, 0xFF5E, 0xA2A6, 0xFFE0, 0xA1CB, 0xFFE1, 0xA1CC, 0xFFE2, 0xA1FE, 0xFFE3, 0xA3FE, 0xFFE5, 0xA1CD, 0xFFE6, 0xA3DC, 0, 0 }; static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ 0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E, 0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25, 0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32, 0x8159, 0xAC33, 0x815A, 0xAC34, 0x8161, 0xAC35, 0x8162, 0xAC36, 0x8163, 0xAC37, 0x8164, 0xAC3A, 0x8165, 0xAC3B, 0x8166, 0xAC3D, 0x8167, 0xAC3E, 0x8168, 0xAC3F, 0x8169, 0xAC41, 0x816A, 0xAC42, 0x816B, 0xAC43, 0x816C, 0xAC44, 0x816D, 0xAC45, 0x816E, 0xAC46, 0x816F, 0xAC47, 0x8170, 0xAC48, 0x8171, 0xAC49, 0x8172, 0xAC4A, 0x8173, 0xAC4C, 0x8174, 0xAC4E, 0x8175, 0xAC4F, 0x8176, 0xAC50, 0x8177, 0xAC51, 0x8178, 0xAC52, 0x8179, 0xAC53, 0x817A, 0xAC55, 0x8181, 0xAC56, 0x8182, 0xAC57, 0x8183, 0xAC59, 0x8184, 0xAC5A, 0x8185, 0xAC5B, 0x8186, 0xAC5D, 0x8187, 0xAC5E, 0x8188, 0xAC5F, 0x8189, 0xAC60, 0x818A, 0xAC61, 0x818B, 0xAC62, 0x818C, 0xAC63, 0x818D, 0xAC64, 0x818E, 0xAC65, 0x818F, 0xAC66, 0x8190, 0xAC67, 0x8191, 0xAC68, 0x8192, 0xAC69, 0x8193, 0xAC6A, 0x8194, 0xAC6B, 0x8195, 0xAC6C, 0x8196, 0xAC6D, 0x8197, 0xAC6E, 0x8198, 0xAC6F, 0x8199, 0xAC72, 0x819A, 0xAC73, 0x819B, 0xAC75, 0x819C, 0xAC76, 0x819D, 0xAC79, 0x819E, 0xAC7B, 0x819F, 0xAC7C, 0x81A0, 0xAC7D, 0x81A1, 0xAC7E, 0x81A2, 0xAC7F, 0x81A3, 0xAC82, 0x81A4, 0xAC87, 0x81A5, 0xAC88, 0x81A6, 0xAC8D, 0x81A7, 0xAC8E, 0x81A8, 0xAC8F, 0x81A9, 0xAC91, 0x81AA, 0xAC92, 0x81AB, 0xAC93, 0x81AC, 0xAC95, 0x81AD, 0xAC96, 0x81AE, 0xAC97, 0x81AF, 0xAC98, 0x81B0, 0xAC99, 0x81B1, 0xAC9A, 0x81B2, 0xAC9B, 0x81B3, 0xAC9E, 0x81B4, 0xACA2, 0x81B5, 0xACA3, 0x81B6, 0xACA4, 0x81B7, 0xACA5, 0x81B8, 0xACA6, 0x81B9, 0xACA7, 0x81BA, 0xACAB, 0x81BB, 0xACAD, 0x81BC, 0xACAE, 0x81BD, 0xACB1, 0x81BE, 0xACB2, 0x81BF, 0xACB3, 0x81C0, 0xACB4, 0x81C1, 0xACB5, 0x81C2, 0xACB6, 0x81C3, 0xACB7, 0x81C4, 0xACBA, 0x81C5, 0xACBE, 0x81C6, 0xACBF, 0x81C7, 0xACC0, 0x81C8, 0xACC2, 0x81C9, 0xACC3, 0x81CA, 0xACC5, 0x81CB, 0xACC6, 0x81CC, 0xACC7, 0x81CD, 0xACC9, 0x81CE, 0xACCA, 0x81CF, 0xACCB, 0x81D0, 0xACCD, 0x81D1, 0xACCE, 0x81D2, 0xACCF, 0x81D3, 0xACD0, 0x81D4, 0xACD1, 0x81D5, 0xACD2, 0x81D6, 0xACD3, 0x81D7, 0xACD4, 0x81D8, 0xACD6, 0x81D9, 0xACD8, 0x81DA, 0xACD9, 0x81DB, 0xACDA, 0x81DC, 0xACDB, 0x81DD, 0xACDC, 0x81DE, 0xACDD, 0x81DF, 0xACDE, 0x81E0, 0xACDF, 0x81E1, 0xACE2, 0x81E2, 0xACE3, 0x81E3, 0xACE5, 0x81E4, 0xACE6, 0x81E5, 0xACE9, 0x81E6, 0xACEB, 0x81E7, 0xACED, 0x81E8, 0xACEE, 0x81E9, 0xACF2, 0x81EA, 0xACF4, 0x81EB, 0xACF7, 0x81EC, 0xACF8, 0x81ED, 0xACF9, 0x81EE, 0xACFA, 0x81EF, 0xACFB, 0x81F0, 0xACFE, 0x81F1, 0xACFF, 0x81F2, 0xAD01, 0x81F3, 0xAD02, 0x81F4, 0xAD03, 0x81F5, 0xAD05, 0x81F6, 0xAD07, 0x81F7, 0xAD08, 0x81F8, 0xAD09, 0x81F9, 0xAD0A, 0x81FA, 0xAD0B, 0x81FB, 0xAD0E, 0x81FC, 0xAD10, 0x81FD, 0xAD12, 0x81FE, 0xAD13, 0x8241, 0xAD14, 0x8242, 0xAD15, 0x8243, 0xAD16, 0x8244, 0xAD17, 0x8245, 0xAD19, 0x8246, 0xAD1A, 0x8247, 0xAD1B, 0x8248, 0xAD1D, 0x8249, 0xAD1E, 0x824A, 0xAD1F, 0x824B, 0xAD21, 0x824C, 0xAD22, 0x824D, 0xAD23, 0x824E, 0xAD24, 0x824F, 0xAD25, 0x8250, 0xAD26, 0x8251, 0xAD27, 0x8252, 0xAD28, 0x8253, 0xAD2A, 0x8254, 0xAD2B, 0x8255, 0xAD2E, 0x8256, 0xAD2F, 0x8257, 0xAD30, 0x8258, 0xAD31, 0x8259, 0xAD32, 0x825A, 0xAD33, 0x8261, 0xAD36, 0x8262, 0xAD37, 0x8263, 0xAD39, 0x8264, 0xAD3A, 0x8265, 0xAD3B, 0x8266, 0xAD3D, 0x8267, 0xAD3E, 0x8268, 0xAD3F, 0x8269, 0xAD40, 0x826A, 0xAD41, 0x826B, 0xAD42, 0x826C, 0xAD43, 0x826D, 0xAD46, 0x826E, 0xAD48, 0x826F, 0xAD4A, 0x8270, 0xAD4B, 0x8271, 0xAD4C, 0x8272, 0xAD4D, 0x8273, 0xAD4E, 0x8274, 0xAD4F, 0x8275, 0xAD51, 0x8276, 0xAD52, 0x8277, 0xAD53, 0x8278, 0xAD55, 0x8279, 0xAD56, 0x827A, 0xAD57, 0x8281, 0xAD59, 0x8282, 0xAD5A, 0x8283, 0xAD5B, 0x8284, 0xAD5C, 0x8285, 0xAD5D, 0x8286, 0xAD5E, 0x8287, 0xAD5F, 0x8288, 0xAD60, 0x8289, 0xAD62, 0x828A, 0xAD64, 0x828B, 0xAD65, 0x828C, 0xAD66, 0x828D, 0xAD67, 0x828E, 0xAD68, 0x828F, 0xAD69, 0x8290, 0xAD6A, 0x8291, 0xAD6B, 0x8292, 0xAD6E, 0x8293, 0xAD6F, 0x8294, 0xAD71, 0x8295, 0xAD72, 0x8296, 0xAD77, 0x8297, 0xAD78, 0x8298, 0xAD79, 0x8299, 0xAD7A, 0x829A, 0xAD7E, 0x829B, 0xAD80, 0x829C, 0xAD83, 0x829D, 0xAD84, 0x829E, 0xAD85, 0x829F, 0xAD86, 0x82A0, 0xAD87, 0x82A1, 0xAD8A, 0x82A2, 0xAD8B, 0x82A3, 0xAD8D, 0x82A4, 0xAD8E, 0x82A5, 0xAD8F, 0x82A6, 0xAD91, 0x82A7, 0xAD92, 0x82A8, 0xAD93, 0x82A9, 0xAD94, 0x82AA, 0xAD95, 0x82AB, 0xAD96, 0x82AC, 0xAD97, 0x82AD, 0xAD98, 0x82AE, 0xAD99, 0x82AF, 0xAD9A, 0x82B0, 0xAD9B, 0x82B1, 0xAD9E, 0x82B2, 0xAD9F, 0x82B3, 0xADA0, 0x82B4, 0xADA1, 0x82B5, 0xADA2, 0x82B6, 0xADA3, 0x82B7, 0xADA5, 0x82B8, 0xADA6, 0x82B9, 0xADA7, 0x82BA, 0xADA8, 0x82BB, 0xADA9, 0x82BC, 0xADAA, 0x82BD, 0xADAB, 0x82BE, 0xADAC, 0x82BF, 0xADAD, 0x82C0, 0xADAE, 0x82C1, 0xADAF, 0x82C2, 0xADB0, 0x82C3, 0xADB1, 0x82C4, 0xADB2, 0x82C5, 0xADB3, 0x82C6, 0xADB4, 0x82C7, 0xADB5, 0x82C8, 0xADB6, 0x82C9, 0xADB8, 0x82CA, 0xADB9, 0x82CB, 0xADBA, 0x82CC, 0xADBB, 0x82CD, 0xADBC, 0x82CE, 0xADBD, 0x82CF, 0xADBE, 0x82D0, 0xADBF, 0x82D1, 0xADC2, 0x82D2, 0xADC3, 0x82D3, 0xADC5, 0x82D4, 0xADC6, 0x82D5, 0xADC7, 0x82D6, 0xADC9, 0x82D7, 0xADCA, 0x82D8, 0xADCB, 0x82D9, 0xADCC, 0x82DA, 0xADCD, 0x82DB, 0xADCE, 0x82DC, 0xADCF, 0x82DD, 0xADD2, 0x82DE, 0xADD4, 0x82DF, 0xADD5, 0x82E0, 0xADD6, 0x82E1, 0xADD7, 0x82E2, 0xADD8, 0x82E3, 0xADD9, 0x82E4, 0xADDA, 0x82E5, 0xADDB, 0x82E6, 0xADDD, 0x82E7, 0xADDE, 0x82E8, 0xADDF, 0x82E9, 0xADE1, 0x82EA, 0xADE2, 0x82EB, 0xADE3, 0x82EC, 0xADE5, 0x82ED, 0xADE6, 0x82EE, 0xADE7, 0x82EF, 0xADE8, 0x82F0, 0xADE9, 0x82F1, 0xADEA, 0x82F2, 0xADEB, 0x82F3, 0xADEC, 0x82F4, 0xADED, 0x82F5, 0xADEE, 0x82F6, 0xADEF, 0x82F7, 0xADF0, 0x82F8, 0xADF1, 0x82F9, 0xADF2, 0x82FA, 0xADF3, 0x82FB, 0xADF4, 0x82FC, 0xADF5, 0x82FD, 0xADF6, 0x82FE, 0xADF7, 0x8341, 0xADFA, 0x8342, 0xADFB, 0x8343, 0xADFD, 0x8344, 0xADFE, 0x8345, 0xAE02, 0x8346, 0xAE03, 0x8347, 0xAE04, 0x8348, 0xAE05, 0x8349, 0xAE06, 0x834A, 0xAE07, 0x834B, 0xAE0A, 0x834C, 0xAE0C, 0x834D, 0xAE0E, 0x834E, 0xAE0F, 0x834F, 0xAE10, 0x8350, 0xAE11, 0x8351, 0xAE12, 0x8352, 0xAE13, 0x8353, 0xAE15, 0x8354, 0xAE16, 0x8355, 0xAE17, 0x8356, 0xAE18, 0x8357, 0xAE19, 0x8358, 0xAE1A, 0x8359, 0xAE1B, 0x835A, 0xAE1C, 0x8361, 0xAE1D, 0x8362, 0xAE1E, 0x8363, 0xAE1F, 0x8364, 0xAE20, 0x8365, 0xAE21, 0x8366, 0xAE22, 0x8367, 0xAE23, 0x8368, 0xAE24, 0x8369, 0xAE25, 0x836A, 0xAE26, 0x836B, 0xAE27, 0x836C, 0xAE28, 0x836D, 0xAE29, 0x836E, 0xAE2A, 0x836F, 0xAE2B, 0x8370, 0xAE2C, 0x8371, 0xAE2D, 0x8372, 0xAE2E, 0x8373, 0xAE2F, 0x8374, 0xAE32, 0x8375, 0xAE33, 0x8376, 0xAE35, 0x8377, 0xAE36, 0x8378, 0xAE39, 0x8379, 0xAE3B, 0x837A, 0xAE3C, 0x8381, 0xAE3D, 0x8382, 0xAE3E, 0x8383, 0xAE3F, 0x8384, 0xAE42, 0x8385, 0xAE44, 0x8386, 0xAE47, 0x8387, 0xAE48, 0x8388, 0xAE49, 0x8389, 0xAE4B, 0x838A, 0xAE4F, 0x838B, 0xAE51, 0x838C, 0xAE52, 0x838D, 0xAE53, 0x838E, 0xAE55, 0x838F, 0xAE57, 0x8390, 0xAE58, 0x8391, 0xAE59, 0x8392, 0xAE5A, 0x8393, 0xAE5B, 0x8394, 0xAE5E, 0x8395, 0xAE62, 0x8396, 0xAE63, 0x8397, 0xAE64, 0x8398, 0xAE66, 0x8399, 0xAE67, 0x839A, 0xAE6A, 0x839B, 0xAE6B, 0x839C, 0xAE6D, 0x839D, 0xAE6E, 0x839E, 0xAE6F, 0x839F, 0xAE71, 0x83A0, 0xAE72, 0x83A1, 0xAE73, 0x83A2, 0xAE74, 0x83A3, 0xAE75, 0x83A4, 0xAE76, 0x83A5, 0xAE77, 0x83A6, 0xAE7A, 0x83A7, 0xAE7E, 0x83A8, 0xAE7F, 0x83A9, 0xAE80, 0x83AA, 0xAE81, 0x83AB, 0xAE82, 0x83AC, 0xAE83, 0x83AD, 0xAE86, 0x83AE, 0xAE87, 0x83AF, 0xAE88, 0x83B0, 0xAE89, 0x83B1, 0xAE8A, 0x83B2, 0xAE8B, 0x83B3, 0xAE8D, 0x83B4, 0xAE8E, 0x83B5, 0xAE8F, 0x83B6, 0xAE90, 0x83B7, 0xAE91, 0x83B8, 0xAE92, 0x83B9, 0xAE93, 0x83BA, 0xAE94, 0x83BB, 0xAE95, 0x83BC, 0xAE96, 0x83BD, 0xAE97, 0x83BE, 0xAE98, 0x83BF, 0xAE99, 0x83C0, 0xAE9A, 0x83C1, 0xAE9B, 0x83C2, 0xAE9C, 0x83C3, 0xAE9D, 0x83C4, 0xAE9E, 0x83C5, 0xAE9F, 0x83C6, 0xAEA0, 0x83C7, 0xAEA1, 0x83C8, 0xAEA2, 0x83C9, 0xAEA3, 0x83CA, 0xAEA4, 0x83CB, 0xAEA5, 0x83CC, 0xAEA6, 0x83CD, 0xAEA7, 0x83CE, 0xAEA8, 0x83CF, 0xAEA9, 0x83D0, 0xAEAA, 0x83D1, 0xAEAB, 0x83D2, 0xAEAC, 0x83D3, 0xAEAD, 0x83D4, 0xAEAE, 0x83D5, 0xAEAF, 0x83D6, 0xAEB0, 0x83D7, 0xAEB1, 0x83D8, 0xAEB2, 0x83D9, 0xAEB3, 0x83DA, 0xAEB4, 0x83DB, 0xAEB5, 0x83DC, 0xAEB6, 0x83DD, 0xAEB7, 0x83DE, 0xAEB8, 0x83DF, 0xAEB9, 0x83E0, 0xAEBA, 0x83E1, 0xAEBB, 0x83E2, 0xAEBF, 0x83E3, 0xAEC1, 0x83E4, 0xAEC2, 0x83E5, 0xAEC3, 0x83E6, 0xAEC5, 0x83E7, 0xAEC6, 0x83E8, 0xAEC7, 0x83E9, 0xAEC8, 0x83EA, 0xAEC9, 0x83EB, 0xAECA, 0x83EC, 0xAECB, 0x83ED, 0xAECE, 0x83EE, 0xAED2, 0x83EF, 0xAED3, 0x83F0, 0xAED4, 0x83F1, 0xAED5, 0x83F2, 0xAED6, 0x83F3, 0xAED7, 0x83F4, 0xAEDA, 0x83F5, 0xAEDB, 0x83F6, 0xAEDD, 0x83F7, 0xAEDE, 0x83F8, 0xAEDF, 0x83F9, 0xAEE0, 0x83FA, 0xAEE1, 0x83FB, 0xAEE2, 0x83FC, 0xAEE3, 0x83FD, 0xAEE4, 0x83FE, 0xAEE5, 0x8441, 0xAEE6, 0x8442, 0xAEE7, 0x8443, 0xAEE9, 0x8444, 0xAEEA, 0x8445, 0xAEEC, 0x8446, 0xAEEE, 0x8447, 0xAEEF, 0x8448, 0xAEF0, 0x8449, 0xAEF1, 0x844A, 0xAEF2, 0x844B, 0xAEF3, 0x844C, 0xAEF5, 0x844D, 0xAEF6, 0x844E, 0xAEF7, 0x844F, 0xAEF9, 0x8450, 0xAEFA, 0x8451, 0xAEFB, 0x8452, 0xAEFD, 0x8453, 0xAEFE, 0x8454, 0xAEFF, 0x8455, 0xAF00, 0x8456, 0xAF01, 0x8457, 0xAF02, 0x8458, 0xAF03, 0x8459, 0xAF04, 0x845A, 0xAF05, 0x8461, 0xAF06, 0x8462, 0xAF09, 0x8463, 0xAF0A, 0x8464, 0xAF0B, 0x8465, 0xAF0C, 0x8466, 0xAF0E, 0x8467, 0xAF0F, 0x8468, 0xAF11, 0x8469, 0xAF12, 0x846A, 0xAF13, 0x846B, 0xAF14, 0x846C, 0xAF15, 0x846D, 0xAF16, 0x846E, 0xAF17, 0x846F, 0xAF18, 0x8470, 0xAF19, 0x8471, 0xAF1A, 0x8472, 0xAF1B, 0x8473, 0xAF1C, 0x8474, 0xAF1D, 0x8475, 0xAF1E, 0x8476, 0xAF1F, 0x8477, 0xAF20, 0x8478, 0xAF21, 0x8479, 0xAF22, 0x847A, 0xAF23, 0x8481, 0xAF24, 0x8482, 0xAF25, 0x8483, 0xAF26, 0x8484, 0xAF27, 0x8485, 0xAF28, 0x8486, 0xAF29, 0x8487, 0xAF2A, 0x8488, 0xAF2B, 0x8489, 0xAF2E, 0x848A, 0xAF2F, 0x848B, 0xAF31, 0x848C, 0xAF33, 0x848D, 0xAF35, 0x848E, 0xAF36, 0x848F, 0xAF37, 0x8490, 0xAF38, 0x8491, 0xAF39, 0x8492, 0xAF3A, 0x8493, 0xAF3B, 0x8494, 0xAF3E, 0x8495, 0xAF40, 0x8496, 0xAF44, 0x8497, 0xAF45, 0x8498, 0xAF46, 0x8499, 0xAF47, 0x849A, 0xAF4A, 0x849B, 0xAF4B, 0x849C, 0xAF4C, 0x849D, 0xAF4D, 0x849E, 0xAF4E, 0x849F, 0xAF4F, 0x84A0, 0xAF51, 0x84A1, 0xAF52, 0x84A2, 0xAF53, 0x84A3, 0xAF54, 0x84A4, 0xAF55, 0x84A5, 0xAF56, 0x84A6, 0xAF57, 0x84A7, 0xAF58, 0x84A8, 0xAF59, 0x84A9, 0xAF5A, 0x84AA, 0xAF5B, 0x84AB, 0xAF5E, 0x84AC, 0xAF5F, 0x84AD, 0xAF60, 0x84AE, 0xAF61, 0x84AF, 0xAF62, 0x84B0, 0xAF63, 0x84B1, 0xAF66, 0x84B2, 0xAF67, 0x84B3, 0xAF68, 0x84B4, 0xAF69, 0x84B5, 0xAF6A, 0x84B6, 0xAF6B, 0x84B7, 0xAF6C, 0x84B8, 0xAF6D, 0x84B9, 0xAF6E, 0x84BA, 0xAF6F, 0x84BB, 0xAF70, 0x84BC, 0xAF71, 0x84BD, 0xAF72, 0x84BE, 0xAF73, 0x84BF, 0xAF74, 0x84C0, 0xAF75, 0x84C1, 0xAF76, 0x84C2, 0xAF77, 0x84C3, 0xAF78, 0x84C4, 0xAF7A, 0x84C5, 0xAF7B, 0x84C6, 0xAF7C, 0x84C7, 0xAF7D, 0x84C8, 0xAF7E, 0x84C9, 0xAF7F, 0x84CA, 0xAF81, 0x84CB, 0xAF82, 0x84CC, 0xAF83, 0x84CD, 0xAF85, 0x84CE, 0xAF86, 0x84CF, 0xAF87, 0x84D0, 0xAF89, 0x84D1, 0xAF8A, 0x84D2, 0xAF8B, 0x84D3, 0xAF8C, 0x84D4, 0xAF8D, 0x84D5, 0xAF8E, 0x84D6, 0xAF8F, 0x84D7, 0xAF92, 0x84D8, 0xAF93, 0x84D9, 0xAF94, 0x84DA, 0xAF96, 0x84DB, 0xAF97, 0x84DC, 0xAF98, 0x84DD, 0xAF99, 0x84DE, 0xAF9A, 0x84DF, 0xAF9B, 0x84E0, 0xAF9D, 0x84E1, 0xAF9E, 0x84E2, 0xAF9F, 0x84E3, 0xAFA0, 0x84E4, 0xAFA1, 0x84E5, 0xAFA2, 0x84E6, 0xAFA3, 0x84E7, 0xAFA4, 0x84E8, 0xAFA5, 0x84E9, 0xAFA6, 0x84EA, 0xAFA7, 0x84EB, 0xAFA8, 0x84EC, 0xAFA9, 0x84ED, 0xAFAA, 0x84EE, 0xAFAB, 0x84EF, 0xAFAC, 0x84F0, 0xAFAD, 0x84F1, 0xAFAE, 0x84F2, 0xAFAF, 0x84F3, 0xAFB0, 0x84F4, 0xAFB1, 0x84F5, 0xAFB2, 0x84F6, 0xAFB3, 0x84F7, 0xAFB4, 0x84F8, 0xAFB5, 0x84F9, 0xAFB6, 0x84FA, 0xAFB7, 0x84FB, 0xAFBA, 0x84FC, 0xAFBB, 0x84FD, 0xAFBD, 0x84FE, 0xAFBE, 0x8541, 0xAFBF, 0x8542, 0xAFC1, 0x8543, 0xAFC2, 0x8544, 0xAFC3, 0x8545, 0xAFC4, 0x8546, 0xAFC5, 0x8547, 0xAFC6, 0x8548, 0xAFCA, 0x8549, 0xAFCC, 0x854A, 0xAFCF, 0x854B, 0xAFD0, 0x854C, 0xAFD1, 0x854D, 0xAFD2, 0x854E, 0xAFD3, 0x854F, 0xAFD5, 0x8550, 0xAFD6, 0x8551, 0xAFD7, 0x8552, 0xAFD8, 0x8553, 0xAFD9, 0x8554, 0xAFDA, 0x8555, 0xAFDB, 0x8556, 0xAFDD, 0x8557, 0xAFDE, 0x8558, 0xAFDF, 0x8559, 0xAFE0, 0x855A, 0xAFE1, 0x8561, 0xAFE2, 0x8562, 0xAFE3, 0x8563, 0xAFE4, 0x8564, 0xAFE5, 0x8565, 0xAFE6, 0x8566, 0xAFE7, 0x8567, 0xAFEA, 0x8568, 0xAFEB, 0x8569, 0xAFEC, 0x856A, 0xAFED, 0x856B, 0xAFEE, 0x856C, 0xAFEF, 0x856D, 0xAFF2, 0x856E, 0xAFF3, 0x856F, 0xAFF5, 0x8570, 0xAFF6, 0x8571, 0xAFF7, 0x8572, 0xAFF9, 0x8573, 0xAFFA, 0x8574, 0xAFFB, 0x8575, 0xAFFC, 0x8576, 0xAFFD, 0x8577, 0xAFFE, 0x8578, 0xAFFF, 0x8579, 0xB002, 0x857A, 0xB003, 0x8581, 0xB005, 0x8582, 0xB006, 0x8583, 0xB007, 0x8584, 0xB008, 0x8585, 0xB009, 0x8586, 0xB00A, 0x8587, 0xB00B, 0x8588, 0xB00D, 0x8589, 0xB00E, 0x858A, 0xB00F, 0x858B, 0xB011, 0x858C, 0xB012, 0x858D, 0xB013, 0x858E, 0xB015, 0x858F, 0xB016, 0x8590, 0xB017, 0x8591, 0xB018, 0x8592, 0xB019, 0x8593, 0xB01A, 0x8594, 0xB01B, 0x8595, 0xB01E, 0x8596, 0xB01F, 0x8597, 0xB020, 0x8598, 0xB021, 0x8599, 0xB022, 0x859A, 0xB023, 0x859B, 0xB024, 0x859C, 0xB025, 0x859D, 0xB026, 0x859E, 0xB027, 0x859F, 0xB029, 0x85A0, 0xB02A, 0x85A1, 0xB02B, 0x85A2, 0xB02C, 0x85A3, 0xB02D, 0x85A4, 0xB02E, 0x85A5, 0xB02F, 0x85A6, 0xB030, 0x85A7, 0xB031, 0x85A8, 0xB032, 0x85A9, 0xB033, 0x85AA, 0xB034, 0x85AB, 0xB035, 0x85AC, 0xB036, 0x85AD, 0xB037, 0x85AE, 0xB038, 0x85AF, 0xB039, 0x85B0, 0xB03A, 0x85B1, 0xB03B, 0x85B2, 0xB03C, 0x85B3, 0xB03D, 0x85B4, 0xB03E, 0x85B5, 0xB03F, 0x85B6, 0xB040, 0x85B7, 0xB041, 0x85B8, 0xB042, 0x85B9, 0xB043, 0x85BA, 0xB046, 0x85BB, 0xB047, 0x85BC, 0xB049, 0x85BD, 0xB04B, 0x85BE, 0xB04D, 0x85BF, 0xB04F, 0x85C0, 0xB050, 0x85C1, 0xB051, 0x85C2, 0xB052, 0x85C3, 0xB056, 0x85C4, 0xB058, 0x85C5, 0xB05A, 0x85C6, 0xB05B, 0x85C7, 0xB05C, 0x85C8, 0xB05E, 0x85C9, 0xB05F, 0x85CA, 0xB060, 0x85CB, 0xB061, 0x85CC, 0xB062, 0x85CD, 0xB063, 0x85CE, 0xB064, 0x85CF, 0xB065, 0x85D0, 0xB066, 0x85D1, 0xB067, 0x85D2, 0xB068, 0x85D3, 0xB069, 0x85D4, 0xB06A, 0x85D5, 0xB06B, 0x85D6, 0xB06C, 0x85D7, 0xB06D, 0x85D8, 0xB06E, 0x85D9, 0xB06F, 0x85DA, 0xB070, 0x85DB, 0xB071, 0x85DC, 0xB072, 0x85DD, 0xB073, 0x85DE, 0xB074, 0x85DF, 0xB075, 0x85E0, 0xB076, 0x85E1, 0xB077, 0x85E2, 0xB078, 0x85E3, 0xB079, 0x85E4, 0xB07A, 0x85E5, 0xB07B, 0x85E6, 0xB07E, 0x85E7, 0xB07F, 0x85E8, 0xB081, 0x85E9, 0xB082, 0x85EA, 0xB083, 0x85EB, 0xB085, 0x85EC, 0xB086, 0x85ED, 0xB087, 0x85EE, 0xB088, 0x85EF, 0xB089, 0x85F0, 0xB08A, 0x85F1, 0xB08B, 0x85F2, 0xB08E, 0x85F3, 0xB090, 0x85F4, 0xB092, 0x85F5, 0xB093, 0x85F6, 0xB094, 0x85F7, 0xB095, 0x85F8, 0xB096, 0x85F9, 0xB097, 0x85FA, 0xB09B, 0x85FB, 0xB09D, 0x85FC, 0xB09E, 0x85FD, 0xB0A3, 0x85FE, 0xB0A4, 0x8641, 0xB0A5, 0x8642, 0xB0A6, 0x8643, 0xB0A7, 0x8644, 0xB0AA, 0x8645, 0xB0B0, 0x8646, 0xB0B2, 0x8647, 0xB0B6, 0x8648, 0xB0B7, 0x8649, 0xB0B9, 0x864A, 0xB0BA, 0x864B, 0xB0BB, 0x864C, 0xB0BD, 0x864D, 0xB0BE, 0x864E, 0xB0BF, 0x864F, 0xB0C0, 0x8650, 0xB0C1, 0x8651, 0xB0C2, 0x8652, 0xB0C3, 0x8653, 0xB0C6, 0x8654, 0xB0CA, 0x8655, 0xB0CB, 0x8656, 0xB0CC, 0x8657, 0xB0CD, 0x8658, 0xB0CE, 0x8659, 0xB0CF, 0x865A, 0xB0D2, 0x8661, 0xB0D3, 0x8662, 0xB0D5, 0x8663, 0xB0D6, 0x8664, 0xB0D7, 0x8665, 0xB0D9, 0x8666, 0xB0DA, 0x8667, 0xB0DB, 0x8668, 0xB0DC, 0x8669, 0xB0DD, 0x866A, 0xB0DE, 0x866B, 0xB0DF, 0x866C, 0xB0E1, 0x866D, 0xB0E2, 0x866E, 0xB0E3, 0x866F, 0xB0E4, 0x8670, 0xB0E6, 0x8671, 0xB0E7, 0x8672, 0xB0E8, 0x8673, 0xB0E9, 0x8674, 0xB0EA, 0x8675, 0xB0EB, 0x8676, 0xB0EC, 0x8677, 0xB0ED, 0x8678, 0xB0EE, 0x8679, 0xB0EF, 0x867A, 0xB0F0, 0x8681, 0xB0F1, 0x8682, 0xB0F2, 0x8683, 0xB0F3, 0x8684, 0xB0F4, 0x8685, 0xB0F5, 0x8686, 0xB0F6, 0x8687, 0xB0F7, 0x8688, 0xB0F8, 0x8689, 0xB0F9, 0x868A, 0xB0FA, 0x868B, 0xB0FB, 0x868C, 0xB0FC, 0x868D, 0xB0FD, 0x868E, 0xB0FE, 0x868F, 0xB0FF, 0x8690, 0xB100, 0x8691, 0xB101, 0x8692, 0xB102, 0x8693, 0xB103, 0x8694, 0xB104, 0x8695, 0xB105, 0x8696, 0xB106, 0x8697, 0xB107, 0x8698, 0xB10A, 0x8699, 0xB10D, 0x869A, 0xB10E, 0x869B, 0xB10F, 0x869C, 0xB111, 0x869D, 0xB114, 0x869E, 0xB115, 0x869F, 0xB116, 0x86A0, 0xB117, 0x86A1, 0xB11A, 0x86A2, 0xB11E, 0x86A3, 0xB11F, 0x86A4, 0xB120, 0x86A5, 0xB121, 0x86A6, 0xB122, 0x86A7, 0xB126, 0x86A8, 0xB127, 0x86A9, 0xB129, 0x86AA, 0xB12A, 0x86AB, 0xB12B, 0x86AC, 0xB12D, 0x86AD, 0xB12E, 0x86AE, 0xB12F, 0x86AF, 0xB130, 0x86B0, 0xB131, 0x86B1, 0xB132, 0x86B2, 0xB133, 0x86B3, 0xB136, 0x86B4, 0xB13A, 0x86B5, 0xB13B, 0x86B6, 0xB13C, 0x86B7, 0xB13D, 0x86B8, 0xB13E, 0x86B9, 0xB13F, 0x86BA, 0xB142, 0x86BB, 0xB143, 0x86BC, 0xB145, 0x86BD, 0xB146, 0x86BE, 0xB147, 0x86BF, 0xB149, 0x86C0, 0xB14A, 0x86C1, 0xB14B, 0x86C2, 0xB14C, 0x86C3, 0xB14D, 0x86C4, 0xB14E, 0x86C5, 0xB14F, 0x86C6, 0xB152, 0x86C7, 0xB153, 0x86C8, 0xB156, 0x86C9, 0xB157, 0x86CA, 0xB159, 0x86CB, 0xB15A, 0x86CC, 0xB15B, 0x86CD, 0xB15D, 0x86CE, 0xB15E, 0x86CF, 0xB15F, 0x86D0, 0xB161, 0x86D1, 0xB162, 0x86D2, 0xB163, 0x86D3, 0xB164, 0x86D4, 0xB165, 0x86D5, 0xB166, 0x86D6, 0xB167, 0x86D7, 0xB168, 0x86D8, 0xB169, 0x86D9, 0xB16A, 0x86DA, 0xB16B, 0x86DB, 0xB16C, 0x86DC, 0xB16D, 0x86DD, 0xB16E, 0x86DE, 0xB16F, 0x86DF, 0xB170, 0x86E0, 0xB171, 0x86E1, 0xB172, 0x86E2, 0xB173, 0x86E3, 0xB174, 0x86E4, 0xB175, 0x86E5, 0xB176, 0x86E6, 0xB177, 0x86E7, 0xB17A, 0x86E8, 0xB17B, 0x86E9, 0xB17D, 0x86EA, 0xB17E, 0x86EB, 0xB17F, 0x86EC, 0xB181, 0x86ED, 0xB183, 0x86EE, 0xB184, 0x86EF, 0xB185, 0x86F0, 0xB186, 0x86F1, 0xB187, 0x86F2, 0xB18A, 0x86F3, 0xB18C, 0x86F4, 0xB18E, 0x86F5, 0xB18F, 0x86F6, 0xB190, 0x86F7, 0xB191, 0x86F8, 0xB195, 0x86F9, 0xB196, 0x86FA, 0xB197, 0x86FB, 0xB199, 0x86FC, 0xB19A, 0x86FD, 0xB19B, 0x86FE, 0xB19D, 0x8741, 0xB19E, 0x8742, 0xB19F, 0x8743, 0xB1A0, 0x8744, 0xB1A1, 0x8745, 0xB1A2, 0x8746, 0xB1A3, 0x8747, 0xB1A4, 0x8748, 0xB1A5, 0x8749, 0xB1A6, 0x874A, 0xB1A7, 0x874B, 0xB1A9, 0x874C, 0xB1AA, 0x874D, 0xB1AB, 0x874E, 0xB1AC, 0x874F, 0xB1AD, 0x8750, 0xB1AE, 0x8751, 0xB1AF, 0x8752, 0xB1B0, 0x8753, 0xB1B1, 0x8754, 0xB1B2, 0x8755, 0xB1B3, 0x8756, 0xB1B4, 0x8757, 0xB1B5, 0x8758, 0xB1B6, 0x8759, 0xB1B7, 0x875A, 0xB1B8, 0x8761, 0xB1B9, 0x8762, 0xB1BA, 0x8763, 0xB1BB, 0x8764, 0xB1BC, 0x8765, 0xB1BD, 0x8766, 0xB1BE, 0x8767, 0xB1BF, 0x8768, 0xB1C0, 0x8769, 0xB1C1, 0x876A, 0xB1C2, 0x876B, 0xB1C3, 0x876C, 0xB1C4, 0x876D, 0xB1C5, 0x876E, 0xB1C6, 0x876F, 0xB1C7, 0x8770, 0xB1C8, 0x8771, 0xB1C9, 0x8772, 0xB1CA, 0x8773, 0xB1CB, 0x8774, 0xB1CD, 0x8775, 0xB1CE, 0x8776, 0xB1CF, 0x8777, 0xB1D1, 0x8778, 0xB1D2, 0x8779, 0xB1D3, 0x877A, 0xB1D5, 0x8781, 0xB1D6, 0x8782, 0xB1D7, 0x8783, 0xB1D8, 0x8784, 0xB1D9, 0x8785, 0xB1DA, 0x8786, 0xB1DB, 0x8787, 0xB1DE, 0x8788, 0xB1E0, 0x8789, 0xB1E1, 0x878A, 0xB1E2, 0x878B, 0xB1E3, 0x878C, 0xB1E4, 0x878D, 0xB1E5, 0x878E, 0xB1E6, 0x878F, 0xB1E7, 0x8790, 0xB1EA, 0x8791, 0xB1EB, 0x8792, 0xB1ED, 0x8793, 0xB1EE, 0x8794, 0xB1EF, 0x8795, 0xB1F1, 0x8796, 0xB1F2, 0x8797, 0xB1F3, 0x8798, 0xB1F4, 0x8799, 0xB1F5, 0x879A, 0xB1F6, 0x879B, 0xB1F7, 0x879C, 0xB1F8, 0x879D, 0xB1FA, 0x879E, 0xB1FC, 0x879F, 0xB1FE, 0x87A0, 0xB1FF, 0x87A1, 0xB200, 0x87A2, 0xB201, 0x87A3, 0xB202, 0x87A4, 0xB203, 0x87A5, 0xB206, 0x87A6, 0xB207, 0x87A7, 0xB209, 0x87A8, 0xB20A, 0x87A9, 0xB20D, 0x87AA, 0xB20E, 0x87AB, 0xB20F, 0x87AC, 0xB210, 0x87AD, 0xB211, 0x87AE, 0xB212, 0x87AF, 0xB213, 0x87B0, 0xB216, 0x87B1, 0xB218, 0x87B2, 0xB21A, 0x87B3, 0xB21B, 0x87B4, 0xB21C, 0x87B5, 0xB21D, 0x87B6, 0xB21E, 0x87B7, 0xB21F, 0x87B8, 0xB221, 0x87B9, 0xB222, 0x87BA, 0xB223, 0x87BB, 0xB224, 0x87BC, 0xB225, 0x87BD, 0xB226, 0x87BE, 0xB227, 0x87BF, 0xB228, 0x87C0, 0xB229, 0x87C1, 0xB22A, 0x87C2, 0xB22B, 0x87C3, 0xB22C, 0x87C4, 0xB22D, 0x87C5, 0xB22E, 0x87C6, 0xB22F, 0x87C7, 0xB230, 0x87C8, 0xB231, 0x87C9, 0xB232, 0x87CA, 0xB233, 0x87CB, 0xB235, 0x87CC, 0xB236, 0x87CD, 0xB237, 0x87CE, 0xB238, 0x87CF, 0xB239, 0x87D0, 0xB23A, 0x87D1, 0xB23B, 0x87D2, 0xB23D, 0x87D3, 0xB23E, 0x87D4, 0xB23F, 0x87D5, 0xB240, 0x87D6, 0xB241, 0x87D7, 0xB242, 0x87D8, 0xB243, 0x87D9, 0xB244, 0x87DA, 0xB245, 0x87DB, 0xB246, 0x87DC, 0xB247, 0x87DD, 0xB248, 0x87DE, 0xB249, 0x87DF, 0xB24A, 0x87E0, 0xB24B, 0x87E1, 0xB24C, 0x87E2, 0xB24D, 0x87E3, 0xB24E, 0x87E4, 0xB24F, 0x87E5, 0xB250, 0x87E6, 0xB251, 0x87E7, 0xB252, 0x87E8, 0xB253, 0x87E9, 0xB254, 0x87EA, 0xB255, 0x87EB, 0xB256, 0x87EC, 0xB257, 0x87ED, 0xB259, 0x87EE, 0xB25A, 0x87EF, 0xB25B, 0x87F0, 0xB25D, 0x87F1, 0xB25E, 0x87F2, 0xB25F, 0x87F3, 0xB261, 0x87F4, 0xB262, 0x87F5, 0xB263, 0x87F6, 0xB264, 0x87F7, 0xB265, 0x87F8, 0xB266, 0x87F9, 0xB267, 0x87FA, 0xB26A, 0x87FB, 0xB26B, 0x87FC, 0xB26C, 0x87FD, 0xB26D, 0x87FE, 0xB26E, 0x8841, 0xB26F, 0x8842, 0xB270, 0x8843, 0xB271, 0x8844, 0xB272, 0x8845, 0xB273, 0x8846, 0xB276, 0x8847, 0xB277, 0x8848, 0xB278, 0x8849, 0xB279, 0x884A, 0xB27A, 0x884B, 0xB27B, 0x884C, 0xB27D, 0x884D, 0xB27E, 0x884E, 0xB27F, 0x884F, 0xB280, 0x8850, 0xB281, 0x8851, 0xB282, 0x8852, 0xB283, 0x8853, 0xB286, 0x8854, 0xB287, 0x8855, 0xB288, 0x8856, 0xB28A, 0x8857, 0xB28B, 0x8858, 0xB28C, 0x8859, 0xB28D, 0x885A, 0xB28E, 0x8861, 0xB28F, 0x8862, 0xB292, 0x8863, 0xB293, 0x8864, 0xB295, 0x8865, 0xB296, 0x8866, 0xB297, 0x8867, 0xB29B, 0x8868, 0xB29C, 0x8869, 0xB29D, 0x886A, 0xB29E, 0x886B, 0xB29F, 0x886C, 0xB2A2, 0x886D, 0xB2A4, 0x886E, 0xB2A7, 0x886F, 0xB2A8, 0x8870, 0xB2A9, 0x8871, 0xB2AB, 0x8872, 0xB2AD, 0x8873, 0xB2AE, 0x8874, 0xB2AF, 0x8875, 0xB2B1, 0x8876, 0xB2B2, 0x8877, 0xB2B3, 0x8878, 0xB2B5, 0x8879, 0xB2B6, 0x887A, 0xB2B7, 0x8881, 0xB2B8, 0x8882, 0xB2B9, 0x8883, 0xB2BA, 0x8884, 0xB2BB, 0x8885, 0xB2BC, 0x8886, 0xB2BD, 0x8887, 0xB2BE, 0x8888, 0xB2BF, 0x8889, 0xB2C0, 0x888A, 0xB2C1, 0x888B, 0xB2C2, 0x888C, 0xB2C3, 0x888D, 0xB2C4, 0x888E, 0xB2C5, 0x888F, 0xB2C6, 0x8890, 0xB2C7, 0x8891, 0xB2CA, 0x8892, 0xB2CB, 0x8893, 0xB2CD, 0x8894, 0xB2CE, 0x8895, 0xB2CF, 0x8896, 0xB2D1, 0x8897, 0xB2D3, 0x8898, 0xB2D4, 0x8899, 0xB2D5, 0x889A, 0xB2D6, 0x889B, 0xB2D7, 0x889C, 0xB2DA, 0x889D, 0xB2DC, 0x889E, 0xB2DE, 0x889F, 0xB2DF, 0x88A0, 0xB2E0, 0x88A1, 0xB2E1, 0x88A2, 0xB2E3, 0x88A3, 0xB2E7, 0x88A4, 0xB2E9, 0x88A5, 0xB2EA, 0x88A6, 0xB2F0, 0x88A7, 0xB2F1, 0x88A8, 0xB2F2, 0x88A9, 0xB2F6, 0x88AA, 0xB2FC, 0x88AB, 0xB2FD, 0x88AC, 0xB2FE, 0x88AD, 0xB302, 0x88AE, 0xB303, 0x88AF, 0xB305, 0x88B0, 0xB306, 0x88B1, 0xB307, 0x88B2, 0xB309, 0x88B3, 0xB30A, 0x88B4, 0xB30B, 0x88B5, 0xB30C, 0x88B6, 0xB30D, 0x88B7, 0xB30E, 0x88B8, 0xB30F, 0x88B9, 0xB312, 0x88BA, 0xB316, 0x88BB, 0xB317, 0x88BC, 0xB318, 0x88BD, 0xB319, 0x88BE, 0xB31A, 0x88BF, 0xB31B, 0x88C0, 0xB31D, 0x88C1, 0xB31E, 0x88C2, 0xB31F, 0x88C3, 0xB320, 0x88C4, 0xB321, 0x88C5, 0xB322, 0x88C6, 0xB323, 0x88C7, 0xB324, 0x88C8, 0xB325, 0x88C9, 0xB326, 0x88CA, 0xB327, 0x88CB, 0xB328, 0x88CC, 0xB329, 0x88CD, 0xB32A, 0x88CE, 0xB32B, 0x88CF, 0xB32C, 0x88D0, 0xB32D, 0x88D1, 0xB32E, 0x88D2, 0xB32F, 0x88D3, 0xB330, 0x88D4, 0xB331, 0x88D5, 0xB332, 0x88D6, 0xB333, 0x88D7, 0xB334, 0x88D8, 0xB335, 0x88D9, 0xB336, 0x88DA, 0xB337, 0x88DB, 0xB338, 0x88DC, 0xB339, 0x88DD, 0xB33A, 0x88DE, 0xB33B, 0x88DF, 0xB33C, 0x88E0, 0xB33D, 0x88E1, 0xB33E, 0x88E2, 0xB33F, 0x88E3, 0xB340, 0x88E4, 0xB341, 0x88E5, 0xB342, 0x88E6, 0xB343, 0x88E7, 0xB344, 0x88E8, 0xB345, 0x88E9, 0xB346, 0x88EA, 0xB347, 0x88EB, 0xB348, 0x88EC, 0xB349, 0x88ED, 0xB34A, 0x88EE, 0xB34B, 0x88EF, 0xB34C, 0x88F0, 0xB34D, 0x88F1, 0xB34E, 0x88F2, 0xB34F, 0x88F3, 0xB350, 0x88F4, 0xB351, 0x88F5, 0xB352, 0x88F6, 0xB353, 0x88F7, 0xB357, 0x88F8, 0xB359, 0x88F9, 0xB35A, 0x88FA, 0xB35D, 0x88FB, 0xB360, 0x88FC, 0xB361, 0x88FD, 0xB362, 0x88FE, 0xB363, 0x8941, 0xB366, 0x8942, 0xB368, 0x8943, 0xB36A, 0x8944, 0xB36C, 0x8945, 0xB36D, 0x8946, 0xB36F, 0x8947, 0xB372, 0x8948, 0xB373, 0x8949, 0xB375, 0x894A, 0xB376, 0x894B, 0xB377, 0x894C, 0xB379, 0x894D, 0xB37A, 0x894E, 0xB37B, 0x894F, 0xB37C, 0x8950, 0xB37D, 0x8951, 0xB37E, 0x8952, 0xB37F, 0x8953, 0xB382, 0x8954, 0xB386, 0x8955, 0xB387, 0x8956, 0xB388, 0x8957, 0xB389, 0x8958, 0xB38A, 0x8959, 0xB38B, 0x895A, 0xB38D, 0x8961, 0xB38E, 0x8962, 0xB38F, 0x8963, 0xB391, 0x8964, 0xB392, 0x8965, 0xB393, 0x8966, 0xB395, 0x8967, 0xB396, 0x8968, 0xB397, 0x8969, 0xB398, 0x896A, 0xB399, 0x896B, 0xB39A, 0x896C, 0xB39B, 0x896D, 0xB39C, 0x896E, 0xB39D, 0x896F, 0xB39E, 0x8970, 0xB39F, 0x8971, 0xB3A2, 0x8972, 0xB3A3, 0x8973, 0xB3A4, 0x8974, 0xB3A5, 0x8975, 0xB3A6, 0x8976, 0xB3A7, 0x8977, 0xB3A9, 0x8978, 0xB3AA, 0x8979, 0xB3AB, 0x897A, 0xB3AD, 0x8981, 0xB3AE, 0x8982, 0xB3AF, 0x8983, 0xB3B0, 0x8984, 0xB3B1, 0x8985, 0xB3B2, 0x8986, 0xB3B3, 0x8987, 0xB3B4, 0x8988, 0xB3B5, 0x8989, 0xB3B6, 0x898A, 0xB3B7, 0x898B, 0xB3B8, 0x898C, 0xB3B9, 0x898D, 0xB3BA, 0x898E, 0xB3BB, 0x898F, 0xB3BC, 0x8990, 0xB3BD, 0x8991, 0xB3BE, 0x8992, 0xB3BF, 0x8993, 0xB3C0, 0x8994, 0xB3C1, 0x8995, 0xB3C2, 0x8996, 0xB3C3, 0x8997, 0xB3C6, 0x8998, 0xB3C7, 0x8999, 0xB3C9, 0x899A, 0xB3CA, 0x899B, 0xB3CD, 0x899C, 0xB3CF, 0x899D, 0xB3D1, 0x899E, 0xB3D2, 0x899F, 0xB3D3, 0x89A0, 0xB3D6, 0x89A1, 0xB3D8, 0x89A2, 0xB3DA, 0x89A3, 0xB3DC, 0x89A4, 0xB3DE, 0x89A5, 0xB3DF, 0x89A6, 0xB3E1, 0x89A7, 0xB3E2, 0x89A8, 0xB3E3, 0x89A9, 0xB3E5, 0x89AA, 0xB3E6, 0x89AB, 0xB3E7, 0x89AC, 0xB3E9, 0x89AD, 0xB3EA, 0x89AE, 0xB3EB, 0x89AF, 0xB3EC, 0x89B0, 0xB3ED, 0x89B1, 0xB3EE, 0x89B2, 0xB3EF, 0x89B3, 0xB3F0, 0x89B4, 0xB3F1, 0x89B5, 0xB3F2, 0x89B6, 0xB3F3, 0x89B7, 0xB3F4, 0x89B8, 0xB3F5, 0x89B9, 0xB3F6, 0x89BA, 0xB3F7, 0x89BB, 0xB3F8, 0x89BC, 0xB3F9, 0x89BD, 0xB3FA, 0x89BE, 0xB3FB, 0x89BF, 0xB3FD, 0x89C0, 0xB3FE, 0x89C1, 0xB3FF, 0x89C2, 0xB400, 0x89C3, 0xB401, 0x89C4, 0xB402, 0x89C5, 0xB403, 0x89C6, 0xB404, 0x89C7, 0xB405, 0x89C8, 0xB406, 0x89C9, 0xB407, 0x89CA, 0xB408, 0x89CB, 0xB409, 0x89CC, 0xB40A, 0x89CD, 0xB40B, 0x89CE, 0xB40C, 0x89CF, 0xB40D, 0x89D0, 0xB40E, 0x89D1, 0xB40F, 0x89D2, 0xB411, 0x89D3, 0xB412, 0x89D4, 0xB413, 0x89D5, 0xB414, 0x89D6, 0xB415, 0x89D7, 0xB416, 0x89D8, 0xB417, 0x89D9, 0xB419, 0x89DA, 0xB41A, 0x89DB, 0xB41B, 0x89DC, 0xB41D, 0x89DD, 0xB41E, 0x89DE, 0xB41F, 0x89DF, 0xB421, 0x89E0, 0xB422, 0x89E1, 0xB423, 0x89E2, 0xB424, 0x89E3, 0xB425, 0x89E4, 0xB426, 0x89E5, 0xB427, 0x89E6, 0xB42A, 0x89E7, 0xB42C, 0x89E8, 0xB42D, 0x89E9, 0xB42E, 0x89EA, 0xB42F, 0x89EB, 0xB430, 0x89EC, 0xB431, 0x89ED, 0xB432, 0x89EE, 0xB433, 0x89EF, 0xB435, 0x89F0, 0xB436, 0x89F1, 0xB437, 0x89F2, 0xB438, 0x89F3, 0xB439, 0x89F4, 0xB43A, 0x89F5, 0xB43B, 0x89F6, 0xB43C, 0x89F7, 0xB43D, 0x89F8, 0xB43E, 0x89F9, 0xB43F, 0x89FA, 0xB440, 0x89FB, 0xB441, 0x89FC, 0xB442, 0x89FD, 0xB443, 0x89FE, 0xB444, 0x8A41, 0xB445, 0x8A42, 0xB446, 0x8A43, 0xB447, 0x8A44, 0xB448, 0x8A45, 0xB449, 0x8A46, 0xB44A, 0x8A47, 0xB44B, 0x8A48, 0xB44C, 0x8A49, 0xB44D, 0x8A4A, 0xB44E, 0x8A4B, 0xB44F, 0x8A4C, 0xB452, 0x8A4D, 0xB453, 0x8A4E, 0xB455, 0x8A4F, 0xB456, 0x8A50, 0xB457, 0x8A51, 0xB459, 0x8A52, 0xB45A, 0x8A53, 0xB45B, 0x8A54, 0xB45C, 0x8A55, 0xB45D, 0x8A56, 0xB45E, 0x8A57, 0xB45F, 0x8A58, 0xB462, 0x8A59, 0xB464, 0x8A5A, 0xB466, 0x8A61, 0xB467, 0x8A62, 0xB468, 0x8A63, 0xB469, 0x8A64, 0xB46A, 0x8A65, 0xB46B, 0x8A66, 0xB46D, 0x8A67, 0xB46E, 0x8A68, 0xB46F, 0x8A69, 0xB470, 0x8A6A, 0xB471, 0x8A6B, 0xB472, 0x8A6C, 0xB473, 0x8A6D, 0xB474, 0x8A6E, 0xB475, 0x8A6F, 0xB476, 0x8A70, 0xB477, 0x8A71, 0xB478, 0x8A72, 0xB479, 0x8A73, 0xB47A, 0x8A74, 0xB47B, 0x8A75, 0xB47C, 0x8A76, 0xB47D, 0x8A77, 0xB47E, 0x8A78, 0xB47F, 0x8A79, 0xB481, 0x8A7A, 0xB482, 0x8A81, 0xB483, 0x8A82, 0xB484, 0x8A83, 0xB485, 0x8A84, 0xB486, 0x8A85, 0xB487, 0x8A86, 0xB489, 0x8A87, 0xB48A, 0x8A88, 0xB48B, 0x8A89, 0xB48C, 0x8A8A, 0xB48D, 0x8A8B, 0xB48E, 0x8A8C, 0xB48F, 0x8A8D, 0xB490, 0x8A8E, 0xB491, 0x8A8F, 0xB492, 0x8A90, 0xB493, 0x8A91, 0xB494, 0x8A92, 0xB495, 0x8A93, 0xB496, 0x8A94, 0xB497, 0x8A95, 0xB498, 0x8A96, 0xB499, 0x8A97, 0xB49A, 0x8A98, 0xB49B, 0x8A99, 0xB49C, 0x8A9A, 0xB49E, 0x8A9B, 0xB49F, 0x8A9C, 0xB4A0, 0x8A9D, 0xB4A1, 0x8A9E, 0xB4A2, 0x8A9F, 0xB4A3, 0x8AA0, 0xB4A5, 0x8AA1, 0xB4A6, 0x8AA2, 0xB4A7, 0x8AA3, 0xB4A9, 0x8AA4, 0xB4AA, 0x8AA5, 0xB4AB, 0x8AA6, 0xB4AD, 0x8AA7, 0xB4AE, 0x8AA8, 0xB4AF, 0x8AA9, 0xB4B0, 0x8AAA, 0xB4B1, 0x8AAB, 0xB4B2, 0x8AAC, 0xB4B3, 0x8AAD, 0xB4B4, 0x8AAE, 0xB4B6, 0x8AAF, 0xB4B8, 0x8AB0, 0xB4BA, 0x8AB1, 0xB4BB, 0x8AB2, 0xB4BC, 0x8AB3, 0xB4BD, 0x8AB4, 0xB4BE, 0x8AB5, 0xB4BF, 0x8AB6, 0xB4C1, 0x8AB7, 0xB4C2, 0x8AB8, 0xB4C3, 0x8AB9, 0xB4C5, 0x8ABA, 0xB4C6, 0x8ABB, 0xB4C7, 0x8ABC, 0xB4C9, 0x8ABD, 0xB4CA, 0x8ABE, 0xB4CB, 0x8ABF, 0xB4CC, 0x8AC0, 0xB4CD, 0x8AC1, 0xB4CE, 0x8AC2, 0xB4CF, 0x8AC3, 0xB4D1, 0x8AC4, 0xB4D2, 0x8AC5, 0xB4D3, 0x8AC6, 0xB4D4, 0x8AC7, 0xB4D6, 0x8AC8, 0xB4D7, 0x8AC9, 0xB4D8, 0x8ACA, 0xB4D9, 0x8ACB, 0xB4DA, 0x8ACC, 0xB4DB, 0x8ACD, 0xB4DE, 0x8ACE, 0xB4DF, 0x8ACF, 0xB4E1, 0x8AD0, 0xB4E2, 0x8AD1, 0xB4E5, 0x8AD2, 0xB4E7, 0x8AD3, 0xB4E8, 0x8AD4, 0xB4E9, 0x8AD5, 0xB4EA, 0x8AD6, 0xB4EB, 0x8AD7, 0xB4EE, 0x8AD8, 0xB4F0, 0x8AD9, 0xB4F2, 0x8ADA, 0xB4F3, 0x8ADB, 0xB4F4, 0x8ADC, 0xB4F5, 0x8ADD, 0xB4F6, 0x8ADE, 0xB4F7, 0x8ADF, 0xB4F9, 0x8AE0, 0xB4FA, 0x8AE1, 0xB4FB, 0x8AE2, 0xB4FC, 0x8AE3, 0xB4FD, 0x8AE4, 0xB4FE, 0x8AE5, 0xB4FF, 0x8AE6, 0xB500, 0x8AE7, 0xB501, 0x8AE8, 0xB502, 0x8AE9, 0xB503, 0x8AEA, 0xB504, 0x8AEB, 0xB505, 0x8AEC, 0xB506, 0x8AED, 0xB507, 0x8AEE, 0xB508, 0x8AEF, 0xB509, 0x8AF0, 0xB50A, 0x8AF1, 0xB50B, 0x8AF2, 0xB50C, 0x8AF3, 0xB50D, 0x8AF4, 0xB50E, 0x8AF5, 0xB50F, 0x8AF6, 0xB510, 0x8AF7, 0xB511, 0x8AF8, 0xB512, 0x8AF9, 0xB513, 0x8AFA, 0xB516, 0x8AFB, 0xB517, 0x8AFC, 0xB519, 0x8AFD, 0xB51A, 0x8AFE, 0xB51D, 0x8B41, 0xB51E, 0x8B42, 0xB51F, 0x8B43, 0xB520, 0x8B44, 0xB521, 0x8B45, 0xB522, 0x8B46, 0xB523, 0x8B47, 0xB526, 0x8B48, 0xB52B, 0x8B49, 0xB52C, 0x8B4A, 0xB52D, 0x8B4B, 0xB52E, 0x8B4C, 0xB52F, 0x8B4D, 0xB532, 0x8B4E, 0xB533, 0x8B4F, 0xB535, 0x8B50, 0xB536, 0x8B51, 0xB537, 0x8B52, 0xB539, 0x8B53, 0xB53A, 0x8B54, 0xB53B, 0x8B55, 0xB53C, 0x8B56, 0xB53D, 0x8B57, 0xB53E, 0x8B58, 0xB53F, 0x8B59, 0xB542, 0x8B5A, 0xB546, 0x8B61, 0xB547, 0x8B62, 0xB548, 0x8B63, 0xB549, 0x8B64, 0xB54A, 0x8B65, 0xB54E, 0x8B66, 0xB54F, 0x8B67, 0xB551, 0x8B68, 0xB552, 0x8B69, 0xB553, 0x8B6A, 0xB555, 0x8B6B, 0xB556, 0x8B6C, 0xB557, 0x8B6D, 0xB558, 0x8B6E, 0xB559, 0x8B6F, 0xB55A, 0x8B70, 0xB55B, 0x8B71, 0xB55E, 0x8B72, 0xB562, 0x8B73, 0xB563, 0x8B74, 0xB564, 0x8B75, 0xB565, 0x8B76, 0xB566, 0x8B77, 0xB567, 0x8B78, 0xB568, 0x8B79, 0xB569, 0x8B7A, 0xB56A, 0x8B81, 0xB56B, 0x8B82, 0xB56C, 0x8B83, 0xB56D, 0x8B84, 0xB56E, 0x8B85, 0xB56F, 0x8B86, 0xB570, 0x8B87, 0xB571, 0x8B88, 0xB572, 0x8B89, 0xB573, 0x8B8A, 0xB574, 0x8B8B, 0xB575, 0x8B8C, 0xB576, 0x8B8D, 0xB577, 0x8B8E, 0xB578, 0x8B8F, 0xB579, 0x8B90, 0xB57A, 0x8B91, 0xB57B, 0x8B92, 0xB57C, 0x8B93, 0xB57D, 0x8B94, 0xB57E, 0x8B95, 0xB57F, 0x8B96, 0xB580, 0x8B97, 0xB581, 0x8B98, 0xB582, 0x8B99, 0xB583, 0x8B9A, 0xB584, 0x8B9B, 0xB585, 0x8B9C, 0xB586, 0x8B9D, 0xB587, 0x8B9E, 0xB588, 0x8B9F, 0xB589, 0x8BA0, 0xB58A, 0x8BA1, 0xB58B, 0x8BA2, 0xB58C, 0x8BA3, 0xB58D, 0x8BA4, 0xB58E, 0x8BA5, 0xB58F, 0x8BA6, 0xB590, 0x8BA7, 0xB591, 0x8BA8, 0xB592, 0x8BA9, 0xB593, 0x8BAA, 0xB594, 0x8BAB, 0xB595, 0x8BAC, 0xB596, 0x8BAD, 0xB597, 0x8BAE, 0xB598, 0x8BAF, 0xB599, 0x8BB0, 0xB59A, 0x8BB1, 0xB59B, 0x8BB2, 0xB59C, 0x8BB3, 0xB59D, 0x8BB4, 0xB59E, 0x8BB5, 0xB59F, 0x8BB6, 0xB5A2, 0x8BB7, 0xB5A3, 0x8BB8, 0xB5A5, 0x8BB9, 0xB5A6, 0x8BBA, 0xB5A7, 0x8BBB, 0xB5A9, 0x8BBC, 0xB5AC, 0x8BBD, 0xB5AD, 0x8BBE, 0xB5AE, 0x8BBF, 0xB5AF, 0x8BC0, 0xB5B2, 0x8BC1, 0xB5B6, 0x8BC2, 0xB5B7, 0x8BC3, 0xB5B8, 0x8BC4, 0xB5B9, 0x8BC5, 0xB5BA, 0x8BC6, 0xB5BE, 0x8BC7, 0xB5BF, 0x8BC8, 0xB5C1, 0x8BC9, 0xB5C2, 0x8BCA, 0xB5C3, 0x8BCB, 0xB5C5, 0x8BCC, 0xB5C6, 0x8BCD, 0xB5C7, 0x8BCE, 0xB5C8, 0x8BCF, 0xB5C9, 0x8BD0, 0xB5CA, 0x8BD1, 0xB5CB, 0x8BD2, 0xB5CE, 0x8BD3, 0xB5D2, 0x8BD4, 0xB5D3, 0x8BD5, 0xB5D4, 0x8BD6, 0xB5D5, 0x8BD7, 0xB5D6, 0x8BD8, 0xB5D7, 0x8BD9, 0xB5D9, 0x8BDA, 0xB5DA, 0x8BDB, 0xB5DB, 0x8BDC, 0xB5DC, 0x8BDD, 0xB5DD, 0x8BDE, 0xB5DE, 0x8BDF, 0xB5DF, 0x8BE0, 0xB5E0, 0x8BE1, 0xB5E1, 0x8BE2, 0xB5E2, 0x8BE3, 0xB5E3, 0x8BE4, 0xB5E4, 0x8BE5, 0xB5E5, 0x8BE6, 0xB5E6, 0x8BE7, 0xB5E7, 0x8BE8, 0xB5E8, 0x8BE9, 0xB5E9, 0x8BEA, 0xB5EA, 0x8BEB, 0xB5EB, 0x8BEC, 0xB5ED, 0x8BED, 0xB5EE, 0x8BEE, 0xB5EF, 0x8BEF, 0xB5F0, 0x8BF0, 0xB5F1, 0x8BF1, 0xB5F2, 0x8BF2, 0xB5F3, 0x8BF3, 0xB5F4, 0x8BF4, 0xB5F5, 0x8BF5, 0xB5F6, 0x8BF6, 0xB5F7, 0x8BF7, 0xB5F8, 0x8BF8, 0xB5F9, 0x8BF9, 0xB5FA, 0x8BFA, 0xB5FB, 0x8BFB, 0xB5FC, 0x8BFC, 0xB5FD, 0x8BFD, 0xB5FE, 0x8BFE, 0xB5FF, 0x8C41, 0xB600, 0x8C42, 0xB601, 0x8C43, 0xB602, 0x8C44, 0xB603, 0x8C45, 0xB604, 0x8C46, 0xB605, 0x8C47, 0xB606, 0x8C48, 0xB607, 0x8C49, 0xB608, 0x8C4A, 0xB609, 0x8C4B, 0xB60A, 0x8C4C, 0xB60B, 0x8C4D, 0xB60C, 0x8C4E, 0xB60D, 0x8C4F, 0xB60E, 0x8C50, 0xB60F, 0x8C51, 0xB612, 0x8C52, 0xB613, 0x8C53, 0xB615, 0x8C54, 0xB616, 0x8C55, 0xB617, 0x8C56, 0xB619, 0x8C57, 0xB61A, 0x8C58, 0xB61B, 0x8C59, 0xB61C, 0x8C5A, 0xB61D, 0x8C61, 0xB61E, 0x8C62, 0xB61F, 0x8C63, 0xB620, 0x8C64, 0xB621, 0x8C65, 0xB622, 0x8C66, 0xB623, 0x8C67, 0xB624, 0x8C68, 0xB626, 0x8C69, 0xB627, 0x8C6A, 0xB628, 0x8C6B, 0xB629, 0x8C6C, 0xB62A, 0x8C6D, 0xB62B, 0x8C6E, 0xB62D, 0x8C6F, 0xB62E, 0x8C70, 0xB62F, 0x8C71, 0xB630, 0x8C72, 0xB631, 0x8C73, 0xB632, 0x8C74, 0xB633, 0x8C75, 0xB635, 0x8C76, 0xB636, 0x8C77, 0xB637, 0x8C78, 0xB638, 0x8C79, 0xB639, 0x8C7A, 0xB63A, 0x8C81, 0xB63B, 0x8C82, 0xB63C, 0x8C83, 0xB63D, 0x8C84, 0xB63E, 0x8C85, 0xB63F, 0x8C86, 0xB640, 0x8C87, 0xB641, 0x8C88, 0xB642, 0x8C89, 0xB643, 0x8C8A, 0xB644, 0x8C8B, 0xB645, 0x8C8C, 0xB646, 0x8C8D, 0xB647, 0x8C8E, 0xB649, 0x8C8F, 0xB64A, 0x8C90, 0xB64B, 0x8C91, 0xB64C, 0x8C92, 0xB64D, 0x8C93, 0xB64E, 0x8C94, 0xB64F, 0x8C95, 0xB650, 0x8C96, 0xB651, 0x8C97, 0xB652, 0x8C98, 0xB653, 0x8C99, 0xB654, 0x8C9A, 0xB655, 0x8C9B, 0xB656, 0x8C9C, 0xB657, 0x8C9D, 0xB658, 0x8C9E, 0xB659, 0x8C9F, 0xB65A, 0x8CA0, 0xB65B, 0x8CA1, 0xB65C, 0x8CA2, 0xB65D, 0x8CA3, 0xB65E, 0x8CA4, 0xB65F, 0x8CA5, 0xB660, 0x8CA6, 0xB661, 0x8CA7, 0xB662, 0x8CA8, 0xB663, 0x8CA9, 0xB665, 0x8CAA, 0xB666, 0x8CAB, 0xB667, 0x8CAC, 0xB669, 0x8CAD, 0xB66A, 0x8CAE, 0xB66B, 0x8CAF, 0xB66C, 0x8CB0, 0xB66D, 0x8CB1, 0xB66E, 0x8CB2, 0xB66F, 0x8CB3, 0xB670, 0x8CB4, 0xB671, 0x8CB5, 0xB672, 0x8CB6, 0xB673, 0x8CB7, 0xB674, 0x8CB8, 0xB675, 0x8CB9, 0xB676, 0x8CBA, 0xB677, 0x8CBB, 0xB678, 0x8CBC, 0xB679, 0x8CBD, 0xB67A, 0x8CBE, 0xB67B, 0x8CBF, 0xB67C, 0x8CC0, 0xB67D, 0x8CC1, 0xB67E, 0x8CC2, 0xB67F, 0x8CC3, 0xB680, 0x8CC4, 0xB681, 0x8CC5, 0xB682, 0x8CC6, 0xB683, 0x8CC7, 0xB684, 0x8CC8, 0xB685, 0x8CC9, 0xB686, 0x8CCA, 0xB687, 0x8CCB, 0xB688, 0x8CCC, 0xB689, 0x8CCD, 0xB68A, 0x8CCE, 0xB68B, 0x8CCF, 0xB68C, 0x8CD0, 0xB68D, 0x8CD1, 0xB68E, 0x8CD2, 0xB68F, 0x8CD3, 0xB690, 0x8CD4, 0xB691, 0x8CD5, 0xB692, 0x8CD6, 0xB693, 0x8CD7, 0xB694, 0x8CD8, 0xB695, 0x8CD9, 0xB696, 0x8CDA, 0xB697, 0x8CDB, 0xB698, 0x8CDC, 0xB699, 0x8CDD, 0xB69A, 0x8CDE, 0xB69B, 0x8CDF, 0xB69E, 0x8CE0, 0xB69F, 0x8CE1, 0xB6A1, 0x8CE2, 0xB6A2, 0x8CE3, 0xB6A3, 0x8CE4, 0xB6A5, 0x8CE5, 0xB6A6, 0x8CE6, 0xB6A7, 0x8CE7, 0xB6A8, 0x8CE8, 0xB6A9, 0x8CE9, 0xB6AA, 0x8CEA, 0xB6AD, 0x8CEB, 0xB6AE, 0x8CEC, 0xB6AF, 0x8CED, 0xB6B0, 0x8CEE, 0xB6B2, 0x8CEF, 0xB6B3, 0x8CF0, 0xB6B4, 0x8CF1, 0xB6B5, 0x8CF2, 0xB6B6, 0x8CF3, 0xB6B7, 0x8CF4, 0xB6B8, 0x8CF5, 0xB6B9, 0x8CF6, 0xB6BA, 0x8CF7, 0xB6BB, 0x8CF8, 0xB6BC, 0x8CF9, 0xB6BD, 0x8CFA, 0xB6BE, 0x8CFB, 0xB6BF, 0x8CFC, 0xB6C0, 0x8CFD, 0xB6C1, 0x8CFE, 0xB6C2, 0x8D41, 0xB6C3, 0x8D42, 0xB6C4, 0x8D43, 0xB6C5, 0x8D44, 0xB6C6, 0x8D45, 0xB6C7, 0x8D46, 0xB6C8, 0x8D47, 0xB6C9, 0x8D48, 0xB6CA, 0x8D49, 0xB6CB, 0x8D4A, 0xB6CC, 0x8D4B, 0xB6CD, 0x8D4C, 0xB6CE, 0x8D4D, 0xB6CF, 0x8D4E, 0xB6D0, 0x8D4F, 0xB6D1, 0x8D50, 0xB6D2, 0x8D51, 0xB6D3, 0x8D52, 0xB6D5, 0x8D53, 0xB6D6, 0x8D54, 0xB6D7, 0x8D55, 0xB6D8, 0x8D56, 0xB6D9, 0x8D57, 0xB6DA, 0x8D58, 0xB6DB, 0x8D59, 0xB6DC, 0x8D5A, 0xB6DD, 0x8D61, 0xB6DE, 0x8D62, 0xB6DF, 0x8D63, 0xB6E0, 0x8D64, 0xB6E1, 0x8D65, 0xB6E2, 0x8D66, 0xB6E3, 0x8D67, 0xB6E4, 0x8D68, 0xB6E5, 0x8D69, 0xB6E6, 0x8D6A, 0xB6E7, 0x8D6B, 0xB6E8, 0x8D6C, 0xB6E9, 0x8D6D, 0xB6EA, 0x8D6E, 0xB6EB, 0x8D6F, 0xB6EC, 0x8D70, 0xB6ED, 0x8D71, 0xB6EE, 0x8D72, 0xB6EF, 0x8D73, 0xB6F1, 0x8D74, 0xB6F2, 0x8D75, 0xB6F3, 0x8D76, 0xB6F5, 0x8D77, 0xB6F6, 0x8D78, 0xB6F7, 0x8D79, 0xB6F9, 0x8D7A, 0xB6FA, 0x8D81, 0xB6FB, 0x8D82, 0xB6FC, 0x8D83, 0xB6FD, 0x8D84, 0xB6FE, 0x8D85, 0xB6FF, 0x8D86, 0xB702, 0x8D87, 0xB703, 0x8D88, 0xB704, 0x8D89, 0xB706, 0x8D8A, 0xB707, 0x8D8B, 0xB708, 0x8D8C, 0xB709, 0x8D8D, 0xB70A, 0x8D8E, 0xB70B, 0x8D8F, 0xB70C, 0x8D90, 0xB70D, 0x8D91, 0xB70E, 0x8D92, 0xB70F, 0x8D93, 0xB710, 0x8D94, 0xB711, 0x8D95, 0xB712, 0x8D96, 0xB713, 0x8D97, 0xB714, 0x8D98, 0xB715, 0x8D99, 0xB716, 0x8D9A, 0xB717, 0x8D9B, 0xB718, 0x8D9C, 0xB719, 0x8D9D, 0xB71A, 0x8D9E, 0xB71B, 0x8D9F, 0xB71C, 0x8DA0, 0xB71D, 0x8DA1, 0xB71E, 0x8DA2, 0xB71F, 0x8DA3, 0xB720, 0x8DA4, 0xB721, 0x8DA5, 0xB722, 0x8DA6, 0xB723, 0x8DA7, 0xB724, 0x8DA8, 0xB725, 0x8DA9, 0xB726, 0x8DAA, 0xB727, 0x8DAB, 0xB72A, 0x8DAC, 0xB72B, 0x8DAD, 0xB72D, 0x8DAE, 0xB72E, 0x8DAF, 0xB731, 0x8DB0, 0xB732, 0x8DB1, 0xB733, 0x8DB2, 0xB734, 0x8DB3, 0xB735, 0x8DB4, 0xB736, 0x8DB5, 0xB737, 0x8DB6, 0xB73A, 0x8DB7, 0xB73C, 0x8DB8, 0xB73D, 0x8DB9, 0xB73E, 0x8DBA, 0xB73F, 0x8DBB, 0xB740, 0x8DBC, 0xB741, 0x8DBD, 0xB742, 0x8DBE, 0xB743, 0x8DBF, 0xB745, 0x8DC0, 0xB746, 0x8DC1, 0xB747, 0x8DC2, 0xB749, 0x8DC3, 0xB74A, 0x8DC4, 0xB74B, 0x8DC5, 0xB74D, 0x8DC6, 0xB74E, 0x8DC7, 0xB74F, 0x8DC8, 0xB750, 0x8DC9, 0xB751, 0x8DCA, 0xB752, 0x8DCB, 0xB753, 0x8DCC, 0xB756, 0x8DCD, 0xB757, 0x8DCE, 0xB758, 0x8DCF, 0xB759, 0x8DD0, 0xB75A, 0x8DD1, 0xB75B, 0x8DD2, 0xB75C, 0x8DD3, 0xB75D, 0x8DD4, 0xB75E, 0x8DD5, 0xB75F, 0x8DD6, 0xB761, 0x8DD7, 0xB762, 0x8DD8, 0xB763, 0x8DD9, 0xB765, 0x8DDA, 0xB766, 0x8DDB, 0xB767, 0x8DDC, 0xB769, 0x8DDD, 0xB76A, 0x8DDE, 0xB76B, 0x8DDF, 0xB76C, 0x8DE0, 0xB76D, 0x8DE1, 0xB76E, 0x8DE2, 0xB76F, 0x8DE3, 0xB772, 0x8DE4, 0xB774, 0x8DE5, 0xB776, 0x8DE6, 0xB777, 0x8DE7, 0xB778, 0x8DE8, 0xB779, 0x8DE9, 0xB77A, 0x8DEA, 0xB77B, 0x8DEB, 0xB77E, 0x8DEC, 0xB77F, 0x8DED, 0xB781, 0x8DEE, 0xB782, 0x8DEF, 0xB783, 0x8DF0, 0xB785, 0x8DF1, 0xB786, 0x8DF2, 0xB787, 0x8DF3, 0xB788, 0x8DF4, 0xB789, 0x8DF5, 0xB78A, 0x8DF6, 0xB78B, 0x8DF7, 0xB78E, 0x8DF8, 0xB793, 0x8DF9, 0xB794, 0x8DFA, 0xB795, 0x8DFB, 0xB79A, 0x8DFC, 0xB79B, 0x8DFD, 0xB79D, 0x8DFE, 0xB79E, 0x8E41, 0xB79F, 0x8E42, 0xB7A1, 0x8E43, 0xB7A2, 0x8E44, 0xB7A3, 0x8E45, 0xB7A4, 0x8E46, 0xB7A5, 0x8E47, 0xB7A6, 0x8E48, 0xB7A7, 0x8E49, 0xB7AA, 0x8E4A, 0xB7AE, 0x8E4B, 0xB7AF, 0x8E4C, 0xB7B0, 0x8E4D, 0xB7B1, 0x8E4E, 0xB7B2, 0x8E4F, 0xB7B3, 0x8E50, 0xB7B6, 0x8E51, 0xB7B7, 0x8E52, 0xB7B9, 0x8E53, 0xB7BA, 0x8E54, 0xB7BB, 0x8E55, 0xB7BC, 0x8E56, 0xB7BD, 0x8E57, 0xB7BE, 0x8E58, 0xB7BF, 0x8E59, 0xB7C0, 0x8E5A, 0xB7C1, 0x8E61, 0xB7C2, 0x8E62, 0xB7C3, 0x8E63, 0xB7C4, 0x8E64, 0xB7C5, 0x8E65, 0xB7C6, 0x8E66, 0xB7C8, 0x8E67, 0xB7CA, 0x8E68, 0xB7CB, 0x8E69, 0xB7CC, 0x8E6A, 0xB7CD, 0x8E6B, 0xB7CE, 0x8E6C, 0xB7CF, 0x8E6D, 0xB7D0, 0x8E6E, 0xB7D1, 0x8E6F, 0xB7D2, 0x8E70, 0xB7D3, 0x8E71, 0xB7D4, 0x8E72, 0xB7D5, 0x8E73, 0xB7D6, 0x8E74, 0xB7D7, 0x8E75, 0xB7D8, 0x8E76, 0xB7D9, 0x8E77, 0xB7DA, 0x8E78, 0xB7DB, 0x8E79, 0xB7DC, 0x8E7A, 0xB7DD, 0x8E81, 0xB7DE, 0x8E82, 0xB7DF, 0x8E83, 0xB7E0, 0x8E84, 0xB7E1, 0x8E85, 0xB7E2, 0x8E86, 0xB7E3, 0x8E87, 0xB7E4, 0x8E88, 0xB7E5, 0x8E89, 0xB7E6, 0x8E8A, 0xB7E7, 0x8E8B, 0xB7E8, 0x8E8C, 0xB7E9, 0x8E8D, 0xB7EA, 0x8E8E, 0xB7EB, 0x8E8F, 0xB7EE, 0x8E90, 0xB7EF, 0x8E91, 0xB7F1, 0x8E92, 0xB7F2, 0x8E93, 0xB7F3, 0x8E94, 0xB7F5, 0x8E95, 0xB7F6, 0x8E96, 0xB7F7, 0x8E97, 0xB7F8, 0x8E98, 0xB7F9, 0x8E99, 0xB7FA, 0x8E9A, 0xB7FB, 0x8E9B, 0xB7FE, 0x8E9C, 0xB802, 0x8E9D, 0xB803, 0x8E9E, 0xB804, 0x8E9F, 0xB805, 0x8EA0, 0xB806, 0x8EA1, 0xB80A, 0x8EA2, 0xB80B, 0x8EA3, 0xB80D, 0x8EA4, 0xB80E, 0x8EA5, 0xB80F, 0x8EA6, 0xB811, 0x8EA7, 0xB812, 0x8EA8, 0xB813, 0x8EA9, 0xB814, 0x8EAA, 0xB815, 0x8EAB, 0xB816, 0x8EAC, 0xB817, 0x8EAD, 0xB81A, 0x8EAE, 0xB81C, 0x8EAF, 0xB81E, 0x8EB0, 0xB81F, 0x8EB1, 0xB820, 0x8EB2, 0xB821, 0x8EB3, 0xB822, 0x8EB4, 0xB823, 0x8EB5, 0xB826, 0x8EB6, 0xB827, 0x8EB7, 0xB829, 0x8EB8, 0xB82A, 0x8EB9, 0xB82B, 0x8EBA, 0xB82D, 0x8EBB, 0xB82E, 0x8EBC, 0xB82F, 0x8EBD, 0xB830, 0x8EBE, 0xB831, 0x8EBF, 0xB832, 0x8EC0, 0xB833, 0x8EC1, 0xB836, 0x8EC2, 0xB83A, 0x8EC3, 0xB83B, 0x8EC4, 0xB83C, 0x8EC5, 0xB83D, 0x8EC6, 0xB83E, 0x8EC7, 0xB83F, 0x8EC8, 0xB841, 0x8EC9, 0xB842, 0x8ECA, 0xB843, 0x8ECB, 0xB845, 0x8ECC, 0xB846, 0x8ECD, 0xB847, 0x8ECE, 0xB848, 0x8ECF, 0xB849, 0x8ED0, 0xB84A, 0x8ED1, 0xB84B, 0x8ED2, 0xB84C, 0x8ED3, 0xB84D, 0x8ED4, 0xB84E, 0x8ED5, 0xB84F, 0x8ED6, 0xB850, 0x8ED7, 0xB852, 0x8ED8, 0xB854, 0x8ED9, 0xB855, 0x8EDA, 0xB856, 0x8EDB, 0xB857, 0x8EDC, 0xB858, 0x8EDD, 0xB859, 0x8EDE, 0xB85A, 0x8EDF, 0xB85B, 0x8EE0, 0xB85E, 0x8EE1, 0xB85F, 0x8EE2, 0xB861, 0x8EE3, 0xB862, 0x8EE4, 0xB863, 0x8EE5, 0xB865, 0x8EE6, 0xB866, 0x8EE7, 0xB867, 0x8EE8, 0xB868, 0x8EE9, 0xB869, 0x8EEA, 0xB86A, 0x8EEB, 0xB86B, 0x8EEC, 0xB86E, 0x8EED, 0xB870, 0x8EEE, 0xB872, 0x8EEF, 0xB873, 0x8EF0, 0xB874, 0x8EF1, 0xB875, 0x8EF2, 0xB876, 0x8EF3, 0xB877, 0x8EF4, 0xB879, 0x8EF5, 0xB87A, 0x8EF6, 0xB87B, 0x8EF7, 0xB87D, 0x8EF8, 0xB87E, 0x8EF9, 0xB87F, 0x8EFA, 0xB880, 0x8EFB, 0xB881, 0x8EFC, 0xB882, 0x8EFD, 0xB883, 0x8EFE, 0xB884, 0x8F41, 0xB885, 0x8F42, 0xB886, 0x8F43, 0xB887, 0x8F44, 0xB888, 0x8F45, 0xB889, 0x8F46, 0xB88A, 0x8F47, 0xB88B, 0x8F48, 0xB88C, 0x8F49, 0xB88E, 0x8F4A, 0xB88F, 0x8F4B, 0xB890, 0x8F4C, 0xB891, 0x8F4D, 0xB892, 0x8F4E, 0xB893, 0x8F4F, 0xB894, 0x8F50, 0xB895, 0x8F51, 0xB896, 0x8F52, 0xB897, 0x8F53, 0xB898, 0x8F54, 0xB899, 0x8F55, 0xB89A, 0x8F56, 0xB89B, 0x8F57, 0xB89C, 0x8F58, 0xB89D, 0x8F59, 0xB89E, 0x8F5A, 0xB89F, 0x8F61, 0xB8A0, 0x8F62, 0xB8A1, 0x8F63, 0xB8A2, 0x8F64, 0xB8A3, 0x8F65, 0xB8A4, 0x8F66, 0xB8A5, 0x8F67, 0xB8A6, 0x8F68, 0xB8A7, 0x8F69, 0xB8A9, 0x8F6A, 0xB8AA, 0x8F6B, 0xB8AB, 0x8F6C, 0xB8AC, 0x8F6D, 0xB8AD, 0x8F6E, 0xB8AE, 0x8F6F, 0xB8AF, 0x8F70, 0xB8B1, 0x8F71, 0xB8B2, 0x8F72, 0xB8B3, 0x8F73, 0xB8B5, 0x8F74, 0xB8B6, 0x8F75, 0xB8B7, 0x8F76, 0xB8B9, 0x8F77, 0xB8BA, 0x8F78, 0xB8BB, 0x8F79, 0xB8BC, 0x8F7A, 0xB8BD, 0x8F81, 0xB8BE, 0x8F82, 0xB8BF, 0x8F83, 0xB8C2, 0x8F84, 0xB8C4, 0x8F85, 0xB8C6, 0x8F86, 0xB8C7, 0x8F87, 0xB8C8, 0x8F88, 0xB8C9, 0x8F89, 0xB8CA, 0x8F8A, 0xB8CB, 0x8F8B, 0xB8CD, 0x8F8C, 0xB8CE, 0x8F8D, 0xB8CF, 0x8F8E, 0xB8D1, 0x8F8F, 0xB8D2, 0x8F90, 0xB8D3, 0x8F91, 0xB8D5, 0x8F92, 0xB8D6, 0x8F93, 0xB8D7, 0x8F94, 0xB8D8, 0x8F95, 0xB8D9, 0x8F96, 0xB8DA, 0x8F97, 0xB8DB, 0x8F98, 0xB8DC, 0x8F99, 0xB8DE, 0x8F9A, 0xB8E0, 0x8F9B, 0xB8E2, 0x8F9C, 0xB8E3, 0x8F9D, 0xB8E4, 0x8F9E, 0xB8E5, 0x8F9F, 0xB8E6, 0x8FA0, 0xB8E7, 0x8FA1, 0xB8EA, 0x8FA2, 0xB8EB, 0x8FA3, 0xB8ED, 0x8FA4, 0xB8EE, 0x8FA5, 0xB8EF, 0x8FA6, 0xB8F1, 0x8FA7, 0xB8F2, 0x8FA8, 0xB8F3, 0x8FA9, 0xB8F4, 0x8FAA, 0xB8F5, 0x8FAB, 0xB8F6, 0x8FAC, 0xB8F7, 0x8FAD, 0xB8FA, 0x8FAE, 0xB8FC, 0x8FAF, 0xB8FE, 0x8FB0, 0xB8FF, 0x8FB1, 0xB900, 0x8FB2, 0xB901, 0x8FB3, 0xB902, 0x8FB4, 0xB903, 0x8FB5, 0xB905, 0x8FB6, 0xB906, 0x8FB7, 0xB907, 0x8FB8, 0xB908, 0x8FB9, 0xB909, 0x8FBA, 0xB90A, 0x8FBB, 0xB90B, 0x8FBC, 0xB90C, 0x8FBD, 0xB90D, 0x8FBE, 0xB90E, 0x8FBF, 0xB90F, 0x8FC0, 0xB910, 0x8FC1, 0xB911, 0x8FC2, 0xB912, 0x8FC3, 0xB913, 0x8FC4, 0xB914, 0x8FC5, 0xB915, 0x8FC6, 0xB916, 0x8FC7, 0xB917, 0x8FC8, 0xB919, 0x8FC9, 0xB91A, 0x8FCA, 0xB91B, 0x8FCB, 0xB91C, 0x8FCC, 0xB91D, 0x8FCD, 0xB91E, 0x8FCE, 0xB91F, 0x8FCF, 0xB921, 0x8FD0, 0xB922, 0x8FD1, 0xB923, 0x8FD2, 0xB924, 0x8FD3, 0xB925, 0x8FD4, 0xB926, 0x8FD5, 0xB927, 0x8FD6, 0xB928, 0x8FD7, 0xB929, 0x8FD8, 0xB92A, 0x8FD9, 0xB92B, 0x8FDA, 0xB92C, 0x8FDB, 0xB92D, 0x8FDC, 0xB92E, 0x8FDD, 0xB92F, 0x8FDE, 0xB930, 0x8FDF, 0xB931, 0x8FE0, 0xB932, 0x8FE1, 0xB933, 0x8FE2, 0xB934, 0x8FE3, 0xB935, 0x8FE4, 0xB936, 0x8FE5, 0xB937, 0x8FE6, 0xB938, 0x8FE7, 0xB939, 0x8FE8, 0xB93A, 0x8FE9, 0xB93B, 0x8FEA, 0xB93E, 0x8FEB, 0xB93F, 0x8FEC, 0xB941, 0x8FED, 0xB942, 0x8FEE, 0xB943, 0x8FEF, 0xB945, 0x8FF0, 0xB946, 0x8FF1, 0xB947, 0x8FF2, 0xB948, 0x8FF3, 0xB949, 0x8FF4, 0xB94A, 0x8FF5, 0xB94B, 0x8FF6, 0xB94D, 0x8FF7, 0xB94E, 0x8FF8, 0xB950, 0x8FF9, 0xB952, 0x8FFA, 0xB953, 0x8FFB, 0xB954, 0x8FFC, 0xB955, 0x8FFD, 0xB956, 0x8FFE, 0xB957, 0x9041, 0xB95A, 0x9042, 0xB95B, 0x9043, 0xB95D, 0x9044, 0xB95E, 0x9045, 0xB95F, 0x9046, 0xB961, 0x9047, 0xB962, 0x9048, 0xB963, 0x9049, 0xB964, 0x904A, 0xB965, 0x904B, 0xB966, 0x904C, 0xB967, 0x904D, 0xB96A, 0x904E, 0xB96C, 0x904F, 0xB96E, 0x9050, 0xB96F, 0x9051, 0xB970, 0x9052, 0xB971, 0x9053, 0xB972, 0x9054, 0xB973, 0x9055, 0xB976, 0x9056, 0xB977, 0x9057, 0xB979, 0x9058, 0xB97A, 0x9059, 0xB97B, 0x905A, 0xB97D, 0x9061, 0xB97E, 0x9062, 0xB97F, 0x9063, 0xB980, 0x9064, 0xB981, 0x9065, 0xB982, 0x9066, 0xB983, 0x9067, 0xB986, 0x9068, 0xB988, 0x9069, 0xB98B, 0x906A, 0xB98C, 0x906B, 0xB98F, 0x906C, 0xB990, 0x906D, 0xB991, 0x906E, 0xB992, 0x906F, 0xB993, 0x9070, 0xB994, 0x9071, 0xB995, 0x9072, 0xB996, 0x9073, 0xB997, 0x9074, 0xB998, 0x9075, 0xB999, 0x9076, 0xB99A, 0x9077, 0xB99B, 0x9078, 0xB99C, 0x9079, 0xB99D, 0x907A, 0xB99E, 0x9081, 0xB99F, 0x9082, 0xB9A0, 0x9083, 0xB9A1, 0x9084, 0xB9A2, 0x9085, 0xB9A3, 0x9086, 0xB9A4, 0x9087, 0xB9A5, 0x9088, 0xB9A6, 0x9089, 0xB9A7, 0x908A, 0xB9A8, 0x908B, 0xB9A9, 0x908C, 0xB9AA, 0x908D, 0xB9AB, 0x908E, 0xB9AE, 0x908F, 0xB9AF, 0x9090, 0xB9B1, 0x9091, 0xB9B2, 0x9092, 0xB9B3, 0x9093, 0xB9B5, 0x9094, 0xB9B6, 0x9095, 0xB9B7, 0x9096, 0xB9B8, 0x9097, 0xB9B9, 0x9098, 0xB9BA, 0x9099, 0xB9BB, 0x909A, 0xB9BE, 0x909B, 0xB9C0, 0x909C, 0xB9C2, 0x909D, 0xB9C3, 0x909E, 0xB9C4, 0x909F, 0xB9C5, 0x90A0, 0xB9C6, 0x90A1, 0xB9C7, 0x90A2, 0xB9CA, 0x90A3, 0xB9CB, 0x90A4, 0xB9CD, 0x90A5, 0xB9D3, 0x90A6, 0xB9D4, 0x90A7, 0xB9D5, 0x90A8, 0xB9D6, 0x90A9, 0xB9D7, 0x90AA, 0xB9DA, 0x90AB, 0xB9DC, 0x90AC, 0xB9DF, 0x90AD, 0xB9E0, 0x90AE, 0xB9E2, 0x90AF, 0xB9E6, 0x90B0, 0xB9E7, 0x90B1, 0xB9E9, 0x90B2, 0xB9EA, 0x90B3, 0xB9EB, 0x90B4, 0xB9ED, 0x90B5, 0xB9EE, 0x90B6, 0xB9EF, 0x90B7, 0xB9F0, 0x90B8, 0xB9F1, 0x90B9, 0xB9F2, 0x90BA, 0xB9F3, 0x90BB, 0xB9F6, 0x90BC, 0xB9FB, 0x90BD, 0xB9FC, 0x90BE, 0xB9FD, 0x90BF, 0xB9FE, 0x90C0, 0xB9FF, 0x90C1, 0xBA02, 0x90C2, 0xBA03, 0x90C3, 0xBA04, 0x90C4, 0xBA05, 0x90C5, 0xBA06, 0x90C6, 0xBA07, 0x90C7, 0xBA09, 0x90C8, 0xBA0A, 0x90C9, 0xBA0B, 0x90CA, 0xBA0C, 0x90CB, 0xBA0D, 0x90CC, 0xBA0E, 0x90CD, 0xBA0F, 0x90CE, 0xBA10, 0x90CF, 0xBA11, 0x90D0, 0xBA12, 0x90D1, 0xBA13, 0x90D2, 0xBA14, 0x90D3, 0xBA16, 0x90D4, 0xBA17, 0x90D5, 0xBA18, 0x90D6, 0xBA19, 0x90D7, 0xBA1A, 0x90D8, 0xBA1B, 0x90D9, 0xBA1C, 0x90DA, 0xBA1D, 0x90DB, 0xBA1E, 0x90DC, 0xBA1F, 0x90DD, 0xBA20, 0x90DE, 0xBA21, 0x90DF, 0xBA22, 0x90E0, 0xBA23, 0x90E1, 0xBA24, 0x90E2, 0xBA25, 0x90E3, 0xBA26, 0x90E4, 0xBA27, 0x90E5, 0xBA28, 0x90E6, 0xBA29, 0x90E7, 0xBA2A, 0x90E8, 0xBA2B, 0x90E9, 0xBA2C, 0x90EA, 0xBA2D, 0x90EB, 0xBA2E, 0x90EC, 0xBA2F, 0x90ED, 0xBA30, 0x90EE, 0xBA31, 0x90EF, 0xBA32, 0x90F0, 0xBA33, 0x90F1, 0xBA34, 0x90F2, 0xBA35, 0x90F3, 0xBA36, 0x90F4, 0xBA37, 0x90F5, 0xBA3A, 0x90F6, 0xBA3B, 0x90F7, 0xBA3D, 0x90F8, 0xBA3E, 0x90F9, 0xBA3F, 0x90FA, 0xBA41, 0x90FB, 0xBA43, 0x90FC, 0xBA44, 0x90FD, 0xBA45, 0x90FE, 0xBA46, 0x9141, 0xBA47, 0x9142, 0xBA4A, 0x9143, 0xBA4C, 0x9144, 0xBA4F, 0x9145, 0xBA50, 0x9146, 0xBA51, 0x9147, 0xBA52, 0x9148, 0xBA56, 0x9149, 0xBA57, 0x914A, 0xBA59, 0x914B, 0xBA5A, 0x914C, 0xBA5B, 0x914D, 0xBA5D, 0x914E, 0xBA5E, 0x914F, 0xBA5F, 0x9150, 0xBA60, 0x9151, 0xBA61, 0x9152, 0xBA62, 0x9153, 0xBA63, 0x9154, 0xBA66, 0x9155, 0xBA6A, 0x9156, 0xBA6B, 0x9157, 0xBA6C, 0x9158, 0xBA6D, 0x9159, 0xBA6E, 0x915A, 0xBA6F, 0x9161, 0xBA72, 0x9162, 0xBA73, 0x9163, 0xBA75, 0x9164, 0xBA76, 0x9165, 0xBA77, 0x9166, 0xBA79, 0x9167, 0xBA7A, 0x9168, 0xBA7B, 0x9169, 0xBA7C, 0x916A, 0xBA7D, 0x916B, 0xBA7E, 0x916C, 0xBA7F, 0x916D, 0xBA80, 0x916E, 0xBA81, 0x916F, 0xBA82, 0x9170, 0xBA86, 0x9171, 0xBA88, 0x9172, 0xBA89, 0x9173, 0xBA8A, 0x9174, 0xBA8B, 0x9175, 0xBA8D, 0x9176, 0xBA8E, 0x9177, 0xBA8F, 0x9178, 0xBA90, 0x9179, 0xBA91, 0x917A, 0xBA92, 0x9181, 0xBA93, 0x9182, 0xBA94, 0x9183, 0xBA95, 0x9184, 0xBA96, 0x9185, 0xBA97, 0x9186, 0xBA98, 0x9187, 0xBA99, 0x9188, 0xBA9A, 0x9189, 0xBA9B, 0x918A, 0xBA9C, 0x918B, 0xBA9D, 0x918C, 0xBA9E, 0x918D, 0xBA9F, 0x918E, 0xBAA0, 0x918F, 0xBAA1, 0x9190, 0xBAA2, 0x9191, 0xBAA3, 0x9192, 0xBAA4, 0x9193, 0xBAA5, 0x9194, 0xBAA6, 0x9195, 0xBAA7, 0x9196, 0xBAAA, 0x9197, 0xBAAD, 0x9198, 0xBAAE, 0x9199, 0xBAAF, 0x919A, 0xBAB1, 0x919B, 0xBAB3, 0x919C, 0xBAB4, 0x919D, 0xBAB5, 0x919E, 0xBAB6, 0x919F, 0xBAB7, 0x91A0, 0xBABA, 0x91A1, 0xBABC, 0x91A2, 0xBABE, 0x91A3, 0xBABF, 0x91A4, 0xBAC0, 0x91A5, 0xBAC1, 0x91A6, 0xBAC2, 0x91A7, 0xBAC3, 0x91A8, 0xBAC5, 0x91A9, 0xBAC6, 0x91AA, 0xBAC7, 0x91AB, 0xBAC9, 0x91AC, 0xBACA, 0x91AD, 0xBACB, 0x91AE, 0xBACC, 0x91AF, 0xBACD, 0x91B0, 0xBACE, 0x91B1, 0xBACF, 0x91B2, 0xBAD0, 0x91B3, 0xBAD1, 0x91B4, 0xBAD2, 0x91B5, 0xBAD3, 0x91B6, 0xBAD4, 0x91B7, 0xBAD5, 0x91B8, 0xBAD6, 0x91B9, 0xBAD7, 0x91BA, 0xBADA, 0x91BB, 0xBADB, 0x91BC, 0xBADC, 0x91BD, 0xBADD, 0x91BE, 0xBADE, 0x91BF, 0xBADF, 0x91C0, 0xBAE0, 0x91C1, 0xBAE1, 0x91C2, 0xBAE2, 0x91C3, 0xBAE3, 0x91C4, 0xBAE4, 0x91C5, 0xBAE5, 0x91C6, 0xBAE6, 0x91C7, 0xBAE7, 0x91C8, 0xBAE8, 0x91C9, 0xBAE9, 0x91CA, 0xBAEA, 0x91CB, 0xBAEB, 0x91CC, 0xBAEC, 0x91CD, 0xBAED, 0x91CE, 0xBAEE, 0x91CF, 0xBAEF, 0x91D0, 0xBAF0, 0x91D1, 0xBAF1, 0x91D2, 0xBAF2, 0x91D3, 0xBAF3, 0x91D4, 0xBAF4, 0x91D5, 0xBAF5, 0x91D6, 0xBAF6, 0x91D7, 0xBAF7, 0x91D8, 0xBAF8, 0x91D9, 0xBAF9, 0x91DA, 0xBAFA, 0x91DB, 0xBAFB, 0x91DC, 0xBAFD, 0x91DD, 0xBAFE, 0x91DE, 0xBAFF, 0x91DF, 0xBB01, 0x91E0, 0xBB02, 0x91E1, 0xBB03, 0x91E2, 0xBB05, 0x91E3, 0xBB06, 0x91E4, 0xBB07, 0x91E5, 0xBB08, 0x91E6, 0xBB09, 0x91E7, 0xBB0A, 0x91E8, 0xBB0B, 0x91E9, 0xBB0C, 0x91EA, 0xBB0E, 0x91EB, 0xBB10, 0x91EC, 0xBB12, 0x91ED, 0xBB13, 0x91EE, 0xBB14, 0x91EF, 0xBB15, 0x91F0, 0xBB16, 0x91F1, 0xBB17, 0x91F2, 0xBB19, 0x91F3, 0xBB1A, 0x91F4, 0xBB1B, 0x91F5, 0xBB1D, 0x91F6, 0xBB1E, 0x91F7, 0xBB1F, 0x91F8, 0xBB21, 0x91F9, 0xBB22, 0x91FA, 0xBB23, 0x91FB, 0xBB24, 0x91FC, 0xBB25, 0x91FD, 0xBB26, 0x91FE, 0xBB27, 0x9241, 0xBB28, 0x9242, 0xBB2A, 0x9243, 0xBB2C, 0x9244, 0xBB2D, 0x9245, 0xBB2E, 0x9246, 0xBB2F, 0x9247, 0xBB30, 0x9248, 0xBB31, 0x9249, 0xBB32, 0x924A, 0xBB33, 0x924B, 0xBB37, 0x924C, 0xBB39, 0x924D, 0xBB3A, 0x924E, 0xBB3F, 0x924F, 0xBB40, 0x9250, 0xBB41, 0x9251, 0xBB42, 0x9252, 0xBB43, 0x9253, 0xBB46, 0x9254, 0xBB48, 0x9255, 0xBB4A, 0x9256, 0xBB4B, 0x9257, 0xBB4C, 0x9258, 0xBB4E, 0x9259, 0xBB51, 0x925A, 0xBB52, 0x9261, 0xBB53, 0x9262, 0xBB55, 0x9263, 0xBB56, 0x9264, 0xBB57, 0x9265, 0xBB59, 0x9266, 0xBB5A, 0x9267, 0xBB5B, 0x9268, 0xBB5C, 0x9269, 0xBB5D, 0x926A, 0xBB5E, 0x926B, 0xBB5F, 0x926C, 0xBB60, 0x926D, 0xBB62, 0x926E, 0xBB64, 0x926F, 0xBB65, 0x9270, 0xBB66, 0x9271, 0xBB67, 0x9272, 0xBB68, 0x9273, 0xBB69, 0x9274, 0xBB6A, 0x9275, 0xBB6B, 0x9276, 0xBB6D, 0x9277, 0xBB6E, 0x9278, 0xBB6F, 0x9279, 0xBB70, 0x927A, 0xBB71, 0x9281, 0xBB72, 0x9282, 0xBB73, 0x9283, 0xBB74, 0x9284, 0xBB75, 0x9285, 0xBB76, 0x9286, 0xBB77, 0x9287, 0xBB78, 0x9288, 0xBB79, 0x9289, 0xBB7A, 0x928A, 0xBB7B, 0x928B, 0xBB7C, 0x928C, 0xBB7D, 0x928D, 0xBB7E, 0x928E, 0xBB7F, 0x928F, 0xBB80, 0x9290, 0xBB81, 0x9291, 0xBB82, 0x9292, 0xBB83, 0x9293, 0xBB84, 0x9294, 0xBB85, 0x9295, 0xBB86, 0x9296, 0xBB87, 0x9297, 0xBB89, 0x9298, 0xBB8A, 0x9299, 0xBB8B, 0x929A, 0xBB8D, 0x929B, 0xBB8E, 0x929C, 0xBB8F, 0x929D, 0xBB91, 0x929E, 0xBB92, 0x929F, 0xBB93, 0x92A0, 0xBB94, 0x92A1, 0xBB95, 0x92A2, 0xBB96, 0x92A3, 0xBB97, 0x92A4, 0xBB98, 0x92A5, 0xBB99, 0x92A6, 0xBB9A, 0x92A7, 0xBB9B, 0x92A8, 0xBB9C, 0x92A9, 0xBB9D, 0x92AA, 0xBB9E, 0x92AB, 0xBB9F, 0x92AC, 0xBBA0, 0x92AD, 0xBBA1, 0x92AE, 0xBBA2, 0x92AF, 0xBBA3, 0x92B0, 0xBBA5, 0x92B1, 0xBBA6, 0x92B2, 0xBBA7, 0x92B3, 0xBBA9, 0x92B4, 0xBBAA, 0x92B5, 0xBBAB, 0x92B6, 0xBBAD, 0x92B7, 0xBBAE, 0x92B8, 0xBBAF, 0x92B9, 0xBBB0, 0x92BA, 0xBBB1, 0x92BB, 0xBBB2, 0x92BC, 0xBBB3, 0x92BD, 0xBBB5, 0x92BE, 0xBBB6, 0x92BF, 0xBBB8, 0x92C0, 0xBBB9, 0x92C1, 0xBBBA, 0x92C2, 0xBBBB, 0x92C3, 0xBBBC, 0x92C4, 0xBBBD, 0x92C5, 0xBBBE, 0x92C6, 0xBBBF, 0x92C7, 0xBBC1, 0x92C8, 0xBBC2, 0x92C9, 0xBBC3, 0x92CA, 0xBBC5, 0x92CB, 0xBBC6, 0x92CC, 0xBBC7, 0x92CD, 0xBBC9, 0x92CE, 0xBBCA, 0x92CF, 0xBBCB, 0x92D0, 0xBBCC, 0x92D1, 0xBBCD, 0x92D2, 0xBBCE, 0x92D3, 0xBBCF, 0x92D4, 0xBBD1, 0x92D5, 0xBBD2, 0x92D6, 0xBBD4, 0x92D7, 0xBBD5, 0x92D8, 0xBBD6, 0x92D9, 0xBBD7, 0x92DA, 0xBBD8, 0x92DB, 0xBBD9, 0x92DC, 0xBBDA, 0x92DD, 0xBBDB, 0x92DE, 0xBBDC, 0x92DF, 0xBBDD, 0x92E0, 0xBBDE, 0x92E1, 0xBBDF, 0x92E2, 0xBBE0, 0x92E3, 0xBBE1, 0x92E4, 0xBBE2, 0x92E5, 0xBBE3, 0x92E6, 0xBBE4, 0x92E7, 0xBBE5, 0x92E8, 0xBBE6, 0x92E9, 0xBBE7, 0x92EA, 0xBBE8, 0x92EB, 0xBBE9, 0x92EC, 0xBBEA, 0x92ED, 0xBBEB, 0x92EE, 0xBBEC, 0x92EF, 0xBBED, 0x92F0, 0xBBEE, 0x92F1, 0xBBEF, 0x92F2, 0xBBF0, 0x92F3, 0xBBF1, 0x92F4, 0xBBF2, 0x92F5, 0xBBF3, 0x92F6, 0xBBF4, 0x92F7, 0xBBF5, 0x92F8, 0xBBF6, 0x92F9, 0xBBF7, 0x92FA, 0xBBFA, 0x92FB, 0xBBFB, 0x92FC, 0xBBFD, 0x92FD, 0xBBFE, 0x92FE, 0xBC01, 0x9341, 0xBC03, 0x9342, 0xBC04, 0x9343, 0xBC05, 0x9344, 0xBC06, 0x9345, 0xBC07, 0x9346, 0xBC0A, 0x9347, 0xBC0E, 0x9348, 0xBC10, 0x9349, 0xBC12, 0x934A, 0xBC13, 0x934B, 0xBC19, 0x934C, 0xBC1A, 0x934D, 0xBC20, 0x934E, 0xBC21, 0x934F, 0xBC22, 0x9350, 0xBC23, 0x9351, 0xBC26, 0x9352, 0xBC28, 0x9353, 0xBC2A, 0x9354, 0xBC2B, 0x9355, 0xBC2C, 0x9356, 0xBC2E, 0x9357, 0xBC2F, 0x9358, 0xBC32, 0x9359, 0xBC33, 0x935A, 0xBC35, 0x9361, 0xBC36, 0x9362, 0xBC37, 0x9363, 0xBC39, 0x9364, 0xBC3A, 0x9365, 0xBC3B, 0x9366, 0xBC3C, 0x9367, 0xBC3D, 0x9368, 0xBC3E, 0x9369, 0xBC3F, 0x936A, 0xBC42, 0x936B, 0xBC46, 0x936C, 0xBC47, 0x936D, 0xBC48, 0x936E, 0xBC4A, 0x936F, 0xBC4B, 0x9370, 0xBC4E, 0x9371, 0xBC4F, 0x9372, 0xBC51, 0x9373, 0xBC52, 0x9374, 0xBC53, 0x9375, 0xBC54, 0x9376, 0xBC55, 0x9377, 0xBC56, 0x9378, 0xBC57, 0x9379, 0xBC58, 0x937A, 0xBC59, 0x9381, 0xBC5A, 0x9382, 0xBC5B, 0x9383, 0xBC5C, 0x9384, 0xBC5E, 0x9385, 0xBC5F, 0x9386, 0xBC60, 0x9387, 0xBC61, 0x9388, 0xBC62, 0x9389, 0xBC63, 0x938A, 0xBC64, 0x938B, 0xBC65, 0x938C, 0xBC66, 0x938D, 0xBC67, 0x938E, 0xBC68, 0x938F, 0xBC69, 0x9390, 0xBC6A, 0x9391, 0xBC6B, 0x9392, 0xBC6C, 0x9393, 0xBC6D, 0x9394, 0xBC6E, 0x9395, 0xBC6F, 0x9396, 0xBC70, 0x9397, 0xBC71, 0x9398, 0xBC72, 0x9399, 0xBC73, 0x939A, 0xBC74, 0x939B, 0xBC75, 0x939C, 0xBC76, 0x939D, 0xBC77, 0x939E, 0xBC78, 0x939F, 0xBC79, 0x93A0, 0xBC7A, 0x93A1, 0xBC7B, 0x93A2, 0xBC7C, 0x93A3, 0xBC7D, 0x93A4, 0xBC7E, 0x93A5, 0xBC7F, 0x93A6, 0xBC80, 0x93A7, 0xBC81, 0x93A8, 0xBC82, 0x93A9, 0xBC83, 0x93AA, 0xBC86, 0x93AB, 0xBC87, 0x93AC, 0xBC89, 0x93AD, 0xBC8A, 0x93AE, 0xBC8D, 0x93AF, 0xBC8F, 0x93B0, 0xBC90, 0x93B1, 0xBC91, 0x93B2, 0xBC92, 0x93B3, 0xBC93, 0x93B4, 0xBC96, 0x93B5, 0xBC98, 0x93B6, 0xBC9B, 0x93B7, 0xBC9C, 0x93B8, 0xBC9D, 0x93B9, 0xBC9E, 0x93BA, 0xBC9F, 0x93BB, 0xBCA2, 0x93BC, 0xBCA3, 0x93BD, 0xBCA5, 0x93BE, 0xBCA6, 0x93BF, 0xBCA9, 0x93C0, 0xBCAA, 0x93C1, 0xBCAB, 0x93C2, 0xBCAC, 0x93C3, 0xBCAD, 0x93C4, 0xBCAE, 0x93C5, 0xBCAF, 0x93C6, 0xBCB2, 0x93C7, 0xBCB6, 0x93C8, 0xBCB7, 0x93C9, 0xBCB8, 0x93CA, 0xBCB9, 0x93CB, 0xBCBA, 0x93CC, 0xBCBB, 0x93CD, 0xBCBE, 0x93CE, 0xBCBF, 0x93CF, 0xBCC1, 0x93D0, 0xBCC2, 0x93D1, 0xBCC3, 0x93D2, 0xBCC5, 0x93D3, 0xBCC6, 0x93D4, 0xBCC7, 0x93D5, 0xBCC8, 0x93D6, 0xBCC9, 0x93D7, 0xBCCA, 0x93D8, 0xBCCB, 0x93D9, 0xBCCC, 0x93DA, 0xBCCE, 0x93DB, 0xBCD2, 0x93DC, 0xBCD3, 0x93DD, 0xBCD4, 0x93DE, 0xBCD6, 0x93DF, 0xBCD7, 0x93E0, 0xBCD9, 0x93E1, 0xBCDA, 0x93E2, 0xBCDB, 0x93E3, 0xBCDD, 0x93E4, 0xBCDE, 0x93E5, 0xBCDF, 0x93E6, 0xBCE0, 0x93E7, 0xBCE1, 0x93E8, 0xBCE2, 0x93E9, 0xBCE3, 0x93EA, 0xBCE4, 0x93EB, 0xBCE5, 0x93EC, 0xBCE6, 0x93ED, 0xBCE7, 0x93EE, 0xBCE8, 0x93EF, 0xBCE9, 0x93F0, 0xBCEA, 0x93F1, 0xBCEB, 0x93F2, 0xBCEC, 0x93F3, 0xBCED, 0x93F4, 0xBCEE, 0x93F5, 0xBCEF, 0x93F6, 0xBCF0, 0x93F7, 0xBCF1, 0x93F8, 0xBCF2, 0x93F9, 0xBCF3, 0x93FA, 0xBCF7, 0x93FB, 0xBCF9, 0x93FC, 0xBCFA, 0x93FD, 0xBCFB, 0x93FE, 0xBCFD, 0x9441, 0xBCFE, 0x9442, 0xBCFF, 0x9443, 0xBD00, 0x9444, 0xBD01, 0x9445, 0xBD02, 0x9446, 0xBD03, 0x9447, 0xBD06, 0x9448, 0xBD08, 0x9449, 0xBD0A, 0x944A, 0xBD0B, 0x944B, 0xBD0C, 0x944C, 0xBD0D, 0x944D, 0xBD0E, 0x944E, 0xBD0F, 0x944F, 0xBD11, 0x9450, 0xBD12, 0x9451, 0xBD13, 0x9452, 0xBD15, 0x9453, 0xBD16, 0x9454, 0xBD17, 0x9455, 0xBD18, 0x9456, 0xBD19, 0x9457, 0xBD1A, 0x9458, 0xBD1B, 0x9459, 0xBD1C, 0x945A, 0xBD1D, 0x9461, 0xBD1E, 0x9462, 0xBD1F, 0x9463, 0xBD20, 0x9464, 0xBD21, 0x9465, 0xBD22, 0x9466, 0xBD23, 0x9467, 0xBD25, 0x9468, 0xBD26, 0x9469, 0xBD27, 0x946A, 0xBD28, 0x946B, 0xBD29, 0x946C, 0xBD2A, 0x946D, 0xBD2B, 0x946E, 0xBD2D, 0x946F, 0xBD2E, 0x9470, 0xBD2F, 0x9471, 0xBD30, 0x9472, 0xBD31, 0x9473, 0xBD32, 0x9474, 0xBD33, 0x9475, 0xBD34, 0x9476, 0xBD35, 0x9477, 0xBD36, 0x9478, 0xBD37, 0x9479, 0xBD38, 0x947A, 0xBD39, 0x9481, 0xBD3A, 0x9482, 0xBD3B, 0x9483, 0xBD3C, 0x9484, 0xBD3D, 0x9485, 0xBD3E, 0x9486, 0xBD3F, 0x9487, 0xBD41, 0x9488, 0xBD42, 0x9489, 0xBD43, 0x948A, 0xBD44, 0x948B, 0xBD45, 0x948C, 0xBD46, 0x948D, 0xBD47, 0x948E, 0xBD4A, 0x948F, 0xBD4B, 0x9490, 0xBD4D, 0x9491, 0xBD4E, 0x9492, 0xBD4F, 0x9493, 0xBD51, 0x9494, 0xBD52, 0x9495, 0xBD53, 0x9496, 0xBD54, 0x9497, 0xBD55, 0x9498, 0xBD56, 0x9499, 0xBD57, 0x949A, 0xBD5A, 0x949B, 0xBD5B, 0x949C, 0xBD5C, 0x949D, 0xBD5D, 0x949E, 0xBD5E, 0x949F, 0xBD5F, 0x94A0, 0xBD60, 0x94A1, 0xBD61, 0x94A2, 0xBD62, 0x94A3, 0xBD63, 0x94A4, 0xBD65, 0x94A5, 0xBD66, 0x94A6, 0xBD67, 0x94A7, 0xBD69, 0x94A8, 0xBD6A, 0x94A9, 0xBD6B, 0x94AA, 0xBD6C, 0x94AB, 0xBD6D, 0x94AC, 0xBD6E, 0x94AD, 0xBD6F, 0x94AE, 0xBD70, 0x94AF, 0xBD71, 0x94B0, 0xBD72, 0x94B1, 0xBD73, 0x94B2, 0xBD74, 0x94B3, 0xBD75, 0x94B4, 0xBD76, 0x94B5, 0xBD77, 0x94B6, 0xBD78, 0x94B7, 0xBD79, 0x94B8, 0xBD7A, 0x94B9, 0xBD7B, 0x94BA, 0xBD7C, 0x94BB, 0xBD7D, 0x94BC, 0xBD7E, 0x94BD, 0xBD7F, 0x94BE, 0xBD82, 0x94BF, 0xBD83, 0x94C0, 0xBD85, 0x94C1, 0xBD86, 0x94C2, 0xBD8B, 0x94C3, 0xBD8C, 0x94C4, 0xBD8D, 0x94C5, 0xBD8E, 0x94C6, 0xBD8F, 0x94C7, 0xBD92, 0x94C8, 0xBD94, 0x94C9, 0xBD96, 0x94CA, 0xBD97, 0x94CB, 0xBD98, 0x94CC, 0xBD9B, 0x94CD, 0xBD9D, 0x94CE, 0xBD9E, 0x94CF, 0xBD9F, 0x94D0, 0xBDA0, 0x94D1, 0xBDA1, 0x94D2, 0xBDA2, 0x94D3, 0xBDA3, 0x94D4, 0xBDA5, 0x94D5, 0xBDA6, 0x94D6, 0xBDA7, 0x94D7, 0xBDA8, 0x94D8, 0xBDA9, 0x94D9, 0xBDAA, 0x94DA, 0xBDAB, 0x94DB, 0xBDAC, 0x94DC, 0xBDAD, 0x94DD, 0xBDAE, 0x94DE, 0xBDAF, 0x94DF, 0xBDB1, 0x94E0, 0xBDB2, 0x94E1, 0xBDB3, 0x94E2, 0xBDB4, 0x94E3, 0xBDB5, 0x94E4, 0xBDB6, 0x94E5, 0xBDB7, 0x94E6, 0xBDB9, 0x94E7, 0xBDBA, 0x94E8, 0xBDBB, 0x94E9, 0xBDBC, 0x94EA, 0xBDBD, 0x94EB, 0xBDBE, 0x94EC, 0xBDBF, 0x94ED, 0xBDC0, 0x94EE, 0xBDC1, 0x94EF, 0xBDC2, 0x94F0, 0xBDC3, 0x94F1, 0xBDC4, 0x94F2, 0xBDC5, 0x94F3, 0xBDC6, 0x94F4, 0xBDC7, 0x94F5, 0xBDC8, 0x94F6, 0xBDC9, 0x94F7, 0xBDCA, 0x94F8, 0xBDCB, 0x94F9, 0xBDCC, 0x94FA, 0xBDCD, 0x94FB, 0xBDCE, 0x94FC, 0xBDCF, 0x94FD, 0xBDD0, 0x94FE, 0xBDD1, 0x9541, 0xBDD2, 0x9542, 0xBDD3, 0x9543, 0xBDD6, 0x9544, 0xBDD7, 0x9545, 0xBDD9, 0x9546, 0xBDDA, 0x9547, 0xBDDB, 0x9548, 0xBDDD, 0x9549, 0xBDDE, 0x954A, 0xBDDF, 0x954B, 0xBDE0, 0x954C, 0xBDE1, 0x954D, 0xBDE2, 0x954E, 0xBDE3, 0x954F, 0xBDE4, 0x9550, 0xBDE5, 0x9551, 0xBDE6, 0x9552, 0xBDE7, 0x9553, 0xBDE8, 0x9554, 0xBDEA, 0x9555, 0xBDEB, 0x9556, 0xBDEC, 0x9557, 0xBDED, 0x9558, 0xBDEE, 0x9559, 0xBDEF, 0x955A, 0xBDF1, 0x9561, 0xBDF2, 0x9562, 0xBDF3, 0x9563, 0xBDF5, 0x9564, 0xBDF6, 0x9565, 0xBDF7, 0x9566, 0xBDF9, 0x9567, 0xBDFA, 0x9568, 0xBDFB, 0x9569, 0xBDFC, 0x956A, 0xBDFD, 0x956B, 0xBDFE, 0x956C, 0xBDFF, 0x956D, 0xBE01, 0x956E, 0xBE02, 0x956F, 0xBE04, 0x9570, 0xBE06, 0x9571, 0xBE07, 0x9572, 0xBE08, 0x9573, 0xBE09, 0x9574, 0xBE0A, 0x9575, 0xBE0B, 0x9576, 0xBE0E, 0x9577, 0xBE0F, 0x9578, 0xBE11, 0x9579, 0xBE12, 0x957A, 0xBE13, 0x9581, 0xBE15, 0x9582, 0xBE16, 0x9583, 0xBE17, 0x9584, 0xBE18, 0x9585, 0xBE19, 0x9586, 0xBE1A, 0x9587, 0xBE1B, 0x9588, 0xBE1E, 0x9589, 0xBE20, 0x958A, 0xBE21, 0x958B, 0xBE22, 0x958C, 0xBE23, 0x958D, 0xBE24, 0x958E, 0xBE25, 0x958F, 0xBE26, 0x9590, 0xBE27, 0x9591, 0xBE28, 0x9592, 0xBE29, 0x9593, 0xBE2A, 0x9594, 0xBE2B, 0x9595, 0xBE2C, 0x9596, 0xBE2D, 0x9597, 0xBE2E, 0x9598, 0xBE2F, 0x9599, 0xBE30, 0x959A, 0xBE31, 0x959B, 0xBE32, 0x959C, 0xBE33, 0x959D, 0xBE34, 0x959E, 0xBE35, 0x959F, 0xBE36, 0x95A0, 0xBE37, 0x95A1, 0xBE38, 0x95A2, 0xBE39, 0x95A3, 0xBE3A, 0x95A4, 0xBE3B, 0x95A5, 0xBE3C, 0x95A6, 0xBE3D, 0x95A7, 0xBE3E, 0x95A8, 0xBE3F, 0x95A9, 0xBE40, 0x95AA, 0xBE41, 0x95AB, 0xBE42, 0x95AC, 0xBE43, 0x95AD, 0xBE46, 0x95AE, 0xBE47, 0x95AF, 0xBE49, 0x95B0, 0xBE4A, 0x95B1, 0xBE4B, 0x95B2, 0xBE4D, 0x95B3, 0xBE4F, 0x95B4, 0xBE50, 0x95B5, 0xBE51, 0x95B6, 0xBE52, 0x95B7, 0xBE53, 0x95B8, 0xBE56, 0x95B9, 0xBE58, 0x95BA, 0xBE5C, 0x95BB, 0xBE5D, 0x95BC, 0xBE5E, 0x95BD, 0xBE5F, 0x95BE, 0xBE62, 0x95BF, 0xBE63, 0x95C0, 0xBE65, 0x95C1, 0xBE66, 0x95C2, 0xBE67, 0x95C3, 0xBE69, 0x95C4, 0xBE6B, 0x95C5, 0xBE6C, 0x95C6, 0xBE6D, 0x95C7, 0xBE6E, 0x95C8, 0xBE6F, 0x95C9, 0xBE72, 0x95CA, 0xBE76, 0x95CB, 0xBE77, 0x95CC, 0xBE78, 0x95CD, 0xBE79, 0x95CE, 0xBE7A, 0x95CF, 0xBE7E, 0x95D0, 0xBE7F, 0x95D1, 0xBE81, 0x95D2, 0xBE82, 0x95D3, 0xBE83, 0x95D4, 0xBE85, 0x95D5, 0xBE86, 0x95D6, 0xBE87, 0x95D7, 0xBE88, 0x95D8, 0xBE89, 0x95D9, 0xBE8A, 0x95DA, 0xBE8B, 0x95DB, 0xBE8E, 0x95DC, 0xBE92, 0x95DD, 0xBE93, 0x95DE, 0xBE94, 0x95DF, 0xBE95, 0x95E0, 0xBE96, 0x95E1, 0xBE97, 0x95E2, 0xBE9A, 0x95E3, 0xBE9B, 0x95E4, 0xBE9C, 0x95E5, 0xBE9D, 0x95E6, 0xBE9E, 0x95E7, 0xBE9F, 0x95E8, 0xBEA0, 0x95E9, 0xBEA1, 0x95EA, 0xBEA2, 0x95EB, 0xBEA3, 0x95EC, 0xBEA4, 0x95ED, 0xBEA5, 0x95EE, 0xBEA6, 0x95EF, 0xBEA7, 0x95F0, 0xBEA9, 0x95F1, 0xBEAA, 0x95F2, 0xBEAB, 0x95F3, 0xBEAC, 0x95F4, 0xBEAD, 0x95F5, 0xBEAE, 0x95F6, 0xBEAF, 0x95F7, 0xBEB0, 0x95F8, 0xBEB1, 0x95F9, 0xBEB2, 0x95FA, 0xBEB3, 0x95FB, 0xBEB4, 0x95FC, 0xBEB5, 0x95FD, 0xBEB6, 0x95FE, 0xBEB7, 0x9641, 0xBEB8, 0x9642, 0xBEB9, 0x9643, 0xBEBA, 0x9644, 0xBEBB, 0x9645, 0xBEBC, 0x9646, 0xBEBD, 0x9647, 0xBEBE, 0x9648, 0xBEBF, 0x9649, 0xBEC0, 0x964A, 0xBEC1, 0x964B, 0xBEC2, 0x964C, 0xBEC3, 0x964D, 0xBEC4, 0x964E, 0xBEC5, 0x964F, 0xBEC6, 0x9650, 0xBEC7, 0x9651, 0xBEC8, 0x9652, 0xBEC9, 0x9653, 0xBECA, 0x9654, 0xBECB, 0x9655, 0xBECC, 0x9656, 0xBECD, 0x9657, 0xBECE, 0x9658, 0xBECF, 0x9659, 0xBED2, 0x965A, 0xBED3, 0x9661, 0xBED5, 0x9662, 0xBED6, 0x9663, 0xBED9, 0x9664, 0xBEDA, 0x9665, 0xBEDB, 0x9666, 0xBEDC, 0x9667, 0xBEDD, 0x9668, 0xBEDE, 0x9669, 0xBEDF, 0x966A, 0xBEE1, 0x966B, 0xBEE2, 0x966C, 0xBEE6, 0x966D, 0xBEE7, 0x966E, 0xBEE8, 0x966F, 0xBEE9, 0x9670, 0xBEEA, 0x9671, 0xBEEB, 0x9672, 0xBEED, 0x9673, 0xBEEE, 0x9674, 0xBEEF, 0x9675, 0xBEF0, 0x9676, 0xBEF1, 0x9677, 0xBEF2, 0x9678, 0xBEF3, 0x9679, 0xBEF4, 0x967A, 0xBEF5, 0x9681, 0xBEF6, 0x9682, 0xBEF7, 0x9683, 0xBEF8, 0x9684, 0xBEF9, 0x9685, 0xBEFA, 0x9686, 0xBEFB, 0x9687, 0xBEFC, 0x9688, 0xBEFD, 0x9689, 0xBEFE, 0x968A, 0xBEFF, 0x968B, 0xBF00, 0x968C, 0xBF02, 0x968D, 0xBF03, 0x968E, 0xBF04, 0x968F, 0xBF05, 0x9690, 0xBF06, 0x9691, 0xBF07, 0x9692, 0xBF0A, 0x9693, 0xBF0B, 0x9694, 0xBF0C, 0x9695, 0xBF0D, 0x9696, 0xBF0E, 0x9697, 0xBF0F, 0x9698, 0xBF10, 0x9699, 0xBF11, 0x969A, 0xBF12, 0x969B, 0xBF13, 0x969C, 0xBF14, 0x969D, 0xBF15, 0x969E, 0xBF16, 0x969F, 0xBF17, 0x96A0, 0xBF1A, 0x96A1, 0xBF1E, 0x96A2, 0xBF1F, 0x96A3, 0xBF20, 0x96A4, 0xBF21, 0x96A5, 0xBF22, 0x96A6, 0xBF23, 0x96A7, 0xBF24, 0x96A8, 0xBF25, 0x96A9, 0xBF26, 0x96AA, 0xBF27, 0x96AB, 0xBF28, 0x96AC, 0xBF29, 0x96AD, 0xBF2A, 0x96AE, 0xBF2B, 0x96AF, 0xBF2C, 0x96B0, 0xBF2D, 0x96B1, 0xBF2E, 0x96B2, 0xBF2F, 0x96B3, 0xBF30, 0x96B4, 0xBF31, 0x96B5, 0xBF32, 0x96B6, 0xBF33, 0x96B7, 0xBF34, 0x96B8, 0xBF35, 0x96B9, 0xBF36, 0x96BA, 0xBF37, 0x96BB, 0xBF38, 0x96BC, 0xBF39, 0x96BD, 0xBF3A, 0x96BE, 0xBF3B, 0x96BF, 0xBF3C, 0x96C0, 0xBF3D, 0x96C1, 0xBF3E, 0x96C2, 0xBF3F, 0x96C3, 0xBF42, 0x96C4, 0xBF43, 0x96C5, 0xBF45, 0x96C6, 0xBF46, 0x96C7, 0xBF47, 0x96C8, 0xBF49, 0x96C9, 0xBF4A, 0x96CA, 0xBF4B, 0x96CB, 0xBF4C, 0x96CC, 0xBF4D, 0x96CD, 0xBF4E, 0x96CE, 0xBF4F, 0x96CF, 0xBF52, 0x96D0, 0xBF53, 0x96D1, 0xBF54, 0x96D2, 0xBF56, 0x96D3, 0xBF57, 0x96D4, 0xBF58, 0x96D5, 0xBF59, 0x96D6, 0xBF5A, 0x96D7, 0xBF5B, 0x96D8, 0xBF5C, 0x96D9, 0xBF5D, 0x96DA, 0xBF5E, 0x96DB, 0xBF5F, 0x96DC, 0xBF60, 0x96DD, 0xBF61, 0x96DE, 0xBF62, 0x96DF, 0xBF63, 0x96E0, 0xBF64, 0x96E1, 0xBF65, 0x96E2, 0xBF66, 0x96E3, 0xBF67, 0x96E4, 0xBF68, 0x96E5, 0xBF69, 0x96E6, 0xBF6A, 0x96E7, 0xBF6B, 0x96E8, 0xBF6C, 0x96E9, 0xBF6D, 0x96EA, 0xBF6E, 0x96EB, 0xBF6F, 0x96EC, 0xBF70, 0x96ED, 0xBF71, 0x96EE, 0xBF72, 0x96EF, 0xBF73, 0x96F0, 0xBF74, 0x96F1, 0xBF75, 0x96F2, 0xBF76, 0x96F3, 0xBF77, 0x96F4, 0xBF78, 0x96F5, 0xBF79, 0x96F6, 0xBF7A, 0x96F7, 0xBF7B, 0x96F8, 0xBF7C, 0x96F9, 0xBF7D, 0x96FA, 0xBF7E, 0x96FB, 0xBF7F, 0x96FC, 0xBF80, 0x96FD, 0xBF81, 0x96FE, 0xBF82, 0x9741, 0xBF83, 0x9742, 0xBF84, 0x9743, 0xBF85, 0x9744, 0xBF86, 0x9745, 0xBF87, 0x9746, 0xBF88, 0x9747, 0xBF89, 0x9748, 0xBF8A, 0x9749, 0xBF8B, 0x974A, 0xBF8C, 0x974B, 0xBF8D, 0x974C, 0xBF8E, 0x974D, 0xBF8F, 0x974E, 0xBF90, 0x974F, 0xBF91, 0x9750, 0xBF92, 0x9751, 0xBF93, 0x9752, 0xBF95, 0x9753, 0xBF96, 0x9754, 0xBF97, 0x9755, 0xBF98, 0x9756, 0xBF99, 0x9757, 0xBF9A, 0x9758, 0xBF9B, 0x9759, 0xBF9C, 0x975A, 0xBF9D, 0x9761, 0xBF9E, 0x9762, 0xBF9F, 0x9763, 0xBFA0, 0x9764, 0xBFA1, 0x9765, 0xBFA2, 0x9766, 0xBFA3, 0x9767, 0xBFA4, 0x9768, 0xBFA5, 0x9769, 0xBFA6, 0x976A, 0xBFA7, 0x976B, 0xBFA8, 0x976C, 0xBFA9, 0x976D, 0xBFAA, 0x976E, 0xBFAB, 0x976F, 0xBFAC, 0x9770, 0xBFAD, 0x9771, 0xBFAE, 0x9772, 0xBFAF, 0x9773, 0xBFB1, 0x9774, 0xBFB2, 0x9775, 0xBFB3, 0x9776, 0xBFB4, 0x9777, 0xBFB5, 0x9778, 0xBFB6, 0x9779, 0xBFB7, 0x977A, 0xBFB8, 0x9781, 0xBFB9, 0x9782, 0xBFBA, 0x9783, 0xBFBB, 0x9784, 0xBFBC, 0x9785, 0xBFBD, 0x9786, 0xBFBE, 0x9787, 0xBFBF, 0x9788, 0xBFC0, 0x9789, 0xBFC1, 0x978A, 0xBFC2, 0x978B, 0xBFC3, 0x978C, 0xBFC4, 0x978D, 0xBFC6, 0x978E, 0xBFC7, 0x978F, 0xBFC8, 0x9790, 0xBFC9, 0x9791, 0xBFCA, 0x9792, 0xBFCB, 0x9793, 0xBFCE, 0x9794, 0xBFCF, 0x9795, 0xBFD1, 0x9796, 0xBFD2, 0x9797, 0xBFD3, 0x9798, 0xBFD5, 0x9799, 0xBFD6, 0x979A, 0xBFD7, 0x979B, 0xBFD8, 0x979C, 0xBFD9, 0x979D, 0xBFDA, 0x979E, 0xBFDB, 0x979F, 0xBFDD, 0x97A0, 0xBFDE, 0x97A1, 0xBFE0, 0x97A2, 0xBFE2, 0x97A3, 0xBFE3, 0x97A4, 0xBFE4, 0x97A5, 0xBFE5, 0x97A6, 0xBFE6, 0x97A7, 0xBFE7, 0x97A8, 0xBFE8, 0x97A9, 0xBFE9, 0x97AA, 0xBFEA, 0x97AB, 0xBFEB, 0x97AC, 0xBFEC, 0x97AD, 0xBFED, 0x97AE, 0xBFEE, 0x97AF, 0xBFEF, 0x97B0, 0xBFF0, 0x97B1, 0xBFF1, 0x97B2, 0xBFF2, 0x97B3, 0xBFF3, 0x97B4, 0xBFF4, 0x97B5, 0xBFF5, 0x97B6, 0xBFF6, 0x97B7, 0xBFF7, 0x97B8, 0xBFF8, 0x97B9, 0xBFF9, 0x97BA, 0xBFFA, 0x97BB, 0xBFFB, 0x97BC, 0xBFFC, 0x97BD, 0xBFFD, 0x97BE, 0xBFFE, 0x97BF, 0xBFFF, 0x97C0, 0xC000, 0x97C1, 0xC001, 0x97C2, 0xC002, 0x97C3, 0xC003, 0x97C4, 0xC004, 0x97C5, 0xC005, 0x97C6, 0xC006, 0x97C7, 0xC007, 0x97C8, 0xC008, 0x97C9, 0xC009, 0x97CA, 0xC00A, 0x97CB, 0xC00B, 0x97CC, 0xC00C, 0x97CD, 0xC00D, 0x97CE, 0xC00E, 0x97CF, 0xC00F, 0x97D0, 0xC010, 0x97D1, 0xC011, 0x97D2, 0xC012, 0x97D3, 0xC013, 0x97D4, 0xC014, 0x97D5, 0xC015, 0x97D6, 0xC016, 0x97D7, 0xC017, 0x97D8, 0xC018, 0x97D9, 0xC019, 0x97DA, 0xC01A, 0x97DB, 0xC01B, 0x97DC, 0xC01C, 0x97DD, 0xC01D, 0x97DE, 0xC01E, 0x97DF, 0xC01F, 0x97E0, 0xC020, 0x97E1, 0xC021, 0x97E2, 0xC022, 0x97E3, 0xC023, 0x97E4, 0xC024, 0x97E5, 0xC025, 0x97E6, 0xC026, 0x97E7, 0xC027, 0x97E8, 0xC028, 0x97E9, 0xC029, 0x97EA, 0xC02A, 0x97EB, 0xC02B, 0x97EC, 0xC02C, 0x97ED, 0xC02D, 0x97EE, 0xC02E, 0x97EF, 0xC02F, 0x97F0, 0xC030, 0x97F1, 0xC031, 0x97F2, 0xC032, 0x97F3, 0xC033, 0x97F4, 0xC034, 0x97F5, 0xC035, 0x97F6, 0xC036, 0x97F7, 0xC037, 0x97F8, 0xC038, 0x97F9, 0xC039, 0x97FA, 0xC03A, 0x97FB, 0xC03B, 0x97FC, 0xC03D, 0x97FD, 0xC03E, 0x97FE, 0xC03F, 0x9841, 0xC040, 0x9842, 0xC041, 0x9843, 0xC042, 0x9844, 0xC043, 0x9845, 0xC044, 0x9846, 0xC045, 0x9847, 0xC046, 0x9848, 0xC047, 0x9849, 0xC048, 0x984A, 0xC049, 0x984B, 0xC04A, 0x984C, 0xC04B, 0x984D, 0xC04C, 0x984E, 0xC04D, 0x984F, 0xC04E, 0x9850, 0xC04F, 0x9851, 0xC050, 0x9852, 0xC052, 0x9853, 0xC053, 0x9854, 0xC054, 0x9855, 0xC055, 0x9856, 0xC056, 0x9857, 0xC057, 0x9858, 0xC059, 0x9859, 0xC05A, 0x985A, 0xC05B, 0x9861, 0xC05D, 0x9862, 0xC05E, 0x9863, 0xC05F, 0x9864, 0xC061, 0x9865, 0xC062, 0x9866, 0xC063, 0x9867, 0xC064, 0x9868, 0xC065, 0x9869, 0xC066, 0x986A, 0xC067, 0x986B, 0xC06A, 0x986C, 0xC06B, 0x986D, 0xC06C, 0x986E, 0xC06D, 0x986F, 0xC06E, 0x9870, 0xC06F, 0x9871, 0xC070, 0x9872, 0xC071, 0x9873, 0xC072, 0x9874, 0xC073, 0x9875, 0xC074, 0x9876, 0xC075, 0x9877, 0xC076, 0x9878, 0xC077, 0x9879, 0xC078, 0x987A, 0xC079, 0x9881, 0xC07A, 0x9882, 0xC07B, 0x9883, 0xC07C, 0x9884, 0xC07D, 0x9885, 0xC07E, 0x9886, 0xC07F, 0x9887, 0xC080, 0x9888, 0xC081, 0x9889, 0xC082, 0x988A, 0xC083, 0x988B, 0xC084, 0x988C, 0xC085, 0x988D, 0xC086, 0x988E, 0xC087, 0x988F, 0xC088, 0x9890, 0xC089, 0x9891, 0xC08A, 0x9892, 0xC08B, 0x9893, 0xC08C, 0x9894, 0xC08D, 0x9895, 0xC08E, 0x9896, 0xC08F, 0x9897, 0xC092, 0x9898, 0xC093, 0x9899, 0xC095, 0x989A, 0xC096, 0x989B, 0xC097, 0x989C, 0xC099, 0x989D, 0xC09A, 0x989E, 0xC09B, 0x989F, 0xC09C, 0x98A0, 0xC09D, 0x98A1, 0xC09E, 0x98A2, 0xC09F, 0x98A3, 0xC0A2, 0x98A4, 0xC0A4, 0x98A5, 0xC0A6, 0x98A6, 0xC0A7, 0x98A7, 0xC0A8, 0x98A8, 0xC0A9, 0x98A9, 0xC0AA, 0x98AA, 0xC0AB, 0x98AB, 0xC0AE, 0x98AC, 0xC0B1, 0x98AD, 0xC0B2, 0x98AE, 0xC0B7, 0x98AF, 0xC0B8, 0x98B0, 0xC0B9, 0x98B1, 0xC0BA, 0x98B2, 0xC0BB, 0x98B3, 0xC0BE, 0x98B4, 0xC0C2, 0x98B5, 0xC0C3, 0x98B6, 0xC0C4, 0x98B7, 0xC0C6, 0x98B8, 0xC0C7, 0x98B9, 0xC0CA, 0x98BA, 0xC0CB, 0x98BB, 0xC0CD, 0x98BC, 0xC0CE, 0x98BD, 0xC0CF, 0x98BE, 0xC0D1, 0x98BF, 0xC0D2, 0x98C0, 0xC0D3, 0x98C1, 0xC0D4, 0x98C2, 0xC0D5, 0x98C3, 0xC0D6, 0x98C4, 0xC0D7, 0x98C5, 0xC0DA, 0x98C6, 0xC0DE, 0x98C7, 0xC0DF, 0x98C8, 0xC0E0, 0x98C9, 0xC0E1, 0x98CA, 0xC0E2, 0x98CB, 0xC0E3, 0x98CC, 0xC0E6, 0x98CD, 0xC0E7, 0x98CE, 0xC0E9, 0x98CF, 0xC0EA, 0x98D0, 0xC0EB, 0x98D1, 0xC0ED, 0x98D2, 0xC0EE, 0x98D3, 0xC0EF, 0x98D4, 0xC0F0, 0x98D5, 0xC0F1, 0x98D6, 0xC0F2, 0x98D7, 0xC0F3, 0x98D8, 0xC0F6, 0x98D9, 0xC0F8, 0x98DA, 0xC0FA, 0x98DB, 0xC0FB, 0x98DC, 0xC0FC, 0x98DD, 0xC0FD, 0x98DE, 0xC0FE, 0x98DF, 0xC0FF, 0x98E0, 0xC101, 0x98E1, 0xC102, 0x98E2, 0xC103, 0x98E3, 0xC105, 0x98E4, 0xC106, 0x98E5, 0xC107, 0x98E6, 0xC109, 0x98E7, 0xC10A, 0x98E8, 0xC10B, 0x98E9, 0xC10C, 0x98EA, 0xC10D, 0x98EB, 0xC10E, 0x98EC, 0xC10F, 0x98ED, 0xC111, 0x98EE, 0xC112, 0x98EF, 0xC113, 0x98F0, 0xC114, 0x98F1, 0xC116, 0x98F2, 0xC117, 0x98F3, 0xC118, 0x98F4, 0xC119, 0x98F5, 0xC11A, 0x98F6, 0xC11B, 0x98F7, 0xC121, 0x98F8, 0xC122, 0x98F9, 0xC125, 0x98FA, 0xC128, 0x98FB, 0xC129, 0x98FC, 0xC12A, 0x98FD, 0xC12B, 0x98FE, 0xC12E, 0x9941, 0xC132, 0x9942, 0xC133, 0x9943, 0xC134, 0x9944, 0xC135, 0x9945, 0xC137, 0x9946, 0xC13A, 0x9947, 0xC13B, 0x9948, 0xC13D, 0x9949, 0xC13E, 0x994A, 0xC13F, 0x994B, 0xC141, 0x994C, 0xC142, 0x994D, 0xC143, 0x994E, 0xC144, 0x994F, 0xC145, 0x9950, 0xC146, 0x9951, 0xC147, 0x9952, 0xC14A, 0x9953, 0xC14E, 0x9954, 0xC14F, 0x9955, 0xC150, 0x9956, 0xC151, 0x9957, 0xC152, 0x9958, 0xC153, 0x9959, 0xC156, 0x995A, 0xC157, 0x9961, 0xC159, 0x9962, 0xC15A, 0x9963, 0xC15B, 0x9964, 0xC15D, 0x9965, 0xC15E, 0x9966, 0xC15F, 0x9967, 0xC160, 0x9968, 0xC161, 0x9969, 0xC162, 0x996A, 0xC163, 0x996B, 0xC166, 0x996C, 0xC16A, 0x996D, 0xC16B, 0x996E, 0xC16C, 0x996F, 0xC16D, 0x9970, 0xC16E, 0x9971, 0xC16F, 0x9972, 0xC171, 0x9973, 0xC172, 0x9974, 0xC173, 0x9975, 0xC175, 0x9976, 0xC176, 0x9977, 0xC177, 0x9978, 0xC179, 0x9979, 0xC17A, 0x997A, 0xC17B, 0x9981, 0xC17C, 0x9982, 0xC17D, 0x9983, 0xC17E, 0x9984, 0xC17F, 0x9985, 0xC180, 0x9986, 0xC181, 0x9987, 0xC182, 0x9988, 0xC183, 0x9989, 0xC184, 0x998A, 0xC186, 0x998B, 0xC187, 0x998C, 0xC188, 0x998D, 0xC189, 0x998E, 0xC18A, 0x998F, 0xC18B, 0x9990, 0xC18F, 0x9991, 0xC191, 0x9992, 0xC192, 0x9993, 0xC193, 0x9994, 0xC195, 0x9995, 0xC197, 0x9996, 0xC198, 0x9997, 0xC199, 0x9998, 0xC19A, 0x9999, 0xC19B, 0x999A, 0xC19E, 0x999B, 0xC1A0, 0x999C, 0xC1A2, 0x999D, 0xC1A3, 0x999E, 0xC1A4, 0x999F, 0xC1A6, 0x99A0, 0xC1A7, 0x99A1, 0xC1AA, 0x99A2, 0xC1AB, 0x99A3, 0xC1AD, 0x99A4, 0xC1AE, 0x99A5, 0xC1AF, 0x99A6, 0xC1B1, 0x99A7, 0xC1B2, 0x99A8, 0xC1B3, 0x99A9, 0xC1B4, 0x99AA, 0xC1B5, 0x99AB, 0xC1B6, 0x99AC, 0xC1B7, 0x99AD, 0xC1B8, 0x99AE, 0xC1B9, 0x99AF, 0xC1BA, 0x99B0, 0xC1BB, 0x99B1, 0xC1BC, 0x99B2, 0xC1BE, 0x99B3, 0xC1BF, 0x99B4, 0xC1C0, 0x99B5, 0xC1C1, 0x99B6, 0xC1C2, 0x99B7, 0xC1C3, 0x99B8, 0xC1C5, 0x99B9, 0xC1C6, 0x99BA, 0xC1C7, 0x99BB, 0xC1C9, 0x99BC, 0xC1CA, 0x99BD, 0xC1CB, 0x99BE, 0xC1CD, 0x99BF, 0xC1CE, 0x99C0, 0xC1CF, 0x99C1, 0xC1D0, 0x99C2, 0xC1D1, 0x99C3, 0xC1D2, 0x99C4, 0xC1D3, 0x99C5, 0xC1D5, 0x99C6, 0xC1D6, 0x99C7, 0xC1D9, 0x99C8, 0xC1DA, 0x99C9, 0xC1DB, 0x99CA, 0xC1DC, 0x99CB, 0xC1DD, 0x99CC, 0xC1DE, 0x99CD, 0xC1DF, 0x99CE, 0xC1E1, 0x99CF, 0xC1E2, 0x99D0, 0xC1E3, 0x99D1, 0xC1E5, 0x99D2, 0xC1E6, 0x99D3, 0xC1E7, 0x99D4, 0xC1E9, 0x99D5, 0xC1EA, 0x99D6, 0xC1EB, 0x99D7, 0xC1EC, 0x99D8, 0xC1ED, 0x99D9, 0xC1EE, 0x99DA, 0xC1EF, 0x99DB, 0xC1F2, 0x99DC, 0xC1F4, 0x99DD, 0xC1F5, 0x99DE, 0xC1F6, 0x99DF, 0xC1F7, 0x99E0, 0xC1F8, 0x99E1, 0xC1F9, 0x99E2, 0xC1FA, 0x99E3, 0xC1FB, 0x99E4, 0xC1FE, 0x99E5, 0xC1FF, 0x99E6, 0xC201, 0x99E7, 0xC202, 0x99E8, 0xC203, 0x99E9, 0xC205, 0x99EA, 0xC206, 0x99EB, 0xC207, 0x99EC, 0xC208, 0x99ED, 0xC209, 0x99EE, 0xC20A, 0x99EF, 0xC20B, 0x99F0, 0xC20E, 0x99F1, 0xC210, 0x99F2, 0xC212, 0x99F3, 0xC213, 0x99F4, 0xC214, 0x99F5, 0xC215, 0x99F6, 0xC216, 0x99F7, 0xC217, 0x99F8, 0xC21A, 0x99F9, 0xC21B, 0x99FA, 0xC21D, 0x99FB, 0xC21E, 0x99FC, 0xC221, 0x99FD, 0xC222, 0x99FE, 0xC223, 0x9A41, 0xC224, 0x9A42, 0xC225, 0x9A43, 0xC226, 0x9A44, 0xC227, 0x9A45, 0xC22A, 0x9A46, 0xC22C, 0x9A47, 0xC22E, 0x9A48, 0xC230, 0x9A49, 0xC233, 0x9A4A, 0xC235, 0x9A4B, 0xC236, 0x9A4C, 0xC237, 0x9A4D, 0xC238, 0x9A4E, 0xC239, 0x9A4F, 0xC23A, 0x9A50, 0xC23B, 0x9A51, 0xC23C, 0x9A52, 0xC23D, 0x9A53, 0xC23E, 0x9A54, 0xC23F, 0x9A55, 0xC240, 0x9A56, 0xC241, 0x9A57, 0xC242, 0x9A58, 0xC243, 0x9A59, 0xC244, 0x9A5A, 0xC245, 0x9A61, 0xC246, 0x9A62, 0xC247, 0x9A63, 0xC249, 0x9A64, 0xC24A, 0x9A65, 0xC24B, 0x9A66, 0xC24C, 0x9A67, 0xC24D, 0x9A68, 0xC24E, 0x9A69, 0xC24F, 0x9A6A, 0xC252, 0x9A6B, 0xC253, 0x9A6C, 0xC255, 0x9A6D, 0xC256, 0x9A6E, 0xC257, 0x9A6F, 0xC259, 0x9A70, 0xC25A, 0x9A71, 0xC25B, 0x9A72, 0xC25C, 0x9A73, 0xC25D, 0x9A74, 0xC25E, 0x9A75, 0xC25F, 0x9A76, 0xC261, 0x9A77, 0xC262, 0x9A78, 0xC263, 0x9A79, 0xC264, 0x9A7A, 0xC266, 0x9A81, 0xC267, 0x9A82, 0xC268, 0x9A83, 0xC269, 0x9A84, 0xC26A, 0x9A85, 0xC26B, 0x9A86, 0xC26E, 0x9A87, 0xC26F, 0x9A88, 0xC271, 0x9A89, 0xC272, 0x9A8A, 0xC273, 0x9A8B, 0xC275, 0x9A8C, 0xC276, 0x9A8D, 0xC277, 0x9A8E, 0xC278, 0x9A8F, 0xC279, 0x9A90, 0xC27A, 0x9A91, 0xC27B, 0x9A92, 0xC27E, 0x9A93, 0xC280, 0x9A94, 0xC282, 0x9A95, 0xC283, 0x9A96, 0xC284, 0x9A97, 0xC285, 0x9A98, 0xC286, 0x9A99, 0xC287, 0x9A9A, 0xC28A, 0x9A9B, 0xC28B, 0x9A9C, 0xC28C, 0x9A9D, 0xC28D, 0x9A9E, 0xC28E, 0x9A9F, 0xC28F, 0x9AA0, 0xC291, 0x9AA1, 0xC292, 0x9AA2, 0xC293, 0x9AA3, 0xC294, 0x9AA4, 0xC295, 0x9AA5, 0xC296, 0x9AA6, 0xC297, 0x9AA7, 0xC299, 0x9AA8, 0xC29A, 0x9AA9, 0xC29C, 0x9AAA, 0xC29E, 0x9AAB, 0xC29F, 0x9AAC, 0xC2A0, 0x9AAD, 0xC2A1, 0x9AAE, 0xC2A2, 0x9AAF, 0xC2A3, 0x9AB0, 0xC2A6, 0x9AB1, 0xC2A7, 0x9AB2, 0xC2A9, 0x9AB3, 0xC2AA, 0x9AB4, 0xC2AB, 0x9AB5, 0xC2AE, 0x9AB6, 0xC2AF, 0x9AB7, 0xC2B0, 0x9AB8, 0xC2B1, 0x9AB9, 0xC2B2, 0x9ABA, 0xC2B3, 0x9ABB, 0xC2B6, 0x9ABC, 0xC2B8, 0x9ABD, 0xC2BA, 0x9ABE, 0xC2BB, 0x9ABF, 0xC2BC, 0x9AC0, 0xC2BD, 0x9AC1, 0xC2BE, 0x9AC2, 0xC2BF, 0x9AC3, 0xC2C0, 0x9AC4, 0xC2C1, 0x9AC5, 0xC2C2, 0x9AC6, 0xC2C3, 0x9AC7, 0xC2C4, 0x9AC8, 0xC2C5, 0x9AC9, 0xC2C6, 0x9ACA, 0xC2C7, 0x9ACB, 0xC2C8, 0x9ACC, 0xC2C9, 0x9ACD, 0xC2CA, 0x9ACE, 0xC2CB, 0x9ACF, 0xC2CC, 0x9AD0, 0xC2CD, 0x9AD1, 0xC2CE, 0x9AD2, 0xC2CF, 0x9AD3, 0xC2D0, 0x9AD4, 0xC2D1, 0x9AD5, 0xC2D2, 0x9AD6, 0xC2D3, 0x9AD7, 0xC2D4, 0x9AD8, 0xC2D5, 0x9AD9, 0xC2D6, 0x9ADA, 0xC2D7, 0x9ADB, 0xC2D8, 0x9ADC, 0xC2D9, 0x9ADD, 0xC2DA, 0x9ADE, 0xC2DB, 0x9ADF, 0xC2DE, 0x9AE0, 0xC2DF, 0x9AE1, 0xC2E1, 0x9AE2, 0xC2E2, 0x9AE3, 0xC2E5, 0x9AE4, 0xC2E6, 0x9AE5, 0xC2E7, 0x9AE6, 0xC2E8, 0x9AE7, 0xC2E9, 0x9AE8, 0xC2EA, 0x9AE9, 0xC2EE, 0x9AEA, 0xC2F0, 0x9AEB, 0xC2F2, 0x9AEC, 0xC2F3, 0x9AED, 0xC2F4, 0x9AEE, 0xC2F5, 0x9AEF, 0xC2F7, 0x9AF0, 0xC2FA, 0x9AF1, 0xC2FD, 0x9AF2, 0xC2FE, 0x9AF3, 0xC2FF, 0x9AF4, 0xC301, 0x9AF5, 0xC302, 0x9AF6, 0xC303, 0x9AF7, 0xC304, 0x9AF8, 0xC305, 0x9AF9, 0xC306, 0x9AFA, 0xC307, 0x9AFB, 0xC30A, 0x9AFC, 0xC30B, 0x9AFD, 0xC30E, 0x9AFE, 0xC30F, 0x9B41, 0xC310, 0x9B42, 0xC311, 0x9B43, 0xC312, 0x9B44, 0xC316, 0x9B45, 0xC317, 0x9B46, 0xC319, 0x9B47, 0xC31A, 0x9B48, 0xC31B, 0x9B49, 0xC31D, 0x9B4A, 0xC31E, 0x9B4B, 0xC31F, 0x9B4C, 0xC320, 0x9B4D, 0xC321, 0x9B4E, 0xC322, 0x9B4F, 0xC323, 0x9B50, 0xC326, 0x9B51, 0xC327, 0x9B52, 0xC32A, 0x9B53, 0xC32B, 0x9B54, 0xC32C, 0x9B55, 0xC32D, 0x9B56, 0xC32E, 0x9B57, 0xC32F, 0x9B58, 0xC330, 0x9B59, 0xC331, 0x9B5A, 0xC332, 0x9B61, 0xC333, 0x9B62, 0xC334, 0x9B63, 0xC335, 0x9B64, 0xC336, 0x9B65, 0xC337, 0x9B66, 0xC338, 0x9B67, 0xC339, 0x9B68, 0xC33A, 0x9B69, 0xC33B, 0x9B6A, 0xC33C, 0x9B6B, 0xC33D, 0x9B6C, 0xC33E, 0x9B6D, 0xC33F, 0x9B6E, 0xC340, 0x9B6F, 0xC341, 0x9B70, 0xC342, 0x9B71, 0xC343, 0x9B72, 0xC344, 0x9B73, 0xC346, 0x9B74, 0xC347, 0x9B75, 0xC348, 0x9B76, 0xC349, 0x9B77, 0xC34A, 0x9B78, 0xC34B, 0x9B79, 0xC34C, 0x9B7A, 0xC34D, 0x9B81, 0xC34E, 0x9B82, 0xC34F, 0x9B83, 0xC350, 0x9B84, 0xC351, 0x9B85, 0xC352, 0x9B86, 0xC353, 0x9B87, 0xC354, 0x9B88, 0xC355, 0x9B89, 0xC356, 0x9B8A, 0xC357, 0x9B8B, 0xC358, 0x9B8C, 0xC359, 0x9B8D, 0xC35A, 0x9B8E, 0xC35B, 0x9B8F, 0xC35C, 0x9B90, 0xC35D, 0x9B91, 0xC35E, 0x9B92, 0xC35F, 0x9B93, 0xC360, 0x9B94, 0xC361, 0x9B95, 0xC362, 0x9B96, 0xC363, 0x9B97, 0xC364, 0x9B98, 0xC365, 0x9B99, 0xC366, 0x9B9A, 0xC367, 0x9B9B, 0xC36A, 0x9B9C, 0xC36B, 0x9B9D, 0xC36D, 0x9B9E, 0xC36E, 0x9B9F, 0xC36F, 0x9BA0, 0xC371, 0x9BA1, 0xC373, 0x9BA2, 0xC374, 0x9BA3, 0xC375, 0x9BA4, 0xC376, 0x9BA5, 0xC377, 0x9BA6, 0xC37A, 0x9BA7, 0xC37B, 0x9BA8, 0xC37E, 0x9BA9, 0xC37F, 0x9BAA, 0xC380, 0x9BAB, 0xC381, 0x9BAC, 0xC382, 0x9BAD, 0xC383, 0x9BAE, 0xC385, 0x9BAF, 0xC386, 0x9BB0, 0xC387, 0x9BB1, 0xC389, 0x9BB2, 0xC38A, 0x9BB3, 0xC38B, 0x9BB4, 0xC38D, 0x9BB5, 0xC38E, 0x9BB6, 0xC38F, 0x9BB7, 0xC390, 0x9BB8, 0xC391, 0x9BB9, 0xC392, 0x9BBA, 0xC393, 0x9BBB, 0xC394, 0x9BBC, 0xC395, 0x9BBD, 0xC396, 0x9BBE, 0xC397, 0x9BBF, 0xC398, 0x9BC0, 0xC399, 0x9BC1, 0xC39A, 0x9BC2, 0xC39B, 0x9BC3, 0xC39C, 0x9BC4, 0xC39D, 0x9BC5, 0xC39E, 0x9BC6, 0xC39F, 0x9BC7, 0xC3A0, 0x9BC8, 0xC3A1, 0x9BC9, 0xC3A2, 0x9BCA, 0xC3A3, 0x9BCB, 0xC3A4, 0x9BCC, 0xC3A5, 0x9BCD, 0xC3A6, 0x9BCE, 0xC3A7, 0x9BCF, 0xC3A8, 0x9BD0, 0xC3A9, 0x9BD1, 0xC3AA, 0x9BD2, 0xC3AB, 0x9BD3, 0xC3AC, 0x9BD4, 0xC3AD, 0x9BD5, 0xC3AE, 0x9BD6, 0xC3AF, 0x9BD7, 0xC3B0, 0x9BD8, 0xC3B1, 0x9BD9, 0xC3B2, 0x9BDA, 0xC3B3, 0x9BDB, 0xC3B4, 0x9BDC, 0xC3B5, 0x9BDD, 0xC3B6, 0x9BDE, 0xC3B7, 0x9BDF, 0xC3B8, 0x9BE0, 0xC3B9, 0x9BE1, 0xC3BA, 0x9BE2, 0xC3BB, 0x9BE3, 0xC3BC, 0x9BE4, 0xC3BD, 0x9BE5, 0xC3BE, 0x9BE6, 0xC3BF, 0x9BE7, 0xC3C1, 0x9BE8, 0xC3C2, 0x9BE9, 0xC3C3, 0x9BEA, 0xC3C4, 0x9BEB, 0xC3C5, 0x9BEC, 0xC3C6, 0x9BED, 0xC3C7, 0x9BEE, 0xC3C8, 0x9BEF, 0xC3C9, 0x9BF0, 0xC3CA, 0x9BF1, 0xC3CB, 0x9BF2, 0xC3CC, 0x9BF3, 0xC3CD, 0x9BF4, 0xC3CE, 0x9BF5, 0xC3CF, 0x9BF6, 0xC3D0, 0x9BF7, 0xC3D1, 0x9BF8, 0xC3D2, 0x9BF9, 0xC3D3, 0x9BFA, 0xC3D4, 0x9BFB, 0xC3D5, 0x9BFC, 0xC3D6, 0x9BFD, 0xC3D7, 0x9BFE, 0xC3DA, 0x9C41, 0xC3DB, 0x9C42, 0xC3DD, 0x9C43, 0xC3DE, 0x9C44, 0xC3E1, 0x9C45, 0xC3E3, 0x9C46, 0xC3E4, 0x9C47, 0xC3E5, 0x9C48, 0xC3E6, 0x9C49, 0xC3E7, 0x9C4A, 0xC3EA, 0x9C4B, 0xC3EB, 0x9C4C, 0xC3EC, 0x9C4D, 0xC3EE, 0x9C4E, 0xC3EF, 0x9C4F, 0xC3F0, 0x9C50, 0xC3F1, 0x9C51, 0xC3F2, 0x9C52, 0xC3F3, 0x9C53, 0xC3F6, 0x9C54, 0xC3F7, 0x9C55, 0xC3F9, 0x9C56, 0xC3FA, 0x9C57, 0xC3FB, 0x9C58, 0xC3FC, 0x9C59, 0xC3FD, 0x9C5A, 0xC3FE, 0x9C61, 0xC3FF, 0x9C62, 0xC400, 0x9C63, 0xC401, 0x9C64, 0xC402, 0x9C65, 0xC403, 0x9C66, 0xC404, 0x9C67, 0xC405, 0x9C68, 0xC406, 0x9C69, 0xC407, 0x9C6A, 0xC409, 0x9C6B, 0xC40A, 0x9C6C, 0xC40B, 0x9C6D, 0xC40C, 0x9C6E, 0xC40D, 0x9C6F, 0xC40E, 0x9C70, 0xC40F, 0x9C71, 0xC411, 0x9C72, 0xC412, 0x9C73, 0xC413, 0x9C74, 0xC414, 0x9C75, 0xC415, 0x9C76, 0xC416, 0x9C77, 0xC417, 0x9C78, 0xC418, 0x9C79, 0xC419, 0x9C7A, 0xC41A, 0x9C81, 0xC41B, 0x9C82, 0xC41C, 0x9C83, 0xC41D, 0x9C84, 0xC41E, 0x9C85, 0xC41F, 0x9C86, 0xC420, 0x9C87, 0xC421, 0x9C88, 0xC422, 0x9C89, 0xC423, 0x9C8A, 0xC425, 0x9C8B, 0xC426, 0x9C8C, 0xC427, 0x9C8D, 0xC428, 0x9C8E, 0xC429, 0x9C8F, 0xC42A, 0x9C90, 0xC42B, 0x9C91, 0xC42D, 0x9C92, 0xC42E, 0x9C93, 0xC42F, 0x9C94, 0xC431, 0x9C95, 0xC432, 0x9C96, 0xC433, 0x9C97, 0xC435, 0x9C98, 0xC436, 0x9C99, 0xC437, 0x9C9A, 0xC438, 0x9C9B, 0xC439, 0x9C9C, 0xC43A, 0x9C9D, 0xC43B, 0x9C9E, 0xC43E, 0x9C9F, 0xC43F, 0x9CA0, 0xC440, 0x9CA1, 0xC441, 0x9CA2, 0xC442, 0x9CA3, 0xC443, 0x9CA4, 0xC444, 0x9CA5, 0xC445, 0x9CA6, 0xC446, 0x9CA7, 0xC447, 0x9CA8, 0xC449, 0x9CA9, 0xC44A, 0x9CAA, 0xC44B, 0x9CAB, 0xC44C, 0x9CAC, 0xC44D, 0x9CAD, 0xC44E, 0x9CAE, 0xC44F, 0x9CAF, 0xC450, 0x9CB0, 0xC451, 0x9CB1, 0xC452, 0x9CB2, 0xC453, 0x9CB3, 0xC454, 0x9CB4, 0xC455, 0x9CB5, 0xC456, 0x9CB6, 0xC457, 0x9CB7, 0xC458, 0x9CB8, 0xC459, 0x9CB9, 0xC45A, 0x9CBA, 0xC45B, 0x9CBB, 0xC45C, 0x9CBC, 0xC45D, 0x9CBD, 0xC45E, 0x9CBE, 0xC45F, 0x9CBF, 0xC460, 0x9CC0, 0xC461, 0x9CC1, 0xC462, 0x9CC2, 0xC463, 0x9CC3, 0xC466, 0x9CC4, 0xC467, 0x9CC5, 0xC469, 0x9CC6, 0xC46A, 0x9CC7, 0xC46B, 0x9CC8, 0xC46D, 0x9CC9, 0xC46E, 0x9CCA, 0xC46F, 0x9CCB, 0xC470, 0x9CCC, 0xC471, 0x9CCD, 0xC472, 0x9CCE, 0xC473, 0x9CCF, 0xC476, 0x9CD0, 0xC477, 0x9CD1, 0xC478, 0x9CD2, 0xC47A, 0x9CD3, 0xC47B, 0x9CD4, 0xC47C, 0x9CD5, 0xC47D, 0x9CD6, 0xC47E, 0x9CD7, 0xC47F, 0x9CD8, 0xC481, 0x9CD9, 0xC482, 0x9CDA, 0xC483, 0x9CDB, 0xC484, 0x9CDC, 0xC485, 0x9CDD, 0xC486, 0x9CDE, 0xC487, 0x9CDF, 0xC488, 0x9CE0, 0xC489, 0x9CE1, 0xC48A, 0x9CE2, 0xC48B, 0x9CE3, 0xC48C, 0x9CE4, 0xC48D, 0x9CE5, 0xC48E, 0x9CE6, 0xC48F, 0x9CE7, 0xC490, 0x9CE8, 0xC491, 0x9CE9, 0xC492, 0x9CEA, 0xC493, 0x9CEB, 0xC495, 0x9CEC, 0xC496, 0x9CED, 0xC497, 0x9CEE, 0xC498, 0x9CEF, 0xC499, 0x9CF0, 0xC49A, 0x9CF1, 0xC49B, 0x9CF2, 0xC49D, 0x9CF3, 0xC49E, 0x9CF4, 0xC49F, 0x9CF5, 0xC4A0, 0x9CF6, 0xC4A1, 0x9CF7, 0xC4A2, 0x9CF8, 0xC4A3, 0x9CF9, 0xC4A4, 0x9CFA, 0xC4A5, 0x9CFB, 0xC4A6, 0x9CFC, 0xC4A7, 0x9CFD, 0xC4A8, 0x9CFE, 0xC4A9, 0x9D41, 0xC4AA, 0x9D42, 0xC4AB, 0x9D43, 0xC4AC, 0x9D44, 0xC4AD, 0x9D45, 0xC4AE, 0x9D46, 0xC4AF, 0x9D47, 0xC4B0, 0x9D48, 0xC4B1, 0x9D49, 0xC4B2, 0x9D4A, 0xC4B3, 0x9D4B, 0xC4B4, 0x9D4C, 0xC4B5, 0x9D4D, 0xC4B6, 0x9D4E, 0xC4B7, 0x9D4F, 0xC4B9, 0x9D50, 0xC4BA, 0x9D51, 0xC4BB, 0x9D52, 0xC4BD, 0x9D53, 0xC4BE, 0x9D54, 0xC4BF, 0x9D55, 0xC4C0, 0x9D56, 0xC4C1, 0x9D57, 0xC4C2, 0x9D58, 0xC4C3, 0x9D59, 0xC4C4, 0x9D5A, 0xC4C5, 0x9D61, 0xC4C6, 0x9D62, 0xC4C7, 0x9D63, 0xC4C8, 0x9D64, 0xC4C9, 0x9D65, 0xC4CA, 0x9D66, 0xC4CB, 0x9D67, 0xC4CC, 0x9D68, 0xC4CD, 0x9D69, 0xC4CE, 0x9D6A, 0xC4CF, 0x9D6B, 0xC4D0, 0x9D6C, 0xC4D1, 0x9D6D, 0xC4D2, 0x9D6E, 0xC4D3, 0x9D6F, 0xC4D4, 0x9D70, 0xC4D5, 0x9D71, 0xC4D6, 0x9D72, 0xC4D7, 0x9D73, 0xC4D8, 0x9D74, 0xC4D9, 0x9D75, 0xC4DA, 0x9D76, 0xC4DB, 0x9D77, 0xC4DC, 0x9D78, 0xC4DD, 0x9D79, 0xC4DE, 0x9D7A, 0xC4DF, 0x9D81, 0xC4E0, 0x9D82, 0xC4E1, 0x9D83, 0xC4E2, 0x9D84, 0xC4E3, 0x9D85, 0xC4E4, 0x9D86, 0xC4E5, 0x9D87, 0xC4E6, 0x9D88, 0xC4E7, 0x9D89, 0xC4E8, 0x9D8A, 0xC4EA, 0x9D8B, 0xC4EB, 0x9D8C, 0xC4EC, 0x9D8D, 0xC4ED, 0x9D8E, 0xC4EE, 0x9D8F, 0xC4EF, 0x9D90, 0xC4F2, 0x9D91, 0xC4F3, 0x9D92, 0xC4F5, 0x9D93, 0xC4F6, 0x9D94, 0xC4F7, 0x9D95, 0xC4F9, 0x9D96, 0xC4FB, 0x9D97, 0xC4FC, 0x9D98, 0xC4FD, 0x9D99, 0xC4FE, 0x9D9A, 0xC502, 0x9D9B, 0xC503, 0x9D9C, 0xC504, 0x9D9D, 0xC505, 0x9D9E, 0xC506, 0x9D9F, 0xC507, 0x9DA0, 0xC508, 0x9DA1, 0xC509, 0x9DA2, 0xC50A, 0x9DA3, 0xC50B, 0x9DA4, 0xC50D, 0x9DA5, 0xC50E, 0x9DA6, 0xC50F, 0x9DA7, 0xC511, 0x9DA8, 0xC512, 0x9DA9, 0xC513, 0x9DAA, 0xC515, 0x9DAB, 0xC516, 0x9DAC, 0xC517, 0x9DAD, 0xC518, 0x9DAE, 0xC519, 0x9DAF, 0xC51A, 0x9DB0, 0xC51B, 0x9DB1, 0xC51D, 0x9DB2, 0xC51E, 0x9DB3, 0xC51F, 0x9DB4, 0xC520, 0x9DB5, 0xC521, 0x9DB6, 0xC522, 0x9DB7, 0xC523, 0x9DB8, 0xC524, 0x9DB9, 0xC525, 0x9DBA, 0xC526, 0x9DBB, 0xC527, 0x9DBC, 0xC52A, 0x9DBD, 0xC52B, 0x9DBE, 0xC52D, 0x9DBF, 0xC52E, 0x9DC0, 0xC52F, 0x9DC1, 0xC531, 0x9DC2, 0xC532, 0x9DC3, 0xC533, 0x9DC4, 0xC534, 0x9DC5, 0xC535, 0x9DC6, 0xC536, 0x9DC7, 0xC537, 0x9DC8, 0xC53A, 0x9DC9, 0xC53C, 0x9DCA, 0xC53E, 0x9DCB, 0xC53F, 0x9DCC, 0xC540, 0x9DCD, 0xC541, 0x9DCE, 0xC542, 0x9DCF, 0xC543, 0x9DD0, 0xC546, 0x9DD1, 0xC547, 0x9DD2, 0xC54B, 0x9DD3, 0xC54F, 0x9DD4, 0xC550, 0x9DD5, 0xC551, 0x9DD6, 0xC552, 0x9DD7, 0xC556, 0x9DD8, 0xC55A, 0x9DD9, 0xC55B, 0x9DDA, 0xC55C, 0x9DDB, 0xC55F, 0x9DDC, 0xC562, 0x9DDD, 0xC563, 0x9DDE, 0xC565, 0x9DDF, 0xC566, 0x9DE0, 0xC567, 0x9DE1, 0xC569, 0x9DE2, 0xC56A, 0x9DE3, 0xC56B, 0x9DE4, 0xC56C, 0x9DE5, 0xC56D, 0x9DE6, 0xC56E, 0x9DE7, 0xC56F, 0x9DE8, 0xC572, 0x9DE9, 0xC576, 0x9DEA, 0xC577, 0x9DEB, 0xC578, 0x9DEC, 0xC579, 0x9DED, 0xC57A, 0x9DEE, 0xC57B, 0x9DEF, 0xC57E, 0x9DF0, 0xC57F, 0x9DF1, 0xC581, 0x9DF2, 0xC582, 0x9DF3, 0xC583, 0x9DF4, 0xC585, 0x9DF5, 0xC586, 0x9DF6, 0xC588, 0x9DF7, 0xC589, 0x9DF8, 0xC58A, 0x9DF9, 0xC58B, 0x9DFA, 0xC58E, 0x9DFB, 0xC590, 0x9DFC, 0xC592, 0x9DFD, 0xC593, 0x9DFE, 0xC594, 0x9E41, 0xC596, 0x9E42, 0xC599, 0x9E43, 0xC59A, 0x9E44, 0xC59B, 0x9E45, 0xC59D, 0x9E46, 0xC59E, 0x9E47, 0xC59F, 0x9E48, 0xC5A1, 0x9E49, 0xC5A2, 0x9E4A, 0xC5A3, 0x9E4B, 0xC5A4, 0x9E4C, 0xC5A5, 0x9E4D, 0xC5A6, 0x9E4E, 0xC5A7, 0x9E4F, 0xC5A8, 0x9E50, 0xC5AA, 0x9E51, 0xC5AB, 0x9E52, 0xC5AC, 0x9E53, 0xC5AD, 0x9E54, 0xC5AE, 0x9E55, 0xC5AF, 0x9E56, 0xC5B0, 0x9E57, 0xC5B1, 0x9E58, 0xC5B2, 0x9E59, 0xC5B3, 0x9E5A, 0xC5B6, 0x9E61, 0xC5B7, 0x9E62, 0xC5BA, 0x9E63, 0xC5BF, 0x9E64, 0xC5C0, 0x9E65, 0xC5C1, 0x9E66, 0xC5C2, 0x9E67, 0xC5C3, 0x9E68, 0xC5CB, 0x9E69, 0xC5CD, 0x9E6A, 0xC5CF, 0x9E6B, 0xC5D2, 0x9E6C, 0xC5D3, 0x9E6D, 0xC5D5, 0x9E6E, 0xC5D6, 0x9E6F, 0xC5D7, 0x9E70, 0xC5D9, 0x9E71, 0xC5DA, 0x9E72, 0xC5DB, 0x9E73, 0xC5DC, 0x9E74, 0xC5DD, 0x9E75, 0xC5DE, 0x9E76, 0xC5DF, 0x9E77, 0xC5E2, 0x9E78, 0xC5E4, 0x9E79, 0xC5E6, 0x9E7A, 0xC5E7, 0x9E81, 0xC5E8, 0x9E82, 0xC5E9, 0x9E83, 0xC5EA, 0x9E84, 0xC5EB, 0x9E85, 0xC5EF, 0x9E86, 0xC5F1, 0x9E87, 0xC5F2, 0x9E88, 0xC5F3, 0x9E89, 0xC5F5, 0x9E8A, 0xC5F8, 0x9E8B, 0xC5F9, 0x9E8C, 0xC5FA, 0x9E8D, 0xC5FB, 0x9E8E, 0xC602, 0x9E8F, 0xC603, 0x9E90, 0xC604, 0x9E91, 0xC609, 0x9E92, 0xC60A, 0x9E93, 0xC60B, 0x9E94, 0xC60D, 0x9E95, 0xC60E, 0x9E96, 0xC60F, 0x9E97, 0xC611, 0x9E98, 0xC612, 0x9E99, 0xC613, 0x9E9A, 0xC614, 0x9E9B, 0xC615, 0x9E9C, 0xC616, 0x9E9D, 0xC617, 0x9E9E, 0xC61A, 0x9E9F, 0xC61D, 0x9EA0, 0xC61E, 0x9EA1, 0xC61F, 0x9EA2, 0xC620, 0x9EA3, 0xC621, 0x9EA4, 0xC622, 0x9EA5, 0xC623, 0x9EA6, 0xC626, 0x9EA7, 0xC627, 0x9EA8, 0xC629, 0x9EA9, 0xC62A, 0x9EAA, 0xC62B, 0x9EAB, 0xC62F, 0x9EAC, 0xC631, 0x9EAD, 0xC632, 0x9EAE, 0xC636, 0x9EAF, 0xC638, 0x9EB0, 0xC63A, 0x9EB1, 0xC63C, 0x9EB2, 0xC63D, 0x9EB3, 0xC63E, 0x9EB4, 0xC63F, 0x9EB5, 0xC642, 0x9EB6, 0xC643, 0x9EB7, 0xC645, 0x9EB8, 0xC646, 0x9EB9, 0xC647, 0x9EBA, 0xC649, 0x9EBB, 0xC64A, 0x9EBC, 0xC64B, 0x9EBD, 0xC64C, 0x9EBE, 0xC64D, 0x9EBF, 0xC64E, 0x9EC0, 0xC64F, 0x9EC1, 0xC652, 0x9EC2, 0xC656, 0x9EC3, 0xC657, 0x9EC4, 0xC658, 0x9EC5, 0xC659, 0x9EC6, 0xC65A, 0x9EC7, 0xC65B, 0x9EC8, 0xC65E, 0x9EC9, 0xC65F, 0x9ECA, 0xC661, 0x9ECB, 0xC662, 0x9ECC, 0xC663, 0x9ECD, 0xC664, 0x9ECE, 0xC665, 0x9ECF, 0xC666, 0x9ED0, 0xC667, 0x9ED1, 0xC668, 0x9ED2, 0xC669, 0x9ED3, 0xC66A, 0x9ED4, 0xC66B, 0x9ED5, 0xC66D, 0x9ED6, 0xC66E, 0x9ED7, 0xC670, 0x9ED8, 0xC672, 0x9ED9, 0xC673, 0x9EDA, 0xC674, 0x9EDB, 0xC675, 0x9EDC, 0xC676, 0x9EDD, 0xC677, 0x9EDE, 0xC67A, 0x9EDF, 0xC67B, 0x9EE0, 0xC67D, 0x9EE1, 0xC67E, 0x9EE2, 0xC67F, 0x9EE3, 0xC681, 0x9EE4, 0xC682, 0x9EE5, 0xC683, 0x9EE6, 0xC684, 0x9EE7, 0xC685, 0x9EE8, 0xC686, 0x9EE9, 0xC687, 0x9EEA, 0xC68A, 0x9EEB, 0xC68C, 0x9EEC, 0xC68E, 0x9EED, 0xC68F, 0x9EEE, 0xC690, 0x9EEF, 0xC691, 0x9EF0, 0xC692, 0x9EF1, 0xC693, 0x9EF2, 0xC696, 0x9EF3, 0xC697, 0x9EF4, 0xC699, 0x9EF5, 0xC69A, 0x9EF6, 0xC69B, 0x9EF7, 0xC69D, 0x9EF8, 0xC69E, 0x9EF9, 0xC69F, 0x9EFA, 0xC6A0, 0x9EFB, 0xC6A1, 0x9EFC, 0xC6A2, 0x9EFD, 0xC6A3, 0x9EFE, 0xC6A6, 0x9F41, 0xC6A8, 0x9F42, 0xC6AA, 0x9F43, 0xC6AB, 0x9F44, 0xC6AC, 0x9F45, 0xC6AD, 0x9F46, 0xC6AE, 0x9F47, 0xC6AF, 0x9F48, 0xC6B2, 0x9F49, 0xC6B3, 0x9F4A, 0xC6B5, 0x9F4B, 0xC6B6, 0x9F4C, 0xC6B7, 0x9F4D, 0xC6BB, 0x9F4E, 0xC6BC, 0x9F4F, 0xC6BD, 0x9F50, 0xC6BE, 0x9F51, 0xC6BF, 0x9F52, 0xC6C2, 0x9F53, 0xC6C4, 0x9F54, 0xC6C6, 0x9F55, 0xC6C7, 0x9F56, 0xC6C8, 0x9F57, 0xC6C9, 0x9F58, 0xC6CA, 0x9F59, 0xC6CB, 0x9F5A, 0xC6CE, 0x9F61, 0xC6CF, 0x9F62, 0xC6D1, 0x9F63, 0xC6D2, 0x9F64, 0xC6D3, 0x9F65, 0xC6D5, 0x9F66, 0xC6D6, 0x9F67, 0xC6D7, 0x9F68, 0xC6D8, 0x9F69, 0xC6D9, 0x9F6A, 0xC6DA, 0x9F6B, 0xC6DB, 0x9F6C, 0xC6DE, 0x9F6D, 0xC6DF, 0x9F6E, 0xC6E2, 0x9F6F, 0xC6E3, 0x9F70, 0xC6E4, 0x9F71, 0xC6E5, 0x9F72, 0xC6E6, 0x9F73, 0xC6E7, 0x9F74, 0xC6EA, 0x9F75, 0xC6EB, 0x9F76, 0xC6ED, 0x9F77, 0xC6EE, 0x9F78, 0xC6EF, 0x9F79, 0xC6F1, 0x9F7A, 0xC6F2, 0x9F81, 0xC6F3, 0x9F82, 0xC6F4, 0x9F83, 0xC6F5, 0x9F84, 0xC6F6, 0x9F85, 0xC6F7, 0x9F86, 0xC6FA, 0x9F87, 0xC6FB, 0x9F88, 0xC6FC, 0x9F89, 0xC6FE, 0x9F8A, 0xC6FF, 0x9F8B, 0xC700, 0x9F8C, 0xC701, 0x9F8D, 0xC702, 0x9F8E, 0xC703, 0x9F8F, 0xC706, 0x9F90, 0xC707, 0x9F91, 0xC709, 0x9F92, 0xC70A, 0x9F93, 0xC70B, 0x9F94, 0xC70D, 0x9F95, 0xC70E, 0x9F96, 0xC70F, 0x9F97, 0xC710, 0x9F98, 0xC711, 0x9F99, 0xC712, 0x9F9A, 0xC713, 0x9F9B, 0xC716, 0x9F9C, 0xC718, 0x9F9D, 0xC71A, 0x9F9E, 0xC71B, 0x9F9F, 0xC71C, 0x9FA0, 0xC71D, 0x9FA1, 0xC71E, 0x9FA2, 0xC71F, 0x9FA3, 0xC722, 0x9FA4, 0xC723, 0x9FA5, 0xC725, 0x9FA6, 0xC726, 0x9FA7, 0xC727, 0x9FA8, 0xC729, 0x9FA9, 0xC72A, 0x9FAA, 0xC72B, 0x9FAB, 0xC72C, 0x9FAC, 0xC72D, 0x9FAD, 0xC72E, 0x9FAE, 0xC72F, 0x9FAF, 0xC732, 0x9FB0, 0xC734, 0x9FB1, 0xC736, 0x9FB2, 0xC738, 0x9FB3, 0xC739, 0x9FB4, 0xC73A, 0x9FB5, 0xC73B, 0x9FB6, 0xC73E, 0x9FB7, 0xC73F, 0x9FB8, 0xC741, 0x9FB9, 0xC742, 0x9FBA, 0xC743, 0x9FBB, 0xC745, 0x9FBC, 0xC746, 0x9FBD, 0xC747, 0x9FBE, 0xC748, 0x9FBF, 0xC749, 0x9FC0, 0xC74B, 0x9FC1, 0xC74E, 0x9FC2, 0xC750, 0x9FC3, 0xC759, 0x9FC4, 0xC75A, 0x9FC5, 0xC75B, 0x9FC6, 0xC75D, 0x9FC7, 0xC75E, 0x9FC8, 0xC75F, 0x9FC9, 0xC761, 0x9FCA, 0xC762, 0x9FCB, 0xC763, 0x9FCC, 0xC764, 0x9FCD, 0xC765, 0x9FCE, 0xC766, 0x9FCF, 0xC767, 0x9FD0, 0xC769, 0x9FD1, 0xC76A, 0x9FD2, 0xC76C, 0x9FD3, 0xC76D, 0x9FD4, 0xC76E, 0x9FD5, 0xC76F, 0x9FD6, 0xC770, 0x9FD7, 0xC771, 0x9FD8, 0xC772, 0x9FD9, 0xC773, 0x9FDA, 0xC776, 0x9FDB, 0xC777, 0x9FDC, 0xC779, 0x9FDD, 0xC77A, 0x9FDE, 0xC77B, 0x9FDF, 0xC77F, 0x9FE0, 0xC780, 0x9FE1, 0xC781, 0x9FE2, 0xC782, 0x9FE3, 0xC786, 0x9FE4, 0xC78B, 0x9FE5, 0xC78C, 0x9FE6, 0xC78D, 0x9FE7, 0xC78F, 0x9FE8, 0xC792, 0x9FE9, 0xC793, 0x9FEA, 0xC795, 0x9FEB, 0xC799, 0x9FEC, 0xC79B, 0x9FED, 0xC79C, 0x9FEE, 0xC79D, 0x9FEF, 0xC79E, 0x9FF0, 0xC79F, 0x9FF1, 0xC7A2, 0x9FF2, 0xC7A7, 0x9FF3, 0xC7A8, 0x9FF4, 0xC7A9, 0x9FF5, 0xC7AA, 0x9FF6, 0xC7AB, 0x9FF7, 0xC7AE, 0x9FF8, 0xC7AF, 0x9FF9, 0xC7B1, 0x9FFA, 0xC7B2, 0x9FFB, 0xC7B3, 0x9FFC, 0xC7B5, 0x9FFD, 0xC7B6, 0x9FFE, 0xC7B7, 0xA041, 0xC7B8, 0xA042, 0xC7B9, 0xA043, 0xC7BA, 0xA044, 0xC7BB, 0xA045, 0xC7BE, 0xA046, 0xC7C2, 0xA047, 0xC7C3, 0xA048, 0xC7C4, 0xA049, 0xC7C5, 0xA04A, 0xC7C6, 0xA04B, 0xC7C7, 0xA04C, 0xC7CA, 0xA04D, 0xC7CB, 0xA04E, 0xC7CD, 0xA04F, 0xC7CF, 0xA050, 0xC7D1, 0xA051, 0xC7D2, 0xA052, 0xC7D3, 0xA053, 0xC7D4, 0xA054, 0xC7D5, 0xA055, 0xC7D6, 0xA056, 0xC7D7, 0xA057, 0xC7D9, 0xA058, 0xC7DA, 0xA059, 0xC7DB, 0xA05A, 0xC7DC, 0xA061, 0xC7DE, 0xA062, 0xC7DF, 0xA063, 0xC7E0, 0xA064, 0xC7E1, 0xA065, 0xC7E2, 0xA066, 0xC7E3, 0xA067, 0xC7E5, 0xA068, 0xC7E6, 0xA069, 0xC7E7, 0xA06A, 0xC7E9, 0xA06B, 0xC7EA, 0xA06C, 0xC7EB, 0xA06D, 0xC7ED, 0xA06E, 0xC7EE, 0xA06F, 0xC7EF, 0xA070, 0xC7F0, 0xA071, 0xC7F1, 0xA072, 0xC7F2, 0xA073, 0xC7F3, 0xA074, 0xC7F4, 0xA075, 0xC7F5, 0xA076, 0xC7F6, 0xA077, 0xC7F7, 0xA078, 0xC7F8, 0xA079, 0xC7F9, 0xA07A, 0xC7FA, 0xA081, 0xC7FB, 0xA082, 0xC7FC, 0xA083, 0xC7FD, 0xA084, 0xC7FE, 0xA085, 0xC7FF, 0xA086, 0xC802, 0xA087, 0xC803, 0xA088, 0xC805, 0xA089, 0xC806, 0xA08A, 0xC807, 0xA08B, 0xC809, 0xA08C, 0xC80B, 0xA08D, 0xC80C, 0xA08E, 0xC80D, 0xA08F, 0xC80E, 0xA090, 0xC80F, 0xA091, 0xC812, 0xA092, 0xC814, 0xA093, 0xC817, 0xA094, 0xC818, 0xA095, 0xC819, 0xA096, 0xC81A, 0xA097, 0xC81B, 0xA098, 0xC81E, 0xA099, 0xC81F, 0xA09A, 0xC821, 0xA09B, 0xC822, 0xA09C, 0xC823, 0xA09D, 0xC825, 0xA09E, 0xC826, 0xA09F, 0xC827, 0xA0A0, 0xC828, 0xA0A1, 0xC829, 0xA0A2, 0xC82A, 0xA0A3, 0xC82B, 0xA0A4, 0xC82E, 0xA0A5, 0xC830, 0xA0A6, 0xC832, 0xA0A7, 0xC833, 0xA0A8, 0xC834, 0xA0A9, 0xC835, 0xA0AA, 0xC836, 0xA0AB, 0xC837, 0xA0AC, 0xC839, 0xA0AD, 0xC83A, 0xA0AE, 0xC83B, 0xA0AF, 0xC83D, 0xA0B0, 0xC83E, 0xA0B1, 0xC83F, 0xA0B2, 0xC841, 0xA0B3, 0xC842, 0xA0B4, 0xC843, 0xA0B5, 0xC844, 0xA0B6, 0xC845, 0xA0B7, 0xC846, 0xA0B8, 0xC847, 0xA0B9, 0xC84A, 0xA0BA, 0xC84B, 0xA0BB, 0xC84E, 0xA0BC, 0xC84F, 0xA0BD, 0xC850, 0xA0BE, 0xC851, 0xA0BF, 0xC852, 0xA0C0, 0xC853, 0xA0C1, 0xC855, 0xA0C2, 0xC856, 0xA0C3, 0xC857, 0xA0C4, 0xC858, 0xA0C5, 0xC859, 0xA0C6, 0xC85A, 0xA0C7, 0xC85B, 0xA0C8, 0xC85C, 0xA0C9, 0xC85D, 0xA0CA, 0xC85E, 0xA0CB, 0xC85F, 0xA0CC, 0xC860, 0xA0CD, 0xC861, 0xA0CE, 0xC862, 0xA0CF, 0xC863, 0xA0D0, 0xC864, 0xA0D1, 0xC865, 0xA0D2, 0xC866, 0xA0D3, 0xC867, 0xA0D4, 0xC868, 0xA0D5, 0xC869, 0xA0D6, 0xC86A, 0xA0D7, 0xC86B, 0xA0D8, 0xC86C, 0xA0D9, 0xC86D, 0xA0DA, 0xC86E, 0xA0DB, 0xC86F, 0xA0DC, 0xC872, 0xA0DD, 0xC873, 0xA0DE, 0xC875, 0xA0DF, 0xC876, 0xA0E0, 0xC877, 0xA0E1, 0xC879, 0xA0E2, 0xC87B, 0xA0E3, 0xC87C, 0xA0E4, 0xC87D, 0xA0E5, 0xC87E, 0xA0E6, 0xC87F, 0xA0E7, 0xC882, 0xA0E8, 0xC884, 0xA0E9, 0xC888, 0xA0EA, 0xC889, 0xA0EB, 0xC88A, 0xA0EC, 0xC88E, 0xA0ED, 0xC88F, 0xA0EE, 0xC890, 0xA0EF, 0xC891, 0xA0F0, 0xC892, 0xA0F1, 0xC893, 0xA0F2, 0xC895, 0xA0F3, 0xC896, 0xA0F4, 0xC897, 0xA0F5, 0xC898, 0xA0F6, 0xC899, 0xA0F7, 0xC89A, 0xA0F8, 0xC89B, 0xA0F9, 0xC89C, 0xA0FA, 0xC89E, 0xA0FB, 0xC8A0, 0xA0FC, 0xC8A2, 0xA0FD, 0xC8A3, 0xA0FE, 0xC8A4, 0xA141, 0xC8A5, 0xA142, 0xC8A6, 0xA143, 0xC8A7, 0xA144, 0xC8A9, 0xA145, 0xC8AA, 0xA146, 0xC8AB, 0xA147, 0xC8AC, 0xA148, 0xC8AD, 0xA149, 0xC8AE, 0xA14A, 0xC8AF, 0xA14B, 0xC8B0, 0xA14C, 0xC8B1, 0xA14D, 0xC8B2, 0xA14E, 0xC8B3, 0xA14F, 0xC8B4, 0xA150, 0xC8B5, 0xA151, 0xC8B6, 0xA152, 0xC8B7, 0xA153, 0xC8B8, 0xA154, 0xC8B9, 0xA155, 0xC8BA, 0xA156, 0xC8BB, 0xA157, 0xC8BE, 0xA158, 0xC8BF, 0xA159, 0xC8C0, 0xA15A, 0xC8C1, 0xA161, 0xC8C2, 0xA162, 0xC8C3, 0xA163, 0xC8C5, 0xA164, 0xC8C6, 0xA165, 0xC8C7, 0xA166, 0xC8C9, 0xA167, 0xC8CA, 0xA168, 0xC8CB, 0xA169, 0xC8CD, 0xA16A, 0xC8CE, 0xA16B, 0xC8CF, 0xA16C, 0xC8D0, 0xA16D, 0xC8D1, 0xA16E, 0xC8D2, 0xA16F, 0xC8D3, 0xA170, 0xC8D6, 0xA171, 0xC8D8, 0xA172, 0xC8DA, 0xA173, 0xC8DB, 0xA174, 0xC8DC, 0xA175, 0xC8DD, 0xA176, 0xC8DE, 0xA177, 0xC8DF, 0xA178, 0xC8E2, 0xA179, 0xC8E3, 0xA17A, 0xC8E5, 0xA181, 0xC8E6, 0xA182, 0xC8E7, 0xA183, 0xC8E8, 0xA184, 0xC8E9, 0xA185, 0xC8EA, 0xA186, 0xC8EB, 0xA187, 0xC8EC, 0xA188, 0xC8ED, 0xA189, 0xC8EE, 0xA18A, 0xC8EF, 0xA18B, 0xC8F0, 0xA18C, 0xC8F1, 0xA18D, 0xC8F2, 0xA18E, 0xC8F3, 0xA18F, 0xC8F4, 0xA190, 0xC8F6, 0xA191, 0xC8F7, 0xA192, 0xC8F8, 0xA193, 0xC8F9, 0xA194, 0xC8FA, 0xA195, 0xC8FB, 0xA196, 0xC8FE, 0xA197, 0xC8FF, 0xA198, 0xC901, 0xA199, 0xC902, 0xA19A, 0xC903, 0xA19B, 0xC907, 0xA19C, 0xC908, 0xA19D, 0xC909, 0xA19E, 0xC90A, 0xA19F, 0xC90B, 0xA1A0, 0xC90E, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, 0xA1A5, 0x2025, 0xA1A6, 0x2026, 0xA1A7, 0x00A8, 0xA1A8, 0x3003, 0xA1A9, 0x00AD, 0xA1AA, 0x2015, 0xA1AB, 0x2225, 0xA1AC, 0xFF3C, 0xA1AD, 0x223C, 0xA1AE, 0x2018, 0xA1AF, 0x2019, 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3010, 0xA1BD, 0x3011, 0xA1BE, 0x00B1, 0xA1BF, 0x00D7, 0xA1C0, 0x00F7, 0xA1C1, 0x2260, 0xA1C2, 0x2264, 0xA1C3, 0x2265, 0xA1C4, 0x221E, 0xA1C5, 0x2234, 0xA1C6, 0x00B0, 0xA1C7, 0x2032, 0xA1C8, 0x2033, 0xA1C9, 0x2103, 0xA1CA, 0x212B, 0xA1CB, 0xFFE0, 0xA1CC, 0xFFE1, 0xA1CD, 0xFFE5, 0xA1CE, 0x2642, 0xA1CF, 0x2640, 0xA1D0, 0x2220, 0xA1D1, 0x22A5, 0xA1D2, 0x2312, 0xA1D3, 0x2202, 0xA1D4, 0x2207, 0xA1D5, 0x2261, 0xA1D6, 0x2252, 0xA1D7, 0x00A7, 0xA1D8, 0x203B, 0xA1D9, 0x2606, 0xA1DA, 0x2605, 0xA1DB, 0x25CB, 0xA1DC, 0x25CF, 0xA1DD, 0x25CE, 0xA1DE, 0x25C7, 0xA1DF, 0x25C6, 0xA1E0, 0x25A1, 0xA1E1, 0x25A0, 0xA1E2, 0x25B3, 0xA1E3, 0x25B2, 0xA1E4, 0x25BD, 0xA1E5, 0x25BC, 0xA1E6, 0x2192, 0xA1E7, 0x2190, 0xA1E8, 0x2191, 0xA1E9, 0x2193, 0xA1EA, 0x2194, 0xA1EB, 0x3013, 0xA1EC, 0x226A, 0xA1ED, 0x226B, 0xA1EE, 0x221A, 0xA1EF, 0x223D, 0xA1F0, 0x221D, 0xA1F1, 0x2235, 0xA1F2, 0x222B, 0xA1F3, 0x222C, 0xA1F4, 0x2208, 0xA1F5, 0x220B, 0xA1F6, 0x2286, 0xA1F7, 0x2287, 0xA1F8, 0x2282, 0xA1F9, 0x2283, 0xA1FA, 0x222A, 0xA1FB, 0x2229, 0xA1FC, 0x2227, 0xA1FD, 0x2228, 0xA1FE, 0xFFE2, 0xA241, 0xC910, 0xA242, 0xC912, 0xA243, 0xC913, 0xA244, 0xC914, 0xA245, 0xC915, 0xA246, 0xC916, 0xA247, 0xC917, 0xA248, 0xC919, 0xA249, 0xC91A, 0xA24A, 0xC91B, 0xA24B, 0xC91C, 0xA24C, 0xC91D, 0xA24D, 0xC91E, 0xA24E, 0xC91F, 0xA24F, 0xC920, 0xA250, 0xC921, 0xA251, 0xC922, 0xA252, 0xC923, 0xA253, 0xC924, 0xA254, 0xC925, 0xA255, 0xC926, 0xA256, 0xC927, 0xA257, 0xC928, 0xA258, 0xC929, 0xA259, 0xC92A, 0xA25A, 0xC92B, 0xA261, 0xC92D, 0xA262, 0xC92E, 0xA263, 0xC92F, 0xA264, 0xC930, 0xA265, 0xC931, 0xA266, 0xC932, 0xA267, 0xC933, 0xA268, 0xC935, 0xA269, 0xC936, 0xA26A, 0xC937, 0xA26B, 0xC938, 0xA26C, 0xC939, 0xA26D, 0xC93A, 0xA26E, 0xC93B, 0xA26F, 0xC93C, 0xA270, 0xC93D, 0xA271, 0xC93E, 0xA272, 0xC93F, 0xA273, 0xC940, 0xA274, 0xC941, 0xA275, 0xC942, 0xA276, 0xC943, 0xA277, 0xC944, 0xA278, 0xC945, 0xA279, 0xC946, 0xA27A, 0xC947, 0xA281, 0xC948, 0xA282, 0xC949, 0xA283, 0xC94A, 0xA284, 0xC94B, 0xA285, 0xC94C, 0xA286, 0xC94D, 0xA287, 0xC94E, 0xA288, 0xC94F, 0xA289, 0xC952, 0xA28A, 0xC953, 0xA28B, 0xC955, 0xA28C, 0xC956, 0xA28D, 0xC957, 0xA28E, 0xC959, 0xA28F, 0xC95A, 0xA290, 0xC95B, 0xA291, 0xC95C, 0xA292, 0xC95D, 0xA293, 0xC95E, 0xA294, 0xC95F, 0xA295, 0xC962, 0xA296, 0xC964, 0xA297, 0xC965, 0xA298, 0xC966, 0xA299, 0xC967, 0xA29A, 0xC968, 0xA29B, 0xC969, 0xA29C, 0xC96A, 0xA29D, 0xC96B, 0xA29E, 0xC96D, 0xA29F, 0xC96E, 0xA2A0, 0xC96F, 0xA2A1, 0x21D2, 0xA2A2, 0x21D4, 0xA2A3, 0x2200, 0xA2A4, 0x2203, 0xA2A5, 0x00B4, 0xA2A6, 0xFF5E, 0xA2A7, 0x02C7, 0xA2A8, 0x02D8, 0xA2A9, 0x02DD, 0xA2AA, 0x02DA, 0xA2AB, 0x02D9, 0xA2AC, 0x00B8, 0xA2AD, 0x02DB, 0xA2AE, 0x00A1, 0xA2AF, 0x00BF, 0xA2B0, 0x02D0, 0xA2B1, 0x222E, 0xA2B2, 0x2211, 0xA2B3, 0x220F, 0xA2B4, 0x00A4, 0xA2B5, 0x2109, 0xA2B6, 0x2030, 0xA2B7, 0x25C1, 0xA2B8, 0x25C0, 0xA2B9, 0x25B7, 0xA2BA, 0x25B6, 0xA2BB, 0x2664, 0xA2BC, 0x2660, 0xA2BD, 0x2661, 0xA2BE, 0x2665, 0xA2BF, 0x2667, 0xA2C0, 0x2663, 0xA2C1, 0x2299, 0xA2C2, 0x25C8, 0xA2C3, 0x25A3, 0xA2C4, 0x25D0, 0xA2C5, 0x25D1, 0xA2C6, 0x2592, 0xA2C7, 0x25A4, 0xA2C8, 0x25A5, 0xA2C9, 0x25A8, 0xA2CA, 0x25A7, 0xA2CB, 0x25A6, 0xA2CC, 0x25A9, 0xA2CD, 0x2668, 0xA2CE, 0x260F, 0xA2CF, 0x260E, 0xA2D0, 0x261C, 0xA2D1, 0x261E, 0xA2D2, 0x00B6, 0xA2D3, 0x2020, 0xA2D4, 0x2021, 0xA2D5, 0x2195, 0xA2D6, 0x2197, 0xA2D7, 0x2199, 0xA2D8, 0x2196, 0xA2D9, 0x2198, 0xA2DA, 0x266D, 0xA2DB, 0x2669, 0xA2DC, 0x266A, 0xA2DD, 0x266C, 0xA2DE, 0x327F, 0xA2DF, 0x321C, 0xA2E0, 0x2116, 0xA2E1, 0x33C7, 0xA2E2, 0x2122, 0xA2E3, 0x33C2, 0xA2E4, 0x33D8, 0xA2E5, 0x2121, 0xA2E6, 0x20AC, 0xA2E7, 0x00AE, 0xA341, 0xC971, 0xA342, 0xC972, 0xA343, 0xC973, 0xA344, 0xC975, 0xA345, 0xC976, 0xA346, 0xC977, 0xA347, 0xC978, 0xA348, 0xC979, 0xA349, 0xC97A, 0xA34A, 0xC97B, 0xA34B, 0xC97D, 0xA34C, 0xC97E, 0xA34D, 0xC97F, 0xA34E, 0xC980, 0xA34F, 0xC981, 0xA350, 0xC982, 0xA351, 0xC983, 0xA352, 0xC984, 0xA353, 0xC985, 0xA354, 0xC986, 0xA355, 0xC987, 0xA356, 0xC98A, 0xA357, 0xC98B, 0xA358, 0xC98D, 0xA359, 0xC98E, 0xA35A, 0xC98F, 0xA361, 0xC991, 0xA362, 0xC992, 0xA363, 0xC993, 0xA364, 0xC994, 0xA365, 0xC995, 0xA366, 0xC996, 0xA367, 0xC997, 0xA368, 0xC99A, 0xA369, 0xC99C, 0xA36A, 0xC99E, 0xA36B, 0xC99F, 0xA36C, 0xC9A0, 0xA36D, 0xC9A1, 0xA36E, 0xC9A2, 0xA36F, 0xC9A3, 0xA370, 0xC9A4, 0xA371, 0xC9A5, 0xA372, 0xC9A6, 0xA373, 0xC9A7, 0xA374, 0xC9A8, 0xA375, 0xC9A9, 0xA376, 0xC9AA, 0xA377, 0xC9AB, 0xA378, 0xC9AC, 0xA379, 0xC9AD, 0xA37A, 0xC9AE, 0xA381, 0xC9AF, 0xA382, 0xC9B0, 0xA383, 0xC9B1, 0xA384, 0xC9B2, 0xA385, 0xC9B3, 0xA386, 0xC9B4, 0xA387, 0xC9B5, 0xA388, 0xC9B6, 0xA389, 0xC9B7, 0xA38A, 0xC9B8, 0xA38B, 0xC9B9, 0xA38C, 0xC9BA, 0xA38D, 0xC9BB, 0xA38E, 0xC9BC, 0xA38F, 0xC9BD, 0xA390, 0xC9BE, 0xA391, 0xC9BF, 0xA392, 0xC9C2, 0xA393, 0xC9C3, 0xA394, 0xC9C5, 0xA395, 0xC9C6, 0xA396, 0xC9C9, 0xA397, 0xC9CB, 0xA398, 0xC9CC, 0xA399, 0xC9CD, 0xA39A, 0xC9CE, 0xA39B, 0xC9CF, 0xA39C, 0xC9D2, 0xA39D, 0xC9D4, 0xA39E, 0xC9D7, 0xA39F, 0xC9D8, 0xA3A0, 0xC9DB, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFF04, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFFE6, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA441, 0xC9DE, 0xA442, 0xC9DF, 0xA443, 0xC9E1, 0xA444, 0xC9E3, 0xA445, 0xC9E5, 0xA446, 0xC9E6, 0xA447, 0xC9E8, 0xA448, 0xC9E9, 0xA449, 0xC9EA, 0xA44A, 0xC9EB, 0xA44B, 0xC9EE, 0xA44C, 0xC9F2, 0xA44D, 0xC9F3, 0xA44E, 0xC9F4, 0xA44F, 0xC9F5, 0xA450, 0xC9F6, 0xA451, 0xC9F7, 0xA452, 0xC9FA, 0xA453, 0xC9FB, 0xA454, 0xC9FD, 0xA455, 0xC9FE, 0xA456, 0xC9FF, 0xA457, 0xCA01, 0xA458, 0xCA02, 0xA459, 0xCA03, 0xA45A, 0xCA04, 0xA461, 0xCA05, 0xA462, 0xCA06, 0xA463, 0xCA07, 0xA464, 0xCA0A, 0xA465, 0xCA0E, 0xA466, 0xCA0F, 0xA467, 0xCA10, 0xA468, 0xCA11, 0xA469, 0xCA12, 0xA46A, 0xCA13, 0xA46B, 0xCA15, 0xA46C, 0xCA16, 0xA46D, 0xCA17, 0xA46E, 0xCA19, 0xA46F, 0xCA1A, 0xA470, 0xCA1B, 0xA471, 0xCA1C, 0xA472, 0xCA1D, 0xA473, 0xCA1E, 0xA474, 0xCA1F, 0xA475, 0xCA20, 0xA476, 0xCA21, 0xA477, 0xCA22, 0xA478, 0xCA23, 0xA479, 0xCA24, 0xA47A, 0xCA25, 0xA481, 0xCA26, 0xA482, 0xCA27, 0xA483, 0xCA28, 0xA484, 0xCA2A, 0xA485, 0xCA2B, 0xA486, 0xCA2C, 0xA487, 0xCA2D, 0xA488, 0xCA2E, 0xA489, 0xCA2F, 0xA48A, 0xCA30, 0xA48B, 0xCA31, 0xA48C, 0xCA32, 0xA48D, 0xCA33, 0xA48E, 0xCA34, 0xA48F, 0xCA35, 0xA490, 0xCA36, 0xA491, 0xCA37, 0xA492, 0xCA38, 0xA493, 0xCA39, 0xA494, 0xCA3A, 0xA495, 0xCA3B, 0xA496, 0xCA3C, 0xA497, 0xCA3D, 0xA498, 0xCA3E, 0xA499, 0xCA3F, 0xA49A, 0xCA40, 0xA49B, 0xCA41, 0xA49C, 0xCA42, 0xA49D, 0xCA43, 0xA49E, 0xCA44, 0xA49F, 0xCA45, 0xA4A0, 0xCA46, 0xA4A1, 0x3131, 0xA4A2, 0x3132, 0xA4A3, 0x3133, 0xA4A4, 0x3134, 0xA4A5, 0x3135, 0xA4A6, 0x3136, 0xA4A7, 0x3137, 0xA4A8, 0x3138, 0xA4A9, 0x3139, 0xA4AA, 0x313A, 0xA4AB, 0x313B, 0xA4AC, 0x313C, 0xA4AD, 0x313D, 0xA4AE, 0x313E, 0xA4AF, 0x313F, 0xA4B0, 0x3140, 0xA4B1, 0x3141, 0xA4B2, 0x3142, 0xA4B3, 0x3143, 0xA4B4, 0x3144, 0xA4B5, 0x3145, 0xA4B6, 0x3146, 0xA4B7, 0x3147, 0xA4B8, 0x3148, 0xA4B9, 0x3149, 0xA4BA, 0x314A, 0xA4BB, 0x314B, 0xA4BC, 0x314C, 0xA4BD, 0x314D, 0xA4BE, 0x314E, 0xA4BF, 0x314F, 0xA4C0, 0x3150, 0xA4C1, 0x3151, 0xA4C2, 0x3152, 0xA4C3, 0x3153, 0xA4C4, 0x3154, 0xA4C5, 0x3155, 0xA4C6, 0x3156, 0xA4C7, 0x3157, 0xA4C8, 0x3158, 0xA4C9, 0x3159, 0xA4CA, 0x315A, 0xA4CB, 0x315B, 0xA4CC, 0x315C, 0xA4CD, 0x315D, 0xA4CE, 0x315E, 0xA4CF, 0x315F, 0xA4D0, 0x3160, 0xA4D1, 0x3161, 0xA4D2, 0x3162, 0xA4D3, 0x3163, 0xA4D4, 0x3164, 0xA4D5, 0x3165, 0xA4D6, 0x3166, 0xA4D7, 0x3167, 0xA4D8, 0x3168, 0xA4D9, 0x3169, 0xA4DA, 0x316A, 0xA4DB, 0x316B, 0xA4DC, 0x316C, 0xA4DD, 0x316D, 0xA4DE, 0x316E, 0xA4DF, 0x316F, 0xA4E0, 0x3170, 0xA4E1, 0x3171, 0xA4E2, 0x3172, 0xA4E3, 0x3173, 0xA4E4, 0x3174, 0xA4E5, 0x3175, 0xA4E6, 0x3176, 0xA4E7, 0x3177, 0xA4E8, 0x3178, 0xA4E9, 0x3179, 0xA4EA, 0x317A, 0xA4EB, 0x317B, 0xA4EC, 0x317C, 0xA4ED, 0x317D, 0xA4EE, 0x317E, 0xA4EF, 0x317F, 0xA4F0, 0x3180, 0xA4F1, 0x3181, 0xA4F2, 0x3182, 0xA4F3, 0x3183, 0xA4F4, 0x3184, 0xA4F5, 0x3185, 0xA4F6, 0x3186, 0xA4F7, 0x3187, 0xA4F8, 0x3188, 0xA4F9, 0x3189, 0xA4FA, 0x318A, 0xA4FB, 0x318B, 0xA4FC, 0x318C, 0xA4FD, 0x318D, 0xA4FE, 0x318E, 0xA541, 0xCA47, 0xA542, 0xCA48, 0xA543, 0xCA49, 0xA544, 0xCA4A, 0xA545, 0xCA4B, 0xA546, 0xCA4E, 0xA547, 0xCA4F, 0xA548, 0xCA51, 0xA549, 0xCA52, 0xA54A, 0xCA53, 0xA54B, 0xCA55, 0xA54C, 0xCA56, 0xA54D, 0xCA57, 0xA54E, 0xCA58, 0xA54F, 0xCA59, 0xA550, 0xCA5A, 0xA551, 0xCA5B, 0xA552, 0xCA5E, 0xA553, 0xCA62, 0xA554, 0xCA63, 0xA555, 0xCA64, 0xA556, 0xCA65, 0xA557, 0xCA66, 0xA558, 0xCA67, 0xA559, 0xCA69, 0xA55A, 0xCA6A, 0xA561, 0xCA6B, 0xA562, 0xCA6C, 0xA563, 0xCA6D, 0xA564, 0xCA6E, 0xA565, 0xCA6F, 0xA566, 0xCA70, 0xA567, 0xCA71, 0xA568, 0xCA72, 0xA569, 0xCA73, 0xA56A, 0xCA74, 0xA56B, 0xCA75, 0xA56C, 0xCA76, 0xA56D, 0xCA77, 0xA56E, 0xCA78, 0xA56F, 0xCA79, 0xA570, 0xCA7A, 0xA571, 0xCA7B, 0xA572, 0xCA7C, 0xA573, 0xCA7E, 0xA574, 0xCA7F, 0xA575, 0xCA80, 0xA576, 0xCA81, 0xA577, 0xCA82, 0xA578, 0xCA83, 0xA579, 0xCA85, 0xA57A, 0xCA86, 0xA581, 0xCA87, 0xA582, 0xCA88, 0xA583, 0xCA89, 0xA584, 0xCA8A, 0xA585, 0xCA8B, 0xA586, 0xCA8C, 0xA587, 0xCA8D, 0xA588, 0xCA8E, 0xA589, 0xCA8F, 0xA58A, 0xCA90, 0xA58B, 0xCA91, 0xA58C, 0xCA92, 0xA58D, 0xCA93, 0xA58E, 0xCA94, 0xA58F, 0xCA95, 0xA590, 0xCA96, 0xA591, 0xCA97, 0xA592, 0xCA99, 0xA593, 0xCA9A, 0xA594, 0xCA9B, 0xA595, 0xCA9C, 0xA596, 0xCA9D, 0xA597, 0xCA9E, 0xA598, 0xCA9F, 0xA599, 0xCAA0, 0xA59A, 0xCAA1, 0xA59B, 0xCAA2, 0xA59C, 0xCAA3, 0xA59D, 0xCAA4, 0xA59E, 0xCAA5, 0xA59F, 0xCAA6, 0xA5A0, 0xCAA7, 0xA5A1, 0x2170, 0xA5A2, 0x2171, 0xA5A3, 0x2172, 0xA5A4, 0x2173, 0xA5A5, 0x2174, 0xA5A6, 0x2175, 0xA5A7, 0x2176, 0xA5A8, 0x2177, 0xA5A9, 0x2178, 0xA5AA, 0x2179, 0xA5B0, 0x2160, 0xA5B1, 0x2161, 0xA5B2, 0x2162, 0xA5B3, 0x2163, 0xA5B4, 0x2164, 0xA5B5, 0x2165, 0xA5B6, 0x2166, 0xA5B7, 0x2167, 0xA5B8, 0x2168, 0xA5B9, 0x2169, 0xA5C1, 0x0391, 0xA5C2, 0x0392, 0xA5C3, 0x0393, 0xA5C4, 0x0394, 0xA5C5, 0x0395, 0xA5C6, 0x0396, 0xA5C7, 0x0397, 0xA5C8, 0x0398, 0xA5C9, 0x0399, 0xA5CA, 0x039A, 0xA5CB, 0x039B, 0xA5CC, 0x039C, 0xA5CD, 0x039D, 0xA5CE, 0x039E, 0xA5CF, 0x039F, 0xA5D0, 0x03A0, 0xA5D1, 0x03A1, 0xA5D2, 0x03A3, 0xA5D3, 0x03A4, 0xA5D4, 0x03A5, 0xA5D5, 0x03A6, 0xA5D6, 0x03A7, 0xA5D7, 0x03A8, 0xA5D8, 0x03A9, 0xA5E1, 0x03B1, 0xA5E2, 0x03B2, 0xA5E3, 0x03B3, 0xA5E4, 0x03B4, 0xA5E5, 0x03B5, 0xA5E6, 0x03B6, 0xA5E7, 0x03B7, 0xA5E8, 0x03B8, 0xA5E9, 0x03B9, 0xA5EA, 0x03BA, 0xA5EB, 0x03BB, 0xA5EC, 0x03BC, 0xA5ED, 0x03BD, 0xA5EE, 0x03BE, 0xA5EF, 0x03BF, 0xA5F0, 0x03C0, 0xA5F1, 0x03C1, 0xA5F2, 0x03C3, 0xA5F3, 0x03C4, 0xA5F4, 0x03C5, 0xA5F5, 0x03C6, 0xA5F6, 0x03C7, 0xA5F7, 0x03C8, 0xA5F8, 0x03C9, 0xA641, 0xCAA8, 0xA642, 0xCAA9, 0xA643, 0xCAAA, 0xA644, 0xCAAB, 0xA645, 0xCAAC, 0xA646, 0xCAAD, 0xA647, 0xCAAE, 0xA648, 0xCAAF, 0xA649, 0xCAB0, 0xA64A, 0xCAB1, 0xA64B, 0xCAB2, 0xA64C, 0xCAB3, 0xA64D, 0xCAB4, 0xA64E, 0xCAB5, 0xA64F, 0xCAB6, 0xA650, 0xCAB7, 0xA651, 0xCAB8, 0xA652, 0xCAB9, 0xA653, 0xCABA, 0xA654, 0xCABB, 0xA655, 0xCABE, 0xA656, 0xCABF, 0xA657, 0xCAC1, 0xA658, 0xCAC2, 0xA659, 0xCAC3, 0xA65A, 0xCAC5, 0xA661, 0xCAC6, 0xA662, 0xCAC7, 0xA663, 0xCAC8, 0xA664, 0xCAC9, 0xA665, 0xCACA, 0xA666, 0xCACB, 0xA667, 0xCACE, 0xA668, 0xCAD0, 0xA669, 0xCAD2, 0xA66A, 0xCAD4, 0xA66B, 0xCAD5, 0xA66C, 0xCAD6, 0xA66D, 0xCAD7, 0xA66E, 0xCADA, 0xA66F, 0xCADB, 0xA670, 0xCADC, 0xA671, 0xCADD, 0xA672, 0xCADE, 0xA673, 0xCADF, 0xA674, 0xCAE1, 0xA675, 0xCAE2, 0xA676, 0xCAE3, 0xA677, 0xCAE4, 0xA678, 0xCAE5, 0xA679, 0xCAE6, 0xA67A, 0xCAE7, 0xA681, 0xCAE8, 0xA682, 0xCAE9, 0xA683, 0xCAEA, 0xA684, 0xCAEB, 0xA685, 0xCAED, 0xA686, 0xCAEE, 0xA687, 0xCAEF, 0xA688, 0xCAF0, 0xA689, 0xCAF1, 0xA68A, 0xCAF2, 0xA68B, 0xCAF3, 0xA68C, 0xCAF5, 0xA68D, 0xCAF6, 0xA68E, 0xCAF7, 0xA68F, 0xCAF8, 0xA690, 0xCAF9, 0xA691, 0xCAFA, 0xA692, 0xCAFB, 0xA693, 0xCAFC, 0xA694, 0xCAFD, 0xA695, 0xCAFE, 0xA696, 0xCAFF, 0xA697, 0xCB00, 0xA698, 0xCB01, 0xA699, 0xCB02, 0xA69A, 0xCB03, 0xA69B, 0xCB04, 0xA69C, 0xCB05, 0xA69D, 0xCB06, 0xA69E, 0xCB07, 0xA69F, 0xCB09, 0xA6A0, 0xCB0A, 0xA6A1, 0x2500, 0xA6A2, 0x2502, 0xA6A3, 0x250C, 0xA6A4, 0x2510, 0xA6A5, 0x2518, 0xA6A6, 0x2514, 0xA6A7, 0x251C, 0xA6A8, 0x252C, 0xA6A9, 0x2524, 0xA6AA, 0x2534, 0xA6AB, 0x253C, 0xA6AC, 0x2501, 0xA6AD, 0x2503, 0xA6AE, 0x250F, 0xA6AF, 0x2513, 0xA6B0, 0x251B, 0xA6B1, 0x2517, 0xA6B2, 0x2523, 0xA6B3, 0x2533, 0xA6B4, 0x252B, 0xA6B5, 0x253B, 0xA6B6, 0x254B, 0xA6B7, 0x2520, 0xA6B8, 0x252F, 0xA6B9, 0x2528, 0xA6BA, 0x2537, 0xA6BB, 0x253F, 0xA6BC, 0x251D, 0xA6BD, 0x2530, 0xA6BE, 0x2525, 0xA6BF, 0x2538, 0xA6C0, 0x2542, 0xA6C1, 0x2512, 0xA6C2, 0x2511, 0xA6C3, 0x251A, 0xA6C4, 0x2519, 0xA6C5, 0x2516, 0xA6C6, 0x2515, 0xA6C7, 0x250E, 0xA6C8, 0x250D, 0xA6C9, 0x251E, 0xA6CA, 0x251F, 0xA6CB, 0x2521, 0xA6CC, 0x2522, 0xA6CD, 0x2526, 0xA6CE, 0x2527, 0xA6CF, 0x2529, 0xA6D0, 0x252A, 0xA6D1, 0x252D, 0xA6D2, 0x252E, 0xA6D3, 0x2531, 0xA6D4, 0x2532, 0xA6D5, 0x2535, 0xA6D6, 0x2536, 0xA6D7, 0x2539, 0xA6D8, 0x253A, 0xA6D9, 0x253D, 0xA6DA, 0x253E, 0xA6DB, 0x2540, 0xA6DC, 0x2541, 0xA6DD, 0x2543, 0xA6DE, 0x2544, 0xA6DF, 0x2545, 0xA6E0, 0x2546, 0xA6E1, 0x2547, 0xA6E2, 0x2548, 0xA6E3, 0x2549, 0xA6E4, 0x254A, 0xA741, 0xCB0B, 0xA742, 0xCB0C, 0xA743, 0xCB0D, 0xA744, 0xCB0E, 0xA745, 0xCB0F, 0xA746, 0xCB11, 0xA747, 0xCB12, 0xA748, 0xCB13, 0xA749, 0xCB15, 0xA74A, 0xCB16, 0xA74B, 0xCB17, 0xA74C, 0xCB19, 0xA74D, 0xCB1A, 0xA74E, 0xCB1B, 0xA74F, 0xCB1C, 0xA750, 0xCB1D, 0xA751, 0xCB1E, 0xA752, 0xCB1F, 0xA753, 0xCB22, 0xA754, 0xCB23, 0xA755, 0xCB24, 0xA756, 0xCB25, 0xA757, 0xCB26, 0xA758, 0xCB27, 0xA759, 0xCB28, 0xA75A, 0xCB29, 0xA761, 0xCB2A, 0xA762, 0xCB2B, 0xA763, 0xCB2C, 0xA764, 0xCB2D, 0xA765, 0xCB2E, 0xA766, 0xCB2F, 0xA767, 0xCB30, 0xA768, 0xCB31, 0xA769, 0xCB32, 0xA76A, 0xCB33, 0xA76B, 0xCB34, 0xA76C, 0xCB35, 0xA76D, 0xCB36, 0xA76E, 0xCB37, 0xA76F, 0xCB38, 0xA770, 0xCB39, 0xA771, 0xCB3A, 0xA772, 0xCB3B, 0xA773, 0xCB3C, 0xA774, 0xCB3D, 0xA775, 0xCB3E, 0xA776, 0xCB3F, 0xA777, 0xCB40, 0xA778, 0xCB42, 0xA779, 0xCB43, 0xA77A, 0xCB44, 0xA781, 0xCB45, 0xA782, 0xCB46, 0xA783, 0xCB47, 0xA784, 0xCB4A, 0xA785, 0xCB4B, 0xA786, 0xCB4D, 0xA787, 0xCB4E, 0xA788, 0xCB4F, 0xA789, 0xCB51, 0xA78A, 0xCB52, 0xA78B, 0xCB53, 0xA78C, 0xCB54, 0xA78D, 0xCB55, 0xA78E, 0xCB56, 0xA78F, 0xCB57, 0xA790, 0xCB5A, 0xA791, 0xCB5B, 0xA792, 0xCB5C, 0xA793, 0xCB5E, 0xA794, 0xCB5F, 0xA795, 0xCB60, 0xA796, 0xCB61, 0xA797, 0xCB62, 0xA798, 0xCB63, 0xA799, 0xCB65, 0xA79A, 0xCB66, 0xA79B, 0xCB67, 0xA79C, 0xCB68, 0xA79D, 0xCB69, 0xA79E, 0xCB6A, 0xA79F, 0xCB6B, 0xA7A0, 0xCB6C, 0xA7A1, 0x3395, 0xA7A2, 0x3396, 0xA7A3, 0x3397, 0xA7A4, 0x2113, 0xA7A5, 0x3398, 0xA7A6, 0x33C4, 0xA7A7, 0x33A3, 0xA7A8, 0x33A4, 0xA7A9, 0x33A5, 0xA7AA, 0x33A6, 0xA7AB, 0x3399, 0xA7AC, 0x339A, 0xA7AD, 0x339B, 0xA7AE, 0x339C, 0xA7AF, 0x339D, 0xA7B0, 0x339E, 0xA7B1, 0x339F, 0xA7B2, 0x33A0, 0xA7B3, 0x33A1, 0xA7B4, 0x33A2, 0xA7B5, 0x33CA, 0xA7B6, 0x338D, 0xA7B7, 0x338E, 0xA7B8, 0x338F, 0xA7B9, 0x33CF, 0xA7BA, 0x3388, 0xA7BB, 0x3389, 0xA7BC, 0x33C8, 0xA7BD, 0x33A7, 0xA7BE, 0x33A8, 0xA7BF, 0x33B0, 0xA7C0, 0x33B1, 0xA7C1, 0x33B2, 0xA7C2, 0x33B3, 0xA7C3, 0x33B4, 0xA7C4, 0x33B5, 0xA7C5, 0x33B6, 0xA7C6, 0x33B7, 0xA7C7, 0x33B8, 0xA7C8, 0x33B9, 0xA7C9, 0x3380, 0xA7CA, 0x3381, 0xA7CB, 0x3382, 0xA7CC, 0x3383, 0xA7CD, 0x3384, 0xA7CE, 0x33BA, 0xA7CF, 0x33BB, 0xA7D0, 0x33BC, 0xA7D1, 0x33BD, 0xA7D2, 0x33BE, 0xA7D3, 0x33BF, 0xA7D4, 0x3390, 0xA7D5, 0x3391, 0xA7D6, 0x3392, 0xA7D7, 0x3393, 0xA7D8, 0x3394, 0xA7D9, 0x2126, 0xA7DA, 0x33C0, 0xA7DB, 0x33C1, 0xA7DC, 0x338A, 0xA7DD, 0x338B, 0xA7DE, 0x338C, 0xA7DF, 0x33D6, 0xA7E0, 0x33C5, 0xA7E1, 0x33AD, 0xA7E2, 0x33AE, 0xA7E3, 0x33AF, 0xA7E4, 0x33DB, 0xA7E5, 0x33A9, 0xA7E6, 0x33AA, 0xA7E7, 0x33AB, 0xA7E8, 0x33AC, 0xA7E9, 0x33DD, 0xA7EA, 0x33D0, 0xA7EB, 0x33D3, 0xA7EC, 0x33C3, 0xA7ED, 0x33C9, 0xA7EE, 0x33DC, 0xA7EF, 0x33C6, 0xA841, 0xCB6D, 0xA842, 0xCB6E, 0xA843, 0xCB6F, 0xA844, 0xCB70, 0xA845, 0xCB71, 0xA846, 0xCB72, 0xA847, 0xCB73, 0xA848, 0xCB74, 0xA849, 0xCB75, 0xA84A, 0xCB76, 0xA84B, 0xCB77, 0xA84C, 0xCB7A, 0xA84D, 0xCB7B, 0xA84E, 0xCB7C, 0xA84F, 0xCB7D, 0xA850, 0xCB7E, 0xA851, 0xCB7F, 0xA852, 0xCB80, 0xA853, 0xCB81, 0xA854, 0xCB82, 0xA855, 0xCB83, 0xA856, 0xCB84, 0xA857, 0xCB85, 0xA858, 0xCB86, 0xA859, 0xCB87, 0xA85A, 0xCB88, 0xA861, 0xCB89, 0xA862, 0xCB8A, 0xA863, 0xCB8B, 0xA864, 0xCB8C, 0xA865, 0xCB8D, 0xA866, 0xCB8E, 0xA867, 0xCB8F, 0xA868, 0xCB90, 0xA869, 0xCB91, 0xA86A, 0xCB92, 0xA86B, 0xCB93, 0xA86C, 0xCB94, 0xA86D, 0xCB95, 0xA86E, 0xCB96, 0xA86F, 0xCB97, 0xA870, 0xCB98, 0xA871, 0xCB99, 0xA872, 0xCB9A, 0xA873, 0xCB9B, 0xA874, 0xCB9D, 0xA875, 0xCB9E, 0xA876, 0xCB9F, 0xA877, 0xCBA0, 0xA878, 0xCBA1, 0xA879, 0xCBA2, 0xA87A, 0xCBA3, 0xA881, 0xCBA4, 0xA882, 0xCBA5, 0xA883, 0xCBA6, 0xA884, 0xCBA7, 0xA885, 0xCBA8, 0xA886, 0xCBA9, 0xA887, 0xCBAA, 0xA888, 0xCBAB, 0xA889, 0xCBAC, 0xA88A, 0xCBAD, 0xA88B, 0xCBAE, 0xA88C, 0xCBAF, 0xA88D, 0xCBB0, 0xA88E, 0xCBB1, 0xA88F, 0xCBB2, 0xA890, 0xCBB3, 0xA891, 0xCBB4, 0xA892, 0xCBB5, 0xA893, 0xCBB6, 0xA894, 0xCBB7, 0xA895, 0xCBB9, 0xA896, 0xCBBA, 0xA897, 0xCBBB, 0xA898, 0xCBBC, 0xA899, 0xCBBD, 0xA89A, 0xCBBE, 0xA89B, 0xCBBF, 0xA89C, 0xCBC0, 0xA89D, 0xCBC1, 0xA89E, 0xCBC2, 0xA89F, 0xCBC3, 0xA8A0, 0xCBC4, 0xA8A1, 0x00C6, 0xA8A2, 0x00D0, 0xA8A3, 0x00AA, 0xA8A4, 0x0126, 0xA8A6, 0x0132, 0xA8A8, 0x013F, 0xA8A9, 0x0141, 0xA8AA, 0x00D8, 0xA8AB, 0x0152, 0xA8AC, 0x00BA, 0xA8AD, 0x00DE, 0xA8AE, 0x0166, 0xA8AF, 0x014A, 0xA8B1, 0x3260, 0xA8B2, 0x3261, 0xA8B3, 0x3262, 0xA8B4, 0x3263, 0xA8B5, 0x3264, 0xA8B6, 0x3265, 0xA8B7, 0x3266, 0xA8B8, 0x3267, 0xA8B9, 0x3268, 0xA8BA, 0x3269, 0xA8BB, 0x326A, 0xA8BC, 0x326B, 0xA8BD, 0x326C, 0xA8BE, 0x326D, 0xA8BF, 0x326E, 0xA8C0, 0x326F, 0xA8C1, 0x3270, 0xA8C2, 0x3271, 0xA8C3, 0x3272, 0xA8C4, 0x3273, 0xA8C5, 0x3274, 0xA8C6, 0x3275, 0xA8C7, 0x3276, 0xA8C8, 0x3277, 0xA8C9, 0x3278, 0xA8CA, 0x3279, 0xA8CB, 0x327A, 0xA8CC, 0x327B, 0xA8CD, 0x24D0, 0xA8CE, 0x24D1, 0xA8CF, 0x24D2, 0xA8D0, 0x24D3, 0xA8D1, 0x24D4, 0xA8D2, 0x24D5, 0xA8D3, 0x24D6, 0xA8D4, 0x24D7, 0xA8D5, 0x24D8, 0xA8D6, 0x24D9, 0xA8D7, 0x24DA, 0xA8D8, 0x24DB, 0xA8D9, 0x24DC, 0xA8DA, 0x24DD, 0xA8DB, 0x24DE, 0xA8DC, 0x24DF, 0xA8DD, 0x24E0, 0xA8DE, 0x24E1, 0xA8DF, 0x24E2, 0xA8E0, 0x24E3, 0xA8E1, 0x24E4, 0xA8E2, 0x24E5, 0xA8E3, 0x24E6, 0xA8E4, 0x24E7, 0xA8E5, 0x24E8, 0xA8E6, 0x24E9, 0xA8E7, 0x2460, 0xA8E8, 0x2461, 0xA8E9, 0x2462, 0xA8EA, 0x2463, 0xA8EB, 0x2464, 0xA8EC, 0x2465, 0xA8ED, 0x2466, 0xA8EE, 0x2467, 0xA8EF, 0x2468, 0xA8F0, 0x2469, 0xA8F1, 0x246A, 0xA8F2, 0x246B, 0xA8F3, 0x246C, 0xA8F4, 0x246D, 0xA8F5, 0x246E, 0xA8F6, 0x00BD, 0xA8F7, 0x2153, 0xA8F8, 0x2154, 0xA8F9, 0x00BC, 0xA8FA, 0x00BE, 0xA8FB, 0x215B, 0xA8FC, 0x215C, 0xA8FD, 0x215D, 0xA8FE, 0x215E, 0xA941, 0xCBC5, 0xA942, 0xCBC6, 0xA943, 0xCBC7, 0xA944, 0xCBC8, 0xA945, 0xCBC9, 0xA946, 0xCBCA, 0xA947, 0xCBCB, 0xA948, 0xCBCC, 0xA949, 0xCBCD, 0xA94A, 0xCBCE, 0xA94B, 0xCBCF, 0xA94C, 0xCBD0, 0xA94D, 0xCBD1, 0xA94E, 0xCBD2, 0xA94F, 0xCBD3, 0xA950, 0xCBD5, 0xA951, 0xCBD6, 0xA952, 0xCBD7, 0xA953, 0xCBD8, 0xA954, 0xCBD9, 0xA955, 0xCBDA, 0xA956, 0xCBDB, 0xA957, 0xCBDC, 0xA958, 0xCBDD, 0xA959, 0xCBDE, 0xA95A, 0xCBDF, 0xA961, 0xCBE0, 0xA962, 0xCBE1, 0xA963, 0xCBE2, 0xA964, 0xCBE3, 0xA965, 0xCBE5, 0xA966, 0xCBE6, 0xA967, 0xCBE8, 0xA968, 0xCBEA, 0xA969, 0xCBEB, 0xA96A, 0xCBEC, 0xA96B, 0xCBED, 0xA96C, 0xCBEE, 0xA96D, 0xCBEF, 0xA96E, 0xCBF0, 0xA96F, 0xCBF1, 0xA970, 0xCBF2, 0xA971, 0xCBF3, 0xA972, 0xCBF4, 0xA973, 0xCBF5, 0xA974, 0xCBF6, 0xA975, 0xCBF7, 0xA976, 0xCBF8, 0xA977, 0xCBF9, 0xA978, 0xCBFA, 0xA979, 0xCBFB, 0xA97A, 0xCBFC, 0xA981, 0xCBFD, 0xA982, 0xCBFE, 0xA983, 0xCBFF, 0xA984, 0xCC00, 0xA985, 0xCC01, 0xA986, 0xCC02, 0xA987, 0xCC03, 0xA988, 0xCC04, 0xA989, 0xCC05, 0xA98A, 0xCC06, 0xA98B, 0xCC07, 0xA98C, 0xCC08, 0xA98D, 0xCC09, 0xA98E, 0xCC0A, 0xA98F, 0xCC0B, 0xA990, 0xCC0E, 0xA991, 0xCC0F, 0xA992, 0xCC11, 0xA993, 0xCC12, 0xA994, 0xCC13, 0xA995, 0xCC15, 0xA996, 0xCC16, 0xA997, 0xCC17, 0xA998, 0xCC18, 0xA999, 0xCC19, 0xA99A, 0xCC1A, 0xA99B, 0xCC1B, 0xA99C, 0xCC1E, 0xA99D, 0xCC1F, 0xA99E, 0xCC20, 0xA99F, 0xCC23, 0xA9A0, 0xCC24, 0xA9A1, 0x00E6, 0xA9A2, 0x0111, 0xA9A3, 0x00F0, 0xA9A4, 0x0127, 0xA9A5, 0x0131, 0xA9A6, 0x0133, 0xA9A7, 0x0138, 0xA9A8, 0x0140, 0xA9A9, 0x0142, 0xA9AA, 0x00F8, 0xA9AB, 0x0153, 0xA9AC, 0x00DF, 0xA9AD, 0x00FE, 0xA9AE, 0x0167, 0xA9AF, 0x014B, 0xA9B0, 0x0149, 0xA9B1, 0x3200, 0xA9B2, 0x3201, 0xA9B3, 0x3202, 0xA9B4, 0x3203, 0xA9B5, 0x3204, 0xA9B6, 0x3205, 0xA9B7, 0x3206, 0xA9B8, 0x3207, 0xA9B9, 0x3208, 0xA9BA, 0x3209, 0xA9BB, 0x320A, 0xA9BC, 0x320B, 0xA9BD, 0x320C, 0xA9BE, 0x320D, 0xA9BF, 0x320E, 0xA9C0, 0x320F, 0xA9C1, 0x3210, 0xA9C2, 0x3211, 0xA9C3, 0x3212, 0xA9C4, 0x3213, 0xA9C5, 0x3214, 0xA9C6, 0x3215, 0xA9C7, 0x3216, 0xA9C8, 0x3217, 0xA9C9, 0x3218, 0xA9CA, 0x3219, 0xA9CB, 0x321A, 0xA9CC, 0x321B, 0xA9CD, 0x249C, 0xA9CE, 0x249D, 0xA9CF, 0x249E, 0xA9D0, 0x249F, 0xA9D1, 0x24A0, 0xA9D2, 0x24A1, 0xA9D3, 0x24A2, 0xA9D4, 0x24A3, 0xA9D5, 0x24A4, 0xA9D6, 0x24A5, 0xA9D7, 0x24A6, 0xA9D8, 0x24A7, 0xA9D9, 0x24A8, 0xA9DA, 0x24A9, 0xA9DB, 0x24AA, 0xA9DC, 0x24AB, 0xA9DD, 0x24AC, 0xA9DE, 0x24AD, 0xA9DF, 0x24AE, 0xA9E0, 0x24AF, 0xA9E1, 0x24B0, 0xA9E2, 0x24B1, 0xA9E3, 0x24B2, 0xA9E4, 0x24B3, 0xA9E5, 0x24B4, 0xA9E6, 0x24B5, 0xA9E7, 0x2474, 0xA9E8, 0x2475, 0xA9E9, 0x2476, 0xA9EA, 0x2477, 0xA9EB, 0x2478, 0xA9EC, 0x2479, 0xA9ED, 0x247A, 0xA9EE, 0x247B, 0xA9EF, 0x247C, 0xA9F0, 0x247D, 0xA9F1, 0x247E, 0xA9F2, 0x247F, 0xA9F3, 0x2480, 0xA9F4, 0x2481, 0xA9F5, 0x2482, 0xA9F6, 0x00B9, 0xA9F7, 0x00B2, 0xA9F8, 0x00B3, 0xA9F9, 0x2074, 0xA9FA, 0x207F, 0xA9FB, 0x2081, 0xA9FC, 0x2082, 0xA9FD, 0x2083, 0xA9FE, 0x2084, 0xAA41, 0xCC25, 0xAA42, 0xCC26, 0xAA43, 0xCC2A, 0xAA44, 0xCC2B, 0xAA45, 0xCC2D, 0xAA46, 0xCC2F, 0xAA47, 0xCC31, 0xAA48, 0xCC32, 0xAA49, 0xCC33, 0xAA4A, 0xCC34, 0xAA4B, 0xCC35, 0xAA4C, 0xCC36, 0xAA4D, 0xCC37, 0xAA4E, 0xCC3A, 0xAA4F, 0xCC3F, 0xAA50, 0xCC40, 0xAA51, 0xCC41, 0xAA52, 0xCC42, 0xAA53, 0xCC43, 0xAA54, 0xCC46, 0xAA55, 0xCC47, 0xAA56, 0xCC49, 0xAA57, 0xCC4A, 0xAA58, 0xCC4B, 0xAA59, 0xCC4D, 0xAA5A, 0xCC4E, 0xAA61, 0xCC4F, 0xAA62, 0xCC50, 0xAA63, 0xCC51, 0xAA64, 0xCC52, 0xAA65, 0xCC53, 0xAA66, 0xCC56, 0xAA67, 0xCC5A, 0xAA68, 0xCC5B, 0xAA69, 0xCC5C, 0xAA6A, 0xCC5D, 0xAA6B, 0xCC5E, 0xAA6C, 0xCC5F, 0xAA6D, 0xCC61, 0xAA6E, 0xCC62, 0xAA6F, 0xCC63, 0xAA70, 0xCC65, 0xAA71, 0xCC67, 0xAA72, 0xCC69, 0xAA73, 0xCC6A, 0xAA74, 0xCC6B, 0xAA75, 0xCC6C, 0xAA76, 0xCC6D, 0xAA77, 0xCC6E, 0xAA78, 0xCC6F, 0xAA79, 0xCC71, 0xAA7A, 0xCC72, 0xAA81, 0xCC73, 0xAA82, 0xCC74, 0xAA83, 0xCC76, 0xAA84, 0xCC77, 0xAA85, 0xCC78, 0xAA86, 0xCC79, 0xAA87, 0xCC7A, 0xAA88, 0xCC7B, 0xAA89, 0xCC7C, 0xAA8A, 0xCC7D, 0xAA8B, 0xCC7E, 0xAA8C, 0xCC7F, 0xAA8D, 0xCC80, 0xAA8E, 0xCC81, 0xAA8F, 0xCC82, 0xAA90, 0xCC83, 0xAA91, 0xCC84, 0xAA92, 0xCC85, 0xAA93, 0xCC86, 0xAA94, 0xCC87, 0xAA95, 0xCC88, 0xAA96, 0xCC89, 0xAA97, 0xCC8A, 0xAA98, 0xCC8B, 0xAA99, 0xCC8C, 0xAA9A, 0xCC8D, 0xAA9B, 0xCC8E, 0xAA9C, 0xCC8F, 0xAA9D, 0xCC90, 0xAA9E, 0xCC91, 0xAA9F, 0xCC92, 0xAAA0, 0xCC93, 0xAAA1, 0x3041, 0xAAA2, 0x3042, 0xAAA3, 0x3043, 0xAAA4, 0x3044, 0xAAA5, 0x3045, 0xAAA6, 0x3046, 0xAAA7, 0x3047, 0xAAA8, 0x3048, 0xAAA9, 0x3049, 0xAAAA, 0x304A, 0xAAAB, 0x304B, 0xAAAC, 0x304C, 0xAAAD, 0x304D, 0xAAAE, 0x304E, 0xAAAF, 0x304F, 0xAAB0, 0x3050, 0xAAB1, 0x3051, 0xAAB2, 0x3052, 0xAAB3, 0x3053, 0xAAB4, 0x3054, 0xAAB5, 0x3055, 0xAAB6, 0x3056, 0xAAB7, 0x3057, 0xAAB8, 0x3058, 0xAAB9, 0x3059, 0xAABA, 0x305A, 0xAABB, 0x305B, 0xAABC, 0x305C, 0xAABD, 0x305D, 0xAABE, 0x305E, 0xAABF, 0x305F, 0xAAC0, 0x3060, 0xAAC1, 0x3061, 0xAAC2, 0x3062, 0xAAC3, 0x3063, 0xAAC4, 0x3064, 0xAAC5, 0x3065, 0xAAC6, 0x3066, 0xAAC7, 0x3067, 0xAAC8, 0x3068, 0xAAC9, 0x3069, 0xAACA, 0x306A, 0xAACB, 0x306B, 0xAACC, 0x306C, 0xAACD, 0x306D, 0xAACE, 0x306E, 0xAACF, 0x306F, 0xAAD0, 0x3070, 0xAAD1, 0x3071, 0xAAD2, 0x3072, 0xAAD3, 0x3073, 0xAAD4, 0x3074, 0xAAD5, 0x3075, 0xAAD6, 0x3076, 0xAAD7, 0x3077, 0xAAD8, 0x3078, 0xAAD9, 0x3079, 0xAADA, 0x307A, 0xAADB, 0x307B, 0xAADC, 0x307C, 0xAADD, 0x307D, 0xAADE, 0x307E, 0xAADF, 0x307F, 0xAAE0, 0x3080, 0xAAE1, 0x3081, 0xAAE2, 0x3082, 0xAAE3, 0x3083, 0xAAE4, 0x3084, 0xAAE5, 0x3085, 0xAAE6, 0x3086, 0xAAE7, 0x3087, 0xAAE8, 0x3088, 0xAAE9, 0x3089, 0xAAEA, 0x308A, 0xAAEB, 0x308B, 0xAAEC, 0x308C, 0xAAED, 0x308D, 0xAAEE, 0x308E, 0xAAEF, 0x308F, 0xAAF0, 0x3090, 0xAAF1, 0x3091, 0xAAF2, 0x3092, 0xAAF3, 0x3093, 0xAB41, 0xCC94, 0xAB42, 0xCC95, 0xAB43, 0xCC96, 0xAB44, 0xCC97, 0xAB45, 0xCC9A, 0xAB46, 0xCC9B, 0xAB47, 0xCC9D, 0xAB48, 0xCC9E, 0xAB49, 0xCC9F, 0xAB4A, 0xCCA1, 0xAB4B, 0xCCA2, 0xAB4C, 0xCCA3, 0xAB4D, 0xCCA4, 0xAB4E, 0xCCA5, 0xAB4F, 0xCCA6, 0xAB50, 0xCCA7, 0xAB51, 0xCCAA, 0xAB52, 0xCCAE, 0xAB53, 0xCCAF, 0xAB54, 0xCCB0, 0xAB55, 0xCCB1, 0xAB56, 0xCCB2, 0xAB57, 0xCCB3, 0xAB58, 0xCCB6, 0xAB59, 0xCCB7, 0xAB5A, 0xCCB9, 0xAB61, 0xCCBA, 0xAB62, 0xCCBB, 0xAB63, 0xCCBD, 0xAB64, 0xCCBE, 0xAB65, 0xCCBF, 0xAB66, 0xCCC0, 0xAB67, 0xCCC1, 0xAB68, 0xCCC2, 0xAB69, 0xCCC3, 0xAB6A, 0xCCC6, 0xAB6B, 0xCCC8, 0xAB6C, 0xCCCA, 0xAB6D, 0xCCCB, 0xAB6E, 0xCCCC, 0xAB6F, 0xCCCD, 0xAB70, 0xCCCE, 0xAB71, 0xCCCF, 0xAB72, 0xCCD1, 0xAB73, 0xCCD2, 0xAB74, 0xCCD3, 0xAB75, 0xCCD5, 0xAB76, 0xCCD6, 0xAB77, 0xCCD7, 0xAB78, 0xCCD8, 0xAB79, 0xCCD9, 0xAB7A, 0xCCDA, 0xAB81, 0xCCDB, 0xAB82, 0xCCDC, 0xAB83, 0xCCDD, 0xAB84, 0xCCDE, 0xAB85, 0xCCDF, 0xAB86, 0xCCE0, 0xAB87, 0xCCE1, 0xAB88, 0xCCE2, 0xAB89, 0xCCE3, 0xAB8A, 0xCCE5, 0xAB8B, 0xCCE6, 0xAB8C, 0xCCE7, 0xAB8D, 0xCCE8, 0xAB8E, 0xCCE9, 0xAB8F, 0xCCEA, 0xAB90, 0xCCEB, 0xAB91, 0xCCED, 0xAB92, 0xCCEE, 0xAB93, 0xCCEF, 0xAB94, 0xCCF1, 0xAB95, 0xCCF2, 0xAB96, 0xCCF3, 0xAB97, 0xCCF4, 0xAB98, 0xCCF5, 0xAB99, 0xCCF6, 0xAB9A, 0xCCF7, 0xAB9B, 0xCCF8, 0xAB9C, 0xCCF9, 0xAB9D, 0xCCFA, 0xAB9E, 0xCCFB, 0xAB9F, 0xCCFC, 0xABA0, 0xCCFD, 0xABA1, 0x30A1, 0xABA2, 0x30A2, 0xABA3, 0x30A3, 0xABA4, 0x30A4, 0xABA5, 0x30A5, 0xABA6, 0x30A6, 0xABA7, 0x30A7, 0xABA8, 0x30A8, 0xABA9, 0x30A9, 0xABAA, 0x30AA, 0xABAB, 0x30AB, 0xABAC, 0x30AC, 0xABAD, 0x30AD, 0xABAE, 0x30AE, 0xABAF, 0x30AF, 0xABB0, 0x30B0, 0xABB1, 0x30B1, 0xABB2, 0x30B2, 0xABB3, 0x30B3, 0xABB4, 0x30B4, 0xABB5, 0x30B5, 0xABB6, 0x30B6, 0xABB7, 0x30B7, 0xABB8, 0x30B8, 0xABB9, 0x30B9, 0xABBA, 0x30BA, 0xABBB, 0x30BB, 0xABBC, 0x30BC, 0xABBD, 0x30BD, 0xABBE, 0x30BE, 0xABBF, 0x30BF, 0xABC0, 0x30C0, 0xABC1, 0x30C1, 0xABC2, 0x30C2, 0xABC3, 0x30C3, 0xABC4, 0x30C4, 0xABC5, 0x30C5, 0xABC6, 0x30C6, 0xABC7, 0x30C7, 0xABC8, 0x30C8, 0xABC9, 0x30C9, 0xABCA, 0x30CA, 0xABCB, 0x30CB, 0xABCC, 0x30CC, 0xABCD, 0x30CD, 0xABCE, 0x30CE, 0xABCF, 0x30CF, 0xABD0, 0x30D0, 0xABD1, 0x30D1, 0xABD2, 0x30D2, 0xABD3, 0x30D3, 0xABD4, 0x30D4, 0xABD5, 0x30D5, 0xABD6, 0x30D6, 0xABD7, 0x30D7, 0xABD8, 0x30D8, 0xABD9, 0x30D9, 0xABDA, 0x30DA, 0xABDB, 0x30DB, 0xABDC, 0x30DC, 0xABDD, 0x30DD, 0xABDE, 0x30DE, 0xABDF, 0x30DF, 0xABE0, 0x30E0, 0xABE1, 0x30E1, 0xABE2, 0x30E2, 0xABE3, 0x30E3, 0xABE4, 0x30E4, 0xABE5, 0x30E5, 0xABE6, 0x30E6, 0xABE7, 0x30E7, 0xABE8, 0x30E8, 0xABE9, 0x30E9, 0xABEA, 0x30EA, 0xABEB, 0x30EB, 0xABEC, 0x30EC, 0xABED, 0x30ED, 0xABEE, 0x30EE, 0xABEF, 0x30EF, 0xABF0, 0x30F0, 0xABF1, 0x30F1, 0xABF2, 0x30F2, 0xABF3, 0x30F3, 0xABF4, 0x30F4, 0xABF5, 0x30F5, 0xABF6, 0x30F6, 0xAC41, 0xCCFE, 0xAC42, 0xCCFF, 0xAC43, 0xCD00, 0xAC44, 0xCD02, 0xAC45, 0xCD03, 0xAC46, 0xCD04, 0xAC47, 0xCD05, 0xAC48, 0xCD06, 0xAC49, 0xCD07, 0xAC4A, 0xCD0A, 0xAC4B, 0xCD0B, 0xAC4C, 0xCD0D, 0xAC4D, 0xCD0E, 0xAC4E, 0xCD0F, 0xAC4F, 0xCD11, 0xAC50, 0xCD12, 0xAC51, 0xCD13, 0xAC52, 0xCD14, 0xAC53, 0xCD15, 0xAC54, 0xCD16, 0xAC55, 0xCD17, 0xAC56, 0xCD1A, 0xAC57, 0xCD1C, 0xAC58, 0xCD1E, 0xAC59, 0xCD1F, 0xAC5A, 0xCD20, 0xAC61, 0xCD21, 0xAC62, 0xCD22, 0xAC63, 0xCD23, 0xAC64, 0xCD25, 0xAC65, 0xCD26, 0xAC66, 0xCD27, 0xAC67, 0xCD29, 0xAC68, 0xCD2A, 0xAC69, 0xCD2B, 0xAC6A, 0xCD2D, 0xAC6B, 0xCD2E, 0xAC6C, 0xCD2F, 0xAC6D, 0xCD30, 0xAC6E, 0xCD31, 0xAC6F, 0xCD32, 0xAC70, 0xCD33, 0xAC71, 0xCD34, 0xAC72, 0xCD35, 0xAC73, 0xCD36, 0xAC74, 0xCD37, 0xAC75, 0xCD38, 0xAC76, 0xCD3A, 0xAC77, 0xCD3B, 0xAC78, 0xCD3C, 0xAC79, 0xCD3D, 0xAC7A, 0xCD3E, 0xAC81, 0xCD3F, 0xAC82, 0xCD40, 0xAC83, 0xCD41, 0xAC84, 0xCD42, 0xAC85, 0xCD43, 0xAC86, 0xCD44, 0xAC87, 0xCD45, 0xAC88, 0xCD46, 0xAC89, 0xCD47, 0xAC8A, 0xCD48, 0xAC8B, 0xCD49, 0xAC8C, 0xCD4A, 0xAC8D, 0xCD4B, 0xAC8E, 0xCD4C, 0xAC8F, 0xCD4D, 0xAC90, 0xCD4E, 0xAC91, 0xCD4F, 0xAC92, 0xCD50, 0xAC93, 0xCD51, 0xAC94, 0xCD52, 0xAC95, 0xCD53, 0xAC96, 0xCD54, 0xAC97, 0xCD55, 0xAC98, 0xCD56, 0xAC99, 0xCD57, 0xAC9A, 0xCD58, 0xAC9B, 0xCD59, 0xAC9C, 0xCD5A, 0xAC9D, 0xCD5B, 0xAC9E, 0xCD5D, 0xAC9F, 0xCD5E, 0xACA0, 0xCD5F, 0xACA1, 0x0410, 0xACA2, 0x0411, 0xACA3, 0x0412, 0xACA4, 0x0413, 0xACA5, 0x0414, 0xACA6, 0x0415, 0xACA7, 0x0401, 0xACA8, 0x0416, 0xACA9, 0x0417, 0xACAA, 0x0418, 0xACAB, 0x0419, 0xACAC, 0x041A, 0xACAD, 0x041B, 0xACAE, 0x041C, 0xACAF, 0x041D, 0xACB0, 0x041E, 0xACB1, 0x041F, 0xACB2, 0x0420, 0xACB3, 0x0421, 0xACB4, 0x0422, 0xACB5, 0x0423, 0xACB6, 0x0424, 0xACB7, 0x0425, 0xACB8, 0x0426, 0xACB9, 0x0427, 0xACBA, 0x0428, 0xACBB, 0x0429, 0xACBC, 0x042A, 0xACBD, 0x042B, 0xACBE, 0x042C, 0xACBF, 0x042D, 0xACC0, 0x042E, 0xACC1, 0x042F, 0xACD1, 0x0430, 0xACD2, 0x0431, 0xACD3, 0x0432, 0xACD4, 0x0433, 0xACD5, 0x0434, 0xACD6, 0x0435, 0xACD7, 0x0451, 0xACD8, 0x0436, 0xACD9, 0x0437, 0xACDA, 0x0438, 0xACDB, 0x0439, 0xACDC, 0x043A, 0xACDD, 0x043B, 0xACDE, 0x043C, 0xACDF, 0x043D, 0xACE0, 0x043E, 0xACE1, 0x043F, 0xACE2, 0x0440, 0xACE3, 0x0441, 0xACE4, 0x0442, 0xACE5, 0x0443, 0xACE6, 0x0444, 0xACE7, 0x0445, 0xACE8, 0x0446, 0xACE9, 0x0447, 0xACEA, 0x0448, 0xACEB, 0x0449, 0xACEC, 0x044A, 0xACED, 0x044B, 0xACEE, 0x044C, 0xACEF, 0x044D, 0xACF0, 0x044E, 0xACF1, 0x044F, 0xAD41, 0xCD61, 0xAD42, 0xCD62, 0xAD43, 0xCD63, 0xAD44, 0xCD65, 0xAD45, 0xCD66, 0xAD46, 0xCD67, 0xAD47, 0xCD68, 0xAD48, 0xCD69, 0xAD49, 0xCD6A, 0xAD4A, 0xCD6B, 0xAD4B, 0xCD6E, 0xAD4C, 0xCD70, 0xAD4D, 0xCD72, 0xAD4E, 0xCD73, 0xAD4F, 0xCD74, 0xAD50, 0xCD75, 0xAD51, 0xCD76, 0xAD52, 0xCD77, 0xAD53, 0xCD79, 0xAD54, 0xCD7A, 0xAD55, 0xCD7B, 0xAD56, 0xCD7C, 0xAD57, 0xCD7D, 0xAD58, 0xCD7E, 0xAD59, 0xCD7F, 0xAD5A, 0xCD80, 0xAD61, 0xCD81, 0xAD62, 0xCD82, 0xAD63, 0xCD83, 0xAD64, 0xCD84, 0xAD65, 0xCD85, 0xAD66, 0xCD86, 0xAD67, 0xCD87, 0xAD68, 0xCD89, 0xAD69, 0xCD8A, 0xAD6A, 0xCD8B, 0xAD6B, 0xCD8C, 0xAD6C, 0xCD8D, 0xAD6D, 0xCD8E, 0xAD6E, 0xCD8F, 0xAD6F, 0xCD90, 0xAD70, 0xCD91, 0xAD71, 0xCD92, 0xAD72, 0xCD93, 0xAD73, 0xCD96, 0xAD74, 0xCD97, 0xAD75, 0xCD99, 0xAD76, 0xCD9A, 0xAD77, 0xCD9B, 0xAD78, 0xCD9D, 0xAD79, 0xCD9E, 0xAD7A, 0xCD9F, 0xAD81, 0xCDA0, 0xAD82, 0xCDA1, 0xAD83, 0xCDA2, 0xAD84, 0xCDA3, 0xAD85, 0xCDA6, 0xAD86, 0xCDA8, 0xAD87, 0xCDAA, 0xAD88, 0xCDAB, 0xAD89, 0xCDAC, 0xAD8A, 0xCDAD, 0xAD8B, 0xCDAE, 0xAD8C, 0xCDAF, 0xAD8D, 0xCDB1, 0xAD8E, 0xCDB2, 0xAD8F, 0xCDB3, 0xAD90, 0xCDB4, 0xAD91, 0xCDB5, 0xAD92, 0xCDB6, 0xAD93, 0xCDB7, 0xAD94, 0xCDB8, 0xAD95, 0xCDB9, 0xAD96, 0xCDBA, 0xAD97, 0xCDBB, 0xAD98, 0xCDBC, 0xAD99, 0xCDBD, 0xAD9A, 0xCDBE, 0xAD9B, 0xCDBF, 0xAD9C, 0xCDC0, 0xAD9D, 0xCDC1, 0xAD9E, 0xCDC2, 0xAD9F, 0xCDC3, 0xADA0, 0xCDC5, 0xAE41, 0xCDC6, 0xAE42, 0xCDC7, 0xAE43, 0xCDC8, 0xAE44, 0xCDC9, 0xAE45, 0xCDCA, 0xAE46, 0xCDCB, 0xAE47, 0xCDCD, 0xAE48, 0xCDCE, 0xAE49, 0xCDCF, 0xAE4A, 0xCDD1, 0xAE4B, 0xCDD2, 0xAE4C, 0xCDD3, 0xAE4D, 0xCDD4, 0xAE4E, 0xCDD5, 0xAE4F, 0xCDD6, 0xAE50, 0xCDD7, 0xAE51, 0xCDD8, 0xAE52, 0xCDD9, 0xAE53, 0xCDDA, 0xAE54, 0xCDDB, 0xAE55, 0xCDDC, 0xAE56, 0xCDDD, 0xAE57, 0xCDDE, 0xAE58, 0xCDDF, 0xAE59, 0xCDE0, 0xAE5A, 0xCDE1, 0xAE61, 0xCDE2, 0xAE62, 0xCDE3, 0xAE63, 0xCDE4, 0xAE64, 0xCDE5, 0xAE65, 0xCDE6, 0xAE66, 0xCDE7, 0xAE67, 0xCDE9, 0xAE68, 0xCDEA, 0xAE69, 0xCDEB, 0xAE6A, 0xCDED, 0xAE6B, 0xCDEE, 0xAE6C, 0xCDEF, 0xAE6D, 0xCDF1, 0xAE6E, 0xCDF2, 0xAE6F, 0xCDF3, 0xAE70, 0xCDF4, 0xAE71, 0xCDF5, 0xAE72, 0xCDF6, 0xAE73, 0xCDF7, 0xAE74, 0xCDFA, 0xAE75, 0xCDFC, 0xAE76, 0xCDFE, 0xAE77, 0xCDFF, 0xAE78, 0xCE00, 0xAE79, 0xCE01, 0xAE7A, 0xCE02, 0xAE81, 0xCE03, 0xAE82, 0xCE05, 0xAE83, 0xCE06, 0xAE84, 0xCE07, 0xAE85, 0xCE09, 0xAE86, 0xCE0A, 0xAE87, 0xCE0B, 0xAE88, 0xCE0D, 0xAE89, 0xCE0E, 0xAE8A, 0xCE0F, 0xAE8B, 0xCE10, 0xAE8C, 0xCE11, 0xAE8D, 0xCE12, 0xAE8E, 0xCE13, 0xAE8F, 0xCE15, 0xAE90, 0xCE16, 0xAE91, 0xCE17, 0xAE92, 0xCE18, 0xAE93, 0xCE1A, 0xAE94, 0xCE1B, 0xAE95, 0xCE1C, 0xAE96, 0xCE1D, 0xAE97, 0xCE1E, 0xAE98, 0xCE1F, 0xAE99, 0xCE22, 0xAE9A, 0xCE23, 0xAE9B, 0xCE25, 0xAE9C, 0xCE26, 0xAE9D, 0xCE27, 0xAE9E, 0xCE29, 0xAE9F, 0xCE2A, 0xAEA0, 0xCE2B, 0xAF41, 0xCE2C, 0xAF42, 0xCE2D, 0xAF43, 0xCE2E, 0xAF44, 0xCE2F, 0xAF45, 0xCE32, 0xAF46, 0xCE34, 0xAF47, 0xCE36, 0xAF48, 0xCE37, 0xAF49, 0xCE38, 0xAF4A, 0xCE39, 0xAF4B, 0xCE3A, 0xAF4C, 0xCE3B, 0xAF4D, 0xCE3C, 0xAF4E, 0xCE3D, 0xAF4F, 0xCE3E, 0xAF50, 0xCE3F, 0xAF51, 0xCE40, 0xAF52, 0xCE41, 0xAF53, 0xCE42, 0xAF54, 0xCE43, 0xAF55, 0xCE44, 0xAF56, 0xCE45, 0xAF57, 0xCE46, 0xAF58, 0xCE47, 0xAF59, 0xCE48, 0xAF5A, 0xCE49, 0xAF61, 0xCE4A, 0xAF62, 0xCE4B, 0xAF63, 0xCE4C, 0xAF64, 0xCE4D, 0xAF65, 0xCE4E, 0xAF66, 0xCE4F, 0xAF67, 0xCE50, 0xAF68, 0xCE51, 0xAF69, 0xCE52, 0xAF6A, 0xCE53, 0xAF6B, 0xCE54, 0xAF6C, 0xCE55, 0xAF6D, 0xCE56, 0xAF6E, 0xCE57, 0xAF6F, 0xCE5A, 0xAF70, 0xCE5B, 0xAF71, 0xCE5D, 0xAF72, 0xCE5E, 0xAF73, 0xCE62, 0xAF74, 0xCE63, 0xAF75, 0xCE64, 0xAF76, 0xCE65, 0xAF77, 0xCE66, 0xAF78, 0xCE67, 0xAF79, 0xCE6A, 0xAF7A, 0xCE6C, 0xAF81, 0xCE6E, 0xAF82, 0xCE6F, 0xAF83, 0xCE70, 0xAF84, 0xCE71, 0xAF85, 0xCE72, 0xAF86, 0xCE73, 0xAF87, 0xCE76, 0xAF88, 0xCE77, 0xAF89, 0xCE79, 0xAF8A, 0xCE7A, 0xAF8B, 0xCE7B, 0xAF8C, 0xCE7D, 0xAF8D, 0xCE7E, 0xAF8E, 0xCE7F, 0xAF8F, 0xCE80, 0xAF90, 0xCE81, 0xAF91, 0xCE82, 0xAF92, 0xCE83, 0xAF93, 0xCE86, 0xAF94, 0xCE88, 0xAF95, 0xCE8A, 0xAF96, 0xCE8B, 0xAF97, 0xCE8C, 0xAF98, 0xCE8D, 0xAF99, 0xCE8E, 0xAF9A, 0xCE8F, 0xAF9B, 0xCE92, 0xAF9C, 0xCE93, 0xAF9D, 0xCE95, 0xAF9E, 0xCE96, 0xAF9F, 0xCE97, 0xAFA0, 0xCE99, 0xB041, 0xCE9A, 0xB042, 0xCE9B, 0xB043, 0xCE9C, 0xB044, 0xCE9D, 0xB045, 0xCE9E, 0xB046, 0xCE9F, 0xB047, 0xCEA2, 0xB048, 0xCEA6, 0xB049, 0xCEA7, 0xB04A, 0xCEA8, 0xB04B, 0xCEA9, 0xB04C, 0xCEAA, 0xB04D, 0xCEAB, 0xB04E, 0xCEAE, 0xB04F, 0xCEAF, 0xB050, 0xCEB0, 0xB051, 0xCEB1, 0xB052, 0xCEB2, 0xB053, 0xCEB3, 0xB054, 0xCEB4, 0xB055, 0xCEB5, 0xB056, 0xCEB6, 0xB057, 0xCEB7, 0xB058, 0xCEB8, 0xB059, 0xCEB9, 0xB05A, 0xCEBA, 0xB061, 0xCEBB, 0xB062, 0xCEBC, 0xB063, 0xCEBD, 0xB064, 0xCEBE, 0xB065, 0xCEBF, 0xB066, 0xCEC0, 0xB067, 0xCEC2, 0xB068, 0xCEC3, 0xB069, 0xCEC4, 0xB06A, 0xCEC5, 0xB06B, 0xCEC6, 0xB06C, 0xCEC7, 0xB06D, 0xCEC8, 0xB06E, 0xCEC9, 0xB06F, 0xCECA, 0xB070, 0xCECB, 0xB071, 0xCECC, 0xB072, 0xCECD, 0xB073, 0xCECE, 0xB074, 0xCECF, 0xB075, 0xCED0, 0xB076, 0xCED1, 0xB077, 0xCED2, 0xB078, 0xCED3, 0xB079, 0xCED4, 0xB07A, 0xCED5, 0xB081, 0xCED6, 0xB082, 0xCED7, 0xB083, 0xCED8, 0xB084, 0xCED9, 0xB085, 0xCEDA, 0xB086, 0xCEDB, 0xB087, 0xCEDC, 0xB088, 0xCEDD, 0xB089, 0xCEDE, 0xB08A, 0xCEDF, 0xB08B, 0xCEE0, 0xB08C, 0xCEE1, 0xB08D, 0xCEE2, 0xB08E, 0xCEE3, 0xB08F, 0xCEE6, 0xB090, 0xCEE7, 0xB091, 0xCEE9, 0xB092, 0xCEEA, 0xB093, 0xCEED, 0xB094, 0xCEEE, 0xB095, 0xCEEF, 0xB096, 0xCEF0, 0xB097, 0xCEF1, 0xB098, 0xCEF2, 0xB099, 0xCEF3, 0xB09A, 0xCEF6, 0xB09B, 0xCEFA, 0xB09C, 0xCEFB, 0xB09D, 0xCEFC, 0xB09E, 0xCEFD, 0xB09F, 0xCEFE, 0xB0A0, 0xCEFF, 0xB0A1, 0xAC00, 0xB0A2, 0xAC01, 0xB0A3, 0xAC04, 0xB0A4, 0xAC07, 0xB0A5, 0xAC08, 0xB0A6, 0xAC09, 0xB0A7, 0xAC0A, 0xB0A8, 0xAC10, 0xB0A9, 0xAC11, 0xB0AA, 0xAC12, 0xB0AB, 0xAC13, 0xB0AC, 0xAC14, 0xB0AD, 0xAC15, 0xB0AE, 0xAC16, 0xB0AF, 0xAC17, 0xB0B0, 0xAC19, 0xB0B1, 0xAC1A, 0xB0B2, 0xAC1B, 0xB0B3, 0xAC1C, 0xB0B4, 0xAC1D, 0xB0B5, 0xAC20, 0xB0B6, 0xAC24, 0xB0B7, 0xAC2C, 0xB0B8, 0xAC2D, 0xB0B9, 0xAC2F, 0xB0BA, 0xAC30, 0xB0BB, 0xAC31, 0xB0BC, 0xAC38, 0xB0BD, 0xAC39, 0xB0BE, 0xAC3C, 0xB0BF, 0xAC40, 0xB0C0, 0xAC4B, 0xB0C1, 0xAC4D, 0xB0C2, 0xAC54, 0xB0C3, 0xAC58, 0xB0C4, 0xAC5C, 0xB0C5, 0xAC70, 0xB0C6, 0xAC71, 0xB0C7, 0xAC74, 0xB0C8, 0xAC77, 0xB0C9, 0xAC78, 0xB0CA, 0xAC7A, 0xB0CB, 0xAC80, 0xB0CC, 0xAC81, 0xB0CD, 0xAC83, 0xB0CE, 0xAC84, 0xB0CF, 0xAC85, 0xB0D0, 0xAC86, 0xB0D1, 0xAC89, 0xB0D2, 0xAC8A, 0xB0D3, 0xAC8B, 0xB0D4, 0xAC8C, 0xB0D5, 0xAC90, 0xB0D6, 0xAC94, 0xB0D7, 0xAC9C, 0xB0D8, 0xAC9D, 0xB0D9, 0xAC9F, 0xB0DA, 0xACA0, 0xB0DB, 0xACA1, 0xB0DC, 0xACA8, 0xB0DD, 0xACA9, 0xB0DE, 0xACAA, 0xB0DF, 0xACAC, 0xB0E0, 0xACAF, 0xB0E1, 0xACB0, 0xB0E2, 0xACB8, 0xB0E3, 0xACB9, 0xB0E4, 0xACBB, 0xB0E5, 0xACBC, 0xB0E6, 0xACBD, 0xB0E7, 0xACC1, 0xB0E8, 0xACC4, 0xB0E9, 0xACC8, 0xB0EA, 0xACCC, 0xB0EB, 0xACD5, 0xB0EC, 0xACD7, 0xB0ED, 0xACE0, 0xB0EE, 0xACE1, 0xB0EF, 0xACE4, 0xB0F0, 0xACE7, 0xB0F1, 0xACE8, 0xB0F2, 0xACEA, 0xB0F3, 0xACEC, 0xB0F4, 0xACEF, 0xB0F5, 0xACF0, 0xB0F6, 0xACF1, 0xB0F7, 0xACF3, 0xB0F8, 0xACF5, 0xB0F9, 0xACF6, 0xB0FA, 0xACFC, 0xB0FB, 0xACFD, 0xB0FC, 0xAD00, 0xB0FD, 0xAD04, 0xB0FE, 0xAD06, 0xB141, 0xCF02, 0xB142, 0xCF03, 0xB143, 0xCF05, 0xB144, 0xCF06, 0xB145, 0xCF07, 0xB146, 0xCF09, 0xB147, 0xCF0A, 0xB148, 0xCF0B, 0xB149, 0xCF0C, 0xB14A, 0xCF0D, 0xB14B, 0xCF0E, 0xB14C, 0xCF0F, 0xB14D, 0xCF12, 0xB14E, 0xCF14, 0xB14F, 0xCF16, 0xB150, 0xCF17, 0xB151, 0xCF18, 0xB152, 0xCF19, 0xB153, 0xCF1A, 0xB154, 0xCF1B, 0xB155, 0xCF1D, 0xB156, 0xCF1E, 0xB157, 0xCF1F, 0xB158, 0xCF21, 0xB159, 0xCF22, 0xB15A, 0xCF23, 0xB161, 0xCF25, 0xB162, 0xCF26, 0xB163, 0xCF27, 0xB164, 0xCF28, 0xB165, 0xCF29, 0xB166, 0xCF2A, 0xB167, 0xCF2B, 0xB168, 0xCF2E, 0xB169, 0xCF32, 0xB16A, 0xCF33, 0xB16B, 0xCF34, 0xB16C, 0xCF35, 0xB16D, 0xCF36, 0xB16E, 0xCF37, 0xB16F, 0xCF39, 0xB170, 0xCF3A, 0xB171, 0xCF3B, 0xB172, 0xCF3C, 0xB173, 0xCF3D, 0xB174, 0xCF3E, 0xB175, 0xCF3F, 0xB176, 0xCF40, 0xB177, 0xCF41, 0xB178, 0xCF42, 0xB179, 0xCF43, 0xB17A, 0xCF44, 0xB181, 0xCF45, 0xB182, 0xCF46, 0xB183, 0xCF47, 0xB184, 0xCF48, 0xB185, 0xCF49, 0xB186, 0xCF4A, 0xB187, 0xCF4B, 0xB188, 0xCF4C, 0xB189, 0xCF4D, 0xB18A, 0xCF4E, 0xB18B, 0xCF4F, 0xB18C, 0xCF50, 0xB18D, 0xCF51, 0xB18E, 0xCF52, 0xB18F, 0xCF53, 0xB190, 0xCF56, 0xB191, 0xCF57, 0xB192, 0xCF59, 0xB193, 0xCF5A, 0xB194, 0xCF5B, 0xB195, 0xCF5D, 0xB196, 0xCF5E, 0xB197, 0xCF5F, 0xB198, 0xCF60, 0xB199, 0xCF61, 0xB19A, 0xCF62, 0xB19B, 0xCF63, 0xB19C, 0xCF66, 0xB19D, 0xCF68, 0xB19E, 0xCF6A, 0xB19F, 0xCF6B, 0xB1A0, 0xCF6C, 0xB1A1, 0xAD0C, 0xB1A2, 0xAD0D, 0xB1A3, 0xAD0F, 0xB1A4, 0xAD11, 0xB1A5, 0xAD18, 0xB1A6, 0xAD1C, 0xB1A7, 0xAD20, 0xB1A8, 0xAD29, 0xB1A9, 0xAD2C, 0xB1AA, 0xAD2D, 0xB1AB, 0xAD34, 0xB1AC, 0xAD35, 0xB1AD, 0xAD38, 0xB1AE, 0xAD3C, 0xB1AF, 0xAD44, 0xB1B0, 0xAD45, 0xB1B1, 0xAD47, 0xB1B2, 0xAD49, 0xB1B3, 0xAD50, 0xB1B4, 0xAD54, 0xB1B5, 0xAD58, 0xB1B6, 0xAD61, 0xB1B7, 0xAD63, 0xB1B8, 0xAD6C, 0xB1B9, 0xAD6D, 0xB1BA, 0xAD70, 0xB1BB, 0xAD73, 0xB1BC, 0xAD74, 0xB1BD, 0xAD75, 0xB1BE, 0xAD76, 0xB1BF, 0xAD7B, 0xB1C0, 0xAD7C, 0xB1C1, 0xAD7D, 0xB1C2, 0xAD7F, 0xB1C3, 0xAD81, 0xB1C4, 0xAD82, 0xB1C5, 0xAD88, 0xB1C6, 0xAD89, 0xB1C7, 0xAD8C, 0xB1C8, 0xAD90, 0xB1C9, 0xAD9C, 0xB1CA, 0xAD9D, 0xB1CB, 0xADA4, 0xB1CC, 0xADB7, 0xB1CD, 0xADC0, 0xB1CE, 0xADC1, 0xB1CF, 0xADC4, 0xB1D0, 0xADC8, 0xB1D1, 0xADD0, 0xB1D2, 0xADD1, 0xB1D3, 0xADD3, 0xB1D4, 0xADDC, 0xB1D5, 0xADE0, 0xB1D6, 0xADE4, 0xB1D7, 0xADF8, 0xB1D8, 0xADF9, 0xB1D9, 0xADFC, 0xB1DA, 0xADFF, 0xB1DB, 0xAE00, 0xB1DC, 0xAE01, 0xB1DD, 0xAE08, 0xB1DE, 0xAE09, 0xB1DF, 0xAE0B, 0xB1E0, 0xAE0D, 0xB1E1, 0xAE14, 0xB1E2, 0xAE30, 0xB1E3, 0xAE31, 0xB1E4, 0xAE34, 0xB1E5, 0xAE37, 0xB1E6, 0xAE38, 0xB1E7, 0xAE3A, 0xB1E8, 0xAE40, 0xB1E9, 0xAE41, 0xB1EA, 0xAE43, 0xB1EB, 0xAE45, 0xB1EC, 0xAE46, 0xB1ED, 0xAE4A, 0xB1EE, 0xAE4C, 0xB1EF, 0xAE4D, 0xB1F0, 0xAE4E, 0xB1F1, 0xAE50, 0xB1F2, 0xAE54, 0xB1F3, 0xAE56, 0xB1F4, 0xAE5C, 0xB1F5, 0xAE5D, 0xB1F6, 0xAE5F, 0xB1F7, 0xAE60, 0xB1F8, 0xAE61, 0xB1F9, 0xAE65, 0xB1FA, 0xAE68, 0xB1FB, 0xAE69, 0xB1FC, 0xAE6C, 0xB1FD, 0xAE70, 0xB1FE, 0xAE78, 0xB241, 0xCF6D, 0xB242, 0xCF6E, 0xB243, 0xCF6F, 0xB244, 0xCF72, 0xB245, 0xCF73, 0xB246, 0xCF75, 0xB247, 0xCF76, 0xB248, 0xCF77, 0xB249, 0xCF79, 0xB24A, 0xCF7A, 0xB24B, 0xCF7B, 0xB24C, 0xCF7C, 0xB24D, 0xCF7D, 0xB24E, 0xCF7E, 0xB24F, 0xCF7F, 0xB250, 0xCF81, 0xB251, 0xCF82, 0xB252, 0xCF83, 0xB253, 0xCF84, 0xB254, 0xCF86, 0xB255, 0xCF87, 0xB256, 0xCF88, 0xB257, 0xCF89, 0xB258, 0xCF8A, 0xB259, 0xCF8B, 0xB25A, 0xCF8D, 0xB261, 0xCF8E, 0xB262, 0xCF8F, 0xB263, 0xCF90, 0xB264, 0xCF91, 0xB265, 0xCF92, 0xB266, 0xCF93, 0xB267, 0xCF94, 0xB268, 0xCF95, 0xB269, 0xCF96, 0xB26A, 0xCF97, 0xB26B, 0xCF98, 0xB26C, 0xCF99, 0xB26D, 0xCF9A, 0xB26E, 0xCF9B, 0xB26F, 0xCF9C, 0xB270, 0xCF9D, 0xB271, 0xCF9E, 0xB272, 0xCF9F, 0xB273, 0xCFA0, 0xB274, 0xCFA2, 0xB275, 0xCFA3, 0xB276, 0xCFA4, 0xB277, 0xCFA5, 0xB278, 0xCFA6, 0xB279, 0xCFA7, 0xB27A, 0xCFA9, 0xB281, 0xCFAA, 0xB282, 0xCFAB, 0xB283, 0xCFAC, 0xB284, 0xCFAD, 0xB285, 0xCFAE, 0xB286, 0xCFAF, 0xB287, 0xCFB1, 0xB288, 0xCFB2, 0xB289, 0xCFB3, 0xB28A, 0xCFB4, 0xB28B, 0xCFB5, 0xB28C, 0xCFB6, 0xB28D, 0xCFB7, 0xB28E, 0xCFB8, 0xB28F, 0xCFB9, 0xB290, 0xCFBA, 0xB291, 0xCFBB, 0xB292, 0xCFBC, 0xB293, 0xCFBD, 0xB294, 0xCFBE, 0xB295, 0xCFBF, 0xB296, 0xCFC0, 0xB297, 0xCFC1, 0xB298, 0xCFC2, 0xB299, 0xCFC3, 0xB29A, 0xCFC5, 0xB29B, 0xCFC6, 0xB29C, 0xCFC7, 0xB29D, 0xCFC8, 0xB29E, 0xCFC9, 0xB29F, 0xCFCA, 0xB2A0, 0xCFCB, 0xB2A1, 0xAE79, 0xB2A2, 0xAE7B, 0xB2A3, 0xAE7C, 0xB2A4, 0xAE7D, 0xB2A5, 0xAE84, 0xB2A6, 0xAE85, 0xB2A7, 0xAE8C, 0xB2A8, 0xAEBC, 0xB2A9, 0xAEBD, 0xB2AA, 0xAEBE, 0xB2AB, 0xAEC0, 0xB2AC, 0xAEC4, 0xB2AD, 0xAECC, 0xB2AE, 0xAECD, 0xB2AF, 0xAECF, 0xB2B0, 0xAED0, 0xB2B1, 0xAED1, 0xB2B2, 0xAED8, 0xB2B3, 0xAED9, 0xB2B4, 0xAEDC, 0xB2B5, 0xAEE8, 0xB2B6, 0xAEEB, 0xB2B7, 0xAEED, 0xB2B8, 0xAEF4, 0xB2B9, 0xAEF8, 0xB2BA, 0xAEFC, 0xB2BB, 0xAF07, 0xB2BC, 0xAF08, 0xB2BD, 0xAF0D, 0xB2BE, 0xAF10, 0xB2BF, 0xAF2C, 0xB2C0, 0xAF2D, 0xB2C1, 0xAF30, 0xB2C2, 0xAF32, 0xB2C3, 0xAF34, 0xB2C4, 0xAF3C, 0xB2C5, 0xAF3D, 0xB2C6, 0xAF3F, 0xB2C7, 0xAF41, 0xB2C8, 0xAF42, 0xB2C9, 0xAF43, 0xB2CA, 0xAF48, 0xB2CB, 0xAF49, 0xB2CC, 0xAF50, 0xB2CD, 0xAF5C, 0xB2CE, 0xAF5D, 0xB2CF, 0xAF64, 0xB2D0, 0xAF65, 0xB2D1, 0xAF79, 0xB2D2, 0xAF80, 0xB2D3, 0xAF84, 0xB2D4, 0xAF88, 0xB2D5, 0xAF90, 0xB2D6, 0xAF91, 0xB2D7, 0xAF95, 0xB2D8, 0xAF9C, 0xB2D9, 0xAFB8, 0xB2DA, 0xAFB9, 0xB2DB, 0xAFBC, 0xB2DC, 0xAFC0, 0xB2DD, 0xAFC7, 0xB2DE, 0xAFC8, 0xB2DF, 0xAFC9, 0xB2E0, 0xAFCB, 0xB2E1, 0xAFCD, 0xB2E2, 0xAFCE, 0xB2E3, 0xAFD4, 0xB2E4, 0xAFDC, 0xB2E5, 0xAFE8, 0xB2E6, 0xAFE9, 0xB2E7, 0xAFF0, 0xB2E8, 0xAFF1, 0xB2E9, 0xAFF4, 0xB2EA, 0xAFF8, 0xB2EB, 0xB000, 0xB2EC, 0xB001, 0xB2ED, 0xB004, 0xB2EE, 0xB00C, 0xB2EF, 0xB010, 0xB2F0, 0xB014, 0xB2F1, 0xB01C, 0xB2F2, 0xB01D, 0xB2F3, 0xB028, 0xB2F4, 0xB044, 0xB2F5, 0xB045, 0xB2F6, 0xB048, 0xB2F7, 0xB04A, 0xB2F8, 0xB04C, 0xB2F9, 0xB04E, 0xB2FA, 0xB053, 0xB2FB, 0xB054, 0xB2FC, 0xB055, 0xB2FD, 0xB057, 0xB2FE, 0xB059, 0xB341, 0xCFCC, 0xB342, 0xCFCD, 0xB343, 0xCFCE, 0xB344, 0xCFCF, 0xB345, 0xCFD0, 0xB346, 0xCFD1, 0xB347, 0xCFD2, 0xB348, 0xCFD3, 0xB349, 0xCFD4, 0xB34A, 0xCFD5, 0xB34B, 0xCFD6, 0xB34C, 0xCFD7, 0xB34D, 0xCFD8, 0xB34E, 0xCFD9, 0xB34F, 0xCFDA, 0xB350, 0xCFDB, 0xB351, 0xCFDC, 0xB352, 0xCFDD, 0xB353, 0xCFDE, 0xB354, 0xCFDF, 0xB355, 0xCFE2, 0xB356, 0xCFE3, 0xB357, 0xCFE5, 0xB358, 0xCFE6, 0xB359, 0xCFE7, 0xB35A, 0xCFE9, 0xB361, 0xCFEA, 0xB362, 0xCFEB, 0xB363, 0xCFEC, 0xB364, 0xCFED, 0xB365, 0xCFEE, 0xB366, 0xCFEF, 0xB367, 0xCFF2, 0xB368, 0xCFF4, 0xB369, 0xCFF6, 0xB36A, 0xCFF7, 0xB36B, 0xCFF8, 0xB36C, 0xCFF9, 0xB36D, 0xCFFA, 0xB36E, 0xCFFB, 0xB36F, 0xCFFD, 0xB370, 0xCFFE, 0xB371, 0xCFFF, 0xB372, 0xD001, 0xB373, 0xD002, 0xB374, 0xD003, 0xB375, 0xD005, 0xB376, 0xD006, 0xB377, 0xD007, 0xB378, 0xD008, 0xB379, 0xD009, 0xB37A, 0xD00A, 0xB381, 0xD00B, 0xB382, 0xD00C, 0xB383, 0xD00D, 0xB384, 0xD00E, 0xB385, 0xD00F, 0xB386, 0xD010, 0xB387, 0xD012, 0xB388, 0xD013, 0xB389, 0xD014, 0xB38A, 0xD015, 0xB38B, 0xD016, 0xB38C, 0xD017, 0xB38D, 0xD019, 0xB38E, 0xD01A, 0xB38F, 0xD01B, 0xB390, 0xD01C, 0xB391, 0xD01D, 0xB392, 0xD01E, 0xB393, 0xD01F, 0xB394, 0xD020, 0xB395, 0xD021, 0xB396, 0xD022, 0xB397, 0xD023, 0xB398, 0xD024, 0xB399, 0xD025, 0xB39A, 0xD026, 0xB39B, 0xD027, 0xB39C, 0xD028, 0xB39D, 0xD029, 0xB39E, 0xD02A, 0xB39F, 0xD02B, 0xB3A0, 0xD02C, 0xB3A1, 0xB05D, 0xB3A2, 0xB07C, 0xB3A3, 0xB07D, 0xB3A4, 0xB080, 0xB3A5, 0xB084, 0xB3A6, 0xB08C, 0xB3A7, 0xB08D, 0xB3A8, 0xB08F, 0xB3A9, 0xB091, 0xB3AA, 0xB098, 0xB3AB, 0xB099, 0xB3AC, 0xB09A, 0xB3AD, 0xB09C, 0xB3AE, 0xB09F, 0xB3AF, 0xB0A0, 0xB3B0, 0xB0A1, 0xB3B1, 0xB0A2, 0xB3B2, 0xB0A8, 0xB3B3, 0xB0A9, 0xB3B4, 0xB0AB, 0xB3B5, 0xB0AC, 0xB3B6, 0xB0AD, 0xB3B7, 0xB0AE, 0xB3B8, 0xB0AF, 0xB3B9, 0xB0B1, 0xB3BA, 0xB0B3, 0xB3BB, 0xB0B4, 0xB3BC, 0xB0B5, 0xB3BD, 0xB0B8, 0xB3BE, 0xB0BC, 0xB3BF, 0xB0C4, 0xB3C0, 0xB0C5, 0xB3C1, 0xB0C7, 0xB3C2, 0xB0C8, 0xB3C3, 0xB0C9, 0xB3C4, 0xB0D0, 0xB3C5, 0xB0D1, 0xB3C6, 0xB0D4, 0xB3C7, 0xB0D8, 0xB3C8, 0xB0E0, 0xB3C9, 0xB0E5, 0xB3CA, 0xB108, 0xB3CB, 0xB109, 0xB3CC, 0xB10B, 0xB3CD, 0xB10C, 0xB3CE, 0xB110, 0xB3CF, 0xB112, 0xB3D0, 0xB113, 0xB3D1, 0xB118, 0xB3D2, 0xB119, 0xB3D3, 0xB11B, 0xB3D4, 0xB11C, 0xB3D5, 0xB11D, 0xB3D6, 0xB123, 0xB3D7, 0xB124, 0xB3D8, 0xB125, 0xB3D9, 0xB128, 0xB3DA, 0xB12C, 0xB3DB, 0xB134, 0xB3DC, 0xB135, 0xB3DD, 0xB137, 0xB3DE, 0xB138, 0xB3DF, 0xB139, 0xB3E0, 0xB140, 0xB3E1, 0xB141, 0xB3E2, 0xB144, 0xB3E3, 0xB148, 0xB3E4, 0xB150, 0xB3E5, 0xB151, 0xB3E6, 0xB154, 0xB3E7, 0xB155, 0xB3E8, 0xB158, 0xB3E9, 0xB15C, 0xB3EA, 0xB160, 0xB3EB, 0xB178, 0xB3EC, 0xB179, 0xB3ED, 0xB17C, 0xB3EE, 0xB180, 0xB3EF, 0xB182, 0xB3F0, 0xB188, 0xB3F1, 0xB189, 0xB3F2, 0xB18B, 0xB3F3, 0xB18D, 0xB3F4, 0xB192, 0xB3F5, 0xB193, 0xB3F6, 0xB194, 0xB3F7, 0xB198, 0xB3F8, 0xB19C, 0xB3F9, 0xB1A8, 0xB3FA, 0xB1CC, 0xB3FB, 0xB1D0, 0xB3FC, 0xB1D4, 0xB3FD, 0xB1DC, 0xB3FE, 0xB1DD, 0xB441, 0xD02E, 0xB442, 0xD02F, 0xB443, 0xD030, 0xB444, 0xD031, 0xB445, 0xD032, 0xB446, 0xD033, 0xB447, 0xD036, 0xB448, 0xD037, 0xB449, 0xD039, 0xB44A, 0xD03A, 0xB44B, 0xD03B, 0xB44C, 0xD03D, 0xB44D, 0xD03E, 0xB44E, 0xD03F, 0xB44F, 0xD040, 0xB450, 0xD041, 0xB451, 0xD042, 0xB452, 0xD043, 0xB453, 0xD046, 0xB454, 0xD048, 0xB455, 0xD04A, 0xB456, 0xD04B, 0xB457, 0xD04C, 0xB458, 0xD04D, 0xB459, 0xD04E, 0xB45A, 0xD04F, 0xB461, 0xD051, 0xB462, 0xD052, 0xB463, 0xD053, 0xB464, 0xD055, 0xB465, 0xD056, 0xB466, 0xD057, 0xB467, 0xD059, 0xB468, 0xD05A, 0xB469, 0xD05B, 0xB46A, 0xD05C, 0xB46B, 0xD05D, 0xB46C, 0xD05E, 0xB46D, 0xD05F, 0xB46E, 0xD061, 0xB46F, 0xD062, 0xB470, 0xD063, 0xB471, 0xD064, 0xB472, 0xD065, 0xB473, 0xD066, 0xB474, 0xD067, 0xB475, 0xD068, 0xB476, 0xD069, 0xB477, 0xD06A, 0xB478, 0xD06B, 0xB479, 0xD06E, 0xB47A, 0xD06F, 0xB481, 0xD071, 0xB482, 0xD072, 0xB483, 0xD073, 0xB484, 0xD075, 0xB485, 0xD076, 0xB486, 0xD077, 0xB487, 0xD078, 0xB488, 0xD079, 0xB489, 0xD07A, 0xB48A, 0xD07B, 0xB48B, 0xD07E, 0xB48C, 0xD07F, 0xB48D, 0xD080, 0xB48E, 0xD082, 0xB48F, 0xD083, 0xB490, 0xD084, 0xB491, 0xD085, 0xB492, 0xD086, 0xB493, 0xD087, 0xB494, 0xD088, 0xB495, 0xD089, 0xB496, 0xD08A, 0xB497, 0xD08B, 0xB498, 0xD08C, 0xB499, 0xD08D, 0xB49A, 0xD08E, 0xB49B, 0xD08F, 0xB49C, 0xD090, 0xB49D, 0xD091, 0xB49E, 0xD092, 0xB49F, 0xD093, 0xB4A0, 0xD094, 0xB4A1, 0xB1DF, 0xB4A2, 0xB1E8, 0xB4A3, 0xB1E9, 0xB4A4, 0xB1EC, 0xB4A5, 0xB1F0, 0xB4A6, 0xB1F9, 0xB4A7, 0xB1FB, 0xB4A8, 0xB1FD, 0xB4A9, 0xB204, 0xB4AA, 0xB205, 0xB4AB, 0xB208, 0xB4AC, 0xB20B, 0xB4AD, 0xB20C, 0xB4AE, 0xB214, 0xB4AF, 0xB215, 0xB4B0, 0xB217, 0xB4B1, 0xB219, 0xB4B2, 0xB220, 0xB4B3, 0xB234, 0xB4B4, 0xB23C, 0xB4B5, 0xB258, 0xB4B6, 0xB25C, 0xB4B7, 0xB260, 0xB4B8, 0xB268, 0xB4B9, 0xB269, 0xB4BA, 0xB274, 0xB4BB, 0xB275, 0xB4BC, 0xB27C, 0xB4BD, 0xB284, 0xB4BE, 0xB285, 0xB4BF, 0xB289, 0xB4C0, 0xB290, 0xB4C1, 0xB291, 0xB4C2, 0xB294, 0xB4C3, 0xB298, 0xB4C4, 0xB299, 0xB4C5, 0xB29A, 0xB4C6, 0xB2A0, 0xB4C7, 0xB2A1, 0xB4C8, 0xB2A3, 0xB4C9, 0xB2A5, 0xB4CA, 0xB2A6, 0xB4CB, 0xB2AA, 0xB4CC, 0xB2AC, 0xB4CD, 0xB2B0, 0xB4CE, 0xB2B4, 0xB4CF, 0xB2C8, 0xB4D0, 0xB2C9, 0xB4D1, 0xB2CC, 0xB4D2, 0xB2D0, 0xB4D3, 0xB2D2, 0xB4D4, 0xB2D8, 0xB4D5, 0xB2D9, 0xB4D6, 0xB2DB, 0xB4D7, 0xB2DD, 0xB4D8, 0xB2E2, 0xB4D9, 0xB2E4, 0xB4DA, 0xB2E5, 0xB4DB, 0xB2E6, 0xB4DC, 0xB2E8, 0xB4DD, 0xB2EB, 0xB4DE, 0xB2EC, 0xB4DF, 0xB2ED, 0xB4E0, 0xB2EE, 0xB4E1, 0xB2EF, 0xB4E2, 0xB2F3, 0xB4E3, 0xB2F4, 0xB4E4, 0xB2F5, 0xB4E5, 0xB2F7, 0xB4E6, 0xB2F8, 0xB4E7, 0xB2F9, 0xB4E8, 0xB2FA, 0xB4E9, 0xB2FB, 0xB4EA, 0xB2FF, 0xB4EB, 0xB300, 0xB4EC, 0xB301, 0xB4ED, 0xB304, 0xB4EE, 0xB308, 0xB4EF, 0xB310, 0xB4F0, 0xB311, 0xB4F1, 0xB313, 0xB4F2, 0xB314, 0xB4F3, 0xB315, 0xB4F4, 0xB31C, 0xB4F5, 0xB354, 0xB4F6, 0xB355, 0xB4F7, 0xB356, 0xB4F8, 0xB358, 0xB4F9, 0xB35B, 0xB4FA, 0xB35C, 0xB4FB, 0xB35E, 0xB4FC, 0xB35F, 0xB4FD, 0xB364, 0xB4FE, 0xB365, 0xB541, 0xD095, 0xB542, 0xD096, 0xB543, 0xD097, 0xB544, 0xD098, 0xB545, 0xD099, 0xB546, 0xD09A, 0xB547, 0xD09B, 0xB548, 0xD09C, 0xB549, 0xD09D, 0xB54A, 0xD09E, 0xB54B, 0xD09F, 0xB54C, 0xD0A0, 0xB54D, 0xD0A1, 0xB54E, 0xD0A2, 0xB54F, 0xD0A3, 0xB550, 0xD0A6, 0xB551, 0xD0A7, 0xB552, 0xD0A9, 0xB553, 0xD0AA, 0xB554, 0xD0AB, 0xB555, 0xD0AD, 0xB556, 0xD0AE, 0xB557, 0xD0AF, 0xB558, 0xD0B0, 0xB559, 0xD0B1, 0xB55A, 0xD0B2, 0xB561, 0xD0B3, 0xB562, 0xD0B6, 0xB563, 0xD0B8, 0xB564, 0xD0BA, 0xB565, 0xD0BB, 0xB566, 0xD0BC, 0xB567, 0xD0BD, 0xB568, 0xD0BE, 0xB569, 0xD0BF, 0xB56A, 0xD0C2, 0xB56B, 0xD0C3, 0xB56C, 0xD0C5, 0xB56D, 0xD0C6, 0xB56E, 0xD0C7, 0xB56F, 0xD0CA, 0xB570, 0xD0CB, 0xB571, 0xD0CC, 0xB572, 0xD0CD, 0xB573, 0xD0CE, 0xB574, 0xD0CF, 0xB575, 0xD0D2, 0xB576, 0xD0D6, 0xB577, 0xD0D7, 0xB578, 0xD0D8, 0xB579, 0xD0D9, 0xB57A, 0xD0DA, 0xB581, 0xD0DB, 0xB582, 0xD0DE, 0xB583, 0xD0DF, 0xB584, 0xD0E1, 0xB585, 0xD0E2, 0xB586, 0xD0E3, 0xB587, 0xD0E5, 0xB588, 0xD0E6, 0xB589, 0xD0E7, 0xB58A, 0xD0E8, 0xB58B, 0xD0E9, 0xB58C, 0xD0EA, 0xB58D, 0xD0EB, 0xB58E, 0xD0EE, 0xB58F, 0xD0F2, 0xB590, 0xD0F3, 0xB591, 0xD0F4, 0xB592, 0xD0F5, 0xB593, 0xD0F6, 0xB594, 0xD0F7, 0xB595, 0xD0F9, 0xB596, 0xD0FA, 0xB597, 0xD0FB, 0xB598, 0xD0FC, 0xB599, 0xD0FD, 0xB59A, 0xD0FE, 0xB59B, 0xD0FF, 0xB59C, 0xD100, 0xB59D, 0xD101, 0xB59E, 0xD102, 0xB59F, 0xD103, 0xB5A0, 0xD104, 0xB5A1, 0xB367, 0xB5A2, 0xB369, 0xB5A3, 0xB36B, 0xB5A4, 0xB36E, 0xB5A5, 0xB370, 0xB5A6, 0xB371, 0xB5A7, 0xB374, 0xB5A8, 0xB378, 0xB5A9, 0xB380, 0xB5AA, 0xB381, 0xB5AB, 0xB383, 0xB5AC, 0xB384, 0xB5AD, 0xB385, 0xB5AE, 0xB38C, 0xB5AF, 0xB390, 0xB5B0, 0xB394, 0xB5B1, 0xB3A0, 0xB5B2, 0xB3A1, 0xB5B3, 0xB3A8, 0xB5B4, 0xB3AC, 0xB5B5, 0xB3C4, 0xB5B6, 0xB3C5, 0xB5B7, 0xB3C8, 0xB5B8, 0xB3CB, 0xB5B9, 0xB3CC, 0xB5BA, 0xB3CE, 0xB5BB, 0xB3D0, 0xB5BC, 0xB3D4, 0xB5BD, 0xB3D5, 0xB5BE, 0xB3D7, 0xB5BF, 0xB3D9, 0xB5C0, 0xB3DB, 0xB5C1, 0xB3DD, 0xB5C2, 0xB3E0, 0xB5C3, 0xB3E4, 0xB5C4, 0xB3E8, 0xB5C5, 0xB3FC, 0xB5C6, 0xB410, 0xB5C7, 0xB418, 0xB5C8, 0xB41C, 0xB5C9, 0xB420, 0xB5CA, 0xB428, 0xB5CB, 0xB429, 0xB5CC, 0xB42B, 0xB5CD, 0xB434, 0xB5CE, 0xB450, 0xB5CF, 0xB451, 0xB5D0, 0xB454, 0xB5D1, 0xB458, 0xB5D2, 0xB460, 0xB5D3, 0xB461, 0xB5D4, 0xB463, 0xB5D5, 0xB465, 0xB5D6, 0xB46C, 0xB5D7, 0xB480, 0xB5D8, 0xB488, 0xB5D9, 0xB49D, 0xB5DA, 0xB4A4, 0xB5DB, 0xB4A8, 0xB5DC, 0xB4AC, 0xB5DD, 0xB4B5, 0xB5DE, 0xB4B7, 0xB5DF, 0xB4B9, 0xB5E0, 0xB4C0, 0xB5E1, 0xB4C4, 0xB5E2, 0xB4C8, 0xB5E3, 0xB4D0, 0xB5E4, 0xB4D5, 0xB5E5, 0xB4DC, 0xB5E6, 0xB4DD, 0xB5E7, 0xB4E0, 0xB5E8, 0xB4E3, 0xB5E9, 0xB4E4, 0xB5EA, 0xB4E6, 0xB5EB, 0xB4EC, 0xB5EC, 0xB4ED, 0xB5ED, 0xB4EF, 0xB5EE, 0xB4F1, 0xB5EF, 0xB4F8, 0xB5F0, 0xB514, 0xB5F1, 0xB515, 0xB5F2, 0xB518, 0xB5F3, 0xB51B, 0xB5F4, 0xB51C, 0xB5F5, 0xB524, 0xB5F6, 0xB525, 0xB5F7, 0xB527, 0xB5F8, 0xB528, 0xB5F9, 0xB529, 0xB5FA, 0xB52A, 0xB5FB, 0xB530, 0xB5FC, 0xB531, 0xB5FD, 0xB534, 0xB5FE, 0xB538, 0xB641, 0xD105, 0xB642, 0xD106, 0xB643, 0xD107, 0xB644, 0xD108, 0xB645, 0xD109, 0xB646, 0xD10A, 0xB647, 0xD10B, 0xB648, 0xD10C, 0xB649, 0xD10E, 0xB64A, 0xD10F, 0xB64B, 0xD110, 0xB64C, 0xD111, 0xB64D, 0xD112, 0xB64E, 0xD113, 0xB64F, 0xD114, 0xB650, 0xD115, 0xB651, 0xD116, 0xB652, 0xD117, 0xB653, 0xD118, 0xB654, 0xD119, 0xB655, 0xD11A, 0xB656, 0xD11B, 0xB657, 0xD11C, 0xB658, 0xD11D, 0xB659, 0xD11E, 0xB65A, 0xD11F, 0xB661, 0xD120, 0xB662, 0xD121, 0xB663, 0xD122, 0xB664, 0xD123, 0xB665, 0xD124, 0xB666, 0xD125, 0xB667, 0xD126, 0xB668, 0xD127, 0xB669, 0xD128, 0xB66A, 0xD129, 0xB66B, 0xD12A, 0xB66C, 0xD12B, 0xB66D, 0xD12C, 0xB66E, 0xD12D, 0xB66F, 0xD12E, 0xB670, 0xD12F, 0xB671, 0xD132, 0xB672, 0xD133, 0xB673, 0xD135, 0xB674, 0xD136, 0xB675, 0xD137, 0xB676, 0xD139, 0xB677, 0xD13B, 0xB678, 0xD13C, 0xB679, 0xD13D, 0xB67A, 0xD13E, 0xB681, 0xD13F, 0xB682, 0xD142, 0xB683, 0xD146, 0xB684, 0xD147, 0xB685, 0xD148, 0xB686, 0xD149, 0xB687, 0xD14A, 0xB688, 0xD14B, 0xB689, 0xD14E, 0xB68A, 0xD14F, 0xB68B, 0xD151, 0xB68C, 0xD152, 0xB68D, 0xD153, 0xB68E, 0xD155, 0xB68F, 0xD156, 0xB690, 0xD157, 0xB691, 0xD158, 0xB692, 0xD159, 0xB693, 0xD15A, 0xB694, 0xD15B, 0xB695, 0xD15E, 0xB696, 0xD160, 0xB697, 0xD162, 0xB698, 0xD163, 0xB699, 0xD164, 0xB69A, 0xD165, 0xB69B, 0xD166, 0xB69C, 0xD167, 0xB69D, 0xD169, 0xB69E, 0xD16A, 0xB69F, 0xD16B, 0xB6A0, 0xD16D, 0xB6A1, 0xB540, 0xB6A2, 0xB541, 0xB6A3, 0xB543, 0xB6A4, 0xB544, 0xB6A5, 0xB545, 0xB6A6, 0xB54B, 0xB6A7, 0xB54C, 0xB6A8, 0xB54D, 0xB6A9, 0xB550, 0xB6AA, 0xB554, 0xB6AB, 0xB55C, 0xB6AC, 0xB55D, 0xB6AD, 0xB55F, 0xB6AE, 0xB560, 0xB6AF, 0xB561, 0xB6B0, 0xB5A0, 0xB6B1, 0xB5A1, 0xB6B2, 0xB5A4, 0xB6B3, 0xB5A8, 0xB6B4, 0xB5AA, 0xB6B5, 0xB5AB, 0xB6B6, 0xB5B0, 0xB6B7, 0xB5B1, 0xB6B8, 0xB5B3, 0xB6B9, 0xB5B4, 0xB6BA, 0xB5B5, 0xB6BB, 0xB5BB, 0xB6BC, 0xB5BC, 0xB6BD, 0xB5BD, 0xB6BE, 0xB5C0, 0xB6BF, 0xB5C4, 0xB6C0, 0xB5CC, 0xB6C1, 0xB5CD, 0xB6C2, 0xB5CF, 0xB6C3, 0xB5D0, 0xB6C4, 0xB5D1, 0xB6C5, 0xB5D8, 0xB6C6, 0xB5EC, 0xB6C7, 0xB610, 0xB6C8, 0xB611, 0xB6C9, 0xB614, 0xB6CA, 0xB618, 0xB6CB, 0xB625, 0xB6CC, 0xB62C, 0xB6CD, 0xB634, 0xB6CE, 0xB648, 0xB6CF, 0xB664, 0xB6D0, 0xB668, 0xB6D1, 0xB69C, 0xB6D2, 0xB69D, 0xB6D3, 0xB6A0, 0xB6D4, 0xB6A4, 0xB6D5, 0xB6AB, 0xB6D6, 0xB6AC, 0xB6D7, 0xB6B1, 0xB6D8, 0xB6D4, 0xB6D9, 0xB6F0, 0xB6DA, 0xB6F4, 0xB6DB, 0xB6F8, 0xB6DC, 0xB700, 0xB6DD, 0xB701, 0xB6DE, 0xB705, 0xB6DF, 0xB728, 0xB6E0, 0xB729, 0xB6E1, 0xB72C, 0xB6E2, 0xB72F, 0xB6E3, 0xB730, 0xB6E4, 0xB738, 0xB6E5, 0xB739, 0xB6E6, 0xB73B, 0xB6E7, 0xB744, 0xB6E8, 0xB748, 0xB6E9, 0xB74C, 0xB6EA, 0xB754, 0xB6EB, 0xB755, 0xB6EC, 0xB760, 0xB6ED, 0xB764, 0xB6EE, 0xB768, 0xB6EF, 0xB770, 0xB6F0, 0xB771, 0xB6F1, 0xB773, 0xB6F2, 0xB775, 0xB6F3, 0xB77C, 0xB6F4, 0xB77D, 0xB6F5, 0xB780, 0xB6F6, 0xB784, 0xB6F7, 0xB78C, 0xB6F8, 0xB78D, 0xB6F9, 0xB78F, 0xB6FA, 0xB790, 0xB6FB, 0xB791, 0xB6FC, 0xB792, 0xB6FD, 0xB796, 0xB6FE, 0xB797, 0xB741, 0xD16E, 0xB742, 0xD16F, 0xB743, 0xD170, 0xB744, 0xD171, 0xB745, 0xD172, 0xB746, 0xD173, 0xB747, 0xD174, 0xB748, 0xD175, 0xB749, 0xD176, 0xB74A, 0xD177, 0xB74B, 0xD178, 0xB74C, 0xD179, 0xB74D, 0xD17A, 0xB74E, 0xD17B, 0xB74F, 0xD17D, 0xB750, 0xD17E, 0xB751, 0xD17F, 0xB752, 0xD180, 0xB753, 0xD181, 0xB754, 0xD182, 0xB755, 0xD183, 0xB756, 0xD185, 0xB757, 0xD186, 0xB758, 0xD187, 0xB759, 0xD189, 0xB75A, 0xD18A, 0xB761, 0xD18B, 0xB762, 0xD18C, 0xB763, 0xD18D, 0xB764, 0xD18E, 0xB765, 0xD18F, 0xB766, 0xD190, 0xB767, 0xD191, 0xB768, 0xD192, 0xB769, 0xD193, 0xB76A, 0xD194, 0xB76B, 0xD195, 0xB76C, 0xD196, 0xB76D, 0xD197, 0xB76E, 0xD198, 0xB76F, 0xD199, 0xB770, 0xD19A, 0xB771, 0xD19B, 0xB772, 0xD19C, 0xB773, 0xD19D, 0xB774, 0xD19E, 0xB775, 0xD19F, 0xB776, 0xD1A2, 0xB777, 0xD1A3, 0xB778, 0xD1A5, 0xB779, 0xD1A6, 0xB77A, 0xD1A7, 0xB781, 0xD1A9, 0xB782, 0xD1AA, 0xB783, 0xD1AB, 0xB784, 0xD1AC, 0xB785, 0xD1AD, 0xB786, 0xD1AE, 0xB787, 0xD1AF, 0xB788, 0xD1B2, 0xB789, 0xD1B4, 0xB78A, 0xD1B6, 0xB78B, 0xD1B7, 0xB78C, 0xD1B8, 0xB78D, 0xD1B9, 0xB78E, 0xD1BB, 0xB78F, 0xD1BD, 0xB790, 0xD1BE, 0xB791, 0xD1BF, 0xB792, 0xD1C1, 0xB793, 0xD1C2, 0xB794, 0xD1C3, 0xB795, 0xD1C4, 0xB796, 0xD1C5, 0xB797, 0xD1C6, 0xB798, 0xD1C7, 0xB799, 0xD1C8, 0xB79A, 0xD1C9, 0xB79B, 0xD1CA, 0xB79C, 0xD1CB, 0xB79D, 0xD1CC, 0xB79E, 0xD1CD, 0xB79F, 0xD1CE, 0xB7A0, 0xD1CF, 0xB7A1, 0xB798, 0xB7A2, 0xB799, 0xB7A3, 0xB79C, 0xB7A4, 0xB7A0, 0xB7A5, 0xB7A8, 0xB7A6, 0xB7A9, 0xB7A7, 0xB7AB, 0xB7A8, 0xB7AC, 0xB7A9, 0xB7AD, 0xB7AA, 0xB7B4, 0xB7AB, 0xB7B5, 0xB7AC, 0xB7B8, 0xB7AD, 0xB7C7, 0xB7AE, 0xB7C9, 0xB7AF, 0xB7EC, 0xB7B0, 0xB7ED, 0xB7B1, 0xB7F0, 0xB7B2, 0xB7F4, 0xB7B3, 0xB7FC, 0xB7B4, 0xB7FD, 0xB7B5, 0xB7FF, 0xB7B6, 0xB800, 0xB7B7, 0xB801, 0xB7B8, 0xB807, 0xB7B9, 0xB808, 0xB7BA, 0xB809, 0xB7BB, 0xB80C, 0xB7BC, 0xB810, 0xB7BD, 0xB818, 0xB7BE, 0xB819, 0xB7BF, 0xB81B, 0xB7C0, 0xB81D, 0xB7C1, 0xB824, 0xB7C2, 0xB825, 0xB7C3, 0xB828, 0xB7C4, 0xB82C, 0xB7C5, 0xB834, 0xB7C6, 0xB835, 0xB7C7, 0xB837, 0xB7C8, 0xB838, 0xB7C9, 0xB839, 0xB7CA, 0xB840, 0xB7CB, 0xB844, 0xB7CC, 0xB851, 0xB7CD, 0xB853, 0xB7CE, 0xB85C, 0xB7CF, 0xB85D, 0xB7D0, 0xB860, 0xB7D1, 0xB864, 0xB7D2, 0xB86C, 0xB7D3, 0xB86D, 0xB7D4, 0xB86F, 0xB7D5, 0xB871, 0xB7D6, 0xB878, 0xB7D7, 0xB87C, 0xB7D8, 0xB88D, 0xB7D9, 0xB8A8, 0xB7DA, 0xB8B0, 0xB7DB, 0xB8B4, 0xB7DC, 0xB8B8, 0xB7DD, 0xB8C0, 0xB7DE, 0xB8C1, 0xB7DF, 0xB8C3, 0xB7E0, 0xB8C5, 0xB7E1, 0xB8CC, 0xB7E2, 0xB8D0, 0xB7E3, 0xB8D4, 0xB7E4, 0xB8DD, 0xB7E5, 0xB8DF, 0xB7E6, 0xB8E1, 0xB7E7, 0xB8E8, 0xB7E8, 0xB8E9, 0xB7E9, 0xB8EC, 0xB7EA, 0xB8F0, 0xB7EB, 0xB8F8, 0xB7EC, 0xB8F9, 0xB7ED, 0xB8FB, 0xB7EE, 0xB8FD, 0xB7EF, 0xB904, 0xB7F0, 0xB918, 0xB7F1, 0xB920, 0xB7F2, 0xB93C, 0xB7F3, 0xB93D, 0xB7F4, 0xB940, 0xB7F5, 0xB944, 0xB7F6, 0xB94C, 0xB7F7, 0xB94F, 0xB7F8, 0xB951, 0xB7F9, 0xB958, 0xB7FA, 0xB959, 0xB7FB, 0xB95C, 0xB7FC, 0xB960, 0xB7FD, 0xB968, 0xB7FE, 0xB969, 0xB841, 0xD1D0, 0xB842, 0xD1D1, 0xB843, 0xD1D2, 0xB844, 0xD1D3, 0xB845, 0xD1D4, 0xB846, 0xD1D5, 0xB847, 0xD1D6, 0xB848, 0xD1D7, 0xB849, 0xD1D9, 0xB84A, 0xD1DA, 0xB84B, 0xD1DB, 0xB84C, 0xD1DC, 0xB84D, 0xD1DD, 0xB84E, 0xD1DE, 0xB84F, 0xD1DF, 0xB850, 0xD1E0, 0xB851, 0xD1E1, 0xB852, 0xD1E2, 0xB853, 0xD1E3, 0xB854, 0xD1E4, 0xB855, 0xD1E5, 0xB856, 0xD1E6, 0xB857, 0xD1E7, 0xB858, 0xD1E8, 0xB859, 0xD1E9, 0xB85A, 0xD1EA, 0xB861, 0xD1EB, 0xB862, 0xD1EC, 0xB863, 0xD1ED, 0xB864, 0xD1EE, 0xB865, 0xD1EF, 0xB866, 0xD1F0, 0xB867, 0xD1F1, 0xB868, 0xD1F2, 0xB869, 0xD1F3, 0xB86A, 0xD1F5, 0xB86B, 0xD1F6, 0xB86C, 0xD1F7, 0xB86D, 0xD1F9, 0xB86E, 0xD1FA, 0xB86F, 0xD1FB, 0xB870, 0xD1FC, 0xB871, 0xD1FD, 0xB872, 0xD1FE, 0xB873, 0xD1FF, 0xB874, 0xD200, 0xB875, 0xD201, 0xB876, 0xD202, 0xB877, 0xD203, 0xB878, 0xD204, 0xB879, 0xD205, 0xB87A, 0xD206, 0xB881, 0xD208, 0xB882, 0xD20A, 0xB883, 0xD20B, 0xB884, 0xD20C, 0xB885, 0xD20D, 0xB886, 0xD20E, 0xB887, 0xD20F, 0xB888, 0xD211, 0xB889, 0xD212, 0xB88A, 0xD213, 0xB88B, 0xD214, 0xB88C, 0xD215, 0xB88D, 0xD216, 0xB88E, 0xD217, 0xB88F, 0xD218, 0xB890, 0xD219, 0xB891, 0xD21A, 0xB892, 0xD21B, 0xB893, 0xD21C, 0xB894, 0xD21D, 0xB895, 0xD21E, 0xB896, 0xD21F, 0xB897, 0xD220, 0xB898, 0xD221, 0xB899, 0xD222, 0xB89A, 0xD223, 0xB89B, 0xD224, 0xB89C, 0xD225, 0xB89D, 0xD226, 0xB89E, 0xD227, 0xB89F, 0xD228, 0xB8A0, 0xD229, 0xB8A1, 0xB96B, 0xB8A2, 0xB96D, 0xB8A3, 0xB974, 0xB8A4, 0xB975, 0xB8A5, 0xB978, 0xB8A6, 0xB97C, 0xB8A7, 0xB984, 0xB8A8, 0xB985, 0xB8A9, 0xB987, 0xB8AA, 0xB989, 0xB8AB, 0xB98A, 0xB8AC, 0xB98D, 0xB8AD, 0xB98E, 0xB8AE, 0xB9AC, 0xB8AF, 0xB9AD, 0xB8B0, 0xB9B0, 0xB8B1, 0xB9B4, 0xB8B2, 0xB9BC, 0xB8B3, 0xB9BD, 0xB8B4, 0xB9BF, 0xB8B5, 0xB9C1, 0xB8B6, 0xB9C8, 0xB8B7, 0xB9C9, 0xB8B8, 0xB9CC, 0xB8B9, 0xB9CE, 0xB8BA, 0xB9CF, 0xB8BB, 0xB9D0, 0xB8BC, 0xB9D1, 0xB8BD, 0xB9D2, 0xB8BE, 0xB9D8, 0xB8BF, 0xB9D9, 0xB8C0, 0xB9DB, 0xB8C1, 0xB9DD, 0xB8C2, 0xB9DE, 0xB8C3, 0xB9E1, 0xB8C4, 0xB9E3, 0xB8C5, 0xB9E4, 0xB8C6, 0xB9E5, 0xB8C7, 0xB9E8, 0xB8C8, 0xB9EC, 0xB8C9, 0xB9F4, 0xB8CA, 0xB9F5, 0xB8CB, 0xB9F7, 0xB8CC, 0xB9F8, 0xB8CD, 0xB9F9, 0xB8CE, 0xB9FA, 0xB8CF, 0xBA00, 0xB8D0, 0xBA01, 0xB8D1, 0xBA08, 0xB8D2, 0xBA15, 0xB8D3, 0xBA38, 0xB8D4, 0xBA39, 0xB8D5, 0xBA3C, 0xB8D6, 0xBA40, 0xB8D7, 0xBA42, 0xB8D8, 0xBA48, 0xB8D9, 0xBA49, 0xB8DA, 0xBA4B, 0xB8DB, 0xBA4D, 0xB8DC, 0xBA4E, 0xB8DD, 0xBA53, 0xB8DE, 0xBA54, 0xB8DF, 0xBA55, 0xB8E0, 0xBA58, 0xB8E1, 0xBA5C, 0xB8E2, 0xBA64, 0xB8E3, 0xBA65, 0xB8E4, 0xBA67, 0xB8E5, 0xBA68, 0xB8E6, 0xBA69, 0xB8E7, 0xBA70, 0xB8E8, 0xBA71, 0xB8E9, 0xBA74, 0xB8EA, 0xBA78, 0xB8EB, 0xBA83, 0xB8EC, 0xBA84, 0xB8ED, 0xBA85, 0xB8EE, 0xBA87, 0xB8EF, 0xBA8C, 0xB8F0, 0xBAA8, 0xB8F1, 0xBAA9, 0xB8F2, 0xBAAB, 0xB8F3, 0xBAAC, 0xB8F4, 0xBAB0, 0xB8F5, 0xBAB2, 0xB8F6, 0xBAB8, 0xB8F7, 0xBAB9, 0xB8F8, 0xBABB, 0xB8F9, 0xBABD, 0xB8FA, 0xBAC4, 0xB8FB, 0xBAC8, 0xB8FC, 0xBAD8, 0xB8FD, 0xBAD9, 0xB8FE, 0xBAFC, 0xB941, 0xD22A, 0xB942, 0xD22B, 0xB943, 0xD22E, 0xB944, 0xD22F, 0xB945, 0xD231, 0xB946, 0xD232, 0xB947, 0xD233, 0xB948, 0xD235, 0xB949, 0xD236, 0xB94A, 0xD237, 0xB94B, 0xD238, 0xB94C, 0xD239, 0xB94D, 0xD23A, 0xB94E, 0xD23B, 0xB94F, 0xD23E, 0xB950, 0xD240, 0xB951, 0xD242, 0xB952, 0xD243, 0xB953, 0xD244, 0xB954, 0xD245, 0xB955, 0xD246, 0xB956, 0xD247, 0xB957, 0xD249, 0xB958, 0xD24A, 0xB959, 0xD24B, 0xB95A, 0xD24C, 0xB961, 0xD24D, 0xB962, 0xD24E, 0xB963, 0xD24F, 0xB964, 0xD250, 0xB965, 0xD251, 0xB966, 0xD252, 0xB967, 0xD253, 0xB968, 0xD254, 0xB969, 0xD255, 0xB96A, 0xD256, 0xB96B, 0xD257, 0xB96C, 0xD258, 0xB96D, 0xD259, 0xB96E, 0xD25A, 0xB96F, 0xD25B, 0xB970, 0xD25D, 0xB971, 0xD25E, 0xB972, 0xD25F, 0xB973, 0xD260, 0xB974, 0xD261, 0xB975, 0xD262, 0xB976, 0xD263, 0xB977, 0xD265, 0xB978, 0xD266, 0xB979, 0xD267, 0xB97A, 0xD268, 0xB981, 0xD269, 0xB982, 0xD26A, 0xB983, 0xD26B, 0xB984, 0xD26C, 0xB985, 0xD26D, 0xB986, 0xD26E, 0xB987, 0xD26F, 0xB988, 0xD270, 0xB989, 0xD271, 0xB98A, 0xD272, 0xB98B, 0xD273, 0xB98C, 0xD274, 0xB98D, 0xD275, 0xB98E, 0xD276, 0xB98F, 0xD277, 0xB990, 0xD278, 0xB991, 0xD279, 0xB992, 0xD27A, 0xB993, 0xD27B, 0xB994, 0xD27C, 0xB995, 0xD27D, 0xB996, 0xD27E, 0xB997, 0xD27F, 0xB998, 0xD282, 0xB999, 0xD283, 0xB99A, 0xD285, 0xB99B, 0xD286, 0xB99C, 0xD287, 0xB99D, 0xD289, 0xB99E, 0xD28A, 0xB99F, 0xD28B, 0xB9A0, 0xD28C, 0xB9A1, 0xBB00, 0xB9A2, 0xBB04, 0xB9A3, 0xBB0D, 0xB9A4, 0xBB0F, 0xB9A5, 0xBB11, 0xB9A6, 0xBB18, 0xB9A7, 0xBB1C, 0xB9A8, 0xBB20, 0xB9A9, 0xBB29, 0xB9AA, 0xBB2B, 0xB9AB, 0xBB34, 0xB9AC, 0xBB35, 0xB9AD, 0xBB36, 0xB9AE, 0xBB38, 0xB9AF, 0xBB3B, 0xB9B0, 0xBB3C, 0xB9B1, 0xBB3D, 0xB9B2, 0xBB3E, 0xB9B3, 0xBB44, 0xB9B4, 0xBB45, 0xB9B5, 0xBB47, 0xB9B6, 0xBB49, 0xB9B7, 0xBB4D, 0xB9B8, 0xBB4F, 0xB9B9, 0xBB50, 0xB9BA, 0xBB54, 0xB9BB, 0xBB58, 0xB9BC, 0xBB61, 0xB9BD, 0xBB63, 0xB9BE, 0xBB6C, 0xB9BF, 0xBB88, 0xB9C0, 0xBB8C, 0xB9C1, 0xBB90, 0xB9C2, 0xBBA4, 0xB9C3, 0xBBA8, 0xB9C4, 0xBBAC, 0xB9C5, 0xBBB4, 0xB9C6, 0xBBB7, 0xB9C7, 0xBBC0, 0xB9C8, 0xBBC4, 0xB9C9, 0xBBC8, 0xB9CA, 0xBBD0, 0xB9CB, 0xBBD3, 0xB9CC, 0xBBF8, 0xB9CD, 0xBBF9, 0xB9CE, 0xBBFC, 0xB9CF, 0xBBFF, 0xB9D0, 0xBC00, 0xB9D1, 0xBC02, 0xB9D2, 0xBC08, 0xB9D3, 0xBC09, 0xB9D4, 0xBC0B, 0xB9D5, 0xBC0C, 0xB9D6, 0xBC0D, 0xB9D7, 0xBC0F, 0xB9D8, 0xBC11, 0xB9D9, 0xBC14, 0xB9DA, 0xBC15, 0xB9DB, 0xBC16, 0xB9DC, 0xBC17, 0xB9DD, 0xBC18, 0xB9DE, 0xBC1B, 0xB9DF, 0xBC1C, 0xB9E0, 0xBC1D, 0xB9E1, 0xBC1E, 0xB9E2, 0xBC1F, 0xB9E3, 0xBC24, 0xB9E4, 0xBC25, 0xB9E5, 0xBC27, 0xB9E6, 0xBC29, 0xB9E7, 0xBC2D, 0xB9E8, 0xBC30, 0xB9E9, 0xBC31, 0xB9EA, 0xBC34, 0xB9EB, 0xBC38, 0xB9EC, 0xBC40, 0xB9ED, 0xBC41, 0xB9EE, 0xBC43, 0xB9EF, 0xBC44, 0xB9F0, 0xBC45, 0xB9F1, 0xBC49, 0xB9F2, 0xBC4C, 0xB9F3, 0xBC4D, 0xB9F4, 0xBC50, 0xB9F5, 0xBC5D, 0xB9F6, 0xBC84, 0xB9F7, 0xBC85, 0xB9F8, 0xBC88, 0xB9F9, 0xBC8B, 0xB9FA, 0xBC8C, 0xB9FB, 0xBC8E, 0xB9FC, 0xBC94, 0xB9FD, 0xBC95, 0xB9FE, 0xBC97, 0xBA41, 0xD28D, 0xBA42, 0xD28E, 0xBA43, 0xD28F, 0xBA44, 0xD292, 0xBA45, 0xD293, 0xBA46, 0xD294, 0xBA47, 0xD296, 0xBA48, 0xD297, 0xBA49, 0xD298, 0xBA4A, 0xD299, 0xBA4B, 0xD29A, 0xBA4C, 0xD29B, 0xBA4D, 0xD29D, 0xBA4E, 0xD29E, 0xBA4F, 0xD29F, 0xBA50, 0xD2A1, 0xBA51, 0xD2A2, 0xBA52, 0xD2A3, 0xBA53, 0xD2A5, 0xBA54, 0xD2A6, 0xBA55, 0xD2A7, 0xBA56, 0xD2A8, 0xBA57, 0xD2A9, 0xBA58, 0xD2AA, 0xBA59, 0xD2AB, 0xBA5A, 0xD2AD, 0xBA61, 0xD2AE, 0xBA62, 0xD2AF, 0xBA63, 0xD2B0, 0xBA64, 0xD2B2, 0xBA65, 0xD2B3, 0xBA66, 0xD2B4, 0xBA67, 0xD2B5, 0xBA68, 0xD2B6, 0xBA69, 0xD2B7, 0xBA6A, 0xD2BA, 0xBA6B, 0xD2BB, 0xBA6C, 0xD2BD, 0xBA6D, 0xD2BE, 0xBA6E, 0xD2C1, 0xBA6F, 0xD2C3, 0xBA70, 0xD2C4, 0xBA71, 0xD2C5, 0xBA72, 0xD2C6, 0xBA73, 0xD2C7, 0xBA74, 0xD2CA, 0xBA75, 0xD2CC, 0xBA76, 0xD2CD, 0xBA77, 0xD2CE, 0xBA78, 0xD2CF, 0xBA79, 0xD2D0, 0xBA7A, 0xD2D1, 0xBA81, 0xD2D2, 0xBA82, 0xD2D3, 0xBA83, 0xD2D5, 0xBA84, 0xD2D6, 0xBA85, 0xD2D7, 0xBA86, 0xD2D9, 0xBA87, 0xD2DA, 0xBA88, 0xD2DB, 0xBA89, 0xD2DD, 0xBA8A, 0xD2DE, 0xBA8B, 0xD2DF, 0xBA8C, 0xD2E0, 0xBA8D, 0xD2E1, 0xBA8E, 0xD2E2, 0xBA8F, 0xD2E3, 0xBA90, 0xD2E6, 0xBA91, 0xD2E7, 0xBA92, 0xD2E8, 0xBA93, 0xD2E9, 0xBA94, 0xD2EA, 0xBA95, 0xD2EB, 0xBA96, 0xD2EC, 0xBA97, 0xD2ED, 0xBA98, 0xD2EE, 0xBA99, 0xD2EF, 0xBA9A, 0xD2F2, 0xBA9B, 0xD2F3, 0xBA9C, 0xD2F5, 0xBA9D, 0xD2F6, 0xBA9E, 0xD2F7, 0xBA9F, 0xD2F9, 0xBAA0, 0xD2FA, 0xBAA1, 0xBC99, 0xBAA2, 0xBC9A, 0xBAA3, 0xBCA0, 0xBAA4, 0xBCA1, 0xBAA5, 0xBCA4, 0xBAA6, 0xBCA7, 0xBAA7, 0xBCA8, 0xBAA8, 0xBCB0, 0xBAA9, 0xBCB1, 0xBAAA, 0xBCB3, 0xBAAB, 0xBCB4, 0xBAAC, 0xBCB5, 0xBAAD, 0xBCBC, 0xBAAE, 0xBCBD, 0xBAAF, 0xBCC0, 0xBAB0, 0xBCC4, 0xBAB1, 0xBCCD, 0xBAB2, 0xBCCF, 0xBAB3, 0xBCD0, 0xBAB4, 0xBCD1, 0xBAB5, 0xBCD5, 0xBAB6, 0xBCD8, 0xBAB7, 0xBCDC, 0xBAB8, 0xBCF4, 0xBAB9, 0xBCF5, 0xBABA, 0xBCF6, 0xBABB, 0xBCF8, 0xBABC, 0xBCFC, 0xBABD, 0xBD04, 0xBABE, 0xBD05, 0xBABF, 0xBD07, 0xBAC0, 0xBD09, 0xBAC1, 0xBD10, 0xBAC2, 0xBD14, 0xBAC3, 0xBD24, 0xBAC4, 0xBD2C, 0xBAC5, 0xBD40, 0xBAC6, 0xBD48, 0xBAC7, 0xBD49, 0xBAC8, 0xBD4C, 0xBAC9, 0xBD50, 0xBACA, 0xBD58, 0xBACB, 0xBD59, 0xBACC, 0xBD64, 0xBACD, 0xBD68, 0xBACE, 0xBD80, 0xBACF, 0xBD81, 0xBAD0, 0xBD84, 0xBAD1, 0xBD87, 0xBAD2, 0xBD88, 0xBAD3, 0xBD89, 0xBAD4, 0xBD8A, 0xBAD5, 0xBD90, 0xBAD6, 0xBD91, 0xBAD7, 0xBD93, 0xBAD8, 0xBD95, 0xBAD9, 0xBD99, 0xBADA, 0xBD9A, 0xBADB, 0xBD9C, 0xBADC, 0xBDA4, 0xBADD, 0xBDB0, 0xBADE, 0xBDB8, 0xBADF, 0xBDD4, 0xBAE0, 0xBDD5, 0xBAE1, 0xBDD8, 0xBAE2, 0xBDDC, 0xBAE3, 0xBDE9, 0xBAE4, 0xBDF0, 0xBAE5, 0xBDF4, 0xBAE6, 0xBDF8, 0xBAE7, 0xBE00, 0xBAE8, 0xBE03, 0xBAE9, 0xBE05, 0xBAEA, 0xBE0C, 0xBAEB, 0xBE0D, 0xBAEC, 0xBE10, 0xBAED, 0xBE14, 0xBAEE, 0xBE1C, 0xBAEF, 0xBE1D, 0xBAF0, 0xBE1F, 0xBAF1, 0xBE44, 0xBAF2, 0xBE45, 0xBAF3, 0xBE48, 0xBAF4, 0xBE4C, 0xBAF5, 0xBE4E, 0xBAF6, 0xBE54, 0xBAF7, 0xBE55, 0xBAF8, 0xBE57, 0xBAF9, 0xBE59, 0xBAFA, 0xBE5A, 0xBAFB, 0xBE5B, 0xBAFC, 0xBE60, 0xBAFD, 0xBE61, 0xBAFE, 0xBE64, 0xBB41, 0xD2FB, 0xBB42, 0xD2FC, 0xBB43, 0xD2FD, 0xBB44, 0xD2FE, 0xBB45, 0xD2FF, 0xBB46, 0xD302, 0xBB47, 0xD304, 0xBB48, 0xD306, 0xBB49, 0xD307, 0xBB4A, 0xD308, 0xBB4B, 0xD309, 0xBB4C, 0xD30A, 0xBB4D, 0xD30B, 0xBB4E, 0xD30F, 0xBB4F, 0xD311, 0xBB50, 0xD312, 0xBB51, 0xD313, 0xBB52, 0xD315, 0xBB53, 0xD317, 0xBB54, 0xD318, 0xBB55, 0xD319, 0xBB56, 0xD31A, 0xBB57, 0xD31B, 0xBB58, 0xD31E, 0xBB59, 0xD322, 0xBB5A, 0xD323, 0xBB61, 0xD324, 0xBB62, 0xD326, 0xBB63, 0xD327, 0xBB64, 0xD32A, 0xBB65, 0xD32B, 0xBB66, 0xD32D, 0xBB67, 0xD32E, 0xBB68, 0xD32F, 0xBB69, 0xD331, 0xBB6A, 0xD332, 0xBB6B, 0xD333, 0xBB6C, 0xD334, 0xBB6D, 0xD335, 0xBB6E, 0xD336, 0xBB6F, 0xD337, 0xBB70, 0xD33A, 0xBB71, 0xD33E, 0xBB72, 0xD33F, 0xBB73, 0xD340, 0xBB74, 0xD341, 0xBB75, 0xD342, 0xBB76, 0xD343, 0xBB77, 0xD346, 0xBB78, 0xD347, 0xBB79, 0xD348, 0xBB7A, 0xD349, 0xBB81, 0xD34A, 0xBB82, 0xD34B, 0xBB83, 0xD34C, 0xBB84, 0xD34D, 0xBB85, 0xD34E, 0xBB86, 0xD34F, 0xBB87, 0xD350, 0xBB88, 0xD351, 0xBB89, 0xD352, 0xBB8A, 0xD353, 0xBB8B, 0xD354, 0xBB8C, 0xD355, 0xBB8D, 0xD356, 0xBB8E, 0xD357, 0xBB8F, 0xD358, 0xBB90, 0xD359, 0xBB91, 0xD35A, 0xBB92, 0xD35B, 0xBB93, 0xD35C, 0xBB94, 0xD35D, 0xBB95, 0xD35E, 0xBB96, 0xD35F, 0xBB97, 0xD360, 0xBB98, 0xD361, 0xBB99, 0xD362, 0xBB9A, 0xD363, 0xBB9B, 0xD364, 0xBB9C, 0xD365, 0xBB9D, 0xD366, 0xBB9E, 0xD367, 0xBB9F, 0xD368, 0xBBA0, 0xD369, 0xBBA1, 0xBE68, 0xBBA2, 0xBE6A, 0xBBA3, 0xBE70, 0xBBA4, 0xBE71, 0xBBA5, 0xBE73, 0xBBA6, 0xBE74, 0xBBA7, 0xBE75, 0xBBA8, 0xBE7B, 0xBBA9, 0xBE7C, 0xBBAA, 0xBE7D, 0xBBAB, 0xBE80, 0xBBAC, 0xBE84, 0xBBAD, 0xBE8C, 0xBBAE, 0xBE8D, 0xBBAF, 0xBE8F, 0xBBB0, 0xBE90, 0xBBB1, 0xBE91, 0xBBB2, 0xBE98, 0xBBB3, 0xBE99, 0xBBB4, 0xBEA8, 0xBBB5, 0xBED0, 0xBBB6, 0xBED1, 0xBBB7, 0xBED4, 0xBBB8, 0xBED7, 0xBBB9, 0xBED8, 0xBBBA, 0xBEE0, 0xBBBB, 0xBEE3, 0xBBBC, 0xBEE4, 0xBBBD, 0xBEE5, 0xBBBE, 0xBEEC, 0xBBBF, 0xBF01, 0xBBC0, 0xBF08, 0xBBC1, 0xBF09, 0xBBC2, 0xBF18, 0xBBC3, 0xBF19, 0xBBC4, 0xBF1B, 0xBBC5, 0xBF1C, 0xBBC6, 0xBF1D, 0xBBC7, 0xBF40, 0xBBC8, 0xBF41, 0xBBC9, 0xBF44, 0xBBCA, 0xBF48, 0xBBCB, 0xBF50, 0xBBCC, 0xBF51, 0xBBCD, 0xBF55, 0xBBCE, 0xBF94, 0xBBCF, 0xBFB0, 0xBBD0, 0xBFC5, 0xBBD1, 0xBFCC, 0xBBD2, 0xBFCD, 0xBBD3, 0xBFD0, 0xBBD4, 0xBFD4, 0xBBD5, 0xBFDC, 0xBBD6, 0xBFDF, 0xBBD7, 0xBFE1, 0xBBD8, 0xC03C, 0xBBD9, 0xC051, 0xBBDA, 0xC058, 0xBBDB, 0xC05C, 0xBBDC, 0xC060, 0xBBDD, 0xC068, 0xBBDE, 0xC069, 0xBBDF, 0xC090, 0xBBE0, 0xC091, 0xBBE1, 0xC094, 0xBBE2, 0xC098, 0xBBE3, 0xC0A0, 0xBBE4, 0xC0A1, 0xBBE5, 0xC0A3, 0xBBE6, 0xC0A5, 0xBBE7, 0xC0AC, 0xBBE8, 0xC0AD, 0xBBE9, 0xC0AF, 0xBBEA, 0xC0B0, 0xBBEB, 0xC0B3, 0xBBEC, 0xC0B4, 0xBBED, 0xC0B5, 0xBBEE, 0xC0B6, 0xBBEF, 0xC0BC, 0xBBF0, 0xC0BD, 0xBBF1, 0xC0BF, 0xBBF2, 0xC0C0, 0xBBF3, 0xC0C1, 0xBBF4, 0xC0C5, 0xBBF5, 0xC0C8, 0xBBF6, 0xC0C9, 0xBBF7, 0xC0CC, 0xBBF8, 0xC0D0, 0xBBF9, 0xC0D8, 0xBBFA, 0xC0D9, 0xBBFB, 0xC0DB, 0xBBFC, 0xC0DC, 0xBBFD, 0xC0DD, 0xBBFE, 0xC0E4, 0xBC41, 0xD36A, 0xBC42, 0xD36B, 0xBC43, 0xD36C, 0xBC44, 0xD36D, 0xBC45, 0xD36E, 0xBC46, 0xD36F, 0xBC47, 0xD370, 0xBC48, 0xD371, 0xBC49, 0xD372, 0xBC4A, 0xD373, 0xBC4B, 0xD374, 0xBC4C, 0xD375, 0xBC4D, 0xD376, 0xBC4E, 0xD377, 0xBC4F, 0xD378, 0xBC50, 0xD379, 0xBC51, 0xD37A, 0xBC52, 0xD37B, 0xBC53, 0xD37E, 0xBC54, 0xD37F, 0xBC55, 0xD381, 0xBC56, 0xD382, 0xBC57, 0xD383, 0xBC58, 0xD385, 0xBC59, 0xD386, 0xBC5A, 0xD387, 0xBC61, 0xD388, 0xBC62, 0xD389, 0xBC63, 0xD38A, 0xBC64, 0xD38B, 0xBC65, 0xD38E, 0xBC66, 0xD392, 0xBC67, 0xD393, 0xBC68, 0xD394, 0xBC69, 0xD395, 0xBC6A, 0xD396, 0xBC6B, 0xD397, 0xBC6C, 0xD39A, 0xBC6D, 0xD39B, 0xBC6E, 0xD39D, 0xBC6F, 0xD39E, 0xBC70, 0xD39F, 0xBC71, 0xD3A1, 0xBC72, 0xD3A2, 0xBC73, 0xD3A3, 0xBC74, 0xD3A4, 0xBC75, 0xD3A5, 0xBC76, 0xD3A6, 0xBC77, 0xD3A7, 0xBC78, 0xD3AA, 0xBC79, 0xD3AC, 0xBC7A, 0xD3AE, 0xBC81, 0xD3AF, 0xBC82, 0xD3B0, 0xBC83, 0xD3B1, 0xBC84, 0xD3B2, 0xBC85, 0xD3B3, 0xBC86, 0xD3B5, 0xBC87, 0xD3B6, 0xBC88, 0xD3B7, 0xBC89, 0xD3B9, 0xBC8A, 0xD3BA, 0xBC8B, 0xD3BB, 0xBC8C, 0xD3BD, 0xBC8D, 0xD3BE, 0xBC8E, 0xD3BF, 0xBC8F, 0xD3C0, 0xBC90, 0xD3C1, 0xBC91, 0xD3C2, 0xBC92, 0xD3C3, 0xBC93, 0xD3C6, 0xBC94, 0xD3C7, 0xBC95, 0xD3CA, 0xBC96, 0xD3CB, 0xBC97, 0xD3CC, 0xBC98, 0xD3CD, 0xBC99, 0xD3CE, 0xBC9A, 0xD3CF, 0xBC9B, 0xD3D1, 0xBC9C, 0xD3D2, 0xBC9D, 0xD3D3, 0xBC9E, 0xD3D4, 0xBC9F, 0xD3D5, 0xBCA0, 0xD3D6, 0xBCA1, 0xC0E5, 0xBCA2, 0xC0E8, 0xBCA3, 0xC0EC, 0xBCA4, 0xC0F4, 0xBCA5, 0xC0F5, 0xBCA6, 0xC0F7, 0xBCA7, 0xC0F9, 0xBCA8, 0xC100, 0xBCA9, 0xC104, 0xBCAA, 0xC108, 0xBCAB, 0xC110, 0xBCAC, 0xC115, 0xBCAD, 0xC11C, 0xBCAE, 0xC11D, 0xBCAF, 0xC11E, 0xBCB0, 0xC11F, 0xBCB1, 0xC120, 0xBCB2, 0xC123, 0xBCB3, 0xC124, 0xBCB4, 0xC126, 0xBCB5, 0xC127, 0xBCB6, 0xC12C, 0xBCB7, 0xC12D, 0xBCB8, 0xC12F, 0xBCB9, 0xC130, 0xBCBA, 0xC131, 0xBCBB, 0xC136, 0xBCBC, 0xC138, 0xBCBD, 0xC139, 0xBCBE, 0xC13C, 0xBCBF, 0xC140, 0xBCC0, 0xC148, 0xBCC1, 0xC149, 0xBCC2, 0xC14B, 0xBCC3, 0xC14C, 0xBCC4, 0xC14D, 0xBCC5, 0xC154, 0xBCC6, 0xC155, 0xBCC7, 0xC158, 0xBCC8, 0xC15C, 0xBCC9, 0xC164, 0xBCCA, 0xC165, 0xBCCB, 0xC167, 0xBCCC, 0xC168, 0xBCCD, 0xC169, 0xBCCE, 0xC170, 0xBCCF, 0xC174, 0xBCD0, 0xC178, 0xBCD1, 0xC185, 0xBCD2, 0xC18C, 0xBCD3, 0xC18D, 0xBCD4, 0xC18E, 0xBCD5, 0xC190, 0xBCD6, 0xC194, 0xBCD7, 0xC196, 0xBCD8, 0xC19C, 0xBCD9, 0xC19D, 0xBCDA, 0xC19F, 0xBCDB, 0xC1A1, 0xBCDC, 0xC1A5, 0xBCDD, 0xC1A8, 0xBCDE, 0xC1A9, 0xBCDF, 0xC1AC, 0xBCE0, 0xC1B0, 0xBCE1, 0xC1BD, 0xBCE2, 0xC1C4, 0xBCE3, 0xC1C8, 0xBCE4, 0xC1CC, 0xBCE5, 0xC1D4, 0xBCE6, 0xC1D7, 0xBCE7, 0xC1D8, 0xBCE8, 0xC1E0, 0xBCE9, 0xC1E4, 0xBCEA, 0xC1E8, 0xBCEB, 0xC1F0, 0xBCEC, 0xC1F1, 0xBCED, 0xC1F3, 0xBCEE, 0xC1FC, 0xBCEF, 0xC1FD, 0xBCF0, 0xC200, 0xBCF1, 0xC204, 0xBCF2, 0xC20C, 0xBCF3, 0xC20D, 0xBCF4, 0xC20F, 0xBCF5, 0xC211, 0xBCF6, 0xC218, 0xBCF7, 0xC219, 0xBCF8, 0xC21C, 0xBCF9, 0xC21F, 0xBCFA, 0xC220, 0xBCFB, 0xC228, 0xBCFC, 0xC229, 0xBCFD, 0xC22B, 0xBCFE, 0xC22D, 0xBD41, 0xD3D7, 0xBD42, 0xD3D9, 0xBD43, 0xD3DA, 0xBD44, 0xD3DB, 0xBD45, 0xD3DC, 0xBD46, 0xD3DD, 0xBD47, 0xD3DE, 0xBD48, 0xD3DF, 0xBD49, 0xD3E0, 0xBD4A, 0xD3E2, 0xBD4B, 0xD3E4, 0xBD4C, 0xD3E5, 0xBD4D, 0xD3E6, 0xBD4E, 0xD3E7, 0xBD4F, 0xD3E8, 0xBD50, 0xD3E9, 0xBD51, 0xD3EA, 0xBD52, 0xD3EB, 0xBD53, 0xD3EE, 0xBD54, 0xD3EF, 0xBD55, 0xD3F1, 0xBD56, 0xD3F2, 0xBD57, 0xD3F3, 0xBD58, 0xD3F5, 0xBD59, 0xD3F6, 0xBD5A, 0xD3F7, 0xBD61, 0xD3F8, 0xBD62, 0xD3F9, 0xBD63, 0xD3FA, 0xBD64, 0xD3FB, 0xBD65, 0xD3FE, 0xBD66, 0xD400, 0xBD67, 0xD402, 0xBD68, 0xD403, 0xBD69, 0xD404, 0xBD6A, 0xD405, 0xBD6B, 0xD406, 0xBD6C, 0xD407, 0xBD6D, 0xD409, 0xBD6E, 0xD40A, 0xBD6F, 0xD40B, 0xBD70, 0xD40C, 0xBD71, 0xD40D, 0xBD72, 0xD40E, 0xBD73, 0xD40F, 0xBD74, 0xD410, 0xBD75, 0xD411, 0xBD76, 0xD412, 0xBD77, 0xD413, 0xBD78, 0xD414, 0xBD79, 0xD415, 0xBD7A, 0xD416, 0xBD81, 0xD417, 0xBD82, 0xD418, 0xBD83, 0xD419, 0xBD84, 0xD41A, 0xBD85, 0xD41B, 0xBD86, 0xD41C, 0xBD87, 0xD41E, 0xBD88, 0xD41F, 0xBD89, 0xD420, 0xBD8A, 0xD421, 0xBD8B, 0xD422, 0xBD8C, 0xD423, 0xBD8D, 0xD424, 0xBD8E, 0xD425, 0xBD8F, 0xD426, 0xBD90, 0xD427, 0xBD91, 0xD428, 0xBD92, 0xD429, 0xBD93, 0xD42A, 0xBD94, 0xD42B, 0xBD95, 0xD42C, 0xBD96, 0xD42D, 0xBD97, 0xD42E, 0xBD98, 0xD42F, 0xBD99, 0xD430, 0xBD9A, 0xD431, 0xBD9B, 0xD432, 0xBD9C, 0xD433, 0xBD9D, 0xD434, 0xBD9E, 0xD435, 0xBD9F, 0xD436, 0xBDA0, 0xD437, 0xBDA1, 0xC22F, 0xBDA2, 0xC231, 0xBDA3, 0xC232, 0xBDA4, 0xC234, 0xBDA5, 0xC248, 0xBDA6, 0xC250, 0xBDA7, 0xC251, 0xBDA8, 0xC254, 0xBDA9, 0xC258, 0xBDAA, 0xC260, 0xBDAB, 0xC265, 0xBDAC, 0xC26C, 0xBDAD, 0xC26D, 0xBDAE, 0xC270, 0xBDAF, 0xC274, 0xBDB0, 0xC27C, 0xBDB1, 0xC27D, 0xBDB2, 0xC27F, 0xBDB3, 0xC281, 0xBDB4, 0xC288, 0xBDB5, 0xC289, 0xBDB6, 0xC290, 0xBDB7, 0xC298, 0xBDB8, 0xC29B, 0xBDB9, 0xC29D, 0xBDBA, 0xC2A4, 0xBDBB, 0xC2A5, 0xBDBC, 0xC2A8, 0xBDBD, 0xC2AC, 0xBDBE, 0xC2AD, 0xBDBF, 0xC2B4, 0xBDC0, 0xC2B5, 0xBDC1, 0xC2B7, 0xBDC2, 0xC2B9, 0xBDC3, 0xC2DC, 0xBDC4, 0xC2DD, 0xBDC5, 0xC2E0, 0xBDC6, 0xC2E3, 0xBDC7, 0xC2E4, 0xBDC8, 0xC2EB, 0xBDC9, 0xC2EC, 0xBDCA, 0xC2ED, 0xBDCB, 0xC2EF, 0xBDCC, 0xC2F1, 0xBDCD, 0xC2F6, 0xBDCE, 0xC2F8, 0xBDCF, 0xC2F9, 0xBDD0, 0xC2FB, 0xBDD1, 0xC2FC, 0xBDD2, 0xC300, 0xBDD3, 0xC308, 0xBDD4, 0xC309, 0xBDD5, 0xC30C, 0xBDD6, 0xC30D, 0xBDD7, 0xC313, 0xBDD8, 0xC314, 0xBDD9, 0xC315, 0xBDDA, 0xC318, 0xBDDB, 0xC31C, 0xBDDC, 0xC324, 0xBDDD, 0xC325, 0xBDDE, 0xC328, 0xBDDF, 0xC329, 0xBDE0, 0xC345, 0xBDE1, 0xC368, 0xBDE2, 0xC369, 0xBDE3, 0xC36C, 0xBDE4, 0xC370, 0xBDE5, 0xC372, 0xBDE6, 0xC378, 0xBDE7, 0xC379, 0xBDE8, 0xC37C, 0xBDE9, 0xC37D, 0xBDEA, 0xC384, 0xBDEB, 0xC388, 0xBDEC, 0xC38C, 0xBDED, 0xC3C0, 0xBDEE, 0xC3D8, 0xBDEF, 0xC3D9, 0xBDF0, 0xC3DC, 0xBDF1, 0xC3DF, 0xBDF2, 0xC3E0, 0xBDF3, 0xC3E2, 0xBDF4, 0xC3E8, 0xBDF5, 0xC3E9, 0xBDF6, 0xC3ED, 0xBDF7, 0xC3F4, 0xBDF8, 0xC3F5, 0xBDF9, 0xC3F8, 0xBDFA, 0xC408, 0xBDFB, 0xC410, 0xBDFC, 0xC424, 0xBDFD, 0xC42C, 0xBDFE, 0xC430, 0xBE41, 0xD438, 0xBE42, 0xD439, 0xBE43, 0xD43A, 0xBE44, 0xD43B, 0xBE45, 0xD43C, 0xBE46, 0xD43D, 0xBE47, 0xD43E, 0xBE48, 0xD43F, 0xBE49, 0xD441, 0xBE4A, 0xD442, 0xBE4B, 0xD443, 0xBE4C, 0xD445, 0xBE4D, 0xD446, 0xBE4E, 0xD447, 0xBE4F, 0xD448, 0xBE50, 0xD449, 0xBE51, 0xD44A, 0xBE52, 0xD44B, 0xBE53, 0xD44C, 0xBE54, 0xD44D, 0xBE55, 0xD44E, 0xBE56, 0xD44F, 0xBE57, 0xD450, 0xBE58, 0xD451, 0xBE59, 0xD452, 0xBE5A, 0xD453, 0xBE61, 0xD454, 0xBE62, 0xD455, 0xBE63, 0xD456, 0xBE64, 0xD457, 0xBE65, 0xD458, 0xBE66, 0xD459, 0xBE67, 0xD45A, 0xBE68, 0xD45B, 0xBE69, 0xD45D, 0xBE6A, 0xD45E, 0xBE6B, 0xD45F, 0xBE6C, 0xD461, 0xBE6D, 0xD462, 0xBE6E, 0xD463, 0xBE6F, 0xD465, 0xBE70, 0xD466, 0xBE71, 0xD467, 0xBE72, 0xD468, 0xBE73, 0xD469, 0xBE74, 0xD46A, 0xBE75, 0xD46B, 0xBE76, 0xD46C, 0xBE77, 0xD46E, 0xBE78, 0xD470, 0xBE79, 0xD471, 0xBE7A, 0xD472, 0xBE81, 0xD473, 0xBE82, 0xD474, 0xBE83, 0xD475, 0xBE84, 0xD476, 0xBE85, 0xD477, 0xBE86, 0xD47A, 0xBE87, 0xD47B, 0xBE88, 0xD47D, 0xBE89, 0xD47E, 0xBE8A, 0xD481, 0xBE8B, 0xD483, 0xBE8C, 0xD484, 0xBE8D, 0xD485, 0xBE8E, 0xD486, 0xBE8F, 0xD487, 0xBE90, 0xD48A, 0xBE91, 0xD48C, 0xBE92, 0xD48E, 0xBE93, 0xD48F, 0xBE94, 0xD490, 0xBE95, 0xD491, 0xBE96, 0xD492, 0xBE97, 0xD493, 0xBE98, 0xD495, 0xBE99, 0xD496, 0xBE9A, 0xD497, 0xBE9B, 0xD498, 0xBE9C, 0xD499, 0xBE9D, 0xD49A, 0xBE9E, 0xD49B, 0xBE9F, 0xD49C, 0xBEA0, 0xD49D, 0xBEA1, 0xC434, 0xBEA2, 0xC43C, 0xBEA3, 0xC43D, 0xBEA4, 0xC448, 0xBEA5, 0xC464, 0xBEA6, 0xC465, 0xBEA7, 0xC468, 0xBEA8, 0xC46C, 0xBEA9, 0xC474, 0xBEAA, 0xC475, 0xBEAB, 0xC479, 0xBEAC, 0xC480, 0xBEAD, 0xC494, 0xBEAE, 0xC49C, 0xBEAF, 0xC4B8, 0xBEB0, 0xC4BC, 0xBEB1, 0xC4E9, 0xBEB2, 0xC4F0, 0xBEB3, 0xC4F1, 0xBEB4, 0xC4F4, 0xBEB5, 0xC4F8, 0xBEB6, 0xC4FA, 0xBEB7, 0xC4FF, 0xBEB8, 0xC500, 0xBEB9, 0xC501, 0xBEBA, 0xC50C, 0xBEBB, 0xC510, 0xBEBC, 0xC514, 0xBEBD, 0xC51C, 0xBEBE, 0xC528, 0xBEBF, 0xC529, 0xBEC0, 0xC52C, 0xBEC1, 0xC530, 0xBEC2, 0xC538, 0xBEC3, 0xC539, 0xBEC4, 0xC53B, 0xBEC5, 0xC53D, 0xBEC6, 0xC544, 0xBEC7, 0xC545, 0xBEC8, 0xC548, 0xBEC9, 0xC549, 0xBECA, 0xC54A, 0xBECB, 0xC54C, 0xBECC, 0xC54D, 0xBECD, 0xC54E, 0xBECE, 0xC553, 0xBECF, 0xC554, 0xBED0, 0xC555, 0xBED1, 0xC557, 0xBED2, 0xC558, 0xBED3, 0xC559, 0xBED4, 0xC55D, 0xBED5, 0xC55E, 0xBED6, 0xC560, 0xBED7, 0xC561, 0xBED8, 0xC564, 0xBED9, 0xC568, 0xBEDA, 0xC570, 0xBEDB, 0xC571, 0xBEDC, 0xC573, 0xBEDD, 0xC574, 0xBEDE, 0xC575, 0xBEDF, 0xC57C, 0xBEE0, 0xC57D, 0xBEE1, 0xC580, 0xBEE2, 0xC584, 0xBEE3, 0xC587, 0xBEE4, 0xC58C, 0xBEE5, 0xC58D, 0xBEE6, 0xC58F, 0xBEE7, 0xC591, 0xBEE8, 0xC595, 0xBEE9, 0xC597, 0xBEEA, 0xC598, 0xBEEB, 0xC59C, 0xBEEC, 0xC5A0, 0xBEED, 0xC5A9, 0xBEEE, 0xC5B4, 0xBEEF, 0xC5B5, 0xBEF0, 0xC5B8, 0xBEF1, 0xC5B9, 0xBEF2, 0xC5BB, 0xBEF3, 0xC5BC, 0xBEF4, 0xC5BD, 0xBEF5, 0xC5BE, 0xBEF6, 0xC5C4, 0xBEF7, 0xC5C5, 0xBEF8, 0xC5C6, 0xBEF9, 0xC5C7, 0xBEFA, 0xC5C8, 0xBEFB, 0xC5C9, 0xBEFC, 0xC5CA, 0xBEFD, 0xC5CC, 0xBEFE, 0xC5CE, 0xBF41, 0xD49E, 0xBF42, 0xD49F, 0xBF43, 0xD4A0, 0xBF44, 0xD4A1, 0xBF45, 0xD4A2, 0xBF46, 0xD4A3, 0xBF47, 0xD4A4, 0xBF48, 0xD4A5, 0xBF49, 0xD4A6, 0xBF4A, 0xD4A7, 0xBF4B, 0xD4A8, 0xBF4C, 0xD4AA, 0xBF4D, 0xD4AB, 0xBF4E, 0xD4AC, 0xBF4F, 0xD4AD, 0xBF50, 0xD4AE, 0xBF51, 0xD4AF, 0xBF52, 0xD4B0, 0xBF53, 0xD4B1, 0xBF54, 0xD4B2, 0xBF55, 0xD4B3, 0xBF56, 0xD4B4, 0xBF57, 0xD4B5, 0xBF58, 0xD4B6, 0xBF59, 0xD4B7, 0xBF5A, 0xD4B8, 0xBF61, 0xD4B9, 0xBF62, 0xD4BA, 0xBF63, 0xD4BB, 0xBF64, 0xD4BC, 0xBF65, 0xD4BD, 0xBF66, 0xD4BE, 0xBF67, 0xD4BF, 0xBF68, 0xD4C0, 0xBF69, 0xD4C1, 0xBF6A, 0xD4C2, 0xBF6B, 0xD4C3, 0xBF6C, 0xD4C4, 0xBF6D, 0xD4C5, 0xBF6E, 0xD4C6, 0xBF6F, 0xD4C7, 0xBF70, 0xD4C8, 0xBF71, 0xD4C9, 0xBF72, 0xD4CA, 0xBF73, 0xD4CB, 0xBF74, 0xD4CD, 0xBF75, 0xD4CE, 0xBF76, 0xD4CF, 0xBF77, 0xD4D1, 0xBF78, 0xD4D2, 0xBF79, 0xD4D3, 0xBF7A, 0xD4D5, 0xBF81, 0xD4D6, 0xBF82, 0xD4D7, 0xBF83, 0xD4D8, 0xBF84, 0xD4D9, 0xBF85, 0xD4DA, 0xBF86, 0xD4DB, 0xBF87, 0xD4DD, 0xBF88, 0xD4DE, 0xBF89, 0xD4E0, 0xBF8A, 0xD4E1, 0xBF8B, 0xD4E2, 0xBF8C, 0xD4E3, 0xBF8D, 0xD4E4, 0xBF8E, 0xD4E5, 0xBF8F, 0xD4E6, 0xBF90, 0xD4E7, 0xBF91, 0xD4E9, 0xBF92, 0xD4EA, 0xBF93, 0xD4EB, 0xBF94, 0xD4ED, 0xBF95, 0xD4EE, 0xBF96, 0xD4EF, 0xBF97, 0xD4F1, 0xBF98, 0xD4F2, 0xBF99, 0xD4F3, 0xBF9A, 0xD4F4, 0xBF9B, 0xD4F5, 0xBF9C, 0xD4F6, 0xBF9D, 0xD4F7, 0xBF9E, 0xD4F9, 0xBF9F, 0xD4FA, 0xBFA0, 0xD4FC, 0xBFA1, 0xC5D0, 0xBFA2, 0xC5D1, 0xBFA3, 0xC5D4, 0xBFA4, 0xC5D8, 0xBFA5, 0xC5E0, 0xBFA6, 0xC5E1, 0xBFA7, 0xC5E3, 0xBFA8, 0xC5E5, 0xBFA9, 0xC5EC, 0xBFAA, 0xC5ED, 0xBFAB, 0xC5EE, 0xBFAC, 0xC5F0, 0xBFAD, 0xC5F4, 0xBFAE, 0xC5F6, 0xBFAF, 0xC5F7, 0xBFB0, 0xC5FC, 0xBFB1, 0xC5FD, 0xBFB2, 0xC5FE, 0xBFB3, 0xC5FF, 0xBFB4, 0xC600, 0xBFB5, 0xC601, 0xBFB6, 0xC605, 0xBFB7, 0xC606, 0xBFB8, 0xC607, 0xBFB9, 0xC608, 0xBFBA, 0xC60C, 0xBFBB, 0xC610, 0xBFBC, 0xC618, 0xBFBD, 0xC619, 0xBFBE, 0xC61B, 0xBFBF, 0xC61C, 0xBFC0, 0xC624, 0xBFC1, 0xC625, 0xBFC2, 0xC628, 0xBFC3, 0xC62C, 0xBFC4, 0xC62D, 0xBFC5, 0xC62E, 0xBFC6, 0xC630, 0xBFC7, 0xC633, 0xBFC8, 0xC634, 0xBFC9, 0xC635, 0xBFCA, 0xC637, 0xBFCB, 0xC639, 0xBFCC, 0xC63B, 0xBFCD, 0xC640, 0xBFCE, 0xC641, 0xBFCF, 0xC644, 0xBFD0, 0xC648, 0xBFD1, 0xC650, 0xBFD2, 0xC651, 0xBFD3, 0xC653, 0xBFD4, 0xC654, 0xBFD5, 0xC655, 0xBFD6, 0xC65C, 0xBFD7, 0xC65D, 0xBFD8, 0xC660, 0xBFD9, 0xC66C, 0xBFDA, 0xC66F, 0xBFDB, 0xC671, 0xBFDC, 0xC678, 0xBFDD, 0xC679, 0xBFDE, 0xC67C, 0xBFDF, 0xC680, 0xBFE0, 0xC688, 0xBFE1, 0xC689, 0xBFE2, 0xC68B, 0xBFE3, 0xC68D, 0xBFE4, 0xC694, 0xBFE5, 0xC695, 0xBFE6, 0xC698, 0xBFE7, 0xC69C, 0xBFE8, 0xC6A4, 0xBFE9, 0xC6A5, 0xBFEA, 0xC6A7, 0xBFEB, 0xC6A9, 0xBFEC, 0xC6B0, 0xBFED, 0xC6B1, 0xBFEE, 0xC6B4, 0xBFEF, 0xC6B8, 0xBFF0, 0xC6B9, 0xBFF1, 0xC6BA, 0xBFF2, 0xC6C0, 0xBFF3, 0xC6C1, 0xBFF4, 0xC6C3, 0xBFF5, 0xC6C5, 0xBFF6, 0xC6CC, 0xBFF7, 0xC6CD, 0xBFF8, 0xC6D0, 0xBFF9, 0xC6D4, 0xBFFA, 0xC6DC, 0xBFFB, 0xC6DD, 0xBFFC, 0xC6E0, 0xBFFD, 0xC6E1, 0xBFFE, 0xC6E8, 0xC041, 0xD4FE, 0xC042, 0xD4FF, 0xC043, 0xD500, 0xC044, 0xD501, 0xC045, 0xD502, 0xC046, 0xD503, 0xC047, 0xD505, 0xC048, 0xD506, 0xC049, 0xD507, 0xC04A, 0xD509, 0xC04B, 0xD50A, 0xC04C, 0xD50B, 0xC04D, 0xD50D, 0xC04E, 0xD50E, 0xC04F, 0xD50F, 0xC050, 0xD510, 0xC051, 0xD511, 0xC052, 0xD512, 0xC053, 0xD513, 0xC054, 0xD516, 0xC055, 0xD518, 0xC056, 0xD519, 0xC057, 0xD51A, 0xC058, 0xD51B, 0xC059, 0xD51C, 0xC05A, 0xD51D, 0xC061, 0xD51E, 0xC062, 0xD51F, 0xC063, 0xD520, 0xC064, 0xD521, 0xC065, 0xD522, 0xC066, 0xD523, 0xC067, 0xD524, 0xC068, 0xD525, 0xC069, 0xD526, 0xC06A, 0xD527, 0xC06B, 0xD528, 0xC06C, 0xD529, 0xC06D, 0xD52A, 0xC06E, 0xD52B, 0xC06F, 0xD52C, 0xC070, 0xD52D, 0xC071, 0xD52E, 0xC072, 0xD52F, 0xC073, 0xD530, 0xC074, 0xD531, 0xC075, 0xD532, 0xC076, 0xD533, 0xC077, 0xD534, 0xC078, 0xD535, 0xC079, 0xD536, 0xC07A, 0xD537, 0xC081, 0xD538, 0xC082, 0xD539, 0xC083, 0xD53A, 0xC084, 0xD53B, 0xC085, 0xD53E, 0xC086, 0xD53F, 0xC087, 0xD541, 0xC088, 0xD542, 0xC089, 0xD543, 0xC08A, 0xD545, 0xC08B, 0xD546, 0xC08C, 0xD547, 0xC08D, 0xD548, 0xC08E, 0xD549, 0xC08F, 0xD54A, 0xC090, 0xD54B, 0xC091, 0xD54E, 0xC092, 0xD550, 0xC093, 0xD552, 0xC094, 0xD553, 0xC095, 0xD554, 0xC096, 0xD555, 0xC097, 0xD556, 0xC098, 0xD557, 0xC099, 0xD55A, 0xC09A, 0xD55B, 0xC09B, 0xD55D, 0xC09C, 0xD55E, 0xC09D, 0xD55F, 0xC09E, 0xD561, 0xC09F, 0xD562, 0xC0A0, 0xD563, 0xC0A1, 0xC6E9, 0xC0A2, 0xC6EC, 0xC0A3, 0xC6F0, 0xC0A4, 0xC6F8, 0xC0A5, 0xC6F9, 0xC0A6, 0xC6FD, 0xC0A7, 0xC704, 0xC0A8, 0xC705, 0xC0A9, 0xC708, 0xC0AA, 0xC70C, 0xC0AB, 0xC714, 0xC0AC, 0xC715, 0xC0AD, 0xC717, 0xC0AE, 0xC719, 0xC0AF, 0xC720, 0xC0B0, 0xC721, 0xC0B1, 0xC724, 0xC0B2, 0xC728, 0xC0B3, 0xC730, 0xC0B4, 0xC731, 0xC0B5, 0xC733, 0xC0B6, 0xC735, 0xC0B7, 0xC737, 0xC0B8, 0xC73C, 0xC0B9, 0xC73D, 0xC0BA, 0xC740, 0xC0BB, 0xC744, 0xC0BC, 0xC74A, 0xC0BD, 0xC74C, 0xC0BE, 0xC74D, 0xC0BF, 0xC74F, 0xC0C0, 0xC751, 0xC0C1, 0xC752, 0xC0C2, 0xC753, 0xC0C3, 0xC754, 0xC0C4, 0xC755, 0xC0C5, 0xC756, 0xC0C6, 0xC757, 0xC0C7, 0xC758, 0xC0C8, 0xC75C, 0xC0C9, 0xC760, 0xC0CA, 0xC768, 0xC0CB, 0xC76B, 0xC0CC, 0xC774, 0xC0CD, 0xC775, 0xC0CE, 0xC778, 0xC0CF, 0xC77C, 0xC0D0, 0xC77D, 0xC0D1, 0xC77E, 0xC0D2, 0xC783, 0xC0D3, 0xC784, 0xC0D4, 0xC785, 0xC0D5, 0xC787, 0xC0D6, 0xC788, 0xC0D7, 0xC789, 0xC0D8, 0xC78A, 0xC0D9, 0xC78E, 0xC0DA, 0xC790, 0xC0DB, 0xC791, 0xC0DC, 0xC794, 0xC0DD, 0xC796, 0xC0DE, 0xC797, 0xC0DF, 0xC798, 0xC0E0, 0xC79A, 0xC0E1, 0xC7A0, 0xC0E2, 0xC7A1, 0xC0E3, 0xC7A3, 0xC0E4, 0xC7A4, 0xC0E5, 0xC7A5, 0xC0E6, 0xC7A6, 0xC0E7, 0xC7AC, 0xC0E8, 0xC7AD, 0xC0E9, 0xC7B0, 0xC0EA, 0xC7B4, 0xC0EB, 0xC7BC, 0xC0EC, 0xC7BD, 0xC0ED, 0xC7BF, 0xC0EE, 0xC7C0, 0xC0EF, 0xC7C1, 0xC0F0, 0xC7C8, 0xC0F1, 0xC7C9, 0xC0F2, 0xC7CC, 0xC0F3, 0xC7CE, 0xC0F4, 0xC7D0, 0xC0F5, 0xC7D8, 0xC0F6, 0xC7DD, 0xC0F7, 0xC7E4, 0xC0F8, 0xC7E8, 0xC0F9, 0xC7EC, 0xC0FA, 0xC800, 0xC0FB, 0xC801, 0xC0FC, 0xC804, 0xC0FD, 0xC808, 0xC0FE, 0xC80A, 0xC141, 0xD564, 0xC142, 0xD566, 0xC143, 0xD567, 0xC144, 0xD56A, 0xC145, 0xD56C, 0xC146, 0xD56E, 0xC147, 0xD56F, 0xC148, 0xD570, 0xC149, 0xD571, 0xC14A, 0xD572, 0xC14B, 0xD573, 0xC14C, 0xD576, 0xC14D, 0xD577, 0xC14E, 0xD579, 0xC14F, 0xD57A, 0xC150, 0xD57B, 0xC151, 0xD57D, 0xC152, 0xD57E, 0xC153, 0xD57F, 0xC154, 0xD580, 0xC155, 0xD581, 0xC156, 0xD582, 0xC157, 0xD583, 0xC158, 0xD586, 0xC159, 0xD58A, 0xC15A, 0xD58B, 0xC161, 0xD58C, 0xC162, 0xD58D, 0xC163, 0xD58E, 0xC164, 0xD58F, 0xC165, 0xD591, 0xC166, 0xD592, 0xC167, 0xD593, 0xC168, 0xD594, 0xC169, 0xD595, 0xC16A, 0xD596, 0xC16B, 0xD597, 0xC16C, 0xD598, 0xC16D, 0xD599, 0xC16E, 0xD59A, 0xC16F, 0xD59B, 0xC170, 0xD59C, 0xC171, 0xD59D, 0xC172, 0xD59E, 0xC173, 0xD59F, 0xC174, 0xD5A0, 0xC175, 0xD5A1, 0xC176, 0xD5A2, 0xC177, 0xD5A3, 0xC178, 0xD5A4, 0xC179, 0xD5A6, 0xC17A, 0xD5A7, 0xC181, 0xD5A8, 0xC182, 0xD5A9, 0xC183, 0xD5AA, 0xC184, 0xD5AB, 0xC185, 0xD5AC, 0xC186, 0xD5AD, 0xC187, 0xD5AE, 0xC188, 0xD5AF, 0xC189, 0xD5B0, 0xC18A, 0xD5B1, 0xC18B, 0xD5B2, 0xC18C, 0xD5B3, 0xC18D, 0xD5B4, 0xC18E, 0xD5B5, 0xC18F, 0xD5B6, 0xC190, 0xD5B7, 0xC191, 0xD5B8, 0xC192, 0xD5B9, 0xC193, 0xD5BA, 0xC194, 0xD5BB, 0xC195, 0xD5BC, 0xC196, 0xD5BD, 0xC197, 0xD5BE, 0xC198, 0xD5BF, 0xC199, 0xD5C0, 0xC19A, 0xD5C1, 0xC19B, 0xD5C2, 0xC19C, 0xD5C3, 0xC19D, 0xD5C4, 0xC19E, 0xD5C5, 0xC19F, 0xD5C6, 0xC1A0, 0xD5C7, 0xC1A1, 0xC810, 0xC1A2, 0xC811, 0xC1A3, 0xC813, 0xC1A4, 0xC815, 0xC1A5, 0xC816, 0xC1A6, 0xC81C, 0xC1A7, 0xC81D, 0xC1A8, 0xC820, 0xC1A9, 0xC824, 0xC1AA, 0xC82C, 0xC1AB, 0xC82D, 0xC1AC, 0xC82F, 0xC1AD, 0xC831, 0xC1AE, 0xC838, 0xC1AF, 0xC83C, 0xC1B0, 0xC840, 0xC1B1, 0xC848, 0xC1B2, 0xC849, 0xC1B3, 0xC84C, 0xC1B4, 0xC84D, 0xC1B5, 0xC854, 0xC1B6, 0xC870, 0xC1B7, 0xC871, 0xC1B8, 0xC874, 0xC1B9, 0xC878, 0xC1BA, 0xC87A, 0xC1BB, 0xC880, 0xC1BC, 0xC881, 0xC1BD, 0xC883, 0xC1BE, 0xC885, 0xC1BF, 0xC886, 0xC1C0, 0xC887, 0xC1C1, 0xC88B, 0xC1C2, 0xC88C, 0xC1C3, 0xC88D, 0xC1C4, 0xC894, 0xC1C5, 0xC89D, 0xC1C6, 0xC89F, 0xC1C7, 0xC8A1, 0xC1C8, 0xC8A8, 0xC1C9, 0xC8BC, 0xC1CA, 0xC8BD, 0xC1CB, 0xC8C4, 0xC1CC, 0xC8C8, 0xC1CD, 0xC8CC, 0xC1CE, 0xC8D4, 0xC1CF, 0xC8D5, 0xC1D0, 0xC8D7, 0xC1D1, 0xC8D9, 0xC1D2, 0xC8E0, 0xC1D3, 0xC8E1, 0xC1D4, 0xC8E4, 0xC1D5, 0xC8F5, 0xC1D6, 0xC8FC, 0xC1D7, 0xC8FD, 0xC1D8, 0xC900, 0xC1D9, 0xC904, 0xC1DA, 0xC905, 0xC1DB, 0xC906, 0xC1DC, 0xC90C, 0xC1DD, 0xC90D, 0xC1DE, 0xC90F, 0xC1DF, 0xC911, 0xC1E0, 0xC918, 0xC1E1, 0xC92C, 0xC1E2, 0xC934, 0xC1E3, 0xC950, 0xC1E4, 0xC951, 0xC1E5, 0xC954, 0xC1E6, 0xC958, 0xC1E7, 0xC960, 0xC1E8, 0xC961, 0xC1E9, 0xC963, 0xC1EA, 0xC96C, 0xC1EB, 0xC970, 0xC1EC, 0xC974, 0xC1ED, 0xC97C, 0xC1EE, 0xC988, 0xC1EF, 0xC989, 0xC1F0, 0xC98C, 0xC1F1, 0xC990, 0xC1F2, 0xC998, 0xC1F3, 0xC999, 0xC1F4, 0xC99B, 0xC1F5, 0xC99D, 0xC1F6, 0xC9C0, 0xC1F7, 0xC9C1, 0xC1F8, 0xC9C4, 0xC1F9, 0xC9C7, 0xC1FA, 0xC9C8, 0xC1FB, 0xC9CA, 0xC1FC, 0xC9D0, 0xC1FD, 0xC9D1, 0xC1FE, 0xC9D3, 0xC241, 0xD5CA, 0xC242, 0xD5CB, 0xC243, 0xD5CD, 0xC244, 0xD5CE, 0xC245, 0xD5CF, 0xC246, 0xD5D1, 0xC247, 0xD5D3, 0xC248, 0xD5D4, 0xC249, 0xD5D5, 0xC24A, 0xD5D6, 0xC24B, 0xD5D7, 0xC24C, 0xD5DA, 0xC24D, 0xD5DC, 0xC24E, 0xD5DE, 0xC24F, 0xD5DF, 0xC250, 0xD5E0, 0xC251, 0xD5E1, 0xC252, 0xD5E2, 0xC253, 0xD5E3, 0xC254, 0xD5E6, 0xC255, 0xD5E7, 0xC256, 0xD5E9, 0xC257, 0xD5EA, 0xC258, 0xD5EB, 0xC259, 0xD5ED, 0xC25A, 0xD5EE, 0xC261, 0xD5EF, 0xC262, 0xD5F0, 0xC263, 0xD5F1, 0xC264, 0xD5F2, 0xC265, 0xD5F3, 0xC266, 0xD5F6, 0xC267, 0xD5F8, 0xC268, 0xD5FA, 0xC269, 0xD5FB, 0xC26A, 0xD5FC, 0xC26B, 0xD5FD, 0xC26C, 0xD5FE, 0xC26D, 0xD5FF, 0xC26E, 0xD602, 0xC26F, 0xD603, 0xC270, 0xD605, 0xC271, 0xD606, 0xC272, 0xD607, 0xC273, 0xD609, 0xC274, 0xD60A, 0xC275, 0xD60B, 0xC276, 0xD60C, 0xC277, 0xD60D, 0xC278, 0xD60E, 0xC279, 0xD60F, 0xC27A, 0xD612, 0xC281, 0xD616, 0xC282, 0xD617, 0xC283, 0xD618, 0xC284, 0xD619, 0xC285, 0xD61A, 0xC286, 0xD61B, 0xC287, 0xD61D, 0xC288, 0xD61E, 0xC289, 0xD61F, 0xC28A, 0xD621, 0xC28B, 0xD622, 0xC28C, 0xD623, 0xC28D, 0xD625, 0xC28E, 0xD626, 0xC28F, 0xD627, 0xC290, 0xD628, 0xC291, 0xD629, 0xC292, 0xD62A, 0xC293, 0xD62B, 0xC294, 0xD62C, 0xC295, 0xD62E, 0xC296, 0xD62F, 0xC297, 0xD630, 0xC298, 0xD631, 0xC299, 0xD632, 0xC29A, 0xD633, 0xC29B, 0xD634, 0xC29C, 0xD635, 0xC29D, 0xD636, 0xC29E, 0xD637, 0xC29F, 0xD63A, 0xC2A0, 0xD63B, 0xC2A1, 0xC9D5, 0xC2A2, 0xC9D6, 0xC2A3, 0xC9D9, 0xC2A4, 0xC9DA, 0xC2A5, 0xC9DC, 0xC2A6, 0xC9DD, 0xC2A7, 0xC9E0, 0xC2A8, 0xC9E2, 0xC2A9, 0xC9E4, 0xC2AA, 0xC9E7, 0xC2AB, 0xC9EC, 0xC2AC, 0xC9ED, 0xC2AD, 0xC9EF, 0xC2AE, 0xC9F0, 0xC2AF, 0xC9F1, 0xC2B0, 0xC9F8, 0xC2B1, 0xC9F9, 0xC2B2, 0xC9FC, 0xC2B3, 0xCA00, 0xC2B4, 0xCA08, 0xC2B5, 0xCA09, 0xC2B6, 0xCA0B, 0xC2B7, 0xCA0C, 0xC2B8, 0xCA0D, 0xC2B9, 0xCA14, 0xC2BA, 0xCA18, 0xC2BB, 0xCA29, 0xC2BC, 0xCA4C, 0xC2BD, 0xCA4D, 0xC2BE, 0xCA50, 0xC2BF, 0xCA54, 0xC2C0, 0xCA5C, 0xC2C1, 0xCA5D, 0xC2C2, 0xCA5F, 0xC2C3, 0xCA60, 0xC2C4, 0xCA61, 0xC2C5, 0xCA68, 0xC2C6, 0xCA7D, 0xC2C7, 0xCA84, 0xC2C8, 0xCA98, 0xC2C9, 0xCABC, 0xC2CA, 0xCABD, 0xC2CB, 0xCAC0, 0xC2CC, 0xCAC4, 0xC2CD, 0xCACC, 0xC2CE, 0xCACD, 0xC2CF, 0xCACF, 0xC2D0, 0xCAD1, 0xC2D1, 0xCAD3, 0xC2D2, 0xCAD8, 0xC2D3, 0xCAD9, 0xC2D4, 0xCAE0, 0xC2D5, 0xCAEC, 0xC2D6, 0xCAF4, 0xC2D7, 0xCB08, 0xC2D8, 0xCB10, 0xC2D9, 0xCB14, 0xC2DA, 0xCB18, 0xC2DB, 0xCB20, 0xC2DC, 0xCB21, 0xC2DD, 0xCB41, 0xC2DE, 0xCB48, 0xC2DF, 0xCB49, 0xC2E0, 0xCB4C, 0xC2E1, 0xCB50, 0xC2E2, 0xCB58, 0xC2E3, 0xCB59, 0xC2E4, 0xCB5D, 0xC2E5, 0xCB64, 0xC2E6, 0xCB78, 0xC2E7, 0xCB79, 0xC2E8, 0xCB9C, 0xC2E9, 0xCBB8, 0xC2EA, 0xCBD4, 0xC2EB, 0xCBE4, 0xC2EC, 0xCBE7, 0xC2ED, 0xCBE9, 0xC2EE, 0xCC0C, 0xC2EF, 0xCC0D, 0xC2F0, 0xCC10, 0xC2F1, 0xCC14, 0xC2F2, 0xCC1C, 0xC2F3, 0xCC1D, 0xC2F4, 0xCC21, 0xC2F5, 0xCC22, 0xC2F6, 0xCC27, 0xC2F7, 0xCC28, 0xC2F8, 0xCC29, 0xC2F9, 0xCC2C, 0xC2FA, 0xCC2E, 0xC2FB, 0xCC30, 0xC2FC, 0xCC38, 0xC2FD, 0xCC39, 0xC2FE, 0xCC3B, 0xC341, 0xD63D, 0xC342, 0xD63E, 0xC343, 0xD63F, 0xC344, 0xD641, 0xC345, 0xD642, 0xC346, 0xD643, 0xC347, 0xD644, 0xC348, 0xD646, 0xC349, 0xD647, 0xC34A, 0xD64A, 0xC34B, 0xD64C, 0xC34C, 0xD64E, 0xC34D, 0xD64F, 0xC34E, 0xD650, 0xC34F, 0xD652, 0xC350, 0xD653, 0xC351, 0xD656, 0xC352, 0xD657, 0xC353, 0xD659, 0xC354, 0xD65A, 0xC355, 0xD65B, 0xC356, 0xD65D, 0xC357, 0xD65E, 0xC358, 0xD65F, 0xC359, 0xD660, 0xC35A, 0xD661, 0xC361, 0xD662, 0xC362, 0xD663, 0xC363, 0xD664, 0xC364, 0xD665, 0xC365, 0xD666, 0xC366, 0xD668, 0xC367, 0xD66A, 0xC368, 0xD66B, 0xC369, 0xD66C, 0xC36A, 0xD66D, 0xC36B, 0xD66E, 0xC36C, 0xD66F, 0xC36D, 0xD672, 0xC36E, 0xD673, 0xC36F, 0xD675, 0xC370, 0xD676, 0xC371, 0xD677, 0xC372, 0xD678, 0xC373, 0xD679, 0xC374, 0xD67A, 0xC375, 0xD67B, 0xC376, 0xD67C, 0xC377, 0xD67D, 0xC378, 0xD67E, 0xC379, 0xD67F, 0xC37A, 0xD680, 0xC381, 0xD681, 0xC382, 0xD682, 0xC383, 0xD684, 0xC384, 0xD686, 0xC385, 0xD687, 0xC386, 0xD688, 0xC387, 0xD689, 0xC388, 0xD68A, 0xC389, 0xD68B, 0xC38A, 0xD68E, 0xC38B, 0xD68F, 0xC38C, 0xD691, 0xC38D, 0xD692, 0xC38E, 0xD693, 0xC38F, 0xD695, 0xC390, 0xD696, 0xC391, 0xD697, 0xC392, 0xD698, 0xC393, 0xD699, 0xC394, 0xD69A, 0xC395, 0xD69B, 0xC396, 0xD69C, 0xC397, 0xD69E, 0xC398, 0xD6A0, 0xC399, 0xD6A2, 0xC39A, 0xD6A3, 0xC39B, 0xD6A4, 0xC39C, 0xD6A5, 0xC39D, 0xD6A6, 0xC39E, 0xD6A7, 0xC39F, 0xD6A9, 0xC3A0, 0xD6AA, 0xC3A1, 0xCC3C, 0xC3A2, 0xCC3D, 0xC3A3, 0xCC3E, 0xC3A4, 0xCC44, 0xC3A5, 0xCC45, 0xC3A6, 0xCC48, 0xC3A7, 0xCC4C, 0xC3A8, 0xCC54, 0xC3A9, 0xCC55, 0xC3AA, 0xCC57, 0xC3AB, 0xCC58, 0xC3AC, 0xCC59, 0xC3AD, 0xCC60, 0xC3AE, 0xCC64, 0xC3AF, 0xCC66, 0xC3B0, 0xCC68, 0xC3B1, 0xCC70, 0xC3B2, 0xCC75, 0xC3B3, 0xCC98, 0xC3B4, 0xCC99, 0xC3B5, 0xCC9C, 0xC3B6, 0xCCA0, 0xC3B7, 0xCCA8, 0xC3B8, 0xCCA9, 0xC3B9, 0xCCAB, 0xC3BA, 0xCCAC, 0xC3BB, 0xCCAD, 0xC3BC, 0xCCB4, 0xC3BD, 0xCCB5, 0xC3BE, 0xCCB8, 0xC3BF, 0xCCBC, 0xC3C0, 0xCCC4, 0xC3C1, 0xCCC5, 0xC3C2, 0xCCC7, 0xC3C3, 0xCCC9, 0xC3C4, 0xCCD0, 0xC3C5, 0xCCD4, 0xC3C6, 0xCCE4, 0xC3C7, 0xCCEC, 0xC3C8, 0xCCF0, 0xC3C9, 0xCD01, 0xC3CA, 0xCD08, 0xC3CB, 0xCD09, 0xC3CC, 0xCD0C, 0xC3CD, 0xCD10, 0xC3CE, 0xCD18, 0xC3CF, 0xCD19, 0xC3D0, 0xCD1B, 0xC3D1, 0xCD1D, 0xC3D2, 0xCD24, 0xC3D3, 0xCD28, 0xC3D4, 0xCD2C, 0xC3D5, 0xCD39, 0xC3D6, 0xCD5C, 0xC3D7, 0xCD60, 0xC3D8, 0xCD64, 0xC3D9, 0xCD6C, 0xC3DA, 0xCD6D, 0xC3DB, 0xCD6F, 0xC3DC, 0xCD71, 0xC3DD, 0xCD78, 0xC3DE, 0xCD88, 0xC3DF, 0xCD94, 0xC3E0, 0xCD95, 0xC3E1, 0xCD98, 0xC3E2, 0xCD9C, 0xC3E3, 0xCDA4, 0xC3E4, 0xCDA5, 0xC3E5, 0xCDA7, 0xC3E6, 0xCDA9, 0xC3E7, 0xCDB0, 0xC3E8, 0xCDC4, 0xC3E9, 0xCDCC, 0xC3EA, 0xCDD0, 0xC3EB, 0xCDE8, 0xC3EC, 0xCDEC, 0xC3ED, 0xCDF0, 0xC3EE, 0xCDF8, 0xC3EF, 0xCDF9, 0xC3F0, 0xCDFB, 0xC3F1, 0xCDFD, 0xC3F2, 0xCE04, 0xC3F3, 0xCE08, 0xC3F4, 0xCE0C, 0xC3F5, 0xCE14, 0xC3F6, 0xCE19, 0xC3F7, 0xCE20, 0xC3F8, 0xCE21, 0xC3F9, 0xCE24, 0xC3FA, 0xCE28, 0xC3FB, 0xCE30, 0xC3FC, 0xCE31, 0xC3FD, 0xCE33, 0xC3FE, 0xCE35, 0xC441, 0xD6AB, 0xC442, 0xD6AD, 0xC443, 0xD6AE, 0xC444, 0xD6AF, 0xC445, 0xD6B1, 0xC446, 0xD6B2, 0xC447, 0xD6B3, 0xC448, 0xD6B4, 0xC449, 0xD6B5, 0xC44A, 0xD6B6, 0xC44B, 0xD6B7, 0xC44C, 0xD6B8, 0xC44D, 0xD6BA, 0xC44E, 0xD6BC, 0xC44F, 0xD6BD, 0xC450, 0xD6BE, 0xC451, 0xD6BF, 0xC452, 0xD6C0, 0xC453, 0xD6C1, 0xC454, 0xD6C2, 0xC455, 0xD6C3, 0xC456, 0xD6C6, 0xC457, 0xD6C7, 0xC458, 0xD6C9, 0xC459, 0xD6CA, 0xC45A, 0xD6CB, 0xC461, 0xD6CD, 0xC462, 0xD6CE, 0xC463, 0xD6CF, 0xC464, 0xD6D0, 0xC465, 0xD6D2, 0xC466, 0xD6D3, 0xC467, 0xD6D5, 0xC468, 0xD6D6, 0xC469, 0xD6D8, 0xC46A, 0xD6DA, 0xC46B, 0xD6DB, 0xC46C, 0xD6DC, 0xC46D, 0xD6DD, 0xC46E, 0xD6DE, 0xC46F, 0xD6DF, 0xC470, 0xD6E1, 0xC471, 0xD6E2, 0xC472, 0xD6E3, 0xC473, 0xD6E5, 0xC474, 0xD6E6, 0xC475, 0xD6E7, 0xC476, 0xD6E9, 0xC477, 0xD6EA, 0xC478, 0xD6EB, 0xC479, 0xD6EC, 0xC47A, 0xD6ED, 0xC481, 0xD6EE, 0xC482, 0xD6EF, 0xC483, 0xD6F1, 0xC484, 0xD6F2, 0xC485, 0xD6F3, 0xC486, 0xD6F4, 0xC487, 0xD6F6, 0xC488, 0xD6F7, 0xC489, 0xD6F8, 0xC48A, 0xD6F9, 0xC48B, 0xD6FA, 0xC48C, 0xD6FB, 0xC48D, 0xD6FE, 0xC48E, 0xD6FF, 0xC48F, 0xD701, 0xC490, 0xD702, 0xC491, 0xD703, 0xC492, 0xD705, 0xC493, 0xD706, 0xC494, 0xD707, 0xC495, 0xD708, 0xC496, 0xD709, 0xC497, 0xD70A, 0xC498, 0xD70B, 0xC499, 0xD70C, 0xC49A, 0xD70D, 0xC49B, 0xD70E, 0xC49C, 0xD70F, 0xC49D, 0xD710, 0xC49E, 0xD712, 0xC49F, 0xD713, 0xC4A0, 0xD714, 0xC4A1, 0xCE58, 0xC4A2, 0xCE59, 0xC4A3, 0xCE5C, 0xC4A4, 0xCE5F, 0xC4A5, 0xCE60, 0xC4A6, 0xCE61, 0xC4A7, 0xCE68, 0xC4A8, 0xCE69, 0xC4A9, 0xCE6B, 0xC4AA, 0xCE6D, 0xC4AB, 0xCE74, 0xC4AC, 0xCE75, 0xC4AD, 0xCE78, 0xC4AE, 0xCE7C, 0xC4AF, 0xCE84, 0xC4B0, 0xCE85, 0xC4B1, 0xCE87, 0xC4B2, 0xCE89, 0xC4B3, 0xCE90, 0xC4B4, 0xCE91, 0xC4B5, 0xCE94, 0xC4B6, 0xCE98, 0xC4B7, 0xCEA0, 0xC4B8, 0xCEA1, 0xC4B9, 0xCEA3, 0xC4BA, 0xCEA4, 0xC4BB, 0xCEA5, 0xC4BC, 0xCEAC, 0xC4BD, 0xCEAD, 0xC4BE, 0xCEC1, 0xC4BF, 0xCEE4, 0xC4C0, 0xCEE5, 0xC4C1, 0xCEE8, 0xC4C2, 0xCEEB, 0xC4C3, 0xCEEC, 0xC4C4, 0xCEF4, 0xC4C5, 0xCEF5, 0xC4C6, 0xCEF7, 0xC4C7, 0xCEF8, 0xC4C8, 0xCEF9, 0xC4C9, 0xCF00, 0xC4CA, 0xCF01, 0xC4CB, 0xCF04, 0xC4CC, 0xCF08, 0xC4CD, 0xCF10, 0xC4CE, 0xCF11, 0xC4CF, 0xCF13, 0xC4D0, 0xCF15, 0xC4D1, 0xCF1C, 0xC4D2, 0xCF20, 0xC4D3, 0xCF24, 0xC4D4, 0xCF2C, 0xC4D5, 0xCF2D, 0xC4D6, 0xCF2F, 0xC4D7, 0xCF30, 0xC4D8, 0xCF31, 0xC4D9, 0xCF38, 0xC4DA, 0xCF54, 0xC4DB, 0xCF55, 0xC4DC, 0xCF58, 0xC4DD, 0xCF5C, 0xC4DE, 0xCF64, 0xC4DF, 0xCF65, 0xC4E0, 0xCF67, 0xC4E1, 0xCF69, 0xC4E2, 0xCF70, 0xC4E3, 0xCF71, 0xC4E4, 0xCF74, 0xC4E5, 0xCF78, 0xC4E6, 0xCF80, 0xC4E7, 0xCF85, 0xC4E8, 0xCF8C, 0xC4E9, 0xCFA1, 0xC4EA, 0xCFA8, 0xC4EB, 0xCFB0, 0xC4EC, 0xCFC4, 0xC4ED, 0xCFE0, 0xC4EE, 0xCFE1, 0xC4EF, 0xCFE4, 0xC4F0, 0xCFE8, 0xC4F1, 0xCFF0, 0xC4F2, 0xCFF1, 0xC4F3, 0xCFF3, 0xC4F4, 0xCFF5, 0xC4F5, 0xCFFC, 0xC4F6, 0xD000, 0xC4F7, 0xD004, 0xC4F8, 0xD011, 0xC4F9, 0xD018, 0xC4FA, 0xD02D, 0xC4FB, 0xD034, 0xC4FC, 0xD035, 0xC4FD, 0xD038, 0xC4FE, 0xD03C, 0xC541, 0xD715, 0xC542, 0xD716, 0xC543, 0xD717, 0xC544, 0xD71A, 0xC545, 0xD71B, 0xC546, 0xD71D, 0xC547, 0xD71E, 0xC548, 0xD71F, 0xC549, 0xD721, 0xC54A, 0xD722, 0xC54B, 0xD723, 0xC54C, 0xD724, 0xC54D, 0xD725, 0xC54E, 0xD726, 0xC54F, 0xD727, 0xC550, 0xD72A, 0xC551, 0xD72C, 0xC552, 0xD72E, 0xC553, 0xD72F, 0xC554, 0xD730, 0xC555, 0xD731, 0xC556, 0xD732, 0xC557, 0xD733, 0xC558, 0xD736, 0xC559, 0xD737, 0xC55A, 0xD739, 0xC561, 0xD73A, 0xC562, 0xD73B, 0xC563, 0xD73D, 0xC564, 0xD73E, 0xC565, 0xD73F, 0xC566, 0xD740, 0xC567, 0xD741, 0xC568, 0xD742, 0xC569, 0xD743, 0xC56A, 0xD745, 0xC56B, 0xD746, 0xC56C, 0xD748, 0xC56D, 0xD74A, 0xC56E, 0xD74B, 0xC56F, 0xD74C, 0xC570, 0xD74D, 0xC571, 0xD74E, 0xC572, 0xD74F, 0xC573, 0xD752, 0xC574, 0xD753, 0xC575, 0xD755, 0xC576, 0xD75A, 0xC577, 0xD75B, 0xC578, 0xD75C, 0xC579, 0xD75D, 0xC57A, 0xD75E, 0xC581, 0xD75F, 0xC582, 0xD762, 0xC583, 0xD764, 0xC584, 0xD766, 0xC585, 0xD767, 0xC586, 0xD768, 0xC587, 0xD76A, 0xC588, 0xD76B, 0xC589, 0xD76D, 0xC58A, 0xD76E, 0xC58B, 0xD76F, 0xC58C, 0xD771, 0xC58D, 0xD772, 0xC58E, 0xD773, 0xC58F, 0xD775, 0xC590, 0xD776, 0xC591, 0xD777, 0xC592, 0xD778, 0xC593, 0xD779, 0xC594, 0xD77A, 0xC595, 0xD77B, 0xC596, 0xD77E, 0xC597, 0xD77F, 0xC598, 0xD780, 0xC599, 0xD782, 0xC59A, 0xD783, 0xC59B, 0xD784, 0xC59C, 0xD785, 0xC59D, 0xD786, 0xC59E, 0xD787, 0xC59F, 0xD78A, 0xC5A0, 0xD78B, 0xC5A1, 0xD044, 0xC5A2, 0xD045, 0xC5A3, 0xD047, 0xC5A4, 0xD049, 0xC5A5, 0xD050, 0xC5A6, 0xD054, 0xC5A7, 0xD058, 0xC5A8, 0xD060, 0xC5A9, 0xD06C, 0xC5AA, 0xD06D, 0xC5AB, 0xD070, 0xC5AC, 0xD074, 0xC5AD, 0xD07C, 0xC5AE, 0xD07D, 0xC5AF, 0xD081, 0xC5B0, 0xD0A4, 0xC5B1, 0xD0A5, 0xC5B2, 0xD0A8, 0xC5B3, 0xD0AC, 0xC5B4, 0xD0B4, 0xC5B5, 0xD0B5, 0xC5B6, 0xD0B7, 0xC5B7, 0xD0B9, 0xC5B8, 0xD0C0, 0xC5B9, 0xD0C1, 0xC5BA, 0xD0C4, 0xC5BB, 0xD0C8, 0xC5BC, 0xD0C9, 0xC5BD, 0xD0D0, 0xC5BE, 0xD0D1, 0xC5BF, 0xD0D3, 0xC5C0, 0xD0D4, 0xC5C1, 0xD0D5, 0xC5C2, 0xD0DC, 0xC5C3, 0xD0DD, 0xC5C4, 0xD0E0, 0xC5C5, 0xD0E4, 0xC5C6, 0xD0EC, 0xC5C7, 0xD0ED, 0xC5C8, 0xD0EF, 0xC5C9, 0xD0F0, 0xC5CA, 0xD0F1, 0xC5CB, 0xD0F8, 0xC5CC, 0xD10D, 0xC5CD, 0xD130, 0xC5CE, 0xD131, 0xC5CF, 0xD134, 0xC5D0, 0xD138, 0xC5D1, 0xD13A, 0xC5D2, 0xD140, 0xC5D3, 0xD141, 0xC5D4, 0xD143, 0xC5D5, 0xD144, 0xC5D6, 0xD145, 0xC5D7, 0xD14C, 0xC5D8, 0xD14D, 0xC5D9, 0xD150, 0xC5DA, 0xD154, 0xC5DB, 0xD15C, 0xC5DC, 0xD15D, 0xC5DD, 0xD15F, 0xC5DE, 0xD161, 0xC5DF, 0xD168, 0xC5E0, 0xD16C, 0xC5E1, 0xD17C, 0xC5E2, 0xD184, 0xC5E3, 0xD188, 0xC5E4, 0xD1A0, 0xC5E5, 0xD1A1, 0xC5E6, 0xD1A4, 0xC5E7, 0xD1A8, 0xC5E8, 0xD1B0, 0xC5E9, 0xD1B1, 0xC5EA, 0xD1B3, 0xC5EB, 0xD1B5, 0xC5EC, 0xD1BA, 0xC5ED, 0xD1BC, 0xC5EE, 0xD1C0, 0xC5EF, 0xD1D8, 0xC5F0, 0xD1F4, 0xC5F1, 0xD1F8, 0xC5F2, 0xD207, 0xC5F3, 0xD209, 0xC5F4, 0xD210, 0xC5F5, 0xD22C, 0xC5F6, 0xD22D, 0xC5F7, 0xD230, 0xC5F8, 0xD234, 0xC5F9, 0xD23C, 0xC5FA, 0xD23D, 0xC5FB, 0xD23F, 0xC5FC, 0xD241, 0xC5FD, 0xD248, 0xC5FE, 0xD25C, 0xC641, 0xD78D, 0xC642, 0xD78E, 0xC643, 0xD78F, 0xC644, 0xD791, 0xC645, 0xD792, 0xC646, 0xD793, 0xC647, 0xD794, 0xC648, 0xD795, 0xC649, 0xD796, 0xC64A, 0xD797, 0xC64B, 0xD79A, 0xC64C, 0xD79C, 0xC64D, 0xD79E, 0xC64E, 0xD79F, 0xC64F, 0xD7A0, 0xC650, 0xD7A1, 0xC651, 0xD7A2, 0xC652, 0xD7A3, 0xC6A1, 0xD264, 0xC6A2, 0xD280, 0xC6A3, 0xD281, 0xC6A4, 0xD284, 0xC6A5, 0xD288, 0xC6A6, 0xD290, 0xC6A7, 0xD291, 0xC6A8, 0xD295, 0xC6A9, 0xD29C, 0xC6AA, 0xD2A0, 0xC6AB, 0xD2A4, 0xC6AC, 0xD2AC, 0xC6AD, 0xD2B1, 0xC6AE, 0xD2B8, 0xC6AF, 0xD2B9, 0xC6B0, 0xD2BC, 0xC6B1, 0xD2BF, 0xC6B2, 0xD2C0, 0xC6B3, 0xD2C2, 0xC6B4, 0xD2C8, 0xC6B5, 0xD2C9, 0xC6B6, 0xD2CB, 0xC6B7, 0xD2D4, 0xC6B8, 0xD2D8, 0xC6B9, 0xD2DC, 0xC6BA, 0xD2E4, 0xC6BB, 0xD2E5, 0xC6BC, 0xD2F0, 0xC6BD, 0xD2F1, 0xC6BE, 0xD2F4, 0xC6BF, 0xD2F8, 0xC6C0, 0xD300, 0xC6C1, 0xD301, 0xC6C2, 0xD303, 0xC6C3, 0xD305, 0xC6C4, 0xD30C, 0xC6C5, 0xD30D, 0xC6C6, 0xD30E, 0xC6C7, 0xD310, 0xC6C8, 0xD314, 0xC6C9, 0xD316, 0xC6CA, 0xD31C, 0xC6CB, 0xD31D, 0xC6CC, 0xD31F, 0xC6CD, 0xD320, 0xC6CE, 0xD321, 0xC6CF, 0xD325, 0xC6D0, 0xD328, 0xC6D1, 0xD329, 0xC6D2, 0xD32C, 0xC6D3, 0xD330, 0xC6D4, 0xD338, 0xC6D5, 0xD339, 0xC6D6, 0xD33B, 0xC6D7, 0xD33C, 0xC6D8, 0xD33D, 0xC6D9, 0xD344, 0xC6DA, 0xD345, 0xC6DB, 0xD37C, 0xC6DC, 0xD37D, 0xC6DD, 0xD380, 0xC6DE, 0xD384, 0xC6DF, 0xD38C, 0xC6E0, 0xD38D, 0xC6E1, 0xD38F, 0xC6E2, 0xD390, 0xC6E3, 0xD391, 0xC6E4, 0xD398, 0xC6E5, 0xD399, 0xC6E6, 0xD39C, 0xC6E7, 0xD3A0, 0xC6E8, 0xD3A8, 0xC6E9, 0xD3A9, 0xC6EA, 0xD3AB, 0xC6EB, 0xD3AD, 0xC6EC, 0xD3B4, 0xC6ED, 0xD3B8, 0xC6EE, 0xD3BC, 0xC6EF, 0xD3C4, 0xC6F0, 0xD3C5, 0xC6F1, 0xD3C8, 0xC6F2, 0xD3C9, 0xC6F3, 0xD3D0, 0xC6F4, 0xD3D8, 0xC6F5, 0xD3E1, 0xC6F6, 0xD3E3, 0xC6F7, 0xD3EC, 0xC6F8, 0xD3ED, 0xC6F9, 0xD3F0, 0xC6FA, 0xD3F4, 0xC6FB, 0xD3FC, 0xC6FC, 0xD3FD, 0xC6FD, 0xD3FF, 0xC6FE, 0xD401, 0xC7A1, 0xD408, 0xC7A2, 0xD41D, 0xC7A3, 0xD440, 0xC7A4, 0xD444, 0xC7A5, 0xD45C, 0xC7A6, 0xD460, 0xC7A7, 0xD464, 0xC7A8, 0xD46D, 0xC7A9, 0xD46F, 0xC7AA, 0xD478, 0xC7AB, 0xD479, 0xC7AC, 0xD47C, 0xC7AD, 0xD47F, 0xC7AE, 0xD480, 0xC7AF, 0xD482, 0xC7B0, 0xD488, 0xC7B1, 0xD489, 0xC7B2, 0xD48B, 0xC7B3, 0xD48D, 0xC7B4, 0xD494, 0xC7B5, 0xD4A9, 0xC7B6, 0xD4CC, 0xC7B7, 0xD4D0, 0xC7B8, 0xD4D4, 0xC7B9, 0xD4DC, 0xC7BA, 0xD4DF, 0xC7BB, 0xD4E8, 0xC7BC, 0xD4EC, 0xC7BD, 0xD4F0, 0xC7BE, 0xD4F8, 0xC7BF, 0xD4FB, 0xC7C0, 0xD4FD, 0xC7C1, 0xD504, 0xC7C2, 0xD508, 0xC7C3, 0xD50C, 0xC7C4, 0xD514, 0xC7C5, 0xD515, 0xC7C6, 0xD517, 0xC7C7, 0xD53C, 0xC7C8, 0xD53D, 0xC7C9, 0xD540, 0xC7CA, 0xD544, 0xC7CB, 0xD54C, 0xC7CC, 0xD54D, 0xC7CD, 0xD54F, 0xC7CE, 0xD551, 0xC7CF, 0xD558, 0xC7D0, 0xD559, 0xC7D1, 0xD55C, 0xC7D2, 0xD560, 0xC7D3, 0xD565, 0xC7D4, 0xD568, 0xC7D5, 0xD569, 0xC7D6, 0xD56B, 0xC7D7, 0xD56D, 0xC7D8, 0xD574, 0xC7D9, 0xD575, 0xC7DA, 0xD578, 0xC7DB, 0xD57C, 0xC7DC, 0xD584, 0xC7DD, 0xD585, 0xC7DE, 0xD587, 0xC7DF, 0xD588, 0xC7E0, 0xD589, 0xC7E1, 0xD590, 0xC7E2, 0xD5A5, 0xC7E3, 0xD5C8, 0xC7E4, 0xD5C9, 0xC7E5, 0xD5CC, 0xC7E6, 0xD5D0, 0xC7E7, 0xD5D2, 0xC7E8, 0xD5D8, 0xC7E9, 0xD5D9, 0xC7EA, 0xD5DB, 0xC7EB, 0xD5DD, 0xC7EC, 0xD5E4, 0xC7ED, 0xD5E5, 0xC7EE, 0xD5E8, 0xC7EF, 0xD5EC, 0xC7F0, 0xD5F4, 0xC7F1, 0xD5F5, 0xC7F2, 0xD5F7, 0xC7F3, 0xD5F9, 0xC7F4, 0xD600, 0xC7F5, 0xD601, 0xC7F6, 0xD604, 0xC7F7, 0xD608, 0xC7F8, 0xD610, 0xC7F9, 0xD611, 0xC7FA, 0xD613, 0xC7FB, 0xD614, 0xC7FC, 0xD615, 0xC7FD, 0xD61C, 0xC7FE, 0xD620, 0xC8A1, 0xD624, 0xC8A2, 0xD62D, 0xC8A3, 0xD638, 0xC8A4, 0xD639, 0xC8A5, 0xD63C, 0xC8A6, 0xD640, 0xC8A7, 0xD645, 0xC8A8, 0xD648, 0xC8A9, 0xD649, 0xC8AA, 0xD64B, 0xC8AB, 0xD64D, 0xC8AC, 0xD651, 0xC8AD, 0xD654, 0xC8AE, 0xD655, 0xC8AF, 0xD658, 0xC8B0, 0xD65C, 0xC8B1, 0xD667, 0xC8B2, 0xD669, 0xC8B3, 0xD670, 0xC8B4, 0xD671, 0xC8B5, 0xD674, 0xC8B6, 0xD683, 0xC8B7, 0xD685, 0xC8B8, 0xD68C, 0xC8B9, 0xD68D, 0xC8BA, 0xD690, 0xC8BB, 0xD694, 0xC8BC, 0xD69D, 0xC8BD, 0xD69F, 0xC8BE, 0xD6A1, 0xC8BF, 0xD6A8, 0xC8C0, 0xD6AC, 0xC8C1, 0xD6B0, 0xC8C2, 0xD6B9, 0xC8C3, 0xD6BB, 0xC8C4, 0xD6C4, 0xC8C5, 0xD6C5, 0xC8C6, 0xD6C8, 0xC8C7, 0xD6CC, 0xC8C8, 0xD6D1, 0xC8C9, 0xD6D4, 0xC8CA, 0xD6D7, 0xC8CB, 0xD6D9, 0xC8CC, 0xD6E0, 0xC8CD, 0xD6E4, 0xC8CE, 0xD6E8, 0xC8CF, 0xD6F0, 0xC8D0, 0xD6F5, 0xC8D1, 0xD6FC, 0xC8D2, 0xD6FD, 0xC8D3, 0xD700, 0xC8D4, 0xD704, 0xC8D5, 0xD711, 0xC8D6, 0xD718, 0xC8D7, 0xD719, 0xC8D8, 0xD71C, 0xC8D9, 0xD720, 0xC8DA, 0xD728, 0xC8DB, 0xD729, 0xC8DC, 0xD72B, 0xC8DD, 0xD72D, 0xC8DE, 0xD734, 0xC8DF, 0xD735, 0xC8E0, 0xD738, 0xC8E1, 0xD73C, 0xC8E2, 0xD744, 0xC8E3, 0xD747, 0xC8E4, 0xD749, 0xC8E5, 0xD750, 0xC8E6, 0xD751, 0xC8E7, 0xD754, 0xC8E8, 0xD756, 0xC8E9, 0xD757, 0xC8EA, 0xD758, 0xC8EB, 0xD759, 0xC8EC, 0xD760, 0xC8ED, 0xD761, 0xC8EE, 0xD763, 0xC8EF, 0xD765, 0xC8F0, 0xD769, 0xC8F1, 0xD76C, 0xC8F2, 0xD770, 0xC8F3, 0xD774, 0xC8F4, 0xD77C, 0xC8F5, 0xD77D, 0xC8F6, 0xD781, 0xC8F7, 0xD788, 0xC8F8, 0xD789, 0xC8F9, 0xD78C, 0xC8FA, 0xD790, 0xC8FB, 0xD798, 0xC8FC, 0xD799, 0xC8FD, 0xD79B, 0xC8FE, 0xD79D, 0xCAA1, 0x4F3D, 0xCAA2, 0x4F73, 0xCAA3, 0x5047, 0xCAA4, 0x50F9, 0xCAA5, 0x52A0, 0xCAA6, 0x53EF, 0xCAA7, 0x5475, 0xCAA8, 0x54E5, 0xCAA9, 0x5609, 0xCAAA, 0x5AC1, 0xCAAB, 0x5BB6, 0xCAAC, 0x6687, 0xCAAD, 0x67B6, 0xCAAE, 0x67B7, 0xCAAF, 0x67EF, 0xCAB0, 0x6B4C, 0xCAB1, 0x73C2, 0xCAB2, 0x75C2, 0xCAB3, 0x7A3C, 0xCAB4, 0x82DB, 0xCAB5, 0x8304, 0xCAB6, 0x8857, 0xCAB7, 0x8888, 0xCAB8, 0x8A36, 0xCAB9, 0x8CC8, 0xCABA, 0x8DCF, 0xCABB, 0x8EFB, 0xCABC, 0x8FE6, 0xCABD, 0x99D5, 0xCABE, 0x523B, 0xCABF, 0x5374, 0xCAC0, 0x5404, 0xCAC1, 0x606A, 0xCAC2, 0x6164, 0xCAC3, 0x6BBC, 0xCAC4, 0x73CF, 0xCAC5, 0x811A, 0xCAC6, 0x89BA, 0xCAC7, 0x89D2, 0xCAC8, 0x95A3, 0xCAC9, 0x4F83, 0xCACA, 0x520A, 0xCACB, 0x58BE, 0xCACC, 0x5978, 0xCACD, 0x59E6, 0xCACE, 0x5E72, 0xCACF, 0x5E79, 0xCAD0, 0x61C7, 0xCAD1, 0x63C0, 0xCAD2, 0x6746, 0xCAD3, 0x67EC, 0xCAD4, 0x687F, 0xCAD5, 0x6F97, 0xCAD6, 0x764E, 0xCAD7, 0x770B, 0xCAD8, 0x78F5, 0xCAD9, 0x7A08, 0xCADA, 0x7AFF, 0xCADB, 0x7C21, 0xCADC, 0x809D, 0xCADD, 0x826E, 0xCADE, 0x8271, 0xCADF, 0x8AEB, 0xCAE0, 0x9593, 0xCAE1, 0x4E6B, 0xCAE2, 0x559D, 0xCAE3, 0x66F7, 0xCAE4, 0x6E34, 0xCAE5, 0x78A3, 0xCAE6, 0x7AED, 0xCAE7, 0x845B, 0xCAE8, 0x8910, 0xCAE9, 0x874E, 0xCAEA, 0x97A8, 0xCAEB, 0x52D8, 0xCAEC, 0x574E, 0xCAED, 0x582A, 0xCAEE, 0x5D4C, 0xCAEF, 0x611F, 0xCAF0, 0x61BE, 0xCAF1, 0x6221, 0xCAF2, 0x6562, 0xCAF3, 0x67D1, 0xCAF4, 0x6A44, 0xCAF5, 0x6E1B, 0xCAF6, 0x7518, 0xCAF7, 0x75B3, 0xCAF8, 0x76E3, 0xCAF9, 0x77B0, 0xCAFA, 0x7D3A, 0xCAFB, 0x90AF, 0xCAFC, 0x9451, 0xCAFD, 0x9452, 0xCAFE, 0x9F95, 0xCBA1, 0x5323, 0xCBA2, 0x5CAC, 0xCBA3, 0x7532, 0xCBA4, 0x80DB, 0xCBA5, 0x9240, 0xCBA6, 0x9598, 0xCBA7, 0x525B, 0xCBA8, 0x5808, 0xCBA9, 0x59DC, 0xCBAA, 0x5CA1, 0xCBAB, 0x5D17, 0xCBAC, 0x5EB7, 0xCBAD, 0x5F3A, 0xCBAE, 0x5F4A, 0xCBAF, 0x6177, 0xCBB0, 0x6C5F, 0xCBB1, 0x757A, 0xCBB2, 0x7586, 0xCBB3, 0x7CE0, 0xCBB4, 0x7D73, 0xCBB5, 0x7DB1, 0xCBB6, 0x7F8C, 0xCBB7, 0x8154, 0xCBB8, 0x8221, 0xCBB9, 0x8591, 0xCBBA, 0x8941, 0xCBBB, 0x8B1B, 0xCBBC, 0x92FC, 0xCBBD, 0x964D, 0xCBBE, 0x9C47, 0xCBBF, 0x4ECB, 0xCBC0, 0x4EF7, 0xCBC1, 0x500B, 0xCBC2, 0x51F1, 0xCBC3, 0x584F, 0xCBC4, 0x6137, 0xCBC5, 0x613E, 0xCBC6, 0x6168, 0xCBC7, 0x6539, 0xCBC8, 0x69EA, 0xCBC9, 0x6F11, 0xCBCA, 0x75A5, 0xCBCB, 0x7686, 0xCBCC, 0x76D6, 0xCBCD, 0x7B87, 0xCBCE, 0x82A5, 0xCBCF, 0x84CB, 0xCBD0, 0xF900, 0xCBD1, 0x93A7, 0xCBD2, 0x958B, 0xCBD3, 0x5580, 0xCBD4, 0x5BA2, 0xCBD5, 0x5751, 0xCBD6, 0xF901, 0xCBD7, 0x7CB3, 0xCBD8, 0x7FB9, 0xCBD9, 0x91B5, 0xCBDA, 0x5028, 0xCBDB, 0x53BB, 0xCBDC, 0x5C45, 0xCBDD, 0x5DE8, 0xCBDE, 0x62D2, 0xCBDF, 0x636E, 0xCBE0, 0x64DA, 0xCBE1, 0x64E7, 0xCBE2, 0x6E20, 0xCBE3, 0x70AC, 0xCBE4, 0x795B, 0xCBE5, 0x8DDD, 0xCBE6, 0x8E1E, 0xCBE7, 0xF902, 0xCBE8, 0x907D, 0xCBE9, 0x9245, 0xCBEA, 0x92F8, 0xCBEB, 0x4E7E, 0xCBEC, 0x4EF6, 0xCBED, 0x5065, 0xCBEE, 0x5DFE, 0xCBEF, 0x5EFA, 0xCBF0, 0x6106, 0xCBF1, 0x6957, 0xCBF2, 0x8171, 0xCBF3, 0x8654, 0xCBF4, 0x8E47, 0xCBF5, 0x9375, 0xCBF6, 0x9A2B, 0xCBF7, 0x4E5E, 0xCBF8, 0x5091, 0xCBF9, 0x6770, 0xCBFA, 0x6840, 0xCBFB, 0x5109, 0xCBFC, 0x528D, 0xCBFD, 0x5292, 0xCBFE, 0x6AA2, 0xCCA1, 0x77BC, 0xCCA2, 0x9210, 0xCCA3, 0x9ED4, 0xCCA4, 0x52AB, 0xCCA5, 0x602F, 0xCCA6, 0x8FF2, 0xCCA7, 0x5048, 0xCCA8, 0x61A9, 0xCCA9, 0x63ED, 0xCCAA, 0x64CA, 0xCCAB, 0x683C, 0xCCAC, 0x6A84, 0xCCAD, 0x6FC0, 0xCCAE, 0x8188, 0xCCAF, 0x89A1, 0xCCB0, 0x9694, 0xCCB1, 0x5805, 0xCCB2, 0x727D, 0xCCB3, 0x72AC, 0xCCB4, 0x7504, 0xCCB5, 0x7D79, 0xCCB6, 0x7E6D, 0xCCB7, 0x80A9, 0xCCB8, 0x898B, 0xCCB9, 0x8B74, 0xCCBA, 0x9063, 0xCCBB, 0x9D51, 0xCCBC, 0x6289, 0xCCBD, 0x6C7A, 0xCCBE, 0x6F54, 0xCCBF, 0x7D50, 0xCCC0, 0x7F3A, 0xCCC1, 0x8A23, 0xCCC2, 0x517C, 0xCCC3, 0x614A, 0xCCC4, 0x7B9D, 0xCCC5, 0x8B19, 0xCCC6, 0x9257, 0xCCC7, 0x938C, 0xCCC8, 0x4EAC, 0xCCC9, 0x4FD3, 0xCCCA, 0x501E, 0xCCCB, 0x50BE, 0xCCCC, 0x5106, 0xCCCD, 0x52C1, 0xCCCE, 0x52CD, 0xCCCF, 0x537F, 0xCCD0, 0x5770, 0xCCD1, 0x5883, 0xCCD2, 0x5E9A, 0xCCD3, 0x5F91, 0xCCD4, 0x6176, 0xCCD5, 0x61AC, 0xCCD6, 0x64CE, 0xCCD7, 0x656C, 0xCCD8, 0x666F, 0xCCD9, 0x66BB, 0xCCDA, 0x66F4, 0xCCDB, 0x6897, 0xCCDC, 0x6D87, 0xCCDD, 0x7085, 0xCCDE, 0x70F1, 0xCCDF, 0x749F, 0xCCE0, 0x74A5, 0xCCE1, 0x74CA, 0xCCE2, 0x75D9, 0xCCE3, 0x786C, 0xCCE4, 0x78EC, 0xCCE5, 0x7ADF, 0xCCE6, 0x7AF6, 0xCCE7, 0x7D45, 0xCCE8, 0x7D93, 0xCCE9, 0x8015, 0xCCEA, 0x803F, 0xCCEB, 0x811B, 0xCCEC, 0x8396, 0xCCED, 0x8B66, 0xCCEE, 0x8F15, 0xCCEF, 0x9015, 0xCCF0, 0x93E1, 0xCCF1, 0x9803, 0xCCF2, 0x9838, 0xCCF3, 0x9A5A, 0xCCF4, 0x9BE8, 0xCCF5, 0x4FC2, 0xCCF6, 0x5553, 0xCCF7, 0x583A, 0xCCF8, 0x5951, 0xCCF9, 0x5B63, 0xCCFA, 0x5C46, 0xCCFB, 0x60B8, 0xCCFC, 0x6212, 0xCCFD, 0x6842, 0xCCFE, 0x68B0, 0xCDA1, 0x68E8, 0xCDA2, 0x6EAA, 0xCDA3, 0x754C, 0xCDA4, 0x7678, 0xCDA5, 0x78CE, 0xCDA6, 0x7A3D, 0xCDA7, 0x7CFB, 0xCDA8, 0x7E6B, 0xCDA9, 0x7E7C, 0xCDAA, 0x8A08, 0xCDAB, 0x8AA1, 0xCDAC, 0x8C3F, 0xCDAD, 0x968E, 0xCDAE, 0x9DC4, 0xCDAF, 0x53E4, 0xCDB0, 0x53E9, 0xCDB1, 0x544A, 0xCDB2, 0x5471, 0xCDB3, 0x56FA, 0xCDB4, 0x59D1, 0xCDB5, 0x5B64, 0xCDB6, 0x5C3B, 0xCDB7, 0x5EAB, 0xCDB8, 0x62F7, 0xCDB9, 0x6537, 0xCDBA, 0x6545, 0xCDBB, 0x6572, 0xCDBC, 0x66A0, 0xCDBD, 0x67AF, 0xCDBE, 0x69C1, 0xCDBF, 0x6CBD, 0xCDC0, 0x75FC, 0xCDC1, 0x7690, 0xCDC2, 0x777E, 0xCDC3, 0x7A3F, 0xCDC4, 0x7F94, 0xCDC5, 0x8003, 0xCDC6, 0x80A1, 0xCDC7, 0x818F, 0xCDC8, 0x82E6, 0xCDC9, 0x82FD, 0xCDCA, 0x83F0, 0xCDCB, 0x85C1, 0xCDCC, 0x8831, 0xCDCD, 0x88B4, 0xCDCE, 0x8AA5, 0xCDCF, 0xF903, 0xCDD0, 0x8F9C, 0xCDD1, 0x932E, 0xCDD2, 0x96C7, 0xCDD3, 0x9867, 0xCDD4, 0x9AD8, 0xCDD5, 0x9F13, 0xCDD6, 0x54ED, 0xCDD7, 0x659B, 0xCDD8, 0x66F2, 0xCDD9, 0x688F, 0xCDDA, 0x7A40, 0xCDDB, 0x8C37, 0xCDDC, 0x9D60, 0xCDDD, 0x56F0, 0xCDDE, 0x5764, 0xCDDF, 0x5D11, 0xCDE0, 0x6606, 0xCDE1, 0x68B1, 0xCDE2, 0x68CD, 0xCDE3, 0x6EFE, 0xCDE4, 0x7428, 0xCDE5, 0x889E, 0xCDE6, 0x9BE4, 0xCDE7, 0x6C68, 0xCDE8, 0xF904, 0xCDE9, 0x9AA8, 0xCDEA, 0x4F9B, 0xCDEB, 0x516C, 0xCDEC, 0x5171, 0xCDED, 0x529F, 0xCDEE, 0x5B54, 0xCDEF, 0x5DE5, 0xCDF0, 0x6050, 0xCDF1, 0x606D, 0xCDF2, 0x62F1, 0xCDF3, 0x63A7, 0xCDF4, 0x653B, 0xCDF5, 0x73D9, 0xCDF6, 0x7A7A, 0xCDF7, 0x86A3, 0xCDF8, 0x8CA2, 0xCDF9, 0x978F, 0xCDFA, 0x4E32, 0xCDFB, 0x5BE1, 0xCDFC, 0x6208, 0xCDFD, 0x679C, 0xCDFE, 0x74DC, 0xCEA1, 0x79D1, 0xCEA2, 0x83D3, 0xCEA3, 0x8A87, 0xCEA4, 0x8AB2, 0xCEA5, 0x8DE8, 0xCEA6, 0x904E, 0xCEA7, 0x934B, 0xCEA8, 0x9846, 0xCEA9, 0x5ED3, 0xCEAA, 0x69E8, 0xCEAB, 0x85FF, 0xCEAC, 0x90ED, 0xCEAD, 0xF905, 0xCEAE, 0x51A0, 0xCEAF, 0x5B98, 0xCEB0, 0x5BEC, 0xCEB1, 0x6163, 0xCEB2, 0x68FA, 0xCEB3, 0x6B3E, 0xCEB4, 0x704C, 0xCEB5, 0x742F, 0xCEB6, 0x74D8, 0xCEB7, 0x7BA1, 0xCEB8, 0x7F50, 0xCEB9, 0x83C5, 0xCEBA, 0x89C0, 0xCEBB, 0x8CAB, 0xCEBC, 0x95DC, 0xCEBD, 0x9928, 0xCEBE, 0x522E, 0xCEBF, 0x605D, 0xCEC0, 0x62EC, 0xCEC1, 0x9002, 0xCEC2, 0x4F8A, 0xCEC3, 0x5149, 0xCEC4, 0x5321, 0xCEC5, 0x58D9, 0xCEC6, 0x5EE3, 0xCEC7, 0x66E0, 0xCEC8, 0x6D38, 0xCEC9, 0x709A, 0xCECA, 0x72C2, 0xCECB, 0x73D6, 0xCECC, 0x7B50, 0xCECD, 0x80F1, 0xCECE, 0x945B, 0xCECF, 0x5366, 0xCED0, 0x639B, 0xCED1, 0x7F6B, 0xCED2, 0x4E56, 0xCED3, 0x5080, 0xCED4, 0x584A, 0xCED5, 0x58DE, 0xCED6, 0x602A, 0xCED7, 0x6127, 0xCED8, 0x62D0, 0xCED9, 0x69D0, 0xCEDA, 0x9B41, 0xCEDB, 0x5B8F, 0xCEDC, 0x7D18, 0xCEDD, 0x80B1, 0xCEDE, 0x8F5F, 0xCEDF, 0x4EA4, 0xCEE0, 0x50D1, 0xCEE1, 0x54AC, 0xCEE2, 0x55AC, 0xCEE3, 0x5B0C, 0xCEE4, 0x5DA0, 0xCEE5, 0x5DE7, 0xCEE6, 0x652A, 0xCEE7, 0x654E, 0xCEE8, 0x6821, 0xCEE9, 0x6A4B, 0xCEEA, 0x72E1, 0xCEEB, 0x768E, 0xCEEC, 0x77EF, 0xCEED, 0x7D5E, 0xCEEE, 0x7FF9, 0xCEEF, 0x81A0, 0xCEF0, 0x854E, 0xCEF1, 0x86DF, 0xCEF2, 0x8F03, 0xCEF3, 0x8F4E, 0xCEF4, 0x90CA, 0xCEF5, 0x9903, 0xCEF6, 0x9A55, 0xCEF7, 0x9BAB, 0xCEF8, 0x4E18, 0xCEF9, 0x4E45, 0xCEFA, 0x4E5D, 0xCEFB, 0x4EC7, 0xCEFC, 0x4FF1, 0xCEFD, 0x5177, 0xCEFE, 0x52FE, 0xCFA1, 0x5340, 0xCFA2, 0x53E3, 0xCFA3, 0x53E5, 0xCFA4, 0x548E, 0xCFA5, 0x5614, 0xCFA6, 0x5775, 0xCFA7, 0x57A2, 0xCFA8, 0x5BC7, 0xCFA9, 0x5D87, 0xCFAA, 0x5ED0, 0xCFAB, 0x61FC, 0xCFAC, 0x62D8, 0xCFAD, 0x6551, 0xCFAE, 0x67B8, 0xCFAF, 0x67E9, 0xCFB0, 0x69CB, 0xCFB1, 0x6B50, 0xCFB2, 0x6BC6, 0xCFB3, 0x6BEC, 0xCFB4, 0x6C42, 0xCFB5, 0x6E9D, 0xCFB6, 0x7078, 0xCFB7, 0x72D7, 0xCFB8, 0x7396, 0xCFB9, 0x7403, 0xCFBA, 0x77BF, 0xCFBB, 0x77E9, 0xCFBC, 0x7A76, 0xCFBD, 0x7D7F, 0xCFBE, 0x8009, 0xCFBF, 0x81FC, 0xCFC0, 0x8205, 0xCFC1, 0x820A, 0xCFC2, 0x82DF, 0xCFC3, 0x8862, 0xCFC4, 0x8B33, 0xCFC5, 0x8CFC, 0xCFC6, 0x8EC0, 0xCFC7, 0x9011, 0xCFC8, 0x90B1, 0xCFC9, 0x9264, 0xCFCA, 0x92B6, 0xCFCB, 0x99D2, 0xCFCC, 0x9A45, 0xCFCD, 0x9CE9, 0xCFCE, 0x9DD7, 0xCFCF, 0x9F9C, 0xCFD0, 0x570B, 0xCFD1, 0x5C40, 0xCFD2, 0x83CA, 0xCFD3, 0x97A0, 0xCFD4, 0x97AB, 0xCFD5, 0x9EB4, 0xCFD6, 0x541B, 0xCFD7, 0x7A98, 0xCFD8, 0x7FA4, 0xCFD9, 0x88D9, 0xCFDA, 0x8ECD, 0xCFDB, 0x90E1, 0xCFDC, 0x5800, 0xCFDD, 0x5C48, 0xCFDE, 0x6398, 0xCFDF, 0x7A9F, 0xCFE0, 0x5BAE, 0xCFE1, 0x5F13, 0xCFE2, 0x7A79, 0xCFE3, 0x7AAE, 0xCFE4, 0x828E, 0xCFE5, 0x8EAC, 0xCFE6, 0x5026, 0xCFE7, 0x5238, 0xCFE8, 0x52F8, 0xCFE9, 0x5377, 0xCFEA, 0x5708, 0xCFEB, 0x62F3, 0xCFEC, 0x6372, 0xCFED, 0x6B0A, 0xCFEE, 0x6DC3, 0xCFEF, 0x7737, 0xCFF0, 0x53A5, 0xCFF1, 0x7357, 0xCFF2, 0x8568, 0xCFF3, 0x8E76, 0xCFF4, 0x95D5, 0xCFF5, 0x673A, 0xCFF6, 0x6AC3, 0xCFF7, 0x6F70, 0xCFF8, 0x8A6D, 0xCFF9, 0x8ECC, 0xCFFA, 0x994B, 0xCFFB, 0xF906, 0xCFFC, 0x6677, 0xCFFD, 0x6B78, 0xCFFE, 0x8CB4, 0xD0A1, 0x9B3C, 0xD0A2, 0xF907, 0xD0A3, 0x53EB, 0xD0A4, 0x572D, 0xD0A5, 0x594E, 0xD0A6, 0x63C6, 0xD0A7, 0x69FB, 0xD0A8, 0x73EA, 0xD0A9, 0x7845, 0xD0AA, 0x7ABA, 0xD0AB, 0x7AC5, 0xD0AC, 0x7CFE, 0xD0AD, 0x8475, 0xD0AE, 0x898F, 0xD0AF, 0x8D73, 0xD0B0, 0x9035, 0xD0B1, 0x95A8, 0xD0B2, 0x52FB, 0xD0B3, 0x5747, 0xD0B4, 0x7547, 0xD0B5, 0x7B60, 0xD0B6, 0x83CC, 0xD0B7, 0x921E, 0xD0B8, 0xF908, 0xD0B9, 0x6A58, 0xD0BA, 0x514B, 0xD0BB, 0x524B, 0xD0BC, 0x5287, 0xD0BD, 0x621F, 0xD0BE, 0x68D8, 0xD0BF, 0x6975, 0xD0C0, 0x9699, 0xD0C1, 0x50C5, 0xD0C2, 0x52A4, 0xD0C3, 0x52E4, 0xD0C4, 0x61C3, 0xD0C5, 0x65A4, 0xD0C6, 0x6839, 0xD0C7, 0x69FF, 0xD0C8, 0x747E, 0xD0C9, 0x7B4B, 0xD0CA, 0x82B9, 0xD0CB, 0x83EB, 0xD0CC, 0x89B2, 0xD0CD, 0x8B39, 0xD0CE, 0x8FD1, 0xD0CF, 0x9949, 0xD0D0, 0xF909, 0xD0D1, 0x4ECA, 0xD0D2, 0x5997, 0xD0D3, 0x64D2, 0xD0D4, 0x6611, 0xD0D5, 0x6A8E, 0xD0D6, 0x7434, 0xD0D7, 0x7981, 0xD0D8, 0x79BD, 0xD0D9, 0x82A9, 0xD0DA, 0x887E, 0xD0DB, 0x887F, 0xD0DC, 0x895F, 0xD0DD, 0xF90A, 0xD0DE, 0x9326, 0xD0DF, 0x4F0B, 0xD0E0, 0x53CA, 0xD0E1, 0x6025, 0xD0E2, 0x6271, 0xD0E3, 0x6C72, 0xD0E4, 0x7D1A, 0xD0E5, 0x7D66, 0xD0E6, 0x4E98, 0xD0E7, 0x5162, 0xD0E8, 0x77DC, 0xD0E9, 0x80AF, 0xD0EA, 0x4F01, 0xD0EB, 0x4F0E, 0xD0EC, 0x5176, 0xD0ED, 0x5180, 0xD0EE, 0x55DC, 0xD0EF, 0x5668, 0xD0F0, 0x573B, 0xD0F1, 0x57FA, 0xD0F2, 0x57FC, 0xD0F3, 0x5914, 0xD0F4, 0x5947, 0xD0F5, 0x5993, 0xD0F6, 0x5BC4, 0xD0F7, 0x5C90, 0xD0F8, 0x5D0E, 0xD0F9, 0x5DF1, 0xD0FA, 0x5E7E, 0xD0FB, 0x5FCC, 0xD0FC, 0x6280, 0xD0FD, 0x65D7, 0xD0FE, 0x65E3, 0xD1A1, 0x671E, 0xD1A2, 0x671F, 0xD1A3, 0x675E, 0xD1A4, 0x68CB, 0xD1A5, 0x68C4, 0xD1A6, 0x6A5F, 0xD1A7, 0x6B3A, 0xD1A8, 0x6C23, 0xD1A9, 0x6C7D, 0xD1AA, 0x6C82, 0xD1AB, 0x6DC7, 0xD1AC, 0x7398, 0xD1AD, 0x7426, 0xD1AE, 0x742A, 0xD1AF, 0x7482, 0xD1B0, 0x74A3, 0xD1B1, 0x7578, 0xD1B2, 0x757F, 0xD1B3, 0x7881, 0xD1B4, 0x78EF, 0xD1B5, 0x7941, 0xD1B6, 0x7947, 0xD1B7, 0x7948, 0xD1B8, 0x797A, 0xD1B9, 0x7B95, 0xD1BA, 0x7D00, 0xD1BB, 0x7DBA, 0xD1BC, 0x7F88, 0xD1BD, 0x8006, 0xD1BE, 0x802D, 0xD1BF, 0x808C, 0xD1C0, 0x8A18, 0xD1C1, 0x8B4F, 0xD1C2, 0x8C48, 0xD1C3, 0x8D77, 0xD1C4, 0x9321, 0xD1C5, 0x9324, 0xD1C6, 0x98E2, 0xD1C7, 0x9951, 0xD1C8, 0x9A0E, 0xD1C9, 0x9A0F, 0xD1CA, 0x9A65, 0xD1CB, 0x9E92, 0xD1CC, 0x7DCA, 0xD1CD, 0x4F76, 0xD1CE, 0x5409, 0xD1CF, 0x62EE, 0xD1D0, 0x6854, 0xD1D1, 0x91D1, 0xD1D2, 0x55AB, 0xD1D3, 0x513A, 0xD1D4, 0xF90B, 0xD1D5, 0xF90C, 0xD1D6, 0x5A1C, 0xD1D7, 0x61E6, 0xD1D8, 0xF90D, 0xD1D9, 0x62CF, 0xD1DA, 0x62FF, 0xD1DB, 0xF90E, 0xD1DC, 0xF90F, 0xD1DD, 0xF910, 0xD1DE, 0xF911, 0xD1DF, 0xF912, 0xD1E0, 0xF913, 0xD1E1, 0x90A3, 0xD1E2, 0xF914, 0xD1E3, 0xF915, 0xD1E4, 0xF916, 0xD1E5, 0xF917, 0xD1E6, 0xF918, 0xD1E7, 0x8AFE, 0xD1E8, 0xF919, 0xD1E9, 0xF91A, 0xD1EA, 0xF91B, 0xD1EB, 0xF91C, 0xD1EC, 0x6696, 0xD1ED, 0xF91D, 0xD1EE, 0x7156, 0xD1EF, 0xF91E, 0xD1F0, 0xF91F, 0xD1F1, 0x96E3, 0xD1F2, 0xF920, 0xD1F3, 0x634F, 0xD1F4, 0x637A, 0xD1F5, 0x5357, 0xD1F6, 0xF921, 0xD1F7, 0x678F, 0xD1F8, 0x6960, 0xD1F9, 0x6E73, 0xD1FA, 0xF922, 0xD1FB, 0x7537, 0xD1FC, 0xF923, 0xD1FD, 0xF924, 0xD1FE, 0xF925, 0xD2A1, 0x7D0D, 0xD2A2, 0xF926, 0xD2A3, 0xF927, 0xD2A4, 0x8872, 0xD2A5, 0x56CA, 0xD2A6, 0x5A18, 0xD2A7, 0xF928, 0xD2A8, 0xF929, 0xD2A9, 0xF92A, 0xD2AA, 0xF92B, 0xD2AB, 0xF92C, 0xD2AC, 0x4E43, 0xD2AD, 0xF92D, 0xD2AE, 0x5167, 0xD2AF, 0x5948, 0xD2B0, 0x67F0, 0xD2B1, 0x8010, 0xD2B2, 0xF92E, 0xD2B3, 0x5973, 0xD2B4, 0x5E74, 0xD2B5, 0x649A, 0xD2B6, 0x79CA, 0xD2B7, 0x5FF5, 0xD2B8, 0x606C, 0xD2B9, 0x62C8, 0xD2BA, 0x637B, 0xD2BB, 0x5BE7, 0xD2BC, 0x5BD7, 0xD2BD, 0x52AA, 0xD2BE, 0xF92F, 0xD2BF, 0x5974, 0xD2C0, 0x5F29, 0xD2C1, 0x6012, 0xD2C2, 0xF930, 0xD2C3, 0xF931, 0xD2C4, 0xF932, 0xD2C5, 0x7459, 0xD2C6, 0xF933, 0xD2C7, 0xF934, 0xD2C8, 0xF935, 0xD2C9, 0xF936, 0xD2CA, 0xF937, 0xD2CB, 0xF938, 0xD2CC, 0x99D1, 0xD2CD, 0xF939, 0xD2CE, 0xF93A, 0xD2CF, 0xF93B, 0xD2D0, 0xF93C, 0xD2D1, 0xF93D, 0xD2D2, 0xF93E, 0xD2D3, 0xF93F, 0xD2D4, 0xF940, 0xD2D5, 0xF941, 0xD2D6, 0xF942, 0xD2D7, 0xF943, 0xD2D8, 0x6FC3, 0xD2D9, 0xF944, 0xD2DA, 0xF945, 0xD2DB, 0x81BF, 0xD2DC, 0x8FB2, 0xD2DD, 0x60F1, 0xD2DE, 0xF946, 0xD2DF, 0xF947, 0xD2E0, 0x8166, 0xD2E1, 0xF948, 0xD2E2, 0xF949, 0xD2E3, 0x5C3F, 0xD2E4, 0xF94A, 0xD2E5, 0xF94B, 0xD2E6, 0xF94C, 0xD2E7, 0xF94D, 0xD2E8, 0xF94E, 0xD2E9, 0xF94F, 0xD2EA, 0xF950, 0xD2EB, 0xF951, 0xD2EC, 0x5AE9, 0xD2ED, 0x8A25, 0xD2EE, 0x677B, 0xD2EF, 0x7D10, 0xD2F0, 0xF952, 0xD2F1, 0xF953, 0xD2F2, 0xF954, 0xD2F3, 0xF955, 0xD2F4, 0xF956, 0xD2F5, 0xF957, 0xD2F6, 0x80FD, 0xD2F7, 0xF958, 0xD2F8, 0xF959, 0xD2F9, 0x5C3C, 0xD2FA, 0x6CE5, 0xD2FB, 0x533F, 0xD2FC, 0x6EBA, 0xD2FD, 0x591A, 0xD2FE, 0x8336, 0xD3A1, 0x4E39, 0xD3A2, 0x4EB6, 0xD3A3, 0x4F46, 0xD3A4, 0x55AE, 0xD3A5, 0x5718, 0xD3A6, 0x58C7, 0xD3A7, 0x5F56, 0xD3A8, 0x65B7, 0xD3A9, 0x65E6, 0xD3AA, 0x6A80, 0xD3AB, 0x6BB5, 0xD3AC, 0x6E4D, 0xD3AD, 0x77ED, 0xD3AE, 0x7AEF, 0xD3AF, 0x7C1E, 0xD3B0, 0x7DDE, 0xD3B1, 0x86CB, 0xD3B2, 0x8892, 0xD3B3, 0x9132, 0xD3B4, 0x935B, 0xD3B5, 0x64BB, 0xD3B6, 0x6FBE, 0xD3B7, 0x737A, 0xD3B8, 0x75B8, 0xD3B9, 0x9054, 0xD3BA, 0x5556, 0xD3BB, 0x574D, 0xD3BC, 0x61BA, 0xD3BD, 0x64D4, 0xD3BE, 0x66C7, 0xD3BF, 0x6DE1, 0xD3C0, 0x6E5B, 0xD3C1, 0x6F6D, 0xD3C2, 0x6FB9, 0xD3C3, 0x75F0, 0xD3C4, 0x8043, 0xD3C5, 0x81BD, 0xD3C6, 0x8541, 0xD3C7, 0x8983, 0xD3C8, 0x8AC7, 0xD3C9, 0x8B5A, 0xD3CA, 0x931F, 0xD3CB, 0x6C93, 0xD3CC, 0x7553, 0xD3CD, 0x7B54, 0xD3CE, 0x8E0F, 0xD3CF, 0x905D, 0xD3D0, 0x5510, 0xD3D1, 0x5802, 0xD3D2, 0x5858, 0xD3D3, 0x5E62, 0xD3D4, 0x6207, 0xD3D5, 0x649E, 0xD3D6, 0x68E0, 0xD3D7, 0x7576, 0xD3D8, 0x7CD6, 0xD3D9, 0x87B3, 0xD3DA, 0x9EE8, 0xD3DB, 0x4EE3, 0xD3DC, 0x5788, 0xD3DD, 0x576E, 0xD3DE, 0x5927, 0xD3DF, 0x5C0D, 0xD3E0, 0x5CB1, 0xD3E1, 0x5E36, 0xD3E2, 0x5F85, 0xD3E3, 0x6234, 0xD3E4, 0x64E1, 0xD3E5, 0x73B3, 0xD3E6, 0x81FA, 0xD3E7, 0x888B, 0xD3E8, 0x8CB8, 0xD3E9, 0x968A, 0xD3EA, 0x9EDB, 0xD3EB, 0x5B85, 0xD3EC, 0x5FB7, 0xD3ED, 0x60B3, 0xD3EE, 0x5012, 0xD3EF, 0x5200, 0xD3F0, 0x5230, 0xD3F1, 0x5716, 0xD3F2, 0x5835, 0xD3F3, 0x5857, 0xD3F4, 0x5C0E, 0xD3F5, 0x5C60, 0xD3F6, 0x5CF6, 0xD3F7, 0x5D8B, 0xD3F8, 0x5EA6, 0xD3F9, 0x5F92, 0xD3FA, 0x60BC, 0xD3FB, 0x6311, 0xD3FC, 0x6389, 0xD3FD, 0x6417, 0xD3FE, 0x6843, 0xD4A1, 0x68F9, 0xD4A2, 0x6AC2, 0xD4A3, 0x6DD8, 0xD4A4, 0x6E21, 0xD4A5, 0x6ED4, 0xD4A6, 0x6FE4, 0xD4A7, 0x71FE, 0xD4A8, 0x76DC, 0xD4A9, 0x7779, 0xD4AA, 0x79B1, 0xD4AB, 0x7A3B, 0xD4AC, 0x8404, 0xD4AD, 0x89A9, 0xD4AE, 0x8CED, 0xD4AF, 0x8DF3, 0xD4B0, 0x8E48, 0xD4B1, 0x9003, 0xD4B2, 0x9014, 0xD4B3, 0x9053, 0xD4B4, 0x90FD, 0xD4B5, 0x934D, 0xD4B6, 0x9676, 0xD4B7, 0x97DC, 0xD4B8, 0x6BD2, 0xD4B9, 0x7006, 0xD4BA, 0x7258, 0xD4BB, 0x72A2, 0xD4BC, 0x7368, 0xD4BD, 0x7763, 0xD4BE, 0x79BF, 0xD4BF, 0x7BE4, 0xD4C0, 0x7E9B, 0xD4C1, 0x8B80, 0xD4C2, 0x58A9, 0xD4C3, 0x60C7, 0xD4C4, 0x6566, 0xD4C5, 0x65FD, 0xD4C6, 0x66BE, 0xD4C7, 0x6C8C, 0xD4C8, 0x711E, 0xD4C9, 0x71C9, 0xD4CA, 0x8C5A, 0xD4CB, 0x9813, 0xD4CC, 0x4E6D, 0xD4CD, 0x7A81, 0xD4CE, 0x4EDD, 0xD4CF, 0x51AC, 0xD4D0, 0x51CD, 0xD4D1, 0x52D5, 0xD4D2, 0x540C, 0xD4D3, 0x61A7, 0xD4D4, 0x6771, 0xD4D5, 0x6850, 0xD4D6, 0x68DF, 0xD4D7, 0x6D1E, 0xD4D8, 0x6F7C, 0xD4D9, 0x75BC, 0xD4DA, 0x77B3, 0xD4DB, 0x7AE5, 0xD4DC, 0x80F4, 0xD4DD, 0x8463, 0xD4DE, 0x9285, 0xD4DF, 0x515C, 0xD4E0, 0x6597, 0xD4E1, 0x675C, 0xD4E2, 0x6793, 0xD4E3, 0x75D8, 0xD4E4, 0x7AC7, 0xD4E5, 0x8373, 0xD4E6, 0xF95A, 0xD4E7, 0x8C46, 0xD4E8, 0x9017, 0xD4E9, 0x982D, 0xD4EA, 0x5C6F, 0xD4EB, 0x81C0, 0xD4EC, 0x829A, 0xD4ED, 0x9041, 0xD4EE, 0x906F, 0xD4EF, 0x920D, 0xD4F0, 0x5F97, 0xD4F1, 0x5D9D, 0xD4F2, 0x6A59, 0xD4F3, 0x71C8, 0xD4F4, 0x767B, 0xD4F5, 0x7B49, 0xD4F6, 0x85E4, 0xD4F7, 0x8B04, 0xD4F8, 0x9127, 0xD4F9, 0x9A30, 0xD4FA, 0x5587, 0xD4FB, 0x61F6, 0xD4FC, 0xF95B, 0xD4FD, 0x7669, 0xD4FE, 0x7F85, 0xD5A1, 0x863F, 0xD5A2, 0x87BA, 0xD5A3, 0x88F8, 0xD5A4, 0x908F, 0xD5A5, 0xF95C, 0xD5A6, 0x6D1B, 0xD5A7, 0x70D9, 0xD5A8, 0x73DE, 0xD5A9, 0x7D61, 0xD5AA, 0x843D, 0xD5AB, 0xF95D, 0xD5AC, 0x916A, 0xD5AD, 0x99F1, 0xD5AE, 0xF95E, 0xD5AF, 0x4E82, 0xD5B0, 0x5375, 0xD5B1, 0x6B04, 0xD5B2, 0x6B12, 0xD5B3, 0x703E, 0xD5B4, 0x721B, 0xD5B5, 0x862D, 0xD5B6, 0x9E1E, 0xD5B7, 0x524C, 0xD5B8, 0x8FA3, 0xD5B9, 0x5D50, 0xD5BA, 0x64E5, 0xD5BB, 0x652C, 0xD5BC, 0x6B16, 0xD5BD, 0x6FEB, 0xD5BE, 0x7C43, 0xD5BF, 0x7E9C, 0xD5C0, 0x85CD, 0xD5C1, 0x8964, 0xD5C2, 0x89BD, 0xD5C3, 0x62C9, 0xD5C4, 0x81D8, 0xD5C5, 0x881F, 0xD5C6, 0x5ECA, 0xD5C7, 0x6717, 0xD5C8, 0x6D6A, 0xD5C9, 0x72FC, 0xD5CA, 0x7405, 0xD5CB, 0x746F, 0xD5CC, 0x8782, 0xD5CD, 0x90DE, 0xD5CE, 0x4F86, 0xD5CF, 0x5D0D, 0xD5D0, 0x5FA0, 0xD5D1, 0x840A, 0xD5D2, 0x51B7, 0xD5D3, 0x63A0, 0xD5D4, 0x7565, 0xD5D5, 0x4EAE, 0xD5D6, 0x5006, 0xD5D7, 0x5169, 0xD5D8, 0x51C9, 0xD5D9, 0x6881, 0xD5DA, 0x6A11, 0xD5DB, 0x7CAE, 0xD5DC, 0x7CB1, 0xD5DD, 0x7CE7, 0xD5DE, 0x826F, 0xD5DF, 0x8AD2, 0xD5E0, 0x8F1B, 0xD5E1, 0x91CF, 0xD5E2, 0x4FB6, 0xD5E3, 0x5137, 0xD5E4, 0x52F5, 0xD5E5, 0x5442, 0xD5E6, 0x5EEC, 0xD5E7, 0x616E, 0xD5E8, 0x623E, 0xD5E9, 0x65C5, 0xD5EA, 0x6ADA, 0xD5EB, 0x6FFE, 0xD5EC, 0x792A, 0xD5ED, 0x85DC, 0xD5EE, 0x8823, 0xD5EF, 0x95AD, 0xD5F0, 0x9A62, 0xD5F1, 0x9A6A, 0xD5F2, 0x9E97, 0xD5F3, 0x9ECE, 0xD5F4, 0x529B, 0xD5F5, 0x66C6, 0xD5F6, 0x6B77, 0xD5F7, 0x701D, 0xD5F8, 0x792B, 0xD5F9, 0x8F62, 0xD5FA, 0x9742, 0xD5FB, 0x6190, 0xD5FC, 0x6200, 0xD5FD, 0x6523, 0xD5FE, 0x6F23, 0xD6A1, 0x7149, 0xD6A2, 0x7489, 0xD6A3, 0x7DF4, 0xD6A4, 0x806F, 0xD6A5, 0x84EE, 0xD6A6, 0x8F26, 0xD6A7, 0x9023, 0xD6A8, 0x934A, 0xD6A9, 0x51BD, 0xD6AA, 0x5217, 0xD6AB, 0x52A3, 0xD6AC, 0x6D0C, 0xD6AD, 0x70C8, 0xD6AE, 0x88C2, 0xD6AF, 0x5EC9, 0xD6B0, 0x6582, 0xD6B1, 0x6BAE, 0xD6B2, 0x6FC2, 0xD6B3, 0x7C3E, 0xD6B4, 0x7375, 0xD6B5, 0x4EE4, 0xD6B6, 0x4F36, 0xD6B7, 0x56F9, 0xD6B8, 0xF95F, 0xD6B9, 0x5CBA, 0xD6BA, 0x5DBA, 0xD6BB, 0x601C, 0xD6BC, 0x73B2, 0xD6BD, 0x7B2D, 0xD6BE, 0x7F9A, 0xD6BF, 0x7FCE, 0xD6C0, 0x8046, 0xD6C1, 0x901E, 0xD6C2, 0x9234, 0xD6C3, 0x96F6, 0xD6C4, 0x9748, 0xD6C5, 0x9818, 0xD6C6, 0x9F61, 0xD6C7, 0x4F8B, 0xD6C8, 0x6FA7, 0xD6C9, 0x79AE, 0xD6CA, 0x91B4, 0xD6CB, 0x96B7, 0xD6CC, 0x52DE, 0xD6CD, 0xF960, 0xD6CE, 0x6488, 0xD6CF, 0x64C4, 0xD6D0, 0x6AD3, 0xD6D1, 0x6F5E, 0xD6D2, 0x7018, 0xD6D3, 0x7210, 0xD6D4, 0x76E7, 0xD6D5, 0x8001, 0xD6D6, 0x8606, 0xD6D7, 0x865C, 0xD6D8, 0x8DEF, 0xD6D9, 0x8F05, 0xD6DA, 0x9732, 0xD6DB, 0x9B6F, 0xD6DC, 0x9DFA, 0xD6DD, 0x9E75, 0xD6DE, 0x788C, 0xD6DF, 0x797F, 0xD6E0, 0x7DA0, 0xD6E1, 0x83C9, 0xD6E2, 0x9304, 0xD6E3, 0x9E7F, 0xD6E4, 0x9E93, 0xD6E5, 0x8AD6, 0xD6E6, 0x58DF, 0xD6E7, 0x5F04, 0xD6E8, 0x6727, 0xD6E9, 0x7027, 0xD6EA, 0x74CF, 0xD6EB, 0x7C60, 0xD6EC, 0x807E, 0xD6ED, 0x5121, 0xD6EE, 0x7028, 0xD6EF, 0x7262, 0xD6F0, 0x78CA, 0xD6F1, 0x8CC2, 0xD6F2, 0x8CDA, 0xD6F3, 0x8CF4, 0xD6F4, 0x96F7, 0xD6F5, 0x4E86, 0xD6F6, 0x50DA, 0xD6F7, 0x5BEE, 0xD6F8, 0x5ED6, 0xD6F9, 0x6599, 0xD6FA, 0x71CE, 0xD6FB, 0x7642, 0xD6FC, 0x77AD, 0xD6FD, 0x804A, 0xD6FE, 0x84FC, 0xD7A1, 0x907C, 0xD7A2, 0x9B27, 0xD7A3, 0x9F8D, 0xD7A4, 0x58D8, 0xD7A5, 0x5A41, 0xD7A6, 0x5C62, 0xD7A7, 0x6A13, 0xD7A8, 0x6DDA, 0xD7A9, 0x6F0F, 0xD7AA, 0x763B, 0xD7AB, 0x7D2F, 0xD7AC, 0x7E37, 0xD7AD, 0x851E, 0xD7AE, 0x8938, 0xD7AF, 0x93E4, 0xD7B0, 0x964B, 0xD7B1, 0x5289, 0xD7B2, 0x65D2, 0xD7B3, 0x67F3, 0xD7B4, 0x69B4, 0xD7B5, 0x6D41, 0xD7B6, 0x6E9C, 0xD7B7, 0x700F, 0xD7B8, 0x7409, 0xD7B9, 0x7460, 0xD7BA, 0x7559, 0xD7BB, 0x7624, 0xD7BC, 0x786B, 0xD7BD, 0x8B2C, 0xD7BE, 0x985E, 0xD7BF, 0x516D, 0xD7C0, 0x622E, 0xD7C1, 0x9678, 0xD7C2, 0x4F96, 0xD7C3, 0x502B, 0xD7C4, 0x5D19, 0xD7C5, 0x6DEA, 0xD7C6, 0x7DB8, 0xD7C7, 0x8F2A, 0xD7C8, 0x5F8B, 0xD7C9, 0x6144, 0xD7CA, 0x6817, 0xD7CB, 0xF961, 0xD7CC, 0x9686, 0xD7CD, 0x52D2, 0xD7CE, 0x808B, 0xD7CF, 0x51DC, 0xD7D0, 0x51CC, 0xD7D1, 0x695E, 0xD7D2, 0x7A1C, 0xD7D3, 0x7DBE, 0xD7D4, 0x83F1, 0xD7D5, 0x9675, 0xD7D6, 0x4FDA, 0xD7D7, 0x5229, 0xD7D8, 0x5398, 0xD7D9, 0x540F, 0xD7DA, 0x550E, 0xD7DB, 0x5C65, 0xD7DC, 0x60A7, 0xD7DD, 0x674E, 0xD7DE, 0x68A8, 0xD7DF, 0x6D6C, 0xD7E0, 0x7281, 0xD7E1, 0x72F8, 0xD7E2, 0x7406, 0xD7E3, 0x7483, 0xD7E4, 0xF962, 0xD7E5, 0x75E2, 0xD7E6, 0x7C6C, 0xD7E7, 0x7F79, 0xD7E8, 0x7FB8, 0xD7E9, 0x8389, 0xD7EA, 0x88CF, 0xD7EB, 0x88E1, 0xD7EC, 0x91CC, 0xD7ED, 0x91D0, 0xD7EE, 0x96E2, 0xD7EF, 0x9BC9, 0xD7F0, 0x541D, 0xD7F1, 0x6F7E, 0xD7F2, 0x71D0, 0xD7F3, 0x7498, 0xD7F4, 0x85FA, 0xD7F5, 0x8EAA, 0xD7F6, 0x96A3, 0xD7F7, 0x9C57, 0xD7F8, 0x9E9F, 0xD7F9, 0x6797, 0xD7FA, 0x6DCB, 0xD7FB, 0x7433, 0xD7FC, 0x81E8, 0xD7FD, 0x9716, 0xD7FE, 0x782C, 0xD8A1, 0x7ACB, 0xD8A2, 0x7B20, 0xD8A3, 0x7C92, 0xD8A4, 0x6469, 0xD8A5, 0x746A, 0xD8A6, 0x75F2, 0xD8A7, 0x78BC, 0xD8A8, 0x78E8, 0xD8A9, 0x99AC, 0xD8AA, 0x9B54, 0xD8AB, 0x9EBB, 0xD8AC, 0x5BDE, 0xD8AD, 0x5E55, 0xD8AE, 0x6F20, 0xD8AF, 0x819C, 0xD8B0, 0x83AB, 0xD8B1, 0x9088, 0xD8B2, 0x4E07, 0xD8B3, 0x534D, 0xD8B4, 0x5A29, 0xD8B5, 0x5DD2, 0xD8B6, 0x5F4E, 0xD8B7, 0x6162, 0xD8B8, 0x633D, 0xD8B9, 0x6669, 0xD8BA, 0x66FC, 0xD8BB, 0x6EFF, 0xD8BC, 0x6F2B, 0xD8BD, 0x7063, 0xD8BE, 0x779E, 0xD8BF, 0x842C, 0xD8C0, 0x8513, 0xD8C1, 0x883B, 0xD8C2, 0x8F13, 0xD8C3, 0x9945, 0xD8C4, 0x9C3B, 0xD8C5, 0x551C, 0xD8C6, 0x62B9, 0xD8C7, 0x672B, 0xD8C8, 0x6CAB, 0xD8C9, 0x8309, 0xD8CA, 0x896A, 0xD8CB, 0x977A, 0xD8CC, 0x4EA1, 0xD8CD, 0x5984, 0xD8CE, 0x5FD8, 0xD8CF, 0x5FD9, 0xD8D0, 0x671B, 0xD8D1, 0x7DB2, 0xD8D2, 0x7F54, 0xD8D3, 0x8292, 0xD8D4, 0x832B, 0xD8D5, 0x83BD, 0xD8D6, 0x8F1E, 0xD8D7, 0x9099, 0xD8D8, 0x57CB, 0xD8D9, 0x59B9, 0xD8DA, 0x5A92, 0xD8DB, 0x5BD0, 0xD8DC, 0x6627, 0xD8DD, 0x679A, 0xD8DE, 0x6885, 0xD8DF, 0x6BCF, 0xD8E0, 0x7164, 0xD8E1, 0x7F75, 0xD8E2, 0x8CB7, 0xD8E3, 0x8CE3, 0xD8E4, 0x9081, 0xD8E5, 0x9B45, 0xD8E6, 0x8108, 0xD8E7, 0x8C8A, 0xD8E8, 0x964C, 0xD8E9, 0x9A40, 0xD8EA, 0x9EA5, 0xD8EB, 0x5B5F, 0xD8EC, 0x6C13, 0xD8ED, 0x731B, 0xD8EE, 0x76F2, 0xD8EF, 0x76DF, 0xD8F0, 0x840C, 0xD8F1, 0x51AA, 0xD8F2, 0x8993, 0xD8F3, 0x514D, 0xD8F4, 0x5195, 0xD8F5, 0x52C9, 0xD8F6, 0x68C9, 0xD8F7, 0x6C94, 0xD8F8, 0x7704, 0xD8F9, 0x7720, 0xD8FA, 0x7DBF, 0xD8FB, 0x7DEC, 0xD8FC, 0x9762, 0xD8FD, 0x9EB5, 0xD8FE, 0x6EC5, 0xD9A1, 0x8511, 0xD9A2, 0x51A5, 0xD9A3, 0x540D, 0xD9A4, 0x547D, 0xD9A5, 0x660E, 0xD9A6, 0x669D, 0xD9A7, 0x6927, 0xD9A8, 0x6E9F, 0xD9A9, 0x76BF, 0xD9AA, 0x7791, 0xD9AB, 0x8317, 0xD9AC, 0x84C2, 0xD9AD, 0x879F, 0xD9AE, 0x9169, 0xD9AF, 0x9298, 0xD9B0, 0x9CF4, 0xD9B1, 0x8882, 0xD9B2, 0x4FAE, 0xD9B3, 0x5192, 0xD9B4, 0x52DF, 0xD9B5, 0x59C6, 0xD9B6, 0x5E3D, 0xD9B7, 0x6155, 0xD9B8, 0x6478, 0xD9B9, 0x6479, 0xD9BA, 0x66AE, 0xD9BB, 0x67D0, 0xD9BC, 0x6A21, 0xD9BD, 0x6BCD, 0xD9BE, 0x6BDB, 0xD9BF, 0x725F, 0xD9C0, 0x7261, 0xD9C1, 0x7441, 0xD9C2, 0x7738, 0xD9C3, 0x77DB, 0xD9C4, 0x8017, 0xD9C5, 0x82BC, 0xD9C6, 0x8305, 0xD9C7, 0x8B00, 0xD9C8, 0x8B28, 0xD9C9, 0x8C8C, 0xD9CA, 0x6728, 0xD9CB, 0x6C90, 0xD9CC, 0x7267, 0xD9CD, 0x76EE, 0xD9CE, 0x7766, 0xD9CF, 0x7A46, 0xD9D0, 0x9DA9, 0xD9D1, 0x6B7F, 0xD9D2, 0x6C92, 0xD9D3, 0x5922, 0xD9D4, 0x6726, 0xD9D5, 0x8499, 0xD9D6, 0x536F, 0xD9D7, 0x5893, 0xD9D8, 0x5999, 0xD9D9, 0x5EDF, 0xD9DA, 0x63CF, 0xD9DB, 0x6634, 0xD9DC, 0x6773, 0xD9DD, 0x6E3A, 0xD9DE, 0x732B, 0xD9DF, 0x7AD7, 0xD9E0, 0x82D7, 0xD9E1, 0x9328, 0xD9E2, 0x52D9, 0xD9E3, 0x5DEB, 0xD9E4, 0x61AE, 0xD9E5, 0x61CB, 0xD9E6, 0x620A, 0xD9E7, 0x62C7, 0xD9E8, 0x64AB, 0xD9E9, 0x65E0, 0xD9EA, 0x6959, 0xD9EB, 0x6B66, 0xD9EC, 0x6BCB, 0xD9ED, 0x7121, 0xD9EE, 0x73F7, 0xD9EF, 0x755D, 0xD9F0, 0x7E46, 0xD9F1, 0x821E, 0xD9F2, 0x8302, 0xD9F3, 0x856A, 0xD9F4, 0x8AA3, 0xD9F5, 0x8CBF, 0xD9F6, 0x9727, 0xD9F7, 0x9D61, 0xD9F8, 0x58A8, 0xD9F9, 0x9ED8, 0xD9FA, 0x5011, 0xD9FB, 0x520E, 0xD9FC, 0x543B, 0xD9FD, 0x554F, 0xD9FE, 0x6587, 0xDAA1, 0x6C76, 0xDAA2, 0x7D0A, 0xDAA3, 0x7D0B, 0xDAA4, 0x805E, 0xDAA5, 0x868A, 0xDAA6, 0x9580, 0xDAA7, 0x96EF, 0xDAA8, 0x52FF, 0xDAA9, 0x6C95, 0xDAAA, 0x7269, 0xDAAB, 0x5473, 0xDAAC, 0x5A9A, 0xDAAD, 0x5C3E, 0xDAAE, 0x5D4B, 0xDAAF, 0x5F4C, 0xDAB0, 0x5FAE, 0xDAB1, 0x672A, 0xDAB2, 0x68B6, 0xDAB3, 0x6963, 0xDAB4, 0x6E3C, 0xDAB5, 0x6E44, 0xDAB6, 0x7709, 0xDAB7, 0x7C73, 0xDAB8, 0x7F8E, 0xDAB9, 0x8587, 0xDABA, 0x8B0E, 0xDABB, 0x8FF7, 0xDABC, 0x9761, 0xDABD, 0x9EF4, 0xDABE, 0x5CB7, 0xDABF, 0x60B6, 0xDAC0, 0x610D, 0xDAC1, 0x61AB, 0xDAC2, 0x654F, 0xDAC3, 0x65FB, 0xDAC4, 0x65FC, 0xDAC5, 0x6C11, 0xDAC6, 0x6CEF, 0xDAC7, 0x739F, 0xDAC8, 0x73C9, 0xDAC9, 0x7DE1, 0xDACA, 0x9594, 0xDACB, 0x5BC6, 0xDACC, 0x871C, 0xDACD, 0x8B10, 0xDACE, 0x525D, 0xDACF, 0x535A, 0xDAD0, 0x62CD, 0xDAD1, 0x640F, 0xDAD2, 0x64B2, 0xDAD3, 0x6734, 0xDAD4, 0x6A38, 0xDAD5, 0x6CCA, 0xDAD6, 0x73C0, 0xDAD7, 0x749E, 0xDAD8, 0x7B94, 0xDAD9, 0x7C95, 0xDADA, 0x7E1B, 0xDADB, 0x818A, 0xDADC, 0x8236, 0xDADD, 0x8584, 0xDADE, 0x8FEB, 0xDADF, 0x96F9, 0xDAE0, 0x99C1, 0xDAE1, 0x4F34, 0xDAE2, 0x534A, 0xDAE3, 0x53CD, 0xDAE4, 0x53DB, 0xDAE5, 0x62CC, 0xDAE6, 0x642C, 0xDAE7, 0x6500, 0xDAE8, 0x6591, 0xDAE9, 0x69C3, 0xDAEA, 0x6CEE, 0xDAEB, 0x6F58, 0xDAEC, 0x73ED, 0xDAED, 0x7554, 0xDAEE, 0x7622, 0xDAEF, 0x76E4, 0xDAF0, 0x76FC, 0xDAF1, 0x78D0, 0xDAF2, 0x78FB, 0xDAF3, 0x792C, 0xDAF4, 0x7D46, 0xDAF5, 0x822C, 0xDAF6, 0x87E0, 0xDAF7, 0x8FD4, 0xDAF8, 0x9812, 0xDAF9, 0x98EF, 0xDAFA, 0x52C3, 0xDAFB, 0x62D4, 0xDAFC, 0x64A5, 0xDAFD, 0x6E24, 0xDAFE, 0x6F51, 0xDBA1, 0x767C, 0xDBA2, 0x8DCB, 0xDBA3, 0x91B1, 0xDBA4, 0x9262, 0xDBA5, 0x9AEE, 0xDBA6, 0x9B43, 0xDBA7, 0x5023, 0xDBA8, 0x508D, 0xDBA9, 0x574A, 0xDBAA, 0x59A8, 0xDBAB, 0x5C28, 0xDBAC, 0x5E47, 0xDBAD, 0x5F77, 0xDBAE, 0x623F, 0xDBAF, 0x653E, 0xDBB0, 0x65B9, 0xDBB1, 0x65C1, 0xDBB2, 0x6609, 0xDBB3, 0x678B, 0xDBB4, 0x699C, 0xDBB5, 0x6EC2, 0xDBB6, 0x78C5, 0xDBB7, 0x7D21, 0xDBB8, 0x80AA, 0xDBB9, 0x8180, 0xDBBA, 0x822B, 0xDBBB, 0x82B3, 0xDBBC, 0x84A1, 0xDBBD, 0x868C, 0xDBBE, 0x8A2A, 0xDBBF, 0x8B17, 0xDBC0, 0x90A6, 0xDBC1, 0x9632, 0xDBC2, 0x9F90, 0xDBC3, 0x500D, 0xDBC4, 0x4FF3, 0xDBC5, 0xF963, 0xDBC6, 0x57F9, 0xDBC7, 0x5F98, 0xDBC8, 0x62DC, 0xDBC9, 0x6392, 0xDBCA, 0x676F, 0xDBCB, 0x6E43, 0xDBCC, 0x7119, 0xDBCD, 0x76C3, 0xDBCE, 0x80CC, 0xDBCF, 0x80DA, 0xDBD0, 0x88F4, 0xDBD1, 0x88F5, 0xDBD2, 0x8919, 0xDBD3, 0x8CE0, 0xDBD4, 0x8F29, 0xDBD5, 0x914D, 0xDBD6, 0x966A, 0xDBD7, 0x4F2F, 0xDBD8, 0x4F70, 0xDBD9, 0x5E1B, 0xDBDA, 0x67CF, 0xDBDB, 0x6822, 0xDBDC, 0x767D, 0xDBDD, 0x767E, 0xDBDE, 0x9B44, 0xDBDF, 0x5E61, 0xDBE0, 0x6A0A, 0xDBE1, 0x7169, 0xDBE2, 0x71D4, 0xDBE3, 0x756A, 0xDBE4, 0xF964, 0xDBE5, 0x7E41, 0xDBE6, 0x8543, 0xDBE7, 0x85E9, 0xDBE8, 0x98DC, 0xDBE9, 0x4F10, 0xDBEA, 0x7B4F, 0xDBEB, 0x7F70, 0xDBEC, 0x95A5, 0xDBED, 0x51E1, 0xDBEE, 0x5E06, 0xDBEF, 0x68B5, 0xDBF0, 0x6C3E, 0xDBF1, 0x6C4E, 0xDBF2, 0x6CDB, 0xDBF3, 0x72AF, 0xDBF4, 0x7BC4, 0xDBF5, 0x8303, 0xDBF6, 0x6CD5, 0xDBF7, 0x743A, 0xDBF8, 0x50FB, 0xDBF9, 0x5288, 0xDBFA, 0x58C1, 0xDBFB, 0x64D8, 0xDBFC, 0x6A97, 0xDBFD, 0x74A7, 0xDBFE, 0x7656, 0xDCA1, 0x78A7, 0xDCA2, 0x8617, 0xDCA3, 0x95E2, 0xDCA4, 0x9739, 0xDCA5, 0xF965, 0xDCA6, 0x535E, 0xDCA7, 0x5F01, 0xDCA8, 0x8B8A, 0xDCA9, 0x8FA8, 0xDCAA, 0x8FAF, 0xDCAB, 0x908A, 0xDCAC, 0x5225, 0xDCAD, 0x77A5, 0xDCAE, 0x9C49, 0xDCAF, 0x9F08, 0xDCB0, 0x4E19, 0xDCB1, 0x5002, 0xDCB2, 0x5175, 0xDCB3, 0x5C5B, 0xDCB4, 0x5E77, 0xDCB5, 0x661E, 0xDCB6, 0x663A, 0xDCB7, 0x67C4, 0xDCB8, 0x68C5, 0xDCB9, 0x70B3, 0xDCBA, 0x7501, 0xDCBB, 0x75C5, 0xDCBC, 0x79C9, 0xDCBD, 0x7ADD, 0xDCBE, 0x8F27, 0xDCBF, 0x9920, 0xDCC0, 0x9A08, 0xDCC1, 0x4FDD, 0xDCC2, 0x5821, 0xDCC3, 0x5831, 0xDCC4, 0x5BF6, 0xDCC5, 0x666E, 0xDCC6, 0x6B65, 0xDCC7, 0x6D11, 0xDCC8, 0x6E7A, 0xDCC9, 0x6F7D, 0xDCCA, 0x73E4, 0xDCCB, 0x752B, 0xDCCC, 0x83E9, 0xDCCD, 0x88DC, 0xDCCE, 0x8913, 0xDCCF, 0x8B5C, 0xDCD0, 0x8F14, 0xDCD1, 0x4F0F, 0xDCD2, 0x50D5, 0xDCD3, 0x5310, 0xDCD4, 0x535C, 0xDCD5, 0x5B93, 0xDCD6, 0x5FA9, 0xDCD7, 0x670D, 0xDCD8, 0x798F, 0xDCD9, 0x8179, 0xDCDA, 0x832F, 0xDCDB, 0x8514, 0xDCDC, 0x8907, 0xDCDD, 0x8986, 0xDCDE, 0x8F39, 0xDCDF, 0x8F3B, 0xDCE0, 0x99A5, 0xDCE1, 0x9C12, 0xDCE2, 0x672C, 0xDCE3, 0x4E76, 0xDCE4, 0x4FF8, 0xDCE5, 0x5949, 0xDCE6, 0x5C01, 0xDCE7, 0x5CEF, 0xDCE8, 0x5CF0, 0xDCE9, 0x6367, 0xDCEA, 0x68D2, 0xDCEB, 0x70FD, 0xDCEC, 0x71A2, 0xDCED, 0x742B, 0xDCEE, 0x7E2B, 0xDCEF, 0x84EC, 0xDCF0, 0x8702, 0xDCF1, 0x9022, 0xDCF2, 0x92D2, 0xDCF3, 0x9CF3, 0xDCF4, 0x4E0D, 0xDCF5, 0x4ED8, 0xDCF6, 0x4FEF, 0xDCF7, 0x5085, 0xDCF8, 0x5256, 0xDCF9, 0x526F, 0xDCFA, 0x5426, 0xDCFB, 0x5490, 0xDCFC, 0x57E0, 0xDCFD, 0x592B, 0xDCFE, 0x5A66, 0xDDA1, 0x5B5A, 0xDDA2, 0x5B75, 0xDDA3, 0x5BCC, 0xDDA4, 0x5E9C, 0xDDA5, 0xF966, 0xDDA6, 0x6276, 0xDDA7, 0x6577, 0xDDA8, 0x65A7, 0xDDA9, 0x6D6E, 0xDDAA, 0x6EA5, 0xDDAB, 0x7236, 0xDDAC, 0x7B26, 0xDDAD, 0x7C3F, 0xDDAE, 0x7F36, 0xDDAF, 0x8150, 0xDDB0, 0x8151, 0xDDB1, 0x819A, 0xDDB2, 0x8240, 0xDDB3, 0x8299, 0xDDB4, 0x83A9, 0xDDB5, 0x8A03, 0xDDB6, 0x8CA0, 0xDDB7, 0x8CE6, 0xDDB8, 0x8CFB, 0xDDB9, 0x8D74, 0xDDBA, 0x8DBA, 0xDDBB, 0x90E8, 0xDDBC, 0x91DC, 0xDDBD, 0x961C, 0xDDBE, 0x9644, 0xDDBF, 0x99D9, 0xDDC0, 0x9CE7, 0xDDC1, 0x5317, 0xDDC2, 0x5206, 0xDDC3, 0x5429, 0xDDC4, 0x5674, 0xDDC5, 0x58B3, 0xDDC6, 0x5954, 0xDDC7, 0x596E, 0xDDC8, 0x5FFF, 0xDDC9, 0x61A4, 0xDDCA, 0x626E, 0xDDCB, 0x6610, 0xDDCC, 0x6C7E, 0xDDCD, 0x711A, 0xDDCE, 0x76C6, 0xDDCF, 0x7C89, 0xDDD0, 0x7CDE, 0xDDD1, 0x7D1B, 0xDDD2, 0x82AC, 0xDDD3, 0x8CC1, 0xDDD4, 0x96F0, 0xDDD5, 0xF967, 0xDDD6, 0x4F5B, 0xDDD7, 0x5F17, 0xDDD8, 0x5F7F, 0xDDD9, 0x62C2, 0xDDDA, 0x5D29, 0xDDDB, 0x670B, 0xDDDC, 0x68DA, 0xDDDD, 0x787C, 0xDDDE, 0x7E43, 0xDDDF, 0x9D6C, 0xDDE0, 0x4E15, 0xDDE1, 0x5099, 0xDDE2, 0x5315, 0xDDE3, 0x532A, 0xDDE4, 0x5351, 0xDDE5, 0x5983, 0xDDE6, 0x5A62, 0xDDE7, 0x5E87, 0xDDE8, 0x60B2, 0xDDE9, 0x618A, 0xDDEA, 0x6249, 0xDDEB, 0x6279, 0xDDEC, 0x6590, 0xDDED, 0x6787, 0xDDEE, 0x69A7, 0xDDEF, 0x6BD4, 0xDDF0, 0x6BD6, 0xDDF1, 0x6BD7, 0xDDF2, 0x6BD8, 0xDDF3, 0x6CB8, 0xDDF4, 0xF968, 0xDDF5, 0x7435, 0xDDF6, 0x75FA, 0xDDF7, 0x7812, 0xDDF8, 0x7891, 0xDDF9, 0x79D5, 0xDDFA, 0x79D8, 0xDDFB, 0x7C83, 0xDDFC, 0x7DCB, 0xDDFD, 0x7FE1, 0xDDFE, 0x80A5, 0xDEA1, 0x813E, 0xDEA2, 0x81C2, 0xDEA3, 0x83F2, 0xDEA4, 0x871A, 0xDEA5, 0x88E8, 0xDEA6, 0x8AB9, 0xDEA7, 0x8B6C, 0xDEA8, 0x8CBB, 0xDEA9, 0x9119, 0xDEAA, 0x975E, 0xDEAB, 0x98DB, 0xDEAC, 0x9F3B, 0xDEAD, 0x56AC, 0xDEAE, 0x5B2A, 0xDEAF, 0x5F6C, 0xDEB0, 0x658C, 0xDEB1, 0x6AB3, 0xDEB2, 0x6BAF, 0xDEB3, 0x6D5C, 0xDEB4, 0x6FF1, 0xDEB5, 0x7015, 0xDEB6, 0x725D, 0xDEB7, 0x73AD, 0xDEB8, 0x8CA7, 0xDEB9, 0x8CD3, 0xDEBA, 0x983B, 0xDEBB, 0x6191, 0xDEBC, 0x6C37, 0xDEBD, 0x8058, 0xDEBE, 0x9A01, 0xDEBF, 0x4E4D, 0xDEC0, 0x4E8B, 0xDEC1, 0x4E9B, 0xDEC2, 0x4ED5, 0xDEC3, 0x4F3A, 0xDEC4, 0x4F3C, 0xDEC5, 0x4F7F, 0xDEC6, 0x4FDF, 0xDEC7, 0x50FF, 0xDEC8, 0x53F2, 0xDEC9, 0x53F8, 0xDECA, 0x5506, 0xDECB, 0x55E3, 0xDECC, 0x56DB, 0xDECD, 0x58EB, 0xDECE, 0x5962, 0xDECF, 0x5A11, 0xDED0, 0x5BEB, 0xDED1, 0x5BFA, 0xDED2, 0x5C04, 0xDED3, 0x5DF3, 0xDED4, 0x5E2B, 0xDED5, 0x5F99, 0xDED6, 0x601D, 0xDED7, 0x6368, 0xDED8, 0x659C, 0xDED9, 0x65AF, 0xDEDA, 0x67F6, 0xDEDB, 0x67FB, 0xDEDC, 0x68AD, 0xDEDD, 0x6B7B, 0xDEDE, 0x6C99, 0xDEDF, 0x6CD7, 0xDEE0, 0x6E23, 0xDEE1, 0x7009, 0xDEE2, 0x7345, 0xDEE3, 0x7802, 0xDEE4, 0x793E, 0xDEE5, 0x7940, 0xDEE6, 0x7960, 0xDEE7, 0x79C1, 0xDEE8, 0x7BE9, 0xDEE9, 0x7D17, 0xDEEA, 0x7D72, 0xDEEB, 0x8086, 0xDEEC, 0x820D, 0xDEED, 0x838E, 0xDEEE, 0x84D1, 0xDEEF, 0x86C7, 0xDEF0, 0x88DF, 0xDEF1, 0x8A50, 0xDEF2, 0x8A5E, 0xDEF3, 0x8B1D, 0xDEF4, 0x8CDC, 0xDEF5, 0x8D66, 0xDEF6, 0x8FAD, 0xDEF7, 0x90AA, 0xDEF8, 0x98FC, 0xDEF9, 0x99DF, 0xDEFA, 0x9E9D, 0xDEFB, 0x524A, 0xDEFC, 0xF969, 0xDEFD, 0x6714, 0xDEFE, 0xF96A, 0xDFA1, 0x5098, 0xDFA2, 0x522A, 0xDFA3, 0x5C71, 0xDFA4, 0x6563, 0xDFA5, 0x6C55, 0xDFA6, 0x73CA, 0xDFA7, 0x7523, 0xDFA8, 0x759D, 0xDFA9, 0x7B97, 0xDFAA, 0x849C, 0xDFAB, 0x9178, 0xDFAC, 0x9730, 0xDFAD, 0x4E77, 0xDFAE, 0x6492, 0xDFAF, 0x6BBA, 0xDFB0, 0x715E, 0xDFB1, 0x85A9, 0xDFB2, 0x4E09, 0xDFB3, 0xF96B, 0xDFB4, 0x6749, 0xDFB5, 0x68EE, 0xDFB6, 0x6E17, 0xDFB7, 0x829F, 0xDFB8, 0x8518, 0xDFB9, 0x886B, 0xDFBA, 0x63F7, 0xDFBB, 0x6F81, 0xDFBC, 0x9212, 0xDFBD, 0x98AF, 0xDFBE, 0x4E0A, 0xDFBF, 0x50B7, 0xDFC0, 0x50CF, 0xDFC1, 0x511F, 0xDFC2, 0x5546, 0xDFC3, 0x55AA, 0xDFC4, 0x5617, 0xDFC5, 0x5B40, 0xDFC6, 0x5C19, 0xDFC7, 0x5CE0, 0xDFC8, 0x5E38, 0xDFC9, 0x5E8A, 0xDFCA, 0x5EA0, 0xDFCB, 0x5EC2, 0xDFCC, 0x60F3, 0xDFCD, 0x6851, 0xDFCE, 0x6A61, 0xDFCF, 0x6E58, 0xDFD0, 0x723D, 0xDFD1, 0x7240, 0xDFD2, 0x72C0, 0xDFD3, 0x76F8, 0xDFD4, 0x7965, 0xDFD5, 0x7BB1, 0xDFD6, 0x7FD4, 0xDFD7, 0x88F3, 0xDFD8, 0x89F4, 0xDFD9, 0x8A73, 0xDFDA, 0x8C61, 0xDFDB, 0x8CDE, 0xDFDC, 0x971C, 0xDFDD, 0x585E, 0xDFDE, 0x74BD, 0xDFDF, 0x8CFD, 0xDFE0, 0x55C7, 0xDFE1, 0xF96C, 0xDFE2, 0x7A61, 0xDFE3, 0x7D22, 0xDFE4, 0x8272, 0xDFE5, 0x7272, 0xDFE6, 0x751F, 0xDFE7, 0x7525, 0xDFE8, 0xF96D, 0xDFE9, 0x7B19, 0xDFEA, 0x5885, 0xDFEB, 0x58FB, 0xDFEC, 0x5DBC, 0xDFED, 0x5E8F, 0xDFEE, 0x5EB6, 0xDFEF, 0x5F90, 0xDFF0, 0x6055, 0xDFF1, 0x6292, 0xDFF2, 0x637F, 0xDFF3, 0x654D, 0xDFF4, 0x6691, 0xDFF5, 0x66D9, 0xDFF6, 0x66F8, 0xDFF7, 0x6816, 0xDFF8, 0x68F2, 0xDFF9, 0x7280, 0xDFFA, 0x745E, 0xDFFB, 0x7B6E, 0xDFFC, 0x7D6E, 0xDFFD, 0x7DD6, 0xDFFE, 0x7F72, 0xE0A1, 0x80E5, 0xE0A2, 0x8212, 0xE0A3, 0x85AF, 0xE0A4, 0x897F, 0xE0A5, 0x8A93, 0xE0A6, 0x901D, 0xE0A7, 0x92E4, 0xE0A8, 0x9ECD, 0xE0A9, 0x9F20, 0xE0AA, 0x5915, 0xE0AB, 0x596D, 0xE0AC, 0x5E2D, 0xE0AD, 0x60DC, 0xE0AE, 0x6614, 0xE0AF, 0x6673, 0xE0B0, 0x6790, 0xE0B1, 0x6C50, 0xE0B2, 0x6DC5, 0xE0B3, 0x6F5F, 0xE0B4, 0x77F3, 0xE0B5, 0x78A9, 0xE0B6, 0x84C6, 0xE0B7, 0x91CB, 0xE0B8, 0x932B, 0xE0B9, 0x4ED9, 0xE0BA, 0x50CA, 0xE0BB, 0x5148, 0xE0BC, 0x5584, 0xE0BD, 0x5B0B, 0xE0BE, 0x5BA3, 0xE0BF, 0x6247, 0xE0C0, 0x657E, 0xE0C1, 0x65CB, 0xE0C2, 0x6E32, 0xE0C3, 0x717D, 0xE0C4, 0x7401, 0xE0C5, 0x7444, 0xE0C6, 0x7487, 0xE0C7, 0x74BF, 0xE0C8, 0x766C, 0xE0C9, 0x79AA, 0xE0CA, 0x7DDA, 0xE0CB, 0x7E55, 0xE0CC, 0x7FA8, 0xE0CD, 0x817A, 0xE0CE, 0x81B3, 0xE0CF, 0x8239, 0xE0D0, 0x861A, 0xE0D1, 0x87EC, 0xE0D2, 0x8A75, 0xE0D3, 0x8DE3, 0xE0D4, 0x9078, 0xE0D5, 0x9291, 0xE0D6, 0x9425, 0xE0D7, 0x994D, 0xE0D8, 0x9BAE, 0xE0D9, 0x5368, 0xE0DA, 0x5C51, 0xE0DB, 0x6954, 0xE0DC, 0x6CC4, 0xE0DD, 0x6D29, 0xE0DE, 0x6E2B, 0xE0DF, 0x820C, 0xE0E0, 0x859B, 0xE0E1, 0x893B, 0xE0E2, 0x8A2D, 0xE0E3, 0x8AAA, 0xE0E4, 0x96EA, 0xE0E5, 0x9F67, 0xE0E6, 0x5261, 0xE0E7, 0x66B9, 0xE0E8, 0x6BB2, 0xE0E9, 0x7E96, 0xE0EA, 0x87FE, 0xE0EB, 0x8D0D, 0xE0EC, 0x9583, 0xE0ED, 0x965D, 0xE0EE, 0x651D, 0xE0EF, 0x6D89, 0xE0F0, 0x71EE, 0xE0F1, 0xF96E, 0xE0F2, 0x57CE, 0xE0F3, 0x59D3, 0xE0F4, 0x5BAC, 0xE0F5, 0x6027, 0xE0F6, 0x60FA, 0xE0F7, 0x6210, 0xE0F8, 0x661F, 0xE0F9, 0x665F, 0xE0FA, 0x7329, 0xE0FB, 0x73F9, 0xE0FC, 0x76DB, 0xE0FD, 0x7701, 0xE0FE, 0x7B6C, 0xE1A1, 0x8056, 0xE1A2, 0x8072, 0xE1A3, 0x8165, 0xE1A4, 0x8AA0, 0xE1A5, 0x9192, 0xE1A6, 0x4E16, 0xE1A7, 0x52E2, 0xE1A8, 0x6B72, 0xE1A9, 0x6D17, 0xE1AA, 0x7A05, 0xE1AB, 0x7B39, 0xE1AC, 0x7D30, 0xE1AD, 0xF96F, 0xE1AE, 0x8CB0, 0xE1AF, 0x53EC, 0xE1B0, 0x562F, 0xE1B1, 0x5851, 0xE1B2, 0x5BB5, 0xE1B3, 0x5C0F, 0xE1B4, 0x5C11, 0xE1B5, 0x5DE2, 0xE1B6, 0x6240, 0xE1B7, 0x6383, 0xE1B8, 0x6414, 0xE1B9, 0x662D, 0xE1BA, 0x68B3, 0xE1BB, 0x6CBC, 0xE1BC, 0x6D88, 0xE1BD, 0x6EAF, 0xE1BE, 0x701F, 0xE1BF, 0x70A4, 0xE1C0, 0x71D2, 0xE1C1, 0x7526, 0xE1C2, 0x758F, 0xE1C3, 0x758E, 0xE1C4, 0x7619, 0xE1C5, 0x7B11, 0xE1C6, 0x7BE0, 0xE1C7, 0x7C2B, 0xE1C8, 0x7D20, 0xE1C9, 0x7D39, 0xE1CA, 0x852C, 0xE1CB, 0x856D, 0xE1CC, 0x8607, 0xE1CD, 0x8A34, 0xE1CE, 0x900D, 0xE1CF, 0x9061, 0xE1D0, 0x90B5, 0xE1D1, 0x92B7, 0xE1D2, 0x97F6, 0xE1D3, 0x9A37, 0xE1D4, 0x4FD7, 0xE1D5, 0x5C6C, 0xE1D6, 0x675F, 0xE1D7, 0x6D91, 0xE1D8, 0x7C9F, 0xE1D9, 0x7E8C, 0xE1DA, 0x8B16, 0xE1DB, 0x8D16, 0xE1DC, 0x901F, 0xE1DD, 0x5B6B, 0xE1DE, 0x5DFD, 0xE1DF, 0x640D, 0xE1E0, 0x84C0, 0xE1E1, 0x905C, 0xE1E2, 0x98E1, 0xE1E3, 0x7387, 0xE1E4, 0x5B8B, 0xE1E5, 0x609A, 0xE1E6, 0x677E, 0xE1E7, 0x6DDE, 0xE1E8, 0x8A1F, 0xE1E9, 0x8AA6, 0xE1EA, 0x9001, 0xE1EB, 0x980C, 0xE1EC, 0x5237, 0xE1ED, 0xF970, 0xE1EE, 0x7051, 0xE1EF, 0x788E, 0xE1F0, 0x9396, 0xE1F1, 0x8870, 0xE1F2, 0x91D7, 0xE1F3, 0x4FEE, 0xE1F4, 0x53D7, 0xE1F5, 0x55FD, 0xE1F6, 0x56DA, 0xE1F7, 0x5782, 0xE1F8, 0x58FD, 0xE1F9, 0x5AC2, 0xE1FA, 0x5B88, 0xE1FB, 0x5CAB, 0xE1FC, 0x5CC0, 0xE1FD, 0x5E25, 0xE1FE, 0x6101, 0xE2A1, 0x620D, 0xE2A2, 0x624B, 0xE2A3, 0x6388, 0xE2A4, 0x641C, 0xE2A5, 0x6536, 0xE2A6, 0x6578, 0xE2A7, 0x6A39, 0xE2A8, 0x6B8A, 0xE2A9, 0x6C34, 0xE2AA, 0x6D19, 0xE2AB, 0x6F31, 0xE2AC, 0x71E7, 0xE2AD, 0x72E9, 0xE2AE, 0x7378, 0xE2AF, 0x7407, 0xE2B0, 0x74B2, 0xE2B1, 0x7626, 0xE2B2, 0x7761, 0xE2B3, 0x79C0, 0xE2B4, 0x7A57, 0xE2B5, 0x7AEA, 0xE2B6, 0x7CB9, 0xE2B7, 0x7D8F, 0xE2B8, 0x7DAC, 0xE2B9, 0x7E61, 0xE2BA, 0x7F9E, 0xE2BB, 0x8129, 0xE2BC, 0x8331, 0xE2BD, 0x8490, 0xE2BE, 0x84DA, 0xE2BF, 0x85EA, 0xE2C0, 0x8896, 0xE2C1, 0x8AB0, 0xE2C2, 0x8B90, 0xE2C3, 0x8F38, 0xE2C4, 0x9042, 0xE2C5, 0x9083, 0xE2C6, 0x916C, 0xE2C7, 0x9296, 0xE2C8, 0x92B9, 0xE2C9, 0x968B, 0xE2CA, 0x96A7, 0xE2CB, 0x96A8, 0xE2CC, 0x96D6, 0xE2CD, 0x9700, 0xE2CE, 0x9808, 0xE2CF, 0x9996, 0xE2D0, 0x9AD3, 0xE2D1, 0x9B1A, 0xE2D2, 0x53D4, 0xE2D3, 0x587E, 0xE2D4, 0x5919, 0xE2D5, 0x5B70, 0xE2D6, 0x5BBF, 0xE2D7, 0x6DD1, 0xE2D8, 0x6F5A, 0xE2D9, 0x719F, 0xE2DA, 0x7421, 0xE2DB, 0x74B9, 0xE2DC, 0x8085, 0xE2DD, 0x83FD, 0xE2DE, 0x5DE1, 0xE2DF, 0x5F87, 0xE2E0, 0x5FAA, 0xE2E1, 0x6042, 0xE2E2, 0x65EC, 0xE2E3, 0x6812, 0xE2E4, 0x696F, 0xE2E5, 0x6A53, 0xE2E6, 0x6B89, 0xE2E7, 0x6D35, 0xE2E8, 0x6DF3, 0xE2E9, 0x73E3, 0xE2EA, 0x76FE, 0xE2EB, 0x77AC, 0xE2EC, 0x7B4D, 0xE2ED, 0x7D14, 0xE2EE, 0x8123, 0xE2EF, 0x821C, 0xE2F0, 0x8340, 0xE2F1, 0x84F4, 0xE2F2, 0x8563, 0xE2F3, 0x8A62, 0xE2F4, 0x8AC4, 0xE2F5, 0x9187, 0xE2F6, 0x931E, 0xE2F7, 0x9806, 0xE2F8, 0x99B4, 0xE2F9, 0x620C, 0xE2FA, 0x8853, 0xE2FB, 0x8FF0, 0xE2FC, 0x9265, 0xE2FD, 0x5D07, 0xE2FE, 0x5D27, 0xE3A1, 0x5D69, 0xE3A2, 0x745F, 0xE3A3, 0x819D, 0xE3A4, 0x8768, 0xE3A5, 0x6FD5, 0xE3A6, 0x62FE, 0xE3A7, 0x7FD2, 0xE3A8, 0x8936, 0xE3A9, 0x8972, 0xE3AA, 0x4E1E, 0xE3AB, 0x4E58, 0xE3AC, 0x50E7, 0xE3AD, 0x52DD, 0xE3AE, 0x5347, 0xE3AF, 0x627F, 0xE3B0, 0x6607, 0xE3B1, 0x7E69, 0xE3B2, 0x8805, 0xE3B3, 0x965E, 0xE3B4, 0x4F8D, 0xE3B5, 0x5319, 0xE3B6, 0x5636, 0xE3B7, 0x59CB, 0xE3B8, 0x5AA4, 0xE3B9, 0x5C38, 0xE3BA, 0x5C4E, 0xE3BB, 0x5C4D, 0xE3BC, 0x5E02, 0xE3BD, 0x5F11, 0xE3BE, 0x6043, 0xE3BF, 0x65BD, 0xE3C0, 0x662F, 0xE3C1, 0x6642, 0xE3C2, 0x67BE, 0xE3C3, 0x67F4, 0xE3C4, 0x731C, 0xE3C5, 0x77E2, 0xE3C6, 0x793A, 0xE3C7, 0x7FC5, 0xE3C8, 0x8494, 0xE3C9, 0x84CD, 0xE3CA, 0x8996, 0xE3CB, 0x8A66, 0xE3CC, 0x8A69, 0xE3CD, 0x8AE1, 0xE3CE, 0x8C55, 0xE3CF, 0x8C7A, 0xE3D0, 0x57F4, 0xE3D1, 0x5BD4, 0xE3D2, 0x5F0F, 0xE3D3, 0x606F, 0xE3D4, 0x62ED, 0xE3D5, 0x690D, 0xE3D6, 0x6B96, 0xE3D7, 0x6E5C, 0xE3D8, 0x7184, 0xE3D9, 0x7BD2, 0xE3DA, 0x8755, 0xE3DB, 0x8B58, 0xE3DC, 0x8EFE, 0xE3DD, 0x98DF, 0xE3DE, 0x98FE, 0xE3DF, 0x4F38, 0xE3E0, 0x4F81, 0xE3E1, 0x4FE1, 0xE3E2, 0x547B, 0xE3E3, 0x5A20, 0xE3E4, 0x5BB8, 0xE3E5, 0x613C, 0xE3E6, 0x65B0, 0xE3E7, 0x6668, 0xE3E8, 0x71FC, 0xE3E9, 0x7533, 0xE3EA, 0x795E, 0xE3EB, 0x7D33, 0xE3EC, 0x814E, 0xE3ED, 0x81E3, 0xE3EE, 0x8398, 0xE3EF, 0x85AA, 0xE3F0, 0x85CE, 0xE3F1, 0x8703, 0xE3F2, 0x8A0A, 0xE3F3, 0x8EAB, 0xE3F4, 0x8F9B, 0xE3F5, 0xF971, 0xE3F6, 0x8FC5, 0xE3F7, 0x5931, 0xE3F8, 0x5BA4, 0xE3F9, 0x5BE6, 0xE3FA, 0x6089, 0xE3FB, 0x5BE9, 0xE3FC, 0x5C0B, 0xE3FD, 0x5FC3, 0xE3FE, 0x6C81, 0xE4A1, 0xF972, 0xE4A2, 0x6DF1, 0xE4A3, 0x700B, 0xE4A4, 0x751A, 0xE4A5, 0x82AF, 0xE4A6, 0x8AF6, 0xE4A7, 0x4EC0, 0xE4A8, 0x5341, 0xE4A9, 0xF973, 0xE4AA, 0x96D9, 0xE4AB, 0x6C0F, 0xE4AC, 0x4E9E, 0xE4AD, 0x4FC4, 0xE4AE, 0x5152, 0xE4AF, 0x555E, 0xE4B0, 0x5A25, 0xE4B1, 0x5CE8, 0xE4B2, 0x6211, 0xE4B3, 0x7259, 0xE4B4, 0x82BD, 0xE4B5, 0x83AA, 0xE4B6, 0x86FE, 0xE4B7, 0x8859, 0xE4B8, 0x8A1D, 0xE4B9, 0x963F, 0xE4BA, 0x96C5, 0xE4BB, 0x9913, 0xE4BC, 0x9D09, 0xE4BD, 0x9D5D, 0xE4BE, 0x580A, 0xE4BF, 0x5CB3, 0xE4C0, 0x5DBD, 0xE4C1, 0x5E44, 0xE4C2, 0x60E1, 0xE4C3, 0x6115, 0xE4C4, 0x63E1, 0xE4C5, 0x6A02, 0xE4C6, 0x6E25, 0xE4C7, 0x9102, 0xE4C8, 0x9354, 0xE4C9, 0x984E, 0xE4CA, 0x9C10, 0xE4CB, 0x9F77, 0xE4CC, 0x5B89, 0xE4CD, 0x5CB8, 0xE4CE, 0x6309, 0xE4CF, 0x664F, 0xE4D0, 0x6848, 0xE4D1, 0x773C, 0xE4D2, 0x96C1, 0xE4D3, 0x978D, 0xE4D4, 0x9854, 0xE4D5, 0x9B9F, 0xE4D6, 0x65A1, 0xE4D7, 0x8B01, 0xE4D8, 0x8ECB, 0xE4D9, 0x95BC, 0xE4DA, 0x5535, 0xE4DB, 0x5CA9, 0xE4DC, 0x5DD6, 0xE4DD, 0x5EB5, 0xE4DE, 0x6697, 0xE4DF, 0x764C, 0xE4E0, 0x83F4, 0xE4E1, 0x95C7, 0xE4E2, 0x58D3, 0xE4E3, 0x62BC, 0xE4E4, 0x72CE, 0xE4E5, 0x9D28, 0xE4E6, 0x4EF0, 0xE4E7, 0x592E, 0xE4E8, 0x600F, 0xE4E9, 0x663B, 0xE4EA, 0x6B83, 0xE4EB, 0x79E7, 0xE4EC, 0x9D26, 0xE4ED, 0x5393, 0xE4EE, 0x54C0, 0xE4EF, 0x57C3, 0xE4F0, 0x5D16, 0xE4F1, 0x611B, 0xE4F2, 0x66D6, 0xE4F3, 0x6DAF, 0xE4F4, 0x788D, 0xE4F5, 0x827E, 0xE4F6, 0x9698, 0xE4F7, 0x9744, 0xE4F8, 0x5384, 0xE4F9, 0x627C, 0xE4FA, 0x6396, 0xE4FB, 0x6DB2, 0xE4FC, 0x7E0A, 0xE4FD, 0x814B, 0xE4FE, 0x984D, 0xE5A1, 0x6AFB, 0xE5A2, 0x7F4C, 0xE5A3, 0x9DAF, 0xE5A4, 0x9E1A, 0xE5A5, 0x4E5F, 0xE5A6, 0x503B, 0xE5A7, 0x51B6, 0xE5A8, 0x591C, 0xE5A9, 0x60F9, 0xE5AA, 0x63F6, 0xE5AB, 0x6930, 0xE5AC, 0x723A, 0xE5AD, 0x8036, 0xE5AE, 0xF974, 0xE5AF, 0x91CE, 0xE5B0, 0x5F31, 0xE5B1, 0xF975, 0xE5B2, 0xF976, 0xE5B3, 0x7D04, 0xE5B4, 0x82E5, 0xE5B5, 0x846F, 0xE5B6, 0x84BB, 0xE5B7, 0x85E5, 0xE5B8, 0x8E8D, 0xE5B9, 0xF977, 0xE5BA, 0x4F6F, 0xE5BB, 0xF978, 0xE5BC, 0xF979, 0xE5BD, 0x58E4, 0xE5BE, 0x5B43, 0xE5BF, 0x6059, 0xE5C0, 0x63DA, 0xE5C1, 0x6518, 0xE5C2, 0x656D, 0xE5C3, 0x6698, 0xE5C4, 0xF97A, 0xE5C5, 0x694A, 0xE5C6, 0x6A23, 0xE5C7, 0x6D0B, 0xE5C8, 0x7001, 0xE5C9, 0x716C, 0xE5CA, 0x75D2, 0xE5CB, 0x760D, 0xE5CC, 0x79B3, 0xE5CD, 0x7A70, 0xE5CE, 0xF97B, 0xE5CF, 0x7F8A, 0xE5D0, 0xF97C, 0xE5D1, 0x8944, 0xE5D2, 0xF97D, 0xE5D3, 0x8B93, 0xE5D4, 0x91C0, 0xE5D5, 0x967D, 0xE5D6, 0xF97E, 0xE5D7, 0x990A, 0xE5D8, 0x5704, 0xE5D9, 0x5FA1, 0xE5DA, 0x65BC, 0xE5DB, 0x6F01, 0xE5DC, 0x7600, 0xE5DD, 0x79A6, 0xE5DE, 0x8A9E, 0xE5DF, 0x99AD, 0xE5E0, 0x9B5A, 0xE5E1, 0x9F6C, 0xE5E2, 0x5104, 0xE5E3, 0x61B6, 0xE5E4, 0x6291, 0xE5E5, 0x6A8D, 0xE5E6, 0x81C6, 0xE5E7, 0x5043, 0xE5E8, 0x5830, 0xE5E9, 0x5F66, 0xE5EA, 0x7109, 0xE5EB, 0x8A00, 0xE5EC, 0x8AFA, 0xE5ED, 0x5B7C, 0xE5EE, 0x8616, 0xE5EF, 0x4FFA, 0xE5F0, 0x513C, 0xE5F1, 0x56B4, 0xE5F2, 0x5944, 0xE5F3, 0x63A9, 0xE5F4, 0x6DF9, 0xE5F5, 0x5DAA, 0xE5F6, 0x696D, 0xE5F7, 0x5186, 0xE5F8, 0x4E88, 0xE5F9, 0x4F59, 0xE5FA, 0xF97F, 0xE5FB, 0xF980, 0xE5FC, 0xF981, 0xE5FD, 0x5982, 0xE5FE, 0xF982, 0xE6A1, 0xF983, 0xE6A2, 0x6B5F, 0xE6A3, 0x6C5D, 0xE6A4, 0xF984, 0xE6A5, 0x74B5, 0xE6A6, 0x7916, 0xE6A7, 0xF985, 0xE6A8, 0x8207, 0xE6A9, 0x8245, 0xE6AA, 0x8339, 0xE6AB, 0x8F3F, 0xE6AC, 0x8F5D, 0xE6AD, 0xF986, 0xE6AE, 0x9918, 0xE6AF, 0xF987, 0xE6B0, 0xF988, 0xE6B1, 0xF989, 0xE6B2, 0x4EA6, 0xE6B3, 0xF98A, 0xE6B4, 0x57DF, 0xE6B5, 0x5F79, 0xE6B6, 0x6613, 0xE6B7, 0xF98B, 0xE6B8, 0xF98C, 0xE6B9, 0x75AB, 0xE6BA, 0x7E79, 0xE6BB, 0x8B6F, 0xE6BC, 0xF98D, 0xE6BD, 0x9006, 0xE6BE, 0x9A5B, 0xE6BF, 0x56A5, 0xE6C0, 0x5827, 0xE6C1, 0x59F8, 0xE6C2, 0x5A1F, 0xE6C3, 0x5BB4, 0xE6C4, 0xF98E, 0xE6C5, 0x5EF6, 0xE6C6, 0xF98F, 0xE6C7, 0xF990, 0xE6C8, 0x6350, 0xE6C9, 0x633B, 0xE6CA, 0xF991, 0xE6CB, 0x693D, 0xE6CC, 0x6C87, 0xE6CD, 0x6CBF, 0xE6CE, 0x6D8E, 0xE6CF, 0x6D93, 0xE6D0, 0x6DF5, 0xE6D1, 0x6F14, 0xE6D2, 0xF992, 0xE6D3, 0x70DF, 0xE6D4, 0x7136, 0xE6D5, 0x7159, 0xE6D6, 0xF993, 0xE6D7, 0x71C3, 0xE6D8, 0x71D5, 0xE6D9, 0xF994, 0xE6DA, 0x784F, 0xE6DB, 0x786F, 0xE6DC, 0xF995, 0xE6DD, 0x7B75, 0xE6DE, 0x7DE3, 0xE6DF, 0xF996, 0xE6E0, 0x7E2F, 0xE6E1, 0xF997, 0xE6E2, 0x884D, 0xE6E3, 0x8EDF, 0xE6E4, 0xF998, 0xE6E5, 0xF999, 0xE6E6, 0xF99A, 0xE6E7, 0x925B, 0xE6E8, 0xF99B, 0xE6E9, 0x9CF6, 0xE6EA, 0xF99C, 0xE6EB, 0xF99D, 0xE6EC, 0xF99E, 0xE6ED, 0x6085, 0xE6EE, 0x6D85, 0xE6EF, 0xF99F, 0xE6F0, 0x71B1, 0xE6F1, 0xF9A0, 0xE6F2, 0xF9A1, 0xE6F3, 0x95B1, 0xE6F4, 0x53AD, 0xE6F5, 0xF9A2, 0xE6F6, 0xF9A3, 0xE6F7, 0xF9A4, 0xE6F8, 0x67D3, 0xE6F9, 0xF9A5, 0xE6FA, 0x708E, 0xE6FB, 0x7130, 0xE6FC, 0x7430, 0xE6FD, 0x8276, 0xE6FE, 0x82D2, 0xE7A1, 0xF9A6, 0xE7A2, 0x95BB, 0xE7A3, 0x9AE5, 0xE7A4, 0x9E7D, 0xE7A5, 0x66C4, 0xE7A6, 0xF9A7, 0xE7A7, 0x71C1, 0xE7A8, 0x8449, 0xE7A9, 0xF9A8, 0xE7AA, 0xF9A9, 0xE7AB, 0x584B, 0xE7AC, 0xF9AA, 0xE7AD, 0xF9AB, 0xE7AE, 0x5DB8, 0xE7AF, 0x5F71, 0xE7B0, 0xF9AC, 0xE7B1, 0x6620, 0xE7B2, 0x668E, 0xE7B3, 0x6979, 0xE7B4, 0x69AE, 0xE7B5, 0x6C38, 0xE7B6, 0x6CF3, 0xE7B7, 0x6E36, 0xE7B8, 0x6F41, 0xE7B9, 0x6FDA, 0xE7BA, 0x701B, 0xE7BB, 0x702F, 0xE7BC, 0x7150, 0xE7BD, 0x71DF, 0xE7BE, 0x7370, 0xE7BF, 0xF9AD, 0xE7C0, 0x745B, 0xE7C1, 0xF9AE, 0xE7C2, 0x74D4, 0xE7C3, 0x76C8, 0xE7C4, 0x7A4E, 0xE7C5, 0x7E93, 0xE7C6, 0xF9AF, 0xE7C7, 0xF9B0, 0xE7C8, 0x82F1, 0xE7C9, 0x8A60, 0xE7CA, 0x8FCE, 0xE7CB, 0xF9B1, 0xE7CC, 0x9348, 0xE7CD, 0xF9B2, 0xE7CE, 0x9719, 0xE7CF, 0xF9B3, 0xE7D0, 0xF9B4, 0xE7D1, 0x4E42, 0xE7D2, 0x502A, 0xE7D3, 0xF9B5, 0xE7D4, 0x5208, 0xE7D5, 0x53E1, 0xE7D6, 0x66F3, 0xE7D7, 0x6C6D, 0xE7D8, 0x6FCA, 0xE7D9, 0x730A, 0xE7DA, 0x777F, 0xE7DB, 0x7A62, 0xE7DC, 0x82AE, 0xE7DD, 0x85DD, 0xE7DE, 0x8602, 0xE7DF, 0xF9B6, 0xE7E0, 0x88D4, 0xE7E1, 0x8A63, 0xE7E2, 0x8B7D, 0xE7E3, 0x8C6B, 0xE7E4, 0xF9B7, 0xE7E5, 0x92B3, 0xE7E6, 0xF9B8, 0xE7E7, 0x9713, 0xE7E8, 0x9810, 0xE7E9, 0x4E94, 0xE7EA, 0x4F0D, 0xE7EB, 0x4FC9, 0xE7EC, 0x50B2, 0xE7ED, 0x5348, 0xE7EE, 0x543E, 0xE7EF, 0x5433, 0xE7F0, 0x55DA, 0xE7F1, 0x5862, 0xE7F2, 0x58BA, 0xE7F3, 0x5967, 0xE7F4, 0x5A1B, 0xE7F5, 0x5BE4, 0xE7F6, 0x609F, 0xE7F7, 0xF9B9, 0xE7F8, 0x61CA, 0xE7F9, 0x6556, 0xE7FA, 0x65FF, 0xE7FB, 0x6664, 0xE7FC, 0x68A7, 0xE7FD, 0x6C5A, 0xE7FE, 0x6FB3, 0xE8A1, 0x70CF, 0xE8A2, 0x71AC, 0xE8A3, 0x7352, 0xE8A4, 0x7B7D, 0xE8A5, 0x8708, 0xE8A6, 0x8AA4, 0xE8A7, 0x9C32, 0xE8A8, 0x9F07, 0xE8A9, 0x5C4B, 0xE8AA, 0x6C83, 0xE8AB, 0x7344, 0xE8AC, 0x7389, 0xE8AD, 0x923A, 0xE8AE, 0x6EAB, 0xE8AF, 0x7465, 0xE8B0, 0x761F, 0xE8B1, 0x7A69, 0xE8B2, 0x7E15, 0xE8B3, 0x860A, 0xE8B4, 0x5140, 0xE8B5, 0x58C5, 0xE8B6, 0x64C1, 0xE8B7, 0x74EE, 0xE8B8, 0x7515, 0xE8B9, 0x7670, 0xE8BA, 0x7FC1, 0xE8BB, 0x9095, 0xE8BC, 0x96CD, 0xE8BD, 0x9954, 0xE8BE, 0x6E26, 0xE8BF, 0x74E6, 0xE8C0, 0x7AA9, 0xE8C1, 0x7AAA, 0xE8C2, 0x81E5, 0xE8C3, 0x86D9, 0xE8C4, 0x8778, 0xE8C5, 0x8A1B, 0xE8C6, 0x5A49, 0xE8C7, 0x5B8C, 0xE8C8, 0x5B9B, 0xE8C9, 0x68A1, 0xE8CA, 0x6900, 0xE8CB, 0x6D63, 0xE8CC, 0x73A9, 0xE8CD, 0x7413, 0xE8CE, 0x742C, 0xE8CF, 0x7897, 0xE8D0, 0x7DE9, 0xE8D1, 0x7FEB, 0xE8D2, 0x8118, 0xE8D3, 0x8155, 0xE8D4, 0x839E, 0xE8D5, 0x8C4C, 0xE8D6, 0x962E, 0xE8D7, 0x9811, 0xE8D8, 0x66F0, 0xE8D9, 0x5F80, 0xE8DA, 0x65FA, 0xE8DB, 0x6789, 0xE8DC, 0x6C6A, 0xE8DD, 0x738B, 0xE8DE, 0x502D, 0xE8DF, 0x5A03, 0xE8E0, 0x6B6A, 0xE8E1, 0x77EE, 0xE8E2, 0x5916, 0xE8E3, 0x5D6C, 0xE8E4, 0x5DCD, 0xE8E5, 0x7325, 0xE8E6, 0x754F, 0xE8E7, 0xF9BA, 0xE8E8, 0xF9BB, 0xE8E9, 0x50E5, 0xE8EA, 0x51F9, 0xE8EB, 0x582F, 0xE8EC, 0x592D, 0xE8ED, 0x5996, 0xE8EE, 0x59DA, 0xE8EF, 0x5BE5, 0xE8F0, 0xF9BC, 0xE8F1, 0xF9BD, 0xE8F2, 0x5DA2, 0xE8F3, 0x62D7, 0xE8F4, 0x6416, 0xE8F5, 0x6493, 0xE8F6, 0x64FE, 0xE8F7, 0xF9BE, 0xE8F8, 0x66DC, 0xE8F9, 0xF9BF, 0xE8FA, 0x6A48, 0xE8FB, 0xF9C0, 0xE8FC, 0x71FF, 0xE8FD, 0x7464, 0xE8FE, 0xF9C1, 0xE9A1, 0x7A88, 0xE9A2, 0x7AAF, 0xE9A3, 0x7E47, 0xE9A4, 0x7E5E, 0xE9A5, 0x8000, 0xE9A6, 0x8170, 0xE9A7, 0xF9C2, 0xE9A8, 0x87EF, 0xE9A9, 0x8981, 0xE9AA, 0x8B20, 0xE9AB, 0x9059, 0xE9AC, 0xF9C3, 0xE9AD, 0x9080, 0xE9AE, 0x9952, 0xE9AF, 0x617E, 0xE9B0, 0x6B32, 0xE9B1, 0x6D74, 0xE9B2, 0x7E1F, 0xE9B3, 0x8925, 0xE9B4, 0x8FB1, 0xE9B5, 0x4FD1, 0xE9B6, 0x50AD, 0xE9B7, 0x5197, 0xE9B8, 0x52C7, 0xE9B9, 0x57C7, 0xE9BA, 0x5889, 0xE9BB, 0x5BB9, 0xE9BC, 0x5EB8, 0xE9BD, 0x6142, 0xE9BE, 0x6995, 0xE9BF, 0x6D8C, 0xE9C0, 0x6E67, 0xE9C1, 0x6EB6, 0xE9C2, 0x7194, 0xE9C3, 0x7462, 0xE9C4, 0x7528, 0xE9C5, 0x752C, 0xE9C6, 0x8073, 0xE9C7, 0x8338, 0xE9C8, 0x84C9, 0xE9C9, 0x8E0A, 0xE9CA, 0x9394, 0xE9CB, 0x93DE, 0xE9CC, 0xF9C4, 0xE9CD, 0x4E8E, 0xE9CE, 0x4F51, 0xE9CF, 0x5076, 0xE9D0, 0x512A, 0xE9D1, 0x53C8, 0xE9D2, 0x53CB, 0xE9D3, 0x53F3, 0xE9D4, 0x5B87, 0xE9D5, 0x5BD3, 0xE9D6, 0x5C24, 0xE9D7, 0x611A, 0xE9D8, 0x6182, 0xE9D9, 0x65F4, 0xE9DA, 0x725B, 0xE9DB, 0x7397, 0xE9DC, 0x7440, 0xE9DD, 0x76C2, 0xE9DE, 0x7950, 0xE9DF, 0x7991, 0xE9E0, 0x79B9, 0xE9E1, 0x7D06, 0xE9E2, 0x7FBD, 0xE9E3, 0x828B, 0xE9E4, 0x85D5, 0xE9E5, 0x865E, 0xE9E6, 0x8FC2, 0xE9E7, 0x9047, 0xE9E8, 0x90F5, 0xE9E9, 0x91EA, 0xE9EA, 0x9685, 0xE9EB, 0x96E8, 0xE9EC, 0x96E9, 0xE9ED, 0x52D6, 0xE9EE, 0x5F67, 0xE9EF, 0x65ED, 0xE9F0, 0x6631, 0xE9F1, 0x682F, 0xE9F2, 0x715C, 0xE9F3, 0x7A36, 0xE9F4, 0x90C1, 0xE9F5, 0x980A, 0xE9F6, 0x4E91, 0xE9F7, 0xF9C5, 0xE9F8, 0x6A52, 0xE9F9, 0x6B9E, 0xE9FA, 0x6F90, 0xE9FB, 0x7189, 0xE9FC, 0x8018, 0xE9FD, 0x82B8, 0xE9FE, 0x8553, 0xEAA1, 0x904B, 0xEAA2, 0x9695, 0xEAA3, 0x96F2, 0xEAA4, 0x97FB, 0xEAA5, 0x851A, 0xEAA6, 0x9B31, 0xEAA7, 0x4E90, 0xEAA8, 0x718A, 0xEAA9, 0x96C4, 0xEAAA, 0x5143, 0xEAAB, 0x539F, 0xEAAC, 0x54E1, 0xEAAD, 0x5713, 0xEAAE, 0x5712, 0xEAAF, 0x57A3, 0xEAB0, 0x5A9B, 0xEAB1, 0x5AC4, 0xEAB2, 0x5BC3, 0xEAB3, 0x6028, 0xEAB4, 0x613F, 0xEAB5, 0x63F4, 0xEAB6, 0x6C85, 0xEAB7, 0x6D39, 0xEAB8, 0x6E72, 0xEAB9, 0x6E90, 0xEABA, 0x7230, 0xEABB, 0x733F, 0xEABC, 0x7457, 0xEABD, 0x82D1, 0xEABE, 0x8881, 0xEABF, 0x8F45, 0xEAC0, 0x9060, 0xEAC1, 0xF9C6, 0xEAC2, 0x9662, 0xEAC3, 0x9858, 0xEAC4, 0x9D1B, 0xEAC5, 0x6708, 0xEAC6, 0x8D8A, 0xEAC7, 0x925E, 0xEAC8, 0x4F4D, 0xEAC9, 0x5049, 0xEACA, 0x50DE, 0xEACB, 0x5371, 0xEACC, 0x570D, 0xEACD, 0x59D4, 0xEACE, 0x5A01, 0xEACF, 0x5C09, 0xEAD0, 0x6170, 0xEAD1, 0x6690, 0xEAD2, 0x6E2D, 0xEAD3, 0x7232, 0xEAD4, 0x744B, 0xEAD5, 0x7DEF, 0xEAD6, 0x80C3, 0xEAD7, 0x840E, 0xEAD8, 0x8466, 0xEAD9, 0x853F, 0xEADA, 0x875F, 0xEADB, 0x885B, 0xEADC, 0x8918, 0xEADD, 0x8B02, 0xEADE, 0x9055, 0xEADF, 0x97CB, 0xEAE0, 0x9B4F, 0xEAE1, 0x4E73, 0xEAE2, 0x4F91, 0xEAE3, 0x5112, 0xEAE4, 0x516A, 0xEAE5, 0xF9C7, 0xEAE6, 0x552F, 0xEAE7, 0x55A9, 0xEAE8, 0x5B7A, 0xEAE9, 0x5BA5, 0xEAEA, 0x5E7C, 0xEAEB, 0x5E7D, 0xEAEC, 0x5EBE, 0xEAED, 0x60A0, 0xEAEE, 0x60DF, 0xEAEF, 0x6108, 0xEAF0, 0x6109, 0xEAF1, 0x63C4, 0xEAF2, 0x6538, 0xEAF3, 0x6709, 0xEAF4, 0xF9C8, 0xEAF5, 0x67D4, 0xEAF6, 0x67DA, 0xEAF7, 0xF9C9, 0xEAF8, 0x6961, 0xEAF9, 0x6962, 0xEAFA, 0x6CB9, 0xEAFB, 0x6D27, 0xEAFC, 0xF9CA, 0xEAFD, 0x6E38, 0xEAFE, 0xF9CB, 0xEBA1, 0x6FE1, 0xEBA2, 0x7336, 0xEBA3, 0x7337, 0xEBA4, 0xF9CC, 0xEBA5, 0x745C, 0xEBA6, 0x7531, 0xEBA7, 0xF9CD, 0xEBA8, 0x7652, 0xEBA9, 0xF9CE, 0xEBAA, 0xF9CF, 0xEBAB, 0x7DAD, 0xEBAC, 0x81FE, 0xEBAD, 0x8438, 0xEBAE, 0x88D5, 0xEBAF, 0x8A98, 0xEBB0, 0x8ADB, 0xEBB1, 0x8AED, 0xEBB2, 0x8E30, 0xEBB3, 0x8E42, 0xEBB4, 0x904A, 0xEBB5, 0x903E, 0xEBB6, 0x907A, 0xEBB7, 0x9149, 0xEBB8, 0x91C9, 0xEBB9, 0x936E, 0xEBBA, 0xF9D0, 0xEBBB, 0xF9D1, 0xEBBC, 0x5809, 0xEBBD, 0xF9D2, 0xEBBE, 0x6BD3, 0xEBBF, 0x8089, 0xEBC0, 0x80B2, 0xEBC1, 0xF9D3, 0xEBC2, 0xF9D4, 0xEBC3, 0x5141, 0xEBC4, 0x596B, 0xEBC5, 0x5C39, 0xEBC6, 0xF9D5, 0xEBC7, 0xF9D6, 0xEBC8, 0x6F64, 0xEBC9, 0x73A7, 0xEBCA, 0x80E4, 0xEBCB, 0x8D07, 0xEBCC, 0xF9D7, 0xEBCD, 0x9217, 0xEBCE, 0x958F, 0xEBCF, 0xF9D8, 0xEBD0, 0xF9D9, 0xEBD1, 0xF9DA, 0xEBD2, 0xF9DB, 0xEBD3, 0x807F, 0xEBD4, 0x620E, 0xEBD5, 0x701C, 0xEBD6, 0x7D68, 0xEBD7, 0x878D, 0xEBD8, 0xF9DC, 0xEBD9, 0x57A0, 0xEBDA, 0x6069, 0xEBDB, 0x6147, 0xEBDC, 0x6BB7, 0xEBDD, 0x8ABE, 0xEBDE, 0x9280, 0xEBDF, 0x96B1, 0xEBE0, 0x4E59, 0xEBE1, 0x541F, 0xEBE2, 0x6DEB, 0xEBE3, 0x852D, 0xEBE4, 0x9670, 0xEBE5, 0x97F3, 0xEBE6, 0x98EE, 0xEBE7, 0x63D6, 0xEBE8, 0x6CE3, 0xEBE9, 0x9091, 0xEBEA, 0x51DD, 0xEBEB, 0x61C9, 0xEBEC, 0x81BA, 0xEBED, 0x9DF9, 0xEBEE, 0x4F9D, 0xEBEF, 0x501A, 0xEBF0, 0x5100, 0xEBF1, 0x5B9C, 0xEBF2, 0x610F, 0xEBF3, 0x61FF, 0xEBF4, 0x64EC, 0xEBF5, 0x6905, 0xEBF6, 0x6BC5, 0xEBF7, 0x7591, 0xEBF8, 0x77E3, 0xEBF9, 0x7FA9, 0xEBFA, 0x8264, 0xEBFB, 0x858F, 0xEBFC, 0x87FB, 0xEBFD, 0x8863, 0xEBFE, 0x8ABC, 0xECA1, 0x8B70, 0xECA2, 0x91AB, 0xECA3, 0x4E8C, 0xECA4, 0x4EE5, 0xECA5, 0x4F0A, 0xECA6, 0xF9DD, 0xECA7, 0xF9DE, 0xECA8, 0x5937, 0xECA9, 0x59E8, 0xECAA, 0xF9DF, 0xECAB, 0x5DF2, 0xECAC, 0x5F1B, 0xECAD, 0x5F5B, 0xECAE, 0x6021, 0xECAF, 0xF9E0, 0xECB0, 0xF9E1, 0xECB1, 0xF9E2, 0xECB2, 0xF9E3, 0xECB3, 0x723E, 0xECB4, 0x73E5, 0xECB5, 0xF9E4, 0xECB6, 0x7570, 0xECB7, 0x75CD, 0xECB8, 0xF9E5, 0xECB9, 0x79FB, 0xECBA, 0xF9E6, 0xECBB, 0x800C, 0xECBC, 0x8033, 0xECBD, 0x8084, 0xECBE, 0x82E1, 0xECBF, 0x8351, 0xECC0, 0xF9E7, 0xECC1, 0xF9E8, 0xECC2, 0x8CBD, 0xECC3, 0x8CB3, 0xECC4, 0x9087, 0xECC5, 0xF9E9, 0xECC6, 0xF9EA, 0xECC7, 0x98F4, 0xECC8, 0x990C, 0xECC9, 0xF9EB, 0xECCA, 0xF9EC, 0xECCB, 0x7037, 0xECCC, 0x76CA, 0xECCD, 0x7FCA, 0xECCE, 0x7FCC, 0xECCF, 0x7FFC, 0xECD0, 0x8B1A, 0xECD1, 0x4EBA, 0xECD2, 0x4EC1, 0xECD3, 0x5203, 0xECD4, 0x5370, 0xECD5, 0xF9ED, 0xECD6, 0x54BD, 0xECD7, 0x56E0, 0xECD8, 0x59FB, 0xECD9, 0x5BC5, 0xECDA, 0x5F15, 0xECDB, 0x5FCD, 0xECDC, 0x6E6E, 0xECDD, 0xF9EE, 0xECDE, 0xF9EF, 0xECDF, 0x7D6A, 0xECE0, 0x8335, 0xECE1, 0xF9F0, 0xECE2, 0x8693, 0xECE3, 0x8A8D, 0xECE4, 0xF9F1, 0xECE5, 0x976D, 0xECE6, 0x9777, 0xECE7, 0xF9F2, 0xECE8, 0xF9F3, 0xECE9, 0x4E00, 0xECEA, 0x4F5A, 0xECEB, 0x4F7E, 0xECEC, 0x58F9, 0xECED, 0x65E5, 0xECEE, 0x6EA2, 0xECEF, 0x9038, 0xECF0, 0x93B0, 0xECF1, 0x99B9, 0xECF2, 0x4EFB, 0xECF3, 0x58EC, 0xECF4, 0x598A, 0xECF5, 0x59D9, 0xECF6, 0x6041, 0xECF7, 0xF9F4, 0xECF8, 0xF9F5, 0xECF9, 0x7A14, 0xECFA, 0xF9F6, 0xECFB, 0x834F, 0xECFC, 0x8CC3, 0xECFD, 0x5165, 0xECFE, 0x5344, 0xEDA1, 0xF9F7, 0xEDA2, 0xF9F8, 0xEDA3, 0xF9F9, 0xEDA4, 0x4ECD, 0xEDA5, 0x5269, 0xEDA6, 0x5B55, 0xEDA7, 0x82BF, 0xEDA8, 0x4ED4, 0xEDA9, 0x523A, 0xEDAA, 0x54A8, 0xEDAB, 0x59C9, 0xEDAC, 0x59FF, 0xEDAD, 0x5B50, 0xEDAE, 0x5B57, 0xEDAF, 0x5B5C, 0xEDB0, 0x6063, 0xEDB1, 0x6148, 0xEDB2, 0x6ECB, 0xEDB3, 0x7099, 0xEDB4, 0x716E, 0xEDB5, 0x7386, 0xEDB6, 0x74F7, 0xEDB7, 0x75B5, 0xEDB8, 0x78C1, 0xEDB9, 0x7D2B, 0xEDBA, 0x8005, 0xEDBB, 0x81EA, 0xEDBC, 0x8328, 0xEDBD, 0x8517, 0xEDBE, 0x85C9, 0xEDBF, 0x8AEE, 0xEDC0, 0x8CC7, 0xEDC1, 0x96CC, 0xEDC2, 0x4F5C, 0xEDC3, 0x52FA, 0xEDC4, 0x56BC, 0xEDC5, 0x65AB, 0xEDC6, 0x6628, 0xEDC7, 0x707C, 0xEDC8, 0x70B8, 0xEDC9, 0x7235, 0xEDCA, 0x7DBD, 0xEDCB, 0x828D, 0xEDCC, 0x914C, 0xEDCD, 0x96C0, 0xEDCE, 0x9D72, 0xEDCF, 0x5B71, 0xEDD0, 0x68E7, 0xEDD1, 0x6B98, 0xEDD2, 0x6F7A, 0xEDD3, 0x76DE, 0xEDD4, 0x5C91, 0xEDD5, 0x66AB, 0xEDD6, 0x6F5B, 0xEDD7, 0x7BB4, 0xEDD8, 0x7C2A, 0xEDD9, 0x8836, 0xEDDA, 0x96DC, 0xEDDB, 0x4E08, 0xEDDC, 0x4ED7, 0xEDDD, 0x5320, 0xEDDE, 0x5834, 0xEDDF, 0x58BB, 0xEDE0, 0x58EF, 0xEDE1, 0x596C, 0xEDE2, 0x5C07, 0xEDE3, 0x5E33, 0xEDE4, 0x5E84, 0xEDE5, 0x5F35, 0xEDE6, 0x638C, 0xEDE7, 0x66B2, 0xEDE8, 0x6756, 0xEDE9, 0x6A1F, 0xEDEA, 0x6AA3, 0xEDEB, 0x6B0C, 0xEDEC, 0x6F3F, 0xEDED, 0x7246, 0xEDEE, 0xF9FA, 0xEDEF, 0x7350, 0xEDF0, 0x748B, 0xEDF1, 0x7AE0, 0xEDF2, 0x7CA7, 0xEDF3, 0x8178, 0xEDF4, 0x81DF, 0xEDF5, 0x81E7, 0xEDF6, 0x838A, 0xEDF7, 0x846C, 0xEDF8, 0x8523, 0xEDF9, 0x8594, 0xEDFA, 0x85CF, 0xEDFB, 0x88DD, 0xEDFC, 0x8D13, 0xEDFD, 0x91AC, 0xEDFE, 0x9577, 0xEEA1, 0x969C, 0xEEA2, 0x518D, 0xEEA3, 0x54C9, 0xEEA4, 0x5728, 0xEEA5, 0x5BB0, 0xEEA6, 0x624D, 0xEEA7, 0x6750, 0xEEA8, 0x683D, 0xEEA9, 0x6893, 0xEEAA, 0x6E3D, 0xEEAB, 0x6ED3, 0xEEAC, 0x707D, 0xEEAD, 0x7E21, 0xEEAE, 0x88C1, 0xEEAF, 0x8CA1, 0xEEB0, 0x8F09, 0xEEB1, 0x9F4B, 0xEEB2, 0x9F4E, 0xEEB3, 0x722D, 0xEEB4, 0x7B8F, 0xEEB5, 0x8ACD, 0xEEB6, 0x931A, 0xEEB7, 0x4F47, 0xEEB8, 0x4F4E, 0xEEB9, 0x5132, 0xEEBA, 0x5480, 0xEEBB, 0x59D0, 0xEEBC, 0x5E95, 0xEEBD, 0x62B5, 0xEEBE, 0x6775, 0xEEBF, 0x696E, 0xEEC0, 0x6A17, 0xEEC1, 0x6CAE, 0xEEC2, 0x6E1A, 0xEEC3, 0x72D9, 0xEEC4, 0x732A, 0xEEC5, 0x75BD, 0xEEC6, 0x7BB8, 0xEEC7, 0x7D35, 0xEEC8, 0x82E7, 0xEEC9, 0x83F9, 0xEECA, 0x8457, 0xEECB, 0x85F7, 0xEECC, 0x8A5B, 0xEECD, 0x8CAF, 0xEECE, 0x8E87, 0xEECF, 0x9019, 0xEED0, 0x90B8, 0xEED1, 0x96CE, 0xEED2, 0x9F5F, 0xEED3, 0x52E3, 0xEED4, 0x540A, 0xEED5, 0x5AE1, 0xEED6, 0x5BC2, 0xEED7, 0x6458, 0xEED8, 0x6575, 0xEED9, 0x6EF4, 0xEEDA, 0x72C4, 0xEEDB, 0xF9FB, 0xEEDC, 0x7684, 0xEEDD, 0x7A4D, 0xEEDE, 0x7B1B, 0xEEDF, 0x7C4D, 0xEEE0, 0x7E3E, 0xEEE1, 0x7FDF, 0xEEE2, 0x837B, 0xEEE3, 0x8B2B, 0xEEE4, 0x8CCA, 0xEEE5, 0x8D64, 0xEEE6, 0x8DE1, 0xEEE7, 0x8E5F, 0xEEE8, 0x8FEA, 0xEEE9, 0x8FF9, 0xEEEA, 0x9069, 0xEEEB, 0x93D1, 0xEEEC, 0x4F43, 0xEEED, 0x4F7A, 0xEEEE, 0x50B3, 0xEEEF, 0x5168, 0xEEF0, 0x5178, 0xEEF1, 0x524D, 0xEEF2, 0x526A, 0xEEF3, 0x5861, 0xEEF4, 0x587C, 0xEEF5, 0x5960, 0xEEF6, 0x5C08, 0xEEF7, 0x5C55, 0xEEF8, 0x5EDB, 0xEEF9, 0x609B, 0xEEFA, 0x6230, 0xEEFB, 0x6813, 0xEEFC, 0x6BBF, 0xEEFD, 0x6C08, 0xEEFE, 0x6FB1, 0xEFA1, 0x714E, 0xEFA2, 0x7420, 0xEFA3, 0x7530, 0xEFA4, 0x7538, 0xEFA5, 0x7551, 0xEFA6, 0x7672, 0xEFA7, 0x7B4C, 0xEFA8, 0x7B8B, 0xEFA9, 0x7BAD, 0xEFAA, 0x7BC6, 0xEFAB, 0x7E8F, 0xEFAC, 0x8A6E, 0xEFAD, 0x8F3E, 0xEFAE, 0x8F49, 0xEFAF, 0x923F, 0xEFB0, 0x9293, 0xEFB1, 0x9322, 0xEFB2, 0x942B, 0xEFB3, 0x96FB, 0xEFB4, 0x985A, 0xEFB5, 0x986B, 0xEFB6, 0x991E, 0xEFB7, 0x5207, 0xEFB8, 0x622A, 0xEFB9, 0x6298, 0xEFBA, 0x6D59, 0xEFBB, 0x7664, 0xEFBC, 0x7ACA, 0xEFBD, 0x7BC0, 0xEFBE, 0x7D76, 0xEFBF, 0x5360, 0xEFC0, 0x5CBE, 0xEFC1, 0x5E97, 0xEFC2, 0x6F38, 0xEFC3, 0x70B9, 0xEFC4, 0x7C98, 0xEFC5, 0x9711, 0xEFC6, 0x9B8E, 0xEFC7, 0x9EDE, 0xEFC8, 0x63A5, 0xEFC9, 0x647A, 0xEFCA, 0x8776, 0xEFCB, 0x4E01, 0xEFCC, 0x4E95, 0xEFCD, 0x4EAD, 0xEFCE, 0x505C, 0xEFCF, 0x5075, 0xEFD0, 0x5448, 0xEFD1, 0x59C3, 0xEFD2, 0x5B9A, 0xEFD3, 0x5E40, 0xEFD4, 0x5EAD, 0xEFD5, 0x5EF7, 0xEFD6, 0x5F81, 0xEFD7, 0x60C5, 0xEFD8, 0x633A, 0xEFD9, 0x653F, 0xEFDA, 0x6574, 0xEFDB, 0x65CC, 0xEFDC, 0x6676, 0xEFDD, 0x6678, 0xEFDE, 0x67FE, 0xEFDF, 0x6968, 0xEFE0, 0x6A89, 0xEFE1, 0x6B63, 0xEFE2, 0x6C40, 0xEFE3, 0x6DC0, 0xEFE4, 0x6DE8, 0xEFE5, 0x6E1F, 0xEFE6, 0x6E5E, 0xEFE7, 0x701E, 0xEFE8, 0x70A1, 0xEFE9, 0x738E, 0xEFEA, 0x73FD, 0xEFEB, 0x753A, 0xEFEC, 0x775B, 0xEFED, 0x7887, 0xEFEE, 0x798E, 0xEFEF, 0x7A0B, 0xEFF0, 0x7A7D, 0xEFF1, 0x7CBE, 0xEFF2, 0x7D8E, 0xEFF3, 0x8247, 0xEFF4, 0x8A02, 0xEFF5, 0x8AEA, 0xEFF6, 0x8C9E, 0xEFF7, 0x912D, 0xEFF8, 0x914A, 0xEFF9, 0x91D8, 0xEFFA, 0x9266, 0xEFFB, 0x92CC, 0xEFFC, 0x9320, 0xEFFD, 0x9706, 0xEFFE, 0x9756, 0xF0A1, 0x975C, 0xF0A2, 0x9802, 0xF0A3, 0x9F0E, 0xF0A4, 0x5236, 0xF0A5, 0x5291, 0xF0A6, 0x557C, 0xF0A7, 0x5824, 0xF0A8, 0x5E1D, 0xF0A9, 0x5F1F, 0xF0AA, 0x608C, 0xF0AB, 0x63D0, 0xF0AC, 0x68AF, 0xF0AD, 0x6FDF, 0xF0AE, 0x796D, 0xF0AF, 0x7B2C, 0xF0B0, 0x81CD, 0xF0B1, 0x85BA, 0xF0B2, 0x88FD, 0xF0B3, 0x8AF8, 0xF0B4, 0x8E44, 0xF0B5, 0x918D, 0xF0B6, 0x9664, 0xF0B7, 0x969B, 0xF0B8, 0x973D, 0xF0B9, 0x984C, 0xF0BA, 0x9F4A, 0xF0BB, 0x4FCE, 0xF0BC, 0x5146, 0xF0BD, 0x51CB, 0xF0BE, 0x52A9, 0xF0BF, 0x5632, 0xF0C0, 0x5F14, 0xF0C1, 0x5F6B, 0xF0C2, 0x63AA, 0xF0C3, 0x64CD, 0xF0C4, 0x65E9, 0xF0C5, 0x6641, 0xF0C6, 0x66FA, 0xF0C7, 0x66F9, 0xF0C8, 0x671D, 0xF0C9, 0x689D, 0xF0CA, 0x68D7, 0xF0CB, 0x69FD, 0xF0CC, 0x6F15, 0xF0CD, 0x6F6E, 0xF0CE, 0x7167, 0xF0CF, 0x71E5, 0xF0D0, 0x722A, 0xF0D1, 0x74AA, 0xF0D2, 0x773A, 0xF0D3, 0x7956, 0xF0D4, 0x795A, 0xF0D5, 0x79DF, 0xF0D6, 0x7A20, 0xF0D7, 0x7A95, 0xF0D8, 0x7C97, 0xF0D9, 0x7CDF, 0xF0DA, 0x7D44, 0xF0DB, 0x7E70, 0xF0DC, 0x8087, 0xF0DD, 0x85FB, 0xF0DE, 0x86A4, 0xF0DF, 0x8A54, 0xF0E0, 0x8ABF, 0xF0E1, 0x8D99, 0xF0E2, 0x8E81, 0xF0E3, 0x9020, 0xF0E4, 0x906D, 0xF0E5, 0x91E3, 0xF0E6, 0x963B, 0xF0E7, 0x96D5, 0xF0E8, 0x9CE5, 0xF0E9, 0x65CF, 0xF0EA, 0x7C07, 0xF0EB, 0x8DB3, 0xF0EC, 0x93C3, 0xF0ED, 0x5B58, 0xF0EE, 0x5C0A, 0xF0EF, 0x5352, 0xF0F0, 0x62D9, 0xF0F1, 0x731D, 0xF0F2, 0x5027, 0xF0F3, 0x5B97, 0xF0F4, 0x5F9E, 0xF0F5, 0x60B0, 0xF0F6, 0x616B, 0xF0F7, 0x68D5, 0xF0F8, 0x6DD9, 0xF0F9, 0x742E, 0xF0FA, 0x7A2E, 0xF0FB, 0x7D42, 0xF0FC, 0x7D9C, 0xF0FD, 0x7E31, 0xF0FE, 0x816B, 0xF1A1, 0x8E2A, 0xF1A2, 0x8E35, 0xF1A3, 0x937E, 0xF1A4, 0x9418, 0xF1A5, 0x4F50, 0xF1A6, 0x5750, 0xF1A7, 0x5DE6, 0xF1A8, 0x5EA7, 0xF1A9, 0x632B, 0xF1AA, 0x7F6A, 0xF1AB, 0x4E3B, 0xF1AC, 0x4F4F, 0xF1AD, 0x4F8F, 0xF1AE, 0x505A, 0xF1AF, 0x59DD, 0xF1B0, 0x80C4, 0xF1B1, 0x546A, 0xF1B2, 0x5468, 0xF1B3, 0x55FE, 0xF1B4, 0x594F, 0xF1B5, 0x5B99, 0xF1B6, 0x5DDE, 0xF1B7, 0x5EDA, 0xF1B8, 0x665D, 0xF1B9, 0x6731, 0xF1BA, 0x67F1, 0xF1BB, 0x682A, 0xF1BC, 0x6CE8, 0xF1BD, 0x6D32, 0xF1BE, 0x6E4A, 0xF1BF, 0x6F8D, 0xF1C0, 0x70B7, 0xF1C1, 0x73E0, 0xF1C2, 0x7587, 0xF1C3, 0x7C4C, 0xF1C4, 0x7D02, 0xF1C5, 0x7D2C, 0xF1C6, 0x7DA2, 0xF1C7, 0x821F, 0xF1C8, 0x86DB, 0xF1C9, 0x8A3B, 0xF1CA, 0x8A85, 0xF1CB, 0x8D70, 0xF1CC, 0x8E8A, 0xF1CD, 0x8F33, 0xF1CE, 0x9031, 0xF1CF, 0x914E, 0xF1D0, 0x9152, 0xF1D1, 0x9444, 0xF1D2, 0x99D0, 0xF1D3, 0x7AF9, 0xF1D4, 0x7CA5, 0xF1D5, 0x4FCA, 0xF1D6, 0x5101, 0xF1D7, 0x51C6, 0xF1D8, 0x57C8, 0xF1D9, 0x5BEF, 0xF1DA, 0x5CFB, 0xF1DB, 0x6659, 0xF1DC, 0x6A3D, 0xF1DD, 0x6D5A, 0xF1DE, 0x6E96, 0xF1DF, 0x6FEC, 0xF1E0, 0x710C, 0xF1E1, 0x756F, 0xF1E2, 0x7AE3, 0xF1E3, 0x8822, 0xF1E4, 0x9021, 0xF1E5, 0x9075, 0xF1E6, 0x96CB, 0xF1E7, 0x99FF, 0xF1E8, 0x8301, 0xF1E9, 0x4E2D, 0xF1EA, 0x4EF2, 0xF1EB, 0x8846, 0xF1EC, 0x91CD, 0xF1ED, 0x537D, 0xF1EE, 0x6ADB, 0xF1EF, 0x696B, 0xF1F0, 0x6C41, 0xF1F1, 0x847A, 0xF1F2, 0x589E, 0xF1F3, 0x618E, 0xF1F4, 0x66FE, 0xF1F5, 0x62EF, 0xF1F6, 0x70DD, 0xF1F7, 0x7511, 0xF1F8, 0x75C7, 0xF1F9, 0x7E52, 0xF1FA, 0x84B8, 0xF1FB, 0x8B49, 0xF1FC, 0x8D08, 0xF1FD, 0x4E4B, 0xF1FE, 0x53EA, 0xF2A1, 0x54AB, 0xF2A2, 0x5730, 0xF2A3, 0x5740, 0xF2A4, 0x5FD7, 0xF2A5, 0x6301, 0xF2A6, 0x6307, 0xF2A7, 0x646F, 0xF2A8, 0x652F, 0xF2A9, 0x65E8, 0xF2AA, 0x667A, 0xF2AB, 0x679D, 0xF2AC, 0x67B3, 0xF2AD, 0x6B62, 0xF2AE, 0x6C60, 0xF2AF, 0x6C9A, 0xF2B0, 0x6F2C, 0xF2B1, 0x77E5, 0xF2B2, 0x7825, 0xF2B3, 0x7949, 0xF2B4, 0x7957, 0xF2B5, 0x7D19, 0xF2B6, 0x80A2, 0xF2B7, 0x8102, 0xF2B8, 0x81F3, 0xF2B9, 0x829D, 0xF2BA, 0x82B7, 0xF2BB, 0x8718, 0xF2BC, 0x8A8C, 0xF2BD, 0xF9FC, 0xF2BE, 0x8D04, 0xF2BF, 0x8DBE, 0xF2C0, 0x9072, 0xF2C1, 0x76F4, 0xF2C2, 0x7A19, 0xF2C3, 0x7A37, 0xF2C4, 0x7E54, 0xF2C5, 0x8077, 0xF2C6, 0x5507, 0xF2C7, 0x55D4, 0xF2C8, 0x5875, 0xF2C9, 0x632F, 0xF2CA, 0x6422, 0xF2CB, 0x6649, 0xF2CC, 0x664B, 0xF2CD, 0x686D, 0xF2CE, 0x699B, 0xF2CF, 0x6B84, 0xF2D0, 0x6D25, 0xF2D1, 0x6EB1, 0xF2D2, 0x73CD, 0xF2D3, 0x7468, 0xF2D4, 0x74A1, 0xF2D5, 0x755B, 0xF2D6, 0x75B9, 0xF2D7, 0x76E1, 0xF2D8, 0x771E, 0xF2D9, 0x778B, 0xF2DA, 0x79E6, 0xF2DB, 0x7E09, 0xF2DC, 0x7E1D, 0xF2DD, 0x81FB, 0xF2DE, 0x852F, 0xF2DF, 0x8897, 0xF2E0, 0x8A3A, 0xF2E1, 0x8CD1, 0xF2E2, 0x8EEB, 0xF2E3, 0x8FB0, 0xF2E4, 0x9032, 0xF2E5, 0x93AD, 0xF2E6, 0x9663, 0xF2E7, 0x9673, 0xF2E8, 0x9707, 0xF2E9, 0x4F84, 0xF2EA, 0x53F1, 0xF2EB, 0x59EA, 0xF2EC, 0x5AC9, 0xF2ED, 0x5E19, 0xF2EE, 0x684E, 0xF2EF, 0x74C6, 0xF2F0, 0x75BE, 0xF2F1, 0x79E9, 0xF2F2, 0x7A92, 0xF2F3, 0x81A3, 0xF2F4, 0x86ED, 0xF2F5, 0x8CEA, 0xF2F6, 0x8DCC, 0xF2F7, 0x8FED, 0xF2F8, 0x659F, 0xF2F9, 0x6715, 0xF2FA, 0xF9FD, 0xF2FB, 0x57F7, 0xF2FC, 0x6F57, 0xF2FD, 0x7DDD, 0xF2FE, 0x8F2F, 0xF3A1, 0x93F6, 0xF3A2, 0x96C6, 0xF3A3, 0x5FB5, 0xF3A4, 0x61F2, 0xF3A5, 0x6F84, 0xF3A6, 0x4E14, 0xF3A7, 0x4F98, 0xF3A8, 0x501F, 0xF3A9, 0x53C9, 0xF3AA, 0x55DF, 0xF3AB, 0x5D6F, 0xF3AC, 0x5DEE, 0xF3AD, 0x6B21, 0xF3AE, 0x6B64, 0xF3AF, 0x78CB, 0xF3B0, 0x7B9A, 0xF3B1, 0xF9FE, 0xF3B2, 0x8E49, 0xF3B3, 0x8ECA, 0xF3B4, 0x906E, 0xF3B5, 0x6349, 0xF3B6, 0x643E, 0xF3B7, 0x7740, 0xF3B8, 0x7A84, 0xF3B9, 0x932F, 0xF3BA, 0x947F, 0xF3BB, 0x9F6A, 0xF3BC, 0x64B0, 0xF3BD, 0x6FAF, 0xF3BE, 0x71E6, 0xF3BF, 0x74A8, 0xF3C0, 0x74DA, 0xF3C1, 0x7AC4, 0xF3C2, 0x7C12, 0xF3C3, 0x7E82, 0xF3C4, 0x7CB2, 0xF3C5, 0x7E98, 0xF3C6, 0x8B9A, 0xF3C7, 0x8D0A, 0xF3C8, 0x947D, 0xF3C9, 0x9910, 0xF3CA, 0x994C, 0xF3CB, 0x5239, 0xF3CC, 0x5BDF, 0xF3CD, 0x64E6, 0xF3CE, 0x672D, 0xF3CF, 0x7D2E, 0xF3D0, 0x50ED, 0xF3D1, 0x53C3, 0xF3D2, 0x5879, 0xF3D3, 0x6158, 0xF3D4, 0x6159, 0xF3D5, 0x61FA, 0xF3D6, 0x65AC, 0xF3D7, 0x7AD9, 0xF3D8, 0x8B92, 0xF3D9, 0x8B96, 0xF3DA, 0x5009, 0xF3DB, 0x5021, 0xF3DC, 0x5275, 0xF3DD, 0x5531, 0xF3DE, 0x5A3C, 0xF3DF, 0x5EE0, 0xF3E0, 0x5F70, 0xF3E1, 0x6134, 0xF3E2, 0x655E, 0xF3E3, 0x660C, 0xF3E4, 0x6636, 0xF3E5, 0x66A2, 0xF3E6, 0x69CD, 0xF3E7, 0x6EC4, 0xF3E8, 0x6F32, 0xF3E9, 0x7316, 0xF3EA, 0x7621, 0xF3EB, 0x7A93, 0xF3EC, 0x8139, 0xF3ED, 0x8259, 0xF3EE, 0x83D6, 0xF3EF, 0x84BC, 0xF3F0, 0x50B5, 0xF3F1, 0x57F0, 0xF3F2, 0x5BC0, 0xF3F3, 0x5BE8, 0xF3F4, 0x5F69, 0xF3F5, 0x63A1, 0xF3F6, 0x7826, 0xF3F7, 0x7DB5, 0xF3F8, 0x83DC, 0xF3F9, 0x8521, 0xF3FA, 0x91C7, 0xF3FB, 0x91F5, 0xF3FC, 0x518A, 0xF3FD, 0x67F5, 0xF3FE, 0x7B56, 0xF4A1, 0x8CAC, 0xF4A2, 0x51C4, 0xF4A3, 0x59BB, 0xF4A4, 0x60BD, 0xF4A5, 0x8655, 0xF4A6, 0x501C, 0xF4A7, 0xF9FF, 0xF4A8, 0x5254, 0xF4A9, 0x5C3A, 0xF4AA, 0x617D, 0xF4AB, 0x621A, 0xF4AC, 0x62D3, 0xF4AD, 0x64F2, 0xF4AE, 0x65A5, 0xF4AF, 0x6ECC, 0xF4B0, 0x7620, 0xF4B1, 0x810A, 0xF4B2, 0x8E60, 0xF4B3, 0x965F, 0xF4B4, 0x96BB, 0xF4B5, 0x4EDF, 0xF4B6, 0x5343, 0xF4B7, 0x5598, 0xF4B8, 0x5929, 0xF4B9, 0x5DDD, 0xF4BA, 0x64C5, 0xF4BB, 0x6CC9, 0xF4BC, 0x6DFA, 0xF4BD, 0x7394, 0xF4BE, 0x7A7F, 0xF4BF, 0x821B, 0xF4C0, 0x85A6, 0xF4C1, 0x8CE4, 0xF4C2, 0x8E10, 0xF4C3, 0x9077, 0xF4C4, 0x91E7, 0xF4C5, 0x95E1, 0xF4C6, 0x9621, 0xF4C7, 0x97C6, 0xF4C8, 0x51F8, 0xF4C9, 0x54F2, 0xF4CA, 0x5586, 0xF4CB, 0x5FB9, 0xF4CC, 0x64A4, 0xF4CD, 0x6F88, 0xF4CE, 0x7DB4, 0xF4CF, 0x8F1F, 0xF4D0, 0x8F4D, 0xF4D1, 0x9435, 0xF4D2, 0x50C9, 0xF4D3, 0x5C16, 0xF4D4, 0x6CBE, 0xF4D5, 0x6DFB, 0xF4D6, 0x751B, 0xF4D7, 0x77BB, 0xF4D8, 0x7C3D, 0xF4D9, 0x7C64, 0xF4DA, 0x8A79, 0xF4DB, 0x8AC2, 0xF4DC, 0x581E, 0xF4DD, 0x59BE, 0xF4DE, 0x5E16, 0xF4DF, 0x6377, 0xF4E0, 0x7252, 0xF4E1, 0x758A, 0xF4E2, 0x776B, 0xF4E3, 0x8ADC, 0xF4E4, 0x8CBC, 0xF4E5, 0x8F12, 0xF4E6, 0x5EF3, 0xF4E7, 0x6674, 0xF4E8, 0x6DF8, 0xF4E9, 0x807D, 0xF4EA, 0x83C1, 0xF4EB, 0x8ACB, 0xF4EC, 0x9751, 0xF4ED, 0x9BD6, 0xF4EE, 0xFA00, 0xF4EF, 0x5243, 0xF4F0, 0x66FF, 0xF4F1, 0x6D95, 0xF4F2, 0x6EEF, 0xF4F3, 0x7DE0, 0xF4F4, 0x8AE6, 0xF4F5, 0x902E, 0xF4F6, 0x905E, 0xF4F7, 0x9AD4, 0xF4F8, 0x521D, 0xF4F9, 0x527F, 0xF4FA, 0x54E8, 0xF4FB, 0x6194, 0xF4FC, 0x6284, 0xF4FD, 0x62DB, 0xF4FE, 0x68A2, 0xF5A1, 0x6912, 0xF5A2, 0x695A, 0xF5A3, 0x6A35, 0xF5A4, 0x7092, 0xF5A5, 0x7126, 0xF5A6, 0x785D, 0xF5A7, 0x7901, 0xF5A8, 0x790E, 0xF5A9, 0x79D2, 0xF5AA, 0x7A0D, 0xF5AB, 0x8096, 0xF5AC, 0x8278, 0xF5AD, 0x82D5, 0xF5AE, 0x8349, 0xF5AF, 0x8549, 0xF5B0, 0x8C82, 0xF5B1, 0x8D85, 0xF5B2, 0x9162, 0xF5B3, 0x918B, 0xF5B4, 0x91AE, 0xF5B5, 0x4FC3, 0xF5B6, 0x56D1, 0xF5B7, 0x71ED, 0xF5B8, 0x77D7, 0xF5B9, 0x8700, 0xF5BA, 0x89F8, 0xF5BB, 0x5BF8, 0xF5BC, 0x5FD6, 0xF5BD, 0x6751, 0xF5BE, 0x90A8, 0xF5BF, 0x53E2, 0xF5C0, 0x585A, 0xF5C1, 0x5BF5, 0xF5C2, 0x60A4, 0xF5C3, 0x6181, 0xF5C4, 0x6460, 0xF5C5, 0x7E3D, 0xF5C6, 0x8070, 0xF5C7, 0x8525, 0xF5C8, 0x9283, 0xF5C9, 0x64AE, 0xF5CA, 0x50AC, 0xF5CB, 0x5D14, 0xF5CC, 0x6700, 0xF5CD, 0x589C, 0xF5CE, 0x62BD, 0xF5CF, 0x63A8, 0xF5D0, 0x690E, 0xF5D1, 0x6978, 0xF5D2, 0x6A1E, 0xF5D3, 0x6E6B, 0xF5D4, 0x76BA, 0xF5D5, 0x79CB, 0xF5D6, 0x82BB, 0xF5D7, 0x8429, 0xF5D8, 0x8ACF, 0xF5D9, 0x8DA8, 0xF5DA, 0x8FFD, 0xF5DB, 0x9112, 0xF5DC, 0x914B, 0xF5DD, 0x919C, 0xF5DE, 0x9310, 0xF5DF, 0x9318, 0xF5E0, 0x939A, 0xF5E1, 0x96DB, 0xF5E2, 0x9A36, 0xF5E3, 0x9C0D, 0xF5E4, 0x4E11, 0xF5E5, 0x755C, 0xF5E6, 0x795D, 0xF5E7, 0x7AFA, 0xF5E8, 0x7B51, 0xF5E9, 0x7BC9, 0xF5EA, 0x7E2E, 0xF5EB, 0x84C4, 0xF5EC, 0x8E59, 0xF5ED, 0x8E74, 0xF5EE, 0x8EF8, 0xF5EF, 0x9010, 0xF5F0, 0x6625, 0xF5F1, 0x693F, 0xF5F2, 0x7443, 0xF5F3, 0x51FA, 0xF5F4, 0x672E, 0xF5F5, 0x9EDC, 0xF5F6, 0x5145, 0xF5F7, 0x5FE0, 0xF5F8, 0x6C96, 0xF5F9, 0x87F2, 0xF5FA, 0x885D, 0xF5FB, 0x8877, 0xF5FC, 0x60B4, 0xF5FD, 0x81B5, 0xF5FE, 0x8403, 0xF6A1, 0x8D05, 0xF6A2, 0x53D6, 0xF6A3, 0x5439, 0xF6A4, 0x5634, 0xF6A5, 0x5A36, 0xF6A6, 0x5C31, 0xF6A7, 0x708A, 0xF6A8, 0x7FE0, 0xF6A9, 0x805A, 0xF6AA, 0x8106, 0xF6AB, 0x81ED, 0xF6AC, 0x8DA3, 0xF6AD, 0x9189, 0xF6AE, 0x9A5F, 0xF6AF, 0x9DF2, 0xF6B0, 0x5074, 0xF6B1, 0x4EC4, 0xF6B2, 0x53A0, 0xF6B3, 0x60FB, 0xF6B4, 0x6E2C, 0xF6B5, 0x5C64, 0xF6B6, 0x4F88, 0xF6B7, 0x5024, 0xF6B8, 0x55E4, 0xF6B9, 0x5CD9, 0xF6BA, 0x5E5F, 0xF6BB, 0x6065, 0xF6BC, 0x6894, 0xF6BD, 0x6CBB, 0xF6BE, 0x6DC4, 0xF6BF, 0x71BE, 0xF6C0, 0x75D4, 0xF6C1, 0x75F4, 0xF6C2, 0x7661, 0xF6C3, 0x7A1A, 0xF6C4, 0x7A49, 0xF6C5, 0x7DC7, 0xF6C6, 0x7DFB, 0xF6C7, 0x7F6E, 0xF6C8, 0x81F4, 0xF6C9, 0x86A9, 0xF6CA, 0x8F1C, 0xF6CB, 0x96C9, 0xF6CC, 0x99B3, 0xF6CD, 0x9F52, 0xF6CE, 0x5247, 0xF6CF, 0x52C5, 0xF6D0, 0x98ED, 0xF6D1, 0x89AA, 0xF6D2, 0x4E03, 0xF6D3, 0x67D2, 0xF6D4, 0x6F06, 0xF6D5, 0x4FB5, 0xF6D6, 0x5BE2, 0xF6D7, 0x6795, 0xF6D8, 0x6C88, 0xF6D9, 0x6D78, 0xF6DA, 0x741B, 0xF6DB, 0x7827, 0xF6DC, 0x91DD, 0xF6DD, 0x937C, 0xF6DE, 0x87C4, 0xF6DF, 0x79E4, 0xF6E0, 0x7A31, 0xF6E1, 0x5FEB, 0xF6E2, 0x4ED6, 0xF6E3, 0x54A4, 0xF6E4, 0x553E, 0xF6E5, 0x58AE, 0xF6E6, 0x59A5, 0xF6E7, 0x60F0, 0xF6E8, 0x6253, 0xF6E9, 0x62D6, 0xF6EA, 0x6736, 0xF6EB, 0x6955, 0xF6EC, 0x8235, 0xF6ED, 0x9640, 0xF6EE, 0x99B1, 0xF6EF, 0x99DD, 0xF6F0, 0x502C, 0xF6F1, 0x5353, 0xF6F2, 0x5544, 0xF6F3, 0x577C, 0xF6F4, 0xFA01, 0xF6F5, 0x6258, 0xF6F6, 0xFA02, 0xF6F7, 0x64E2, 0xF6F8, 0x666B, 0xF6F9, 0x67DD, 0xF6FA, 0x6FC1, 0xF6FB, 0x6FEF, 0xF6FC, 0x7422, 0xF6FD, 0x7438, 0xF6FE, 0x8A17, 0xF7A1, 0x9438, 0xF7A2, 0x5451, 0xF7A3, 0x5606, 0xF7A4, 0x5766, 0xF7A5, 0x5F48, 0xF7A6, 0x619A, 0xF7A7, 0x6B4E, 0xF7A8, 0x7058, 0xF7A9, 0x70AD, 0xF7AA, 0x7DBB, 0xF7AB, 0x8A95, 0xF7AC, 0x596A, 0xF7AD, 0x812B, 0xF7AE, 0x63A2, 0xF7AF, 0x7708, 0xF7B0, 0x803D, 0xF7B1, 0x8CAA, 0xF7B2, 0x5854, 0xF7B3, 0x642D, 0xF7B4, 0x69BB, 0xF7B5, 0x5B95, 0xF7B6, 0x5E11, 0xF7B7, 0x6E6F, 0xF7B8, 0xFA03, 0xF7B9, 0x8569, 0xF7BA, 0x514C, 0xF7BB, 0x53F0, 0xF7BC, 0x592A, 0xF7BD, 0x6020, 0xF7BE, 0x614B, 0xF7BF, 0x6B86, 0xF7C0, 0x6C70, 0xF7C1, 0x6CF0, 0xF7C2, 0x7B1E, 0xF7C3, 0x80CE, 0xF7C4, 0x82D4, 0xF7C5, 0x8DC6, 0xF7C6, 0x90B0, 0xF7C7, 0x98B1, 0xF7C8, 0xFA04, 0xF7C9, 0x64C7, 0xF7CA, 0x6FA4, 0xF7CB, 0x6491, 0xF7CC, 0x6504, 0xF7CD, 0x514E, 0xF7CE, 0x5410, 0xF7CF, 0x571F, 0xF7D0, 0x8A0E, 0xF7D1, 0x615F, 0xF7D2, 0x6876, 0xF7D3, 0xFA05, 0xF7D4, 0x75DB, 0xF7D5, 0x7B52, 0xF7D6, 0x7D71, 0xF7D7, 0x901A, 0xF7D8, 0x5806, 0xF7D9, 0x69CC, 0xF7DA, 0x817F, 0xF7DB, 0x892A, 0xF7DC, 0x9000, 0xF7DD, 0x9839, 0xF7DE, 0x5078, 0xF7DF, 0x5957, 0xF7E0, 0x59AC, 0xF7E1, 0x6295, 0xF7E2, 0x900F, 0xF7E3, 0x9B2A, 0xF7E4, 0x615D, 0xF7E5, 0x7279, 0xF7E6, 0x95D6, 0xF7E7, 0x5761, 0xF7E8, 0x5A46, 0xF7E9, 0x5DF4, 0xF7EA, 0x628A, 0xF7EB, 0x64AD, 0xF7EC, 0x64FA, 0xF7ED, 0x6777, 0xF7EE, 0x6CE2, 0xF7EF, 0x6D3E, 0xF7F0, 0x722C, 0xF7F1, 0x7436, 0xF7F2, 0x7834, 0xF7F3, 0x7F77, 0xF7F4, 0x82AD, 0xF7F5, 0x8DDB, 0xF7F6, 0x9817, 0xF7F7, 0x5224, 0xF7F8, 0x5742, 0xF7F9, 0x677F, 0xF7FA, 0x7248, 0xF7FB, 0x74E3, 0xF7FC, 0x8CA9, 0xF7FD, 0x8FA6, 0xF7FE, 0x9211, 0xF8A1, 0x962A, 0xF8A2, 0x516B, 0xF8A3, 0x53ED, 0xF8A4, 0x634C, 0xF8A5, 0x4F69, 0xF8A6, 0x5504, 0xF8A7, 0x6096, 0xF8A8, 0x6557, 0xF8A9, 0x6C9B, 0xF8AA, 0x6D7F, 0xF8AB, 0x724C, 0xF8AC, 0x72FD, 0xF8AD, 0x7A17, 0xF8AE, 0x8987, 0xF8AF, 0x8C9D, 0xF8B0, 0x5F6D, 0xF8B1, 0x6F8E, 0xF8B2, 0x70F9, 0xF8B3, 0x81A8, 0xF8B4, 0x610E, 0xF8B5, 0x4FBF, 0xF8B6, 0x504F, 0xF8B7, 0x6241, 0xF8B8, 0x7247, 0xF8B9, 0x7BC7, 0xF8BA, 0x7DE8, 0xF8BB, 0x7FE9, 0xF8BC, 0x904D, 0xF8BD, 0x97AD, 0xF8BE, 0x9A19, 0xF8BF, 0x8CB6, 0xF8C0, 0x576A, 0xF8C1, 0x5E73, 0xF8C2, 0x67B0, 0xF8C3, 0x840D, 0xF8C4, 0x8A55, 0xF8C5, 0x5420, 0xF8C6, 0x5B16, 0xF8C7, 0x5E63, 0xF8C8, 0x5EE2, 0xF8C9, 0x5F0A, 0xF8CA, 0x6583, 0xF8CB, 0x80BA, 0xF8CC, 0x853D, 0xF8CD, 0x9589, 0xF8CE, 0x965B, 0xF8CF, 0x4F48, 0xF8D0, 0x5305, 0xF8D1, 0x530D, 0xF8D2, 0x530F, 0xF8D3, 0x5486, 0xF8D4, 0x54FA, 0xF8D5, 0x5703, 0xF8D6, 0x5E03, 0xF8D7, 0x6016, 0xF8D8, 0x629B, 0xF8D9, 0x62B1, 0xF8DA, 0x6355, 0xF8DB, 0xFA06, 0xF8DC, 0x6CE1, 0xF8DD, 0x6D66, 0xF8DE, 0x75B1, 0xF8DF, 0x7832, 0xF8E0, 0x80DE, 0xF8E1, 0x812F, 0xF8E2, 0x82DE, 0xF8E3, 0x8461, 0xF8E4, 0x84B2, 0xF8E5, 0x888D, 0xF8E6, 0x8912, 0xF8E7, 0x900B, 0xF8E8, 0x92EA, 0xF8E9, 0x98FD, 0xF8EA, 0x9B91, 0xF8EB, 0x5E45, 0xF8EC, 0x66B4, 0xF8ED, 0x66DD, 0xF8EE, 0x7011, 0xF8EF, 0x7206, 0xF8F0, 0xFA07, 0xF8F1, 0x4FF5, 0xF8F2, 0x527D, 0xF8F3, 0x5F6A, 0xF8F4, 0x6153, 0xF8F5, 0x6753, 0xF8F6, 0x6A19, 0xF8F7, 0x6F02, 0xF8F8, 0x74E2, 0xF8F9, 0x7968, 0xF8FA, 0x8868, 0xF8FB, 0x8C79, 0xF8FC, 0x98C7, 0xF8FD, 0x98C4, 0xF8FE, 0x9A43, 0xF9A1, 0x54C1, 0xF9A2, 0x7A1F, 0xF9A3, 0x6953, 0xF9A4, 0x8AF7, 0xF9A5, 0x8C4A, 0xF9A6, 0x98A8, 0xF9A7, 0x99AE, 0xF9A8, 0x5F7C, 0xF9A9, 0x62AB, 0xF9AA, 0x75B2, 0xF9AB, 0x76AE, 0xF9AC, 0x88AB, 0xF9AD, 0x907F, 0xF9AE, 0x9642, 0xF9AF, 0x5339, 0xF9B0, 0x5F3C, 0xF9B1, 0x5FC5, 0xF9B2, 0x6CCC, 0xF9B3, 0x73CC, 0xF9B4, 0x7562, 0xF9B5, 0x758B, 0xF9B6, 0x7B46, 0xF9B7, 0x82FE, 0xF9B8, 0x999D, 0xF9B9, 0x4E4F, 0xF9BA, 0x903C, 0xF9BB, 0x4E0B, 0xF9BC, 0x4F55, 0xF9BD, 0x53A6, 0xF9BE, 0x590F, 0xF9BF, 0x5EC8, 0xF9C0, 0x6630, 0xF9C1, 0x6CB3, 0xF9C2, 0x7455, 0xF9C3, 0x8377, 0xF9C4, 0x8766, 0xF9C5, 0x8CC0, 0xF9C6, 0x9050, 0xF9C7, 0x971E, 0xF9C8, 0x9C15, 0xF9C9, 0x58D1, 0xF9CA, 0x5B78, 0xF9CB, 0x8650, 0xF9CC, 0x8B14, 0xF9CD, 0x9DB4, 0xF9CE, 0x5BD2, 0xF9CF, 0x6068, 0xF9D0, 0x608D, 0xF9D1, 0x65F1, 0xF9D2, 0x6C57, 0xF9D3, 0x6F22, 0xF9D4, 0x6FA3, 0xF9D5, 0x701A, 0xF9D6, 0x7F55, 0xF9D7, 0x7FF0, 0xF9D8, 0x9591, 0xF9D9, 0x9592, 0xF9DA, 0x9650, 0xF9DB, 0x97D3, 0xF9DC, 0x5272, 0xF9DD, 0x8F44, 0xF9DE, 0x51FD, 0xF9DF, 0x542B, 0xF9E0, 0x54B8, 0xF9E1, 0x5563, 0xF9E2, 0x558A, 0xF9E3, 0x6ABB, 0xF9E4, 0x6DB5, 0xF9E5, 0x7DD8, 0xF9E6, 0x8266, 0xF9E7, 0x929C, 0xF9E8, 0x9677, 0xF9E9, 0x9E79, 0xF9EA, 0x5408, 0xF9EB, 0x54C8, 0xF9EC, 0x76D2, 0xF9ED, 0x86E4, 0xF9EE, 0x95A4, 0xF9EF, 0x95D4, 0xF9F0, 0x965C, 0xF9F1, 0x4EA2, 0xF9F2, 0x4F09, 0xF9F3, 0x59EE, 0xF9F4, 0x5AE6, 0xF9F5, 0x5DF7, 0xF9F6, 0x6052, 0xF9F7, 0x6297, 0xF9F8, 0x676D, 0xF9F9, 0x6841, 0xF9FA, 0x6C86, 0xF9FB, 0x6E2F, 0xF9FC, 0x7F38, 0xF9FD, 0x809B, 0xF9FE, 0x822A, 0xFAA1, 0xFA08, 0xFAA2, 0xFA09, 0xFAA3, 0x9805, 0xFAA4, 0x4EA5, 0xFAA5, 0x5055, 0xFAA6, 0x54B3, 0xFAA7, 0x5793, 0xFAA8, 0x595A, 0xFAA9, 0x5B69, 0xFAAA, 0x5BB3, 0xFAAB, 0x61C8, 0xFAAC, 0x6977, 0xFAAD, 0x6D77, 0xFAAE, 0x7023, 0xFAAF, 0x87F9, 0xFAB0, 0x89E3, 0xFAB1, 0x8A72, 0xFAB2, 0x8AE7, 0xFAB3, 0x9082, 0xFAB4, 0x99ED, 0xFAB5, 0x9AB8, 0xFAB6, 0x52BE, 0xFAB7, 0x6838, 0xFAB8, 0x5016, 0xFAB9, 0x5E78, 0xFABA, 0x674F, 0xFABB, 0x8347, 0xFABC, 0x884C, 0xFABD, 0x4EAB, 0xFABE, 0x5411, 0xFABF, 0x56AE, 0xFAC0, 0x73E6, 0xFAC1, 0x9115, 0xFAC2, 0x97FF, 0xFAC3, 0x9909, 0xFAC4, 0x9957, 0xFAC5, 0x9999, 0xFAC6, 0x5653, 0xFAC7, 0x589F, 0xFAC8, 0x865B, 0xFAC9, 0x8A31, 0xFACA, 0x61B2, 0xFACB, 0x6AF6, 0xFACC, 0x737B, 0xFACD, 0x8ED2, 0xFACE, 0x6B47, 0xFACF, 0x96AA, 0xFAD0, 0x9A57, 0xFAD1, 0x5955, 0xFAD2, 0x7200, 0xFAD3, 0x8D6B, 0xFAD4, 0x9769, 0xFAD5, 0x4FD4, 0xFAD6, 0x5CF4, 0xFAD7, 0x5F26, 0xFAD8, 0x61F8, 0xFAD9, 0x665B, 0xFADA, 0x6CEB, 0xFADB, 0x70AB, 0xFADC, 0x7384, 0xFADD, 0x73B9, 0xFADE, 0x73FE, 0xFADF, 0x7729, 0xFAE0, 0x774D, 0xFAE1, 0x7D43, 0xFAE2, 0x7D62, 0xFAE3, 0x7E23, 0xFAE4, 0x8237, 0xFAE5, 0x8852, 0xFAE6, 0xFA0A, 0xFAE7, 0x8CE2, 0xFAE8, 0x9249, 0xFAE9, 0x986F, 0xFAEA, 0x5B51, 0xFAEB, 0x7A74, 0xFAEC, 0x8840, 0xFAED, 0x9801, 0xFAEE, 0x5ACC, 0xFAEF, 0x4FE0, 0xFAF0, 0x5354, 0xFAF1, 0x593E, 0xFAF2, 0x5CFD, 0xFAF3, 0x633E, 0xFAF4, 0x6D79, 0xFAF5, 0x72F9, 0xFAF6, 0x8105, 0xFAF7, 0x8107, 0xFAF8, 0x83A2, 0xFAF9, 0x92CF, 0xFAFA, 0x9830, 0xFAFB, 0x4EA8, 0xFAFC, 0x5144, 0xFAFD, 0x5211, 0xFAFE, 0x578B, 0xFBA1, 0x5F62, 0xFBA2, 0x6CC2, 0xFBA3, 0x6ECE, 0xFBA4, 0x7005, 0xFBA5, 0x7050, 0xFBA6, 0x70AF, 0xFBA7, 0x7192, 0xFBA8, 0x73E9, 0xFBA9, 0x7469, 0xFBAA, 0x834A, 0xFBAB, 0x87A2, 0xFBAC, 0x8861, 0xFBAD, 0x9008, 0xFBAE, 0x90A2, 0xFBAF, 0x93A3, 0xFBB0, 0x99A8, 0xFBB1, 0x516E, 0xFBB2, 0x5F57, 0xFBB3, 0x60E0, 0xFBB4, 0x6167, 0xFBB5, 0x66B3, 0xFBB6, 0x8559, 0xFBB7, 0x8E4A, 0xFBB8, 0x91AF, 0xFBB9, 0x978B, 0xFBBA, 0x4E4E, 0xFBBB, 0x4E92, 0xFBBC, 0x547C, 0xFBBD, 0x58D5, 0xFBBE, 0x58FA, 0xFBBF, 0x597D, 0xFBC0, 0x5CB5, 0xFBC1, 0x5F27, 0xFBC2, 0x6236, 0xFBC3, 0x6248, 0xFBC4, 0x660A, 0xFBC5, 0x6667, 0xFBC6, 0x6BEB, 0xFBC7, 0x6D69, 0xFBC8, 0x6DCF, 0xFBC9, 0x6E56, 0xFBCA, 0x6EF8, 0xFBCB, 0x6F94, 0xFBCC, 0x6FE0, 0xFBCD, 0x6FE9, 0xFBCE, 0x705D, 0xFBCF, 0x72D0, 0xFBD0, 0x7425, 0xFBD1, 0x745A, 0xFBD2, 0x74E0, 0xFBD3, 0x7693, 0xFBD4, 0x795C, 0xFBD5, 0x7CCA, 0xFBD6, 0x7E1E, 0xFBD7, 0x80E1, 0xFBD8, 0x82A6, 0xFBD9, 0x846B, 0xFBDA, 0x84BF, 0xFBDB, 0x864E, 0xFBDC, 0x865F, 0xFBDD, 0x8774, 0xFBDE, 0x8B77, 0xFBDF, 0x8C6A, 0xFBE0, 0x93AC, 0xFBE1, 0x9800, 0xFBE2, 0x9865, 0xFBE3, 0x60D1, 0xFBE4, 0x6216, 0xFBE5, 0x9177, 0xFBE6, 0x5A5A, 0xFBE7, 0x660F, 0xFBE8, 0x6DF7, 0xFBE9, 0x6E3E, 0xFBEA, 0x743F, 0xFBEB, 0x9B42, 0xFBEC, 0x5FFD, 0xFBED, 0x60DA, 0xFBEE, 0x7B0F, 0xFBEF, 0x54C4, 0xFBF0, 0x5F18, 0xFBF1, 0x6C5E, 0xFBF2, 0x6CD3, 0xFBF3, 0x6D2A, 0xFBF4, 0x70D8, 0xFBF5, 0x7D05, 0xFBF6, 0x8679, 0xFBF7, 0x8A0C, 0xFBF8, 0x9D3B, 0xFBF9, 0x5316, 0xFBFA, 0x548C, 0xFBFB, 0x5B05, 0xFBFC, 0x6A3A, 0xFBFD, 0x706B, 0xFBFE, 0x7575, 0xFCA1, 0x798D, 0xFCA2, 0x79BE, 0xFCA3, 0x82B1, 0xFCA4, 0x83EF, 0xFCA5, 0x8A71, 0xFCA6, 0x8B41, 0xFCA7, 0x8CA8, 0xFCA8, 0x9774, 0xFCA9, 0xFA0B, 0xFCAA, 0x64F4, 0xFCAB, 0x652B, 0xFCAC, 0x78BA, 0xFCAD, 0x78BB, 0xFCAE, 0x7A6B, 0xFCAF, 0x4E38, 0xFCB0, 0x559A, 0xFCB1, 0x5950, 0xFCB2, 0x5BA6, 0xFCB3, 0x5E7B, 0xFCB4, 0x60A3, 0xFCB5, 0x63DB, 0xFCB6, 0x6B61, 0xFCB7, 0x6665, 0xFCB8, 0x6853, 0xFCB9, 0x6E19, 0xFCBA, 0x7165, 0xFCBB, 0x74B0, 0xFCBC, 0x7D08, 0xFCBD, 0x9084, 0xFCBE, 0x9A69, 0xFCBF, 0x9C25, 0xFCC0, 0x6D3B, 0xFCC1, 0x6ED1, 0xFCC2, 0x733E, 0xFCC3, 0x8C41, 0xFCC4, 0x95CA, 0xFCC5, 0x51F0, 0xFCC6, 0x5E4C, 0xFCC7, 0x5FA8, 0xFCC8, 0x604D, 0xFCC9, 0x60F6, 0xFCCA, 0x6130, 0xFCCB, 0x614C, 0xFCCC, 0x6643, 0xFCCD, 0x6644, 0xFCCE, 0x69A5, 0xFCCF, 0x6CC1, 0xFCD0, 0x6E5F, 0xFCD1, 0x6EC9, 0xFCD2, 0x6F62, 0xFCD3, 0x714C, 0xFCD4, 0x749C, 0xFCD5, 0x7687, 0xFCD6, 0x7BC1, 0xFCD7, 0x7C27, 0xFCD8, 0x8352, 0xFCD9, 0x8757, 0xFCDA, 0x9051, 0xFCDB, 0x968D, 0xFCDC, 0x9EC3, 0xFCDD, 0x532F, 0xFCDE, 0x56DE, 0xFCDF, 0x5EFB, 0xFCE0, 0x5F8A, 0xFCE1, 0x6062, 0xFCE2, 0x6094, 0xFCE3, 0x61F7, 0xFCE4, 0x6666, 0xFCE5, 0x6703, 0xFCE6, 0x6A9C, 0xFCE7, 0x6DEE, 0xFCE8, 0x6FAE, 0xFCE9, 0x7070, 0xFCEA, 0x736A, 0xFCEB, 0x7E6A, 0xFCEC, 0x81BE, 0xFCED, 0x8334, 0xFCEE, 0x86D4, 0xFCEF, 0x8AA8, 0xFCF0, 0x8CC4, 0xFCF1, 0x5283, 0xFCF2, 0x7372, 0xFCF3, 0x5B96, 0xFCF4, 0x6A6B, 0xFCF5, 0x9404, 0xFCF6, 0x54EE, 0xFCF7, 0x5686, 0xFCF8, 0x5B5D, 0xFCF9, 0x6548, 0xFCFA, 0x6585, 0xFCFB, 0x66C9, 0xFCFC, 0x689F, 0xFCFD, 0x6D8D, 0xFCFE, 0x6DC6, 0xFDA1, 0x723B, 0xFDA2, 0x80B4, 0xFDA3, 0x9175, 0xFDA4, 0x9A4D, 0xFDA5, 0x4FAF, 0xFDA6, 0x5019, 0xFDA7, 0x539A, 0xFDA8, 0x540E, 0xFDA9, 0x543C, 0xFDAA, 0x5589, 0xFDAB, 0x55C5, 0xFDAC, 0x5E3F, 0xFDAD, 0x5F8C, 0xFDAE, 0x673D, 0xFDAF, 0x7166, 0xFDB0, 0x73DD, 0xFDB1, 0x9005, 0xFDB2, 0x52DB, 0xFDB3, 0x52F3, 0xFDB4, 0x5864, 0xFDB5, 0x58CE, 0xFDB6, 0x7104, 0xFDB7, 0x718F, 0xFDB8, 0x71FB, 0xFDB9, 0x85B0, 0xFDBA, 0x8A13, 0xFDBB, 0x6688, 0xFDBC, 0x85A8, 0xFDBD, 0x55A7, 0xFDBE, 0x6684, 0xFDBF, 0x714A, 0xFDC0, 0x8431, 0xFDC1, 0x5349, 0xFDC2, 0x5599, 0xFDC3, 0x6BC1, 0xFDC4, 0x5F59, 0xFDC5, 0x5FBD, 0xFDC6, 0x63EE, 0xFDC7, 0x6689, 0xFDC8, 0x7147, 0xFDC9, 0x8AF1, 0xFDCA, 0x8F1D, 0xFDCB, 0x9EBE, 0xFDCC, 0x4F11, 0xFDCD, 0x643A, 0xFDCE, 0x70CB, 0xFDCF, 0x7566, 0xFDD0, 0x8667, 0xFDD1, 0x6064, 0xFDD2, 0x8B4E, 0xFDD3, 0x9DF8, 0xFDD4, 0x5147, 0xFDD5, 0x51F6, 0xFDD6, 0x5308, 0xFDD7, 0x6D36, 0xFDD8, 0x80F8, 0xFDD9, 0x9ED1, 0xFDDA, 0x6615, 0xFDDB, 0x6B23, 0xFDDC, 0x7098, 0xFDDD, 0x75D5, 0xFDDE, 0x5403, 0xFDDF, 0x5C79, 0xFDE0, 0x7D07, 0xFDE1, 0x8A16, 0xFDE2, 0x6B20, 0xFDE3, 0x6B3D, 0xFDE4, 0x6B46, 0xFDE5, 0x5438, 0xFDE6, 0x6070, 0xFDE7, 0x6D3D, 0xFDE8, 0x7FD5, 0xFDE9, 0x8208, 0xFDEA, 0x50D6, 0xFDEB, 0x51DE, 0xFDEC, 0x559C, 0xFDED, 0x566B, 0xFDEE, 0x56CD, 0xFDEF, 0x59EC, 0xFDF0, 0x5B09, 0xFDF1, 0x5E0C, 0xFDF2, 0x6199, 0xFDF3, 0x6198, 0xFDF4, 0x6231, 0xFDF5, 0x665E, 0xFDF6, 0x66E6, 0xFDF7, 0x7199, 0xFDF8, 0x71B9, 0xFDF9, 0x71BA, 0xFDFA, 0x72A7, 0xFDFB, 0x79A7, 0xFDFC, 0x7A00, 0xFDFD, 0x7FB2, 0xFDFE, 0x8A70, 0, 0 }; #endif #if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */ static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ 0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE, 0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346, 0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E, 0x039C, 0xA34F, 0x039D, 0xA350, 0x039E, 0xA351, 0x039F, 0xA352, 0x03A0, 0xA353, 0x03A1, 0xA354, 0x03A3, 0xA355, 0x03A4, 0xA356, 0x03A5, 0xA357, 0x03A6, 0xA358, 0x03A7, 0xA359, 0x03A8, 0xA35A, 0x03A9, 0xA35B, 0x03B1, 0xA35C, 0x03B2, 0xA35D, 0x03B3, 0xA35E, 0x03B4, 0xA35F, 0x03B5, 0xA360, 0x03B6, 0xA361, 0x03B7, 0xA362, 0x03B8, 0xA363, 0x03B9, 0xA364, 0x03BA, 0xA365, 0x03BB, 0xA366, 0x03BC, 0xA367, 0x03BD, 0xA368, 0x03BE, 0xA369, 0x03BF, 0xA36A, 0x03C0, 0xA36B, 0x03C1, 0xA36C, 0x03C3, 0xA36D, 0x03C4, 0xA36E, 0x03C5, 0xA36F, 0x03C6, 0xA370, 0x03C7, 0xA371, 0x03C8, 0xA372, 0x03C9, 0xA373, 0x2013, 0xA156, 0x2014, 0xA158, 0x2018, 0xA1A5, 0x2019, 0xA1A6, 0x201C, 0xA1A7, 0x201D, 0xA1A8, 0x2025, 0xA14C, 0x2026, 0xA14B, 0x2027, 0xA145, 0x2032, 0xA1AC, 0x2035, 0xA1AB, 0x203B, 0xA1B0, 0x20AC, 0xA3E1, 0x2103, 0xA24A, 0x2105, 0xA1C1, 0x2109, 0xA24B, 0x2160, 0xA2B9, 0x2161, 0xA2BA, 0x2162, 0xA2BB, 0x2163, 0xA2BC, 0x2164, 0xA2BD, 0x2165, 0xA2BE, 0x2166, 0xA2BF, 0x2167, 0xA2C0, 0x2168, 0xA2C1, 0x2169, 0xA2C2, 0x2190, 0xA1F6, 0x2191, 0xA1F4, 0x2192, 0xA1F7, 0x2193, 0xA1F5, 0x2196, 0xA1F8, 0x2197, 0xA1F9, 0x2198, 0xA1FB, 0x2199, 0xA1FA, 0x2215, 0xA241, 0x221A, 0xA1D4, 0x221E, 0xA1DB, 0x221F, 0xA1E8, 0x2220, 0xA1E7, 0x2223, 0xA1FD, 0x2225, 0xA1FC, 0x2229, 0xA1E4, 0x222A, 0xA1E5, 0x222B, 0xA1EC, 0x222E, 0xA1ED, 0x2234, 0xA1EF, 0x2235, 0xA1EE, 0x2252, 0xA1DC, 0x2260, 0xA1DA, 0x2261, 0xA1DD, 0x2266, 0xA1D8, 0x2267, 0xA1D9, 0x2295, 0xA1F2, 0x2299, 0xA1F3, 0x22A5, 0xA1E6, 0x22BF, 0xA1E9, 0x2500, 0xA277, 0x2502, 0xA278, 0x250C, 0xA27A, 0x2510, 0xA27B, 0x2514, 0xA27C, 0x2518, 0xA27D, 0x251C, 0xA275, 0x2524, 0xA274, 0x252C, 0xA273, 0x2534, 0xA272, 0x253C, 0xA271, 0x2550, 0xA2A4, 0x2550, 0xF9F9, 0x2551, 0xF9F8, 0x2552, 0xF9E6, 0x2553, 0xF9EF, 0x2554, 0xF9DD, 0x2555, 0xF9E8, 0x2556, 0xF9F1, 0x2557, 0xF9DF, 0x2558, 0xF9EC, 0x2559, 0xF9F5, 0x255A, 0xF9E3, 0x255B, 0xF9EE, 0x255C, 0xF9F7, 0x255D, 0xF9E5, 0x255E, 0xA2A5, 0x255E, 0xF9E9, 0x255F, 0xF9F2, 0x2560, 0xF9E0, 0x2561, 0xA2A7, 0x2561, 0xF9EB, 0x2562, 0xF9F4, 0x2563, 0xF9E2, 0x2564, 0xF9E7, 0x2565, 0xF9F0, 0x2566, 0xF9DE, 0x2567, 0xF9ED, 0x2568, 0xF9F6, 0x2569, 0xF9E4, 0x256A, 0xA2A6, 0x256A, 0xF9EA, 0x256B, 0xF9F3, 0x256C, 0xF9E1, 0x256D, 0xA27E, 0x256D, 0xF9FA, 0x256E, 0xA2A1, 0x256E, 0xF9FB, 0x256F, 0xA2A3, 0x256F, 0xF9FD, 0x2570, 0xA2A2, 0x2570, 0xF9FC, 0x2571, 0xA2AC, 0x2572, 0xA2AD, 0x2573, 0xA2AE, 0x2574, 0xA15A, 0x2581, 0xA262, 0x2582, 0xA263, 0x2583, 0xA264, 0x2584, 0xA265, 0x2585, 0xA266, 0x2586, 0xA267, 0x2587, 0xA268, 0x2588, 0xA269, 0x2589, 0xA270, 0x258A, 0xA26F, 0x258B, 0xA26E, 0x258C, 0xA26D, 0x258D, 0xA26C, 0x258E, 0xA26B, 0x258F, 0xA26A, 0x2593, 0xF9FE, 0x2594, 0xA276, 0x2595, 0xA279, 0x25A0, 0xA1BD, 0x25A1, 0xA1BC, 0x25B2, 0xA1B6, 0x25B3, 0xA1B5, 0x25BC, 0xA1BF, 0x25BD, 0xA1BE, 0x25C6, 0xA1BB, 0x25C7, 0xA1BA, 0x25CB, 0xA1B3, 0x25CE, 0xA1B7, 0x25CF, 0xA1B4, 0x25E2, 0xA2A8, 0x25E3, 0xA2A9, 0x25E4, 0xA2AB, 0x25E5, 0xA2AA, 0x2605, 0xA1B9, 0x2606, 0xA1B8, 0x2640, 0xA1F0, 0x2642, 0xA1F1, 0x3000, 0xA140, 0x3001, 0xA142, 0x3002, 0xA143, 0x3003, 0xA1B2, 0x3008, 0xA171, 0x3009, 0xA172, 0x300A, 0xA16D, 0x300B, 0xA16E, 0x300C, 0xA175, 0x300D, 0xA176, 0x300E, 0xA179, 0x300F, 0xA17A, 0x3010, 0xA169, 0x3011, 0xA16A, 0x3012, 0xA245, 0x3014, 0xA165, 0x3015, 0xA166, 0x301D, 0xA1A9, 0x301E, 0xA1AA, 0x3021, 0xA2C3, 0x3022, 0xA2C4, 0x3023, 0xA2C5, 0x3024, 0xA2C6, 0x3025, 0xA2C7, 0x3026, 0xA2C8, 0x3027, 0xA2C9, 0x3028, 0xA2CA, 0x3029, 0xA2CB, 0x3105, 0xA374, 0x3106, 0xA375, 0x3107, 0xA376, 0x3108, 0xA377, 0x3109, 0xA378, 0x310A, 0xA379, 0x310B, 0xA37A, 0x310C, 0xA37B, 0x310D, 0xA37C, 0x310E, 0xA37D, 0x310F, 0xA37E, 0x3110, 0xA3A1, 0x3111, 0xA3A2, 0x3112, 0xA3A3, 0x3113, 0xA3A4, 0x3114, 0xA3A5, 0x3115, 0xA3A6, 0x3116, 0xA3A7, 0x3117, 0xA3A8, 0x3118, 0xA3A9, 0x3119, 0xA3AA, 0x311A, 0xA3AB, 0x311B, 0xA3AC, 0x311C, 0xA3AD, 0x311D, 0xA3AE, 0x311E, 0xA3AF, 0x311F, 0xA3B0, 0x3120, 0xA3B1, 0x3121, 0xA3B2, 0x3122, 0xA3B3, 0x3123, 0xA3B4, 0x3124, 0xA3B5, 0x3125, 0xA3B6, 0x3126, 0xA3B7, 0x3127, 0xA3B8, 0x3128, 0xA3B9, 0x3129, 0xA3BA, 0x32A3, 0xA1C0, 0x338E, 0xA255, 0x338F, 0xA256, 0x339C, 0xA250, 0x339D, 0xA251, 0x339E, 0xA252, 0x33A1, 0xA254, 0x33C4, 0xA257, 0x33CE, 0xA253, 0x33D1, 0xA1EB, 0x33D2, 0xA1EA, 0x33D5, 0xA24F, 0x4E00, 0xA440, 0x4E01, 0xA442, 0x4E03, 0xA443, 0x4E07, 0xC945, 0x4E08, 0xA456, 0x4E09, 0xA454, 0x4E0A, 0xA457, 0x4E0B, 0xA455, 0x4E0C, 0xC946, 0x4E0D, 0xA4A3, 0x4E0E, 0xC94F, 0x4E0F, 0xC94D, 0x4E10, 0xA4A2, 0x4E11, 0xA4A1, 0x4E14, 0xA542, 0x4E15, 0xA541, 0x4E16, 0xA540, 0x4E18, 0xA543, 0x4E19, 0xA4FE, 0x4E1E, 0xA5E0, 0x4E1F, 0xA5E1, 0x4E26, 0xA8C3, 0x4E2B, 0xA458, 0x4E2D, 0xA4A4, 0x4E2E, 0xC950, 0x4E30, 0xA4A5, 0x4E31, 0xC963, 0x4E32, 0xA6EA, 0x4E33, 0xCBB1, 0x4E38, 0xA459, 0x4E39, 0xA4A6, 0x4E3B, 0xA544, 0x4E3C, 0xC964, 0x4E42, 0xC940, 0x4E43, 0xA444, 0x4E45, 0xA45B, 0x4E47, 0xC947, 0x4E48, 0xA45C, 0x4E4B, 0xA4A7, 0x4E4D, 0xA545, 0x4E4E, 0xA547, 0x4E4F, 0xA546, 0x4E52, 0xA5E2, 0x4E53, 0xA5E3, 0x4E56, 0xA8C4, 0x4E58, 0xADBC, 0x4E59, 0xA441, 0x4E5C, 0xC941, 0x4E5D, 0xA445, 0x4E5E, 0xA45E, 0x4E5F, 0xA45D, 0x4E69, 0xA5E4, 0x4E73, 0xA8C5, 0x4E7E, 0xB0AE, 0x4E7F, 0xD44B, 0x4E82, 0xB6C3, 0x4E83, 0xDCB1, 0x4E84, 0xDCB2, 0x4E86, 0xA446, 0x4E88, 0xA4A9, 0x4E8B, 0xA8C6, 0x4E8C, 0xA447, 0x4E8D, 0xC948, 0x4E8E, 0xA45F, 0x4E91, 0xA4AA, 0x4E92, 0xA4AC, 0x4E93, 0xC951, 0x4E94, 0xA4AD, 0x4E95, 0xA4AB, 0x4E99, 0xA5E5, 0x4E9B, 0xA8C7, 0x4E9E, 0xA8C8, 0x4E9F, 0xAB45, 0x4EA1, 0xA460, 0x4EA2, 0xA4AE, 0x4EA4, 0xA5E6, 0x4EA5, 0xA5E8, 0x4EA6, 0xA5E7, 0x4EA8, 0xA6EB, 0x4EAB, 0xA8C9, 0x4EAC, 0xA8CA, 0x4EAD, 0xAB46, 0x4EAE, 0xAB47, 0x4EB3, 0xADBD, 0x4EB6, 0xDCB3, 0x4EB9, 0xF6D6, 0x4EBA, 0xA448, 0x4EC0, 0xA4B0, 0x4EC1, 0xA4AF, 0x4EC2, 0xC952, 0x4EC3, 0xA4B1, 0x4EC4, 0xA4B7, 0x4EC6, 0xA4B2, 0x4EC7, 0xA4B3, 0x4EC8, 0xC954, 0x4EC9, 0xC953, 0x4ECA, 0xA4B5, 0x4ECB, 0xA4B6, 0x4ECD, 0xA4B4, 0x4ED4, 0xA54A, 0x4ED5, 0xA54B, 0x4ED6, 0xA54C, 0x4ED7, 0xA54D, 0x4ED8, 0xA549, 0x4ED9, 0xA550, 0x4EDA, 0xC96A, 0x4EDC, 0xC966, 0x4EDD, 0xC969, 0x4EDE, 0xA551, 0x4EDF, 0xA561, 0x4EE1, 0xC968, 0x4EE3, 0xA54E, 0x4EE4, 0xA54F, 0x4EE5, 0xA548, 0x4EE8, 0xC965, 0x4EE9, 0xC967, 0x4EF0, 0xA5F5, 0x4EF1, 0xC9B0, 0x4EF2, 0xA5F2, 0x4EF3, 0xA5F6, 0x4EF4, 0xC9BA, 0x4EF5, 0xC9AE, 0x4EF6, 0xA5F3, 0x4EF7, 0xC9B2, 0x4EFB, 0xA5F4, 0x4EFD, 0xA5F7, 0x4EFF, 0xA5E9, 0x4F00, 0xC9B1, 0x4F01, 0xA5F8, 0x4F02, 0xC9B5, 0x4F04, 0xC9B9, 0x4F05, 0xC9B6, 0x4F08, 0xC9B3, 0x4F09, 0xA5EA, 0x4F0A, 0xA5EC, 0x4F0B, 0xA5F9, 0x4F0D, 0xA5EE, 0x4F0E, 0xC9AB, 0x4F0F, 0xA5F1, 0x4F10, 0xA5EF, 0x4F11, 0xA5F0, 0x4F12, 0xC9BB, 0x4F13, 0xC9B8, 0x4F14, 0xC9AF, 0x4F15, 0xA5ED, 0x4F18, 0xC9AC, 0x4F19, 0xA5EB, 0x4F1D, 0xC9B4, 0x4F22, 0xC9B7, 0x4F2C, 0xC9AD, 0x4F2D, 0xCA66, 0x4F2F, 0xA742, 0x4F30, 0xA6F4, 0x4F33, 0xCA67, 0x4F34, 0xA6F1, 0x4F36, 0xA744, 0x4F38, 0xA6F9, 0x4F3A, 0xA6F8, 0x4F3B, 0xCA5B, 0x4F3C, 0xA6FC, 0x4F3D, 0xA6F7, 0x4F3E, 0xCA60, 0x4F3F, 0xCA68, 0x4F41, 0xCA64, 0x4F43, 0xA6FA, 0x4F46, 0xA6FD, 0x4F47, 0xA6EE, 0x4F48, 0xA747, 0x4F49, 0xCA5D, 0x4F4C, 0xCBBD, 0x4F4D, 0xA6EC, 0x4F4E, 0xA743, 0x4F4F, 0xA6ED, 0x4F50, 0xA6F5, 0x4F51, 0xA6F6, 0x4F52, 0xCA62, 0x4F53, 0xCA5E, 0x4F54, 0xA6FB, 0x4F55, 0xA6F3, 0x4F56, 0xCA5A, 0x4F57, 0xA6EF, 0x4F58, 0xCA65, 0x4F59, 0xA745, 0x4F5A, 0xA748, 0x4F5B, 0xA6F2, 0x4F5C, 0xA740, 0x4F5D, 0xA746, 0x4F5E, 0xA6F0, 0x4F5F, 0xCA63, 0x4F60, 0xA741, 0x4F61, 0xCA69, 0x4F62, 0xCA5C, 0x4F63, 0xA6FE, 0x4F64, 0xCA5F, 0x4F67, 0xCA61, 0x4F69, 0xA8D8, 0x4F6A, 0xCBBF, 0x4F6B, 0xCBCB, 0x4F6C, 0xA8D0, 0x4F6E, 0xCBCC, 0x4F6F, 0xA8CB, 0x4F70, 0xA8D5, 0x4F73, 0xA8CE, 0x4F74, 0xCBB9, 0x4F75, 0xA8D6, 0x4F76, 0xCBB8, 0x4F77, 0xCBBC, 0x4F78, 0xCBC3, 0x4F79, 0xCBC1, 0x4F7A, 0xA8DE, 0x4F7B, 0xA8D9, 0x4F7C, 0xCBB3, 0x4F7D, 0xCBB5, 0x4F7E, 0xA8DB, 0x4F7F, 0xA8CF, 0x4F80, 0xCBB6, 0x4F81, 0xCBC2, 0x4F82, 0xCBC9, 0x4F83, 0xA8D4, 0x4F84, 0xCBBB, 0x4F85, 0xCBB4, 0x4F86, 0xA8D3, 0x4F87, 0xCBB7, 0x4F88, 0xA8D7, 0x4F89, 0xCBBA, 0x4F8B, 0xA8D2, 0x4F8D, 0xA8CD, 0x4F8F, 0xA8DC, 0x4F90, 0xCBC4, 0x4F91, 0xA8DD, 0x4F92, 0xCBC8, 0x4F94, 0xCBC6, 0x4F95, 0xCBCA, 0x4F96, 0xA8DA, 0x4F97, 0xCBBE, 0x4F98, 0xCBB2, 0x4F9A, 0xCBC0, 0x4F9B, 0xA8D1, 0x4F9C, 0xCBC5, 0x4F9D, 0xA8CC, 0x4F9E, 0xCBC7, 0x4FAE, 0xAB56, 0x4FAF, 0xAB4A, 0x4FB2, 0xCDE0, 0x4FB3, 0xCDE8, 0x4FB5, 0xAB49, 0x4FB6, 0xAB51, 0x4FB7, 0xAB5D, 0x4FB9, 0xCDEE, 0x4FBA, 0xCDEC, 0x4FBB, 0xCDE7, 0x4FBF, 0xAB4B, 0x4FC0, 0xCDED, 0x4FC1, 0xCDE3, 0x4FC2, 0xAB59, 0x4FC3, 0xAB50, 0x4FC4, 0xAB58, 0x4FC5, 0xCDDE, 0x4FC7, 0xCDEA, 0x4FC9, 0xCDE1, 0x4FCA, 0xAB54, 0x4FCB, 0xCDE2, 0x4FCD, 0xCDDD, 0x4FCE, 0xAB5B, 0x4FCF, 0xAB4E, 0x4FD0, 0xAB57, 0x4FD1, 0xAB4D, 0x4FD3, 0xCDDF, 0x4FD4, 0xCDE4, 0x4FD6, 0xCDEB, 0x4FD7, 0xAB55, 0x4FD8, 0xAB52, 0x4FD9, 0xCDE6, 0x4FDA, 0xAB5A, 0x4FDB, 0xCDE9, 0x4FDC, 0xCDE5, 0x4FDD, 0xAB4F, 0x4FDE, 0xAB5C, 0x4FDF, 0xAB53, 0x4FE0, 0xAB4C, 0x4FE1, 0xAB48, 0x4FEC, 0xCDEF, 0x4FEE, 0xADD7, 0x4FEF, 0xADC1, 0x4FF1, 0xADD1, 0x4FF3, 0xADD6, 0x4FF4, 0xD0D0, 0x4FF5, 0xD0CF, 0x4FF6, 0xD0D4, 0x4FF7, 0xD0D5, 0x4FF8, 0xADC4, 0x4FFA, 0xADCD, 0x4FFE, 0xADDA, 0x5000, 0xADCE, 0x5005, 0xD0C9, 0x5006, 0xADC7, 0x5007, 0xD0CA, 0x5009, 0xADDC, 0x500B, 0xADD3, 0x500C, 0xADBE, 0x500D, 0xADBF, 0x500E, 0xD0DD, 0x500F, 0xB0BF, 0x5011, 0xADCC, 0x5012, 0xADCB, 0x5013, 0xD0CB, 0x5014, 0xADCF, 0x5015, 0xD45B, 0x5016, 0xADC6, 0x5017, 0xD0D6, 0x5018, 0xADD5, 0x5019, 0xADD4, 0x501A, 0xADCA, 0x501B, 0xD0CE, 0x501C, 0xD0D7, 0x501E, 0xD0C8, 0x501F, 0xADC9, 0x5020, 0xD0D8, 0x5021, 0xADD2, 0x5022, 0xD0CC, 0x5023, 0xADC0, 0x5025, 0xADC3, 0x5026, 0xADC2, 0x5027, 0xD0D9, 0x5028, 0xADD0, 0x5029, 0xADC5, 0x502A, 0xADD9, 0x502B, 0xADDB, 0x502C, 0xD0D3, 0x502D, 0xADD8, 0x502F, 0xD0DB, 0x5030, 0xD0CD, 0x5031, 0xD0DC, 0x5033, 0xD0D1, 0x5035, 0xD0DA, 0x5037, 0xD0D2, 0x503C, 0xADC8, 0x5040, 0xD463, 0x5041, 0xD457, 0x5043, 0xB0B3, 0x5045, 0xD45C, 0x5046, 0xD462, 0x5047, 0xB0B2, 0x5048, 0xD455, 0x5049, 0xB0B6, 0x504A, 0xD459, 0x504B, 0xD452, 0x504C, 0xB0B4, 0x504D, 0xD456, 0x504E, 0xB0B9, 0x504F, 0xB0BE, 0x5051, 0xD467, 0x5053, 0xD451, 0x5055, 0xB0BA, 0x5057, 0xD466, 0x505A, 0xB0B5, 0x505B, 0xD458, 0x505C, 0xB0B1, 0x505D, 0xD453, 0x505E, 0xD44F, 0x505F, 0xD45D, 0x5060, 0xD450, 0x5061, 0xD44E, 0x5062, 0xD45A, 0x5063, 0xD460, 0x5064, 0xD461, 0x5065, 0xB0B7, 0x5068, 0xD85B, 0x5069, 0xD45E, 0x506A, 0xD44D, 0x506B, 0xD45F, 0x506D, 0xB0C1, 0x506E, 0xD464, 0x506F, 0xB0C0, 0x5070, 0xD44C, 0x5072, 0xD454, 0x5073, 0xD465, 0x5074, 0xB0BC, 0x5075, 0xB0BB, 0x5076, 0xB0B8, 0x5077, 0xB0BD, 0x507A, 0xB0AF, 0x507D, 0xB0B0, 0x5080, 0xB3C8, 0x5082, 0xD85E, 0x5083, 0xD857, 0x5085, 0xB3C5, 0x5087, 0xD85F, 0x508B, 0xD855, 0x508C, 0xD858, 0x508D, 0xB3C4, 0x508E, 0xD859, 0x5091, 0xB3C7, 0x5092, 0xD85D, 0x5094, 0xD853, 0x5095, 0xD852, 0x5096, 0xB3C9, 0x5098, 0xB3CA, 0x5099, 0xB3C6, 0x509A, 0xB3CB, 0x509B, 0xD851, 0x509C, 0xD85C, 0x509D, 0xD85A, 0x509E, 0xD854, 0x50A2, 0xB3C3, 0x50A3, 0xD856, 0x50AC, 0xB6CA, 0x50AD, 0xB6C4, 0x50AE, 0xDCB7, 0x50AF, 0xB6CD, 0x50B0, 0xDCBD, 0x50B1, 0xDCC0, 0x50B2, 0xB6C6, 0x50B3, 0xB6C7, 0x50B4, 0xDCBA, 0x50B5, 0xB6C5, 0x50B6, 0xDCC3, 0x50B7, 0xB6CB, 0x50B8, 0xDCC4, 0x50BA, 0xDCBF, 0x50BB, 0xB6CC, 0x50BD, 0xDCB4, 0x50BE, 0xB6C9, 0x50BF, 0xDCB5, 0x50C1, 0xDCBE, 0x50C2, 0xDCBC, 0x50C4, 0xDCB8, 0x50C5, 0xB6C8, 0x50C6, 0xDCB6, 0x50C7, 0xB6CE, 0x50C8, 0xDCBB, 0x50C9, 0xDCC2, 0x50CA, 0xDCB9, 0x50CB, 0xDCC1, 0x50CE, 0xB9B6, 0x50CF, 0xB9B3, 0x50D1, 0xB9B4, 0x50D3, 0xE0F9, 0x50D4, 0xE0F1, 0x50D5, 0xB9B2, 0x50D6, 0xB9AF, 0x50D7, 0xE0F2, 0x50DA, 0xB9B1, 0x50DB, 0xE0F5, 0x50DD, 0xE0F7, 0x50E0, 0xE0FE, 0x50E3, 0xE0FD, 0x50E4, 0xE0F8, 0x50E5, 0xB9AE, 0x50E6, 0xE0F0, 0x50E7, 0xB9AC, 0x50E8, 0xE0F3, 0x50E9, 0xB9B7, 0x50EA, 0xE0F6, 0x50EC, 0xE0FA, 0x50ED, 0xB9B0, 0x50EE, 0xB9AD, 0x50EF, 0xE0FC, 0x50F0, 0xE0FB, 0x50F1, 0xB9B5, 0x50F3, 0xE0F4, 0x50F5, 0xBBF8, 0x50F6, 0xE4EC, 0x50F8, 0xE4E9, 0x50F9, 0xBBF9, 0x50FB, 0xBBF7, 0x50FD, 0xE4F0, 0x50FE, 0xE4ED, 0x50FF, 0xE4E6, 0x5100, 0xBBF6, 0x5102, 0xBBFA, 0x5103, 0xE4E7, 0x5104, 0xBBF5, 0x5105, 0xBBFD, 0x5106, 0xE4EA, 0x5107, 0xE4EB, 0x5108, 0xBBFB, 0x5109, 0xBBFC, 0x510A, 0xE4F1, 0x510B, 0xE4EE, 0x510C, 0xE4EF, 0x5110, 0xBEAA, 0x5111, 0xE8F8, 0x5112, 0xBEA7, 0x5113, 0xE8F5, 0x5114, 0xBEA9, 0x5115, 0xBEAB, 0x5117, 0xE8F6, 0x5118, 0xBEA8, 0x511A, 0xE8F7, 0x511C, 0xE8F4, 0x511F, 0xC076, 0x5120, 0xECBD, 0x5121, 0xC077, 0x5122, 0xECBB, 0x5124, 0xECBC, 0x5125, 0xECBA, 0x5126, 0xECB9, 0x5129, 0xECBE, 0x512A, 0xC075, 0x512D, 0xEFB8, 0x512E, 0xEFB9, 0x5130, 0xE4E8, 0x5131, 0xEFB7, 0x5132, 0xC078, 0x5133, 0xC35F, 0x5134, 0xF1EB, 0x5135, 0xF1EC, 0x5137, 0xC4D7, 0x5138, 0xC4D8, 0x5139, 0xF5C1, 0x513A, 0xF5C0, 0x513B, 0xC56C, 0x513C, 0xC56B, 0x513D, 0xF7D0, 0x513F, 0xA449, 0x5140, 0xA461, 0x5141, 0xA4B9, 0x5143, 0xA4B8, 0x5144, 0xA553, 0x5145, 0xA552, 0x5146, 0xA5FC, 0x5147, 0xA5FB, 0x5148, 0xA5FD, 0x5149, 0xA5FA, 0x514B, 0xA74A, 0x514C, 0xA749, 0x514D, 0xA74B, 0x5152, 0xA8E0, 0x5154, 0xA8DF, 0x5155, 0xA8E1, 0x5157, 0xAB5E, 0x5159, 0xA259, 0x515A, 0xD0DE, 0x515B, 0xA25A, 0x515C, 0xB0C2, 0x515D, 0xA25C, 0x515E, 0xA25B, 0x515F, 0xD860, 0x5161, 0xA25D, 0x5162, 0xB9B8, 0x5163, 0xA25E, 0x5165, 0xA44A, 0x5167, 0xA4BA, 0x5168, 0xA5FE, 0x5169, 0xA8E2, 0x516B, 0xA44B, 0x516C, 0xA4BD, 0x516D, 0xA4BB, 0x516E, 0xA4BC, 0x5171, 0xA640, 0x5175, 0xA74C, 0x5176, 0xA8E4, 0x5177, 0xA8E3, 0x5178, 0xA8E5, 0x517C, 0xADDD, 0x5180, 0xBEAC, 0x5187, 0xC94E, 0x5189, 0xA554, 0x518A, 0xA555, 0x518D, 0xA641, 0x518F, 0xCA6A, 0x5191, 0xAB60, 0x5192, 0xAB5F, 0x5193, 0xD0E0, 0x5194, 0xD0DF, 0x5195, 0xB0C3, 0x5197, 0xA4BE, 0x5198, 0xC955, 0x519E, 0xCBCD, 0x51A0, 0xAB61, 0x51A2, 0xADE0, 0x51A4, 0xADDE, 0x51A5, 0xADDF, 0x51AA, 0xBEAD, 0x51AC, 0xA556, 0x51B0, 0xA642, 0x51B1, 0xC9BC, 0x51B6, 0xA74D, 0x51B7, 0xA74E, 0x51B9, 0xCA6B, 0x51BC, 0xCBCE, 0x51BD, 0xA8E6, 0x51BE, 0xCBCF, 0x51C4, 0xD0E2, 0x51C5, 0xD0E3, 0x51C6, 0xADE3, 0x51C8, 0xD0E4, 0x51CA, 0xD0E1, 0x51CB, 0xADE4, 0x51CC, 0xADE2, 0x51CD, 0xADE1, 0x51CE, 0xD0E5, 0x51D0, 0xD468, 0x51D4, 0xD861, 0x51D7, 0xDCC5, 0x51D8, 0xE140, 0x51DC, 0xBBFE, 0x51DD, 0xBEAE, 0x51DE, 0xE8F9, 0x51E0, 0xA44C, 0x51E1, 0xA45A, 0x51F0, 0xB0C4, 0x51F1, 0xB3CD, 0x51F3, 0xB9B9, 0x51F5, 0xC942, 0x51F6, 0xA4BF, 0x51F8, 0xA559, 0x51F9, 0xA557, 0x51FA, 0xA558, 0x51FD, 0xA8E7, 0x5200, 0xA44D, 0x5201, 0xA44E, 0x5203, 0xA462, 0x5206, 0xA4C0, 0x5207, 0xA4C1, 0x5208, 0xA4C2, 0x5209, 0xC9BE, 0x520A, 0xA55A, 0x520C, 0xC96B, 0x520E, 0xA646, 0x5210, 0xC9BF, 0x5211, 0xA644, 0x5212, 0xA645, 0x5213, 0xC9BD, 0x5216, 0xA647, 0x5217, 0xA643, 0x521C, 0xCA6C, 0x521D, 0xAAEC, 0x521E, 0xCA6D, 0x5221, 0xCA6E, 0x5224, 0xA750, 0x5225, 0xA74F, 0x5228, 0xA753, 0x5229, 0xA751, 0x522A, 0xA752, 0x522E, 0xA8ED, 0x5230, 0xA8EC, 0x5231, 0xCBD4, 0x5232, 0xCBD1, 0x5233, 0xCBD2, 0x5235, 0xCBD0, 0x5236, 0xA8EE, 0x5237, 0xA8EA, 0x5238, 0xA8E9, 0x523A, 0xA8EB, 0x523B, 0xA8E8, 0x5241, 0xA8EF, 0x5243, 0xAB63, 0x5244, 0xCDF0, 0x5246, 0xCBD3, 0x5247, 0xAB68, 0x5249, 0xCDF1, 0x524A, 0xAB64, 0x524B, 0xAB67, 0x524C, 0xAB66, 0x524D, 0xAB65, 0x524E, 0xAB62, 0x5252, 0xD0E8, 0x5254, 0xADE7, 0x5255, 0xD0EB, 0x5256, 0xADE5, 0x525A, 0xD0E7, 0x525B, 0xADE8, 0x525C, 0xADE6, 0x525D, 0xADE9, 0x525E, 0xD0E9, 0x525F, 0xD0EA, 0x5261, 0xD0E6, 0x5262, 0xD0EC, 0x5269, 0xB3D1, 0x526A, 0xB0C5, 0x526B, 0xD469, 0x526C, 0xD46B, 0x526D, 0xD46A, 0x526E, 0xD46C, 0x526F, 0xB0C6, 0x5272, 0xB3CE, 0x5274, 0xB3CF, 0x5275, 0xB3D0, 0x5277, 0xB6D0, 0x5278, 0xDCC7, 0x527A, 0xDCC6, 0x527B, 0xDCC8, 0x527C, 0xDCC9, 0x527D, 0xB6D1, 0x527F, 0xB6CF, 0x5280, 0xE141, 0x5281, 0xE142, 0x5282, 0xB9BB, 0x5283, 0xB9BA, 0x5284, 0xE35A, 0x5287, 0xBC40, 0x5288, 0xBC41, 0x5289, 0xBC42, 0x528A, 0xBC44, 0x528B, 0xE4F2, 0x528C, 0xE4F3, 0x528D, 0xBC43, 0x5291, 0xBEAF, 0x5293, 0xBEB0, 0x5296, 0xF1ED, 0x5297, 0xF5C3, 0x5298, 0xF5C2, 0x5299, 0xF7D1, 0x529B, 0xA44F, 0x529F, 0xA55C, 0x52A0, 0xA55B, 0x52A3, 0xA648, 0x52A6, 0xC9C0, 0x52A9, 0xA755, 0x52AA, 0xA756, 0x52AB, 0xA754, 0x52AC, 0xA757, 0x52AD, 0xCA6F, 0x52AE, 0xCA70, 0x52BB, 0xA8F1, 0x52BC, 0xCBD5, 0x52BE, 0xA8F0, 0x52C0, 0xCDF2, 0x52C1, 0xAB6C, 0x52C2, 0xCDF3, 0x52C3, 0xAB6B, 0x52C7, 0xAB69, 0x52C9, 0xAB6A, 0x52CD, 0xD0ED, 0x52D2, 0xB0C7, 0x52D3, 0xD46E, 0x52D5, 0xB0CA, 0x52D6, 0xD46D, 0x52D7, 0xB1E5, 0x52D8, 0xB0C9, 0x52D9, 0xB0C8, 0x52DB, 0xB3D4, 0x52DD, 0xB3D3, 0x52DE, 0xB3D2, 0x52DF, 0xB6D2, 0x52E2, 0xB6D5, 0x52E3, 0xB6D6, 0x52E4, 0xB6D4, 0x52E6, 0xB6D3, 0x52E9, 0xE143, 0x52EB, 0xE144, 0x52EF, 0xE4F5, 0x52F0, 0xBC45, 0x52F1, 0xE4F4, 0x52F3, 0xBEB1, 0x52F4, 0xECBF, 0x52F5, 0xC079, 0x52F7, 0xF1EE, 0x52F8, 0xC455, 0x52FA, 0xA463, 0x52FB, 0xA4C3, 0x52FC, 0xC956, 0x52FE, 0xA4C4, 0x52FF, 0xA4C5, 0x5305, 0xA55D, 0x5306, 0xA55E, 0x5308, 0xA649, 0x5309, 0xCA71, 0x530A, 0xCBD6, 0x530B, 0xCBD7, 0x530D, 0xAB6D, 0x530E, 0xD0EE, 0x530F, 0xB0CC, 0x5310, 0xB0CB, 0x5311, 0xD863, 0x5312, 0xD862, 0x5315, 0xA450, 0x5316, 0xA4C6, 0x5317, 0xA55F, 0x5319, 0xB0CD, 0x531A, 0xC943, 0x531C, 0xC96C, 0x531D, 0xA560, 0x531F, 0xC9C2, 0x5320, 0xA64B, 0x5321, 0xA64A, 0x5322, 0xC9C1, 0x5323, 0xA758, 0x532A, 0xADEA, 0x532D, 0xD46F, 0x532F, 0xB6D7, 0x5330, 0xE145, 0x5331, 0xB9BC, 0x5334, 0xE8FA, 0x5337, 0xF3FD, 0x5339, 0xA4C7, 0x533C, 0xCBD8, 0x533D, 0xCDF4, 0x533E, 0xB0D0, 0x533F, 0xB0CE, 0x5340, 0xB0CF, 0x5341, 0xA2CC, 0x5341, 0xA451, 0x5343, 0xA464, 0x5344, 0xA2CD, 0x5345, 0xA2CE, 0x5345, 0xA4CA, 0x5347, 0xA4C9, 0x5348, 0xA4C8, 0x5349, 0xA563, 0x534A, 0xA562, 0x534C, 0xC96D, 0x534D, 0xC9C3, 0x5351, 0xA8F5, 0x5352, 0xA8F2, 0x5353, 0xA8F4, 0x5354, 0xA8F3, 0x5357, 0xAB6E, 0x535A, 0xB3D5, 0x535C, 0xA452, 0x535E, 0xA4CB, 0x5360, 0xA565, 0x5361, 0xA564, 0x5363, 0xCA72, 0x5366, 0xA8F6, 0x536C, 0xC957, 0x536E, 0xA567, 0x536F, 0xA566, 0x5370, 0xA64C, 0x5371, 0xA64D, 0x5372, 0xCA73, 0x5373, 0xA759, 0x5375, 0xA75A, 0x5377, 0xA8F7, 0x5378, 0xA8F8, 0x5379, 0xA8F9, 0x537B, 0xAB6F, 0x537C, 0xCDF5, 0x537F, 0xADEB, 0x5382, 0xC944, 0x5384, 0xA4CC, 0x538A, 0xC9C4, 0x538E, 0xCA74, 0x538F, 0xCA75, 0x5392, 0xCBD9, 0x5394, 0xCBDA, 0x5396, 0xCDF7, 0x5397, 0xCDF6, 0x5398, 0xCDF9, 0x5399, 0xCDF8, 0x539A, 0xAB70, 0x539C, 0xD470, 0x539D, 0xADED, 0x539E, 0xD0EF, 0x539F, 0xADEC, 0x53A4, 0xD864, 0x53A5, 0xB3D6, 0x53A7, 0xD865, 0x53AC, 0xE146, 0x53AD, 0xB9BD, 0x53B2, 0xBC46, 0x53B4, 0xF1EF, 0x53B9, 0xC958, 0x53BB, 0xA568, 0x53C3, 0xB0D1, 0x53C8, 0xA453, 0x53C9, 0xA465, 0x53CA, 0xA4CE, 0x53CB, 0xA4CD, 0x53CD, 0xA4CF, 0x53D4, 0xA8FB, 0x53D6, 0xA8FA, 0x53D7, 0xA8FC, 0x53DB, 0xAB71, 0x53DF, 0xADEE, 0x53E1, 0xE8FB, 0x53E2, 0xC24F, 0x53E3, 0xA466, 0x53E4, 0xA56A, 0x53E5, 0xA579, 0x53E6, 0xA574, 0x53E8, 0xA56F, 0x53E9, 0xA56E, 0x53EA, 0xA575, 0x53EB, 0xA573, 0x53EC, 0xA56C, 0x53ED, 0xA57A, 0x53EE, 0xA56D, 0x53EF, 0xA569, 0x53F0, 0xA578, 0x53F1, 0xA577, 0x53F2, 0xA576, 0x53F3, 0xA56B, 0x53F5, 0xA572, 0x53F8, 0xA571, 0x53FB, 0xA57B, 0x53FC, 0xA570, 0x5401, 0xA653, 0x5403, 0xA659, 0x5404, 0xA655, 0x5406, 0xA65B, 0x5407, 0xC9C5, 0x5408, 0xA658, 0x5409, 0xA64E, 0x540A, 0xA651, 0x540B, 0xA654, 0x540C, 0xA650, 0x540D, 0xA657, 0x540E, 0xA65A, 0x540F, 0xA64F, 0x5410, 0xA652, 0x5411, 0xA656, 0x5412, 0xA65C, 0x5418, 0xCA7E, 0x5419, 0xCA7B, 0x541B, 0xA767, 0x541C, 0xCA7C, 0x541D, 0xA75B, 0x541E, 0xA75D, 0x541F, 0xA775, 0x5420, 0xA770, 0x5424, 0xCAA5, 0x5425, 0xCA7D, 0x5426, 0xA75F, 0x5427, 0xA761, 0x5428, 0xCAA4, 0x5429, 0xA768, 0x542A, 0xCA78, 0x542B, 0xA774, 0x542C, 0xA776, 0x542D, 0xA75C, 0x542E, 0xA76D, 0x5430, 0xCA76, 0x5431, 0xA773, 0x5433, 0xA764, 0x5435, 0xA76E, 0x5436, 0xA76F, 0x5437, 0xCA77, 0x5438, 0xA76C, 0x5439, 0xA76A, 0x543B, 0xA76B, 0x543C, 0xA771, 0x543D, 0xCAA1, 0x543E, 0xA75E, 0x5440, 0xA772, 0x5441, 0xCAA3, 0x5442, 0xA766, 0x5443, 0xA763, 0x5445, 0xCA7A, 0x5446, 0xA762, 0x5447, 0xCAA6, 0x5448, 0xA765, 0x544A, 0xA769, 0x544E, 0xA760, 0x544F, 0xCAA2, 0x5454, 0xCA79, 0x5460, 0xCBEB, 0x5461, 0xCBEA, 0x5462, 0xA94F, 0x5463, 0xCBED, 0x5464, 0xCBEF, 0x5465, 0xCBE4, 0x5466, 0xCBE7, 0x5467, 0xCBEE, 0x5468, 0xA950, 0x546B, 0xCBE1, 0x546C, 0xCBE5, 0x546F, 0xCBE9, 0x5470, 0xCE49, 0x5471, 0xA94B, 0x5472, 0xCE4D, 0x5473, 0xA8FD, 0x5474, 0xCBE6, 0x5475, 0xA8FE, 0x5476, 0xA94C, 0x5477, 0xA945, 0x5478, 0xA941, 0x547A, 0xCBE2, 0x547B, 0xA944, 0x547C, 0xA949, 0x547D, 0xA952, 0x547E, 0xCBE3, 0x547F, 0xCBDC, 0x5480, 0xA943, 0x5481, 0xCBDD, 0x5482, 0xCBDF, 0x5484, 0xA946, 0x5486, 0xA948, 0x5487, 0xCBDB, 0x5488, 0xCBE0, 0x548B, 0xA951, 0x548C, 0xA94D, 0x548D, 0xCBE8, 0x548E, 0xA953, 0x5490, 0xA94A, 0x5491, 0xCBDE, 0x5492, 0xA947, 0x5495, 0xA942, 0x5496, 0xA940, 0x5498, 0xCBEC, 0x549A, 0xA94E, 0x54A0, 0xCE48, 0x54A1, 0xCDFB, 0x54A2, 0xCE4B, 0x54A5, 0xCDFD, 0x54A6, 0xAB78, 0x54A7, 0xABA8, 0x54A8, 0xAB74, 0x54A9, 0xABA7, 0x54AA, 0xAB7D, 0x54AB, 0xABA4, 0x54AC, 0xAB72, 0x54AD, 0xCDFC, 0x54AE, 0xCE43, 0x54AF, 0xABA3, 0x54B0, 0xCE4F, 0x54B1, 0xABA5, 0x54B3, 0xAB79, 0x54B6, 0xCE45, 0x54B7, 0xCE42, 0x54B8, 0xAB77, 0x54BA, 0xCDFA, 0x54BB, 0xABA6, 0x54BC, 0xCE4A, 0x54BD, 0xAB7C, 0x54BE, 0xCE4C, 0x54BF, 0xABA9, 0x54C0, 0xAB73, 0x54C1, 0xAB7E, 0x54C2, 0xAB7B, 0x54C3, 0xCE40, 0x54C4, 0xABA1, 0x54C5, 0xCE46, 0x54C6, 0xCE47, 0x54C7, 0xAB7A, 0x54C8, 0xABA2, 0x54C9, 0xAB76, 0x54CE, 0xAB75, 0x54CF, 0xCDFE, 0x54D6, 0xCE44, 0x54DE, 0xCE4E, 0x54E0, 0xD144, 0x54E1, 0xADFB, 0x54E2, 0xD0F1, 0x54E4, 0xD0F6, 0x54E5, 0xADF4, 0x54E6, 0xAE40, 0x54E7, 0xD0F4, 0x54E8, 0xADEF, 0x54E9, 0xADF9, 0x54EA, 0xADFE, 0x54EB, 0xD0FB, 0x54ED, 0xADFA, 0x54EE, 0xADFD, 0x54F1, 0xD0FE, 0x54F2, 0xADF5, 0x54F3, 0xD0F5, 0x54F7, 0xD142, 0x54F8, 0xD143, 0x54FA, 0xADF7, 0x54FB, 0xD141, 0x54FC, 0xADF3, 0x54FD, 0xAE43, 0x54FF, 0xD0F8, 0x5501, 0xADF1, 0x5503, 0xD146, 0x5504, 0xD0F9, 0x5505, 0xD0FD, 0x5506, 0xADF6, 0x5507, 0xAE42, 0x5508, 0xD0FA, 0x5509, 0xADFC, 0x550A, 0xD140, 0x550B, 0xD147, 0x550C, 0xD4A1, 0x550E, 0xD145, 0x550F, 0xAE44, 0x5510, 0xADF0, 0x5511, 0xD0FC, 0x5512, 0xD0F3, 0x5514, 0xADF8, 0x5517, 0xD0F2, 0x551A, 0xD0F7, 0x5526, 0xD0F0, 0x5527, 0xAE41, 0x552A, 0xD477, 0x552C, 0xB0E4, 0x552D, 0xD4A7, 0x552E, 0xB0E2, 0x552F, 0xB0DF, 0x5530, 0xD47C, 0x5531, 0xB0DB, 0x5532, 0xD4A2, 0x5533, 0xB0E6, 0x5534, 0xD476, 0x5535, 0xD47B, 0x5536, 0xD47A, 0x5537, 0xADF2, 0x5538, 0xB0E1, 0x5539, 0xD4A5, 0x553B, 0xD4A8, 0x553C, 0xD473, 0x553E, 0xB3E8, 0x5540, 0xD4A9, 0x5541, 0xB0E7, 0x5543, 0xB0D9, 0x5544, 0xB0D6, 0x5545, 0xD47E, 0x5546, 0xB0D3, 0x5548, 0xD4A6, 0x554A, 0xB0DA, 0x554B, 0xD4AA, 0x554D, 0xD474, 0x554E, 0xD4A4, 0x554F, 0xB0DD, 0x5550, 0xD475, 0x5551, 0xD478, 0x5552, 0xD47D, 0x5555, 0xB0DE, 0x5556, 0xB0DC, 0x5557, 0xB0E8, 0x555C, 0xB0E3, 0x555E, 0xB0D7, 0x555F, 0xB1D2, 0x5561, 0xB0D8, 0x5562, 0xD479, 0x5563, 0xB0E5, 0x5564, 0xB0E0, 0x5565, 0xD4A3, 0x5566, 0xB0D5, 0x556A, 0xB0D4, 0x5575, 0xD471, 0x5576, 0xD472, 0x5577, 0xD86A, 0x557B, 0xB3D7, 0x557C, 0xB3DA, 0x557D, 0xD875, 0x557E, 0xB3EE, 0x557F, 0xD878, 0x5580, 0xB3D8, 0x5581, 0xD871, 0x5582, 0xB3DE, 0x5583, 0xB3E4, 0x5584, 0xB5BD, 0x5587, 0xB3E2, 0x5588, 0xD86E, 0x5589, 0xB3EF, 0x558A, 0xB3DB, 0x558B, 0xB3E3, 0x558C, 0xD876, 0x558D, 0xDCD7, 0x558E, 0xD87B, 0x558F, 0xD86F, 0x5591, 0xD866, 0x5592, 0xD873, 0x5593, 0xD86D, 0x5594, 0xB3E1, 0x5595, 0xD879, 0x5598, 0xB3DD, 0x5599, 0xB3F1, 0x559A, 0xB3EA, 0x559C, 0xB3DF, 0x559D, 0xB3DC, 0x559F, 0xB3E7, 0x55A1, 0xD87A, 0x55A2, 0xD86C, 0x55A3, 0xD872, 0x55A4, 0xD874, 0x55A5, 0xD868, 0x55A6, 0xD877, 0x55A7, 0xB3D9, 0x55A8, 0xD867, 0x55AA, 0xB3E0, 0x55AB, 0xB3F0, 0x55AC, 0xB3EC, 0x55AD, 0xD869, 0x55AE, 0xB3E6, 0x55B1, 0xB3ED, 0x55B2, 0xB3E9, 0x55B3, 0xB3E5, 0x55B5, 0xD870, 0x55BB, 0xB3EB, 0x55BF, 0xDCD5, 0x55C0, 0xDCD1, 0x55C2, 0xDCE0, 0x55C3, 0xDCCA, 0x55C4, 0xDCD3, 0x55C5, 0xB6E5, 0x55C6, 0xB6E6, 0x55C7, 0xB6DE, 0x55C8, 0xDCDC, 0x55C9, 0xB6E8, 0x55CA, 0xDCCF, 0x55CB, 0xDCCE, 0x55CC, 0xDCCC, 0x55CD, 0xDCDE, 0x55CE, 0xB6DC, 0x55CF, 0xDCD8, 0x55D0, 0xDCCD, 0x55D1, 0xB6DF, 0x55D2, 0xDCD6, 0x55D3, 0xB6DA, 0x55D4, 0xDCD2, 0x55D5, 0xDCD9, 0x55D6, 0xDCDB, 0x55D9, 0xDCDF, 0x55DA, 0xB6E3, 0x55DB, 0xDCCB, 0x55DC, 0xB6DD, 0x55DD, 0xDCD0, 0x55DF, 0xB6D8, 0x55E1, 0xB6E4, 0x55E2, 0xDCDA, 0x55E3, 0xB6E0, 0x55E4, 0xB6E1, 0x55E5, 0xB6E7, 0x55E6, 0xB6DB, 0x55E7, 0xA25F, 0x55E8, 0xB6D9, 0x55E9, 0xDCD4, 0x55EF, 0xB6E2, 0x55F2, 0xDCDD, 0x55F6, 0xB9CD, 0x55F7, 0xB9C8, 0x55F9, 0xE155, 0x55FA, 0xE151, 0x55FC, 0xE14B, 0x55FD, 0xB9C2, 0x55FE, 0xB9BE, 0x55FF, 0xE154, 0x5600, 0xB9BF, 0x5601, 0xE14E, 0x5602, 0xE150, 0x5604, 0xE153, 0x5606, 0xB9C4, 0x5608, 0xB9CB, 0x5609, 0xB9C5, 0x560C, 0xE149, 0x560D, 0xB9C6, 0x560E, 0xB9C7, 0x560F, 0xE14C, 0x5610, 0xB9CC, 0x5612, 0xE14A, 0x5613, 0xE14F, 0x5614, 0xB9C3, 0x5615, 0xE148, 0x5616, 0xB9C9, 0x5617, 0xB9C1, 0x561B, 0xB9C0, 0x561C, 0xE14D, 0x561D, 0xE152, 0x561F, 0xB9CA, 0x5627, 0xE147, 0x5629, 0xBC4D, 0x562A, 0xE547, 0x562C, 0xE544, 0x562E, 0xBC47, 0x562F, 0xBC53, 0x5630, 0xBC54, 0x5632, 0xBC4A, 0x5633, 0xE542, 0x5634, 0xBC4C, 0x5635, 0xE4F9, 0x5636, 0xBC52, 0x5638, 0xE546, 0x5639, 0xBC49, 0x563A, 0xE548, 0x563B, 0xBC48, 0x563D, 0xE543, 0x563E, 0xE545, 0x563F, 0xBC4B, 0x5640, 0xE541, 0x5641, 0xE4FA, 0x5642, 0xE4F7, 0x5645, 0xD86B, 0x5646, 0xE4FD, 0x5648, 0xE4F6, 0x5649, 0xE4FC, 0x564A, 0xE4FB, 0x564C, 0xE4F8, 0x564E, 0xBC4F, 0x5653, 0xBC4E, 0x5657, 0xBC50, 0x5658, 0xE4FE, 0x5659, 0xBEB2, 0x565A, 0xE540, 0x565E, 0xE945, 0x5660, 0xE8FD, 0x5662, 0xBEBE, 0x5663, 0xE942, 0x5664, 0xBEB6, 0x5665, 0xBEBA, 0x5666, 0xE941, 0x5668, 0xBEB9, 0x5669, 0xBEB5, 0x566A, 0xBEB8, 0x566B, 0xBEB3, 0x566C, 0xBEBD, 0x566D, 0xE943, 0x566E, 0xE8FE, 0x566F, 0xBEBC, 0x5670, 0xE8FC, 0x5671, 0xBEBB, 0x5672, 0xE944, 0x5673, 0xE940, 0x5674, 0xBC51, 0x5676, 0xBEBF, 0x5677, 0xE946, 0x5678, 0xBEB7, 0x5679, 0xBEB4, 0x567E, 0xECC6, 0x567F, 0xECC8, 0x5680, 0xC07B, 0x5681, 0xECC9, 0x5682, 0xECC7, 0x5683, 0xECC5, 0x5684, 0xECC4, 0x5685, 0xC07D, 0x5686, 0xECC3, 0x5687, 0xC07E, 0x568C, 0xECC1, 0x568D, 0xECC2, 0x568E, 0xC07A, 0x568F, 0xC0A1, 0x5690, 0xC07C, 0x5693, 0xECC0, 0x5695, 0xC250, 0x5697, 0xEFBC, 0x5698, 0xEFBA, 0x5699, 0xEFBF, 0x569A, 0xEFBD, 0x569C, 0xEFBB, 0x569D, 0xEFBE, 0x56A5, 0xC360, 0x56A6, 0xF1F2, 0x56A7, 0xF1F3, 0x56A8, 0xC456, 0x56AA, 0xF1F4, 0x56AB, 0xF1F0, 0x56AC, 0xF1F5, 0x56AD, 0xF1F1, 0x56AE, 0xC251, 0x56B2, 0xF3FE, 0x56B3, 0xF441, 0x56B4, 0xC459, 0x56B5, 0xF440, 0x56B6, 0xC458, 0x56B7, 0xC457, 0x56BC, 0xC45A, 0x56BD, 0xF5C5, 0x56BE, 0xF5C6, 0x56C0, 0xC4DA, 0x56C1, 0xC4D9, 0x56C2, 0xC4DB, 0x56C3, 0xF5C4, 0x56C5, 0xF6D8, 0x56C6, 0xF6D7, 0x56C8, 0xC56D, 0x56C9, 0xC56F, 0x56CA, 0xC56E, 0x56CB, 0xF6D9, 0x56CC, 0xC5C8, 0x56CD, 0xF8A6, 0x56D1, 0xC5F1, 0x56D3, 0xF8A5, 0x56D4, 0xF8EE, 0x56D7, 0xC949, 0x56DA, 0xA57D, 0x56DB, 0xA57C, 0x56DD, 0xA65F, 0x56DE, 0xA65E, 0x56DF, 0xC9C7, 0x56E0, 0xA65D, 0x56E1, 0xC9C6, 0x56E4, 0xA779, 0x56E5, 0xCAA9, 0x56E7, 0xCAA8, 0x56EA, 0xA777, 0x56EB, 0xA77A, 0x56EE, 0xCAA7, 0x56F0, 0xA778, 0x56F7, 0xCBF0, 0x56F9, 0xCBF1, 0x56FA, 0xA954, 0x56FF, 0xABAA, 0x5701, 0xD148, 0x5702, 0xD149, 0x5703, 0xAE45, 0x5704, 0xAE46, 0x5707, 0xD4AC, 0x5708, 0xB0E9, 0x5709, 0xB0EB, 0x570A, 0xD4AB, 0x570B, 0xB0EA, 0x570C, 0xD87C, 0x570D, 0xB3F2, 0x5712, 0xB6E9, 0x5713, 0xB6EA, 0x5714, 0xDCE1, 0x5716, 0xB9CF, 0x5718, 0xB9CE, 0x571A, 0xE549, 0x571B, 0xE948, 0x571C, 0xE947, 0x571E, 0xF96B, 0x571F, 0xA467, 0x5720, 0xC959, 0x5722, 0xC96E, 0x5723, 0xC96F, 0x5728, 0xA662, 0x5729, 0xA666, 0x572A, 0xC9C9, 0x572C, 0xA664, 0x572D, 0xA663, 0x572E, 0xC9C8, 0x572F, 0xA665, 0x5730, 0xA661, 0x5733, 0xA660, 0x5734, 0xC9CA, 0x573B, 0xA7A6, 0x573E, 0xA7A3, 0x5740, 0xA77D, 0x5741, 0xCAAA, 0x5745, 0xCAAB, 0x5747, 0xA7A1, 0x5749, 0xCAAD, 0x574A, 0xA77B, 0x574B, 0xCAAE, 0x574C, 0xCAAC, 0x574D, 0xA77E, 0x574E, 0xA7A2, 0x574F, 0xA7A5, 0x5750, 0xA7A4, 0x5751, 0xA77C, 0x5752, 0xCAAF, 0x5761, 0xA959, 0x5762, 0xCBFE, 0x5764, 0xA95B, 0x5766, 0xA95A, 0x5768, 0xCC40, 0x5769, 0xA958, 0x576A, 0xA957, 0x576B, 0xCBF5, 0x576D, 0xCBF4, 0x576F, 0xCBF2, 0x5770, 0xCBF7, 0x5771, 0xCBF6, 0x5772, 0xCBF3, 0x5773, 0xCBFC, 0x5774, 0xCBFD, 0x5775, 0xCBFA, 0x5776, 0xCBF8, 0x5777, 0xA956, 0x577B, 0xCBFB, 0x577C, 0xA95C, 0x577D, 0xCC41, 0x5780, 0xCBF9, 0x5782, 0xABAB, 0x5783, 0xA955, 0x578B, 0xABAC, 0x578C, 0xCE54, 0x578F, 0xCE5A, 0x5793, 0xABB2, 0x5794, 0xCE58, 0x5795, 0xCE5E, 0x5797, 0xCE55, 0x5798, 0xCE59, 0x5799, 0xCE5B, 0x579A, 0xCE5D, 0x579B, 0xCE57, 0x579D, 0xCE56, 0x579E, 0xCE51, 0x579F, 0xCE52, 0x57A0, 0xABAD, 0x57A2, 0xABAF, 0x57A3, 0xABAE, 0x57A4, 0xCE53, 0x57A5, 0xCE5C, 0x57AE, 0xABB1, 0x57B5, 0xCE50, 0x57B6, 0xD153, 0x57B8, 0xD152, 0x57B9, 0xD157, 0x57BA, 0xD14E, 0x57BC, 0xD151, 0x57BD, 0xD150, 0x57BF, 0xD154, 0x57C1, 0xD158, 0x57C2, 0xAE47, 0x57C3, 0xAE4A, 0x57C6, 0xD14F, 0x57C7, 0xD155, 0x57CB, 0xAE49, 0x57CC, 0xD14A, 0x57CE, 0xABB0, 0x57CF, 0xD4BA, 0x57D0, 0xD156, 0x57D2, 0xD14D, 0x57D4, 0xAE48, 0x57D5, 0xD14C, 0x57DC, 0xD4B1, 0x57DF, 0xB0EC, 0x57E0, 0xB0F0, 0x57E1, 0xD4C1, 0x57E2, 0xD4AF, 0x57E3, 0xD4BD, 0x57E4, 0xB0F1, 0x57E5, 0xD4BF, 0x57E7, 0xD4C5, 0x57E9, 0xD4C9, 0x57EC, 0xD4C0, 0x57ED, 0xD4B4, 0x57EE, 0xD4BC, 0x57F0, 0xD4CA, 0x57F1, 0xD4C8, 0x57F2, 0xD4BE, 0x57F3, 0xD4B9, 0x57F4, 0xD4B2, 0x57F5, 0xD8A6, 0x57F6, 0xD4B0, 0x57F7, 0xB0F5, 0x57F8, 0xD4B7, 0x57F9, 0xB0F6, 0x57FA, 0xB0F2, 0x57FB, 0xD4AD, 0x57FC, 0xD4C3, 0x57FD, 0xD4B5, 0x5800, 0xD4B3, 0x5801, 0xD4C6, 0x5802, 0xB0F3, 0x5804, 0xD4CC, 0x5805, 0xB0ED, 0x5806, 0xB0EF, 0x5807, 0xD4BB, 0x5808, 0xD4B6, 0x5809, 0xAE4B, 0x580A, 0xB0EE, 0x580B, 0xD4B8, 0x580C, 0xD4C7, 0x580D, 0xD4CB, 0x580E, 0xD4C2, 0x5810, 0xD4C4, 0x5814, 0xD4AE, 0x5819, 0xD8A1, 0x581B, 0xD8AA, 0x581C, 0xD8A9, 0x581D, 0xB3FA, 0x581E, 0xD8A2, 0x5820, 0xB3FB, 0x5821, 0xB3F9, 0x5823, 0xD8A4, 0x5824, 0xB3F6, 0x5825, 0xD8A8, 0x5827, 0xD8A3, 0x5828, 0xD8A5, 0x5829, 0xD87D, 0x582A, 0xB3F4, 0x582C, 0xD8B2, 0x582D, 0xD8B1, 0x582E, 0xD8AE, 0x582F, 0xB3F3, 0x5830, 0xB3F7, 0x5831, 0xB3F8, 0x5832, 0xD14B, 0x5833, 0xD8AB, 0x5834, 0xB3F5, 0x5835, 0xB0F4, 0x5836, 0xD8AD, 0x5837, 0xD87E, 0x5838, 0xD8B0, 0x5839, 0xD8AF, 0x583B, 0xD8B3, 0x583D, 0xDCEF, 0x583F, 0xD8AC, 0x5848, 0xD8A7, 0x5849, 0xDCE7, 0x584A, 0xB6F4, 0x584B, 0xB6F7, 0x584C, 0xB6F2, 0x584D, 0xDCE6, 0x584E, 0xDCEA, 0x584F, 0xDCE5, 0x5851, 0xB6EC, 0x5852, 0xB6F6, 0x5853, 0xDCE2, 0x5854, 0xB6F0, 0x5855, 0xDCE9, 0x5857, 0xB6EE, 0x5858, 0xB6ED, 0x5859, 0xDCEC, 0x585A, 0xB6EF, 0x585B, 0xDCEE, 0x585D, 0xDCEB, 0x585E, 0xB6EB, 0x5862, 0xB6F5, 0x5863, 0xDCF0, 0x5864, 0xDCE4, 0x5865, 0xDCED, 0x5868, 0xDCE3, 0x586B, 0xB6F1, 0x586D, 0xB6F3, 0x586F, 0xDCE8, 0x5871, 0xDCF1, 0x5874, 0xE15D, 0x5875, 0xB9D0, 0x5876, 0xE163, 0x5879, 0xB9D5, 0x587A, 0xE15F, 0x587B, 0xE166, 0x587C, 0xE157, 0x587D, 0xB9D7, 0x587E, 0xB9D1, 0x587F, 0xE15C, 0x5880, 0xBC55, 0x5881, 0xE15B, 0x5882, 0xE164, 0x5883, 0xB9D2, 0x5885, 0xB9D6, 0x5886, 0xE15A, 0x5887, 0xE160, 0x5888, 0xE165, 0x5889, 0xE156, 0x588A, 0xB9D4, 0x588B, 0xE15E, 0x588E, 0xE162, 0x588F, 0xE168, 0x5890, 0xE158, 0x5891, 0xE161, 0x5893, 0xB9D3, 0x5894, 0xE167, 0x5898, 0xE159, 0x589C, 0xBC59, 0x589D, 0xE54B, 0x589E, 0xBC57, 0x589F, 0xBC56, 0x58A0, 0xE54D, 0x58A1, 0xE552, 0x58A3, 0xE54E, 0x58A5, 0xE551, 0x58A6, 0xBC5C, 0x58A8, 0xBEA5, 0x58A9, 0xBC5B, 0x58AB, 0xE54A, 0x58AC, 0xE550, 0x58AE, 0xBC5A, 0x58AF, 0xE54F, 0x58B1, 0xE54C, 0x58B3, 0xBC58, 0x58BA, 0xE94D, 0x58BB, 0xF9D9, 0x58BC, 0xE94F, 0x58BD, 0xE94A, 0x58BE, 0xBEC1, 0x58BF, 0xE94C, 0x58C1, 0xBEC0, 0x58C2, 0xE94E, 0x58C5, 0xBEC3, 0x58C6, 0xE950, 0x58C7, 0xBEC2, 0x58C8, 0xE949, 0x58C9, 0xE94B, 0x58CE, 0xC0A5, 0x58CF, 0xECCC, 0x58D1, 0xC0A4, 0x58D2, 0xECCD, 0x58D3, 0xC0A3, 0x58D4, 0xECCB, 0x58D5, 0xC0A2, 0x58D6, 0xECCA, 0x58D8, 0xC253, 0x58D9, 0xC252, 0x58DA, 0xF1F6, 0x58DB, 0xF1F8, 0x58DD, 0xF1F7, 0x58DE, 0xC361, 0x58DF, 0xC362, 0x58E2, 0xC363, 0x58E3, 0xF442, 0x58E4, 0xC45B, 0x58E7, 0xF7D3, 0x58E8, 0xF7D2, 0x58E9, 0xC5F2, 0x58EB, 0xA468, 0x58EC, 0xA4D0, 0x58EF, 0xA7A7, 0x58F4, 0xCE5F, 0x58F9, 0xB3FC, 0x58FA, 0xB3FD, 0x58FC, 0xDCF2, 0x58FD, 0xB9D8, 0x58FE, 0xE169, 0x58FF, 0xE553, 0x5903, 0xC95A, 0x5906, 0xCAB0, 0x590C, 0xCC42, 0x590D, 0xCE60, 0x590E, 0xD159, 0x590F, 0xAE4C, 0x5912, 0xF1F9, 0x5914, 0xC4DC, 0x5915, 0xA469, 0x5916, 0xA57E, 0x5917, 0xC970, 0x5919, 0xA667, 0x591A, 0xA668, 0x591C, 0xA95D, 0x5920, 0xB0F7, 0x5922, 0xB9DA, 0x5924, 0xB9DB, 0x5925, 0xB9D9, 0x5927, 0xA46A, 0x5929, 0xA4D1, 0x592A, 0xA4D3, 0x592B, 0xA4D2, 0x592C, 0xC95B, 0x592D, 0xA4D4, 0x592E, 0xA5A1, 0x592F, 0xC971, 0x5931, 0xA5A2, 0x5937, 0xA669, 0x5938, 0xA66A, 0x593C, 0xC9CB, 0x593E, 0xA7A8, 0x5940, 0xCAB1, 0x5944, 0xA961, 0x5945, 0xCC43, 0x5947, 0xA95F, 0x5948, 0xA960, 0x5949, 0xA95E, 0x594A, 0xD15A, 0x594E, 0xABB6, 0x594F, 0xABB5, 0x5950, 0xABB7, 0x5951, 0xABB4, 0x5953, 0xCE61, 0x5954, 0xA962, 0x5955, 0xABB3, 0x5957, 0xAE4D, 0x5958, 0xAE4E, 0x595A, 0xAE4F, 0x595C, 0xD4CD, 0x5960, 0xB3FE, 0x5961, 0xD8B4, 0x5962, 0xB0F8, 0x5967, 0xB6F8, 0x5969, 0xB9DD, 0x596A, 0xB9DC, 0x596B, 0xE16A, 0x596D, 0xBC5D, 0x596E, 0xBEC4, 0x5970, 0xEFC0, 0x5971, 0xF6DA, 0x5972, 0xF7D4, 0x5973, 0xA46B, 0x5974, 0xA5A3, 0x5976, 0xA5A4, 0x5977, 0xC9D1, 0x5978, 0xA66C, 0x5979, 0xA66F, 0x597B, 0xC9CF, 0x597C, 0xC9CD, 0x597D, 0xA66E, 0x597E, 0xC9D0, 0x597F, 0xC9D2, 0x5980, 0xC9CC, 0x5981, 0xA671, 0x5982, 0xA670, 0x5983, 0xA66D, 0x5984, 0xA66B, 0x5985, 0xC9CE, 0x598A, 0xA7B3, 0x598D, 0xA7B0, 0x598E, 0xCAB6, 0x598F, 0xCAB9, 0x5990, 0xCAB8, 0x5992, 0xA7AA, 0x5993, 0xA7B2, 0x5996, 0xA7AF, 0x5997, 0xCAB5, 0x5998, 0xCAB3, 0x5999, 0xA7AE, 0x599D, 0xA7A9, 0x599E, 0xA7AC, 0x59A0, 0xCAB4, 0x59A1, 0xCABB, 0x59A2, 0xCAB7, 0x59A3, 0xA7AD, 0x59A4, 0xA7B1, 0x59A5, 0xA7B4, 0x59A6, 0xCAB2, 0x59A7, 0xCABA, 0x59A8, 0xA7AB, 0x59AE, 0xA967, 0x59AF, 0xA96F, 0x59B1, 0xCC4F, 0x59B2, 0xCC48, 0x59B3, 0xA970, 0x59B4, 0xCC53, 0x59B5, 0xCC44, 0x59B6, 0xCC4B, 0x59B9, 0xA966, 0x59BA, 0xCC45, 0x59BB, 0xA964, 0x59BC, 0xCC4C, 0x59BD, 0xCC50, 0x59BE, 0xA963, 0x59C0, 0xCC51, 0x59C1, 0xCC4A, 0x59C3, 0xCC4D, 0x59C5, 0xA972, 0x59C6, 0xA969, 0x59C7, 0xCC54, 0x59C8, 0xCC52, 0x59CA, 0xA96E, 0x59CB, 0xA96C, 0x59CC, 0xCC49, 0x59CD, 0xA96B, 0x59CE, 0xCC47, 0x59CF, 0xCC46, 0x59D0, 0xA96A, 0x59D1, 0xA968, 0x59D2, 0xA971, 0x59D3, 0xA96D, 0x59D4, 0xA965, 0x59D6, 0xCC4E, 0x59D8, 0xABB9, 0x59DA, 0xABC0, 0x59DB, 0xCE6F, 0x59DC, 0xABB8, 0x59DD, 0xCE67, 0x59DE, 0xCE63, 0x59E0, 0xCE73, 0x59E1, 0xCE62, 0x59E3, 0xABBB, 0x59E4, 0xCE6C, 0x59E5, 0xABBE, 0x59E6, 0xABC1, 0x59E8, 0xABBC, 0x59E9, 0xCE70, 0x59EA, 0xABBF, 0x59EC, 0xAE56, 0x59ED, 0xCE76, 0x59EE, 0xCE64, 0x59F1, 0xCE66, 0x59F2, 0xCE6D, 0x59F3, 0xCE71, 0x59F4, 0xCE75, 0x59F5, 0xCE72, 0x59F6, 0xCE6B, 0x59F7, 0xCE6E, 0x59FA, 0xCE68, 0x59FB, 0xABC3, 0x59FC, 0xCE6A, 0x59FD, 0xCE69, 0x59FE, 0xCE74, 0x59FF, 0xABBA, 0x5A00, 0xCE65, 0x5A01, 0xABC2, 0x5A03, 0xABBD, 0x5A09, 0xAE5C, 0x5A0A, 0xD162, 0x5A0C, 0xAE5B, 0x5A0F, 0xD160, 0x5A11, 0xAE50, 0x5A13, 0xAE55, 0x5A15, 0xD15F, 0x5A16, 0xD15C, 0x5A17, 0xD161, 0x5A18, 0xAE51, 0x5A19, 0xD15B, 0x5A1B, 0xAE54, 0x5A1C, 0xAE52, 0x5A1E, 0xD163, 0x5A1F, 0xAE53, 0x5A20, 0xAE57, 0x5A23, 0xAE58, 0x5A25, 0xAE5A, 0x5A29, 0xAE59, 0x5A2D, 0xD15D, 0x5A2E, 0xD15E, 0x5A33, 0xD164, 0x5A35, 0xD4D4, 0x5A36, 0xB0F9, 0x5A37, 0xD8C2, 0x5A38, 0xD4D3, 0x5A39, 0xD4E6, 0x5A3C, 0xB140, 0x5A3E, 0xD4E4, 0x5A40, 0xB0FE, 0x5A41, 0xB0FA, 0x5A42, 0xD4ED, 0x5A43, 0xD4DD, 0x5A44, 0xD4E0, 0x5A46, 0xB143, 0x5A47, 0xD4EA, 0x5A48, 0xD4E2, 0x5A49, 0xB0FB, 0x5A4A, 0xB144, 0x5A4C, 0xD4E7, 0x5A4D, 0xD4E5, 0x5A50, 0xD4D6, 0x5A51, 0xD4EB, 0x5A52, 0xD4DF, 0x5A53, 0xD4DA, 0x5A55, 0xD4D0, 0x5A56, 0xD4EC, 0x5A57, 0xD4DC, 0x5A58, 0xD4CF, 0x5A5A, 0xB142, 0x5A5B, 0xD4E1, 0x5A5C, 0xD4EE, 0x5A5D, 0xD4DE, 0x5A5E, 0xD4D2, 0x5A5F, 0xD4D7, 0x5A60, 0xD4CE, 0x5A62, 0xB141, 0x5A64, 0xD4DB, 0x5A65, 0xD4D8, 0x5A66, 0xB0FC, 0x5A67, 0xD4D1, 0x5A69, 0xD4E9, 0x5A6A, 0xB0FD, 0x5A6C, 0xD4D9, 0x5A6D, 0xD4D5, 0x5A70, 0xD4E8, 0x5A77, 0xB440, 0x5A78, 0xD8BB, 0x5A7A, 0xD8B8, 0x5A7B, 0xD8C9, 0x5A7C, 0xD8BD, 0x5A7D, 0xD8CA, 0x5A7F, 0xB442, 0x5A83, 0xD8C6, 0x5A84, 0xD8C3, 0x5A8A, 0xD8C4, 0x5A8B, 0xD8C7, 0x5A8C, 0xD8CB, 0x5A8E, 0xD4E3, 0x5A8F, 0xD8CD, 0x5A90, 0xDD47, 0x5A92, 0xB443, 0x5A93, 0xD8CE, 0x5A94, 0xD8B6, 0x5A95, 0xD8C0, 0x5A97, 0xD8C5, 0x5A9A, 0xB441, 0x5A9B, 0xB444, 0x5A9C, 0xD8CC, 0x5A9D, 0xD8CF, 0x5A9E, 0xD8BA, 0x5A9F, 0xD8B7, 0x5AA2, 0xD8B9, 0x5AA5, 0xD8BE, 0x5AA6, 0xD8BC, 0x5AA7, 0xB445, 0x5AA9, 0xD8C8, 0x5AAC, 0xD8BF, 0x5AAE, 0xD8C1, 0x5AAF, 0xD8B5, 0x5AB0, 0xDCFA, 0x5AB1, 0xDCF8, 0x5AB2, 0xB742, 0x5AB3, 0xB740, 0x5AB4, 0xDD43, 0x5AB5, 0xDCF9, 0x5AB6, 0xDD44, 0x5AB7, 0xDD40, 0x5AB8, 0xDCF7, 0x5AB9, 0xDD46, 0x5ABA, 0xDCF6, 0x5ABB, 0xDCFD, 0x5ABC, 0xB6FE, 0x5ABD, 0xB6FD, 0x5ABE, 0xB6FC, 0x5ABF, 0xDCFB, 0x5AC0, 0xDD41, 0x5AC1, 0xB6F9, 0x5AC2, 0xB741, 0x5AC4, 0xDCF4, 0x5AC6, 0xDCFE, 0x5AC7, 0xDCF3, 0x5AC8, 0xDCFC, 0x5AC9, 0xB6FA, 0x5ACA, 0xDD42, 0x5ACB, 0xDCF5, 0x5ACC, 0xB6FB, 0x5ACD, 0xDD45, 0x5AD5, 0xE16E, 0x5AD6, 0xB9E2, 0x5AD7, 0xB9E1, 0x5AD8, 0xB9E3, 0x5AD9, 0xE17A, 0x5ADA, 0xE170, 0x5ADB, 0xE176, 0x5ADC, 0xE16B, 0x5ADD, 0xE179, 0x5ADE, 0xE178, 0x5ADF, 0xE17C, 0x5AE0, 0xE175, 0x5AE1, 0xB9DE, 0x5AE2, 0xE174, 0x5AE3, 0xB9E4, 0x5AE5, 0xE16D, 0x5AE6, 0xB9DF, 0x5AE8, 0xE17B, 0x5AE9, 0xB9E0, 0x5AEA, 0xE16F, 0x5AEB, 0xE172, 0x5AEC, 0xE177, 0x5AED, 0xE171, 0x5AEE, 0xE16C, 0x5AF3, 0xE173, 0x5AF4, 0xE555, 0x5AF5, 0xBC61, 0x5AF6, 0xE558, 0x5AF7, 0xE557, 0x5AF8, 0xE55A, 0x5AF9, 0xE55C, 0x5AFA, 0xF9DC, 0x5AFB, 0xBC5F, 0x5AFD, 0xE556, 0x5AFF, 0xE554, 0x5B01, 0xE55D, 0x5B02, 0xE55B, 0x5B03, 0xE559, 0x5B05, 0xE55F, 0x5B07, 0xE55E, 0x5B08, 0xBC63, 0x5B09, 0xBC5E, 0x5B0B, 0xBC60, 0x5B0C, 0xBC62, 0x5B0F, 0xE560, 0x5B10, 0xE957, 0x5B13, 0xE956, 0x5B14, 0xE955, 0x5B16, 0xE958, 0x5B17, 0xE951, 0x5B19, 0xE952, 0x5B1A, 0xE95A, 0x5B1B, 0xE953, 0x5B1D, 0xBEC5, 0x5B1E, 0xE95C, 0x5B20, 0xE95B, 0x5B21, 0xE954, 0x5B23, 0xECD1, 0x5B24, 0xC0A8, 0x5B25, 0xECCF, 0x5B26, 0xECD4, 0x5B27, 0xECD3, 0x5B28, 0xE959, 0x5B2A, 0xC0A7, 0x5B2C, 0xECD2, 0x5B2D, 0xECCE, 0x5B2E, 0xECD6, 0x5B2F, 0xECD5, 0x5B30, 0xC0A6, 0x5B32, 0xECD0, 0x5B34, 0xBEC6, 0x5B38, 0xC254, 0x5B3C, 0xEFC1, 0x5B3D, 0xF1FA, 0x5B3E, 0xF1FB, 0x5B3F, 0xF1FC, 0x5B40, 0xC45C, 0x5B43, 0xC45D, 0x5B45, 0xF443, 0x5B47, 0xF5C8, 0x5B48, 0xF5C7, 0x5B4B, 0xF6DB, 0x5B4C, 0xF6DC, 0x5B4D, 0xF7D5, 0x5B4E, 0xF8A7, 0x5B50, 0xA46C, 0x5B51, 0xA46D, 0x5B53, 0xA46E, 0x5B54, 0xA4D5, 0x5B55, 0xA5A5, 0x5B56, 0xC9D3, 0x5B57, 0xA672, 0x5B58, 0xA673, 0x5B5A, 0xA7B7, 0x5B5B, 0xA7B8, 0x5B5C, 0xA7B6, 0x5B5D, 0xA7B5, 0x5B5F, 0xA973, 0x5B62, 0xCC55, 0x5B63, 0xA975, 0x5B64, 0xA974, 0x5B65, 0xCC56, 0x5B69, 0xABC4, 0x5B6B, 0xAE5D, 0x5B6C, 0xD165, 0x5B6E, 0xD4F0, 0x5B70, 0xB145, 0x5B71, 0xB447, 0x5B72, 0xD4EF, 0x5B73, 0xB446, 0x5B75, 0xB9E5, 0x5B77, 0xE17D, 0x5B78, 0xBEC7, 0x5B7A, 0xC0A9, 0x5B7B, 0xECD7, 0x5B7D, 0xC45E, 0x5B7F, 0xC570, 0x5B81, 0xC972, 0x5B83, 0xA5A6, 0x5B84, 0xC973, 0x5B85, 0xA676, 0x5B87, 0xA674, 0x5B88, 0xA675, 0x5B89, 0xA677, 0x5B8B, 0xA7BA, 0x5B8C, 0xA7B9, 0x5B8E, 0xCABC, 0x5B8F, 0xA7BB, 0x5B92, 0xCABD, 0x5B93, 0xCC57, 0x5B95, 0xCC58, 0x5B97, 0xA976, 0x5B98, 0xA978, 0x5B99, 0xA97A, 0x5B9A, 0xA977, 0x5B9B, 0xA97B, 0x5B9C, 0xA979, 0x5BA2, 0xABC8, 0x5BA3, 0xABC5, 0x5BA4, 0xABC7, 0x5BA5, 0xABC9, 0x5BA6, 0xABC6, 0x5BA7, 0xD166, 0x5BA8, 0xCE77, 0x5BAC, 0xD168, 0x5BAD, 0xD167, 0x5BAE, 0xAE63, 0x5BB0, 0xAE5F, 0x5BB3, 0xAE60, 0x5BB4, 0xAE62, 0x5BB5, 0xAE64, 0x5BB6, 0xAE61, 0x5BB8, 0xAE66, 0x5BB9, 0xAE65, 0x5BBF, 0xB14A, 0x5BC0, 0xD4F2, 0x5BC1, 0xD4F1, 0x5BC2, 0xB149, 0x5BC4, 0xB148, 0x5BC5, 0xB147, 0x5BC6, 0xB14B, 0x5BC7, 0xB146, 0x5BCA, 0xD8D5, 0x5BCB, 0xD8D2, 0x5BCC, 0xB449, 0x5BCD, 0xD8D1, 0x5BCE, 0xD8D6, 0x5BD0, 0xB44B, 0x5BD1, 0xD8D4, 0x5BD2, 0xB448, 0x5BD3, 0xB44A, 0x5BD4, 0xD8D3, 0x5BD6, 0xDD48, 0x5BD8, 0xDD49, 0x5BD9, 0xDD4A, 0x5BDE, 0xB9E6, 0x5BDF, 0xB9EE, 0x5BE0, 0xE17E, 0x5BE1, 0xB9E8, 0x5BE2, 0xB9EC, 0x5BE3, 0xE1A1, 0x5BE4, 0xB9ED, 0x5BE5, 0xB9E9, 0x5BE6, 0xB9EA, 0x5BE7, 0xB9E7, 0x5BE8, 0xB9EB, 0x5BE9, 0xBC66, 0x5BEA, 0xD8D0, 0x5BEB, 0xBC67, 0x5BEC, 0xBC65, 0x5BEE, 0xBC64, 0x5BEF, 0xE95D, 0x5BF0, 0xBEC8, 0x5BF1, 0xECD8, 0x5BF2, 0xECD9, 0x5BF5, 0xC364, 0x5BF6, 0xC45F, 0x5BF8, 0xA46F, 0x5BFA, 0xA678, 0x5C01, 0xABCA, 0x5C03, 0xD169, 0x5C04, 0xAE67, 0x5C07, 0xB14E, 0x5C08, 0xB14D, 0x5C09, 0xB14C, 0x5C0A, 0xB44C, 0x5C0B, 0xB44D, 0x5C0C, 0xD8D7, 0x5C0D, 0xB9EF, 0x5C0E, 0xBEC9, 0x5C0F, 0xA470, 0x5C10, 0xC95C, 0x5C11, 0xA4D6, 0x5C12, 0xC974, 0x5C15, 0xC9D4, 0x5C16, 0xA679, 0x5C1A, 0xA97C, 0x5C1F, 0xDD4B, 0x5C22, 0xA471, 0x5C24, 0xA4D7, 0x5C25, 0xC9D5, 0x5C28, 0xCABE, 0x5C2A, 0xCABF, 0x5C2C, 0xA7BC, 0x5C30, 0xD8D8, 0x5C31, 0xB44E, 0x5C33, 0xDD4C, 0x5C37, 0xC0AA, 0x5C38, 0xA472, 0x5C39, 0xA4A8, 0x5C3A, 0xA4D8, 0x5C3B, 0xC975, 0x5C3C, 0xA5A7, 0x5C3E, 0xA7C0, 0x5C3F, 0xA7BF, 0x5C40, 0xA7BD, 0x5C41, 0xA7BE, 0x5C44, 0xCC59, 0x5C45, 0xA97E, 0x5C46, 0xA9A1, 0x5C47, 0xCC5A, 0x5C48, 0xA97D, 0x5C4B, 0xABCE, 0x5C4C, 0xCE78, 0x5C4D, 0xABCD, 0x5C4E, 0xABCB, 0x5C4F, 0xABCC, 0x5C50, 0xAE6A, 0x5C51, 0xAE68, 0x5C54, 0xD16B, 0x5C55, 0xAE69, 0x5C56, 0xD16A, 0x5C58, 0xAE5E, 0x5C59, 0xD4F3, 0x5C5C, 0xB150, 0x5C5D, 0xB151, 0x5C60, 0xB14F, 0x5C62, 0xB9F0, 0x5C63, 0xE1A2, 0x5C64, 0xBC68, 0x5C65, 0xBC69, 0x5C67, 0xE561, 0x5C68, 0xC0AB, 0x5C69, 0xEFC2, 0x5C6A, 0xEFC3, 0x5C6C, 0xC4DD, 0x5C6D, 0xF8A8, 0x5C6E, 0xC94B, 0x5C6F, 0xA4D9, 0x5C71, 0xA473, 0x5C73, 0xC977, 0x5C74, 0xC976, 0x5C79, 0xA67A, 0x5C7A, 0xC9D7, 0x5C7B, 0xC9D8, 0x5C7C, 0xC9D6, 0x5C7E, 0xC9D9, 0x5C86, 0xCAC7, 0x5C88, 0xCAC2, 0x5C89, 0xCAC4, 0x5C8A, 0xCAC6, 0x5C8B, 0xCAC3, 0x5C8C, 0xA7C4, 0x5C8D, 0xCAC0, 0x5C8F, 0xCAC1, 0x5C90, 0xA7C1, 0x5C91, 0xA7C2, 0x5C92, 0xCAC5, 0x5C93, 0xCAC8, 0x5C94, 0xA7C3, 0x5C95, 0xCAC9, 0x5C9D, 0xCC68, 0x5C9F, 0xCC62, 0x5CA0, 0xCC5D, 0x5CA1, 0xA9A3, 0x5CA2, 0xCC65, 0x5CA3, 0xCC63, 0x5CA4, 0xCC5C, 0x5CA5, 0xCC69, 0x5CA6, 0xCC6C, 0x5CA7, 0xCC67, 0x5CA8, 0xCC60, 0x5CA9, 0xA9A5, 0x5CAA, 0xCC66, 0x5CAB, 0xA9A6, 0x5CAC, 0xCC61, 0x5CAD, 0xCC64, 0x5CAE, 0xCC5B, 0x5CAF, 0xCC5F, 0x5CB0, 0xCC6B, 0x5CB1, 0xA9A7, 0x5CB3, 0xA9A8, 0x5CB5, 0xCC5E, 0x5CB6, 0xCC6A, 0x5CB7, 0xA9A2, 0x5CB8, 0xA9A4, 0x5CC6, 0xCEAB, 0x5CC7, 0xCEA4, 0x5CC8, 0xCEAA, 0x5CC9, 0xCEA3, 0x5CCA, 0xCEA5, 0x5CCB, 0xCE7D, 0x5CCC, 0xCE7B, 0x5CCE, 0xCEAC, 0x5CCF, 0xCEA9, 0x5CD0, 0xCE79, 0x5CD2, 0xABD0, 0x5CD3, 0xCEA7, 0x5CD4, 0xCEA8, 0x5CD6, 0xCEA6, 0x5CD7, 0xCE7C, 0x5CD8, 0xCE7A, 0x5CD9, 0xABCF, 0x5CDA, 0xCEA2, 0x5CDB, 0xCE7E, 0x5CDE, 0xCEA1, 0x5CDF, 0xCEAD, 0x5CE8, 0xAE6F, 0x5CEA, 0xAE6E, 0x5CEC, 0xD16C, 0x5CED, 0xAE6B, 0x5CEE, 0xD16E, 0x5CF0, 0xAE70, 0x5CF1, 0xD16F, 0x5CF4, 0xAE73, 0x5CF6, 0xAE71, 0x5CF7, 0xD170, 0x5CF8, 0xCEAE, 0x5CF9, 0xD172, 0x5CFB, 0xAE6D, 0x5CFD, 0xAE6C, 0x5CFF, 0xD16D, 0x5D00, 0xD171, 0x5D01, 0xAE72, 0x5D06, 0xB153, 0x5D07, 0xB152, 0x5D0B, 0xD4F5, 0x5D0C, 0xD4F9, 0x5D0D, 0xD4FB, 0x5D0E, 0xB154, 0x5D0F, 0xD4FE, 0x5D11, 0xB158, 0x5D12, 0xD541, 0x5D14, 0xB15A, 0x5D16, 0xB156, 0x5D17, 0xB15E, 0x5D19, 0xB15B, 0x5D1A, 0xD4F7, 0x5D1B, 0xB155, 0x5D1D, 0xD4F6, 0x5D1E, 0xD4F4, 0x5D1F, 0xD543, 0x5D20, 0xD4F8, 0x5D22, 0xB157, 0x5D23, 0xD542, 0x5D24, 0xB15C, 0x5D25, 0xD4FD, 0x5D26, 0xD4FC, 0x5D27, 0xB15D, 0x5D28, 0xD4FA, 0x5D29, 0xB159, 0x5D2E, 0xD544, 0x5D30, 0xD540, 0x5D31, 0xD8E7, 0x5D32, 0xD8EE, 0x5D33, 0xD8E3, 0x5D34, 0xB451, 0x5D35, 0xD8DF, 0x5D36, 0xD8EF, 0x5D37, 0xD8D9, 0x5D38, 0xD8EC, 0x5D39, 0xD8EA, 0x5D3A, 0xD8E4, 0x5D3C, 0xD8ED, 0x5D3D, 0xD8E6, 0x5D3F, 0xD8DE, 0x5D40, 0xD8F0, 0x5D41, 0xD8DC, 0x5D42, 0xD8E9, 0x5D43, 0xD8DA, 0x5D45, 0xD8F1, 0x5D47, 0xB452, 0x5D49, 0xD8EB, 0x5D4A, 0xDD4F, 0x5D4B, 0xD8DD, 0x5D4C, 0xB44F, 0x5D4E, 0xD8E1, 0x5D50, 0xB450, 0x5D51, 0xD8E0, 0x5D52, 0xD8E5, 0x5D55, 0xD8E2, 0x5D59, 0xD8E8, 0x5D5E, 0xDD53, 0x5D62, 0xDD56, 0x5D63, 0xDD4E, 0x5D65, 0xDD50, 0x5D67, 0xDD55, 0x5D68, 0xDD54, 0x5D69, 0xB743, 0x5D6B, 0xD8DB, 0x5D6C, 0xDD52, 0x5D6F, 0xB744, 0x5D71, 0xDD4D, 0x5D72, 0xDD51, 0x5D77, 0xE1A9, 0x5D79, 0xE1B0, 0x5D7A, 0xE1A7, 0x5D7C, 0xE1AE, 0x5D7D, 0xE1A5, 0x5D7E, 0xE1AD, 0x5D7F, 0xE1B1, 0x5D80, 0xE1A4, 0x5D81, 0xE1A8, 0x5D82, 0xE1A3, 0x5D84, 0xB9F1, 0x5D86, 0xE1A6, 0x5D87, 0xB9F2, 0x5D88, 0xE1AC, 0x5D89, 0xE1AB, 0x5D8A, 0xE1AA, 0x5D8D, 0xE1AF, 0x5D92, 0xE565, 0x5D93, 0xE567, 0x5D94, 0xBC6B, 0x5D95, 0xE568, 0x5D97, 0xE563, 0x5D99, 0xE562, 0x5D9A, 0xE56C, 0x5D9C, 0xE56A, 0x5D9D, 0xBC6A, 0x5D9E, 0xE56D, 0x5D9F, 0xE564, 0x5DA0, 0xE569, 0x5DA1, 0xE56B, 0x5DA2, 0xE566, 0x5DA7, 0xE961, 0x5DA8, 0xE966, 0x5DA9, 0xE960, 0x5DAA, 0xE965, 0x5DAC, 0xE95E, 0x5DAD, 0xE968, 0x5DAE, 0xE964, 0x5DAF, 0xE969, 0x5DB0, 0xE963, 0x5DB1, 0xE95F, 0x5DB2, 0xE967, 0x5DB4, 0xE96A, 0x5DB5, 0xE962, 0x5DB7, 0xECDA, 0x5DB8, 0xC0AF, 0x5DBA, 0xC0AD, 0x5DBC, 0xC0AC, 0x5DBD, 0xC0AE, 0x5DC0, 0xEFC4, 0x5DC2, 0xF172, 0x5DC3, 0xF1FD, 0x5DC6, 0xF444, 0x5DC7, 0xF445, 0x5DC9, 0xC460, 0x5DCB, 0xF5C9, 0x5DCD, 0xC4DE, 0x5DCF, 0xF5CA, 0x5DD1, 0xF6DE, 0x5DD2, 0xC572, 0x5DD4, 0xC571, 0x5DD5, 0xF6DD, 0x5DD6, 0xC5C9, 0x5DD8, 0xF7D6, 0x5DDD, 0xA474, 0x5DDE, 0xA67B, 0x5DDF, 0xC9DA, 0x5DE0, 0xCACA, 0x5DE1, 0xA8B5, 0x5DE2, 0xB15F, 0x5DE5, 0xA475, 0x5DE6, 0xA5AA, 0x5DE7, 0xA5A9, 0x5DE8, 0xA5A8, 0x5DEB, 0xA7C5, 0x5DEE, 0xAE74, 0x5DF0, 0xDD57, 0x5DF1, 0xA476, 0x5DF2, 0xA477, 0x5DF3, 0xA478, 0x5DF4, 0xA4DA, 0x5DF7, 0xABD1, 0x5DF9, 0xCEAF, 0x5DFD, 0xB453, 0x5DFE, 0xA479, 0x5DFF, 0xC95D, 0x5E02, 0xA5AB, 0x5E03, 0xA5AC, 0x5E04, 0xC978, 0x5E06, 0xA67C, 0x5E0A, 0xCACB, 0x5E0C, 0xA7C6, 0x5E0E, 0xCACC, 0x5E11, 0xA9AE, 0x5E14, 0xCC6E, 0x5E15, 0xA9AC, 0x5E16, 0xA9AB, 0x5E17, 0xCC6D, 0x5E18, 0xA9A9, 0x5E19, 0xCC6F, 0x5E1A, 0xA9AA, 0x5E1B, 0xA9AD, 0x5E1D, 0xABD2, 0x5E1F, 0xABD4, 0x5E20, 0xCEB3, 0x5E21, 0xCEB0, 0x5E22, 0xCEB1, 0x5E23, 0xCEB2, 0x5E24, 0xCEB4, 0x5E25, 0xABD3, 0x5E28, 0xD174, 0x5E29, 0xD173, 0x5E2B, 0xAE76, 0x5E2D, 0xAE75, 0x5E33, 0xB162, 0x5E34, 0xD546, 0x5E36, 0xB161, 0x5E37, 0xB163, 0x5E38, 0xB160, 0x5E3D, 0xB455, 0x5E3E, 0xD545, 0x5E40, 0xB456, 0x5E41, 0xD8F3, 0x5E43, 0xB457, 0x5E44, 0xD8F2, 0x5E45, 0xB454, 0x5E4A, 0xDD5A, 0x5E4B, 0xDD5C, 0x5E4C, 0xB745, 0x5E4D, 0xDD5B, 0x5E4E, 0xDD59, 0x5E4F, 0xDD58, 0x5E53, 0xE1B4, 0x5E54, 0xB9F7, 0x5E55, 0xB9F5, 0x5E57, 0xB9F6, 0x5E58, 0xE1B2, 0x5E59, 0xE1B3, 0x5E5B, 0xB9F3, 0x5E5C, 0xE571, 0x5E5D, 0xE56F, 0x5E5F, 0xBC6D, 0x5E60, 0xE570, 0x5E61, 0xBC6E, 0x5E62, 0xBC6C, 0x5E63, 0xB9F4, 0x5E66, 0xE96D, 0x5E67, 0xE96B, 0x5E68, 0xE96C, 0x5E69, 0xE56E, 0x5E6A, 0xECDC, 0x5E6B, 0xC0B0, 0x5E6C, 0xECDB, 0x5E6D, 0xEFC5, 0x5E6E, 0xEFC6, 0x5E6F, 0xE96E, 0x5E70, 0xF1FE, 0x5E72, 0xA47A, 0x5E73, 0xA5AD, 0x5E74, 0xA67E, 0x5E75, 0xC9DB, 0x5E76, 0xA67D, 0x5E78, 0xA9AF, 0x5E79, 0xB746, 0x5E7B, 0xA4DB, 0x5E7C, 0xA5AE, 0x5E7D, 0xABD5, 0x5E7E, 0xB458, 0x5E80, 0xC979, 0x5E82, 0xC97A, 0x5E84, 0xC9DC, 0x5E87, 0xA7C8, 0x5E88, 0xCAD0, 0x5E89, 0xCACE, 0x5E8A, 0xA7C9, 0x5E8B, 0xCACD, 0x5E8C, 0xCACF, 0x5E8D, 0xCAD1, 0x5E8F, 0xA7C7, 0x5E95, 0xA9B3, 0x5E96, 0xA9B4, 0x5E97, 0xA9B1, 0x5E9A, 0xA9B0, 0x5E9B, 0xCEB8, 0x5E9C, 0xA9B2, 0x5EA0, 0xABD6, 0x5EA2, 0xCEB7, 0x5EA3, 0xCEB9, 0x5EA4, 0xCEB6, 0x5EA5, 0xCEBA, 0x5EA6, 0xABD7, 0x5EA7, 0xAE79, 0x5EA8, 0xD175, 0x5EAA, 0xD177, 0x5EAB, 0xAE77, 0x5EAC, 0xD178, 0x5EAD, 0xAE78, 0x5EAE, 0xD176, 0x5EB0, 0xCEB5, 0x5EB1, 0xD547, 0x5EB2, 0xD54A, 0x5EB3, 0xD54B, 0x5EB4, 0xD548, 0x5EB5, 0xB167, 0x5EB6, 0xB166, 0x5EB7, 0xB164, 0x5EB8, 0xB165, 0x5EB9, 0xD549, 0x5EBE, 0xB168, 0x5EC1, 0xB45A, 0x5EC2, 0xB45B, 0x5EC4, 0xB45C, 0x5EC5, 0xDD5D, 0x5EC6, 0xDD5F, 0x5EC7, 0xDD61, 0x5EC8, 0xB748, 0x5EC9, 0xB747, 0x5ECA, 0xB459, 0x5ECB, 0xDD60, 0x5ECC, 0xDD5E, 0x5ECE, 0xE1B8, 0x5ED1, 0xE1B6, 0x5ED2, 0xE1BC, 0x5ED3, 0xB9F8, 0x5ED4, 0xE1BD, 0x5ED5, 0xE1BA, 0x5ED6, 0xB9F9, 0x5ED7, 0xE1B7, 0x5ED8, 0xE1B5, 0x5ED9, 0xE1BB, 0x5EDA, 0xBC70, 0x5EDB, 0xE573, 0x5EDC, 0xE1B9, 0x5EDD, 0xBC72, 0x5EDE, 0xE574, 0x5EDF, 0xBC71, 0x5EE0, 0xBC74, 0x5EE1, 0xE575, 0x5EE2, 0xBC6F, 0x5EE3, 0xBC73, 0x5EE5, 0xE973, 0x5EE6, 0xE971, 0x5EE7, 0xE970, 0x5EE8, 0xE972, 0x5EE9, 0xE96F, 0x5EEC, 0xC366, 0x5EEE, 0xF446, 0x5EEF, 0xF447, 0x5EF1, 0xF5CB, 0x5EF2, 0xF6DF, 0x5EF3, 0xC655, 0x5EF6, 0xA9B5, 0x5EF7, 0xA7CA, 0x5EFA, 0xABD8, 0x5EFE, 0xA47B, 0x5EFF, 0xA4DC, 0x5F01, 0xA5AF, 0x5F02, 0xC9DD, 0x5F04, 0xA7CB, 0x5F05, 0xCAD2, 0x5F07, 0xCEBB, 0x5F08, 0xABD9, 0x5F0A, 0xB9FA, 0x5F0B, 0xA47C, 0x5F0F, 0xA6A1, 0x5F12, 0xB749, 0x5F13, 0xA47D, 0x5F14, 0xA4DD, 0x5F15, 0xA4DE, 0x5F17, 0xA5B1, 0x5F18, 0xA5B0, 0x5F1A, 0xC9DE, 0x5F1B, 0xA6A2, 0x5F1D, 0xCAD3, 0x5F1F, 0xA7CC, 0x5F22, 0xCC71, 0x5F23, 0xCC72, 0x5F24, 0xCC73, 0x5F26, 0xA9B6, 0x5F27, 0xA9B7, 0x5F28, 0xCC70, 0x5F29, 0xA9B8, 0x5F2D, 0xABDA, 0x5F2E, 0xCEBC, 0x5F30, 0xD17A, 0x5F31, 0xAE7A, 0x5F33, 0xD179, 0x5F35, 0xB169, 0x5F36, 0xD54C, 0x5F37, 0xB16A, 0x5F38, 0xD54D, 0x5F3C, 0xB45D, 0x5F40, 0xDD62, 0x5F43, 0xE1BF, 0x5F44, 0xE1BE, 0x5F46, 0xB9FB, 0x5F48, 0xBC75, 0x5F49, 0xE576, 0x5F4A, 0xBECA, 0x5F4B, 0xE974, 0x5F4C, 0xC0B1, 0x5F4E, 0xC573, 0x5F4F, 0xF7D8, 0x5F54, 0xCC74, 0x5F56, 0xCEBD, 0x5F57, 0xB16B, 0x5F58, 0xD8F4, 0x5F59, 0xB74A, 0x5F5D, 0xC255, 0x5F62, 0xA7CE, 0x5F64, 0xA7CD, 0x5F65, 0xABDB, 0x5F67, 0xD17B, 0x5F69, 0xB16D, 0x5F6A, 0xB343, 0x5F6B, 0xB16E, 0x5F6C, 0xB16C, 0x5F6D, 0xB45E, 0x5F6F, 0xE1C0, 0x5F70, 0xB9FC, 0x5F71, 0xBC76, 0x5F73, 0xC94C, 0x5F74, 0xC9DF, 0x5F76, 0xCAD5, 0x5F77, 0xA7CF, 0x5F78, 0xCAD4, 0x5F79, 0xA7D0, 0x5F7C, 0xA9BC, 0x5F7D, 0xCC77, 0x5F7E, 0xCC76, 0x5F7F, 0xA9BB, 0x5F80, 0xA9B9, 0x5F81, 0xA9BA, 0x5F82, 0xCC75, 0x5F85, 0xABDD, 0x5F86, 0xCEBE, 0x5F87, 0xABE0, 0x5F88, 0xABDC, 0x5F89, 0xABE2, 0x5F8A, 0xABDE, 0x5F8B, 0xABDF, 0x5F8C, 0xABE1, 0x5F90, 0xAE7D, 0x5F91, 0xAE7C, 0x5F92, 0xAE7B, 0x5F96, 0xD54F, 0x5F97, 0xB16F, 0x5F98, 0xB172, 0x5F99, 0xB170, 0x5F9B, 0xD54E, 0x5F9C, 0xB175, 0x5F9E, 0xB171, 0x5F9F, 0xD550, 0x5FA0, 0xB174, 0x5FA1, 0xB173, 0x5FA5, 0xD8F6, 0x5FA6, 0xD8F5, 0x5FA8, 0xB461, 0x5FA9, 0xB45F, 0x5FAA, 0xB460, 0x5FAB, 0xD8F7, 0x5FAC, 0xB74B, 0x5FAD, 0xDD64, 0x5FAE, 0xB74C, 0x5FAF, 0xDD63, 0x5FB2, 0xE577, 0x5FB5, 0xBC78, 0x5FB6, 0xE1C1, 0x5FB7, 0xBC77, 0x5FB9, 0xB9FD, 0x5FBB, 0xECDE, 0x5FBC, 0xE975, 0x5FBD, 0xC0B2, 0x5FBE, 0xECDD, 0x5FBF, 0xF240, 0x5FC0, 0xF448, 0x5FC1, 0xF449, 0x5FC3, 0xA4DF, 0x5FC5, 0xA5B2, 0x5FC9, 0xC97B, 0x5FCC, 0xA7D2, 0x5FCD, 0xA7D4, 0x5FCF, 0xC9E2, 0x5FD0, 0xCAD8, 0x5FD1, 0xCAD7, 0x5FD2, 0xCAD6, 0x5FD4, 0xC9E1, 0x5FD5, 0xC9E0, 0x5FD6, 0xA6A4, 0x5FD7, 0xA7D3, 0x5FD8, 0xA7D1, 0x5FD9, 0xA6A3, 0x5FDD, 0xA9BD, 0x5FDE, 0xCC78, 0x5FE0, 0xA9BE, 0x5FE1, 0xCADD, 0x5FE3, 0xCADF, 0x5FE4, 0xCADE, 0x5FE5, 0xCC79, 0x5FE8, 0xCADA, 0x5FEA, 0xA7D8, 0x5FEB, 0xA7D6, 0x5FED, 0xCAD9, 0x5FEE, 0xCADB, 0x5FEF, 0xCAE1, 0x5FF1, 0xA7D5, 0x5FF3, 0xCADC, 0x5FF4, 0xCAE5, 0x5FF5, 0xA9C0, 0x5FF7, 0xCAE2, 0x5FF8, 0xA7D7, 0x5FFA, 0xCAE0, 0x5FFB, 0xCAE3, 0x5FFD, 0xA9BF, 0x5FFF, 0xA9C1, 0x6000, 0xCAE4, 0x6009, 0xCCAF, 0x600A, 0xCCA2, 0x600B, 0xCC7E, 0x600C, 0xCCAE, 0x600D, 0xCCA9, 0x600E, 0xABE7, 0x600F, 0xA9C2, 0x6010, 0xCCAA, 0x6011, 0xCCAD, 0x6012, 0xABE3, 0x6013, 0xCCAC, 0x6014, 0xA9C3, 0x6015, 0xA9C8, 0x6016, 0xA9C6, 0x6017, 0xCCA3, 0x6019, 0xCC7C, 0x601A, 0xCCA5, 0x601B, 0xA9CD, 0x601C, 0xCCB0, 0x601D, 0xABE4, 0x601E, 0xCCA6, 0x6020, 0xABE5, 0x6021, 0xA9C9, 0x6022, 0xCCA8, 0x6024, 0xCECD, 0x6025, 0xABE6, 0x6026, 0xCC7B, 0x6027, 0xA9CA, 0x6028, 0xABE8, 0x6029, 0xA9CB, 0x602A, 0xA9C7, 0x602B, 0xA9CC, 0x602C, 0xCCA7, 0x602D, 0xCC7A, 0x602E, 0xCCAB, 0x602F, 0xA9C4, 0x6032, 0xCC7D, 0x6033, 0xCCA4, 0x6034, 0xCCA1, 0x6035, 0xA9C5, 0x6037, 0xCEBF, 0x6039, 0xCEC0, 0x6040, 0xCECA, 0x6041, 0xD1A1, 0x6042, 0xCECB, 0x6043, 0xABEE, 0x6044, 0xCECE, 0x6045, 0xCEC4, 0x6046, 0xABED, 0x6047, 0xCEC6, 0x6049, 0xCEC7, 0x604C, 0xCEC9, 0x604D, 0xABE9, 0x6050, 0xAEA3, 0x6052, 0xF9DA, 0x6053, 0xCEC5, 0x6054, 0xCEC1, 0x6055, 0xAEA4, 0x6058, 0xCECF, 0x6059, 0xAE7E, 0x605A, 0xD17D, 0x605B, 0xCEC8, 0x605D, 0xD17C, 0x605E, 0xCEC3, 0x605F, 0xCECC, 0x6062, 0xABEC, 0x6063, 0xAEA1, 0x6064, 0xABF2, 0x6065, 0xAEA2, 0x6066, 0xCED0, 0x6067, 0xD17E, 0x6068, 0xABEB, 0x6069, 0xAEA6, 0x606A, 0xABF1, 0x606B, 0xABF0, 0x606C, 0xABEF, 0x606D, 0xAEA5, 0x606E, 0xCED1, 0x606F, 0xAEA7, 0x6070, 0xABEA, 0x6072, 0xCEC2, 0x607F, 0xB176, 0x6080, 0xD1A4, 0x6081, 0xD1A6, 0x6083, 0xD1A8, 0x6084, 0xAEA8, 0x6085, 0xAEAE, 0x6086, 0xD553, 0x6087, 0xD1AC, 0x6088, 0xD1A3, 0x6089, 0xB178, 0x608A, 0xD551, 0x608C, 0xAEAD, 0x608D, 0xAEAB, 0x608E, 0xD1AE, 0x6090, 0xD552, 0x6092, 0xD1A5, 0x6094, 0xAEAC, 0x6095, 0xD1A9, 0x6096, 0xAEAF, 0x6097, 0xD1AB, 0x609A, 0xAEAA, 0x609B, 0xD1AA, 0x609C, 0xD1AD, 0x609D, 0xD1A7, 0x609F, 0xAEA9, 0x60A0, 0xB179, 0x60A2, 0xD1A2, 0x60A3, 0xB177, 0x60A8, 0xB17A, 0x60B0, 0xD555, 0x60B1, 0xD55E, 0x60B2, 0xB464, 0x60B4, 0xB17C, 0x60B5, 0xB1A3, 0x60B6, 0xB465, 0x60B7, 0xD560, 0x60B8, 0xB1AA, 0x60B9, 0xD8F9, 0x60BA, 0xD556, 0x60BB, 0xB1A2, 0x60BC, 0xB1A5, 0x60BD, 0xB17E, 0x60BE, 0xD554, 0x60BF, 0xD562, 0x60C0, 0xD565, 0x60C1, 0xD949, 0x60C3, 0xD563, 0x60C4, 0xD8FD, 0x60C5, 0xB1A1, 0x60C6, 0xB1A8, 0x60C7, 0xB1AC, 0x60C8, 0xD55D, 0x60C9, 0xD8F8, 0x60CA, 0xD561, 0x60CB, 0xB17B, 0x60CC, 0xD8FA, 0x60CD, 0xD564, 0x60CE, 0xD8FC, 0x60CF, 0xD559, 0x60D1, 0xB462, 0x60D3, 0xD557, 0x60D4, 0xD558, 0x60D5, 0xB1A7, 0x60D8, 0xB1A6, 0x60D9, 0xD55B, 0x60DA, 0xB1AB, 0x60DB, 0xD55F, 0x60DC, 0xB1A4, 0x60DD, 0xD55C, 0x60DF, 0xB1A9, 0x60E0, 0xB466, 0x60E1, 0xB463, 0x60E2, 0xD8FB, 0x60E4, 0xD55A, 0x60E6, 0xB17D, 0x60F0, 0xB46B, 0x60F1, 0xB46F, 0x60F2, 0xD940, 0x60F3, 0xB751, 0x60F4, 0xB46D, 0x60F5, 0xD944, 0x60F6, 0xB471, 0x60F7, 0xDD65, 0x60F8, 0xD946, 0x60F9, 0xB753, 0x60FA, 0xB469, 0x60FB, 0xB46C, 0x60FC, 0xD947, 0x60FE, 0xD948, 0x60FF, 0xD94E, 0x6100, 0xB473, 0x6101, 0xB754, 0x6103, 0xD94A, 0x6104, 0xD94F, 0x6105, 0xD943, 0x6106, 0xB75E, 0x6108, 0xB755, 0x6109, 0xB472, 0x610A, 0xD941, 0x610B, 0xD950, 0x610D, 0xB75D, 0x610E, 0xB470, 0x610F, 0xB74E, 0x6110, 0xD94D, 0x6112, 0xB474, 0x6113, 0xD945, 0x6114, 0xD8FE, 0x6115, 0xB46A, 0x6116, 0xD942, 0x6118, 0xD94B, 0x611A, 0xB74D, 0x611B, 0xB752, 0x611C, 0xB467, 0x611D, 0xD94C, 0x611F, 0xB750, 0x6123, 0xB468, 0x6127, 0xB75C, 0x6128, 0xE1C3, 0x6129, 0xDD70, 0x612B, 0xDD68, 0x612C, 0xE1C2, 0x612E, 0xDD6C, 0x612F, 0xDD6E, 0x6132, 0xDD6B, 0x6134, 0xB75B, 0x6136, 0xDD6A, 0x6137, 0xB75F, 0x613B, 0xE1D2, 0x613E, 0xB75A, 0x613F, 0xBA40, 0x6140, 0xDD71, 0x6141, 0xE1C4, 0x6144, 0xB758, 0x6145, 0xDD69, 0x6146, 0xDD6D, 0x6147, 0xB9FE, 0x6148, 0xB74F, 0x6149, 0xDD66, 0x614A, 0xDD67, 0x614B, 0xBA41, 0x614C, 0xB757, 0x614D, 0xB759, 0x614E, 0xB756, 0x614F, 0xDD6F, 0x6152, 0xE1C8, 0x6153, 0xE1C9, 0x6154, 0xE1CE, 0x6155, 0xBC7D, 0x6156, 0xE1D5, 0x6158, 0xBA47, 0x615A, 0xBA46, 0x615B, 0xE1D0, 0x615D, 0xBC7C, 0x615E, 0xE1C5, 0x615F, 0xBA45, 0x6161, 0xE1D4, 0x6162, 0xBA43, 0x6163, 0xBA44, 0x6165, 0xE1D1, 0x6166, 0xE5AA, 0x6167, 0xBC7A, 0x6168, 0xB46E, 0x616A, 0xE1D3, 0x616B, 0xBCA3, 0x616C, 0xE1CB, 0x616E, 0xBC7B, 0x6170, 0xBCA2, 0x6171, 0xE1C6, 0x6172, 0xE1CA, 0x6173, 0xE1C7, 0x6174, 0xE1CD, 0x6175, 0xBA48, 0x6176, 0xBC79, 0x6177, 0xBA42, 0x6179, 0xE57A, 0x617A, 0xE1CF, 0x617C, 0xBCA1, 0x617E, 0xBCA4, 0x6180, 0xE1CC, 0x6182, 0xBC7E, 0x6183, 0xE579, 0x6189, 0xE57E, 0x618A, 0xBECE, 0x618B, 0xE578, 0x618C, 0xE9A3, 0x618D, 0xE5A9, 0x618E, 0xBCA8, 0x6190, 0xBCA6, 0x6191, 0xBECC, 0x6192, 0xE5A6, 0x6193, 0xE5A2, 0x6194, 0xBCAC, 0x6196, 0xE978, 0x619A, 0xBCAA, 0x619B, 0xE5A1, 0x619D, 0xE976, 0x619F, 0xE5A5, 0x61A1, 0xE5A8, 0x61A2, 0xE57D, 0x61A4, 0xBCAB, 0x61A7, 0xBCA5, 0x61A8, 0xE977, 0x61A9, 0xBECD, 0x61AA, 0xE5A7, 0x61AB, 0xBCA7, 0x61AC, 0xBCA9, 0x61AD, 0xE5A4, 0x61AE, 0xBCAD, 0x61AF, 0xE5A3, 0x61B0, 0xE57C, 0x61B1, 0xE57B, 0x61B2, 0xBECB, 0x61B3, 0xE5AB, 0x61B4, 0xE97A, 0x61B5, 0xECE0, 0x61B6, 0xBED0, 0x61B8, 0xE9A2, 0x61BA, 0xE97E, 0x61BC, 0xECE1, 0x61BE, 0xBED1, 0x61BF, 0xE9A1, 0x61C1, 0xE97C, 0x61C2, 0xC0B4, 0x61C3, 0xECDF, 0x61C5, 0xE979, 0x61C6, 0xE97B, 0x61C7, 0xC0B5, 0x61C8, 0xBED3, 0x61C9, 0xC0B3, 0x61CA, 0xBED2, 0x61CB, 0xC0B7, 0x61CC, 0xE97D, 0x61CD, 0xBECF, 0x61D6, 0xEFCF, 0x61D8, 0xEFC7, 0x61DE, 0xECE7, 0x61DF, 0xEFC8, 0x61E0, 0xECE3, 0x61E3, 0xC256, 0x61E4, 0xECE5, 0x61E5, 0xECE4, 0x61E6, 0xC0B6, 0x61E7, 0xECE2, 0x61E8, 0xECE6, 0x61E9, 0xEFD0, 0x61EA, 0xEFCC, 0x61EB, 0xEFCE, 0x61ED, 0xEFC9, 0x61EE, 0xEFCA, 0x61F0, 0xEFCD, 0x61F1, 0xEFCB, 0x61F2, 0xC367, 0x61F5, 0xC36A, 0x61F6, 0xC369, 0x61F7, 0xC368, 0x61F8, 0xC461, 0x61F9, 0xF44A, 0x61FA, 0xC462, 0x61FB, 0xF241, 0x61FC, 0xC4DF, 0x61FD, 0xF5CC, 0x61FE, 0xC4E0, 0x61FF, 0xC574, 0x6200, 0xC5CA, 0x6201, 0xF7D9, 0x6203, 0xF7DA, 0x6204, 0xF7DB, 0x6207, 0xF9BA, 0x6208, 0xA4E0, 0x6209, 0xC97C, 0x620A, 0xA5B3, 0x620C, 0xA6A6, 0x620D, 0xA6A7, 0x620E, 0xA6A5, 0x6210, 0xA6A8, 0x6211, 0xA7DA, 0x6212, 0xA7D9, 0x6214, 0xCCB1, 0x6215, 0xA9CF, 0x6216, 0xA9CE, 0x6219, 0xD1AF, 0x621A, 0xB1AD, 0x621B, 0xB1AE, 0x621F, 0xB475, 0x6220, 0xDD72, 0x6221, 0xB760, 0x6222, 0xB761, 0x6223, 0xDD74, 0x6224, 0xDD76, 0x6225, 0xDD75, 0x6227, 0xE1D7, 0x6229, 0xE1D6, 0x622A, 0xBA49, 0x622B, 0xE1D8, 0x622D, 0xE5AC, 0x622E, 0xBCAE, 0x6230, 0xBED4, 0x6232, 0xC0B8, 0x6233, 0xC257, 0x6234, 0xC0B9, 0x6236, 0xA4E1, 0x623A, 0xCAE6, 0x623D, 0xCCB2, 0x623E, 0xA9D1, 0x623F, 0xA9D0, 0x6240, 0xA9D2, 0x6241, 0xABF3, 0x6242, 0xCED2, 0x6243, 0xCED3, 0x6246, 0xD1B0, 0x6247, 0xAEB0, 0x6248, 0xB1AF, 0x6249, 0xB476, 0x624A, 0xD951, 0x624B, 0xA4E2, 0x624D, 0xA47E, 0x624E, 0xA4E3, 0x6250, 0xC97D, 0x6251, 0xA5B7, 0x6252, 0xA5B6, 0x6253, 0xA5B4, 0x6254, 0xA5B5, 0x6258, 0xA6AB, 0x6259, 0xC9E9, 0x625A, 0xC9EB, 0x625B, 0xA6AA, 0x625C, 0xC9E3, 0x625E, 0xC9E4, 0x6260, 0xC9EA, 0x6261, 0xC9E6, 0x6262, 0xC9E8, 0x6263, 0xA6A9, 0x6264, 0xC9E5, 0x6265, 0xC9EC, 0x6266, 0xC9E7, 0x626D, 0xA7E1, 0x626E, 0xA7EA, 0x626F, 0xA7E8, 0x6270, 0xCAF0, 0x6271, 0xCAED, 0x6272, 0xCAF5, 0x6273, 0xA7E6, 0x6274, 0xCAF6, 0x6276, 0xA7DF, 0x6277, 0xCAF3, 0x6279, 0xA7E5, 0x627A, 0xCAEF, 0x627B, 0xCAEE, 0x627C, 0xA7E3, 0x627D, 0xCAF4, 0x627E, 0xA7E4, 0x627F, 0xA9D3, 0x6280, 0xA7DE, 0x6281, 0xCAF1, 0x6283, 0xCAE7, 0x6284, 0xA7DB, 0x6286, 0xA7EE, 0x6287, 0xCAEC, 0x6288, 0xCAF2, 0x6289, 0xA7E0, 0x628A, 0xA7E2, 0x628C, 0xCAE8, 0x628E, 0xCAE9, 0x628F, 0xCAEA, 0x6291, 0xA7ED, 0x6292, 0xA7E7, 0x6293, 0xA7EC, 0x6294, 0xCAEB, 0x6295, 0xA7EB, 0x6296, 0xA7DD, 0x6297, 0xA7DC, 0x6298, 0xA7E9, 0x62A8, 0xA9E1, 0x62A9, 0xCCBE, 0x62AA, 0xCCB7, 0x62AB, 0xA9DC, 0x62AC, 0xA9EF, 0x62AD, 0xCCB3, 0x62AE, 0xCCBA, 0x62AF, 0xCCBC, 0x62B0, 0xCCBF, 0x62B1, 0xA9EA, 0x62B3, 0xCCBB, 0x62B4, 0xCCB4, 0x62B5, 0xA9E8, 0x62B6, 0xCCB8, 0x62B8, 0xCCC0, 0x62B9, 0xA9D9, 0x62BB, 0xCCBD, 0x62BC, 0xA9E3, 0x62BD, 0xA9E2, 0x62BE, 0xCCB6, 0x62BF, 0xA9D7, 0x62C2, 0xA9D8, 0x62C4, 0xA9D6, 0x62C6, 0xA9EE, 0x62C7, 0xA9E6, 0x62C8, 0xA9E0, 0x62C9, 0xA9D4, 0x62CA, 0xCCB9, 0x62CB, 0xA9DF, 0x62CC, 0xA9D5, 0x62CD, 0xA9E7, 0x62CE, 0xA9F0, 0x62CF, 0xCED4, 0x62D0, 0xA9E4, 0x62D1, 0xCCB5, 0x62D2, 0xA9DA, 0x62D3, 0xA9DD, 0x62D4, 0xA9DE, 0x62D6, 0xA9EC, 0x62D7, 0xA9ED, 0x62D8, 0xA9EB, 0x62D9, 0xA9E5, 0x62DA, 0xA9E9, 0x62DB, 0xA9DB, 0x62DC, 0xABF4, 0x62EB, 0xCEDA, 0x62EC, 0xAC41, 0x62ED, 0xABF8, 0x62EE, 0xABFA, 0x62EF, 0xAC40, 0x62F0, 0xCEE6, 0x62F1, 0xABFD, 0x62F2, 0xD1B1, 0x62F3, 0xAEB1, 0x62F4, 0xAC43, 0x62F5, 0xCED7, 0x62F6, 0xCEDF, 0x62F7, 0xABFE, 0x62F8, 0xCEDE, 0x62F9, 0xCEDB, 0x62FA, 0xCEE3, 0x62FB, 0xCEE5, 0x62FC, 0xABF7, 0x62FD, 0xABFB, 0x62FE, 0xAC42, 0x62FF, 0xAEB3, 0x6300, 0xCEE0, 0x6301, 0xABF9, 0x6302, 0xAC45, 0x6303, 0xCED9, 0x6307, 0xABFC, 0x6308, 0xAEB2, 0x6309, 0xABF6, 0x630B, 0xCED6, 0x630C, 0xCEDD, 0x630D, 0xCED5, 0x630E, 0xCED8, 0x630F, 0xCEDC, 0x6310, 0xD1B2, 0x6311, 0xAC44, 0x6313, 0xCEE1, 0x6314, 0xCEE2, 0x6315, 0xCEE4, 0x6316, 0xABF5, 0x6328, 0xAEC1, 0x6329, 0xD1BE, 0x632A, 0xAEBF, 0x632B, 0xAEC0, 0x632C, 0xD1B4, 0x632D, 0xD1C4, 0x632F, 0xAEB6, 0x6332, 0xD566, 0x6333, 0xD1C6, 0x6334, 0xD1C0, 0x6336, 0xD1B7, 0x6338, 0xD1C9, 0x6339, 0xD1BA, 0x633A, 0xAEBC, 0x633B, 0xD57D, 0x633C, 0xD1BD, 0x633D, 0xAEBE, 0x633E, 0xAEB5, 0x6340, 0xD1CB, 0x6341, 0xD1BF, 0x6342, 0xAEB8, 0x6343, 0xD1B8, 0x6344, 0xD1B5, 0x6345, 0xD1B6, 0x6346, 0xAEB9, 0x6347, 0xD1C5, 0x6348, 0xD1CC, 0x6349, 0xAEBB, 0x634A, 0xD1BC, 0x634B, 0xD1BB, 0x634C, 0xAEC3, 0x634D, 0xAEC2, 0x634E, 0xAEB4, 0x634F, 0xAEBA, 0x6350, 0xAEBD, 0x6351, 0xD1C8, 0x6354, 0xD1C2, 0x6355, 0xAEB7, 0x6356, 0xD1B3, 0x6357, 0xD1CA, 0x6358, 0xD1C1, 0x6359, 0xD1C3, 0x635A, 0xD1C7, 0x6365, 0xD567, 0x6367, 0xB1B7, 0x6368, 0xB1CB, 0x6369, 0xB1CA, 0x636B, 0xB1BF, 0x636D, 0xD579, 0x636E, 0xD575, 0x636F, 0xD572, 0x6370, 0xD5A6, 0x6371, 0xB1BA, 0x6372, 0xB1B2, 0x6375, 0xD577, 0x6376, 0xB4A8, 0x6377, 0xB1B6, 0x6378, 0xD5A1, 0x637A, 0xB1CC, 0x637B, 0xB1C9, 0x637C, 0xD57B, 0x637D, 0xD56A, 0x6380, 0xB1C8, 0x6381, 0xD5A3, 0x6382, 0xD569, 0x6383, 0xB1BD, 0x6384, 0xB1C1, 0x6385, 0xD5A2, 0x6387, 0xD573, 0x6388, 0xB1C2, 0x6389, 0xB1BC, 0x638A, 0xD568, 0x638C, 0xB478, 0x638D, 0xD5A5, 0x638E, 0xD571, 0x638F, 0xB1C7, 0x6390, 0xD574, 0x6391, 0xD5A4, 0x6392, 0xB1C6, 0x6394, 0xD952, 0x6396, 0xB1B3, 0x6397, 0xD56F, 0x6398, 0xB1B8, 0x6399, 0xB1C3, 0x639B, 0xB1BE, 0x639C, 0xD578, 0x639D, 0xD56E, 0x639E, 0xD56C, 0x639F, 0xD57E, 0x63A0, 0xB1B0, 0x63A1, 0xB1C4, 0x63A2, 0xB1B4, 0x63A3, 0xB477, 0x63A4, 0xD57C, 0x63A5, 0xB1B5, 0x63A7, 0xB1B1, 0x63A8, 0xB1C0, 0x63A9, 0xB1BB, 0x63AA, 0xB1B9, 0x63AB, 0xD570, 0x63AC, 0xB1C5, 0x63AD, 0xD56D, 0x63AE, 0xD57A, 0x63AF, 0xD576, 0x63B0, 0xD954, 0x63B1, 0xD953, 0x63BD, 0xD56B, 0x63BE, 0xD964, 0x63C0, 0xB47A, 0x63C2, 0xD96A, 0x63C3, 0xD959, 0x63C4, 0xD967, 0x63C5, 0xDD77, 0x63C6, 0xB47D, 0x63C7, 0xD96B, 0x63C8, 0xD96E, 0x63C9, 0xB47C, 0x63CA, 0xD95C, 0x63CB, 0xD96D, 0x63CC, 0xD96C, 0x63CD, 0xB47E, 0x63CE, 0xD955, 0x63CF, 0xB479, 0x63D0, 0xB4A3, 0x63D2, 0xB4A1, 0x63D3, 0xD969, 0x63D5, 0xD95F, 0x63D6, 0xB4A5, 0x63D7, 0xD970, 0x63D8, 0xD968, 0x63D9, 0xD971, 0x63DA, 0xB4AD, 0x63DB, 0xB4AB, 0x63DC, 0xD966, 0x63DD, 0xD965, 0x63DF, 0xD963, 0x63E0, 0xD95D, 0x63E1, 0xB4A4, 0x63E3, 0xB4A2, 0x63E4, 0xD1B9, 0x63E5, 0xD956, 0x63E7, 0xDDB7, 0x63E8, 0xD957, 0x63E9, 0xB47B, 0x63EA, 0xB4AA, 0x63EB, 0xDD79, 0x63ED, 0xB4A6, 0x63EE, 0xB4A7, 0x63EF, 0xD958, 0x63F0, 0xD96F, 0x63F1, 0xDD78, 0x63F2, 0xD960, 0x63F3, 0xD95B, 0x63F4, 0xB4A9, 0x63F5, 0xD961, 0x63F6, 0xD95E, 0x63F9, 0xB4AE, 0x6406, 0xB770, 0x6409, 0xDD7C, 0x640A, 0xDDB1, 0x640B, 0xDDB6, 0x640C, 0xDDAA, 0x640D, 0xB76C, 0x640E, 0xDDBB, 0x640F, 0xB769, 0x6410, 0xDD7A, 0x6412, 0xDD7B, 0x6413, 0xB762, 0x6414, 0xB76B, 0x6415, 0xDDA4, 0x6416, 0xB76E, 0x6417, 0xB76F, 0x6418, 0xDDA5, 0x641A, 0xDDB2, 0x641B, 0xDDB8, 0x641C, 0xB76A, 0x641E, 0xB764, 0x641F, 0xDDA3, 0x6420, 0xDD7D, 0x6421, 0xDDBA, 0x6422, 0xDDA8, 0x6423, 0xDDA9, 0x6424, 0xDD7E, 0x6425, 0xDDB4, 0x6426, 0xDDAB, 0x6427, 0xDDB5, 0x6428, 0xDDAD, 0x642A, 0xB765, 0x642B, 0xE1D9, 0x642C, 0xB768, 0x642D, 0xB766, 0x642E, 0xDDB9, 0x642F, 0xDDB0, 0x6430, 0xDDAC, 0x6433, 0xDDA1, 0x6434, 0xBA53, 0x6435, 0xDDAF, 0x6436, 0xB76D, 0x6437, 0xDDA7, 0x6439, 0xDDA6, 0x643D, 0xB767, 0x643E, 0xB763, 0x643F, 0xE1EE, 0x6440, 0xDDB3, 0x6441, 0xDDAE, 0x6443, 0xDDA2, 0x644B, 0xE1E9, 0x644D, 0xE1DA, 0x644E, 0xE1E5, 0x6450, 0xE1EC, 0x6451, 0xBA51, 0x6452, 0xB4AC, 0x6453, 0xE1EA, 0x6454, 0xBA4C, 0x6458, 0xBA4B, 0x6459, 0xE1F1, 0x645B, 0xE1DB, 0x645C, 0xE1E8, 0x645D, 0xE1DC, 0x645E, 0xE1E7, 0x645F, 0xBA4F, 0x6460, 0xE1EB, 0x6461, 0xD962, 0x6465, 0xE1F2, 0x6466, 0xE1E3, 0x6467, 0xBA52, 0x6468, 0xE5BA, 0x6469, 0xBCAF, 0x646B, 0xE1F0, 0x646C, 0xE1EF, 0x646D, 0xBA54, 0x646E, 0xE5AD, 0x646F, 0xBCB0, 0x6470, 0xE5AE, 0x6472, 0xE1DF, 0x6473, 0xE1E0, 0x6474, 0xE1DD, 0x6475, 0xE1E2, 0x6476, 0xE1DE, 0x6477, 0xE1F3, 0x6478, 0xBA4E, 0x6479, 0xBCB1, 0x647A, 0xBA50, 0x647B, 0xBA55, 0x647D, 0xE1E1, 0x647F, 0xE1ED, 0x6482, 0xE1E6, 0x6485, 0xE5B1, 0x6487, 0xBA4A, 0x6488, 0xBCB4, 0x6489, 0xE9AA, 0x648A, 0xE5B6, 0x648B, 0xE5B5, 0x648C, 0xE5B7, 0x648F, 0xE5B4, 0x6490, 0xBCB5, 0x6492, 0xBCBB, 0x6493, 0xBCB8, 0x6495, 0xBCB9, 0x6496, 0xE5AF, 0x6497, 0xE5B2, 0x6498, 0xE5BC, 0x6499, 0xBCC1, 0x649A, 0xBCBF, 0x649C, 0xE5B3, 0x649D, 0xD95A, 0x649E, 0xBCB2, 0x649F, 0xE5B9, 0x64A0, 0xE5B0, 0x64A2, 0xBCC2, 0x64A3, 0xE5B8, 0x64A4, 0xBA4D, 0x64A5, 0xBCB7, 0x64A6, 0xE1E4, 0x64A9, 0xBCBA, 0x64AB, 0xBCBE, 0x64AC, 0xBCC0, 0x64AD, 0xBCBD, 0x64AE, 0xBCBC, 0x64B0, 0xBCB6, 0x64B1, 0xE5BB, 0x64B2, 0xBCB3, 0x64B3, 0xBCC3, 0x64BB, 0xBED8, 0x64BC, 0xBED9, 0x64BD, 0xE9A9, 0x64BE, 0xBEE2, 0x64BF, 0xBEDF, 0x64C1, 0xBED6, 0x64C2, 0xBEDD, 0x64C3, 0xE9AB, 0x64C4, 0xBEDB, 0x64C5, 0xBED5, 0x64C7, 0xBEDC, 0x64C9, 0xE9A8, 0x64CA, 0xC0BB, 0x64CB, 0xBED7, 0x64CD, 0xBEDE, 0x64CE, 0xC0BA, 0x64CF, 0xE9A7, 0x64D0, 0xE9A6, 0x64D2, 0xBEE0, 0x64D4, 0xBEE1, 0x64D6, 0xE9A5, 0x64D7, 0xE9A4, 0x64D8, 0xC0BC, 0x64D9, 0xE9AE, 0x64DA, 0xBEDA, 0x64DB, 0xE9AC, 0x64E0, 0xC0BD, 0x64E2, 0xC0C2, 0x64E3, 0xECEA, 0x64E4, 0xECEC, 0x64E6, 0xC0BF, 0x64E8, 0xECED, 0x64E9, 0xECE9, 0x64EB, 0xECEB, 0x64EC, 0xC0C0, 0x64ED, 0xC0C3, 0x64EF, 0xECE8, 0x64F0, 0xC0BE, 0x64F1, 0xC0C1, 0x64F2, 0xC259, 0x64F3, 0xE9AD, 0x64F4, 0xC258, 0x64F7, 0xC25E, 0x64F8, 0xEFD4, 0x64FA, 0xC25C, 0x64FB, 0xC25D, 0x64FC, 0xEFD7, 0x64FD, 0xEFD3, 0x64FE, 0xC25A, 0x64FF, 0xEFD1, 0x6500, 0xC36B, 0x6501, 0xEFD5, 0x6503, 0xEFD6, 0x6504, 0xEFD2, 0x6506, 0xC25B, 0x6507, 0xF242, 0x6509, 0xF245, 0x650C, 0xF246, 0x650D, 0xF244, 0x650E, 0xF247, 0x650F, 0xC36C, 0x6510, 0xF243, 0x6513, 0xF44E, 0x6514, 0xC464, 0x6515, 0xF44D, 0x6516, 0xF44C, 0x6517, 0xF44B, 0x6518, 0xC463, 0x6519, 0xC465, 0x651B, 0xF5CD, 0x651C, 0xC4E2, 0x651D, 0xC4E1, 0x6520, 0xF6E1, 0x6521, 0xF6E0, 0x6522, 0xF6E3, 0x6523, 0xC5CB, 0x6524, 0xC575, 0x6525, 0xF7DD, 0x6526, 0xF6E2, 0x6529, 0xF7DC, 0x652A, 0xC5CD, 0x652B, 0xC5CC, 0x652C, 0xC5F3, 0x652D, 0xF8A9, 0x652E, 0xF8EF, 0x652F, 0xA4E4, 0x6532, 0xD972, 0x6533, 0xE9AF, 0x6536, 0xA6AC, 0x6537, 0xCAF7, 0x6538, 0xA7F1, 0x6539, 0xA7EF, 0x653B, 0xA7F0, 0x653D, 0xCCC1, 0x653E, 0xA9F1, 0x653F, 0xAC46, 0x6541, 0xCEE7, 0x6543, 0xCEE8, 0x6545, 0xAC47, 0x6546, 0xD1CE, 0x6548, 0xAEC4, 0x6549, 0xAEC5, 0x654A, 0xD1CD, 0x654F, 0xB1D3, 0x6551, 0xB1CF, 0x6553, 0xD5A7, 0x6554, 0xB1D6, 0x6555, 0xB1D5, 0x6556, 0xB1CE, 0x6557, 0xB1D1, 0x6558, 0xB1D4, 0x6559, 0xB1D0, 0x655C, 0xD976, 0x655D, 0xB1CD, 0x655E, 0xB4AF, 0x6562, 0xB4B1, 0x6563, 0xB4B2, 0x6564, 0xD975, 0x6565, 0xD978, 0x6566, 0xB4B0, 0x6567, 0xD973, 0x6568, 0xD977, 0x656A, 0xD974, 0x656C, 0xB771, 0x656F, 0xDDBC, 0x6572, 0xBA56, 0x6573, 0xE1F4, 0x6574, 0xBEE3, 0x6575, 0xBCC4, 0x6576, 0xE5BD, 0x6577, 0xBCC5, 0x6578, 0xBCC6, 0x6579, 0xE5BF, 0x657A, 0xE5BE, 0x657B, 0xE5C0, 0x657C, 0xE9B1, 0x657F, 0xE9B0, 0x6580, 0xECEF, 0x6581, 0xECEE, 0x6582, 0xC0C4, 0x6583, 0xC0C5, 0x6584, 0xF248, 0x6587, 0xA4E5, 0x658C, 0xD979, 0x6590, 0xB4B4, 0x6591, 0xB4B3, 0x6592, 0xDDBD, 0x6594, 0xEFD8, 0x6595, 0xC4E3, 0x6596, 0xF7DE, 0x6597, 0xA4E6, 0x6599, 0xAEC6, 0x659B, 0xB1D8, 0x659C, 0xB1D7, 0x659D, 0xD97A, 0x659E, 0xD97B, 0x659F, 0xB772, 0x65A0, 0xE1F5, 0x65A1, 0xBA57, 0x65A2, 0xE9B2, 0x65A4, 0xA4E7, 0x65A5, 0xA5B8, 0x65A7, 0xA9F2, 0x65A8, 0xCCC2, 0x65AA, 0xCEE9, 0x65AB, 0xAC48, 0x65AC, 0xB1D9, 0x65AE, 0xD97C, 0x65AF, 0xB4B5, 0x65B0, 0xB773, 0x65B2, 0xE5C1, 0x65B3, 0xE5C2, 0x65B6, 0xECF0, 0x65B7, 0xC25F, 0x65B8, 0xF8F0, 0x65B9, 0xA4E8, 0x65BB, 0xCCC3, 0x65BC, 0xA9F3, 0x65BD, 0xAC49, 0x65BF, 0xCEEA, 0x65C1, 0xAEC7, 0x65C2, 0xD1D2, 0x65C3, 0xD1D0, 0x65C4, 0xD1D1, 0x65C5, 0xAEC8, 0x65C6, 0xD1CF, 0x65CB, 0xB1DB, 0x65CC, 0xB1DC, 0x65CD, 0xD5A8, 0x65CE, 0xB1DD, 0x65CF, 0xB1DA, 0x65D0, 0xD97D, 0x65D2, 0xD97E, 0x65D3, 0xDDBE, 0x65D6, 0xBA59, 0x65D7, 0xBA58, 0x65DA, 0xECF1, 0x65DB, 0xEFD9, 0x65DD, 0xF24A, 0x65DE, 0xF249, 0x65DF, 0xF44F, 0x65E1, 0xC95E, 0x65E2, 0xAC4A, 0x65E5, 0xA4E9, 0x65E6, 0xA5B9, 0x65E8, 0xA6AE, 0x65E9, 0xA6AD, 0x65EC, 0xA6AF, 0x65ED, 0xA6B0, 0x65EE, 0xC9EE, 0x65EF, 0xC9ED, 0x65F0, 0xCAF8, 0x65F1, 0xA7F2, 0x65F2, 0xCAFB, 0x65F3, 0xCAFA, 0x65F4, 0xCAF9, 0x65F5, 0xCAFC, 0x65FA, 0xA9F4, 0x65FB, 0xCCC9, 0x65FC, 0xCCC5, 0x65FD, 0xCCCE, 0x6600, 0xA9FB, 0x6602, 0xA9F9, 0x6603, 0xCCCA, 0x6604, 0xCCC6, 0x6605, 0xCCCD, 0x6606, 0xA9F8, 0x6607, 0xAA40, 0x6608, 0xCCC8, 0x6609, 0xCCC4, 0x660A, 0xA9FE, 0x660B, 0xCCCB, 0x660C, 0xA9F7, 0x660D, 0xCCCC, 0x660E, 0xA9FA, 0x660F, 0xA9FC, 0x6610, 0xCCD0, 0x6611, 0xCCCF, 0x6612, 0xCCC7, 0x6613, 0xA9F6, 0x6614, 0xA9F5, 0x6615, 0xA9FD, 0x661C, 0xCEEF, 0x661D, 0xCEF5, 0x661F, 0xAC50, 0x6620, 0xAC4D, 0x6621, 0xCEEC, 0x6622, 0xCEF1, 0x6624, 0xAC53, 0x6625, 0xAC4B, 0x6626, 0xCEF0, 0x6627, 0xAC4E, 0x6628, 0xAC51, 0x662B, 0xCEF3, 0x662D, 0xAC4C, 0x662E, 0xCEF8, 0x662F, 0xAC4F, 0x6631, 0xAC52, 0x6632, 0xCEED, 0x6633, 0xCEF2, 0x6634, 0xCEF6, 0x6635, 0xCEEE, 0x6636, 0xCEEB, 0x6639, 0xCEF7, 0x663A, 0xCEF4, 0x6641, 0xAED0, 0x6642, 0xAEC9, 0x6643, 0xAECC, 0x6645, 0xAECF, 0x6647, 0xD1D5, 0x6649, 0xAECA, 0x664A, 0xD1D3, 0x664C, 0xAECE, 0x664F, 0xAECB, 0x6651, 0xD1D6, 0x6652, 0xAECD, 0x6659, 0xD5AC, 0x665A, 0xB1DF, 0x665B, 0xD5AB, 0x665C, 0xD5AD, 0x665D, 0xB1DE, 0x665E, 0xB1E3, 0x665F, 0xD1D4, 0x6661, 0xD5AA, 0x6662, 0xD5AE, 0x6664, 0xB1E0, 0x6665, 0xD5A9, 0x6666, 0xB1E2, 0x6668, 0xB1E1, 0x666A, 0xD9A7, 0x666C, 0xD9A2, 0x666E, 0xB4B6, 0x666F, 0xB4BA, 0x6670, 0xB4B7, 0x6671, 0xD9A5, 0x6672, 0xD9A8, 0x6674, 0xB4B8, 0x6676, 0xB4B9, 0x6677, 0xB4BE, 0x6678, 0xDDC7, 0x6679, 0xD9A6, 0x667A, 0xB4BC, 0x667B, 0xD9A3, 0x667C, 0xD9A1, 0x667E, 0xB4BD, 0x6680, 0xD9A4, 0x6684, 0xB779, 0x6686, 0xDDBF, 0x6687, 0xB776, 0x6688, 0xB777, 0x6689, 0xB775, 0x668A, 0xDDC4, 0x668B, 0xDDC3, 0x668C, 0xDDC0, 0x668D, 0xB77B, 0x6690, 0xDDC2, 0x6691, 0xB4BB, 0x6694, 0xDDC6, 0x6695, 0xDDC1, 0x6696, 0xB778, 0x6697, 0xB774, 0x6698, 0xB77A, 0x6699, 0xDDC5, 0x669D, 0xBA5C, 0x669F, 0xE1F8, 0x66A0, 0xE1F7, 0x66A1, 0xE1F6, 0x66A2, 0xBA5A, 0x66A8, 0xBA5B, 0x66A9, 0xE5C5, 0x66AA, 0xE5C8, 0x66AB, 0xBCC8, 0x66AE, 0xBCC7, 0x66AF, 0xE5C9, 0x66B0, 0xE5C4, 0x66B1, 0xBCCA, 0x66B2, 0xE5C6, 0x66B4, 0xBCC9, 0x66B5, 0xE5C3, 0x66B7, 0xE5C7, 0x66B8, 0xBEE9, 0x66B9, 0xBEE6, 0x66BA, 0xE9BB, 0x66BB, 0xE9BA, 0x66BD, 0xE9B9, 0x66BE, 0xE9B4, 0x66C0, 0xE9B5, 0x66C4, 0xBEE7, 0x66C6, 0xBEE4, 0x66C7, 0xBEE8, 0x66C8, 0xE9B3, 0x66C9, 0xBEE5, 0x66CA, 0xE9B6, 0x66CB, 0xE9B7, 0x66CC, 0xE9BC, 0x66CF, 0xE9B8, 0x66D2, 0xECF2, 0x66D6, 0xC0C7, 0x66D8, 0xEFDC, 0x66D9, 0xC0C6, 0x66DA, 0xEFDA, 0x66DB, 0xEFDB, 0x66DC, 0xC260, 0x66DD, 0xC36E, 0x66DE, 0xF24B, 0x66E0, 0xC36D, 0x66E3, 0xF451, 0x66E4, 0xF452, 0x66E6, 0xC466, 0x66E8, 0xF450, 0x66E9, 0xC4E4, 0x66EB, 0xF7DF, 0x66EC, 0xC5CE, 0x66ED, 0xF8AA, 0x66EE, 0xF8AB, 0x66F0, 0xA4EA, 0x66F2, 0xA6B1, 0x66F3, 0xA6B2, 0x66F4, 0xA7F3, 0x66F6, 0xCCD1, 0x66F7, 0xAC54, 0x66F8, 0xAED1, 0x66F9, 0xB1E4, 0x66FC, 0xB0D2, 0x66FE, 0xB4BF, 0x66FF, 0xB4C0, 0x6700, 0xB3CC, 0x6701, 0xD9A9, 0x6703, 0xB77C, 0x6704, 0xE1FA, 0x6705, 0xE1F9, 0x6708, 0xA4EB, 0x6709, 0xA6B3, 0x670A, 0xCCD2, 0x670B, 0xAA42, 0x670D, 0xAA41, 0x670F, 0xCEF9, 0x6710, 0xCEFA, 0x6712, 0xD1D7, 0x6713, 0xD1D8, 0x6714, 0xAED2, 0x6715, 0xAED3, 0x6717, 0xAED4, 0x6718, 0xD5AF, 0x671B, 0xB1E6, 0x671D, 0xB4C2, 0x671F, 0xB4C1, 0x6720, 0xDDC8, 0x6721, 0xDF7A, 0x6722, 0xE1FB, 0x6723, 0xE9BD, 0x6726, 0xC261, 0x6727, 0xC467, 0x6728, 0xA4EC, 0x672A, 0xA5BC, 0x672B, 0xA5BD, 0x672C, 0xA5BB, 0x672D, 0xA5BE, 0x672E, 0xA5BA, 0x6731, 0xA6B6, 0x6733, 0xC9F6, 0x6734, 0xA6B5, 0x6735, 0xA6B7, 0x6738, 0xC9F1, 0x6739, 0xC9F0, 0x673A, 0xC9F3, 0x673B, 0xC9F2, 0x673C, 0xC9F5, 0x673D, 0xA6B4, 0x673E, 0xC9EF, 0x673F, 0xC9F4, 0x6745, 0xCAFD, 0x6746, 0xA7FD, 0x6747, 0xCAFE, 0x6748, 0xCB43, 0x6749, 0xA7FC, 0x674B, 0xCB47, 0x674C, 0xCB42, 0x674D, 0xCB45, 0x674E, 0xA7F5, 0x674F, 0xA7F6, 0x6750, 0xA7F7, 0x6751, 0xA7F8, 0x6753, 0xA840, 0x6755, 0xCB41, 0x6756, 0xA7FA, 0x6757, 0xA841, 0x6759, 0xCB40, 0x675A, 0xCB46, 0x675C, 0xA7F9, 0x675D, 0xCB44, 0x675E, 0xA7FB, 0x675F, 0xA7F4, 0x6760, 0xA7FE, 0x676A, 0xAA57, 0x676C, 0xCCD4, 0x676D, 0xAA43, 0x676F, 0xAA4D, 0x6770, 0xAA4E, 0x6771, 0xAA46, 0x6772, 0xAA58, 0x6773, 0xAA48, 0x6774, 0xCCDC, 0x6775, 0xAA53, 0x6776, 0xCCD7, 0x6777, 0xAA49, 0x6778, 0xCCE6, 0x6779, 0xCCE7, 0x677A, 0xCCDF, 0x677B, 0xCCD8, 0x677C, 0xAA56, 0x677D, 0xCCE4, 0x677E, 0xAA51, 0x677F, 0xAA4F, 0x6781, 0xCCE5, 0x6783, 0xCCE3, 0x6784, 0xCCDB, 0x6785, 0xCCD3, 0x6786, 0xCCDA, 0x6787, 0xAA4A, 0x6789, 0xAA50, 0x678B, 0xAA44, 0x678C, 0xCCDE, 0x678D, 0xCCDD, 0x678E, 0xCCD5, 0x6790, 0xAA52, 0x6791, 0xCCE1, 0x6792, 0xCCD6, 0x6793, 0xAA55, 0x6794, 0xCCE8, 0x6795, 0xAA45, 0x6797, 0xAA4C, 0x6798, 0xCCD9, 0x6799, 0xCCE2, 0x679A, 0xAA54, 0x679C, 0xAA47, 0x679D, 0xAA4B, 0x679F, 0xCCE0, 0x67AE, 0xCF5B, 0x67AF, 0xAC5C, 0x67B0, 0xAC69, 0x67B2, 0xCF56, 0x67B3, 0xCF4C, 0x67B4, 0xAC62, 0x67B5, 0xCF4A, 0x67B6, 0xAC5B, 0x67B7, 0xCF45, 0x67B8, 0xAC65, 0x67B9, 0xCF52, 0x67BA, 0xCEFE, 0x67BB, 0xCF41, 0x67C0, 0xCF44, 0x67C1, 0xCEFB, 0x67C2, 0xCF51, 0x67C3, 0xCF61, 0x67C4, 0xAC60, 0x67C5, 0xCF46, 0x67C6, 0xCF58, 0x67C8, 0xCEFD, 0x67C9, 0xCF5F, 0x67CA, 0xCF60, 0x67CB, 0xCF63, 0x67CC, 0xCF5A, 0x67CD, 0xCF4B, 0x67CE, 0xCF53, 0x67CF, 0xAC66, 0x67D0, 0xAC59, 0x67D1, 0xAC61, 0x67D2, 0xAC6D, 0x67D3, 0xAC56, 0x67D4, 0xAC58, 0x67D8, 0xCF43, 0x67D9, 0xAC6A, 0x67DA, 0xAC63, 0x67DB, 0xCF5D, 0x67DC, 0xCF40, 0x67DD, 0xAC6C, 0x67DE, 0xAC67, 0x67DF, 0xCF49, 0x67E2, 0xAC6B, 0x67E3, 0xCF50, 0x67E4, 0xCF48, 0x67E5, 0xAC64, 0x67E6, 0xCF5C, 0x67E7, 0xCF54, 0x67E9, 0xAC5E, 0x67EA, 0xCF62, 0x67EB, 0xCF47, 0x67EC, 0xAC5A, 0x67ED, 0xCF59, 0x67EE, 0xCF4F, 0x67EF, 0xAC5F, 0x67F0, 0xCF55, 0x67F1, 0xAC57, 0x67F2, 0xCEFC, 0x67F3, 0xAC68, 0x67F4, 0xAEE3, 0x67F5, 0xAC5D, 0x67F6, 0xCF4E, 0x67F7, 0xCF4D, 0x67F8, 0xCF42, 0x67FA, 0xCF5E, 0x67FC, 0xCF57, 0x67FF, 0xAC55, 0x6812, 0xD1EC, 0x6813, 0xAEEA, 0x6814, 0xD1ED, 0x6816, 0xD1E1, 0x6817, 0xAEDF, 0x6818, 0xAEEB, 0x681A, 0xD1DA, 0x681C, 0xD1E3, 0x681D, 0xD1EB, 0x681F, 0xD1D9, 0x6820, 0xD1F4, 0x6821, 0xAED5, 0x6825, 0xD1F3, 0x6826, 0xD1EE, 0x6828, 0xD1EF, 0x6829, 0xAEDD, 0x682A, 0xAEE8, 0x682B, 0xD1E5, 0x682D, 0xD1E6, 0x682E, 0xD1F0, 0x682F, 0xD1E7, 0x6831, 0xD1E2, 0x6832, 0xD1DC, 0x6833, 0xD1DD, 0x6834, 0xD1EA, 0x6835, 0xD1E4, 0x6838, 0xAED6, 0x6839, 0xAEDA, 0x683A, 0xD1F2, 0x683B, 0xD1DE, 0x683C, 0xAEE6, 0x683D, 0xAEE2, 0x6840, 0xAEE5, 0x6841, 0xAEEC, 0x6842, 0xAEDB, 0x6843, 0xAEE7, 0x6844, 0xD1E9, 0x6845, 0xAEE9, 0x6846, 0xAED8, 0x6848, 0xAED7, 0x6849, 0xD1DB, 0x684B, 0xD1DF, 0x684C, 0xAEE0, 0x684D, 0xD1F1, 0x684E, 0xD1E8, 0x684F, 0xD1E0, 0x6850, 0xAEE4, 0x6851, 0xAEE1, 0x6853, 0xAED9, 0x6854, 0xAEDC, 0x686B, 0xD5C4, 0x686D, 0xD5B4, 0x686E, 0xD5B5, 0x686F, 0xD5B9, 0x6871, 0xD5C8, 0x6872, 0xD5C5, 0x6874, 0xD5BE, 0x6875, 0xD5BD, 0x6876, 0xB1ED, 0x6877, 0xD5C1, 0x6878, 0xD5D0, 0x6879, 0xD5B0, 0x687B, 0xD5D1, 0x687C, 0xD5C3, 0x687D, 0xD5D5, 0x687E, 0xD5C9, 0x687F, 0xB1EC, 0x6880, 0xD5C7, 0x6881, 0xB1E7, 0x6882, 0xB1FC, 0x6883, 0xB1F2, 0x6885, 0xB1F6, 0x6886, 0xB1F5, 0x6887, 0xD5B1, 0x6889, 0xD5CE, 0x688A, 0xD5D4, 0x688B, 0xD5CC, 0x688C, 0xD5D3, 0x688F, 0xD5C0, 0x6890, 0xD5B2, 0x6891, 0xD5D2, 0x6892, 0xD5C2, 0x6893, 0xB1EA, 0x6894, 0xB1F7, 0x6896, 0xD5CB, 0x6897, 0xB1F0, 0x689B, 0xD5CA, 0x689C, 0xD5B3, 0x689D, 0xB1F8, 0x689F, 0xB1FA, 0x68A0, 0xD5CD, 0x68A1, 0xB1FB, 0x68A2, 0xB1E9, 0x68A3, 0xD5BA, 0x68A4, 0xD5CF, 0x68A7, 0xB1EF, 0x68A8, 0xB1F9, 0x68A9, 0xD5BC, 0x68AA, 0xD5C6, 0x68AB, 0xD5B7, 0x68AC, 0xD5BB, 0x68AD, 0xB1F4, 0x68AE, 0xD5B6, 0x68AF, 0xB1E8, 0x68B0, 0xB1F1, 0x68B1, 0xB1EE, 0x68B2, 0xD5BF, 0x68B3, 0xAEDE, 0x68B4, 0xD9C0, 0x68B5, 0xB1EB, 0x68C4, 0xB1F3, 0x68C6, 0xD9C3, 0x68C7, 0xD9D9, 0x68C8, 0xD9CE, 0x68C9, 0xB4D6, 0x68CB, 0xB4D1, 0x68CC, 0xD9BD, 0x68CD, 0xB4D2, 0x68CE, 0xD9CD, 0x68D0, 0xD9C6, 0x68D1, 0xD9D3, 0x68D2, 0xB4CE, 0x68D3, 0xD9AB, 0x68D4, 0xD9D5, 0x68D5, 0xB4C4, 0x68D6, 0xD9B3, 0x68D7, 0xB4C7, 0x68D8, 0xB4C6, 0x68DA, 0xB4D7, 0x68DC, 0xD9AD, 0x68DD, 0xD9CF, 0x68DE, 0xD9D0, 0x68DF, 0xB4C9, 0x68E0, 0xB4C5, 0x68E1, 0xD9BB, 0x68E3, 0xB4D0, 0x68E4, 0xD9B6, 0x68E6, 0xD9D1, 0x68E7, 0xB4CC, 0x68E8, 0xD9C9, 0x68E9, 0xD9D6, 0x68EA, 0xD9B0, 0x68EB, 0xD9B5, 0x68EC, 0xD9AF, 0x68EE, 0xB4CB, 0x68EF, 0xD9C2, 0x68F0, 0xDDDE, 0x68F1, 0xD9B1, 0x68F2, 0xB4CF, 0x68F3, 0xD9BA, 0x68F4, 0xD9D2, 0x68F5, 0xB4CA, 0x68F6, 0xD9B7, 0x68F7, 0xD9B4, 0x68F8, 0xD9C5, 0x68F9, 0xB4CD, 0x68FA, 0xB4C3, 0x68FB, 0xB4D9, 0x68FC, 0xD9C8, 0x68FD, 0xD9C7, 0x6904, 0xD9AC, 0x6905, 0xB4C8, 0x6906, 0xD9D4, 0x6907, 0xD9BC, 0x6908, 0xD9BE, 0x690A, 0xD9CB, 0x690B, 0xD9CA, 0x690C, 0xD9AA, 0x690D, 0xB4D3, 0x690E, 0xB4D5, 0x690F, 0xD9B2, 0x6910, 0xD9B9, 0x6911, 0xD9C1, 0x6912, 0xB4D4, 0x6913, 0xD9B8, 0x6914, 0xD9C4, 0x6915, 0xD9D7, 0x6917, 0xD9CC, 0x6925, 0xD9D8, 0x692A, 0xD9AE, 0x692F, 0xDDF2, 0x6930, 0xB7A6, 0x6932, 0xDDF0, 0x6933, 0xDDDB, 0x6934, 0xDDE0, 0x6935, 0xDDD9, 0x6937, 0xDDEC, 0x6938, 0xDDCB, 0x6939, 0xDDD2, 0x693B, 0xDDEA, 0x693C, 0xDDF4, 0x693D, 0xDDDC, 0x693F, 0xDDCF, 0x6940, 0xDDE2, 0x6941, 0xDDE7, 0x6942, 0xDDD3, 0x6944, 0xDDE4, 0x6945, 0xDDD0, 0x6948, 0xDDD7, 0x6949, 0xDDD8, 0x694A, 0xB7A8, 0x694B, 0xDDEB, 0x694C, 0xDDE9, 0x694E, 0xDDCC, 0x694F, 0xDDEE, 0x6951, 0xDDEF, 0x6952, 0xDDF1, 0x6953, 0xB7AC, 0x6954, 0xB7A4, 0x6956, 0xD5B8, 0x6957, 0xDDD4, 0x6958, 0xDDE6, 0x6959, 0xDDD5, 0x695A, 0xB7A1, 0x695B, 0xB7B1, 0x695C, 0xDDED, 0x695D, 0xB7AF, 0x695E, 0xB7AB, 0x695F, 0xDDCA, 0x6960, 0xB7A3, 0x6962, 0xDDCD, 0x6963, 0xB7B0, 0x6965, 0xDDDD, 0x6966, 0xDDC9, 0x6968, 0xB7A9, 0x6969, 0xDDE1, 0x696A, 0xDDD1, 0x696B, 0xB7AA, 0x696C, 0xDDDA, 0x696D, 0xB77E, 0x696E, 0xB4D8, 0x696F, 0xDDE3, 0x6970, 0xD9BF, 0x6971, 0xDDCE, 0x6974, 0xDDE8, 0x6975, 0xB7A5, 0x6976, 0xDDE5, 0x6977, 0xB7A2, 0x6978, 0xDDDF, 0x6979, 0xB7AD, 0x697A, 0xDDD6, 0x697B, 0xDDF3, 0x6982, 0xB7A7, 0x6983, 0xDEC6, 0x6986, 0xB7AE, 0x698D, 0xE24A, 0x698E, 0xE248, 0x6990, 0xE25E, 0x6991, 0xE246, 0x6993, 0xE258, 0x6994, 0xB77D, 0x6995, 0xBA5F, 0x6996, 0xE242, 0x6997, 0xE25D, 0x6999, 0xE247, 0x699A, 0xE255, 0x699B, 0xBA64, 0x699C, 0xBA5D, 0x699E, 0xE25B, 0x69A0, 0xE240, 0x69A1, 0xE25A, 0x69A3, 0xBA6F, 0x69A4, 0xE251, 0x69A5, 0xE261, 0x69A6, 0xBA6D, 0x69A7, 0xE249, 0x69A8, 0xBA5E, 0x69A9, 0xE24B, 0x69AA, 0xE259, 0x69AB, 0xBA67, 0x69AC, 0xE244, 0x69AD, 0xBA6B, 0x69AE, 0xBA61, 0x69AF, 0xE24D, 0x69B0, 0xE243, 0x69B1, 0xE1FC, 0x69B3, 0xE257, 0x69B4, 0xBA68, 0x69B5, 0xE260, 0x69B6, 0xE1FD, 0x69B7, 0xBA65, 0x69B9, 0xE253, 0x69BB, 0xBA66, 0x69BC, 0xE245, 0x69BD, 0xE250, 0x69BE, 0xE24C, 0x69BF, 0xE24E, 0x69C1, 0xBA60, 0x69C2, 0xE25F, 0x69C3, 0xBA6E, 0x69C4, 0xE24F, 0x69C6, 0xE262, 0x69C9, 0xE1FE, 0x69CA, 0xE254, 0x69CB, 0xBA63, 0x69CC, 0xBA6C, 0x69CD, 0xBA6A, 0x69CE, 0xE241, 0x69CF, 0xE256, 0x69D0, 0xBA69, 0x69D3, 0xBA62, 0x69D4, 0xE252, 0x69D9, 0xE25C, 0x69E2, 0xE5D5, 0x69E4, 0xE5D1, 0x69E5, 0xE5CD, 0x69E6, 0xE5E1, 0x69E7, 0xE5DE, 0x69E8, 0xBCCD, 0x69EB, 0xE5E5, 0x69EC, 0xE5D4, 0x69ED, 0xBCD8, 0x69EE, 0xE5DB, 0x69F1, 0xE5D0, 0x69F2, 0xE5DA, 0x69F3, 0xBCD5, 0x69F4, 0xE5EE, 0x69F6, 0xE5EB, 0x69F7, 0xE5DD, 0x69F8, 0xE5CE, 0x69FB, 0xE5E2, 0x69FC, 0xE5E4, 0x69FD, 0xBCD1, 0x69FE, 0xE5D8, 0x69FF, 0xE5D3, 0x6A00, 0xE5CA, 0x6A01, 0xBCCE, 0x6A02, 0xBCD6, 0x6A04, 0xE5E7, 0x6A05, 0xBCD7, 0x6A06, 0xE5CB, 0x6A07, 0xE5ED, 0x6A08, 0xE5E0, 0x6A09, 0xE5E6, 0x6A0A, 0xBCD4, 0x6A0D, 0xE5E3, 0x6A0F, 0xE5EA, 0x6A11, 0xBCD9, 0x6A13, 0xBCD3, 0x6A14, 0xE5DC, 0x6A15, 0xE5CF, 0x6A16, 0xE5EF, 0x6A17, 0xE5CC, 0x6A18, 0xE5E8, 0x6A19, 0xBCD0, 0x6A1B, 0xE5D6, 0x6A1D, 0xE5D7, 0x6A1E, 0xBCCF, 0x6A1F, 0xBCCC, 0x6A20, 0xE5D2, 0x6A21, 0xBCD2, 0x6A23, 0xBCCB, 0x6A25, 0xE5E9, 0x6A26, 0xE5EC, 0x6A27, 0xE5D9, 0x6A28, 0xE9CA, 0x6A32, 0xE9C2, 0x6A34, 0xE9BE, 0x6A35, 0xBEF6, 0x6A38, 0xBEEB, 0x6A39, 0xBEF0, 0x6A3A, 0xBEEC, 0x6A3B, 0xE9CC, 0x6A3C, 0xE9D7, 0x6A3D, 0xBEEA, 0x6A3E, 0xE9C4, 0x6A3F, 0xE9CD, 0x6A40, 0xE5DF, 0x6A41, 0xE9CE, 0x6A44, 0xBEF1, 0x6A46, 0xE9DD, 0x6A47, 0xBEF5, 0x6A48, 0xBEF8, 0x6A49, 0xE9C0, 0x6A4B, 0xBEF4, 0x6A4D, 0xE9DB, 0x6A4E, 0xE9DC, 0x6A4F, 0xE9D2, 0x6A50, 0xE9D1, 0x6A51, 0xE9C9, 0x6A54, 0xE9D3, 0x6A55, 0xE9DA, 0x6A56, 0xE9D9, 0x6A58, 0xBEEF, 0x6A59, 0xBEED, 0x6A5A, 0xE9CB, 0x6A5B, 0xE9C8, 0x6A5D, 0xE9C5, 0x6A5E, 0xE9D8, 0x6A5F, 0xBEF7, 0x6A60, 0xE9D6, 0x6A61, 0xBEF3, 0x6A62, 0xBEF2, 0x6A64, 0xE9D0, 0x6A66, 0xE9BF, 0x6A67, 0xE9C1, 0x6A68, 0xE9C3, 0x6A69, 0xE9D5, 0x6A6A, 0xE9CF, 0x6A6B, 0xBEEE, 0x6A6D, 0xE9C6, 0x6A6F, 0xE9D4, 0x6A76, 0xE9C7, 0x6A7E, 0xC0CF, 0x6A7F, 0xED45, 0x6A80, 0xC0C8, 0x6A81, 0xECF5, 0x6A83, 0xED41, 0x6A84, 0xC0CA, 0x6A85, 0xED48, 0x6A87, 0xECFC, 0x6A89, 0xECF7, 0x6A8C, 0xED49, 0x6A8D, 0xECF3, 0x6A8E, 0xECFE, 0x6A90, 0xC0D1, 0x6A91, 0xED44, 0x6A92, 0xED4A, 0x6A93, 0xECFD, 0x6A94, 0xC0C9, 0x6A95, 0xED40, 0x6A96, 0xECF4, 0x6A97, 0xC0D0, 0x6A9A, 0xED47, 0x6A9B, 0xECF9, 0x6A9C, 0xC0CC, 0x6A9E, 0xECFB, 0x6A9F, 0xECF8, 0x6AA0, 0xC0D2, 0x6AA1, 0xECFA, 0x6AA2, 0xC0CB, 0x6AA3, 0xC0CE, 0x6AA4, 0xED43, 0x6AA5, 0xECF6, 0x6AA6, 0xED46, 0x6AA8, 0xED42, 0x6AAC, 0xC263, 0x6AAD, 0xEFE7, 0x6AAE, 0xC268, 0x6AAF, 0xC269, 0x6AB3, 0xC262, 0x6AB4, 0xEFE6, 0x6AB6, 0xEFE3, 0x6AB7, 0xEFE4, 0x6AB8, 0xC266, 0x6AB9, 0xEFDE, 0x6ABA, 0xEFE2, 0x6ABB, 0xC265, 0x6ABD, 0xEFDF, 0x6AC2, 0xC267, 0x6AC3, 0xC264, 0x6AC5, 0xEFDD, 0x6AC6, 0xEFE1, 0x6AC7, 0xEFE5, 0x6ACB, 0xF251, 0x6ACC, 0xF24E, 0x6ACD, 0xF257, 0x6ACF, 0xF256, 0x6AD0, 0xF254, 0x6AD1, 0xF24F, 0x6AD3, 0xC372, 0x6AD9, 0xF250, 0x6ADA, 0xC371, 0x6ADB, 0xC0CD, 0x6ADC, 0xF253, 0x6ADD, 0xC370, 0x6ADE, 0xF258, 0x6ADF, 0xF252, 0x6AE0, 0xF24D, 0x6AE1, 0xEFE0, 0x6AE5, 0xC36F, 0x6AE7, 0xF24C, 0x6AE8, 0xF456, 0x6AEA, 0xF455, 0x6AEB, 0xF255, 0x6AEC, 0xC468, 0x6AEE, 0xF459, 0x6AEF, 0xF45A, 0x6AF0, 0xF454, 0x6AF1, 0xF458, 0x6AF3, 0xF453, 0x6AF8, 0xF5D1, 0x6AF9, 0xF457, 0x6AFA, 0xC4E7, 0x6AFB, 0xC4E5, 0x6AFC, 0xF5CF, 0x6B00, 0xF5D2, 0x6B02, 0xF5CE, 0x6B03, 0xF5D0, 0x6B04, 0xC4E6, 0x6B08, 0xF6E5, 0x6B09, 0xF6E6, 0x6B0A, 0xC576, 0x6B0B, 0xF6E4, 0x6B0F, 0xF7E2, 0x6B10, 0xC5CF, 0x6B11, 0xF7E0, 0x6B12, 0xF7E1, 0x6B13, 0xF8AC, 0x6B16, 0xC656, 0x6B17, 0xF8F3, 0x6B18, 0xF8F1, 0x6B19, 0xF8F2, 0x6B1A, 0xF8F4, 0x6B1E, 0xF9BB, 0x6B20, 0xA4ED, 0x6B21, 0xA6B8, 0x6B23, 0xAA59, 0x6B25, 0xCCE9, 0x6B28, 0xCF64, 0x6B2C, 0xD1F5, 0x6B2D, 0xD1F7, 0x6B2F, 0xD1F6, 0x6B31, 0xD1F8, 0x6B32, 0xB1FD, 0x6B33, 0xD5D7, 0x6B34, 0xD1F9, 0x6B36, 0xD5D6, 0x6B37, 0xD5D8, 0x6B38, 0xD5D9, 0x6B39, 0xD9DA, 0x6B3A, 0xB4DB, 0x6B3B, 0xD9DB, 0x6B3C, 0xD9DD, 0x6B3D, 0xB4DC, 0x6B3E, 0xB4DA, 0x6B3F, 0xD9DC, 0x6B41, 0xDDFA, 0x6B42, 0xDDF8, 0x6B43, 0xDDF7, 0x6B45, 0xDDF6, 0x6B46, 0xDDF5, 0x6B47, 0xB7B2, 0x6B48, 0xDDF9, 0x6B49, 0xBA70, 0x6B4A, 0xE263, 0x6B4B, 0xE265, 0x6B4C, 0xBA71, 0x6B4D, 0xE264, 0x6B4E, 0xBCDB, 0x6B50, 0xBCDA, 0x6B51, 0xE5F0, 0x6B54, 0xE9DF, 0x6B55, 0xE9DE, 0x6B56, 0xE9E0, 0x6B59, 0xBEF9, 0x6B5B, 0xED4B, 0x6B5C, 0xC0D3, 0x6B5E, 0xEFE8, 0x6B5F, 0xC26A, 0x6B60, 0xF259, 0x6B61, 0xC577, 0x6B62, 0xA4EE, 0x6B63, 0xA5BF, 0x6B64, 0xA6B9, 0x6B65, 0xA842, 0x6B66, 0xAA5A, 0x6B67, 0xAA5B, 0x6B6A, 0xAC6E, 0x6B6D, 0xD1FA, 0x6B72, 0xB7B3, 0x6B76, 0xE6D1, 0x6B77, 0xBEFA, 0x6B78, 0xC26B, 0x6B79, 0xA4EF, 0x6B7B, 0xA6BA, 0x6B7E, 0xCCEB, 0x6B7F, 0xAA5C, 0x6B80, 0xCCEA, 0x6B82, 0xCF65, 0x6B83, 0xAC6F, 0x6B84, 0xCF66, 0x6B86, 0xAC70, 0x6B88, 0xD1FC, 0x6B89, 0xAEEE, 0x6B8A, 0xAEED, 0x6B8C, 0xD5DE, 0x6B8D, 0xD5DC, 0x6B8E, 0xD5DD, 0x6B8F, 0xD5DB, 0x6B91, 0xD5DA, 0x6B94, 0xD9DE, 0x6B95, 0xD9E1, 0x6B96, 0xB4DE, 0x6B97, 0xD9DF, 0x6B98, 0xB4DD, 0x6B99, 0xD9E0, 0x6B9B, 0xDDFB, 0x6B9E, 0xE266, 0x6B9F, 0xE267, 0x6BA0, 0xE268, 0x6BA2, 0xE5F3, 0x6BA3, 0xE5F2, 0x6BA4, 0xBCDC, 0x6BA5, 0xE5F1, 0x6BA6, 0xE5F4, 0x6BA7, 0xE9E1, 0x6BAA, 0xE9E2, 0x6BAB, 0xE9E3, 0x6BAD, 0xED4C, 0x6BAE, 0xC0D4, 0x6BAF, 0xC26C, 0x6BB0, 0xF25A, 0x6BB2, 0xC4E8, 0x6BB3, 0xC95F, 0x6BB5, 0xAC71, 0x6BB6, 0xCF67, 0x6BB7, 0xAEEF, 0x6BBA, 0xB1FE, 0x6BBC, 0xB4DF, 0x6BBD, 0xD9E2, 0x6BBF, 0xB7B5, 0x6BC0, 0xB7B4, 0x6BC3, 0xE269, 0x6BC4, 0xE26A, 0x6BC5, 0xBCDD, 0x6BC6, 0xBCDE, 0x6BC7, 0xE9E5, 0x6BC8, 0xE9E4, 0x6BC9, 0xEFE9, 0x6BCA, 0xF7E3, 0x6BCB, 0xA4F0, 0x6BCC, 0xC960, 0x6BCD, 0xA5C0, 0x6BCF, 0xA843, 0x6BD0, 0xCB48, 0x6BD2, 0xAC72, 0x6BD3, 0xB7B6, 0x6BD4, 0xA4F1, 0x6BD6, 0xCF68, 0x6BD7, 0xAC73, 0x6BD8, 0xCF69, 0x6BDA, 0xC0D5, 0x6BDB, 0xA4F2, 0x6BDE, 0xCCEC, 0x6BE0, 0xCF6A, 0x6BE2, 0xD242, 0x6BE3, 0xD241, 0x6BE4, 0xD1FE, 0x6BE6, 0xD1FD, 0x6BE7, 0xD243, 0x6BE8, 0xD240, 0x6BEB, 0xB240, 0x6BEC, 0xB241, 0x6BEF, 0xB4E0, 0x6BF0, 0xD9E3, 0x6BF2, 0xD9E4, 0x6BF3, 0xD9E5, 0x6BF7, 0xDE41, 0x6BF8, 0xDE42, 0x6BF9, 0xDE40, 0x6BFB, 0xDDFD, 0x6BFC, 0xDDFE, 0x6BFD, 0xB7B7, 0x6BFE, 0xE26B, 0x6BFF, 0xE5F7, 0x6C00, 0xE5F6, 0x6C01, 0xE5F5, 0x6C02, 0xE5F8, 0x6C03, 0xE9E7, 0x6C04, 0xE9E6, 0x6C05, 0xBEFB, 0x6C06, 0xE9E8, 0x6C08, 0xC0D6, 0x6C09, 0xED4D, 0x6C0B, 0xEFEA, 0x6C0C, 0xF25B, 0x6C0D, 0xF6E7, 0x6C0F, 0xA4F3, 0x6C10, 0xA5C2, 0x6C11, 0xA5C1, 0x6C13, 0xAA5D, 0x6C14, 0xC961, 0x6C15, 0xC97E, 0x6C16, 0xA6BB, 0x6C18, 0xC9F7, 0x6C19, 0xCB49, 0x6C1A, 0xCB4A, 0x6C1B, 0xAA5E, 0x6C1D, 0xCCED, 0x6C1F, 0xAC74, 0x6C20, 0xCF6B, 0x6C21, 0xCF6C, 0x6C23, 0xAEF0, 0x6C24, 0xAEF4, 0x6C25, 0xD244, 0x6C26, 0xAEF3, 0x6C27, 0xAEF1, 0x6C28, 0xAEF2, 0x6C2A, 0xD5DF, 0x6C2B, 0xB242, 0x6C2C, 0xB4E3, 0x6C2E, 0xB4E1, 0x6C2F, 0xB4E2, 0x6C30, 0xD9E6, 0x6C33, 0xBA72, 0x6C34, 0xA4F4, 0x6C36, 0xC9A1, 0x6C38, 0xA5C3, 0x6C3B, 0xC9A4, 0x6C3E, 0xA5C6, 0x6C3F, 0xC9A3, 0x6C40, 0xA5C5, 0x6C41, 0xA5C4, 0x6C42, 0xA844, 0x6C43, 0xC9A2, 0x6C46, 0xC9F8, 0x6C4A, 0xC9FC, 0x6C4B, 0xC9FE, 0x6C4C, 0xCA40, 0x6C4D, 0xA6C5, 0x6C4E, 0xA6C6, 0x6C4F, 0xC9FB, 0x6C50, 0xA6C1, 0x6C52, 0xC9F9, 0x6C54, 0xC9FD, 0x6C55, 0xA6C2, 0x6C57, 0xA6BD, 0x6C59, 0xA6BE, 0x6C5B, 0xA6C4, 0x6C5C, 0xC9FA, 0x6C5D, 0xA6BC, 0x6C5E, 0xA845, 0x6C5F, 0xA6BF, 0x6C60, 0xA6C0, 0x6C61, 0xA6C3, 0x6C65, 0xCB5B, 0x6C66, 0xCB59, 0x6C67, 0xCB4C, 0x6C68, 0xA851, 0x6C69, 0xCB53, 0x6C6A, 0xA84C, 0x6C6B, 0xCB4D, 0x6C6D, 0xCB55, 0x6C6F, 0xCB52, 0x6C70, 0xA84F, 0x6C71, 0xCB51, 0x6C72, 0xA856, 0x6C73, 0xCB5A, 0x6C74, 0xA858, 0x6C76, 0xA85A, 0x6C78, 0xCB4B, 0x6C7A, 0xA84D, 0x6C7B, 0xCB5C, 0x6C7D, 0xA854, 0x6C7E, 0xA857, 0x6C80, 0xCD45, 0x6C81, 0xA847, 0x6C82, 0xA85E, 0x6C83, 0xA855, 0x6C84, 0xCB4E, 0x6C85, 0xA84A, 0x6C86, 0xA859, 0x6C87, 0xCB56, 0x6C88, 0xA848, 0x6C89, 0xA849, 0x6C8A, 0xCD43, 0x6C8B, 0xCB4F, 0x6C8C, 0xA850, 0x6C8D, 0xA85B, 0x6C8E, 0xCB5D, 0x6C8F, 0xCB50, 0x6C90, 0xA84E, 0x6C92, 0xA853, 0x6C93, 0xCCEE, 0x6C94, 0xA85C, 0x6C95, 0xCB57, 0x6C96, 0xA852, 0x6C98, 0xA85D, 0x6C99, 0xA846, 0x6C9A, 0xCB54, 0x6C9B, 0xA84B, 0x6C9C, 0xCB58, 0x6C9D, 0xCD44, 0x6CAB, 0xAA6A, 0x6CAC, 0xAA7A, 0x6CAD, 0xCCF5, 0x6CAE, 0xAA71, 0x6CB0, 0xCD4B, 0x6CB1, 0xAA62, 0x6CB3, 0xAA65, 0x6CB4, 0xCD42, 0x6CB6, 0xCCF3, 0x6CB7, 0xCCF7, 0x6CB8, 0xAA6D, 0x6CB9, 0xAA6F, 0x6CBA, 0xCCFA, 0x6CBB, 0xAA76, 0x6CBC, 0xAA68, 0x6CBD, 0xAA66, 0x6CBE, 0xAA67, 0x6CBF, 0xAA75, 0x6CC0, 0xCD47, 0x6CC1, 0xAA70, 0x6CC2, 0xCCF9, 0x6CC3, 0xCCFB, 0x6CC4, 0xAA6E, 0x6CC5, 0xAA73, 0x6CC6, 0xCCFC, 0x6CC7, 0xCD4A, 0x6CC9, 0xAC75, 0x6CCA, 0xAA79, 0x6CCC, 0xAA63, 0x6CCD, 0xCD49, 0x6CCF, 0xCD4D, 0x6CD0, 0xCCF8, 0x6CD1, 0xCD4F, 0x6CD2, 0xCD40, 0x6CD3, 0xAA6C, 0x6CD4, 0xCCF4, 0x6CD5, 0xAA6B, 0x6CD6, 0xAA7D, 0x6CD7, 0xAA72, 0x6CD9, 0xCCF2, 0x6CDA, 0xCF75, 0x6CDB, 0xAA78, 0x6CDC, 0xAA7C, 0x6CDD, 0xCD41, 0x6CDE, 0xCD46, 0x6CE0, 0xAA7E, 0x6CE1, 0xAA77, 0x6CE2, 0xAA69, 0x6CE3, 0xAA5F, 0x6CE5, 0xAA64, 0x6CE7, 0xCCF6, 0x6CE8, 0xAA60, 0x6CE9, 0xCD4E, 0x6CEB, 0xCCF0, 0x6CEC, 0xCCEF, 0x6CED, 0xCCFD, 0x6CEE, 0xCCF1, 0x6CEF, 0xAA7B, 0x6CF0, 0xAEF5, 0x6CF1, 0xAA74, 0x6CF2, 0xCCFE, 0x6CF3, 0xAA61, 0x6CF5, 0xACA6, 0x6CF9, 0xCD4C, 0x6D00, 0xCF7C, 0x6D01, 0xCFA1, 0x6D03, 0xCFA4, 0x6D04, 0xCF77, 0x6D07, 0xCFA7, 0x6D08, 0xCFAA, 0x6D09, 0xCFAC, 0x6D0A, 0xCF74, 0x6D0B, 0xAC76, 0x6D0C, 0xAC7B, 0x6D0D, 0xD249, 0x6D0E, 0xACAD, 0x6D0F, 0xCFA5, 0x6D10, 0xCFAD, 0x6D11, 0xCF7B, 0x6D12, 0xCF73, 0x6D16, 0xD264, 0x6D17, 0xAC7E, 0x6D18, 0xCFA2, 0x6D19, 0xCF78, 0x6D1A, 0xCF7A, 0x6D1B, 0xACA5, 0x6D1D, 0xCF7D, 0x6D1E, 0xAC7D, 0x6D1F, 0xCF70, 0x6D20, 0xCFA8, 0x6D22, 0xCFAB, 0x6D25, 0xAC7A, 0x6D27, 0xACA8, 0x6D28, 0xCF6D, 0x6D29, 0xACAA, 0x6D2A, 0xAC78, 0x6D2B, 0xACAE, 0x6D2C, 0xCFA9, 0x6D2D, 0xCF6F, 0x6D2E, 0xACAB, 0x6D2F, 0xD25E, 0x6D30, 0xCD48, 0x6D31, 0xAC7C, 0x6D32, 0xAC77, 0x6D33, 0xCF76, 0x6D34, 0xCF6E, 0x6D35, 0xACAC, 0x6D36, 0xACA4, 0x6D37, 0xCFA3, 0x6D38, 0xACA9, 0x6D39, 0xACA7, 0x6D3A, 0xCF79, 0x6D3B, 0xACA1, 0x6D3C, 0xCF71, 0x6D3D, 0xACA2, 0x6D3E, 0xACA3, 0x6D3F, 0xCF72, 0x6D40, 0xCFA6, 0x6D41, 0xAC79, 0x6D42, 0xCF7E, 0x6D58, 0xD24C, 0x6D59, 0xAEFD, 0x6D5A, 0xAF43, 0x6D5E, 0xD255, 0x6D5F, 0xD25B, 0x6D60, 0xD257, 0x6D61, 0xD24A, 0x6D62, 0xD24D, 0x6D63, 0xD246, 0x6D64, 0xD247, 0x6D65, 0xAF4A, 0x6D66, 0xAEFA, 0x6D67, 0xD256, 0x6D68, 0xD25F, 0x6D69, 0xAF45, 0x6D6A, 0xAEF6, 0x6D6C, 0xAF40, 0x6D6D, 0xD24E, 0x6D6E, 0xAF42, 0x6D6F, 0xD24F, 0x6D70, 0xD259, 0x6D74, 0xAF44, 0x6D75, 0xD268, 0x6D76, 0xD248, 0x6D77, 0xAEFC, 0x6D78, 0xAEFB, 0x6D79, 0xAF48, 0x6D7A, 0xD245, 0x6D7B, 0xD266, 0x6D7C, 0xD25A, 0x6D7D, 0xD267, 0x6D7E, 0xD261, 0x6D7F, 0xD253, 0x6D80, 0xD262, 0x6D82, 0xD25C, 0x6D83, 0xD265, 0x6D84, 0xD263, 0x6D85, 0xAF49, 0x6D86, 0xD254, 0x6D87, 0xAEF9, 0x6D88, 0xAEF8, 0x6D89, 0xAF41, 0x6D8A, 0xAF47, 0x6D8B, 0xD260, 0x6D8C, 0xAF46, 0x6D8D, 0xD251, 0x6D8E, 0xB243, 0x6D90, 0xD269, 0x6D91, 0xD250, 0x6D92, 0xD24B, 0x6D93, 0xAEFE, 0x6D94, 0xAF4B, 0x6D95, 0xAEF7, 0x6D97, 0xD258, 0x6D98, 0xD25D, 0x6DAA, 0xB265, 0x6DAB, 0xD5E1, 0x6DAC, 0xD5E5, 0x6DAE, 0xB252, 0x6DAF, 0xB250, 0x6DB2, 0xB247, 0x6DB3, 0xD5E3, 0x6DB4, 0xD5E2, 0x6DB5, 0xB25B, 0x6DB7, 0xD5E8, 0x6DB8, 0xB255, 0x6DBA, 0xD5FA, 0x6DBB, 0xD647, 0x6DBC, 0xB244, 0x6DBD, 0xD5F7, 0x6DBE, 0xD5F0, 0x6DBF, 0xB267, 0x6DC0, 0xD5E0, 0x6DC2, 0xD5FC, 0x6DC4, 0xB264, 0x6DC5, 0xB258, 0x6DC6, 0xB263, 0x6DC7, 0xB24E, 0x6DC8, 0xD5EC, 0x6DC9, 0xD5FE, 0x6DCA, 0xD5F6, 0x6DCB, 0xB24F, 0x6DCC, 0xB249, 0x6DCD, 0xD645, 0x6DCF, 0xD5FD, 0x6DD0, 0xD640, 0x6DD1, 0xB251, 0x6DD2, 0xB259, 0x6DD3, 0xD642, 0x6DD4, 0xD5EA, 0x6DD5, 0xD5FB, 0x6DD6, 0xD5EF, 0x6DD7, 0xD644, 0x6DD8, 0xB25E, 0x6DD9, 0xB246, 0x6DDA, 0xB25C, 0x6DDB, 0xD5F4, 0x6DDC, 0xD5F2, 0x6DDD, 0xD5F3, 0x6DDE, 0xB253, 0x6DDF, 0xD5EE, 0x6DE0, 0xD5ED, 0x6DE1, 0xB248, 0x6DE2, 0xD5E7, 0x6DE3, 0xD646, 0x6DE4, 0xB24A, 0x6DE5, 0xD5F1, 0x6DE6, 0xB268, 0x6DE8, 0xB262, 0x6DE9, 0xD5E6, 0x6DEA, 0xB25F, 0x6DEB, 0xB25D, 0x6DEC, 0xB266, 0x6DED, 0xD5F8, 0x6DEE, 0xB261, 0x6DEF, 0xD252, 0x6DF0, 0xD5F9, 0x6DF1, 0xB260, 0x6DF2, 0xD641, 0x6DF3, 0xB245, 0x6DF4, 0xD5F5, 0x6DF5, 0xB257, 0x6DF6, 0xD5E9, 0x6DF7, 0xB256, 0x6DF9, 0xB254, 0x6DFA, 0xB24C, 0x6DFB, 0xB24B, 0x6DFC, 0xD9E7, 0x6DFD, 0xD643, 0x6E00, 0xD5EB, 0x6E03, 0xD9FC, 0x6E05, 0xB24D, 0x6E19, 0xB541, 0x6E1A, 0xB25A, 0x6E1B, 0xB4EE, 0x6E1C, 0xD9F6, 0x6E1D, 0xB4FC, 0x6E1F, 0xD9EA, 0x6E20, 0xB4EB, 0x6E21, 0xB4E7, 0x6E22, 0xDA49, 0x6E23, 0xB4ED, 0x6E24, 0xB4F1, 0x6E25, 0xB4EC, 0x6E26, 0xB4F5, 0x6E27, 0xDA4D, 0x6E28, 0xDA44, 0x6E2B, 0xD9F1, 0x6E2C, 0xB4FA, 0x6E2D, 0xB4F4, 0x6E2E, 0xD9FD, 0x6E2F, 0xB4E4, 0x6E30, 0xDA4A, 0x6E31, 0xDA43, 0x6E32, 0xB4E8, 0x6E33, 0xD9F7, 0x6E34, 0xB4F7, 0x6E35, 0xDA55, 0x6E36, 0xDA56, 0x6E38, 0xB4E5, 0x6E39, 0xDA48, 0x6E3A, 0xB4F9, 0x6E3B, 0xD9FB, 0x6E3C, 0xD9ED, 0x6E3D, 0xD9EE, 0x6E3E, 0xB4FD, 0x6E3F, 0xD9F2, 0x6E40, 0xD9F9, 0x6E41, 0xD9F3, 0x6E43, 0xB4FB, 0x6E44, 0xB544, 0x6E45, 0xD9EF, 0x6E46, 0xD9E8, 0x6E47, 0xD9E9, 0x6E49, 0xD9EB, 0x6E4A, 0xB4EA, 0x6E4B, 0xD9F8, 0x6E4D, 0xB4F8, 0x6E4E, 0xB542, 0x6E51, 0xD9FA, 0x6E52, 0xDA53, 0x6E53, 0xDA4B, 0x6E54, 0xB4E6, 0x6E55, 0xDA51, 0x6E56, 0xB4F2, 0x6E58, 0xB4F0, 0x6E5A, 0xDA57, 0x6E5B, 0xB4EF, 0x6E5C, 0xDA41, 0x6E5D, 0xD9F4, 0x6E5E, 0xD9FE, 0x6E5F, 0xB547, 0x6E60, 0xDA45, 0x6E61, 0xDA42, 0x6E62, 0xD9F0, 0x6E63, 0xB543, 0x6E64, 0xDA4F, 0x6E65, 0xDA4C, 0x6E66, 0xDA54, 0x6E67, 0xB4E9, 0x6E68, 0xDA40, 0x6E69, 0xB546, 0x6E6B, 0xDA47, 0x6E6E, 0xB4F3, 0x6E6F, 0xB4F6, 0x6E71, 0xDA46, 0x6E72, 0xB545, 0x6E73, 0xD9F5, 0x6E74, 0xD5E4, 0x6E77, 0xDA50, 0x6E78, 0xDA4E, 0x6E79, 0xDA52, 0x6E88, 0xD9EC, 0x6E89, 0xB540, 0x6E8D, 0xDE61, 0x6E8E, 0xDE60, 0x6E8F, 0xDE46, 0x6E90, 0xB7BD, 0x6E92, 0xDE5F, 0x6E93, 0xDE49, 0x6E94, 0xDE4A, 0x6E96, 0xB7C7, 0x6E97, 0xDE68, 0x6E98, 0xB7C2, 0x6E99, 0xDE5E, 0x6E9B, 0xDE43, 0x6E9C, 0xB7C8, 0x6E9D, 0xB7BE, 0x6E9E, 0xDE52, 0x6E9F, 0xDE48, 0x6EA0, 0xDE4B, 0x6EA1, 0xDE63, 0x6EA2, 0xB7B8, 0x6EA3, 0xDE6A, 0x6EA4, 0xDE62, 0x6EA5, 0xB7C1, 0x6EA6, 0xDE57, 0x6EA7, 0xB7CC, 0x6EAA, 0xB7CB, 0x6EAB, 0xB7C5, 0x6EAE, 0xDE69, 0x6EAF, 0xB7B9, 0x6EB0, 0xDE55, 0x6EB1, 0xDE4C, 0x6EB2, 0xDE59, 0x6EB3, 0xDE65, 0x6EB4, 0xB7CD, 0x6EB6, 0xB7BB, 0x6EB7, 0xDE54, 0x6EB9, 0xDE4D, 0x6EBA, 0xB7C4, 0x6EBC, 0xB7C3, 0x6EBD, 0xDE50, 0x6EBE, 0xDE5A, 0x6EBF, 0xDE64, 0x6EC0, 0xDE47, 0x6EC1, 0xDE51, 0x6EC2, 0xB7BC, 0x6EC3, 0xDE5B, 0x6EC4, 0xB7C9, 0x6EC5, 0xB7C0, 0x6EC6, 0xDE4E, 0x6EC7, 0xB7BF, 0x6EC8, 0xDE45, 0x6EC9, 0xDE53, 0x6ECA, 0xDE67, 0x6ECB, 0xB4FE, 0x6ECC, 0xBAB0, 0x6ECD, 0xDE56, 0x6ECE, 0xE26C, 0x6ECF, 0xDE58, 0x6ED0, 0xDE66, 0x6ED1, 0xB7C6, 0x6ED2, 0xDE4F, 0x6ED3, 0xB7BA, 0x6ED4, 0xB7CA, 0x6ED5, 0xBCF0, 0x6ED6, 0xDE44, 0x6ED8, 0xDE5D, 0x6EDC, 0xDE5C, 0x6EEB, 0xE2AA, 0x6EEC, 0xBAAD, 0x6EED, 0xE27D, 0x6EEE, 0xE2A4, 0x6EEF, 0xBAA2, 0x6EF1, 0xE26E, 0x6EF2, 0xBAAF, 0x6EF4, 0xBA77, 0x6EF5, 0xE26D, 0x6EF6, 0xE2B0, 0x6EF7, 0xBAB1, 0x6EF8, 0xE271, 0x6EF9, 0xE2A3, 0x6EFB, 0xE273, 0x6EFC, 0xE2B3, 0x6EFD, 0xE2AF, 0x6EFE, 0xBA75, 0x6EFF, 0xBAA1, 0x6F00, 0xE653, 0x6F01, 0xBAAE, 0x6F02, 0xBA7D, 0x6F03, 0xE26F, 0x6F05, 0xE2AE, 0x6F06, 0xBAA3, 0x6F07, 0xE2AB, 0x6F08, 0xE2B8, 0x6F09, 0xE275, 0x6F0A, 0xE27E, 0x6F0D, 0xE2B6, 0x6F0E, 0xE2AC, 0x6F0F, 0xBA7C, 0x6F12, 0xE27C, 0x6F13, 0xBA76, 0x6F14, 0xBA74, 0x6F15, 0xBAA8, 0x6F18, 0xE27A, 0x6F19, 0xE277, 0x6F1A, 0xE278, 0x6F1C, 0xE2B2, 0x6F1E, 0xE2B7, 0x6F1F, 0xE2B5, 0x6F20, 0xBA7A, 0x6F21, 0xE2B9, 0x6F22, 0xBA7E, 0x6F23, 0xBAA7, 0x6F25, 0xE270, 0x6F26, 0xE5FA, 0x6F27, 0xE279, 0x6F29, 0xBA78, 0x6F2A, 0xBAAC, 0x6F2B, 0xBAA9, 0x6F2C, 0xBA7B, 0x6F2D, 0xE2A5, 0x6F2E, 0xE274, 0x6F2F, 0xBAAA, 0x6F30, 0xE2A7, 0x6F31, 0xBAA4, 0x6F32, 0xBAA6, 0x6F33, 0xBA73, 0x6F35, 0xE2A9, 0x6F36, 0xE2A1, 0x6F37, 0xE272, 0x6F38, 0xBAA5, 0x6F39, 0xE2B1, 0x6F3A, 0xE2B4, 0x6F3B, 0xE27B, 0x6F3C, 0xE2A8, 0x6F3E, 0xBA79, 0x6F3F, 0xBCDF, 0x6F40, 0xE2A6, 0x6F41, 0xE5F9, 0x6F43, 0xE2AD, 0x6F4E, 0xE276, 0x6F4F, 0xE644, 0x6F50, 0xE64E, 0x6F51, 0xBCE2, 0x6F52, 0xE64D, 0x6F53, 0xE659, 0x6F54, 0xBCE4, 0x6F55, 0xE64B, 0x6F57, 0xE64F, 0x6F58, 0xBCEF, 0x6F5A, 0xE646, 0x6F5B, 0xBCE7, 0x6F5D, 0xE652, 0x6F5E, 0xE9F0, 0x6F5F, 0xBCF3, 0x6F60, 0xBCF2, 0x6F61, 0xE654, 0x6F62, 0xE643, 0x6F63, 0xE65E, 0x6F64, 0xBCED, 0x6F66, 0xBCE3, 0x6F67, 0xE657, 0x6F69, 0xE65B, 0x6F6A, 0xE660, 0x6F6B, 0xE655, 0x6F6C, 0xE649, 0x6F6D, 0xBCE6, 0x6F6E, 0xBCE9, 0x6F6F, 0xBCF1, 0x6F70, 0xBCEC, 0x6F72, 0xE64C, 0x6F73, 0xE2A2, 0x6F76, 0xE648, 0x6F77, 0xE65F, 0x6F78, 0xBCE8, 0x6F7A, 0xBCEB, 0x6F7B, 0xE661, 0x6F7C, 0xBCE0, 0x6F7D, 0xE656, 0x6F7E, 0xE5FB, 0x6F7F, 0xE65C, 0x6F80, 0xC0DF, 0x6F82, 0xE64A, 0x6F84, 0xBCE1, 0x6F85, 0xE645, 0x6F86, 0xBCE5, 0x6F87, 0xE5FC, 0x6F88, 0xBAAB, 0x6F89, 0xE641, 0x6F8B, 0xE65A, 0x6F8C, 0xE642, 0x6F8D, 0xE640, 0x6F8E, 0xBCEA, 0x6F90, 0xE658, 0x6F92, 0xE5FE, 0x6F93, 0xE651, 0x6F94, 0xE650, 0x6F95, 0xE65D, 0x6F96, 0xE647, 0x6F97, 0xBCEE, 0x6F9E, 0xE9F3, 0x6FA0, 0xBF49, 0x6FA1, 0xBEFE, 0x6FA2, 0xEA40, 0x6FA3, 0xE9EB, 0x6FA4, 0xBF41, 0x6FA5, 0xE9F7, 0x6FA6, 0xBF48, 0x6FA7, 0xBF43, 0x6FA8, 0xE9F5, 0x6FA9, 0xED4F, 0x6FAA, 0xE9FB, 0x6FAB, 0xEA42, 0x6FAC, 0xE9FA, 0x6FAD, 0xE9E9, 0x6FAE, 0xE9F8, 0x6FAF, 0xEA44, 0x6FB0, 0xEA46, 0x6FB1, 0xBEFD, 0x6FB2, 0xEA45, 0x6FB3, 0xBF44, 0x6FB4, 0xBF4A, 0x6FB6, 0xBF47, 0x6FB8, 0xE9FE, 0x6FB9, 0xBF46, 0x6FBA, 0xE9F9, 0x6FBC, 0xE9ED, 0x6FBD, 0xE9F2, 0x6FBF, 0xE9FD, 0x6FC0, 0xBF45, 0x6FC1, 0xBF42, 0x6FC2, 0xBEFC, 0x6FC3, 0xBF40, 0x6FC4, 0xE9F1, 0x6FC6, 0xE5FD, 0x6FC7, 0xE9EC, 0x6FC8, 0xE9EF, 0x6FC9, 0xEA41, 0x6FCA, 0xE9F4, 0x6FCB, 0xE9EA, 0x6FCC, 0xED4E, 0x6FCD, 0xEA43, 0x6FCE, 0xE9EE, 0x6FCF, 0xE9FC, 0x6FD4, 0xED51, 0x6FD5, 0xC0E3, 0x6FD8, 0xC0D7, 0x6FDB, 0xC0DB, 0x6FDC, 0xED53, 0x6FDD, 0xED59, 0x6FDE, 0xED57, 0x6FDF, 0xC0D9, 0x6FE0, 0xC0DA, 0x6FE1, 0xC0E1, 0x6FE2, 0xED5A, 0x6FE3, 0xED52, 0x6FE4, 0xC0DC, 0x6FE6, 0xED56, 0x6FE7, 0xED55, 0x6FE8, 0xED5B, 0x6FE9, 0xC0E2, 0x6FEB, 0xC0DD, 0x6FEC, 0xC0E0, 0x6FED, 0xED54, 0x6FEE, 0xC0E4, 0x6FEF, 0xC0DE, 0x6FF0, 0xC0E5, 0x6FF1, 0xC0D8, 0x6FF2, 0xED58, 0x6FF4, 0xED50, 0x6FF7, 0xEFF7, 0x6FFA, 0xC271, 0x6FFB, 0xEFF4, 0x6FFC, 0xEFF6, 0x6FFE, 0xC26F, 0x6FFF, 0xEFF2, 0x7000, 0xEFF3, 0x7001, 0xEFEE, 0x7004, 0xE9F6, 0x7005, 0xEFEF, 0x7006, 0xC270, 0x7007, 0xEFEB, 0x7009, 0xC26D, 0x700A, 0xEFF8, 0x700B, 0xC26E, 0x700C, 0xEFEC, 0x700D, 0xEFED, 0x700E, 0xEFF1, 0x700F, 0xC273, 0x7011, 0xC272, 0x7014, 0xEFF0, 0x7015, 0xC378, 0x7016, 0xF25F, 0x7017, 0xF265, 0x7018, 0xC379, 0x7019, 0xF25C, 0x701A, 0xC376, 0x701B, 0xC373, 0x701C, 0xF267, 0x701D, 0xC377, 0x701F, 0xC374, 0x7020, 0xF25E, 0x7021, 0xF261, 0x7022, 0xF262, 0x7023, 0xF263, 0x7024, 0xF266, 0x7026, 0xEFF5, 0x7027, 0xF25D, 0x7028, 0xC375, 0x7029, 0xF264, 0x702A, 0xF268, 0x702B, 0xF260, 0x702F, 0xF45D, 0x7030, 0xC46A, 0x7031, 0xF460, 0x7032, 0xC46B, 0x7033, 0xF468, 0x7034, 0xF45F, 0x7035, 0xF45C, 0x7037, 0xF45E, 0x7038, 0xF462, 0x7039, 0xF465, 0x703A, 0xF464, 0x703B, 0xF467, 0x703C, 0xF45B, 0x703E, 0xC469, 0x703F, 0xF463, 0x7040, 0xF466, 0x7041, 0xF469, 0x7042, 0xF461, 0x7043, 0xF5D3, 0x7044, 0xF5D4, 0x7045, 0xF5D8, 0x7046, 0xF5D9, 0x7048, 0xF5D6, 0x7049, 0xF5D7, 0x704A, 0xF5D5, 0x704C, 0xC4E9, 0x7051, 0xC578, 0x7052, 0xF6EB, 0x7055, 0xF6E8, 0x7056, 0xF6E9, 0x7057, 0xF6EA, 0x7058, 0xC579, 0x705A, 0xF7E5, 0x705B, 0xF7E4, 0x705D, 0xF8AF, 0x705E, 0xC5F4, 0x705F, 0xF8AD, 0x7060, 0xF8B0, 0x7061, 0xF8AE, 0x7062, 0xF8F5, 0x7063, 0xC657, 0x7064, 0xC665, 0x7065, 0xF9A3, 0x7066, 0xF96C, 0x7068, 0xF9A2, 0x7069, 0xF9D0, 0x706A, 0xF9D1, 0x706B, 0xA4F5, 0x7070, 0xA6C7, 0x7071, 0xCA41, 0x7074, 0xCB5E, 0x7076, 0xA85F, 0x7078, 0xA862, 0x707A, 0xCB5F, 0x707C, 0xA860, 0x707D, 0xA861, 0x7082, 0xCD58, 0x7083, 0xCD5A, 0x7084, 0xCD55, 0x7085, 0xCD52, 0x7086, 0xCD54, 0x708A, 0xAAA4, 0x708E, 0xAAA2, 0x7091, 0xCD56, 0x7092, 0xAAA3, 0x7093, 0xCD53, 0x7094, 0xCD50, 0x7095, 0xAAA1, 0x7096, 0xCD57, 0x7098, 0xCD51, 0x7099, 0xAAA5, 0x709A, 0xCD59, 0x709F, 0xCFAF, 0x70A1, 0xCFB3, 0x70A4, 0xACB7, 0x70A9, 0xCFB6, 0x70AB, 0xACAF, 0x70AC, 0xACB2, 0x70AD, 0xACB4, 0x70AE, 0xACB6, 0x70AF, 0xACB3, 0x70B0, 0xCFB2, 0x70B1, 0xCFB1, 0x70B3, 0xACB1, 0x70B4, 0xCFB4, 0x70B5, 0xCFB5, 0x70B7, 0xCFAE, 0x70B8, 0xACB5, 0x70BA, 0xACB0, 0x70BE, 0xCFB0, 0x70C5, 0xD277, 0x70C6, 0xD278, 0x70C7, 0xD279, 0x70C8, 0xAF50, 0x70CA, 0xAF4C, 0x70CB, 0xD26E, 0x70CD, 0xD276, 0x70CE, 0xD27B, 0x70CF, 0xAF51, 0x70D1, 0xD26C, 0x70D2, 0xD272, 0x70D3, 0xD26B, 0x70D4, 0xD275, 0x70D7, 0xD271, 0x70D8, 0xAF4D, 0x70D9, 0xAF4F, 0x70DA, 0xD27A, 0x70DC, 0xD26A, 0x70DD, 0xD26D, 0x70DE, 0xD273, 0x70E0, 0xD274, 0x70E1, 0xD27C, 0x70E2, 0xD270, 0x70E4, 0xAF4E, 0x70EF, 0xB26D, 0x70F0, 0xD64E, 0x70F3, 0xD650, 0x70F4, 0xD64C, 0x70F6, 0xD658, 0x70F7, 0xD64A, 0x70F8, 0xD657, 0x70F9, 0xB269, 0x70FA, 0xD648, 0x70FB, 0xDA5B, 0x70FC, 0xD652, 0x70FD, 0xB26C, 0x70FF, 0xD653, 0x7100, 0xD656, 0x7102, 0xD65A, 0x7104, 0xD64F, 0x7106, 0xD654, 0x7109, 0xB26A, 0x710A, 0xB26B, 0x710B, 0xD659, 0x710C, 0xD64D, 0x710D, 0xD649, 0x710E, 0xD65B, 0x7110, 0xD651, 0x7113, 0xD655, 0x7117, 0xD64B, 0x7119, 0xB548, 0x711A, 0xB549, 0x711B, 0xDA65, 0x711C, 0xB54F, 0x711E, 0xDA59, 0x711F, 0xDA62, 0x7120, 0xDA58, 0x7121, 0xB54C, 0x7122, 0xDA60, 0x7123, 0xDA5E, 0x7125, 0xDA5F, 0x7126, 0xB54A, 0x7128, 0xDA63, 0x712E, 0xDA5C, 0x712F, 0xDA5A, 0x7130, 0xB54B, 0x7131, 0xDA5D, 0x7132, 0xDA61, 0x7136, 0xB54D, 0x713A, 0xDA64, 0x7141, 0xDE70, 0x7142, 0xDE77, 0x7143, 0xDE79, 0x7144, 0xDEA1, 0x7146, 0xB7DA, 0x7147, 0xDE6B, 0x7149, 0xB7D2, 0x714B, 0xDE7A, 0x714C, 0xB7D7, 0x714D, 0xDEA2, 0x714E, 0xB7CE, 0x7150, 0xDE7D, 0x7152, 0xDE6D, 0x7153, 0xDE7E, 0x7154, 0xDE6C, 0x7156, 0xB7DC, 0x7158, 0xDE78, 0x7159, 0xB7CF, 0x715A, 0xDEA3, 0x715C, 0xB7D4, 0x715D, 0xDE71, 0x715E, 0xB7D9, 0x715F, 0xDE7C, 0x7160, 0xDE6F, 0x7161, 0xDE76, 0x7162, 0xDE72, 0x7163, 0xDE6E, 0x7164, 0xB7D1, 0x7165, 0xB7D8, 0x7166, 0xB7D6, 0x7167, 0xB7D3, 0x7168, 0xB7DB, 0x7169, 0xB7D0, 0x716A, 0xDE75, 0x716C, 0xB7D5, 0x716E, 0xB54E, 0x7170, 0xDE7B, 0x7172, 0xDE73, 0x7178, 0xDE74, 0x717B, 0xE2C1, 0x717D, 0xBAB4, 0x7180, 0xE2BD, 0x7181, 0xE2C3, 0x7182, 0xE2BF, 0x7184, 0xBAB6, 0x7185, 0xE2BE, 0x7186, 0xE2C2, 0x7187, 0xE2BA, 0x7189, 0xE2BC, 0x718A, 0xBAB5, 0x718F, 0xE2C0, 0x7190, 0xE2BB, 0x7192, 0xBAB7, 0x7194, 0xBAB2, 0x7197, 0xE2C4, 0x7199, 0xBAB3, 0x719A, 0xE667, 0x719B, 0xE664, 0x719C, 0xE670, 0x719D, 0xE66A, 0x719E, 0xE66C, 0x719F, 0xBCF4, 0x71A0, 0xE666, 0x71A1, 0xE66E, 0x71A4, 0xE66D, 0x71A5, 0xE66B, 0x71A7, 0xE671, 0x71A8, 0xBCF7, 0x71A9, 0xE668, 0x71AA, 0xE66F, 0x71AC, 0xBCF5, 0x71AF, 0xE663, 0x71B0, 0xE665, 0x71B1, 0xBCF6, 0x71B2, 0xE662, 0x71B3, 0xE672, 0x71B5, 0xE669, 0x71B8, 0xEA4A, 0x71B9, 0xBF51, 0x71BC, 0xEA55, 0x71BD, 0xEA53, 0x71BE, 0xBF4B, 0x71BF, 0xEA49, 0x71C0, 0xEA4C, 0x71C1, 0xEA4D, 0x71C2, 0xEA48, 0x71C3, 0xBF55, 0x71C4, 0xBF56, 0x71C5, 0xEA47, 0x71C6, 0xEA56, 0x71C7, 0xEA51, 0x71C8, 0xBF4F, 0x71C9, 0xBF4C, 0x71CA, 0xEA50, 0x71CB, 0xEA4E, 0x71CE, 0xBF52, 0x71CF, 0xEA52, 0x71D0, 0xBF4D, 0x71D2, 0xBF4E, 0x71D4, 0xEA4F, 0x71D5, 0xBF50, 0x71D6, 0xEA4B, 0x71D8, 0xEA54, 0x71D9, 0xBF53, 0x71DA, 0xEA57, 0x71DB, 0xEA58, 0x71DC, 0xBF54, 0x71DF, 0xC0E7, 0x71E0, 0xC0EE, 0x71E1, 0xED5C, 0x71E2, 0xED62, 0x71E4, 0xED60, 0x71E5, 0xC0EA, 0x71E6, 0xC0E9, 0x71E7, 0xC0E6, 0x71E8, 0xED5E, 0x71EC, 0xC0EC, 0x71ED, 0xC0EB, 0x71EE, 0xC0E8, 0x71F0, 0xED61, 0x71F1, 0xED5D, 0x71F2, 0xED5F, 0x71F4, 0xC0ED, 0x71F8, 0xC277, 0x71F9, 0xEFFB, 0x71FB, 0xC274, 0x71FC, 0xC275, 0x71FD, 0xEFFD, 0x71FE, 0xC276, 0x71FF, 0xEFFA, 0x7201, 0xEFF9, 0x7202, 0xF26C, 0x7203, 0xEFFC, 0x7205, 0xF26D, 0x7206, 0xC37A, 0x7207, 0xF26B, 0x720A, 0xF26A, 0x720C, 0xF269, 0x720D, 0xC37B, 0x7210, 0xC46C, 0x7213, 0xF46A, 0x7214, 0xF46B, 0x7219, 0xF5DC, 0x721A, 0xF5DB, 0x721B, 0xC4EA, 0x721D, 0xF5DA, 0x721E, 0xF6EC, 0x721F, 0xF6ED, 0x7222, 0xF7E6, 0x7223, 0xF8B1, 0x7226, 0xF8F6, 0x7227, 0xF9BC, 0x7228, 0xC679, 0x7229, 0xF9C6, 0x722A, 0xA4F6, 0x722C, 0xAAA6, 0x722D, 0xAAA7, 0x7230, 0xACB8, 0x7235, 0xC0EF, 0x7236, 0xA4F7, 0x7238, 0xAAA8, 0x7239, 0xAF52, 0x723A, 0xB7DD, 0x723B, 0xA4F8, 0x723D, 0xB26E, 0x723E, 0xBAB8, 0x723F, 0xC962, 0x7241, 0xCFB7, 0x7242, 0xD27D, 0x7244, 0xE2C5, 0x7246, 0xC0F0, 0x7247, 0xA4F9, 0x7248, 0xAAA9, 0x7249, 0xCFB8, 0x724A, 0xCFB9, 0x724B, 0xDA66, 0x724C, 0xB550, 0x724F, 0xDEA4, 0x7252, 0xB7DE, 0x7253, 0xE2C6, 0x7256, 0xBCF8, 0x7258, 0xC37C, 0x7259, 0xA4FA, 0x725A, 0xDA67, 0x725B, 0xA4FB, 0x725D, 0xA6C9, 0x725E, 0xCA42, 0x725F, 0xA6C8, 0x7260, 0xA865, 0x7261, 0xA864, 0x7262, 0xA863, 0x7263, 0xCB60, 0x7267, 0xAAAA, 0x7269, 0xAAAB, 0x726A, 0xCD5B, 0x726C, 0xCFBA, 0x726E, 0xCFBD, 0x726F, 0xACBA, 0x7270, 0xCFBB, 0x7272, 0xACB9, 0x7273, 0xCFBC, 0x7274, 0xACBB, 0x7276, 0xD2A2, 0x7277, 0xD2A1, 0x7278, 0xD27E, 0x7279, 0xAF53, 0x727B, 0xD65D, 0x727C, 0xD65E, 0x727D, 0xB26F, 0x727E, 0xD65C, 0x727F, 0xD65F, 0x7280, 0xB552, 0x7281, 0xB270, 0x7284, 0xB551, 0x7285, 0xDA6B, 0x7286, 0xDA6A, 0x7288, 0xDA68, 0x7289, 0xDA69, 0x728B, 0xDA6C, 0x728C, 0xDEA6, 0x728D, 0xDEA5, 0x728E, 0xDEA9, 0x7290, 0xDEA8, 0x7291, 0xDEA7, 0x7292, 0xBAB9, 0x7293, 0xE2C9, 0x7295, 0xE2C8, 0x7296, 0xBABA, 0x7297, 0xE2C7, 0x7298, 0xE673, 0x729A, 0xE674, 0x729B, 0xBCF9, 0x729D, 0xEA59, 0x729E, 0xEA5A, 0x72A1, 0xF272, 0x72A2, 0xC37D, 0x72A3, 0xF271, 0x72A4, 0xF270, 0x72A5, 0xF26E, 0x72A6, 0xF26F, 0x72A7, 0xC4EB, 0x72A8, 0xF46C, 0x72A9, 0xF6EE, 0x72AA, 0xF8F7, 0x72AC, 0xA4FC, 0x72AE, 0xC9A5, 0x72AF, 0xA5C7, 0x72B0, 0xC9A6, 0x72B4, 0xCA43, 0x72B5, 0xCA44, 0x72BA, 0xCB66, 0x72BD, 0xCB62, 0x72BF, 0xCB61, 0x72C0, 0xAAAC, 0x72C1, 0xCB65, 0x72C2, 0xA867, 0x72C3, 0xCB63, 0x72C4, 0xA866, 0x72C5, 0xCB67, 0x72C6, 0xCB64, 0x72C9, 0xCD5F, 0x72CA, 0xCFBE, 0x72CB, 0xCD5D, 0x72CC, 0xCD64, 0x72CE, 0xAAAD, 0x72D0, 0xAAB0, 0x72D1, 0xCD65, 0x72D2, 0xCD61, 0x72D4, 0xCD62, 0x72D6, 0xCD5C, 0x72D7, 0xAAAF, 0x72D8, 0xCD5E, 0x72D9, 0xAAAE, 0x72DA, 0xCD63, 0x72DC, 0xCD60, 0x72DF, 0xCFC2, 0x72E0, 0xACBD, 0x72E1, 0xACBE, 0x72E3, 0xCFC5, 0x72E4, 0xCFBF, 0x72E6, 0xCFC4, 0x72E8, 0xCFC0, 0x72E9, 0xACBC, 0x72EA, 0xCFC3, 0x72EB, 0xCFC1, 0x72F3, 0xD2A8, 0x72F4, 0xD2A5, 0x72F6, 0xD2A7, 0x72F7, 0xAF58, 0x72F8, 0xAF57, 0x72F9, 0xAF55, 0x72FA, 0xD2A4, 0x72FB, 0xD2A9, 0x72FC, 0xAF54, 0x72FD, 0xAF56, 0x72FE, 0xD2A6, 0x72FF, 0xD667, 0x7300, 0xD2A3, 0x7301, 0xD2AA, 0x7307, 0xD662, 0x7308, 0xD666, 0x730A, 0xD665, 0x730B, 0xDA6E, 0x730C, 0xDA79, 0x730F, 0xD668, 0x7311, 0xD663, 0x7312, 0xDA6D, 0x7313, 0xB274, 0x7316, 0xB273, 0x7317, 0xD661, 0x7318, 0xD664, 0x7319, 0xB275, 0x731B, 0xB272, 0x731C, 0xB271, 0x731D, 0xD660, 0x731E, 0xD669, 0x7322, 0xDA70, 0x7323, 0xDA77, 0x7325, 0xB554, 0x7326, 0xDA76, 0x7327, 0xDA73, 0x7329, 0xB556, 0x732D, 0xDA75, 0x7330, 0xDA6F, 0x7331, 0xDA71, 0x7332, 0xDA74, 0x7333, 0xDA72, 0x7334, 0xB555, 0x7335, 0xDA78, 0x7336, 0xB553, 0x7337, 0xB7DF, 0x733A, 0xDEAD, 0x733B, 0xDEAC, 0x733C, 0xDEAA, 0x733E, 0xB7E2, 0x733F, 0xB7E1, 0x7340, 0xDEAE, 0x7342, 0xDEAB, 0x7343, 0xE2CA, 0x7344, 0xBABB, 0x7345, 0xB7E0, 0x7349, 0xDEB0, 0x734A, 0xDEAF, 0x734C, 0xE2CD, 0x734D, 0xE2CB, 0x734E, 0xBCFA, 0x7350, 0xBABC, 0x7351, 0xE2CC, 0x7352, 0xE676, 0x7357, 0xBCFB, 0x7358, 0xE675, 0x7359, 0xE67E, 0x735A, 0xE67D, 0x735B, 0xE67B, 0x735D, 0xE67A, 0x735E, 0xE677, 0x735F, 0xE678, 0x7360, 0xE679, 0x7361, 0xE67C, 0x7362, 0xE6A1, 0x7365, 0xEA5F, 0x7366, 0xEA5C, 0x7367, 0xEA5D, 0x7368, 0xBF57, 0x7369, 0xEA5B, 0x736A, 0xEA61, 0x736B, 0xEA60, 0x736C, 0xEA5E, 0x736E, 0xED64, 0x736F, 0xED65, 0x7370, 0xC0F1, 0x7372, 0xC0F2, 0x7373, 0xED63, 0x7375, 0xC279, 0x7376, 0xEFFE, 0x7377, 0xC278, 0x7378, 0xC37E, 0x737A, 0xC3A1, 0x737B, 0xC46D, 0x737C, 0xF46E, 0x737D, 0xF46D, 0x737E, 0xF5DD, 0x737F, 0xF6EF, 0x7380, 0xC57A, 0x7381, 0xF7E8, 0x7382, 0xF7E7, 0x7383, 0xF7E9, 0x7384, 0xA5C8, 0x7385, 0xCFC6, 0x7386, 0xAF59, 0x7387, 0xB276, 0x7388, 0xD66A, 0x7389, 0xA5C9, 0x738A, 0xC9A7, 0x738B, 0xA4FD, 0x738E, 0xCA45, 0x7392, 0xCB6C, 0x7393, 0xCB6A, 0x7394, 0xCB6B, 0x7395, 0xCB68, 0x7396, 0xA868, 0x7397, 0xCB69, 0x739D, 0xCD6D, 0x739F, 0xAAB3, 0x73A0, 0xCD6B, 0x73A1, 0xCD67, 0x73A2, 0xCD6A, 0x73A4, 0xCD66, 0x73A5, 0xAAB5, 0x73A6, 0xCD69, 0x73A8, 0xAAB2, 0x73A9, 0xAAB1, 0x73AB, 0xAAB4, 0x73AC, 0xCD6C, 0x73AD, 0xCD68, 0x73B2, 0xACC2, 0x73B3, 0xACC5, 0x73B4, 0xCFCE, 0x73B5, 0xCFCD, 0x73B6, 0xCFCC, 0x73B7, 0xACBF, 0x73B8, 0xCFD5, 0x73B9, 0xCFCB, 0x73BB, 0xACC1, 0x73BC, 0xD2AF, 0x73BE, 0xCFD2, 0x73BF, 0xCFD0, 0x73C0, 0xACC4, 0x73C2, 0xCFC8, 0x73C3, 0xCFD3, 0x73C5, 0xCFCA, 0x73C6, 0xCFD4, 0x73C7, 0xCFD1, 0x73C8, 0xCFC9, 0x73CA, 0xACC0, 0x73CB, 0xCFD6, 0x73CC, 0xCFC7, 0x73CD, 0xACC3, 0x73D2, 0xD2B4, 0x73D3, 0xD2AB, 0x73D4, 0xD2B6, 0x73D6, 0xD2AE, 0x73D7, 0xD2B9, 0x73D8, 0xD2BA, 0x73D9, 0xD2AC, 0x73DA, 0xD2B8, 0x73DB, 0xD2B5, 0x73DC, 0xD2B3, 0x73DD, 0xD2B7, 0x73DE, 0xAF5F, 0x73E0, 0xAF5D, 0x73E3, 0xD2B1, 0x73E5, 0xD2AD, 0x73E7, 0xD2B0, 0x73E8, 0xD2BB, 0x73E9, 0xD2B2, 0x73EA, 0xAF5E, 0x73EB, 0xCFCF, 0x73ED, 0xAF5A, 0x73EE, 0xAF5C, 0x73F4, 0xD678, 0x73F5, 0xD66D, 0x73F6, 0xD66B, 0x73F8, 0xD66C, 0x73FA, 0xD673, 0x73FC, 0xD674, 0x73FD, 0xD670, 0x73FE, 0xB27B, 0x73FF, 0xD675, 0x7400, 0xD672, 0x7401, 0xD66F, 0x7403, 0xB279, 0x7404, 0xD66E, 0x7405, 0xB277, 0x7406, 0xB27A, 0x7407, 0xD671, 0x7408, 0xD679, 0x7409, 0xAF5B, 0x740A, 0xB278, 0x740B, 0xD677, 0x740C, 0xD676, 0x740D, 0xB27C, 0x7416, 0xDA7E, 0x741A, 0xDAA1, 0x741B, 0xB560, 0x741D, 0xDAA7, 0x7420, 0xDAA9, 0x7421, 0xDAA2, 0x7422, 0xB55A, 0x7423, 0xDAA6, 0x7424, 0xDAA5, 0x7425, 0xB55B, 0x7426, 0xB561, 0x7428, 0xB562, 0x7429, 0xDAA8, 0x742A, 0xB558, 0x742B, 0xDA7D, 0x742C, 0xDA7B, 0x742D, 0xDAA3, 0x742E, 0xDA7A, 0x742F, 0xB55F, 0x7430, 0xDA7C, 0x7431, 0xDAA4, 0x7432, 0xDAAA, 0x7433, 0xB559, 0x7434, 0xB55E, 0x7435, 0xB55C, 0x7436, 0xB55D, 0x743A, 0xB557, 0x743F, 0xB7E9, 0x7440, 0xDEB7, 0x7441, 0xB7E8, 0x7442, 0xDEBB, 0x7444, 0xDEB1, 0x7446, 0xDEBC, 0x744A, 0xDEB2, 0x744B, 0xDEB3, 0x744D, 0xDEBD, 0x744E, 0xDEBA, 0x744F, 0xDEB8, 0x7450, 0xDEB9, 0x7451, 0xDEB5, 0x7452, 0xDEB4, 0x7454, 0xDEBE, 0x7455, 0xB7E5, 0x7457, 0xDEB6, 0x7459, 0xB7EA, 0x745A, 0xB7E4, 0x745B, 0xB7EB, 0x745C, 0xB7EC, 0x745E, 0xB7E7, 0x745F, 0xB7E6, 0x7462, 0xE2CE, 0x7463, 0xBABE, 0x7464, 0xBABD, 0x7467, 0xE2D3, 0x7469, 0xBCFC, 0x746A, 0xBABF, 0x746D, 0xBAC1, 0x746E, 0xE2D4, 0x746F, 0xB7E3, 0x7470, 0xBAC0, 0x7471, 0xE2D0, 0x7472, 0xE2D2, 0x7473, 0xE2CF, 0x7475, 0xE2D1, 0x7479, 0xE6AB, 0x747C, 0xE6AA, 0x747D, 0xE6A7, 0x747E, 0xBD40, 0x747F, 0xEA62, 0x7480, 0xBD41, 0x7481, 0xE6A6, 0x7483, 0xBCFE, 0x7485, 0xE6A8, 0x7486, 0xE6A5, 0x7487, 0xE6A2, 0x7488, 0xE6A9, 0x7489, 0xE6A3, 0x748A, 0xE6A4, 0x748B, 0xBCFD, 0x7490, 0xED69, 0x7492, 0xEA66, 0x7494, 0xEA65, 0x7495, 0xEA67, 0x7497, 0xED66, 0x7498, 0xBF5A, 0x749A, 0xEA63, 0x749C, 0xBF58, 0x749E, 0xBF5C, 0x749F, 0xBF5B, 0x74A0, 0xEA64, 0x74A1, 0xEA68, 0x74A3, 0xBF59, 0x74A5, 0xED6D, 0x74A6, 0xC0F5, 0x74A7, 0xC27A, 0x74A8, 0xC0F6, 0x74A9, 0xC0F3, 0x74AA, 0xED6A, 0x74AB, 0xED68, 0x74AD, 0xED6B, 0x74AF, 0xED6E, 0x74B0, 0xC0F4, 0x74B1, 0xED6C, 0x74B2, 0xED67, 0x74B5, 0xF042, 0x74B6, 0xF045, 0x74B7, 0xF275, 0x74B8, 0xF040, 0x74BA, 0xF46F, 0x74BB, 0xF046, 0x74BD, 0xC3A2, 0x74BE, 0xF044, 0x74BF, 0xC27B, 0x74C0, 0xF041, 0x74C1, 0xF043, 0x74C2, 0xF047, 0x74C3, 0xF276, 0x74C5, 0xF274, 0x74CA, 0xC3A3, 0x74CB, 0xF273, 0x74CF, 0xC46E, 0x74D4, 0xC4ED, 0x74D5, 0xF6F1, 0x74D6, 0xC4EC, 0x74D7, 0xF6F3, 0x74D8, 0xF6F0, 0x74D9, 0xF6F2, 0x74DA, 0xC5D0, 0x74DB, 0xF8B2, 0x74DC, 0xA5CA, 0x74DD, 0xCD6E, 0x74DE, 0xD2BC, 0x74DF, 0xD2BD, 0x74E0, 0xB27D, 0x74E1, 0xDEBF, 0x74E2, 0xBF5D, 0x74E3, 0xC3A4, 0x74E4, 0xC57B, 0x74E5, 0xF8B3, 0x74E6, 0xA5CB, 0x74E8, 0xCD6F, 0x74E9, 0xA260, 0x74EC, 0xCFD7, 0x74EE, 0xCFD8, 0x74F4, 0xD2BE, 0x74F5, 0xD2BF, 0x74F6, 0xB27E, 0x74F7, 0xB2A1, 0x74FB, 0xDAAB, 0x74FD, 0xDEC2, 0x74FE, 0xDEC1, 0x74FF, 0xDEC0, 0x7500, 0xE2D5, 0x7502, 0xE2D6, 0x7503, 0xE2D7, 0x7504, 0xBAC2, 0x7507, 0xE6AD, 0x7508, 0xE6AC, 0x750B, 0xEA69, 0x750C, 0xBF5E, 0x750D, 0xBF5F, 0x750F, 0xED72, 0x7510, 0xED6F, 0x7511, 0xED70, 0x7512, 0xED71, 0x7513, 0xF049, 0x7514, 0xF048, 0x7515, 0xC27C, 0x7516, 0xF277, 0x7517, 0xF5DE, 0x7518, 0xA5CC, 0x751A, 0xACC6, 0x751C, 0xB2A2, 0x751D, 0xDEC3, 0x751F, 0xA5CD, 0x7521, 0xD2C0, 0x7522, 0xB2A3, 0x7525, 0xB563, 0x7526, 0xB564, 0x7528, 0xA5CE, 0x7529, 0xA5CF, 0x752A, 0xCA46, 0x752B, 0xA86A, 0x752C, 0xA869, 0x752D, 0xACC7, 0x752E, 0xCFD9, 0x752F, 0xDAAC, 0x7530, 0xA5D0, 0x7531, 0xA5D1, 0x7532, 0xA5D2, 0x7533, 0xA5D3, 0x7537, 0xA86B, 0x7538, 0xA86C, 0x7539, 0xCB6E, 0x753A, 0xCB6D, 0x753D, 0xAAB6, 0x753E, 0xCD72, 0x753F, 0xCD70, 0x7540, 0xCD71, 0x7547, 0xCFDA, 0x7548, 0xCFDB, 0x754B, 0xACCB, 0x754C, 0xACC9, 0x754E, 0xACCA, 0x754F, 0xACC8, 0x7554, 0xAF60, 0x7559, 0xAF64, 0x755A, 0xAF63, 0x755B, 0xD2C1, 0x755C, 0xAF62, 0x755D, 0xAF61, 0x755F, 0xD2C2, 0x7562, 0xB2A6, 0x7563, 0xD67B, 0x7564, 0xD67A, 0x7565, 0xB2A4, 0x7566, 0xB2A5, 0x756A, 0xB566, 0x756B, 0xB565, 0x756C, 0xDAAE, 0x756F, 0xDAAD, 0x7570, 0xB2A7, 0x7576, 0xB7ED, 0x7577, 0xDEC5, 0x7578, 0xB7EE, 0x7579, 0xDEC4, 0x757D, 0xE2D8, 0x757E, 0xE6AE, 0x757F, 0xBD42, 0x7580, 0xEA6A, 0x7584, 0xED73, 0x7586, 0xC3A6, 0x7587, 0xC3A5, 0x758A, 0xC57C, 0x758B, 0xA5D4, 0x758C, 0xCD73, 0x758F, 0xB2A8, 0x7590, 0xE2D9, 0x7591, 0xBAC3, 0x7594, 0xCB6F, 0x7595, 0xCB70, 0x7598, 0xCD74, 0x7599, 0xAAB8, 0x759A, 0xAAB9, 0x759D, 0xAAB7, 0x75A2, 0xACCF, 0x75A3, 0xACD0, 0x75A4, 0xACCD, 0x75A5, 0xACCE, 0x75A7, 0xCFDC, 0x75AA, 0xCFDD, 0x75AB, 0xACCC, 0x75B0, 0xD2C3, 0x75B2, 0xAF68, 0x75B3, 0xAF69, 0x75B5, 0xB2AB, 0x75B6, 0xD2C9, 0x75B8, 0xAF6E, 0x75B9, 0xAF6C, 0x75BA, 0xD2CA, 0x75BB, 0xD2C5, 0x75BC, 0xAF6B, 0x75BD, 0xAF6A, 0x75BE, 0xAF65, 0x75BF, 0xD2C8, 0x75C0, 0xD2C7, 0x75C1, 0xD2C4, 0x75C2, 0xAF6D, 0x75C4, 0xD2C6, 0x75C5, 0xAF66, 0x75C7, 0xAF67, 0x75CA, 0xB2AC, 0x75CB, 0xD6A1, 0x75CC, 0xD6A2, 0x75CD, 0xB2AD, 0x75CE, 0xD67C, 0x75CF, 0xD67E, 0x75D0, 0xD6A4, 0x75D1, 0xD6A3, 0x75D2, 0xD67D, 0x75D4, 0xB2A9, 0x75D5, 0xB2AA, 0x75D7, 0xDAB6, 0x75D8, 0xB56B, 0x75D9, 0xB56A, 0x75DA, 0xDAB0, 0x75DB, 0xB568, 0x75DD, 0xDAB3, 0x75DE, 0xB56C, 0x75DF, 0xDAB4, 0x75E0, 0xB56D, 0x75E1, 0xDAB1, 0x75E2, 0xB567, 0x75E3, 0xB569, 0x75E4, 0xDAB5, 0x75E6, 0xDAB2, 0x75E7, 0xDAAF, 0x75ED, 0xDED2, 0x75EF, 0xDEC7, 0x75F0, 0xB7F0, 0x75F1, 0xB7F3, 0x75F2, 0xB7F2, 0x75F3, 0xB7F7, 0x75F4, 0xB7F6, 0x75F5, 0xDED3, 0x75F6, 0xDED1, 0x75F7, 0xDECA, 0x75F8, 0xDECE, 0x75F9, 0xDECD, 0x75FA, 0xB7F4, 0x75FB, 0xDED0, 0x75FC, 0xDECC, 0x75FD, 0xDED4, 0x75FE, 0xDECB, 0x75FF, 0xB7F5, 0x7600, 0xB7EF, 0x7601, 0xB7F1, 0x7603, 0xDEC9, 0x7608, 0xE2DB, 0x7609, 0xBAC7, 0x760A, 0xE2DF, 0x760B, 0xBAC6, 0x760C, 0xE2DC, 0x760D, 0xBAC5, 0x760F, 0xDEC8, 0x7610, 0xDECF, 0x7611, 0xE2DE, 0x7613, 0xBAC8, 0x7614, 0xE2E0, 0x7615, 0xE2DD, 0x7616, 0xE2DA, 0x7619, 0xE6B1, 0x761A, 0xE6B5, 0x761B, 0xE6B7, 0x761C, 0xE6B3, 0x761D, 0xE6B2, 0x761E, 0xE6B0, 0x761F, 0xBD45, 0x7620, 0xBD43, 0x7621, 0xBD48, 0x7622, 0xBD49, 0x7623, 0xE6B4, 0x7624, 0xBD46, 0x7625, 0xE6AF, 0x7626, 0xBD47, 0x7627, 0xBAC4, 0x7628, 0xE6B6, 0x7629, 0xBD44, 0x762D, 0xEA6C, 0x762F, 0xEA6B, 0x7630, 0xEA73, 0x7631, 0xEA6D, 0x7632, 0xEA72, 0x7633, 0xEA6F, 0x7634, 0xBF60, 0x7635, 0xEA71, 0x7638, 0xBF61, 0x763A, 0xBF62, 0x763C, 0xEA70, 0x763D, 0xEA6E, 0x7642, 0xC0F8, 0x7643, 0xED74, 0x7646, 0xC0F7, 0x7647, 0xED77, 0x7648, 0xED75, 0x7649, 0xED76, 0x764C, 0xC0F9, 0x7650, 0xF04D, 0x7652, 0xC2A1, 0x7653, 0xF04E, 0x7656, 0xC27D, 0x7657, 0xF04F, 0x7658, 0xC27E, 0x7659, 0xF04C, 0x765A, 0xF050, 0x765C, 0xF04A, 0x765F, 0xC3A7, 0x7660, 0xF278, 0x7661, 0xC3A8, 0x7662, 0xC46F, 0x7664, 0xF04B, 0x7665, 0xC470, 0x7669, 0xC4EE, 0x766A, 0xF5DF, 0x766C, 0xC57E, 0x766D, 0xF6F4, 0x766E, 0xC57D, 0x7670, 0xF7EA, 0x7671, 0xC5F5, 0x7672, 0xC5F6, 0x7675, 0xF9CC, 0x7678, 0xACD1, 0x7679, 0xCFDE, 0x767B, 0xB56E, 0x767C, 0xB56F, 0x767D, 0xA5D5, 0x767E, 0xA6CA, 0x767F, 0xCA47, 0x7681, 0xCB71, 0x7682, 0xA86D, 0x7684, 0xAABA, 0x7686, 0xACD2, 0x7687, 0xACD3, 0x7688, 0xACD4, 0x7689, 0xD6A6, 0x768A, 0xD2CB, 0x768B, 0xAF6F, 0x768E, 0xB2AE, 0x768F, 0xD6A5, 0x7692, 0xDAB8, 0x7693, 0xB571, 0x7695, 0xDAB7, 0x7696, 0xB570, 0x7699, 0xDED5, 0x769A, 0xBD4A, 0x769B, 0xE6BB, 0x769C, 0xE6B8, 0x769D, 0xE6B9, 0x769E, 0xE6BA, 0x76A4, 0xED78, 0x76A6, 0xF051, 0x76AA, 0xF471, 0x76AB, 0xF470, 0x76AD, 0xF6F5, 0x76AE, 0xA5D6, 0x76AF, 0xCD75, 0x76B0, 0xAF70, 0x76B4, 0xB572, 0x76B5, 0xDED6, 0x76B8, 0xE2E1, 0x76BA, 0xBD4B, 0x76BB, 0xEA74, 0x76BD, 0xF052, 0x76BE, 0xF472, 0x76BF, 0xA5D7, 0x76C2, 0xAABB, 0x76C3, 0xACD7, 0x76C4, 0xCFDF, 0x76C5, 0xACD8, 0x76C6, 0xACD6, 0x76C8, 0xACD5, 0x76C9, 0xD2CC, 0x76CA, 0xAF71, 0x76CD, 0xAF72, 0x76CE, 0xAF73, 0x76D2, 0xB2B0, 0x76D3, 0xD6A7, 0x76D4, 0xB2AF, 0x76DA, 0xDAB9, 0x76DB, 0xB2B1, 0x76DC, 0xB573, 0x76DD, 0xDED7, 0x76DE, 0xB7F8, 0x76DF, 0xB7F9, 0x76E1, 0xBAC9, 0x76E3, 0xBACA, 0x76E4, 0xBD4C, 0x76E5, 0xBF64, 0x76E6, 0xEA75, 0x76E7, 0xBF63, 0x76E9, 0xED79, 0x76EA, 0xC0FA, 0x76EC, 0xF053, 0x76ED, 0xF473, 0x76EE, 0xA5D8, 0x76EF, 0xA86E, 0x76F0, 0xCD78, 0x76F1, 0xCD77, 0x76F2, 0xAABC, 0x76F3, 0xCD76, 0x76F4, 0xAABD, 0x76F5, 0xCD79, 0x76F7, 0xCFE5, 0x76F8, 0xACDB, 0x76F9, 0xACDA, 0x76FA, 0xCFE7, 0x76FB, 0xCFE6, 0x76FC, 0xACDF, 0x76FE, 0xACDE, 0x7701, 0xACD9, 0x7703, 0xCFE1, 0x7704, 0xCFE2, 0x7705, 0xCFE3, 0x7707, 0xACE0, 0x7708, 0xCFE0, 0x7709, 0xACDC, 0x770A, 0xCFE4, 0x770B, 0xACDD, 0x7710, 0xD2CF, 0x7711, 0xD2D3, 0x7712, 0xD2D1, 0x7713, 0xD2D0, 0x7715, 0xD2D4, 0x7719, 0xD2D5, 0x771A, 0xD2D6, 0x771B, 0xD2CE, 0x771D, 0xD2CD, 0x771F, 0xAF75, 0x7720, 0xAF76, 0x7722, 0xD2D7, 0x7723, 0xD2D2, 0x7725, 0xD6B0, 0x7727, 0xD2D8, 0x7728, 0xAF77, 0x7729, 0xAF74, 0x772D, 0xD6AA, 0x772F, 0xD6A9, 0x7731, 0xD6AB, 0x7732, 0xD6AC, 0x7733, 0xD6AE, 0x7734, 0xD6AD, 0x7735, 0xD6B2, 0x7736, 0xB2B5, 0x7737, 0xB2B2, 0x7738, 0xB2B6, 0x7739, 0xD6A8, 0x773A, 0xB2B7, 0x773B, 0xD6B1, 0x773C, 0xB2B4, 0x773D, 0xD6AF, 0x773E, 0xB2B3, 0x7744, 0xDABC, 0x7745, 0xDABE, 0x7746, 0xDABA, 0x7747, 0xDABB, 0x774A, 0xDABF, 0x774B, 0xDAC1, 0x774C, 0xDAC2, 0x774D, 0xDABD, 0x774E, 0xDAC0, 0x774F, 0xB574, 0x7752, 0xDEDB, 0x7754, 0xDEE0, 0x7755, 0xDED8, 0x7756, 0xDEDC, 0x7759, 0xDEE1, 0x775A, 0xDEDD, 0x775B, 0xB7FA, 0x775C, 0xB843, 0x775E, 0xB7FD, 0x775F, 0xDED9, 0x7760, 0xDEDA, 0x7761, 0xBACE, 0x7762, 0xB846, 0x7763, 0xB7FE, 0x7765, 0xB844, 0x7766, 0xB7FC, 0x7767, 0xDEDF, 0x7768, 0xB845, 0x7769, 0xDEDE, 0x776A, 0xB841, 0x776B, 0xB7FB, 0x776C, 0xB842, 0x776D, 0xDEE2, 0x776E, 0xE2E6, 0x776F, 0xE2E8, 0x7779, 0xB840, 0x777C, 0xE2E3, 0x777D, 0xBACC, 0x777E, 0xE2E9, 0x777F, 0xBACD, 0x7780, 0xE2E7, 0x7781, 0xE2E2, 0x7782, 0xE2E5, 0x7783, 0xE2EA, 0x7784, 0xBACB, 0x7785, 0xE2E4, 0x7787, 0xBD4E, 0x7788, 0xE6BF, 0x7789, 0xE6BE, 0x778B, 0xBD51, 0x778C, 0xBD4F, 0x778D, 0xE6BC, 0x778E, 0xBD4D, 0x778F, 0xE6BD, 0x7791, 0xBD50, 0x7795, 0xEA7D, 0x7797, 0xEAA1, 0x7799, 0xEA7E, 0x779A, 0xEA76, 0x779B, 0xEA7A, 0x779C, 0xEA79, 0x779D, 0xEA77, 0x779E, 0xBF66, 0x779F, 0xBF67, 0x77A0, 0xBF65, 0x77A1, 0xEA78, 0x77A2, 0xEA7B, 0x77A3, 0xEA7C, 0x77A5, 0xBF68, 0x77A7, 0xC140, 0x77A8, 0xEDA3, 0x77AA, 0xC0FC, 0x77AB, 0xED7B, 0x77AC, 0xC0FE, 0x77AD, 0xC141, 0x77B0, 0xC0FD, 0x77B1, 0xEDA2, 0x77B2, 0xED7C, 0x77B3, 0xC0FB, 0x77B4, 0xEDA1, 0x77B5, 0xED7A, 0x77B6, 0xED7E, 0x77B7, 0xED7D, 0x77BA, 0xF055, 0x77BB, 0xC2A4, 0x77BC, 0xC2A5, 0x77BD, 0xC2A2, 0x77BF, 0xC2A3, 0x77C2, 0xF054, 0x77C4, 0xF27B, 0x77C7, 0xC3A9, 0x77C9, 0xF279, 0x77CA, 0xF27A, 0x77CC, 0xF474, 0x77CD, 0xF477, 0x77CE, 0xF475, 0x77CF, 0xF476, 0x77D0, 0xF5E0, 0x77D3, 0xC4EF, 0x77D4, 0xF7EB, 0x77D5, 0xF8B4, 0x77D7, 0xC5F7, 0x77D8, 0xF8F8, 0x77D9, 0xF8F9, 0x77DA, 0xC666, 0x77DB, 0xA5D9, 0x77DC, 0xACE1, 0x77DE, 0xDAC3, 0x77E0, 0xDEE3, 0x77E2, 0xA5DA, 0x77E3, 0xA86F, 0x77E5, 0xAABE, 0x77E7, 0xCFE8, 0x77E8, 0xCFE9, 0x77E9, 0xAF78, 0x77EC, 0xDAC4, 0x77ED, 0xB575, 0x77EE, 0xB847, 0x77EF, 0xC142, 0x77F0, 0xEDA4, 0x77F1, 0xF27C, 0x77F2, 0xF478, 0x77F3, 0xA5DB, 0x77F7, 0xCDA1, 0x77F8, 0xCD7A, 0x77F9, 0xCD7C, 0x77FA, 0xCD7E, 0x77FB, 0xCD7D, 0x77FC, 0xCD7B, 0x77FD, 0xAABF, 0x7802, 0xACE2, 0x7803, 0xCFF2, 0x7805, 0xCFED, 0x7806, 0xCFEA, 0x7809, 0xCFF1, 0x780C, 0xACE4, 0x780D, 0xACE5, 0x780E, 0xCFF0, 0x780F, 0xCFEF, 0x7810, 0xCFEE, 0x7811, 0xCFEB, 0x7812, 0xCFEC, 0x7813, 0xCFF3, 0x7814, 0xACE3, 0x781D, 0xAF7C, 0x781F, 0xAFA4, 0x7820, 0xAFA3, 0x7821, 0xD2E1, 0x7822, 0xD2DB, 0x7823, 0xD2D9, 0x7825, 0xAFA1, 0x7826, 0xD6B9, 0x7827, 0xAF7A, 0x7828, 0xD2DE, 0x7829, 0xD2E2, 0x782A, 0xD2E4, 0x782B, 0xD2E0, 0x782C, 0xD2DA, 0x782D, 0xAFA2, 0x782E, 0xD2DF, 0x782F, 0xD2DD, 0x7830, 0xAF79, 0x7831, 0xD2E5, 0x7832, 0xAFA5, 0x7833, 0xD2E3, 0x7834, 0xAF7D, 0x7835, 0xD2DC, 0x7837, 0xAF7E, 0x7838, 0xAF7B, 0x7843, 0xB2B9, 0x7845, 0xD6BA, 0x7848, 0xD6B3, 0x7849, 0xD6B5, 0x784A, 0xD6B7, 0x784C, 0xD6B8, 0x784D, 0xD6B6, 0x784E, 0xB2BA, 0x7850, 0xD6BB, 0x7852, 0xD6B4, 0x785C, 0xDAC8, 0x785D, 0xB576, 0x785E, 0xDAD0, 0x7860, 0xDAC5, 0x7862, 0xDAD1, 0x7864, 0xDAC6, 0x7865, 0xDAC7, 0x7868, 0xDACF, 0x7869, 0xDACE, 0x786A, 0xDACB, 0x786B, 0xB2B8, 0x786C, 0xB577, 0x786D, 0xDAC9, 0x786E, 0xDACC, 0x786F, 0xB578, 0x7870, 0xDACD, 0x7871, 0xDACA, 0x7879, 0xDEEE, 0x787B, 0xDEF2, 0x787C, 0xB84E, 0x787E, 0xE2F0, 0x787F, 0xB851, 0x7880, 0xDEF0, 0x7881, 0xF9D6, 0x7883, 0xDEED, 0x7884, 0xDEE8, 0x7885, 0xDEEA, 0x7886, 0xDEEB, 0x7887, 0xDEE4, 0x7889, 0xB84D, 0x788C, 0xB84C, 0x788E, 0xB848, 0x788F, 0xDEE7, 0x7891, 0xB84F, 0x7893, 0xB850, 0x7894, 0xDEE6, 0x7895, 0xDEE9, 0x7896, 0xDEF1, 0x7897, 0xB84A, 0x7898, 0xB84B, 0x7899, 0xDEEF, 0x789A, 0xDEE5, 0x789E, 0xE2F2, 0x789F, 0xBAD0, 0x78A0, 0xE2F4, 0x78A1, 0xDEEC, 0x78A2, 0xE2F6, 0x78A3, 0xBAD4, 0x78A4, 0xE2F7, 0x78A5, 0xE2F3, 0x78A7, 0xBAD1, 0x78A8, 0xE2EF, 0x78A9, 0xBAD3, 0x78AA, 0xE2EC, 0x78AB, 0xE2F1, 0x78AC, 0xE2F5, 0x78AD, 0xE2EE, 0x78B0, 0xB849, 0x78B2, 0xE2EB, 0x78B3, 0xBAD2, 0x78B4, 0xE2ED, 0x78BA, 0xBD54, 0x78BB, 0xE6C1, 0x78BC, 0xBD58, 0x78BE, 0xBD56, 0x78C1, 0xBACF, 0x78C3, 0xE6C8, 0x78C4, 0xE6C9, 0x78C5, 0xBD53, 0x78C8, 0xE6C7, 0x78C9, 0xE6CA, 0x78CA, 0xBD55, 0x78CB, 0xBD52, 0x78CC, 0xE6C3, 0x78CD, 0xE6C0, 0x78CE, 0xE6C5, 0x78CF, 0xE6C2, 0x78D0, 0xBD59, 0x78D1, 0xE6C4, 0x78D4, 0xE6C6, 0x78D5, 0xBD57, 0x78DA, 0xBF6A, 0x78DB, 0xEAA8, 0x78DD, 0xEAA2, 0x78DE, 0xEAA6, 0x78DF, 0xEAAC, 0x78E0, 0xEAAD, 0x78E1, 0xEAA9, 0x78E2, 0xEAAA, 0x78E3, 0xEAA7, 0x78E5, 0xEAA4, 0x78E7, 0xBF6C, 0x78E8, 0xBF69, 0x78E9, 0xEAA3, 0x78EA, 0xEAA5, 0x78EC, 0xBF6B, 0x78ED, 0xEAAB, 0x78EF, 0xC146, 0x78F2, 0xEDAA, 0x78F3, 0xEDA5, 0x78F4, 0xC145, 0x78F7, 0xC143, 0x78F9, 0xEDAC, 0x78FA, 0xC144, 0x78FB, 0xEDA8, 0x78FC, 0xEDA9, 0x78FD, 0xEDA6, 0x78FE, 0xEDAD, 0x78FF, 0xF056, 0x7901, 0xC147, 0x7902, 0xEDA7, 0x7904, 0xEDAE, 0x7905, 0xEDAB, 0x7909, 0xF05A, 0x790C, 0xF057, 0x790E, 0xC2A6, 0x7910, 0xF05B, 0x7911, 0xF05D, 0x7912, 0xF05C, 0x7913, 0xF058, 0x7914, 0xF059, 0x7917, 0xF2A3, 0x7919, 0xC3AA, 0x791B, 0xF27E, 0x791C, 0xF2A2, 0x791D, 0xF27D, 0x791E, 0xF2A4, 0x7921, 0xF2A1, 0x7923, 0xF47A, 0x7924, 0xF47D, 0x7925, 0xF479, 0x7926, 0xC471, 0x7927, 0xF47B, 0x7928, 0xF47C, 0x7929, 0xF47E, 0x792A, 0xC472, 0x792B, 0xC474, 0x792C, 0xC473, 0x792D, 0xF5E1, 0x792F, 0xF5E3, 0x7931, 0xF5E2, 0x7935, 0xF6F6, 0x7938, 0xF8B5, 0x7939, 0xF8FA, 0x793A, 0xA5DC, 0x793D, 0xCB72, 0x793E, 0xAAC0, 0x793F, 0xCDA3, 0x7940, 0xAAC1, 0x7941, 0xAAC2, 0x7942, 0xCDA2, 0x7944, 0xCFF8, 0x7945, 0xCFF7, 0x7946, 0xACE6, 0x7947, 0xACE9, 0x7948, 0xACE8, 0x7949, 0xACE7, 0x794A, 0xCFF4, 0x794B, 0xCFF6, 0x794C, 0xCFF5, 0x794F, 0xD2E8, 0x7950, 0xAFA7, 0x7951, 0xD2EC, 0x7952, 0xD2EB, 0x7953, 0xD2EA, 0x7954, 0xD2E6, 0x7955, 0xAFA6, 0x7956, 0xAFAA, 0x7957, 0xAFAD, 0x795A, 0xAFAE, 0x795B, 0xD2E7, 0x795C, 0xD2E9, 0x795D, 0xAFAC, 0x795E, 0xAFAB, 0x795F, 0xAFA9, 0x7960, 0xAFA8, 0x7961, 0xD6C2, 0x7963, 0xD6C0, 0x7964, 0xD6BC, 0x7965, 0xB2BB, 0x7967, 0xD6BD, 0x7968, 0xB2BC, 0x7969, 0xD6BE, 0x796A, 0xD6BF, 0x796B, 0xD6C1, 0x796D, 0xB2BD, 0x7970, 0xDAD5, 0x7972, 0xDAD4, 0x7973, 0xDAD3, 0x7974, 0xDAD2, 0x7979, 0xDEF6, 0x797A, 0xB852, 0x797C, 0xDEF3, 0x797D, 0xDEF5, 0x797F, 0xB853, 0x7981, 0xB854, 0x7982, 0xDEF4, 0x7988, 0xE341, 0x798A, 0xE2F9, 0x798B, 0xE2FA, 0x798D, 0xBAD7, 0x798E, 0xBAD5, 0x798F, 0xBAD6, 0x7990, 0xE343, 0x7992, 0xE342, 0x7993, 0xE2FE, 0x7994, 0xE2FD, 0x7995, 0xE2FC, 0x7996, 0xE2FB, 0x7997, 0xE340, 0x7998, 0xE2F8, 0x799A, 0xE6CB, 0x799B, 0xE6D0, 0x799C, 0xE6CE, 0x79A0, 0xE6CD, 0x79A1, 0xE6CC, 0x79A2, 0xE6CF, 0x79A4, 0xEAAE, 0x79A6, 0xBF6D, 0x79A7, 0xC148, 0x79A8, 0xEDB0, 0x79AA, 0xC149, 0x79AB, 0xEDAF, 0x79AC, 0xF05F, 0x79AD, 0xF05E, 0x79AE, 0xC2A7, 0x79B0, 0xF2A5, 0x79B1, 0xC3AB, 0x79B2, 0xF4A1, 0x79B3, 0xC5A1, 0x79B4, 0xF6F7, 0x79B6, 0xF8B7, 0x79B7, 0xF8B6, 0x79B8, 0xC9A8, 0x79B9, 0xACEA, 0x79BA, 0xACEB, 0x79BB, 0xD6C3, 0x79BD, 0xB856, 0x79BE, 0xA5DD, 0x79BF, 0xA872, 0x79C0, 0xA871, 0x79C1, 0xA870, 0x79C5, 0xCDA4, 0x79C8, 0xAAC4, 0x79C9, 0xAAC3, 0x79CB, 0xACEE, 0x79CD, 0xCFFA, 0x79CE, 0xCFFD, 0x79CF, 0xCFFB, 0x79D1, 0xACEC, 0x79D2, 0xACED, 0x79D5, 0xCFF9, 0x79D6, 0xCFFC, 0x79D8, 0xAFB5, 0x79DC, 0xD2F3, 0x79DD, 0xD2F5, 0x79DE, 0xD2F4, 0x79DF, 0xAFB2, 0x79E0, 0xD2EF, 0x79E3, 0xAFB0, 0x79E4, 0xAFAF, 0x79E6, 0xAFB3, 0x79E7, 0xAFB1, 0x79E9, 0xAFB4, 0x79EA, 0xD2F2, 0x79EB, 0xD2ED, 0x79EC, 0xD2EE, 0x79ED, 0xD2F1, 0x79EE, 0xD2F0, 0x79F6, 0xD6C6, 0x79F7, 0xD6C7, 0x79F8, 0xD6C5, 0x79FA, 0xD6C4, 0x79FB, 0xB2BE, 0x7A00, 0xB57D, 0x7A02, 0xDAD6, 0x7A03, 0xDAD8, 0x7A04, 0xDADA, 0x7A05, 0xB57C, 0x7A08, 0xB57A, 0x7A0A, 0xDAD7, 0x7A0B, 0xB57B, 0x7A0C, 0xDAD9, 0x7A0D, 0xB579, 0x7A10, 0xDF41, 0x7A11, 0xDEF7, 0x7A12, 0xDEFA, 0x7A13, 0xDEFE, 0x7A14, 0xB85A, 0x7A15, 0xDEFC, 0x7A17, 0xDEFB, 0x7A18, 0xDEF8, 0x7A19, 0xDEF9, 0x7A1A, 0xB858, 0x7A1B, 0xDF40, 0x7A1C, 0xB857, 0x7A1E, 0xB85C, 0x7A1F, 0xB85B, 0x7A20, 0xB859, 0x7A22, 0xDEFD, 0x7A26, 0xE349, 0x7A28, 0xE348, 0x7A2B, 0xE344, 0x7A2E, 0xBAD8, 0x7A2F, 0xE347, 0x7A30, 0xE346, 0x7A31, 0xBAD9, 0x7A37, 0xBD5E, 0x7A39, 0xE6D2, 0x7A3B, 0xBD5F, 0x7A3C, 0xBD5B, 0x7A3D, 0xBD5D, 0x7A3F, 0xBD5A, 0x7A40, 0xBD5C, 0x7A44, 0xEAAF, 0x7A46, 0xBF70, 0x7A47, 0xEAB1, 0x7A48, 0xEAB0, 0x7A4A, 0xE345, 0x7A4B, 0xBF72, 0x7A4C, 0xBF71, 0x7A4D, 0xBF6E, 0x7A4E, 0xBF6F, 0x7A54, 0xEDB5, 0x7A56, 0xEDB3, 0x7A57, 0xC14A, 0x7A58, 0xEDB4, 0x7A5A, 0xEDB6, 0x7A5B, 0xEDB2, 0x7A5C, 0xEDB1, 0x7A5F, 0xF060, 0x7A60, 0xC2AA, 0x7A61, 0xC2A8, 0x7A62, 0xC2A9, 0x7A67, 0xF2A6, 0x7A68, 0xF2A7, 0x7A69, 0xC3AD, 0x7A6B, 0xC3AC, 0x7A6C, 0xF4A3, 0x7A6D, 0xF4A4, 0x7A6E, 0xF4A2, 0x7A70, 0xF6F8, 0x7A71, 0xF6F9, 0x7A74, 0xA5DE, 0x7A75, 0xCA48, 0x7A76, 0xA873, 0x7A78, 0xCDA5, 0x7A79, 0xAAC6, 0x7A7A, 0xAAC5, 0x7A7B, 0xCDA6, 0x7A7E, 0xD040, 0x7A7F, 0xACEF, 0x7A80, 0xCFFE, 0x7A81, 0xACF0, 0x7A84, 0xAFB6, 0x7A85, 0xD2F8, 0x7A86, 0xD2F6, 0x7A87, 0xD2FC, 0x7A88, 0xAFB7, 0x7A89, 0xD2F7, 0x7A8A, 0xD2FB, 0x7A8B, 0xD2F9, 0x7A8C, 0xD2FA, 0x7A8F, 0xD6C8, 0x7A90, 0xD6CA, 0x7A92, 0xB2BF, 0x7A94, 0xD6C9, 0x7A95, 0xB2C0, 0x7A96, 0xB5A2, 0x7A97, 0xB5A1, 0x7A98, 0xB57E, 0x7A99, 0xDADB, 0x7A9E, 0xDF44, 0x7A9F, 0xB85D, 0x7AA0, 0xB85E, 0x7AA2, 0xDF43, 0x7AA3, 0xDF42, 0x7AA8, 0xE34A, 0x7AA9, 0xBADB, 0x7AAA, 0xBADA, 0x7AAB, 0xE34B, 0x7AAC, 0xE34C, 0x7AAE, 0xBD61, 0x7AAF, 0xBD60, 0x7AB1, 0xEAB5, 0x7AB2, 0xE6D3, 0x7AB3, 0xE6D5, 0x7AB4, 0xE6D4, 0x7AB5, 0xEAB4, 0x7AB6, 0xEAB2, 0x7AB7, 0xEAB6, 0x7AB8, 0xEAB3, 0x7ABA, 0xBF73, 0x7ABE, 0xEDB7, 0x7ABF, 0xC14B, 0x7AC0, 0xEDB8, 0x7AC1, 0xEDB9, 0x7AC4, 0xC2AB, 0x7AC5, 0xC2AC, 0x7AC7, 0xC475, 0x7ACA, 0xC5D1, 0x7ACB, 0xA5DF, 0x7AD1, 0xD041, 0x7AD8, 0xD2FD, 0x7AD9, 0xAFB8, 0x7ADF, 0xB3BA, 0x7AE0, 0xB3B9, 0x7AE3, 0xB5A4, 0x7AE4, 0xDADD, 0x7AE5, 0xB5A3, 0x7AE6, 0xDADC, 0x7AEB, 0xDF45, 0x7AED, 0xBADC, 0x7AEE, 0xE34D, 0x7AEF, 0xBADD, 0x7AF6, 0xC476, 0x7AF7, 0xF4A5, 0x7AF9, 0xA6CB, 0x7AFA, 0xAAC7, 0x7AFB, 0xCDA7, 0x7AFD, 0xACF2, 0x7AFF, 0xACF1, 0x7B00, 0xD042, 0x7B01, 0xD043, 0x7B04, 0xD340, 0x7B05, 0xD342, 0x7B06, 0xAFB9, 0x7B08, 0xD344, 0x7B09, 0xD347, 0x7B0A, 0xD345, 0x7B0E, 0xD346, 0x7B0F, 0xD343, 0x7B10, 0xD2FE, 0x7B11, 0xAFBA, 0x7B12, 0xD348, 0x7B13, 0xD341, 0x7B18, 0xD6D3, 0x7B19, 0xB2C6, 0x7B1A, 0xD6DC, 0x7B1B, 0xB2C3, 0x7B1D, 0xD6D5, 0x7B1E, 0xB2C7, 0x7B20, 0xB2C1, 0x7B22, 0xD6D0, 0x7B23, 0xD6DD, 0x7B24, 0xD6D1, 0x7B25, 0xD6CE, 0x7B26, 0xB2C5, 0x7B28, 0xB2C2, 0x7B2A, 0xD6D4, 0x7B2B, 0xD6D7, 0x7B2C, 0xB2C4, 0x7B2D, 0xD6D8, 0x7B2E, 0xB2C8, 0x7B2F, 0xD6D9, 0x7B30, 0xD6CF, 0x7B31, 0xD6D6, 0x7B32, 0xD6DA, 0x7B33, 0xD6D2, 0x7B34, 0xD6CD, 0x7B35, 0xD6CB, 0x7B38, 0xD6DB, 0x7B3B, 0xDADF, 0x7B40, 0xDAE4, 0x7B44, 0xDAE0, 0x7B45, 0xDAE6, 0x7B46, 0xB5A7, 0x7B47, 0xD6CC, 0x7B48, 0xDAE1, 0x7B49, 0xB5A5, 0x7B4A, 0xDADE, 0x7B4B, 0xB5AC, 0x7B4C, 0xDAE2, 0x7B4D, 0xB5AB, 0x7B4E, 0xDAE3, 0x7B4F, 0xB5AD, 0x7B50, 0xB5A8, 0x7B51, 0xB5AE, 0x7B52, 0xB5A9, 0x7B54, 0xB5AA, 0x7B56, 0xB5A6, 0x7B58, 0xDAE5, 0x7B60, 0xB861, 0x7B61, 0xDF50, 0x7B63, 0xDF53, 0x7B64, 0xDF47, 0x7B65, 0xDF4C, 0x7B66, 0xDF46, 0x7B67, 0xB863, 0x7B69, 0xDF4A, 0x7B6D, 0xDF48, 0x7B6E, 0xB862, 0x7B70, 0xDF4F, 0x7B71, 0xDF4E, 0x7B72, 0xDF4B, 0x7B73, 0xDF4D, 0x7B74, 0xDF49, 0x7B75, 0xBAE1, 0x7B76, 0xDF52, 0x7B77, 0xB85F, 0x7B78, 0xDF51, 0x7B82, 0xE35D, 0x7B84, 0xBAE8, 0x7B85, 0xE358, 0x7B87, 0xBAE7, 0x7B88, 0xE34E, 0x7B8A, 0xE350, 0x7B8B, 0xBAE0, 0x7B8C, 0xE355, 0x7B8D, 0xE354, 0x7B8E, 0xE357, 0x7B8F, 0xBAE5, 0x7B90, 0xE352, 0x7B91, 0xE351, 0x7B94, 0xBAE4, 0x7B95, 0xBADF, 0x7B96, 0xE353, 0x7B97, 0xBAE2, 0x7B98, 0xE359, 0x7B99, 0xE35B, 0x7B9B, 0xE356, 0x7B9C, 0xE34F, 0x7B9D, 0xBAE3, 0x7BA0, 0xBD69, 0x7BA1, 0xBADE, 0x7BA4, 0xE35C, 0x7BAC, 0xE6D9, 0x7BAD, 0xBD62, 0x7BAF, 0xE6DB, 0x7BB1, 0xBD63, 0x7BB4, 0xBD65, 0x7BB5, 0xE6DE, 0x7BB7, 0xE6D6, 0x7BB8, 0xBAE6, 0x7BB9, 0xE6DC, 0x7BBE, 0xE6D8, 0x7BC0, 0xB860, 0x7BC1, 0xBD68, 0x7BC4, 0xBD64, 0x7BC6, 0xBD66, 0x7BC7, 0xBD67, 0x7BC9, 0xBF76, 0x7BCA, 0xE6DD, 0x7BCB, 0xE6D7, 0x7BCC, 0xBD6A, 0x7BCE, 0xE6DA, 0x7BD4, 0xEAC0, 0x7BD5, 0xEABB, 0x7BD8, 0xEAC5, 0x7BD9, 0xBF74, 0x7BDA, 0xEABD, 0x7BDB, 0xBF78, 0x7BDC, 0xEAC3, 0x7BDD, 0xEABA, 0x7BDE, 0xEAB7, 0x7BDF, 0xEAC6, 0x7BE0, 0xC151, 0x7BE1, 0xBF79, 0x7BE2, 0xEAC2, 0x7BE3, 0xEAB8, 0x7BE4, 0xBF77, 0x7BE5, 0xEABC, 0x7BE6, 0xBF7B, 0x7BE7, 0xEAB9, 0x7BE8, 0xEABE, 0x7BE9, 0xBF7A, 0x7BEA, 0xEAC1, 0x7BEB, 0xEAC4, 0x7BF0, 0xEDCB, 0x7BF1, 0xEDCC, 0x7BF2, 0xEDBC, 0x7BF3, 0xEDC3, 0x7BF4, 0xEDC1, 0x7BF7, 0xC14F, 0x7BF8, 0xEDC8, 0x7BF9, 0xEABF, 0x7BFB, 0xEDBF, 0x7BFD, 0xEDC9, 0x7BFE, 0xC14E, 0x7BFF, 0xEDBE, 0x7C00, 0xEDBD, 0x7C01, 0xEDC7, 0x7C02, 0xEDC4, 0x7C03, 0xEDC6, 0x7C05, 0xEDBA, 0x7C06, 0xEDCA, 0x7C07, 0xC14C, 0x7C09, 0xEDC5, 0x7C0A, 0xEDCE, 0x7C0B, 0xEDC2, 0x7C0C, 0xC150, 0x7C0D, 0xC14D, 0x7C0E, 0xEDC0, 0x7C0F, 0xEDBB, 0x7C10, 0xEDCD, 0x7C11, 0xBF75, 0x7C19, 0xF063, 0x7C1C, 0xF061, 0x7C1D, 0xF067, 0x7C1E, 0xC2B0, 0x7C1F, 0xF065, 0x7C20, 0xF064, 0x7C21, 0xC2B2, 0x7C22, 0xF06A, 0x7C23, 0xC2B1, 0x7C25, 0xF06B, 0x7C26, 0xF068, 0x7C27, 0xC2AE, 0x7C28, 0xF069, 0x7C29, 0xF062, 0x7C2A, 0xC2AF, 0x7C2B, 0xC2AD, 0x7C2C, 0xF2AB, 0x7C2D, 0xF066, 0x7C30, 0xF06C, 0x7C33, 0xF2A8, 0x7C37, 0xC3B2, 0x7C38, 0xC3B0, 0x7C39, 0xF2AA, 0x7C3B, 0xF2AC, 0x7C3C, 0xF2A9, 0x7C3D, 0xC3B1, 0x7C3E, 0xC3AE, 0x7C3F, 0xC3AF, 0x7C40, 0xC3B3, 0x7C43, 0xC478, 0x7C45, 0xF4AA, 0x7C47, 0xF4A9, 0x7C48, 0xF4A7, 0x7C49, 0xF4A6, 0x7C4A, 0xF4A8, 0x7C4C, 0xC477, 0x7C4D, 0xC479, 0x7C50, 0xC4F0, 0x7C53, 0xF5E5, 0x7C54, 0xF5E4, 0x7C57, 0xF6FA, 0x7C59, 0xF6FC, 0x7C5A, 0xF6FE, 0x7C5B, 0xF6FD, 0x7C5C, 0xF6FB, 0x7C5F, 0xC5A3, 0x7C60, 0xC5A2, 0x7C63, 0xC5D3, 0x7C64, 0xC5D2, 0x7C65, 0xC5D4, 0x7C66, 0xF7ED, 0x7C67, 0xF7EC, 0x7C69, 0xF8FB, 0x7C6A, 0xF8B8, 0x7C6B, 0xF8FC, 0x7C6C, 0xC658, 0x7C6E, 0xC659, 0x7C6F, 0xF96D, 0x7C72, 0xC67E, 0x7C73, 0xA6CC, 0x7C75, 0xCDA8, 0x7C78, 0xD045, 0x7C79, 0xD046, 0x7C7A, 0xD044, 0x7C7D, 0xACF3, 0x7C7F, 0xD047, 0x7C80, 0xD048, 0x7C81, 0xD049, 0x7C84, 0xD349, 0x7C85, 0xD34F, 0x7C88, 0xD34D, 0x7C89, 0xAFBB, 0x7C8A, 0xD34B, 0x7C8C, 0xD34C, 0x7C8D, 0xD34E, 0x7C91, 0xD34A, 0x7C92, 0xB2C9, 0x7C94, 0xD6DE, 0x7C95, 0xB2CB, 0x7C96, 0xD6E0, 0x7C97, 0xB2CA, 0x7C98, 0xD6DF, 0x7C9E, 0xDAE8, 0x7C9F, 0xB5AF, 0x7CA1, 0xDAEA, 0x7CA2, 0xDAE7, 0x7CA3, 0xD6E1, 0x7CA5, 0xB5B0, 0x7CA7, 0xF9DB, 0x7CA8, 0xDAE9, 0x7CAF, 0xDF56, 0x7CB1, 0xB864, 0x7CB2, 0xDF54, 0x7CB3, 0xB865, 0x7CB4, 0xDF55, 0x7CB5, 0xB866, 0x7CB9, 0xBAE9, 0x7CBA, 0xE361, 0x7CBB, 0xE35E, 0x7CBC, 0xE360, 0x7CBD, 0xBAEA, 0x7CBE, 0xBAEB, 0x7CBF, 0xE35F, 0x7CC5, 0xE6DF, 0x7CC8, 0xE6E0, 0x7CCA, 0xBD6B, 0x7CCB, 0xE6E2, 0x7CCC, 0xE6E1, 0x7CCE, 0xA261, 0x7CD0, 0xEACA, 0x7CD1, 0xEACB, 0x7CD2, 0xEAC7, 0x7CD4, 0xEAC8, 0x7CD5, 0xBF7C, 0x7CD6, 0xBF7D, 0x7CD7, 0xEAC9, 0x7CD9, 0xC157, 0x7CDC, 0xC153, 0x7CDD, 0xC158, 0x7CDE, 0xC154, 0x7CDF, 0xC156, 0x7CE0, 0xC152, 0x7CE2, 0xC155, 0x7CE7, 0xC2B3, 0x7CE8, 0xEDCF, 0x7CEA, 0xF2AE, 0x7CEC, 0xF2AD, 0x7CEE, 0xF4AB, 0x7CEF, 0xC47A, 0x7CF0, 0xC47B, 0x7CF1, 0xF741, 0x7CF2, 0xF5E6, 0x7CF4, 0xF740, 0x7CF6, 0xF8FD, 0x7CF7, 0xF9A4, 0x7CF8, 0xA6CD, 0x7CFB, 0xA874, 0x7CFD, 0xCDA9, 0x7CFE, 0xAAC8, 0x7D00, 0xACF6, 0x7D01, 0xD04C, 0x7D02, 0xACF4, 0x7D03, 0xD04A, 0x7D04, 0xACF9, 0x7D05, 0xACF5, 0x7D06, 0xACFA, 0x7D07, 0xACF8, 0x7D08, 0xD04B, 0x7D09, 0xACF7, 0x7D0A, 0xAFBF, 0x7D0B, 0xAFBE, 0x7D0C, 0xD35A, 0x7D0D, 0xAFC7, 0x7D0E, 0xD353, 0x7D0F, 0xD359, 0x7D10, 0xAFC3, 0x7D11, 0xD352, 0x7D12, 0xD358, 0x7D13, 0xD356, 0x7D14, 0xAFC2, 0x7D15, 0xAFC4, 0x7D16, 0xD355, 0x7D17, 0xAFBD, 0x7D18, 0xD354, 0x7D19, 0xAFC8, 0x7D1A, 0xAFC5, 0x7D1B, 0xAFC9, 0x7D1C, 0xAFC6, 0x7D1D, 0xD351, 0x7D1E, 0xD350, 0x7D1F, 0xD357, 0x7D20, 0xAFC0, 0x7D21, 0xAFBC, 0x7D22, 0xAFC1, 0x7D28, 0xD6F0, 0x7D29, 0xD6E9, 0x7D2B, 0xB5B5, 0x7D2C, 0xD6E8, 0x7D2E, 0xB2CF, 0x7D2F, 0xB2D6, 0x7D30, 0xB2D3, 0x7D31, 0xB2D9, 0x7D32, 0xB2D8, 0x7D33, 0xB2D4, 0x7D35, 0xD6E2, 0x7D36, 0xD6E5, 0x7D38, 0xD6E4, 0x7D39, 0xB2D0, 0x7D3A, 0xD6E6, 0x7D3B, 0xD6EF, 0x7D3C, 0xB2D1, 0x7D3D, 0xD6E3, 0x7D3E, 0xD6EC, 0x7D3F, 0xD6ED, 0x7D40, 0xB2D2, 0x7D41, 0xD6EA, 0x7D42, 0xB2D7, 0x7D43, 0xB2CD, 0x7D44, 0xB2D5, 0x7D45, 0xD6E7, 0x7D46, 0xB2CC, 0x7D47, 0xD6EB, 0x7D4A, 0xD6EE, 0x7D4E, 0xDAFB, 0x7D4F, 0xDAF2, 0x7D50, 0xB5B2, 0x7D51, 0xDAF9, 0x7D52, 0xDAF6, 0x7D53, 0xDAEE, 0x7D54, 0xDAF7, 0x7D55, 0xB5B4, 0x7D56, 0xDAEF, 0x7D58, 0xDAEB, 0x7D5B, 0xB86C, 0x7D5C, 0xDAF4, 0x7D5E, 0xB5B1, 0x7D5F, 0xDAFA, 0x7D61, 0xB5B8, 0x7D62, 0xB5BA, 0x7D63, 0xDAED, 0x7D66, 0xB5B9, 0x7D67, 0xDAF0, 0x7D68, 0xB5B3, 0x7D69, 0xDAF8, 0x7D6A, 0xDAF1, 0x7D6B, 0xDAF5, 0x7D6D, 0xDAF3, 0x7D6E, 0xB5B6, 0x7D6F, 0xDAEC, 0x7D70, 0xB5BB, 0x7D71, 0xB2CE, 0x7D72, 0xB5B7, 0x7D73, 0xB5BC, 0x7D79, 0xB868, 0x7D7A, 0xDF5D, 0x7D7B, 0xDF5F, 0x7D7C, 0xDF61, 0x7D7D, 0xDF65, 0x7D7F, 0xDF5B, 0x7D80, 0xDF59, 0x7D81, 0xB86A, 0x7D83, 0xDF60, 0x7D84, 0xDF64, 0x7D85, 0xDF5C, 0x7D86, 0xDF58, 0x7D88, 0xDF57, 0x7D8C, 0xDF62, 0x7D8D, 0xDF5A, 0x7D8E, 0xDF5E, 0x7D8F, 0xB86B, 0x7D91, 0xB869, 0x7D92, 0xDF66, 0x7D93, 0xB867, 0x7D94, 0xDF63, 0x7D96, 0xE372, 0x7D9C, 0xBAEE, 0x7D9D, 0xE36A, 0x7D9E, 0xBD78, 0x7D9F, 0xE374, 0x7DA0, 0xBAF1, 0x7DA1, 0xE378, 0x7DA2, 0xBAF7, 0x7DA3, 0xE365, 0x7DA6, 0xE375, 0x7DA7, 0xE362, 0x7DA9, 0xE377, 0x7DAA, 0xE366, 0x7DAC, 0xBAFE, 0x7DAD, 0xBAFB, 0x7DAE, 0xE376, 0x7DAF, 0xE370, 0x7DB0, 0xBAED, 0x7DB1, 0xBAF5, 0x7DB2, 0xBAF4, 0x7DB4, 0xBAF3, 0x7DB5, 0xBAF9, 0x7DB7, 0xE363, 0x7DB8, 0xBAFA, 0x7DB9, 0xE371, 0x7DBA, 0xBAF6, 0x7DBB, 0xBAEC, 0x7DBC, 0xE373, 0x7DBD, 0xBAEF, 0x7DBE, 0xBAF0, 0x7DBF, 0xBAF8, 0x7DC0, 0xE368, 0x7DC1, 0xE367, 0x7DC2, 0xE364, 0x7DC4, 0xE36C, 0x7DC5, 0xE369, 0x7DC6, 0xE36D, 0x7DC7, 0xBAFD, 0x7DC9, 0xE379, 0x7DCA, 0xBAF2, 0x7DCB, 0xE36E, 0x7DCC, 0xE36F, 0x7DCE, 0xE36B, 0x7DD2, 0xBAFC, 0x7DD7, 0xE6E7, 0x7DD8, 0xBD70, 0x7DD9, 0xBD79, 0x7DDA, 0xBD75, 0x7DDB, 0xE6E4, 0x7DDD, 0xBD72, 0x7DDE, 0xBD76, 0x7DDF, 0xE6F0, 0x7DE0, 0xBD6C, 0x7DE1, 0xE6E8, 0x7DE3, 0xBD74, 0x7DE6, 0xE6EB, 0x7DE7, 0xE6E6, 0x7DE8, 0xBD73, 0x7DE9, 0xBD77, 0x7DEA, 0xE6E5, 0x7DEC, 0xBD71, 0x7DEE, 0xE6EF, 0x7DEF, 0xBD6E, 0x7DF0, 0xE6EE, 0x7DF1, 0xE6ED, 0x7DF2, 0xBD7A, 0x7DF3, 0xE572, 0x7DF4, 0xBD6D, 0x7DF6, 0xE6EC, 0x7DF7, 0xE6E3, 0x7DF9, 0xBD7B, 0x7DFA, 0xE6EA, 0x7DFB, 0xBD6F, 0x7E03, 0xE6E9, 0x7E08, 0xBFA2, 0x7E09, 0xBFA7, 0x7E0A, 0xBF7E, 0x7E0B, 0xEAD8, 0x7E0C, 0xEACF, 0x7E0D, 0xEADB, 0x7E0E, 0xEAD3, 0x7E0F, 0xEAD9, 0x7E10, 0xBFA8, 0x7E11, 0xBFA1, 0x7E12, 0xEACC, 0x7E13, 0xEAD2, 0x7E14, 0xEADC, 0x7E15, 0xEAD5, 0x7E16, 0xEADA, 0x7E17, 0xEACE, 0x7E1A, 0xEAD6, 0x7E1B, 0xBFA3, 0x7E1C, 0xEAD4, 0x7E1D, 0xBFA6, 0x7E1E, 0xBFA5, 0x7E1F, 0xEAD0, 0x7E20, 0xEAD1, 0x7E21, 0xEACD, 0x7E22, 0xEAD7, 0x7E23, 0xBFA4, 0x7E24, 0xEADE, 0x7E25, 0xEADD, 0x7E29, 0xEDDA, 0x7E2A, 0xEDD6, 0x7E2B, 0xC15F, 0x7E2D, 0xEDD0, 0x7E2E, 0xC159, 0x7E2F, 0xC169, 0x7E30, 0xEDDC, 0x7E31, 0xC161, 0x7E32, 0xC15D, 0x7E33, 0xEDD3, 0x7E34, 0xC164, 0x7E35, 0xC167, 0x7E36, 0xEDDE, 0x7E37, 0xC15C, 0x7E38, 0xEDD5, 0x7E39, 0xC165, 0x7E3A, 0xEDE0, 0x7E3B, 0xEDDD, 0x7E3C, 0xEDD1, 0x7E3D, 0xC160, 0x7E3E, 0xC15A, 0x7E3F, 0xC168, 0x7E40, 0xEDD8, 0x7E41, 0xC163, 0x7E42, 0xEDD2, 0x7E43, 0xC15E, 0x7E44, 0xEDDF, 0x7E45, 0xC162, 0x7E46, 0xC15B, 0x7E47, 0xEDD9, 0x7E48, 0xC166, 0x7E49, 0xEDD7, 0x7E4C, 0xEDDB, 0x7E50, 0xF06E, 0x7E51, 0xF074, 0x7E52, 0xC2B9, 0x7E53, 0xF077, 0x7E54, 0xC2B4, 0x7E55, 0xC2B5, 0x7E56, 0xF06F, 0x7E57, 0xF076, 0x7E58, 0xF071, 0x7E59, 0xC2BA, 0x7E5A, 0xC2B7, 0x7E5C, 0xF06D, 0x7E5E, 0xC2B6, 0x7E5F, 0xF073, 0x7E60, 0xF075, 0x7E61, 0xC2B8, 0x7E62, 0xF072, 0x7E63, 0xF070, 0x7E68, 0xF2B8, 0x7E69, 0xC3B7, 0x7E6A, 0xC3B8, 0x7E6B, 0xC3B4, 0x7E6D, 0xC3B5, 0x7E6F, 0xF2B4, 0x7E70, 0xF2B2, 0x7E72, 0xF2B6, 0x7E73, 0xC3BA, 0x7E74, 0xF2B7, 0x7E75, 0xF2B0, 0x7E76, 0xF2AF, 0x7E77, 0xF2B3, 0x7E78, 0xF2B1, 0x7E79, 0xC3B6, 0x7E7A, 0xF2B5, 0x7E7B, 0xF4AC, 0x7E7C, 0xC47E, 0x7E7D, 0xC47D, 0x7E7E, 0xF4AD, 0x7E80, 0xF4AF, 0x7E81, 0xF4AE, 0x7E82, 0xC4A1, 0x7E86, 0xF5EB, 0x7E87, 0xF5E8, 0x7E88, 0xF5E9, 0x7E8A, 0xF5E7, 0x7E8B, 0xF5EA, 0x7E8C, 0xC4F2, 0x7E8D, 0xF5EC, 0x7E8F, 0xC4F1, 0x7E91, 0xF742, 0x7E93, 0xC5D5, 0x7E94, 0xC5D7, 0x7E95, 0xF7EE, 0x7E96, 0xC5D6, 0x7E97, 0xF8B9, 0x7E98, 0xF940, 0x7E99, 0xF942, 0x7E9A, 0xF8FE, 0x7E9B, 0xF941, 0x7E9C, 0xC66C, 0x7F36, 0xA6CE, 0x7F38, 0xACFB, 0x7F39, 0xD26F, 0x7F3A, 0xAFCA, 0x7F3D, 0xB2DA, 0x7F3E, 0xDAFC, 0x7F3F, 0xDAFD, 0x7F43, 0xEADF, 0x7F44, 0xC16A, 0x7F45, 0xEDE1, 0x7F48, 0xC2BB, 0x7F4A, 0xF2BA, 0x7F4B, 0xF2B9, 0x7F4C, 0xC4A2, 0x7F4D, 0xF5ED, 0x7F4F, 0xF743, 0x7F50, 0xC5F8, 0x7F51, 0xCA49, 0x7F54, 0xAAC9, 0x7F55, 0xA875, 0x7F58, 0xD04D, 0x7F5B, 0xD360, 0x7F5C, 0xD35B, 0x7F5D, 0xD35F, 0x7F5E, 0xD35D, 0x7F5F, 0xAFCB, 0x7F60, 0xD35E, 0x7F61, 0xD35C, 0x7F63, 0xD6F1, 0x7F65, 0xDAFE, 0x7F66, 0xDB40, 0x7F67, 0xDF69, 0x7F68, 0xDF6A, 0x7F69, 0xB86E, 0x7F6A, 0xB86F, 0x7F6B, 0xDF68, 0x7F6C, 0xDF6B, 0x7F6D, 0xDF67, 0x7F6E, 0xB86D, 0x7F70, 0xBB40, 0x7F72, 0xB870, 0x7F73, 0xE37A, 0x7F75, 0xBD7C, 0x7F76, 0xE6F1, 0x7F77, 0xBD7D, 0x7F79, 0xBFA9, 0x7F7A, 0xEAE2, 0x7F7B, 0xEAE0, 0x7F7C, 0xEAE1, 0x7F7D, 0xEDE4, 0x7F7E, 0xEDE3, 0x7F7F, 0xEDE2, 0x7F83, 0xF2BB, 0x7F85, 0xC3B9, 0x7F86, 0xF2BC, 0x7F87, 0xF744, 0x7F88, 0xC5F9, 0x7F89, 0xF8BA, 0x7F8A, 0xA6CF, 0x7F8B, 0xAACB, 0x7F8C, 0xAACA, 0x7F8D, 0xD04F, 0x7F8E, 0xACFC, 0x7F91, 0xD04E, 0x7F92, 0xD362, 0x7F94, 0xAFCC, 0x7F95, 0xD6F2, 0x7F96, 0xD361, 0x7F9A, 0xB2DC, 0x7F9B, 0xD6F5, 0x7F9C, 0xD6F3, 0x7F9D, 0xD6F4, 0x7F9E, 0xB2DB, 0x7FA0, 0xDB42, 0x7FA1, 0xDB43, 0x7FA2, 0xDB41, 0x7FA4, 0xB873, 0x7FA5, 0xDF6D, 0x7FA6, 0xDF6C, 0x7FA7, 0xDF6E, 0x7FA8, 0xB872, 0x7FA9, 0xB871, 0x7FAC, 0xE6F2, 0x7FAD, 0xE6F4, 0x7FAF, 0xBD7E, 0x7FB0, 0xE6F3, 0x7FB1, 0xEAE3, 0x7FB2, 0xBFAA, 0x7FB3, 0xF079, 0x7FB5, 0xF078, 0x7FB6, 0xC3BB, 0x7FB7, 0xF2BD, 0x7FB8, 0xC3BD, 0x7FB9, 0xC3BC, 0x7FBA, 0xF4B0, 0x7FBB, 0xF5EE, 0x7FBC, 0xC4F3, 0x7FBD, 0xA6D0, 0x7FBE, 0xD050, 0x7FBF, 0xACFD, 0x7FC0, 0xD365, 0x7FC1, 0xAFCE, 0x7FC2, 0xD364, 0x7FC3, 0xD363, 0x7FC5, 0xAFCD, 0x7FC7, 0xD6FB, 0x7FC9, 0xD6FD, 0x7FCA, 0xD6F6, 0x7FCB, 0xD6F7, 0x7FCC, 0xB2DD, 0x7FCD, 0xD6F8, 0x7FCE, 0xB2DE, 0x7FCF, 0xD6FC, 0x7FD0, 0xD6F9, 0x7FD1, 0xD6FA, 0x7FD2, 0xB2DF, 0x7FD4, 0xB5BE, 0x7FD5, 0xB5BF, 0x7FD7, 0xDB44, 0x7FDB, 0xDF6F, 0x7FDC, 0xDF70, 0x7FDE, 0xE37E, 0x7FDF, 0xBB43, 0x7FE0, 0xBB41, 0x7FE1, 0xBB42, 0x7FE2, 0xE37B, 0x7FE3, 0xE37C, 0x7FE5, 0xE37D, 0x7FE6, 0xE6F9, 0x7FE8, 0xE6FA, 0x7FE9, 0xBDA1, 0x7FEA, 0xE6F7, 0x7FEB, 0xE6F6, 0x7FEC, 0xE6F8, 0x7FED, 0xE6F5, 0x7FEE, 0xBFAD, 0x7FEF, 0xEAE4, 0x7FF0, 0xBFAB, 0x7FF1, 0xBFAC, 0x7FF2, 0xEDE6, 0x7FF3, 0xC16B, 0x7FF4, 0xEDE5, 0x7FF5, 0xEFA8, 0x7FF7, 0xF07A, 0x7FF8, 0xF07B, 0x7FF9, 0xC2BC, 0x7FFB, 0xC2BD, 0x7FFC, 0xC16C, 0x7FFD, 0xF2BE, 0x7FFE, 0xF2BF, 0x7FFF, 0xF4B1, 0x8000, 0xC4A3, 0x8001, 0xA6D1, 0x8003, 0xA6D2, 0x8004, 0xACFE, 0x8005, 0xAACC, 0x8006, 0xAFCF, 0x8007, 0xD051, 0x800B, 0xB5C0, 0x800C, 0xA6D3, 0x800D, 0xAD41, 0x800E, 0xD052, 0x800F, 0xD053, 0x8010, 0xAD40, 0x8011, 0xAD42, 0x8012, 0xA6D4, 0x8014, 0xD054, 0x8015, 0xAFD1, 0x8016, 0xD366, 0x8017, 0xAFD3, 0x8018, 0xAFD0, 0x8019, 0xAFD2, 0x801B, 0xD741, 0x801C, 0xB2E0, 0x801E, 0xD740, 0x801F, 0xD6FE, 0x8021, 0xDF71, 0x8024, 0xE3A1, 0x8026, 0xBDA2, 0x8028, 0xBFAE, 0x8029, 0xEAE6, 0x802A, 0xEAE5, 0x802C, 0xEDE7, 0x8030, 0xF5EF, 0x8033, 0xA6D5, 0x8034, 0xCB73, 0x8035, 0xCDAA, 0x8036, 0xAD43, 0x8037, 0xD055, 0x8039, 0xD368, 0x803D, 0xAFD4, 0x803E, 0xD367, 0x803F, 0xAFD5, 0x8043, 0xD743, 0x8046, 0xB2E2, 0x8047, 0xD742, 0x8048, 0xD744, 0x804A, 0xB2E1, 0x804F, 0xDB46, 0x8050, 0xDB47, 0x8051, 0xDB45, 0x8052, 0xB5C1, 0x8056, 0xB874, 0x8058, 0xB875, 0x805A, 0xBB45, 0x805C, 0xE3A3, 0x805D, 0xE3A2, 0x805E, 0xBB44, 0x8064, 0xE6FB, 0x8067, 0xE6FC, 0x806C, 0xEAE7, 0x806F, 0xC170, 0x8070, 0xC16F, 0x8071, 0xC16D, 0x8072, 0xC16E, 0x8073, 0xC171, 0x8075, 0xF07C, 0x8076, 0xC2BF, 0x8077, 0xC2BE, 0x8078, 0xF2C0, 0x8079, 0xF4B2, 0x807D, 0xC5A5, 0x807E, 0xC5A4, 0x807F, 0xA6D6, 0x8082, 0xD1FB, 0x8084, 0xB877, 0x8085, 0xB5C2, 0x8086, 0xB876, 0x8087, 0xBB46, 0x8089, 0xA6D7, 0x808A, 0xC9A9, 0x808B, 0xA6D8, 0x808C, 0xA6D9, 0x808F, 0xCDAB, 0x8090, 0xCB76, 0x8092, 0xCB77, 0x8093, 0xA877, 0x8095, 0xCB74, 0x8096, 0xA876, 0x8098, 0xA879, 0x8099, 0xCB75, 0x809A, 0xA87B, 0x809B, 0xA87A, 0x809C, 0xCB78, 0x809D, 0xA878, 0x80A1, 0xAAD1, 0x80A2, 0xAACF, 0x80A3, 0xCDAD, 0x80A5, 0xAACE, 0x80A9, 0xAAD3, 0x80AA, 0xAAD5, 0x80AB, 0xAAD2, 0x80AD, 0xCDB0, 0x80AE, 0xCDAC, 0x80AF, 0xAAD6, 0x80B1, 0xAAD0, 0x80B2, 0xA87C, 0x80B4, 0xAAD4, 0x80B5, 0xCDAF, 0x80B8, 0xCDAE, 0x80BA, 0xAACD, 0x80C2, 0xD05B, 0x80C3, 0xAD47, 0x80C4, 0xAD48, 0x80C5, 0xD05D, 0x80C7, 0xD057, 0x80C8, 0xD05A, 0x80C9, 0xD063, 0x80CA, 0xD061, 0x80CC, 0xAD49, 0x80CD, 0xD067, 0x80CE, 0xAD4C, 0x80CF, 0xD064, 0x80D0, 0xD05C, 0x80D1, 0xD059, 0x80D4, 0xDB49, 0x80D5, 0xD062, 0x80D6, 0xAD44, 0x80D7, 0xD065, 0x80D8, 0xD056, 0x80D9, 0xD05F, 0x80DA, 0xAD46, 0x80DB, 0xAD4B, 0x80DC, 0xD060, 0x80DD, 0xAD4F, 0x80DE, 0xAD4D, 0x80E0, 0xD058, 0x80E1, 0xAD4A, 0x80E3, 0xD05E, 0x80E4, 0xAD4E, 0x80E5, 0xAD45, 0x80E6, 0xD066, 0x80ED, 0xAFDA, 0x80EF, 0xAFE3, 0x80F0, 0xAFD8, 0x80F1, 0xAFD6, 0x80F2, 0xD36A, 0x80F3, 0xAFDE, 0x80F4, 0xAFDB, 0x80F5, 0xD36C, 0x80F8, 0xAFDD, 0x80F9, 0xD36B, 0x80FA, 0xD369, 0x80FB, 0xD36E, 0x80FC, 0xAFE2, 0x80FD, 0xAFE0, 0x80FE, 0xDB48, 0x8100, 0xD36F, 0x8101, 0xD36D, 0x8102, 0xAFD7, 0x8105, 0xAFD9, 0x8106, 0xAFDC, 0x8108, 0xAFDF, 0x810A, 0xAFE1, 0x8115, 0xD74E, 0x8116, 0xB2E4, 0x8118, 0xD745, 0x8119, 0xD747, 0x811B, 0xD748, 0x811D, 0xD750, 0x811E, 0xD74C, 0x811F, 0xD74A, 0x8121, 0xD74D, 0x8122, 0xD751, 0x8123, 0xB2E5, 0x8124, 0xB2E9, 0x8125, 0xD746, 0x8127, 0xD74F, 0x8129, 0xB2E7, 0x812B, 0xB2E6, 0x812C, 0xD74B, 0x812D, 0xD749, 0x812F, 0xB2E3, 0x8130, 0xB2E8, 0x8139, 0xB5C8, 0x813A, 0xDB51, 0x813D, 0xDB4F, 0x813E, 0xB5CA, 0x8143, 0xDB4A, 0x8144, 0xDFA1, 0x8146, 0xB5C9, 0x8147, 0xDB4E, 0x814A, 0xDB4B, 0x814B, 0xB5C5, 0x814C, 0xB5CB, 0x814D, 0xDB50, 0x814E, 0xB5C7, 0x814F, 0xDB4D, 0x8150, 0xBB47, 0x8151, 0xB5C6, 0x8152, 0xDB4C, 0x8153, 0xB5CC, 0x8154, 0xB5C4, 0x8155, 0xB5C3, 0x815B, 0xDF77, 0x815C, 0xDF75, 0x815E, 0xDF7B, 0x8160, 0xDF73, 0x8161, 0xDFA2, 0x8162, 0xDF78, 0x8164, 0xDF72, 0x8165, 0xB87B, 0x8166, 0xB8A3, 0x8167, 0xDF7D, 0x8169, 0xDF76, 0x816B, 0xB87E, 0x816E, 0xB87C, 0x816F, 0xDF7E, 0x8170, 0xB879, 0x8171, 0xB878, 0x8172, 0xDF79, 0x8173, 0xB87D, 0x8174, 0xB5CD, 0x8176, 0xDF7C, 0x8177, 0xDF74, 0x8178, 0xB87A, 0x8179, 0xB8A1, 0x817A, 0xB8A2, 0x817F, 0xBB4C, 0x8180, 0xBB48, 0x8182, 0xBB4D, 0x8183, 0xE3A6, 0x8186, 0xE3A5, 0x8187, 0xE3A7, 0x8188, 0xBB4A, 0x8189, 0xE3A4, 0x818A, 0xBB4B, 0x818B, 0xE3AA, 0x818C, 0xE3A9, 0x818D, 0xE3A8, 0x818F, 0xBB49, 0x8195, 0xE741, 0x8197, 0xE744, 0x8198, 0xBDA8, 0x8199, 0xE743, 0x819A, 0xBDA7, 0x819B, 0xBDA3, 0x819C, 0xBDA4, 0x819D, 0xBDA5, 0x819E, 0xE740, 0x819F, 0xE6FE, 0x81A0, 0xBDA6, 0x81A2, 0xE742, 0x81A3, 0xE6FD, 0x81A6, 0xEAE9, 0x81A7, 0xEAF3, 0x81A8, 0xBFB1, 0x81A9, 0xBFB0, 0x81AB, 0xEAED, 0x81AC, 0xEAEF, 0x81AE, 0xEAEA, 0x81B0, 0xEAEE, 0x81B1, 0xEAE8, 0x81B2, 0xEAF1, 0x81B3, 0xBFAF, 0x81B4, 0xEAF0, 0x81B5, 0xEAEC, 0x81B7, 0xEAF2, 0x81B9, 0xEAEB, 0x81BA, 0xC174, 0x81BB, 0xEDE8, 0x81BC, 0xEDEE, 0x81BD, 0xC178, 0x81BE, 0xC17A, 0x81BF, 0xC177, 0x81C0, 0xC176, 0x81C2, 0xC175, 0x81C3, 0xC173, 0x81C4, 0xEDE9, 0x81C5, 0xEDEC, 0x81C6, 0xC172, 0x81C7, 0xEDED, 0x81C9, 0xC179, 0x81CA, 0xEDEB, 0x81CC, 0xEDEA, 0x81CD, 0xC2C0, 0x81CF, 0xC2C1, 0x81D0, 0xF0A1, 0x81D1, 0xF07D, 0x81D2, 0xF07E, 0x81D5, 0xF2C2, 0x81D7, 0xF2C1, 0x81D8, 0xC3BE, 0x81D9, 0xF4B4, 0x81DA, 0xC4A4, 0x81DB, 0xF4B3, 0x81DD, 0xF5F0, 0x81DE, 0xF745, 0x81DF, 0xC5A6, 0x81E0, 0xF943, 0x81E1, 0xF944, 0x81E2, 0xC5D8, 0x81E3, 0xA6DA, 0x81E5, 0xAAD7, 0x81E6, 0xDB52, 0x81E7, 0xBB4E, 0x81E8, 0xC17B, 0x81E9, 0xEDEF, 0x81EA, 0xA6DB, 0x81EC, 0xAFE5, 0x81ED, 0xAFE4, 0x81EE, 0xDB53, 0x81F2, 0xEAF4, 0x81F3, 0xA6DC, 0x81F4, 0xAD50, 0x81F7, 0xDB54, 0x81F8, 0xDB55, 0x81F9, 0xDB56, 0x81FA, 0xBB4F, 0x81FB, 0xBFB2, 0x81FC, 0xA6DD, 0x81FE, 0xAAD8, 0x81FF, 0xD068, 0x8200, 0xAFE6, 0x8201, 0xD370, 0x8202, 0xB2EA, 0x8204, 0xDB57, 0x8205, 0xB8A4, 0x8207, 0xBB50, 0x8208, 0xBFB3, 0x8209, 0xC17C, 0x820A, 0xC2C2, 0x820B, 0xF4B5, 0x820C, 0xA6DE, 0x820D, 0xAAD9, 0x8210, 0xAFE7, 0x8211, 0xD752, 0x8212, 0xB5CE, 0x8214, 0xBB51, 0x8215, 0xE3AB, 0x8216, 0xE745, 0x821B, 0xA6DF, 0x821C, 0xB5CF, 0x821D, 0xDFA3, 0x821E, 0xBB52, 0x821F, 0xA6E0, 0x8220, 0xCDB1, 0x8221, 0xD069, 0x8222, 0xAD51, 0x8225, 0xD372, 0x8228, 0xAFEA, 0x822A, 0xAFE8, 0x822B, 0xAFE9, 0x822C, 0xAFEB, 0x822F, 0xD371, 0x8232, 0xD757, 0x8233, 0xD754, 0x8234, 0xD756, 0x8235, 0xB2EB, 0x8236, 0xB2ED, 0x8237, 0xB2EC, 0x8238, 0xD753, 0x8239, 0xB2EE, 0x823A, 0xD755, 0x823C, 0xDB58, 0x823D, 0xDB59, 0x823F, 0xDB5A, 0x8240, 0xDFA6, 0x8242, 0xDFA7, 0x8244, 0xDFA5, 0x8245, 0xDFA8, 0x8247, 0xB8A5, 0x8249, 0xDFA4, 0x824B, 0xBB53, 0x824E, 0xE74A, 0x824F, 0xE746, 0x8250, 0xE749, 0x8251, 0xE74B, 0x8252, 0xE748, 0x8253, 0xE747, 0x8255, 0xEAF5, 0x8256, 0xEAF6, 0x8257, 0xEAF7, 0x8258, 0xBFB4, 0x8259, 0xBFB5, 0x825A, 0xEDF1, 0x825B, 0xEDF0, 0x825C, 0xEDF2, 0x825E, 0xF0A3, 0x825F, 0xF0A2, 0x8261, 0xF2C4, 0x8263, 0xF2C5, 0x8264, 0xF2C3, 0x8266, 0xC4A5, 0x8268, 0xF4B6, 0x8269, 0xF4B7, 0x826B, 0xF746, 0x826C, 0xF7EF, 0x826D, 0xF8BB, 0x826E, 0xA6E1, 0x826F, 0xA87D, 0x8271, 0xC17D, 0x8272, 0xA6E2, 0x8274, 0xD758, 0x8275, 0xDB5B, 0x8277, 0xC641, 0x8278, 0xCA4A, 0x827C, 0xCA4B, 0x827D, 0xCA4D, 0x827E, 0xA6E3, 0x827F, 0xCA4E, 0x8280, 0xCA4C, 0x8283, 0xCBA2, 0x8284, 0xCBA3, 0x8285, 0xCB7B, 0x828A, 0xCBA1, 0x828B, 0xA8A1, 0x828D, 0xA8A2, 0x828E, 0xCB7C, 0x828F, 0xCB7A, 0x8290, 0xCB79, 0x8291, 0xCB7D, 0x8292, 0xA87E, 0x8293, 0xCB7E, 0x8294, 0xD06A, 0x8298, 0xCDB6, 0x8299, 0xAADC, 0x829A, 0xCDB5, 0x829B, 0xCDB7, 0x829D, 0xAADB, 0x829E, 0xCDBC, 0x829F, 0xAADF, 0x82A0, 0xCDB2, 0x82A1, 0xCDC0, 0x82A2, 0xCDC6, 0x82A3, 0xAAE6, 0x82A4, 0xCDC3, 0x82A5, 0xAAE3, 0x82A7, 0xCDB9, 0x82A8, 0xCDBF, 0x82A9, 0xCDC1, 0x82AB, 0xCDB4, 0x82AC, 0xAAE2, 0x82AD, 0xAADD, 0x82AE, 0xCDBA, 0x82AF, 0xAAE4, 0x82B0, 0xAAE7, 0x82B1, 0xAAE1, 0x82B3, 0xAADA, 0x82B4, 0xCDBE, 0x82B5, 0xCDB8, 0x82B6, 0xCDC5, 0x82B7, 0xAAE9, 0x82B8, 0xAAE5, 0x82B9, 0xAAE0, 0x82BA, 0xCDBD, 0x82BB, 0xAFEC, 0x82BC, 0xCDBB, 0x82BD, 0xAADE, 0x82BE, 0xAAE8, 0x82C0, 0xCDB3, 0x82C2, 0xCDC2, 0x82C3, 0xCDC4, 0x82D1, 0xAD62, 0x82D2, 0xAD5C, 0x82D3, 0xAD64, 0x82D4, 0xAD61, 0x82D5, 0xD071, 0x82D6, 0xD074, 0x82D7, 0xAD5D, 0x82D9, 0xD06B, 0x82DB, 0xAD56, 0x82DC, 0xAD60, 0x82DE, 0xAD63, 0x82DF, 0xAD65, 0x82E0, 0xD0A2, 0x82E1, 0xD077, 0x82E3, 0xAD55, 0x82E4, 0xD0A1, 0x82E5, 0xAD59, 0x82E6, 0xAD57, 0x82E7, 0xAD52, 0x82E8, 0xD06F, 0x82EA, 0xD07E, 0x82EB, 0xD073, 0x82EC, 0xD076, 0x82ED, 0xD0A5, 0x82EF, 0xAD66, 0x82F0, 0xD07D, 0x82F1, 0xAD5E, 0x82F2, 0xD078, 0x82F3, 0xD0A4, 0x82F4, 0xD075, 0x82F5, 0xD079, 0x82F6, 0xD07C, 0x82F9, 0xD06D, 0x82FA, 0xD0A3, 0x82FB, 0xD07B, 0x82FE, 0xD06C, 0x8300, 0xD070, 0x8301, 0xAD5F, 0x8302, 0xAD5A, 0x8303, 0xAD53, 0x8304, 0xAD58, 0x8305, 0xAD54, 0x8306, 0xAD67, 0x8307, 0xD06E, 0x8308, 0xD3A5, 0x8309, 0xAD5B, 0x830C, 0xD07A, 0x830D, 0xCE41, 0x8316, 0xD3A8, 0x8317, 0xAFFA, 0x8319, 0xD376, 0x831B, 0xD3A3, 0x831C, 0xD37D, 0x831E, 0xD3B2, 0x8320, 0xD3AA, 0x8322, 0xD37E, 0x8324, 0xD3A9, 0x8325, 0xD378, 0x8326, 0xD37C, 0x8327, 0xD3B5, 0x8328, 0xAFFD, 0x8329, 0xD3AD, 0x832A, 0xD3A4, 0x832B, 0xAFED, 0x832C, 0xD3B3, 0x832D, 0xD374, 0x832F, 0xD3AC, 0x8331, 0xAFFC, 0x8332, 0xAFF7, 0x8333, 0xD373, 0x8334, 0xAFF5, 0x8335, 0xAFF4, 0x8336, 0xAFF9, 0x8337, 0xD3AB, 0x8338, 0xAFF1, 0x8339, 0xAFF8, 0x833A, 0xD072, 0x833B, 0xDB5C, 0x833C, 0xD3A6, 0x833F, 0xD37A, 0x8340, 0xAFFB, 0x8341, 0xD37B, 0x8342, 0xD3A1, 0x8343, 0xAFFE, 0x8344, 0xD375, 0x8345, 0xD3AF, 0x8347, 0xD3AE, 0x8348, 0xD3B6, 0x8349, 0xAFF3, 0x834A, 0xAFF0, 0x834B, 0xD3B4, 0x834C, 0xD3B0, 0x834D, 0xD3A7, 0x834E, 0xD3A2, 0x834F, 0xAFF6, 0x8350, 0xAFF2, 0x8351, 0xD377, 0x8352, 0xAFEE, 0x8353, 0xD3B1, 0x8354, 0xAFEF, 0x8356, 0xD379, 0x8373, 0xD75E, 0x8374, 0xD760, 0x8375, 0xD765, 0x8376, 0xD779, 0x8377, 0xB2FC, 0x8378, 0xB2F2, 0x837A, 0xD75D, 0x837B, 0xB2FD, 0x837C, 0xB2FE, 0x837D, 0xD768, 0x837E, 0xD76F, 0x837F, 0xD775, 0x8381, 0xD762, 0x8383, 0xD769, 0x8386, 0xB340, 0x8387, 0xD777, 0x8388, 0xD772, 0x8389, 0xB2FA, 0x838A, 0xB2F8, 0x838B, 0xD76E, 0x838C, 0xD76A, 0x838D, 0xD75C, 0x838E, 0xB2EF, 0x838F, 0xD761, 0x8390, 0xD759, 0x8392, 0xB2F7, 0x8393, 0xB2F9, 0x8394, 0xD766, 0x8395, 0xD763, 0x8396, 0xB2F4, 0x8397, 0xD773, 0x8398, 0xB2F1, 0x8399, 0xD764, 0x839A, 0xD77A, 0x839B, 0xD76C, 0x839D, 0xD76B, 0x839E, 0xB2F0, 0x83A0, 0xB2FB, 0x83A2, 0xB2F3, 0x83A3, 0xD75A, 0x83A4, 0xD75F, 0x83A5, 0xD770, 0x83A6, 0xD776, 0x83A7, 0xB341, 0x83A8, 0xD75B, 0x83A9, 0xD767, 0x83AA, 0xD76D, 0x83AB, 0xB2F6, 0x83AE, 0xD778, 0x83AF, 0xD771, 0x83B0, 0xD774, 0x83BD, 0xB2F5, 0x83BF, 0xDB6C, 0x83C0, 0xDB60, 0x83C1, 0xB5D7, 0x83C2, 0xDB7D, 0x83C3, 0xDBA7, 0x83C4, 0xDBAA, 0x83C5, 0xB5D5, 0x83C6, 0xDB68, 0x83C7, 0xDBA3, 0x83C8, 0xDB69, 0x83C9, 0xDB77, 0x83CA, 0xB5E2, 0x83CB, 0xDB73, 0x83CC, 0xB5DF, 0x83CE, 0xDB74, 0x83CF, 0xDB5D, 0x83D1, 0xDBA4, 0x83D4, 0xB5E8, 0x83D5, 0xDBA1, 0x83D6, 0xDB75, 0x83D7, 0xDBAC, 0x83D8, 0xDB70, 0x83D9, 0xDFC8, 0x83DB, 0xDBAF, 0x83DC, 0xB5E6, 0x83DD, 0xDB6E, 0x83DE, 0xDB7A, 0x83DF, 0xB5E9, 0x83E0, 0xB5D4, 0x83E1, 0xDB72, 0x83E2, 0xDBAD, 0x83E3, 0xDB6B, 0x83E4, 0xDB64, 0x83E5, 0xDB6F, 0x83E7, 0xDB63, 0x83E8, 0xDB61, 0x83E9, 0xB5D0, 0x83EA, 0xDBA5, 0x83EB, 0xDB6A, 0x83EC, 0xDBA8, 0x83EE, 0xDBA9, 0x83EF, 0xB5D8, 0x83F0, 0xB5DD, 0x83F1, 0xB5D9, 0x83F2, 0xB5E1, 0x83F3, 0xDB7E, 0x83F4, 0xB5DA, 0x83F5, 0xDB76, 0x83F6, 0xDB66, 0x83F8, 0xB5D2, 0x83F9, 0xDB5E, 0x83FA, 0xDBA2, 0x83FB, 0xDBAB, 0x83FC, 0xDB65, 0x83FD, 0xB5E0, 0x83FE, 0xDBB0, 0x83FF, 0xDB71, 0x8401, 0xDB6D, 0x8403, 0xB5D1, 0x8404, 0xB5E5, 0x8406, 0xDB7C, 0x8407, 0xB5E7, 0x8409, 0xDB78, 0x840A, 0xB5DC, 0x840B, 0xB5D6, 0x840C, 0xB5DE, 0x840D, 0xB5D3, 0x840E, 0xB5E4, 0x840F, 0xDB79, 0x8410, 0xDB67, 0x8411, 0xDB7B, 0x8412, 0xDB62, 0x8413, 0xDBA6, 0x841B, 0xDBAE, 0x8423, 0xDB5F, 0x8429, 0xDFC7, 0x842B, 0xDFDD, 0x842C, 0xB855, 0x842D, 0xDFCC, 0x842F, 0xDFCA, 0x8430, 0xDFB5, 0x8431, 0xB8A9, 0x8432, 0xDFC5, 0x8433, 0xDFD9, 0x8434, 0xDFC1, 0x8435, 0xB8B1, 0x8436, 0xDFD8, 0x8437, 0xDFBF, 0x8438, 0xB5E3, 0x8439, 0xDFCF, 0x843A, 0xDFC0, 0x843B, 0xDFD6, 0x843C, 0xB8B0, 0x843D, 0xB8A8, 0x843F, 0xDFAA, 0x8440, 0xDFB2, 0x8442, 0xDFCB, 0x8443, 0xDFC3, 0x8444, 0xDFDC, 0x8445, 0xDFC6, 0x8446, 0xB8B6, 0x8447, 0xDFD7, 0x8449, 0xB8AD, 0x844B, 0xDFC9, 0x844C, 0xDFD1, 0x844D, 0xDFB6, 0x844E, 0xDFD0, 0x8450, 0xDFE1, 0x8451, 0xDFB1, 0x8452, 0xDFD2, 0x8454, 0xDFDF, 0x8456, 0xDFAB, 0x8457, 0xB5DB, 0x8459, 0xDFB9, 0x845A, 0xDFB8, 0x845B, 0xB8AF, 0x845D, 0xDFBC, 0x845E, 0xDFBE, 0x845F, 0xDFCD, 0x8460, 0xDFDE, 0x8461, 0xB8B2, 0x8463, 0xB8B3, 0x8465, 0xDFB0, 0x8466, 0xB8AB, 0x8467, 0xDFB4, 0x8468, 0xDFDA, 0x8469, 0xB8B4, 0x846B, 0xB8AC, 0x846C, 0xB8AE, 0x846D, 0xB8B5, 0x846E, 0xDFE0, 0x846F, 0xDFD3, 0x8470, 0xDFCE, 0x8473, 0xDFBB, 0x8474, 0xDFBA, 0x8475, 0xB8AA, 0x8476, 0xDFAC, 0x8477, 0xB8A7, 0x8478, 0xDFC4, 0x8479, 0xDFAD, 0x847A, 0xDFC2, 0x847D, 0xDFB7, 0x847E, 0xDFDB, 0x8482, 0xB8A6, 0x8486, 0xDFB3, 0x848D, 0xDFAF, 0x848E, 0xDFD5, 0x848F, 0xDFAE, 0x8490, 0xBB60, 0x8491, 0xE3D3, 0x8494, 0xE3C2, 0x8497, 0xE3AC, 0x8498, 0xE3CA, 0x8499, 0xBB58, 0x849A, 0xE3BB, 0x849B, 0xE3C5, 0x849C, 0xBB5B, 0x849D, 0xE3BE, 0x849E, 0xBB59, 0x849F, 0xE3AF, 0x84A0, 0xE3CD, 0x84A1, 0xE3AE, 0x84A2, 0xE3C1, 0x84A4, 0xE3AD, 0x84A7, 0xE3BF, 0x84A8, 0xE3C8, 0x84A9, 0xE3C6, 0x84AA, 0xE3BA, 0x84AB, 0xE3B5, 0x84AC, 0xE3B3, 0x84AE, 0xE3B4, 0x84AF, 0xE3C7, 0x84B0, 0xE3D2, 0x84B1, 0xE3BC, 0x84B2, 0xBB5A, 0x84B4, 0xE3B7, 0x84B6, 0xE3CB, 0x84B8, 0xBB5D, 0x84B9, 0xE3B6, 0x84BA, 0xE3B0, 0x84BB, 0xE3C0, 0x84BC, 0xBB61, 0x84BF, 0xBB55, 0x84C0, 0xBB5E, 0x84C1, 0xE3B8, 0x84C2, 0xE3B2, 0x84C4, 0xBB57, 0x84C5, 0xDFD4, 0x84C6, 0xBB56, 0x84C7, 0xE3C3, 0x84C9, 0xBB54, 0x84CA, 0xBB63, 0x84CB, 0xBB5C, 0x84CC, 0xE3C4, 0x84CD, 0xE3B9, 0x84CE, 0xE3B1, 0x84CF, 0xE3CC, 0x84D0, 0xE3BD, 0x84D1, 0xBB62, 0x84D2, 0xE3D0, 0x84D3, 0xBB5F, 0x84D4, 0xE3CF, 0x84D6, 0xE3C9, 0x84D7, 0xE3CE, 0x84DB, 0xE3D1, 0x84E7, 0xE773, 0x84E8, 0xE774, 0x84E9, 0xE767, 0x84EA, 0xE766, 0x84EB, 0xE762, 0x84EC, 0xBDB4, 0x84EE, 0xBDAC, 0x84EF, 0xE776, 0x84F0, 0xE775, 0x84F1, 0xDFA9, 0x84F2, 0xE75F, 0x84F3, 0xE763, 0x84F4, 0xE75D, 0x84F6, 0xE770, 0x84F7, 0xE761, 0x84F9, 0xE777, 0x84FA, 0xE75A, 0x84FB, 0xE758, 0x84FC, 0xE764, 0x84FD, 0xE76E, 0x84FE, 0xE769, 0x84FF, 0xBDB6, 0x8500, 0xE74F, 0x8502, 0xE76D, 0x8506, 0xBDB7, 0x8507, 0xDFBD, 0x8508, 0xE75B, 0x8509, 0xE752, 0x850A, 0xE755, 0x850B, 0xE77B, 0x850C, 0xE75C, 0x850D, 0xE753, 0x850E, 0xE751, 0x850F, 0xE74E, 0x8511, 0xBDB0, 0x8512, 0xE765, 0x8513, 0xBDAF, 0x8514, 0xBDB3, 0x8515, 0xE760, 0x8516, 0xE768, 0x8517, 0xBDA9, 0x8518, 0xE778, 0x8519, 0xE77C, 0x851A, 0xBDAB, 0x851C, 0xE757, 0x851D, 0xE76B, 0x851E, 0xE76F, 0x851F, 0xE754, 0x8520, 0xE779, 0x8521, 0xBDB2, 0x8523, 0xBDB1, 0x8524, 0xE74C, 0x8525, 0xBDB5, 0x8526, 0xE772, 0x8527, 0xE756, 0x8528, 0xE76A, 0x8529, 0xE750, 0x852A, 0xE75E, 0x852B, 0xE759, 0x852C, 0xBDAD, 0x852D, 0xBDAE, 0x852E, 0xE76C, 0x852F, 0xE77D, 0x8530, 0xE77A, 0x8531, 0xE771, 0x853B, 0xE74D, 0x853D, 0xBDAA, 0x853E, 0xEB49, 0x8540, 0xEB40, 0x8541, 0xEB43, 0x8543, 0xBFBB, 0x8544, 0xEB45, 0x8545, 0xEAF9, 0x8546, 0xEB41, 0x8547, 0xEB47, 0x8548, 0xBFB8, 0x8549, 0xBFBC, 0x854A, 0xBFB6, 0x854D, 0xEAFB, 0x854E, 0xEB4C, 0x8551, 0xEB46, 0x8553, 0xEAFC, 0x8554, 0xEB55, 0x8555, 0xEB4F, 0x8556, 0xEAF8, 0x8557, 0xEE46, 0x8558, 0xEAFE, 0x8559, 0xBFB7, 0x855B, 0xEB4A, 0x855D, 0xEB54, 0x855E, 0xBFBF, 0x8560, 0xEB51, 0x8561, 0xEAFD, 0x8562, 0xEB44, 0x8563, 0xEB48, 0x8564, 0xEB42, 0x8565, 0xEB56, 0x8566, 0xEB53, 0x8567, 0xEB50, 0x8568, 0xBFB9, 0x8569, 0xBFBA, 0x856A, 0xBFBE, 0x856B, 0xEAFA, 0x856C, 0xEB57, 0x856D, 0xBFBD, 0x856E, 0xEB4D, 0x8571, 0xEB4B, 0x8575, 0xEB4E, 0x8576, 0xEE53, 0x8577, 0xEE40, 0x8578, 0xEE45, 0x8579, 0xEE52, 0x857A, 0xEE44, 0x857B, 0xEDFB, 0x857C, 0xEE41, 0x857E, 0xC1A2, 0x8580, 0xEDF4, 0x8581, 0xEE4D, 0x8582, 0xEE4F, 0x8583, 0xEDF3, 0x8584, 0xC1A1, 0x8585, 0xEE51, 0x8586, 0xEE49, 0x8587, 0xC1A8, 0x8588, 0xEE50, 0x8589, 0xEE42, 0x858A, 0xC1AA, 0x858B, 0xEDF9, 0x858C, 0xEB52, 0x858D, 0xEE4A, 0x858E, 0xEE47, 0x858F, 0xEDF5, 0x8590, 0xEE55, 0x8591, 0xC1A4, 0x8594, 0xC1A5, 0x8595, 0xEDF7, 0x8596, 0xEE48, 0x8598, 0xEE54, 0x8599, 0xEE4B, 0x859A, 0xEDFD, 0x859B, 0xC1A7, 0x859C, 0xC1A3, 0x859D, 0xEE4C, 0x859E, 0xEDFE, 0x859F, 0xEE56, 0x85A0, 0xEDF8, 0x85A1, 0xEE43, 0x85A2, 0xEE4E, 0x85A3, 0xEDFA, 0x85A4, 0xEDFC, 0x85A6, 0xC2CB, 0x85A7, 0xEDF6, 0x85A8, 0xC1A9, 0x85A9, 0xC2C4, 0x85AA, 0xC17E, 0x85AF, 0xC1A6, 0x85B0, 0xC2C8, 0x85B1, 0xF0B3, 0x85B3, 0xF0A9, 0x85B4, 0xF0A4, 0x85B5, 0xF0AA, 0x85B6, 0xF0B4, 0x85B7, 0xF0B8, 0x85B8, 0xF0B7, 0x85B9, 0xC2CA, 0x85BA, 0xC2C9, 0x85BD, 0xF0AB, 0x85BE, 0xF0B9, 0x85BF, 0xF0AE, 0x85C0, 0xF0A6, 0x85C2, 0xF0A8, 0x85C3, 0xF0A7, 0x85C4, 0xF0AD, 0x85C5, 0xF0B2, 0x85C6, 0xF0A5, 0x85C7, 0xF0AC, 0x85C8, 0xF0B1, 0x85C9, 0xC2C7, 0x85CB, 0xF0AF, 0x85CD, 0xC2C5, 0x85CE, 0xF0B0, 0x85CF, 0xC2C3, 0x85D0, 0xC2C6, 0x85D1, 0xF2D5, 0x85D2, 0xF0B5, 0x85D5, 0xC3C2, 0x85D7, 0xF2CD, 0x85D8, 0xF2D1, 0x85D9, 0xF2C9, 0x85DA, 0xF2CC, 0x85DC, 0xF2D4, 0x85DD, 0xC3C0, 0x85DE, 0xF2D9, 0x85DF, 0xF2D2, 0x85E1, 0xF2CA, 0x85E2, 0xF2DA, 0x85E3, 0xF2D3, 0x85E4, 0xC3C3, 0x85E5, 0xC3C4, 0x85E6, 0xF2D7, 0x85E8, 0xF2CB, 0x85E9, 0xC3BF, 0x85EA, 0xC3C1, 0x85EB, 0xF2C6, 0x85EC, 0xF2CE, 0x85ED, 0xF2C8, 0x85EF, 0xF2D8, 0x85F0, 0xF2D6, 0x85F1, 0xF2C7, 0x85F2, 0xF2CF, 0x85F6, 0xF4BE, 0x85F7, 0xC3C5, 0x85F8, 0xF2D0, 0x85F9, 0xC4A7, 0x85FA, 0xC4A9, 0x85FB, 0xC4A6, 0x85FD, 0xF4C3, 0x85FE, 0xF4BB, 0x85FF, 0xF4B9, 0x8600, 0xF4BD, 0x8601, 0xF4BA, 0x8604, 0xF4BF, 0x8605, 0xF4C1, 0x8606, 0xC4AA, 0x8607, 0xC4AC, 0x8609, 0xF4C0, 0x860A, 0xC4AD, 0x860B, 0xC4AB, 0x860C, 0xF4C2, 0x8611, 0xC4A8, 0x8617, 0xC4F4, 0x8618, 0xF5F1, 0x8619, 0xF5F7, 0x861A, 0xC4F6, 0x861B, 0xF4BC, 0x861C, 0xF5F6, 0x861E, 0xF5FD, 0x861F, 0xF5F4, 0x8620, 0xF5FB, 0x8621, 0xF5FA, 0x8622, 0xF4B8, 0x8623, 0xF5F5, 0x8624, 0xF0B6, 0x8625, 0xF5FE, 0x8626, 0xF5F3, 0x8627, 0xF5F8, 0x8629, 0xF5FC, 0x862A, 0xF5F2, 0x862C, 0xF74A, 0x862D, 0xC4F5, 0x862E, 0xF5F9, 0x8631, 0xF7F4, 0x8632, 0xF74B, 0x8633, 0xF749, 0x8634, 0xF747, 0x8635, 0xF748, 0x8636, 0xF74C, 0x8638, 0xC5D9, 0x8639, 0xF7F2, 0x863A, 0xF7F0, 0x863B, 0xF7F5, 0x863C, 0xF7F3, 0x863E, 0xF7F6, 0x863F, 0xC5DA, 0x8640, 0xF7F1, 0x8643, 0xF8BC, 0x8646, 0xF945, 0x8647, 0xF946, 0x8648, 0xF947, 0x864B, 0xF9C7, 0x864C, 0xF9BD, 0x864D, 0xCA4F, 0x864E, 0xAAEA, 0x8650, 0xAD68, 0x8652, 0xD3B8, 0x8653, 0xD3B7, 0x8654, 0xB040, 0x8655, 0xB342, 0x8656, 0xD77C, 0x8659, 0xD77B, 0x865B, 0xB5EA, 0x865C, 0xB8B8, 0x865E, 0xB8B7, 0x865F, 0xB8B9, 0x8661, 0xE3D4, 0x8662, 0xE77E, 0x8663, 0xEB58, 0x8664, 0xEB5A, 0x8665, 0xEB59, 0x8667, 0xC1AB, 0x8668, 0xEE57, 0x8669, 0xF0BA, 0x866A, 0xF9A5, 0x866B, 0xA6E4, 0x866D, 0xCDC9, 0x866E, 0xCDCA, 0x866F, 0xCDC8, 0x8670, 0xCDC7, 0x8671, 0xAAEB, 0x8673, 0xD0A9, 0x8674, 0xD0A7, 0x8677, 0xD0A6, 0x8679, 0xAD69, 0x867A, 0xAD6B, 0x867B, 0xAD6A, 0x867C, 0xD0A8, 0x8685, 0xD3C4, 0x8686, 0xD3C1, 0x8687, 0xD3BF, 0x868A, 0xB041, 0x868B, 0xD3C2, 0x868C, 0xB046, 0x868D, 0xD3BC, 0x868E, 0xD3CB, 0x8690, 0xD3CD, 0x8691, 0xD3BD, 0x8693, 0xB043, 0x8694, 0xD3CE, 0x8695, 0xD3C9, 0x8696, 0xD3BB, 0x8697, 0xD3C0, 0x8698, 0xD3CA, 0x8699, 0xD3C6, 0x869A, 0xD3C3, 0x869C, 0xB048, 0x869D, 0xD3CC, 0x869E, 0xD3BE, 0x86A1, 0xD3C7, 0x86A2, 0xD3B9, 0x86A3, 0xB047, 0x86A4, 0xB044, 0x86A5, 0xD3C5, 0x86A7, 0xD3C8, 0x86A8, 0xD3BA, 0x86A9, 0xB045, 0x86AA, 0xB042, 0x86AF, 0xB34C, 0x86B0, 0xD7A5, 0x86B1, 0xB34B, 0x86B3, 0xD7A8, 0x86B4, 0xD7AB, 0x86B5, 0xB348, 0x86B6, 0xB346, 0x86B7, 0xD77E, 0x86B8, 0xD7A9, 0x86B9, 0xD7A7, 0x86BA, 0xD7A4, 0x86BB, 0xD7AC, 0x86BC, 0xD7AD, 0x86BD, 0xD7AF, 0x86BE, 0xD7B0, 0x86BF, 0xD77D, 0x86C0, 0xB345, 0x86C1, 0xD7A2, 0x86C2, 0xD7A1, 0x86C3, 0xD7AE, 0x86C4, 0xB347, 0x86C5, 0xD7A3, 0x86C6, 0xB349, 0x86C7, 0xB344, 0x86C8, 0xD7A6, 0x86C9, 0xB34D, 0x86CB, 0xB34A, 0x86CC, 0xD7AA, 0x86D0, 0xB5F1, 0x86D1, 0xDBBF, 0x86D3, 0xDBB4, 0x86D4, 0xB5EE, 0x86D6, 0xDFE7, 0x86D7, 0xDBBD, 0x86D8, 0xDBB1, 0x86D9, 0xB5EC, 0x86DA, 0xDBB6, 0x86DB, 0xB5EF, 0x86DC, 0xDBBA, 0x86DD, 0xDBB8, 0x86DE, 0xB5F2, 0x86DF, 0xB5EB, 0x86E2, 0xDBB2, 0x86E3, 0xDBB5, 0x86E4, 0xB5F0, 0x86E6, 0xDBB3, 0x86E8, 0xDBBE, 0x86E9, 0xDBBC, 0x86EA, 0xDBB7, 0x86EB, 0xDBB9, 0x86EC, 0xDBBB, 0x86ED, 0xB5ED, 0x86F5, 0xDFE8, 0x86F6, 0xDFEE, 0x86F7, 0xDFE4, 0x86F8, 0xDFEA, 0x86F9, 0xB8BA, 0x86FA, 0xDFE6, 0x86FB, 0xB8C0, 0x86FE, 0xB8BF, 0x8700, 0xB8BE, 0x8701, 0xDFED, 0x8702, 0xB8C1, 0x8703, 0xB8C2, 0x8704, 0xDFE3, 0x8705, 0xDFF0, 0x8706, 0xB8C3, 0x8707, 0xB8BD, 0x8708, 0xB8BC, 0x8709, 0xDFEC, 0x870A, 0xB8C4, 0x870B, 0xDFE2, 0x870C, 0xDFE5, 0x870D, 0xDFEF, 0x870E, 0xDFEB, 0x8711, 0xE3F4, 0x8712, 0xE3E9, 0x8713, 0xB8BB, 0x8718, 0xBB6A, 0x8719, 0xE3DD, 0x871A, 0xE3F2, 0x871B, 0xE3DE, 0x871C, 0xBB65, 0x871E, 0xE3DB, 0x8720, 0xE3E4, 0x8721, 0xE3DC, 0x8722, 0xBB67, 0x8723, 0xE3D6, 0x8724, 0xE3F1, 0x8725, 0xBB68, 0x8726, 0xE3EE, 0x8727, 0xE3EF, 0x8728, 0xE3D7, 0x8729, 0xBB6D, 0x872A, 0xE3E6, 0x872C, 0xE3E0, 0x872D, 0xE3E7, 0x872E, 0xE3DA, 0x8730, 0xE3F3, 0x8731, 0xE3EB, 0x8732, 0xE3E5, 0x8733, 0xE3D5, 0x8734, 0xBB69, 0x8735, 0xE3EC, 0x8737, 0xBB6C, 0x8738, 0xE3F0, 0x873A, 0xE3EA, 0x873B, 0xBB66, 0x873C, 0xE3E8, 0x873E, 0xE3E2, 0x873F, 0xBB64, 0x8740, 0xE3D9, 0x8741, 0xE3E1, 0x8742, 0xE3ED, 0x8743, 0xE3DF, 0x8746, 0xE3E3, 0x874C, 0xBDC1, 0x874D, 0xDFE9, 0x874E, 0xE7B2, 0x874F, 0xE7BB, 0x8750, 0xE7B1, 0x8751, 0xE7AD, 0x8752, 0xE7AA, 0x8753, 0xBDC2, 0x8754, 0xE7A8, 0x8755, 0xBB6B, 0x8756, 0xE7A1, 0x8757, 0xBDC0, 0x8758, 0xE7A7, 0x8759, 0xBDBF, 0x875A, 0xE7AC, 0x875B, 0xE7A9, 0x875C, 0xE7B9, 0x875D, 0xE7B4, 0x875E, 0xE7AE, 0x875F, 0xE7B3, 0x8760, 0xBDBB, 0x8761, 0xE7AB, 0x8762, 0xE7BE, 0x8763, 0xE7A2, 0x8764, 0xE7A3, 0x8765, 0xE7BA, 0x8766, 0xBDBC, 0x8767, 0xE7BF, 0x8768, 0xBDBE, 0x8769, 0xE7C0, 0x876A, 0xE7B0, 0x876B, 0xE3D8, 0x876C, 0xE7B6, 0x876D, 0xE7AF, 0x876E, 0xE7B8, 0x876F, 0xE7B5, 0x8773, 0xE7A6, 0x8774, 0xBDB9, 0x8775, 0xE7BD, 0x8776, 0xBDBA, 0x8777, 0xE7A4, 0x8778, 0xBDBD, 0x8779, 0xEB64, 0x877A, 0xE7B7, 0x877B, 0xE7BC, 0x8781, 0xEB61, 0x8782, 0xBDB8, 0x8783, 0xBFC0, 0x8784, 0xEB6B, 0x8785, 0xEB67, 0x8787, 0xEB65, 0x8788, 0xEB60, 0x8789, 0xEB6F, 0x878D, 0xBFC4, 0x878F, 0xEB5C, 0x8790, 0xEB68, 0x8791, 0xEB69, 0x8792, 0xEB5F, 0x8793, 0xEB5E, 0x8794, 0xEB6C, 0x8796, 0xEB62, 0x8797, 0xEB5D, 0x8798, 0xEB63, 0x879A, 0xEB6E, 0x879B, 0xEB5B, 0x879C, 0xEB6D, 0x879D, 0xEB6A, 0x879E, 0xBFC2, 0x879F, 0xBFC1, 0x87A2, 0xBFC3, 0x87A3, 0xEB66, 0x87A4, 0xF0CB, 0x87AA, 0xEE59, 0x87AB, 0xC1B1, 0x87AC, 0xEE5D, 0x87AD, 0xEE5A, 0x87AE, 0xEE61, 0x87AF, 0xEE67, 0x87B0, 0xEE5C, 0x87B2, 0xEE70, 0x87B3, 0xC1AE, 0x87B4, 0xEE6A, 0x87B5, 0xEE5F, 0x87B6, 0xEE6B, 0x87B7, 0xEE66, 0x87B8, 0xEE6D, 0x87B9, 0xEE5E, 0x87BA, 0xC1B3, 0x87BB, 0xC1B2, 0x87BC, 0xEE60, 0x87BD, 0xEE6E, 0x87BE, 0xEE58, 0x87BF, 0xEE6C, 0x87C0, 0xC1AC, 0x87C2, 0xEE64, 0x87C3, 0xEE63, 0x87C4, 0xEE68, 0x87C5, 0xEE5B, 0x87C6, 0xC1B0, 0x87C8, 0xC1B4, 0x87C9, 0xEE62, 0x87CA, 0xEE69, 0x87CB, 0xC1B5, 0x87CC, 0xEE65, 0x87D1, 0xC1AD, 0x87D2, 0xC1AF, 0x87D3, 0xF0C7, 0x87D4, 0xF0C5, 0x87D7, 0xF0CC, 0x87D8, 0xF0C9, 0x87D9, 0xF0CD, 0x87DB, 0xF0BE, 0x87DC, 0xF0C6, 0x87DD, 0xF0D1, 0x87DE, 0xEE6F, 0x87DF, 0xF0C2, 0x87E0, 0xC2CF, 0x87E1, 0xE7A5, 0x87E2, 0xF0BD, 0x87E3, 0xF0CA, 0x87E4, 0xF0C4, 0x87E5, 0xF0C1, 0x87E6, 0xF0BC, 0x87E7, 0xF0BB, 0x87E8, 0xF0D0, 0x87EA, 0xF0C0, 0x87EB, 0xF0BF, 0x87EC, 0xC2CD, 0x87ED, 0xF0C8, 0x87EF, 0xC2CC, 0x87F2, 0xC2CE, 0x87F3, 0xF0C3, 0x87F4, 0xF0CF, 0x87F6, 0xF2DE, 0x87F7, 0xF2DF, 0x87F9, 0xC3C9, 0x87FA, 0xF2DC, 0x87FB, 0xC3C6, 0x87FC, 0xF2E4, 0x87FE, 0xC3CA, 0x87FF, 0xF2E6, 0x8800, 0xF2DB, 0x8801, 0xF0CE, 0x8802, 0xF2E8, 0x8803, 0xF2DD, 0x8805, 0xC3C7, 0x8806, 0xF2E3, 0x8808, 0xF2E5, 0x8809, 0xF2E0, 0x880A, 0xF2E7, 0x880B, 0xF2E2, 0x880C, 0xF2E1, 0x880D, 0xC3C8, 0x8810, 0xF4C5, 0x8811, 0xF4C6, 0x8813, 0xF4C8, 0x8814, 0xC4AE, 0x8815, 0xC4AF, 0x8816, 0xF4C9, 0x8817, 0xF4C7, 0x8819, 0xF4C4, 0x881B, 0xF642, 0x881C, 0xF645, 0x881D, 0xF641, 0x881F, 0xC4FA, 0x8820, 0xF643, 0x8821, 0xC4F9, 0x8822, 0xC4F8, 0x8823, 0xC4F7, 0x8824, 0xF644, 0x8825, 0xF751, 0x8826, 0xF74F, 0x8828, 0xF74E, 0x8829, 0xF640, 0x882A, 0xF750, 0x882B, 0xF646, 0x882C, 0xF74D, 0x882E, 0xF7F9, 0x882F, 0xF7D7, 0x8830, 0xF7F7, 0x8831, 0xC5DB, 0x8832, 0xF7F8, 0x8833, 0xF7FA, 0x8835, 0xF8BF, 0x8836, 0xC5FA, 0x8837, 0xF8BE, 0x8838, 0xF8BD, 0x8839, 0xC5FB, 0x883B, 0xC65A, 0x883C, 0xF96E, 0x883D, 0xF9A7, 0x883E, 0xF9A6, 0x883F, 0xF9A8, 0x8840, 0xA6E5, 0x8841, 0xD0AA, 0x8843, 0xD3CF, 0x8844, 0xD3D0, 0x8848, 0xDBC0, 0x884A, 0xF647, 0x884B, 0xF8C0, 0x884C, 0xA6E6, 0x884D, 0xAD6C, 0x884E, 0xD0AB, 0x8852, 0xD7B1, 0x8853, 0xB34E, 0x8855, 0xDBC2, 0x8856, 0xDBC1, 0x8857, 0xB5F3, 0x8859, 0xB8C5, 0x885A, 0xE7C1, 0x885B, 0xBDC3, 0x885D, 0xBDC4, 0x8861, 0xBFC5, 0x8862, 0xC5FC, 0x8863, 0xA6E7, 0x8867, 0xD0AC, 0x8868, 0xAAED, 0x8869, 0xD0AE, 0x886A, 0xD0AD, 0x886B, 0xAD6D, 0x886D, 0xD3D1, 0x886F, 0xD3D8, 0x8870, 0xB049, 0x8871, 0xD3D6, 0x8872, 0xD3D4, 0x8874, 0xD3DB, 0x8875, 0xD3D2, 0x8876, 0xD3D3, 0x8877, 0xB04A, 0x8879, 0xB04E, 0x887C, 0xD3DC, 0x887D, 0xB04D, 0x887E, 0xD3DA, 0x887F, 0xD3D7, 0x8880, 0xD3D5, 0x8881, 0xB04B, 0x8882, 0xB04C, 0x8883, 0xD3D9, 0x8888, 0xB350, 0x8889, 0xD7B2, 0x888B, 0xB355, 0x888C, 0xD7C2, 0x888D, 0xB354, 0x888E, 0xD7C4, 0x8891, 0xD7B8, 0x8892, 0xB352, 0x8893, 0xD7C3, 0x8895, 0xD7B3, 0x8896, 0xB353, 0x8897, 0xD7BF, 0x8898, 0xD7BB, 0x8899, 0xD7BD, 0x889A, 0xD7B7, 0x889B, 0xD7BE, 0x889E, 0xB34F, 0x889F, 0xD7BA, 0x88A1, 0xD7B9, 0x88A2, 0xD7B5, 0x88A4, 0xD7C0, 0x88A7, 0xD7BC, 0x88A8, 0xD7B4, 0x88AA, 0xD7B6, 0x88AB, 0xB351, 0x88AC, 0xD7C1, 0x88B1, 0xB5F6, 0x88B2, 0xDBCD, 0x88B6, 0xDBC9, 0x88B7, 0xDBCB, 0x88B8, 0xDBC6, 0x88B9, 0xDBC5, 0x88BA, 0xDBC3, 0x88BC, 0xDBCA, 0x88BD, 0xDBCC, 0x88BE, 0xDBC8, 0x88C0, 0xDBC7, 0x88C1, 0xB5F4, 0x88C2, 0xB5F5, 0x88C9, 0xDBCF, 0x88CA, 0xB8CD, 0x88CB, 0xDFF2, 0x88CC, 0xDFF8, 0x88CD, 0xDFF3, 0x88CE, 0xDFF4, 0x88CF, 0xF9D8, 0x88D0, 0xDFF9, 0x88D2, 0xB8CF, 0x88D4, 0xB8C7, 0x88D5, 0xB8CE, 0x88D6, 0xDFF1, 0x88D7, 0xDBC4, 0x88D8, 0xB8CA, 0x88D9, 0xB8C8, 0x88DA, 0xDFF7, 0x88DB, 0xDFF6, 0x88DC, 0xB8C9, 0x88DD, 0xB8CB, 0x88DE, 0xDFF5, 0x88DF, 0xB8C6, 0x88E1, 0xB8CC, 0x88E7, 0xE3F6, 0x88E8, 0xBB74, 0x88EB, 0xE442, 0x88EC, 0xE441, 0x88EE, 0xE3FB, 0x88EF, 0xBB76, 0x88F0, 0xE440, 0x88F1, 0xE3F7, 0x88F2, 0xE3F8, 0x88F3, 0xBB6E, 0x88F4, 0xBB70, 0x88F6, 0xE3FD, 0x88F7, 0xE3F5, 0x88F8, 0xBB72, 0x88F9, 0xBB71, 0x88FA, 0xE3F9, 0x88FB, 0xE3FE, 0x88FC, 0xE3FC, 0x88FD, 0xBB73, 0x88FE, 0xE3FA, 0x8901, 0xDBCE, 0x8902, 0xBB6F, 0x8905, 0xE7C2, 0x8906, 0xE7C9, 0x8907, 0xBDC6, 0x8909, 0xE7CD, 0x890A, 0xBDCA, 0x890B, 0xE7C5, 0x890C, 0xE7C3, 0x890E, 0xE7CC, 0x8910, 0xBDC5, 0x8911, 0xE7CB, 0x8912, 0xBDC7, 0x8913, 0xBDC8, 0x8914, 0xE7C4, 0x8915, 0xBDC9, 0x8916, 0xE7CA, 0x8917, 0xE7C6, 0x8918, 0xE7C7, 0x8919, 0xE7C8, 0x891A, 0xBB75, 0x891E, 0xEB70, 0x891F, 0xEB7C, 0x8921, 0xBFCA, 0x8922, 0xEB77, 0x8923, 0xEB79, 0x8925, 0xBFC8, 0x8926, 0xEB71, 0x8927, 0xEB75, 0x8929, 0xEB78, 0x892A, 0xBFC6, 0x892B, 0xBFC9, 0x892C, 0xEB7B, 0x892D, 0xEB73, 0x892E, 0xEB74, 0x892F, 0xEB7A, 0x8930, 0xEB72, 0x8931, 0xEB76, 0x8932, 0xBFC7, 0x8933, 0xEE72, 0x8935, 0xEE71, 0x8936, 0xC1B7, 0x8937, 0xEE77, 0x8938, 0xC1B9, 0x893B, 0xC1B6, 0x893C, 0xEE73, 0x893D, 0xC1BA, 0x893E, 0xEE74, 0x8941, 0xEE75, 0x8942, 0xEE78, 0x8944, 0xC1B8, 0x8946, 0xF0D6, 0x8949, 0xF0D9, 0x894B, 0xF0D3, 0x894C, 0xF0D5, 0x894F, 0xF0D4, 0x8950, 0xF0D7, 0x8951, 0xF0D8, 0x8952, 0xEE76, 0x8953, 0xF0D2, 0x8956, 0xC3CD, 0x8957, 0xF2EC, 0x8958, 0xF2EF, 0x8959, 0xF2F1, 0x895A, 0xF2EA, 0x895B, 0xF2EB, 0x895C, 0xF2EE, 0x895D, 0xF2F0, 0x895E, 0xC3CE, 0x895F, 0xC3CC, 0x8960, 0xC3CB, 0x8961, 0xF2ED, 0x8962, 0xF2E9, 0x8963, 0xF4CA, 0x8964, 0xC4B0, 0x8966, 0xF4CB, 0x8969, 0xF649, 0x896A, 0xC4FB, 0x896B, 0xF64B, 0x896C, 0xC4FC, 0x896D, 0xF648, 0x896E, 0xF64A, 0x896F, 0xC5A8, 0x8971, 0xF752, 0x8972, 0xC5A7, 0x8973, 0xF7FD, 0x8974, 0xF7FC, 0x8976, 0xF7FB, 0x8979, 0xF948, 0x897A, 0xF949, 0x897B, 0xF94B, 0x897C, 0xF94A, 0x897E, 0xCA50, 0x897F, 0xA6E8, 0x8981, 0xAD6E, 0x8982, 0xD7C5, 0x8983, 0xB5F7, 0x8985, 0xDFFA, 0x8986, 0xC2D0, 0x8988, 0xF2F2, 0x898B, 0xA8A3, 0x898F, 0xB357, 0x8993, 0xB356, 0x8995, 0xDBD0, 0x8996, 0xB5F8, 0x8997, 0xDBD2, 0x8998, 0xDBD1, 0x899B, 0xDFFB, 0x899C, 0xB8D0, 0x899D, 0xE443, 0x899E, 0xE446, 0x899F, 0xE445, 0x89A1, 0xE444, 0x89A2, 0xE7CE, 0x89A3, 0xE7D0, 0x89A4, 0xE7CF, 0x89A6, 0xBFCC, 0x89AA, 0xBFCB, 0x89AC, 0xC1BB, 0x89AD, 0xEE79, 0x89AE, 0xEE7B, 0x89AF, 0xEE7A, 0x89B2, 0xC2D1, 0x89B6, 0xF2F4, 0x89B7, 0xF2F3, 0x89B9, 0xF4CC, 0x89BA, 0xC4B1, 0x89BD, 0xC4FD, 0x89BE, 0xF754, 0x89BF, 0xF753, 0x89C0, 0xC65B, 0x89D2, 0xA8A4, 0x89D3, 0xD0AF, 0x89D4, 0xAD6F, 0x89D5, 0xD7C8, 0x89D6, 0xD7C6, 0x89D9, 0xD7C7, 0x89DA, 0xDBD4, 0x89DB, 0xDBD5, 0x89DC, 0xE043, 0x89DD, 0xDBD3, 0x89DF, 0xDFFC, 0x89E0, 0xE041, 0x89E1, 0xE040, 0x89E2, 0xE042, 0x89E3, 0xB8D1, 0x89E4, 0xDFFE, 0x89E5, 0xDFFD, 0x89E6, 0xE044, 0x89E8, 0xE449, 0x89E9, 0xE447, 0x89EB, 0xE448, 0x89EC, 0xE7D3, 0x89ED, 0xE7D1, 0x89F0, 0xE7D2, 0x89F1, 0xEB7D, 0x89F2, 0xEE7C, 0x89F3, 0xEE7D, 0x89F4, 0xC2D2, 0x89F6, 0xF2F5, 0x89F7, 0xF4CD, 0x89F8, 0xC4B2, 0x89FA, 0xF64C, 0x89FB, 0xF755, 0x89FC, 0xC5A9, 0x89FE, 0xF7FE, 0x89FF, 0xF94C, 0x8A00, 0xA8A5, 0x8A02, 0xAD71, 0x8A03, 0xAD72, 0x8A04, 0xD0B0, 0x8A07, 0xD0B1, 0x8A08, 0xAD70, 0x8A0A, 0xB054, 0x8A0C, 0xB052, 0x8A0E, 0xB051, 0x8A0F, 0xB058, 0x8A10, 0xB050, 0x8A11, 0xB059, 0x8A12, 0xD3DD, 0x8A13, 0xB056, 0x8A15, 0xB053, 0x8A16, 0xB057, 0x8A17, 0xB055, 0x8A18, 0xB04F, 0x8A1B, 0xB35F, 0x8A1D, 0xB359, 0x8A1E, 0xD7CC, 0x8A1F, 0xB35E, 0x8A22, 0xB360, 0x8A23, 0xB35A, 0x8A25, 0xB35B, 0x8A27, 0xD7CA, 0x8A2A, 0xB358, 0x8A2C, 0xD7CB, 0x8A2D, 0xB35D, 0x8A30, 0xD7C9, 0x8A31, 0xB35C, 0x8A34, 0xB644, 0x8A36, 0xB646, 0x8A39, 0xDBD8, 0x8A3A, 0xB645, 0x8A3B, 0xB5F9, 0x8A3C, 0xB5FD, 0x8A3E, 0xB8E4, 0x8A3F, 0xE049, 0x8A40, 0xDBDA, 0x8A41, 0xB5FE, 0x8A44, 0xDBDD, 0x8A45, 0xDBDE, 0x8A46, 0xB643, 0x8A48, 0xDBE0, 0x8A4A, 0xDBE2, 0x8A4C, 0xDBE3, 0x8A4D, 0xDBD7, 0x8A4E, 0xDBD6, 0x8A4F, 0xDBE4, 0x8A50, 0xB642, 0x8A51, 0xDBE1, 0x8A52, 0xDBDF, 0x8A54, 0xB640, 0x8A55, 0xB5FB, 0x8A56, 0xB647, 0x8A57, 0xDBDB, 0x8A58, 0xDBDC, 0x8A59, 0xDBD9, 0x8A5B, 0xB641, 0x8A5E, 0xB5FC, 0x8A60, 0xB5FA, 0x8A61, 0xE048, 0x8A62, 0xB8DF, 0x8A63, 0xB8DA, 0x8A66, 0xB8D5, 0x8A68, 0xB8E5, 0x8A69, 0xB8D6, 0x8A6B, 0xB8D2, 0x8A6C, 0xB8E1, 0x8A6D, 0xB8DE, 0x8A6E, 0xB8E0, 0x8A70, 0xB8D7, 0x8A71, 0xB8DC, 0x8A72, 0xB8D3, 0x8A73, 0xB8D4, 0x8A74, 0xE050, 0x8A75, 0xE04D, 0x8A76, 0xE045, 0x8A77, 0xE04A, 0x8A79, 0xB8E2, 0x8A7A, 0xE051, 0x8A7B, 0xB8E3, 0x8A7C, 0xB8D9, 0x8A7F, 0xE047, 0x8A81, 0xE04F, 0x8A82, 0xE04B, 0x8A83, 0xE04E, 0x8A84, 0xE04C, 0x8A85, 0xB8DD, 0x8A86, 0xE046, 0x8A87, 0xB8D8, 0x8A8B, 0xE44C, 0x8A8C, 0xBB78, 0x8A8D, 0xBB7B, 0x8A8F, 0xE44E, 0x8A91, 0xBBA5, 0x8A92, 0xE44D, 0x8A93, 0xBB7D, 0x8A95, 0xBDCF, 0x8A96, 0xE44F, 0x8A98, 0xBBA4, 0x8A99, 0xE44B, 0x8A9A, 0xBBA6, 0x8A9E, 0xBB79, 0x8AA0, 0xB8DB, 0x8AA1, 0xBB7C, 0x8AA3, 0xBB7A, 0x8AA4, 0xBB7E, 0x8AA5, 0xBBA2, 0x8AA6, 0xBB77, 0x8AA7, 0xBBA7, 0x8AA8, 0xBBA3, 0x8AAA, 0xBBA1, 0x8AAB, 0xE44A, 0x8AB0, 0xBDD6, 0x8AB2, 0xBDD2, 0x8AB6, 0xBDD9, 0x8AB8, 0xE7D6, 0x8AB9, 0xBDDA, 0x8ABA, 0xE7E2, 0x8ABB, 0xE7DB, 0x8ABC, 0xBDCB, 0x8ABD, 0xE7E3, 0x8ABE, 0xE7DD, 0x8ABF, 0xBDD5, 0x8AC0, 0xE7DE, 0x8AC2, 0xBDD4, 0x8AC3, 0xE7E1, 0x8AC4, 0xBDCE, 0x8AC5, 0xE7DF, 0x8AC6, 0xE7D5, 0x8AC7, 0xBDCD, 0x8AC8, 0xEBAA, 0x8AC9, 0xBDD3, 0x8ACB, 0xBDD0, 0x8ACD, 0xBDD8, 0x8ACF, 0xE7D4, 0x8AD1, 0xE7D8, 0x8AD2, 0xBDCC, 0x8AD3, 0xE7D7, 0x8AD4, 0xE7D9, 0x8AD5, 0xE7DA, 0x8AD6, 0xBDD7, 0x8AD7, 0xE7DC, 0x8AD8, 0xE7E0, 0x8AD9, 0xE7E4, 0x8ADB, 0xBDDB, 0x8ADC, 0xBFD2, 0x8ADD, 0xEBA5, 0x8ADE, 0xEBAB, 0x8ADF, 0xEBA8, 0x8AE0, 0xEB7E, 0x8AE1, 0xEBAC, 0x8AE2, 0xEBA1, 0x8AE4, 0xEBA7, 0x8AE6, 0xBFCD, 0x8AE7, 0xBFD3, 0x8AE8, 0xEBAD, 0x8AEB, 0xBFCF, 0x8AED, 0xBFD9, 0x8AEE, 0xBFD4, 0x8AEF, 0xEBAF, 0x8AF0, 0xEBA9, 0x8AF1, 0xBFD0, 0x8AF2, 0xEBA2, 0x8AF3, 0xBFDA, 0x8AF4, 0xEBA3, 0x8AF5, 0xEBA4, 0x8AF6, 0xBFDB, 0x8AF7, 0xBFD8, 0x8AF8, 0xBDD1, 0x8AFA, 0xBFCE, 0x8AFB, 0xEBB0, 0x8AFC, 0xBFDC, 0x8AFE, 0xBFD5, 0x8AFF, 0xEBAE, 0x8B00, 0xBFD1, 0x8B01, 0xBFD6, 0x8B02, 0xBFD7, 0x8B04, 0xC1C3, 0x8B05, 0xEEA4, 0x8B06, 0xEEAD, 0x8B07, 0xEEAA, 0x8B08, 0xEEAC, 0x8B0A, 0xC1C0, 0x8B0B, 0xEEA5, 0x8B0D, 0xEEAB, 0x8B0E, 0xC1BC, 0x8B0F, 0xEEA7, 0x8B10, 0xC1C4, 0x8B11, 0xEEA3, 0x8B12, 0xEEA8, 0x8B13, 0xEEAF, 0x8B14, 0xEBA6, 0x8B15, 0xEEA9, 0x8B16, 0xEEA2, 0x8B17, 0xC1BD, 0x8B18, 0xEEA1, 0x8B19, 0xC1BE, 0x8B1A, 0xEEB0, 0x8B1B, 0xC1BF, 0x8B1C, 0xEEAE, 0x8B1D, 0xC1C2, 0x8B1E, 0xEE7E, 0x8B20, 0xC1C1, 0x8B22, 0xEEA6, 0x8B23, 0xF0DC, 0x8B24, 0xF0EA, 0x8B25, 0xF0E5, 0x8B26, 0xF0E7, 0x8B27, 0xF0DB, 0x8B28, 0xC2D3, 0x8B2A, 0xF0DA, 0x8B2B, 0xC2D6, 0x8B2C, 0xC2D5, 0x8B2E, 0xF0E9, 0x8B2F, 0xF0E1, 0x8B30, 0xF0DE, 0x8B31, 0xF0E4, 0x8B33, 0xF0DD, 0x8B35, 0xF0DF, 0x8B36, 0xF0E8, 0x8B37, 0xF0E6, 0x8B39, 0xC2D4, 0x8B3A, 0xF0ED, 0x8B3B, 0xF0EB, 0x8B3C, 0xF0E2, 0x8B3D, 0xF0EC, 0x8B3E, 0xF0E3, 0x8B40, 0xF2F9, 0x8B41, 0xC3CF, 0x8B42, 0xF341, 0x8B45, 0xF64F, 0x8B46, 0xC3D6, 0x8B47, 0xF0E0, 0x8B48, 0xF2F7, 0x8B49, 0xC3D2, 0x8B4A, 0xF2F8, 0x8B4B, 0xF2FD, 0x8B4E, 0xC3D4, 0x8B4F, 0xC3D5, 0x8B50, 0xF2F6, 0x8B51, 0xF340, 0x8B52, 0xF342, 0x8B53, 0xF2FA, 0x8B54, 0xF2FC, 0x8B55, 0xF2FE, 0x8B56, 0xF2FB, 0x8B57, 0xF343, 0x8B58, 0xC3D1, 0x8B59, 0xC3D7, 0x8B5A, 0xC3D3, 0x8B5C, 0xC3D0, 0x8B5D, 0xF4D0, 0x8B5F, 0xC4B7, 0x8B60, 0xF4CE, 0x8B63, 0xF4D2, 0x8B65, 0xF4D3, 0x8B66, 0xC4B5, 0x8B67, 0xF4D4, 0x8B68, 0xF4D1, 0x8B6A, 0xF4CF, 0x8B6B, 0xC4B8, 0x8B6C, 0xC4B4, 0x8B6D, 0xF4D5, 0x8B6F, 0xC4B6, 0x8B70, 0xC4B3, 0x8B74, 0xC4FE, 0x8B77, 0xC540, 0x8B78, 0xF64E, 0x8B79, 0xF64D, 0x8B7A, 0xF650, 0x8B7B, 0xF651, 0x8B7D, 0xC541, 0x8B7E, 0xF756, 0x8B7F, 0xF75B, 0x8B80, 0xC5AA, 0x8B82, 0xF758, 0x8B84, 0xF757, 0x8B85, 0xF75A, 0x8B86, 0xF759, 0x8B88, 0xF843, 0x8B8A, 0xC5DC, 0x8B8B, 0xF842, 0x8B8C, 0xF840, 0x8B8E, 0xF841, 0x8B92, 0xC5FE, 0x8B93, 0xC5FD, 0x8B94, 0xF8C1, 0x8B95, 0xF8C2, 0x8B96, 0xC640, 0x8B98, 0xF94D, 0x8B99, 0xF94E, 0x8B9A, 0xC667, 0x8B9C, 0xC66D, 0x8B9E, 0xF9A9, 0x8B9F, 0xF9C8, 0x8C37, 0xA8A6, 0x8C39, 0xD7CD, 0x8C3B, 0xD7CE, 0x8C3C, 0xE052, 0x8C3D, 0xE450, 0x8C3E, 0xE7E5, 0x8C3F, 0xC1C6, 0x8C41, 0xC1C5, 0x8C42, 0xF0EE, 0x8C43, 0xF344, 0x8C45, 0xF844, 0x8C46, 0xA8A7, 0x8C47, 0xD3DE, 0x8C48, 0xB05A, 0x8C49, 0xB361, 0x8C4A, 0xE054, 0x8C4B, 0xE053, 0x8C4C, 0xBDDC, 0x8C4D, 0xE7E6, 0x8C4E, 0xBDDD, 0x8C4F, 0xEEB1, 0x8C50, 0xC2D7, 0x8C54, 0xC676, 0x8C55, 0xA8A8, 0x8C56, 0xCDCB, 0x8C57, 0xD3DF, 0x8C5A, 0xB362, 0x8C5C, 0xD7CF, 0x8C5D, 0xD7D0, 0x8C5F, 0xDBE5, 0x8C61, 0xB648, 0x8C62, 0xB8E6, 0x8C64, 0xE056, 0x8C65, 0xE055, 0x8C66, 0xE057, 0x8C68, 0xE451, 0x8C69, 0xE452, 0x8C6A, 0xBBA8, 0x8C6B, 0xBFDD, 0x8C6C, 0xBDDE, 0x8C6D, 0xBFDE, 0x8C6F, 0xEEB5, 0x8C70, 0xEEB2, 0x8C71, 0xEEB4, 0x8C72, 0xEEB3, 0x8C73, 0xC1C7, 0x8C75, 0xF0EF, 0x8C76, 0xF346, 0x8C77, 0xF345, 0x8C78, 0xCBA4, 0x8C79, 0xB05C, 0x8C7A, 0xB05B, 0x8C7B, 0xD3E0, 0x8C7D, 0xD7D1, 0x8C80, 0xDBE7, 0x8C81, 0xDBE6, 0x8C82, 0xB649, 0x8C84, 0xE059, 0x8C85, 0xE05A, 0x8C86, 0xE058, 0x8C89, 0xB8E8, 0x8C8A, 0xB8E7, 0x8C8C, 0xBBAA, 0x8C8D, 0xBBA9, 0x8C8F, 0xE7E7, 0x8C90, 0xEBB3, 0x8C91, 0xEBB1, 0x8C92, 0xEBB2, 0x8C93, 0xBFDF, 0x8C94, 0xEEB7, 0x8C95, 0xEEB6, 0x8C97, 0xF0F2, 0x8C98, 0xF0F1, 0x8C99, 0xF0F0, 0x8C9A, 0xF347, 0x8C9C, 0xF9AA, 0x8C9D, 0xA8A9, 0x8C9E, 0xAD73, 0x8CA0, 0xAD74, 0x8CA1, 0xB05D, 0x8CA2, 0xB05E, 0x8CA3, 0xD3E2, 0x8CA4, 0xD3E1, 0x8CA5, 0xD7D2, 0x8CA7, 0xB368, 0x8CA8, 0xB366, 0x8CA9, 0xB363, 0x8CAA, 0xB367, 0x8CAB, 0xB365, 0x8CAC, 0xB364, 0x8CAF, 0xB64A, 0x8CB0, 0xDBEA, 0x8CB2, 0xB8ED, 0x8CB3, 0xB64C, 0x8CB4, 0xB651, 0x8CB5, 0xDBEC, 0x8CB6, 0xB653, 0x8CB7, 0xB652, 0x8CB8, 0xB655, 0x8CB9, 0xDBEB, 0x8CBA, 0xDBE8, 0x8CBB, 0xB64F, 0x8CBC, 0xB64B, 0x8CBD, 0xB64D, 0x8CBE, 0xDBE9, 0x8CBF, 0xB654, 0x8CC0, 0xB650, 0x8CC1, 0xB64E, 0x8CC2, 0xB8EF, 0x8CC3, 0xB8EE, 0x8CC4, 0xB8EC, 0x8CC5, 0xB8F0, 0x8CC7, 0xB8EA, 0x8CC8, 0xB8EB, 0x8CCA, 0xB8E9, 0x8CCC, 0xE05B, 0x8CCF, 0xE454, 0x8CD1, 0xBBAC, 0x8CD2, 0xBBAD, 0x8CD3, 0xBBAB, 0x8CD5, 0xE453, 0x8CD7, 0xE455, 0x8CD9, 0xE7EA, 0x8CDA, 0xE7EC, 0x8CDC, 0xBDE7, 0x8CDD, 0xE7ED, 0x8CDE, 0xBDE0, 0x8CDF, 0xE7E9, 0x8CE0, 0xBDDF, 0x8CE1, 0xBDE9, 0x8CE2, 0xBDE5, 0x8CE3, 0xBDE6, 0x8CE4, 0xBDE2, 0x8CE5, 0xE7E8, 0x8CE6, 0xBDE1, 0x8CE7, 0xE7EE, 0x8CE8, 0xE7EB, 0x8CEA, 0xBDE8, 0x8CEC, 0xBDE3, 0x8CED, 0xBDE4, 0x8CEE, 0xEBB5, 0x8CF0, 0xEBB7, 0x8CF1, 0xEBB6, 0x8CF3, 0xEBB8, 0x8CF4, 0xBFE0, 0x8CF5, 0xEBB4, 0x8CF8, 0xC1CB, 0x8CF9, 0xEEB8, 0x8CFA, 0xC1C8, 0x8CFB, 0xC1CC, 0x8CFC, 0xC1CA, 0x8CFD, 0xC1C9, 0x8CFE, 0xF0F3, 0x8D00, 0xF0F6, 0x8D02, 0xF0F5, 0x8D04, 0xF0F4, 0x8D05, 0xC2D8, 0x8D06, 0xF348, 0x8D07, 0xF349, 0x8D08, 0xC3D8, 0x8D09, 0xF34A, 0x8D0A, 0xC3D9, 0x8D0D, 0xC4BA, 0x8D0F, 0xC4B9, 0x8D10, 0xF652, 0x8D13, 0xC542, 0x8D14, 0xF653, 0x8D15, 0xF75C, 0x8D16, 0xC5AB, 0x8D17, 0xC5AC, 0x8D19, 0xF845, 0x8D1B, 0xC642, 0x8D64, 0xA8AA, 0x8D66, 0xB36A, 0x8D67, 0xB369, 0x8D68, 0xE05C, 0x8D69, 0xE05D, 0x8D6B, 0xBBAE, 0x8D6C, 0xEBB9, 0x8D6D, 0xBDEA, 0x8D6E, 0xEBBA, 0x8D6F, 0xEEB9, 0x8D70, 0xA8AB, 0x8D72, 0xD0B2, 0x8D73, 0xAD76, 0x8D74, 0xAD75, 0x8D76, 0xD3E3, 0x8D77, 0xB05F, 0x8D78, 0xD3E4, 0x8D79, 0xD7D5, 0x8D7B, 0xD7D4, 0x8D7D, 0xD7D3, 0x8D80, 0xDBEE, 0x8D81, 0xB658, 0x8D84, 0xDBED, 0x8D85, 0xB657, 0x8D89, 0xDBEF, 0x8D8A, 0xB656, 0x8D8C, 0xE05F, 0x8D8D, 0xE062, 0x8D8E, 0xE060, 0x8D8F, 0xE061, 0x8D90, 0xE065, 0x8D91, 0xE05E, 0x8D92, 0xE066, 0x8D93, 0xE063, 0x8D94, 0xE064, 0x8D95, 0xBBB0, 0x8D96, 0xE456, 0x8D99, 0xBBAF, 0x8D9B, 0xE7F2, 0x8D9C, 0xE7F0, 0x8D9F, 0xBDEB, 0x8DA0, 0xE7EF, 0x8DA1, 0xE7F1, 0x8DA3, 0xBDEC, 0x8DA5, 0xEBBB, 0x8DA7, 0xEBBC, 0x8DA8, 0xC1CD, 0x8DAA, 0xF34C, 0x8DAB, 0xF34E, 0x8DAC, 0xF34B, 0x8DAD, 0xF34D, 0x8DAE, 0xF4D6, 0x8DAF, 0xF654, 0x8DB2, 0xF96F, 0x8DB3, 0xA8AC, 0x8DB4, 0xAD77, 0x8DB5, 0xD3E5, 0x8DB6, 0xD3E7, 0x8DB7, 0xD3E6, 0x8DB9, 0xD7D8, 0x8DBA, 0xB36C, 0x8DBC, 0xD7D6, 0x8DBE, 0xB36B, 0x8DBF, 0xD7D9, 0x8DC1, 0xD7DA, 0x8DC2, 0xD7D7, 0x8DC5, 0xDBFB, 0x8DC6, 0xB660, 0x8DC7, 0xDBF3, 0x8DC8, 0xDBF9, 0x8DCB, 0xB65B, 0x8DCC, 0xB65E, 0x8DCD, 0xDBF2, 0x8DCE, 0xB659, 0x8DCF, 0xDBF6, 0x8DD0, 0xE06C, 0x8DD1, 0xB65D, 0x8DD3, 0xDBF1, 0x8DD5, 0xDBF7, 0x8DD6, 0xDBF4, 0x8DD7, 0xDBFA, 0x8DD8, 0xDBF0, 0x8DD9, 0xDBF8, 0x8DDA, 0xB65C, 0x8DDB, 0xB65F, 0x8DDC, 0xDBF5, 0x8DDD, 0xB65A, 0x8DDF, 0xB8F2, 0x8DE0, 0xE068, 0x8DE1, 0xB8F1, 0x8DE2, 0xE06F, 0x8DE3, 0xE06E, 0x8DE4, 0xB8F8, 0x8DE6, 0xB8F9, 0x8DE7, 0xE070, 0x8DE8, 0xB8F3, 0x8DE9, 0xE06D, 0x8DEA, 0xB8F7, 0x8DEB, 0xE072, 0x8DEC, 0xE069, 0x8DEE, 0xE06B, 0x8DEF, 0xB8F4, 0x8DF0, 0xE067, 0x8DF1, 0xE06A, 0x8DF2, 0xE071, 0x8DF3, 0xB8F5, 0x8DF4, 0xE073, 0x8DFA, 0xB8F6, 0x8DFC, 0xBBB1, 0x8DFD, 0xE45B, 0x8DFE, 0xE461, 0x8DFF, 0xE459, 0x8E00, 0xE462, 0x8E02, 0xE458, 0x8E03, 0xE45D, 0x8E04, 0xE463, 0x8E05, 0xE460, 0x8E06, 0xE45F, 0x8E07, 0xE45E, 0x8E09, 0xE457, 0x8E0A, 0xE45C, 0x8E0D, 0xE45A, 0x8E0F, 0xBDF1, 0x8E10, 0xBDEE, 0x8E11, 0xE7FB, 0x8E12, 0xE841, 0x8E13, 0xE843, 0x8E14, 0xE840, 0x8E15, 0xE7F8, 0x8E16, 0xE7FA, 0x8E17, 0xE845, 0x8E18, 0xE842, 0x8E19, 0xE7FC, 0x8E1A, 0xE846, 0x8E1B, 0xE7F9, 0x8E1C, 0xE844, 0x8E1D, 0xBDEF, 0x8E1E, 0xBDF5, 0x8E1F, 0xBDF3, 0x8E20, 0xE7F3, 0x8E21, 0xBDF4, 0x8E22, 0xBDF0, 0x8E23, 0xE7F4, 0x8E24, 0xE7F6, 0x8E25, 0xE7F5, 0x8E26, 0xE7FD, 0x8E27, 0xE7FE, 0x8E29, 0xBDF2, 0x8E2B, 0xBDED, 0x8E2E, 0xE7F7, 0x8E30, 0xEBC6, 0x8E31, 0xBFE2, 0x8E33, 0xEBBD, 0x8E34, 0xBFE3, 0x8E35, 0xBFE6, 0x8E36, 0xEBC2, 0x8E38, 0xEBBF, 0x8E39, 0xBFE5, 0x8E3C, 0xEBC3, 0x8E3D, 0xEBC4, 0x8E3E, 0xEBBE, 0x8E3F, 0xEBC7, 0x8E40, 0xEBC0, 0x8E41, 0xEBC5, 0x8E42, 0xBFE4, 0x8E44, 0xBFE1, 0x8E45, 0xEBC1, 0x8E47, 0xEEBF, 0x8E48, 0xC1D0, 0x8E49, 0xC1CE, 0x8E4A, 0xC1D1, 0x8E4B, 0xC1CF, 0x8E4C, 0xEEBE, 0x8E4D, 0xEEBB, 0x8E4E, 0xEEBA, 0x8E50, 0xEEBD, 0x8E53, 0xEEBC, 0x8E54, 0xF145, 0x8E55, 0xC2DE, 0x8E56, 0xF0FB, 0x8E57, 0xF0FA, 0x8E59, 0xC2D9, 0x8E5A, 0xF141, 0x8E5B, 0xF140, 0x8E5C, 0xF0F7, 0x8E5D, 0xF143, 0x8E5E, 0xF0FC, 0x8E5F, 0xC2DD, 0x8E60, 0xF0F9, 0x8E61, 0xF142, 0x8E62, 0xF0F8, 0x8E63, 0xC2DA, 0x8E64, 0xC2DC, 0x8E65, 0xF0FD, 0x8E66, 0xC2DB, 0x8E67, 0xF0FE, 0x8E69, 0xF144, 0x8E6A, 0xF352, 0x8E6C, 0xC3DE, 0x8E6D, 0xF34F, 0x8E6F, 0xF353, 0x8E72, 0xC3DB, 0x8E73, 0xF351, 0x8E74, 0xC3E0, 0x8E76, 0xC3DD, 0x8E78, 0xF350, 0x8E7A, 0xC3DF, 0x8E7B, 0xF354, 0x8E7C, 0xC3DA, 0x8E81, 0xC4BC, 0x8E82, 0xC4BE, 0x8E84, 0xF4D9, 0x8E85, 0xC4BD, 0x8E86, 0xF4D7, 0x8E87, 0xC3DC, 0x8E88, 0xF4D8, 0x8E89, 0xC4BB, 0x8E8A, 0xC543, 0x8E8B, 0xC545, 0x8E8C, 0xF656, 0x8E8D, 0xC544, 0x8E8E, 0xF655, 0x8E90, 0xF761, 0x8E91, 0xC5AD, 0x8E92, 0xF760, 0x8E93, 0xC5AE, 0x8E94, 0xF75E, 0x8E95, 0xF75D, 0x8E96, 0xF762, 0x8E97, 0xF763, 0x8E98, 0xF846, 0x8E9A, 0xF75F, 0x8E9D, 0xF8C6, 0x8E9E, 0xF8C3, 0x8E9F, 0xF8C4, 0x8EA0, 0xF8C5, 0x8EA1, 0xC65C, 0x8EA3, 0xF951, 0x8EA4, 0xF950, 0x8EA5, 0xF94F, 0x8EA6, 0xF970, 0x8EA8, 0xF9BE, 0x8EA9, 0xF9AB, 0x8EAA, 0xC66E, 0x8EAB, 0xA8AD, 0x8EAC, 0xB060, 0x8EB2, 0xB8FA, 0x8EBA, 0xBDF6, 0x8EBD, 0xEBC8, 0x8EC0, 0xC2DF, 0x8EC2, 0xF355, 0x8EC9, 0xF9AC, 0x8ECA, 0xA8AE, 0x8ECB, 0xAAEE, 0x8ECC, 0xAD79, 0x8ECD, 0xAD78, 0x8ECF, 0xB063, 0x8ED1, 0xD3E8, 0x8ED2, 0xB061, 0x8ED3, 0xD3E9, 0x8ED4, 0xB062, 0x8ED7, 0xD7DF, 0x8ED8, 0xD7DB, 0x8EDB, 0xB36D, 0x8EDC, 0xD7DE, 0x8EDD, 0xD7DD, 0x8EDE, 0xD7DC, 0x8EDF, 0xB36E, 0x8EE0, 0xD7E0, 0x8EE1, 0xD7E1, 0x8EE5, 0xDC43, 0x8EE6, 0xDC41, 0x8EE7, 0xDC45, 0x8EE8, 0xDC46, 0x8EE9, 0xDC4C, 0x8EEB, 0xDC48, 0x8EEC, 0xDC4A, 0x8EEE, 0xDC42, 0x8EEF, 0xDBFC, 0x8EF1, 0xDC49, 0x8EF4, 0xDC4B, 0x8EF5, 0xDC44, 0x8EF6, 0xDC47, 0x8EF7, 0xDBFD, 0x8EF8, 0xB662, 0x8EF9, 0xDC40, 0x8EFA, 0xDBFE, 0x8EFB, 0xB661, 0x8EFC, 0xB663, 0x8EFE, 0xB8FD, 0x8EFF, 0xE075, 0x8F00, 0xE077, 0x8F01, 0xE076, 0x8F02, 0xE07B, 0x8F03, 0xB8FB, 0x8F05, 0xE078, 0x8F06, 0xE074, 0x8F07, 0xE079, 0x8F08, 0xE07A, 0x8F09, 0xB8FC, 0x8F0A, 0xB8FE, 0x8F0B, 0xE07C, 0x8F0D, 0xE467, 0x8F0E, 0xE466, 0x8F10, 0xE464, 0x8F11, 0xE465, 0x8F12, 0xBBB3, 0x8F13, 0xBBB5, 0x8F14, 0xBBB2, 0x8F15, 0xBBB4, 0x8F16, 0xE84D, 0x8F17, 0xE84E, 0x8F18, 0xE849, 0x8F1A, 0xE84A, 0x8F1B, 0xBDF8, 0x8F1C, 0xBDFD, 0x8F1D, 0xBDF7, 0x8F1E, 0xBDFE, 0x8F1F, 0xBDF9, 0x8F20, 0xE84B, 0x8F23, 0xE84C, 0x8F24, 0xE848, 0x8F25, 0xBE40, 0x8F26, 0xBDFB, 0x8F29, 0xBDFA, 0x8F2A, 0xBDFC, 0x8F2C, 0xE847, 0x8F2E, 0xEBCA, 0x8F2F, 0xBFE8, 0x8F32, 0xEBCC, 0x8F33, 0xBFEA, 0x8F34, 0xEBCF, 0x8F35, 0xEBCB, 0x8F36, 0xEBC9, 0x8F37, 0xEBCE, 0x8F38, 0xBFE9, 0x8F39, 0xEBCD, 0x8F3B, 0xBFE7, 0x8F3E, 0xC1D3, 0x8F3F, 0xC1D6, 0x8F40, 0xEEC1, 0x8F42, 0xC1D4, 0x8F43, 0xEEC0, 0x8F44, 0xC1D2, 0x8F45, 0xC1D5, 0x8F46, 0xF146, 0x8F47, 0xF147, 0x8F48, 0xF148, 0x8F49, 0xC2E0, 0x8F4B, 0xF149, 0x8F4D, 0xC2E1, 0x8F4E, 0xC3E2, 0x8F4F, 0xF358, 0x8F50, 0xF359, 0x8F51, 0xF357, 0x8F52, 0xF356, 0x8F53, 0xF35A, 0x8F54, 0xC3E1, 0x8F55, 0xF4DD, 0x8F56, 0xF4DB, 0x8F57, 0xF4DC, 0x8F58, 0xF4DE, 0x8F59, 0xF4DA, 0x8F5A, 0xF4DF, 0x8F5B, 0xF658, 0x8F5D, 0xF659, 0x8F5E, 0xF657, 0x8F5F, 0xC546, 0x8F60, 0xF764, 0x8F61, 0xC5AF, 0x8F62, 0xF765, 0x8F63, 0xF848, 0x8F64, 0xF847, 0x8F9B, 0xA8AF, 0x8F9C, 0xB664, 0x8F9F, 0xB940, 0x8FA3, 0xBBB6, 0x8FA6, 0xBFEC, 0x8FA8, 0xBFEB, 0x8FAD, 0xC3E3, 0x8FAE, 0xC47C, 0x8FAF, 0xC547, 0x8FB0, 0xA8B0, 0x8FB1, 0xB064, 0x8FB2, 0xB941, 0x8FB4, 0xF35B, 0x8FBF, 0xCBA6, 0x8FC2, 0xA8B1, 0x8FC4, 0xA8B4, 0x8FC5, 0xA8B3, 0x8FC6, 0xA8B2, 0x8FC9, 0xCBA5, 0x8FCB, 0xCDCD, 0x8FCD, 0xCDCF, 0x8FCE, 0xAAEF, 0x8FD1, 0xAAF1, 0x8FD2, 0xCDCC, 0x8FD3, 0xCDCE, 0x8FD4, 0xAAF0, 0x8FD5, 0xCDD1, 0x8FD6, 0xCDD0, 0x8FD7, 0xCDD2, 0x8FE0, 0xD0B6, 0x8FE1, 0xD0B4, 0x8FE2, 0xAD7C, 0x8FE3, 0xD0B3, 0x8FE4, 0xADA3, 0x8FE5, 0xAD7E, 0x8FE6, 0xAD7B, 0x8FE8, 0xADA4, 0x8FEA, 0xAD7D, 0x8FEB, 0xADA2, 0x8FED, 0xADA1, 0x8FEE, 0xD0B5, 0x8FF0, 0xAD7A, 0x8FF4, 0xB06A, 0x8FF5, 0xD3EB, 0x8FF6, 0xD3F1, 0x8FF7, 0xB067, 0x8FF8, 0xB06E, 0x8FFA, 0xB069, 0x8FFB, 0xD3EE, 0x8FFC, 0xD3F0, 0x8FFD, 0xB06C, 0x8FFE, 0xD3EA, 0x8FFF, 0xD3ED, 0x9000, 0xB068, 0x9001, 0xB065, 0x9002, 0xD3EC, 0x9003, 0xB06B, 0x9004, 0xD3EF, 0x9005, 0xB06D, 0x9006, 0xB066, 0x900B, 0xD7E3, 0x900C, 0xD7E6, 0x900D, 0xB370, 0x900F, 0xB37A, 0x9010, 0xB376, 0x9011, 0xD7E4, 0x9014, 0xB37E, 0x9015, 0xB377, 0x9016, 0xB37C, 0x9017, 0xB372, 0x9019, 0xB36F, 0x901A, 0xB371, 0x901B, 0xB37D, 0x901C, 0xD7E5, 0x901D, 0xB375, 0x901E, 0xB378, 0x901F, 0xB374, 0x9020, 0xB379, 0x9021, 0xD7E7, 0x9022, 0xB37B, 0x9023, 0xB373, 0x9024, 0xD7E2, 0x902D, 0xDC4D, 0x902E, 0xB665, 0x902F, 0xDC4F, 0x9031, 0xB667, 0x9032, 0xB669, 0x9034, 0xDC4E, 0x9035, 0xB666, 0x9036, 0xB66A, 0x9038, 0xB668, 0x903C, 0xB947, 0x903D, 0xE0A3, 0x903E, 0xB94F, 0x903F, 0xE07E, 0x9041, 0xB950, 0x9042, 0xB945, 0x9044, 0xE0A1, 0x9047, 0xB94A, 0x9049, 0xE0A2, 0x904A, 0xB943, 0x904B, 0xB942, 0x904D, 0xB94D, 0x904E, 0xB94C, 0x904F, 0xB94B, 0x9050, 0xB949, 0x9051, 0xB94E, 0x9052, 0xE07D, 0x9053, 0xB944, 0x9054, 0xB946, 0x9055, 0xB948, 0x9058, 0xBBB8, 0x9059, 0xBBBB, 0x905B, 0xBBBF, 0x905C, 0xBBB9, 0x905D, 0xBBBE, 0x905E, 0xBBBC, 0x9060, 0xBBB7, 0x9062, 0xBBBD, 0x9063, 0xBBBA, 0x9067, 0xE852, 0x9068, 0xBE43, 0x9069, 0xBE41, 0x906B, 0xE853, 0x906D, 0xBE44, 0x906E, 0xBE42, 0x906F, 0xE851, 0x9070, 0xE850, 0x9072, 0xBFF0, 0x9073, 0xE84F, 0x9074, 0xBFEE, 0x9075, 0xBFED, 0x9076, 0xEBD0, 0x9077, 0xBE45, 0x9078, 0xBFEF, 0x9079, 0xEBD1, 0x907A, 0xBFF2, 0x907B, 0xEBD2, 0x907C, 0xBFF1, 0x907D, 0xC1D8, 0x907E, 0xEEC3, 0x907F, 0xC1D7, 0x9080, 0xC1DC, 0x9081, 0xC1DA, 0x9082, 0xC1DB, 0x9083, 0xC2E3, 0x9084, 0xC1D9, 0x9085, 0xEEC2, 0x9086, 0xEBD3, 0x9087, 0xC2E2, 0x9088, 0xC2E4, 0x908A, 0xC3E4, 0x908B, 0xC3E5, 0x908D, 0xF4E0, 0x908F, 0xC5DE, 0x9090, 0xC5DD, 0x9091, 0xA8B6, 0x9094, 0xCA55, 0x9095, 0xB06F, 0x9097, 0xCA52, 0x9098, 0xCA53, 0x9099, 0xCA51, 0x909B, 0xCA54, 0x909E, 0xCBAA, 0x909F, 0xCBA7, 0x90A0, 0xCBAC, 0x90A1, 0xCBA8, 0x90A2, 0xA8B7, 0x90A3, 0xA8BA, 0x90A5, 0xCBA9, 0x90A6, 0xA8B9, 0x90A7, 0xCBAB, 0x90AA, 0xA8B8, 0x90AF, 0xCDD5, 0x90B0, 0xCDD7, 0x90B1, 0xAAF4, 0x90B2, 0xCDD3, 0x90B3, 0xCDD6, 0x90B4, 0xCDD4, 0x90B5, 0xAAF2, 0x90B6, 0xAAF5, 0x90B8, 0xAAF3, 0x90BD, 0xD0B8, 0x90BE, 0xD0BC, 0x90BF, 0xD0B9, 0x90C1, 0xADA7, 0x90C3, 0xADA8, 0x90C5, 0xD0BB, 0x90C7, 0xD0BD, 0x90C8, 0xD0BF, 0x90CA, 0xADA5, 0x90CB, 0xD0BE, 0x90CE, 0xADA6, 0x90D4, 0xD7EE, 0x90D5, 0xD0BA, 0x90D6, 0xD3F2, 0x90D7, 0xD3FB, 0x90D8, 0xD3F9, 0x90D9, 0xD3F4, 0x90DA, 0xD3F5, 0x90DB, 0xD3FA, 0x90DC, 0xD3FC, 0x90DD, 0xB071, 0x90DF, 0xD3F7, 0x90E0, 0xD3F3, 0x90E1, 0xB070, 0x90E2, 0xB072, 0x90E3, 0xD3F6, 0x90E4, 0xD3FD, 0x90E5, 0xD3F8, 0x90E8, 0xB3A1, 0x90E9, 0xD7F1, 0x90EA, 0xD7E9, 0x90EB, 0xD7EF, 0x90EC, 0xD7F0, 0x90ED, 0xB3A2, 0x90EF, 0xD7E8, 0x90F0, 0xD7EA, 0x90F1, 0xD0B7, 0x90F2, 0xD7EC, 0x90F3, 0xD7ED, 0x90F4, 0xD7EB, 0x90F5, 0xB66C, 0x90F9, 0xDC56, 0x90FA, 0xEBD4, 0x90FB, 0xDC57, 0x90FC, 0xDC54, 0x90FD, 0xB3A3, 0x90FE, 0xB66E, 0x90FF, 0xDC53, 0x9100, 0xDC59, 0x9101, 0xDC58, 0x9102, 0xB66B, 0x9103, 0xDC5C, 0x9104, 0xDC52, 0x9105, 0xDC5B, 0x9106, 0xDC50, 0x9107, 0xDC5A, 0x9108, 0xDC55, 0x9109, 0xB66D, 0x910B, 0xE0AA, 0x910D, 0xE0A5, 0x910E, 0xE0AB, 0x910F, 0xE0A6, 0x9110, 0xE0A4, 0x9111, 0xE0A7, 0x9112, 0xB951, 0x9114, 0xE0A9, 0x9116, 0xE0A8, 0x9117, 0xB952, 0x9118, 0xBBC1, 0x9119, 0xBBC0, 0x911A, 0xE46E, 0x911B, 0xE471, 0x911C, 0xE469, 0x911D, 0xE46D, 0x911E, 0xBBC2, 0x911F, 0xE46C, 0x9120, 0xE46A, 0x9121, 0xE470, 0x9122, 0xE46B, 0x9123, 0xE468, 0x9124, 0xE46F, 0x9126, 0xE859, 0x9127, 0xBE48, 0x9128, 0xF14A, 0x9129, 0xE856, 0x912A, 0xE857, 0x912B, 0xE855, 0x912C, 0xDC51, 0x912D, 0xBE47, 0x912E, 0xE85A, 0x912F, 0xE854, 0x9130, 0xBE46, 0x9131, 0xBE49, 0x9132, 0xE858, 0x9133, 0xEBD5, 0x9134, 0xBFF3, 0x9135, 0xEBD6, 0x9136, 0xEBD7, 0x9138, 0xEEC4, 0x9139, 0xC1DD, 0x913A, 0xF14B, 0x913B, 0xF14C, 0x913E, 0xF14D, 0x913F, 0xF35D, 0x9140, 0xF35C, 0x9141, 0xF4E2, 0x9143, 0xF4E1, 0x9144, 0xF65B, 0x9145, 0xF65C, 0x9146, 0xF65A, 0x9147, 0xF766, 0x9148, 0xC5B0, 0x9149, 0xA8BB, 0x914A, 0xADAA, 0x914B, 0xADA9, 0x914C, 0xB075, 0x914D, 0xB074, 0x914E, 0xD440, 0x914F, 0xD441, 0x9150, 0xD3FE, 0x9152, 0xB073, 0x9153, 0xD7F5, 0x9155, 0xD7F6, 0x9156, 0xD7F2, 0x9157, 0xB3A4, 0x9158, 0xD7F3, 0x915A, 0xD7F4, 0x915F, 0xDC5F, 0x9160, 0xDC61, 0x9161, 0xDC5D, 0x9162, 0xDC60, 0x9163, 0xB66F, 0x9164, 0xDC5E, 0x9165, 0xB670, 0x9168, 0xDD73, 0x9169, 0xB955, 0x916A, 0xB954, 0x916C, 0xB953, 0x916E, 0xE0AC, 0x916F, 0xE0AD, 0x9172, 0xE473, 0x9173, 0xE475, 0x9174, 0xBBC6, 0x9175, 0xBBC3, 0x9177, 0xBBC5, 0x9178, 0xBBC4, 0x9179, 0xE474, 0x917A, 0xE472, 0x9180, 0xE861, 0x9181, 0xE85E, 0x9182, 0xE85F, 0x9183, 0xBE4D, 0x9184, 0xE860, 0x9185, 0xE85B, 0x9186, 0xE85C, 0x9187, 0xBE4A, 0x9189, 0xBE4B, 0x918A, 0xE85D, 0x918B, 0xBE4C, 0x918D, 0xEBDB, 0x918F, 0xEBDC, 0x9190, 0xEBD9, 0x9191, 0xEBDA, 0x9192, 0xBFF4, 0x9193, 0xEBD8, 0x9199, 0xEEC8, 0x919A, 0xEEC5, 0x919B, 0xEEC7, 0x919C, 0xC1E0, 0x919D, 0xEECB, 0x919E, 0xC1DF, 0x919F, 0xEEC9, 0x91A0, 0xEECC, 0x91A1, 0xEECA, 0x91A2, 0xEEC6, 0x91A3, 0xC1DE, 0x91A5, 0xF14F, 0x91A7, 0xF150, 0x91A8, 0xF14E, 0x91AA, 0xF152, 0x91AB, 0xC2E5, 0x91AC, 0xC2E6, 0x91AD, 0xF35F, 0x91AE, 0xC3E7, 0x91AF, 0xF151, 0x91B0, 0xF35E, 0x91B1, 0xC3E6, 0x91B2, 0xF4E5, 0x91B3, 0xF4E6, 0x91B4, 0xC4BF, 0x91B5, 0xF4E4, 0x91B7, 0xF4E3, 0x91B9, 0xF65D, 0x91BA, 0xC548, 0x91BC, 0xF849, 0x91BD, 0xF8C8, 0x91BE, 0xF8C7, 0x91C0, 0xC643, 0x91C1, 0xC65D, 0x91C2, 0xF8C9, 0x91C3, 0xF971, 0x91C5, 0xC66F, 0x91C6, 0xA8BC, 0x91C7, 0xAAF6, 0x91C9, 0xB956, 0x91CB, 0xC4C0, 0x91CC, 0xA8BD, 0x91CD, 0xADAB, 0x91CE, 0xB3A5, 0x91CF, 0xB671, 0x91D0, 0xC2E7, 0x91D1, 0xAAF7, 0x91D3, 0xD0C1, 0x91D4, 0xD0C0, 0x91D5, 0xD442, 0x91D7, 0xB078, 0x91D8, 0xB076, 0x91D9, 0xB07A, 0x91DA, 0xD444, 0x91DC, 0xB079, 0x91DD, 0xB077, 0x91E2, 0xD443, 0x91E3, 0xB3A8, 0x91E4, 0xD7FC, 0x91E6, 0xB3A7, 0x91E7, 0xB3A9, 0x91E8, 0xD842, 0x91E9, 0xB3AB, 0x91EA, 0xD7FE, 0x91EB, 0xD840, 0x91EC, 0xD7F7, 0x91ED, 0xB3AA, 0x91EE, 0xD843, 0x91F1, 0xD7F9, 0x91F3, 0xD7FA, 0x91F4, 0xD7F8, 0x91F5, 0xB3A6, 0x91F7, 0xD841, 0x91F8, 0xD7FB, 0x91F9, 0xD7FD, 0x91FD, 0xDC6D, 0x91FF, 0xDC6C, 0x9200, 0xDC6A, 0x9201, 0xDC62, 0x9202, 0xDC71, 0x9203, 0xDC65, 0x9204, 0xDC6F, 0x9205, 0xDC76, 0x9206, 0xDC6E, 0x9207, 0xB679, 0x9209, 0xB675, 0x920A, 0xDC63, 0x920C, 0xDC69, 0x920D, 0xB677, 0x920F, 0xDC68, 0x9210, 0xB678, 0x9211, 0xB67A, 0x9212, 0xDC6B, 0x9214, 0xB672, 0x9215, 0xB673, 0x9216, 0xDC77, 0x9217, 0xDC75, 0x9219, 0xDC74, 0x921A, 0xDC66, 0x921C, 0xDC72, 0x921E, 0xB676, 0x9223, 0xB674, 0x9224, 0xDC73, 0x9225, 0xDC64, 0x9226, 0xDC67, 0x9227, 0xDC70, 0x922D, 0xE4BA, 0x922E, 0xE0B7, 0x9230, 0xE0B0, 0x9231, 0xE0C3, 0x9232, 0xE0CC, 0x9233, 0xE0B3, 0x9234, 0xB961, 0x9236, 0xE0C0, 0x9237, 0xB957, 0x9238, 0xB959, 0x9239, 0xB965, 0x923A, 0xE0B1, 0x923D, 0xB95A, 0x923E, 0xB95C, 0x923F, 0xB966, 0x9240, 0xB95B, 0x9245, 0xB964, 0x9246, 0xE0B9, 0x9248, 0xE0AE, 0x9249, 0xB962, 0x924A, 0xE0B8, 0x924B, 0xB95E, 0x924C, 0xE0CA, 0x924D, 0xB963, 0x924E, 0xE0C8, 0x924F, 0xE0BC, 0x9250, 0xE0C6, 0x9251, 0xB960, 0x9252, 0xE0AF, 0x9253, 0xE0C9, 0x9254, 0xE0C4, 0x9256, 0xE0CB, 0x9257, 0xB958, 0x925A, 0xB967, 0x925B, 0xB95D, 0x925E, 0xE0B5, 0x9260, 0xE0BD, 0x9261, 0xE0C1, 0x9263, 0xE0C5, 0x9264, 0xB95F, 0x9265, 0xE0B4, 0x9266, 0xE0B2, 0x9267, 0xE0BE, 0x926C, 0xE0BB, 0x926D, 0xE0BA, 0x926F, 0xE0BF, 0x9270, 0xE0C2, 0x9272, 0xE0C7, 0x9276, 0xE478, 0x9278, 0xBBC7, 0x9279, 0xE4A4, 0x927A, 0xE47A, 0x927B, 0xBBCC, 0x927C, 0xBBD0, 0x927D, 0xE4AD, 0x927E, 0xE4B5, 0x927F, 0xE4A6, 0x9280, 0xBBC8, 0x9282, 0xE4AA, 0x9283, 0xE0B6, 0x9285, 0xBBC9, 0x9286, 0xE4B1, 0x9287, 0xE4B6, 0x9288, 0xE4AE, 0x928A, 0xE4B0, 0x928B, 0xE4B9, 0x928C, 0xE4B2, 0x928D, 0xE47E, 0x928E, 0xE4A9, 0x9291, 0xBBD1, 0x9293, 0xBBCD, 0x9294, 0xE47C, 0x9295, 0xE4AB, 0x9296, 0xBBCB, 0x9297, 0xE4A5, 0x9298, 0xBBCA, 0x9299, 0xE4B3, 0x929A, 0xE4A2, 0x929B, 0xE479, 0x929C, 0xBBCE, 0x929D, 0xE4B8, 0x92A0, 0xE47B, 0x92A1, 0xE4AF, 0x92A2, 0xE4AC, 0x92A3, 0xE4A7, 0x92A4, 0xE477, 0x92A5, 0xE476, 0x92A6, 0xE4A1, 0x92A7, 0xE4B4, 0x92A8, 0xBBCF, 0x92A9, 0xE4B7, 0x92AA, 0xE47D, 0x92AB, 0xE4A3, 0x92AC, 0xBE52, 0x92B2, 0xBE5A, 0x92B3, 0xBE55, 0x92B4, 0xE8A4, 0x92B5, 0xE8A1, 0x92B6, 0xE867, 0x92B7, 0xBE50, 0x92B9, 0xF9D7, 0x92BB, 0xBE4F, 0x92BC, 0xBE56, 0x92C0, 0xE865, 0x92C1, 0xBE54, 0x92C2, 0xE871, 0x92C3, 0xE863, 0x92C4, 0xE864, 0x92C5, 0xBE4E, 0x92C6, 0xE8A3, 0x92C7, 0xBE58, 0x92C8, 0xE874, 0x92C9, 0xE879, 0x92CA, 0xE873, 0x92CB, 0xEBEE, 0x92CC, 0xE86F, 0x92CD, 0xE877, 0x92CE, 0xE875, 0x92CF, 0xE868, 0x92D0, 0xE862, 0x92D1, 0xE87D, 0x92D2, 0xBE57, 0x92D3, 0xE87E, 0x92D5, 0xE878, 0x92D7, 0xE86D, 0x92D8, 0xE86B, 0x92D9, 0xE866, 0x92DD, 0xE86E, 0x92DE, 0xE87B, 0x92DF, 0xE86A, 0x92E0, 0xE87A, 0x92E1, 0xE8A2, 0x92E4, 0xBE53, 0x92E6, 0xE876, 0x92E7, 0xE87C, 0x92E8, 0xE872, 0x92E9, 0xE86C, 0x92EA, 0xBE51, 0x92EE, 0xE4A8, 0x92EF, 0xE870, 0x92F0, 0xBE59, 0x92F1, 0xE869, 0x92F7, 0xEBF4, 0x92F8, 0xBFF7, 0x92F9, 0xEBF3, 0x92FA, 0xEBF0, 0x92FB, 0xEC44, 0x92FC, 0xBFFB, 0x92FE, 0xEC41, 0x92FF, 0xEBF8, 0x9300, 0xEC43, 0x9301, 0xEBE9, 0x9302, 0xEBF6, 0x9304, 0xBFFD, 0x9306, 0xEBE1, 0x9308, 0xEBDF, 0x9309, 0xEC42, 0x930B, 0xEC40, 0x930C, 0xEBFE, 0x930D, 0xEBED, 0x930E, 0xEBEC, 0x930F, 0xEBE2, 0x9310, 0xC040, 0x9312, 0xEBE8, 0x9313, 0xEBF2, 0x9314, 0xEBFD, 0x9315, 0xC043, 0x9316, 0xEC45, 0x9318, 0xC1E8, 0x9319, 0xC045, 0x931A, 0xBFFE, 0x931B, 0xEBE6, 0x931D, 0xEBEF, 0x931E, 0xEBDE, 0x931F, 0xEBE0, 0x9320, 0xBFF5, 0x9321, 0xC042, 0x9322, 0xBFFA, 0x9323, 0xEBE7, 0x9324, 0xEBF7, 0x9325, 0xEBF1, 0x9326, 0xC041, 0x9327, 0xEBDD, 0x9328, 0xC1E3, 0x9329, 0xEBF9, 0x932A, 0xEBFC, 0x932B, 0xBFFC, 0x932D, 0xEBEB, 0x932E, 0xC044, 0x932F, 0xBFF9, 0x9333, 0xBFF8, 0x9334, 0xEBF5, 0x9335, 0xEBFB, 0x9336, 0xBFF6, 0x9338, 0xEBE4, 0x9339, 0xEBFA, 0x933C, 0xEBE5, 0x9346, 0xEBEA, 0x9347, 0xEED2, 0x9349, 0xEED7, 0x934A, 0xC1E5, 0x934B, 0xC1E7, 0x934C, 0xEEDD, 0x934D, 0xC1E1, 0x934E, 0xEEEC, 0x934F, 0xEEE3, 0x9350, 0xEED8, 0x9351, 0xEED9, 0x9352, 0xEEE2, 0x9354, 0xC1EE, 0x9355, 0xEEE1, 0x9356, 0xEED1, 0x9357, 0xEEE0, 0x9358, 0xEED4, 0x9359, 0xEEED, 0x935A, 0xC1ED, 0x935B, 0xC1EB, 0x935C, 0xEED5, 0x935E, 0xEEE8, 0x9360, 0xEEDA, 0x9361, 0xEEE7, 0x9363, 0xEEE9, 0x9364, 0xEED0, 0x9365, 0xC1E6, 0x9367, 0xEEEA, 0x936A, 0xEEDE, 0x936C, 0xC1EA, 0x936D, 0xEEDB, 0x9370, 0xC1EC, 0x9371, 0xEEE4, 0x9375, 0xC1E4, 0x9376, 0xEED6, 0x9377, 0xEEE5, 0x9379, 0xEEDF, 0x937A, 0xEBE3, 0x937B, 0xEEE6, 0x937C, 0xEED3, 0x937E, 0xC1E9, 0x9380, 0xEEEB, 0x9382, 0xC1E2, 0x9383, 0xEECE, 0x9388, 0xF160, 0x9389, 0xF159, 0x938A, 0xC2E9, 0x938C, 0xF154, 0x938D, 0xF163, 0x938E, 0xF15B, 0x938F, 0xEEDC, 0x9391, 0xF165, 0x9392, 0xF155, 0x9394, 0xC2E8, 0x9395, 0xF15F, 0x9396, 0xC2EA, 0x9397, 0xC2F2, 0x9398, 0xC2F0, 0x9399, 0xF161, 0x939A, 0xC2F1, 0x939B, 0xF157, 0x939D, 0xF158, 0x939E, 0xF15D, 0x939F, 0xF162, 0x93A1, 0xEECD, 0x93A2, 0xC2EB, 0x93A3, 0xF16A, 0x93A4, 0xF167, 0x93A5, 0xF16B, 0x93A6, 0xF15E, 0x93A7, 0xF15A, 0x93A8, 0xF168, 0x93A9, 0xF36A, 0x93AA, 0xF15C, 0x93AC, 0xC2EE, 0x93AE, 0xC2ED, 0x93AF, 0xEECF, 0x93B0, 0xC2EF, 0x93B1, 0xF164, 0x93B2, 0xF166, 0x93B3, 0xC2EC, 0x93B4, 0xF169, 0x93B5, 0xF153, 0x93B7, 0xF156, 0x93C0, 0xF373, 0x93C2, 0xF363, 0x93C3, 0xC3EB, 0x93C4, 0xF371, 0x93C7, 0xF361, 0x93C8, 0xC3EC, 0x93CA, 0xF36C, 0x93CC, 0xF368, 0x93CD, 0xC3F1, 0x93CE, 0xF372, 0x93CF, 0xF362, 0x93D0, 0xF365, 0x93D1, 0xC3E9, 0x93D2, 0xF374, 0x93D4, 0xF36D, 0x93D5, 0xF370, 0x93D6, 0xC3EF, 0x93D7, 0xC3F4, 0x93D8, 0xC3F2, 0x93D9, 0xF369, 0x93DA, 0xF364, 0x93DC, 0xC3ED, 0x93DD, 0xC3EE, 0x93DE, 0xF360, 0x93DF, 0xC3EA, 0x93E1, 0xC3E8, 0x93E2, 0xC3F0, 0x93E3, 0xF36F, 0x93E4, 0xC3F3, 0x93E6, 0xF36B, 0x93E7, 0xF375, 0x93E8, 0xC3F5, 0x93EC, 0xF367, 0x93EE, 0xF36E, 0x93F5, 0xF4F3, 0x93F6, 0xF542, 0x93F7, 0xF4F5, 0x93F8, 0xF4FC, 0x93F9, 0xF366, 0x93FA, 0xF4FA, 0x93FB, 0xF4E9, 0x93FC, 0xF540, 0x93FD, 0xC4C3, 0x93FE, 0xF4ED, 0x93FF, 0xF4FE, 0x9400, 0xF4F4, 0x9403, 0xC4C2, 0x9406, 0xF544, 0x9407, 0xF4F6, 0x9409, 0xF4FB, 0x940A, 0xF4FD, 0x940B, 0xF4E7, 0x940C, 0xF541, 0x940D, 0xF4F2, 0x940E, 0xF4F7, 0x940F, 0xF4EB, 0x9410, 0xF4EF, 0x9411, 0xF543, 0x9412, 0xF4F9, 0x9413, 0xF4E8, 0x9414, 0xF4EC, 0x9415, 0xF4EE, 0x9416, 0xF4F8, 0x9418, 0xC4C1, 0x9419, 0xF4F1, 0x9420, 0xF4EA, 0x9428, 0xF4F0, 0x9429, 0xF661, 0x942A, 0xF666, 0x942B, 0xC54F, 0x942C, 0xF668, 0x942E, 0xC549, 0x9430, 0xF664, 0x9431, 0xF66A, 0x9432, 0xC54E, 0x9433, 0xC54A, 0x9435, 0xC54B, 0x9436, 0xF660, 0x9437, 0xF667, 0x9438, 0xC54D, 0x9439, 0xF665, 0x943A, 0xC54C, 0x943B, 0xF65F, 0x943C, 0xF663, 0x943D, 0xF662, 0x943F, 0xF65E, 0x9440, 0xF669, 0x9444, 0xC5B1, 0x9445, 0xF76D, 0x9446, 0xF770, 0x9447, 0xF76C, 0x9448, 0xF76E, 0x9449, 0xF76F, 0x944A, 0xF769, 0x944B, 0xF76A, 0x944C, 0xF767, 0x944F, 0xF76B, 0x9450, 0xF768, 0x9451, 0xC5B2, 0x9452, 0xC5B3, 0x9455, 0xF84B, 0x9457, 0xF84D, 0x945D, 0xF84C, 0x945E, 0xF84E, 0x9460, 0xC5E0, 0x9462, 0xF84A, 0x9463, 0xC5DF, 0x9464, 0xC5E1, 0x9468, 0xF8CB, 0x9469, 0xF8CC, 0x946A, 0xC644, 0x946B, 0xF8CA, 0x946D, 0xF953, 0x946E, 0xF952, 0x946F, 0xF954, 0x9470, 0xC65F, 0x9471, 0xF955, 0x9472, 0xC65E, 0x9473, 0xF956, 0x9474, 0xF972, 0x9475, 0xF975, 0x9476, 0xF974, 0x9477, 0xC668, 0x9478, 0xF973, 0x947C, 0xC672, 0x947D, 0xC670, 0x947E, 0xC671, 0x947F, 0xC677, 0x9480, 0xF9C0, 0x9481, 0xF9C1, 0x9482, 0xF9BF, 0x9483, 0xF9C9, 0x9577, 0xAAF8, 0x957A, 0xD844, 0x957B, 0xDC78, 0x957C, 0xE8A5, 0x957D, 0xF376, 0x9580, 0xAAF9, 0x9582, 0xADAC, 0x9583, 0xB07B, 0x9586, 0xD845, 0x9588, 0xD846, 0x9589, 0xB3AC, 0x958B, 0xB67D, 0x958C, 0xDC7A, 0x958D, 0xDC79, 0x958E, 0xB6A3, 0x958F, 0xB67C, 0x9590, 0xDC7B, 0x9591, 0xB67E, 0x9592, 0xB6A2, 0x9593, 0xB6A1, 0x9594, 0xB67B, 0x9598, 0xB968, 0x959B, 0xE0D0, 0x959C, 0xE0CE, 0x959E, 0xE0CF, 0x959F, 0xE0CD, 0x95A1, 0xBBD2, 0x95A3, 0xBBD5, 0x95A4, 0xBBD7, 0x95A5, 0xBBD6, 0x95A8, 0xBBD3, 0x95A9, 0xBBD4, 0x95AB, 0xE8A7, 0x95AC, 0xE8A6, 0x95AD, 0xBE5B, 0x95AE, 0xE8A8, 0x95B0, 0xE8A9, 0x95B1, 0xBE5C, 0x95B5, 0xEC4D, 0x95B6, 0xEC4B, 0x95B7, 0xEEF3, 0x95B9, 0xEC49, 0x95BA, 0xEC4A, 0x95BB, 0xC046, 0x95BC, 0xEC46, 0x95BD, 0xEC4E, 0x95BE, 0xEC48, 0x95BF, 0xEC4C, 0x95C0, 0xEEEF, 0x95C3, 0xEEF1, 0x95C5, 0xEEF2, 0x95C6, 0xC1F3, 0x95C7, 0xEEEE, 0x95C8, 0xC1F2, 0x95C9, 0xEEF0, 0x95CA, 0xC1EF, 0x95CB, 0xC1F0, 0x95CC, 0xC1F1, 0x95CD, 0xEC47, 0x95D0, 0xC2F5, 0x95D1, 0xF16E, 0x95D2, 0xF16C, 0x95D3, 0xF16D, 0x95D4, 0xC2F3, 0x95D5, 0xC2F6, 0x95D6, 0xC2F4, 0x95DA, 0xF377, 0x95DB, 0xF378, 0x95DC, 0xC3F6, 0x95DE, 0xF545, 0x95DF, 0xF547, 0x95E0, 0xF546, 0x95E1, 0xC4C4, 0x95E2, 0xC550, 0x95E3, 0xF66D, 0x95E4, 0xF66C, 0x95E5, 0xF66B, 0x961C, 0xAAFA, 0x961E, 0xC9AA, 0x9620, 0xCA58, 0x9621, 0xA6E9, 0x9622, 0xCA56, 0x9623, 0xCA59, 0x9624, 0xCA57, 0x9628, 0xCBAE, 0x962A, 0xA8C1, 0x962C, 0xA8C2, 0x962D, 0xCBB0, 0x962E, 0xA8BF, 0x962F, 0xCBAF, 0x9630, 0xCBAD, 0x9631, 0xA8C0, 0x9632, 0xA8BE, 0x9639, 0xCDD8, 0x963A, 0xCDDB, 0x963B, 0xAAFD, 0x963C, 0xCDDA, 0x963D, 0xCDD9, 0x963F, 0xAAFC, 0x9640, 0xAAFB, 0x9642, 0xAB40, 0x9643, 0xCDDC, 0x9644, 0xAAFE, 0x964A, 0xD0C6, 0x964B, 0xADAE, 0x964C, 0xADAF, 0x964D, 0xADB0, 0x964E, 0xD0C7, 0x964F, 0xD0C3, 0x9650, 0xADAD, 0x9651, 0xD0C4, 0x9653, 0xD0C5, 0x9654, 0xD0C2, 0x9658, 0xB0A4, 0x965B, 0xB0A1, 0x965C, 0xD445, 0x965D, 0xB0A2, 0x965E, 0xB0A5, 0x965F, 0xD446, 0x9661, 0xB07E, 0x9662, 0xB07C, 0x9663, 0xB07D, 0x9664, 0xB0A3, 0x966A, 0xB3AD, 0x966B, 0xD849, 0x966C, 0xB3B5, 0x966D, 0xD848, 0x966F, 0xD84B, 0x9670, 0xB3B1, 0x9671, 0xD84A, 0x9672, 0xB6AB, 0x9673, 0xB3AF, 0x9674, 0xB3B2, 0x9675, 0xB3AE, 0x9676, 0xB3B3, 0x9677, 0xB3B4, 0x9678, 0xB3B0, 0x967C, 0xD847, 0x967D, 0xB6A7, 0x967E, 0xDC7D, 0x9680, 0xDCA3, 0x9683, 0xDCA2, 0x9684, 0xB6AC, 0x9685, 0xB6A8, 0x9686, 0xB6A9, 0x9687, 0xDC7C, 0x9688, 0xDC7E, 0x9689, 0xDCA1, 0x968A, 0xB6A4, 0x968B, 0xB6A6, 0x968D, 0xB6AA, 0x968E, 0xB6A5, 0x9691, 0xE0D3, 0x9692, 0xE0D1, 0x9693, 0xE0D2, 0x9694, 0xB96A, 0x9695, 0xB96B, 0x9697, 0xE0D4, 0x9698, 0xB969, 0x9699, 0xBBD8, 0x969B, 0xBBDA, 0x969C, 0xBBD9, 0x969E, 0xE4BB, 0x96A1, 0xE4BC, 0x96A2, 0xE8AB, 0x96A4, 0xE8AA, 0x96A7, 0xC047, 0x96A8, 0xC048, 0x96A9, 0xEC4F, 0x96AA, 0xC049, 0x96AC, 0xEEF6, 0x96AE, 0xEEF4, 0x96B0, 0xEEF5, 0x96B1, 0xC1F4, 0x96B3, 0xF16F, 0x96B4, 0xC3F7, 0x96B8, 0xC1F5, 0x96B9, 0xAB41, 0x96BB, 0xB0A6, 0x96BC, 0xD447, 0x96BF, 0xD84C, 0x96C0, 0xB3B6, 0x96C1, 0xB6AD, 0x96C2, 0xDCA4, 0x96C3, 0xDCA6, 0x96C4, 0xB6AF, 0x96C5, 0xB6AE, 0x96C6, 0xB6B0, 0x96C7, 0xB6B1, 0x96C8, 0xDCA5, 0x96C9, 0xB96E, 0x96CA, 0xB96F, 0x96CB, 0xB96D, 0x96CC, 0xBBDB, 0x96CD, 0xB96C, 0x96CE, 0xE0D5, 0x96D2, 0xBBDC, 0x96D3, 0xE8AC, 0x96D4, 0xEC50, 0x96D5, 0xC04A, 0x96D6, 0xC1F6, 0x96D7, 0xF170, 0x96D8, 0xF174, 0x96D9, 0xC2F9, 0x96DA, 0xF171, 0x96DB, 0xC2FA, 0x96DC, 0xC2F8, 0x96DD, 0xF175, 0x96DE, 0xC2FB, 0x96DF, 0xF173, 0x96E1, 0xF379, 0x96E2, 0xC2F7, 0x96E3, 0xC3F8, 0x96E5, 0xF8CD, 0x96E8, 0xAB42, 0x96E9, 0xB3B8, 0x96EA, 0xB3B7, 0x96EF, 0xB6B2, 0x96F0, 0xDCA8, 0x96F1, 0xDCA7, 0x96F2, 0xB6B3, 0x96F5, 0xE0D9, 0x96F6, 0xB973, 0x96F7, 0xB970, 0x96F8, 0xE0D8, 0x96F9, 0xB972, 0x96FA, 0xE0D6, 0x96FB, 0xB971, 0x96FD, 0xE0D7, 0x96FF, 0xE4BD, 0x9700, 0xBBDD, 0x9702, 0xE8AF, 0x9704, 0xBE5D, 0x9705, 0xE8AD, 0x9706, 0xBE5E, 0x9707, 0xBE5F, 0x9708, 0xE8AE, 0x9709, 0xBE60, 0x970B, 0xEC51, 0x970D, 0xC04E, 0x970E, 0xC04B, 0x970F, 0xC050, 0x9710, 0xEC53, 0x9711, 0xC04C, 0x9712, 0xEC52, 0x9713, 0xC04F, 0x9716, 0xC04D, 0x9718, 0xEEF9, 0x9719, 0xEEFB, 0x971C, 0xC1F7, 0x971D, 0xEEFA, 0x971E, 0xC1F8, 0x971F, 0xEEF8, 0x9720, 0xEEF7, 0x9722, 0xF177, 0x9723, 0xF176, 0x9724, 0xC2FC, 0x9725, 0xF178, 0x9726, 0xF37E, 0x9727, 0xC3FA, 0x9728, 0xF37D, 0x9729, 0xF37A, 0x972A, 0xC3F9, 0x972B, 0xF37B, 0x972C, 0xF37C, 0x972E, 0xF548, 0x972F, 0xF549, 0x9730, 0xC4C5, 0x9732, 0xC553, 0x9735, 0xF66E, 0x9738, 0xC551, 0x9739, 0xC552, 0x973A, 0xF66F, 0x973D, 0xC5B4, 0x973E, 0xC5B5, 0x973F, 0xF771, 0x9742, 0xC645, 0x9743, 0xF8CF, 0x9744, 0xC647, 0x9746, 0xF8CE, 0x9747, 0xF8D0, 0x9748, 0xC646, 0x9749, 0xF957, 0x974B, 0xF9AD, 0x9752, 0xAB43, 0x9756, 0xB974, 0x9758, 0xE4BE, 0x975A, 0xE8B0, 0x975B, 0xC051, 0x975C, 0xC052, 0x975E, 0xAB44, 0x9760, 0xBE61, 0x9761, 0xC3FB, 0x9762, 0xADB1, 0x9766, 0xC053, 0x9768, 0xC5E2, 0x9769, 0xADB2, 0x976A, 0xD84D, 0x976C, 0xDCA9, 0x976E, 0xDCAB, 0x9770, 0xDCAA, 0x9772, 0xE0DD, 0x9773, 0xE0DA, 0x9774, 0xB975, 0x9776, 0xB976, 0x9777, 0xE0DB, 0x9778, 0xE0DC, 0x977A, 0xE4C0, 0x977B, 0xE4C5, 0x977C, 0xBBDE, 0x977D, 0xE4BF, 0x977E, 0xE4C1, 0x977F, 0xE4C8, 0x9780, 0xE4C3, 0x9781, 0xE4C7, 0x9782, 0xE4C4, 0x9783, 0xE4C2, 0x9784, 0xE4C6, 0x9785, 0xBBDF, 0x9788, 0xE8B3, 0x978A, 0xE8B1, 0x978B, 0xBE63, 0x978D, 0xBE62, 0x978E, 0xE8B2, 0x978F, 0xBE64, 0x9794, 0xEC56, 0x9797, 0xEC55, 0x9798, 0xC054, 0x9799, 0xEC54, 0x979A, 0xEEFC, 0x979C, 0xEEFE, 0x979D, 0xEF41, 0x979E, 0xEF40, 0x97A0, 0xC1F9, 0x97A1, 0xEEFD, 0x97A2, 0xF1A1, 0x97A3, 0xC2FD, 0x97A4, 0xF17D, 0x97A5, 0xF1A2, 0x97A6, 0xC2FE, 0x97A8, 0xF17B, 0x97AA, 0xF17E, 0x97AB, 0xF17C, 0x97AC, 0xF179, 0x97AD, 0xC340, 0x97AE, 0xF17A, 0x97B3, 0xF3A1, 0x97B6, 0xF3A3, 0x97B7, 0xF3A2, 0x97B9, 0xF54A, 0x97BB, 0xF54B, 0x97BF, 0xF670, 0x97C1, 0xC5B7, 0x97C3, 0xC5B6, 0x97C4, 0xF84F, 0x97C5, 0xF850, 0x97C6, 0xC648, 0x97C7, 0xF8D1, 0x97C9, 0xC669, 0x97CB, 0xADB3, 0x97CC, 0xB6B4, 0x97CD, 0xE4CA, 0x97CE, 0xE4C9, 0x97CF, 0xE8B5, 0x97D0, 0xE8B4, 0x97D3, 0xC1FA, 0x97D4, 0xEF43, 0x97D5, 0xEF42, 0x97D6, 0xF1A5, 0x97D7, 0xF1A3, 0x97D8, 0xF1A6, 0x97D9, 0xF1A4, 0x97DC, 0xC3FC, 0x97DD, 0xF3A4, 0x97DE, 0xF3A5, 0x97DF, 0xF3A6, 0x97E1, 0xF671, 0x97E3, 0xF772, 0x97E5, 0xF8D2, 0x97ED, 0xADB4, 0x97F0, 0xEC57, 0x97F1, 0xEF44, 0x97F3, 0xADB5, 0x97F6, 0xBBE0, 0x97F8, 0xEC58, 0x97F9, 0xC341, 0x97FA, 0xF1A7, 0x97FB, 0xC3FD, 0x97FD, 0xF54C, 0x97FE, 0xF54D, 0x97FF, 0xC554, 0x9800, 0xF851, 0x9801, 0xADB6, 0x9802, 0xB3BB, 0x9803, 0xB3BC, 0x9804, 0xD84E, 0x9805, 0xB6B5, 0x9806, 0xB6B6, 0x9807, 0xDCAC, 0x9808, 0xB6B7, 0x980A, 0xB97A, 0x980C, 0xB97C, 0x980D, 0xE0DF, 0x980E, 0xE0E0, 0x980F, 0xE0DE, 0x9810, 0xB977, 0x9811, 0xB978, 0x9812, 0xB97B, 0x9813, 0xB979, 0x9816, 0xE4CB, 0x9817, 0xBBE1, 0x9818, 0xBBE2, 0x981B, 0xE8BC, 0x981C, 0xBE67, 0x981D, 0xE8B7, 0x981E, 0xE8B6, 0x9820, 0xE8BB, 0x9821, 0xBE65, 0x9824, 0xC05B, 0x9826, 0xE8B8, 0x9827, 0xE8BD, 0x9828, 0xE8BA, 0x9829, 0xE8B9, 0x982B, 0xBE66, 0x982D, 0xC059, 0x982F, 0xEC5A, 0x9830, 0xC055, 0x9832, 0xEC5B, 0x9835, 0xEC59, 0x9837, 0xC058, 0x9838, 0xC056, 0x9839, 0xC05A, 0x983B, 0xC057, 0x9841, 0xEF45, 0x9843, 0xEF4A, 0x9844, 0xEF46, 0x9845, 0xEF49, 0x9846, 0xC1FB, 0x9848, 0xEDD4, 0x9849, 0xEF48, 0x984A, 0xEF47, 0x984C, 0xC344, 0x984D, 0xC342, 0x984E, 0xC345, 0x984F, 0xC343, 0x9850, 0xF1A8, 0x9851, 0xF1A9, 0x9852, 0xF1AA, 0x9853, 0xC346, 0x9857, 0xF3AA, 0x9858, 0xC440, 0x9859, 0xF3A8, 0x985B, 0xC441, 0x985C, 0xF3A7, 0x985D, 0xF3A9, 0x985E, 0xC3FE, 0x985F, 0xF551, 0x9860, 0xF54E, 0x9862, 0xF54F, 0x9863, 0xF550, 0x9864, 0xF672, 0x9865, 0xC556, 0x9867, 0xC555, 0x9869, 0xF774, 0x986A, 0xF773, 0x986B, 0xC5B8, 0x986F, 0xC5E3, 0x9870, 0xC649, 0x9871, 0xC660, 0x9872, 0xF958, 0x9873, 0xF9AE, 0x9874, 0xF9AF, 0x98A8, 0xADB7, 0x98A9, 0xDCAD, 0x98AC, 0xE0E1, 0x98AD, 0xE4CC, 0x98AE, 0xE4CD, 0x98AF, 0xBBE3, 0x98B1, 0xBBE4, 0x98B2, 0xE8BE, 0x98B3, 0xBE68, 0x98B6, 0xC1FC, 0x98B8, 0xF1AB, 0x98BA, 0xC347, 0x98BB, 0xF3AD, 0x98BC, 0xC442, 0x98BD, 0xF3AC, 0x98BE, 0xF3AE, 0x98BF, 0xF3AB, 0x98C0, 0xF675, 0x98C1, 0xF552, 0x98C2, 0xF553, 0x98C4, 0xC4C6, 0x98C6, 0xF674, 0x98C9, 0xF673, 0x98CB, 0xF775, 0x98CC, 0xF9B0, 0x98DB, 0xADB8, 0x98DF, 0xADB9, 0x98E2, 0xB0A7, 0x98E3, 0xD448, 0x98E5, 0xD84F, 0x98E7, 0xB6B8, 0x98E9, 0xB6BB, 0x98EA, 0xB6B9, 0x98EB, 0xDCAE, 0x98ED, 0xB6BD, 0x98EF, 0xB6BA, 0x98F2, 0xB6BC, 0x98F4, 0xB97E, 0x98F6, 0xE0E2, 0x98F9, 0xE0E3, 0x98FA, 0xE8C0, 0x98FC, 0xB97D, 0x98FD, 0xB9A1, 0x98FE, 0xB9A2, 0x9900, 0xE4CF, 0x9902, 0xE4CE, 0x9903, 0xBBE5, 0x9905, 0xBBE6, 0x9907, 0xE4D0, 0x9908, 0xE8BF, 0x9909, 0xBBE8, 0x990A, 0xBE69, 0x990C, 0xBBE7, 0x9910, 0xC05C, 0x9911, 0xE8C1, 0x9912, 0xBE6B, 0x9913, 0xBE6A, 0x9914, 0xE8C2, 0x9915, 0xE8C5, 0x9916, 0xE8C3, 0x9917, 0xE8C4, 0x9918, 0xBE6C, 0x991A, 0xC061, 0x991B, 0xC05F, 0x991E, 0xC05E, 0x991F, 0xEC5D, 0x9921, 0xC060, 0x9924, 0xEC5C, 0x9925, 0xEF4B, 0x9927, 0xEC5E, 0x9928, 0xC05D, 0x9929, 0xEC5F, 0x992A, 0xEF4E, 0x992B, 0xEF4C, 0x992C, 0xEF4D, 0x992D, 0xEF52, 0x992E, 0xC34B, 0x992F, 0xEF51, 0x9930, 0xEF54, 0x9931, 0xEF53, 0x9932, 0xEF50, 0x9933, 0xEF4F, 0x9935, 0xC1FD, 0x993A, 0xF1AE, 0x993C, 0xF1AD, 0x993D, 0xC34A, 0x993E, 0xC348, 0x993F, 0xC349, 0x9941, 0xF1AC, 0x9943, 0xF3B1, 0x9945, 0xC443, 0x9947, 0xF3B0, 0x9948, 0xF3AF, 0x9949, 0xC444, 0x994B, 0xF558, 0x994C, 0xF557, 0x994E, 0xF555, 0x9950, 0xF554, 0x9951, 0xC4C8, 0x9952, 0xC4C7, 0x9953, 0xF559, 0x9954, 0xF776, 0x9955, 0xC5B9, 0x9956, 0xF677, 0x9957, 0xC557, 0x9958, 0xF676, 0x9959, 0xF556, 0x995B, 0xF777, 0x995C, 0xC5E4, 0x995E, 0xC661, 0x995F, 0xF959, 0x9961, 0xF9B1, 0x9996, 0xADBA, 0x9997, 0xD850, 0x9998, 0xEF55, 0x9999, 0xADBB, 0x999C, 0xE4D2, 0x999D, 0xE4D1, 0x999E, 0xEC60, 0x99A1, 0xEF57, 0x99A3, 0xEF56, 0x99A5, 0xC34C, 0x99A6, 0xF3B2, 0x99A7, 0xF3B3, 0x99A8, 0xC4C9, 0x99AB, 0xF9B2, 0x99AC, 0xB0A8, 0x99AD, 0xB6BF, 0x99AE, 0xB6BE, 0x99AF, 0xE0E4, 0x99B0, 0xE0E6, 0x99B1, 0xB9A4, 0x99B2, 0xE0E5, 0x99B3, 0xB9A3, 0x99B4, 0xB9A5, 0x99B5, 0xE0E7, 0x99B9, 0xE4D4, 0x99BA, 0xE4D6, 0x99BB, 0xE4D5, 0x99BD, 0xE4D8, 0x99C1, 0xBBE9, 0x99C2, 0xE4D7, 0x99C3, 0xE4D3, 0x99C7, 0xE4D9, 0x99C9, 0xE8CC, 0x99CB, 0xE8CF, 0x99CC, 0xE8D1, 0x99CD, 0xE8C7, 0x99CE, 0xE8CB, 0x99CF, 0xE8C8, 0x99D0, 0xBE6E, 0x99D1, 0xBE71, 0x99D2, 0xBE73, 0x99D3, 0xE8C9, 0x99D4, 0xE8CA, 0x99D5, 0xBE72, 0x99D6, 0xE8CD, 0x99D7, 0xE8D0, 0x99D8, 0xE8CE, 0x99D9, 0xBE74, 0x99DB, 0xBE70, 0x99DC, 0xE8C6, 0x99DD, 0xBE6D, 0x99DF, 0xBE6F, 0x99E2, 0xC063, 0x99E3, 0xEC66, 0x99E4, 0xEC64, 0x99E5, 0xEC63, 0x99E7, 0xEC69, 0x99E9, 0xEC68, 0x99EA, 0xEC67, 0x99EC, 0xEC62, 0x99ED, 0xC062, 0x99EE, 0xEC61, 0x99F0, 0xEC65, 0x99F1, 0xC064, 0x99F4, 0xEF5A, 0x99F6, 0xEF5E, 0x99F7, 0xEF5B, 0x99F8, 0xEF5D, 0x99F9, 0xEF5C, 0x99FA, 0xEF59, 0x99FB, 0xEF5F, 0x99FC, 0xEF62, 0x99FD, 0xEF60, 0x99FE, 0xEF61, 0x99FF, 0xC240, 0x9A01, 0xC1FE, 0x9A02, 0xEF58, 0x9A03, 0xEF63, 0x9A04, 0xF1B3, 0x9A05, 0xF1B6, 0x9A06, 0xF1B8, 0x9A07, 0xF1B7, 0x9A09, 0xF1B1, 0x9A0A, 0xF1B5, 0x9A0B, 0xF1B0, 0x9A0D, 0xF1B2, 0x9A0E, 0xC34D, 0x9A0F, 0xF1AF, 0x9A11, 0xF1B4, 0x9A14, 0xF3C0, 0x9A15, 0xF3B5, 0x9A16, 0xC445, 0x9A19, 0xC446, 0x9A1A, 0xF3B4, 0x9A1B, 0xF3B9, 0x9A1C, 0xF3BF, 0x9A1D, 0xF3B7, 0x9A1E, 0xF3BE, 0x9A20, 0xF3BB, 0x9A22, 0xF3BA, 0x9A23, 0xF3BD, 0x9A24, 0xF3B8, 0x9A25, 0xF3B6, 0x9A27, 0xF3BC, 0x9A29, 0xF560, 0x9A2A, 0xF55E, 0x9A2B, 0xC4CA, 0x9A2C, 0xF55D, 0x9A2D, 0xF563, 0x9A2E, 0xF561, 0x9A30, 0xC4CB, 0x9A31, 0xF55C, 0x9A32, 0xF55A, 0x9A34, 0xF55B, 0x9A35, 0xC4CD, 0x9A36, 0xF55F, 0x9A37, 0xC4CC, 0x9A38, 0xF562, 0x9A39, 0xF678, 0x9A3A, 0xF67E, 0x9A3D, 0xF679, 0x9A3E, 0xC55B, 0x9A3F, 0xF6A1, 0x9A40, 0xC55A, 0x9A41, 0xF67D, 0x9A42, 0xF67C, 0x9A43, 0xC559, 0x9A44, 0xF67B, 0x9A45, 0xC558, 0x9A46, 0xF67A, 0x9A48, 0xF77D, 0x9A49, 0xF7A1, 0x9A4A, 0xF77E, 0x9A4C, 0xF77B, 0x9A4D, 0xC5BB, 0x9A4E, 0xF778, 0x9A4F, 0xF77C, 0x9A50, 0xF7A3, 0x9A52, 0xF7A2, 0x9A53, 0xF779, 0x9A54, 0xF77A, 0x9A55, 0xC5BA, 0x9A56, 0xF852, 0x9A57, 0xC5E7, 0x9A59, 0xF853, 0x9A5A, 0xC5E5, 0x9A5B, 0xC5E6, 0x9A5E, 0xF8D3, 0x9A5F, 0xC64A, 0x9A60, 0xF976, 0x9A62, 0xC66A, 0x9A64, 0xF9B3, 0x9A65, 0xC66B, 0x9A66, 0xF9B4, 0x9A67, 0xF9B5, 0x9A68, 0xF9C3, 0x9A69, 0xF9C2, 0x9A6A, 0xC67A, 0x9A6B, 0xF9CD, 0x9AA8, 0xB0A9, 0x9AAB, 0xE0E9, 0x9AAD, 0xE0E8, 0x9AAF, 0xBBEA, 0x9AB0, 0xBBEB, 0x9AB1, 0xE4DA, 0x9AB3, 0xE8D2, 0x9AB4, 0xEC6C, 0x9AB7, 0xBE75, 0x9AB8, 0xC065, 0x9AB9, 0xEC6A, 0x9ABB, 0xEC6D, 0x9ABC, 0xC066, 0x9ABE, 0xEF64, 0x9ABF, 0xEC6B, 0x9AC0, 0xF1B9, 0x9AC1, 0xC34E, 0x9AC2, 0xF3C1, 0x9AC6, 0xF566, 0x9AC7, 0xF564, 0x9ACA, 0xF565, 0x9ACD, 0xF6A2, 0x9ACF, 0xC55C, 0x9AD0, 0xF7A4, 0x9AD1, 0xC5EA, 0x9AD2, 0xC5BC, 0x9AD3, 0xC5E8, 0x9AD4, 0xC5E9, 0x9AD5, 0xF8D4, 0x9AD6, 0xC662, 0x9AD8, 0xB0AA, 0x9ADC, 0xF1BA, 0x9ADF, 0xD449, 0x9AE1, 0xB9A6, 0x9AE3, 0xE4DB, 0x9AE6, 0xBBEC, 0x9AE7, 0xE4DC, 0x9AEB, 0xE8D4, 0x9AEC, 0xE8D3, 0x9AED, 0xC068, 0x9AEE, 0xBE76, 0x9AEF, 0xBE77, 0x9AF1, 0xE8D7, 0x9AF2, 0xE8D6, 0x9AF3, 0xE8D5, 0x9AF6, 0xEC6E, 0x9AF7, 0xEC71, 0x9AF9, 0xEC70, 0x9AFA, 0xEC6F, 0x9AFB, 0xC067, 0x9AFC, 0xEF68, 0x9AFD, 0xEF66, 0x9AFE, 0xEF65, 0x9B01, 0xEF67, 0x9B03, 0xC34F, 0x9B04, 0xF1BC, 0x9B05, 0xF1BD, 0x9B06, 0xC350, 0x9B08, 0xF1BB, 0x9B0A, 0xF3C3, 0x9B0B, 0xF3C2, 0x9B0C, 0xF3C5, 0x9B0D, 0xC447, 0x9B0E, 0xF3C4, 0x9B10, 0xF567, 0x9B11, 0xF569, 0x9B12, 0xF568, 0x9B15, 0xF6A3, 0x9B16, 0xF6A6, 0x9B17, 0xF6A4, 0x9B18, 0xF6A5, 0x9B19, 0xF7A5, 0x9B1A, 0xC5BD, 0x9B1E, 0xF854, 0x9B1F, 0xF855, 0x9B20, 0xF856, 0x9B22, 0xC64B, 0x9B23, 0xC663, 0x9B24, 0xF9B6, 0x9B25, 0xB0AB, 0x9B27, 0xBE78, 0x9B28, 0xC069, 0x9B29, 0xF1BE, 0x9B2B, 0xF7A6, 0x9B2E, 0xF9C4, 0x9B2F, 0xD44A, 0x9B31, 0xC67B, 0x9B32, 0xB0AC, 0x9B33, 0xEC72, 0x9B35, 0xF1BF, 0x9B37, 0xF3C6, 0x9B3A, 0xF6A7, 0x9B3B, 0xF7A7, 0x9B3C, 0xB0AD, 0x9B3E, 0xE4DD, 0x9B3F, 0xE4DE, 0x9B41, 0xBBED, 0x9B42, 0xBBEE, 0x9B43, 0xE8D9, 0x9B44, 0xBE7A, 0x9B45, 0xBE79, 0x9B46, 0xE8D8, 0x9B48, 0xEF69, 0x9B4A, 0xF1C0, 0x9B4B, 0xF1C2, 0x9B4C, 0xF1C1, 0x9B4D, 0xC353, 0x9B4E, 0xC352, 0x9B4F, 0xC351, 0x9B51, 0xC55E, 0x9B52, 0xF6A8, 0x9B54, 0xC55D, 0x9B55, 0xF7A9, 0x9B56, 0xF7A8, 0x9B58, 0xC64C, 0x9B59, 0xF8D5, 0x9B5A, 0xB3BD, 0x9B5B, 0xE0EA, 0x9B5F, 0xE4E1, 0x9B60, 0xE4DF, 0x9B61, 0xE4E0, 0x9B64, 0xE8E2, 0x9B66, 0xE8DD, 0x9B67, 0xE8DA, 0x9B68, 0xE8E1, 0x9B6C, 0xE8E3, 0x9B6F, 0xBE7C, 0x9B70, 0xE8E0, 0x9B71, 0xE8DC, 0x9B74, 0xE8DB, 0x9B75, 0xE8DF, 0x9B76, 0xE8DE, 0x9B77, 0xBE7B, 0x9B7A, 0xEC7D, 0x9B7B, 0xEC78, 0x9B7C, 0xEC76, 0x9B7D, 0xECA1, 0x9B7E, 0xEC77, 0x9B80, 0xEC73, 0x9B82, 0xEC79, 0x9B85, 0xEC74, 0x9B86, 0xEF72, 0x9B87, 0xEC75, 0x9B88, 0xECA2, 0x9B90, 0xEC7C, 0x9B91, 0xC06A, 0x9B92, 0xEC7B, 0x9B93, 0xEC7A, 0x9B95, 0xEC7E, 0x9B9A, 0xEF6A, 0x9B9B, 0xEF6D, 0x9B9E, 0xEF6C, 0x9BA0, 0xEF74, 0x9BA1, 0xEF6F, 0x9BA2, 0xEF73, 0x9BA4, 0xEF71, 0x9BA5, 0xEF70, 0x9BA6, 0xEF6E, 0x9BA8, 0xEF6B, 0x9BAA, 0xC243, 0x9BAB, 0xC242, 0x9BAD, 0xC244, 0x9BAE, 0xC241, 0x9BAF, 0xEF75, 0x9BB5, 0xF1C8, 0x9BB6, 0xF1CB, 0x9BB8, 0xF1C9, 0x9BB9, 0xF1CD, 0x9BBD, 0xF1CE, 0x9BBF, 0xF1C6, 0x9BC0, 0xC358, 0x9BC1, 0xF1C7, 0x9BC3, 0xF1C5, 0x9BC4, 0xF1CC, 0x9BC6, 0xF1C4, 0x9BC7, 0xF1C3, 0x9BC8, 0xC357, 0x9BC9, 0xC355, 0x9BCA, 0xC354, 0x9BD3, 0xF1CA, 0x9BD4, 0xF3CF, 0x9BD5, 0xF3D5, 0x9BD6, 0xC44A, 0x9BD7, 0xF3D0, 0x9BD9, 0xF3D3, 0x9BDA, 0xF3D7, 0x9BDB, 0xC44B, 0x9BDC, 0xF3D2, 0x9BDE, 0xF3CA, 0x9BE0, 0xF3C9, 0x9BE1, 0xF3D6, 0x9BE2, 0xF3CD, 0x9BE4, 0xF3CB, 0x9BE5, 0xF3D4, 0x9BE6, 0xF3CC, 0x9BE7, 0xC449, 0x9BE8, 0xC448, 0x9BEA, 0xF3C7, 0x9BEB, 0xF3C8, 0x9BEC, 0xF3D1, 0x9BF0, 0xF3CE, 0x9BF7, 0xF56C, 0x9BF8, 0xF56F, 0x9BFD, 0xC356, 0x9C05, 0xF56D, 0x9C06, 0xF573, 0x9C07, 0xF571, 0x9C08, 0xF56B, 0x9C09, 0xF576, 0x9C0B, 0xF56A, 0x9C0D, 0xC4CF, 0x9C0E, 0xF572, 0x9C12, 0xF56E, 0x9C13, 0xC4CE, 0x9C14, 0xF575, 0x9C17, 0xF574, 0x9C1C, 0xF6AB, 0x9C1D, 0xF6AA, 0x9C21, 0xF6B1, 0x9C23, 0xF6AD, 0x9C24, 0xF6B0, 0x9C25, 0xC560, 0x9C28, 0xF6AE, 0x9C29, 0xF6AF, 0x9C2B, 0xF6A9, 0x9C2C, 0xF6AC, 0x9C2D, 0xC55F, 0x9C31, 0xC5BF, 0x9C32, 0xF7B4, 0x9C33, 0xF7AF, 0x9C34, 0xF7B3, 0x9C36, 0xF7B6, 0x9C37, 0xF7B2, 0x9C39, 0xF7AE, 0x9C3B, 0xC5C1, 0x9C3C, 0xF7B1, 0x9C3D, 0xF7B5, 0x9C3E, 0xC5C0, 0x9C3F, 0xF7AC, 0x9C40, 0xF570, 0x9C41, 0xF7B0, 0x9C44, 0xF7AD, 0x9C46, 0xF7AA, 0x9C48, 0xF7AB, 0x9C49, 0xC5BE, 0x9C4A, 0xF85A, 0x9C4B, 0xF85C, 0x9C4C, 0xF85F, 0x9C4D, 0xF85B, 0x9C4E, 0xF860, 0x9C50, 0xF859, 0x9C52, 0xF857, 0x9C54, 0xC5EB, 0x9C55, 0xF85D, 0x9C56, 0xC5ED, 0x9C57, 0xC5EC, 0x9C58, 0xF858, 0x9C59, 0xF85E, 0x9C5E, 0xF8DA, 0x9C5F, 0xC64D, 0x9C60, 0xF8DB, 0x9C62, 0xF8D9, 0x9C63, 0xF8D6, 0x9C66, 0xF8D8, 0x9C67, 0xF8D7, 0x9C68, 0xF95A, 0x9C6D, 0xF95C, 0x9C6E, 0xF95B, 0x9C71, 0xF979, 0x9C73, 0xF978, 0x9C74, 0xF977, 0x9C75, 0xF97A, 0x9C77, 0xC673, 0x9C78, 0xC674, 0x9C79, 0xF9CA, 0x9C7A, 0xF9CE, 0x9CE5, 0xB3BE, 0x9CE6, 0xDCAF, 0x9CE7, 0xE0ED, 0x9CE9, 0xB9A7, 0x9CEA, 0xE0EB, 0x9CED, 0xE0EC, 0x9CF1, 0xE4E2, 0x9CF2, 0xE4E3, 0x9CF3, 0xBBF1, 0x9CF4, 0xBBEF, 0x9CF5, 0xE4E4, 0x9CF6, 0xBBF0, 0x9CF7, 0xE8E8, 0x9CF9, 0xE8EB, 0x9CFA, 0xE8E5, 0x9CFB, 0xE8EC, 0x9CFC, 0xE8E4, 0x9CFD, 0xE8E6, 0x9CFF, 0xE8E7, 0x9D00, 0xE8EA, 0x9D03, 0xBEA1, 0x9D04, 0xE8EF, 0x9D05, 0xE8EE, 0x9D06, 0xBE7D, 0x9D07, 0xE8E9, 0x9D08, 0xE8ED, 0x9D09, 0xBE7E, 0x9D10, 0xECAC, 0x9D12, 0xC06F, 0x9D14, 0xECA7, 0x9D15, 0xC06B, 0x9D17, 0xECA4, 0x9D18, 0xECAA, 0x9D19, 0xECAD, 0x9D1B, 0xC070, 0x9D1D, 0xECA9, 0x9D1E, 0xECA6, 0x9D1F, 0xECAE, 0x9D20, 0xECA5, 0x9D22, 0xECAB, 0x9D23, 0xC06C, 0x9D25, 0xECA3, 0x9D26, 0xC06D, 0x9D28, 0xC06E, 0x9D29, 0xECA8, 0x9D2D, 0xEFA9, 0x9D2E, 0xEF7A, 0x9D2F, 0xEF7B, 0x9D30, 0xEF7E, 0x9D31, 0xEF7C, 0x9D33, 0xEF76, 0x9D36, 0xEF79, 0x9D37, 0xEFA5, 0x9D38, 0xEF7D, 0x9D3B, 0xC245, 0x9D3D, 0xEFA7, 0x9D3E, 0xEFA4, 0x9D3F, 0xC246, 0x9D40, 0xEFA6, 0x9D41, 0xEF77, 0x9D42, 0xEFA2, 0x9D43, 0xEFA3, 0x9D45, 0xEFA1, 0x9D4A, 0xF1D2, 0x9D4B, 0xF1D4, 0x9D4C, 0xF1D7, 0x9D4F, 0xF1D1, 0x9D51, 0xC359, 0x9D52, 0xF1D9, 0x9D53, 0xF1D0, 0x9D54, 0xF1DA, 0x9D56, 0xF1D6, 0x9D57, 0xF1D8, 0x9D58, 0xF1DC, 0x9D59, 0xF1D5, 0x9D5A, 0xF1DD, 0x9D5B, 0xF1D3, 0x9D5C, 0xF1CF, 0x9D5D, 0xC35A, 0x9D5F, 0xF1DB, 0x9D60, 0xC35B, 0x9D61, 0xC44D, 0x9D67, 0xEF78, 0x9D68, 0xF3F1, 0x9D69, 0xF3E8, 0x9D6A, 0xC44F, 0x9D6B, 0xF3E4, 0x9D6C, 0xC450, 0x9D6F, 0xF3ED, 0x9D70, 0xF3E7, 0x9D71, 0xF3DD, 0x9D72, 0xC44E, 0x9D73, 0xF3EA, 0x9D74, 0xF3E5, 0x9D75, 0xF3E6, 0x9D77, 0xF3D8, 0x9D78, 0xF3DF, 0x9D79, 0xF3EE, 0x9D7B, 0xF3EB, 0x9D7D, 0xF3E3, 0x9D7F, 0xF3EF, 0x9D80, 0xF3DE, 0x9D81, 0xF3D9, 0x9D82, 0xF3EC, 0x9D84, 0xF3DB, 0x9D85, 0xF3E9, 0x9D86, 0xF3E0, 0x9D87, 0xF3F0, 0x9D88, 0xF3DC, 0x9D89, 0xC44C, 0x9D8A, 0xF3DA, 0x9D8B, 0xF3E1, 0x9D8C, 0xF3E2, 0x9D90, 0xF57D, 0x9D92, 0xF57B, 0x9D94, 0xF5A2, 0x9D96, 0xF5AE, 0x9D97, 0xF5A5, 0x9D98, 0xF57C, 0x9D99, 0xF578, 0x9D9A, 0xF5A7, 0x9D9B, 0xF57E, 0x9D9C, 0xF5A3, 0x9D9D, 0xF57A, 0x9D9E, 0xF5AA, 0x9D9F, 0xF577, 0x9DA0, 0xF5A1, 0x9DA1, 0xF5A6, 0x9DA2, 0xF5A8, 0x9DA3, 0xF5AB, 0x9DA4, 0xF579, 0x9DA6, 0xF5AF, 0x9DA7, 0xF5B0, 0x9DA8, 0xF5A9, 0x9DA9, 0xF5AD, 0x9DAA, 0xF5A4, 0x9DAC, 0xF6C1, 0x9DAD, 0xF6C4, 0x9DAF, 0xC561, 0x9DB1, 0xF6C3, 0x9DB2, 0xF6C8, 0x9DB3, 0xF6C6, 0x9DB4, 0xC562, 0x9DB5, 0xF6BD, 0x9DB6, 0xF6B3, 0x9DB7, 0xF6B2, 0x9DB8, 0xC564, 0x9DB9, 0xF6BF, 0x9DBA, 0xF6C0, 0x9DBB, 0xF6BC, 0x9DBC, 0xF6B4, 0x9DBE, 0xF6B9, 0x9DBF, 0xF5AC, 0x9DC1, 0xF6B5, 0x9DC2, 0xC563, 0x9DC3, 0xF6BB, 0x9DC5, 0xF6BA, 0x9DC7, 0xF6B6, 0x9DC8, 0xF6C2, 0x9DCA, 0xF6B7, 0x9DCB, 0xF7BB, 0x9DCC, 0xF6C5, 0x9DCD, 0xF6C7, 0x9DCE, 0xF6BE, 0x9DCF, 0xF6B8, 0x9DD0, 0xF7BC, 0x9DD1, 0xF7BE, 0x9DD2, 0xF7B8, 0x9DD3, 0xC5C2, 0x9DD5, 0xF7C5, 0x9DD6, 0xF7C3, 0x9DD7, 0xC5C3, 0x9DD8, 0xF7C2, 0x9DD9, 0xF7C1, 0x9DDA, 0xF7BA, 0x9DDB, 0xF7B7, 0x9DDC, 0xF7BD, 0x9DDD, 0xF7C6, 0x9DDE, 0xF7B9, 0x9DDF, 0xF7BF, 0x9DE1, 0xF869, 0x9DE2, 0xF86E, 0x9DE3, 0xF864, 0x9DE4, 0xF867, 0x9DE5, 0xC5EE, 0x9DE6, 0xF86B, 0x9DE8, 0xF872, 0x9DE9, 0xF7C0, 0x9DEB, 0xF865, 0x9DEC, 0xF86F, 0x9DED, 0xF873, 0x9DEE, 0xF86A, 0x9DEF, 0xF863, 0x9DF0, 0xF86D, 0x9DF2, 0xF86C, 0x9DF3, 0xF871, 0x9DF4, 0xF870, 0x9DF5, 0xF7C4, 0x9DF6, 0xF868, 0x9DF7, 0xF862, 0x9DF8, 0xF866, 0x9DF9, 0xC64E, 0x9DFA, 0xC64F, 0x9DFB, 0xF861, 0x9DFD, 0xF8E6, 0x9DFE, 0xF8DD, 0x9DFF, 0xF8E5, 0x9E00, 0xF8E2, 0x9E01, 0xF8E3, 0x9E02, 0xF8DC, 0x9E03, 0xF8DF, 0x9E04, 0xF8E7, 0x9E05, 0xF8E1, 0x9E06, 0xF8E0, 0x9E07, 0xF8DE, 0x9E09, 0xF8E4, 0x9E0B, 0xF95D, 0x9E0D, 0xF95E, 0x9E0F, 0xF960, 0x9E10, 0xF95F, 0x9E11, 0xF962, 0x9E12, 0xF961, 0x9E13, 0xF97C, 0x9E14, 0xF97B, 0x9E15, 0xF9B7, 0x9E17, 0xF9B8, 0x9E19, 0xF9C5, 0x9E1A, 0xC678, 0x9E1B, 0xC67C, 0x9E1D, 0xF9CF, 0x9E1E, 0xC67D, 0x9E75, 0xB3BF, 0x9E79, 0xC4D0, 0x9E7A, 0xF6C9, 0x9E7C, 0xC650, 0x9E7D, 0xC651, 0x9E7F, 0xB3C0, 0x9E80, 0xE0EE, 0x9E82, 0xB9A8, 0x9E83, 0xE8F0, 0x9E86, 0xECB0, 0x9E87, 0xECB1, 0x9E88, 0xECAF, 0x9E89, 0xEFAB, 0x9E8A, 0xEFAA, 0x9E8B, 0xC247, 0x9E8C, 0xF1DF, 0x9E8D, 0xEFAC, 0x9E8E, 0xF1DE, 0x9E91, 0xF3F3, 0x9E92, 0xC451, 0x9E93, 0xC453, 0x9E94, 0xF3F2, 0x9E97, 0xC452, 0x9E99, 0xF5B1, 0x9E9A, 0xF5B3, 0x9E9B, 0xF5B2, 0x9E9C, 0xF6CA, 0x9E9D, 0xC565, 0x9E9F, 0xC5EF, 0x9EA0, 0xF8E8, 0x9EA1, 0xF963, 0x9EA4, 0xF9D2, 0x9EA5, 0xB3C1, 0x9EA7, 0xE4E5, 0x9EA9, 0xBEA2, 0x9EAD, 0xECB3, 0x9EAE, 0xECB2, 0x9EB0, 0xEFAD, 0x9EB4, 0xC454, 0x9EB5, 0xC4D1, 0x9EB6, 0xF7C7, 0x9EB7, 0xF9CB, 0x9EBB, 0xB3C2, 0x9EBC, 0xBBF2, 0x9EBE, 0xBEA3, 0x9EC0, 0xF3F4, 0x9EC2, 0xF874, 0x9EC3, 0xB6C0, 0x9EC8, 0xEFAE, 0x9ECC, 0xC664, 0x9ECD, 0xB6C1, 0x9ECE, 0xBEA4, 0x9ECF, 0xC248, 0x9ED0, 0xF875, 0x9ED1, 0xB6C2, 0x9ED3, 0xE8F1, 0x9ED4, 0xC072, 0x9ED5, 0xECB4, 0x9ED6, 0xECB5, 0x9ED8, 0xC071, 0x9EDA, 0xEFAF, 0x9EDB, 0xC24C, 0x9EDC, 0xC24A, 0x9EDD, 0xC24B, 0x9EDE, 0xC249, 0x9EDF, 0xF1E0, 0x9EE0, 0xC35C, 0x9EE4, 0xF5B5, 0x9EE5, 0xF5B4, 0x9EE6, 0xF5B7, 0x9EE7, 0xF5B6, 0x9EE8, 0xC4D2, 0x9EEB, 0xF6CB, 0x9EED, 0xF6CD, 0x9EEE, 0xF6CC, 0x9EEF, 0xC566, 0x9EF0, 0xF7C8, 0x9EF2, 0xF876, 0x9EF3, 0xF877, 0x9EF4, 0xC5F0, 0x9EF5, 0xF964, 0x9EF6, 0xF97D, 0x9EF7, 0xC675, 0x9EF9, 0xDCB0, 0x9EFA, 0xECB6, 0x9EFB, 0xEFB0, 0x9EFC, 0xF3F5, 0x9EFD, 0xE0EF, 0x9EFF, 0xEFB1, 0x9F00, 0xF1E2, 0x9F01, 0xF1E1, 0x9F06, 0xF878, 0x9F07, 0xC652, 0x9F09, 0xF965, 0x9F0A, 0xF97E, 0x9F0E, 0xB9A9, 0x9F0F, 0xE8F2, 0x9F10, 0xE8F3, 0x9F12, 0xECB7, 0x9F13, 0xB9AA, 0x9F15, 0xC35D, 0x9F16, 0xF1E3, 0x9F18, 0xF6CF, 0x9F19, 0xC567, 0x9F1A, 0xF6D0, 0x9F1B, 0xF6CE, 0x9F1C, 0xF879, 0x9F1E, 0xF8E9, 0x9F20, 0xB9AB, 0x9F22, 0xEFB4, 0x9F23, 0xEFB3, 0x9F24, 0xEFB2, 0x9F25, 0xF1E4, 0x9F28, 0xF1E8, 0x9F29, 0xF1E7, 0x9F2A, 0xF1E6, 0x9F2B, 0xF1E5, 0x9F2C, 0xC35E, 0x9F2D, 0xF3F6, 0x9F2E, 0xF5B9, 0x9F2F, 0xC4D3, 0x9F30, 0xF5B8, 0x9F31, 0xF6D1, 0x9F32, 0xF7CB, 0x9F33, 0xF7CA, 0x9F34, 0xC5C4, 0x9F35, 0xF7C9, 0x9F36, 0xF87C, 0x9F37, 0xF87B, 0x9F38, 0xF87A, 0x9F3B, 0xBBF3, 0x9F3D, 0xECB8, 0x9F3E, 0xC24D, 0x9F40, 0xF3F7, 0x9F41, 0xF3F8, 0x9F42, 0xF7CC, 0x9F43, 0xF87D, 0x9F46, 0xF8EA, 0x9F47, 0xF966, 0x9F48, 0xF9B9, 0x9F49, 0xF9D4, 0x9F4A, 0xBBF4, 0x9F4B, 0xC24E, 0x9F4C, 0xF1E9, 0x9F4D, 0xF3F9, 0x9F4E, 0xF6D2, 0x9F4F, 0xF87E, 0x9F52, 0xBEA6, 0x9F54, 0xEFB5, 0x9F55, 0xF1EA, 0x9F56, 0xF3FA, 0x9F57, 0xF3FB, 0x9F58, 0xF3FC, 0x9F59, 0xF5BE, 0x9F5B, 0xF5BA, 0x9F5C, 0xC568, 0x9F5D, 0xF5BD, 0x9F5E, 0xF5BC, 0x9F5F, 0xC4D4, 0x9F60, 0xF5BB, 0x9F61, 0xC4D6, 0x9F63, 0xC4D5, 0x9F64, 0xF6D4, 0x9F65, 0xF6D3, 0x9F66, 0xC569, 0x9F67, 0xC56A, 0x9F6A, 0xC5C6, 0x9F6B, 0xF7CD, 0x9F6C, 0xC5C5, 0x9F6E, 0xF8A3, 0x9F6F, 0xF8A4, 0x9F70, 0xF8A2, 0x9F71, 0xF8A1, 0x9F72, 0xC654, 0x9F74, 0xF8EB, 0x9F75, 0xF8EC, 0x9F76, 0xF8ED, 0x9F77, 0xC653, 0x9F78, 0xF967, 0x9F79, 0xF96A, 0x9F7A, 0xF969, 0x9F7B, 0xF968, 0x9F7E, 0xF9D3, 0x9F8D, 0xC073, 0x9F90, 0xC365, 0x9F91, 0xF5BF, 0x9F92, 0xF6D5, 0x9F94, 0xC5C7, 0x9F95, 0xF7CE, 0x9F98, 0xF9D5, 0x9F9C, 0xC074, 0x9FA0, 0xEFB6, 0x9FA2, 0xF7CF, 0x9FA4, 0xF9A1, 0xFA0C, 0xC94A, 0xFA0D, 0xDDFC, 0xFE30, 0xA14A, 0xFE31, 0xA157, 0xFE33, 0xA159, 0xFE34, 0xA15B, 0xFE35, 0xA15F, 0xFE36, 0xA160, 0xFE37, 0xA163, 0xFE38, 0xA164, 0xFE39, 0xA167, 0xFE3A, 0xA168, 0xFE3B, 0xA16B, 0xFE3C, 0xA16C, 0xFE3D, 0xA16F, 0xFE3E, 0xA170, 0xFE3F, 0xA173, 0xFE40, 0xA174, 0xFE41, 0xA177, 0xFE42, 0xA178, 0xFE43, 0xA17B, 0xFE44, 0xA17C, 0xFE49, 0xA1C6, 0xFE4A, 0xA1C7, 0xFE4B, 0xA1CA, 0xFE4C, 0xA1CB, 0xFE4D, 0xA1C8, 0xFE4E, 0xA1C9, 0xFE4F, 0xA15C, 0xFE50, 0xA14D, 0xFE51, 0xA14E, 0xFE52, 0xA14F, 0xFE54, 0xA151, 0xFE55, 0xA152, 0xFE56, 0xA153, 0xFE57, 0xA154, 0xFE59, 0xA17D, 0xFE5A, 0xA17E, 0xFE5B, 0xA1A1, 0xFE5C, 0xA1A2, 0xFE5D, 0xA1A3, 0xFE5E, 0xA1A4, 0xFE5F, 0xA1CC, 0xFE60, 0xA1CD, 0xFE61, 0xA1CE, 0xFE62, 0xA1DE, 0xFE63, 0xA1DF, 0xFE64, 0xA1E0, 0xFE65, 0xA1E1, 0xFE66, 0xA1E2, 0xFE68, 0xA242, 0xFE69, 0xA24C, 0xFE6A, 0xA24D, 0xFE6B, 0xA24E, 0xFF01, 0xA149, 0xFF03, 0xA1AD, 0xFF04, 0xA243, 0xFF05, 0xA248, 0xFF06, 0xA1AE, 0xFF08, 0xA15D, 0xFF09, 0xA15E, 0xFF0A, 0xA1AF, 0xFF0B, 0xA1CF, 0xFF0C, 0xA141, 0xFF0D, 0xA1D0, 0xFF0E, 0xA144, 0xFF0F, 0xA1FE, 0xFF10, 0xA2AF, 0xFF11, 0xA2B0, 0xFF12, 0xA2B1, 0xFF13, 0xA2B2, 0xFF14, 0xA2B3, 0xFF15, 0xA2B4, 0xFF16, 0xA2B5, 0xFF17, 0xA2B6, 0xFF18, 0xA2B7, 0xFF19, 0xA2B8, 0xFF1A, 0xA147, 0xFF1B, 0xA146, 0xFF1C, 0xA1D5, 0xFF1D, 0xA1D7, 0xFF1E, 0xA1D6, 0xFF1F, 0xA148, 0xFF20, 0xA249, 0xFF21, 0xA2CF, 0xFF22, 0xA2D0, 0xFF23, 0xA2D1, 0xFF24, 0xA2D2, 0xFF25, 0xA2D3, 0xFF26, 0xA2D4, 0xFF27, 0xA2D5, 0xFF28, 0xA2D6, 0xFF29, 0xA2D7, 0xFF2A, 0xA2D8, 0xFF2B, 0xA2D9, 0xFF2C, 0xA2DA, 0xFF2D, 0xA2DB, 0xFF2E, 0xA2DC, 0xFF2F, 0xA2DD, 0xFF30, 0xA2DE, 0xFF31, 0xA2DF, 0xFF32, 0xA2E0, 0xFF33, 0xA2E1, 0xFF34, 0xA2E2, 0xFF35, 0xA2E3, 0xFF36, 0xA2E4, 0xFF37, 0xA2E5, 0xFF38, 0xA2E6, 0xFF39, 0xA2E7, 0xFF3A, 0xA2E8, 0xFF3C, 0xA240, 0xFF3F, 0xA1C4, 0xFF41, 0xA2E9, 0xFF42, 0xA2EA, 0xFF43, 0xA2EB, 0xFF44, 0xA2EC, 0xFF45, 0xA2ED, 0xFF46, 0xA2EE, 0xFF47, 0xA2EF, 0xFF48, 0xA2F0, 0xFF49, 0xA2F1, 0xFF4A, 0xA2F2, 0xFF4B, 0xA2F3, 0xFF4C, 0xA2F4, 0xFF4D, 0xA2F5, 0xFF4E, 0xA2F6, 0xFF4F, 0xA2F7, 0xFF50, 0xA2F8, 0xFF51, 0xA2F9, 0xFF52, 0xA2FA, 0xFF53, 0xA2FB, 0xFF54, 0xA2FC, 0xFF55, 0xA2FD, 0xFF56, 0xA2FE, 0xFF57, 0xA340, 0xFF58, 0xA341, 0xFF59, 0xA342, 0xFF5A, 0xA343, 0xFF5B, 0xA161, 0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0 }; static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ 0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A, 0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52, 0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31, 0xA158, 0x2014, 0xA159, 0xFE33, 0xA15A, 0x2574, 0xA15B, 0xFE34, 0xA15C, 0xFE4F, 0xA15D, 0xFF08, 0xA15E, 0xFF09, 0xA15F, 0xFE35, 0xA160, 0xFE36, 0xA161, 0xFF5B, 0xA162, 0xFF5D, 0xA163, 0xFE37, 0xA164, 0xFE38, 0xA165, 0x3014, 0xA166, 0x3015, 0xA167, 0xFE39, 0xA168, 0xFE3A, 0xA169, 0x3010, 0xA16A, 0x3011, 0xA16B, 0xFE3B, 0xA16C, 0xFE3C, 0xA16D, 0x300A, 0xA16E, 0x300B, 0xA16F, 0xFE3D, 0xA170, 0xFE3E, 0xA171, 0x3008, 0xA172, 0x3009, 0xA173, 0xFE3F, 0xA174, 0xFE40, 0xA175, 0x300C, 0xA176, 0x300D, 0xA177, 0xFE41, 0xA178, 0xFE42, 0xA179, 0x300E, 0xA17A, 0x300F, 0xA17B, 0xFE43, 0xA17C, 0xFE44, 0xA17D, 0xFE59, 0xA17E, 0xFE5A, 0xA1A1, 0xFE5B, 0xA1A2, 0xFE5C, 0xA1A3, 0xFE5D, 0xA1A4, 0xFE5E, 0xA1A5, 0x2018, 0xA1A6, 0x2019, 0xA1A7, 0x201C, 0xA1A8, 0x201D, 0xA1A9, 0x301D, 0xA1AA, 0x301E, 0xA1AB, 0x2035, 0xA1AC, 0x2032, 0xA1AD, 0xFF03, 0xA1AE, 0xFF06, 0xA1AF, 0xFF0A, 0xA1B0, 0x203B, 0xA1B1, 0x00A7, 0xA1B2, 0x3003, 0xA1B3, 0x25CB, 0xA1B4, 0x25CF, 0xA1B5, 0x25B3, 0xA1B6, 0x25B2, 0xA1B7, 0x25CE, 0xA1B8, 0x2606, 0xA1B9, 0x2605, 0xA1BA, 0x25C7, 0xA1BB, 0x25C6, 0xA1BC, 0x25A1, 0xA1BD, 0x25A0, 0xA1BE, 0x25BD, 0xA1BF, 0x25BC, 0xA1C0, 0x32A3, 0xA1C1, 0x2105, 0xA1C2, 0x00AF, 0xA1C3, 0xFFE3, 0xA1C4, 0xFF3F, 0xA1C5, 0x02CD, 0xA1C6, 0xFE49, 0xA1C7, 0xFE4A, 0xA1C8, 0xFE4D, 0xA1C9, 0xFE4E, 0xA1CA, 0xFE4B, 0xA1CB, 0xFE4C, 0xA1CC, 0xFE5F, 0xA1CD, 0xFE60, 0xA1CE, 0xFE61, 0xA1CF, 0xFF0B, 0xA1D0, 0xFF0D, 0xA1D1, 0x00D7, 0xA1D2, 0x00F7, 0xA1D3, 0x00B1, 0xA1D4, 0x221A, 0xA1D5, 0xFF1C, 0xA1D6, 0xFF1E, 0xA1D7, 0xFF1D, 0xA1D8, 0x2266, 0xA1D9, 0x2267, 0xA1DA, 0x2260, 0xA1DB, 0x221E, 0xA1DC, 0x2252, 0xA1DD, 0x2261, 0xA1DE, 0xFE62, 0xA1DF, 0xFE63, 0xA1E0, 0xFE64, 0xA1E1, 0xFE65, 0xA1E2, 0xFE66, 0xA1E3, 0xFF5E, 0xA1E4, 0x2229, 0xA1E5, 0x222A, 0xA1E6, 0x22A5, 0xA1E7, 0x2220, 0xA1E8, 0x221F, 0xA1E9, 0x22BF, 0xA1EA, 0x33D2, 0xA1EB, 0x33D1, 0xA1EC, 0x222B, 0xA1ED, 0x222E, 0xA1EE, 0x2235, 0xA1EF, 0x2234, 0xA1F0, 0x2640, 0xA1F1, 0x2642, 0xA1F2, 0x2295, 0xA1F3, 0x2299, 0xA1F4, 0x2191, 0xA1F5, 0x2193, 0xA1F6, 0x2190, 0xA1F7, 0x2192, 0xA1F8, 0x2196, 0xA1F9, 0x2197, 0xA1FA, 0x2199, 0xA1FB, 0x2198, 0xA1FC, 0x2225, 0xA1FD, 0x2223, 0xA1FE, 0xFF0F, 0xA240, 0xFF3C, 0xA241, 0x2215, 0xA242, 0xFE68, 0xA243, 0xFF04, 0xA244, 0xFFE5, 0xA245, 0x3012, 0xA246, 0xFFE0, 0xA247, 0xFFE1, 0xA248, 0xFF05, 0xA249, 0xFF20, 0xA24A, 0x2103, 0xA24B, 0x2109, 0xA24C, 0xFE69, 0xA24D, 0xFE6A, 0xA24E, 0xFE6B, 0xA24F, 0x33D5, 0xA250, 0x339C, 0xA251, 0x339D, 0xA252, 0x339E, 0xA253, 0x33CE, 0xA254, 0x33A1, 0xA255, 0x338E, 0xA256, 0x338F, 0xA257, 0x33C4, 0xA258, 0x00B0, 0xA259, 0x5159, 0xA25A, 0x515B, 0xA25B, 0x515E, 0xA25C, 0x515D, 0xA25D, 0x5161, 0xA25E, 0x5163, 0xA25F, 0x55E7, 0xA260, 0x74E9, 0xA261, 0x7CCE, 0xA262, 0x2581, 0xA263, 0x2582, 0xA264, 0x2583, 0xA265, 0x2584, 0xA266, 0x2585, 0xA267, 0x2586, 0xA268, 0x2587, 0xA269, 0x2588, 0xA26A, 0x258F, 0xA26B, 0x258E, 0xA26C, 0x258D, 0xA26D, 0x258C, 0xA26E, 0x258B, 0xA26F, 0x258A, 0xA270, 0x2589, 0xA271, 0x253C, 0xA272, 0x2534, 0xA273, 0x252C, 0xA274, 0x2524, 0xA275, 0x251C, 0xA276, 0x2594, 0xA277, 0x2500, 0xA278, 0x2502, 0xA279, 0x2595, 0xA27A, 0x250C, 0xA27B, 0x2510, 0xA27C, 0x2514, 0xA27D, 0x2518, 0xA27E, 0x256D, 0xA2A1, 0x256E, 0xA2A2, 0x2570, 0xA2A3, 0x256F, 0xA2A4, 0x2550, 0xA2A5, 0x255E, 0xA2A6, 0x256A, 0xA2A7, 0x2561, 0xA2A8, 0x25E2, 0xA2A9, 0x25E3, 0xA2AA, 0x25E5, 0xA2AB, 0x25E4, 0xA2AC, 0x2571, 0xA2AD, 0x2572, 0xA2AE, 0x2573, 0xA2AF, 0xFF10, 0xA2B0, 0xFF11, 0xA2B1, 0xFF12, 0xA2B2, 0xFF13, 0xA2B3, 0xFF14, 0xA2B4, 0xFF15, 0xA2B5, 0xFF16, 0xA2B6, 0xFF17, 0xA2B7, 0xFF18, 0xA2B8, 0xFF19, 0xA2B9, 0x2160, 0xA2BA, 0x2161, 0xA2BB, 0x2162, 0xA2BC, 0x2163, 0xA2BD, 0x2164, 0xA2BE, 0x2165, 0xA2BF, 0x2166, 0xA2C0, 0x2167, 0xA2C1, 0x2168, 0xA2C2, 0x2169, 0xA2C3, 0x3021, 0xA2C4, 0x3022, 0xA2C5, 0x3023, 0xA2C6, 0x3024, 0xA2C7, 0x3025, 0xA2C8, 0x3026, 0xA2C9, 0x3027, 0xA2CA, 0x3028, 0xA2CB, 0x3029, 0xA2CC, 0x5341, 0xA2CD, 0x5344, 0xA2CE, 0x5345, 0xA2CF, 0xFF21, 0xA2D0, 0xFF22, 0xA2D1, 0xFF23, 0xA2D2, 0xFF24, 0xA2D3, 0xFF25, 0xA2D4, 0xFF26, 0xA2D5, 0xFF27, 0xA2D6, 0xFF28, 0xA2D7, 0xFF29, 0xA2D8, 0xFF2A, 0xA2D9, 0xFF2B, 0xA2DA, 0xFF2C, 0xA2DB, 0xFF2D, 0xA2DC, 0xFF2E, 0xA2DD, 0xFF2F, 0xA2DE, 0xFF30, 0xA2DF, 0xFF31, 0xA2E0, 0xFF32, 0xA2E1, 0xFF33, 0xA2E2, 0xFF34, 0xA2E3, 0xFF35, 0xA2E4, 0xFF36, 0xA2E5, 0xFF37, 0xA2E6, 0xFF38, 0xA2E7, 0xFF39, 0xA2E8, 0xFF3A, 0xA2E9, 0xFF41, 0xA2EA, 0xFF42, 0xA2EB, 0xFF43, 0xA2EC, 0xFF44, 0xA2ED, 0xFF45, 0xA2EE, 0xFF46, 0xA2EF, 0xFF47, 0xA2F0, 0xFF48, 0xA2F1, 0xFF49, 0xA2F2, 0xFF4A, 0xA2F3, 0xFF4B, 0xA2F4, 0xFF4C, 0xA2F5, 0xFF4D, 0xA2F6, 0xFF4E, 0xA2F7, 0xFF4F, 0xA2F8, 0xFF50, 0xA2F9, 0xFF51, 0xA2FA, 0xFF52, 0xA2FB, 0xFF53, 0xA2FC, 0xFF54, 0xA2FD, 0xFF55, 0xA2FE, 0xFF56, 0xA340, 0xFF57, 0xA341, 0xFF58, 0xA342, 0xFF59, 0xA343, 0xFF5A, 0xA344, 0x0391, 0xA345, 0x0392, 0xA346, 0x0393, 0xA347, 0x0394, 0xA348, 0x0395, 0xA349, 0x0396, 0xA34A, 0x0397, 0xA34B, 0x0398, 0xA34C, 0x0399, 0xA34D, 0x039A, 0xA34E, 0x039B, 0xA34F, 0x039C, 0xA350, 0x039D, 0xA351, 0x039E, 0xA352, 0x039F, 0xA353, 0x03A0, 0xA354, 0x03A1, 0xA355, 0x03A3, 0xA356, 0x03A4, 0xA357, 0x03A5, 0xA358, 0x03A6, 0xA359, 0x03A7, 0xA35A, 0x03A8, 0xA35B, 0x03A9, 0xA35C, 0x03B1, 0xA35D, 0x03B2, 0xA35E, 0x03B3, 0xA35F, 0x03B4, 0xA360, 0x03B5, 0xA361, 0x03B6, 0xA362, 0x03B7, 0xA363, 0x03B8, 0xA364, 0x03B9, 0xA365, 0x03BA, 0xA366, 0x03BB, 0xA367, 0x03BC, 0xA368, 0x03BD, 0xA369, 0x03BE, 0xA36A, 0x03BF, 0xA36B, 0x03C0, 0xA36C, 0x03C1, 0xA36D, 0x03C3, 0xA36E, 0x03C4, 0xA36F, 0x03C5, 0xA370, 0x03C6, 0xA371, 0x03C7, 0xA372, 0x03C8, 0xA373, 0x03C9, 0xA374, 0x3105, 0xA375, 0x3106, 0xA376, 0x3107, 0xA377, 0x3108, 0xA378, 0x3109, 0xA379, 0x310A, 0xA37A, 0x310B, 0xA37B, 0x310C, 0xA37C, 0x310D, 0xA37D, 0x310E, 0xA37E, 0x310F, 0xA3A1, 0x3110, 0xA3A2, 0x3111, 0xA3A3, 0x3112, 0xA3A4, 0x3113, 0xA3A5, 0x3114, 0xA3A6, 0x3115, 0xA3A7, 0x3116, 0xA3A8, 0x3117, 0xA3A9, 0x3118, 0xA3AA, 0x3119, 0xA3AB, 0x311A, 0xA3AC, 0x311B, 0xA3AD, 0x311C, 0xA3AE, 0x311D, 0xA3AF, 0x311E, 0xA3B0, 0x311F, 0xA3B1, 0x3120, 0xA3B2, 0x3121, 0xA3B3, 0x3122, 0xA3B4, 0x3123, 0xA3B5, 0x3124, 0xA3B6, 0x3125, 0xA3B7, 0x3126, 0xA3B8, 0x3127, 0xA3B9, 0x3128, 0xA3BA, 0x3129, 0xA3BB, 0x02D9, 0xA3BC, 0x02C9, 0xA3BD, 0x02CA, 0xA3BE, 0x02C7, 0xA3BF, 0x02CB, 0xA3E1, 0x20AC, 0xA440, 0x4E00, 0xA441, 0x4E59, 0xA442, 0x4E01, 0xA443, 0x4E03, 0xA444, 0x4E43, 0xA445, 0x4E5D, 0xA446, 0x4E86, 0xA447, 0x4E8C, 0xA448, 0x4EBA, 0xA449, 0x513F, 0xA44A, 0x5165, 0xA44B, 0x516B, 0xA44C, 0x51E0, 0xA44D, 0x5200, 0xA44E, 0x5201, 0xA44F, 0x529B, 0xA450, 0x5315, 0xA451, 0x5341, 0xA452, 0x535C, 0xA453, 0x53C8, 0xA454, 0x4E09, 0xA455, 0x4E0B, 0xA456, 0x4E08, 0xA457, 0x4E0A, 0xA458, 0x4E2B, 0xA459, 0x4E38, 0xA45A, 0x51E1, 0xA45B, 0x4E45, 0xA45C, 0x4E48, 0xA45D, 0x4E5F, 0xA45E, 0x4E5E, 0xA45F, 0x4E8E, 0xA460, 0x4EA1, 0xA461, 0x5140, 0xA462, 0x5203, 0xA463, 0x52FA, 0xA464, 0x5343, 0xA465, 0x53C9, 0xA466, 0x53E3, 0xA467, 0x571F, 0xA468, 0x58EB, 0xA469, 0x5915, 0xA46A, 0x5927, 0xA46B, 0x5973, 0xA46C, 0x5B50, 0xA46D, 0x5B51, 0xA46E, 0x5B53, 0xA46F, 0x5BF8, 0xA470, 0x5C0F, 0xA471, 0x5C22, 0xA472, 0x5C38, 0xA473, 0x5C71, 0xA474, 0x5DDD, 0xA475, 0x5DE5, 0xA476, 0x5DF1, 0xA477, 0x5DF2, 0xA478, 0x5DF3, 0xA479, 0x5DFE, 0xA47A, 0x5E72, 0xA47B, 0x5EFE, 0xA47C, 0x5F0B, 0xA47D, 0x5F13, 0xA47E, 0x624D, 0xA4A1, 0x4E11, 0xA4A2, 0x4E10, 0xA4A3, 0x4E0D, 0xA4A4, 0x4E2D, 0xA4A5, 0x4E30, 0xA4A6, 0x4E39, 0xA4A7, 0x4E4B, 0xA4A8, 0x5C39, 0xA4A9, 0x4E88, 0xA4AA, 0x4E91, 0xA4AB, 0x4E95, 0xA4AC, 0x4E92, 0xA4AD, 0x4E94, 0xA4AE, 0x4EA2, 0xA4AF, 0x4EC1, 0xA4B0, 0x4EC0, 0xA4B1, 0x4EC3, 0xA4B2, 0x4EC6, 0xA4B3, 0x4EC7, 0xA4B4, 0x4ECD, 0xA4B5, 0x4ECA, 0xA4B6, 0x4ECB, 0xA4B7, 0x4EC4, 0xA4B8, 0x5143, 0xA4B9, 0x5141, 0xA4BA, 0x5167, 0xA4BB, 0x516D, 0xA4BC, 0x516E, 0xA4BD, 0x516C, 0xA4BE, 0x5197, 0xA4BF, 0x51F6, 0xA4C0, 0x5206, 0xA4C1, 0x5207, 0xA4C2, 0x5208, 0xA4C3, 0x52FB, 0xA4C4, 0x52FE, 0xA4C5, 0x52FF, 0xA4C6, 0x5316, 0xA4C7, 0x5339, 0xA4C8, 0x5348, 0xA4C9, 0x5347, 0xA4CA, 0x5345, 0xA4CB, 0x535E, 0xA4CC, 0x5384, 0xA4CD, 0x53CB, 0xA4CE, 0x53CA, 0xA4CF, 0x53CD, 0xA4D0, 0x58EC, 0xA4D1, 0x5929, 0xA4D2, 0x592B, 0xA4D3, 0x592A, 0xA4D4, 0x592D, 0xA4D5, 0x5B54, 0xA4D6, 0x5C11, 0xA4D7, 0x5C24, 0xA4D8, 0x5C3A, 0xA4D9, 0x5C6F, 0xA4DA, 0x5DF4, 0xA4DB, 0x5E7B, 0xA4DC, 0x5EFF, 0xA4DD, 0x5F14, 0xA4DE, 0x5F15, 0xA4DF, 0x5FC3, 0xA4E0, 0x6208, 0xA4E1, 0x6236, 0xA4E2, 0x624B, 0xA4E3, 0x624E, 0xA4E4, 0x652F, 0xA4E5, 0x6587, 0xA4E6, 0x6597, 0xA4E7, 0x65A4, 0xA4E8, 0x65B9, 0xA4E9, 0x65E5, 0xA4EA, 0x66F0, 0xA4EB, 0x6708, 0xA4EC, 0x6728, 0xA4ED, 0x6B20, 0xA4EE, 0x6B62, 0xA4EF, 0x6B79, 0xA4F0, 0x6BCB, 0xA4F1, 0x6BD4, 0xA4F2, 0x6BDB, 0xA4F3, 0x6C0F, 0xA4F4, 0x6C34, 0xA4F5, 0x706B, 0xA4F6, 0x722A, 0xA4F7, 0x7236, 0xA4F8, 0x723B, 0xA4F9, 0x7247, 0xA4FA, 0x7259, 0xA4FB, 0x725B, 0xA4FC, 0x72AC, 0xA4FD, 0x738B, 0xA4FE, 0x4E19, 0xA540, 0x4E16, 0xA541, 0x4E15, 0xA542, 0x4E14, 0xA543, 0x4E18, 0xA544, 0x4E3B, 0xA545, 0x4E4D, 0xA546, 0x4E4F, 0xA547, 0x4E4E, 0xA548, 0x4EE5, 0xA549, 0x4ED8, 0xA54A, 0x4ED4, 0xA54B, 0x4ED5, 0xA54C, 0x4ED6, 0xA54D, 0x4ED7, 0xA54E, 0x4EE3, 0xA54F, 0x4EE4, 0xA550, 0x4ED9, 0xA551, 0x4EDE, 0xA552, 0x5145, 0xA553, 0x5144, 0xA554, 0x5189, 0xA555, 0x518A, 0xA556, 0x51AC, 0xA557, 0x51F9, 0xA558, 0x51FA, 0xA559, 0x51F8, 0xA55A, 0x520A, 0xA55B, 0x52A0, 0xA55C, 0x529F, 0xA55D, 0x5305, 0xA55E, 0x5306, 0xA55F, 0x5317, 0xA560, 0x531D, 0xA561, 0x4EDF, 0xA562, 0x534A, 0xA563, 0x5349, 0xA564, 0x5361, 0xA565, 0x5360, 0xA566, 0x536F, 0xA567, 0x536E, 0xA568, 0x53BB, 0xA569, 0x53EF, 0xA56A, 0x53E4, 0xA56B, 0x53F3, 0xA56C, 0x53EC, 0xA56D, 0x53EE, 0xA56E, 0x53E9, 0xA56F, 0x53E8, 0xA570, 0x53FC, 0xA571, 0x53F8, 0xA572, 0x53F5, 0xA573, 0x53EB, 0xA574, 0x53E6, 0xA575, 0x53EA, 0xA576, 0x53F2, 0xA577, 0x53F1, 0xA578, 0x53F0, 0xA579, 0x53E5, 0xA57A, 0x53ED, 0xA57B, 0x53FB, 0xA57C, 0x56DB, 0xA57D, 0x56DA, 0xA57E, 0x5916, 0xA5A1, 0x592E, 0xA5A2, 0x5931, 0xA5A3, 0x5974, 0xA5A4, 0x5976, 0xA5A5, 0x5B55, 0xA5A6, 0x5B83, 0xA5A7, 0x5C3C, 0xA5A8, 0x5DE8, 0xA5A9, 0x5DE7, 0xA5AA, 0x5DE6, 0xA5AB, 0x5E02, 0xA5AC, 0x5E03, 0xA5AD, 0x5E73, 0xA5AE, 0x5E7C, 0xA5AF, 0x5F01, 0xA5B0, 0x5F18, 0xA5B1, 0x5F17, 0xA5B2, 0x5FC5, 0xA5B3, 0x620A, 0xA5B4, 0x6253, 0xA5B5, 0x6254, 0xA5B6, 0x6252, 0xA5B7, 0x6251, 0xA5B8, 0x65A5, 0xA5B9, 0x65E6, 0xA5BA, 0x672E, 0xA5BB, 0x672C, 0xA5BC, 0x672A, 0xA5BD, 0x672B, 0xA5BE, 0x672D, 0xA5BF, 0x6B63, 0xA5C0, 0x6BCD, 0xA5C1, 0x6C11, 0xA5C2, 0x6C10, 0xA5C3, 0x6C38, 0xA5C4, 0x6C41, 0xA5C5, 0x6C40, 0xA5C6, 0x6C3E, 0xA5C7, 0x72AF, 0xA5C8, 0x7384, 0xA5C9, 0x7389, 0xA5CA, 0x74DC, 0xA5CB, 0x74E6, 0xA5CC, 0x7518, 0xA5CD, 0x751F, 0xA5CE, 0x7528, 0xA5CF, 0x7529, 0xA5D0, 0x7530, 0xA5D1, 0x7531, 0xA5D2, 0x7532, 0xA5D3, 0x7533, 0xA5D4, 0x758B, 0xA5D5, 0x767D, 0xA5D6, 0x76AE, 0xA5D7, 0x76BF, 0xA5D8, 0x76EE, 0xA5D9, 0x77DB, 0xA5DA, 0x77E2, 0xA5DB, 0x77F3, 0xA5DC, 0x793A, 0xA5DD, 0x79BE, 0xA5DE, 0x7A74, 0xA5DF, 0x7ACB, 0xA5E0, 0x4E1E, 0xA5E1, 0x4E1F, 0xA5E2, 0x4E52, 0xA5E3, 0x4E53, 0xA5E4, 0x4E69, 0xA5E5, 0x4E99, 0xA5E6, 0x4EA4, 0xA5E7, 0x4EA6, 0xA5E8, 0x4EA5, 0xA5E9, 0x4EFF, 0xA5EA, 0x4F09, 0xA5EB, 0x4F19, 0xA5EC, 0x4F0A, 0xA5ED, 0x4F15, 0xA5EE, 0x4F0D, 0xA5EF, 0x4F10, 0xA5F0, 0x4F11, 0xA5F1, 0x4F0F, 0xA5F2, 0x4EF2, 0xA5F3, 0x4EF6, 0xA5F4, 0x4EFB, 0xA5F5, 0x4EF0, 0xA5F6, 0x4EF3, 0xA5F7, 0x4EFD, 0xA5F8, 0x4F01, 0xA5F9, 0x4F0B, 0xA5FA, 0x5149, 0xA5FB, 0x5147, 0xA5FC, 0x5146, 0xA5FD, 0x5148, 0xA5FE, 0x5168, 0xA640, 0x5171, 0xA641, 0x518D, 0xA642, 0x51B0, 0xA643, 0x5217, 0xA644, 0x5211, 0xA645, 0x5212, 0xA646, 0x520E, 0xA647, 0x5216, 0xA648, 0x52A3, 0xA649, 0x5308, 0xA64A, 0x5321, 0xA64B, 0x5320, 0xA64C, 0x5370, 0xA64D, 0x5371, 0xA64E, 0x5409, 0xA64F, 0x540F, 0xA650, 0x540C, 0xA651, 0x540A, 0xA652, 0x5410, 0xA653, 0x5401, 0xA654, 0x540B, 0xA655, 0x5404, 0xA656, 0x5411, 0xA657, 0x540D, 0xA658, 0x5408, 0xA659, 0x5403, 0xA65A, 0x540E, 0xA65B, 0x5406, 0xA65C, 0x5412, 0xA65D, 0x56E0, 0xA65E, 0x56DE, 0xA65F, 0x56DD, 0xA660, 0x5733, 0xA661, 0x5730, 0xA662, 0x5728, 0xA663, 0x572D, 0xA664, 0x572C, 0xA665, 0x572F, 0xA666, 0x5729, 0xA667, 0x5919, 0xA668, 0x591A, 0xA669, 0x5937, 0xA66A, 0x5938, 0xA66B, 0x5984, 0xA66C, 0x5978, 0xA66D, 0x5983, 0xA66E, 0x597D, 0xA66F, 0x5979, 0xA670, 0x5982, 0xA671, 0x5981, 0xA672, 0x5B57, 0xA673, 0x5B58, 0xA674, 0x5B87, 0xA675, 0x5B88, 0xA676, 0x5B85, 0xA677, 0x5B89, 0xA678, 0x5BFA, 0xA679, 0x5C16, 0xA67A, 0x5C79, 0xA67B, 0x5DDE, 0xA67C, 0x5E06, 0xA67D, 0x5E76, 0xA67E, 0x5E74, 0xA6A1, 0x5F0F, 0xA6A2, 0x5F1B, 0xA6A3, 0x5FD9, 0xA6A4, 0x5FD6, 0xA6A5, 0x620E, 0xA6A6, 0x620C, 0xA6A7, 0x620D, 0xA6A8, 0x6210, 0xA6A9, 0x6263, 0xA6AA, 0x625B, 0xA6AB, 0x6258, 0xA6AC, 0x6536, 0xA6AD, 0x65E9, 0xA6AE, 0x65E8, 0xA6AF, 0x65EC, 0xA6B0, 0x65ED, 0xA6B1, 0x66F2, 0xA6B2, 0x66F3, 0xA6B3, 0x6709, 0xA6B4, 0x673D, 0xA6B5, 0x6734, 0xA6B6, 0x6731, 0xA6B7, 0x6735, 0xA6B8, 0x6B21, 0xA6B9, 0x6B64, 0xA6BA, 0x6B7B, 0xA6BB, 0x6C16, 0xA6BC, 0x6C5D, 0xA6BD, 0x6C57, 0xA6BE, 0x6C59, 0xA6BF, 0x6C5F, 0xA6C0, 0x6C60, 0xA6C1, 0x6C50, 0xA6C2, 0x6C55, 0xA6C3, 0x6C61, 0xA6C4, 0x6C5B, 0xA6C5, 0x6C4D, 0xA6C6, 0x6C4E, 0xA6C7, 0x7070, 0xA6C8, 0x725F, 0xA6C9, 0x725D, 0xA6CA, 0x767E, 0xA6CB, 0x7AF9, 0xA6CC, 0x7C73, 0xA6CD, 0x7CF8, 0xA6CE, 0x7F36, 0xA6CF, 0x7F8A, 0xA6D0, 0x7FBD, 0xA6D1, 0x8001, 0xA6D2, 0x8003, 0xA6D3, 0x800C, 0xA6D4, 0x8012, 0xA6D5, 0x8033, 0xA6D6, 0x807F, 0xA6D7, 0x8089, 0xA6D8, 0x808B, 0xA6D9, 0x808C, 0xA6DA, 0x81E3, 0xA6DB, 0x81EA, 0xA6DC, 0x81F3, 0xA6DD, 0x81FC, 0xA6DE, 0x820C, 0xA6DF, 0x821B, 0xA6E0, 0x821F, 0xA6E1, 0x826E, 0xA6E2, 0x8272, 0xA6E3, 0x827E, 0xA6E4, 0x866B, 0xA6E5, 0x8840, 0xA6E6, 0x884C, 0xA6E7, 0x8863, 0xA6E8, 0x897F, 0xA6E9, 0x9621, 0xA6EA, 0x4E32, 0xA6EB, 0x4EA8, 0xA6EC, 0x4F4D, 0xA6ED, 0x4F4F, 0xA6EE, 0x4F47, 0xA6EF, 0x4F57, 0xA6F0, 0x4F5E, 0xA6F1, 0x4F34, 0xA6F2, 0x4F5B, 0xA6F3, 0x4F55, 0xA6F4, 0x4F30, 0xA6F5, 0x4F50, 0xA6F6, 0x4F51, 0xA6F7, 0x4F3D, 0xA6F8, 0x4F3A, 0xA6F9, 0x4F38, 0xA6FA, 0x4F43, 0xA6FB, 0x4F54, 0xA6FC, 0x4F3C, 0xA6FD, 0x4F46, 0xA6FE, 0x4F63, 0xA740, 0x4F5C, 0xA741, 0x4F60, 0xA742, 0x4F2F, 0xA743, 0x4F4E, 0xA744, 0x4F36, 0xA745, 0x4F59, 0xA746, 0x4F5D, 0xA747, 0x4F48, 0xA748, 0x4F5A, 0xA749, 0x514C, 0xA74A, 0x514B, 0xA74B, 0x514D, 0xA74C, 0x5175, 0xA74D, 0x51B6, 0xA74E, 0x51B7, 0xA74F, 0x5225, 0xA750, 0x5224, 0xA751, 0x5229, 0xA752, 0x522A, 0xA753, 0x5228, 0xA754, 0x52AB, 0xA755, 0x52A9, 0xA756, 0x52AA, 0xA757, 0x52AC, 0xA758, 0x5323, 0xA759, 0x5373, 0xA75A, 0x5375, 0xA75B, 0x541D, 0xA75C, 0x542D, 0xA75D, 0x541E, 0xA75E, 0x543E, 0xA75F, 0x5426, 0xA760, 0x544E, 0xA761, 0x5427, 0xA762, 0x5446, 0xA763, 0x5443, 0xA764, 0x5433, 0xA765, 0x5448, 0xA766, 0x5442, 0xA767, 0x541B, 0xA768, 0x5429, 0xA769, 0x544A, 0xA76A, 0x5439, 0xA76B, 0x543B, 0xA76C, 0x5438, 0xA76D, 0x542E, 0xA76E, 0x5435, 0xA76F, 0x5436, 0xA770, 0x5420, 0xA771, 0x543C, 0xA772, 0x5440, 0xA773, 0x5431, 0xA774, 0x542B, 0xA775, 0x541F, 0xA776, 0x542C, 0xA777, 0x56EA, 0xA778, 0x56F0, 0xA779, 0x56E4, 0xA77A, 0x56EB, 0xA77B, 0x574A, 0xA77C, 0x5751, 0xA77D, 0x5740, 0xA77E, 0x574D, 0xA7A1, 0x5747, 0xA7A2, 0x574E, 0xA7A3, 0x573E, 0xA7A4, 0x5750, 0xA7A5, 0x574F, 0xA7A6, 0x573B, 0xA7A7, 0x58EF, 0xA7A8, 0x593E, 0xA7A9, 0x599D, 0xA7AA, 0x5992, 0xA7AB, 0x59A8, 0xA7AC, 0x599E, 0xA7AD, 0x59A3, 0xA7AE, 0x5999, 0xA7AF, 0x5996, 0xA7B0, 0x598D, 0xA7B1, 0x59A4, 0xA7B2, 0x5993, 0xA7B3, 0x598A, 0xA7B4, 0x59A5, 0xA7B5, 0x5B5D, 0xA7B6, 0x5B5C, 0xA7B7, 0x5B5A, 0xA7B8, 0x5B5B, 0xA7B9, 0x5B8C, 0xA7BA, 0x5B8B, 0xA7BB, 0x5B8F, 0xA7BC, 0x5C2C, 0xA7BD, 0x5C40, 0xA7BE, 0x5C41, 0xA7BF, 0x5C3F, 0xA7C0, 0x5C3E, 0xA7C1, 0x5C90, 0xA7C2, 0x5C91, 0xA7C3, 0x5C94, 0xA7C4, 0x5C8C, 0xA7C5, 0x5DEB, 0xA7C6, 0x5E0C, 0xA7C7, 0x5E8F, 0xA7C8, 0x5E87, 0xA7C9, 0x5E8A, 0xA7CA, 0x5EF7, 0xA7CB, 0x5F04, 0xA7CC, 0x5F1F, 0xA7CD, 0x5F64, 0xA7CE, 0x5F62, 0xA7CF, 0x5F77, 0xA7D0, 0x5F79, 0xA7D1, 0x5FD8, 0xA7D2, 0x5FCC, 0xA7D3, 0x5FD7, 0xA7D4, 0x5FCD, 0xA7D5, 0x5FF1, 0xA7D6, 0x5FEB, 0xA7D7, 0x5FF8, 0xA7D8, 0x5FEA, 0xA7D9, 0x6212, 0xA7DA, 0x6211, 0xA7DB, 0x6284, 0xA7DC, 0x6297, 0xA7DD, 0x6296, 0xA7DE, 0x6280, 0xA7DF, 0x6276, 0xA7E0, 0x6289, 0xA7E1, 0x626D, 0xA7E2, 0x628A, 0xA7E3, 0x627C, 0xA7E4, 0x627E, 0xA7E5, 0x6279, 0xA7E6, 0x6273, 0xA7E7, 0x6292, 0xA7E8, 0x626F, 0xA7E9, 0x6298, 0xA7EA, 0x626E, 0xA7EB, 0x6295, 0xA7EC, 0x6293, 0xA7ED, 0x6291, 0xA7EE, 0x6286, 0xA7EF, 0x6539, 0xA7F0, 0x653B, 0xA7F1, 0x6538, 0xA7F2, 0x65F1, 0xA7F3, 0x66F4, 0xA7F4, 0x675F, 0xA7F5, 0x674E, 0xA7F6, 0x674F, 0xA7F7, 0x6750, 0xA7F8, 0x6751, 0xA7F9, 0x675C, 0xA7FA, 0x6756, 0xA7FB, 0x675E, 0xA7FC, 0x6749, 0xA7FD, 0x6746, 0xA7FE, 0x6760, 0xA840, 0x6753, 0xA841, 0x6757, 0xA842, 0x6B65, 0xA843, 0x6BCF, 0xA844, 0x6C42, 0xA845, 0x6C5E, 0xA846, 0x6C99, 0xA847, 0x6C81, 0xA848, 0x6C88, 0xA849, 0x6C89, 0xA84A, 0x6C85, 0xA84B, 0x6C9B, 0xA84C, 0x6C6A, 0xA84D, 0x6C7A, 0xA84E, 0x6C90, 0xA84F, 0x6C70, 0xA850, 0x6C8C, 0xA851, 0x6C68, 0xA852, 0x6C96, 0xA853, 0x6C92, 0xA854, 0x6C7D, 0xA855, 0x6C83, 0xA856, 0x6C72, 0xA857, 0x6C7E, 0xA858, 0x6C74, 0xA859, 0x6C86, 0xA85A, 0x6C76, 0xA85B, 0x6C8D, 0xA85C, 0x6C94, 0xA85D, 0x6C98, 0xA85E, 0x6C82, 0xA85F, 0x7076, 0xA860, 0x707C, 0xA861, 0x707D, 0xA862, 0x7078, 0xA863, 0x7262, 0xA864, 0x7261, 0xA865, 0x7260, 0xA866, 0x72C4, 0xA867, 0x72C2, 0xA868, 0x7396, 0xA869, 0x752C, 0xA86A, 0x752B, 0xA86B, 0x7537, 0xA86C, 0x7538, 0xA86D, 0x7682, 0xA86E, 0x76EF, 0xA86F, 0x77E3, 0xA870, 0x79C1, 0xA871, 0x79C0, 0xA872, 0x79BF, 0xA873, 0x7A76, 0xA874, 0x7CFB, 0xA875, 0x7F55, 0xA876, 0x8096, 0xA877, 0x8093, 0xA878, 0x809D, 0xA879, 0x8098, 0xA87A, 0x809B, 0xA87B, 0x809A, 0xA87C, 0x80B2, 0xA87D, 0x826F, 0xA87E, 0x8292, 0xA8A1, 0x828B, 0xA8A2, 0x828D, 0xA8A3, 0x898B, 0xA8A4, 0x89D2, 0xA8A5, 0x8A00, 0xA8A6, 0x8C37, 0xA8A7, 0x8C46, 0xA8A8, 0x8C55, 0xA8A9, 0x8C9D, 0xA8AA, 0x8D64, 0xA8AB, 0x8D70, 0xA8AC, 0x8DB3, 0xA8AD, 0x8EAB, 0xA8AE, 0x8ECA, 0xA8AF, 0x8F9B, 0xA8B0, 0x8FB0, 0xA8B1, 0x8FC2, 0xA8B2, 0x8FC6, 0xA8B3, 0x8FC5, 0xA8B4, 0x8FC4, 0xA8B5, 0x5DE1, 0xA8B6, 0x9091, 0xA8B7, 0x90A2, 0xA8B8, 0x90AA, 0xA8B9, 0x90A6, 0xA8BA, 0x90A3, 0xA8BB, 0x9149, 0xA8BC, 0x91C6, 0xA8BD, 0x91CC, 0xA8BE, 0x9632, 0xA8BF, 0x962E, 0xA8C0, 0x9631, 0xA8C1, 0x962A, 0xA8C2, 0x962C, 0xA8C3, 0x4E26, 0xA8C4, 0x4E56, 0xA8C5, 0x4E73, 0xA8C6, 0x4E8B, 0xA8C7, 0x4E9B, 0xA8C8, 0x4E9E, 0xA8C9, 0x4EAB, 0xA8CA, 0x4EAC, 0xA8CB, 0x4F6F, 0xA8CC, 0x4F9D, 0xA8CD, 0x4F8D, 0xA8CE, 0x4F73, 0xA8CF, 0x4F7F, 0xA8D0, 0x4F6C, 0xA8D1, 0x4F9B, 0xA8D2, 0x4F8B, 0xA8D3, 0x4F86, 0xA8D4, 0x4F83, 0xA8D5, 0x4F70, 0xA8D6, 0x4F75, 0xA8D7, 0x4F88, 0xA8D8, 0x4F69, 0xA8D9, 0x4F7B, 0xA8DA, 0x4F96, 0xA8DB, 0x4F7E, 0xA8DC, 0x4F8F, 0xA8DD, 0x4F91, 0xA8DE, 0x4F7A, 0xA8DF, 0x5154, 0xA8E0, 0x5152, 0xA8E1, 0x5155, 0xA8E2, 0x5169, 0xA8E3, 0x5177, 0xA8E4, 0x5176, 0xA8E5, 0x5178, 0xA8E6, 0x51BD, 0xA8E7, 0x51FD, 0xA8E8, 0x523B, 0xA8E9, 0x5238, 0xA8EA, 0x5237, 0xA8EB, 0x523A, 0xA8EC, 0x5230, 0xA8ED, 0x522E, 0xA8EE, 0x5236, 0xA8EF, 0x5241, 0xA8F0, 0x52BE, 0xA8F1, 0x52BB, 0xA8F2, 0x5352, 0xA8F3, 0x5354, 0xA8F4, 0x5353, 0xA8F5, 0x5351, 0xA8F6, 0x5366, 0xA8F7, 0x5377, 0xA8F8, 0x5378, 0xA8F9, 0x5379, 0xA8FA, 0x53D6, 0xA8FB, 0x53D4, 0xA8FC, 0x53D7, 0xA8FD, 0x5473, 0xA8FE, 0x5475, 0xA940, 0x5496, 0xA941, 0x5478, 0xA942, 0x5495, 0xA943, 0x5480, 0xA944, 0x547B, 0xA945, 0x5477, 0xA946, 0x5484, 0xA947, 0x5492, 0xA948, 0x5486, 0xA949, 0x547C, 0xA94A, 0x5490, 0xA94B, 0x5471, 0xA94C, 0x5476, 0xA94D, 0x548C, 0xA94E, 0x549A, 0xA94F, 0x5462, 0xA950, 0x5468, 0xA951, 0x548B, 0xA952, 0x547D, 0xA953, 0x548E, 0xA954, 0x56FA, 0xA955, 0x5783, 0xA956, 0x5777, 0xA957, 0x576A, 0xA958, 0x5769, 0xA959, 0x5761, 0xA95A, 0x5766, 0xA95B, 0x5764, 0xA95C, 0x577C, 0xA95D, 0x591C, 0xA95E, 0x5949, 0xA95F, 0x5947, 0xA960, 0x5948, 0xA961, 0x5944, 0xA962, 0x5954, 0xA963, 0x59BE, 0xA964, 0x59BB, 0xA965, 0x59D4, 0xA966, 0x59B9, 0xA967, 0x59AE, 0xA968, 0x59D1, 0xA969, 0x59C6, 0xA96A, 0x59D0, 0xA96B, 0x59CD, 0xA96C, 0x59CB, 0xA96D, 0x59D3, 0xA96E, 0x59CA, 0xA96F, 0x59AF, 0xA970, 0x59B3, 0xA971, 0x59D2, 0xA972, 0x59C5, 0xA973, 0x5B5F, 0xA974, 0x5B64, 0xA975, 0x5B63, 0xA976, 0x5B97, 0xA977, 0x5B9A, 0xA978, 0x5B98, 0xA979, 0x5B9C, 0xA97A, 0x5B99, 0xA97B, 0x5B9B, 0xA97C, 0x5C1A, 0xA97D, 0x5C48, 0xA97E, 0x5C45, 0xA9A1, 0x5C46, 0xA9A2, 0x5CB7, 0xA9A3, 0x5CA1, 0xA9A4, 0x5CB8, 0xA9A5, 0x5CA9, 0xA9A6, 0x5CAB, 0xA9A7, 0x5CB1, 0xA9A8, 0x5CB3, 0xA9A9, 0x5E18, 0xA9AA, 0x5E1A, 0xA9AB, 0x5E16, 0xA9AC, 0x5E15, 0xA9AD, 0x5E1B, 0xA9AE, 0x5E11, 0xA9AF, 0x5E78, 0xA9B0, 0x5E9A, 0xA9B1, 0x5E97, 0xA9B2, 0x5E9C, 0xA9B3, 0x5E95, 0xA9B4, 0x5E96, 0xA9B5, 0x5EF6, 0xA9B6, 0x5F26, 0xA9B7, 0x5F27, 0xA9B8, 0x5F29, 0xA9B9, 0x5F80, 0xA9BA, 0x5F81, 0xA9BB, 0x5F7F, 0xA9BC, 0x5F7C, 0xA9BD, 0x5FDD, 0xA9BE, 0x5FE0, 0xA9BF, 0x5FFD, 0xA9C0, 0x5FF5, 0xA9C1, 0x5FFF, 0xA9C2, 0x600F, 0xA9C3, 0x6014, 0xA9C4, 0x602F, 0xA9C5, 0x6035, 0xA9C6, 0x6016, 0xA9C7, 0x602A, 0xA9C8, 0x6015, 0xA9C9, 0x6021, 0xA9CA, 0x6027, 0xA9CB, 0x6029, 0xA9CC, 0x602B, 0xA9CD, 0x601B, 0xA9CE, 0x6216, 0xA9CF, 0x6215, 0xA9D0, 0x623F, 0xA9D1, 0x623E, 0xA9D2, 0x6240, 0xA9D3, 0x627F, 0xA9D4, 0x62C9, 0xA9D5, 0x62CC, 0xA9D6, 0x62C4, 0xA9D7, 0x62BF, 0xA9D8, 0x62C2, 0xA9D9, 0x62B9, 0xA9DA, 0x62D2, 0xA9DB, 0x62DB, 0xA9DC, 0x62AB, 0xA9DD, 0x62D3, 0xA9DE, 0x62D4, 0xA9DF, 0x62CB, 0xA9E0, 0x62C8, 0xA9E1, 0x62A8, 0xA9E2, 0x62BD, 0xA9E3, 0x62BC, 0xA9E4, 0x62D0, 0xA9E5, 0x62D9, 0xA9E6, 0x62C7, 0xA9E7, 0x62CD, 0xA9E8, 0x62B5, 0xA9E9, 0x62DA, 0xA9EA, 0x62B1, 0xA9EB, 0x62D8, 0xA9EC, 0x62D6, 0xA9ED, 0x62D7, 0xA9EE, 0x62C6, 0xA9EF, 0x62AC, 0xA9F0, 0x62CE, 0xA9F1, 0x653E, 0xA9F2, 0x65A7, 0xA9F3, 0x65BC, 0xA9F4, 0x65FA, 0xA9F5, 0x6614, 0xA9F6, 0x6613, 0xA9F7, 0x660C, 0xA9F8, 0x6606, 0xA9F9, 0x6602, 0xA9FA, 0x660E, 0xA9FB, 0x6600, 0xA9FC, 0x660F, 0xA9FD, 0x6615, 0xA9FE, 0x660A, 0xAA40, 0x6607, 0xAA41, 0x670D, 0xAA42, 0x670B, 0xAA43, 0x676D, 0xAA44, 0x678B, 0xAA45, 0x6795, 0xAA46, 0x6771, 0xAA47, 0x679C, 0xAA48, 0x6773, 0xAA49, 0x6777, 0xAA4A, 0x6787, 0xAA4B, 0x679D, 0xAA4C, 0x6797, 0xAA4D, 0x676F, 0xAA4E, 0x6770, 0xAA4F, 0x677F, 0xAA50, 0x6789, 0xAA51, 0x677E, 0xAA52, 0x6790, 0xAA53, 0x6775, 0xAA54, 0x679A, 0xAA55, 0x6793, 0xAA56, 0x677C, 0xAA57, 0x676A, 0xAA58, 0x6772, 0xAA59, 0x6B23, 0xAA5A, 0x6B66, 0xAA5B, 0x6B67, 0xAA5C, 0x6B7F, 0xAA5D, 0x6C13, 0xAA5E, 0x6C1B, 0xAA5F, 0x6CE3, 0xAA60, 0x6CE8, 0xAA61, 0x6CF3, 0xAA62, 0x6CB1, 0xAA63, 0x6CCC, 0xAA64, 0x6CE5, 0xAA65, 0x6CB3, 0xAA66, 0x6CBD, 0xAA67, 0x6CBE, 0xAA68, 0x6CBC, 0xAA69, 0x6CE2, 0xAA6A, 0x6CAB, 0xAA6B, 0x6CD5, 0xAA6C, 0x6CD3, 0xAA6D, 0x6CB8, 0xAA6E, 0x6CC4, 0xAA6F, 0x6CB9, 0xAA70, 0x6CC1, 0xAA71, 0x6CAE, 0xAA72, 0x6CD7, 0xAA73, 0x6CC5, 0xAA74, 0x6CF1, 0xAA75, 0x6CBF, 0xAA76, 0x6CBB, 0xAA77, 0x6CE1, 0xAA78, 0x6CDB, 0xAA79, 0x6CCA, 0xAA7A, 0x6CAC, 0xAA7B, 0x6CEF, 0xAA7C, 0x6CDC, 0xAA7D, 0x6CD6, 0xAA7E, 0x6CE0, 0xAAA1, 0x7095, 0xAAA2, 0x708E, 0xAAA3, 0x7092, 0xAAA4, 0x708A, 0xAAA5, 0x7099, 0xAAA6, 0x722C, 0xAAA7, 0x722D, 0xAAA8, 0x7238, 0xAAA9, 0x7248, 0xAAAA, 0x7267, 0xAAAB, 0x7269, 0xAAAC, 0x72C0, 0xAAAD, 0x72CE, 0xAAAE, 0x72D9, 0xAAAF, 0x72D7, 0xAAB0, 0x72D0, 0xAAB1, 0x73A9, 0xAAB2, 0x73A8, 0xAAB3, 0x739F, 0xAAB4, 0x73AB, 0xAAB5, 0x73A5, 0xAAB6, 0x753D, 0xAAB7, 0x759D, 0xAAB8, 0x7599, 0xAAB9, 0x759A, 0xAABA, 0x7684, 0xAABB, 0x76C2, 0xAABC, 0x76F2, 0xAABD, 0x76F4, 0xAABE, 0x77E5, 0xAABF, 0x77FD, 0xAAC0, 0x793E, 0xAAC1, 0x7940, 0xAAC2, 0x7941, 0xAAC3, 0x79C9, 0xAAC4, 0x79C8, 0xAAC5, 0x7A7A, 0xAAC6, 0x7A79, 0xAAC7, 0x7AFA, 0xAAC8, 0x7CFE, 0xAAC9, 0x7F54, 0xAACA, 0x7F8C, 0xAACB, 0x7F8B, 0xAACC, 0x8005, 0xAACD, 0x80BA, 0xAACE, 0x80A5, 0xAACF, 0x80A2, 0xAAD0, 0x80B1, 0xAAD1, 0x80A1, 0xAAD2, 0x80AB, 0xAAD3, 0x80A9, 0xAAD4, 0x80B4, 0xAAD5, 0x80AA, 0xAAD6, 0x80AF, 0xAAD7, 0x81E5, 0xAAD8, 0x81FE, 0xAAD9, 0x820D, 0xAADA, 0x82B3, 0xAADB, 0x829D, 0xAADC, 0x8299, 0xAADD, 0x82AD, 0xAADE, 0x82BD, 0xAADF, 0x829F, 0xAAE0, 0x82B9, 0xAAE1, 0x82B1, 0xAAE2, 0x82AC, 0xAAE3, 0x82A5, 0xAAE4, 0x82AF, 0xAAE5, 0x82B8, 0xAAE6, 0x82A3, 0xAAE7, 0x82B0, 0xAAE8, 0x82BE, 0xAAE9, 0x82B7, 0xAAEA, 0x864E, 0xAAEB, 0x8671, 0xAAEC, 0x521D, 0xAAED, 0x8868, 0xAAEE, 0x8ECB, 0xAAEF, 0x8FCE, 0xAAF0, 0x8FD4, 0xAAF1, 0x8FD1, 0xAAF2, 0x90B5, 0xAAF3, 0x90B8, 0xAAF4, 0x90B1, 0xAAF5, 0x90B6, 0xAAF6, 0x91C7, 0xAAF7, 0x91D1, 0xAAF8, 0x9577, 0xAAF9, 0x9580, 0xAAFA, 0x961C, 0xAAFB, 0x9640, 0xAAFC, 0x963F, 0xAAFD, 0x963B, 0xAAFE, 0x9644, 0xAB40, 0x9642, 0xAB41, 0x96B9, 0xAB42, 0x96E8, 0xAB43, 0x9752, 0xAB44, 0x975E, 0xAB45, 0x4E9F, 0xAB46, 0x4EAD, 0xAB47, 0x4EAE, 0xAB48, 0x4FE1, 0xAB49, 0x4FB5, 0xAB4A, 0x4FAF, 0xAB4B, 0x4FBF, 0xAB4C, 0x4FE0, 0xAB4D, 0x4FD1, 0xAB4E, 0x4FCF, 0xAB4F, 0x4FDD, 0xAB50, 0x4FC3, 0xAB51, 0x4FB6, 0xAB52, 0x4FD8, 0xAB53, 0x4FDF, 0xAB54, 0x4FCA, 0xAB55, 0x4FD7, 0xAB56, 0x4FAE, 0xAB57, 0x4FD0, 0xAB58, 0x4FC4, 0xAB59, 0x4FC2, 0xAB5A, 0x4FDA, 0xAB5B, 0x4FCE, 0xAB5C, 0x4FDE, 0xAB5D, 0x4FB7, 0xAB5E, 0x5157, 0xAB5F, 0x5192, 0xAB60, 0x5191, 0xAB61, 0x51A0, 0xAB62, 0x524E, 0xAB63, 0x5243, 0xAB64, 0x524A, 0xAB65, 0x524D, 0xAB66, 0x524C, 0xAB67, 0x524B, 0xAB68, 0x5247, 0xAB69, 0x52C7, 0xAB6A, 0x52C9, 0xAB6B, 0x52C3, 0xAB6C, 0x52C1, 0xAB6D, 0x530D, 0xAB6E, 0x5357, 0xAB6F, 0x537B, 0xAB70, 0x539A, 0xAB71, 0x53DB, 0xAB72, 0x54AC, 0xAB73, 0x54C0, 0xAB74, 0x54A8, 0xAB75, 0x54CE, 0xAB76, 0x54C9, 0xAB77, 0x54B8, 0xAB78, 0x54A6, 0xAB79, 0x54B3, 0xAB7A, 0x54C7, 0xAB7B, 0x54C2, 0xAB7C, 0x54BD, 0xAB7D, 0x54AA, 0xAB7E, 0x54C1, 0xABA1, 0x54C4, 0xABA2, 0x54C8, 0xABA3, 0x54AF, 0xABA4, 0x54AB, 0xABA5, 0x54B1, 0xABA6, 0x54BB, 0xABA7, 0x54A9, 0xABA8, 0x54A7, 0xABA9, 0x54BF, 0xABAA, 0x56FF, 0xABAB, 0x5782, 0xABAC, 0x578B, 0xABAD, 0x57A0, 0xABAE, 0x57A3, 0xABAF, 0x57A2, 0xABB0, 0x57CE, 0xABB1, 0x57AE, 0xABB2, 0x5793, 0xABB3, 0x5955, 0xABB4, 0x5951, 0xABB5, 0x594F, 0xABB6, 0x594E, 0xABB7, 0x5950, 0xABB8, 0x59DC, 0xABB9, 0x59D8, 0xABBA, 0x59FF, 0xABBB, 0x59E3, 0xABBC, 0x59E8, 0xABBD, 0x5A03, 0xABBE, 0x59E5, 0xABBF, 0x59EA, 0xABC0, 0x59DA, 0xABC1, 0x59E6, 0xABC2, 0x5A01, 0xABC3, 0x59FB, 0xABC4, 0x5B69, 0xABC5, 0x5BA3, 0xABC6, 0x5BA6, 0xABC7, 0x5BA4, 0xABC8, 0x5BA2, 0xABC9, 0x5BA5, 0xABCA, 0x5C01, 0xABCB, 0x5C4E, 0xABCC, 0x5C4F, 0xABCD, 0x5C4D, 0xABCE, 0x5C4B, 0xABCF, 0x5CD9, 0xABD0, 0x5CD2, 0xABD1, 0x5DF7, 0xABD2, 0x5E1D, 0xABD3, 0x5E25, 0xABD4, 0x5E1F, 0xABD5, 0x5E7D, 0xABD6, 0x5EA0, 0xABD7, 0x5EA6, 0xABD8, 0x5EFA, 0xABD9, 0x5F08, 0xABDA, 0x5F2D, 0xABDB, 0x5F65, 0xABDC, 0x5F88, 0xABDD, 0x5F85, 0xABDE, 0x5F8A, 0xABDF, 0x5F8B, 0xABE0, 0x5F87, 0xABE1, 0x5F8C, 0xABE2, 0x5F89, 0xABE3, 0x6012, 0xABE4, 0x601D, 0xABE5, 0x6020, 0xABE6, 0x6025, 0xABE7, 0x600E, 0xABE8, 0x6028, 0xABE9, 0x604D, 0xABEA, 0x6070, 0xABEB, 0x6068, 0xABEC, 0x6062, 0xABED, 0x6046, 0xABEE, 0x6043, 0xABEF, 0x606C, 0xABF0, 0x606B, 0xABF1, 0x606A, 0xABF2, 0x6064, 0xABF3, 0x6241, 0xABF4, 0x62DC, 0xABF5, 0x6316, 0xABF6, 0x6309, 0xABF7, 0x62FC, 0xABF8, 0x62ED, 0xABF9, 0x6301, 0xABFA, 0x62EE, 0xABFB, 0x62FD, 0xABFC, 0x6307, 0xABFD, 0x62F1, 0xABFE, 0x62F7, 0xAC40, 0x62EF, 0xAC41, 0x62EC, 0xAC42, 0x62FE, 0xAC43, 0x62F4, 0xAC44, 0x6311, 0xAC45, 0x6302, 0xAC46, 0x653F, 0xAC47, 0x6545, 0xAC48, 0x65AB, 0xAC49, 0x65BD, 0xAC4A, 0x65E2, 0xAC4B, 0x6625, 0xAC4C, 0x662D, 0xAC4D, 0x6620, 0xAC4E, 0x6627, 0xAC4F, 0x662F, 0xAC50, 0x661F, 0xAC51, 0x6628, 0xAC52, 0x6631, 0xAC53, 0x6624, 0xAC54, 0x66F7, 0xAC55, 0x67FF, 0xAC56, 0x67D3, 0xAC57, 0x67F1, 0xAC58, 0x67D4, 0xAC59, 0x67D0, 0xAC5A, 0x67EC, 0xAC5B, 0x67B6, 0xAC5C, 0x67AF, 0xAC5D, 0x67F5, 0xAC5E, 0x67E9, 0xAC5F, 0x67EF, 0xAC60, 0x67C4, 0xAC61, 0x67D1, 0xAC62, 0x67B4, 0xAC63, 0x67DA, 0xAC64, 0x67E5, 0xAC65, 0x67B8, 0xAC66, 0x67CF, 0xAC67, 0x67DE, 0xAC68, 0x67F3, 0xAC69, 0x67B0, 0xAC6A, 0x67D9, 0xAC6B, 0x67E2, 0xAC6C, 0x67DD, 0xAC6D, 0x67D2, 0xAC6E, 0x6B6A, 0xAC6F, 0x6B83, 0xAC70, 0x6B86, 0xAC71, 0x6BB5, 0xAC72, 0x6BD2, 0xAC73, 0x6BD7, 0xAC74, 0x6C1F, 0xAC75, 0x6CC9, 0xAC76, 0x6D0B, 0xAC77, 0x6D32, 0xAC78, 0x6D2A, 0xAC79, 0x6D41, 0xAC7A, 0x6D25, 0xAC7B, 0x6D0C, 0xAC7C, 0x6D31, 0xAC7D, 0x6D1E, 0xAC7E, 0x6D17, 0xACA1, 0x6D3B, 0xACA2, 0x6D3D, 0xACA3, 0x6D3E, 0xACA4, 0x6D36, 0xACA5, 0x6D1B, 0xACA6, 0x6CF5, 0xACA7, 0x6D39, 0xACA8, 0x6D27, 0xACA9, 0x6D38, 0xACAA, 0x6D29, 0xACAB, 0x6D2E, 0xACAC, 0x6D35, 0xACAD, 0x6D0E, 0xACAE, 0x6D2B, 0xACAF, 0x70AB, 0xACB0, 0x70BA, 0xACB1, 0x70B3, 0xACB2, 0x70AC, 0xACB3, 0x70AF, 0xACB4, 0x70AD, 0xACB5, 0x70B8, 0xACB6, 0x70AE, 0xACB7, 0x70A4, 0xACB8, 0x7230, 0xACB9, 0x7272, 0xACBA, 0x726F, 0xACBB, 0x7274, 0xACBC, 0x72E9, 0xACBD, 0x72E0, 0xACBE, 0x72E1, 0xACBF, 0x73B7, 0xACC0, 0x73CA, 0xACC1, 0x73BB, 0xACC2, 0x73B2, 0xACC3, 0x73CD, 0xACC4, 0x73C0, 0xACC5, 0x73B3, 0xACC6, 0x751A, 0xACC7, 0x752D, 0xACC8, 0x754F, 0xACC9, 0x754C, 0xACCA, 0x754E, 0xACCB, 0x754B, 0xACCC, 0x75AB, 0xACCD, 0x75A4, 0xACCE, 0x75A5, 0xACCF, 0x75A2, 0xACD0, 0x75A3, 0xACD1, 0x7678, 0xACD2, 0x7686, 0xACD3, 0x7687, 0xACD4, 0x7688, 0xACD5, 0x76C8, 0xACD6, 0x76C6, 0xACD7, 0x76C3, 0xACD8, 0x76C5, 0xACD9, 0x7701, 0xACDA, 0x76F9, 0xACDB, 0x76F8, 0xACDC, 0x7709, 0xACDD, 0x770B, 0xACDE, 0x76FE, 0xACDF, 0x76FC, 0xACE0, 0x7707, 0xACE1, 0x77DC, 0xACE2, 0x7802, 0xACE3, 0x7814, 0xACE4, 0x780C, 0xACE5, 0x780D, 0xACE6, 0x7946, 0xACE7, 0x7949, 0xACE8, 0x7948, 0xACE9, 0x7947, 0xACEA, 0x79B9, 0xACEB, 0x79BA, 0xACEC, 0x79D1, 0xACED, 0x79D2, 0xACEE, 0x79CB, 0xACEF, 0x7A7F, 0xACF0, 0x7A81, 0xACF1, 0x7AFF, 0xACF2, 0x7AFD, 0xACF3, 0x7C7D, 0xACF4, 0x7D02, 0xACF5, 0x7D05, 0xACF6, 0x7D00, 0xACF7, 0x7D09, 0xACF8, 0x7D07, 0xACF9, 0x7D04, 0xACFA, 0x7D06, 0xACFB, 0x7F38, 0xACFC, 0x7F8E, 0xACFD, 0x7FBF, 0xACFE, 0x8004, 0xAD40, 0x8010, 0xAD41, 0x800D, 0xAD42, 0x8011, 0xAD43, 0x8036, 0xAD44, 0x80D6, 0xAD45, 0x80E5, 0xAD46, 0x80DA, 0xAD47, 0x80C3, 0xAD48, 0x80C4, 0xAD49, 0x80CC, 0xAD4A, 0x80E1, 0xAD4B, 0x80DB, 0xAD4C, 0x80CE, 0xAD4D, 0x80DE, 0xAD4E, 0x80E4, 0xAD4F, 0x80DD, 0xAD50, 0x81F4, 0xAD51, 0x8222, 0xAD52, 0x82E7, 0xAD53, 0x8303, 0xAD54, 0x8305, 0xAD55, 0x82E3, 0xAD56, 0x82DB, 0xAD57, 0x82E6, 0xAD58, 0x8304, 0xAD59, 0x82E5, 0xAD5A, 0x8302, 0xAD5B, 0x8309, 0xAD5C, 0x82D2, 0xAD5D, 0x82D7, 0xAD5E, 0x82F1, 0xAD5F, 0x8301, 0xAD60, 0x82DC, 0xAD61, 0x82D4, 0xAD62, 0x82D1, 0xAD63, 0x82DE, 0xAD64, 0x82D3, 0xAD65, 0x82DF, 0xAD66, 0x82EF, 0xAD67, 0x8306, 0xAD68, 0x8650, 0xAD69, 0x8679, 0xAD6A, 0x867B, 0xAD6B, 0x867A, 0xAD6C, 0x884D, 0xAD6D, 0x886B, 0xAD6E, 0x8981, 0xAD6F, 0x89D4, 0xAD70, 0x8A08, 0xAD71, 0x8A02, 0xAD72, 0x8A03, 0xAD73, 0x8C9E, 0xAD74, 0x8CA0, 0xAD75, 0x8D74, 0xAD76, 0x8D73, 0xAD77, 0x8DB4, 0xAD78, 0x8ECD, 0xAD79, 0x8ECC, 0xAD7A, 0x8FF0, 0xAD7B, 0x8FE6, 0xAD7C, 0x8FE2, 0xAD7D, 0x8FEA, 0xAD7E, 0x8FE5, 0xADA1, 0x8FED, 0xADA2, 0x8FEB, 0xADA3, 0x8FE4, 0xADA4, 0x8FE8, 0xADA5, 0x90CA, 0xADA6, 0x90CE, 0xADA7, 0x90C1, 0xADA8, 0x90C3, 0xADA9, 0x914B, 0xADAA, 0x914A, 0xADAB, 0x91CD, 0xADAC, 0x9582, 0xADAD, 0x9650, 0xADAE, 0x964B, 0xADAF, 0x964C, 0xADB0, 0x964D, 0xADB1, 0x9762, 0xADB2, 0x9769, 0xADB3, 0x97CB, 0xADB4, 0x97ED, 0xADB5, 0x97F3, 0xADB6, 0x9801, 0xADB7, 0x98A8, 0xADB8, 0x98DB, 0xADB9, 0x98DF, 0xADBA, 0x9996, 0xADBB, 0x9999, 0xADBC, 0x4E58, 0xADBD, 0x4EB3, 0xADBE, 0x500C, 0xADBF, 0x500D, 0xADC0, 0x5023, 0xADC1, 0x4FEF, 0xADC2, 0x5026, 0xADC3, 0x5025, 0xADC4, 0x4FF8, 0xADC5, 0x5029, 0xADC6, 0x5016, 0xADC7, 0x5006, 0xADC8, 0x503C, 0xADC9, 0x501F, 0xADCA, 0x501A, 0xADCB, 0x5012, 0xADCC, 0x5011, 0xADCD, 0x4FFA, 0xADCE, 0x5000, 0xADCF, 0x5014, 0xADD0, 0x5028, 0xADD1, 0x4FF1, 0xADD2, 0x5021, 0xADD3, 0x500B, 0xADD4, 0x5019, 0xADD5, 0x5018, 0xADD6, 0x4FF3, 0xADD7, 0x4FEE, 0xADD8, 0x502D, 0xADD9, 0x502A, 0xADDA, 0x4FFE, 0xADDB, 0x502B, 0xADDC, 0x5009, 0xADDD, 0x517C, 0xADDE, 0x51A4, 0xADDF, 0x51A5, 0xADE0, 0x51A2, 0xADE1, 0x51CD, 0xADE2, 0x51CC, 0xADE3, 0x51C6, 0xADE4, 0x51CB, 0xADE5, 0x5256, 0xADE6, 0x525C, 0xADE7, 0x5254, 0xADE8, 0x525B, 0xADE9, 0x525D, 0xADEA, 0x532A, 0xADEB, 0x537F, 0xADEC, 0x539F, 0xADED, 0x539D, 0xADEE, 0x53DF, 0xADEF, 0x54E8, 0xADF0, 0x5510, 0xADF1, 0x5501, 0xADF2, 0x5537, 0xADF3, 0x54FC, 0xADF4, 0x54E5, 0xADF5, 0x54F2, 0xADF6, 0x5506, 0xADF7, 0x54FA, 0xADF8, 0x5514, 0xADF9, 0x54E9, 0xADFA, 0x54ED, 0xADFB, 0x54E1, 0xADFC, 0x5509, 0xADFD, 0x54EE, 0xADFE, 0x54EA, 0xAE40, 0x54E6, 0xAE41, 0x5527, 0xAE42, 0x5507, 0xAE43, 0x54FD, 0xAE44, 0x550F, 0xAE45, 0x5703, 0xAE46, 0x5704, 0xAE47, 0x57C2, 0xAE48, 0x57D4, 0xAE49, 0x57CB, 0xAE4A, 0x57C3, 0xAE4B, 0x5809, 0xAE4C, 0x590F, 0xAE4D, 0x5957, 0xAE4E, 0x5958, 0xAE4F, 0x595A, 0xAE50, 0x5A11, 0xAE51, 0x5A18, 0xAE52, 0x5A1C, 0xAE53, 0x5A1F, 0xAE54, 0x5A1B, 0xAE55, 0x5A13, 0xAE56, 0x59EC, 0xAE57, 0x5A20, 0xAE58, 0x5A23, 0xAE59, 0x5A29, 0xAE5A, 0x5A25, 0xAE5B, 0x5A0C, 0xAE5C, 0x5A09, 0xAE5D, 0x5B6B, 0xAE5E, 0x5C58, 0xAE5F, 0x5BB0, 0xAE60, 0x5BB3, 0xAE61, 0x5BB6, 0xAE62, 0x5BB4, 0xAE63, 0x5BAE, 0xAE64, 0x5BB5, 0xAE65, 0x5BB9, 0xAE66, 0x5BB8, 0xAE67, 0x5C04, 0xAE68, 0x5C51, 0xAE69, 0x5C55, 0xAE6A, 0x5C50, 0xAE6B, 0x5CED, 0xAE6C, 0x5CFD, 0xAE6D, 0x5CFB, 0xAE6E, 0x5CEA, 0xAE6F, 0x5CE8, 0xAE70, 0x5CF0, 0xAE71, 0x5CF6, 0xAE72, 0x5D01, 0xAE73, 0x5CF4, 0xAE74, 0x5DEE, 0xAE75, 0x5E2D, 0xAE76, 0x5E2B, 0xAE77, 0x5EAB, 0xAE78, 0x5EAD, 0xAE79, 0x5EA7, 0xAE7A, 0x5F31, 0xAE7B, 0x5F92, 0xAE7C, 0x5F91, 0xAE7D, 0x5F90, 0xAE7E, 0x6059, 0xAEA1, 0x6063, 0xAEA2, 0x6065, 0xAEA3, 0x6050, 0xAEA4, 0x6055, 0xAEA5, 0x606D, 0xAEA6, 0x6069, 0xAEA7, 0x606F, 0xAEA8, 0x6084, 0xAEA9, 0x609F, 0xAEAA, 0x609A, 0xAEAB, 0x608D, 0xAEAC, 0x6094, 0xAEAD, 0x608C, 0xAEAE, 0x6085, 0xAEAF, 0x6096, 0xAEB0, 0x6247, 0xAEB1, 0x62F3, 0xAEB2, 0x6308, 0xAEB3, 0x62FF, 0xAEB4, 0x634E, 0xAEB5, 0x633E, 0xAEB6, 0x632F, 0xAEB7, 0x6355, 0xAEB8, 0x6342, 0xAEB9, 0x6346, 0xAEBA, 0x634F, 0xAEBB, 0x6349, 0xAEBC, 0x633A, 0xAEBD, 0x6350, 0xAEBE, 0x633D, 0xAEBF, 0x632A, 0xAEC0, 0x632B, 0xAEC1, 0x6328, 0xAEC2, 0x634D, 0xAEC3, 0x634C, 0xAEC4, 0x6548, 0xAEC5, 0x6549, 0xAEC6, 0x6599, 0xAEC7, 0x65C1, 0xAEC8, 0x65C5, 0xAEC9, 0x6642, 0xAECA, 0x6649, 0xAECB, 0x664F, 0xAECC, 0x6643, 0xAECD, 0x6652, 0xAECE, 0x664C, 0xAECF, 0x6645, 0xAED0, 0x6641, 0xAED1, 0x66F8, 0xAED2, 0x6714, 0xAED3, 0x6715, 0xAED4, 0x6717, 0xAED5, 0x6821, 0xAED6, 0x6838, 0xAED7, 0x6848, 0xAED8, 0x6846, 0xAED9, 0x6853, 0xAEDA, 0x6839, 0xAEDB, 0x6842, 0xAEDC, 0x6854, 0xAEDD, 0x6829, 0xAEDE, 0x68B3, 0xAEDF, 0x6817, 0xAEE0, 0x684C, 0xAEE1, 0x6851, 0xAEE2, 0x683D, 0xAEE3, 0x67F4, 0xAEE4, 0x6850, 0xAEE5, 0x6840, 0xAEE6, 0x683C, 0xAEE7, 0x6843, 0xAEE8, 0x682A, 0xAEE9, 0x6845, 0xAEEA, 0x6813, 0xAEEB, 0x6818, 0xAEEC, 0x6841, 0xAEED, 0x6B8A, 0xAEEE, 0x6B89, 0xAEEF, 0x6BB7, 0xAEF0, 0x6C23, 0xAEF1, 0x6C27, 0xAEF2, 0x6C28, 0xAEF3, 0x6C26, 0xAEF4, 0x6C24, 0xAEF5, 0x6CF0, 0xAEF6, 0x6D6A, 0xAEF7, 0x6D95, 0xAEF8, 0x6D88, 0xAEF9, 0x6D87, 0xAEFA, 0x6D66, 0xAEFB, 0x6D78, 0xAEFC, 0x6D77, 0xAEFD, 0x6D59, 0xAEFE, 0x6D93, 0xAF40, 0x6D6C, 0xAF41, 0x6D89, 0xAF42, 0x6D6E, 0xAF43, 0x6D5A, 0xAF44, 0x6D74, 0xAF45, 0x6D69, 0xAF46, 0x6D8C, 0xAF47, 0x6D8A, 0xAF48, 0x6D79, 0xAF49, 0x6D85, 0xAF4A, 0x6D65, 0xAF4B, 0x6D94, 0xAF4C, 0x70CA, 0xAF4D, 0x70D8, 0xAF4E, 0x70E4, 0xAF4F, 0x70D9, 0xAF50, 0x70C8, 0xAF51, 0x70CF, 0xAF52, 0x7239, 0xAF53, 0x7279, 0xAF54, 0x72FC, 0xAF55, 0x72F9, 0xAF56, 0x72FD, 0xAF57, 0x72F8, 0xAF58, 0x72F7, 0xAF59, 0x7386, 0xAF5A, 0x73ED, 0xAF5B, 0x7409, 0xAF5C, 0x73EE, 0xAF5D, 0x73E0, 0xAF5E, 0x73EA, 0xAF5F, 0x73DE, 0xAF60, 0x7554, 0xAF61, 0x755D, 0xAF62, 0x755C, 0xAF63, 0x755A, 0xAF64, 0x7559, 0xAF65, 0x75BE, 0xAF66, 0x75C5, 0xAF67, 0x75C7, 0xAF68, 0x75B2, 0xAF69, 0x75B3, 0xAF6A, 0x75BD, 0xAF6B, 0x75BC, 0xAF6C, 0x75B9, 0xAF6D, 0x75C2, 0xAF6E, 0x75B8, 0xAF6F, 0x768B, 0xAF70, 0x76B0, 0xAF71, 0x76CA, 0xAF72, 0x76CD, 0xAF73, 0x76CE, 0xAF74, 0x7729, 0xAF75, 0x771F, 0xAF76, 0x7720, 0xAF77, 0x7728, 0xAF78, 0x77E9, 0xAF79, 0x7830, 0xAF7A, 0x7827, 0xAF7B, 0x7838, 0xAF7C, 0x781D, 0xAF7D, 0x7834, 0xAF7E, 0x7837, 0xAFA1, 0x7825, 0xAFA2, 0x782D, 0xAFA3, 0x7820, 0xAFA4, 0x781F, 0xAFA5, 0x7832, 0xAFA6, 0x7955, 0xAFA7, 0x7950, 0xAFA8, 0x7960, 0xAFA9, 0x795F, 0xAFAA, 0x7956, 0xAFAB, 0x795E, 0xAFAC, 0x795D, 0xAFAD, 0x7957, 0xAFAE, 0x795A, 0xAFAF, 0x79E4, 0xAFB0, 0x79E3, 0xAFB1, 0x79E7, 0xAFB2, 0x79DF, 0xAFB3, 0x79E6, 0xAFB4, 0x79E9, 0xAFB5, 0x79D8, 0xAFB6, 0x7A84, 0xAFB7, 0x7A88, 0xAFB8, 0x7AD9, 0xAFB9, 0x7B06, 0xAFBA, 0x7B11, 0xAFBB, 0x7C89, 0xAFBC, 0x7D21, 0xAFBD, 0x7D17, 0xAFBE, 0x7D0B, 0xAFBF, 0x7D0A, 0xAFC0, 0x7D20, 0xAFC1, 0x7D22, 0xAFC2, 0x7D14, 0xAFC3, 0x7D10, 0xAFC4, 0x7D15, 0xAFC5, 0x7D1A, 0xAFC6, 0x7D1C, 0xAFC7, 0x7D0D, 0xAFC8, 0x7D19, 0xAFC9, 0x7D1B, 0xAFCA, 0x7F3A, 0xAFCB, 0x7F5F, 0xAFCC, 0x7F94, 0xAFCD, 0x7FC5, 0xAFCE, 0x7FC1, 0xAFCF, 0x8006, 0xAFD0, 0x8018, 0xAFD1, 0x8015, 0xAFD2, 0x8019, 0xAFD3, 0x8017, 0xAFD4, 0x803D, 0xAFD5, 0x803F, 0xAFD6, 0x80F1, 0xAFD7, 0x8102, 0xAFD8, 0x80F0, 0xAFD9, 0x8105, 0xAFDA, 0x80ED, 0xAFDB, 0x80F4, 0xAFDC, 0x8106, 0xAFDD, 0x80F8, 0xAFDE, 0x80F3, 0xAFDF, 0x8108, 0xAFE0, 0x80FD, 0xAFE1, 0x810A, 0xAFE2, 0x80FC, 0xAFE3, 0x80EF, 0xAFE4, 0x81ED, 0xAFE5, 0x81EC, 0xAFE6, 0x8200, 0xAFE7, 0x8210, 0xAFE8, 0x822A, 0xAFE9, 0x822B, 0xAFEA, 0x8228, 0xAFEB, 0x822C, 0xAFEC, 0x82BB, 0xAFED, 0x832B, 0xAFEE, 0x8352, 0xAFEF, 0x8354, 0xAFF0, 0x834A, 0xAFF1, 0x8338, 0xAFF2, 0x8350, 0xAFF3, 0x8349, 0xAFF4, 0x8335, 0xAFF5, 0x8334, 0xAFF6, 0x834F, 0xAFF7, 0x8332, 0xAFF8, 0x8339, 0xAFF9, 0x8336, 0xAFFA, 0x8317, 0xAFFB, 0x8340, 0xAFFC, 0x8331, 0xAFFD, 0x8328, 0xAFFE, 0x8343, 0xB040, 0x8654, 0xB041, 0x868A, 0xB042, 0x86AA, 0xB043, 0x8693, 0xB044, 0x86A4, 0xB045, 0x86A9, 0xB046, 0x868C, 0xB047, 0x86A3, 0xB048, 0x869C, 0xB049, 0x8870, 0xB04A, 0x8877, 0xB04B, 0x8881, 0xB04C, 0x8882, 0xB04D, 0x887D, 0xB04E, 0x8879, 0xB04F, 0x8A18, 0xB050, 0x8A10, 0xB051, 0x8A0E, 0xB052, 0x8A0C, 0xB053, 0x8A15, 0xB054, 0x8A0A, 0xB055, 0x8A17, 0xB056, 0x8A13, 0xB057, 0x8A16, 0xB058, 0x8A0F, 0xB059, 0x8A11, 0xB05A, 0x8C48, 0xB05B, 0x8C7A, 0xB05C, 0x8C79, 0xB05D, 0x8CA1, 0xB05E, 0x8CA2, 0xB05F, 0x8D77, 0xB060, 0x8EAC, 0xB061, 0x8ED2, 0xB062, 0x8ED4, 0xB063, 0x8ECF, 0xB064, 0x8FB1, 0xB065, 0x9001, 0xB066, 0x9006, 0xB067, 0x8FF7, 0xB068, 0x9000, 0xB069, 0x8FFA, 0xB06A, 0x8FF4, 0xB06B, 0x9003, 0xB06C, 0x8FFD, 0xB06D, 0x9005, 0xB06E, 0x8FF8, 0xB06F, 0x9095, 0xB070, 0x90E1, 0xB071, 0x90DD, 0xB072, 0x90E2, 0xB073, 0x9152, 0xB074, 0x914D, 0xB075, 0x914C, 0xB076, 0x91D8, 0xB077, 0x91DD, 0xB078, 0x91D7, 0xB079, 0x91DC, 0xB07A, 0x91D9, 0xB07B, 0x9583, 0xB07C, 0x9662, 0xB07D, 0x9663, 0xB07E, 0x9661, 0xB0A1, 0x965B, 0xB0A2, 0x965D, 0xB0A3, 0x9664, 0xB0A4, 0x9658, 0xB0A5, 0x965E, 0xB0A6, 0x96BB, 0xB0A7, 0x98E2, 0xB0A8, 0x99AC, 0xB0A9, 0x9AA8, 0xB0AA, 0x9AD8, 0xB0AB, 0x9B25, 0xB0AC, 0x9B32, 0xB0AD, 0x9B3C, 0xB0AE, 0x4E7E, 0xB0AF, 0x507A, 0xB0B0, 0x507D, 0xB0B1, 0x505C, 0xB0B2, 0x5047, 0xB0B3, 0x5043, 0xB0B4, 0x504C, 0xB0B5, 0x505A, 0xB0B6, 0x5049, 0xB0B7, 0x5065, 0xB0B8, 0x5076, 0xB0B9, 0x504E, 0xB0BA, 0x5055, 0xB0BB, 0x5075, 0xB0BC, 0x5074, 0xB0BD, 0x5077, 0xB0BE, 0x504F, 0xB0BF, 0x500F, 0xB0C0, 0x506F, 0xB0C1, 0x506D, 0xB0C2, 0x515C, 0xB0C3, 0x5195, 0xB0C4, 0x51F0, 0xB0C5, 0x526A, 0xB0C6, 0x526F, 0xB0C7, 0x52D2, 0xB0C8, 0x52D9, 0xB0C9, 0x52D8, 0xB0CA, 0x52D5, 0xB0CB, 0x5310, 0xB0CC, 0x530F, 0xB0CD, 0x5319, 0xB0CE, 0x533F, 0xB0CF, 0x5340, 0xB0D0, 0x533E, 0xB0D1, 0x53C3, 0xB0D2, 0x66FC, 0xB0D3, 0x5546, 0xB0D4, 0x556A, 0xB0D5, 0x5566, 0xB0D6, 0x5544, 0xB0D7, 0x555E, 0xB0D8, 0x5561, 0xB0D9, 0x5543, 0xB0DA, 0x554A, 0xB0DB, 0x5531, 0xB0DC, 0x5556, 0xB0DD, 0x554F, 0xB0DE, 0x5555, 0xB0DF, 0x552F, 0xB0E0, 0x5564, 0xB0E1, 0x5538, 0xB0E2, 0x552E, 0xB0E3, 0x555C, 0xB0E4, 0x552C, 0xB0E5, 0x5563, 0xB0E6, 0x5533, 0xB0E7, 0x5541, 0xB0E8, 0x5557, 0xB0E9, 0x5708, 0xB0EA, 0x570B, 0xB0EB, 0x5709, 0xB0EC, 0x57DF, 0xB0ED, 0x5805, 0xB0EE, 0x580A, 0xB0EF, 0x5806, 0xB0F0, 0x57E0, 0xB0F1, 0x57E4, 0xB0F2, 0x57FA, 0xB0F3, 0x5802, 0xB0F4, 0x5835, 0xB0F5, 0x57F7, 0xB0F6, 0x57F9, 0xB0F7, 0x5920, 0xB0F8, 0x5962, 0xB0F9, 0x5A36, 0xB0FA, 0x5A41, 0xB0FB, 0x5A49, 0xB0FC, 0x5A66, 0xB0FD, 0x5A6A, 0xB0FE, 0x5A40, 0xB140, 0x5A3C, 0xB141, 0x5A62, 0xB142, 0x5A5A, 0xB143, 0x5A46, 0xB144, 0x5A4A, 0xB145, 0x5B70, 0xB146, 0x5BC7, 0xB147, 0x5BC5, 0xB148, 0x5BC4, 0xB149, 0x5BC2, 0xB14A, 0x5BBF, 0xB14B, 0x5BC6, 0xB14C, 0x5C09, 0xB14D, 0x5C08, 0xB14E, 0x5C07, 0xB14F, 0x5C60, 0xB150, 0x5C5C, 0xB151, 0x5C5D, 0xB152, 0x5D07, 0xB153, 0x5D06, 0xB154, 0x5D0E, 0xB155, 0x5D1B, 0xB156, 0x5D16, 0xB157, 0x5D22, 0xB158, 0x5D11, 0xB159, 0x5D29, 0xB15A, 0x5D14, 0xB15B, 0x5D19, 0xB15C, 0x5D24, 0xB15D, 0x5D27, 0xB15E, 0x5D17, 0xB15F, 0x5DE2, 0xB160, 0x5E38, 0xB161, 0x5E36, 0xB162, 0x5E33, 0xB163, 0x5E37, 0xB164, 0x5EB7, 0xB165, 0x5EB8, 0xB166, 0x5EB6, 0xB167, 0x5EB5, 0xB168, 0x5EBE, 0xB169, 0x5F35, 0xB16A, 0x5F37, 0xB16B, 0x5F57, 0xB16C, 0x5F6C, 0xB16D, 0x5F69, 0xB16E, 0x5F6B, 0xB16F, 0x5F97, 0xB170, 0x5F99, 0xB171, 0x5F9E, 0xB172, 0x5F98, 0xB173, 0x5FA1, 0xB174, 0x5FA0, 0xB175, 0x5F9C, 0xB176, 0x607F, 0xB177, 0x60A3, 0xB178, 0x6089, 0xB179, 0x60A0, 0xB17A, 0x60A8, 0xB17B, 0x60CB, 0xB17C, 0x60B4, 0xB17D, 0x60E6, 0xB17E, 0x60BD, 0xB1A1, 0x60C5, 0xB1A2, 0x60BB, 0xB1A3, 0x60B5, 0xB1A4, 0x60DC, 0xB1A5, 0x60BC, 0xB1A6, 0x60D8, 0xB1A7, 0x60D5, 0xB1A8, 0x60C6, 0xB1A9, 0x60DF, 0xB1AA, 0x60B8, 0xB1AB, 0x60DA, 0xB1AC, 0x60C7, 0xB1AD, 0x621A, 0xB1AE, 0x621B, 0xB1AF, 0x6248, 0xB1B0, 0x63A0, 0xB1B1, 0x63A7, 0xB1B2, 0x6372, 0xB1B3, 0x6396, 0xB1B4, 0x63A2, 0xB1B5, 0x63A5, 0xB1B6, 0x6377, 0xB1B7, 0x6367, 0xB1B8, 0x6398, 0xB1B9, 0x63AA, 0xB1BA, 0x6371, 0xB1BB, 0x63A9, 0xB1BC, 0x6389, 0xB1BD, 0x6383, 0xB1BE, 0x639B, 0xB1BF, 0x636B, 0xB1C0, 0x63A8, 0xB1C1, 0x6384, 0xB1C2, 0x6388, 0xB1C3, 0x6399, 0xB1C4, 0x63A1, 0xB1C5, 0x63AC, 0xB1C6, 0x6392, 0xB1C7, 0x638F, 0xB1C8, 0x6380, 0xB1C9, 0x637B, 0xB1CA, 0x6369, 0xB1CB, 0x6368, 0xB1CC, 0x637A, 0xB1CD, 0x655D, 0xB1CE, 0x6556, 0xB1CF, 0x6551, 0xB1D0, 0x6559, 0xB1D1, 0x6557, 0xB1D2, 0x555F, 0xB1D3, 0x654F, 0xB1D4, 0x6558, 0xB1D5, 0x6555, 0xB1D6, 0x6554, 0xB1D7, 0x659C, 0xB1D8, 0x659B, 0xB1D9, 0x65AC, 0xB1DA, 0x65CF, 0xB1DB, 0x65CB, 0xB1DC, 0x65CC, 0xB1DD, 0x65CE, 0xB1DE, 0x665D, 0xB1DF, 0x665A, 0xB1E0, 0x6664, 0xB1E1, 0x6668, 0xB1E2, 0x6666, 0xB1E3, 0x665E, 0xB1E4, 0x66F9, 0xB1E5, 0x52D7, 0xB1E6, 0x671B, 0xB1E7, 0x6881, 0xB1E8, 0x68AF, 0xB1E9, 0x68A2, 0xB1EA, 0x6893, 0xB1EB, 0x68B5, 0xB1EC, 0x687F, 0xB1ED, 0x6876, 0xB1EE, 0x68B1, 0xB1EF, 0x68A7, 0xB1F0, 0x6897, 0xB1F1, 0x68B0, 0xB1F2, 0x6883, 0xB1F3, 0x68C4, 0xB1F4, 0x68AD, 0xB1F5, 0x6886, 0xB1F6, 0x6885, 0xB1F7, 0x6894, 0xB1F8, 0x689D, 0xB1F9, 0x68A8, 0xB1FA, 0x689F, 0xB1FB, 0x68A1, 0xB1FC, 0x6882, 0xB1FD, 0x6B32, 0xB1FE, 0x6BBA, 0xB240, 0x6BEB, 0xB241, 0x6BEC, 0xB242, 0x6C2B, 0xB243, 0x6D8E, 0xB244, 0x6DBC, 0xB245, 0x6DF3, 0xB246, 0x6DD9, 0xB247, 0x6DB2, 0xB248, 0x6DE1, 0xB249, 0x6DCC, 0xB24A, 0x6DE4, 0xB24B, 0x6DFB, 0xB24C, 0x6DFA, 0xB24D, 0x6E05, 0xB24E, 0x6DC7, 0xB24F, 0x6DCB, 0xB250, 0x6DAF, 0xB251, 0x6DD1, 0xB252, 0x6DAE, 0xB253, 0x6DDE, 0xB254, 0x6DF9, 0xB255, 0x6DB8, 0xB256, 0x6DF7, 0xB257, 0x6DF5, 0xB258, 0x6DC5, 0xB259, 0x6DD2, 0xB25A, 0x6E1A, 0xB25B, 0x6DB5, 0xB25C, 0x6DDA, 0xB25D, 0x6DEB, 0xB25E, 0x6DD8, 0xB25F, 0x6DEA, 0xB260, 0x6DF1, 0xB261, 0x6DEE, 0xB262, 0x6DE8, 0xB263, 0x6DC6, 0xB264, 0x6DC4, 0xB265, 0x6DAA, 0xB266, 0x6DEC, 0xB267, 0x6DBF, 0xB268, 0x6DE6, 0xB269, 0x70F9, 0xB26A, 0x7109, 0xB26B, 0x710A, 0xB26C, 0x70FD, 0xB26D, 0x70EF, 0xB26E, 0x723D, 0xB26F, 0x727D, 0xB270, 0x7281, 0xB271, 0x731C, 0xB272, 0x731B, 0xB273, 0x7316, 0xB274, 0x7313, 0xB275, 0x7319, 0xB276, 0x7387, 0xB277, 0x7405, 0xB278, 0x740A, 0xB279, 0x7403, 0xB27A, 0x7406, 0xB27B, 0x73FE, 0xB27C, 0x740D, 0xB27D, 0x74E0, 0xB27E, 0x74F6, 0xB2A1, 0x74F7, 0xB2A2, 0x751C, 0xB2A3, 0x7522, 0xB2A4, 0x7565, 0xB2A5, 0x7566, 0xB2A6, 0x7562, 0xB2A7, 0x7570, 0xB2A8, 0x758F, 0xB2A9, 0x75D4, 0xB2AA, 0x75D5, 0xB2AB, 0x75B5, 0xB2AC, 0x75CA, 0xB2AD, 0x75CD, 0xB2AE, 0x768E, 0xB2AF, 0x76D4, 0xB2B0, 0x76D2, 0xB2B1, 0x76DB, 0xB2B2, 0x7737, 0xB2B3, 0x773E, 0xB2B4, 0x773C, 0xB2B5, 0x7736, 0xB2B6, 0x7738, 0xB2B7, 0x773A, 0xB2B8, 0x786B, 0xB2B9, 0x7843, 0xB2BA, 0x784E, 0xB2BB, 0x7965, 0xB2BC, 0x7968, 0xB2BD, 0x796D, 0xB2BE, 0x79FB, 0xB2BF, 0x7A92, 0xB2C0, 0x7A95, 0xB2C1, 0x7B20, 0xB2C2, 0x7B28, 0xB2C3, 0x7B1B, 0xB2C4, 0x7B2C, 0xB2C5, 0x7B26, 0xB2C6, 0x7B19, 0xB2C7, 0x7B1E, 0xB2C8, 0x7B2E, 0xB2C9, 0x7C92, 0xB2CA, 0x7C97, 0xB2CB, 0x7C95, 0xB2CC, 0x7D46, 0xB2CD, 0x7D43, 0xB2CE, 0x7D71, 0xB2CF, 0x7D2E, 0xB2D0, 0x7D39, 0xB2D1, 0x7D3C, 0xB2D2, 0x7D40, 0xB2D3, 0x7D30, 0xB2D4, 0x7D33, 0xB2D5, 0x7D44, 0xB2D6, 0x7D2F, 0xB2D7, 0x7D42, 0xB2D8, 0x7D32, 0xB2D9, 0x7D31, 0xB2DA, 0x7F3D, 0xB2DB, 0x7F9E, 0xB2DC, 0x7F9A, 0xB2DD, 0x7FCC, 0xB2DE, 0x7FCE, 0xB2DF, 0x7FD2, 0xB2E0, 0x801C, 0xB2E1, 0x804A, 0xB2E2, 0x8046, 0xB2E3, 0x812F, 0xB2E4, 0x8116, 0xB2E5, 0x8123, 0xB2E6, 0x812B, 0xB2E7, 0x8129, 0xB2E8, 0x8130, 0xB2E9, 0x8124, 0xB2EA, 0x8202, 0xB2EB, 0x8235, 0xB2EC, 0x8237, 0xB2ED, 0x8236, 0xB2EE, 0x8239, 0xB2EF, 0x838E, 0xB2F0, 0x839E, 0xB2F1, 0x8398, 0xB2F2, 0x8378, 0xB2F3, 0x83A2, 0xB2F4, 0x8396, 0xB2F5, 0x83BD, 0xB2F6, 0x83AB, 0xB2F7, 0x8392, 0xB2F8, 0x838A, 0xB2F9, 0x8393, 0xB2FA, 0x8389, 0xB2FB, 0x83A0, 0xB2FC, 0x8377, 0xB2FD, 0x837B, 0xB2FE, 0x837C, 0xB340, 0x8386, 0xB341, 0x83A7, 0xB342, 0x8655, 0xB343, 0x5F6A, 0xB344, 0x86C7, 0xB345, 0x86C0, 0xB346, 0x86B6, 0xB347, 0x86C4, 0xB348, 0x86B5, 0xB349, 0x86C6, 0xB34A, 0x86CB, 0xB34B, 0x86B1, 0xB34C, 0x86AF, 0xB34D, 0x86C9, 0xB34E, 0x8853, 0xB34F, 0x889E, 0xB350, 0x8888, 0xB351, 0x88AB, 0xB352, 0x8892, 0xB353, 0x8896, 0xB354, 0x888D, 0xB355, 0x888B, 0xB356, 0x8993, 0xB357, 0x898F, 0xB358, 0x8A2A, 0xB359, 0x8A1D, 0xB35A, 0x8A23, 0xB35B, 0x8A25, 0xB35C, 0x8A31, 0xB35D, 0x8A2D, 0xB35E, 0x8A1F, 0xB35F, 0x8A1B, 0xB360, 0x8A22, 0xB361, 0x8C49, 0xB362, 0x8C5A, 0xB363, 0x8CA9, 0xB364, 0x8CAC, 0xB365, 0x8CAB, 0xB366, 0x8CA8, 0xB367, 0x8CAA, 0xB368, 0x8CA7, 0xB369, 0x8D67, 0xB36A, 0x8D66, 0xB36B, 0x8DBE, 0xB36C, 0x8DBA, 0xB36D, 0x8EDB, 0xB36E, 0x8EDF, 0xB36F, 0x9019, 0xB370, 0x900D, 0xB371, 0x901A, 0xB372, 0x9017, 0xB373, 0x9023, 0xB374, 0x901F, 0xB375, 0x901D, 0xB376, 0x9010, 0xB377, 0x9015, 0xB378, 0x901E, 0xB379, 0x9020, 0xB37A, 0x900F, 0xB37B, 0x9022, 0xB37C, 0x9016, 0xB37D, 0x901B, 0xB37E, 0x9014, 0xB3A1, 0x90E8, 0xB3A2, 0x90ED, 0xB3A3, 0x90FD, 0xB3A4, 0x9157, 0xB3A5, 0x91CE, 0xB3A6, 0x91F5, 0xB3A7, 0x91E6, 0xB3A8, 0x91E3, 0xB3A9, 0x91E7, 0xB3AA, 0x91ED, 0xB3AB, 0x91E9, 0xB3AC, 0x9589, 0xB3AD, 0x966A, 0xB3AE, 0x9675, 0xB3AF, 0x9673, 0xB3B0, 0x9678, 0xB3B1, 0x9670, 0xB3B2, 0x9674, 0xB3B3, 0x9676, 0xB3B4, 0x9677, 0xB3B5, 0x966C, 0xB3B6, 0x96C0, 0xB3B7, 0x96EA, 0xB3B8, 0x96E9, 0xB3B9, 0x7AE0, 0xB3BA, 0x7ADF, 0xB3BB, 0x9802, 0xB3BC, 0x9803, 0xB3BD, 0x9B5A, 0xB3BE, 0x9CE5, 0xB3BF, 0x9E75, 0xB3C0, 0x9E7F, 0xB3C1, 0x9EA5, 0xB3C2, 0x9EBB, 0xB3C3, 0x50A2, 0xB3C4, 0x508D, 0xB3C5, 0x5085, 0xB3C6, 0x5099, 0xB3C7, 0x5091, 0xB3C8, 0x5080, 0xB3C9, 0x5096, 0xB3CA, 0x5098, 0xB3CB, 0x509A, 0xB3CC, 0x6700, 0xB3CD, 0x51F1, 0xB3CE, 0x5272, 0xB3CF, 0x5274, 0xB3D0, 0x5275, 0xB3D1, 0x5269, 0xB3D2, 0x52DE, 0xB3D3, 0x52DD, 0xB3D4, 0x52DB, 0xB3D5, 0x535A, 0xB3D6, 0x53A5, 0xB3D7, 0x557B, 0xB3D8, 0x5580, 0xB3D9, 0x55A7, 0xB3DA, 0x557C, 0xB3DB, 0x558A, 0xB3DC, 0x559D, 0xB3DD, 0x5598, 0xB3DE, 0x5582, 0xB3DF, 0x559C, 0xB3E0, 0x55AA, 0xB3E1, 0x5594, 0xB3E2, 0x5587, 0xB3E3, 0x558B, 0xB3E4, 0x5583, 0xB3E5, 0x55B3, 0xB3E6, 0x55AE, 0xB3E7, 0x559F, 0xB3E8, 0x553E, 0xB3E9, 0x55B2, 0xB3EA, 0x559A, 0xB3EB, 0x55BB, 0xB3EC, 0x55AC, 0xB3ED, 0x55B1, 0xB3EE, 0x557E, 0xB3EF, 0x5589, 0xB3F0, 0x55AB, 0xB3F1, 0x5599, 0xB3F2, 0x570D, 0xB3F3, 0x582F, 0xB3F4, 0x582A, 0xB3F5, 0x5834, 0xB3F6, 0x5824, 0xB3F7, 0x5830, 0xB3F8, 0x5831, 0xB3F9, 0x5821, 0xB3FA, 0x581D, 0xB3FB, 0x5820, 0xB3FC, 0x58F9, 0xB3FD, 0x58FA, 0xB3FE, 0x5960, 0xB440, 0x5A77, 0xB441, 0x5A9A, 0xB442, 0x5A7F, 0xB443, 0x5A92, 0xB444, 0x5A9B, 0xB445, 0x5AA7, 0xB446, 0x5B73, 0xB447, 0x5B71, 0xB448, 0x5BD2, 0xB449, 0x5BCC, 0xB44A, 0x5BD3, 0xB44B, 0x5BD0, 0xB44C, 0x5C0A, 0xB44D, 0x5C0B, 0xB44E, 0x5C31, 0xB44F, 0x5D4C, 0xB450, 0x5D50, 0xB451, 0x5D34, 0xB452, 0x5D47, 0xB453, 0x5DFD, 0xB454, 0x5E45, 0xB455, 0x5E3D, 0xB456, 0x5E40, 0xB457, 0x5E43, 0xB458, 0x5E7E, 0xB459, 0x5ECA, 0xB45A, 0x5EC1, 0xB45B, 0x5EC2, 0xB45C, 0x5EC4, 0xB45D, 0x5F3C, 0xB45E, 0x5F6D, 0xB45F, 0x5FA9, 0xB460, 0x5FAA, 0xB461, 0x5FA8, 0xB462, 0x60D1, 0xB463, 0x60E1, 0xB464, 0x60B2, 0xB465, 0x60B6, 0xB466, 0x60E0, 0xB467, 0x611C, 0xB468, 0x6123, 0xB469, 0x60FA, 0xB46A, 0x6115, 0xB46B, 0x60F0, 0xB46C, 0x60FB, 0xB46D, 0x60F4, 0xB46E, 0x6168, 0xB46F, 0x60F1, 0xB470, 0x610E, 0xB471, 0x60F6, 0xB472, 0x6109, 0xB473, 0x6100, 0xB474, 0x6112, 0xB475, 0x621F, 0xB476, 0x6249, 0xB477, 0x63A3, 0xB478, 0x638C, 0xB479, 0x63CF, 0xB47A, 0x63C0, 0xB47B, 0x63E9, 0xB47C, 0x63C9, 0xB47D, 0x63C6, 0xB47E, 0x63CD, 0xB4A1, 0x63D2, 0xB4A2, 0x63E3, 0xB4A3, 0x63D0, 0xB4A4, 0x63E1, 0xB4A5, 0x63D6, 0xB4A6, 0x63ED, 0xB4A7, 0x63EE, 0xB4A8, 0x6376, 0xB4A9, 0x63F4, 0xB4AA, 0x63EA, 0xB4AB, 0x63DB, 0xB4AC, 0x6452, 0xB4AD, 0x63DA, 0xB4AE, 0x63F9, 0xB4AF, 0x655E, 0xB4B0, 0x6566, 0xB4B1, 0x6562, 0xB4B2, 0x6563, 0xB4B3, 0x6591, 0xB4B4, 0x6590, 0xB4B5, 0x65AF, 0xB4B6, 0x666E, 0xB4B7, 0x6670, 0xB4B8, 0x6674, 0xB4B9, 0x6676, 0xB4BA, 0x666F, 0xB4BB, 0x6691, 0xB4BC, 0x667A, 0xB4BD, 0x667E, 0xB4BE, 0x6677, 0xB4BF, 0x66FE, 0xB4C0, 0x66FF, 0xB4C1, 0x671F, 0xB4C2, 0x671D, 0xB4C3, 0x68FA, 0xB4C4, 0x68D5, 0xB4C5, 0x68E0, 0xB4C6, 0x68D8, 0xB4C7, 0x68D7, 0xB4C8, 0x6905, 0xB4C9, 0x68DF, 0xB4CA, 0x68F5, 0xB4CB, 0x68EE, 0xB4CC, 0x68E7, 0xB4CD, 0x68F9, 0xB4CE, 0x68D2, 0xB4CF, 0x68F2, 0xB4D0, 0x68E3, 0xB4D1, 0x68CB, 0xB4D2, 0x68CD, 0xB4D3, 0x690D, 0xB4D4, 0x6912, 0xB4D5, 0x690E, 0xB4D6, 0x68C9, 0xB4D7, 0x68DA, 0xB4D8, 0x696E, 0xB4D9, 0x68FB, 0xB4DA, 0x6B3E, 0xB4DB, 0x6B3A, 0xB4DC, 0x6B3D, 0xB4DD, 0x6B98, 0xB4DE, 0x6B96, 0xB4DF, 0x6BBC, 0xB4E0, 0x6BEF, 0xB4E1, 0x6C2E, 0xB4E2, 0x6C2F, 0xB4E3, 0x6C2C, 0xB4E4, 0x6E2F, 0xB4E5, 0x6E38, 0xB4E6, 0x6E54, 0xB4E7, 0x6E21, 0xB4E8, 0x6E32, 0xB4E9, 0x6E67, 0xB4EA, 0x6E4A, 0xB4EB, 0x6E20, 0xB4EC, 0x6E25, 0xB4ED, 0x6E23, 0xB4EE, 0x6E1B, 0xB4EF, 0x6E5B, 0xB4F0, 0x6E58, 0xB4F1, 0x6E24, 0xB4F2, 0x6E56, 0xB4F3, 0x6E6E, 0xB4F4, 0x6E2D, 0xB4F5, 0x6E26, 0xB4F6, 0x6E6F, 0xB4F7, 0x6E34, 0xB4F8, 0x6E4D, 0xB4F9, 0x6E3A, 0xB4FA, 0x6E2C, 0xB4FB, 0x6E43, 0xB4FC, 0x6E1D, 0xB4FD, 0x6E3E, 0xB4FE, 0x6ECB, 0xB540, 0x6E89, 0xB541, 0x6E19, 0xB542, 0x6E4E, 0xB543, 0x6E63, 0xB544, 0x6E44, 0xB545, 0x6E72, 0xB546, 0x6E69, 0xB547, 0x6E5F, 0xB548, 0x7119, 0xB549, 0x711A, 0xB54A, 0x7126, 0xB54B, 0x7130, 0xB54C, 0x7121, 0xB54D, 0x7136, 0xB54E, 0x716E, 0xB54F, 0x711C, 0xB550, 0x724C, 0xB551, 0x7284, 0xB552, 0x7280, 0xB553, 0x7336, 0xB554, 0x7325, 0xB555, 0x7334, 0xB556, 0x7329, 0xB557, 0x743A, 0xB558, 0x742A, 0xB559, 0x7433, 0xB55A, 0x7422, 0xB55B, 0x7425, 0xB55C, 0x7435, 0xB55D, 0x7436, 0xB55E, 0x7434, 0xB55F, 0x742F, 0xB560, 0x741B, 0xB561, 0x7426, 0xB562, 0x7428, 0xB563, 0x7525, 0xB564, 0x7526, 0xB565, 0x756B, 0xB566, 0x756A, 0xB567, 0x75E2, 0xB568, 0x75DB, 0xB569, 0x75E3, 0xB56A, 0x75D9, 0xB56B, 0x75D8, 0xB56C, 0x75DE, 0xB56D, 0x75E0, 0xB56E, 0x767B, 0xB56F, 0x767C, 0xB570, 0x7696, 0xB571, 0x7693, 0xB572, 0x76B4, 0xB573, 0x76DC, 0xB574, 0x774F, 0xB575, 0x77ED, 0xB576, 0x785D, 0xB577, 0x786C, 0xB578, 0x786F, 0xB579, 0x7A0D, 0xB57A, 0x7A08, 0xB57B, 0x7A0B, 0xB57C, 0x7A05, 0xB57D, 0x7A00, 0xB57E, 0x7A98, 0xB5A1, 0x7A97, 0xB5A2, 0x7A96, 0xB5A3, 0x7AE5, 0xB5A4, 0x7AE3, 0xB5A5, 0x7B49, 0xB5A6, 0x7B56, 0xB5A7, 0x7B46, 0xB5A8, 0x7B50, 0xB5A9, 0x7B52, 0xB5AA, 0x7B54, 0xB5AB, 0x7B4D, 0xB5AC, 0x7B4B, 0xB5AD, 0x7B4F, 0xB5AE, 0x7B51, 0xB5AF, 0x7C9F, 0xB5B0, 0x7CA5, 0xB5B1, 0x7D5E, 0xB5B2, 0x7D50, 0xB5B3, 0x7D68, 0xB5B4, 0x7D55, 0xB5B5, 0x7D2B, 0xB5B6, 0x7D6E, 0xB5B7, 0x7D72, 0xB5B8, 0x7D61, 0xB5B9, 0x7D66, 0xB5BA, 0x7D62, 0xB5BB, 0x7D70, 0xB5BC, 0x7D73, 0xB5BD, 0x5584, 0xB5BE, 0x7FD4, 0xB5BF, 0x7FD5, 0xB5C0, 0x800B, 0xB5C1, 0x8052, 0xB5C2, 0x8085, 0xB5C3, 0x8155, 0xB5C4, 0x8154, 0xB5C5, 0x814B, 0xB5C6, 0x8151, 0xB5C7, 0x814E, 0xB5C8, 0x8139, 0xB5C9, 0x8146, 0xB5CA, 0x813E, 0xB5CB, 0x814C, 0xB5CC, 0x8153, 0xB5CD, 0x8174, 0xB5CE, 0x8212, 0xB5CF, 0x821C, 0xB5D0, 0x83E9, 0xB5D1, 0x8403, 0xB5D2, 0x83F8, 0xB5D3, 0x840D, 0xB5D4, 0x83E0, 0xB5D5, 0x83C5, 0xB5D6, 0x840B, 0xB5D7, 0x83C1, 0xB5D8, 0x83EF, 0xB5D9, 0x83F1, 0xB5DA, 0x83F4, 0xB5DB, 0x8457, 0xB5DC, 0x840A, 0xB5DD, 0x83F0, 0xB5DE, 0x840C, 0xB5DF, 0x83CC, 0xB5E0, 0x83FD, 0xB5E1, 0x83F2, 0xB5E2, 0x83CA, 0xB5E3, 0x8438, 0xB5E4, 0x840E, 0xB5E5, 0x8404, 0xB5E6, 0x83DC, 0xB5E7, 0x8407, 0xB5E8, 0x83D4, 0xB5E9, 0x83DF, 0xB5EA, 0x865B, 0xB5EB, 0x86DF, 0xB5EC, 0x86D9, 0xB5ED, 0x86ED, 0xB5EE, 0x86D4, 0xB5EF, 0x86DB, 0xB5F0, 0x86E4, 0xB5F1, 0x86D0, 0xB5F2, 0x86DE, 0xB5F3, 0x8857, 0xB5F4, 0x88C1, 0xB5F5, 0x88C2, 0xB5F6, 0x88B1, 0xB5F7, 0x8983, 0xB5F8, 0x8996, 0xB5F9, 0x8A3B, 0xB5FA, 0x8A60, 0xB5FB, 0x8A55, 0xB5FC, 0x8A5E, 0xB5FD, 0x8A3C, 0xB5FE, 0x8A41, 0xB640, 0x8A54, 0xB641, 0x8A5B, 0xB642, 0x8A50, 0xB643, 0x8A46, 0xB644, 0x8A34, 0xB645, 0x8A3A, 0xB646, 0x8A36, 0xB647, 0x8A56, 0xB648, 0x8C61, 0xB649, 0x8C82, 0xB64A, 0x8CAF, 0xB64B, 0x8CBC, 0xB64C, 0x8CB3, 0xB64D, 0x8CBD, 0xB64E, 0x8CC1, 0xB64F, 0x8CBB, 0xB650, 0x8CC0, 0xB651, 0x8CB4, 0xB652, 0x8CB7, 0xB653, 0x8CB6, 0xB654, 0x8CBF, 0xB655, 0x8CB8, 0xB656, 0x8D8A, 0xB657, 0x8D85, 0xB658, 0x8D81, 0xB659, 0x8DCE, 0xB65A, 0x8DDD, 0xB65B, 0x8DCB, 0xB65C, 0x8DDA, 0xB65D, 0x8DD1, 0xB65E, 0x8DCC, 0xB65F, 0x8DDB, 0xB660, 0x8DC6, 0xB661, 0x8EFB, 0xB662, 0x8EF8, 0xB663, 0x8EFC, 0xB664, 0x8F9C, 0xB665, 0x902E, 0xB666, 0x9035, 0xB667, 0x9031, 0xB668, 0x9038, 0xB669, 0x9032, 0xB66A, 0x9036, 0xB66B, 0x9102, 0xB66C, 0x90F5, 0xB66D, 0x9109, 0xB66E, 0x90FE, 0xB66F, 0x9163, 0xB670, 0x9165, 0xB671, 0x91CF, 0xB672, 0x9214, 0xB673, 0x9215, 0xB674, 0x9223, 0xB675, 0x9209, 0xB676, 0x921E, 0xB677, 0x920D, 0xB678, 0x9210, 0xB679, 0x9207, 0xB67A, 0x9211, 0xB67B, 0x9594, 0xB67C, 0x958F, 0xB67D, 0x958B, 0xB67E, 0x9591, 0xB6A1, 0x9593, 0xB6A2, 0x9592, 0xB6A3, 0x958E, 0xB6A4, 0x968A, 0xB6A5, 0x968E, 0xB6A6, 0x968B, 0xB6A7, 0x967D, 0xB6A8, 0x9685, 0xB6A9, 0x9686, 0xB6AA, 0x968D, 0xB6AB, 0x9672, 0xB6AC, 0x9684, 0xB6AD, 0x96C1, 0xB6AE, 0x96C5, 0xB6AF, 0x96C4, 0xB6B0, 0x96C6, 0xB6B1, 0x96C7, 0xB6B2, 0x96EF, 0xB6B3, 0x96F2, 0xB6B4, 0x97CC, 0xB6B5, 0x9805, 0xB6B6, 0x9806, 0xB6B7, 0x9808, 0xB6B8, 0x98E7, 0xB6B9, 0x98EA, 0xB6BA, 0x98EF, 0xB6BB, 0x98E9, 0xB6BC, 0x98F2, 0xB6BD, 0x98ED, 0xB6BE, 0x99AE, 0xB6BF, 0x99AD, 0xB6C0, 0x9EC3, 0xB6C1, 0x9ECD, 0xB6C2, 0x9ED1, 0xB6C3, 0x4E82, 0xB6C4, 0x50AD, 0xB6C5, 0x50B5, 0xB6C6, 0x50B2, 0xB6C7, 0x50B3, 0xB6C8, 0x50C5, 0xB6C9, 0x50BE, 0xB6CA, 0x50AC, 0xB6CB, 0x50B7, 0xB6CC, 0x50BB, 0xB6CD, 0x50AF, 0xB6CE, 0x50C7, 0xB6CF, 0x527F, 0xB6D0, 0x5277, 0xB6D1, 0x527D, 0xB6D2, 0x52DF, 0xB6D3, 0x52E6, 0xB6D4, 0x52E4, 0xB6D5, 0x52E2, 0xB6D6, 0x52E3, 0xB6D7, 0x532F, 0xB6D8, 0x55DF, 0xB6D9, 0x55E8, 0xB6DA, 0x55D3, 0xB6DB, 0x55E6, 0xB6DC, 0x55CE, 0xB6DD, 0x55DC, 0xB6DE, 0x55C7, 0xB6DF, 0x55D1, 0xB6E0, 0x55E3, 0xB6E1, 0x55E4, 0xB6E2, 0x55EF, 0xB6E3, 0x55DA, 0xB6E4, 0x55E1, 0xB6E5, 0x55C5, 0xB6E6, 0x55C6, 0xB6E7, 0x55E5, 0xB6E8, 0x55C9, 0xB6E9, 0x5712, 0xB6EA, 0x5713, 0xB6EB, 0x585E, 0xB6EC, 0x5851, 0xB6ED, 0x5858, 0xB6EE, 0x5857, 0xB6EF, 0x585A, 0xB6F0, 0x5854, 0xB6F1, 0x586B, 0xB6F2, 0x584C, 0xB6F3, 0x586D, 0xB6F4, 0x584A, 0xB6F5, 0x5862, 0xB6F6, 0x5852, 0xB6F7, 0x584B, 0xB6F8, 0x5967, 0xB6F9, 0x5AC1, 0xB6FA, 0x5AC9, 0xB6FB, 0x5ACC, 0xB6FC, 0x5ABE, 0xB6FD, 0x5ABD, 0xB6FE, 0x5ABC, 0xB740, 0x5AB3, 0xB741, 0x5AC2, 0xB742, 0x5AB2, 0xB743, 0x5D69, 0xB744, 0x5D6F, 0xB745, 0x5E4C, 0xB746, 0x5E79, 0xB747, 0x5EC9, 0xB748, 0x5EC8, 0xB749, 0x5F12, 0xB74A, 0x5F59, 0xB74B, 0x5FAC, 0xB74C, 0x5FAE, 0xB74D, 0x611A, 0xB74E, 0x610F, 0xB74F, 0x6148, 0xB750, 0x611F, 0xB751, 0x60F3, 0xB752, 0x611B, 0xB753, 0x60F9, 0xB754, 0x6101, 0xB755, 0x6108, 0xB756, 0x614E, 0xB757, 0x614C, 0xB758, 0x6144, 0xB759, 0x614D, 0xB75A, 0x613E, 0xB75B, 0x6134, 0xB75C, 0x6127, 0xB75D, 0x610D, 0xB75E, 0x6106, 0xB75F, 0x6137, 0xB760, 0x6221, 0xB761, 0x6222, 0xB762, 0x6413, 0xB763, 0x643E, 0xB764, 0x641E, 0xB765, 0x642A, 0xB766, 0x642D, 0xB767, 0x643D, 0xB768, 0x642C, 0xB769, 0x640F, 0xB76A, 0x641C, 0xB76B, 0x6414, 0xB76C, 0x640D, 0xB76D, 0x6436, 0xB76E, 0x6416, 0xB76F, 0x6417, 0xB770, 0x6406, 0xB771, 0x656C, 0xB772, 0x659F, 0xB773, 0x65B0, 0xB774, 0x6697, 0xB775, 0x6689, 0xB776, 0x6687, 0xB777, 0x6688, 0xB778, 0x6696, 0xB779, 0x6684, 0xB77A, 0x6698, 0xB77B, 0x668D, 0xB77C, 0x6703, 0xB77D, 0x6994, 0xB77E, 0x696D, 0xB7A1, 0x695A, 0xB7A2, 0x6977, 0xB7A3, 0x6960, 0xB7A4, 0x6954, 0xB7A5, 0x6975, 0xB7A6, 0x6930, 0xB7A7, 0x6982, 0xB7A8, 0x694A, 0xB7A9, 0x6968, 0xB7AA, 0x696B, 0xB7AB, 0x695E, 0xB7AC, 0x6953, 0xB7AD, 0x6979, 0xB7AE, 0x6986, 0xB7AF, 0x695D, 0xB7B0, 0x6963, 0xB7B1, 0x695B, 0xB7B2, 0x6B47, 0xB7B3, 0x6B72, 0xB7B4, 0x6BC0, 0xB7B5, 0x6BBF, 0xB7B6, 0x6BD3, 0xB7B7, 0x6BFD, 0xB7B8, 0x6EA2, 0xB7B9, 0x6EAF, 0xB7BA, 0x6ED3, 0xB7BB, 0x6EB6, 0xB7BC, 0x6EC2, 0xB7BD, 0x6E90, 0xB7BE, 0x6E9D, 0xB7BF, 0x6EC7, 0xB7C0, 0x6EC5, 0xB7C1, 0x6EA5, 0xB7C2, 0x6E98, 0xB7C3, 0x6EBC, 0xB7C4, 0x6EBA, 0xB7C5, 0x6EAB, 0xB7C6, 0x6ED1, 0xB7C7, 0x6E96, 0xB7C8, 0x6E9C, 0xB7C9, 0x6EC4, 0xB7CA, 0x6ED4, 0xB7CB, 0x6EAA, 0xB7CC, 0x6EA7, 0xB7CD, 0x6EB4, 0xB7CE, 0x714E, 0xB7CF, 0x7159, 0xB7D0, 0x7169, 0xB7D1, 0x7164, 0xB7D2, 0x7149, 0xB7D3, 0x7167, 0xB7D4, 0x715C, 0xB7D5, 0x716C, 0xB7D6, 0x7166, 0xB7D7, 0x714C, 0xB7D8, 0x7165, 0xB7D9, 0x715E, 0xB7DA, 0x7146, 0xB7DB, 0x7168, 0xB7DC, 0x7156, 0xB7DD, 0x723A, 0xB7DE, 0x7252, 0xB7DF, 0x7337, 0xB7E0, 0x7345, 0xB7E1, 0x733F, 0xB7E2, 0x733E, 0xB7E3, 0x746F, 0xB7E4, 0x745A, 0xB7E5, 0x7455, 0xB7E6, 0x745F, 0xB7E7, 0x745E, 0xB7E8, 0x7441, 0xB7E9, 0x743F, 0xB7EA, 0x7459, 0xB7EB, 0x745B, 0xB7EC, 0x745C, 0xB7ED, 0x7576, 0xB7EE, 0x7578, 0xB7EF, 0x7600, 0xB7F0, 0x75F0, 0xB7F1, 0x7601, 0xB7F2, 0x75F2, 0xB7F3, 0x75F1, 0xB7F4, 0x75FA, 0xB7F5, 0x75FF, 0xB7F6, 0x75F4, 0xB7F7, 0x75F3, 0xB7F8, 0x76DE, 0xB7F9, 0x76DF, 0xB7FA, 0x775B, 0xB7FB, 0x776B, 0xB7FC, 0x7766, 0xB7FD, 0x775E, 0xB7FE, 0x7763, 0xB840, 0x7779, 0xB841, 0x776A, 0xB842, 0x776C, 0xB843, 0x775C, 0xB844, 0x7765, 0xB845, 0x7768, 0xB846, 0x7762, 0xB847, 0x77EE, 0xB848, 0x788E, 0xB849, 0x78B0, 0xB84A, 0x7897, 0xB84B, 0x7898, 0xB84C, 0x788C, 0xB84D, 0x7889, 0xB84E, 0x787C, 0xB84F, 0x7891, 0xB850, 0x7893, 0xB851, 0x787F, 0xB852, 0x797A, 0xB853, 0x797F, 0xB854, 0x7981, 0xB855, 0x842C, 0xB856, 0x79BD, 0xB857, 0x7A1C, 0xB858, 0x7A1A, 0xB859, 0x7A20, 0xB85A, 0x7A14, 0xB85B, 0x7A1F, 0xB85C, 0x7A1E, 0xB85D, 0x7A9F, 0xB85E, 0x7AA0, 0xB85F, 0x7B77, 0xB860, 0x7BC0, 0xB861, 0x7B60, 0xB862, 0x7B6E, 0xB863, 0x7B67, 0xB864, 0x7CB1, 0xB865, 0x7CB3, 0xB866, 0x7CB5, 0xB867, 0x7D93, 0xB868, 0x7D79, 0xB869, 0x7D91, 0xB86A, 0x7D81, 0xB86B, 0x7D8F, 0xB86C, 0x7D5B, 0xB86D, 0x7F6E, 0xB86E, 0x7F69, 0xB86F, 0x7F6A, 0xB870, 0x7F72, 0xB871, 0x7FA9, 0xB872, 0x7FA8, 0xB873, 0x7FA4, 0xB874, 0x8056, 0xB875, 0x8058, 0xB876, 0x8086, 0xB877, 0x8084, 0xB878, 0x8171, 0xB879, 0x8170, 0xB87A, 0x8178, 0xB87B, 0x8165, 0xB87C, 0x816E, 0xB87D, 0x8173, 0xB87E, 0x816B, 0xB8A1, 0x8179, 0xB8A2, 0x817A, 0xB8A3, 0x8166, 0xB8A4, 0x8205, 0xB8A5, 0x8247, 0xB8A6, 0x8482, 0xB8A7, 0x8477, 0xB8A8, 0x843D, 0xB8A9, 0x8431, 0xB8AA, 0x8475, 0xB8AB, 0x8466, 0xB8AC, 0x846B, 0xB8AD, 0x8449, 0xB8AE, 0x846C, 0xB8AF, 0x845B, 0xB8B0, 0x843C, 0xB8B1, 0x8435, 0xB8B2, 0x8461, 0xB8B3, 0x8463, 0xB8B4, 0x8469, 0xB8B5, 0x846D, 0xB8B6, 0x8446, 0xB8B7, 0x865E, 0xB8B8, 0x865C, 0xB8B9, 0x865F, 0xB8BA, 0x86F9, 0xB8BB, 0x8713, 0xB8BC, 0x8708, 0xB8BD, 0x8707, 0xB8BE, 0x8700, 0xB8BF, 0x86FE, 0xB8C0, 0x86FB, 0xB8C1, 0x8702, 0xB8C2, 0x8703, 0xB8C3, 0x8706, 0xB8C4, 0x870A, 0xB8C5, 0x8859, 0xB8C6, 0x88DF, 0xB8C7, 0x88D4, 0xB8C8, 0x88D9, 0xB8C9, 0x88DC, 0xB8CA, 0x88D8, 0xB8CB, 0x88DD, 0xB8CC, 0x88E1, 0xB8CD, 0x88CA, 0xB8CE, 0x88D5, 0xB8CF, 0x88D2, 0xB8D0, 0x899C, 0xB8D1, 0x89E3, 0xB8D2, 0x8A6B, 0xB8D3, 0x8A72, 0xB8D4, 0x8A73, 0xB8D5, 0x8A66, 0xB8D6, 0x8A69, 0xB8D7, 0x8A70, 0xB8D8, 0x8A87, 0xB8D9, 0x8A7C, 0xB8DA, 0x8A63, 0xB8DB, 0x8AA0, 0xB8DC, 0x8A71, 0xB8DD, 0x8A85, 0xB8DE, 0x8A6D, 0xB8DF, 0x8A62, 0xB8E0, 0x8A6E, 0xB8E1, 0x8A6C, 0xB8E2, 0x8A79, 0xB8E3, 0x8A7B, 0xB8E4, 0x8A3E, 0xB8E5, 0x8A68, 0xB8E6, 0x8C62, 0xB8E7, 0x8C8A, 0xB8E8, 0x8C89, 0xB8E9, 0x8CCA, 0xB8EA, 0x8CC7, 0xB8EB, 0x8CC8, 0xB8EC, 0x8CC4, 0xB8ED, 0x8CB2, 0xB8EE, 0x8CC3, 0xB8EF, 0x8CC2, 0xB8F0, 0x8CC5, 0xB8F1, 0x8DE1, 0xB8F2, 0x8DDF, 0xB8F3, 0x8DE8, 0xB8F4, 0x8DEF, 0xB8F5, 0x8DF3, 0xB8F6, 0x8DFA, 0xB8F7, 0x8DEA, 0xB8F8, 0x8DE4, 0xB8F9, 0x8DE6, 0xB8FA, 0x8EB2, 0xB8FB, 0x8F03, 0xB8FC, 0x8F09, 0xB8FD, 0x8EFE, 0xB8FE, 0x8F0A, 0xB940, 0x8F9F, 0xB941, 0x8FB2, 0xB942, 0x904B, 0xB943, 0x904A, 0xB944, 0x9053, 0xB945, 0x9042, 0xB946, 0x9054, 0xB947, 0x903C, 0xB948, 0x9055, 0xB949, 0x9050, 0xB94A, 0x9047, 0xB94B, 0x904F, 0xB94C, 0x904E, 0xB94D, 0x904D, 0xB94E, 0x9051, 0xB94F, 0x903E, 0xB950, 0x9041, 0xB951, 0x9112, 0xB952, 0x9117, 0xB953, 0x916C, 0xB954, 0x916A, 0xB955, 0x9169, 0xB956, 0x91C9, 0xB957, 0x9237, 0xB958, 0x9257, 0xB959, 0x9238, 0xB95A, 0x923D, 0xB95B, 0x9240, 0xB95C, 0x923E, 0xB95D, 0x925B, 0xB95E, 0x924B, 0xB95F, 0x9264, 0xB960, 0x9251, 0xB961, 0x9234, 0xB962, 0x9249, 0xB963, 0x924D, 0xB964, 0x9245, 0xB965, 0x9239, 0xB966, 0x923F, 0xB967, 0x925A, 0xB968, 0x9598, 0xB969, 0x9698, 0xB96A, 0x9694, 0xB96B, 0x9695, 0xB96C, 0x96CD, 0xB96D, 0x96CB, 0xB96E, 0x96C9, 0xB96F, 0x96CA, 0xB970, 0x96F7, 0xB971, 0x96FB, 0xB972, 0x96F9, 0xB973, 0x96F6, 0xB974, 0x9756, 0xB975, 0x9774, 0xB976, 0x9776, 0xB977, 0x9810, 0xB978, 0x9811, 0xB979, 0x9813, 0xB97A, 0x980A, 0xB97B, 0x9812, 0xB97C, 0x980C, 0xB97D, 0x98FC, 0xB97E, 0x98F4, 0xB9A1, 0x98FD, 0xB9A2, 0x98FE, 0xB9A3, 0x99B3, 0xB9A4, 0x99B1, 0xB9A5, 0x99B4, 0xB9A6, 0x9AE1, 0xB9A7, 0x9CE9, 0xB9A8, 0x9E82, 0xB9A9, 0x9F0E, 0xB9AA, 0x9F13, 0xB9AB, 0x9F20, 0xB9AC, 0x50E7, 0xB9AD, 0x50EE, 0xB9AE, 0x50E5, 0xB9AF, 0x50D6, 0xB9B0, 0x50ED, 0xB9B1, 0x50DA, 0xB9B2, 0x50D5, 0xB9B3, 0x50CF, 0xB9B4, 0x50D1, 0xB9B5, 0x50F1, 0xB9B6, 0x50CE, 0xB9B7, 0x50E9, 0xB9B8, 0x5162, 0xB9B9, 0x51F3, 0xB9BA, 0x5283, 0xB9BB, 0x5282, 0xB9BC, 0x5331, 0xB9BD, 0x53AD, 0xB9BE, 0x55FE, 0xB9BF, 0x5600, 0xB9C0, 0x561B, 0xB9C1, 0x5617, 0xB9C2, 0x55FD, 0xB9C3, 0x5614, 0xB9C4, 0x5606, 0xB9C5, 0x5609, 0xB9C6, 0x560D, 0xB9C7, 0x560E, 0xB9C8, 0x55F7, 0xB9C9, 0x5616, 0xB9CA, 0x561F, 0xB9CB, 0x5608, 0xB9CC, 0x5610, 0xB9CD, 0x55F6, 0xB9CE, 0x5718, 0xB9CF, 0x5716, 0xB9D0, 0x5875, 0xB9D1, 0x587E, 0xB9D2, 0x5883, 0xB9D3, 0x5893, 0xB9D4, 0x588A, 0xB9D5, 0x5879, 0xB9D6, 0x5885, 0xB9D7, 0x587D, 0xB9D8, 0x58FD, 0xB9D9, 0x5925, 0xB9DA, 0x5922, 0xB9DB, 0x5924, 0xB9DC, 0x596A, 0xB9DD, 0x5969, 0xB9DE, 0x5AE1, 0xB9DF, 0x5AE6, 0xB9E0, 0x5AE9, 0xB9E1, 0x5AD7, 0xB9E2, 0x5AD6, 0xB9E3, 0x5AD8, 0xB9E4, 0x5AE3, 0xB9E5, 0x5B75, 0xB9E6, 0x5BDE, 0xB9E7, 0x5BE7, 0xB9E8, 0x5BE1, 0xB9E9, 0x5BE5, 0xB9EA, 0x5BE6, 0xB9EB, 0x5BE8, 0xB9EC, 0x5BE2, 0xB9ED, 0x5BE4, 0xB9EE, 0x5BDF, 0xB9EF, 0x5C0D, 0xB9F0, 0x5C62, 0xB9F1, 0x5D84, 0xB9F2, 0x5D87, 0xB9F3, 0x5E5B, 0xB9F4, 0x5E63, 0xB9F5, 0x5E55, 0xB9F6, 0x5E57, 0xB9F7, 0x5E54, 0xB9F8, 0x5ED3, 0xB9F9, 0x5ED6, 0xB9FA, 0x5F0A, 0xB9FB, 0x5F46, 0xB9FC, 0x5F70, 0xB9FD, 0x5FB9, 0xB9FE, 0x6147, 0xBA40, 0x613F, 0xBA41, 0x614B, 0xBA42, 0x6177, 0xBA43, 0x6162, 0xBA44, 0x6163, 0xBA45, 0x615F, 0xBA46, 0x615A, 0xBA47, 0x6158, 0xBA48, 0x6175, 0xBA49, 0x622A, 0xBA4A, 0x6487, 0xBA4B, 0x6458, 0xBA4C, 0x6454, 0xBA4D, 0x64A4, 0xBA4E, 0x6478, 0xBA4F, 0x645F, 0xBA50, 0x647A, 0xBA51, 0x6451, 0xBA52, 0x6467, 0xBA53, 0x6434, 0xBA54, 0x646D, 0xBA55, 0x647B, 0xBA56, 0x6572, 0xBA57, 0x65A1, 0xBA58, 0x65D7, 0xBA59, 0x65D6, 0xBA5A, 0x66A2, 0xBA5B, 0x66A8, 0xBA5C, 0x669D, 0xBA5D, 0x699C, 0xBA5E, 0x69A8, 0xBA5F, 0x6995, 0xBA60, 0x69C1, 0xBA61, 0x69AE, 0xBA62, 0x69D3, 0xBA63, 0x69CB, 0xBA64, 0x699B, 0xBA65, 0x69B7, 0xBA66, 0x69BB, 0xBA67, 0x69AB, 0xBA68, 0x69B4, 0xBA69, 0x69D0, 0xBA6A, 0x69CD, 0xBA6B, 0x69AD, 0xBA6C, 0x69CC, 0xBA6D, 0x69A6, 0xBA6E, 0x69C3, 0xBA6F, 0x69A3, 0xBA70, 0x6B49, 0xBA71, 0x6B4C, 0xBA72, 0x6C33, 0xBA73, 0x6F33, 0xBA74, 0x6F14, 0xBA75, 0x6EFE, 0xBA76, 0x6F13, 0xBA77, 0x6EF4, 0xBA78, 0x6F29, 0xBA79, 0x6F3E, 0xBA7A, 0x6F20, 0xBA7B, 0x6F2C, 0xBA7C, 0x6F0F, 0xBA7D, 0x6F02, 0xBA7E, 0x6F22, 0xBAA1, 0x6EFF, 0xBAA2, 0x6EEF, 0xBAA3, 0x6F06, 0xBAA4, 0x6F31, 0xBAA5, 0x6F38, 0xBAA6, 0x6F32, 0xBAA7, 0x6F23, 0xBAA8, 0x6F15, 0xBAA9, 0x6F2B, 0xBAAA, 0x6F2F, 0xBAAB, 0x6F88, 0xBAAC, 0x6F2A, 0xBAAD, 0x6EEC, 0xBAAE, 0x6F01, 0xBAAF, 0x6EF2, 0xBAB0, 0x6ECC, 0xBAB1, 0x6EF7, 0xBAB2, 0x7194, 0xBAB3, 0x7199, 0xBAB4, 0x717D, 0xBAB5, 0x718A, 0xBAB6, 0x7184, 0xBAB7, 0x7192, 0xBAB8, 0x723E, 0xBAB9, 0x7292, 0xBABA, 0x7296, 0xBABB, 0x7344, 0xBABC, 0x7350, 0xBABD, 0x7464, 0xBABE, 0x7463, 0xBABF, 0x746A, 0xBAC0, 0x7470, 0xBAC1, 0x746D, 0xBAC2, 0x7504, 0xBAC3, 0x7591, 0xBAC4, 0x7627, 0xBAC5, 0x760D, 0xBAC6, 0x760B, 0xBAC7, 0x7609, 0xBAC8, 0x7613, 0xBAC9, 0x76E1, 0xBACA, 0x76E3, 0xBACB, 0x7784, 0xBACC, 0x777D, 0xBACD, 0x777F, 0xBACE, 0x7761, 0xBACF, 0x78C1, 0xBAD0, 0x789F, 0xBAD1, 0x78A7, 0xBAD2, 0x78B3, 0xBAD3, 0x78A9, 0xBAD4, 0x78A3, 0xBAD5, 0x798E, 0xBAD6, 0x798F, 0xBAD7, 0x798D, 0xBAD8, 0x7A2E, 0xBAD9, 0x7A31, 0xBADA, 0x7AAA, 0xBADB, 0x7AA9, 0xBADC, 0x7AED, 0xBADD, 0x7AEF, 0xBADE, 0x7BA1, 0xBADF, 0x7B95, 0xBAE0, 0x7B8B, 0xBAE1, 0x7B75, 0xBAE2, 0x7B97, 0xBAE3, 0x7B9D, 0xBAE4, 0x7B94, 0xBAE5, 0x7B8F, 0xBAE6, 0x7BB8, 0xBAE7, 0x7B87, 0xBAE8, 0x7B84, 0xBAE9, 0x7CB9, 0xBAEA, 0x7CBD, 0xBAEB, 0x7CBE, 0xBAEC, 0x7DBB, 0xBAED, 0x7DB0, 0xBAEE, 0x7D9C, 0xBAEF, 0x7DBD, 0xBAF0, 0x7DBE, 0xBAF1, 0x7DA0, 0xBAF2, 0x7DCA, 0xBAF3, 0x7DB4, 0xBAF4, 0x7DB2, 0xBAF5, 0x7DB1, 0xBAF6, 0x7DBA, 0xBAF7, 0x7DA2, 0xBAF8, 0x7DBF, 0xBAF9, 0x7DB5, 0xBAFA, 0x7DB8, 0xBAFB, 0x7DAD, 0xBAFC, 0x7DD2, 0xBAFD, 0x7DC7, 0xBAFE, 0x7DAC, 0xBB40, 0x7F70, 0xBB41, 0x7FE0, 0xBB42, 0x7FE1, 0xBB43, 0x7FDF, 0xBB44, 0x805E, 0xBB45, 0x805A, 0xBB46, 0x8087, 0xBB47, 0x8150, 0xBB48, 0x8180, 0xBB49, 0x818F, 0xBB4A, 0x8188, 0xBB4B, 0x818A, 0xBB4C, 0x817F, 0xBB4D, 0x8182, 0xBB4E, 0x81E7, 0xBB4F, 0x81FA, 0xBB50, 0x8207, 0xBB51, 0x8214, 0xBB52, 0x821E, 0xBB53, 0x824B, 0xBB54, 0x84C9, 0xBB55, 0x84BF, 0xBB56, 0x84C6, 0xBB57, 0x84C4, 0xBB58, 0x8499, 0xBB59, 0x849E, 0xBB5A, 0x84B2, 0xBB5B, 0x849C, 0xBB5C, 0x84CB, 0xBB5D, 0x84B8, 0xBB5E, 0x84C0, 0xBB5F, 0x84D3, 0xBB60, 0x8490, 0xBB61, 0x84BC, 0xBB62, 0x84D1, 0xBB63, 0x84CA, 0xBB64, 0x873F, 0xBB65, 0x871C, 0xBB66, 0x873B, 0xBB67, 0x8722, 0xBB68, 0x8725, 0xBB69, 0x8734, 0xBB6A, 0x8718, 0xBB6B, 0x8755, 0xBB6C, 0x8737, 0xBB6D, 0x8729, 0xBB6E, 0x88F3, 0xBB6F, 0x8902, 0xBB70, 0x88F4, 0xBB71, 0x88F9, 0xBB72, 0x88F8, 0xBB73, 0x88FD, 0xBB74, 0x88E8, 0xBB75, 0x891A, 0xBB76, 0x88EF, 0xBB77, 0x8AA6, 0xBB78, 0x8A8C, 0xBB79, 0x8A9E, 0xBB7A, 0x8AA3, 0xBB7B, 0x8A8D, 0xBB7C, 0x8AA1, 0xBB7D, 0x8A93, 0xBB7E, 0x8AA4, 0xBBA1, 0x8AAA, 0xBBA2, 0x8AA5, 0xBBA3, 0x8AA8, 0xBBA4, 0x8A98, 0xBBA5, 0x8A91, 0xBBA6, 0x8A9A, 0xBBA7, 0x8AA7, 0xBBA8, 0x8C6A, 0xBBA9, 0x8C8D, 0xBBAA, 0x8C8C, 0xBBAB, 0x8CD3, 0xBBAC, 0x8CD1, 0xBBAD, 0x8CD2, 0xBBAE, 0x8D6B, 0xBBAF, 0x8D99, 0xBBB0, 0x8D95, 0xBBB1, 0x8DFC, 0xBBB2, 0x8F14, 0xBBB3, 0x8F12, 0xBBB4, 0x8F15, 0xBBB5, 0x8F13, 0xBBB6, 0x8FA3, 0xBBB7, 0x9060, 0xBBB8, 0x9058, 0xBBB9, 0x905C, 0xBBBA, 0x9063, 0xBBBB, 0x9059, 0xBBBC, 0x905E, 0xBBBD, 0x9062, 0xBBBE, 0x905D, 0xBBBF, 0x905B, 0xBBC0, 0x9119, 0xBBC1, 0x9118, 0xBBC2, 0x911E, 0xBBC3, 0x9175, 0xBBC4, 0x9178, 0xBBC5, 0x9177, 0xBBC6, 0x9174, 0xBBC7, 0x9278, 0xBBC8, 0x9280, 0xBBC9, 0x9285, 0xBBCA, 0x9298, 0xBBCB, 0x9296, 0xBBCC, 0x927B, 0xBBCD, 0x9293, 0xBBCE, 0x929C, 0xBBCF, 0x92A8, 0xBBD0, 0x927C, 0xBBD1, 0x9291, 0xBBD2, 0x95A1, 0xBBD3, 0x95A8, 0xBBD4, 0x95A9, 0xBBD5, 0x95A3, 0xBBD6, 0x95A5, 0xBBD7, 0x95A4, 0xBBD8, 0x9699, 0xBBD9, 0x969C, 0xBBDA, 0x969B, 0xBBDB, 0x96CC, 0xBBDC, 0x96D2, 0xBBDD, 0x9700, 0xBBDE, 0x977C, 0xBBDF, 0x9785, 0xBBE0, 0x97F6, 0xBBE1, 0x9817, 0xBBE2, 0x9818, 0xBBE3, 0x98AF, 0xBBE4, 0x98B1, 0xBBE5, 0x9903, 0xBBE6, 0x9905, 0xBBE7, 0x990C, 0xBBE8, 0x9909, 0xBBE9, 0x99C1, 0xBBEA, 0x9AAF, 0xBBEB, 0x9AB0, 0xBBEC, 0x9AE6, 0xBBED, 0x9B41, 0xBBEE, 0x9B42, 0xBBEF, 0x9CF4, 0xBBF0, 0x9CF6, 0xBBF1, 0x9CF3, 0xBBF2, 0x9EBC, 0xBBF3, 0x9F3B, 0xBBF4, 0x9F4A, 0xBBF5, 0x5104, 0xBBF6, 0x5100, 0xBBF7, 0x50FB, 0xBBF8, 0x50F5, 0xBBF9, 0x50F9, 0xBBFA, 0x5102, 0xBBFB, 0x5108, 0xBBFC, 0x5109, 0xBBFD, 0x5105, 0xBBFE, 0x51DC, 0xBC40, 0x5287, 0xBC41, 0x5288, 0xBC42, 0x5289, 0xBC43, 0x528D, 0xBC44, 0x528A, 0xBC45, 0x52F0, 0xBC46, 0x53B2, 0xBC47, 0x562E, 0xBC48, 0x563B, 0xBC49, 0x5639, 0xBC4A, 0x5632, 0xBC4B, 0x563F, 0xBC4C, 0x5634, 0xBC4D, 0x5629, 0xBC4E, 0x5653, 0xBC4F, 0x564E, 0xBC50, 0x5657, 0xBC51, 0x5674, 0xBC52, 0x5636, 0xBC53, 0x562F, 0xBC54, 0x5630, 0xBC55, 0x5880, 0xBC56, 0x589F, 0xBC57, 0x589E, 0xBC58, 0x58B3, 0xBC59, 0x589C, 0xBC5A, 0x58AE, 0xBC5B, 0x58A9, 0xBC5C, 0x58A6, 0xBC5D, 0x596D, 0xBC5E, 0x5B09, 0xBC5F, 0x5AFB, 0xBC60, 0x5B0B, 0xBC61, 0x5AF5, 0xBC62, 0x5B0C, 0xBC63, 0x5B08, 0xBC64, 0x5BEE, 0xBC65, 0x5BEC, 0xBC66, 0x5BE9, 0xBC67, 0x5BEB, 0xBC68, 0x5C64, 0xBC69, 0x5C65, 0xBC6A, 0x5D9D, 0xBC6B, 0x5D94, 0xBC6C, 0x5E62, 0xBC6D, 0x5E5F, 0xBC6E, 0x5E61, 0xBC6F, 0x5EE2, 0xBC70, 0x5EDA, 0xBC71, 0x5EDF, 0xBC72, 0x5EDD, 0xBC73, 0x5EE3, 0xBC74, 0x5EE0, 0xBC75, 0x5F48, 0xBC76, 0x5F71, 0xBC77, 0x5FB7, 0xBC78, 0x5FB5, 0xBC79, 0x6176, 0xBC7A, 0x6167, 0xBC7B, 0x616E, 0xBC7C, 0x615D, 0xBC7D, 0x6155, 0xBC7E, 0x6182, 0xBCA1, 0x617C, 0xBCA2, 0x6170, 0xBCA3, 0x616B, 0xBCA4, 0x617E, 0xBCA5, 0x61A7, 0xBCA6, 0x6190, 0xBCA7, 0x61AB, 0xBCA8, 0x618E, 0xBCA9, 0x61AC, 0xBCAA, 0x619A, 0xBCAB, 0x61A4, 0xBCAC, 0x6194, 0xBCAD, 0x61AE, 0xBCAE, 0x622E, 0xBCAF, 0x6469, 0xBCB0, 0x646F, 0xBCB1, 0x6479, 0xBCB2, 0x649E, 0xBCB3, 0x64B2, 0xBCB4, 0x6488, 0xBCB5, 0x6490, 0xBCB6, 0x64B0, 0xBCB7, 0x64A5, 0xBCB8, 0x6493, 0xBCB9, 0x6495, 0xBCBA, 0x64A9, 0xBCBB, 0x6492, 0xBCBC, 0x64AE, 0xBCBD, 0x64AD, 0xBCBE, 0x64AB, 0xBCBF, 0x649A, 0xBCC0, 0x64AC, 0xBCC1, 0x6499, 0xBCC2, 0x64A2, 0xBCC3, 0x64B3, 0xBCC4, 0x6575, 0xBCC5, 0x6577, 0xBCC6, 0x6578, 0xBCC7, 0x66AE, 0xBCC8, 0x66AB, 0xBCC9, 0x66B4, 0xBCCA, 0x66B1, 0xBCCB, 0x6A23, 0xBCCC, 0x6A1F, 0xBCCD, 0x69E8, 0xBCCE, 0x6A01, 0xBCCF, 0x6A1E, 0xBCD0, 0x6A19, 0xBCD1, 0x69FD, 0xBCD2, 0x6A21, 0xBCD3, 0x6A13, 0xBCD4, 0x6A0A, 0xBCD5, 0x69F3, 0xBCD6, 0x6A02, 0xBCD7, 0x6A05, 0xBCD8, 0x69ED, 0xBCD9, 0x6A11, 0xBCDA, 0x6B50, 0xBCDB, 0x6B4E, 0xBCDC, 0x6BA4, 0xBCDD, 0x6BC5, 0xBCDE, 0x6BC6, 0xBCDF, 0x6F3F, 0xBCE0, 0x6F7C, 0xBCE1, 0x6F84, 0xBCE2, 0x6F51, 0xBCE3, 0x6F66, 0xBCE4, 0x6F54, 0xBCE5, 0x6F86, 0xBCE6, 0x6F6D, 0xBCE7, 0x6F5B, 0xBCE8, 0x6F78, 0xBCE9, 0x6F6E, 0xBCEA, 0x6F8E, 0xBCEB, 0x6F7A, 0xBCEC, 0x6F70, 0xBCED, 0x6F64, 0xBCEE, 0x6F97, 0xBCEF, 0x6F58, 0xBCF0, 0x6ED5, 0xBCF1, 0x6F6F, 0xBCF2, 0x6F60, 0xBCF3, 0x6F5F, 0xBCF4, 0x719F, 0xBCF5, 0x71AC, 0xBCF6, 0x71B1, 0xBCF7, 0x71A8, 0xBCF8, 0x7256, 0xBCF9, 0x729B, 0xBCFA, 0x734E, 0xBCFB, 0x7357, 0xBCFC, 0x7469, 0xBCFD, 0x748B, 0xBCFE, 0x7483, 0xBD40, 0x747E, 0xBD41, 0x7480, 0xBD42, 0x757F, 0xBD43, 0x7620, 0xBD44, 0x7629, 0xBD45, 0x761F, 0xBD46, 0x7624, 0xBD47, 0x7626, 0xBD48, 0x7621, 0xBD49, 0x7622, 0xBD4A, 0x769A, 0xBD4B, 0x76BA, 0xBD4C, 0x76E4, 0xBD4D, 0x778E, 0xBD4E, 0x7787, 0xBD4F, 0x778C, 0xBD50, 0x7791, 0xBD51, 0x778B, 0xBD52, 0x78CB, 0xBD53, 0x78C5, 0xBD54, 0x78BA, 0xBD55, 0x78CA, 0xBD56, 0x78BE, 0xBD57, 0x78D5, 0xBD58, 0x78BC, 0xBD59, 0x78D0, 0xBD5A, 0x7A3F, 0xBD5B, 0x7A3C, 0xBD5C, 0x7A40, 0xBD5D, 0x7A3D, 0xBD5E, 0x7A37, 0xBD5F, 0x7A3B, 0xBD60, 0x7AAF, 0xBD61, 0x7AAE, 0xBD62, 0x7BAD, 0xBD63, 0x7BB1, 0xBD64, 0x7BC4, 0xBD65, 0x7BB4, 0xBD66, 0x7BC6, 0xBD67, 0x7BC7, 0xBD68, 0x7BC1, 0xBD69, 0x7BA0, 0xBD6A, 0x7BCC, 0xBD6B, 0x7CCA, 0xBD6C, 0x7DE0, 0xBD6D, 0x7DF4, 0xBD6E, 0x7DEF, 0xBD6F, 0x7DFB, 0xBD70, 0x7DD8, 0xBD71, 0x7DEC, 0xBD72, 0x7DDD, 0xBD73, 0x7DE8, 0xBD74, 0x7DE3, 0xBD75, 0x7DDA, 0xBD76, 0x7DDE, 0xBD77, 0x7DE9, 0xBD78, 0x7D9E, 0xBD79, 0x7DD9, 0xBD7A, 0x7DF2, 0xBD7B, 0x7DF9, 0xBD7C, 0x7F75, 0xBD7D, 0x7F77, 0xBD7E, 0x7FAF, 0xBDA1, 0x7FE9, 0xBDA2, 0x8026, 0xBDA3, 0x819B, 0xBDA4, 0x819C, 0xBDA5, 0x819D, 0xBDA6, 0x81A0, 0xBDA7, 0x819A, 0xBDA8, 0x8198, 0xBDA9, 0x8517, 0xBDAA, 0x853D, 0xBDAB, 0x851A, 0xBDAC, 0x84EE, 0xBDAD, 0x852C, 0xBDAE, 0x852D, 0xBDAF, 0x8513, 0xBDB0, 0x8511, 0xBDB1, 0x8523, 0xBDB2, 0x8521, 0xBDB3, 0x8514, 0xBDB4, 0x84EC, 0xBDB5, 0x8525, 0xBDB6, 0x84FF, 0xBDB7, 0x8506, 0xBDB8, 0x8782, 0xBDB9, 0x8774, 0xBDBA, 0x8776, 0xBDBB, 0x8760, 0xBDBC, 0x8766, 0xBDBD, 0x8778, 0xBDBE, 0x8768, 0xBDBF, 0x8759, 0xBDC0, 0x8757, 0xBDC1, 0x874C, 0xBDC2, 0x8753, 0xBDC3, 0x885B, 0xBDC4, 0x885D, 0xBDC5, 0x8910, 0xBDC6, 0x8907, 0xBDC7, 0x8912, 0xBDC8, 0x8913, 0xBDC9, 0x8915, 0xBDCA, 0x890A, 0xBDCB, 0x8ABC, 0xBDCC, 0x8AD2, 0xBDCD, 0x8AC7, 0xBDCE, 0x8AC4, 0xBDCF, 0x8A95, 0xBDD0, 0x8ACB, 0xBDD1, 0x8AF8, 0xBDD2, 0x8AB2, 0xBDD3, 0x8AC9, 0xBDD4, 0x8AC2, 0xBDD5, 0x8ABF, 0xBDD6, 0x8AB0, 0xBDD7, 0x8AD6, 0xBDD8, 0x8ACD, 0xBDD9, 0x8AB6, 0xBDDA, 0x8AB9, 0xBDDB, 0x8ADB, 0xBDDC, 0x8C4C, 0xBDDD, 0x8C4E, 0xBDDE, 0x8C6C, 0xBDDF, 0x8CE0, 0xBDE0, 0x8CDE, 0xBDE1, 0x8CE6, 0xBDE2, 0x8CE4, 0xBDE3, 0x8CEC, 0xBDE4, 0x8CED, 0xBDE5, 0x8CE2, 0xBDE6, 0x8CE3, 0xBDE7, 0x8CDC, 0xBDE8, 0x8CEA, 0xBDE9, 0x8CE1, 0xBDEA, 0x8D6D, 0xBDEB, 0x8D9F, 0xBDEC, 0x8DA3, 0xBDED, 0x8E2B, 0xBDEE, 0x8E10, 0xBDEF, 0x8E1D, 0xBDF0, 0x8E22, 0xBDF1, 0x8E0F, 0xBDF2, 0x8E29, 0xBDF3, 0x8E1F, 0xBDF4, 0x8E21, 0xBDF5, 0x8E1E, 0xBDF6, 0x8EBA, 0xBDF7, 0x8F1D, 0xBDF8, 0x8F1B, 0xBDF9, 0x8F1F, 0xBDFA, 0x8F29, 0xBDFB, 0x8F26, 0xBDFC, 0x8F2A, 0xBDFD, 0x8F1C, 0xBDFE, 0x8F1E, 0xBE40, 0x8F25, 0xBE41, 0x9069, 0xBE42, 0x906E, 0xBE43, 0x9068, 0xBE44, 0x906D, 0xBE45, 0x9077, 0xBE46, 0x9130, 0xBE47, 0x912D, 0xBE48, 0x9127, 0xBE49, 0x9131, 0xBE4A, 0x9187, 0xBE4B, 0x9189, 0xBE4C, 0x918B, 0xBE4D, 0x9183, 0xBE4E, 0x92C5, 0xBE4F, 0x92BB, 0xBE50, 0x92B7, 0xBE51, 0x92EA, 0xBE52, 0x92AC, 0xBE53, 0x92E4, 0xBE54, 0x92C1, 0xBE55, 0x92B3, 0xBE56, 0x92BC, 0xBE57, 0x92D2, 0xBE58, 0x92C7, 0xBE59, 0x92F0, 0xBE5A, 0x92B2, 0xBE5B, 0x95AD, 0xBE5C, 0x95B1, 0xBE5D, 0x9704, 0xBE5E, 0x9706, 0xBE5F, 0x9707, 0xBE60, 0x9709, 0xBE61, 0x9760, 0xBE62, 0x978D, 0xBE63, 0x978B, 0xBE64, 0x978F, 0xBE65, 0x9821, 0xBE66, 0x982B, 0xBE67, 0x981C, 0xBE68, 0x98B3, 0xBE69, 0x990A, 0xBE6A, 0x9913, 0xBE6B, 0x9912, 0xBE6C, 0x9918, 0xBE6D, 0x99DD, 0xBE6E, 0x99D0, 0xBE6F, 0x99DF, 0xBE70, 0x99DB, 0xBE71, 0x99D1, 0xBE72, 0x99D5, 0xBE73, 0x99D2, 0xBE74, 0x99D9, 0xBE75, 0x9AB7, 0xBE76, 0x9AEE, 0xBE77, 0x9AEF, 0xBE78, 0x9B27, 0xBE79, 0x9B45, 0xBE7A, 0x9B44, 0xBE7B, 0x9B77, 0xBE7C, 0x9B6F, 0xBE7D, 0x9D06, 0xBE7E, 0x9D09, 0xBEA1, 0x9D03, 0xBEA2, 0x9EA9, 0xBEA3, 0x9EBE, 0xBEA4, 0x9ECE, 0xBEA5, 0x58A8, 0xBEA6, 0x9F52, 0xBEA7, 0x5112, 0xBEA8, 0x5118, 0xBEA9, 0x5114, 0xBEAA, 0x5110, 0xBEAB, 0x5115, 0xBEAC, 0x5180, 0xBEAD, 0x51AA, 0xBEAE, 0x51DD, 0xBEAF, 0x5291, 0xBEB0, 0x5293, 0xBEB1, 0x52F3, 0xBEB2, 0x5659, 0xBEB3, 0x566B, 0xBEB4, 0x5679, 0xBEB5, 0x5669, 0xBEB6, 0x5664, 0xBEB7, 0x5678, 0xBEB8, 0x566A, 0xBEB9, 0x5668, 0xBEBA, 0x5665, 0xBEBB, 0x5671, 0xBEBC, 0x566F, 0xBEBD, 0x566C, 0xBEBE, 0x5662, 0xBEBF, 0x5676, 0xBEC0, 0x58C1, 0xBEC1, 0x58BE, 0xBEC2, 0x58C7, 0xBEC3, 0x58C5, 0xBEC4, 0x596E, 0xBEC5, 0x5B1D, 0xBEC6, 0x5B34, 0xBEC7, 0x5B78, 0xBEC8, 0x5BF0, 0xBEC9, 0x5C0E, 0xBECA, 0x5F4A, 0xBECB, 0x61B2, 0xBECC, 0x6191, 0xBECD, 0x61A9, 0xBECE, 0x618A, 0xBECF, 0x61CD, 0xBED0, 0x61B6, 0xBED1, 0x61BE, 0xBED2, 0x61CA, 0xBED3, 0x61C8, 0xBED4, 0x6230, 0xBED5, 0x64C5, 0xBED6, 0x64C1, 0xBED7, 0x64CB, 0xBED8, 0x64BB, 0xBED9, 0x64BC, 0xBEDA, 0x64DA, 0xBEDB, 0x64C4, 0xBEDC, 0x64C7, 0xBEDD, 0x64C2, 0xBEDE, 0x64CD, 0xBEDF, 0x64BF, 0xBEE0, 0x64D2, 0xBEE1, 0x64D4, 0xBEE2, 0x64BE, 0xBEE3, 0x6574, 0xBEE4, 0x66C6, 0xBEE5, 0x66C9, 0xBEE6, 0x66B9, 0xBEE7, 0x66C4, 0xBEE8, 0x66C7, 0xBEE9, 0x66B8, 0xBEEA, 0x6A3D, 0xBEEB, 0x6A38, 0xBEEC, 0x6A3A, 0xBEED, 0x6A59, 0xBEEE, 0x6A6B, 0xBEEF, 0x6A58, 0xBEF0, 0x6A39, 0xBEF1, 0x6A44, 0xBEF2, 0x6A62, 0xBEF3, 0x6A61, 0xBEF4, 0x6A4B, 0xBEF5, 0x6A47, 0xBEF6, 0x6A35, 0xBEF7, 0x6A5F, 0xBEF8, 0x6A48, 0xBEF9, 0x6B59, 0xBEFA, 0x6B77, 0xBEFB, 0x6C05, 0xBEFC, 0x6FC2, 0xBEFD, 0x6FB1, 0xBEFE, 0x6FA1, 0xBF40, 0x6FC3, 0xBF41, 0x6FA4, 0xBF42, 0x6FC1, 0xBF43, 0x6FA7, 0xBF44, 0x6FB3, 0xBF45, 0x6FC0, 0xBF46, 0x6FB9, 0xBF47, 0x6FB6, 0xBF48, 0x6FA6, 0xBF49, 0x6FA0, 0xBF4A, 0x6FB4, 0xBF4B, 0x71BE, 0xBF4C, 0x71C9, 0xBF4D, 0x71D0, 0xBF4E, 0x71D2, 0xBF4F, 0x71C8, 0xBF50, 0x71D5, 0xBF51, 0x71B9, 0xBF52, 0x71CE, 0xBF53, 0x71D9, 0xBF54, 0x71DC, 0xBF55, 0x71C3, 0xBF56, 0x71C4, 0xBF57, 0x7368, 0xBF58, 0x749C, 0xBF59, 0x74A3, 0xBF5A, 0x7498, 0xBF5B, 0x749F, 0xBF5C, 0x749E, 0xBF5D, 0x74E2, 0xBF5E, 0x750C, 0xBF5F, 0x750D, 0xBF60, 0x7634, 0xBF61, 0x7638, 0xBF62, 0x763A, 0xBF63, 0x76E7, 0xBF64, 0x76E5, 0xBF65, 0x77A0, 0xBF66, 0x779E, 0xBF67, 0x779F, 0xBF68, 0x77A5, 0xBF69, 0x78E8, 0xBF6A, 0x78DA, 0xBF6B, 0x78EC, 0xBF6C, 0x78E7, 0xBF6D, 0x79A6, 0xBF6E, 0x7A4D, 0xBF6F, 0x7A4E, 0xBF70, 0x7A46, 0xBF71, 0x7A4C, 0xBF72, 0x7A4B, 0xBF73, 0x7ABA, 0xBF74, 0x7BD9, 0xBF75, 0x7C11, 0xBF76, 0x7BC9, 0xBF77, 0x7BE4, 0xBF78, 0x7BDB, 0xBF79, 0x7BE1, 0xBF7A, 0x7BE9, 0xBF7B, 0x7BE6, 0xBF7C, 0x7CD5, 0xBF7D, 0x7CD6, 0xBF7E, 0x7E0A, 0xBFA1, 0x7E11, 0xBFA2, 0x7E08, 0xBFA3, 0x7E1B, 0xBFA4, 0x7E23, 0xBFA5, 0x7E1E, 0xBFA6, 0x7E1D, 0xBFA7, 0x7E09, 0xBFA8, 0x7E10, 0xBFA9, 0x7F79, 0xBFAA, 0x7FB2, 0xBFAB, 0x7FF0, 0xBFAC, 0x7FF1, 0xBFAD, 0x7FEE, 0xBFAE, 0x8028, 0xBFAF, 0x81B3, 0xBFB0, 0x81A9, 0xBFB1, 0x81A8, 0xBFB2, 0x81FB, 0xBFB3, 0x8208, 0xBFB4, 0x8258, 0xBFB5, 0x8259, 0xBFB6, 0x854A, 0xBFB7, 0x8559, 0xBFB8, 0x8548, 0xBFB9, 0x8568, 0xBFBA, 0x8569, 0xBFBB, 0x8543, 0xBFBC, 0x8549, 0xBFBD, 0x856D, 0xBFBE, 0x856A, 0xBFBF, 0x855E, 0xBFC0, 0x8783, 0xBFC1, 0x879F, 0xBFC2, 0x879E, 0xBFC3, 0x87A2, 0xBFC4, 0x878D, 0xBFC5, 0x8861, 0xBFC6, 0x892A, 0xBFC7, 0x8932, 0xBFC8, 0x8925, 0xBFC9, 0x892B, 0xBFCA, 0x8921, 0xBFCB, 0x89AA, 0xBFCC, 0x89A6, 0xBFCD, 0x8AE6, 0xBFCE, 0x8AFA, 0xBFCF, 0x8AEB, 0xBFD0, 0x8AF1, 0xBFD1, 0x8B00, 0xBFD2, 0x8ADC, 0xBFD3, 0x8AE7, 0xBFD4, 0x8AEE, 0xBFD5, 0x8AFE, 0xBFD6, 0x8B01, 0xBFD7, 0x8B02, 0xBFD8, 0x8AF7, 0xBFD9, 0x8AED, 0xBFDA, 0x8AF3, 0xBFDB, 0x8AF6, 0xBFDC, 0x8AFC, 0xBFDD, 0x8C6B, 0xBFDE, 0x8C6D, 0xBFDF, 0x8C93, 0xBFE0, 0x8CF4, 0xBFE1, 0x8E44, 0xBFE2, 0x8E31, 0xBFE3, 0x8E34, 0xBFE4, 0x8E42, 0xBFE5, 0x8E39, 0xBFE6, 0x8E35, 0xBFE7, 0x8F3B, 0xBFE8, 0x8F2F, 0xBFE9, 0x8F38, 0xBFEA, 0x8F33, 0xBFEB, 0x8FA8, 0xBFEC, 0x8FA6, 0xBFED, 0x9075, 0xBFEE, 0x9074, 0xBFEF, 0x9078, 0xBFF0, 0x9072, 0xBFF1, 0x907C, 0xBFF2, 0x907A, 0xBFF3, 0x9134, 0xBFF4, 0x9192, 0xBFF5, 0x9320, 0xBFF6, 0x9336, 0xBFF7, 0x92F8, 0xBFF8, 0x9333, 0xBFF9, 0x932F, 0xBFFA, 0x9322, 0xBFFB, 0x92FC, 0xBFFC, 0x932B, 0xBFFD, 0x9304, 0xBFFE, 0x931A, 0xC040, 0x9310, 0xC041, 0x9326, 0xC042, 0x9321, 0xC043, 0x9315, 0xC044, 0x932E, 0xC045, 0x9319, 0xC046, 0x95BB, 0xC047, 0x96A7, 0xC048, 0x96A8, 0xC049, 0x96AA, 0xC04A, 0x96D5, 0xC04B, 0x970E, 0xC04C, 0x9711, 0xC04D, 0x9716, 0xC04E, 0x970D, 0xC04F, 0x9713, 0xC050, 0x970F, 0xC051, 0x975B, 0xC052, 0x975C, 0xC053, 0x9766, 0xC054, 0x9798, 0xC055, 0x9830, 0xC056, 0x9838, 0xC057, 0x983B, 0xC058, 0x9837, 0xC059, 0x982D, 0xC05A, 0x9839, 0xC05B, 0x9824, 0xC05C, 0x9910, 0xC05D, 0x9928, 0xC05E, 0x991E, 0xC05F, 0x991B, 0xC060, 0x9921, 0xC061, 0x991A, 0xC062, 0x99ED, 0xC063, 0x99E2, 0xC064, 0x99F1, 0xC065, 0x9AB8, 0xC066, 0x9ABC, 0xC067, 0x9AFB, 0xC068, 0x9AED, 0xC069, 0x9B28, 0xC06A, 0x9B91, 0xC06B, 0x9D15, 0xC06C, 0x9D23, 0xC06D, 0x9D26, 0xC06E, 0x9D28, 0xC06F, 0x9D12, 0xC070, 0x9D1B, 0xC071, 0x9ED8, 0xC072, 0x9ED4, 0xC073, 0x9F8D, 0xC074, 0x9F9C, 0xC075, 0x512A, 0xC076, 0x511F, 0xC077, 0x5121, 0xC078, 0x5132, 0xC079, 0x52F5, 0xC07A, 0x568E, 0xC07B, 0x5680, 0xC07C, 0x5690, 0xC07D, 0x5685, 0xC07E, 0x5687, 0xC0A1, 0x568F, 0xC0A2, 0x58D5, 0xC0A3, 0x58D3, 0xC0A4, 0x58D1, 0xC0A5, 0x58CE, 0xC0A6, 0x5B30, 0xC0A7, 0x5B2A, 0xC0A8, 0x5B24, 0xC0A9, 0x5B7A, 0xC0AA, 0x5C37, 0xC0AB, 0x5C68, 0xC0AC, 0x5DBC, 0xC0AD, 0x5DBA, 0xC0AE, 0x5DBD, 0xC0AF, 0x5DB8, 0xC0B0, 0x5E6B, 0xC0B1, 0x5F4C, 0xC0B2, 0x5FBD, 0xC0B3, 0x61C9, 0xC0B4, 0x61C2, 0xC0B5, 0x61C7, 0xC0B6, 0x61E6, 0xC0B7, 0x61CB, 0xC0B8, 0x6232, 0xC0B9, 0x6234, 0xC0BA, 0x64CE, 0xC0BB, 0x64CA, 0xC0BC, 0x64D8, 0xC0BD, 0x64E0, 0xC0BE, 0x64F0, 0xC0BF, 0x64E6, 0xC0C0, 0x64EC, 0xC0C1, 0x64F1, 0xC0C2, 0x64E2, 0xC0C3, 0x64ED, 0xC0C4, 0x6582, 0xC0C5, 0x6583, 0xC0C6, 0x66D9, 0xC0C7, 0x66D6, 0xC0C8, 0x6A80, 0xC0C9, 0x6A94, 0xC0CA, 0x6A84, 0xC0CB, 0x6AA2, 0xC0CC, 0x6A9C, 0xC0CD, 0x6ADB, 0xC0CE, 0x6AA3, 0xC0CF, 0x6A7E, 0xC0D0, 0x6A97, 0xC0D1, 0x6A90, 0xC0D2, 0x6AA0, 0xC0D3, 0x6B5C, 0xC0D4, 0x6BAE, 0xC0D5, 0x6BDA, 0xC0D6, 0x6C08, 0xC0D7, 0x6FD8, 0xC0D8, 0x6FF1, 0xC0D9, 0x6FDF, 0xC0DA, 0x6FE0, 0xC0DB, 0x6FDB, 0xC0DC, 0x6FE4, 0xC0DD, 0x6FEB, 0xC0DE, 0x6FEF, 0xC0DF, 0x6F80, 0xC0E0, 0x6FEC, 0xC0E1, 0x6FE1, 0xC0E2, 0x6FE9, 0xC0E3, 0x6FD5, 0xC0E4, 0x6FEE, 0xC0E5, 0x6FF0, 0xC0E6, 0x71E7, 0xC0E7, 0x71DF, 0xC0E8, 0x71EE, 0xC0E9, 0x71E6, 0xC0EA, 0x71E5, 0xC0EB, 0x71ED, 0xC0EC, 0x71EC, 0xC0ED, 0x71F4, 0xC0EE, 0x71E0, 0xC0EF, 0x7235, 0xC0F0, 0x7246, 0xC0F1, 0x7370, 0xC0F2, 0x7372, 0xC0F3, 0x74A9, 0xC0F4, 0x74B0, 0xC0F5, 0x74A6, 0xC0F6, 0x74A8, 0xC0F7, 0x7646, 0xC0F8, 0x7642, 0xC0F9, 0x764C, 0xC0FA, 0x76EA, 0xC0FB, 0x77B3, 0xC0FC, 0x77AA, 0xC0FD, 0x77B0, 0xC0FE, 0x77AC, 0xC140, 0x77A7, 0xC141, 0x77AD, 0xC142, 0x77EF, 0xC143, 0x78F7, 0xC144, 0x78FA, 0xC145, 0x78F4, 0xC146, 0x78EF, 0xC147, 0x7901, 0xC148, 0x79A7, 0xC149, 0x79AA, 0xC14A, 0x7A57, 0xC14B, 0x7ABF, 0xC14C, 0x7C07, 0xC14D, 0x7C0D, 0xC14E, 0x7BFE, 0xC14F, 0x7BF7, 0xC150, 0x7C0C, 0xC151, 0x7BE0, 0xC152, 0x7CE0, 0xC153, 0x7CDC, 0xC154, 0x7CDE, 0xC155, 0x7CE2, 0xC156, 0x7CDF, 0xC157, 0x7CD9, 0xC158, 0x7CDD, 0xC159, 0x7E2E, 0xC15A, 0x7E3E, 0xC15B, 0x7E46, 0xC15C, 0x7E37, 0xC15D, 0x7E32, 0xC15E, 0x7E43, 0xC15F, 0x7E2B, 0xC160, 0x7E3D, 0xC161, 0x7E31, 0xC162, 0x7E45, 0xC163, 0x7E41, 0xC164, 0x7E34, 0xC165, 0x7E39, 0xC166, 0x7E48, 0xC167, 0x7E35, 0xC168, 0x7E3F, 0xC169, 0x7E2F, 0xC16A, 0x7F44, 0xC16B, 0x7FF3, 0xC16C, 0x7FFC, 0xC16D, 0x8071, 0xC16E, 0x8072, 0xC16F, 0x8070, 0xC170, 0x806F, 0xC171, 0x8073, 0xC172, 0x81C6, 0xC173, 0x81C3, 0xC174, 0x81BA, 0xC175, 0x81C2, 0xC176, 0x81C0, 0xC177, 0x81BF, 0xC178, 0x81BD, 0xC179, 0x81C9, 0xC17A, 0x81BE, 0xC17B, 0x81E8, 0xC17C, 0x8209, 0xC17D, 0x8271, 0xC17E, 0x85AA, 0xC1A1, 0x8584, 0xC1A2, 0x857E, 0xC1A3, 0x859C, 0xC1A4, 0x8591, 0xC1A5, 0x8594, 0xC1A6, 0x85AF, 0xC1A7, 0x859B, 0xC1A8, 0x8587, 0xC1A9, 0x85A8, 0xC1AA, 0x858A, 0xC1AB, 0x8667, 0xC1AC, 0x87C0, 0xC1AD, 0x87D1, 0xC1AE, 0x87B3, 0xC1AF, 0x87D2, 0xC1B0, 0x87C6, 0xC1B1, 0x87AB, 0xC1B2, 0x87BB, 0xC1B3, 0x87BA, 0xC1B4, 0x87C8, 0xC1B5, 0x87CB, 0xC1B6, 0x893B, 0xC1B7, 0x8936, 0xC1B8, 0x8944, 0xC1B9, 0x8938, 0xC1BA, 0x893D, 0xC1BB, 0x89AC, 0xC1BC, 0x8B0E, 0xC1BD, 0x8B17, 0xC1BE, 0x8B19, 0xC1BF, 0x8B1B, 0xC1C0, 0x8B0A, 0xC1C1, 0x8B20, 0xC1C2, 0x8B1D, 0xC1C3, 0x8B04, 0xC1C4, 0x8B10, 0xC1C5, 0x8C41, 0xC1C6, 0x8C3F, 0xC1C7, 0x8C73, 0xC1C8, 0x8CFA, 0xC1C9, 0x8CFD, 0xC1CA, 0x8CFC, 0xC1CB, 0x8CF8, 0xC1CC, 0x8CFB, 0xC1CD, 0x8DA8, 0xC1CE, 0x8E49, 0xC1CF, 0x8E4B, 0xC1D0, 0x8E48, 0xC1D1, 0x8E4A, 0xC1D2, 0x8F44, 0xC1D3, 0x8F3E, 0xC1D4, 0x8F42, 0xC1D5, 0x8F45, 0xC1D6, 0x8F3F, 0xC1D7, 0x907F, 0xC1D8, 0x907D, 0xC1D9, 0x9084, 0xC1DA, 0x9081, 0xC1DB, 0x9082, 0xC1DC, 0x9080, 0xC1DD, 0x9139, 0xC1DE, 0x91A3, 0xC1DF, 0x919E, 0xC1E0, 0x919C, 0xC1E1, 0x934D, 0xC1E2, 0x9382, 0xC1E3, 0x9328, 0xC1E4, 0x9375, 0xC1E5, 0x934A, 0xC1E6, 0x9365, 0xC1E7, 0x934B, 0xC1E8, 0x9318, 0xC1E9, 0x937E, 0xC1EA, 0x936C, 0xC1EB, 0x935B, 0xC1EC, 0x9370, 0xC1ED, 0x935A, 0xC1EE, 0x9354, 0xC1EF, 0x95CA, 0xC1F0, 0x95CB, 0xC1F1, 0x95CC, 0xC1F2, 0x95C8, 0xC1F3, 0x95C6, 0xC1F4, 0x96B1, 0xC1F5, 0x96B8, 0xC1F6, 0x96D6, 0xC1F7, 0x971C, 0xC1F8, 0x971E, 0xC1F9, 0x97A0, 0xC1FA, 0x97D3, 0xC1FB, 0x9846, 0xC1FC, 0x98B6, 0xC1FD, 0x9935, 0xC1FE, 0x9A01, 0xC240, 0x99FF, 0xC241, 0x9BAE, 0xC242, 0x9BAB, 0xC243, 0x9BAA, 0xC244, 0x9BAD, 0xC245, 0x9D3B, 0xC246, 0x9D3F, 0xC247, 0x9E8B, 0xC248, 0x9ECF, 0xC249, 0x9EDE, 0xC24A, 0x9EDC, 0xC24B, 0x9EDD, 0xC24C, 0x9EDB, 0xC24D, 0x9F3E, 0xC24E, 0x9F4B, 0xC24F, 0x53E2, 0xC250, 0x5695, 0xC251, 0x56AE, 0xC252, 0x58D9, 0xC253, 0x58D8, 0xC254, 0x5B38, 0xC255, 0x5F5D, 0xC256, 0x61E3, 0xC257, 0x6233, 0xC258, 0x64F4, 0xC259, 0x64F2, 0xC25A, 0x64FE, 0xC25B, 0x6506, 0xC25C, 0x64FA, 0xC25D, 0x64FB, 0xC25E, 0x64F7, 0xC25F, 0x65B7, 0xC260, 0x66DC, 0xC261, 0x6726, 0xC262, 0x6AB3, 0xC263, 0x6AAC, 0xC264, 0x6AC3, 0xC265, 0x6ABB, 0xC266, 0x6AB8, 0xC267, 0x6AC2, 0xC268, 0x6AAE, 0xC269, 0x6AAF, 0xC26A, 0x6B5F, 0xC26B, 0x6B78, 0xC26C, 0x6BAF, 0xC26D, 0x7009, 0xC26E, 0x700B, 0xC26F, 0x6FFE, 0xC270, 0x7006, 0xC271, 0x6FFA, 0xC272, 0x7011, 0xC273, 0x700F, 0xC274, 0x71FB, 0xC275, 0x71FC, 0xC276, 0x71FE, 0xC277, 0x71F8, 0xC278, 0x7377, 0xC279, 0x7375, 0xC27A, 0x74A7, 0xC27B, 0x74BF, 0xC27C, 0x7515, 0xC27D, 0x7656, 0xC27E, 0x7658, 0xC2A1, 0x7652, 0xC2A2, 0x77BD, 0xC2A3, 0x77BF, 0xC2A4, 0x77BB, 0xC2A5, 0x77BC, 0xC2A6, 0x790E, 0xC2A7, 0x79AE, 0xC2A8, 0x7A61, 0xC2A9, 0x7A62, 0xC2AA, 0x7A60, 0xC2AB, 0x7AC4, 0xC2AC, 0x7AC5, 0xC2AD, 0x7C2B, 0xC2AE, 0x7C27, 0xC2AF, 0x7C2A, 0xC2B0, 0x7C1E, 0xC2B1, 0x7C23, 0xC2B2, 0x7C21, 0xC2B3, 0x7CE7, 0xC2B4, 0x7E54, 0xC2B5, 0x7E55, 0xC2B6, 0x7E5E, 0xC2B7, 0x7E5A, 0xC2B8, 0x7E61, 0xC2B9, 0x7E52, 0xC2BA, 0x7E59, 0xC2BB, 0x7F48, 0xC2BC, 0x7FF9, 0xC2BD, 0x7FFB, 0xC2BE, 0x8077, 0xC2BF, 0x8076, 0xC2C0, 0x81CD, 0xC2C1, 0x81CF, 0xC2C2, 0x820A, 0xC2C3, 0x85CF, 0xC2C4, 0x85A9, 0xC2C5, 0x85CD, 0xC2C6, 0x85D0, 0xC2C7, 0x85C9, 0xC2C8, 0x85B0, 0xC2C9, 0x85BA, 0xC2CA, 0x85B9, 0xC2CB, 0x85A6, 0xC2CC, 0x87EF, 0xC2CD, 0x87EC, 0xC2CE, 0x87F2, 0xC2CF, 0x87E0, 0xC2D0, 0x8986, 0xC2D1, 0x89B2, 0xC2D2, 0x89F4, 0xC2D3, 0x8B28, 0xC2D4, 0x8B39, 0xC2D5, 0x8B2C, 0xC2D6, 0x8B2B, 0xC2D7, 0x8C50, 0xC2D8, 0x8D05, 0xC2D9, 0x8E59, 0xC2DA, 0x8E63, 0xC2DB, 0x8E66, 0xC2DC, 0x8E64, 0xC2DD, 0x8E5F, 0xC2DE, 0x8E55, 0xC2DF, 0x8EC0, 0xC2E0, 0x8F49, 0xC2E1, 0x8F4D, 0xC2E2, 0x9087, 0xC2E3, 0x9083, 0xC2E4, 0x9088, 0xC2E5, 0x91AB, 0xC2E6, 0x91AC, 0xC2E7, 0x91D0, 0xC2E8, 0x9394, 0xC2E9, 0x938A, 0xC2EA, 0x9396, 0xC2EB, 0x93A2, 0xC2EC, 0x93B3, 0xC2ED, 0x93AE, 0xC2EE, 0x93AC, 0xC2EF, 0x93B0, 0xC2F0, 0x9398, 0xC2F1, 0x939A, 0xC2F2, 0x9397, 0xC2F3, 0x95D4, 0xC2F4, 0x95D6, 0xC2F5, 0x95D0, 0xC2F6, 0x95D5, 0xC2F7, 0x96E2, 0xC2F8, 0x96DC, 0xC2F9, 0x96D9, 0xC2FA, 0x96DB, 0xC2FB, 0x96DE, 0xC2FC, 0x9724, 0xC2FD, 0x97A3, 0xC2FE, 0x97A6, 0xC340, 0x97AD, 0xC341, 0x97F9, 0xC342, 0x984D, 0xC343, 0x984F, 0xC344, 0x984C, 0xC345, 0x984E, 0xC346, 0x9853, 0xC347, 0x98BA, 0xC348, 0x993E, 0xC349, 0x993F, 0xC34A, 0x993D, 0xC34B, 0x992E, 0xC34C, 0x99A5, 0xC34D, 0x9A0E, 0xC34E, 0x9AC1, 0xC34F, 0x9B03, 0xC350, 0x9B06, 0xC351, 0x9B4F, 0xC352, 0x9B4E, 0xC353, 0x9B4D, 0xC354, 0x9BCA, 0xC355, 0x9BC9, 0xC356, 0x9BFD, 0xC357, 0x9BC8, 0xC358, 0x9BC0, 0xC359, 0x9D51, 0xC35A, 0x9D5D, 0xC35B, 0x9D60, 0xC35C, 0x9EE0, 0xC35D, 0x9F15, 0xC35E, 0x9F2C, 0xC35F, 0x5133, 0xC360, 0x56A5, 0xC361, 0x58DE, 0xC362, 0x58DF, 0xC363, 0x58E2, 0xC364, 0x5BF5, 0xC365, 0x9F90, 0xC366, 0x5EEC, 0xC367, 0x61F2, 0xC368, 0x61F7, 0xC369, 0x61F6, 0xC36A, 0x61F5, 0xC36B, 0x6500, 0xC36C, 0x650F, 0xC36D, 0x66E0, 0xC36E, 0x66DD, 0xC36F, 0x6AE5, 0xC370, 0x6ADD, 0xC371, 0x6ADA, 0xC372, 0x6AD3, 0xC373, 0x701B, 0xC374, 0x701F, 0xC375, 0x7028, 0xC376, 0x701A, 0xC377, 0x701D, 0xC378, 0x7015, 0xC379, 0x7018, 0xC37A, 0x7206, 0xC37B, 0x720D, 0xC37C, 0x7258, 0xC37D, 0x72A2, 0xC37E, 0x7378, 0xC3A1, 0x737A, 0xC3A2, 0x74BD, 0xC3A3, 0x74CA, 0xC3A4, 0x74E3, 0xC3A5, 0x7587, 0xC3A6, 0x7586, 0xC3A7, 0x765F, 0xC3A8, 0x7661, 0xC3A9, 0x77C7, 0xC3AA, 0x7919, 0xC3AB, 0x79B1, 0xC3AC, 0x7A6B, 0xC3AD, 0x7A69, 0xC3AE, 0x7C3E, 0xC3AF, 0x7C3F, 0xC3B0, 0x7C38, 0xC3B1, 0x7C3D, 0xC3B2, 0x7C37, 0xC3B3, 0x7C40, 0xC3B4, 0x7E6B, 0xC3B5, 0x7E6D, 0xC3B6, 0x7E79, 0xC3B7, 0x7E69, 0xC3B8, 0x7E6A, 0xC3B9, 0x7F85, 0xC3BA, 0x7E73, 0xC3BB, 0x7FB6, 0xC3BC, 0x7FB9, 0xC3BD, 0x7FB8, 0xC3BE, 0x81D8, 0xC3BF, 0x85E9, 0xC3C0, 0x85DD, 0xC3C1, 0x85EA, 0xC3C2, 0x85D5, 0xC3C3, 0x85E4, 0xC3C4, 0x85E5, 0xC3C5, 0x85F7, 0xC3C6, 0x87FB, 0xC3C7, 0x8805, 0xC3C8, 0x880D, 0xC3C9, 0x87F9, 0xC3CA, 0x87FE, 0xC3CB, 0x8960, 0xC3CC, 0x895F, 0xC3CD, 0x8956, 0xC3CE, 0x895E, 0xC3CF, 0x8B41, 0xC3D0, 0x8B5C, 0xC3D1, 0x8B58, 0xC3D2, 0x8B49, 0xC3D3, 0x8B5A, 0xC3D4, 0x8B4E, 0xC3D5, 0x8B4F, 0xC3D6, 0x8B46, 0xC3D7, 0x8B59, 0xC3D8, 0x8D08, 0xC3D9, 0x8D0A, 0xC3DA, 0x8E7C, 0xC3DB, 0x8E72, 0xC3DC, 0x8E87, 0xC3DD, 0x8E76, 0xC3DE, 0x8E6C, 0xC3DF, 0x8E7A, 0xC3E0, 0x8E74, 0xC3E1, 0x8F54, 0xC3E2, 0x8F4E, 0xC3E3, 0x8FAD, 0xC3E4, 0x908A, 0xC3E5, 0x908B, 0xC3E6, 0x91B1, 0xC3E7, 0x91AE, 0xC3E8, 0x93E1, 0xC3E9, 0x93D1, 0xC3EA, 0x93DF, 0xC3EB, 0x93C3, 0xC3EC, 0x93C8, 0xC3ED, 0x93DC, 0xC3EE, 0x93DD, 0xC3EF, 0x93D6, 0xC3F0, 0x93E2, 0xC3F1, 0x93CD, 0xC3F2, 0x93D8, 0xC3F3, 0x93E4, 0xC3F4, 0x93D7, 0xC3F5, 0x93E8, 0xC3F6, 0x95DC, 0xC3F7, 0x96B4, 0xC3F8, 0x96E3, 0xC3F9, 0x972A, 0xC3FA, 0x9727, 0xC3FB, 0x9761, 0xC3FC, 0x97DC, 0xC3FD, 0x97FB, 0xC3FE, 0x985E, 0xC440, 0x9858, 0xC441, 0x985B, 0xC442, 0x98BC, 0xC443, 0x9945, 0xC444, 0x9949, 0xC445, 0x9A16, 0xC446, 0x9A19, 0xC447, 0x9B0D, 0xC448, 0x9BE8, 0xC449, 0x9BE7, 0xC44A, 0x9BD6, 0xC44B, 0x9BDB, 0xC44C, 0x9D89, 0xC44D, 0x9D61, 0xC44E, 0x9D72, 0xC44F, 0x9D6A, 0xC450, 0x9D6C, 0xC451, 0x9E92, 0xC452, 0x9E97, 0xC453, 0x9E93, 0xC454, 0x9EB4, 0xC455, 0x52F8, 0xC456, 0x56A8, 0xC457, 0x56B7, 0xC458, 0x56B6, 0xC459, 0x56B4, 0xC45A, 0x56BC, 0xC45B, 0x58E4, 0xC45C, 0x5B40, 0xC45D, 0x5B43, 0xC45E, 0x5B7D, 0xC45F, 0x5BF6, 0xC460, 0x5DC9, 0xC461, 0x61F8, 0xC462, 0x61FA, 0xC463, 0x6518, 0xC464, 0x6514, 0xC465, 0x6519, 0xC466, 0x66E6, 0xC467, 0x6727, 0xC468, 0x6AEC, 0xC469, 0x703E, 0xC46A, 0x7030, 0xC46B, 0x7032, 0xC46C, 0x7210, 0xC46D, 0x737B, 0xC46E, 0x74CF, 0xC46F, 0x7662, 0xC470, 0x7665, 0xC471, 0x7926, 0xC472, 0x792A, 0xC473, 0x792C, 0xC474, 0x792B, 0xC475, 0x7AC7, 0xC476, 0x7AF6, 0xC477, 0x7C4C, 0xC478, 0x7C43, 0xC479, 0x7C4D, 0xC47A, 0x7CEF, 0xC47B, 0x7CF0, 0xC47C, 0x8FAE, 0xC47D, 0x7E7D, 0xC47E, 0x7E7C, 0xC4A1, 0x7E82, 0xC4A2, 0x7F4C, 0xC4A3, 0x8000, 0xC4A4, 0x81DA, 0xC4A5, 0x8266, 0xC4A6, 0x85FB, 0xC4A7, 0x85F9, 0xC4A8, 0x8611, 0xC4A9, 0x85FA, 0xC4AA, 0x8606, 0xC4AB, 0x860B, 0xC4AC, 0x8607, 0xC4AD, 0x860A, 0xC4AE, 0x8814, 0xC4AF, 0x8815, 0xC4B0, 0x8964, 0xC4B1, 0x89BA, 0xC4B2, 0x89F8, 0xC4B3, 0x8B70, 0xC4B4, 0x8B6C, 0xC4B5, 0x8B66, 0xC4B6, 0x8B6F, 0xC4B7, 0x8B5F, 0xC4B8, 0x8B6B, 0xC4B9, 0x8D0F, 0xC4BA, 0x8D0D, 0xC4BB, 0x8E89, 0xC4BC, 0x8E81, 0xC4BD, 0x8E85, 0xC4BE, 0x8E82, 0xC4BF, 0x91B4, 0xC4C0, 0x91CB, 0xC4C1, 0x9418, 0xC4C2, 0x9403, 0xC4C3, 0x93FD, 0xC4C4, 0x95E1, 0xC4C5, 0x9730, 0xC4C6, 0x98C4, 0xC4C7, 0x9952, 0xC4C8, 0x9951, 0xC4C9, 0x99A8, 0xC4CA, 0x9A2B, 0xC4CB, 0x9A30, 0xC4CC, 0x9A37, 0xC4CD, 0x9A35, 0xC4CE, 0x9C13, 0xC4CF, 0x9C0D, 0xC4D0, 0x9E79, 0xC4D1, 0x9EB5, 0xC4D2, 0x9EE8, 0xC4D3, 0x9F2F, 0xC4D4, 0x9F5F, 0xC4D5, 0x9F63, 0xC4D6, 0x9F61, 0xC4D7, 0x5137, 0xC4D8, 0x5138, 0xC4D9, 0x56C1, 0xC4DA, 0x56C0, 0xC4DB, 0x56C2, 0xC4DC, 0x5914, 0xC4DD, 0x5C6C, 0xC4DE, 0x5DCD, 0xC4DF, 0x61FC, 0xC4E0, 0x61FE, 0xC4E1, 0x651D, 0xC4E2, 0x651C, 0xC4E3, 0x6595, 0xC4E4, 0x66E9, 0xC4E5, 0x6AFB, 0xC4E6, 0x6B04, 0xC4E7, 0x6AFA, 0xC4E8, 0x6BB2, 0xC4E9, 0x704C, 0xC4EA, 0x721B, 0xC4EB, 0x72A7, 0xC4EC, 0x74D6, 0xC4ED, 0x74D4, 0xC4EE, 0x7669, 0xC4EF, 0x77D3, 0xC4F0, 0x7C50, 0xC4F1, 0x7E8F, 0xC4F2, 0x7E8C, 0xC4F3, 0x7FBC, 0xC4F4, 0x8617, 0xC4F5, 0x862D, 0xC4F6, 0x861A, 0xC4F7, 0x8823, 0xC4F8, 0x8822, 0xC4F9, 0x8821, 0xC4FA, 0x881F, 0xC4FB, 0x896A, 0xC4FC, 0x896C, 0xC4FD, 0x89BD, 0xC4FE, 0x8B74, 0xC540, 0x8B77, 0xC541, 0x8B7D, 0xC542, 0x8D13, 0xC543, 0x8E8A, 0xC544, 0x8E8D, 0xC545, 0x8E8B, 0xC546, 0x8F5F, 0xC547, 0x8FAF, 0xC548, 0x91BA, 0xC549, 0x942E, 0xC54A, 0x9433, 0xC54B, 0x9435, 0xC54C, 0x943A, 0xC54D, 0x9438, 0xC54E, 0x9432, 0xC54F, 0x942B, 0xC550, 0x95E2, 0xC551, 0x9738, 0xC552, 0x9739, 0xC553, 0x9732, 0xC554, 0x97FF, 0xC555, 0x9867, 0xC556, 0x9865, 0xC557, 0x9957, 0xC558, 0x9A45, 0xC559, 0x9A43, 0xC55A, 0x9A40, 0xC55B, 0x9A3E, 0xC55C, 0x9ACF, 0xC55D, 0x9B54, 0xC55E, 0x9B51, 0xC55F, 0x9C2D, 0xC560, 0x9C25, 0xC561, 0x9DAF, 0xC562, 0x9DB4, 0xC563, 0x9DC2, 0xC564, 0x9DB8, 0xC565, 0x9E9D, 0xC566, 0x9EEF, 0xC567, 0x9F19, 0xC568, 0x9F5C, 0xC569, 0x9F66, 0xC56A, 0x9F67, 0xC56B, 0x513C, 0xC56C, 0x513B, 0xC56D, 0x56C8, 0xC56E, 0x56CA, 0xC56F, 0x56C9, 0xC570, 0x5B7F, 0xC571, 0x5DD4, 0xC572, 0x5DD2, 0xC573, 0x5F4E, 0xC574, 0x61FF, 0xC575, 0x6524, 0xC576, 0x6B0A, 0xC577, 0x6B61, 0xC578, 0x7051, 0xC579, 0x7058, 0xC57A, 0x7380, 0xC57B, 0x74E4, 0xC57C, 0x758A, 0xC57D, 0x766E, 0xC57E, 0x766C, 0xC5A1, 0x79B3, 0xC5A2, 0x7C60, 0xC5A3, 0x7C5F, 0xC5A4, 0x807E, 0xC5A5, 0x807D, 0xC5A6, 0x81DF, 0xC5A7, 0x8972, 0xC5A8, 0x896F, 0xC5A9, 0x89FC, 0xC5AA, 0x8B80, 0xC5AB, 0x8D16, 0xC5AC, 0x8D17, 0xC5AD, 0x8E91, 0xC5AE, 0x8E93, 0xC5AF, 0x8F61, 0xC5B0, 0x9148, 0xC5B1, 0x9444, 0xC5B2, 0x9451, 0xC5B3, 0x9452, 0xC5B4, 0x973D, 0xC5B5, 0x973E, 0xC5B6, 0x97C3, 0xC5B7, 0x97C1, 0xC5B8, 0x986B, 0xC5B9, 0x9955, 0xC5BA, 0x9A55, 0xC5BB, 0x9A4D, 0xC5BC, 0x9AD2, 0xC5BD, 0x9B1A, 0xC5BE, 0x9C49, 0xC5BF, 0x9C31, 0xC5C0, 0x9C3E, 0xC5C1, 0x9C3B, 0xC5C2, 0x9DD3, 0xC5C3, 0x9DD7, 0xC5C4, 0x9F34, 0xC5C5, 0x9F6C, 0xC5C6, 0x9F6A, 0xC5C7, 0x9F94, 0xC5C8, 0x56CC, 0xC5C9, 0x5DD6, 0xC5CA, 0x6200, 0xC5CB, 0x6523, 0xC5CC, 0x652B, 0xC5CD, 0x652A, 0xC5CE, 0x66EC, 0xC5CF, 0x6B10, 0xC5D0, 0x74DA, 0xC5D1, 0x7ACA, 0xC5D2, 0x7C64, 0xC5D3, 0x7C63, 0xC5D4, 0x7C65, 0xC5D5, 0x7E93, 0xC5D6, 0x7E96, 0xC5D7, 0x7E94, 0xC5D8, 0x81E2, 0xC5D9, 0x8638, 0xC5DA, 0x863F, 0xC5DB, 0x8831, 0xC5DC, 0x8B8A, 0xC5DD, 0x9090, 0xC5DE, 0x908F, 0xC5DF, 0x9463, 0xC5E0, 0x9460, 0xC5E1, 0x9464, 0xC5E2, 0x9768, 0xC5E3, 0x986F, 0xC5E4, 0x995C, 0xC5E5, 0x9A5A, 0xC5E6, 0x9A5B, 0xC5E7, 0x9A57, 0xC5E8, 0x9AD3, 0xC5E9, 0x9AD4, 0xC5EA, 0x9AD1, 0xC5EB, 0x9C54, 0xC5EC, 0x9C57, 0xC5ED, 0x9C56, 0xC5EE, 0x9DE5, 0xC5EF, 0x9E9F, 0xC5F0, 0x9EF4, 0xC5F1, 0x56D1, 0xC5F2, 0x58E9, 0xC5F3, 0x652C, 0xC5F4, 0x705E, 0xC5F5, 0x7671, 0xC5F6, 0x7672, 0xC5F7, 0x77D7, 0xC5F8, 0x7F50, 0xC5F9, 0x7F88, 0xC5FA, 0x8836, 0xC5FB, 0x8839, 0xC5FC, 0x8862, 0xC5FD, 0x8B93, 0xC5FE, 0x8B92, 0xC640, 0x8B96, 0xC641, 0x8277, 0xC642, 0x8D1B, 0xC643, 0x91C0, 0xC644, 0x946A, 0xC645, 0x9742, 0xC646, 0x9748, 0xC647, 0x9744, 0xC648, 0x97C6, 0xC649, 0x9870, 0xC64A, 0x9A5F, 0xC64B, 0x9B22, 0xC64C, 0x9B58, 0xC64D, 0x9C5F, 0xC64E, 0x9DF9, 0xC64F, 0x9DFA, 0xC650, 0x9E7C, 0xC651, 0x9E7D, 0xC652, 0x9F07, 0xC653, 0x9F77, 0xC654, 0x9F72, 0xC655, 0x5EF3, 0xC656, 0x6B16, 0xC657, 0x7063, 0xC658, 0x7C6C, 0xC659, 0x7C6E, 0xC65A, 0x883B, 0xC65B, 0x89C0, 0xC65C, 0x8EA1, 0xC65D, 0x91C1, 0xC65E, 0x9472, 0xC65F, 0x9470, 0xC660, 0x9871, 0xC661, 0x995E, 0xC662, 0x9AD6, 0xC663, 0x9B23, 0xC664, 0x9ECC, 0xC665, 0x7064, 0xC666, 0x77DA, 0xC667, 0x8B9A, 0xC668, 0x9477, 0xC669, 0x97C9, 0xC66A, 0x9A62, 0xC66B, 0x9A65, 0xC66C, 0x7E9C, 0xC66D, 0x8B9C, 0xC66E, 0x8EAA, 0xC66F, 0x91C5, 0xC670, 0x947D, 0xC671, 0x947E, 0xC672, 0x947C, 0xC673, 0x9C77, 0xC674, 0x9C78, 0xC675, 0x9EF7, 0xC676, 0x8C54, 0xC677, 0x947F, 0xC678, 0x9E1A, 0xC679, 0x7228, 0xC67A, 0x9A6A, 0xC67B, 0x9B31, 0xC67C, 0x9E1B, 0xC67D, 0x9E1E, 0xC67E, 0x7C72, 0xC940, 0x4E42, 0xC941, 0x4E5C, 0xC942, 0x51F5, 0xC943, 0x531A, 0xC944, 0x5382, 0xC945, 0x4E07, 0xC946, 0x4E0C, 0xC947, 0x4E47, 0xC948, 0x4E8D, 0xC949, 0x56D7, 0xC94A, 0xFA0C, 0xC94B, 0x5C6E, 0xC94C, 0x5F73, 0xC94D, 0x4E0F, 0xC94E, 0x5187, 0xC94F, 0x4E0E, 0xC950, 0x4E2E, 0xC951, 0x4E93, 0xC952, 0x4EC2, 0xC953, 0x4EC9, 0xC954, 0x4EC8, 0xC955, 0x5198, 0xC956, 0x52FC, 0xC957, 0x536C, 0xC958, 0x53B9, 0xC959, 0x5720, 0xC95A, 0x5903, 0xC95B, 0x592C, 0xC95C, 0x5C10, 0xC95D, 0x5DFF, 0xC95E, 0x65E1, 0xC95F, 0x6BB3, 0xC960, 0x6BCC, 0xC961, 0x6C14, 0xC962, 0x723F, 0xC963, 0x4E31, 0xC964, 0x4E3C, 0xC965, 0x4EE8, 0xC966, 0x4EDC, 0xC967, 0x4EE9, 0xC968, 0x4EE1, 0xC969, 0x4EDD, 0xC96A, 0x4EDA, 0xC96B, 0x520C, 0xC96C, 0x531C, 0xC96D, 0x534C, 0xC96E, 0x5722, 0xC96F, 0x5723, 0xC970, 0x5917, 0xC971, 0x592F, 0xC972, 0x5B81, 0xC973, 0x5B84, 0xC974, 0x5C12, 0xC975, 0x5C3B, 0xC976, 0x5C74, 0xC977, 0x5C73, 0xC978, 0x5E04, 0xC979, 0x5E80, 0xC97A, 0x5E82, 0xC97B, 0x5FC9, 0xC97C, 0x6209, 0xC97D, 0x6250, 0xC97E, 0x6C15, 0xC9A1, 0x6C36, 0xC9A2, 0x6C43, 0xC9A3, 0x6C3F, 0xC9A4, 0x6C3B, 0xC9A5, 0x72AE, 0xC9A6, 0x72B0, 0xC9A7, 0x738A, 0xC9A8, 0x79B8, 0xC9A9, 0x808A, 0xC9AA, 0x961E, 0xC9AB, 0x4F0E, 0xC9AC, 0x4F18, 0xC9AD, 0x4F2C, 0xC9AE, 0x4EF5, 0xC9AF, 0x4F14, 0xC9B0, 0x4EF1, 0xC9B1, 0x4F00, 0xC9B2, 0x4EF7, 0xC9B3, 0x4F08, 0xC9B4, 0x4F1D, 0xC9B5, 0x4F02, 0xC9B6, 0x4F05, 0xC9B7, 0x4F22, 0xC9B8, 0x4F13, 0xC9B9, 0x4F04, 0xC9BA, 0x4EF4, 0xC9BB, 0x4F12, 0xC9BC, 0x51B1, 0xC9BD, 0x5213, 0xC9BE, 0x5209, 0xC9BF, 0x5210, 0xC9C0, 0x52A6, 0xC9C1, 0x5322, 0xC9C2, 0x531F, 0xC9C3, 0x534D, 0xC9C4, 0x538A, 0xC9C5, 0x5407, 0xC9C6, 0x56E1, 0xC9C7, 0x56DF, 0xC9C8, 0x572E, 0xC9C9, 0x572A, 0xC9CA, 0x5734, 0xC9CB, 0x593C, 0xC9CC, 0x5980, 0xC9CD, 0x597C, 0xC9CE, 0x5985, 0xC9CF, 0x597B, 0xC9D0, 0x597E, 0xC9D1, 0x5977, 0xC9D2, 0x597F, 0xC9D3, 0x5B56, 0xC9D4, 0x5C15, 0xC9D5, 0x5C25, 0xC9D6, 0x5C7C, 0xC9D7, 0x5C7A, 0xC9D8, 0x5C7B, 0xC9D9, 0x5C7E, 0xC9DA, 0x5DDF, 0xC9DB, 0x5E75, 0xC9DC, 0x5E84, 0xC9DD, 0x5F02, 0xC9DE, 0x5F1A, 0xC9DF, 0x5F74, 0xC9E0, 0x5FD5, 0xC9E1, 0x5FD4, 0xC9E2, 0x5FCF, 0xC9E3, 0x625C, 0xC9E4, 0x625E, 0xC9E5, 0x6264, 0xC9E6, 0x6261, 0xC9E7, 0x6266, 0xC9E8, 0x6262, 0xC9E9, 0x6259, 0xC9EA, 0x6260, 0xC9EB, 0x625A, 0xC9EC, 0x6265, 0xC9ED, 0x65EF, 0xC9EE, 0x65EE, 0xC9EF, 0x673E, 0xC9F0, 0x6739, 0xC9F1, 0x6738, 0xC9F2, 0x673B, 0xC9F3, 0x673A, 0xC9F4, 0x673F, 0xC9F5, 0x673C, 0xC9F6, 0x6733, 0xC9F7, 0x6C18, 0xC9F8, 0x6C46, 0xC9F9, 0x6C52, 0xC9FA, 0x6C5C, 0xC9FB, 0x6C4F, 0xC9FC, 0x6C4A, 0xC9FD, 0x6C54, 0xC9FE, 0x6C4B, 0xCA40, 0x6C4C, 0xCA41, 0x7071, 0xCA42, 0x725E, 0xCA43, 0x72B4, 0xCA44, 0x72B5, 0xCA45, 0x738E, 0xCA46, 0x752A, 0xCA47, 0x767F, 0xCA48, 0x7A75, 0xCA49, 0x7F51, 0xCA4A, 0x8278, 0xCA4B, 0x827C, 0xCA4C, 0x8280, 0xCA4D, 0x827D, 0xCA4E, 0x827F, 0xCA4F, 0x864D, 0xCA50, 0x897E, 0xCA51, 0x9099, 0xCA52, 0x9097, 0xCA53, 0x9098, 0xCA54, 0x909B, 0xCA55, 0x9094, 0xCA56, 0x9622, 0xCA57, 0x9624, 0xCA58, 0x9620, 0xCA59, 0x9623, 0xCA5A, 0x4F56, 0xCA5B, 0x4F3B, 0xCA5C, 0x4F62, 0xCA5D, 0x4F49, 0xCA5E, 0x4F53, 0xCA5F, 0x4F64, 0xCA60, 0x4F3E, 0xCA61, 0x4F67, 0xCA62, 0x4F52, 0xCA63, 0x4F5F, 0xCA64, 0x4F41, 0xCA65, 0x4F58, 0xCA66, 0x4F2D, 0xCA67, 0x4F33, 0xCA68, 0x4F3F, 0xCA69, 0x4F61, 0xCA6A, 0x518F, 0xCA6B, 0x51B9, 0xCA6C, 0x521C, 0xCA6D, 0x521E, 0xCA6E, 0x5221, 0xCA6F, 0x52AD, 0xCA70, 0x52AE, 0xCA71, 0x5309, 0xCA72, 0x5363, 0xCA73, 0x5372, 0xCA74, 0x538E, 0xCA75, 0x538F, 0xCA76, 0x5430, 0xCA77, 0x5437, 0xCA78, 0x542A, 0xCA79, 0x5454, 0xCA7A, 0x5445, 0xCA7B, 0x5419, 0xCA7C, 0x541C, 0xCA7D, 0x5425, 0xCA7E, 0x5418, 0xCAA1, 0x543D, 0xCAA2, 0x544F, 0xCAA3, 0x5441, 0xCAA4, 0x5428, 0xCAA5, 0x5424, 0xCAA6, 0x5447, 0xCAA7, 0x56EE, 0xCAA8, 0x56E7, 0xCAA9, 0x56E5, 0xCAAA, 0x5741, 0xCAAB, 0x5745, 0xCAAC, 0x574C, 0xCAAD, 0x5749, 0xCAAE, 0x574B, 0xCAAF, 0x5752, 0xCAB0, 0x5906, 0xCAB1, 0x5940, 0xCAB2, 0x59A6, 0xCAB3, 0x5998, 0xCAB4, 0x59A0, 0xCAB5, 0x5997, 0xCAB6, 0x598E, 0xCAB7, 0x59A2, 0xCAB8, 0x5990, 0xCAB9, 0x598F, 0xCABA, 0x59A7, 0xCABB, 0x59A1, 0xCABC, 0x5B8E, 0xCABD, 0x5B92, 0xCABE, 0x5C28, 0xCABF, 0x5C2A, 0xCAC0, 0x5C8D, 0xCAC1, 0x5C8F, 0xCAC2, 0x5C88, 0xCAC3, 0x5C8B, 0xCAC4, 0x5C89, 0xCAC5, 0x5C92, 0xCAC6, 0x5C8A, 0xCAC7, 0x5C86, 0xCAC8, 0x5C93, 0xCAC9, 0x5C95, 0xCACA, 0x5DE0, 0xCACB, 0x5E0A, 0xCACC, 0x5E0E, 0xCACD, 0x5E8B, 0xCACE, 0x5E89, 0xCACF, 0x5E8C, 0xCAD0, 0x5E88, 0xCAD1, 0x5E8D, 0xCAD2, 0x5F05, 0xCAD3, 0x5F1D, 0xCAD4, 0x5F78, 0xCAD5, 0x5F76, 0xCAD6, 0x5FD2, 0xCAD7, 0x5FD1, 0xCAD8, 0x5FD0, 0xCAD9, 0x5FED, 0xCADA, 0x5FE8, 0xCADB, 0x5FEE, 0xCADC, 0x5FF3, 0xCADD, 0x5FE1, 0xCADE, 0x5FE4, 0xCADF, 0x5FE3, 0xCAE0, 0x5FFA, 0xCAE1, 0x5FEF, 0xCAE2, 0x5FF7, 0xCAE3, 0x5FFB, 0xCAE4, 0x6000, 0xCAE5, 0x5FF4, 0xCAE6, 0x623A, 0xCAE7, 0x6283, 0xCAE8, 0x628C, 0xCAE9, 0x628E, 0xCAEA, 0x628F, 0xCAEB, 0x6294, 0xCAEC, 0x6287, 0xCAED, 0x6271, 0xCAEE, 0x627B, 0xCAEF, 0x627A, 0xCAF0, 0x6270, 0xCAF1, 0x6281, 0xCAF2, 0x6288, 0xCAF3, 0x6277, 0xCAF4, 0x627D, 0xCAF5, 0x6272, 0xCAF6, 0x6274, 0xCAF7, 0x6537, 0xCAF8, 0x65F0, 0xCAF9, 0x65F4, 0xCAFA, 0x65F3, 0xCAFB, 0x65F2, 0xCAFC, 0x65F5, 0xCAFD, 0x6745, 0xCAFE, 0x6747, 0xCB40, 0x6759, 0xCB41, 0x6755, 0xCB42, 0x674C, 0xCB43, 0x6748, 0xCB44, 0x675D, 0xCB45, 0x674D, 0xCB46, 0x675A, 0xCB47, 0x674B, 0xCB48, 0x6BD0, 0xCB49, 0x6C19, 0xCB4A, 0x6C1A, 0xCB4B, 0x6C78, 0xCB4C, 0x6C67, 0xCB4D, 0x6C6B, 0xCB4E, 0x6C84, 0xCB4F, 0x6C8B, 0xCB50, 0x6C8F, 0xCB51, 0x6C71, 0xCB52, 0x6C6F, 0xCB53, 0x6C69, 0xCB54, 0x6C9A, 0xCB55, 0x6C6D, 0xCB56, 0x6C87, 0xCB57, 0x6C95, 0xCB58, 0x6C9C, 0xCB59, 0x6C66, 0xCB5A, 0x6C73, 0xCB5B, 0x6C65, 0xCB5C, 0x6C7B, 0xCB5D, 0x6C8E, 0xCB5E, 0x7074, 0xCB5F, 0x707A, 0xCB60, 0x7263, 0xCB61, 0x72BF, 0xCB62, 0x72BD, 0xCB63, 0x72C3, 0xCB64, 0x72C6, 0xCB65, 0x72C1, 0xCB66, 0x72BA, 0xCB67, 0x72C5, 0xCB68, 0x7395, 0xCB69, 0x7397, 0xCB6A, 0x7393, 0xCB6B, 0x7394, 0xCB6C, 0x7392, 0xCB6D, 0x753A, 0xCB6E, 0x7539, 0xCB6F, 0x7594, 0xCB70, 0x7595, 0xCB71, 0x7681, 0xCB72, 0x793D, 0xCB73, 0x8034, 0xCB74, 0x8095, 0xCB75, 0x8099, 0xCB76, 0x8090, 0xCB77, 0x8092, 0xCB78, 0x809C, 0xCB79, 0x8290, 0xCB7A, 0x828F, 0xCB7B, 0x8285, 0xCB7C, 0x828E, 0xCB7D, 0x8291, 0xCB7E, 0x8293, 0xCBA1, 0x828A, 0xCBA2, 0x8283, 0xCBA3, 0x8284, 0xCBA4, 0x8C78, 0xCBA5, 0x8FC9, 0xCBA6, 0x8FBF, 0xCBA7, 0x909F, 0xCBA8, 0x90A1, 0xCBA9, 0x90A5, 0xCBAA, 0x909E, 0xCBAB, 0x90A7, 0xCBAC, 0x90A0, 0xCBAD, 0x9630, 0xCBAE, 0x9628, 0xCBAF, 0x962F, 0xCBB0, 0x962D, 0xCBB1, 0x4E33, 0xCBB2, 0x4F98, 0xCBB3, 0x4F7C, 0xCBB4, 0x4F85, 0xCBB5, 0x4F7D, 0xCBB6, 0x4F80, 0xCBB7, 0x4F87, 0xCBB8, 0x4F76, 0xCBB9, 0x4F74, 0xCBBA, 0x4F89, 0xCBBB, 0x4F84, 0xCBBC, 0x4F77, 0xCBBD, 0x4F4C, 0xCBBE, 0x4F97, 0xCBBF, 0x4F6A, 0xCBC0, 0x4F9A, 0xCBC1, 0x4F79, 0xCBC2, 0x4F81, 0xCBC3, 0x4F78, 0xCBC4, 0x4F90, 0xCBC5, 0x4F9C, 0xCBC6, 0x4F94, 0xCBC7, 0x4F9E, 0xCBC8, 0x4F92, 0xCBC9, 0x4F82, 0xCBCA, 0x4F95, 0xCBCB, 0x4F6B, 0xCBCC, 0x4F6E, 0xCBCD, 0x519E, 0xCBCE, 0x51BC, 0xCBCF, 0x51BE, 0xCBD0, 0x5235, 0xCBD1, 0x5232, 0xCBD2, 0x5233, 0xCBD3, 0x5246, 0xCBD4, 0x5231, 0xCBD5, 0x52BC, 0xCBD6, 0x530A, 0xCBD7, 0x530B, 0xCBD8, 0x533C, 0xCBD9, 0x5392, 0xCBDA, 0x5394, 0xCBDB, 0x5487, 0xCBDC, 0x547F, 0xCBDD, 0x5481, 0xCBDE, 0x5491, 0xCBDF, 0x5482, 0xCBE0, 0x5488, 0xCBE1, 0x546B, 0xCBE2, 0x547A, 0xCBE3, 0x547E, 0xCBE4, 0x5465, 0xCBE5, 0x546C, 0xCBE6, 0x5474, 0xCBE7, 0x5466, 0xCBE8, 0x548D, 0xCBE9, 0x546F, 0xCBEA, 0x5461, 0xCBEB, 0x5460, 0xCBEC, 0x5498, 0xCBED, 0x5463, 0xCBEE, 0x5467, 0xCBEF, 0x5464, 0xCBF0, 0x56F7, 0xCBF1, 0x56F9, 0xCBF2, 0x576F, 0xCBF3, 0x5772, 0xCBF4, 0x576D, 0xCBF5, 0x576B, 0xCBF6, 0x5771, 0xCBF7, 0x5770, 0xCBF8, 0x5776, 0xCBF9, 0x5780, 0xCBFA, 0x5775, 0xCBFB, 0x577B, 0xCBFC, 0x5773, 0xCBFD, 0x5774, 0xCBFE, 0x5762, 0xCC40, 0x5768, 0xCC41, 0x577D, 0xCC42, 0x590C, 0xCC43, 0x5945, 0xCC44, 0x59B5, 0xCC45, 0x59BA, 0xCC46, 0x59CF, 0xCC47, 0x59CE, 0xCC48, 0x59B2, 0xCC49, 0x59CC, 0xCC4A, 0x59C1, 0xCC4B, 0x59B6, 0xCC4C, 0x59BC, 0xCC4D, 0x59C3, 0xCC4E, 0x59D6, 0xCC4F, 0x59B1, 0xCC50, 0x59BD, 0xCC51, 0x59C0, 0xCC52, 0x59C8, 0xCC53, 0x59B4, 0xCC54, 0x59C7, 0xCC55, 0x5B62, 0xCC56, 0x5B65, 0xCC57, 0x5B93, 0xCC58, 0x5B95, 0xCC59, 0x5C44, 0xCC5A, 0x5C47, 0xCC5B, 0x5CAE, 0xCC5C, 0x5CA4, 0xCC5D, 0x5CA0, 0xCC5E, 0x5CB5, 0xCC5F, 0x5CAF, 0xCC60, 0x5CA8, 0xCC61, 0x5CAC, 0xCC62, 0x5C9F, 0xCC63, 0x5CA3, 0xCC64, 0x5CAD, 0xCC65, 0x5CA2, 0xCC66, 0x5CAA, 0xCC67, 0x5CA7, 0xCC68, 0x5C9D, 0xCC69, 0x5CA5, 0xCC6A, 0x5CB6, 0xCC6B, 0x5CB0, 0xCC6C, 0x5CA6, 0xCC6D, 0x5E17, 0xCC6E, 0x5E14, 0xCC6F, 0x5E19, 0xCC70, 0x5F28, 0xCC71, 0x5F22, 0xCC72, 0x5F23, 0xCC73, 0x5F24, 0xCC74, 0x5F54, 0xCC75, 0x5F82, 0xCC76, 0x5F7E, 0xCC77, 0x5F7D, 0xCC78, 0x5FDE, 0xCC79, 0x5FE5, 0xCC7A, 0x602D, 0xCC7B, 0x6026, 0xCC7C, 0x6019, 0xCC7D, 0x6032, 0xCC7E, 0x600B, 0xCCA1, 0x6034, 0xCCA2, 0x600A, 0xCCA3, 0x6017, 0xCCA4, 0x6033, 0xCCA5, 0x601A, 0xCCA6, 0x601E, 0xCCA7, 0x602C, 0xCCA8, 0x6022, 0xCCA9, 0x600D, 0xCCAA, 0x6010, 0xCCAB, 0x602E, 0xCCAC, 0x6013, 0xCCAD, 0x6011, 0xCCAE, 0x600C, 0xCCAF, 0x6009, 0xCCB0, 0x601C, 0xCCB1, 0x6214, 0xCCB2, 0x623D, 0xCCB3, 0x62AD, 0xCCB4, 0x62B4, 0xCCB5, 0x62D1, 0xCCB6, 0x62BE, 0xCCB7, 0x62AA, 0xCCB8, 0x62B6, 0xCCB9, 0x62CA, 0xCCBA, 0x62AE, 0xCCBB, 0x62B3, 0xCCBC, 0x62AF, 0xCCBD, 0x62BB, 0xCCBE, 0x62A9, 0xCCBF, 0x62B0, 0xCCC0, 0x62B8, 0xCCC1, 0x653D, 0xCCC2, 0x65A8, 0xCCC3, 0x65BB, 0xCCC4, 0x6609, 0xCCC5, 0x65FC, 0xCCC6, 0x6604, 0xCCC7, 0x6612, 0xCCC8, 0x6608, 0xCCC9, 0x65FB, 0xCCCA, 0x6603, 0xCCCB, 0x660B, 0xCCCC, 0x660D, 0xCCCD, 0x6605, 0xCCCE, 0x65FD, 0xCCCF, 0x6611, 0xCCD0, 0x6610, 0xCCD1, 0x66F6, 0xCCD2, 0x670A, 0xCCD3, 0x6785, 0xCCD4, 0x676C, 0xCCD5, 0x678E, 0xCCD6, 0x6792, 0xCCD7, 0x6776, 0xCCD8, 0x677B, 0xCCD9, 0x6798, 0xCCDA, 0x6786, 0xCCDB, 0x6784, 0xCCDC, 0x6774, 0xCCDD, 0x678D, 0xCCDE, 0x678C, 0xCCDF, 0x677A, 0xCCE0, 0x679F, 0xCCE1, 0x6791, 0xCCE2, 0x6799, 0xCCE3, 0x6783, 0xCCE4, 0x677D, 0xCCE5, 0x6781, 0xCCE6, 0x6778, 0xCCE7, 0x6779, 0xCCE8, 0x6794, 0xCCE9, 0x6B25, 0xCCEA, 0x6B80, 0xCCEB, 0x6B7E, 0xCCEC, 0x6BDE, 0xCCED, 0x6C1D, 0xCCEE, 0x6C93, 0xCCEF, 0x6CEC, 0xCCF0, 0x6CEB, 0xCCF1, 0x6CEE, 0xCCF2, 0x6CD9, 0xCCF3, 0x6CB6, 0xCCF4, 0x6CD4, 0xCCF5, 0x6CAD, 0xCCF6, 0x6CE7, 0xCCF7, 0x6CB7, 0xCCF8, 0x6CD0, 0xCCF9, 0x6CC2, 0xCCFA, 0x6CBA, 0xCCFB, 0x6CC3, 0xCCFC, 0x6CC6, 0xCCFD, 0x6CED, 0xCCFE, 0x6CF2, 0xCD40, 0x6CD2, 0xCD41, 0x6CDD, 0xCD42, 0x6CB4, 0xCD43, 0x6C8A, 0xCD44, 0x6C9D, 0xCD45, 0x6C80, 0xCD46, 0x6CDE, 0xCD47, 0x6CC0, 0xCD48, 0x6D30, 0xCD49, 0x6CCD, 0xCD4A, 0x6CC7, 0xCD4B, 0x6CB0, 0xCD4C, 0x6CF9, 0xCD4D, 0x6CCF, 0xCD4E, 0x6CE9, 0xCD4F, 0x6CD1, 0xCD50, 0x7094, 0xCD51, 0x7098, 0xCD52, 0x7085, 0xCD53, 0x7093, 0xCD54, 0x7086, 0xCD55, 0x7084, 0xCD56, 0x7091, 0xCD57, 0x7096, 0xCD58, 0x7082, 0xCD59, 0x709A, 0xCD5A, 0x7083, 0xCD5B, 0x726A, 0xCD5C, 0x72D6, 0xCD5D, 0x72CB, 0xCD5E, 0x72D8, 0xCD5F, 0x72C9, 0xCD60, 0x72DC, 0xCD61, 0x72D2, 0xCD62, 0x72D4, 0xCD63, 0x72DA, 0xCD64, 0x72CC, 0xCD65, 0x72D1, 0xCD66, 0x73A4, 0xCD67, 0x73A1, 0xCD68, 0x73AD, 0xCD69, 0x73A6, 0xCD6A, 0x73A2, 0xCD6B, 0x73A0, 0xCD6C, 0x73AC, 0xCD6D, 0x739D, 0xCD6E, 0x74DD, 0xCD6F, 0x74E8, 0xCD70, 0x753F, 0xCD71, 0x7540, 0xCD72, 0x753E, 0xCD73, 0x758C, 0xCD74, 0x7598, 0xCD75, 0x76AF, 0xCD76, 0x76F3, 0xCD77, 0x76F1, 0xCD78, 0x76F0, 0xCD79, 0x76F5, 0xCD7A, 0x77F8, 0xCD7B, 0x77FC, 0xCD7C, 0x77F9, 0xCD7D, 0x77FB, 0xCD7E, 0x77FA, 0xCDA1, 0x77F7, 0xCDA2, 0x7942, 0xCDA3, 0x793F, 0xCDA4, 0x79C5, 0xCDA5, 0x7A78, 0xCDA6, 0x7A7B, 0xCDA7, 0x7AFB, 0xCDA8, 0x7C75, 0xCDA9, 0x7CFD, 0xCDAA, 0x8035, 0xCDAB, 0x808F, 0xCDAC, 0x80AE, 0xCDAD, 0x80A3, 0xCDAE, 0x80B8, 0xCDAF, 0x80B5, 0xCDB0, 0x80AD, 0xCDB1, 0x8220, 0xCDB2, 0x82A0, 0xCDB3, 0x82C0, 0xCDB4, 0x82AB, 0xCDB5, 0x829A, 0xCDB6, 0x8298, 0xCDB7, 0x829B, 0xCDB8, 0x82B5, 0xCDB9, 0x82A7, 0xCDBA, 0x82AE, 0xCDBB, 0x82BC, 0xCDBC, 0x829E, 0xCDBD, 0x82BA, 0xCDBE, 0x82B4, 0xCDBF, 0x82A8, 0xCDC0, 0x82A1, 0xCDC1, 0x82A9, 0xCDC2, 0x82C2, 0xCDC3, 0x82A4, 0xCDC4, 0x82C3, 0xCDC5, 0x82B6, 0xCDC6, 0x82A2, 0xCDC7, 0x8670, 0xCDC8, 0x866F, 0xCDC9, 0x866D, 0xCDCA, 0x866E, 0xCDCB, 0x8C56, 0xCDCC, 0x8FD2, 0xCDCD, 0x8FCB, 0xCDCE, 0x8FD3, 0xCDCF, 0x8FCD, 0xCDD0, 0x8FD6, 0xCDD1, 0x8FD5, 0xCDD2, 0x8FD7, 0xCDD3, 0x90B2, 0xCDD4, 0x90B4, 0xCDD5, 0x90AF, 0xCDD6, 0x90B3, 0xCDD7, 0x90B0, 0xCDD8, 0x9639, 0xCDD9, 0x963D, 0xCDDA, 0x963C, 0xCDDB, 0x963A, 0xCDDC, 0x9643, 0xCDDD, 0x4FCD, 0xCDDE, 0x4FC5, 0xCDDF, 0x4FD3, 0xCDE0, 0x4FB2, 0xCDE1, 0x4FC9, 0xCDE2, 0x4FCB, 0xCDE3, 0x4FC1, 0xCDE4, 0x4FD4, 0xCDE5, 0x4FDC, 0xCDE6, 0x4FD9, 0xCDE7, 0x4FBB, 0xCDE8, 0x4FB3, 0xCDE9, 0x4FDB, 0xCDEA, 0x4FC7, 0xCDEB, 0x4FD6, 0xCDEC, 0x4FBA, 0xCDED, 0x4FC0, 0xCDEE, 0x4FB9, 0xCDEF, 0x4FEC, 0xCDF0, 0x5244, 0xCDF1, 0x5249, 0xCDF2, 0x52C0, 0xCDF3, 0x52C2, 0xCDF4, 0x533D, 0xCDF5, 0x537C, 0xCDF6, 0x5397, 0xCDF7, 0x5396, 0xCDF8, 0x5399, 0xCDF9, 0x5398, 0xCDFA, 0x54BA, 0xCDFB, 0x54A1, 0xCDFC, 0x54AD, 0xCDFD, 0x54A5, 0xCDFE, 0x54CF, 0xCE40, 0x54C3, 0xCE41, 0x830D, 0xCE42, 0x54B7, 0xCE43, 0x54AE, 0xCE44, 0x54D6, 0xCE45, 0x54B6, 0xCE46, 0x54C5, 0xCE47, 0x54C6, 0xCE48, 0x54A0, 0xCE49, 0x5470, 0xCE4A, 0x54BC, 0xCE4B, 0x54A2, 0xCE4C, 0x54BE, 0xCE4D, 0x5472, 0xCE4E, 0x54DE, 0xCE4F, 0x54B0, 0xCE50, 0x57B5, 0xCE51, 0x579E, 0xCE52, 0x579F, 0xCE53, 0x57A4, 0xCE54, 0x578C, 0xCE55, 0x5797, 0xCE56, 0x579D, 0xCE57, 0x579B, 0xCE58, 0x5794, 0xCE59, 0x5798, 0xCE5A, 0x578F, 0xCE5B, 0x5799, 0xCE5C, 0x57A5, 0xCE5D, 0x579A, 0xCE5E, 0x5795, 0xCE5F, 0x58F4, 0xCE60, 0x590D, 0xCE61, 0x5953, 0xCE62, 0x59E1, 0xCE63, 0x59DE, 0xCE64, 0x59EE, 0xCE65, 0x5A00, 0xCE66, 0x59F1, 0xCE67, 0x59DD, 0xCE68, 0x59FA, 0xCE69, 0x59FD, 0xCE6A, 0x59FC, 0xCE6B, 0x59F6, 0xCE6C, 0x59E4, 0xCE6D, 0x59F2, 0xCE6E, 0x59F7, 0xCE6F, 0x59DB, 0xCE70, 0x59E9, 0xCE71, 0x59F3, 0xCE72, 0x59F5, 0xCE73, 0x59E0, 0xCE74, 0x59FE, 0xCE75, 0x59F4, 0xCE76, 0x59ED, 0xCE77, 0x5BA8, 0xCE78, 0x5C4C, 0xCE79, 0x5CD0, 0xCE7A, 0x5CD8, 0xCE7B, 0x5CCC, 0xCE7C, 0x5CD7, 0xCE7D, 0x5CCB, 0xCE7E, 0x5CDB, 0xCEA1, 0x5CDE, 0xCEA2, 0x5CDA, 0xCEA3, 0x5CC9, 0xCEA4, 0x5CC7, 0xCEA5, 0x5CCA, 0xCEA6, 0x5CD6, 0xCEA7, 0x5CD3, 0xCEA8, 0x5CD4, 0xCEA9, 0x5CCF, 0xCEAA, 0x5CC8, 0xCEAB, 0x5CC6, 0xCEAC, 0x5CCE, 0xCEAD, 0x5CDF, 0xCEAE, 0x5CF8, 0xCEAF, 0x5DF9, 0xCEB0, 0x5E21, 0xCEB1, 0x5E22, 0xCEB2, 0x5E23, 0xCEB3, 0x5E20, 0xCEB4, 0x5E24, 0xCEB5, 0x5EB0, 0xCEB6, 0x5EA4, 0xCEB7, 0x5EA2, 0xCEB8, 0x5E9B, 0xCEB9, 0x5EA3, 0xCEBA, 0x5EA5, 0xCEBB, 0x5F07, 0xCEBC, 0x5F2E, 0xCEBD, 0x5F56, 0xCEBE, 0x5F86, 0xCEBF, 0x6037, 0xCEC0, 0x6039, 0xCEC1, 0x6054, 0xCEC2, 0x6072, 0xCEC3, 0x605E, 0xCEC4, 0x6045, 0xCEC5, 0x6053, 0xCEC6, 0x6047, 0xCEC7, 0x6049, 0xCEC8, 0x605B, 0xCEC9, 0x604C, 0xCECA, 0x6040, 0xCECB, 0x6042, 0xCECC, 0x605F, 0xCECD, 0x6024, 0xCECE, 0x6044, 0xCECF, 0x6058, 0xCED0, 0x6066, 0xCED1, 0x606E, 0xCED2, 0x6242, 0xCED3, 0x6243, 0xCED4, 0x62CF, 0xCED5, 0x630D, 0xCED6, 0x630B, 0xCED7, 0x62F5, 0xCED8, 0x630E, 0xCED9, 0x6303, 0xCEDA, 0x62EB, 0xCEDB, 0x62F9, 0xCEDC, 0x630F, 0xCEDD, 0x630C, 0xCEDE, 0x62F8, 0xCEDF, 0x62F6, 0xCEE0, 0x6300, 0xCEE1, 0x6313, 0xCEE2, 0x6314, 0xCEE3, 0x62FA, 0xCEE4, 0x6315, 0xCEE5, 0x62FB, 0xCEE6, 0x62F0, 0xCEE7, 0x6541, 0xCEE8, 0x6543, 0xCEE9, 0x65AA, 0xCEEA, 0x65BF, 0xCEEB, 0x6636, 0xCEEC, 0x6621, 0xCEED, 0x6632, 0xCEEE, 0x6635, 0xCEEF, 0x661C, 0xCEF0, 0x6626, 0xCEF1, 0x6622, 0xCEF2, 0x6633, 0xCEF3, 0x662B, 0xCEF4, 0x663A, 0xCEF5, 0x661D, 0xCEF6, 0x6634, 0xCEF7, 0x6639, 0xCEF8, 0x662E, 0xCEF9, 0x670F, 0xCEFA, 0x6710, 0xCEFB, 0x67C1, 0xCEFC, 0x67F2, 0xCEFD, 0x67C8, 0xCEFE, 0x67BA, 0xCF40, 0x67DC, 0xCF41, 0x67BB, 0xCF42, 0x67F8, 0xCF43, 0x67D8, 0xCF44, 0x67C0, 0xCF45, 0x67B7, 0xCF46, 0x67C5, 0xCF47, 0x67EB, 0xCF48, 0x67E4, 0xCF49, 0x67DF, 0xCF4A, 0x67B5, 0xCF4B, 0x67CD, 0xCF4C, 0x67B3, 0xCF4D, 0x67F7, 0xCF4E, 0x67F6, 0xCF4F, 0x67EE, 0xCF50, 0x67E3, 0xCF51, 0x67C2, 0xCF52, 0x67B9, 0xCF53, 0x67CE, 0xCF54, 0x67E7, 0xCF55, 0x67F0, 0xCF56, 0x67B2, 0xCF57, 0x67FC, 0xCF58, 0x67C6, 0xCF59, 0x67ED, 0xCF5A, 0x67CC, 0xCF5B, 0x67AE, 0xCF5C, 0x67E6, 0xCF5D, 0x67DB, 0xCF5E, 0x67FA, 0xCF5F, 0x67C9, 0xCF60, 0x67CA, 0xCF61, 0x67C3, 0xCF62, 0x67EA, 0xCF63, 0x67CB, 0xCF64, 0x6B28, 0xCF65, 0x6B82, 0xCF66, 0x6B84, 0xCF67, 0x6BB6, 0xCF68, 0x6BD6, 0xCF69, 0x6BD8, 0xCF6A, 0x6BE0, 0xCF6B, 0x6C20, 0xCF6C, 0x6C21, 0xCF6D, 0x6D28, 0xCF6E, 0x6D34, 0xCF6F, 0x6D2D, 0xCF70, 0x6D1F, 0xCF71, 0x6D3C, 0xCF72, 0x6D3F, 0xCF73, 0x6D12, 0xCF74, 0x6D0A, 0xCF75, 0x6CDA, 0xCF76, 0x6D33, 0xCF77, 0x6D04, 0xCF78, 0x6D19, 0xCF79, 0x6D3A, 0xCF7A, 0x6D1A, 0xCF7B, 0x6D11, 0xCF7C, 0x6D00, 0xCF7D, 0x6D1D, 0xCF7E, 0x6D42, 0xCFA1, 0x6D01, 0xCFA2, 0x6D18, 0xCFA3, 0x6D37, 0xCFA4, 0x6D03, 0xCFA5, 0x6D0F, 0xCFA6, 0x6D40, 0xCFA7, 0x6D07, 0xCFA8, 0x6D20, 0xCFA9, 0x6D2C, 0xCFAA, 0x6D08, 0xCFAB, 0x6D22, 0xCFAC, 0x6D09, 0xCFAD, 0x6D10, 0xCFAE, 0x70B7, 0xCFAF, 0x709F, 0xCFB0, 0x70BE, 0xCFB1, 0x70B1, 0xCFB2, 0x70B0, 0xCFB3, 0x70A1, 0xCFB4, 0x70B4, 0xCFB5, 0x70B5, 0xCFB6, 0x70A9, 0xCFB7, 0x7241, 0xCFB8, 0x7249, 0xCFB9, 0x724A, 0xCFBA, 0x726C, 0xCFBB, 0x7270, 0xCFBC, 0x7273, 0xCFBD, 0x726E, 0xCFBE, 0x72CA, 0xCFBF, 0x72E4, 0xCFC0, 0x72E8, 0xCFC1, 0x72EB, 0xCFC2, 0x72DF, 0xCFC3, 0x72EA, 0xCFC4, 0x72E6, 0xCFC5, 0x72E3, 0xCFC6, 0x7385, 0xCFC7, 0x73CC, 0xCFC8, 0x73C2, 0xCFC9, 0x73C8, 0xCFCA, 0x73C5, 0xCFCB, 0x73B9, 0xCFCC, 0x73B6, 0xCFCD, 0x73B5, 0xCFCE, 0x73B4, 0xCFCF, 0x73EB, 0xCFD0, 0x73BF, 0xCFD1, 0x73C7, 0xCFD2, 0x73BE, 0xCFD3, 0x73C3, 0xCFD4, 0x73C6, 0xCFD5, 0x73B8, 0xCFD6, 0x73CB, 0xCFD7, 0x74EC, 0xCFD8, 0x74EE, 0xCFD9, 0x752E, 0xCFDA, 0x7547, 0xCFDB, 0x7548, 0xCFDC, 0x75A7, 0xCFDD, 0x75AA, 0xCFDE, 0x7679, 0xCFDF, 0x76C4, 0xCFE0, 0x7708, 0xCFE1, 0x7703, 0xCFE2, 0x7704, 0xCFE3, 0x7705, 0xCFE4, 0x770A, 0xCFE5, 0x76F7, 0xCFE6, 0x76FB, 0xCFE7, 0x76FA, 0xCFE8, 0x77E7, 0xCFE9, 0x77E8, 0xCFEA, 0x7806, 0xCFEB, 0x7811, 0xCFEC, 0x7812, 0xCFED, 0x7805, 0xCFEE, 0x7810, 0xCFEF, 0x780F, 0xCFF0, 0x780E, 0xCFF1, 0x7809, 0xCFF2, 0x7803, 0xCFF3, 0x7813, 0xCFF4, 0x794A, 0xCFF5, 0x794C, 0xCFF6, 0x794B, 0xCFF7, 0x7945, 0xCFF8, 0x7944, 0xCFF9, 0x79D5, 0xCFFA, 0x79CD, 0xCFFB, 0x79CF, 0xCFFC, 0x79D6, 0xCFFD, 0x79CE, 0xCFFE, 0x7A80, 0xD040, 0x7A7E, 0xD041, 0x7AD1, 0xD042, 0x7B00, 0xD043, 0x7B01, 0xD044, 0x7C7A, 0xD045, 0x7C78, 0xD046, 0x7C79, 0xD047, 0x7C7F, 0xD048, 0x7C80, 0xD049, 0x7C81, 0xD04A, 0x7D03, 0xD04B, 0x7D08, 0xD04C, 0x7D01, 0xD04D, 0x7F58, 0xD04E, 0x7F91, 0xD04F, 0x7F8D, 0xD050, 0x7FBE, 0xD051, 0x8007, 0xD052, 0x800E, 0xD053, 0x800F, 0xD054, 0x8014, 0xD055, 0x8037, 0xD056, 0x80D8, 0xD057, 0x80C7, 0xD058, 0x80E0, 0xD059, 0x80D1, 0xD05A, 0x80C8, 0xD05B, 0x80C2, 0xD05C, 0x80D0, 0xD05D, 0x80C5, 0xD05E, 0x80E3, 0xD05F, 0x80D9, 0xD060, 0x80DC, 0xD061, 0x80CA, 0xD062, 0x80D5, 0xD063, 0x80C9, 0xD064, 0x80CF, 0xD065, 0x80D7, 0xD066, 0x80E6, 0xD067, 0x80CD, 0xD068, 0x81FF, 0xD069, 0x8221, 0xD06A, 0x8294, 0xD06B, 0x82D9, 0xD06C, 0x82FE, 0xD06D, 0x82F9, 0xD06E, 0x8307, 0xD06F, 0x82E8, 0xD070, 0x8300, 0xD071, 0x82D5, 0xD072, 0x833A, 0xD073, 0x82EB, 0xD074, 0x82D6, 0xD075, 0x82F4, 0xD076, 0x82EC, 0xD077, 0x82E1, 0xD078, 0x82F2, 0xD079, 0x82F5, 0xD07A, 0x830C, 0xD07B, 0x82FB, 0xD07C, 0x82F6, 0xD07D, 0x82F0, 0xD07E, 0x82EA, 0xD0A1, 0x82E4, 0xD0A2, 0x82E0, 0xD0A3, 0x82FA, 0xD0A4, 0x82F3, 0xD0A5, 0x82ED, 0xD0A6, 0x8677, 0xD0A7, 0x8674, 0xD0A8, 0x867C, 0xD0A9, 0x8673, 0xD0AA, 0x8841, 0xD0AB, 0x884E, 0xD0AC, 0x8867, 0xD0AD, 0x886A, 0xD0AE, 0x8869, 0xD0AF, 0x89D3, 0xD0B0, 0x8A04, 0xD0B1, 0x8A07, 0xD0B2, 0x8D72, 0xD0B3, 0x8FE3, 0xD0B4, 0x8FE1, 0xD0B5, 0x8FEE, 0xD0B6, 0x8FE0, 0xD0B7, 0x90F1, 0xD0B8, 0x90BD, 0xD0B9, 0x90BF, 0xD0BA, 0x90D5, 0xD0BB, 0x90C5, 0xD0BC, 0x90BE, 0xD0BD, 0x90C7, 0xD0BE, 0x90CB, 0xD0BF, 0x90C8, 0xD0C0, 0x91D4, 0xD0C1, 0x91D3, 0xD0C2, 0x9654, 0xD0C3, 0x964F, 0xD0C4, 0x9651, 0xD0C5, 0x9653, 0xD0C6, 0x964A, 0xD0C7, 0x964E, 0xD0C8, 0x501E, 0xD0C9, 0x5005, 0xD0CA, 0x5007, 0xD0CB, 0x5013, 0xD0CC, 0x5022, 0xD0CD, 0x5030, 0xD0CE, 0x501B, 0xD0CF, 0x4FF5, 0xD0D0, 0x4FF4, 0xD0D1, 0x5033, 0xD0D2, 0x5037, 0xD0D3, 0x502C, 0xD0D4, 0x4FF6, 0xD0D5, 0x4FF7, 0xD0D6, 0x5017, 0xD0D7, 0x501C, 0xD0D8, 0x5020, 0xD0D9, 0x5027, 0xD0DA, 0x5035, 0xD0DB, 0x502F, 0xD0DC, 0x5031, 0xD0DD, 0x500E, 0xD0DE, 0x515A, 0xD0DF, 0x5194, 0xD0E0, 0x5193, 0xD0E1, 0x51CA, 0xD0E2, 0x51C4, 0xD0E3, 0x51C5, 0xD0E4, 0x51C8, 0xD0E5, 0x51CE, 0xD0E6, 0x5261, 0xD0E7, 0x525A, 0xD0E8, 0x5252, 0xD0E9, 0x525E, 0xD0EA, 0x525F, 0xD0EB, 0x5255, 0xD0EC, 0x5262, 0xD0ED, 0x52CD, 0xD0EE, 0x530E, 0xD0EF, 0x539E, 0xD0F0, 0x5526, 0xD0F1, 0x54E2, 0xD0F2, 0x5517, 0xD0F3, 0x5512, 0xD0F4, 0x54E7, 0xD0F5, 0x54F3, 0xD0F6, 0x54E4, 0xD0F7, 0x551A, 0xD0F8, 0x54FF, 0xD0F9, 0x5504, 0xD0FA, 0x5508, 0xD0FB, 0x54EB, 0xD0FC, 0x5511, 0xD0FD, 0x5505, 0xD0FE, 0x54F1, 0xD140, 0x550A, 0xD141, 0x54FB, 0xD142, 0x54F7, 0xD143, 0x54F8, 0xD144, 0x54E0, 0xD145, 0x550E, 0xD146, 0x5503, 0xD147, 0x550B, 0xD148, 0x5701, 0xD149, 0x5702, 0xD14A, 0x57CC, 0xD14B, 0x5832, 0xD14C, 0x57D5, 0xD14D, 0x57D2, 0xD14E, 0x57BA, 0xD14F, 0x57C6, 0xD150, 0x57BD, 0xD151, 0x57BC, 0xD152, 0x57B8, 0xD153, 0x57B6, 0xD154, 0x57BF, 0xD155, 0x57C7, 0xD156, 0x57D0, 0xD157, 0x57B9, 0xD158, 0x57C1, 0xD159, 0x590E, 0xD15A, 0x594A, 0xD15B, 0x5A19, 0xD15C, 0x5A16, 0xD15D, 0x5A2D, 0xD15E, 0x5A2E, 0xD15F, 0x5A15, 0xD160, 0x5A0F, 0xD161, 0x5A17, 0xD162, 0x5A0A, 0xD163, 0x5A1E, 0xD164, 0x5A33, 0xD165, 0x5B6C, 0xD166, 0x5BA7, 0xD167, 0x5BAD, 0xD168, 0x5BAC, 0xD169, 0x5C03, 0xD16A, 0x5C56, 0xD16B, 0x5C54, 0xD16C, 0x5CEC, 0xD16D, 0x5CFF, 0xD16E, 0x5CEE, 0xD16F, 0x5CF1, 0xD170, 0x5CF7, 0xD171, 0x5D00, 0xD172, 0x5CF9, 0xD173, 0x5E29, 0xD174, 0x5E28, 0xD175, 0x5EA8, 0xD176, 0x5EAE, 0xD177, 0x5EAA, 0xD178, 0x5EAC, 0xD179, 0x5F33, 0xD17A, 0x5F30, 0xD17B, 0x5F67, 0xD17C, 0x605D, 0xD17D, 0x605A, 0xD17E, 0x6067, 0xD1A1, 0x6041, 0xD1A2, 0x60A2, 0xD1A3, 0x6088, 0xD1A4, 0x6080, 0xD1A5, 0x6092, 0xD1A6, 0x6081, 0xD1A7, 0x609D, 0xD1A8, 0x6083, 0xD1A9, 0x6095, 0xD1AA, 0x609B, 0xD1AB, 0x6097, 0xD1AC, 0x6087, 0xD1AD, 0x609C, 0xD1AE, 0x608E, 0xD1AF, 0x6219, 0xD1B0, 0x6246, 0xD1B1, 0x62F2, 0xD1B2, 0x6310, 0xD1B3, 0x6356, 0xD1B4, 0x632C, 0xD1B5, 0x6344, 0xD1B6, 0x6345, 0xD1B7, 0x6336, 0xD1B8, 0x6343, 0xD1B9, 0x63E4, 0xD1BA, 0x6339, 0xD1BB, 0x634B, 0xD1BC, 0x634A, 0xD1BD, 0x633C, 0xD1BE, 0x6329, 0xD1BF, 0x6341, 0xD1C0, 0x6334, 0xD1C1, 0x6358, 0xD1C2, 0x6354, 0xD1C3, 0x6359, 0xD1C4, 0x632D, 0xD1C5, 0x6347, 0xD1C6, 0x6333, 0xD1C7, 0x635A, 0xD1C8, 0x6351, 0xD1C9, 0x6338, 0xD1CA, 0x6357, 0xD1CB, 0x6340, 0xD1CC, 0x6348, 0xD1CD, 0x654A, 0xD1CE, 0x6546, 0xD1CF, 0x65C6, 0xD1D0, 0x65C3, 0xD1D1, 0x65C4, 0xD1D2, 0x65C2, 0xD1D3, 0x664A, 0xD1D4, 0x665F, 0xD1D5, 0x6647, 0xD1D6, 0x6651, 0xD1D7, 0x6712, 0xD1D8, 0x6713, 0xD1D9, 0x681F, 0xD1DA, 0x681A, 0xD1DB, 0x6849, 0xD1DC, 0x6832, 0xD1DD, 0x6833, 0xD1DE, 0x683B, 0xD1DF, 0x684B, 0xD1E0, 0x684F, 0xD1E1, 0x6816, 0xD1E2, 0x6831, 0xD1E3, 0x681C, 0xD1E4, 0x6835, 0xD1E5, 0x682B, 0xD1E6, 0x682D, 0xD1E7, 0x682F, 0xD1E8, 0x684E, 0xD1E9, 0x6844, 0xD1EA, 0x6834, 0xD1EB, 0x681D, 0xD1EC, 0x6812, 0xD1ED, 0x6814, 0xD1EE, 0x6826, 0xD1EF, 0x6828, 0xD1F0, 0x682E, 0xD1F1, 0x684D, 0xD1F2, 0x683A, 0xD1F3, 0x6825, 0xD1F4, 0x6820, 0xD1F5, 0x6B2C, 0xD1F6, 0x6B2F, 0xD1F7, 0x6B2D, 0xD1F8, 0x6B31, 0xD1F9, 0x6B34, 0xD1FA, 0x6B6D, 0xD1FB, 0x8082, 0xD1FC, 0x6B88, 0xD1FD, 0x6BE6, 0xD1FE, 0x6BE4, 0xD240, 0x6BE8, 0xD241, 0x6BE3, 0xD242, 0x6BE2, 0xD243, 0x6BE7, 0xD244, 0x6C25, 0xD245, 0x6D7A, 0xD246, 0x6D63, 0xD247, 0x6D64, 0xD248, 0x6D76, 0xD249, 0x6D0D, 0xD24A, 0x6D61, 0xD24B, 0x6D92, 0xD24C, 0x6D58, 0xD24D, 0x6D62, 0xD24E, 0x6D6D, 0xD24F, 0x6D6F, 0xD250, 0x6D91, 0xD251, 0x6D8D, 0xD252, 0x6DEF, 0xD253, 0x6D7F, 0xD254, 0x6D86, 0xD255, 0x6D5E, 0xD256, 0x6D67, 0xD257, 0x6D60, 0xD258, 0x6D97, 0xD259, 0x6D70, 0xD25A, 0x6D7C, 0xD25B, 0x6D5F, 0xD25C, 0x6D82, 0xD25D, 0x6D98, 0xD25E, 0x6D2F, 0xD25F, 0x6D68, 0xD260, 0x6D8B, 0xD261, 0x6D7E, 0xD262, 0x6D80, 0xD263, 0x6D84, 0xD264, 0x6D16, 0xD265, 0x6D83, 0xD266, 0x6D7B, 0xD267, 0x6D7D, 0xD268, 0x6D75, 0xD269, 0x6D90, 0xD26A, 0x70DC, 0xD26B, 0x70D3, 0xD26C, 0x70D1, 0xD26D, 0x70DD, 0xD26E, 0x70CB, 0xD26F, 0x7F39, 0xD270, 0x70E2, 0xD271, 0x70D7, 0xD272, 0x70D2, 0xD273, 0x70DE, 0xD274, 0x70E0, 0xD275, 0x70D4, 0xD276, 0x70CD, 0xD277, 0x70C5, 0xD278, 0x70C6, 0xD279, 0x70C7, 0xD27A, 0x70DA, 0xD27B, 0x70CE, 0xD27C, 0x70E1, 0xD27D, 0x7242, 0xD27E, 0x7278, 0xD2A1, 0x7277, 0xD2A2, 0x7276, 0xD2A3, 0x7300, 0xD2A4, 0x72FA, 0xD2A5, 0x72F4, 0xD2A6, 0x72FE, 0xD2A7, 0x72F6, 0xD2A8, 0x72F3, 0xD2A9, 0x72FB, 0xD2AA, 0x7301, 0xD2AB, 0x73D3, 0xD2AC, 0x73D9, 0xD2AD, 0x73E5, 0xD2AE, 0x73D6, 0xD2AF, 0x73BC, 0xD2B0, 0x73E7, 0xD2B1, 0x73E3, 0xD2B2, 0x73E9, 0xD2B3, 0x73DC, 0xD2B4, 0x73D2, 0xD2B5, 0x73DB, 0xD2B6, 0x73D4, 0xD2B7, 0x73DD, 0xD2B8, 0x73DA, 0xD2B9, 0x73D7, 0xD2BA, 0x73D8, 0xD2BB, 0x73E8, 0xD2BC, 0x74DE, 0xD2BD, 0x74DF, 0xD2BE, 0x74F4, 0xD2BF, 0x74F5, 0xD2C0, 0x7521, 0xD2C1, 0x755B, 0xD2C2, 0x755F, 0xD2C3, 0x75B0, 0xD2C4, 0x75C1, 0xD2C5, 0x75BB, 0xD2C6, 0x75C4, 0xD2C7, 0x75C0, 0xD2C8, 0x75BF, 0xD2C9, 0x75B6, 0xD2CA, 0x75BA, 0xD2CB, 0x768A, 0xD2CC, 0x76C9, 0xD2CD, 0x771D, 0xD2CE, 0x771B, 0xD2CF, 0x7710, 0xD2D0, 0x7713, 0xD2D1, 0x7712, 0xD2D2, 0x7723, 0xD2D3, 0x7711, 0xD2D4, 0x7715, 0xD2D5, 0x7719, 0xD2D6, 0x771A, 0xD2D7, 0x7722, 0xD2D8, 0x7727, 0xD2D9, 0x7823, 0xD2DA, 0x782C, 0xD2DB, 0x7822, 0xD2DC, 0x7835, 0xD2DD, 0x782F, 0xD2DE, 0x7828, 0xD2DF, 0x782E, 0xD2E0, 0x782B, 0xD2E1, 0x7821, 0xD2E2, 0x7829, 0xD2E3, 0x7833, 0xD2E4, 0x782A, 0xD2E5, 0x7831, 0xD2E6, 0x7954, 0xD2E7, 0x795B, 0xD2E8, 0x794F, 0xD2E9, 0x795C, 0xD2EA, 0x7953, 0xD2EB, 0x7952, 0xD2EC, 0x7951, 0xD2ED, 0x79EB, 0xD2EE, 0x79EC, 0xD2EF, 0x79E0, 0xD2F0, 0x79EE, 0xD2F1, 0x79ED, 0xD2F2, 0x79EA, 0xD2F3, 0x79DC, 0xD2F4, 0x79DE, 0xD2F5, 0x79DD, 0xD2F6, 0x7A86, 0xD2F7, 0x7A89, 0xD2F8, 0x7A85, 0xD2F9, 0x7A8B, 0xD2FA, 0x7A8C, 0xD2FB, 0x7A8A, 0xD2FC, 0x7A87, 0xD2FD, 0x7AD8, 0xD2FE, 0x7B10, 0xD340, 0x7B04, 0xD341, 0x7B13, 0xD342, 0x7B05, 0xD343, 0x7B0F, 0xD344, 0x7B08, 0xD345, 0x7B0A, 0xD346, 0x7B0E, 0xD347, 0x7B09, 0xD348, 0x7B12, 0xD349, 0x7C84, 0xD34A, 0x7C91, 0xD34B, 0x7C8A, 0xD34C, 0x7C8C, 0xD34D, 0x7C88, 0xD34E, 0x7C8D, 0xD34F, 0x7C85, 0xD350, 0x7D1E, 0xD351, 0x7D1D, 0xD352, 0x7D11, 0xD353, 0x7D0E, 0xD354, 0x7D18, 0xD355, 0x7D16, 0xD356, 0x7D13, 0xD357, 0x7D1F, 0xD358, 0x7D12, 0xD359, 0x7D0F, 0xD35A, 0x7D0C, 0xD35B, 0x7F5C, 0xD35C, 0x7F61, 0xD35D, 0x7F5E, 0xD35E, 0x7F60, 0xD35F, 0x7F5D, 0xD360, 0x7F5B, 0xD361, 0x7F96, 0xD362, 0x7F92, 0xD363, 0x7FC3, 0xD364, 0x7FC2, 0xD365, 0x7FC0, 0xD366, 0x8016, 0xD367, 0x803E, 0xD368, 0x8039, 0xD369, 0x80FA, 0xD36A, 0x80F2, 0xD36B, 0x80F9, 0xD36C, 0x80F5, 0xD36D, 0x8101, 0xD36E, 0x80FB, 0xD36F, 0x8100, 0xD370, 0x8201, 0xD371, 0x822F, 0xD372, 0x8225, 0xD373, 0x8333, 0xD374, 0x832D, 0xD375, 0x8344, 0xD376, 0x8319, 0xD377, 0x8351, 0xD378, 0x8325, 0xD379, 0x8356, 0xD37A, 0x833F, 0xD37B, 0x8341, 0xD37C, 0x8326, 0xD37D, 0x831C, 0xD37E, 0x8322, 0xD3A1, 0x8342, 0xD3A2, 0x834E, 0xD3A3, 0x831B, 0xD3A4, 0x832A, 0xD3A5, 0x8308, 0xD3A6, 0x833C, 0xD3A7, 0x834D, 0xD3A8, 0x8316, 0xD3A9, 0x8324, 0xD3AA, 0x8320, 0xD3AB, 0x8337, 0xD3AC, 0x832F, 0xD3AD, 0x8329, 0xD3AE, 0x8347, 0xD3AF, 0x8345, 0xD3B0, 0x834C, 0xD3B1, 0x8353, 0xD3B2, 0x831E, 0xD3B3, 0x832C, 0xD3B4, 0x834B, 0xD3B5, 0x8327, 0xD3B6, 0x8348, 0xD3B7, 0x8653, 0xD3B8, 0x8652, 0xD3B9, 0x86A2, 0xD3BA, 0x86A8, 0xD3BB, 0x8696, 0xD3BC, 0x868D, 0xD3BD, 0x8691, 0xD3BE, 0x869E, 0xD3BF, 0x8687, 0xD3C0, 0x8697, 0xD3C1, 0x8686, 0xD3C2, 0x868B, 0xD3C3, 0x869A, 0xD3C4, 0x8685, 0xD3C5, 0x86A5, 0xD3C6, 0x8699, 0xD3C7, 0x86A1, 0xD3C8, 0x86A7, 0xD3C9, 0x8695, 0xD3CA, 0x8698, 0xD3CB, 0x868E, 0xD3CC, 0x869D, 0xD3CD, 0x8690, 0xD3CE, 0x8694, 0xD3CF, 0x8843, 0xD3D0, 0x8844, 0xD3D1, 0x886D, 0xD3D2, 0x8875, 0xD3D3, 0x8876, 0xD3D4, 0x8872, 0xD3D5, 0x8880, 0xD3D6, 0x8871, 0xD3D7, 0x887F, 0xD3D8, 0x886F, 0xD3D9, 0x8883, 0xD3DA, 0x887E, 0xD3DB, 0x8874, 0xD3DC, 0x887C, 0xD3DD, 0x8A12, 0xD3DE, 0x8C47, 0xD3DF, 0x8C57, 0xD3E0, 0x8C7B, 0xD3E1, 0x8CA4, 0xD3E2, 0x8CA3, 0xD3E3, 0x8D76, 0xD3E4, 0x8D78, 0xD3E5, 0x8DB5, 0xD3E6, 0x8DB7, 0xD3E7, 0x8DB6, 0xD3E8, 0x8ED1, 0xD3E9, 0x8ED3, 0xD3EA, 0x8FFE, 0xD3EB, 0x8FF5, 0xD3EC, 0x9002, 0xD3ED, 0x8FFF, 0xD3EE, 0x8FFB, 0xD3EF, 0x9004, 0xD3F0, 0x8FFC, 0xD3F1, 0x8FF6, 0xD3F2, 0x90D6, 0xD3F3, 0x90E0, 0xD3F4, 0x90D9, 0xD3F5, 0x90DA, 0xD3F6, 0x90E3, 0xD3F7, 0x90DF, 0xD3F8, 0x90E5, 0xD3F9, 0x90D8, 0xD3FA, 0x90DB, 0xD3FB, 0x90D7, 0xD3FC, 0x90DC, 0xD3FD, 0x90E4, 0xD3FE, 0x9150, 0xD440, 0x914E, 0xD441, 0x914F, 0xD442, 0x91D5, 0xD443, 0x91E2, 0xD444, 0x91DA, 0xD445, 0x965C, 0xD446, 0x965F, 0xD447, 0x96BC, 0xD448, 0x98E3, 0xD449, 0x9ADF, 0xD44A, 0x9B2F, 0xD44B, 0x4E7F, 0xD44C, 0x5070, 0xD44D, 0x506A, 0xD44E, 0x5061, 0xD44F, 0x505E, 0xD450, 0x5060, 0xD451, 0x5053, 0xD452, 0x504B, 0xD453, 0x505D, 0xD454, 0x5072, 0xD455, 0x5048, 0xD456, 0x504D, 0xD457, 0x5041, 0xD458, 0x505B, 0xD459, 0x504A, 0xD45A, 0x5062, 0xD45B, 0x5015, 0xD45C, 0x5045, 0xD45D, 0x505F, 0xD45E, 0x5069, 0xD45F, 0x506B, 0xD460, 0x5063, 0xD461, 0x5064, 0xD462, 0x5046, 0xD463, 0x5040, 0xD464, 0x506E, 0xD465, 0x5073, 0xD466, 0x5057, 0xD467, 0x5051, 0xD468, 0x51D0, 0xD469, 0x526B, 0xD46A, 0x526D, 0xD46B, 0x526C, 0xD46C, 0x526E, 0xD46D, 0x52D6, 0xD46E, 0x52D3, 0xD46F, 0x532D, 0xD470, 0x539C, 0xD471, 0x5575, 0xD472, 0x5576, 0xD473, 0x553C, 0xD474, 0x554D, 0xD475, 0x5550, 0xD476, 0x5534, 0xD477, 0x552A, 0xD478, 0x5551, 0xD479, 0x5562, 0xD47A, 0x5536, 0xD47B, 0x5535, 0xD47C, 0x5530, 0xD47D, 0x5552, 0xD47E, 0x5545, 0xD4A1, 0x550C, 0xD4A2, 0x5532, 0xD4A3, 0x5565, 0xD4A4, 0x554E, 0xD4A5, 0x5539, 0xD4A6, 0x5548, 0xD4A7, 0x552D, 0xD4A8, 0x553B, 0xD4A9, 0x5540, 0xD4AA, 0x554B, 0xD4AB, 0x570A, 0xD4AC, 0x5707, 0xD4AD, 0x57FB, 0xD4AE, 0x5814, 0xD4AF, 0x57E2, 0xD4B0, 0x57F6, 0xD4B1, 0x57DC, 0xD4B2, 0x57F4, 0xD4B3, 0x5800, 0xD4B4, 0x57ED, 0xD4B5, 0x57FD, 0xD4B6, 0x5808, 0xD4B7, 0x57F8, 0xD4B8, 0x580B, 0xD4B9, 0x57F3, 0xD4BA, 0x57CF, 0xD4BB, 0x5807, 0xD4BC, 0x57EE, 0xD4BD, 0x57E3, 0xD4BE, 0x57F2, 0xD4BF, 0x57E5, 0xD4C0, 0x57EC, 0xD4C1, 0x57E1, 0xD4C2, 0x580E, 0xD4C3, 0x57FC, 0xD4C4, 0x5810, 0xD4C5, 0x57E7, 0xD4C6, 0x5801, 0xD4C7, 0x580C, 0xD4C8, 0x57F1, 0xD4C9, 0x57E9, 0xD4CA, 0x57F0, 0xD4CB, 0x580D, 0xD4CC, 0x5804, 0xD4CD, 0x595C, 0xD4CE, 0x5A60, 0xD4CF, 0x5A58, 0xD4D0, 0x5A55, 0xD4D1, 0x5A67, 0xD4D2, 0x5A5E, 0xD4D3, 0x5A38, 0xD4D4, 0x5A35, 0xD4D5, 0x5A6D, 0xD4D6, 0x5A50, 0xD4D7, 0x5A5F, 0xD4D8, 0x5A65, 0xD4D9, 0x5A6C, 0xD4DA, 0x5A53, 0xD4DB, 0x5A64, 0xD4DC, 0x5A57, 0xD4DD, 0x5A43, 0xD4DE, 0x5A5D, 0xD4DF, 0x5A52, 0xD4E0, 0x5A44, 0xD4E1, 0x5A5B, 0xD4E2, 0x5A48, 0xD4E3, 0x5A8E, 0xD4E4, 0x5A3E, 0xD4E5, 0x5A4D, 0xD4E6, 0x5A39, 0xD4E7, 0x5A4C, 0xD4E8, 0x5A70, 0xD4E9, 0x5A69, 0xD4EA, 0x5A47, 0xD4EB, 0x5A51, 0xD4EC, 0x5A56, 0xD4ED, 0x5A42, 0xD4EE, 0x5A5C, 0xD4EF, 0x5B72, 0xD4F0, 0x5B6E, 0xD4F1, 0x5BC1, 0xD4F2, 0x5BC0, 0xD4F3, 0x5C59, 0xD4F4, 0x5D1E, 0xD4F5, 0x5D0B, 0xD4F6, 0x5D1D, 0xD4F7, 0x5D1A, 0xD4F8, 0x5D20, 0xD4F9, 0x5D0C, 0xD4FA, 0x5D28, 0xD4FB, 0x5D0D, 0xD4FC, 0x5D26, 0xD4FD, 0x5D25, 0xD4FE, 0x5D0F, 0xD540, 0x5D30, 0xD541, 0x5D12, 0xD542, 0x5D23, 0xD543, 0x5D1F, 0xD544, 0x5D2E, 0xD545, 0x5E3E, 0xD546, 0x5E34, 0xD547, 0x5EB1, 0xD548, 0x5EB4, 0xD549, 0x5EB9, 0xD54A, 0x5EB2, 0xD54B, 0x5EB3, 0xD54C, 0x5F36, 0xD54D, 0x5F38, 0xD54E, 0x5F9B, 0xD54F, 0x5F96, 0xD550, 0x5F9F, 0xD551, 0x608A, 0xD552, 0x6090, 0xD553, 0x6086, 0xD554, 0x60BE, 0xD555, 0x60B0, 0xD556, 0x60BA, 0xD557, 0x60D3, 0xD558, 0x60D4, 0xD559, 0x60CF, 0xD55A, 0x60E4, 0xD55B, 0x60D9, 0xD55C, 0x60DD, 0xD55D, 0x60C8, 0xD55E, 0x60B1, 0xD55F, 0x60DB, 0xD560, 0x60B7, 0xD561, 0x60CA, 0xD562, 0x60BF, 0xD563, 0x60C3, 0xD564, 0x60CD, 0xD565, 0x60C0, 0xD566, 0x6332, 0xD567, 0x6365, 0xD568, 0x638A, 0xD569, 0x6382, 0xD56A, 0x637D, 0xD56B, 0x63BD, 0xD56C, 0x639E, 0xD56D, 0x63AD, 0xD56E, 0x639D, 0xD56F, 0x6397, 0xD570, 0x63AB, 0xD571, 0x638E, 0xD572, 0x636F, 0xD573, 0x6387, 0xD574, 0x6390, 0xD575, 0x636E, 0xD576, 0x63AF, 0xD577, 0x6375, 0xD578, 0x639C, 0xD579, 0x636D, 0xD57A, 0x63AE, 0xD57B, 0x637C, 0xD57C, 0x63A4, 0xD57D, 0x633B, 0xD57E, 0x639F, 0xD5A1, 0x6378, 0xD5A2, 0x6385, 0xD5A3, 0x6381, 0xD5A4, 0x6391, 0xD5A5, 0x638D, 0xD5A6, 0x6370, 0xD5A7, 0x6553, 0xD5A8, 0x65CD, 0xD5A9, 0x6665, 0xD5AA, 0x6661, 0xD5AB, 0x665B, 0xD5AC, 0x6659, 0xD5AD, 0x665C, 0xD5AE, 0x6662, 0xD5AF, 0x6718, 0xD5B0, 0x6879, 0xD5B1, 0x6887, 0xD5B2, 0x6890, 0xD5B3, 0x689C, 0xD5B4, 0x686D, 0xD5B5, 0x686E, 0xD5B6, 0x68AE, 0xD5B7, 0x68AB, 0xD5B8, 0x6956, 0xD5B9, 0x686F, 0xD5BA, 0x68A3, 0xD5BB, 0x68AC, 0xD5BC, 0x68A9, 0xD5BD, 0x6875, 0xD5BE, 0x6874, 0xD5BF, 0x68B2, 0xD5C0, 0x688F, 0xD5C1, 0x6877, 0xD5C2, 0x6892, 0xD5C3, 0x687C, 0xD5C4, 0x686B, 0xD5C5, 0x6872, 0xD5C6, 0x68AA, 0xD5C7, 0x6880, 0xD5C8, 0x6871, 0xD5C9, 0x687E, 0xD5CA, 0x689B, 0xD5CB, 0x6896, 0xD5CC, 0x688B, 0xD5CD, 0x68A0, 0xD5CE, 0x6889, 0xD5CF, 0x68A4, 0xD5D0, 0x6878, 0xD5D1, 0x687B, 0xD5D2, 0x6891, 0xD5D3, 0x688C, 0xD5D4, 0x688A, 0xD5D5, 0x687D, 0xD5D6, 0x6B36, 0xD5D7, 0x6B33, 0xD5D8, 0x6B37, 0xD5D9, 0x6B38, 0xD5DA, 0x6B91, 0xD5DB, 0x6B8F, 0xD5DC, 0x6B8D, 0xD5DD, 0x6B8E, 0xD5DE, 0x6B8C, 0xD5DF, 0x6C2A, 0xD5E0, 0x6DC0, 0xD5E1, 0x6DAB, 0xD5E2, 0x6DB4, 0xD5E3, 0x6DB3, 0xD5E4, 0x6E74, 0xD5E5, 0x6DAC, 0xD5E6, 0x6DE9, 0xD5E7, 0x6DE2, 0xD5E8, 0x6DB7, 0xD5E9, 0x6DF6, 0xD5EA, 0x6DD4, 0xD5EB, 0x6E00, 0xD5EC, 0x6DC8, 0xD5ED, 0x6DE0, 0xD5EE, 0x6DDF, 0xD5EF, 0x6DD6, 0xD5F0, 0x6DBE, 0xD5F1, 0x6DE5, 0xD5F2, 0x6DDC, 0xD5F3, 0x6DDD, 0xD5F4, 0x6DDB, 0xD5F5, 0x6DF4, 0xD5F6, 0x6DCA, 0xD5F7, 0x6DBD, 0xD5F8, 0x6DED, 0xD5F9, 0x6DF0, 0xD5FA, 0x6DBA, 0xD5FB, 0x6DD5, 0xD5FC, 0x6DC2, 0xD5FD, 0x6DCF, 0xD5FE, 0x6DC9, 0xD640, 0x6DD0, 0xD641, 0x6DF2, 0xD642, 0x6DD3, 0xD643, 0x6DFD, 0xD644, 0x6DD7, 0xD645, 0x6DCD, 0xD646, 0x6DE3, 0xD647, 0x6DBB, 0xD648, 0x70FA, 0xD649, 0x710D, 0xD64A, 0x70F7, 0xD64B, 0x7117, 0xD64C, 0x70F4, 0xD64D, 0x710C, 0xD64E, 0x70F0, 0xD64F, 0x7104, 0xD650, 0x70F3, 0xD651, 0x7110, 0xD652, 0x70FC, 0xD653, 0x70FF, 0xD654, 0x7106, 0xD655, 0x7113, 0xD656, 0x7100, 0xD657, 0x70F8, 0xD658, 0x70F6, 0xD659, 0x710B, 0xD65A, 0x7102, 0xD65B, 0x710E, 0xD65C, 0x727E, 0xD65D, 0x727B, 0xD65E, 0x727C, 0xD65F, 0x727F, 0xD660, 0x731D, 0xD661, 0x7317, 0xD662, 0x7307, 0xD663, 0x7311, 0xD664, 0x7318, 0xD665, 0x730A, 0xD666, 0x7308, 0xD667, 0x72FF, 0xD668, 0x730F, 0xD669, 0x731E, 0xD66A, 0x7388, 0xD66B, 0x73F6, 0xD66C, 0x73F8, 0xD66D, 0x73F5, 0xD66E, 0x7404, 0xD66F, 0x7401, 0xD670, 0x73FD, 0xD671, 0x7407, 0xD672, 0x7400, 0xD673, 0x73FA, 0xD674, 0x73FC, 0xD675, 0x73FF, 0xD676, 0x740C, 0xD677, 0x740B, 0xD678, 0x73F4, 0xD679, 0x7408, 0xD67A, 0x7564, 0xD67B, 0x7563, 0xD67C, 0x75CE, 0xD67D, 0x75D2, 0xD67E, 0x75CF, 0xD6A1, 0x75CB, 0xD6A2, 0x75CC, 0xD6A3, 0x75D1, 0xD6A4, 0x75D0, 0xD6A5, 0x768F, 0xD6A6, 0x7689, 0xD6A7, 0x76D3, 0xD6A8, 0x7739, 0xD6A9, 0x772F, 0xD6AA, 0x772D, 0xD6AB, 0x7731, 0xD6AC, 0x7732, 0xD6AD, 0x7734, 0xD6AE, 0x7733, 0xD6AF, 0x773D, 0xD6B0, 0x7725, 0xD6B1, 0x773B, 0xD6B2, 0x7735, 0xD6B3, 0x7848, 0xD6B4, 0x7852, 0xD6B5, 0x7849, 0xD6B6, 0x784D, 0xD6B7, 0x784A, 0xD6B8, 0x784C, 0xD6B9, 0x7826, 0xD6BA, 0x7845, 0xD6BB, 0x7850, 0xD6BC, 0x7964, 0xD6BD, 0x7967, 0xD6BE, 0x7969, 0xD6BF, 0x796A, 0xD6C0, 0x7963, 0xD6C1, 0x796B, 0xD6C2, 0x7961, 0xD6C3, 0x79BB, 0xD6C4, 0x79FA, 0xD6C5, 0x79F8, 0xD6C6, 0x79F6, 0xD6C7, 0x79F7, 0xD6C8, 0x7A8F, 0xD6C9, 0x7A94, 0xD6CA, 0x7A90, 0xD6CB, 0x7B35, 0xD6CC, 0x7B47, 0xD6CD, 0x7B34, 0xD6CE, 0x7B25, 0xD6CF, 0x7B30, 0xD6D0, 0x7B22, 0xD6D1, 0x7B24, 0xD6D2, 0x7B33, 0xD6D3, 0x7B18, 0xD6D4, 0x7B2A, 0xD6D5, 0x7B1D, 0xD6D6, 0x7B31, 0xD6D7, 0x7B2B, 0xD6D8, 0x7B2D, 0xD6D9, 0x7B2F, 0xD6DA, 0x7B32, 0xD6DB, 0x7B38, 0xD6DC, 0x7B1A, 0xD6DD, 0x7B23, 0xD6DE, 0x7C94, 0xD6DF, 0x7C98, 0xD6E0, 0x7C96, 0xD6E1, 0x7CA3, 0xD6E2, 0x7D35, 0xD6E3, 0x7D3D, 0xD6E4, 0x7D38, 0xD6E5, 0x7D36, 0xD6E6, 0x7D3A, 0xD6E7, 0x7D45, 0xD6E8, 0x7D2C, 0xD6E9, 0x7D29, 0xD6EA, 0x7D41, 0xD6EB, 0x7D47, 0xD6EC, 0x7D3E, 0xD6ED, 0x7D3F, 0xD6EE, 0x7D4A, 0xD6EF, 0x7D3B, 0xD6F0, 0x7D28, 0xD6F1, 0x7F63, 0xD6F2, 0x7F95, 0xD6F3, 0x7F9C, 0xD6F4, 0x7F9D, 0xD6F5, 0x7F9B, 0xD6F6, 0x7FCA, 0xD6F7, 0x7FCB, 0xD6F8, 0x7FCD, 0xD6F9, 0x7FD0, 0xD6FA, 0x7FD1, 0xD6FB, 0x7FC7, 0xD6FC, 0x7FCF, 0xD6FD, 0x7FC9, 0xD6FE, 0x801F, 0xD740, 0x801E, 0xD741, 0x801B, 0xD742, 0x8047, 0xD743, 0x8043, 0xD744, 0x8048, 0xD745, 0x8118, 0xD746, 0x8125, 0xD747, 0x8119, 0xD748, 0x811B, 0xD749, 0x812D, 0xD74A, 0x811F, 0xD74B, 0x812C, 0xD74C, 0x811E, 0xD74D, 0x8121, 0xD74E, 0x8115, 0xD74F, 0x8127, 0xD750, 0x811D, 0xD751, 0x8122, 0xD752, 0x8211, 0xD753, 0x8238, 0xD754, 0x8233, 0xD755, 0x823A, 0xD756, 0x8234, 0xD757, 0x8232, 0xD758, 0x8274, 0xD759, 0x8390, 0xD75A, 0x83A3, 0xD75B, 0x83A8, 0xD75C, 0x838D, 0xD75D, 0x837A, 0xD75E, 0x8373, 0xD75F, 0x83A4, 0xD760, 0x8374, 0xD761, 0x838F, 0xD762, 0x8381, 0xD763, 0x8395, 0xD764, 0x8399, 0xD765, 0x8375, 0xD766, 0x8394, 0xD767, 0x83A9, 0xD768, 0x837D, 0xD769, 0x8383, 0xD76A, 0x838C, 0xD76B, 0x839D, 0xD76C, 0x839B, 0xD76D, 0x83AA, 0xD76E, 0x838B, 0xD76F, 0x837E, 0xD770, 0x83A5, 0xD771, 0x83AF, 0xD772, 0x8388, 0xD773, 0x8397, 0xD774, 0x83B0, 0xD775, 0x837F, 0xD776, 0x83A6, 0xD777, 0x8387, 0xD778, 0x83AE, 0xD779, 0x8376, 0xD77A, 0x839A, 0xD77B, 0x8659, 0xD77C, 0x8656, 0xD77D, 0x86BF, 0xD77E, 0x86B7, 0xD7A1, 0x86C2, 0xD7A2, 0x86C1, 0xD7A3, 0x86C5, 0xD7A4, 0x86BA, 0xD7A5, 0x86B0, 0xD7A6, 0x86C8, 0xD7A7, 0x86B9, 0xD7A8, 0x86B3, 0xD7A9, 0x86B8, 0xD7AA, 0x86CC, 0xD7AB, 0x86B4, 0xD7AC, 0x86BB, 0xD7AD, 0x86BC, 0xD7AE, 0x86C3, 0xD7AF, 0x86BD, 0xD7B0, 0x86BE, 0xD7B1, 0x8852, 0xD7B2, 0x8889, 0xD7B3, 0x8895, 0xD7B4, 0x88A8, 0xD7B5, 0x88A2, 0xD7B6, 0x88AA, 0xD7B7, 0x889A, 0xD7B8, 0x8891, 0xD7B9, 0x88A1, 0xD7BA, 0x889F, 0xD7BB, 0x8898, 0xD7BC, 0x88A7, 0xD7BD, 0x8899, 0xD7BE, 0x889B, 0xD7BF, 0x8897, 0xD7C0, 0x88A4, 0xD7C1, 0x88AC, 0xD7C2, 0x888C, 0xD7C3, 0x8893, 0xD7C4, 0x888E, 0xD7C5, 0x8982, 0xD7C6, 0x89D6, 0xD7C7, 0x89D9, 0xD7C8, 0x89D5, 0xD7C9, 0x8A30, 0xD7CA, 0x8A27, 0xD7CB, 0x8A2C, 0xD7CC, 0x8A1E, 0xD7CD, 0x8C39, 0xD7CE, 0x8C3B, 0xD7CF, 0x8C5C, 0xD7D0, 0x8C5D, 0xD7D1, 0x8C7D, 0xD7D2, 0x8CA5, 0xD7D3, 0x8D7D, 0xD7D4, 0x8D7B, 0xD7D5, 0x8D79, 0xD7D6, 0x8DBC, 0xD7D7, 0x8DC2, 0xD7D8, 0x8DB9, 0xD7D9, 0x8DBF, 0xD7DA, 0x8DC1, 0xD7DB, 0x8ED8, 0xD7DC, 0x8EDE, 0xD7DD, 0x8EDD, 0xD7DE, 0x8EDC, 0xD7DF, 0x8ED7, 0xD7E0, 0x8EE0, 0xD7E1, 0x8EE1, 0xD7E2, 0x9024, 0xD7E3, 0x900B, 0xD7E4, 0x9011, 0xD7E5, 0x901C, 0xD7E6, 0x900C, 0xD7E7, 0x9021, 0xD7E8, 0x90EF, 0xD7E9, 0x90EA, 0xD7EA, 0x90F0, 0xD7EB, 0x90F4, 0xD7EC, 0x90F2, 0xD7ED, 0x90F3, 0xD7EE, 0x90D4, 0xD7EF, 0x90EB, 0xD7F0, 0x90EC, 0xD7F1, 0x90E9, 0xD7F2, 0x9156, 0xD7F3, 0x9158, 0xD7F4, 0x915A, 0xD7F5, 0x9153, 0xD7F6, 0x9155, 0xD7F7, 0x91EC, 0xD7F8, 0x91F4, 0xD7F9, 0x91F1, 0xD7FA, 0x91F3, 0xD7FB, 0x91F8, 0xD7FC, 0x91E4, 0xD7FD, 0x91F9, 0xD7FE, 0x91EA, 0xD840, 0x91EB, 0xD841, 0x91F7, 0xD842, 0x91E8, 0xD843, 0x91EE, 0xD844, 0x957A, 0xD845, 0x9586, 0xD846, 0x9588, 0xD847, 0x967C, 0xD848, 0x966D, 0xD849, 0x966B, 0xD84A, 0x9671, 0xD84B, 0x966F, 0xD84C, 0x96BF, 0xD84D, 0x976A, 0xD84E, 0x9804, 0xD84F, 0x98E5, 0xD850, 0x9997, 0xD851, 0x509B, 0xD852, 0x5095, 0xD853, 0x5094, 0xD854, 0x509E, 0xD855, 0x508B, 0xD856, 0x50A3, 0xD857, 0x5083, 0xD858, 0x508C, 0xD859, 0x508E, 0xD85A, 0x509D, 0xD85B, 0x5068, 0xD85C, 0x509C, 0xD85D, 0x5092, 0xD85E, 0x5082, 0xD85F, 0x5087, 0xD860, 0x515F, 0xD861, 0x51D4, 0xD862, 0x5312, 0xD863, 0x5311, 0xD864, 0x53A4, 0xD865, 0x53A7, 0xD866, 0x5591, 0xD867, 0x55A8, 0xD868, 0x55A5, 0xD869, 0x55AD, 0xD86A, 0x5577, 0xD86B, 0x5645, 0xD86C, 0x55A2, 0xD86D, 0x5593, 0xD86E, 0x5588, 0xD86F, 0x558F, 0xD870, 0x55B5, 0xD871, 0x5581, 0xD872, 0x55A3, 0xD873, 0x5592, 0xD874, 0x55A4, 0xD875, 0x557D, 0xD876, 0x558C, 0xD877, 0x55A6, 0xD878, 0x557F, 0xD879, 0x5595, 0xD87A, 0x55A1, 0xD87B, 0x558E, 0xD87C, 0x570C, 0xD87D, 0x5829, 0xD87E, 0x5837, 0xD8A1, 0x5819, 0xD8A2, 0x581E, 0xD8A3, 0x5827, 0xD8A4, 0x5823, 0xD8A5, 0x5828, 0xD8A6, 0x57F5, 0xD8A7, 0x5848, 0xD8A8, 0x5825, 0xD8A9, 0x581C, 0xD8AA, 0x581B, 0xD8AB, 0x5833, 0xD8AC, 0x583F, 0xD8AD, 0x5836, 0xD8AE, 0x582E, 0xD8AF, 0x5839, 0xD8B0, 0x5838, 0xD8B1, 0x582D, 0xD8B2, 0x582C, 0xD8B3, 0x583B, 0xD8B4, 0x5961, 0xD8B5, 0x5AAF, 0xD8B6, 0x5A94, 0xD8B7, 0x5A9F, 0xD8B8, 0x5A7A, 0xD8B9, 0x5AA2, 0xD8BA, 0x5A9E, 0xD8BB, 0x5A78, 0xD8BC, 0x5AA6, 0xD8BD, 0x5A7C, 0xD8BE, 0x5AA5, 0xD8BF, 0x5AAC, 0xD8C0, 0x5A95, 0xD8C1, 0x5AAE, 0xD8C2, 0x5A37, 0xD8C3, 0x5A84, 0xD8C4, 0x5A8A, 0xD8C5, 0x5A97, 0xD8C6, 0x5A83, 0xD8C7, 0x5A8B, 0xD8C8, 0x5AA9, 0xD8C9, 0x5A7B, 0xD8CA, 0x5A7D, 0xD8CB, 0x5A8C, 0xD8CC, 0x5A9C, 0xD8CD, 0x5A8F, 0xD8CE, 0x5A93, 0xD8CF, 0x5A9D, 0xD8D0, 0x5BEA, 0xD8D1, 0x5BCD, 0xD8D2, 0x5BCB, 0xD8D3, 0x5BD4, 0xD8D4, 0x5BD1, 0xD8D5, 0x5BCA, 0xD8D6, 0x5BCE, 0xD8D7, 0x5C0C, 0xD8D8, 0x5C30, 0xD8D9, 0x5D37, 0xD8DA, 0x5D43, 0xD8DB, 0x5D6B, 0xD8DC, 0x5D41, 0xD8DD, 0x5D4B, 0xD8DE, 0x5D3F, 0xD8DF, 0x5D35, 0xD8E0, 0x5D51, 0xD8E1, 0x5D4E, 0xD8E2, 0x5D55, 0xD8E3, 0x5D33, 0xD8E4, 0x5D3A, 0xD8E5, 0x5D52, 0xD8E6, 0x5D3D, 0xD8E7, 0x5D31, 0xD8E8, 0x5D59, 0xD8E9, 0x5D42, 0xD8EA, 0x5D39, 0xD8EB, 0x5D49, 0xD8EC, 0x5D38, 0xD8ED, 0x5D3C, 0xD8EE, 0x5D32, 0xD8EF, 0x5D36, 0xD8F0, 0x5D40, 0xD8F1, 0x5D45, 0xD8F2, 0x5E44, 0xD8F3, 0x5E41, 0xD8F4, 0x5F58, 0xD8F5, 0x5FA6, 0xD8F6, 0x5FA5, 0xD8F7, 0x5FAB, 0xD8F8, 0x60C9, 0xD8F9, 0x60B9, 0xD8FA, 0x60CC, 0xD8FB, 0x60E2, 0xD8FC, 0x60CE, 0xD8FD, 0x60C4, 0xD8FE, 0x6114, 0xD940, 0x60F2, 0xD941, 0x610A, 0xD942, 0x6116, 0xD943, 0x6105, 0xD944, 0x60F5, 0xD945, 0x6113, 0xD946, 0x60F8, 0xD947, 0x60FC, 0xD948, 0x60FE, 0xD949, 0x60C1, 0xD94A, 0x6103, 0xD94B, 0x6118, 0xD94C, 0x611D, 0xD94D, 0x6110, 0xD94E, 0x60FF, 0xD94F, 0x6104, 0xD950, 0x610B, 0xD951, 0x624A, 0xD952, 0x6394, 0xD953, 0x63B1, 0xD954, 0x63B0, 0xD955, 0x63CE, 0xD956, 0x63E5, 0xD957, 0x63E8, 0xD958, 0x63EF, 0xD959, 0x63C3, 0xD95A, 0x649D, 0xD95B, 0x63F3, 0xD95C, 0x63CA, 0xD95D, 0x63E0, 0xD95E, 0x63F6, 0xD95F, 0x63D5, 0xD960, 0x63F2, 0xD961, 0x63F5, 0xD962, 0x6461, 0xD963, 0x63DF, 0xD964, 0x63BE, 0xD965, 0x63DD, 0xD966, 0x63DC, 0xD967, 0x63C4, 0xD968, 0x63D8, 0xD969, 0x63D3, 0xD96A, 0x63C2, 0xD96B, 0x63C7, 0xD96C, 0x63CC, 0xD96D, 0x63CB, 0xD96E, 0x63C8, 0xD96F, 0x63F0, 0xD970, 0x63D7, 0xD971, 0x63D9, 0xD972, 0x6532, 0xD973, 0x6567, 0xD974, 0x656A, 0xD975, 0x6564, 0xD976, 0x655C, 0xD977, 0x6568, 0xD978, 0x6565, 0xD979, 0x658C, 0xD97A, 0x659D, 0xD97B, 0x659E, 0xD97C, 0x65AE, 0xD97D, 0x65D0, 0xD97E, 0x65D2, 0xD9A1, 0x667C, 0xD9A2, 0x666C, 0xD9A3, 0x667B, 0xD9A4, 0x6680, 0xD9A5, 0x6671, 0xD9A6, 0x6679, 0xD9A7, 0x666A, 0xD9A8, 0x6672, 0xD9A9, 0x6701, 0xD9AA, 0x690C, 0xD9AB, 0x68D3, 0xD9AC, 0x6904, 0xD9AD, 0x68DC, 0xD9AE, 0x692A, 0xD9AF, 0x68EC, 0xD9B0, 0x68EA, 0xD9B1, 0x68F1, 0xD9B2, 0x690F, 0xD9B3, 0x68D6, 0xD9B4, 0x68F7, 0xD9B5, 0x68EB, 0xD9B6, 0x68E4, 0xD9B7, 0x68F6, 0xD9B8, 0x6913, 0xD9B9, 0x6910, 0xD9BA, 0x68F3, 0xD9BB, 0x68E1, 0xD9BC, 0x6907, 0xD9BD, 0x68CC, 0xD9BE, 0x6908, 0xD9BF, 0x6970, 0xD9C0, 0x68B4, 0xD9C1, 0x6911, 0xD9C2, 0x68EF, 0xD9C3, 0x68C6, 0xD9C4, 0x6914, 0xD9C5, 0x68F8, 0xD9C6, 0x68D0, 0xD9C7, 0x68FD, 0xD9C8, 0x68FC, 0xD9C9, 0x68E8, 0xD9CA, 0x690B, 0xD9CB, 0x690A, 0xD9CC, 0x6917, 0xD9CD, 0x68CE, 0xD9CE, 0x68C8, 0xD9CF, 0x68DD, 0xD9D0, 0x68DE, 0xD9D1, 0x68E6, 0xD9D2, 0x68F4, 0xD9D3, 0x68D1, 0xD9D4, 0x6906, 0xD9D5, 0x68D4, 0xD9D6, 0x68E9, 0xD9D7, 0x6915, 0xD9D8, 0x6925, 0xD9D9, 0x68C7, 0xD9DA, 0x6B39, 0xD9DB, 0x6B3B, 0xD9DC, 0x6B3F, 0xD9DD, 0x6B3C, 0xD9DE, 0x6B94, 0xD9DF, 0x6B97, 0xD9E0, 0x6B99, 0xD9E1, 0x6B95, 0xD9E2, 0x6BBD, 0xD9E3, 0x6BF0, 0xD9E4, 0x6BF2, 0xD9E5, 0x6BF3, 0xD9E6, 0x6C30, 0xD9E7, 0x6DFC, 0xD9E8, 0x6E46, 0xD9E9, 0x6E47, 0xD9EA, 0x6E1F, 0xD9EB, 0x6E49, 0xD9EC, 0x6E88, 0xD9ED, 0x6E3C, 0xD9EE, 0x6E3D, 0xD9EF, 0x6E45, 0xD9F0, 0x6E62, 0xD9F1, 0x6E2B, 0xD9F2, 0x6E3F, 0xD9F3, 0x6E41, 0xD9F4, 0x6E5D, 0xD9F5, 0x6E73, 0xD9F6, 0x6E1C, 0xD9F7, 0x6E33, 0xD9F8, 0x6E4B, 0xD9F9, 0x6E40, 0xD9FA, 0x6E51, 0xD9FB, 0x6E3B, 0xD9FC, 0x6E03, 0xD9FD, 0x6E2E, 0xD9FE, 0x6E5E, 0xDA40, 0x6E68, 0xDA41, 0x6E5C, 0xDA42, 0x6E61, 0xDA43, 0x6E31, 0xDA44, 0x6E28, 0xDA45, 0x6E60, 0xDA46, 0x6E71, 0xDA47, 0x6E6B, 0xDA48, 0x6E39, 0xDA49, 0x6E22, 0xDA4A, 0x6E30, 0xDA4B, 0x6E53, 0xDA4C, 0x6E65, 0xDA4D, 0x6E27, 0xDA4E, 0x6E78, 0xDA4F, 0x6E64, 0xDA50, 0x6E77, 0xDA51, 0x6E55, 0xDA52, 0x6E79, 0xDA53, 0x6E52, 0xDA54, 0x6E66, 0xDA55, 0x6E35, 0xDA56, 0x6E36, 0xDA57, 0x6E5A, 0xDA58, 0x7120, 0xDA59, 0x711E, 0xDA5A, 0x712F, 0xDA5B, 0x70FB, 0xDA5C, 0x712E, 0xDA5D, 0x7131, 0xDA5E, 0x7123, 0xDA5F, 0x7125, 0xDA60, 0x7122, 0xDA61, 0x7132, 0xDA62, 0x711F, 0xDA63, 0x7128, 0xDA64, 0x713A, 0xDA65, 0x711B, 0xDA66, 0x724B, 0xDA67, 0x725A, 0xDA68, 0x7288, 0xDA69, 0x7289, 0xDA6A, 0x7286, 0xDA6B, 0x7285, 0xDA6C, 0x728B, 0xDA6D, 0x7312, 0xDA6E, 0x730B, 0xDA6F, 0x7330, 0xDA70, 0x7322, 0xDA71, 0x7331, 0xDA72, 0x7333, 0xDA73, 0x7327, 0xDA74, 0x7332, 0xDA75, 0x732D, 0xDA76, 0x7326, 0xDA77, 0x7323, 0xDA78, 0x7335, 0xDA79, 0x730C, 0xDA7A, 0x742E, 0xDA7B, 0x742C, 0xDA7C, 0x7430, 0xDA7D, 0x742B, 0xDA7E, 0x7416, 0xDAA1, 0x741A, 0xDAA2, 0x7421, 0xDAA3, 0x742D, 0xDAA4, 0x7431, 0xDAA5, 0x7424, 0xDAA6, 0x7423, 0xDAA7, 0x741D, 0xDAA8, 0x7429, 0xDAA9, 0x7420, 0xDAAA, 0x7432, 0xDAAB, 0x74FB, 0xDAAC, 0x752F, 0xDAAD, 0x756F, 0xDAAE, 0x756C, 0xDAAF, 0x75E7, 0xDAB0, 0x75DA, 0xDAB1, 0x75E1, 0xDAB2, 0x75E6, 0xDAB3, 0x75DD, 0xDAB4, 0x75DF, 0xDAB5, 0x75E4, 0xDAB6, 0x75D7, 0xDAB7, 0x7695, 0xDAB8, 0x7692, 0xDAB9, 0x76DA, 0xDABA, 0x7746, 0xDABB, 0x7747, 0xDABC, 0x7744, 0xDABD, 0x774D, 0xDABE, 0x7745, 0xDABF, 0x774A, 0xDAC0, 0x774E, 0xDAC1, 0x774B, 0xDAC2, 0x774C, 0xDAC3, 0x77DE, 0xDAC4, 0x77EC, 0xDAC5, 0x7860, 0xDAC6, 0x7864, 0xDAC7, 0x7865, 0xDAC8, 0x785C, 0xDAC9, 0x786D, 0xDACA, 0x7871, 0xDACB, 0x786A, 0xDACC, 0x786E, 0xDACD, 0x7870, 0xDACE, 0x7869, 0xDACF, 0x7868, 0xDAD0, 0x785E, 0xDAD1, 0x7862, 0xDAD2, 0x7974, 0xDAD3, 0x7973, 0xDAD4, 0x7972, 0xDAD5, 0x7970, 0xDAD6, 0x7A02, 0xDAD7, 0x7A0A, 0xDAD8, 0x7A03, 0xDAD9, 0x7A0C, 0xDADA, 0x7A04, 0xDADB, 0x7A99, 0xDADC, 0x7AE6, 0xDADD, 0x7AE4, 0xDADE, 0x7B4A, 0xDADF, 0x7B3B, 0xDAE0, 0x7B44, 0xDAE1, 0x7B48, 0xDAE2, 0x7B4C, 0xDAE3, 0x7B4E, 0xDAE4, 0x7B40, 0xDAE5, 0x7B58, 0xDAE6, 0x7B45, 0xDAE7, 0x7CA2, 0xDAE8, 0x7C9E, 0xDAE9, 0x7CA8, 0xDAEA, 0x7CA1, 0xDAEB, 0x7D58, 0xDAEC, 0x7D6F, 0xDAED, 0x7D63, 0xDAEE, 0x7D53, 0xDAEF, 0x7D56, 0xDAF0, 0x7D67, 0xDAF1, 0x7D6A, 0xDAF2, 0x7D4F, 0xDAF3, 0x7D6D, 0xDAF4, 0x7D5C, 0xDAF5, 0x7D6B, 0xDAF6, 0x7D52, 0xDAF7, 0x7D54, 0xDAF8, 0x7D69, 0xDAF9, 0x7D51, 0xDAFA, 0x7D5F, 0xDAFB, 0x7D4E, 0xDAFC, 0x7F3E, 0xDAFD, 0x7F3F, 0xDAFE, 0x7F65, 0xDB40, 0x7F66, 0xDB41, 0x7FA2, 0xDB42, 0x7FA0, 0xDB43, 0x7FA1, 0xDB44, 0x7FD7, 0xDB45, 0x8051, 0xDB46, 0x804F, 0xDB47, 0x8050, 0xDB48, 0x80FE, 0xDB49, 0x80D4, 0xDB4A, 0x8143, 0xDB4B, 0x814A, 0xDB4C, 0x8152, 0xDB4D, 0x814F, 0xDB4E, 0x8147, 0xDB4F, 0x813D, 0xDB50, 0x814D, 0xDB51, 0x813A, 0xDB52, 0x81E6, 0xDB53, 0x81EE, 0xDB54, 0x81F7, 0xDB55, 0x81F8, 0xDB56, 0x81F9, 0xDB57, 0x8204, 0xDB58, 0x823C, 0xDB59, 0x823D, 0xDB5A, 0x823F, 0xDB5B, 0x8275, 0xDB5C, 0x833B, 0xDB5D, 0x83CF, 0xDB5E, 0x83F9, 0xDB5F, 0x8423, 0xDB60, 0x83C0, 0xDB61, 0x83E8, 0xDB62, 0x8412, 0xDB63, 0x83E7, 0xDB64, 0x83E4, 0xDB65, 0x83FC, 0xDB66, 0x83F6, 0xDB67, 0x8410, 0xDB68, 0x83C6, 0xDB69, 0x83C8, 0xDB6A, 0x83EB, 0xDB6B, 0x83E3, 0xDB6C, 0x83BF, 0xDB6D, 0x8401, 0xDB6E, 0x83DD, 0xDB6F, 0x83E5, 0xDB70, 0x83D8, 0xDB71, 0x83FF, 0xDB72, 0x83E1, 0xDB73, 0x83CB, 0xDB74, 0x83CE, 0xDB75, 0x83D6, 0xDB76, 0x83F5, 0xDB77, 0x83C9, 0xDB78, 0x8409, 0xDB79, 0x840F, 0xDB7A, 0x83DE, 0xDB7B, 0x8411, 0xDB7C, 0x8406, 0xDB7D, 0x83C2, 0xDB7E, 0x83F3, 0xDBA1, 0x83D5, 0xDBA2, 0x83FA, 0xDBA3, 0x83C7, 0xDBA4, 0x83D1, 0xDBA5, 0x83EA, 0xDBA6, 0x8413, 0xDBA7, 0x83C3, 0xDBA8, 0x83EC, 0xDBA9, 0x83EE, 0xDBAA, 0x83C4, 0xDBAB, 0x83FB, 0xDBAC, 0x83D7, 0xDBAD, 0x83E2, 0xDBAE, 0x841B, 0xDBAF, 0x83DB, 0xDBB0, 0x83FE, 0xDBB1, 0x86D8, 0xDBB2, 0x86E2, 0xDBB3, 0x86E6, 0xDBB4, 0x86D3, 0xDBB5, 0x86E3, 0xDBB6, 0x86DA, 0xDBB7, 0x86EA, 0xDBB8, 0x86DD, 0xDBB9, 0x86EB, 0xDBBA, 0x86DC, 0xDBBB, 0x86EC, 0xDBBC, 0x86E9, 0xDBBD, 0x86D7, 0xDBBE, 0x86E8, 0xDBBF, 0x86D1, 0xDBC0, 0x8848, 0xDBC1, 0x8856, 0xDBC2, 0x8855, 0xDBC3, 0x88BA, 0xDBC4, 0x88D7, 0xDBC5, 0x88B9, 0xDBC6, 0x88B8, 0xDBC7, 0x88C0, 0xDBC8, 0x88BE, 0xDBC9, 0x88B6, 0xDBCA, 0x88BC, 0xDBCB, 0x88B7, 0xDBCC, 0x88BD, 0xDBCD, 0x88B2, 0xDBCE, 0x8901, 0xDBCF, 0x88C9, 0xDBD0, 0x8995, 0xDBD1, 0x8998, 0xDBD2, 0x8997, 0xDBD3, 0x89DD, 0xDBD4, 0x89DA, 0xDBD5, 0x89DB, 0xDBD6, 0x8A4E, 0xDBD7, 0x8A4D, 0xDBD8, 0x8A39, 0xDBD9, 0x8A59, 0xDBDA, 0x8A40, 0xDBDB, 0x8A57, 0xDBDC, 0x8A58, 0xDBDD, 0x8A44, 0xDBDE, 0x8A45, 0xDBDF, 0x8A52, 0xDBE0, 0x8A48, 0xDBE1, 0x8A51, 0xDBE2, 0x8A4A, 0xDBE3, 0x8A4C, 0xDBE4, 0x8A4F, 0xDBE5, 0x8C5F, 0xDBE6, 0x8C81, 0xDBE7, 0x8C80, 0xDBE8, 0x8CBA, 0xDBE9, 0x8CBE, 0xDBEA, 0x8CB0, 0xDBEB, 0x8CB9, 0xDBEC, 0x8CB5, 0xDBED, 0x8D84, 0xDBEE, 0x8D80, 0xDBEF, 0x8D89, 0xDBF0, 0x8DD8, 0xDBF1, 0x8DD3, 0xDBF2, 0x8DCD, 0xDBF3, 0x8DC7, 0xDBF4, 0x8DD6, 0xDBF5, 0x8DDC, 0xDBF6, 0x8DCF, 0xDBF7, 0x8DD5, 0xDBF8, 0x8DD9, 0xDBF9, 0x8DC8, 0xDBFA, 0x8DD7, 0xDBFB, 0x8DC5, 0xDBFC, 0x8EEF, 0xDBFD, 0x8EF7, 0xDBFE, 0x8EFA, 0xDC40, 0x8EF9, 0xDC41, 0x8EE6, 0xDC42, 0x8EEE, 0xDC43, 0x8EE5, 0xDC44, 0x8EF5, 0xDC45, 0x8EE7, 0xDC46, 0x8EE8, 0xDC47, 0x8EF6, 0xDC48, 0x8EEB, 0xDC49, 0x8EF1, 0xDC4A, 0x8EEC, 0xDC4B, 0x8EF4, 0xDC4C, 0x8EE9, 0xDC4D, 0x902D, 0xDC4E, 0x9034, 0xDC4F, 0x902F, 0xDC50, 0x9106, 0xDC51, 0x912C, 0xDC52, 0x9104, 0xDC53, 0x90FF, 0xDC54, 0x90FC, 0xDC55, 0x9108, 0xDC56, 0x90F9, 0xDC57, 0x90FB, 0xDC58, 0x9101, 0xDC59, 0x9100, 0xDC5A, 0x9107, 0xDC5B, 0x9105, 0xDC5C, 0x9103, 0xDC5D, 0x9161, 0xDC5E, 0x9164, 0xDC5F, 0x915F, 0xDC60, 0x9162, 0xDC61, 0x9160, 0xDC62, 0x9201, 0xDC63, 0x920A, 0xDC64, 0x9225, 0xDC65, 0x9203, 0xDC66, 0x921A, 0xDC67, 0x9226, 0xDC68, 0x920F, 0xDC69, 0x920C, 0xDC6A, 0x9200, 0xDC6B, 0x9212, 0xDC6C, 0x91FF, 0xDC6D, 0x91FD, 0xDC6E, 0x9206, 0xDC6F, 0x9204, 0xDC70, 0x9227, 0xDC71, 0x9202, 0xDC72, 0x921C, 0xDC73, 0x9224, 0xDC74, 0x9219, 0xDC75, 0x9217, 0xDC76, 0x9205, 0xDC77, 0x9216, 0xDC78, 0x957B, 0xDC79, 0x958D, 0xDC7A, 0x958C, 0xDC7B, 0x9590, 0xDC7C, 0x9687, 0xDC7D, 0x967E, 0xDC7E, 0x9688, 0xDCA1, 0x9689, 0xDCA2, 0x9683, 0xDCA3, 0x9680, 0xDCA4, 0x96C2, 0xDCA5, 0x96C8, 0xDCA6, 0x96C3, 0xDCA7, 0x96F1, 0xDCA8, 0x96F0, 0xDCA9, 0x976C, 0xDCAA, 0x9770, 0xDCAB, 0x976E, 0xDCAC, 0x9807, 0xDCAD, 0x98A9, 0xDCAE, 0x98EB, 0xDCAF, 0x9CE6, 0xDCB0, 0x9EF9, 0xDCB1, 0x4E83, 0xDCB2, 0x4E84, 0xDCB3, 0x4EB6, 0xDCB4, 0x50BD, 0xDCB5, 0x50BF, 0xDCB6, 0x50C6, 0xDCB7, 0x50AE, 0xDCB8, 0x50C4, 0xDCB9, 0x50CA, 0xDCBA, 0x50B4, 0xDCBB, 0x50C8, 0xDCBC, 0x50C2, 0xDCBD, 0x50B0, 0xDCBE, 0x50C1, 0xDCBF, 0x50BA, 0xDCC0, 0x50B1, 0xDCC1, 0x50CB, 0xDCC2, 0x50C9, 0xDCC3, 0x50B6, 0xDCC4, 0x50B8, 0xDCC5, 0x51D7, 0xDCC6, 0x527A, 0xDCC7, 0x5278, 0xDCC8, 0x527B, 0xDCC9, 0x527C, 0xDCCA, 0x55C3, 0xDCCB, 0x55DB, 0xDCCC, 0x55CC, 0xDCCD, 0x55D0, 0xDCCE, 0x55CB, 0xDCCF, 0x55CA, 0xDCD0, 0x55DD, 0xDCD1, 0x55C0, 0xDCD2, 0x55D4, 0xDCD3, 0x55C4, 0xDCD4, 0x55E9, 0xDCD5, 0x55BF, 0xDCD6, 0x55D2, 0xDCD7, 0x558D, 0xDCD8, 0x55CF, 0xDCD9, 0x55D5, 0xDCDA, 0x55E2, 0xDCDB, 0x55D6, 0xDCDC, 0x55C8, 0xDCDD, 0x55F2, 0xDCDE, 0x55CD, 0xDCDF, 0x55D9, 0xDCE0, 0x55C2, 0xDCE1, 0x5714, 0xDCE2, 0x5853, 0xDCE3, 0x5868, 0xDCE4, 0x5864, 0xDCE5, 0x584F, 0xDCE6, 0x584D, 0xDCE7, 0x5849, 0xDCE8, 0x586F, 0xDCE9, 0x5855, 0xDCEA, 0x584E, 0xDCEB, 0x585D, 0xDCEC, 0x5859, 0xDCED, 0x5865, 0xDCEE, 0x585B, 0xDCEF, 0x583D, 0xDCF0, 0x5863, 0xDCF1, 0x5871, 0xDCF2, 0x58FC, 0xDCF3, 0x5AC7, 0xDCF4, 0x5AC4, 0xDCF5, 0x5ACB, 0xDCF6, 0x5ABA, 0xDCF7, 0x5AB8, 0xDCF8, 0x5AB1, 0xDCF9, 0x5AB5, 0xDCFA, 0x5AB0, 0xDCFB, 0x5ABF, 0xDCFC, 0x5AC8, 0xDCFD, 0x5ABB, 0xDCFE, 0x5AC6, 0xDD40, 0x5AB7, 0xDD41, 0x5AC0, 0xDD42, 0x5ACA, 0xDD43, 0x5AB4, 0xDD44, 0x5AB6, 0xDD45, 0x5ACD, 0xDD46, 0x5AB9, 0xDD47, 0x5A90, 0xDD48, 0x5BD6, 0xDD49, 0x5BD8, 0xDD4A, 0x5BD9, 0xDD4B, 0x5C1F, 0xDD4C, 0x5C33, 0xDD4D, 0x5D71, 0xDD4E, 0x5D63, 0xDD4F, 0x5D4A, 0xDD50, 0x5D65, 0xDD51, 0x5D72, 0xDD52, 0x5D6C, 0xDD53, 0x5D5E, 0xDD54, 0x5D68, 0xDD55, 0x5D67, 0xDD56, 0x5D62, 0xDD57, 0x5DF0, 0xDD58, 0x5E4F, 0xDD59, 0x5E4E, 0xDD5A, 0x5E4A, 0xDD5B, 0x5E4D, 0xDD5C, 0x5E4B, 0xDD5D, 0x5EC5, 0xDD5E, 0x5ECC, 0xDD5F, 0x5EC6, 0xDD60, 0x5ECB, 0xDD61, 0x5EC7, 0xDD62, 0x5F40, 0xDD63, 0x5FAF, 0xDD64, 0x5FAD, 0xDD65, 0x60F7, 0xDD66, 0x6149, 0xDD67, 0x614A, 0xDD68, 0x612B, 0xDD69, 0x6145, 0xDD6A, 0x6136, 0xDD6B, 0x6132, 0xDD6C, 0x612E, 0xDD6D, 0x6146, 0xDD6E, 0x612F, 0xDD6F, 0x614F, 0xDD70, 0x6129, 0xDD71, 0x6140, 0xDD72, 0x6220, 0xDD73, 0x9168, 0xDD74, 0x6223, 0xDD75, 0x6225, 0xDD76, 0x6224, 0xDD77, 0x63C5, 0xDD78, 0x63F1, 0xDD79, 0x63EB, 0xDD7A, 0x6410, 0xDD7B, 0x6412, 0xDD7C, 0x6409, 0xDD7D, 0x6420, 0xDD7E, 0x6424, 0xDDA1, 0x6433, 0xDDA2, 0x6443, 0xDDA3, 0x641F, 0xDDA4, 0x6415, 0xDDA5, 0x6418, 0xDDA6, 0x6439, 0xDDA7, 0x6437, 0xDDA8, 0x6422, 0xDDA9, 0x6423, 0xDDAA, 0x640C, 0xDDAB, 0x6426, 0xDDAC, 0x6430, 0xDDAD, 0x6428, 0xDDAE, 0x6441, 0xDDAF, 0x6435, 0xDDB0, 0x642F, 0xDDB1, 0x640A, 0xDDB2, 0x641A, 0xDDB3, 0x6440, 0xDDB4, 0x6425, 0xDDB5, 0x6427, 0xDDB6, 0x640B, 0xDDB7, 0x63E7, 0xDDB8, 0x641B, 0xDDB9, 0x642E, 0xDDBA, 0x6421, 0xDDBB, 0x640E, 0xDDBC, 0x656F, 0xDDBD, 0x6592, 0xDDBE, 0x65D3, 0xDDBF, 0x6686, 0xDDC0, 0x668C, 0xDDC1, 0x6695, 0xDDC2, 0x6690, 0xDDC3, 0x668B, 0xDDC4, 0x668A, 0xDDC5, 0x6699, 0xDDC6, 0x6694, 0xDDC7, 0x6678, 0xDDC8, 0x6720, 0xDDC9, 0x6966, 0xDDCA, 0x695F, 0xDDCB, 0x6938, 0xDDCC, 0x694E, 0xDDCD, 0x6962, 0xDDCE, 0x6971, 0xDDCF, 0x693F, 0xDDD0, 0x6945, 0xDDD1, 0x696A, 0xDDD2, 0x6939, 0xDDD3, 0x6942, 0xDDD4, 0x6957, 0xDDD5, 0x6959, 0xDDD6, 0x697A, 0xDDD7, 0x6948, 0xDDD8, 0x6949, 0xDDD9, 0x6935, 0xDDDA, 0x696C, 0xDDDB, 0x6933, 0xDDDC, 0x693D, 0xDDDD, 0x6965, 0xDDDE, 0x68F0, 0xDDDF, 0x6978, 0xDDE0, 0x6934, 0xDDE1, 0x6969, 0xDDE2, 0x6940, 0xDDE3, 0x696F, 0xDDE4, 0x6944, 0xDDE5, 0x6976, 0xDDE6, 0x6958, 0xDDE7, 0x6941, 0xDDE8, 0x6974, 0xDDE9, 0x694C, 0xDDEA, 0x693B, 0xDDEB, 0x694B, 0xDDEC, 0x6937, 0xDDED, 0x695C, 0xDDEE, 0x694F, 0xDDEF, 0x6951, 0xDDF0, 0x6932, 0xDDF1, 0x6952, 0xDDF2, 0x692F, 0xDDF3, 0x697B, 0xDDF4, 0x693C, 0xDDF5, 0x6B46, 0xDDF6, 0x6B45, 0xDDF7, 0x6B43, 0xDDF8, 0x6B42, 0xDDF9, 0x6B48, 0xDDFA, 0x6B41, 0xDDFB, 0x6B9B, 0xDDFC, 0xFA0D, 0xDDFD, 0x6BFB, 0xDDFE, 0x6BFC, 0xDE40, 0x6BF9, 0xDE41, 0x6BF7, 0xDE42, 0x6BF8, 0xDE43, 0x6E9B, 0xDE44, 0x6ED6, 0xDE45, 0x6EC8, 0xDE46, 0x6E8F, 0xDE47, 0x6EC0, 0xDE48, 0x6E9F, 0xDE49, 0x6E93, 0xDE4A, 0x6E94, 0xDE4B, 0x6EA0, 0xDE4C, 0x6EB1, 0xDE4D, 0x6EB9, 0xDE4E, 0x6EC6, 0xDE4F, 0x6ED2, 0xDE50, 0x6EBD, 0xDE51, 0x6EC1, 0xDE52, 0x6E9E, 0xDE53, 0x6EC9, 0xDE54, 0x6EB7, 0xDE55, 0x6EB0, 0xDE56, 0x6ECD, 0xDE57, 0x6EA6, 0xDE58, 0x6ECF, 0xDE59, 0x6EB2, 0xDE5A, 0x6EBE, 0xDE5B, 0x6EC3, 0xDE5C, 0x6EDC, 0xDE5D, 0x6ED8, 0xDE5E, 0x6E99, 0xDE5F, 0x6E92, 0xDE60, 0x6E8E, 0xDE61, 0x6E8D, 0xDE62, 0x6EA4, 0xDE63, 0x6EA1, 0xDE64, 0x6EBF, 0xDE65, 0x6EB3, 0xDE66, 0x6ED0, 0xDE67, 0x6ECA, 0xDE68, 0x6E97, 0xDE69, 0x6EAE, 0xDE6A, 0x6EA3, 0xDE6B, 0x7147, 0xDE6C, 0x7154, 0xDE6D, 0x7152, 0xDE6E, 0x7163, 0xDE6F, 0x7160, 0xDE70, 0x7141, 0xDE71, 0x715D, 0xDE72, 0x7162, 0xDE73, 0x7172, 0xDE74, 0x7178, 0xDE75, 0x716A, 0xDE76, 0x7161, 0xDE77, 0x7142, 0xDE78, 0x7158, 0xDE79, 0x7143, 0xDE7A, 0x714B, 0xDE7B, 0x7170, 0xDE7C, 0x715F, 0xDE7D, 0x7150, 0xDE7E, 0x7153, 0xDEA1, 0x7144, 0xDEA2, 0x714D, 0xDEA3, 0x715A, 0xDEA4, 0x724F, 0xDEA5, 0x728D, 0xDEA6, 0x728C, 0xDEA7, 0x7291, 0xDEA8, 0x7290, 0xDEA9, 0x728E, 0xDEAA, 0x733C, 0xDEAB, 0x7342, 0xDEAC, 0x733B, 0xDEAD, 0x733A, 0xDEAE, 0x7340, 0xDEAF, 0x734A, 0xDEB0, 0x7349, 0xDEB1, 0x7444, 0xDEB2, 0x744A, 0xDEB3, 0x744B, 0xDEB4, 0x7452, 0xDEB5, 0x7451, 0xDEB6, 0x7457, 0xDEB7, 0x7440, 0xDEB8, 0x744F, 0xDEB9, 0x7450, 0xDEBA, 0x744E, 0xDEBB, 0x7442, 0xDEBC, 0x7446, 0xDEBD, 0x744D, 0xDEBE, 0x7454, 0xDEBF, 0x74E1, 0xDEC0, 0x74FF, 0xDEC1, 0x74FE, 0xDEC2, 0x74FD, 0xDEC3, 0x751D, 0xDEC4, 0x7579, 0xDEC5, 0x7577, 0xDEC6, 0x6983, 0xDEC7, 0x75EF, 0xDEC8, 0x760F, 0xDEC9, 0x7603, 0xDECA, 0x75F7, 0xDECB, 0x75FE, 0xDECC, 0x75FC, 0xDECD, 0x75F9, 0xDECE, 0x75F8, 0xDECF, 0x7610, 0xDED0, 0x75FB, 0xDED1, 0x75F6, 0xDED2, 0x75ED, 0xDED3, 0x75F5, 0xDED4, 0x75FD, 0xDED5, 0x7699, 0xDED6, 0x76B5, 0xDED7, 0x76DD, 0xDED8, 0x7755, 0xDED9, 0x775F, 0xDEDA, 0x7760, 0xDEDB, 0x7752, 0xDEDC, 0x7756, 0xDEDD, 0x775A, 0xDEDE, 0x7769, 0xDEDF, 0x7767, 0xDEE0, 0x7754, 0xDEE1, 0x7759, 0xDEE2, 0x776D, 0xDEE3, 0x77E0, 0xDEE4, 0x7887, 0xDEE5, 0x789A, 0xDEE6, 0x7894, 0xDEE7, 0x788F, 0xDEE8, 0x7884, 0xDEE9, 0x7895, 0xDEEA, 0x7885, 0xDEEB, 0x7886, 0xDEEC, 0x78A1, 0xDEED, 0x7883, 0xDEEE, 0x7879, 0xDEEF, 0x7899, 0xDEF0, 0x7880, 0xDEF1, 0x7896, 0xDEF2, 0x787B, 0xDEF3, 0x797C, 0xDEF4, 0x7982, 0xDEF5, 0x797D, 0xDEF6, 0x7979, 0xDEF7, 0x7A11, 0xDEF8, 0x7A18, 0xDEF9, 0x7A19, 0xDEFA, 0x7A12, 0xDEFB, 0x7A17, 0xDEFC, 0x7A15, 0xDEFD, 0x7A22, 0xDEFE, 0x7A13, 0xDF40, 0x7A1B, 0xDF41, 0x7A10, 0xDF42, 0x7AA3, 0xDF43, 0x7AA2, 0xDF44, 0x7A9E, 0xDF45, 0x7AEB, 0xDF46, 0x7B66, 0xDF47, 0x7B64, 0xDF48, 0x7B6D, 0xDF49, 0x7B74, 0xDF4A, 0x7B69, 0xDF4B, 0x7B72, 0xDF4C, 0x7B65, 0xDF4D, 0x7B73, 0xDF4E, 0x7B71, 0xDF4F, 0x7B70, 0xDF50, 0x7B61, 0xDF51, 0x7B78, 0xDF52, 0x7B76, 0xDF53, 0x7B63, 0xDF54, 0x7CB2, 0xDF55, 0x7CB4, 0xDF56, 0x7CAF, 0xDF57, 0x7D88, 0xDF58, 0x7D86, 0xDF59, 0x7D80, 0xDF5A, 0x7D8D, 0xDF5B, 0x7D7F, 0xDF5C, 0x7D85, 0xDF5D, 0x7D7A, 0xDF5E, 0x7D8E, 0xDF5F, 0x7D7B, 0xDF60, 0x7D83, 0xDF61, 0x7D7C, 0xDF62, 0x7D8C, 0xDF63, 0x7D94, 0xDF64, 0x7D84, 0xDF65, 0x7D7D, 0xDF66, 0x7D92, 0xDF67, 0x7F6D, 0xDF68, 0x7F6B, 0xDF69, 0x7F67, 0xDF6A, 0x7F68, 0xDF6B, 0x7F6C, 0xDF6C, 0x7FA6, 0xDF6D, 0x7FA5, 0xDF6E, 0x7FA7, 0xDF6F, 0x7FDB, 0xDF70, 0x7FDC, 0xDF71, 0x8021, 0xDF72, 0x8164, 0xDF73, 0x8160, 0xDF74, 0x8177, 0xDF75, 0x815C, 0xDF76, 0x8169, 0xDF77, 0x815B, 0xDF78, 0x8162, 0xDF79, 0x8172, 0xDF7A, 0x6721, 0xDF7B, 0x815E, 0xDF7C, 0x8176, 0xDF7D, 0x8167, 0xDF7E, 0x816F, 0xDFA1, 0x8144, 0xDFA2, 0x8161, 0xDFA3, 0x821D, 0xDFA4, 0x8249, 0xDFA5, 0x8244, 0xDFA6, 0x8240, 0xDFA7, 0x8242, 0xDFA8, 0x8245, 0xDFA9, 0x84F1, 0xDFAA, 0x843F, 0xDFAB, 0x8456, 0xDFAC, 0x8476, 0xDFAD, 0x8479, 0xDFAE, 0x848F, 0xDFAF, 0x848D, 0xDFB0, 0x8465, 0xDFB1, 0x8451, 0xDFB2, 0x8440, 0xDFB3, 0x8486, 0xDFB4, 0x8467, 0xDFB5, 0x8430, 0xDFB6, 0x844D, 0xDFB7, 0x847D, 0xDFB8, 0x845A, 0xDFB9, 0x8459, 0xDFBA, 0x8474, 0xDFBB, 0x8473, 0xDFBC, 0x845D, 0xDFBD, 0x8507, 0xDFBE, 0x845E, 0xDFBF, 0x8437, 0xDFC0, 0x843A, 0xDFC1, 0x8434, 0xDFC2, 0x847A, 0xDFC3, 0x8443, 0xDFC4, 0x8478, 0xDFC5, 0x8432, 0xDFC6, 0x8445, 0xDFC7, 0x8429, 0xDFC8, 0x83D9, 0xDFC9, 0x844B, 0xDFCA, 0x842F, 0xDFCB, 0x8442, 0xDFCC, 0x842D, 0xDFCD, 0x845F, 0xDFCE, 0x8470, 0xDFCF, 0x8439, 0xDFD0, 0x844E, 0xDFD1, 0x844C, 0xDFD2, 0x8452, 0xDFD3, 0x846F, 0xDFD4, 0x84C5, 0xDFD5, 0x848E, 0xDFD6, 0x843B, 0xDFD7, 0x8447, 0xDFD8, 0x8436, 0xDFD9, 0x8433, 0xDFDA, 0x8468, 0xDFDB, 0x847E, 0xDFDC, 0x8444, 0xDFDD, 0x842B, 0xDFDE, 0x8460, 0xDFDF, 0x8454, 0xDFE0, 0x846E, 0xDFE1, 0x8450, 0xDFE2, 0x870B, 0xDFE3, 0x8704, 0xDFE4, 0x86F7, 0xDFE5, 0x870C, 0xDFE6, 0x86FA, 0xDFE7, 0x86D6, 0xDFE8, 0x86F5, 0xDFE9, 0x874D, 0xDFEA, 0x86F8, 0xDFEB, 0x870E, 0xDFEC, 0x8709, 0xDFED, 0x8701, 0xDFEE, 0x86F6, 0xDFEF, 0x870D, 0xDFF0, 0x8705, 0xDFF1, 0x88D6, 0xDFF2, 0x88CB, 0xDFF3, 0x88CD, 0xDFF4, 0x88CE, 0xDFF5, 0x88DE, 0xDFF6, 0x88DB, 0xDFF7, 0x88DA, 0xDFF8, 0x88CC, 0xDFF9, 0x88D0, 0xDFFA, 0x8985, 0xDFFB, 0x899B, 0xDFFC, 0x89DF, 0xDFFD, 0x89E5, 0xDFFE, 0x89E4, 0xE040, 0x89E1, 0xE041, 0x89E0, 0xE042, 0x89E2, 0xE043, 0x89DC, 0xE044, 0x89E6, 0xE045, 0x8A76, 0xE046, 0x8A86, 0xE047, 0x8A7F, 0xE048, 0x8A61, 0xE049, 0x8A3F, 0xE04A, 0x8A77, 0xE04B, 0x8A82, 0xE04C, 0x8A84, 0xE04D, 0x8A75, 0xE04E, 0x8A83, 0xE04F, 0x8A81, 0xE050, 0x8A74, 0xE051, 0x8A7A, 0xE052, 0x8C3C, 0xE053, 0x8C4B, 0xE054, 0x8C4A, 0xE055, 0x8C65, 0xE056, 0x8C64, 0xE057, 0x8C66, 0xE058, 0x8C86, 0xE059, 0x8C84, 0xE05A, 0x8C85, 0xE05B, 0x8CCC, 0xE05C, 0x8D68, 0xE05D, 0x8D69, 0xE05E, 0x8D91, 0xE05F, 0x8D8C, 0xE060, 0x8D8E, 0xE061, 0x8D8F, 0xE062, 0x8D8D, 0xE063, 0x8D93, 0xE064, 0x8D94, 0xE065, 0x8D90, 0xE066, 0x8D92, 0xE067, 0x8DF0, 0xE068, 0x8DE0, 0xE069, 0x8DEC, 0xE06A, 0x8DF1, 0xE06B, 0x8DEE, 0xE06C, 0x8DD0, 0xE06D, 0x8DE9, 0xE06E, 0x8DE3, 0xE06F, 0x8DE2, 0xE070, 0x8DE7, 0xE071, 0x8DF2, 0xE072, 0x8DEB, 0xE073, 0x8DF4, 0xE074, 0x8F06, 0xE075, 0x8EFF, 0xE076, 0x8F01, 0xE077, 0x8F00, 0xE078, 0x8F05, 0xE079, 0x8F07, 0xE07A, 0x8F08, 0xE07B, 0x8F02, 0xE07C, 0x8F0B, 0xE07D, 0x9052, 0xE07E, 0x903F, 0xE0A1, 0x9044, 0xE0A2, 0x9049, 0xE0A3, 0x903D, 0xE0A4, 0x9110, 0xE0A5, 0x910D, 0xE0A6, 0x910F, 0xE0A7, 0x9111, 0xE0A8, 0x9116, 0xE0A9, 0x9114, 0xE0AA, 0x910B, 0xE0AB, 0x910E, 0xE0AC, 0x916E, 0xE0AD, 0x916F, 0xE0AE, 0x9248, 0xE0AF, 0x9252, 0xE0B0, 0x9230, 0xE0B1, 0x923A, 0xE0B2, 0x9266, 0xE0B3, 0x9233, 0xE0B4, 0x9265, 0xE0B5, 0x925E, 0xE0B6, 0x9283, 0xE0B7, 0x922E, 0xE0B8, 0x924A, 0xE0B9, 0x9246, 0xE0BA, 0x926D, 0xE0BB, 0x926C, 0xE0BC, 0x924F, 0xE0BD, 0x9260, 0xE0BE, 0x9267, 0xE0BF, 0x926F, 0xE0C0, 0x9236, 0xE0C1, 0x9261, 0xE0C2, 0x9270, 0xE0C3, 0x9231, 0xE0C4, 0x9254, 0xE0C5, 0x9263, 0xE0C6, 0x9250, 0xE0C7, 0x9272, 0xE0C8, 0x924E, 0xE0C9, 0x9253, 0xE0CA, 0x924C, 0xE0CB, 0x9256, 0xE0CC, 0x9232, 0xE0CD, 0x959F, 0xE0CE, 0x959C, 0xE0CF, 0x959E, 0xE0D0, 0x959B, 0xE0D1, 0x9692, 0xE0D2, 0x9693, 0xE0D3, 0x9691, 0xE0D4, 0x9697, 0xE0D5, 0x96CE, 0xE0D6, 0x96FA, 0xE0D7, 0x96FD, 0xE0D8, 0x96F8, 0xE0D9, 0x96F5, 0xE0DA, 0x9773, 0xE0DB, 0x9777, 0xE0DC, 0x9778, 0xE0DD, 0x9772, 0xE0DE, 0x980F, 0xE0DF, 0x980D, 0xE0E0, 0x980E, 0xE0E1, 0x98AC, 0xE0E2, 0x98F6, 0xE0E3, 0x98F9, 0xE0E4, 0x99AF, 0xE0E5, 0x99B2, 0xE0E6, 0x99B0, 0xE0E7, 0x99B5, 0xE0E8, 0x9AAD, 0xE0E9, 0x9AAB, 0xE0EA, 0x9B5B, 0xE0EB, 0x9CEA, 0xE0EC, 0x9CED, 0xE0ED, 0x9CE7, 0xE0EE, 0x9E80, 0xE0EF, 0x9EFD, 0xE0F0, 0x50E6, 0xE0F1, 0x50D4, 0xE0F2, 0x50D7, 0xE0F3, 0x50E8, 0xE0F4, 0x50F3, 0xE0F5, 0x50DB, 0xE0F6, 0x50EA, 0xE0F7, 0x50DD, 0xE0F8, 0x50E4, 0xE0F9, 0x50D3, 0xE0FA, 0x50EC, 0xE0FB, 0x50F0, 0xE0FC, 0x50EF, 0xE0FD, 0x50E3, 0xE0FE, 0x50E0, 0xE140, 0x51D8, 0xE141, 0x5280, 0xE142, 0x5281, 0xE143, 0x52E9, 0xE144, 0x52EB, 0xE145, 0x5330, 0xE146, 0x53AC, 0xE147, 0x5627, 0xE148, 0x5615, 0xE149, 0x560C, 0xE14A, 0x5612, 0xE14B, 0x55FC, 0xE14C, 0x560F, 0xE14D, 0x561C, 0xE14E, 0x5601, 0xE14F, 0x5613, 0xE150, 0x5602, 0xE151, 0x55FA, 0xE152, 0x561D, 0xE153, 0x5604, 0xE154, 0x55FF, 0xE155, 0x55F9, 0xE156, 0x5889, 0xE157, 0x587C, 0xE158, 0x5890, 0xE159, 0x5898, 0xE15A, 0x5886, 0xE15B, 0x5881, 0xE15C, 0x587F, 0xE15D, 0x5874, 0xE15E, 0x588B, 0xE15F, 0x587A, 0xE160, 0x5887, 0xE161, 0x5891, 0xE162, 0x588E, 0xE163, 0x5876, 0xE164, 0x5882, 0xE165, 0x5888, 0xE166, 0x587B, 0xE167, 0x5894, 0xE168, 0x588F, 0xE169, 0x58FE, 0xE16A, 0x596B, 0xE16B, 0x5ADC, 0xE16C, 0x5AEE, 0xE16D, 0x5AE5, 0xE16E, 0x5AD5, 0xE16F, 0x5AEA, 0xE170, 0x5ADA, 0xE171, 0x5AED, 0xE172, 0x5AEB, 0xE173, 0x5AF3, 0xE174, 0x5AE2, 0xE175, 0x5AE0, 0xE176, 0x5ADB, 0xE177, 0x5AEC, 0xE178, 0x5ADE, 0xE179, 0x5ADD, 0xE17A, 0x5AD9, 0xE17B, 0x5AE8, 0xE17C, 0x5ADF, 0xE17D, 0x5B77, 0xE17E, 0x5BE0, 0xE1A1, 0x5BE3, 0xE1A2, 0x5C63, 0xE1A3, 0x5D82, 0xE1A4, 0x5D80, 0xE1A5, 0x5D7D, 0xE1A6, 0x5D86, 0xE1A7, 0x5D7A, 0xE1A8, 0x5D81, 0xE1A9, 0x5D77, 0xE1AA, 0x5D8A, 0xE1AB, 0x5D89, 0xE1AC, 0x5D88, 0xE1AD, 0x5D7E, 0xE1AE, 0x5D7C, 0xE1AF, 0x5D8D, 0xE1B0, 0x5D79, 0xE1B1, 0x5D7F, 0xE1B2, 0x5E58, 0xE1B3, 0x5E59, 0xE1B4, 0x5E53, 0xE1B5, 0x5ED8, 0xE1B6, 0x5ED1, 0xE1B7, 0x5ED7, 0xE1B8, 0x5ECE, 0xE1B9, 0x5EDC, 0xE1BA, 0x5ED5, 0xE1BB, 0x5ED9, 0xE1BC, 0x5ED2, 0xE1BD, 0x5ED4, 0xE1BE, 0x5F44, 0xE1BF, 0x5F43, 0xE1C0, 0x5F6F, 0xE1C1, 0x5FB6, 0xE1C2, 0x612C, 0xE1C3, 0x6128, 0xE1C4, 0x6141, 0xE1C5, 0x615E, 0xE1C6, 0x6171, 0xE1C7, 0x6173, 0xE1C8, 0x6152, 0xE1C9, 0x6153, 0xE1CA, 0x6172, 0xE1CB, 0x616C, 0xE1CC, 0x6180, 0xE1CD, 0x6174, 0xE1CE, 0x6154, 0xE1CF, 0x617A, 0xE1D0, 0x615B, 0xE1D1, 0x6165, 0xE1D2, 0x613B, 0xE1D3, 0x616A, 0xE1D4, 0x6161, 0xE1D5, 0x6156, 0xE1D6, 0x6229, 0xE1D7, 0x6227, 0xE1D8, 0x622B, 0xE1D9, 0x642B, 0xE1DA, 0x644D, 0xE1DB, 0x645B, 0xE1DC, 0x645D, 0xE1DD, 0x6474, 0xE1DE, 0x6476, 0xE1DF, 0x6472, 0xE1E0, 0x6473, 0xE1E1, 0x647D, 0xE1E2, 0x6475, 0xE1E3, 0x6466, 0xE1E4, 0x64A6, 0xE1E5, 0x644E, 0xE1E6, 0x6482, 0xE1E7, 0x645E, 0xE1E8, 0x645C, 0xE1E9, 0x644B, 0xE1EA, 0x6453, 0xE1EB, 0x6460, 0xE1EC, 0x6450, 0xE1ED, 0x647F, 0xE1EE, 0x643F, 0xE1EF, 0x646C, 0xE1F0, 0x646B, 0xE1F1, 0x6459, 0xE1F2, 0x6465, 0xE1F3, 0x6477, 0xE1F4, 0x6573, 0xE1F5, 0x65A0, 0xE1F6, 0x66A1, 0xE1F7, 0x66A0, 0xE1F8, 0x669F, 0xE1F9, 0x6705, 0xE1FA, 0x6704, 0xE1FB, 0x6722, 0xE1FC, 0x69B1, 0xE1FD, 0x69B6, 0xE1FE, 0x69C9, 0xE240, 0x69A0, 0xE241, 0x69CE, 0xE242, 0x6996, 0xE243, 0x69B0, 0xE244, 0x69AC, 0xE245, 0x69BC, 0xE246, 0x6991, 0xE247, 0x6999, 0xE248, 0x698E, 0xE249, 0x69A7, 0xE24A, 0x698D, 0xE24B, 0x69A9, 0xE24C, 0x69BE, 0xE24D, 0x69AF, 0xE24E, 0x69BF, 0xE24F, 0x69C4, 0xE250, 0x69BD, 0xE251, 0x69A4, 0xE252, 0x69D4, 0xE253, 0x69B9, 0xE254, 0x69CA, 0xE255, 0x699A, 0xE256, 0x69CF, 0xE257, 0x69B3, 0xE258, 0x6993, 0xE259, 0x69AA, 0xE25A, 0x69A1, 0xE25B, 0x699E, 0xE25C, 0x69D9, 0xE25D, 0x6997, 0xE25E, 0x6990, 0xE25F, 0x69C2, 0xE260, 0x69B5, 0xE261, 0x69A5, 0xE262, 0x69C6, 0xE263, 0x6B4A, 0xE264, 0x6B4D, 0xE265, 0x6B4B, 0xE266, 0x6B9E, 0xE267, 0x6B9F, 0xE268, 0x6BA0, 0xE269, 0x6BC3, 0xE26A, 0x6BC4, 0xE26B, 0x6BFE, 0xE26C, 0x6ECE, 0xE26D, 0x6EF5, 0xE26E, 0x6EF1, 0xE26F, 0x6F03, 0xE270, 0x6F25, 0xE271, 0x6EF8, 0xE272, 0x6F37, 0xE273, 0x6EFB, 0xE274, 0x6F2E, 0xE275, 0x6F09, 0xE276, 0x6F4E, 0xE277, 0x6F19, 0xE278, 0x6F1A, 0xE279, 0x6F27, 0xE27A, 0x6F18, 0xE27B, 0x6F3B, 0xE27C, 0x6F12, 0xE27D, 0x6EED, 0xE27E, 0x6F0A, 0xE2A1, 0x6F36, 0xE2A2, 0x6F73, 0xE2A3, 0x6EF9, 0xE2A4, 0x6EEE, 0xE2A5, 0x6F2D, 0xE2A6, 0x6F40, 0xE2A7, 0x6F30, 0xE2A8, 0x6F3C, 0xE2A9, 0x6F35, 0xE2AA, 0x6EEB, 0xE2AB, 0x6F07, 0xE2AC, 0x6F0E, 0xE2AD, 0x6F43, 0xE2AE, 0x6F05, 0xE2AF, 0x6EFD, 0xE2B0, 0x6EF6, 0xE2B1, 0x6F39, 0xE2B2, 0x6F1C, 0xE2B3, 0x6EFC, 0xE2B4, 0x6F3A, 0xE2B5, 0x6F1F, 0xE2B6, 0x6F0D, 0xE2B7, 0x6F1E, 0xE2B8, 0x6F08, 0xE2B9, 0x6F21, 0xE2BA, 0x7187, 0xE2BB, 0x7190, 0xE2BC, 0x7189, 0xE2BD, 0x7180, 0xE2BE, 0x7185, 0xE2BF, 0x7182, 0xE2C0, 0x718F, 0xE2C1, 0x717B, 0xE2C2, 0x7186, 0xE2C3, 0x7181, 0xE2C4, 0x7197, 0xE2C5, 0x7244, 0xE2C6, 0x7253, 0xE2C7, 0x7297, 0xE2C8, 0x7295, 0xE2C9, 0x7293, 0xE2CA, 0x7343, 0xE2CB, 0x734D, 0xE2CC, 0x7351, 0xE2CD, 0x734C, 0xE2CE, 0x7462, 0xE2CF, 0x7473, 0xE2D0, 0x7471, 0xE2D1, 0x7475, 0xE2D2, 0x7472, 0xE2D3, 0x7467, 0xE2D4, 0x746E, 0xE2D5, 0x7500, 0xE2D6, 0x7502, 0xE2D7, 0x7503, 0xE2D8, 0x757D, 0xE2D9, 0x7590, 0xE2DA, 0x7616, 0xE2DB, 0x7608, 0xE2DC, 0x760C, 0xE2DD, 0x7615, 0xE2DE, 0x7611, 0xE2DF, 0x760A, 0xE2E0, 0x7614, 0xE2E1, 0x76B8, 0xE2E2, 0x7781, 0xE2E3, 0x777C, 0xE2E4, 0x7785, 0xE2E5, 0x7782, 0xE2E6, 0x776E, 0xE2E7, 0x7780, 0xE2E8, 0x776F, 0xE2E9, 0x777E, 0xE2EA, 0x7783, 0xE2EB, 0x78B2, 0xE2EC, 0x78AA, 0xE2ED, 0x78B4, 0xE2EE, 0x78AD, 0xE2EF, 0x78A8, 0xE2F0, 0x787E, 0xE2F1, 0x78AB, 0xE2F2, 0x789E, 0xE2F3, 0x78A5, 0xE2F4, 0x78A0, 0xE2F5, 0x78AC, 0xE2F6, 0x78A2, 0xE2F7, 0x78A4, 0xE2F8, 0x7998, 0xE2F9, 0x798A, 0xE2FA, 0x798B, 0xE2FB, 0x7996, 0xE2FC, 0x7995, 0xE2FD, 0x7994, 0xE2FE, 0x7993, 0xE340, 0x7997, 0xE341, 0x7988, 0xE342, 0x7992, 0xE343, 0x7990, 0xE344, 0x7A2B, 0xE345, 0x7A4A, 0xE346, 0x7A30, 0xE347, 0x7A2F, 0xE348, 0x7A28, 0xE349, 0x7A26, 0xE34A, 0x7AA8, 0xE34B, 0x7AAB, 0xE34C, 0x7AAC, 0xE34D, 0x7AEE, 0xE34E, 0x7B88, 0xE34F, 0x7B9C, 0xE350, 0x7B8A, 0xE351, 0x7B91, 0xE352, 0x7B90, 0xE353, 0x7B96, 0xE354, 0x7B8D, 0xE355, 0x7B8C, 0xE356, 0x7B9B, 0xE357, 0x7B8E, 0xE358, 0x7B85, 0xE359, 0x7B98, 0xE35A, 0x5284, 0xE35B, 0x7B99, 0xE35C, 0x7BA4, 0xE35D, 0x7B82, 0xE35E, 0x7CBB, 0xE35F, 0x7CBF, 0xE360, 0x7CBC, 0xE361, 0x7CBA, 0xE362, 0x7DA7, 0xE363, 0x7DB7, 0xE364, 0x7DC2, 0xE365, 0x7DA3, 0xE366, 0x7DAA, 0xE367, 0x7DC1, 0xE368, 0x7DC0, 0xE369, 0x7DC5, 0xE36A, 0x7D9D, 0xE36B, 0x7DCE, 0xE36C, 0x7DC4, 0xE36D, 0x7DC6, 0xE36E, 0x7DCB, 0xE36F, 0x7DCC, 0xE370, 0x7DAF, 0xE371, 0x7DB9, 0xE372, 0x7D96, 0xE373, 0x7DBC, 0xE374, 0x7D9F, 0xE375, 0x7DA6, 0xE376, 0x7DAE, 0xE377, 0x7DA9, 0xE378, 0x7DA1, 0xE379, 0x7DC9, 0xE37A, 0x7F73, 0xE37B, 0x7FE2, 0xE37C, 0x7FE3, 0xE37D, 0x7FE5, 0xE37E, 0x7FDE, 0xE3A1, 0x8024, 0xE3A2, 0x805D, 0xE3A3, 0x805C, 0xE3A4, 0x8189, 0xE3A5, 0x8186, 0xE3A6, 0x8183, 0xE3A7, 0x8187, 0xE3A8, 0x818D, 0xE3A9, 0x818C, 0xE3AA, 0x818B, 0xE3AB, 0x8215, 0xE3AC, 0x8497, 0xE3AD, 0x84A4, 0xE3AE, 0x84A1, 0xE3AF, 0x849F, 0xE3B0, 0x84BA, 0xE3B1, 0x84CE, 0xE3B2, 0x84C2, 0xE3B3, 0x84AC, 0xE3B4, 0x84AE, 0xE3B5, 0x84AB, 0xE3B6, 0x84B9, 0xE3B7, 0x84B4, 0xE3B8, 0x84C1, 0xE3B9, 0x84CD, 0xE3BA, 0x84AA, 0xE3BB, 0x849A, 0xE3BC, 0x84B1, 0xE3BD, 0x84D0, 0xE3BE, 0x849D, 0xE3BF, 0x84A7, 0xE3C0, 0x84BB, 0xE3C1, 0x84A2, 0xE3C2, 0x8494, 0xE3C3, 0x84C7, 0xE3C4, 0x84CC, 0xE3C5, 0x849B, 0xE3C6, 0x84A9, 0xE3C7, 0x84AF, 0xE3C8, 0x84A8, 0xE3C9, 0x84D6, 0xE3CA, 0x8498, 0xE3CB, 0x84B6, 0xE3CC, 0x84CF, 0xE3CD, 0x84A0, 0xE3CE, 0x84D7, 0xE3CF, 0x84D4, 0xE3D0, 0x84D2, 0xE3D1, 0x84DB, 0xE3D2, 0x84B0, 0xE3D3, 0x8491, 0xE3D4, 0x8661, 0xE3D5, 0x8733, 0xE3D6, 0x8723, 0xE3D7, 0x8728, 0xE3D8, 0x876B, 0xE3D9, 0x8740, 0xE3DA, 0x872E, 0xE3DB, 0x871E, 0xE3DC, 0x8721, 0xE3DD, 0x8719, 0xE3DE, 0x871B, 0xE3DF, 0x8743, 0xE3E0, 0x872C, 0xE3E1, 0x8741, 0xE3E2, 0x873E, 0xE3E3, 0x8746, 0xE3E4, 0x8720, 0xE3E5, 0x8732, 0xE3E6, 0x872A, 0xE3E7, 0x872D, 0xE3E8, 0x873C, 0xE3E9, 0x8712, 0xE3EA, 0x873A, 0xE3EB, 0x8731, 0xE3EC, 0x8735, 0xE3ED, 0x8742, 0xE3EE, 0x8726, 0xE3EF, 0x8727, 0xE3F0, 0x8738, 0xE3F1, 0x8724, 0xE3F2, 0x871A, 0xE3F3, 0x8730, 0xE3F4, 0x8711, 0xE3F5, 0x88F7, 0xE3F6, 0x88E7, 0xE3F7, 0x88F1, 0xE3F8, 0x88F2, 0xE3F9, 0x88FA, 0xE3FA, 0x88FE, 0xE3FB, 0x88EE, 0xE3FC, 0x88FC, 0xE3FD, 0x88F6, 0xE3FE, 0x88FB, 0xE440, 0x88F0, 0xE441, 0x88EC, 0xE442, 0x88EB, 0xE443, 0x899D, 0xE444, 0x89A1, 0xE445, 0x899F, 0xE446, 0x899E, 0xE447, 0x89E9, 0xE448, 0x89EB, 0xE449, 0x89E8, 0xE44A, 0x8AAB, 0xE44B, 0x8A99, 0xE44C, 0x8A8B, 0xE44D, 0x8A92, 0xE44E, 0x8A8F, 0xE44F, 0x8A96, 0xE450, 0x8C3D, 0xE451, 0x8C68, 0xE452, 0x8C69, 0xE453, 0x8CD5, 0xE454, 0x8CCF, 0xE455, 0x8CD7, 0xE456, 0x8D96, 0xE457, 0x8E09, 0xE458, 0x8E02, 0xE459, 0x8DFF, 0xE45A, 0x8E0D, 0xE45B, 0x8DFD, 0xE45C, 0x8E0A, 0xE45D, 0x8E03, 0xE45E, 0x8E07, 0xE45F, 0x8E06, 0xE460, 0x8E05, 0xE461, 0x8DFE, 0xE462, 0x8E00, 0xE463, 0x8E04, 0xE464, 0x8F10, 0xE465, 0x8F11, 0xE466, 0x8F0E, 0xE467, 0x8F0D, 0xE468, 0x9123, 0xE469, 0x911C, 0xE46A, 0x9120, 0xE46B, 0x9122, 0xE46C, 0x911F, 0xE46D, 0x911D, 0xE46E, 0x911A, 0xE46F, 0x9124, 0xE470, 0x9121, 0xE471, 0x911B, 0xE472, 0x917A, 0xE473, 0x9172, 0xE474, 0x9179, 0xE475, 0x9173, 0xE476, 0x92A5, 0xE477, 0x92A4, 0xE478, 0x9276, 0xE479, 0x929B, 0xE47A, 0x927A, 0xE47B, 0x92A0, 0xE47C, 0x9294, 0xE47D, 0x92AA, 0xE47E, 0x928D, 0xE4A1, 0x92A6, 0xE4A2, 0x929A, 0xE4A3, 0x92AB, 0xE4A4, 0x9279, 0xE4A5, 0x9297, 0xE4A6, 0x927F, 0xE4A7, 0x92A3, 0xE4A8, 0x92EE, 0xE4A9, 0x928E, 0xE4AA, 0x9282, 0xE4AB, 0x9295, 0xE4AC, 0x92A2, 0xE4AD, 0x927D, 0xE4AE, 0x9288, 0xE4AF, 0x92A1, 0xE4B0, 0x928A, 0xE4B1, 0x9286, 0xE4B2, 0x928C, 0xE4B3, 0x9299, 0xE4B4, 0x92A7, 0xE4B5, 0x927E, 0xE4B6, 0x9287, 0xE4B7, 0x92A9, 0xE4B8, 0x929D, 0xE4B9, 0x928B, 0xE4BA, 0x922D, 0xE4BB, 0x969E, 0xE4BC, 0x96A1, 0xE4BD, 0x96FF, 0xE4BE, 0x9758, 0xE4BF, 0x977D, 0xE4C0, 0x977A, 0xE4C1, 0x977E, 0xE4C2, 0x9783, 0xE4C3, 0x9780, 0xE4C4, 0x9782, 0xE4C5, 0x977B, 0xE4C6, 0x9784, 0xE4C7, 0x9781, 0xE4C8, 0x977F, 0xE4C9, 0x97CE, 0xE4CA, 0x97CD, 0xE4CB, 0x9816, 0xE4CC, 0x98AD, 0xE4CD, 0x98AE, 0xE4CE, 0x9902, 0xE4CF, 0x9900, 0xE4D0, 0x9907, 0xE4D1, 0x999D, 0xE4D2, 0x999C, 0xE4D3, 0x99C3, 0xE4D4, 0x99B9, 0xE4D5, 0x99BB, 0xE4D6, 0x99BA, 0xE4D7, 0x99C2, 0xE4D8, 0x99BD, 0xE4D9, 0x99C7, 0xE4DA, 0x9AB1, 0xE4DB, 0x9AE3, 0xE4DC, 0x9AE7, 0xE4DD, 0x9B3E, 0xE4DE, 0x9B3F, 0xE4DF, 0x9B60, 0xE4E0, 0x9B61, 0xE4E1, 0x9B5F, 0xE4E2, 0x9CF1, 0xE4E3, 0x9CF2, 0xE4E4, 0x9CF5, 0xE4E5, 0x9EA7, 0xE4E6, 0x50FF, 0xE4E7, 0x5103, 0xE4E8, 0x5130, 0xE4E9, 0x50F8, 0xE4EA, 0x5106, 0xE4EB, 0x5107, 0xE4EC, 0x50F6, 0xE4ED, 0x50FE, 0xE4EE, 0x510B, 0xE4EF, 0x510C, 0xE4F0, 0x50FD, 0xE4F1, 0x510A, 0xE4F2, 0x528B, 0xE4F3, 0x528C, 0xE4F4, 0x52F1, 0xE4F5, 0x52EF, 0xE4F6, 0x5648, 0xE4F7, 0x5642, 0xE4F8, 0x564C, 0xE4F9, 0x5635, 0xE4FA, 0x5641, 0xE4FB, 0x564A, 0xE4FC, 0x5649, 0xE4FD, 0x5646, 0xE4FE, 0x5658, 0xE540, 0x565A, 0xE541, 0x5640, 0xE542, 0x5633, 0xE543, 0x563D, 0xE544, 0x562C, 0xE545, 0x563E, 0xE546, 0x5638, 0xE547, 0x562A, 0xE548, 0x563A, 0xE549, 0x571A, 0xE54A, 0x58AB, 0xE54B, 0x589D, 0xE54C, 0x58B1, 0xE54D, 0x58A0, 0xE54E, 0x58A3, 0xE54F, 0x58AF, 0xE550, 0x58AC, 0xE551, 0x58A5, 0xE552, 0x58A1, 0xE553, 0x58FF, 0xE554, 0x5AFF, 0xE555, 0x5AF4, 0xE556, 0x5AFD, 0xE557, 0x5AF7, 0xE558, 0x5AF6, 0xE559, 0x5B03, 0xE55A, 0x5AF8, 0xE55B, 0x5B02, 0xE55C, 0x5AF9, 0xE55D, 0x5B01, 0xE55E, 0x5B07, 0xE55F, 0x5B05, 0xE560, 0x5B0F, 0xE561, 0x5C67, 0xE562, 0x5D99, 0xE563, 0x5D97, 0xE564, 0x5D9F, 0xE565, 0x5D92, 0xE566, 0x5DA2, 0xE567, 0x5D93, 0xE568, 0x5D95, 0xE569, 0x5DA0, 0xE56A, 0x5D9C, 0xE56B, 0x5DA1, 0xE56C, 0x5D9A, 0xE56D, 0x5D9E, 0xE56E, 0x5E69, 0xE56F, 0x5E5D, 0xE570, 0x5E60, 0xE571, 0x5E5C, 0xE572, 0x7DF3, 0xE573, 0x5EDB, 0xE574, 0x5EDE, 0xE575, 0x5EE1, 0xE576, 0x5F49, 0xE577, 0x5FB2, 0xE578, 0x618B, 0xE579, 0x6183, 0xE57A, 0x6179, 0xE57B, 0x61B1, 0xE57C, 0x61B0, 0xE57D, 0x61A2, 0xE57E, 0x6189, 0xE5A1, 0x619B, 0xE5A2, 0x6193, 0xE5A3, 0x61AF, 0xE5A4, 0x61AD, 0xE5A5, 0x619F, 0xE5A6, 0x6192, 0xE5A7, 0x61AA, 0xE5A8, 0x61A1, 0xE5A9, 0x618D, 0xE5AA, 0x6166, 0xE5AB, 0x61B3, 0xE5AC, 0x622D, 0xE5AD, 0x646E, 0xE5AE, 0x6470, 0xE5AF, 0x6496, 0xE5B0, 0x64A0, 0xE5B1, 0x6485, 0xE5B2, 0x6497, 0xE5B3, 0x649C, 0xE5B4, 0x648F, 0xE5B5, 0x648B, 0xE5B6, 0x648A, 0xE5B7, 0x648C, 0xE5B8, 0x64A3, 0xE5B9, 0x649F, 0xE5BA, 0x6468, 0xE5BB, 0x64B1, 0xE5BC, 0x6498, 0xE5BD, 0x6576, 0xE5BE, 0x657A, 0xE5BF, 0x6579, 0xE5C0, 0x657B, 0xE5C1, 0x65B2, 0xE5C2, 0x65B3, 0xE5C3, 0x66B5, 0xE5C4, 0x66B0, 0xE5C5, 0x66A9, 0xE5C6, 0x66B2, 0xE5C7, 0x66B7, 0xE5C8, 0x66AA, 0xE5C9, 0x66AF, 0xE5CA, 0x6A00, 0xE5CB, 0x6A06, 0xE5CC, 0x6A17, 0xE5CD, 0x69E5, 0xE5CE, 0x69F8, 0xE5CF, 0x6A15, 0xE5D0, 0x69F1, 0xE5D1, 0x69E4, 0xE5D2, 0x6A20, 0xE5D3, 0x69FF, 0xE5D4, 0x69EC, 0xE5D5, 0x69E2, 0xE5D6, 0x6A1B, 0xE5D7, 0x6A1D, 0xE5D8, 0x69FE, 0xE5D9, 0x6A27, 0xE5DA, 0x69F2, 0xE5DB, 0x69EE, 0xE5DC, 0x6A14, 0xE5DD, 0x69F7, 0xE5DE, 0x69E7, 0xE5DF, 0x6A40, 0xE5E0, 0x6A08, 0xE5E1, 0x69E6, 0xE5E2, 0x69FB, 0xE5E3, 0x6A0D, 0xE5E4, 0x69FC, 0xE5E5, 0x69EB, 0xE5E6, 0x6A09, 0xE5E7, 0x6A04, 0xE5E8, 0x6A18, 0xE5E9, 0x6A25, 0xE5EA, 0x6A0F, 0xE5EB, 0x69F6, 0xE5EC, 0x6A26, 0xE5ED, 0x6A07, 0xE5EE, 0x69F4, 0xE5EF, 0x6A16, 0xE5F0, 0x6B51, 0xE5F1, 0x6BA5, 0xE5F2, 0x6BA3, 0xE5F3, 0x6BA2, 0xE5F4, 0x6BA6, 0xE5F5, 0x6C01, 0xE5F6, 0x6C00, 0xE5F7, 0x6BFF, 0xE5F8, 0x6C02, 0xE5F9, 0x6F41, 0xE5FA, 0x6F26, 0xE5FB, 0x6F7E, 0xE5FC, 0x6F87, 0xE5FD, 0x6FC6, 0xE5FE, 0x6F92, 0xE640, 0x6F8D, 0xE641, 0x6F89, 0xE642, 0x6F8C, 0xE643, 0x6F62, 0xE644, 0x6F4F, 0xE645, 0x6F85, 0xE646, 0x6F5A, 0xE647, 0x6F96, 0xE648, 0x6F76, 0xE649, 0x6F6C, 0xE64A, 0x6F82, 0xE64B, 0x6F55, 0xE64C, 0x6F72, 0xE64D, 0x6F52, 0xE64E, 0x6F50, 0xE64F, 0x6F57, 0xE650, 0x6F94, 0xE651, 0x6F93, 0xE652, 0x6F5D, 0xE653, 0x6F00, 0xE654, 0x6F61, 0xE655, 0x6F6B, 0xE656, 0x6F7D, 0xE657, 0x6F67, 0xE658, 0x6F90, 0xE659, 0x6F53, 0xE65A, 0x6F8B, 0xE65B, 0x6F69, 0xE65C, 0x6F7F, 0xE65D, 0x6F95, 0xE65E, 0x6F63, 0xE65F, 0x6F77, 0xE660, 0x6F6A, 0xE661, 0x6F7B, 0xE662, 0x71B2, 0xE663, 0x71AF, 0xE664, 0x719B, 0xE665, 0x71B0, 0xE666, 0x71A0, 0xE667, 0x719A, 0xE668, 0x71A9, 0xE669, 0x71B5, 0xE66A, 0x719D, 0xE66B, 0x71A5, 0xE66C, 0x719E, 0xE66D, 0x71A4, 0xE66E, 0x71A1, 0xE66F, 0x71AA, 0xE670, 0x719C, 0xE671, 0x71A7, 0xE672, 0x71B3, 0xE673, 0x7298, 0xE674, 0x729A, 0xE675, 0x7358, 0xE676, 0x7352, 0xE677, 0x735E, 0xE678, 0x735F, 0xE679, 0x7360, 0xE67A, 0x735D, 0xE67B, 0x735B, 0xE67C, 0x7361, 0xE67D, 0x735A, 0xE67E, 0x7359, 0xE6A1, 0x7362, 0xE6A2, 0x7487, 0xE6A3, 0x7489, 0xE6A4, 0x748A, 0xE6A5, 0x7486, 0xE6A6, 0x7481, 0xE6A7, 0x747D, 0xE6A8, 0x7485, 0xE6A9, 0x7488, 0xE6AA, 0x747C, 0xE6AB, 0x7479, 0xE6AC, 0x7508, 0xE6AD, 0x7507, 0xE6AE, 0x757E, 0xE6AF, 0x7625, 0xE6B0, 0x761E, 0xE6B1, 0x7619, 0xE6B2, 0x761D, 0xE6B3, 0x761C, 0xE6B4, 0x7623, 0xE6B5, 0x761A, 0xE6B6, 0x7628, 0xE6B7, 0x761B, 0xE6B8, 0x769C, 0xE6B9, 0x769D, 0xE6BA, 0x769E, 0xE6BB, 0x769B, 0xE6BC, 0x778D, 0xE6BD, 0x778F, 0xE6BE, 0x7789, 0xE6BF, 0x7788, 0xE6C0, 0x78CD, 0xE6C1, 0x78BB, 0xE6C2, 0x78CF, 0xE6C3, 0x78CC, 0xE6C4, 0x78D1, 0xE6C5, 0x78CE, 0xE6C6, 0x78D4, 0xE6C7, 0x78C8, 0xE6C8, 0x78C3, 0xE6C9, 0x78C4, 0xE6CA, 0x78C9, 0xE6CB, 0x799A, 0xE6CC, 0x79A1, 0xE6CD, 0x79A0, 0xE6CE, 0x799C, 0xE6CF, 0x79A2, 0xE6D0, 0x799B, 0xE6D1, 0x6B76, 0xE6D2, 0x7A39, 0xE6D3, 0x7AB2, 0xE6D4, 0x7AB4, 0xE6D5, 0x7AB3, 0xE6D6, 0x7BB7, 0xE6D7, 0x7BCB, 0xE6D8, 0x7BBE, 0xE6D9, 0x7BAC, 0xE6DA, 0x7BCE, 0xE6DB, 0x7BAF, 0xE6DC, 0x7BB9, 0xE6DD, 0x7BCA, 0xE6DE, 0x7BB5, 0xE6DF, 0x7CC5, 0xE6E0, 0x7CC8, 0xE6E1, 0x7CCC, 0xE6E2, 0x7CCB, 0xE6E3, 0x7DF7, 0xE6E4, 0x7DDB, 0xE6E5, 0x7DEA, 0xE6E6, 0x7DE7, 0xE6E7, 0x7DD7, 0xE6E8, 0x7DE1, 0xE6E9, 0x7E03, 0xE6EA, 0x7DFA, 0xE6EB, 0x7DE6, 0xE6EC, 0x7DF6, 0xE6ED, 0x7DF1, 0xE6EE, 0x7DF0, 0xE6EF, 0x7DEE, 0xE6F0, 0x7DDF, 0xE6F1, 0x7F76, 0xE6F2, 0x7FAC, 0xE6F3, 0x7FB0, 0xE6F4, 0x7FAD, 0xE6F5, 0x7FED, 0xE6F6, 0x7FEB, 0xE6F7, 0x7FEA, 0xE6F8, 0x7FEC, 0xE6F9, 0x7FE6, 0xE6FA, 0x7FE8, 0xE6FB, 0x8064, 0xE6FC, 0x8067, 0xE6FD, 0x81A3, 0xE6FE, 0x819F, 0xE740, 0x819E, 0xE741, 0x8195, 0xE742, 0x81A2, 0xE743, 0x8199, 0xE744, 0x8197, 0xE745, 0x8216, 0xE746, 0x824F, 0xE747, 0x8253, 0xE748, 0x8252, 0xE749, 0x8250, 0xE74A, 0x824E, 0xE74B, 0x8251, 0xE74C, 0x8524, 0xE74D, 0x853B, 0xE74E, 0x850F, 0xE74F, 0x8500, 0xE750, 0x8529, 0xE751, 0x850E, 0xE752, 0x8509, 0xE753, 0x850D, 0xE754, 0x851F, 0xE755, 0x850A, 0xE756, 0x8527, 0xE757, 0x851C, 0xE758, 0x84FB, 0xE759, 0x852B, 0xE75A, 0x84FA, 0xE75B, 0x8508, 0xE75C, 0x850C, 0xE75D, 0x84F4, 0xE75E, 0x852A, 0xE75F, 0x84F2, 0xE760, 0x8515, 0xE761, 0x84F7, 0xE762, 0x84EB, 0xE763, 0x84F3, 0xE764, 0x84FC, 0xE765, 0x8512, 0xE766, 0x84EA, 0xE767, 0x84E9, 0xE768, 0x8516, 0xE769, 0x84FE, 0xE76A, 0x8528, 0xE76B, 0x851D, 0xE76C, 0x852E, 0xE76D, 0x8502, 0xE76E, 0x84FD, 0xE76F, 0x851E, 0xE770, 0x84F6, 0xE771, 0x8531, 0xE772, 0x8526, 0xE773, 0x84E7, 0xE774, 0x84E8, 0xE775, 0x84F0, 0xE776, 0x84EF, 0xE777, 0x84F9, 0xE778, 0x8518, 0xE779, 0x8520, 0xE77A, 0x8530, 0xE77B, 0x850B, 0xE77C, 0x8519, 0xE77D, 0x852F, 0xE77E, 0x8662, 0xE7A1, 0x8756, 0xE7A2, 0x8763, 0xE7A3, 0x8764, 0xE7A4, 0x8777, 0xE7A5, 0x87E1, 0xE7A6, 0x8773, 0xE7A7, 0x8758, 0xE7A8, 0x8754, 0xE7A9, 0x875B, 0xE7AA, 0x8752, 0xE7AB, 0x8761, 0xE7AC, 0x875A, 0xE7AD, 0x8751, 0xE7AE, 0x875E, 0xE7AF, 0x876D, 0xE7B0, 0x876A, 0xE7B1, 0x8750, 0xE7B2, 0x874E, 0xE7B3, 0x875F, 0xE7B4, 0x875D, 0xE7B5, 0x876F, 0xE7B6, 0x876C, 0xE7B7, 0x877A, 0xE7B8, 0x876E, 0xE7B9, 0x875C, 0xE7BA, 0x8765, 0xE7BB, 0x874F, 0xE7BC, 0x877B, 0xE7BD, 0x8775, 0xE7BE, 0x8762, 0xE7BF, 0x8767, 0xE7C0, 0x8769, 0xE7C1, 0x885A, 0xE7C2, 0x8905, 0xE7C3, 0x890C, 0xE7C4, 0x8914, 0xE7C5, 0x890B, 0xE7C6, 0x8917, 0xE7C7, 0x8918, 0xE7C8, 0x8919, 0xE7C9, 0x8906, 0xE7CA, 0x8916, 0xE7CB, 0x8911, 0xE7CC, 0x890E, 0xE7CD, 0x8909, 0xE7CE, 0x89A2, 0xE7CF, 0x89A4, 0xE7D0, 0x89A3, 0xE7D1, 0x89ED, 0xE7D2, 0x89F0, 0xE7D3, 0x89EC, 0xE7D4, 0x8ACF, 0xE7D5, 0x8AC6, 0xE7D6, 0x8AB8, 0xE7D7, 0x8AD3, 0xE7D8, 0x8AD1, 0xE7D9, 0x8AD4, 0xE7DA, 0x8AD5, 0xE7DB, 0x8ABB, 0xE7DC, 0x8AD7, 0xE7DD, 0x8ABE, 0xE7DE, 0x8AC0, 0xE7DF, 0x8AC5, 0xE7E0, 0x8AD8, 0xE7E1, 0x8AC3, 0xE7E2, 0x8ABA, 0xE7E3, 0x8ABD, 0xE7E4, 0x8AD9, 0xE7E5, 0x8C3E, 0xE7E6, 0x8C4D, 0xE7E7, 0x8C8F, 0xE7E8, 0x8CE5, 0xE7E9, 0x8CDF, 0xE7EA, 0x8CD9, 0xE7EB, 0x8CE8, 0xE7EC, 0x8CDA, 0xE7ED, 0x8CDD, 0xE7EE, 0x8CE7, 0xE7EF, 0x8DA0, 0xE7F0, 0x8D9C, 0xE7F1, 0x8DA1, 0xE7F2, 0x8D9B, 0xE7F3, 0x8E20, 0xE7F4, 0x8E23, 0xE7F5, 0x8E25, 0xE7F6, 0x8E24, 0xE7F7, 0x8E2E, 0xE7F8, 0x8E15, 0xE7F9, 0x8E1B, 0xE7FA, 0x8E16, 0xE7FB, 0x8E11, 0xE7FC, 0x8E19, 0xE7FD, 0x8E26, 0xE7FE, 0x8E27, 0xE840, 0x8E14, 0xE841, 0x8E12, 0xE842, 0x8E18, 0xE843, 0x8E13, 0xE844, 0x8E1C, 0xE845, 0x8E17, 0xE846, 0x8E1A, 0xE847, 0x8F2C, 0xE848, 0x8F24, 0xE849, 0x8F18, 0xE84A, 0x8F1A, 0xE84B, 0x8F20, 0xE84C, 0x8F23, 0xE84D, 0x8F16, 0xE84E, 0x8F17, 0xE84F, 0x9073, 0xE850, 0x9070, 0xE851, 0x906F, 0xE852, 0x9067, 0xE853, 0x906B, 0xE854, 0x912F, 0xE855, 0x912B, 0xE856, 0x9129, 0xE857, 0x912A, 0xE858, 0x9132, 0xE859, 0x9126, 0xE85A, 0x912E, 0xE85B, 0x9185, 0xE85C, 0x9186, 0xE85D, 0x918A, 0xE85E, 0x9181, 0xE85F, 0x9182, 0xE860, 0x9184, 0xE861, 0x9180, 0xE862, 0x92D0, 0xE863, 0x92C3, 0xE864, 0x92C4, 0xE865, 0x92C0, 0xE866, 0x92D9, 0xE867, 0x92B6, 0xE868, 0x92CF, 0xE869, 0x92F1, 0xE86A, 0x92DF, 0xE86B, 0x92D8, 0xE86C, 0x92E9, 0xE86D, 0x92D7, 0xE86E, 0x92DD, 0xE86F, 0x92CC, 0xE870, 0x92EF, 0xE871, 0x92C2, 0xE872, 0x92E8, 0xE873, 0x92CA, 0xE874, 0x92C8, 0xE875, 0x92CE, 0xE876, 0x92E6, 0xE877, 0x92CD, 0xE878, 0x92D5, 0xE879, 0x92C9, 0xE87A, 0x92E0, 0xE87B, 0x92DE, 0xE87C, 0x92E7, 0xE87D, 0x92D1, 0xE87E, 0x92D3, 0xE8A1, 0x92B5, 0xE8A2, 0x92E1, 0xE8A3, 0x92C6, 0xE8A4, 0x92B4, 0xE8A5, 0x957C, 0xE8A6, 0x95AC, 0xE8A7, 0x95AB, 0xE8A8, 0x95AE, 0xE8A9, 0x95B0, 0xE8AA, 0x96A4, 0xE8AB, 0x96A2, 0xE8AC, 0x96D3, 0xE8AD, 0x9705, 0xE8AE, 0x9708, 0xE8AF, 0x9702, 0xE8B0, 0x975A, 0xE8B1, 0x978A, 0xE8B2, 0x978E, 0xE8B3, 0x9788, 0xE8B4, 0x97D0, 0xE8B5, 0x97CF, 0xE8B6, 0x981E, 0xE8B7, 0x981D, 0xE8B8, 0x9826, 0xE8B9, 0x9829, 0xE8BA, 0x9828, 0xE8BB, 0x9820, 0xE8BC, 0x981B, 0xE8BD, 0x9827, 0xE8BE, 0x98B2, 0xE8BF, 0x9908, 0xE8C0, 0x98FA, 0xE8C1, 0x9911, 0xE8C2, 0x9914, 0xE8C3, 0x9916, 0xE8C4, 0x9917, 0xE8C5, 0x9915, 0xE8C6, 0x99DC, 0xE8C7, 0x99CD, 0xE8C8, 0x99CF, 0xE8C9, 0x99D3, 0xE8CA, 0x99D4, 0xE8CB, 0x99CE, 0xE8CC, 0x99C9, 0xE8CD, 0x99D6, 0xE8CE, 0x99D8, 0xE8CF, 0x99CB, 0xE8D0, 0x99D7, 0xE8D1, 0x99CC, 0xE8D2, 0x9AB3, 0xE8D3, 0x9AEC, 0xE8D4, 0x9AEB, 0xE8D5, 0x9AF3, 0xE8D6, 0x9AF2, 0xE8D7, 0x9AF1, 0xE8D8, 0x9B46, 0xE8D9, 0x9B43, 0xE8DA, 0x9B67, 0xE8DB, 0x9B74, 0xE8DC, 0x9B71, 0xE8DD, 0x9B66, 0xE8DE, 0x9B76, 0xE8DF, 0x9B75, 0xE8E0, 0x9B70, 0xE8E1, 0x9B68, 0xE8E2, 0x9B64, 0xE8E3, 0x9B6C, 0xE8E4, 0x9CFC, 0xE8E5, 0x9CFA, 0xE8E6, 0x9CFD, 0xE8E7, 0x9CFF, 0xE8E8, 0x9CF7, 0xE8E9, 0x9D07, 0xE8EA, 0x9D00, 0xE8EB, 0x9CF9, 0xE8EC, 0x9CFB, 0xE8ED, 0x9D08, 0xE8EE, 0x9D05, 0xE8EF, 0x9D04, 0xE8F0, 0x9E83, 0xE8F1, 0x9ED3, 0xE8F2, 0x9F0F, 0xE8F3, 0x9F10, 0xE8F4, 0x511C, 0xE8F5, 0x5113, 0xE8F6, 0x5117, 0xE8F7, 0x511A, 0xE8F8, 0x5111, 0xE8F9, 0x51DE, 0xE8FA, 0x5334, 0xE8FB, 0x53E1, 0xE8FC, 0x5670, 0xE8FD, 0x5660, 0xE8FE, 0x566E, 0xE940, 0x5673, 0xE941, 0x5666, 0xE942, 0x5663, 0xE943, 0x566D, 0xE944, 0x5672, 0xE945, 0x565E, 0xE946, 0x5677, 0xE947, 0x571C, 0xE948, 0x571B, 0xE949, 0x58C8, 0xE94A, 0x58BD, 0xE94B, 0x58C9, 0xE94C, 0x58BF, 0xE94D, 0x58BA, 0xE94E, 0x58C2, 0xE94F, 0x58BC, 0xE950, 0x58C6, 0xE951, 0x5B17, 0xE952, 0x5B19, 0xE953, 0x5B1B, 0xE954, 0x5B21, 0xE955, 0x5B14, 0xE956, 0x5B13, 0xE957, 0x5B10, 0xE958, 0x5B16, 0xE959, 0x5B28, 0xE95A, 0x5B1A, 0xE95B, 0x5B20, 0xE95C, 0x5B1E, 0xE95D, 0x5BEF, 0xE95E, 0x5DAC, 0xE95F, 0x5DB1, 0xE960, 0x5DA9, 0xE961, 0x5DA7, 0xE962, 0x5DB5, 0xE963, 0x5DB0, 0xE964, 0x5DAE, 0xE965, 0x5DAA, 0xE966, 0x5DA8, 0xE967, 0x5DB2, 0xE968, 0x5DAD, 0xE969, 0x5DAF, 0xE96A, 0x5DB4, 0xE96B, 0x5E67, 0xE96C, 0x5E68, 0xE96D, 0x5E66, 0xE96E, 0x5E6F, 0xE96F, 0x5EE9, 0xE970, 0x5EE7, 0xE971, 0x5EE6, 0xE972, 0x5EE8, 0xE973, 0x5EE5, 0xE974, 0x5F4B, 0xE975, 0x5FBC, 0xE976, 0x619D, 0xE977, 0x61A8, 0xE978, 0x6196, 0xE979, 0x61C5, 0xE97A, 0x61B4, 0xE97B, 0x61C6, 0xE97C, 0x61C1, 0xE97D, 0x61CC, 0xE97E, 0x61BA, 0xE9A1, 0x61BF, 0xE9A2, 0x61B8, 0xE9A3, 0x618C, 0xE9A4, 0x64D7, 0xE9A5, 0x64D6, 0xE9A6, 0x64D0, 0xE9A7, 0x64CF, 0xE9A8, 0x64C9, 0xE9A9, 0x64BD, 0xE9AA, 0x6489, 0xE9AB, 0x64C3, 0xE9AC, 0x64DB, 0xE9AD, 0x64F3, 0xE9AE, 0x64D9, 0xE9AF, 0x6533, 0xE9B0, 0x657F, 0xE9B1, 0x657C, 0xE9B2, 0x65A2, 0xE9B3, 0x66C8, 0xE9B4, 0x66BE, 0xE9B5, 0x66C0, 0xE9B6, 0x66CA, 0xE9B7, 0x66CB, 0xE9B8, 0x66CF, 0xE9B9, 0x66BD, 0xE9BA, 0x66BB, 0xE9BB, 0x66BA, 0xE9BC, 0x66CC, 0xE9BD, 0x6723, 0xE9BE, 0x6A34, 0xE9BF, 0x6A66, 0xE9C0, 0x6A49, 0xE9C1, 0x6A67, 0xE9C2, 0x6A32, 0xE9C3, 0x6A68, 0xE9C4, 0x6A3E, 0xE9C5, 0x6A5D, 0xE9C6, 0x6A6D, 0xE9C7, 0x6A76, 0xE9C8, 0x6A5B, 0xE9C9, 0x6A51, 0xE9CA, 0x6A28, 0xE9CB, 0x6A5A, 0xE9CC, 0x6A3B, 0xE9CD, 0x6A3F, 0xE9CE, 0x6A41, 0xE9CF, 0x6A6A, 0xE9D0, 0x6A64, 0xE9D1, 0x6A50, 0xE9D2, 0x6A4F, 0xE9D3, 0x6A54, 0xE9D4, 0x6A6F, 0xE9D5, 0x6A69, 0xE9D6, 0x6A60, 0xE9D7, 0x6A3C, 0xE9D8, 0x6A5E, 0xE9D9, 0x6A56, 0xE9DA, 0x6A55, 0xE9DB, 0x6A4D, 0xE9DC, 0x6A4E, 0xE9DD, 0x6A46, 0xE9DE, 0x6B55, 0xE9DF, 0x6B54, 0xE9E0, 0x6B56, 0xE9E1, 0x6BA7, 0xE9E2, 0x6BAA, 0xE9E3, 0x6BAB, 0xE9E4, 0x6BC8, 0xE9E5, 0x6BC7, 0xE9E6, 0x6C04, 0xE9E7, 0x6C03, 0xE9E8, 0x6C06, 0xE9E9, 0x6FAD, 0xE9EA, 0x6FCB, 0xE9EB, 0x6FA3, 0xE9EC, 0x6FC7, 0xE9ED, 0x6FBC, 0xE9EE, 0x6FCE, 0xE9EF, 0x6FC8, 0xE9F0, 0x6F5E, 0xE9F1, 0x6FC4, 0xE9F2, 0x6FBD, 0xE9F3, 0x6F9E, 0xE9F4, 0x6FCA, 0xE9F5, 0x6FA8, 0xE9F6, 0x7004, 0xE9F7, 0x6FA5, 0xE9F8, 0x6FAE, 0xE9F9, 0x6FBA, 0xE9FA, 0x6FAC, 0xE9FB, 0x6FAA, 0xE9FC, 0x6FCF, 0xE9FD, 0x6FBF, 0xE9FE, 0x6FB8, 0xEA40, 0x6FA2, 0xEA41, 0x6FC9, 0xEA42, 0x6FAB, 0xEA43, 0x6FCD, 0xEA44, 0x6FAF, 0xEA45, 0x6FB2, 0xEA46, 0x6FB0, 0xEA47, 0x71C5, 0xEA48, 0x71C2, 0xEA49, 0x71BF, 0xEA4A, 0x71B8, 0xEA4B, 0x71D6, 0xEA4C, 0x71C0, 0xEA4D, 0x71C1, 0xEA4E, 0x71CB, 0xEA4F, 0x71D4, 0xEA50, 0x71CA, 0xEA51, 0x71C7, 0xEA52, 0x71CF, 0xEA53, 0x71BD, 0xEA54, 0x71D8, 0xEA55, 0x71BC, 0xEA56, 0x71C6, 0xEA57, 0x71DA, 0xEA58, 0x71DB, 0xEA59, 0x729D, 0xEA5A, 0x729E, 0xEA5B, 0x7369, 0xEA5C, 0x7366, 0xEA5D, 0x7367, 0xEA5E, 0x736C, 0xEA5F, 0x7365, 0xEA60, 0x736B, 0xEA61, 0x736A, 0xEA62, 0x747F, 0xEA63, 0x749A, 0xEA64, 0x74A0, 0xEA65, 0x7494, 0xEA66, 0x7492, 0xEA67, 0x7495, 0xEA68, 0x74A1, 0xEA69, 0x750B, 0xEA6A, 0x7580, 0xEA6B, 0x762F, 0xEA6C, 0x762D, 0xEA6D, 0x7631, 0xEA6E, 0x763D, 0xEA6F, 0x7633, 0xEA70, 0x763C, 0xEA71, 0x7635, 0xEA72, 0x7632, 0xEA73, 0x7630, 0xEA74, 0x76BB, 0xEA75, 0x76E6, 0xEA76, 0x779A, 0xEA77, 0x779D, 0xEA78, 0x77A1, 0xEA79, 0x779C, 0xEA7A, 0x779B, 0xEA7B, 0x77A2, 0xEA7C, 0x77A3, 0xEA7D, 0x7795, 0xEA7E, 0x7799, 0xEAA1, 0x7797, 0xEAA2, 0x78DD, 0xEAA3, 0x78E9, 0xEAA4, 0x78E5, 0xEAA5, 0x78EA, 0xEAA6, 0x78DE, 0xEAA7, 0x78E3, 0xEAA8, 0x78DB, 0xEAA9, 0x78E1, 0xEAAA, 0x78E2, 0xEAAB, 0x78ED, 0xEAAC, 0x78DF, 0xEAAD, 0x78E0, 0xEAAE, 0x79A4, 0xEAAF, 0x7A44, 0xEAB0, 0x7A48, 0xEAB1, 0x7A47, 0xEAB2, 0x7AB6, 0xEAB3, 0x7AB8, 0xEAB4, 0x7AB5, 0xEAB5, 0x7AB1, 0xEAB6, 0x7AB7, 0xEAB7, 0x7BDE, 0xEAB8, 0x7BE3, 0xEAB9, 0x7BE7, 0xEABA, 0x7BDD, 0xEABB, 0x7BD5, 0xEABC, 0x7BE5, 0xEABD, 0x7BDA, 0xEABE, 0x7BE8, 0xEABF, 0x7BF9, 0xEAC0, 0x7BD4, 0xEAC1, 0x7BEA, 0xEAC2, 0x7BE2, 0xEAC3, 0x7BDC, 0xEAC4, 0x7BEB, 0xEAC5, 0x7BD8, 0xEAC6, 0x7BDF, 0xEAC7, 0x7CD2, 0xEAC8, 0x7CD4, 0xEAC9, 0x7CD7, 0xEACA, 0x7CD0, 0xEACB, 0x7CD1, 0xEACC, 0x7E12, 0xEACD, 0x7E21, 0xEACE, 0x7E17, 0xEACF, 0x7E0C, 0xEAD0, 0x7E1F, 0xEAD1, 0x7E20, 0xEAD2, 0x7E13, 0xEAD3, 0x7E0E, 0xEAD4, 0x7E1C, 0xEAD5, 0x7E15, 0xEAD6, 0x7E1A, 0xEAD7, 0x7E22, 0xEAD8, 0x7E0B, 0xEAD9, 0x7E0F, 0xEADA, 0x7E16, 0xEADB, 0x7E0D, 0xEADC, 0x7E14, 0xEADD, 0x7E25, 0xEADE, 0x7E24, 0xEADF, 0x7F43, 0xEAE0, 0x7F7B, 0xEAE1, 0x7F7C, 0xEAE2, 0x7F7A, 0xEAE3, 0x7FB1, 0xEAE4, 0x7FEF, 0xEAE5, 0x802A, 0xEAE6, 0x8029, 0xEAE7, 0x806C, 0xEAE8, 0x81B1, 0xEAE9, 0x81A6, 0xEAEA, 0x81AE, 0xEAEB, 0x81B9, 0xEAEC, 0x81B5, 0xEAED, 0x81AB, 0xEAEE, 0x81B0, 0xEAEF, 0x81AC, 0xEAF0, 0x81B4, 0xEAF1, 0x81B2, 0xEAF2, 0x81B7, 0xEAF3, 0x81A7, 0xEAF4, 0x81F2, 0xEAF5, 0x8255, 0xEAF6, 0x8256, 0xEAF7, 0x8257, 0xEAF8, 0x8556, 0xEAF9, 0x8545, 0xEAFA, 0x856B, 0xEAFB, 0x854D, 0xEAFC, 0x8553, 0xEAFD, 0x8561, 0xEAFE, 0x8558, 0xEB40, 0x8540, 0xEB41, 0x8546, 0xEB42, 0x8564, 0xEB43, 0x8541, 0xEB44, 0x8562, 0xEB45, 0x8544, 0xEB46, 0x8551, 0xEB47, 0x8547, 0xEB48, 0x8563, 0xEB49, 0x853E, 0xEB4A, 0x855B, 0xEB4B, 0x8571, 0xEB4C, 0x854E, 0xEB4D, 0x856E, 0xEB4E, 0x8575, 0xEB4F, 0x8555, 0xEB50, 0x8567, 0xEB51, 0x8560, 0xEB52, 0x858C, 0xEB53, 0x8566, 0xEB54, 0x855D, 0xEB55, 0x8554, 0xEB56, 0x8565, 0xEB57, 0x856C, 0xEB58, 0x8663, 0xEB59, 0x8665, 0xEB5A, 0x8664, 0xEB5B, 0x879B, 0xEB5C, 0x878F, 0xEB5D, 0x8797, 0xEB5E, 0x8793, 0xEB5F, 0x8792, 0xEB60, 0x8788, 0xEB61, 0x8781, 0xEB62, 0x8796, 0xEB63, 0x8798, 0xEB64, 0x8779, 0xEB65, 0x8787, 0xEB66, 0x87A3, 0xEB67, 0x8785, 0xEB68, 0x8790, 0xEB69, 0x8791, 0xEB6A, 0x879D, 0xEB6B, 0x8784, 0xEB6C, 0x8794, 0xEB6D, 0x879C, 0xEB6E, 0x879A, 0xEB6F, 0x8789, 0xEB70, 0x891E, 0xEB71, 0x8926, 0xEB72, 0x8930, 0xEB73, 0x892D, 0xEB74, 0x892E, 0xEB75, 0x8927, 0xEB76, 0x8931, 0xEB77, 0x8922, 0xEB78, 0x8929, 0xEB79, 0x8923, 0xEB7A, 0x892F, 0xEB7B, 0x892C, 0xEB7C, 0x891F, 0xEB7D, 0x89F1, 0xEB7E, 0x8AE0, 0xEBA1, 0x8AE2, 0xEBA2, 0x8AF2, 0xEBA3, 0x8AF4, 0xEBA4, 0x8AF5, 0xEBA5, 0x8ADD, 0xEBA6, 0x8B14, 0xEBA7, 0x8AE4, 0xEBA8, 0x8ADF, 0xEBA9, 0x8AF0, 0xEBAA, 0x8AC8, 0xEBAB, 0x8ADE, 0xEBAC, 0x8AE1, 0xEBAD, 0x8AE8, 0xEBAE, 0x8AFF, 0xEBAF, 0x8AEF, 0xEBB0, 0x8AFB, 0xEBB1, 0x8C91, 0xEBB2, 0x8C92, 0xEBB3, 0x8C90, 0xEBB4, 0x8CF5, 0xEBB5, 0x8CEE, 0xEBB6, 0x8CF1, 0xEBB7, 0x8CF0, 0xEBB8, 0x8CF3, 0xEBB9, 0x8D6C, 0xEBBA, 0x8D6E, 0xEBBB, 0x8DA5, 0xEBBC, 0x8DA7, 0xEBBD, 0x8E33, 0xEBBE, 0x8E3E, 0xEBBF, 0x8E38, 0xEBC0, 0x8E40, 0xEBC1, 0x8E45, 0xEBC2, 0x8E36, 0xEBC3, 0x8E3C, 0xEBC4, 0x8E3D, 0xEBC5, 0x8E41, 0xEBC6, 0x8E30, 0xEBC7, 0x8E3F, 0xEBC8, 0x8EBD, 0xEBC9, 0x8F36, 0xEBCA, 0x8F2E, 0xEBCB, 0x8F35, 0xEBCC, 0x8F32, 0xEBCD, 0x8F39, 0xEBCE, 0x8F37, 0xEBCF, 0x8F34, 0xEBD0, 0x9076, 0xEBD1, 0x9079, 0xEBD2, 0x907B, 0xEBD3, 0x9086, 0xEBD4, 0x90FA, 0xEBD5, 0x9133, 0xEBD6, 0x9135, 0xEBD7, 0x9136, 0xEBD8, 0x9193, 0xEBD9, 0x9190, 0xEBDA, 0x9191, 0xEBDB, 0x918D, 0xEBDC, 0x918F, 0xEBDD, 0x9327, 0xEBDE, 0x931E, 0xEBDF, 0x9308, 0xEBE0, 0x931F, 0xEBE1, 0x9306, 0xEBE2, 0x930F, 0xEBE3, 0x937A, 0xEBE4, 0x9338, 0xEBE5, 0x933C, 0xEBE6, 0x931B, 0xEBE7, 0x9323, 0xEBE8, 0x9312, 0xEBE9, 0x9301, 0xEBEA, 0x9346, 0xEBEB, 0x932D, 0xEBEC, 0x930E, 0xEBED, 0x930D, 0xEBEE, 0x92CB, 0xEBEF, 0x931D, 0xEBF0, 0x92FA, 0xEBF1, 0x9325, 0xEBF2, 0x9313, 0xEBF3, 0x92F9, 0xEBF4, 0x92F7, 0xEBF5, 0x9334, 0xEBF6, 0x9302, 0xEBF7, 0x9324, 0xEBF8, 0x92FF, 0xEBF9, 0x9329, 0xEBFA, 0x9339, 0xEBFB, 0x9335, 0xEBFC, 0x932A, 0xEBFD, 0x9314, 0xEBFE, 0x930C, 0xEC40, 0x930B, 0xEC41, 0x92FE, 0xEC42, 0x9309, 0xEC43, 0x9300, 0xEC44, 0x92FB, 0xEC45, 0x9316, 0xEC46, 0x95BC, 0xEC47, 0x95CD, 0xEC48, 0x95BE, 0xEC49, 0x95B9, 0xEC4A, 0x95BA, 0xEC4B, 0x95B6, 0xEC4C, 0x95BF, 0xEC4D, 0x95B5, 0xEC4E, 0x95BD, 0xEC4F, 0x96A9, 0xEC50, 0x96D4, 0xEC51, 0x970B, 0xEC52, 0x9712, 0xEC53, 0x9710, 0xEC54, 0x9799, 0xEC55, 0x9797, 0xEC56, 0x9794, 0xEC57, 0x97F0, 0xEC58, 0x97F8, 0xEC59, 0x9835, 0xEC5A, 0x982F, 0xEC5B, 0x9832, 0xEC5C, 0x9924, 0xEC5D, 0x991F, 0xEC5E, 0x9927, 0xEC5F, 0x9929, 0xEC60, 0x999E, 0xEC61, 0x99EE, 0xEC62, 0x99EC, 0xEC63, 0x99E5, 0xEC64, 0x99E4, 0xEC65, 0x99F0, 0xEC66, 0x99E3, 0xEC67, 0x99EA, 0xEC68, 0x99E9, 0xEC69, 0x99E7, 0xEC6A, 0x9AB9, 0xEC6B, 0x9ABF, 0xEC6C, 0x9AB4, 0xEC6D, 0x9ABB, 0xEC6E, 0x9AF6, 0xEC6F, 0x9AFA, 0xEC70, 0x9AF9, 0xEC71, 0x9AF7, 0xEC72, 0x9B33, 0xEC73, 0x9B80, 0xEC74, 0x9B85, 0xEC75, 0x9B87, 0xEC76, 0x9B7C, 0xEC77, 0x9B7E, 0xEC78, 0x9B7B, 0xEC79, 0x9B82, 0xEC7A, 0x9B93, 0xEC7B, 0x9B92, 0xEC7C, 0x9B90, 0xEC7D, 0x9B7A, 0xEC7E, 0x9B95, 0xECA1, 0x9B7D, 0xECA2, 0x9B88, 0xECA3, 0x9D25, 0xECA4, 0x9D17, 0xECA5, 0x9D20, 0xECA6, 0x9D1E, 0xECA7, 0x9D14, 0xECA8, 0x9D29, 0xECA9, 0x9D1D, 0xECAA, 0x9D18, 0xECAB, 0x9D22, 0xECAC, 0x9D10, 0xECAD, 0x9D19, 0xECAE, 0x9D1F, 0xECAF, 0x9E88, 0xECB0, 0x9E86, 0xECB1, 0x9E87, 0xECB2, 0x9EAE, 0xECB3, 0x9EAD, 0xECB4, 0x9ED5, 0xECB5, 0x9ED6, 0xECB6, 0x9EFA, 0xECB7, 0x9F12, 0xECB8, 0x9F3D, 0xECB9, 0x5126, 0xECBA, 0x5125, 0xECBB, 0x5122, 0xECBC, 0x5124, 0xECBD, 0x5120, 0xECBE, 0x5129, 0xECBF, 0x52F4, 0xECC0, 0x5693, 0xECC1, 0x568C, 0xECC2, 0x568D, 0xECC3, 0x5686, 0xECC4, 0x5684, 0xECC5, 0x5683, 0xECC6, 0x567E, 0xECC7, 0x5682, 0xECC8, 0x567F, 0xECC9, 0x5681, 0xECCA, 0x58D6, 0xECCB, 0x58D4, 0xECCC, 0x58CF, 0xECCD, 0x58D2, 0xECCE, 0x5B2D, 0xECCF, 0x5B25, 0xECD0, 0x5B32, 0xECD1, 0x5B23, 0xECD2, 0x5B2C, 0xECD3, 0x5B27, 0xECD4, 0x5B26, 0xECD5, 0x5B2F, 0xECD6, 0x5B2E, 0xECD7, 0x5B7B, 0xECD8, 0x5BF1, 0xECD9, 0x5BF2, 0xECDA, 0x5DB7, 0xECDB, 0x5E6C, 0xECDC, 0x5E6A, 0xECDD, 0x5FBE, 0xECDE, 0x5FBB, 0xECDF, 0x61C3, 0xECE0, 0x61B5, 0xECE1, 0x61BC, 0xECE2, 0x61E7, 0xECE3, 0x61E0, 0xECE4, 0x61E5, 0xECE5, 0x61E4, 0xECE6, 0x61E8, 0xECE7, 0x61DE, 0xECE8, 0x64EF, 0xECE9, 0x64E9, 0xECEA, 0x64E3, 0xECEB, 0x64EB, 0xECEC, 0x64E4, 0xECED, 0x64E8, 0xECEE, 0x6581, 0xECEF, 0x6580, 0xECF0, 0x65B6, 0xECF1, 0x65DA, 0xECF2, 0x66D2, 0xECF3, 0x6A8D, 0xECF4, 0x6A96, 0xECF5, 0x6A81, 0xECF6, 0x6AA5, 0xECF7, 0x6A89, 0xECF8, 0x6A9F, 0xECF9, 0x6A9B, 0xECFA, 0x6AA1, 0xECFB, 0x6A9E, 0xECFC, 0x6A87, 0xECFD, 0x6A93, 0xECFE, 0x6A8E, 0xED40, 0x6A95, 0xED41, 0x6A83, 0xED42, 0x6AA8, 0xED43, 0x6AA4, 0xED44, 0x6A91, 0xED45, 0x6A7F, 0xED46, 0x6AA6, 0xED47, 0x6A9A, 0xED48, 0x6A85, 0xED49, 0x6A8C, 0xED4A, 0x6A92, 0xED4B, 0x6B5B, 0xED4C, 0x6BAD, 0xED4D, 0x6C09, 0xED4E, 0x6FCC, 0xED4F, 0x6FA9, 0xED50, 0x6FF4, 0xED51, 0x6FD4, 0xED52, 0x6FE3, 0xED53, 0x6FDC, 0xED54, 0x6FED, 0xED55, 0x6FE7, 0xED56, 0x6FE6, 0xED57, 0x6FDE, 0xED58, 0x6FF2, 0xED59, 0x6FDD, 0xED5A, 0x6FE2, 0xED5B, 0x6FE8, 0xED5C, 0x71E1, 0xED5D, 0x71F1, 0xED5E, 0x71E8, 0xED5F, 0x71F2, 0xED60, 0x71E4, 0xED61, 0x71F0, 0xED62, 0x71E2, 0xED63, 0x7373, 0xED64, 0x736E, 0xED65, 0x736F, 0xED66, 0x7497, 0xED67, 0x74B2, 0xED68, 0x74AB, 0xED69, 0x7490, 0xED6A, 0x74AA, 0xED6B, 0x74AD, 0xED6C, 0x74B1, 0xED6D, 0x74A5, 0xED6E, 0x74AF, 0xED6F, 0x7510, 0xED70, 0x7511, 0xED71, 0x7512, 0xED72, 0x750F, 0xED73, 0x7584, 0xED74, 0x7643, 0xED75, 0x7648, 0xED76, 0x7649, 0xED77, 0x7647, 0xED78, 0x76A4, 0xED79, 0x76E9, 0xED7A, 0x77B5, 0xED7B, 0x77AB, 0xED7C, 0x77B2, 0xED7D, 0x77B7, 0xED7E, 0x77B6, 0xEDA1, 0x77B4, 0xEDA2, 0x77B1, 0xEDA3, 0x77A8, 0xEDA4, 0x77F0, 0xEDA5, 0x78F3, 0xEDA6, 0x78FD, 0xEDA7, 0x7902, 0xEDA8, 0x78FB, 0xEDA9, 0x78FC, 0xEDAA, 0x78F2, 0xEDAB, 0x7905, 0xEDAC, 0x78F9, 0xEDAD, 0x78FE, 0xEDAE, 0x7904, 0xEDAF, 0x79AB, 0xEDB0, 0x79A8, 0xEDB1, 0x7A5C, 0xEDB2, 0x7A5B, 0xEDB3, 0x7A56, 0xEDB4, 0x7A58, 0xEDB5, 0x7A54, 0xEDB6, 0x7A5A, 0xEDB7, 0x7ABE, 0xEDB8, 0x7AC0, 0xEDB9, 0x7AC1, 0xEDBA, 0x7C05, 0xEDBB, 0x7C0F, 0xEDBC, 0x7BF2, 0xEDBD, 0x7C00, 0xEDBE, 0x7BFF, 0xEDBF, 0x7BFB, 0xEDC0, 0x7C0E, 0xEDC1, 0x7BF4, 0xEDC2, 0x7C0B, 0xEDC3, 0x7BF3, 0xEDC4, 0x7C02, 0xEDC5, 0x7C09, 0xEDC6, 0x7C03, 0xEDC7, 0x7C01, 0xEDC8, 0x7BF8, 0xEDC9, 0x7BFD, 0xEDCA, 0x7C06, 0xEDCB, 0x7BF0, 0xEDCC, 0x7BF1, 0xEDCD, 0x7C10, 0xEDCE, 0x7C0A, 0xEDCF, 0x7CE8, 0xEDD0, 0x7E2D, 0xEDD1, 0x7E3C, 0xEDD2, 0x7E42, 0xEDD3, 0x7E33, 0xEDD4, 0x9848, 0xEDD5, 0x7E38, 0xEDD6, 0x7E2A, 0xEDD7, 0x7E49, 0xEDD8, 0x7E40, 0xEDD9, 0x7E47, 0xEDDA, 0x7E29, 0xEDDB, 0x7E4C, 0xEDDC, 0x7E30, 0xEDDD, 0x7E3B, 0xEDDE, 0x7E36, 0xEDDF, 0x7E44, 0xEDE0, 0x7E3A, 0xEDE1, 0x7F45, 0xEDE2, 0x7F7F, 0xEDE3, 0x7F7E, 0xEDE4, 0x7F7D, 0xEDE5, 0x7FF4, 0xEDE6, 0x7FF2, 0xEDE7, 0x802C, 0xEDE8, 0x81BB, 0xEDE9, 0x81C4, 0xEDEA, 0x81CC, 0xEDEB, 0x81CA, 0xEDEC, 0x81C5, 0xEDED, 0x81C7, 0xEDEE, 0x81BC, 0xEDEF, 0x81E9, 0xEDF0, 0x825B, 0xEDF1, 0x825A, 0xEDF2, 0x825C, 0xEDF3, 0x8583, 0xEDF4, 0x8580, 0xEDF5, 0x858F, 0xEDF6, 0x85A7, 0xEDF7, 0x8595, 0xEDF8, 0x85A0, 0xEDF9, 0x858B, 0xEDFA, 0x85A3, 0xEDFB, 0x857B, 0xEDFC, 0x85A4, 0xEDFD, 0x859A, 0xEDFE, 0x859E, 0xEE40, 0x8577, 0xEE41, 0x857C, 0xEE42, 0x8589, 0xEE43, 0x85A1, 0xEE44, 0x857A, 0xEE45, 0x8578, 0xEE46, 0x8557, 0xEE47, 0x858E, 0xEE48, 0x8596, 0xEE49, 0x8586, 0xEE4A, 0x858D, 0xEE4B, 0x8599, 0xEE4C, 0x859D, 0xEE4D, 0x8581, 0xEE4E, 0x85A2, 0xEE4F, 0x8582, 0xEE50, 0x8588, 0xEE51, 0x8585, 0xEE52, 0x8579, 0xEE53, 0x8576, 0xEE54, 0x8598, 0xEE55, 0x8590, 0xEE56, 0x859F, 0xEE57, 0x8668, 0xEE58, 0x87BE, 0xEE59, 0x87AA, 0xEE5A, 0x87AD, 0xEE5B, 0x87C5, 0xEE5C, 0x87B0, 0xEE5D, 0x87AC, 0xEE5E, 0x87B9, 0xEE5F, 0x87B5, 0xEE60, 0x87BC, 0xEE61, 0x87AE, 0xEE62, 0x87C9, 0xEE63, 0x87C3, 0xEE64, 0x87C2, 0xEE65, 0x87CC, 0xEE66, 0x87B7, 0xEE67, 0x87AF, 0xEE68, 0x87C4, 0xEE69, 0x87CA, 0xEE6A, 0x87B4, 0xEE6B, 0x87B6, 0xEE6C, 0x87BF, 0xEE6D, 0x87B8, 0xEE6E, 0x87BD, 0xEE6F, 0x87DE, 0xEE70, 0x87B2, 0xEE71, 0x8935, 0xEE72, 0x8933, 0xEE73, 0x893C, 0xEE74, 0x893E, 0xEE75, 0x8941, 0xEE76, 0x8952, 0xEE77, 0x8937, 0xEE78, 0x8942, 0xEE79, 0x89AD, 0xEE7A, 0x89AF, 0xEE7B, 0x89AE, 0xEE7C, 0x89F2, 0xEE7D, 0x89F3, 0xEE7E, 0x8B1E, 0xEEA1, 0x8B18, 0xEEA2, 0x8B16, 0xEEA3, 0x8B11, 0xEEA4, 0x8B05, 0xEEA5, 0x8B0B, 0xEEA6, 0x8B22, 0xEEA7, 0x8B0F, 0xEEA8, 0x8B12, 0xEEA9, 0x8B15, 0xEEAA, 0x8B07, 0xEEAB, 0x8B0D, 0xEEAC, 0x8B08, 0xEEAD, 0x8B06, 0xEEAE, 0x8B1C, 0xEEAF, 0x8B13, 0xEEB0, 0x8B1A, 0xEEB1, 0x8C4F, 0xEEB2, 0x8C70, 0xEEB3, 0x8C72, 0xEEB4, 0x8C71, 0xEEB5, 0x8C6F, 0xEEB6, 0x8C95, 0xEEB7, 0x8C94, 0xEEB8, 0x8CF9, 0xEEB9, 0x8D6F, 0xEEBA, 0x8E4E, 0xEEBB, 0x8E4D, 0xEEBC, 0x8E53, 0xEEBD, 0x8E50, 0xEEBE, 0x8E4C, 0xEEBF, 0x8E47, 0xEEC0, 0x8F43, 0xEEC1, 0x8F40, 0xEEC2, 0x9085, 0xEEC3, 0x907E, 0xEEC4, 0x9138, 0xEEC5, 0x919A, 0xEEC6, 0x91A2, 0xEEC7, 0x919B, 0xEEC8, 0x9199, 0xEEC9, 0x919F, 0xEECA, 0x91A1, 0xEECB, 0x919D, 0xEECC, 0x91A0, 0xEECD, 0x93A1, 0xEECE, 0x9383, 0xEECF, 0x93AF, 0xEED0, 0x9364, 0xEED1, 0x9356, 0xEED2, 0x9347, 0xEED3, 0x937C, 0xEED4, 0x9358, 0xEED5, 0x935C, 0xEED6, 0x9376, 0xEED7, 0x9349, 0xEED8, 0x9350, 0xEED9, 0x9351, 0xEEDA, 0x9360, 0xEEDB, 0x936D, 0xEEDC, 0x938F, 0xEEDD, 0x934C, 0xEEDE, 0x936A, 0xEEDF, 0x9379, 0xEEE0, 0x9357, 0xEEE1, 0x9355, 0xEEE2, 0x9352, 0xEEE3, 0x934F, 0xEEE4, 0x9371, 0xEEE5, 0x9377, 0xEEE6, 0x937B, 0xEEE7, 0x9361, 0xEEE8, 0x935E, 0xEEE9, 0x9363, 0xEEEA, 0x9367, 0xEEEB, 0x9380, 0xEEEC, 0x934E, 0xEEED, 0x9359, 0xEEEE, 0x95C7, 0xEEEF, 0x95C0, 0xEEF0, 0x95C9, 0xEEF1, 0x95C3, 0xEEF2, 0x95C5, 0xEEF3, 0x95B7, 0xEEF4, 0x96AE, 0xEEF5, 0x96B0, 0xEEF6, 0x96AC, 0xEEF7, 0x9720, 0xEEF8, 0x971F, 0xEEF9, 0x9718, 0xEEFA, 0x971D, 0xEEFB, 0x9719, 0xEEFC, 0x979A, 0xEEFD, 0x97A1, 0xEEFE, 0x979C, 0xEF40, 0x979E, 0xEF41, 0x979D, 0xEF42, 0x97D5, 0xEF43, 0x97D4, 0xEF44, 0x97F1, 0xEF45, 0x9841, 0xEF46, 0x9844, 0xEF47, 0x984A, 0xEF48, 0x9849, 0xEF49, 0x9845, 0xEF4A, 0x9843, 0xEF4B, 0x9925, 0xEF4C, 0x992B, 0xEF4D, 0x992C, 0xEF4E, 0x992A, 0xEF4F, 0x9933, 0xEF50, 0x9932, 0xEF51, 0x992F, 0xEF52, 0x992D, 0xEF53, 0x9931, 0xEF54, 0x9930, 0xEF55, 0x9998, 0xEF56, 0x99A3, 0xEF57, 0x99A1, 0xEF58, 0x9A02, 0xEF59, 0x99FA, 0xEF5A, 0x99F4, 0xEF5B, 0x99F7, 0xEF5C, 0x99F9, 0xEF5D, 0x99F8, 0xEF5E, 0x99F6, 0xEF5F, 0x99FB, 0xEF60, 0x99FD, 0xEF61, 0x99FE, 0xEF62, 0x99FC, 0xEF63, 0x9A03, 0xEF64, 0x9ABE, 0xEF65, 0x9AFE, 0xEF66, 0x9AFD, 0xEF67, 0x9B01, 0xEF68, 0x9AFC, 0xEF69, 0x9B48, 0xEF6A, 0x9B9A, 0xEF6B, 0x9BA8, 0xEF6C, 0x9B9E, 0xEF6D, 0x9B9B, 0xEF6E, 0x9BA6, 0xEF6F, 0x9BA1, 0xEF70, 0x9BA5, 0xEF71, 0x9BA4, 0xEF72, 0x9B86, 0xEF73, 0x9BA2, 0xEF74, 0x9BA0, 0xEF75, 0x9BAF, 0xEF76, 0x9D33, 0xEF77, 0x9D41, 0xEF78, 0x9D67, 0xEF79, 0x9D36, 0xEF7A, 0x9D2E, 0xEF7B, 0x9D2F, 0xEF7C, 0x9D31, 0xEF7D, 0x9D38, 0xEF7E, 0x9D30, 0xEFA1, 0x9D45, 0xEFA2, 0x9D42, 0xEFA3, 0x9D43, 0xEFA4, 0x9D3E, 0xEFA5, 0x9D37, 0xEFA6, 0x9D40, 0xEFA7, 0x9D3D, 0xEFA8, 0x7FF5, 0xEFA9, 0x9D2D, 0xEFAA, 0x9E8A, 0xEFAB, 0x9E89, 0xEFAC, 0x9E8D, 0xEFAD, 0x9EB0, 0xEFAE, 0x9EC8, 0xEFAF, 0x9EDA, 0xEFB0, 0x9EFB, 0xEFB1, 0x9EFF, 0xEFB2, 0x9F24, 0xEFB3, 0x9F23, 0xEFB4, 0x9F22, 0xEFB5, 0x9F54, 0xEFB6, 0x9FA0, 0xEFB7, 0x5131, 0xEFB8, 0x512D, 0xEFB9, 0x512E, 0xEFBA, 0x5698, 0xEFBB, 0x569C, 0xEFBC, 0x5697, 0xEFBD, 0x569A, 0xEFBE, 0x569D, 0xEFBF, 0x5699, 0xEFC0, 0x5970, 0xEFC1, 0x5B3C, 0xEFC2, 0x5C69, 0xEFC3, 0x5C6A, 0xEFC4, 0x5DC0, 0xEFC5, 0x5E6D, 0xEFC6, 0x5E6E, 0xEFC7, 0x61D8, 0xEFC8, 0x61DF, 0xEFC9, 0x61ED, 0xEFCA, 0x61EE, 0xEFCB, 0x61F1, 0xEFCC, 0x61EA, 0xEFCD, 0x61F0, 0xEFCE, 0x61EB, 0xEFCF, 0x61D6, 0xEFD0, 0x61E9, 0xEFD1, 0x64FF, 0xEFD2, 0x6504, 0xEFD3, 0x64FD, 0xEFD4, 0x64F8, 0xEFD5, 0x6501, 0xEFD6, 0x6503, 0xEFD7, 0x64FC, 0xEFD8, 0x6594, 0xEFD9, 0x65DB, 0xEFDA, 0x66DA, 0xEFDB, 0x66DB, 0xEFDC, 0x66D8, 0xEFDD, 0x6AC5, 0xEFDE, 0x6AB9, 0xEFDF, 0x6ABD, 0xEFE0, 0x6AE1, 0xEFE1, 0x6AC6, 0xEFE2, 0x6ABA, 0xEFE3, 0x6AB6, 0xEFE4, 0x6AB7, 0xEFE5, 0x6AC7, 0xEFE6, 0x6AB4, 0xEFE7, 0x6AAD, 0xEFE8, 0x6B5E, 0xEFE9, 0x6BC9, 0xEFEA, 0x6C0B, 0xEFEB, 0x7007, 0xEFEC, 0x700C, 0xEFED, 0x700D, 0xEFEE, 0x7001, 0xEFEF, 0x7005, 0xEFF0, 0x7014, 0xEFF1, 0x700E, 0xEFF2, 0x6FFF, 0xEFF3, 0x7000, 0xEFF4, 0x6FFB, 0xEFF5, 0x7026, 0xEFF6, 0x6FFC, 0xEFF7, 0x6FF7, 0xEFF8, 0x700A, 0xEFF9, 0x7201, 0xEFFA, 0x71FF, 0xEFFB, 0x71F9, 0xEFFC, 0x7203, 0xEFFD, 0x71FD, 0xEFFE, 0x7376, 0xF040, 0x74B8, 0xF041, 0x74C0, 0xF042, 0x74B5, 0xF043, 0x74C1, 0xF044, 0x74BE, 0xF045, 0x74B6, 0xF046, 0x74BB, 0xF047, 0x74C2, 0xF048, 0x7514, 0xF049, 0x7513, 0xF04A, 0x765C, 0xF04B, 0x7664, 0xF04C, 0x7659, 0xF04D, 0x7650, 0xF04E, 0x7653, 0xF04F, 0x7657, 0xF050, 0x765A, 0xF051, 0x76A6, 0xF052, 0x76BD, 0xF053, 0x76EC, 0xF054, 0x77C2, 0xF055, 0x77BA, 0xF056, 0x78FF, 0xF057, 0x790C, 0xF058, 0x7913, 0xF059, 0x7914, 0xF05A, 0x7909, 0xF05B, 0x7910, 0xF05C, 0x7912, 0xF05D, 0x7911, 0xF05E, 0x79AD, 0xF05F, 0x79AC, 0xF060, 0x7A5F, 0xF061, 0x7C1C, 0xF062, 0x7C29, 0xF063, 0x7C19, 0xF064, 0x7C20, 0xF065, 0x7C1F, 0xF066, 0x7C2D, 0xF067, 0x7C1D, 0xF068, 0x7C26, 0xF069, 0x7C28, 0xF06A, 0x7C22, 0xF06B, 0x7C25, 0xF06C, 0x7C30, 0xF06D, 0x7E5C, 0xF06E, 0x7E50, 0xF06F, 0x7E56, 0xF070, 0x7E63, 0xF071, 0x7E58, 0xF072, 0x7E62, 0xF073, 0x7E5F, 0xF074, 0x7E51, 0xF075, 0x7E60, 0xF076, 0x7E57, 0xF077, 0x7E53, 0xF078, 0x7FB5, 0xF079, 0x7FB3, 0xF07A, 0x7FF7, 0xF07B, 0x7FF8, 0xF07C, 0x8075, 0xF07D, 0x81D1, 0xF07E, 0x81D2, 0xF0A1, 0x81D0, 0xF0A2, 0x825F, 0xF0A3, 0x825E, 0xF0A4, 0x85B4, 0xF0A5, 0x85C6, 0xF0A6, 0x85C0, 0xF0A7, 0x85C3, 0xF0A8, 0x85C2, 0xF0A9, 0x85B3, 0xF0AA, 0x85B5, 0xF0AB, 0x85BD, 0xF0AC, 0x85C7, 0xF0AD, 0x85C4, 0xF0AE, 0x85BF, 0xF0AF, 0x85CB, 0xF0B0, 0x85CE, 0xF0B1, 0x85C8, 0xF0B2, 0x85C5, 0xF0B3, 0x85B1, 0xF0B4, 0x85B6, 0xF0B5, 0x85D2, 0xF0B6, 0x8624, 0xF0B7, 0x85B8, 0xF0B8, 0x85B7, 0xF0B9, 0x85BE, 0xF0BA, 0x8669, 0xF0BB, 0x87E7, 0xF0BC, 0x87E6, 0xF0BD, 0x87E2, 0xF0BE, 0x87DB, 0xF0BF, 0x87EB, 0xF0C0, 0x87EA, 0xF0C1, 0x87E5, 0xF0C2, 0x87DF, 0xF0C3, 0x87F3, 0xF0C4, 0x87E4, 0xF0C5, 0x87D4, 0xF0C6, 0x87DC, 0xF0C7, 0x87D3, 0xF0C8, 0x87ED, 0xF0C9, 0x87D8, 0xF0CA, 0x87E3, 0xF0CB, 0x87A4, 0xF0CC, 0x87D7, 0xF0CD, 0x87D9, 0xF0CE, 0x8801, 0xF0CF, 0x87F4, 0xF0D0, 0x87E8, 0xF0D1, 0x87DD, 0xF0D2, 0x8953, 0xF0D3, 0x894B, 0xF0D4, 0x894F, 0xF0D5, 0x894C, 0xF0D6, 0x8946, 0xF0D7, 0x8950, 0xF0D8, 0x8951, 0xF0D9, 0x8949, 0xF0DA, 0x8B2A, 0xF0DB, 0x8B27, 0xF0DC, 0x8B23, 0xF0DD, 0x8B33, 0xF0DE, 0x8B30, 0xF0DF, 0x8B35, 0xF0E0, 0x8B47, 0xF0E1, 0x8B2F, 0xF0E2, 0x8B3C, 0xF0E3, 0x8B3E, 0xF0E4, 0x8B31, 0xF0E5, 0x8B25, 0xF0E6, 0x8B37, 0xF0E7, 0x8B26, 0xF0E8, 0x8B36, 0xF0E9, 0x8B2E, 0xF0EA, 0x8B24, 0xF0EB, 0x8B3B, 0xF0EC, 0x8B3D, 0xF0ED, 0x8B3A, 0xF0EE, 0x8C42, 0xF0EF, 0x8C75, 0xF0F0, 0x8C99, 0xF0F1, 0x8C98, 0xF0F2, 0x8C97, 0xF0F3, 0x8CFE, 0xF0F4, 0x8D04, 0xF0F5, 0x8D02, 0xF0F6, 0x8D00, 0xF0F7, 0x8E5C, 0xF0F8, 0x8E62, 0xF0F9, 0x8E60, 0xF0FA, 0x8E57, 0xF0FB, 0x8E56, 0xF0FC, 0x8E5E, 0xF0FD, 0x8E65, 0xF0FE, 0x8E67, 0xF140, 0x8E5B, 0xF141, 0x8E5A, 0xF142, 0x8E61, 0xF143, 0x8E5D, 0xF144, 0x8E69, 0xF145, 0x8E54, 0xF146, 0x8F46, 0xF147, 0x8F47, 0xF148, 0x8F48, 0xF149, 0x8F4B, 0xF14A, 0x9128, 0xF14B, 0x913A, 0xF14C, 0x913B, 0xF14D, 0x913E, 0xF14E, 0x91A8, 0xF14F, 0x91A5, 0xF150, 0x91A7, 0xF151, 0x91AF, 0xF152, 0x91AA, 0xF153, 0x93B5, 0xF154, 0x938C, 0xF155, 0x9392, 0xF156, 0x93B7, 0xF157, 0x939B, 0xF158, 0x939D, 0xF159, 0x9389, 0xF15A, 0x93A7, 0xF15B, 0x938E, 0xF15C, 0x93AA, 0xF15D, 0x939E, 0xF15E, 0x93A6, 0xF15F, 0x9395, 0xF160, 0x9388, 0xF161, 0x9399, 0xF162, 0x939F, 0xF163, 0x938D, 0xF164, 0x93B1, 0xF165, 0x9391, 0xF166, 0x93B2, 0xF167, 0x93A4, 0xF168, 0x93A8, 0xF169, 0x93B4, 0xF16A, 0x93A3, 0xF16B, 0x93A5, 0xF16C, 0x95D2, 0xF16D, 0x95D3, 0xF16E, 0x95D1, 0xF16F, 0x96B3, 0xF170, 0x96D7, 0xF171, 0x96DA, 0xF172, 0x5DC2, 0xF173, 0x96DF, 0xF174, 0x96D8, 0xF175, 0x96DD, 0xF176, 0x9723, 0xF177, 0x9722, 0xF178, 0x9725, 0xF179, 0x97AC, 0xF17A, 0x97AE, 0xF17B, 0x97A8, 0xF17C, 0x97AB, 0xF17D, 0x97A4, 0xF17E, 0x97AA, 0xF1A1, 0x97A2, 0xF1A2, 0x97A5, 0xF1A3, 0x97D7, 0xF1A4, 0x97D9, 0xF1A5, 0x97D6, 0xF1A6, 0x97D8, 0xF1A7, 0x97FA, 0xF1A8, 0x9850, 0xF1A9, 0x9851, 0xF1AA, 0x9852, 0xF1AB, 0x98B8, 0xF1AC, 0x9941, 0xF1AD, 0x993C, 0xF1AE, 0x993A, 0xF1AF, 0x9A0F, 0xF1B0, 0x9A0B, 0xF1B1, 0x9A09, 0xF1B2, 0x9A0D, 0xF1B3, 0x9A04, 0xF1B4, 0x9A11, 0xF1B5, 0x9A0A, 0xF1B6, 0x9A05, 0xF1B7, 0x9A07, 0xF1B8, 0x9A06, 0xF1B9, 0x9AC0, 0xF1BA, 0x9ADC, 0xF1BB, 0x9B08, 0xF1BC, 0x9B04, 0xF1BD, 0x9B05, 0xF1BE, 0x9B29, 0xF1BF, 0x9B35, 0xF1C0, 0x9B4A, 0xF1C1, 0x9B4C, 0xF1C2, 0x9B4B, 0xF1C3, 0x9BC7, 0xF1C4, 0x9BC6, 0xF1C5, 0x9BC3, 0xF1C6, 0x9BBF, 0xF1C7, 0x9BC1, 0xF1C8, 0x9BB5, 0xF1C9, 0x9BB8, 0xF1CA, 0x9BD3, 0xF1CB, 0x9BB6, 0xF1CC, 0x9BC4, 0xF1CD, 0x9BB9, 0xF1CE, 0x9BBD, 0xF1CF, 0x9D5C, 0xF1D0, 0x9D53, 0xF1D1, 0x9D4F, 0xF1D2, 0x9D4A, 0xF1D3, 0x9D5B, 0xF1D4, 0x9D4B, 0xF1D5, 0x9D59, 0xF1D6, 0x9D56, 0xF1D7, 0x9D4C, 0xF1D8, 0x9D57, 0xF1D9, 0x9D52, 0xF1DA, 0x9D54, 0xF1DB, 0x9D5F, 0xF1DC, 0x9D58, 0xF1DD, 0x9D5A, 0xF1DE, 0x9E8E, 0xF1DF, 0x9E8C, 0xF1E0, 0x9EDF, 0xF1E1, 0x9F01, 0xF1E2, 0x9F00, 0xF1E3, 0x9F16, 0xF1E4, 0x9F25, 0xF1E5, 0x9F2B, 0xF1E6, 0x9F2A, 0xF1E7, 0x9F29, 0xF1E8, 0x9F28, 0xF1E9, 0x9F4C, 0xF1EA, 0x9F55, 0xF1EB, 0x5134, 0xF1EC, 0x5135, 0xF1ED, 0x5296, 0xF1EE, 0x52F7, 0xF1EF, 0x53B4, 0xF1F0, 0x56AB, 0xF1F1, 0x56AD, 0xF1F2, 0x56A6, 0xF1F3, 0x56A7, 0xF1F4, 0x56AA, 0xF1F5, 0x56AC, 0xF1F6, 0x58DA, 0xF1F7, 0x58DD, 0xF1F8, 0x58DB, 0xF1F9, 0x5912, 0xF1FA, 0x5B3D, 0xF1FB, 0x5B3E, 0xF1FC, 0x5B3F, 0xF1FD, 0x5DC3, 0xF1FE, 0x5E70, 0xF240, 0x5FBF, 0xF241, 0x61FB, 0xF242, 0x6507, 0xF243, 0x6510, 0xF244, 0x650D, 0xF245, 0x6509, 0xF246, 0x650C, 0xF247, 0x650E, 0xF248, 0x6584, 0xF249, 0x65DE, 0xF24A, 0x65DD, 0xF24B, 0x66DE, 0xF24C, 0x6AE7, 0xF24D, 0x6AE0, 0xF24E, 0x6ACC, 0xF24F, 0x6AD1, 0xF250, 0x6AD9, 0xF251, 0x6ACB, 0xF252, 0x6ADF, 0xF253, 0x6ADC, 0xF254, 0x6AD0, 0xF255, 0x6AEB, 0xF256, 0x6ACF, 0xF257, 0x6ACD, 0xF258, 0x6ADE, 0xF259, 0x6B60, 0xF25A, 0x6BB0, 0xF25B, 0x6C0C, 0xF25C, 0x7019, 0xF25D, 0x7027, 0xF25E, 0x7020, 0xF25F, 0x7016, 0xF260, 0x702B, 0xF261, 0x7021, 0xF262, 0x7022, 0xF263, 0x7023, 0xF264, 0x7029, 0xF265, 0x7017, 0xF266, 0x7024, 0xF267, 0x701C, 0xF268, 0x702A, 0xF269, 0x720C, 0xF26A, 0x720A, 0xF26B, 0x7207, 0xF26C, 0x7202, 0xF26D, 0x7205, 0xF26E, 0x72A5, 0xF26F, 0x72A6, 0xF270, 0x72A4, 0xF271, 0x72A3, 0xF272, 0x72A1, 0xF273, 0x74CB, 0xF274, 0x74C5, 0xF275, 0x74B7, 0xF276, 0x74C3, 0xF277, 0x7516, 0xF278, 0x7660, 0xF279, 0x77C9, 0xF27A, 0x77CA, 0xF27B, 0x77C4, 0xF27C, 0x77F1, 0xF27D, 0x791D, 0xF27E, 0x791B, 0xF2A1, 0x7921, 0xF2A2, 0x791C, 0xF2A3, 0x7917, 0xF2A4, 0x791E, 0xF2A5, 0x79B0, 0xF2A6, 0x7A67, 0xF2A7, 0x7A68, 0xF2A8, 0x7C33, 0xF2A9, 0x7C3C, 0xF2AA, 0x7C39, 0xF2AB, 0x7C2C, 0xF2AC, 0x7C3B, 0xF2AD, 0x7CEC, 0xF2AE, 0x7CEA, 0xF2AF, 0x7E76, 0xF2B0, 0x7E75, 0xF2B1, 0x7E78, 0xF2B2, 0x7E70, 0xF2B3, 0x7E77, 0xF2B4, 0x7E6F, 0xF2B5, 0x7E7A, 0xF2B6, 0x7E72, 0xF2B7, 0x7E74, 0xF2B8, 0x7E68, 0xF2B9, 0x7F4B, 0xF2BA, 0x7F4A, 0xF2BB, 0x7F83, 0xF2BC, 0x7F86, 0xF2BD, 0x7FB7, 0xF2BE, 0x7FFD, 0xF2BF, 0x7FFE, 0xF2C0, 0x8078, 0xF2C1, 0x81D7, 0xF2C2, 0x81D5, 0xF2C3, 0x8264, 0xF2C4, 0x8261, 0xF2C5, 0x8263, 0xF2C6, 0x85EB, 0xF2C7, 0x85F1, 0xF2C8, 0x85ED, 0xF2C9, 0x85D9, 0xF2CA, 0x85E1, 0xF2CB, 0x85E8, 0xF2CC, 0x85DA, 0xF2CD, 0x85D7, 0xF2CE, 0x85EC, 0xF2CF, 0x85F2, 0xF2D0, 0x85F8, 0xF2D1, 0x85D8, 0xF2D2, 0x85DF, 0xF2D3, 0x85E3, 0xF2D4, 0x85DC, 0xF2D5, 0x85D1, 0xF2D6, 0x85F0, 0xF2D7, 0x85E6, 0xF2D8, 0x85EF, 0xF2D9, 0x85DE, 0xF2DA, 0x85E2, 0xF2DB, 0x8800, 0xF2DC, 0x87FA, 0xF2DD, 0x8803, 0xF2DE, 0x87F6, 0xF2DF, 0x87F7, 0xF2E0, 0x8809, 0xF2E1, 0x880C, 0xF2E2, 0x880B, 0xF2E3, 0x8806, 0xF2E4, 0x87FC, 0xF2E5, 0x8808, 0xF2E6, 0x87FF, 0xF2E7, 0x880A, 0xF2E8, 0x8802, 0xF2E9, 0x8962, 0xF2EA, 0x895A, 0xF2EB, 0x895B, 0xF2EC, 0x8957, 0xF2ED, 0x8961, 0xF2EE, 0x895C, 0xF2EF, 0x8958, 0xF2F0, 0x895D, 0xF2F1, 0x8959, 0xF2F2, 0x8988, 0xF2F3, 0x89B7, 0xF2F4, 0x89B6, 0xF2F5, 0x89F6, 0xF2F6, 0x8B50, 0xF2F7, 0x8B48, 0xF2F8, 0x8B4A, 0xF2F9, 0x8B40, 0xF2FA, 0x8B53, 0xF2FB, 0x8B56, 0xF2FC, 0x8B54, 0xF2FD, 0x8B4B, 0xF2FE, 0x8B55, 0xF340, 0x8B51, 0xF341, 0x8B42, 0xF342, 0x8B52, 0xF343, 0x8B57, 0xF344, 0x8C43, 0xF345, 0x8C77, 0xF346, 0x8C76, 0xF347, 0x8C9A, 0xF348, 0x8D06, 0xF349, 0x8D07, 0xF34A, 0x8D09, 0xF34B, 0x8DAC, 0xF34C, 0x8DAA, 0xF34D, 0x8DAD, 0xF34E, 0x8DAB, 0xF34F, 0x8E6D, 0xF350, 0x8E78, 0xF351, 0x8E73, 0xF352, 0x8E6A, 0xF353, 0x8E6F, 0xF354, 0x8E7B, 0xF355, 0x8EC2, 0xF356, 0x8F52, 0xF357, 0x8F51, 0xF358, 0x8F4F, 0xF359, 0x8F50, 0xF35A, 0x8F53, 0xF35B, 0x8FB4, 0xF35C, 0x9140, 0xF35D, 0x913F, 0xF35E, 0x91B0, 0xF35F, 0x91AD, 0xF360, 0x93DE, 0xF361, 0x93C7, 0xF362, 0x93CF, 0xF363, 0x93C2, 0xF364, 0x93DA, 0xF365, 0x93D0, 0xF366, 0x93F9, 0xF367, 0x93EC, 0xF368, 0x93CC, 0xF369, 0x93D9, 0xF36A, 0x93A9, 0xF36B, 0x93E6, 0xF36C, 0x93CA, 0xF36D, 0x93D4, 0xF36E, 0x93EE, 0xF36F, 0x93E3, 0xF370, 0x93D5, 0xF371, 0x93C4, 0xF372, 0x93CE, 0xF373, 0x93C0, 0xF374, 0x93D2, 0xF375, 0x93E7, 0xF376, 0x957D, 0xF377, 0x95DA, 0xF378, 0x95DB, 0xF379, 0x96E1, 0xF37A, 0x9729, 0xF37B, 0x972B, 0xF37C, 0x972C, 0xF37D, 0x9728, 0xF37E, 0x9726, 0xF3A1, 0x97B3, 0xF3A2, 0x97B7, 0xF3A3, 0x97B6, 0xF3A4, 0x97DD, 0xF3A5, 0x97DE, 0xF3A6, 0x97DF, 0xF3A7, 0x985C, 0xF3A8, 0x9859, 0xF3A9, 0x985D, 0xF3AA, 0x9857, 0xF3AB, 0x98BF, 0xF3AC, 0x98BD, 0xF3AD, 0x98BB, 0xF3AE, 0x98BE, 0xF3AF, 0x9948, 0xF3B0, 0x9947, 0xF3B1, 0x9943, 0xF3B2, 0x99A6, 0xF3B3, 0x99A7, 0xF3B4, 0x9A1A, 0xF3B5, 0x9A15, 0xF3B6, 0x9A25, 0xF3B7, 0x9A1D, 0xF3B8, 0x9A24, 0xF3B9, 0x9A1B, 0xF3BA, 0x9A22, 0xF3BB, 0x9A20, 0xF3BC, 0x9A27, 0xF3BD, 0x9A23, 0xF3BE, 0x9A1E, 0xF3BF, 0x9A1C, 0xF3C0, 0x9A14, 0xF3C1, 0x9AC2, 0xF3C2, 0x9B0B, 0xF3C3, 0x9B0A, 0xF3C4, 0x9B0E, 0xF3C5, 0x9B0C, 0xF3C6, 0x9B37, 0xF3C7, 0x9BEA, 0xF3C8, 0x9BEB, 0xF3C9, 0x9BE0, 0xF3CA, 0x9BDE, 0xF3CB, 0x9BE4, 0xF3CC, 0x9BE6, 0xF3CD, 0x9BE2, 0xF3CE, 0x9BF0, 0xF3CF, 0x9BD4, 0xF3D0, 0x9BD7, 0xF3D1, 0x9BEC, 0xF3D2, 0x9BDC, 0xF3D3, 0x9BD9, 0xF3D4, 0x9BE5, 0xF3D5, 0x9BD5, 0xF3D6, 0x9BE1, 0xF3D7, 0x9BDA, 0xF3D8, 0x9D77, 0xF3D9, 0x9D81, 0xF3DA, 0x9D8A, 0xF3DB, 0x9D84, 0xF3DC, 0x9D88, 0xF3DD, 0x9D71, 0xF3DE, 0x9D80, 0xF3DF, 0x9D78, 0xF3E0, 0x9D86, 0xF3E1, 0x9D8B, 0xF3E2, 0x9D8C, 0xF3E3, 0x9D7D, 0xF3E4, 0x9D6B, 0xF3E5, 0x9D74, 0xF3E6, 0x9D75, 0xF3E7, 0x9D70, 0xF3E8, 0x9D69, 0xF3E9, 0x9D85, 0xF3EA, 0x9D73, 0xF3EB, 0x9D7B, 0xF3EC, 0x9D82, 0xF3ED, 0x9D6F, 0xF3EE, 0x9D79, 0xF3EF, 0x9D7F, 0xF3F0, 0x9D87, 0xF3F1, 0x9D68, 0xF3F2, 0x9E94, 0xF3F3, 0x9E91, 0xF3F4, 0x9EC0, 0xF3F5, 0x9EFC, 0xF3F6, 0x9F2D, 0xF3F7, 0x9F40, 0xF3F8, 0x9F41, 0xF3F9, 0x9F4D, 0xF3FA, 0x9F56, 0xF3FB, 0x9F57, 0xF3FC, 0x9F58, 0xF3FD, 0x5337, 0xF3FE, 0x56B2, 0xF440, 0x56B5, 0xF441, 0x56B3, 0xF442, 0x58E3, 0xF443, 0x5B45, 0xF444, 0x5DC6, 0xF445, 0x5DC7, 0xF446, 0x5EEE, 0xF447, 0x5EEF, 0xF448, 0x5FC0, 0xF449, 0x5FC1, 0xF44A, 0x61F9, 0xF44B, 0x6517, 0xF44C, 0x6516, 0xF44D, 0x6515, 0xF44E, 0x6513, 0xF44F, 0x65DF, 0xF450, 0x66E8, 0xF451, 0x66E3, 0xF452, 0x66E4, 0xF453, 0x6AF3, 0xF454, 0x6AF0, 0xF455, 0x6AEA, 0xF456, 0x6AE8, 0xF457, 0x6AF9, 0xF458, 0x6AF1, 0xF459, 0x6AEE, 0xF45A, 0x6AEF, 0xF45B, 0x703C, 0xF45C, 0x7035, 0xF45D, 0x702F, 0xF45E, 0x7037, 0xF45F, 0x7034, 0xF460, 0x7031, 0xF461, 0x7042, 0xF462, 0x7038, 0xF463, 0x703F, 0xF464, 0x703A, 0xF465, 0x7039, 0xF466, 0x7040, 0xF467, 0x703B, 0xF468, 0x7033, 0xF469, 0x7041, 0xF46A, 0x7213, 0xF46B, 0x7214, 0xF46C, 0x72A8, 0xF46D, 0x737D, 0xF46E, 0x737C, 0xF46F, 0x74BA, 0xF470, 0x76AB, 0xF471, 0x76AA, 0xF472, 0x76BE, 0xF473, 0x76ED, 0xF474, 0x77CC, 0xF475, 0x77CE, 0xF476, 0x77CF, 0xF477, 0x77CD, 0xF478, 0x77F2, 0xF479, 0x7925, 0xF47A, 0x7923, 0xF47B, 0x7927, 0xF47C, 0x7928, 0xF47D, 0x7924, 0xF47E, 0x7929, 0xF4A1, 0x79B2, 0xF4A2, 0x7A6E, 0xF4A3, 0x7A6C, 0xF4A4, 0x7A6D, 0xF4A5, 0x7AF7, 0xF4A6, 0x7C49, 0xF4A7, 0x7C48, 0xF4A8, 0x7C4A, 0xF4A9, 0x7C47, 0xF4AA, 0x7C45, 0xF4AB, 0x7CEE, 0xF4AC, 0x7E7B, 0xF4AD, 0x7E7E, 0xF4AE, 0x7E81, 0xF4AF, 0x7E80, 0xF4B0, 0x7FBA, 0xF4B1, 0x7FFF, 0xF4B2, 0x8079, 0xF4B3, 0x81DB, 0xF4B4, 0x81D9, 0xF4B5, 0x820B, 0xF4B6, 0x8268, 0xF4B7, 0x8269, 0xF4B8, 0x8622, 0xF4B9, 0x85FF, 0xF4BA, 0x8601, 0xF4BB, 0x85FE, 0xF4BC, 0x861B, 0xF4BD, 0x8600, 0xF4BE, 0x85F6, 0xF4BF, 0x8604, 0xF4C0, 0x8609, 0xF4C1, 0x8605, 0xF4C2, 0x860C, 0xF4C3, 0x85FD, 0xF4C4, 0x8819, 0xF4C5, 0x8810, 0xF4C6, 0x8811, 0xF4C7, 0x8817, 0xF4C8, 0x8813, 0xF4C9, 0x8816, 0xF4CA, 0x8963, 0xF4CB, 0x8966, 0xF4CC, 0x89B9, 0xF4CD, 0x89F7, 0xF4CE, 0x8B60, 0xF4CF, 0x8B6A, 0xF4D0, 0x8B5D, 0xF4D1, 0x8B68, 0xF4D2, 0x8B63, 0xF4D3, 0x8B65, 0xF4D4, 0x8B67, 0xF4D5, 0x8B6D, 0xF4D6, 0x8DAE, 0xF4D7, 0x8E86, 0xF4D8, 0x8E88, 0xF4D9, 0x8E84, 0xF4DA, 0x8F59, 0xF4DB, 0x8F56, 0xF4DC, 0x8F57, 0xF4DD, 0x8F55, 0xF4DE, 0x8F58, 0xF4DF, 0x8F5A, 0xF4E0, 0x908D, 0xF4E1, 0x9143, 0xF4E2, 0x9141, 0xF4E3, 0x91B7, 0xF4E4, 0x91B5, 0xF4E5, 0x91B2, 0xF4E6, 0x91B3, 0xF4E7, 0x940B, 0xF4E8, 0x9413, 0xF4E9, 0x93FB, 0xF4EA, 0x9420, 0xF4EB, 0x940F, 0xF4EC, 0x9414, 0xF4ED, 0x93FE, 0xF4EE, 0x9415, 0xF4EF, 0x9410, 0xF4F0, 0x9428, 0xF4F1, 0x9419, 0xF4F2, 0x940D, 0xF4F3, 0x93F5, 0xF4F4, 0x9400, 0xF4F5, 0x93F7, 0xF4F6, 0x9407, 0xF4F7, 0x940E, 0xF4F8, 0x9416, 0xF4F9, 0x9412, 0xF4FA, 0x93FA, 0xF4FB, 0x9409, 0xF4FC, 0x93F8, 0xF4FD, 0x940A, 0xF4FE, 0x93FF, 0xF540, 0x93FC, 0xF541, 0x940C, 0xF542, 0x93F6, 0xF543, 0x9411, 0xF544, 0x9406, 0xF545, 0x95DE, 0xF546, 0x95E0, 0xF547, 0x95DF, 0xF548, 0x972E, 0xF549, 0x972F, 0xF54A, 0x97B9, 0xF54B, 0x97BB, 0xF54C, 0x97FD, 0xF54D, 0x97FE, 0xF54E, 0x9860, 0xF54F, 0x9862, 0xF550, 0x9863, 0xF551, 0x985F, 0xF552, 0x98C1, 0xF553, 0x98C2, 0xF554, 0x9950, 0xF555, 0x994E, 0xF556, 0x9959, 0xF557, 0x994C, 0xF558, 0x994B, 0xF559, 0x9953, 0xF55A, 0x9A32, 0xF55B, 0x9A34, 0xF55C, 0x9A31, 0xF55D, 0x9A2C, 0xF55E, 0x9A2A, 0xF55F, 0x9A36, 0xF560, 0x9A29, 0xF561, 0x9A2E, 0xF562, 0x9A38, 0xF563, 0x9A2D, 0xF564, 0x9AC7, 0xF565, 0x9ACA, 0xF566, 0x9AC6, 0xF567, 0x9B10, 0xF568, 0x9B12, 0xF569, 0x9B11, 0xF56A, 0x9C0B, 0xF56B, 0x9C08, 0xF56C, 0x9BF7, 0xF56D, 0x9C05, 0xF56E, 0x9C12, 0xF56F, 0x9BF8, 0xF570, 0x9C40, 0xF571, 0x9C07, 0xF572, 0x9C0E, 0xF573, 0x9C06, 0xF574, 0x9C17, 0xF575, 0x9C14, 0xF576, 0x9C09, 0xF577, 0x9D9F, 0xF578, 0x9D99, 0xF579, 0x9DA4, 0xF57A, 0x9D9D, 0xF57B, 0x9D92, 0xF57C, 0x9D98, 0xF57D, 0x9D90, 0xF57E, 0x9D9B, 0xF5A1, 0x9DA0, 0xF5A2, 0x9D94, 0xF5A3, 0x9D9C, 0xF5A4, 0x9DAA, 0xF5A5, 0x9D97, 0xF5A6, 0x9DA1, 0xF5A7, 0x9D9A, 0xF5A8, 0x9DA2, 0xF5A9, 0x9DA8, 0xF5AA, 0x9D9E, 0xF5AB, 0x9DA3, 0xF5AC, 0x9DBF, 0xF5AD, 0x9DA9, 0xF5AE, 0x9D96, 0xF5AF, 0x9DA6, 0xF5B0, 0x9DA7, 0xF5B1, 0x9E99, 0xF5B2, 0x9E9B, 0xF5B3, 0x9E9A, 0xF5B4, 0x9EE5, 0xF5B5, 0x9EE4, 0xF5B6, 0x9EE7, 0xF5B7, 0x9EE6, 0xF5B8, 0x9F30, 0xF5B9, 0x9F2E, 0xF5BA, 0x9F5B, 0xF5BB, 0x9F60, 0xF5BC, 0x9F5E, 0xF5BD, 0x9F5D, 0xF5BE, 0x9F59, 0xF5BF, 0x9F91, 0xF5C0, 0x513A, 0xF5C1, 0x5139, 0xF5C2, 0x5298, 0xF5C3, 0x5297, 0xF5C4, 0x56C3, 0xF5C5, 0x56BD, 0xF5C6, 0x56BE, 0xF5C7, 0x5B48, 0xF5C8, 0x5B47, 0xF5C9, 0x5DCB, 0xF5CA, 0x5DCF, 0xF5CB, 0x5EF1, 0xF5CC, 0x61FD, 0xF5CD, 0x651B, 0xF5CE, 0x6B02, 0xF5CF, 0x6AFC, 0xF5D0, 0x6B03, 0xF5D1, 0x6AF8, 0xF5D2, 0x6B00, 0xF5D3, 0x7043, 0xF5D4, 0x7044, 0xF5D5, 0x704A, 0xF5D6, 0x7048, 0xF5D7, 0x7049, 0xF5D8, 0x7045, 0xF5D9, 0x7046, 0xF5DA, 0x721D, 0xF5DB, 0x721A, 0xF5DC, 0x7219, 0xF5DD, 0x737E, 0xF5DE, 0x7517, 0xF5DF, 0x766A, 0xF5E0, 0x77D0, 0xF5E1, 0x792D, 0xF5E2, 0x7931, 0xF5E3, 0x792F, 0xF5E4, 0x7C54, 0xF5E5, 0x7C53, 0xF5E6, 0x7CF2, 0xF5E7, 0x7E8A, 0xF5E8, 0x7E87, 0xF5E9, 0x7E88, 0xF5EA, 0x7E8B, 0xF5EB, 0x7E86, 0xF5EC, 0x7E8D, 0xF5ED, 0x7F4D, 0xF5EE, 0x7FBB, 0xF5EF, 0x8030, 0xF5F0, 0x81DD, 0xF5F1, 0x8618, 0xF5F2, 0x862A, 0xF5F3, 0x8626, 0xF5F4, 0x861F, 0xF5F5, 0x8623, 0xF5F6, 0x861C, 0xF5F7, 0x8619, 0xF5F8, 0x8627, 0xF5F9, 0x862E, 0xF5FA, 0x8621, 0xF5FB, 0x8620, 0xF5FC, 0x8629, 0xF5FD, 0x861E, 0xF5FE, 0x8625, 0xF640, 0x8829, 0xF641, 0x881D, 0xF642, 0x881B, 0xF643, 0x8820, 0xF644, 0x8824, 0xF645, 0x881C, 0xF646, 0x882B, 0xF647, 0x884A, 0xF648, 0x896D, 0xF649, 0x8969, 0xF64A, 0x896E, 0xF64B, 0x896B, 0xF64C, 0x89FA, 0xF64D, 0x8B79, 0xF64E, 0x8B78, 0xF64F, 0x8B45, 0xF650, 0x8B7A, 0xF651, 0x8B7B, 0xF652, 0x8D10, 0xF653, 0x8D14, 0xF654, 0x8DAF, 0xF655, 0x8E8E, 0xF656, 0x8E8C, 0xF657, 0x8F5E, 0xF658, 0x8F5B, 0xF659, 0x8F5D, 0xF65A, 0x9146, 0xF65B, 0x9144, 0xF65C, 0x9145, 0xF65D, 0x91B9, 0xF65E, 0x943F, 0xF65F, 0x943B, 0xF660, 0x9436, 0xF661, 0x9429, 0xF662, 0x943D, 0xF663, 0x943C, 0xF664, 0x9430, 0xF665, 0x9439, 0xF666, 0x942A, 0xF667, 0x9437, 0xF668, 0x942C, 0xF669, 0x9440, 0xF66A, 0x9431, 0xF66B, 0x95E5, 0xF66C, 0x95E4, 0xF66D, 0x95E3, 0xF66E, 0x9735, 0xF66F, 0x973A, 0xF670, 0x97BF, 0xF671, 0x97E1, 0xF672, 0x9864, 0xF673, 0x98C9, 0xF674, 0x98C6, 0xF675, 0x98C0, 0xF676, 0x9958, 0xF677, 0x9956, 0xF678, 0x9A39, 0xF679, 0x9A3D, 0xF67A, 0x9A46, 0xF67B, 0x9A44, 0xF67C, 0x9A42, 0xF67D, 0x9A41, 0xF67E, 0x9A3A, 0xF6A1, 0x9A3F, 0xF6A2, 0x9ACD, 0xF6A3, 0x9B15, 0xF6A4, 0x9B17, 0xF6A5, 0x9B18, 0xF6A6, 0x9B16, 0xF6A7, 0x9B3A, 0xF6A8, 0x9B52, 0xF6A9, 0x9C2B, 0xF6AA, 0x9C1D, 0xF6AB, 0x9C1C, 0xF6AC, 0x9C2C, 0xF6AD, 0x9C23, 0xF6AE, 0x9C28, 0xF6AF, 0x9C29, 0xF6B0, 0x9C24, 0xF6B1, 0x9C21, 0xF6B2, 0x9DB7, 0xF6B3, 0x9DB6, 0xF6B4, 0x9DBC, 0xF6B5, 0x9DC1, 0xF6B6, 0x9DC7, 0xF6B7, 0x9DCA, 0xF6B8, 0x9DCF, 0xF6B9, 0x9DBE, 0xF6BA, 0x9DC5, 0xF6BB, 0x9DC3, 0xF6BC, 0x9DBB, 0xF6BD, 0x9DB5, 0xF6BE, 0x9DCE, 0xF6BF, 0x9DB9, 0xF6C0, 0x9DBA, 0xF6C1, 0x9DAC, 0xF6C2, 0x9DC8, 0xF6C3, 0x9DB1, 0xF6C4, 0x9DAD, 0xF6C5, 0x9DCC, 0xF6C6, 0x9DB3, 0xF6C7, 0x9DCD, 0xF6C8, 0x9DB2, 0xF6C9, 0x9E7A, 0xF6CA, 0x9E9C, 0xF6CB, 0x9EEB, 0xF6CC, 0x9EEE, 0xF6CD, 0x9EED, 0xF6CE, 0x9F1B, 0xF6CF, 0x9F18, 0xF6D0, 0x9F1A, 0xF6D1, 0x9F31, 0xF6D2, 0x9F4E, 0xF6D3, 0x9F65, 0xF6D4, 0x9F64, 0xF6D5, 0x9F92, 0xF6D6, 0x4EB9, 0xF6D7, 0x56C6, 0xF6D8, 0x56C5, 0xF6D9, 0x56CB, 0xF6DA, 0x5971, 0xF6DB, 0x5B4B, 0xF6DC, 0x5B4C, 0xF6DD, 0x5DD5, 0xF6DE, 0x5DD1, 0xF6DF, 0x5EF2, 0xF6E0, 0x6521, 0xF6E1, 0x6520, 0xF6E2, 0x6526, 0xF6E3, 0x6522, 0xF6E4, 0x6B0B, 0xF6E5, 0x6B08, 0xF6E6, 0x6B09, 0xF6E7, 0x6C0D, 0xF6E8, 0x7055, 0xF6E9, 0x7056, 0xF6EA, 0x7057, 0xF6EB, 0x7052, 0xF6EC, 0x721E, 0xF6ED, 0x721F, 0xF6EE, 0x72A9, 0xF6EF, 0x737F, 0xF6F0, 0x74D8, 0xF6F1, 0x74D5, 0xF6F2, 0x74D9, 0xF6F3, 0x74D7, 0xF6F4, 0x766D, 0xF6F5, 0x76AD, 0xF6F6, 0x7935, 0xF6F7, 0x79B4, 0xF6F8, 0x7A70, 0xF6F9, 0x7A71, 0xF6FA, 0x7C57, 0xF6FB, 0x7C5C, 0xF6FC, 0x7C59, 0xF6FD, 0x7C5B, 0xF6FE, 0x7C5A, 0xF740, 0x7CF4, 0xF741, 0x7CF1, 0xF742, 0x7E91, 0xF743, 0x7F4F, 0xF744, 0x7F87, 0xF745, 0x81DE, 0xF746, 0x826B, 0xF747, 0x8634, 0xF748, 0x8635, 0xF749, 0x8633, 0xF74A, 0x862C, 0xF74B, 0x8632, 0xF74C, 0x8636, 0xF74D, 0x882C, 0xF74E, 0x8828, 0xF74F, 0x8826, 0xF750, 0x882A, 0xF751, 0x8825, 0xF752, 0x8971, 0xF753, 0x89BF, 0xF754, 0x89BE, 0xF755, 0x89FB, 0xF756, 0x8B7E, 0xF757, 0x8B84, 0xF758, 0x8B82, 0xF759, 0x8B86, 0xF75A, 0x8B85, 0xF75B, 0x8B7F, 0xF75C, 0x8D15, 0xF75D, 0x8E95, 0xF75E, 0x8E94, 0xF75F, 0x8E9A, 0xF760, 0x8E92, 0xF761, 0x8E90, 0xF762, 0x8E96, 0xF763, 0x8E97, 0xF764, 0x8F60, 0xF765, 0x8F62, 0xF766, 0x9147, 0xF767, 0x944C, 0xF768, 0x9450, 0xF769, 0x944A, 0xF76A, 0x944B, 0xF76B, 0x944F, 0xF76C, 0x9447, 0xF76D, 0x9445, 0xF76E, 0x9448, 0xF76F, 0x9449, 0xF770, 0x9446, 0xF771, 0x973F, 0xF772, 0x97E3, 0xF773, 0x986A, 0xF774, 0x9869, 0xF775, 0x98CB, 0xF776, 0x9954, 0xF777, 0x995B, 0xF778, 0x9A4E, 0xF779, 0x9A53, 0xF77A, 0x9A54, 0xF77B, 0x9A4C, 0xF77C, 0x9A4F, 0xF77D, 0x9A48, 0xF77E, 0x9A4A, 0xF7A1, 0x9A49, 0xF7A2, 0x9A52, 0xF7A3, 0x9A50, 0xF7A4, 0x9AD0, 0xF7A5, 0x9B19, 0xF7A6, 0x9B2B, 0xF7A7, 0x9B3B, 0xF7A8, 0x9B56, 0xF7A9, 0x9B55, 0xF7AA, 0x9C46, 0xF7AB, 0x9C48, 0xF7AC, 0x9C3F, 0xF7AD, 0x9C44, 0xF7AE, 0x9C39, 0xF7AF, 0x9C33, 0xF7B0, 0x9C41, 0xF7B1, 0x9C3C, 0xF7B2, 0x9C37, 0xF7B3, 0x9C34, 0xF7B4, 0x9C32, 0xF7B5, 0x9C3D, 0xF7B6, 0x9C36, 0xF7B7, 0x9DDB, 0xF7B8, 0x9DD2, 0xF7B9, 0x9DDE, 0xF7BA, 0x9DDA, 0xF7BB, 0x9DCB, 0xF7BC, 0x9DD0, 0xF7BD, 0x9DDC, 0xF7BE, 0x9DD1, 0xF7BF, 0x9DDF, 0xF7C0, 0x9DE9, 0xF7C1, 0x9DD9, 0xF7C2, 0x9DD8, 0xF7C3, 0x9DD6, 0xF7C4, 0x9DF5, 0xF7C5, 0x9DD5, 0xF7C6, 0x9DDD, 0xF7C7, 0x9EB6, 0xF7C8, 0x9EF0, 0xF7C9, 0x9F35, 0xF7CA, 0x9F33, 0xF7CB, 0x9F32, 0xF7CC, 0x9F42, 0xF7CD, 0x9F6B, 0xF7CE, 0x9F95, 0xF7CF, 0x9FA2, 0xF7D0, 0x513D, 0xF7D1, 0x5299, 0xF7D2, 0x58E8, 0xF7D3, 0x58E7, 0xF7D4, 0x5972, 0xF7D5, 0x5B4D, 0xF7D6, 0x5DD8, 0xF7D7, 0x882F, 0xF7D8, 0x5F4F, 0xF7D9, 0x6201, 0xF7DA, 0x6203, 0xF7DB, 0x6204, 0xF7DC, 0x6529, 0xF7DD, 0x6525, 0xF7DE, 0x6596, 0xF7DF, 0x66EB, 0xF7E0, 0x6B11, 0xF7E1, 0x6B12, 0xF7E2, 0x6B0F, 0xF7E3, 0x6BCA, 0xF7E4, 0x705B, 0xF7E5, 0x705A, 0xF7E6, 0x7222, 0xF7E7, 0x7382, 0xF7E8, 0x7381, 0xF7E9, 0x7383, 0xF7EA, 0x7670, 0xF7EB, 0x77D4, 0xF7EC, 0x7C67, 0xF7ED, 0x7C66, 0xF7EE, 0x7E95, 0xF7EF, 0x826C, 0xF7F0, 0x863A, 0xF7F1, 0x8640, 0xF7F2, 0x8639, 0xF7F3, 0x863C, 0xF7F4, 0x8631, 0xF7F5, 0x863B, 0xF7F6, 0x863E, 0xF7F7, 0x8830, 0xF7F8, 0x8832, 0xF7F9, 0x882E, 0xF7FA, 0x8833, 0xF7FB, 0x8976, 0xF7FC, 0x8974, 0xF7FD, 0x8973, 0xF7FE, 0x89FE, 0xF840, 0x8B8C, 0xF841, 0x8B8E, 0xF842, 0x8B8B, 0xF843, 0x8B88, 0xF844, 0x8C45, 0xF845, 0x8D19, 0xF846, 0x8E98, 0xF847, 0x8F64, 0xF848, 0x8F63, 0xF849, 0x91BC, 0xF84A, 0x9462, 0xF84B, 0x9455, 0xF84C, 0x945D, 0xF84D, 0x9457, 0xF84E, 0x945E, 0xF84F, 0x97C4, 0xF850, 0x97C5, 0xF851, 0x9800, 0xF852, 0x9A56, 0xF853, 0x9A59, 0xF854, 0x9B1E, 0xF855, 0x9B1F, 0xF856, 0x9B20, 0xF857, 0x9C52, 0xF858, 0x9C58, 0xF859, 0x9C50, 0xF85A, 0x9C4A, 0xF85B, 0x9C4D, 0xF85C, 0x9C4B, 0xF85D, 0x9C55, 0xF85E, 0x9C59, 0xF85F, 0x9C4C, 0xF860, 0x9C4E, 0xF861, 0x9DFB, 0xF862, 0x9DF7, 0xF863, 0x9DEF, 0xF864, 0x9DE3, 0xF865, 0x9DEB, 0xF866, 0x9DF8, 0xF867, 0x9DE4, 0xF868, 0x9DF6, 0xF869, 0x9DE1, 0xF86A, 0x9DEE, 0xF86B, 0x9DE6, 0xF86C, 0x9DF2, 0xF86D, 0x9DF0, 0xF86E, 0x9DE2, 0xF86F, 0x9DEC, 0xF870, 0x9DF4, 0xF871, 0x9DF3, 0xF872, 0x9DE8, 0xF873, 0x9DED, 0xF874, 0x9EC2, 0xF875, 0x9ED0, 0xF876, 0x9EF2, 0xF877, 0x9EF3, 0xF878, 0x9F06, 0xF879, 0x9F1C, 0xF87A, 0x9F38, 0xF87B, 0x9F37, 0xF87C, 0x9F36, 0xF87D, 0x9F43, 0xF87E, 0x9F4F, 0xF8A1, 0x9F71, 0xF8A2, 0x9F70, 0xF8A3, 0x9F6E, 0xF8A4, 0x9F6F, 0xF8A5, 0x56D3, 0xF8A6, 0x56CD, 0xF8A7, 0x5B4E, 0xF8A8, 0x5C6D, 0xF8A9, 0x652D, 0xF8AA, 0x66ED, 0xF8AB, 0x66EE, 0xF8AC, 0x6B13, 0xF8AD, 0x705F, 0xF8AE, 0x7061, 0xF8AF, 0x705D, 0xF8B0, 0x7060, 0xF8B1, 0x7223, 0xF8B2, 0x74DB, 0xF8B3, 0x74E5, 0xF8B4, 0x77D5, 0xF8B5, 0x7938, 0xF8B6, 0x79B7, 0xF8B7, 0x79B6, 0xF8B8, 0x7C6A, 0xF8B9, 0x7E97, 0xF8BA, 0x7F89, 0xF8BB, 0x826D, 0xF8BC, 0x8643, 0xF8BD, 0x8838, 0xF8BE, 0x8837, 0xF8BF, 0x8835, 0xF8C0, 0x884B, 0xF8C1, 0x8B94, 0xF8C2, 0x8B95, 0xF8C3, 0x8E9E, 0xF8C4, 0x8E9F, 0xF8C5, 0x8EA0, 0xF8C6, 0x8E9D, 0xF8C7, 0x91BE, 0xF8C8, 0x91BD, 0xF8C9, 0x91C2, 0xF8CA, 0x946B, 0xF8CB, 0x9468, 0xF8CC, 0x9469, 0xF8CD, 0x96E5, 0xF8CE, 0x9746, 0xF8CF, 0x9743, 0xF8D0, 0x9747, 0xF8D1, 0x97C7, 0xF8D2, 0x97E5, 0xF8D3, 0x9A5E, 0xF8D4, 0x9AD5, 0xF8D5, 0x9B59, 0xF8D6, 0x9C63, 0xF8D7, 0x9C67, 0xF8D8, 0x9C66, 0xF8D9, 0x9C62, 0xF8DA, 0x9C5E, 0xF8DB, 0x9C60, 0xF8DC, 0x9E02, 0xF8DD, 0x9DFE, 0xF8DE, 0x9E07, 0xF8DF, 0x9E03, 0xF8E0, 0x9E06, 0xF8E1, 0x9E05, 0xF8E2, 0x9E00, 0xF8E3, 0x9E01, 0xF8E4, 0x9E09, 0xF8E5, 0x9DFF, 0xF8E6, 0x9DFD, 0xF8E7, 0x9E04, 0xF8E8, 0x9EA0, 0xF8E9, 0x9F1E, 0xF8EA, 0x9F46, 0xF8EB, 0x9F74, 0xF8EC, 0x9F75, 0xF8ED, 0x9F76, 0xF8EE, 0x56D4, 0xF8EF, 0x652E, 0xF8F0, 0x65B8, 0xF8F1, 0x6B18, 0xF8F2, 0x6B19, 0xF8F3, 0x6B17, 0xF8F4, 0x6B1A, 0xF8F5, 0x7062, 0xF8F6, 0x7226, 0xF8F7, 0x72AA, 0xF8F8, 0x77D8, 0xF8F9, 0x77D9, 0xF8FA, 0x7939, 0xF8FB, 0x7C69, 0xF8FC, 0x7C6B, 0xF8FD, 0x7CF6, 0xF8FE, 0x7E9A, 0xF940, 0x7E98, 0xF941, 0x7E9B, 0xF942, 0x7E99, 0xF943, 0x81E0, 0xF944, 0x81E1, 0xF945, 0x8646, 0xF946, 0x8647, 0xF947, 0x8648, 0xF948, 0x8979, 0xF949, 0x897A, 0xF94A, 0x897C, 0xF94B, 0x897B, 0xF94C, 0x89FF, 0xF94D, 0x8B98, 0xF94E, 0x8B99, 0xF94F, 0x8EA5, 0xF950, 0x8EA4, 0xF951, 0x8EA3, 0xF952, 0x946E, 0xF953, 0x946D, 0xF954, 0x946F, 0xF955, 0x9471, 0xF956, 0x9473, 0xF957, 0x9749, 0xF958, 0x9872, 0xF959, 0x995F, 0xF95A, 0x9C68, 0xF95B, 0x9C6E, 0xF95C, 0x9C6D, 0xF95D, 0x9E0B, 0xF95E, 0x9E0D, 0xF95F, 0x9E10, 0xF960, 0x9E0F, 0xF961, 0x9E12, 0xF962, 0x9E11, 0xF963, 0x9EA1, 0xF964, 0x9EF5, 0xF965, 0x9F09, 0xF966, 0x9F47, 0xF967, 0x9F78, 0xF968, 0x9F7B, 0xF969, 0x9F7A, 0xF96A, 0x9F79, 0xF96B, 0x571E, 0xF96C, 0x7066, 0xF96D, 0x7C6F, 0xF96E, 0x883C, 0xF96F, 0x8DB2, 0xF970, 0x8EA6, 0xF971, 0x91C3, 0xF972, 0x9474, 0xF973, 0x9478, 0xF974, 0x9476, 0xF975, 0x9475, 0xF976, 0x9A60, 0xF977, 0x9C74, 0xF978, 0x9C73, 0xF979, 0x9C71, 0xF97A, 0x9C75, 0xF97B, 0x9E14, 0xF97C, 0x9E13, 0xF97D, 0x9EF6, 0xF97E, 0x9F0A, 0xF9A1, 0x9FA4, 0xF9A2, 0x7068, 0xF9A3, 0x7065, 0xF9A4, 0x7CF7, 0xF9A5, 0x866A, 0xF9A6, 0x883E, 0xF9A7, 0x883D, 0xF9A8, 0x883F, 0xF9A9, 0x8B9E, 0xF9AA, 0x8C9C, 0xF9AB, 0x8EA9, 0xF9AC, 0x8EC9, 0xF9AD, 0x974B, 0xF9AE, 0x9873, 0xF9AF, 0x9874, 0xF9B0, 0x98CC, 0xF9B1, 0x9961, 0xF9B2, 0x99AB, 0xF9B3, 0x9A64, 0xF9B4, 0x9A66, 0xF9B5, 0x9A67, 0xF9B6, 0x9B24, 0xF9B7, 0x9E15, 0xF9B8, 0x9E17, 0xF9B9, 0x9F48, 0xF9BA, 0x6207, 0xF9BB, 0x6B1E, 0xF9BC, 0x7227, 0xF9BD, 0x864C, 0xF9BE, 0x8EA8, 0xF9BF, 0x9482, 0xF9C0, 0x9480, 0xF9C1, 0x9481, 0xF9C2, 0x9A69, 0xF9C3, 0x9A68, 0xF9C4, 0x9B2E, 0xF9C5, 0x9E19, 0xF9C6, 0x7229, 0xF9C7, 0x864B, 0xF9C8, 0x8B9F, 0xF9C9, 0x9483, 0xF9CA, 0x9C79, 0xF9CB, 0x9EB7, 0xF9CC, 0x7675, 0xF9CD, 0x9A6B, 0xF9CE, 0x9C7A, 0xF9CF, 0x9E1D, 0xF9D0, 0x7069, 0xF9D1, 0x706A, 0xF9D2, 0x9EA4, 0xF9D3, 0x9F7E, 0xF9D4, 0x9F49, 0xF9D5, 0x9F98, 0xF9D6, 0x7881, 0xF9D7, 0x92B9, 0xF9D8, 0x88CF, 0xF9D9, 0x58BB, 0xF9DA, 0x6052, 0xF9DB, 0x7CA7, 0xF9DC, 0x5AFA, 0xF9DD, 0x2554, 0xF9DE, 0x2566, 0xF9DF, 0x2557, 0xF9E0, 0x2560, 0xF9E1, 0x256C, 0xF9E2, 0x2563, 0xF9E3, 0x255A, 0xF9E4, 0x2569, 0xF9E5, 0x255D, 0xF9E6, 0x2552, 0xF9E7, 0x2564, 0xF9E8, 0x2555, 0xF9E9, 0x255E, 0xF9EA, 0x256A, 0xF9EB, 0x2561, 0xF9EC, 0x2558, 0xF9ED, 0x2567, 0xF9EE, 0x255B, 0xF9EF, 0x2553, 0xF9F0, 0x2565, 0xF9F1, 0x2556, 0xF9F2, 0x255F, 0xF9F3, 0x256B, 0xF9F4, 0x2562, 0xF9F5, 0x2559, 0xF9F6, 0x2568, 0xF9F7, 0x255C, 0xF9F8, 0x2551, 0xF9F9, 0x2550, 0xF9FA, 0x256D, 0xF9FB, 0x256E, 0xF9FC, 0x2570, 0xF9FD, 0x256F, 0xF9FE, 0x2593, 0, 0 }; #endif #if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 }; #endif #if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 }; #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* SBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (oem < 0x100) c = p[oem - 0x80]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* DBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ uc = (WCHAR)uni; p = CVTBL(uni2oem, FF_CODE_PAGE); hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i = 0, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ p = CVTBL(oem2uni, FF_CODE_PAGE); hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for dynamic code page configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000) { /* Is it in BMP? */ uc = (WCHAR)uni; p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ p = cp_table[i]; if (p) { /* Is it valid code page ? */ for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ c = (c + 0x80) & 0xFF; } } else { /* DBCS */ switch (cp) { /* Get conversion table */ case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; } if (p) { /* Is it valid code page? */ li = 0; for (n = 16; n; n--) { /* Find OEM code */ i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ p = cp_table[i]; if (p) { /* Is it a valid CP ? */ if (oem < 0x100) c = p[oem - 0x80]; } } else { /* DBCS */ switch (cp) { case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; } if (p) { li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } return c; } #endif /*------------------------------------------------------------------------*/ /* Unicode up-case conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { const WORD *p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, /* Latin Extended-A */ 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, 0x0000 /* EOT */ }; static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ 0x1E00,0x0196, 0x1EA0,0x015A, /* Greek Extended */ 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ 0x2170,0x0210, 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ 0x24D0,0x051A, 0x2C30,0x042F, /* Latin Extended-C */ 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ 0x2D00,0x0826, /* Full-width */ 0xFF41,0x031A, 0x0000 /* EOT */ }; if (uni < 0x10000) { /* Is it in BMP? */ uc = (WORD)uni; p = uc < 0x1000 ? cvt1 : cvt2; for (;;) { bc = *p++; /* Get the block base */ if (bc == 0 || uc < bc) break; /* Not matched? */ nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ if (uc < bc + nc) { /* In the block? */ switch (cmd) { case 0: uc = p[uc - bc]; break; /* Table conversion */ case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ case 2: uc -= 16; break; /* Shift -16 */ case 3: uc -= 32; break; /* Shift -32 */ case 4: uc -= 48; break; /* Shift -48 */ case 5: uc -= 26; break; /* Shift -26 */ case 6: uc += 8; break; /* Shift +8 */ case 7: uc -= 80; break; /* Shift -80 */ case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ } break; } if (cmd == 0) p += nc; /* Skip table if needed */ } uni = uc; } return uni; } #endif /* #if FF_USE_LFN */ ================================================ FILE: exosphere/mariko_fatal/source/fs/fatal_fs_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../fatfs/ff.h" #include "fatal_fs_api.hpp" namespace ams::fs { namespace { constexpr size_t MaxFiles = 8; constinit bool g_is_sd_mounted = false; FATFS g_sd_fs; constinit FIL g_files[MaxFiles] = {}; constinit bool g_files_opened[MaxFiles] = {}; constinit int g_open_modes[MaxFiles] = {}; Result TranslateFatFsError(FRESULT res) { switch (res) { case FR_OK: R_SUCCEED(); case FR_DISK_ERR: R_THROW(fs::ResultMmcAccessFailed()); case FR_INT_ERR: R_THROW(fs::ResultPreconditionViolation()); case FR_NOT_READY: R_THROW(fs::ResultMmcAccessFailed()); case FR_NO_FILE: R_THROW(fs::ResultPathNotFound()); case FR_NO_PATH: R_THROW(fs::ResultPathNotFound()); case FR_INVALID_NAME: R_THROW(fs::ResultInvalidPath()); case FR_DENIED: R_THROW(fs::ResultPermissionDenied()); case FR_EXIST: R_THROW(fs::ResultPathAlreadyExists()); case FR_INVALID_OBJECT: R_THROW(fs::ResultInvalidArgument()); case FR_WRITE_PROTECTED: R_THROW(fs::ResultWriteNotPermitted()); case FR_INVALID_DRIVE: R_THROW(fs::ResultInvalidMountName()); case FR_NOT_ENABLED: R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */ case FR_NO_FILESYSTEM: R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */ case FR_TIMEOUT: R_THROW(fs::ResultTargetLocked()); /* BAD/TODO */ case FR_LOCKED: R_THROW(fs::ResultTargetLocked()); case FR_NOT_ENOUGH_CORE: R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */ case FR_TOO_MANY_OPEN_FILES: R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */ case FR_INVALID_PARAMETER: R_THROW(fs::ResultInvalidArgument()); default: R_THROW(fs::ResultInternal()); } } int TranslateToFatFsMode(int mode) { int fmode = FA_OPEN_EXISTING; if ((mode & OpenMode_Read) != 0) { fmode |= FA_READ; } if ((mode & OpenMode_Write) != 0) { fmode |= FA_WRITE; } if ((mode & OpenMode_AllowAppend) != 0) { fmode |= FA_OPEN_APPEND; } return fmode; } FIL *GetInternalFile(FileHandle handle) { return static_cast<FIL *>(handle._handle); } ALWAYS_INLINE size_t GetFileIndex(FIL *fp) { const size_t file_index = (fp - g_files); AMS_ASSERT(file_index < MaxFiles); return file_index; } } bool MountSdCard() { AMS_ASSERT(!g_is_sd_mounted); g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc", 1) == FR_OK; return g_is_sd_mounted; } void UnmountSdCard() { AMS_ASSERT(g_is_sd_mounted); f_unmount("sdmc"); g_is_sd_mounted = false; } Result CreateFile(const char *path, s64 size) { /* Create the file. */ FIL fp; R_TRY(TranslateFatFsError(f_open(std::addressof(fp), path, FA_CREATE_NEW | FA_READ | FA_WRITE))); /* Ensure that we close the file when we're done with it. */ ON_SCOPE_EXIT { f_close(std::addressof(fp)); }; /* Expand the file. */ R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1))); R_SUCCEED(); } Result CreateDirectory(const char *path) { R_RETURN(TranslateFatFsError(f_mkdir(path))); } Result OpenFile(FileHandle *out_file, const char *path, int mode) { /* Find a free file. */ for (size_t i = 0; i < MaxFiles; ++i) { if (!g_files_opened[i]) { /* Open the file. */ FIL *fp = std::addressof(g_files[i]); R_TRY(TranslateFatFsError(f_open(fp, path, TranslateToFatFsMode(mode)))); /* Set the output. */ out_file->_handle = fp; g_files_opened[i] = true; g_open_modes[i] = mode; R_SUCCEED(); } } R_THROW(fs::ResultOpenCountLimit()); } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { /* Option is unused. */ AMS_UNUSED(option); /* Seek to the offset we're reading at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Read the data. */ u32 br; R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br)))); /* Check that we read the correct amount. */ R_UNLESS(br == size, fs::ResultOutOfRange()); R_SUCCEED(); } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) { R_RETURN(ReadFile(handle, offset, buffer, size, fs::ReadOption::None)); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { /* Option is unused. */ AMS_UNUSED(option); /* Seek to the offset we're reading at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Read the data. */ u32 br; R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br)))); /* Set the output size. */ *out = br; R_SUCCEED(); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) { R_RETURN(ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None)); } Result GetFileSize(s64 *out, FileHandle handle) { FIL *fp = GetInternalFile(handle); *out = f_size(fp); R_SUCCEED(); } Result FlushFile(FileHandle handle) { R_RETURN(TranslateFatFsError(f_sync(GetInternalFile(handle)))); } Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { /* Seek to the offset we're writing at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Write the data. */ u32 bw; R_TRY(TranslateFatFsError(f_write(GetInternalFile(handle), buffer, size, std::addressof(bw)))); /* Check that we wrote the correct amount. */ R_UNLESS(bw == size, fs::ResultOutOfRange()); /* If we should, flush the file. */ if (option.HasFlushFlag()) { R_TRY(FlushFile(handle)); } R_SUCCEED(); } Result SetFileSize(FileHandle handle, s64 size) { FIL *fp = GetInternalFile(handle); /* Check if we have nothing to do. */ const size_t fsize = f_size(fp); R_SUCCEED_IF(static_cast<FSIZE_t>(size) == fsize); /* NOTE/TODO: This may not preserve file data. Do this in a way that does? */ /* Truncate the file. */ R_TRY(TranslateFatFsError(f_truncate(fp))); /* Expand the file. */ R_TRY(TranslateFatFsError(f_expand(fp, size, 1))); /* Ensure the file is synchronized. */ R_TRY(FlushFile(handle)); /* Check that our expansion succeeded. */ AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size)); R_SUCCEED(); } int GetFileOpenMode(FileHandle handle) { return g_open_modes[GetFileIndex(GetInternalFile(handle))]; } void CloseFile(FileHandle handle) { const size_t index = GetFileIndex(GetInternalFile(handle)); f_close(std::addressof(g_files[index])); g_open_modes[index] = 0; g_files_opened[index] = false; } } ================================================ FILE: exosphere/mariko_fatal/source/fs/fatal_fs_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::fs { enum OpenMode { OpenMode_Read = (1 << 0), OpenMode_Write = (1 << 1), OpenMode_AllowAppend = (1 << 2), OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write), OpenMode_All = (OpenMode_ReadWrite | OpenMode_AllowAppend), }; struct ReadOption { u32 _value; static const ReadOption None; }; inline constexpr const ReadOption ReadOption::None = {0}; inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32)); struct WriteOption { u32 _value; constexpr inline bool HasFlushFlag() const { return _value & 1; } static const WriteOption None; static const WriteOption Flush; }; inline constexpr const WriteOption WriteOption::None = {0}; inline constexpr const WriteOption WriteOption::Flush = {1}; inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32)); struct FileHandle { void *_handle; }; bool MountSdCard(); void UnmountSdCard(); Result CreateFile(const char *path, s64 size); Result CreateDirectory(const char *path); Result OpenFile(FileHandle *out_file, const char *path, int mode); Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size); Result GetFileSize(s64 *out, FileHandle handle); Result FlushFile(FileHandle handle); Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option); Result SetFileSize(FileHandle handle, s64 size); int GetFileOpenMode(FileHandle handle); void CloseFile(FileHandle handle); } ================================================ FILE: exosphere/program/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/program/program.ld ================================================ OUTPUT_ARCH(aarch64) ENTRY(_start) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K unused_region : ORIGIN = 0x1000, LENGTH = 4K iram_boot_code : ORIGIN = 0x040032000, LENGTH = 4K iram_boot_keys : ORIGIN = 0x040033000, LENGTH = 4K tzram : ORIGIN = 0x07C010000, LENGTH = 64K /* Warmboot code follows the vectors in memory. */ /* However, we can't know for sure how big warmboot is, so we'll just say it's 2K. */ warmboot_text : ORIGIN = ORIGIN(tzram) + 10K, LENGTH = 2K main : ORIGIN = 0x1F00C0000, LENGTH = 48K debug_code : ORIGIN = 0x1F0150000, LENGTH = 16K tzram_boot : ORIGIN = 0x1F01C0800, LENGTH = 6K glob : ORIGIN = 0x040032000, LENGTH = 128K } SECTIONS { .metadata : { . = ALIGN(8); KEEP (*(.metadata .metadata.*)) . = ALIGN(8); } >unused_region AT>glob PROVIDE(__glob_start__ = ORIGIN(glob)); . = __glob_start__; __bootcode_start__ = ABSOLUTE(.); .crt0 : { KEEP (*(.crt0 .crt0.*)) KEEP (secmon_crt0_cpp.o(.text*)) KEEP (secmon_make_page_table.o(.text*)) *(.crt0.rodata*) secmon_crt0_cpp.o(.rodata*) secmon_make_page_table.o(.rodata*) *(.crt0.data*) secmon_crt0_cpp.o(.data*) secmon_make_page_table.o(.data*) . = ALIGN(8); } >iram_boot_code AT>glob .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >iram_boot_code AT>glob .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >iram_boot_code AT>glob .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >iram_boot_code AT>glob .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >iram_boot_code AT>glob .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >iram_boot_code AT>glob .boot_code.fill : { FILL(0x00000000); . = ORIGIN(iram_boot_code) + 0xFFF; BYTE(0x00); } >iram_boot_code AT>glob .boot_code_volatile_keys : { KEEP (*(.volatile_keys .volatile_keys.*)) } >iram_boot_keys AT>glob .boot_keys.fill : { FILL(0x00000000); . = ORIGIN(iram_boot_keys) + 0xFFF; BYTE(0x00); } >iram_boot_keys AT>glob .debug_code : { KEEP (*(.text._ZN3ams3log6PrintfEPKcz .text._ZN3ams3log7VPrintfEPKcSt9__va_list .text._ZN3ams3log4DumpEPKvm)) KEEP (*(.text._ZN3ams4util10TVSNPrintfEPcmPKcSt9__va_list .text._ZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_list .text._ZZN3ams4util12_GLOBAL__N_114TVSNPrintfImplEPcmPKcSt9__va_listENKUlbmE3_clEbm)) KEEP (*(.text._ZN3ams4util12_GLOBAL__N_1L14TVSNPrintfImplEPcmPKcSt9__va_list .text._ZZN3ams4util12_GLOBAL__N_1L14TVSNPrintfImplEPcmPKcSt9__va_listENKUlbmE_clEbm)) KEEP(secmon_exception_handler.o(.text*)) secmon_exception_handler.o(.rodata*) secmon_exception_handler.o(.data*) } >debug_code AT>glob .debug_code.bss_fill : { FILL(0x00000000); secmon_exception_handler.o(.bss* COMMON) . = ORIGIN(debug_code) + LENGTH(debug_code) - 1; BYTE(0x00); } >debug_code AT>glob __bootcode_end__ = ABSOLUTE(.) - ORIGIN(debug_code) + 0x40034000; __program_start__ = __bootcode_end__; .tzram_boot_code : { KEEP(secmon_main.o(.text*)) KEEP(secmon_boot_functions.o(.text*)) KEEP(secmon_boot_cache.o(.text*)) KEEP(secmon_boot_config.o(.text*)) KEEP(secmon_boot_setup.o(.text*)) KEEP(secmon_boot_rsa.o(.text*)) KEEP(secmon_package2.o(.text*)) secmon_main.o(.rodata*) secmon_boot_functions.o(.rodata*) secmon_boot_cache.o(.rodata*) secmon_boot_config.o(.rodata*) secmon_boot_setup.o(.rodata*) secmon_boot_rsa.o(.rodata*) secmon_package2.o(.rodata*) secmon_main.o(.data*) secmon_boot_functions.o(.data*) secmon_boot_cache.o(.data*) secmon_boot_config.o(.data*) secmon_boot_setup.o(.data*) secmon_boot_rsa.o(.data*) secmon_package2.o(.data*) . = ALIGN(8); } >tzram_boot AT>glob .tzram_boot_code.bss_fill : { FILL(0x00000000); __boot_bss_start__ = ABSOLUTE(.); secmon_main.o(.bss* COMMON) secmon_boot_functions.o(.bss* COMMON) secmon_boot_cache.o(.bss* COMMON) secmon_boot_config.o(.bss* COMMON) secmon_boot_setup.o(.bss* COMMON) secmon_boot_rsa.o(.bss* COMMON) secmon_package2.o(.bss* COMMON) __boot_bss_end__ = ABSOLUTE(.); . = ORIGIN(tzram_boot) + LENGTH(tzram_boot) - 1; BYTE(0x00); } > tzram_boot AT>glob .vectors : { KEEP (*(.vectors*)) . = ALIGN(0x100); } >main AT>glob .warmboot : { KEEP (*(.warmboot.text.start)) /* Should be first */ KEEP (*(.warmboot.text*)) KEEP(secmon_setup_warm.o(.text*)) KEEP(*(.text._ZN3ams4tsec4LockEv)) KEEP (*(.warmboot.rodata*)) KEEP(secmon_setup_warm.o(.rodata*)) KEEP (*(.warmboot.data*)) KEEP(secmon_setup_warm.o(.data*)) } >warmboot_text AT>glob .text ORIGIN(main) + SIZEOF(.vectors) + SIZEOF(.warmboot) : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >main AT>glob .init : { KEEP( *(.init) ) . = ALIGN(8); } >main AT>glob .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >main AT>glob .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >main AT>glob /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >main AT>glob .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >main AT>glob .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >main AT>glob .hash : { *(.hash) } >main AT>glob /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >main AT>glob .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >main AT>glob __got_start__ = .; .got : { *(.got) *(.igot) } >main AT>glob .got.plt : { *(.got.plt) *(.igot.plt) } >main AT>glob __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >main AT>glob .bss ALIGN(8) (NOLOAD) : { __bss_start__ = ABSOLUTE(.); *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); __bss_end__ = ABSOLUTE(.); } >main AT>glob __program_end__ = ABSOLUTE(.); /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/program/program.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ $(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR) \ $(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := sc7fw.bin rebootstub.bin #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib check_boot_lib check_sc7fw check_rebootstub #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.bin $(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.bin @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifneq ($(strip $(ATMOSPHERE_LIBRARY_DIR)),$(strip $(ATMOSPHERE_BOOT_LIBRARY_DIR))) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a: check_boot_lib @$(SILENTCMD)echo "Checked boot library." endif $(CURRENT_DIRECTORY)/sc7fw/$(ATMOSPHERE_BOOT_OUT_DIR)/sc7fw.bin: check_sc7fw $(CURRENT_DIRECTORY)/rebootstub/$(ATMOSPHERE_BOOT_OUT_DIR)/rebootstub.bin: check_rebootstub ifeq ($(ATMOSPHERE_CHECKED_SC7FW),1) check_sc7fw: else check_sc7fw: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/sc7fw -f $(CURRENT_DIRECTORY)/sc7fw/sc7fw.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 endif ifeq ($(ATMOSPHERE_CHECKED_REBOOTSTUB),1) check_rebootstub: else check_rebootstub: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_BOOT_LIBRARY_DIR)/libexosphere.a @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/rebootstub -f $(CURRENT_DIRECTORY)/rebootstub/rebootstub.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE=1 endif ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif ifeq ($(ATMOSPHERE_CHECKED_BOOT_LIBEXOSPHERE),1) check_boot_lib: else check_boot_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/rebootstub -f $(CURRENT_DIRECTORY)/rebootstub/rebootstub.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/sc7fw -f $(CURRENT_DIRECTORY)/sc7fw/sc7fw.mk clean ATMOSPHERE_CPU="$(strip $(ATMOSPHERE_BOOT_CPU))" @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).lz4 : $(OUTPUT).bin $(SILENTCMD)$(PYTHON) $(CURRENT_DIRECTORY)/split_program.py $(OUTPUT).bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) @echo built ... $(notdir $@) $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a secmon_crt0_cpp.o secmon_make_page_table.o : CFLAGS += -fno-builtin sc7fw.bin.o: sc7fw.bin @echo $(notdir $<) @$(bin2o) rebootstub.bin.o: rebootstub.bin @echo $(notdir $<) @$(bin2o) %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(OFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/program/program.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /program.ld) --gc-sections --nmagic ================================================ FILE: exosphere/program/rebootstub/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/rebootstub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/rebootstub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/program/rebootstub/rebootstub.ld ================================================ OUTPUT_ARCH(arm) ENTRY(reset) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K rebootstub : ORIGIN = 0x4003F000, LENGTH = 4K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(rebootstub)); . = __start__; __code_start = . ; .vectors : { KEEP (*(.vectors .vectors.*)) . = ALIGN(8); } >rebootstub .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >rebootstub .init : { KEEP( *(.init) ) . = ALIGN(8); } >rebootstub .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >rebootstub .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >rebootstub /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >rebootstub .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >rebootstub .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >rebootstub .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >rebootstub .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >rebootstub .hash : { *(.hash) } >rebootstub /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >rebootstub .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >rebootstub .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >rebootstub .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >rebootstub .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >rebootstub .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >rebootstub .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >rebootstub .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >rebootstub .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >rebootstub __got_start__ = .; .got : { *(.got) *(.igot) } >rebootstub .got.plt : { *(.got.plt) *(.igot.plt) } >rebootstub __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >rebootstub __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >rebootstub __bss_end__ = .; __end__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/program/rebootstub/rebootstub.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/program/rebootstub/rebootstub.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /rebootstub.ld) --gc-sections --nmagic ================================================ FILE: exosphere/program/rebootstub/source/rebootstub_exception_vectors.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .vectors, "ax", %progbits .align 3 .global reset reset: b _ZN3ams10rebootstub4MainEv .global _ZN3ams10rebootstub10RebootTypeE _ZN3ams10rebootstub10RebootTypeE: .word 0x00000001 ================================================ FILE: exosphere/program/rebootstub/source/rebootstub_main.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams10rebootstub4MainEv, "ax", %progbits .align 3 .global _ZN3ams10rebootstub4MainEv _ZN3ams10rebootstub4MainEv: /* Get the reboot type. */ ldr r0, =_ZN3ams10rebootstub10RebootTypeE ldr r0, [r0] /* If the reboot type is power off, perform a power off. */ cmp r0, #0 beq _ZN3ams10rebootstub8PowerOffEv /* Otherwise, clear all registers jump to the reboot payload in iram. */ ldr r0, =0x52425430 /* RBT0 */ mov r1, #0 mov r2, #0 mov r3, #0 mov r4, #0 mov r5, #0 mov r5, #0 mov r6, #0 mov r7, #0 mov r8, #0 mov r9, #0 mov r10, #0 mov r11, #0 mov r12, #0 mov r9, #0 mov lr, #0 ldr sp, =0x40010000 ldr pc, =0x40010000 /* Infinite loop. */ 1: b 1b ================================================ FILE: exosphere/program/rebootstub/source/rebootstub_power_off.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::rebootstub { NORETURN void Halt() { while (true) { reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED)); } __builtin_unreachable(); } NORETURN void PowerOff() { /* Ensure that i2c5 is usable. */ clkrst::EnableI2c5Clock(); /* Initialize i2c5. */ i2c::Initialize(i2c::Port_5); /* Stop rtc alarms. */ rtc::StopAlarm(); /* Perform a pmic power off. */ pmic::PowerOff(); /* Halt the bpmp. */ Halt(); /* This can never be reached. */ __builtin_unreachable(); } } namespace ams::diag { NORETURN void AbortImpl() { /* Halt the bpmp. */ rebootstub::Halt(); /* This can never be reached. */ __builtin_unreachable(); } #include <exosphere/diag/diag_detailed_assertion_impl.inc> } ================================================ FILE: exosphere/program/sc7fw/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/sc7fw.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/sc7fw.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/program/sc7fw/sc7fw.ld ================================================ OUTPUT_ARCH(arm) ENTRY(reset) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K sc7fw : ORIGIN = 0x40003000, LENGTH = 4K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(sc7fw)); . = __start__; __code_start = . ; .vectors : { KEEP (*(.vectors .vectors.*)) . = ALIGN(8); } >sc7fw .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >sc7fw .init : { KEEP( *(.init) ) . = ALIGN(8); } >sc7fw .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >sc7fw .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >sc7fw /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >sc7fw .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >sc7fw .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >sc7fw .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >sc7fw .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >sc7fw .hash : { *(.hash) } >sc7fw /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >sc7fw .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >sc7fw .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >sc7fw .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >sc7fw .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >sc7fw .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >sc7fw .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >sc7fw .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >sc7fw .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >sc7fw __got_start__ = .; .got : { *(.got) *(.igot) } >sc7fw .got.plt : { *(.got.plt) *(.igot.plt) } >sc7fw __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >sc7fw __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >sc7fw __bss_end__ = .; __end__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/program/sc7fw/sc7fw.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/program/sc7fw/sc7fw.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /sc7fw.ld) --gc-sections --nmagic ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_dram.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "sc7fw_util.hpp" #include "sc7fw_dram.hpp" namespace ams::sc7fw { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); void UpdateEmcTiming() { /* Enable timing update. */ reg::Write(EMC_ADDRESS(EMC_TIMING_CONTROL), EMC_REG_BITS_ENUM(TIMING_CONTROL_TIMING_UPDATE, ENABLED)); /* Wait for the timing update to complete. */ while (!reg::HasValue(EMC_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_TIMING_UPDATE_STALLED, DONE))) { /* ... */ } } void RequestAllPadsPowerDown(uintptr_t addr, uintptr_t expected) { constexpr u32 DpdAllRequestValue = reg::Encode(PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_ON)) | 0x0FFFFFFF; const auto RequestAddress = addr; const auto StatusAddress = addr + 4; /* Request all pads enter power down. */ reg::Write(PMC + RequestAddress, DpdAllRequestValue); /* Wait until the status reflects our expectation (and all pads are shut down). */ while (reg::Read(PMC + StatusAddress) != expected) { /* ... */ } /* Wait a little while to allow the power down status to propagate. */ SpinLoop(0x20); }; } void SaveEmcFsp() { /* We require that the RAM is LPDDR4. */ AMS_ABORT_UNLESS(reg::HasValue(EMC_ADDRESS(EMC_FBIO_CFG5), EMC_REG_BITS_ENUM(FBIO_CFG5_DRAM_TYPE, LPDDR4))); /* Read the frequency set points from MRW3. */ constexpr u32 FspShift = 6; constexpr u32 FspBits = 2; constexpr u32 FspMask = ((1u << FspBits) - 1) << FspShift; static_assert(FspMask == 0x000000C0); const u32 fsp = (reg::Read(EMC_ADDRESS(EMC_MRW3)) & FspMask) >> FspShift; /* Write the fsp to PMC_SCRATCH18, where it will be restored to MRW3 by brom. */ reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH18, REG_BITS_VALUE(FspShift, FspBits, fsp)); /* Write the fsp twice to PMC_SCRATCH12, where it will be restored to MRW12 by brom. */ reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH12, REG_BITS_VALUE(FspShift, FspBits, fsp), REG_BITS_VALUE(FspShift + 8, FspBits, fsp)); /* Write the fsp twice to PMC_SCRATCH13, where it will be restored to MRW13 by brom. */ reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH13, REG_BITS_VALUE(FspShift, FspBits, fsp), REG_BITS_VALUE(FspShift + 8, FspBits, fsp)); } void EnableSdramSelfRefresh() { /* We require that the RAM is dual-channel. */ AMS_ABORT_UNLESS(reg::HasValue(EMC_ADDRESS(EMC_FBIO_CFG7), EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE))); /* Disable RAM's ability to dynamically self-refresh, and to opportunistically perform powerdown. */ reg::Write(EMC_ADDRESS(EMC_CFG), EMC_REG_BITS_ENUM(CFG_DYN_SELF_REF, DISABLED), EMC_REG_BITS_ENUM(CFG_DRAM_ACPD, NO_POWERDOWN)); /* Update the EMC timing. */ UpdateEmcTiming(); /* Wait five microseconds. */ util::WaitMicroSeconds(5); /* Disable ZQ calibration. */ reg::Write(EMC_ADDRESS(EMC_ZCAL_INTERVAL), 0); /* Disable automatic calibration. */ reg::Write(EMC_ADDRESS(EMC_AUTO_CAL_CONFIG), EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_MEASURE_STALL, ENABLE), EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_UPDATE_STALL, ENABLE), EMC_REG_BITS_ENUM(AUTO_CAL_CONFIG_AUTO_CAL_START, DISABLE)); /* Get whether digital delay locked loops are enabled. */ const bool has_dll = reg::HasValue(EMC_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, ENABLED)); if (has_dll) { /* If they are, disable them. */ reg::ReadWrite(EMC_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED)); } /* Update the EMC timing. */ UpdateEmcTiming(); /* If dll was enabled, wait until both EMC0 and EMC1 have dll disabled. */ if (has_dll) { while (!reg::HasValue(EMC0_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED))) { /* ... */ } while (!reg::HasValue(EMC1_ADDRESS(EMC_CFG_DIG_DLL), EMC_REG_BITS_ENUM(CFG_DIG_DLL_CFG_DLL_EN, DISABLED))) { /* ... */ } } /* Stall all reads and writes. */ reg::Write(EMC_ADDRESS(EMC_REQ_CTRL), EMC_REG_BITS_VALUE(REQ_CTRL_STALL_ALL_READS, 1), EMC_REG_BITS_VALUE(REQ_CTRL_STALL_ALL_WRITES, 1)); /* Wait until both EMC0 and EMC1 have no outstanding transactions. */ while (!reg::HasValue(EMC0_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_NO_OUTSTANDING_TRANSACTIONS, COMPLETED))) { /* ... */ } while (!reg::HasValue(EMC1_ADDRESS(EMC_EMC_STATUS), EMC_REG_BITS_ENUM(EMC_STATUS_NO_OUTSTANDING_TRANSACTIONS, COMPLETED))) { /* ... */ } /* Enable self-refresh. */ reg::Write(EMC_ADDRESS(EMC_SELF_REF), EMC_REG_BITS_ENUM(SELF_REF_SREF_DEV_SELECTN, BOTH), EMC_REG_BITS_ENUM(SELF_REF_SELF_REF_CMD, ENABLED)); /* Wait until both EMC and EMC1 are in self-refresh. */ const auto desired = reg::HasValue(EMC_ADDRESS(EMC_ADR_CFG), EMC_REG_BITS_ENUM(ADR_CFG_EMEM_NUMDEV, N2)) ? EMC_REG_BITS_ENUM(EMC_STATUS_DRAM_IN_SELF_REFRESH, BOTH_ENABLED) : EMC_REG_BITS_ENUM(EMC_STATUS_DRAM_DEV0_IN_SELF_REFRESH, ENABLED); /* NOTE: Nintendo's sc7 entry firmware has a bug here. */ /* Instead of waiting for both EMCs to report self-refresh, they just read the EMC_STATUS for each EMC. */ /* This is incorrect, per documentation. */ while (!reg::HasValue(EMC0_ADDRESS(EMC_EMC_STATUS), desired)) { /* ... */ } while (!reg::HasValue(EMC1_ADDRESS(EMC_EMC_STATUS), desired)) { /* ... */ } } void EnableEmcAllSegmentsRefresh() { constexpr int MR17_PASR_Segment = 17; /* Write zeros to MR17_PASR_Segment to enable refresh for all segments for dev0. */ reg::Write(EMC_ADDRESS(EMC_MRW), EMC_REG_BITS_ENUM (MRW_DEV_SELECTN, DEV0), EMC_REG_BITS_ENUM (MRW_CNT, EXT1), EMC_REG_BITS_VALUE(MRW_MA, MR17_PASR_Segment), EMC_REG_BITS_VALUE(MRW_OP, 0)); /* If dev1 exists, do the same for dev1. */ if (reg::HasValue(EMC_ADDRESS(EMC_ADR_CFG), EMC_REG_BITS_ENUM(ADR_CFG_EMEM_NUMDEV, N2))) { reg::Write(EMC_ADDRESS(EMC_MRW), EMC_REG_BITS_ENUM (MRW_DEV_SELECTN, DEV1), EMC_REG_BITS_ENUM (MRW_CNT, EXT1), EMC_REG_BITS_VALUE(MRW_MA, MR17_PASR_Segment), EMC_REG_BITS_VALUE(MRW_OP, 0)); } } void EnableDdrDeepPowerDown() { /* Read and decode the parameters Nintendo stores in EMC_PMC_SCRATCH3. */ const u32 scratch3 = reg::Read(EMC_ADDRESS(EMC_PMC_SCRATCH3)); const bool weak_bias = (scratch3 & reg::EncodeMask(EMC_REG_BITS_MASK(PMC_SCRATCH3_WEAK_BIAS))) == reg::EncodeValue(EMC_REG_BITS_ENUM(PMC_SCRATCH3_WEAK_BIAS, ENABLED)); const u32 ddr_cntrl = (scratch3 & reg::EncodeMask(EMC_REG_BITS_MASK(PMC_SCRATCH3_DDR_CNTRL))); /* Write the decoded value to PMC_DDR_CNTRL. */ reg::Write(PMC + APBDEV_PMC_DDR_CNTRL, ddr_cntrl); /* If weak bias is enabled, set all VTT_E_WB bits in APBDEV_PMC_WEAK_BIAS. */ if (weak_bias) { constexpr u32 WeakBiasVttEWbAll = 0x7FFF0000; reg::Write(PMC + APBDEV_PMC_WEAK_BIAS, WeakBiasVttEWbAll); } /* Request that DPD3 pads power down. */ constexpr u32 EristaDpd3Mask = 0x0FFFFFFF; constexpr u32 MarikoDpd3Mask = 0x0FFF9FFF; if (fuse::GetSocType() == fuse::SocType_Erista) { RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD3_REQ, EristaDpd3Mask); } else { RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD3_REQ, MarikoDpd3Mask); } /* Request that DPD4 pads power down. */ constexpr u32 Dpd4Mask = 0x0FFF1FFF; RequestAllPadsPowerDown(APBDEV_PMC_IO_DPD4_REQ, Dpd4Mask); } } ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_dram.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::sc7fw { void SaveEmcFsp(); void EnableSdramSelfRefresh(); void EnableEmcAllSegmentsRefresh(); void EnableDdrDeepPowerDown(); } ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_exception_vectors.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .vectors, "ax", %progbits .align 3 .global reset reset: b _start b _ZN3ams5sc7fw16ExceptionHandlerEv ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "sc7fw_util.hpp" #include "sc7fw_dram.hpp" namespace ams::sc7fw { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); void DisableCrail() { /* Wait for CRAIL to be off. */ while (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, OFF))) { /* ... */ } /* Set CRAIL to be clamped. */ reg::ReadWrite(PMC + APBDEV_PMC_SET_SW_CLAMP, PMC_REG_BITS_VALUE(SET_SW_CLAMP_CRAIL, 1)); /* Wait for CRAIL to be clamped. */ while (!reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, PMC_REG_BITS_ENUM(CLAMP_STATUS_CRAIL, ENABLE))) { /* ... */ } /* Spin loop for a short while, to allow time for the clamp to take effect. */ sc7fw::SpinLoop(10); /* Initialize i2c-5. */ i2c::Initialize(i2c::Port_5); /* Disable the voltage to CPU. */ pmic::DisableVddCpu(fuse::GetRegulator()); /* Wait 700 microseconds to ensure voltage is disabled. */ util::WaitMicroSeconds(700); } void DisableAllInterrupts() { /* Disable all interrupts for bpmp in all interrupt controllers. */ reg::Write(PRI_ICTLR(ICTLR_COP_IER_CLR), ~0u); reg::Write(SEC_ICTLR(ICTLR_COP_IER_CLR), ~0u); reg::Write(TRI_ICTLR(ICTLR_COP_IER_CLR), ~0u); reg::Write(QUAD_ICTLR(ICTLR_COP_IER_CLR), ~0u); reg::Write(PENTA_ICTLR(ICTLR_COP_IER_CLR), ~0u); reg::Write(HEXA_ICTLR(ICTLR_COP_IER_CLR), ~0u); } void EnterSc7() { /* Disable read buffering and write buffering in the BPMP cache. */ reg::ReadWrite(AVP_CACHE_ADDR(AVP_CACHE_CONFIG), AVP_CACHE_REG_BITS_ENUM(CONFIG_DISABLE_WB, TRUE), AVP_CACHE_REG_BITS_ENUM(CONFIG_DISABLE_RB, TRUE)); /* Ensure the CPU Rail is turned off. */ DisableCrail(); /* Disable all interrupts. */ DisableAllInterrupts(); /* Save the EMC FSP */ SaveEmcFsp(); /* Enable self-refresh for DRAM */ EnableSdramSelfRefresh(); /* Enable refresh for all EMC devices. */ EnableEmcAllSegmentsRefresh(); /* Enable deep power-down for ddr. */ EnableDdrDeepPowerDown(); /* Enable pad sampling during deep sleep. */ reg::ReadWrite(PMC + APBDEV_PMC_DPD_SAMPLE, PMC_REG_BITS_ENUM(DPD_SAMPLE_ON, ENABLE)); reg::Read(PMC + APBDEV_PMC_DPD_SAMPLE); /* Wait a while for pad sampling to be enabled. */ sc7fw::SpinLoop(0x128); /* Enter deep sleep. */ reg::ReadWrite(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_ON, ENABLE)); /* Wait forever until we're asleep. */ AMS_INFINITE_LOOP(); } } void Main() { EnterSc7(); } NORETURN void ExceptionHandler() { /* Write enable to MAIN_RESET. */ reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE)); /* Wait forever until we're reset. */ AMS_INFINITE_LOOP(); } } namespace ams::diag { NORETURN void AbortImpl() { sc7fw::ExceptionHandler(); } #include <exosphere/diag/diag_detailed_assertion_impl.inc> } ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text.start, "ax", %progbits .align 3 .global _start _start: /* Set CPSR_cf and CPSR_cf. */ msr cpsr_f, #0xC0 msr cpsr_cf, #0xD3 /* Set the stack pointer. */ ldr sp, =0x40005000 /* Set our link register to the exception handler. */ ldr lr, =_ZN3ams5sc7fw16ExceptionHandlerEv /* Invoke main. */ bl _ZN3ams5sc7fw4MainEv /* Infinite loop. */ 1: b 1b ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::sc7fw { void SpinLoop(unsigned int num); } ================================================ FILE: exosphere/program/sc7fw/source/sc7fw_util_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams5sc7fw8SpinLoopEj, "ax", %progbits .global _ZN3ams5sc7fw8SpinLoopEj .thumb_func .syntax unified _ZN3ams5sc7fw8SpinLoopEj: 1: /* Subtract one from the count. */ subs r0, r0, #1 /* If we aren't at zero, continue looping. */ bgt 1b /* Return. */ bx lr ================================================ FILE: exosphere/program/source/boot/secmon_boot.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::boot { void MakePageTable(); void UnmapPhysicalIdentityMapping(); void UnmapDram(); void LoadMarikoProgram(); void InitializeColdBoot(); bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size); bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size); bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size); bool VerifyBootConfigEcid(const pkg1::BootConfig &bc); void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start); bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size); void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *key, size_t key_size, const void *iv, size_t iv_size, u8 key_generation); bool VerifyPackage2Meta(const pkg2::Package2Meta &meta); bool VerifyPackage2Version(const pkg2::Package2Meta &meta); bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address); } ================================================ FILE: exosphere/program/source/boot/secmon_boot_cache.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot_cache.hpp" namespace ams::secmon::boot { #include "../secmon_cache_impl.inc" } ================================================ FILE: exosphere/program/source/boot/secmon_boot_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::boot { #include "../secmon_cache.inc" } ================================================ FILE: exosphere/program/source/boot/secmon_boot_config.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot.hpp" namespace ams::secmon::boot { bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size) { return VerifySignature(std::addressof(bc.signature), sizeof(bc.signature), mod, mod_size, std::addressof(bc.signed_data), sizeof(bc.signed_data)); } bool VerifyBootConfigEcid(const pkg1::BootConfig &bc) { /* Get the ecid. */ br::BootEcid ecid; fuse::GetEcid(std::addressof(ecid)); /* Verify it matches. */ return crypto::IsSameBytes(std::addressof(ecid), bc.signed_data.ecid, sizeof(ecid)); } } ================================================ FILE: exosphere/program/source/boot/secmon_boot_functions.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_boot.hpp" #include "secmon_boot_cache.hpp" #include "secmon_boot_functions.hpp" namespace ams::secmon::boot { namespace { constexpr inline uintptr_t SYSCTR0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress(); NOINLINE void DecryptPayload(uintptr_t dst, uintptr_t src, size_t size, const void *iv, size_t iv_size, u8 key_generation) { secmon::boot::DecryptPackage2(reinterpret_cast<void *>(dst), size, reinterpret_cast<void *>(src), size, secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, iv, iv_size, key_generation); } u32 GetChipId() { constexpr u32 ChipIdErista = 0x210; constexpr u32 ChipIdMariko = 0x214; switch (GetSocType()) { case fuse::SocType_Erista: return ChipIdErista; case fuse::SocType_Mariko: return ChipIdMariko; AMS_UNREACHABLE_DEFAULT_CASE(); } } } void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message) { if (!verify_result) { secmon::SetError(error_info); AMS_ABORT(message); } } void ClearIramBootCode() { /* Clear the boot code image from where it was loaded in IRAM. */ util::ClearMemory(MemoryRegionPhysicalIramBootCodeCode.GetPointer(), MemoryRegionPhysicalIramBootCodeCode.GetSize()); } void ClearIramBootKeys() { /* Clear the boot keys from where they were loaded in IRAM. */ util::ClearMemory(MemoryRegionPhysicalIramBootCodeKeys.GetPointer(), MemoryRegionPhysicalIramBootCodeKeys.GetSize()); } void ClearIramDebugCode() { /* Clear the boot code image from where it was loaded in IRAM. */ util::ClearMemory(MemoryRegionPhysicalDebugCode.GetPointer(), MemoryRegionPhysicalDebugCode.GetSize()); } void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state) { /* Check NX Bootloader's state once per microsecond until it's advanced enough. */ while (params.bootloader_state < state) { util::WaitMicroSeconds(1); } } void LoadBootConfig(const void *src) { pkg1::BootConfig * const dst = secmon::impl::GetBootConfigStorage(); if (pkg1::IsProduction()) { std::memset(dst, 0, sizeof(*dst)); } else { hw::FlushDataCache(src, sizeof(*dst)); hw::DataSynchronizationBarrierInnerShareable(); std::memcpy(dst, src, sizeof(*dst)); } } void VerifyOrClearBootConfig() { /* On production hardware, the boot config is already cleared. */ if (pkg1::IsProduction()) { return; } pkg1::BootConfig * const bc = secmon::impl::GetBootConfigStorage(); /* Determine if the bc is valid for the device. */ bool valid_for_device = false; { const bool valid_signature = secmon::boot::VerifyBootConfigSignature(*bc, secmon::boot::GetBootConfigRsaModulus(), se::RsaSize); if (valid_signature) { valid_for_device = secmon::boot::VerifyBootConfigEcid(*bc); } } /* If the boot config is not valid for the device, clear its signed data. */ if (!valid_for_device) { util::ClearMemory(std::addressof(bc->signed_data), sizeof(bc->signed_data)); } } void EnableTsc(u64 initial_tsc_value) { /* Write the initial value to the CNTCV registers. */ const u32 lo = static_cast<u32>(initial_tsc_value >> 0); const u32 hi = static_cast<u32>(initial_tsc_value >> 32); reg::Write(SYSCTR0 + SYSCTR0_CNTCV0, lo); reg::Write(SYSCTR0 + SYSCTR0_CNTCV1, hi); /* Configure the system counter control register. */ reg::Write(SYSCTR0 + SYSCTR0_CNTCR, SYSCTR0_REG_BITS_ENUM(CNTCR_HDBG, ENABLE), SYSCTR0_REG_BITS_ENUM(CNTCR_EN, ENABLE)); } void WriteGpuCarveoutMagicNumbers() { /* Define the magic numbers. */ constexpr u32 GpuMagicNumber = 0xC0EDBBCC; constexpr u32 SkuInfo = 0x83; constexpr u32 HdcpMicroCodeVersion = 0x2; /* Get our pointers. */ u32 *gpu_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x004 / sizeof(*gpu_magic)); u32 *tsec_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x100 / sizeof(*tsec_magic)); /* Write the gpu magic number. */ gpu_magic[0] = GpuMagicNumber; /* Write the tsec magic numbers. */ tsec_magic[0] = SkuInfo; tsec_magic[1] = HdcpMicroCodeVersion; tsec_magic[2] = GetChipId(); /* Flush the magic numbers. */ hw::FlushDataCache(gpu_magic, 1 * sizeof(u32)); hw::FlushDataCache(tsec_magic, 3 * sizeof(u32)); hw::DataSynchronizationBarrierInnerShareable(); } void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header) { /* Check for all-zeroes signature. */ const bool is_unsigned = header.signature[0] == 0 && crypto::IsSameBytes(header.signature, header.signature + 1, sizeof(header.signature) - 1); secmon::impl::GetBootConfigStorage()->signed_data.SetPackage2SignatureVerificationDisabled(is_unsigned); /* Check for valid magic. */ const bool is_decrypted = crypto::IsSameBytes(header.meta.magic, pkg2::Package2Meta::Magic::String, sizeof(header.meta.magic)); secmon::impl::GetBootConfigStorage()->signed_data.SetPackage2EncryptionDisabled(is_decrypted); } void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify) { const u8 * const mod = secmon::boot::GetPackage2RsaModulus(pkg1::IsProductionForPublicKey()); const size_t mod_size = se::RsaSize; if (verify) { CheckVerifyResult(secmon::boot::VerifyPackage2Signature(header, mod, mod_size), pkg1::ErrorInfo_InvalidPackage2Signature, "pkg2 sign FAIL"); } } void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted) { if (encrypted) { constexpr int IvSize = 0x10; /* Decrypt the header. */ DecryptPackage2(dst, sizeof(*dst), std::addressof(src), sizeof(src), secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, std::addressof(src), IvSize, src.GetKeyGeneration()); /* Copy back the iv, which encodes encrypted metadata. */ std::memcpy(dst, std::addressof(src), IvSize); } else { std::memcpy(dst, std::addressof(src), sizeof(*dst)); } } void VerifyPackage2Header(const pkg2::Package2Meta &meta) { /* Validate the metadata. */ CheckVerifyResult(VerifyPackage2Meta(meta), pkg1::ErrorInfo_InvalidPackage2Meta, "pkg2 meta FAIL"); /* Validate the version. */ CheckVerifyResult(VerifyPackage2Version(meta), pkg1::ErrorInfo_InvalidPackage2Version, "pkg2 version FAIL"); } void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted) { /* Get the key generation for crypto. */ const u8 key_generation = meta.GetKeyGeneration(); /* Decrypt or load each payload in order. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { AMS_SECMON_LOG("pkg2 payload[%d]: %09lx -> %09lx size=%08x\n", i, src, dst + meta.payload_offsets[i], meta.payload_sizes[i]); if (encrypted) { DecryptPayload(dst + meta.payload_offsets[i], src, meta.payload_sizes[i], meta.payload_ivs[i], sizeof(meta.payload_ivs[i]), key_generation); } else { std::memcpy(reinterpret_cast<void *>(dst + meta.payload_offsets[i]), reinterpret_cast<void *>(src), meta.payload_sizes[i]); } src += meta.payload_sizes[i]; } } } ================================================ FILE: exosphere/program/source/boot/secmon_boot_functions.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::boot { void ClearIramBootCode(); void ClearIramBootKeys(); void ClearIramDebugCode(); void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state); void LoadBootConfig(const void *src); void VerifyOrClearBootConfig(); void EnableTsc(u64 initial_tsc_value); void WriteGpuCarveoutMagicNumbers(); void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header); void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify); void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted); void VerifyPackage2Header(const pkg2::Package2Meta &meta); void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted); void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message); } ================================================ FILE: exosphere/program/source/boot/secmon_boot_key_data.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .volatile_keys._ZN3ams6secmon4boot15VolatileKeyDataE, "aw", %progbits .global _ZN3ams6secmon4boot15VolatileKeyDataE _ZN3ams6secmon4boot15VolatileKeyDataE: /* BootConfig Rsa Modulus. */ .byte 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64 .byte 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33 .byte 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB .byte 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9 .byte 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B .byte 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25 .byte 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49 .byte 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24 .byte 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF .byte 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E .byte 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6 .byte 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9 .byte 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12 .byte 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5 .byte 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93 .byte 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D /* Package2 Development Rsa Modulus. */ .byte 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99 .byte 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7 .byte 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6 .byte 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38 .byte 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83 .byte 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0 .byte 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6 .byte 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50 .byte 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7 .byte 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42 .byte 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E .byte 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8 .byte 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7 .byte 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4 .byte 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46 .byte 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B /* Package2 Production Rsa Modulus. */ .byte 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59 .byte 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE .byte 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5 .byte 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74 .byte 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48 .byte 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE .byte 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32 .byte 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A .byte 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B .byte 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3 .byte 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9 .byte 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47 .byte 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D .byte 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2 .byte 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF .byte 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F /* Package2 Aes Key Source. */ .byte 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 /* Master Key Source. */ .byte 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C /* Device Master Key Source Kek Source. */ .byte 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 /* NOTE: These are just latest-master-kek encrypted with KEK. */ /* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */ /* TODO: Update on next change of keys. */ /* Mariko Development Master Kek Source. */ .byte 0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB /* Mariko Production Master Kek Source. */ .byte 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 /* Development Master Key Vectors. */ .byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */ .byte 0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23 /* Master key 00 encrypted with Master key 01. */ .byte 0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D /* Master key 01 encrypted with Master key 02. */ .byte 0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3 /* Master key 02 encrypted with Master key 03. */ .byte 0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA /* Master key 03 encrypted with Master key 04. */ .byte 0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC /* Master key 04 encrypted with Master key 05. */ .byte 0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E /* Master key 05 encrypted with Master key 06. */ .byte 0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19 /* Master key 06 encrypted with Master key 07. */ .byte 0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04 /* Master key 07 encrypted with Master key 08. */ .byte 0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE /* Master key 08 encrypted with Master key 09. */ .byte 0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4 /* Master key 09 encrypted with Master key 0A. */ .byte 0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C /* Master key 0A encrypted with Master key 0B. */ .byte 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 /* Master key 0B encrypted with Master key 0C. */ .byte 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 /* Master key 0C encrypted with Master key 0D. */ .byte 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D /* Master key 0D encrypted with Master key 0E. */ .byte 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 /* Master key 0E encrypted with Master key 0F. */ .byte 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 /* Master key 0F encrypted with Master key 10. */ .byte 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 /* Master key 10 encrypted with Master key 11. */ .byte 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 /* Master key 11 encrypted with Master key 12. */ .byte 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE /* Master key 12 encrypted with Master key 13. */ .byte 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E /* Master key 13 encrypted with Master key 14. */ /* Production Master Key Vectors. */ .byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */ .byte 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD /* Master key 00 encrypted with Master key 01. */ .byte 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 /* Master key 01 encrypted with Master key 02. */ .byte 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 /* Master key 02 encrypted with Master key 03. */ .byte 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 /* Master key 03 encrypted with Master key 04. */ .byte 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE /* Master key 04 encrypted with Master key 05. */ .byte 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 /* Master key 05 encrypted with Master key 06. */ .byte 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F /* Master key 06 encrypted with Master key 07. */ .byte 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 /* Master key 07 encrypted with Master key 08. */ .byte 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 /* Master key 08 encrypted with Master key 09. */ .byte 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A /* Master key 09 encrypted with Master key 0A. */ .byte 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 /* Master key 0A encrypted with Master key 0B. */ .byte 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 /* Master key 0B encrypted with Master key 0C. */ .byte 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 /* Master key 0C encrypted with Master key 0D. */ .byte 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 /* Master key 0D encrypted with Master key 0E. */ .byte 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 /* Master key 0E encrypted with Master key 0F. */ .byte 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD /* Master key 0F encrypted with Master key 10. */ .byte 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 /* Master key 10 encrypted with Master key 11. */ .byte 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 /* Master key 11 encrypted with Master key 12. */ .byte 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 /* Master key 12 encrypted with Master key 13. */ .byte 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA /* Master key 13 encrypted with Master key 14. */ /* Device Master Key Source Sources. */ .byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */ .byte 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C /* 5.0.0 Device Master Key Source Source. */ .byte 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 /* 6.0.0 Device Master Key Source Source. */ .byte 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 /* 6.2.0 Device Master Key Source Source. */ .byte 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D /* 7.0.0 Device Master Key Source Source. */ .byte 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE /* 8.1.0 Device Master Key Source Source. */ .byte 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 /* 9.0.0 Device Master Key Source Source. */ .byte 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 /* 9.1.0 Device Master Key Source Source. */ .byte 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 /* 12.1.0 Device Master Key Source Source. */ .byte 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F /* 13.0.0 Device Master Key Source Source. */ .byte 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D /* 14.0.0 Device Master Key Source Source. */ .byte 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 /* 15.0.0 Device Master Key Source Source. */ .byte 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C /* 16.0.0 Device Master Key Source Source. */ .byte 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 /* 17.0.0 Device Master Key Source Source. */ .byte 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 /* 18.0.0 Device Master Key Source Source. */ .byte 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 /* 19.0.0 Device Master Key Source Source. */ .byte 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 /* 20.0.0 Device Master Key Source Source. */ .byte 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F /* 21.0.0 Device Master Key Source Source. */ /* Development Device Master Kek Sources. */ .byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */ .byte 0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8 /* 5.0.0 Device Master Kek Source. */ .byte 0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5 /* 6.0.0 Device Master Kek Source. */ .byte 0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38 /* 6.2.0 Device Master Kek Source. */ .byte 0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE /* 7.0.0 Device Master Kek Source. */ .byte 0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87 /* 8.1.0 Device Master Kek Source. */ .byte 0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F /* 9.0.0 Device Master Kek Source. */ .byte 0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B /* 9.1.0 Device Master Kek Source. */ .byte 0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB /* 12.1.0 Device Master Kek Source. */ .byte 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F /* 13.0.0 Device Master Kek Source. */ .byte 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA /* 14.0.0 Device Master Kek Source. */ .byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */ .byte 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F /* 16.0.0 Device Master Kek Source. */ .byte 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 /* 17.0.0 Device Master Kek Source. */ .byte 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF /* 18.0.0 Device Master Kek Source. */ .byte 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 /* 19.0.0 Device Master Kek Source. */ .byte 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D /* 20.0.0 Device Master Kek Source. */ .byte 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F /* 21.0.0 Device Master Kek Source. */ /* Production Device Master Kek Sources. */ .byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */ .byte 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E /* 5.0.0 Device Master Kek Source. */ .byte 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF /* 6.0.0 Device Master Kek Source. */ .byte 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB /* 6.2.0 Device Master Kek Source. */ .byte 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E /* 7.0.0 Device Master Kek Source. */ .byte 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D /* 8.1.0 Device Master Kek Source. */ .byte 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED /* 9.0.0 Device Master Kek Source. */ .byte 0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36 /* 9.1.0 Device Master Kek Source. */ .byte 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 /* 12.1.0 Device Master Kek Source. */ .byte 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 /* 13.0.0 Device Master Kek Source. */ .byte 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 /* 14.0.0 Device Master Kek Source. */ .byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */ .byte 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F /* 16.0.0 Device Master Kek Source. */ .byte 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E /* 17.0.0 Device Master Kek Source. */ .byte 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B /* 18.0.0 Device Master Kek Source. */ .byte 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F /* 19.0.0 Device Master Kek Source. */ .byte 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 /* 20.0.0 Device Master Kek Source. */ .byte 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 /* 21.0.0 Device Master Kek Source. */ ================================================ FILE: exosphere/program/source/boot/secmon_boot_rsa.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot.hpp" namespace ams::secmon::boot { namespace { constinit const u8 RsaPublicKeyExponent[] = { 0x00, 0x01, 0x00, 0x01, }; constexpr inline u8 TailMagic = 0xBC; bool VerifyRsaPssSha256(const u8 *sig, const void *msg, size_t msg_size) { /* Define constants. */ constexpr int EmBits = 2047; constexpr int EmLen = util::DivideUp(EmBits, BITSIZEOF(u8)); constexpr int SaltLen = 0x20; constexpr int HashLen = se::Sha256HashSize; /* Define a work buffer. */ u8 work[EmLen]; ON_SCOPE_EXIT { util::ClearMemory(work, sizeof(work)); }; /* Calculate the message hash, first flushing cache to ensure SE sees correct data. */ se::Sha256Hash msg_hash; hw::FlushDataCache(msg, msg_size); hw::DataSynchronizationBarrierInnerShareable(); se::CalculateSha256(std::addressof(msg_hash), msg, msg_size); /* Verify the tail magic. */ bool is_valid = sig[EmLen - 1] == TailMagic; /* Determine extents of masked db and h. */ const u8 *masked_db = std::addressof(sig[0]); const u8 *h = std::addressof(sig[EmLen - HashLen - 1]); /* Verify the extra bits are zero. */ is_valid &= (masked_db[0] >> (BITSIZEOF(u8) - (BITSIZEOF(u8) * EmLen - EmBits))) == 0; /* Calculate the db mask. */ { constexpr int MaskLen = EmLen - HashLen - 1; constexpr int HashIters = util::DivideUp(MaskLen, HashLen); u8 mgf1_buf[sizeof(u32) + HashLen]; std::memcpy(std::addressof(mgf1_buf[0]), h, HashLen); std::memset(std::addressof(mgf1_buf[HashLen]), 0, sizeof(u32)); for (int i = 0; i < HashIters; ++i) { /* Set the counter for this iteration. */ mgf1_buf[sizeof(mgf1_buf) - 1] = i; /* Calculate the sha256 to the appropriate place in the work buffer. */ auto *mgf1_dst = reinterpret_cast<se::Sha256Hash *>(std::addressof(work[HashLen * i])); hw::FlushDataCache(mgf1_buf, sizeof(mgf1_buf)); hw::DataSynchronizationBarrierInnerShareable(); se::CalculateSha256(mgf1_dst, mgf1_buf, sizeof(mgf1_buf)); } } /* Decrypt masked db using the mask we just generated. */ for (int i = 0; i < EmLen - HashLen - 1; ++i) { work[i] ^= masked_db[i]; } /* Mask out the top bits. */ u8 *db = work; db[0] &= 0xFF >> (BITSIZEOF(u8) * EmLen - EmBits); /* Verify that DB is of the form 0000...0001 */ constexpr int DbLen = EmLen - HashLen - 1; int salt_ofs = 0; { int looking_for_one = 1; int invalid_db_padding = 0; int is_zero; int is_one; for (size_t i = 0; i < DbLen; /* ... */) { is_zero = (db[i] == 0); is_one = (db[i] == 1); salt_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i)); looking_for_one &= ~is_one; invalid_db_padding |= (looking_for_one & ~is_zero); } is_valid &= (invalid_db_padding == 0); } /* Verify salt. */ is_valid &= (DbLen - salt_ofs) == SaltLen; /* Setup the message to verify. */ const u8 *salt = std::addressof(db[DbLen - SaltLen]); u8 verif_msg[8 + HashLen + SaltLen]; ON_SCOPE_EXIT { util::ClearMemory(verif_msg, sizeof(verif_msg)); }; util::ClearMemory(std::addressof(verif_msg[0]), 8); std::memcpy(std::addressof(verif_msg[8]), std::addressof(msg_hash), HashLen); std::memcpy(std::addressof(verif_msg[8 + HashLen]), salt, SaltLen); /* Verify the final hash. */ return VerifyHash(h, reinterpret_cast<uintptr_t>(std::addressof(verif_msg[0])), sizeof(verif_msg)); } bool VerifyRsaPssSha256(int slot, void *sig, size_t sig_size, const void *msg, size_t msg_size) { /* Exponentiate the signature, using the signature as the destination buffer. */ se::ModularExponentiate(sig, sig_size, slot, sig, sig_size); /* Verify the pss padding. */ return VerifyRsaPssSha256(static_cast<const u8 *>(sig), msg, msg_size); } } bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size) { /* Load the public key into a temporary keyslot. */ const int slot = pkg1::RsaKeySlot_Temporary; se::SetRsaKey(slot, mod, mod_size, RsaPublicKeyExponent, util::size(RsaPublicKeyExponent)); return VerifyRsaPssSha256(slot, sig, sig_size, msg, msg_size); } bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size) { /* Zero-sized messages are always valid. */ if (msg_size == 0) { return true; } /* Ensure that the SE sees correct data for the message. */ hw::FlushDataCache(reinterpret_cast<void *>(msg), msg_size); hw::DataSynchronizationBarrierInnerShareable(); /* Calculate the hash. */ se::Sha256Hash calc_hash; se::CalculateSha256(std::addressof(calc_hash), reinterpret_cast<void *>(msg), msg_size); /* Verify the result. */ return crypto::IsSameBytes(std::addressof(calc_hash), hash, sizeof(calc_hash)); } } ================================================ FILE: exosphere/program/source/boot/secmon_boot_setup.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot.hpp" #include "secmon_boot_cache.hpp" #include "../secmon_setup.hpp" #include "../secmon_key_storage.hpp" namespace ams::secmon::boot { namespace { void ValidateSystemCounters() { const uintptr_t sysctr0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress(); /* Validate the system counter frequency is as expected. */ AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_CNTFID0) == 19'200'000u); /* Validate the system counters are as expected. */ AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 0)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 1)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 2)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 3)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 4)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 5)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 6)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 7)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 8)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 9)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(10)) == 0); AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(11)) == 0); } void SetupPmcRegisters() { const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress(); /* Set the physical address of the warmboot binary to scratch 1. */ if (GetSocType() == fuse::SocType_Mariko) { reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH119, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress())); } else /* if (GetSocType() == fuse::SocType_Erista) */ { reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress())); } /* Configure logging by setting bits 18-19 of scratch 20. */ reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0)); /* Clear the wdt reset flag. */ reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0)); /* Configure warmboot to set Set FUSE_PRIVATEKEYDISABLE to KEY_INVISIBLE. */ reg::ReadWrite(pmc + APBDEV_PMC_SECURE_SCRATCH21, REG_BITS_VALUE(4, 1, 1)); /* NOTE: Here, Nintendo writes the warmboot key. */ /* However, we rely on the bootloader (e.g. fusee/hekate) having already done this. */ /* reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH32, ...); */ } /* This function derives the master kek and device keys using the tsec root key. */ void DeriveMasterKekAndDeviceKeyErista(bool is_prod) { /* NOTE: Exosphere does not use this in practice, and expects the bootloader to set up keys already. */ /* NOTE: This function is currently not implemented. If implemented, it will only be a reference implementation. */ if constexpr (false) { /* TODO: Consider implementing this as a reference. */ } AMS_UNUSED(is_prod); } void DeriveMasterKekAndDeviceKeyMariko(bool is_prod) { /* Clear all keyslots other than KEK and SBK in SE1. */ for (int i = 0; i < pkg1::AesKeySlot_Count; ++i) { if (i != pkg1::AesKeySlot_MarikoKek && i != pkg1::AesKeySlot_SecureBoot) { se::ClearAesKeySlot(i); } } /* Clear all keyslots in SE2. */ for (int i = 0; i < pkg1::AesKeySlot_Count; ++i) { se::ClearAesKeySlot2(i); } /* Derive the master kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_MasterKek, pkg1::AesKeySlot_MarikoKek, GetMarikoMasterKekSource(is_prod), se::AesBlockSize); /* Derive the device master key source kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko, pkg1::AesKeySlot_SecureBoot, GetDeviceMasterKeySourceKekSource(), se::AesBlockSize); /* Clear the KEK, now that we're done using it. */ se::ClearAesKeySlot(pkg1::AesKeySlot_MarikoKek); } void DeriveMasterKekAndDeviceKey(bool is_prod) { if (GetSocType() == fuse::SocType_Mariko) { DeriveMasterKekAndDeviceKeyMariko(is_prod); } else /* if (GetSocType() == fuse::SocType_Erista) */ { DeriveMasterKekAndDeviceKeyErista(is_prod); } } void DeriveMasterKey() { if (GetSocType() == fuse::SocType_Mariko) { se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, GetMasterKeySource(), se::AesBlockSize); } else /* if (GetSocType() == fuse::SocType_Erista) */ { /* Nothing to do here; erista bootloader will have derived master key already. */ } } void SetupRandomKey(int slot, se::KeySlotLockFlags flags) { /* Create an aligned buffer to hold the key. */ constexpr size_t KeySize = se::AesBlockSize; util::AlignedBuffer<hw::DataCacheLineSize, KeySize> key; /* Ensure data is consistent before triggering the SE. */ hw::FlushDataCache(key, KeySize); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes into the key. */ se::GenerateRandomBytes(key, KeySize); /* Ensure that the CPU sees consistent data. */ hw::DataSynchronizationBarrierInnerShareable(); hw::FlushDataCache(key, KeySize); hw::DataSynchronizationBarrierInnerShareable(); /* Use the random bytes as a key source. */ se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_DeviceMaster, key, KeySize); /* Lock the keyslot. */ se::LockAesKeySlot(slot, flags); } bool TestKeyGeneration(int generation, bool is_prod) { /* Decrypt the vector chain from generation to start. */ int slot = pkg1::AesKeySlot_Master; for (int i = generation; i > 0; --i) { se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, GetMasterKeyVector(is_prod, i), se::AesBlockSize); slot = pkg1::AesKeySlot_Temporary; } /* Decrypt the final vector. */ u8 test_vector[se::AesBlockSize]; se::DecryptAes128(test_vector, se::AesBlockSize, slot, GetMasterKeyVector(is_prod, 0), se::AesBlockSize); constexpr u8 ZeroBlock[se::AesBlockSize] = {}; return crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize); } int DetermineKeyGeneration(bool is_prod) { /* Test each generation in order. */ for (int generation = 0; generation < pkg1::KeyGeneration_Count; ++generation) { if (TestKeyGeneration(generation, is_prod)) { return generation; } } /* We must have found a correct key generation. */ AMS_ABORT(); } void DeriveAllMasterKeys(bool is_prod, u8 * const work_block) { /* Determine the generation. */ const int generation = DetermineKeyGeneration(is_prod); AMS_SECMON_LOG("KeyGen: %02X\n", static_cast<unsigned int>(generation)); /* Set the global generation. */ ::ams::secmon::impl::SetKeyGeneration(generation); /* Derive all old keys. */ int slot = pkg1::AesKeySlot_Master; for (int i = generation; i > 0; --i) { /* Decrypt the old master key. */ se::DecryptAes128(work_block, se::AesBlockSize, slot, GetMasterKeyVector(is_prod, i), se::AesBlockSize); /* Set the old master key. */ SetMasterKey(i - 1, work_block, se::AesBlockSize); /* Set the old master key into a temporary keyslot. */ se::SetAesKey(pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize); /* Perform the next decryption with the older master key. */ slot = pkg1::AesKeySlot_Temporary; } } void DeriveAllDeviceMasterKeys(bool is_prod, u8 * const work_block) { /* Get the current key generation. */ const int current_generation = secmon::GetKeyGeneration(); /* Get the kek slot. */ const int kek_slot = GetSocType() == fuse::SocType_Mariko ? pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko : pkg1::AesKeySlot_DeviceMasterKeySourceKekErista; /* Iterate for all generations. */ for (int i = 0; i < pkg1::OldDeviceMasterKeyCount; ++i) { const int generation = pkg1::KeyGeneration_4_0_0 + i; /* Load the first master key into the temporary keyslot keyslot. */ LoadMasterKey(pkg1::AesKeySlot_Temporary, pkg1::KeyGeneration_1_0_0); /* Decrypt the device master kek for the generation. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, GetDeviceMasterKekSource(is_prod, i), se::AesBlockSize); /* Decrypt the device master key source into the work block. */ se::DecryptAes128(work_block, se::AesBlockSize, kek_slot, GetDeviceMasterKeySourceSource(i), se::AesBlockSize); /* If we're decrypting the current device master key, decrypt into the keyslot. */ if (generation == current_generation) { se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize); } else { /* Otherwise, decrypt the work block into itself and set the old device master key. */ se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize); /* Set the device master key. */ SetDeviceMasterKey(generation, work_block, se::AesBlockSize); } } /* Clear and lock the Device Master Key Source Kek. */ se::ClearAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko); se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKekMariko, se::KeySlotLockFlags_AllLockKek); } void DeriveAllKeys(bool is_prod) { /* Get the ephemeral work block. */ u8 * const work_block = se::GetEphemeralWorkBlock(); ON_SCOPE_EXIT { util::ClearMemory(work_block, se::AesBlockSize); }; /* Lock the master key as a key. */ se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKey); /* Setup a random key to protect the old master and device master keys. */ SetupRandomKey(pkg1::AesKeySlot_RandomForKeyStorageWrap, se::KeySlotLockFlags_AllLockKey); /* Derive the master keys. */ DeriveAllMasterKeys(is_prod, work_block); /* Lock the master key as a kek. */ se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKek); /* Derive the device master keys. */ DeriveAllDeviceMasterKeys(is_prod, work_block); /* Lock the device master key as a kek. */ se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMaster, se::KeySlotLockFlags_AllLockKek); /* Setup a random key to protect user keys. */ SetupRandomKey(pkg1::AesKeySlot_RandomForUserWrap, se::KeySlotLockFlags_AllLockKek); } void InitializeKeys() { /* Read lock all aes keys. */ for (int i = 0; i < se::AesKeySlotCount; ++i) { se::LockAesKeySlot(i, se::KeySlotLockFlags_AllReadLock); } /* Lock the secure monitor aes keys to be secmon only and non-readable. */ for (int i = pkg1::AesKeySlot_SecmonStart; i < pkg1::AesKeySlot_SecmonEnd; ++i) { se::LockAesKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey); } /* Lock the unused keyslots entirely. */ static_assert(pkg1::AesKeySlot_UserEnd <= pkg1::AesKeySlot_SecmonStart); for (int i = pkg1::AesKeySlot_UserEnd; i < pkg1::AesKeySlot_SecmonStart; ++i) { se::LockAesKeySlot(i, se::KeySlotLockFlags_AllLockKek); } /* Read lock all rsa keys. */ for (int i = 0; i < se::RsaKeySlotCount; ++i) { se::LockRsaKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey | se::KeySlotLockFlags_KeyRead); } /* Initialize the rng. */ se::InitializeRandom(); /* Determine whether we're production. */ const bool is_prod = IsProduction(); /* Derive the master kek and device key. */ /* NOTE: This is a no-op on erista, because fusee will have set up keys. */ DeriveMasterKekAndDeviceKey(is_prod); /* Lock the device key as only usable as a kek. */ se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek); /* Derive the master key. */ DeriveMasterKey(); /* Derive all other keys. */ DeriveAllKeys(is_prod); } } namespace { using namespace ams::mmu; constexpr void UnmapPhysicalIdentityMappingImpl(u64 *l1, u64 *l2, u64 *l3) { /* Invalidate the L3 entries for the tzram and iram boot code regions. */ InvalidateL3Entries(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize()); InvalidateL3Entries(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize()); /* Unmap the L2 entries corresponding to those L3 entries. */ InvalidateL2Entries(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalIramL2.GetSize()); InvalidateL2Entries(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2.GetSize()); /* Unmap the L1 entry corresponding to to those L2 entries. */ InvalidateL1Entries(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysical.GetSize()); } constexpr void UnmapDramImpl(u64 *l1, u64 *l2, u64 *l3) { /* Unmap the L1 entry corresponding to to the Dram entries. */ AMS_UNUSED(l2, l3); InvalidateL1Entries(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize()); } constexpr void UnmapMarikoProgramImpl(u64 *l1, u64 *l2, u64 *l3) { /* Unmap the L1 entry corresponding to to the Dram entries. */ AMS_UNUSED(l1, l2); InvalidateL3Entries(l3, MemoryRegionVirtualTzramMarikoProgram.GetAddress(), MemoryRegionVirtualTzramMarikoProgram.GetSize()); } } void InitializeColdBoot() { /* Ensure that the system counters are valid. */ ValidateSystemCounters(); /* Set the security engine to Tzram Secure. */ se::SetTzramSecure(); /* Set the security engine to Per Key Secure. */ se::SetPerKeySecure(); /* Set the security engine to Context Save Secure. */ se::SetContextSaveSecure(); /* Setup the PMC registers. */ SetupPmcRegisters(); /* Lockout the scratch that we've just written. */ /* pmc::LockSecureRegisters(1); */ /* Generate a random srk. */ se::GenerateSrk(); /* Initialize the SE keyslots. */ InitializeKeys(); /* Save a test vector for the SE keyslots. */ SaveSecurityEngineAesKeySlotTestVector(); } void UnmapPhysicalIdentityMapping() { /* Get the tables. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); /* Unmap. */ UnmapPhysicalIdentityMappingImpl(l1, l2_l3, l2_l3); /* Ensure the mappings are consistent. */ secmon::boot::EnsureMappingConsistency(); } void UnmapDram() { /* Get the tables. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); /* Unmap. */ UnmapDramImpl(l1, l2_l3, l2_l3); /* Ensure the mappings are consistent. */ secmon::boot::EnsureMappingConsistency(); } void LoadMarikoProgram() { void * const mariko_program_dst = MemoryRegionVirtualTzramMarikoProgram.GetPointer<void>(); void * const mariko_program_src = MemoryRegionPhysicalMarikoProgramImage.GetPointer<void>(); const size_t mariko_program_size = MemoryRegionVirtualTzramMarikoProgram.GetSize(); if (fuse::GetSocType() == fuse::SocType_Mariko) { /* On Mariko, we want to load the mariko program image into mariko tzram. */ std::memcpy(mariko_program_dst, mariko_program_src, mariko_program_size); hw::FlushDataCache(mariko_program_dst, mariko_program_size); } else { /* On Erista, we don't have mariko-only-tzram, so unmap it. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); UnmapMarikoProgramImpl(l1, l2_l3, l2_l3); } /* Clear the Mariko program image from DRAM. */ util::ClearMemory(mariko_program_src, mariko_program_size); hw::FlushDataCache(mariko_program_src, mariko_program_size); hw::DataSynchronizationBarrierInnerShareable(); /* Ensure the mappings are consistent. */ secmon::boot::EnsureMappingConsistency(); } } ================================================ FILE: exosphere/program/source/boot/secmon_crt0.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .crt0.text.start, "ax", %progbits .align 6 .global _start _start: /* mask all interrupts */ msr daifset, #0xF /* Set the stack pointer to a temporary location. */ ldr x20, =0x7C010800 mov sp, x20 /* Initialize all memory to expected state. */ ldr x0, =__bss_start__ ldr x1, =__bss_end__ ldr x2, =__boot_bss_start__ ldr x3, =__boot_bss_end__ bl _ZN3ams6secmon4boot10InitializeEmmmm /* Jump to the first bit of virtual code. */ ldr x16, =_ZN3ams6secmon5StartEv br x16 ================================================ FILE: exosphere/program/source/boot/secmon_crt0_cpp.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot.hpp" #include "../secmon_setup.hpp" extern "C" void __libc_init_array(); namespace ams::secmon::boot { void Initialize(uintptr_t bss_start, size_t bss_end, uintptr_t boot_bss_start, uintptr_t boot_bss_end) { /* Set our start time. */ auto &secmon_params = *MemoryRegionPhysicalDeviceBootloaderParams.GetPointer<pkg1::SecureMonitorParameters>(); secmon_params.secmon_start_time = *reinterpret_cast<volatile u32 *>(MemoryRegionPhysicalDeviceTimer.GetAddress() + 0x10); /* Setup DMA controllers. */ SetupSocDmaControllers(); /* Make the page table. */ MakePageTable(); /* Setup memory controllers the MMU. */ SetupCpuMemoryControllersEnableMmu(); /* Clear bss. */ std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start); std::memset(reinterpret_cast<void *>(boot_bss_start), 0, boot_bss_end - boot_bss_start); /* Call init array. */ __libc_init_array(); } } ================================================ FILE: exosphere/program/source/boot/secmon_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_boot.hpp" #include "secmon_boot_functions.hpp" #include "../smc/secmon_random_cache.hpp" #include "../smc/secmon_smc_handler.hpp" #include "../secmon_cache.hpp" #include "../secmon_cpu_context.hpp" #include "../secmon_misc.hpp" #include "../secmon_setup.hpp" namespace ams::secmon { namespace { constexpr inline const uintptr_t Package2LoadAddress = MemoryRegionDramPackage2Payloads.GetAddress(); } void Main() { /* Set library register addresses. */ actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress()); flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress()); fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress()); gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress()); i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress()); i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress()); pinmux::SetRegisterAddress(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress()); pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress()); se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress(), MemoryRegionVirtualDeviceSecurityEngine2.GetAddress()); uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress()); wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress()); util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress()); /* Get the secure monitor parameters. */ auto &secmon_params = *reinterpret_cast<pkg1::SecureMonitorParameters *>(MemoryRegionVirtualDeviceBootloaderParams.GetAddress()); /* Perform initialization. */ { /* Perform initial setup. */ /* This checks the security engine's validity, and configures common interrupts in the GIC. */ /* This also initializes the global configuration context. */ secmon::Setup1(); AMS_SECMON_LOG("%s\n", "Boot begin."); /* Save the boot info. */ secmon::SaveBootInfo(secmon_params); /* Perform cold-boot specific init. */ secmon::boot::InitializeColdBoot(); /* Setup the SoC security measures. */ secmon::SetupSocSecurity(); /* Setup the Cpu core context. */ secmon::SetupCpuCoreContext(); /* Clear the crt0 code that was present in iram. */ secmon::boot::ClearIramBootCode(); /* Clear the debug code from iram, if we're not in debug config. */ #if !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING) secmon::boot::ClearIramDebugCode(); #endif /* Alert the bootloader that we're initialized. */ secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized; hw::FlushDataCache(std::addressof(secmon_params.secmon_state), sizeof(secmon_params.secmon_state)); hw::DataSynchronizationBarrierInnerShareable(); } /* Wait for NX Bootloader to finish loading the BootConfig. */ secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedBootConfig); hw::DataSynchronizationBarrierInnerShareable(); /* Load the bootconfig. */ secmon::boot::LoadBootConfig(MemoryRegionPhysicalIramBootConfig.GetPointer()); /* Verify or clear the boot config. */ secmon::boot::VerifyOrClearBootConfig(); /* Get the boot config. */ const auto &bc = secmon::GetBootConfig(); /* Set the tsc value by the boot config. */ { constexpr u64 TscMask = (static_cast<u64>(1) << 55) - 1; secmon::boot::EnableTsc(bc.data.GetInitialTscValue() & TscMask); } /* Wait for NX Bootloader to initialize DRAM. */ secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_InitializedDram); /* Secure the PMC and MC. */ secmon::SetupPmcAndMcSecure(); /* Copy warmboot to dram. */ { /* Define warmboot extents. */ const void * const src = MemoryRegionPhysicalIramWarmbootBin.GetPointer(); void * const dst = MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware.GetPointer(); const size_t size = MemoryRegionPhysicalIramWarmbootBin.GetSize(); /* Ensure we copy the correct data. */ hw::FlushDataCache(src, size); hw::DataSynchronizationBarrierInnerShareable(); /* Copy warmboot.bin to its secure dram location. */ std::memcpy(dst, src, size); } /* Load the mariko program image. */ secmon::boot::LoadMarikoProgram(); /* Setup the GPU carveout's magic numbers. */ secmon::boot::WriteGpuCarveoutMagicNumbers(); /* Wait for NX bootloader to load Package2. */ secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedPackage2); /* Parse and decrypt the package2 header. */ pkg2::Package2Meta &pkg2_meta = secmon::boot::GetEphemeralPackage2Meta(); const uintptr_t pkg2_payloads_start = MemoryRegionDramPackage2.GetAddress() + sizeof(pkg2::Package2Header); { /* Read the encrypred header. */ pkg2::Package2Header encrypted_header; const auto *dram_header = MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>(); hw::FlushDataCache(dram_header, sizeof(*dram_header)); hw::DataSynchronizationBarrierInnerShareable(); std::memcpy(std::addressof(encrypted_header), dram_header, sizeof(encrypted_header)); /* Atmosphere extension: support plaintext package2, identified by all-zeroes signature and decrypted header. */ secmon::boot::UpdateBootConfigForPackage2Header(encrypted_header); /* Verify the package2 header's signature. */ secmon::boot::VerifyPackage2HeaderSignature(encrypted_header, !bc.signed_data.IsPackage2SignatureVerificationDisabled()); /* Decrypt the package2 header. */ secmon::boot::DecryptPackage2Header(std::addressof(pkg2_meta), encrypted_header.meta, !bc.signed_data.IsPackage2EncryptionDisabled()); } /* Verify the package2 header. */ secmon::boot::VerifyPackage2Header(pkg2_meta); /* Save the package2 hash if in recovery boot. */ if (secmon::IsRecoveryBoot()) { se::Sha256Hash hash; secmon::boot::CalculatePackage2Hash(std::addressof(hash), pkg2_meta, MemoryRegionDramPackage2.GetAddress()); secmon::SetPackage2Hash(hash); } /* Verify the package2 payloads. */ secmon::boot::CheckVerifyResult(secmon::boot::VerifyPackage2Payloads(pkg2_meta, pkg2_payloads_start), pkg1::ErrorInfo_InvalidPackage2Payload, "pkg2 payload FAIL"); /* Decrypt/Move the package2 payloads to the right places. */ secmon::boot::DecryptAndLoadPackage2Payloads(Package2LoadAddress, pkg2_meta, pkg2_payloads_start, !bc.signed_data.IsPackage2EncryptionDisabled()); /* Ensure that the CPU sees correct package2 data. */ secmon::FlushEntireDataCache(); secmon::EnsureInstructionConsistency(); /* Set the core's entrypoint and argument. */ secmon::SetEntryContext(0, Package2LoadAddress + pkg2_meta.entrypoint, 0); /* Clear the boot keys from iram. */ secmon::boot::ClearIramBootKeys(); /* Unmap the identity mapping. */ secmon::boot::UnmapPhysicalIdentityMapping(); /* Unmap DRAM. */ secmon::boot::UnmapDram(); /* Wait for NX bootloader to be done. */ secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_Done); /* Perform final initialization. */ secmon::SetupSocProtections(); secmon::SetupCpuSErrorDebug(); /* Configure the smc handler tables to reflect the current target firmware. */ secmon::smc::ConfigureSmcHandlersForTargetFirmware(); AMS_SECMON_LOG("%s\n", "Boot end."); } } ================================================ FILE: exosphere/program/source/boot/secmon_make_page_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_setup.hpp" #include "secmon_boot.hpp" namespace ams::secmon::boot { namespace { using namespace ams::mmu; constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoCode, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwCode, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoData, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexDevice); constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexDevice); constexpr void ClearMemory(volatile u64 *start, size_t size) { volatile u64 * const end = start + (size / sizeof(u64)); for (volatile u64 *cur = start; cur < end; ++cur) { *cur = 0; } } constexpr void MakePageTablesImpl(u64 *l1, u64 *l2, u64 *l3) { /* Setup the L1 table. */ { ClearMemory(l1, MemoryRegionPhysicalTzramL1PageTable.GetSize()); /* Create an L1 table entry for the physical region. */ SetL1TableEntry(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); static_assert(GetL1EntryIndex(MemoryRegionPhysical.GetAddress()) == 1); /* Create an L1 mapping entry for dram. */ SetL1BlockEntry(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize(), MappingAttributesEl3NonSecureRwData); /* Create an L1 table entry for the virtual region. */ SetL1TableEntry(l1, MemoryRegionVirtual.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); } /* Setup the L2 table. */ { ClearMemory(l2, MemoryRegionPhysicalTzramL2L3PageTable.GetSize()); /* Create an L2 table entry for the virtual region. */ SetL2TableEntry(l2, MemoryRegionVirtualL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); /* Create an L2 table entry for the physical iram region. */ SetL2TableEntry(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); /* Create an L2 table entry for the physical tzram region. */ SetL2TableEntry(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); } /* Setup the L3 table. */ { /* L2 and L3 share a page table. */ if (l2 != l3) { ClearMemory(l3, MemoryRegionPhysicalTzramL2L3PageTable.GetSize()); } /* Identity-map TZRAM as rwx. */ SetL3BlockEntry(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize(), MappingAttributesEl3SecureRwCode); /* Identity-map IRAM boot code as rwx. */ SetL3BlockEntry(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize(), MappingAttributesEl3SecureRwCode); #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) { /* Map the debug code region as rwx. */ SetL3BlockEntry(l3, MemoryRegionVirtualDebugCode.GetAddress(), MemoryRegionPhysicalDebugCode.GetAddress(), MemoryRegionPhysicalDebugCode.GetSize(), MappingAttributesEl3SecureRwCode); /* Map the DRAM debug code store region as rw. */ SetL3BlockEntry(l3, MemoryRegionVirtualDramDebugDataStore.GetAddress(), MemoryRegionPhysicalDramDebugDataStore.GetAddress(), MemoryRegionPhysicalDramDebugDataStore.GetSize(), MappingAttributesEl3NonSecureRwData); } #endif /* Map all devices. */ { #define MAP_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \ SetL3BlockEntry(l3, MemoryRegionVirtualDevice##_NAME_.GetAddress(), MemoryRegionPhysicalDevice##_NAME_.GetAddress(), MemoryRegionVirtualDevice##_NAME_.GetSize(), _SECURE_ ? MappingAttributesEl3SecureDevice : MappingAttributesEl3NonSecureDevice); AMS_SECMON_FOREACH_DEVICE_REGION(MAP_DEVICE_REGION); #undef MAP_DEVICE_REGION } /* Map the IRAM SC7 work region. */ SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Work.GetAddress(), MemoryRegionPhysicalIramSc7Work.GetAddress(), MemoryRegionVirtualIramSc7Work.GetSize(), MappingAttributesEl3NonSecureDevice); /* Map the IRAM SC7 firmware region. */ SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Firmware.GetAddress(), MemoryRegionPhysicalIramSc7Firmware.GetAddress(), MemoryRegionVirtualIramSc7Firmware.GetSize(), MappingAttributesEl3NonSecureDevice); /* Map the Debug region. */ /* NOTE: This region is reserved for debug. By default it will be the last 0x8000 bytes of IRAM, but this is subject to change. */ /* If you are doing development work for exosphere, feel free to locally change this to whatever is useful. */ SetL3BlockEntry(l3, MemoryRegionVirtualDebug.GetAddress(), MemoryRegionPhysicalIram.GetEndAddress() - 0x8000, 0x8000, MappingAttributesEl3SecureDevice); /* Map the TZRAM ro alias region. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramReadOnlyAlias.GetAddress(), MemoryRegionPhysicalTzramReadOnlyAlias.GetAddress(), MemoryRegionVirtualTzramReadOnlyAlias.GetSize(), MappingAttributesEl3SecureRoData); /* Map the DRAM secure data store region. */ SetL3BlockEntry(l3, MemoryRegionVirtualDramSecureDataStore.GetAddress(), MemoryRegionPhysicalDramSecureDataStore.GetAddress(), MemoryRegionVirtualDramSecureDataStore.GetSize(), MappingAttributesEl3NonSecureDevice); /* Map the program region as rwx. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramProgram.GetAddress(), MemoryRegionPhysicalTzramProgram.GetAddress(), MemoryRegionVirtualTzramProgram.GetSize(), MappingAttributesEl3SecureRwCode); /* Map the mariko program region as rwx. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramMarikoProgram.GetAddress(), MemoryRegionPhysicalTzramMarikoProgram.GetAddress(), MemoryRegionPhysicalTzramMarikoProgram.GetSize(), MappingAttributesEl3SecureRwCode); /* Map the mariko program region as rwx. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramMarikoProgramStack.GetAddress(), MemoryRegionPhysicalTzramMarikoProgramStack.GetAddress(), MemoryRegionPhysicalTzramMarikoProgramStack.GetSize(), MappingAttributesEl3SecureRwData); /* Map the boot code region. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramBootCode.GetAddress(), MemoryRegionPhysicalTzramBootCode.GetAddress(), MemoryRegionVirtualTzramBootCode.GetSize(), MappingAttributesEl3SecureRwCode); /* Map the volatile data regions regions. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileData.GetAddress(), MemoryRegionPhysicalTzramVolatileData.GetAddress(), MemoryRegionVirtualTzramVolatileData.GetSize(), MappingAttributesEl3SecureRwData); SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileStack.GetAddress(), MemoryRegionPhysicalTzramVolatileStack.GetAddress(), MemoryRegionVirtualTzramVolatileStack.GetSize(), MappingAttributesEl3SecureRwData); /* Map the configuration data. */ SetL3BlockEntry(l3, MemoryRegionVirtualTzramConfigurationData.GetAddress(), MemoryRegionPhysicalTzramConfigurationData.GetAddress(), MemoryRegionVirtualTzramConfigurationData.GetSize(), MappingAttributesEl3SecureRwData); /* Map the page tables. */ SetL3BlockEntry(l3, util::AlignDown(MemoryRegionVirtualTzramL1PageTable.GetAddress(), PageSize), util::AlignDown(MemoryRegionPhysicalTzramL1PageTable.GetAddress(), PageSize), PageSize, MappingAttributesEl3SecureRwData); SetL3BlockEntry(l3, MemoryRegionVirtualTzramL2L3PageTable.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), MemoryRegionVirtualTzramL2L3PageTable.GetSize(), MappingAttributesEl3SecureRwData); } } constexpr bool ValidateTzramPageTables() { u64 l1_table[MemoryRegionPhysicalTzramL1PageTable.GetSize() / sizeof(u64)] = {}; u64 l2_l3_table[MemoryRegionPhysicalTzramL2L3PageTable.GetSize() / sizeof(u64)] = {}; MakePageTablesImpl(l1_table, l2_l3_table, l2_l3_table); return true; } static_assert(ValidateTzramPageTables()); } void MakePageTable() { u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer<u64>(); MakePageTablesImpl(l1, l2_l3, l2_l3); } } ================================================ FILE: exosphere/program/source/boot/secmon_package2.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_key_storage.hpp" #include "secmon_boot.hpp" namespace ams::secmon::boot { void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start) { /* Determine the region to hash. */ const void *data = reinterpret_cast<const void *>(package2_start); const size_t size = meta.GetSize(); /* Flush to ensure the SE sees the correct data. */ hw::FlushDataCache(data, size); hw::DataSynchronizationBarrierInnerShareable(); /* Calculate the hash. */ se::CalculateSha256(dst, data, size); } bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size) { return VerifySignature(header.signature, sizeof(header.signature), mod, mod_size, std::addressof(header.meta), sizeof(header.meta)); } int PrepareMasterKey(int key_generation) { if (key_generation == GetKeyGeneration()) { return pkg1::AesKeySlot_Master; } constexpr int Slot = pkg1::AesKeySlot_Temporary; LoadMasterKey(Slot, key_generation); return Slot; } void PreparePackage2Key(int pkg2_slot, int key_generation, const void *key, size_t key_size) { /* Get keyslot for the desired master key. */ const int master_slot = PrepareMasterKey(key_generation); /* Load the package2 key into the desired keyslot. */ se::SetEncryptedAesKey128(pkg2_slot, master_slot, key, key_size); } void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *key, size_t key_size, const void *iv, size_t iv_size, u8 key_generation) { /* Ensure that the SE sees consistent data. */ hw::FlushDataCache(key, key_size); hw::FlushDataCache(src, src_size); hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); /* Load the package2 key into the temporary keyslot. */ PreparePackage2Key(pkg1::AesKeySlot_Temporary, key_generation, key, key_size); /* Decrypt the data. */ se::ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Temporary, src, src_size, iv, iv_size); /* Clear the keyslot we just used. */ se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary); /* Ensure that the cpu sees consistent data. */ hw::DataSynchronizationBarrierInnerShareable(); hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); } bool VerifyPackage2Meta(const pkg2::Package2Meta &meta) { /* Get the obfuscated metadata. */ const size_t size = meta.GetSize(); const u8 key_generation = meta.GetKeyGeneration(); /* Check that size is big enough for the header. */ if (size <= sizeof(pkg2::Package2Header)) { return false; } /* Check that the size isn't larger than what we allow. */ if (size > pkg2::Package2SizeMax) { return false; } /* Check that the key generation is one that we can use. */ static_assert(pkg1::KeyGeneration_Count == 21); if (key_generation >= pkg1::KeyGeneration_Count) { return false; } /* Check the magic number. */ if (!crypto::IsSameBytes(meta.magic, pkg2::Package2Meta::Magic::String, sizeof(meta.magic))) { return false; } /* Check the payload alignments. */ if ((meta.entrypoint % pkg2::PayloadAlignment) != 0) { return false; } for (int i = 0; i < pkg2::PayloadCount; ++i) { if ((meta.payload_sizes[i] % pkg2::PayloadAlignment) != 0) { return false; } } /* Check that the sizes sum to the total. */ if (size != sizeof(pkg2::Package2Header) + meta.payload_sizes[0] + meta.payload_sizes[1] + meta.payload_sizes[2]) { return false; } /* Check that the payloads do not overflow. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { if (meta.payload_offsets[i] > meta.payload_offsets[i] + meta.payload_sizes[i]) { return false; } } /* Verify that no payloads overlap. */ for (int i = 0; i < pkg2::PayloadCount - 1; ++i) { for (int j = i + 1; j < pkg2::PayloadCount; ++j) { if (util::HasOverlap(meta.payload_offsets[i], meta.payload_sizes[i], meta.payload_offsets[j], meta.payload_sizes[j])) { return false; } } } /* Check whether any payload contains the entrypoint. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { if (util::Contains(meta.payload_offsets[i], meta.payload_sizes[i], meta.entrypoint)) { return true; } } /* No payload contains the entrypoint, so we're not valid. */ return false; } bool VerifyPackage2Version(const pkg2::Package2Meta &meta) { return meta.bootloader_version <= pkg2::CurrentBootloaderVersion && meta.package2_version >= pkg2::MinimumValidDataVersion; } bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) { /* Verify hashes match for all payloads. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { /* Allow all-zero bytes to match any payload. */ if (!(meta.payload_hashes[i][0] == 0 && std::memcmp(meta.payload_hashes[i] + 0, meta.payload_hashes[i] + 1, sizeof(meta.payload_hashes[i]) - 1) == 0)) { if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) { return false; } } payload_address += meta.payload_sizes[i]; } return true; } } ================================================ FILE: exosphere/program/source/boot/secmon_size_data.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .metadata.sizes, "ax", %progbits .align 6 .global __metadata__sizes __metadata__sizes: .quad 0xAAAAAAAAAAAAAAAA, 0xBBBBBBBBBBBBBBBB .quad __glob_start__ .quad __bootcode_start__ .quad __bootcode_end__ .quad __program_start__ .quad 0xCCCCCCCCCCCCCCCC, 0xDDDDDDDDDDDDDDDD ================================================ FILE: exosphere/program/source/secmon_cache.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_cache.hpp" namespace ams::secmon { #include "secmon_cache_impl.inc" } ================================================ FILE: exosphere/program/source/secmon_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { #include "secmon_cache.inc" } ================================================ FILE: exosphere/program/source/secmon_cache.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ void FlushEntireDataCache(); void FlushEntireDataCacheLocal(); void InvalidateEntireDataCache(); void EnsureMappingConsistency(); void EnsureMappingConsistency(uintptr_t address); void EnsureInstructionConsistency(); ================================================ FILE: exosphere/program/source/secmon_cache_impl.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ namespace { ALWAYS_INLINE int FloorLog2(int v) { return BITSIZEOF(u32) - (hw::CountLeadingZeros(static_cast<u32>(v)) + 1); } ALWAYS_INLINE int CeilLog2(int v) { const int log = FloorLog2(v); return ((1 << log) == v) ? log : log + 1; } void FlushDataCacheTo(int loc) { for (int level = 0; level < loc; ++level) { /* Set the selection register. */ { util::BitPack32 csselr = {}; csselr.Set<hw::CsselrEl1::InD>(0); csselr.Set<hw::CsselrEl1::Level>(level); HW_CPU_SET_CSSELR_EL1(csselr); } /* Ensure that reordering doesn't occur around this operation. */ hw::InstructionSynchronizationBarrier(); /* Get ccsidr. */ util::BitPack32 ccsidr; HW_CPU_GET_CCSIDR_EL1(ccsidr); /* Get cache size id info. */ const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1; const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1; const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4; const int way_shift = 32 - FloorLog2(num_ways); const int set_shift = line_size; for (int way = 0; way <= num_ways; way++) { for (int set = 0; set <= num_sets; set++) { const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1); __asm__ __volatile__("dc cisw, %[value]" :: [value]"r"(value) : "memory"); } } } } void FlushDataCacheFrom(int loc) { for (int level = loc - 1; level >= 0; --level) { /* Set the selection register. */ { util::BitPack32 csselr = {}; csselr.Set<hw::CsselrEl1::InD>(0); csselr.Set<hw::CsselrEl1::Level>(level); HW_CPU_SET_CSSELR_EL1(csselr); } /* Ensure that reordering doesn't occur around this operation. */ hw::InstructionSynchronizationBarrier(); /* Get ccsidr. */ util::BitPack32 ccsidr; HW_CPU_GET_CCSIDR_EL1(ccsidr); /* Get cache size id info. */ const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1; const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1; const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4; const int way_shift = 32 - FloorLog2(num_ways); const int set_shift = line_size; for (int way = 0; way <= num_ways; way++) { for (int set = 0; set <= num_sets; set++) { const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1); __asm__ __volatile__("dc cisw, %[value]" :: [value]"r"(value) : "memory"); } } } } void InvalidateDataCacheTo(int loc) { for (int level = 0; level < loc; ++level) { /* Set the selection register. */ { util::BitPack32 csselr = {}; csselr.Set<hw::CsselrEl1::InD>(0); csselr.Set<hw::CsselrEl1::Level>(level); HW_CPU_SET_CSSELR_EL1(csselr); } /* Ensure that reordering doesn't occur around this operation. */ hw::InstructionSynchronizationBarrier(); /* Get ccsidr. */ util::BitPack32 ccsidr; HW_CPU_GET_CCSIDR_EL1(ccsidr); /* Get cache size id info. */ const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1; const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1; const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4; const int way_shift = 32 - FloorLog2(num_ways); const int set_shift = line_size; for (int way = 0; way <= num_ways; way++) { for (int set = 0; set <= num_sets; set++) { const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1); __asm__ __volatile__("dc isw, %[value]" :: [value]"r"(value) : "memory"); } } } } } void FlushEntireDataCache() { util::BitPack32 clidr; HW_CPU_GET_CLIDR_EL1(clidr); FlushDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>()); } void FlushEntireDataCacheLocal() { util::BitPack32 clidr; HW_CPU_GET_CLIDR_EL1(clidr); FlushDataCacheFrom(clidr.Get<hw::ClidrEl1::Louis>()); } void InvalidateEntireDataCache() { util::BitPack32 clidr; HW_CPU_GET_CLIDR_EL1(clidr); InvalidateDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>()); } void EnsureMappingConsistency() { ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InvalidateEntireTlb(); ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InstructionSynchronizationBarrier(); } void EnsureMappingConsistency(uintptr_t address) { ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InvalidateTlb(address); ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InstructionSynchronizationBarrier(); } void EnsureInstructionConsistency() { ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InvalidateEntireInstructionCache(); ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InstructionSynchronizationBarrier(); } ================================================ FILE: exosphere/program/source/secmon_cpu_context.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_cpu_context.hpp" #include "secmon_error.hpp" namespace ams::secmon { namespace { struct DebugRegisters { u32 osdttrx_el1; u32 osdtrtx_el1; u32 mdscr_el1; u32 oseccr_el1; u32 mdccint_el1; u32 dbgclaimclr_el1; u32 dbgvcr32_el2; u32 sder32_el3; u32 mdcr_el2; u32 mdcr_el3; u32 spsr_el3; }; struct CoreContext { EntryContext entry_context; bool is_on; bool is_reset_expected; bool is_debug_registers_saved; DebugRegisters debug_registers; }; void SaveDebugRegisters(DebugRegisters &dr) { /* Set the OS lock; this will be unlocked by entry code. */ HW_CPU_SET_OSLAR_EL1(1); /* Save general debug registers. */ HW_CPU_GET_OSDTRRX_EL1 (dr.osdttrx_el1); HW_CPU_GET_OSDTRTX_EL1 (dr.osdtrtx_el1); HW_CPU_GET_MDSCR_EL1 (dr.mdscr_el1); HW_CPU_GET_OSECCR_EL1 (dr.oseccr_el1); HW_CPU_GET_MDCCINT_EL1 (dr.mdccint_el1); HW_CPU_GET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1); HW_CPU_GET_DBGVCR32_EL2 (dr.dbgvcr32_el2); HW_CPU_GET_SDER32_EL3 (dr.sder32_el3); HW_CPU_GET_MDCR_EL2 (dr.mdcr_el2); HW_CPU_GET_MDCR_EL3 (dr.mdcr_el3); HW_CPU_GET_SPSR_EL3 (dr.spsr_el3); } void RestoreDebugRegisters(const DebugRegisters &dr) { /* Restore general debug registers. */ HW_CPU_SET_OSDTRRX_EL1 (dr.osdttrx_el1); HW_CPU_SET_OSDTRTX_EL1 (dr.osdtrtx_el1); HW_CPU_SET_MDSCR_EL1 (dr.mdscr_el1); HW_CPU_SET_OSECCR_EL1 (dr.oseccr_el1); HW_CPU_SET_MDCCINT_EL1 (dr.mdccint_el1); HW_CPU_SET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1); HW_CPU_SET_DBGVCR32_EL2 (dr.dbgvcr32_el2); HW_CPU_SET_SDER32_EL3 (dr.sder32_el3); HW_CPU_SET_MDCR_EL2 (dr.mdcr_el2); HW_CPU_SET_MDCR_EL3 (dr.mdcr_el3); HW_CPU_SET_SPSR_EL3 (dr.spsr_el3); } constinit CoreContext g_core_contexts[NumCores] = {}; } bool IsCoreOn(int core) { return g_core_contexts[core].is_on; } void SetCoreOff() { g_core_contexts[hw::GetCurrentCoreId()].is_on = false; } bool IsResetExpected() { return g_core_contexts[hw::GetCurrentCoreId()].is_reset_expected; } void SetResetExpected(int core, bool expected) { g_core_contexts[core].is_reset_expected = expected; } void SetResetExpected(bool expected) { SetResetExpected(hw::GetCurrentCoreId(), expected); } void SetEntryContext(int core, uintptr_t address, uintptr_t arg) { g_core_contexts[core].entry_context.pc = address; g_core_contexts[core].entry_context.x0 = arg; } void GetEntryContext(EntryContext *out) { auto &ctx = g_core_contexts[hw::GetCurrentCoreId()]; const auto pc = ctx.entry_context.pc; const auto x0 = ctx.entry_context.x0; if (pc == 0 || ctx.is_on) { SetError(pkg1::ErrorInfo_InvalidCoreContext); AMS_ABORT("Invalid core context"); } ctx.entry_context = {}; ctx.is_on = true; out->pc = pc; out->x0 = x0; } void SaveDebugRegisters() { auto &ctx = g_core_contexts[hw::GetCurrentCoreId()]; SaveDebugRegisters(ctx.debug_registers); ctx.is_debug_registers_saved = true; } void RestoreDebugRegisters() { auto &ctx = g_core_contexts[hw::GetCurrentCoreId()]; if (ctx.is_debug_registers_saved) { RestoreDebugRegisters(ctx.debug_registers); ctx.is_debug_registers_saved = false; } } } ================================================ FILE: exosphere/program/source/secmon_cpu_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { constexpr inline int NumCores = 4; struct EntryContext { u64 x0; u64 pc; }; bool IsCoreOn(int core); void SetCoreOff(); bool IsResetExpected(); void SetResetExpected(int core, bool expected); void SetResetExpected(bool expected); void SetEntryContext(int core, uintptr_t address, uintptr_t arg); void GetEntryContext(EntryContext *out); void SaveDebugRegisters(); void RestoreDebugRegisters(); } ================================================ FILE: exosphere/program/source/secmon_error.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_error.hpp" namespace ams { namespace { constexpr bool SaveSystemStateForDebug = false; } } namespace ams::diag { namespace { ALWAYS_INLINE void SaveSystemStateForDebugAbort() { *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x00) = 0xDDDDDDDD; u64 temp_reg; __asm__ __volatile__("mov %0, lr" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x10) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x14) = static_cast<u32>(temp_reg >> 32); __asm__ __volatile__("mov %0, sp" : "=r"(temp_reg) :: "memory"); for (int i = 0; i < 0x100; i += 4) { *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x20 + i) = *(volatile u32 *)(temp_reg + i); } *(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x50) = 0x02; *(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x00) = 0x10; util::WaitMicroSeconds(1000); } } NORETURN void AbortImpl() { /* Perform any necessary (typically none) debugging. */ if constexpr (SaveSystemStateForDebug) { SaveSystemStateForDebugAbort(); } secmon::SetError(pkg1::ErrorInfo_UnknownAbort); secmon::ErrorReboot(); } #include <exosphere/diag/diag_detailed_assertion_impl.inc> } namespace ams::secmon { namespace { constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress(); ALWAYS_INLINE void SaveSystemStateForDebugErrorReboot() { u64 temp_reg; *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x00) = 0x5A5A5A5A; __asm__ __volatile__("mrs %0, esr_el3" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x08) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x0C) = static_cast<u32>(temp_reg >> 32); __asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x10) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x14) = static_cast<u32>(temp_reg >> 32); __asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x18) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x1C) = static_cast<u32>(temp_reg >> 32); __asm__ __volatile__("mov %0, lr" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x20) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x24) = static_cast<u32>(temp_reg >> 32); __asm__ __volatile__("mov %0, sp" : "=r"(temp_reg) :: "memory"); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x30) = static_cast<u32>(temp_reg >> 0); *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x34) = static_cast<u32>(temp_reg >> 32); for (int i = 0; i < 0x100; i += 4) { *(volatile u32 *)(secmon::MemoryRegionVirtualDebug.GetAddress() + 0x40 + i) = *(volatile u32 *)(temp_reg + i); } *(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x50) = 0x02; *(volatile u32 *)(secmon::MemoryRegionVirtualDevicePmc.GetAddress() + 0x00) = 0x10; util::WaitMicroSeconds(1000); } } void SetError(pkg1::ErrorInfo info) { const uintptr_t address = secmon::MemoryRegionVirtualDevicePmc.GetAddress() + PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH; if (reg::Read(address) == pkg1::ErrorInfo_None) { reg::Write(address, info); } } NORETURN void ErrorReboot() { /* Perform any necessary (typically none) debugging. */ if constexpr (SaveSystemStateForDebug) { SaveSystemStateForDebugErrorReboot(); } /* Lockout the security engine. */ se::Lockout(); /* Lockout fuses. */ fuse::Lockout(); /* Disable crypto operations after reboot. */ reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0); while (true) { wdt::Reboot(); } } } ================================================ FILE: exosphere/program/source/secmon_error.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { void SetError(pkg1::ErrorInfo info); NORETURN void ErrorReboot(); } ================================================ FILE: exosphere/program/source/secmon_exception_handler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_error.hpp" namespace ams::secmon { namespace { constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress(); constinit util::Atomic<bool> g_is_locked = false; } void ExceptionHandlerImpl(uintptr_t lr, uintptr_t sp) { /* On release config, we won't actually use the passed parameters. */ AMS_UNUSED(lr, sp); /* Ensure that previous logs have been flushed. */ AMS_LOG_FLUSH(); /* Get system registers. */ uintptr_t far_el1, far_el3, elr_el3; util::BitPack32 esr_el3; HW_CPU_GET_FAR_EL1(far_el1); HW_CPU_GET_FAR_EL3(far_el3); HW_CPU_GET_ELR_EL3(elr_el3); HW_CPU_GET_ESR_EL3(esr_el3); /* Print some whitespace before the exception handler. */ AMS_LOG("\n\n"); AMS_SECMON_LOG("ExceptionHandler\n"); AMS_SECMON_LOG("----------------\n"); AMS_SECMON_LOG("esr: 0x%08X\n", esr_el3.value); AMS_SECMON_LOG(" Exception Class: 0x%02X\n", esr_el3.Get<hw::EsrEl3::Ec>()); AMS_SECMON_LOG(" Instruction Length: %d\n", esr_el3.Get<hw::EsrEl3::Il>() ? 32 : 16); AMS_SECMON_LOG(" Instruction Specific Syndrome: 0x%07X\n", esr_el3.Get<hw::EsrEl3::Iss>()); AMS_SECMON_LOG("far_el1: 0x%016lX\n", far_el1); AMS_SECMON_LOG("far_el3: 0x%016lX\n", far_el3); AMS_SECMON_LOG("elr_el3: 0x%016lX\n", elr_el3); AMS_SECMON_LOG("lr: 0x%016lX\n", lr); AMS_SECMON_LOG("sp: 0x%016lX\n", sp); AMS_DUMP(reinterpret_cast<void *>(sp), util::AlignUp(sp, mmu::PageSize) - sp); AMS_LOG_FLUSH(); } NORETURN void ExceptionHandler() { /* Get link register and stack pointer. */ u64 lr, sp; { __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); __asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory"); } /* Acquire exclusive access to exception handling logic. */ if (!g_is_locked.Exchange(true)) { /* Invoke the exception handler impl. */ ExceptionHandlerImpl(lr, sp); /* Lockout the security engine. */ se::Lockout(); /* Lockout fuses. */ fuse::Lockout(); /* Disable crypto operations after reboot. */ reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0); /* Perform an error reboot. */ secmon::SetError(pkg1::ErrorInfo_UnknownAbort); secmon::ErrorReboot(); } else { /* Wait forever while the first core prints the exception and reboots. */ while (true) { util::WaitMicroSeconds(1000); } } } } ================================================ FILE: exosphere/program/source/secmon_exception_vectors.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Some macros taken from https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/common/aarch64/asm_macros.S */ /* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Declare the exception vector table, enforcing it is aligned on a * 2KB boundary, as required by the ARMv8 architecture. * Use zero bytes as the fill value to be stored in the padding bytes * so that it inserts illegal AArch64 instructions. This increases * security, robustness and potentially facilitates debugging. */ .macro vector_base label, section_name=.vectors .section \section_name, "ax" .align 11, 0 \label: .endm /* * Create an entry in the exception vector table, enforcing it is * aligned on a 128-byte boundary, as required by the ARMv8 architecture. * Use zero bytes as the fill value to be stored in the padding bytes * so that it inserts illegal AArch64 instructions. This increases * security, robustness and potentially facilitates debugging. */ .macro vector_entry label, section_name=.vectors .cfi_sections .debug_frame .section \section_name, "ax" .align 7, 0 .type \label, %function .func \label .cfi_startproc \label: .endm /* * This macro verifies that the given vector doesnt exceed the * architectural limit of 32 instructions. This is meant to be placed * immediately after the last instruction in the vector. It takes the * vector entry as the parameter */ .macro check_vector_size since .endfunc .cfi_endproc .if (. - \since) > (32 * 4) .error "Vector exceeds 32 instructions" .endif .endm /* Actual Vectors for Secure Monitor. */ .global _ZN3ams6secmon16ExceptionVectorsEv vector_base _ZN3ams6secmon16ExceptionVectorsEv /* Current EL, SP0 */ vector_entry synch_sp0 /* Branch to the exception handler. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv .endfunc .cfi_endproc _ZN3ams6secmon26UnexpectedExceptionHandlerEv: #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) /* Jump to the debug exception handler. */ ldr x16, =_ZN3ams6secmon16ExceptionHandlerEv br x16 #else /* Load the ErrorInfo scratch. */ ldr x0, =0x1F004AC40 /* Write ErrorInfo_UnknownAbort to it. */ ldr w1, =0x07F00010 str w1, [x0] /* Perform an error reboot. */ b _ZN3ams6secmon11ErrorRebootEv #endif vector_entry irq_sp0 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size irq_sp0 vector_entry fiq_sp0 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size fiq_sp0 vector_entry serror_sp0 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size serror_sp0 /* Current EL, SPx */ vector_entry synch_spx /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size synch_spx vector_entry irq_spx /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size irq_spx vector_entry fiq_spx /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size fiq_spx vector_entry serror_spx /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size serror_spx /* Lower EL, A64 */ vector_entry synch_a64 /* Check whether the exception is an SMC. If it's not, take the unexpected handler. */ stp x29, x30, [sp, #-0x10]! mrs x30, esr_el3 lsr w29, w30, #26 cmp w29, #0x17 ldp x29, x30, [sp], #0x10 b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv /* Save x29 and x30. */ stp x29, x30, [sp, #-0x10]! /* Get the current core. */ mrs x29, mpidr_el1 and x29, x29, #3 /* If we're not on core 3, take the core0-2 handler. */ cmp x29, #3 b.ne _ZN3ams6secmon25HandleSmcExceptionCore012Ev /* Handle the smc. */ bl _ZN3ams6secmon18HandleSmcExceptionEv /* Return. */ ldp x29, x30, [sp], #0x10 eret check_vector_size synch_a64 vector_entry irq_a64 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size irq_a64 vector_entry fiq_a64 /* Save x18, x26-x30. */ stp x29, x30, [sp, #-0x10]! stp x28, x18, [sp, #-0x10]! stp x26, x27, [sp, #-0x10]! /* Set x18 to the global data region. */ ldr x18, =0x1F01FA000 /* Get the current core. */ mrs x29, mpidr_el1 and x29, x29, #3 /* If we're not on core 3, take the core0-2 handler. */ cmp x29, #3 b.ne _ZN3ams6secmon25HandleFiqExceptionCore012Ev /* Handle the fiq exception. */ bl _ZN3ams6secmon18HandleFiqExceptionEv /* Restore registers. */ ldp x26, x27, [sp], #0x10 ldp x28, x18, [sp], #0x10 ldp x29, x30, [sp], #0x10 /* Return. */ eret check_vector_size fiq_a64 vector_entry serror_a64 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv .endfunc .cfi_endproc _ZN3ams6secmon25HandleSmcExceptionCore012Ev: /* Acquire exclusive access to the common smc stack. */ stp x4, x5, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! stp x0, x1, [sp, #-0x10]! bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv ldp x0, x1, [sp], #0x10 ldp x2, x3, [sp], #0x10 ldp x4, x5, [sp], #0x10 /* Pivot to use the common smc stack. */ mov x30, sp ldr x29, =0x1F01F6E80 mov sp, x29 stp x29, x30, [sp, #-0x10]! /* Handle the SMC. */ bl _ZN3ams6secmon18HandleSmcExceptionEv /* Restore our core-specific stack. */ ldp x29, x30, [sp], #0x10 mov sp, x30 /* Release our exclusive access to the common smc stack. */ stp x0, x1, [sp, #-0x10]! bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv ldp x0, x1, [sp], #0x10 /* Return. */ ldp x29, x30, [sp], #0x10 eret /* Lower EL, A32 */ vector_entry synch_a32 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv check_vector_size synch_a32 vector_entry irq_a32 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv .endfunc .cfi_endproc _ZN3ams6secmon18HandleSmcExceptionEv: /* Save registers. */ stp x29, x30, [sp, #-0x10]! stp x18, x19, [sp, #-0x10]! stp x16, x17, [sp, #-0x10]! stp x14, x15, [sp, #-0x10]! stp x12, x13, [sp, #-0x10]! stp x10, x11, [sp, #-0x10]! stp x8, x9, [sp, #-0x10]! stp x6, x7, [sp, #-0x10]! stp x4, x5, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! stp x0, x1, [sp, #-0x10]! /* Set x18 to the global data region. */ ldr x18, =0x1F01FA000 /* Get esr. */ mrs x0, esr_el3 and x0, x0, #0xFFFF /* Get the function arguments. */ mov x1, sp /* Invoke the smc handler. */ bl _ZN3ams6secmon3smc9HandleSmcEiRNS1_12SmcArgumentsE /* Restore registers. */ ldp x0, x1, [sp], #0x10 ldp x2, x3, [sp], #0x10 ldp x4, x5, [sp], #0x10 ldp x6, x7, [sp], #0x10 ldp x8, x9, [sp], #0x10 ldp x10, x11, [sp], #0x10 ldp x12, x13, [sp], #0x10 ldp x14, x15, [sp], #0x10 ldp x16, x17, [sp], #0x10 ldp x18, x19, [sp], #0x10 ldp x29, x30, [sp], #0x10 ret vector_entry fiq_a32 /* Handle fiq from a32 the same as fiq from a64. */ b fiq_a64 .endfunc .cfi_endproc _ZN3ams6secmon18HandleFiqExceptionEv: /* Save registers. */ stp x29, x30, [sp, #-0x10]! stp x24, x25, [sp, #-0x10]! stp x22, x23, [sp, #-0x10]! stp x20, x21, [sp, #-0x10]! stp x18, x19, [sp, #-0x10]! stp x16, x17, [sp, #-0x10]! stp x14, x15, [sp, #-0x10]! stp x12, x13, [sp, #-0x10]! stp x10, x11, [sp, #-0x10]! stp x8, x9, [sp, #-0x10]! stp x6, x7, [sp, #-0x10]! stp x4, x5, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! stp x0, x1, [sp, #-0x10]! /* Invoke the interrupt handler. */ bl _ZN3ams6secmon15HandleInterruptEv /* Restore registers. */ ldp x0, x1, [sp], #0x10 ldp x2, x3, [sp], #0x10 ldp x4, x5, [sp], #0x10 ldp x6, x7, [sp], #0x10 ldp x8, x9, [sp], #0x10 ldp x10, x11, [sp], #0x10 ldp x12, x13, [sp], #0x10 ldp x14, x15, [sp], #0x10 ldp x16, x17, [sp], #0x10 ldp x18, x19, [sp], #0x10 ldp x20, x21, [sp], #0x10 ldp x22, x23, [sp], #0x10 ldp x24, x25, [sp], #0x10 ldp x29, x30, [sp], #0x10 ret vector_entry serror_a32 /* An unexpected exception was taken. */ b _ZN3ams6secmon26UnexpectedExceptionHandlerEv .endfunc .cfi_endproc _ZN3ams6secmon25HandleFiqExceptionCore012Ev: /* Acquire exclusive access to the common smc stack. */ stp x4, x5, [sp, #-0x10]! stp x2, x3, [sp, #-0x10]! stp x0, x1, [sp, #-0x10]! bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv ldp x0, x1, [sp], #0x10 ldp x2, x3, [sp], #0x10 ldp x4, x5, [sp], #0x10 /* Pivot to use the common smc stack. */ mov x30, sp ldr x29, =0x1F01F6E80 mov sp, x29 stp x29, x30, [sp, #-0x10]! /* Handle the fiq exception. */ bl _ZN3ams6secmon18HandleFiqExceptionEv /* Restore our core-specific stack. */ ldp x29, x30, [sp], #0x10 mov sp, x30 /* Release our exclusive access to the common smc stack. */ stp x0, x1, [sp, #-0x10]! bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv ldp x0, x1, [sp], #0x10 /* Return. */ ldp x26, x27, [sp], #0x10 ldp x28, x18, [sp], #0x10 ldp x29, x30, [sp], #0x10 eret /* Instantiate the literal pool for the exception vectors. */ .ltorg ================================================ FILE: exosphere/program/source/secmon_interrupt_handler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_interrupt_handler.hpp" #include "secmon_error.hpp" namespace ams::secmon { namespace { constexpr inline int InterruptHandlersMax = 4; constinit InterruptHandler g_handlers[InterruptHandlersMax] = {}; constinit int g_interrupt_ids[InterruptHandlersMax] = {}; constinit u8 g_interrupt_core_masks[InterruptHandlersMax] = {}; } void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler) { for (int i = 0; i < InterruptHandlersMax; ++i) { if (g_interrupt_ids[i] == 0) { g_interrupt_ids[i] = interrupt_id; g_handlers[i] = handler; g_interrupt_core_masks[i] = core_mask; return; } } AMS_ABORT("Failed to register interrupt handler"); } void HandleInterrupt() { /* Get the interrupt id. */ const int interrupt_id = gic::GetInterruptRequestId(); if (interrupt_id >= gic::InterruptCount) { /* Invalid interrupt number, just return. */ return; } /* Check each handler. */ for (int i = 0; i < InterruptHandlersMax; ++i) { if (g_interrupt_ids[i] == interrupt_id) { /* Validate that we can invoke the handler. */ AMS_ABORT_UNLESS((g_interrupt_core_masks[i] & (1u << hw::GetCurrentCoreId())) != 0); /* Invoke the handler. */ g_handlers[i](); gic::SetEndOfInterrupt(interrupt_id); return; } } AMS_ABORT("Failed to find interrupt handler."); } } ================================================ FILE: exosphere/program/source/secmon_interrupt_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { using InterruptHandler = void (*)(); void SetInterruptHandler(int interrupt_id, u8 core_mask, InterruptHandler handler); } ================================================ FILE: exosphere/program/source/secmon_key_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_key_storage.hpp" namespace ams::secmon { namespace { constexpr const u8 RsaPublicKey[] = { 0x00, 0x01, 0x00, 0x01 }; constinit u8 g_rsa_moduli[ImportRsaKey_Count][se::RsaSize] = {}; constinit bool g_rsa_modulus_committed[ImportRsaKey_Count] = {}; ALWAYS_INLINE u8 *GetRsaKeyModulus(ImportRsaKey which) { return g_rsa_moduli[which]; } ALWAYS_INLINE u8 *GetRsaKeyPrivateExponent(ImportRsaKey which) { return ::ams::secmon::impl::GetRsaPrivateExponentStorage(static_cast<int>(which)); } ALWAYS_INLINE bool IsRsaKeyProvisional(ImportRsaKey which) { return g_rsa_modulus_committed[which] == false; } void ClearRsaKeyModulus(ImportRsaKey which) { g_rsa_modulus_committed[which] = false; std::memset(g_rsa_moduli[which], 0, se::RsaSize); } ALWAYS_INLINE u8 *GetMasterKeyStorage(int index) { return ::ams::secmon::impl::GetMasterKeyStorage(index); } ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int index) { return ::ams::secmon::impl::GetDeviceMasterKeyStorage(index); } } void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size) { /* If we import an exponent, the modulus is not committed. */ ClearRsaKeyModulus(which); /* Copy the exponent. */ std::memcpy(GetRsaKeyPrivateExponent(which), src, size); } void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size) { std::memcpy(GetRsaKeyModulus(which), src, std::min(static_cast<int>(size), se::RsaSize)); } void CommitRsaKeyModulus(ImportRsaKey which) { g_rsa_modulus_committed[which] = true; } bool LoadRsaKey(int slot, ImportRsaKey which) { /* If the key is still provisional, we can't load it. */ if (IsRsaKeyProvisional(which)) { return false; } se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize); return true; } void LoadProvisionalRsaKey(int slot, ImportRsaKey which) { se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize); } void LoadProvisionalRsaPublicKey(int slot, ImportRsaKey which) { se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, RsaPublicKey, sizeof(RsaPublicKey)); } void SetMasterKey(int generation, const void *src, size_t size) { const int index = generation - pkg1::KeyGeneration_Min; se::EncryptAes128(GetMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size); } void LoadMasterKey(int slot, int generation) { const int index = std::max(0, generation - pkg1::KeyGeneration_Min); se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetMasterKeyStorage(index), se::AesBlockSize); } void SetDeviceMasterKey(int generation, const void *src, size_t size) { const int index = generation - pkg1::KeyGeneration_4_0_0; se::EncryptAes128(GetDeviceMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size); } void LoadDeviceMasterKey(int slot, int generation) { const int index = std::max(0, generation - pkg1::KeyGeneration_4_0_0); se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetDeviceMasterKeyStorage(index), se::AesBlockSize); } } ================================================ FILE: exosphere/program/source/secmon_key_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { /* NOTE: Lotus and EsDrmCert are switched here versus official enum, */ /* however, this considerably simplifies logic. */ enum ImportRsaKey { ImportRsaKey_Lotus = 0, ImportRsaKey_EsDrmCert = 1, ImportRsaKey_Ssl = 2, ImportRsaKey_EsClientCert = 3, ImportRsaKey_Count = 4, }; static_assert(util::size(secmon::ConfigurationContext{}.rsa_private_exponents) == ImportRsaKey_Count); void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size); void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size); void CommitRsaKeyModulus(ImportRsaKey which); bool LoadRsaKey(int slot, ImportRsaKey which); void LoadProvisionalRsaKey(int slot, ImportRsaKey which); void LoadProvisionalRsaPublicKey(int slot, ImportRsaKey which); void SetMasterKey(int generation, const void *src, size_t size); void LoadMasterKey(int slot, int generation); void SetDeviceMasterKey(int generation, const void *src, size_t size); void LoadDeviceMasterKey(int slot, int generation); } ================================================ FILE: exosphere/program/source/secmon_map.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_cache.hpp" #include "secmon_setup.hpp" #include "secmon_spinlock.hpp" #include "secmon_map.hpp" #include "smc/secmon_smc_info.hpp" namespace ams::secmon { namespace { constexpr inline const uintptr_t BootCodeAddress = MemoryRegionVirtualTzramBootCode.GetAddress(); constexpr inline const size_t BootCodeSize = MemoryRegionVirtualTzramBootCode.GetSize(); constinit uintptr_t g_smc_user_page_physical_address = 0; constinit uintptr_t g_ams_iram_page_physical_address = 0; constinit uintptr_t g_ams_user_page_physical_address = 0; constinit SpinLockType g_ams_iram_page_spin_lock = {}; constinit SpinLockType g_ams_user_page_spin_lock = {}; using namespace ams::mmu; constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexNormal); constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexDevice); constexpr void UnmapBootCodeImpl(u64 *l1, u64 *l2, u64 *l3, uintptr_t boot_code, size_t boot_code_size) { /* Unmap the L3 entries corresponding to the boot code. */ AMS_UNUSED(l1, l2); InvalidateL3Entries(l3, boot_code, boot_code_size); } constexpr void UnmapTzramImpl(u64 *l1, u64 *l2, u64 *l3) { /* Unmap the L3 entries corresponding to tzram. */ InvalidateL3Entries(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize()); /* Unmap the L2 entries corresponding to those L3 entries. */ InvalidateL2Entries(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2.GetSize()); /* Unmap the L1 entry corresponding to to those L2 entries. */ InvalidateL1Entries(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysical.GetSize()); } constexpr void MapSmcUserPageImpl(u64 *l3, uintptr_t address) { /* Set the L3 entry. */ SetL3BlockEntry(l3, MemoryRegionVirtualSmcUserPage.GetAddress(), address, MemoryRegionVirtualSmcUserPage.GetSize(), MappingAttributesEl3NonSecureRwData); } constexpr void UnmapSmcUserPageImpl(u64 *l3) { /* Unmap the L3 entry. */ InvalidateL3Entries(l3, MemoryRegionVirtualSmcUserPage.GetAddress(), MemoryRegionVirtualSmcUserPage.GetSize()); } constexpr void MapAtmosphereIramPageImpl(u64 *l3, uintptr_t address) { /* Set the L3 entry. */ SetL3BlockEntry(l3, MemoryRegionVirtualAtmosphereIramPage.GetAddress(), address, MemoryRegionVirtualAtmosphereIramPage.GetSize(), MappingAttributesEl3NonSecureDevice); } constexpr void UnmapAtmosphereIramPageImpl(u64 *l3) { /* Unmap the L3 entry. */ InvalidateL3Entries(l3, MemoryRegionVirtualAtmosphereIramPage.GetAddress(), MemoryRegionVirtualAtmosphereIramPage.GetSize()); } constexpr void MapAtmosphereUserPageImpl(u64 *l3, uintptr_t address) { /* Set the L3 entry. */ SetL3BlockEntry(l3, MemoryRegionVirtualAtmosphereUserPage.GetAddress(), address, MemoryRegionVirtualAtmosphereUserPage.GetSize(), MappingAttributesEl3NonSecureRwData); } constexpr void UnmapAtmosphereUserPageImpl(u64 *l3) { /* Unmap the L3 entry. */ InvalidateL3Entries(l3, MemoryRegionVirtualAtmosphereUserPage.GetAddress(), MemoryRegionVirtualAtmosphereUserPage.GetSize()); } constexpr void MapDramForMarikoProgramImpl(u64 *l1, u64 *l2, u64 *l3) { /* Map the L1 entry corresponding to the mariko program dram entry. */ AMS_UNUSED(l2, l3); SetL1BlockEntry(l1, MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetAddress(), MemoryRegionDramForMarikoProgram.GetSize(), MappingAttributesEl3NonSecureRwData); } void ClearLow(uintptr_t address, size_t size) { /* Clear the low part. */ util::ClearMemory(reinterpret_cast<void *>(address), size / 2); } void ClearHigh(uintptr_t address, size_t size) { /* Clear the high part. */ util::ClearMemory(reinterpret_cast<void *>(address + size / 2), size / 2); } } void ClearBootCodeHigh() { ClearHigh(BootCodeAddress, BootCodeSize); } void UnmapBootCode() { /* Get the tables. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); /* Clear the low boot code region; high was already cleared by a previous call. */ ClearLow(BootCodeAddress, BootCodeSize); /* Unmap. */ UnmapBootCodeImpl(l1, l2_l3, l2_l3, BootCodeAddress, BootCodeSize); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(); } size_t GetPhysicalMemorySize() { switch (smc::GetPhysicalMemorySize()) { case pkg1::MemorySize_4GB: return 4_GB; case pkg1::MemorySize_6GB: return 6_GB; case pkg1::MemorySize_8GB: return 8_GB; AMS_UNREACHABLE_DEFAULT_CASE(); } } bool IsPhysicalMemoryAddress(uintptr_t address) { return (address - MemoryRegionDram.GetAddress()) < GetPhysicalMemorySize(); } void UnmapTzram() { /* Get the tables. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); /* Unmap. */ UnmapTzramImpl(l1, l2_l3, l2_l3); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(); } uintptr_t MapSmcUserPage(uintptr_t address) { if (g_smc_user_page_physical_address == 0) { if (!IsPhysicalMemoryAddress(address)) { return 0; } if (!util::IsAligned(address, 4_KB)) { return 0; } g_smc_user_page_physical_address = address; u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); MapSmcUserPageImpl(l2_l3, address); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualSmcUserPage.GetAddress()); } else { AMS_ABORT_UNLESS(address == g_smc_user_page_physical_address); } return MemoryRegionVirtualSmcUserPage.GetAddress(); } void UnmapSmcUserPage() { if (g_smc_user_page_physical_address == 0) { return; } /* Ensure that the page is no longer in cache. */ hw::FlushDataCache(MemoryRegionVirtualSmcUserPage.GetPointer<void>(), MemoryRegionVirtualSmcUserPage.GetSize()); hw::DataSynchronizationBarrierInnerShareable(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); UnmapSmcUserPageImpl(l2_l3); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualSmcUserPage.GetAddress()); g_smc_user_page_physical_address = 0; } uintptr_t MapAtmosphereIramPage(uintptr_t address) { /* Acquire the ams iram spinlock. */ AcquireSpinLock(g_ams_iram_page_spin_lock); auto lock_guard = SCOPE_GUARD { ReleaseSpinLock(g_ams_iram_page_spin_lock); }; /* Validate that the page is an IRAM page. */ if (!MemoryRegionPhysicalIram.Contains(address, 1)) { return 0; } /* Validate that the page isn't a secure monitor debug page. */ if (MemoryRegionPhysicalIramSecureMonitorDebug.Contains(address, 1)) { return 0; } /* Validate that the page is aligned. */ if (!util::IsAligned(address, 4_KB)) { return 0; } /* Map the page. */ g_ams_iram_page_physical_address = address; u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); MapAtmosphereIramPageImpl(l2_l3, address); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualAtmosphereIramPage.GetAddress()); /* Hold the lock. */ lock_guard.Cancel(); return MemoryRegionVirtualAtmosphereIramPage.GetAddress(); } void UnmapAtmosphereIramPage() { /* Can't unmap if nothing's unmapped. */ if (g_ams_iram_page_physical_address == 0) { return; } /* Ensure that the page is no longer in cache. */ hw::FlushDataCache(MemoryRegionVirtualAtmosphereIramPage.GetPointer<void>(), MemoryRegionVirtualAtmosphereIramPage.GetSize()); hw::DataSynchronizationBarrierInnerShareable(); /* Unmap the page. */ u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); UnmapAtmosphereIramPageImpl(l2_l3); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualAtmosphereIramPage.GetAddress()); /* Release the page. */ g_ams_iram_page_physical_address = 0; ReleaseSpinLock(g_ams_iram_page_spin_lock); } uintptr_t MapAtmosphereUserPage(uintptr_t address) { /* Acquire the ams user spinlock. */ AcquireSpinLock(g_ams_user_page_spin_lock); auto lock_guard = SCOPE_GUARD { ReleaseSpinLock(g_ams_user_page_spin_lock); }; /* Validate that the page is a dram page. */ if (!IsPhysicalMemoryAddress(address)) { return 0; } /* Validate that the page is aligned. */ if (!util::IsAligned(address, 4_KB)) { return 0; } /* Map the page. */ g_ams_user_page_physical_address = address; u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); MapAtmosphereUserPageImpl(l2_l3, address); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualAtmosphereUserPage.GetAddress()); /* Hold the lock. */ lock_guard.Cancel(); return MemoryRegionVirtualAtmosphereUserPage.GetAddress(); } void UnmapAtmosphereUserPage() { /* Can't unmap if nothing's unmapped. */ if (g_ams_user_page_physical_address == 0) { return; } /* Ensure that the page is no longer in cache. */ hw::FlushDataCache(MemoryRegionVirtualAtmosphereUserPage.GetPointer<void>(), MemoryRegionVirtualAtmosphereUserPage.GetSize()); hw::DataSynchronizationBarrierInnerShareable(); /* Unmap the page. */ u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); UnmapAtmosphereUserPageImpl(l2_l3); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(MemoryRegionVirtualAtmosphereUserPage.GetAddress()); /* Release the page. */ g_ams_user_page_physical_address = 0; ReleaseSpinLock(g_ams_user_page_spin_lock); } void MapDramForMarikoProgram() { /* Get the tables. */ u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>(); /* Map. */ MapDramForMarikoProgramImpl(l1, l2_l3, l2_l3); /* Ensure the mappings are consistent. */ secmon::EnsureMappingConsistency(); } } ================================================ FILE: exosphere/program/source/secmon_map.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { bool IsPhysicalMemoryAddress(uintptr_t address); size_t GetPhysicalMemorySize(); void UnmapTzram(); uintptr_t MapSmcUserPage(uintptr_t address); void UnmapSmcUserPage(); uintptr_t MapAtmosphereIramPage(uintptr_t address); void UnmapAtmosphereIramPage(); uintptr_t MapAtmosphereUserPage(uintptr_t address); void UnmapAtmosphereUserPage(); void MapDramForMarikoProgram(); } ================================================ FILE: exosphere/program/source/secmon_mariko_fatal_error.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_cpu_context.hpp" #include "secmon_map.hpp" #include "secmon_page_mapper.hpp" #include "secmon_mariko_fatal_error.hpp" #include "smc/secmon_smc_power_management.hpp" namespace ams::secmon { namespace { constinit u8 g_fatal_error_mask = 0; } void HandleMarikoFatalErrorInterrupt() { /* This interrupt handler doesn't return, so mark that we're at end of interrupt. */ gic::SetEndOfInterrupt(MarikoFatalErrorInterruptId); /* Get the current core id. */ const auto core_id = hw::GetCurrentCoreId(); /* Set that we received the fatal on the current core. */ g_fatal_error_mask |= (1u << core_id); hw::FlushDataCache(std::addressof(g_fatal_error_mask), sizeof(g_fatal_error_mask)); hw::DataSynchronizationBarrier(); /* If not all cores have received the fatal, we need to trigger the interrupt on other cores. */ if (g_fatal_error_mask != (1u << NumCores) - 1) { /* Configure and send the interrupt to the next core. */ const auto next_core = __builtin_ctz(~g_fatal_error_mask); gic::SetSpiTargetCpu(MarikoFatalErrorInterruptId, (1u << next_core)); gic::SetPending(MarikoFatalErrorInterruptId); } /* If current core is not 3, kill ourselves. */ if (core_id != NumCores - 1) { smc::PowerOffCpu(); } else { /* Wait for all cores to kill themselves. */ while (g_fatal_error_mask != (1u << NumCores) - 1) { util::WaitMicroSeconds(100); } } /* Copy the fatal error context to mariko tzram. */ { /* Map the iram page. */ constexpr uintptr_t FatalErrorPhysicalAddress = MemoryRegionPhysicalIramFatalErrorContext.GetAddress(); AtmosphereIramPageMapper mapper(FatalErrorPhysicalAddress); if (mapper.Map()) { /* Copy the fatal error context. */ void *dst = MemoryRegionVirtualTzramMarikoProgramFatalErrorContext.GetPointer<void>(); const void *src = mapper.GetPointerTo(FatalErrorPhysicalAddress, sizeof(ams::impl::FatalErrorContext)); std::memcpy(dst, src, sizeof(ams::impl::FatalErrorContext)); } } /* Map Dram for the mariko program. */ MapDramForMarikoProgram(); AMS_SECMON_LOG("%s\n", "Jumping to Mariko Fatal."); AMS_LOG_FLUSH(); /* Jump to the mariko fatal program. */ reinterpret_cast<void (*)()>(secmon::MemoryRegionVirtualTzramMarikoProgram.GetAddress())(); /* The mariko fatal program never returns. */ __builtin_unreachable(); AMS_INFINITE_LOOP(); } } ================================================ FILE: exosphere/program/source/secmon_mariko_fatal_error.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { constexpr inline int MarikoFatalErrorInterruptId = 198; NORETURN void HandleMarikoFatalErrorInterrupt(); } ================================================ FILE: exosphere/program/source/secmon_misc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_misc.hpp" namespace ams::secmon { namespace { constinit pkg1::BctParameters g_bct_params = {}; constinit se::Sha256Hash g_package2_hash = {}; constinit u32 g_deprecated_boot_reason_value = {}; constinit u8 g_deprecated_boot_reason_state = {}; } void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params) { /* Save the BCT parameters. */ g_bct_params = secmon_params.bct_params; /* Save the deprecated boot reason. */ g_deprecated_boot_reason_value = secmon_params.deprecated_boot_reason_value; g_deprecated_boot_reason_state = secmon_params.deprecated_boot_reason_state; } bool IsRecoveryBoot() { return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RecoveryBoot) != 0; } u32 GetRestrictedSmcMask() { return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RestrictedSmcMask) >> pkg1::BootloaderAttribute_RestrictedSmcShift; } bool IsJtagEnabled() { util::BitPack32 dbg_auth; HW_CPU_GET_DBGAUTHSTATUS_EL1(dbg_auth); return dbg_auth.Get<hw::DbgAuthStatusEl1::Nsid>() == 3; } void GetPackage2Hash(se::Sha256Hash *out) { *out = g_package2_hash; } void SetPackage2Hash(const se::Sha256Hash &hash) { g_package2_hash = hash; } u32 GetDeprecatedBootReason() { return (static_cast<u32>(g_deprecated_boot_reason_state) << 24) | (g_deprecated_boot_reason_value & 0x00FFFFFF); } } ================================================ FILE: exosphere/program/source/secmon_misc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params); bool IsRecoveryBoot(); u32 GetRestrictedSmcMask(); bool IsJtagEnabled(); void GetPackage2Hash(se::Sha256Hash *out); void SetPackage2Hash(const se::Sha256Hash &hash); u32 GetDeprecatedBootReason(); } ================================================ FILE: exosphere/program/source/secmon_page_mapper.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_map.hpp" #include "secmon_page_mapper.hpp" namespace ams::secmon { namespace impl { void *PageMapperImpl::GetPointerTo(uintptr_t phys, size_t size) const { /* Ensure we stay within the page. */ if (util::AlignDown(phys, 4_KB) != m_physical_address) { return nullptr; } if (size != 0) { if (util::AlignDown(phys + size - 1, 4_KB) != m_physical_address) { return nullptr; } } return reinterpret_cast<void *>(phys + (m_virtual_address - m_physical_address)); } bool PageMapperImpl::CopyToMapping(uintptr_t dst_phys, const void *src, size_t size) const { void * const dst = this->GetPointerTo(dst_phys, size); if (dst == nullptr) { return false; } std::memcpy(dst, src, size); return true; } bool PageMapperImpl::CopyFromMapping(void *dst, uintptr_t src_phys, size_t size) const { const void * const src = this->GetPointerTo(src_phys, size); if (src == nullptr) { return false; } std::memcpy(dst, src, size); return true; } } bool UserPageMapper::Map() { return this->MapImpl<MapSmcUserPage>(); } bool AtmosphereIramPageMapper::Map() { return this->MapImpl<MapAtmosphereIramPage>(); } bool AtmosphereUserPageMapper::Map() { return this->MapImpl<MapAtmosphereUserPage>(); } AtmosphereIramPageMapper::~AtmosphereIramPageMapper() { this->UnmapImpl<UnmapAtmosphereIramPage>(); } AtmosphereUserPageMapper::~AtmosphereUserPageMapper() { this->UnmapImpl<UnmapAtmosphereUserPage>(); } } ================================================ FILE: exosphere/program/source/secmon_page_mapper.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { namespace impl { class PageMapperImpl { private: uintptr_t m_physical_address; uintptr_t m_virtual_address; public: constexpr PageMapperImpl(uintptr_t phys) : m_physical_address(util::AlignDown(phys, 4_KB)), m_virtual_address() { /* ... */ } void *GetPointerTo(uintptr_t phys, size_t size) const; bool CopyToMapping(uintptr_t dst_phys, const void *src, size_t size) const; bool CopyFromMapping(void *dst, uintptr_t src_phys, size_t size) const; ALWAYS_INLINE bool CopyToUser(uintptr_t dst_phys, const void *src, size_t size) const { return CopyToMapping(dst_phys, src, size); } ALWAYS_INLINE bool CopyFromUser(void *dst, uintptr_t src_phys, size_t size) const { return CopyFromMapping(dst, src_phys, size); } template<auto F> bool MapImpl() { m_virtual_address = F(m_physical_address); return m_virtual_address != 0; } template<auto F> void UnmapImpl() { F(); m_virtual_address = 0; } }; } class UserPageMapper : public impl::PageMapperImpl { public: constexpr UserPageMapper(uintptr_t phys) : PageMapperImpl(phys) { /* ... */ } bool Map(); }; class AtmosphereIramPageMapper : public impl::PageMapperImpl { public: constexpr AtmosphereIramPageMapper(uintptr_t phys) : PageMapperImpl(phys) { /* ... */ } ~AtmosphereIramPageMapper(); bool Map(); }; class AtmosphereUserPageMapper : public impl::PageMapperImpl { public: constexpr AtmosphereUserPageMapper(uintptr_t phys) : PageMapperImpl(phys) { /* ... */ } ~AtmosphereUserPageMapper(); bool Map(); }; } ================================================ FILE: exosphere/program/source/secmon_setup.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_setup.hpp" #include "secmon_error.hpp" #include "secmon_map.hpp" #include "secmon_cpu_context.hpp" #include "secmon_mariko_fatal_error.hpp" #include "secmon_interrupt_handler.hpp" #include "secmon_misc.hpp" #include "smc/secmon_random_cache.hpp" #include "smc/secmon_smc_power_management.hpp" #include "smc/secmon_smc_se_lock.hpp" namespace ams::secmon { namespace { constexpr inline const uintptr_t TIMER = secmon::MemoryRegionVirtualDeviceTimer.GetAddress(); constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionVirtualDeviceSystem.GetAddress(); constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionVirtualDeviceFlowController.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc.GetAddress(); constexpr inline const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress(); constexpr inline const uintptr_t EVP = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress(); constexpr inline const uintptr_t CLK_RST = secmon::MemoryRegionVirtualDeviceClkRst.GetAddress(); alignas(8) constinit u8 g_se_aes_key_slot_test_vector[se::AesBlockSize] = {}; struct Carveout { uintptr_t address; size_t size; }; constinit Carveout g_kernel_carveouts[KernelCarveoutCount] = { { secmon::MemoryRegionDramDefaultKernelCarveout.GetAddress(), secmon::MemoryRegionDramDefaultKernelCarveout.GetSize(), }, { 0, 0, }, }; constinit bool g_is_cold_boot = true; constinit se::StickyBits ExpectedSeStickyBits = { .se_security = (1 << 0), /* SE_HARD_SETTING */ .tzram_security = 0, .crypto_security_perkey = (1 << pkg1::AesKeySlot_UserEnd) - 1, .crypto_keytable_access = { (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 6: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 7: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (0 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEY. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ }, .rsa_security_perkey = 0, .rsa_keytable_access = { (0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */ (0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */ }, }; void InitializeConfigurationContext() { /* Get the global context. */ auto &ctx = ::ams::secmon::impl::GetConfigurationContext(); /* Clear the context to zero. */ std::memset(std::addressof(ctx), 0, sizeof(ctx)); /* If the storage context is valid, we want to copy it to the global context. */ if (const auto &storage_ctx = *MemoryRegionPhysicalDramMonitorConfiguration.GetPointer<const SecureMonitorStorageConfiguration>(); storage_ctx.IsValid()) { ctx.secmon_cfg.CopyFrom(storage_ctx); ctx.emummc_cfg = storage_ctx.emummc_cfg; } else { /* If we don't have a valid storage context, we can just use the default one. */ ctx.secmon_cfg = DefaultSecureMonitorConfiguration; } /* Cache the fuse info for quick access. */ ctx.secmon_cfg.SetFuseInfo(); } void GenerateSecurityEngineAesKeySlotTestVector(void *dst, size_t size) { /* Clear the output. */ AMS_ABORT_UNLESS(size == se::AesBlockSize); std::memset(dst, 0, se::AesBlockSize); /* Ensure output is seen as cleared by the se. */ hw::FlushDataCache(dst, se::AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Declare a block. */ alignas(8) u8 empty_block[se::AesBlockSize]; /* Iteratively transform an empty block. */ #define TRANSFORM_WITH_KEY(key) \ __builtin_memset(empty_block, 0, sizeof(empty_block)); \ se::SetEncryptedAesKey256(pkg1::AesKeySlot_Temporary, key, empty_block, sizeof(empty_block)); \ se::DecryptAes128(dst, se::AesBlockSize, pkg1::AesKeySlot_Temporary, dst, se::AesBlockSize) TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster); TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device); /* Ensure output is seen correctly by the cpu. */ hw::FlushDataCache(dst, se::AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Clear the temporary key slot. */ se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary); } void VerifySecurityEngineStickyBits() { /* On mariko, an extra sticky bit is set. */ if (GetSocType() == fuse::SocType_Mariko) { ExpectedSeStickyBits.se_security |= (1 << 5); } else /* if (GetSocType() == fuse::SocType_Erista) */ { /* Erista does not support DST_KEYTABLE_ONLY, and so all keys will have the bit clear. */ for (size_t i = 0; i < util::size(ExpectedSeStickyBits.crypto_keytable_access); ++i) { ExpectedSeStickyBits.crypto_keytable_access[i] &= ~(1 << 7); } } if (!se::ValidateStickyBits(ExpectedSeStickyBits)) { SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits); AMS_ABORT("Invalid sticky bits"); } } void VerifySecurityEngineAesKeySlotTestVector() { alignas(8) u8 test_vector[se::AesBlockSize]; GenerateSecurityEngineAesKeySlotTestVector(test_vector, sizeof(test_vector)); AMS_ABORT_UNLESS(crypto::IsSameBytes(g_se_aes_key_slot_test_vector, test_vector, se::AesBlockSize)); } void ClearAesKeySlots() { /* Clear all non-secure monitor keys. */ for (int i = 0; i < pkg1::AesKeySlot_SecmonStart; ++i) { se::ClearAesKeySlot(i); } /* Clear the secure-monitor temporary keys. */ se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary); se::ClearAesKeySlot(pkg1::AesKeySlot_Smc); } void ClearRsaKeySlots() { /* Clear all rsa keyslots. */ for (int i = 0; i < se::RsaKeySlotCount; ++i) { se::ClearRsaKeySlot(i); } } void SetupKernelCarveouts() { #define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE) constexpr u32 ClientAccess0 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, PTCR), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0A), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0AB), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0B), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0BB), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0C), MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0CB), MC_ENABLE_CLIENT_ACCESS(0, AFIR), MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHC), MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHCB), MC_ENABLE_CLIENT_ACCESS(0, HDAR), MC_ENABLE_CLIENT_ACCESS(0, HOST1XDMAR), MC_ENABLE_CLIENT_ACCESS(0, HOST1XR), MC_ENABLE_CLIENT_ACCESS(0, NVENCSRD), MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBDMAR), MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR)); constexpr u32 ClientAccess1 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, MPCORER), MC_ENABLE_CLIENT_ACCESS(1, NVENCSWR), MC_ENABLE_CLIENT_ACCESS(1, AFIW), MC_ENABLE_CLIENT_ACCESS(1, HDAW), MC_ENABLE_CLIENT_ACCESS(1, HOST1XW), MC_ENABLE_CLIENT_ACCESS(1, MPCOREW), MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBDMAW), MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBSLVW)); constexpr u32 ClientAccess2 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR), MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW), MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR), MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW)); constexpr u32 ClientAccess2_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR), MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW), MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR), MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW), MC_ENABLE_CLIENT_ACCESS(2, TSECSRD), MC_ENABLE_CLIENT_ACCESS(2, TSECSWR)); constexpr u32 ClientAccess3 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB), MC_ENABLE_CLIENT_ACCESS(3, VICSRD), MC_ENABLE_CLIENT_ACCESS(3, VICSWR), MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD), MC_ENABLE_CLIENT_ACCESS(3, APER), MC_ENABLE_CLIENT_ACCESS(3, APEW), MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD), MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR)); constexpr u32 ClientAccess3_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA), MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB), MC_ENABLE_CLIENT_ACCESS(3, VICSRD), MC_ENABLE_CLIENT_ACCESS(3, VICSWR), MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD), MC_ENABLE_CLIENT_ACCESS(3, NVDECSRD), MC_ENABLE_CLIENT_ACCESS(3, NVDECSWR), MC_ENABLE_CLIENT_ACCESS(3, APER), MC_ENABLE_CLIENT_ACCESS(3, APEW), MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD), MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR)); constexpr u32 ClientAccess4 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD), MC_ENABLE_CLIENT_ACCESS(4, SESWR)); constexpr u32 ClientAccess4_800 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD), MC_ENABLE_CLIENT_ACCESS(4, SESWR), MC_ENABLE_CLIENT_ACCESS(4, TSECRDB), MC_ENABLE_CLIENT_ACCESS(4, TSECWRB)); constexpr u32 ClientAccess4_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD), MC_ENABLE_CLIENT_ACCESS(4, SESWR)); #undef MC_ENABLE_CLIENT_ACCESS constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE)); constexpr u32 ForceInternalAccess0_100 = 0; constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE)); constexpr u32 ForceInternalAccess1_100 = 0; constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE)); constexpr u32 CarveoutConfig_100 = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE)); const u32 target_fw = GetTargetFirmware(); u32 client_access_2; u32 client_access_3; u32 client_access_4; u32 carveout_config; if (target_fw >= TargetFirmware_8_1_0) { client_access_2 = ClientAccess2; client_access_3 = ClientAccess3; client_access_4 = ClientAccess4; carveout_config = CarveoutConfig; } else if (target_fw >= TargetFirmware_8_0_0) { client_access_2 = ClientAccess2; client_access_3 = ClientAccess3; client_access_4 = ClientAccess4_800; carveout_config = CarveoutConfig; } else { client_access_2 = ClientAccess2_100; client_access_3 = ClientAccess3_100; client_access_4 = ClientAccess4_100; carveout_config = CarveoutConfig_100; } /* Configure carveout 4. */ reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, g_kernel_carveouts[0].address >> 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, g_kernel_carveouts[0].address >> 32); reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, g_kernel_carveouts[0].size / 128_KB); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, ClientAccess0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, ClientAccess1); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, client_access_2); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, client_access_3); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, client_access_4); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess0 : ForceInternalAccess0_100); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess1 : ForceInternalAccess1_100); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, carveout_config); /* Configure carveout 5. */ reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM, g_kernel_carveouts[1].address >> 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM_HI, g_kernel_carveouts[1].address >> 32); reg::Write(MC + MC_SECURITY_CARVEOUT5_SIZE_128KB, g_kernel_carveouts[1].size / 128_KB); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0, ClientAccess0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1, ClientAccess1); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2, client_access_2); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3, client_access_3); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4, client_access_4); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT5_CFG0, carveout_config); } void ConfigureSlaveSecurity() { u32 reg0, reg1, reg2; if (GetTargetFirmware() > TargetFirmware_1_0_0) { reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, SE, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE)); reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE)); reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC3, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(2, DP2, ENABLE)); const auto hw_type = GetHardwareType(); /* Switch Lite can't use HDMI, so set CEC to secure on hoag. */ if (hw_type == fuse::HardwareType_Hoag) { reg0 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, CEC, ENABLE)); } /* Icosa, Iowa, and Aula all set I2C4 to be secure. */ if (hw_type == fuse::HardwareType_Icosa && hw_type == fuse::HardwareType_Iowa && hw_type == fuse::HardwareType_Aula) { reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, I2C4, ENABLE)); } /* Hoag additionally sets UART_B to secure. */ if (hw_type == fuse::HardwareType_Hoag) { reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE)); } /* Copper and Calcio lack a lot of hardware, so set the corresponding registers to secure for them. */ if (hw_type == fuse::HardwareType_Calcio || hw_type == fuse::HardwareType_Copper) { reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, UART_C, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI4, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, I2C2, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, I2C3, ENABLE)); /* Copper/Calcio have no gamecard reader, and thus set SDMMC2 as secure. */ reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC2, ENABLE)); } /* Mariko hardware types (not Icosa or Copper) additionally set mariko-only mmio (SE2, PKA1, FEK) as secure. */ if (hw_type != fuse::HardwareType_Icosa && hw_type != fuse::HardwareType_Copper) { reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SE2, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(2, PKA1, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(2, FEK, ENABLE)); } } else { reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE)); reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE)); reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE), REG_BITS_VALUE(5, 1, 1), /* Note: Bit 5 is not documented in TRM. */ REG_BITS_VALUE(4, 1, 1)); /* Note: Bit 4 is not documented in TRM. */ } reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, reg0); reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, reg1); reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0, reg2); } void SetupSecureRegisters() { /* Configure timers 5-8 and watchdog timers 0-3 as secure. */ reg::Write(TIMER + TIMER_SHARED_TIMER_SECURE_CFG, TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR5, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR6, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR7, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR8, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT0, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT1, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT2, ENABLE), TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT3, ENABLE)); /* Lock cluster switching, to prevent usage of the A53 cores. */ reg::Write(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER_LOCK, ENABLE), FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_CLUSTER_SWITCH_ENABLE, DISABLE), FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, FAST)); /* Enable flow controller debug qualifier for legacy FIQs. */ reg::Write(FLOW_CTLR + FLOW_CTLR_FLOW_DBG_QUAL, FLOW_REG_BITS_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, ENABLE)); /* Configure the PMC to disable deep power-down. */ reg::Write(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, DISABLE), PMC_REG_BITS_ENUM(DPD_ENABLE_ON, DISABLE)); /* Configure the video protect region. */ reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_0, 1); reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 0); reg::Write(MC + MC_VIDEO_PROTECT_BOM, 0); reg::Write(MC + MC_VIDEO_PROTECT_SIZE_MB, 0); reg::Write(MC + MC_VIDEO_PROTECT_REG_CTRL, MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_ALLOW_TZ_WRITE, DISABLED), MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_WRITE_ACCESS, DISABLED)); /* Configure the SEC carveout. */ reg::Write(MC + MC_SEC_CARVEOUT_BOM, 0); reg::Write(MC + MC_SEC_CARVEOUT_SIZE_MB, 0); reg::Write(MC + MC_SEC_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(SEC_CARVEOUT_REG_CTRL_SEC_CARVEOUT_WRITE_ACCESS, DISABLED)); /* Configure the MTS carveout. */ reg::Write(MC + MC_MTS_CARVEOUT_BOM, 0); reg::Write(MC + MC_MTS_CARVEOUT_SIZE_MB, 0); reg::Write(MC + MC_MTS_CARVEOUT_ADR_HI, 0); reg::Write(MC + MC_MTS_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(MTS_CARVEOUT_REG_CTRL_MTS_CARVEOUT_WRITE_ACCESS, DISABLED)); /* Configure the security carveout. */ reg::Write(MC + MC_SECURITY_CFG0, MC_REG_BITS_VALUE(SECURITY_CFG0_SECURITY_BOM, 0)); reg::Write(MC + MC_SECURITY_CFG1, MC_REG_BITS_VALUE(SECURITY_CFG1_SECURITY_SIZE, 0)); reg::Write(MC + MC_SECURITY_CFG3, MC_REG_BITS_VALUE(SECURITY_CFG3_SECURITY_BOM_HI, 3)); /* Configure security carveout 1. */ reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM_HI, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_SIZE_128KB, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT1_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE)); /* Security carveout 2 will be configured later by SetupGpuCarveout, after magic values are written to configure gpu/tsec. */ /* Configure carveout 3. */ reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM_HI, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_SIZE_128KB, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2, MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD, ENABLE), MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR, ENABLE)); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4, MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE), MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE)); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT3_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 3), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE)); /* If we're cold-booting and on 1.0.0, alter the default carveout size. */ if (g_is_cold_boot && GetTargetFirmware() <= TargetFirmware_1_0_0) { g_kernel_carveouts[0].size = 200 * 128_KB; } /* NOTE: Here Nintendo configures the two kernel carveouts; we will do this later, to allow fusee to continue using AVP_CACHE. */ /* SetupKernelCarveouts(); */ /* Configure slave register security. */ ConfigureSlaveSecurity(); } void SetupSmmu() { /* Turn on SMMU translation for all devices. */ reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_0, ~0u); reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_1, ~0u); reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_2, ~0u); reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_3, ~0u); reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_4, ~0u); /* On modern firmware, configure ASIDs 1-3 as secure, and all others as non-secure. */ if (GetTargetFirmware() >= TargetFirmware_4_0_0) { reg::Write(MC + MC_SMMU_ASID_SECURITY, MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, SECURE), MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, SECURE), MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, SECURE)); } else { /* Legacy firmware accesses the MC directly, though, and so correspondingly we must allow ASIDs to be edited by non-secure world. */ reg::Write(MC + MC_SMMU_ASID_SECURITY, 0); } reg::Write(MC + MC_SMMU_ASID_SECURITY_1, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_2, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_3, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_4, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_5, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_6, 0); reg::Write(MC + MC_SMMU_ASID_SECURITY_7, 0); /* Initialize the PTB registers to zero .*/ reg::Write(MC + MC_SMMU_PTB_ASID, 0); reg::Write(MC + MC_SMMU_PTB_DATA, 0); /* Configure the TLB and PTC, then read TLB_CONFIG to ensure configuration takes. */ reg::Write(MC + MC_SMMU_TLB_CONFIG, MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_HIT_UNDER_MISS, ENABLE), MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_ROUND_ROBIN_ARBITRATION, ENABLE), MC_REG_BITS_VALUE(SMMU_TLB_CONFIG_TLB_ACTIVE_LINES, 0x30)); reg::Write(MC + MC_SMMU_PTC_CONFIG, MC_REG_BITS_ENUM (SMMU_PTC_CONFIG_PTC_CACHE_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_REQ_LIMIT, 8), MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_INDEX_MAP, 0x3F)); reg::Read (MC + MC_SMMU_TLB_CONFIG); /* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */ reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0); reg::Read (MC + MC_SMMU_TLB_CONFIG); /* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */ reg::Write(MC + MC_SMMU_TLB_FLUSH, 0); reg::Read (MC + MC_SMMU_TLB_CONFIG); /* Enable the SMMU, and read TLB_CONFIG to ensure the enable takes. */ reg::Write(MC + MC_SMMU_CONFIG, MC_REG_BITS_ENUM (SMMU_CONFIG_SMMU_ENABLE, ENABLE)); reg::Read (MC + MC_SMMU_TLB_CONFIG); } void SetupSecureEl2AndEl1SystemRegisters() { /* Setup actlr_el2 and actlr_el3. */ { util::BitPack32 actlr = {}; actlr.Set<hw::ActlrCortexA57::Cpuactlr>(1); /* Enable access to cpuactlr from lower EL. */ actlr.Set<hw::ActlrCortexA57::Cpuectlr>(1); /* Enable access to cpuectlr from lower EL. */ actlr.Set<hw::ActlrCortexA57::L2ctlr>(1); /* Enable access to l2ctlr from lower EL. */ actlr.Set<hw::ActlrCortexA57::L2actlr>(1); /* Enable access to l2actlr from lower EL. */ actlr.Set<hw::ActlrCortexA57::L2ectlr>(1); /* Enable access to l2ectlr from lower EL. */ HW_CPU_SET_ACTLR_EL3(actlr); HW_CPU_SET_ACTLR_EL2(actlr); } /* Setup hcr_el2. */ { util::BitPack64 hcr = {}; hcr.Set<hw::HcrEl2::Rw>(1); /* EL1 is aarch64 mode. */ HW_CPU_SET_HCR_EL2(hcr); } /* Configure all domain access permissions as manager. */ HW_CPU_SET_DACR32_EL2(~0u); /* Setup sctlr_el1. */ { util::BitPack64 sctlr = { hw::SctlrEl1::Res1 }; sctlr.Set<hw::SctlrEl1::M>(0); /* Globally disable the MMU. */ sctlr.Set<hw::SctlrEl1::A>(0); /* Disable alignment fault checking. */ sctlr.Set<hw::SctlrEl1::C>(0); /* Globally disable the data and unified caches. */ sctlr.Set<hw::SctlrEl1::Sa>(1); /* Enable stack alignment checking. */ sctlr.Set<hw::SctlrEl1::Sa0>(1); /* Enable el0 stack alignment checking. */ sctlr.Set<hw::SctlrEl1::Cp15BEn>(1); /* Enable cp15 barrier operations. */ sctlr.Set<hw::SctlrEl1::Thee>(0); /* Disable ThumbEE. */ sctlr.Set<hw::SctlrEl1::Itd>(0); /* Enable itd instructions. */ sctlr.Set<hw::SctlrEl1::Sed>(0); /* Enable setend instruction. */ sctlr.Set<hw::SctlrEl1::Uma>(0); /* Disable el0 interrupt mask access. */ sctlr.Set<hw::SctlrEl1::I>(0); /* Globally disable the instruction cache. */ sctlr.Set<hw::SctlrEl1::Dze>(0); /* Disable el0 access to dc zva instruction. */ sctlr.Set<hw::SctlrEl1::Ntwi>(1); /* wfi instructions in el0 trap. */ sctlr.Set<hw::SctlrEl1::Ntwe>(1); /* wfe instructions in el0 trap. */ sctlr.Set<hw::SctlrEl1::Wxn>(0); /* Do not force writable pages to be ExecuteNever. */ sctlr.Set<hw::SctlrEl1::E0e>(0); /* Data accesses in el0 are little endian. */ sctlr.Set<hw::SctlrEl1::Ee>(0); /* Exceptions should be little endian. */ sctlr.Set<hw::SctlrEl1::Uci>(0); /* Disable el0 access to dc cvau, dc civac, dc cvac, ic ivau. */ HW_CPU_SET_SCTLR_EL1(sctlr); } /* Setup sctlr_el2. */ { util::BitPack64 sctlr = { hw::SctlrEl2::Res1 }; sctlr.Set<hw::SctlrEl2::M>(0); /* Globally disable the MMU. */ sctlr.Set<hw::SctlrEl2::A>(0); /* Disable alignment fault checking. */ sctlr.Set<hw::SctlrEl2::C>(0); /* Globally disable the data and unified caches. */ sctlr.Set<hw::SctlrEl2::Sa>(1); /* Enable stack alignment checking. */ sctlr.Set<hw::SctlrEl2::I>(0); /* Globally disable the instruction cache. */ sctlr.Set<hw::SctlrEl2::Wxn>(0); /* Do not force writable pages to be ExecuteNever. */ sctlr.Set<hw::SctlrEl2::Ee>(0); /* Exceptions should be little endian. */ HW_CPU_SET_SCTLR_EL2(sctlr); } /* Ensure instruction consistency. */ hw::InstructionSynchronizationBarrier(); } void SetupNonSecureSystemRegisters(u32 tsc_frequency) { /* Set cntfrq_el0. */ HW_CPU_SET_CNTFRQ_EL0(tsc_frequency); /* Set cnthctl_el2. */ { util::BitPack32 cnthctl = {}; cnthctl.Set<hw::CnthctlEl2::El1PctEn>(1); /* Do not trap accesses to cntpct_el0. */ cnthctl.Set<hw::CnthctlEl2::El1PcEn>(1); /* Do not trap accesses to cntp_ctl_el0, cntp_cval_el0, and cntp_tval_el0. */ cnthctl.Set<hw::CnthctlEl2::EvntEn>(0); /* Disable the event stream. */ cnthctl.Set<hw::CnthctlEl2::EvntDir>(0); /* Trigger events on 0 -> 1 transition. */ cnthctl.Set<hw::CnthctlEl2::EvntI>(0); /* Select bit0 of cntpct_el0 as the event stream trigger. */ HW_CPU_SET_CNTHCTL_EL2(cnthctl); } /* Ensure instruction consistency. */ hw::InstructionSynchronizationBarrier(); } void SetupGpuCarveout() { /* Configure carveout 2. */ reg::Write(MC + MC_SECURITY_CARVEOUT2_BOM, static_cast<u32>(MemoryRegionDramGpuCarveout.GetAddress() >> 0)); reg::Write(MC + MC_SECURITY_CARVEOUT2_BOM_HI, static_cast<u32>(MemoryRegionDramGpuCarveout.GetAddress() >> BITSIZEOF(u32))); reg::Write(MC + MC_SECURITY_CARVEOUT2_SIZE_128KB, MemoryRegionDramGpuCarveout.GetSize() / 128_KB); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2, MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD, ENABLE), MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR, ENABLE), MC_REG_BITS_ENUM (CLIENT_ACCESS2_TSECSRD, ENABLE)); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4, MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE), MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE)); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT2_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 2), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE)); } void DisableArc() { /* Configure IRAM top/bottom to point to memory ends (disabling redirection). */ reg::Write(MC + MC_IRAM_BOM, MC_REG_BITS_VALUE(IRAM_BOM_IRAM_BOM, (~0u))); reg::Write(MC + MC_IRAM_TOM, MC_REG_BITS_VALUE(IRAM_TOM_IRAM_TOM, ( 0u))); /* Lock the IRAM aperture. */ reg::ReadWrite(MC + MC_IRAM_REG_CTRL, MC_REG_BITS_ENUM(IRAM_REG_CTRL_IRAM_CFG_WRITE_ACCESS, DISABLED)); /* Disable the ARC clock gate override. */ reg::ReadWrite(CLK_RST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, CLK_RST_REG_BITS_ENUM(LVL2_CLK_GATE_OVRD_ARC_CLK_OVR_ON, OFF)); /* Read IRAM REG CTRL to make sure our writes take. */ reg::Read(MC + MC_IRAM_REG_CTRL); } void DisableUntranslatedDeviceMemoryAccess() { /* If we can (mariko only), disable GMMU accesses that bypass the SMMU. */ /* Additionally, force all untranslated acccesses to hit one of the carveouts. */ if (GetSocType() == fuse::SocType_Mariko) { reg::Write(MC + MC_UNTRANSLATED_REGION_CHECK, MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_UNTRANSLATED_REGION_CHECK_ACCESS, DISABLED), MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_CLIENTS_HIT_CARVEOUT, ENABLED), MC_REG_BITS_ENUM(UNTRANSLATED_REGION_CHECK_REQUIRE_UNTRANSLATED_GPU_HIT_CARVEOUT, ENABLED)); } } void FinalizeCarveoutSecureScratchRegisters() { /* Define carveout scratch values. */ constexpr uintptr_t WarmbootCarveoutAddress = MemoryRegionDram.GetAddress(); constexpr size_t WarmbootCarveoutSize = 128_KB; #define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE) constexpr u32 WarmbootCarveoutClientAccess0 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, AVPCARM7R), MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR)); constexpr u32 WarmbootCarveoutClientAccess1 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, AVPCARM7W)); #undef MC_ENABLE_CLIENT_ACCESS constexpr u32 WarmbootCarveoutForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE), MC_REG_BITS_ENUM(CLIENT_ACCESS0_PPCSAHBSLVR, ENABLE)); constexpr u32 WarmbootCarveoutForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE)); constexpr u32 WarmbootCarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, UNLOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE)); /* Save the carveout values into secure scratch. */ /* Save MC_SECURITY_CARVEOUT4_BOM. */ reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH51, REG_BITS_VALUE( 0, 15, WarmbootCarveoutAddress >> 17)); /* Save MC_SECURITY_CARVEOUT4_BOM_HI. */ reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH16, REG_BITS_VALUE(30, 2, WarmbootCarveoutAddress >> 32)); /* Save MC_SECURITY_CARVEOUT4_SIZE_128KB. */ reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH55, REG_BITS_VALUE(12, 12, WarmbootCarveoutSize / 128_KB)); /* Save MC_SECURITY_CARVEOUT4_CLIENT_ACCESS. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH74, WarmbootCarveoutClientAccess0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH75, WarmbootCarveoutClientAccess1); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH76, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH77, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH78, 0); /* Save MC_SECURITY_CARVEOUT4_FORCE_INTERNAL_ACCESS. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH99, WarmbootCarveoutForceInternalAccess0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH100, WarmbootCarveoutForceInternalAccess1); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH101, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH102, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH103, 0); /* Save MC_SECURITY_CARVEOUT4_CFG0. */ reg::ReadWrite(PMC + APBDEV_PMC_SECURE_SCRATCH39, REG_BITS_VALUE(0, 27, WarmbootCarveoutConfig)); } void EnableBpmpSmmu() { /* Define the ASID contents. */ constexpr int BpmpAsid = 1; constexpr uintptr_t BpmpAsidPde = MemoryRegionPhysicalDeviceSecurityEngine.GetAddress(); /* Configure the ASID. */ reg::Write(MC + MC_SMMU_PTB_ASID, MC_REG_BITS_VALUE(SMMU_PTB_ASID_CURRENT_ASID, BpmpAsid)); reg::Write(MC + MC_SMMU_PTB_DATA, MC_REG_BITS_VALUE(SMMU_PTB_DATA_ASID_PDE_BASE, BpmpAsidPde / 4_KB), MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_NONSECURE, DISABLE), MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_WRITABLE, DISABLE), MC_REG_BITS_ENUM (SMMU_PTB_DATA_ASID_READABLE, DISABLE)); /* Configure the BPMP and PPCS1 to use the asid. */ reg::Write(MC + MC_SMMU_AVPC_ASID, MC_REG_BITS_ENUM(SMMU_AVPC_ASID_AVPC_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_AVPC_ASID_AVPC_ASID, BpmpAsid)); reg::Write(MC + MC_SMMU_PPCS1_ASID, MC_REG_BITS_ENUM(SMMU_PPCS1_ASID_PPCS1_SMMU_ENABLE, ENABLE), MC_REG_BITS_VALUE(SMMU_PPCS1_ASID_PPCS1_ASID, BpmpAsid)); /* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */ reg::Write(MC + MC_SMMU_PTC_FLUSH_0, 0); reg::Read (MC + MC_SMMU_TLB_CONFIG); /* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */ reg::Write(MC + MC_SMMU_TLB_FLUSH, 0); reg::Read (MC + MC_SMMU_TLB_CONFIG); } void ValidateResetExpected() { /* We're coming out of reset, so check that we expected to come out of reset. */ if (!IsResetExpected()) { secmon::SetError(pkg1::ErrorInfo_UnexpectedReset); AMS_ABORT("unexpected reset"); } SetResetExpected(false); } void ActmonInterruptHandler() { SetError(pkg1::ErrorInfo_ActivityMonitorInterrupt); AMS_ABORT("actmon observed bpmp wakeup"); } void ExitChargerHiZMode() { /* Setup I2c-1. */ pinmux::SetupI2c1(); clkrst::EnableI2c1Clock(); /* Initialize I2c-1. */ i2c::Initialize(i2c::Port_1); /* Exit Hi-Z mode. */ charger::ExitHiZMode(); /* Disable clock to I2c-1. */ clkrst::DisableI2c1Clock(); } bool IsExitLp0() { return reg::Read(MC + MC_SECURITY_CFG3) == 0; } void SetupLogForBoot() { log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags()); log::SendText("OHAYO\n", 6); log::Flush(); } void LogExitLp0() { /* NOTE: Nintendo only does this on dev, but we will always do it. */ if (true /* !pkg1::IsProduction() */) { SetupLogForBoot(); } } void SetupForLp0Exit() { /* Exit HiZ mode in charger, if we need to. */ const auto target_fw = GetTargetFirmware(); const bool force_exit_hiz_mode = (target_fw < TargetFirmware_4_0_0) || (target_fw < TargetFirmware_8_0_0 && fuse::GetHardwareType() == fuse::HardwareType_Icosa); if (force_exit_hiz_mode || smc::IsChargerHiZModeEnabled()) { ExitChargerHiZMode(); } /* Refill the random cache, which is volatile and thus wiped on warmboot. */ smc::FillRandomCache(); /* Unlock the security engine. */ secmon::smc::UnlockSecurityEngine(); } } void Setup1() { /* Load the global configuration context. */ InitializeConfigurationContext(); /* Initialize uart for logging. */ SetupLogForBoot(); /* Initialize the security engine. */ se::Initialize(); /* Initialize the gic. */ gic::InitializeCommon(); } void Setup1ForWarmboot() { /* Initialize the security engine. */ se::Initialize(); /* Initialize the gic. */ gic::InitializeCommon(); } void SaveSecurityEngineAesKeySlotTestVector() { GenerateSecurityEngineAesKeySlotTestVector(g_se_aes_key_slot_test_vector, sizeof(g_se_aes_key_slot_test_vector)); } void SetupSocSecurity() { /* Set the fuse visibility. */ clkrst::SetFuseVisibility(true); /* Set fuses as only secure-writable. */ fuse::SetWriteSecureOnly(); /* Lockout the fuses. */ fuse::Lockout(); /* Set the security engine to secure mode. */ se::SetSecure(true); /* Verify the security engine's sticky bits. */ VerifySecurityEngineStickyBits(); /* Verify the security engine's Aes slots contain correct contents. */ VerifySecurityEngineAesKeySlotTestVector(); /* Clear aes keyslots. */ ClearAesKeySlots(); /* Clear rsa keyslots. */ ClearRsaKeySlots(); /* Overwrite keys that we want to be random with random contents. */ se::InitializeRandom(); se::ConfigureAutomaticContextSave(); se::SetRandomKey(pkg1::AesKeySlot_Temporary); se::GenerateSrk(); se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek); /* Initialize pmc secure scratch. */ if (GetSocType() == fuse::SocType_Erista) { pmc::InitializeRandomScratch(); } pmc::LockSecureRegister(pmc::SecureRegister_Srk); /* Setup secure registers. */ SetupSecureRegisters(); /* Setup the smmu. */ SetupSmmu(); /* Clear the cpu reset vector. */ reg::Write(EVP + EVP_CPU_RESET_VECTOR, 0); /* Configure the SB registers to our start address. */ constexpr u32 ResetVectorLow = static_cast<u32>((PhysicalTzramProgramResetVector >> 0)); constexpr u32 ResetVectorHigh = static_cast<u32>((PhysicalTzramProgramResetVector >> BITSIZEOF(u32))); /* Write our reset vector to the secure boot registers. */ reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_LOW, ResetVectorLow | 1); reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_HIGH, ResetVectorHigh); /* Disable non-secure writes to the reset vector. */ reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR, SB_REG_BITS_ENUM(CSR_NS_RST_VEC_WR_DIS, DISABLE)); /* Read back SB_CSR to make sure our non-secure write disable takes. */ reg::Read(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR); /* Write our reset vector to scratch registers used by warmboot, and lock those scratch registers. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH34, ResetVectorLow); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH35, ResetVectorHigh); pmc::LockSecureRegister(pmc::SecureRegister_ResetVector); /* Setup the security engine interrupt. */ constexpr int SecurityEngineInterruptId = 90; constexpr u8 SecurityEngineInterruptCoreMask = (1 << 3); gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority); gic::SetInterruptGroup(SecurityEngineInterruptId, 0); gic::SetEnable (SecurityEngineInterruptId, true); gic::SetSpiTargetCpu (SecurityEngineInterruptId, SecurityEngineInterruptCoreMask); gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level); /* Setup the activity monitor interrupt. */ constexpr int ActivityMonitorInterruptId = 77; constexpr u8 ActivityMonitorInterruptCoreMask = (1 << 3); gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority); gic::SetInterruptGroup(ActivityMonitorInterruptId, 0); gic::SetEnable (ActivityMonitorInterruptId, true); gic::SetSpiTargetCpu (ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask); gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level); /* Setup the mariko fatal error interrupt. */ constexpr u8 MarikoFatalInterruptCoreMask = 0b1111; gic::SetPriority (MarikoFatalErrorInterruptId, gic::HighestPriority); gic::SetInterruptGroup(MarikoFatalErrorInterruptId, 0); gic::SetEnable (MarikoFatalErrorInterruptId, true); gic::SetSpiTargetCpu (MarikoFatalErrorInterruptId, 0); gic::SetSpiMode (MarikoFatalErrorInterruptId, gic::InterruptMode_Level); /* If we're coldboot, perform one-time setup. */ if (g_is_cold_boot) { /* Register all interrupt handlers. */ SetInterruptHandler(SecurityEngineInterruptId, SecurityEngineInterruptCoreMask, se::HandleInterrupt); SetInterruptHandler(ActivityMonitorInterruptId, ActivityMonitorInterruptCoreMask, actmon::HandleInterrupt); SetInterruptHandler(MarikoFatalErrorInterruptId, MarikoFatalInterruptCoreMask, secmon::HandleMarikoFatalErrorInterrupt); /* We're expecting the other cores to come out of reset. */ for (int i = 1; i < NumCores; ++i) { SetResetExpected(i, true); } /* We only coldboot once. */ g_is_cold_boot = false; } } void SetupSocSecurityWarmboot() { /* Check that we're allowed to continue. */ ValidateResetExpected(); /* Unmap the tzram identity mapping. */ UnmapTzram(); /* If we're exiting LP0, there's a little more work for us to do. */ if (IsExitLp0()) { /* Log that we're exiting LP0. */ LogExitLp0(); /* Perform initial setup. */ Setup1ForWarmboot(); /* Generate a random srk. */ se::GenerateSrk(); /* Setup the Soc security. */ SetupSocSecurity(); /* Set the PMC and MC as secure-only. */ SetupPmcAndMcSecure(); /* Perform Lp0-exit specific init. */ SetupForLp0Exit(); /* Setup the Soc protections. */ SetupSocProtections(); } /* Perform remaining CPU initialization. */ SetupCpuCoreContext(); SetupCpuSErrorDebug(); } void SetupSocProtections() { /* Setup the GPU carveout. */ SetupGpuCarveout(); /* Configure the two kernel carveouts. */ SetupKernelCarveouts(); /* Disable the ARC. */ DisableArc(); /* Disable untranslated memory accesses by devices. */ DisableUntranslatedDeviceMemoryAccess(); /* Further protections aren't applied on <= 1.0.0. */ if (GetTargetFirmware() <= TargetFirmware_1_0_0) { return; } /* Finalize and lock the carveout scratch registers. */ FinalizeCarveoutSecureScratchRegisters(); pmc::LockSecureRegister(pmc::SecureRegister_Carveout); /* Clear all the BPMP exception vectors to a fixed value. */ constexpr u32 BpmpExceptionVector = 0x7D000000; reg::Write(EVP + EVP_COP_RESET_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_UNDEF_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_SWI_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_RSVD_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_IRQ_VECTOR, BpmpExceptionVector); reg::Write(EVP + EVP_COP_FIQ_VECTOR, BpmpExceptionVector); /* Disable arbitration for the bpmp. */ reg::ReadWrite(SYSTEM + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE)); /* Turn on the SMMU for the BPMP. */ EnableBpmpSmmu(); /* Wait until the flow controller reports that the BPMP is halted. */ while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP))) { util::WaitMicroSeconds(1); } /* Enable clock to the activity monitor. */ clkrst::EnableActmonClock(); /* If JTAG is disabled, disable JTAG. */ if (!secmon::IsJtagEnabled()) { reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, DISABLED)); /* Turn on the activity monitor to prevent booting up the bpmp. */ actmon::StartMonitoringBpmp(ActmonInterruptHandler); } } void SetupPmcAndMcSecure() { const auto target_fw = GetTargetFirmware(); if (target_fw >= TargetFirmware_2_0_0) { /* Set the PMC secure. */ reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE)); } if (target_fw >= TargetFirmware_4_0_0) { /* Set the MC secure. */ reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, SLAVE_SECURITY_REG_BITS_ENUM(1, MC0, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, MC1, ENABLE), SLAVE_SECURITY_REG_BITS_ENUM(1, MCB, ENABLE)); } } void SetupCpuCoreContext() { /* Get the tsc frequency. */ const u32 tsc_frequency = reg::Read(MemoryRegionVirtualDeviceSysCtr0.GetAddress() + SYSCTR0_CNTFID0); /* Setup the secure EL2/EL1 system registers. */ SetupSecureEl2AndEl1SystemRegisters(); /* Setup the non-secure system registers. */ SetupNonSecureSystemRegisters(tsc_frequency); /* Reset the cpu flow controller registers. */ flow::ResetCpuRegisters(hw::GetCurrentCoreId()); /* Initialize the core unique gic registers. */ gic::InitializeCoreUnique(); /* Configure cpu fiq. */ constexpr int FiqInterruptId = 28; gic::SetPriority (FiqInterruptId, gic::HighestPriority); gic::SetInterruptGroup(FiqInterruptId, 0); gic::SetEnable (FiqInterruptId, true); /* Restore the cpu's debug registers. */ RestoreDebugRegisters(); } void SetupCpuSErrorDebug() { /* Get whether we should enable SError debug. */ const auto &bc_data = secmon::GetBootConfig().data; const bool enabled = bc_data.IsDevelopmentFunctionEnabled() && bc_data.IsSErrorDebugEnabled(); /* Get and set scr_el3. */ { util::BitPack32 scr; HW_CPU_GET_SCR_EL3(scr); scr.Set<hw::ScrEl3::Ea>(enabled ? 0 : 1); HW_CPU_SET_SCR_EL3(scr); } /* Prevent reordering instructions around this call. */ hw::InstructionSynchronizationBarrier(); } void SetKernelCarveoutRegion(int index, uintptr_t address, size_t size) { /* Configure the carveout. */ auto &carveout = g_kernel_carveouts[index]; carveout.address = address; carveout.size = size; SetupKernelCarveouts(); } } ================================================ FILE: exosphere/program/source/secmon_setup.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { constexpr inline u64 MemoryAttributeIndexNormal = 0; constexpr inline u64 MemoryAttributeIndexDevice = 1; constexpr inline int KernelCarveoutCount = 2; constexpr size_t CarveoutSizeMax = 512_MB - 128_KB; void SetupCpuMemoryControllersEnableMmu(); void SetupCpuCoreContext(); void SetupCpuSErrorDebug(); void SetupSocDmaControllers(); void SetupSocSecurity(); void SetupSocProtections(); void SetupPmcAndMcSecure(); void Setup1(); void SaveSecurityEngineAesKeySlotTestVector(); void SetKernelCarveoutRegion(int index, uintptr_t address, size_t size); } ================================================ FILE: exosphere/program/source/secmon_setup_warm.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_setup.hpp" namespace ams::secmon { namespace setup { #include "secmon_cache_impl.inc" } namespace { constexpr inline uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress(); using namespace ams::mmu; constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwCode, MemoryAttributeIndexNormal); void SetupCpuCommonControllers() { /* Set cpuactlr_el1. */ { util::BitPack64 cpuactlr = {}; cpuactlr.Set<hw::CpuactlrEl1CortexA57::NonCacheableStreamingEnhancement>(1); cpuactlr.Set<hw::CpuactlrEl1CortexA57::DisableLoadPassDmb>(1); HW_CPU_SET_CPUACTLR_EL1(cpuactlr); } /* Set cpuectlr_el1. */ { util::BitPack64 cpuectlr = {}; cpuectlr.Set<hw::CpuectlrEl1CortexA57::Smpen>(1); cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2LoadStoreDataPrefetchDistance>(3); cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2InstructionFetchPrefetchDistance>(3); HW_CPU_SET_CPUECTLR_EL1(cpuectlr); } /* Prevent instruction reordering. */ hw::InstructionSynchronizationBarrier(); } void SetupCpuEl3Controllers() { /* Set scr_el3. */ { util::BitPack32 scr = {}; scr.Set<hw::ScrEl3::Ns >(1); /* Set EL0/EL1 as Non-Secure. */ scr.Set<hw::ScrEl3::Irq >(0); /* IRQs are taken in IRQ mode. */ scr.Set<hw::ScrEl3::Fiq >(1); /* FIQs are taken in Monitor mode. */ scr.Set<hw::ScrEl3::Ea >(1); /* External aborts are taken in Monitor mode. */ scr.Set<hw::ScrEl3::Fw >(1); /* CPSR.F is non-secure writable. */ scr.Set<hw::ScrEl3::Aw >(1); /* CPSR.A is non-secure writable. */ scr.Set<hw::ScrEl3::Net >(0); /* This bit is not implemented. */ scr.Set<hw::ScrEl3::Smd >(0); /* Secure Monitor Call is allowed. */ scr.Set<hw::ScrEl3::Hce >(0); /* Hypervisor Calls are disabled. */ /* TODO: Enable for thermosphere? */ scr.Set<hw::ScrEl3::Sif >(1); /* Secure mode cannot fetch instructions from non-secure memory. */ scr.Set<hw::ScrEl3::RwCortexA53>(1); /* Reserved bit. N probably sets it because on Cortex A53, this sets kernel as aarch64. */ scr.Set<hw::ScrEl3::StCortexA53>(0); /* Reserved bit. On Cortex A53, this sets secure registers to EL3 only. */ scr.Set<hw::ScrEl3::Twi >(0); /* WFI is not trapped. */ scr.Set<hw::ScrEl3::Twe >(0); /* WFE is not trapped. */ HW_CPU_SET_SCR_EL3(scr); } /* Set ttbr0_el3. */ { constexpr u64 ttbr0 = MemoryRegionPhysicalTzramL1PageTable.GetAddress(); HW_CPU_SET_TTBR0_EL3(ttbr0); } /* Set tcr_el3. */ { util::BitPack32 tcr = { hw::TcrEl3::Res1 }; tcr.Set<hw::TcrEl3::T0sz >(31); /* Configure TTBR0 addressed size to be 64 GiB */ tcr.Set<hw::TcrEl3::Irgn0>(1); /* Configure PTE walks as inner write-back write-allocate cacheable */ tcr.Set<hw::TcrEl3::Orgn0>(1); /* Configure PTE walks as outer write-back write-allocate cacheable */ tcr.Set<hw::TcrEl3::Sh0 >(3); /* Configure PTE walks as inner shareable */ tcr.Set<hw::TcrEl3::Tg0 >(0); /* Set TTBR0_EL3 granule as 4 KiB */ tcr.Set<hw::TcrEl3::Ps >(1); /* Set the physical addrss size as 36-bit (64 GiB) */ tcr.Set<hw::TcrEl3::Tbi >(0); /* Top byte is not ignored in addrss calculations */ HW_CPU_SET_TCR_EL3(tcr); } /* Clear cptr_el3. */ { util::BitPack32 cptr = {}; cptr.Set<hw::CptrEl3::Tfp >(0); /* FP/SIMD instructions don't trap. */ cptr.Set<hw::CptrEl3::Tta >(0); /* Reserved bit (no trace functionality present). */ cptr.Set<hw::CptrEl3::Tcpac>(0); /* Access to cpacr_El1 does not trap. */ HW_CPU_SET_CPTR_EL3(cptr); } /* Set mair_el3. */ { u64 mair = (MemoryRegionAttributes_Normal << (MemoryRegionAttributeWidth * MemoryAttributeIndexNormal)) | (MemoryRegionAttributes_Device << (MemoryRegionAttributeWidth * MemoryAttributeIndexDevice)); HW_CPU_SET_MAIR_EL3(mair); } /* Set vectors. */ { constexpr u64 vectors = MemoryRegionVirtualTzramProgramExceptionVectors.GetAddress(); HW_CPU_SET_VBAR_EL3(vectors); } /* Prevent instruction re-ordering around this point. */ hw::InstructionSynchronizationBarrier(); } void EnableMmu() { /* Create sctlr value. */ util::BitPack64 sctlr = { hw::SctlrEl3::Res1 }; sctlr.Set<hw::SctlrEl3::M>(1); /* Globally enable the MMU. */ sctlr.Set<hw::SctlrEl3::A>(0); /* Disable alignment fault checking. */ sctlr.Set<hw::SctlrEl3::C>(1); /* Globally enable the data and unified caches. */ sctlr.Set<hw::SctlrEl3::Sa>(0); /* Disable stack alignment checking. */ sctlr.Set<hw::SctlrEl3::I>(1); /* Globally enable the instruction cache. */ sctlr.Set<hw::SctlrEl3::Wxn>(0); /* Do not force writable pages to be ExecuteNever. */ sctlr.Set<hw::SctlrEl3::Ee>(0); /* Exceptions should be little endian. */ /* Ensure all writes are done before turning on the mmu. */ hw::DataSynchronizationBarrierInnerShareable(); /* Invalidate the entire tlb. */ hw::InvalidateEntireTlb(); /* Ensure instruction consistency. */ hw::DataSynchronizationBarrierInnerShareable(); hw::InstructionSynchronizationBarrier(); /* Set sctlr_el3. */ HW_CPU_SET_SCTLR_EL3(sctlr); hw::InstructionSynchronizationBarrier(); } bool IsExitLp0() { return reg::Read(MC + MC_SECURITY_CFG3) == 0; } constexpr void AddPhysicalTzramIdentityMappingImpl(u64 *l1, u64 *l2, u64 *l3) { /* Define extents. */ const uintptr_t start_address = MemoryRegionPhysicalTzram.GetAddress(); const size_t size = MemoryRegionPhysicalTzram.GetSize(); const uintptr_t end_address = start_address + size; /* Flush cache for the L3 page table entries. */ { const uintptr_t start = GetL3EntryIndex(start_address); const uintptr_t end = GetL3EntryIndex(end_address); for (uintptr_t i = start; i < end; i += hw::DataCacheLineSize / sizeof(*l3)) { if (!std::is_constant_evaluated()) { hw::FlushDataCacheLine(l3 + i); } } } /* Flush cache for the L2 page table entry. */ if (!std::is_constant_evaluated()) { hw::FlushDataCacheLine(l2 + GetL2EntryIndex(start_address)); } /* Flush cache for the L1 page table entry. */ if (!std::is_constant_evaluated()) { hw::FlushDataCacheLine(l1 + GetL1EntryIndex(start_address)); } /* Add the L3 mappings. */ SetL3BlockEntry(l3, start_address, start_address, size, MappingAttributesEl3SecureRwCode); /* Add the L2 entry for the physical tzram region. */ SetL2TableEntry(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); /* Add the L1 entry for the physical region. */ SetL1TableEntry(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode); static_assert(GetL1EntryIndex(MemoryRegionPhysical.GetAddress()) == 1); /* Invalidate the data cache for the L3 page table entries. */ { const uintptr_t start = GetL3EntryIndex(start_address); const uintptr_t end = GetL3EntryIndex(end_address); for (uintptr_t i = start; i < end; i += hw::DataCacheLineSize / sizeof(*l3)) { if (!std::is_constant_evaluated()) { hw::InvalidateDataCacheLine(l3 + i); } } } /* Flush cache for the L2 page table entry. */ if (!std::is_constant_evaluated()) { hw::InvalidateDataCacheLine(l2 + GetL2EntryIndex(start_address)); } /* Flush cache for the L1 page table entry. */ if (!std::is_constant_evaluated()) { hw::InvalidateDataCacheLine(l1 + GetL1EntryIndex(start_address)); } } void RestoreDebugCode() { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) { const u64 *src = MemoryRegionPhysicalDramDebugDataStore.GetPointer<u64>(); volatile u64 *dst = MemoryRegionPhysicalDebugCode.GetPointer<u64>(); for (size_t i = 0; i < MemoryRegionPhysicalDramDebugDataStore.GetSize() / sizeof(u64); ++i) { dst[i] = src[i]; } } #endif } void AddPhysicalTzramIdentityMapping() { /* Get page table extents. */ u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>(); u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer<u64>(); /* Add the mapping. */ AddPhysicalTzramIdentityMappingImpl(l1, l2_l3, l2_l3); /* Ensure that mappings are consistent. */ setup::EnsureMappingConsistency(); } } void SetupCpuMemoryControllersEnableMmu() { SetupCpuCommonControllers(); SetupCpuEl3Controllers(); EnableMmu(); } void SetupSocDmaControllers() { /* Ensure that our caches are managed. */ setup::InvalidateEntireDataCache(); setup::EnsureInstructionConsistency(); /* Lock tsec. */ tsec::Lock(); /* Enable SWID[0] for all bits. */ reg::Write(AHB_ARBC(AHB_MASTER_SWID), ~0u); /* Clear SWID1 for all bits. */ reg::Write(AHB_ARBC(AHB_MASTER_SWID_1), 0u); /* Set MSELECT config to set WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */ /* and clear ERR_RESP_EN_SLAVE1(PCIe) | ERR_RESP_EN_SLAVE2(GPU) */ { reg::ReadWrite(MSELECT(MSELECT_CONFIG), MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE1, DISABLE), MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE2, DISABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE0, ENABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE1, ENABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE2, ENABLE)); } /* Disable USB, USB2, AHB-DMA from arbitration. */ { reg::ReadWrite(AHB_ARBC(AHB_ARBITRATION_DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_AHBDMA, DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB, DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB2, DISABLE)); } /* Select high priority group with priority 7. */ { u32 priority_ctrl = {}; priority_ctrl |= (7u << 29); /* Set group 7. */ priority_ctrl |= (1u << 0); /* Set high priority. */ reg::Write(AHB_ARBC(AHB_ARBITRATION_PRIORITY_CTRL), priority_ctrl); } /* Prevent splitting AHB writes to TZRAM. */ { reg::Write(AHB_ARBC(AHB_GIZMO_TZRAM), (1u << 7)); } /* NOTE: This is Mariko only in Nintendo's firmware. */ /* Still, it seems to have no adverse effects on Erista... */ /* TODO: Find a way to get access to SocType this early (fuse driver isn't alive yet), only write on mariko? */ { reg::ReadWrite(AHB_ARBC(AHB_AHB_SPARE_REG), AHB_REG_BITS_VALUE(AHB_SPARE_REG_AHB_SPARE_REG, 0xE0000)); } } void SetupSocDmaControllersCpuMemoryControllersEnableMmuWarmboot() { /* If this is being called from lp0 exit, we want to setup the soc dma controllers. */ if (IsExitLp0()) { RestoreDebugCode(); SetupSocDmaControllers(); } /* Add a physical TZRAM identity map. */ AddPhysicalTzramIdentityMapping(); /* Initialize cpu memory controllers and the MMU. */ SetupCpuMemoryControllersEnableMmu(); } } ================================================ FILE: exosphere/program/source/secmon_spinlock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { using SpinLockType = u32; void AcquireSpinLock(SpinLockType &lock); void ReleaseSpinLock(SpinLockType &lock); } ================================================ FILE: exosphere/program/source/secmon_spinlock.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams6secmon15AcquireSpinLockERj, "ax", %progbits .align 4 .global _ZN3ams6secmon15AcquireSpinLockERj _ZN3ams6secmon15AcquireSpinLockERj: /* Prepare to try to take the spinlock. */ mov w1, #1 sevl prfm pstl1keep, [x0] 1: /* Repeatedly try to take the lock. */ wfe ldaxr w2, [x0] cbnz w2, 1b stxr w2, w1, [x0] cbnz w2, 1b /* Return. */ ret .section .text._ZN3ams6secmon15ReleaseSpinLockERj, "ax", %progbits .align 4 .global _ZN3ams6secmon15ReleaseSpinLockERj _ZN3ams6secmon15ReleaseSpinLockERj: /* Release the spinlock. */ stlr wzr, [x0] /* Return. */ ret ================================================ FILE: exosphere/program/source/secmon_stack_warm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .warmboot.data._ZN3ams6secmon23CommonWarmbootStackLockE, "aw", %progbits .global _ZN3ams6secmon23CommonWarmbootStackLockE _ZN3ams6secmon23CommonWarmbootStackLockE: /* Define storage for the global common warmboot stack bakery lock. */ .word 0 ================================================ FILE: exosphere/program/source/secmon_start_virtual.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams6secmon5StartEv, "ax", %progbits .align 4 .global _ZN3ams6secmon5StartEv _ZN3ams6secmon5StartEv: /* Set SPSEL 1 stack pointer to the core 0 exception stack address. */ msr spsel, #1 ldr x20, =0x1F01F6F00 mov sp, x20 /* Set SPSEL 0 stack pointer to a temporary location in volatile memory. */ msr spsel, #0 ldr x20, =0x1F01C0800 mov sp, x20 /* Setup X18 to point to the global context. */ ldr x18, =0x1F01FA000 /* Invoke main. */ bl _ZN3ams6secmon4MainEv /* Clear boot code high. */ bl _ZN3ams6secmon17ClearBootCodeHighEv /* Set the stack pointer to the core 3 exception stack address. */ ldr x20, =0x1F01F9000 mov sp, x20 /* Unmap the boot code region (and clear the low part). */ bl _ZN3ams6secmon13UnmapBootCodeEv /* Initialize the random cache. */ /* NOTE: Nintendo does this much earlier, but we reuse volatile space. */ bl _ZN3ams6secmon3smc15FillRandomCacheEv /* Jump to lower exception level. */ b _ZN3ams6secmon25JumpToLowerExceptionLevelEv .section .text._ZN3ams6secmon20StartWarmbootVirtualEv, "ax", %progbits .align 4 .global _ZN3ams6secmon20StartWarmbootVirtualEv _ZN3ams6secmon20StartWarmbootVirtualEv: /* Set the stack pointer to the shared warmboot stack address. */ ldr x20, =0x1F01F67C0 mov sp, x20 /* Setup X18 to point to the global context. */ ldr x18, =0x1F01FA000 /* Perform final warmboot setup. */ bl _ZN3ams6secmon24SetupSocSecurityWarmbootEv /* Jump to lower exception level. */ b _ZN3ams6secmon25JumpToLowerExceptionLevelEv .section .text._ZN3ams6secmon25JumpToLowerExceptionLevelEv, "ax", %progbits .align 4 .global _ZN3ams6secmon25JumpToLowerExceptionLevelEv _ZN3ams6secmon25JumpToLowerExceptionLevelEv: /* Get the EntryContext. */ sub sp, sp, #0x10 mov x0, sp bl _ZN3ams6secmon15GetEntryContextEPNS0_12EntryContextE /* Load the entrypoint and argument from the context. */ ldr x19, [sp, #0x00] ldr x0, [sp, #0x08] /* Set the exception return address. */ msr elr_el3, x0 /* Get the core exception stack. */ bl _ZN3ams6secmon28GetCoreExceptionStackVirtualEv mov sp, x0 /* Release our exclusive access to the common warmboot stack. */ bl _ZN3ams6secmon26ReleaseCommonWarmbootStackEv /* Configure SPSR_EL3. */ mov x0, #0x3C5 msr spsr_el3, x0 /* Set x0 to the entry argument. */ mov x0, x19 /* Ensure instruction reordering doesn't happen around this point. */ isb /* Return to lower level. */ eret /* Infinite loop, though we should never get here. */ 1: b 1b .section .text._ZN3ams6secmon28GetCoreExceptionStackVirtualEv, "ax", %progbits .align 4 .global _ZN3ams6secmon28GetCoreExceptionStackVirtualEv _ZN3ams6secmon28GetCoreExceptionStackVirtualEv: /* Get the current core id. */ mrs x0, mpidr_el1 and x0, x0, #3 /* Jump to the appropriate core's stack handler. */ cmp x0, #3 b.eq 3f cmp x0, #2 b.eq 2f cmp x0, #1 b.eq 1f /* cmp x0, #0 */ /* b.eq 0f */ 0: ldr x0, =0x1F01F6F00 ret 1: ldr x0, =0x1F01F6F80 ret 2: ldr x0, =0x1F01F7000 ret 3: ldr x0, =0x1F01F9000 ret .section .text._ZN3ams6secmon25AcquireCommonSmcStackLockEv, "ax", %progbits .align 4 .global _ZN3ams6secmon25AcquireCommonSmcStackLockEv _ZN3ams6secmon25AcquireCommonSmcStackLockEv: /* Get the address of the lock. */ ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE /* Take the lock. */ b _ZN3ams6secmon15AcquireSpinLockERj .section .text._ZN3ams6secmon25ReleaseCommonSmcStackLockEv, "ax", %progbits .align 4 .global _ZN3ams6secmon25ReleaseCommonSmcStackLockEv _ZN3ams6secmon25ReleaseCommonSmcStackLockEv: /* Get the address of the lock. */ ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE /* Release the lock. */ b _ZN3ams6secmon15ReleaseSpinLockERj .section .text._ZN3ams6secmon26ReleaseCommonWarmbootStackEv, "ax", %progbits .align 4 .global _ZN3ams6secmon26ReleaseCommonWarmbootStackEv _ZN3ams6secmon26ReleaseCommonWarmbootStackEv: /* Get the virtual address of the lock. */ ldr x0, =_ZN3ams6secmon23CommonWarmbootStackLockE ldr x1, =(0x1F00C0000 - 0x07C012000) add x1, x1, x0 /* Get the bakery value for our core. */ mrs x0, mpidr_el1 and x0, x0, #3 ldrb w2, [x1, x0] /* Clear our ticket number. */ and w2, w2, #(~0x7F) strb w2, [x1, x0] /* Flush the cache. */ dc civac, x1 /* Synchronize data for all cores. */ dsb sy /* Send an event. */ sev /* Return. */ ret .section .text._ZN3ams6secmon19PivotStackAndInvokeEPvPFvvE, "ax", %progbits .align 4 .global _ZN3ams6secmon19PivotStackAndInvokeEPvPFvvE _ZN3ams6secmon19PivotStackAndInvokeEPvPFvvE: /* Pivot to use the provided stack pointer. */ mov sp, x0 /* Release our lock on the common smc stack. */ mov x19, x1 bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv /* Invoke the function with the new stack. */ br x19 .section .data._ZN3ams6secmon18CommonSmcStackLockE, "aw", %progbits .global _ZN3ams6secmon18CommonSmcStackLockE _ZN3ams6secmon18CommonSmcStackLockE: /* Define storage for the global common smc stack spinlock. */ .word 0 ================================================ FILE: exosphere/program/source/secmon_start_warm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ #define cpuactlr_el1 s3_1_c15_c2_0 #define cpuectlr_el1 s3_1_c15_c2_1 .macro RESET_CORE mov x0, #(1 << 63) msr cpuactlr_el1, x0 /* disable regional clock gating */ isb mov x0, #3 msr rmr_el3, x0 isb dsb sy /* Nintendo forgot to copy-paste the branch instruction below. */ 1: wfi b 1b .endm .macro ERRATUM_INVALIDATE_BTB_AT_BOOT /* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */ /* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* The following comments are mine. */ /* Enable invalidates of branch target buffer, then flush the entire instruction cache at the local level, and with the reg change, the branch target buffer, then disable invalidates of the branch target buffer again. */ mrs x0, cpuactlr_el1 orr x0, x0, #1 msr cpuactlr_el1, x0 dsb sy isb ic iallu dsb sy isb mrs x0, cpuactlr_el1 bic x0, x0, #1 msr cpuactlr_el1, x0 .rept 7 nop /* wait long enough for the write to cpuactlr_el1 to have completed */ .endr /* if the OS lock is set, disable it and request a warm reset */ mrs x0, oslsr_el1 ands x0, x0, #2 b.eq 2f mov x0, xzr msr oslar_el1, x0 RESET_CORE .rept 65 nop /* guard against speculative excecution */ .endr 2: /* set the OS lock */ mov x0, #1 msr oslar_el1, x0 .endm .section .warmboot.text.start, "ax", %progbits .align 4 .global _start_warm _start_warm: /* mask all interrupts */ msr daifset, #0xF /* Fixup hardware erratum */ ERRATUM_INVALIDATE_BTB_AT_BOOT /* Acquire exclusive access to the common warmboot stack. */ bl _ZN3ams6secmon26AcquireCommonWarmbootStackEv /* Set the stack pointer to the common warmboot stack address. */ msr spsel, #1 ldr x20, =0x7C0107C0 mov sp, x20 /* Perform warmboot setup. */ bl _ZN3ams6secmon59SetupSocDmaControllersCpuMemoryControllersEnableMmuWarmbootEv /* Jump to the newly-mapped virtual address. */ b _ZN3ams6secmon20StartWarmbootVirtualEv /* void ams::secmon::AcquireCommonWarmbootStack() { */ /* NOTE: This implements critical section enter via https://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm */ /* This algorithm is used because the MMU is not awake yet, so exclusive load/store instructions are not usable. */ /* NOTE: Nintendo attempted to implement this algorithm themselves, but did not really understand how it works. */ /* They use the same ticket number for all cores; this can lead to starvation and other problems. */ .section .warmboot.text._ZN3ams6secmon26AcquireCommonWarmbootStackEv, "ax", %progbits .align 4 .global _ZN3ams6secmon26AcquireCommonWarmbootStackEv _ZN3ams6secmon26AcquireCommonWarmbootStackEv: /* BakeryLock *lock = std::addressof(secmon::CommonWarmBootStackLock); */ ldr x0, =_ZN3ams6secmon23CommonWarmbootStackLockE /* const u32 id = GetCurrentCoreId(); */ mrs x8, mpidr_el1 and x8, x8, #3 /* lock->customers[id].is_entering = true; */ ldrb w2, [x0, x8] orr w2, w2, #~0x7F strb w2, [x0, x8] /* const u8 ticket_0 = lock->customers[0].ticket_number; */ ldrb w4, [x0, #0] and w4, w4, #0x7F /* const u8 ticket_1 = lock->customers[1].ticket_number; */ ldrb w5, [x0, #1] and w5, w5, #0x7F /* const u8 ticket_2 = lock->customers[2].ticket_number; */ ldrb w6, [x0, #2] and w6, w6, #0x7F /* const u8 ticket_3 = lock->customers[3].ticket_number; */ ldrb w7, [x0, #3] and w7, w7, #0x7F /* u8 biggest_ticket = std::max(std::max(ticket_0, ticket_1), std::max(ticket_2, ticket_3)) */ cmp w4, w5 csel w2, w4, w5, hi cmp w6, w7 csel w3, w6, w7, hi cmp w2, w3 csel w2, w2, w3, hi /* NOTE: The biggest a ticket can ever be is 4, so the general increment is safe and 7-bit increment is not needed. */ /* lock->customers[id] = { .is_entering = false, .ticket_number = ++biggest_ticket }; */ add w2, w2, #1 strb w2, [x0, x8] /* Ensure instructions aren't reordered around this point. */ /* hw::DataSynchronizationBarrier(); */ dsb sy /* hw::SendEvent(); */ sev /* for (unsigned int i = 0; i < 4; ++i) { */ mov w3, #0 1: /* hw::SendEventLocal(); */ sevl /* do { */ 2: /* hw::WaitForEvent(); */ wfe /* while (lock->customers[i].is_entering); */ ldrb w4, [x0, x3] tbnz w4, #7, 2b /* u8 their_ticket; */ /* hw::SendEventLocal(); */ sevl /* do { */ 2: /* hw::WaitForEvent(); */ wfe /* their_ticket = lock->customers[i].ticket_number; */ ldrb w4, [x0, x3] ands w4, w4, #0x7F /* if (their_ticket == 0) { break; } */ b.eq 3f /* while ((their_ticket > my_ticket) || (their_ticket == my_ticket && id > i)); */ cmp w2, w4 b.hi 2b ccmp w8, w3, #0, eq b.hi 2b /* } */ 3: add w3, w3, #1 cmp w3, #4 b.ne 1b /* hw::DataMemoryBarrier(); */ dmb sy ret ================================================ FILE: exosphere/program/source/secmon_user_power_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_cpu_context.hpp" #include "secmon_page_mapper.hpp" #include "secmon_mariko_fatal_error.hpp" #include "secmon_user_power_management.hpp" #include "rebootstub_bin.h" namespace ams::secmon { namespace { constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress(); constexpr inline const u32 RebootStubPhysicalAddress = MemoryRegionPhysicalIramRebootStub.GetAddress(); enum RebootStubAction { RebootStubAction_ShutDown = 0, RebootStubAction_JumpToPayload = 1, }; NORETURN void PerformPmcReboot() { /* Write MAIN_RST. */ reg::Write(PMC + APBDEV_PMC_CNTRL, 0x10); while (true) { /* ... */ } } void LoadRebootStub(u32 action) { /* Configure the bootrom to boot to warmboot payload. */ reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x1); /* Patch the bootrom to perform an SVC immediately after the second spare write. */ reg::Write(PMC + APBDEV_PMC_SCRATCH45, 0x2E38DFFF); reg::Write(PMC + APBDEV_PMC_SCRATCH46, 0x6001DC28); /* Patch the bootrom to jump to the reboot stub we'll prepare in iram on SVC. */ reg::Write(PMC + APBDEV_PMC_SCRATCH33, RebootStubPhysicalAddress); reg::Write(PMC + APBDEV_PMC_SCRATCH40, 0x6000F208); { /* Map the iram page. */ AtmosphereIramPageMapper mapper(RebootStubPhysicalAddress); AMS_ABORT_UNLESS(mapper.Map()); /* Copy the reboot stub. */ AMS_ABORT_UNLESS(mapper.CopyToMapping(RebootStubPhysicalAddress, rebootstub_bin, rebootstub_bin_size)); /* Set the reboot type. */ AMS_ABORT_UNLESS(mapper.CopyToMapping(RebootStubPhysicalAddress + 4, std::addressof(action), sizeof(action))); } } } void PerformUserRebootByPmic() { /* Ensure that i2c-5 is usable for communicating with the pmic. */ clkrst::EnableI2c5Clock(); i2c::Initialize(i2c::Port_5); /* Reboot. */ pmic::ShutdownSystem(true); } void PerformUserRebootToRcm() { /* Configure the bootrom to boot to rcm. */ reg::Write(PMC + APBDEV_PMC_SCRATCH0, 0x2); /* Reboot. */ PerformPmcReboot(); } void PerformUserRebootToPayload() { /* Load our reboot stub to iram. */ LoadRebootStub(RebootStubAction_JumpToPayload); /* Reboot. */ PerformPmcReboot(); } void PerformUserRebootToFatalError() { if (fuse::GetSocType() == fuse::SocType_Erista) { /* On Erista, we reboot to fatal error by jumping to fusee primary's handler. */ return PerformUserRebootToPayload(); } else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { /* Call the fatal error handler. */ HandleMarikoFatalErrorInterrupt(); /* We should never get to this point. */ AMS_ABORT("Returned from Mariko Fatal handler?\n"); } } void PerformUserShutDown() { if (fuse::GetSocType() == fuse::SocType_Mariko) { /* Ensure that i2c-5 is usable for communicating with the pmic. */ clkrst::EnableI2c5Clock(); i2c::Initialize(i2c::Port_5); /* On Mariko shutdown via pmic. */ pmic::ShutdownSystem(false); } else /* if (fuse::GetSocType() == fuse::SocType_Erista) */ { /* Load our reboot stub to iram. */ LoadRebootStub(RebootStubAction_ShutDown); /* Reboot. */ PerformPmcReboot(); } } } ================================================ FILE: exosphere/program/source/secmon_user_power_management.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon { enum UserRebootType { UserRebootType_None = 0, UserRebootType_ToRcm = 1, UserRebootType_ToPayload = 2, UserRebootType_ToFatalError = 3, UserRebootType_ByPmic = 4, }; void PerformUserRebootToRcm(); void PerformUserRebootToPayload(); void PerformUserRebootToFatalError(); void PerformUserRebootByPmic(); void PerformUserShutDown(); } ================================================ FILE: exosphere/program/source/smc/secmon_define_access_table.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using __ACCESS_TABLE_NAME__ = AccessTable<__ACCESS_TABLE_ADDRESS__, [] { /* Declare a table. */ std::array<u8, 0x80> table = {}; /* Declare a helper. */ auto SetRegisterAllowed = [&](uintptr_t reg) { SetRegisterTableAllowed(table, reg); }; /* Populate the table. */ #include __ACCESS_TABLE_INC__ return table; }()>; static_assert(__ACCESS_TABLE_NAME__::Address >= __ACCESS_TABLE_ADDRESS__); ================================================ FILE: exosphere/program/source/smc/secmon_define_mc01_access_table.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define __ACCESS_TABLE_NAME__ Mc01AccessTable #define __ACCESS_TABLE_ADDRESS__ 0 #define __ACCESS_TABLE_INC__ "secmon_mc01_access_table_data.inc" #include "secmon_define_access_table.inc" #undef __ACCESS_TABLE_INC__ #undef __ACCESS_TABLE_ADDRESS__ #undef __ACCESS_TABLE_NAME__ ================================================ FILE: exosphere/program/source/smc/secmon_define_mc_access_table.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define __ACCESS_TABLE_NAME__ McAccessTable #define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDeviceMemoryController.GetAddress() #define __ACCESS_TABLE_INC__ "secmon_mc_access_table_data.inc" #include "secmon_define_access_table.inc" #undef __ACCESS_TABLE_INC__ #undef __ACCESS_TABLE_ADDRESS__ #undef __ACCESS_TABLE_NAME__ ================================================ FILE: exosphere/program/source/smc/secmon_define_pmc_access_table.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define __ACCESS_TABLE_NAME__ PmcAccessTable #define __ACCESS_TABLE_ADDRESS__ MemoryRegionPhysicalDevicePmc.GetAddress() #define __ACCESS_TABLE_INC__ "secmon_pmc_access_table_data.inc" #include "secmon_define_access_table.inc" #undef __ACCESS_TABLE_INC__ #undef __ACCESS_TABLE_ADDRESS__ #undef __ACCESS_TABLE_NAME__ ================================================ FILE: exosphere/program/source/smc/secmon_mc01_access_table_data.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ SetRegisterAllowed(MC_STAT_CONTROL); /* 0x100 */ SetRegisterAllowed(MC_STAT_EMC_CLOCK_LIMIT); /* 0x108 */ SetRegisterAllowed(MC_STAT_EMC_CLOCK_LIMIT_MSBS); /* 0x10C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_LO); /* 0x118 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_HI); /* 0x11C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_SPARE); /* 0x124 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_0); /* 0x128 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_1); /* 0x12C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_2); /* 0x130 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_3); /* 0x134 */ SetRegisterAllowed(MC_STAT_EMC_SET0_COUNT); /* 0x138 */ SetRegisterAllowed(MC_STAT_EMC_SET0_COUNT_MSBS); /* 0x13C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_LO); /* 0x158 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_HI); /* 0x15C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_SPARE); /* 0x164 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_0); /* 0x168 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_1); /* 0x16C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_2); /* 0x170 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_3); /* 0x174 */ SetRegisterAllowed(MC_STAT_EMC_SET1_COUNT); /* 0x178 */ SetRegisterAllowed(MC_STAT_EMC_SET1_COUNT_MSBS); /* 0x17C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_ADR_LIMIT_UPPER); /* 0xA20 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_ADR_LIMIT_UPPER); /* 0xA24 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_4); /* 0xB88 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_4); /* 0xB8C */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET0_CLIENT_5); /* 0xBC4 */ SetRegisterAllowed(MC_STAT_EMC_FILTER_SET1_CLIENT_5); /* 0xBC8 */ ================================================ FILE: exosphere/program/source/smc/secmon_mc_access_table_data.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ SetRegisterAllowed(MC_INTSTATUS); /* 0x000 */ SetRegisterAllowed(MC_INTMASK); /* 0x004 */ SetRegisterAllowed(MC_ERR_STATUS); /* 0x008 */ SetRegisterAllowed(MC_ERR_ADR); /* 0x00C */ SetRegisterAllowed(MC_SMMU_CONFIG); /* 0x010 */ SetRegisterAllowed(MC_SMMU_PTB_ASID); /* 0x01C */ SetRegisterAllowed(MC_SMMU_PTB_DATA); /* 0x020 */ SetRegisterAllowed(MC_SMMU_TLB_FLUSH); /* 0x030 */ SetRegisterAllowed(MC_SMMU_PTC_FLUSH_0); /* 0x034 */ SetRegisterAllowed(MC_EMEM_CFG); /* 0x050 */ SetRegisterAllowed(MC_EMEM_ADR_CFG); /* 0x054 */ SetRegisterAllowed(MC_EMEM_ARB_CFG); /* 0x090 */ SetRegisterAllowed(MC_EMEM_ARB_OUTSTANDING_REQ); /* 0x094 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RCD); /* 0x098 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RP); /* 0x09C */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RC); /* 0x0A0 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RAS); /* 0x0A4 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_FAW); /* 0x0A8 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RRD); /* 0x0AC */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RAP2PRE); /* 0x0B0 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_WAP2PRE); /* 0x0B4 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_R2R); /* 0x0B8 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_W2W); /* 0x0BC */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_R2W); /* 0x0C0 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_W2R); /* 0x0C4 */ SetRegisterAllowed(MC_EMEM_ARB_MISC2); /* 0x0C8 */ SetRegisterAllowed(MC_EMEM_ARB_DA_TURNS); /* 0x0D0 */ SetRegisterAllowed(MC_EMEM_ARB_DA_COVERS); /* 0x0D4 */ SetRegisterAllowed(MC_EMEM_ARB_MISC0); /* 0x0D8 */ SetRegisterAllowed(MC_EMEM_ARB_MISC1); /* 0x0DC */ SetRegisterAllowed(MC_EMEM_ARB_RING1_THROTTLE); /* 0x0E0 */ SetRegisterAllowed(MC_CLIENT_HOTRESET_CTRL); /* 0x200 */ SetRegisterAllowed(MC_CLIENT_HOTRESET_STATUS); /* 0x204 */ SetRegisterAllowed(MC_SMMU_AFI_ASID); /* 0x238 */ SetRegisterAllowed(MC_SMMU_DC_ASID); /* 0x240 */ SetRegisterAllowed(MC_SMMU_DCB_ASID); /* 0x244 */ SetRegisterAllowed(MC_SMMU_HC_ASID); /* 0x250 */ SetRegisterAllowed(MC_SMMU_HDA_ASID); /* 0x254 */ SetRegisterAllowed(MC_SMMU_ISP2_ASID); /* 0x258 */ SetRegisterAllowed(MC_SMMU_MSENC_NVENC_ASID); /* 0x264 */ SetRegisterAllowed(MC_SMMU_NV_ASID); /* 0x268 */ SetRegisterAllowed(MC_SMMU_NV2_ASID); /* 0x26C */ SetRegisterAllowed(MC_SMMU_PPCS_ASID); /* 0x270 */ SetRegisterAllowed(MC_SMMU_SATA_ASID); /* 0x274 */ SetRegisterAllowed(MC_SMMU_VI_ASID); /* 0x280 */ SetRegisterAllowed(MC_SMMU_VIC_ASID); /* 0x284 */ SetRegisterAllowed(MC_SMMU_XUSB_HOST_ASID); /* 0x288 */ SetRegisterAllowed(MC_SMMU_XUSB_DEV_ASID); /* 0x28C */ SetRegisterAllowed(MC_SMMU_TSEC_ASID); /* 0x294 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_AVPC_0); /* 0x2E4 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DC_0); /* 0x2E8 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DC_1); /* 0x2EC */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DCB_0); /* 0x2F4 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_DCB_1); /* 0x2F8 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_HC_0); /* 0x310 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_HC_1); /* 0x314 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_MPCORE_0); /* 0x320 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_NVENC_0); /* 0x328 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_PPCS_0); /* 0x344 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_PPCS_1); /* 0x348 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_ISP2_0); /* 0x370 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_ISP2_1); /* 0x374 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_XUSB_0); /* 0x37C */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_XUSB_1); /* 0x380 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_TSEC_0); /* 0x390 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_VIC_0); /* 0x394 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_VI2_0); /* 0x398 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_GPU_0); /* 0x3AC */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCA_0); /* 0x3B8 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCAA_0); /* 0x3BC */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMC_0); /* 0x3C0 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_SDMMCAB_0); /* 0x3C4 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_NVDEC_0); /* 0x3D8 */ SetRegisterAllowed(MC_LATENCY_ALLOWANCE_GPU2_0); /* 0x3E8 */ SetRegisterAllowed(MC_DIS_PTSA_RATE); /* 0x41C */ SetRegisterAllowed(MC_DIS_PTSA_MIN); /* 0x420 */ SetRegisterAllowed(MC_DIS_PTSA_MAX); /* 0x424 */ SetRegisterAllowed(MC_DISB_PTSA_RATE); /* 0x428 */ SetRegisterAllowed(MC_DISB_PTSA_MIN); /* 0x42C */ SetRegisterAllowed(MC_DISB_PTSA_MAX); /* 0x430 */ SetRegisterAllowed(MC_VE_PTSA_RATE); /* 0x434 */ SetRegisterAllowed(MC_VE_PTSA_MIN); /* 0x438 */ SetRegisterAllowed(MC_VE_PTSA_MAX); /* 0x43C */ SetRegisterAllowed(MC_MLL_MPCORER_PTSA_RATE); /* 0x44C */ SetRegisterAllowed(MC_RING1_PTSA_RATE); /* 0x47C */ SetRegisterAllowed(MC_RING1_PTSA_MIN); /* 0x480 */ SetRegisterAllowed(MC_RING1_PTSA_MAX); /* 0x484 */ SetRegisterAllowed(MC_PCX_PTSA_RATE); /* 0x4AC */ SetRegisterAllowed(MC_PCX_PTSA_MIN); /* 0x4B0 */ SetRegisterAllowed(MC_PCX_PTSA_MAX); /* 0x4B4 */ SetRegisterAllowed(MC_MSE_PTSA_RATE); /* 0x4C4 */ SetRegisterAllowed(MC_MSE_PTSA_MIN); /* 0x4C8 */ SetRegisterAllowed(MC_MSE_PTSA_MAX); /* 0x4CC */ SetRegisterAllowed(MC_AHB_PTSA_RATE); /* 0x4DC */ SetRegisterAllowed(MC_AHB_PTSA_MIN); /* 0x4E0 */ SetRegisterAllowed(MC_AHB_PTSA_MAX); /* 0x4E4 */ SetRegisterAllowed(MC_APB_PTSA_RATE); /* 0x4E8 */ SetRegisterAllowed(MC_APB_PTSA_MIN); /* 0x4EC */ SetRegisterAllowed(MC_APB_PTSA_MAX); /* 0x4F0 */ SetRegisterAllowed(MC_FTOP_PTSA_RATE); /* 0x50C */ SetRegisterAllowed(MC_HOST_PTSA_RATE); /* 0x518 */ SetRegisterAllowed(MC_HOST_PTSA_MIN); /* 0x51C */ SetRegisterAllowed(MC_HOST_PTSA_MAX); /* 0x520 */ SetRegisterAllowed(MC_USBX_PTSA_RATE); /* 0x524 */ SetRegisterAllowed(MC_USBX_PTSA_MIN); /* 0x528 */ SetRegisterAllowed(MC_USBX_PTSA_MAX); /* 0x52C */ SetRegisterAllowed(MC_USBD_PTSA_RATE); /* 0x530 */ SetRegisterAllowed(MC_USBD_PTSA_MIN); /* 0x534 */ SetRegisterAllowed(MC_USBD_PTSA_MAX); /* 0x538 */ SetRegisterAllowed(MC_GK_PTSA_RATE); /* 0x53C */ SetRegisterAllowed(MC_GK_PTSA_MIN); /* 0x540 */ SetRegisterAllowed(MC_GK_PTSA_MAX); /* 0x544 */ SetRegisterAllowed(MC_AUD_PTSA_RATE); /* 0x548 */ SetRegisterAllowed(MC_AUD_PTSA_MIN); /* 0x54C */ SetRegisterAllowed(MC_AUD_PTSA_MAX); /* 0x550 */ SetRegisterAllowed(MC_VICPC_PTSA_RATE); /* 0x554 */ SetRegisterAllowed(MC_VICPC_PTSA_MIN); /* 0x558 */ SetRegisterAllowed(MC_VICPC_PTSA_MAX); /* 0x55C */ SetRegisterAllowed(MC_JPG_PTSA_RATE); /* 0x584 */ SetRegisterAllowed(MC_JPG_PTSA_MIN); /* 0x588 */ SetRegisterAllowed(MC_JPG_PTSA_MAX); /* 0x58C */ SetRegisterAllowed(MC_GK2_PTSA_RATE); /* 0x610 */ SetRegisterAllowed(MC_GK2_PTSA_MIN); /* 0x614 */ SetRegisterAllowed(MC_GK2_PTSA_MAX); /* 0x618 */ SetRegisterAllowed(MC_SDM_PTSA_RATE); /* 0x61C */ SetRegisterAllowed(MC_SDM_PTSA_MIN); /* 0x620 */ SetRegisterAllowed(MC_SDM_PTSA_MAX); /* 0x624 */ SetRegisterAllowed(MC_HDAPC_PTSA_RATE); /* 0x628 */ SetRegisterAllowed(MC_HDAPC_PTSA_MIN); /* 0x62C */ SetRegisterAllowed(MC_HDAPC_PTSA_MAX); /* 0x630 */ SetRegisterAllowed(MC_SEC_CARVEOUT_BOM); /* 0x670 */ SetRegisterAllowed(MC_SEC_CARVEOUT_SIZE_MB); /* 0x674 */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A); /* 0x690 */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB); /* 0x694 */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B); /* 0x698 */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB); /* 0x69C */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C); /* 0x6A0 */ SetRegisterAllowed(MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB); /* 0x6A4 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_RFCPB); /* 0x6C0 */ SetRegisterAllowed(MC_EMEM_ARB_TIMING_CCDMW); /* 0x6C4 */ SetRegisterAllowed(MC_EMEM_ARB_REFPB_HP_CTRL); /* 0x6F0 */ SetRegisterAllowed(MC_EMEM_ARB_REFPB_BANK_CTRL); /* 0x6F4 */ SetRegisterAllowed(MC_PTSA_GRANT_DECREMENT); /* 0x960 */ SetRegisterAllowed(MC_CLIENT_HOTRESET_CTRL_1); /* 0x970 */ SetRegisterAllowed(MC_CLIENT_HOTRESET_STATUS_1); /* 0x974 */ SetRegisterAllowed(MC_SMMU_PTC_FLUSH_1); /* 0x9B8 */ SetRegisterAllowed(MC_SMMU_DC1_ASID); /* 0xA88 */ SetRegisterAllowed(MC_SMMU_SDMMC1A_ASID); /* 0xA94 */ SetRegisterAllowed(MC_SMMU_SDMMC2A_ASID); /* 0xA98 */ SetRegisterAllowed(MC_SMMU_SDMMC3A_ASID); /* 0xA9C */ SetRegisterAllowed(MC_SMMU_SDMMC4A_ASID); /* 0xAA0 */ SetRegisterAllowed(MC_SMMU_ISP2B_ASID); /* 0xAA4 */ SetRegisterAllowed(MC_SMMU_GPU_ASID); /* 0xAA8 */ SetRegisterAllowed(MC_SMMU_GPUB_ASID); /* 0xAAC */ SetRegisterAllowed(MC_SMMU_PPCS2_ASID); /* 0xAB0 */ SetRegisterAllowed(MC_SMMU_NVDEC_ASID); /* 0xAB4 */ SetRegisterAllowed(MC_SMMU_APE_ASID); /* 0xAB8 */ SetRegisterAllowed(MC_SMMU_SE_ASID); /* 0xABC */ SetRegisterAllowed(MC_SMMU_NVJPG_ASID); /* 0xAC0 */ SetRegisterAllowed(MC_SMMU_HC1_ASID); /* 0xAC4 */ SetRegisterAllowed(MC_SMMU_SE1_ASID); /* 0xAC8 */ SetRegisterAllowed(MC_SMMU_AXIAP_ASID); /* 0xACC */ SetRegisterAllowed(MC_SMMU_ETR_ASID); /* 0xAD0 */ SetRegisterAllowed(MC_SMMU_TSECB_ASID); /* 0xAD4 */ SetRegisterAllowed(MC_SMMU_TSEC1_ASID); /* 0xAD8 */ SetRegisterAllowed(MC_SMMU_TSECB1_ASID); /* 0xADC */ SetRegisterAllowed(MC_SMMU_NVDEC1_ASID); /* 0xAE0 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_CTRL); /* 0xBCC */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0); /* 0xBD0 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1); /* 0xBD4 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2); /* 0xBD8 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3); /* 0xBDC */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4); /* 0xBE0 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5); /* 0xBE4 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6); /* 0xBE8 */ SetRegisterAllowed(MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7); /* 0xBEC */ SetRegisterAllowed(MC_ERR_GENERALIZED_CARVEOUT_STATUS); /* 0xC00 */ SetRegisterAllowed(MC_SECURITY_CARVEOUT2_BOM); /* 0xC5C */ SetRegisterAllowed(MC_SECURITY_CARVEOUT3_BOM); /* 0xCAC */ ================================================ FILE: exosphere/program/source/smc/secmon_pmc_access_table_data.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ SetRegisterAllowed(APBDEV_PMC_CNTRL); /* 0x000 */ SetRegisterAllowed(APBDEV_PMC_WAKE_MASK); /* 0x00C */ SetRegisterAllowed(APBDEV_PMC_WAKE_LVL); /* 0x010 */ SetRegisterAllowed(APBDEV_PMC_WAKE_STATUS); /* 0x014 */ SetRegisterAllowed(APBDEV_PMC_DPD_PADS_ORIDE); /* 0x01C */ SetRegisterAllowed(APBDEV_PMC_DPD_SAMPLE); /* 0x020 */ SetRegisterAllowed(APBDEV_PMC_CLAMP_STATUS); /* 0x02C */ SetRegisterAllowed(APBDEV_PMC_PWRGATE_TOGGLE); /* 0x030 */ SetRegisterAllowed(APBDEV_PMC_REMOVE_CLAMPING_CMD ); /* 0x034 */ SetRegisterAllowed(APBDEV_PMC_PWRGATE_STATUS); /* 0x038 */ SetRegisterAllowed(APBDEV_PMC_PWRGOOD_TIMER); /* 0x03C */ SetRegisterAllowed(APBDEV_PMC_BLINK_TIMER); /* 0x040 */ SetRegisterAllowed(APBDEV_PMC_NO_IOPOWER); /* 0x044 */ SetRegisterAllowed(APBDEV_PMC_PWR_DET); /* 0x048 */ SetRegisterAllowed(APBDEV_PMC_AUTO_WAKE_LVL_MASK); /* 0x0DC */ SetRegisterAllowed(APBDEV_PMC_WAKE_DELAY); /* 0x0E0 */ SetRegisterAllowed(APBDEV_PMC_PWR_DET_VAL); /* 0x0E4 */ SetRegisterAllowed(APBDEV_PMC_WAKE2_MASK); /* 0x160 */ SetRegisterAllowed(APBDEV_PMC_WAKE2_LVL); /* 0x164 */ SetRegisterAllowed(APBDEV_PMC_WAKE2_STATUS); /* 0x168 */ SetRegisterAllowed(APBDEV_PMC_AUTO_WAKE2_LVL_MASK ); /* 0x170 */ SetRegisterAllowed(APBDEV_PMC_CLK_OUT_CNTRL); /* 0x1A8 */ SetRegisterAllowed(APBDEV_PMC_IO_DPD_REQ); /* 0x1B8 */ SetRegisterAllowed(APBDEV_PMC_IO_DPD_STATUS); /* 0x1BC */ SetRegisterAllowed(APBDEV_PMC_IO_DPD2_REQ); /* 0x1C0 */ SetRegisterAllowed(APBDEV_PMC_IO_DPD2_STATUS); /* 0x1C4 */ SetRegisterAllowed(APBDEV_PMC_SEL_DPD_TIM); /* 0x1C8 */ SetRegisterAllowed(APBDEV_PMC_TSC_MULT); /* 0x2B4 */ SetRegisterAllowed(APBDEV_PMC_GPU_RG_CNTRL); /* 0x2D4 */ SetRegisterAllowed(APBDEV_PMC_CNTRL2); /* 0x440 */ SetRegisterAllowed(APBDEV_PMC_WAKE_DEBOUNCE_EN); /* 0x4D8 */ ================================================ FILE: exosphere/program/source/smc/secmon_random_cache.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "secmon_smc_common.hpp" #include "secmon_random_cache.hpp" namespace ams::secmon::smc { namespace { constinit int g_random_offset_low = 0; constinit int g_random_offset_high = 0; void FillRandomCache(int offset, int size) { /* Get the cache. */ u8 * const random_cache_loc = GetRandomBytesCache() + offset; /* Flush the region we're about to fill to ensure consistency with the SE. */ hw::FlushDataCache(random_cache_loc, size); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes. */ se::GenerateRandomBytes(random_cache_loc, size); hw::DataSynchronizationBarrierInnerShareable(); /* Flush to ensure the CPU sees consistent data for the region. */ hw::FlushDataCache(random_cache_loc, size); hw::DataSynchronizationBarrierInnerShareable(); } } void FillRandomCache() { /* Fill the cache. */ FillRandomCache(0, GetRandomBytesCacheSize()); /* Set the extents. */ g_random_offset_low = 0; g_random_offset_high = GetRandomBytesCacheSize() - 1; } void RefillRandomCache() { /* Check that we need to do any refilling. */ if (const int used_start = (g_random_offset_high + 1) % GetRandomBytesCacheSize(); used_start != g_random_offset_low) { if (used_start < g_random_offset_low) { /* The region we need to fill is after used_start but before g_random_offset_low. */ const auto size = g_random_offset_low - used_start; FillRandomCache(used_start, size); g_random_offset_high += size; } else { /* We need to fill the space from high to the end and from low to start. */ const int high_size = GetRandomBytesCacheSize() - used_start; if (high_size > 0) { FillRandomCache(used_start, high_size); g_random_offset_high += high_size; } const int low_size = g_random_offset_low; if (low_size > 0) { FillRandomCache(0, low_size); g_random_offset_high += low_size; } } g_random_offset_high %= GetRandomBytesCacheSize(); } } void GetRandomFromCache(void *dst, size_t size) { /* Copy out the requested size. */ std::memcpy(dst, GetRandomBytesCache() + g_random_offset_low, size); /* Advance. */ g_random_offset_low += size; /* Ensure that at all times g_random_offset_low is not within 0x38 bytes of the end of the pool. */ if (g_random_offset_low + MaxRandomBytes >= GetRandomBytesCacheSize()) { g_random_offset_low = 0; } } } ================================================ FILE: exosphere/program/source/smc/secmon_random_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { constexpr inline size_t MaxRandomBytes = sizeof(SmcArguments) - sizeof(SmcArguments{}.r[0]); void FillRandomCache(); void RefillRandomCache(); void GetRandomFromCache(void *dst, size_t size); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_aes.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_key_storage.hpp" #include "../secmon_misc.hpp" #include "../secmon_page_mapper.hpp" #include "secmon_smc_aes.hpp" #include "secmon_smc_device_unique_data.hpp" #include "secmon_smc_se_lock.hpp" namespace ams::secmon::smc { namespace { constexpr inline auto AesKeySize = se::AesBlockSize; constexpr inline size_t CmacSizeMax = 1_KB; constexpr inline size_t DeviceUniqueDataSizeMin = 0x130; constexpr inline size_t DeviceUniqueDataSizeMax = 0x240; enum SealKey { SealKey_LoadAesKey = 0, SealKey_DecryptDeviceUniqueData = 1, SealKey_ImportLotusKey = 2, SealKey_ImportEsDeviceKey = 3, SealKey_ReencryptDeviceUniqueData = 4, SealKey_ImportSslKey = 5, SealKey_ImportEsClientCertKey = 6, SealKey_Count, }; enum KeyType { KeyType_Default = 0, KeyType_NormalOnly = 1, KeyType_RecoveryOnly = 2, KeyType_NormalAndRecovery = 3, KeyType_Count, }; enum CipherMode { CipherMode_CbcEncryption = 0, CipherMode_CbcDecryption = 1, CipherMode_Ctr = 2, CipherMode_Cmac = 3, }; enum SpecificAesKey { SpecificAesKey_CalibrationEncryption0 = 0, SpecificAesKey_CalibrationEncryption1 = 1, SpecificAesKey_Count, }; enum DeviceUniqueData { DeviceUniqueData_DecryptDeviceUniqueData = 0, DeviceUniqueData_ImportLotusKey = 1, DeviceUniqueData_ImportEsDeviceKey = 2, DeviceUniqueData_ImportSslKey = 3, DeviceUniqueData_ImportEsClientCertKey = 4, DeviceUniqueData_Count, }; /* Ensure that our "subtract one" simplification is valid for the cases we care about. */ static_assert(DeviceUniqueData_ImportLotusKey - 1 == ImportRsaKey_Lotus); static_assert(DeviceUniqueData_ImportEsDeviceKey - 1 == ImportRsaKey_EsDrmCert); static_assert(DeviceUniqueData_ImportSslKey - 1 == ImportRsaKey_Ssl); static_assert(DeviceUniqueData_ImportEsClientCertKey - 1 == ImportRsaKey_EsClientCert); constexpr ImportRsaKey ConvertToImportRsaKey(DeviceUniqueData data) { /* Not necessary, but if this is invoked at compile-time this will force a compile-time error. */ AMS_ASSUME(data != DeviceUniqueData_DecryptDeviceUniqueData); AMS_ASSUME(data < DeviceUniqueData_Count); return static_cast<ImportRsaKey>(static_cast<int>(data) - 1); } enum SecureData { SecureData_Calibration = 0, SecureData_SafeMode = 1, SecureData_UserSystemProperEncryption = 2, SecureData_UserSystem = 3, SecureData_Count, }; struct GenerateAesKekOption { using IsDeviceUnique = util::BitPack32::Field<0, 1, bool>; using KeyTypeIndex = util::BitPack32::Field<1, 4, KeyType>; using SealKeyIndex = util::BitPack32::Field<5, 3, SealKey>; using Reserved = util::BitPack32::Field<8, 24, u32>; }; struct ComputeAesOption { using KeySlot = util::BitPack32::Field<0, 3, int>; using CipherModeIndex = util::BitPack32::Field<4, 2, CipherMode>; }; struct DecryptDeviceUniqueDataOption { using DeviceUniqueDataIndex = util::BitPack32::Field<0, 3, DeviceUniqueData>; using Reserved = util::BitPack32::Field<3, 29, u32>; /* Legacy. */ using EnforceDeviceUnique = util::BitPack32::Field<0, 1, bool>; }; constexpr const u8 SealKeySources[SealKey_Count][AesKeySize] = { [SealKey_LoadAesKey] = { 0xF4, 0x0C, 0x16, 0x26, 0x0D, 0x46, 0x3B, 0xE0, 0x8C, 0x6A, 0x56, 0xE5, 0x82, 0xD4, 0x1B, 0xF6 }, [SealKey_DecryptDeviceUniqueData] = { 0x7F, 0x54, 0x2C, 0x98, 0x1E, 0x54, 0x18, 0x3B, 0xBA, 0x63, 0xBD, 0x4C, 0x13, 0x5B, 0xF1, 0x06 }, [SealKey_ImportLotusKey] = { 0xC7, 0x3F, 0x73, 0x60, 0xB7, 0xB9, 0x9D, 0x74, 0x0A, 0xF8, 0x35, 0x60, 0x1A, 0x18, 0x74, 0x63 }, [SealKey_ImportEsDeviceKey] = { 0x0E, 0xE0, 0xC4, 0x33, 0x82, 0x66, 0xE8, 0x08, 0x39, 0x13, 0x41, 0x7D, 0x04, 0x64, 0x2B, 0x6D }, [SealKey_ReencryptDeviceUniqueData] = { 0xE1, 0xA8, 0xAA, 0x6A, 0x2D, 0x9C, 0xDE, 0x43, 0x0C, 0xDE, 0xC6, 0x17, 0xF6, 0xC7, 0xF1, 0xDE }, [SealKey_ImportSslKey] = { 0x74, 0x20, 0xF6, 0x46, 0x77, 0xB0, 0x59, 0x2C, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9 }, [SealKey_ImportEsClientCertKey] = { 0xAA, 0x19, 0x0F, 0xFA, 0x4C, 0x30, 0x3B, 0x2E, 0xE6, 0xD8, 0x9A, 0xCF, 0xE5, 0x3F, 0xB3, 0x4B }, }; constexpr const u8 KeyTypeSources[KeyType_Count][AesKeySize] = { [KeyType_Default] = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 }, [KeyType_NormalOnly] = { 0x25, 0x03, 0x31, 0xFB, 0x25, 0x26, 0x0B, 0x79, 0x8C, 0x80, 0xD2, 0x69, 0x98, 0xE2, 0x22, 0x77 }, [KeyType_RecoveryOnly] = { 0x76, 0x14, 0x1D, 0x34, 0x93, 0x2D, 0xE1, 0x84, 0x24, 0x7B, 0x66, 0x65, 0x55, 0x04, 0x65, 0x81 }, [KeyType_NormalAndRecovery] = { 0xAF, 0x3D, 0xB7, 0xF3, 0x08, 0xA2, 0xD8, 0xA2, 0x08, 0xCA, 0x18, 0xA8, 0x69, 0x46, 0xC9, 0x0B }, }; constexpr const u8 SealKeyMasks[SealKey_Count][AesKeySize] = { [SealKey_LoadAesKey] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, [SealKey_DecryptDeviceUniqueData] = { 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74 }, [SealKey_ImportLotusKey] = { 0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C }, [SealKey_ImportEsDeviceKey] = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB }, [SealKey_ReencryptDeviceUniqueData] = { 0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31 }, [SealKey_ImportSslKey] = { 0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75 }, [SealKey_ImportEsClientCertKey] = { 0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61 }, }; constexpr const SealKey DeviceUniqueDataToSealKey[DeviceUniqueData_Count] = { [DeviceUniqueData_DecryptDeviceUniqueData] = SealKey_DecryptDeviceUniqueData, [DeviceUniqueData_ImportLotusKey] = SealKey_ImportLotusKey, [DeviceUniqueData_ImportEsDeviceKey] = SealKey_ImportEsDeviceKey, [DeviceUniqueData_ImportSslKey] = SealKey_ImportSslKey, [DeviceUniqueData_ImportEsClientCertKey] = SealKey_ImportEsClientCertKey, }; constexpr const u8 CalibrationKeySource[AesKeySize] = { 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95 }; constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = { [EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B }, [EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D }, [EsCommonKeyType_Unknown2] = { 0x42, 0x64, 0x0B, 0xE3, 0x5F, 0xC6, 0xBE, 0x47, 0xC7, 0xB4, 0x84, 0xC5, 0xEB, 0x63, 0xAA, 0x02 }, }; constexpr const u8 EsSealKeySource[AesKeySize] = { 0xCB, 0xB7, 0x6E, 0x38, 0xA1, 0xCB, 0x77, 0x0F, 0xB2, 0xA5, 0xB2, 0x9D, 0xD8, 0x56, 0x9F, 0x76 }; constexpr const u8 SecureDataSource[AesKeySize] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; constexpr const u8 SecureDataCounters[][AesKeySize] = { [SecureData_Calibration] = { 0x3C, 0xD5, 0x92, 0xEC, 0x68, 0x31, 0x4A, 0x06, 0xD4, 0x1B, 0x0C, 0xD9, 0xF6, 0x2E, 0xD9, 0xE9 }, [SecureData_SafeMode] = { 0x50, 0x81, 0xCF, 0x77, 0x18, 0x11, 0xD7, 0x0D, 0x13, 0x29, 0x60, 0xED, 0x4B, 0x21, 0x3E, 0xFC }, [SecureData_UserSystemProperEncryption] = { 0x98, 0xCB, 0x4C, 0xEB, 0x15, 0xF1, 0x4A, 0x5A, 0x7A, 0x86, 0xB6, 0xF1, 0x94, 0x66, 0xF4, 0x9D }, }; constexpr const u8 SecureDataTweaks[][AesKeySize] = { [SecureData_Calibration] = { 0xAC, 0xCA, 0x9A, 0xCA, 0xFF, 0x2E, 0xB9, 0x22, 0xCC, 0x1F, 0x4F, 0xAD, 0xDD, 0x77, 0x21, 0x1E }, [SecureData_SafeMode] = { 0x6E, 0xF8, 0x2A, 0x1A, 0xE0, 0x4F, 0xC3, 0x20, 0x08, 0x7B, 0xBA, 0x50, 0xC0, 0xCD, 0x7B, 0x39 }, [SecureData_UserSystemProperEncryption] = { 0x6D, 0x02, 0x56, 0x2D, 0xF4, 0x3D, 0x0A, 0x15, 0xB1, 0x34, 0x5C, 0xC2, 0x84, 0x4C, 0xD4, 0x28 }, }; constexpr const u8 *GetSecureDataCounter(SecureData which) { switch (which) { case SecureData_Calibration: return SecureDataCounters[SecureData_Calibration]; case SecureData_SafeMode: return SecureDataCounters[SecureData_SafeMode]; case SecureData_UserSystem: case SecureData_UserSystemProperEncryption: return SecureDataCounters[SecureData_UserSystemProperEncryption]; default: return nullptr; } } constexpr const u8 *GetSecureDataTweak(SecureData which) { switch (which) { case SecureData_Calibration: return SecureDataTweaks[SecureData_Calibration]; case SecureData_SafeMode: return SecureDataTweaks[SecureData_SafeMode]; case SecureData_UserSystem: case SecureData_UserSystemProperEncryption: return SecureDataTweaks[SecureData_UserSystemProperEncryption]; default: return nullptr; } } constexpr uintptr_t LinkedListAddressMinimum = secmon::MemoryRegionDram.GetAddress(); constexpr size_t LinkedListAddressRangeSize = 4_MB - 2_KB; constexpr uintptr_t LinkedListAddressMaximum = LinkedListAddressMinimum + LinkedListAddressRangeSize; constexpr size_t LinkedListSize = 12; constexpr bool IsValidLinkedListAddress(uintptr_t address) { return LinkedListAddressMinimum <= address && address <= (LinkedListAddressMaximum - LinkedListSize); } constinit bool g_is_compute_aes_completed = false; void SecurityEngineDoneHandler() { /* Check that the compute succeeded. */ se::ValidateAesOperationResult(); /* End the asynchronous operation. */ g_is_compute_aes_completed = true; EndAsyncOperation(); } SmcResult GetComputeAesResult(void *dst, size_t size) { /* Arguments are unused. */ AMS_UNUSED(dst); AMS_UNUSED(size); /* Check that the operation is completed. */ SMC_R_UNLESS(g_is_compute_aes_completed, Busy); /* Unlock the security engine and succeed. */ UnlockSecurityEngine(); return SmcResult::Success; } int PrepareMasterKey(int generation) { if (generation == GetKeyGeneration()) { return pkg1::AesKeySlot_Master; } constexpr int Slot = pkg1::AesKeySlot_Smc; LoadMasterKey(Slot, generation); return Slot; } int PrepareDeviceMasterKey(int generation) { if (generation == pkg1::KeyGeneration_1_0_0 && GetSocType() == fuse::SocType_Erista) { return pkg1::AesKeySlot_Device; } if (generation == GetKeyGeneration()) { return pkg1::AesKeySlot_DeviceMaster; } constexpr int Slot = pkg1::AesKeySlot_Smc; LoadDeviceMasterKey(Slot, generation); return Slot; } void GetSecureDataImpl(u8 *dst, SecureData which, bool tweak) { /* Compute the appropriate AES-CTR. */ { /* Ensure that the SE sees consistent data. */ hw::FlushDataCache(dst, AesKeySize); hw::DataSynchronizationBarrierInnerShareable(); /* Perform the appropriate AES operation. */ se::ComputeAes128Ctr(dst, AesKeySize, pkg1::AesKeySlot_Device, SecureDataSource, AesKeySize, GetSecureDataCounter(which), AesKeySize); hw::DataSynchronizationBarrierInnerShareable(); /* Ensure the CPU sees consistent data. */ hw::FlushDataCache(dst, AesKeySize); hw::DataSynchronizationBarrierInnerShareable(); } /* Tweak, if we should. */ if (tweak) { const u8 * const tweak = GetSecureDataTweak(which); for (size_t i = 0; i < AesKeySize; ++i) { dst[i] ^= tweak[i]; } } } SmcResult GenerateAesKekImpl(SmcArguments &args) { /* Decode arguments. */ u8 kek_source[AesKeySize]; std::memcpy(kek_source, std::addressof(args.r[1]), AesKeySize); const int generation = std::max<int>(static_cast<int>(args.r[3]) - 1, pkg1::KeyGeneration_1_0_0); const util::BitPack32 option = { static_cast<u32>(args.r[4]) }; const bool is_device_unique = option.Get<GenerateAesKekOption::IsDeviceUnique>(); const auto key_type = option.Get<GenerateAesKekOption::KeyTypeIndex>(); const auto seal_key = option.Get<GenerateAesKekOption::SealKeyIndex>(); const u32 reserved = option.Get<GenerateAesKekOption::Reserved>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); if (is_device_unique) { SMC_R_UNLESS(pkg1::IsValidDeviceUniqueKeyGeneration(generation), InvalidArgument); } else { SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument); SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument); } SMC_R_UNLESS(0 <= key_type && key_type < KeyType_Count, InvalidArgument); SMC_R_UNLESS(0 <= seal_key && seal_key < SealKey_Count, InvalidArgument); switch (key_type) { case KeyType_NormalOnly: SMC_R_UNLESS(!IsRecoveryBoot(), InvalidArgument); break; case KeyType_RecoveryOnly: SMC_R_UNLESS( IsRecoveryBoot(), InvalidArgument); break; default: break; } /* Declare temporary data storage. */ u8 static_source[AesKeySize]; u8 generated_key[AesKeySize]; u8 access_key[AesKeySize]; /* Derive the static source. */ for (size_t i = 0; i < sizeof(static_source); ++i) { static_source[i] = KeyTypeSources[key_type][i] ^ SealKeyMasks[seal_key][i]; } /* Get the seal key source. */ const u8 * const seal_key_source = SealKeySources[seal_key]; /* Get the key slot. */ const int slot = is_device_unique ? PrepareDeviceMasterKey(generation) : PrepareMasterKey(generation); /* Derive a static generation kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, static_source, sizeof(static_source)); /* Decrypt the input with the static generation kek. */ se::DecryptAes128(generated_key, sizeof(generated_key), pkg1::AesKeySlot_Smc, kek_source, sizeof(kek_source)); /* Generate the seal key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, seal_key_source, AesKeySize); /* Seal the generated key. */ se::EncryptAes128(access_key, sizeof(access_key), pkg1::AesKeySlot_Smc, generated_key, sizeof(generated_key)); /* Copy the access key out. */ std::memcpy(std::addressof(args.r[1]), access_key, sizeof(access_key)); return SmcResult::Success; } SmcResult LoadAesKeyImpl(SmcArguments &args) { /* Decode arguments. */ const int slot = args.r[1]; u8 access_key[AesKeySize]; std::memcpy(access_key, std::addressof(args.r[2]), sizeof(access_key)); u8 key_source[AesKeySize]; std::memcpy(key_source, std::addressof(args.r[4]), sizeof(key_source)); /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument); /* Get the seal key source. */ constexpr const u8 * const SealKeySource = SealKeySources[SealKey_LoadAesKey]; /* Derive the seal key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, SealKeySource, AesKeySize); /* Unseal the access key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, access_key, sizeof(access_key)); /* Derive the key. */ se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_Smc, key_source, sizeof(key_source)); return SmcResult::Success; } SmcResult ComputeAesImpl(SmcArguments &args) { /* Decode arguments. */ u8 iv[se::AesBlockSize]; const util::BitPack32 option = { static_cast<u32>(args.r[1]) }; std::memcpy(iv, std::addressof(args.r[2]), sizeof(iv)); const u32 input_address = args.r[4]; const u32 output_address = args.r[5]; const u32 size = args.r[6]; const int slot = option.Get<ComputeAesOption::KeySlot>(); const auto cipher_mode = option.Get<ComputeAesOption::CipherModeIndex>(); /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument); SMC_R_UNLESS(util::IsAligned(size, se::AesBlockSize), InvalidArgument); SMC_R_UNLESS(IsValidLinkedListAddress(input_address), InvalidArgument); SMC_R_UNLESS(IsValidLinkedListAddress(output_address), InvalidArgument); /* We're starting an aes operation, so reset the completion status. */ g_is_compute_aes_completed = false; /* Dispatch the correct aes operation asynchronously. */ switch (cipher_mode) { case CipherMode_CbcEncryption: se::EncryptAes128CbcAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break; case CipherMode_CbcDecryption: se::DecryptAes128CbcAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break; case CipherMode_Ctr: se::ComputeAes128CtrAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break; case CipherMode_Cmac: return SmcResult::NotSupported; default: return SmcResult::InvalidArgument; } return SmcResult::Success; } SmcResult GenerateSpecificAesKeyImpl(SmcArguments &args) { /* Decode arguments. */ u8 key_source[AesKeySize]; std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source)); const int generation = GetTargetFirmware() >= TargetFirmware_4_0_0 ? std::max<int>(static_cast<int>(args.r[3]) - 1, pkg1::KeyGeneration_1_0_0) : pkg1::KeyGeneration_1_0_0; const auto which = static_cast<SpecificAesKey>(args.r[4]); /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument); SMC_R_UNLESS(which < SpecificAesKey_Count, InvalidArgument); /* Generate the specific aes key. */ u8 output_key[AesKeySize]; if (fuse::GetPatchVersion() >= fuse::PatchVersion_Odnx02A2) { const int slot = PrepareDeviceMasterKey(generation); se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, CalibrationKeySource, sizeof(CalibrationKeySource)); se::DecryptAes128(output_key, sizeof(output_key), pkg1::AesKeySlot_Smc, key_source, sizeof(key_source)); } else { GetSecureDataImpl(output_key, SecureData_Calibration, which == SpecificAesKey_CalibrationEncryption1); } /* Copy the key to output. */ std::memcpy(std::addressof(args.r[1]), output_key, sizeof(output_key)); return SmcResult::Success; } SmcResult ComputeCmacImpl(SmcArguments &args) { /* Decode arguments. */ const int slot = args.r[1]; const uintptr_t data_address = args.r[2]; const size_t data_size = args.r[3]; /* Declare buffer for user data. */ alignas(8) u8 user_data[CmacSizeMax]; /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument); SMC_R_UNLESS(data_size <= sizeof(user_data), InvalidArgument); /* Map the user data, and copy to stack. */ { UserPageMapper mapper(data_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(user_data, data_address, data_size), InvalidArgument); } /* Ensure the SE sees consistent data. */ hw::FlushDataCache(user_data, data_size); hw::DataSynchronizationBarrierInnerShareable(); /* Compute the mac. */ { u8 mac[se::AesBlockSize]; se::ComputeAes128Cmac(mac, sizeof(mac), slot, user_data, data_size); std::memcpy(std::addressof(args.r[1]), mac, sizeof(mac)); } return SmcResult::Success; } SmcResult LoadPreparedAesKeyImpl(SmcArguments &args) { /* Decode arguments. */ u8 access_key[AesKeySize]; const int slot = args.r[1]; std::memcpy(access_key, std::addressof(args.r[2]), sizeof(access_key)); /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument); /* Derive the seal key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource)); /* Unseal the key. */ se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_Smc, access_key, sizeof(access_key)); return SmcResult::Success; } SmcResult PrepareEsCommonTitleKeyImpl(SmcArguments &args) { /* Declare variables. */ u8 key_source[se::AesBlockSize]; u8 key[se::AesBlockSize]; u8 access_key[se::AesBlockSize]; /* Decode arguments. */ std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source)); const int generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, static_cast<int>(args.r[3]) - 1) : pkg1::KeyGeneration_1_0_0; /* Validate arguments. */ SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument); SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument); /* Derive the key. */ DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), EsCommonKeyType_TitleKey, generation); /* Prepare the aes key. */ PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key)); /* Copy the access key to output. */ std::memcpy(std::addressof(args.r[1]), access_key, sizeof(access_key)); return SmcResult::Success; } constexpr size_t GetDiscountedMinimumDeviceUniqueDataSize(bool enforce_device_unique) { if (enforce_device_unique) { return 0; } else { return DeviceUniqueDataTotalMetaSize - DeviceUniqueDataIvSize; } } SmcResult ValidateDeviceUniqueDataSize(DeviceUniqueData mode, size_t data_size, bool enforce_device_unique) { /* Determine the discounted size towards the minimum. */ const size_t discounted_size = GetDiscountedMinimumDeviceUniqueDataSize(enforce_device_unique); SMC_R_UNLESS(enforce_device_unique || fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, InvalidArgument); switch (mode) { case DeviceUniqueData_DecryptDeviceUniqueData: { SMC_R_UNLESS(DeviceUniqueDataTotalMetaSize - discounted_size < data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument); } break; case DeviceUniqueData_ImportLotusKey: case DeviceUniqueData_ImportEsDeviceKey: case DeviceUniqueData_ImportSslKey: case DeviceUniqueData_ImportEsClientCertKey: { SMC_R_UNLESS(DeviceUniqueDataSizeMin - discounted_size <= data_size && data_size <= DeviceUniqueDataSizeMax, InvalidArgument); } break; default: return SmcResult::InvalidArgument; } return SmcResult::Success; } SmcResult DecryptDeviceUniqueDataImpl(const u8 *access_key, const u8 *key_source, const DeviceUniqueData mode, const uintptr_t data_address, const size_t data_size, bool enforce_device_unique) { /* Validate arguments. */ SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique)); /* Decrypt the device unique data. */ alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax]; ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); }; { /* Map and copy in the encrypted data. */ UserPageMapper mapper(data_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(work_buffer, data_address, data_size), InvalidArgument); /* Determine the seal key to use. */ const auto seal_key_type = DeviceUniqueDataToSealKey[mode]; const u8 * const seal_key_source = SealKeySources[seal_key_type]; /* Decrypt the data. */ if (!DecryptDeviceUniqueData(work_buffer, data_size, nullptr, seal_key_source, se::AesBlockSize, access_key, se::AesBlockSize, key_source, se::AesBlockSize, work_buffer, data_size, enforce_device_unique)) { return SmcResult::InvalidArgument; } /* Either output the key, or import it. */ switch (mode) { case DeviceUniqueData_DecryptDeviceUniqueData: { SMC_R_UNLESS(mapper.CopyToUser(data_address, work_buffer, data_size), InvalidArgument); } break; case DeviceUniqueData_ImportLotusKey: case DeviceUniqueData_ImportSslKey: ImportRsaKeyExponent(ConvertToImportRsaKey(mode), work_buffer, se::RsaSize); break; case DeviceUniqueData_ImportEsDeviceKey: case DeviceUniqueData_ImportEsClientCertKey: ImportRsaKeyExponent(ConvertToImportRsaKey(mode), work_buffer, se::RsaSize); ImportRsaKeyModulusProvisionally(ConvertToImportRsaKey(mode), work_buffer + se::RsaSize, se::RsaSize); CommitRsaKeyModulus(ConvertToImportRsaKey(mode)); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } return SmcResult::Success; } SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) { /* Decode arguments. */ u8 access_key[se::AesBlockSize]; u8 key_source[se::AesBlockSize]; std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key)); const util::BitPack32 option = { static_cast<u32>(args.r[3]) }; const uintptr_t data_address = args.r[4]; const size_t data_size = args.r[5]; std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source)); const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>() : DeviceUniqueData_DecryptDeviceUniqueData; const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>(); const bool enforce_device_unique = GetTargetFirmware() >= TargetFirmware_5_0_0 ? true : option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); /* Decrypt the device unique data. */ return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique); } SmcResult DecryptAndImportEsDeviceKeyImpl(SmcArguments &args) { /* Decode arguments. */ u8 access_key[se::AesBlockSize]; u8 key_source[se::AesBlockSize]; std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key)); const util::BitPack32 option = { static_cast<u32>(args.r[3]) }; const uintptr_t data_address = args.r[4]; const size_t data_size = args.r[5]; std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source)); const auto mode = DeviceUniqueData_ImportEsDeviceKey; const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>(); const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); /* Ensure that the key is exactly the correct size. */ if (enforce_device_unique) { SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataTotalMetaSize, InvalidArgument); } else { SMC_R_UNLESS(data_size == util::AlignUp(2 * se::RsaSize + sizeof(u32), se::AesBlockSize) + DeviceUniqueDataIvSize, InvalidArgument); } /* Decrypt the device unique data. */ return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique); } SmcResult DecryptAndImportLotusKeyImpl(SmcArguments &args) { /* Decode arguments. */ u8 access_key[se::AesBlockSize]; u8 key_source[se::AesBlockSize]; std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key)); const util::BitPack32 option = { static_cast<u32>(args.r[3]) }; const uintptr_t data_address = args.r[4]; const size_t data_size = args.r[5]; std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source)); const auto mode = DeviceUniqueData_ImportLotusKey; const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>(); const bool enforce_device_unique = option.Get<DecryptDeviceUniqueDataOption::EnforceDeviceUnique>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); /* Ensure that the key is exactly the correct size. */ if (enforce_device_unique) { SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataTotalMetaSize, InvalidArgument); } else { SMC_R_UNLESS(data_size == se::RsaSize + DeviceUniqueDataIvSize, InvalidArgument); } /* Decrypt the device unique data. */ return DecryptDeviceUniqueDataImpl(access_key, key_source, mode, data_address, data_size, enforce_device_unique); } SmcResult ReencryptDeviceUniqueDataImpl(SmcArguments &args) { /* Decode arguments. */ u8 access_key_dec[se::AesBlockSize]; u8 access_key_enc[se::AesBlockSize]; u8 key_source_dec[se::AesBlockSize]; u8 key_source_enc[se::AesBlockSize]; const uintptr_t access_key_dec_address = args.r[1]; const uintptr_t access_key_enc_address = args.r[2]; const util::BitPack32 option = { static_cast<u32>(args.r[3]) }; const uintptr_t data_address = args.r[4]; const size_t data_size = args.r[5]; const uintptr_t key_source_dec_address = args.r[6]; const uintptr_t key_source_enc_address = args.r[7]; const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>(); const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>(); const bool enforce_device_unique = true; /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size, enforce_device_unique)); /* Decrypt the device unique data. */ alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax]; ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); }; { /* Map and copy in the encrypted data. */ UserPageMapper mapper(data_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(work_buffer, data_address, data_size), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(access_key_dec, access_key_dec_address, sizeof(access_key_dec)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(access_key_enc, access_key_enc_address, sizeof(access_key_enc)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(key_source_dec, key_source_dec_address, sizeof(key_source_dec)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(key_source_enc, key_source_enc_address, sizeof(key_source_enc)), InvalidArgument); /* Decrypt the data. */ u8 device_id_high; { /* Determine the seal key to use. */ const u8 * const seal_key_source = SealKeySources[SealKey_ReencryptDeviceUniqueData]; if (!DecryptDeviceUniqueData(work_buffer, data_size, std::addressof(device_id_high), seal_key_source, se::AesBlockSize, access_key_dec, sizeof(access_key_dec), key_source_dec, sizeof(key_source_dec), work_buffer, data_size, enforce_device_unique)) { return SmcResult::InvalidArgument; } } /* Reencrypt the data. */ { /* Determine the seal key to use. */ const auto seal_key_type = DeviceUniqueDataToSealKey[mode]; const u8 * const seal_key_source = SealKeySources[seal_key_type]; /* Encrypt the data. */ EncryptDeviceUniqueData(work_buffer, data_size, seal_key_source, se::AesBlockSize, access_key_enc, sizeof(access_key_enc), key_source_enc, sizeof(key_source_enc), work_buffer, data_size - DeviceUniqueDataTotalMetaSize, device_id_high); } /* Copy the reencrypted data back to user. */ SMC_R_UNLESS(mapper.CopyToUser(data_address, work_buffer, data_size), InvalidArgument); } return SmcResult::Success; } SmcResult GetSecureDataImpl(SmcArguments &args) { /* Decode arguments. */ const auto which = static_cast<SecureData>(args.r[1]); /* Validate arguments/conditions. */ SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotSupported); SMC_R_UNLESS(which < SecureData_Count, NotSupported); /* Use a temporary buffer. */ u8 secure_data[AesKeySize]; GetSecureDataImpl(secure_data, which, false); /* Copy out. */ std::memcpy(std::addressof(args.r[1]), secure_data, sizeof(secure_data)); return SmcResult::Success; } } /* Aes functionality. */ SmcResult SmcGenerateAesKek(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, GenerateAesKekImpl); } SmcResult SmcLoadAesKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, LoadAesKeyImpl); } SmcResult SmcComputeAes(SmcArguments &args) { return LockSecurityEngineAndInvokeAsync(args, ComputeAesImpl, GetComputeAesResult); } SmcResult SmcGenerateSpecificAesKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, GenerateSpecificAesKeyImpl); } SmcResult SmcComputeCmac(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, ComputeCmacImpl); } SmcResult SmcLoadPreparedAesKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, LoadPreparedAesKeyImpl); } SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, PrepareEsCommonTitleKeyImpl); } /* Device unique data functionality. */ SmcResult SmcDecryptDeviceUniqueData(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, DecryptDeviceUniqueDataImpl); } SmcResult SmcReencryptDeviceUniqueData(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, ReencryptDeviceUniqueDataImpl); } /* Legacy APIs. */ SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, DecryptAndImportEsDeviceKeyImpl); } SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, DecryptAndImportLotusKeyImpl); } /* Es encryption utilities. */ void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation) { /* Validate pre-conditions. */ AMS_ABORT_UNLESS(dst_size == AesKeySize); AMS_ABORT_UNLESS(src_size == AesKeySize); AMS_ABORT_UNLESS(0 <= type && type < EsCommonKeyType_Count); /* Prepare the master key for the generation. */ const int slot = PrepareMasterKey(generation); /* Derive the es common key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, EsCommonKeySources[type], AesKeySize); /* Decrypt the input using the common key. */ se::DecryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size); } void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Validate pre-conditions. */ AMS_ABORT_UNLESS(dst_size == AesKeySize); AMS_ABORT_UNLESS(src_size == AesKeySize); /* Derive the seal key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource)); /* Seal the key. */ se::EncryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size); } /* 'Tis the last rose of summer, / Left blooming alone; */ /* Oh! who would inhabit / This bleak world alone? */ SmcResult SmcGetSecureData(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, GetSecureDataImpl); } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_aes.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { enum EsCommonKeyType { EsCommonKeyType_TitleKey = 0, EsCommonKeyType_ArchiveKey = 1, EsCommonKeyType_Unknown2 = 2, EsCommonKeyType_Count, }; /* General Aes functionality. */ SmcResult SmcGenerateAesKek(SmcArguments &args); SmcResult SmcLoadAesKey(SmcArguments &args); SmcResult SmcComputeAes(SmcArguments &args); SmcResult SmcGenerateSpecificAesKey(SmcArguments &args); SmcResult SmcComputeCmac(SmcArguments &args); SmcResult SmcLoadPreparedAesKey(SmcArguments &args); SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args); /* Device unique data functionality. */ SmcResult SmcDecryptDeviceUniqueData(SmcArguments &args); SmcResult SmcReencryptDeviceUniqueData(SmcArguments &args); /* Legacy device unique data functionality. */ SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args); SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args); /* Es encryption utilities. */ void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation); void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size); /* The last rose of summer. */ SmcResult SmcGetSecureData(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_carveout.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_setup.hpp" #include "secmon_smc_carveout.hpp" namespace ams::secmon::smc { SmcResult SmcSetKernelCarveoutRegion(SmcArguments &args) { /* Decode arguments. */ const int index = args.r[1]; const uintptr_t address = args.r[2]; const size_t size = args.r[3]; /* Validate arguments. */ SMC_R_UNLESS(0 <= index && index < KernelCarveoutCount, InvalidArgument); SMC_R_UNLESS(util::IsAligned(address, 128_KB), InvalidArgument); SMC_R_UNLESS(util::IsAligned(size, 128_KB), InvalidArgument); SMC_R_UNLESS(size <= CarveoutSizeMax, InvalidArgument); /* Set the carveout. */ SetKernelCarveoutRegion(index, address, size); return SmcResult::Success; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_carveout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { SmcResult SmcSetKernelCarveoutRegion(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::secmon::smc { enum class SmcResult : u32 { Success = 0, NotSupported = 1, InvalidArgument = 2, Busy = 3, NoAsyncOperation = 4, InvalidAsyncOperation = 5, NotPermitted = 6, NotInitialized = 7, PsciSuccess = 0, PsciNotSupported = static_cast<u32>(-1), PsciInvalidParameters = static_cast<u32>(-2), PsciDenied = static_cast<u32>(-3), PsciAlreadyOn = static_cast<u32>(-4), }; #define SMC_R_SUCCEEEDED(res) (res == SmcResult::Success) #define SMC_R_FAILED(res) (res != SmcResult::Success) #define SMC_R_TRY(res_expr) ({ const auto _tmp_r_try_rc = (res_expr); if (SMC_R_FAILED(_tmp_r_try_rc)) { return _tmp_r_try_rc; } }) #define SMC_R_UNLESS(cond, RES) ({ if (!(cond)) { return SmcResult::RES; }}) struct SmcArguments { u64 r[8]; }; constexpr inline int SecurityEngineUserInterruptId = 44; constexpr inline u64 InvalidAsyncKey = 0; } ================================================ FILE: exosphere/program/source/smc/secmon_smc_cpu_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ #define cpuactlr_el1 s3_1_c15_c2_0 #define cpuectlr_el1 s3_1_c15_c2_1 .section .text._ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE, "ax", %progbits .align 4 .global _ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE _ZN3ams6secmon3smc19PivotStackAndInvokeEPvPFvvE: /* Pivot to use the provided stack pointer. */ mov sp, x0 /* Release our lock on the common smc stack. */ mov x19, x1 bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv /* Invoke the function with the new stack. */ br x19 .section .text._ZN3ams6secmon3smc16FinalizePowerOffEv, "ax", %progbits .align 4 .global _ZN3ams6secmon3smc16FinalizePowerOffEv _ZN3ams6secmon3smc16FinalizePowerOffEv: /* Disable all caches by clearing sctlr_el1.C. */ mrs x0, sctlr_el1 and x0, x0, #~(1 << 2) msr sctlr_el1, x0 isb /* Disable all caches by clearing sctlr_el3.C. */ mrs x0, sctlr_el3 and x0, x0, #~(1 << 2) msr sctlr_el3, x0 isb /* Disable prefetching of page table walking descriptors. */ mrs x0, cpuectlr_el1 orr x0, x0, #(1 << 38) /* Disable prefetching of instructions. */ and x0, x0, #~(3 << 35) /* Disable prefetching of data. */ and x0, x0, #~(3 << 32) msr cpuectlr_el1, x0 isb /* Ensure that all data prefetching prior to our configuration change completes. */ dsb sy /* Flush the entire data cache (local). */ bl _ZN3ams6secmon25FlushEntireDataCacheLocalEv /* Disable receiving instruction cache/TLB maintenance operations. */ mrs x0, cpuectlr_el1 and x0, x0, #~(1 << 6) msr cpuectlr_el1, x0 /* Configure the gic to not send interrupts to the current core. */ ldr x1, =0x1F0043000 mov w0, #0x1E0 /* Set FIQBypDisGrp1, IRQBypDisGrp1, reserved bits 7/8. */ str w0, [x1] /* Lock the OS Double Lock. */ mrs x0, osdlr_el1 orr x0, x0, #(1 << 0) msr osdlr_el1, x0 /* Ensure that our configuration takes. */ isb dsb sy /* Wait for interrupts, infinitely. */ 0: wfi b 0b ================================================ FILE: exosphere/program/source/smc/secmon_smc_device_unique_data.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_smc_device_unique_data.hpp" namespace ams::secmon::smc { namespace { void GenerateIv(void *dst, size_t dst_size) { /* Flush the region we're about to fill to ensure consistency with the SE. */ hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes. */ se::GenerateRandomBytes(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); /* Flush to ensure the CPU sees consistent data for the region. */ hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); } void PrepareDeviceUniqueDataKey(const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size) { /* Derive the seal key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, seal_key_source, seal_key_source_size); /* Derive the device unique data kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, access_key, access_key_size); /* Derive the actual device unique data key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_Smc, key_source, key_source_size); } void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { /* Ensure that the SE sees consistent data. */ hw::FlushDataCache(src, src_size); hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); /* Use the security engine to transform the data. */ se::ComputeAes128Ctr(dst, dst_size, slot, src, src_size, iv, iv_size); hw::DataSynchronizationBarrierInnerShareable(); /* Ensure the CPU sees consistent data. */ hw::FlushDataCache(dst, dst_size); hw::DataSynchronizationBarrierInnerShareable(); } void ComputeGmac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *iv, size_t iv_size) { /* Declare keyslot (as encryptor will need to take it by pointer/reference). */ constexpr int Slot = pkg1::AesKeySlot_Smc; /* Calculate the mac. */ crypto::Aes128GcmEncryptor gcm; gcm.Initialize(std::addressof(Slot), sizeof(Slot), iv, iv_size); gcm.UpdateAad(data, data_size); gcm.GetMac(dst, dst_size); } constexpr u64 GetDeviceIdLow(u64 device_id) { /* Mask out the top byte. */ constexpr u64 ByteMask = (static_cast<u64>(1) << BITSIZEOF(u8)) - 1; constexpr u64 LowMask = ~(ByteMask << (BITSIZEOF(u64) - BITSIZEOF(u8))); return device_id & LowMask; } constexpr u8 GetDeviceIdHigh(u64 device_id) { /* Get the top byte. */ return static_cast<u8>(device_id >> (BITSIZEOF(u64) - BITSIZEOF(u8))); } constexpr u64 EncodeDeviceId(u8 device_id_high, u64 device_id_low) { return (static_cast<u64>(device_id_high) << (BITSIZEOF(u64) - BITSIZEOF(u8))) | device_id_low; } } bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique) { /* Determine how much decrypted data there will be. */ const size_t enc_size = src_size - (enforce_device_unique ? DeviceUniqueDataOuterMetaSize : DeviceUniqueDataIvSize); const size_t dec_size = enc_size - DeviceUniqueDataInnerMetaSize; /* Ensure that our sizes are allowed. */ AMS_ABORT_UNLESS(src_size > (enforce_device_unique ? DeviceUniqueDataTotalMetaSize : DeviceUniqueDataIvSize)); AMS_ABORT_UNLESS(dst_size >= enc_size); /* Determine the extents of the data. */ const u8 * const iv = static_cast<const u8 *>(src); const u8 * const enc = iv + DeviceUniqueDataIvSize; const u8 * const mac = enc + enc_size; /* Decrypt the data. */ { /* Declare temporaries. */ u8 temp_iv[DeviceUniqueDataIvSize]; u8 calc_mac[DeviceUniqueDataMacSize]; ON_SCOPE_EXIT { crypto::ClearMemory(temp_iv, sizeof(temp_iv)); crypto::ClearMemory(calc_mac, sizeof(calc_mac)); }; /* Prepare the key used to decrypt the data. */ PrepareDeviceUniqueDataKey(seal_key_source, seal_key_source_size, access_key, access_key_size, key_source, key_source_size); /* Copy the iv to stack. */ std::memcpy(temp_iv, iv, sizeof(temp_iv)); /* Decrypt the data. */ ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Smc, enc, enc_size, temp_iv, DeviceUniqueDataIvSize); /* If we're not enforcing device unique, there's no mac/device id. */ if (!enforce_device_unique) { return true; } /* Compute the gmac. */ ComputeGmac(calc_mac, DeviceUniqueDataMacSize, dst, enc_size, temp_iv, DeviceUniqueDataIvSize); /* Validate the gmac. */ if (!crypto::IsSameBytes(mac, calc_mac, sizeof(calc_mac))) { return false; } } /* Validate device id, output device id if needed. */ { /* Locate the device id in the decryption output. */ const u8 * const padding = static_cast<const u8 *>(dst) + dec_size; const u8 * const device_id = padding + DeviceUniqueDataPaddingSize; /* Load the big endian device id. */ const u64 device_id_val = util::LoadBigEndian(static_cast<const u64 *>(static_cast<const void *>(device_id))); /* Validate that the device id low matches the value in fuses. */ if (GetDeviceIdLow(device_id_val) != fuse::GetDeviceId()) { return false; } /* Set the output device id high, if needed. */ if (out_device_id_high != nullptr) { *out_device_id_high = GetDeviceIdHigh(device_id_val); } } return true; } void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high) { /* Determine metadata locations. */ u8 * const dst_iv = static_cast<u8 *>(dst); u8 * const dst_data = dst_iv + DeviceUniqueDataIvSize; u8 * const dst_pad = dst_data + src_size; u8 * const dst_did = dst_pad + DeviceUniqueDataPaddingSize; u8 * const dst_mac = dst_did + DeviceUniqueDataDeviceIdSize; /* Verify that our sizes are okay. */ const size_t enc_size = src_size + DeviceUniqueDataInnerMetaSize; const size_t res_size = src_size + DeviceUniqueDataTotalMetaSize; AMS_ABORT_UNLESS(res_size <= dst_size); /* Layout the image as expected. */ { /* Generate a random iv. */ util::AlignedBuffer<hw::DataCacheLineSize, DeviceUniqueDataIvSize> iv; GenerateIv(iv, DeviceUniqueDataIvSize); /* Move the data to the output image. */ std::memmove(dst_data, src, src_size); /* Copy the iv. */ std::memcpy(dst_iv, iv, DeviceUniqueDataIvSize); /* Clear the padding. */ std::memset(dst_pad, 0, DeviceUniqueDataPaddingSize); /* Store the device id. */ util::StoreBigEndian(reinterpret_cast<u64 *>(dst_did), EncodeDeviceId(device_id_high, fuse::GetDeviceId())); } /* Encrypt and mac. */ { /* Prepare the key used to encrypt the data. */ PrepareDeviceUniqueDataKey(seal_key_source, seal_key_source_size, access_key, access_key_size, key_source, key_source_size); /* Compute the gmac. */ ComputeGmac(dst_mac, DeviceUniqueDataMacSize, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize); /* Encrypt the data. */ ComputeAes128Ctr(dst_data, enc_size, pkg1::AesKeySlot_Smc, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize); } } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_device_unique_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { constexpr inline size_t DeviceUniqueDataIvSize = se::AesBlockSize; constexpr inline size_t DeviceUniqueDataMacSize = se::AesBlockSize; constexpr inline size_t DeviceUniqueDataDeviceIdSize = sizeof(u64); constexpr inline size_t DeviceUniqueDataPaddingSize = se::AesBlockSize - DeviceUniqueDataDeviceIdSize; constexpr inline size_t DeviceUniqueDataOuterMetaSize = DeviceUniqueDataIvSize + DeviceUniqueDataMacSize; constexpr inline size_t DeviceUniqueDataInnerMetaSize = DeviceUniqueDataPaddingSize + DeviceUniqueDataDeviceIdSize; constexpr inline size_t DeviceUniqueDataTotalMetaSize = DeviceUniqueDataOuterMetaSize + DeviceUniqueDataInnerMetaSize; bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, bool enforce_device_unique); void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_error.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_smc_error.hpp" namespace ams::secmon::smc { SmcResult SmcShowError(SmcArguments &args) { /* Decode arguments. */ const u32 r = ((args.r[1] >> 8) & 0xF); const u32 g = ((args.r[1] >> 4) & 0xF); const u32 b = ((args.r[1] >> 0) & 0xF); const u32 rgb = (b << 8) | (g << 4) | (r << 0); /* Set the error info. */ SetError(pkg1::MakeKernelPanicResetInfo(rgb)); /* Reboot. */ ErrorReboot(); /* This point will never be reached. */ __builtin_unreachable(); } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_error.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { SmcResult SmcShowError(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_handler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_misc.hpp" #include "secmon_smc_common.hpp" #include "secmon_smc_handler.hpp" #include "secmon_smc_aes.hpp" #include "secmon_smc_carveout.hpp" #include "secmon_smc_device_unique_data.hpp" #include "secmon_smc_error.hpp" #include "secmon_smc_info.hpp" #include "secmon_smc_memory_access.hpp" #include "secmon_smc_power_management.hpp" #include "secmon_smc_random.hpp" #include "secmon_smc_register_access.hpp" #include "secmon_smc_result.hpp" #include "secmon_smc_rsa.hpp" namespace ams::secmon::smc { namespace { struct HandlerInfo { u32 function_id; u32 restriction_mask; SmcHandler handler; }; struct HandlerTable { const HandlerInfo *entries; size_t count; }; enum HandlerType : int { HandlerType_User = 0, HandlerType_Kern = 1, HandlerType_Count = 2, }; enum Restriction { Restriction_None = (0 << 0), Restriction_Normal = (1 << 0), Restriction_DeviceUniqueDataNotAllowed = (1 << 1), Restriction_SafeModeNotAllowed = (1 << 2), }; enum SmcCallRange { SmcCallRange_ArmArch = 0, SmcCallRange_Cpu = 1, SmcCallRange_Sip = 2, SmcCallRange_Oem = 3, SmcCallRange_Standard = 4, SmcCallRange_TrustedApp = 0x30, }; enum SmcArgumentType { ArgumentType_Integer = 0, ArgumentType_Pointer = 1, }; enum SmcConvention { Convention_Smc32 = 0, Convention_Smc64 = 1, }; enum SmcCallType { SmcCallType_YieldingCall = 0, SmcCallType_FastCall = 1, }; struct SmcFunctionId { using FunctionId = util::BitPack64::Field< 0, 8, u32>; using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>; using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>; using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>; using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>; using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>; using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>; using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>; using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>; using Reserved = util::BitPack64::Field<16, 8, u32>; using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>; using Convention = util::BitPack64::Field<30, 1, SmcConvention>; using CallType = util::BitPack64::Field<31, 1, SmcCallType>; using Reserved2 = util::BitPack64::Field<32, 32, u32>; }; constinit HandlerInfo g_user_handlers[] = { { 0x00000000, Restriction_SafeModeNotAllowed, nullptr }, { 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig }, { 0xC3000002, Restriction_Normal, SmcGetConfigUser }, { 0xC3000003, Restriction_Normal, SmcGetResult }, { 0xC3000404, Restriction_Normal, SmcGetResultData }, { 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate }, { 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes }, { 0xC3000007, Restriction_Normal, SmcGenerateAesKek }, { 0xC3000008, Restriction_Normal, SmcLoadAesKey }, { 0xC3000009, Restriction_Normal, SmcComputeAes }, { 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey }, { 0xC300040B, Restriction_Normal, SmcComputeCmac }, { 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData }, { 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData }, { 0xC300000E, Restriction_SafeModeNotAllowed, nullptr }, { 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey }, { 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey }, { 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey }, { 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey } }; /* Deprecated handlerss. */ constexpr inline const HandlerInfo DecryptAndImportEsDeviceKeyHandlerInfo = { 0xC300100C, Restriction_Normal, SmcDecryptAndImportEsDeviceKey }; constexpr inline const HandlerInfo DecryptAndImportLotusKeyHandlerInfo = { 0xC300100E, Restriction_SafeModeNotAllowed, SmcDecryptAndImportLotusKey }; constinit HandlerInfo g_kern_handlers[] = { { 0x00000000, Restriction_SafeModeNotAllowed, nullptr }, { 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu }, { 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu }, { 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu }, { 0xC3000004, Restriction_Normal, SmcGetConfigKern }, { 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking }, { 0xC3000006, Restriction_Normal, SmcShowError }, { 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion }, { 0xC3000008, Restriction_Normal, SmcReadWriteRegister }, /* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */ { 0xC3000409, Restriction_Normal, SmcSetConfig }, }; constinit HandlerInfo g_ams_handlers[] = { { 0x00000000, Restriction_SafeModeNotAllowed, nullptr }, { 0xF0000201, Restriction_None, SmcIramCopy }, { 0xF0000002, Restriction_None, SmcReadWriteRegister }, { 0xF0000003, Restriction_None, SmcWriteAddress }, { 0xF0000404, Restriction_None, SmcGetEmummcConfig }, }; constexpr const HandlerInfo GetSecureDataHandlerInfo = { 0x67891234, Restriction_None, SmcGetSecureData }; constinit HandlerTable g_handler_tables[] = { { g_user_handlers, util::size(g_user_handlers) }, { g_kern_handlers, util::size(g_kern_handlers) }, }; constinit HandlerTable g_ams_handler_table = { g_ams_handlers, util::size(g_ams_handlers) }; NORETURN void InvalidSmcError(u64 id) { SetError(pkg1::ErrorInfo_UnknownSmc); AMS_ABORT("Invalid SMC: %lx", id); } const HandlerTable &GetHandlerTable(HandlerType type, u64 id) { /* Ensure we have a valid handler type. */ if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) { InvalidSmcError(id); } /* Provide support for legacy SmcGetSecureData. */ if (id == GetSecureDataHandlerInfo.function_id) { return g_handler_tables[HandlerType_User]; } /* Check if we're a user SMC. */ if (type == HandlerType_User) { /* Nintendo uses OEM SMCs. */ /* We will assign Atmosphere extension SMCs the TrustedApplication range. */ if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) { return g_ams_handler_table; } /* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */ if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) { InvalidSmcError(id); } } return g_handler_tables[type]; } const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) { /* Provide support for legacy SmcGetSecureData. */ if (id == GetSecureDataHandlerInfo.function_id) { return GetSecureDataHandlerInfo; } /* Get and check the index. */ const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>(); if (AMS_UNLIKELY(index >= table.count)) { InvalidSmcError(id); } /* Get and check the handler info. */ const auto &handler_info = table.entries[index]; /* Check that the handler isn't null. */ if (AMS_UNLIKELY(handler_info.handler == nullptr)) { InvalidSmcError(id); } /* Check that the handler's id matches. */ if (AMS_UNLIKELY(handler_info.function_id != id)) { InvalidSmcError(id); } return handler_info; } bool IsHandlerRestricted(const HandlerInfo &info) { return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0; } SmcResult InvokeSmcHandler(const HandlerInfo &info, SmcArguments &args) { /* Check if the smc is restricted. */ if (GetTargetFirmware() >= TargetFirmware_8_0_0 && AMS_UNLIKELY(IsHandlerRestricted(info))) { return SmcResult::NotPermitted; } /* Invoke the smc. */ return info.handler(args); } } void ConfigureSmcHandlersForTargetFirmware() { const auto target_fw = GetTargetFirmware(); if (target_fw < TargetFirmware_5_0_0) { g_user_handlers[DecryptAndImportEsDeviceKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportEsDeviceKeyHandlerInfo; g_user_handlers[DecryptAndImportLotusKeyHandlerInfo.function_id & 0xFF] = DecryptAndImportLotusKeyHandlerInfo; } } void HandleSmc(int type, SmcArguments &args) { /* Get the table. */ const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]); /* Get the handler info. */ const auto &info = GetHandlerInfo(table, args.r[0]); /* Set the invocation result. */ args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args)); } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { using SmcHandler = SmcResult (*)(SmcArguments &args); void ConfigureSmcHandlersForTargetFirmware(); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_info.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_map.hpp" #include "../secmon_misc.hpp" #include "../secmon_page_mapper.hpp" #include "../secmon_user_power_management.hpp" #include "secmon_smc_info.hpp" #include "secmon_smc_power_management.hpp" namespace ams::secmon::smc { namespace { struct KernelConfiguration { /* Secure Monitor view. */ using Flags1 = util::BitPack32::Field< 0, 8>; using Flags0 = util::BitPack32::Field< 8, 8>; using PhysicalMemorySize = util::BitPack32::Field<16, 2>; /* Kernel view, from libmesosphere. */ using DebugFillMemory = util::BitPack32::Field<0, 1, bool>; using EnableUserExceptionHandlers = util::BitPack32::Field<DebugFillMemory::Next, 1, bool>; using EnableUserPmuAccess = util::BitPack32::Field<EnableUserExceptionHandlers::Next, 1, bool>; using IncreaseThreadResourceLimit = util::BitPack32::Field<EnableUserPmuAccess::Next, 1, bool>; using DisableDynamicResourceLimits = util::BitPack32::Field<IncreaseThreadResourceLimit::Next, 1, bool>; using Reserved5 = util::BitPack32::Field<DisableDynamicResourceLimits::Next, 3, u32>; using UseSecureMonitorPanicCall = util::BitPack32::Field<Reserved5::Next, 1, bool>; using Reserved9 = util::BitPack32::Field<UseSecureMonitorPanicCall::Next, 7, u32>; using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, u32>; /* smc::MemorySize = pkg1::MemorySize */ }; constexpr const pkg1::MemorySize DramIdToMemorySize[fuse::DramId_Count] = { [fuse::DramId_IcosaSamsung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IcosaHynix4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IcosaMicron4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IowaHynix1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB, [fuse::DramId_HoagHynix1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_AulaHynix1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_Deprecated7] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSamsung8GB] = pkg1::MemorySize_8GB, [fuse::DramId_IowaHynix4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IowaMicron4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagSamsung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagSamsung8GB] = pkg1::MemorySize_8GB, [fuse::DramId_HoagHynix4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagMicron4GB] = pkg1::MemorySize_4GB, [fuse::DramId_Deprecated16] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSamsung1y4GBX] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSamsung1y8GBX] = pkg1::MemorySize_8GB, [fuse::DramId_HoagSamsung1y4GBX] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSamsung1z4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagSamsung1z4GB] = pkg1::MemorySize_4GB, [fuse::DramId_AulaSamsung1z4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagSamsung1y8GBX] = pkg1::MemorySize_8GB, [fuse::DramId_AulaSamsung1y4GBX] = pkg1::MemorySize_4GB, [fuse::DramId_IowaMicron1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagMicron1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_AulaMicron1y4GB] = pkg1::MemorySize_4GB, [fuse::DramId_AulaSamsung1y8GBX] = pkg1::MemorySize_8GB, [fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_HoagX1X2Samsung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_AulaX1X2Samsung4GB] = pkg1::MemorySize_4GB, [fuse::DramId_IowaSamsung4GBY] = pkg1::MemorySize_4GB, [fuse::DramId_HoagSamsung4GBY] = pkg1::MemorySize_4GB, [fuse::DramId_AulaSamsung4GBY] = pkg1::MemorySize_4GB, }; constexpr const pkg1::MemoryMode MemoryModes[] = { pkg1::MemoryMode_Auto, pkg1::MemoryMode_4GB, pkg1::MemoryMode_4GBAppletDev, pkg1::MemoryMode_4GBSystemDev, pkg1::MemoryMode_6GB, pkg1::MemoryMode_6GBAppletDev, pkg1::MemoryMode_8GB, }; constexpr bool IsValidMemoryMode(pkg1::MemoryMode mode) { for (const auto known_mode : MemoryModes) { if (mode == known_mode) { return true; } } return false; } pkg1::MemoryMode SanitizeMemoryMode(pkg1::MemoryMode mode) { if (IsValidMemoryMode(mode)) { return mode; } return pkg1::MemoryMode_Auto; } pkg1::MemorySize GetAvailableMemorySize(pkg1::MemorySize size) { return std::min(GetPhysicalMemorySize(), size); } pkg1::MemoryMode GetMemoryMode(pkg1::MemoryMode mode) { /* Sanitize the mode. */ mode = SanitizeMemoryMode(mode); /* If the mode is auto, construct the memory mode. */ if (mode == pkg1::MemoryMode_Auto) { return pkg1::MakeMemoryMode(GetPhysicalMemorySize(), pkg1::MemoryArrange_Normal); } else { const auto mode_size = GetMemorySize(mode); const auto mode_arrange = GetMemoryArrange(mode); const auto size = GetAvailableMemorySize(mode_size); const auto arrange = (size == mode_size) ? mode_arrange : pkg1::MemoryArrange_Normal; return pkg1::MakeMemoryMode(size, arrange); } } u32 GetMemoryMode() { /* Unless development function is enabled, we're 4 GB. */ u32 memory_mode = pkg1::MemoryMode_4GB; if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) { memory_mode = GetMemoryMode(bcd.GetMemoryMode()); } return memory_mode; } u32 GetKernelConfiguration() { pkg1::MemorySize memory_size = pkg1::MemorySize_4GB; util::BitPack32 value = {}; if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) { memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode())); value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1()); value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0()); } value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size); /* Exosphere extensions. */ const auto &sc = GetSecmonConfiguration(); if (!sc.DisableUserModeExceptionHandlers()) { value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true); } if (sc.EnableUserModePerformanceCounterAccess()) { value.Set<KernelConfiguration::EnableUserPmuAccess>(true); } return value.value; } constinit u64 g_payload_address = 0; constinit bool g_set_true_target_firmware = false; SmcResult GetConfig(SmcArguments &args, bool kern) { switch (static_cast<ConfigItem>(args.r[1])) { case ConfigItem::DisableProgramVerification: args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled(); break; case ConfigItem::DramId: args.r[1] = fuse::GetDramId(); break; case ConfigItem::SecurityEngineInterruptNumber: args.r[1] = SecurityEngineUserInterruptId; break; case ConfigItem::FuseVersion: args.r[1] = fuse::GetExpectedFuseVersion(GetTargetFirmware()); break; case ConfigItem::HardwareType: args.r[1] = fuse::GetHardwareType(); break; case ConfigItem::HardwareState: args.r[1] = fuse::GetHardwareState(); break; case ConfigItem::IsRecoveryBoot: args.r[1] = IsRecoveryBoot(); break; case ConfigItem::DeviceId: args.r[1] = fuse::GetDeviceId(); break; case ConfigItem::BootReason: { /* This was removed in firmware 4.0.0. */ if (GetTargetFirmware() >= TargetFirmware_4_0_0) { return SmcResult::InvalidArgument; } args.r[1] = GetDeprecatedBootReason(); } break; case ConfigItem::MemoryMode: args.r[1] = GetMemoryMode(); break; case ConfigItem::IsDevelopmentFunctionEnabled: args.r[1] = GetSecmonConfiguration().IsDevelopmentFunctionEnabled(kern) || GetBootConfig().data.IsDevelopmentFunctionEnabled(); break; case ConfigItem::KernelConfiguration: args.r[1] = GetKernelConfiguration(); break; case ConfigItem::IsChargerHiZModeEnabled: args.r[1] = IsChargerHiZModeEnabled(); break; case ConfigItem::RetailInteractiveDisplayState: args.r[1] = fuse::GetRetailInteractiveDisplayState(); break; case ConfigItem::RegulatorType: args.r[1] = fuse::GetRegulator(); break; case ConfigItem::DeviceUniqueKeyGeneration: args.r[1] = fuse::GetDeviceUniqueKeyGeneration(); break; case ConfigItem::Package2Hash: { /* Only allow getting the package2 hash in recovery boot. */ if (!IsRecoveryBoot()) { return SmcResult::InvalidArgument; } /* Get the hash. */ se::Sha256Hash tmp_hash; GetPackage2Hash(std::addressof(tmp_hash)); /* Copy it out. */ static_assert(sizeof(args) - sizeof(args.r[0]) >= sizeof(tmp_hash)); std::memcpy(std::addressof(args.r[1]), std::addressof(tmp_hash), sizeof(tmp_hash)); } break; case ConfigItem::ExosphereApiVersion: /* Get information about the current exosphere version. */ if (kern || g_set_true_target_firmware) { args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) | (static_cast<u64>(GetKeyGeneration()) << 32) | (static_cast<u64>(GetTargetFirmware()) << 0); } else { return SmcResult::NotInitialized; } break; case ConfigItem::ExosphereNeedsReboot: /* We are executing, so we aren't in the process of rebooting. */ args.r[1] = 0; break; case ConfigItem::ExosphereNeedsShutdown: /* We are executing, so we aren't in the process of shutting down. */ args.r[1] = 0; break; case ConfigItem::ExosphereGitCommitHash: /* Get information about the current exosphere git commit hash. */ args.r[1] = ATMOSPHERE_GIT_HASH; break; case ConfigItem::ExosphereHasRcmBugPatch: /* Get information about whether this unit has the RCM bug patched. */ args.r[1] = fuse::HasRcmVulnerabilityPatch(); break; case ConfigItem::ExosphereBlankProdInfo: /* Get whether this unit should simulate a "blanked" PRODINFO. */ args.r[1] = GetSecmonConfiguration().ShouldUseBlankCalibrationBinary(); break; case ConfigItem::ExosphereAllowCalWrites: /* Get whether this unit should allow writing to the calibration partition. */ args.r[1] = (GetEmummcConfiguration().IsEmummcActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc()); break; case ConfigItem::ExosphereEmummcType: /* Get what kind of emummc this unit has active. */ /* NOTE: This may return values other than 1 in the future. */ args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0); break; case ConfigItem::ExospherePayloadAddress: /* Gets the physical address of the reboot payload buffer, if one exists. */ if (g_payload_address != 0) { args.r[1] = g_payload_address; } else { return SmcResult::NotInitialized; } break; case ConfigItem::ExosphereLogConfiguration: /* Get the log configuration. */ args.r[1] = (static_cast<u64>(static_cast<u8>(secmon::GetLogPort())) << 32) | static_cast<u64>(secmon::GetLogBaudRate()); break; case ConfigItem::ExosphereForceEnableUsb30: /* Get whether usb 3.0 should be force-enabled. */ args.r[1] = GetSecmonConfiguration().IsUsb30ForceEnabled(); break; case ConfigItem::ExosphereSupportedHosVersion: /* Get information about the supported hos version. */ args.r[1] = (static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR & 0xFF) << 24) | (static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR & 0xFF) << 16) | (static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO & 0xFF) << 8); break; case ConfigItem::ExosphereApproximateApiVersion: /* Get information about the current exosphere version. */ if (!g_set_true_target_firmware) { args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) | (static_cast<u64>(GetKeyGeneration()) << 32) | (static_cast<u64>(GetTargetFirmware()) << 0); } else { return SmcResult::Busy; } break; default: return SmcResult::InvalidArgument; } return SmcResult::Success; } SmcResult SetConfig(SmcArguments &args) { const auto soc_type = GetSocType(); switch (static_cast<ConfigItem>(args.r[1])) { case ConfigItem::IsChargerHiZModeEnabled: /* Configure the HiZ mode. */ SetChargerHiZModeEnabled(static_cast<bool>(args.r[3])); break; case ConfigItem::ExosphereApiVersion: if (!g_set_true_target_firmware) { ::ams::secmon::impl::SetTargetFirmware(static_cast<ams::TargetFirmware>(args.r[3] & 0xFFFFFFFF)); g_set_true_target_firmware = true; } else { return SmcResult::Busy; } break; case ConfigItem::ExosphereNeedsReboot: if (soc_type == fuse::SocType_Erista) { switch (static_cast<UserRebootType>(args.r[3])) { case UserRebootType_None: break; case UserRebootType_ToRcm: PerformUserRebootToRcm(); break; case UserRebootType_ToPayload: PerformUserRebootToPayload(); break; case UserRebootType_ToFatalError: PerformUserRebootToFatalError(); break; case UserRebootType_ByPmic: PerformUserRebootByPmic(); break; default: return SmcResult::InvalidArgument; } } else /* if (soc_type == fuse::SocType_Mariko) */ { switch (static_cast<UserRebootType>(args.r[3])) { case UserRebootType_ToFatalError: PerformUserRebootToFatalError(); break; case UserRebootType_ByPmic: PerformUserRebootByPmic(); break; default: return SmcResult::InvalidArgument; } } break; case ConfigItem::ExosphereNeedsShutdown: if (args.r[3] != 0) { PerformUserShutDown(); } break; case ConfigItem::ExospherePayloadAddress: if (g_payload_address == 0) { if (secmon::IsPhysicalMemoryAddress(args.r[2])) { g_payload_address = args.r[2]; } else { return SmcResult::InvalidArgument; } } else { return SmcResult::Busy; } break; default: return SmcResult::InvalidArgument; } return SmcResult::Success; } } SmcResult SmcGetConfigUser(SmcArguments &args) { return GetConfig(args, false); } SmcResult SmcGetConfigKern(SmcArguments &args) { return GetConfig(args, true); } SmcResult SmcSetConfig(SmcArguments &args) { return SetConfig(args); } /* This is an atmosphere extension smc. */ SmcResult SmcGetEmummcConfig(SmcArguments &args) { /* Decode arguments. */ const auto mmc = static_cast<EmummcMmc>(args.r[1]); const uintptr_t user_address = args.r[2]; const uintptr_t user_offset = user_address % 4_KB; /* Validate arguments. */ /* NOTE: In the future, configuration for non-NAND storage may be implemented. */ SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotSupported); SMC_R_UNLESS(user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument); /* Get the emummc config. */ const auto &cfg = GetEmummcConfiguration(); static_assert(sizeof(cfg.file_cfg) == sizeof(EmummcFilePath)); static_assert(sizeof(cfg.emu_dir_path) == sizeof(EmummcFilePath)); /* Clear the output. */ constexpr size_t InlineOutputSize = sizeof(args) - sizeof(args.r[0]); u8 * const inline_output = static_cast<u8 *>(static_cast<void *>(std::addressof(args.r[1]))); std::memset(inline_output, 0, InlineOutputSize); /* Copy out the configuration. */ { /* Map the user output page. */ AtmosphereUserPageMapper mapper(user_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); /* Copy the base configuration. */ static_assert(sizeof(cfg.base_cfg) <= InlineOutputSize); std::memcpy(inline_output, std::addressof(cfg.base_cfg), sizeof(cfg.base_cfg)); /* Copy out type-specific data. */ switch (cfg.base_cfg.type) { case EmummcType_None: /* No additional configuration needs to be copied. */ break; case EmummcType_Partition: /* Copy the partition config. */ static_assert(sizeof(cfg.base_cfg) + sizeof(cfg.partition_cfg) <= InlineOutputSize); std::memcpy(inline_output + sizeof(cfg.base_cfg), std::addressof(cfg.partition_cfg), sizeof(cfg.partition_cfg)); break; case EmummcType_File: /* Copy the file config. */ SMC_R_UNLESS(mapper.CopyToUser(user_address, std::addressof(cfg.file_cfg), sizeof(cfg.file_cfg)), InvalidArgument); break; AMS_UNREACHABLE_DEFAULT_CASE(); } /* Copy the redirection directory path to the user page. */ SMC_R_UNLESS(mapper.CopyToUser(user_address + sizeof(EmummcFilePath), std::addressof(cfg.emu_dir_path), sizeof(cfg.emu_dir_path)), InvalidArgument); } return SmcResult::Success; } /* For exosphere's usage. */ pkg1::MemorySize GetPhysicalMemorySize() { const auto dram_id = fuse::GetDramId(); AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count); return DramIdToMemorySize[dram_id]; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { enum class ConfigItem : u32 { /* Standard config items. */ DisableProgramVerification = 1, DramId = 2, SecurityEngineInterruptNumber = 3, FuseVersion = 4, HardwareType = 5, HardwareState = 6, IsRecoveryBoot = 7, DeviceId = 8, BootReason = 9, MemoryMode = 10, IsDevelopmentFunctionEnabled = 11, KernelConfiguration = 12, IsChargerHiZModeEnabled = 13, RetailInteractiveDisplayState = 14, RegulatorType = 15, DeviceUniqueKeyGeneration = 16, Package2Hash = 17, /* Extension config items for exosphere. */ ExosphereApiVersion = 65000, ExosphereNeedsReboot = 65001, ExosphereNeedsShutdown = 65002, ExosphereGitCommitHash = 65003, ExosphereHasRcmBugPatch = 65004, ExosphereBlankProdInfo = 65005, ExosphereAllowCalWrites = 65006, ExosphereEmummcType = 65007, ExospherePayloadAddress = 65008, ExosphereLogConfiguration = 65009, ExosphereForceEnableUsb30 = 65010, ExosphereSupportedHosVersion = 65011, ExosphereApproximateApiVersion = 65012, }; SmcResult SmcGetConfigUser(SmcArguments &args); SmcResult SmcGetConfigKern(SmcArguments &args); SmcResult SmcSetConfig(SmcArguments &args); /* This is an atmosphere extension smc. */ SmcResult SmcGetEmummcConfig(SmcArguments &args); /* For other parts of exosphere. */ pkg1::MemorySize GetPhysicalMemorySize(); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_memory_access.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_page_mapper.hpp" #include "secmon_smc_memory_access.hpp" namespace ams::secmon::smc { namespace { enum IramCopyType { IramCopyType_FromIramToDram = 0, IramCopyType_FromDramToIram = 1, IramCopyType_Count, }; struct IramCopyOption { using CopyType = util::BitPack32::Field<0, 1, IramCopyType>; }; } /* This is an atmosphere extension smc. */ SmcResult SmcIramCopy(SmcArguments &args) { /* Decode arguments. */ const uintptr_t dram_address = args.r[1]; const uintptr_t iram_address = args.r[2]; const size_t size = args.r[3]; const util::BitPack32 option = { static_cast<u32>(args.r[4]) }; const auto copy_type = option.Get<IramCopyOption::CopyType>(); /* Validate arguments. */ SMC_R_UNLESS(copy_type < IramCopyType_Count, InvalidArgument); { /* Map the pages. */ AtmosphereUserPageMapper dram_mapper(dram_address); AtmosphereIramPageMapper iram_mapper(iram_address); SMC_R_UNLESS(dram_mapper.Map(), InvalidArgument); SMC_R_UNLESS(iram_mapper.Map(), InvalidArgument); /* Get the ranges we're copying. */ const void * const src = (copy_type == IramCopyType_FromIramToDram) ? iram_mapper.GetPointerTo(iram_address, size) : dram_mapper.GetPointerTo(dram_address, size); void * const dst = (copy_type == IramCopyType_FromIramToDram) ? dram_mapper.GetPointerTo(dram_address, size) : iram_mapper.GetPointerTo(iram_address, size); SMC_R_UNLESS(src != nullptr, InvalidArgument); SMC_R_UNLESS(dst != nullptr, InvalidArgument); /* Copy the data. */ std::memcpy(dst, src, size); } return SmcResult::Success; } SmcResult SmcWriteAddress(SmcArguments &args) { /* NOTE: This smc was deprecated in Atmosphère 0.13.0. */ AMS_UNUSED(args); return SmcResult::NotSupported; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_memory_access.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { /* This is an atmosphere extension smc. */ SmcResult SmcIramCopy(SmcArguments &args); SmcResult SmcWriteAddress(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_power_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_cache.hpp" #include "../secmon_cpu_context.hpp" #include "../secmon_error.hpp" #include "../secmon_misc.hpp" #include "secmon_smc_power_management.hpp" #include "secmon_smc_se_lock.hpp" #include "sc7fw_bin.h" namespace ams::secmon { /* Declare assembly functionality. */ void *GetCoreExceptionStackVirtual(); } namespace ams::secmon::smc { /* Declare assembly power-management functionality. */ void PivotStackAndInvoke(void *stack, void (*function)()); void FinalizePowerOff(); namespace { constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress(); constexpr inline const uintptr_t APB_MISC = MemoryRegionVirtualDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t GPIO = MemoryRegionVirtualDeviceGpio.GetAddress(); constexpr inline const uintptr_t CLK_RST = MemoryRegionVirtualDeviceClkRst.GetAddress(); constexpr inline const uintptr_t EVP = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress(); constexpr inline const uintptr_t FLOW_CTLR = MemoryRegionVirtualDeviceFlowController.GetAddress(); constexpr inline const uintptr_t AHB_ARBC = MemoryRegionVirtualDeviceSystem.GetAddress(); constexpr inline uintptr_t CommonSmcStackTop = MemoryRegionVirtualTzramVolatileData.GetEndAddress() - (0x80 * (NumCores - 1)); enum PowerStateType { PowerStateType_StandBy = 0, PowerStateType_PowerDown = 1, }; enum PowerStateId { PowerStateId_Sc7 = 27, }; /* http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf Page 46 */ struct SuspendCpuPowerState { using StateId = util::BitPack32::Field< 0, 16, PowerStateId>; using StateType = util::BitPack32::Field<16, 1, PowerStateType>; using PowerLevel = util::BitPack32::Field<24, 2, u32>; }; constinit bool g_charger_hi_z_mode_enabled = false; constinit const reg::BitsMask CpuPowerGateStatusMasks[NumCores] = { PMC_REG_BITS_MASK(PWRGATE_STATUS_CE0), PMC_REG_BITS_MASK(PWRGATE_STATUS_CE1), PMC_REG_BITS_MASK(PWRGATE_STATUS_CE2), PMC_REG_BITS_MASK(PWRGATE_STATUS_CE3), }; constinit const APBDEV_PMC_PWRGATE_TOGGLE_PARTID CpuPowerGateTogglePartitionIds[NumCores] = { APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0, APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE1, APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE2, APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE3, }; bool IsCpuPoweredOn(const reg::BitsMask mask) { return reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, REG_BITS_VALUE_FROM_MASK(mask, APBDEV_PMC_PWRGATE_STATUS_STATUS_ON)); } void PowerOnCpu(const reg::BitsMask mask, u32 toggle_partid) { /* If the cpu is already on, we have nothing to do. */ if (IsCpuPoweredOn(mask)) { return; } /* Wait until nothing is being powergated. */ int timeout = 5000; while (true) { if (reg::HasValue(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, DISABLE))) { break; } util::WaitMicroSeconds(1); if ((--timeout) < 0) { /* NOTE: Nintendo doesn't do any error handling here... */ return; } } /* Toggle on the cpu partition. */ reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE), PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, toggle_partid)); /* Wait up to 5000 us for the powergate to complete. */ timeout = 5000; while (true) { if (IsCpuPoweredOn(mask)) { break; } util::WaitMicroSeconds(1); if ((--timeout) < 0) { /* NOTE: Nintendo doesn't do any error handling here... */ return; } } } void ResetCpu(int which_core) { reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */ REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */ } void StartCpu(int which_core) { reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */ REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */ } void PowerOffCpuImpl() { /* Get the current core id. */ const auto core_id = hw::GetCurrentCoreId(); /* Configure the flow controller to prepare for shutting down the current core. */ flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_ONLY); flow::SetHaltCpuEvents(core_id, false); flow::SetCc4Ctrl(core_id, 0); /* Save the core's context for restoration on next power-on. */ SaveDebugRegisters(); SetCoreOff(); /* Ensure there are no pending memory transactions prior to our power-down. */ FlushEntireDataCache(); /* Finalize our powerdown and wait for an interrupt. */ FinalizePowerOff(); } void ValidateSocStateForSuspend() { /* Validate that all other cores are off. */ AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0))); /* Validate that the bpmp is appropriately halted. */ const bool jtag = IsJtagEnabled(); AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED))); /* Further validations aren't guaranteed on < 6.0.0. */ if (GetTargetFirmware() < TargetFirmware_6_0_0) { return; } /* Validate that USB2, APB-DMA, AHB-DMA are held in reset. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_USB2_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_APBDMA_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_AHBDMA_RST, ENABLE))); /* Validate that USBD is held in reset. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_USBD_RST, ENABLE))); /* Validate that AHB-DMA, USB, USB2, COP are not allowed to arbitrate on the AHB. */ AMS_ABORT_UNLESS(reg::HasValue(AHB_ARBC + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_AHBDMA, DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB, DISABLE), AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB2, DISABLE))); /* Validate that the GPIO controller has clock enabled. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_GPIO, ENABLE))); /* Validate that both FUSE and KFUSE have clock enabled. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_FUSE, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_KFUSE, ENABLE))); /* Validate that all of IRAM has clock enabled. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMA, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMB, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMC, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMD, ENABLE))); /* Validate that ACTMON has clock enabled. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_V_CLK_ENB_ACTMON, ENABLE))); /* Validate that ENTROPY has clock enabled. */ AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_W_CLK_ENB_ENTROPY, ENABLE))); } void GenerateCryptographicallyRandomBytes(void * const dst, int size) { /* Flush the region we're about to fill to ensure consistency with the SE. */ hw::FlushDataCache(dst, size); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes. */ se::GenerateRandomBytes(dst, size); hw::DataSynchronizationBarrierInnerShareable(); /* Flush to ensure the CPU sees consistent data for the region. */ hw::FlushDataCache(dst, size); hw::DataSynchronizationBarrierInnerShareable(); } void SaveSecureContextForErista() { /* Generate a random key source. */ util::AlignedBuffer<hw::DataCacheLineSize, se::AesBlockSize> key_source; GenerateCryptographicallyRandomBytes(key_source, se::AesBlockSize); const u32 * const key_source_32 = reinterpret_cast<const u32 *>(static_cast<u8 *>(key_source)); /* Ensure that the key source registers are not locked. */ AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) != pmc::LockState::Locked); /* Write the key source, lock writes to the key source, and verify that the key source is write-locked. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, key_source_32[0]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, key_source_32[1]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, key_source_32[2]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, key_source_32[3]); pmc::LockSecureRegister(pmc::SecureRegister_KeySourceWrite); AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceWrite) == pmc::LockState::Locked); /* Verify the key source is correct in registers, and read-lock the key source registers. */ AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24) == key_source_32[0]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25) == key_source_32[1]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26) == key_source_32[2]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27) == key_source_32[3]); pmc::LockSecureRegister(pmc::SecureRegister_KeySourceRead); /* Ensure that the key source registers are locked. */ AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) == pmc::LockState::Locked); /* Generate a random kek into keyslot 2. */ se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek); /* Verify that the se is in a validate state, context save, and validate again. */ { se::ValidateErrStatus(); ON_SCOPE_EXIT { se::ValidateErrStatus(); }; { /* Transition to non-secure mode for the duration of the context save operation. */ se::SetSecure(false); ON_SCOPE_EXIT { se::SetSecure(true); }; /* Get a pointer to the context storage. */ se::Context * const context = MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetPointer<se::Context>(); static_assert(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetSize() == sizeof(*context)); /* Save the context. */ se::SaveContext(context); /* Ensure that the cpu sees consistent data. */ hw::FlushDataCache(context, sizeof(*context)); hw::DataSynchronizationBarrierInnerShareable(); /* Write the context pointer to pmc scratch, so that the bootrom will restore it on wake. */ reg::Write(PMC + APBDEV_PMC_SCRATCH43, MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState.GetAddress()); } } /* Clear keyslot 3, and then derive the save key. */ se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, se::AesBlockSize); /* Declare a temporary block to be used as both iv and mac. */ u32 temp_block[se::AesBlockSize / sizeof(u32)] = {}; /* Ensure that the SE sees consistent data for tzram. */ const void * const tzram_save_src = MemoryRegionVirtualTzramReadOnlyAlias.GetPointer<u8>() + MemoryRegionVirtualTzramVolatileData.GetSize() + MemoryRegionVirtualTzramVolatileStack.GetSize(); void * const tzram_save_dst = MemoryRegionVirtualIramSc7Work.GetPointer<void>(); constexpr size_t TzramSaveSize = MemoryRegionVirtualDramSecureDataStoreTzram.GetSize(); hw::FlushDataCache(tzram_save_src, TzramSaveSize); hw::FlushDataCache(tzram_save_dst, TzramSaveSize); hw::DataSynchronizationBarrierInnerShareable(); /* Encrypt tzram using our random key. */ se::EncryptAes256Cbc(tzram_save_dst, TzramSaveSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize, temp_block, se::AesBlockSize); hw::FlushDataCache(tzram_save_dst, TzramSaveSize); hw::DataSynchronizationBarrierInnerShareable(); /* Copy the data from work space to the secure storage destination. */ void * const tzram_store_dst = MemoryRegionVirtualDramSecureDataStoreTzram.GetPointer<void>(); std::memcpy(tzram_store_dst, tzram_save_dst, TzramSaveSize); hw::FlushDataCache(tzram_store_dst, TzramSaveSize); hw::DataSynchronizationBarrierInnerShareable(); /* Compute cmac of tzram into our temporary block. */ se::ComputeAes256Cmac(temp_block, se::AesBlockSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize); /* Ensure that the cmac registers are not locked. */ AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) != pmc::LockState::Locked); /* Write the cmac, lock writes to the cmac, and verify that the cmac is write-locked. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, temp_block[0]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, temp_block[1]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, temp_block[2]); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, temp_block[3]); pmc::LockSecureRegister(pmc::SecureRegister_CmacWrite); AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacWrite) == pmc::LockState::Locked); /* Verify the key source is correct in registers, and read-lock the key source registers. */ AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112) == temp_block[0]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113) == temp_block[1]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114) == temp_block[2]); AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115) == temp_block[3]); pmc::LockSecureRegister(pmc::SecureRegister_CmacRead); /* Ensure that the key source registers are locked. */ AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) == pmc::LockState::Locked); } void SaveSecureContextForMariko() { /* Save security engine context to TZRAM SE carveout (inaccessible to cpu). */ se::SaveContextAutomatic(); /* Save TZRAM to shadow-TZRAM in always-on power domain. */ se::SaveTzramAutomatic(); } void SaveSecureContext() { /* Save the appropriate secure context. */ const auto soc_type = GetSocType(); if (soc_type == fuse::SocType_Erista) { SaveSecureContextForErista(); } else /* if (soc_type == fuse::SocType_Mariko) */ { SaveSecureContextForMariko(); } /* Save the debug code. */ #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) { const void * const debug_code_src = MemoryRegionVirtualDebugCode.GetPointer<void>(); void * const debug_code_dst = MemoryRegionVirtualDramDebugDataStore.GetPointer<void>(); std::memcpy(debug_code_dst, debug_code_src, MemoryRegionVirtualDebugCode.GetSize()); hw::FlushDataCache(debug_code_dst, MemoryRegionVirtualDebugCode.GetSize()); hw::DataSynchronizationBarrierInnerShareable(); } #endif } void LoadAndStartSc7BpmpFirmware() { /* Set BPMP reset. */ reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE)); /* Set the PMC as insecure, so that the BPMP firmware can access it. */ reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, DISABLE)); /* Set the exception vectors for the bpmp. RESET should point to RESET, all others should point to generic exception/panic. */ constexpr const u32 Sc7FirmwareResetVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x0); constexpr const u32 Sc7FirmwarePanicVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x4); reg::Write(EVP + EVP_COP_RESET_VECTOR, Sc7FirmwareResetVector); reg::Write(EVP + EVP_COP_UNDEF_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_SWI_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_RSVD_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_IRQ_VECTOR, Sc7FirmwarePanicVector); reg::Write(EVP + EVP_COP_FIQ_VECTOR, Sc7FirmwarePanicVector); /* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */ actmon::StopMonitoringBpmp(); /* Load the bpmp firmware. */ void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>(); std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size); hw::FlushDataCache(sc7fw_load_address, sc7fw_bin_size); hw::DataSynchronizationBarrierInnerShareable(); /* Ensure that the bpmp firmware was loaded. */ AMS_ABORT_UNLESS(crypto::IsSameBytes(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size)); /* Clear BPMP reset. */ reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_COP_RST, ENABLE)); /* Start the bpmp. */ reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_NONE)); } void SaveSecureContextAndSuspend() { /* Ensure there are no pending memory transactions before we continue */ FlushEntireDataCache(); hw::DataSynchronizationBarrierInnerShareable(); /* Save all secure context (security engine state + tzram). */ SaveSecureContext(); /* Load and start the sc7 firmware on the bpmp. */ if (GetTargetFirmware() >= TargetFirmware_2_0_0) { LoadAndStartSc7BpmpFirmware(); } /* Log our suspension. */ /* NOTE: Nintendo only does this on dev, but we will always do it. */ if (true /* !pkg1::IsProduction() */) { log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags()); log::SendText("OYASUMI\n", 8); log::Flush(); } /* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */ if (GetSocType() == fuse::SocType_Erista) { reg::Write(PMC + APBDEV_PMC_SCRATCH31, 0x2202E012); reg::Write(PMC + APBDEV_PMC_SCRATCH32, 0x6001DC28); } /* Finalize our powerdown and wait for an interrupt. */ FinalizePowerOff(); } SmcResult SuspendCpuImpl(SmcArguments &args) { /* Decode arguments. */ const util::BitPack32 power_state = { static_cast<u32>(args.r[1]) }; const uintptr_t entry_point = args.r[2]; const uintptr_t context_id = args.r[3]; const auto state_type = power_state.Get<SuspendCpuPowerState::StateType>(); const auto state_id = power_state.Get<SuspendCpuPowerState::StateId>(); const auto core_id = hw::GetCurrentCoreId(); /* Validate arguments. */ SMC_R_UNLESS(state_type == PowerStateType_PowerDown, PsciDenied); SMC_R_UNLESS(state_id == PowerStateId_Sc7, PsciDenied); /* Orchestrate charger transition to Hi-Z mode if needed. */ if (IsChargerHiZModeEnabled()) { /* Ensure we can do comms over i2c-1. */ clkrst::EnableI2c1Clock(); /* If the charger isn't in hi-z mode, perform a transition. */ if (!charger::IsHiZMode()) { charger::EnterHiZMode(); /* Wait up to 50ms for the transition to complete. */ const auto start_time = util::GetMicroSeconds(); auto current_time = start_time; while ((current_time - start_time) <= 50'000) { if (auto intr_status = reg::Read(GPIO + 0x634); (intr_status & 1) == 0) { /* Wait 256 us to ensure the transition completes. */ util::WaitMicroSeconds(256); break; } current_time = util::GetMicroSeconds(); } } /* Disable i2c-1, since we're done communicating over it. */ clkrst::DisableI2c1Clock(); } /* Enable wake event detection. */ pmc::EnableWakeEventDetection(); /* Ensure that i2c-5 is usable for communicating with the pmic. */ clkrst::EnableI2c5Clock(); i2c::Initialize(i2c::Port_5); /* Orchestrate sleep entry with the pmic. */ pmic::EnableSleep(); /* Ensure that the soc is in a state valid for us to suspend. */ if (GetTargetFirmware() >= TargetFirmware_2_0_0) { ValidateSocStateForSuspend(); } /* Configure the pmc for sc7 entry. */ pmc::ConfigureForSc7Entry(); /* Configure the flow controller for sc7 entry. */ flow::SetCc4Ctrl(core_id, 0); flow::SetHaltCpuEvents(core_id, false); flow::ClearL2FlushControl(); flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_TURNOFF_CPURAIL); /* Save the entry context. */ SetEntryContext(core_id, entry_point, context_id); /* Configure the cpu context for reset. */ SaveDebugRegisters(); SetCoreOff(); SetResetExpected(true); /* Switch to use the common smc stack (all other cores are off), and perform suspension. */ PivotStackAndInvoke(reinterpret_cast<void *>(CommonSmcStackTop), SaveSecureContextAndSuspend); /* This code will never be reached. */ __builtin_unreachable(); } } void PowerOffCpu() { /* Get the current core id. */ const auto core_id = hw::GetCurrentCoreId(); /* Note that we're expecting a reset for the current core. */ SetResetExpected(true); /* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */ if (core_id == NumCores - 1) { PowerOffCpuImpl(); } else { PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl); } /* This code will never be reached. */ __builtin_unreachable(); } SmcResult SmcPowerOffCpu(SmcArguments &args) { AMS_UNUSED(args); PowerOffCpu(); } SmcResult SmcPowerOnCpu(SmcArguments &args) { /* Get and validate the core to power on. */ const int which_core = args.r[1]; SMC_R_UNLESS(0 <= which_core && which_core < NumCores, PsciInvalidParameters); /* Ensure the core isn't already on. */ SMC_R_UNLESS(!IsCoreOn(which_core), PsciAlreadyOn); /* Save the entry context. */ SetEntryContext(which_core, args.r[2], args.r[3]); /* Reset the cpu. */ ResetCpu(which_core); /* Turn on the core. */ PowerOnCpu(CpuPowerGateStatusMasks[which_core], CpuPowerGateTogglePartitionIds[which_core]); /* Start the core. */ StartCpu(which_core); return SmcResult::PsciSuccess; } SmcResult SmcSuspendCpu(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, SuspendCpuImpl); } bool IsChargerHiZModeEnabled() { return g_charger_hi_z_mode_enabled; } void SetChargerHiZModeEnabled(bool en) { g_charger_hi_z_mode_enabled = en; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_power_management.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { NORETURN void PowerOffCpu(); SmcResult SmcPowerOffCpu(SmcArguments &args); SmcResult SmcPowerOnCpu(SmcArguments &args); SmcResult SmcSuspendCpu(SmcArguments &args); bool IsChargerHiZModeEnabled(); void SetChargerHiZModeEnabled(bool en); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_random.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_smc_random.hpp" #include "secmon_random_cache.hpp" #include "secmon_smc_se_lock.hpp" namespace ams::secmon::smc { namespace { SmcResult GenerateRandomBytesImpl(SmcArguments &args) { /* Validate the input size. */ const size_t size = args.r[1]; SMC_R_UNLESS(size <= MaxRandomBytes, InvalidArgument); /* Create a buffer that the se can generate bytes into. */ util::AlignedBuffer<hw::DataCacheLineSize, MaxRandomBytes> buffer; hw::FlushDataCache(buffer, size); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes into the buffer. */ se::GenerateRandomBytes(buffer, size); /* Ensure that the cpu sees consistent data. */ hw::DataSynchronizationBarrierInnerShareable(); hw::FlushDataCache(buffer, size); hw::DataSynchronizationBarrierInnerShareable(); /* Copy the bytes to output. */ std::memcpy(std::addressof(args.r[1]), buffer, size); return SmcResult::Success; } } SmcResult SmcGenerateRandomBytes(SmcArguments &args) { return LockSecurityEngineAndInvoke(args, GenerateRandomBytesImpl); } SmcResult SmcGenerateRandomBytesNonBlocking(SmcArguments &args) { /* Try to lock the security engine, so that we can call the standard impl. */ if (TryLockSecurityEngine()) { /* Ensure we unlock the security engine when done. */ ON_SCOPE_EXIT { UnlockSecurityEngine(); }; /* Take advantage of our lock to refill lthe random cache. */ ON_SCOPE_EXIT { RefillRandomCache(); }; /* If we lock it successfully, we can just call the blocking impl. */ return GenerateRandomBytesImpl(args); } else { /* Otherwise, we'll retrieve some bytes from the cache. */ const size_t size = args.r[1]; SMC_R_UNLESS(size <= MaxRandomBytes, InvalidArgument); /* Get random bytes from the cache. */ GetRandomFromCache(std::addressof(args.r[1]), size); return SmcResult::Success; } } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_random.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { SmcResult SmcGenerateRandomBytes(SmcArguments &args); SmcResult SmcGenerateRandomBytesNonBlocking(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_register_access.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_smc_register_access.hpp" namespace ams::secmon::smc { namespace { template<size_t N> constexpr void SetRegisterTableAllowed(std::array<u8, N> &arr, uintptr_t reg) { /* All registers should be four byte aligned. */ AMS_ASSUME(reg % sizeof(u32) == 0); /* Reduce the register to an index. */ reg /= sizeof(u32); /* Get the index and mask. */ const auto index = reg / BITSIZEOF(u8); const auto mask = (1u << (reg % BITSIZEOF(u8))); /* Check that the permission bit isn't already set. */ AMS_ASSUME((arr[index] & mask) == 0); /* Set the permission bit. */ arr[index] |= mask; /* Ensure that indices are set in sorted order. */ for (auto i = (reg % BITSIZEOF(u8)) + 1; i < 8; ++i) { AMS_ASSUME((arr[index] & (1u << i)) == 0); } for (auto i = index + 1; i < arr.size(); ++i) { AMS_ASSUME(arr[i] == 0); } } template<size_t N> consteval std::pair<size_t, size_t> GetReducedAccessTableInfo(const std::array<u8, N> &arr) { for (int last = arr.size() - 1; last >= 0; --last) { if (arr[last] != 0) { const int end = last + 1; for (int start = 0; start < end; ++start) { if (arr[start] != 0) { return std::make_pair(static_cast<size_t>(start), static_cast<size_t>(end)); } } return std::make_pair(static_cast<size_t>(0), static_cast<size_t>(end)); } } /* All empty perm table is disallowed. */ AMS_ASSUME(false); } template<u32 _Address, auto RawTable> struct AccessTable { static constexpr inline auto ReducedAccessTableInfo = GetReducedAccessTableInfo(RawTable); static constexpr inline size_t ReducedAccessTableSize = ReducedAccessTableInfo.second - ReducedAccessTableInfo.first; static constexpr inline auto ReducedAccessTable = []() -> std::array<u8, ReducedAccessTableSize> { std::array<u8, ReducedAccessTableSize> reduced = {}; for (size_t i = ReducedAccessTableInfo.first; i < ReducedAccessTableInfo.second; ++i) { reduced[i - ReducedAccessTableInfo.first] = RawTable[i]; } return reduced; }(); static constexpr u32 Address = _Address + (ReducedAccessTableInfo.first * sizeof(u32) * BITSIZEOF(u8)); static constexpr u32 Size = static_cast<u32>(ReducedAccessTableSize * sizeof(u32) * BITSIZEOF(u8)); static_assert(Size <= 0x1000); }; struct AccessTableEntry { const u8 * const table; uintptr_t virtual_address; u32 address; u32 size; }; /* Include the access tables. */ #include "secmon_define_pmc_access_table.inc" #include "secmon_define_mc_access_table.inc" #include "secmon_define_mc01_access_table.inc" constexpr const AccessTableEntry AccessTables[] = { { PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, }, { McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, }, { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, }, { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, }, }; constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) { /* Check if the address is within range. */ if (!(entry.address <= address && address < entry.address + entry.size)) { return false; } /* Get the offset. */ const auto offset = address - entry.address; /* Convert it to an index. */ const auto reg_index = offset / sizeof(u32); /* Get the bit fields. */ const auto index = reg_index / BITSIZEOF(u8); const auto mask = (1u << (reg_index % BITSIZEOF(u8))); /* Validate that we're not going out of bounds. */ if (index >= entry.size / sizeof(u32)) { return false; } return (entry.table[index] & mask) != 0; } constexpr const AccessTableEntry *GetAccessTableEntry(uintptr_t address) { for (const auto &entry : AccessTables) { if (IsAccessAllowed(entry, address)) { return std::addressof(entry); } } return nullptr; } } SmcResult SmcReadWriteRegister(SmcArguments &args) { /* Get the arguments. */ const uintptr_t address = args.r[1]; const u32 mask = args.r[2]; const u32 value = args.r[3]; /* Validate that the address is aligned. */ SMC_R_UNLESS(util::IsAligned(address, alignof(u32)), InvalidArgument); /* Find the access table. */ const AccessTableEntry * const entry = GetAccessTableEntry(address); /* Translate our entry into an address to access. */ uintptr_t virtual_address = 0; if (entry != nullptr) { /* Get the address to read or write. */ virtual_address = entry->virtual_address + (address - entry->address); } else { /* For no clearly discernable reason, SmcReadWriteRegister returns success despite not doing the read/write */ /* when accessing the SMMU controls for the BPMP and for APB-DMA. */ /* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */ /* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */ constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress(); SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument); /* For backwards compatibility, we'll allow access to these devices on 1.0.0. */ if (GetTargetFirmware() < TargetFirmware_2_0_0) { virtual_address = MemoryRegionVirtualDeviceMemoryController.GetAddress() + (address - MC); } } /* Perform the read or write, if we should. */ if (virtual_address != 0) { u32 out = 0; if (mask != ~static_cast<u32>(0)) { out = reg::Read(virtual_address); } if (mask != static_cast<u32>(0)) { reg::Write(virtual_address, (out & ~mask) | (value & mask)); } args.r[1] = out; } return SmcResult::Success; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_register_access.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { SmcResult SmcReadWriteRegister(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_result.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_page_mapper.hpp" #include "secmon_smc_result.hpp" namespace ams::secmon::smc { namespace { constinit u64 g_async_key = InvalidAsyncKey; constinit GetResultHandler g_async_handler = nullptr; u64 GenerateRandomU64() { /* NOTE: This is one of the only places where Nintendo does not do data flushing. */ /* to ensure coherency when doing random byte generation. */ /* It is not clear why it is necessary elsewhere but not here. */ /* TODO: Figure out why. */ u64 v; se::GenerateRandomBytes(std::addressof(v), sizeof(v)); return v; } } u64 BeginAsyncOperation(GetResultHandler handler) { /* Only allow one async operation at a time. */ if (g_async_key != InvalidAsyncKey) { return InvalidAsyncKey; } /* Generate a random async key. */ g_async_key = GenerateRandomU64(); g_async_handler = handler; return g_async_key; } void CancelAsyncOperation(u64 async_key) { if (async_key == g_async_key) { g_async_key = InvalidAsyncKey; } } void EndAsyncOperation() { gic::SetPending(SecurityEngineUserInterruptId); } SmcResult SmcGetResult(SmcArguments &args) { /* Decode arguments. */ const u64 async_key = args.r[1]; /* Validate arguments. */ SMC_R_UNLESS(g_async_key != InvalidAsyncKey, NoAsyncOperation); SMC_R_UNLESS(g_async_key == async_key, InvalidAsyncOperation); /* Call the handler. */ args.r[1] = static_cast<u64>(g_async_handler(nullptr, 0)); g_async_key = InvalidAsyncKey; return SmcResult::Success; } SmcResult SmcGetResultData(SmcArguments &args) { /* Decode arguments. */ const u64 async_key = args.r[1]; const uintptr_t user_phys_addr = args.r[2]; const size_t user_size = args.r[3]; /* Allocate a work buffer on the stack. */ alignas(8) u8 work_buffer[1_KB]; /* Validate arguments. */ SMC_R_UNLESS(g_async_key != InvalidAsyncKey, NoAsyncOperation); SMC_R_UNLESS(g_async_key == async_key, InvalidAsyncOperation); SMC_R_UNLESS(user_size <= sizeof(work_buffer), InvalidArgument); /* Call the handler. */ args.r[1] = static_cast<u64>(g_async_handler(work_buffer, user_size)); g_async_key = InvalidAsyncKey; /* Map the user buffer. */ { UserPageMapper mapper(user_phys_addr); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyToUser(user_phys_addr, work_buffer, user_size), InvalidArgument); } return SmcResult::Success; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_result.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { using GetResultHandler = SmcResult (*)(void *dst, size_t dst_size); u64 BeginAsyncOperation(GetResultHandler handler); void CancelAsyncOperation(u64 async_key); void EndAsyncOperation(); SmcResult SmcGetResult(SmcArguments &args); SmcResult SmcGetResultData(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_rsa.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "../secmon_key_storage.hpp" #include "../secmon_page_mapper.hpp" #include "secmon_smc_aes.hpp" #include "secmon_smc_rsa.hpp" #include "secmon_smc_se_lock.hpp" namespace ams::secmon::smc { namespace { struct ModularExponentiateByStorageKeyOption { using Mode = util::BitPack32::Field<0, 2, u32>; using Reserved = util::BitPack32::Field<2, 30, u32>; }; struct PrepareEsDeviceUniqueKeyOption { using KeyGeneration = util::BitPack32::Field<0, 6, int>; using Type = util::BitPack32::Field<6, 2, EsCommonKeyType>; using Reserved = util::BitPack32::Field<8, 24, u32>; }; constexpr const u8 ModularExponentiateByStorageKeyTable[] = { static_cast<u8>(ImportRsaKey_Lotus), static_cast<u8>(ImportRsaKey_Ssl), static_cast<u8>(ImportRsaKey_EsClientCert), }; constexpr size_t ModularExponentiateByStorageKeyTableSize = util::size(ModularExponentiateByStorageKeyTable); consteval u32 GetModeForImportRsaKey(ImportRsaKey import_key) { for (size_t i = 0; i < ModularExponentiateByStorageKeyTableSize; ++i) { if (static_cast<ImportRsaKey>(ModularExponentiateByStorageKeyTable[i]) == import_key) { return i; } } AMS_ASSUME(false); } class PrepareEsDeviceUniqueKeyAsyncArguments { private: int m_generation; EsCommonKeyType m_type; u8 m_label_digest[crypto::Sha256Generator::HashSize]; public: void Set(int gen, EsCommonKeyType t, const u8 ld[crypto::Sha256Generator::HashSize]) { m_generation = gen; m_type = t; std::memcpy(m_label_digest, ld, sizeof(m_label_digest)); } int GetKeyGeneration() const { return m_generation; } EsCommonKeyType GetCommonKeyType() const { return m_type; } void GetLabelDigest(u8 dst[crypto::Sha256Generator::HashSize]) const { std::memcpy(dst, m_label_digest, sizeof(m_label_digest)); } }; class ModularExponentiateByStorageKeyAsyncArguments { private: u8 m_msg[se::RsaSize]; public: void Set(const void *m, size_t m_size) { AMS_UNUSED(m_size); std::memcpy(m_msg, m, sizeof(m_msg)); } const u8 *GetMessage() const { return m_msg; } }; constinit SmcResult g_exp_mod_result = SmcResult::Success; constinit bool g_test_exp_mod_public = false; constinit int g_test_exp_mod_slot = pkg1::RsaKeySlot_Temporary; constinit ImportRsaKey g_test_exp_mod_key = {}; constinit union { ModularExponentiateByStorageKeyAsyncArguments modular_exponentiate_by_storage_key; PrepareEsDeviceUniqueKeyAsyncArguments prepare_es_device_unique_key; } g_async_arguments; ALWAYS_INLINE ModularExponentiateByStorageKeyAsyncArguments &GetModularExponentiateByStorageKeyAsyncArguments() { return g_async_arguments.modular_exponentiate_by_storage_key; } ALWAYS_INLINE PrepareEsDeviceUniqueKeyAsyncArguments &GetPrepareEsDeviceUniqueKeyAsyncArguments() { return g_async_arguments.prepare_es_device_unique_key; } void SecurityEngineDoneHandler() { /* End the asynchronous operation. */ g_exp_mod_result = SmcResult::Success; EndAsyncOperation(); } void TestRsaPublicKey(ImportRsaKey which, int slot, const void *mod, size_t mod_size, se::DoneHandler handler) { /* Declare a buffer for our test message. */ u8 msg[se::RsaSize]; std::memset(msg, 'D', sizeof(msg)); /* Provisionally import the modulus. */ ImportRsaKeyModulusProvisionally(which, mod, mod_size); /* Load the provisional public key into the slot. */ LoadProvisionalRsaPublicKey(slot, which); /* Perform the test exponentiation. */ se::ModularExponentiateAsync(slot, msg, sizeof(msg), handler); } void TestRsaPrivateKey(ImportRsaKey which, int slot, se::DoneHandler handler) { /* Get the result of the public key test. */ u8 msg[se::RsaSize]; se::GetRsaResult(msg, sizeof(msg)); /* Load the provisional private key into the slot. */ LoadProvisionalRsaKey(slot, which); /* Perform the test exponentiation. */ se::ModularExponentiateAsync(slot, msg, sizeof(msg), handler); } void VerifyTestRsaKeyResult(ImportRsaKey which) { /* Get the result of the test. */ u8 msg[se::RsaSize]; se::GetRsaResult(msg, sizeof(msg)); /* Validate the result. */ const bool is_valid = (msg[0] == 'D') & (crypto::IsSameBytes(msg, msg + 1, sizeof(msg) - 1)); /* If the test passes, the key is no longer provisional. */ if (is_valid) { CommitRsaKeyModulus(which); } } void TestRsaKeyDoneHandler() { if (g_test_exp_mod_public) { /* If we're testing the public key, we still have another exponentiation to do to test the private key. */ g_test_exp_mod_public = false; /* Test the private key. */ TestRsaPrivateKey(g_test_exp_mod_key, g_test_exp_mod_slot, TestRsaKeyDoneHandler); } else { /* We're testing the private key, so validate the result. */ VerifyTestRsaKeyResult(g_test_exp_mod_key); /* If the test passed, we can proceed to perform the intended exponentiation. */ if (LoadRsaKey(g_test_exp_mod_slot, g_test_exp_mod_key)) { se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, GetModularExponentiateByStorageKeyAsyncArguments().GetMessage(), se::RsaSize, SecurityEngineDoneHandler); } else { /* The test failed, so end the asynchronous operation. */ g_exp_mod_result = SmcResult::InvalidArgument; EndAsyncOperation(); } } } SmcResult ModularExponentiateImpl(SmcArguments &args) { /* Decode arguments. */ const uintptr_t msg_address = args.r[1]; const uintptr_t exp_address = args.r[2]; const uintptr_t mod_address = args.r[3]; const size_t exp_size = args.r[4]; /* Validate arguments. */ SMC_R_UNLESS(util::IsAligned(exp_size, sizeof(u32)), InvalidArgument); SMC_R_UNLESS(exp_size <= se::RsaSize, InvalidArgument); /* Copy the message and modulus from the user. */ alignas(8) u8 msg[se::RsaSize]; alignas(8) u8 exp[se::RsaSize]; alignas(8) u8 mod[se::RsaSize]; { UserPageMapper mapper(msg_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(exp, exp_address, exp_size), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument); } /* We're performing an operation, so set the result to busy. */ g_exp_mod_result = SmcResult::Busy; /* Load the key into the temporary keyslot. */ se::SetRsaKey(pkg1::RsaKeySlot_Temporary, mod, sizeof(mod), exp, exp_size); /* Begin the asynchronous exponentiation. */ se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler); return SmcResult::Success; } SmcResult ModularExponentiateByStorageKeyImpl(SmcArguments &args) { /* Decode arguments. */ const uintptr_t msg_address = args.r[1]; const uintptr_t mod_address = args.r[2]; const util::BitPack32 option = { static_cast<u32>(args.r[3]) }; const auto mode = GetTargetFirmware() >= TargetFirmware_5_0_0 ? option.Get<ModularExponentiateByStorageKeyOption::Mode>() : GetModeForImportRsaKey(ImportRsaKey_Lotus); const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); SMC_R_UNLESS(mode < ModularExponentiateByStorageKeyTableSize, InvalidArgument); /* Convert the mode to an import key. */ const auto import_key = static_cast<ImportRsaKey>(ModularExponentiateByStorageKeyTable[mode]); /* Copy the message and modulus from the user. */ alignas(8) u8 msg[se::RsaSize]; alignas(8) u8 mod[se::RsaSize]; { UserPageMapper mapper(msg_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument); } /* We're performing an operation, so set the result to busy. */ g_exp_mod_result = SmcResult::Busy; /* In the ideal case, the key pair is already verified. If it is, we can use it directly. */ if (LoadRsaKey(pkg1::RsaKeySlot_Temporary, import_key)) { se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler); } else { /* Set the async arguments. */ GetModularExponentiateByStorageKeyAsyncArguments().Set(msg, sizeof(msg)); /* Test the rsa key. */ g_test_exp_mod_slot = pkg1::RsaKeySlot_Temporary; g_test_exp_mod_key = import_key; g_test_exp_mod_public = true; TestRsaPublicKey(import_key, pkg1::RsaKeySlot_Temporary, mod, sizeof(mod), TestRsaKeyDoneHandler); } return SmcResult::Success; } SmcResult PrepareEsDeviceUniqueKeyImpl(SmcArguments &args) { /* Decode arguments. */ u8 label_digest[crypto::Sha256Generator::HashSize]; const uintptr_t msg_address = args.r[1]; const uintptr_t mod_address = args.r[2]; std::memcpy(label_digest, std::addressof(args.r[3]), sizeof(label_digest)); const util::BitPack32 option = { static_cast<u32>(args.r[7]) }; const auto generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max<int>(pkg1::KeyGeneration_1_0_0, option.Get<PrepareEsDeviceUniqueKeyOption::KeyGeneration>() - 1) : pkg1::KeyGeneration_1_0_0; const auto type = option.Get<PrepareEsDeviceUniqueKeyOption::Type>(); const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>(); /* Validate arguments. */ SMC_R_UNLESS(reserved == 0, InvalidArgument); SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument); SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument); SMC_R_UNLESS(type < EsCommonKeyType_Count, InvalidArgument); /* Copy the message and modulus from the user. */ alignas(8) u8 msg[se::RsaSize]; alignas(8) u8 mod[se::RsaSize]; { UserPageMapper mapper(msg_address); SMC_R_UNLESS(mapper.Map(), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument); SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument); } /* We're performing an operation, so set the result to busy. */ g_exp_mod_result = SmcResult::Busy; /* Set the async arguments. */ GetPrepareEsDeviceUniqueKeyAsyncArguments().Set(generation, type, label_digest); /* Load the es drm key into the security engine. */ SMC_R_UNLESS(LoadRsaKey(pkg1::RsaKeySlot_Temporary, ImportRsaKey_EsDrmCert), NotInitialized); /* Trigger the asynchronous modular exponentiation. */ se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler); return SmcResult::Success; } SmcResult GetModularExponentiateResult(void *dst, size_t dst_size) { /* Validate state. */ SMC_R_TRY(g_exp_mod_result); SMC_R_UNLESS(dst_size == se::RsaSize, InvalidArgument); /* We want to relinquish our security engine lock at the end of scope. */ ON_SCOPE_EXIT { UnlockSecurityEngine(); }; /* Get the result of the exponentiation. */ se::GetRsaResult(dst, se::RsaSize); return SmcResult::Success; } SmcResult GetPrepareEsDeviceUniqueKeyResult(void *dst, size_t dst_size) { /* Declare variables. */ u8 key_source[se::AesBlockSize]; u8 key[se::AesBlockSize]; u8 access_key[se::AesBlockSize]; /* Validate state. */ SMC_R_TRY(g_exp_mod_result); SMC_R_UNLESS(dst_size == sizeof(access_key), InvalidArgument); /* We want to relinquish our security engine lock at the end of scope. */ ON_SCOPE_EXIT { UnlockSecurityEngine(); }; /* Get the async args. */ const auto &async_args = GetPrepareEsDeviceUniqueKeyAsyncArguments(); /* Get the exponentiation output. */ alignas(8) u8 msg[se::RsaSize]; se::GetRsaResult(msg, sizeof(msg)); /* Decode the key. */ { /* Get the label digest. */ u8 label_digest[crypto::Sha256Generator::HashSize]; async_args.GetLabelDigest(label_digest); /* Decode the key source. */ const size_t key_source_size = se::DecodeRsaOaepSha256(key_source, sizeof(key_source), msg, sizeof(msg), label_digest, sizeof(label_digest)); SMC_R_UNLESS(key_source_size == sizeof(key_source), InvalidArgument); } /* Decrypt the key. */ DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), async_args.GetCommonKeyType(), async_args.GetKeyGeneration()); PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key)); /* Copy the access key to output. */ std::memcpy(dst, access_key, sizeof(access_key)); return SmcResult::Success; } } SmcResult SmcModularExponentiate(SmcArguments &args) { return LockSecurityEngineAndInvokeAsync(args, ModularExponentiateImpl, GetModularExponentiateResult); } SmcResult SmcModularExponentiateByStorageKey(SmcArguments &args) { return LockSecurityEngineAndInvokeAsync(args, ModularExponentiateByStorageKeyImpl, GetModularExponentiateResult); } SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args) { return LockSecurityEngineAndInvokeAsync(args, PrepareEsDeviceUniqueKeyImpl, GetPrepareEsDeviceUniqueKeyResult); } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_rsa.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" namespace ams::secmon::smc { SmcResult SmcModularExponentiate(SmcArguments &args); SmcResult SmcModularExponentiateByStorageKey(SmcArguments &args); SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args); } ================================================ FILE: exosphere/program/source/smc/secmon_smc_se_lock.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../secmon_error.hpp" #include "secmon_smc_se_lock.hpp" namespace ams::secmon::smc { namespace { constinit util::Atomic<bool> g_is_locked = false; ALWAYS_INLINE bool TryLockSecurityEngineImpl() { bool value = false; return g_is_locked.CompareExchangeStrong(value, true); } ALWAYS_INLINE void UnlockSecurityEngineImpl() { g_is_locked = false; } ALWAYS_INLINE bool IsSecurityEngineLockedImpl() { return g_is_locked.Load(); } } bool TryLockSecurityEngine() { return TryLockSecurityEngineImpl(); } void UnlockSecurityEngine() { return UnlockSecurityEngineImpl(); } bool IsSecurityEngineLocked() { return IsSecurityEngineLockedImpl(); } SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl) { /* Try to lock the security engine. */ SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy); ON_SCOPE_EXIT { UnlockSecurityEngineImpl(); }; return impl(args); } SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler) { /* Try to lock the security engine. */ SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy); auto se_guard = SCOPE_GUARD { UnlockSecurityEngineImpl(); }; /* Try to start an async operation. */ const u64 async_key = BeginAsyncOperation(result_handler); SMC_R_UNLESS(async_key != InvalidAsyncKey, Busy); auto async_guard = SCOPE_GUARD { CancelAsyncOperation(async_key); }; /* Try to invoke the operation. */ SMC_R_TRY(impl(args)); /* We succeeded! Cancel our guards, and return the async key to our caller. */ async_guard.Cancel(); se_guard.Cancel(); args.r[1] = async_key; return SmcResult::Success; } } ================================================ FILE: exosphere/program/source/smc/secmon_smc_se_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "secmon_smc_common.hpp" #include "secmon_smc_handler.hpp" #include "secmon_smc_result.hpp" namespace ams::secmon::smc { bool TryLockSecurityEngine(); void UnlockSecurityEngine(); bool IsSecurityEngineLocked(); SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl); SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler); } ================================================ FILE: exosphere/program/split_program.py ================================================ #!/usr/bin/env python import sys, lz4 from struct import unpack as up def lz4_compress(data): try: import lz4.block as block except ImportError: block = lz4.LZ4_compress return block.compress(data, 'high_compression', store_size=False) def split_binary(data): A, B, START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START, C, D = up('<QQQQQQQQ', data[:0x40]) assert A == 0xAAAAAAAAAAAAAAAA assert B == 0xBBBBBBBBBBBBBBBB assert C == 0xCCCCCCCCCCCCCCCC assert D == 0xDDDDDDDDDDDDDDDD data = data[0x40:] #print ('%X %X %X %X' % (START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START)) boot_code = data[BOOT_CODE_START - START:BOOT_CODE_END - BOOT_CODE_START] program = data[PROGRAM_START - START:] return [('boot_code.lz4', lz4_compress(boot_code)), ('program.lz4', lz4_compress(program))] def main(argc, argv): if argc != 3: print('Usage: %s in outdir' % argv[0]) return 1 with open(argv[1], 'rb') as f: data = f.read() assert len(data) >= 0x40 for (fn, fdata) in split_binary(data): with open('%s/%s' % (argv[2], fn), 'wb') as f: f.write(fdata) return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv)) ================================================ FILE: exosphere/sdmmc_test/Makefile ================================================ #--------------------------------------------------------------------------------- # Define the atmosphere board and cpu #--------------------------------------------------------------------------------- export ATMOSPHERE_BOARD := nx-hac-001 export ATMOSPHERE_CPU := arm7tdmi #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(CURDIR) export DEPSDIR := $(CURDIR)/$(BUILD) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib -L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: $(BUILD) clean all #--------------------------------------------------------------------------------- all: $(BUILD) check_libexo $(BUILD): check_libexo @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile check_libexo: @$(MAKE) --no-print-directory -C ../../libraries/libexosphere arm #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf *.lz4 #--------------------------------------------------------------------------------- else .PHONY: all DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- all : $(OUTPUT).bin $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) ../../../libraries/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/sdmmc_test/sdmmc_test.ld ================================================ OUTPUT_ARCH(arm) ENTRY(_ZN3ams10sdmmc_test5StartEv) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K test_fw : ORIGIN = 0x40010000, LENGTH = 32K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(test_fw)); . = __start__; __code_start = . ; .crt0 : { KEEP (*(.crt0 .crt0.*)) . = ALIGN(8); } >test_fw .vectors : { KEEP (*(.vectors .vectors.*)) . = ALIGN(8); } >test_fw .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >test_fw .init : { KEEP( *(.init) ) . = ALIGN(8); } >test_fw .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >test_fw .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >test_fw /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >test_fw .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >test_fw .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >test_fw .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >test_fw .hash : { *(.hash) } >test_fw /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >test_fw .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >test_fw .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >test_fw .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >test_fw .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >test_fw .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >test_fw .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >test_fw .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >test_fw .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >test_fw __got_start__ = .; .got : { *(.got) *(.igot) } >test_fw .got.plt : { *(.got.plt) *(.igot.plt) } >test_fw __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >test_fw __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >test_fw __bss_end__ = .; __end__ = ABSOLUTE(.) ; __total_size__ = (__end__ - __start__); __stack_top__ = 0x40031000; __stack_bottom__ = 0x40030000; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/sdmmc_test/sdmmc_test.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(TOPDIR /sdmmc_test.ld) --gc-sections --nmagic ================================================ FILE: exosphere/sdmmc_test/source/sdmmc_test_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::sdmmc_test { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline auto Port = sdmmc::Port_SdCard0; alignas(8) constinit u8 g_sd_work_buffer[sdmmc::SdCardWorkBufferSize]; constexpr inline u32 SectorIndex = 0; constexpr inline u32 SectorCount = 2; NORETURN void PmcMainReboot() { /* Write enable to MAIN_RESET. */ reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE)); /* Wait forever until we're reset. */ AMS_INFINITE_LOOP(); } void CheckResult(const Result result) { volatile u32 * const DEBUG = reinterpret_cast<volatile u32 *>(0x4003C000); if (R_FAILED(result)) { DEBUG[1] = result.GetValue(); PmcMainReboot(); } } } void Main() { /* Perform butchered hwinit. */ /* TODO: replace with simpler, non-C logic. */ /* nx_hwinit(); */ /* Clear output buffer for debug. */ std::memset((void *)0x40038000, 0xAA, 0x400); /* Normally, these pins get configured by boot sysmodule during initial pinmux config. */ /* However, they're required to access the SD card. */ { const uintptr_t apb_misc = dd::QueryIoMapping(0x70000000, 0x4000); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_CLK, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CLK_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_CMD, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CMD_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT3, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT3_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT2, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT2_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT1, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT1_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_SDMMC1_DAT0, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, SDMMC1)); reg::ReadWrite(apb_misc + PINMUX_AUX_DMIC3_CLK, PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, RSVD2)); } /* Debug signaler. */ volatile u32 * const DEBUG = reinterpret_cast<volatile u32 *>(0x4003C000); DEBUG[0] = 0; DEBUG[1] = 0xAAAAAAAA; /* Initialize sdmmc library. */ sdmmc::Initialize(Port); DEBUG[0] = 1; sdmmc::SetSdCardWorkBuffer(Port, g_sd_work_buffer, sizeof(g_sd_work_buffer)); DEBUG[0] = 2; Result result = sdmmc::Activate(Port); DEBUG[0] = 3; CheckResult(result); /* Read the first two sectors from disk. */ void * const sector_dst = reinterpret_cast<void *>(0x40038000); result = sdmmc::Read(sector_dst, SectorCount * sdmmc::SectorSize, Port, SectorIndex, SectorCount); DEBUG[0] = 4; CheckResult(result); /* Get the connection status. */ sdmmc::SpeedMode speed_mode; sdmmc::BusWidth bus_width; result = sdmmc::CheckSdCardConnection(std::addressof(speed_mode), std::addressof(bus_width), Port); /* Save status for debug. */ DEBUG[0] = 5; DEBUG[1] = result.GetValue(); DEBUG[2] = static_cast<u32>(speed_mode); DEBUG[3] = static_cast<u32>(bus_width); /* Perform a reboot. */ PmcMainReboot(); } NORETURN void ExceptionHandler() { PmcMainReboot(); } } namespace ams::diag { void AbortImpl() { sdmmc_test::ExceptionHandler(); } } ================================================ FILE: exosphere/sdmmc_test/source/sdmmc_test_start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .crt0.text._ZN3ams10sdmmc_test5StartEv, "ax", %progbits .align 3 .global _ZN3ams10sdmmc_test5StartEv _ZN3ams10sdmmc_test5StartEv: /* Switch to system mode, mask all interrupts, clear all flags */ msr cpsr_cxsf, #0xDF /* Set the stack pointer. */ ldr sp, =__stack_top__ /* Set our link register to the exception handler. */ ldr lr, =_ZN3ams10sdmmc_test16ExceptionHandlerEv /* Call init array functions. */ bl __libc_init_array /* Invoke main. */ b _ZN3ams10sdmmc_test4MainEv /* Infinite loop. */ 2: b 2b ================================================ FILE: exosphere/warmboot/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/warmboot.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/warmboot.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: exosphere/warmboot/source/warmboot_bootrom_workaround.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_clkrst.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t EMC = EMC_ADDRESS(0); } void ApplyMbistWorkaround() { /* Clear all LVL2 clock gate overrides to zero. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE, 0); /* Clear clock enable for all but a select few devices. */ auto devices_to_clear_l = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_l), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_RTC ), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_TMR ), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_GPIO ), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_CACHE2)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, devices_to_clear_l); auto devices_to_clear_h = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_h), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_MEM ), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_PMC ), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_FUSE), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_EMC )); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, devices_to_clear_h); auto devices_to_clear_u = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_u), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CSITE), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMA), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMB), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMC), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMD), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CRAM2)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_CLR, devices_to_clear_u); auto devices_to_clear_v = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_v), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_MSELECT ), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SPDIF_DOUBLER), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_TZRAM ), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SE )); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_CLR, devices_to_clear_v); auto devices_to_clear_w = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_w), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX0), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX1), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX2), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX3), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX4), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX5), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_ENTROPY)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, devices_to_clear_w); auto devices_to_clear_x = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_x), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CAPA ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CBPA ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CPU ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_BBC ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_EMC_DLL ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_GPU ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_DBGAPB ), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_PLLG_REF)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_CLR, devices_to_clear_x); auto devices_to_clear_y = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y); reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_y), CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CCPA), CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CDPA)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_CLR, devices_to_clear_y); /* If CH1 is enabled, enable clock to MC1. */ if (reg::HasValue(EMC + EMC_FBIO_CFG7, EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE))) { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE)); } } } ================================================ FILE: exosphere/warmboot/source/warmboot_bootrom_workaround.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void ApplyMbistWorkaround(); } ================================================ FILE: exosphere/warmboot/source/warmboot_clkrst.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_clkrst.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t TIMER = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); } void ConfigureOscillators() { /* Enable the crystal oscillator, and copy the drive strength from pmc. */ const auto xofs = reg::GetValue(PMC + APBDEV_PMC_OSC_EDPD_OVER, PMC_REG_BITS_MASK(OSC_EDPD_OVER_XOFS)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_OSC_CTRL, CLK_RST_REG_BITS_ENUM (OSC_CTRL_XOE, ENABLE), CLK_RST_REG_BITS_VALUE(OSC_CTRL_XOFS, xofs)); /* Configure CLK_M_DIVISOR to 2. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0, CLK_RST_REG_BITS_ENUM(SPARE_REG0_CLK_M_DIVISOR, CLK_M_DIVISOR2)); reg::Read(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0); /* Restore TIMERUS config to 19.2 MHz. */ reg::Write(TIMER + TIMERUS_USEC_CFG, TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVIDEND, 5 - 1), TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVISOR, 96 - 1)); } } ================================================ FILE: exosphere/warmboot/source/warmboot_clkrst.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void ConfigureOscillators(); } ================================================ FILE: exosphere/warmboot/source/warmboot_cpu_cluster.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_clkrst.hpp" #include "warmboot_util.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); constexpr inline const uintptr_t GPIO = secmon::MemoryRegionPhysicalDeviceGpio.GetAddress(); constexpr inline const uintptr_t MSELECT = MSELECT(0); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress(); ALWAYS_INLINE void EnableClusterPartition(const reg::BitsValue value, APBDEV_PMC_PWRGATE_TOGGLE_PARTID part_id) { /* Toggle the partitions if necessary. */ if (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) { reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE), PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, part_id)); } /* Wait for the toggle to complete. */ while (!reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, value)) { /* ... */ } /* Remove clamping. */ reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, value); /* Wait for clamping to be removed. */ while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, value)) { /* ... */ } } } void InitializeCpuCluster() { /* Set CoreSight reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_U_SET_SET_CSITE_RST, ENABLE)); /* Restore PROD setting to CPU_SOFTRST_CTRL2 by clearing CAR2PMC_CPU_ACK_WIDTH. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2, CLK_RST_REG_BITS_VALUE(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0)); /* Restore the CPU reset vector from PMC scratch. */ reg::Write(SYSTEM + SB_AA64_RESET_LOW, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH34) | 1); reg::Write(SYSTEM + SB_AA64_RESET_HIGH, reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH35)); /* Configure SUPER_CCLKG_DIVIDER. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKG_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKG_DIVIDER_SUPER_CDIV_ENB, ENABLE), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0)); /* Configure SUPER_CCLKLP_DIVIDER. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLKLP_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLKLP_DIVIDER_SUPER_CDIV_ENB, ENABLE), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0)); /* Enable CoreSight clock. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_SET_SET_CLK_ENB_CSITE, ENABLE)); /* Clear CoreSight reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_U_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_U_CLR_CLR_CSITE_RST, ENABLE)); /* Select MSELECT clock source as PLLP_OUT0 with divider of 4. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_MSELECT_MSELECT_CLK_SRC, PLLP_OUT0), CLK_RST_REG_BITS_VALUE(CLK_SOURCE_MSELECT_MSELECT_CLK_DIVISOR, 6)); /* Enable clock to MSELECT. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_MSELECT, ENABLE)); /* Wait two microseconds, then take MSELECT out of reset. */ util::WaitMicroSeconds(2); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_V_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_V_CLR_CLR_MSELECT_RST, ENABLE)); /* Workaround bug by disabling MSELECT error mechanism and enabling WRAP type conversion. */ reg::ReadWrite(MSELECT + MSELECT_CONFIG, MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE1, DISABLE), MSELECT_REG_BITS_ENUM(CONFIG_ERR_RESP_EN_SLAVE2, DISABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE0, ENABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE1, ENABLE), MSELECT_REG_BITS_ENUM(CONFIG_WRAP_TO_INCR_SLAVE2, ENABLE)); /* Disable PLLX. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, CLK_RST_REG_BITS_ENUM(PLLX_BASE_PLLX_ENABLE, DISABLE)); /* Clear bit 0 of PMC Scratch 190. */ reg::ReadWrite(PMC + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0)); /* Clear PMC_DPD_SAMPLE, and wait 10 us for clear to take effect. */ reg::Write(PMC + APBDEV_PMC_DPD_SAMPLE, 0); util::WaitMicroSeconds(10); /* Configure UART2_RTS low (GPIO controller 2 G). */ reg::ReadWrite(GPIO + 0x108, REG_BITS_VALUE(2, 1, 1)); /* GPIO_CNF */ reg::ReadWrite(GPIO + 0x118, REG_BITS_VALUE(2, 1, 1)); /* GPIO_OE */ reg::ReadWrite(GPIO + 0x128, REG_BITS_VALUE(2, 1, 0)); /* GPIO_OUT */ /* Tristate CLDVFS PWN. */ reg::Write(APB_MISC + PINMUX_AUX_DVFS_PWM, PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), PINMUX_REG_BITS_ENUM(AUX_DVFS_PWM_PM, CLDVFS)); reg::Read(APB_MISC + PINMUX_AUX_DVFS_PWM); /* Restore PWR_I2C E_INPUT. */ reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); reg::Write(APB_MISC + PINMUX_AUX_PWR_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); /* Enable CLDVFS clock. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DVFS, ENABLE)); /* Set CLDVFS clock source/divider. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_REF, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_REF_DVFS_REF_CLK_SRC, PLLP_OUT0), CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_REF_DVFS_REF_DIVISOR, 14)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_DVFS_SOC, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DVFS_SOC_DVFS_SOC_CLK_SRC, PLLP_OUT0), CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DVFS_SOC_DVFS_SOC_DIVISOR, 14)); /* Enable PWR_I2C controller (I2C5). */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_I2C5, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE)); util::WaitMicroSeconds(5); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_I2C5_I2C5_CLK_SRC, PLLP_OUT0), CLK_RST_REG_BITS_VALUE(CLK_SOURCE_I2C5_I2C5_CLK_DIVISOR, 4)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_I2C5_RST, ENABLE)); /* Set the EN bit in pmic regulator. */ pmic::SetEnBit(fuse::GetRegulator()); /* Wait 2ms. */ util::WaitMicroSeconds(2'000); /* Enable power to the CRAIL partition. */ EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CRAIL); /* Remove software clamp to CRAIL. */ reg::Write(PMC + APBDEV_PMC_SET_SW_CLAMP, 0); reg::Write(PMC + APBDEV_PMC_REMOVE_CLAMPING_CMD, PMC_REG_BITS_ENUM(REMOVE_CLAMPING_COMMAND_CRAIL, ENABLE)); while (reg::HasValue(PMC + APBDEV_PMC_CLAMP_STATUS, PMC_REG_BITS_ENUM(CLAMP_STATUS_CRAIL, ENABLE))) { /* ... */ } /* Spinloop 8 times, to add a little delay. */ SpinLoop(8); /* Disable PWR_I2C controller (I2C5). */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_I2C5_RST, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_I2C5, ENABLE)); /* Disable CLDVFS clock. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLR_CLR_CLK_ENB_DVFS, ENABLE)); /* Perform fast cluster RAM repair if needed. */ if (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, SLOW))) { reg::Write(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_REQ, ENABLE)); while (!reg::HasValue(FLOW_CTLR + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_STS, DONE))) { /* ... */ } } /* Enable power to the non-cpu partition. */ EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_C0NC, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_C0NC); /* Enable clock to PLLP_OUT_CPU. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_SET_SET_CLK_ENB_PLLP_OUT_CPU, ENABLE)); util::WaitMicroSeconds(2); /* Enable clock to the cpu complex. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_CPU, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_CPUG, ENABLE)); util::WaitMicroSeconds(10); /* Select cpu complex clock source. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKG_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLKLP_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN)); util::WaitMicroSeconds(10); /* Wake non-cpu out of reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, ENABLE)); } void PowerOnCpu() { /* Enable power to the CE0 partition. */ EnableClusterPartition(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CE0, ON), APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0); /* Clear CPU reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET0, ENABLE), CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET0, ENABLE)); } } ================================================ FILE: exosphere/warmboot/source/warmboot_cpu_cluster.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void InitializeCpuCluster(); void PowerOnCpu(); } ================================================ FILE: exosphere/warmboot/source/warmboot_dram.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_dram.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t EMC = EMC_ADDRESS(0); constexpr inline const uintptr_t EMC0 = EMC0_ADDRESS(0); constexpr inline const uintptr_t EMC1 = EMC1_ADDRESS(0); constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); constexpr inline const uintptr_t MC0 = secmon::MemoryRegionPhysicalDeviceMemoryController0.GetAddress(); constexpr inline const uintptr_t MC1 = secmon::MemoryRegionPhysicalDeviceMemoryController1.GetAddress(); } void RestrictBpmpAccessToMainMemory() { /* Bpmp memory access is restricted by forcing internal access to an invalid carveout. */ constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE)); constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE)); constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS), MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED), MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE)); /* Specify a 128KB carveout at NULL with no clients allowed access, and bpmp forced to access. */ reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, 1); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, ForceInternalAccess0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, ForceInternalAccess1); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4, 0); reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, CarveoutConfig); } void RestoreRamSvop() { reg::ReadWrite(APB_MISC + APB_MISC_GP_ASDBGREG, APB_MISC_REG_BITS_VALUE(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 2)); } void ConfigureEmcPmacroTraining() { /* Disable writes to BYTE0-7. */ reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, ENABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE)); /* Set E_WRPTR on Channel 0. */ reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_0, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_ENABLED, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_TRAIN_QPOP, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_RX_E_DIRECT_ZI, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_E_WRPTR, ENABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_0_CH0_TRAINING_DRV_DQS, DISABLED)); /* Set E_WRPTR on Channel 1. */ reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_1, EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_ENABLED, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_TRAIN_QPOP, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_RX_E_DIRECT_ZI, DISABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_E_WRPTR, ENABLED), EMC_REG_BITS_ENUM(PMACRO_TRAINING_CTRL_1_CH1_TRAINING_DRV_DQS, DISABLED)); /* Re-enable writes to BYTE0-7. */ reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD0, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD1, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD2, DISABLE), EMC_REG_BITS_ENUM(PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_CMD3, DISABLE)); } } ================================================ FILE: exosphere/warmboot/source/warmboot_dram.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void RestrictBpmpAccessToMainMemory(); void RestoreRamSvop(); void ConfigureEmcPmacroTraining(); } ================================================ FILE: exosphere/warmboot/source/warmboot_exception_vectors.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .vectors, "ax", %progbits .align 3 .global warmboot_header warmboot_header: /* TODO: If Mariko warmboothax ever happens, generate a mariko header? */ /* Warmboot header. */ .word __total_size__ .rept 3 .word 0x00000000 .endr /* RSA modulus. */ .rept 0x40 .word 0xFFFFFFFF .endr /* Padding */ .rept 4 .word 0x00000000 .endr /* RSA signature */ .rept 0x40 .word 0xFFFFFFFF .endr /* Padding */ .rept 4 .word 0x00000000 .endr /* Firmware metadata. */ .word __total_size__ .word _reset .word _reset .word __executable_size__ .global _reset _reset: b _ZN3ams8warmboot5StartEv .global _metadata _metadata: .ascii "WBT0" /* Magic number */ .word 0x00000000 /* Target firmware. */ .word 0x00000000 /* Reserved */ .word 0x00000000 /* Reserved */ ================================================ FILE: exosphere/warmboot/source/warmboot_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_bootrom_workaround.hpp" #include "warmboot_clkrst.hpp" #include "warmboot_cpu_cluster.hpp" #include "warmboot_dram.hpp" #include "warmboot_main.hpp" #include "warmboot_misc.hpp" #include "warmboot_secure_monitor.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); constexpr inline const uintptr_t ExpectedMetadataAddress = 0x40010244; } void Main(const Metadata *metadata) { /* Ensure that we're running under vaguely sane conditions. */ AMS_ABORT_UNLESS(metadata->magic == Metadata::Magic); /* Restrict the bpmp's access to dram. */ if (metadata->target_firmware >= TargetFirmware_4_0_0) { RestrictBpmpAccessToMainMemory(); } /* Configure rtck-daisychaining/jtag. */ ConfigureMiscSystemDebug(); /* NOTE: Here, Nintendo checks that the number of burnt anti-downgrade fuses is valid. */ /* NOTE: Here, Nintendo validates that APBDEV_PMC_SECURE_SCRATCH32 contains the correct magic number for the current warmboot firmware revision. */ /* Validate that we're executing at the correct address. */ AMS_ABORT_UNLESS(reinterpret_cast<uintptr_t>(metadata) == ExpectedMetadataAddress); /* Validate that we're executing on the bpmp. */ AMS_ABORT_UNLESS(reg::Read(PG_UP(PG_UP_TAG)) == PG_UP_TAG_PID_COP); /* Configure fuse bypass. */ fuse::ConfigureFuseBypass(); /* Configure system oscillators. */ ConfigureOscillators(); /* Restore DRAM configuration. */ RestoreRamSvop(); ConfigureEmcPmacroTraining(); /* If on Erista, work around the bootrom mbist issue. */ if (fuse::GetSocType() == fuse::SocType_Erista) { ApplyMbistWorkaround(); } /* Initialize the cpu cluster. */ InitializeCpuCluster(); /* Restore the secure monitor to tzram. */ RestoreSecureMonitorToTzram(metadata->target_firmware); /* Power on the cpu. */ PowerOnCpu(); /* Halt ourselves. */ while (true) { reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED)); } } NORETURN void ExceptionHandler() { /* Write enable to MAIN_RESET. */ reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE)); /* Wait forever until we're reset. */ AMS_INFINITE_LOOP(); } } namespace ams::diag { NORETURN void AbortImpl() { warmboot::ExceptionHandler(); } #include <exosphere/diag/diag_detailed_assertion_impl.inc> } ================================================ FILE: exosphere/warmboot/source/warmboot_main.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { struct Metadata { static constexpr u32 Magic = util::FourCC<'W','B','T','0'>::Code; u32 magic; ams::TargetFirmware target_firmware; u32 reserved[2]; }; static_assert(util::is_pod<Metadata>::value); static_assert(sizeof(Metadata) == 0x10); } ================================================ FILE: exosphere/warmboot/source/warmboot_misc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_misc.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress(); } void ConfigureMiscSystemDebug() { /* Enable RTCK daisy-chaining. */ reg::Write(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM(PP_CONFIG_CTL_TBE, ENABLE)); /* If we're in production mode, perform JTAG configuration. */ /* NOTE: While this is what NVidia's code does, this is almost certainly a logic error. */ /* They intend to configure JTAG only when *not* in production mode. */ /* However, here we will do what they do, and not what they intend. */ const bool production_mode = fuse::IsOdmProductionMode(); if (production_mode) { const bool jtag_sts = reg::HasValue(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM(STICKY_BITS_JTAG_STS, ENABLE)); reg::ReadWrite(SYSTEM + SB_PFCFG, SB_REG_BITS_ENUM_SEL(PFCFG_DBGEN, jtag_sts, ENABLE, DISABLE), SB_REG_BITS_ENUM_SEL(PFCFG_SPNIDEN, jtag_sts, ENABLE, DISABLE), SB_REG_BITS_ENUM (PFCFG_NIDEN, ENABLE), SB_REG_BITS_ENUM (PFCFG_SPIDEN, DISABLE)); reg::ReadWrite(APB_MISC + APB_MISC_PP_CONFIG_CTL, APB_MISC_REG_BITS_ENUM_SEL(PP_CONFIG_CTL_JTAG, jtag_sts, ENABLE, DISABLE)); } /* Configure HDA codec disable. */ reg::ReadWrite(PMC + APBDEV_PMC_STICKY_BITS, PMC_REG_BITS_ENUM_SEL(STICKY_BITS_HDA_LPBK_DIS, production_mode, ENABLE, DISABLE)); /* Set E_INPUT in PINMUX_AUX_GPIO_PA6 (needed by the XUSB and SATA controllers). */ reg::ReadWrite(APB_MISC + PINMUX_AUX_GPIO_PA6, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE)); } } ================================================ FILE: exosphere/warmboot/source/warmboot_misc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void ConfigureMiscSystemDebug(); } ================================================ FILE: exosphere/warmboot/source/warmboot_secure_monitor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "warmboot_secure_monitor.hpp" namespace ams::warmboot { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const pkg1::AesKeySlot SavedAesKeySlots[] = { pkg1::AesKeySlot_TzramSaveKek, pkg1::AesKeySlot_RandomForUserWrap, pkg1::AesKeySlot_RandomForKeyStorageWrap, pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_Master, pkg1::AesKeySlot_Device, }; constexpr ALWAYS_INLINE bool IsSavedAesKeySlot(int slot) { for (const auto SavedSlot : SavedAesKeySlots) { if (slot == SavedSlot) { return true; } } return false; } void ClearUnsavedSecurityEngineKeySlots() { /* Clear unsaved aes keys and all ivs. */ for (int slot = 0; slot < se::AesKeySlotCount; ++slot) { if (!IsSavedAesKeySlot(slot)) { se::ClearAesKeySlot(slot); } se::ClearAesKeyIv(slot); } /* Clear all rsa keys. */ for (int slot = 0; slot < se::RsaKeySlotCount; ++slot) { se::ClearRsaKeySlot(slot); } } void RestoreEncryptedTzram(void * const tzram_dst, const void * const tzram_src, size_t tzram_size) { /* Derive the save key from the save kek. */ const u32 key_source[se::AesBlockSize / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27)}; se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, sizeof(key_source)); /* Decrypt tzram. */ const u8 tzram_iv[se::AesBlockSize] = {}; se::DecryptAes256Cbc(tzram_dst, tzram_size, pkg1::AesKeySlot_TzramSaveKey, tzram_src, tzram_size, tzram_iv, sizeof(tzram_iv)); /* Calculate the cmac of decrypted tzram. */ u8 tzram_mac[se::AesBlockSize] = {}; se::ComputeAes256Cmac(tzram_mac, sizeof(tzram_mac), pkg1::AesKeySlot_TzramSaveKey, tzram_dst, tzram_size); /* Get the expected mac from pmc scratch. */ const u32 expected_mac[sizeof(tzram_mac) / sizeof(u32)] = { reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114), reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115)}; /* Validate that the calculated mac is correct. */ AMS_ABORT_UNLESS(crypto::IsSameBytes(tzram_mac, expected_mac, sizeof(tzram_mac))); } void RestoreSecureMonitorToTzramErista(const TargetFirmware target_fw) { /* Clear all unsaved security engine keyslots. */ ClearUnsavedSecurityEngineKeySlots(); /* Restore encrypted tzram contents. */ void * const tzram_src = secmon::MemoryRegionPhysicalDramSecureDataStoreTzram.GetPointer<void>(); void * const tzram_dst = secmon::MemoryRegionPhysicalTzramNonVolatile.GetPointer<void>(); const size_t tzram_size = secmon::MemoryRegionPhysicalTzramNonVolatile.GetSize(); RestoreEncryptedTzram(tzram_dst, tzram_src, tzram_size); /* Clear the tzram kek registers. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, 0); /* Clear the tzram cmac registers. */ reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, 0); reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, 0); /* Clear the keydata used to protect tzram. */ se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKek); se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); /* Clear the encrypted copy of tzram in dram. */ /* NOTE: This does not actually clear the encrypted copy, because BPMP access to main memory has been restricted. */ /* Nintendo seems to not realize this, though, so we'll do the same. */ std::memset(tzram_src, 0, tzram_size); /* Set Tzram to secure-world only. */ se::SetTzramSecure(); } } void RestoreSecureMonitorToTzram(const TargetFirmware target_fw) { /* If erista, perform restoration procedure. */ if (fuse::GetSocType() == fuse::SocType_Erista) { RestoreSecureMonitorToTzramErista(target_fw); } /* Lock secure scratch. */ pmc::LockSecureRegister(static_cast<pmc::SecureRegister>(pmc::SecureRegister_DramParameters | pmc::SecureRegister_Other)); /* Lockout fuses. */ fuse::Lockout(); } } ================================================ FILE: exosphere/warmboot/source/warmboot_secure_monitor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void RestoreSecureMonitorToTzram(const TargetFirmware target_fw); } ================================================ FILE: exosphere/warmboot/source/warmboot_start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams8warmboot5StartEv, "ax", %progbits .align 3 .global _ZN3ams8warmboot5StartEv _ZN3ams8warmboot5StartEv: /* Set CPSR_cf and CPSR_cf. */ msr cpsr_f, #0xC0 msr cpsr_cf, #0xD3 /* Set the stack pointer. */ ldr sp, =__stack_top__ /* Set our link register to the exception handler. */ ldr lr, =_ZN3ams8warmboot16ExceptionHandlerEv /* Invoke main. */ ldr r0, =_metadata b _ZN3ams8warmboot4MainEPKNS0_8MetadataE /* Infinite loop. */ 1: b 1b ================================================ FILE: exosphere/warmboot/source/warmboot_util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::warmboot { void SpinLoop(unsigned int num); } ================================================ FILE: exosphere/warmboot/source/warmboot_util_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams8warmboot8SpinLoopEj, "ax", %progbits .global _ZN3ams8warmboot8SpinLoopEj .thumb_func .syntax unified _ZN3ams8warmboot8SpinLoopEj: 1: /* Subtract one from the count. */ subs r0, r0, #1 /* If we aren't at zero, continue looping. */ bgt 1b /* Return. */ bx lr ================================================ FILE: exosphere/warmboot/warmboot.ld ================================================ OUTPUT_ARCH(arm) ENTRY(_reset) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K lp0fw : ORIGIN = 0x40010000, LENGTH = 16K } SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(lp0fw)); . = __start__; __code_start = . ; .vectors : { KEEP (*(.vectors .vectors.*)) . = ALIGN(8); } >lp0fw .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(8); } >lp0fw .init : { KEEP( *(.init) ) . = ALIGN(8); } >lp0fw .plt : { *(.plt) *(.iplt) . = ALIGN(8); } >lp0fw .fini : { KEEP( *(.fini) ) . = ALIGN(8); } >lp0fw /* =========== RODATA section =========== */ . = ALIGN(8); __rodata_start = . ; .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >lp0fw .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >lp0fw .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >lp0fw .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >lp0fw .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >lp0fw .hash : { *(.hash) } >lp0fw /* =========== DATA section =========== */ . = ALIGN(8); __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >lp0fw .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >lp0fw .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >lp0fw .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >lp0fw .preinit_array ALIGN(8) : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >lp0fw .init_array ALIGN(8) : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >lp0fw .fini_array ALIGN(8) : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >lp0fw .ctors ALIGN(8) : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >lp0fw .dtors ALIGN(8) : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >lp0fw __got_start__ = .; .got : { *(.got) *(.igot) } >lp0fw .got.plt : { *(.got.plt) *(.igot.plt) } >lp0fw __got_end__ = .; .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >lp0fw __bss_start__ = .; .bss ALIGN(8) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(16); } >lp0fw __bss_end__ = .; __end__ = ABSOLUTE(.) ; __total_size__ = (__end__ - __start__); __executable_size__ = (__end__ - _reset); __stack_top__ = 0x40013000; __stack_bottom__ = 0x40012000; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: exosphere/warmboot/warmboot.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: exosphere/warmboot/warmboot.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /warmboot.ld) --gc-sections --nmagic ================================================ FILE: fusee/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/fusee.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/fusee.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: fusee/build_package3.py ================================================ #!/usr/bin/env python import sys, lz4, hashlib, os from struct import unpack as up, pack as pk def lz4_compress(data): try: import lz4.block as block except ImportError: block = lz4.LZ4_compress return block.compress(data, 'high_compression', store_size=False) def read_file(fn): with open(fn, 'rb') as f: return f.read() def pad(data, size): assert len(data) <= size return (data + b'\x00' * size)[:size] def get_overlay(program, i): return program[0x2B000 + 0x14000 * i:0x2B000 + 0x14000 * (i+1)] KIP_NAMES = [b'Loader', b'NCM', b'ProcessManager', b'sm', b'boot', b'spl', b'ams_mitm'] def get_kips(ams_dir, build_out_dir): emummc = read_file(os.path.join(ams_dir, 'emummc/emummc_unpacked.kip')) loader = read_file(os.path.join(ams_dir, 'stratosphere/loader/%s/loader.kip' % build_out_dir)) ncm = read_file(os.path.join(ams_dir, 'stratosphere/ncm/%s/ncm.kip' % build_out_dir)) pm = read_file(os.path.join(ams_dir, 'stratosphere/pm/%s/pm.kip' % build_out_dir)) sm = read_file(os.path.join(ams_dir, 'stratosphere/sm/%s/sm.kip' % build_out_dir)) boot = read_file(os.path.join(ams_dir, 'stratosphere/boot/%s/boot.kip' % build_out_dir)) spl = read_file(os.path.join(ams_dir, 'stratosphere/spl/%s/spl.kip' % build_out_dir)) ams_mitm = read_file(os.path.join(ams_dir, 'stratosphere/ams_mitm/%s/ams_mitm.kip' % build_out_dir)) return (emummc, { b'Loader' : loader, b'NCM' : ncm, b'ProcessManager' : pm, b'sm' : sm, b'boot' : boot, b'spl' : spl, b'ams_mitm' : ams_mitm, }) def write_kip_meta(f, kip, ofs): # Write program id f.write(kip[0x10:0x18]) # Write offset, size f.write(pk('<II', ofs - 0x100000, len(kip))) # Write hash f.write(hashlib.sha256(kip).digest()) def write_header(f, all_kips, wb_size, tk_size, xf_size, ex_size, ms_size, fs_size, rb_size, git_revision, major, minor, micro, relstep, s_major, s_minor, s_micro, s_relstep): # Unpack kips emummc, kips = all_kips # Write magic as PK31 magic. f.write(b'PK31') # Write metadata offset = 0x10 f.write(pk('<I', 0x20)) # Write flags f.write(pk('<I', 0x00000000)) # Write meso_size f.write(pk('<I', ms_size)) # Write num_kips f.write(pk('<I', len(KIP_NAMES))) # Write reserved1 f.write(b'\xCC' * 0xC) # Write legacy magic f.write(b'FSS0') # Write total size f.write(pk('<I', 0x800000)) # Write reserved2 f.write(pk('<I', 0xCCCCCCCC)) # Write content_header_offset f.write(pk('<I', 0x40)) # Write num_content_headers; f.write(pk('<I', 8 + len(KIP_NAMES))) # Write supported_hos_version; f.write(pk('<BBBB', s_relstep, s_micro, s_minor, s_major)) # Write release_version; f.write(pk('<BBBB', relstep, micro, minor, major)) # Write git_revision; f.write(pk('<I', git_revision)) # Write content metas f.write(pk('<IIBBBBI16s', 0x000800, wb_size, 2, 0, 0, 0, 0xCCCCCCCC, b'warmboot')) f.write(pk('<IIBBBBI16s', 0x002000, tk_size, 12, 0, 0, 0, 0xCCCCCCCC, b'tsec_keygen')) f.write(pk('<IIBBBBI16s', 0x004000, xf_size, 11, 0, 0, 0, 0xCCCCCCCC, b'exosphere_fatal')) f.write(pk('<IIBBBBI16s', 0x048000, ex_size, 1, 0, 0, 0, 0xCCCCCCCC, b'exosphere')) f.write(pk('<IIBBBBI16s', 0x056000, ms_size, 10, 0, 0, 0, 0xCCCCCCCC, b'mesosphere')) f.write(pk('<IIBBBBI16s', 0x7C0000, fs_size, 0, 0, 0, 0, 0xCCCCCCCC, b'fusee')) f.write(pk('<IIBBBBI16s', 0x7E0000, rb_size, 3, 0, 0, 0, 0xCCCCCCCC, b'rebootstub')) f.write(pk('<IIBBBBI16s', 0x100000, len(emummc), 8, 0, 0, 0, 0xCCCCCCCC, b'emummc')) ofs = (0x100000 + len(emummc) + 0xF) & ~0xF for kip_name in KIP_NAMES: kip_data = kips[kip_name] f.write(pk('<IIBBBBI16s', ofs, len(kip_data), 6, 0, 0, 0, 0xCCCCCCCC, kip_name)) ofs += len(kip_data) ofs += 0xF ofs &= ~0xF # Pad to kip metas. f.write(b'\xCC' * (0x400 - 0x40 - (0x20 * (8 + len(KIP_NAMES))))) # Write emummc_meta. */ write_kip_meta(f, emummc, 0x100000) # Write kip metas ofs = (0x100000 + len(emummc) + 0xF) & ~0xF for kip_name in KIP_NAMES: kip_data = kips[kip_name] write_kip_meta(f, kip_data, ofs) ofs += len(kip_data) ofs += 0xF ofs &= ~0xF # Pad to end of header f.write(b'\xCC' * (0x800 - (0x400 + (1 + len(KIP_NAMES)) * 0x30))) def write_kips(f, all_kips): # Unpack kips emummc, kips = all_kips # Write emummc f.write(emummc) # Write kips tot = len(emummc) if (tot & 0xF): f.write(b'\xCC' * (0x10 - (tot & 0xF))) tot += 0xF tot &= ~0xF for kip_name in KIP_NAMES: kip_data = kips[kip_name] f.write(kip_data) tot += len(kip_data) if (tot & 0xF): f.write(b'\xCC' * (0x10 - (tot & 0xF))) tot += 0xF tot &= ~0xF # Pad to 3 MB f.write(b'\xCC' * (0x300000 - tot)) def main(argc, argv): if argc != 13: print('Usage: %s ams_dir build_out_dir build_boot_out_dir revision major minor micro relstep s_major s_minor s_micro s_relstep' % argv[0]) return 1 # Parse arguments ams_dir = argv[1] build_out_dir = argv[2] build_boot_out_dir = argv[3] revision = int(argv[4][:8], 16) major = int(argv[5]) minor = int(argv[6]) micro = int(argv[7]) relstep = int(argv[8]) s_major = int(argv[9]) s_minor = int(argv[10]) s_micro = int(argv[11]) s_relstep = int(argv[12]) # Read/parse fusee fusee_program = read_file(os.path.join(ams_dir, 'fusee/program/%s/program.bin' % build_boot_out_dir)) fusee_bin = read_file(os.path.join(ams_dir, 'fusee/%s/fusee.bin' % build_boot_out_dir)) erista_mtc = get_overlay(fusee_program, 1) mariko_mtc = get_overlay(fusee_program, 2) erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4] mariko_hsh = hashlib.sha256(mariko_mtc[:-4]).digest()[:4] # Read other files exosphere = read_file(os.path.join(ams_dir, 'exosphere/%s/exosphere.bin' % build_out_dir)) warmboot = read_file(os.path.join(ams_dir, 'exosphere/warmboot/%s/warmboot.bin' % build_boot_out_dir)) mariko_fatal = read_file(os.path.join(ams_dir, 'exosphere/mariko_fatal/%s/mariko_fatal.bin' % build_out_dir)) rebootstub = read_file(os.path.join(ams_dir, 'exosphere/program/rebootstub/%s/rebootstub.bin' % build_boot_out_dir)) mesosphere = read_file(os.path.join(ams_dir, 'mesosphere/%s/mesosphere.bin' % build_out_dir)) all_kips = get_kips(ams_dir, build_out_dir) tsec_keygen = read_file(os.path.join(ams_dir, 'fusee/program/tsec_keygen/tsec_keygen.bin')) splash_bin = read_file(os.path.join(ams_dir, 'img/splash.bin')) assert len(splash_bin) == 0x3C0000 with open(os.path.join(ams_dir, 'fusee/%s/package3' % build_boot_out_dir), 'wb') as f: # Write header write_header(f, all_kips, len(warmboot), len(tsec_keygen), len(mariko_fatal), len(exosphere), len(mesosphere), len(fusee_bin), len(rebootstub), revision, major, minor, micro, relstep, s_major, s_minor, s_micro, s_relstep) # Write warmboot f.write(pad(warmboot, 0x1800)) # Write TSEC Keygen f.write(pad(tsec_keygen, 0x2000)) # Write Mariko Fatal f.write(pad(mariko_fatal, 0x1C000)) # Write Erista MTC f.write(erista_mtc[:-4] + erista_hsh) # Write Mariko MTC f.write(mariko_mtc[:-4] + mariko_hsh) # Write exosphere f.write(pad(exosphere, 0xE000)) # Write mesosphere f.write(pad(mesosphere, 0xAA000)) # Write kips write_kips(f, all_kips) # Write Splash Screen f.write(splash_bin) # Write fusee f.write(pad(fusee_bin, 0x20000)) # Write rebootstub f.write(pad(rebootstub, 0x1000)) # Pad to 8 MB f.write(b'\xCC' * (0x800000 - 0x7E1000)) return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv)) ================================================ FILE: fusee/fusee.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../libraries/config/common.mk all: $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin: $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) @cp $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin @echo "Built fusee.bin..." $(CURRENT_DIRECTORY)/loader_stub/$(ATMOSPHERE_OUT_DIR)/loader_stub.bin: check_loader_stub @$(SILENTCMD)echo "Checked loader stub." $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.bin: check_program @$(SILENTCMD)echo "Checked program." $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." check_loader_stub: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/program/$(ATMOSPHERE_OUT_DIR)/program.bin @$(SILENTCMD)echo "Checking loader stub..." @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ATMOSPHERE_CHECKED_FUSEE_PROGRAM=1 check_program: $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(SILENTCMD)echo "Checking program..." @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR): @[ -d $@ ] || mkdir -p $@ clean: @echo clean ... @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/loader_stub -f $(CURRENT_DIRECTORY)/loader_stub/loader_stub.mk clean @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/program -f $(CURRENT_DIRECTORY)/program/program.mk clean @rm -fr $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR) @for i in $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done .PHONY: all clean check_lib check_loader_stub check_program ================================================ FILE: fusee/loader_stub/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/loader_stub.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: fusee/loader_stub/loader_stub.ld ================================================ OUTPUT_ARCH(arm) ENTRY(_ZN3ams6nxboot6loader5StartEv) MEMORY { NULL : ORIGIN = 0, LENGTH = 4K data : ORIGIN = 0x40010000, LENGTH = 0x28000 loader_stub : ORIGIN = 0x4003D000, LENGTH = 4K } SECTIONS { /* =========== CODE section =========== */ . = ORIGIN(data); __data_start__ = . ; .crt0 : { KEEP(*(.crt0 .crt0.*)) . = ALIGN(8); } >data /* =========== RODATA section =========== */ . = ALIGN(8); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(8); } >data .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >data .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >data .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >data .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >data .hash : { *(.hash) } >data /* =========== DATA section =========== */ . = ALIGN(8); .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >data .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >data .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >data .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >data .data ALIGN(8) : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } >data __bss_start__ = .; .bss (NOLOAD) : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(32); } >data :NONE __bss_end__ = .; __data_end__ = ABSOLUTE(.); .loader_stub : { . = ALIGN(32); PROVIDE (__loader_stub_start__ = ABSOLUTE(.)); PROVIDE (__loader_stub_lma__ = LOADADDR(.loader_stub)); fusee_loader_main.o(.text*) fusee_loader_uncompress.o(.text*) fusee_loader_error.o(.text*) *(.text.memcpy) fusee_loader_main.o(.rodata*) fusee_loader_uncompress.o(.rodata*) fusee_loader_error.o(.rodata*) fusee_loader_main.o(.data*) fusee_loader_uncompress.o(.data*) fusee_loader_error.o(.data*) . = ALIGN(32); PROVIDE (__loader_stub_end__ = ABSOLUTE(.)); } >loader_stub AT>data /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: fusee/loader_stub/loader_stub.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := program.lz4 #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4 @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." $(CURRENT_DIRECTORY)/../program/$(ATMOSPHERE_OUT_DIR)/program.lz4: check_fusee_program @$(SILENTCMD)echo "Checked fusee program." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif ifeq ($(ATMOSPHERE_CHECKED_FUSEE_PROGRAM),1) check_fusee_program: else check_fusee_program: check_lib @$(MAKE) --no-print-directory -C $(CURRENT_DIRECTORY)/../program -f $(CURRENT_DIRECTORY)/../program/program.mk ATMOSPHERE_CHECKED_LIBEXOSPHERE=1 endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) program.lz4.o: program.lz4 @echo $(notdir $<) @$(bin2o) $(OFILES_SRC) : $(OFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: fusee/loader_stub/loader_stub.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /loader_stub.ld) --gc-sections --nmagic ================================================ FILE: fusee/loader_stub/source/fusee_loader_error.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_loader_error.hpp" namespace ams::diag { NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { AMS_UNUSED(expr, func, line, file); ams::nxboot::loader::ErrorStop(); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { AMS_UNUSED(expr, func, line, file, format); ams::nxboot::loader::ErrorStop(); } NORETURN void AbortImpl() { ams::nxboot::loader::ErrorStop(); } } namespace ams::nxboot::loader { NORETURN void ErrorStop() { /* Halt ourselves. */ while (true) { reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED)); } } } ================================================ FILE: fusee/loader_stub/source/fusee_loader_error.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot::loader { NORETURN void ErrorStop(); } ================================================ FILE: fusee/loader_stub/source/fusee_loader_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_loader_uncompress.hpp" #include "program_lz4.h" namespace ams::nxboot::loader { namespace { constexpr uintptr_t ProgramImageBase = 0x40001000; constexpr uintptr_t ProgramImageEnd = 0x4003D000; constexpr size_t ProgramImageSizeMax = ProgramImageEnd - ProgramImageBase; void CopyBackwards(void *dst, const void *src, size_t size) { u8 *dst_8 = static_cast<u8 *>(dst) + size; const u8 *src_8 = static_cast<const u8 *>(src) + size; for (size_t i = 0; i < size; ++i) { *(--dst_8) = *(--src_8); } } } NORETURN void UncompressAndExecute(const void *program, size_t program_size) { /* Relocate the compressed binary to a place where we can safely decompress it. */ void *relocated_program = reinterpret_cast<void *>(ProgramImageEnd - program_size); if (relocated_program != program) { CopyBackwards(relocated_program, program, program_size); } /* Uncompress the program image. */ Uncompress(reinterpret_cast<void *>(ProgramImageBase), ProgramImageSizeMax, relocated_program, program_size); /* Jump to the boot image. */ reinterpret_cast<void (*)()>(ProgramImageBase)(); /* We will never reach this point. */ __builtin_unreachable(); } } ================================================ FILE: fusee/loader_stub/source/fusee_loader_start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .crt0._ZN3ams6nxboot6loader5StartEv, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot6loader5StartEv .type _ZN3ams6nxboot6loader5StartEv, %function _ZN3ams6nxboot6loader5StartEv: /* Switch to system mode, mask all interrupts, clear all flags */ msr cpsr_cxsf, #0xDF /* Relocate main program. */ ldr r0, =_ZN3ams6nxboot6loader5StartEv adr r1, _ZN3ams6nxboot6loader5StartEv cmp r0, r1 beq 3f /* Relocate first 0x100. */ mov r4, #0x100 0: ldmia r1!, {r5-r12} stmia r0!, {r5-r12} subs r4, #0x20 bne 0b /* Jump, continue relocating. */ ldr r3, =1f bx r3 1: ldr r4, =__loader_stub_lma__ ldr r3, =__loader_stub_end__ add r4, r4, r3 ldr r3, =__loader_stub_start__ sub r4, r4, r3 sub r4, r4, r0 2: ldmia r1!, {r5-r12} stmia r0!, {r5-r12} subs r4, #0x20 bne 2b /* Relocate loader stub. */ 3: ldr r2, =__loader_stub_lma__ ldr r3, =__loader_stub_start__ ldr r4, =__loader_stub_end__ sub r4, r4, r3 4: ldmia r2!, {r5-r12} stmia r3!, {r5-r12} subs r4, #0x20 bne 4b /* Set the stack pointer */ ldr sp, =0x40001000 mov fp, #0 /* Generate arguments. */ ldr r3, =program_lz4 ldr r4, =program_lz4_end sub r4, r4, r3 mov r0, r3 mov r1, r4 /* Jump to the loader stub. */ ldr r3, =_ZN3ams6nxboot6loader20UncompressAndExecuteEPKvj bx r3 ================================================ FILE: fusee/loader_stub/source/fusee_loader_uncompress.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_loader_uncompress.hpp" namespace ams::nxboot::loader { namespace { class Lz4Uncompressor { private: const u8 *m_src; size_t m_src_size; size_t m_src_offset; u8 *m_dst; size_t m_dst_size; size_t m_dst_offset; public: Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) { /* ... */ } void Uncompress() { while (true) { /* Read a control byte. */ const u8 control = this->ReadByte(); /* Copy what it specifies we should copy. */ this->Copy(this->GetCopySize(control >> 4)); /* If we've exceeded size, we're done. */ if (m_src_offset >= m_src_size) { break; } /* Read the wide copy offset. */ u16 wide_offset = this->ReadByte(); AMS_ABORT_UNLESS(this->CanRead()); wide_offset |= (this->ReadByte() << 8); /* Determine the copy size. */ const size_t wide_copy_size = this->GetCopySize(control & 0xF); /* Copy bytes. */ const size_t end_offset = m_dst_offset + wide_copy_size + 4; for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) { AMS_ABORT_UNLESS(wide_offset <= cur_offset); m_dst[cur_offset] = m_dst[cur_offset - wide_offset]; } } } private: u8 ReadByte() { return m_src[m_src_offset++]; } bool CanRead() const { return m_src_offset < m_src_size; } size_t GetCopySize(u8 control) { size_t size = control; if (control >= 0xF) { do { AMS_ABORT_UNLESS(this->CanRead()); control = this->ReadByte(); size += control; } while (control == 0xFF); } return size; } void Copy(size_t size) { __builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size); m_dst_offset += size; m_src_offset += size; } }; } void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Create and execute a decompressor. */ Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress(); } } ================================================ FILE: fusee/loader_stub/source/fusee_loader_uncompress.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot::loader { void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size); } ================================================ FILE: fusee/program/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/program.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: fusee/program/lz4_compress.py ================================================ #!/usr/bin/env python import sys, lz4, hashlib from struct import unpack as up, pack as pk def lz4_compress(data): try: import lz4.block as block except ImportError: block = lz4.LZ4_compress return block.compress(data, 'high_compression', store_size=False) def read_file(fn): with open(fn, 'rb') as f: return f.read() def get_overlay(program, i): return program[0x2B000 + 0x14000 * i:0x2B000 + 0x14000 * (i+1)] def main(argc, argv): if argc != 3: print('Usage: %s in out' % argv[0]) return 1 data = read_file(argv[1]) erista_mtc = get_overlay(data, 1) mariko_mtc = get_overlay(data, 2) erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4] mariko_hsh = hashlib.sha256(mariko_mtc[:-4]).digest()[:4] fusee_program = lz4_compress(data[:0x2B000 - 8] + erista_hsh + mariko_hsh + get_overlay(data, 0)[:0x11000]) with open(argv[2], 'wb') as f: f.write(fusee_program) return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv)) ================================================ FILE: fusee/program/program.ld ================================================ OUTPUT_ARCH(arm) ENTRY(_ZN3ams6nxboot5StartEv) SECTIONS { /* =========== CODE section =========== */ PROVIDE(__start__ = ORIGIN(main)); . = __start__; __main_start__ = . ; .crt0 : { FILL(0x00000000) KEEP (*(.crt0 .crt0.*)) . = ORIGIN(main) + 0xC0 - 1; BYTE(00); } >main AT>glob .text : { FILL(0x00000000) KEEP(*(.text._ZN3ams4util15GetMicroSecondsEv)) KEEP(*(.text._ZN3ams4util16WaitMicroSecondsEi)) KEEP(*(.text.memcpy)) KEEP(*(.text.memset)) KEEP(*(.text.memcmp)) KEEP(*(.text._ZN3ams6nxboot14ShowFatalErrorEPKcz)) KEEP(*(.text._ZN3ams6nxboot10UncompressEPvjPKvj)) KEEP(*(.text._ZN3ams6nxboot12RebootToSelfEv)) _*.o(SORT(.text*)) *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(.text.exit .text.exit.*) *(.text.startup .text.startup.*) *(.text.hot .text.hot.*) *(.text .stub .text.* .gnu.linkonce.t.*) . = ALIGN(16); . = . + 15; BYTE(0x00); } >main AT>glob .init : { KEEP( *(.init) ) } >main AT>glob .plt : { *(.plt) *(.iplt) } >main AT>glob .fini : { KEEP( *(.fini) ) } >main AT>glob /* =========== RODATA section =========== */ __rodata_start = . ; .rodata : { FILL(0x00000000) *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(16); . = . + 15; BYTE(0x00); } >main AT>glob .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >main AT>glob .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >main AT>glob .hash : { *(.hash) } >main AT>glob /* =========== DATA section =========== */ __data_start = . ; .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >main AT>glob .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >main AT>glob .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >main AT>glob .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >main AT>glob .preinit_array : { PROVIDE (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE (__preinit_array_end = .); } >main AT>glob .init_array : { PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE (__init_array_end = .); } >main AT>glob .fini_array : { PROVIDE (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE (__fini_array_end = .); } >main AT>glob .ctors : { KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >main AT>glob .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >main AT>glob __got_start__ = .; .got : { *(.got) *(.igot) } >main .got.plt : { *(.got.plt) *(.igot.plt) } >main __got_end__ = .; .data : { FILL(0x00000000) *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) . = ALIGN(16); . = . + 15; BYTE(0x00); } >main AT>glob __bss_start__ = .; .main.fill : { FILL(0x00000000) *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ORIGIN(main) + LENGTH(main) - 1; BYTE(0x00); } >main AT>glob __bss_end__ = .; __main_end__ = ABSOLUTE(.) ; /* ================== ==== Metadata ==== ================== */ /* Discard sections that difficult post-processing */ /DISCARD/ : { *(.group .comment .note .interp) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } } ================================================ FILE: fusee/program/program.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../../libraries/config/templates/exosphere.mk #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export ATMOSPHERE_TOPDIR := $(CURRENT_DIRECTORY) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) BINFILES := #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(subst -,_,$(BINFILES)))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR)) .PHONY: clean all check_lib #--------------------------------------------------------------------------------- all: $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/$(notdir $(ATMOSPHERE_TOPDIR)) \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a: check_lib @$(SILENTCMD)echo "Checked library." ifeq ($(ATMOSPHERE_CHECKED_LIBEXOSPHERE),1) check_lib: else check_lib: @$(MAKE) --no-print-directory -C $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere -f $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/libexosphere.mk endif $(ATMOSPHERE_OUT_DIR) $(ATMOSPHERE_BUILD_DIR): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) #--------------------------------------------------------------------------------- else DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).lz4 : $(OUTPUT).bin $(SILENTCMD)$(PYTHON) $(CURRENT_DIRECTORY)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4 @echo built ... $(notdir $@) $(OUTPUT).bin : $(OUTPUT).elf $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@ @echo built ... $(notdir $@) $(OUTPUT).elf : $(OFILES) $(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/$(ATMOSPHERE_LIBRARY_DIR)/libexosphere.a %.elf: @echo linking $(notdir $@) $(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ @$(NM) -CSn $@ > $(notdir $*.lst) $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: fusee/program/program.specs ================================================ %rename link old_link *link: %(old_link) -T %:getenv(ATMOSPHERE_TOPDIR /program_ovl.ld) -T %:getenv(ATMOSPHERE_TOPDIR /program.ld) --gc-sections --nmagic ================================================ FILE: fusee/program/program_ovl.ld ================================================ MEMORY { NULL : ORIGIN = 0, LENGTH = 4K main : ORIGIN = 0x40001000, LENGTH = 0x2B000 ovl : ORIGIN = 0x4002C000, LENGTH = 0x14000 glob : ORIGIN = ORIGIN(main), LENGTH = LENGTH(main) + LENGTH(ovl) * 3 } SECTIONS { OVERLAY : NOCROSSREFS { .ovl_sein { fusee_secure_initialize.o(.text*); fusee_sdram.o(.text*); fusee_secure_initialize.o(.rodata*); fusee_sdram.o(.rodata*); fusee_secure_initialize.o(.data*); fusee_sdram.o(.data*); fusee_secure_initialize.o(.bss*); fusee_sdram.o(.bss*); FILL(0x00000000) . = ORIGIN(ovl) + LENGTH(ovl) - 1; BYTE(0x00); } .ovl_mtc_erista { KEEP(*(.text._ZN3ams6nxboot22DoMemoryTrainingEristaEiPv)) fusee_mtc_erista.o(.text*); fusee_mtc_erista.o(SORT(.rodata*)); fusee_mtc_erista.o(SORT(.data*)); fusee_mtc_erista.o(SORT(.bss*)); FILL(0x00000000) . = ORIGIN(ovl) + LENGTH(ovl) - 1; BYTE(0x00); } .ovl_mtc_mariko { KEEP(*(.text._ZN3ams6nxboot22DoMemoryTrainingMarikoEPbiPv)) fusee_mtc_mariko.o(.text*); fusee_mtc_mariko.o(SORT(.rodata*)); fusee_mtc_mariko.o(SORT(.data*)); fusee_mtc_mariko.o(SORT(.bss*)); FILL(0x00000000) . = ORIGIN(ovl) + LENGTH(ovl) - 1; BYTE(0x00); } } >ovl AT>glob } INSERT AFTER .main.fill ================================================ FILE: fusee/program/source/fatfs/diskio.c ================================================ /*-----------------------------------------------------------------------*/ /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ /* This is an example of glue functions to attach various exsisting */ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ #include <stdbool.h> #include <string.h> #include "ff.h" /* Obtains integer types */ #include "diskio.h" /* Declarations of disk functions */ #include "ffconf.h" #include "diskio_cpp.h" /*-----------------------------------------------------------------------*/ /* Get Drive Status */ /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return RES_OK; } /*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return RES_OK; } /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { switch (pdrv) { case DRIVE_SD: return diskio_read_sd_card(buff, count * 512, sector, count) ? RES_OK : RES_ERROR; case DRIVE_SYS: return diskio_read_system(buff, count * 512, sector, count) ? RES_OK : RES_ERROR; default: return RES_PARERR; } } /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ #if FF_FS_READONLY == 0 DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { switch (pdrv) { case DRIVE_SD: return diskio_write_sd_card(sector, count, buff, count * 512) ? RES_OK : RES_ERROR; case DRIVE_SYS: return diskio_write_system(sector, count, buff, count * 512) ? RES_OK : RES_ERROR; default: return RES_PARERR; } } #endif /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { return RES_OK; } ================================================ FILE: fusee/program/source/fatfs/diskio.h ================================================ /*-----------------------------------------------------------------------/ / Low level disk interface modlue include file (C)ChaN, 2019 / /-----------------------------------------------------------------------*/ #ifndef _DISKIO_DEFINED #define _DISKIO_DEFINED #ifdef __cplusplus extern "C" { #endif /* Status of Disk Functions */ typedef BYTE DSTATUS; /* Results of Disk Functions */ typedef enum { RES_OK = 0, /* 0: Successful */ RES_ERROR, /* 1: R/W Error */ RES_WRPRT, /* 2: Write Protected */ RES_NOTRDY, /* 3: Not Ready */ RES_PARERR /* 4: Invalid Parameter */ } DRESULT; /* Disk drives. */ typedef enum { DRIVE_SD, DRIVE_SYS, } DDRIVE; /*---------------------------------------*/ /* Prototypes for disk control functions */ DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ #define STA_NODISK 0x02 /* No medium in the drive */ #define STA_PROTECT 0x04 /* Write protected */ /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ #define CTRL_LOCK 6 /* Lock/Unlock media removal */ #define CTRL_EJECT 7 /* Eject media */ #define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ #define MMC_GET_TYPE 10 /* Get card type */ #define MMC_GET_CSD 11 /* Get CSD */ #define MMC_GET_CID 12 /* Get CID */ #define MMC_GET_OCR 13 /* Get OCR */ #define MMC_GET_SDSTAT 14 /* Get SD status */ #define ISDIO_READ 55 /* Read data form SD iSDIO register */ #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ /* ATA/CF specific ioctl command */ #define ATA_GET_REV 20 /* Get F/W revision */ #define ATA_GET_MODEL 21 /* Get model name */ #define ATA_GET_SN 22 /* Get serial number */ #ifdef __cplusplus } #endif #endif ================================================ FILE: fusee/program/source/fatfs/diskio_cpp.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef __cplusplus extern "C" { #endif bool diskio_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count); bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size); bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count); bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size); #ifdef __cplusplus } #endif ================================================ FILE: fusee/program/source/fatfs/ff.c ================================================ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem Module R0.14 / /-----------------------------------------------------------------------------/ / / Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wincompatible-pointer-types" #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- Module Private Definitions ---------------------------------------------------------------------------*/ #if FF_DEFINED != 86606 /* Revision ID */ #error Wrong include file (ff.h). #endif /* Limits and boundaries */ #define MAX_DIR 0x200000 /* Max size of FAT directory */ #define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ #define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ /* Character code support macros */ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') #define IsDigit(c) ((c) >= '0' && (c) <= '9') #define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) /* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ /* Additional file attribute bits for internal use */ #define AM_VOL 0x08 /* Volume label */ #define AM_LFN 0x0F /* LFN entry */ #define AM_MASK 0x3F /* Mask of defined bits */ /* Name status flags in fn[11] */ #define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ #define NS_NOLFN 0x40 /* Do not find LFN */ #define NS_NONAME 0x80 /* Not followed */ /* exFAT directory entry types */ #define ET_BITMAP 0x81 /* Allocation bitmap */ #define ET_UPCASE 0x82 /* Up-case table */ #define ET_VLABEL 0x83 /* Volume label */ #define ET_FILEDIR 0x85 /* File and directory */ #define ET_STREAM 0xC0 /* Stream extension */ #define ET_FILENAME 0xC1 /* Name extension */ /* FatFs refers the FAT structure as simple byte array instead of structure member / because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ #define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ #define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ #define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ #define BS_NTres 37 /* WindowsNT error flag (BYTE) */ #define BS_BootSig 38 /* Extended boot signature (BYTE) */ #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ #define BS_BootCode 62 /* Boot code (448-byte) */ #define BS_55AA 510 /* Signature word (WORD) */ #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ #define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ #define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ #define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ #define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ #define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ #define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ #define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ #define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ #define DIR_Name 0 /* Short file name (11-byte) */ #define DIR_Attr 11 /* Attribute (BYTE) */ #define DIR_NTres 12 /* Lower case flag (BYTE) */ #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ #define DIR_CrtTime 14 /* Created time (DWORD) */ #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ #define DIR_ModTime 22 /* Modified time (DWORD) */ #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ #define DIR_FileSize 28 /* File size (DWORD) */ #define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ #define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ #define LDIR_Type 12 /* LFN: Entry type (BYTE) */ #define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ #define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ #define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ #define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ #define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ #define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ #define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ #define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ #define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ #define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ #define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ #define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ #define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ #define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ #define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ #define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ #define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ #define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ #define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ #define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ #define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ #define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ #define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ #define SZDIRE 32 /* Size of a directory entry */ #define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ #define PTE_Boot 0 /* MBR PTE: Boot indicator */ #define PTE_StHead 1 /* MBR PTE: Start head */ #define PTE_StSec 2 /* MBR PTE: Start sector */ #define PTE_StCyl 3 /* MBR PTE: Start cylinder */ #define PTE_System 4 /* MBR PTE: System ID */ #define PTE_EdHead 5 /* MBR PTE: End head */ #define PTE_EdSec 6 /* MBR PTE: End sector */ #define PTE_EdCyl 7 /* MBR PTE: End cylinder */ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ #define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ #define GPTH_Rev 8 /* GPT: Revision (DWORD) */ #define GPTH_Size 12 /* GPT: Header size (DWORD) */ #define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ #define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ #define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ #define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ #define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ #define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ #define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ #define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ #define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ #define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ #define SZ_GPTE 128 /* GPT: Size of partition table entry */ #define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ #define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ #define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ #define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ #define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ #define GPTE_Name 56 /* GPT PTE: Name */ /* Post process on fatal error in the file operations */ #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } /* Re-entrancy related */ #if FF_FS_REENTRANT #if FF_USE_LFN == 1 #error Static LFN work area cannot be used at thread-safe configuration #endif #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif /* Definitions of logical drive - physical location conversion */ #if FF_MULTI_PARTITION #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ #else #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is associated with the same physical drive number */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif /* Definitions of sector size */ #if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) #error Wrong sector size configuration #endif #if FF_MAX_SS == FF_MIN_SS #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ #else #define SS(fs) ((fs)->ssize) /* Variable sector size */ #endif /* Timestamp */ #if FF_FS_NORTC == 1 #if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 #error Invalid FF_FS_NORTC settings #endif #define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) #else #define GET_FATTIME() get_fattime() #endif /* File lock controls */ #if FF_FS_LOCK != 0 #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif /* SBCS up-case tables (\x80-\xFF) */ #define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} #define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} #define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} #define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} /* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ /* <------> <------> <------> <------> <------> */ #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} #define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} /* Macros for table definitions */ #define MERGE_2STR(a, b) a ## b #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) /*-------------------------------------------------------------------------- Module Private Work Area ---------------------------------------------------------------------------*/ /* Remark: Variables defined here without initial value shall be guaranteed / zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ /*--------------------------------*/ /* File/Volume controls */ /*--------------------------------*/ #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 static BYTE CurrVol; /* Current drive */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif #if FF_LBA64 #if FF_MIN_GPT > 0x100000000 #error Wrong FF_MIN_GPT setting #endif static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7}; #endif /*--------------------------------*/ /* LFN/Directory working buffer */ /*--------------------------------*/ #if FF_USE_LFN == 0 /* Non-LFN configuration */ #if FF_FS_EXFAT #error LFN must be enabled when enable exFAT #endif #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #else /* LFN configurations */ #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 #error Wrong setting of FF_MAX_LFN #endif #if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF #endif #if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 #error Wrong setting of FF_LFN_UNICODE #endif static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ #define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ #if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ #if FF_FS_EXFAT static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() #endif #define LEAVE_MKFS(res) return res #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if FF_FS_EXFAT #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } #define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN #endif /* FF_USE_LFN == 1 */ #endif /* FF_USE_LFN == 0 */ /*--------------------------------*/ /* Code conversion tables */ /*--------------------------------*/ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct737[] = TBL_CT737; static const BYTE Ct771[] = TBL_CT771; static const BYTE Ct775[] = TBL_CT775; static const BYTE Ct850[] = TBL_CT850; static const BYTE Ct852[] = TBL_CT852; static const BYTE Ct855[] = TBL_CT855; static const BYTE Ct857[] = TBL_CT857; static const BYTE Ct860[] = TBL_CT860; static const BYTE Ct861[] = TBL_CT861; static const BYTE Ct862[] = TBL_CT862; static const BYTE Ct863[] = TBL_CT863; static const BYTE Ct864[] = TBL_CT864; static const BYTE Ct865[] = TBL_CT865; static const BYTE Ct866[] = TBL_CT866; static const BYTE Ct869[] = TBL_CT869; static const BYTE Dc932[] = TBL_DC932; static const BYTE Dc936[] = TBL_DC936; static const BYTE Dc949[] = TBL_DC949; static const BYTE Dc950[] = TBL_DC950; #elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); #else /* Static code page configuration (DBCS) */ #define CODEPAGE FF_CODE_PAGE static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); #endif /*-------------------------------------------------------------------------- Module Private Functions ---------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; rv = ptr[1]; rv = rv << 8 | ptr[0]; return rv; } static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; rv = ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #if FF_FS_EXFAT static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; rv = ptr[7]; rv = rv << 8 | ptr[6]; rv = rv << 8 | ptr[5]; rv = rv << 8 | ptr[4]; rv = rv << 8 | ptr[3]; rv = rv << 8 | ptr[2]; rv = rv << 8 | ptr[1]; rv = rv << 8 | ptr[0]; return rv; } #endif #if !FF_FS_READONLY static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #if FF_FS_EXFAT static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } #endif #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ /* Copy memory to memory */ static void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; if (cnt != 0) { do { *d++ = *s++; } while (--cnt); } } /* Fill memory block */ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; do { *d++ = (BYTE)val; } while (--cnt); } /* Compare memory block */ static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ { const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; do { r = *d++ - *s++; } while (--cnt && r == 0); return r; } /* Check if chr is contained in the string */ static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ { while (*str && *str != chr) str++; return *str; } /* Test if the byte is DBC 1st byte */ static int dbc_1st (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[0]) { if (c <= DbcTbl[1]) return 1; if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } /* Test if the byte is DBC 2nd byte */ static int dbc_2nd (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ } #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ if (c >= DbcTbl[4]) { if (c <= DbcTbl[5]) return 1; if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; } #else /* SBCS fixed code page */ if (c != 0) return 0; /* Always false */ #endif return 0; } #if FF_USE_LFN /* Get a Unicode code point from the TCHAR string in defined API encodeing */ static DWORD tchar2uni ( /* Returns a character in UTF-16 encoding (>=0x10000 on surrogate pair, 0xFFFFFFFF on decode error) */ const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ ) { DWORD uc; const TCHAR *p = *str; #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; uc = *p++; /* Get a unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ uc = uc << 16 | wc; } #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ BYTE b; int nf; uc = (BYTE)*p++; /* Get an encoding unit */ if (uc & 0x80) { /* Multiple byte code? */ if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; } else { if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ uc &= 0x0F; nf = 2; } else { if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ uc &= 0x07; nf = 3; } else { /* Wrong sequence */ return 0xFFFFFFFF; } } } do { /* Get trailing bytes */ b = (BYTE)*p++; if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ uc = uc << 6 | (b & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ } #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ uc = (TCHAR)*p++; /* Get a unit */ if (uc >= 0x110000 || IsSurrogate(uc)) return 0xFFFFFFFF; /* Wrong code? */ if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ #else /* ANSI/OEM input */ BYTE b; WCHAR wc; wc = (BYTE)*p++; /* Get a byte */ if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ b = (BYTE)*p++; /* Get 2nd byte */ if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ wc = (wc << 8) + b; /* Make a DBC */ } if (wc != 0) { wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ } uc = wc; #endif *str = p; /* Next read pointer */ return uc; } /* Output a TCHAR string in defined API encoding */ static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Surrogate pair if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ ) { #if FF_LFN_UNICODE == 1 /* UTF-16 output */ WCHAR hs, wc; hs = (WCHAR)(chr >> 16); wc = (WCHAR)chr; if (hs == 0) { /* Single encoding unit? */ if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ *buf = wc; return 1; } if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ *buf++ = hs; *buf++ = wc; return 2; #elif FF_LFN_UNICODE == 2 /* UTF-8 output */ DWORD hc; if (chr < 0x80) { /* Single byte code? */ if (szb < 1) return 0; /* Buffer overflow? */ *buf = (TCHAR)chr; return 1; } if (chr < 0x800) { /* 2-byte sequence? */ if (szb < 2) return 0; /* Buffer overflow? */ *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 2; } if (chr < 0x10000) { /* 3-byte sequence? */ if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 3; } /* 4-byte sequence */ if (szb < 4) return 0; /* Buffer overflow? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 4; #elif FF_LFN_UNICODE == 3 /* UTF-32 output */ DWORD hc; if (szb < 1) return 0; /* Buffer overflow? */ if (chr >= 0x10000) { /* Out of BMP? */ hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ chr = (hc | chr) + 0x10000; } *buf++ = (TCHAR)chr; return 1; #else /* ANSI/OEM output */ WCHAR wc; wc = ff_uni2oem(chr, CODEPAGE); if (wc >= 0x100) { /* Is this a DBC? */ if (szb < 2) return 0; *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ return 2; } if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ *buf++ = (TCHAR)wc; /* Store the character */ return 1; #endif } #endif /* FF_USE_LFN */ #if FF_FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ static int lock_fs ( /* 1:Ok, 0:timeout */ FATFS* fs /* Filesystem object */ ) { return ff_req_grant(fs->sobj); } static void unlock_fs ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { ff_rel_grant(fs->sobj); } } #endif #if FF_FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ static FRESULT chk_lock ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) { UINT i, be; /* Search open object table for the object */ be = 0; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } if (i == FF_FS_LOCK) { /* The object has not been opened */ return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ } /* The object was opened. Reject any open against writing file and all write mode open */ return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; return (i == FF_FS_LOCK) ? 0 : 1; } static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ if (Files[i].fs == dp->obj.fs && Files[i].clu == dp->obj.sclust && Files[i].ofs == dp->dptr) break; } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; Files[i].ofs = dp->dptr; Files[i].ctr = 0; } if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ return i + 1; /* Index number origin from 1 */ } static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { WORD n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { res = FR_INT_ERR; /* Invalid index nunber */ } return res; } static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { UINT i; for (i = 0; i < FF_FS_LOCK; i++) { if (Files[i].fs == fs) Files[i].fs = 0; } } #endif /* FF_FS_LOCK != 0 */ /*-----------------------------------------------------------------------*/ /* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res = FR_OK; if (fs->wflag) { /* Is the disk access window dirty? */ if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write it back into the volume */ fs->wflag = 0; /* Clear window dirty flag */ if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } } else { res = FR_DISK_ERR; } } return res; } #endif static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector LBA to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; if (sect != fs->winsect) { /* Window offset changed? */ #if !FF_FS_READONLY res = sync_window(fs); /* Flush the window */ #endif if (res == FR_OK) { /* Fill sector window with new data */ if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) { sect = (LBA_t)0 - 1; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } fs->winsect = sect; } } return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { FRESULT res; res = sync_window(fs); if (res == FR_OK) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); st_dword(fs->win + FSI_Free_Count, fs->free_clst); st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; disk_write(fs->pdrv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the lower layer */ if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; } #endif /*-----------------------------------------------------------------------*/ /* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ static LBA_t clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) { clst -= 2; /* Cluster number is origin from 2 */ if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ return fs->database + (LBA_t)fs->csize * clst; /* Start sector number of the cluster */ } /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; DWORD val; FATFS *fs = obj->fs; if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ val = 1; /* Internal error */ } else { val = 0xFFFFFFFF; /* Default value falls on disk error */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ break; #if FF_FS_EXFAT case FS_EXFAT : if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((LBA_t)((obj->objsize - 1) / SS(fs)) / fs->csize); /* Number of clusters - 1 */ if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ break; } if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ if (obj->n_frag != 0) { /* Is it on the growing edge? */ val = 0x7FFFFFFF; /* Generate EOC */ } else { if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; } break; } } /* go to default */ #endif default: val = 1; /* Internal error */ } } return val; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) { UINT bc; BYTE *p; FRESULT res = FR_INT_ERR; if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { case FS_FAT12 : bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc++ % SS(fs); *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Update 1st byte */ fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; p = fs->win + bc % SS(fs); *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Update 2nd byte */ fs->wflag = 1; break; case FS_FAT16 : res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ fs->wflag = 1; break; case FS_FAT32 : #if FF_FS_EXFAT case FS_EXFAT : #endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } st_dword(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } } return res; } #endif /* !FF_FS_READONLY */ #if FF_FS_EXFAT && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ /*--------------------------------------*/ /* Find a contiguous free cluster block */ /*--------------------------------------*/ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ ) { BYTE bm, bv; UINT i; DWORD val, scl, ctr; clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ val = 0; bm = 0; i = SS(fs); } if (bv == 0) { /* Is it a free cluster? */ if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ } while (bm != 0); bm = 1; } while (++i < SS(fs)); } } /*----------------------------------------*/ /* Set/Clear a block of allocation bitmap */ /*----------------------------------------*/ static FRESULT change_bitmap ( FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ int bv /* bit value to be set (0 or 1) */ ) { BYTE bm; UINT i; LBA_t sect; clst -= 2; /* The first bit corresponds to cluster #2 */ sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ i = clst / 8 % SS(fs); /* Byte offset in the sector */ bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { do { if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ fs->win[i] ^= bm; /* Flip the bit */ fs->wflag = 1; if (--ncl == 0) return FR_OK; /* All bits processed? */ } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ i = 0; } } /*---------------------------------------------*/ /* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_first_frag ( FFOBJID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; } obj->stat = 0; /* Change status 'FAT chain is valid' */ } return FR_OK; } /*---------------------------------------------*/ /* Fill the last fragment of the FAT chain */ /*---------------------------------------------*/ static FRESULT fill_last_frag ( FFOBJID* obj, /* Pointer to the corresponding object */ DWORD lcl, /* Last cluster of the fragment */ DWORD term /* Value to set the last FAT entry */ ) { FRESULT res; while (obj->n_frag > 0) { /* Create the chain of last fragment */ res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); if (res != FR_OK) return res; obj->n_frag--; } return FR_OK; } #endif /* FF_FS_EXFAT && !FF_FS_READONLY */ #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; DWORD nxt; FATFS *fs = obj->fs; #if FF_FS_EXFAT || FF_USE_TRIM DWORD scl = clst, ecl = clst; #endif #if FF_USE_TRIM LBA_t rt[2]; #endif if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ /* Mark the previous cluster 'EOC' on the FAT if it exists */ if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { res = put_fat(fs, pclst, 0xFFFFFFFF); if (res != FR_OK) return res; } /* Remove the chain */ do { nxt = get_fat(obj, clst); /* Get cluster status */ if (nxt == 0) break; /* Empty cluster? */ if (nxt == 1) return FR_INT_ERR; /* Internal error? */ if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } #if FF_FS_EXFAT || FF_USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; } else { /* End of contiguous cluster block */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ if (res != FR_OK) return res; } #endif #if FF_USE_TRIM rt[0] = clst2sect(fs, scl); /* Start of data area to be freed */ rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area to be freed */ disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform storage device that the data in the block may be erased */ #endif scl = ecl = nxt; } #endif clst = nxt; /* Next cluster */ } while (clst < fs->n_fatent); /* Repeat while not the last link */ #if FF_FS_EXFAT /* Some post processes for chain status */ if (fs->fs_type == FS_EXFAT) { if (pclst == 0) { /* Has the entire chain been removed? */ obj->stat = 0; /* Change the chain status 'initial' */ } else { if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ while (clst != pclst) { nxt = get_fat(obj, clst); if (nxt < 2) return FR_INT_ERR; if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; if (nxt != clst + 1) break; /* Not contiguous? */ clst++; } if (clst == pclst) { /* Has the chain got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } else { if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ obj->stat = 2; /* Change the chain status 'contiguous' */ } } } } #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { DWORD cs, ncl, scl; FRESULT res; FATFS *fs = obj->fs; if (clst == 0) { /* Create a new chain */ scl = fs->last_clst; /* Suggested cluster to start to find */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch a chain */ cs = get_fat(obj, clst); /* Check the cluster status */ if (cs < 2) return 1; /* Test for insanity */ if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; /* Cluster to start to find */ } if (fs->free_clst == 0) return 0; /* No free cluster */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ obj->stat = 2; /* Set status 'contiguous' */ } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } if (obj->stat != 2) { /* Is the file non-contiguous? */ if (ncl == clst + 1) { /* Is the cluster next to previous one? */ obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ } else { /* New fragment */ if (obj->n_frag == 0) obj->n_frag = 1; res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ if (res == FR_OK) obj->n_frag = 1; } } } else #endif { /* On the FAT/FAT32 volume */ ncl = 0; if (scl == clst) { /* Stretching an existing chain? */ ncl = scl + 1; /* Test if next cluster is free */ if (ncl >= fs->n_fatent) ncl = 2; cs = get_fat(obj, ncl); /* Get next cluster status */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (cs != 0) { /* Not free? */ cs = fs->last_clst; /* Start at suggested cluster if it is valid */ if (cs >= 2 && cs < fs->n_fatent) scl = cs; ncl = 0; } } if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ if (ncl >= fs->n_fatent) { /* Check wrap-around */ ncl = 2; if (ncl > scl) return 0; /* No free cluster found? */ } cs = get_fat(obj, ncl); /* Get the cluster status */ if (cs == 0) break; /* Found a free cluster? */ if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ if (ncl == scl) return 0; /* No free cluster found? */ } } res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } #endif /* !FF_FS_READONLY */ #if FF_USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { DWORD cl, ncl, *tbl; FATFS *fs = fp->obj.fs; tbl = fp->cltbl + 1; /* Top of CLMT */ cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ for (;;) { ncl = *tbl++; /* Number of cluters in the fragment */ if (ncl == 0) return 0; /* End of table? (error) */ if (cl < ncl) break; /* In this fragment? */ cl -= ncl; tbl++; /* Next fragment */ } return cl + *tbl; /* Return the cluster number */ } #endif /* FF_USE_FASTSEEK */ /*-----------------------------------------------------------------------*/ /* Directory handling - Fill a cluster with zeros */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ FATFS *fs, /* Filesystem object */ DWORD clst /* Directory table to clear */ ) { LBA_t sect; UINT n, szb; BYTE *ibuf; if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ sect = clst2sect(fs, clst); /* Top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */ mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ /* Allocate a temporary buffer */ for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; if (szb > SS(fs)) { /* Buffer allocated? */ mem_set(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ ff_memfree(ibuf); } else #endif { ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ } return (n == fs->csize) ? FR_OK : FR_DISK_ERR; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) { DWORD csz, clst; FATFS *fs = dp->obj.fs; if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; } dp->dptr = ofs; /* Set current offset */ clst = dp->obj.sclust; /* Table start cluster (0:root) */ if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ clst = (DWORD)fs->dirbase; if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ } if (clst == 0) { /* Static table (root-directory on the FAT volume) */ if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ dp->sect = fs->dirbase; } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ while (ofs >= csz) { /* Follow cluster chain */ clst = get_fat(&dp->obj, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ ofs -= csz; } dp->sect = clst2sect(fs, clst); } dp->clust = clst; /* Current cluster# */ if (dp->sect == 0) return FR_INT_ERR; dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ return FR_OK; } /*-----------------------------------------------------------------------*/ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ DIR* dp, /* Pointer to the directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; FATFS *fs = dp->obj.fs; ofs = dp->dptr + SZDIRE; /* Next entry */ if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ if (dp->clust == 0) { /* Static table */ if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ dp->sect = 0; return FR_NO_FILE; } } else { /* Dynamic table */ if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ #if !FF_FS_READONLY if (!stretch) { /* If no stretch, report EOT */ dp->sect = 0; return FR_NO_FILE; } clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ if (clst == 0) return FR_DENIED; /* No free cluster */ if (clst == 1) return FR_INT_ERR; /* Internal error */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ #else if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } dp->clust = clst; /* Initialize data for new cluster */ dp->sect = clst2sect(fs, clst); } } } dp->dptr = ofs; /* Current entry */ dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ return FR_OK; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to the directory object */ UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; UINT n; FATFS *fs = dp->obj.fs; res = dir_sdi(dp, 0); if (res == FR_OK) { n = 0; do { res = move_window(fs, dp->sect); if (res != FR_OK) break; #if FF_FS_EXFAT if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { #endif if (++n == nent) break; /* A block of contiguous free entries is found */ } else { n = 0; /* Not a blank entry. Restart to search */ } res = dir_next(dp, 1); } while (res == FR_OK); /* Next entry with table stretch enabled */ } if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ FATFS* fs, /* Pointer to the fs object */ const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; cl = ld_word(dir + DIR_FstClusLO); if (fs->fs_type == FS_FAT32) { cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; } return cl; } #if !FF_FS_READONLY static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ ) { st_word(dir + DIR_FstClusLO, (WORD)cl); if (fs->fs_type == FS_FAT32) { st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); } } #endif #if FF_USE_LFN /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ return 1; /* The part of LFN matched */ } #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) { UINT i, s; WCHAR wc, uc; if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } return 1; /* The part of LFN is valid */ } #endif #if !FF_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ BYTE sum /* Checksum of the corresponding SFN */ ) { UINT i, s; WCHAR wc; dir[LDIR_Chksum] = sum; /* Set checksum */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Type] = 0; st_word(dir + LDIR_FstClusLO, 0); i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ s = wc = 0; do { if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ st_word(dir + LfnOfs[s], wc); /* Put it */ if (wc == 0) wc = 0xFFFF; /* Padding characters for following items */ } while (++s < 13); if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LFN */ #if FF_USE_LFN && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ UINT seq /* Sequence number */ ) { BYTE ns[8], c; UINT i, j; WCHAR wc; DWORD sreg; mem_cpy(dst, src, 11); if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sreg = seq; while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sreg = (sreg << 1) + (wc & 1); wc >>= 1; if (sreg & 0x10000) sreg ^= 0x11021; } } seq = (UINT)sreg; } /* itoa (hexdecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); if (c > '9') c += 7; ns[i--] = c; seq /= 16; } while (seq); ns[i] = '~'; /* Append the number to the SFN body */ for (j = 0; j < i && dst[j] != ' '; j++) { if (dbc_1st(dst[j])) { if (j == i - 1) break; j++; } } do { dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } #endif /* FF_USE_LFN && !FF_FS_READONLY */ #if FF_USE_LFN /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { BYTE sum = 0; UINT n = 11; do { sum = (sum >> 1) + (sum << 7) + *dir++; } while (--n); return sum; } #endif /* FF_USE_LFN */ #if FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { UINT i, szblk; WORD sum; szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; } } return sum; } static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { WCHAR chr; WORD sum = 0; while ((chr = *name++) != 0) { chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } return sum; } #if !FF_FS_READONLY && FF_USE_MKFS static DWORD xsum32 ( /* Returns 32-bit checksum */ BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; return sum; } #endif #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { WCHAR wc, hs; UINT di, si, nc; /* Get file name from the entry block */ si = SZDIRE * 2; /* 1st C1 entry */ nc = 0; hs = 0; di = 0; while (nc < dirb[XDIR_NumName]) { if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Load stream-extension entry */ res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Load file-name entries */ i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); /* Sanity check (do it for only accessible object) */ if (i <= MAXDIRB(FF_MAX_LFN)) { if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; } return FR_OK; } /*------------------------------------------------------------------*/ /* exFAT: Initialize object allocation info with loaded entry block */ /*------------------------------------------------------------------*/ static void init_alloc_info ( FATFS* fs, /* Filesystem object */ FFOBJID* obj /* Object allocation information to be initialized */ ) { obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ obj->n_frag = 0; /* No last fragment info */ } #if !FF_FS_READONLY || FF_FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_xdir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ const FFOBJID* obj /* Object with its containing directory information */ ) { FRESULT res; /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } return res; } #endif #if !FF_FS_READONLY /*----------------------------------------*/ /* exFAT: Store the directory entry block */ /*----------------------------------------*/ static FRESULT store_xdir ( DIR* dp /* Pointer to the direcotry object */ ) { FRESULT res; UINT nent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; /* Store the direcotry entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) break; mem_cpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; if (--nent == 0) break; dirb += SZDIRE; res = dir_next(dp, 0); } return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; } /*-------------------------------------------*/ /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { UINT i; BYTE nc1, nlen; WCHAR wc; /* Create file-directory and stream-extension entry */ mem_set(dirb, 0, 2 * SZDIRE); dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; /* Create file-name entries */ i = SZDIRE * 2; /* Top of file_name entries */ nlen = nc1 = 0; wc = 1; do { dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ st_word(dirb + i, wc); /* Store it */ i += 2; } while (i % SZDIRE != 0); nc1++; } while (lfn[nlen]); /* Fill next entry if any char follows */ dirb[XDIR_NumName] = nlen; /* Set name length */ dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_EXFAT */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ #define DIR_READ_FILE(dp) dir_read(dp, 0) #define DIR_READ_LABEL(dp) dir_read(dp, 1) static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; BYTE attr, b; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; b = dp->dir[DIR_Name]; /* Test for the entry type */ if (b == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { if (b == ET_VLABEL) break; /* Volume label entry? */ } else { if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ } break; } } } else #endif { /* On the FAT/FAT32 volume */ dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { if (attr == AM_LFN) { /* An LFN entry is found */ if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ } break; } } #else /* Non LFN configuration */ if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif } res = dir_next(dp, 0); /* Next entry */ if (res != FR_OK) break; } if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ return res; } #endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ /*-----------------------------------------------------------------------*/ /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; FATFS *fs = dp->obj.fs; BYTE c; #if FF_USE_LFN BYTE a, ord, sum; #endif res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } return res; } #endif /* On the FAT/FAT32 volume */ #if FF_USE_LFN ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif do { res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ #if FF_USE_LFN /* LFN configuration */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ sum = dp->dir[LDIR_Chksum]; c &= (BYTE)~LLEF; ord = c; /* LFN start order */ dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); return res; } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ UINT n, nlen, nent; BYTE sn[12], sum; if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ dp->obj.stat &= ~4; res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ DIR dj; res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; /* Update the allocation status */ res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } } create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif /* On the FAT/FAT32 volume */ mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } if (n == 100) return FR_DENIED; /* Abort if too many collisions */ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ dp->fn[NSFLAG] = sn[NSFLAG]; } /* Create an SFN with/without LFNs. */ nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ res = dir_alloc(dp, nent); /* Allocate entries */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */ res = dir_sdi(dp, dp->dptr - nent * SZDIRE); if (res == FR_OK) { sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); } } #else /* Non LFN configuration */ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ #endif /* Set SFN entry */ if (res == FR_OK) { res = move_window(fs, dp->sect); if (res == FR_OK) { mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ #if FF_USE_LFN dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif fs->wflag = 1; } } return res; } #endif /* !FF_FS_READONLY */ #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; FATFS *fs = dp->obj.fs; #if FF_USE_LFN /* LFN configuration */ DWORD last = dp->dptr; res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { res = move_window(fs, dp->sect); if (res != FR_OK) break; if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ } else { /* On the FAT/FAT32 volume */ dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ } fs->wflag = 1; if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR; } #else /* Non LFN configuration */ res = move_window(fs, dp->sect); if (res == FR_OK) { dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ fs->wflag = 1; } #endif return res; } #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ static void get_fileinfo ( DIR* dp, /* Pointer to the directory object */ FILINFO* fno /* Pointer to the file information to be filled */ ) { UINT si, di; #if FF_USE_LFN BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else TCHAR c; #endif fno->fname[0] = 0; /* Invaidate file info */ if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ #if FF_USE_LFN /* LFN configuration */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ get_xfileinfo(fs->dirbuf, fno); return; } else #endif { /* On the FAT/FAT32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ si = di = hs = 0; while (fs->lfnbuf[si] != 0) { wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ } } si = di = 0; while (si < 11) { /* Get SFN from SFN entry */ wc = dp->dir[si++]; /* Get a char */ if (wc == ' ') continue; /* Skip padding spaces */ if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ #if FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ if (wc == 0) { di = 0; break; } /* Buffer overflow? */ di += wc; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ #endif } fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; if (wc == '.') lcf = NS_EXT; if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } fno->fname[di] = 0; /* Terminate the LFN */ if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ } #else /* Non-LFN configuration */ si = di = 0; while (si < 11) { /* Copy name body and extension */ c = (TCHAR)dp->dir[si++]; if (c == ' ') continue; /* Skip padding spaces */ if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ fno->fname[di++] = c; } fno->fname[di] = 0; #endif fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ } #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ static DWORD get_achar ( /* Get a character and advances ptr */ const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { DWORD chr; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ chr = tchar2uni(ptr); if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ chr = ff_wtoupper(chr); #else /* ANSI/OEM input */ chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ #if FF_CODE_PAGE == 0 if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #elif FF_CODE_PAGE < 900 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #endif #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; } #endif #endif return chr; } static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ int inf /* Infinite search (* specified) */ ) { const TCHAR *pp, *np; DWORD pc, nc; int nm, nx; while (skip--) { /* Pre-skip name chars */ if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ } if (*pat == 0 && inf) return 1; /* (short circuit) */ do { pp = pat; np = nam; /* Top of pattern and name to match */ for (;;) { if (*pp == '?' || *pp == '*') { /* Wildcard? */ nm = nx = 0; do { /* Analyze the wildcard block */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ nc = *np; break; /* Branch mismatched */ } pc = get_achar(&pp); /* Get a pattern char */ nc = get_achar(&np); /* Get a name char */ if (pc != nc) break; /* Branch mismatched? */ if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ } get_achar(&nam); /* nam++ */ } while (inf && nc); /* Retry until end of name if infinite search is specified */ return 0; } #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ /*-----------------------------------------------------------------------*/ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ DIR* dp, /* Pointer to the directory object */ const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; WCHAR wc, *lfn; DWORD uc; UINT i, ni, si, di; const TCHAR *p; /* Create LFN into LFN working buffer */ p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; for (;;) { uc = tchar2uni(&p); /* Get a character */ if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ wc = (WCHAR)uc; if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ lfn[di++] = wc; /* Store the Unicode character */ } if (wc < ' ') { /* End of path? */ cf = NS_LAST; /* Set last segment flag */ } else { cf = 0; /* Next segment follows */ while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ } *path = p; /* Return pointer to the next segment */ #if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; } dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif while (di) { /* Snip off trailing spaces and dots if exist */ wc = lfn[di - 1]; if (wc != ' ' && wc != '.') break; di--; } lfn[di] = 0; /* LFN is created into the working buffer */ if (di == 0) return FR_INVALID_NAME; /* Reject null name */ /* Create SFN in directory form */ for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ mem_set(dp->fn, ' ', 11); i = b = 0; ni = 8; for (;;) { wc = lfn[si++]; /* Get an LFN character */ if (wc == 0) break; /* Break on end of the LFN */ if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ cf |= NS_LOSS | NS_LFN; continue; } if (i >= ni || si == di) { /* End of field? */ if (ni == 11) { /* Name extension overflow? */ cf |= NS_LOSS | NS_LFN; break; } if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ if (si > di) break; /* No name extension? */ si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ continue; } if (wc >= 0x80) { /* Is this a non-ASCII character? */ cf |= NS_LFN; /* LFN entry needs to be created */ #if FF_CODE_PAGE == 0 if (ExCvt) { /* At SBCS */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ } else { /* At DBCS */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ } #elif FF_CODE_PAGE < 900 /* SBCS cfg */ wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ #else /* DBCS cfg */ wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ #endif } if (wc >= 0x100) { /* Is this a DBC? */ if (i >= ni - 1) { /* Field overflow? */ cf |= NS_LOSS | NS_LFN; i = ni; continue; /* Next field */ } dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ } else { /* SBC */ if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ } else { if (IsUpper(wc)) { /* ASCII upper case? */ b |= 2; } if (IsLower(wc)) { /* ASCII lower case? */ b |= 1; wc -= 0x20; } } } dp->fn[i++] = (BYTE)wc; } if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ } dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ return FR_OK; #else /* FF_USE_LFN : Non-LFN configuration */ BYTE c, d, *sfn; UINT ni, si, i; const char *p; /* Create file name in directory form */ p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = 0; ni = 8; #if FF_FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; if (c != '.' || si >= 3) break; sfn[i++] = c; } if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; *path = p + si; /* Return pointer to the next segment */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } #endif for (;;) { c = (BYTE)p[si++]; /* Get a byte */ if (c <= ' ') break; /* Break if end of the path name */ if (c == '/' || c == '\\') { /* Break if a separator is found */ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } if (c == '.' || i >= ni) { /* End of body or field overflow? */ if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ i = 8; ni = 11; /* Enter file extension field */ continue; } #if FF_CODE_PAGE == 0 if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #elif FF_CODE_PAGE < 900 if (c >= 0x80) { /* Is SBC extended character? */ c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ } #endif if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ d = (BYTE)p[si++]; /* Get 2nd byte */ if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } *path = p + si; /* Return pointer to the next segment */ if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; #endif /* FF_USE_LFN */ } /*-----------------------------------------------------------------------*/ /* Follow a file path */ /*-----------------------------------------------------------------------*/ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ DIR* dp, /* Directory object to return last directory and found object */ const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; BYTE ns; FATFS *fs = dp->obj.fs; #if FF_FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ dp->obj.sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ dp->obj.sclust = 0; /* Start from root directory */ } #if FF_FS_EXFAT dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ #if FF_FS_RPATH != 0 if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ DIR dj; dp->obj.c_scl = fs->cdc_scl; dp->obj.c_size = fs->cdc_size; dp->obj.c_ofs = fs->cdc_ofs; res = load_obj_xdir(&dj, &dp->obj); if (res != FR_OK) return res; dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } #endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); } else { /* Follow path */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ dp->fn[NSFLAG] = NS_NONAME; res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } } break; } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ /* Get into the sub-directory */ if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ dp->obj.c_scl = dp->obj.sclust; dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Open next directory */ } else #endif { dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } return res; } /*-----------------------------------------------------------------------*/ /* Get logical drive number from path name */ /*-----------------------------------------------------------------------*/ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ const TCHAR** path /* Pointer to pointer to the path name */ ) { const TCHAR *tp, *tt; TCHAR tc; int i, vol = -1; #if FF_STR_VOLUME_ID /* Find string volume ID */ const char *sp; char c; #endif tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ i = (int)*tp - '0'; /* Get the LD number */ } #if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ else { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *tp++; if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ } #endif if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tt; /* Snip the drive prefix off */ } return vol; } #if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ if (*tp == '/') { i = 0; do { sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ do { /* Compare the volume ID with path name */ c = *sp++; tc = *(++tp); if (IsLower(c)) c -= 0x20; if (IsLower(tc)) tc -= 0x20; } while (c && (TCHAR)c == tc); } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ vol = i; /* Drive number */ *path = tp; /* Snip the drive prefix off */ return vol; } } #endif /* No drive prefix is found */ #if FF_FS_RPATH != 0 vol = CurrVol; /* Default drive is current drive */ #else vol = 0; /* Default drive is 0 */ #endif return vol; /* Return the default drive */ } /*-----------------------------------------------------------------------*/ /* GPT support functions */ /*-----------------------------------------------------------------------*/ #if FF_LBA64 /* Calculate CRC32 in byte-by-byte */ static DWORD crc32 ( /* Returns next CRC value */ DWORD crc, /* Current CRC value */ BYTE d /* A byte to be processed */ ) { BYTE b; for (b = 1; b; b <<= 1) { crc ^= (d & b) ? 1 : 0; crc = (crc & 1) ? crc >> 1 ^ 0xEDB88320 : crc >> 1; } return crc; } /* Check validity of GPT header */ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ const BYTE* gpth /* Pointer to the GPT header */ ) { UINT i; DWORD bcc; if (mem_cmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ return 1; } #if !FF_FS_READONLY && FF_USE_MKFS /* Generate random value */ static DWORD make_rand ( DWORD seed, /* Seed value */ BYTE* buff, /* Output buffer */ UINT n /* Data length */ ) { UINT r; if (seed == 0) seed = 1; do { for (r = 0; r < 8; r++) seed = seed & 1 ? seed >> 1 ^ 0xA3000000 : seed >> 1; /* Shift 8 bits the 32-bit LFSR */ *buff++ = (BYTE)seed; } while (--n); return seed; } #endif #endif /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ /* Check what the sector is */ static UINT check_fs ( /* 0:FAT VBR, 1:exFAT VBR, 2:Not FAT and valid BS, 3:Not FAT and invalid BS, 4:Disk error */ FATFS* fs, /* Filesystem object */ LBA_t sect /* Sector to load and check if it is an FAT-VBR or not */ ) { WORD w, sign; BYTE b; fs->wflag = 0; fs->winsect = (LBA_t)0 - 1; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load the boot sector */ sign = ld_word(fs->win + BS_55AA); #if FF_FS_EXFAT if (sign == 0xAA55 && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* It is an exFAT VBR */ #endif b = fs->win[BS_JmpBoot]; if (b == 0xEB || b == 0xE9 || b == 0xE8) { /* Valid JumpBoot code? (short jump, near jump or near call) */ if (sign == 0xAA55 && !mem_cmp(fs->win + BS_FilSysType32, "FAT32 ", 8)) return 0; /* It is an FAT32 VBR */ /* FAT volumes formatted with early MS-DOS lack boot signature and FAT string, so that we need to identify the FAT VBR without them. */ w = ld_word(fs->win + BPB_BytsPerSec); if ((w & (w - 1)) == 0 && w >= FF_MIN_SS && w <= FF_MAX_SS) { /* Properness of sector size */ b = fs->win[BPB_SecPerClus]; if (b != 0 && (b & (b - 1)) == 0 /* Properness of cluster size */ && (fs->win[BPB_NumFATs] == 1 || fs->win[BPB_NumFATs] == 2) /* Properness of number of FATs */ && ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root entry count */ && ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size */ return 0; /* Sector can be presumed an FAT VBR */ } } } return sign == 0xAA55 ? 2 : 3; /* Not an FAT VBR (valid or invalid BS) */ } /* Find an FAT volume */ /* (It supports only generic partitioning rules, MBR, GPT and SFD) */ static UINT find_volume ( /* Returns BS status found in the hosting drive */ FATFS* fs, /* Filesystem object */ UINT part /* Partition to fined = 0:auto, 1..:forced */ ) { UINT fmt, i; DWORD mbr_pt[4]; fmt = check_fs(fs, 0); /* Load sector 0 and check if it is an FAT VBR as SFD */ if (fmt != 2 && (fmt >= 3 || part == 0)) return fmt; /* Returns if it is a FAT VBR as auto scan, not a BS or disk error */ /* Sector 0 is not an FAT VBR or forced partition number wants a partition */ #if FF_LBA64 if (fs->win[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, v_ent, ofs; QWORD pt_lba; if (move_window(fs, 1) != FR_OK) return 4; /* Load GPT header sector (next to MBR) */ if (!test_gpt_header(fs->win)) return 3; /* Check if GPT header is valid */ n_ent = ld_dword(fs->win + GPTH_PtNum); /* Number of entries */ pt_lba = ld_qword(fs->win + GPTH_PtOfs); /* Table location */ for (v_ent = i = 0; i < n_ent; i++) { /* Find FAT partition */ if (move_window(fs, pt_lba + i * SZ_GPTE / SS(fs)) != FR_OK) return 4; /* PT sector */ ofs = i * SZ_GPTE % SS(fs); /* Offset in the sector */ if (!mem_cmp(fs->win + ofs + GPTE_PtGuid, GUID_MS_Basic, 16)) { /* MS basic data partition? */ v_ent++; fmt = check_fs(fs, ld_qword(fs->win + ofs + GPTE_FstLba)); /* Load VBR and check status */ if (part == 0 && fmt <= 1) return fmt; /* Auto search (valid FAT volume found first) */ if (part != 0 && v_ent == part) return fmt; /* Forced partition order (regardless of it is valid or not) */ } } return 3; /* Not found */ } #endif if (FF_MULTI_PARTITION && part > 4) return 3; /* MBR has 4 partitions max */ for (i = 0; i < 4; i++) { /* Load partition offset in the MBR */ mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); } i = part ? part - 1 : 0; /* Table index to find first */ do { /* Find an FAT volume */ fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; /* Check if the partition is FAT */ } while (part == 0 && fmt >= 2 && ++i < 4); return fmt; } /*-----------------------------------------------------------------------*/ /* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ BYTE mode /* !=0: Check write protection for write access */ ) { int vol; DSTATUS stat; LBA_t bsect; DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; FATFS *fs; UINT fmt; /* Get logical drive number */ *rfs = 0; vol = get_ldnumber(path); if (vol < 0) return FR_INVALID_DRIVE; /* Check if the filesystem object is valid or not */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ #endif *rfs = fs; /* Return pointer to the filesystem object */ mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type != 0) { /* If the volume has been mounted */ stat = disk_status(fs->pdrv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; } return FR_OK; /* The filesystem object is already valid */ } } /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find a FAT volume, analyze the BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif /* Find an FAT volume on the drive */ fmt = find_volume(fs, LD2PT(vol)); if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ bsect = fs->winsect; /* Volume location */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; DWORD so, cv, bcl, i; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ fs->n_fatent = nclst + 2; /* Boundaries and Limits */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ so = i = 0; for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ if (i == 0) { if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; so++; } if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ i = (i + SZDIRE) % SS(fs); /* Next entry */ } bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ for (;;) { /* Check if bitmap is contiguous */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ } #if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else #endif /* FF_FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ fasize *= fs->n_fats; /* Number of sectors for FAT area */ fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = 0; if (nclst <= MAX_FAT32) fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; if (fmt == 0) return FR_NO_FILESYSTEM; /* Boundaries and Limits */ fs->n_fatent = nclst + 2; /* Number of FAT entries */ fs->volbase = bsect; /* Volume start sector */ fs->fatbase = bsect + nrsv; /* FAT start sector */ fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !FF_FS_READONLY /* Get FSInfo if available */ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; #if (FF_FS_NOFSINFO & 3) != 3 if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) { fs->fsi_flag = 0; if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) { #if (FF_FS_NOFSINFO & 1) == 0 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif #if (FF_FS_NOFSINFO & 2) == 0 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif } } #endif /* (FF_FS_NOFSINFO & 3) != 3 */ #endif /* !FF_FS_READONLY */ } fs->fs_type = (BYTE)fmt;/* FAT sub-type */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if FF_FS_EXFAT fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif #if FF_FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; } /*-----------------------------------------------------------------------*/ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { FRESULT res = FR_INVALID_OBJECT; if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } else { unlock_fs(obj->fs, FR_OK); } } else { res = FR_TIMEOUT; } #else if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif } *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ return res; } /*--------------------------------------------------------------------------- Public Functions (FatFs API) ----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) { FATFS *cfs; int vol; FRESULT res; const TCHAR *rp = path; /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; cfs = FatFs[vol]; /* Pointer to fs object */ if (cfs) { #if FF_FS_LOCK != 0 clear_lock(cfs); #endif #if FF_FS_REENTRANT /* Discard sync object of the current volume */ if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; #endif cfs->fs_type = 0; /* Clear old fs object */ } if (fs) { fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; #endif } FatFs[vol] = fs; /* Register new fs object */ if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Open or Create a File */ /*-----------------------------------------------------------------------*/ FRESULT f_open ( FIL* fp, /* Pointer to the blank file object */ const TCHAR* path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ ) { FRESULT res; DIR dj; FATFS *fs; #if !FF_FS_READONLY DWORD cl, bcs, clst; LBA_t sc; FSIZE_t ofs; #endif DEF_NAMBUF if (!fp) return FR_INVALID_OBJECT; /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = mount_volume(&path, &fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !FF_FS_READONLY /* Read/Write configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } #if FF_FS_LOCK != 0 else { res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ #if FF_FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif } mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object with the same name is already existing */ if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Get current allocation info */ fp->obj.fs = fs; init_alloc_info(fs, &fp->obj); /* Set directory entry block initial state */ mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ fs->dirbuf[XDIR_Attr] = AM_ARC; st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); fs->dirbuf[XDIR_GenFlags] = 1; res = store_xdir(&dj); if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ } } else #endif { /* Set directory entry initial state */ cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ st_dword(dj.dir + DIR_FileSize, 0); fs->wflag = 1; if (cl != 0) { /* Remove the cluster chain if exist */ sc = fs->winsect; res = remove_chain(&dj.obj, cl, 0); if (res == FR_OK) { res = move_window(fs, sc); fs->last_clst = cl - 1; /* Reuse the cluster hole */ } } } } } else { /* Open an existing file */ if (res == FR_OK) { /* Is the object exsiting? */ if (dj.obj.attr & AM_DIR) { /* File open against a directory */ res = FR_NO_FILE; } else { if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ res = FR_DENIED; } } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; #if FF_FS_LOCK != 0 fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } #else /* R/O configuration */ if (res == FR_OK) { if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ res = FR_INVALID_NAME; } else { if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ res = FR_NO_FILE; } } } #endif if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; init_alloc_info(fs, &fp->obj); } else #endif { fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if FF_USE_FASTSEEK fp->cltbl = 0; /* Disable fast seek mode */ #endif fp->obj.fs = fs; /* Validate the file object */ fp->obj.id = fs->id; fp->flag = mode; /* Set file access mode */ fp->err = 0; /* Clear error flag */ fp->sect = 0; /* Invalidate current data sector */ fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ clst = fp->obj.sclust; /* Follow the cluster chain */ for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { clst = get_fat(&fp->obj, clst); if (clst <= 1) res = FR_INT_ERR; if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; } fp->clust = clst; if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ sc = clst2sect(fs, clst); if (sc == 0) { res = FR_INT_ERR; } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } } } #endif } FREE_NAMBUF(); } if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Read File */ /*-----------------------------------------------------------------------*/ FRESULT f_read ( FIL* fp, /* Pointer to the file object */ void* buff, /* Pointer to data buffer */ UINT btr, /* Number of bytes to read */ UINT* br /* Pointer to number of bytes read */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, cc, csect; BYTE *rbuff = (BYTE*)buff; *br = 0; /* Clear read byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until btr bytes read */ btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ } } if (clst < 2) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Read maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } #else if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); } #endif #endif rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if !FF_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; } rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } LEAVE_FF(fs, FR_OK); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ FRESULT f_write ( FIL* fp, /* Pointer to the file object */ const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write */ UINT* bw /* Pointer to number of bytes written */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; *bw = 0; /* Clear write byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->obj.sclust; /* Follow from the origin */ if (clst == 0) { /* If no cluster is allocated, */ clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ } } else { /* On the middle or end of the file */ #if FF_USE_FASTSEEK if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ } else #endif { clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ } } if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ if (clst == 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if FF_FS_TINY if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clst2sect(fs, fp->clust); /* Get current sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc > 0) { /* Write maximum contiguous sectors directly */ if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if FF_FS_MINIMIZE <= 2 #if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); fs->wflag = 0; } #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); fp->flag &= (BYTE)~FA_DIRTY; } #endif #endif wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if FF_FS_TINY if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; } #else if (fp->sect != sect && /* Fill sector cache with file data */ fp->fptr < fp->obj.objsize && disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { ABORT(fs, FR_DISK_ERR); } #endif fp->sect = sect; } wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if FF_FS_TINY if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; #else mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fp->flag |= FA_DIRTY; #endif } fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ FRESULT f_sync ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD tm; BYTE *dir; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ if (res == FR_OK) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } if (res == FR_OK) { DIR dj; DEF_NAMBUF INIT_NAMBUF(fs); res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); /* Update start cluster */ st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); /* Update file size */ st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); /* (FatFs does not support Valid File Size feature) */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; st_dword(fs->dirbuf + XDIR_AccTime, 0); res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); fp->flag &= (BYTE)~FA_MODIFIED; } } FREE_NAMBUF(); } } else #endif { res = move_window(fs, fp->dir_sect); if (res == FR_OK) { dir = fp->dir_ptr; dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); fs->wflag = 1; res = sync_fs(fs); /* Restore it to the directory */ fp->flag &= (BYTE)~FA_MODIFIED; } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ /*-----------------------------------------------------------------------*/ /* Close File */ /*-----------------------------------------------------------------------*/ FRESULT f_close ( FIL* fp /* Pointer to the file object to be closed */ ) { FRESULT res; FATFS *fs; #if !FF_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { #if FF_FS_LOCK != 0 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } } return res; } #if FF_FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_chdrive ( const TCHAR* path /* Drive number to set */ ) { int vol; /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { #if FF_STR_VOLUME_ID == 2 UINT i; #endif FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; fs->cdc_size = dj.obj.c_size; fs->cdc_ofs = dj.obj.c_ofs; } #endif } else { if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fs->cdc_ofs = dj.blk_ofs; } else #endif { fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ } } else { res = FR_NO_PATH; /* Reached but a file */ } } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; #if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ if (res == FR_OK) { for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ CurrVol = (BYTE)i; } #endif } LEAVE_FF(fs, res); } #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( TCHAR* buff, /* Pointer to the directory path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; #if FF_STR_VOLUME_ID const char *vp; #endif #endif FILINFO fno; DEF_NAMBUF /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ res = mount_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; res = move_window(fs, dj.sect); if (res != FR_OK) break; dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ for (n = 0; fno.fname[n]; n++) ; /* Name length */ if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } if (res == FR_OK) { if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ #if FF_VOLUMES >= 2 /* Put drive prefix */ vl = 0; #if FF_STR_VOLUME_ID >= 1 /* String volume ID */ for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; if (i >= n + 2) { if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; vl++; } #else /* Numeric volume ID */ if (i >= 3) { *tp++ = (TCHAR)'0' + CurrVol; *tp++ = (TCHAR)':'; vl = 2; } #endif if (vl == 0) res = FR_NOT_ENOUGH_CORE; #endif /* Add current directory path */ if (res == FR_OK) { do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } FREE_NAMBUF(); } *tp = 0; LEAVE_FF(fs, res); } #endif /* FF_FS_RPATH >= 2 */ #endif /* FF_FS_RPATH >= 1 */ #if FF_FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ /* Seek File Read/Write Pointer */ /*-----------------------------------------------------------------------*/ FRESULT f_lseek ( FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File pointer from top of file */ ) { FRESULT res; FATFS *fs; DWORD clst, bcs; LBA_t nsect; FSIZE_t ifptr; #if FF_USE_FASTSEEK DWORD cl, pcl, ncl, tcl, tlen, ulen, *tbl; LBA_t dsc; #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) res = (FRESULT)fp->err; #if FF_FS_EXFAT && !FF_FS_READONLY if (res == FR_OK && fs->fs_type == FS_EXFAT) { res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ } #endif if (res != FR_OK) LEAVE_FF(fs, res); #if FF_USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ cl = fp->obj.sclust; /* Origin of the chain */ if (cl != 0) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ do { pcl = cl; ncl++; cl = get_fat(&fp->obj, cl); if (cl <= 1) ABORT(fs, FR_INT_ERR); if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); } while (cl == pcl + 1); if (ulen <= tlen) { /* Store the length and top of the fragment */ *tbl++ = ncl; *tbl++ = tcl; } } while (cl < fs->n_fatent); /* Repeat until end of chain */ } *fp->cltbl = ulen; /* Number of items used */ if (ulen <= tlen) { *tbl = 0; /* Terminate table */ } else { res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ } } else { /* Fast seek */ if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ if (ofs > 0) { fp->clust = clmt_clust(fp, ofs - 1); dsc = clst2sect(fs, fp->clust); if (dsc == 0) ABORT(fs, FR_INT_ERR); dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } } } } else #endif /* Normal Seek */ { #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ #endif if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ ofs = fp->obj.objsize; } ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs > 0) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ clst = fp->obj.sclust; /* start from the first cluster */ #if !FF_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ clst = create_chain(&fp->obj, 0); if (clst == 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->obj.sclust = clst; } #endif fp->clust = clst; } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ ofs -= bcs; fp->fptr += bcs; #if !FF_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ if (clst == 0) { /* Clip file size in case of disk full */ ofs = 0; break; } } else #endif { clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ } if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; } fp->fptr += ofs; if (ofs % SS(fs)) { nsect = clst2sect(fs, clst); /* Current sector */ if (nsect == 0) ABORT(fs, FR_INT_ERR); nsect += (DWORD)(ofs / SS(fs)); } } } if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ fp->obj.objsize = fp->fptr; fp->flag |= FA_MODIFIED; } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } } LEAVE_FF(fs, res); } #if FF_FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( DIR* dp, /* Pointer to directory object to create */ const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { dp->obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ } else #endif { dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; } } if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ #if FF_FS_LOCK != 0 if (res == FR_OK) { if (dp->obj.sclust != 0) { dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ } } #endif } } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Close Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_closedir ( DIR *dp /* Pointer to the directory object to be closed */ ) { FRESULT res; FATFS *fs; res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { #if FF_FS_LOCK != 0 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ FRESULT f_readdir ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; FATFS *fs; DEF_NAMBUF res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } FREE_NAMBUF(); } } LEAVE_FF(fs, res); } #if FF_USE_FIND /*-----------------------------------------------------------------------*/ /* Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( DIR* dp, /* Pointer to the open directory object */ FILINFO* fno /* Pointer to the file information structure */ ) { FRESULT res; for (;;) { res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ #if FF_USE_LFN && FF_USE_FIND == 2 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif } return res; } /*-----------------------------------------------------------------------*/ /* Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( DIR* dp, /* Pointer to the blank directory object */ FILINFO* fno, /* Pointer to the file information structure */ const TCHAR* path, /* Pointer to the directory to open */ const TCHAR* pattern /* Pointer to the matching pattern */ ) { FRESULT res; dp->pat = pattern; /* Save pointer to pattern string */ res = f_opendir(dp, path); /* Open the target directory */ if (res == FR_OK) { res = f_findnext(dp, fno); /* Find the first item */ } return res; } #endif /* FF_USE_FIND */ #if FF_FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ FRESULT f_stat ( const TCHAR* path, /* Pointer to the file path */ FILINFO* fno /* Pointer to file information to return */ ) { FRESULT res; DIR dj; DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ res = FR_INVALID_NAME; } else { /* Found an object */ if (fno) get_fileinfo(&dj, fno); } } FREE_NAMBUF(); } LEAVE_FF(dj.obj.fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( const TCHAR* path, /* Logical drive number */ DWORD* nclst, /* Pointer to a variable to return number of free clusters */ FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ ) { FRESULT res; FATFS *fs; DWORD nfree, clst, stat; LBA_t sect; UINT i; FFOBJID obj; /* Get logical drive */ res = mount_volume(&path, &fs, 0); if (res == FR_OK) { *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; } else { /* Scan FAT to obtain number of free clusters */ nfree = 0; if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ BYTE bm; UINT b; clst = fs->n_fatent - 2; /* Number of clusters */ sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { if (!(bm & 1)) nfree++; bm >>= 1; } i = (i + 1) % SS(fs); } while (clst); } else #endif { /* FAT16/32: Scan WORD/DWORD FAT entries */ clst = fs->n_fatent; /* Number of entries */ sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ if (i == 0) { res = move_window(fs, sect++); if (res != FR_OK) break; } if (fs->fs_type == FS_FAT16) { if (ld_word(fs->win + i) == 0) nfree++; i += 2; } else { if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; i += 4; } i %= SS(fs); } while (--clst); } } *nclst = nfree; /* Return the free clusters */ fs->free_clst = nfree; /* Now free_clst is valid */ fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ } } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Truncate File */ /*-----------------------------------------------------------------------*/ FRESULT f_truncate ( FIL* fp /* Pointer to the file object */ ) { FRESULT res; FATFS *fs; DWORD ncl; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; } else { /* When truncate a part of the file, remove remaining clusters */ ncl = get_fat(&fp->obj, fp->clust); res = FR_OK; if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; if (ncl == 1) res = FR_INT_ERR; if (res == FR_OK && ncl < fs->n_fatent) { res = remove_chain(&fp->obj, ncl, fp->clust); } } fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ fp->flag |= FA_MODIFIED; #if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { fp->flag &= (BYTE)~FA_DIRTY; } } #endif if (res != FR_OK) ABORT(fs, res); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( const TCHAR* path /* Pointer to the file or directory path */ ) { FRESULT res; DIR dj, sdj; DWORD dclst = 0; FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif DEF_NAMBUF /* Get logical drive */ res = mount_volume(&path, &fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } #if FF_FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { if (dj.obj.attr & AM_RDO) { res = FR_DENIED; /* Cannot remove R/O object */ } } if (res == FR_OK) { #if FF_FS_EXFAT obj.fs = fs; if (fs->fs_type == FS_EXFAT) { init_alloc_info(fs, &obj); dclst = obj.sclust; } else #endif { dclst = ld_clust(fs, dj.dir); } if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if FF_FS_RPATH != 0 if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { sdj.obj.fs = fs; /* Open the sub-directory */ sdj.obj.sclust = dclst; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { sdj.obj.objsize = obj.objsize; sdj.obj.stat = obj.stat; } #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } } if (res == FR_OK) { res = dir_remove(&dj); /* Remove the directory entry */ if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ #if FF_FS_EXFAT res = remove_chain(&obj, dclst, 0); #else res = remove_chain(&dj.obj, dclst, 0); #endif } if (res == FR_OK) res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Create a Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; DIR dj; FFOBJID sobj; FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Name collision? */ if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } if (res == FR_NO_FILE) { /* It is clear to create a new directory */ sobj.fs = fs; /* New object id to create a new chain */ dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); if (res == FR_OK) { res = dir_clear(fs, dcl); /* Clean up the new table */ if (res == FR_OK) { if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ fs->win[DIR_Name] = '.'; fs->win[DIR_Attr] = AM_DIR; st_dword(fs->win + DIR_ModTime, tm); st_clust(fs, fs->win, dcl); mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; st_clust(fs, fs->win + SZDIRE, pcl); fs->wflag = 1; } res = dir_register(&dj); /* Register the object to the parent directoy */ } } if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* Directory size needs to be valid */ st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dj.dir, dcl); /* Table start cluster */ dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } else { remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( const TCHAR* path_old, /* Pointer to the object name to be renamed */ const TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; DIR djo, djn; FATFS *fs; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; LBA_t sect; DEF_NAMBUF get_ldnumber(&path_new); /* Snip the drive number of new name off */ res = mount_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if FF_FS_LOCK != 0 if (res == FR_OK) { res = chk_lock(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ BYTE nf, nn; WORD nh; mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ mem_cpy(&djn, &djo, sizeof djo); res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ /* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } } else #endif { /* At FAT/FAT32 volume */ mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ if (res == FR_OK) { /* Is new name already in use by any other object? */ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { dir = djn.dir; /* Copy directory entry of the object except name */ mem_cpy(dir + 13, buf + 13, SZDIRE - 13); dir[DIR_Attr] = buf[DIR_Attr]; if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ fs->wflag = 1; if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ sect = clst2sect(fs, ld_clust(fs, dir)); if (sect == 0) { res = FR_INT_ERR; } else { /* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, sect); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { st_clust(fs, dir, djn.obj.sclust); fs->wflag = 1; } } } } } } if (res == FR_OK) { res = dir_remove(&djo); /* Remove old entry */ if (res == FR_OK) { res = sync_fs(fs); } } /* End of the critical section */ } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_FS_MINIMIZE == 0 */ #endif /* FF_FS_MINIMIZE <= 1 */ #endif /* FF_FS_MINIMIZE <= 2 */ #if FF_USE_CHMOD && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( const TCHAR* path, /* Pointer to the file path */ BYTE attr, /* Attribute bits */ BYTE mask /* Attribute mask to change */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ res = store_xdir(&dj); } else #endif { dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ /* Change Timestamp */ /*-----------------------------------------------------------------------*/ FRESULT f_utime ( const TCHAR* path, /* Pointer to the file/directory name */ const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; DIR dj; FATFS *fs; DEF_NAMBUF res = mount_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); } else #endif { st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } FREE_NAMBUF(); } LEAVE_FF(fs, res); } #endif /* FF_USE_CHMOD && !FF_FS_READONLY */ #if FF_USE_LABEL /*-----------------------------------------------------------------------*/ /* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( const TCHAR* path, /* Logical drive number */ TCHAR* label, /* Buffer to store the volume label */ DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; FATFS *fs; UINT si, di; WCHAR wc; /* Get logical drive */ res = mount_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { WCHAR hs; for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ wc = ld_word(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue; } wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); if (wc == 0) { di = 0; break; } di += wc; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ label[di] = 0; } else #endif { si = di = 0; /* Extract volume label from AM_VOL entry */ while (si < 11) { wc = dj.dir[si++]; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ if (wc == 0) { di = 0; break; } di += wc; #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; #endif } do { /* Truncate trailing spaces */ label[di] = 0; if (di == 0) break; } while (label[--di] == ' '); } } } if (res == FR_NO_FILE) { /* No label entry and return nul string */ label[0] = 0; res = FR_OK; } } /* Get volume serial number */ if (res == FR_OK && vsn) { res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { case FS_EXFAT: di = BPB_VolIDEx; break; case FS_FAT32: di = BS_VolID32; break; default: di = BS_VolID; } *vsn = ld_dword(fs->win + di); } } LEAVE_FF(fs, res); } #if !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; FATFS *fs; BYTE dirvn[22]; UINT di; WCHAR wc; static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ #if FF_USE_LFN DWORD dc; #endif /* Get logical drive */ res = mount_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ mem_set(dirvn, 0, 22); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ dc = tchar2uni(&label); /* Get a Unicode character */ if (dc >= 0x10000) { if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ dc = 0; } else { st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; } } if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } st_word(dirvn + di * 2, (WCHAR)dc); di++; } } else #endif { /* On the FAT/FAT32 volume */ mem_set(dirvn, ' ', 11); di = 0; while ((UINT)*label >= ' ') { /* Create volume label */ #if FF_USE_LFN dc = tchar2uni(&label); wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; #else /* ANSI/OEM input */ wc = (BYTE)*label++; if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ #if FF_CODE_PAGE == 0 if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #elif FF_CODE_PAGE < 900 if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ #endif #endif if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ LEAVE_FF(fs, FR_INVALID_NAME); } if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); dirvn[di++] = (BYTE)wc; } if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ } /* Set volume label */ dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { if (di != 0) { mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ } else { dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ } } fs->wflag = 1; res = sync_fs(fs); } else { /* No volume label entry or an error */ if (res == FR_NO_FILE) { res = FR_OK; if (di != 0) { /* Create a volume label entry */ res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ mem_cpy(dj.dir, dirvn, 11); } fs->wflag = 1; res = sync_fs(fs); } } } } } LEAVE_FF(fs, res); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_LABEL */ #if FF_USE_EXPAND && !FF_FS_READONLY /*-----------------------------------------------------------------------*/ /* Allocate a Contiguous Blocks to the File */ /*-----------------------------------------------------------------------*/ FRESULT f_expand ( FIL* fp, /* Pointer to the file object */ FSIZE_t fsz, /* File size to be expanded to */ BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ ) { FRESULT res; FATFS *fs; DWORD n, clst, stcl, scl, ncl, tcl, lclst; res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); #if FF_FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif n = (DWORD)fs->csize * SS(fs); /* Cluster size */ tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } else #endif { scl = clst = stcl; ncl = 0; for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; if (n == 1) { res = FR_INT_ERR; break; } if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } } if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } } } LEAVE_FF(fs, res); } #endif /* FF_USE_EXPAND && !FF_FS_READONLY */ #if FF_USE_FORWARD /*-----------------------------------------------------------------------*/ /* Forward Data to the Stream Directly */ /*-----------------------------------------------------------------------*/ FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ UINT btf, /* Number of bytes to forward */ UINT* bf /* Pointer to number of bytes forwarded */ ) { FRESULT res; FATFS *fs; DWORD clst; LBA_t sect; FSIZE_t remain; UINT rcnt, csect; BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ if (csect == 0) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ fp->obj.sclust : get_fat(&fp->obj, fp->clust); if (clst <= 1) ABORT(fs, FR_INT_ERR); if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } } sect = clst2sect(fs, fp->clust); /* Get current data sector */ if (sect == 0) ABORT(fs, FR_INT_ERR); sect += csect; #if FF_FS_TINY if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ dbuf = fs->win; #else if (fp->sect != sect) { /* Fill sector cache with file data */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); } dbuf = fp->buf; #endif fp->sect = sect; rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes remains in the sector */ if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ if (rcnt == 0) ABORT(fs, FR_INT_ERR); } LEAVE_FF(fs, FR_OK); } #endif /* FF_USE_FORWARD */ #if !FF_FS_READONLY && FF_USE_MKFS /*-----------------------------------------------------------------------*/ /* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ #define N_SEC_TRACK 63 /* Sectors per track for determination of drive CHS */ #define GPT_ALIGN 0x100000 /* Alignment of partitions in GPT [byte] (>=128KB) */ #define GPT_ITEMS 128 /* Number of GPT table size (>=128, sector aligned) */ /* Create partitions on the physical drive */ static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ UINT sys, /* System ID (for only MBR, temp setting) and bit8:GPT */ BYTE* buf /* Working buffer for a sector */ ) { UINT i, cy; LBA_t sz_drv; DWORD sz_drv32, s_lba32, n_lba32; BYTE *pte, hd, n_hd, sc, n_sc; /* Get drive size */ if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR; #if FF_LBA64 if (sz_drv >= FF_MIN_GPT) { /* Create partitions in GPT */ WORD ss; UINT sz_pt, pi, si, ofs; DWORD bcc, rnd, align; QWORD s_lba64, n_lba64, sz_pool, s_bpt; static const BYTE gpt_mbr[16] = {0x00, 0x00, 0x02, 0x00, 0xEE, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(drv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; /* Get sector size */ if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif rnd = GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment [sector] */ sz_pt = GPT_ITEMS * SZ_GPTE / ss; /* Size of PT [sector] */ s_bpt = sz_drv - sz_pt - 1; /* Backup PT start sector */ s_lba64 = 2 + sz_pt; /* First allocatable sector */ sz_pool = s_bpt - s_lba64; /* Size of allocatable area */ bcc = 0xFFFFFFFF; n_lba64 = 1; pi = si = 0; /* partition table index, size table index */ do { if (pi * SZ_GPTE % ss == 0) mem_set(buf, 0, ss); /* Clean the buffer if needed */ if (n_lba64 != 0) { /* Is the size table not termintated? */ s_lba64 = (s_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition start */ n_lba64 = plst[si++]; /* Get a partition size */ if (n_lba64 <= 100) { /* Is the size in percentage? */ n_lba64 = sz_pool * n_lba64 / 100; n_lba64 = (n_lba64 + align - 1) & ((QWORD)0 - align); /* Align partition end (only if in percentage) */ } if (s_lba64 + n_lba64 > s_bpt) { /* Clip at end of the pool */ n_lba64 = (s_lba64 < s_bpt) ? s_bpt - s_lba64 : 0; } } if (n_lba64 != 0) { /* Add a partition? */ ofs = pi * SZ_GPTE % ss; mem_cpy(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16); /* Partition GUID (Microsoft Basic Data) */ rnd = make_rand(rnd, buf + ofs + GPTE_UpGuid, 16); /* Unique partition GUID */ st_qword(buf + ofs + GPTE_FstLba, s_lba64); /* Partition start LBA */ st_qword(buf + ofs + GPTE_LstLba, s_lba64 + n_lba64 - 1); /* Partition end LBA */ s_lba64 += n_lba64; /* Next partition LBA */ } if ((pi + 1) * SZ_GPTE % ss == 0) { /* Write the buffer if it is filled up */ for (i = 0; i < ss; bcc = crc32(bcc, buf[i++])) ; /* Calculate table check sum */ if (disk_write(drv, buf, 2 + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Primary table */ if (disk_write(drv, buf, s_bpt + pi * SZ_GPTE / ss, 1) != RES_OK) return FR_DISK_ERR; /* Secondary table */ } } while (++pi < GPT_ITEMS); /* Create primary GPT header */ mem_set(buf, 0, ss); mem_cpy(buf + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16); /* Signature, version (1.0) and size (92) */ st_dword(buf + GPTH_PtBcc, ~bcc); /* Table check sum */ st_qword(buf + GPTH_CurLba, 1); /* LBA of this header */ st_qword(buf + GPTH_BakLba, sz_drv - 1); /* LBA of another header */ st_qword(buf + GPTH_FstLba, 2 + sz_pt); /* LBA of first allocatable sector */ st_qword(buf + GPTH_LstLba, s_bpt - 1); /* LBA of last allocatable sector */ st_dword(buf + GPTH_PteSize, SZ_GPTE); /* Size of a table entry */ st_dword(buf + GPTH_PtNum, GPT_ITEMS); /* Number of table entries */ st_dword(buf + GPTH_PtOfs, 2); /* LBA of this table */ rnd = make_rand(rnd, buf + GPTH_DskGuid, 16); /* Disk GUID */ for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, 1, 1) != RES_OK) return FR_DISK_ERR; /* Create secondary GPT header */ st_qword(buf + GPTH_CurLba, sz_drv - 1); /* LBA of this header */ st_qword(buf + GPTH_BakLba, 1); /* LBA of another header */ st_qword(buf + GPTH_PtOfs, s_bpt); /* LBA of this table */ st_dword(buf + GPTH_Bcc, 0); for (i = 0, bcc= 0xFFFFFFFF; i < 92; bcc = crc32(bcc, buf[i++])) ; /* Calculate header check sum */ st_dword(buf + GPTH_Bcc, ~bcc); /* Header check sum */ if (disk_write(drv, buf, sz_drv - 1, 1) != RES_OK) return FR_DISK_ERR; /* Create protective MBR */ mem_set(buf, 0, ss); mem_cpy(buf + MBR_Table, gpt_mbr, 16); /* Create a GPT partition */ st_word(buf + BS_55AA, 0xAA55); if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; } else #endif { /* Create partitions in MBR */ sz_drv32 = (DWORD)sz_drv; n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry */ for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ; if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */ mem_set(buf, 0, FF_MAX_SS); /* Clear MBR */ pte = buf + MBR_Table; /* Partition table in the MBR */ for (i = 0, s_lba32 = n_sc; i < 4 && s_lba32 != 0 && s_lba32 < sz_drv32; i++, s_lba32 += n_lba32) { n_lba32 = (DWORD)plst[i]; /* Get partition size */ if (n_lba32 <= 100) n_lba32 = (n_lba32 == 100) ? sz_drv32 : sz_drv32 / 100 * n_lba32; /* Size in percentage? */ if (s_lba32 + n_lba32 > sz_drv32 || s_lba32 + n_lba32 < s_lba32) n_lba32 = sz_drv32 - s_lba32; /* Clip at drive size */ if (n_lba32 == 0) break; /* End of table or no sector to allocate? */ st_dword(pte + PTE_StLba, s_lba32); /* Start LBA */ st_dword(pte + PTE_SizLba, n_lba32); /* Number of sectors */ pte[PTE_System] = (BYTE)sys; /* System type */ cy = (UINT)(s_lba32 / n_sc / n_hd); /* Start cylinder */ hd = (BYTE)(s_lba32 / n_sc % n_hd); /* Start head */ sc = (BYTE)(s_lba32 % n_sc + 1); /* Start sector */ pte[PTE_StHead] = hd; pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_StCyl] = (BYTE)cy; cy = (UINT)((s_lba32 + n_lba32 - 1) / n_sc / n_hd); /* End cylinder */ hd = (BYTE)((s_lba32 + n_lba32 - 1) / n_sc % n_hd); /* End head */ sc = (BYTE)((s_lba32 + n_lba32 - 1) % n_sc + 1); /* End sector */ pte[PTE_EdHead] = hd; pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc); pte[PTE_EdCyl] = (BYTE)cy; pte += SZ_PTE; /* Next entry */ } st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ } return FR_OK; } FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ void* work, /* Pointer to working buffer (null: use heap memory) */ UINT len /* Size of working buffer [byte] */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ LBA_t sect, lba[2]; DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; DSTATUS ds; FRESULT fr; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ pdrv = LD2PD(vol); /* Physical drive */ ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ if (!opt) opt = &defopt; /* Use default parameter if it is not given */ /* Get physical drive status (sz_drv, sz_blk, ss) */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; sz_blk = opt->align; if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif /* Options for FAT sub-type and FAT parameters */ fsopt = opt->fmt & (FM_ANY | FM_SFD); n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512; sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0; sz_au /= ss; /* Byte --> Sector */ /* Get working buffer */ sz_buf = len / ss; /* Size of working buffer [sector] */ if (sz_buf == 0) return FR_NOT_ENOUGH_CORE; buf = (BYTE*)work; /* Working buffer */ #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(sz_buf * ss); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; /* Determine where the volume to be located (b_vol, sz_vol) */ b_vol = sz_vol = 0; if (FF_MULTI_PARTITION && ipart != 0) { /* Is the volume associated with any specific partition? */ /* Get partition location from the existing partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ #if FF_LBA64 if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */ DWORD n_ent, ofs; QWORD pt_lba; /* Get the partition location from GPT */ if (disk_read(pdrv, buf, 1, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load GPT header sector (next to MBR) */ if (!test_gpt_header(buf)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if GPT header is valid */ n_ent = ld_dword(buf + GPTH_PtNum); /* Number of entries */ pt_lba = ld_qword(buf + GPTH_PtOfs); /* Table start sector */ ofs = i = 0; while (n_ent) { /* Find MS Basic partition with order of ipart */ if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */ if (!mem_cmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */ b_vol = ld_qword(buf + ofs + GPTE_FstLba); sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1; break; } n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */ } if (n_ent == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* Partition not found */ fsopt |= 0x80; /* Partitioning is in GPT */ } else #endif { /* Get the partition location from MBR partition table */ pte = buf + (MBR_Table + (ipart - 1) * SZ_PTE); if (ipart > 4 || pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } } else { /* The volume is associated with a physical drive */ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); if (!(fsopt & FM_SFD)) { /* To be partitioned? */ /* Create a single-partition on the drive in this function */ #if FF_LBA64 if (sz_vol >= FF_MIN_GPT) { /* Which partition type to create, MBR or GPT? */ fsopt |= 0x80; /* Partitioning is in GPT */ b_vol = GPT_ALIGN / ss; sz_vol -= b_vol + GPT_ITEMS * SZ_GPTE / ss + 1; /* Estimated partition offset and size */ } else #endif { /* Partitioning is in MBR */ if (sz_vol > N_SEC_TRACK) { b_vol = N_SEC_TRACK; sz_vol -= b_vol; /* Estimated partition offset and size */ } } } } if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ /* Now start to create a FAT volume at b_vol and sz_vol */ do { /* Pre-determine the FAT type */ if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? */ if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64MS or sz_au > 128S ? */ fsty = FS_EXFAT; break; } } #if FF_LBA64 if (sz_vol >= 0x100000000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too large volume for FAT/FAT32 */ #endif if (sz_au > 128) sz_au = 128; /* Invalid AU for FAT/FAT32? */ if (fsopt & FM_FAT32) { /* FAT32 possible? */ if (!(fsopt & FM_FAT)) { /* no-FAT? */ fsty = FS_FAT32; break; } } if (!(fsopt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ fsty = FS_FAT16; } while (0); #if FF_FS_EXFAT if (fsty == FS_EXFAT) { /* Create an exFAT volume */ DWORD szb_bit, szb_case, sum, nb, cl, tbl[3]; WCHAR ch, si; UINT j, st; BYTE b; if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume for exFAT? */ #if FF_USE_TRIM lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Determine FAT location, data location and number of clusters */ if (sz_au == 0) { /* AU auto-selection */ sz_au = 8; if (sz_vol >= 0x80000) sz_au = 64; /* >= 512Ks */ if (sz_vol >= 0x4000000) sz_au = 256; /* >= 64Ms */ } b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ tbl[0] = (szb_bit + sz_au * ss - 1) / (sz_au * ss); /* Number of allocation bitmap clusters */ /* Create a compressed up-case table */ sect = b_data + sz_au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ if (ch != si) { si++; break; /* Store the up-case char if exist */ } for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ if (j >= 128) { ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; default: ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); i += 2; szb_case += 2; if (si == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */ n = (i + ss - 1) / ss; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; i = 0; } } while (si); tbl[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */ tbl[2] = 1; /* Number of root dir clusters */ /* Initialize the allocation bitmap */ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ do { mem_set(buf, 0, sz_buf * ss); for (i = 0; nb >= 8 && i < sz_buf * ss; buf[i++] = 0xFF, nb -= 8) ; for (b = 1; nb != 0 && i < sz_buf * ss; buf[i] |= b, b <<= 1, nb--) ; n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the FAT */ sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ j = nb = cl = 0; do { mem_set(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write index */ if (cl == 0) { /* Set FAT [0] and FAT[1] */ st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } do { /* Create chains of bitmap, up-case and root dir */ while (nb != 0 && i < sz_buf * ss) { /* Create a chain */ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); i += 4; cl++; nb--; } if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ } while (nb != 0 && i < sz_buf * ss); n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); /* Initialize the root directory */ mem_set(buf, 0, sz_buf * ss); buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */ buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + sz_au * (tbl[0] + tbl[1]); nsect = sz_au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); sect += n; nsect -= n; } while (nsect); /* Create two set of the exFAT VBR blocks */ sect = b_vol; for (n = 0; n < 2; n++) { /* Main record (+0) */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */ st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ for (buf[BPB_SecPerClusEx] = 0, i = sz_au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ buf[BPB_NumFATsEx] = 1; /* Number of FATs */ buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ for (i = sum = 0; i < ss; i++) { /* VBR checksum */ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); } if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Extended bootstrap record (+1..+8) */ mem_set(buf, 0, ss); st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ for (j = 1; j < 9; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* OEM/Reserved record (+9..+10) */ mem_set(buf, 0, ss); for ( ; j < 11; j++) { for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } /* Sum record (+11) */ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); } } else #endif /* FF_FS_EXFAT */ { /* Create an FAT/FAT32 volume */ do { pau = sz_au; /* Pre-determine number of clusters and FAT sub-type */ if (fsty == FS_FAT32) { /* FAT32 volume */ if (pau == 0) { /* AU auto-selection */ n = (DWORD)sz_vol / 0x20000; /* Volume size in unit of 128KS */ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = (DWORD)sz_vol / pau; /* Number of clusters */ sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 32; /* Number of reserved sectors */ sz_dir = 0; /* No static directory */ if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); } else { /* FAT volume */ if (pau == 0) { /* au auto-selection */ n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS */ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ } n_clst = (DWORD)sz_vol / pau; if (n_clst > MAX_FAT12) { n = n_clst * 2 + 4; /* FAT size [byte] */ } else { fsty = FS_FAT12; n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ } sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ sz_rsv = 1; /* Number of reserved sectors */ sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root dir size [sector] */ } b_fat = b_vol + sz_rsv; /* FAT base */ b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base */ /* Align data area to erase block boundary (for flash memory media) */ n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base */ if (fsty == FS_FAT32) { /* FAT32: Move FAT */ sz_rsv += n; b_fat += n; } else { /* FAT: Expand FAT */ if (n % n_fat) { /* Adjust fractional error if needed */ n--; sz_rsv++; b_fat++; } sz_fat += n / n_fat; } /* Determine number of clusters and final check of validity of the FAT sub-type */ if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau; if (fsty == FS_FAT32) { if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */ if (sz_au == 0 && (sz_au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fsty == FS_FAT16) { if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ if (sz_au == 0 && (pau * 2) <= 64) { sz_au = pau * 2; continue; /* Adjust cluster size and retry */ } if ((fsopt & FM_FAT32)) { fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */ } if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ LEAVE_MKFS(FR_MKFS_ABORTED); } } if (fsty == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ /* Ok, it is the valid cluster configuration */ break; } while (1); #if FF_USE_TRIM lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, lba); #endif /* Create FAT VBR */ mem_set(buf, 0, ss); mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ buf[BPB_NumFATs] = (BYTE)n_fat; /* Number of FATs */ st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries */ if (sz_vol < 0x10000) { st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ } else { st_dword(buf + BPB_TotSec32, (DWORD)sz_vol); /* Volume size in 32-bit LBA */ } buf[BPB_Media] = 0xF8; /* Media descriptor byte */ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ st_dword(buf + BPB_HiddSec, (DWORD)b_vol); /* Volume offset in the physical drive [sector] */ if (fsty == FS_FAT32) { st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_BootSig] = 0x29; /* Extended boot signature */ mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ /* Create FSINFO record if needed */ if (fsty == FS_FAT32) { disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ mem_set(buf, 0, ss); st_dword(buf + FSI_LeadSig, 0x41615252); st_dword(buf + FSI_StrucSig, 0x61417272); st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ st_word(buf + BS_55AA, 0xAA55); disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } /* Initialize FAT area */ mem_set(buf, 0, sz_buf * ss); sect = b_fat; /* FAT start sector */ for (i = 0; i < n_fat; i++) { /* Initialize FATs each */ if (fsty == FS_FAT32) { st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */ st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */ st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory) */ } else { st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ } nsect = sz_fat; /* Number of FAT sectors */ do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); mem_set(buf, 0, ss); /* Rest of FAT all are cleared */ sect += n; nsect -= n; } while (nsect); } /* Initialize root directory (fill with zero) */ nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ do { n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; } while (nsect); } /* A FAT volume has been created here */ /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { sys = 0x07; /* exFAT */ } else { if (fsty == FS_FAT32) { sys = 0x0C; /* FAT32X */ } else { if (sz_vol >= 0x10000) { sys = 0x06; /* FAT12/16 (large) */ } else { sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ } } } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ if (!FF_LBA64 || !(fsopt & 0x80)) { /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ lba[0] = sz_vol, lba[1] = 0; fr = create_partition(pdrv, lba, sys, buf); if (fr != FR_OK) LEAVE_MKFS(fr); } } if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); LEAVE_MKFS(FR_OK); } #if FF_MULTI_PARTITION /*-----------------------------------------------------------------------*/ /* Create Partition Table on the Physical Drive */ /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ const LBA_t ptbl[], /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer (null: use heap memory) */ ) { BYTE *buf = (BYTE*)work; DSTATUS stat; stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); } #endif /* FF_MULTI_PARTITION */ #endif /* !FF_FS_READONLY && FF_USE_MKFS */ #if FF_USE_STRFUNC #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) #error Wrong FF_STRF_ENCODE setting #endif /*-----------------------------------------------------------------------*/ /* Get a String from the File */ /*-----------------------------------------------------------------------*/ TCHAR* f_gets ( TCHAR* buff, /* Pointer to the buffer to store read string */ int len, /* Size of string buffer (items) */ FIL* fp /* Pointer to the file object */ ) { int nc = 0; TCHAR *p = buff; BYTE s[4]; UINT rc; DWORD dc; #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 WCHAR wc; #endif #if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 UINT ct; #endif #if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ /* Make a room for the character and terminator */ if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; if (FF_LFN_UNICODE == 3) len -= 1; while (nc < len) { #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ f_read(fp, s, 1, &rc); /* Get a code unit */ if (rc != 1) break; /* EOF? */ wc = s[0]; if (dbc_1st((BYTE)wc)) { /* DBC 1st byte? */ f_read(fp, s, 1, &rc); /* Get DBC 2nd byte */ if (rc != 1 || !dbc_2nd(s[0])) continue; /* Wrong code? */ wc = wc << 8 | s[0]; } dc = ff_oem2uni(wc, CODEPAGE); /* OEM --> */ if (dc == 0) continue; #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ f_read(fp, s, 2, &rc); /* Get a code unit */ if (rc != 2) break; /* EOF? */ dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (IsSurrogateL(dc)) continue; /* Broken surrogate pair? */ if (IsSurrogateH(dc)) { /* High surrogate? */ f_read(fp, s, 2, &rc); /* Get low surrogate */ if (rc != 2) break; /* EOF? */ wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; if (!IsSurrogateL(wc)) continue; /* Broken surrogate pair? */ dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); /* Merge surrogate pair */ } #else /* Read a character in UTF-8 */ f_read(fp, s, 1, &rc); /* Get a code unit */ if (rc != 1) break; /* EOF? */ dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; rc = 0; do { /* Merge the byte sequence */ if ((s[rc] & 0xC0) != 0x80) break; dc = dc << 6 | (s[rc] & 0x3F); } while (++rc < ct); if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ } #endif /* A code point is avaialble in dc to be output */ if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ #if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ } *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ #elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ if (dc < 0x80) { /* Single byte? */ *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ } else { if (dc < 0x800) { /* 2-byte sequence? */ *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; } else { if (dc < 0x10000) { /* 3-byte sequence? */ *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 3; } else { /* 4-byte sequence? */ *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 4; } } } #endif } #else /* Byte-by-byte read without any conversion (ANSI/OEM API) */ len -= 1; /* Make a room for the terminator */ while (nc < len) { f_read(fp, s, 1, &rc); /* Get a byte */ if (rc != 1) break; /* EOF? */ dc = s[0]; if (FF_USE_STRFUNC == 2 && dc == '\r') continue; *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; } #endif *p = 0; /* Terminate the string */ return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ } #if !FF_FS_READONLY #include <stdarg.h> /*-----------------------------------------------------------------------*/ /* Put a Character to the File (sub-functions) */ /*-----------------------------------------------------------------------*/ /* Putchar output buffer and work area */ typedef struct { FIL *fp; /* Ptr to the writing file */ int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ #if FF_USE_LFN && FF_LFN_UNICODE == 1 WCHAR hs; #elif FF_USE_LFN && FF_LFN_UNICODE == 2 BYTE bs[4]; UINT wi, ct; #endif BYTE buf[64]; /* Write buffer */ } putbuff; /* Buffered write with code conversion */ static void putc_bfd (putbuff* pb, TCHAR c) { UINT n; int i, nc; #if FF_USE_LFN && FF_LFN_UNICODE WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; TCHAR *tp; #endif #endif if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ putc_bfd(pb, '\r'); } i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; nc = pb->nchr; /* Write unit counter */ #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ if (IsSurrogateH(c)) { /* High surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; if (hs != 0) { /* There is a leading high surrogate */ if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ } else { if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ if ((BYTE)c < 0x80) break; /* Single byte? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ return; } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ pb->ct = 0; continue; } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ if (--pb->ct == 0) break; /* End of multi-byte sequence? */ return; } } tp = (TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ } else { hs = 0; wc = (WCHAR)c; } #endif /* A code point in UTF-16 is available in hs and wc */ #if FF_STRF_ENCODE == 1 /* Write a code point in UTF-16LE */ if (hs != 0) { /* Surrogate pair? */ st_word(&pb->buf[i], hs); i += 2; nc++; } st_word(&pb->buf[i], wc); i += 2; #elif FF_STRF_ENCODE == 2 /* Write a code point in UTF-16BE */ if (hs != 0) { /* Surrogate pair? */ pb->buf[i++] = (BYTE)(hs >> 8); pb->buf[i++] = (BYTE)hs; nc++; } pb->buf[i++] = (BYTE)(wc >> 8); pb->buf[i++] = (BYTE)wc; #elif FF_STRF_ENCODE == 3 /* Write a code point in UTF-8 */ if (hs != 0) { /* 4-byte sequence? */ nc += 3; hs = (hs & 0x3FF) + 0x40; pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } else { if (wc < 0x80) { /* Single byte? */ pb->buf[i++] = (BYTE)wc; } else { if (wc < 0x800) { /* 2-byte sequence? */ nc += 1; pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); } else { /* 3-byte sequence */ nc += 2; pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); } pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); } } #else /* Write a code point in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ if (wc == 0) return; if (wc >= 0x100) { pb->buf[i++] = (BYTE)(wc >> 8); nc++; } pb->buf[i++] = (BYTE)wc; #endif #else /* ANSI/OEM input (without re-encoding) */ pb->buf[i++] = (BYTE)c; #endif if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ f_write(pb->fp, pb->buf, (UINT)i, &n); i = (n == (UINT)i) ? 0 : -1; } pb->idx = i; pb->nchr = nc + 1; } /* Flush remaining characters in the buffer */ static int putc_flush (putbuff* pb) { UINT nw; if ( pb->idx >= 0 /* Flush buffered characters to the file */ && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK && (UINT)pb->idx == nw) return pb->nchr; return EOF; } /* Initialize write buffer */ static void putc_init (putbuff* pb, FIL* fp) { mem_set(pb, 0, sizeof (putbuff)); pb->fp = fp; } int f_putc ( TCHAR c, /* A character to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); putc_bfd(&pb, c); /* Put the character */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a String to the File */ /*-----------------------------------------------------------------------*/ int f_puts ( const TCHAR* str, /* Pointer to the string to be output */ FIL* fp /* Pointer to the file object */ ) { putbuff pb; putc_init(&pb, fp); while (*str) putc_bfd(&pb, *str++); /* Put the string */ return putc_flush(&pb); } /*-----------------------------------------------------------------------*/ /* Put a Formatted String to the File */ /*-----------------------------------------------------------------------*/ int f_printf ( FIL* fp, /* Pointer to the file object */ const TCHAR* fmt, /* Pointer to the format string */ ... /* Optional arguments... */ ) { va_list arp; putbuff pb; BYTE f, r; UINT i, j, w; DWORD v; TCHAR c, d, str[32], *p; putc_init(&pb, fp); va_start(arp, fmt); for (;;) { c = *fmt++; if (c == 0) break; /* End of string */ if (c != '%') { /* Non escape character */ putc_bfd(&pb, c); continue; } w = f = 0; c = *fmt++; if (c == '0') { /* Flag: '0' padding */ f = 1; c = *fmt++; } else { if (c == '-') { /* Flag: left justified */ f = 2; c = *fmt++; } } if (c == '*') { /* Minimum width by argument */ w = va_arg(arp, int); c = *fmt++; } else { while (IsDigit(c)) { /* Minimum width */ w = w * 10 + c - '0'; c = *fmt++; } } if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ f |= 4; c = *fmt++; } if (c == 0) break; d = c; if (IsLower(d)) d -= 0x20; switch (d) { /* Atgument type is... */ case 'S' : /* String */ p = va_arg(arp, TCHAR*); for (j = 0; p[j]; j++) ; if (!(f & 2)) { /* Right padded */ while (j++ < w) putc_bfd(&pb, ' ') ; } while (*p) putc_bfd(&pb, *p++) ; /* String body */ while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ continue; case 'C' : /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; case 'B' : /* Unsigned binary */ r = 2; break; case 'O' : /* Unsigned octal */ r = 8; break; case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; case 'X' : /* Unsigned hexdecimal */ r = 16; break; default: /* Unknown type (pass-through) */ putc_bfd(&pb, c); continue; } /* Get an argument and put it in numeral */ v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); if (d == 'D' && (v & 0x80000000)) { v = 0 - v; f |= 8; } i = 0; do { d = (TCHAR)(v % r); v /= r; if (d > 9) d += (c == 'x') ? 0x27 : 0x07; str[i++] = d + '0'; } while (v && i < sizeof str / sizeof *str); if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; if (!(f & 2)) { while (j++ < w) putc_bfd(&pb, d); /* Right pad */ } do { putc_bfd(&pb, str[--i]); /* Number body */ } while (i); while (j++ < w) putc_bfd(&pb, d); /* Left pad */ } va_end(arp); return putc_flush(&pb); } #endif /* !FF_FS_READONLY */ #endif /* FF_USE_STRFUNC */ #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ /* Set Active Codepage for the Path Name */ /*-----------------------------------------------------------------------*/ FRESULT f_setcp ( WORD cp /* Value to be set as active code page */ ) { static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ ExCvt = 0; DbcTbl = tables[i]; } else { /* SBCS */ ExCvt = tables[i]; DbcTbl = 0; } return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ ================================================ FILE: fusee/program/source/fatfs/ff.h ================================================ /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem module R0.14 / /-----------------------------------------------------------------------------/ / / Copyright (C) 2019, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. / /----------------------------------------------------------------------------*/ #ifndef FF_DEFINED #define FF_DEFINED 86606 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif #include "ffconf.h" /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif /* Integer types used for FatFs API */ #if defined(_WIN32) /* Main development platform */ #define FF_INTDEF 2 #include <windows.h> typedef unsigned __int64 QWORD; #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ #define FF_INTDEF 2 #include <stdint.h> typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef uint16_t WORD; /* 16-bit unsigned integer */ typedef uint32_t DWORD; /* 32-bit unsigned integer */ typedef uint64_t QWORD; /* 64-bit unsigned integer */ typedef WORD WCHAR; /* UTF-16 character type */ #else /* Earlier than C99 */ #define FF_INTDEF 1 typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ typedef unsigned char BYTE; /* char must be 8-bit */ typedef unsigned short WORD; /* 16-bit unsigned integer */ typedef unsigned long DWORD; /* 32-bit unsigned integer */ typedef WORD WCHAR; /* UTF-16 character type */ #endif /* Definitions of volume management */ #if FF_MULTI_PARTITION /* Multiple partition configuration */ typedef struct { BYTE pd; /* Physical drive number */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ #endif #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ #endif #endif /* Type of path name strings on FatFs API */ #ifndef _INC_TCHAR #define _INC_TCHAR #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ typedef char TCHAR; #define _T(x) u8 ## x #define _TEXT(x) u8 ## x #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ typedef DWORD TCHAR; #define _T(x) U ## x #define _TEXT(x) U ## x #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) #error Wrong FF_LFN_UNICODE setting #else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif #endif /* Type of file size and LBA variables */ #if FF_FS_EXFAT #if FF_INTDEF != 2 #error exFAT feature wants C99 or later #endif typedef QWORD FSIZE_t; #if FF_LBA64 typedef QWORD LBA_t; #else typedef DWORD LBA_t; #endif #else #if FF_LBA64 #error exFAT needs to be enabled when enable 64-bit LBA #endif typedef DWORD FSIZE_t; typedef DWORD LBA_t; #endif /* Filesystem object structure (FATFS) */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ #if FF_MAX_SS != FF_MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif #if FF_USE_LFN WCHAR* lfnbuf; /* LFN working buffer */ #endif #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif #if FF_FS_REENTRANT FF_SYNC_t sobj; /* Identifier of sync object */ #endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ #endif #if FF_FS_RPATH DWORD cdir; /* Current directory start cluster (0:root) */ #if FF_FS_EXFAT DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD fsize; /* Size of an FAT [sectors] */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t database; /* Data base sector */ #if FF_FS_EXFAT LBA_t bitbase; /* Allocation bitmap base sector */ #endif LBA_t winsect; /* Current sector appearing in the win[] */ BYTE pad[4]; BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; /* Object ID and allocation information (FFOBJID) */ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ #endif #if FF_FS_LOCK UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ #endif } FFOBJID; /* File object structure (FIL) */ typedef struct { FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ #if !FF_FS_READONLY LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !FF_FS_TINY BYTE buf[FF_MAX_SS]; /* File private data read/write window */ #endif } FIL; /* Directory object structure (DIR) */ typedef struct { FFOBJID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ LBA_t sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if FF_USE_LFN DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ #endif #if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; /* File information structure (FILINFO) */ typedef struct { FSIZE_t fsize; /* File size */ WORD fdate; /* Modified date */ WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ #endif } FILINFO; /* Format parameter structure (MKFS_PARM) */ typedef struct { BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ BYTE n_fat; /* Number of FATs */ UINT align; /* Data area alignment (sector) */ UINT n_root; /* Number of root directory entries */ DWORD au_size; /* Cluster size (byte) */ } MKFS_PARM; /* File function return code (FRESULT) */ typedef enum { FR_OK = 0, /* (0) Succeeded */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ FR_INT_ERR, /* (2) Assertion failed */ FR_NOT_READY, /* (3) The physical drive cannot work */ FR_NO_FILE, /* (4) Could not find the file */ FR_NO_PATH, /* (5) Could not find the path */ FR_INVALID_NAME, /* (6) The path name format is invalid */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ FR_EXIST, /* (8) Access denied due to prohibited access */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; /*--------------------------------------------------------------*/ /* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) #define f_rmdir(path) f_unlink(path) #define f_unmount(path) f_mount(0, path, 0) #ifndef EOF #define EOF (-1) #endif /*--------------------------------------------------------------*/ /* Additional user defined functions */ /* RTC function */ #if !FF_FS_READONLY && !FF_FS_NORTC DWORD get_fattime (void); #endif /* LFN support functions */ #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif #if FF_USE_LFN == 3 /* Dynamic memory allocation */ void* ff_memalloc (UINT msize); /* Allocate memory block */ void ff_memfree (void* mblock); /* Free memory block */ #endif /* Sync functions */ #if FF_FS_REENTRANT int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ #endif /*--------------------------------------------------------------*/ /* Flags and offset address */ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 #define FA_OPEN_APPEND 0x30 /* Fast seek controls (2nd argument of f_lseek) */ #define CREATE_LINKMAP ((FSIZE_t)0 - 1) /* Format options (2nd argument of f_mkfs) */ #define FM_FAT 0x01 #define FM_FAT32 0x02 #define FM_EXFAT 0x04 #define FM_ANY 0x07 #define FM_SFD 0x08 /* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 #define FS_EXFAT 4 /* File attribute bits for directory entry (FILINFO.fattrib) */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ #ifdef __cplusplus } #endif #endif /* FF_DEFINED */ ================================================ FILE: fusee/program/source/fatfs/ffconf.h ================================================ /*---------------------------------------------------------------------------/ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ #define FFCONF_DEF 86606 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ #define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ #define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ #define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ #define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define FF_USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ #define FF_USE_FASTSEEK 0 /* This option switches fast seek function. (0:Disable or 1:Enable) */ #define FF_USE_EXPAND 1 /* This option switches f_expand function. (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 0 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ #define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ #define FF_CODE_PAGE 850 /* This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / / 437 - U.S. / 720 - Arabic / 737 - Greek / 771 - KBL / 775 - Baltic / 850 - Latin 1 / 852 - Latin 2 / 855 - Cyrillic / 857 - Turkish / 860 - Portuguese / 861 - Icelandic / 862 - Hebrew / 863 - Canadian French / 864 - Arabic / 865 - Nordic / 866 - Russian / 869 - Greek 2 / 932 - Japanese (DBCS) / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) / 0 - Include all code pages above and configured by f_setcp() */ #define FF_USE_LFN 1 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ #define FF_LFN_UNICODE 2 /* This option switches the character encoding on the API when LFN is enabled. / / 0: ANSI/OEM in current CP (TCHAR = char) / 1: Unicode in UTF-16 (TCHAR = WCHAR) / 2: Unicode in UTF-8 (TCHAR = char) / 3: Unicode in UTF-32 (TCHAR = DWORD) / / Also behavior of string I/O functions will be affected by this option. / When LFN is not enabled, this option has no effect. */ #define FF_LFN_BUF 255 #define FF_SFN_BUF 12 /* This set of options defines size of file name members in the FILINFO structure / which is used to read out directory items. These values should be suffcient for / the file names to read. The maximum possible length of the read file name depends / on character encoding. When LFN is not enabled, these options have no effect. */ #define FF_STRF_ENCODE 3 /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), / f_putc(), f_puts and f_printf() convert the character encoding in it. / This option selects assumption of character encoding ON THE FILE to be / read/written via those functions. / / 0: ANSI/OEM in current CP / 1: Unicode in UTF-16LE / 2: Unicode in UTF-16BE / 3: Unicode in UTF-8 */ #define FF_FS_RPATH 0 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. */ /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ #define FF_VOLUMES 2 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 1 #define FF_VOLUME_STRS "sdmc","sys" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ #define FF_MULTI_PARTITION 0 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ #define FF_MIN_SS 512 #define FF_MAX_SS 512 /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / for variable sector size mode and disk_ioctl() function needs to implement / GET_SECTOR_SIZE command. */ #define FF_LBA64 0 /* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ #define FF_MIN_GPT 0x100000000 /* Minimum number of sectors to switch GPT format to create partition in f_mkfs and / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ #define FF_USE_TRIM 0 /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ #define FF_FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ #define FF_FS_EXFAT 1 /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define FF_FS_NORTC 1 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2019 /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. / These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. / bit0=1: Do not trust free cluster count in the FSINFO. / bit1=0: Use last allocated cluster number in the FSINFO if available. / bit1=1: Do not trust last allocated cluster number in the FSINFO. */ #define FF_FS_LOCK 0 /* The option FF_FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. / >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file / lock control is independent of re-entrancy. */ /* #include <somertos.h> // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 #define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / / The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ /*--- End of configuration options ---*/ ================================================ FILE: fusee/program/source/fatfs/ffsystem.c ================================================ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ /* (C)ChaN, 2018 */ /*------------------------------------------------------------------------*/ #include "ff.h" #if FF_USE_LFN == 3 /* Dynamic memory allocation */ /*------------------------------------------------------------------------*/ /* Allocate a memory block */ /*------------------------------------------------------------------------*/ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { return malloc(msize); /* Allocate a new memory block with POSIX API */ } /*------------------------------------------------------------------------*/ /* Free a memory block */ /*------------------------------------------------------------------------*/ void ff_memfree ( void* mblock /* Pointer to the memory block to free (nothing to do if null) */ ) { free(mblock); /* Free the memory block with POSIX API */ } #endif #if FF_FS_REENTRANT /* Mutal exclusion */ /*------------------------------------------------------------------------*/ /* Create a Synchronization Object */ /*------------------------------------------------------------------------*/ /* This function is called in f_mount() function to create a new / synchronization object for the volume, such as semaphore and mutex. / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. */ //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ BYTE vol, /* Corresponding volume (logical drive number) */ FF_SYNC_t* sobj /* Pointer to return the created sync object */ ) { /* Win32 */ *sobj = CreateMutex(NULL, FALSE, NULL); return (int)(*sobj != INVALID_HANDLE_VALUE); /* uITRON */ // T_CSEM csem = {TA_TPRI,1,1}; // *sobj = acre_sem(&csem); // return (int)(*sobj > 0); /* uC/OS-II */ // OS_ERR err; // *sobj = OSMutexCreate(0, &err); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // *sobj = xSemaphoreCreateMutex(); // return (int)(*sobj != NULL); /* CMSIS-RTOS */ // *sobj = osMutexCreate(&Mutex[vol]); // return (int)(*sobj != NULL); } /*------------------------------------------------------------------------*/ /* Delete a Synchronization Object */ /*------------------------------------------------------------------------*/ /* This function is called in f_mount() function to delete a synchronization / object that created with ff_cre_syncobj() function. When a 0 is returned, / the f_mount() function fails with FR_INT_ERR. */ int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ ) { /* Win32 */ return (int)CloseHandle(sobj); /* uITRON */ // return (int)(del_sem(sobj) == E_OK); /* uC/OS-II */ // OS_ERR err; // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // vSemaphoreDelete(sobj); // return 1; /* CMSIS-RTOS */ // return (int)(osMutexDelete(sobj) == osOK); } /*------------------------------------------------------------------------*/ /* Request Grant to Access the Volume */ /*------------------------------------------------------------------------*/ /* This function is called on entering file functions to lock the volume. / When a 0 is returned, the file function fails with FR_TIMEOUT. */ int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ FF_SYNC_t sobj /* Sync object to wait */ ) { /* Win32 */ return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); /* uITRON */ // return (int)(wai_sem(sobj) == E_OK); /* uC/OS-II */ // OS_ERR err; // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); // return (int)(err == OS_NO_ERR); /* FreeRTOS */ // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); /* CMSIS-RTOS */ // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); } /*------------------------------------------------------------------------*/ /* Release Grant to Access the Volume */ /*------------------------------------------------------------------------*/ /* This function is called on leaving file functions to unlock the volume. */ void ff_rel_grant ( FF_SYNC_t sobj /* Sync object to be signaled */ ) { /* Win32 */ ReleaseMutex(sobj); /* uITRON */ // sig_sem(sobj); /* uC/OS-II */ // OSMutexPost(sobj); /* FreeRTOS */ // xSemaphoreGive(sobj); /* CMSIS-RTOS */ // osMutexRelease(sobj); } #endif ================================================ FILE: fusee/program/source/fatfs/ffunicode.c ================================================ /*------------------------------------------------------------------------*/ /* Unicode handling functions for FatFs R0.13+ */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / / utilitiy for the code conversion, this module should be modified to use / / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* / Copyright (C) 2014, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / / This software is provided by the copyright holder and contributors "AS IS" / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. */ #include "ff.h" #if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */ static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ 0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180, 0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6, 0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE, 0x03A1, 0x83AF, 0x03A3, 0x83B0, 0x03A4, 0x83B1, 0x03A5, 0x83B2, 0x03A6, 0x83B3, 0x03A7, 0x83B4, 0x03A8, 0x83B5, 0x03A9, 0x83B6, 0x03B1, 0x83BF, 0x03B2, 0x83C0, 0x03B3, 0x83C1, 0x03B4, 0x83C2, 0x03B5, 0x83C3, 0x03B6, 0x83C4, 0x03B7, 0x83C5, 0x03B8, 0x83C6, 0x03B9, 0x83C7, 0x03BA, 0x83C8, 0x03BB, 0x83C9, 0x03BC, 0x83CA, 0x03BD, 0x83CB, 0x03BE, 0x83CC, 0x03BF, 0x83CD, 0x03C0, 0x83CE, 0x03C1, 0x83CF, 0x03C3, 0x83D0, 0x03C4, 0x83D1, 0x03C5, 0x83D2, 0x03C6, 0x83D3, 0x03C7, 0x83D4, 0x03C8, 0x83D5, 0x03C9, 0x83D6, 0x0401, 0x8446, 0x0410, 0x8440, 0x0411, 0x8441, 0x0412, 0x8442, 0x0413, 0x8443, 0x0414, 0x8444, 0x0415, 0x8445, 0x0416, 0x8447, 0x0417, 0x8448, 0x0418, 0x8449, 0x0419, 0x844A, 0x041A, 0x844B, 0x041B, 0x844C, 0x041C, 0x844D, 0x041D, 0x844E, 0x041E, 0x844F, 0x041F, 0x8450, 0x0420, 0x8451, 0x0421, 0x8452, 0x0422, 0x8453, 0x0423, 0x8454, 0x0424, 0x8455, 0x0425, 0x8456, 0x0426, 0x8457, 0x0427, 0x8458, 0x0428, 0x8459, 0x0429, 0x845A, 0x042A, 0x845B, 0x042B, 0x845C, 0x042C, 0x845D, 0x042D, 0x845E, 0x042E, 0x845F, 0x042F, 0x8460, 0x0430, 0x8470, 0x0431, 0x8471, 0x0432, 0x8472, 0x0433, 0x8473, 0x0434, 0x8474, 0x0435, 0x8475, 0x0436, 0x8477, 0x0437, 0x8478, 0x0438, 0x8479, 0x0439, 0x847A, 0x043A, 0x847B, 0x043B, 0x847C, 0x043C, 0x847D, 0x043D, 0x847E, 0x043E, 0x8480, 0x043F, 0x8481, 0x0440, 0x8482, 0x0441, 0x8483, 0x0442, 0x8484, 0x0443, 0x8485, 0x0444, 0x8486, 0x0445, 0x8487, 0x0446, 0x8488, 0x0447, 0x8489, 0x0448, 0x848A, 0x0449, 0x848B, 0x044A, 0x848C, 0x044B, 0x848D, 0x044C, 0x848E, 0x044D, 0x848F, 0x044E, 0x8490, 0x044F, 0x8491, 0x0451, 0x8476, 0x2010, 0x815D, 0x2015, 0x815C, 0x2018, 0x8165, 0x2019, 0x8166, 0x201C, 0x8167, 0x201D, 0x8168, 0x2020, 0x81F5, 0x2021, 0x81F6, 0x2025, 0x8164, 0x2026, 0x8163, 0x2030, 0x81F1, 0x2032, 0x818C, 0x2033, 0x818D, 0x203B, 0x81A6, 0x2103, 0x818E, 0x2116, 0x8782, 0x2121, 0x8784, 0x212B, 0x81F0, 0x2160, 0x8754, 0x2161, 0x8755, 0x2162, 0x8756, 0x2163, 0x8757, 0x2164, 0x8758, 0x2165, 0x8759, 0x2166, 0x875A, 0x2167, 0x875B, 0x2168, 0x875C, 0x2169, 0x875D, 0x2170, 0xFA40, 0x2171, 0xFA41, 0x2172, 0xFA42, 0x2173, 0xFA43, 0x2174, 0xFA44, 0x2175, 0xFA45, 0x2176, 0xFA46, 0x2177, 0xFA47, 0x2178, 0xFA48, 0x2179, 0xFA49, 0x2190, 0x81A9, 0x2191, 0x81AA, 0x2192, 0x81A8, 0x2193, 0x81AB, 0x21D2, 0x81CB, 0x21D4, 0x81CC, 0x2200, 0x81CD, 0x2202, 0x81DD, 0x2203, 0x81CE, 0x2207, 0x81DE, 0x2208, 0x81B8, 0x220B, 0x81B9, 0x2211, 0x8794, 0x221A, 0x81E3, 0x221D, 0x81E5, 0x221E, 0x8187, 0x221F, 0x8798, 0x2220, 0x81DA, 0x2225, 0x8161, 0x2227, 0x81C8, 0x2228, 0x81C9, 0x2229, 0x81BF, 0x222A, 0x81BE, 0x222B, 0x81E7, 0x222C, 0x81E8, 0x222E, 0x8793, 0x2234, 0x8188, 0x2235, 0x81E6, 0x223D, 0x81E4, 0x2252, 0x81E0, 0x2260, 0x8182, 0x2261, 0x81DF, 0x2266, 0x8185, 0x2267, 0x8186, 0x226A, 0x81E1, 0x226B, 0x81E2, 0x2282, 0x81BC, 0x2283, 0x81BD, 0x2286, 0x81BA, 0x2287, 0x81BB, 0x22A5, 0x81DB, 0x22BF, 0x8799, 0x2312, 0x81DC, 0x2460, 0x8740, 0x2461, 0x8741, 0x2462, 0x8742, 0x2463, 0x8743, 0x2464, 0x8744, 0x2465, 0x8745, 0x2466, 0x8746, 0x2467, 0x8747, 0x2468, 0x8748, 0x2469, 0x8749, 0x246A, 0x874A, 0x246B, 0x874B, 0x246C, 0x874C, 0x246D, 0x874D, 0x246E, 0x874E, 0x246F, 0x874F, 0x2470, 0x8750, 0x2471, 0x8751, 0x2472, 0x8752, 0x2473, 0x8753, 0x2500, 0x849F, 0x2501, 0x84AA, 0x2502, 0x84A0, 0x2503, 0x84AB, 0x250C, 0x84A1, 0x250F, 0x84AC, 0x2510, 0x84A2, 0x2513, 0x84AD, 0x2514, 0x84A4, 0x2517, 0x84AF, 0x2518, 0x84A3, 0x251B, 0x84AE, 0x251C, 0x84A5, 0x251D, 0x84BA, 0x2520, 0x84B5, 0x2523, 0x84B0, 0x2524, 0x84A7, 0x2525, 0x84BC, 0x2528, 0x84B7, 0x252B, 0x84B2, 0x252C, 0x84A6, 0x252F, 0x84B6, 0x2530, 0x84BB, 0x2533, 0x84B1, 0x2534, 0x84A8, 0x2537, 0x84B8, 0x2538, 0x84BD, 0x253B, 0x84B3, 0x253C, 0x84A9, 0x253F, 0x84B9, 0x2542, 0x84BE, 0x254B, 0x84B4, 0x25A0, 0x81A1, 0x25A1, 0x81A0, 0x25B2, 0x81A3, 0x25B3, 0x81A2, 0x25BC, 0x81A5, 0x25BD, 0x81A4, 0x25C6, 0x819F, 0x25C7, 0x819E, 0x25CB, 0x819B, 0x25CE, 0x819D, 0x25CF, 0x819C, 0x25EF, 0x81FC, 0x2605, 0x819A, 0x2606, 0x8199, 0x2640, 0x818A, 0x2642, 0x8189, 0x266A, 0x81F4, 0x266D, 0x81F3, 0x266F, 0x81F2, 0x3000, 0x8140, 0x3001, 0x8141, 0x3002, 0x8142, 0x3003, 0x8156, 0x3005, 0x8158, 0x3006, 0x8159, 0x3007, 0x815A, 0x3008, 0x8171, 0x3009, 0x8172, 0x300A, 0x8173, 0x300B, 0x8174, 0x300C, 0x8175, 0x300D, 0x8176, 0x300E, 0x8177, 0x300F, 0x8178, 0x3010, 0x8179, 0x3011, 0x817A, 0x3012, 0x81A7, 0x3013, 0x81AC, 0x3014, 0x816B, 0x3015, 0x816C, 0x301D, 0x8780, 0x301F, 0x8781, 0x3041, 0x829F, 0x3042, 0x82A0, 0x3043, 0x82A1, 0x3044, 0x82A2, 0x3045, 0x82A3, 0x3046, 0x82A4, 0x3047, 0x82A5, 0x3048, 0x82A6, 0x3049, 0x82A7, 0x304A, 0x82A8, 0x304B, 0x82A9, 0x304C, 0x82AA, 0x304D, 0x82AB, 0x304E, 0x82AC, 0x304F, 0x82AD, 0x3050, 0x82AE, 0x3051, 0x82AF, 0x3052, 0x82B0, 0x3053, 0x82B1, 0x3054, 0x82B2, 0x3055, 0x82B3, 0x3056, 0x82B4, 0x3057, 0x82B5, 0x3058, 0x82B6, 0x3059, 0x82B7, 0x305A, 0x82B8, 0x305B, 0x82B9, 0x305C, 0x82BA, 0x305D, 0x82BB, 0x305E, 0x82BC, 0x305F, 0x82BD, 0x3060, 0x82BE, 0x3061, 0x82BF, 0x3062, 0x82C0, 0x3063, 0x82C1, 0x3064, 0x82C2, 0x3065, 0x82C3, 0x3066, 0x82C4, 0x3067, 0x82C5, 0x3068, 0x82C6, 0x3069, 0x82C7, 0x306A, 0x82C8, 0x306B, 0x82C9, 0x306C, 0x82CA, 0x306D, 0x82CB, 0x306E, 0x82CC, 0x306F, 0x82CD, 0x3070, 0x82CE, 0x3071, 0x82CF, 0x3072, 0x82D0, 0x3073, 0x82D1, 0x3074, 0x82D2, 0x3075, 0x82D3, 0x3076, 0x82D4, 0x3077, 0x82D5, 0x3078, 0x82D6, 0x3079, 0x82D7, 0x307A, 0x82D8, 0x307B, 0x82D9, 0x307C, 0x82DA, 0x307D, 0x82DB, 0x307E, 0x82DC, 0x307F, 0x82DD, 0x3080, 0x82DE, 0x3081, 0x82DF, 0x3082, 0x82E0, 0x3083, 0x82E1, 0x3084, 0x82E2, 0x3085, 0x82E3, 0x3086, 0x82E4, 0x3087, 0x82E5, 0x3088, 0x82E6, 0x3089, 0x82E7, 0x308A, 0x82E8, 0x308B, 0x82E9, 0x308C, 0x82EA, 0x308D, 0x82EB, 0x308E, 0x82EC, 0x308F, 0x82ED, 0x3090, 0x82EE, 0x3091, 0x82EF, 0x3092, 0x82F0, 0x3093, 0x82F1, 0x309B, 0x814A, 0x309C, 0x814B, 0x309D, 0x8154, 0x309E, 0x8155, 0x30A1, 0x8340, 0x30A2, 0x8341, 0x30A3, 0x8342, 0x30A4, 0x8343, 0x30A5, 0x8344, 0x30A6, 0x8345, 0x30A7, 0x8346, 0x30A8, 0x8347, 0x30A9, 0x8348, 0x30AA, 0x8349, 0x30AB, 0x834A, 0x30AC, 0x834B, 0x30AD, 0x834C, 0x30AE, 0x834D, 0x30AF, 0x834E, 0x30B0, 0x834F, 0x30B1, 0x8350, 0x30B2, 0x8351, 0x30B3, 0x8352, 0x30B4, 0x8353, 0x30B5, 0x8354, 0x30B6, 0x8355, 0x30B7, 0x8356, 0x30B8, 0x8357, 0x30B9, 0x8358, 0x30BA, 0x8359, 0x30BB, 0x835A, 0x30BC, 0x835B, 0x30BD, 0x835C, 0x30BE, 0x835D, 0x30BF, 0x835E, 0x30C0, 0x835F, 0x30C1, 0x8360, 0x30C2, 0x8361, 0x30C3, 0x8362, 0x30C4, 0x8363, 0x30C5, 0x8364, 0x30C6, 0x8365, 0x30C7, 0x8366, 0x30C8, 0x8367, 0x30C9, 0x8368, 0x30CA, 0x8369, 0x30CB, 0x836A, 0x30CC, 0x836B, 0x30CD, 0x836C, 0x30CE, 0x836D, 0x30CF, 0x836E, 0x30D0, 0x836F, 0x30D1, 0x8370, 0x30D2, 0x8371, 0x30D3, 0x8372, 0x30D4, 0x8373, 0x30D5, 0x8374, 0x30D6, 0x8375, 0x30D7, 0x8376, 0x30D8, 0x8377, 0x30D9, 0x8378, 0x30DA, 0x8379, 0x30DB, 0x837A, 0x30DC, 0x837B, 0x30DD, 0x837C, 0x30DE, 0x837D, 0x30DF, 0x837E, 0x30E0, 0x8380, 0x30E1, 0x8381, 0x30E2, 0x8382, 0x30E3, 0x8383, 0x30E4, 0x8384, 0x30E5, 0x8385, 0x30E6, 0x8386, 0x30E7, 0x8387, 0x30E8, 0x8388, 0x30E9, 0x8389, 0x30EA, 0x838A, 0x30EB, 0x838B, 0x30EC, 0x838C, 0x30ED, 0x838D, 0x30EE, 0x838E, 0x30EF, 0x838F, 0x30F0, 0x8390, 0x30F1, 0x8391, 0x30F2, 0x8392, 0x30F3, 0x8393, 0x30F4, 0x8394, 0x30F5, 0x8395, 0x30F6, 0x8396, 0x30FB, 0x8145, 0x30FC, 0x815B, 0x30FD, 0x8152, 0x30FE, 0x8153, 0x3231, 0x878A, 0x3232, 0x878B, 0x3239, 0x878C, 0x32A4, 0x8785, 0x32A5, 0x8786, 0x32A6, 0x8787, 0x32A7, 0x8788, 0x32A8, 0x8789, 0x3303, 0x8765, 0x330D, 0x8769, 0x3314, 0x8760, 0x3318, 0x8763, 0x3322, 0x8761, 0x3323, 0x876B, 0x3326, 0x876A, 0x3327, 0x8764, 0x332B, 0x876C, 0x3336, 0x8766, 0x333B, 0x876E, 0x3349, 0x875F, 0x334A, 0x876D, 0x334D, 0x8762, 0x3351, 0x8767, 0x3357, 0x8768, 0x337B, 0x877E, 0x337C, 0x878F, 0x337D, 0x878E, 0x337E, 0x878D, 0x338E, 0x8772, 0x338F, 0x8773, 0x339C, 0x876F, 0x339D, 0x8770, 0x339E, 0x8771, 0x33A1, 0x8775, 0x33C4, 0x8774, 0x33CD, 0x8783, 0x4E00, 0x88EA, 0x4E01, 0x929A, 0x4E03, 0x8EB5, 0x4E07, 0x969C, 0x4E08, 0x8FE4, 0x4E09, 0x8E4F, 0x4E0A, 0x8FE3, 0x4E0B, 0x89BA, 0x4E0D, 0x9573, 0x4E0E, 0x975E, 0x4E10, 0x98A0, 0x4E11, 0x894E, 0x4E14, 0x8A8E, 0x4E15, 0x98A1, 0x4E16, 0x90A2, 0x4E17, 0x99C0, 0x4E18, 0x8B75, 0x4E19, 0x95B8, 0x4E1E, 0x8FE5, 0x4E21, 0x97BC, 0x4E26, 0x95C0, 0x4E28, 0xFA68, 0x4E2A, 0x98A2, 0x4E2D, 0x9286, 0x4E31, 0x98A3, 0x4E32, 0x8BF8, 0x4E36, 0x98A4, 0x4E38, 0x8ADB, 0x4E39, 0x924F, 0x4E3B, 0x8EE5, 0x4E3C, 0x98A5, 0x4E3F, 0x98A6, 0x4E42, 0x98A7, 0x4E43, 0x9454, 0x4E45, 0x8B76, 0x4E4B, 0x9456, 0x4E4D, 0x93E1, 0x4E4E, 0x8CC1, 0x4E4F, 0x9652, 0x4E55, 0xE568, 0x4E56, 0x98A8, 0x4E57, 0x8FE6, 0x4E58, 0x98A9, 0x4E59, 0x89B3, 0x4E5D, 0x8BE3, 0x4E5E, 0x8CEE, 0x4E5F, 0x96E7, 0x4E62, 0x9BA4, 0x4E71, 0x9790, 0x4E73, 0x93FB, 0x4E7E, 0x8AA3, 0x4E80, 0x8B54, 0x4E82, 0x98AA, 0x4E85, 0x98AB, 0x4E86, 0x97B9, 0x4E88, 0x975C, 0x4E89, 0x9188, 0x4E8A, 0x98AD, 0x4E8B, 0x8E96, 0x4E8C, 0x93F1, 0x4E8E, 0x98B0, 0x4E91, 0x895D, 0x4E92, 0x8CDD, 0x4E94, 0x8CDC, 0x4E95, 0x88E4, 0x4E98, 0x986A, 0x4E99, 0x9869, 0x4E9B, 0x8DB1, 0x4E9C, 0x889F, 0x4E9E, 0x98B1, 0x4E9F, 0x98B2, 0x4EA0, 0x98B3, 0x4EA1, 0x9653, 0x4EA2, 0x98B4, 0x4EA4, 0x8CF0, 0x4EA5, 0x88E5, 0x4EA6, 0x9692, 0x4EA8, 0x8B9C, 0x4EAB, 0x8B9D, 0x4EAC, 0x8B9E, 0x4EAD, 0x92E0, 0x4EAE, 0x97BA, 0x4EB0, 0x98B5, 0x4EB3, 0x98B6, 0x4EB6, 0x98B7, 0x4EBA, 0x906C, 0x4EC0, 0x8F59, 0x4EC1, 0x906D, 0x4EC2, 0x98BC, 0x4EC4, 0x98BA, 0x4EC6, 0x98BB, 0x4EC7, 0x8B77, 0x4ECA, 0x8DA1, 0x4ECB, 0x89EE, 0x4ECD, 0x98B9, 0x4ECE, 0x98B8, 0x4ECF, 0x95A7, 0x4ED4, 0x8E65, 0x4ED5, 0x8E64, 0x4ED6, 0x91BC, 0x4ED7, 0x98BD, 0x4ED8, 0x9574, 0x4ED9, 0x90E5, 0x4EDD, 0x8157, 0x4EDE, 0x98BE, 0x4EDF, 0x98C0, 0x4EE1, 0xFA69, 0x4EE3, 0x91E3, 0x4EE4, 0x97DF, 0x4EE5, 0x88C8, 0x4EED, 0x98BF, 0x4EEE, 0x89BC, 0x4EF0, 0x8BC2, 0x4EF2, 0x9287, 0x4EF6, 0x8C8F, 0x4EF7, 0x98C1, 0x4EFB, 0x9443, 0x4EFC, 0xFA6A, 0x4F00, 0xFA6B, 0x4F01, 0x8AE9, 0x4F03, 0xFA6C, 0x4F09, 0x98C2, 0x4F0A, 0x88C9, 0x4F0D, 0x8CDE, 0x4F0E, 0x8AEA, 0x4F0F, 0x959A, 0x4F10, 0x94B0, 0x4F11, 0x8B78, 0x4F1A, 0x89EF, 0x4F1C, 0x98E5, 0x4F1D, 0x9360, 0x4F2F, 0x948C, 0x4F30, 0x98C4, 0x4F34, 0x94BA, 0x4F36, 0x97E0, 0x4F38, 0x904C, 0x4F39, 0xFA6D, 0x4F3A, 0x8E66, 0x4F3C, 0x8E97, 0x4F3D, 0x89BE, 0x4F43, 0x92CF, 0x4F46, 0x9241, 0x4F47, 0x98C8, 0x4F4D, 0x88CA, 0x4F4E, 0x92E1, 0x4F4F, 0x8F5A, 0x4F50, 0x8DB2, 0x4F51, 0x9743, 0x4F53, 0x91CC, 0x4F55, 0x89BD, 0x4F56, 0xFA6E, 0x4F57, 0x98C7, 0x4F59, 0x975D, 0x4F5A, 0x98C3, 0x4F5B, 0x98C5, 0x4F5C, 0x8DEC, 0x4F5D, 0x98C6, 0x4F5E, 0x9B43, 0x4F69, 0x98CE, 0x4F6F, 0x98D1, 0x4F70, 0x98CF, 0x4F73, 0x89C0, 0x4F75, 0x95B9, 0x4F76, 0x98C9, 0x4F7B, 0x98CD, 0x4F7C, 0x8CF1, 0x4F7F, 0x8E67, 0x4F83, 0x8AA4, 0x4F86, 0x98D2, 0x4F88, 0x98CA, 0x4F8A, 0xFA70, 0x4F8B, 0x97E1, 0x4F8D, 0x8E98, 0x4F8F, 0x98CB, 0x4F91, 0x98D0, 0x4F92, 0xFA6F, 0x4F94, 0xFA72, 0x4F96, 0x98D3, 0x4F98, 0x98CC, 0x4F9A, 0xFA71, 0x4F9B, 0x8B9F, 0x4F9D, 0x88CB, 0x4FA0, 0x8BA0, 0x4FA1, 0x89BF, 0x4FAB, 0x9B44, 0x4FAD, 0x9699, 0x4FAE, 0x958E, 0x4FAF, 0x8CF2, 0x4FB5, 0x904E, 0x4FB6, 0x97B5, 0x4FBF, 0x95D6, 0x4FC2, 0x8C57, 0x4FC3, 0x91A3, 0x4FC4, 0x89E2, 0x4FC9, 0xFA61, 0x4FCA, 0x8F72, 0x4FCD, 0xFA73, 0x4FCE, 0x98D7, 0x4FD0, 0x98DC, 0x4FD1, 0x98DA, 0x4FD4, 0x98D5, 0x4FD7, 0x91AD, 0x4FD8, 0x98D8, 0x4FDA, 0x98DB, 0x4FDB, 0x98D9, 0x4FDD, 0x95DB, 0x4FDF, 0x98D6, 0x4FE1, 0x904D, 0x4FE3, 0x9693, 0x4FE4, 0x98DD, 0x4FE5, 0x98DE, 0x4FEE, 0x8F43, 0x4FEF, 0x98EB, 0x4FF3, 0x946F, 0x4FF5, 0x9555, 0x4FF6, 0x98E6, 0x4FF8, 0x95EE, 0x4FFA, 0x89B4, 0x4FFE, 0x98EA, 0x4FFF, 0xFA76, 0x5005, 0x98E4, 0x5006, 0x98ED, 0x5009, 0x9171, 0x500B, 0x8CC2, 0x500D, 0x947B, 0x500F, 0xE0C5, 0x5011, 0x98EC, 0x5012, 0x937C, 0x5014, 0x98E1, 0x5016, 0x8CF4, 0x5019, 0x8CF3, 0x501A, 0x98DF, 0x501E, 0xFA77, 0x501F, 0x8ED8, 0x5021, 0x98E7, 0x5022, 0xFA75, 0x5023, 0x95ED, 0x5024, 0x926C, 0x5025, 0x98E3, 0x5026, 0x8C91, 0x5028, 0x98E0, 0x5029, 0x98E8, 0x502A, 0x98E2, 0x502B, 0x97CF, 0x502C, 0x98E9, 0x502D, 0x9860, 0x5036, 0x8BE4, 0x5039, 0x8C90, 0x5040, 0xFA74, 0x5042, 0xFA7A, 0x5043, 0x98EE, 0x5046, 0xFA78, 0x5047, 0x98EF, 0x5048, 0x98F3, 0x5049, 0x88CC, 0x504F, 0x95CE, 0x5050, 0x98F2, 0x5055, 0x98F1, 0x5056, 0x98F5, 0x505A, 0x98F4, 0x505C, 0x92E2, 0x5065, 0x8C92, 0x506C, 0x98F6, 0x5070, 0xFA79, 0x5072, 0x8EC3, 0x5074, 0x91A4, 0x5075, 0x92E3, 0x5076, 0x8BF4, 0x5078, 0x98F7, 0x507D, 0x8B55, 0x5080, 0x98F8, 0x5085, 0x98FA, 0x508D, 0x9654, 0x5091, 0x8C86, 0x5094, 0xFA7B, 0x5098, 0x8E50, 0x5099, 0x94F5, 0x509A, 0x98F9, 0x50AC, 0x8DC3, 0x50AD, 0x9762, 0x50B2, 0x98FC, 0x50B3, 0x9942, 0x50B4, 0x98FB, 0x50B5, 0x8DC2, 0x50B7, 0x8F9D, 0x50BE, 0x8C58, 0x50C2, 0x9943, 0x50C5, 0x8BCD, 0x50C9, 0x9940, 0x50CA, 0x9941, 0x50CD, 0x93AD, 0x50CF, 0x919C, 0x50D1, 0x8BA1, 0x50D5, 0x966C, 0x50D6, 0x9944, 0x50D8, 0xFA7D, 0x50DA, 0x97BB, 0x50DE, 0x9945, 0x50E3, 0x9948, 0x50E5, 0x9946, 0x50E7, 0x916D, 0x50ED, 0x9947, 0x50EE, 0x9949, 0x50F4, 0xFA7C, 0x50F5, 0x994B, 0x50F9, 0x994A, 0x50FB, 0x95C6, 0x5100, 0x8B56, 0x5101, 0x994D, 0x5102, 0x994E, 0x5104, 0x89AD, 0x5109, 0x994C, 0x5112, 0x8EF2, 0x5114, 0x9951, 0x5115, 0x9950, 0x5116, 0x994F, 0x5118, 0x98D4, 0x511A, 0x9952, 0x511F, 0x8F9E, 0x5121, 0x9953, 0x512A, 0x9744, 0x5132, 0x96D7, 0x5137, 0x9955, 0x513A, 0x9954, 0x513B, 0x9957, 0x513C, 0x9956, 0x513F, 0x9958, 0x5140, 0x9959, 0x5141, 0x88F2, 0x5143, 0x8CB3, 0x5144, 0x8C5A, 0x5145, 0x8F5B, 0x5146, 0x929B, 0x5147, 0x8BA2, 0x5148, 0x90E6, 0x5149, 0x8CF5, 0x514A, 0xFA7E, 0x514B, 0x8D8E, 0x514C, 0x995B, 0x514D, 0x96C6, 0x514E, 0x9365, 0x5150, 0x8E99, 0x5152, 0x995A, 0x5154, 0x995C, 0x515A, 0x937D, 0x515C, 0x8A95, 0x5162, 0x995D, 0x5164, 0xFA80, 0x5165, 0x93FC, 0x5168, 0x9153, 0x5169, 0x995F, 0x516A, 0x9960, 0x516B, 0x94AA, 0x516C, 0x8CF6, 0x516D, 0x985A, 0x516E, 0x9961, 0x5171, 0x8BA4, 0x5175, 0x95BA, 0x5176, 0x91B4, 0x5177, 0x8BEF, 0x5178, 0x9354, 0x517C, 0x8C93, 0x5180, 0x9962, 0x5182, 0x9963, 0x5185, 0x93E0, 0x5186, 0x897E, 0x5189, 0x9966, 0x518A, 0x8DFB, 0x518C, 0x9965, 0x518D, 0x8DC4, 0x518F, 0x9967, 0x5190, 0xE3EC, 0x5191, 0x9968, 0x5192, 0x9660, 0x5193, 0x9969, 0x5195, 0x996A, 0x5196, 0x996B, 0x5197, 0x8FE7, 0x5199, 0x8ECA, 0x519D, 0xFA81, 0x51A0, 0x8AA5, 0x51A2, 0x996E, 0x51A4, 0x996C, 0x51A5, 0x96BB, 0x51A6, 0x996D, 0x51A8, 0x9579, 0x51A9, 0x996F, 0x51AA, 0x9970, 0x51AB, 0x9971, 0x51AC, 0x937E, 0x51B0, 0x9975, 0x51B1, 0x9973, 0x51B2, 0x9974, 0x51B3, 0x9972, 0x51B4, 0x8DE1, 0x51B5, 0x9976, 0x51B6, 0x96E8, 0x51B7, 0x97E2, 0x51BD, 0x9977, 0x51BE, 0xFA82, 0x51C4, 0x90A6, 0x51C5, 0x9978, 0x51C6, 0x8F79, 0x51C9, 0x9979, 0x51CB, 0x929C, 0x51CC, 0x97BD, 0x51CD, 0x9380, 0x51D6, 0x99C3, 0x51DB, 0x997A, 0x51DC, 0xEAA3, 0x51DD, 0x8BC3, 0x51E0, 0x997B, 0x51E1, 0x967D, 0x51E6, 0x8F88, 0x51E7, 0x91FA, 0x51E9, 0x997D, 0x51EA, 0x93E2, 0x51EC, 0xFA83, 0x51ED, 0x997E, 0x51F0, 0x9980, 0x51F1, 0x8A4D, 0x51F5, 0x9981, 0x51F6, 0x8BA5, 0x51F8, 0x93CA, 0x51F9, 0x899A, 0x51FA, 0x8F6F, 0x51FD, 0x949F, 0x51FE, 0x9982, 0x5200, 0x9381, 0x5203, 0x906E, 0x5204, 0x9983, 0x5206, 0x95AA, 0x5207, 0x90D8, 0x5208, 0x8AA0, 0x520A, 0x8AA7, 0x520B, 0x9984, 0x520E, 0x9986, 0x5211, 0x8C59, 0x5214, 0x9985, 0x5215, 0xFA84, 0x5217, 0x97F1, 0x521D, 0x8F89, 0x5224, 0x94BB, 0x5225, 0x95CA, 0x5227, 0x9987, 0x5229, 0x9798, 0x522A, 0x9988, 0x522E, 0x9989, 0x5230, 0x939E, 0x5233, 0x998A, 0x5236, 0x90A7, 0x5237, 0x8DFC, 0x5238, 0x8C94, 0x5239, 0x998B, 0x523A, 0x8E68, 0x523B, 0x8D8F, 0x5243, 0x92E4, 0x5244, 0x998D, 0x5247, 0x91A5, 0x524A, 0x8DED, 0x524B, 0x998E, 0x524C, 0x998F, 0x524D, 0x914F, 0x524F, 0x998C, 0x5254, 0x9991, 0x5256, 0x9655, 0x525B, 0x8D84, 0x525E, 0x9990, 0x5263, 0x8C95, 0x5264, 0x8DDC, 0x5265, 0x948D, 0x5269, 0x9994, 0x526A, 0x9992, 0x526F, 0x959B, 0x5270, 0x8FE8, 0x5271, 0x999B, 0x5272, 0x8A84, 0x5273, 0x9995, 0x5274, 0x9993, 0x5275, 0x916E, 0x527D, 0x9997, 0x527F, 0x9996, 0x5283, 0x8A63, 0x5287, 0x8C80, 0x5288, 0x999C, 0x5289, 0x97AB, 0x528D, 0x9998, 0x5291, 0x999D, 0x5292, 0x999A, 0x5294, 0x9999, 0x529B, 0x97CD, 0x529C, 0xFA85, 0x529F, 0x8CF7, 0x52A0, 0x89C1, 0x52A3, 0x97F2, 0x52A6, 0xFA86, 0x52A9, 0x8F95, 0x52AA, 0x9377, 0x52AB, 0x8D85, 0x52AC, 0x99A0, 0x52AD, 0x99A1, 0x52AF, 0xFB77, 0x52B1, 0x97E3, 0x52B4, 0x984A, 0x52B5, 0x99A3, 0x52B9, 0x8CF8, 0x52BC, 0x99A2, 0x52BE, 0x8A4E, 0x52C0, 0xFA87, 0x52C1, 0x99A4, 0x52C3, 0x9675, 0x52C5, 0x92BA, 0x52C7, 0x9745, 0x52C9, 0x95D7, 0x52CD, 0x99A5, 0x52D2, 0xE8D3, 0x52D5, 0x93AE, 0x52D7, 0x99A6, 0x52D8, 0x8AA8, 0x52D9, 0x96B1, 0x52DB, 0xFA88, 0x52DD, 0x8F9F, 0x52DE, 0x99A7, 0x52DF, 0x95E5, 0x52E0, 0x99AB, 0x52E2, 0x90A8, 0x52E3, 0x99A8, 0x52E4, 0x8BCE, 0x52E6, 0x99A9, 0x52E7, 0x8AA9, 0x52F2, 0x8C4D, 0x52F3, 0x99AC, 0x52F5, 0x99AD, 0x52F8, 0x99AE, 0x52F9, 0x99AF, 0x52FA, 0x8ED9, 0x52FE, 0x8CF9, 0x52FF, 0x96DC, 0x5300, 0xFA89, 0x5301, 0x96E6, 0x5302, 0x93F5, 0x5305, 0x95EF, 0x5306, 0x99B0, 0x5307, 0xFA8A, 0x5308, 0x99B1, 0x530D, 0x99B3, 0x530F, 0x99B5, 0x5310, 0x99B4, 0x5315, 0x99B6, 0x5316, 0x89BB, 0x5317, 0x966B, 0x5319, 0x8DFA, 0x531A, 0x99B7, 0x531D, 0x9178, 0x5320, 0x8FA0, 0x5321, 0x8BA7, 0x5323, 0x99B8, 0x5324, 0xFA8B, 0x532A, 0x94D9, 0x532F, 0x99B9, 0x5331, 0x99BA, 0x5333, 0x99BB, 0x5338, 0x99BC, 0x5339, 0x9543, 0x533A, 0x8BE6, 0x533B, 0x88E3, 0x533F, 0x93BD, 0x5340, 0x99BD, 0x5341, 0x8F5C, 0x5343, 0x90E7, 0x5345, 0x99BF, 0x5346, 0x99BE, 0x5347, 0x8FA1, 0x5348, 0x8CDF, 0x5349, 0x99C1, 0x534A, 0x94BC, 0x534D, 0x99C2, 0x5351, 0x94DA, 0x5352, 0x91B2, 0x5353, 0x91EC, 0x5354, 0x8BA6, 0x5357, 0x93EC, 0x5358, 0x9250, 0x535A, 0x948E, 0x535C, 0x966D, 0x535E, 0x99C4, 0x5360, 0x90E8, 0x5366, 0x8C54, 0x5369, 0x99C5, 0x536E, 0x99C6, 0x536F, 0x894B, 0x5370, 0x88F3, 0x5371, 0x8AEB, 0x5372, 0xFA8C, 0x5373, 0x91A6, 0x5374, 0x8B70, 0x5375, 0x9791, 0x5377, 0x99C9, 0x5378, 0x89B5, 0x537B, 0x99C8, 0x537F, 0x8BA8, 0x5382, 0x99CA, 0x5384, 0x96EF, 0x5393, 0xFA8D, 0x5396, 0x99CB, 0x5398, 0x97D0, 0x539A, 0x8CFA, 0x539F, 0x8CB4, 0x53A0, 0x99CC, 0x53A5, 0x99CE, 0x53A6, 0x99CD, 0x53A8, 0x907E, 0x53A9, 0x8958, 0x53AD, 0x897D, 0x53AE, 0x99CF, 0x53B0, 0x99D0, 0x53B2, 0xFA8E, 0x53B3, 0x8CB5, 0x53B6, 0x99D1, 0x53BB, 0x8B8E, 0x53C2, 0x8E51, 0x53C3, 0x99D2, 0x53C8, 0x9694, 0x53C9, 0x8DB3, 0x53CA, 0x8B79, 0x53CB, 0x9746, 0x53CC, 0x916F, 0x53CD, 0x94BD, 0x53CE, 0x8EFB, 0x53D4, 0x8F66, 0x53D6, 0x8EE6, 0x53D7, 0x8EF3, 0x53D9, 0x8F96, 0x53DB, 0x94BE, 0x53DD, 0xFA8F, 0x53DF, 0x99D5, 0x53E1, 0x8962, 0x53E2, 0x9170, 0x53E3, 0x8CFB, 0x53E4, 0x8CC3, 0x53E5, 0x8BE5, 0x53E8, 0x99D9, 0x53E9, 0x9240, 0x53EA, 0x91FC, 0x53EB, 0x8BA9, 0x53EC, 0x8FA2, 0x53ED, 0x99DA, 0x53EE, 0x99D8, 0x53EF, 0x89C2, 0x53F0, 0x91E4, 0x53F1, 0x8EB6, 0x53F2, 0x8E6A, 0x53F3, 0x8945, 0x53F6, 0x8A90, 0x53F7, 0x8D86, 0x53F8, 0x8E69, 0x53FA, 0x99DB, 0x5401, 0x99DC, 0x5403, 0x8B68, 0x5404, 0x8A65, 0x5408, 0x8D87, 0x5409, 0x8B67, 0x540A, 0x92DD, 0x540B, 0x8944, 0x540C, 0x93AF, 0x540D, 0x96BC, 0x540E, 0x8D40, 0x540F, 0x9799, 0x5410, 0x9366, 0x5411, 0x8CFC, 0x541B, 0x8C4E, 0x541D, 0x99E5, 0x541F, 0x8BE1, 0x5420, 0x9669, 0x5426, 0x94DB, 0x5429, 0x99E4, 0x542B, 0x8ADC, 0x542C, 0x99DF, 0x542D, 0x99E0, 0x542E, 0x99E2, 0x5436, 0x99E3, 0x5438, 0x8B7A, 0x5439, 0x9081, 0x543B, 0x95AB, 0x543C, 0x99E1, 0x543D, 0x99DD, 0x543E, 0x8CE1, 0x5440, 0x99DE, 0x5442, 0x9843, 0x5446, 0x95F0, 0x5448, 0x92E6, 0x5449, 0x8CE0, 0x544A, 0x8D90, 0x544E, 0x99E6, 0x5451, 0x93DB, 0x545F, 0x99EA, 0x5468, 0x8EFC, 0x546A, 0x8EF4, 0x5470, 0x99ED, 0x5471, 0x99EB, 0x5473, 0x96A1, 0x5475, 0x99E8, 0x5476, 0x99F1, 0x5477, 0x99EC, 0x547B, 0x99EF, 0x547C, 0x8CC4, 0x547D, 0x96BD, 0x5480, 0x99F0, 0x5484, 0x99F2, 0x5486, 0x99F4, 0x548A, 0xFA92, 0x548B, 0x8DEE, 0x548C, 0x9861, 0x548E, 0x99E9, 0x548F, 0x99E7, 0x5490, 0x99F3, 0x5492, 0x99EE, 0x549C, 0xFA91, 0x54A2, 0x99F6, 0x54A4, 0x9A42, 0x54A5, 0x99F8, 0x54A8, 0x99FC, 0x54A9, 0xFA93, 0x54AB, 0x9A40, 0x54AC, 0x99F9, 0x54AF, 0x9A5D, 0x54B2, 0x8DE7, 0x54B3, 0x8A50, 0x54B8, 0x99F7, 0x54BC, 0x9A44, 0x54BD, 0x88F4, 0x54BE, 0x9A43, 0x54C0, 0x88A3, 0x54C1, 0x9569, 0x54C2, 0x9A41, 0x54C4, 0x99FA, 0x54C7, 0x99F5, 0x54C8, 0x99FB, 0x54C9, 0x8DC6, 0x54D8, 0x9A45, 0x54E1, 0x88F5, 0x54E2, 0x9A4E, 0x54E5, 0x9A46, 0x54E6, 0x9A47, 0x54E8, 0x8FA3, 0x54E9, 0x9689, 0x54ED, 0x9A4C, 0x54EE, 0x9A4B, 0x54F2, 0x934E, 0x54FA, 0x9A4D, 0x54FD, 0x9A4A, 0x54FF, 0xFA94, 0x5504, 0x8953, 0x5506, 0x8DB4, 0x5507, 0x904F, 0x550F, 0x9A48, 0x5510, 0x9382, 0x5514, 0x9A49, 0x5516, 0x88A0, 0x552E, 0x9A53, 0x552F, 0x9742, 0x5531, 0x8FA5, 0x5533, 0x9A59, 0x5538, 0x9A58, 0x5539, 0x9A4F, 0x553E, 0x91C1, 0x5540, 0x9A50, 0x5544, 0x91ED, 0x5545, 0x9A55, 0x5546, 0x8FA4, 0x554C, 0x9A52, 0x554F, 0x96E2, 0x5553, 0x8C5B, 0x5556, 0x9A56, 0x5557, 0x9A57, 0x555C, 0x9A54, 0x555D, 0x9A5A, 0x5563, 0x9A51, 0x557B, 0x9A60, 0x557C, 0x9A65, 0x557E, 0x9A61, 0x5580, 0x9A5C, 0x5583, 0x9A66, 0x5584, 0x9150, 0x5586, 0xFA95, 0x5587, 0x9A68, 0x5589, 0x8D41, 0x558A, 0x9A5E, 0x558B, 0x929D, 0x5598, 0x9A62, 0x5599, 0x9A5B, 0x559A, 0x8AAB, 0x559C, 0x8AEC, 0x559D, 0x8A85, 0x559E, 0x9A63, 0x559F, 0x9A5F, 0x55A7, 0x8C96, 0x55A8, 0x9A69, 0x55A9, 0x9A67, 0x55AA, 0x9172, 0x55AB, 0x8B69, 0x55AC, 0x8BAA, 0x55AE, 0x9A64, 0x55B0, 0x8BF2, 0x55B6, 0x8963, 0x55C4, 0x9A6D, 0x55C5, 0x9A6B, 0x55C7, 0x9AA5, 0x55D4, 0x9A70, 0x55DA, 0x9A6A, 0x55DC, 0x9A6E, 0x55DF, 0x9A6C, 0x55E3, 0x8E6B, 0x55E4, 0x9A6F, 0x55F7, 0x9A72, 0x55F9, 0x9A77, 0x55FD, 0x9A75, 0x55FE, 0x9A74, 0x5606, 0x9251, 0x5609, 0x89C3, 0x5614, 0x9A71, 0x5616, 0x9A73, 0x5617, 0x8FA6, 0x5618, 0x8952, 0x561B, 0x9A76, 0x5629, 0x89DC, 0x562F, 0x9A82, 0x5631, 0x8FFA, 0x5632, 0x9A7D, 0x5634, 0x9A7B, 0x5636, 0x9A7C, 0x5638, 0x9A7E, 0x5642, 0x895C, 0x564C, 0x9158, 0x564E, 0x9A78, 0x5650, 0x9A79, 0x565B, 0x8A9A, 0x5664, 0x9A81, 0x5668, 0x8AED, 0x566A, 0x9A84, 0x566B, 0x9A80, 0x566C, 0x9A83, 0x5674, 0x95AC, 0x5678, 0x93D3, 0x567A, 0x94B6, 0x5680, 0x9A86, 0x5686, 0x9A85, 0x5687, 0x8A64, 0x568A, 0x9A87, 0x568F, 0x9A8A, 0x5694, 0x9A89, 0x56A0, 0x9A88, 0x56A2, 0x9458, 0x56A5, 0x9A8B, 0x56AE, 0x9A8C, 0x56B4, 0x9A8E, 0x56B6, 0x9A8D, 0x56BC, 0x9A90, 0x56C0, 0x9A93, 0x56C1, 0x9A91, 0x56C2, 0x9A8F, 0x56C3, 0x9A92, 0x56C8, 0x9A94, 0x56CE, 0x9A95, 0x56D1, 0x9A96, 0x56D3, 0x9A97, 0x56D7, 0x9A98, 0x56D8, 0x9964, 0x56DA, 0x8EFA, 0x56DB, 0x8E6C, 0x56DE, 0x89F1, 0x56E0, 0x88F6, 0x56E3, 0x9263, 0x56EE, 0x9A99, 0x56F0, 0x8DA2, 0x56F2, 0x88CD, 0x56F3, 0x907D, 0x56F9, 0x9A9A, 0x56FA, 0x8CC5, 0x56FD, 0x8D91, 0x56FF, 0x9A9C, 0x5700, 0x9A9B, 0x5703, 0x95DE, 0x5704, 0x9A9D, 0x5708, 0x9A9F, 0x5709, 0x9A9E, 0x570B, 0x9AA0, 0x570D, 0x9AA1, 0x570F, 0x8C97, 0x5712, 0x8980, 0x5713, 0x9AA2, 0x5716, 0x9AA4, 0x5718, 0x9AA3, 0x571C, 0x9AA6, 0x571F, 0x9379, 0x5726, 0x9AA7, 0x5727, 0x88B3, 0x5728, 0x8DDD, 0x572D, 0x8C5C, 0x5730, 0x926E, 0x5737, 0x9AA8, 0x5738, 0x9AA9, 0x573B, 0x9AAB, 0x5740, 0x9AAC, 0x5742, 0x8DE2, 0x5747, 0x8BCF, 0x574A, 0x9656, 0x574E, 0x9AAA, 0x574F, 0x9AAD, 0x5750, 0x8DBF, 0x5751, 0x8D42, 0x5759, 0xFA96, 0x5761, 0x9AB1, 0x5764, 0x8DA3, 0x5765, 0xFA97, 0x5766, 0x9252, 0x5769, 0x9AAE, 0x576A, 0x92D8, 0x577F, 0x9AB2, 0x5782, 0x9082, 0x5788, 0x9AB0, 0x5789, 0x9AB3, 0x578B, 0x8C5E, 0x5793, 0x9AB4, 0x57A0, 0x9AB5, 0x57A2, 0x8D43, 0x57A3, 0x8A5F, 0x57A4, 0x9AB7, 0x57AA, 0x9AB8, 0x57AC, 0xFA98, 0x57B0, 0x9AB9, 0x57B3, 0x9AB6, 0x57C0, 0x9AAF, 0x57C3, 0x9ABA, 0x57C6, 0x9ABB, 0x57C7, 0xFA9A, 0x57C8, 0xFA99, 0x57CB, 0x9684, 0x57CE, 0x8FE9, 0x57D2, 0x9ABD, 0x57D3, 0x9ABE, 0x57D4, 0x9ABC, 0x57D6, 0x9AC0, 0x57DC, 0x9457, 0x57DF, 0x88E6, 0x57E0, 0x9575, 0x57E3, 0x9AC1, 0x57F4, 0x8FFB, 0x57F7, 0x8EB7, 0x57F9, 0x947C, 0x57FA, 0x8AEE, 0x57FC, 0x8DE9, 0x5800, 0x9678, 0x5802, 0x93B0, 0x5805, 0x8C98, 0x5806, 0x91CD, 0x580A, 0x9ABF, 0x580B, 0x9AC2, 0x5815, 0x91C2, 0x5819, 0x9AC3, 0x581D, 0x9AC4, 0x5821, 0x9AC6, 0x5824, 0x92E7, 0x582A, 0x8AAC, 0x582F, 0xEA9F, 0x5830, 0x8981, 0x5831, 0x95F1, 0x5834, 0x8FEA, 0x5835, 0x9367, 0x583A, 0x8DE4, 0x583D, 0x9ACC, 0x5840, 0x95BB, 0x5841, 0x97DB, 0x584A, 0x89F2, 0x584B, 0x9AC8, 0x5851, 0x9159, 0x5852, 0x9ACB, 0x5854, 0x9383, 0x5857, 0x9368, 0x5858, 0x9384, 0x5859, 0x94B7, 0x585A, 0x92CB, 0x585E, 0x8DC7, 0x5862, 0x9AC7, 0x5869, 0x8996, 0x586B, 0x9355, 0x5870, 0x9AC9, 0x5872, 0x9AC5, 0x5875, 0x906F, 0x5879, 0x9ACD, 0x587E, 0x8F6D, 0x5883, 0x8BAB, 0x5885, 0x9ACE, 0x5893, 0x95E6, 0x5897, 0x919D, 0x589C, 0x92C4, 0x589E, 0xFA9D, 0x589F, 0x9AD0, 0x58A8, 0x966E, 0x58AB, 0x9AD1, 0x58AE, 0x9AD6, 0x58B2, 0xFA9E, 0x58B3, 0x95AD, 0x58B8, 0x9AD5, 0x58B9, 0x9ACF, 0x58BA, 0x9AD2, 0x58BB, 0x9AD4, 0x58BE, 0x8DA4, 0x58C1, 0x95C7, 0x58C5, 0x9AD7, 0x58C7, 0x9264, 0x58CA, 0x89F3, 0x58CC, 0x8FEB, 0x58D1, 0x9AD9, 0x58D3, 0x9AD8, 0x58D5, 0x8D88, 0x58D7, 0x9ADA, 0x58D8, 0x9ADC, 0x58D9, 0x9ADB, 0x58DC, 0x9ADE, 0x58DE, 0x9AD3, 0x58DF, 0x9AE0, 0x58E4, 0x9ADF, 0x58E5, 0x9ADD, 0x58EB, 0x8E6D, 0x58EC, 0x9070, 0x58EE, 0x9173, 0x58EF, 0x9AE1, 0x58F0, 0x90BA, 0x58F1, 0x88EB, 0x58F2, 0x9484, 0x58F7, 0x92D9, 0x58F9, 0x9AE3, 0x58FA, 0x9AE2, 0x58FB, 0x9AE4, 0x58FC, 0x9AE5, 0x58FD, 0x9AE6, 0x5902, 0x9AE7, 0x5909, 0x95CF, 0x590A, 0x9AE8, 0x590B, 0xFA9F, 0x590F, 0x89C4, 0x5910, 0x9AE9, 0x5915, 0x975B, 0x5916, 0x8A4F, 0x5918, 0x99C7, 0x5919, 0x8F67, 0x591A, 0x91BD, 0x591B, 0x9AEA, 0x591C, 0x96E9, 0x5922, 0x96B2, 0x5925, 0x9AEC, 0x5927, 0x91E5, 0x5929, 0x9356, 0x592A, 0x91BE, 0x592B, 0x9576, 0x592C, 0x9AED, 0x592D, 0x9AEE, 0x592E, 0x899B, 0x5931, 0x8EB8, 0x5932, 0x9AEF, 0x5937, 0x88CE, 0x5938, 0x9AF0, 0x593E, 0x9AF1, 0x5944, 0x8982, 0x5947, 0x8AEF, 0x5948, 0x93DE, 0x5949, 0x95F2, 0x594E, 0x9AF5, 0x594F, 0x9174, 0x5950, 0x9AF4, 0x5951, 0x8C5F, 0x5953, 0xFAA0, 0x5954, 0x967A, 0x5955, 0x9AF3, 0x5957, 0x9385, 0x5958, 0x9AF7, 0x595A, 0x9AF6, 0x595B, 0xFAA1, 0x595D, 0xFAA2, 0x5960, 0x9AF9, 0x5962, 0x9AF8, 0x5963, 0xFAA3, 0x5965, 0x899C, 0x5967, 0x9AFA, 0x5968, 0x8FA7, 0x5969, 0x9AFC, 0x596A, 0x9244, 0x596C, 0x9AFB, 0x596E, 0x95B1, 0x5973, 0x8F97, 0x5974, 0x937A, 0x5978, 0x9B40, 0x597D, 0x8D44, 0x5981, 0x9B41, 0x5982, 0x9440, 0x5983, 0x94DC, 0x5984, 0x96CF, 0x598A, 0x9444, 0x598D, 0x9B4A, 0x5993, 0x8B57, 0x5996, 0x9764, 0x5999, 0x96AD, 0x599B, 0x9BAA, 0x599D, 0x9B42, 0x59A3, 0x9B45, 0x59A4, 0xFAA4, 0x59A5, 0x91C3, 0x59A8, 0x9657, 0x59AC, 0x9369, 0x59B2, 0x9B46, 0x59B9, 0x9685, 0x59BA, 0xFAA5, 0x59BB, 0x8DC8, 0x59BE, 0x8FA8, 0x59C6, 0x9B47, 0x59C9, 0x8E6F, 0x59CB, 0x8E6E, 0x59D0, 0x88B7, 0x59D1, 0x8CC6, 0x59D3, 0x90A9, 0x59D4, 0x88CF, 0x59D9, 0x9B4B, 0x59DA, 0x9B4C, 0x59DC, 0x9B49, 0x59E5, 0x8957, 0x59E6, 0x8AAD, 0x59E8, 0x9B48, 0x59EA, 0x96C3, 0x59EB, 0x9550, 0x59F6, 0x88A6, 0x59FB, 0x88F7, 0x59FF, 0x8E70, 0x5A01, 0x88D0, 0x5A03, 0x88A1, 0x5A09, 0x9B51, 0x5A11, 0x9B4F, 0x5A18, 0x96BA, 0x5A1A, 0x9B52, 0x5A1C, 0x9B50, 0x5A1F, 0x9B4E, 0x5A20, 0x9050, 0x5A25, 0x9B4D, 0x5A29, 0x95D8, 0x5A2F, 0x8CE2, 0x5A35, 0x9B56, 0x5A36, 0x9B57, 0x5A3C, 0x8FA9, 0x5A40, 0x9B53, 0x5A41, 0x984B, 0x5A46, 0x946B, 0x5A49, 0x9B55, 0x5A5A, 0x8DA5, 0x5A62, 0x9B58, 0x5A66, 0x9577, 0x5A6A, 0x9B59, 0x5A6C, 0x9B54, 0x5A7F, 0x96B9, 0x5A92, 0x947D, 0x5A9A, 0x9B5A, 0x5A9B, 0x9551, 0x5ABC, 0x9B5B, 0x5ABD, 0x9B5F, 0x5ABE, 0x9B5C, 0x5AC1, 0x89C5, 0x5AC2, 0x9B5E, 0x5AC9, 0x8EB9, 0x5ACB, 0x9B5D, 0x5ACC, 0x8C99, 0x5AD0, 0x9B6B, 0x5AD6, 0x9B64, 0x5AD7, 0x9B61, 0x5AE1, 0x9284, 0x5AE3, 0x9B60, 0x5AE6, 0x9B62, 0x5AE9, 0x9B63, 0x5AFA, 0x9B65, 0x5AFB, 0x9B66, 0x5B09, 0x8AF0, 0x5B0B, 0x9B68, 0x5B0C, 0x9B67, 0x5B16, 0x9B69, 0x5B22, 0x8FEC, 0x5B2A, 0x9B6C, 0x5B2C, 0x92DA, 0x5B30, 0x8964, 0x5B32, 0x9B6A, 0x5B36, 0x9B6D, 0x5B3E, 0x9B6E, 0x5B40, 0x9B71, 0x5B43, 0x9B6F, 0x5B45, 0x9B70, 0x5B50, 0x8E71, 0x5B51, 0x9B72, 0x5B54, 0x8D45, 0x5B55, 0x9B73, 0x5B56, 0xFAA6, 0x5B57, 0x8E9A, 0x5B58, 0x91B6, 0x5B5A, 0x9B74, 0x5B5B, 0x9B75, 0x5B5C, 0x8E79, 0x5B5D, 0x8D46, 0x5B5F, 0x96D0, 0x5B63, 0x8B47, 0x5B64, 0x8CC7, 0x5B65, 0x9B76, 0x5B66, 0x8A77, 0x5B69, 0x9B77, 0x5B6B, 0x91B7, 0x5B70, 0x9B78, 0x5B71, 0x9BA1, 0x5B73, 0x9B79, 0x5B75, 0x9B7A, 0x5B78, 0x9B7B, 0x5B7A, 0x9B7D, 0x5B80, 0x9B7E, 0x5B83, 0x9B80, 0x5B85, 0x91EE, 0x5B87, 0x8946, 0x5B88, 0x8EE7, 0x5B89, 0x88C0, 0x5B8B, 0x9176, 0x5B8C, 0x8AAE, 0x5B8D, 0x8EB3, 0x5B8F, 0x8D47, 0x5B95, 0x9386, 0x5B97, 0x8F40, 0x5B98, 0x8AAF, 0x5B99, 0x9288, 0x5B9A, 0x92E8, 0x5B9B, 0x88B6, 0x5B9C, 0x8B58, 0x5B9D, 0x95F3, 0x5B9F, 0x8EC0, 0x5BA2, 0x8B71, 0x5BA3, 0x90E9, 0x5BA4, 0x8EBA, 0x5BA5, 0x9747, 0x5BA6, 0x9B81, 0x5BAE, 0x8B7B, 0x5BB0, 0x8DC9, 0x5BB3, 0x8A51, 0x5BB4, 0x8983, 0x5BB5, 0x8FAA, 0x5BB6, 0x89C6, 0x5BB8, 0x9B82, 0x5BB9, 0x9765, 0x5BBF, 0x8F68, 0x5BC0, 0xFAA7, 0x5BC2, 0x8EE2, 0x5BC3, 0x9B83, 0x5BC4, 0x8AF1, 0x5BC5, 0x93D0, 0x5BC6, 0x96A7, 0x5BC7, 0x9B84, 0x5BC9, 0x9B85, 0x5BCC, 0x9578, 0x5BD0, 0x9B87, 0x5BD2, 0x8AA6, 0x5BD3, 0x8BF5, 0x5BD4, 0x9B86, 0x5BD8, 0xFAA9, 0x5BDB, 0x8AB0, 0x5BDD, 0x9051, 0x5BDE, 0x9B8B, 0x5BDF, 0x8E40, 0x5BE1, 0x89C7, 0x5BE2, 0x9B8A, 0x5BE4, 0x9B88, 0x5BE5, 0x9B8C, 0x5BE6, 0x9B89, 0x5BE7, 0x944A, 0x5BE8, 0x9ECB, 0x5BE9, 0x9052, 0x5BEB, 0x9B8D, 0x5BEC, 0xFAAA, 0x5BEE, 0x97BE, 0x5BF0, 0x9B8E, 0x5BF3, 0x9B90, 0x5BF5, 0x929E, 0x5BF6, 0x9B8F, 0x5BF8, 0x90A1, 0x5BFA, 0x8E9B, 0x5BFE, 0x91CE, 0x5BFF, 0x8EF5, 0x5C01, 0x9595, 0x5C02, 0x90EA, 0x5C04, 0x8ECB, 0x5C05, 0x9B91, 0x5C06, 0x8FAB, 0x5C07, 0x9B92, 0x5C08, 0x9B93, 0x5C09, 0x88D1, 0x5C0A, 0x91B8, 0x5C0B, 0x9071, 0x5C0D, 0x9B94, 0x5C0E, 0x93B1, 0x5C0F, 0x8FAC, 0x5C11, 0x8FAD, 0x5C13, 0x9B95, 0x5C16, 0x90EB, 0x5C1A, 0x8FAE, 0x5C1E, 0xFAAB, 0x5C20, 0x9B96, 0x5C22, 0x9B97, 0x5C24, 0x96DE, 0x5C28, 0x9B98, 0x5C2D, 0x8BC4, 0x5C31, 0x8F41, 0x5C38, 0x9B99, 0x5C39, 0x9B9A, 0x5C3A, 0x8EDA, 0x5C3B, 0x904B, 0x5C3C, 0x93F2, 0x5C3D, 0x9073, 0x5C3E, 0x94F6, 0x5C3F, 0x9441, 0x5C40, 0x8BC7, 0x5C41, 0x9B9B, 0x5C45, 0x8B8F, 0x5C46, 0x9B9C, 0x5C48, 0x8BFC, 0x5C4A, 0x93CD, 0x5C4B, 0x89AE, 0x5C4D, 0x8E72, 0x5C4E, 0x9B9D, 0x5C4F, 0x9BA0, 0x5C50, 0x9B9F, 0x5C51, 0x8BFB, 0x5C53, 0x9B9E, 0x5C55, 0x9357, 0x5C5E, 0x91AE, 0x5C60, 0x936A, 0x5C61, 0x8EC6, 0x5C64, 0x9177, 0x5C65, 0x979A, 0x5C6C, 0x9BA2, 0x5C6E, 0x9BA3, 0x5C6F, 0x93D4, 0x5C71, 0x8E52, 0x5C76, 0x9BA5, 0x5C79, 0x9BA6, 0x5C8C, 0x9BA7, 0x5C90, 0x8AF2, 0x5C91, 0x9BA8, 0x5C94, 0x9BA9, 0x5CA1, 0x89AA, 0x5CA6, 0xFAAC, 0x5CA8, 0x915A, 0x5CA9, 0x8AE2, 0x5CAB, 0x9BAB, 0x5CAC, 0x96A6, 0x5CB1, 0x91D0, 0x5CB3, 0x8A78, 0x5CB6, 0x9BAD, 0x5CB7, 0x9BAF, 0x5CB8, 0x8ADD, 0x5CBA, 0xFAAD, 0x5CBB, 0x9BAC, 0x5CBC, 0x9BAE, 0x5CBE, 0x9BB1, 0x5CC5, 0x9BB0, 0x5CC7, 0x9BB2, 0x5CD9, 0x9BB3, 0x5CE0, 0x93BB, 0x5CE1, 0x8BAC, 0x5CE8, 0x89E3, 0x5CE9, 0x9BB4, 0x5CEA, 0x9BB9, 0x5CED, 0x9BB7, 0x5CEF, 0x95F5, 0x5CF0, 0x95F4, 0x5CF5, 0xFAAE, 0x5CF6, 0x9387, 0x5CFA, 0x9BB6, 0x5CFB, 0x8F73, 0x5CFD, 0x9BB5, 0x5D07, 0x9092, 0x5D0B, 0x9BBA, 0x5D0E, 0x8DE8, 0x5D11, 0x9BC0, 0x5D14, 0x9BC1, 0x5D15, 0x9BBB, 0x5D16, 0x8A52, 0x5D17, 0x9BBC, 0x5D18, 0x9BC5, 0x5D19, 0x9BC4, 0x5D1A, 0x9BC3, 0x5D1B, 0x9BBF, 0x5D1F, 0x9BBE, 0x5D22, 0x9BC2, 0x5D27, 0xFAAF, 0x5D29, 0x95F6, 0x5D42, 0xFAB2, 0x5D4B, 0x9BC9, 0x5D4C, 0x9BC6, 0x5D4E, 0x9BC8, 0x5D50, 0x9792, 0x5D52, 0x9BC7, 0x5D53, 0xFAB0, 0x5D5C, 0x9BBD, 0x5D69, 0x9093, 0x5D6C, 0x9BCA, 0x5D6D, 0xFAB3, 0x5D6F, 0x8DB5, 0x5D73, 0x9BCB, 0x5D76, 0x9BCC, 0x5D82, 0x9BCF, 0x5D84, 0x9BCE, 0x5D87, 0x9BCD, 0x5D8B, 0x9388, 0x5D8C, 0x9BB8, 0x5D90, 0x9BD5, 0x5D9D, 0x9BD1, 0x5DA2, 0x9BD0, 0x5DAC, 0x9BD2, 0x5DAE, 0x9BD3, 0x5DB7, 0x9BD6, 0x5DB8, 0xFAB4, 0x5DB9, 0xFAB5, 0x5DBA, 0x97E4, 0x5DBC, 0x9BD7, 0x5DBD, 0x9BD4, 0x5DC9, 0x9BD8, 0x5DCC, 0x8ADE, 0x5DCD, 0x9BD9, 0x5DD0, 0xFAB6, 0x5DD2, 0x9BDB, 0x5DD3, 0x9BDA, 0x5DD6, 0x9BDC, 0x5DDB, 0x9BDD, 0x5DDD, 0x90EC, 0x5DDE, 0x8F42, 0x5DE1, 0x8F84, 0x5DE3, 0x9183, 0x5DE5, 0x8D48, 0x5DE6, 0x8DB6, 0x5DE7, 0x8D49, 0x5DE8, 0x8B90, 0x5DEB, 0x9BDE, 0x5DEE, 0x8DB7, 0x5DF1, 0x8CC8, 0x5DF2, 0x9BDF, 0x5DF3, 0x96A4, 0x5DF4, 0x9462, 0x5DF5, 0x9BE0, 0x5DF7, 0x8D4A, 0x5DFB, 0x8AAA, 0x5DFD, 0x9246, 0x5DFE, 0x8BD0, 0x5E02, 0x8E73, 0x5E03, 0x957A, 0x5E06, 0x94BF, 0x5E0B, 0x9BE1, 0x5E0C, 0x8AF3, 0x5E11, 0x9BE4, 0x5E16, 0x929F, 0x5E19, 0x9BE3, 0x5E1A, 0x9BE2, 0x5E1B, 0x9BE5, 0x5E1D, 0x92E9, 0x5E25, 0x9083, 0x5E2B, 0x8E74, 0x5E2D, 0x90C8, 0x5E2F, 0x91D1, 0x5E30, 0x8B41, 0x5E33, 0x92A0, 0x5E36, 0x9BE6, 0x5E37, 0x9BE7, 0x5E38, 0x8FED, 0x5E3D, 0x9658, 0x5E40, 0x9BEA, 0x5E43, 0x9BE9, 0x5E44, 0x9BE8, 0x5E45, 0x959D, 0x5E47, 0x9BF1, 0x5E4C, 0x9679, 0x5E4E, 0x9BEB, 0x5E54, 0x9BED, 0x5E55, 0x968B, 0x5E57, 0x9BEC, 0x5E5F, 0x9BEE, 0x5E61, 0x94A6, 0x5E62, 0x9BEF, 0x5E63, 0x95BC, 0x5E64, 0x9BF0, 0x5E72, 0x8AB1, 0x5E73, 0x95BD, 0x5E74, 0x944E, 0x5E75, 0x9BF2, 0x5E76, 0x9BF3, 0x5E78, 0x8D4B, 0x5E79, 0x8AB2, 0x5E7A, 0x9BF4, 0x5E7B, 0x8CB6, 0x5E7C, 0x9763, 0x5E7D, 0x9748, 0x5E7E, 0x8AF4, 0x5E7F, 0x9BF6, 0x5E81, 0x92A1, 0x5E83, 0x8D4C, 0x5E84, 0x8FAF, 0x5E87, 0x94DD, 0x5E8A, 0x8FB0, 0x5E8F, 0x8F98, 0x5E95, 0x92EA, 0x5E96, 0x95F7, 0x5E97, 0x9358, 0x5E9A, 0x8D4D, 0x5E9C, 0x957B, 0x5EA0, 0x9BF7, 0x5EA6, 0x9378, 0x5EA7, 0x8DC0, 0x5EAB, 0x8CC9, 0x5EAD, 0x92EB, 0x5EB5, 0x88C1, 0x5EB6, 0x8F8E, 0x5EB7, 0x8D4E, 0x5EB8, 0x9766, 0x5EC1, 0x9BF8, 0x5EC2, 0x9BF9, 0x5EC3, 0x9470, 0x5EC8, 0x9BFA, 0x5EC9, 0x97F5, 0x5ECA, 0x984C, 0x5ECF, 0x9BFC, 0x5ED0, 0x9BFB, 0x5ED3, 0x8A66, 0x5ED6, 0x9C40, 0x5EDA, 0x9C43, 0x5EDB, 0x9C44, 0x5EDD, 0x9C42, 0x5EDF, 0x955F, 0x5EE0, 0x8FB1, 0x5EE1, 0x9C46, 0x5EE2, 0x9C45, 0x5EE3, 0x9C41, 0x5EE8, 0x9C47, 0x5EE9, 0x9C48, 0x5EEC, 0x9C49, 0x5EF0, 0x9C4C, 0x5EF1, 0x9C4A, 0x5EF3, 0x9C4B, 0x5EF4, 0x9C4D, 0x5EF6, 0x8984, 0x5EF7, 0x92EC, 0x5EF8, 0x9C4E, 0x5EFA, 0x8C9A, 0x5EFB, 0x89F4, 0x5EFC, 0x9455, 0x5EFE, 0x9C4F, 0x5EFF, 0x93F9, 0x5F01, 0x95D9, 0x5F03, 0x9C50, 0x5F04, 0x984D, 0x5F09, 0x9C51, 0x5F0A, 0x95BE, 0x5F0B, 0x9C54, 0x5F0C, 0x989F, 0x5F0D, 0x98AF, 0x5F0F, 0x8EAE, 0x5F10, 0x93F3, 0x5F11, 0x9C55, 0x5F13, 0x8B7C, 0x5F14, 0x92A2, 0x5F15, 0x88F8, 0x5F16, 0x9C56, 0x5F17, 0x95A4, 0x5F18, 0x8D4F, 0x5F1B, 0x926F, 0x5F1F, 0x92ED, 0x5F21, 0xFAB7, 0x5F25, 0x96ED, 0x5F26, 0x8CB7, 0x5F27, 0x8CCA, 0x5F29, 0x9C57, 0x5F2D, 0x9C58, 0x5F2F, 0x9C5E, 0x5F31, 0x8EE3, 0x5F34, 0xFAB8, 0x5F35, 0x92A3, 0x5F37, 0x8BAD, 0x5F38, 0x9C59, 0x5F3C, 0x954A, 0x5F3E, 0x9265, 0x5F41, 0x9C5A, 0x5F45, 0xFA67, 0x5F48, 0x9C5B, 0x5F4A, 0x8BAE, 0x5F4C, 0x9C5C, 0x5F4E, 0x9C5D, 0x5F51, 0x9C5F, 0x5F53, 0x9396, 0x5F56, 0x9C60, 0x5F57, 0x9C61, 0x5F59, 0x9C62, 0x5F5C, 0x9C53, 0x5F5D, 0x9C52, 0x5F61, 0x9C63, 0x5F62, 0x8C60, 0x5F66, 0x9546, 0x5F67, 0xFAB9, 0x5F69, 0x8DCA, 0x5F6A, 0x9556, 0x5F6B, 0x92A4, 0x5F6C, 0x956A, 0x5F6D, 0x9C64, 0x5F70, 0x8FB2, 0x5F71, 0x8965, 0x5F73, 0x9C65, 0x5F77, 0x9C66, 0x5F79, 0x96F0, 0x5F7C, 0x94DE, 0x5F7F, 0x9C69, 0x5F80, 0x899D, 0x5F81, 0x90AA, 0x5F82, 0x9C68, 0x5F83, 0x9C67, 0x5F84, 0x8C61, 0x5F85, 0x91D2, 0x5F87, 0x9C6D, 0x5F88, 0x9C6B, 0x5F8A, 0x9C6A, 0x5F8B, 0x97A5, 0x5F8C, 0x8CE3, 0x5F90, 0x8F99, 0x5F91, 0x9C6C, 0x5F92, 0x936B, 0x5F93, 0x8F5D, 0x5F97, 0x93BE, 0x5F98, 0x9C70, 0x5F99, 0x9C6F, 0x5F9E, 0x9C6E, 0x5FA0, 0x9C71, 0x5FA1, 0x8CE4, 0x5FA8, 0x9C72, 0x5FA9, 0x959C, 0x5FAA, 0x8F7A, 0x5FAD, 0x9C73, 0x5FAE, 0x94F7, 0x5FB3, 0x93BF, 0x5FB4, 0x92A5, 0x5FB7, 0xFABA, 0x5FB9, 0x934F, 0x5FBC, 0x9C74, 0x5FBD, 0x8B4A, 0x5FC3, 0x9053, 0x5FC5, 0x954B, 0x5FCC, 0x8AF5, 0x5FCD, 0x9445, 0x5FD6, 0x9C75, 0x5FD7, 0x8E75, 0x5FD8, 0x9659, 0x5FD9, 0x965A, 0x5FDC, 0x899E, 0x5FDD, 0x9C7A, 0x5FDE, 0xFABB, 0x5FE0, 0x9289, 0x5FE4, 0x9C77, 0x5FEB, 0x89F5, 0x5FF0, 0x9CAB, 0x5FF1, 0x9C79, 0x5FF5, 0x944F, 0x5FF8, 0x9C78, 0x5FFB, 0x9C76, 0x5FFD, 0x8D9A, 0x5FFF, 0x9C7C, 0x600E, 0x9C83, 0x600F, 0x9C89, 0x6010, 0x9C81, 0x6012, 0x937B, 0x6015, 0x9C86, 0x6016, 0x957C, 0x6019, 0x9C80, 0x601B, 0x9C85, 0x601C, 0x97E5, 0x601D, 0x8E76, 0x6020, 0x91D3, 0x6021, 0x9C7D, 0x6025, 0x8B7D, 0x6026, 0x9C88, 0x6027, 0x90AB, 0x6028, 0x8985, 0x6029, 0x9C82, 0x602A, 0x89F6, 0x602B, 0x9C87, 0x602F, 0x8BAF, 0x6031, 0x9C84, 0x603A, 0x9C8A, 0x6041, 0x9C8C, 0x6042, 0x9C96, 0x6043, 0x9C94, 0x6046, 0x9C91, 0x604A, 0x9C90, 0x604B, 0x97F6, 0x604D, 0x9C92, 0x6050, 0x8BB0, 0x6052, 0x8D50, 0x6055, 0x8F9A, 0x6059, 0x9C99, 0x605A, 0x9C8B, 0x605D, 0xFABC, 0x605F, 0x9C8F, 0x6060, 0x9C7E, 0x6062, 0x89F8, 0x6063, 0x9C93, 0x6064, 0x9C95, 0x6065, 0x9270, 0x6068, 0x8DA6, 0x6069, 0x89B6, 0x606A, 0x9C8D, 0x606B, 0x9C98, 0x606C, 0x9C97, 0x606D, 0x8BB1, 0x606F, 0x91A7, 0x6070, 0x8A86, 0x6075, 0x8C62, 0x6077, 0x9C8E, 0x6081, 0x9C9A, 0x6083, 0x9C9D, 0x6084, 0x9C9F, 0x6085, 0xFABD, 0x6089, 0x8EBB, 0x608A, 0xFABE, 0x608B, 0x9CA5, 0x608C, 0x92EE, 0x608D, 0x9C9B, 0x6092, 0x9CA3, 0x6094, 0x89F7, 0x6096, 0x9CA1, 0x6097, 0x9CA2, 0x609A, 0x9C9E, 0x609B, 0x9CA0, 0x609F, 0x8CE5, 0x60A0, 0x9749, 0x60A3, 0x8AB3, 0x60A6, 0x8978, 0x60A7, 0x9CA4, 0x60A9, 0x9459, 0x60AA, 0x88AB, 0x60B2, 0x94DF, 0x60B3, 0x9C7B, 0x60B4, 0x9CAA, 0x60B5, 0x9CAE, 0x60B6, 0x96E3, 0x60B8, 0x9CA7, 0x60BC, 0x9389, 0x60BD, 0x9CAC, 0x60C5, 0x8FEE, 0x60C6, 0x9CAD, 0x60C7, 0x93D5, 0x60D1, 0x9866, 0x60D3, 0x9CA9, 0x60D5, 0xFAC0, 0x60D8, 0x9CAF, 0x60DA, 0x8D9B, 0x60DC, 0x90C9, 0x60DE, 0xFABF, 0x60DF, 0x88D2, 0x60E0, 0x9CA8, 0x60E1, 0x9CA6, 0x60E3, 0x9179, 0x60E7, 0x9C9C, 0x60E8, 0x8E53, 0x60F0, 0x91C4, 0x60F1, 0x9CBB, 0x60F2, 0xFAC2, 0x60F3, 0x917A, 0x60F4, 0x9CB6, 0x60F6, 0x9CB3, 0x60F7, 0x9CB4, 0x60F9, 0x8EE4, 0x60FA, 0x9CB7, 0x60FB, 0x9CBA, 0x6100, 0x9CB5, 0x6101, 0x8F44, 0x6103, 0x9CB8, 0x6106, 0x9CB2, 0x6108, 0x96FA, 0x6109, 0x96F9, 0x610D, 0x9CBC, 0x610E, 0x9CBD, 0x610F, 0x88D3, 0x6111, 0xFAC3, 0x6115, 0x9CB1, 0x611A, 0x8BF0, 0x611B, 0x88A4, 0x611F, 0x8AB4, 0x6120, 0xFAC1, 0x6121, 0x9CB9, 0x6127, 0x9CC1, 0x6128, 0x9CC0, 0x612C, 0x9CC5, 0x6130, 0xFAC5, 0x6134, 0x9CC6, 0x6137, 0xFAC4, 0x613C, 0x9CC4, 0x613D, 0x9CC7, 0x613E, 0x9CBF, 0x613F, 0x9CC3, 0x6142, 0x9CC8, 0x6144, 0x9CC9, 0x6147, 0x9CBE, 0x6148, 0x8E9C, 0x614A, 0x9CC2, 0x614B, 0x91D4, 0x614C, 0x8D51, 0x614D, 0x9CB0, 0x614E, 0x9054, 0x6153, 0x9CD6, 0x6155, 0x95E7, 0x6158, 0x9CCC, 0x6159, 0x9CCD, 0x615A, 0x9CCE, 0x615D, 0x9CD5, 0x615F, 0x9CD4, 0x6162, 0x969D, 0x6163, 0x8AB5, 0x6165, 0x9CD2, 0x6167, 0x8C64, 0x6168, 0x8A53, 0x616B, 0x9CCF, 0x616E, 0x97B6, 0x616F, 0x9CD1, 0x6170, 0x88D4, 0x6171, 0x9CD3, 0x6173, 0x9CCA, 0x6174, 0x9CD0, 0x6175, 0x9CD7, 0x6176, 0x8C63, 0x6177, 0x9CCB, 0x617E, 0x977C, 0x6182, 0x974A, 0x6187, 0x9CDA, 0x618A, 0x9CDE, 0x618E, 0x919E, 0x6190, 0x97F7, 0x6191, 0x9CDF, 0x6194, 0x9CDC, 0x6196, 0x9CD9, 0x6198, 0xFAC6, 0x6199, 0x9CD8, 0x619A, 0x9CDD, 0x61A4, 0x95AE, 0x61A7, 0x93B2, 0x61A9, 0x8C65, 0x61AB, 0x9CE0, 0x61AC, 0x9CDB, 0x61AE, 0x9CE1, 0x61B2, 0x8C9B, 0x61B6, 0x89AF, 0x61BA, 0x9CE9, 0x61BE, 0x8AB6, 0x61C3, 0x9CE7, 0x61C6, 0x9CE8, 0x61C7, 0x8DA7, 0x61C8, 0x9CE6, 0x61C9, 0x9CE4, 0x61CA, 0x9CE3, 0x61CB, 0x9CEA, 0x61CC, 0x9CE2, 0x61CD, 0x9CEC, 0x61D0, 0x89F9, 0x61E3, 0x9CEE, 0x61E6, 0x9CED, 0x61F2, 0x92A6, 0x61F4, 0x9CF1, 0x61F6, 0x9CEF, 0x61F7, 0x9CE5, 0x61F8, 0x8C9C, 0x61FA, 0x9CF0, 0x61FC, 0x9CF4, 0x61FD, 0x9CF3, 0x61FE, 0x9CF5, 0x61FF, 0x9CF2, 0x6200, 0x9CF6, 0x6208, 0x9CF7, 0x6209, 0x9CF8, 0x620A, 0x95E8, 0x620C, 0x9CFA, 0x620D, 0x9CF9, 0x620E, 0x8F5E, 0x6210, 0x90AC, 0x6211, 0x89E4, 0x6212, 0x89FA, 0x6213, 0xFAC7, 0x6214, 0x9CFB, 0x6216, 0x88BD, 0x621A, 0x90CA, 0x621B, 0x9CFC, 0x621D, 0xE6C1, 0x621E, 0x9D40, 0x621F, 0x8C81, 0x6221, 0x9D41, 0x6226, 0x90ED, 0x622A, 0x9D42, 0x622E, 0x9D43, 0x622F, 0x8B59, 0x6230, 0x9D44, 0x6232, 0x9D45, 0x6233, 0x9D46, 0x6234, 0x91D5, 0x6238, 0x8CCB, 0x623B, 0x96DF, 0x623F, 0x965B, 0x6240, 0x8F8A, 0x6241, 0x9D47, 0x6247, 0x90EE, 0x6248, 0xE7BB, 0x6249, 0x94E0, 0x624B, 0x8EE8, 0x624D, 0x8DCB, 0x624E, 0x9D48, 0x6253, 0x91C5, 0x6255, 0x95A5, 0x6258, 0x91EF, 0x625B, 0x9D4B, 0x625E, 0x9D49, 0x6260, 0x9D4C, 0x6263, 0x9D4A, 0x6268, 0x9D4D, 0x626E, 0x95AF, 0x6271, 0x88B5, 0x6276, 0x957D, 0x6279, 0x94E1, 0x627C, 0x9D4E, 0x627E, 0x9D51, 0x627F, 0x8FB3, 0x6280, 0x8B5A, 0x6282, 0x9D4F, 0x6283, 0x9D56, 0x6284, 0x8FB4, 0x6289, 0x9D50, 0x628A, 0x9463, 0x6291, 0x977D, 0x6292, 0x9D52, 0x6293, 0x9D53, 0x6294, 0x9D57, 0x6295, 0x938A, 0x6296, 0x9D54, 0x6297, 0x8D52, 0x6298, 0x90DC, 0x629B, 0x9D65, 0x629C, 0x94B2, 0x629E, 0x91F0, 0x62A6, 0xFAC8, 0x62AB, 0x94E2, 0x62AC, 0x9DAB, 0x62B1, 0x95F8, 0x62B5, 0x92EF, 0x62B9, 0x9695, 0x62BB, 0x9D5A, 0x62BC, 0x899F, 0x62BD, 0x928A, 0x62C2, 0x9D63, 0x62C5, 0x9253, 0x62C6, 0x9D5D, 0x62C7, 0x9D64, 0x62C8, 0x9D5F, 0x62C9, 0x9D66, 0x62CA, 0x9D62, 0x62CC, 0x9D61, 0x62CD, 0x948F, 0x62CF, 0x9D5B, 0x62D0, 0x89FB, 0x62D1, 0x9D59, 0x62D2, 0x8B91, 0x62D3, 0x91F1, 0x62D4, 0x9D55, 0x62D7, 0x9D58, 0x62D8, 0x8D53, 0x62D9, 0x90D9, 0x62DB, 0x8FB5, 0x62DC, 0x9D60, 0x62DD, 0x9471, 0x62E0, 0x8B92, 0x62E1, 0x8A67, 0x62EC, 0x8A87, 0x62ED, 0x9040, 0x62EE, 0x9D68, 0x62EF, 0x9D6D, 0x62F1, 0x9D69, 0x62F3, 0x8C9D, 0x62F5, 0x9D6E, 0x62F6, 0x8E41, 0x62F7, 0x8D89, 0x62FE, 0x8F45, 0x62FF, 0x9D5C, 0x6301, 0x8E9D, 0x6302, 0x9D6B, 0x6307, 0x8E77, 0x6308, 0x9D6C, 0x6309, 0x88C2, 0x630C, 0x9D67, 0x6311, 0x92A7, 0x6319, 0x8B93, 0x631F, 0x8BB2, 0x6327, 0x9D6A, 0x6328, 0x88A5, 0x632B, 0x8DC1, 0x632F, 0x9055, 0x633A, 0x92F0, 0x633D, 0x94D2, 0x633E, 0x9D70, 0x633F, 0x917D, 0x6349, 0x91A8, 0x634C, 0x8E4A, 0x634D, 0x9D71, 0x634F, 0x9D73, 0x6350, 0x9D6F, 0x6355, 0x95DF, 0x6357, 0x92BB, 0x635C, 0x917B, 0x6367, 0x95F9, 0x6368, 0x8ECC, 0x6369, 0x9D80, 0x636B, 0x9D7E, 0x636E, 0x9098, 0x6372, 0x8C9E, 0x6376, 0x9D78, 0x6377, 0x8FB7, 0x637A, 0x93E6, 0x637B, 0x9450, 0x6380, 0x9D76, 0x6383, 0x917C, 0x6388, 0x8EF6, 0x6389, 0x9D7B, 0x638C, 0x8FB6, 0x638E, 0x9D75, 0x638F, 0x9D7A, 0x6392, 0x9472, 0x6396, 0x9D74, 0x6398, 0x8C40, 0x639B, 0x8A7C, 0x639F, 0x9D7C, 0x63A0, 0x97A9, 0x63A1, 0x8DCC, 0x63A2, 0x9254, 0x63A3, 0x9D79, 0x63A5, 0x90DA, 0x63A7, 0x8D54, 0x63A8, 0x9084, 0x63A9, 0x8986, 0x63AA, 0x915B, 0x63AB, 0x9D77, 0x63AC, 0x8B64, 0x63B2, 0x8C66, 0x63B4, 0x92CD, 0x63B5, 0x9D7D, 0x63BB, 0x917E, 0x63BE, 0x9D81, 0x63C0, 0x9D83, 0x63C3, 0x91B5, 0x63C4, 0x9D89, 0x63C6, 0x9D84, 0x63C9, 0x9D86, 0x63CF, 0x9560, 0x63D0, 0x92F1, 0x63D2, 0x9D87, 0x63D6, 0x974B, 0x63DA, 0x9767, 0x63DB, 0x8AB7, 0x63E1, 0x88AC, 0x63E3, 0x9D85, 0x63E9, 0x9D82, 0x63EE, 0x8AF6, 0x63F4, 0x8987, 0x63F5, 0xFAC9, 0x63F6, 0x9D88, 0x63FA, 0x9768, 0x6406, 0x9D8C, 0x640D, 0x91B9, 0x640F, 0x9D93, 0x6413, 0x9D8D, 0x6416, 0x9D8A, 0x6417, 0x9D91, 0x641C, 0x9D72, 0x6426, 0x9D8E, 0x6428, 0x9D92, 0x642C, 0x94C0, 0x642D, 0x938B, 0x6434, 0x9D8B, 0x6436, 0x9D8F, 0x643A, 0x8C67, 0x643E, 0x8DEF, 0x6442, 0x90DB, 0x644E, 0x9D97, 0x6458, 0x9345, 0x6460, 0xFACA, 0x6467, 0x9D94, 0x6469, 0x9680, 0x646F, 0x9D95, 0x6476, 0x9D96, 0x6478, 0x96CC, 0x647A, 0x90A0, 0x6483, 0x8C82, 0x6488, 0x9D9D, 0x6492, 0x8E54, 0x6493, 0x9D9A, 0x6495, 0x9D99, 0x649A, 0x9451, 0x649D, 0xFACB, 0x649E, 0x93B3, 0x64A4, 0x9350, 0x64A5, 0x9D9B, 0x64A9, 0x9D9C, 0x64AB, 0x958F, 0x64AD, 0x9464, 0x64AE, 0x8E42, 0x64B0, 0x90EF, 0x64B2, 0x966F, 0x64B9, 0x8A68, 0x64BB, 0x9DA3, 0x64BC, 0x9D9E, 0x64C1, 0x9769, 0x64C2, 0x9DA5, 0x64C5, 0x9DA1, 0x64C7, 0x9DA2, 0x64CD, 0x9180, 0x64CE, 0xFACC, 0x64D2, 0x9DA0, 0x64D4, 0x9D5E, 0x64D8, 0x9DA4, 0x64DA, 0x9D9F, 0x64E0, 0x9DA9, 0x64E1, 0x9DAA, 0x64E2, 0x9346, 0x64E3, 0x9DAC, 0x64E6, 0x8E43, 0x64E7, 0x9DA7, 0x64EC, 0x8B5B, 0x64EF, 0x9DAD, 0x64F1, 0x9DA6, 0x64F2, 0x9DB1, 0x64F4, 0x9DB0, 0x64F6, 0x9DAF, 0x64FA, 0x9DB2, 0x64FD, 0x9DB4, 0x64FE, 0x8FEF, 0x6500, 0x9DB3, 0x6505, 0x9DB7, 0x6518, 0x9DB5, 0x651C, 0x9DB6, 0x651D, 0x9D90, 0x6523, 0x9DB9, 0x6524, 0x9DB8, 0x652A, 0x9D98, 0x652B, 0x9DBA, 0x652C, 0x9DAE, 0x652F, 0x8E78, 0x6534, 0x9DBB, 0x6535, 0x9DBC, 0x6536, 0x9DBE, 0x6537, 0x9DBD, 0x6538, 0x9DBF, 0x6539, 0x89FC, 0x653B, 0x8D55, 0x653E, 0x95FA, 0x653F, 0x90AD, 0x6545, 0x8CCC, 0x6548, 0x9DC1, 0x654D, 0x9DC4, 0x654E, 0xFACD, 0x654F, 0x9571, 0x6551, 0x8B7E, 0x6555, 0x9DC3, 0x6556, 0x9DC2, 0x6557, 0x9473, 0x6558, 0x9DC5, 0x6559, 0x8BB3, 0x655D, 0x9DC7, 0x655E, 0x9DC6, 0x6562, 0x8AB8, 0x6563, 0x8E55, 0x6566, 0x93D6, 0x656C, 0x8C68, 0x6570, 0x9094, 0x6572, 0x9DC8, 0x6574, 0x90AE, 0x6575, 0x9347, 0x6577, 0x957E, 0x6578, 0x9DC9, 0x6582, 0x9DCA, 0x6583, 0x9DCB, 0x6587, 0x95B6, 0x6588, 0x9B7C, 0x6589, 0x90C4, 0x658C, 0x956B, 0x658E, 0x8DD6, 0x6590, 0x94E3, 0x6591, 0x94C1, 0x6597, 0x936C, 0x6599, 0x97BF, 0x659B, 0x9DCD, 0x659C, 0x8ECE, 0x659F, 0x9DCE, 0x65A1, 0x88B4, 0x65A4, 0x8BD2, 0x65A5, 0x90CB, 0x65A7, 0x9580, 0x65AB, 0x9DCF, 0x65AC, 0x8E61, 0x65AD, 0x9266, 0x65AF, 0x8E7A, 0x65B0, 0x9056, 0x65B7, 0x9DD0, 0x65B9, 0x95FB, 0x65BC, 0x8997, 0x65BD, 0x8E7B, 0x65C1, 0x9DD3, 0x65C3, 0x9DD1, 0x65C4, 0x9DD4, 0x65C5, 0x97B7, 0x65C6, 0x9DD2, 0x65CB, 0x90F9, 0x65CC, 0x9DD5, 0x65CF, 0x91B0, 0x65D2, 0x9DD6, 0x65D7, 0x8AF8, 0x65D9, 0x9DD8, 0x65DB, 0x9DD7, 0x65E0, 0x9DD9, 0x65E1, 0x9DDA, 0x65E2, 0x8AF9, 0x65E5, 0x93FA, 0x65E6, 0x9255, 0x65E7, 0x8B8C, 0x65E8, 0x8E7C, 0x65E9, 0x9181, 0x65EC, 0x8F7B, 0x65ED, 0x88AE, 0x65F1, 0x9DDB, 0x65FA, 0x89A0, 0x65FB, 0x9DDF, 0x6600, 0xFACE, 0x6602, 0x8D56, 0x6603, 0x9DDE, 0x6606, 0x8DA9, 0x6607, 0x8FB8, 0x6609, 0xFAD1, 0x660A, 0x9DDD, 0x660C, 0x8FB9, 0x660E, 0x96BE, 0x660F, 0x8DA8, 0x6613, 0x88D5, 0x6614, 0x90CC, 0x6615, 0xFACF, 0x661C, 0x9DE4, 0x661E, 0xFAD3, 0x661F, 0x90AF, 0x6620, 0x8966, 0x6624, 0xFAD4, 0x6625, 0x8F74, 0x6627, 0x9686, 0x6628, 0x8DF0, 0x662D, 0x8FBA, 0x662E, 0xFAD2, 0x662F, 0x90A5, 0x6631, 0xFA63, 0x6634, 0x9DE3, 0x6635, 0x9DE1, 0x6636, 0x9DE2, 0x663B, 0xFAD0, 0x663C, 0x928B, 0x663F, 0x9E45, 0x6641, 0x9DE8, 0x6642, 0x8E9E, 0x6643, 0x8D57, 0x6644, 0x9DE6, 0x6649, 0x9DE7, 0x664B, 0x9057, 0x664F, 0x9DE5, 0x6652, 0x8E4E, 0x6657, 0xFAD6, 0x6659, 0xFAD7, 0x665D, 0x9DEA, 0x665E, 0x9DE9, 0x665F, 0x9DEE, 0x6662, 0x9DEF, 0x6664, 0x9DEB, 0x6665, 0xFAD5, 0x6666, 0x8A41, 0x6667, 0x9DEC, 0x6668, 0x9DED, 0x6669, 0x94D3, 0x666E, 0x9581, 0x666F, 0x8C69, 0x6670, 0x9DF0, 0x6673, 0xFAD9, 0x6674, 0x90B0, 0x6676, 0x8FBB, 0x667A, 0x9271, 0x6681, 0x8BC5, 0x6683, 0x9DF1, 0x6684, 0x9DF5, 0x6687, 0x89C9, 0x6688, 0x9DF2, 0x6689, 0x9DF4, 0x668E, 0x9DF3, 0x6691, 0x8F8B, 0x6696, 0x9267, 0x6697, 0x88C3, 0x6698, 0x9DF6, 0x6699, 0xFADA, 0x669D, 0x9DF7, 0x66A0, 0xFADB, 0x66A2, 0x92A8, 0x66A6, 0x97EF, 0x66AB, 0x8E62, 0x66AE, 0x95E9, 0x66B2, 0xFADC, 0x66B4, 0x965C, 0x66B8, 0x9E41, 0x66B9, 0x9DF9, 0x66BC, 0x9DFC, 0x66BE, 0x9DFB, 0x66BF, 0xFADD, 0x66C1, 0x9DF8, 0x66C4, 0x9E40, 0x66C7, 0x93DC, 0x66C9, 0x9DFA, 0x66D6, 0x9E42, 0x66D9, 0x8F8C, 0x66DA, 0x9E43, 0x66DC, 0x976A, 0x66DD, 0x9498, 0x66E0, 0x9E44, 0x66E6, 0x9E46, 0x66E9, 0x9E47, 0x66F0, 0x9E48, 0x66F2, 0x8BC8, 0x66F3, 0x8967, 0x66F4, 0x8D58, 0x66F5, 0x9E49, 0x66F7, 0x9E4A, 0x66F8, 0x8F91, 0x66F9, 0x9182, 0x66FA, 0xFADE, 0x66FB, 0xFA66, 0x66FC, 0x99D6, 0x66FD, 0x915D, 0x66FE, 0x915C, 0x66FF, 0x91D6, 0x6700, 0x8DC5, 0x6703, 0x98F0, 0x6708, 0x8C8E, 0x6709, 0x974C, 0x670B, 0x95FC, 0x670D, 0x959E, 0x670E, 0xFADF, 0x670F, 0x9E4B, 0x6714, 0x8DF1, 0x6715, 0x92BD, 0x6716, 0x9E4C, 0x6717, 0x984E, 0x671B, 0x965D, 0x671D, 0x92A9, 0x671E, 0x9E4D, 0x671F, 0x8AFA, 0x6726, 0x9E4E, 0x6727, 0x9E4F, 0x6728, 0x96D8, 0x672A, 0x96A2, 0x672B, 0x9696, 0x672C, 0x967B, 0x672D, 0x8E44, 0x672E, 0x9E51, 0x6731, 0x8EE9, 0x6734, 0x9670, 0x6736, 0x9E53, 0x6737, 0x9E56, 0x6738, 0x9E55, 0x673A, 0x8AF7, 0x673D, 0x8B80, 0x673F, 0x9E52, 0x6741, 0x9E54, 0x6746, 0x9E57, 0x6749, 0x9099, 0x674E, 0x979B, 0x674F, 0x88C7, 0x6750, 0x8DDE, 0x6751, 0x91BA, 0x6753, 0x8EDB, 0x6756, 0x8FF1, 0x6759, 0x9E5A, 0x675C, 0x936D, 0x675E, 0x9E58, 0x675F, 0x91A9, 0x6760, 0x9E59, 0x6761, 0x8FF0, 0x6762, 0x96DB, 0x6763, 0x9E5B, 0x6764, 0x9E5C, 0x6765, 0x9788, 0x6766, 0xFAE1, 0x676A, 0x9E61, 0x676D, 0x8D59, 0x676F, 0x9474, 0x6770, 0x9E5E, 0x6771, 0x938C, 0x6772, 0x9DDC, 0x6773, 0x9DE0, 0x6775, 0x8B6E, 0x6777, 0x9466, 0x677C, 0x9E60, 0x677E, 0x8FBC, 0x677F, 0x94C2, 0x6785, 0x9E66, 0x6787, 0x94F8, 0x6789, 0x9E5D, 0x678B, 0x9E63, 0x678C, 0x9E62, 0x6790, 0x90CD, 0x6795, 0x968D, 0x6797, 0x97D1, 0x679A, 0x9687, 0x679C, 0x89CA, 0x679D, 0x8E7D, 0x67A0, 0x9867, 0x67A1, 0x9E65, 0x67A2, 0x9095, 0x67A6, 0x9E64, 0x67A9, 0x9E5F, 0x67AF, 0x8CCD, 0x67B3, 0x9E6B, 0x67B4, 0x9E69, 0x67B6, 0x89CB, 0x67B7, 0x9E67, 0x67B8, 0x9E6D, 0x67B9, 0x9E73, 0x67BB, 0xFAE2, 0x67C0, 0xFAE4, 0x67C1, 0x91C6, 0x67C4, 0x95BF, 0x67C6, 0x9E75, 0x67CA, 0x9541, 0x67CE, 0x9E74, 0x67CF, 0x9490, 0x67D0, 0x965E, 0x67D1, 0x8AB9, 0x67D3, 0x90F5, 0x67D4, 0x8F5F, 0x67D8, 0x92D1, 0x67DA, 0x974D, 0x67DD, 0x9E70, 0x67DE, 0x9E6F, 0x67E2, 0x9E71, 0x67E4, 0x9E6E, 0x67E7, 0x9E76, 0x67E9, 0x9E6C, 0x67EC, 0x9E6A, 0x67EE, 0x9E72, 0x67EF, 0x9E68, 0x67F1, 0x928C, 0x67F3, 0x96F6, 0x67F4, 0x8EC4, 0x67F5, 0x8DF2, 0x67FB, 0x8DB8, 0x67FE, 0x968F, 0x67FF, 0x8A60, 0x6801, 0xFAE5, 0x6802, 0x92CC, 0x6803, 0x93C8, 0x6804, 0x8968, 0x6813, 0x90F0, 0x6816, 0x90B2, 0x6817, 0x8C49, 0x681E, 0x9E78, 0x6821, 0x8D5A, 0x6822, 0x8A9C, 0x6829, 0x9E7A, 0x682A, 0x8A94, 0x682B, 0x9E81, 0x6832, 0x9E7D, 0x6834, 0x90F1, 0x6838, 0x8A6A, 0x6839, 0x8DAA, 0x683C, 0x8A69, 0x683D, 0x8DCD, 0x6840, 0x9E7B, 0x6841, 0x8C85, 0x6842, 0x8C6A, 0x6843, 0x938D, 0x6844, 0xFAE6, 0x6846, 0x9E79, 0x6848, 0x88C4, 0x684D, 0x9E7C, 0x684E, 0x9E7E, 0x6850, 0x8BCB, 0x6851, 0x8C4B, 0x6852, 0xFAE3, 0x6853, 0x8ABA, 0x6854, 0x8B6A, 0x6859, 0x9E82, 0x685C, 0x8DF7, 0x685D, 0x9691, 0x685F, 0x8E56, 0x6863, 0x9E83, 0x6867, 0x954F, 0x6874, 0x9E8F, 0x6876, 0x89B1, 0x6877, 0x9E84, 0x687E, 0x9E95, 0x687F, 0x9E85, 0x6881, 0x97C0, 0x6883, 0x9E8C, 0x6885, 0x947E, 0x688D, 0x9E94, 0x688F, 0x9E87, 0x6893, 0x88B2, 0x6894, 0x9E89, 0x6897, 0x8D5B, 0x689B, 0x9E8B, 0x689D, 0x9E8A, 0x689F, 0x9E86, 0x68A0, 0x9E91, 0x68A2, 0x8FBD, 0x68A6, 0x9AEB, 0x68A7, 0x8CE6, 0x68A8, 0x979C, 0x68AD, 0x9E88, 0x68AF, 0x92F2, 0x68B0, 0x8A42, 0x68B1, 0x8DAB, 0x68B3, 0x9E80, 0x68B5, 0x9E90, 0x68B6, 0x8A81, 0x68B9, 0x9E8E, 0x68BA, 0x9E92, 0x68BC, 0x938E, 0x68C4, 0x8AFC, 0x68C6, 0x9EB0, 0x68C8, 0xFA64, 0x68C9, 0x96C7, 0x68CA, 0x9E97, 0x68CB, 0x8AFB, 0x68CD, 0x9E9E, 0x68CF, 0xFAE7, 0x68D2, 0x965F, 0x68D4, 0x9E9F, 0x68D5, 0x9EA1, 0x68D7, 0x9EA5, 0x68D8, 0x9E99, 0x68DA, 0x9249, 0x68DF, 0x938F, 0x68E0, 0x9EA9, 0x68E1, 0x9E9C, 0x68E3, 0x9EA6, 0x68E7, 0x9EA0, 0x68EE, 0x9058, 0x68EF, 0x9EAA, 0x68F2, 0x90B1, 0x68F9, 0x9EA8, 0x68FA, 0x8ABB, 0x6900, 0x986F, 0x6901, 0x9E96, 0x6904, 0x9EA4, 0x6905, 0x88D6, 0x6908, 0x9E98, 0x690B, 0x96B8, 0x690C, 0x9E9D, 0x690D, 0x9041, 0x690E, 0x92C5, 0x690F, 0x9E93, 0x6912, 0x9EA3, 0x6919, 0x909A, 0x691A, 0x9EAD, 0x691B, 0x8A91, 0x691C, 0x8C9F, 0x6921, 0x9EAF, 0x6922, 0x9E9A, 0x6923, 0x9EAE, 0x6925, 0x9EA7, 0x6926, 0x9E9B, 0x6928, 0x9EAB, 0x692A, 0x9EAC, 0x6930, 0x9EBD, 0x6934, 0x93CC, 0x6936, 0x9EA2, 0x6939, 0x9EB9, 0x693D, 0x9EBB, 0x693F, 0x92D6, 0x694A, 0x976B, 0x6953, 0x9596, 0x6954, 0x9EB6, 0x6955, 0x91C8, 0x6959, 0x9EBC, 0x695A, 0x915E, 0x695C, 0x9EB3, 0x695D, 0x9EC0, 0x695E, 0x9EBF, 0x6960, 0x93ED, 0x6961, 0x9EBE, 0x6962, 0x93E8, 0x6968, 0xFAE9, 0x696A, 0x9EC2, 0x696B, 0x9EB5, 0x696D, 0x8BC6, 0x696E, 0x9EB8, 0x696F, 0x8F7C, 0x6973, 0x9480, 0x6974, 0x9EBA, 0x6975, 0x8BC9, 0x6977, 0x9EB2, 0x6978, 0x9EB4, 0x6979, 0x9EB1, 0x697C, 0x984F, 0x697D, 0x8A79, 0x697E, 0x9EB7, 0x6981, 0x9EC1, 0x6982, 0x8A54, 0x698A, 0x8DE5, 0x698E, 0x897C, 0x6991, 0x9ED2, 0x6994, 0x9850, 0x6995, 0x9ED5, 0x6998, 0xFAEB, 0x699B, 0x9059, 0x699C, 0x9ED4, 0x69A0, 0x9ED3, 0x69A7, 0x9ED0, 0x69AE, 0x9EC4, 0x69B1, 0x9EE1, 0x69B2, 0x9EC3, 0x69B4, 0x9ED6, 0x69BB, 0x9ECE, 0x69BE, 0x9EC9, 0x69BF, 0x9EC6, 0x69C1, 0x9EC7, 0x69C3, 0x9ECF, 0x69C7, 0xEAA0, 0x69CA, 0x9ECC, 0x69CB, 0x8D5C, 0x69CC, 0x92C6, 0x69CD, 0x9184, 0x69CE, 0x9ECA, 0x69D0, 0x9EC5, 0x69D3, 0x9EC8, 0x69D8, 0x976C, 0x69D9, 0x968A, 0x69DD, 0x9ECD, 0x69DE, 0x9ED7, 0x69E2, 0xFAEC, 0x69E7, 0x9EDF, 0x69E8, 0x9ED8, 0x69EB, 0x9EE5, 0x69ED, 0x9EE3, 0x69F2, 0x9EDE, 0x69F9, 0x9EDD, 0x69FB, 0x92CE, 0x69FD, 0x9185, 0x69FF, 0x9EDB, 0x6A02, 0x9ED9, 0x6A05, 0x9EE0, 0x6A0A, 0x9EE6, 0x6A0B, 0x94F3, 0x6A0C, 0x9EEC, 0x6A12, 0x9EE7, 0x6A13, 0x9EEA, 0x6A14, 0x9EE4, 0x6A17, 0x9294, 0x6A19, 0x9557, 0x6A1B, 0x9EDA, 0x6A1E, 0x9EE2, 0x6A1F, 0x8FBE, 0x6A21, 0x96CD, 0x6A22, 0x9EF6, 0x6A23, 0x9EE9, 0x6A29, 0x8CA0, 0x6A2A, 0x89A1, 0x6A2B, 0x8A7E, 0x6A2E, 0x9ED1, 0x6A30, 0xFAED, 0x6A35, 0x8FBF, 0x6A36, 0x9EEE, 0x6A38, 0x9EF5, 0x6A39, 0x8EF7, 0x6A3A, 0x8A92, 0x6A3D, 0x924D, 0x6A44, 0x9EEB, 0x6A46, 0xFAEF, 0x6A47, 0x9EF0, 0x6A48, 0x9EF4, 0x6A4B, 0x8BB4, 0x6A58, 0x8B6B, 0x6A59, 0x9EF2, 0x6A5F, 0x8B40, 0x6A61, 0x93C9, 0x6A62, 0x9EF1, 0x6A66, 0x9EF3, 0x6A6B, 0xFAEE, 0x6A72, 0x9EED, 0x6A73, 0xFAF0, 0x6A78, 0x9EEF, 0x6A7E, 0xFAF1, 0x6A7F, 0x8A80, 0x6A80, 0x9268, 0x6A84, 0x9EFA, 0x6A8D, 0x9EF8, 0x6A8E, 0x8CE7, 0x6A90, 0x9EF7, 0x6A97, 0x9F40, 0x6A9C, 0x9E77, 0x6AA0, 0x9EF9, 0x6AA2, 0x9EFB, 0x6AA3, 0x9EFC, 0x6AAA, 0x9F4B, 0x6AAC, 0x9F47, 0x6AAE, 0x9E8D, 0x6AB3, 0x9F46, 0x6AB8, 0x9F45, 0x6ABB, 0x9F42, 0x6AC1, 0x9EE8, 0x6AC2, 0x9F44, 0x6AC3, 0x9F43, 0x6AD1, 0x9F49, 0x6AD3, 0x9845, 0x6ADA, 0x9F4C, 0x6ADB, 0x8BF9, 0x6ADE, 0x9F48, 0x6ADF, 0x9F4A, 0x6AE2, 0xFAF2, 0x6AE4, 0xFAF3, 0x6AE8, 0x94A5, 0x6AEA, 0x9F4D, 0x6AFA, 0x9F51, 0x6AFB, 0x9F4E, 0x6B04, 0x9793, 0x6B05, 0x9F4F, 0x6B0A, 0x9EDC, 0x6B12, 0x9F52, 0x6B16, 0x9F53, 0x6B1D, 0x8954, 0x6B1F, 0x9F55, 0x6B20, 0x8C87, 0x6B21, 0x8E9F, 0x6B23, 0x8BD3, 0x6B27, 0x89A2, 0x6B32, 0x977E, 0x6B37, 0x9F57, 0x6B38, 0x9F56, 0x6B39, 0x9F59, 0x6B3A, 0x8B5C, 0x6B3D, 0x8BD4, 0x6B3E, 0x8ABC, 0x6B43, 0x9F5C, 0x6B47, 0x9F5B, 0x6B49, 0x9F5D, 0x6B4C, 0x89CC, 0x6B4E, 0x9256, 0x6B50, 0x9F5E, 0x6B53, 0x8ABD, 0x6B54, 0x9F60, 0x6B59, 0x9F5F, 0x6B5B, 0x9F61, 0x6B5F, 0x9F62, 0x6B61, 0x9F63, 0x6B62, 0x8E7E, 0x6B63, 0x90B3, 0x6B64, 0x8D9F, 0x6B66, 0x9590, 0x6B69, 0x95E0, 0x6B6A, 0x9863, 0x6B6F, 0x8E95, 0x6B73, 0x8DCE, 0x6B74, 0x97F0, 0x6B78, 0x9F64, 0x6B79, 0x9F65, 0x6B7B, 0x8E80, 0x6B7F, 0x9F66, 0x6B80, 0x9F67, 0x6B83, 0x9F69, 0x6B84, 0x9F68, 0x6B86, 0x9677, 0x6B89, 0x8F7D, 0x6B8A, 0x8EEA, 0x6B8B, 0x8E63, 0x6B8D, 0x9F6A, 0x6B95, 0x9F6C, 0x6B96, 0x9042, 0x6B98, 0x9F6B, 0x6B9E, 0x9F6D, 0x6BA4, 0x9F6E, 0x6BAA, 0x9F6F, 0x6BAB, 0x9F70, 0x6BAF, 0x9F71, 0x6BB1, 0x9F73, 0x6BB2, 0x9F72, 0x6BB3, 0x9F74, 0x6BB4, 0x89A3, 0x6BB5, 0x9269, 0x6BB7, 0x9F75, 0x6BBA, 0x8E45, 0x6BBB, 0x8A6B, 0x6BBC, 0x9F76, 0x6BBF, 0x9361, 0x6BC0, 0x9ACA, 0x6BC5, 0x8B42, 0x6BC6, 0x9F77, 0x6BCB, 0x9F78, 0x6BCD, 0x95EA, 0x6BCE, 0x9688, 0x6BD2, 0x93C5, 0x6BD3, 0x9F79, 0x6BD4, 0x94E4, 0x6BD6, 0xFAF4, 0x6BD8, 0x94F9, 0x6BDB, 0x96D1, 0x6BDF, 0x9F7A, 0x6BEB, 0x9F7C, 0x6BEC, 0x9F7B, 0x6BEF, 0x9F7E, 0x6BF3, 0x9F7D, 0x6C08, 0x9F81, 0x6C0F, 0x8E81, 0x6C11, 0x96AF, 0x6C13, 0x9F82, 0x6C14, 0x9F83, 0x6C17, 0x8B43, 0x6C1B, 0x9F84, 0x6C23, 0x9F86, 0x6C24, 0x9F85, 0x6C34, 0x9085, 0x6C37, 0x9558, 0x6C38, 0x8969, 0x6C3E, 0x94C3, 0x6C3F, 0xFAF5, 0x6C40, 0x92F3, 0x6C41, 0x8F60, 0x6C42, 0x8B81, 0x6C4E, 0x94C4, 0x6C50, 0x8EAC, 0x6C55, 0x9F88, 0x6C57, 0x8ABE, 0x6C5A, 0x8998, 0x6C5C, 0xFAF6, 0x6C5D, 0x93F0, 0x6C5E, 0x9F87, 0x6C5F, 0x8D5D, 0x6C60, 0x9272, 0x6C62, 0x9F89, 0x6C68, 0x9F91, 0x6C6A, 0x9F8A, 0x6C6F, 0xFAF8, 0x6C70, 0x91BF, 0x6C72, 0x8B82, 0x6C73, 0x9F92, 0x6C7A, 0x8C88, 0x6C7D, 0x8B44, 0x6C7E, 0x9F90, 0x6C81, 0x9F8E, 0x6C82, 0x9F8B, 0x6C83, 0x9780, 0x6C86, 0xFAF7, 0x6C88, 0x92BE, 0x6C8C, 0x93D7, 0x6C8D, 0x9F8C, 0x6C90, 0x9F94, 0x6C92, 0x9F93, 0x6C93, 0x8C42, 0x6C96, 0x89AB, 0x6C99, 0x8DB9, 0x6C9A, 0x9F8D, 0x6C9B, 0x9F8F, 0x6CA1, 0x9676, 0x6CA2, 0x91F2, 0x6CAB, 0x9697, 0x6CAE, 0x9F9C, 0x6CB1, 0x9F9D, 0x6CB3, 0x89CD, 0x6CB8, 0x95A6, 0x6CB9, 0x96FB, 0x6CBA, 0x9F9F, 0x6CBB, 0x8EA1, 0x6CBC, 0x8FC0, 0x6CBD, 0x9F98, 0x6CBE, 0x9F9E, 0x6CBF, 0x8988, 0x6CC1, 0x8BB5, 0x6CC4, 0x9F95, 0x6CC5, 0x9F9A, 0x6CC9, 0x90F2, 0x6CCA, 0x9491, 0x6CCC, 0x94E5, 0x6CD3, 0x9F97, 0x6CD5, 0x9640, 0x6CD7, 0x9F99, 0x6CD9, 0x9FA2, 0x6CDA, 0xFAF9, 0x6CDB, 0x9FA0, 0x6CDD, 0x9F9B, 0x6CE1, 0x9641, 0x6CE2, 0x9467, 0x6CE3, 0x8B83, 0x6CE5, 0x9344, 0x6CE8, 0x928D, 0x6CEA, 0x9FA3, 0x6CEF, 0x9FA1, 0x6CF0, 0x91D7, 0x6CF1, 0x9F96, 0x6CF3, 0x896A, 0x6D04, 0xFAFA, 0x6D0B, 0x976D, 0x6D0C, 0x9FAE, 0x6D12, 0x9FAD, 0x6D17, 0x90F4, 0x6D19, 0x9FAA, 0x6D1B, 0x978C, 0x6D1E, 0x93B4, 0x6D1F, 0x9FA4, 0x6D25, 0x92C3, 0x6D29, 0x896B, 0x6D2A, 0x8D5E, 0x6D2B, 0x9FA7, 0x6D32, 0x8F46, 0x6D33, 0x9FAC, 0x6D35, 0x9FAB, 0x6D36, 0x9FA6, 0x6D38, 0x9FA9, 0x6D3B, 0x8A88, 0x6D3D, 0x9FA8, 0x6D3E, 0x9468, 0x6D41, 0x97AC, 0x6D44, 0x8FF2, 0x6D45, 0x90F3, 0x6D59, 0x9FB4, 0x6D5A, 0x9FB2, 0x6D5C, 0x956C, 0x6D63, 0x9FAF, 0x6D64, 0x9FB1, 0x6D66, 0x8959, 0x6D69, 0x8D5F, 0x6D6A, 0x9851, 0x6D6C, 0x8A5C, 0x6D6E, 0x9582, 0x6D6F, 0xFAFC, 0x6D74, 0x9781, 0x6D77, 0x8A43, 0x6D78, 0x905A, 0x6D79, 0x9FB3, 0x6D85, 0x9FB8, 0x6D87, 0xFAFB, 0x6D88, 0x8FC1, 0x6D8C, 0x974F, 0x6D8E, 0x9FB5, 0x6D93, 0x9FB0, 0x6D95, 0x9FB6, 0x6D96, 0xFB40, 0x6D99, 0x97DC, 0x6D9B, 0x9393, 0x6D9C, 0x93C0, 0x6DAC, 0xFB41, 0x6DAF, 0x8A55, 0x6DB2, 0x8974, 0x6DB5, 0x9FBC, 0x6DB8, 0x9FBF, 0x6DBC, 0x97C1, 0x6DC0, 0x9784, 0x6DC5, 0x9FC6, 0x6DC6, 0x9FC0, 0x6DC7, 0x9FBD, 0x6DCB, 0x97D2, 0x6DCC, 0x9FC3, 0x6DCF, 0xFB42, 0x6DD1, 0x8F69, 0x6DD2, 0x9FC5, 0x6DD5, 0x9FCA, 0x6DD8, 0x9391, 0x6DD9, 0x9FC8, 0x6DDE, 0x9FC2, 0x6DE1, 0x9257, 0x6DE4, 0x9FC9, 0x6DE6, 0x9FBE, 0x6DE8, 0x9FC4, 0x6DEA, 0x9FCB, 0x6DEB, 0x88FA, 0x6DEC, 0x9FC1, 0x6DEE, 0x9FCC, 0x6DF1, 0x905B, 0x6DF2, 0xFB44, 0x6DF3, 0x8F7E, 0x6DF5, 0x95A3, 0x6DF7, 0x8DAC, 0x6DF8, 0xFB43, 0x6DF9, 0x9FB9, 0x6DFA, 0x9FC7, 0x6DFB, 0x9359, 0x6DFC, 0xFB45, 0x6E05, 0x90B4, 0x6E07, 0x8A89, 0x6E08, 0x8DCF, 0x6E09, 0x8FC2, 0x6E0A, 0x9FBB, 0x6E0B, 0x8F61, 0x6E13, 0x8C6B, 0x6E15, 0x9FBA, 0x6E19, 0x9FD0, 0x6E1A, 0x8F8D, 0x6E1B, 0x8CB8, 0x6E1D, 0x9FDF, 0x6E1F, 0x9FD9, 0x6E20, 0x8B94, 0x6E21, 0x936E, 0x6E23, 0x9FD4, 0x6E24, 0x9FDD, 0x6E25, 0x88AD, 0x6E26, 0x8951, 0x6E27, 0xFB48, 0x6E29, 0x89B7, 0x6E2B, 0x9FD6, 0x6E2C, 0x91AA, 0x6E2D, 0x9FCD, 0x6E2E, 0x9FCF, 0x6E2F, 0x8D60, 0x6E38, 0x9FE0, 0x6E39, 0xFB46, 0x6E3A, 0x9FDB, 0x6E3C, 0xFB49, 0x6E3E, 0x9FD3, 0x6E43, 0x9FDA, 0x6E4A, 0x96A9, 0x6E4D, 0x9FD8, 0x6E4E, 0x9FDC, 0x6E56, 0x8CCE, 0x6E58, 0x8FC3, 0x6E5B, 0x9258, 0x6E5C, 0xFB47, 0x6E5F, 0x9FD2, 0x6E67, 0x974E, 0x6E6B, 0x9FD5, 0x6E6E, 0x9FCE, 0x6E6F, 0x9392, 0x6E72, 0x9FD1, 0x6E76, 0x9FD7, 0x6E7E, 0x9870, 0x6E7F, 0x8EBC, 0x6E80, 0x969E, 0x6E82, 0x9FE1, 0x6E8C, 0x94AC, 0x6E8F, 0x9FED, 0x6E90, 0x8CB9, 0x6E96, 0x8F80, 0x6E98, 0x9FE3, 0x6E9C, 0x97AD, 0x6E9D, 0x8D61, 0x6E9F, 0x9FF0, 0x6EA2, 0x88EC, 0x6EA5, 0x9FEE, 0x6EAA, 0x9FE2, 0x6EAF, 0x9FE8, 0x6EB2, 0x9FEA, 0x6EB6, 0x976E, 0x6EB7, 0x9FE5, 0x6EBA, 0x934D, 0x6EBD, 0x9FE7, 0x6EBF, 0xFB4A, 0x6EC2, 0x9FEF, 0x6EC4, 0x9FE9, 0x6EC5, 0x96C5, 0x6EC9, 0x9FE4, 0x6ECB, 0x8EA0, 0x6ECC, 0x9FFC, 0x6ED1, 0x8A8A, 0x6ED3, 0x9FE6, 0x6ED4, 0x9FEB, 0x6ED5, 0x9FEC, 0x6EDD, 0x91EA, 0x6EDE, 0x91D8, 0x6EEC, 0x9FF4, 0x6EEF, 0x9FFA, 0x6EF2, 0x9FF8, 0x6EF4, 0x9348, 0x6EF7, 0xE042, 0x6EF8, 0x9FF5, 0x6EFE, 0x9FF6, 0x6EFF, 0x9FDE, 0x6F01, 0x8B99, 0x6F02, 0x9559, 0x6F06, 0x8EBD, 0x6F09, 0x8D97, 0x6F0F, 0x9852, 0x6F11, 0x9FF2, 0x6F13, 0xE041, 0x6F14, 0x8989, 0x6F15, 0x9186, 0x6F20, 0x9499, 0x6F22, 0x8ABF, 0x6F23, 0x97F8, 0x6F2B, 0x969F, 0x6F2C, 0x92D0, 0x6F31, 0x9FF9, 0x6F32, 0x9FFB, 0x6F38, 0x9151, 0x6F3E, 0xE040, 0x6F3F, 0x9FF7, 0x6F41, 0x9FF1, 0x6F45, 0x8AC1, 0x6F54, 0x8C89, 0x6F58, 0xE04E, 0x6F5B, 0xE049, 0x6F5C, 0x90F6, 0x6F5F, 0x8A83, 0x6F64, 0x8F81, 0x6F66, 0xE052, 0x6F6D, 0xE04B, 0x6F6E, 0x92AA, 0x6F6F, 0xE048, 0x6F70, 0x92D7, 0x6F74, 0xE06B, 0x6F78, 0xE045, 0x6F7A, 0xE044, 0x6F7C, 0xE04D, 0x6F80, 0xE047, 0x6F81, 0xE046, 0x6F82, 0xE04C, 0x6F84, 0x909F, 0x6F86, 0xE043, 0x6F88, 0xFB4B, 0x6F8E, 0xE04F, 0x6F91, 0xE050, 0x6F97, 0x8AC0, 0x6FA1, 0xE055, 0x6FA3, 0xE054, 0x6FA4, 0xE056, 0x6FAA, 0xE059, 0x6FB1, 0x9362, 0x6FB3, 0xE053, 0x6FB5, 0xFB4C, 0x6FB9, 0xE057, 0x6FC0, 0x8C83, 0x6FC1, 0x91F7, 0x6FC2, 0xE051, 0x6FC3, 0x945A, 0x6FC6, 0xE058, 0x6FD4, 0xE05D, 0x6FD5, 0xE05B, 0x6FD8, 0xE05E, 0x6FDB, 0xE061, 0x6FDF, 0xE05A, 0x6FE0, 0x8D8A, 0x6FE1, 0x9447, 0x6FE4, 0x9FB7, 0x6FEB, 0x9794, 0x6FEC, 0xE05C, 0x6FEE, 0xE060, 0x6FEF, 0x91F3, 0x6FF1, 0xE05F, 0x6FF3, 0xE04A, 0x6FF5, 0xFB4D, 0x6FF6, 0xE889, 0x6FFA, 0xE064, 0x6FFE, 0xE068, 0x7001, 0xE066, 0x7005, 0xFB4E, 0x7007, 0xFB4F, 0x7009, 0xE062, 0x700B, 0xE063, 0x700F, 0xE067, 0x7011, 0xE065, 0x7015, 0x956D, 0x7018, 0xE06D, 0x701A, 0xE06A, 0x701B, 0xE069, 0x701D, 0xE06C, 0x701E, 0x93D2, 0x701F, 0xE06E, 0x7026, 0x9295, 0x7027, 0x91EB, 0x7028, 0xFB50, 0x702C, 0x90A3, 0x7030, 0xE06F, 0x7032, 0xE071, 0x703E, 0xE070, 0x704C, 0x9FF3, 0x7051, 0xE072, 0x7058, 0x93E5, 0x7063, 0xE073, 0x706B, 0x89CE, 0x706F, 0x9394, 0x7070, 0x8A44, 0x7078, 0x8B84, 0x707C, 0x8EDC, 0x707D, 0x8DD0, 0x7085, 0xFB51, 0x7089, 0x9846, 0x708A, 0x9086, 0x708E, 0x898A, 0x7092, 0xE075, 0x7099, 0xE074, 0x70AB, 0xFB52, 0x70AC, 0xE078, 0x70AD, 0x9259, 0x70AE, 0xE07B, 0x70AF, 0xE076, 0x70B3, 0xE07A, 0x70B8, 0xE079, 0x70B9, 0x935F, 0x70BA, 0x88D7, 0x70BB, 0xFA62, 0x70C8, 0x97F3, 0x70CB, 0xE07D, 0x70CF, 0x8947, 0x70D9, 0xE080, 0x70DD, 0xE07E, 0x70DF, 0xE07C, 0x70F1, 0xE077, 0x70F9, 0x9642, 0x70FD, 0xE082, 0x7104, 0xFB54, 0x7109, 0xE081, 0x710F, 0xFB53, 0x7114, 0x898B, 0x7119, 0xE084, 0x711A, 0x95B0, 0x711C, 0xE083, 0x7121, 0x96B3, 0x7126, 0x8FC5, 0x7136, 0x9152, 0x713C, 0x8FC4, 0x7146, 0xFB56, 0x7147, 0xFB57, 0x7149, 0x97F9, 0x714C, 0xE08A, 0x714E, 0x90F7, 0x7155, 0xE086, 0x7156, 0xE08B, 0x7159, 0x898C, 0x715C, 0xFB55, 0x7162, 0xE089, 0x7164, 0x9481, 0x7165, 0xE085, 0x7166, 0xE088, 0x7167, 0x8FC6, 0x7169, 0x94CF, 0x716C, 0xE08C, 0x716E, 0x8ECF, 0x717D, 0x90F8, 0x7184, 0xE08F, 0x7188, 0xE087, 0x718A, 0x8C46, 0x718F, 0xE08D, 0x7194, 0x976F, 0x7195, 0xE090, 0x7199, 0xEAA4, 0x719F, 0x8F6E, 0x71A8, 0xE091, 0x71AC, 0xE092, 0x71B1, 0x944D, 0x71B9, 0xE094, 0x71BE, 0xE095, 0x71C1, 0xFB59, 0x71C3, 0x9452, 0x71C8, 0x9395, 0x71C9, 0xE097, 0x71CE, 0xE099, 0x71D0, 0x97D3, 0x71D2, 0xE096, 0x71D4, 0xE098, 0x71D5, 0x898D, 0x71D7, 0xE093, 0x71DF, 0x9A7A, 0x71E0, 0xE09A, 0x71E5, 0x9187, 0x71E6, 0x8E57, 0x71E7, 0xE09C, 0x71EC, 0xE09B, 0x71ED, 0x9043, 0x71EE, 0x99D7, 0x71F5, 0xE09D, 0x71F9, 0xE09F, 0x71FB, 0xE08E, 0x71FC, 0xE09E, 0x71FE, 0xFB5A, 0x71FF, 0xE0A0, 0x7206, 0x949A, 0x720D, 0xE0A1, 0x7210, 0xE0A2, 0x721B, 0xE0A3, 0x7228, 0xE0A4, 0x722A, 0x92DC, 0x722C, 0xE0A6, 0x722D, 0xE0A5, 0x7230, 0xE0A7, 0x7232, 0xE0A8, 0x7235, 0x8EDD, 0x7236, 0x9583, 0x723A, 0x96EA, 0x723B, 0xE0A9, 0x723C, 0xE0AA, 0x723D, 0x9175, 0x723E, 0x8EA2, 0x723F, 0xE0AB, 0x7240, 0xE0AC, 0x7246, 0xE0AD, 0x7247, 0x95D0, 0x7248, 0x94C5, 0x724B, 0xE0AE, 0x724C, 0x9476, 0x7252, 0x92AB, 0x7258, 0xE0AF, 0x7259, 0x89E5, 0x725B, 0x8B8D, 0x725D, 0x96C4, 0x725F, 0x96B4, 0x7261, 0x89B2, 0x7262, 0x9853, 0x7267, 0x9671, 0x7269, 0x95A8, 0x7272, 0x90B5, 0x7274, 0xE0B0, 0x7279, 0x93C1, 0x727D, 0x8CA1, 0x727E, 0xE0B1, 0x7280, 0x8DD2, 0x7281, 0xE0B3, 0x7282, 0xE0B2, 0x7287, 0xE0B4, 0x7292, 0xE0B5, 0x7296, 0xE0B6, 0x72A0, 0x8B5D, 0x72A2, 0xE0B7, 0x72A7, 0xE0B8, 0x72AC, 0x8CA2, 0x72AF, 0x94C6, 0x72B1, 0xFB5B, 0x72B2, 0xE0BA, 0x72B6, 0x8FF3, 0x72B9, 0xE0B9, 0x72BE, 0xFB5C, 0x72C2, 0x8BB6, 0x72C3, 0xE0BB, 0x72C4, 0xE0BD, 0x72C6, 0xE0BC, 0x72CE, 0xE0BE, 0x72D0, 0x8CCF, 0x72D2, 0xE0BF, 0x72D7, 0x8BE7, 0x72D9, 0x915F, 0x72DB, 0x8D9D, 0x72E0, 0xE0C1, 0x72E1, 0xE0C2, 0x72E2, 0xE0C0, 0x72E9, 0x8EEB, 0x72EC, 0x93C6, 0x72ED, 0x8BB7, 0x72F7, 0xE0C4, 0x72F8, 0x924B, 0x72F9, 0xE0C3, 0x72FC, 0x9854, 0x72FD, 0x9482, 0x730A, 0xE0C7, 0x7316, 0xE0C9, 0x7317, 0xE0C6, 0x731B, 0x96D2, 0x731C, 0xE0C8, 0x731D, 0xE0CA, 0x731F, 0x97C2, 0x7324, 0xFB5D, 0x7325, 0xE0CE, 0x7329, 0xE0CD, 0x732A, 0x9296, 0x732B, 0x944C, 0x732E, 0x8CA3, 0x732F, 0xE0CC, 0x7334, 0xE0CB, 0x7336, 0x9750, 0x7337, 0x9751, 0x733E, 0xE0CF, 0x733F, 0x898E, 0x7344, 0x8D96, 0x7345, 0x8E82, 0x734E, 0xE0D0, 0x734F, 0xE0D1, 0x7357, 0xE0D3, 0x7363, 0x8F62, 0x7368, 0xE0D5, 0x736A, 0xE0D4, 0x7370, 0xE0D6, 0x7372, 0x8A6C, 0x7375, 0xE0D8, 0x7377, 0xFB5F, 0x7378, 0xE0D7, 0x737A, 0xE0DA, 0x737B, 0xE0D9, 0x7384, 0x8CBA, 0x7387, 0x97A6, 0x7389, 0x8BCA, 0x738B, 0x89A4, 0x7396, 0x8BE8, 0x73A9, 0x8ADF, 0x73B2, 0x97E6, 0x73B3, 0xE0DC, 0x73BB, 0xE0DE, 0x73BD, 0xFB60, 0x73C0, 0xE0DF, 0x73C2, 0x89CF, 0x73C8, 0xE0DB, 0x73C9, 0xFB61, 0x73CA, 0x8E58, 0x73CD, 0x92BF, 0x73CE, 0xE0DD, 0x73D2, 0xFB64, 0x73D6, 0xFB62, 0x73DE, 0xE0E2, 0x73E0, 0x8EEC, 0x73E3, 0xFB63, 0x73E5, 0xE0E0, 0x73EA, 0x8C5D, 0x73ED, 0x94C7, 0x73EE, 0xE0E1, 0x73F1, 0xE0FC, 0x73F5, 0xFB66, 0x73F8, 0xE0E7, 0x73FE, 0x8CBB, 0x7403, 0x8B85, 0x7405, 0xE0E4, 0x7406, 0x979D, 0x7407, 0xFB65, 0x7409, 0x97AE, 0x7422, 0x91F4, 0x7425, 0xE0E6, 0x7426, 0xFB67, 0x7429, 0xFB69, 0x742A, 0xFB68, 0x742E, 0xFB6A, 0x7432, 0xE0E8, 0x7433, 0x97D4, 0x7434, 0x8BD5, 0x7435, 0x94FA, 0x7436, 0x9469, 0x743A, 0xE0E9, 0x743F, 0xE0EB, 0x7441, 0xE0EE, 0x7455, 0xE0EA, 0x7459, 0xE0ED, 0x745A, 0x8CE8, 0x745B, 0x896C, 0x745C, 0xE0EF, 0x745E, 0x9090, 0x745F, 0xE0EC, 0x7460, 0x97DA, 0x7462, 0xFB6B, 0x7463, 0xE0F2, 0x7464, 0xEAA2, 0x7469, 0xE0F0, 0x746A, 0xE0F3, 0x746F, 0xE0E5, 0x7470, 0xE0F1, 0x7473, 0x8DBA, 0x7476, 0xE0F4, 0x747E, 0xE0F5, 0x7483, 0x979E, 0x7489, 0xFB6C, 0x748B, 0xE0F6, 0x749E, 0xE0F7, 0x749F, 0xFB6D, 0x74A2, 0xE0E3, 0x74A7, 0xE0F8, 0x74B0, 0x8AC2, 0x74BD, 0x8EA3, 0x74CA, 0xE0F9, 0x74CF, 0xE0FA, 0x74D4, 0xE0FB, 0x74DC, 0x895A, 0x74E0, 0xE140, 0x74E2, 0x955A, 0x74E3, 0xE141, 0x74E6, 0x8AA2, 0x74E7, 0xE142, 0x74E9, 0xE143, 0x74EE, 0xE144, 0x74F0, 0xE146, 0x74F1, 0xE147, 0x74F2, 0xE145, 0x74F6, 0x9572, 0x74F7, 0xE149, 0x74F8, 0xE148, 0x7501, 0xFB6E, 0x7503, 0xE14B, 0x7504, 0xE14A, 0x7505, 0xE14C, 0x750C, 0xE14D, 0x750D, 0xE14F, 0x750E, 0xE14E, 0x7511, 0x8D99, 0x7513, 0xE151, 0x7515, 0xE150, 0x7518, 0x8AC3, 0x751A, 0x9072, 0x751C, 0x935B, 0x751E, 0xE152, 0x751F, 0x90B6, 0x7523, 0x8E59, 0x7525, 0x8999, 0x7526, 0xE153, 0x7528, 0x9770, 0x752B, 0x95E1, 0x752C, 0xE154, 0x752F, 0xFAA8, 0x7530, 0x9363, 0x7531, 0x9752, 0x7532, 0x8D62, 0x7533, 0x905C, 0x7537, 0x926A, 0x7538, 0x99B2, 0x753A, 0x92AC, 0x753B, 0x89E6, 0x753C, 0xE155, 0x7544, 0xE156, 0x7546, 0xE15B, 0x7549, 0xE159, 0x754A, 0xE158, 0x754B, 0x9DC0, 0x754C, 0x8A45, 0x754D, 0xE157, 0x754F, 0x88D8, 0x7551, 0x94A8, 0x7554, 0x94C8, 0x7559, 0x97AF, 0x755A, 0xE15C, 0x755B, 0xE15A, 0x755C, 0x927B, 0x755D, 0x90A4, 0x7560, 0x94A9, 0x7562, 0x954C, 0x7564, 0xE15E, 0x7565, 0x97AA, 0x7566, 0x8C6C, 0x7567, 0xE15F, 0x7569, 0xE15D, 0x756A, 0x94D4, 0x756B, 0xE160, 0x756D, 0xE161, 0x756F, 0xFB6F, 0x7570, 0x88D9, 0x7573, 0x8FF4, 0x7574, 0xE166, 0x7576, 0xE163, 0x7577, 0x93EB, 0x7578, 0xE162, 0x757F, 0x8B45, 0x7582, 0xE169, 0x7586, 0xE164, 0x7587, 0xE165, 0x7589, 0xE168, 0x758A, 0xE167, 0x758B, 0x9544, 0x758E, 0x9161, 0x758F, 0x9160, 0x7591, 0x8B5E, 0x7594, 0xE16A, 0x759A, 0xE16B, 0x759D, 0xE16C, 0x75A3, 0xE16E, 0x75A5, 0xE16D, 0x75AB, 0x8975, 0x75B1, 0xE176, 0x75B2, 0x94E6, 0x75B3, 0xE170, 0x75B5, 0xE172, 0x75B8, 0xE174, 0x75B9, 0x905D, 0x75BC, 0xE175, 0x75BD, 0xE173, 0x75BE, 0x8EBE, 0x75C2, 0xE16F, 0x75C3, 0xE171, 0x75C5, 0x9561, 0x75C7, 0x8FC7, 0x75CA, 0xE178, 0x75CD, 0xE177, 0x75D2, 0xE179, 0x75D4, 0x8EA4, 0x75D5, 0x8DAD, 0x75D8, 0x9397, 0x75D9, 0xE17A, 0x75DB, 0x92C9, 0x75DE, 0xE17C, 0x75E2, 0x979F, 0x75E3, 0xE17B, 0x75E9, 0x9189, 0x75F0, 0xE182, 0x75F2, 0xE184, 0x75F3, 0xE185, 0x75F4, 0x9273, 0x75FA, 0xE183, 0x75FC, 0xE180, 0x75FE, 0xE17D, 0x75FF, 0xE17E, 0x7601, 0xE181, 0x7609, 0xE188, 0x760B, 0xE186, 0x760D, 0xE187, 0x761F, 0xE189, 0x7620, 0xE18B, 0x7621, 0xE18C, 0x7622, 0xE18D, 0x7624, 0xE18E, 0x7627, 0xE18A, 0x7630, 0xE190, 0x7634, 0xE18F, 0x763B, 0xE191, 0x7642, 0x97C3, 0x7646, 0xE194, 0x7647, 0xE192, 0x7648, 0xE193, 0x764C, 0x8AE0, 0x7652, 0x96FC, 0x7656, 0x95C8, 0x7658, 0xE196, 0x765C, 0xE195, 0x7661, 0xE197, 0x7662, 0xE198, 0x7667, 0xE19C, 0x7668, 0xE199, 0x7669, 0xE19A, 0x766A, 0xE19B, 0x766C, 0xE19D, 0x7670, 0xE19E, 0x7672, 0xE19F, 0x7676, 0xE1A0, 0x7678, 0xE1A1, 0x767A, 0x94AD, 0x767B, 0x936F, 0x767C, 0xE1A2, 0x767D, 0x9492, 0x767E, 0x9553, 0x7680, 0xE1A3, 0x7682, 0xFB70, 0x7683, 0xE1A4, 0x7684, 0x9349, 0x7686, 0x8A46, 0x7687, 0x8D63, 0x7688, 0xE1A5, 0x768B, 0xE1A6, 0x768E, 0xE1A7, 0x7690, 0x8E48, 0x7693, 0xE1A9, 0x7696, 0xE1A8, 0x7699, 0xE1AA, 0x769A, 0xE1AB, 0x769B, 0xFB73, 0x769C, 0xFB71, 0x769E, 0xFB72, 0x76A6, 0xFB74, 0x76AE, 0x94E7, 0x76B0, 0xE1AC, 0x76B4, 0xE1AD, 0x76B7, 0xEA89, 0x76B8, 0xE1AE, 0x76B9, 0xE1AF, 0x76BA, 0xE1B0, 0x76BF, 0x8E4D, 0x76C2, 0xE1B1, 0x76C3, 0x9475, 0x76C6, 0x967E, 0x76C8, 0x896D, 0x76CA, 0x8976, 0x76CD, 0xE1B2, 0x76D2, 0xE1B4, 0x76D6, 0xE1B3, 0x76D7, 0x9390, 0x76DB, 0x90B7, 0x76DC, 0x9F58, 0x76DE, 0xE1B5, 0x76DF, 0x96BF, 0x76E1, 0xE1B6, 0x76E3, 0x8AC4, 0x76E4, 0x94D5, 0x76E5, 0xE1B7, 0x76E7, 0xE1B8, 0x76EA, 0xE1B9, 0x76EE, 0x96DA, 0x76F2, 0x96D3, 0x76F4, 0x92BC, 0x76F8, 0x918A, 0x76FB, 0xE1BB, 0x76FE, 0x8F82, 0x7701, 0x8FC8, 0x7704, 0xE1BE, 0x7707, 0xE1BD, 0x7708, 0xE1BC, 0x7709, 0x94FB, 0x770B, 0x8AC5, 0x770C, 0x8CA7, 0x771B, 0xE1C4, 0x771E, 0xE1C1, 0x771F, 0x905E, 0x7720, 0x96B0, 0x7724, 0xE1C0, 0x7725, 0xE1C2, 0x7726, 0xE1C3, 0x7729, 0xE1BF, 0x7737, 0xE1C5, 0x7738, 0xE1C6, 0x773A, 0x92AD, 0x773C, 0x8AE1, 0x7740, 0x9285, 0x7746, 0xFB76, 0x7747, 0xE1C7, 0x775A, 0xE1C8, 0x775B, 0xE1CB, 0x7761, 0x9087, 0x7763, 0x93C2, 0x7765, 0xE1CC, 0x7766, 0x9672, 0x7768, 0xE1C9, 0x776B, 0xE1CA, 0x7779, 0xE1CF, 0x777E, 0xE1CE, 0x777F, 0xE1CD, 0x778B, 0xE1D1, 0x778E, 0xE1D0, 0x7791, 0xE1D2, 0x779E, 0xE1D4, 0x77A0, 0xE1D3, 0x77A5, 0x95CB, 0x77AC, 0x8F75, 0x77AD, 0x97C4, 0x77B0, 0xE1D5, 0x77B3, 0x93B5, 0x77B6, 0xE1D6, 0x77B9, 0xE1D7, 0x77BB, 0xE1DB, 0x77BC, 0xE1D9, 0x77BD, 0xE1DA, 0x77BF, 0xE1D8, 0x77C7, 0xE1DC, 0x77CD, 0xE1DD, 0x77D7, 0xE1DE, 0x77DA, 0xE1DF, 0x77DB, 0x96B5, 0x77DC, 0xE1E0, 0x77E2, 0x96EE, 0x77E3, 0xE1E1, 0x77E5, 0x926D, 0x77E7, 0x948A, 0x77E9, 0x8BE9, 0x77ED, 0x925A, 0x77EE, 0xE1E2, 0x77EF, 0x8BB8, 0x77F3, 0x90CE, 0x77FC, 0xE1E3, 0x7802, 0x8DBB, 0x780C, 0xE1E4, 0x7812, 0xE1E5, 0x7814, 0x8CA4, 0x7815, 0x8DD3, 0x7820, 0xE1E7, 0x7821, 0xFB78, 0x7825, 0x9375, 0x7826, 0x8DD4, 0x7827, 0x8B6D, 0x7832, 0x9643, 0x7834, 0x946A, 0x783A, 0x9376, 0x783F, 0x8D7B, 0x7845, 0xE1E9, 0x784E, 0xFB79, 0x785D, 0x8FC9, 0x7864, 0xFB7A, 0x786B, 0x97B0, 0x786C, 0x8D64, 0x786F, 0x8CA5, 0x7872, 0x94A1, 0x7874, 0xE1EB, 0x787A, 0xFB7B, 0x787C, 0xE1ED, 0x7881, 0x8CE9, 0x7886, 0xE1EC, 0x7887, 0x92F4, 0x788C, 0xE1EF, 0x788D, 0x8A56, 0x788E, 0xE1EA, 0x7891, 0x94E8, 0x7893, 0x894F, 0x7895, 0x8DEA, 0x7897, 0x9871, 0x789A, 0xE1EE, 0x78A3, 0xE1F0, 0x78A7, 0x95C9, 0x78A9, 0x90D7, 0x78AA, 0xE1F2, 0x78AF, 0xE1F3, 0x78B5, 0xE1F1, 0x78BA, 0x8A6D, 0x78BC, 0xE1F9, 0x78BE, 0xE1F8, 0x78C1, 0x8EA5, 0x78C5, 0xE1FA, 0x78C6, 0xE1F5, 0x78CA, 0xE1FB, 0x78CB, 0xE1F6, 0x78D0, 0x94D6, 0x78D1, 0xE1F4, 0x78D4, 0xE1F7, 0x78DA, 0xE241, 0x78E7, 0xE240, 0x78E8, 0x9681, 0x78EC, 0xE1FC, 0x78EF, 0x88E9, 0x78F4, 0xE243, 0x78FD, 0xE242, 0x7901, 0x8FCA, 0x7907, 0xE244, 0x790E, 0x9162, 0x7911, 0xE246, 0x7912, 0xE245, 0x7919, 0xE247, 0x7926, 0xE1E6, 0x792A, 0xE1E8, 0x792B, 0xE249, 0x792C, 0xE248, 0x7930, 0xFB7C, 0x793A, 0x8EA6, 0x793C, 0x97E7, 0x793E, 0x8ED0, 0x7940, 0xE24A, 0x7941, 0x8C56, 0x7947, 0x8B5F, 0x7948, 0x8B46, 0x7949, 0x8E83, 0x7950, 0x9753, 0x7953, 0xE250, 0x7955, 0xE24F, 0x7956, 0x9163, 0x7957, 0xE24C, 0x795A, 0xE24E, 0x795D, 0x8F6A, 0x795E, 0x905F, 0x795F, 0xE24D, 0x7960, 0xE24B, 0x7962, 0x9449, 0x7965, 0x8FCB, 0x7968, 0x955B, 0x796D, 0x8DD5, 0x7977, 0x9398, 0x797A, 0xE251, 0x797F, 0xE252, 0x7980, 0xE268, 0x7981, 0x8BD6, 0x7984, 0x985C, 0x7985, 0x9154, 0x798A, 0xE253, 0x798D, 0x89D0, 0x798E, 0x92F5, 0x798F, 0x959F, 0x7994, 0xFB81, 0x799B, 0xFB83, 0x799D, 0xE254, 0x79A6, 0x8B9A, 0x79A7, 0xE255, 0x79AA, 0xE257, 0x79AE, 0xE258, 0x79B0, 0x9448, 0x79B3, 0xE259, 0x79B9, 0xE25A, 0x79BA, 0xE25B, 0x79BD, 0x8BD7, 0x79BE, 0x89D1, 0x79BF, 0x93C3, 0x79C0, 0x8F47, 0x79C1, 0x8E84, 0x79C9, 0xE25C, 0x79CB, 0x8F48, 0x79D1, 0x89C8, 0x79D2, 0x9562, 0x79D5, 0xE25D, 0x79D8, 0x94E9, 0x79DF, 0x9164, 0x79E1, 0xE260, 0x79E3, 0xE261, 0x79E4, 0x9489, 0x79E6, 0x9060, 0x79E7, 0xE25E, 0x79E9, 0x9281, 0x79EC, 0xE25F, 0x79F0, 0x8FCC, 0x79FB, 0x88DA, 0x7A00, 0x8B48, 0x7A08, 0xE262, 0x7A0B, 0x92F6, 0x7A0D, 0xE263, 0x7A0E, 0x90C5, 0x7A14, 0x96AB, 0x7A17, 0x9542, 0x7A18, 0xE264, 0x7A19, 0xE265, 0x7A1A, 0x9274, 0x7A1C, 0x97C5, 0x7A1F, 0xE267, 0x7A20, 0xE266, 0x7A2E, 0x8EED, 0x7A31, 0xE269, 0x7A32, 0x88EE, 0x7A37, 0xE26C, 0x7A3B, 0xE26A, 0x7A3C, 0x89D2, 0x7A3D, 0x8C6D, 0x7A3E, 0xE26B, 0x7A3F, 0x8D65, 0x7A40, 0x8D92, 0x7A42, 0x95E4, 0x7A43, 0xE26D, 0x7A46, 0x9673, 0x7A49, 0xE26F, 0x7A4D, 0x90CF, 0x7A4E, 0x896E, 0x7A4F, 0x89B8, 0x7A50, 0x88AA, 0x7A57, 0xE26E, 0x7A61, 0xE270, 0x7A62, 0xE271, 0x7A63, 0x8FF5, 0x7A69, 0xE272, 0x7A6B, 0x8A6E, 0x7A70, 0xE274, 0x7A74, 0x8C8A, 0x7A76, 0x8B86, 0x7A79, 0xE275, 0x7A7A, 0x8BF3, 0x7A7D, 0xE276, 0x7A7F, 0x90FA, 0x7A81, 0x93CB, 0x7A83, 0x90DE, 0x7A84, 0x8DF3, 0x7A88, 0xE277, 0x7A92, 0x9282, 0x7A93, 0x918B, 0x7A95, 0xE279, 0x7A96, 0xE27B, 0x7A97, 0xE278, 0x7A98, 0xE27A, 0x7A9F, 0x8C41, 0x7AA9, 0xE27C, 0x7AAA, 0x8C45, 0x7AAE, 0x8B87, 0x7AAF, 0x9771, 0x7AB0, 0xE27E, 0x7AB6, 0xE280, 0x7ABA, 0x894D, 0x7ABF, 0xE283, 0x7AC3, 0x8A96, 0x7AC4, 0xE282, 0x7AC5, 0xE281, 0x7AC7, 0xE285, 0x7AC8, 0xE27D, 0x7ACA, 0xE286, 0x7ACB, 0x97A7, 0x7ACD, 0xE287, 0x7ACF, 0xE288, 0x7AD1, 0xFB84, 0x7AD2, 0x9AF2, 0x7AD3, 0xE28A, 0x7AD5, 0xE289, 0x7AD9, 0xE28B, 0x7ADA, 0xE28C, 0x7ADC, 0x97B3, 0x7ADD, 0xE28D, 0x7ADF, 0xE8ED, 0x7AE0, 0x8FCD, 0x7AE1, 0xE28E, 0x7AE2, 0xE28F, 0x7AE3, 0x8F76, 0x7AE5, 0x93B6, 0x7AE6, 0xE290, 0x7AE7, 0xFB85, 0x7AEA, 0x9247, 0x7AEB, 0xFB87, 0x7AED, 0xE291, 0x7AEF, 0x925B, 0x7AF0, 0xE292, 0x7AF6, 0x8BA3, 0x7AF8, 0x995E, 0x7AF9, 0x927C, 0x7AFA, 0x8EB1, 0x7AFF, 0x8AC6, 0x7B02, 0xE293, 0x7B04, 0xE2A0, 0x7B06, 0xE296, 0x7B08, 0x8B88, 0x7B0A, 0xE295, 0x7B0B, 0xE2A2, 0x7B0F, 0xE294, 0x7B11, 0x8FCE, 0x7B18, 0xE298, 0x7B19, 0xE299, 0x7B1B, 0x934A, 0x7B1E, 0xE29A, 0x7B20, 0x8A7D, 0x7B25, 0x9079, 0x7B26, 0x9584, 0x7B28, 0xE29C, 0x7B2C, 0x91E6, 0x7B33, 0xE297, 0x7B35, 0xE29B, 0x7B36, 0xE29D, 0x7B39, 0x8DF9, 0x7B45, 0xE2A4, 0x7B46, 0x954D, 0x7B48, 0x94A4, 0x7B49, 0x9399, 0x7B4B, 0x8BD8, 0x7B4C, 0xE2A3, 0x7B4D, 0xE2A1, 0x7B4F, 0x94B3, 0x7B50, 0xE29E, 0x7B51, 0x927D, 0x7B52, 0x939B, 0x7B54, 0x939A, 0x7B56, 0x8DF4, 0x7B5D, 0xE2B6, 0x7B65, 0xE2A6, 0x7B67, 0xE2A8, 0x7B6C, 0xE2AB, 0x7B6E, 0xE2AC, 0x7B70, 0xE2A9, 0x7B71, 0xE2AA, 0x7B74, 0xE2A7, 0x7B75, 0xE2A5, 0x7B7A, 0xE29F, 0x7B86, 0x95CD, 0x7B87, 0x89D3, 0x7B8B, 0xE2B3, 0x7B8D, 0xE2B0, 0x7B8F, 0xE2B5, 0x7B92, 0xE2B4, 0x7B94, 0x9493, 0x7B95, 0x96A5, 0x7B97, 0x8E5A, 0x7B98, 0xE2AE, 0x7B99, 0xE2B7, 0x7B9A, 0xE2B2, 0x7B9C, 0xE2B1, 0x7B9D, 0xE2AD, 0x7B9E, 0xFB88, 0x7B9F, 0xE2AF, 0x7BA1, 0x8AC7, 0x7BAA, 0x925C, 0x7BAD, 0x90FB, 0x7BB1, 0x94A0, 0x7BB4, 0xE2BC, 0x7BB8, 0x94A2, 0x7BC0, 0x90DF, 0x7BC1, 0xE2B9, 0x7BC4, 0x94CD, 0x7BC6, 0xE2BD, 0x7BC7, 0x95D1, 0x7BC9, 0x927A, 0x7BCB, 0xE2B8, 0x7BCC, 0xE2BA, 0x7BCF, 0xE2BB, 0x7BDD, 0xE2BE, 0x7BE0, 0x8EC2, 0x7BE4, 0x93C4, 0x7BE5, 0xE2C3, 0x7BE6, 0xE2C2, 0x7BE9, 0xE2BF, 0x7BED, 0x9855, 0x7BF3, 0xE2C8, 0x7BF6, 0xE2CC, 0x7BF7, 0xE2C9, 0x7C00, 0xE2C5, 0x7C07, 0xE2C6, 0x7C0D, 0xE2CB, 0x7C11, 0xE2C0, 0x7C12, 0x99D3, 0x7C13, 0xE2C7, 0x7C14, 0xE2C1, 0x7C17, 0xE2CA, 0x7C1F, 0xE2D0, 0x7C21, 0x8AC8, 0x7C23, 0xE2CD, 0x7C27, 0xE2CE, 0x7C2A, 0xE2CF, 0x7C2B, 0xE2D2, 0x7C37, 0xE2D1, 0x7C38, 0x94F4, 0x7C3D, 0xE2D3, 0x7C3E, 0x97FA, 0x7C3F, 0x95EB, 0x7C40, 0xE2D8, 0x7C43, 0xE2D5, 0x7C4C, 0xE2D4, 0x7C4D, 0x90D0, 0x7C4F, 0xE2D7, 0x7C50, 0xE2D9, 0x7C54, 0xE2D6, 0x7C56, 0xE2DD, 0x7C58, 0xE2DA, 0x7C5F, 0xE2DB, 0x7C60, 0xE2C4, 0x7C64, 0xE2DC, 0x7C65, 0xE2DE, 0x7C6C, 0xE2DF, 0x7C73, 0x95C4, 0x7C75, 0xE2E0, 0x7C7E, 0x96E0, 0x7C81, 0x8BCC, 0x7C82, 0x8C48, 0x7C83, 0xE2E1, 0x7C89, 0x95B2, 0x7C8B, 0x9088, 0x7C8D, 0x96AE, 0x7C90, 0xE2E2, 0x7C92, 0x97B1, 0x7C95, 0x9494, 0x7C97, 0x9165, 0x7C98, 0x9453, 0x7C9B, 0x8F6C, 0x7C9F, 0x88BE, 0x7CA1, 0xE2E7, 0x7CA2, 0xE2E5, 0x7CA4, 0xE2E3, 0x7CA5, 0x8A9F, 0x7CA7, 0x8FCF, 0x7CA8, 0xE2E8, 0x7CAB, 0xE2E6, 0x7CAD, 0xE2E4, 0x7CAE, 0xE2EC, 0x7CB1, 0xE2EB, 0x7CB2, 0xE2EA, 0x7CB3, 0xE2E9, 0x7CB9, 0xE2ED, 0x7CBD, 0xE2EE, 0x7CBE, 0x90B8, 0x7CC0, 0xE2EF, 0x7CC2, 0xE2F1, 0x7CC5, 0xE2F0, 0x7CCA, 0x8CD0, 0x7CCE, 0x9157, 0x7CD2, 0xE2F3, 0x7CD6, 0x939C, 0x7CD8, 0xE2F2, 0x7CDC, 0xE2F4, 0x7CDE, 0x95B3, 0x7CDF, 0x918C, 0x7CE0, 0x8D66, 0x7CE2, 0xE2F5, 0x7CE7, 0x97C6, 0x7CEF, 0xE2F7, 0x7CF2, 0xE2F8, 0x7CF4, 0xE2F9, 0x7CF6, 0xE2FA, 0x7CF8, 0x8E85, 0x7CFA, 0xE2FB, 0x7CFB, 0x8C6E, 0x7CFE, 0x8B8A, 0x7D00, 0x8B49, 0x7D02, 0xE340, 0x7D04, 0x96F1, 0x7D05, 0x8D67, 0x7D06, 0xE2FC, 0x7D0A, 0xE343, 0x7D0B, 0x96E4, 0x7D0D, 0x945B, 0x7D10, 0x9552, 0x7D14, 0x8F83, 0x7D15, 0xE342, 0x7D17, 0x8ED1, 0x7D18, 0x8D68, 0x7D19, 0x8E86, 0x7D1A, 0x8B89, 0x7D1B, 0x95B4, 0x7D1C, 0xE341, 0x7D20, 0x9166, 0x7D21, 0x9661, 0x7D22, 0x8DF5, 0x7D2B, 0x8E87, 0x7D2C, 0x92DB, 0x7D2E, 0xE346, 0x7D2F, 0x97DD, 0x7D30, 0x8DD7, 0x7D32, 0xE347, 0x7D33, 0x9061, 0x7D35, 0xE349, 0x7D39, 0x8FD0, 0x7D3A, 0x8DAE, 0x7D3F, 0xE348, 0x7D42, 0x8F49, 0x7D43, 0x8CBC, 0x7D44, 0x9167, 0x7D45, 0xE344, 0x7D46, 0xE34A, 0x7D48, 0xFB8A, 0x7D4B, 0xE345, 0x7D4C, 0x8C6F, 0x7D4E, 0xE34D, 0x7D4F, 0xE351, 0x7D50, 0x8C8B, 0x7D56, 0xE34C, 0x7D5B, 0xE355, 0x7D5C, 0xFB8B, 0x7D5E, 0x8D69, 0x7D61, 0x978D, 0x7D62, 0x88BA, 0x7D63, 0xE352, 0x7D66, 0x8B8B, 0x7D68, 0xE34F, 0x7D6E, 0xE350, 0x7D71, 0x939D, 0x7D72, 0xE34E, 0x7D73, 0xE34B, 0x7D75, 0x8A47, 0x7D76, 0x90E2, 0x7D79, 0x8CA6, 0x7D7D, 0xE357, 0x7D89, 0xE354, 0x7D8F, 0xE356, 0x7D93, 0xE353, 0x7D99, 0x8C70, 0x7D9A, 0x91B1, 0x7D9B, 0xE358, 0x7D9C, 0x918E, 0x7D9F, 0xE365, 0x7DA0, 0xFB8D, 0x7DA2, 0xE361, 0x7DA3, 0xE35B, 0x7DAB, 0xE35F, 0x7DAC, 0x8EF8, 0x7DAD, 0x88DB, 0x7DAE, 0xE35A, 0x7DAF, 0xE362, 0x7DB0, 0xE366, 0x7DB1, 0x8D6A, 0x7DB2, 0x96D4, 0x7DB4, 0x92D4, 0x7DB5, 0xE35C, 0x7DB7, 0xFB8C, 0x7DB8, 0xE364, 0x7DBA, 0xE359, 0x7DBB, 0x925D, 0x7DBD, 0xE35E, 0x7DBE, 0x88BB, 0x7DBF, 0x96C8, 0x7DC7, 0xE35D, 0x7DCA, 0x8BD9, 0x7DCB, 0x94EA, 0x7DCF, 0x918D, 0x7DD1, 0x97CE, 0x7DD2, 0x8F8F, 0x7DD5, 0xE38E, 0x7DD6, 0xFB8E, 0x7DD8, 0xE367, 0x7DDA, 0x90FC, 0x7DDC, 0xE363, 0x7DDD, 0xE368, 0x7DDE, 0xE36A, 0x7DE0, 0x92F7, 0x7DE1, 0xE36D, 0x7DE4, 0xE369, 0x7DE8, 0x95D2, 0x7DE9, 0x8AC9, 0x7DEC, 0x96C9, 0x7DEF, 0x88DC, 0x7DF2, 0xE36C, 0x7DF4, 0x97FB, 0x7DFB, 0xE36B, 0x7E01, 0x898F, 0x7E04, 0x93EA, 0x7E05, 0xE36E, 0x7E09, 0xE375, 0x7E0A, 0xE36F, 0x7E0B, 0xE376, 0x7E12, 0xE372, 0x7E1B, 0x949B, 0x7E1E, 0x8EC8, 0x7E1F, 0xE374, 0x7E21, 0xE371, 0x7E22, 0xE377, 0x7E23, 0xE370, 0x7E26, 0x8F63, 0x7E2B, 0x9644, 0x7E2E, 0x8F6B, 0x7E31, 0xE373, 0x7E32, 0xE380, 0x7E35, 0xE37B, 0x7E37, 0xE37E, 0x7E39, 0xE37C, 0x7E3A, 0xE381, 0x7E3B, 0xE37A, 0x7E3D, 0xE360, 0x7E3E, 0x90D1, 0x7E41, 0x94C9, 0x7E43, 0xE37D, 0x7E46, 0xE378, 0x7E4A, 0x9140, 0x7E4B, 0x8C71, 0x7E4D, 0x8F4A, 0x7E52, 0xFB8F, 0x7E54, 0x9044, 0x7E55, 0x9155, 0x7E56, 0xE384, 0x7E59, 0xE386, 0x7E5A, 0xE387, 0x7E5D, 0xE383, 0x7E5E, 0xE385, 0x7E66, 0xE379, 0x7E67, 0xE382, 0x7E69, 0xE38A, 0x7E6A, 0xE389, 0x7E6D, 0x969A, 0x7E70, 0x8C4A, 0x7E79, 0xE388, 0x7E7B, 0xE38C, 0x7E7C, 0xE38B, 0x7E7D, 0xE38F, 0x7E7F, 0xE391, 0x7E82, 0x8E5B, 0x7E83, 0xE38D, 0x7E88, 0xE392, 0x7E89, 0xE393, 0x7E8A, 0xFA5C, 0x7E8C, 0xE394, 0x7E8E, 0xE39A, 0x7E8F, 0x935A, 0x7E90, 0xE396, 0x7E92, 0xE395, 0x7E93, 0xE397, 0x7E94, 0xE398, 0x7E96, 0xE399, 0x7E9B, 0xE39B, 0x7E9C, 0xE39C, 0x7F36, 0x8ACA, 0x7F38, 0xE39D, 0x7F3A, 0xE39E, 0x7F45, 0xE39F, 0x7F47, 0xFB90, 0x7F4C, 0xE3A0, 0x7F4D, 0xE3A1, 0x7F4E, 0xE3A2, 0x7F50, 0xE3A3, 0x7F51, 0xE3A4, 0x7F54, 0xE3A6, 0x7F55, 0xE3A5, 0x7F58, 0xE3A7, 0x7F5F, 0xE3A8, 0x7F60, 0xE3A9, 0x7F67, 0xE3AC, 0x7F68, 0xE3AA, 0x7F69, 0xE3AB, 0x7F6A, 0x8DDF, 0x7F6B, 0x8C72, 0x7F6E, 0x9275, 0x7F70, 0x94B1, 0x7F72, 0x8F90, 0x7F75, 0x946C, 0x7F77, 0x94EB, 0x7F78, 0xE3AD, 0x7F79, 0x9CEB, 0x7F82, 0xE3AE, 0x7F83, 0xE3B0, 0x7F85, 0x9785, 0x7F86, 0xE3AF, 0x7F87, 0xE3B2, 0x7F88, 0xE3B1, 0x7F8A, 0x9772, 0x7F8C, 0xE3B3, 0x7F8E, 0x94FC, 0x7F94, 0xE3B4, 0x7F9A, 0xE3B7, 0x7F9D, 0xE3B6, 0x7F9E, 0xE3B5, 0x7FA1, 0xFB91, 0x7FA3, 0xE3B8, 0x7FA4, 0x8C51, 0x7FA8, 0x9141, 0x7FA9, 0x8B60, 0x7FAE, 0xE3BC, 0x7FAF, 0xE3B9, 0x7FB2, 0xE3BA, 0x7FB6, 0xE3BD, 0x7FB8, 0xE3BE, 0x7FB9, 0xE3BB, 0x7FBD, 0x8948, 0x7FC1, 0x89A5, 0x7FC5, 0xE3C0, 0x7FC6, 0xE3C1, 0x7FCA, 0xE3C2, 0x7FCC, 0x9782, 0x7FD2, 0x8F4B, 0x7FD4, 0xE3C4, 0x7FD5, 0xE3C3, 0x7FE0, 0x9089, 0x7FE1, 0xE3C5, 0x7FE6, 0xE3C6, 0x7FE9, 0xE3C7, 0x7FEB, 0x8AE3, 0x7FF0, 0x8ACB, 0x7FF3, 0xE3C8, 0x7FF9, 0xE3C9, 0x7FFB, 0x967C, 0x7FFC, 0x9783, 0x8000, 0x9773, 0x8001, 0x9856, 0x8003, 0x8D6C, 0x8004, 0xE3CC, 0x8005, 0x8ED2, 0x8006, 0xE3CB, 0x800B, 0xE3CD, 0x800C, 0x8EA7, 0x8010, 0x91CF, 0x8012, 0xE3CE, 0x8015, 0x8D6B, 0x8017, 0x96D5, 0x8018, 0xE3CF, 0x8019, 0xE3D0, 0x801C, 0xE3D1, 0x8021, 0xE3D2, 0x8028, 0xE3D3, 0x8033, 0x8EA8, 0x8036, 0x96EB, 0x803B, 0xE3D5, 0x803D, 0x925E, 0x803F, 0xE3D4, 0x8046, 0xE3D7, 0x804A, 0xE3D6, 0x8052, 0xE3D8, 0x8056, 0x90B9, 0x8058, 0xE3D9, 0x805A, 0xE3DA, 0x805E, 0x95B7, 0x805F, 0xE3DB, 0x8061, 0x918F, 0x8062, 0xE3DC, 0x8068, 0xE3DD, 0x806F, 0x97FC, 0x8070, 0xE3E0, 0x8072, 0xE3DF, 0x8073, 0xE3DE, 0x8074, 0x92AE, 0x8076, 0xE3E1, 0x8077, 0x9045, 0x8079, 0xE3E2, 0x807D, 0xE3E3, 0x807E, 0x9857, 0x807F, 0xE3E4, 0x8084, 0xE3E5, 0x8085, 0xE3E7, 0x8086, 0xE3E6, 0x8087, 0x94A3, 0x8089, 0x93F7, 0x808B, 0x985D, 0x808C, 0x94A7, 0x8093, 0xE3E9, 0x8096, 0x8FD1, 0x8098, 0x9549, 0x809A, 0xE3EA, 0x809B, 0xE3E8, 0x809D, 0x8ACC, 0x80A1, 0x8CD2, 0x80A2, 0x8E88, 0x80A5, 0x94EC, 0x80A9, 0x8CA8, 0x80AA, 0x9662, 0x80AC, 0xE3ED, 0x80AD, 0xE3EB, 0x80AF, 0x8D6D, 0x80B1, 0x8D6E, 0x80B2, 0x88E7, 0x80B4, 0x8DE6, 0x80BA, 0x9478, 0x80C3, 0x88DD, 0x80C4, 0xE3F2, 0x80C6, 0x925F, 0x80CC, 0x9477, 0x80CE, 0x91D9, 0x80D6, 0xE3F4, 0x80D9, 0xE3F0, 0x80DA, 0xE3F3, 0x80DB, 0xE3EE, 0x80DD, 0xE3F1, 0x80DE, 0x9645, 0x80E1, 0x8CD3, 0x80E4, 0x88FB, 0x80E5, 0xE3EF, 0x80EF, 0xE3F6, 0x80F1, 0xE3F7, 0x80F4, 0x93B7, 0x80F8, 0x8BB9, 0x80FC, 0xE445, 0x80FD, 0x945C, 0x8102, 0x8E89, 0x8105, 0x8BBA, 0x8106, 0x90C6, 0x8107, 0x9865, 0x8108, 0x96AC, 0x8109, 0xE3F5, 0x810A, 0x90D2, 0x811A, 0x8B72, 0x811B, 0xE3F8, 0x8123, 0xE3FA, 0x8129, 0xE3F9, 0x812F, 0xE3FB, 0x8131, 0x9245, 0x8133, 0x945D, 0x8139, 0x92AF, 0x813E, 0xE442, 0x8146, 0xE441, 0x814B, 0xE3FC, 0x814E, 0x9074, 0x8150, 0x9585, 0x8151, 0xE444, 0x8153, 0xE443, 0x8154, 0x8D6F, 0x8155, 0x9872, 0x815F, 0xE454, 0x8165, 0xE448, 0x8166, 0xE449, 0x816B, 0x8EEE, 0x816E, 0xE447, 0x8170, 0x8D98, 0x8171, 0xE446, 0x8174, 0xE44A, 0x8178, 0x92B0, 0x8179, 0x95A0, 0x817A, 0x9142, 0x817F, 0x91DA, 0x8180, 0xE44E, 0x8182, 0xE44F, 0x8183, 0xE44B, 0x8188, 0xE44C, 0x818A, 0xE44D, 0x818F, 0x8D70, 0x8193, 0xE455, 0x8195, 0xE451, 0x819A, 0x9586, 0x819C, 0x968C, 0x819D, 0x9547, 0x81A0, 0xE450, 0x81A3, 0xE453, 0x81A4, 0xE452, 0x81A8, 0x9663, 0x81A9, 0xE456, 0x81B0, 0xE457, 0x81B3, 0x9156, 0x81B5, 0xE458, 0x81B8, 0xE45A, 0x81BA, 0xE45E, 0x81BD, 0xE45B, 0x81BE, 0xE459, 0x81BF, 0x945E, 0x81C0, 0xE45C, 0x81C2, 0xE45D, 0x81C6, 0x89B0, 0x81C8, 0xE464, 0x81C9, 0xE45F, 0x81CD, 0xE460, 0x81D1, 0xE461, 0x81D3, 0x919F, 0x81D8, 0xE463, 0x81D9, 0xE462, 0x81DA, 0xE465, 0x81DF, 0xE466, 0x81E0, 0xE467, 0x81E3, 0x9062, 0x81E5, 0x89E7, 0x81E7, 0xE468, 0x81E8, 0x97D5, 0x81EA, 0x8EA9, 0x81ED, 0x8F4C, 0x81F3, 0x8E8A, 0x81F4, 0x9276, 0x81FA, 0xE469, 0x81FB, 0xE46A, 0x81FC, 0x8950, 0x81FE, 0xE46B, 0x8201, 0xE46C, 0x8202, 0xE46D, 0x8205, 0xE46E, 0x8207, 0xE46F, 0x8208, 0x8BBB, 0x8209, 0x9DA8, 0x820A, 0xE470, 0x820C, 0x90E3, 0x820D, 0xE471, 0x820E, 0x8EC9, 0x8210, 0xE472, 0x8212, 0x98AE, 0x8216, 0xE473, 0x8217, 0x95DC, 0x8218, 0x8ADA, 0x821B, 0x9143, 0x821C, 0x8F77, 0x821E, 0x9591, 0x821F, 0x8F4D, 0x8229, 0xE474, 0x822A, 0x8D71, 0x822B, 0xE475, 0x822C, 0x94CA, 0x822E, 0xE484, 0x8233, 0xE477, 0x8235, 0x91C7, 0x8236, 0x9495, 0x8237, 0x8CBD, 0x8238, 0xE476, 0x8239, 0x9144, 0x8240, 0xE478, 0x8247, 0x92F8, 0x8258, 0xE47A, 0x8259, 0xE479, 0x825A, 0xE47C, 0x825D, 0xE47B, 0x825F, 0xE47D, 0x8262, 0xE480, 0x8264, 0xE47E, 0x8266, 0x8ACD, 0x8268, 0xE481, 0x826A, 0xE482, 0x826B, 0xE483, 0x826E, 0x8DAF, 0x826F, 0x97C7, 0x8271, 0xE485, 0x8272, 0x9046, 0x8276, 0x8990, 0x8277, 0xE486, 0x8278, 0xE487, 0x827E, 0xE488, 0x828B, 0x88F0, 0x828D, 0xE489, 0x8292, 0xE48A, 0x8299, 0x9587, 0x829D, 0x8EC5, 0x829F, 0xE48C, 0x82A5, 0x8A48, 0x82A6, 0x88B0, 0x82AB, 0xE48B, 0x82AC, 0xE48E, 0x82AD, 0x946D, 0x82AF, 0x9063, 0x82B1, 0x89D4, 0x82B3, 0x9646, 0x82B8, 0x8C7C, 0x82B9, 0x8BDA, 0x82BB, 0xE48D, 0x82BD, 0x89E8, 0x82C5, 0x8AA1, 0x82D1, 0x8991, 0x82D2, 0xE492, 0x82D3, 0x97E8, 0x82D4, 0x91DB, 0x82D7, 0x9563, 0x82D9, 0xE49E, 0x82DB, 0x89D5, 0x82DC, 0xE49C, 0x82DE, 0xE49A, 0x82DF, 0xE491, 0x82E1, 0xE48F, 0x82E3, 0xE490, 0x82E5, 0x8EE1, 0x82E6, 0x8BEA, 0x82E7, 0x9297, 0x82EB, 0x93CF, 0x82F1, 0x8970, 0x82F3, 0xE494, 0x82F4, 0xE493, 0x82F9, 0xE499, 0x82FA, 0xE495, 0x82FB, 0xE498, 0x8301, 0xFB93, 0x8302, 0x96CE, 0x8303, 0xE497, 0x8304, 0x89D6, 0x8305, 0x8A9D, 0x8306, 0xE49B, 0x8309, 0xE49D, 0x830E, 0x8C73, 0x8316, 0xE4A1, 0x8317, 0xE4AA, 0x8318, 0xE4AB, 0x831C, 0x88A9, 0x8323, 0xE4B2, 0x8328, 0x88EF, 0x832B, 0xE4A9, 0x832F, 0xE4A8, 0x8331, 0xE4A3, 0x8332, 0xE4A2, 0x8334, 0xE4A0, 0x8335, 0xE49F, 0x8336, 0x9283, 0x8338, 0x91F9, 0x8339, 0xE4A5, 0x8340, 0xE4A4, 0x8345, 0xE4A7, 0x8349, 0x9190, 0x834A, 0x8C74, 0x834F, 0x8960, 0x8350, 0xE4A6, 0x8352, 0x8D72, 0x8358, 0x9191, 0x8362, 0xFB94, 0x8373, 0xE4B8, 0x8375, 0xE4B9, 0x8377, 0x89D7, 0x837B, 0x89AC, 0x837C, 0xE4B6, 0x837F, 0xFB95, 0x8385, 0xE4AC, 0x8387, 0xE4B4, 0x8389, 0xE4BB, 0x838A, 0xE4B5, 0x838E, 0xE4B3, 0x8393, 0xE496, 0x8396, 0xE4B1, 0x839A, 0xE4AD, 0x839E, 0x8ACE, 0x839F, 0xE4AF, 0x83A0, 0xE4BA, 0x83A2, 0xE4B0, 0x83A8, 0xE4BC, 0x83AA, 0xE4AE, 0x83AB, 0x949C, 0x83B1, 0x9789, 0x83B5, 0xE4B7, 0x83BD, 0xE4CD, 0x83C1, 0xE4C5, 0x83C5, 0x909B, 0x83C7, 0xFB96, 0x83CA, 0x8B65, 0x83CC, 0x8BDB, 0x83CE, 0xE4C0, 0x83D3, 0x89D9, 0x83D6, 0x8FD2, 0x83D8, 0xE4C3, 0x83DC, 0x8DD8, 0x83DF, 0x9370, 0x83E0, 0xE4C8, 0x83E9, 0x95EC, 0x83EB, 0xE4BF, 0x83EF, 0x89D8, 0x83F0, 0x8CD4, 0x83F1, 0x9548, 0x83F2, 0xE4C9, 0x83F4, 0xE4BD, 0x83F6, 0xFB97, 0x83F7, 0xE4C6, 0x83FB, 0xE4D0, 0x83FD, 0xE4C1, 0x8403, 0xE4C2, 0x8404, 0x93B8, 0x8407, 0xE4C7, 0x840B, 0xE4C4, 0x840C, 0x9647, 0x840D, 0xE4CA, 0x840E, 0x88DE, 0x8413, 0xE4BE, 0x8420, 0xE4CC, 0x8422, 0xE4CB, 0x8429, 0x948B, 0x842A, 0xE4D2, 0x842C, 0xE4DD, 0x8431, 0x8A9E, 0x8435, 0xE4E0, 0x8438, 0xE4CE, 0x843C, 0xE4D3, 0x843D, 0x978E, 0x8446, 0xE4DC, 0x8448, 0xFB98, 0x8449, 0x9774, 0x844E, 0x97A8, 0x8457, 0x9298, 0x845B, 0x8A8B, 0x8461, 0x9592, 0x8462, 0xE4E2, 0x8463, 0x939F, 0x8466, 0x88AF, 0x8469, 0xE4DB, 0x846B, 0xE4D7, 0x846C, 0x9192, 0x846D, 0xE4D1, 0x846E, 0xE4D9, 0x846F, 0xE4DE, 0x8471, 0x944B, 0x8475, 0x88A8, 0x8477, 0xE4D6, 0x8479, 0xE4DF, 0x847A, 0x9598, 0x8482, 0xE4DA, 0x8484, 0xE4D5, 0x848B, 0x8FD3, 0x8490, 0x8F4E, 0x8494, 0x8EAA, 0x8499, 0x96D6, 0x849C, 0x9566, 0x849F, 0xE4E5, 0x84A1, 0xE4EE, 0x84AD, 0xE4D8, 0x84B2, 0x8A97, 0x84B4, 0xFB99, 0x84B8, 0x8FF6, 0x84B9, 0xE4E3, 0x84BB, 0xE4E8, 0x84BC, 0x9193, 0x84BF, 0xE4E4, 0x84C1, 0xE4EB, 0x84C4, 0x927E, 0x84C6, 0xE4EC, 0x84C9, 0x9775, 0x84CA, 0xE4E1, 0x84CB, 0x8A57, 0x84CD, 0xE4E7, 0x84D0, 0xE4EA, 0x84D1, 0x96AA, 0x84D6, 0xE4ED, 0x84D9, 0xE4E6, 0x84DA, 0xE4E9, 0x84DC, 0xFA60, 0x84EC, 0x9648, 0x84EE, 0x9840, 0x84F4, 0xE4F1, 0x84FC, 0xE4F8, 0x84FF, 0xE4F0, 0x8500, 0x8EC1, 0x8506, 0xE4CF, 0x8511, 0x95CC, 0x8513, 0x96A0, 0x8514, 0xE4F7, 0x8515, 0xE4F6, 0x8517, 0xE4F2, 0x8518, 0xE4F3, 0x851A, 0x8955, 0x851F, 0xE4F5, 0x8521, 0xE4EF, 0x8526, 0x92D3, 0x852C, 0xE4F4, 0x852D, 0x88FC, 0x8535, 0x91A0, 0x853D, 0x95C1, 0x8540, 0xE4F9, 0x8541, 0xE540, 0x8543, 0x94D7, 0x8548, 0xE4FC, 0x8549, 0x8FD4, 0x854A, 0x8EC7, 0x854B, 0xE542, 0x854E, 0x8BBC, 0x8553, 0xFB9A, 0x8555, 0xE543, 0x8557, 0x9599, 0x8558, 0xE4FB, 0x8559, 0xFB9B, 0x855A, 0xE4D4, 0x8563, 0xE4FA, 0x8568, 0x986E, 0x8569, 0x93A0, 0x856A, 0x9593, 0x856B, 0xFB9C, 0x856D, 0xE54A, 0x8577, 0xE550, 0x857E, 0xE551, 0x8580, 0xE544, 0x8584, 0x9496, 0x8587, 0xE54E, 0x8588, 0xE546, 0x858A, 0xE548, 0x8590, 0xE552, 0x8591, 0xE547, 0x8594, 0xE54B, 0x8597, 0x8992, 0x8599, 0x93E3, 0x859B, 0xE54C, 0x859C, 0xE54F, 0x85A4, 0xE545, 0x85A6, 0x9145, 0x85A8, 0xE549, 0x85A9, 0x8E46, 0x85AA, 0x9064, 0x85AB, 0x8C4F, 0x85AC, 0x96F2, 0x85AE, 0x96F7, 0x85AF, 0x8F92, 0x85B0, 0xFB9E, 0x85B9, 0xE556, 0x85BA, 0xE554, 0x85C1, 0x986D, 0x85C9, 0xE553, 0x85CD, 0x9795, 0x85CF, 0xE555, 0x85D0, 0xE557, 0x85D5, 0xE558, 0x85DC, 0xE55B, 0x85DD, 0xE559, 0x85E4, 0x93A1, 0x85E5, 0xE55A, 0x85E9, 0x94CB, 0x85EA, 0xE54D, 0x85F7, 0x8F93, 0x85F9, 0xE55C, 0x85FA, 0xE561, 0x85FB, 0x9194, 0x85FE, 0xE560, 0x8602, 0xE541, 0x8606, 0xE562, 0x8607, 0x9168, 0x860A, 0xE55D, 0x860B, 0xE55F, 0x8613, 0xE55E, 0x8616, 0x9F50, 0x8617, 0x9F41, 0x861A, 0xE564, 0x8622, 0xE563, 0x862D, 0x9796, 0x862F, 0xE1BA, 0x8630, 0xE565, 0x863F, 0xE566, 0x864D, 0xE567, 0x864E, 0x8CD5, 0x8650, 0x8B73, 0x8654, 0xE569, 0x8655, 0x997C, 0x865A, 0x8B95, 0x865C, 0x97B8, 0x865E, 0x8BF1, 0x865F, 0xE56A, 0x8667, 0xE56B, 0x866B, 0x928E, 0x8671, 0xE56C, 0x8679, 0x93F8, 0x867B, 0x88B8, 0x868A, 0x89E1, 0x868B, 0xE571, 0x868C, 0xE572, 0x8693, 0xE56D, 0x8695, 0x8E5C, 0x86A3, 0xE56E, 0x86A4, 0x9461, 0x86A9, 0xE56F, 0x86AA, 0xE570, 0x86AB, 0xE57A, 0x86AF, 0xE574, 0x86B0, 0xE577, 0x86B6, 0xE573, 0x86C4, 0xE575, 0x86C6, 0xE576, 0x86C7, 0x8ED6, 0x86C9, 0xE578, 0x86CB, 0x9260, 0x86CD, 0x8C75, 0x86CE, 0x8A61, 0x86D4, 0xE57B, 0x86D9, 0x8A5E, 0x86DB, 0xE581, 0x86DE, 0xE57C, 0x86DF, 0xE580, 0x86E4, 0x94B8, 0x86E9, 0xE57D, 0x86EC, 0xE57E, 0x86ED, 0x9567, 0x86EE, 0x94D8, 0x86EF, 0xE582, 0x86F8, 0x91FB, 0x86F9, 0xE58C, 0x86FB, 0xE588, 0x86FE, 0x89E9, 0x8700, 0xE586, 0x8702, 0x9649, 0x8703, 0xE587, 0x8706, 0xE584, 0x8708, 0xE585, 0x8709, 0xE58A, 0x870A, 0xE58D, 0x870D, 0xE58B, 0x8711, 0xE589, 0x8712, 0xE583, 0x8718, 0x9277, 0x871A, 0xE594, 0x871C, 0x96A8, 0x8725, 0xE592, 0x8729, 0xE593, 0x8734, 0xE58E, 0x8737, 0xE590, 0x873B, 0xE591, 0x873F, 0xE58F, 0x8749, 0x90E4, 0x874B, 0x9858, 0x874C, 0xE598, 0x874E, 0xE599, 0x8753, 0xE59F, 0x8755, 0x9049, 0x8757, 0xE59B, 0x8759, 0xE59E, 0x875F, 0xE596, 0x8760, 0xE595, 0x8763, 0xE5A0, 0x8766, 0x89DA, 0x8768, 0xE59C, 0x876A, 0xE5A1, 0x876E, 0xE59D, 0x8774, 0xE59A, 0x8776, 0x92B1, 0x8778, 0xE597, 0x877F, 0x9488, 0x8782, 0xE5A5, 0x878D, 0x975A, 0x879F, 0xE5A4, 0x87A2, 0xE5A3, 0x87AB, 0xE5AC, 0x87AF, 0xE5A6, 0x87B3, 0xE5AE, 0x87BA, 0x9786, 0x87BB, 0xE5B1, 0x87BD, 0xE5A8, 0x87C0, 0xE5A9, 0x87C4, 0xE5AD, 0x87C6, 0xE5B0, 0x87C7, 0xE5AF, 0x87CB, 0xE5A7, 0x87D0, 0xE5AA, 0x87D2, 0xE5BB, 0x87E0, 0xE5B4, 0x87EF, 0xE5B2, 0x87F2, 0xE5B3, 0x87F6, 0xE5B8, 0x87F7, 0xE5B9, 0x87F9, 0x8A49, 0x87FB, 0x8B61, 0x87FE, 0xE5B7, 0x8805, 0xE5A2, 0x8807, 0xFBA1, 0x880D, 0xE5B6, 0x880E, 0xE5BA, 0x880F, 0xE5B5, 0x8811, 0xE5BC, 0x8815, 0xE5BE, 0x8816, 0xE5BD, 0x8821, 0xE5C0, 0x8822, 0xE5BF, 0x8823, 0xE579, 0x8827, 0xE5C4, 0x8831, 0xE5C1, 0x8836, 0xE5C2, 0x8839, 0xE5C3, 0x883B, 0xE5C5, 0x8840, 0x8C8C, 0x8842, 0xE5C7, 0x8844, 0xE5C6, 0x8846, 0x8F4F, 0x884C, 0x8D73, 0x884D, 0x9FA5, 0x8852, 0xE5C8, 0x8853, 0x8F70, 0x8857, 0x8A58, 0x8859, 0xE5C9, 0x885B, 0x8971, 0x885D, 0x8FD5, 0x885E, 0xE5CA, 0x8861, 0x8D74, 0x8862, 0xE5CB, 0x8863, 0x88DF, 0x8868, 0x955C, 0x886B, 0xE5CC, 0x8870, 0x908A, 0x8872, 0xE5D3, 0x8875, 0xE5D0, 0x8877, 0x928F, 0x887D, 0xE5D1, 0x887E, 0xE5CE, 0x887F, 0x8BDC, 0x8881, 0xE5CD, 0x8882, 0xE5D4, 0x8888, 0x8C55, 0x888B, 0x91DC, 0x888D, 0xE5DA, 0x8892, 0xE5D6, 0x8896, 0x91B3, 0x8897, 0xE5D5, 0x8899, 0xE5D8, 0x889E, 0xE5CF, 0x88A2, 0xE5D9, 0x88A4, 0xE5DB, 0x88AB, 0x94ED, 0x88AE, 0xE5D7, 0x88B0, 0xE5DC, 0x88B1, 0xE5DE, 0x88B4, 0x8CD1, 0x88B5, 0xE5D2, 0x88B7, 0x88BF, 0x88BF, 0xE5DD, 0x88C1, 0x8DD9, 0x88C2, 0x97F4, 0x88C3, 0xE5DF, 0x88C4, 0xE5E0, 0x88C5, 0x9195, 0x88CF, 0x97A0, 0x88D4, 0xE5E1, 0x88D5, 0x9754, 0x88D8, 0xE5E2, 0x88D9, 0xE5E3, 0x88DC, 0x95E2, 0x88DD, 0xE5E4, 0x88DF, 0x8DBE, 0x88E1, 0x97A1, 0x88E8, 0xE5E9, 0x88F2, 0xE5EA, 0x88F3, 0x8FD6, 0x88F4, 0xE5E8, 0x88F5, 0xFBA2, 0x88F8, 0x9787, 0x88F9, 0xE5E5, 0x88FC, 0xE5E7, 0x88FD, 0x90BB, 0x88FE, 0x909E, 0x8902, 0xE5E6, 0x8904, 0xE5EB, 0x8907, 0x95A1, 0x890A, 0xE5ED, 0x890C, 0xE5EC, 0x8910, 0x8A8C, 0x8912, 0x964A, 0x8913, 0xE5EE, 0x891C, 0xFA5D, 0x891D, 0xE5FA, 0x891E, 0xE5F0, 0x8925, 0xE5F1, 0x892A, 0xE5F2, 0x892B, 0xE5F3, 0x8936, 0xE5F7, 0x8938, 0xE5F8, 0x893B, 0xE5F6, 0x8941, 0xE5F4, 0x8943, 0xE5EF, 0x8944, 0xE5F5, 0x894C, 0xE5F9, 0x894D, 0xE8B5, 0x8956, 0x89A6, 0x895E, 0xE5FC, 0x895F, 0x8BDD, 0x8960, 0xE5FB, 0x8964, 0xE641, 0x8966, 0xE640, 0x896A, 0xE643, 0x896D, 0xE642, 0x896F, 0xE644, 0x8972, 0x8F50, 0x8974, 0xE645, 0x8977, 0xE646, 0x897E, 0xE647, 0x897F, 0x90BC, 0x8981, 0x9776, 0x8983, 0xE648, 0x8986, 0x95A2, 0x8987, 0x9465, 0x8988, 0xE649, 0x898A, 0xE64A, 0x898B, 0x8CA9, 0x898F, 0x8B4B, 0x8993, 0xE64B, 0x8996, 0x8E8B, 0x8997, 0x9460, 0x8998, 0xE64C, 0x899A, 0x8A6F, 0x89A1, 0xE64D, 0x89A6, 0xE64F, 0x89A7, 0x9797, 0x89A9, 0xE64E, 0x89AA, 0x9065, 0x89AC, 0xE650, 0x89AF, 0xE651, 0x89B2, 0xE652, 0x89B3, 0x8ACF, 0x89BA, 0xE653, 0x89BD, 0xE654, 0x89BF, 0xE655, 0x89C0, 0xE656, 0x89D2, 0x8A70, 0x89DA, 0xE657, 0x89DC, 0xE658, 0x89DD, 0xE659, 0x89E3, 0x89F0, 0x89E6, 0x9047, 0x89E7, 0xE65A, 0x89F4, 0xE65B, 0x89F8, 0xE65C, 0x8A00, 0x8CBE, 0x8A02, 0x92F9, 0x8A03, 0xE65D, 0x8A08, 0x8C76, 0x8A0A, 0x9075, 0x8A0C, 0xE660, 0x8A0E, 0x93A2, 0x8A10, 0xE65F, 0x8A12, 0xFBA3, 0x8A13, 0x8C50, 0x8A16, 0xE65E, 0x8A17, 0x91F5, 0x8A18, 0x8B4C, 0x8A1B, 0xE661, 0x8A1D, 0xE662, 0x8A1F, 0x8FD7, 0x8A23, 0x8C8D, 0x8A25, 0xE663, 0x8A2A, 0x964B, 0x8A2D, 0x90DD, 0x8A31, 0x8B96, 0x8A33, 0x96F3, 0x8A34, 0x9169, 0x8A36, 0xE664, 0x8A37, 0xFBA4, 0x8A3A, 0x9066, 0x8A3B, 0x9290, 0x8A3C, 0x8FD8, 0x8A41, 0xE665, 0x8A46, 0xE668, 0x8A48, 0xE669, 0x8A50, 0x8DBC, 0x8A51, 0x91C0, 0x8A52, 0xE667, 0x8A54, 0x8FD9, 0x8A55, 0x955D, 0x8A5B, 0xE666, 0x8A5E, 0x8E8C, 0x8A60, 0x8972, 0x8A62, 0xE66D, 0x8A63, 0x8C77, 0x8A66, 0x8E8E, 0x8A69, 0x8E8D, 0x8A6B, 0x986C, 0x8A6C, 0xE66C, 0x8A6D, 0xE66B, 0x8A6E, 0x9146, 0x8A70, 0x8B6C, 0x8A71, 0x9862, 0x8A72, 0x8A59, 0x8A73, 0x8FDA, 0x8A79, 0xFBA5, 0x8A7C, 0xE66A, 0x8A82, 0xE66F, 0x8A84, 0xE670, 0x8A85, 0xE66E, 0x8A87, 0x8CD6, 0x8A89, 0x975F, 0x8A8C, 0x8E8F, 0x8A8D, 0x9446, 0x8A91, 0xE673, 0x8A93, 0x90BE, 0x8A95, 0x9261, 0x8A98, 0x9755, 0x8A9A, 0xE676, 0x8A9E, 0x8CEA, 0x8AA0, 0x90BD, 0x8AA1, 0xE672, 0x8AA3, 0xE677, 0x8AA4, 0x8CEB, 0x8AA5, 0xE674, 0x8AA6, 0xE675, 0x8AA7, 0xFBA6, 0x8AA8, 0xE671, 0x8AAC, 0x90E0, 0x8AAD, 0x93C7, 0x8AB0, 0x924E, 0x8AB2, 0x89DB, 0x8AB9, 0x94EE, 0x8ABC, 0x8B62, 0x8ABE, 0xFBA7, 0x8ABF, 0x92B2, 0x8AC2, 0xE67A, 0x8AC4, 0xE678, 0x8AC7, 0x926B, 0x8ACB, 0x90BF, 0x8ACC, 0x8AD0, 0x8ACD, 0xE679, 0x8ACF, 0x907A, 0x8AD2, 0x97C8, 0x8AD6, 0x985F, 0x8ADA, 0xE67B, 0x8ADB, 0xE687, 0x8ADC, 0x92B3, 0x8ADE, 0xE686, 0x8ADF, 0xFBA8, 0x8AE0, 0xE683, 0x8AE1, 0xE68B, 0x8AE2, 0xE684, 0x8AE4, 0xE680, 0x8AE6, 0x92FA, 0x8AE7, 0xE67E, 0x8AEB, 0xE67C, 0x8AED, 0x9740, 0x8AEE, 0x8E90, 0x8AF1, 0xE681, 0x8AF3, 0xE67D, 0x8AF6, 0xFBAA, 0x8AF7, 0xE685, 0x8AF8, 0x8F94, 0x8AFA, 0x8CBF, 0x8AFE, 0x91F8, 0x8B00, 0x9664, 0x8B01, 0x8979, 0x8B02, 0x88E0, 0x8B04, 0x93A3, 0x8B07, 0xE689, 0x8B0C, 0xE688, 0x8B0E, 0x93E4, 0x8B10, 0xE68D, 0x8B14, 0xE682, 0x8B16, 0xE68C, 0x8B17, 0xE68E, 0x8B19, 0x8CAA, 0x8B1A, 0xE68A, 0x8B1B, 0x8D75, 0x8B1D, 0x8ED3, 0x8B20, 0xE68F, 0x8B21, 0x9777, 0x8B26, 0xE692, 0x8B28, 0xE695, 0x8B2B, 0xE693, 0x8B2C, 0x9554, 0x8B33, 0xE690, 0x8B39, 0x8BDE, 0x8B3E, 0xE694, 0x8B41, 0xE696, 0x8B49, 0xE69A, 0x8B4C, 0xE697, 0x8B4E, 0xE699, 0x8B4F, 0xE698, 0x8B53, 0xFBAB, 0x8B56, 0xE69B, 0x8B58, 0x8EAF, 0x8B5A, 0xE69D, 0x8B5B, 0xE69C, 0x8B5C, 0x9588, 0x8B5F, 0xE69F, 0x8B66, 0x8C78, 0x8B6B, 0xE69E, 0x8B6C, 0xE6A0, 0x8B6F, 0xE6A1, 0x8B70, 0x8B63, 0x8B71, 0xE3BF, 0x8B72, 0x8FF7, 0x8B74, 0xE6A2, 0x8B77, 0x8CEC, 0x8B7D, 0xE6A3, 0x8B7F, 0xFBAC, 0x8B80, 0xE6A4, 0x8B83, 0x8E5D, 0x8B8A, 0x9DCC, 0x8B8C, 0xE6A5, 0x8B8E, 0xE6A6, 0x8B90, 0x8F51, 0x8B92, 0xE6A7, 0x8B93, 0xE6A8, 0x8B96, 0xE6A9, 0x8B99, 0xE6AA, 0x8B9A, 0xE6AB, 0x8C37, 0x924A, 0x8C3A, 0xE6AC, 0x8C3F, 0xE6AE, 0x8C41, 0xE6AD, 0x8C46, 0x93A4, 0x8C48, 0xE6AF, 0x8C4A, 0x964C, 0x8C4C, 0xE6B0, 0x8C4E, 0xE6B1, 0x8C50, 0xE6B2, 0x8C55, 0xE6B3, 0x8C5A, 0x93D8, 0x8C61, 0x8FDB, 0x8C62, 0xE6B4, 0x8C6A, 0x8D8B, 0x8C6B, 0x98AC, 0x8C6C, 0xE6B5, 0x8C78, 0xE6B6, 0x8C79, 0x955E, 0x8C7A, 0xE6B7, 0x8C7C, 0xE6BF, 0x8C82, 0xE6B8, 0x8C85, 0xE6BA, 0x8C89, 0xE6B9, 0x8C8A, 0xE6BB, 0x8C8C, 0x9665, 0x8C8D, 0xE6BC, 0x8C8E, 0xE6BD, 0x8C94, 0xE6BE, 0x8C98, 0xE6C0, 0x8C9D, 0x8A4C, 0x8C9E, 0x92E5, 0x8CA0, 0x9589, 0x8CA1, 0x8DE0, 0x8CA2, 0x8D76, 0x8CA7, 0x956E, 0x8CA8, 0x89DD, 0x8CA9, 0x94CC, 0x8CAA, 0xE6C3, 0x8CAB, 0x8AD1, 0x8CAC, 0x90D3, 0x8CAD, 0xE6C2, 0x8CAE, 0xE6C7, 0x8CAF, 0x9299, 0x8CB0, 0x96E1, 0x8CB2, 0xE6C5, 0x8CB3, 0xE6C6, 0x8CB4, 0x8B4D, 0x8CB6, 0xE6C8, 0x8CB7, 0x9483, 0x8CB8, 0x91DD, 0x8CBB, 0x94EF, 0x8CBC, 0x935C, 0x8CBD, 0xE6C4, 0x8CBF, 0x9666, 0x8CC0, 0x89EA, 0x8CC1, 0xE6CA, 0x8CC2, 0x9847, 0x8CC3, 0x92C0, 0x8CC4, 0x9864, 0x8CC7, 0x8E91, 0x8CC8, 0xE6C9, 0x8CCA, 0x91AF, 0x8CCD, 0xE6DA, 0x8CCE, 0x9147, 0x8CD1, 0x93F6, 0x8CD3, 0x956F, 0x8CDA, 0xE6CD, 0x8CDB, 0x8E5E, 0x8CDC, 0x8E92, 0x8CDE, 0x8FDC, 0x8CE0, 0x9485, 0x8CE2, 0x8CAB, 0x8CE3, 0xE6CC, 0x8CE4, 0xE6CB, 0x8CE6, 0x958A, 0x8CEA, 0x8EBF, 0x8CED, 0x9371, 0x8CF0, 0xFBAD, 0x8CF4, 0xFBAE, 0x8CFA, 0xE6CF, 0x8CFB, 0xE6D0, 0x8CFC, 0x8D77, 0x8CFD, 0xE6CE, 0x8D04, 0xE6D1, 0x8D05, 0xE6D2, 0x8D07, 0xE6D4, 0x8D08, 0x91A1, 0x8D0A, 0xE6D3, 0x8D0B, 0x8AE4, 0x8D0D, 0xE6D6, 0x8D0F, 0xE6D5, 0x8D10, 0xE6D7, 0x8D12, 0xFBAF, 0x8D13, 0xE6D9, 0x8D14, 0xE6DB, 0x8D16, 0xE6DC, 0x8D64, 0x90D4, 0x8D66, 0x8ECD, 0x8D67, 0xE6DD, 0x8D6B, 0x8A71, 0x8D6D, 0xE6DE, 0x8D70, 0x9196, 0x8D71, 0xE6DF, 0x8D73, 0xE6E0, 0x8D74, 0x958B, 0x8D76, 0xFBB0, 0x8D77, 0x8B4E, 0x8D81, 0xE6E1, 0x8D85, 0x92B4, 0x8D8A, 0x897A, 0x8D99, 0xE6E2, 0x8DA3, 0x8EEF, 0x8DA8, 0x9096, 0x8DB3, 0x91AB, 0x8DBA, 0xE6E5, 0x8DBE, 0xE6E4, 0x8DC2, 0xE6E3, 0x8DCB, 0xE6EB, 0x8DCC, 0xE6E9, 0x8DCF, 0xE6E6, 0x8DD6, 0xE6E8, 0x8DDA, 0xE6E7, 0x8DDB, 0xE6EA, 0x8DDD, 0x8B97, 0x8DDF, 0xE6EE, 0x8DE1, 0x90D5, 0x8DE3, 0xE6EF, 0x8DE8, 0x8CD7, 0x8DEA, 0xE6EC, 0x8DEB, 0xE6ED, 0x8DEF, 0x9848, 0x8DF3, 0x92B5, 0x8DF5, 0x9148, 0x8DFC, 0xE6F0, 0x8DFF, 0xE6F3, 0x8E08, 0xE6F1, 0x8E09, 0xE6F2, 0x8E0A, 0x9778, 0x8E0F, 0x93A5, 0x8E10, 0xE6F6, 0x8E1D, 0xE6F4, 0x8E1E, 0xE6F5, 0x8E1F, 0xE6F7, 0x8E2A, 0xE748, 0x8E30, 0xE6FA, 0x8E34, 0xE6FB, 0x8E35, 0xE6F9, 0x8E42, 0xE6F8, 0x8E44, 0x92FB, 0x8E47, 0xE740, 0x8E48, 0xE744, 0x8E49, 0xE741, 0x8E4A, 0xE6FC, 0x8E4C, 0xE742, 0x8E50, 0xE743, 0x8E55, 0xE74A, 0x8E59, 0xE745, 0x8E5F, 0x90D6, 0x8E60, 0xE747, 0x8E63, 0xE749, 0x8E64, 0xE746, 0x8E72, 0xE74C, 0x8E74, 0x8F52, 0x8E76, 0xE74B, 0x8E7C, 0xE74D, 0x8E81, 0xE74E, 0x8E84, 0xE751, 0x8E85, 0xE750, 0x8E87, 0xE74F, 0x8E8A, 0xE753, 0x8E8B, 0xE752, 0x8E8D, 0x96F4, 0x8E91, 0xE755, 0x8E93, 0xE754, 0x8E94, 0xE756, 0x8E99, 0xE757, 0x8EA1, 0xE759, 0x8EAA, 0xE758, 0x8EAB, 0x9067, 0x8EAC, 0xE75A, 0x8EAF, 0x8BEB, 0x8EB0, 0xE75B, 0x8EB1, 0xE75D, 0x8EBE, 0xE75E, 0x8EC5, 0xE75F, 0x8EC6, 0xE75C, 0x8EC8, 0xE760, 0x8ECA, 0x8ED4, 0x8ECB, 0xE761, 0x8ECC, 0x8B4F, 0x8ECD, 0x8C52, 0x8ECF, 0xFBB2, 0x8ED2, 0x8CAC, 0x8EDB, 0xE762, 0x8EDF, 0x93EE, 0x8EE2, 0x935D, 0x8EE3, 0xE763, 0x8EEB, 0xE766, 0x8EF8, 0x8EB2, 0x8EFB, 0xE765, 0x8EFC, 0xE764, 0x8EFD, 0x8C79, 0x8EFE, 0xE767, 0x8F03, 0x8A72, 0x8F05, 0xE769, 0x8F09, 0x8DDA, 0x8F0A, 0xE768, 0x8F0C, 0xE771, 0x8F12, 0xE76B, 0x8F13, 0xE76D, 0x8F14, 0x95E3, 0x8F15, 0xE76A, 0x8F19, 0xE76C, 0x8F1B, 0xE770, 0x8F1C, 0xE76E, 0x8F1D, 0x8B50, 0x8F1F, 0xE76F, 0x8F26, 0xE772, 0x8F29, 0x9479, 0x8F2A, 0x97D6, 0x8F2F, 0x8F53, 0x8F33, 0xE773, 0x8F38, 0x9741, 0x8F39, 0xE775, 0x8F3B, 0xE774, 0x8F3E, 0xE778, 0x8F3F, 0x9760, 0x8F42, 0xE777, 0x8F44, 0x8A8D, 0x8F45, 0xE776, 0x8F46, 0xE77B, 0x8F49, 0xE77A, 0x8F4C, 0xE779, 0x8F4D, 0x9351, 0x8F4E, 0xE77C, 0x8F57, 0xE77D, 0x8F5C, 0xE77E, 0x8F5F, 0x8D8C, 0x8F61, 0x8C44, 0x8F62, 0xE780, 0x8F63, 0xE781, 0x8F64, 0xE782, 0x8F9B, 0x9068, 0x8F9C, 0xE783, 0x8F9E, 0x8EAB, 0x8F9F, 0xE784, 0x8FA3, 0xE785, 0x8FA7, 0x999F, 0x8FA8, 0x999E, 0x8FAD, 0xE786, 0x8FAE, 0xE390, 0x8FAF, 0xE787, 0x8FB0, 0x9243, 0x8FB1, 0x904A, 0x8FB2, 0x945F, 0x8FB7, 0xE788, 0x8FBA, 0x95D3, 0x8FBB, 0x92D2, 0x8FBC, 0x8D9E, 0x8FBF, 0x9248, 0x8FC2, 0x8949, 0x8FC4, 0x9698, 0x8FC5, 0x9076, 0x8FCE, 0x8C7D, 0x8FD1, 0x8BDF, 0x8FD4, 0x95D4, 0x8FDA, 0xE789, 0x8FE2, 0xE78B, 0x8FE5, 0xE78A, 0x8FE6, 0x89DE, 0x8FE9, 0x93F4, 0x8FEA, 0xE78C, 0x8FEB, 0x9497, 0x8FED, 0x9352, 0x8FEF, 0xE78D, 0x8FF0, 0x8F71, 0x8FF4, 0xE78F, 0x8FF7, 0x96C0, 0x8FF8, 0xE79E, 0x8FF9, 0xE791, 0x8FFA, 0xE792, 0x8FFD, 0x92C7, 0x9000, 0x91DE, 0x9001, 0x9197, 0x9003, 0x93A6, 0x9005, 0xE790, 0x9006, 0x8B74, 0x900B, 0xE799, 0x900D, 0xE796, 0x900E, 0xE7A3, 0x900F, 0x93A7, 0x9010, 0x9280, 0x9011, 0xE793, 0x9013, 0x92FC, 0x9014, 0x9372, 0x9015, 0xE794, 0x9016, 0xE798, 0x9017, 0x9080, 0x9019, 0x9487, 0x901A, 0x92CA, 0x901D, 0x90C0, 0x901E, 0xE797, 0x901F, 0x91AC, 0x9020, 0x91A2, 0x9021, 0xE795, 0x9022, 0x88A7, 0x9023, 0x9841, 0x9027, 0xE79A, 0x902E, 0x91DF, 0x9031, 0x8F54, 0x9032, 0x9069, 0x9035, 0xE79C, 0x9036, 0xE79B, 0x9038, 0x88ED, 0x9039, 0xE79D, 0x903C, 0x954E, 0x903E, 0xE7A5, 0x9041, 0x93D9, 0x9042, 0x908B, 0x9045, 0x9278, 0x9047, 0x8BF6, 0x9049, 0xE7A4, 0x904A, 0x9756, 0x904B, 0x895E, 0x904D, 0x95D5, 0x904E, 0x89DF, 0x904F, 0xE79F, 0x9050, 0xE7A0, 0x9051, 0xE7A1, 0x9052, 0xE7A2, 0x9053, 0x93B9, 0x9054, 0x9242, 0x9055, 0x88E1, 0x9056, 0xE7A6, 0x9058, 0xE7A7, 0x9059, 0xEAA1, 0x905C, 0x91BB, 0x905E, 0xE7A8, 0x9060, 0x8993, 0x9061, 0x916B, 0x9063, 0x8CAD, 0x9065, 0x9779, 0x9067, 0xFBB5, 0x9068, 0xE7A9, 0x9069, 0x934B, 0x906D, 0x9198, 0x906E, 0x8ED5, 0x906F, 0xE7AA, 0x9072, 0xE7AD, 0x9075, 0x8F85, 0x9076, 0xE7AB, 0x9077, 0x914A, 0x9078, 0x9149, 0x907A, 0x88E2, 0x907C, 0x97C9, 0x907D, 0xE7AF, 0x907F, 0x94F0, 0x9080, 0xE7B1, 0x9081, 0xE7B0, 0x9082, 0xE7AE, 0x9083, 0xE284, 0x9084, 0x8AD2, 0x9087, 0xE78E, 0x9089, 0xE7B3, 0x908A, 0xE7B2, 0x908F, 0xE7B4, 0x9091, 0x9757, 0x90A3, 0x93DF, 0x90A6, 0x964D, 0x90A8, 0xE7B5, 0x90AA, 0x8ED7, 0x90AF, 0xE7B6, 0x90B1, 0xE7B7, 0x90B5, 0xE7B8, 0x90B8, 0x9340, 0x90C1, 0x88E8, 0x90CA, 0x8D78, 0x90CE, 0x9859, 0x90DB, 0xE7BC, 0x90DE, 0xFBB6, 0x90E1, 0x8C53, 0x90E2, 0xE7B9, 0x90E4, 0xE7BA, 0x90E8, 0x9594, 0x90ED, 0x8A73, 0x90F5, 0x9758, 0x90F7, 0x8BBD, 0x90FD, 0x9373, 0x9102, 0xE7BD, 0x9112, 0xE7BE, 0x9115, 0xFBB8, 0x9119, 0xE7BF, 0x9127, 0xFBB9, 0x912D, 0x9341, 0x9130, 0xE7C1, 0x9132, 0xE7C0, 0x9149, 0x93D1, 0x914A, 0xE7C2, 0x914B, 0x8F55, 0x914C, 0x8EDE, 0x914D, 0x947A, 0x914E, 0x9291, 0x9152, 0x8EF0, 0x9154, 0x908C, 0x9156, 0xE7C3, 0x9158, 0xE7C4, 0x9162, 0x907C, 0x9163, 0xE7C5, 0x9165, 0xE7C6, 0x9169, 0xE7C7, 0x916A, 0x978F, 0x916C, 0x8F56, 0x9172, 0xE7C9, 0x9173, 0xE7C8, 0x9175, 0x8D79, 0x9177, 0x8D93, 0x9178, 0x8E5F, 0x9182, 0xE7CC, 0x9187, 0x8F86, 0x9189, 0xE7CB, 0x918B, 0xE7CA, 0x918D, 0x91E7, 0x9190, 0x8CED, 0x9192, 0x90C1, 0x9197, 0x94AE, 0x919C, 0x8F58, 0x91A2, 0xE7CD, 0x91A4, 0x8FDD, 0x91AA, 0xE7D0, 0x91AB, 0xE7CE, 0x91AF, 0xE7CF, 0x91B4, 0xE7D2, 0x91B5, 0xE7D1, 0x91B8, 0x8FF8, 0x91BA, 0xE7D3, 0x91C0, 0xE7D4, 0x91C1, 0xE7D5, 0x91C6, 0x94CE, 0x91C7, 0x8DD1, 0x91C8, 0x8EDF, 0x91C9, 0xE7D6, 0x91CB, 0xE7D7, 0x91CC, 0x97A2, 0x91CD, 0x8F64, 0x91CE, 0x96EC, 0x91CF, 0x97CA, 0x91D0, 0xE7D8, 0x91D1, 0x8BE0, 0x91D6, 0xE7D9, 0x91D7, 0xFBBB, 0x91D8, 0x9342, 0x91DA, 0xFBBA, 0x91DB, 0xE7DC, 0x91DC, 0x8A98, 0x91DD, 0x906A, 0x91DE, 0xFBBC, 0x91DF, 0xE7DA, 0x91E1, 0xE7DB, 0x91E3, 0x92DE, 0x91E4, 0xFBBF, 0x91E5, 0xFBC0, 0x91E6, 0x9674, 0x91E7, 0x8BFA, 0x91ED, 0xFBBD, 0x91EE, 0xFBBE, 0x91F5, 0xE7DE, 0x91F6, 0xE7DF, 0x91FC, 0xE7DD, 0x91FF, 0xE7E1, 0x9206, 0xFBC1, 0x920A, 0xFBC3, 0x920D, 0x93DD, 0x920E, 0x8A62, 0x9210, 0xFBC2, 0x9211, 0xE7E5, 0x9214, 0xE7E2, 0x9215, 0xE7E4, 0x921E, 0xE7E0, 0x9229, 0xE86E, 0x922C, 0xE7E3, 0x9234, 0x97E9, 0x9237, 0x8CD8, 0x9239, 0xFBCA, 0x923A, 0xFBC4, 0x923C, 0xFBC6, 0x923F, 0xE7ED, 0x9240, 0xFBC5, 0x9244, 0x9353, 0x9245, 0xE7E8, 0x9248, 0xE7EB, 0x9249, 0xE7E9, 0x924B, 0xE7EE, 0x924E, 0xFBC7, 0x9250, 0xE7EF, 0x9251, 0xFBC9, 0x9257, 0xE7E7, 0x9259, 0xFBC8, 0x925A, 0xE7F4, 0x925B, 0x8994, 0x925E, 0xE7E6, 0x9262, 0x94AB, 0x9264, 0xE7EA, 0x9266, 0x8FDE, 0x9267, 0xFBCB, 0x9271, 0x8D7A, 0x9277, 0xFBCD, 0x9278, 0xFBCE, 0x927E, 0x9667, 0x9280, 0x8BE2, 0x9283, 0x8F65, 0x9285, 0x93BA, 0x9288, 0xFA5F, 0x9291, 0x914C, 0x9293, 0xE7F2, 0x9295, 0xE7EC, 0x9296, 0xE7F1, 0x9298, 0x96C1, 0x929A, 0x92B6, 0x929B, 0xE7F3, 0x929C, 0xE7F0, 0x92A7, 0xFBCC, 0x92AD, 0x914B, 0x92B7, 0xE7F7, 0x92B9, 0xE7F6, 0x92CF, 0xE7F5, 0x92D0, 0xFBD2, 0x92D2, 0x964E, 0x92D3, 0xFBD6, 0x92D5, 0xFBD4, 0x92D7, 0xFBD0, 0x92D9, 0xFBD1, 0x92E0, 0xFBD5, 0x92E4, 0x8F9B, 0x92E7, 0xFBCF, 0x92E9, 0xE7F8, 0x92EA, 0x95DD, 0x92ED, 0x8973, 0x92F2, 0x9565, 0x92F3, 0x9292, 0x92F8, 0x8B98, 0x92F9, 0xFA65, 0x92FA, 0xE7FA, 0x92FB, 0xFBD9, 0x92FC, 0x8D7C, 0x92FF, 0xFBDC, 0x9302, 0xFBDE, 0x9306, 0x8E4B, 0x930F, 0xE7F9, 0x9310, 0x908D, 0x9318, 0x908E, 0x9319, 0xE840, 0x931A, 0xE842, 0x931D, 0xFBDD, 0x931E, 0xFBDB, 0x9320, 0x8FF9, 0x9321, 0xFBD8, 0x9322, 0xE841, 0x9323, 0xE843, 0x9325, 0xFBD7, 0x9326, 0x8BD1, 0x9328, 0x9564, 0x932B, 0x8EE0, 0x932C, 0x9842, 0x932E, 0xE7FC, 0x932F, 0x8DF6, 0x9332, 0x985E, 0x9335, 0xE845, 0x933A, 0xE844, 0x933B, 0xE846, 0x9344, 0xE7FB, 0x9348, 0xFA5E, 0x934B, 0x93E7, 0x934D, 0x9374, 0x9354, 0x92D5, 0x9356, 0xE84B, 0x9357, 0xFBE0, 0x935B, 0x9262, 0x935C, 0xE847, 0x9360, 0xE848, 0x936C, 0x8C4C, 0x936E, 0xE84A, 0x9370, 0xFBDF, 0x9375, 0x8CAE, 0x937C, 0xE849, 0x937E, 0x8FDF, 0x938C, 0x8A99, 0x9394, 0xE84F, 0x9396, 0x8DBD, 0x9397, 0x9199, 0x939A, 0x92C8, 0x93A4, 0xFBE1, 0x93A7, 0x8A5A, 0x93AC, 0xE84D, 0x93AD, 0xE84E, 0x93AE, 0x92C1, 0x93B0, 0xE84C, 0x93B9, 0xE850, 0x93C3, 0xE856, 0x93C6, 0xFBE2, 0x93C8, 0xE859, 0x93D0, 0xE858, 0x93D1, 0x934C, 0x93D6, 0xE851, 0x93D7, 0xE852, 0x93D8, 0xE855, 0x93DD, 0xE857, 0x93DE, 0xFBE3, 0x93E1, 0x8BBE, 0x93E4, 0xE85A, 0x93E5, 0xE854, 0x93E8, 0xE853, 0x93F8, 0xFBE4, 0x9403, 0xE85E, 0x9407, 0xE85F, 0x9410, 0xE860, 0x9413, 0xE85D, 0x9414, 0xE85C, 0x9418, 0x8FE0, 0x9419, 0x93A8, 0x941A, 0xE85B, 0x9421, 0xE864, 0x942B, 0xE862, 0x9431, 0xFBE5, 0x9435, 0xE863, 0x9436, 0xE861, 0x9438, 0x91F6, 0x943A, 0xE865, 0x9441, 0xE866, 0x9444, 0xE868, 0x9445, 0xFBE6, 0x9448, 0xFBE7, 0x9451, 0x8AD3, 0x9452, 0xE867, 0x9453, 0x96F8, 0x945A, 0xE873, 0x945B, 0xE869, 0x945E, 0xE86C, 0x9460, 0xE86A, 0x9462, 0xE86B, 0x946A, 0xE86D, 0x9470, 0xE86F, 0x9475, 0xE870, 0x9477, 0xE871, 0x947C, 0xE874, 0x947D, 0xE872, 0x947E, 0xE875, 0x947F, 0xE877, 0x9481, 0xE876, 0x9577, 0x92B7, 0x9580, 0x96E5, 0x9582, 0xE878, 0x9583, 0x914D, 0x9587, 0xE879, 0x9589, 0x95C2, 0x958A, 0xE87A, 0x958B, 0x8A4A, 0x958F, 0x895B, 0x9591, 0x8AD5, 0x9592, 0xFBE8, 0x9593, 0x8AD4, 0x9594, 0xE87B, 0x9596, 0xE87C, 0x9598, 0xE87D, 0x9599, 0xE87E, 0x95A0, 0xE880, 0x95A2, 0x8AD6, 0x95A3, 0x8A74, 0x95A4, 0x8D7D, 0x95A5, 0x94B4, 0x95A7, 0xE882, 0x95A8, 0xE881, 0x95AD, 0xE883, 0x95B2, 0x897B, 0x95B9, 0xE886, 0x95BB, 0xE885, 0x95BC, 0xE884, 0x95BE, 0xE887, 0x95C3, 0xE88A, 0x95C7, 0x88C5, 0x95CA, 0xE888, 0x95CC, 0xE88C, 0x95CD, 0xE88B, 0x95D4, 0xE88E, 0x95D5, 0xE88D, 0x95D6, 0xE88F, 0x95D8, 0x93AC, 0x95DC, 0xE890, 0x95E1, 0xE891, 0x95E2, 0xE893, 0x95E5, 0xE892, 0x961C, 0x958C, 0x9621, 0xE894, 0x9628, 0xE895, 0x962A, 0x8DE3, 0x962E, 0xE896, 0x962F, 0xE897, 0x9632, 0x9668, 0x963B, 0x916A, 0x963F, 0x88A2, 0x9640, 0x91C9, 0x9642, 0xE898, 0x9644, 0x958D, 0x964B, 0xE89B, 0x964C, 0xE899, 0x964D, 0x8D7E, 0x964F, 0xE89A, 0x9650, 0x8CC0, 0x965B, 0x95C3, 0x965C, 0xE89D, 0x965D, 0xE89F, 0x965E, 0xE89E, 0x965F, 0xE8A0, 0x9662, 0x8940, 0x9663, 0x9077, 0x9664, 0x8F9C, 0x9665, 0x8AD7, 0x9666, 0xE8A1, 0x966A, 0x9486, 0x966C, 0xE8A3, 0x9670, 0x8941, 0x9672, 0xE8A2, 0x9673, 0x92C2, 0x9675, 0x97CB, 0x9676, 0x93A9, 0x9677, 0xE89C, 0x9678, 0x97A4, 0x967A, 0x8CAF, 0x967D, 0x977A, 0x9685, 0x8BF7, 0x9686, 0x97B2, 0x9688, 0x8C47, 0x968A, 0x91E0, 0x968B, 0xE440, 0x968D, 0xE8A4, 0x968E, 0x8A4B, 0x968F, 0x908F, 0x9694, 0x8A75, 0x9695, 0xE8A6, 0x9697, 0xE8A7, 0x9698, 0xE8A5, 0x9699, 0x8C84, 0x969B, 0x8DDB, 0x969C, 0x8FE1, 0x969D, 0xFBEB, 0x96A0, 0x8942, 0x96A3, 0x97D7, 0x96A7, 0xE8A9, 0x96A8, 0xE7AC, 0x96AA, 0xE8A8, 0x96AF, 0xFBEC, 0x96B0, 0xE8AC, 0x96B1, 0xE8AA, 0x96B2, 0xE8AB, 0x96B4, 0xE8AD, 0x96B6, 0xE8AE, 0x96B7, 0x97EA, 0x96B8, 0xE8AF, 0x96B9, 0xE8B0, 0x96BB, 0x90C7, 0x96BC, 0x94B9, 0x96C0, 0x909D, 0x96C1, 0x8AE5, 0x96C4, 0x9759, 0x96C5, 0x89EB, 0x96C6, 0x8F57, 0x96C7, 0x8CD9, 0x96C9, 0xE8B3, 0x96CB, 0xE8B2, 0x96CC, 0x8E93, 0x96CD, 0xE8B4, 0x96CE, 0xE8B1, 0x96D1, 0x8E47, 0x96D5, 0xE8B8, 0x96D6, 0xE5AB, 0x96D9, 0x99D4, 0x96DB, 0x9097, 0x96DC, 0xE8B6, 0x96E2, 0x97A3, 0x96E3, 0x93EF, 0x96E8, 0x894A, 0x96EA, 0x90E1, 0x96EB, 0x8EB4, 0x96F0, 0x95B5, 0x96F2, 0x895F, 0x96F6, 0x97EB, 0x96F7, 0x978B, 0x96F9, 0xE8B9, 0x96FB, 0x9364, 0x9700, 0x8EF9, 0x9704, 0xE8BA, 0x9706, 0xE8BB, 0x9707, 0x906B, 0x9708, 0xE8BC, 0x970A, 0x97EC, 0x970D, 0xE8B7, 0x970E, 0xE8BE, 0x970F, 0xE8C0, 0x9711, 0xE8BF, 0x9713, 0xE8BD, 0x9716, 0xE8C1, 0x9719, 0xE8C2, 0x971C, 0x919A, 0x971E, 0x89E0, 0x9724, 0xE8C3, 0x9727, 0x96B6, 0x972A, 0xE8C4, 0x9730, 0xE8C5, 0x9732, 0x9849, 0x9733, 0xFBED, 0x9738, 0x9E50, 0x9739, 0xE8C6, 0x973B, 0xFBEE, 0x973D, 0xE8C7, 0x973E, 0xE8C8, 0x9742, 0xE8CC, 0x9743, 0xFBEF, 0x9744, 0xE8C9, 0x9746, 0xE8CA, 0x9748, 0xE8CB, 0x9749, 0xE8CD, 0x974D, 0xFBF0, 0x974F, 0xFBF1, 0x9751, 0xFBF2, 0x9752, 0x90C2, 0x9755, 0xFBF3, 0x9756, 0x96F5, 0x9759, 0x90C3, 0x975C, 0xE8CE, 0x975E, 0x94F1, 0x9760, 0xE8CF, 0x9761, 0xEA72, 0x9762, 0x96CA, 0x9764, 0xE8D0, 0x9766, 0xE8D1, 0x9768, 0xE8D2, 0x9769, 0x8A76, 0x976B, 0xE8D4, 0x976D, 0x9078, 0x9771, 0xE8D5, 0x9774, 0x8C43, 0x9779, 0xE8D6, 0x977A, 0xE8DA, 0x977C, 0xE8D8, 0x9781, 0xE8D9, 0x9784, 0x8A93, 0x9785, 0xE8D7, 0x9786, 0xE8DB, 0x978B, 0xE8DC, 0x978D, 0x88C6, 0x978F, 0xE8DD, 0x9790, 0xE8DE, 0x9798, 0x8FE2, 0x979C, 0xE8DF, 0x97A0, 0x8B66, 0x97A3, 0xE8E2, 0x97A6, 0xE8E1, 0x97A8, 0xE8E0, 0x97AB, 0xE691, 0x97AD, 0x95DA, 0x97B3, 0xE8E3, 0x97B4, 0xE8E4, 0x97C3, 0xE8E5, 0x97C6, 0xE8E6, 0x97C8, 0xE8E7, 0x97CB, 0xE8E8, 0x97D3, 0x8AD8, 0x97DC, 0xE8E9, 0x97ED, 0xE8EA, 0x97EE, 0x9442, 0x97F2, 0xE8EC, 0x97F3, 0x89B9, 0x97F5, 0xE8EF, 0x97F6, 0xE8EE, 0x97FB, 0x8943, 0x97FF, 0x8BBF, 0x9801, 0x95C5, 0x9802, 0x92B8, 0x9803, 0x8DA0, 0x9805, 0x8D80, 0x9806, 0x8F87, 0x9808, 0x907B, 0x980C, 0xE8F1, 0x980F, 0xE8F0, 0x9810, 0x9761, 0x9811, 0x8AE6, 0x9812, 0x94D0, 0x9813, 0x93DA, 0x9817, 0x909C, 0x9818, 0x97CC, 0x981A, 0x8C7A, 0x9821, 0xE8F4, 0x9824, 0xE8F3, 0x982C, 0x966A, 0x982D, 0x93AA, 0x9834, 0x896F, 0x9837, 0xE8F5, 0x9838, 0xE8F2, 0x983B, 0x9570, 0x983C, 0x978A, 0x983D, 0xE8F6, 0x9846, 0xE8F7, 0x984B, 0xE8F9, 0x984C, 0x91E8, 0x984D, 0x8A7A, 0x984E, 0x8A7B, 0x984F, 0xE8F8, 0x9854, 0x8AE7, 0x9855, 0x8CB0, 0x9857, 0xFBF4, 0x9858, 0x8AE8, 0x985B, 0x935E, 0x985E, 0x97DE, 0x9865, 0xFBF5, 0x9867, 0x8CDA, 0x986B, 0xE8FA, 0x986F, 0xE8FB, 0x9870, 0xE8FC, 0x9871, 0xE940, 0x9873, 0xE942, 0x9874, 0xE941, 0x98A8, 0x9597, 0x98AA, 0xE943, 0x98AF, 0xE944, 0x98B1, 0xE945, 0x98B6, 0xE946, 0x98C3, 0xE948, 0x98C4, 0xE947, 0x98C6, 0xE949, 0x98DB, 0x94F2, 0x98DC, 0xE3CA, 0x98DF, 0x9048, 0x98E2, 0x8B51, 0x98E9, 0xE94A, 0x98EB, 0xE94B, 0x98ED, 0x99AA, 0x98EE, 0x9F5A, 0x98EF, 0x94D1, 0x98F2, 0x88F9, 0x98F4, 0x88B9, 0x98FC, 0x8E94, 0x98FD, 0x964F, 0x98FE, 0x8FFC, 0x9903, 0xE94C, 0x9905, 0x96DD, 0x9909, 0xE94D, 0x990A, 0x977B, 0x990C, 0x8961, 0x9910, 0x8E60, 0x9912, 0xE94E, 0x9913, 0x89EC, 0x9914, 0xE94F, 0x9918, 0xE950, 0x991D, 0xE952, 0x991E, 0xE953, 0x9920, 0xE955, 0x9921, 0xE951, 0x9924, 0xE954, 0x9927, 0xFBF8, 0x9928, 0x8AD9, 0x992C, 0xE956, 0x992E, 0xE957, 0x993D, 0xE958, 0x993E, 0xE959, 0x9942, 0xE95A, 0x9945, 0xE95C, 0x9949, 0xE95B, 0x994B, 0xE95E, 0x994C, 0xE961, 0x9950, 0xE95D, 0x9951, 0xE95F, 0x9952, 0xE960, 0x9955, 0xE962, 0x9957, 0x8BC0, 0x9996, 0x8EF1, 0x9997, 0xE963, 0x9998, 0xE964, 0x9999, 0x8D81, 0x999E, 0xFBFA, 0x99A5, 0xE965, 0x99A8, 0x8A5D, 0x99AC, 0x946E, 0x99AD, 0xE966, 0x99AE, 0xE967, 0x99B3, 0x9279, 0x99B4, 0x93E9, 0x99BC, 0xE968, 0x99C1, 0x949D, 0x99C4, 0x91CA, 0x99C5, 0x8977, 0x99C6, 0x8BEC, 0x99C8, 0x8BED, 0x99D0, 0x9293, 0x99D1, 0xE96D, 0x99D2, 0x8BEE, 0x99D5, 0x89ED, 0x99D8, 0xE96C, 0x99DB, 0xE96A, 0x99DD, 0xE96B, 0x99DF, 0xE969, 0x99E2, 0xE977, 0x99ED, 0xE96E, 0x99EE, 0xE96F, 0x99F1, 0xE970, 0x99F2, 0xE971, 0x99F8, 0xE973, 0x99FB, 0xE972, 0x99FF, 0x8F78, 0x9A01, 0xE974, 0x9A05, 0xE976, 0x9A0E, 0x8B52, 0x9A0F, 0xE975, 0x9A12, 0x919B, 0x9A13, 0x8CB1, 0x9A19, 0xE978, 0x9A28, 0x91CB, 0x9A2B, 0xE979, 0x9A30, 0x93AB, 0x9A37, 0xE97A, 0x9A3E, 0xE980, 0x9A40, 0xE97D, 0x9A42, 0xE97C, 0x9A43, 0xE97E, 0x9A45, 0xE97B, 0x9A4D, 0xE982, 0x9A4E, 0xFBFB, 0x9A55, 0xE981, 0x9A57, 0xE984, 0x9A5A, 0x8BC1, 0x9A5B, 0xE983, 0x9A5F, 0xE985, 0x9A62, 0xE986, 0x9A64, 0xE988, 0x9A65, 0xE987, 0x9A69, 0xE989, 0x9A6A, 0xE98B, 0x9A6B, 0xE98A, 0x9AA8, 0x8D9C, 0x9AAD, 0xE98C, 0x9AB0, 0xE98D, 0x9AB8, 0x8A5B, 0x9ABC, 0xE98E, 0x9AC0, 0xE98F, 0x9AC4, 0x9091, 0x9ACF, 0xE990, 0x9AD1, 0xE991, 0x9AD3, 0xE992, 0x9AD4, 0xE993, 0x9AD8, 0x8D82, 0x9AD9, 0xFBFC, 0x9ADC, 0xFC40, 0x9ADE, 0xE994, 0x9ADF, 0xE995, 0x9AE2, 0xE996, 0x9AE3, 0xE997, 0x9AE6, 0xE998, 0x9AEA, 0x94AF, 0x9AEB, 0xE99A, 0x9AED, 0x9545, 0x9AEE, 0xE99B, 0x9AEF, 0xE999, 0x9AF1, 0xE99D, 0x9AF4, 0xE99C, 0x9AF7, 0xE99E, 0x9AFB, 0xE99F, 0x9B06, 0xE9A0, 0x9B18, 0xE9A1, 0x9B1A, 0xE9A2, 0x9B1F, 0xE9A3, 0x9B22, 0xE9A4, 0x9B23, 0xE9A5, 0x9B25, 0xE9A6, 0x9B27, 0xE9A7, 0x9B28, 0xE9A8, 0x9B29, 0xE9A9, 0x9B2A, 0xE9AA, 0x9B2E, 0xE9AB, 0x9B2F, 0xE9AC, 0x9B31, 0x9F54, 0x9B32, 0xE9AD, 0x9B3B, 0xE2F6, 0x9B3C, 0x8B53, 0x9B41, 0x8A40, 0x9B42, 0x8DB0, 0x9B43, 0xE9AF, 0x9B44, 0xE9AE, 0x9B45, 0x96A3, 0x9B4D, 0xE9B1, 0x9B4E, 0xE9B2, 0x9B4F, 0xE9B0, 0x9B51, 0xE9B3, 0x9B54, 0x9682, 0x9B58, 0xE9B4, 0x9B5A, 0x8B9B, 0x9B6F, 0x9844, 0x9B72, 0xFC42, 0x9B74, 0xE9B5, 0x9B75, 0xFC41, 0x9B83, 0xE9B7, 0x9B8E, 0x88BC, 0x9B8F, 0xFC43, 0x9B91, 0xE9B8, 0x9B92, 0x95A9, 0x9B93, 0xE9B6, 0x9B96, 0xE9B9, 0x9B97, 0xE9BA, 0x9B9F, 0xE9BB, 0x9BA0, 0xE9BC, 0x9BA8, 0xE9BD, 0x9BAA, 0x968E, 0x9BAB, 0x8E4C, 0x9BAD, 0x8DF8, 0x9BAE, 0x914E, 0x9BB1, 0xFC44, 0x9BB4, 0xE9BE, 0x9BB9, 0xE9C1, 0x9BBB, 0xFC45, 0x9BC0, 0xE9BF, 0x9BC6, 0xE9C2, 0x9BC9, 0x8CEF, 0x9BCA, 0xE9C0, 0x9BCF, 0xE9C3, 0x9BD1, 0xE9C4, 0x9BD2, 0xE9C5, 0x9BD4, 0xE9C9, 0x9BD6, 0x8E49, 0x9BDB, 0x91E2, 0x9BE1, 0xE9CA, 0x9BE2, 0xE9C7, 0x9BE3, 0xE9C6, 0x9BE4, 0xE9C8, 0x9BE8, 0x8C7E, 0x9BF0, 0xE9CE, 0x9BF1, 0xE9CD, 0x9BF2, 0xE9CC, 0x9BF5, 0x88B1, 0x9C00, 0xFC46, 0x9C04, 0xE9D8, 0x9C06, 0xE9D4, 0x9C08, 0xE9D5, 0x9C09, 0xE9D1, 0x9C0A, 0xE9D7, 0x9C0C, 0xE9D3, 0x9C0D, 0x8A82, 0x9C10, 0x986B, 0x9C12, 0xE9D6, 0x9C13, 0xE9D2, 0x9C14, 0xE9D0, 0x9C15, 0xE9CF, 0x9C1B, 0xE9DA, 0x9C21, 0xE9DD, 0x9C24, 0xE9DC, 0x9C25, 0xE9DB, 0x9C2D, 0x9568, 0x9C2E, 0xE9D9, 0x9C2F, 0x88F1, 0x9C30, 0xE9DE, 0x9C32, 0xE9E0, 0x9C39, 0x8A8F, 0x9C3A, 0xE9CB, 0x9C3B, 0x8956, 0x9C3E, 0xE9E2, 0x9C46, 0xE9E1, 0x9C47, 0xE9DF, 0x9C48, 0x924C, 0x9C52, 0x9690, 0x9C57, 0x97D8, 0x9C5A, 0xE9E3, 0x9C60, 0xE9E4, 0x9C67, 0xE9E5, 0x9C76, 0xE9E6, 0x9C78, 0xE9E7, 0x9CE5, 0x92B9, 0x9CE7, 0xE9E8, 0x9CE9, 0x94B5, 0x9CEB, 0xE9ED, 0x9CEC, 0xE9E9, 0x9CF0, 0xE9EA, 0x9CF3, 0x9650, 0x9CF4, 0x96C2, 0x9CF6, 0x93CE, 0x9D03, 0xE9EE, 0x9D06, 0xE9EF, 0x9D07, 0x93BC, 0x9D08, 0xE9EC, 0x9D09, 0xE9EB, 0x9D0E, 0x89A8, 0x9D12, 0xE9F7, 0x9D15, 0xE9F6, 0x9D1B, 0x8995, 0x9D1F, 0xE9F4, 0x9D23, 0xE9F3, 0x9D26, 0xE9F1, 0x9D28, 0x8A9B, 0x9D2A, 0xE9F0, 0x9D2B, 0x8EB0, 0x9D2C, 0x89A7, 0x9D3B, 0x8D83, 0x9D3E, 0xE9FA, 0x9D3F, 0xE9F9, 0x9D41, 0xE9F8, 0x9D44, 0xE9F5, 0x9D46, 0xE9FB, 0x9D48, 0xE9FC, 0x9D50, 0xEA44, 0x9D51, 0xEA43, 0x9D59, 0xEA45, 0x9D5C, 0x894C, 0x9D5D, 0xEA40, 0x9D5E, 0xEA41, 0x9D60, 0x8D94, 0x9D61, 0x96B7, 0x9D64, 0xEA42, 0x9D6B, 0xFC48, 0x9D6C, 0x9651, 0x9D6F, 0xEA4A, 0x9D70, 0xFC47, 0x9D72, 0xEA46, 0x9D7A, 0xEA4B, 0x9D87, 0xEA48, 0x9D89, 0xEA47, 0x9D8F, 0x8C7B, 0x9D9A, 0xEA4C, 0x9DA4, 0xEA4D, 0x9DA9, 0xEA4E, 0x9DAB, 0xEA49, 0x9DAF, 0xE9F2, 0x9DB2, 0xEA4F, 0x9DB4, 0x92DF, 0x9DB8, 0xEA53, 0x9DBA, 0xEA54, 0x9DBB, 0xEA52, 0x9DC1, 0xEA51, 0x9DC2, 0xEA57, 0x9DC4, 0xEA50, 0x9DC6, 0xEA55, 0x9DCF, 0xEA56, 0x9DD3, 0xEA59, 0x9DD9, 0xEA58, 0x9DE6, 0xEA5B, 0x9DED, 0xEA5C, 0x9DEF, 0xEA5D, 0x9DF2, 0x9868, 0x9DF8, 0xEA5A, 0x9DF9, 0x91E9, 0x9DFA, 0x8DEB, 0x9DFD, 0xEA5E, 0x9E19, 0xFC4A, 0x9E1A, 0xEA5F, 0x9E1B, 0xEA60, 0x9E1E, 0xEA61, 0x9E75, 0xEA62, 0x9E78, 0x8CB2, 0x9E79, 0xEA63, 0x9E7D, 0xEA64, 0x9E7F, 0x8EAD, 0x9E81, 0xEA65, 0x9E88, 0xEA66, 0x9E8B, 0xEA67, 0x9E8C, 0xEA68, 0x9E91, 0xEA6B, 0x9E92, 0xEA69, 0x9E93, 0x985B, 0x9E95, 0xEA6A, 0x9E97, 0x97ED, 0x9E9D, 0xEA6C, 0x9E9F, 0x97D9, 0x9EA5, 0xEA6D, 0x9EA6, 0x949E, 0x9EA9, 0xEA6E, 0x9EAA, 0xEA70, 0x9EAD, 0xEA71, 0x9EB8, 0xEA6F, 0x9EB9, 0x8D8D, 0x9EBA, 0x96CB, 0x9EBB, 0x9683, 0x9EBC, 0x9BF5, 0x9EBE, 0x9F80, 0x9EBF, 0x969B, 0x9EC4, 0x89A9, 0x9ECC, 0xEA73, 0x9ECD, 0x8B6F, 0x9ECE, 0xEA74, 0x9ECF, 0xEA75, 0x9ED0, 0xEA76, 0x9ED1, 0xFC4B, 0x9ED2, 0x8D95, 0x9ED4, 0xEA77, 0x9ED8, 0xE0D2, 0x9ED9, 0x96D9, 0x9EDB, 0x91E1, 0x9EDC, 0xEA78, 0x9EDD, 0xEA7A, 0x9EDE, 0xEA79, 0x9EE0, 0xEA7B, 0x9EE5, 0xEA7C, 0x9EE8, 0xEA7D, 0x9EEF, 0xEA7E, 0x9EF4, 0xEA80, 0x9EF6, 0xEA81, 0x9EF7, 0xEA82, 0x9EF9, 0xEA83, 0x9EFB, 0xEA84, 0x9EFC, 0xEA85, 0x9EFD, 0xEA86, 0x9F07, 0xEA87, 0x9F08, 0xEA88, 0x9F0E, 0x9343, 0x9F13, 0x8CDB, 0x9F15, 0xEA8A, 0x9F20, 0x916C, 0x9F21, 0xEA8B, 0x9F2C, 0xEA8C, 0x9F3B, 0x9540, 0x9F3E, 0xEA8D, 0x9F4A, 0xEA8E, 0x9F4B, 0xE256, 0x9F4E, 0xE6D8, 0x9F4F, 0xE8EB, 0x9F52, 0xEA8F, 0x9F54, 0xEA90, 0x9F5F, 0xEA92, 0x9F60, 0xEA93, 0x9F61, 0xEA94, 0x9F62, 0x97EE, 0x9F63, 0xEA91, 0x9F66, 0xEA95, 0x9F67, 0xEA96, 0x9F6A, 0xEA98, 0x9F6C, 0xEA97, 0x9F72, 0xEA9A, 0x9F76, 0xEA9B, 0x9F77, 0xEA99, 0x9F8D, 0x97B4, 0x9F95, 0xEA9C, 0x9F9C, 0xEA9D, 0x9F9D, 0xE273, 0x9FA0, 0xEA9E, 0xF929, 0xFAE0, 0xF9DC, 0xFBE9, 0xFA0E, 0xFA90, 0xFA0F, 0xFA9B, 0xFA10, 0xFA9C, 0xFA11, 0xFAB1, 0xFA12, 0xFAD8, 0xFA13, 0xFAE8, 0xFA14, 0xFAEA, 0xFA15, 0xFB58, 0xFA16, 0xFB5E, 0xFA17, 0xFB75, 0xFA18, 0xFB7D, 0xFA19, 0xFB7E, 0xFA1A, 0xFB80, 0xFA1B, 0xFB82, 0xFA1C, 0xFB86, 0xFA1D, 0xFB89, 0xFA1E, 0xFB92, 0xFA1F, 0xFB9D, 0xFA20, 0xFB9F, 0xFA21, 0xFBA0, 0xFA22, 0xFBA9, 0xFA23, 0xFBB1, 0xFA24, 0xFBB3, 0xFA25, 0xFBB4, 0xFA26, 0xFBB7, 0xFA27, 0xFBD3, 0xFA28, 0xFBDA, 0xFA29, 0xFBEA, 0xFA2A, 0xFBF6, 0xFA2B, 0xFBF7, 0xFA2C, 0xFBF9, 0xFA2D, 0xFC49, 0xFF01, 0x8149, 0xFF02, 0xFA57, 0xFF03, 0x8194, 0xFF04, 0x8190, 0xFF05, 0x8193, 0xFF06, 0x8195, 0xFF07, 0xFA56, 0xFF08, 0x8169, 0xFF09, 0x816A, 0xFF0A, 0x8196, 0xFF0B, 0x817B, 0xFF0C, 0x8143, 0xFF0D, 0x817C, 0xFF0E, 0x8144, 0xFF0F, 0x815E, 0xFF10, 0x824F, 0xFF11, 0x8250, 0xFF12, 0x8251, 0xFF13, 0x8252, 0xFF14, 0x8253, 0xFF15, 0x8254, 0xFF16, 0x8255, 0xFF17, 0x8256, 0xFF18, 0x8257, 0xFF19, 0x8258, 0xFF1A, 0x8146, 0xFF1B, 0x8147, 0xFF1C, 0x8183, 0xFF1D, 0x8181, 0xFF1E, 0x8184, 0xFF1F, 0x8148, 0xFF20, 0x8197, 0xFF21, 0x8260, 0xFF22, 0x8261, 0xFF23, 0x8262, 0xFF24, 0x8263, 0xFF25, 0x8264, 0xFF26, 0x8265, 0xFF27, 0x8266, 0xFF28, 0x8267, 0xFF29, 0x8268, 0xFF2A, 0x8269, 0xFF2B, 0x826A, 0xFF2C, 0x826B, 0xFF2D, 0x826C, 0xFF2E, 0x826D, 0xFF2F, 0x826E, 0xFF30, 0x826F, 0xFF31, 0x8270, 0xFF32, 0x8271, 0xFF33, 0x8272, 0xFF34, 0x8273, 0xFF35, 0x8274, 0xFF36, 0x8275, 0xFF37, 0x8276, 0xFF38, 0x8277, 0xFF39, 0x8278, 0xFF3A, 0x8279, 0xFF3B, 0x816D, 0xFF3C, 0x815F, 0xFF3D, 0x816E, 0xFF3E, 0x814F, 0xFF3F, 0x8151, 0xFF40, 0x814D, 0xFF41, 0x8281, 0xFF42, 0x8282, 0xFF43, 0x8283, 0xFF44, 0x8284, 0xFF45, 0x8285, 0xFF46, 0x8286, 0xFF47, 0x8287, 0xFF48, 0x8288, 0xFF49, 0x8289, 0xFF4A, 0x828A, 0xFF4B, 0x828B, 0xFF4C, 0x828C, 0xFF4D, 0x828D, 0xFF4E, 0x828E, 0xFF4F, 0x828F, 0xFF50, 0x8290, 0xFF51, 0x8291, 0xFF52, 0x8292, 0xFF53, 0x8293, 0xFF54, 0x8294, 0xFF55, 0x8295, 0xFF56, 0x8296, 0xFF57, 0x8297, 0xFF58, 0x8298, 0xFF59, 0x8299, 0xFF5A, 0x829A, 0xFF5B, 0x816F, 0xFF5C, 0x8162, 0xFF5D, 0x8170, 0xFF5E, 0x8160, 0xFF61, 0x00A1, 0xFF62, 0x00A2, 0xFF63, 0x00A3, 0xFF64, 0x00A4, 0xFF65, 0x00A5, 0xFF66, 0x00A6, 0xFF67, 0x00A7, 0xFF68, 0x00A8, 0xFF69, 0x00A9, 0xFF6A, 0x00AA, 0xFF6B, 0x00AB, 0xFF6C, 0x00AC, 0xFF6D, 0x00AD, 0xFF6E, 0x00AE, 0xFF6F, 0x00AF, 0xFF70, 0x00B0, 0xFF71, 0x00B1, 0xFF72, 0x00B2, 0xFF73, 0x00B3, 0xFF74, 0x00B4, 0xFF75, 0x00B5, 0xFF76, 0x00B6, 0xFF77, 0x00B7, 0xFF78, 0x00B8, 0xFF79, 0x00B9, 0xFF7A, 0x00BA, 0xFF7B, 0x00BB, 0xFF7C, 0x00BC, 0xFF7D, 0x00BD, 0xFF7E, 0x00BE, 0xFF7F, 0x00BF, 0xFF80, 0x00C0, 0xFF81, 0x00C1, 0xFF82, 0x00C2, 0xFF83, 0x00C3, 0xFF84, 0x00C4, 0xFF85, 0x00C5, 0xFF86, 0x00C6, 0xFF87, 0x00C7, 0xFF88, 0x00C8, 0xFF89, 0x00C9, 0xFF8A, 0x00CA, 0xFF8B, 0x00CB, 0xFF8C, 0x00CC, 0xFF8D, 0x00CD, 0xFF8E, 0x00CE, 0xFF8F, 0x00CF, 0xFF90, 0x00D0, 0xFF91, 0x00D1, 0xFF92, 0x00D2, 0xFF93, 0x00D3, 0xFF94, 0x00D4, 0xFF95, 0x00D5, 0xFF96, 0x00D6, 0xFF97, 0x00D7, 0xFF98, 0x00D8, 0xFF99, 0x00D9, 0xFF9A, 0x00DA, 0xFF9B, 0x00DB, 0xFF9C, 0x00DC, 0xFF9D, 0x00DD, 0xFF9E, 0x00DE, 0xFF9F, 0x00DF, 0xFFE0, 0x8191, 0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0 }; static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ 0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68, 0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70, 0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78, 0x00B9, 0xFF79, 0x00BA, 0xFF7A, 0x00BB, 0xFF7B, 0x00BC, 0xFF7C, 0x00BD, 0xFF7D, 0x00BE, 0xFF7E, 0x00BF, 0xFF7F, 0x00C0, 0xFF80, 0x00C1, 0xFF81, 0x00C2, 0xFF82, 0x00C3, 0xFF83, 0x00C4, 0xFF84, 0x00C5, 0xFF85, 0x00C6, 0xFF86, 0x00C7, 0xFF87, 0x00C8, 0xFF88, 0x00C9, 0xFF89, 0x00CA, 0xFF8A, 0x00CB, 0xFF8B, 0x00CC, 0xFF8C, 0x00CD, 0xFF8D, 0x00CE, 0xFF8E, 0x00CF, 0xFF8F, 0x00D0, 0xFF90, 0x00D1, 0xFF91, 0x00D2, 0xFF92, 0x00D3, 0xFF93, 0x00D4, 0xFF94, 0x00D5, 0xFF95, 0x00D6, 0xFF96, 0x00D7, 0xFF97, 0x00D8, 0xFF98, 0x00D9, 0xFF99, 0x00DA, 0xFF9A, 0x00DB, 0xFF9B, 0x00DC, 0xFF9C, 0x00DD, 0xFF9D, 0x00DE, 0xFF9E, 0x00DF, 0xFF9F, 0x8140, 0x3000, 0x8141, 0x3001, 0x8142, 0x3002, 0x8143, 0xFF0C, 0x8144, 0xFF0E, 0x8145, 0x30FB, 0x8146, 0xFF1A, 0x8147, 0xFF1B, 0x8148, 0xFF1F, 0x8149, 0xFF01, 0x814A, 0x309B, 0x814B, 0x309C, 0x814C, 0x00B4, 0x814D, 0xFF40, 0x814E, 0x00A8, 0x814F, 0xFF3E, 0x8150, 0xFFE3, 0x8151, 0xFF3F, 0x8152, 0x30FD, 0x8153, 0x30FE, 0x8154, 0x309D, 0x8155, 0x309E, 0x8156, 0x3003, 0x8157, 0x4EDD, 0x8158, 0x3005, 0x8159, 0x3006, 0x815A, 0x3007, 0x815B, 0x30FC, 0x815C, 0x2015, 0x815D, 0x2010, 0x815E, 0xFF0F, 0x815F, 0xFF3C, 0x8160, 0xFF5E, 0x8161, 0x2225, 0x8162, 0xFF5C, 0x8163, 0x2026, 0x8164, 0x2025, 0x8165, 0x2018, 0x8166, 0x2019, 0x8167, 0x201C, 0x8168, 0x201D, 0x8169, 0xFF08, 0x816A, 0xFF09, 0x816B, 0x3014, 0x816C, 0x3015, 0x816D, 0xFF3B, 0x816E, 0xFF3D, 0x816F, 0xFF5B, 0x8170, 0xFF5D, 0x8171, 0x3008, 0x8172, 0x3009, 0x8173, 0x300A, 0x8174, 0x300B, 0x8175, 0x300C, 0x8176, 0x300D, 0x8177, 0x300E, 0x8178, 0x300F, 0x8179, 0x3010, 0x817A, 0x3011, 0x817B, 0xFF0B, 0x817C, 0xFF0D, 0x817D, 0x00B1, 0x817E, 0x00D7, 0x8180, 0x00F7, 0x8181, 0xFF1D, 0x8182, 0x2260, 0x8183, 0xFF1C, 0x8184, 0xFF1E, 0x8185, 0x2266, 0x8186, 0x2267, 0x8187, 0x221E, 0x8188, 0x2234, 0x8189, 0x2642, 0x818A, 0x2640, 0x818B, 0x00B0, 0x818C, 0x2032, 0x818D, 0x2033, 0x818E, 0x2103, 0x818F, 0xFFE5, 0x8190, 0xFF04, 0x8191, 0xFFE0, 0x8192, 0xFFE1, 0x8193, 0xFF05, 0x8194, 0xFF03, 0x8195, 0xFF06, 0x8196, 0xFF0A, 0x8197, 0xFF20, 0x8198, 0x00A7, 0x8199, 0x2606, 0x819A, 0x2605, 0x819B, 0x25CB, 0x819C, 0x25CF, 0x819D, 0x25CE, 0x819E, 0x25C7, 0x819F, 0x25C6, 0x81A0, 0x25A1, 0x81A1, 0x25A0, 0x81A2, 0x25B3, 0x81A3, 0x25B2, 0x81A4, 0x25BD, 0x81A5, 0x25BC, 0x81A6, 0x203B, 0x81A7, 0x3012, 0x81A8, 0x2192, 0x81A9, 0x2190, 0x81AA, 0x2191, 0x81AB, 0x2193, 0x81AC, 0x3013, 0x81B8, 0x2208, 0x81B9, 0x220B, 0x81BA, 0x2286, 0x81BB, 0x2287, 0x81BC, 0x2282, 0x81BD, 0x2283, 0x81BE, 0x222A, 0x81BF, 0x2229, 0x81C8, 0x2227, 0x81C9, 0x2228, 0x81CA, 0xFFE2, 0x81CB, 0x21D2, 0x81CC, 0x21D4, 0x81CD, 0x2200, 0x81CE, 0x2203, 0x81DA, 0x2220, 0x81DB, 0x22A5, 0x81DC, 0x2312, 0x81DD, 0x2202, 0x81DE, 0x2207, 0x81DF, 0x2261, 0x81E0, 0x2252, 0x81E1, 0x226A, 0x81E2, 0x226B, 0x81E3, 0x221A, 0x81E4, 0x223D, 0x81E5, 0x221D, 0x81E6, 0x2235, 0x81E7, 0x222B, 0x81E8, 0x222C, 0x81F0, 0x212B, 0x81F1, 0x2030, 0x81F2, 0x266F, 0x81F3, 0x266D, 0x81F4, 0x266A, 0x81F5, 0x2020, 0x81F6, 0x2021, 0x81F7, 0x00B6, 0x81FC, 0x25EF, 0x824F, 0xFF10, 0x8250, 0xFF11, 0x8251, 0xFF12, 0x8252, 0xFF13, 0x8253, 0xFF14, 0x8254, 0xFF15, 0x8255, 0xFF16, 0x8256, 0xFF17, 0x8257, 0xFF18, 0x8258, 0xFF19, 0x8260, 0xFF21, 0x8261, 0xFF22, 0x8262, 0xFF23, 0x8263, 0xFF24, 0x8264, 0xFF25, 0x8265, 0xFF26, 0x8266, 0xFF27, 0x8267, 0xFF28, 0x8268, 0xFF29, 0x8269, 0xFF2A, 0x826A, 0xFF2B, 0x826B, 0xFF2C, 0x826C, 0xFF2D, 0x826D, 0xFF2E, 0x826E, 0xFF2F, 0x826F, 0xFF30, 0x8270, 0xFF31, 0x8271, 0xFF32, 0x8272, 0xFF33, 0x8273, 0xFF34, 0x8274, 0xFF35, 0x8275, 0xFF36, 0x8276, 0xFF37, 0x8277, 0xFF38, 0x8278, 0xFF39, 0x8279, 0xFF3A, 0x8281, 0xFF41, 0x8282, 0xFF42, 0x8283, 0xFF43, 0x8284, 0xFF44, 0x8285, 0xFF45, 0x8286, 0xFF46, 0x8287, 0xFF47, 0x8288, 0xFF48, 0x8289, 0xFF49, 0x828A, 0xFF4A, 0x828B, 0xFF4B, 0x828C, 0xFF4C, 0x828D, 0xFF4D, 0x828E, 0xFF4E, 0x828F, 0xFF4F, 0x8290, 0xFF50, 0x8291, 0xFF51, 0x8292, 0xFF52, 0x8293, 0xFF53, 0x8294, 0xFF54, 0x8295, 0xFF55, 0x8296, 0xFF56, 0x8297, 0xFF57, 0x8298, 0xFF58, 0x8299, 0xFF59, 0x829A, 0xFF5A, 0x829F, 0x3041, 0x82A0, 0x3042, 0x82A1, 0x3043, 0x82A2, 0x3044, 0x82A3, 0x3045, 0x82A4, 0x3046, 0x82A5, 0x3047, 0x82A6, 0x3048, 0x82A7, 0x3049, 0x82A8, 0x304A, 0x82A9, 0x304B, 0x82AA, 0x304C, 0x82AB, 0x304D, 0x82AC, 0x304E, 0x82AD, 0x304F, 0x82AE, 0x3050, 0x82AF, 0x3051, 0x82B0, 0x3052, 0x82B1, 0x3053, 0x82B2, 0x3054, 0x82B3, 0x3055, 0x82B4, 0x3056, 0x82B5, 0x3057, 0x82B6, 0x3058, 0x82B7, 0x3059, 0x82B8, 0x305A, 0x82B9, 0x305B, 0x82BA, 0x305C, 0x82BB, 0x305D, 0x82BC, 0x305E, 0x82BD, 0x305F, 0x82BE, 0x3060, 0x82BF, 0x3061, 0x82C0, 0x3062, 0x82C1, 0x3063, 0x82C2, 0x3064, 0x82C3, 0x3065, 0x82C4, 0x3066, 0x82C5, 0x3067, 0x82C6, 0x3068, 0x82C7, 0x3069, 0x82C8, 0x306A, 0x82C9, 0x306B, 0x82CA, 0x306C, 0x82CB, 0x306D, 0x82CC, 0x306E, 0x82CD, 0x306F, 0x82CE, 0x3070, 0x82CF, 0x3071, 0x82D0, 0x3072, 0x82D1, 0x3073, 0x82D2, 0x3074, 0x82D3, 0x3075, 0x82D4, 0x3076, 0x82D5, 0x3077, 0x82D6, 0x3078, 0x82D7, 0x3079, 0x82D8, 0x307A, 0x82D9, 0x307B, 0x82DA, 0x307C, 0x82DB, 0x307D, 0x82DC, 0x307E, 0x82DD, 0x307F, 0x82DE, 0x3080, 0x82DF, 0x3081, 0x82E0, 0x3082, 0x82E1, 0x3083, 0x82E2, 0x3084, 0x82E3, 0x3085, 0x82E4, 0x3086, 0x82E5, 0x3087, 0x82E6, 0x3088, 0x82E7, 0x3089, 0x82E8, 0x308A, 0x82E9, 0x308B, 0x82EA, 0x308C, 0x82EB, 0x308D, 0x82EC, 0x308E, 0x82ED, 0x308F, 0x82EE, 0x3090, 0x82EF, 0x3091, 0x82F0, 0x3092, 0x82F1, 0x3093, 0x8340, 0x30A1, 0x8341, 0x30A2, 0x8342, 0x30A3, 0x8343, 0x30A4, 0x8344, 0x30A5, 0x8345, 0x30A6, 0x8346, 0x30A7, 0x8347, 0x30A8, 0x8348, 0x30A9, 0x8349, 0x30AA, 0x834A, 0x30AB, 0x834B, 0x30AC, 0x834C, 0x30AD, 0x834D, 0x30AE, 0x834E, 0x30AF, 0x834F, 0x30B0, 0x8350, 0x30B1, 0x8351, 0x30B2, 0x8352, 0x30B3, 0x8353, 0x30B4, 0x8354, 0x30B5, 0x8355, 0x30B6, 0x8356, 0x30B7, 0x8357, 0x30B8, 0x8358, 0x30B9, 0x8359, 0x30BA, 0x835A, 0x30BB, 0x835B, 0x30BC, 0x835C, 0x30BD, 0x835D, 0x30BE, 0x835E, 0x30BF, 0x835F, 0x30C0, 0x8360, 0x30C1, 0x8361, 0x30C2, 0x8362, 0x30C3, 0x8363, 0x30C4, 0x8364, 0x30C5, 0x8365, 0x30C6, 0x8366, 0x30C7, 0x8367, 0x30C8, 0x8368, 0x30C9, 0x8369, 0x30CA, 0x836A, 0x30CB, 0x836B, 0x30CC, 0x836C, 0x30CD, 0x836D, 0x30CE, 0x836E, 0x30CF, 0x836F, 0x30D0, 0x8370, 0x30D1, 0x8371, 0x30D2, 0x8372, 0x30D3, 0x8373, 0x30D4, 0x8374, 0x30D5, 0x8375, 0x30D6, 0x8376, 0x30D7, 0x8377, 0x30D8, 0x8378, 0x30D9, 0x8379, 0x30DA, 0x837A, 0x30DB, 0x837B, 0x30DC, 0x837C, 0x30DD, 0x837D, 0x30DE, 0x837E, 0x30DF, 0x8380, 0x30E0, 0x8381, 0x30E1, 0x8382, 0x30E2, 0x8383, 0x30E3, 0x8384, 0x30E4, 0x8385, 0x30E5, 0x8386, 0x30E6, 0x8387, 0x30E7, 0x8388, 0x30E8, 0x8389, 0x30E9, 0x838A, 0x30EA, 0x838B, 0x30EB, 0x838C, 0x30EC, 0x838D, 0x30ED, 0x838E, 0x30EE, 0x838F, 0x30EF, 0x8390, 0x30F0, 0x8391, 0x30F1, 0x8392, 0x30F2, 0x8393, 0x30F3, 0x8394, 0x30F4, 0x8395, 0x30F5, 0x8396, 0x30F6, 0x839F, 0x0391, 0x83A0, 0x0392, 0x83A1, 0x0393, 0x83A2, 0x0394, 0x83A3, 0x0395, 0x83A4, 0x0396, 0x83A5, 0x0397, 0x83A6, 0x0398, 0x83A7, 0x0399, 0x83A8, 0x039A, 0x83A9, 0x039B, 0x83AA, 0x039C, 0x83AB, 0x039D, 0x83AC, 0x039E, 0x83AD, 0x039F, 0x83AE, 0x03A0, 0x83AF, 0x03A1, 0x83B0, 0x03A3, 0x83B1, 0x03A4, 0x83B2, 0x03A5, 0x83B3, 0x03A6, 0x83B4, 0x03A7, 0x83B5, 0x03A8, 0x83B6, 0x03A9, 0x83BF, 0x03B1, 0x83C0, 0x03B2, 0x83C1, 0x03B3, 0x83C2, 0x03B4, 0x83C3, 0x03B5, 0x83C4, 0x03B6, 0x83C5, 0x03B7, 0x83C6, 0x03B8, 0x83C7, 0x03B9, 0x83C8, 0x03BA, 0x83C9, 0x03BB, 0x83CA, 0x03BC, 0x83CB, 0x03BD, 0x83CC, 0x03BE, 0x83CD, 0x03BF, 0x83CE, 0x03C0, 0x83CF, 0x03C1, 0x83D0, 0x03C3, 0x83D1, 0x03C4, 0x83D2, 0x03C5, 0x83D3, 0x03C6, 0x83D4, 0x03C7, 0x83D5, 0x03C8, 0x83D6, 0x03C9, 0x8440, 0x0410, 0x8441, 0x0411, 0x8442, 0x0412, 0x8443, 0x0413, 0x8444, 0x0414, 0x8445, 0x0415, 0x8446, 0x0401, 0x8447, 0x0416, 0x8448, 0x0417, 0x8449, 0x0418, 0x844A, 0x0419, 0x844B, 0x041A, 0x844C, 0x041B, 0x844D, 0x041C, 0x844E, 0x041D, 0x844F, 0x041E, 0x8450, 0x041F, 0x8451, 0x0420, 0x8452, 0x0421, 0x8453, 0x0422, 0x8454, 0x0423, 0x8455, 0x0424, 0x8456, 0x0425, 0x8457, 0x0426, 0x8458, 0x0427, 0x8459, 0x0428, 0x845A, 0x0429, 0x845B, 0x042A, 0x845C, 0x042B, 0x845D, 0x042C, 0x845E, 0x042D, 0x845F, 0x042E, 0x8460, 0x042F, 0x8470, 0x0430, 0x8471, 0x0431, 0x8472, 0x0432, 0x8473, 0x0433, 0x8474, 0x0434, 0x8475, 0x0435, 0x8476, 0x0451, 0x8477, 0x0436, 0x8478, 0x0437, 0x8479, 0x0438, 0x847A, 0x0439, 0x847B, 0x043A, 0x847C, 0x043B, 0x847D, 0x043C, 0x847E, 0x043D, 0x8480, 0x043E, 0x8481, 0x043F, 0x8482, 0x0440, 0x8483, 0x0441, 0x8484, 0x0442, 0x8485, 0x0443, 0x8486, 0x0444, 0x8487, 0x0445, 0x8488, 0x0446, 0x8489, 0x0447, 0x848A, 0x0448, 0x848B, 0x0449, 0x848C, 0x044A, 0x848D, 0x044B, 0x848E, 0x044C, 0x848F, 0x044D, 0x8490, 0x044E, 0x8491, 0x044F, 0x849F, 0x2500, 0x84A0, 0x2502, 0x84A1, 0x250C, 0x84A2, 0x2510, 0x84A3, 0x2518, 0x84A4, 0x2514, 0x84A5, 0x251C, 0x84A6, 0x252C, 0x84A7, 0x2524, 0x84A8, 0x2534, 0x84A9, 0x253C, 0x84AA, 0x2501, 0x84AB, 0x2503, 0x84AC, 0x250F, 0x84AD, 0x2513, 0x84AE, 0x251B, 0x84AF, 0x2517, 0x84B0, 0x2523, 0x84B1, 0x2533, 0x84B2, 0x252B, 0x84B3, 0x253B, 0x84B4, 0x254B, 0x84B5, 0x2520, 0x84B6, 0x252F, 0x84B7, 0x2528, 0x84B8, 0x2537, 0x84B9, 0x253F, 0x84BA, 0x251D, 0x84BB, 0x2530, 0x84BC, 0x2525, 0x84BD, 0x2538, 0x84BE, 0x2542, 0x8740, 0x2460, 0x8741, 0x2461, 0x8742, 0x2462, 0x8743, 0x2463, 0x8744, 0x2464, 0x8745, 0x2465, 0x8746, 0x2466, 0x8747, 0x2467, 0x8748, 0x2468, 0x8749, 0x2469, 0x874A, 0x246A, 0x874B, 0x246B, 0x874C, 0x246C, 0x874D, 0x246D, 0x874E, 0x246E, 0x874F, 0x246F, 0x8750, 0x2470, 0x8751, 0x2471, 0x8752, 0x2472, 0x8753, 0x2473, 0x8754, 0x2160, 0x8755, 0x2161, 0x8756, 0x2162, 0x8757, 0x2163, 0x8758, 0x2164, 0x8759, 0x2165, 0x875A, 0x2166, 0x875B, 0x2167, 0x875C, 0x2168, 0x875D, 0x2169, 0x875F, 0x3349, 0x8760, 0x3314, 0x8761, 0x3322, 0x8762, 0x334D, 0x8763, 0x3318, 0x8764, 0x3327, 0x8765, 0x3303, 0x8766, 0x3336, 0x8767, 0x3351, 0x8768, 0x3357, 0x8769, 0x330D, 0x876A, 0x3326, 0x876B, 0x3323, 0x876C, 0x332B, 0x876D, 0x334A, 0x876E, 0x333B, 0x876F, 0x339C, 0x8770, 0x339D, 0x8771, 0x339E, 0x8772, 0x338E, 0x8773, 0x338F, 0x8774, 0x33C4, 0x8775, 0x33A1, 0x877E, 0x337B, 0x8780, 0x301D, 0x8781, 0x301F, 0x8782, 0x2116, 0x8783, 0x33CD, 0x8784, 0x2121, 0x8785, 0x32A4, 0x8786, 0x32A5, 0x8787, 0x32A6, 0x8788, 0x32A7, 0x8789, 0x32A8, 0x878A, 0x3231, 0x878B, 0x3232, 0x878C, 0x3239, 0x878D, 0x337E, 0x878E, 0x337D, 0x878F, 0x337C, 0x8793, 0x222E, 0x8794, 0x2211, 0x8798, 0x221F, 0x8799, 0x22BF, 0x889F, 0x4E9C, 0x88A0, 0x5516, 0x88A1, 0x5A03, 0x88A2, 0x963F, 0x88A3, 0x54C0, 0x88A4, 0x611B, 0x88A5, 0x6328, 0x88A6, 0x59F6, 0x88A7, 0x9022, 0x88A8, 0x8475, 0x88A9, 0x831C, 0x88AA, 0x7A50, 0x88AB, 0x60AA, 0x88AC, 0x63E1, 0x88AD, 0x6E25, 0x88AE, 0x65ED, 0x88AF, 0x8466, 0x88B0, 0x82A6, 0x88B1, 0x9BF5, 0x88B2, 0x6893, 0x88B3, 0x5727, 0x88B4, 0x65A1, 0x88B5, 0x6271, 0x88B6, 0x5B9B, 0x88B7, 0x59D0, 0x88B8, 0x867B, 0x88B9, 0x98F4, 0x88BA, 0x7D62, 0x88BB, 0x7DBE, 0x88BC, 0x9B8E, 0x88BD, 0x6216, 0x88BE, 0x7C9F, 0x88BF, 0x88B7, 0x88C0, 0x5B89, 0x88C1, 0x5EB5, 0x88C2, 0x6309, 0x88C3, 0x6697, 0x88C4, 0x6848, 0x88C5, 0x95C7, 0x88C6, 0x978D, 0x88C7, 0x674F, 0x88C8, 0x4EE5, 0x88C9, 0x4F0A, 0x88CA, 0x4F4D, 0x88CB, 0x4F9D, 0x88CC, 0x5049, 0x88CD, 0x56F2, 0x88CE, 0x5937, 0x88CF, 0x59D4, 0x88D0, 0x5A01, 0x88D1, 0x5C09, 0x88D2, 0x60DF, 0x88D3, 0x610F, 0x88D4, 0x6170, 0x88D5, 0x6613, 0x88D6, 0x6905, 0x88D7, 0x70BA, 0x88D8, 0x754F, 0x88D9, 0x7570, 0x88DA, 0x79FB, 0x88DB, 0x7DAD, 0x88DC, 0x7DEF, 0x88DD, 0x80C3, 0x88DE, 0x840E, 0x88DF, 0x8863, 0x88E0, 0x8B02, 0x88E1, 0x9055, 0x88E2, 0x907A, 0x88E3, 0x533B, 0x88E4, 0x4E95, 0x88E5, 0x4EA5, 0x88E6, 0x57DF, 0x88E7, 0x80B2, 0x88E8, 0x90C1, 0x88E9, 0x78EF, 0x88EA, 0x4E00, 0x88EB, 0x58F1, 0x88EC, 0x6EA2, 0x88ED, 0x9038, 0x88EE, 0x7A32, 0x88EF, 0x8328, 0x88F0, 0x828B, 0x88F1, 0x9C2F, 0x88F2, 0x5141, 0x88F3, 0x5370, 0x88F4, 0x54BD, 0x88F5, 0x54E1, 0x88F6, 0x56E0, 0x88F7, 0x59FB, 0x88F8, 0x5F15, 0x88F9, 0x98F2, 0x88FA, 0x6DEB, 0x88FB, 0x80E4, 0x88FC, 0x852D, 0x8940, 0x9662, 0x8941, 0x9670, 0x8942, 0x96A0, 0x8943, 0x97FB, 0x8944, 0x540B, 0x8945, 0x53F3, 0x8946, 0x5B87, 0x8947, 0x70CF, 0x8948, 0x7FBD, 0x8949, 0x8FC2, 0x894A, 0x96E8, 0x894B, 0x536F, 0x894C, 0x9D5C, 0x894D, 0x7ABA, 0x894E, 0x4E11, 0x894F, 0x7893, 0x8950, 0x81FC, 0x8951, 0x6E26, 0x8952, 0x5618, 0x8953, 0x5504, 0x8954, 0x6B1D, 0x8955, 0x851A, 0x8956, 0x9C3B, 0x8957, 0x59E5, 0x8958, 0x53A9, 0x8959, 0x6D66, 0x895A, 0x74DC, 0x895B, 0x958F, 0x895C, 0x5642, 0x895D, 0x4E91, 0x895E, 0x904B, 0x895F, 0x96F2, 0x8960, 0x834F, 0x8961, 0x990C, 0x8962, 0x53E1, 0x8963, 0x55B6, 0x8964, 0x5B30, 0x8965, 0x5F71, 0x8966, 0x6620, 0x8967, 0x66F3, 0x8968, 0x6804, 0x8969, 0x6C38, 0x896A, 0x6CF3, 0x896B, 0x6D29, 0x896C, 0x745B, 0x896D, 0x76C8, 0x896E, 0x7A4E, 0x896F, 0x9834, 0x8970, 0x82F1, 0x8971, 0x885B, 0x8972, 0x8A60, 0x8973, 0x92ED, 0x8974, 0x6DB2, 0x8975, 0x75AB, 0x8976, 0x76CA, 0x8977, 0x99C5, 0x8978, 0x60A6, 0x8979, 0x8B01, 0x897A, 0x8D8A, 0x897B, 0x95B2, 0x897C, 0x698E, 0x897D, 0x53AD, 0x897E, 0x5186, 0x8980, 0x5712, 0x8981, 0x5830, 0x8982, 0x5944, 0x8983, 0x5BB4, 0x8984, 0x5EF6, 0x8985, 0x6028, 0x8986, 0x63A9, 0x8987, 0x63F4, 0x8988, 0x6CBF, 0x8989, 0x6F14, 0x898A, 0x708E, 0x898B, 0x7114, 0x898C, 0x7159, 0x898D, 0x71D5, 0x898E, 0x733F, 0x898F, 0x7E01, 0x8990, 0x8276, 0x8991, 0x82D1, 0x8992, 0x8597, 0x8993, 0x9060, 0x8994, 0x925B, 0x8995, 0x9D1B, 0x8996, 0x5869, 0x8997, 0x65BC, 0x8998, 0x6C5A, 0x8999, 0x7525, 0x899A, 0x51F9, 0x899B, 0x592E, 0x899C, 0x5965, 0x899D, 0x5F80, 0x899E, 0x5FDC, 0x899F, 0x62BC, 0x89A0, 0x65FA, 0x89A1, 0x6A2A, 0x89A2, 0x6B27, 0x89A3, 0x6BB4, 0x89A4, 0x738B, 0x89A5, 0x7FC1, 0x89A6, 0x8956, 0x89A7, 0x9D2C, 0x89A8, 0x9D0E, 0x89A9, 0x9EC4, 0x89AA, 0x5CA1, 0x89AB, 0x6C96, 0x89AC, 0x837B, 0x89AD, 0x5104, 0x89AE, 0x5C4B, 0x89AF, 0x61B6, 0x89B0, 0x81C6, 0x89B1, 0x6876, 0x89B2, 0x7261, 0x89B3, 0x4E59, 0x89B4, 0x4FFA, 0x89B5, 0x5378, 0x89B6, 0x6069, 0x89B7, 0x6E29, 0x89B8, 0x7A4F, 0x89B9, 0x97F3, 0x89BA, 0x4E0B, 0x89BB, 0x5316, 0x89BC, 0x4EEE, 0x89BD, 0x4F55, 0x89BE, 0x4F3D, 0x89BF, 0x4FA1, 0x89C0, 0x4F73, 0x89C1, 0x52A0, 0x89C2, 0x53EF, 0x89C3, 0x5609, 0x89C4, 0x590F, 0x89C5, 0x5AC1, 0x89C6, 0x5BB6, 0x89C7, 0x5BE1, 0x89C8, 0x79D1, 0x89C9, 0x6687, 0x89CA, 0x679C, 0x89CB, 0x67B6, 0x89CC, 0x6B4C, 0x89CD, 0x6CB3, 0x89CE, 0x706B, 0x89CF, 0x73C2, 0x89D0, 0x798D, 0x89D1, 0x79BE, 0x89D2, 0x7A3C, 0x89D3, 0x7B87, 0x89D4, 0x82B1, 0x89D5, 0x82DB, 0x89D6, 0x8304, 0x89D7, 0x8377, 0x89D8, 0x83EF, 0x89D9, 0x83D3, 0x89DA, 0x8766, 0x89DB, 0x8AB2, 0x89DC, 0x5629, 0x89DD, 0x8CA8, 0x89DE, 0x8FE6, 0x89DF, 0x904E, 0x89E0, 0x971E, 0x89E1, 0x868A, 0x89E2, 0x4FC4, 0x89E3, 0x5CE8, 0x89E4, 0x6211, 0x89E5, 0x7259, 0x89E6, 0x753B, 0x89E7, 0x81E5, 0x89E8, 0x82BD, 0x89E9, 0x86FE, 0x89EA, 0x8CC0, 0x89EB, 0x96C5, 0x89EC, 0x9913, 0x89ED, 0x99D5, 0x89EE, 0x4ECB, 0x89EF, 0x4F1A, 0x89F0, 0x89E3, 0x89F1, 0x56DE, 0x89F2, 0x584A, 0x89F3, 0x58CA, 0x89F4, 0x5EFB, 0x89F5, 0x5FEB, 0x89F6, 0x602A, 0x89F7, 0x6094, 0x89F8, 0x6062, 0x89F9, 0x61D0, 0x89FA, 0x6212, 0x89FB, 0x62D0, 0x89FC, 0x6539, 0x8A40, 0x9B41, 0x8A41, 0x6666, 0x8A42, 0x68B0, 0x8A43, 0x6D77, 0x8A44, 0x7070, 0x8A45, 0x754C, 0x8A46, 0x7686, 0x8A47, 0x7D75, 0x8A48, 0x82A5, 0x8A49, 0x87F9, 0x8A4A, 0x958B, 0x8A4B, 0x968E, 0x8A4C, 0x8C9D, 0x8A4D, 0x51F1, 0x8A4E, 0x52BE, 0x8A4F, 0x5916, 0x8A50, 0x54B3, 0x8A51, 0x5BB3, 0x8A52, 0x5D16, 0x8A53, 0x6168, 0x8A54, 0x6982, 0x8A55, 0x6DAF, 0x8A56, 0x788D, 0x8A57, 0x84CB, 0x8A58, 0x8857, 0x8A59, 0x8A72, 0x8A5A, 0x93A7, 0x8A5B, 0x9AB8, 0x8A5C, 0x6D6C, 0x8A5D, 0x99A8, 0x8A5E, 0x86D9, 0x8A5F, 0x57A3, 0x8A60, 0x67FF, 0x8A61, 0x86CE, 0x8A62, 0x920E, 0x8A63, 0x5283, 0x8A64, 0x5687, 0x8A65, 0x5404, 0x8A66, 0x5ED3, 0x8A67, 0x62E1, 0x8A68, 0x64B9, 0x8A69, 0x683C, 0x8A6A, 0x6838, 0x8A6B, 0x6BBB, 0x8A6C, 0x7372, 0x8A6D, 0x78BA, 0x8A6E, 0x7A6B, 0x8A6F, 0x899A, 0x8A70, 0x89D2, 0x8A71, 0x8D6B, 0x8A72, 0x8F03, 0x8A73, 0x90ED, 0x8A74, 0x95A3, 0x8A75, 0x9694, 0x8A76, 0x9769, 0x8A77, 0x5B66, 0x8A78, 0x5CB3, 0x8A79, 0x697D, 0x8A7A, 0x984D, 0x8A7B, 0x984E, 0x8A7C, 0x639B, 0x8A7D, 0x7B20, 0x8A7E, 0x6A2B, 0x8A80, 0x6A7F, 0x8A81, 0x68B6, 0x8A82, 0x9C0D, 0x8A83, 0x6F5F, 0x8A84, 0x5272, 0x8A85, 0x559D, 0x8A86, 0x6070, 0x8A87, 0x62EC, 0x8A88, 0x6D3B, 0x8A89, 0x6E07, 0x8A8A, 0x6ED1, 0x8A8B, 0x845B, 0x8A8C, 0x8910, 0x8A8D, 0x8F44, 0x8A8E, 0x4E14, 0x8A8F, 0x9C39, 0x8A90, 0x53F6, 0x8A91, 0x691B, 0x8A92, 0x6A3A, 0x8A93, 0x9784, 0x8A94, 0x682A, 0x8A95, 0x515C, 0x8A96, 0x7AC3, 0x8A97, 0x84B2, 0x8A98, 0x91DC, 0x8A99, 0x938C, 0x8A9A, 0x565B, 0x8A9B, 0x9D28, 0x8A9C, 0x6822, 0x8A9D, 0x8305, 0x8A9E, 0x8431, 0x8A9F, 0x7CA5, 0x8AA0, 0x5208, 0x8AA1, 0x82C5, 0x8AA2, 0x74E6, 0x8AA3, 0x4E7E, 0x8AA4, 0x4F83, 0x8AA5, 0x51A0, 0x8AA6, 0x5BD2, 0x8AA7, 0x520A, 0x8AA8, 0x52D8, 0x8AA9, 0x52E7, 0x8AAA, 0x5DFB, 0x8AAB, 0x559A, 0x8AAC, 0x582A, 0x8AAD, 0x59E6, 0x8AAE, 0x5B8C, 0x8AAF, 0x5B98, 0x8AB0, 0x5BDB, 0x8AB1, 0x5E72, 0x8AB2, 0x5E79, 0x8AB3, 0x60A3, 0x8AB4, 0x611F, 0x8AB5, 0x6163, 0x8AB6, 0x61BE, 0x8AB7, 0x63DB, 0x8AB8, 0x6562, 0x8AB9, 0x67D1, 0x8ABA, 0x6853, 0x8ABB, 0x68FA, 0x8ABC, 0x6B3E, 0x8ABD, 0x6B53, 0x8ABE, 0x6C57, 0x8ABF, 0x6F22, 0x8AC0, 0x6F97, 0x8AC1, 0x6F45, 0x8AC2, 0x74B0, 0x8AC3, 0x7518, 0x8AC4, 0x76E3, 0x8AC5, 0x770B, 0x8AC6, 0x7AFF, 0x8AC7, 0x7BA1, 0x8AC8, 0x7C21, 0x8AC9, 0x7DE9, 0x8ACA, 0x7F36, 0x8ACB, 0x7FF0, 0x8ACC, 0x809D, 0x8ACD, 0x8266, 0x8ACE, 0x839E, 0x8ACF, 0x89B3, 0x8AD0, 0x8ACC, 0x8AD1, 0x8CAB, 0x8AD2, 0x9084, 0x8AD3, 0x9451, 0x8AD4, 0x9593, 0x8AD5, 0x9591, 0x8AD6, 0x95A2, 0x8AD7, 0x9665, 0x8AD8, 0x97D3, 0x8AD9, 0x9928, 0x8ADA, 0x8218, 0x8ADB, 0x4E38, 0x8ADC, 0x542B, 0x8ADD, 0x5CB8, 0x8ADE, 0x5DCC, 0x8ADF, 0x73A9, 0x8AE0, 0x764C, 0x8AE1, 0x773C, 0x8AE2, 0x5CA9, 0x8AE3, 0x7FEB, 0x8AE4, 0x8D0B, 0x8AE5, 0x96C1, 0x8AE6, 0x9811, 0x8AE7, 0x9854, 0x8AE8, 0x9858, 0x8AE9, 0x4F01, 0x8AEA, 0x4F0E, 0x8AEB, 0x5371, 0x8AEC, 0x559C, 0x8AED, 0x5668, 0x8AEE, 0x57FA, 0x8AEF, 0x5947, 0x8AF0, 0x5B09, 0x8AF1, 0x5BC4, 0x8AF2, 0x5C90, 0x8AF3, 0x5E0C, 0x8AF4, 0x5E7E, 0x8AF5, 0x5FCC, 0x8AF6, 0x63EE, 0x8AF7, 0x673A, 0x8AF8, 0x65D7, 0x8AF9, 0x65E2, 0x8AFA, 0x671F, 0x8AFB, 0x68CB, 0x8AFC, 0x68C4, 0x8B40, 0x6A5F, 0x8B41, 0x5E30, 0x8B42, 0x6BC5, 0x8B43, 0x6C17, 0x8B44, 0x6C7D, 0x8B45, 0x757F, 0x8B46, 0x7948, 0x8B47, 0x5B63, 0x8B48, 0x7A00, 0x8B49, 0x7D00, 0x8B4A, 0x5FBD, 0x8B4B, 0x898F, 0x8B4C, 0x8A18, 0x8B4D, 0x8CB4, 0x8B4E, 0x8D77, 0x8B4F, 0x8ECC, 0x8B50, 0x8F1D, 0x8B51, 0x98E2, 0x8B52, 0x9A0E, 0x8B53, 0x9B3C, 0x8B54, 0x4E80, 0x8B55, 0x507D, 0x8B56, 0x5100, 0x8B57, 0x5993, 0x8B58, 0x5B9C, 0x8B59, 0x622F, 0x8B5A, 0x6280, 0x8B5B, 0x64EC, 0x8B5C, 0x6B3A, 0x8B5D, 0x72A0, 0x8B5E, 0x7591, 0x8B5F, 0x7947, 0x8B60, 0x7FA9, 0x8B61, 0x87FB, 0x8B62, 0x8ABC, 0x8B63, 0x8B70, 0x8B64, 0x63AC, 0x8B65, 0x83CA, 0x8B66, 0x97A0, 0x8B67, 0x5409, 0x8B68, 0x5403, 0x8B69, 0x55AB, 0x8B6A, 0x6854, 0x8B6B, 0x6A58, 0x8B6C, 0x8A70, 0x8B6D, 0x7827, 0x8B6E, 0x6775, 0x8B6F, 0x9ECD, 0x8B70, 0x5374, 0x8B71, 0x5BA2, 0x8B72, 0x811A, 0x8B73, 0x8650, 0x8B74, 0x9006, 0x8B75, 0x4E18, 0x8B76, 0x4E45, 0x8B77, 0x4EC7, 0x8B78, 0x4F11, 0x8B79, 0x53CA, 0x8B7A, 0x5438, 0x8B7B, 0x5BAE, 0x8B7C, 0x5F13, 0x8B7D, 0x6025, 0x8B7E, 0x6551, 0x8B80, 0x673D, 0x8B81, 0x6C42, 0x8B82, 0x6C72, 0x8B83, 0x6CE3, 0x8B84, 0x7078, 0x8B85, 0x7403, 0x8B86, 0x7A76, 0x8B87, 0x7AAE, 0x8B88, 0x7B08, 0x8B89, 0x7D1A, 0x8B8A, 0x7CFE, 0x8B8B, 0x7D66, 0x8B8C, 0x65E7, 0x8B8D, 0x725B, 0x8B8E, 0x53BB, 0x8B8F, 0x5C45, 0x8B90, 0x5DE8, 0x8B91, 0x62D2, 0x8B92, 0x62E0, 0x8B93, 0x6319, 0x8B94, 0x6E20, 0x8B95, 0x865A, 0x8B96, 0x8A31, 0x8B97, 0x8DDD, 0x8B98, 0x92F8, 0x8B99, 0x6F01, 0x8B9A, 0x79A6, 0x8B9B, 0x9B5A, 0x8B9C, 0x4EA8, 0x8B9D, 0x4EAB, 0x8B9E, 0x4EAC, 0x8B9F, 0x4F9B, 0x8BA0, 0x4FA0, 0x8BA1, 0x50D1, 0x8BA2, 0x5147, 0x8BA3, 0x7AF6, 0x8BA4, 0x5171, 0x8BA5, 0x51F6, 0x8BA6, 0x5354, 0x8BA7, 0x5321, 0x8BA8, 0x537F, 0x8BA9, 0x53EB, 0x8BAA, 0x55AC, 0x8BAB, 0x5883, 0x8BAC, 0x5CE1, 0x8BAD, 0x5F37, 0x8BAE, 0x5F4A, 0x8BAF, 0x602F, 0x8BB0, 0x6050, 0x8BB1, 0x606D, 0x8BB2, 0x631F, 0x8BB3, 0x6559, 0x8BB4, 0x6A4B, 0x8BB5, 0x6CC1, 0x8BB6, 0x72C2, 0x8BB7, 0x72ED, 0x8BB8, 0x77EF, 0x8BB9, 0x80F8, 0x8BBA, 0x8105, 0x8BBB, 0x8208, 0x8BBC, 0x854E, 0x8BBD, 0x90F7, 0x8BBE, 0x93E1, 0x8BBF, 0x97FF, 0x8BC0, 0x9957, 0x8BC1, 0x9A5A, 0x8BC2, 0x4EF0, 0x8BC3, 0x51DD, 0x8BC4, 0x5C2D, 0x8BC5, 0x6681, 0x8BC6, 0x696D, 0x8BC7, 0x5C40, 0x8BC8, 0x66F2, 0x8BC9, 0x6975, 0x8BCA, 0x7389, 0x8BCB, 0x6850, 0x8BCC, 0x7C81, 0x8BCD, 0x50C5, 0x8BCE, 0x52E4, 0x8BCF, 0x5747, 0x8BD0, 0x5DFE, 0x8BD1, 0x9326, 0x8BD2, 0x65A4, 0x8BD3, 0x6B23, 0x8BD4, 0x6B3D, 0x8BD5, 0x7434, 0x8BD6, 0x7981, 0x8BD7, 0x79BD, 0x8BD8, 0x7B4B, 0x8BD9, 0x7DCA, 0x8BDA, 0x82B9, 0x8BDB, 0x83CC, 0x8BDC, 0x887F, 0x8BDD, 0x895F, 0x8BDE, 0x8B39, 0x8BDF, 0x8FD1, 0x8BE0, 0x91D1, 0x8BE1, 0x541F, 0x8BE2, 0x9280, 0x8BE3, 0x4E5D, 0x8BE4, 0x5036, 0x8BE5, 0x53E5, 0x8BE6, 0x533A, 0x8BE7, 0x72D7, 0x8BE8, 0x7396, 0x8BE9, 0x77E9, 0x8BEA, 0x82E6, 0x8BEB, 0x8EAF, 0x8BEC, 0x99C6, 0x8BED, 0x99C8, 0x8BEE, 0x99D2, 0x8BEF, 0x5177, 0x8BF0, 0x611A, 0x8BF1, 0x865E, 0x8BF2, 0x55B0, 0x8BF3, 0x7A7A, 0x8BF4, 0x5076, 0x8BF5, 0x5BD3, 0x8BF6, 0x9047, 0x8BF7, 0x9685, 0x8BF8, 0x4E32, 0x8BF9, 0x6ADB, 0x8BFA, 0x91E7, 0x8BFB, 0x5C51, 0x8BFC, 0x5C48, 0x8C40, 0x6398, 0x8C41, 0x7A9F, 0x8C42, 0x6C93, 0x8C43, 0x9774, 0x8C44, 0x8F61, 0x8C45, 0x7AAA, 0x8C46, 0x718A, 0x8C47, 0x9688, 0x8C48, 0x7C82, 0x8C49, 0x6817, 0x8C4A, 0x7E70, 0x8C4B, 0x6851, 0x8C4C, 0x936C, 0x8C4D, 0x52F2, 0x8C4E, 0x541B, 0x8C4F, 0x85AB, 0x8C50, 0x8A13, 0x8C51, 0x7FA4, 0x8C52, 0x8ECD, 0x8C53, 0x90E1, 0x8C54, 0x5366, 0x8C55, 0x8888, 0x8C56, 0x7941, 0x8C57, 0x4FC2, 0x8C58, 0x50BE, 0x8C59, 0x5211, 0x8C5A, 0x5144, 0x8C5B, 0x5553, 0x8C5C, 0x572D, 0x8C5D, 0x73EA, 0x8C5E, 0x578B, 0x8C5F, 0x5951, 0x8C60, 0x5F62, 0x8C61, 0x5F84, 0x8C62, 0x6075, 0x8C63, 0x6176, 0x8C64, 0x6167, 0x8C65, 0x61A9, 0x8C66, 0x63B2, 0x8C67, 0x643A, 0x8C68, 0x656C, 0x8C69, 0x666F, 0x8C6A, 0x6842, 0x8C6B, 0x6E13, 0x8C6C, 0x7566, 0x8C6D, 0x7A3D, 0x8C6E, 0x7CFB, 0x8C6F, 0x7D4C, 0x8C70, 0x7D99, 0x8C71, 0x7E4B, 0x8C72, 0x7F6B, 0x8C73, 0x830E, 0x8C74, 0x834A, 0x8C75, 0x86CD, 0x8C76, 0x8A08, 0x8C77, 0x8A63, 0x8C78, 0x8B66, 0x8C79, 0x8EFD, 0x8C7A, 0x981A, 0x8C7B, 0x9D8F, 0x8C7C, 0x82B8, 0x8C7D, 0x8FCE, 0x8C7E, 0x9BE8, 0x8C80, 0x5287, 0x8C81, 0x621F, 0x8C82, 0x6483, 0x8C83, 0x6FC0, 0x8C84, 0x9699, 0x8C85, 0x6841, 0x8C86, 0x5091, 0x8C87, 0x6B20, 0x8C88, 0x6C7A, 0x8C89, 0x6F54, 0x8C8A, 0x7A74, 0x8C8B, 0x7D50, 0x8C8C, 0x8840, 0x8C8D, 0x8A23, 0x8C8E, 0x6708, 0x8C8F, 0x4EF6, 0x8C90, 0x5039, 0x8C91, 0x5026, 0x8C92, 0x5065, 0x8C93, 0x517C, 0x8C94, 0x5238, 0x8C95, 0x5263, 0x8C96, 0x55A7, 0x8C97, 0x570F, 0x8C98, 0x5805, 0x8C99, 0x5ACC, 0x8C9A, 0x5EFA, 0x8C9B, 0x61B2, 0x8C9C, 0x61F8, 0x8C9D, 0x62F3, 0x8C9E, 0x6372, 0x8C9F, 0x691C, 0x8CA0, 0x6A29, 0x8CA1, 0x727D, 0x8CA2, 0x72AC, 0x8CA3, 0x732E, 0x8CA4, 0x7814, 0x8CA5, 0x786F, 0x8CA6, 0x7D79, 0x8CA7, 0x770C, 0x8CA8, 0x80A9, 0x8CA9, 0x898B, 0x8CAA, 0x8B19, 0x8CAB, 0x8CE2, 0x8CAC, 0x8ED2, 0x8CAD, 0x9063, 0x8CAE, 0x9375, 0x8CAF, 0x967A, 0x8CB0, 0x9855, 0x8CB1, 0x9A13, 0x8CB2, 0x9E78, 0x8CB3, 0x5143, 0x8CB4, 0x539F, 0x8CB5, 0x53B3, 0x8CB6, 0x5E7B, 0x8CB7, 0x5F26, 0x8CB8, 0x6E1B, 0x8CB9, 0x6E90, 0x8CBA, 0x7384, 0x8CBB, 0x73FE, 0x8CBC, 0x7D43, 0x8CBD, 0x8237, 0x8CBE, 0x8A00, 0x8CBF, 0x8AFA, 0x8CC0, 0x9650, 0x8CC1, 0x4E4E, 0x8CC2, 0x500B, 0x8CC3, 0x53E4, 0x8CC4, 0x547C, 0x8CC5, 0x56FA, 0x8CC6, 0x59D1, 0x8CC7, 0x5B64, 0x8CC8, 0x5DF1, 0x8CC9, 0x5EAB, 0x8CCA, 0x5F27, 0x8CCB, 0x6238, 0x8CCC, 0x6545, 0x8CCD, 0x67AF, 0x8CCE, 0x6E56, 0x8CCF, 0x72D0, 0x8CD0, 0x7CCA, 0x8CD1, 0x88B4, 0x8CD2, 0x80A1, 0x8CD3, 0x80E1, 0x8CD4, 0x83F0, 0x8CD5, 0x864E, 0x8CD6, 0x8A87, 0x8CD7, 0x8DE8, 0x8CD8, 0x9237, 0x8CD9, 0x96C7, 0x8CDA, 0x9867, 0x8CDB, 0x9F13, 0x8CDC, 0x4E94, 0x8CDD, 0x4E92, 0x8CDE, 0x4F0D, 0x8CDF, 0x5348, 0x8CE0, 0x5449, 0x8CE1, 0x543E, 0x8CE2, 0x5A2F, 0x8CE3, 0x5F8C, 0x8CE4, 0x5FA1, 0x8CE5, 0x609F, 0x8CE6, 0x68A7, 0x8CE7, 0x6A8E, 0x8CE8, 0x745A, 0x8CE9, 0x7881, 0x8CEA, 0x8A9E, 0x8CEB, 0x8AA4, 0x8CEC, 0x8B77, 0x8CED, 0x9190, 0x8CEE, 0x4E5E, 0x8CEF, 0x9BC9, 0x8CF0, 0x4EA4, 0x8CF1, 0x4F7C, 0x8CF2, 0x4FAF, 0x8CF3, 0x5019, 0x8CF4, 0x5016, 0x8CF5, 0x5149, 0x8CF6, 0x516C, 0x8CF7, 0x529F, 0x8CF8, 0x52B9, 0x8CF9, 0x52FE, 0x8CFA, 0x539A, 0x8CFB, 0x53E3, 0x8CFC, 0x5411, 0x8D40, 0x540E, 0x8D41, 0x5589, 0x8D42, 0x5751, 0x8D43, 0x57A2, 0x8D44, 0x597D, 0x8D45, 0x5B54, 0x8D46, 0x5B5D, 0x8D47, 0x5B8F, 0x8D48, 0x5DE5, 0x8D49, 0x5DE7, 0x8D4A, 0x5DF7, 0x8D4B, 0x5E78, 0x8D4C, 0x5E83, 0x8D4D, 0x5E9A, 0x8D4E, 0x5EB7, 0x8D4F, 0x5F18, 0x8D50, 0x6052, 0x8D51, 0x614C, 0x8D52, 0x6297, 0x8D53, 0x62D8, 0x8D54, 0x63A7, 0x8D55, 0x653B, 0x8D56, 0x6602, 0x8D57, 0x6643, 0x8D58, 0x66F4, 0x8D59, 0x676D, 0x8D5A, 0x6821, 0x8D5B, 0x6897, 0x8D5C, 0x69CB, 0x8D5D, 0x6C5F, 0x8D5E, 0x6D2A, 0x8D5F, 0x6D69, 0x8D60, 0x6E2F, 0x8D61, 0x6E9D, 0x8D62, 0x7532, 0x8D63, 0x7687, 0x8D64, 0x786C, 0x8D65, 0x7A3F, 0x8D66, 0x7CE0, 0x8D67, 0x7D05, 0x8D68, 0x7D18, 0x8D69, 0x7D5E, 0x8D6A, 0x7DB1, 0x8D6B, 0x8015, 0x8D6C, 0x8003, 0x8D6D, 0x80AF, 0x8D6E, 0x80B1, 0x8D6F, 0x8154, 0x8D70, 0x818F, 0x8D71, 0x822A, 0x8D72, 0x8352, 0x8D73, 0x884C, 0x8D74, 0x8861, 0x8D75, 0x8B1B, 0x8D76, 0x8CA2, 0x8D77, 0x8CFC, 0x8D78, 0x90CA, 0x8D79, 0x9175, 0x8D7A, 0x9271, 0x8D7B, 0x783F, 0x8D7C, 0x92FC, 0x8D7D, 0x95A4, 0x8D7E, 0x964D, 0x8D80, 0x9805, 0x8D81, 0x9999, 0x8D82, 0x9AD8, 0x8D83, 0x9D3B, 0x8D84, 0x525B, 0x8D85, 0x52AB, 0x8D86, 0x53F7, 0x8D87, 0x5408, 0x8D88, 0x58D5, 0x8D89, 0x62F7, 0x8D8A, 0x6FE0, 0x8D8B, 0x8C6A, 0x8D8C, 0x8F5F, 0x8D8D, 0x9EB9, 0x8D8E, 0x514B, 0x8D8F, 0x523B, 0x8D90, 0x544A, 0x8D91, 0x56FD, 0x8D92, 0x7A40, 0x8D93, 0x9177, 0x8D94, 0x9D60, 0x8D95, 0x9ED2, 0x8D96, 0x7344, 0x8D97, 0x6F09, 0x8D98, 0x8170, 0x8D99, 0x7511, 0x8D9A, 0x5FFD, 0x8D9B, 0x60DA, 0x8D9C, 0x9AA8, 0x8D9D, 0x72DB, 0x8D9E, 0x8FBC, 0x8D9F, 0x6B64, 0x8DA0, 0x9803, 0x8DA1, 0x4ECA, 0x8DA2, 0x56F0, 0x8DA3, 0x5764, 0x8DA4, 0x58BE, 0x8DA5, 0x5A5A, 0x8DA6, 0x6068, 0x8DA7, 0x61C7, 0x8DA8, 0x660F, 0x8DA9, 0x6606, 0x8DAA, 0x6839, 0x8DAB, 0x68B1, 0x8DAC, 0x6DF7, 0x8DAD, 0x75D5, 0x8DAE, 0x7D3A, 0x8DAF, 0x826E, 0x8DB0, 0x9B42, 0x8DB1, 0x4E9B, 0x8DB2, 0x4F50, 0x8DB3, 0x53C9, 0x8DB4, 0x5506, 0x8DB5, 0x5D6F, 0x8DB6, 0x5DE6, 0x8DB7, 0x5DEE, 0x8DB8, 0x67FB, 0x8DB9, 0x6C99, 0x8DBA, 0x7473, 0x8DBB, 0x7802, 0x8DBC, 0x8A50, 0x8DBD, 0x9396, 0x8DBE, 0x88DF, 0x8DBF, 0x5750, 0x8DC0, 0x5EA7, 0x8DC1, 0x632B, 0x8DC2, 0x50B5, 0x8DC3, 0x50AC, 0x8DC4, 0x518D, 0x8DC5, 0x6700, 0x8DC6, 0x54C9, 0x8DC7, 0x585E, 0x8DC8, 0x59BB, 0x8DC9, 0x5BB0, 0x8DCA, 0x5F69, 0x8DCB, 0x624D, 0x8DCC, 0x63A1, 0x8DCD, 0x683D, 0x8DCE, 0x6B73, 0x8DCF, 0x6E08, 0x8DD0, 0x707D, 0x8DD1, 0x91C7, 0x8DD2, 0x7280, 0x8DD3, 0x7815, 0x8DD4, 0x7826, 0x8DD5, 0x796D, 0x8DD6, 0x658E, 0x8DD7, 0x7D30, 0x8DD8, 0x83DC, 0x8DD9, 0x88C1, 0x8DDA, 0x8F09, 0x8DDB, 0x969B, 0x8DDC, 0x5264, 0x8DDD, 0x5728, 0x8DDE, 0x6750, 0x8DDF, 0x7F6A, 0x8DE0, 0x8CA1, 0x8DE1, 0x51B4, 0x8DE2, 0x5742, 0x8DE3, 0x962A, 0x8DE4, 0x583A, 0x8DE5, 0x698A, 0x8DE6, 0x80B4, 0x8DE7, 0x54B2, 0x8DE8, 0x5D0E, 0x8DE9, 0x57FC, 0x8DEA, 0x7895, 0x8DEB, 0x9DFA, 0x8DEC, 0x4F5C, 0x8DED, 0x524A, 0x8DEE, 0x548B, 0x8DEF, 0x643E, 0x8DF0, 0x6628, 0x8DF1, 0x6714, 0x8DF2, 0x67F5, 0x8DF3, 0x7A84, 0x8DF4, 0x7B56, 0x8DF5, 0x7D22, 0x8DF6, 0x932F, 0x8DF7, 0x685C, 0x8DF8, 0x9BAD, 0x8DF9, 0x7B39, 0x8DFA, 0x5319, 0x8DFB, 0x518A, 0x8DFC, 0x5237, 0x8E40, 0x5BDF, 0x8E41, 0x62F6, 0x8E42, 0x64AE, 0x8E43, 0x64E6, 0x8E44, 0x672D, 0x8E45, 0x6BBA, 0x8E46, 0x85A9, 0x8E47, 0x96D1, 0x8E48, 0x7690, 0x8E49, 0x9BD6, 0x8E4A, 0x634C, 0x8E4B, 0x9306, 0x8E4C, 0x9BAB, 0x8E4D, 0x76BF, 0x8E4E, 0x6652, 0x8E4F, 0x4E09, 0x8E50, 0x5098, 0x8E51, 0x53C2, 0x8E52, 0x5C71, 0x8E53, 0x60E8, 0x8E54, 0x6492, 0x8E55, 0x6563, 0x8E56, 0x685F, 0x8E57, 0x71E6, 0x8E58, 0x73CA, 0x8E59, 0x7523, 0x8E5A, 0x7B97, 0x8E5B, 0x7E82, 0x8E5C, 0x8695, 0x8E5D, 0x8B83, 0x8E5E, 0x8CDB, 0x8E5F, 0x9178, 0x8E60, 0x9910, 0x8E61, 0x65AC, 0x8E62, 0x66AB, 0x8E63, 0x6B8B, 0x8E64, 0x4ED5, 0x8E65, 0x4ED4, 0x8E66, 0x4F3A, 0x8E67, 0x4F7F, 0x8E68, 0x523A, 0x8E69, 0x53F8, 0x8E6A, 0x53F2, 0x8E6B, 0x55E3, 0x8E6C, 0x56DB, 0x8E6D, 0x58EB, 0x8E6E, 0x59CB, 0x8E6F, 0x59C9, 0x8E70, 0x59FF, 0x8E71, 0x5B50, 0x8E72, 0x5C4D, 0x8E73, 0x5E02, 0x8E74, 0x5E2B, 0x8E75, 0x5FD7, 0x8E76, 0x601D, 0x8E77, 0x6307, 0x8E78, 0x652F, 0x8E79, 0x5B5C, 0x8E7A, 0x65AF, 0x8E7B, 0x65BD, 0x8E7C, 0x65E8, 0x8E7D, 0x679D, 0x8E7E, 0x6B62, 0x8E80, 0x6B7B, 0x8E81, 0x6C0F, 0x8E82, 0x7345, 0x8E83, 0x7949, 0x8E84, 0x79C1, 0x8E85, 0x7CF8, 0x8E86, 0x7D19, 0x8E87, 0x7D2B, 0x8E88, 0x80A2, 0x8E89, 0x8102, 0x8E8A, 0x81F3, 0x8E8B, 0x8996, 0x8E8C, 0x8A5E, 0x8E8D, 0x8A69, 0x8E8E, 0x8A66, 0x8E8F, 0x8A8C, 0x8E90, 0x8AEE, 0x8E91, 0x8CC7, 0x8E92, 0x8CDC, 0x8E93, 0x96CC, 0x8E94, 0x98FC, 0x8E95, 0x6B6F, 0x8E96, 0x4E8B, 0x8E97, 0x4F3C, 0x8E98, 0x4F8D, 0x8E99, 0x5150, 0x8E9A, 0x5B57, 0x8E9B, 0x5BFA, 0x8E9C, 0x6148, 0x8E9D, 0x6301, 0x8E9E, 0x6642, 0x8E9F, 0x6B21, 0x8EA0, 0x6ECB, 0x8EA1, 0x6CBB, 0x8EA2, 0x723E, 0x8EA3, 0x74BD, 0x8EA4, 0x75D4, 0x8EA5, 0x78C1, 0x8EA6, 0x793A, 0x8EA7, 0x800C, 0x8EA8, 0x8033, 0x8EA9, 0x81EA, 0x8EAA, 0x8494, 0x8EAB, 0x8F9E, 0x8EAC, 0x6C50, 0x8EAD, 0x9E7F, 0x8EAE, 0x5F0F, 0x8EAF, 0x8B58, 0x8EB0, 0x9D2B, 0x8EB1, 0x7AFA, 0x8EB2, 0x8EF8, 0x8EB3, 0x5B8D, 0x8EB4, 0x96EB, 0x8EB5, 0x4E03, 0x8EB6, 0x53F1, 0x8EB7, 0x57F7, 0x8EB8, 0x5931, 0x8EB9, 0x5AC9, 0x8EBA, 0x5BA4, 0x8EBB, 0x6089, 0x8EBC, 0x6E7F, 0x8EBD, 0x6F06, 0x8EBE, 0x75BE, 0x8EBF, 0x8CEA, 0x8EC0, 0x5B9F, 0x8EC1, 0x8500, 0x8EC2, 0x7BE0, 0x8EC3, 0x5072, 0x8EC4, 0x67F4, 0x8EC5, 0x829D, 0x8EC6, 0x5C61, 0x8EC7, 0x854A, 0x8EC8, 0x7E1E, 0x8EC9, 0x820E, 0x8ECA, 0x5199, 0x8ECB, 0x5C04, 0x8ECC, 0x6368, 0x8ECD, 0x8D66, 0x8ECE, 0x659C, 0x8ECF, 0x716E, 0x8ED0, 0x793E, 0x8ED1, 0x7D17, 0x8ED2, 0x8005, 0x8ED3, 0x8B1D, 0x8ED4, 0x8ECA, 0x8ED5, 0x906E, 0x8ED6, 0x86C7, 0x8ED7, 0x90AA, 0x8ED8, 0x501F, 0x8ED9, 0x52FA, 0x8EDA, 0x5C3A, 0x8EDB, 0x6753, 0x8EDC, 0x707C, 0x8EDD, 0x7235, 0x8EDE, 0x914C, 0x8EDF, 0x91C8, 0x8EE0, 0x932B, 0x8EE1, 0x82E5, 0x8EE2, 0x5BC2, 0x8EE3, 0x5F31, 0x8EE4, 0x60F9, 0x8EE5, 0x4E3B, 0x8EE6, 0x53D6, 0x8EE7, 0x5B88, 0x8EE8, 0x624B, 0x8EE9, 0x6731, 0x8EEA, 0x6B8A, 0x8EEB, 0x72E9, 0x8EEC, 0x73E0, 0x8EED, 0x7A2E, 0x8EEE, 0x816B, 0x8EEF, 0x8DA3, 0x8EF0, 0x9152, 0x8EF1, 0x9996, 0x8EF2, 0x5112, 0x8EF3, 0x53D7, 0x8EF4, 0x546A, 0x8EF5, 0x5BFF, 0x8EF6, 0x6388, 0x8EF7, 0x6A39, 0x8EF8, 0x7DAC, 0x8EF9, 0x9700, 0x8EFA, 0x56DA, 0x8EFB, 0x53CE, 0x8EFC, 0x5468, 0x8F40, 0x5B97, 0x8F41, 0x5C31, 0x8F42, 0x5DDE, 0x8F43, 0x4FEE, 0x8F44, 0x6101, 0x8F45, 0x62FE, 0x8F46, 0x6D32, 0x8F47, 0x79C0, 0x8F48, 0x79CB, 0x8F49, 0x7D42, 0x8F4A, 0x7E4D, 0x8F4B, 0x7FD2, 0x8F4C, 0x81ED, 0x8F4D, 0x821F, 0x8F4E, 0x8490, 0x8F4F, 0x8846, 0x8F50, 0x8972, 0x8F51, 0x8B90, 0x8F52, 0x8E74, 0x8F53, 0x8F2F, 0x8F54, 0x9031, 0x8F55, 0x914B, 0x8F56, 0x916C, 0x8F57, 0x96C6, 0x8F58, 0x919C, 0x8F59, 0x4EC0, 0x8F5A, 0x4F4F, 0x8F5B, 0x5145, 0x8F5C, 0x5341, 0x8F5D, 0x5F93, 0x8F5E, 0x620E, 0x8F5F, 0x67D4, 0x8F60, 0x6C41, 0x8F61, 0x6E0B, 0x8F62, 0x7363, 0x8F63, 0x7E26, 0x8F64, 0x91CD, 0x8F65, 0x9283, 0x8F66, 0x53D4, 0x8F67, 0x5919, 0x8F68, 0x5BBF, 0x8F69, 0x6DD1, 0x8F6A, 0x795D, 0x8F6B, 0x7E2E, 0x8F6C, 0x7C9B, 0x8F6D, 0x587E, 0x8F6E, 0x719F, 0x8F6F, 0x51FA, 0x8F70, 0x8853, 0x8F71, 0x8FF0, 0x8F72, 0x4FCA, 0x8F73, 0x5CFB, 0x8F74, 0x6625, 0x8F75, 0x77AC, 0x8F76, 0x7AE3, 0x8F77, 0x821C, 0x8F78, 0x99FF, 0x8F79, 0x51C6, 0x8F7A, 0x5FAA, 0x8F7B, 0x65EC, 0x8F7C, 0x696F, 0x8F7D, 0x6B89, 0x8F7E, 0x6DF3, 0x8F80, 0x6E96, 0x8F81, 0x6F64, 0x8F82, 0x76FE, 0x8F83, 0x7D14, 0x8F84, 0x5DE1, 0x8F85, 0x9075, 0x8F86, 0x9187, 0x8F87, 0x9806, 0x8F88, 0x51E6, 0x8F89, 0x521D, 0x8F8A, 0x6240, 0x8F8B, 0x6691, 0x8F8C, 0x66D9, 0x8F8D, 0x6E1A, 0x8F8E, 0x5EB6, 0x8F8F, 0x7DD2, 0x8F90, 0x7F72, 0x8F91, 0x66F8, 0x8F92, 0x85AF, 0x8F93, 0x85F7, 0x8F94, 0x8AF8, 0x8F95, 0x52A9, 0x8F96, 0x53D9, 0x8F97, 0x5973, 0x8F98, 0x5E8F, 0x8F99, 0x5F90, 0x8F9A, 0x6055, 0x8F9B, 0x92E4, 0x8F9C, 0x9664, 0x8F9D, 0x50B7, 0x8F9E, 0x511F, 0x8F9F, 0x52DD, 0x8FA0, 0x5320, 0x8FA1, 0x5347, 0x8FA2, 0x53EC, 0x8FA3, 0x54E8, 0x8FA4, 0x5546, 0x8FA5, 0x5531, 0x8FA6, 0x5617, 0x8FA7, 0x5968, 0x8FA8, 0x59BE, 0x8FA9, 0x5A3C, 0x8FAA, 0x5BB5, 0x8FAB, 0x5C06, 0x8FAC, 0x5C0F, 0x8FAD, 0x5C11, 0x8FAE, 0x5C1A, 0x8FAF, 0x5E84, 0x8FB0, 0x5E8A, 0x8FB1, 0x5EE0, 0x8FB2, 0x5F70, 0x8FB3, 0x627F, 0x8FB4, 0x6284, 0x8FB5, 0x62DB, 0x8FB6, 0x638C, 0x8FB7, 0x6377, 0x8FB8, 0x6607, 0x8FB9, 0x660C, 0x8FBA, 0x662D, 0x8FBB, 0x6676, 0x8FBC, 0x677E, 0x8FBD, 0x68A2, 0x8FBE, 0x6A1F, 0x8FBF, 0x6A35, 0x8FC0, 0x6CBC, 0x8FC1, 0x6D88, 0x8FC2, 0x6E09, 0x8FC3, 0x6E58, 0x8FC4, 0x713C, 0x8FC5, 0x7126, 0x8FC6, 0x7167, 0x8FC7, 0x75C7, 0x8FC8, 0x7701, 0x8FC9, 0x785D, 0x8FCA, 0x7901, 0x8FCB, 0x7965, 0x8FCC, 0x79F0, 0x8FCD, 0x7AE0, 0x8FCE, 0x7B11, 0x8FCF, 0x7CA7, 0x8FD0, 0x7D39, 0x8FD1, 0x8096, 0x8FD2, 0x83D6, 0x8FD3, 0x848B, 0x8FD4, 0x8549, 0x8FD5, 0x885D, 0x8FD6, 0x88F3, 0x8FD7, 0x8A1F, 0x8FD8, 0x8A3C, 0x8FD9, 0x8A54, 0x8FDA, 0x8A73, 0x8FDB, 0x8C61, 0x8FDC, 0x8CDE, 0x8FDD, 0x91A4, 0x8FDE, 0x9266, 0x8FDF, 0x937E, 0x8FE0, 0x9418, 0x8FE1, 0x969C, 0x8FE2, 0x9798, 0x8FE3, 0x4E0A, 0x8FE4, 0x4E08, 0x8FE5, 0x4E1E, 0x8FE6, 0x4E57, 0x8FE7, 0x5197, 0x8FE8, 0x5270, 0x8FE9, 0x57CE, 0x8FEA, 0x5834, 0x8FEB, 0x58CC, 0x8FEC, 0x5B22, 0x8FED, 0x5E38, 0x8FEE, 0x60C5, 0x8FEF, 0x64FE, 0x8FF0, 0x6761, 0x8FF1, 0x6756, 0x8FF2, 0x6D44, 0x8FF3, 0x72B6, 0x8FF4, 0x7573, 0x8FF5, 0x7A63, 0x8FF6, 0x84B8, 0x8FF7, 0x8B72, 0x8FF8, 0x91B8, 0x8FF9, 0x9320, 0x8FFA, 0x5631, 0x8FFB, 0x57F4, 0x8FFC, 0x98FE, 0x9040, 0x62ED, 0x9041, 0x690D, 0x9042, 0x6B96, 0x9043, 0x71ED, 0x9044, 0x7E54, 0x9045, 0x8077, 0x9046, 0x8272, 0x9047, 0x89E6, 0x9048, 0x98DF, 0x9049, 0x8755, 0x904A, 0x8FB1, 0x904B, 0x5C3B, 0x904C, 0x4F38, 0x904D, 0x4FE1, 0x904E, 0x4FB5, 0x904F, 0x5507, 0x9050, 0x5A20, 0x9051, 0x5BDD, 0x9052, 0x5BE9, 0x9053, 0x5FC3, 0x9054, 0x614E, 0x9055, 0x632F, 0x9056, 0x65B0, 0x9057, 0x664B, 0x9058, 0x68EE, 0x9059, 0x699B, 0x905A, 0x6D78, 0x905B, 0x6DF1, 0x905C, 0x7533, 0x905D, 0x75B9, 0x905E, 0x771F, 0x905F, 0x795E, 0x9060, 0x79E6, 0x9061, 0x7D33, 0x9062, 0x81E3, 0x9063, 0x82AF, 0x9064, 0x85AA, 0x9065, 0x89AA, 0x9066, 0x8A3A, 0x9067, 0x8EAB, 0x9068, 0x8F9B, 0x9069, 0x9032, 0x906A, 0x91DD, 0x906B, 0x9707, 0x906C, 0x4EBA, 0x906D, 0x4EC1, 0x906E, 0x5203, 0x906F, 0x5875, 0x9070, 0x58EC, 0x9071, 0x5C0B, 0x9072, 0x751A, 0x9073, 0x5C3D, 0x9074, 0x814E, 0x9075, 0x8A0A, 0x9076, 0x8FC5, 0x9077, 0x9663, 0x9078, 0x976D, 0x9079, 0x7B25, 0x907A, 0x8ACF, 0x907B, 0x9808, 0x907C, 0x9162, 0x907D, 0x56F3, 0x907E, 0x53A8, 0x9080, 0x9017, 0x9081, 0x5439, 0x9082, 0x5782, 0x9083, 0x5E25, 0x9084, 0x63A8, 0x9085, 0x6C34, 0x9086, 0x708A, 0x9087, 0x7761, 0x9088, 0x7C8B, 0x9089, 0x7FE0, 0x908A, 0x8870, 0x908B, 0x9042, 0x908C, 0x9154, 0x908D, 0x9310, 0x908E, 0x9318, 0x908F, 0x968F, 0x9090, 0x745E, 0x9091, 0x9AC4, 0x9092, 0x5D07, 0x9093, 0x5D69, 0x9094, 0x6570, 0x9095, 0x67A2, 0x9096, 0x8DA8, 0x9097, 0x96DB, 0x9098, 0x636E, 0x9099, 0x6749, 0x909A, 0x6919, 0x909B, 0x83C5, 0x909C, 0x9817, 0x909D, 0x96C0, 0x909E, 0x88FE, 0x909F, 0x6F84, 0x90A0, 0x647A, 0x90A1, 0x5BF8, 0x90A2, 0x4E16, 0x90A3, 0x702C, 0x90A4, 0x755D, 0x90A5, 0x662F, 0x90A6, 0x51C4, 0x90A7, 0x5236, 0x90A8, 0x52E2, 0x90A9, 0x59D3, 0x90AA, 0x5F81, 0x90AB, 0x6027, 0x90AC, 0x6210, 0x90AD, 0x653F, 0x90AE, 0x6574, 0x90AF, 0x661F, 0x90B0, 0x6674, 0x90B1, 0x68F2, 0x90B2, 0x6816, 0x90B3, 0x6B63, 0x90B4, 0x6E05, 0x90B5, 0x7272, 0x90B6, 0x751F, 0x90B7, 0x76DB, 0x90B8, 0x7CBE, 0x90B9, 0x8056, 0x90BA, 0x58F0, 0x90BB, 0x88FD, 0x90BC, 0x897F, 0x90BD, 0x8AA0, 0x90BE, 0x8A93, 0x90BF, 0x8ACB, 0x90C0, 0x901D, 0x90C1, 0x9192, 0x90C2, 0x9752, 0x90C3, 0x9759, 0x90C4, 0x6589, 0x90C5, 0x7A0E, 0x90C6, 0x8106, 0x90C7, 0x96BB, 0x90C8, 0x5E2D, 0x90C9, 0x60DC, 0x90CA, 0x621A, 0x90CB, 0x65A5, 0x90CC, 0x6614, 0x90CD, 0x6790, 0x90CE, 0x77F3, 0x90CF, 0x7A4D, 0x90D0, 0x7C4D, 0x90D1, 0x7E3E, 0x90D2, 0x810A, 0x90D3, 0x8CAC, 0x90D4, 0x8D64, 0x90D5, 0x8DE1, 0x90D6, 0x8E5F, 0x90D7, 0x78A9, 0x90D8, 0x5207, 0x90D9, 0x62D9, 0x90DA, 0x63A5, 0x90DB, 0x6442, 0x90DC, 0x6298, 0x90DD, 0x8A2D, 0x90DE, 0x7A83, 0x90DF, 0x7BC0, 0x90E0, 0x8AAC, 0x90E1, 0x96EA, 0x90E2, 0x7D76, 0x90E3, 0x820C, 0x90E4, 0x8749, 0x90E5, 0x4ED9, 0x90E6, 0x5148, 0x90E7, 0x5343, 0x90E8, 0x5360, 0x90E9, 0x5BA3, 0x90EA, 0x5C02, 0x90EB, 0x5C16, 0x90EC, 0x5DDD, 0x90ED, 0x6226, 0x90EE, 0x6247, 0x90EF, 0x64B0, 0x90F0, 0x6813, 0x90F1, 0x6834, 0x90F2, 0x6CC9, 0x90F3, 0x6D45, 0x90F4, 0x6D17, 0x90F5, 0x67D3, 0x90F6, 0x6F5C, 0x90F7, 0x714E, 0x90F8, 0x717D, 0x90F9, 0x65CB, 0x90FA, 0x7A7F, 0x90FB, 0x7BAD, 0x90FC, 0x7DDA, 0x9140, 0x7E4A, 0x9141, 0x7FA8, 0x9142, 0x817A, 0x9143, 0x821B, 0x9144, 0x8239, 0x9145, 0x85A6, 0x9146, 0x8A6E, 0x9147, 0x8CCE, 0x9148, 0x8DF5, 0x9149, 0x9078, 0x914A, 0x9077, 0x914B, 0x92AD, 0x914C, 0x9291, 0x914D, 0x9583, 0x914E, 0x9BAE, 0x914F, 0x524D, 0x9150, 0x5584, 0x9151, 0x6F38, 0x9152, 0x7136, 0x9153, 0x5168, 0x9154, 0x7985, 0x9155, 0x7E55, 0x9156, 0x81B3, 0x9157, 0x7CCE, 0x9158, 0x564C, 0x9159, 0x5851, 0x915A, 0x5CA8, 0x915B, 0x63AA, 0x915C, 0x66FE, 0x915D, 0x66FD, 0x915E, 0x695A, 0x915F, 0x72D9, 0x9160, 0x758F, 0x9161, 0x758E, 0x9162, 0x790E, 0x9163, 0x7956, 0x9164, 0x79DF, 0x9165, 0x7C97, 0x9166, 0x7D20, 0x9167, 0x7D44, 0x9168, 0x8607, 0x9169, 0x8A34, 0x916A, 0x963B, 0x916B, 0x9061, 0x916C, 0x9F20, 0x916D, 0x50E7, 0x916E, 0x5275, 0x916F, 0x53CC, 0x9170, 0x53E2, 0x9171, 0x5009, 0x9172, 0x55AA, 0x9173, 0x58EE, 0x9174, 0x594F, 0x9175, 0x723D, 0x9176, 0x5B8B, 0x9177, 0x5C64, 0x9178, 0x531D, 0x9179, 0x60E3, 0x917A, 0x60F3, 0x917B, 0x635C, 0x917C, 0x6383, 0x917D, 0x633F, 0x917E, 0x63BB, 0x9180, 0x64CD, 0x9181, 0x65E9, 0x9182, 0x66F9, 0x9183, 0x5DE3, 0x9184, 0x69CD, 0x9185, 0x69FD, 0x9186, 0x6F15, 0x9187, 0x71E5, 0x9188, 0x4E89, 0x9189, 0x75E9, 0x918A, 0x76F8, 0x918B, 0x7A93, 0x918C, 0x7CDF, 0x918D, 0x7DCF, 0x918E, 0x7D9C, 0x918F, 0x8061, 0x9190, 0x8349, 0x9191, 0x8358, 0x9192, 0x846C, 0x9193, 0x84BC, 0x9194, 0x85FB, 0x9195, 0x88C5, 0x9196, 0x8D70, 0x9197, 0x9001, 0x9198, 0x906D, 0x9199, 0x9397, 0x919A, 0x971C, 0x919B, 0x9A12, 0x919C, 0x50CF, 0x919D, 0x5897, 0x919E, 0x618E, 0x919F, 0x81D3, 0x91A0, 0x8535, 0x91A1, 0x8D08, 0x91A2, 0x9020, 0x91A3, 0x4FC3, 0x91A4, 0x5074, 0x91A5, 0x5247, 0x91A6, 0x5373, 0x91A7, 0x606F, 0x91A8, 0x6349, 0x91A9, 0x675F, 0x91AA, 0x6E2C, 0x91AB, 0x8DB3, 0x91AC, 0x901F, 0x91AD, 0x4FD7, 0x91AE, 0x5C5E, 0x91AF, 0x8CCA, 0x91B0, 0x65CF, 0x91B1, 0x7D9A, 0x91B2, 0x5352, 0x91B3, 0x8896, 0x91B4, 0x5176, 0x91B5, 0x63C3, 0x91B6, 0x5B58, 0x91B7, 0x5B6B, 0x91B8, 0x5C0A, 0x91B9, 0x640D, 0x91BA, 0x6751, 0x91BB, 0x905C, 0x91BC, 0x4ED6, 0x91BD, 0x591A, 0x91BE, 0x592A, 0x91BF, 0x6C70, 0x91C0, 0x8A51, 0x91C1, 0x553E, 0x91C2, 0x5815, 0x91C3, 0x59A5, 0x91C4, 0x60F0, 0x91C5, 0x6253, 0x91C6, 0x67C1, 0x91C7, 0x8235, 0x91C8, 0x6955, 0x91C9, 0x9640, 0x91CA, 0x99C4, 0x91CB, 0x9A28, 0x91CC, 0x4F53, 0x91CD, 0x5806, 0x91CE, 0x5BFE, 0x91CF, 0x8010, 0x91D0, 0x5CB1, 0x91D1, 0x5E2F, 0x91D2, 0x5F85, 0x91D3, 0x6020, 0x91D4, 0x614B, 0x91D5, 0x6234, 0x91D6, 0x66FF, 0x91D7, 0x6CF0, 0x91D8, 0x6EDE, 0x91D9, 0x80CE, 0x91DA, 0x817F, 0x91DB, 0x82D4, 0x91DC, 0x888B, 0x91DD, 0x8CB8, 0x91DE, 0x9000, 0x91DF, 0x902E, 0x91E0, 0x968A, 0x91E1, 0x9EDB, 0x91E2, 0x9BDB, 0x91E3, 0x4EE3, 0x91E4, 0x53F0, 0x91E5, 0x5927, 0x91E6, 0x7B2C, 0x91E7, 0x918D, 0x91E8, 0x984C, 0x91E9, 0x9DF9, 0x91EA, 0x6EDD, 0x91EB, 0x7027, 0x91EC, 0x5353, 0x91ED, 0x5544, 0x91EE, 0x5B85, 0x91EF, 0x6258, 0x91F0, 0x629E, 0x91F1, 0x62D3, 0x91F2, 0x6CA2, 0x91F3, 0x6FEF, 0x91F4, 0x7422, 0x91F5, 0x8A17, 0x91F6, 0x9438, 0x91F7, 0x6FC1, 0x91F8, 0x8AFE, 0x91F9, 0x8338, 0x91FA, 0x51E7, 0x91FB, 0x86F8, 0x91FC, 0x53EA, 0x9240, 0x53E9, 0x9241, 0x4F46, 0x9242, 0x9054, 0x9243, 0x8FB0, 0x9244, 0x596A, 0x9245, 0x8131, 0x9246, 0x5DFD, 0x9247, 0x7AEA, 0x9248, 0x8FBF, 0x9249, 0x68DA, 0x924A, 0x8C37, 0x924B, 0x72F8, 0x924C, 0x9C48, 0x924D, 0x6A3D, 0x924E, 0x8AB0, 0x924F, 0x4E39, 0x9250, 0x5358, 0x9251, 0x5606, 0x9252, 0x5766, 0x9253, 0x62C5, 0x9254, 0x63A2, 0x9255, 0x65E6, 0x9256, 0x6B4E, 0x9257, 0x6DE1, 0x9258, 0x6E5B, 0x9259, 0x70AD, 0x925A, 0x77ED, 0x925B, 0x7AEF, 0x925C, 0x7BAA, 0x925D, 0x7DBB, 0x925E, 0x803D, 0x925F, 0x80C6, 0x9260, 0x86CB, 0x9261, 0x8A95, 0x9262, 0x935B, 0x9263, 0x56E3, 0x9264, 0x58C7, 0x9265, 0x5F3E, 0x9266, 0x65AD, 0x9267, 0x6696, 0x9268, 0x6A80, 0x9269, 0x6BB5, 0x926A, 0x7537, 0x926B, 0x8AC7, 0x926C, 0x5024, 0x926D, 0x77E5, 0x926E, 0x5730, 0x926F, 0x5F1B, 0x9270, 0x6065, 0x9271, 0x667A, 0x9272, 0x6C60, 0x9273, 0x75F4, 0x9274, 0x7A1A, 0x9275, 0x7F6E, 0x9276, 0x81F4, 0x9277, 0x8718, 0x9278, 0x9045, 0x9279, 0x99B3, 0x927A, 0x7BC9, 0x927B, 0x755C, 0x927C, 0x7AF9, 0x927D, 0x7B51, 0x927E, 0x84C4, 0x9280, 0x9010, 0x9281, 0x79E9, 0x9282, 0x7A92, 0x9283, 0x8336, 0x9284, 0x5AE1, 0x9285, 0x7740, 0x9286, 0x4E2D, 0x9287, 0x4EF2, 0x9288, 0x5B99, 0x9289, 0x5FE0, 0x928A, 0x62BD, 0x928B, 0x663C, 0x928C, 0x67F1, 0x928D, 0x6CE8, 0x928E, 0x866B, 0x928F, 0x8877, 0x9290, 0x8A3B, 0x9291, 0x914E, 0x9292, 0x92F3, 0x9293, 0x99D0, 0x9294, 0x6A17, 0x9295, 0x7026, 0x9296, 0x732A, 0x9297, 0x82E7, 0x9298, 0x8457, 0x9299, 0x8CAF, 0x929A, 0x4E01, 0x929B, 0x5146, 0x929C, 0x51CB, 0x929D, 0x558B, 0x929E, 0x5BF5, 0x929F, 0x5E16, 0x92A0, 0x5E33, 0x92A1, 0x5E81, 0x92A2, 0x5F14, 0x92A3, 0x5F35, 0x92A4, 0x5F6B, 0x92A5, 0x5FB4, 0x92A6, 0x61F2, 0x92A7, 0x6311, 0x92A8, 0x66A2, 0x92A9, 0x671D, 0x92AA, 0x6F6E, 0x92AB, 0x7252, 0x92AC, 0x753A, 0x92AD, 0x773A, 0x92AE, 0x8074, 0x92AF, 0x8139, 0x92B0, 0x8178, 0x92B1, 0x8776, 0x92B2, 0x8ABF, 0x92B3, 0x8ADC, 0x92B4, 0x8D85, 0x92B5, 0x8DF3, 0x92B6, 0x929A, 0x92B7, 0x9577, 0x92B8, 0x9802, 0x92B9, 0x9CE5, 0x92BA, 0x52C5, 0x92BB, 0x6357, 0x92BC, 0x76F4, 0x92BD, 0x6715, 0x92BE, 0x6C88, 0x92BF, 0x73CD, 0x92C0, 0x8CC3, 0x92C1, 0x93AE, 0x92C2, 0x9673, 0x92C3, 0x6D25, 0x92C4, 0x589C, 0x92C5, 0x690E, 0x92C6, 0x69CC, 0x92C7, 0x8FFD, 0x92C8, 0x939A, 0x92C9, 0x75DB, 0x92CA, 0x901A, 0x92CB, 0x585A, 0x92CC, 0x6802, 0x92CD, 0x63B4, 0x92CE, 0x69FB, 0x92CF, 0x4F43, 0x92D0, 0x6F2C, 0x92D1, 0x67D8, 0x92D2, 0x8FBB, 0x92D3, 0x8526, 0x92D4, 0x7DB4, 0x92D5, 0x9354, 0x92D6, 0x693F, 0x92D7, 0x6F70, 0x92D8, 0x576A, 0x92D9, 0x58F7, 0x92DA, 0x5B2C, 0x92DB, 0x7D2C, 0x92DC, 0x722A, 0x92DD, 0x540A, 0x92DE, 0x91E3, 0x92DF, 0x9DB4, 0x92E0, 0x4EAD, 0x92E1, 0x4F4E, 0x92E2, 0x505C, 0x92E3, 0x5075, 0x92E4, 0x5243, 0x92E5, 0x8C9E, 0x92E6, 0x5448, 0x92E7, 0x5824, 0x92E8, 0x5B9A, 0x92E9, 0x5E1D, 0x92EA, 0x5E95, 0x92EB, 0x5EAD, 0x92EC, 0x5EF7, 0x92ED, 0x5F1F, 0x92EE, 0x608C, 0x92EF, 0x62B5, 0x92F0, 0x633A, 0x92F1, 0x63D0, 0x92F2, 0x68AF, 0x92F3, 0x6C40, 0x92F4, 0x7887, 0x92F5, 0x798E, 0x92F6, 0x7A0B, 0x92F7, 0x7DE0, 0x92F8, 0x8247, 0x92F9, 0x8A02, 0x92FA, 0x8AE6, 0x92FB, 0x8E44, 0x92FC, 0x9013, 0x9340, 0x90B8, 0x9341, 0x912D, 0x9342, 0x91D8, 0x9343, 0x9F0E, 0x9344, 0x6CE5, 0x9345, 0x6458, 0x9346, 0x64E2, 0x9347, 0x6575, 0x9348, 0x6EF4, 0x9349, 0x7684, 0x934A, 0x7B1B, 0x934B, 0x9069, 0x934C, 0x93D1, 0x934D, 0x6EBA, 0x934E, 0x54F2, 0x934F, 0x5FB9, 0x9350, 0x64A4, 0x9351, 0x8F4D, 0x9352, 0x8FED, 0x9353, 0x9244, 0x9354, 0x5178, 0x9355, 0x586B, 0x9356, 0x5929, 0x9357, 0x5C55, 0x9358, 0x5E97, 0x9359, 0x6DFB, 0x935A, 0x7E8F, 0x935B, 0x751C, 0x935C, 0x8CBC, 0x935D, 0x8EE2, 0x935E, 0x985B, 0x935F, 0x70B9, 0x9360, 0x4F1D, 0x9361, 0x6BBF, 0x9362, 0x6FB1, 0x9363, 0x7530, 0x9364, 0x96FB, 0x9365, 0x514E, 0x9366, 0x5410, 0x9367, 0x5835, 0x9368, 0x5857, 0x9369, 0x59AC, 0x936A, 0x5C60, 0x936B, 0x5F92, 0x936C, 0x6597, 0x936D, 0x675C, 0x936E, 0x6E21, 0x936F, 0x767B, 0x9370, 0x83DF, 0x9371, 0x8CED, 0x9372, 0x9014, 0x9373, 0x90FD, 0x9374, 0x934D, 0x9375, 0x7825, 0x9376, 0x783A, 0x9377, 0x52AA, 0x9378, 0x5EA6, 0x9379, 0x571F, 0x937A, 0x5974, 0x937B, 0x6012, 0x937C, 0x5012, 0x937D, 0x515A, 0x937E, 0x51AC, 0x9380, 0x51CD, 0x9381, 0x5200, 0x9382, 0x5510, 0x9383, 0x5854, 0x9384, 0x5858, 0x9385, 0x5957, 0x9386, 0x5B95, 0x9387, 0x5CF6, 0x9388, 0x5D8B, 0x9389, 0x60BC, 0x938A, 0x6295, 0x938B, 0x642D, 0x938C, 0x6771, 0x938D, 0x6843, 0x938E, 0x68BC, 0x938F, 0x68DF, 0x9390, 0x76D7, 0x9391, 0x6DD8, 0x9392, 0x6E6F, 0x9393, 0x6D9B, 0x9394, 0x706F, 0x9395, 0x71C8, 0x9396, 0x5F53, 0x9397, 0x75D8, 0x9398, 0x7977, 0x9399, 0x7B49, 0x939A, 0x7B54, 0x939B, 0x7B52, 0x939C, 0x7CD6, 0x939D, 0x7D71, 0x939E, 0x5230, 0x939F, 0x8463, 0x93A0, 0x8569, 0x93A1, 0x85E4, 0x93A2, 0x8A0E, 0x93A3, 0x8B04, 0x93A4, 0x8C46, 0x93A5, 0x8E0F, 0x93A6, 0x9003, 0x93A7, 0x900F, 0x93A8, 0x9419, 0x93A9, 0x9676, 0x93AA, 0x982D, 0x93AB, 0x9A30, 0x93AC, 0x95D8, 0x93AD, 0x50CD, 0x93AE, 0x52D5, 0x93AF, 0x540C, 0x93B0, 0x5802, 0x93B1, 0x5C0E, 0x93B2, 0x61A7, 0x93B3, 0x649E, 0x93B4, 0x6D1E, 0x93B5, 0x77B3, 0x93B6, 0x7AE5, 0x93B7, 0x80F4, 0x93B8, 0x8404, 0x93B9, 0x9053, 0x93BA, 0x9285, 0x93BB, 0x5CE0, 0x93BC, 0x9D07, 0x93BD, 0x533F, 0x93BE, 0x5F97, 0x93BF, 0x5FB3, 0x93C0, 0x6D9C, 0x93C1, 0x7279, 0x93C2, 0x7763, 0x93C3, 0x79BF, 0x93C4, 0x7BE4, 0x93C5, 0x6BD2, 0x93C6, 0x72EC, 0x93C7, 0x8AAD, 0x93C8, 0x6803, 0x93C9, 0x6A61, 0x93CA, 0x51F8, 0x93CB, 0x7A81, 0x93CC, 0x6934, 0x93CD, 0x5C4A, 0x93CE, 0x9CF6, 0x93CF, 0x82EB, 0x93D0, 0x5BC5, 0x93D1, 0x9149, 0x93D2, 0x701E, 0x93D3, 0x5678, 0x93D4, 0x5C6F, 0x93D5, 0x60C7, 0x93D6, 0x6566, 0x93D7, 0x6C8C, 0x93D8, 0x8C5A, 0x93D9, 0x9041, 0x93DA, 0x9813, 0x93DB, 0x5451, 0x93DC, 0x66C7, 0x93DD, 0x920D, 0x93DE, 0x5948, 0x93DF, 0x90A3, 0x93E0, 0x5185, 0x93E1, 0x4E4D, 0x93E2, 0x51EA, 0x93E3, 0x8599, 0x93E4, 0x8B0E, 0x93E5, 0x7058, 0x93E6, 0x637A, 0x93E7, 0x934B, 0x93E8, 0x6962, 0x93E9, 0x99B4, 0x93EA, 0x7E04, 0x93EB, 0x7577, 0x93EC, 0x5357, 0x93ED, 0x6960, 0x93EE, 0x8EDF, 0x93EF, 0x96E3, 0x93F0, 0x6C5D, 0x93F1, 0x4E8C, 0x93F2, 0x5C3C, 0x93F3, 0x5F10, 0x93F4, 0x8FE9, 0x93F5, 0x5302, 0x93F6, 0x8CD1, 0x93F7, 0x8089, 0x93F8, 0x8679, 0x93F9, 0x5EFF, 0x93FA, 0x65E5, 0x93FB, 0x4E73, 0x93FC, 0x5165, 0x9440, 0x5982, 0x9441, 0x5C3F, 0x9442, 0x97EE, 0x9443, 0x4EFB, 0x9444, 0x598A, 0x9445, 0x5FCD, 0x9446, 0x8A8D, 0x9447, 0x6FE1, 0x9448, 0x79B0, 0x9449, 0x7962, 0x944A, 0x5BE7, 0x944B, 0x8471, 0x944C, 0x732B, 0x944D, 0x71B1, 0x944E, 0x5E74, 0x944F, 0x5FF5, 0x9450, 0x637B, 0x9451, 0x649A, 0x9452, 0x71C3, 0x9453, 0x7C98, 0x9454, 0x4E43, 0x9455, 0x5EFC, 0x9456, 0x4E4B, 0x9457, 0x57DC, 0x9458, 0x56A2, 0x9459, 0x60A9, 0x945A, 0x6FC3, 0x945B, 0x7D0D, 0x945C, 0x80FD, 0x945D, 0x8133, 0x945E, 0x81BF, 0x945F, 0x8FB2, 0x9460, 0x8997, 0x9461, 0x86A4, 0x9462, 0x5DF4, 0x9463, 0x628A, 0x9464, 0x64AD, 0x9465, 0x8987, 0x9466, 0x6777, 0x9467, 0x6CE2, 0x9468, 0x6D3E, 0x9469, 0x7436, 0x946A, 0x7834, 0x946B, 0x5A46, 0x946C, 0x7F75, 0x946D, 0x82AD, 0x946E, 0x99AC, 0x946F, 0x4FF3, 0x9470, 0x5EC3, 0x9471, 0x62DD, 0x9472, 0x6392, 0x9473, 0x6557, 0x9474, 0x676F, 0x9475, 0x76C3, 0x9476, 0x724C, 0x9477, 0x80CC, 0x9478, 0x80BA, 0x9479, 0x8F29, 0x947A, 0x914D, 0x947B, 0x500D, 0x947C, 0x57F9, 0x947D, 0x5A92, 0x947E, 0x6885, 0x9480, 0x6973, 0x9481, 0x7164, 0x9482, 0x72FD, 0x9483, 0x8CB7, 0x9484, 0x58F2, 0x9485, 0x8CE0, 0x9486, 0x966A, 0x9487, 0x9019, 0x9488, 0x877F, 0x9489, 0x79E4, 0x948A, 0x77E7, 0x948B, 0x8429, 0x948C, 0x4F2F, 0x948D, 0x5265, 0x948E, 0x535A, 0x948F, 0x62CD, 0x9490, 0x67CF, 0x9491, 0x6CCA, 0x9492, 0x767D, 0x9493, 0x7B94, 0x9494, 0x7C95, 0x9495, 0x8236, 0x9496, 0x8584, 0x9497, 0x8FEB, 0x9498, 0x66DD, 0x9499, 0x6F20, 0x949A, 0x7206, 0x949B, 0x7E1B, 0x949C, 0x83AB, 0x949D, 0x99C1, 0x949E, 0x9EA6, 0x949F, 0x51FD, 0x94A0, 0x7BB1, 0x94A1, 0x7872, 0x94A2, 0x7BB8, 0x94A3, 0x8087, 0x94A4, 0x7B48, 0x94A5, 0x6AE8, 0x94A6, 0x5E61, 0x94A7, 0x808C, 0x94A8, 0x7551, 0x94A9, 0x7560, 0x94AA, 0x516B, 0x94AB, 0x9262, 0x94AC, 0x6E8C, 0x94AD, 0x767A, 0x94AE, 0x9197, 0x94AF, 0x9AEA, 0x94B0, 0x4F10, 0x94B1, 0x7F70, 0x94B2, 0x629C, 0x94B3, 0x7B4F, 0x94B4, 0x95A5, 0x94B5, 0x9CE9, 0x94B6, 0x567A, 0x94B7, 0x5859, 0x94B8, 0x86E4, 0x94B9, 0x96BC, 0x94BA, 0x4F34, 0x94BB, 0x5224, 0x94BC, 0x534A, 0x94BD, 0x53CD, 0x94BE, 0x53DB, 0x94BF, 0x5E06, 0x94C0, 0x642C, 0x94C1, 0x6591, 0x94C2, 0x677F, 0x94C3, 0x6C3E, 0x94C4, 0x6C4E, 0x94C5, 0x7248, 0x94C6, 0x72AF, 0x94C7, 0x73ED, 0x94C8, 0x7554, 0x94C9, 0x7E41, 0x94CA, 0x822C, 0x94CB, 0x85E9, 0x94CC, 0x8CA9, 0x94CD, 0x7BC4, 0x94CE, 0x91C6, 0x94CF, 0x7169, 0x94D0, 0x9812, 0x94D1, 0x98EF, 0x94D2, 0x633D, 0x94D3, 0x6669, 0x94D4, 0x756A, 0x94D5, 0x76E4, 0x94D6, 0x78D0, 0x94D7, 0x8543, 0x94D8, 0x86EE, 0x94D9, 0x532A, 0x94DA, 0x5351, 0x94DB, 0x5426, 0x94DC, 0x5983, 0x94DD, 0x5E87, 0x94DE, 0x5F7C, 0x94DF, 0x60B2, 0x94E0, 0x6249, 0x94E1, 0x6279, 0x94E2, 0x62AB, 0x94E3, 0x6590, 0x94E4, 0x6BD4, 0x94E5, 0x6CCC, 0x94E6, 0x75B2, 0x94E7, 0x76AE, 0x94E8, 0x7891, 0x94E9, 0x79D8, 0x94EA, 0x7DCB, 0x94EB, 0x7F77, 0x94EC, 0x80A5, 0x94ED, 0x88AB, 0x94EE, 0x8AB9, 0x94EF, 0x8CBB, 0x94F0, 0x907F, 0x94F1, 0x975E, 0x94F2, 0x98DB, 0x94F3, 0x6A0B, 0x94F4, 0x7C38, 0x94F5, 0x5099, 0x94F6, 0x5C3E, 0x94F7, 0x5FAE, 0x94F8, 0x6787, 0x94F9, 0x6BD8, 0x94FA, 0x7435, 0x94FB, 0x7709, 0x94FC, 0x7F8E, 0x9540, 0x9F3B, 0x9541, 0x67CA, 0x9542, 0x7A17, 0x9543, 0x5339, 0x9544, 0x758B, 0x9545, 0x9AED, 0x9546, 0x5F66, 0x9547, 0x819D, 0x9548, 0x83F1, 0x9549, 0x8098, 0x954A, 0x5F3C, 0x954B, 0x5FC5, 0x954C, 0x7562, 0x954D, 0x7B46, 0x954E, 0x903C, 0x954F, 0x6867, 0x9550, 0x59EB, 0x9551, 0x5A9B, 0x9552, 0x7D10, 0x9553, 0x767E, 0x9554, 0x8B2C, 0x9555, 0x4FF5, 0x9556, 0x5F6A, 0x9557, 0x6A19, 0x9558, 0x6C37, 0x9559, 0x6F02, 0x955A, 0x74E2, 0x955B, 0x7968, 0x955C, 0x8868, 0x955D, 0x8A55, 0x955E, 0x8C79, 0x955F, 0x5EDF, 0x9560, 0x63CF, 0x9561, 0x75C5, 0x9562, 0x79D2, 0x9563, 0x82D7, 0x9564, 0x9328, 0x9565, 0x92F2, 0x9566, 0x849C, 0x9567, 0x86ED, 0x9568, 0x9C2D, 0x9569, 0x54C1, 0x956A, 0x5F6C, 0x956B, 0x658C, 0x956C, 0x6D5C, 0x956D, 0x7015, 0x956E, 0x8CA7, 0x956F, 0x8CD3, 0x9570, 0x983B, 0x9571, 0x654F, 0x9572, 0x74F6, 0x9573, 0x4E0D, 0x9574, 0x4ED8, 0x9575, 0x57E0, 0x9576, 0x592B, 0x9577, 0x5A66, 0x9578, 0x5BCC, 0x9579, 0x51A8, 0x957A, 0x5E03, 0x957B, 0x5E9C, 0x957C, 0x6016, 0x957D, 0x6276, 0x957E, 0x6577, 0x9580, 0x65A7, 0x9581, 0x666E, 0x9582, 0x6D6E, 0x9583, 0x7236, 0x9584, 0x7B26, 0x9585, 0x8150, 0x9586, 0x819A, 0x9587, 0x8299, 0x9588, 0x8B5C, 0x9589, 0x8CA0, 0x958A, 0x8CE6, 0x958B, 0x8D74, 0x958C, 0x961C, 0x958D, 0x9644, 0x958E, 0x4FAE, 0x958F, 0x64AB, 0x9590, 0x6B66, 0x9591, 0x821E, 0x9592, 0x8461, 0x9593, 0x856A, 0x9594, 0x90E8, 0x9595, 0x5C01, 0x9596, 0x6953, 0x9597, 0x98A8, 0x9598, 0x847A, 0x9599, 0x8557, 0x959A, 0x4F0F, 0x959B, 0x526F, 0x959C, 0x5FA9, 0x959D, 0x5E45, 0x959E, 0x670D, 0x959F, 0x798F, 0x95A0, 0x8179, 0x95A1, 0x8907, 0x95A2, 0x8986, 0x95A3, 0x6DF5, 0x95A4, 0x5F17, 0x95A5, 0x6255, 0x95A6, 0x6CB8, 0x95A7, 0x4ECF, 0x95A8, 0x7269, 0x95A9, 0x9B92, 0x95AA, 0x5206, 0x95AB, 0x543B, 0x95AC, 0x5674, 0x95AD, 0x58B3, 0x95AE, 0x61A4, 0x95AF, 0x626E, 0x95B0, 0x711A, 0x95B1, 0x596E, 0x95B2, 0x7C89, 0x95B3, 0x7CDE, 0x95B4, 0x7D1B, 0x95B5, 0x96F0, 0x95B6, 0x6587, 0x95B7, 0x805E, 0x95B8, 0x4E19, 0x95B9, 0x4F75, 0x95BA, 0x5175, 0x95BB, 0x5840, 0x95BC, 0x5E63, 0x95BD, 0x5E73, 0x95BE, 0x5F0A, 0x95BF, 0x67C4, 0x95C0, 0x4E26, 0x95C1, 0x853D, 0x95C2, 0x9589, 0x95C3, 0x965B, 0x95C4, 0x7C73, 0x95C5, 0x9801, 0x95C6, 0x50FB, 0x95C7, 0x58C1, 0x95C8, 0x7656, 0x95C9, 0x78A7, 0x95CA, 0x5225, 0x95CB, 0x77A5, 0x95CC, 0x8511, 0x95CD, 0x7B86, 0x95CE, 0x504F, 0x95CF, 0x5909, 0x95D0, 0x7247, 0x95D1, 0x7BC7, 0x95D2, 0x7DE8, 0x95D3, 0x8FBA, 0x95D4, 0x8FD4, 0x95D5, 0x904D, 0x95D6, 0x4FBF, 0x95D7, 0x52C9, 0x95D8, 0x5A29, 0x95D9, 0x5F01, 0x95DA, 0x97AD, 0x95DB, 0x4FDD, 0x95DC, 0x8217, 0x95DD, 0x92EA, 0x95DE, 0x5703, 0x95DF, 0x6355, 0x95E0, 0x6B69, 0x95E1, 0x752B, 0x95E2, 0x88DC, 0x95E3, 0x8F14, 0x95E4, 0x7A42, 0x95E5, 0x52DF, 0x95E6, 0x5893, 0x95E7, 0x6155, 0x95E8, 0x620A, 0x95E9, 0x66AE, 0x95EA, 0x6BCD, 0x95EB, 0x7C3F, 0x95EC, 0x83E9, 0x95ED, 0x5023, 0x95EE, 0x4FF8, 0x95EF, 0x5305, 0x95F0, 0x5446, 0x95F1, 0x5831, 0x95F2, 0x5949, 0x95F3, 0x5B9D, 0x95F4, 0x5CF0, 0x95F5, 0x5CEF, 0x95F6, 0x5D29, 0x95F7, 0x5E96, 0x95F8, 0x62B1, 0x95F9, 0x6367, 0x95FA, 0x653E, 0x95FB, 0x65B9, 0x95FC, 0x670B, 0x9640, 0x6CD5, 0x9641, 0x6CE1, 0x9642, 0x70F9, 0x9643, 0x7832, 0x9644, 0x7E2B, 0x9645, 0x80DE, 0x9646, 0x82B3, 0x9647, 0x840C, 0x9648, 0x84EC, 0x9649, 0x8702, 0x964A, 0x8912, 0x964B, 0x8A2A, 0x964C, 0x8C4A, 0x964D, 0x90A6, 0x964E, 0x92D2, 0x964F, 0x98FD, 0x9650, 0x9CF3, 0x9651, 0x9D6C, 0x9652, 0x4E4F, 0x9653, 0x4EA1, 0x9654, 0x508D, 0x9655, 0x5256, 0x9656, 0x574A, 0x9657, 0x59A8, 0x9658, 0x5E3D, 0x9659, 0x5FD8, 0x965A, 0x5FD9, 0x965B, 0x623F, 0x965C, 0x66B4, 0x965D, 0x671B, 0x965E, 0x67D0, 0x965F, 0x68D2, 0x9660, 0x5192, 0x9661, 0x7D21, 0x9662, 0x80AA, 0x9663, 0x81A8, 0x9664, 0x8B00, 0x9665, 0x8C8C, 0x9666, 0x8CBF, 0x9667, 0x927E, 0x9668, 0x9632, 0x9669, 0x5420, 0x966A, 0x982C, 0x966B, 0x5317, 0x966C, 0x50D5, 0x966D, 0x535C, 0x966E, 0x58A8, 0x966F, 0x64B2, 0x9670, 0x6734, 0x9671, 0x7267, 0x9672, 0x7766, 0x9673, 0x7A46, 0x9674, 0x91E6, 0x9675, 0x52C3, 0x9676, 0x6CA1, 0x9677, 0x6B86, 0x9678, 0x5800, 0x9679, 0x5E4C, 0x967A, 0x5954, 0x967B, 0x672C, 0x967C, 0x7FFB, 0x967D, 0x51E1, 0x967E, 0x76C6, 0x9680, 0x6469, 0x9681, 0x78E8, 0x9682, 0x9B54, 0x9683, 0x9EBB, 0x9684, 0x57CB, 0x9685, 0x59B9, 0x9686, 0x6627, 0x9687, 0x679A, 0x9688, 0x6BCE, 0x9689, 0x54E9, 0x968A, 0x69D9, 0x968B, 0x5E55, 0x968C, 0x819C, 0x968D, 0x6795, 0x968E, 0x9BAA, 0x968F, 0x67FE, 0x9690, 0x9C52, 0x9691, 0x685D, 0x9692, 0x4EA6, 0x9693, 0x4FE3, 0x9694, 0x53C8, 0x9695, 0x62B9, 0x9696, 0x672B, 0x9697, 0x6CAB, 0x9698, 0x8FC4, 0x9699, 0x4FAD, 0x969A, 0x7E6D, 0x969B, 0x9EBF, 0x969C, 0x4E07, 0x969D, 0x6162, 0x969E, 0x6E80, 0x969F, 0x6F2B, 0x96A0, 0x8513, 0x96A1, 0x5473, 0x96A2, 0x672A, 0x96A3, 0x9B45, 0x96A4, 0x5DF3, 0x96A5, 0x7B95, 0x96A6, 0x5CAC, 0x96A7, 0x5BC6, 0x96A8, 0x871C, 0x96A9, 0x6E4A, 0x96AA, 0x84D1, 0x96AB, 0x7A14, 0x96AC, 0x8108, 0x96AD, 0x5999, 0x96AE, 0x7C8D, 0x96AF, 0x6C11, 0x96B0, 0x7720, 0x96B1, 0x52D9, 0x96B2, 0x5922, 0x96B3, 0x7121, 0x96B4, 0x725F, 0x96B5, 0x77DB, 0x96B6, 0x9727, 0x96B7, 0x9D61, 0x96B8, 0x690B, 0x96B9, 0x5A7F, 0x96BA, 0x5A18, 0x96BB, 0x51A5, 0x96BC, 0x540D, 0x96BD, 0x547D, 0x96BE, 0x660E, 0x96BF, 0x76DF, 0x96C0, 0x8FF7, 0x96C1, 0x9298, 0x96C2, 0x9CF4, 0x96C3, 0x59EA, 0x96C4, 0x725D, 0x96C5, 0x6EC5, 0x96C6, 0x514D, 0x96C7, 0x68C9, 0x96C8, 0x7DBF, 0x96C9, 0x7DEC, 0x96CA, 0x9762, 0x96CB, 0x9EBA, 0x96CC, 0x6478, 0x96CD, 0x6A21, 0x96CE, 0x8302, 0x96CF, 0x5984, 0x96D0, 0x5B5F, 0x96D1, 0x6BDB, 0x96D2, 0x731B, 0x96D3, 0x76F2, 0x96D4, 0x7DB2, 0x96D5, 0x8017, 0x96D6, 0x8499, 0x96D7, 0x5132, 0x96D8, 0x6728, 0x96D9, 0x9ED9, 0x96DA, 0x76EE, 0x96DB, 0x6762, 0x96DC, 0x52FF, 0x96DD, 0x9905, 0x96DE, 0x5C24, 0x96DF, 0x623B, 0x96E0, 0x7C7E, 0x96E1, 0x8CB0, 0x96E2, 0x554F, 0x96E3, 0x60B6, 0x96E4, 0x7D0B, 0x96E5, 0x9580, 0x96E6, 0x5301, 0x96E7, 0x4E5F, 0x96E8, 0x51B6, 0x96E9, 0x591C, 0x96EA, 0x723A, 0x96EB, 0x8036, 0x96EC, 0x91CE, 0x96ED, 0x5F25, 0x96EE, 0x77E2, 0x96EF, 0x5384, 0x96F0, 0x5F79, 0x96F1, 0x7D04, 0x96F2, 0x85AC, 0x96F3, 0x8A33, 0x96F4, 0x8E8D, 0x96F5, 0x9756, 0x96F6, 0x67F3, 0x96F7, 0x85AE, 0x96F8, 0x9453, 0x96F9, 0x6109, 0x96FA, 0x6108, 0x96FB, 0x6CB9, 0x96FC, 0x7652, 0x9740, 0x8AED, 0x9741, 0x8F38, 0x9742, 0x552F, 0x9743, 0x4F51, 0x9744, 0x512A, 0x9745, 0x52C7, 0x9746, 0x53CB, 0x9747, 0x5BA5, 0x9748, 0x5E7D, 0x9749, 0x60A0, 0x974A, 0x6182, 0x974B, 0x63D6, 0x974C, 0x6709, 0x974D, 0x67DA, 0x974E, 0x6E67, 0x974F, 0x6D8C, 0x9750, 0x7336, 0x9751, 0x7337, 0x9752, 0x7531, 0x9753, 0x7950, 0x9754, 0x88D5, 0x9755, 0x8A98, 0x9756, 0x904A, 0x9757, 0x9091, 0x9758, 0x90F5, 0x9759, 0x96C4, 0x975A, 0x878D, 0x975B, 0x5915, 0x975C, 0x4E88, 0x975D, 0x4F59, 0x975E, 0x4E0E, 0x975F, 0x8A89, 0x9760, 0x8F3F, 0x9761, 0x9810, 0x9762, 0x50AD, 0x9763, 0x5E7C, 0x9764, 0x5996, 0x9765, 0x5BB9, 0x9766, 0x5EB8, 0x9767, 0x63DA, 0x9768, 0x63FA, 0x9769, 0x64C1, 0x976A, 0x66DC, 0x976B, 0x694A, 0x976C, 0x69D8, 0x976D, 0x6D0B, 0x976E, 0x6EB6, 0x976F, 0x7194, 0x9770, 0x7528, 0x9771, 0x7AAF, 0x9772, 0x7F8A, 0x9773, 0x8000, 0x9774, 0x8449, 0x9775, 0x84C9, 0x9776, 0x8981, 0x9777, 0x8B21, 0x9778, 0x8E0A, 0x9779, 0x9065, 0x977A, 0x967D, 0x977B, 0x990A, 0x977C, 0x617E, 0x977D, 0x6291, 0x977E, 0x6B32, 0x9780, 0x6C83, 0x9781, 0x6D74, 0x9782, 0x7FCC, 0x9783, 0x7FFC, 0x9784, 0x6DC0, 0x9785, 0x7F85, 0x9786, 0x87BA, 0x9787, 0x88F8, 0x9788, 0x6765, 0x9789, 0x83B1, 0x978A, 0x983C, 0x978B, 0x96F7, 0x978C, 0x6D1B, 0x978D, 0x7D61, 0x978E, 0x843D, 0x978F, 0x916A, 0x9790, 0x4E71, 0x9791, 0x5375, 0x9792, 0x5D50, 0x9793, 0x6B04, 0x9794, 0x6FEB, 0x9795, 0x85CD, 0x9796, 0x862D, 0x9797, 0x89A7, 0x9798, 0x5229, 0x9799, 0x540F, 0x979A, 0x5C65, 0x979B, 0x674E, 0x979C, 0x68A8, 0x979D, 0x7406, 0x979E, 0x7483, 0x979F, 0x75E2, 0x97A0, 0x88CF, 0x97A1, 0x88E1, 0x97A2, 0x91CC, 0x97A3, 0x96E2, 0x97A4, 0x9678, 0x97A5, 0x5F8B, 0x97A6, 0x7387, 0x97A7, 0x7ACB, 0x97A8, 0x844E, 0x97A9, 0x63A0, 0x97AA, 0x7565, 0x97AB, 0x5289, 0x97AC, 0x6D41, 0x97AD, 0x6E9C, 0x97AE, 0x7409, 0x97AF, 0x7559, 0x97B0, 0x786B, 0x97B1, 0x7C92, 0x97B2, 0x9686, 0x97B3, 0x7ADC, 0x97B4, 0x9F8D, 0x97B5, 0x4FB6, 0x97B6, 0x616E, 0x97B7, 0x65C5, 0x97B8, 0x865C, 0x97B9, 0x4E86, 0x97BA, 0x4EAE, 0x97BB, 0x50DA, 0x97BC, 0x4E21, 0x97BD, 0x51CC, 0x97BE, 0x5BEE, 0x97BF, 0x6599, 0x97C0, 0x6881, 0x97C1, 0x6DBC, 0x97C2, 0x731F, 0x97C3, 0x7642, 0x97C4, 0x77AD, 0x97C5, 0x7A1C, 0x97C6, 0x7CE7, 0x97C7, 0x826F, 0x97C8, 0x8AD2, 0x97C9, 0x907C, 0x97CA, 0x91CF, 0x97CB, 0x9675, 0x97CC, 0x9818, 0x97CD, 0x529B, 0x97CE, 0x7DD1, 0x97CF, 0x502B, 0x97D0, 0x5398, 0x97D1, 0x6797, 0x97D2, 0x6DCB, 0x97D3, 0x71D0, 0x97D4, 0x7433, 0x97D5, 0x81E8, 0x97D6, 0x8F2A, 0x97D7, 0x96A3, 0x97D8, 0x9C57, 0x97D9, 0x9E9F, 0x97DA, 0x7460, 0x97DB, 0x5841, 0x97DC, 0x6D99, 0x97DD, 0x7D2F, 0x97DE, 0x985E, 0x97DF, 0x4EE4, 0x97E0, 0x4F36, 0x97E1, 0x4F8B, 0x97E2, 0x51B7, 0x97E3, 0x52B1, 0x97E4, 0x5DBA, 0x97E5, 0x601C, 0x97E6, 0x73B2, 0x97E7, 0x793C, 0x97E8, 0x82D3, 0x97E9, 0x9234, 0x97EA, 0x96B7, 0x97EB, 0x96F6, 0x97EC, 0x970A, 0x97ED, 0x9E97, 0x97EE, 0x9F62, 0x97EF, 0x66A6, 0x97F0, 0x6B74, 0x97F1, 0x5217, 0x97F2, 0x52A3, 0x97F3, 0x70C8, 0x97F4, 0x88C2, 0x97F5, 0x5EC9, 0x97F6, 0x604B, 0x97F7, 0x6190, 0x97F8, 0x6F23, 0x97F9, 0x7149, 0x97FA, 0x7C3E, 0x97FB, 0x7DF4, 0x97FC, 0x806F, 0x9840, 0x84EE, 0x9841, 0x9023, 0x9842, 0x932C, 0x9843, 0x5442, 0x9844, 0x9B6F, 0x9845, 0x6AD3, 0x9846, 0x7089, 0x9847, 0x8CC2, 0x9848, 0x8DEF, 0x9849, 0x9732, 0x984A, 0x52B4, 0x984B, 0x5A41, 0x984C, 0x5ECA, 0x984D, 0x5F04, 0x984E, 0x6717, 0x984F, 0x697C, 0x9850, 0x6994, 0x9851, 0x6D6A, 0x9852, 0x6F0F, 0x9853, 0x7262, 0x9854, 0x72FC, 0x9855, 0x7BED, 0x9856, 0x8001, 0x9857, 0x807E, 0x9858, 0x874B, 0x9859, 0x90CE, 0x985A, 0x516D, 0x985B, 0x9E93, 0x985C, 0x7984, 0x985D, 0x808B, 0x985E, 0x9332, 0x985F, 0x8AD6, 0x9860, 0x502D, 0x9861, 0x548C, 0x9862, 0x8A71, 0x9863, 0x6B6A, 0x9864, 0x8CC4, 0x9865, 0x8107, 0x9866, 0x60D1, 0x9867, 0x67A0, 0x9868, 0x9DF2, 0x9869, 0x4E99, 0x986A, 0x4E98, 0x986B, 0x9C10, 0x986C, 0x8A6B, 0x986D, 0x85C1, 0x986E, 0x8568, 0x986F, 0x6900, 0x9870, 0x6E7E, 0x9871, 0x7897, 0x9872, 0x8155, 0x989F, 0x5F0C, 0x98A0, 0x4E10, 0x98A1, 0x4E15, 0x98A2, 0x4E2A, 0x98A3, 0x4E31, 0x98A4, 0x4E36, 0x98A5, 0x4E3C, 0x98A6, 0x4E3F, 0x98A7, 0x4E42, 0x98A8, 0x4E56, 0x98A9, 0x4E58, 0x98AA, 0x4E82, 0x98AB, 0x4E85, 0x98AC, 0x8C6B, 0x98AD, 0x4E8A, 0x98AE, 0x8212, 0x98AF, 0x5F0D, 0x98B0, 0x4E8E, 0x98B1, 0x4E9E, 0x98B2, 0x4E9F, 0x98B3, 0x4EA0, 0x98B4, 0x4EA2, 0x98B5, 0x4EB0, 0x98B6, 0x4EB3, 0x98B7, 0x4EB6, 0x98B8, 0x4ECE, 0x98B9, 0x4ECD, 0x98BA, 0x4EC4, 0x98BB, 0x4EC6, 0x98BC, 0x4EC2, 0x98BD, 0x4ED7, 0x98BE, 0x4EDE, 0x98BF, 0x4EED, 0x98C0, 0x4EDF, 0x98C1, 0x4EF7, 0x98C2, 0x4F09, 0x98C3, 0x4F5A, 0x98C4, 0x4F30, 0x98C5, 0x4F5B, 0x98C6, 0x4F5D, 0x98C7, 0x4F57, 0x98C8, 0x4F47, 0x98C9, 0x4F76, 0x98CA, 0x4F88, 0x98CB, 0x4F8F, 0x98CC, 0x4F98, 0x98CD, 0x4F7B, 0x98CE, 0x4F69, 0x98CF, 0x4F70, 0x98D0, 0x4F91, 0x98D1, 0x4F6F, 0x98D2, 0x4F86, 0x98D3, 0x4F96, 0x98D4, 0x5118, 0x98D5, 0x4FD4, 0x98D6, 0x4FDF, 0x98D7, 0x4FCE, 0x98D8, 0x4FD8, 0x98D9, 0x4FDB, 0x98DA, 0x4FD1, 0x98DB, 0x4FDA, 0x98DC, 0x4FD0, 0x98DD, 0x4FE4, 0x98DE, 0x4FE5, 0x98DF, 0x501A, 0x98E0, 0x5028, 0x98E1, 0x5014, 0x98E2, 0x502A, 0x98E3, 0x5025, 0x98E4, 0x5005, 0x98E5, 0x4F1C, 0x98E6, 0x4FF6, 0x98E7, 0x5021, 0x98E8, 0x5029, 0x98E9, 0x502C, 0x98EA, 0x4FFE, 0x98EB, 0x4FEF, 0x98EC, 0x5011, 0x98ED, 0x5006, 0x98EE, 0x5043, 0x98EF, 0x5047, 0x98F0, 0x6703, 0x98F1, 0x5055, 0x98F2, 0x5050, 0x98F3, 0x5048, 0x98F4, 0x505A, 0x98F5, 0x5056, 0x98F6, 0x506C, 0x98F7, 0x5078, 0x98F8, 0x5080, 0x98F9, 0x509A, 0x98FA, 0x5085, 0x98FB, 0x50B4, 0x98FC, 0x50B2, 0x9940, 0x50C9, 0x9941, 0x50CA, 0x9942, 0x50B3, 0x9943, 0x50C2, 0x9944, 0x50D6, 0x9945, 0x50DE, 0x9946, 0x50E5, 0x9947, 0x50ED, 0x9948, 0x50E3, 0x9949, 0x50EE, 0x994A, 0x50F9, 0x994B, 0x50F5, 0x994C, 0x5109, 0x994D, 0x5101, 0x994E, 0x5102, 0x994F, 0x5116, 0x9950, 0x5115, 0x9951, 0x5114, 0x9952, 0x511A, 0x9953, 0x5121, 0x9954, 0x513A, 0x9955, 0x5137, 0x9956, 0x513C, 0x9957, 0x513B, 0x9958, 0x513F, 0x9959, 0x5140, 0x995A, 0x5152, 0x995B, 0x514C, 0x995C, 0x5154, 0x995D, 0x5162, 0x995E, 0x7AF8, 0x995F, 0x5169, 0x9960, 0x516A, 0x9961, 0x516E, 0x9962, 0x5180, 0x9963, 0x5182, 0x9964, 0x56D8, 0x9965, 0x518C, 0x9966, 0x5189, 0x9967, 0x518F, 0x9968, 0x5191, 0x9969, 0x5193, 0x996A, 0x5195, 0x996B, 0x5196, 0x996C, 0x51A4, 0x996D, 0x51A6, 0x996E, 0x51A2, 0x996F, 0x51A9, 0x9970, 0x51AA, 0x9971, 0x51AB, 0x9972, 0x51B3, 0x9973, 0x51B1, 0x9974, 0x51B2, 0x9975, 0x51B0, 0x9976, 0x51B5, 0x9977, 0x51BD, 0x9978, 0x51C5, 0x9979, 0x51C9, 0x997A, 0x51DB, 0x997B, 0x51E0, 0x997C, 0x8655, 0x997D, 0x51E9, 0x997E, 0x51ED, 0x9980, 0x51F0, 0x9981, 0x51F5, 0x9982, 0x51FE, 0x9983, 0x5204, 0x9984, 0x520B, 0x9985, 0x5214, 0x9986, 0x520E, 0x9987, 0x5227, 0x9988, 0x522A, 0x9989, 0x522E, 0x998A, 0x5233, 0x998B, 0x5239, 0x998C, 0x524F, 0x998D, 0x5244, 0x998E, 0x524B, 0x998F, 0x524C, 0x9990, 0x525E, 0x9991, 0x5254, 0x9992, 0x526A, 0x9993, 0x5274, 0x9994, 0x5269, 0x9995, 0x5273, 0x9996, 0x527F, 0x9997, 0x527D, 0x9998, 0x528D, 0x9999, 0x5294, 0x999A, 0x5292, 0x999B, 0x5271, 0x999C, 0x5288, 0x999D, 0x5291, 0x999E, 0x8FA8, 0x999F, 0x8FA7, 0x99A0, 0x52AC, 0x99A1, 0x52AD, 0x99A2, 0x52BC, 0x99A3, 0x52B5, 0x99A4, 0x52C1, 0x99A5, 0x52CD, 0x99A6, 0x52D7, 0x99A7, 0x52DE, 0x99A8, 0x52E3, 0x99A9, 0x52E6, 0x99AA, 0x98ED, 0x99AB, 0x52E0, 0x99AC, 0x52F3, 0x99AD, 0x52F5, 0x99AE, 0x52F8, 0x99AF, 0x52F9, 0x99B0, 0x5306, 0x99B1, 0x5308, 0x99B2, 0x7538, 0x99B3, 0x530D, 0x99B4, 0x5310, 0x99B5, 0x530F, 0x99B6, 0x5315, 0x99B7, 0x531A, 0x99B8, 0x5323, 0x99B9, 0x532F, 0x99BA, 0x5331, 0x99BB, 0x5333, 0x99BC, 0x5338, 0x99BD, 0x5340, 0x99BE, 0x5346, 0x99BF, 0x5345, 0x99C0, 0x4E17, 0x99C1, 0x5349, 0x99C2, 0x534D, 0x99C3, 0x51D6, 0x99C4, 0x535E, 0x99C5, 0x5369, 0x99C6, 0x536E, 0x99C7, 0x5918, 0x99C8, 0x537B, 0x99C9, 0x5377, 0x99CA, 0x5382, 0x99CB, 0x5396, 0x99CC, 0x53A0, 0x99CD, 0x53A6, 0x99CE, 0x53A5, 0x99CF, 0x53AE, 0x99D0, 0x53B0, 0x99D1, 0x53B6, 0x99D2, 0x53C3, 0x99D3, 0x7C12, 0x99D4, 0x96D9, 0x99D5, 0x53DF, 0x99D6, 0x66FC, 0x99D7, 0x71EE, 0x99D8, 0x53EE, 0x99D9, 0x53E8, 0x99DA, 0x53ED, 0x99DB, 0x53FA, 0x99DC, 0x5401, 0x99DD, 0x543D, 0x99DE, 0x5440, 0x99DF, 0x542C, 0x99E0, 0x542D, 0x99E1, 0x543C, 0x99E2, 0x542E, 0x99E3, 0x5436, 0x99E4, 0x5429, 0x99E5, 0x541D, 0x99E6, 0x544E, 0x99E7, 0x548F, 0x99E8, 0x5475, 0x99E9, 0x548E, 0x99EA, 0x545F, 0x99EB, 0x5471, 0x99EC, 0x5477, 0x99ED, 0x5470, 0x99EE, 0x5492, 0x99EF, 0x547B, 0x99F0, 0x5480, 0x99F1, 0x5476, 0x99F2, 0x5484, 0x99F3, 0x5490, 0x99F4, 0x5486, 0x99F5, 0x54C7, 0x99F6, 0x54A2, 0x99F7, 0x54B8, 0x99F8, 0x54A5, 0x99F9, 0x54AC, 0x99FA, 0x54C4, 0x99FB, 0x54C8, 0x99FC, 0x54A8, 0x9A40, 0x54AB, 0x9A41, 0x54C2, 0x9A42, 0x54A4, 0x9A43, 0x54BE, 0x9A44, 0x54BC, 0x9A45, 0x54D8, 0x9A46, 0x54E5, 0x9A47, 0x54E6, 0x9A48, 0x550F, 0x9A49, 0x5514, 0x9A4A, 0x54FD, 0x9A4B, 0x54EE, 0x9A4C, 0x54ED, 0x9A4D, 0x54FA, 0x9A4E, 0x54E2, 0x9A4F, 0x5539, 0x9A50, 0x5540, 0x9A51, 0x5563, 0x9A52, 0x554C, 0x9A53, 0x552E, 0x9A54, 0x555C, 0x9A55, 0x5545, 0x9A56, 0x5556, 0x9A57, 0x5557, 0x9A58, 0x5538, 0x9A59, 0x5533, 0x9A5A, 0x555D, 0x9A5B, 0x5599, 0x9A5C, 0x5580, 0x9A5D, 0x54AF, 0x9A5E, 0x558A, 0x9A5F, 0x559F, 0x9A60, 0x557B, 0x9A61, 0x557E, 0x9A62, 0x5598, 0x9A63, 0x559E, 0x9A64, 0x55AE, 0x9A65, 0x557C, 0x9A66, 0x5583, 0x9A67, 0x55A9, 0x9A68, 0x5587, 0x9A69, 0x55A8, 0x9A6A, 0x55DA, 0x9A6B, 0x55C5, 0x9A6C, 0x55DF, 0x9A6D, 0x55C4, 0x9A6E, 0x55DC, 0x9A6F, 0x55E4, 0x9A70, 0x55D4, 0x9A71, 0x5614, 0x9A72, 0x55F7, 0x9A73, 0x5616, 0x9A74, 0x55FE, 0x9A75, 0x55FD, 0x9A76, 0x561B, 0x9A77, 0x55F9, 0x9A78, 0x564E, 0x9A79, 0x5650, 0x9A7A, 0x71DF, 0x9A7B, 0x5634, 0x9A7C, 0x5636, 0x9A7D, 0x5632, 0x9A7E, 0x5638, 0x9A80, 0x566B, 0x9A81, 0x5664, 0x9A82, 0x562F, 0x9A83, 0x566C, 0x9A84, 0x566A, 0x9A85, 0x5686, 0x9A86, 0x5680, 0x9A87, 0x568A, 0x9A88, 0x56A0, 0x9A89, 0x5694, 0x9A8A, 0x568F, 0x9A8B, 0x56A5, 0x9A8C, 0x56AE, 0x9A8D, 0x56B6, 0x9A8E, 0x56B4, 0x9A8F, 0x56C2, 0x9A90, 0x56BC, 0x9A91, 0x56C1, 0x9A92, 0x56C3, 0x9A93, 0x56C0, 0x9A94, 0x56C8, 0x9A95, 0x56CE, 0x9A96, 0x56D1, 0x9A97, 0x56D3, 0x9A98, 0x56D7, 0x9A99, 0x56EE, 0x9A9A, 0x56F9, 0x9A9B, 0x5700, 0x9A9C, 0x56FF, 0x9A9D, 0x5704, 0x9A9E, 0x5709, 0x9A9F, 0x5708, 0x9AA0, 0x570B, 0x9AA1, 0x570D, 0x9AA2, 0x5713, 0x9AA3, 0x5718, 0x9AA4, 0x5716, 0x9AA5, 0x55C7, 0x9AA6, 0x571C, 0x9AA7, 0x5726, 0x9AA8, 0x5737, 0x9AA9, 0x5738, 0x9AAA, 0x574E, 0x9AAB, 0x573B, 0x9AAC, 0x5740, 0x9AAD, 0x574F, 0x9AAE, 0x5769, 0x9AAF, 0x57C0, 0x9AB0, 0x5788, 0x9AB1, 0x5761, 0x9AB2, 0x577F, 0x9AB3, 0x5789, 0x9AB4, 0x5793, 0x9AB5, 0x57A0, 0x9AB6, 0x57B3, 0x9AB7, 0x57A4, 0x9AB8, 0x57AA, 0x9AB9, 0x57B0, 0x9ABA, 0x57C3, 0x9ABB, 0x57C6, 0x9ABC, 0x57D4, 0x9ABD, 0x57D2, 0x9ABE, 0x57D3, 0x9ABF, 0x580A, 0x9AC0, 0x57D6, 0x9AC1, 0x57E3, 0x9AC2, 0x580B, 0x9AC3, 0x5819, 0x9AC4, 0x581D, 0x9AC5, 0x5872, 0x9AC6, 0x5821, 0x9AC7, 0x5862, 0x9AC8, 0x584B, 0x9AC9, 0x5870, 0x9ACA, 0x6BC0, 0x9ACB, 0x5852, 0x9ACC, 0x583D, 0x9ACD, 0x5879, 0x9ACE, 0x5885, 0x9ACF, 0x58B9, 0x9AD0, 0x589F, 0x9AD1, 0x58AB, 0x9AD2, 0x58BA, 0x9AD3, 0x58DE, 0x9AD4, 0x58BB, 0x9AD5, 0x58B8, 0x9AD6, 0x58AE, 0x9AD7, 0x58C5, 0x9AD8, 0x58D3, 0x9AD9, 0x58D1, 0x9ADA, 0x58D7, 0x9ADB, 0x58D9, 0x9ADC, 0x58D8, 0x9ADD, 0x58E5, 0x9ADE, 0x58DC, 0x9ADF, 0x58E4, 0x9AE0, 0x58DF, 0x9AE1, 0x58EF, 0x9AE2, 0x58FA, 0x9AE3, 0x58F9, 0x9AE4, 0x58FB, 0x9AE5, 0x58FC, 0x9AE6, 0x58FD, 0x9AE7, 0x5902, 0x9AE8, 0x590A, 0x9AE9, 0x5910, 0x9AEA, 0x591B, 0x9AEB, 0x68A6, 0x9AEC, 0x5925, 0x9AED, 0x592C, 0x9AEE, 0x592D, 0x9AEF, 0x5932, 0x9AF0, 0x5938, 0x9AF1, 0x593E, 0x9AF2, 0x7AD2, 0x9AF3, 0x5955, 0x9AF4, 0x5950, 0x9AF5, 0x594E, 0x9AF6, 0x595A, 0x9AF7, 0x5958, 0x9AF8, 0x5962, 0x9AF9, 0x5960, 0x9AFA, 0x5967, 0x9AFB, 0x596C, 0x9AFC, 0x5969, 0x9B40, 0x5978, 0x9B41, 0x5981, 0x9B42, 0x599D, 0x9B43, 0x4F5E, 0x9B44, 0x4FAB, 0x9B45, 0x59A3, 0x9B46, 0x59B2, 0x9B47, 0x59C6, 0x9B48, 0x59E8, 0x9B49, 0x59DC, 0x9B4A, 0x598D, 0x9B4B, 0x59D9, 0x9B4C, 0x59DA, 0x9B4D, 0x5A25, 0x9B4E, 0x5A1F, 0x9B4F, 0x5A11, 0x9B50, 0x5A1C, 0x9B51, 0x5A09, 0x9B52, 0x5A1A, 0x9B53, 0x5A40, 0x9B54, 0x5A6C, 0x9B55, 0x5A49, 0x9B56, 0x5A35, 0x9B57, 0x5A36, 0x9B58, 0x5A62, 0x9B59, 0x5A6A, 0x9B5A, 0x5A9A, 0x9B5B, 0x5ABC, 0x9B5C, 0x5ABE, 0x9B5D, 0x5ACB, 0x9B5E, 0x5AC2, 0x9B5F, 0x5ABD, 0x9B60, 0x5AE3, 0x9B61, 0x5AD7, 0x9B62, 0x5AE6, 0x9B63, 0x5AE9, 0x9B64, 0x5AD6, 0x9B65, 0x5AFA, 0x9B66, 0x5AFB, 0x9B67, 0x5B0C, 0x9B68, 0x5B0B, 0x9B69, 0x5B16, 0x9B6A, 0x5B32, 0x9B6B, 0x5AD0, 0x9B6C, 0x5B2A, 0x9B6D, 0x5B36, 0x9B6E, 0x5B3E, 0x9B6F, 0x5B43, 0x9B70, 0x5B45, 0x9B71, 0x5B40, 0x9B72, 0x5B51, 0x9B73, 0x5B55, 0x9B74, 0x5B5A, 0x9B75, 0x5B5B, 0x9B76, 0x5B65, 0x9B77, 0x5B69, 0x9B78, 0x5B70, 0x9B79, 0x5B73, 0x9B7A, 0x5B75, 0x9B7B, 0x5B78, 0x9B7C, 0x6588, 0x9B7D, 0x5B7A, 0x9B7E, 0x5B80, 0x9B80, 0x5B83, 0x9B81, 0x5BA6, 0x9B82, 0x5BB8, 0x9B83, 0x5BC3, 0x9B84, 0x5BC7, 0x9B85, 0x5BC9, 0x9B86, 0x5BD4, 0x9B87, 0x5BD0, 0x9B88, 0x5BE4, 0x9B89, 0x5BE6, 0x9B8A, 0x5BE2, 0x9B8B, 0x5BDE, 0x9B8C, 0x5BE5, 0x9B8D, 0x5BEB, 0x9B8E, 0x5BF0, 0x9B8F, 0x5BF6, 0x9B90, 0x5BF3, 0x9B91, 0x5C05, 0x9B92, 0x5C07, 0x9B93, 0x5C08, 0x9B94, 0x5C0D, 0x9B95, 0x5C13, 0x9B96, 0x5C20, 0x9B97, 0x5C22, 0x9B98, 0x5C28, 0x9B99, 0x5C38, 0x9B9A, 0x5C39, 0x9B9B, 0x5C41, 0x9B9C, 0x5C46, 0x9B9D, 0x5C4E, 0x9B9E, 0x5C53, 0x9B9F, 0x5C50, 0x9BA0, 0x5C4F, 0x9BA1, 0x5B71, 0x9BA2, 0x5C6C, 0x9BA3, 0x5C6E, 0x9BA4, 0x4E62, 0x9BA5, 0x5C76, 0x9BA6, 0x5C79, 0x9BA7, 0x5C8C, 0x9BA8, 0x5C91, 0x9BA9, 0x5C94, 0x9BAA, 0x599B, 0x9BAB, 0x5CAB, 0x9BAC, 0x5CBB, 0x9BAD, 0x5CB6, 0x9BAE, 0x5CBC, 0x9BAF, 0x5CB7, 0x9BB0, 0x5CC5, 0x9BB1, 0x5CBE, 0x9BB2, 0x5CC7, 0x9BB3, 0x5CD9, 0x9BB4, 0x5CE9, 0x9BB5, 0x5CFD, 0x9BB6, 0x5CFA, 0x9BB7, 0x5CED, 0x9BB8, 0x5D8C, 0x9BB9, 0x5CEA, 0x9BBA, 0x5D0B, 0x9BBB, 0x5D15, 0x9BBC, 0x5D17, 0x9BBD, 0x5D5C, 0x9BBE, 0x5D1F, 0x9BBF, 0x5D1B, 0x9BC0, 0x5D11, 0x9BC1, 0x5D14, 0x9BC2, 0x5D22, 0x9BC3, 0x5D1A, 0x9BC4, 0x5D19, 0x9BC5, 0x5D18, 0x9BC6, 0x5D4C, 0x9BC7, 0x5D52, 0x9BC8, 0x5D4E, 0x9BC9, 0x5D4B, 0x9BCA, 0x5D6C, 0x9BCB, 0x5D73, 0x9BCC, 0x5D76, 0x9BCD, 0x5D87, 0x9BCE, 0x5D84, 0x9BCF, 0x5D82, 0x9BD0, 0x5DA2, 0x9BD1, 0x5D9D, 0x9BD2, 0x5DAC, 0x9BD3, 0x5DAE, 0x9BD4, 0x5DBD, 0x9BD5, 0x5D90, 0x9BD6, 0x5DB7, 0x9BD7, 0x5DBC, 0x9BD8, 0x5DC9, 0x9BD9, 0x5DCD, 0x9BDA, 0x5DD3, 0x9BDB, 0x5DD2, 0x9BDC, 0x5DD6, 0x9BDD, 0x5DDB, 0x9BDE, 0x5DEB, 0x9BDF, 0x5DF2, 0x9BE0, 0x5DF5, 0x9BE1, 0x5E0B, 0x9BE2, 0x5E1A, 0x9BE3, 0x5E19, 0x9BE4, 0x5E11, 0x9BE5, 0x5E1B, 0x9BE6, 0x5E36, 0x9BE7, 0x5E37, 0x9BE8, 0x5E44, 0x9BE9, 0x5E43, 0x9BEA, 0x5E40, 0x9BEB, 0x5E4E, 0x9BEC, 0x5E57, 0x9BED, 0x5E54, 0x9BEE, 0x5E5F, 0x9BEF, 0x5E62, 0x9BF0, 0x5E64, 0x9BF1, 0x5E47, 0x9BF2, 0x5E75, 0x9BF3, 0x5E76, 0x9BF4, 0x5E7A, 0x9BF5, 0x9EBC, 0x9BF6, 0x5E7F, 0x9BF7, 0x5EA0, 0x9BF8, 0x5EC1, 0x9BF9, 0x5EC2, 0x9BFA, 0x5EC8, 0x9BFB, 0x5ED0, 0x9BFC, 0x5ECF, 0x9C40, 0x5ED6, 0x9C41, 0x5EE3, 0x9C42, 0x5EDD, 0x9C43, 0x5EDA, 0x9C44, 0x5EDB, 0x9C45, 0x5EE2, 0x9C46, 0x5EE1, 0x9C47, 0x5EE8, 0x9C48, 0x5EE9, 0x9C49, 0x5EEC, 0x9C4A, 0x5EF1, 0x9C4B, 0x5EF3, 0x9C4C, 0x5EF0, 0x9C4D, 0x5EF4, 0x9C4E, 0x5EF8, 0x9C4F, 0x5EFE, 0x9C50, 0x5F03, 0x9C51, 0x5F09, 0x9C52, 0x5F5D, 0x9C53, 0x5F5C, 0x9C54, 0x5F0B, 0x9C55, 0x5F11, 0x9C56, 0x5F16, 0x9C57, 0x5F29, 0x9C58, 0x5F2D, 0x9C59, 0x5F38, 0x9C5A, 0x5F41, 0x9C5B, 0x5F48, 0x9C5C, 0x5F4C, 0x9C5D, 0x5F4E, 0x9C5E, 0x5F2F, 0x9C5F, 0x5F51, 0x9C60, 0x5F56, 0x9C61, 0x5F57, 0x9C62, 0x5F59, 0x9C63, 0x5F61, 0x9C64, 0x5F6D, 0x9C65, 0x5F73, 0x9C66, 0x5F77, 0x9C67, 0x5F83, 0x9C68, 0x5F82, 0x9C69, 0x5F7F, 0x9C6A, 0x5F8A, 0x9C6B, 0x5F88, 0x9C6C, 0x5F91, 0x9C6D, 0x5F87, 0x9C6E, 0x5F9E, 0x9C6F, 0x5F99, 0x9C70, 0x5F98, 0x9C71, 0x5FA0, 0x9C72, 0x5FA8, 0x9C73, 0x5FAD, 0x9C74, 0x5FBC, 0x9C75, 0x5FD6, 0x9C76, 0x5FFB, 0x9C77, 0x5FE4, 0x9C78, 0x5FF8, 0x9C79, 0x5FF1, 0x9C7A, 0x5FDD, 0x9C7B, 0x60B3, 0x9C7C, 0x5FFF, 0x9C7D, 0x6021, 0x9C7E, 0x6060, 0x9C80, 0x6019, 0x9C81, 0x6010, 0x9C82, 0x6029, 0x9C83, 0x600E, 0x9C84, 0x6031, 0x9C85, 0x601B, 0x9C86, 0x6015, 0x9C87, 0x602B, 0x9C88, 0x6026, 0x9C89, 0x600F, 0x9C8A, 0x603A, 0x9C8B, 0x605A, 0x9C8C, 0x6041, 0x9C8D, 0x606A, 0x9C8E, 0x6077, 0x9C8F, 0x605F, 0x9C90, 0x604A, 0x9C91, 0x6046, 0x9C92, 0x604D, 0x9C93, 0x6063, 0x9C94, 0x6043, 0x9C95, 0x6064, 0x9C96, 0x6042, 0x9C97, 0x606C, 0x9C98, 0x606B, 0x9C99, 0x6059, 0x9C9A, 0x6081, 0x9C9B, 0x608D, 0x9C9C, 0x60E7, 0x9C9D, 0x6083, 0x9C9E, 0x609A, 0x9C9F, 0x6084, 0x9CA0, 0x609B, 0x9CA1, 0x6096, 0x9CA2, 0x6097, 0x9CA3, 0x6092, 0x9CA4, 0x60A7, 0x9CA5, 0x608B, 0x9CA6, 0x60E1, 0x9CA7, 0x60B8, 0x9CA8, 0x60E0, 0x9CA9, 0x60D3, 0x9CAA, 0x60B4, 0x9CAB, 0x5FF0, 0x9CAC, 0x60BD, 0x9CAD, 0x60C6, 0x9CAE, 0x60B5, 0x9CAF, 0x60D8, 0x9CB0, 0x614D, 0x9CB1, 0x6115, 0x9CB2, 0x6106, 0x9CB3, 0x60F6, 0x9CB4, 0x60F7, 0x9CB5, 0x6100, 0x9CB6, 0x60F4, 0x9CB7, 0x60FA, 0x9CB8, 0x6103, 0x9CB9, 0x6121, 0x9CBA, 0x60FB, 0x9CBB, 0x60F1, 0x9CBC, 0x610D, 0x9CBD, 0x610E, 0x9CBE, 0x6147, 0x9CBF, 0x613E, 0x9CC0, 0x6128, 0x9CC1, 0x6127, 0x9CC2, 0x614A, 0x9CC3, 0x613F, 0x9CC4, 0x613C, 0x9CC5, 0x612C, 0x9CC6, 0x6134, 0x9CC7, 0x613D, 0x9CC8, 0x6142, 0x9CC9, 0x6144, 0x9CCA, 0x6173, 0x9CCB, 0x6177, 0x9CCC, 0x6158, 0x9CCD, 0x6159, 0x9CCE, 0x615A, 0x9CCF, 0x616B, 0x9CD0, 0x6174, 0x9CD1, 0x616F, 0x9CD2, 0x6165, 0x9CD3, 0x6171, 0x9CD4, 0x615F, 0x9CD5, 0x615D, 0x9CD6, 0x6153, 0x9CD7, 0x6175, 0x9CD8, 0x6199, 0x9CD9, 0x6196, 0x9CDA, 0x6187, 0x9CDB, 0x61AC, 0x9CDC, 0x6194, 0x9CDD, 0x619A, 0x9CDE, 0x618A, 0x9CDF, 0x6191, 0x9CE0, 0x61AB, 0x9CE1, 0x61AE, 0x9CE2, 0x61CC, 0x9CE3, 0x61CA, 0x9CE4, 0x61C9, 0x9CE5, 0x61F7, 0x9CE6, 0x61C8, 0x9CE7, 0x61C3, 0x9CE8, 0x61C6, 0x9CE9, 0x61BA, 0x9CEA, 0x61CB, 0x9CEB, 0x7F79, 0x9CEC, 0x61CD, 0x9CED, 0x61E6, 0x9CEE, 0x61E3, 0x9CEF, 0x61F6, 0x9CF0, 0x61FA, 0x9CF1, 0x61F4, 0x9CF2, 0x61FF, 0x9CF3, 0x61FD, 0x9CF4, 0x61FC, 0x9CF5, 0x61FE, 0x9CF6, 0x6200, 0x9CF7, 0x6208, 0x9CF8, 0x6209, 0x9CF9, 0x620D, 0x9CFA, 0x620C, 0x9CFB, 0x6214, 0x9CFC, 0x621B, 0x9D40, 0x621E, 0x9D41, 0x6221, 0x9D42, 0x622A, 0x9D43, 0x622E, 0x9D44, 0x6230, 0x9D45, 0x6232, 0x9D46, 0x6233, 0x9D47, 0x6241, 0x9D48, 0x624E, 0x9D49, 0x625E, 0x9D4A, 0x6263, 0x9D4B, 0x625B, 0x9D4C, 0x6260, 0x9D4D, 0x6268, 0x9D4E, 0x627C, 0x9D4F, 0x6282, 0x9D50, 0x6289, 0x9D51, 0x627E, 0x9D52, 0x6292, 0x9D53, 0x6293, 0x9D54, 0x6296, 0x9D55, 0x62D4, 0x9D56, 0x6283, 0x9D57, 0x6294, 0x9D58, 0x62D7, 0x9D59, 0x62D1, 0x9D5A, 0x62BB, 0x9D5B, 0x62CF, 0x9D5C, 0x62FF, 0x9D5D, 0x62C6, 0x9D5E, 0x64D4, 0x9D5F, 0x62C8, 0x9D60, 0x62DC, 0x9D61, 0x62CC, 0x9D62, 0x62CA, 0x9D63, 0x62C2, 0x9D64, 0x62C7, 0x9D65, 0x629B, 0x9D66, 0x62C9, 0x9D67, 0x630C, 0x9D68, 0x62EE, 0x9D69, 0x62F1, 0x9D6A, 0x6327, 0x9D6B, 0x6302, 0x9D6C, 0x6308, 0x9D6D, 0x62EF, 0x9D6E, 0x62F5, 0x9D6F, 0x6350, 0x9D70, 0x633E, 0x9D71, 0x634D, 0x9D72, 0x641C, 0x9D73, 0x634F, 0x9D74, 0x6396, 0x9D75, 0x638E, 0x9D76, 0x6380, 0x9D77, 0x63AB, 0x9D78, 0x6376, 0x9D79, 0x63A3, 0x9D7A, 0x638F, 0x9D7B, 0x6389, 0x9D7C, 0x639F, 0x9D7D, 0x63B5, 0x9D7E, 0x636B, 0x9D80, 0x6369, 0x9D81, 0x63BE, 0x9D82, 0x63E9, 0x9D83, 0x63C0, 0x9D84, 0x63C6, 0x9D85, 0x63E3, 0x9D86, 0x63C9, 0x9D87, 0x63D2, 0x9D88, 0x63F6, 0x9D89, 0x63C4, 0x9D8A, 0x6416, 0x9D8B, 0x6434, 0x9D8C, 0x6406, 0x9D8D, 0x6413, 0x9D8E, 0x6426, 0x9D8F, 0x6436, 0x9D90, 0x651D, 0x9D91, 0x6417, 0x9D92, 0x6428, 0x9D93, 0x640F, 0x9D94, 0x6467, 0x9D95, 0x646F, 0x9D96, 0x6476, 0x9D97, 0x644E, 0x9D98, 0x652A, 0x9D99, 0x6495, 0x9D9A, 0x6493, 0x9D9B, 0x64A5, 0x9D9C, 0x64A9, 0x9D9D, 0x6488, 0x9D9E, 0x64BC, 0x9D9F, 0x64DA, 0x9DA0, 0x64D2, 0x9DA1, 0x64C5, 0x9DA2, 0x64C7, 0x9DA3, 0x64BB, 0x9DA4, 0x64D8, 0x9DA5, 0x64C2, 0x9DA6, 0x64F1, 0x9DA7, 0x64E7, 0x9DA8, 0x8209, 0x9DA9, 0x64E0, 0x9DAA, 0x64E1, 0x9DAB, 0x62AC, 0x9DAC, 0x64E3, 0x9DAD, 0x64EF, 0x9DAE, 0x652C, 0x9DAF, 0x64F6, 0x9DB0, 0x64F4, 0x9DB1, 0x64F2, 0x9DB2, 0x64FA, 0x9DB3, 0x6500, 0x9DB4, 0x64FD, 0x9DB5, 0x6518, 0x9DB6, 0x651C, 0x9DB7, 0x6505, 0x9DB8, 0x6524, 0x9DB9, 0x6523, 0x9DBA, 0x652B, 0x9DBB, 0x6534, 0x9DBC, 0x6535, 0x9DBD, 0x6537, 0x9DBE, 0x6536, 0x9DBF, 0x6538, 0x9DC0, 0x754B, 0x9DC1, 0x6548, 0x9DC2, 0x6556, 0x9DC3, 0x6555, 0x9DC4, 0x654D, 0x9DC5, 0x6558, 0x9DC6, 0x655E, 0x9DC7, 0x655D, 0x9DC8, 0x6572, 0x9DC9, 0x6578, 0x9DCA, 0x6582, 0x9DCB, 0x6583, 0x9DCC, 0x8B8A, 0x9DCD, 0x659B, 0x9DCE, 0x659F, 0x9DCF, 0x65AB, 0x9DD0, 0x65B7, 0x9DD1, 0x65C3, 0x9DD2, 0x65C6, 0x9DD3, 0x65C1, 0x9DD4, 0x65C4, 0x9DD5, 0x65CC, 0x9DD6, 0x65D2, 0x9DD7, 0x65DB, 0x9DD8, 0x65D9, 0x9DD9, 0x65E0, 0x9DDA, 0x65E1, 0x9DDB, 0x65F1, 0x9DDC, 0x6772, 0x9DDD, 0x660A, 0x9DDE, 0x6603, 0x9DDF, 0x65FB, 0x9DE0, 0x6773, 0x9DE1, 0x6635, 0x9DE2, 0x6636, 0x9DE3, 0x6634, 0x9DE4, 0x661C, 0x9DE5, 0x664F, 0x9DE6, 0x6644, 0x9DE7, 0x6649, 0x9DE8, 0x6641, 0x9DE9, 0x665E, 0x9DEA, 0x665D, 0x9DEB, 0x6664, 0x9DEC, 0x6667, 0x9DED, 0x6668, 0x9DEE, 0x665F, 0x9DEF, 0x6662, 0x9DF0, 0x6670, 0x9DF1, 0x6683, 0x9DF2, 0x6688, 0x9DF3, 0x668E, 0x9DF4, 0x6689, 0x9DF5, 0x6684, 0x9DF6, 0x6698, 0x9DF7, 0x669D, 0x9DF8, 0x66C1, 0x9DF9, 0x66B9, 0x9DFA, 0x66C9, 0x9DFB, 0x66BE, 0x9DFC, 0x66BC, 0x9E40, 0x66C4, 0x9E41, 0x66B8, 0x9E42, 0x66D6, 0x9E43, 0x66DA, 0x9E44, 0x66E0, 0x9E45, 0x663F, 0x9E46, 0x66E6, 0x9E47, 0x66E9, 0x9E48, 0x66F0, 0x9E49, 0x66F5, 0x9E4A, 0x66F7, 0x9E4B, 0x670F, 0x9E4C, 0x6716, 0x9E4D, 0x671E, 0x9E4E, 0x6726, 0x9E4F, 0x6727, 0x9E50, 0x9738, 0x9E51, 0x672E, 0x9E52, 0x673F, 0x9E53, 0x6736, 0x9E54, 0x6741, 0x9E55, 0x6738, 0x9E56, 0x6737, 0x9E57, 0x6746, 0x9E58, 0x675E, 0x9E59, 0x6760, 0x9E5A, 0x6759, 0x9E5B, 0x6763, 0x9E5C, 0x6764, 0x9E5D, 0x6789, 0x9E5E, 0x6770, 0x9E5F, 0x67A9, 0x9E60, 0x677C, 0x9E61, 0x676A, 0x9E62, 0x678C, 0x9E63, 0x678B, 0x9E64, 0x67A6, 0x9E65, 0x67A1, 0x9E66, 0x6785, 0x9E67, 0x67B7, 0x9E68, 0x67EF, 0x9E69, 0x67B4, 0x9E6A, 0x67EC, 0x9E6B, 0x67B3, 0x9E6C, 0x67E9, 0x9E6D, 0x67B8, 0x9E6E, 0x67E4, 0x9E6F, 0x67DE, 0x9E70, 0x67DD, 0x9E71, 0x67E2, 0x9E72, 0x67EE, 0x9E73, 0x67B9, 0x9E74, 0x67CE, 0x9E75, 0x67C6, 0x9E76, 0x67E7, 0x9E77, 0x6A9C, 0x9E78, 0x681E, 0x9E79, 0x6846, 0x9E7A, 0x6829, 0x9E7B, 0x6840, 0x9E7C, 0x684D, 0x9E7D, 0x6832, 0x9E7E, 0x684E, 0x9E80, 0x68B3, 0x9E81, 0x682B, 0x9E82, 0x6859, 0x9E83, 0x6863, 0x9E84, 0x6877, 0x9E85, 0x687F, 0x9E86, 0x689F, 0x9E87, 0x688F, 0x9E88, 0x68AD, 0x9E89, 0x6894, 0x9E8A, 0x689D, 0x9E8B, 0x689B, 0x9E8C, 0x6883, 0x9E8D, 0x6AAE, 0x9E8E, 0x68B9, 0x9E8F, 0x6874, 0x9E90, 0x68B5, 0x9E91, 0x68A0, 0x9E92, 0x68BA, 0x9E93, 0x690F, 0x9E94, 0x688D, 0x9E95, 0x687E, 0x9E96, 0x6901, 0x9E97, 0x68CA, 0x9E98, 0x6908, 0x9E99, 0x68D8, 0x9E9A, 0x6922, 0x9E9B, 0x6926, 0x9E9C, 0x68E1, 0x9E9D, 0x690C, 0x9E9E, 0x68CD, 0x9E9F, 0x68D4, 0x9EA0, 0x68E7, 0x9EA1, 0x68D5, 0x9EA2, 0x6936, 0x9EA3, 0x6912, 0x9EA4, 0x6904, 0x9EA5, 0x68D7, 0x9EA6, 0x68E3, 0x9EA7, 0x6925, 0x9EA8, 0x68F9, 0x9EA9, 0x68E0, 0x9EAA, 0x68EF, 0x9EAB, 0x6928, 0x9EAC, 0x692A, 0x9EAD, 0x691A, 0x9EAE, 0x6923, 0x9EAF, 0x6921, 0x9EB0, 0x68C6, 0x9EB1, 0x6979, 0x9EB2, 0x6977, 0x9EB3, 0x695C, 0x9EB4, 0x6978, 0x9EB5, 0x696B, 0x9EB6, 0x6954, 0x9EB7, 0x697E, 0x9EB8, 0x696E, 0x9EB9, 0x6939, 0x9EBA, 0x6974, 0x9EBB, 0x693D, 0x9EBC, 0x6959, 0x9EBD, 0x6930, 0x9EBE, 0x6961, 0x9EBF, 0x695E, 0x9EC0, 0x695D, 0x9EC1, 0x6981, 0x9EC2, 0x696A, 0x9EC3, 0x69B2, 0x9EC4, 0x69AE, 0x9EC5, 0x69D0, 0x9EC6, 0x69BF, 0x9EC7, 0x69C1, 0x9EC8, 0x69D3, 0x9EC9, 0x69BE, 0x9ECA, 0x69CE, 0x9ECB, 0x5BE8, 0x9ECC, 0x69CA, 0x9ECD, 0x69DD, 0x9ECE, 0x69BB, 0x9ECF, 0x69C3, 0x9ED0, 0x69A7, 0x9ED1, 0x6A2E, 0x9ED2, 0x6991, 0x9ED3, 0x69A0, 0x9ED4, 0x699C, 0x9ED5, 0x6995, 0x9ED6, 0x69B4, 0x9ED7, 0x69DE, 0x9ED8, 0x69E8, 0x9ED9, 0x6A02, 0x9EDA, 0x6A1B, 0x9EDB, 0x69FF, 0x9EDC, 0x6B0A, 0x9EDD, 0x69F9, 0x9EDE, 0x69F2, 0x9EDF, 0x69E7, 0x9EE0, 0x6A05, 0x9EE1, 0x69B1, 0x9EE2, 0x6A1E, 0x9EE3, 0x69ED, 0x9EE4, 0x6A14, 0x9EE5, 0x69EB, 0x9EE6, 0x6A0A, 0x9EE7, 0x6A12, 0x9EE8, 0x6AC1, 0x9EE9, 0x6A23, 0x9EEA, 0x6A13, 0x9EEB, 0x6A44, 0x9EEC, 0x6A0C, 0x9EED, 0x6A72, 0x9EEE, 0x6A36, 0x9EEF, 0x6A78, 0x9EF0, 0x6A47, 0x9EF1, 0x6A62, 0x9EF2, 0x6A59, 0x9EF3, 0x6A66, 0x9EF4, 0x6A48, 0x9EF5, 0x6A38, 0x9EF6, 0x6A22, 0x9EF7, 0x6A90, 0x9EF8, 0x6A8D, 0x9EF9, 0x6AA0, 0x9EFA, 0x6A84, 0x9EFB, 0x6AA2, 0x9EFC, 0x6AA3, 0x9F40, 0x6A97, 0x9F41, 0x8617, 0x9F42, 0x6ABB, 0x9F43, 0x6AC3, 0x9F44, 0x6AC2, 0x9F45, 0x6AB8, 0x9F46, 0x6AB3, 0x9F47, 0x6AAC, 0x9F48, 0x6ADE, 0x9F49, 0x6AD1, 0x9F4A, 0x6ADF, 0x9F4B, 0x6AAA, 0x9F4C, 0x6ADA, 0x9F4D, 0x6AEA, 0x9F4E, 0x6AFB, 0x9F4F, 0x6B05, 0x9F50, 0x8616, 0x9F51, 0x6AFA, 0x9F52, 0x6B12, 0x9F53, 0x6B16, 0x9F54, 0x9B31, 0x9F55, 0x6B1F, 0x9F56, 0x6B38, 0x9F57, 0x6B37, 0x9F58, 0x76DC, 0x9F59, 0x6B39, 0x9F5A, 0x98EE, 0x9F5B, 0x6B47, 0x9F5C, 0x6B43, 0x9F5D, 0x6B49, 0x9F5E, 0x6B50, 0x9F5F, 0x6B59, 0x9F60, 0x6B54, 0x9F61, 0x6B5B, 0x9F62, 0x6B5F, 0x9F63, 0x6B61, 0x9F64, 0x6B78, 0x9F65, 0x6B79, 0x9F66, 0x6B7F, 0x9F67, 0x6B80, 0x9F68, 0x6B84, 0x9F69, 0x6B83, 0x9F6A, 0x6B8D, 0x9F6B, 0x6B98, 0x9F6C, 0x6B95, 0x9F6D, 0x6B9E, 0x9F6E, 0x6BA4, 0x9F6F, 0x6BAA, 0x9F70, 0x6BAB, 0x9F71, 0x6BAF, 0x9F72, 0x6BB2, 0x9F73, 0x6BB1, 0x9F74, 0x6BB3, 0x9F75, 0x6BB7, 0x9F76, 0x6BBC, 0x9F77, 0x6BC6, 0x9F78, 0x6BCB, 0x9F79, 0x6BD3, 0x9F7A, 0x6BDF, 0x9F7B, 0x6BEC, 0x9F7C, 0x6BEB, 0x9F7D, 0x6BF3, 0x9F7E, 0x6BEF, 0x9F80, 0x9EBE, 0x9F81, 0x6C08, 0x9F82, 0x6C13, 0x9F83, 0x6C14, 0x9F84, 0x6C1B, 0x9F85, 0x6C24, 0x9F86, 0x6C23, 0x9F87, 0x6C5E, 0x9F88, 0x6C55, 0x9F89, 0x6C62, 0x9F8A, 0x6C6A, 0x9F8B, 0x6C82, 0x9F8C, 0x6C8D, 0x9F8D, 0x6C9A, 0x9F8E, 0x6C81, 0x9F8F, 0x6C9B, 0x9F90, 0x6C7E, 0x9F91, 0x6C68, 0x9F92, 0x6C73, 0x9F93, 0x6C92, 0x9F94, 0x6C90, 0x9F95, 0x6CC4, 0x9F96, 0x6CF1, 0x9F97, 0x6CD3, 0x9F98, 0x6CBD, 0x9F99, 0x6CD7, 0x9F9A, 0x6CC5, 0x9F9B, 0x6CDD, 0x9F9C, 0x6CAE, 0x9F9D, 0x6CB1, 0x9F9E, 0x6CBE, 0x9F9F, 0x6CBA, 0x9FA0, 0x6CDB, 0x9FA1, 0x6CEF, 0x9FA2, 0x6CD9, 0x9FA3, 0x6CEA, 0x9FA4, 0x6D1F, 0x9FA5, 0x884D, 0x9FA6, 0x6D36, 0x9FA7, 0x6D2B, 0x9FA8, 0x6D3D, 0x9FA9, 0x6D38, 0x9FAA, 0x6D19, 0x9FAB, 0x6D35, 0x9FAC, 0x6D33, 0x9FAD, 0x6D12, 0x9FAE, 0x6D0C, 0x9FAF, 0x6D63, 0x9FB0, 0x6D93, 0x9FB1, 0x6D64, 0x9FB2, 0x6D5A, 0x9FB3, 0x6D79, 0x9FB4, 0x6D59, 0x9FB5, 0x6D8E, 0x9FB6, 0x6D95, 0x9FB7, 0x6FE4, 0x9FB8, 0x6D85, 0x9FB9, 0x6DF9, 0x9FBA, 0x6E15, 0x9FBB, 0x6E0A, 0x9FBC, 0x6DB5, 0x9FBD, 0x6DC7, 0x9FBE, 0x6DE6, 0x9FBF, 0x6DB8, 0x9FC0, 0x6DC6, 0x9FC1, 0x6DEC, 0x9FC2, 0x6DDE, 0x9FC3, 0x6DCC, 0x9FC4, 0x6DE8, 0x9FC5, 0x6DD2, 0x9FC6, 0x6DC5, 0x9FC7, 0x6DFA, 0x9FC8, 0x6DD9, 0x9FC9, 0x6DE4, 0x9FCA, 0x6DD5, 0x9FCB, 0x6DEA, 0x9FCC, 0x6DEE, 0x9FCD, 0x6E2D, 0x9FCE, 0x6E6E, 0x9FCF, 0x6E2E, 0x9FD0, 0x6E19, 0x9FD1, 0x6E72, 0x9FD2, 0x6E5F, 0x9FD3, 0x6E3E, 0x9FD4, 0x6E23, 0x9FD5, 0x6E6B, 0x9FD6, 0x6E2B, 0x9FD7, 0x6E76, 0x9FD8, 0x6E4D, 0x9FD9, 0x6E1F, 0x9FDA, 0x6E43, 0x9FDB, 0x6E3A, 0x9FDC, 0x6E4E, 0x9FDD, 0x6E24, 0x9FDE, 0x6EFF, 0x9FDF, 0x6E1D, 0x9FE0, 0x6E38, 0x9FE1, 0x6E82, 0x9FE2, 0x6EAA, 0x9FE3, 0x6E98, 0x9FE4, 0x6EC9, 0x9FE5, 0x6EB7, 0x9FE6, 0x6ED3, 0x9FE7, 0x6EBD, 0x9FE8, 0x6EAF, 0x9FE9, 0x6EC4, 0x9FEA, 0x6EB2, 0x9FEB, 0x6ED4, 0x9FEC, 0x6ED5, 0x9FED, 0x6E8F, 0x9FEE, 0x6EA5, 0x9FEF, 0x6EC2, 0x9FF0, 0x6E9F, 0x9FF1, 0x6F41, 0x9FF2, 0x6F11, 0x9FF3, 0x704C, 0x9FF4, 0x6EEC, 0x9FF5, 0x6EF8, 0x9FF6, 0x6EFE, 0x9FF7, 0x6F3F, 0x9FF8, 0x6EF2, 0x9FF9, 0x6F31, 0x9FFA, 0x6EEF, 0x9FFB, 0x6F32, 0x9FFC, 0x6ECC, 0xE040, 0x6F3E, 0xE041, 0x6F13, 0xE042, 0x6EF7, 0xE043, 0x6F86, 0xE044, 0x6F7A, 0xE045, 0x6F78, 0xE046, 0x6F81, 0xE047, 0x6F80, 0xE048, 0x6F6F, 0xE049, 0x6F5B, 0xE04A, 0x6FF3, 0xE04B, 0x6F6D, 0xE04C, 0x6F82, 0xE04D, 0x6F7C, 0xE04E, 0x6F58, 0xE04F, 0x6F8E, 0xE050, 0x6F91, 0xE051, 0x6FC2, 0xE052, 0x6F66, 0xE053, 0x6FB3, 0xE054, 0x6FA3, 0xE055, 0x6FA1, 0xE056, 0x6FA4, 0xE057, 0x6FB9, 0xE058, 0x6FC6, 0xE059, 0x6FAA, 0xE05A, 0x6FDF, 0xE05B, 0x6FD5, 0xE05C, 0x6FEC, 0xE05D, 0x6FD4, 0xE05E, 0x6FD8, 0xE05F, 0x6FF1, 0xE060, 0x6FEE, 0xE061, 0x6FDB, 0xE062, 0x7009, 0xE063, 0x700B, 0xE064, 0x6FFA, 0xE065, 0x7011, 0xE066, 0x7001, 0xE067, 0x700F, 0xE068, 0x6FFE, 0xE069, 0x701B, 0xE06A, 0x701A, 0xE06B, 0x6F74, 0xE06C, 0x701D, 0xE06D, 0x7018, 0xE06E, 0x701F, 0xE06F, 0x7030, 0xE070, 0x703E, 0xE071, 0x7032, 0xE072, 0x7051, 0xE073, 0x7063, 0xE074, 0x7099, 0xE075, 0x7092, 0xE076, 0x70AF, 0xE077, 0x70F1, 0xE078, 0x70AC, 0xE079, 0x70B8, 0xE07A, 0x70B3, 0xE07B, 0x70AE, 0xE07C, 0x70DF, 0xE07D, 0x70CB, 0xE07E, 0x70DD, 0xE080, 0x70D9, 0xE081, 0x7109, 0xE082, 0x70FD, 0xE083, 0x711C, 0xE084, 0x7119, 0xE085, 0x7165, 0xE086, 0x7155, 0xE087, 0x7188, 0xE088, 0x7166, 0xE089, 0x7162, 0xE08A, 0x714C, 0xE08B, 0x7156, 0xE08C, 0x716C, 0xE08D, 0x718F, 0xE08E, 0x71FB, 0xE08F, 0x7184, 0xE090, 0x7195, 0xE091, 0x71A8, 0xE092, 0x71AC, 0xE093, 0x71D7, 0xE094, 0x71B9, 0xE095, 0x71BE, 0xE096, 0x71D2, 0xE097, 0x71C9, 0xE098, 0x71D4, 0xE099, 0x71CE, 0xE09A, 0x71E0, 0xE09B, 0x71EC, 0xE09C, 0x71E7, 0xE09D, 0x71F5, 0xE09E, 0x71FC, 0xE09F, 0x71F9, 0xE0A0, 0x71FF, 0xE0A1, 0x720D, 0xE0A2, 0x7210, 0xE0A3, 0x721B, 0xE0A4, 0x7228, 0xE0A5, 0x722D, 0xE0A6, 0x722C, 0xE0A7, 0x7230, 0xE0A8, 0x7232, 0xE0A9, 0x723B, 0xE0AA, 0x723C, 0xE0AB, 0x723F, 0xE0AC, 0x7240, 0xE0AD, 0x7246, 0xE0AE, 0x724B, 0xE0AF, 0x7258, 0xE0B0, 0x7274, 0xE0B1, 0x727E, 0xE0B2, 0x7282, 0xE0B3, 0x7281, 0xE0B4, 0x7287, 0xE0B5, 0x7292, 0xE0B6, 0x7296, 0xE0B7, 0x72A2, 0xE0B8, 0x72A7, 0xE0B9, 0x72B9, 0xE0BA, 0x72B2, 0xE0BB, 0x72C3, 0xE0BC, 0x72C6, 0xE0BD, 0x72C4, 0xE0BE, 0x72CE, 0xE0BF, 0x72D2, 0xE0C0, 0x72E2, 0xE0C1, 0x72E0, 0xE0C2, 0x72E1, 0xE0C3, 0x72F9, 0xE0C4, 0x72F7, 0xE0C5, 0x500F, 0xE0C6, 0x7317, 0xE0C7, 0x730A, 0xE0C8, 0x731C, 0xE0C9, 0x7316, 0xE0CA, 0x731D, 0xE0CB, 0x7334, 0xE0CC, 0x732F, 0xE0CD, 0x7329, 0xE0CE, 0x7325, 0xE0CF, 0x733E, 0xE0D0, 0x734E, 0xE0D1, 0x734F, 0xE0D2, 0x9ED8, 0xE0D3, 0x7357, 0xE0D4, 0x736A, 0xE0D5, 0x7368, 0xE0D6, 0x7370, 0xE0D7, 0x7378, 0xE0D8, 0x7375, 0xE0D9, 0x737B, 0xE0DA, 0x737A, 0xE0DB, 0x73C8, 0xE0DC, 0x73B3, 0xE0DD, 0x73CE, 0xE0DE, 0x73BB, 0xE0DF, 0x73C0, 0xE0E0, 0x73E5, 0xE0E1, 0x73EE, 0xE0E2, 0x73DE, 0xE0E3, 0x74A2, 0xE0E4, 0x7405, 0xE0E5, 0x746F, 0xE0E6, 0x7425, 0xE0E7, 0x73F8, 0xE0E8, 0x7432, 0xE0E9, 0x743A, 0xE0EA, 0x7455, 0xE0EB, 0x743F, 0xE0EC, 0x745F, 0xE0ED, 0x7459, 0xE0EE, 0x7441, 0xE0EF, 0x745C, 0xE0F0, 0x7469, 0xE0F1, 0x7470, 0xE0F2, 0x7463, 0xE0F3, 0x746A, 0xE0F4, 0x7476, 0xE0F5, 0x747E, 0xE0F6, 0x748B, 0xE0F7, 0x749E, 0xE0F8, 0x74A7, 0xE0F9, 0x74CA, 0xE0FA, 0x74CF, 0xE0FB, 0x74D4, 0xE0FC, 0x73F1, 0xE140, 0x74E0, 0xE141, 0x74E3, 0xE142, 0x74E7, 0xE143, 0x74E9, 0xE144, 0x74EE, 0xE145, 0x74F2, 0xE146, 0x74F0, 0xE147, 0x74F1, 0xE148, 0x74F8, 0xE149, 0x74F7, 0xE14A, 0x7504, 0xE14B, 0x7503, 0xE14C, 0x7505, 0xE14D, 0x750C, 0xE14E, 0x750E, 0xE14F, 0x750D, 0xE150, 0x7515, 0xE151, 0x7513, 0xE152, 0x751E, 0xE153, 0x7526, 0xE154, 0x752C, 0xE155, 0x753C, 0xE156, 0x7544, 0xE157, 0x754D, 0xE158, 0x754A, 0xE159, 0x7549, 0xE15A, 0x755B, 0xE15B, 0x7546, 0xE15C, 0x755A, 0xE15D, 0x7569, 0xE15E, 0x7564, 0xE15F, 0x7567, 0xE160, 0x756B, 0xE161, 0x756D, 0xE162, 0x7578, 0xE163, 0x7576, 0xE164, 0x7586, 0xE165, 0x7587, 0xE166, 0x7574, 0xE167, 0x758A, 0xE168, 0x7589, 0xE169, 0x7582, 0xE16A, 0x7594, 0xE16B, 0x759A, 0xE16C, 0x759D, 0xE16D, 0x75A5, 0xE16E, 0x75A3, 0xE16F, 0x75C2, 0xE170, 0x75B3, 0xE171, 0x75C3, 0xE172, 0x75B5, 0xE173, 0x75BD, 0xE174, 0x75B8, 0xE175, 0x75BC, 0xE176, 0x75B1, 0xE177, 0x75CD, 0xE178, 0x75CA, 0xE179, 0x75D2, 0xE17A, 0x75D9, 0xE17B, 0x75E3, 0xE17C, 0x75DE, 0xE17D, 0x75FE, 0xE17E, 0x75FF, 0xE180, 0x75FC, 0xE181, 0x7601, 0xE182, 0x75F0, 0xE183, 0x75FA, 0xE184, 0x75F2, 0xE185, 0x75F3, 0xE186, 0x760B, 0xE187, 0x760D, 0xE188, 0x7609, 0xE189, 0x761F, 0xE18A, 0x7627, 0xE18B, 0x7620, 0xE18C, 0x7621, 0xE18D, 0x7622, 0xE18E, 0x7624, 0xE18F, 0x7634, 0xE190, 0x7630, 0xE191, 0x763B, 0xE192, 0x7647, 0xE193, 0x7648, 0xE194, 0x7646, 0xE195, 0x765C, 0xE196, 0x7658, 0xE197, 0x7661, 0xE198, 0x7662, 0xE199, 0x7668, 0xE19A, 0x7669, 0xE19B, 0x766A, 0xE19C, 0x7667, 0xE19D, 0x766C, 0xE19E, 0x7670, 0xE19F, 0x7672, 0xE1A0, 0x7676, 0xE1A1, 0x7678, 0xE1A2, 0x767C, 0xE1A3, 0x7680, 0xE1A4, 0x7683, 0xE1A5, 0x7688, 0xE1A6, 0x768B, 0xE1A7, 0x768E, 0xE1A8, 0x7696, 0xE1A9, 0x7693, 0xE1AA, 0x7699, 0xE1AB, 0x769A, 0xE1AC, 0x76B0, 0xE1AD, 0x76B4, 0xE1AE, 0x76B8, 0xE1AF, 0x76B9, 0xE1B0, 0x76BA, 0xE1B1, 0x76C2, 0xE1B2, 0x76CD, 0xE1B3, 0x76D6, 0xE1B4, 0x76D2, 0xE1B5, 0x76DE, 0xE1B6, 0x76E1, 0xE1B7, 0x76E5, 0xE1B8, 0x76E7, 0xE1B9, 0x76EA, 0xE1BA, 0x862F, 0xE1BB, 0x76FB, 0xE1BC, 0x7708, 0xE1BD, 0x7707, 0xE1BE, 0x7704, 0xE1BF, 0x7729, 0xE1C0, 0x7724, 0xE1C1, 0x771E, 0xE1C2, 0x7725, 0xE1C3, 0x7726, 0xE1C4, 0x771B, 0xE1C5, 0x7737, 0xE1C6, 0x7738, 0xE1C7, 0x7747, 0xE1C8, 0x775A, 0xE1C9, 0x7768, 0xE1CA, 0x776B, 0xE1CB, 0x775B, 0xE1CC, 0x7765, 0xE1CD, 0x777F, 0xE1CE, 0x777E, 0xE1CF, 0x7779, 0xE1D0, 0x778E, 0xE1D1, 0x778B, 0xE1D2, 0x7791, 0xE1D3, 0x77A0, 0xE1D4, 0x779E, 0xE1D5, 0x77B0, 0xE1D6, 0x77B6, 0xE1D7, 0x77B9, 0xE1D8, 0x77BF, 0xE1D9, 0x77BC, 0xE1DA, 0x77BD, 0xE1DB, 0x77BB, 0xE1DC, 0x77C7, 0xE1DD, 0x77CD, 0xE1DE, 0x77D7, 0xE1DF, 0x77DA, 0xE1E0, 0x77DC, 0xE1E1, 0x77E3, 0xE1E2, 0x77EE, 0xE1E3, 0x77FC, 0xE1E4, 0x780C, 0xE1E5, 0x7812, 0xE1E6, 0x7926, 0xE1E7, 0x7820, 0xE1E8, 0x792A, 0xE1E9, 0x7845, 0xE1EA, 0x788E, 0xE1EB, 0x7874, 0xE1EC, 0x7886, 0xE1ED, 0x787C, 0xE1EE, 0x789A, 0xE1EF, 0x788C, 0xE1F0, 0x78A3, 0xE1F1, 0x78B5, 0xE1F2, 0x78AA, 0xE1F3, 0x78AF, 0xE1F4, 0x78D1, 0xE1F5, 0x78C6, 0xE1F6, 0x78CB, 0xE1F7, 0x78D4, 0xE1F8, 0x78BE, 0xE1F9, 0x78BC, 0xE1FA, 0x78C5, 0xE1FB, 0x78CA, 0xE1FC, 0x78EC, 0xE240, 0x78E7, 0xE241, 0x78DA, 0xE242, 0x78FD, 0xE243, 0x78F4, 0xE244, 0x7907, 0xE245, 0x7912, 0xE246, 0x7911, 0xE247, 0x7919, 0xE248, 0x792C, 0xE249, 0x792B, 0xE24A, 0x7940, 0xE24B, 0x7960, 0xE24C, 0x7957, 0xE24D, 0x795F, 0xE24E, 0x795A, 0xE24F, 0x7955, 0xE250, 0x7953, 0xE251, 0x797A, 0xE252, 0x797F, 0xE253, 0x798A, 0xE254, 0x799D, 0xE255, 0x79A7, 0xE256, 0x9F4B, 0xE257, 0x79AA, 0xE258, 0x79AE, 0xE259, 0x79B3, 0xE25A, 0x79B9, 0xE25B, 0x79BA, 0xE25C, 0x79C9, 0xE25D, 0x79D5, 0xE25E, 0x79E7, 0xE25F, 0x79EC, 0xE260, 0x79E1, 0xE261, 0x79E3, 0xE262, 0x7A08, 0xE263, 0x7A0D, 0xE264, 0x7A18, 0xE265, 0x7A19, 0xE266, 0x7A20, 0xE267, 0x7A1F, 0xE268, 0x7980, 0xE269, 0x7A31, 0xE26A, 0x7A3B, 0xE26B, 0x7A3E, 0xE26C, 0x7A37, 0xE26D, 0x7A43, 0xE26E, 0x7A57, 0xE26F, 0x7A49, 0xE270, 0x7A61, 0xE271, 0x7A62, 0xE272, 0x7A69, 0xE273, 0x9F9D, 0xE274, 0x7A70, 0xE275, 0x7A79, 0xE276, 0x7A7D, 0xE277, 0x7A88, 0xE278, 0x7A97, 0xE279, 0x7A95, 0xE27A, 0x7A98, 0xE27B, 0x7A96, 0xE27C, 0x7AA9, 0xE27D, 0x7AC8, 0xE27E, 0x7AB0, 0xE280, 0x7AB6, 0xE281, 0x7AC5, 0xE282, 0x7AC4, 0xE283, 0x7ABF, 0xE284, 0x9083, 0xE285, 0x7AC7, 0xE286, 0x7ACA, 0xE287, 0x7ACD, 0xE288, 0x7ACF, 0xE289, 0x7AD5, 0xE28A, 0x7AD3, 0xE28B, 0x7AD9, 0xE28C, 0x7ADA, 0xE28D, 0x7ADD, 0xE28E, 0x7AE1, 0xE28F, 0x7AE2, 0xE290, 0x7AE6, 0xE291, 0x7AED, 0xE292, 0x7AF0, 0xE293, 0x7B02, 0xE294, 0x7B0F, 0xE295, 0x7B0A, 0xE296, 0x7B06, 0xE297, 0x7B33, 0xE298, 0x7B18, 0xE299, 0x7B19, 0xE29A, 0x7B1E, 0xE29B, 0x7B35, 0xE29C, 0x7B28, 0xE29D, 0x7B36, 0xE29E, 0x7B50, 0xE29F, 0x7B7A, 0xE2A0, 0x7B04, 0xE2A1, 0x7B4D, 0xE2A2, 0x7B0B, 0xE2A3, 0x7B4C, 0xE2A4, 0x7B45, 0xE2A5, 0x7B75, 0xE2A6, 0x7B65, 0xE2A7, 0x7B74, 0xE2A8, 0x7B67, 0xE2A9, 0x7B70, 0xE2AA, 0x7B71, 0xE2AB, 0x7B6C, 0xE2AC, 0x7B6E, 0xE2AD, 0x7B9D, 0xE2AE, 0x7B98, 0xE2AF, 0x7B9F, 0xE2B0, 0x7B8D, 0xE2B1, 0x7B9C, 0xE2B2, 0x7B9A, 0xE2B3, 0x7B8B, 0xE2B4, 0x7B92, 0xE2B5, 0x7B8F, 0xE2B6, 0x7B5D, 0xE2B7, 0x7B99, 0xE2B8, 0x7BCB, 0xE2B9, 0x7BC1, 0xE2BA, 0x7BCC, 0xE2BB, 0x7BCF, 0xE2BC, 0x7BB4, 0xE2BD, 0x7BC6, 0xE2BE, 0x7BDD, 0xE2BF, 0x7BE9, 0xE2C0, 0x7C11, 0xE2C1, 0x7C14, 0xE2C2, 0x7BE6, 0xE2C3, 0x7BE5, 0xE2C4, 0x7C60, 0xE2C5, 0x7C00, 0xE2C6, 0x7C07, 0xE2C7, 0x7C13, 0xE2C8, 0x7BF3, 0xE2C9, 0x7BF7, 0xE2CA, 0x7C17, 0xE2CB, 0x7C0D, 0xE2CC, 0x7BF6, 0xE2CD, 0x7C23, 0xE2CE, 0x7C27, 0xE2CF, 0x7C2A, 0xE2D0, 0x7C1F, 0xE2D1, 0x7C37, 0xE2D2, 0x7C2B, 0xE2D3, 0x7C3D, 0xE2D4, 0x7C4C, 0xE2D5, 0x7C43, 0xE2D6, 0x7C54, 0xE2D7, 0x7C4F, 0xE2D8, 0x7C40, 0xE2D9, 0x7C50, 0xE2DA, 0x7C58, 0xE2DB, 0x7C5F, 0xE2DC, 0x7C64, 0xE2DD, 0x7C56, 0xE2DE, 0x7C65, 0xE2DF, 0x7C6C, 0xE2E0, 0x7C75, 0xE2E1, 0x7C83, 0xE2E2, 0x7C90, 0xE2E3, 0x7CA4, 0xE2E4, 0x7CAD, 0xE2E5, 0x7CA2, 0xE2E6, 0x7CAB, 0xE2E7, 0x7CA1, 0xE2E8, 0x7CA8, 0xE2E9, 0x7CB3, 0xE2EA, 0x7CB2, 0xE2EB, 0x7CB1, 0xE2EC, 0x7CAE, 0xE2ED, 0x7CB9, 0xE2EE, 0x7CBD, 0xE2EF, 0x7CC0, 0xE2F0, 0x7CC5, 0xE2F1, 0x7CC2, 0xE2F2, 0x7CD8, 0xE2F3, 0x7CD2, 0xE2F4, 0x7CDC, 0xE2F5, 0x7CE2, 0xE2F6, 0x9B3B, 0xE2F7, 0x7CEF, 0xE2F8, 0x7CF2, 0xE2F9, 0x7CF4, 0xE2FA, 0x7CF6, 0xE2FB, 0x7CFA, 0xE2FC, 0x7D06, 0xE340, 0x7D02, 0xE341, 0x7D1C, 0xE342, 0x7D15, 0xE343, 0x7D0A, 0xE344, 0x7D45, 0xE345, 0x7D4B, 0xE346, 0x7D2E, 0xE347, 0x7D32, 0xE348, 0x7D3F, 0xE349, 0x7D35, 0xE34A, 0x7D46, 0xE34B, 0x7D73, 0xE34C, 0x7D56, 0xE34D, 0x7D4E, 0xE34E, 0x7D72, 0xE34F, 0x7D68, 0xE350, 0x7D6E, 0xE351, 0x7D4F, 0xE352, 0x7D63, 0xE353, 0x7D93, 0xE354, 0x7D89, 0xE355, 0x7D5B, 0xE356, 0x7D8F, 0xE357, 0x7D7D, 0xE358, 0x7D9B, 0xE359, 0x7DBA, 0xE35A, 0x7DAE, 0xE35B, 0x7DA3, 0xE35C, 0x7DB5, 0xE35D, 0x7DC7, 0xE35E, 0x7DBD, 0xE35F, 0x7DAB, 0xE360, 0x7E3D, 0xE361, 0x7DA2, 0xE362, 0x7DAF, 0xE363, 0x7DDC, 0xE364, 0x7DB8, 0xE365, 0x7D9F, 0xE366, 0x7DB0, 0xE367, 0x7DD8, 0xE368, 0x7DDD, 0xE369, 0x7DE4, 0xE36A, 0x7DDE, 0xE36B, 0x7DFB, 0xE36C, 0x7DF2, 0xE36D, 0x7DE1, 0xE36E, 0x7E05, 0xE36F, 0x7E0A, 0xE370, 0x7E23, 0xE371, 0x7E21, 0xE372, 0x7E12, 0xE373, 0x7E31, 0xE374, 0x7E1F, 0xE375, 0x7E09, 0xE376, 0x7E0B, 0xE377, 0x7E22, 0xE378, 0x7E46, 0xE379, 0x7E66, 0xE37A, 0x7E3B, 0xE37B, 0x7E35, 0xE37C, 0x7E39, 0xE37D, 0x7E43, 0xE37E, 0x7E37, 0xE380, 0x7E32, 0xE381, 0x7E3A, 0xE382, 0x7E67, 0xE383, 0x7E5D, 0xE384, 0x7E56, 0xE385, 0x7E5E, 0xE386, 0x7E59, 0xE387, 0x7E5A, 0xE388, 0x7E79, 0xE389, 0x7E6A, 0xE38A, 0x7E69, 0xE38B, 0x7E7C, 0xE38C, 0x7E7B, 0xE38D, 0x7E83, 0xE38E, 0x7DD5, 0xE38F, 0x7E7D, 0xE390, 0x8FAE, 0xE391, 0x7E7F, 0xE392, 0x7E88, 0xE393, 0x7E89, 0xE394, 0x7E8C, 0xE395, 0x7E92, 0xE396, 0x7E90, 0xE397, 0x7E93, 0xE398, 0x7E94, 0xE399, 0x7E96, 0xE39A, 0x7E8E, 0xE39B, 0x7E9B, 0xE39C, 0x7E9C, 0xE39D, 0x7F38, 0xE39E, 0x7F3A, 0xE39F, 0x7F45, 0xE3A0, 0x7F4C, 0xE3A1, 0x7F4D, 0xE3A2, 0x7F4E, 0xE3A3, 0x7F50, 0xE3A4, 0x7F51, 0xE3A5, 0x7F55, 0xE3A6, 0x7F54, 0xE3A7, 0x7F58, 0xE3A8, 0x7F5F, 0xE3A9, 0x7F60, 0xE3AA, 0x7F68, 0xE3AB, 0x7F69, 0xE3AC, 0x7F67, 0xE3AD, 0x7F78, 0xE3AE, 0x7F82, 0xE3AF, 0x7F86, 0xE3B0, 0x7F83, 0xE3B1, 0x7F88, 0xE3B2, 0x7F87, 0xE3B3, 0x7F8C, 0xE3B4, 0x7F94, 0xE3B5, 0x7F9E, 0xE3B6, 0x7F9D, 0xE3B7, 0x7F9A, 0xE3B8, 0x7FA3, 0xE3B9, 0x7FAF, 0xE3BA, 0x7FB2, 0xE3BB, 0x7FB9, 0xE3BC, 0x7FAE, 0xE3BD, 0x7FB6, 0xE3BE, 0x7FB8, 0xE3BF, 0x8B71, 0xE3C0, 0x7FC5, 0xE3C1, 0x7FC6, 0xE3C2, 0x7FCA, 0xE3C3, 0x7FD5, 0xE3C4, 0x7FD4, 0xE3C5, 0x7FE1, 0xE3C6, 0x7FE6, 0xE3C7, 0x7FE9, 0xE3C8, 0x7FF3, 0xE3C9, 0x7FF9, 0xE3CA, 0x98DC, 0xE3CB, 0x8006, 0xE3CC, 0x8004, 0xE3CD, 0x800B, 0xE3CE, 0x8012, 0xE3CF, 0x8018, 0xE3D0, 0x8019, 0xE3D1, 0x801C, 0xE3D2, 0x8021, 0xE3D3, 0x8028, 0xE3D4, 0x803F, 0xE3D5, 0x803B, 0xE3D6, 0x804A, 0xE3D7, 0x8046, 0xE3D8, 0x8052, 0xE3D9, 0x8058, 0xE3DA, 0x805A, 0xE3DB, 0x805F, 0xE3DC, 0x8062, 0xE3DD, 0x8068, 0xE3DE, 0x8073, 0xE3DF, 0x8072, 0xE3E0, 0x8070, 0xE3E1, 0x8076, 0xE3E2, 0x8079, 0xE3E3, 0x807D, 0xE3E4, 0x807F, 0xE3E5, 0x8084, 0xE3E6, 0x8086, 0xE3E7, 0x8085, 0xE3E8, 0x809B, 0xE3E9, 0x8093, 0xE3EA, 0x809A, 0xE3EB, 0x80AD, 0xE3EC, 0x5190, 0xE3ED, 0x80AC, 0xE3EE, 0x80DB, 0xE3EF, 0x80E5, 0xE3F0, 0x80D9, 0xE3F1, 0x80DD, 0xE3F2, 0x80C4, 0xE3F3, 0x80DA, 0xE3F4, 0x80D6, 0xE3F5, 0x8109, 0xE3F6, 0x80EF, 0xE3F7, 0x80F1, 0xE3F8, 0x811B, 0xE3F9, 0x8129, 0xE3FA, 0x8123, 0xE3FB, 0x812F, 0xE3FC, 0x814B, 0xE440, 0x968B, 0xE441, 0x8146, 0xE442, 0x813E, 0xE443, 0x8153, 0xE444, 0x8151, 0xE445, 0x80FC, 0xE446, 0x8171, 0xE447, 0x816E, 0xE448, 0x8165, 0xE449, 0x8166, 0xE44A, 0x8174, 0xE44B, 0x8183, 0xE44C, 0x8188, 0xE44D, 0x818A, 0xE44E, 0x8180, 0xE44F, 0x8182, 0xE450, 0x81A0, 0xE451, 0x8195, 0xE452, 0x81A4, 0xE453, 0x81A3, 0xE454, 0x815F, 0xE455, 0x8193, 0xE456, 0x81A9, 0xE457, 0x81B0, 0xE458, 0x81B5, 0xE459, 0x81BE, 0xE45A, 0x81B8, 0xE45B, 0x81BD, 0xE45C, 0x81C0, 0xE45D, 0x81C2, 0xE45E, 0x81BA, 0xE45F, 0x81C9, 0xE460, 0x81CD, 0xE461, 0x81D1, 0xE462, 0x81D9, 0xE463, 0x81D8, 0xE464, 0x81C8, 0xE465, 0x81DA, 0xE466, 0x81DF, 0xE467, 0x81E0, 0xE468, 0x81E7, 0xE469, 0x81FA, 0xE46A, 0x81FB, 0xE46B, 0x81FE, 0xE46C, 0x8201, 0xE46D, 0x8202, 0xE46E, 0x8205, 0xE46F, 0x8207, 0xE470, 0x820A, 0xE471, 0x820D, 0xE472, 0x8210, 0xE473, 0x8216, 0xE474, 0x8229, 0xE475, 0x822B, 0xE476, 0x8238, 0xE477, 0x8233, 0xE478, 0x8240, 0xE479, 0x8259, 0xE47A, 0x8258, 0xE47B, 0x825D, 0xE47C, 0x825A, 0xE47D, 0x825F, 0xE47E, 0x8264, 0xE480, 0x8262, 0xE481, 0x8268, 0xE482, 0x826A, 0xE483, 0x826B, 0xE484, 0x822E, 0xE485, 0x8271, 0xE486, 0x8277, 0xE487, 0x8278, 0xE488, 0x827E, 0xE489, 0x828D, 0xE48A, 0x8292, 0xE48B, 0x82AB, 0xE48C, 0x829F, 0xE48D, 0x82BB, 0xE48E, 0x82AC, 0xE48F, 0x82E1, 0xE490, 0x82E3, 0xE491, 0x82DF, 0xE492, 0x82D2, 0xE493, 0x82F4, 0xE494, 0x82F3, 0xE495, 0x82FA, 0xE496, 0x8393, 0xE497, 0x8303, 0xE498, 0x82FB, 0xE499, 0x82F9, 0xE49A, 0x82DE, 0xE49B, 0x8306, 0xE49C, 0x82DC, 0xE49D, 0x8309, 0xE49E, 0x82D9, 0xE49F, 0x8335, 0xE4A0, 0x8334, 0xE4A1, 0x8316, 0xE4A2, 0x8332, 0xE4A3, 0x8331, 0xE4A4, 0x8340, 0xE4A5, 0x8339, 0xE4A6, 0x8350, 0xE4A7, 0x8345, 0xE4A8, 0x832F, 0xE4A9, 0x832B, 0xE4AA, 0x8317, 0xE4AB, 0x8318, 0xE4AC, 0x8385, 0xE4AD, 0x839A, 0xE4AE, 0x83AA, 0xE4AF, 0x839F, 0xE4B0, 0x83A2, 0xE4B1, 0x8396, 0xE4B2, 0x8323, 0xE4B3, 0x838E, 0xE4B4, 0x8387, 0xE4B5, 0x838A, 0xE4B6, 0x837C, 0xE4B7, 0x83B5, 0xE4B8, 0x8373, 0xE4B9, 0x8375, 0xE4BA, 0x83A0, 0xE4BB, 0x8389, 0xE4BC, 0x83A8, 0xE4BD, 0x83F4, 0xE4BE, 0x8413, 0xE4BF, 0x83EB, 0xE4C0, 0x83CE, 0xE4C1, 0x83FD, 0xE4C2, 0x8403, 0xE4C3, 0x83D8, 0xE4C4, 0x840B, 0xE4C5, 0x83C1, 0xE4C6, 0x83F7, 0xE4C7, 0x8407, 0xE4C8, 0x83E0, 0xE4C9, 0x83F2, 0xE4CA, 0x840D, 0xE4CB, 0x8422, 0xE4CC, 0x8420, 0xE4CD, 0x83BD, 0xE4CE, 0x8438, 0xE4CF, 0x8506, 0xE4D0, 0x83FB, 0xE4D1, 0x846D, 0xE4D2, 0x842A, 0xE4D3, 0x843C, 0xE4D4, 0x855A, 0xE4D5, 0x8484, 0xE4D6, 0x8477, 0xE4D7, 0x846B, 0xE4D8, 0x84AD, 0xE4D9, 0x846E, 0xE4DA, 0x8482, 0xE4DB, 0x8469, 0xE4DC, 0x8446, 0xE4DD, 0x842C, 0xE4DE, 0x846F, 0xE4DF, 0x8479, 0xE4E0, 0x8435, 0xE4E1, 0x84CA, 0xE4E2, 0x8462, 0xE4E3, 0x84B9, 0xE4E4, 0x84BF, 0xE4E5, 0x849F, 0xE4E6, 0x84D9, 0xE4E7, 0x84CD, 0xE4E8, 0x84BB, 0xE4E9, 0x84DA, 0xE4EA, 0x84D0, 0xE4EB, 0x84C1, 0xE4EC, 0x84C6, 0xE4ED, 0x84D6, 0xE4EE, 0x84A1, 0xE4EF, 0x8521, 0xE4F0, 0x84FF, 0xE4F1, 0x84F4, 0xE4F2, 0x8517, 0xE4F3, 0x8518, 0xE4F4, 0x852C, 0xE4F5, 0x851F, 0xE4F6, 0x8515, 0xE4F7, 0x8514, 0xE4F8, 0x84FC, 0xE4F9, 0x8540, 0xE4FA, 0x8563, 0xE4FB, 0x8558, 0xE4FC, 0x8548, 0xE540, 0x8541, 0xE541, 0x8602, 0xE542, 0x854B, 0xE543, 0x8555, 0xE544, 0x8580, 0xE545, 0x85A4, 0xE546, 0x8588, 0xE547, 0x8591, 0xE548, 0x858A, 0xE549, 0x85A8, 0xE54A, 0x856D, 0xE54B, 0x8594, 0xE54C, 0x859B, 0xE54D, 0x85EA, 0xE54E, 0x8587, 0xE54F, 0x859C, 0xE550, 0x8577, 0xE551, 0x857E, 0xE552, 0x8590, 0xE553, 0x85C9, 0xE554, 0x85BA, 0xE555, 0x85CF, 0xE556, 0x85B9, 0xE557, 0x85D0, 0xE558, 0x85D5, 0xE559, 0x85DD, 0xE55A, 0x85E5, 0xE55B, 0x85DC, 0xE55C, 0x85F9, 0xE55D, 0x860A, 0xE55E, 0x8613, 0xE55F, 0x860B, 0xE560, 0x85FE, 0xE561, 0x85FA, 0xE562, 0x8606, 0xE563, 0x8622, 0xE564, 0x861A, 0xE565, 0x8630, 0xE566, 0x863F, 0xE567, 0x864D, 0xE568, 0x4E55, 0xE569, 0x8654, 0xE56A, 0x865F, 0xE56B, 0x8667, 0xE56C, 0x8671, 0xE56D, 0x8693, 0xE56E, 0x86A3, 0xE56F, 0x86A9, 0xE570, 0x86AA, 0xE571, 0x868B, 0xE572, 0x868C, 0xE573, 0x86B6, 0xE574, 0x86AF, 0xE575, 0x86C4, 0xE576, 0x86C6, 0xE577, 0x86B0, 0xE578, 0x86C9, 0xE579, 0x8823, 0xE57A, 0x86AB, 0xE57B, 0x86D4, 0xE57C, 0x86DE, 0xE57D, 0x86E9, 0xE57E, 0x86EC, 0xE580, 0x86DF, 0xE581, 0x86DB, 0xE582, 0x86EF, 0xE583, 0x8712, 0xE584, 0x8706, 0xE585, 0x8708, 0xE586, 0x8700, 0xE587, 0x8703, 0xE588, 0x86FB, 0xE589, 0x8711, 0xE58A, 0x8709, 0xE58B, 0x870D, 0xE58C, 0x86F9, 0xE58D, 0x870A, 0xE58E, 0x8734, 0xE58F, 0x873F, 0xE590, 0x8737, 0xE591, 0x873B, 0xE592, 0x8725, 0xE593, 0x8729, 0xE594, 0x871A, 0xE595, 0x8760, 0xE596, 0x875F, 0xE597, 0x8778, 0xE598, 0x874C, 0xE599, 0x874E, 0xE59A, 0x8774, 0xE59B, 0x8757, 0xE59C, 0x8768, 0xE59D, 0x876E, 0xE59E, 0x8759, 0xE59F, 0x8753, 0xE5A0, 0x8763, 0xE5A1, 0x876A, 0xE5A2, 0x8805, 0xE5A3, 0x87A2, 0xE5A4, 0x879F, 0xE5A5, 0x8782, 0xE5A6, 0x87AF, 0xE5A7, 0x87CB, 0xE5A8, 0x87BD, 0xE5A9, 0x87C0, 0xE5AA, 0x87D0, 0xE5AB, 0x96D6, 0xE5AC, 0x87AB, 0xE5AD, 0x87C4, 0xE5AE, 0x87B3, 0xE5AF, 0x87C7, 0xE5B0, 0x87C6, 0xE5B1, 0x87BB, 0xE5B2, 0x87EF, 0xE5B3, 0x87F2, 0xE5B4, 0x87E0, 0xE5B5, 0x880F, 0xE5B6, 0x880D, 0xE5B7, 0x87FE, 0xE5B8, 0x87F6, 0xE5B9, 0x87F7, 0xE5BA, 0x880E, 0xE5BB, 0x87D2, 0xE5BC, 0x8811, 0xE5BD, 0x8816, 0xE5BE, 0x8815, 0xE5BF, 0x8822, 0xE5C0, 0x8821, 0xE5C1, 0x8831, 0xE5C2, 0x8836, 0xE5C3, 0x8839, 0xE5C4, 0x8827, 0xE5C5, 0x883B, 0xE5C6, 0x8844, 0xE5C7, 0x8842, 0xE5C8, 0x8852, 0xE5C9, 0x8859, 0xE5CA, 0x885E, 0xE5CB, 0x8862, 0xE5CC, 0x886B, 0xE5CD, 0x8881, 0xE5CE, 0x887E, 0xE5CF, 0x889E, 0xE5D0, 0x8875, 0xE5D1, 0x887D, 0xE5D2, 0x88B5, 0xE5D3, 0x8872, 0xE5D4, 0x8882, 0xE5D5, 0x8897, 0xE5D6, 0x8892, 0xE5D7, 0x88AE, 0xE5D8, 0x8899, 0xE5D9, 0x88A2, 0xE5DA, 0x888D, 0xE5DB, 0x88A4, 0xE5DC, 0x88B0, 0xE5DD, 0x88BF, 0xE5DE, 0x88B1, 0xE5DF, 0x88C3, 0xE5E0, 0x88C4, 0xE5E1, 0x88D4, 0xE5E2, 0x88D8, 0xE5E3, 0x88D9, 0xE5E4, 0x88DD, 0xE5E5, 0x88F9, 0xE5E6, 0x8902, 0xE5E7, 0x88FC, 0xE5E8, 0x88F4, 0xE5E9, 0x88E8, 0xE5EA, 0x88F2, 0xE5EB, 0x8904, 0xE5EC, 0x890C, 0xE5ED, 0x890A, 0xE5EE, 0x8913, 0xE5EF, 0x8943, 0xE5F0, 0x891E, 0xE5F1, 0x8925, 0xE5F2, 0x892A, 0xE5F3, 0x892B, 0xE5F4, 0x8941, 0xE5F5, 0x8944, 0xE5F6, 0x893B, 0xE5F7, 0x8936, 0xE5F8, 0x8938, 0xE5F9, 0x894C, 0xE5FA, 0x891D, 0xE5FB, 0x8960, 0xE5FC, 0x895E, 0xE640, 0x8966, 0xE641, 0x8964, 0xE642, 0x896D, 0xE643, 0x896A, 0xE644, 0x896F, 0xE645, 0x8974, 0xE646, 0x8977, 0xE647, 0x897E, 0xE648, 0x8983, 0xE649, 0x8988, 0xE64A, 0x898A, 0xE64B, 0x8993, 0xE64C, 0x8998, 0xE64D, 0x89A1, 0xE64E, 0x89A9, 0xE64F, 0x89A6, 0xE650, 0x89AC, 0xE651, 0x89AF, 0xE652, 0x89B2, 0xE653, 0x89BA, 0xE654, 0x89BD, 0xE655, 0x89BF, 0xE656, 0x89C0, 0xE657, 0x89DA, 0xE658, 0x89DC, 0xE659, 0x89DD, 0xE65A, 0x89E7, 0xE65B, 0x89F4, 0xE65C, 0x89F8, 0xE65D, 0x8A03, 0xE65E, 0x8A16, 0xE65F, 0x8A10, 0xE660, 0x8A0C, 0xE661, 0x8A1B, 0xE662, 0x8A1D, 0xE663, 0x8A25, 0xE664, 0x8A36, 0xE665, 0x8A41, 0xE666, 0x8A5B, 0xE667, 0x8A52, 0xE668, 0x8A46, 0xE669, 0x8A48, 0xE66A, 0x8A7C, 0xE66B, 0x8A6D, 0xE66C, 0x8A6C, 0xE66D, 0x8A62, 0xE66E, 0x8A85, 0xE66F, 0x8A82, 0xE670, 0x8A84, 0xE671, 0x8AA8, 0xE672, 0x8AA1, 0xE673, 0x8A91, 0xE674, 0x8AA5, 0xE675, 0x8AA6, 0xE676, 0x8A9A, 0xE677, 0x8AA3, 0xE678, 0x8AC4, 0xE679, 0x8ACD, 0xE67A, 0x8AC2, 0xE67B, 0x8ADA, 0xE67C, 0x8AEB, 0xE67D, 0x8AF3, 0xE67E, 0x8AE7, 0xE680, 0x8AE4, 0xE681, 0x8AF1, 0xE682, 0x8B14, 0xE683, 0x8AE0, 0xE684, 0x8AE2, 0xE685, 0x8AF7, 0xE686, 0x8ADE, 0xE687, 0x8ADB, 0xE688, 0x8B0C, 0xE689, 0x8B07, 0xE68A, 0x8B1A, 0xE68B, 0x8AE1, 0xE68C, 0x8B16, 0xE68D, 0x8B10, 0xE68E, 0x8B17, 0xE68F, 0x8B20, 0xE690, 0x8B33, 0xE691, 0x97AB, 0xE692, 0x8B26, 0xE693, 0x8B2B, 0xE694, 0x8B3E, 0xE695, 0x8B28, 0xE696, 0x8B41, 0xE697, 0x8B4C, 0xE698, 0x8B4F, 0xE699, 0x8B4E, 0xE69A, 0x8B49, 0xE69B, 0x8B56, 0xE69C, 0x8B5B, 0xE69D, 0x8B5A, 0xE69E, 0x8B6B, 0xE69F, 0x8B5F, 0xE6A0, 0x8B6C, 0xE6A1, 0x8B6F, 0xE6A2, 0x8B74, 0xE6A3, 0x8B7D, 0xE6A4, 0x8B80, 0xE6A5, 0x8B8C, 0xE6A6, 0x8B8E, 0xE6A7, 0x8B92, 0xE6A8, 0x8B93, 0xE6A9, 0x8B96, 0xE6AA, 0x8B99, 0xE6AB, 0x8B9A, 0xE6AC, 0x8C3A, 0xE6AD, 0x8C41, 0xE6AE, 0x8C3F, 0xE6AF, 0x8C48, 0xE6B0, 0x8C4C, 0xE6B1, 0x8C4E, 0xE6B2, 0x8C50, 0xE6B3, 0x8C55, 0xE6B4, 0x8C62, 0xE6B5, 0x8C6C, 0xE6B6, 0x8C78, 0xE6B7, 0x8C7A, 0xE6B8, 0x8C82, 0xE6B9, 0x8C89, 0xE6BA, 0x8C85, 0xE6BB, 0x8C8A, 0xE6BC, 0x8C8D, 0xE6BD, 0x8C8E, 0xE6BE, 0x8C94, 0xE6BF, 0x8C7C, 0xE6C0, 0x8C98, 0xE6C1, 0x621D, 0xE6C2, 0x8CAD, 0xE6C3, 0x8CAA, 0xE6C4, 0x8CBD, 0xE6C5, 0x8CB2, 0xE6C6, 0x8CB3, 0xE6C7, 0x8CAE, 0xE6C8, 0x8CB6, 0xE6C9, 0x8CC8, 0xE6CA, 0x8CC1, 0xE6CB, 0x8CE4, 0xE6CC, 0x8CE3, 0xE6CD, 0x8CDA, 0xE6CE, 0x8CFD, 0xE6CF, 0x8CFA, 0xE6D0, 0x8CFB, 0xE6D1, 0x8D04, 0xE6D2, 0x8D05, 0xE6D3, 0x8D0A, 0xE6D4, 0x8D07, 0xE6D5, 0x8D0F, 0xE6D6, 0x8D0D, 0xE6D7, 0x8D10, 0xE6D8, 0x9F4E, 0xE6D9, 0x8D13, 0xE6DA, 0x8CCD, 0xE6DB, 0x8D14, 0xE6DC, 0x8D16, 0xE6DD, 0x8D67, 0xE6DE, 0x8D6D, 0xE6DF, 0x8D71, 0xE6E0, 0x8D73, 0xE6E1, 0x8D81, 0xE6E2, 0x8D99, 0xE6E3, 0x8DC2, 0xE6E4, 0x8DBE, 0xE6E5, 0x8DBA, 0xE6E6, 0x8DCF, 0xE6E7, 0x8DDA, 0xE6E8, 0x8DD6, 0xE6E9, 0x8DCC, 0xE6EA, 0x8DDB, 0xE6EB, 0x8DCB, 0xE6EC, 0x8DEA, 0xE6ED, 0x8DEB, 0xE6EE, 0x8DDF, 0xE6EF, 0x8DE3, 0xE6F0, 0x8DFC, 0xE6F1, 0x8E08, 0xE6F2, 0x8E09, 0xE6F3, 0x8DFF, 0xE6F4, 0x8E1D, 0xE6F5, 0x8E1E, 0xE6F6, 0x8E10, 0xE6F7, 0x8E1F, 0xE6F8, 0x8E42, 0xE6F9, 0x8E35, 0xE6FA, 0x8E30, 0xE6FB, 0x8E34, 0xE6FC, 0x8E4A, 0xE740, 0x8E47, 0xE741, 0x8E49, 0xE742, 0x8E4C, 0xE743, 0x8E50, 0xE744, 0x8E48, 0xE745, 0x8E59, 0xE746, 0x8E64, 0xE747, 0x8E60, 0xE748, 0x8E2A, 0xE749, 0x8E63, 0xE74A, 0x8E55, 0xE74B, 0x8E76, 0xE74C, 0x8E72, 0xE74D, 0x8E7C, 0xE74E, 0x8E81, 0xE74F, 0x8E87, 0xE750, 0x8E85, 0xE751, 0x8E84, 0xE752, 0x8E8B, 0xE753, 0x8E8A, 0xE754, 0x8E93, 0xE755, 0x8E91, 0xE756, 0x8E94, 0xE757, 0x8E99, 0xE758, 0x8EAA, 0xE759, 0x8EA1, 0xE75A, 0x8EAC, 0xE75B, 0x8EB0, 0xE75C, 0x8EC6, 0xE75D, 0x8EB1, 0xE75E, 0x8EBE, 0xE75F, 0x8EC5, 0xE760, 0x8EC8, 0xE761, 0x8ECB, 0xE762, 0x8EDB, 0xE763, 0x8EE3, 0xE764, 0x8EFC, 0xE765, 0x8EFB, 0xE766, 0x8EEB, 0xE767, 0x8EFE, 0xE768, 0x8F0A, 0xE769, 0x8F05, 0xE76A, 0x8F15, 0xE76B, 0x8F12, 0xE76C, 0x8F19, 0xE76D, 0x8F13, 0xE76E, 0x8F1C, 0xE76F, 0x8F1F, 0xE770, 0x8F1B, 0xE771, 0x8F0C, 0xE772, 0x8F26, 0xE773, 0x8F33, 0xE774, 0x8F3B, 0xE775, 0x8F39, 0xE776, 0x8F45, 0xE777, 0x8F42, 0xE778, 0x8F3E, 0xE779, 0x8F4C, 0xE77A, 0x8F49, 0xE77B, 0x8F46, 0xE77C, 0x8F4E, 0xE77D, 0x8F57, 0xE77E, 0x8F5C, 0xE780, 0x8F62, 0xE781, 0x8F63, 0xE782, 0x8F64, 0xE783, 0x8F9C, 0xE784, 0x8F9F, 0xE785, 0x8FA3, 0xE786, 0x8FAD, 0xE787, 0x8FAF, 0xE788, 0x8FB7, 0xE789, 0x8FDA, 0xE78A, 0x8FE5, 0xE78B, 0x8FE2, 0xE78C, 0x8FEA, 0xE78D, 0x8FEF, 0xE78E, 0x9087, 0xE78F, 0x8FF4, 0xE790, 0x9005, 0xE791, 0x8FF9, 0xE792, 0x8FFA, 0xE793, 0x9011, 0xE794, 0x9015, 0xE795, 0x9021, 0xE796, 0x900D, 0xE797, 0x901E, 0xE798, 0x9016, 0xE799, 0x900B, 0xE79A, 0x9027, 0xE79B, 0x9036, 0xE79C, 0x9035, 0xE79D, 0x9039, 0xE79E, 0x8FF8, 0xE79F, 0x904F, 0xE7A0, 0x9050, 0xE7A1, 0x9051, 0xE7A2, 0x9052, 0xE7A3, 0x900E, 0xE7A4, 0x9049, 0xE7A5, 0x903E, 0xE7A6, 0x9056, 0xE7A7, 0x9058, 0xE7A8, 0x905E, 0xE7A9, 0x9068, 0xE7AA, 0x906F, 0xE7AB, 0x9076, 0xE7AC, 0x96A8, 0xE7AD, 0x9072, 0xE7AE, 0x9082, 0xE7AF, 0x907D, 0xE7B0, 0x9081, 0xE7B1, 0x9080, 0xE7B2, 0x908A, 0xE7B3, 0x9089, 0xE7B4, 0x908F, 0xE7B5, 0x90A8, 0xE7B6, 0x90AF, 0xE7B7, 0x90B1, 0xE7B8, 0x90B5, 0xE7B9, 0x90E2, 0xE7BA, 0x90E4, 0xE7BB, 0x6248, 0xE7BC, 0x90DB, 0xE7BD, 0x9102, 0xE7BE, 0x9112, 0xE7BF, 0x9119, 0xE7C0, 0x9132, 0xE7C1, 0x9130, 0xE7C2, 0x914A, 0xE7C3, 0x9156, 0xE7C4, 0x9158, 0xE7C5, 0x9163, 0xE7C6, 0x9165, 0xE7C7, 0x9169, 0xE7C8, 0x9173, 0xE7C9, 0x9172, 0xE7CA, 0x918B, 0xE7CB, 0x9189, 0xE7CC, 0x9182, 0xE7CD, 0x91A2, 0xE7CE, 0x91AB, 0xE7CF, 0x91AF, 0xE7D0, 0x91AA, 0xE7D1, 0x91B5, 0xE7D2, 0x91B4, 0xE7D3, 0x91BA, 0xE7D4, 0x91C0, 0xE7D5, 0x91C1, 0xE7D6, 0x91C9, 0xE7D7, 0x91CB, 0xE7D8, 0x91D0, 0xE7D9, 0x91D6, 0xE7DA, 0x91DF, 0xE7DB, 0x91E1, 0xE7DC, 0x91DB, 0xE7DD, 0x91FC, 0xE7DE, 0x91F5, 0xE7DF, 0x91F6, 0xE7E0, 0x921E, 0xE7E1, 0x91FF, 0xE7E2, 0x9214, 0xE7E3, 0x922C, 0xE7E4, 0x9215, 0xE7E5, 0x9211, 0xE7E6, 0x925E, 0xE7E7, 0x9257, 0xE7E8, 0x9245, 0xE7E9, 0x9249, 0xE7EA, 0x9264, 0xE7EB, 0x9248, 0xE7EC, 0x9295, 0xE7ED, 0x923F, 0xE7EE, 0x924B, 0xE7EF, 0x9250, 0xE7F0, 0x929C, 0xE7F1, 0x9296, 0xE7F2, 0x9293, 0xE7F3, 0x929B, 0xE7F4, 0x925A, 0xE7F5, 0x92CF, 0xE7F6, 0x92B9, 0xE7F7, 0x92B7, 0xE7F8, 0x92E9, 0xE7F9, 0x930F, 0xE7FA, 0x92FA, 0xE7FB, 0x9344, 0xE7FC, 0x932E, 0xE840, 0x9319, 0xE841, 0x9322, 0xE842, 0x931A, 0xE843, 0x9323, 0xE844, 0x933A, 0xE845, 0x9335, 0xE846, 0x933B, 0xE847, 0x935C, 0xE848, 0x9360, 0xE849, 0x937C, 0xE84A, 0x936E, 0xE84B, 0x9356, 0xE84C, 0x93B0, 0xE84D, 0x93AC, 0xE84E, 0x93AD, 0xE84F, 0x9394, 0xE850, 0x93B9, 0xE851, 0x93D6, 0xE852, 0x93D7, 0xE853, 0x93E8, 0xE854, 0x93E5, 0xE855, 0x93D8, 0xE856, 0x93C3, 0xE857, 0x93DD, 0xE858, 0x93D0, 0xE859, 0x93C8, 0xE85A, 0x93E4, 0xE85B, 0x941A, 0xE85C, 0x9414, 0xE85D, 0x9413, 0xE85E, 0x9403, 0xE85F, 0x9407, 0xE860, 0x9410, 0xE861, 0x9436, 0xE862, 0x942B, 0xE863, 0x9435, 0xE864, 0x9421, 0xE865, 0x943A, 0xE866, 0x9441, 0xE867, 0x9452, 0xE868, 0x9444, 0xE869, 0x945B, 0xE86A, 0x9460, 0xE86B, 0x9462, 0xE86C, 0x945E, 0xE86D, 0x946A, 0xE86E, 0x9229, 0xE86F, 0x9470, 0xE870, 0x9475, 0xE871, 0x9477, 0xE872, 0x947D, 0xE873, 0x945A, 0xE874, 0x947C, 0xE875, 0x947E, 0xE876, 0x9481, 0xE877, 0x947F, 0xE878, 0x9582, 0xE879, 0x9587, 0xE87A, 0x958A, 0xE87B, 0x9594, 0xE87C, 0x9596, 0xE87D, 0x9598, 0xE87E, 0x9599, 0xE880, 0x95A0, 0xE881, 0x95A8, 0xE882, 0x95A7, 0xE883, 0x95AD, 0xE884, 0x95BC, 0xE885, 0x95BB, 0xE886, 0x95B9, 0xE887, 0x95BE, 0xE888, 0x95CA, 0xE889, 0x6FF6, 0xE88A, 0x95C3, 0xE88B, 0x95CD, 0xE88C, 0x95CC, 0xE88D, 0x95D5, 0xE88E, 0x95D4, 0xE88F, 0x95D6, 0xE890, 0x95DC, 0xE891, 0x95E1, 0xE892, 0x95E5, 0xE893, 0x95E2, 0xE894, 0x9621, 0xE895, 0x9628, 0xE896, 0x962E, 0xE897, 0x962F, 0xE898, 0x9642, 0xE899, 0x964C, 0xE89A, 0x964F, 0xE89B, 0x964B, 0xE89C, 0x9677, 0xE89D, 0x965C, 0xE89E, 0x965E, 0xE89F, 0x965D, 0xE8A0, 0x965F, 0xE8A1, 0x9666, 0xE8A2, 0x9672, 0xE8A3, 0x966C, 0xE8A4, 0x968D, 0xE8A5, 0x9698, 0xE8A6, 0x9695, 0xE8A7, 0x9697, 0xE8A8, 0x96AA, 0xE8A9, 0x96A7, 0xE8AA, 0x96B1, 0xE8AB, 0x96B2, 0xE8AC, 0x96B0, 0xE8AD, 0x96B4, 0xE8AE, 0x96B6, 0xE8AF, 0x96B8, 0xE8B0, 0x96B9, 0xE8B1, 0x96CE, 0xE8B2, 0x96CB, 0xE8B3, 0x96C9, 0xE8B4, 0x96CD, 0xE8B5, 0x894D, 0xE8B6, 0x96DC, 0xE8B7, 0x970D, 0xE8B8, 0x96D5, 0xE8B9, 0x96F9, 0xE8BA, 0x9704, 0xE8BB, 0x9706, 0xE8BC, 0x9708, 0xE8BD, 0x9713, 0xE8BE, 0x970E, 0xE8BF, 0x9711, 0xE8C0, 0x970F, 0xE8C1, 0x9716, 0xE8C2, 0x9719, 0xE8C3, 0x9724, 0xE8C4, 0x972A, 0xE8C5, 0x9730, 0xE8C6, 0x9739, 0xE8C7, 0x973D, 0xE8C8, 0x973E, 0xE8C9, 0x9744, 0xE8CA, 0x9746, 0xE8CB, 0x9748, 0xE8CC, 0x9742, 0xE8CD, 0x9749, 0xE8CE, 0x975C, 0xE8CF, 0x9760, 0xE8D0, 0x9764, 0xE8D1, 0x9766, 0xE8D2, 0x9768, 0xE8D3, 0x52D2, 0xE8D4, 0x976B, 0xE8D5, 0x9771, 0xE8D6, 0x9779, 0xE8D7, 0x9785, 0xE8D8, 0x977C, 0xE8D9, 0x9781, 0xE8DA, 0x977A, 0xE8DB, 0x9786, 0xE8DC, 0x978B, 0xE8DD, 0x978F, 0xE8DE, 0x9790, 0xE8DF, 0x979C, 0xE8E0, 0x97A8, 0xE8E1, 0x97A6, 0xE8E2, 0x97A3, 0xE8E3, 0x97B3, 0xE8E4, 0x97B4, 0xE8E5, 0x97C3, 0xE8E6, 0x97C6, 0xE8E7, 0x97C8, 0xE8E8, 0x97CB, 0xE8E9, 0x97DC, 0xE8EA, 0x97ED, 0xE8EB, 0x9F4F, 0xE8EC, 0x97F2, 0xE8ED, 0x7ADF, 0xE8EE, 0x97F6, 0xE8EF, 0x97F5, 0xE8F0, 0x980F, 0xE8F1, 0x980C, 0xE8F2, 0x9838, 0xE8F3, 0x9824, 0xE8F4, 0x9821, 0xE8F5, 0x9837, 0xE8F6, 0x983D, 0xE8F7, 0x9846, 0xE8F8, 0x984F, 0xE8F9, 0x984B, 0xE8FA, 0x986B, 0xE8FB, 0x986F, 0xE8FC, 0x9870, 0xE940, 0x9871, 0xE941, 0x9874, 0xE942, 0x9873, 0xE943, 0x98AA, 0xE944, 0x98AF, 0xE945, 0x98B1, 0xE946, 0x98B6, 0xE947, 0x98C4, 0xE948, 0x98C3, 0xE949, 0x98C6, 0xE94A, 0x98E9, 0xE94B, 0x98EB, 0xE94C, 0x9903, 0xE94D, 0x9909, 0xE94E, 0x9912, 0xE94F, 0x9914, 0xE950, 0x9918, 0xE951, 0x9921, 0xE952, 0x991D, 0xE953, 0x991E, 0xE954, 0x9924, 0xE955, 0x9920, 0xE956, 0x992C, 0xE957, 0x992E, 0xE958, 0x993D, 0xE959, 0x993E, 0xE95A, 0x9942, 0xE95B, 0x9949, 0xE95C, 0x9945, 0xE95D, 0x9950, 0xE95E, 0x994B, 0xE95F, 0x9951, 0xE960, 0x9952, 0xE961, 0x994C, 0xE962, 0x9955, 0xE963, 0x9997, 0xE964, 0x9998, 0xE965, 0x99A5, 0xE966, 0x99AD, 0xE967, 0x99AE, 0xE968, 0x99BC, 0xE969, 0x99DF, 0xE96A, 0x99DB, 0xE96B, 0x99DD, 0xE96C, 0x99D8, 0xE96D, 0x99D1, 0xE96E, 0x99ED, 0xE96F, 0x99EE, 0xE970, 0x99F1, 0xE971, 0x99F2, 0xE972, 0x99FB, 0xE973, 0x99F8, 0xE974, 0x9A01, 0xE975, 0x9A0F, 0xE976, 0x9A05, 0xE977, 0x99E2, 0xE978, 0x9A19, 0xE979, 0x9A2B, 0xE97A, 0x9A37, 0xE97B, 0x9A45, 0xE97C, 0x9A42, 0xE97D, 0x9A40, 0xE97E, 0x9A43, 0xE980, 0x9A3E, 0xE981, 0x9A55, 0xE982, 0x9A4D, 0xE983, 0x9A5B, 0xE984, 0x9A57, 0xE985, 0x9A5F, 0xE986, 0x9A62, 0xE987, 0x9A65, 0xE988, 0x9A64, 0xE989, 0x9A69, 0xE98A, 0x9A6B, 0xE98B, 0x9A6A, 0xE98C, 0x9AAD, 0xE98D, 0x9AB0, 0xE98E, 0x9ABC, 0xE98F, 0x9AC0, 0xE990, 0x9ACF, 0xE991, 0x9AD1, 0xE992, 0x9AD3, 0xE993, 0x9AD4, 0xE994, 0x9ADE, 0xE995, 0x9ADF, 0xE996, 0x9AE2, 0xE997, 0x9AE3, 0xE998, 0x9AE6, 0xE999, 0x9AEF, 0xE99A, 0x9AEB, 0xE99B, 0x9AEE, 0xE99C, 0x9AF4, 0xE99D, 0x9AF1, 0xE99E, 0x9AF7, 0xE99F, 0x9AFB, 0xE9A0, 0x9B06, 0xE9A1, 0x9B18, 0xE9A2, 0x9B1A, 0xE9A3, 0x9B1F, 0xE9A4, 0x9B22, 0xE9A5, 0x9B23, 0xE9A6, 0x9B25, 0xE9A7, 0x9B27, 0xE9A8, 0x9B28, 0xE9A9, 0x9B29, 0xE9AA, 0x9B2A, 0xE9AB, 0x9B2E, 0xE9AC, 0x9B2F, 0xE9AD, 0x9B32, 0xE9AE, 0x9B44, 0xE9AF, 0x9B43, 0xE9B0, 0x9B4F, 0xE9B1, 0x9B4D, 0xE9B2, 0x9B4E, 0xE9B3, 0x9B51, 0xE9B4, 0x9B58, 0xE9B5, 0x9B74, 0xE9B6, 0x9B93, 0xE9B7, 0x9B83, 0xE9B8, 0x9B91, 0xE9B9, 0x9B96, 0xE9BA, 0x9B97, 0xE9BB, 0x9B9F, 0xE9BC, 0x9BA0, 0xE9BD, 0x9BA8, 0xE9BE, 0x9BB4, 0xE9BF, 0x9BC0, 0xE9C0, 0x9BCA, 0xE9C1, 0x9BB9, 0xE9C2, 0x9BC6, 0xE9C3, 0x9BCF, 0xE9C4, 0x9BD1, 0xE9C5, 0x9BD2, 0xE9C6, 0x9BE3, 0xE9C7, 0x9BE2, 0xE9C8, 0x9BE4, 0xE9C9, 0x9BD4, 0xE9CA, 0x9BE1, 0xE9CB, 0x9C3A, 0xE9CC, 0x9BF2, 0xE9CD, 0x9BF1, 0xE9CE, 0x9BF0, 0xE9CF, 0x9C15, 0xE9D0, 0x9C14, 0xE9D1, 0x9C09, 0xE9D2, 0x9C13, 0xE9D3, 0x9C0C, 0xE9D4, 0x9C06, 0xE9D5, 0x9C08, 0xE9D6, 0x9C12, 0xE9D7, 0x9C0A, 0xE9D8, 0x9C04, 0xE9D9, 0x9C2E, 0xE9DA, 0x9C1B, 0xE9DB, 0x9C25, 0xE9DC, 0x9C24, 0xE9DD, 0x9C21, 0xE9DE, 0x9C30, 0xE9DF, 0x9C47, 0xE9E0, 0x9C32, 0xE9E1, 0x9C46, 0xE9E2, 0x9C3E, 0xE9E3, 0x9C5A, 0xE9E4, 0x9C60, 0xE9E5, 0x9C67, 0xE9E6, 0x9C76, 0xE9E7, 0x9C78, 0xE9E8, 0x9CE7, 0xE9E9, 0x9CEC, 0xE9EA, 0x9CF0, 0xE9EB, 0x9D09, 0xE9EC, 0x9D08, 0xE9ED, 0x9CEB, 0xE9EE, 0x9D03, 0xE9EF, 0x9D06, 0xE9F0, 0x9D2A, 0xE9F1, 0x9D26, 0xE9F2, 0x9DAF, 0xE9F3, 0x9D23, 0xE9F4, 0x9D1F, 0xE9F5, 0x9D44, 0xE9F6, 0x9D15, 0xE9F7, 0x9D12, 0xE9F8, 0x9D41, 0xE9F9, 0x9D3F, 0xE9FA, 0x9D3E, 0xE9FB, 0x9D46, 0xE9FC, 0x9D48, 0xEA40, 0x9D5D, 0xEA41, 0x9D5E, 0xEA42, 0x9D64, 0xEA43, 0x9D51, 0xEA44, 0x9D50, 0xEA45, 0x9D59, 0xEA46, 0x9D72, 0xEA47, 0x9D89, 0xEA48, 0x9D87, 0xEA49, 0x9DAB, 0xEA4A, 0x9D6F, 0xEA4B, 0x9D7A, 0xEA4C, 0x9D9A, 0xEA4D, 0x9DA4, 0xEA4E, 0x9DA9, 0xEA4F, 0x9DB2, 0xEA50, 0x9DC4, 0xEA51, 0x9DC1, 0xEA52, 0x9DBB, 0xEA53, 0x9DB8, 0xEA54, 0x9DBA, 0xEA55, 0x9DC6, 0xEA56, 0x9DCF, 0xEA57, 0x9DC2, 0xEA58, 0x9DD9, 0xEA59, 0x9DD3, 0xEA5A, 0x9DF8, 0xEA5B, 0x9DE6, 0xEA5C, 0x9DED, 0xEA5D, 0x9DEF, 0xEA5E, 0x9DFD, 0xEA5F, 0x9E1A, 0xEA60, 0x9E1B, 0xEA61, 0x9E1E, 0xEA62, 0x9E75, 0xEA63, 0x9E79, 0xEA64, 0x9E7D, 0xEA65, 0x9E81, 0xEA66, 0x9E88, 0xEA67, 0x9E8B, 0xEA68, 0x9E8C, 0xEA69, 0x9E92, 0xEA6A, 0x9E95, 0xEA6B, 0x9E91, 0xEA6C, 0x9E9D, 0xEA6D, 0x9EA5, 0xEA6E, 0x9EA9, 0xEA6F, 0x9EB8, 0xEA70, 0x9EAA, 0xEA71, 0x9EAD, 0xEA72, 0x9761, 0xEA73, 0x9ECC, 0xEA74, 0x9ECE, 0xEA75, 0x9ECF, 0xEA76, 0x9ED0, 0xEA77, 0x9ED4, 0xEA78, 0x9EDC, 0xEA79, 0x9EDE, 0xEA7A, 0x9EDD, 0xEA7B, 0x9EE0, 0xEA7C, 0x9EE5, 0xEA7D, 0x9EE8, 0xEA7E, 0x9EEF, 0xEA80, 0x9EF4, 0xEA81, 0x9EF6, 0xEA82, 0x9EF7, 0xEA83, 0x9EF9, 0xEA84, 0x9EFB, 0xEA85, 0x9EFC, 0xEA86, 0x9EFD, 0xEA87, 0x9F07, 0xEA88, 0x9F08, 0xEA89, 0x76B7, 0xEA8A, 0x9F15, 0xEA8B, 0x9F21, 0xEA8C, 0x9F2C, 0xEA8D, 0x9F3E, 0xEA8E, 0x9F4A, 0xEA8F, 0x9F52, 0xEA90, 0x9F54, 0xEA91, 0x9F63, 0xEA92, 0x9F5F, 0xEA93, 0x9F60, 0xEA94, 0x9F61, 0xEA95, 0x9F66, 0xEA96, 0x9F67, 0xEA97, 0x9F6C, 0xEA98, 0x9F6A, 0xEA99, 0x9F77, 0xEA9A, 0x9F72, 0xEA9B, 0x9F76, 0xEA9C, 0x9F95, 0xEA9D, 0x9F9C, 0xEA9E, 0x9FA0, 0xEA9F, 0x582F, 0xEAA0, 0x69C7, 0xEAA1, 0x9059, 0xEAA2, 0x7464, 0xEAA3, 0x51DC, 0xEAA4, 0x7199, 0xFA40, 0x2170, 0xFA41, 0x2171, 0xFA42, 0x2172, 0xFA43, 0x2173, 0xFA44, 0x2174, 0xFA45, 0x2175, 0xFA46, 0x2176, 0xFA47, 0x2177, 0xFA48, 0x2178, 0xFA49, 0x2179, 0xFA55, 0xFFE4, 0xFA56, 0xFF07, 0xFA57, 0xFF02, 0xFA5C, 0x7E8A, 0xFA5D, 0x891C, 0xFA5E, 0x9348, 0xFA5F, 0x9288, 0xFA60, 0x84DC, 0xFA61, 0x4FC9, 0xFA62, 0x70BB, 0xFA63, 0x6631, 0xFA64, 0x68C8, 0xFA65, 0x92F9, 0xFA66, 0x66FB, 0xFA67, 0x5F45, 0xFA68, 0x4E28, 0xFA69, 0x4EE1, 0xFA6A, 0x4EFC, 0xFA6B, 0x4F00, 0xFA6C, 0x4F03, 0xFA6D, 0x4F39, 0xFA6E, 0x4F56, 0xFA6F, 0x4F92, 0xFA70, 0x4F8A, 0xFA71, 0x4F9A, 0xFA72, 0x4F94, 0xFA73, 0x4FCD, 0xFA74, 0x5040, 0xFA75, 0x5022, 0xFA76, 0x4FFF, 0xFA77, 0x501E, 0xFA78, 0x5046, 0xFA79, 0x5070, 0xFA7A, 0x5042, 0xFA7B, 0x5094, 0xFA7C, 0x50F4, 0xFA7D, 0x50D8, 0xFA7E, 0x514A, 0xFA80, 0x5164, 0xFA81, 0x519D, 0xFA82, 0x51BE, 0xFA83, 0x51EC, 0xFA84, 0x5215, 0xFA85, 0x529C, 0xFA86, 0x52A6, 0xFA87, 0x52C0, 0xFA88, 0x52DB, 0xFA89, 0x5300, 0xFA8A, 0x5307, 0xFA8B, 0x5324, 0xFA8C, 0x5372, 0xFA8D, 0x5393, 0xFA8E, 0x53B2, 0xFA8F, 0x53DD, 0xFA90, 0xFA0E, 0xFA91, 0x549C, 0xFA92, 0x548A, 0xFA93, 0x54A9, 0xFA94, 0x54FF, 0xFA95, 0x5586, 0xFA96, 0x5759, 0xFA97, 0x5765, 0xFA98, 0x57AC, 0xFA99, 0x57C8, 0xFA9A, 0x57C7, 0xFA9B, 0xFA0F, 0xFA9C, 0xFA10, 0xFA9D, 0x589E, 0xFA9E, 0x58B2, 0xFA9F, 0x590B, 0xFAA0, 0x5953, 0xFAA1, 0x595B, 0xFAA2, 0x595D, 0xFAA3, 0x5963, 0xFAA4, 0x59A4, 0xFAA5, 0x59BA, 0xFAA6, 0x5B56, 0xFAA7, 0x5BC0, 0xFAA8, 0x752F, 0xFAA9, 0x5BD8, 0xFAAA, 0x5BEC, 0xFAAB, 0x5C1E, 0xFAAC, 0x5CA6, 0xFAAD, 0x5CBA, 0xFAAE, 0x5CF5, 0xFAAF, 0x5D27, 0xFAB0, 0x5D53, 0xFAB1, 0xFA11, 0xFAB2, 0x5D42, 0xFAB3, 0x5D6D, 0xFAB4, 0x5DB8, 0xFAB5, 0x5DB9, 0xFAB6, 0x5DD0, 0xFAB7, 0x5F21, 0xFAB8, 0x5F34, 0xFAB9, 0x5F67, 0xFABA, 0x5FB7, 0xFABB, 0x5FDE, 0xFABC, 0x605D, 0xFABD, 0x6085, 0xFABE, 0x608A, 0xFABF, 0x60DE, 0xFAC0, 0x60D5, 0xFAC1, 0x6120, 0xFAC2, 0x60F2, 0xFAC3, 0x6111, 0xFAC4, 0x6137, 0xFAC5, 0x6130, 0xFAC6, 0x6198, 0xFAC7, 0x6213, 0xFAC8, 0x62A6, 0xFAC9, 0x63F5, 0xFACA, 0x6460, 0xFACB, 0x649D, 0xFACC, 0x64CE, 0xFACD, 0x654E, 0xFACE, 0x6600, 0xFACF, 0x6615, 0xFAD0, 0x663B, 0xFAD1, 0x6609, 0xFAD2, 0x662E, 0xFAD3, 0x661E, 0xFAD4, 0x6624, 0xFAD5, 0x6665, 0xFAD6, 0x6657, 0xFAD7, 0x6659, 0xFAD8, 0xFA12, 0xFAD9, 0x6673, 0xFADA, 0x6699, 0xFADB, 0x66A0, 0xFADC, 0x66B2, 0xFADD, 0x66BF, 0xFADE, 0x66FA, 0xFADF, 0x670E, 0xFAE0, 0xF929, 0xFAE1, 0x6766, 0xFAE2, 0x67BB, 0xFAE3, 0x6852, 0xFAE4, 0x67C0, 0xFAE5, 0x6801, 0xFAE6, 0x6844, 0xFAE7, 0x68CF, 0xFAE8, 0xFA13, 0xFAE9, 0x6968, 0xFAEA, 0xFA14, 0xFAEB, 0x6998, 0xFAEC, 0x69E2, 0xFAED, 0x6A30, 0xFAEE, 0x6A6B, 0xFAEF, 0x6A46, 0xFAF0, 0x6A73, 0xFAF1, 0x6A7E, 0xFAF2, 0x6AE2, 0xFAF3, 0x6AE4, 0xFAF4, 0x6BD6, 0xFAF5, 0x6C3F, 0xFAF6, 0x6C5C, 0xFAF7, 0x6C86, 0xFAF8, 0x6C6F, 0xFAF9, 0x6CDA, 0xFAFA, 0x6D04, 0xFAFB, 0x6D87, 0xFAFC, 0x6D6F, 0xFB40, 0x6D96, 0xFB41, 0x6DAC, 0xFB42, 0x6DCF, 0xFB43, 0x6DF8, 0xFB44, 0x6DF2, 0xFB45, 0x6DFC, 0xFB46, 0x6E39, 0xFB47, 0x6E5C, 0xFB48, 0x6E27, 0xFB49, 0x6E3C, 0xFB4A, 0x6EBF, 0xFB4B, 0x6F88, 0xFB4C, 0x6FB5, 0xFB4D, 0x6FF5, 0xFB4E, 0x7005, 0xFB4F, 0x7007, 0xFB50, 0x7028, 0xFB51, 0x7085, 0xFB52, 0x70AB, 0xFB53, 0x710F, 0xFB54, 0x7104, 0xFB55, 0x715C, 0xFB56, 0x7146, 0xFB57, 0x7147, 0xFB58, 0xFA15, 0xFB59, 0x71C1, 0xFB5A, 0x71FE, 0xFB5B, 0x72B1, 0xFB5C, 0x72BE, 0xFB5D, 0x7324, 0xFB5E, 0xFA16, 0xFB5F, 0x7377, 0xFB60, 0x73BD, 0xFB61, 0x73C9, 0xFB62, 0x73D6, 0xFB63, 0x73E3, 0xFB64, 0x73D2, 0xFB65, 0x7407, 0xFB66, 0x73F5, 0xFB67, 0x7426, 0xFB68, 0x742A, 0xFB69, 0x7429, 0xFB6A, 0x742E, 0xFB6B, 0x7462, 0xFB6C, 0x7489, 0xFB6D, 0x749F, 0xFB6E, 0x7501, 0xFB6F, 0x756F, 0xFB70, 0x7682, 0xFB71, 0x769C, 0xFB72, 0x769E, 0xFB73, 0x769B, 0xFB74, 0x76A6, 0xFB75, 0xFA17, 0xFB76, 0x7746, 0xFB77, 0x52AF, 0xFB78, 0x7821, 0xFB79, 0x784E, 0xFB7A, 0x7864, 0xFB7B, 0x787A, 0xFB7C, 0x7930, 0xFB7D, 0xFA18, 0xFB7E, 0xFA19, 0xFB80, 0xFA1A, 0xFB81, 0x7994, 0xFB82, 0xFA1B, 0xFB83, 0x799B, 0xFB84, 0x7AD1, 0xFB85, 0x7AE7, 0xFB86, 0xFA1C, 0xFB87, 0x7AEB, 0xFB88, 0x7B9E, 0xFB89, 0xFA1D, 0xFB8A, 0x7D48, 0xFB8B, 0x7D5C, 0xFB8C, 0x7DB7, 0xFB8D, 0x7DA0, 0xFB8E, 0x7DD6, 0xFB8F, 0x7E52, 0xFB90, 0x7F47, 0xFB91, 0x7FA1, 0xFB92, 0xFA1E, 0xFB93, 0x8301, 0xFB94, 0x8362, 0xFB95, 0x837F, 0xFB96, 0x83C7, 0xFB97, 0x83F6, 0xFB98, 0x8448, 0xFB99, 0x84B4, 0xFB9A, 0x8553, 0xFB9B, 0x8559, 0xFB9C, 0x856B, 0xFB9D, 0xFA1F, 0xFB9E, 0x85B0, 0xFB9F, 0xFA20, 0xFBA0, 0xFA21, 0xFBA1, 0x8807, 0xFBA2, 0x88F5, 0xFBA3, 0x8A12, 0xFBA4, 0x8A37, 0xFBA5, 0x8A79, 0xFBA6, 0x8AA7, 0xFBA7, 0x8ABE, 0xFBA8, 0x8ADF, 0xFBA9, 0xFA22, 0xFBAA, 0x8AF6, 0xFBAB, 0x8B53, 0xFBAC, 0x8B7F, 0xFBAD, 0x8CF0, 0xFBAE, 0x8CF4, 0xFBAF, 0x8D12, 0xFBB0, 0x8D76, 0xFBB1, 0xFA23, 0xFBB2, 0x8ECF, 0xFBB3, 0xFA24, 0xFBB4, 0xFA25, 0xFBB5, 0x9067, 0xFBB6, 0x90DE, 0xFBB7, 0xFA26, 0xFBB8, 0x9115, 0xFBB9, 0x9127, 0xFBBA, 0x91DA, 0xFBBB, 0x91D7, 0xFBBC, 0x91DE, 0xFBBD, 0x91ED, 0xFBBE, 0x91EE, 0xFBBF, 0x91E4, 0xFBC0, 0x91E5, 0xFBC1, 0x9206, 0xFBC2, 0x9210, 0xFBC3, 0x920A, 0xFBC4, 0x923A, 0xFBC5, 0x9240, 0xFBC6, 0x923C, 0xFBC7, 0x924E, 0xFBC8, 0x9259, 0xFBC9, 0x9251, 0xFBCA, 0x9239, 0xFBCB, 0x9267, 0xFBCC, 0x92A7, 0xFBCD, 0x9277, 0xFBCE, 0x9278, 0xFBCF, 0x92E7, 0xFBD0, 0x92D7, 0xFBD1, 0x92D9, 0xFBD2, 0x92D0, 0xFBD3, 0xFA27, 0xFBD4, 0x92D5, 0xFBD5, 0x92E0, 0xFBD6, 0x92D3, 0xFBD7, 0x9325, 0xFBD8, 0x9321, 0xFBD9, 0x92FB, 0xFBDA, 0xFA28, 0xFBDB, 0x931E, 0xFBDC, 0x92FF, 0xFBDD, 0x931D, 0xFBDE, 0x9302, 0xFBDF, 0x9370, 0xFBE0, 0x9357, 0xFBE1, 0x93A4, 0xFBE2, 0x93C6, 0xFBE3, 0x93DE, 0xFBE4, 0x93F8, 0xFBE5, 0x9431, 0xFBE6, 0x9445, 0xFBE7, 0x9448, 0xFBE8, 0x9592, 0xFBE9, 0xF9DC, 0xFBEA, 0xFA29, 0xFBEB, 0x969D, 0xFBEC, 0x96AF, 0xFBED, 0x9733, 0xFBEE, 0x973B, 0xFBEF, 0x9743, 0xFBF0, 0x974D, 0xFBF1, 0x974F, 0xFBF2, 0x9751, 0xFBF3, 0x9755, 0xFBF4, 0x9857, 0xFBF5, 0x9865, 0xFBF6, 0xFA2A, 0xFBF7, 0xFA2B, 0xFBF8, 0x9927, 0xFBF9, 0xFA2C, 0xFBFA, 0x999E, 0xFBFB, 0x9A4E, 0xFBFC, 0x9AD9, 0xFC40, 0x9ADC, 0xFC41, 0x9B75, 0xFC42, 0x9B72, 0xFC43, 0x9B8F, 0xFC44, 0x9BB1, 0xFC45, 0x9BBB, 0xFC46, 0x9C00, 0xFC47, 0x9D70, 0xFC48, 0x9D6B, 0xFC49, 0xFA2D, 0xFC4A, 0x9E19, 0xFC4B, 0x9ED1, 0, 0 }; #endif #if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */ static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ 0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4, 0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE, 0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9, 0x0144, 0xA8BD, 0x0148, 0xA8BE, 0x014D, 0xA8AD, 0x016B, 0xA8B1, 0x01CE, 0xA8A3, 0x01D0, 0xA8AB, 0x01D2, 0xA8AF, 0x01D4, 0xA8B3, 0x01D6, 0xA8B5, 0x01D8, 0xA8B6, 0x01DA, 0xA8B7, 0x01DC, 0xA8B8, 0x0251, 0xA8BB, 0x0261, 0xA8C0, 0x02C7, 0xA1A6, 0x02C9, 0xA1A5, 0x02CA, 0xA840, 0x02CB, 0xA841, 0x02D9, 0xA842, 0x0391, 0xA6A1, 0x0392, 0xA6A2, 0x0393, 0xA6A3, 0x0394, 0xA6A4, 0x0395, 0xA6A5, 0x0396, 0xA6A6, 0x0397, 0xA6A7, 0x0398, 0xA6A8, 0x0399, 0xA6A9, 0x039A, 0xA6AA, 0x039B, 0xA6AB, 0x039C, 0xA6AC, 0x039D, 0xA6AD, 0x039E, 0xA6AE, 0x039F, 0xA6AF, 0x03A0, 0xA6B0, 0x03A1, 0xA6B1, 0x03A3, 0xA6B2, 0x03A4, 0xA6B3, 0x03A5, 0xA6B4, 0x03A6, 0xA6B5, 0x03A7, 0xA6B6, 0x03A8, 0xA6B7, 0x03A9, 0xA6B8, 0x03B1, 0xA6C1, 0x03B2, 0xA6C2, 0x03B3, 0xA6C3, 0x03B4, 0xA6C4, 0x03B5, 0xA6C5, 0x03B6, 0xA6C6, 0x03B7, 0xA6C7, 0x03B8, 0xA6C8, 0x03B9, 0xA6C9, 0x03BA, 0xA6CA, 0x03BB, 0xA6CB, 0x03BC, 0xA6CC, 0x03BD, 0xA6CD, 0x03BE, 0xA6CE, 0x03BF, 0xA6CF, 0x03C0, 0xA6D0, 0x03C1, 0xA6D1, 0x03C3, 0xA6D2, 0x03C4, 0xA6D3, 0x03C5, 0xA6D4, 0x03C6, 0xA6D5, 0x03C7, 0xA6D6, 0x03C8, 0xA6D7, 0x03C9, 0xA6D8, 0x0401, 0xA7A7, 0x0410, 0xA7A1, 0x0411, 0xA7A2, 0x0412, 0xA7A3, 0x0413, 0xA7A4, 0x0414, 0xA7A5, 0x0415, 0xA7A6, 0x0416, 0xA7A8, 0x0417, 0xA7A9, 0x0418, 0xA7AA, 0x0419, 0xA7AB, 0x041A, 0xA7AC, 0x041B, 0xA7AD, 0x041C, 0xA7AE, 0x041D, 0xA7AF, 0x041E, 0xA7B0, 0x041F, 0xA7B1, 0x0420, 0xA7B2, 0x0421, 0xA7B3, 0x0422, 0xA7B4, 0x0423, 0xA7B5, 0x0424, 0xA7B6, 0x0425, 0xA7B7, 0x0426, 0xA7B8, 0x0427, 0xA7B9, 0x0428, 0xA7BA, 0x0429, 0xA7BB, 0x042A, 0xA7BC, 0x042B, 0xA7BD, 0x042C, 0xA7BE, 0x042D, 0xA7BF, 0x042E, 0xA7C0, 0x042F, 0xA7C1, 0x0430, 0xA7D1, 0x0431, 0xA7D2, 0x0432, 0xA7D3, 0x0433, 0xA7D4, 0x0434, 0xA7D5, 0x0435, 0xA7D6, 0x0436, 0xA7D8, 0x0437, 0xA7D9, 0x0438, 0xA7DA, 0x0439, 0xA7DB, 0x043A, 0xA7DC, 0x043B, 0xA7DD, 0x043C, 0xA7DE, 0x043D, 0xA7DF, 0x043E, 0xA7E0, 0x043F, 0xA7E1, 0x0440, 0xA7E2, 0x0441, 0xA7E3, 0x0442, 0xA7E4, 0x0443, 0xA7E5, 0x0444, 0xA7E6, 0x0445, 0xA7E7, 0x0446, 0xA7E8, 0x0447, 0xA7E9, 0x0448, 0xA7EA, 0x0449, 0xA7EB, 0x044A, 0xA7EC, 0x044B, 0xA7ED, 0x044C, 0xA7EE, 0x044D, 0xA7EF, 0x044E, 0xA7F0, 0x044F, 0xA7F1, 0x0451, 0xA7D7, 0x2010, 0xA95C, 0x2013, 0xA843, 0x2014, 0xA1AA, 0x2015, 0xA844, 0x2016, 0xA1AC, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, 0x2025, 0xA845, 0x2026, 0xA1AD, 0x2030, 0xA1EB, 0x2032, 0xA1E4, 0x2033, 0xA1E5, 0x2035, 0xA846, 0x203B, 0xA1F9, 0x20AC, 0x0080, 0x2103, 0xA1E6, 0x2105, 0xA847, 0x2109, 0xA848, 0x2116, 0xA1ED, 0x2121, 0xA959, 0x2160, 0xA2F1, 0x2161, 0xA2F2, 0x2162, 0xA2F3, 0x2163, 0xA2F4, 0x2164, 0xA2F5, 0x2165, 0xA2F6, 0x2166, 0xA2F7, 0x2167, 0xA2F8, 0x2168, 0xA2F9, 0x2169, 0xA2FA, 0x216A, 0xA2FB, 0x216B, 0xA2FC, 0x2170, 0xA2A1, 0x2171, 0xA2A2, 0x2172, 0xA2A3, 0x2173, 0xA2A4, 0x2174, 0xA2A5, 0x2175, 0xA2A6, 0x2176, 0xA2A7, 0x2177, 0xA2A8, 0x2178, 0xA2A9, 0x2179, 0xA2AA, 0x2190, 0xA1FB, 0x2191, 0xA1FC, 0x2192, 0xA1FA, 0x2193, 0xA1FD, 0x2196, 0xA849, 0x2197, 0xA84A, 0x2198, 0xA84B, 0x2199, 0xA84C, 0x2208, 0xA1CA, 0x220F, 0xA1C7, 0x2211, 0xA1C6, 0x2215, 0xA84D, 0x221A, 0xA1CC, 0x221D, 0xA1D8, 0x221E, 0xA1DE, 0x221F, 0xA84E, 0x2220, 0xA1CF, 0x2223, 0xA84F, 0x2225, 0xA1CE, 0x2227, 0xA1C4, 0x2228, 0xA1C5, 0x2229, 0xA1C9, 0x222A, 0xA1C8, 0x222B, 0xA1D2, 0x222E, 0xA1D3, 0x2234, 0xA1E0, 0x2235, 0xA1DF, 0x2236, 0xA1C3, 0x2237, 0xA1CB, 0x223D, 0xA1D7, 0x2248, 0xA1D6, 0x224C, 0xA1D5, 0x2252, 0xA850, 0x2260, 0xA1D9, 0x2261, 0xA1D4, 0x2264, 0xA1DC, 0x2265, 0xA1DD, 0x2266, 0xA851, 0x2267, 0xA852, 0x226E, 0xA1DA, 0x226F, 0xA1DB, 0x2295, 0xA892, 0x2299, 0xA1D1, 0x22A5, 0xA1CD, 0x22BF, 0xA853, 0x2312, 0xA1D0, 0x2460, 0xA2D9, 0x2461, 0xA2DA, 0x2462, 0xA2DB, 0x2463, 0xA2DC, 0x2464, 0xA2DD, 0x2465, 0xA2DE, 0x2466, 0xA2DF, 0x2467, 0xA2E0, 0x2468, 0xA2E1, 0x2469, 0xA2E2, 0x2474, 0xA2C5, 0x2475, 0xA2C6, 0x2476, 0xA2C7, 0x2477, 0xA2C8, 0x2478, 0xA2C9, 0x2479, 0xA2CA, 0x247A, 0xA2CB, 0x247B, 0xA2CC, 0x247C, 0xA2CD, 0x247D, 0xA2CE, 0x247E, 0xA2CF, 0x247F, 0xA2D0, 0x2480, 0xA2D1, 0x2481, 0xA2D2, 0x2482, 0xA2D3, 0x2483, 0xA2D4, 0x2484, 0xA2D5, 0x2485, 0xA2D6, 0x2486, 0xA2D7, 0x2487, 0xA2D8, 0x2488, 0xA2B1, 0x2489, 0xA2B2, 0x248A, 0xA2B3, 0x248B, 0xA2B4, 0x248C, 0xA2B5, 0x248D, 0xA2B6, 0x248E, 0xA2B7, 0x248F, 0xA2B8, 0x2490, 0xA2B9, 0x2491, 0xA2BA, 0x2492, 0xA2BB, 0x2493, 0xA2BC, 0x2494, 0xA2BD, 0x2495, 0xA2BE, 0x2496, 0xA2BF, 0x2497, 0xA2C0, 0x2498, 0xA2C1, 0x2499, 0xA2C2, 0x249A, 0xA2C3, 0x249B, 0xA2C4, 0x2500, 0xA9A4, 0x2501, 0xA9A5, 0x2502, 0xA9A6, 0x2503, 0xA9A7, 0x2504, 0xA9A8, 0x2505, 0xA9A9, 0x2506, 0xA9AA, 0x2507, 0xA9AB, 0x2508, 0xA9AC, 0x2509, 0xA9AD, 0x250A, 0xA9AE, 0x250B, 0xA9AF, 0x250C, 0xA9B0, 0x250D, 0xA9B1, 0x250E, 0xA9B2, 0x250F, 0xA9B3, 0x2510, 0xA9B4, 0x2511, 0xA9B5, 0x2512, 0xA9B6, 0x2513, 0xA9B7, 0x2514, 0xA9B8, 0x2515, 0xA9B9, 0x2516, 0xA9BA, 0x2517, 0xA9BB, 0x2518, 0xA9BC, 0x2519, 0xA9BD, 0x251A, 0xA9BE, 0x251B, 0xA9BF, 0x251C, 0xA9C0, 0x251D, 0xA9C1, 0x251E, 0xA9C2, 0x251F, 0xA9C3, 0x2520, 0xA9C4, 0x2521, 0xA9C5, 0x2522, 0xA9C6, 0x2523, 0xA9C7, 0x2524, 0xA9C8, 0x2525, 0xA9C9, 0x2526, 0xA9CA, 0x2527, 0xA9CB, 0x2528, 0xA9CC, 0x2529, 0xA9CD, 0x252A, 0xA9CE, 0x252B, 0xA9CF, 0x252C, 0xA9D0, 0x252D, 0xA9D1, 0x252E, 0xA9D2, 0x252F, 0xA9D3, 0x2530, 0xA9D4, 0x2531, 0xA9D5, 0x2532, 0xA9D6, 0x2533, 0xA9D7, 0x2534, 0xA9D8, 0x2535, 0xA9D9, 0x2536, 0xA9DA, 0x2537, 0xA9DB, 0x2538, 0xA9DC, 0x2539, 0xA9DD, 0x253A, 0xA9DE, 0x253B, 0xA9DF, 0x253C, 0xA9E0, 0x253D, 0xA9E1, 0x253E, 0xA9E2, 0x253F, 0xA9E3, 0x2540, 0xA9E4, 0x2541, 0xA9E5, 0x2542, 0xA9E6, 0x2543, 0xA9E7, 0x2544, 0xA9E8, 0x2545, 0xA9E9, 0x2546, 0xA9EA, 0x2547, 0xA9EB, 0x2548, 0xA9EC, 0x2549, 0xA9ED, 0x254A, 0xA9EE, 0x254B, 0xA9EF, 0x2550, 0xA854, 0x2551, 0xA855, 0x2552, 0xA856, 0x2553, 0xA857, 0x2554, 0xA858, 0x2555, 0xA859, 0x2556, 0xA85A, 0x2557, 0xA85B, 0x2558, 0xA85C, 0x2559, 0xA85D, 0x255A, 0xA85E, 0x255B, 0xA85F, 0x255C, 0xA860, 0x255D, 0xA861, 0x255E, 0xA862, 0x255F, 0xA863, 0x2560, 0xA864, 0x2561, 0xA865, 0x2562, 0xA866, 0x2563, 0xA867, 0x2564, 0xA868, 0x2565, 0xA869, 0x2566, 0xA86A, 0x2567, 0xA86B, 0x2568, 0xA86C, 0x2569, 0xA86D, 0x256A, 0xA86E, 0x256B, 0xA86F, 0x256C, 0xA870, 0x256D, 0xA871, 0x256E, 0xA872, 0x256F, 0xA873, 0x2570, 0xA874, 0x2571, 0xA875, 0x2572, 0xA876, 0x2573, 0xA877, 0x2581, 0xA878, 0x2582, 0xA879, 0x2583, 0xA87A, 0x2584, 0xA87B, 0x2585, 0xA87C, 0x2586, 0xA87D, 0x2587, 0xA87E, 0x2588, 0xA880, 0x2589, 0xA881, 0x258A, 0xA882, 0x258B, 0xA883, 0x258C, 0xA884, 0x258D, 0xA885, 0x258E, 0xA886, 0x258F, 0xA887, 0x2593, 0xA888, 0x2594, 0xA889, 0x2595, 0xA88A, 0x25A0, 0xA1F6, 0x25A1, 0xA1F5, 0x25B2, 0xA1F8, 0x25B3, 0xA1F7, 0x25BC, 0xA88B, 0x25BD, 0xA88C, 0x25C6, 0xA1F4, 0x25C7, 0xA1F3, 0x25CB, 0xA1F0, 0x25CE, 0xA1F2, 0x25CF, 0xA1F1, 0x25E2, 0xA88D, 0x25E3, 0xA88E, 0x25E4, 0xA88F, 0x25E5, 0xA890, 0x2605, 0xA1EF, 0x2606, 0xA1EE, 0x2609, 0xA891, 0x2640, 0xA1E2, 0x2642, 0xA1E1, 0x3000, 0xA1A1, 0x3001, 0xA1A2, 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3005, 0xA1A9, 0x3006, 0xA965, 0x3007, 0xA996, 0x3008, 0xA1B4, 0x3009, 0xA1B5, 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BE, 0x3011, 0xA1BF, 0x3012, 0xA893, 0x3013, 0xA1FE, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3016, 0xA1BC, 0x3017, 0xA1BD, 0x301D, 0xA894, 0x301E, 0xA895, 0x3021, 0xA940, 0x3022, 0xA941, 0x3023, 0xA942, 0x3024, 0xA943, 0x3025, 0xA944, 0x3026, 0xA945, 0x3027, 0xA946, 0x3028, 0xA947, 0x3029, 0xA948, 0x3041, 0xA4A1, 0x3042, 0xA4A2, 0x3043, 0xA4A3, 0x3044, 0xA4A4, 0x3045, 0xA4A5, 0x3046, 0xA4A6, 0x3047, 0xA4A7, 0x3048, 0xA4A8, 0x3049, 0xA4A9, 0x304A, 0xA4AA, 0x304B, 0xA4AB, 0x304C, 0xA4AC, 0x304D, 0xA4AD, 0x304E, 0xA4AE, 0x304F, 0xA4AF, 0x3050, 0xA4B0, 0x3051, 0xA4B1, 0x3052, 0xA4B2, 0x3053, 0xA4B3, 0x3054, 0xA4B4, 0x3055, 0xA4B5, 0x3056, 0xA4B6, 0x3057, 0xA4B7, 0x3058, 0xA4B8, 0x3059, 0xA4B9, 0x305A, 0xA4BA, 0x305B, 0xA4BB, 0x305C, 0xA4BC, 0x305D, 0xA4BD, 0x305E, 0xA4BE, 0x305F, 0xA4BF, 0x3060, 0xA4C0, 0x3061, 0xA4C1, 0x3062, 0xA4C2, 0x3063, 0xA4C3, 0x3064, 0xA4C4, 0x3065, 0xA4C5, 0x3066, 0xA4C6, 0x3067, 0xA4C7, 0x3068, 0xA4C8, 0x3069, 0xA4C9, 0x306A, 0xA4CA, 0x306B, 0xA4CB, 0x306C, 0xA4CC, 0x306D, 0xA4CD, 0x306E, 0xA4CE, 0x306F, 0xA4CF, 0x3070, 0xA4D0, 0x3071, 0xA4D1, 0x3072, 0xA4D2, 0x3073, 0xA4D3, 0x3074, 0xA4D4, 0x3075, 0xA4D5, 0x3076, 0xA4D6, 0x3077, 0xA4D7, 0x3078, 0xA4D8, 0x3079, 0xA4D9, 0x307A, 0xA4DA, 0x307B, 0xA4DB, 0x307C, 0xA4DC, 0x307D, 0xA4DD, 0x307E, 0xA4DE, 0x307F, 0xA4DF, 0x3080, 0xA4E0, 0x3081, 0xA4E1, 0x3082, 0xA4E2, 0x3083, 0xA4E3, 0x3084, 0xA4E4, 0x3085, 0xA4E5, 0x3086, 0xA4E6, 0x3087, 0xA4E7, 0x3088, 0xA4E8, 0x3089, 0xA4E9, 0x308A, 0xA4EA, 0x308B, 0xA4EB, 0x308C, 0xA4EC, 0x308D, 0xA4ED, 0x308E, 0xA4EE, 0x308F, 0xA4EF, 0x3090, 0xA4F0, 0x3091, 0xA4F1, 0x3092, 0xA4F2, 0x3093, 0xA4F3, 0x309B, 0xA961, 0x309C, 0xA962, 0x309D, 0xA966, 0x309E, 0xA967, 0x30A1, 0xA5A1, 0x30A2, 0xA5A2, 0x30A3, 0xA5A3, 0x30A4, 0xA5A4, 0x30A5, 0xA5A5, 0x30A6, 0xA5A6, 0x30A7, 0xA5A7, 0x30A8, 0xA5A8, 0x30A9, 0xA5A9, 0x30AA, 0xA5AA, 0x30AB, 0xA5AB, 0x30AC, 0xA5AC, 0x30AD, 0xA5AD, 0x30AE, 0xA5AE, 0x30AF, 0xA5AF, 0x30B0, 0xA5B0, 0x30B1, 0xA5B1, 0x30B2, 0xA5B2, 0x30B3, 0xA5B3, 0x30B4, 0xA5B4, 0x30B5, 0xA5B5, 0x30B6, 0xA5B6, 0x30B7, 0xA5B7, 0x30B8, 0xA5B8, 0x30B9, 0xA5B9, 0x30BA, 0xA5BA, 0x30BB, 0xA5BB, 0x30BC, 0xA5BC, 0x30BD, 0xA5BD, 0x30BE, 0xA5BE, 0x30BF, 0xA5BF, 0x30C0, 0xA5C0, 0x30C1, 0xA5C1, 0x30C2, 0xA5C2, 0x30C3, 0xA5C3, 0x30C4, 0xA5C4, 0x30C5, 0xA5C5, 0x30C6, 0xA5C6, 0x30C7, 0xA5C7, 0x30C8, 0xA5C8, 0x30C9, 0xA5C9, 0x30CA, 0xA5CA, 0x30CB, 0xA5CB, 0x30CC, 0xA5CC, 0x30CD, 0xA5CD, 0x30CE, 0xA5CE, 0x30CF, 0xA5CF, 0x30D0, 0xA5D0, 0x30D1, 0xA5D1, 0x30D2, 0xA5D2, 0x30D3, 0xA5D3, 0x30D4, 0xA5D4, 0x30D5, 0xA5D5, 0x30D6, 0xA5D6, 0x30D7, 0xA5D7, 0x30D8, 0xA5D8, 0x30D9, 0xA5D9, 0x30DA, 0xA5DA, 0x30DB, 0xA5DB, 0x30DC, 0xA5DC, 0x30DD, 0xA5DD, 0x30DE, 0xA5DE, 0x30DF, 0xA5DF, 0x30E0, 0xA5E0, 0x30E1, 0xA5E1, 0x30E2, 0xA5E2, 0x30E3, 0xA5E3, 0x30E4, 0xA5E4, 0x30E5, 0xA5E5, 0x30E6, 0xA5E6, 0x30E7, 0xA5E7, 0x30E8, 0xA5E8, 0x30E9, 0xA5E9, 0x30EA, 0xA5EA, 0x30EB, 0xA5EB, 0x30EC, 0xA5EC, 0x30ED, 0xA5ED, 0x30EE, 0xA5EE, 0x30EF, 0xA5EF, 0x30F0, 0xA5F0, 0x30F1, 0xA5F1, 0x30F2, 0xA5F2, 0x30F3, 0xA5F3, 0x30F4, 0xA5F4, 0x30F5, 0xA5F5, 0x30F6, 0xA5F6, 0x30FC, 0xA960, 0x30FD, 0xA963, 0x30FE, 0xA964, 0x3105, 0xA8C5, 0x3106, 0xA8C6, 0x3107, 0xA8C7, 0x3108, 0xA8C8, 0x3109, 0xA8C9, 0x310A, 0xA8CA, 0x310B, 0xA8CB, 0x310C, 0xA8CC, 0x310D, 0xA8CD, 0x310E, 0xA8CE, 0x310F, 0xA8CF, 0x3110, 0xA8D0, 0x3111, 0xA8D1, 0x3112, 0xA8D2, 0x3113, 0xA8D3, 0x3114, 0xA8D4, 0x3115, 0xA8D5, 0x3116, 0xA8D6, 0x3117, 0xA8D7, 0x3118, 0xA8D8, 0x3119, 0xA8D9, 0x311A, 0xA8DA, 0x311B, 0xA8DB, 0x311C, 0xA8DC, 0x311D, 0xA8DD, 0x311E, 0xA8DE, 0x311F, 0xA8DF, 0x3120, 0xA8E0, 0x3121, 0xA8E1, 0x3122, 0xA8E2, 0x3123, 0xA8E3, 0x3124, 0xA8E4, 0x3125, 0xA8E5, 0x3126, 0xA8E6, 0x3127, 0xA8E7, 0x3128, 0xA8E8, 0x3129, 0xA8E9, 0x3220, 0xA2E5, 0x3221, 0xA2E6, 0x3222, 0xA2E7, 0x3223, 0xA2E8, 0x3224, 0xA2E9, 0x3225, 0xA2EA, 0x3226, 0xA2EB, 0x3227, 0xA2EC, 0x3228, 0xA2ED, 0x3229, 0xA2EE, 0x3231, 0xA95A, 0x32A3, 0xA949, 0x338E, 0xA94A, 0x338F, 0xA94B, 0x339C, 0xA94C, 0x339D, 0xA94D, 0x339E, 0xA94E, 0x33A1, 0xA94F, 0x33C4, 0xA950, 0x33CE, 0xA951, 0x33D1, 0xA952, 0x33D2, 0xA953, 0x33D5, 0xA954, 0x4E00, 0xD2BB, 0x4E01, 0xB6A1, 0x4E02, 0x8140, 0x4E03, 0xC6DF, 0x4E04, 0x8141, 0x4E05, 0x8142, 0x4E06, 0x8143, 0x4E07, 0xCDF2, 0x4E08, 0xD5C9, 0x4E09, 0xC8FD, 0x4E0A, 0xC9CF, 0x4E0B, 0xCFC2, 0x4E0C, 0xD8A2, 0x4E0D, 0xB2BB, 0x4E0E, 0xD3EB, 0x4E0F, 0x8144, 0x4E10, 0xD8A4, 0x4E11, 0xB3F3, 0x4E12, 0x8145, 0x4E13, 0xD7A8, 0x4E14, 0xC7D2, 0x4E15, 0xD8A7, 0x4E16, 0xCAC0, 0x4E17, 0x8146, 0x4E18, 0xC7F0, 0x4E19, 0xB1FB, 0x4E1A, 0xD2B5, 0x4E1B, 0xB4D4, 0x4E1C, 0xB6AB, 0x4E1D, 0xCBBF, 0x4E1E, 0xD8A9, 0x4E1F, 0x8147, 0x4E20, 0x8148, 0x4E21, 0x8149, 0x4E22, 0xB6AA, 0x4E23, 0x814A, 0x4E24, 0xC1BD, 0x4E25, 0xD1CF, 0x4E26, 0x814B, 0x4E27, 0xC9A5, 0x4E28, 0xD8AD, 0x4E29, 0x814C, 0x4E2A, 0xB8F6, 0x4E2B, 0xD1BE, 0x4E2C, 0xE3DC, 0x4E2D, 0xD6D0, 0x4E2E, 0x814D, 0x4E2F, 0x814E, 0x4E30, 0xB7E1, 0x4E31, 0x814F, 0x4E32, 0xB4AE, 0x4E33, 0x8150, 0x4E34, 0xC1D9, 0x4E35, 0x8151, 0x4E36, 0xD8BC, 0x4E37, 0x8152, 0x4E38, 0xCDE8, 0x4E39, 0xB5A4, 0x4E3A, 0xCEAA, 0x4E3B, 0xD6F7, 0x4E3C, 0x8153, 0x4E3D, 0xC0F6, 0x4E3E, 0xBED9, 0x4E3F, 0xD8AF, 0x4E40, 0x8154, 0x4E41, 0x8155, 0x4E42, 0x8156, 0x4E43, 0xC4CB, 0x4E44, 0x8157, 0x4E45, 0xBEC3, 0x4E46, 0x8158, 0x4E47, 0xD8B1, 0x4E48, 0xC3B4, 0x4E49, 0xD2E5, 0x4E4A, 0x8159, 0x4E4B, 0xD6AE, 0x4E4C, 0xCEDA, 0x4E4D, 0xD5A7, 0x4E4E, 0xBAF5, 0x4E4F, 0xB7A6, 0x4E50, 0xC0D6, 0x4E51, 0x815A, 0x4E52, 0xC6B9, 0x4E53, 0xC5D2, 0x4E54, 0xC7C7, 0x4E55, 0x815B, 0x4E56, 0xB9D4, 0x4E57, 0x815C, 0x4E58, 0xB3CB, 0x4E59, 0xD2D2, 0x4E5A, 0x815D, 0x4E5B, 0x815E, 0x4E5C, 0xD8BF, 0x4E5D, 0xBEC5, 0x4E5E, 0xC6F2, 0x4E5F, 0xD2B2, 0x4E60, 0xCFB0, 0x4E61, 0xCFE7, 0x4E62, 0x815F, 0x4E63, 0x8160, 0x4E64, 0x8161, 0x4E65, 0x8162, 0x4E66, 0xCAE9, 0x4E67, 0x8163, 0x4E68, 0x8164, 0x4E69, 0xD8C0, 0x4E6A, 0x8165, 0x4E6B, 0x8166, 0x4E6C, 0x8167, 0x4E6D, 0x8168, 0x4E6E, 0x8169, 0x4E6F, 0x816A, 0x4E70, 0xC2F2, 0x4E71, 0xC2D2, 0x4E72, 0x816B, 0x4E73, 0xC8E9, 0x4E74, 0x816C, 0x4E75, 0x816D, 0x4E76, 0x816E, 0x4E77, 0x816F, 0x4E78, 0x8170, 0x4E79, 0x8171, 0x4E7A, 0x8172, 0x4E7B, 0x8173, 0x4E7C, 0x8174, 0x4E7D, 0x8175, 0x4E7E, 0xC7AC, 0x4E7F, 0x8176, 0x4E80, 0x8177, 0x4E81, 0x8178, 0x4E82, 0x8179, 0x4E83, 0x817A, 0x4E84, 0x817B, 0x4E85, 0x817C, 0x4E86, 0xC1CB, 0x4E87, 0x817D, 0x4E88, 0xD3E8, 0x4E89, 0xD5F9, 0x4E8A, 0x817E, 0x4E8B, 0xCAC2, 0x4E8C, 0xB6FE, 0x4E8D, 0xD8A1, 0x4E8E, 0xD3DA, 0x4E8F, 0xBFF7, 0x4E90, 0x8180, 0x4E91, 0xD4C6, 0x4E92, 0xBBA5, 0x4E93, 0xD8C1, 0x4E94, 0xCEE5, 0x4E95, 0xBEAE, 0x4E96, 0x8181, 0x4E97, 0x8182, 0x4E98, 0xD8A8, 0x4E99, 0x8183, 0x4E9A, 0xD1C7, 0x4E9B, 0xD0A9, 0x4E9C, 0x8184, 0x4E9D, 0x8185, 0x4E9E, 0x8186, 0x4E9F, 0xD8BD, 0x4EA0, 0xD9EF, 0x4EA1, 0xCDF6, 0x4EA2, 0xBFBA, 0x4EA3, 0x8187, 0x4EA4, 0xBDBB, 0x4EA5, 0xBAA5, 0x4EA6, 0xD2E0, 0x4EA7, 0xB2FA, 0x4EA8, 0xBAE0, 0x4EA9, 0xC4B6, 0x4EAA, 0x8188, 0x4EAB, 0xCFED, 0x4EAC, 0xBEA9, 0x4EAD, 0xCDA4, 0x4EAE, 0xC1C1, 0x4EAF, 0x8189, 0x4EB0, 0x818A, 0x4EB1, 0x818B, 0x4EB2, 0xC7D7, 0x4EB3, 0xD9F1, 0x4EB4, 0x818C, 0x4EB5, 0xD9F4, 0x4EB6, 0x818D, 0x4EB7, 0x818E, 0x4EB8, 0x818F, 0x4EB9, 0x8190, 0x4EBA, 0xC8CB, 0x4EBB, 0xD8E9, 0x4EBC, 0x8191, 0x4EBD, 0x8192, 0x4EBE, 0x8193, 0x4EBF, 0xD2DA, 0x4EC0, 0xCAB2, 0x4EC1, 0xC8CA, 0x4EC2, 0xD8EC, 0x4EC3, 0xD8EA, 0x4EC4, 0xD8C6, 0x4EC5, 0xBDF6, 0x4EC6, 0xC6CD, 0x4EC7, 0xB3F0, 0x4EC8, 0x8194, 0x4EC9, 0xD8EB, 0x4ECA, 0xBDF1, 0x4ECB, 0xBDE9, 0x4ECC, 0x8195, 0x4ECD, 0xC8D4, 0x4ECE, 0xB4D3, 0x4ECF, 0x8196, 0x4ED0, 0x8197, 0x4ED1, 0xC2D8, 0x4ED2, 0x8198, 0x4ED3, 0xB2D6, 0x4ED4, 0xD7D0, 0x4ED5, 0xCACB, 0x4ED6, 0xCBFB, 0x4ED7, 0xD5CC, 0x4ED8, 0xB8B6, 0x4ED9, 0xCFC9, 0x4EDA, 0x8199, 0x4EDB, 0x819A, 0x4EDC, 0x819B, 0x4EDD, 0xD9DA, 0x4EDE, 0xD8F0, 0x4EDF, 0xC7AA, 0x4EE0, 0x819C, 0x4EE1, 0xD8EE, 0x4EE2, 0x819D, 0x4EE3, 0xB4FA, 0x4EE4, 0xC1EE, 0x4EE5, 0xD2D4, 0x4EE6, 0x819E, 0x4EE7, 0x819F, 0x4EE8, 0xD8ED, 0x4EE9, 0x81A0, 0x4EEA, 0xD2C7, 0x4EEB, 0xD8EF, 0x4EEC, 0xC3C7, 0x4EED, 0x81A1, 0x4EEE, 0x81A2, 0x4EEF, 0x81A3, 0x4EF0, 0xD1F6, 0x4EF1, 0x81A4, 0x4EF2, 0xD6D9, 0x4EF3, 0xD8F2, 0x4EF4, 0x81A5, 0x4EF5, 0xD8F5, 0x4EF6, 0xBCFE, 0x4EF7, 0xBCDB, 0x4EF8, 0x81A6, 0x4EF9, 0x81A7, 0x4EFA, 0x81A8, 0x4EFB, 0xC8CE, 0x4EFC, 0x81A9, 0x4EFD, 0xB7DD, 0x4EFE, 0x81AA, 0x4EFF, 0xB7C2, 0x4F00, 0x81AB, 0x4F01, 0xC6F3, 0x4F02, 0x81AC, 0x4F03, 0x81AD, 0x4F04, 0x81AE, 0x4F05, 0x81AF, 0x4F06, 0x81B0, 0x4F07, 0x81B1, 0x4F08, 0x81B2, 0x4F09, 0xD8F8, 0x4F0A, 0xD2C1, 0x4F0B, 0x81B3, 0x4F0C, 0x81B4, 0x4F0D, 0xCEE9, 0x4F0E, 0xBCBF, 0x4F0F, 0xB7FC, 0x4F10, 0xB7A5, 0x4F11, 0xD0DD, 0x4F12, 0x81B5, 0x4F13, 0x81B6, 0x4F14, 0x81B7, 0x4F15, 0x81B8, 0x4F16, 0x81B9, 0x4F17, 0xD6DA, 0x4F18, 0xD3C5, 0x4F19, 0xBBEF, 0x4F1A, 0xBBE1, 0x4F1B, 0xD8F1, 0x4F1C, 0x81BA, 0x4F1D, 0x81BB, 0x4F1E, 0xC9A1, 0x4F1F, 0xCEB0, 0x4F20, 0xB4AB, 0x4F21, 0x81BC, 0x4F22, 0xD8F3, 0x4F23, 0x81BD, 0x4F24, 0xC9CB, 0x4F25, 0xD8F6, 0x4F26, 0xC2D7, 0x4F27, 0xD8F7, 0x4F28, 0x81BE, 0x4F29, 0x81BF, 0x4F2A, 0xCEB1, 0x4F2B, 0xD8F9, 0x4F2C, 0x81C0, 0x4F2D, 0x81C1, 0x4F2E, 0x81C2, 0x4F2F, 0xB2AE, 0x4F30, 0xB9C0, 0x4F31, 0x81C3, 0x4F32, 0xD9A3, 0x4F33, 0x81C4, 0x4F34, 0xB0E9, 0x4F35, 0x81C5, 0x4F36, 0xC1E6, 0x4F37, 0x81C6, 0x4F38, 0xC9EC, 0x4F39, 0x81C7, 0x4F3A, 0xCBC5, 0x4F3B, 0x81C8, 0x4F3C, 0xCBC6, 0x4F3D, 0xD9A4, 0x4F3E, 0x81C9, 0x4F3F, 0x81CA, 0x4F40, 0x81CB, 0x4F41, 0x81CC, 0x4F42, 0x81CD, 0x4F43, 0xB5E8, 0x4F44, 0x81CE, 0x4F45, 0x81CF, 0x4F46, 0xB5AB, 0x4F47, 0x81D0, 0x4F48, 0x81D1, 0x4F49, 0x81D2, 0x4F4A, 0x81D3, 0x4F4B, 0x81D4, 0x4F4C, 0x81D5, 0x4F4D, 0xCEBB, 0x4F4E, 0xB5CD, 0x4F4F, 0xD7A1, 0x4F50, 0xD7F4, 0x4F51, 0xD3D3, 0x4F52, 0x81D6, 0x4F53, 0xCCE5, 0x4F54, 0x81D7, 0x4F55, 0xBACE, 0x4F56, 0x81D8, 0x4F57, 0xD9A2, 0x4F58, 0xD9DC, 0x4F59, 0xD3E0, 0x4F5A, 0xD8FD, 0x4F5B, 0xB7F0, 0x4F5C, 0xD7F7, 0x4F5D, 0xD8FE, 0x4F5E, 0xD8FA, 0x4F5F, 0xD9A1, 0x4F60, 0xC4E3, 0x4F61, 0x81D9, 0x4F62, 0x81DA, 0x4F63, 0xD3B6, 0x4F64, 0xD8F4, 0x4F65, 0xD9DD, 0x4F66, 0x81DB, 0x4F67, 0xD8FB, 0x4F68, 0x81DC, 0x4F69, 0xC5E5, 0x4F6A, 0x81DD, 0x4F6B, 0x81DE, 0x4F6C, 0xC0D0, 0x4F6D, 0x81DF, 0x4F6E, 0x81E0, 0x4F6F, 0xD1F0, 0x4F70, 0xB0DB, 0x4F71, 0x81E1, 0x4F72, 0x81E2, 0x4F73, 0xBCD1, 0x4F74, 0xD9A6, 0x4F75, 0x81E3, 0x4F76, 0xD9A5, 0x4F77, 0x81E4, 0x4F78, 0x81E5, 0x4F79, 0x81E6, 0x4F7A, 0x81E7, 0x4F7B, 0xD9AC, 0x4F7C, 0xD9AE, 0x4F7D, 0x81E8, 0x4F7E, 0xD9AB, 0x4F7F, 0xCAB9, 0x4F80, 0x81E9, 0x4F81, 0x81EA, 0x4F82, 0x81EB, 0x4F83, 0xD9A9, 0x4F84, 0xD6B6, 0x4F85, 0x81EC, 0x4F86, 0x81ED, 0x4F87, 0x81EE, 0x4F88, 0xB3DE, 0x4F89, 0xD9A8, 0x4F8A, 0x81EF, 0x4F8B, 0xC0FD, 0x4F8C, 0x81F0, 0x4F8D, 0xCACC, 0x4F8E, 0x81F1, 0x4F8F, 0xD9AA, 0x4F90, 0x81F2, 0x4F91, 0xD9A7, 0x4F92, 0x81F3, 0x4F93, 0x81F4, 0x4F94, 0xD9B0, 0x4F95, 0x81F5, 0x4F96, 0x81F6, 0x4F97, 0xB6B1, 0x4F98, 0x81F7, 0x4F99, 0x81F8, 0x4F9A, 0x81F9, 0x4F9B, 0xB9A9, 0x4F9C, 0x81FA, 0x4F9D, 0xD2C0, 0x4F9E, 0x81FB, 0x4F9F, 0x81FC, 0x4FA0, 0xCFC0, 0x4FA1, 0x81FD, 0x4FA2, 0x81FE, 0x4FA3, 0xC2C2, 0x4FA4, 0x8240, 0x4FA5, 0xBDC4, 0x4FA6, 0xD5EC, 0x4FA7, 0xB2E0, 0x4FA8, 0xC7C8, 0x4FA9, 0xBFEB, 0x4FAA, 0xD9AD, 0x4FAB, 0x8241, 0x4FAC, 0xD9AF, 0x4FAD, 0x8242, 0x4FAE, 0xCEEA, 0x4FAF, 0xBAEE, 0x4FB0, 0x8243, 0x4FB1, 0x8244, 0x4FB2, 0x8245, 0x4FB3, 0x8246, 0x4FB4, 0x8247, 0x4FB5, 0xC7D6, 0x4FB6, 0x8248, 0x4FB7, 0x8249, 0x4FB8, 0x824A, 0x4FB9, 0x824B, 0x4FBA, 0x824C, 0x4FBB, 0x824D, 0x4FBC, 0x824E, 0x4FBD, 0x824F, 0x4FBE, 0x8250, 0x4FBF, 0xB1E3, 0x4FC0, 0x8251, 0x4FC1, 0x8252, 0x4FC2, 0x8253, 0x4FC3, 0xB4D9, 0x4FC4, 0xB6ED, 0x4FC5, 0xD9B4, 0x4FC6, 0x8254, 0x4FC7, 0x8255, 0x4FC8, 0x8256, 0x4FC9, 0x8257, 0x4FCA, 0xBFA1, 0x4FCB, 0x8258, 0x4FCC, 0x8259, 0x4FCD, 0x825A, 0x4FCE, 0xD9DE, 0x4FCF, 0xC7CE, 0x4FD0, 0xC0FE, 0x4FD1, 0xD9B8, 0x4FD2, 0x825B, 0x4FD3, 0x825C, 0x4FD4, 0x825D, 0x4FD5, 0x825E, 0x4FD6, 0x825F, 0x4FD7, 0xCBD7, 0x4FD8, 0xB7FD, 0x4FD9, 0x8260, 0x4FDA, 0xD9B5, 0x4FDB, 0x8261, 0x4FDC, 0xD9B7, 0x4FDD, 0xB1A3, 0x4FDE, 0xD3E1, 0x4FDF, 0xD9B9, 0x4FE0, 0x8262, 0x4FE1, 0xD0C5, 0x4FE2, 0x8263, 0x4FE3, 0xD9B6, 0x4FE4, 0x8264, 0x4FE5, 0x8265, 0x4FE6, 0xD9B1, 0x4FE7, 0x8266, 0x4FE8, 0xD9B2, 0x4FE9, 0xC1A9, 0x4FEA, 0xD9B3, 0x4FEB, 0x8267, 0x4FEC, 0x8268, 0x4FED, 0xBCF3, 0x4FEE, 0xD0DE, 0x4FEF, 0xB8A9, 0x4FF0, 0x8269, 0x4FF1, 0xBEE3, 0x4FF2, 0x826A, 0x4FF3, 0xD9BD, 0x4FF4, 0x826B, 0x4FF5, 0x826C, 0x4FF6, 0x826D, 0x4FF7, 0x826E, 0x4FF8, 0xD9BA, 0x4FF9, 0x826F, 0x4FFA, 0xB0B3, 0x4FFB, 0x8270, 0x4FFC, 0x8271, 0x4FFD, 0x8272, 0x4FFE, 0xD9C2, 0x4FFF, 0x8273, 0x5000, 0x8274, 0x5001, 0x8275, 0x5002, 0x8276, 0x5003, 0x8277, 0x5004, 0x8278, 0x5005, 0x8279, 0x5006, 0x827A, 0x5007, 0x827B, 0x5008, 0x827C, 0x5009, 0x827D, 0x500A, 0x827E, 0x500B, 0x8280, 0x500C, 0xD9C4, 0x500D, 0xB1B6, 0x500E, 0x8281, 0x500F, 0xD9BF, 0x5010, 0x8282, 0x5011, 0x8283, 0x5012, 0xB5B9, 0x5013, 0x8284, 0x5014, 0xBEF3, 0x5015, 0x8285, 0x5016, 0x8286, 0x5017, 0x8287, 0x5018, 0xCCC8, 0x5019, 0xBAF2, 0x501A, 0xD2D0, 0x501B, 0x8288, 0x501C, 0xD9C3, 0x501D, 0x8289, 0x501E, 0x828A, 0x501F, 0xBDE8, 0x5020, 0x828B, 0x5021, 0xB3AB, 0x5022, 0x828C, 0x5023, 0x828D, 0x5024, 0x828E, 0x5025, 0xD9C5, 0x5026, 0xBEEB, 0x5027, 0x828F, 0x5028, 0xD9C6, 0x5029, 0xD9BB, 0x502A, 0xC4DF, 0x502B, 0x8290, 0x502C, 0xD9BE, 0x502D, 0xD9C1, 0x502E, 0xD9C0, 0x502F, 0x8291, 0x5030, 0x8292, 0x5031, 0x8293, 0x5032, 0x8294, 0x5033, 0x8295, 0x5034, 0x8296, 0x5035, 0x8297, 0x5036, 0x8298, 0x5037, 0x8299, 0x5038, 0x829A, 0x5039, 0x829B, 0x503A, 0xD5AE, 0x503B, 0x829C, 0x503C, 0xD6B5, 0x503D, 0x829D, 0x503E, 0xC7E3, 0x503F, 0x829E, 0x5040, 0x829F, 0x5041, 0x82A0, 0x5042, 0x82A1, 0x5043, 0xD9C8, 0x5044, 0x82A2, 0x5045, 0x82A3, 0x5046, 0x82A4, 0x5047, 0xBCD9, 0x5048, 0xD9CA, 0x5049, 0x82A5, 0x504A, 0x82A6, 0x504B, 0x82A7, 0x504C, 0xD9BC, 0x504D, 0x82A8, 0x504E, 0xD9CB, 0x504F, 0xC6AB, 0x5050, 0x82A9, 0x5051, 0x82AA, 0x5052, 0x82AB, 0x5053, 0x82AC, 0x5054, 0x82AD, 0x5055, 0xD9C9, 0x5056, 0x82AE, 0x5057, 0x82AF, 0x5058, 0x82B0, 0x5059, 0x82B1, 0x505A, 0xD7F6, 0x505B, 0x82B2, 0x505C, 0xCDA3, 0x505D, 0x82B3, 0x505E, 0x82B4, 0x505F, 0x82B5, 0x5060, 0x82B6, 0x5061, 0x82B7, 0x5062, 0x82B8, 0x5063, 0x82B9, 0x5064, 0x82BA, 0x5065, 0xBDA1, 0x5066, 0x82BB, 0x5067, 0x82BC, 0x5068, 0x82BD, 0x5069, 0x82BE, 0x506A, 0x82BF, 0x506B, 0x82C0, 0x506C, 0xD9CC, 0x506D, 0x82C1, 0x506E, 0x82C2, 0x506F, 0x82C3, 0x5070, 0x82C4, 0x5071, 0x82C5, 0x5072, 0x82C6, 0x5073, 0x82C7, 0x5074, 0x82C8, 0x5075, 0x82C9, 0x5076, 0xC5BC, 0x5077, 0xCDB5, 0x5078, 0x82CA, 0x5079, 0x82CB, 0x507A, 0x82CC, 0x507B, 0xD9CD, 0x507C, 0x82CD, 0x507D, 0x82CE, 0x507E, 0xD9C7, 0x507F, 0xB3A5, 0x5080, 0xBFFE, 0x5081, 0x82CF, 0x5082, 0x82D0, 0x5083, 0x82D1, 0x5084, 0x82D2, 0x5085, 0xB8B5, 0x5086, 0x82D3, 0x5087, 0x82D4, 0x5088, 0xC0FC, 0x5089, 0x82D5, 0x508A, 0x82D6, 0x508B, 0x82D7, 0x508C, 0x82D8, 0x508D, 0xB0F8, 0x508E, 0x82D9, 0x508F, 0x82DA, 0x5090, 0x82DB, 0x5091, 0x82DC, 0x5092, 0x82DD, 0x5093, 0x82DE, 0x5094, 0x82DF, 0x5095, 0x82E0, 0x5096, 0x82E1, 0x5097, 0x82E2, 0x5098, 0x82E3, 0x5099, 0x82E4, 0x509A, 0x82E5, 0x509B, 0x82E6, 0x509C, 0x82E7, 0x509D, 0x82E8, 0x509E, 0x82E9, 0x509F, 0x82EA, 0x50A0, 0x82EB, 0x50A1, 0x82EC, 0x50A2, 0x82ED, 0x50A3, 0xB4F6, 0x50A4, 0x82EE, 0x50A5, 0xD9CE, 0x50A6, 0x82EF, 0x50A7, 0xD9CF, 0x50A8, 0xB4A2, 0x50A9, 0xD9D0, 0x50AA, 0x82F0, 0x50AB, 0x82F1, 0x50AC, 0xB4DF, 0x50AD, 0x82F2, 0x50AE, 0x82F3, 0x50AF, 0x82F4, 0x50B0, 0x82F5, 0x50B1, 0x82F6, 0x50B2, 0xB0C1, 0x50B3, 0x82F7, 0x50B4, 0x82F8, 0x50B5, 0x82F9, 0x50B6, 0x82FA, 0x50B7, 0x82FB, 0x50B8, 0x82FC, 0x50B9, 0x82FD, 0x50BA, 0xD9D1, 0x50BB, 0xC9B5, 0x50BC, 0x82FE, 0x50BD, 0x8340, 0x50BE, 0x8341, 0x50BF, 0x8342, 0x50C0, 0x8343, 0x50C1, 0x8344, 0x50C2, 0x8345, 0x50C3, 0x8346, 0x50C4, 0x8347, 0x50C5, 0x8348, 0x50C6, 0x8349, 0x50C7, 0x834A, 0x50C8, 0x834B, 0x50C9, 0x834C, 0x50CA, 0x834D, 0x50CB, 0x834E, 0x50CC, 0x834F, 0x50CD, 0x8350, 0x50CE, 0x8351, 0x50CF, 0xCFF1, 0x50D0, 0x8352, 0x50D1, 0x8353, 0x50D2, 0x8354, 0x50D3, 0x8355, 0x50D4, 0x8356, 0x50D5, 0x8357, 0x50D6, 0xD9D2, 0x50D7, 0x8358, 0x50D8, 0x8359, 0x50D9, 0x835A, 0x50DA, 0xC1C5, 0x50DB, 0x835B, 0x50DC, 0x835C, 0x50DD, 0x835D, 0x50DE, 0x835E, 0x50DF, 0x835F, 0x50E0, 0x8360, 0x50E1, 0x8361, 0x50E2, 0x8362, 0x50E3, 0x8363, 0x50E4, 0x8364, 0x50E5, 0x8365, 0x50E6, 0xD9D6, 0x50E7, 0xC9AE, 0x50E8, 0x8366, 0x50E9, 0x8367, 0x50EA, 0x8368, 0x50EB, 0x8369, 0x50EC, 0xD9D5, 0x50ED, 0xD9D4, 0x50EE, 0xD9D7, 0x50EF, 0x836A, 0x50F0, 0x836B, 0x50F1, 0x836C, 0x50F2, 0x836D, 0x50F3, 0xCBDB, 0x50F4, 0x836E, 0x50F5, 0xBDA9, 0x50F6, 0x836F, 0x50F7, 0x8370, 0x50F8, 0x8371, 0x50F9, 0x8372, 0x50FA, 0x8373, 0x50FB, 0xC6A7, 0x50FC, 0x8374, 0x50FD, 0x8375, 0x50FE, 0x8376, 0x50FF, 0x8377, 0x5100, 0x8378, 0x5101, 0x8379, 0x5102, 0x837A, 0x5103, 0x837B, 0x5104, 0x837C, 0x5105, 0x837D, 0x5106, 0xD9D3, 0x5107, 0xD9D8, 0x5108, 0x837E, 0x5109, 0x8380, 0x510A, 0x8381, 0x510B, 0xD9D9, 0x510C, 0x8382, 0x510D, 0x8383, 0x510E, 0x8384, 0x510F, 0x8385, 0x5110, 0x8386, 0x5111, 0x8387, 0x5112, 0xC8E5, 0x5113, 0x8388, 0x5114, 0x8389, 0x5115, 0x838A, 0x5116, 0x838B, 0x5117, 0x838C, 0x5118, 0x838D, 0x5119, 0x838E, 0x511A, 0x838F, 0x511B, 0x8390, 0x511C, 0x8391, 0x511D, 0x8392, 0x511E, 0x8393, 0x511F, 0x8394, 0x5120, 0x8395, 0x5121, 0xC0DC, 0x5122, 0x8396, 0x5123, 0x8397, 0x5124, 0x8398, 0x5125, 0x8399, 0x5126, 0x839A, 0x5127, 0x839B, 0x5128, 0x839C, 0x5129, 0x839D, 0x512A, 0x839E, 0x512B, 0x839F, 0x512C, 0x83A0, 0x512D, 0x83A1, 0x512E, 0x83A2, 0x512F, 0x83A3, 0x5130, 0x83A4, 0x5131, 0x83A5, 0x5132, 0x83A6, 0x5133, 0x83A7, 0x5134, 0x83A8, 0x5135, 0x83A9, 0x5136, 0x83AA, 0x5137, 0x83AB, 0x5138, 0x83AC, 0x5139, 0x83AD, 0x513A, 0x83AE, 0x513B, 0x83AF, 0x513C, 0x83B0, 0x513D, 0x83B1, 0x513E, 0x83B2, 0x513F, 0xB6F9, 0x5140, 0xD8A3, 0x5141, 0xD4CA, 0x5142, 0x83B3, 0x5143, 0xD4AA, 0x5144, 0xD0D6, 0x5145, 0xB3E4, 0x5146, 0xD5D7, 0x5147, 0x83B4, 0x5148, 0xCFC8, 0x5149, 0xB9E2, 0x514A, 0x83B5, 0x514B, 0xBFCB, 0x514C, 0x83B6, 0x514D, 0xC3E2, 0x514E, 0x83B7, 0x514F, 0x83B8, 0x5150, 0x83B9, 0x5151, 0xB6D2, 0x5152, 0x83BA, 0x5153, 0x83BB, 0x5154, 0xCDC3, 0x5155, 0xD9EE, 0x5156, 0xD9F0, 0x5157, 0x83BC, 0x5158, 0x83BD, 0x5159, 0x83BE, 0x515A, 0xB5B3, 0x515B, 0x83BF, 0x515C, 0xB6B5, 0x515D, 0x83C0, 0x515E, 0x83C1, 0x515F, 0x83C2, 0x5160, 0x83C3, 0x5161, 0x83C4, 0x5162, 0xBEA4, 0x5163, 0x83C5, 0x5164, 0x83C6, 0x5165, 0xC8EB, 0x5166, 0x83C7, 0x5167, 0x83C8, 0x5168, 0xC8AB, 0x5169, 0x83C9, 0x516A, 0x83CA, 0x516B, 0xB0CB, 0x516C, 0xB9AB, 0x516D, 0xC1F9, 0x516E, 0xD9E2, 0x516F, 0x83CB, 0x5170, 0xC0BC, 0x5171, 0xB9B2, 0x5172, 0x83CC, 0x5173, 0xB9D8, 0x5174, 0xD0CB, 0x5175, 0xB1F8, 0x5176, 0xC6E4, 0x5177, 0xBEDF, 0x5178, 0xB5E4, 0x5179, 0xD7C8, 0x517A, 0x83CD, 0x517B, 0xD1F8, 0x517C, 0xBCE6, 0x517D, 0xCADE, 0x517E, 0x83CE, 0x517F, 0x83CF, 0x5180, 0xBCBD, 0x5181, 0xD9E6, 0x5182, 0xD8E7, 0x5183, 0x83D0, 0x5184, 0x83D1, 0x5185, 0xC4DA, 0x5186, 0x83D2, 0x5187, 0x83D3, 0x5188, 0xB8D4, 0x5189, 0xC8BD, 0x518A, 0x83D4, 0x518B, 0x83D5, 0x518C, 0xB2E1, 0x518D, 0xD4D9, 0x518E, 0x83D6, 0x518F, 0x83D7, 0x5190, 0x83D8, 0x5191, 0x83D9, 0x5192, 0xC3B0, 0x5193, 0x83DA, 0x5194, 0x83DB, 0x5195, 0xC3E1, 0x5196, 0xDAA2, 0x5197, 0xC8DF, 0x5198, 0x83DC, 0x5199, 0xD0B4, 0x519A, 0x83DD, 0x519B, 0xBEFC, 0x519C, 0xC5A9, 0x519D, 0x83DE, 0x519E, 0x83DF, 0x519F, 0x83E0, 0x51A0, 0xB9DA, 0x51A1, 0x83E1, 0x51A2, 0xDAA3, 0x51A3, 0x83E2, 0x51A4, 0xD4A9, 0x51A5, 0xDAA4, 0x51A6, 0x83E3, 0x51A7, 0x83E4, 0x51A8, 0x83E5, 0x51A9, 0x83E6, 0x51AA, 0x83E7, 0x51AB, 0xD9FB, 0x51AC, 0xB6AC, 0x51AD, 0x83E8, 0x51AE, 0x83E9, 0x51AF, 0xB7EB, 0x51B0, 0xB1F9, 0x51B1, 0xD9FC, 0x51B2, 0xB3E5, 0x51B3, 0xBEF6, 0x51B4, 0x83EA, 0x51B5, 0xBFF6, 0x51B6, 0xD2B1, 0x51B7, 0xC0E4, 0x51B8, 0x83EB, 0x51B9, 0x83EC, 0x51BA, 0x83ED, 0x51BB, 0xB6B3, 0x51BC, 0xD9FE, 0x51BD, 0xD9FD, 0x51BE, 0x83EE, 0x51BF, 0x83EF, 0x51C0, 0xBEBB, 0x51C1, 0x83F0, 0x51C2, 0x83F1, 0x51C3, 0x83F2, 0x51C4, 0xC6E0, 0x51C5, 0x83F3, 0x51C6, 0xD7BC, 0x51C7, 0xDAA1, 0x51C8, 0x83F4, 0x51C9, 0xC1B9, 0x51CA, 0x83F5, 0x51CB, 0xB5F2, 0x51CC, 0xC1E8, 0x51CD, 0x83F6, 0x51CE, 0x83F7, 0x51CF, 0xBCF5, 0x51D0, 0x83F8, 0x51D1, 0xB4D5, 0x51D2, 0x83F9, 0x51D3, 0x83FA, 0x51D4, 0x83FB, 0x51D5, 0x83FC, 0x51D6, 0x83FD, 0x51D7, 0x83FE, 0x51D8, 0x8440, 0x51D9, 0x8441, 0x51DA, 0x8442, 0x51DB, 0xC1DD, 0x51DC, 0x8443, 0x51DD, 0xC4FD, 0x51DE, 0x8444, 0x51DF, 0x8445, 0x51E0, 0xBCB8, 0x51E1, 0xB7B2, 0x51E2, 0x8446, 0x51E3, 0x8447, 0x51E4, 0xB7EF, 0x51E5, 0x8448, 0x51E6, 0x8449, 0x51E7, 0x844A, 0x51E8, 0x844B, 0x51E9, 0x844C, 0x51EA, 0x844D, 0x51EB, 0xD9EC, 0x51EC, 0x844E, 0x51ED, 0xC6BE, 0x51EE, 0x844F, 0x51EF, 0xBFAD, 0x51F0, 0xBBCB, 0x51F1, 0x8450, 0x51F2, 0x8451, 0x51F3, 0xB5CA, 0x51F4, 0x8452, 0x51F5, 0xDBC9, 0x51F6, 0xD0D7, 0x51F7, 0x8453, 0x51F8, 0xCDB9, 0x51F9, 0xB0BC, 0x51FA, 0xB3F6, 0x51FB, 0xBBF7, 0x51FC, 0xDBCA, 0x51FD, 0xBAAF, 0x51FE, 0x8454, 0x51FF, 0xD4E4, 0x5200, 0xB5B6, 0x5201, 0xB5F3, 0x5202, 0xD8D6, 0x5203, 0xC8D0, 0x5204, 0x8455, 0x5205, 0x8456, 0x5206, 0xB7D6, 0x5207, 0xC7D0, 0x5208, 0xD8D7, 0x5209, 0x8457, 0x520A, 0xBFAF, 0x520B, 0x8458, 0x520C, 0x8459, 0x520D, 0xDBBB, 0x520E, 0xD8D8, 0x520F, 0x845A, 0x5210, 0x845B, 0x5211, 0xD0CC, 0x5212, 0xBBAE, 0x5213, 0x845C, 0x5214, 0x845D, 0x5215, 0x845E, 0x5216, 0xEBBE, 0x5217, 0xC1D0, 0x5218, 0xC1F5, 0x5219, 0xD4F2, 0x521A, 0xB8D5, 0x521B, 0xB4B4, 0x521C, 0x845F, 0x521D, 0xB3F5, 0x521E, 0x8460, 0x521F, 0x8461, 0x5220, 0xC9BE, 0x5221, 0x8462, 0x5222, 0x8463, 0x5223, 0x8464, 0x5224, 0xC5D0, 0x5225, 0x8465, 0x5226, 0x8466, 0x5227, 0x8467, 0x5228, 0xC5D9, 0x5229, 0xC0FB, 0x522A, 0x8468, 0x522B, 0xB1F0, 0x522C, 0x8469, 0x522D, 0xD8D9, 0x522E, 0xB9CE, 0x522F, 0x846A, 0x5230, 0xB5BD, 0x5231, 0x846B, 0x5232, 0x846C, 0x5233, 0xD8DA, 0x5234, 0x846D, 0x5235, 0x846E, 0x5236, 0xD6C6, 0x5237, 0xCBA2, 0x5238, 0xC8AF, 0x5239, 0xC9B2, 0x523A, 0xB4CC, 0x523B, 0xBFCC, 0x523C, 0x846F, 0x523D, 0xB9F4, 0x523E, 0x8470, 0x523F, 0xD8DB, 0x5240, 0xD8DC, 0x5241, 0xB6E7, 0x5242, 0xBCC1, 0x5243, 0xCCEA, 0x5244, 0x8471, 0x5245, 0x8472, 0x5246, 0x8473, 0x5247, 0x8474, 0x5248, 0x8475, 0x5249, 0x8476, 0x524A, 0xCFF7, 0x524B, 0x8477, 0x524C, 0xD8DD, 0x524D, 0xC7B0, 0x524E, 0x8478, 0x524F, 0x8479, 0x5250, 0xB9D0, 0x5251, 0xBDA3, 0x5252, 0x847A, 0x5253, 0x847B, 0x5254, 0xCCDE, 0x5255, 0x847C, 0x5256, 0xC6CA, 0x5257, 0x847D, 0x5258, 0x847E, 0x5259, 0x8480, 0x525A, 0x8481, 0x525B, 0x8482, 0x525C, 0xD8E0, 0x525D, 0x8483, 0x525E, 0xD8DE, 0x525F, 0x8484, 0x5260, 0x8485, 0x5261, 0xD8DF, 0x5262, 0x8486, 0x5263, 0x8487, 0x5264, 0x8488, 0x5265, 0xB0FE, 0x5266, 0x8489, 0x5267, 0xBEE7, 0x5268, 0x848A, 0x5269, 0xCAA3, 0x526A, 0xBCF4, 0x526B, 0x848B, 0x526C, 0x848C, 0x526D, 0x848D, 0x526E, 0x848E, 0x526F, 0xB8B1, 0x5270, 0x848F, 0x5271, 0x8490, 0x5272, 0xB8EE, 0x5273, 0x8491, 0x5274, 0x8492, 0x5275, 0x8493, 0x5276, 0x8494, 0x5277, 0x8495, 0x5278, 0x8496, 0x5279, 0x8497, 0x527A, 0x8498, 0x527B, 0x8499, 0x527C, 0x849A, 0x527D, 0xD8E2, 0x527E, 0x849B, 0x527F, 0xBDCB, 0x5280, 0x849C, 0x5281, 0xD8E4, 0x5282, 0xD8E3, 0x5283, 0x849D, 0x5284, 0x849E, 0x5285, 0x849F, 0x5286, 0x84A0, 0x5287, 0x84A1, 0x5288, 0xC5FC, 0x5289, 0x84A2, 0x528A, 0x84A3, 0x528B, 0x84A4, 0x528C, 0x84A5, 0x528D, 0x84A6, 0x528E, 0x84A7, 0x528F, 0x84A8, 0x5290, 0xD8E5, 0x5291, 0x84A9, 0x5292, 0x84AA, 0x5293, 0xD8E6, 0x5294, 0x84AB, 0x5295, 0x84AC, 0x5296, 0x84AD, 0x5297, 0x84AE, 0x5298, 0x84AF, 0x5299, 0x84B0, 0x529A, 0x84B1, 0x529B, 0xC1A6, 0x529C, 0x84B2, 0x529D, 0xC8B0, 0x529E, 0xB0EC, 0x529F, 0xB9A6, 0x52A0, 0xBCD3, 0x52A1, 0xCEF1, 0x52A2, 0xDBBD, 0x52A3, 0xC1D3, 0x52A4, 0x84B3, 0x52A5, 0x84B4, 0x52A6, 0x84B5, 0x52A7, 0x84B6, 0x52A8, 0xB6AF, 0x52A9, 0xD6FA, 0x52AA, 0xC5AC, 0x52AB, 0xBDD9, 0x52AC, 0xDBBE, 0x52AD, 0xDBBF, 0x52AE, 0x84B7, 0x52AF, 0x84B8, 0x52B0, 0x84B9, 0x52B1, 0xC0F8, 0x52B2, 0xBEA2, 0x52B3, 0xC0CD, 0x52B4, 0x84BA, 0x52B5, 0x84BB, 0x52B6, 0x84BC, 0x52B7, 0x84BD, 0x52B8, 0x84BE, 0x52B9, 0x84BF, 0x52BA, 0x84C0, 0x52BB, 0x84C1, 0x52BC, 0x84C2, 0x52BD, 0x84C3, 0x52BE, 0xDBC0, 0x52BF, 0xCAC6, 0x52C0, 0x84C4, 0x52C1, 0x84C5, 0x52C2, 0x84C6, 0x52C3, 0xB2AA, 0x52C4, 0x84C7, 0x52C5, 0x84C8, 0x52C6, 0x84C9, 0x52C7, 0xD3C2, 0x52C8, 0x84CA, 0x52C9, 0xC3E3, 0x52CA, 0x84CB, 0x52CB, 0xD1AB, 0x52CC, 0x84CC, 0x52CD, 0x84CD, 0x52CE, 0x84CE, 0x52CF, 0x84CF, 0x52D0, 0xDBC2, 0x52D1, 0x84D0, 0x52D2, 0xC0D5, 0x52D3, 0x84D1, 0x52D4, 0x84D2, 0x52D5, 0x84D3, 0x52D6, 0xDBC3, 0x52D7, 0x84D4, 0x52D8, 0xBFB1, 0x52D9, 0x84D5, 0x52DA, 0x84D6, 0x52DB, 0x84D7, 0x52DC, 0x84D8, 0x52DD, 0x84D9, 0x52DE, 0x84DA, 0x52DF, 0xC4BC, 0x52E0, 0x84DB, 0x52E1, 0x84DC, 0x52E2, 0x84DD, 0x52E3, 0x84DE, 0x52E4, 0xC7DA, 0x52E5, 0x84DF, 0x52E6, 0x84E0, 0x52E7, 0x84E1, 0x52E8, 0x84E2, 0x52E9, 0x84E3, 0x52EA, 0x84E4, 0x52EB, 0x84E5, 0x52EC, 0x84E6, 0x52ED, 0x84E7, 0x52EE, 0x84E8, 0x52EF, 0x84E9, 0x52F0, 0xDBC4, 0x52F1, 0x84EA, 0x52F2, 0x84EB, 0x52F3, 0x84EC, 0x52F4, 0x84ED, 0x52F5, 0x84EE, 0x52F6, 0x84EF, 0x52F7, 0x84F0, 0x52F8, 0x84F1, 0x52F9, 0xD9E8, 0x52FA, 0xC9D7, 0x52FB, 0x84F2, 0x52FC, 0x84F3, 0x52FD, 0x84F4, 0x52FE, 0xB9B4, 0x52FF, 0xCEF0, 0x5300, 0xD4C8, 0x5301, 0x84F5, 0x5302, 0x84F6, 0x5303, 0x84F7, 0x5304, 0x84F8, 0x5305, 0xB0FC, 0x5306, 0xB4D2, 0x5307, 0x84F9, 0x5308, 0xD0D9, 0x5309, 0x84FA, 0x530A, 0x84FB, 0x530B, 0x84FC, 0x530C, 0x84FD, 0x530D, 0xD9E9, 0x530E, 0x84FE, 0x530F, 0xDECB, 0x5310, 0xD9EB, 0x5311, 0x8540, 0x5312, 0x8541, 0x5313, 0x8542, 0x5314, 0x8543, 0x5315, 0xD8B0, 0x5316, 0xBBAF, 0x5317, 0xB1B1, 0x5318, 0x8544, 0x5319, 0xB3D7, 0x531A, 0xD8CE, 0x531B, 0x8545, 0x531C, 0x8546, 0x531D, 0xD4D1, 0x531E, 0x8547, 0x531F, 0x8548, 0x5320, 0xBDB3, 0x5321, 0xBFEF, 0x5322, 0x8549, 0x5323, 0xCFBB, 0x5324, 0x854A, 0x5325, 0x854B, 0x5326, 0xD8D0, 0x5327, 0x854C, 0x5328, 0x854D, 0x5329, 0x854E, 0x532A, 0xB7CB, 0x532B, 0x854F, 0x532C, 0x8550, 0x532D, 0x8551, 0x532E, 0xD8D1, 0x532F, 0x8552, 0x5330, 0x8553, 0x5331, 0x8554, 0x5332, 0x8555, 0x5333, 0x8556, 0x5334, 0x8557, 0x5335, 0x8558, 0x5336, 0x8559, 0x5337, 0x855A, 0x5338, 0x855B, 0x5339, 0xC6A5, 0x533A, 0xC7F8, 0x533B, 0xD2BD, 0x533C, 0x855C, 0x533D, 0x855D, 0x533E, 0xD8D2, 0x533F, 0xC4E4, 0x5340, 0x855E, 0x5341, 0xCAAE, 0x5342, 0x855F, 0x5343, 0xC7A7, 0x5344, 0x8560, 0x5345, 0xD8A6, 0x5346, 0x8561, 0x5347, 0xC9FD, 0x5348, 0xCEE7, 0x5349, 0xBBDC, 0x534A, 0xB0EB, 0x534B, 0x8562, 0x534C, 0x8563, 0x534D, 0x8564, 0x534E, 0xBBAA, 0x534F, 0xD0AD, 0x5350, 0x8565, 0x5351, 0xB1B0, 0x5352, 0xD7E4, 0x5353, 0xD7BF, 0x5354, 0x8566, 0x5355, 0xB5A5, 0x5356, 0xC2F4, 0x5357, 0xC4CF, 0x5358, 0x8567, 0x5359, 0x8568, 0x535A, 0xB2A9, 0x535B, 0x8569, 0x535C, 0xB2B7, 0x535D, 0x856A, 0x535E, 0xB1E5, 0x535F, 0xDFB2, 0x5360, 0xD5BC, 0x5361, 0xBFA8, 0x5362, 0xC2AC, 0x5363, 0xD8D5, 0x5364, 0xC2B1, 0x5365, 0x856B, 0x5366, 0xD8D4, 0x5367, 0xCED4, 0x5368, 0x856C, 0x5369, 0xDAE0, 0x536A, 0x856D, 0x536B, 0xCEC0, 0x536C, 0x856E, 0x536D, 0x856F, 0x536E, 0xD8B4, 0x536F, 0xC3AE, 0x5370, 0xD3A1, 0x5371, 0xCEA3, 0x5372, 0x8570, 0x5373, 0xBCB4, 0x5374, 0xC8B4, 0x5375, 0xC2D1, 0x5376, 0x8571, 0x5377, 0xBEED, 0x5378, 0xD0B6, 0x5379, 0x8572, 0x537A, 0xDAE1, 0x537B, 0x8573, 0x537C, 0x8574, 0x537D, 0x8575, 0x537E, 0x8576, 0x537F, 0xC7E4, 0x5380, 0x8577, 0x5381, 0x8578, 0x5382, 0xB3A7, 0x5383, 0x8579, 0x5384, 0xB6F2, 0x5385, 0xCCFC, 0x5386, 0xC0FA, 0x5387, 0x857A, 0x5388, 0x857B, 0x5389, 0xC0F7, 0x538A, 0x857C, 0x538B, 0xD1B9, 0x538C, 0xD1E1, 0x538D, 0xD8C7, 0x538E, 0x857D, 0x538F, 0x857E, 0x5390, 0x8580, 0x5391, 0x8581, 0x5392, 0x8582, 0x5393, 0x8583, 0x5394, 0x8584, 0x5395, 0xB2DE, 0x5396, 0x8585, 0x5397, 0x8586, 0x5398, 0xC0E5, 0x5399, 0x8587, 0x539A, 0xBAF1, 0x539B, 0x8588, 0x539C, 0x8589, 0x539D, 0xD8C8, 0x539E, 0x858A, 0x539F, 0xD4AD, 0x53A0, 0x858B, 0x53A1, 0x858C, 0x53A2, 0xCFE1, 0x53A3, 0xD8C9, 0x53A4, 0x858D, 0x53A5, 0xD8CA, 0x53A6, 0xCFC3, 0x53A7, 0x858E, 0x53A8, 0xB3F8, 0x53A9, 0xBEC7, 0x53AA, 0x858F, 0x53AB, 0x8590, 0x53AC, 0x8591, 0x53AD, 0x8592, 0x53AE, 0xD8CB, 0x53AF, 0x8593, 0x53B0, 0x8594, 0x53B1, 0x8595, 0x53B2, 0x8596, 0x53B3, 0x8597, 0x53B4, 0x8598, 0x53B5, 0x8599, 0x53B6, 0xDBCC, 0x53B7, 0x859A, 0x53B8, 0x859B, 0x53B9, 0x859C, 0x53BA, 0x859D, 0x53BB, 0xC8A5, 0x53BC, 0x859E, 0x53BD, 0x859F, 0x53BE, 0x85A0, 0x53BF, 0xCFD8, 0x53C0, 0x85A1, 0x53C1, 0xC8FE, 0x53C2, 0xB2CE, 0x53C3, 0x85A2, 0x53C4, 0x85A3, 0x53C5, 0x85A4, 0x53C6, 0x85A5, 0x53C7, 0x85A6, 0x53C8, 0xD3D6, 0x53C9, 0xB2E6, 0x53CA, 0xBCB0, 0x53CB, 0xD3D1, 0x53CC, 0xCBAB, 0x53CD, 0xB7B4, 0x53CE, 0x85A7, 0x53CF, 0x85A8, 0x53D0, 0x85A9, 0x53D1, 0xB7A2, 0x53D2, 0x85AA, 0x53D3, 0x85AB, 0x53D4, 0xCAE5, 0x53D5, 0x85AC, 0x53D6, 0xC8A1, 0x53D7, 0xCADC, 0x53D8, 0xB1E4, 0x53D9, 0xD0F0, 0x53DA, 0x85AD, 0x53DB, 0xC5D1, 0x53DC, 0x85AE, 0x53DD, 0x85AF, 0x53DE, 0x85B0, 0x53DF, 0xDBC5, 0x53E0, 0xB5FE, 0x53E1, 0x85B1, 0x53E2, 0x85B2, 0x53E3, 0xBFDA, 0x53E4, 0xB9C5, 0x53E5, 0xBEE4, 0x53E6, 0xC1ED, 0x53E7, 0x85B3, 0x53E8, 0xDFB6, 0x53E9, 0xDFB5, 0x53EA, 0xD6BB, 0x53EB, 0xBDD0, 0x53EC, 0xD5D9, 0x53ED, 0xB0C8, 0x53EE, 0xB6A3, 0x53EF, 0xBFC9, 0x53F0, 0xCCA8, 0x53F1, 0xDFB3, 0x53F2, 0xCAB7, 0x53F3, 0xD3D2, 0x53F4, 0x85B4, 0x53F5, 0xD8CF, 0x53F6, 0xD2B6, 0x53F7, 0xBAC5, 0x53F8, 0xCBBE, 0x53F9, 0xCCBE, 0x53FA, 0x85B5, 0x53FB, 0xDFB7, 0x53FC, 0xB5F0, 0x53FD, 0xDFB4, 0x53FE, 0x85B6, 0x53FF, 0x85B7, 0x5400, 0x85B8, 0x5401, 0xD3F5, 0x5402, 0x85B9, 0x5403, 0xB3D4, 0x5404, 0xB8F7, 0x5405, 0x85BA, 0x5406, 0xDFBA, 0x5407, 0x85BB, 0x5408, 0xBACF, 0x5409, 0xBCAA, 0x540A, 0xB5F5, 0x540B, 0x85BC, 0x540C, 0xCDAC, 0x540D, 0xC3FB, 0x540E, 0xBAF3, 0x540F, 0xC0F4, 0x5410, 0xCDC2, 0x5411, 0xCFF2, 0x5412, 0xDFB8, 0x5413, 0xCFC5, 0x5414, 0x85BD, 0x5415, 0xC2C0, 0x5416, 0xDFB9, 0x5417, 0xC2F0, 0x5418, 0x85BE, 0x5419, 0x85BF, 0x541A, 0x85C0, 0x541B, 0xBEFD, 0x541C, 0x85C1, 0x541D, 0xC1DF, 0x541E, 0xCDCC, 0x541F, 0xD2F7, 0x5420, 0xB7CD, 0x5421, 0xDFC1, 0x5422, 0x85C2, 0x5423, 0xDFC4, 0x5424, 0x85C3, 0x5425, 0x85C4, 0x5426, 0xB7F1, 0x5427, 0xB0C9, 0x5428, 0xB6D6, 0x5429, 0xB7D4, 0x542A, 0x85C5, 0x542B, 0xBAAC, 0x542C, 0xCCFD, 0x542D, 0xBFD4, 0x542E, 0xCBB1, 0x542F, 0xC6F4, 0x5430, 0x85C6, 0x5431, 0xD6A8, 0x5432, 0xDFC5, 0x5433, 0x85C7, 0x5434, 0xCEE2, 0x5435, 0xB3B3, 0x5436, 0x85C8, 0x5437, 0x85C9, 0x5438, 0xCEFC, 0x5439, 0xB4B5, 0x543A, 0x85CA, 0x543B, 0xCEC7, 0x543C, 0xBAF0, 0x543D, 0x85CB, 0x543E, 0xCEE1, 0x543F, 0x85CC, 0x5440, 0xD1BD, 0x5441, 0x85CD, 0x5442, 0x85CE, 0x5443, 0xDFC0, 0x5444, 0x85CF, 0x5445, 0x85D0, 0x5446, 0xB4F4, 0x5447, 0x85D1, 0x5448, 0xB3CA, 0x5449, 0x85D2, 0x544A, 0xB8E6, 0x544B, 0xDFBB, 0x544C, 0x85D3, 0x544D, 0x85D4, 0x544E, 0x85D5, 0x544F, 0x85D6, 0x5450, 0xC4C5, 0x5451, 0x85D7, 0x5452, 0xDFBC, 0x5453, 0xDFBD, 0x5454, 0xDFBE, 0x5455, 0xC5BB, 0x5456, 0xDFBF, 0x5457, 0xDFC2, 0x5458, 0xD4B1, 0x5459, 0xDFC3, 0x545A, 0x85D8, 0x545B, 0xC7BA, 0x545C, 0xCED8, 0x545D, 0x85D9, 0x545E, 0x85DA, 0x545F, 0x85DB, 0x5460, 0x85DC, 0x5461, 0x85DD, 0x5462, 0xC4D8, 0x5463, 0x85DE, 0x5464, 0xDFCA, 0x5465, 0x85DF, 0x5466, 0xDFCF, 0x5467, 0x85E0, 0x5468, 0xD6DC, 0x5469, 0x85E1, 0x546A, 0x85E2, 0x546B, 0x85E3, 0x546C, 0x85E4, 0x546D, 0x85E5, 0x546E, 0x85E6, 0x546F, 0x85E7, 0x5470, 0x85E8, 0x5471, 0xDFC9, 0x5472, 0xDFDA, 0x5473, 0xCEB6, 0x5474, 0x85E9, 0x5475, 0xBAC7, 0x5476, 0xDFCE, 0x5477, 0xDFC8, 0x5478, 0xC5DE, 0x5479, 0x85EA, 0x547A, 0x85EB, 0x547B, 0xC9EB, 0x547C, 0xBAF4, 0x547D, 0xC3FC, 0x547E, 0x85EC, 0x547F, 0x85ED, 0x5480, 0xBED7, 0x5481, 0x85EE, 0x5482, 0xDFC6, 0x5483, 0x85EF, 0x5484, 0xDFCD, 0x5485, 0x85F0, 0x5486, 0xC5D8, 0x5487, 0x85F1, 0x5488, 0x85F2, 0x5489, 0x85F3, 0x548A, 0x85F4, 0x548B, 0xD5A6, 0x548C, 0xBACD, 0x548D, 0x85F5, 0x548E, 0xBECC, 0x548F, 0xD3BD, 0x5490, 0xB8C0, 0x5491, 0x85F6, 0x5492, 0xD6E4, 0x5493, 0x85F7, 0x5494, 0xDFC7, 0x5495, 0xB9BE, 0x5496, 0xBFA7, 0x5497, 0x85F8, 0x5498, 0x85F9, 0x5499, 0xC1FC, 0x549A, 0xDFCB, 0x549B, 0xDFCC, 0x549C, 0x85FA, 0x549D, 0xDFD0, 0x549E, 0x85FB, 0x549F, 0x85FC, 0x54A0, 0x85FD, 0x54A1, 0x85FE, 0x54A2, 0x8640, 0x54A3, 0xDFDB, 0x54A4, 0xDFE5, 0x54A5, 0x8641, 0x54A6, 0xDFD7, 0x54A7, 0xDFD6, 0x54A8, 0xD7C9, 0x54A9, 0xDFE3, 0x54AA, 0xDFE4, 0x54AB, 0xE5EB, 0x54AC, 0xD2A7, 0x54AD, 0xDFD2, 0x54AE, 0x8642, 0x54AF, 0xBFA9, 0x54B0, 0x8643, 0x54B1, 0xD4DB, 0x54B2, 0x8644, 0x54B3, 0xBFC8, 0x54B4, 0xDFD4, 0x54B5, 0x8645, 0x54B6, 0x8646, 0x54B7, 0x8647, 0x54B8, 0xCFCC, 0x54B9, 0x8648, 0x54BA, 0x8649, 0x54BB, 0xDFDD, 0x54BC, 0x864A, 0x54BD, 0xD1CA, 0x54BE, 0x864B, 0x54BF, 0xDFDE, 0x54C0, 0xB0A7, 0x54C1, 0xC6B7, 0x54C2, 0xDFD3, 0x54C3, 0x864C, 0x54C4, 0xBAE5, 0x54C5, 0x864D, 0x54C6, 0xB6DF, 0x54C7, 0xCDDB, 0x54C8, 0xB9FE, 0x54C9, 0xD4D5, 0x54CA, 0x864E, 0x54CB, 0x864F, 0x54CC, 0xDFDF, 0x54CD, 0xCFEC, 0x54CE, 0xB0A5, 0x54CF, 0xDFE7, 0x54D0, 0xDFD1, 0x54D1, 0xD1C6, 0x54D2, 0xDFD5, 0x54D3, 0xDFD8, 0x54D4, 0xDFD9, 0x54D5, 0xDFDC, 0x54D6, 0x8650, 0x54D7, 0xBBA9, 0x54D8, 0x8651, 0x54D9, 0xDFE0, 0x54DA, 0xDFE1, 0x54DB, 0x8652, 0x54DC, 0xDFE2, 0x54DD, 0xDFE6, 0x54DE, 0xDFE8, 0x54DF, 0xD3B4, 0x54E0, 0x8653, 0x54E1, 0x8654, 0x54E2, 0x8655, 0x54E3, 0x8656, 0x54E4, 0x8657, 0x54E5, 0xB8E7, 0x54E6, 0xC5B6, 0x54E7, 0xDFEA, 0x54E8, 0xC9DA, 0x54E9, 0xC1A8, 0x54EA, 0xC4C4, 0x54EB, 0x8658, 0x54EC, 0x8659, 0x54ED, 0xBFDE, 0x54EE, 0xCFF8, 0x54EF, 0x865A, 0x54F0, 0x865B, 0x54F1, 0x865C, 0x54F2, 0xD5DC, 0x54F3, 0xDFEE, 0x54F4, 0x865D, 0x54F5, 0x865E, 0x54F6, 0x865F, 0x54F7, 0x8660, 0x54F8, 0x8661, 0x54F9, 0x8662, 0x54FA, 0xB2B8, 0x54FB, 0x8663, 0x54FC, 0xBADF, 0x54FD, 0xDFEC, 0x54FE, 0x8664, 0x54FF, 0xDBC1, 0x5500, 0x8665, 0x5501, 0xD1E4, 0x5502, 0x8666, 0x5503, 0x8667, 0x5504, 0x8668, 0x5505, 0x8669, 0x5506, 0xCBF4, 0x5507, 0xB4BD, 0x5508, 0x866A, 0x5509, 0xB0A6, 0x550A, 0x866B, 0x550B, 0x866C, 0x550C, 0x866D, 0x550D, 0x866E, 0x550E, 0x866F, 0x550F, 0xDFF1, 0x5510, 0xCCC6, 0x5511, 0xDFF2, 0x5512, 0x8670, 0x5513, 0x8671, 0x5514, 0xDFED, 0x5515, 0x8672, 0x5516, 0x8673, 0x5517, 0x8674, 0x5518, 0x8675, 0x5519, 0x8676, 0x551A, 0x8677, 0x551B, 0xDFE9, 0x551C, 0x8678, 0x551D, 0x8679, 0x551E, 0x867A, 0x551F, 0x867B, 0x5520, 0xDFEB, 0x5521, 0x867C, 0x5522, 0xDFEF, 0x5523, 0xDFF0, 0x5524, 0xBBBD, 0x5525, 0x867D, 0x5526, 0x867E, 0x5527, 0xDFF3, 0x5528, 0x8680, 0x5529, 0x8681, 0x552A, 0xDFF4, 0x552B, 0x8682, 0x552C, 0xBBA3, 0x552D, 0x8683, 0x552E, 0xCADB, 0x552F, 0xCEA8, 0x5530, 0xE0A7, 0x5531, 0xB3AA, 0x5532, 0x8684, 0x5533, 0xE0A6, 0x5534, 0x8685, 0x5535, 0x8686, 0x5536, 0x8687, 0x5537, 0xE0A1, 0x5538, 0x8688, 0x5539, 0x8689, 0x553A, 0x868A, 0x553B, 0x868B, 0x553C, 0xDFFE, 0x553D, 0x868C, 0x553E, 0xCDD9, 0x553F, 0xDFFC, 0x5540, 0x868D, 0x5541, 0xDFFA, 0x5542, 0x868E, 0x5543, 0xBFD0, 0x5544, 0xD7C4, 0x5545, 0x868F, 0x5546, 0xC9CC, 0x5547, 0x8690, 0x5548, 0x8691, 0x5549, 0xDFF8, 0x554A, 0xB0A1, 0x554B, 0x8692, 0x554C, 0x8693, 0x554D, 0x8694, 0x554E, 0x8695, 0x554F, 0x8696, 0x5550, 0xDFFD, 0x5551, 0x8697, 0x5552, 0x8698, 0x5553, 0x8699, 0x5554, 0x869A, 0x5555, 0xDFFB, 0x5556, 0xE0A2, 0x5557, 0x869B, 0x5558, 0x869C, 0x5559, 0x869D, 0x555A, 0x869E, 0x555B, 0x869F, 0x555C, 0xE0A8, 0x555D, 0x86A0, 0x555E, 0x86A1, 0x555F, 0x86A2, 0x5560, 0x86A3, 0x5561, 0xB7C8, 0x5562, 0x86A4, 0x5563, 0x86A5, 0x5564, 0xC6A1, 0x5565, 0xC9B6, 0x5566, 0xC0B2, 0x5567, 0xDFF5, 0x5568, 0x86A6, 0x5569, 0x86A7, 0x556A, 0xC5BE, 0x556B, 0x86A8, 0x556C, 0xD8C4, 0x556D, 0xDFF9, 0x556E, 0xC4F6, 0x556F, 0x86A9, 0x5570, 0x86AA, 0x5571, 0x86AB, 0x5572, 0x86AC, 0x5573, 0x86AD, 0x5574, 0x86AE, 0x5575, 0xE0A3, 0x5576, 0xE0A4, 0x5577, 0xE0A5, 0x5578, 0xD0A5, 0x5579, 0x86AF, 0x557A, 0x86B0, 0x557B, 0xE0B4, 0x557C, 0xCCE4, 0x557D, 0x86B1, 0x557E, 0xE0B1, 0x557F, 0x86B2, 0x5580, 0xBFA6, 0x5581, 0xE0AF, 0x5582, 0xCEB9, 0x5583, 0xE0AB, 0x5584, 0xC9C6, 0x5585, 0x86B3, 0x5586, 0x86B4, 0x5587, 0xC0AE, 0x5588, 0xE0AE, 0x5589, 0xBAED, 0x558A, 0xBAB0, 0x558B, 0xE0A9, 0x558C, 0x86B5, 0x558D, 0x86B6, 0x558E, 0x86B7, 0x558F, 0xDFF6, 0x5590, 0x86B8, 0x5591, 0xE0B3, 0x5592, 0x86B9, 0x5593, 0x86BA, 0x5594, 0xE0B8, 0x5595, 0x86BB, 0x5596, 0x86BC, 0x5597, 0x86BD, 0x5598, 0xB4AD, 0x5599, 0xE0B9, 0x559A, 0x86BE, 0x559B, 0x86BF, 0x559C, 0xCFB2, 0x559D, 0xBAC8, 0x559E, 0x86C0, 0x559F, 0xE0B0, 0x55A0, 0x86C1, 0x55A1, 0x86C2, 0x55A2, 0x86C3, 0x55A3, 0x86C4, 0x55A4, 0x86C5, 0x55A5, 0x86C6, 0x55A6, 0x86C7, 0x55A7, 0xD0FA, 0x55A8, 0x86C8, 0x55A9, 0x86C9, 0x55AA, 0x86CA, 0x55AB, 0x86CB, 0x55AC, 0x86CC, 0x55AD, 0x86CD, 0x55AE, 0x86CE, 0x55AF, 0x86CF, 0x55B0, 0x86D0, 0x55B1, 0xE0AC, 0x55B2, 0x86D1, 0x55B3, 0xD4FB, 0x55B4, 0x86D2, 0x55B5, 0xDFF7, 0x55B6, 0x86D3, 0x55B7, 0xC5E7, 0x55B8, 0x86D4, 0x55B9, 0xE0AD, 0x55BA, 0x86D5, 0x55BB, 0xD3F7, 0x55BC, 0x86D6, 0x55BD, 0xE0B6, 0x55BE, 0xE0B7, 0x55BF, 0x86D7, 0x55C0, 0x86D8, 0x55C1, 0x86D9, 0x55C2, 0x86DA, 0x55C3, 0x86DB, 0x55C4, 0xE0C4, 0x55C5, 0xD0E1, 0x55C6, 0x86DC, 0x55C7, 0x86DD, 0x55C8, 0x86DE, 0x55C9, 0xE0BC, 0x55CA, 0x86DF, 0x55CB, 0x86E0, 0x55CC, 0xE0C9, 0x55CD, 0xE0CA, 0x55CE, 0x86E1, 0x55CF, 0x86E2, 0x55D0, 0x86E3, 0x55D1, 0xE0BE, 0x55D2, 0xE0AA, 0x55D3, 0xC9A4, 0x55D4, 0xE0C1, 0x55D5, 0x86E4, 0x55D6, 0xE0B2, 0x55D7, 0x86E5, 0x55D8, 0x86E6, 0x55D9, 0x86E7, 0x55DA, 0x86E8, 0x55DB, 0x86E9, 0x55DC, 0xCAC8, 0x55DD, 0xE0C3, 0x55DE, 0x86EA, 0x55DF, 0xE0B5, 0x55E0, 0x86EB, 0x55E1, 0xCECB, 0x55E2, 0x86EC, 0x55E3, 0xCBC3, 0x55E4, 0xE0CD, 0x55E5, 0xE0C6, 0x55E6, 0xE0C2, 0x55E7, 0x86ED, 0x55E8, 0xE0CB, 0x55E9, 0x86EE, 0x55EA, 0xE0BA, 0x55EB, 0xE0BF, 0x55EC, 0xE0C0, 0x55ED, 0x86EF, 0x55EE, 0x86F0, 0x55EF, 0xE0C5, 0x55F0, 0x86F1, 0x55F1, 0x86F2, 0x55F2, 0xE0C7, 0x55F3, 0xE0C8, 0x55F4, 0x86F3, 0x55F5, 0xE0CC, 0x55F6, 0x86F4, 0x55F7, 0xE0BB, 0x55F8, 0x86F5, 0x55F9, 0x86F6, 0x55FA, 0x86F7, 0x55FB, 0x86F8, 0x55FC, 0x86F9, 0x55FD, 0xCBD4, 0x55FE, 0xE0D5, 0x55FF, 0x86FA, 0x5600, 0xE0D6, 0x5601, 0xE0D2, 0x5602, 0x86FB, 0x5603, 0x86FC, 0x5604, 0x86FD, 0x5605, 0x86FE, 0x5606, 0x8740, 0x5607, 0x8741, 0x5608, 0xE0D0, 0x5609, 0xBCCE, 0x560A, 0x8742, 0x560B, 0x8743, 0x560C, 0xE0D1, 0x560D, 0x8744, 0x560E, 0xB8C2, 0x560F, 0xD8C5, 0x5610, 0x8745, 0x5611, 0x8746, 0x5612, 0x8747, 0x5613, 0x8748, 0x5614, 0x8749, 0x5615, 0x874A, 0x5616, 0x874B, 0x5617, 0x874C, 0x5618, 0xD0EA, 0x5619, 0x874D, 0x561A, 0x874E, 0x561B, 0xC2EF, 0x561C, 0x874F, 0x561D, 0x8750, 0x561E, 0xE0CF, 0x561F, 0xE0BD, 0x5620, 0x8751, 0x5621, 0x8752, 0x5622, 0x8753, 0x5623, 0xE0D4, 0x5624, 0xE0D3, 0x5625, 0x8754, 0x5626, 0x8755, 0x5627, 0xE0D7, 0x5628, 0x8756, 0x5629, 0x8757, 0x562A, 0x8758, 0x562B, 0x8759, 0x562C, 0xE0DC, 0x562D, 0xE0D8, 0x562E, 0x875A, 0x562F, 0x875B, 0x5630, 0x875C, 0x5631, 0xD6F6, 0x5632, 0xB3B0, 0x5633, 0x875D, 0x5634, 0xD7EC, 0x5635, 0x875E, 0x5636, 0xCBBB, 0x5637, 0x875F, 0x5638, 0x8760, 0x5639, 0xE0DA, 0x563A, 0x8761, 0x563B, 0xCEFB, 0x563C, 0x8762, 0x563D, 0x8763, 0x563E, 0x8764, 0x563F, 0xBAD9, 0x5640, 0x8765, 0x5641, 0x8766, 0x5642, 0x8767, 0x5643, 0x8768, 0x5644, 0x8769, 0x5645, 0x876A, 0x5646, 0x876B, 0x5647, 0x876C, 0x5648, 0x876D, 0x5649, 0x876E, 0x564A, 0x876F, 0x564B, 0x8770, 0x564C, 0xE0E1, 0x564D, 0xE0DD, 0x564E, 0xD2AD, 0x564F, 0x8771, 0x5650, 0x8772, 0x5651, 0x8773, 0x5652, 0x8774, 0x5653, 0x8775, 0x5654, 0xE0E2, 0x5655, 0x8776, 0x5656, 0x8777, 0x5657, 0xE0DB, 0x5658, 0xE0D9, 0x5659, 0xE0DF, 0x565A, 0x8778, 0x565B, 0x8779, 0x565C, 0xE0E0, 0x565D, 0x877A, 0x565E, 0x877B, 0x565F, 0x877C, 0x5660, 0x877D, 0x5661, 0x877E, 0x5662, 0xE0DE, 0x5663, 0x8780, 0x5664, 0xE0E4, 0x5665, 0x8781, 0x5666, 0x8782, 0x5667, 0x8783, 0x5668, 0xC6F7, 0x5669, 0xD8AC, 0x566A, 0xD4EB, 0x566B, 0xE0E6, 0x566C, 0xCAC9, 0x566D, 0x8784, 0x566E, 0x8785, 0x566F, 0x8786, 0x5670, 0x8787, 0x5671, 0xE0E5, 0x5672, 0x8788, 0x5673, 0x8789, 0x5674, 0x878A, 0x5675, 0x878B, 0x5676, 0xB8C1, 0x5677, 0x878C, 0x5678, 0x878D, 0x5679, 0x878E, 0x567A, 0x878F, 0x567B, 0xE0E7, 0x567C, 0xE0E8, 0x567D, 0x8790, 0x567E, 0x8791, 0x567F, 0x8792, 0x5680, 0x8793, 0x5681, 0x8794, 0x5682, 0x8795, 0x5683, 0x8796, 0x5684, 0x8797, 0x5685, 0xE0E9, 0x5686, 0xE0E3, 0x5687, 0x8798, 0x5688, 0x8799, 0x5689, 0x879A, 0x568A, 0x879B, 0x568B, 0x879C, 0x568C, 0x879D, 0x568D, 0x879E, 0x568E, 0xBABF, 0x568F, 0xCCE7, 0x5690, 0x879F, 0x5691, 0x87A0, 0x5692, 0x87A1, 0x5693, 0xE0EA, 0x5694, 0x87A2, 0x5695, 0x87A3, 0x5696, 0x87A4, 0x5697, 0x87A5, 0x5698, 0x87A6, 0x5699, 0x87A7, 0x569A, 0x87A8, 0x569B, 0x87A9, 0x569C, 0x87AA, 0x569D, 0x87AB, 0x569E, 0x87AC, 0x569F, 0x87AD, 0x56A0, 0x87AE, 0x56A1, 0x87AF, 0x56A2, 0x87B0, 0x56A3, 0xCFF9, 0x56A4, 0x87B1, 0x56A5, 0x87B2, 0x56A6, 0x87B3, 0x56A7, 0x87B4, 0x56A8, 0x87B5, 0x56A9, 0x87B6, 0x56AA, 0x87B7, 0x56AB, 0x87B8, 0x56AC, 0x87B9, 0x56AD, 0x87BA, 0x56AE, 0x87BB, 0x56AF, 0xE0EB, 0x56B0, 0x87BC, 0x56B1, 0x87BD, 0x56B2, 0x87BE, 0x56B3, 0x87BF, 0x56B4, 0x87C0, 0x56B5, 0x87C1, 0x56B6, 0x87C2, 0x56B7, 0xC8C2, 0x56B8, 0x87C3, 0x56B9, 0x87C4, 0x56BA, 0x87C5, 0x56BB, 0x87C6, 0x56BC, 0xBDC0, 0x56BD, 0x87C7, 0x56BE, 0x87C8, 0x56BF, 0x87C9, 0x56C0, 0x87CA, 0x56C1, 0x87CB, 0x56C2, 0x87CC, 0x56C3, 0x87CD, 0x56C4, 0x87CE, 0x56C5, 0x87CF, 0x56C6, 0x87D0, 0x56C7, 0x87D1, 0x56C8, 0x87D2, 0x56C9, 0x87D3, 0x56CA, 0xC4D2, 0x56CB, 0x87D4, 0x56CC, 0x87D5, 0x56CD, 0x87D6, 0x56CE, 0x87D7, 0x56CF, 0x87D8, 0x56D0, 0x87D9, 0x56D1, 0x87DA, 0x56D2, 0x87DB, 0x56D3, 0x87DC, 0x56D4, 0xE0EC, 0x56D5, 0x87DD, 0x56D6, 0x87DE, 0x56D7, 0xE0ED, 0x56D8, 0x87DF, 0x56D9, 0x87E0, 0x56DA, 0xC7F4, 0x56DB, 0xCBC4, 0x56DC, 0x87E1, 0x56DD, 0xE0EE, 0x56DE, 0xBBD8, 0x56DF, 0xD8B6, 0x56E0, 0xD2F2, 0x56E1, 0xE0EF, 0x56E2, 0xCDC5, 0x56E3, 0x87E2, 0x56E4, 0xB6DA, 0x56E5, 0x87E3, 0x56E6, 0x87E4, 0x56E7, 0x87E5, 0x56E8, 0x87E6, 0x56E9, 0x87E7, 0x56EA, 0x87E8, 0x56EB, 0xE0F1, 0x56EC, 0x87E9, 0x56ED, 0xD4B0, 0x56EE, 0x87EA, 0x56EF, 0x87EB, 0x56F0, 0xC0A7, 0x56F1, 0xB4D1, 0x56F2, 0x87EC, 0x56F3, 0x87ED, 0x56F4, 0xCEA7, 0x56F5, 0xE0F0, 0x56F6, 0x87EE, 0x56F7, 0x87EF, 0x56F8, 0x87F0, 0x56F9, 0xE0F2, 0x56FA, 0xB9CC, 0x56FB, 0x87F1, 0x56FC, 0x87F2, 0x56FD, 0xB9FA, 0x56FE, 0xCDBC, 0x56FF, 0xE0F3, 0x5700, 0x87F3, 0x5701, 0x87F4, 0x5702, 0x87F5, 0x5703, 0xC6D4, 0x5704, 0xE0F4, 0x5705, 0x87F6, 0x5706, 0xD4B2, 0x5707, 0x87F7, 0x5708, 0xC8A6, 0x5709, 0xE0F6, 0x570A, 0xE0F5, 0x570B, 0x87F8, 0x570C, 0x87F9, 0x570D, 0x87FA, 0x570E, 0x87FB, 0x570F, 0x87FC, 0x5710, 0x87FD, 0x5711, 0x87FE, 0x5712, 0x8840, 0x5713, 0x8841, 0x5714, 0x8842, 0x5715, 0x8843, 0x5716, 0x8844, 0x5717, 0x8845, 0x5718, 0x8846, 0x5719, 0x8847, 0x571A, 0x8848, 0x571B, 0x8849, 0x571C, 0xE0F7, 0x571D, 0x884A, 0x571E, 0x884B, 0x571F, 0xCDC1, 0x5720, 0x884C, 0x5721, 0x884D, 0x5722, 0x884E, 0x5723, 0xCAA5, 0x5724, 0x884F, 0x5725, 0x8850, 0x5726, 0x8851, 0x5727, 0x8852, 0x5728, 0xD4DA, 0x5729, 0xDBD7, 0x572A, 0xDBD9, 0x572B, 0x8853, 0x572C, 0xDBD8, 0x572D, 0xB9E7, 0x572E, 0xDBDC, 0x572F, 0xDBDD, 0x5730, 0xB5D8, 0x5731, 0x8854, 0x5732, 0x8855, 0x5733, 0xDBDA, 0x5734, 0x8856, 0x5735, 0x8857, 0x5736, 0x8858, 0x5737, 0x8859, 0x5738, 0x885A, 0x5739, 0xDBDB, 0x573A, 0xB3A1, 0x573B, 0xDBDF, 0x573C, 0x885B, 0x573D, 0x885C, 0x573E, 0xBBF8, 0x573F, 0x885D, 0x5740, 0xD6B7, 0x5741, 0x885E, 0x5742, 0xDBE0, 0x5743, 0x885F, 0x5744, 0x8860, 0x5745, 0x8861, 0x5746, 0x8862, 0x5747, 0xBEF9, 0x5748, 0x8863, 0x5749, 0x8864, 0x574A, 0xB7BB, 0x574B, 0x8865, 0x574C, 0xDBD0, 0x574D, 0xCCAE, 0x574E, 0xBFB2, 0x574F, 0xBBB5, 0x5750, 0xD7F8, 0x5751, 0xBFD3, 0x5752, 0x8866, 0x5753, 0x8867, 0x5754, 0x8868, 0x5755, 0x8869, 0x5756, 0x886A, 0x5757, 0xBFE9, 0x5758, 0x886B, 0x5759, 0x886C, 0x575A, 0xBCE1, 0x575B, 0xCCB3, 0x575C, 0xDBDE, 0x575D, 0xB0D3, 0x575E, 0xCEEB, 0x575F, 0xB7D8, 0x5760, 0xD7B9, 0x5761, 0xC6C2, 0x5762, 0x886D, 0x5763, 0x886E, 0x5764, 0xC0A4, 0x5765, 0x886F, 0x5766, 0xCCB9, 0x5767, 0x8870, 0x5768, 0xDBE7, 0x5769, 0xDBE1, 0x576A, 0xC6BA, 0x576B, 0xDBE3, 0x576C, 0x8871, 0x576D, 0xDBE8, 0x576E, 0x8872, 0x576F, 0xC5F7, 0x5770, 0x8873, 0x5771, 0x8874, 0x5772, 0x8875, 0x5773, 0xDBEA, 0x5774, 0x8876, 0x5775, 0x8877, 0x5776, 0xDBE9, 0x5777, 0xBFC0, 0x5778, 0x8878, 0x5779, 0x8879, 0x577A, 0x887A, 0x577B, 0xDBE6, 0x577C, 0xDBE5, 0x577D, 0x887B, 0x577E, 0x887C, 0x577F, 0x887D, 0x5780, 0x887E, 0x5781, 0x8880, 0x5782, 0xB4B9, 0x5783, 0xC0AC, 0x5784, 0xC2A2, 0x5785, 0xDBE2, 0x5786, 0xDBE4, 0x5787, 0x8881, 0x5788, 0x8882, 0x5789, 0x8883, 0x578A, 0x8884, 0x578B, 0xD0CD, 0x578C, 0xDBED, 0x578D, 0x8885, 0x578E, 0x8886, 0x578F, 0x8887, 0x5790, 0x8888, 0x5791, 0x8889, 0x5792, 0xC0DD, 0x5793, 0xDBF2, 0x5794, 0x888A, 0x5795, 0x888B, 0x5796, 0x888C, 0x5797, 0x888D, 0x5798, 0x888E, 0x5799, 0x888F, 0x579A, 0x8890, 0x579B, 0xB6E2, 0x579C, 0x8891, 0x579D, 0x8892, 0x579E, 0x8893, 0x579F, 0x8894, 0x57A0, 0xDBF3, 0x57A1, 0xDBD2, 0x57A2, 0xB9B8, 0x57A3, 0xD4AB, 0x57A4, 0xDBEC, 0x57A5, 0x8895, 0x57A6, 0xBFD1, 0x57A7, 0xDBF0, 0x57A8, 0x8896, 0x57A9, 0xDBD1, 0x57AA, 0x8897, 0x57AB, 0xB5E6, 0x57AC, 0x8898, 0x57AD, 0xDBEB, 0x57AE, 0xBFE5, 0x57AF, 0x8899, 0x57B0, 0x889A, 0x57B1, 0x889B, 0x57B2, 0xDBEE, 0x57B3, 0x889C, 0x57B4, 0xDBF1, 0x57B5, 0x889D, 0x57B6, 0x889E, 0x57B7, 0x889F, 0x57B8, 0xDBF9, 0x57B9, 0x88A0, 0x57BA, 0x88A1, 0x57BB, 0x88A2, 0x57BC, 0x88A3, 0x57BD, 0x88A4, 0x57BE, 0x88A5, 0x57BF, 0x88A6, 0x57C0, 0x88A7, 0x57C1, 0x88A8, 0x57C2, 0xB9A1, 0x57C3, 0xB0A3, 0x57C4, 0x88A9, 0x57C5, 0x88AA, 0x57C6, 0x88AB, 0x57C7, 0x88AC, 0x57C8, 0x88AD, 0x57C9, 0x88AE, 0x57CA, 0x88AF, 0x57CB, 0xC2F1, 0x57CC, 0x88B0, 0x57CD, 0x88B1, 0x57CE, 0xB3C7, 0x57CF, 0xDBEF, 0x57D0, 0x88B2, 0x57D1, 0x88B3, 0x57D2, 0xDBF8, 0x57D3, 0x88B4, 0x57D4, 0xC6D2, 0x57D5, 0xDBF4, 0x57D6, 0x88B5, 0x57D7, 0x88B6, 0x57D8, 0xDBF5, 0x57D9, 0xDBF7, 0x57DA, 0xDBF6, 0x57DB, 0x88B7, 0x57DC, 0x88B8, 0x57DD, 0xDBFE, 0x57DE, 0x88B9, 0x57DF, 0xD3F2, 0x57E0, 0xB2BA, 0x57E1, 0x88BA, 0x57E2, 0x88BB, 0x57E3, 0x88BC, 0x57E4, 0xDBFD, 0x57E5, 0x88BD, 0x57E6, 0x88BE, 0x57E7, 0x88BF, 0x57E8, 0x88C0, 0x57E9, 0x88C1, 0x57EA, 0x88C2, 0x57EB, 0x88C3, 0x57EC, 0x88C4, 0x57ED, 0xDCA4, 0x57EE, 0x88C5, 0x57EF, 0xDBFB, 0x57F0, 0x88C6, 0x57F1, 0x88C7, 0x57F2, 0x88C8, 0x57F3, 0x88C9, 0x57F4, 0xDBFA, 0x57F5, 0x88CA, 0x57F6, 0x88CB, 0x57F7, 0x88CC, 0x57F8, 0xDBFC, 0x57F9, 0xC5E0, 0x57FA, 0xBBF9, 0x57FB, 0x88CD, 0x57FC, 0x88CE, 0x57FD, 0xDCA3, 0x57FE, 0x88CF, 0x57FF, 0x88D0, 0x5800, 0xDCA5, 0x5801, 0x88D1, 0x5802, 0xCCC3, 0x5803, 0x88D2, 0x5804, 0x88D3, 0x5805, 0x88D4, 0x5806, 0xB6D1, 0x5807, 0xDDC0, 0x5808, 0x88D5, 0x5809, 0x88D6, 0x580A, 0x88D7, 0x580B, 0xDCA1, 0x580C, 0x88D8, 0x580D, 0xDCA2, 0x580E, 0x88D9, 0x580F, 0x88DA, 0x5810, 0x88DB, 0x5811, 0xC7B5, 0x5812, 0x88DC, 0x5813, 0x88DD, 0x5814, 0x88DE, 0x5815, 0xB6E9, 0x5816, 0x88DF, 0x5817, 0x88E0, 0x5818, 0x88E1, 0x5819, 0xDCA7, 0x581A, 0x88E2, 0x581B, 0x88E3, 0x581C, 0x88E4, 0x581D, 0x88E5, 0x581E, 0xDCA6, 0x581F, 0x88E6, 0x5820, 0xDCA9, 0x5821, 0xB1A4, 0x5822, 0x88E7, 0x5823, 0x88E8, 0x5824, 0xB5CC, 0x5825, 0x88E9, 0x5826, 0x88EA, 0x5827, 0x88EB, 0x5828, 0x88EC, 0x5829, 0x88ED, 0x582A, 0xBFB0, 0x582B, 0x88EE, 0x582C, 0x88EF, 0x582D, 0x88F0, 0x582E, 0x88F1, 0x582F, 0x88F2, 0x5830, 0xD1DF, 0x5831, 0x88F3, 0x5832, 0x88F4, 0x5833, 0x88F5, 0x5834, 0x88F6, 0x5835, 0xB6C2, 0x5836, 0x88F7, 0x5837, 0x88F8, 0x5838, 0x88F9, 0x5839, 0x88FA, 0x583A, 0x88FB, 0x583B, 0x88FC, 0x583C, 0x88FD, 0x583D, 0x88FE, 0x583E, 0x8940, 0x583F, 0x8941, 0x5840, 0x8942, 0x5841, 0x8943, 0x5842, 0x8944, 0x5843, 0x8945, 0x5844, 0xDCA8, 0x5845, 0x8946, 0x5846, 0x8947, 0x5847, 0x8948, 0x5848, 0x8949, 0x5849, 0x894A, 0x584A, 0x894B, 0x584B, 0x894C, 0x584C, 0xCBFA, 0x584D, 0xEBF3, 0x584E, 0x894D, 0x584F, 0x894E, 0x5850, 0x894F, 0x5851, 0xCBDC, 0x5852, 0x8950, 0x5853, 0x8951, 0x5854, 0xCBFE, 0x5855, 0x8952, 0x5856, 0x8953, 0x5857, 0x8954, 0x5858, 0xCCC1, 0x5859, 0x8955, 0x585A, 0x8956, 0x585B, 0x8957, 0x585C, 0x8958, 0x585D, 0x8959, 0x585E, 0xC8FB, 0x585F, 0x895A, 0x5860, 0x895B, 0x5861, 0x895C, 0x5862, 0x895D, 0x5863, 0x895E, 0x5864, 0x895F, 0x5865, 0xDCAA, 0x5866, 0x8960, 0x5867, 0x8961, 0x5868, 0x8962, 0x5869, 0x8963, 0x586A, 0x8964, 0x586B, 0xCCEE, 0x586C, 0xDCAB, 0x586D, 0x8965, 0x586E, 0x8966, 0x586F, 0x8967, 0x5870, 0x8968, 0x5871, 0x8969, 0x5872, 0x896A, 0x5873, 0x896B, 0x5874, 0x896C, 0x5875, 0x896D, 0x5876, 0x896E, 0x5877, 0x896F, 0x5878, 0x8970, 0x5879, 0x8971, 0x587A, 0x8972, 0x587B, 0x8973, 0x587C, 0x8974, 0x587D, 0x8975, 0x587E, 0xDBD3, 0x587F, 0x8976, 0x5880, 0xDCAF, 0x5881, 0xDCAC, 0x5882, 0x8977, 0x5883, 0xBEB3, 0x5884, 0x8978, 0x5885, 0xCAFB, 0x5886, 0x8979, 0x5887, 0x897A, 0x5888, 0x897B, 0x5889, 0xDCAD, 0x588A, 0x897C, 0x588B, 0x897D, 0x588C, 0x897E, 0x588D, 0x8980, 0x588E, 0x8981, 0x588F, 0x8982, 0x5890, 0x8983, 0x5891, 0x8984, 0x5892, 0xC9CA, 0x5893, 0xC4B9, 0x5894, 0x8985, 0x5895, 0x8986, 0x5896, 0x8987, 0x5897, 0x8988, 0x5898, 0x8989, 0x5899, 0xC7BD, 0x589A, 0xDCAE, 0x589B, 0x898A, 0x589C, 0x898B, 0x589D, 0x898C, 0x589E, 0xD4F6, 0x589F, 0xD0E6, 0x58A0, 0x898D, 0x58A1, 0x898E, 0x58A2, 0x898F, 0x58A3, 0x8990, 0x58A4, 0x8991, 0x58A5, 0x8992, 0x58A6, 0x8993, 0x58A7, 0x8994, 0x58A8, 0xC4AB, 0x58A9, 0xB6D5, 0x58AA, 0x8995, 0x58AB, 0x8996, 0x58AC, 0x8997, 0x58AD, 0x8998, 0x58AE, 0x8999, 0x58AF, 0x899A, 0x58B0, 0x899B, 0x58B1, 0x899C, 0x58B2, 0x899D, 0x58B3, 0x899E, 0x58B4, 0x899F, 0x58B5, 0x89A0, 0x58B6, 0x89A1, 0x58B7, 0x89A2, 0x58B8, 0x89A3, 0x58B9, 0x89A4, 0x58BA, 0x89A5, 0x58BB, 0x89A6, 0x58BC, 0xDBD4, 0x58BD, 0x89A7, 0x58BE, 0x89A8, 0x58BF, 0x89A9, 0x58C0, 0x89AA, 0x58C1, 0xB1DA, 0x58C2, 0x89AB, 0x58C3, 0x89AC, 0x58C4, 0x89AD, 0x58C5, 0xDBD5, 0x58C6, 0x89AE, 0x58C7, 0x89AF, 0x58C8, 0x89B0, 0x58C9, 0x89B1, 0x58CA, 0x89B2, 0x58CB, 0x89B3, 0x58CC, 0x89B4, 0x58CD, 0x89B5, 0x58CE, 0x89B6, 0x58CF, 0x89B7, 0x58D0, 0x89B8, 0x58D1, 0xDBD6, 0x58D2, 0x89B9, 0x58D3, 0x89BA, 0x58D4, 0x89BB, 0x58D5, 0xBABE, 0x58D6, 0x89BC, 0x58D7, 0x89BD, 0x58D8, 0x89BE, 0x58D9, 0x89BF, 0x58DA, 0x89C0, 0x58DB, 0x89C1, 0x58DC, 0x89C2, 0x58DD, 0x89C3, 0x58DE, 0x89C4, 0x58DF, 0x89C5, 0x58E0, 0x89C6, 0x58E1, 0x89C7, 0x58E2, 0x89C8, 0x58E3, 0x89C9, 0x58E4, 0xC8C0, 0x58E5, 0x89CA, 0x58E6, 0x89CB, 0x58E7, 0x89CC, 0x58E8, 0x89CD, 0x58E9, 0x89CE, 0x58EA, 0x89CF, 0x58EB, 0xCABF, 0x58EC, 0xC8C9, 0x58ED, 0x89D0, 0x58EE, 0xD7B3, 0x58EF, 0x89D1, 0x58F0, 0xC9F9, 0x58F1, 0x89D2, 0x58F2, 0x89D3, 0x58F3, 0xBFC7, 0x58F4, 0x89D4, 0x58F5, 0x89D5, 0x58F6, 0xBAF8, 0x58F7, 0x89D6, 0x58F8, 0x89D7, 0x58F9, 0xD2BC, 0x58FA, 0x89D8, 0x58FB, 0x89D9, 0x58FC, 0x89DA, 0x58FD, 0x89DB, 0x58FE, 0x89DC, 0x58FF, 0x89DD, 0x5900, 0x89DE, 0x5901, 0x89DF, 0x5902, 0xE2BA, 0x5903, 0x89E0, 0x5904, 0xB4A6, 0x5905, 0x89E1, 0x5906, 0x89E2, 0x5907, 0xB1B8, 0x5908, 0x89E3, 0x5909, 0x89E4, 0x590A, 0x89E5, 0x590B, 0x89E6, 0x590C, 0x89E7, 0x590D, 0xB8B4, 0x590E, 0x89E8, 0x590F, 0xCFC4, 0x5910, 0x89E9, 0x5911, 0x89EA, 0x5912, 0x89EB, 0x5913, 0x89EC, 0x5914, 0xD9E7, 0x5915, 0xCFA6, 0x5916, 0xCDE2, 0x5917, 0x89ED, 0x5918, 0x89EE, 0x5919, 0xD9ED, 0x591A, 0xB6E0, 0x591B, 0x89EF, 0x591C, 0xD2B9, 0x591D, 0x89F0, 0x591E, 0x89F1, 0x591F, 0xB9BB, 0x5920, 0x89F2, 0x5921, 0x89F3, 0x5922, 0x89F4, 0x5923, 0x89F5, 0x5924, 0xE2B9, 0x5925, 0xE2B7, 0x5926, 0x89F6, 0x5927, 0xB4F3, 0x5928, 0x89F7, 0x5929, 0xCCEC, 0x592A, 0xCCAB, 0x592B, 0xB7F2, 0x592C, 0x89F8, 0x592D, 0xD8B2, 0x592E, 0xD1EB, 0x592F, 0xBABB, 0x5930, 0x89F9, 0x5931, 0xCAA7, 0x5932, 0x89FA, 0x5933, 0x89FB, 0x5934, 0xCDB7, 0x5935, 0x89FC, 0x5936, 0x89FD, 0x5937, 0xD2C4, 0x5938, 0xBFE4, 0x5939, 0xBCD0, 0x593A, 0xB6E1, 0x593B, 0x89FE, 0x593C, 0xDEC5, 0x593D, 0x8A40, 0x593E, 0x8A41, 0x593F, 0x8A42, 0x5940, 0x8A43, 0x5941, 0xDEC6, 0x5942, 0xDBBC, 0x5943, 0x8A44, 0x5944, 0xD1D9, 0x5945, 0x8A45, 0x5946, 0x8A46, 0x5947, 0xC6E6, 0x5948, 0xC4CE, 0x5949, 0xB7EE, 0x594A, 0x8A47, 0x594B, 0xB7DC, 0x594C, 0x8A48, 0x594D, 0x8A49, 0x594E, 0xBFFC, 0x594F, 0xD7E0, 0x5950, 0x8A4A, 0x5951, 0xC6F5, 0x5952, 0x8A4B, 0x5953, 0x8A4C, 0x5954, 0xB1BC, 0x5955, 0xDEC8, 0x5956, 0xBDB1, 0x5957, 0xCCD7, 0x5958, 0xDECA, 0x5959, 0x8A4D, 0x595A, 0xDEC9, 0x595B, 0x8A4E, 0x595C, 0x8A4F, 0x595D, 0x8A50, 0x595E, 0x8A51, 0x595F, 0x8A52, 0x5960, 0xB5EC, 0x5961, 0x8A53, 0x5962, 0xC9DD, 0x5963, 0x8A54, 0x5964, 0x8A55, 0x5965, 0xB0C2, 0x5966, 0x8A56, 0x5967, 0x8A57, 0x5968, 0x8A58, 0x5969, 0x8A59, 0x596A, 0x8A5A, 0x596B, 0x8A5B, 0x596C, 0x8A5C, 0x596D, 0x8A5D, 0x596E, 0x8A5E, 0x596F, 0x8A5F, 0x5970, 0x8A60, 0x5971, 0x8A61, 0x5972, 0x8A62, 0x5973, 0xC5AE, 0x5974, 0xC5AB, 0x5975, 0x8A63, 0x5976, 0xC4CC, 0x5977, 0x8A64, 0x5978, 0xBCE9, 0x5979, 0xCBFD, 0x597A, 0x8A65, 0x597B, 0x8A66, 0x597C, 0x8A67, 0x597D, 0xBAC3, 0x597E, 0x8A68, 0x597F, 0x8A69, 0x5980, 0x8A6A, 0x5981, 0xE5F9, 0x5982, 0xC8E7, 0x5983, 0xE5FA, 0x5984, 0xCDFD, 0x5985, 0x8A6B, 0x5986, 0xD7B1, 0x5987, 0xB8BE, 0x5988, 0xC2E8, 0x5989, 0x8A6C, 0x598A, 0xC8D1, 0x598B, 0x8A6D, 0x598C, 0x8A6E, 0x598D, 0xE5FB, 0x598E, 0x8A6F, 0x598F, 0x8A70, 0x5990, 0x8A71, 0x5991, 0x8A72, 0x5992, 0xB6CA, 0x5993, 0xBCCB, 0x5994, 0x8A73, 0x5995, 0x8A74, 0x5996, 0xD1FD, 0x5997, 0xE6A1, 0x5998, 0x8A75, 0x5999, 0xC3EE, 0x599A, 0x8A76, 0x599B, 0x8A77, 0x599C, 0x8A78, 0x599D, 0x8A79, 0x599E, 0xE6A4, 0x599F, 0x8A7A, 0x59A0, 0x8A7B, 0x59A1, 0x8A7C, 0x59A2, 0x8A7D, 0x59A3, 0xE5FE, 0x59A4, 0xE6A5, 0x59A5, 0xCDD7, 0x59A6, 0x8A7E, 0x59A7, 0x8A80, 0x59A8, 0xB7C1, 0x59A9, 0xE5FC, 0x59AA, 0xE5FD, 0x59AB, 0xE6A3, 0x59AC, 0x8A81, 0x59AD, 0x8A82, 0x59AE, 0xC4DD, 0x59AF, 0xE6A8, 0x59B0, 0x8A83, 0x59B1, 0x8A84, 0x59B2, 0xE6A7, 0x59B3, 0x8A85, 0x59B4, 0x8A86, 0x59B5, 0x8A87, 0x59B6, 0x8A88, 0x59B7, 0x8A89, 0x59B8, 0x8A8A, 0x59B9, 0xC3C3, 0x59BA, 0x8A8B, 0x59BB, 0xC6DE, 0x59BC, 0x8A8C, 0x59BD, 0x8A8D, 0x59BE, 0xE6AA, 0x59BF, 0x8A8E, 0x59C0, 0x8A8F, 0x59C1, 0x8A90, 0x59C2, 0x8A91, 0x59C3, 0x8A92, 0x59C4, 0x8A93, 0x59C5, 0x8A94, 0x59C6, 0xC4B7, 0x59C7, 0x8A95, 0x59C8, 0x8A96, 0x59C9, 0x8A97, 0x59CA, 0xE6A2, 0x59CB, 0xCABC, 0x59CC, 0x8A98, 0x59CD, 0x8A99, 0x59CE, 0x8A9A, 0x59CF, 0x8A9B, 0x59D0, 0xBDE3, 0x59D1, 0xB9C3, 0x59D2, 0xE6A6, 0x59D3, 0xD0D5, 0x59D4, 0xCEAF, 0x59D5, 0x8A9C, 0x59D6, 0x8A9D, 0x59D7, 0xE6A9, 0x59D8, 0xE6B0, 0x59D9, 0x8A9E, 0x59DA, 0xD2A6, 0x59DB, 0x8A9F, 0x59DC, 0xBDAA, 0x59DD, 0xE6AD, 0x59DE, 0x8AA0, 0x59DF, 0x8AA1, 0x59E0, 0x8AA2, 0x59E1, 0x8AA3, 0x59E2, 0x8AA4, 0x59E3, 0xE6AF, 0x59E4, 0x8AA5, 0x59E5, 0xC0D1, 0x59E6, 0x8AA6, 0x59E7, 0x8AA7, 0x59E8, 0xD2CC, 0x59E9, 0x8AA8, 0x59EA, 0x8AA9, 0x59EB, 0x8AAA, 0x59EC, 0xBCA7, 0x59ED, 0x8AAB, 0x59EE, 0x8AAC, 0x59EF, 0x8AAD, 0x59F0, 0x8AAE, 0x59F1, 0x8AAF, 0x59F2, 0x8AB0, 0x59F3, 0x8AB1, 0x59F4, 0x8AB2, 0x59F5, 0x8AB3, 0x59F6, 0x8AB4, 0x59F7, 0x8AB5, 0x59F8, 0x8AB6, 0x59F9, 0xE6B1, 0x59FA, 0x8AB7, 0x59FB, 0xD2F6, 0x59FC, 0x8AB8, 0x59FD, 0x8AB9, 0x59FE, 0x8ABA, 0x59FF, 0xD7CB, 0x5A00, 0x8ABB, 0x5A01, 0xCDFE, 0x5A02, 0x8ABC, 0x5A03, 0xCDDE, 0x5A04, 0xC2A6, 0x5A05, 0xE6AB, 0x5A06, 0xE6AC, 0x5A07, 0xBDBF, 0x5A08, 0xE6AE, 0x5A09, 0xE6B3, 0x5A0A, 0x8ABD, 0x5A0B, 0x8ABE, 0x5A0C, 0xE6B2, 0x5A0D, 0x8ABF, 0x5A0E, 0x8AC0, 0x5A0F, 0x8AC1, 0x5A10, 0x8AC2, 0x5A11, 0xE6B6, 0x5A12, 0x8AC3, 0x5A13, 0xE6B8, 0x5A14, 0x8AC4, 0x5A15, 0x8AC5, 0x5A16, 0x8AC6, 0x5A17, 0x8AC7, 0x5A18, 0xC4EF, 0x5A19, 0x8AC8, 0x5A1A, 0x8AC9, 0x5A1B, 0x8ACA, 0x5A1C, 0xC4C8, 0x5A1D, 0x8ACB, 0x5A1E, 0x8ACC, 0x5A1F, 0xBEEA, 0x5A20, 0xC9EF, 0x5A21, 0x8ACD, 0x5A22, 0x8ACE, 0x5A23, 0xE6B7, 0x5A24, 0x8ACF, 0x5A25, 0xB6F0, 0x5A26, 0x8AD0, 0x5A27, 0x8AD1, 0x5A28, 0x8AD2, 0x5A29, 0xC3E4, 0x5A2A, 0x8AD3, 0x5A2B, 0x8AD4, 0x5A2C, 0x8AD5, 0x5A2D, 0x8AD6, 0x5A2E, 0x8AD7, 0x5A2F, 0x8AD8, 0x5A30, 0x8AD9, 0x5A31, 0xD3E9, 0x5A32, 0xE6B4, 0x5A33, 0x8ADA, 0x5A34, 0xE6B5, 0x5A35, 0x8ADB, 0x5A36, 0xC8A2, 0x5A37, 0x8ADC, 0x5A38, 0x8ADD, 0x5A39, 0x8ADE, 0x5A3A, 0x8ADF, 0x5A3B, 0x8AE0, 0x5A3C, 0xE6BD, 0x5A3D, 0x8AE1, 0x5A3E, 0x8AE2, 0x5A3F, 0x8AE3, 0x5A40, 0xE6B9, 0x5A41, 0x8AE4, 0x5A42, 0x8AE5, 0x5A43, 0x8AE6, 0x5A44, 0x8AE7, 0x5A45, 0x8AE8, 0x5A46, 0xC6C5, 0x5A47, 0x8AE9, 0x5A48, 0x8AEA, 0x5A49, 0xCDF1, 0x5A4A, 0xE6BB, 0x5A4B, 0x8AEB, 0x5A4C, 0x8AEC, 0x5A4D, 0x8AED, 0x5A4E, 0x8AEE, 0x5A4F, 0x8AEF, 0x5A50, 0x8AF0, 0x5A51, 0x8AF1, 0x5A52, 0x8AF2, 0x5A53, 0x8AF3, 0x5A54, 0x8AF4, 0x5A55, 0xE6BC, 0x5A56, 0x8AF5, 0x5A57, 0x8AF6, 0x5A58, 0x8AF7, 0x5A59, 0x8AF8, 0x5A5A, 0xBBE9, 0x5A5B, 0x8AF9, 0x5A5C, 0x8AFA, 0x5A5D, 0x8AFB, 0x5A5E, 0x8AFC, 0x5A5F, 0x8AFD, 0x5A60, 0x8AFE, 0x5A61, 0x8B40, 0x5A62, 0xE6BE, 0x5A63, 0x8B41, 0x5A64, 0x8B42, 0x5A65, 0x8B43, 0x5A66, 0x8B44, 0x5A67, 0xE6BA, 0x5A68, 0x8B45, 0x5A69, 0x8B46, 0x5A6A, 0xC0B7, 0x5A6B, 0x8B47, 0x5A6C, 0x8B48, 0x5A6D, 0x8B49, 0x5A6E, 0x8B4A, 0x5A6F, 0x8B4B, 0x5A70, 0x8B4C, 0x5A71, 0x8B4D, 0x5A72, 0x8B4E, 0x5A73, 0x8B4F, 0x5A74, 0xD3A4, 0x5A75, 0xE6BF, 0x5A76, 0xC9F4, 0x5A77, 0xE6C3, 0x5A78, 0x8B50, 0x5A79, 0x8B51, 0x5A7A, 0xE6C4, 0x5A7B, 0x8B52, 0x5A7C, 0x8B53, 0x5A7D, 0x8B54, 0x5A7E, 0x8B55, 0x5A7F, 0xD0F6, 0x5A80, 0x8B56, 0x5A81, 0x8B57, 0x5A82, 0x8B58, 0x5A83, 0x8B59, 0x5A84, 0x8B5A, 0x5A85, 0x8B5B, 0x5A86, 0x8B5C, 0x5A87, 0x8B5D, 0x5A88, 0x8B5E, 0x5A89, 0x8B5F, 0x5A8A, 0x8B60, 0x5A8B, 0x8B61, 0x5A8C, 0x8B62, 0x5A8D, 0x8B63, 0x5A8E, 0x8B64, 0x5A8F, 0x8B65, 0x5A90, 0x8B66, 0x5A91, 0x8B67, 0x5A92, 0xC3BD, 0x5A93, 0x8B68, 0x5A94, 0x8B69, 0x5A95, 0x8B6A, 0x5A96, 0x8B6B, 0x5A97, 0x8B6C, 0x5A98, 0x8B6D, 0x5A99, 0x8B6E, 0x5A9A, 0xC3C4, 0x5A9B, 0xE6C2, 0x5A9C, 0x8B6F, 0x5A9D, 0x8B70, 0x5A9E, 0x8B71, 0x5A9F, 0x8B72, 0x5AA0, 0x8B73, 0x5AA1, 0x8B74, 0x5AA2, 0x8B75, 0x5AA3, 0x8B76, 0x5AA4, 0x8B77, 0x5AA5, 0x8B78, 0x5AA6, 0x8B79, 0x5AA7, 0x8B7A, 0x5AA8, 0x8B7B, 0x5AA9, 0x8B7C, 0x5AAA, 0xE6C1, 0x5AAB, 0x8B7D, 0x5AAC, 0x8B7E, 0x5AAD, 0x8B80, 0x5AAE, 0x8B81, 0x5AAF, 0x8B82, 0x5AB0, 0x8B83, 0x5AB1, 0x8B84, 0x5AB2, 0xE6C7, 0x5AB3, 0xCFB1, 0x5AB4, 0x8B85, 0x5AB5, 0xEBF4, 0x5AB6, 0x8B86, 0x5AB7, 0x8B87, 0x5AB8, 0xE6CA, 0x5AB9, 0x8B88, 0x5ABA, 0x8B89, 0x5ABB, 0x8B8A, 0x5ABC, 0x8B8B, 0x5ABD, 0x8B8C, 0x5ABE, 0xE6C5, 0x5ABF, 0x8B8D, 0x5AC0, 0x8B8E, 0x5AC1, 0xBCDE, 0x5AC2, 0xC9A9, 0x5AC3, 0x8B8F, 0x5AC4, 0x8B90, 0x5AC5, 0x8B91, 0x5AC6, 0x8B92, 0x5AC7, 0x8B93, 0x5AC8, 0x8B94, 0x5AC9, 0xBCB5, 0x5ACA, 0x8B95, 0x5ACB, 0x8B96, 0x5ACC, 0xCFD3, 0x5ACD, 0x8B97, 0x5ACE, 0x8B98, 0x5ACF, 0x8B99, 0x5AD0, 0x8B9A, 0x5AD1, 0x8B9B, 0x5AD2, 0xE6C8, 0x5AD3, 0x8B9C, 0x5AD4, 0xE6C9, 0x5AD5, 0x8B9D, 0x5AD6, 0xE6CE, 0x5AD7, 0x8B9E, 0x5AD8, 0xE6D0, 0x5AD9, 0x8B9F, 0x5ADA, 0x8BA0, 0x5ADB, 0x8BA1, 0x5ADC, 0xE6D1, 0x5ADD, 0x8BA2, 0x5ADE, 0x8BA3, 0x5ADF, 0x8BA4, 0x5AE0, 0xE6CB, 0x5AE1, 0xB5D5, 0x5AE2, 0x8BA5, 0x5AE3, 0xE6CC, 0x5AE4, 0x8BA6, 0x5AE5, 0x8BA7, 0x5AE6, 0xE6CF, 0x5AE7, 0x8BA8, 0x5AE8, 0x8BA9, 0x5AE9, 0xC4DB, 0x5AEA, 0x8BAA, 0x5AEB, 0xE6C6, 0x5AEC, 0x8BAB, 0x5AED, 0x8BAC, 0x5AEE, 0x8BAD, 0x5AEF, 0x8BAE, 0x5AF0, 0x8BAF, 0x5AF1, 0xE6CD, 0x5AF2, 0x8BB0, 0x5AF3, 0x8BB1, 0x5AF4, 0x8BB2, 0x5AF5, 0x8BB3, 0x5AF6, 0x8BB4, 0x5AF7, 0x8BB5, 0x5AF8, 0x8BB6, 0x5AF9, 0x8BB7, 0x5AFA, 0x8BB8, 0x5AFB, 0x8BB9, 0x5AFC, 0x8BBA, 0x5AFD, 0x8BBB, 0x5AFE, 0x8BBC, 0x5AFF, 0x8BBD, 0x5B00, 0x8BBE, 0x5B01, 0x8BBF, 0x5B02, 0x8BC0, 0x5B03, 0x8BC1, 0x5B04, 0x8BC2, 0x5B05, 0x8BC3, 0x5B06, 0x8BC4, 0x5B07, 0x8BC5, 0x5B08, 0x8BC6, 0x5B09, 0xE6D2, 0x5B0A, 0x8BC7, 0x5B0B, 0x8BC8, 0x5B0C, 0x8BC9, 0x5B0D, 0x8BCA, 0x5B0E, 0x8BCB, 0x5B0F, 0x8BCC, 0x5B10, 0x8BCD, 0x5B11, 0x8BCE, 0x5B12, 0x8BCF, 0x5B13, 0x8BD0, 0x5B14, 0x8BD1, 0x5B15, 0x8BD2, 0x5B16, 0xE6D4, 0x5B17, 0xE6D3, 0x5B18, 0x8BD3, 0x5B19, 0x8BD4, 0x5B1A, 0x8BD5, 0x5B1B, 0x8BD6, 0x5B1C, 0x8BD7, 0x5B1D, 0x8BD8, 0x5B1E, 0x8BD9, 0x5B1F, 0x8BDA, 0x5B20, 0x8BDB, 0x5B21, 0x8BDC, 0x5B22, 0x8BDD, 0x5B23, 0x8BDE, 0x5B24, 0x8BDF, 0x5B25, 0x8BE0, 0x5B26, 0x8BE1, 0x5B27, 0x8BE2, 0x5B28, 0x8BE3, 0x5B29, 0x8BE4, 0x5B2A, 0x8BE5, 0x5B2B, 0x8BE6, 0x5B2C, 0x8BE7, 0x5B2D, 0x8BE8, 0x5B2E, 0x8BE9, 0x5B2F, 0x8BEA, 0x5B30, 0x8BEB, 0x5B31, 0x8BEC, 0x5B32, 0xE6D5, 0x5B33, 0x8BED, 0x5B34, 0xD9F8, 0x5B35, 0x8BEE, 0x5B36, 0x8BEF, 0x5B37, 0xE6D6, 0x5B38, 0x8BF0, 0x5B39, 0x8BF1, 0x5B3A, 0x8BF2, 0x5B3B, 0x8BF3, 0x5B3C, 0x8BF4, 0x5B3D, 0x8BF5, 0x5B3E, 0x8BF6, 0x5B3F, 0x8BF7, 0x5B40, 0xE6D7, 0x5B41, 0x8BF8, 0x5B42, 0x8BF9, 0x5B43, 0x8BFA, 0x5B44, 0x8BFB, 0x5B45, 0x8BFC, 0x5B46, 0x8BFD, 0x5B47, 0x8BFE, 0x5B48, 0x8C40, 0x5B49, 0x8C41, 0x5B4A, 0x8C42, 0x5B4B, 0x8C43, 0x5B4C, 0x8C44, 0x5B4D, 0x8C45, 0x5B4E, 0x8C46, 0x5B4F, 0x8C47, 0x5B50, 0xD7D3, 0x5B51, 0xE6DD, 0x5B52, 0x8C48, 0x5B53, 0xE6DE, 0x5B54, 0xBFD7, 0x5B55, 0xD4D0, 0x5B56, 0x8C49, 0x5B57, 0xD7D6, 0x5B58, 0xB4E6, 0x5B59, 0xCBEF, 0x5B5A, 0xE6DA, 0x5B5B, 0xD8C3, 0x5B5C, 0xD7CE, 0x5B5D, 0xD0A2, 0x5B5E, 0x8C4A, 0x5B5F, 0xC3CF, 0x5B60, 0x8C4B, 0x5B61, 0x8C4C, 0x5B62, 0xE6DF, 0x5B63, 0xBCBE, 0x5B64, 0xB9C2, 0x5B65, 0xE6DB, 0x5B66, 0xD1A7, 0x5B67, 0x8C4D, 0x5B68, 0x8C4E, 0x5B69, 0xBAA2, 0x5B6A, 0xC2CF, 0x5B6B, 0x8C4F, 0x5B6C, 0xD8AB, 0x5B6D, 0x8C50, 0x5B6E, 0x8C51, 0x5B6F, 0x8C52, 0x5B70, 0xCAEB, 0x5B71, 0xE5EE, 0x5B72, 0x8C53, 0x5B73, 0xE6DC, 0x5B74, 0x8C54, 0x5B75, 0xB7F5, 0x5B76, 0x8C55, 0x5B77, 0x8C56, 0x5B78, 0x8C57, 0x5B79, 0x8C58, 0x5B7A, 0xC8E6, 0x5B7B, 0x8C59, 0x5B7C, 0x8C5A, 0x5B7D, 0xC4F5, 0x5B7E, 0x8C5B, 0x5B7F, 0x8C5C, 0x5B80, 0xE5B2, 0x5B81, 0xC4FE, 0x5B82, 0x8C5D, 0x5B83, 0xCBFC, 0x5B84, 0xE5B3, 0x5B85, 0xD5AC, 0x5B86, 0x8C5E, 0x5B87, 0xD3EE, 0x5B88, 0xCAD8, 0x5B89, 0xB0B2, 0x5B8A, 0x8C5F, 0x5B8B, 0xCBCE, 0x5B8C, 0xCDEA, 0x5B8D, 0x8C60, 0x5B8E, 0x8C61, 0x5B8F, 0xBAEA, 0x5B90, 0x8C62, 0x5B91, 0x8C63, 0x5B92, 0x8C64, 0x5B93, 0xE5B5, 0x5B94, 0x8C65, 0x5B95, 0xE5B4, 0x5B96, 0x8C66, 0x5B97, 0xD7DA, 0x5B98, 0xB9D9, 0x5B99, 0xD6E6, 0x5B9A, 0xB6A8, 0x5B9B, 0xCDF0, 0x5B9C, 0xD2CB, 0x5B9D, 0xB1A6, 0x5B9E, 0xCAB5, 0x5B9F, 0x8C67, 0x5BA0, 0xB3E8, 0x5BA1, 0xC9F3, 0x5BA2, 0xBFCD, 0x5BA3, 0xD0FB, 0x5BA4, 0xCAD2, 0x5BA5, 0xE5B6, 0x5BA6, 0xBBC2, 0x5BA7, 0x8C68, 0x5BA8, 0x8C69, 0x5BA9, 0x8C6A, 0x5BAA, 0xCFDC, 0x5BAB, 0xB9AC, 0x5BAC, 0x8C6B, 0x5BAD, 0x8C6C, 0x5BAE, 0x8C6D, 0x5BAF, 0x8C6E, 0x5BB0, 0xD4D7, 0x5BB1, 0x8C6F, 0x5BB2, 0x8C70, 0x5BB3, 0xBAA6, 0x5BB4, 0xD1E7, 0x5BB5, 0xCFFC, 0x5BB6, 0xBCD2, 0x5BB7, 0x8C71, 0x5BB8, 0xE5B7, 0x5BB9, 0xC8DD, 0x5BBA, 0x8C72, 0x5BBB, 0x8C73, 0x5BBC, 0x8C74, 0x5BBD, 0xBFED, 0x5BBE, 0xB1F6, 0x5BBF, 0xCBDE, 0x5BC0, 0x8C75, 0x5BC1, 0x8C76, 0x5BC2, 0xBCC5, 0x5BC3, 0x8C77, 0x5BC4, 0xBCC4, 0x5BC5, 0xD2FA, 0x5BC6, 0xC3DC, 0x5BC7, 0xBFDC, 0x5BC8, 0x8C78, 0x5BC9, 0x8C79, 0x5BCA, 0x8C7A, 0x5BCB, 0x8C7B, 0x5BCC, 0xB8BB, 0x5BCD, 0x8C7C, 0x5BCE, 0x8C7D, 0x5BCF, 0x8C7E, 0x5BD0, 0xC3C2, 0x5BD1, 0x8C80, 0x5BD2, 0xBAAE, 0x5BD3, 0xD4A2, 0x5BD4, 0x8C81, 0x5BD5, 0x8C82, 0x5BD6, 0x8C83, 0x5BD7, 0x8C84, 0x5BD8, 0x8C85, 0x5BD9, 0x8C86, 0x5BDA, 0x8C87, 0x5BDB, 0x8C88, 0x5BDC, 0x8C89, 0x5BDD, 0xC7DE, 0x5BDE, 0xC4AF, 0x5BDF, 0xB2EC, 0x5BE0, 0x8C8A, 0x5BE1, 0xB9D1, 0x5BE2, 0x8C8B, 0x5BE3, 0x8C8C, 0x5BE4, 0xE5BB, 0x5BE5, 0xC1C8, 0x5BE6, 0x8C8D, 0x5BE7, 0x8C8E, 0x5BE8, 0xD5AF, 0x5BE9, 0x8C8F, 0x5BEA, 0x8C90, 0x5BEB, 0x8C91, 0x5BEC, 0x8C92, 0x5BED, 0x8C93, 0x5BEE, 0xE5BC, 0x5BEF, 0x8C94, 0x5BF0, 0xE5BE, 0x5BF1, 0x8C95, 0x5BF2, 0x8C96, 0x5BF3, 0x8C97, 0x5BF4, 0x8C98, 0x5BF5, 0x8C99, 0x5BF6, 0x8C9A, 0x5BF7, 0x8C9B, 0x5BF8, 0xB4E7, 0x5BF9, 0xB6D4, 0x5BFA, 0xCBC2, 0x5BFB, 0xD1B0, 0x5BFC, 0xB5BC, 0x5BFD, 0x8C9C, 0x5BFE, 0x8C9D, 0x5BFF, 0xCAD9, 0x5C00, 0x8C9E, 0x5C01, 0xB7E2, 0x5C02, 0x8C9F, 0x5C03, 0x8CA0, 0x5C04, 0xC9E4, 0x5C05, 0x8CA1, 0x5C06, 0xBDAB, 0x5C07, 0x8CA2, 0x5C08, 0x8CA3, 0x5C09, 0xCEBE, 0x5C0A, 0xD7F0, 0x5C0B, 0x8CA4, 0x5C0C, 0x8CA5, 0x5C0D, 0x8CA6, 0x5C0E, 0x8CA7, 0x5C0F, 0xD0A1, 0x5C10, 0x8CA8, 0x5C11, 0xC9D9, 0x5C12, 0x8CA9, 0x5C13, 0x8CAA, 0x5C14, 0xB6FB, 0x5C15, 0xE6D8, 0x5C16, 0xBCE2, 0x5C17, 0x8CAB, 0x5C18, 0xB3BE, 0x5C19, 0x8CAC, 0x5C1A, 0xC9D0, 0x5C1B, 0x8CAD, 0x5C1C, 0xE6D9, 0x5C1D, 0xB3A2, 0x5C1E, 0x8CAE, 0x5C1F, 0x8CAF, 0x5C20, 0x8CB0, 0x5C21, 0x8CB1, 0x5C22, 0xDECC, 0x5C23, 0x8CB2, 0x5C24, 0xD3C8, 0x5C25, 0xDECD, 0x5C26, 0x8CB3, 0x5C27, 0xD2A2, 0x5C28, 0x8CB4, 0x5C29, 0x8CB5, 0x5C2A, 0x8CB6, 0x5C2B, 0x8CB7, 0x5C2C, 0xDECE, 0x5C2D, 0x8CB8, 0x5C2E, 0x8CB9, 0x5C2F, 0x8CBA, 0x5C30, 0x8CBB, 0x5C31, 0xBECD, 0x5C32, 0x8CBC, 0x5C33, 0x8CBD, 0x5C34, 0xDECF, 0x5C35, 0x8CBE, 0x5C36, 0x8CBF, 0x5C37, 0x8CC0, 0x5C38, 0xCAAC, 0x5C39, 0xD2FC, 0x5C3A, 0xB3DF, 0x5C3B, 0xE5EA, 0x5C3C, 0xC4E1, 0x5C3D, 0xBEA1, 0x5C3E, 0xCEB2, 0x5C3F, 0xC4F2, 0x5C40, 0xBED6, 0x5C41, 0xC6A8, 0x5C42, 0xB2E3, 0x5C43, 0x8CC1, 0x5C44, 0x8CC2, 0x5C45, 0xBED3, 0x5C46, 0x8CC3, 0x5C47, 0x8CC4, 0x5C48, 0xC7FC, 0x5C49, 0xCCEB, 0x5C4A, 0xBDEC, 0x5C4B, 0xCEDD, 0x5C4C, 0x8CC5, 0x5C4D, 0x8CC6, 0x5C4E, 0xCABA, 0x5C4F, 0xC6C1, 0x5C50, 0xE5EC, 0x5C51, 0xD0BC, 0x5C52, 0x8CC7, 0x5C53, 0x8CC8, 0x5C54, 0x8CC9, 0x5C55, 0xD5B9, 0x5C56, 0x8CCA, 0x5C57, 0x8CCB, 0x5C58, 0x8CCC, 0x5C59, 0xE5ED, 0x5C5A, 0x8CCD, 0x5C5B, 0x8CCE, 0x5C5C, 0x8CCF, 0x5C5D, 0x8CD0, 0x5C5E, 0xCAF4, 0x5C5F, 0x8CD1, 0x5C60, 0xCDC0, 0x5C61, 0xC2C5, 0x5C62, 0x8CD2, 0x5C63, 0xE5EF, 0x5C64, 0x8CD3, 0x5C65, 0xC2C4, 0x5C66, 0xE5F0, 0x5C67, 0x8CD4, 0x5C68, 0x8CD5, 0x5C69, 0x8CD6, 0x5C6A, 0x8CD7, 0x5C6B, 0x8CD8, 0x5C6C, 0x8CD9, 0x5C6D, 0x8CDA, 0x5C6E, 0xE5F8, 0x5C6F, 0xCDCD, 0x5C70, 0x8CDB, 0x5C71, 0xC9BD, 0x5C72, 0x8CDC, 0x5C73, 0x8CDD, 0x5C74, 0x8CDE, 0x5C75, 0x8CDF, 0x5C76, 0x8CE0, 0x5C77, 0x8CE1, 0x5C78, 0x8CE2, 0x5C79, 0xD2D9, 0x5C7A, 0xE1A8, 0x5C7B, 0x8CE3, 0x5C7C, 0x8CE4, 0x5C7D, 0x8CE5, 0x5C7E, 0x8CE6, 0x5C7F, 0xD3EC, 0x5C80, 0x8CE7, 0x5C81, 0xCBEA, 0x5C82, 0xC6F1, 0x5C83, 0x8CE8, 0x5C84, 0x8CE9, 0x5C85, 0x8CEA, 0x5C86, 0x8CEB, 0x5C87, 0x8CEC, 0x5C88, 0xE1AC, 0x5C89, 0x8CED, 0x5C8A, 0x8CEE, 0x5C8B, 0x8CEF, 0x5C8C, 0xE1A7, 0x5C8D, 0xE1A9, 0x5C8E, 0x8CF0, 0x5C8F, 0x8CF1, 0x5C90, 0xE1AA, 0x5C91, 0xE1AF, 0x5C92, 0x8CF2, 0x5C93, 0x8CF3, 0x5C94, 0xB2ED, 0x5C95, 0x8CF4, 0x5C96, 0xE1AB, 0x5C97, 0xB8DA, 0x5C98, 0xE1AD, 0x5C99, 0xE1AE, 0x5C9A, 0xE1B0, 0x5C9B, 0xB5BA, 0x5C9C, 0xE1B1, 0x5C9D, 0x8CF5, 0x5C9E, 0x8CF6, 0x5C9F, 0x8CF7, 0x5CA0, 0x8CF8, 0x5CA1, 0x8CF9, 0x5CA2, 0xE1B3, 0x5CA3, 0xE1B8, 0x5CA4, 0x8CFA, 0x5CA5, 0x8CFB, 0x5CA6, 0x8CFC, 0x5CA7, 0x8CFD, 0x5CA8, 0x8CFE, 0x5CA9, 0xD1D2, 0x5CAA, 0x8D40, 0x5CAB, 0xE1B6, 0x5CAC, 0xE1B5, 0x5CAD, 0xC1EB, 0x5CAE, 0x8D41, 0x5CAF, 0x8D42, 0x5CB0, 0x8D43, 0x5CB1, 0xE1B7, 0x5CB2, 0x8D44, 0x5CB3, 0xD4C0, 0x5CB4, 0x8D45, 0x5CB5, 0xE1B2, 0x5CB6, 0x8D46, 0x5CB7, 0xE1BA, 0x5CB8, 0xB0B6, 0x5CB9, 0x8D47, 0x5CBA, 0x8D48, 0x5CBB, 0x8D49, 0x5CBC, 0x8D4A, 0x5CBD, 0xE1B4, 0x5CBE, 0x8D4B, 0x5CBF, 0xBFF9, 0x5CC0, 0x8D4C, 0x5CC1, 0xE1B9, 0x5CC2, 0x8D4D, 0x5CC3, 0x8D4E, 0x5CC4, 0xE1BB, 0x5CC5, 0x8D4F, 0x5CC6, 0x8D50, 0x5CC7, 0x8D51, 0x5CC8, 0x8D52, 0x5CC9, 0x8D53, 0x5CCA, 0x8D54, 0x5CCB, 0xE1BE, 0x5CCC, 0x8D55, 0x5CCD, 0x8D56, 0x5CCE, 0x8D57, 0x5CCF, 0x8D58, 0x5CD0, 0x8D59, 0x5CD1, 0x8D5A, 0x5CD2, 0xE1BC, 0x5CD3, 0x8D5B, 0x5CD4, 0x8D5C, 0x5CD5, 0x8D5D, 0x5CD6, 0x8D5E, 0x5CD7, 0x8D5F, 0x5CD8, 0x8D60, 0x5CD9, 0xD6C5, 0x5CDA, 0x8D61, 0x5CDB, 0x8D62, 0x5CDC, 0x8D63, 0x5CDD, 0x8D64, 0x5CDE, 0x8D65, 0x5CDF, 0x8D66, 0x5CE0, 0x8D67, 0x5CE1, 0xCFBF, 0x5CE2, 0x8D68, 0x5CE3, 0x8D69, 0x5CE4, 0xE1BD, 0x5CE5, 0xE1BF, 0x5CE6, 0xC2CD, 0x5CE7, 0x8D6A, 0x5CE8, 0xB6EB, 0x5CE9, 0x8D6B, 0x5CEA, 0xD3F8, 0x5CEB, 0x8D6C, 0x5CEC, 0x8D6D, 0x5CED, 0xC7CD, 0x5CEE, 0x8D6E, 0x5CEF, 0x8D6F, 0x5CF0, 0xB7E5, 0x5CF1, 0x8D70, 0x5CF2, 0x8D71, 0x5CF3, 0x8D72, 0x5CF4, 0x8D73, 0x5CF5, 0x8D74, 0x5CF6, 0x8D75, 0x5CF7, 0x8D76, 0x5CF8, 0x8D77, 0x5CF9, 0x8D78, 0x5CFA, 0x8D79, 0x5CFB, 0xBEFE, 0x5CFC, 0x8D7A, 0x5CFD, 0x8D7B, 0x5CFE, 0x8D7C, 0x5CFF, 0x8D7D, 0x5D00, 0x8D7E, 0x5D01, 0x8D80, 0x5D02, 0xE1C0, 0x5D03, 0xE1C1, 0x5D04, 0x8D81, 0x5D05, 0x8D82, 0x5D06, 0xE1C7, 0x5D07, 0xB3E7, 0x5D08, 0x8D83, 0x5D09, 0x8D84, 0x5D0A, 0x8D85, 0x5D0B, 0x8D86, 0x5D0C, 0x8D87, 0x5D0D, 0x8D88, 0x5D0E, 0xC6E9, 0x5D0F, 0x8D89, 0x5D10, 0x8D8A, 0x5D11, 0x8D8B, 0x5D12, 0x8D8C, 0x5D13, 0x8D8D, 0x5D14, 0xB4DE, 0x5D15, 0x8D8E, 0x5D16, 0xD1C2, 0x5D17, 0x8D8F, 0x5D18, 0x8D90, 0x5D19, 0x8D91, 0x5D1A, 0x8D92, 0x5D1B, 0xE1C8, 0x5D1C, 0x8D93, 0x5D1D, 0x8D94, 0x5D1E, 0xE1C6, 0x5D1F, 0x8D95, 0x5D20, 0x8D96, 0x5D21, 0x8D97, 0x5D22, 0x8D98, 0x5D23, 0x8D99, 0x5D24, 0xE1C5, 0x5D25, 0x8D9A, 0x5D26, 0xE1C3, 0x5D27, 0xE1C2, 0x5D28, 0x8D9B, 0x5D29, 0xB1C0, 0x5D2A, 0x8D9C, 0x5D2B, 0x8D9D, 0x5D2C, 0x8D9E, 0x5D2D, 0xD5B8, 0x5D2E, 0xE1C4, 0x5D2F, 0x8D9F, 0x5D30, 0x8DA0, 0x5D31, 0x8DA1, 0x5D32, 0x8DA2, 0x5D33, 0x8DA3, 0x5D34, 0xE1CB, 0x5D35, 0x8DA4, 0x5D36, 0x8DA5, 0x5D37, 0x8DA6, 0x5D38, 0x8DA7, 0x5D39, 0x8DA8, 0x5D3A, 0x8DA9, 0x5D3B, 0x8DAA, 0x5D3C, 0x8DAB, 0x5D3D, 0xE1CC, 0x5D3E, 0xE1CA, 0x5D3F, 0x8DAC, 0x5D40, 0x8DAD, 0x5D41, 0x8DAE, 0x5D42, 0x8DAF, 0x5D43, 0x8DB0, 0x5D44, 0x8DB1, 0x5D45, 0x8DB2, 0x5D46, 0x8DB3, 0x5D47, 0xEFFA, 0x5D48, 0x8DB4, 0x5D49, 0x8DB5, 0x5D4A, 0xE1D3, 0x5D4B, 0xE1D2, 0x5D4C, 0xC7B6, 0x5D4D, 0x8DB6, 0x5D4E, 0x8DB7, 0x5D4F, 0x8DB8, 0x5D50, 0x8DB9, 0x5D51, 0x8DBA, 0x5D52, 0x8DBB, 0x5D53, 0x8DBC, 0x5D54, 0x8DBD, 0x5D55, 0x8DBE, 0x5D56, 0x8DBF, 0x5D57, 0x8DC0, 0x5D58, 0xE1C9, 0x5D59, 0x8DC1, 0x5D5A, 0x8DC2, 0x5D5B, 0xE1CE, 0x5D5C, 0x8DC3, 0x5D5D, 0xE1D0, 0x5D5E, 0x8DC4, 0x5D5F, 0x8DC5, 0x5D60, 0x8DC6, 0x5D61, 0x8DC7, 0x5D62, 0x8DC8, 0x5D63, 0x8DC9, 0x5D64, 0x8DCA, 0x5D65, 0x8DCB, 0x5D66, 0x8DCC, 0x5D67, 0x8DCD, 0x5D68, 0x8DCE, 0x5D69, 0xE1D4, 0x5D6A, 0x8DCF, 0x5D6B, 0xE1D1, 0x5D6C, 0xE1CD, 0x5D6D, 0x8DD0, 0x5D6E, 0x8DD1, 0x5D6F, 0xE1CF, 0x5D70, 0x8DD2, 0x5D71, 0x8DD3, 0x5D72, 0x8DD4, 0x5D73, 0x8DD5, 0x5D74, 0xE1D5, 0x5D75, 0x8DD6, 0x5D76, 0x8DD7, 0x5D77, 0x8DD8, 0x5D78, 0x8DD9, 0x5D79, 0x8DDA, 0x5D7A, 0x8DDB, 0x5D7B, 0x8DDC, 0x5D7C, 0x8DDD, 0x5D7D, 0x8DDE, 0x5D7E, 0x8DDF, 0x5D7F, 0x8DE0, 0x5D80, 0x8DE1, 0x5D81, 0x8DE2, 0x5D82, 0xE1D6, 0x5D83, 0x8DE3, 0x5D84, 0x8DE4, 0x5D85, 0x8DE5, 0x5D86, 0x8DE6, 0x5D87, 0x8DE7, 0x5D88, 0x8DE8, 0x5D89, 0x8DE9, 0x5D8A, 0x8DEA, 0x5D8B, 0x8DEB, 0x5D8C, 0x8DEC, 0x5D8D, 0x8DED, 0x5D8E, 0x8DEE, 0x5D8F, 0x8DEF, 0x5D90, 0x8DF0, 0x5D91, 0x8DF1, 0x5D92, 0x8DF2, 0x5D93, 0x8DF3, 0x5D94, 0x8DF4, 0x5D95, 0x8DF5, 0x5D96, 0x8DF6, 0x5D97, 0x8DF7, 0x5D98, 0x8DF8, 0x5D99, 0xE1D7, 0x5D9A, 0x8DF9, 0x5D9B, 0x8DFA, 0x5D9C, 0x8DFB, 0x5D9D, 0xE1D8, 0x5D9E, 0x8DFC, 0x5D9F, 0x8DFD, 0x5DA0, 0x8DFE, 0x5DA1, 0x8E40, 0x5DA2, 0x8E41, 0x5DA3, 0x8E42, 0x5DA4, 0x8E43, 0x5DA5, 0x8E44, 0x5DA6, 0x8E45, 0x5DA7, 0x8E46, 0x5DA8, 0x8E47, 0x5DA9, 0x8E48, 0x5DAA, 0x8E49, 0x5DAB, 0x8E4A, 0x5DAC, 0x8E4B, 0x5DAD, 0x8E4C, 0x5DAE, 0x8E4D, 0x5DAF, 0x8E4E, 0x5DB0, 0x8E4F, 0x5DB1, 0x8E50, 0x5DB2, 0x8E51, 0x5DB3, 0x8E52, 0x5DB4, 0x8E53, 0x5DB5, 0x8E54, 0x5DB6, 0x8E55, 0x5DB7, 0xE1DA, 0x5DB8, 0x8E56, 0x5DB9, 0x8E57, 0x5DBA, 0x8E58, 0x5DBB, 0x8E59, 0x5DBC, 0x8E5A, 0x5DBD, 0x8E5B, 0x5DBE, 0x8E5C, 0x5DBF, 0x8E5D, 0x5DC0, 0x8E5E, 0x5DC1, 0x8E5F, 0x5DC2, 0x8E60, 0x5DC3, 0x8E61, 0x5DC4, 0x8E62, 0x5DC5, 0xE1DB, 0x5DC6, 0x8E63, 0x5DC7, 0x8E64, 0x5DC8, 0x8E65, 0x5DC9, 0x8E66, 0x5DCA, 0x8E67, 0x5DCB, 0x8E68, 0x5DCC, 0x8E69, 0x5DCD, 0xCEA1, 0x5DCE, 0x8E6A, 0x5DCF, 0x8E6B, 0x5DD0, 0x8E6C, 0x5DD1, 0x8E6D, 0x5DD2, 0x8E6E, 0x5DD3, 0x8E6F, 0x5DD4, 0x8E70, 0x5DD5, 0x8E71, 0x5DD6, 0x8E72, 0x5DD7, 0x8E73, 0x5DD8, 0x8E74, 0x5DD9, 0x8E75, 0x5DDA, 0x8E76, 0x5DDB, 0xE7DD, 0x5DDC, 0x8E77, 0x5DDD, 0xB4A8, 0x5DDE, 0xD6DD, 0x5DDF, 0x8E78, 0x5DE0, 0x8E79, 0x5DE1, 0xD1B2, 0x5DE2, 0xB3B2, 0x5DE3, 0x8E7A, 0x5DE4, 0x8E7B, 0x5DE5, 0xB9A4, 0x5DE6, 0xD7F3, 0x5DE7, 0xC7C9, 0x5DE8, 0xBEDE, 0x5DE9, 0xB9AE, 0x5DEA, 0x8E7C, 0x5DEB, 0xCED7, 0x5DEC, 0x8E7D, 0x5DED, 0x8E7E, 0x5DEE, 0xB2EE, 0x5DEF, 0xDBCF, 0x5DF0, 0x8E80, 0x5DF1, 0xBCBA, 0x5DF2, 0xD2D1, 0x5DF3, 0xCBC8, 0x5DF4, 0xB0CD, 0x5DF5, 0x8E81, 0x5DF6, 0x8E82, 0x5DF7, 0xCFEF, 0x5DF8, 0x8E83, 0x5DF9, 0x8E84, 0x5DFA, 0x8E85, 0x5DFB, 0x8E86, 0x5DFC, 0x8E87, 0x5DFD, 0xD9E3, 0x5DFE, 0xBDED, 0x5DFF, 0x8E88, 0x5E00, 0x8E89, 0x5E01, 0xB1D2, 0x5E02, 0xCAD0, 0x5E03, 0xB2BC, 0x5E04, 0x8E8A, 0x5E05, 0xCBA7, 0x5E06, 0xB7AB, 0x5E07, 0x8E8B, 0x5E08, 0xCAA6, 0x5E09, 0x8E8C, 0x5E0A, 0x8E8D, 0x5E0B, 0x8E8E, 0x5E0C, 0xCFA3, 0x5E0D, 0x8E8F, 0x5E0E, 0x8E90, 0x5E0F, 0xE0F8, 0x5E10, 0xD5CA, 0x5E11, 0xE0FB, 0x5E12, 0x8E91, 0x5E13, 0x8E92, 0x5E14, 0xE0FA, 0x5E15, 0xC5C1, 0x5E16, 0xCCFB, 0x5E17, 0x8E93, 0x5E18, 0xC1B1, 0x5E19, 0xE0F9, 0x5E1A, 0xD6E3, 0x5E1B, 0xB2AF, 0x5E1C, 0xD6C4, 0x5E1D, 0xB5DB, 0x5E1E, 0x8E94, 0x5E1F, 0x8E95, 0x5E20, 0x8E96, 0x5E21, 0x8E97, 0x5E22, 0x8E98, 0x5E23, 0x8E99, 0x5E24, 0x8E9A, 0x5E25, 0x8E9B, 0x5E26, 0xB4F8, 0x5E27, 0xD6A1, 0x5E28, 0x8E9C, 0x5E29, 0x8E9D, 0x5E2A, 0x8E9E, 0x5E2B, 0x8E9F, 0x5E2C, 0x8EA0, 0x5E2D, 0xCFAF, 0x5E2E, 0xB0EF, 0x5E2F, 0x8EA1, 0x5E30, 0x8EA2, 0x5E31, 0xE0FC, 0x5E32, 0x8EA3, 0x5E33, 0x8EA4, 0x5E34, 0x8EA5, 0x5E35, 0x8EA6, 0x5E36, 0x8EA7, 0x5E37, 0xE1A1, 0x5E38, 0xB3A3, 0x5E39, 0x8EA8, 0x5E3A, 0x8EA9, 0x5E3B, 0xE0FD, 0x5E3C, 0xE0FE, 0x5E3D, 0xC3B1, 0x5E3E, 0x8EAA, 0x5E3F, 0x8EAB, 0x5E40, 0x8EAC, 0x5E41, 0x8EAD, 0x5E42, 0xC3DD, 0x5E43, 0x8EAE, 0x5E44, 0xE1A2, 0x5E45, 0xB7F9, 0x5E46, 0x8EAF, 0x5E47, 0x8EB0, 0x5E48, 0x8EB1, 0x5E49, 0x8EB2, 0x5E4A, 0x8EB3, 0x5E4B, 0x8EB4, 0x5E4C, 0xBBCF, 0x5E4D, 0x8EB5, 0x5E4E, 0x8EB6, 0x5E4F, 0x8EB7, 0x5E50, 0x8EB8, 0x5E51, 0x8EB9, 0x5E52, 0x8EBA, 0x5E53, 0x8EBB, 0x5E54, 0xE1A3, 0x5E55, 0xC4BB, 0x5E56, 0x8EBC, 0x5E57, 0x8EBD, 0x5E58, 0x8EBE, 0x5E59, 0x8EBF, 0x5E5A, 0x8EC0, 0x5E5B, 0xE1A4, 0x5E5C, 0x8EC1, 0x5E5D, 0x8EC2, 0x5E5E, 0xE1A5, 0x5E5F, 0x8EC3, 0x5E60, 0x8EC4, 0x5E61, 0xE1A6, 0x5E62, 0xB4B1, 0x5E63, 0x8EC5, 0x5E64, 0x8EC6, 0x5E65, 0x8EC7, 0x5E66, 0x8EC8, 0x5E67, 0x8EC9, 0x5E68, 0x8ECA, 0x5E69, 0x8ECB, 0x5E6A, 0x8ECC, 0x5E6B, 0x8ECD, 0x5E6C, 0x8ECE, 0x5E6D, 0x8ECF, 0x5E6E, 0x8ED0, 0x5E6F, 0x8ED1, 0x5E70, 0x8ED2, 0x5E71, 0x8ED3, 0x5E72, 0xB8C9, 0x5E73, 0xC6BD, 0x5E74, 0xC4EA, 0x5E75, 0x8ED4, 0x5E76, 0xB2A2, 0x5E77, 0x8ED5, 0x5E78, 0xD0D2, 0x5E79, 0x8ED6, 0x5E7A, 0xE7DB, 0x5E7B, 0xBBC3, 0x5E7C, 0xD3D7, 0x5E7D, 0xD3C4, 0x5E7E, 0x8ED7, 0x5E7F, 0xB9E3, 0x5E80, 0xE2CF, 0x5E81, 0x8ED8, 0x5E82, 0x8ED9, 0x5E83, 0x8EDA, 0x5E84, 0xD7AF, 0x5E85, 0x8EDB, 0x5E86, 0xC7EC, 0x5E87, 0xB1D3, 0x5E88, 0x8EDC, 0x5E89, 0x8EDD, 0x5E8A, 0xB4B2, 0x5E8B, 0xE2D1, 0x5E8C, 0x8EDE, 0x5E8D, 0x8EDF, 0x5E8E, 0x8EE0, 0x5E8F, 0xD0F2, 0x5E90, 0xC2AE, 0x5E91, 0xE2D0, 0x5E92, 0x8EE1, 0x5E93, 0xBFE2, 0x5E94, 0xD3A6, 0x5E95, 0xB5D7, 0x5E96, 0xE2D2, 0x5E97, 0xB5EA, 0x5E98, 0x8EE2, 0x5E99, 0xC3ED, 0x5E9A, 0xB8FD, 0x5E9B, 0x8EE3, 0x5E9C, 0xB8AE, 0x5E9D, 0x8EE4, 0x5E9E, 0xC5D3, 0x5E9F, 0xB7CF, 0x5EA0, 0xE2D4, 0x5EA1, 0x8EE5, 0x5EA2, 0x8EE6, 0x5EA3, 0x8EE7, 0x5EA4, 0x8EE8, 0x5EA5, 0xE2D3, 0x5EA6, 0xB6C8, 0x5EA7, 0xD7F9, 0x5EA8, 0x8EE9, 0x5EA9, 0x8EEA, 0x5EAA, 0x8EEB, 0x5EAB, 0x8EEC, 0x5EAC, 0x8EED, 0x5EAD, 0xCDA5, 0x5EAE, 0x8EEE, 0x5EAF, 0x8EEF, 0x5EB0, 0x8EF0, 0x5EB1, 0x8EF1, 0x5EB2, 0x8EF2, 0x5EB3, 0xE2D8, 0x5EB4, 0x8EF3, 0x5EB5, 0xE2D6, 0x5EB6, 0xCAFC, 0x5EB7, 0xBFB5, 0x5EB8, 0xD3B9, 0x5EB9, 0xE2D5, 0x5EBA, 0x8EF4, 0x5EBB, 0x8EF5, 0x5EBC, 0x8EF6, 0x5EBD, 0x8EF7, 0x5EBE, 0xE2D7, 0x5EBF, 0x8EF8, 0x5EC0, 0x8EF9, 0x5EC1, 0x8EFA, 0x5EC2, 0x8EFB, 0x5EC3, 0x8EFC, 0x5EC4, 0x8EFD, 0x5EC5, 0x8EFE, 0x5EC6, 0x8F40, 0x5EC7, 0x8F41, 0x5EC8, 0x8F42, 0x5EC9, 0xC1AE, 0x5ECA, 0xC0C8, 0x5ECB, 0x8F43, 0x5ECC, 0x8F44, 0x5ECD, 0x8F45, 0x5ECE, 0x8F46, 0x5ECF, 0x8F47, 0x5ED0, 0x8F48, 0x5ED1, 0xE2DB, 0x5ED2, 0xE2DA, 0x5ED3, 0xC0AA, 0x5ED4, 0x8F49, 0x5ED5, 0x8F4A, 0x5ED6, 0xC1CE, 0x5ED7, 0x8F4B, 0x5ED8, 0x8F4C, 0x5ED9, 0x8F4D, 0x5EDA, 0x8F4E, 0x5EDB, 0xE2DC, 0x5EDC, 0x8F4F, 0x5EDD, 0x8F50, 0x5EDE, 0x8F51, 0x5EDF, 0x8F52, 0x5EE0, 0x8F53, 0x5EE1, 0x8F54, 0x5EE2, 0x8F55, 0x5EE3, 0x8F56, 0x5EE4, 0x8F57, 0x5EE5, 0x8F58, 0x5EE6, 0x8F59, 0x5EE7, 0x8F5A, 0x5EE8, 0xE2DD, 0x5EE9, 0x8F5B, 0x5EEA, 0xE2DE, 0x5EEB, 0x8F5C, 0x5EEC, 0x8F5D, 0x5EED, 0x8F5E, 0x5EEE, 0x8F5F, 0x5EEF, 0x8F60, 0x5EF0, 0x8F61, 0x5EF1, 0x8F62, 0x5EF2, 0x8F63, 0x5EF3, 0x8F64, 0x5EF4, 0xDBC8, 0x5EF5, 0x8F65, 0x5EF6, 0xD1D3, 0x5EF7, 0xCDA2, 0x5EF8, 0x8F66, 0x5EF9, 0x8F67, 0x5EFA, 0xBDA8, 0x5EFB, 0x8F68, 0x5EFC, 0x8F69, 0x5EFD, 0x8F6A, 0x5EFE, 0xDEC3, 0x5EFF, 0xD8A5, 0x5F00, 0xBFAA, 0x5F01, 0xDBCD, 0x5F02, 0xD2EC, 0x5F03, 0xC6FA, 0x5F04, 0xC5AA, 0x5F05, 0x8F6B, 0x5F06, 0x8F6C, 0x5F07, 0x8F6D, 0x5F08, 0xDEC4, 0x5F09, 0x8F6E, 0x5F0A, 0xB1D7, 0x5F0B, 0xDFAE, 0x5F0C, 0x8F6F, 0x5F0D, 0x8F70, 0x5F0E, 0x8F71, 0x5F0F, 0xCABD, 0x5F10, 0x8F72, 0x5F11, 0xDFB1, 0x5F12, 0x8F73, 0x5F13, 0xB9AD, 0x5F14, 0x8F74, 0x5F15, 0xD2FD, 0x5F16, 0x8F75, 0x5F17, 0xB8A5, 0x5F18, 0xBAEB, 0x5F19, 0x8F76, 0x5F1A, 0x8F77, 0x5F1B, 0xB3DA, 0x5F1C, 0x8F78, 0x5F1D, 0x8F79, 0x5F1E, 0x8F7A, 0x5F1F, 0xB5DC, 0x5F20, 0xD5C5, 0x5F21, 0x8F7B, 0x5F22, 0x8F7C, 0x5F23, 0x8F7D, 0x5F24, 0x8F7E, 0x5F25, 0xC3D6, 0x5F26, 0xCFD2, 0x5F27, 0xBBA1, 0x5F28, 0x8F80, 0x5F29, 0xE5F3, 0x5F2A, 0xE5F2, 0x5F2B, 0x8F81, 0x5F2C, 0x8F82, 0x5F2D, 0xE5F4, 0x5F2E, 0x8F83, 0x5F2F, 0xCDE4, 0x5F30, 0x8F84, 0x5F31, 0xC8F5, 0x5F32, 0x8F85, 0x5F33, 0x8F86, 0x5F34, 0x8F87, 0x5F35, 0x8F88, 0x5F36, 0x8F89, 0x5F37, 0x8F8A, 0x5F38, 0x8F8B, 0x5F39, 0xB5AF, 0x5F3A, 0xC7BF, 0x5F3B, 0x8F8C, 0x5F3C, 0xE5F6, 0x5F3D, 0x8F8D, 0x5F3E, 0x8F8E, 0x5F3F, 0x8F8F, 0x5F40, 0xECB0, 0x5F41, 0x8F90, 0x5F42, 0x8F91, 0x5F43, 0x8F92, 0x5F44, 0x8F93, 0x5F45, 0x8F94, 0x5F46, 0x8F95, 0x5F47, 0x8F96, 0x5F48, 0x8F97, 0x5F49, 0x8F98, 0x5F4A, 0x8F99, 0x5F4B, 0x8F9A, 0x5F4C, 0x8F9B, 0x5F4D, 0x8F9C, 0x5F4E, 0x8F9D, 0x5F4F, 0x8F9E, 0x5F50, 0xE5E6, 0x5F51, 0x8F9F, 0x5F52, 0xB9E9, 0x5F53, 0xB5B1, 0x5F54, 0x8FA0, 0x5F55, 0xC2BC, 0x5F56, 0xE5E8, 0x5F57, 0xE5E7, 0x5F58, 0xE5E9, 0x5F59, 0x8FA1, 0x5F5A, 0x8FA2, 0x5F5B, 0x8FA3, 0x5F5C, 0x8FA4, 0x5F5D, 0xD2CD, 0x5F5E, 0x8FA5, 0x5F5F, 0x8FA6, 0x5F60, 0x8FA7, 0x5F61, 0xE1EA, 0x5F62, 0xD0CE, 0x5F63, 0x8FA8, 0x5F64, 0xCDAE, 0x5F65, 0x8FA9, 0x5F66, 0xD1E5, 0x5F67, 0x8FAA, 0x5F68, 0x8FAB, 0x5F69, 0xB2CA, 0x5F6A, 0xB1EB, 0x5F6B, 0x8FAC, 0x5F6C, 0xB1F2, 0x5F6D, 0xC5ED, 0x5F6E, 0x8FAD, 0x5F6F, 0x8FAE, 0x5F70, 0xD5C3, 0x5F71, 0xD3B0, 0x5F72, 0x8FAF, 0x5F73, 0xE1DC, 0x5F74, 0x8FB0, 0x5F75, 0x8FB1, 0x5F76, 0x8FB2, 0x5F77, 0xE1DD, 0x5F78, 0x8FB3, 0x5F79, 0xD2DB, 0x5F7A, 0x8FB4, 0x5F7B, 0xB3B9, 0x5F7C, 0xB1CB, 0x5F7D, 0x8FB5, 0x5F7E, 0x8FB6, 0x5F7F, 0x8FB7, 0x5F80, 0xCDF9, 0x5F81, 0xD5F7, 0x5F82, 0xE1DE, 0x5F83, 0x8FB8, 0x5F84, 0xBEB6, 0x5F85, 0xB4FD, 0x5F86, 0x8FB9, 0x5F87, 0xE1DF, 0x5F88, 0xBADC, 0x5F89, 0xE1E0, 0x5F8A, 0xBBB2, 0x5F8B, 0xC2C9, 0x5F8C, 0xE1E1, 0x5F8D, 0x8FBA, 0x5F8E, 0x8FBB, 0x5F8F, 0x8FBC, 0x5F90, 0xD0EC, 0x5F91, 0x8FBD, 0x5F92, 0xCDBD, 0x5F93, 0x8FBE, 0x5F94, 0x8FBF, 0x5F95, 0xE1E2, 0x5F96, 0x8FC0, 0x5F97, 0xB5C3, 0x5F98, 0xC5C7, 0x5F99, 0xE1E3, 0x5F9A, 0x8FC1, 0x5F9B, 0x8FC2, 0x5F9C, 0xE1E4, 0x5F9D, 0x8FC3, 0x5F9E, 0x8FC4, 0x5F9F, 0x8FC5, 0x5FA0, 0x8FC6, 0x5FA1, 0xD3F9, 0x5FA2, 0x8FC7, 0x5FA3, 0x8FC8, 0x5FA4, 0x8FC9, 0x5FA5, 0x8FCA, 0x5FA6, 0x8FCB, 0x5FA7, 0x8FCC, 0x5FA8, 0xE1E5, 0x5FA9, 0x8FCD, 0x5FAA, 0xD1AD, 0x5FAB, 0x8FCE, 0x5FAC, 0x8FCF, 0x5FAD, 0xE1E6, 0x5FAE, 0xCEA2, 0x5FAF, 0x8FD0, 0x5FB0, 0x8FD1, 0x5FB1, 0x8FD2, 0x5FB2, 0x8FD3, 0x5FB3, 0x8FD4, 0x5FB4, 0x8FD5, 0x5FB5, 0xE1E7, 0x5FB6, 0x8FD6, 0x5FB7, 0xB5C2, 0x5FB8, 0x8FD7, 0x5FB9, 0x8FD8, 0x5FBA, 0x8FD9, 0x5FBB, 0x8FDA, 0x5FBC, 0xE1E8, 0x5FBD, 0xBBD5, 0x5FBE, 0x8FDB, 0x5FBF, 0x8FDC, 0x5FC0, 0x8FDD, 0x5FC1, 0x8FDE, 0x5FC2, 0x8FDF, 0x5FC3, 0xD0C4, 0x5FC4, 0xE2E0, 0x5FC5, 0xB1D8, 0x5FC6, 0xD2E4, 0x5FC7, 0x8FE0, 0x5FC8, 0x8FE1, 0x5FC9, 0xE2E1, 0x5FCA, 0x8FE2, 0x5FCB, 0x8FE3, 0x5FCC, 0xBCC9, 0x5FCD, 0xC8CC, 0x5FCE, 0x8FE4, 0x5FCF, 0xE2E3, 0x5FD0, 0xECFE, 0x5FD1, 0xECFD, 0x5FD2, 0xDFAF, 0x5FD3, 0x8FE5, 0x5FD4, 0x8FE6, 0x5FD5, 0x8FE7, 0x5FD6, 0xE2E2, 0x5FD7, 0xD6BE, 0x5FD8, 0xCDFC, 0x5FD9, 0xC3A6, 0x5FDA, 0x8FE8, 0x5FDB, 0x8FE9, 0x5FDC, 0x8FEA, 0x5FDD, 0xE3C3, 0x5FDE, 0x8FEB, 0x5FDF, 0x8FEC, 0x5FE0, 0xD6D2, 0x5FE1, 0xE2E7, 0x5FE2, 0x8FED, 0x5FE3, 0x8FEE, 0x5FE4, 0xE2E8, 0x5FE5, 0x8FEF, 0x5FE6, 0x8FF0, 0x5FE7, 0xD3C7, 0x5FE8, 0x8FF1, 0x5FE9, 0x8FF2, 0x5FEA, 0xE2EC, 0x5FEB, 0xBFEC, 0x5FEC, 0x8FF3, 0x5FED, 0xE2ED, 0x5FEE, 0xE2E5, 0x5FEF, 0x8FF4, 0x5FF0, 0x8FF5, 0x5FF1, 0xB3C0, 0x5FF2, 0x8FF6, 0x5FF3, 0x8FF7, 0x5FF4, 0x8FF8, 0x5FF5, 0xC4EE, 0x5FF6, 0x8FF9, 0x5FF7, 0x8FFA, 0x5FF8, 0xE2EE, 0x5FF9, 0x8FFB, 0x5FFA, 0x8FFC, 0x5FFB, 0xD0C3, 0x5FFC, 0x8FFD, 0x5FFD, 0xBAF6, 0x5FFE, 0xE2E9, 0x5FFF, 0xB7DE, 0x6000, 0xBBB3, 0x6001, 0xCCAC, 0x6002, 0xCBCB, 0x6003, 0xE2E4, 0x6004, 0xE2E6, 0x6005, 0xE2EA, 0x6006, 0xE2EB, 0x6007, 0x8FFE, 0x6008, 0x9040, 0x6009, 0x9041, 0x600A, 0xE2F7, 0x600B, 0x9042, 0x600C, 0x9043, 0x600D, 0xE2F4, 0x600E, 0xD4F5, 0x600F, 0xE2F3, 0x6010, 0x9044, 0x6011, 0x9045, 0x6012, 0xC5AD, 0x6013, 0x9046, 0x6014, 0xD5FA, 0x6015, 0xC5C2, 0x6016, 0xB2C0, 0x6017, 0x9047, 0x6018, 0x9048, 0x6019, 0xE2EF, 0x601A, 0x9049, 0x601B, 0xE2F2, 0x601C, 0xC1AF, 0x601D, 0xCBBC, 0x601E, 0x904A, 0x601F, 0x904B, 0x6020, 0xB5A1, 0x6021, 0xE2F9, 0x6022, 0x904C, 0x6023, 0x904D, 0x6024, 0x904E, 0x6025, 0xBCB1, 0x6026, 0xE2F1, 0x6027, 0xD0D4, 0x6028, 0xD4B9, 0x6029, 0xE2F5, 0x602A, 0xB9D6, 0x602B, 0xE2F6, 0x602C, 0x904F, 0x602D, 0x9050, 0x602E, 0x9051, 0x602F, 0xC7D3, 0x6030, 0x9052, 0x6031, 0x9053, 0x6032, 0x9054, 0x6033, 0x9055, 0x6034, 0x9056, 0x6035, 0xE2F0, 0x6036, 0x9057, 0x6037, 0x9058, 0x6038, 0x9059, 0x6039, 0x905A, 0x603A, 0x905B, 0x603B, 0xD7DC, 0x603C, 0xEDA1, 0x603D, 0x905C, 0x603E, 0x905D, 0x603F, 0xE2F8, 0x6040, 0x905E, 0x6041, 0xEDA5, 0x6042, 0xE2FE, 0x6043, 0xCAD1, 0x6044, 0x905F, 0x6045, 0x9060, 0x6046, 0x9061, 0x6047, 0x9062, 0x6048, 0x9063, 0x6049, 0x9064, 0x604A, 0x9065, 0x604B, 0xC1B5, 0x604C, 0x9066, 0x604D, 0xBBD0, 0x604E, 0x9067, 0x604F, 0x9068, 0x6050, 0xBFD6, 0x6051, 0x9069, 0x6052, 0xBAE3, 0x6053, 0x906A, 0x6054, 0x906B, 0x6055, 0xCBA1, 0x6056, 0x906C, 0x6057, 0x906D, 0x6058, 0x906E, 0x6059, 0xEDA6, 0x605A, 0xEDA3, 0x605B, 0x906F, 0x605C, 0x9070, 0x605D, 0xEDA2, 0x605E, 0x9071, 0x605F, 0x9072, 0x6060, 0x9073, 0x6061, 0x9074, 0x6062, 0xBBD6, 0x6063, 0xEDA7, 0x6064, 0xD0F4, 0x6065, 0x9075, 0x6066, 0x9076, 0x6067, 0xEDA4, 0x6068, 0xBADE, 0x6069, 0xB6F7, 0x606A, 0xE3A1, 0x606B, 0xB6B2, 0x606C, 0xCCF1, 0x606D, 0xB9A7, 0x606E, 0x9077, 0x606F, 0xCFA2, 0x6070, 0xC7A1, 0x6071, 0x9078, 0x6072, 0x9079, 0x6073, 0xBFD2, 0x6074, 0x907A, 0x6075, 0x907B, 0x6076, 0xB6F1, 0x6077, 0x907C, 0x6078, 0xE2FA, 0x6079, 0xE2FB, 0x607A, 0xE2FD, 0x607B, 0xE2FC, 0x607C, 0xC4D5, 0x607D, 0xE3A2, 0x607E, 0x907D, 0x607F, 0xD3C1, 0x6080, 0x907E, 0x6081, 0x9080, 0x6082, 0x9081, 0x6083, 0xE3A7, 0x6084, 0xC7C4, 0x6085, 0x9082, 0x6086, 0x9083, 0x6087, 0x9084, 0x6088, 0x9085, 0x6089, 0xCFA4, 0x608A, 0x9086, 0x608B, 0x9087, 0x608C, 0xE3A9, 0x608D, 0xBAB7, 0x608E, 0x9088, 0x608F, 0x9089, 0x6090, 0x908A, 0x6091, 0x908B, 0x6092, 0xE3A8, 0x6093, 0x908C, 0x6094, 0xBBDA, 0x6095, 0x908D, 0x6096, 0xE3A3, 0x6097, 0x908E, 0x6098, 0x908F, 0x6099, 0x9090, 0x609A, 0xE3A4, 0x609B, 0xE3AA, 0x609C, 0x9091, 0x609D, 0xE3A6, 0x609E, 0x9092, 0x609F, 0xCEF2, 0x60A0, 0xD3C6, 0x60A1, 0x9093, 0x60A2, 0x9094, 0x60A3, 0xBBBC, 0x60A4, 0x9095, 0x60A5, 0x9096, 0x60A6, 0xD4C3, 0x60A7, 0x9097, 0x60A8, 0xC4FA, 0x60A9, 0x9098, 0x60AA, 0x9099, 0x60AB, 0xEDA8, 0x60AC, 0xD0FC, 0x60AD, 0xE3A5, 0x60AE, 0x909A, 0x60AF, 0xC3F5, 0x60B0, 0x909B, 0x60B1, 0xE3AD, 0x60B2, 0xB1AF, 0x60B3, 0x909C, 0x60B4, 0xE3B2, 0x60B5, 0x909D, 0x60B6, 0x909E, 0x60B7, 0x909F, 0x60B8, 0xBCC2, 0x60B9, 0x90A0, 0x60BA, 0x90A1, 0x60BB, 0xE3AC, 0x60BC, 0xB5BF, 0x60BD, 0x90A2, 0x60BE, 0x90A3, 0x60BF, 0x90A4, 0x60C0, 0x90A5, 0x60C1, 0x90A6, 0x60C2, 0x90A7, 0x60C3, 0x90A8, 0x60C4, 0x90A9, 0x60C5, 0xC7E9, 0x60C6, 0xE3B0, 0x60C7, 0x90AA, 0x60C8, 0x90AB, 0x60C9, 0x90AC, 0x60CA, 0xBEAA, 0x60CB, 0xCDEF, 0x60CC, 0x90AD, 0x60CD, 0x90AE, 0x60CE, 0x90AF, 0x60CF, 0x90B0, 0x60D0, 0x90B1, 0x60D1, 0xBBF3, 0x60D2, 0x90B2, 0x60D3, 0x90B3, 0x60D4, 0x90B4, 0x60D5, 0xCCE8, 0x60D6, 0x90B5, 0x60D7, 0x90B6, 0x60D8, 0xE3AF, 0x60D9, 0x90B7, 0x60DA, 0xE3B1, 0x60DB, 0x90B8, 0x60DC, 0xCFA7, 0x60DD, 0xE3AE, 0x60DE, 0x90B9, 0x60DF, 0xCEA9, 0x60E0, 0xBBDD, 0x60E1, 0x90BA, 0x60E2, 0x90BB, 0x60E3, 0x90BC, 0x60E4, 0x90BD, 0x60E5, 0x90BE, 0x60E6, 0xB5EB, 0x60E7, 0xBEE5, 0x60E8, 0xB2D2, 0x60E9, 0xB3CD, 0x60EA, 0x90BF, 0x60EB, 0xB1B9, 0x60EC, 0xE3AB, 0x60ED, 0xB2D1, 0x60EE, 0xB5AC, 0x60EF, 0xB9DF, 0x60F0, 0xB6E8, 0x60F1, 0x90C0, 0x60F2, 0x90C1, 0x60F3, 0xCFEB, 0x60F4, 0xE3B7, 0x60F5, 0x90C2, 0x60F6, 0xBBCC, 0x60F7, 0x90C3, 0x60F8, 0x90C4, 0x60F9, 0xC8C7, 0x60FA, 0xD0CA, 0x60FB, 0x90C5, 0x60FC, 0x90C6, 0x60FD, 0x90C7, 0x60FE, 0x90C8, 0x60FF, 0x90C9, 0x6100, 0xE3B8, 0x6101, 0xB3EE, 0x6102, 0x90CA, 0x6103, 0x90CB, 0x6104, 0x90CC, 0x6105, 0x90CD, 0x6106, 0xEDA9, 0x6107, 0x90CE, 0x6108, 0xD3FA, 0x6109, 0xD3E4, 0x610A, 0x90CF, 0x610B, 0x90D0, 0x610C, 0x90D1, 0x610D, 0xEDAA, 0x610E, 0xE3B9, 0x610F, 0xD2E2, 0x6110, 0x90D2, 0x6111, 0x90D3, 0x6112, 0x90D4, 0x6113, 0x90D5, 0x6114, 0x90D6, 0x6115, 0xE3B5, 0x6116, 0x90D7, 0x6117, 0x90D8, 0x6118, 0x90D9, 0x6119, 0x90DA, 0x611A, 0xD3DE, 0x611B, 0x90DB, 0x611C, 0x90DC, 0x611D, 0x90DD, 0x611E, 0x90DE, 0x611F, 0xB8D0, 0x6120, 0xE3B3, 0x6121, 0x90DF, 0x6122, 0x90E0, 0x6123, 0xE3B6, 0x6124, 0xB7DF, 0x6125, 0x90E1, 0x6126, 0xE3B4, 0x6127, 0xC0A2, 0x6128, 0x90E2, 0x6129, 0x90E3, 0x612A, 0x90E4, 0x612B, 0xE3BA, 0x612C, 0x90E5, 0x612D, 0x90E6, 0x612E, 0x90E7, 0x612F, 0x90E8, 0x6130, 0x90E9, 0x6131, 0x90EA, 0x6132, 0x90EB, 0x6133, 0x90EC, 0x6134, 0x90ED, 0x6135, 0x90EE, 0x6136, 0x90EF, 0x6137, 0x90F0, 0x6138, 0x90F1, 0x6139, 0x90F2, 0x613A, 0x90F3, 0x613B, 0x90F4, 0x613C, 0x90F5, 0x613D, 0x90F6, 0x613E, 0x90F7, 0x613F, 0xD4B8, 0x6140, 0x90F8, 0x6141, 0x90F9, 0x6142, 0x90FA, 0x6143, 0x90FB, 0x6144, 0x90FC, 0x6145, 0x90FD, 0x6146, 0x90FE, 0x6147, 0x9140, 0x6148, 0xB4C8, 0x6149, 0x9141, 0x614A, 0xE3BB, 0x614B, 0x9142, 0x614C, 0xBBC5, 0x614D, 0x9143, 0x614E, 0xC9F7, 0x614F, 0x9144, 0x6150, 0x9145, 0x6151, 0xC9E5, 0x6152, 0x9146, 0x6153, 0x9147, 0x6154, 0x9148, 0x6155, 0xC4BD, 0x6156, 0x9149, 0x6157, 0x914A, 0x6158, 0x914B, 0x6159, 0x914C, 0x615A, 0x914D, 0x615B, 0x914E, 0x615C, 0x914F, 0x615D, 0xEDAB, 0x615E, 0x9150, 0x615F, 0x9151, 0x6160, 0x9152, 0x6161, 0x9153, 0x6162, 0xC2FD, 0x6163, 0x9154, 0x6164, 0x9155, 0x6165, 0x9156, 0x6166, 0x9157, 0x6167, 0xBBDB, 0x6168, 0xBFAE, 0x6169, 0x9158, 0x616A, 0x9159, 0x616B, 0x915A, 0x616C, 0x915B, 0x616D, 0x915C, 0x616E, 0x915D, 0x616F, 0x915E, 0x6170, 0xCEBF, 0x6171, 0x915F, 0x6172, 0x9160, 0x6173, 0x9161, 0x6174, 0x9162, 0x6175, 0xE3BC, 0x6176, 0x9163, 0x6177, 0xBFB6, 0x6178, 0x9164, 0x6179, 0x9165, 0x617A, 0x9166, 0x617B, 0x9167, 0x617C, 0x9168, 0x617D, 0x9169, 0x617E, 0x916A, 0x617F, 0x916B, 0x6180, 0x916C, 0x6181, 0x916D, 0x6182, 0x916E, 0x6183, 0x916F, 0x6184, 0x9170, 0x6185, 0x9171, 0x6186, 0x9172, 0x6187, 0x9173, 0x6188, 0x9174, 0x6189, 0x9175, 0x618A, 0x9176, 0x618B, 0xB1EF, 0x618C, 0x9177, 0x618D, 0x9178, 0x618E, 0xD4F7, 0x618F, 0x9179, 0x6190, 0x917A, 0x6191, 0x917B, 0x6192, 0x917C, 0x6193, 0x917D, 0x6194, 0xE3BE, 0x6195, 0x917E, 0x6196, 0x9180, 0x6197, 0x9181, 0x6198, 0x9182, 0x6199, 0x9183, 0x619A, 0x9184, 0x619B, 0x9185, 0x619C, 0x9186, 0x619D, 0xEDAD, 0x619E, 0x9187, 0x619F, 0x9188, 0x61A0, 0x9189, 0x61A1, 0x918A, 0x61A2, 0x918B, 0x61A3, 0x918C, 0x61A4, 0x918D, 0x61A5, 0x918E, 0x61A6, 0x918F, 0x61A7, 0xE3BF, 0x61A8, 0xBAA9, 0x61A9, 0xEDAC, 0x61AA, 0x9190, 0x61AB, 0x9191, 0x61AC, 0xE3BD, 0x61AD, 0x9192, 0x61AE, 0x9193, 0x61AF, 0x9194, 0x61B0, 0x9195, 0x61B1, 0x9196, 0x61B2, 0x9197, 0x61B3, 0x9198, 0x61B4, 0x9199, 0x61B5, 0x919A, 0x61B6, 0x919B, 0x61B7, 0xE3C0, 0x61B8, 0x919C, 0x61B9, 0x919D, 0x61BA, 0x919E, 0x61BB, 0x919F, 0x61BC, 0x91A0, 0x61BD, 0x91A1, 0x61BE, 0xBAB6, 0x61BF, 0x91A2, 0x61C0, 0x91A3, 0x61C1, 0x91A4, 0x61C2, 0xB6AE, 0x61C3, 0x91A5, 0x61C4, 0x91A6, 0x61C5, 0x91A7, 0x61C6, 0x91A8, 0x61C7, 0x91A9, 0x61C8, 0xD0B8, 0x61C9, 0x91AA, 0x61CA, 0xB0C3, 0x61CB, 0xEDAE, 0x61CC, 0x91AB, 0x61CD, 0x91AC, 0x61CE, 0x91AD, 0x61CF, 0x91AE, 0x61D0, 0x91AF, 0x61D1, 0xEDAF, 0x61D2, 0xC0C1, 0x61D3, 0x91B0, 0x61D4, 0xE3C1, 0x61D5, 0x91B1, 0x61D6, 0x91B2, 0x61D7, 0x91B3, 0x61D8, 0x91B4, 0x61D9, 0x91B5, 0x61DA, 0x91B6, 0x61DB, 0x91B7, 0x61DC, 0x91B8, 0x61DD, 0x91B9, 0x61DE, 0x91BA, 0x61DF, 0x91BB, 0x61E0, 0x91BC, 0x61E1, 0x91BD, 0x61E2, 0x91BE, 0x61E3, 0x91BF, 0x61E4, 0x91C0, 0x61E5, 0x91C1, 0x61E6, 0xC5B3, 0x61E7, 0x91C2, 0x61E8, 0x91C3, 0x61E9, 0x91C4, 0x61EA, 0x91C5, 0x61EB, 0x91C6, 0x61EC, 0x91C7, 0x61ED, 0x91C8, 0x61EE, 0x91C9, 0x61EF, 0x91CA, 0x61F0, 0x91CB, 0x61F1, 0x91CC, 0x61F2, 0x91CD, 0x61F3, 0x91CE, 0x61F4, 0x91CF, 0x61F5, 0xE3C2, 0x61F6, 0x91D0, 0x61F7, 0x91D1, 0x61F8, 0x91D2, 0x61F9, 0x91D3, 0x61FA, 0x91D4, 0x61FB, 0x91D5, 0x61FC, 0x91D6, 0x61FD, 0x91D7, 0x61FE, 0x91D8, 0x61FF, 0xDCB2, 0x6200, 0x91D9, 0x6201, 0x91DA, 0x6202, 0x91DB, 0x6203, 0x91DC, 0x6204, 0x91DD, 0x6205, 0x91DE, 0x6206, 0xEDB0, 0x6207, 0x91DF, 0x6208, 0xB8EA, 0x6209, 0x91E0, 0x620A, 0xCEEC, 0x620B, 0xEAA7, 0x620C, 0xD0E7, 0x620D, 0xCAF9, 0x620E, 0xC8D6, 0x620F, 0xCFB7, 0x6210, 0xB3C9, 0x6211, 0xCED2, 0x6212, 0xBDE4, 0x6213, 0x91E1, 0x6214, 0x91E2, 0x6215, 0xE3DE, 0x6216, 0xBBF2, 0x6217, 0xEAA8, 0x6218, 0xD5BD, 0x6219, 0x91E3, 0x621A, 0xC6DD, 0x621B, 0xEAA9, 0x621C, 0x91E4, 0x621D, 0x91E5, 0x621E, 0x91E6, 0x621F, 0xEAAA, 0x6220, 0x91E7, 0x6221, 0xEAAC, 0x6222, 0xEAAB, 0x6223, 0x91E8, 0x6224, 0xEAAE, 0x6225, 0xEAAD, 0x6226, 0x91E9, 0x6227, 0x91EA, 0x6228, 0x91EB, 0x6229, 0x91EC, 0x622A, 0xBDD8, 0x622B, 0x91ED, 0x622C, 0xEAAF, 0x622D, 0x91EE, 0x622E, 0xC2BE, 0x622F, 0x91EF, 0x6230, 0x91F0, 0x6231, 0x91F1, 0x6232, 0x91F2, 0x6233, 0xB4C1, 0x6234, 0xB4F7, 0x6235, 0x91F3, 0x6236, 0x91F4, 0x6237, 0xBBA7, 0x6238, 0x91F5, 0x6239, 0x91F6, 0x623A, 0x91F7, 0x623B, 0x91F8, 0x623C, 0x91F9, 0x623D, 0xECE6, 0x623E, 0xECE5, 0x623F, 0xB7BF, 0x6240, 0xCBF9, 0x6241, 0xB1E2, 0x6242, 0x91FA, 0x6243, 0xECE7, 0x6244, 0x91FB, 0x6245, 0x91FC, 0x6246, 0x91FD, 0x6247, 0xC9C8, 0x6248, 0xECE8, 0x6249, 0xECE9, 0x624A, 0x91FE, 0x624B, 0xCAD6, 0x624C, 0xDED0, 0x624D, 0xB2C5, 0x624E, 0xD4FA, 0x624F, 0x9240, 0x6250, 0x9241, 0x6251, 0xC6CB, 0x6252, 0xB0C7, 0x6253, 0xB4F2, 0x6254, 0xC8D3, 0x6255, 0x9242, 0x6256, 0x9243, 0x6257, 0x9244, 0x6258, 0xCDD0, 0x6259, 0x9245, 0x625A, 0x9246, 0x625B, 0xBFB8, 0x625C, 0x9247, 0x625D, 0x9248, 0x625E, 0x9249, 0x625F, 0x924A, 0x6260, 0x924B, 0x6261, 0x924C, 0x6262, 0x924D, 0x6263, 0xBFDB, 0x6264, 0x924E, 0x6265, 0x924F, 0x6266, 0xC7A4, 0x6267, 0xD6B4, 0x6268, 0x9250, 0x6269, 0xC0A9, 0x626A, 0xDED1, 0x626B, 0xC9A8, 0x626C, 0xD1EF, 0x626D, 0xC5A4, 0x626E, 0xB0E7, 0x626F, 0xB3B6, 0x6270, 0xC8C5, 0x6271, 0x9251, 0x6272, 0x9252, 0x6273, 0xB0E2, 0x6274, 0x9253, 0x6275, 0x9254, 0x6276, 0xB7F6, 0x6277, 0x9255, 0x6278, 0x9256, 0x6279, 0xC5FA, 0x627A, 0x9257, 0x627B, 0x9258, 0x627C, 0xB6F3, 0x627D, 0x9259, 0x627E, 0xD5D2, 0x627F, 0xB3D0, 0x6280, 0xBCBC, 0x6281, 0x925A, 0x6282, 0x925B, 0x6283, 0x925C, 0x6284, 0xB3AD, 0x6285, 0x925D, 0x6286, 0x925E, 0x6287, 0x925F, 0x6288, 0x9260, 0x6289, 0xBEF1, 0x628A, 0xB0D1, 0x628B, 0x9261, 0x628C, 0x9262, 0x628D, 0x9263, 0x628E, 0x9264, 0x628F, 0x9265, 0x6290, 0x9266, 0x6291, 0xD2D6, 0x6292, 0xCAE3, 0x6293, 0xD7A5, 0x6294, 0x9267, 0x6295, 0xCDB6, 0x6296, 0xB6B6, 0x6297, 0xBFB9, 0x6298, 0xD5DB, 0x6299, 0x9268, 0x629A, 0xB8A7, 0x629B, 0xC5D7, 0x629C, 0x9269, 0x629D, 0x926A, 0x629E, 0x926B, 0x629F, 0xDED2, 0x62A0, 0xBFD9, 0x62A1, 0xC2D5, 0x62A2, 0xC7C0, 0x62A3, 0x926C, 0x62A4, 0xBBA4, 0x62A5, 0xB1A8, 0x62A6, 0x926D, 0x62A7, 0x926E, 0x62A8, 0xC5EA, 0x62A9, 0x926F, 0x62AA, 0x9270, 0x62AB, 0xC5FB, 0x62AC, 0xCCA7, 0x62AD, 0x9271, 0x62AE, 0x9272, 0x62AF, 0x9273, 0x62B0, 0x9274, 0x62B1, 0xB1A7, 0x62B2, 0x9275, 0x62B3, 0x9276, 0x62B4, 0x9277, 0x62B5, 0xB5D6, 0x62B6, 0x9278, 0x62B7, 0x9279, 0x62B8, 0x927A, 0x62B9, 0xC4A8, 0x62BA, 0x927B, 0x62BB, 0xDED3, 0x62BC, 0xD1BA, 0x62BD, 0xB3E9, 0x62BE, 0x927C, 0x62BF, 0xC3F2, 0x62C0, 0x927D, 0x62C1, 0x927E, 0x62C2, 0xB7F7, 0x62C3, 0x9280, 0x62C4, 0xD6F4, 0x62C5, 0xB5A3, 0x62C6, 0xB2F0, 0x62C7, 0xC4B4, 0x62C8, 0xC4E9, 0x62C9, 0xC0AD, 0x62CA, 0xDED4, 0x62CB, 0x9281, 0x62CC, 0xB0E8, 0x62CD, 0xC5C4, 0x62CE, 0xC1E0, 0x62CF, 0x9282, 0x62D0, 0xB9D5, 0x62D1, 0x9283, 0x62D2, 0xBEDC, 0x62D3, 0xCDD8, 0x62D4, 0xB0CE, 0x62D5, 0x9284, 0x62D6, 0xCDCF, 0x62D7, 0xDED6, 0x62D8, 0xBED0, 0x62D9, 0xD7BE, 0x62DA, 0xDED5, 0x62DB, 0xD5D0, 0x62DC, 0xB0DD, 0x62DD, 0x9285, 0x62DE, 0x9286, 0x62DF, 0xC4E2, 0x62E0, 0x9287, 0x62E1, 0x9288, 0x62E2, 0xC2A3, 0x62E3, 0xBCF0, 0x62E4, 0x9289, 0x62E5, 0xD3B5, 0x62E6, 0xC0B9, 0x62E7, 0xC5A1, 0x62E8, 0xB2A6, 0x62E9, 0xD4F1, 0x62EA, 0x928A, 0x62EB, 0x928B, 0x62EC, 0xC0A8, 0x62ED, 0xCAC3, 0x62EE, 0xDED7, 0x62EF, 0xD5FC, 0x62F0, 0x928C, 0x62F1, 0xB9B0, 0x62F2, 0x928D, 0x62F3, 0xC8AD, 0x62F4, 0xCBA9, 0x62F5, 0x928E, 0x62F6, 0xDED9, 0x62F7, 0xBFBD, 0x62F8, 0x928F, 0x62F9, 0x9290, 0x62FA, 0x9291, 0x62FB, 0x9292, 0x62FC, 0xC6B4, 0x62FD, 0xD7A7, 0x62FE, 0xCAB0, 0x62FF, 0xC4C3, 0x6300, 0x9293, 0x6301, 0xB3D6, 0x6302, 0xB9D2, 0x6303, 0x9294, 0x6304, 0x9295, 0x6305, 0x9296, 0x6306, 0x9297, 0x6307, 0xD6B8, 0x6308, 0xEAFC, 0x6309, 0xB0B4, 0x630A, 0x9298, 0x630B, 0x9299, 0x630C, 0x929A, 0x630D, 0x929B, 0x630E, 0xBFE6, 0x630F, 0x929C, 0x6310, 0x929D, 0x6311, 0xCCF4, 0x6312, 0x929E, 0x6313, 0x929F, 0x6314, 0x92A0, 0x6315, 0x92A1, 0x6316, 0xCDDA, 0x6317, 0x92A2, 0x6318, 0x92A3, 0x6319, 0x92A4, 0x631A, 0xD6BF, 0x631B, 0xC2CE, 0x631C, 0x92A5, 0x631D, 0xCECE, 0x631E, 0xCCA2, 0x631F, 0xD0AE, 0x6320, 0xC4D3, 0x6321, 0xB5B2, 0x6322, 0xDED8, 0x6323, 0xD5F5, 0x6324, 0xBCB7, 0x6325, 0xBBD3, 0x6326, 0x92A6, 0x6327, 0x92A7, 0x6328, 0xB0A4, 0x6329, 0x92A8, 0x632A, 0xC5B2, 0x632B, 0xB4EC, 0x632C, 0x92A9, 0x632D, 0x92AA, 0x632E, 0x92AB, 0x632F, 0xD5F1, 0x6330, 0x92AC, 0x6331, 0x92AD, 0x6332, 0xEAFD, 0x6333, 0x92AE, 0x6334, 0x92AF, 0x6335, 0x92B0, 0x6336, 0x92B1, 0x6337, 0x92B2, 0x6338, 0x92B3, 0x6339, 0xDEDA, 0x633A, 0xCDA6, 0x633B, 0x92B4, 0x633C, 0x92B5, 0x633D, 0xCDEC, 0x633E, 0x92B6, 0x633F, 0x92B7, 0x6340, 0x92B8, 0x6341, 0x92B9, 0x6342, 0xCEE6, 0x6343, 0xDEDC, 0x6344, 0x92BA, 0x6345, 0xCDB1, 0x6346, 0xC0A6, 0x6347, 0x92BB, 0x6348, 0x92BC, 0x6349, 0xD7BD, 0x634A, 0x92BD, 0x634B, 0xDEDB, 0x634C, 0xB0C6, 0x634D, 0xBAB4, 0x634E, 0xC9D3, 0x634F, 0xC4F3, 0x6350, 0xBEE8, 0x6351, 0x92BE, 0x6352, 0x92BF, 0x6353, 0x92C0, 0x6354, 0x92C1, 0x6355, 0xB2B6, 0x6356, 0x92C2, 0x6357, 0x92C3, 0x6358, 0x92C4, 0x6359, 0x92C5, 0x635A, 0x92C6, 0x635B, 0x92C7, 0x635C, 0x92C8, 0x635D, 0x92C9, 0x635E, 0xC0CC, 0x635F, 0xCBF0, 0x6360, 0x92CA, 0x6361, 0xBCF1, 0x6362, 0xBBBB, 0x6363, 0xB5B7, 0x6364, 0x92CB, 0x6365, 0x92CC, 0x6366, 0x92CD, 0x6367, 0xC5F5, 0x6368, 0x92CE, 0x6369, 0xDEE6, 0x636A, 0x92CF, 0x636B, 0x92D0, 0x636C, 0x92D1, 0x636D, 0xDEE3, 0x636E, 0xBEDD, 0x636F, 0x92D2, 0x6370, 0x92D3, 0x6371, 0xDEDF, 0x6372, 0x92D4, 0x6373, 0x92D5, 0x6374, 0x92D6, 0x6375, 0x92D7, 0x6376, 0xB4B7, 0x6377, 0xBDDD, 0x6378, 0x92D8, 0x6379, 0x92D9, 0x637A, 0xDEE0, 0x637B, 0xC4ED, 0x637C, 0x92DA, 0x637D, 0x92DB, 0x637E, 0x92DC, 0x637F, 0x92DD, 0x6380, 0xCFC6, 0x6381, 0x92DE, 0x6382, 0xB5E0, 0x6383, 0x92DF, 0x6384, 0x92E0, 0x6385, 0x92E1, 0x6386, 0x92E2, 0x6387, 0xB6DE, 0x6388, 0xCADA, 0x6389, 0xB5F4, 0x638A, 0xDEE5, 0x638B, 0x92E3, 0x638C, 0xD5C6, 0x638D, 0x92E4, 0x638E, 0xDEE1, 0x638F, 0xCCCD, 0x6390, 0xC6FE, 0x6391, 0x92E5, 0x6392, 0xC5C5, 0x6393, 0x92E6, 0x6394, 0x92E7, 0x6395, 0x92E8, 0x6396, 0xD2B4, 0x6397, 0x92E9, 0x6398, 0xBEF2, 0x6399, 0x92EA, 0x639A, 0x92EB, 0x639B, 0x92EC, 0x639C, 0x92ED, 0x639D, 0x92EE, 0x639E, 0x92EF, 0x639F, 0x92F0, 0x63A0, 0xC2D3, 0x63A1, 0x92F1, 0x63A2, 0xCCBD, 0x63A3, 0xB3B8, 0x63A4, 0x92F2, 0x63A5, 0xBDD3, 0x63A6, 0x92F3, 0x63A7, 0xBFD8, 0x63A8, 0xCDC6, 0x63A9, 0xD1DA, 0x63AA, 0xB4EB, 0x63AB, 0x92F4, 0x63AC, 0xDEE4, 0x63AD, 0xDEDD, 0x63AE, 0xDEE7, 0x63AF, 0x92F5, 0x63B0, 0xEAFE, 0x63B1, 0x92F6, 0x63B2, 0x92F7, 0x63B3, 0xC2B0, 0x63B4, 0xDEE2, 0x63B5, 0x92F8, 0x63B6, 0x92F9, 0x63B7, 0xD6C0, 0x63B8, 0xB5A7, 0x63B9, 0x92FA, 0x63BA, 0xB2F4, 0x63BB, 0x92FB, 0x63BC, 0xDEE8, 0x63BD, 0x92FC, 0x63BE, 0xDEF2, 0x63BF, 0x92FD, 0x63C0, 0x92FE, 0x63C1, 0x9340, 0x63C2, 0x9341, 0x63C3, 0x9342, 0x63C4, 0xDEED, 0x63C5, 0x9343, 0x63C6, 0xDEF1, 0x63C7, 0x9344, 0x63C8, 0x9345, 0x63C9, 0xC8E0, 0x63CA, 0x9346, 0x63CB, 0x9347, 0x63CC, 0x9348, 0x63CD, 0xD7E1, 0x63CE, 0xDEEF, 0x63CF, 0xC3E8, 0x63D0, 0xCCE1, 0x63D1, 0x9349, 0x63D2, 0xB2E5, 0x63D3, 0x934A, 0x63D4, 0x934B, 0x63D5, 0x934C, 0x63D6, 0xD2BE, 0x63D7, 0x934D, 0x63D8, 0x934E, 0x63D9, 0x934F, 0x63DA, 0x9350, 0x63DB, 0x9351, 0x63DC, 0x9352, 0x63DD, 0x9353, 0x63DE, 0xDEEE, 0x63DF, 0x9354, 0x63E0, 0xDEEB, 0x63E1, 0xCED5, 0x63E2, 0x9355, 0x63E3, 0xB4A7, 0x63E4, 0x9356, 0x63E5, 0x9357, 0x63E6, 0x9358, 0x63E7, 0x9359, 0x63E8, 0x935A, 0x63E9, 0xBFAB, 0x63EA, 0xBEBE, 0x63EB, 0x935B, 0x63EC, 0x935C, 0x63ED, 0xBDD2, 0x63EE, 0x935D, 0x63EF, 0x935E, 0x63F0, 0x935F, 0x63F1, 0x9360, 0x63F2, 0xDEE9, 0x63F3, 0x9361, 0x63F4, 0xD4AE, 0x63F5, 0x9362, 0x63F6, 0xDEDE, 0x63F7, 0x9363, 0x63F8, 0xDEEA, 0x63F9, 0x9364, 0x63FA, 0x9365, 0x63FB, 0x9366, 0x63FC, 0x9367, 0x63FD, 0xC0BF, 0x63FE, 0x9368, 0x63FF, 0xDEEC, 0x6400, 0xB2F3, 0x6401, 0xB8E9, 0x6402, 0xC2A7, 0x6403, 0x9369, 0x6404, 0x936A, 0x6405, 0xBDC1, 0x6406, 0x936B, 0x6407, 0x936C, 0x6408, 0x936D, 0x6409, 0x936E, 0x640A, 0x936F, 0x640B, 0xDEF5, 0x640C, 0xDEF8, 0x640D, 0x9370, 0x640E, 0x9371, 0x640F, 0xB2AB, 0x6410, 0xB4A4, 0x6411, 0x9372, 0x6412, 0x9373, 0x6413, 0xB4EA, 0x6414, 0xC9A6, 0x6415, 0x9374, 0x6416, 0x9375, 0x6417, 0x9376, 0x6418, 0x9377, 0x6419, 0x9378, 0x641A, 0x9379, 0x641B, 0xDEF6, 0x641C, 0xCBD1, 0x641D, 0x937A, 0x641E, 0xB8E3, 0x641F, 0x937B, 0x6420, 0xDEF7, 0x6421, 0xDEFA, 0x6422, 0x937C, 0x6423, 0x937D, 0x6424, 0x937E, 0x6425, 0x9380, 0x6426, 0xDEF9, 0x6427, 0x9381, 0x6428, 0x9382, 0x6429, 0x9383, 0x642A, 0xCCC2, 0x642B, 0x9384, 0x642C, 0xB0E1, 0x642D, 0xB4EE, 0x642E, 0x9385, 0x642F, 0x9386, 0x6430, 0x9387, 0x6431, 0x9388, 0x6432, 0x9389, 0x6433, 0x938A, 0x6434, 0xE5BA, 0x6435, 0x938B, 0x6436, 0x938C, 0x6437, 0x938D, 0x6438, 0x938E, 0x6439, 0x938F, 0x643A, 0xD0AF, 0x643B, 0x9390, 0x643C, 0x9391, 0x643D, 0xB2EB, 0x643E, 0x9392, 0x643F, 0xEBA1, 0x6440, 0x9393, 0x6441, 0xDEF4, 0x6442, 0x9394, 0x6443, 0x9395, 0x6444, 0xC9E3, 0x6445, 0xDEF3, 0x6446, 0xB0DA, 0x6447, 0xD2A1, 0x6448, 0xB1F7, 0x6449, 0x9396, 0x644A, 0xCCAF, 0x644B, 0x9397, 0x644C, 0x9398, 0x644D, 0x9399, 0x644E, 0x939A, 0x644F, 0x939B, 0x6450, 0x939C, 0x6451, 0x939D, 0x6452, 0xDEF0, 0x6453, 0x939E, 0x6454, 0xCBA4, 0x6455, 0x939F, 0x6456, 0x93A0, 0x6457, 0x93A1, 0x6458, 0xD5AA, 0x6459, 0x93A2, 0x645A, 0x93A3, 0x645B, 0x93A4, 0x645C, 0x93A5, 0x645D, 0x93A6, 0x645E, 0xDEFB, 0x645F, 0x93A7, 0x6460, 0x93A8, 0x6461, 0x93A9, 0x6462, 0x93AA, 0x6463, 0x93AB, 0x6464, 0x93AC, 0x6465, 0x93AD, 0x6466, 0x93AE, 0x6467, 0xB4DD, 0x6468, 0x93AF, 0x6469, 0xC4A6, 0x646A, 0x93B0, 0x646B, 0x93B1, 0x646C, 0x93B2, 0x646D, 0xDEFD, 0x646E, 0x93B3, 0x646F, 0x93B4, 0x6470, 0x93B5, 0x6471, 0x93B6, 0x6472, 0x93B7, 0x6473, 0x93B8, 0x6474, 0x93B9, 0x6475, 0x93BA, 0x6476, 0x93BB, 0x6477, 0x93BC, 0x6478, 0xC3FE, 0x6479, 0xC4A1, 0x647A, 0xDFA1, 0x647B, 0x93BD, 0x647C, 0x93BE, 0x647D, 0x93BF, 0x647E, 0x93C0, 0x647F, 0x93C1, 0x6480, 0x93C2, 0x6481, 0x93C3, 0x6482, 0xC1CC, 0x6483, 0x93C4, 0x6484, 0xDEFC, 0x6485, 0xBEEF, 0x6486, 0x93C5, 0x6487, 0xC6B2, 0x6488, 0x93C6, 0x6489, 0x93C7, 0x648A, 0x93C8, 0x648B, 0x93C9, 0x648C, 0x93CA, 0x648D, 0x93CB, 0x648E, 0x93CC, 0x648F, 0x93CD, 0x6490, 0x93CE, 0x6491, 0xB3C5, 0x6492, 0xC8F6, 0x6493, 0x93CF, 0x6494, 0x93D0, 0x6495, 0xCBBA, 0x6496, 0xDEFE, 0x6497, 0x93D1, 0x6498, 0x93D2, 0x6499, 0xDFA4, 0x649A, 0x93D3, 0x649B, 0x93D4, 0x649C, 0x93D5, 0x649D, 0x93D6, 0x649E, 0xD7B2, 0x649F, 0x93D7, 0x64A0, 0x93D8, 0x64A1, 0x93D9, 0x64A2, 0x93DA, 0x64A3, 0x93DB, 0x64A4, 0xB3B7, 0x64A5, 0x93DC, 0x64A6, 0x93DD, 0x64A7, 0x93DE, 0x64A8, 0x93DF, 0x64A9, 0xC1C3, 0x64AA, 0x93E0, 0x64AB, 0x93E1, 0x64AC, 0xC7CB, 0x64AD, 0xB2A5, 0x64AE, 0xB4E9, 0x64AF, 0x93E2, 0x64B0, 0xD7AB, 0x64B1, 0x93E3, 0x64B2, 0x93E4, 0x64B3, 0x93E5, 0x64B4, 0x93E6, 0x64B5, 0xC4EC, 0x64B6, 0x93E7, 0x64B7, 0xDFA2, 0x64B8, 0xDFA3, 0x64B9, 0x93E8, 0x64BA, 0xDFA5, 0x64BB, 0x93E9, 0x64BC, 0xBAB3, 0x64BD, 0x93EA, 0x64BE, 0x93EB, 0x64BF, 0x93EC, 0x64C0, 0xDFA6, 0x64C1, 0x93ED, 0x64C2, 0xC0DE, 0x64C3, 0x93EE, 0x64C4, 0x93EF, 0x64C5, 0xC9C3, 0x64C6, 0x93F0, 0x64C7, 0x93F1, 0x64C8, 0x93F2, 0x64C9, 0x93F3, 0x64CA, 0x93F4, 0x64CB, 0x93F5, 0x64CC, 0x93F6, 0x64CD, 0xB2D9, 0x64CE, 0xC7E6, 0x64CF, 0x93F7, 0x64D0, 0xDFA7, 0x64D1, 0x93F8, 0x64D2, 0xC7DC, 0x64D3, 0x93F9, 0x64D4, 0x93FA, 0x64D5, 0x93FB, 0x64D6, 0x93FC, 0x64D7, 0xDFA8, 0x64D8, 0xEBA2, 0x64D9, 0x93FD, 0x64DA, 0x93FE, 0x64DB, 0x9440, 0x64DC, 0x9441, 0x64DD, 0x9442, 0x64DE, 0xCBD3, 0x64DF, 0x9443, 0x64E0, 0x9444, 0x64E1, 0x9445, 0x64E2, 0xDFAA, 0x64E3, 0x9446, 0x64E4, 0xDFA9, 0x64E5, 0x9447, 0x64E6, 0xB2C1, 0x64E7, 0x9448, 0x64E8, 0x9449, 0x64E9, 0x944A, 0x64EA, 0x944B, 0x64EB, 0x944C, 0x64EC, 0x944D, 0x64ED, 0x944E, 0x64EE, 0x944F, 0x64EF, 0x9450, 0x64F0, 0x9451, 0x64F1, 0x9452, 0x64F2, 0x9453, 0x64F3, 0x9454, 0x64F4, 0x9455, 0x64F5, 0x9456, 0x64F6, 0x9457, 0x64F7, 0x9458, 0x64F8, 0x9459, 0x64F9, 0x945A, 0x64FA, 0x945B, 0x64FB, 0x945C, 0x64FC, 0x945D, 0x64FD, 0x945E, 0x64FE, 0x945F, 0x64FF, 0x9460, 0x6500, 0xC5CA, 0x6501, 0x9461, 0x6502, 0x9462, 0x6503, 0x9463, 0x6504, 0x9464, 0x6505, 0x9465, 0x6506, 0x9466, 0x6507, 0x9467, 0x6508, 0x9468, 0x6509, 0xDFAB, 0x650A, 0x9469, 0x650B, 0x946A, 0x650C, 0x946B, 0x650D, 0x946C, 0x650E, 0x946D, 0x650F, 0x946E, 0x6510, 0x946F, 0x6511, 0x9470, 0x6512, 0xD4DC, 0x6513, 0x9471, 0x6514, 0x9472, 0x6515, 0x9473, 0x6516, 0x9474, 0x6517, 0x9475, 0x6518, 0xC8C1, 0x6519, 0x9476, 0x651A, 0x9477, 0x651B, 0x9478, 0x651C, 0x9479, 0x651D, 0x947A, 0x651E, 0x947B, 0x651F, 0x947C, 0x6520, 0x947D, 0x6521, 0x947E, 0x6522, 0x9480, 0x6523, 0x9481, 0x6524, 0x9482, 0x6525, 0xDFAC, 0x6526, 0x9483, 0x6527, 0x9484, 0x6528, 0x9485, 0x6529, 0x9486, 0x652A, 0x9487, 0x652B, 0xBEF0, 0x652C, 0x9488, 0x652D, 0x9489, 0x652E, 0xDFAD, 0x652F, 0xD6A7, 0x6530, 0x948A, 0x6531, 0x948B, 0x6532, 0x948C, 0x6533, 0x948D, 0x6534, 0xEAB7, 0x6535, 0xEBB6, 0x6536, 0xCAD5, 0x6537, 0x948E, 0x6538, 0xD8FC, 0x6539, 0xB8C4, 0x653A, 0x948F, 0x653B, 0xB9A5, 0x653C, 0x9490, 0x653D, 0x9491, 0x653E, 0xB7C5, 0x653F, 0xD5FE, 0x6540, 0x9492, 0x6541, 0x9493, 0x6542, 0x9494, 0x6543, 0x9495, 0x6544, 0x9496, 0x6545, 0xB9CA, 0x6546, 0x9497, 0x6547, 0x9498, 0x6548, 0xD0A7, 0x6549, 0xF4CD, 0x654A, 0x9499, 0x654B, 0x949A, 0x654C, 0xB5D0, 0x654D, 0x949B, 0x654E, 0x949C, 0x654F, 0xC3F4, 0x6550, 0x949D, 0x6551, 0xBEC8, 0x6552, 0x949E, 0x6553, 0x949F, 0x6554, 0x94A0, 0x6555, 0xEBB7, 0x6556, 0xB0BD, 0x6557, 0x94A1, 0x6558, 0x94A2, 0x6559, 0xBDCC, 0x655A, 0x94A3, 0x655B, 0xC1B2, 0x655C, 0x94A4, 0x655D, 0xB1D6, 0x655E, 0xB3A8, 0x655F, 0x94A5, 0x6560, 0x94A6, 0x6561, 0x94A7, 0x6562, 0xB8D2, 0x6563, 0xC9A2, 0x6564, 0x94A8, 0x6565, 0x94A9, 0x6566, 0xB6D8, 0x6567, 0x94AA, 0x6568, 0x94AB, 0x6569, 0x94AC, 0x656A, 0x94AD, 0x656B, 0xEBB8, 0x656C, 0xBEB4, 0x656D, 0x94AE, 0x656E, 0x94AF, 0x656F, 0x94B0, 0x6570, 0xCAFD, 0x6571, 0x94B1, 0x6572, 0xC7C3, 0x6573, 0x94B2, 0x6574, 0xD5FB, 0x6575, 0x94B3, 0x6576, 0x94B4, 0x6577, 0xB7F3, 0x6578, 0x94B5, 0x6579, 0x94B6, 0x657A, 0x94B7, 0x657B, 0x94B8, 0x657C, 0x94B9, 0x657D, 0x94BA, 0x657E, 0x94BB, 0x657F, 0x94BC, 0x6580, 0x94BD, 0x6581, 0x94BE, 0x6582, 0x94BF, 0x6583, 0x94C0, 0x6584, 0x94C1, 0x6585, 0x94C2, 0x6586, 0x94C3, 0x6587, 0xCEC4, 0x6588, 0x94C4, 0x6589, 0x94C5, 0x658A, 0x94C6, 0x658B, 0xD5AB, 0x658C, 0xB1F3, 0x658D, 0x94C7, 0x658E, 0x94C8, 0x658F, 0x94C9, 0x6590, 0xECB3, 0x6591, 0xB0DF, 0x6592, 0x94CA, 0x6593, 0xECB5, 0x6594, 0x94CB, 0x6595, 0x94CC, 0x6596, 0x94CD, 0x6597, 0xB6B7, 0x6598, 0x94CE, 0x6599, 0xC1CF, 0x659A, 0x94CF, 0x659B, 0xF5FA, 0x659C, 0xD0B1, 0x659D, 0x94D0, 0x659E, 0x94D1, 0x659F, 0xD5E5, 0x65A0, 0x94D2, 0x65A1, 0xCED3, 0x65A2, 0x94D3, 0x65A3, 0x94D4, 0x65A4, 0xBDEF, 0x65A5, 0xB3E2, 0x65A6, 0x94D5, 0x65A7, 0xB8AB, 0x65A8, 0x94D6, 0x65A9, 0xD5B6, 0x65AA, 0x94D7, 0x65AB, 0xEDBD, 0x65AC, 0x94D8, 0x65AD, 0xB6CF, 0x65AE, 0x94D9, 0x65AF, 0xCBB9, 0x65B0, 0xD0C2, 0x65B1, 0x94DA, 0x65B2, 0x94DB, 0x65B3, 0x94DC, 0x65B4, 0x94DD, 0x65B5, 0x94DE, 0x65B6, 0x94DF, 0x65B7, 0x94E0, 0x65B8, 0x94E1, 0x65B9, 0xB7BD, 0x65BA, 0x94E2, 0x65BB, 0x94E3, 0x65BC, 0xECB6, 0x65BD, 0xCAA9, 0x65BE, 0x94E4, 0x65BF, 0x94E5, 0x65C0, 0x94E6, 0x65C1, 0xC5D4, 0x65C2, 0x94E7, 0x65C3, 0xECB9, 0x65C4, 0xECB8, 0x65C5, 0xC2C3, 0x65C6, 0xECB7, 0x65C7, 0x94E8, 0x65C8, 0x94E9, 0x65C9, 0x94EA, 0x65CA, 0x94EB, 0x65CB, 0xD0FD, 0x65CC, 0xECBA, 0x65CD, 0x94EC, 0x65CE, 0xECBB, 0x65CF, 0xD7E5, 0x65D0, 0x94ED, 0x65D1, 0x94EE, 0x65D2, 0xECBC, 0x65D3, 0x94EF, 0x65D4, 0x94F0, 0x65D5, 0x94F1, 0x65D6, 0xECBD, 0x65D7, 0xC6EC, 0x65D8, 0x94F2, 0x65D9, 0x94F3, 0x65DA, 0x94F4, 0x65DB, 0x94F5, 0x65DC, 0x94F6, 0x65DD, 0x94F7, 0x65DE, 0x94F8, 0x65DF, 0x94F9, 0x65E0, 0xCEDE, 0x65E1, 0x94FA, 0x65E2, 0xBCC8, 0x65E3, 0x94FB, 0x65E4, 0x94FC, 0x65E5, 0xC8D5, 0x65E6, 0xB5A9, 0x65E7, 0xBEC9, 0x65E8, 0xD6BC, 0x65E9, 0xD4E7, 0x65EA, 0x94FD, 0x65EB, 0x94FE, 0x65EC, 0xD1AE, 0x65ED, 0xD0F1, 0x65EE, 0xEAB8, 0x65EF, 0xEAB9, 0x65F0, 0xEABA, 0x65F1, 0xBAB5, 0x65F2, 0x9540, 0x65F3, 0x9541, 0x65F4, 0x9542, 0x65F5, 0x9543, 0x65F6, 0xCAB1, 0x65F7, 0xBFF5, 0x65F8, 0x9544, 0x65F9, 0x9545, 0x65FA, 0xCDFA, 0x65FB, 0x9546, 0x65FC, 0x9547, 0x65FD, 0x9548, 0x65FE, 0x9549, 0x65FF, 0x954A, 0x6600, 0xEAC0, 0x6601, 0x954B, 0x6602, 0xB0BA, 0x6603, 0xEABE, 0x6604, 0x954C, 0x6605, 0x954D, 0x6606, 0xC0A5, 0x6607, 0x954E, 0x6608, 0x954F, 0x6609, 0x9550, 0x660A, 0xEABB, 0x660B, 0x9551, 0x660C, 0xB2FD, 0x660D, 0x9552, 0x660E, 0xC3F7, 0x660F, 0xBBE8, 0x6610, 0x9553, 0x6611, 0x9554, 0x6612, 0x9555, 0x6613, 0xD2D7, 0x6614, 0xCEF4, 0x6615, 0xEABF, 0x6616, 0x9556, 0x6617, 0x9557, 0x6618, 0x9558, 0x6619, 0xEABC, 0x661A, 0x9559, 0x661B, 0x955A, 0x661C, 0x955B, 0x661D, 0xEAC3, 0x661E, 0x955C, 0x661F, 0xD0C7, 0x6620, 0xD3B3, 0x6621, 0x955D, 0x6622, 0x955E, 0x6623, 0x955F, 0x6624, 0x9560, 0x6625, 0xB4BA, 0x6626, 0x9561, 0x6627, 0xC3C1, 0x6628, 0xD7F2, 0x6629, 0x9562, 0x662A, 0x9563, 0x662B, 0x9564, 0x662C, 0x9565, 0x662D, 0xD5D1, 0x662E, 0x9566, 0x662F, 0xCAC7, 0x6630, 0x9567, 0x6631, 0xEAC5, 0x6632, 0x9568, 0x6633, 0x9569, 0x6634, 0xEAC4, 0x6635, 0xEAC7, 0x6636, 0xEAC6, 0x6637, 0x956A, 0x6638, 0x956B, 0x6639, 0x956C, 0x663A, 0x956D, 0x663B, 0x956E, 0x663C, 0xD6E7, 0x663D, 0x956F, 0x663E, 0xCFD4, 0x663F, 0x9570, 0x6640, 0x9571, 0x6641, 0xEACB, 0x6642, 0x9572, 0x6643, 0xBBCE, 0x6644, 0x9573, 0x6645, 0x9574, 0x6646, 0x9575, 0x6647, 0x9576, 0x6648, 0x9577, 0x6649, 0x9578, 0x664A, 0x9579, 0x664B, 0xBDFA, 0x664C, 0xC9CE, 0x664D, 0x957A, 0x664E, 0x957B, 0x664F, 0xEACC, 0x6650, 0x957C, 0x6651, 0x957D, 0x6652, 0xC9B9, 0x6653, 0xCFFE, 0x6654, 0xEACA, 0x6655, 0xD4CE, 0x6656, 0xEACD, 0x6657, 0xEACF, 0x6658, 0x957E, 0x6659, 0x9580, 0x665A, 0xCDED, 0x665B, 0x9581, 0x665C, 0x9582, 0x665D, 0x9583, 0x665E, 0x9584, 0x665F, 0xEAC9, 0x6660, 0x9585, 0x6661, 0xEACE, 0x6662, 0x9586, 0x6663, 0x9587, 0x6664, 0xCEEE, 0x6665, 0x9588, 0x6666, 0xBBDE, 0x6667, 0x9589, 0x6668, 0xB3BF, 0x6669, 0x958A, 0x666A, 0x958B, 0x666B, 0x958C, 0x666C, 0x958D, 0x666D, 0x958E, 0x666E, 0xC6D5, 0x666F, 0xBEB0, 0x6670, 0xCEFA, 0x6671, 0x958F, 0x6672, 0x9590, 0x6673, 0x9591, 0x6674, 0xC7E7, 0x6675, 0x9592, 0x6676, 0xBEA7, 0x6677, 0xEAD0, 0x6678, 0x9593, 0x6679, 0x9594, 0x667A, 0xD6C7, 0x667B, 0x9595, 0x667C, 0x9596, 0x667D, 0x9597, 0x667E, 0xC1C0, 0x667F, 0x9598, 0x6680, 0x9599, 0x6681, 0x959A, 0x6682, 0xD4DD, 0x6683, 0x959B, 0x6684, 0xEAD1, 0x6685, 0x959C, 0x6686, 0x959D, 0x6687, 0xCFBE, 0x6688, 0x959E, 0x6689, 0x959F, 0x668A, 0x95A0, 0x668B, 0x95A1, 0x668C, 0xEAD2, 0x668D, 0x95A2, 0x668E, 0x95A3, 0x668F, 0x95A4, 0x6690, 0x95A5, 0x6691, 0xCAEE, 0x6692, 0x95A6, 0x6693, 0x95A7, 0x6694, 0x95A8, 0x6695, 0x95A9, 0x6696, 0xC5AF, 0x6697, 0xB0B5, 0x6698, 0x95AA, 0x6699, 0x95AB, 0x669A, 0x95AC, 0x669B, 0x95AD, 0x669C, 0x95AE, 0x669D, 0xEAD4, 0x669E, 0x95AF, 0x669F, 0x95B0, 0x66A0, 0x95B1, 0x66A1, 0x95B2, 0x66A2, 0x95B3, 0x66A3, 0x95B4, 0x66A4, 0x95B5, 0x66A5, 0x95B6, 0x66A6, 0x95B7, 0x66A7, 0xEAD3, 0x66A8, 0xF4DF, 0x66A9, 0x95B8, 0x66AA, 0x95B9, 0x66AB, 0x95BA, 0x66AC, 0x95BB, 0x66AD, 0x95BC, 0x66AE, 0xC4BA, 0x66AF, 0x95BD, 0x66B0, 0x95BE, 0x66B1, 0x95BF, 0x66B2, 0x95C0, 0x66B3, 0x95C1, 0x66B4, 0xB1A9, 0x66B5, 0x95C2, 0x66B6, 0x95C3, 0x66B7, 0x95C4, 0x66B8, 0x95C5, 0x66B9, 0xE5DF, 0x66BA, 0x95C6, 0x66BB, 0x95C7, 0x66BC, 0x95C8, 0x66BD, 0x95C9, 0x66BE, 0xEAD5, 0x66BF, 0x95CA, 0x66C0, 0x95CB, 0x66C1, 0x95CC, 0x66C2, 0x95CD, 0x66C3, 0x95CE, 0x66C4, 0x95CF, 0x66C5, 0x95D0, 0x66C6, 0x95D1, 0x66C7, 0x95D2, 0x66C8, 0x95D3, 0x66C9, 0x95D4, 0x66CA, 0x95D5, 0x66CB, 0x95D6, 0x66CC, 0x95D7, 0x66CD, 0x95D8, 0x66CE, 0x95D9, 0x66CF, 0x95DA, 0x66D0, 0x95DB, 0x66D1, 0x95DC, 0x66D2, 0x95DD, 0x66D3, 0x95DE, 0x66D4, 0x95DF, 0x66D5, 0x95E0, 0x66D6, 0x95E1, 0x66D7, 0x95E2, 0x66D8, 0x95E3, 0x66D9, 0xCAEF, 0x66DA, 0x95E4, 0x66DB, 0xEAD6, 0x66DC, 0xEAD7, 0x66DD, 0xC6D8, 0x66DE, 0x95E5, 0x66DF, 0x95E6, 0x66E0, 0x95E7, 0x66E1, 0x95E8, 0x66E2, 0x95E9, 0x66E3, 0x95EA, 0x66E4, 0x95EB, 0x66E5, 0x95EC, 0x66E6, 0xEAD8, 0x66E7, 0x95ED, 0x66E8, 0x95EE, 0x66E9, 0xEAD9, 0x66EA, 0x95EF, 0x66EB, 0x95F0, 0x66EC, 0x95F1, 0x66ED, 0x95F2, 0x66EE, 0x95F3, 0x66EF, 0x95F4, 0x66F0, 0xD4BB, 0x66F1, 0x95F5, 0x66F2, 0xC7FA, 0x66F3, 0xD2B7, 0x66F4, 0xB8FC, 0x66F5, 0x95F6, 0x66F6, 0x95F7, 0x66F7, 0xEAC2, 0x66F8, 0x95F8, 0x66F9, 0xB2DC, 0x66FA, 0x95F9, 0x66FB, 0x95FA, 0x66FC, 0xC2FC, 0x66FD, 0x95FB, 0x66FE, 0xD4F8, 0x66FF, 0xCCE6, 0x6700, 0xD7EE, 0x6701, 0x95FC, 0x6702, 0x95FD, 0x6703, 0x95FE, 0x6704, 0x9640, 0x6705, 0x9641, 0x6706, 0x9642, 0x6707, 0x9643, 0x6708, 0xD4C2, 0x6709, 0xD3D0, 0x670A, 0xEBC3, 0x670B, 0xC5F3, 0x670C, 0x9644, 0x670D, 0xB7FE, 0x670E, 0x9645, 0x670F, 0x9646, 0x6710, 0xEBD4, 0x6711, 0x9647, 0x6712, 0x9648, 0x6713, 0x9649, 0x6714, 0xCBB7, 0x6715, 0xEBDE, 0x6716, 0x964A, 0x6717, 0xC0CA, 0x6718, 0x964B, 0x6719, 0x964C, 0x671A, 0x964D, 0x671B, 0xCDFB, 0x671C, 0x964E, 0x671D, 0xB3AF, 0x671E, 0x964F, 0x671F, 0xC6DA, 0x6720, 0x9650, 0x6721, 0x9651, 0x6722, 0x9652, 0x6723, 0x9653, 0x6724, 0x9654, 0x6725, 0x9655, 0x6726, 0xEBFC, 0x6727, 0x9656, 0x6728, 0xC4BE, 0x6729, 0x9657, 0x672A, 0xCEB4, 0x672B, 0xC4A9, 0x672C, 0xB1BE, 0x672D, 0xD4FD, 0x672E, 0x9658, 0x672F, 0xCAF5, 0x6730, 0x9659, 0x6731, 0xD6EC, 0x6732, 0x965A, 0x6733, 0x965B, 0x6734, 0xC6D3, 0x6735, 0xB6E4, 0x6736, 0x965C, 0x6737, 0x965D, 0x6738, 0x965E, 0x6739, 0x965F, 0x673A, 0xBBFA, 0x673B, 0x9660, 0x673C, 0x9661, 0x673D, 0xD0E0, 0x673E, 0x9662, 0x673F, 0x9663, 0x6740, 0xC9B1, 0x6741, 0x9664, 0x6742, 0xD4D3, 0x6743, 0xC8A8, 0x6744, 0x9665, 0x6745, 0x9666, 0x6746, 0xB8CB, 0x6747, 0x9667, 0x6748, 0xE8BE, 0x6749, 0xC9BC, 0x674A, 0x9668, 0x674B, 0x9669, 0x674C, 0xE8BB, 0x674D, 0x966A, 0x674E, 0xC0EE, 0x674F, 0xD0D3, 0x6750, 0xB2C4, 0x6751, 0xB4E5, 0x6752, 0x966B, 0x6753, 0xE8BC, 0x6754, 0x966C, 0x6755, 0x966D, 0x6756, 0xD5C8, 0x6757, 0x966E, 0x6758, 0x966F, 0x6759, 0x9670, 0x675A, 0x9671, 0x675B, 0x9672, 0x675C, 0xB6C5, 0x675D, 0x9673, 0x675E, 0xE8BD, 0x675F, 0xCAF8, 0x6760, 0xB8DC, 0x6761, 0xCCF5, 0x6762, 0x9674, 0x6763, 0x9675, 0x6764, 0x9676, 0x6765, 0xC0B4, 0x6766, 0x9677, 0x6767, 0x9678, 0x6768, 0xD1EE, 0x6769, 0xE8BF, 0x676A, 0xE8C2, 0x676B, 0x9679, 0x676C, 0x967A, 0x676D, 0xBABC, 0x676E, 0x967B, 0x676F, 0xB1AD, 0x6770, 0xBDDC, 0x6771, 0x967C, 0x6772, 0xEABD, 0x6773, 0xE8C3, 0x6774, 0x967D, 0x6775, 0xE8C6, 0x6776, 0x967E, 0x6777, 0xE8CB, 0x6778, 0x9680, 0x6779, 0x9681, 0x677A, 0x9682, 0x677B, 0x9683, 0x677C, 0xE8CC, 0x677D, 0x9684, 0x677E, 0xCBC9, 0x677F, 0xB0E5, 0x6780, 0x9685, 0x6781, 0xBCAB, 0x6782, 0x9686, 0x6783, 0x9687, 0x6784, 0xB9B9, 0x6785, 0x9688, 0x6786, 0x9689, 0x6787, 0xE8C1, 0x6788, 0x968A, 0x6789, 0xCDF7, 0x678A, 0x968B, 0x678B, 0xE8CA, 0x678C, 0x968C, 0x678D, 0x968D, 0x678E, 0x968E, 0x678F, 0x968F, 0x6790, 0xCEF6, 0x6791, 0x9690, 0x6792, 0x9691, 0x6793, 0x9692, 0x6794, 0x9693, 0x6795, 0xD5ED, 0x6796, 0x9694, 0x6797, 0xC1D6, 0x6798, 0xE8C4, 0x6799, 0x9695, 0x679A, 0xC3B6, 0x679B, 0x9696, 0x679C, 0xB9FB, 0x679D, 0xD6A6, 0x679E, 0xE8C8, 0x679F, 0x9697, 0x67A0, 0x9698, 0x67A1, 0x9699, 0x67A2, 0xCAE0, 0x67A3, 0xD4E6, 0x67A4, 0x969A, 0x67A5, 0xE8C0, 0x67A6, 0x969B, 0x67A7, 0xE8C5, 0x67A8, 0xE8C7, 0x67A9, 0x969C, 0x67AA, 0xC7B9, 0x67AB, 0xB7E3, 0x67AC, 0x969D, 0x67AD, 0xE8C9, 0x67AE, 0x969E, 0x67AF, 0xBFDD, 0x67B0, 0xE8D2, 0x67B1, 0x969F, 0x67B2, 0x96A0, 0x67B3, 0xE8D7, 0x67B4, 0x96A1, 0x67B5, 0xE8D5, 0x67B6, 0xBCDC, 0x67B7, 0xBCCF, 0x67B8, 0xE8DB, 0x67B9, 0x96A2, 0x67BA, 0x96A3, 0x67BB, 0x96A4, 0x67BC, 0x96A5, 0x67BD, 0x96A6, 0x67BE, 0x96A7, 0x67BF, 0x96A8, 0x67C0, 0x96A9, 0x67C1, 0xE8DE, 0x67C2, 0x96AA, 0x67C3, 0xE8DA, 0x67C4, 0xB1FA, 0x67C5, 0x96AB, 0x67C6, 0x96AC, 0x67C7, 0x96AD, 0x67C8, 0x96AE, 0x67C9, 0x96AF, 0x67CA, 0x96B0, 0x67CB, 0x96B1, 0x67CC, 0x96B2, 0x67CD, 0x96B3, 0x67CE, 0x96B4, 0x67CF, 0xB0D8, 0x67D0, 0xC4B3, 0x67D1, 0xB8CC, 0x67D2, 0xC6E2, 0x67D3, 0xC8BE, 0x67D4, 0xC8E1, 0x67D5, 0x96B5, 0x67D6, 0x96B6, 0x67D7, 0x96B7, 0x67D8, 0xE8CF, 0x67D9, 0xE8D4, 0x67DA, 0xE8D6, 0x67DB, 0x96B8, 0x67DC, 0xB9F1, 0x67DD, 0xE8D8, 0x67DE, 0xD7F5, 0x67DF, 0x96B9, 0x67E0, 0xC4FB, 0x67E1, 0x96BA, 0x67E2, 0xE8DC, 0x67E3, 0x96BB, 0x67E4, 0x96BC, 0x67E5, 0xB2E9, 0x67E6, 0x96BD, 0x67E7, 0x96BE, 0x67E8, 0x96BF, 0x67E9, 0xE8D1, 0x67EA, 0x96C0, 0x67EB, 0x96C1, 0x67EC, 0xBCED, 0x67ED, 0x96C2, 0x67EE, 0x96C3, 0x67EF, 0xBFC2, 0x67F0, 0xE8CD, 0x67F1, 0xD6F9, 0x67F2, 0x96C4, 0x67F3, 0xC1F8, 0x67F4, 0xB2F1, 0x67F5, 0x96C5, 0x67F6, 0x96C6, 0x67F7, 0x96C7, 0x67F8, 0x96C8, 0x67F9, 0x96C9, 0x67FA, 0x96CA, 0x67FB, 0x96CB, 0x67FC, 0x96CC, 0x67FD, 0xE8DF, 0x67FE, 0x96CD, 0x67FF, 0xCAC1, 0x6800, 0xE8D9, 0x6801, 0x96CE, 0x6802, 0x96CF, 0x6803, 0x96D0, 0x6804, 0x96D1, 0x6805, 0xD5A4, 0x6806, 0x96D2, 0x6807, 0xB1EA, 0x6808, 0xD5BB, 0x6809, 0xE8CE, 0x680A, 0xE8D0, 0x680B, 0xB6B0, 0x680C, 0xE8D3, 0x680D, 0x96D3, 0x680E, 0xE8DD, 0x680F, 0xC0B8, 0x6810, 0x96D4, 0x6811, 0xCAF7, 0x6812, 0x96D5, 0x6813, 0xCBA8, 0x6814, 0x96D6, 0x6815, 0x96D7, 0x6816, 0xC6DC, 0x6817, 0xC0F5, 0x6818, 0x96D8, 0x6819, 0x96D9, 0x681A, 0x96DA, 0x681B, 0x96DB, 0x681C, 0x96DC, 0x681D, 0xE8E9, 0x681E, 0x96DD, 0x681F, 0x96DE, 0x6820, 0x96DF, 0x6821, 0xD0A3, 0x6822, 0x96E0, 0x6823, 0x96E1, 0x6824, 0x96E2, 0x6825, 0x96E3, 0x6826, 0x96E4, 0x6827, 0x96E5, 0x6828, 0x96E6, 0x6829, 0xE8F2, 0x682A, 0xD6EA, 0x682B, 0x96E7, 0x682C, 0x96E8, 0x682D, 0x96E9, 0x682E, 0x96EA, 0x682F, 0x96EB, 0x6830, 0x96EC, 0x6831, 0x96ED, 0x6832, 0xE8E0, 0x6833, 0xE8E1, 0x6834, 0x96EE, 0x6835, 0x96EF, 0x6836, 0x96F0, 0x6837, 0xD1F9, 0x6838, 0xBACB, 0x6839, 0xB8F9, 0x683A, 0x96F1, 0x683B, 0x96F2, 0x683C, 0xB8F1, 0x683D, 0xD4D4, 0x683E, 0xE8EF, 0x683F, 0x96F3, 0x6840, 0xE8EE, 0x6841, 0xE8EC, 0x6842, 0xB9F0, 0x6843, 0xCCD2, 0x6844, 0xE8E6, 0x6845, 0xCEA6, 0x6846, 0xBFF2, 0x6847, 0x96F4, 0x6848, 0xB0B8, 0x6849, 0xE8F1, 0x684A, 0xE8F0, 0x684B, 0x96F5, 0x684C, 0xD7C0, 0x684D, 0x96F6, 0x684E, 0xE8E4, 0x684F, 0x96F7, 0x6850, 0xCDA9, 0x6851, 0xC9A3, 0x6852, 0x96F8, 0x6853, 0xBBB8, 0x6854, 0xBDDB, 0x6855, 0xE8EA, 0x6856, 0x96F9, 0x6857, 0x96FA, 0x6858, 0x96FB, 0x6859, 0x96FC, 0x685A, 0x96FD, 0x685B, 0x96FE, 0x685C, 0x9740, 0x685D, 0x9741, 0x685E, 0x9742, 0x685F, 0x9743, 0x6860, 0xE8E2, 0x6861, 0xE8E3, 0x6862, 0xE8E5, 0x6863, 0xB5B5, 0x6864, 0xE8E7, 0x6865, 0xC7C5, 0x6866, 0xE8EB, 0x6867, 0xE8ED, 0x6868, 0xBDB0, 0x6869, 0xD7AE, 0x686A, 0x9744, 0x686B, 0xE8F8, 0x686C, 0x9745, 0x686D, 0x9746, 0x686E, 0x9747, 0x686F, 0x9748, 0x6870, 0x9749, 0x6871, 0x974A, 0x6872, 0x974B, 0x6873, 0x974C, 0x6874, 0xE8F5, 0x6875, 0x974D, 0x6876, 0xCDB0, 0x6877, 0xE8F6, 0x6878, 0x974E, 0x6879, 0x974F, 0x687A, 0x9750, 0x687B, 0x9751, 0x687C, 0x9752, 0x687D, 0x9753, 0x687E, 0x9754, 0x687F, 0x9755, 0x6880, 0x9756, 0x6881, 0xC1BA, 0x6882, 0x9757, 0x6883, 0xE8E8, 0x6884, 0x9758, 0x6885, 0xC3B7, 0x6886, 0xB0F0, 0x6887, 0x9759, 0x6888, 0x975A, 0x6889, 0x975B, 0x688A, 0x975C, 0x688B, 0x975D, 0x688C, 0x975E, 0x688D, 0x975F, 0x688E, 0x9760, 0x688F, 0xE8F4, 0x6890, 0x9761, 0x6891, 0x9762, 0x6892, 0x9763, 0x6893, 0xE8F7, 0x6894, 0x9764, 0x6895, 0x9765, 0x6896, 0x9766, 0x6897, 0xB9A3, 0x6898, 0x9767, 0x6899, 0x9768, 0x689A, 0x9769, 0x689B, 0x976A, 0x689C, 0x976B, 0x689D, 0x976C, 0x689E, 0x976D, 0x689F, 0x976E, 0x68A0, 0x976F, 0x68A1, 0x9770, 0x68A2, 0xC9D2, 0x68A3, 0x9771, 0x68A4, 0x9772, 0x68A5, 0x9773, 0x68A6, 0xC3CE, 0x68A7, 0xCEE0, 0x68A8, 0xC0E6, 0x68A9, 0x9774, 0x68AA, 0x9775, 0x68AB, 0x9776, 0x68AC, 0x9777, 0x68AD, 0xCBF3, 0x68AE, 0x9778, 0x68AF, 0xCCDD, 0x68B0, 0xD0B5, 0x68B1, 0x9779, 0x68B2, 0x977A, 0x68B3, 0xCAE1, 0x68B4, 0x977B, 0x68B5, 0xE8F3, 0x68B6, 0x977C, 0x68B7, 0x977D, 0x68B8, 0x977E, 0x68B9, 0x9780, 0x68BA, 0x9781, 0x68BB, 0x9782, 0x68BC, 0x9783, 0x68BD, 0x9784, 0x68BE, 0x9785, 0x68BF, 0x9786, 0x68C0, 0xBCEC, 0x68C1, 0x9787, 0x68C2, 0xE8F9, 0x68C3, 0x9788, 0x68C4, 0x9789, 0x68C5, 0x978A, 0x68C6, 0x978B, 0x68C7, 0x978C, 0x68C8, 0x978D, 0x68C9, 0xC3DE, 0x68CA, 0x978E, 0x68CB, 0xC6E5, 0x68CC, 0x978F, 0x68CD, 0xB9F7, 0x68CE, 0x9790, 0x68CF, 0x9791, 0x68D0, 0x9792, 0x68D1, 0x9793, 0x68D2, 0xB0F4, 0x68D3, 0x9794, 0x68D4, 0x9795, 0x68D5, 0xD7D8, 0x68D6, 0x9796, 0x68D7, 0x9797, 0x68D8, 0xBCAC, 0x68D9, 0x9798, 0x68DA, 0xC5EF, 0x68DB, 0x9799, 0x68DC, 0x979A, 0x68DD, 0x979B, 0x68DE, 0x979C, 0x68DF, 0x979D, 0x68E0, 0xCCC4, 0x68E1, 0x979E, 0x68E2, 0x979F, 0x68E3, 0xE9A6, 0x68E4, 0x97A0, 0x68E5, 0x97A1, 0x68E6, 0x97A2, 0x68E7, 0x97A3, 0x68E8, 0x97A4, 0x68E9, 0x97A5, 0x68EA, 0x97A6, 0x68EB, 0x97A7, 0x68EC, 0x97A8, 0x68ED, 0x97A9, 0x68EE, 0xC9AD, 0x68EF, 0x97AA, 0x68F0, 0xE9A2, 0x68F1, 0xC0E2, 0x68F2, 0x97AB, 0x68F3, 0x97AC, 0x68F4, 0x97AD, 0x68F5, 0xBFC3, 0x68F6, 0x97AE, 0x68F7, 0x97AF, 0x68F8, 0x97B0, 0x68F9, 0xE8FE, 0x68FA, 0xB9D7, 0x68FB, 0x97B1, 0x68FC, 0xE8FB, 0x68FD, 0x97B2, 0x68FE, 0x97B3, 0x68FF, 0x97B4, 0x6900, 0x97B5, 0x6901, 0xE9A4, 0x6902, 0x97B6, 0x6903, 0x97B7, 0x6904, 0x97B8, 0x6905, 0xD2CE, 0x6906, 0x97B9, 0x6907, 0x97BA, 0x6908, 0x97BB, 0x6909, 0x97BC, 0x690A, 0x97BD, 0x690B, 0xE9A3, 0x690C, 0x97BE, 0x690D, 0xD6B2, 0x690E, 0xD7B5, 0x690F, 0x97BF, 0x6910, 0xE9A7, 0x6911, 0x97C0, 0x6912, 0xBDB7, 0x6913, 0x97C1, 0x6914, 0x97C2, 0x6915, 0x97C3, 0x6916, 0x97C4, 0x6917, 0x97C5, 0x6918, 0x97C6, 0x6919, 0x97C7, 0x691A, 0x97C8, 0x691B, 0x97C9, 0x691C, 0x97CA, 0x691D, 0x97CB, 0x691E, 0x97CC, 0x691F, 0xE8FC, 0x6920, 0xE8FD, 0x6921, 0x97CD, 0x6922, 0x97CE, 0x6923, 0x97CF, 0x6924, 0xE9A1, 0x6925, 0x97D0, 0x6926, 0x97D1, 0x6927, 0x97D2, 0x6928, 0x97D3, 0x6929, 0x97D4, 0x692A, 0x97D5, 0x692B, 0x97D6, 0x692C, 0x97D7, 0x692D, 0xCDD6, 0x692E, 0x97D8, 0x692F, 0x97D9, 0x6930, 0xD2AC, 0x6931, 0x97DA, 0x6932, 0x97DB, 0x6933, 0x97DC, 0x6934, 0xE9B2, 0x6935, 0x97DD, 0x6936, 0x97DE, 0x6937, 0x97DF, 0x6938, 0x97E0, 0x6939, 0xE9A9, 0x693A, 0x97E1, 0x693B, 0x97E2, 0x693C, 0x97E3, 0x693D, 0xB4AA, 0x693E, 0x97E4, 0x693F, 0xB4BB, 0x6940, 0x97E5, 0x6941, 0x97E6, 0x6942, 0xE9AB, 0x6943, 0x97E7, 0x6944, 0x97E8, 0x6945, 0x97E9, 0x6946, 0x97EA, 0x6947, 0x97EB, 0x6948, 0x97EC, 0x6949, 0x97ED, 0x694A, 0x97EE, 0x694B, 0x97EF, 0x694C, 0x97F0, 0x694D, 0x97F1, 0x694E, 0x97F2, 0x694F, 0x97F3, 0x6950, 0x97F4, 0x6951, 0x97F5, 0x6952, 0x97F6, 0x6953, 0x97F7, 0x6954, 0xD0A8, 0x6955, 0x97F8, 0x6956, 0x97F9, 0x6957, 0xE9A5, 0x6958, 0x97FA, 0x6959, 0x97FB, 0x695A, 0xB3FE, 0x695B, 0x97FC, 0x695C, 0x97FD, 0x695D, 0xE9AC, 0x695E, 0xC0E3, 0x695F, 0x97FE, 0x6960, 0xE9AA, 0x6961, 0x9840, 0x6962, 0x9841, 0x6963, 0xE9B9, 0x6964, 0x9842, 0x6965, 0x9843, 0x6966, 0xE9B8, 0x6967, 0x9844, 0x6968, 0x9845, 0x6969, 0x9846, 0x696A, 0x9847, 0x696B, 0xE9AE, 0x696C, 0x9848, 0x696D, 0x9849, 0x696E, 0xE8FA, 0x696F, 0x984A, 0x6970, 0x984B, 0x6971, 0xE9A8, 0x6972, 0x984C, 0x6973, 0x984D, 0x6974, 0x984E, 0x6975, 0x984F, 0x6976, 0x9850, 0x6977, 0xBFAC, 0x6978, 0xE9B1, 0x6979, 0xE9BA, 0x697A, 0x9851, 0x697B, 0x9852, 0x697C, 0xC2A5, 0x697D, 0x9853, 0x697E, 0x9854, 0x697F, 0x9855, 0x6980, 0xE9AF, 0x6981, 0x9856, 0x6982, 0xB8C5, 0x6983, 0x9857, 0x6984, 0xE9AD, 0x6985, 0x9858, 0x6986, 0xD3DC, 0x6987, 0xE9B4, 0x6988, 0xE9B5, 0x6989, 0xE9B7, 0x698A, 0x9859, 0x698B, 0x985A, 0x698C, 0x985B, 0x698D, 0xE9C7, 0x698E, 0x985C, 0x698F, 0x985D, 0x6990, 0x985E, 0x6991, 0x985F, 0x6992, 0x9860, 0x6993, 0x9861, 0x6994, 0xC0C6, 0x6995, 0xE9C5, 0x6996, 0x9862, 0x6997, 0x9863, 0x6998, 0xE9B0, 0x6999, 0x9864, 0x699A, 0x9865, 0x699B, 0xE9BB, 0x699C, 0xB0F1, 0x699D, 0x9866, 0x699E, 0x9867, 0x699F, 0x9868, 0x69A0, 0x9869, 0x69A1, 0x986A, 0x69A2, 0x986B, 0x69A3, 0x986C, 0x69A4, 0x986D, 0x69A5, 0x986E, 0x69A6, 0x986F, 0x69A7, 0xE9BC, 0x69A8, 0xD5A5, 0x69A9, 0x9870, 0x69AA, 0x9871, 0x69AB, 0xE9BE, 0x69AC, 0x9872, 0x69AD, 0xE9BF, 0x69AE, 0x9873, 0x69AF, 0x9874, 0x69B0, 0x9875, 0x69B1, 0xE9C1, 0x69B2, 0x9876, 0x69B3, 0x9877, 0x69B4, 0xC1F1, 0x69B5, 0x9878, 0x69B6, 0x9879, 0x69B7, 0xC8B6, 0x69B8, 0x987A, 0x69B9, 0x987B, 0x69BA, 0x987C, 0x69BB, 0xE9BD, 0x69BC, 0x987D, 0x69BD, 0x987E, 0x69BE, 0x9880, 0x69BF, 0x9881, 0x69C0, 0x9882, 0x69C1, 0xE9C2, 0x69C2, 0x9883, 0x69C3, 0x9884, 0x69C4, 0x9885, 0x69C5, 0x9886, 0x69C6, 0x9887, 0x69C7, 0x9888, 0x69C8, 0x9889, 0x69C9, 0x988A, 0x69CA, 0xE9C3, 0x69CB, 0x988B, 0x69CC, 0xE9B3, 0x69CD, 0x988C, 0x69CE, 0xE9B6, 0x69CF, 0x988D, 0x69D0, 0xBBB1, 0x69D1, 0x988E, 0x69D2, 0x988F, 0x69D3, 0x9890, 0x69D4, 0xE9C0, 0x69D5, 0x9891, 0x69D6, 0x9892, 0x69D7, 0x9893, 0x69D8, 0x9894, 0x69D9, 0x9895, 0x69DA, 0x9896, 0x69DB, 0xBCF7, 0x69DC, 0x9897, 0x69DD, 0x9898, 0x69DE, 0x9899, 0x69DF, 0xE9C4, 0x69E0, 0xE9C6, 0x69E1, 0x989A, 0x69E2, 0x989B, 0x69E3, 0x989C, 0x69E4, 0x989D, 0x69E5, 0x989E, 0x69E6, 0x989F, 0x69E7, 0x98A0, 0x69E8, 0x98A1, 0x69E9, 0x98A2, 0x69EA, 0x98A3, 0x69EB, 0x98A4, 0x69EC, 0x98A5, 0x69ED, 0xE9CA, 0x69EE, 0x98A6, 0x69EF, 0x98A7, 0x69F0, 0x98A8, 0x69F1, 0x98A9, 0x69F2, 0xE9CE, 0x69F3, 0x98AA, 0x69F4, 0x98AB, 0x69F5, 0x98AC, 0x69F6, 0x98AD, 0x69F7, 0x98AE, 0x69F8, 0x98AF, 0x69F9, 0x98B0, 0x69FA, 0x98B1, 0x69FB, 0x98B2, 0x69FC, 0x98B3, 0x69FD, 0xB2DB, 0x69FE, 0x98B4, 0x69FF, 0xE9C8, 0x6A00, 0x98B5, 0x6A01, 0x98B6, 0x6A02, 0x98B7, 0x6A03, 0x98B8, 0x6A04, 0x98B9, 0x6A05, 0x98BA, 0x6A06, 0x98BB, 0x6A07, 0x98BC, 0x6A08, 0x98BD, 0x6A09, 0x98BE, 0x6A0A, 0xB7AE, 0x6A0B, 0x98BF, 0x6A0C, 0x98C0, 0x6A0D, 0x98C1, 0x6A0E, 0x98C2, 0x6A0F, 0x98C3, 0x6A10, 0x98C4, 0x6A11, 0x98C5, 0x6A12, 0x98C6, 0x6A13, 0x98C7, 0x6A14, 0x98C8, 0x6A15, 0x98C9, 0x6A16, 0x98CA, 0x6A17, 0xE9CB, 0x6A18, 0xE9CC, 0x6A19, 0x98CB, 0x6A1A, 0x98CC, 0x6A1B, 0x98CD, 0x6A1C, 0x98CE, 0x6A1D, 0x98CF, 0x6A1E, 0x98D0, 0x6A1F, 0xD5C1, 0x6A20, 0x98D1, 0x6A21, 0xC4A3, 0x6A22, 0x98D2, 0x6A23, 0x98D3, 0x6A24, 0x98D4, 0x6A25, 0x98D5, 0x6A26, 0x98D6, 0x6A27, 0x98D7, 0x6A28, 0xE9D8, 0x6A29, 0x98D8, 0x6A2A, 0xBAE1, 0x6A2B, 0x98D9, 0x6A2C, 0x98DA, 0x6A2D, 0x98DB, 0x6A2E, 0x98DC, 0x6A2F, 0xE9C9, 0x6A30, 0x98DD, 0x6A31, 0xD3A3, 0x6A32, 0x98DE, 0x6A33, 0x98DF, 0x6A34, 0x98E0, 0x6A35, 0xE9D4, 0x6A36, 0x98E1, 0x6A37, 0x98E2, 0x6A38, 0x98E3, 0x6A39, 0x98E4, 0x6A3A, 0x98E5, 0x6A3B, 0x98E6, 0x6A3C, 0x98E7, 0x6A3D, 0xE9D7, 0x6A3E, 0xE9D0, 0x6A3F, 0x98E8, 0x6A40, 0x98E9, 0x6A41, 0x98EA, 0x6A42, 0x98EB, 0x6A43, 0x98EC, 0x6A44, 0xE9CF, 0x6A45, 0x98ED, 0x6A46, 0x98EE, 0x6A47, 0xC7C1, 0x6A48, 0x98EF, 0x6A49, 0x98F0, 0x6A4A, 0x98F1, 0x6A4B, 0x98F2, 0x6A4C, 0x98F3, 0x6A4D, 0x98F4, 0x6A4E, 0x98F5, 0x6A4F, 0x98F6, 0x6A50, 0xE9D2, 0x6A51, 0x98F7, 0x6A52, 0x98F8, 0x6A53, 0x98F9, 0x6A54, 0x98FA, 0x6A55, 0x98FB, 0x6A56, 0x98FC, 0x6A57, 0x98FD, 0x6A58, 0xE9D9, 0x6A59, 0xB3C8, 0x6A5A, 0x98FE, 0x6A5B, 0xE9D3, 0x6A5C, 0x9940, 0x6A5D, 0x9941, 0x6A5E, 0x9942, 0x6A5F, 0x9943, 0x6A60, 0x9944, 0x6A61, 0xCFF0, 0x6A62, 0x9945, 0x6A63, 0x9946, 0x6A64, 0x9947, 0x6A65, 0xE9CD, 0x6A66, 0x9948, 0x6A67, 0x9949, 0x6A68, 0x994A, 0x6A69, 0x994B, 0x6A6A, 0x994C, 0x6A6B, 0x994D, 0x6A6C, 0x994E, 0x6A6D, 0x994F, 0x6A6E, 0x9950, 0x6A6F, 0x9951, 0x6A70, 0x9952, 0x6A71, 0xB3F7, 0x6A72, 0x9953, 0x6A73, 0x9954, 0x6A74, 0x9955, 0x6A75, 0x9956, 0x6A76, 0x9957, 0x6A77, 0x9958, 0x6A78, 0x9959, 0x6A79, 0xE9D6, 0x6A7A, 0x995A, 0x6A7B, 0x995B, 0x6A7C, 0xE9DA, 0x6A7D, 0x995C, 0x6A7E, 0x995D, 0x6A7F, 0x995E, 0x6A80, 0xCCB4, 0x6A81, 0x995F, 0x6A82, 0x9960, 0x6A83, 0x9961, 0x6A84, 0xCFAD, 0x6A85, 0x9962, 0x6A86, 0x9963, 0x6A87, 0x9964, 0x6A88, 0x9965, 0x6A89, 0x9966, 0x6A8A, 0x9967, 0x6A8B, 0x9968, 0x6A8C, 0x9969, 0x6A8D, 0x996A, 0x6A8E, 0xE9D5, 0x6A8F, 0x996B, 0x6A90, 0xE9DC, 0x6A91, 0xE9DB, 0x6A92, 0x996C, 0x6A93, 0x996D, 0x6A94, 0x996E, 0x6A95, 0x996F, 0x6A96, 0x9970, 0x6A97, 0xE9DE, 0x6A98, 0x9971, 0x6A99, 0x9972, 0x6A9A, 0x9973, 0x6A9B, 0x9974, 0x6A9C, 0x9975, 0x6A9D, 0x9976, 0x6A9E, 0x9977, 0x6A9F, 0x9978, 0x6AA0, 0xE9D1, 0x6AA1, 0x9979, 0x6AA2, 0x997A, 0x6AA3, 0x997B, 0x6AA4, 0x997C, 0x6AA5, 0x997D, 0x6AA6, 0x997E, 0x6AA7, 0x9980, 0x6AA8, 0x9981, 0x6AA9, 0xE9DD, 0x6AAA, 0x9982, 0x6AAB, 0xE9DF, 0x6AAC, 0xC3CA, 0x6AAD, 0x9983, 0x6AAE, 0x9984, 0x6AAF, 0x9985, 0x6AB0, 0x9986, 0x6AB1, 0x9987, 0x6AB2, 0x9988, 0x6AB3, 0x9989, 0x6AB4, 0x998A, 0x6AB5, 0x998B, 0x6AB6, 0x998C, 0x6AB7, 0x998D, 0x6AB8, 0x998E, 0x6AB9, 0x998F, 0x6ABA, 0x9990, 0x6ABB, 0x9991, 0x6ABC, 0x9992, 0x6ABD, 0x9993, 0x6ABE, 0x9994, 0x6ABF, 0x9995, 0x6AC0, 0x9996, 0x6AC1, 0x9997, 0x6AC2, 0x9998, 0x6AC3, 0x9999, 0x6AC4, 0x999A, 0x6AC5, 0x999B, 0x6AC6, 0x999C, 0x6AC7, 0x999D, 0x6AC8, 0x999E, 0x6AC9, 0x999F, 0x6ACA, 0x99A0, 0x6ACB, 0x99A1, 0x6ACC, 0x99A2, 0x6ACD, 0x99A3, 0x6ACE, 0x99A4, 0x6ACF, 0x99A5, 0x6AD0, 0x99A6, 0x6AD1, 0x99A7, 0x6AD2, 0x99A8, 0x6AD3, 0x99A9, 0x6AD4, 0x99AA, 0x6AD5, 0x99AB, 0x6AD6, 0x99AC, 0x6AD7, 0x99AD, 0x6AD8, 0x99AE, 0x6AD9, 0x99AF, 0x6ADA, 0x99B0, 0x6ADB, 0x99B1, 0x6ADC, 0x99B2, 0x6ADD, 0x99B3, 0x6ADE, 0x99B4, 0x6ADF, 0x99B5, 0x6AE0, 0x99B6, 0x6AE1, 0x99B7, 0x6AE2, 0x99B8, 0x6AE3, 0x99B9, 0x6AE4, 0x99BA, 0x6AE5, 0x99BB, 0x6AE6, 0x99BC, 0x6AE7, 0x99BD, 0x6AE8, 0x99BE, 0x6AE9, 0x99BF, 0x6AEA, 0x99C0, 0x6AEB, 0x99C1, 0x6AEC, 0x99C2, 0x6AED, 0x99C3, 0x6AEE, 0x99C4, 0x6AEF, 0x99C5, 0x6AF0, 0x99C6, 0x6AF1, 0x99C7, 0x6AF2, 0x99C8, 0x6AF3, 0x99C9, 0x6AF4, 0x99CA, 0x6AF5, 0x99CB, 0x6AF6, 0x99CC, 0x6AF7, 0x99CD, 0x6AF8, 0x99CE, 0x6AF9, 0x99CF, 0x6AFA, 0x99D0, 0x6AFB, 0x99D1, 0x6AFC, 0x99D2, 0x6AFD, 0x99D3, 0x6AFE, 0x99D4, 0x6AFF, 0x99D5, 0x6B00, 0x99D6, 0x6B01, 0x99D7, 0x6B02, 0x99D8, 0x6B03, 0x99D9, 0x6B04, 0x99DA, 0x6B05, 0x99DB, 0x6B06, 0x99DC, 0x6B07, 0x99DD, 0x6B08, 0x99DE, 0x6B09, 0x99DF, 0x6B0A, 0x99E0, 0x6B0B, 0x99E1, 0x6B0C, 0x99E2, 0x6B0D, 0x99E3, 0x6B0E, 0x99E4, 0x6B0F, 0x99E5, 0x6B10, 0x99E6, 0x6B11, 0x99E7, 0x6B12, 0x99E8, 0x6B13, 0x99E9, 0x6B14, 0x99EA, 0x6B15, 0x99EB, 0x6B16, 0x99EC, 0x6B17, 0x99ED, 0x6B18, 0x99EE, 0x6B19, 0x99EF, 0x6B1A, 0x99F0, 0x6B1B, 0x99F1, 0x6B1C, 0x99F2, 0x6B1D, 0x99F3, 0x6B1E, 0x99F4, 0x6B1F, 0x99F5, 0x6B20, 0xC7B7, 0x6B21, 0xB4CE, 0x6B22, 0xBBB6, 0x6B23, 0xD0C0, 0x6B24, 0xECA3, 0x6B25, 0x99F6, 0x6B26, 0x99F7, 0x6B27, 0xC5B7, 0x6B28, 0x99F8, 0x6B29, 0x99F9, 0x6B2A, 0x99FA, 0x6B2B, 0x99FB, 0x6B2C, 0x99FC, 0x6B2D, 0x99FD, 0x6B2E, 0x99FE, 0x6B2F, 0x9A40, 0x6B30, 0x9A41, 0x6B31, 0x9A42, 0x6B32, 0xD3FB, 0x6B33, 0x9A43, 0x6B34, 0x9A44, 0x6B35, 0x9A45, 0x6B36, 0x9A46, 0x6B37, 0xECA4, 0x6B38, 0x9A47, 0x6B39, 0xECA5, 0x6B3A, 0xC6DB, 0x6B3B, 0x9A48, 0x6B3C, 0x9A49, 0x6B3D, 0x9A4A, 0x6B3E, 0xBFEE, 0x6B3F, 0x9A4B, 0x6B40, 0x9A4C, 0x6B41, 0x9A4D, 0x6B42, 0x9A4E, 0x6B43, 0xECA6, 0x6B44, 0x9A4F, 0x6B45, 0x9A50, 0x6B46, 0xECA7, 0x6B47, 0xD0AA, 0x6B48, 0x9A51, 0x6B49, 0xC7B8, 0x6B4A, 0x9A52, 0x6B4B, 0x9A53, 0x6B4C, 0xB8E8, 0x6B4D, 0x9A54, 0x6B4E, 0x9A55, 0x6B4F, 0x9A56, 0x6B50, 0x9A57, 0x6B51, 0x9A58, 0x6B52, 0x9A59, 0x6B53, 0x9A5A, 0x6B54, 0x9A5B, 0x6B55, 0x9A5C, 0x6B56, 0x9A5D, 0x6B57, 0x9A5E, 0x6B58, 0x9A5F, 0x6B59, 0xECA8, 0x6B5A, 0x9A60, 0x6B5B, 0x9A61, 0x6B5C, 0x9A62, 0x6B5D, 0x9A63, 0x6B5E, 0x9A64, 0x6B5F, 0x9A65, 0x6B60, 0x9A66, 0x6B61, 0x9A67, 0x6B62, 0xD6B9, 0x6B63, 0xD5FD, 0x6B64, 0xB4CB, 0x6B65, 0xB2BD, 0x6B66, 0xCEE4, 0x6B67, 0xC6E7, 0x6B68, 0x9A68, 0x6B69, 0x9A69, 0x6B6A, 0xCDE1, 0x6B6B, 0x9A6A, 0x6B6C, 0x9A6B, 0x6B6D, 0x9A6C, 0x6B6E, 0x9A6D, 0x6B6F, 0x9A6E, 0x6B70, 0x9A6F, 0x6B71, 0x9A70, 0x6B72, 0x9A71, 0x6B73, 0x9A72, 0x6B74, 0x9A73, 0x6B75, 0x9A74, 0x6B76, 0x9A75, 0x6B77, 0x9A76, 0x6B78, 0x9A77, 0x6B79, 0xB4F5, 0x6B7A, 0x9A78, 0x6B7B, 0xCBC0, 0x6B7C, 0xBCDF, 0x6B7D, 0x9A79, 0x6B7E, 0x9A7A, 0x6B7F, 0x9A7B, 0x6B80, 0x9A7C, 0x6B81, 0xE9E2, 0x6B82, 0xE9E3, 0x6B83, 0xD1EA, 0x6B84, 0xE9E5, 0x6B85, 0x9A7D, 0x6B86, 0xB4F9, 0x6B87, 0xE9E4, 0x6B88, 0x9A7E, 0x6B89, 0xD1B3, 0x6B8A, 0xCAE2, 0x6B8B, 0xB2D0, 0x6B8C, 0x9A80, 0x6B8D, 0xE9E8, 0x6B8E, 0x9A81, 0x6B8F, 0x9A82, 0x6B90, 0x9A83, 0x6B91, 0x9A84, 0x6B92, 0xE9E6, 0x6B93, 0xE9E7, 0x6B94, 0x9A85, 0x6B95, 0x9A86, 0x6B96, 0xD6B3, 0x6B97, 0x9A87, 0x6B98, 0x9A88, 0x6B99, 0x9A89, 0x6B9A, 0xE9E9, 0x6B9B, 0xE9EA, 0x6B9C, 0x9A8A, 0x6B9D, 0x9A8B, 0x6B9E, 0x9A8C, 0x6B9F, 0x9A8D, 0x6BA0, 0x9A8E, 0x6BA1, 0xE9EB, 0x6BA2, 0x9A8F, 0x6BA3, 0x9A90, 0x6BA4, 0x9A91, 0x6BA5, 0x9A92, 0x6BA6, 0x9A93, 0x6BA7, 0x9A94, 0x6BA8, 0x9A95, 0x6BA9, 0x9A96, 0x6BAA, 0xE9EC, 0x6BAB, 0x9A97, 0x6BAC, 0x9A98, 0x6BAD, 0x9A99, 0x6BAE, 0x9A9A, 0x6BAF, 0x9A9B, 0x6BB0, 0x9A9C, 0x6BB1, 0x9A9D, 0x6BB2, 0x9A9E, 0x6BB3, 0xECAF, 0x6BB4, 0xC5B9, 0x6BB5, 0xB6CE, 0x6BB6, 0x9A9F, 0x6BB7, 0xD2F3, 0x6BB8, 0x9AA0, 0x6BB9, 0x9AA1, 0x6BBA, 0x9AA2, 0x6BBB, 0x9AA3, 0x6BBC, 0x9AA4, 0x6BBD, 0x9AA5, 0x6BBE, 0x9AA6, 0x6BBF, 0xB5EE, 0x6BC0, 0x9AA7, 0x6BC1, 0xBBD9, 0x6BC2, 0xECB1, 0x6BC3, 0x9AA8, 0x6BC4, 0x9AA9, 0x6BC5, 0xD2E3, 0x6BC6, 0x9AAA, 0x6BC7, 0x9AAB, 0x6BC8, 0x9AAC, 0x6BC9, 0x9AAD, 0x6BCA, 0x9AAE, 0x6BCB, 0xCEE3, 0x6BCC, 0x9AAF, 0x6BCD, 0xC4B8, 0x6BCE, 0x9AB0, 0x6BCF, 0xC3BF, 0x6BD0, 0x9AB1, 0x6BD1, 0x9AB2, 0x6BD2, 0xB6BE, 0x6BD3, 0xD8B9, 0x6BD4, 0xB1C8, 0x6BD5, 0xB1CF, 0x6BD6, 0xB1D1, 0x6BD7, 0xC5FE, 0x6BD8, 0x9AB3, 0x6BD9, 0xB1D0, 0x6BDA, 0x9AB4, 0x6BDB, 0xC3AB, 0x6BDC, 0x9AB5, 0x6BDD, 0x9AB6, 0x6BDE, 0x9AB7, 0x6BDF, 0x9AB8, 0x6BE0, 0x9AB9, 0x6BE1, 0xD5B1, 0x6BE2, 0x9ABA, 0x6BE3, 0x9ABB, 0x6BE4, 0x9ABC, 0x6BE5, 0x9ABD, 0x6BE6, 0x9ABE, 0x6BE7, 0x9ABF, 0x6BE8, 0x9AC0, 0x6BE9, 0x9AC1, 0x6BEA, 0xEBA4, 0x6BEB, 0xBAC1, 0x6BEC, 0x9AC2, 0x6BED, 0x9AC3, 0x6BEE, 0x9AC4, 0x6BEF, 0xCCBA, 0x6BF0, 0x9AC5, 0x6BF1, 0x9AC6, 0x6BF2, 0x9AC7, 0x6BF3, 0xEBA5, 0x6BF4, 0x9AC8, 0x6BF5, 0xEBA7, 0x6BF6, 0x9AC9, 0x6BF7, 0x9ACA, 0x6BF8, 0x9ACB, 0x6BF9, 0xEBA8, 0x6BFA, 0x9ACC, 0x6BFB, 0x9ACD, 0x6BFC, 0x9ACE, 0x6BFD, 0xEBA6, 0x6BFE, 0x9ACF, 0x6BFF, 0x9AD0, 0x6C00, 0x9AD1, 0x6C01, 0x9AD2, 0x6C02, 0x9AD3, 0x6C03, 0x9AD4, 0x6C04, 0x9AD5, 0x6C05, 0xEBA9, 0x6C06, 0xEBAB, 0x6C07, 0xEBAA, 0x6C08, 0x9AD6, 0x6C09, 0x9AD7, 0x6C0A, 0x9AD8, 0x6C0B, 0x9AD9, 0x6C0C, 0x9ADA, 0x6C0D, 0xEBAC, 0x6C0E, 0x9ADB, 0x6C0F, 0xCACF, 0x6C10, 0xD8B5, 0x6C11, 0xC3F1, 0x6C12, 0x9ADC, 0x6C13, 0xC3A5, 0x6C14, 0xC6F8, 0x6C15, 0xEBAD, 0x6C16, 0xC4CA, 0x6C17, 0x9ADD, 0x6C18, 0xEBAE, 0x6C19, 0xEBAF, 0x6C1A, 0xEBB0, 0x6C1B, 0xB7D5, 0x6C1C, 0x9ADE, 0x6C1D, 0x9ADF, 0x6C1E, 0x9AE0, 0x6C1F, 0xB7FA, 0x6C20, 0x9AE1, 0x6C21, 0xEBB1, 0x6C22, 0xC7E2, 0x6C23, 0x9AE2, 0x6C24, 0xEBB3, 0x6C25, 0x9AE3, 0x6C26, 0xBAA4, 0x6C27, 0xD1F5, 0x6C28, 0xB0B1, 0x6C29, 0xEBB2, 0x6C2A, 0xEBB4, 0x6C2B, 0x9AE4, 0x6C2C, 0x9AE5, 0x6C2D, 0x9AE6, 0x6C2E, 0xB5AA, 0x6C2F, 0xC2C8, 0x6C30, 0xC7E8, 0x6C31, 0x9AE7, 0x6C32, 0xEBB5, 0x6C33, 0x9AE8, 0x6C34, 0xCBAE, 0x6C35, 0xE3DF, 0x6C36, 0x9AE9, 0x6C37, 0x9AEA, 0x6C38, 0xD3C0, 0x6C39, 0x9AEB, 0x6C3A, 0x9AEC, 0x6C3B, 0x9AED, 0x6C3C, 0x9AEE, 0x6C3D, 0xD9DB, 0x6C3E, 0x9AEF, 0x6C3F, 0x9AF0, 0x6C40, 0xCDA1, 0x6C41, 0xD6AD, 0x6C42, 0xC7F3, 0x6C43, 0x9AF1, 0x6C44, 0x9AF2, 0x6C45, 0x9AF3, 0x6C46, 0xD9E0, 0x6C47, 0xBBE3, 0x6C48, 0x9AF4, 0x6C49, 0xBABA, 0x6C4A, 0xE3E2, 0x6C4B, 0x9AF5, 0x6C4C, 0x9AF6, 0x6C4D, 0x9AF7, 0x6C4E, 0x9AF8, 0x6C4F, 0x9AF9, 0x6C50, 0xCFAB, 0x6C51, 0x9AFA, 0x6C52, 0x9AFB, 0x6C53, 0x9AFC, 0x6C54, 0xE3E0, 0x6C55, 0xC9C7, 0x6C56, 0x9AFD, 0x6C57, 0xBAB9, 0x6C58, 0x9AFE, 0x6C59, 0x9B40, 0x6C5A, 0x9B41, 0x6C5B, 0xD1B4, 0x6C5C, 0xE3E1, 0x6C5D, 0xC8EA, 0x6C5E, 0xB9AF, 0x6C5F, 0xBDAD, 0x6C60, 0xB3D8, 0x6C61, 0xCEDB, 0x6C62, 0x9B42, 0x6C63, 0x9B43, 0x6C64, 0xCCC0, 0x6C65, 0x9B44, 0x6C66, 0x9B45, 0x6C67, 0x9B46, 0x6C68, 0xE3E8, 0x6C69, 0xE3E9, 0x6C6A, 0xCDF4, 0x6C6B, 0x9B47, 0x6C6C, 0x9B48, 0x6C6D, 0x9B49, 0x6C6E, 0x9B4A, 0x6C6F, 0x9B4B, 0x6C70, 0xCCAD, 0x6C71, 0x9B4C, 0x6C72, 0xBCB3, 0x6C73, 0x9B4D, 0x6C74, 0xE3EA, 0x6C75, 0x9B4E, 0x6C76, 0xE3EB, 0x6C77, 0x9B4F, 0x6C78, 0x9B50, 0x6C79, 0xD0DA, 0x6C7A, 0x9B51, 0x6C7B, 0x9B52, 0x6C7C, 0x9B53, 0x6C7D, 0xC6FB, 0x6C7E, 0xB7DA, 0x6C7F, 0x9B54, 0x6C80, 0x9B55, 0x6C81, 0xC7DF, 0x6C82, 0xD2CA, 0x6C83, 0xCED6, 0x6C84, 0x9B56, 0x6C85, 0xE3E4, 0x6C86, 0xE3EC, 0x6C87, 0x9B57, 0x6C88, 0xC9F2, 0x6C89, 0xB3C1, 0x6C8A, 0x9B58, 0x6C8B, 0x9B59, 0x6C8C, 0xE3E7, 0x6C8D, 0x9B5A, 0x6C8E, 0x9B5B, 0x6C8F, 0xC6E3, 0x6C90, 0xE3E5, 0x6C91, 0x9B5C, 0x6C92, 0x9B5D, 0x6C93, 0xEDB3, 0x6C94, 0xE3E6, 0x6C95, 0x9B5E, 0x6C96, 0x9B5F, 0x6C97, 0x9B60, 0x6C98, 0x9B61, 0x6C99, 0xC9B3, 0x6C9A, 0x9B62, 0x6C9B, 0xC5E6, 0x6C9C, 0x9B63, 0x6C9D, 0x9B64, 0x6C9E, 0x9B65, 0x6C9F, 0xB9B5, 0x6CA0, 0x9B66, 0x6CA1, 0xC3BB, 0x6CA2, 0x9B67, 0x6CA3, 0xE3E3, 0x6CA4, 0xC5BD, 0x6CA5, 0xC1A4, 0x6CA6, 0xC2D9, 0x6CA7, 0xB2D7, 0x6CA8, 0x9B68, 0x6CA9, 0xE3ED, 0x6CAA, 0xBBA6, 0x6CAB, 0xC4AD, 0x6CAC, 0x9B69, 0x6CAD, 0xE3F0, 0x6CAE, 0xBEDA, 0x6CAF, 0x9B6A, 0x6CB0, 0x9B6B, 0x6CB1, 0xE3FB, 0x6CB2, 0xE3F5, 0x6CB3, 0xBAD3, 0x6CB4, 0x9B6C, 0x6CB5, 0x9B6D, 0x6CB6, 0x9B6E, 0x6CB7, 0x9B6F, 0x6CB8, 0xB7D0, 0x6CB9, 0xD3CD, 0x6CBA, 0x9B70, 0x6CBB, 0xD6CE, 0x6CBC, 0xD5D3, 0x6CBD, 0xB9C1, 0x6CBE, 0xD5B4, 0x6CBF, 0xD1D8, 0x6CC0, 0x9B71, 0x6CC1, 0x9B72, 0x6CC2, 0x9B73, 0x6CC3, 0x9B74, 0x6CC4, 0xD0B9, 0x6CC5, 0xC7F6, 0x6CC6, 0x9B75, 0x6CC7, 0x9B76, 0x6CC8, 0x9B77, 0x6CC9, 0xC8AA, 0x6CCA, 0xB2B4, 0x6CCB, 0x9B78, 0x6CCC, 0xC3DA, 0x6CCD, 0x9B79, 0x6CCE, 0x9B7A, 0x6CCF, 0x9B7B, 0x6CD0, 0xE3EE, 0x6CD1, 0x9B7C, 0x6CD2, 0x9B7D, 0x6CD3, 0xE3FC, 0x6CD4, 0xE3EF, 0x6CD5, 0xB7A8, 0x6CD6, 0xE3F7, 0x6CD7, 0xE3F4, 0x6CD8, 0x9B7E, 0x6CD9, 0x9B80, 0x6CDA, 0x9B81, 0x6CDB, 0xB7BA, 0x6CDC, 0x9B82, 0x6CDD, 0x9B83, 0x6CDE, 0xC5A2, 0x6CDF, 0x9B84, 0x6CE0, 0xE3F6, 0x6CE1, 0xC5DD, 0x6CE2, 0xB2A8, 0x6CE3, 0xC6FC, 0x6CE4, 0x9B85, 0x6CE5, 0xC4E0, 0x6CE6, 0x9B86, 0x6CE7, 0x9B87, 0x6CE8, 0xD7A2, 0x6CE9, 0x9B88, 0x6CEA, 0xC0E1, 0x6CEB, 0xE3F9, 0x6CEC, 0x9B89, 0x6CED, 0x9B8A, 0x6CEE, 0xE3FA, 0x6CEF, 0xE3FD, 0x6CF0, 0xCCA9, 0x6CF1, 0xE3F3, 0x6CF2, 0x9B8B, 0x6CF3, 0xD3BE, 0x6CF4, 0x9B8C, 0x6CF5, 0xB1C3, 0x6CF6, 0xEDB4, 0x6CF7, 0xE3F1, 0x6CF8, 0xE3F2, 0x6CF9, 0x9B8D, 0x6CFA, 0xE3F8, 0x6CFB, 0xD0BA, 0x6CFC, 0xC6C3, 0x6CFD, 0xD4F3, 0x6CFE, 0xE3FE, 0x6CFF, 0x9B8E, 0x6D00, 0x9B8F, 0x6D01, 0xBDE0, 0x6D02, 0x9B90, 0x6D03, 0x9B91, 0x6D04, 0xE4A7, 0x6D05, 0x9B92, 0x6D06, 0x9B93, 0x6D07, 0xE4A6, 0x6D08, 0x9B94, 0x6D09, 0x9B95, 0x6D0A, 0x9B96, 0x6D0B, 0xD1F3, 0x6D0C, 0xE4A3, 0x6D0D, 0x9B97, 0x6D0E, 0xE4A9, 0x6D0F, 0x9B98, 0x6D10, 0x9B99, 0x6D11, 0x9B9A, 0x6D12, 0xC8F7, 0x6D13, 0x9B9B, 0x6D14, 0x9B9C, 0x6D15, 0x9B9D, 0x6D16, 0x9B9E, 0x6D17, 0xCFB4, 0x6D18, 0x9B9F, 0x6D19, 0xE4A8, 0x6D1A, 0xE4AE, 0x6D1B, 0xC2E5, 0x6D1C, 0x9BA0, 0x6D1D, 0x9BA1, 0x6D1E, 0xB6B4, 0x6D1F, 0x9BA2, 0x6D20, 0x9BA3, 0x6D21, 0x9BA4, 0x6D22, 0x9BA5, 0x6D23, 0x9BA6, 0x6D24, 0x9BA7, 0x6D25, 0xBDF2, 0x6D26, 0x9BA8, 0x6D27, 0xE4A2, 0x6D28, 0x9BA9, 0x6D29, 0x9BAA, 0x6D2A, 0xBAE9, 0x6D2B, 0xE4AA, 0x6D2C, 0x9BAB, 0x6D2D, 0x9BAC, 0x6D2E, 0xE4AC, 0x6D2F, 0x9BAD, 0x6D30, 0x9BAE, 0x6D31, 0xB6FD, 0x6D32, 0xD6DE, 0x6D33, 0xE4B2, 0x6D34, 0x9BAF, 0x6D35, 0xE4AD, 0x6D36, 0x9BB0, 0x6D37, 0x9BB1, 0x6D38, 0x9BB2, 0x6D39, 0xE4A1, 0x6D3A, 0x9BB3, 0x6D3B, 0xBBEE, 0x6D3C, 0xCDDD, 0x6D3D, 0xC7A2, 0x6D3E, 0xC5C9, 0x6D3F, 0x9BB4, 0x6D40, 0x9BB5, 0x6D41, 0xC1F7, 0x6D42, 0x9BB6, 0x6D43, 0xE4A4, 0x6D44, 0x9BB7, 0x6D45, 0xC7B3, 0x6D46, 0xBDAC, 0x6D47, 0xBDBD, 0x6D48, 0xE4A5, 0x6D49, 0x9BB8, 0x6D4A, 0xD7C7, 0x6D4B, 0xB2E2, 0x6D4C, 0x9BB9, 0x6D4D, 0xE4AB, 0x6D4E, 0xBCC3, 0x6D4F, 0xE4AF, 0x6D50, 0x9BBA, 0x6D51, 0xBBEB, 0x6D52, 0xE4B0, 0x6D53, 0xC5A8, 0x6D54, 0xE4B1, 0x6D55, 0x9BBB, 0x6D56, 0x9BBC, 0x6D57, 0x9BBD, 0x6D58, 0x9BBE, 0x6D59, 0xD5E3, 0x6D5A, 0xBFA3, 0x6D5B, 0x9BBF, 0x6D5C, 0xE4BA, 0x6D5D, 0x9BC0, 0x6D5E, 0xE4B7, 0x6D5F, 0x9BC1, 0x6D60, 0xE4BB, 0x6D61, 0x9BC2, 0x6D62, 0x9BC3, 0x6D63, 0xE4BD, 0x6D64, 0x9BC4, 0x6D65, 0x9BC5, 0x6D66, 0xC6D6, 0x6D67, 0x9BC6, 0x6D68, 0x9BC7, 0x6D69, 0xBAC6, 0x6D6A, 0xC0CB, 0x6D6B, 0x9BC8, 0x6D6C, 0x9BC9, 0x6D6D, 0x9BCA, 0x6D6E, 0xB8A1, 0x6D6F, 0xE4B4, 0x6D70, 0x9BCB, 0x6D71, 0x9BCC, 0x6D72, 0x9BCD, 0x6D73, 0x9BCE, 0x6D74, 0xD4A1, 0x6D75, 0x9BCF, 0x6D76, 0x9BD0, 0x6D77, 0xBAA3, 0x6D78, 0xBDFE, 0x6D79, 0x9BD1, 0x6D7A, 0x9BD2, 0x6D7B, 0x9BD3, 0x6D7C, 0xE4BC, 0x6D7D, 0x9BD4, 0x6D7E, 0x9BD5, 0x6D7F, 0x9BD6, 0x6D80, 0x9BD7, 0x6D81, 0x9BD8, 0x6D82, 0xCDBF, 0x6D83, 0x9BD9, 0x6D84, 0x9BDA, 0x6D85, 0xC4F9, 0x6D86, 0x9BDB, 0x6D87, 0x9BDC, 0x6D88, 0xCFFB, 0x6D89, 0xC9E6, 0x6D8A, 0x9BDD, 0x6D8B, 0x9BDE, 0x6D8C, 0xD3BF, 0x6D8D, 0x9BDF, 0x6D8E, 0xCFD1, 0x6D8F, 0x9BE0, 0x6D90, 0x9BE1, 0x6D91, 0xE4B3, 0x6D92, 0x9BE2, 0x6D93, 0xE4B8, 0x6D94, 0xE4B9, 0x6D95, 0xCCE9, 0x6D96, 0x9BE3, 0x6D97, 0x9BE4, 0x6D98, 0x9BE5, 0x6D99, 0x9BE6, 0x6D9A, 0x9BE7, 0x6D9B, 0xCCCE, 0x6D9C, 0x9BE8, 0x6D9D, 0xC0D4, 0x6D9E, 0xE4B5, 0x6D9F, 0xC1B0, 0x6DA0, 0xE4B6, 0x6DA1, 0xCED0, 0x6DA2, 0x9BE9, 0x6DA3, 0xBBC1, 0x6DA4, 0xB5D3, 0x6DA5, 0x9BEA, 0x6DA6, 0xC8F3, 0x6DA7, 0xBDA7, 0x6DA8, 0xD5C7, 0x6DA9, 0xC9AC, 0x6DAA, 0xB8A2, 0x6DAB, 0xE4CA, 0x6DAC, 0x9BEB, 0x6DAD, 0x9BEC, 0x6DAE, 0xE4CC, 0x6DAF, 0xD1C4, 0x6DB0, 0x9BED, 0x6DB1, 0x9BEE, 0x6DB2, 0xD2BA, 0x6DB3, 0x9BEF, 0x6DB4, 0x9BF0, 0x6DB5, 0xBAAD, 0x6DB6, 0x9BF1, 0x6DB7, 0x9BF2, 0x6DB8, 0xBAD4, 0x6DB9, 0x9BF3, 0x6DBA, 0x9BF4, 0x6DBB, 0x9BF5, 0x6DBC, 0x9BF6, 0x6DBD, 0x9BF7, 0x6DBE, 0x9BF8, 0x6DBF, 0xE4C3, 0x6DC0, 0xB5ED, 0x6DC1, 0x9BF9, 0x6DC2, 0x9BFA, 0x6DC3, 0x9BFB, 0x6DC4, 0xD7CD, 0x6DC5, 0xE4C0, 0x6DC6, 0xCFFD, 0x6DC7, 0xE4BF, 0x6DC8, 0x9BFC, 0x6DC9, 0x9BFD, 0x6DCA, 0x9BFE, 0x6DCB, 0xC1DC, 0x6DCC, 0xCCCA, 0x6DCD, 0x9C40, 0x6DCE, 0x9C41, 0x6DCF, 0x9C42, 0x6DD0, 0x9C43, 0x6DD1, 0xCAE7, 0x6DD2, 0x9C44, 0x6DD3, 0x9C45, 0x6DD4, 0x9C46, 0x6DD5, 0x9C47, 0x6DD6, 0xC4D7, 0x6DD7, 0x9C48, 0x6DD8, 0xCCD4, 0x6DD9, 0xE4C8, 0x6DDA, 0x9C49, 0x6DDB, 0x9C4A, 0x6DDC, 0x9C4B, 0x6DDD, 0xE4C7, 0x6DDE, 0xE4C1, 0x6DDF, 0x9C4C, 0x6DE0, 0xE4C4, 0x6DE1, 0xB5AD, 0x6DE2, 0x9C4D, 0x6DE3, 0x9C4E, 0x6DE4, 0xD3D9, 0x6DE5, 0x9C4F, 0x6DE6, 0xE4C6, 0x6DE7, 0x9C50, 0x6DE8, 0x9C51, 0x6DE9, 0x9C52, 0x6DEA, 0x9C53, 0x6DEB, 0xD2F9, 0x6DEC, 0xB4E3, 0x6DED, 0x9C54, 0x6DEE, 0xBBB4, 0x6DEF, 0x9C55, 0x6DF0, 0x9C56, 0x6DF1, 0xC9EE, 0x6DF2, 0x9C57, 0x6DF3, 0xB4BE, 0x6DF4, 0x9C58, 0x6DF5, 0x9C59, 0x6DF6, 0x9C5A, 0x6DF7, 0xBBEC, 0x6DF8, 0x9C5B, 0x6DF9, 0xD1CD, 0x6DFA, 0x9C5C, 0x6DFB, 0xCCED, 0x6DFC, 0xEDB5, 0x6DFD, 0x9C5D, 0x6DFE, 0x9C5E, 0x6DFF, 0x9C5F, 0x6E00, 0x9C60, 0x6E01, 0x9C61, 0x6E02, 0x9C62, 0x6E03, 0x9C63, 0x6E04, 0x9C64, 0x6E05, 0xC7E5, 0x6E06, 0x9C65, 0x6E07, 0x9C66, 0x6E08, 0x9C67, 0x6E09, 0x9C68, 0x6E0A, 0xD4A8, 0x6E0B, 0x9C69, 0x6E0C, 0xE4CB, 0x6E0D, 0xD7D5, 0x6E0E, 0xE4C2, 0x6E0F, 0x9C6A, 0x6E10, 0xBDA5, 0x6E11, 0xE4C5, 0x6E12, 0x9C6B, 0x6E13, 0x9C6C, 0x6E14, 0xD3E6, 0x6E15, 0x9C6D, 0x6E16, 0xE4C9, 0x6E17, 0xC9F8, 0x6E18, 0x9C6E, 0x6E19, 0x9C6F, 0x6E1A, 0xE4BE, 0x6E1B, 0x9C70, 0x6E1C, 0x9C71, 0x6E1D, 0xD3E5, 0x6E1E, 0x9C72, 0x6E1F, 0x9C73, 0x6E20, 0xC7FE, 0x6E21, 0xB6C9, 0x6E22, 0x9C74, 0x6E23, 0xD4FC, 0x6E24, 0xB2B3, 0x6E25, 0xE4D7, 0x6E26, 0x9C75, 0x6E27, 0x9C76, 0x6E28, 0x9C77, 0x6E29, 0xCEC2, 0x6E2A, 0x9C78, 0x6E2B, 0xE4CD, 0x6E2C, 0x9C79, 0x6E2D, 0xCEBC, 0x6E2E, 0x9C7A, 0x6E2F, 0xB8DB, 0x6E30, 0x9C7B, 0x6E31, 0x9C7C, 0x6E32, 0xE4D6, 0x6E33, 0x9C7D, 0x6E34, 0xBFCA, 0x6E35, 0x9C7E, 0x6E36, 0x9C80, 0x6E37, 0x9C81, 0x6E38, 0xD3CE, 0x6E39, 0x9C82, 0x6E3A, 0xC3EC, 0x6E3B, 0x9C83, 0x6E3C, 0x9C84, 0x6E3D, 0x9C85, 0x6E3E, 0x9C86, 0x6E3F, 0x9C87, 0x6E40, 0x9C88, 0x6E41, 0x9C89, 0x6E42, 0x9C8A, 0x6E43, 0xC5C8, 0x6E44, 0xE4D8, 0x6E45, 0x9C8B, 0x6E46, 0x9C8C, 0x6E47, 0x9C8D, 0x6E48, 0x9C8E, 0x6E49, 0x9C8F, 0x6E4A, 0x9C90, 0x6E4B, 0x9C91, 0x6E4C, 0x9C92, 0x6E4D, 0xCDC4, 0x6E4E, 0xE4CF, 0x6E4F, 0x9C93, 0x6E50, 0x9C94, 0x6E51, 0x9C95, 0x6E52, 0x9C96, 0x6E53, 0xE4D4, 0x6E54, 0xE4D5, 0x6E55, 0x9C97, 0x6E56, 0xBAFE, 0x6E57, 0x9C98, 0x6E58, 0xCFE6, 0x6E59, 0x9C99, 0x6E5A, 0x9C9A, 0x6E5B, 0xD5BF, 0x6E5C, 0x9C9B, 0x6E5D, 0x9C9C, 0x6E5E, 0x9C9D, 0x6E5F, 0xE4D2, 0x6E60, 0x9C9E, 0x6E61, 0x9C9F, 0x6E62, 0x9CA0, 0x6E63, 0x9CA1, 0x6E64, 0x9CA2, 0x6E65, 0x9CA3, 0x6E66, 0x9CA4, 0x6E67, 0x9CA5, 0x6E68, 0x9CA6, 0x6E69, 0x9CA7, 0x6E6A, 0x9CA8, 0x6E6B, 0xE4D0, 0x6E6C, 0x9CA9, 0x6E6D, 0x9CAA, 0x6E6E, 0xE4CE, 0x6E6F, 0x9CAB, 0x6E70, 0x9CAC, 0x6E71, 0x9CAD, 0x6E72, 0x9CAE, 0x6E73, 0x9CAF, 0x6E74, 0x9CB0, 0x6E75, 0x9CB1, 0x6E76, 0x9CB2, 0x6E77, 0x9CB3, 0x6E78, 0x9CB4, 0x6E79, 0x9CB5, 0x6E7A, 0x9CB6, 0x6E7B, 0x9CB7, 0x6E7C, 0x9CB8, 0x6E7D, 0x9CB9, 0x6E7E, 0xCDE5, 0x6E7F, 0xCAAA, 0x6E80, 0x9CBA, 0x6E81, 0x9CBB, 0x6E82, 0x9CBC, 0x6E83, 0xC0A3, 0x6E84, 0x9CBD, 0x6E85, 0xBDA6, 0x6E86, 0xE4D3, 0x6E87, 0x9CBE, 0x6E88, 0x9CBF, 0x6E89, 0xB8C8, 0x6E8A, 0x9CC0, 0x6E8B, 0x9CC1, 0x6E8C, 0x9CC2, 0x6E8D, 0x9CC3, 0x6E8E, 0x9CC4, 0x6E8F, 0xE4E7, 0x6E90, 0xD4B4, 0x6E91, 0x9CC5, 0x6E92, 0x9CC6, 0x6E93, 0x9CC7, 0x6E94, 0x9CC8, 0x6E95, 0x9CC9, 0x6E96, 0x9CCA, 0x6E97, 0x9CCB, 0x6E98, 0xE4DB, 0x6E99, 0x9CCC, 0x6E9A, 0x9CCD, 0x6E9B, 0x9CCE, 0x6E9C, 0xC1EF, 0x6E9D, 0x9CCF, 0x6E9E, 0x9CD0, 0x6E9F, 0xE4E9, 0x6EA0, 0x9CD1, 0x6EA1, 0x9CD2, 0x6EA2, 0xD2E7, 0x6EA3, 0x9CD3, 0x6EA4, 0x9CD4, 0x6EA5, 0xE4DF, 0x6EA6, 0x9CD5, 0x6EA7, 0xE4E0, 0x6EA8, 0x9CD6, 0x6EA9, 0x9CD7, 0x6EAA, 0xCFAA, 0x6EAB, 0x9CD8, 0x6EAC, 0x9CD9, 0x6EAD, 0x9CDA, 0x6EAE, 0x9CDB, 0x6EAF, 0xCBDD, 0x6EB0, 0x9CDC, 0x6EB1, 0xE4DA, 0x6EB2, 0xE4D1, 0x6EB3, 0x9CDD, 0x6EB4, 0xE4E5, 0x6EB5, 0x9CDE, 0x6EB6, 0xC8DC, 0x6EB7, 0xE4E3, 0x6EB8, 0x9CDF, 0x6EB9, 0x9CE0, 0x6EBA, 0xC4E7, 0x6EBB, 0xE4E2, 0x6EBC, 0x9CE1, 0x6EBD, 0xE4E1, 0x6EBE, 0x9CE2, 0x6EBF, 0x9CE3, 0x6EC0, 0x9CE4, 0x6EC1, 0xB3FC, 0x6EC2, 0xE4E8, 0x6EC3, 0x9CE5, 0x6EC4, 0x9CE6, 0x6EC5, 0x9CE7, 0x6EC6, 0x9CE8, 0x6EC7, 0xB5E1, 0x6EC8, 0x9CE9, 0x6EC9, 0x9CEA, 0x6ECA, 0x9CEB, 0x6ECB, 0xD7CC, 0x6ECC, 0x9CEC, 0x6ECD, 0x9CED, 0x6ECE, 0x9CEE, 0x6ECF, 0xE4E6, 0x6ED0, 0x9CEF, 0x6ED1, 0xBBAC, 0x6ED2, 0x9CF0, 0x6ED3, 0xD7D2, 0x6ED4, 0xCCCF, 0x6ED5, 0xEBF8, 0x6ED6, 0x9CF1, 0x6ED7, 0xE4E4, 0x6ED8, 0x9CF2, 0x6ED9, 0x9CF3, 0x6EDA, 0xB9F6, 0x6EDB, 0x9CF4, 0x6EDC, 0x9CF5, 0x6EDD, 0x9CF6, 0x6EDE, 0xD6CD, 0x6EDF, 0xE4D9, 0x6EE0, 0xE4DC, 0x6EE1, 0xC2FA, 0x6EE2, 0xE4DE, 0x6EE3, 0x9CF7, 0x6EE4, 0xC2CB, 0x6EE5, 0xC0C4, 0x6EE6, 0xC2D0, 0x6EE7, 0x9CF8, 0x6EE8, 0xB1F5, 0x6EE9, 0xCCB2, 0x6EEA, 0x9CF9, 0x6EEB, 0x9CFA, 0x6EEC, 0x9CFB, 0x6EED, 0x9CFC, 0x6EEE, 0x9CFD, 0x6EEF, 0x9CFE, 0x6EF0, 0x9D40, 0x6EF1, 0x9D41, 0x6EF2, 0x9D42, 0x6EF3, 0x9D43, 0x6EF4, 0xB5CE, 0x6EF5, 0x9D44, 0x6EF6, 0x9D45, 0x6EF7, 0x9D46, 0x6EF8, 0x9D47, 0x6EF9, 0xE4EF, 0x6EFA, 0x9D48, 0x6EFB, 0x9D49, 0x6EFC, 0x9D4A, 0x6EFD, 0x9D4B, 0x6EFE, 0x9D4C, 0x6EFF, 0x9D4D, 0x6F00, 0x9D4E, 0x6F01, 0x9D4F, 0x6F02, 0xC6AF, 0x6F03, 0x9D50, 0x6F04, 0x9D51, 0x6F05, 0x9D52, 0x6F06, 0xC6E1, 0x6F07, 0x9D53, 0x6F08, 0x9D54, 0x6F09, 0xE4F5, 0x6F0A, 0x9D55, 0x6F0B, 0x9D56, 0x6F0C, 0x9D57, 0x6F0D, 0x9D58, 0x6F0E, 0x9D59, 0x6F0F, 0xC2A9, 0x6F10, 0x9D5A, 0x6F11, 0x9D5B, 0x6F12, 0x9D5C, 0x6F13, 0xC0EC, 0x6F14, 0xD1DD, 0x6F15, 0xE4EE, 0x6F16, 0x9D5D, 0x6F17, 0x9D5E, 0x6F18, 0x9D5F, 0x6F19, 0x9D60, 0x6F1A, 0x9D61, 0x6F1B, 0x9D62, 0x6F1C, 0x9D63, 0x6F1D, 0x9D64, 0x6F1E, 0x9D65, 0x6F1F, 0x9D66, 0x6F20, 0xC4AE, 0x6F21, 0x9D67, 0x6F22, 0x9D68, 0x6F23, 0x9D69, 0x6F24, 0xE4ED, 0x6F25, 0x9D6A, 0x6F26, 0x9D6B, 0x6F27, 0x9D6C, 0x6F28, 0x9D6D, 0x6F29, 0xE4F6, 0x6F2A, 0xE4F4, 0x6F2B, 0xC2FE, 0x6F2C, 0x9D6E, 0x6F2D, 0xE4DD, 0x6F2E, 0x9D6F, 0x6F2F, 0xE4F0, 0x6F30, 0x9D70, 0x6F31, 0xCAFE, 0x6F32, 0x9D71, 0x6F33, 0xD5C4, 0x6F34, 0x9D72, 0x6F35, 0x9D73, 0x6F36, 0xE4F1, 0x6F37, 0x9D74, 0x6F38, 0x9D75, 0x6F39, 0x9D76, 0x6F3A, 0x9D77, 0x6F3B, 0x9D78, 0x6F3C, 0x9D79, 0x6F3D, 0x9D7A, 0x6F3E, 0xD1FA, 0x6F3F, 0x9D7B, 0x6F40, 0x9D7C, 0x6F41, 0x9D7D, 0x6F42, 0x9D7E, 0x6F43, 0x9D80, 0x6F44, 0x9D81, 0x6F45, 0x9D82, 0x6F46, 0xE4EB, 0x6F47, 0xE4EC, 0x6F48, 0x9D83, 0x6F49, 0x9D84, 0x6F4A, 0x9D85, 0x6F4B, 0xE4F2, 0x6F4C, 0x9D86, 0x6F4D, 0xCEAB, 0x6F4E, 0x9D87, 0x6F4F, 0x9D88, 0x6F50, 0x9D89, 0x6F51, 0x9D8A, 0x6F52, 0x9D8B, 0x6F53, 0x9D8C, 0x6F54, 0x9D8D, 0x6F55, 0x9D8E, 0x6F56, 0x9D8F, 0x6F57, 0x9D90, 0x6F58, 0xC5CB, 0x6F59, 0x9D91, 0x6F5A, 0x9D92, 0x6F5B, 0x9D93, 0x6F5C, 0xC7B1, 0x6F5D, 0x9D94, 0x6F5E, 0xC2BA, 0x6F5F, 0x9D95, 0x6F60, 0x9D96, 0x6F61, 0x9D97, 0x6F62, 0xE4EA, 0x6F63, 0x9D98, 0x6F64, 0x9D99, 0x6F65, 0x9D9A, 0x6F66, 0xC1CA, 0x6F67, 0x9D9B, 0x6F68, 0x9D9C, 0x6F69, 0x9D9D, 0x6F6A, 0x9D9E, 0x6F6B, 0x9D9F, 0x6F6C, 0x9DA0, 0x6F6D, 0xCCB6, 0x6F6E, 0xB3B1, 0x6F6F, 0x9DA1, 0x6F70, 0x9DA2, 0x6F71, 0x9DA3, 0x6F72, 0xE4FB, 0x6F73, 0x9DA4, 0x6F74, 0xE4F3, 0x6F75, 0x9DA5, 0x6F76, 0x9DA6, 0x6F77, 0x9DA7, 0x6F78, 0xE4FA, 0x6F79, 0x9DA8, 0x6F7A, 0xE4FD, 0x6F7B, 0x9DA9, 0x6F7C, 0xE4FC, 0x6F7D, 0x9DAA, 0x6F7E, 0x9DAB, 0x6F7F, 0x9DAC, 0x6F80, 0x9DAD, 0x6F81, 0x9DAE, 0x6F82, 0x9DAF, 0x6F83, 0x9DB0, 0x6F84, 0xB3CE, 0x6F85, 0x9DB1, 0x6F86, 0x9DB2, 0x6F87, 0x9DB3, 0x6F88, 0xB3BA, 0x6F89, 0xE4F7, 0x6F8A, 0x9DB4, 0x6F8B, 0x9DB5, 0x6F8C, 0xE4F9, 0x6F8D, 0xE4F8, 0x6F8E, 0xC5EC, 0x6F8F, 0x9DB6, 0x6F90, 0x9DB7, 0x6F91, 0x9DB8, 0x6F92, 0x9DB9, 0x6F93, 0x9DBA, 0x6F94, 0x9DBB, 0x6F95, 0x9DBC, 0x6F96, 0x9DBD, 0x6F97, 0x9DBE, 0x6F98, 0x9DBF, 0x6F99, 0x9DC0, 0x6F9A, 0x9DC1, 0x6F9B, 0x9DC2, 0x6F9C, 0xC0BD, 0x6F9D, 0x9DC3, 0x6F9E, 0x9DC4, 0x6F9F, 0x9DC5, 0x6FA0, 0x9DC6, 0x6FA1, 0xD4E8, 0x6FA2, 0x9DC7, 0x6FA3, 0x9DC8, 0x6FA4, 0x9DC9, 0x6FA5, 0x9DCA, 0x6FA6, 0x9DCB, 0x6FA7, 0xE5A2, 0x6FA8, 0x9DCC, 0x6FA9, 0x9DCD, 0x6FAA, 0x9DCE, 0x6FAB, 0x9DCF, 0x6FAC, 0x9DD0, 0x6FAD, 0x9DD1, 0x6FAE, 0x9DD2, 0x6FAF, 0x9DD3, 0x6FB0, 0x9DD4, 0x6FB1, 0x9DD5, 0x6FB2, 0x9DD6, 0x6FB3, 0xB0C4, 0x6FB4, 0x9DD7, 0x6FB5, 0x9DD8, 0x6FB6, 0xE5A4, 0x6FB7, 0x9DD9, 0x6FB8, 0x9DDA, 0x6FB9, 0xE5A3, 0x6FBA, 0x9DDB, 0x6FBB, 0x9DDC, 0x6FBC, 0x9DDD, 0x6FBD, 0x9DDE, 0x6FBE, 0x9DDF, 0x6FBF, 0x9DE0, 0x6FC0, 0xBCA4, 0x6FC1, 0x9DE1, 0x6FC2, 0xE5A5, 0x6FC3, 0x9DE2, 0x6FC4, 0x9DE3, 0x6FC5, 0x9DE4, 0x6FC6, 0x9DE5, 0x6FC7, 0x9DE6, 0x6FC8, 0x9DE7, 0x6FC9, 0xE5A1, 0x6FCA, 0x9DE8, 0x6FCB, 0x9DE9, 0x6FCC, 0x9DEA, 0x6FCD, 0x9DEB, 0x6FCE, 0x9DEC, 0x6FCF, 0x9DED, 0x6FD0, 0x9DEE, 0x6FD1, 0xE4FE, 0x6FD2, 0xB1F4, 0x6FD3, 0x9DEF, 0x6FD4, 0x9DF0, 0x6FD5, 0x9DF1, 0x6FD6, 0x9DF2, 0x6FD7, 0x9DF3, 0x6FD8, 0x9DF4, 0x6FD9, 0x9DF5, 0x6FDA, 0x9DF6, 0x6FDB, 0x9DF7, 0x6FDC, 0x9DF8, 0x6FDD, 0x9DF9, 0x6FDE, 0xE5A8, 0x6FDF, 0x9DFA, 0x6FE0, 0xE5A9, 0x6FE1, 0xE5A6, 0x6FE2, 0x9DFB, 0x6FE3, 0x9DFC, 0x6FE4, 0x9DFD, 0x6FE5, 0x9DFE, 0x6FE6, 0x9E40, 0x6FE7, 0x9E41, 0x6FE8, 0x9E42, 0x6FE9, 0x9E43, 0x6FEA, 0x9E44, 0x6FEB, 0x9E45, 0x6FEC, 0x9E46, 0x6FED, 0x9E47, 0x6FEE, 0xE5A7, 0x6FEF, 0xE5AA, 0x6FF0, 0x9E48, 0x6FF1, 0x9E49, 0x6FF2, 0x9E4A, 0x6FF3, 0x9E4B, 0x6FF4, 0x9E4C, 0x6FF5, 0x9E4D, 0x6FF6, 0x9E4E, 0x6FF7, 0x9E4F, 0x6FF8, 0x9E50, 0x6FF9, 0x9E51, 0x6FFA, 0x9E52, 0x6FFB, 0x9E53, 0x6FFC, 0x9E54, 0x6FFD, 0x9E55, 0x6FFE, 0x9E56, 0x6FFF, 0x9E57, 0x7000, 0x9E58, 0x7001, 0x9E59, 0x7002, 0x9E5A, 0x7003, 0x9E5B, 0x7004, 0x9E5C, 0x7005, 0x9E5D, 0x7006, 0x9E5E, 0x7007, 0x9E5F, 0x7008, 0x9E60, 0x7009, 0x9E61, 0x700A, 0x9E62, 0x700B, 0x9E63, 0x700C, 0x9E64, 0x700D, 0x9E65, 0x700E, 0x9E66, 0x700F, 0x9E67, 0x7010, 0x9E68, 0x7011, 0xC6D9, 0x7012, 0x9E69, 0x7013, 0x9E6A, 0x7014, 0x9E6B, 0x7015, 0x9E6C, 0x7016, 0x9E6D, 0x7017, 0x9E6E, 0x7018, 0x9E6F, 0x7019, 0x9E70, 0x701A, 0xE5AB, 0x701B, 0xE5AD, 0x701C, 0x9E71, 0x701D, 0x9E72, 0x701E, 0x9E73, 0x701F, 0x9E74, 0x7020, 0x9E75, 0x7021, 0x9E76, 0x7022, 0x9E77, 0x7023, 0xE5AC, 0x7024, 0x9E78, 0x7025, 0x9E79, 0x7026, 0x9E7A, 0x7027, 0x9E7B, 0x7028, 0x9E7C, 0x7029, 0x9E7D, 0x702A, 0x9E7E, 0x702B, 0x9E80, 0x702C, 0x9E81, 0x702D, 0x9E82, 0x702E, 0x9E83, 0x702F, 0x9E84, 0x7030, 0x9E85, 0x7031, 0x9E86, 0x7032, 0x9E87, 0x7033, 0x9E88, 0x7034, 0x9E89, 0x7035, 0xE5AF, 0x7036, 0x9E8A, 0x7037, 0x9E8B, 0x7038, 0x9E8C, 0x7039, 0xE5AE, 0x703A, 0x9E8D, 0x703B, 0x9E8E, 0x703C, 0x9E8F, 0x703D, 0x9E90, 0x703E, 0x9E91, 0x703F, 0x9E92, 0x7040, 0x9E93, 0x7041, 0x9E94, 0x7042, 0x9E95, 0x7043, 0x9E96, 0x7044, 0x9E97, 0x7045, 0x9E98, 0x7046, 0x9E99, 0x7047, 0x9E9A, 0x7048, 0x9E9B, 0x7049, 0x9E9C, 0x704A, 0x9E9D, 0x704B, 0x9E9E, 0x704C, 0xB9E0, 0x704D, 0x9E9F, 0x704E, 0x9EA0, 0x704F, 0xE5B0, 0x7050, 0x9EA1, 0x7051, 0x9EA2, 0x7052, 0x9EA3, 0x7053, 0x9EA4, 0x7054, 0x9EA5, 0x7055, 0x9EA6, 0x7056, 0x9EA7, 0x7057, 0x9EA8, 0x7058, 0x9EA9, 0x7059, 0x9EAA, 0x705A, 0x9EAB, 0x705B, 0x9EAC, 0x705C, 0x9EAD, 0x705D, 0x9EAE, 0x705E, 0xE5B1, 0x705F, 0x9EAF, 0x7060, 0x9EB0, 0x7061, 0x9EB1, 0x7062, 0x9EB2, 0x7063, 0x9EB3, 0x7064, 0x9EB4, 0x7065, 0x9EB5, 0x7066, 0x9EB6, 0x7067, 0x9EB7, 0x7068, 0x9EB8, 0x7069, 0x9EB9, 0x706A, 0x9EBA, 0x706B, 0xBBF0, 0x706C, 0xECE1, 0x706D, 0xC3F0, 0x706E, 0x9EBB, 0x706F, 0xB5C6, 0x7070, 0xBBD2, 0x7071, 0x9EBC, 0x7072, 0x9EBD, 0x7073, 0x9EBE, 0x7074, 0x9EBF, 0x7075, 0xC1E9, 0x7076, 0xD4EE, 0x7077, 0x9EC0, 0x7078, 0xBEC4, 0x7079, 0x9EC1, 0x707A, 0x9EC2, 0x707B, 0x9EC3, 0x707C, 0xD7C6, 0x707D, 0x9EC4, 0x707E, 0xD4D6, 0x707F, 0xB2D3, 0x7080, 0xECBE, 0x7081, 0x9EC5, 0x7082, 0x9EC6, 0x7083, 0x9EC7, 0x7084, 0x9EC8, 0x7085, 0xEAC1, 0x7086, 0x9EC9, 0x7087, 0x9ECA, 0x7088, 0x9ECB, 0x7089, 0xC2AF, 0x708A, 0xB4B6, 0x708B, 0x9ECC, 0x708C, 0x9ECD, 0x708D, 0x9ECE, 0x708E, 0xD1D7, 0x708F, 0x9ECF, 0x7090, 0x9ED0, 0x7091, 0x9ED1, 0x7092, 0xB3B4, 0x7093, 0x9ED2, 0x7094, 0xC8B2, 0x7095, 0xBFBB, 0x7096, 0xECC0, 0x7097, 0x9ED3, 0x7098, 0x9ED4, 0x7099, 0xD6CB, 0x709A, 0x9ED5, 0x709B, 0x9ED6, 0x709C, 0xECBF, 0x709D, 0xECC1, 0x709E, 0x9ED7, 0x709F, 0x9ED8, 0x70A0, 0x9ED9, 0x70A1, 0x9EDA, 0x70A2, 0x9EDB, 0x70A3, 0x9EDC, 0x70A4, 0x9EDD, 0x70A5, 0x9EDE, 0x70A6, 0x9EDF, 0x70A7, 0x9EE0, 0x70A8, 0x9EE1, 0x70A9, 0x9EE2, 0x70AA, 0x9EE3, 0x70AB, 0xECC5, 0x70AC, 0xBEE6, 0x70AD, 0xCCBF, 0x70AE, 0xC5DA, 0x70AF, 0xBEBC, 0x70B0, 0x9EE4, 0x70B1, 0xECC6, 0x70B2, 0x9EE5, 0x70B3, 0xB1FE, 0x70B4, 0x9EE6, 0x70B5, 0x9EE7, 0x70B6, 0x9EE8, 0x70B7, 0xECC4, 0x70B8, 0xD5A8, 0x70B9, 0xB5E3, 0x70BA, 0x9EE9, 0x70BB, 0xECC2, 0x70BC, 0xC1B6, 0x70BD, 0xB3E3, 0x70BE, 0x9EEA, 0x70BF, 0x9EEB, 0x70C0, 0xECC3, 0x70C1, 0xCBB8, 0x70C2, 0xC0C3, 0x70C3, 0xCCFE, 0x70C4, 0x9EEC, 0x70C5, 0x9EED, 0x70C6, 0x9EEE, 0x70C7, 0x9EEF, 0x70C8, 0xC1D2, 0x70C9, 0x9EF0, 0x70CA, 0xECC8, 0x70CB, 0x9EF1, 0x70CC, 0x9EF2, 0x70CD, 0x9EF3, 0x70CE, 0x9EF4, 0x70CF, 0x9EF5, 0x70D0, 0x9EF6, 0x70D1, 0x9EF7, 0x70D2, 0x9EF8, 0x70D3, 0x9EF9, 0x70D4, 0x9EFA, 0x70D5, 0x9EFB, 0x70D6, 0x9EFC, 0x70D7, 0x9EFD, 0x70D8, 0xBAE6, 0x70D9, 0xC0D3, 0x70DA, 0x9EFE, 0x70DB, 0xD6F2, 0x70DC, 0x9F40, 0x70DD, 0x9F41, 0x70DE, 0x9F42, 0x70DF, 0xD1CC, 0x70E0, 0x9F43, 0x70E1, 0x9F44, 0x70E2, 0x9F45, 0x70E3, 0x9F46, 0x70E4, 0xBFBE, 0x70E5, 0x9F47, 0x70E6, 0xB7B3, 0x70E7, 0xC9D5, 0x70E8, 0xECC7, 0x70E9, 0xBBE2, 0x70EA, 0x9F48, 0x70EB, 0xCCCC, 0x70EC, 0xBDFD, 0x70ED, 0xC8C8, 0x70EE, 0x9F49, 0x70EF, 0xCFA9, 0x70F0, 0x9F4A, 0x70F1, 0x9F4B, 0x70F2, 0x9F4C, 0x70F3, 0x9F4D, 0x70F4, 0x9F4E, 0x70F5, 0x9F4F, 0x70F6, 0x9F50, 0x70F7, 0xCDE9, 0x70F8, 0x9F51, 0x70F9, 0xC5EB, 0x70FA, 0x9F52, 0x70FB, 0x9F53, 0x70FC, 0x9F54, 0x70FD, 0xB7E9, 0x70FE, 0x9F55, 0x70FF, 0x9F56, 0x7100, 0x9F57, 0x7101, 0x9F58, 0x7102, 0x9F59, 0x7103, 0x9F5A, 0x7104, 0x9F5B, 0x7105, 0x9F5C, 0x7106, 0x9F5D, 0x7107, 0x9F5E, 0x7108, 0x9F5F, 0x7109, 0xD1C9, 0x710A, 0xBAB8, 0x710B, 0x9F60, 0x710C, 0x9F61, 0x710D, 0x9F62, 0x710E, 0x9F63, 0x710F, 0x9F64, 0x7110, 0xECC9, 0x7111, 0x9F65, 0x7112, 0x9F66, 0x7113, 0xECCA, 0x7114, 0x9F67, 0x7115, 0xBBC0, 0x7116, 0xECCB, 0x7117, 0x9F68, 0x7118, 0xECE2, 0x7119, 0xB1BA, 0x711A, 0xB7D9, 0x711B, 0x9F69, 0x711C, 0x9F6A, 0x711D, 0x9F6B, 0x711E, 0x9F6C, 0x711F, 0x9F6D, 0x7120, 0x9F6E, 0x7121, 0x9F6F, 0x7122, 0x9F70, 0x7123, 0x9F71, 0x7124, 0x9F72, 0x7125, 0x9F73, 0x7126, 0xBDB9, 0x7127, 0x9F74, 0x7128, 0x9F75, 0x7129, 0x9F76, 0x712A, 0x9F77, 0x712B, 0x9F78, 0x712C, 0x9F79, 0x712D, 0x9F7A, 0x712E, 0x9F7B, 0x712F, 0xECCC, 0x7130, 0xD1E6, 0x7131, 0xECCD, 0x7132, 0x9F7C, 0x7133, 0x9F7D, 0x7134, 0x9F7E, 0x7135, 0x9F80, 0x7136, 0xC8BB, 0x7137, 0x9F81, 0x7138, 0x9F82, 0x7139, 0x9F83, 0x713A, 0x9F84, 0x713B, 0x9F85, 0x713C, 0x9F86, 0x713D, 0x9F87, 0x713E, 0x9F88, 0x713F, 0x9F89, 0x7140, 0x9F8A, 0x7141, 0x9F8B, 0x7142, 0x9F8C, 0x7143, 0x9F8D, 0x7144, 0x9F8E, 0x7145, 0xECD1, 0x7146, 0x9F8F, 0x7147, 0x9F90, 0x7148, 0x9F91, 0x7149, 0x9F92, 0x714A, 0xECD3, 0x714B, 0x9F93, 0x714C, 0xBBCD, 0x714D, 0x9F94, 0x714E, 0xBCE5, 0x714F, 0x9F95, 0x7150, 0x9F96, 0x7151, 0x9F97, 0x7152, 0x9F98, 0x7153, 0x9F99, 0x7154, 0x9F9A, 0x7155, 0x9F9B, 0x7156, 0x9F9C, 0x7157, 0x9F9D, 0x7158, 0x9F9E, 0x7159, 0x9F9F, 0x715A, 0x9FA0, 0x715B, 0x9FA1, 0x715C, 0xECCF, 0x715D, 0x9FA2, 0x715E, 0xC9B7, 0x715F, 0x9FA3, 0x7160, 0x9FA4, 0x7161, 0x9FA5, 0x7162, 0x9FA6, 0x7163, 0x9FA7, 0x7164, 0xC3BA, 0x7165, 0x9FA8, 0x7166, 0xECE3, 0x7167, 0xD5D5, 0x7168, 0xECD0, 0x7169, 0x9FA9, 0x716A, 0x9FAA, 0x716B, 0x9FAB, 0x716C, 0x9FAC, 0x716D, 0x9FAD, 0x716E, 0xD6F3, 0x716F, 0x9FAE, 0x7170, 0x9FAF, 0x7171, 0x9FB0, 0x7172, 0xECD2, 0x7173, 0xECCE, 0x7174, 0x9FB1, 0x7175, 0x9FB2, 0x7176, 0x9FB3, 0x7177, 0x9FB4, 0x7178, 0xECD4, 0x7179, 0x9FB5, 0x717A, 0xECD5, 0x717B, 0x9FB6, 0x717C, 0x9FB7, 0x717D, 0xC9BF, 0x717E, 0x9FB8, 0x717F, 0x9FB9, 0x7180, 0x9FBA, 0x7181, 0x9FBB, 0x7182, 0x9FBC, 0x7183, 0x9FBD, 0x7184, 0xCFA8, 0x7185, 0x9FBE, 0x7186, 0x9FBF, 0x7187, 0x9FC0, 0x7188, 0x9FC1, 0x7189, 0x9FC2, 0x718A, 0xD0DC, 0x718B, 0x9FC3, 0x718C, 0x9FC4, 0x718D, 0x9FC5, 0x718E, 0x9FC6, 0x718F, 0xD1AC, 0x7190, 0x9FC7, 0x7191, 0x9FC8, 0x7192, 0x9FC9, 0x7193, 0x9FCA, 0x7194, 0xC8DB, 0x7195, 0x9FCB, 0x7196, 0x9FCC, 0x7197, 0x9FCD, 0x7198, 0xECD6, 0x7199, 0xCEF5, 0x719A, 0x9FCE, 0x719B, 0x9FCF, 0x719C, 0x9FD0, 0x719D, 0x9FD1, 0x719E, 0x9FD2, 0x719F, 0xCAEC, 0x71A0, 0xECDA, 0x71A1, 0x9FD3, 0x71A2, 0x9FD4, 0x71A3, 0x9FD5, 0x71A4, 0x9FD6, 0x71A5, 0x9FD7, 0x71A6, 0x9FD8, 0x71A7, 0x9FD9, 0x71A8, 0xECD9, 0x71A9, 0x9FDA, 0x71AA, 0x9FDB, 0x71AB, 0x9FDC, 0x71AC, 0xB0BE, 0x71AD, 0x9FDD, 0x71AE, 0x9FDE, 0x71AF, 0x9FDF, 0x71B0, 0x9FE0, 0x71B1, 0x9FE1, 0x71B2, 0x9FE2, 0x71B3, 0xECD7, 0x71B4, 0x9FE3, 0x71B5, 0xECD8, 0x71B6, 0x9FE4, 0x71B7, 0x9FE5, 0x71B8, 0x9FE6, 0x71B9, 0xECE4, 0x71BA, 0x9FE7, 0x71BB, 0x9FE8, 0x71BC, 0x9FE9, 0x71BD, 0x9FEA, 0x71BE, 0x9FEB, 0x71BF, 0x9FEC, 0x71C0, 0x9FED, 0x71C1, 0x9FEE, 0x71C2, 0x9FEF, 0x71C3, 0xC8BC, 0x71C4, 0x9FF0, 0x71C5, 0x9FF1, 0x71C6, 0x9FF2, 0x71C7, 0x9FF3, 0x71C8, 0x9FF4, 0x71C9, 0x9FF5, 0x71CA, 0x9FF6, 0x71CB, 0x9FF7, 0x71CC, 0x9FF8, 0x71CD, 0x9FF9, 0x71CE, 0xC1C7, 0x71CF, 0x9FFA, 0x71D0, 0x9FFB, 0x71D1, 0x9FFC, 0x71D2, 0x9FFD, 0x71D3, 0x9FFE, 0x71D4, 0xECDC, 0x71D5, 0xD1E0, 0x71D6, 0xA040, 0x71D7, 0xA041, 0x71D8, 0xA042, 0x71D9, 0xA043, 0x71DA, 0xA044, 0x71DB, 0xA045, 0x71DC, 0xA046, 0x71DD, 0xA047, 0x71DE, 0xA048, 0x71DF, 0xA049, 0x71E0, 0xECDB, 0x71E1, 0xA04A, 0x71E2, 0xA04B, 0x71E3, 0xA04C, 0x71E4, 0xA04D, 0x71E5, 0xD4EF, 0x71E6, 0xA04E, 0x71E7, 0xECDD, 0x71E8, 0xA04F, 0x71E9, 0xA050, 0x71EA, 0xA051, 0x71EB, 0xA052, 0x71EC, 0xA053, 0x71ED, 0xA054, 0x71EE, 0xDBC6, 0x71EF, 0xA055, 0x71F0, 0xA056, 0x71F1, 0xA057, 0x71F2, 0xA058, 0x71F3, 0xA059, 0x71F4, 0xA05A, 0x71F5, 0xA05B, 0x71F6, 0xA05C, 0x71F7, 0xA05D, 0x71F8, 0xA05E, 0x71F9, 0xECDE, 0x71FA, 0xA05F, 0x71FB, 0xA060, 0x71FC, 0xA061, 0x71FD, 0xA062, 0x71FE, 0xA063, 0x71FF, 0xA064, 0x7200, 0xA065, 0x7201, 0xA066, 0x7202, 0xA067, 0x7203, 0xA068, 0x7204, 0xA069, 0x7205, 0xA06A, 0x7206, 0xB1AC, 0x7207, 0xA06B, 0x7208, 0xA06C, 0x7209, 0xA06D, 0x720A, 0xA06E, 0x720B, 0xA06F, 0x720C, 0xA070, 0x720D, 0xA071, 0x720E, 0xA072, 0x720F, 0xA073, 0x7210, 0xA074, 0x7211, 0xA075, 0x7212, 0xA076, 0x7213, 0xA077, 0x7214, 0xA078, 0x7215, 0xA079, 0x7216, 0xA07A, 0x7217, 0xA07B, 0x7218, 0xA07C, 0x7219, 0xA07D, 0x721A, 0xA07E, 0x721B, 0xA080, 0x721C, 0xA081, 0x721D, 0xECDF, 0x721E, 0xA082, 0x721F, 0xA083, 0x7220, 0xA084, 0x7221, 0xA085, 0x7222, 0xA086, 0x7223, 0xA087, 0x7224, 0xA088, 0x7225, 0xA089, 0x7226, 0xA08A, 0x7227, 0xA08B, 0x7228, 0xECE0, 0x7229, 0xA08C, 0x722A, 0xD7A6, 0x722B, 0xA08D, 0x722C, 0xC5C0, 0x722D, 0xA08E, 0x722E, 0xA08F, 0x722F, 0xA090, 0x7230, 0xEBBC, 0x7231, 0xB0AE, 0x7232, 0xA091, 0x7233, 0xA092, 0x7234, 0xA093, 0x7235, 0xBEF4, 0x7236, 0xB8B8, 0x7237, 0xD2AF, 0x7238, 0xB0D6, 0x7239, 0xB5F9, 0x723A, 0xA094, 0x723B, 0xD8B3, 0x723C, 0xA095, 0x723D, 0xCBAC, 0x723E, 0xA096, 0x723F, 0xE3DD, 0x7240, 0xA097, 0x7241, 0xA098, 0x7242, 0xA099, 0x7243, 0xA09A, 0x7244, 0xA09B, 0x7245, 0xA09C, 0x7246, 0xA09D, 0x7247, 0xC6AC, 0x7248, 0xB0E6, 0x7249, 0xA09E, 0x724A, 0xA09F, 0x724B, 0xA0A0, 0x724C, 0xC5C6, 0x724D, 0xEBB9, 0x724E, 0xA0A1, 0x724F, 0xA0A2, 0x7250, 0xA0A3, 0x7251, 0xA0A4, 0x7252, 0xEBBA, 0x7253, 0xA0A5, 0x7254, 0xA0A6, 0x7255, 0xA0A7, 0x7256, 0xEBBB, 0x7257, 0xA0A8, 0x7258, 0xA0A9, 0x7259, 0xD1C0, 0x725A, 0xA0AA, 0x725B, 0xC5A3, 0x725C, 0xA0AB, 0x725D, 0xEAF2, 0x725E, 0xA0AC, 0x725F, 0xC4B2, 0x7260, 0xA0AD, 0x7261, 0xC4B5, 0x7262, 0xC0CE, 0x7263, 0xA0AE, 0x7264, 0xA0AF, 0x7265, 0xA0B0, 0x7266, 0xEAF3, 0x7267, 0xC4C1, 0x7268, 0xA0B1, 0x7269, 0xCEEF, 0x726A, 0xA0B2, 0x726B, 0xA0B3, 0x726C, 0xA0B4, 0x726D, 0xA0B5, 0x726E, 0xEAF0, 0x726F, 0xEAF4, 0x7270, 0xA0B6, 0x7271, 0xA0B7, 0x7272, 0xC9FC, 0x7273, 0xA0B8, 0x7274, 0xA0B9, 0x7275, 0xC7A3, 0x7276, 0xA0BA, 0x7277, 0xA0BB, 0x7278, 0xA0BC, 0x7279, 0xCCD8, 0x727A, 0xCEFE, 0x727B, 0xA0BD, 0x727C, 0xA0BE, 0x727D, 0xA0BF, 0x727E, 0xEAF5, 0x727F, 0xEAF6, 0x7280, 0xCFAC, 0x7281, 0xC0E7, 0x7282, 0xA0C0, 0x7283, 0xA0C1, 0x7284, 0xEAF7, 0x7285, 0xA0C2, 0x7286, 0xA0C3, 0x7287, 0xA0C4, 0x7288, 0xA0C5, 0x7289, 0xA0C6, 0x728A, 0xB6BF, 0x728B, 0xEAF8, 0x728C, 0xA0C7, 0x728D, 0xEAF9, 0x728E, 0xA0C8, 0x728F, 0xEAFA, 0x7290, 0xA0C9, 0x7291, 0xA0CA, 0x7292, 0xEAFB, 0x7293, 0xA0CB, 0x7294, 0xA0CC, 0x7295, 0xA0CD, 0x7296, 0xA0CE, 0x7297, 0xA0CF, 0x7298, 0xA0D0, 0x7299, 0xA0D1, 0x729A, 0xA0D2, 0x729B, 0xA0D3, 0x729C, 0xA0D4, 0x729D, 0xA0D5, 0x729E, 0xA0D6, 0x729F, 0xEAF1, 0x72A0, 0xA0D7, 0x72A1, 0xA0D8, 0x72A2, 0xA0D9, 0x72A3, 0xA0DA, 0x72A4, 0xA0DB, 0x72A5, 0xA0DC, 0x72A6, 0xA0DD, 0x72A7, 0xA0DE, 0x72A8, 0xA0DF, 0x72A9, 0xA0E0, 0x72AA, 0xA0E1, 0x72AB, 0xA0E2, 0x72AC, 0xC8AE, 0x72AD, 0xE1EB, 0x72AE, 0xA0E3, 0x72AF, 0xB7B8, 0x72B0, 0xE1EC, 0x72B1, 0xA0E4, 0x72B2, 0xA0E5, 0x72B3, 0xA0E6, 0x72B4, 0xE1ED, 0x72B5, 0xA0E7, 0x72B6, 0xD7B4, 0x72B7, 0xE1EE, 0x72B8, 0xE1EF, 0x72B9, 0xD3CC, 0x72BA, 0xA0E8, 0x72BB, 0xA0E9, 0x72BC, 0xA0EA, 0x72BD, 0xA0EB, 0x72BE, 0xA0EC, 0x72BF, 0xA0ED, 0x72C0, 0xA0EE, 0x72C1, 0xE1F1, 0x72C2, 0xBFF1, 0x72C3, 0xE1F0, 0x72C4, 0xB5D2, 0x72C5, 0xA0EF, 0x72C6, 0xA0F0, 0x72C7, 0xA0F1, 0x72C8, 0xB1B7, 0x72C9, 0xA0F2, 0x72CA, 0xA0F3, 0x72CB, 0xA0F4, 0x72CC, 0xA0F5, 0x72CD, 0xE1F3, 0x72CE, 0xE1F2, 0x72CF, 0xA0F6, 0x72D0, 0xBAFC, 0x72D1, 0xA0F7, 0x72D2, 0xE1F4, 0x72D3, 0xA0F8, 0x72D4, 0xA0F9, 0x72D5, 0xA0FA, 0x72D6, 0xA0FB, 0x72D7, 0xB9B7, 0x72D8, 0xA0FC, 0x72D9, 0xBED1, 0x72DA, 0xA0FD, 0x72DB, 0xA0FE, 0x72DC, 0xAA40, 0x72DD, 0xAA41, 0x72DE, 0xC4FC, 0x72DF, 0xAA42, 0x72E0, 0xBADD, 0x72E1, 0xBDC6, 0x72E2, 0xAA43, 0x72E3, 0xAA44, 0x72E4, 0xAA45, 0x72E5, 0xAA46, 0x72E6, 0xAA47, 0x72E7, 0xAA48, 0x72E8, 0xE1F5, 0x72E9, 0xE1F7, 0x72EA, 0xAA49, 0x72EB, 0xAA4A, 0x72EC, 0xB6C0, 0x72ED, 0xCFC1, 0x72EE, 0xCAA8, 0x72EF, 0xE1F6, 0x72F0, 0xD5F8, 0x72F1, 0xD3FC, 0x72F2, 0xE1F8, 0x72F3, 0xE1FC, 0x72F4, 0xE1F9, 0x72F5, 0xAA4B, 0x72F6, 0xAA4C, 0x72F7, 0xE1FA, 0x72F8, 0xC0EA, 0x72F9, 0xAA4D, 0x72FA, 0xE1FE, 0x72FB, 0xE2A1, 0x72FC, 0xC0C7, 0x72FD, 0xAA4E, 0x72FE, 0xAA4F, 0x72FF, 0xAA50, 0x7300, 0xAA51, 0x7301, 0xE1FB, 0x7302, 0xAA52, 0x7303, 0xE1FD, 0x7304, 0xAA53, 0x7305, 0xAA54, 0x7306, 0xAA55, 0x7307, 0xAA56, 0x7308, 0xAA57, 0x7309, 0xAA58, 0x730A, 0xE2A5, 0x730B, 0xAA59, 0x730C, 0xAA5A, 0x730D, 0xAA5B, 0x730E, 0xC1D4, 0x730F, 0xAA5C, 0x7310, 0xAA5D, 0x7311, 0xAA5E, 0x7312, 0xAA5F, 0x7313, 0xE2A3, 0x7314, 0xAA60, 0x7315, 0xE2A8, 0x7316, 0xB2FE, 0x7317, 0xE2A2, 0x7318, 0xAA61, 0x7319, 0xAA62, 0x731A, 0xAA63, 0x731B, 0xC3CD, 0x731C, 0xB2C2, 0x731D, 0xE2A7, 0x731E, 0xE2A6, 0x731F, 0xAA64, 0x7320, 0xAA65, 0x7321, 0xE2A4, 0x7322, 0xE2A9, 0x7323, 0xAA66, 0x7324, 0xAA67, 0x7325, 0xE2AB, 0x7326, 0xAA68, 0x7327, 0xAA69, 0x7328, 0xAA6A, 0x7329, 0xD0C9, 0x732A, 0xD6ED, 0x732B, 0xC3A8, 0x732C, 0xE2AC, 0x732D, 0xAA6B, 0x732E, 0xCFD7, 0x732F, 0xAA6C, 0x7330, 0xAA6D, 0x7331, 0xE2AE, 0x7332, 0xAA6E, 0x7333, 0xAA6F, 0x7334, 0xBAEF, 0x7335, 0xAA70, 0x7336, 0xAA71, 0x7337, 0xE9E0, 0x7338, 0xE2AD, 0x7339, 0xE2AA, 0x733A, 0xAA72, 0x733B, 0xAA73, 0x733C, 0xAA74, 0x733D, 0xAA75, 0x733E, 0xBBAB, 0x733F, 0xD4B3, 0x7340, 0xAA76, 0x7341, 0xAA77, 0x7342, 0xAA78, 0x7343, 0xAA79, 0x7344, 0xAA7A, 0x7345, 0xAA7B, 0x7346, 0xAA7C, 0x7347, 0xAA7D, 0x7348, 0xAA7E, 0x7349, 0xAA80, 0x734A, 0xAA81, 0x734B, 0xAA82, 0x734C, 0xAA83, 0x734D, 0xE2B0, 0x734E, 0xAA84, 0x734F, 0xAA85, 0x7350, 0xE2AF, 0x7351, 0xAA86, 0x7352, 0xE9E1, 0x7353, 0xAA87, 0x7354, 0xAA88, 0x7355, 0xAA89, 0x7356, 0xAA8A, 0x7357, 0xE2B1, 0x7358, 0xAA8B, 0x7359, 0xAA8C, 0x735A, 0xAA8D, 0x735B, 0xAA8E, 0x735C, 0xAA8F, 0x735D, 0xAA90, 0x735E, 0xAA91, 0x735F, 0xAA92, 0x7360, 0xE2B2, 0x7361, 0xAA93, 0x7362, 0xAA94, 0x7363, 0xAA95, 0x7364, 0xAA96, 0x7365, 0xAA97, 0x7366, 0xAA98, 0x7367, 0xAA99, 0x7368, 0xAA9A, 0x7369, 0xAA9B, 0x736A, 0xAA9C, 0x736B, 0xAA9D, 0x736C, 0xE2B3, 0x736D, 0xCCA1, 0x736E, 0xAA9E, 0x736F, 0xE2B4, 0x7370, 0xAA9F, 0x7371, 0xAAA0, 0x7372, 0xAB40, 0x7373, 0xAB41, 0x7374, 0xAB42, 0x7375, 0xAB43, 0x7376, 0xAB44, 0x7377, 0xAB45, 0x7378, 0xAB46, 0x7379, 0xAB47, 0x737A, 0xAB48, 0x737B, 0xAB49, 0x737C, 0xAB4A, 0x737D, 0xAB4B, 0x737E, 0xE2B5, 0x737F, 0xAB4C, 0x7380, 0xAB4D, 0x7381, 0xAB4E, 0x7382, 0xAB4F, 0x7383, 0xAB50, 0x7384, 0xD0FE, 0x7385, 0xAB51, 0x7386, 0xAB52, 0x7387, 0xC2CA, 0x7388, 0xAB53, 0x7389, 0xD3F1, 0x738A, 0xAB54, 0x738B, 0xCDF5, 0x738C, 0xAB55, 0x738D, 0xAB56, 0x738E, 0xE7E0, 0x738F, 0xAB57, 0x7390, 0xAB58, 0x7391, 0xE7E1, 0x7392, 0xAB59, 0x7393, 0xAB5A, 0x7394, 0xAB5B, 0x7395, 0xAB5C, 0x7396, 0xBEC1, 0x7397, 0xAB5D, 0x7398, 0xAB5E, 0x7399, 0xAB5F, 0x739A, 0xAB60, 0x739B, 0xC2EA, 0x739C, 0xAB61, 0x739D, 0xAB62, 0x739E, 0xAB63, 0x739F, 0xE7E4, 0x73A0, 0xAB64, 0x73A1, 0xAB65, 0x73A2, 0xE7E3, 0x73A3, 0xAB66, 0x73A4, 0xAB67, 0x73A5, 0xAB68, 0x73A6, 0xAB69, 0x73A7, 0xAB6A, 0x73A8, 0xAB6B, 0x73A9, 0xCDE6, 0x73AA, 0xAB6C, 0x73AB, 0xC3B5, 0x73AC, 0xAB6D, 0x73AD, 0xAB6E, 0x73AE, 0xE7E2, 0x73AF, 0xBBB7, 0x73B0, 0xCFD6, 0x73B1, 0xAB6F, 0x73B2, 0xC1E1, 0x73B3, 0xE7E9, 0x73B4, 0xAB70, 0x73B5, 0xAB71, 0x73B6, 0xAB72, 0x73B7, 0xE7E8, 0x73B8, 0xAB73, 0x73B9, 0xAB74, 0x73BA, 0xE7F4, 0x73BB, 0xB2A3, 0x73BC, 0xAB75, 0x73BD, 0xAB76, 0x73BE, 0xAB77, 0x73BF, 0xAB78, 0x73C0, 0xE7EA, 0x73C1, 0xAB79, 0x73C2, 0xE7E6, 0x73C3, 0xAB7A, 0x73C4, 0xAB7B, 0x73C5, 0xAB7C, 0x73C6, 0xAB7D, 0x73C7, 0xAB7E, 0x73C8, 0xE7EC, 0x73C9, 0xE7EB, 0x73CA, 0xC9BA, 0x73CB, 0xAB80, 0x73CC, 0xAB81, 0x73CD, 0xD5E4, 0x73CE, 0xAB82, 0x73CF, 0xE7E5, 0x73D0, 0xB7A9, 0x73D1, 0xE7E7, 0x73D2, 0xAB83, 0x73D3, 0xAB84, 0x73D4, 0xAB85, 0x73D5, 0xAB86, 0x73D6, 0xAB87, 0x73D7, 0xAB88, 0x73D8, 0xAB89, 0x73D9, 0xE7EE, 0x73DA, 0xAB8A, 0x73DB, 0xAB8B, 0x73DC, 0xAB8C, 0x73DD, 0xAB8D, 0x73DE, 0xE7F3, 0x73DF, 0xAB8E, 0x73E0, 0xD6E9, 0x73E1, 0xAB8F, 0x73E2, 0xAB90, 0x73E3, 0xAB91, 0x73E4, 0xAB92, 0x73E5, 0xE7ED, 0x73E6, 0xAB93, 0x73E7, 0xE7F2, 0x73E8, 0xAB94, 0x73E9, 0xE7F1, 0x73EA, 0xAB95, 0x73EB, 0xAB96, 0x73EC, 0xAB97, 0x73ED, 0xB0E0, 0x73EE, 0xAB98, 0x73EF, 0xAB99, 0x73F0, 0xAB9A, 0x73F1, 0xAB9B, 0x73F2, 0xE7F5, 0x73F3, 0xAB9C, 0x73F4, 0xAB9D, 0x73F5, 0xAB9E, 0x73F6, 0xAB9F, 0x73F7, 0xABA0, 0x73F8, 0xAC40, 0x73F9, 0xAC41, 0x73FA, 0xAC42, 0x73FB, 0xAC43, 0x73FC, 0xAC44, 0x73FD, 0xAC45, 0x73FE, 0xAC46, 0x73FF, 0xAC47, 0x7400, 0xAC48, 0x7401, 0xAC49, 0x7402, 0xAC4A, 0x7403, 0xC7F2, 0x7404, 0xAC4B, 0x7405, 0xC0C5, 0x7406, 0xC0ED, 0x7407, 0xAC4C, 0x7408, 0xAC4D, 0x7409, 0xC1F0, 0x740A, 0xE7F0, 0x740B, 0xAC4E, 0x740C, 0xAC4F, 0x740D, 0xAC50, 0x740E, 0xAC51, 0x740F, 0xE7F6, 0x7410, 0xCBF6, 0x7411, 0xAC52, 0x7412, 0xAC53, 0x7413, 0xAC54, 0x7414, 0xAC55, 0x7415, 0xAC56, 0x7416, 0xAC57, 0x7417, 0xAC58, 0x7418, 0xAC59, 0x7419, 0xAC5A, 0x741A, 0xE8A2, 0x741B, 0xE8A1, 0x741C, 0xAC5B, 0x741D, 0xAC5C, 0x741E, 0xAC5D, 0x741F, 0xAC5E, 0x7420, 0xAC5F, 0x7421, 0xAC60, 0x7422, 0xD7C1, 0x7423, 0xAC61, 0x7424, 0xAC62, 0x7425, 0xE7FA, 0x7426, 0xE7F9, 0x7427, 0xAC63, 0x7428, 0xE7FB, 0x7429, 0xAC64, 0x742A, 0xE7F7, 0x742B, 0xAC65, 0x742C, 0xE7FE, 0x742D, 0xAC66, 0x742E, 0xE7FD, 0x742F, 0xAC67, 0x7430, 0xE7FC, 0x7431, 0xAC68, 0x7432, 0xAC69, 0x7433, 0xC1D5, 0x7434, 0xC7D9, 0x7435, 0xC5FD, 0x7436, 0xC5C3, 0x7437, 0xAC6A, 0x7438, 0xAC6B, 0x7439, 0xAC6C, 0x743A, 0xAC6D, 0x743B, 0xAC6E, 0x743C, 0xC7ED, 0x743D, 0xAC6F, 0x743E, 0xAC70, 0x743F, 0xAC71, 0x7440, 0xAC72, 0x7441, 0xE8A3, 0x7442, 0xAC73, 0x7443, 0xAC74, 0x7444, 0xAC75, 0x7445, 0xAC76, 0x7446, 0xAC77, 0x7447, 0xAC78, 0x7448, 0xAC79, 0x7449, 0xAC7A, 0x744A, 0xAC7B, 0x744B, 0xAC7C, 0x744C, 0xAC7D, 0x744D, 0xAC7E, 0x744E, 0xAC80, 0x744F, 0xAC81, 0x7450, 0xAC82, 0x7451, 0xAC83, 0x7452, 0xAC84, 0x7453, 0xAC85, 0x7454, 0xAC86, 0x7455, 0xE8A6, 0x7456, 0xAC87, 0x7457, 0xE8A5, 0x7458, 0xAC88, 0x7459, 0xE8A7, 0x745A, 0xBAF7, 0x745B, 0xE7F8, 0x745C, 0xE8A4, 0x745D, 0xAC89, 0x745E, 0xC8F0, 0x745F, 0xC9AA, 0x7460, 0xAC8A, 0x7461, 0xAC8B, 0x7462, 0xAC8C, 0x7463, 0xAC8D, 0x7464, 0xAC8E, 0x7465, 0xAC8F, 0x7466, 0xAC90, 0x7467, 0xAC91, 0x7468, 0xAC92, 0x7469, 0xAC93, 0x746A, 0xAC94, 0x746B, 0xAC95, 0x746C, 0xAC96, 0x746D, 0xE8A9, 0x746E, 0xAC97, 0x746F, 0xAC98, 0x7470, 0xB9E5, 0x7471, 0xAC99, 0x7472, 0xAC9A, 0x7473, 0xAC9B, 0x7474, 0xAC9C, 0x7475, 0xAC9D, 0x7476, 0xD1FE, 0x7477, 0xE8A8, 0x7478, 0xAC9E, 0x7479, 0xAC9F, 0x747A, 0xACA0, 0x747B, 0xAD40, 0x747C, 0xAD41, 0x747D, 0xAD42, 0x747E, 0xE8AA, 0x747F, 0xAD43, 0x7480, 0xE8AD, 0x7481, 0xE8AE, 0x7482, 0xAD44, 0x7483, 0xC1A7, 0x7484, 0xAD45, 0x7485, 0xAD46, 0x7486, 0xAD47, 0x7487, 0xE8AF, 0x7488, 0xAD48, 0x7489, 0xAD49, 0x748A, 0xAD4A, 0x748B, 0xE8B0, 0x748C, 0xAD4B, 0x748D, 0xAD4C, 0x748E, 0xE8AC, 0x748F, 0xAD4D, 0x7490, 0xE8B4, 0x7491, 0xAD4E, 0x7492, 0xAD4F, 0x7493, 0xAD50, 0x7494, 0xAD51, 0x7495, 0xAD52, 0x7496, 0xAD53, 0x7497, 0xAD54, 0x7498, 0xAD55, 0x7499, 0xAD56, 0x749A, 0xAD57, 0x749B, 0xAD58, 0x749C, 0xE8AB, 0x749D, 0xAD59, 0x749E, 0xE8B1, 0x749F, 0xAD5A, 0x74A0, 0xAD5B, 0x74A1, 0xAD5C, 0x74A2, 0xAD5D, 0x74A3, 0xAD5E, 0x74A4, 0xAD5F, 0x74A5, 0xAD60, 0x74A6, 0xAD61, 0x74A7, 0xE8B5, 0x74A8, 0xE8B2, 0x74A9, 0xE8B3, 0x74AA, 0xAD62, 0x74AB, 0xAD63, 0x74AC, 0xAD64, 0x74AD, 0xAD65, 0x74AE, 0xAD66, 0x74AF, 0xAD67, 0x74B0, 0xAD68, 0x74B1, 0xAD69, 0x74B2, 0xAD6A, 0x74B3, 0xAD6B, 0x74B4, 0xAD6C, 0x74B5, 0xAD6D, 0x74B6, 0xAD6E, 0x74B7, 0xAD6F, 0x74B8, 0xAD70, 0x74B9, 0xAD71, 0x74BA, 0xE8B7, 0x74BB, 0xAD72, 0x74BC, 0xAD73, 0x74BD, 0xAD74, 0x74BE, 0xAD75, 0x74BF, 0xAD76, 0x74C0, 0xAD77, 0x74C1, 0xAD78, 0x74C2, 0xAD79, 0x74C3, 0xAD7A, 0x74C4, 0xAD7B, 0x74C5, 0xAD7C, 0x74C6, 0xAD7D, 0x74C7, 0xAD7E, 0x74C8, 0xAD80, 0x74C9, 0xAD81, 0x74CA, 0xAD82, 0x74CB, 0xAD83, 0x74CC, 0xAD84, 0x74CD, 0xAD85, 0x74CE, 0xAD86, 0x74CF, 0xAD87, 0x74D0, 0xAD88, 0x74D1, 0xAD89, 0x74D2, 0xE8B6, 0x74D3, 0xAD8A, 0x74D4, 0xAD8B, 0x74D5, 0xAD8C, 0x74D6, 0xAD8D, 0x74D7, 0xAD8E, 0x74D8, 0xAD8F, 0x74D9, 0xAD90, 0x74DA, 0xAD91, 0x74DB, 0xAD92, 0x74DC, 0xB9CF, 0x74DD, 0xAD93, 0x74DE, 0xF0AC, 0x74DF, 0xAD94, 0x74E0, 0xF0AD, 0x74E1, 0xAD95, 0x74E2, 0xC6B0, 0x74E3, 0xB0EA, 0x74E4, 0xC8BF, 0x74E5, 0xAD96, 0x74E6, 0xCDDF, 0x74E7, 0xAD97, 0x74E8, 0xAD98, 0x74E9, 0xAD99, 0x74EA, 0xAD9A, 0x74EB, 0xAD9B, 0x74EC, 0xAD9C, 0x74ED, 0xAD9D, 0x74EE, 0xCECD, 0x74EF, 0xEAB1, 0x74F0, 0xAD9E, 0x74F1, 0xAD9F, 0x74F2, 0xADA0, 0x74F3, 0xAE40, 0x74F4, 0xEAB2, 0x74F5, 0xAE41, 0x74F6, 0xC6BF, 0x74F7, 0xB4C9, 0x74F8, 0xAE42, 0x74F9, 0xAE43, 0x74FA, 0xAE44, 0x74FB, 0xAE45, 0x74FC, 0xAE46, 0x74FD, 0xAE47, 0x74FE, 0xAE48, 0x74FF, 0xEAB3, 0x7500, 0xAE49, 0x7501, 0xAE4A, 0x7502, 0xAE4B, 0x7503, 0xAE4C, 0x7504, 0xD5E7, 0x7505, 0xAE4D, 0x7506, 0xAE4E, 0x7507, 0xAE4F, 0x7508, 0xAE50, 0x7509, 0xAE51, 0x750A, 0xAE52, 0x750B, 0xAE53, 0x750C, 0xAE54, 0x750D, 0xDDF9, 0x750E, 0xAE55, 0x750F, 0xEAB4, 0x7510, 0xAE56, 0x7511, 0xEAB5, 0x7512, 0xAE57, 0x7513, 0xEAB6, 0x7514, 0xAE58, 0x7515, 0xAE59, 0x7516, 0xAE5A, 0x7517, 0xAE5B, 0x7518, 0xB8CA, 0x7519, 0xDFB0, 0x751A, 0xC9F5, 0x751B, 0xAE5C, 0x751C, 0xCCF0, 0x751D, 0xAE5D, 0x751E, 0xAE5E, 0x751F, 0xC9FA, 0x7520, 0xAE5F, 0x7521, 0xAE60, 0x7522, 0xAE61, 0x7523, 0xAE62, 0x7524, 0xAE63, 0x7525, 0xC9FB, 0x7526, 0xAE64, 0x7527, 0xAE65, 0x7528, 0xD3C3, 0x7529, 0xCBA6, 0x752A, 0xAE66, 0x752B, 0xB8A6, 0x752C, 0xF0AE, 0x752D, 0xB1C2, 0x752E, 0xAE67, 0x752F, 0xE5B8, 0x7530, 0xCCEF, 0x7531, 0xD3C9, 0x7532, 0xBCD7, 0x7533, 0xC9EA, 0x7534, 0xAE68, 0x7535, 0xB5E7, 0x7536, 0xAE69, 0x7537, 0xC4D0, 0x7538, 0xB5E9, 0x7539, 0xAE6A, 0x753A, 0xEEAE, 0x753B, 0xBBAD, 0x753C, 0xAE6B, 0x753D, 0xAE6C, 0x753E, 0xE7DE, 0x753F, 0xAE6D, 0x7540, 0xEEAF, 0x7541, 0xAE6E, 0x7542, 0xAE6F, 0x7543, 0xAE70, 0x7544, 0xAE71, 0x7545, 0xB3A9, 0x7546, 0xAE72, 0x7547, 0xAE73, 0x7548, 0xEEB2, 0x7549, 0xAE74, 0x754A, 0xAE75, 0x754B, 0xEEB1, 0x754C, 0xBDE7, 0x754D, 0xAE76, 0x754E, 0xEEB0, 0x754F, 0xCEB7, 0x7550, 0xAE77, 0x7551, 0xAE78, 0x7552, 0xAE79, 0x7553, 0xAE7A, 0x7554, 0xC5CF, 0x7555, 0xAE7B, 0x7556, 0xAE7C, 0x7557, 0xAE7D, 0x7558, 0xAE7E, 0x7559, 0xC1F4, 0x755A, 0xDBCE, 0x755B, 0xEEB3, 0x755C, 0xD0F3, 0x755D, 0xAE80, 0x755E, 0xAE81, 0x755F, 0xAE82, 0x7560, 0xAE83, 0x7561, 0xAE84, 0x7562, 0xAE85, 0x7563, 0xAE86, 0x7564, 0xAE87, 0x7565, 0xC2D4, 0x7566, 0xC6E8, 0x7567, 0xAE88, 0x7568, 0xAE89, 0x7569, 0xAE8A, 0x756A, 0xB7AC, 0x756B, 0xAE8B, 0x756C, 0xAE8C, 0x756D, 0xAE8D, 0x756E, 0xAE8E, 0x756F, 0xAE8F, 0x7570, 0xAE90, 0x7571, 0xAE91, 0x7572, 0xEEB4, 0x7573, 0xAE92, 0x7574, 0xB3EB, 0x7575, 0xAE93, 0x7576, 0xAE94, 0x7577, 0xAE95, 0x7578, 0xBBFB, 0x7579, 0xEEB5, 0x757A, 0xAE96, 0x757B, 0xAE97, 0x757C, 0xAE98, 0x757D, 0xAE99, 0x757E, 0xAE9A, 0x757F, 0xE7DC, 0x7580, 0xAE9B, 0x7581, 0xAE9C, 0x7582, 0xAE9D, 0x7583, 0xEEB6, 0x7584, 0xAE9E, 0x7585, 0xAE9F, 0x7586, 0xBDAE, 0x7587, 0xAEA0, 0x7588, 0xAF40, 0x7589, 0xAF41, 0x758A, 0xAF42, 0x758B, 0xF1E2, 0x758C, 0xAF43, 0x758D, 0xAF44, 0x758E, 0xAF45, 0x758F, 0xCAE8, 0x7590, 0xAF46, 0x7591, 0xD2C9, 0x7592, 0xF0DA, 0x7593, 0xAF47, 0x7594, 0xF0DB, 0x7595, 0xAF48, 0x7596, 0xF0DC, 0x7597, 0xC1C6, 0x7598, 0xAF49, 0x7599, 0xB8ED, 0x759A, 0xBECE, 0x759B, 0xAF4A, 0x759C, 0xAF4B, 0x759D, 0xF0DE, 0x759E, 0xAF4C, 0x759F, 0xC5B1, 0x75A0, 0xF0DD, 0x75A1, 0xD1F1, 0x75A2, 0xAF4D, 0x75A3, 0xF0E0, 0x75A4, 0xB0CC, 0x75A5, 0xBDEA, 0x75A6, 0xAF4E, 0x75A7, 0xAF4F, 0x75A8, 0xAF50, 0x75A9, 0xAF51, 0x75AA, 0xAF52, 0x75AB, 0xD2DF, 0x75AC, 0xF0DF, 0x75AD, 0xAF53, 0x75AE, 0xB4AF, 0x75AF, 0xB7E8, 0x75B0, 0xF0E6, 0x75B1, 0xF0E5, 0x75B2, 0xC6A3, 0x75B3, 0xF0E1, 0x75B4, 0xF0E2, 0x75B5, 0xB4C3, 0x75B6, 0xAF54, 0x75B7, 0xAF55, 0x75B8, 0xF0E3, 0x75B9, 0xD5EE, 0x75BA, 0xAF56, 0x75BB, 0xAF57, 0x75BC, 0xCCDB, 0x75BD, 0xBED2, 0x75BE, 0xBCB2, 0x75BF, 0xAF58, 0x75C0, 0xAF59, 0x75C1, 0xAF5A, 0x75C2, 0xF0E8, 0x75C3, 0xF0E7, 0x75C4, 0xF0E4, 0x75C5, 0xB2A1, 0x75C6, 0xAF5B, 0x75C7, 0xD6A2, 0x75C8, 0xD3B8, 0x75C9, 0xBEB7, 0x75CA, 0xC8AC, 0x75CB, 0xAF5C, 0x75CC, 0xAF5D, 0x75CD, 0xF0EA, 0x75CE, 0xAF5E, 0x75CF, 0xAF5F, 0x75D0, 0xAF60, 0x75D1, 0xAF61, 0x75D2, 0xD1F7, 0x75D3, 0xAF62, 0x75D4, 0xD6CC, 0x75D5, 0xBADB, 0x75D6, 0xF0E9, 0x75D7, 0xAF63, 0x75D8, 0xB6BB, 0x75D9, 0xAF64, 0x75DA, 0xAF65, 0x75DB, 0xCDB4, 0x75DC, 0xAF66, 0x75DD, 0xAF67, 0x75DE, 0xC6A6, 0x75DF, 0xAF68, 0x75E0, 0xAF69, 0x75E1, 0xAF6A, 0x75E2, 0xC1A1, 0x75E3, 0xF0EB, 0x75E4, 0xF0EE, 0x75E5, 0xAF6B, 0x75E6, 0xF0ED, 0x75E7, 0xF0F0, 0x75E8, 0xF0EC, 0x75E9, 0xAF6C, 0x75EA, 0xBBBE, 0x75EB, 0xF0EF, 0x75EC, 0xAF6D, 0x75ED, 0xAF6E, 0x75EE, 0xAF6F, 0x75EF, 0xAF70, 0x75F0, 0xCCB5, 0x75F1, 0xF0F2, 0x75F2, 0xAF71, 0x75F3, 0xAF72, 0x75F4, 0xB3D5, 0x75F5, 0xAF73, 0x75F6, 0xAF74, 0x75F7, 0xAF75, 0x75F8, 0xAF76, 0x75F9, 0xB1D4, 0x75FA, 0xAF77, 0x75FB, 0xAF78, 0x75FC, 0xF0F3, 0x75FD, 0xAF79, 0x75FE, 0xAF7A, 0x75FF, 0xF0F4, 0x7600, 0xF0F6, 0x7601, 0xB4E1, 0x7602, 0xAF7B, 0x7603, 0xF0F1, 0x7604, 0xAF7C, 0x7605, 0xF0F7, 0x7606, 0xAF7D, 0x7607, 0xAF7E, 0x7608, 0xAF80, 0x7609, 0xAF81, 0x760A, 0xF0FA, 0x760B, 0xAF82, 0x760C, 0xF0F8, 0x760D, 0xAF83, 0x760E, 0xAF84, 0x760F, 0xAF85, 0x7610, 0xF0F5, 0x7611, 0xAF86, 0x7612, 0xAF87, 0x7613, 0xAF88, 0x7614, 0xAF89, 0x7615, 0xF0FD, 0x7616, 0xAF8A, 0x7617, 0xF0F9, 0x7618, 0xF0FC, 0x7619, 0xF0FE, 0x761A, 0xAF8B, 0x761B, 0xF1A1, 0x761C, 0xAF8C, 0x761D, 0xAF8D, 0x761E, 0xAF8E, 0x761F, 0xCEC1, 0x7620, 0xF1A4, 0x7621, 0xAF8F, 0x7622, 0xF1A3, 0x7623, 0xAF90, 0x7624, 0xC1F6, 0x7625, 0xF0FB, 0x7626, 0xCADD, 0x7627, 0xAF91, 0x7628, 0xAF92, 0x7629, 0xB4F1, 0x762A, 0xB1F1, 0x762B, 0xCCB1, 0x762C, 0xAF93, 0x762D, 0xF1A6, 0x762E, 0xAF94, 0x762F, 0xAF95, 0x7630, 0xF1A7, 0x7631, 0xAF96, 0x7632, 0xAF97, 0x7633, 0xF1AC, 0x7634, 0xD5CE, 0x7635, 0xF1A9, 0x7636, 0xAF98, 0x7637, 0xAF99, 0x7638, 0xC8B3, 0x7639, 0xAF9A, 0x763A, 0xAF9B, 0x763B, 0xAF9C, 0x763C, 0xF1A2, 0x763D, 0xAF9D, 0x763E, 0xF1AB, 0x763F, 0xF1A8, 0x7640, 0xF1A5, 0x7641, 0xAF9E, 0x7642, 0xAF9F, 0x7643, 0xF1AA, 0x7644, 0xAFA0, 0x7645, 0xB040, 0x7646, 0xB041, 0x7647, 0xB042, 0x7648, 0xB043, 0x7649, 0xB044, 0x764A, 0xB045, 0x764B, 0xB046, 0x764C, 0xB0A9, 0x764D, 0xF1AD, 0x764E, 0xB047, 0x764F, 0xB048, 0x7650, 0xB049, 0x7651, 0xB04A, 0x7652, 0xB04B, 0x7653, 0xB04C, 0x7654, 0xF1AF, 0x7655, 0xB04D, 0x7656, 0xF1B1, 0x7657, 0xB04E, 0x7658, 0xB04F, 0x7659, 0xB050, 0x765A, 0xB051, 0x765B, 0xB052, 0x765C, 0xF1B0, 0x765D, 0xB053, 0x765E, 0xF1AE, 0x765F, 0xB054, 0x7660, 0xB055, 0x7661, 0xB056, 0x7662, 0xB057, 0x7663, 0xD1A2, 0x7664, 0xB058, 0x7665, 0xB059, 0x7666, 0xB05A, 0x7667, 0xB05B, 0x7668, 0xB05C, 0x7669, 0xB05D, 0x766A, 0xB05E, 0x766B, 0xF1B2, 0x766C, 0xB05F, 0x766D, 0xB060, 0x766E, 0xB061, 0x766F, 0xF1B3, 0x7670, 0xB062, 0x7671, 0xB063, 0x7672, 0xB064, 0x7673, 0xB065, 0x7674, 0xB066, 0x7675, 0xB067, 0x7676, 0xB068, 0x7677, 0xB069, 0x7678, 0xB9EF, 0x7679, 0xB06A, 0x767A, 0xB06B, 0x767B, 0xB5C7, 0x767C, 0xB06C, 0x767D, 0xB0D7, 0x767E, 0xB0D9, 0x767F, 0xB06D, 0x7680, 0xB06E, 0x7681, 0xB06F, 0x7682, 0xD4ED, 0x7683, 0xB070, 0x7684, 0xB5C4, 0x7685, 0xB071, 0x7686, 0xBDD4, 0x7687, 0xBBCA, 0x7688, 0xF0A7, 0x7689, 0xB072, 0x768A, 0xB073, 0x768B, 0xB8DE, 0x768C, 0xB074, 0x768D, 0xB075, 0x768E, 0xF0A8, 0x768F, 0xB076, 0x7690, 0xB077, 0x7691, 0xB0A8, 0x7692, 0xB078, 0x7693, 0xF0A9, 0x7694, 0xB079, 0x7695, 0xB07A, 0x7696, 0xCDEE, 0x7697, 0xB07B, 0x7698, 0xB07C, 0x7699, 0xF0AA, 0x769A, 0xB07D, 0x769B, 0xB07E, 0x769C, 0xB080, 0x769D, 0xB081, 0x769E, 0xB082, 0x769F, 0xB083, 0x76A0, 0xB084, 0x76A1, 0xB085, 0x76A2, 0xB086, 0x76A3, 0xB087, 0x76A4, 0xF0AB, 0x76A5, 0xB088, 0x76A6, 0xB089, 0x76A7, 0xB08A, 0x76A8, 0xB08B, 0x76A9, 0xB08C, 0x76AA, 0xB08D, 0x76AB, 0xB08E, 0x76AC, 0xB08F, 0x76AD, 0xB090, 0x76AE, 0xC6A4, 0x76AF, 0xB091, 0x76B0, 0xB092, 0x76B1, 0xD6E5, 0x76B2, 0xF1E4, 0x76B3, 0xB093, 0x76B4, 0xF1E5, 0x76B5, 0xB094, 0x76B6, 0xB095, 0x76B7, 0xB096, 0x76B8, 0xB097, 0x76B9, 0xB098, 0x76BA, 0xB099, 0x76BB, 0xB09A, 0x76BC, 0xB09B, 0x76BD, 0xB09C, 0x76BE, 0xB09D, 0x76BF, 0xC3F3, 0x76C0, 0xB09E, 0x76C1, 0xB09F, 0x76C2, 0xD3DB, 0x76C3, 0xB0A0, 0x76C4, 0xB140, 0x76C5, 0xD6D1, 0x76C6, 0xC5E8, 0x76C7, 0xB141, 0x76C8, 0xD3AF, 0x76C9, 0xB142, 0x76CA, 0xD2E6, 0x76CB, 0xB143, 0x76CC, 0xB144, 0x76CD, 0xEEC1, 0x76CE, 0xB0BB, 0x76CF, 0xD5B5, 0x76D0, 0xD1CE, 0x76D1, 0xBCE0, 0x76D2, 0xBAD0, 0x76D3, 0xB145, 0x76D4, 0xBFF8, 0x76D5, 0xB146, 0x76D6, 0xB8C7, 0x76D7, 0xB5C1, 0x76D8, 0xC5CC, 0x76D9, 0xB147, 0x76DA, 0xB148, 0x76DB, 0xCAA2, 0x76DC, 0xB149, 0x76DD, 0xB14A, 0x76DE, 0xB14B, 0x76DF, 0xC3CB, 0x76E0, 0xB14C, 0x76E1, 0xB14D, 0x76E2, 0xB14E, 0x76E3, 0xB14F, 0x76E4, 0xB150, 0x76E5, 0xEEC2, 0x76E6, 0xB151, 0x76E7, 0xB152, 0x76E8, 0xB153, 0x76E9, 0xB154, 0x76EA, 0xB155, 0x76EB, 0xB156, 0x76EC, 0xB157, 0x76ED, 0xB158, 0x76EE, 0xC4BF, 0x76EF, 0xB6A2, 0x76F0, 0xB159, 0x76F1, 0xEDEC, 0x76F2, 0xC3A4, 0x76F3, 0xB15A, 0x76F4, 0xD6B1, 0x76F5, 0xB15B, 0x76F6, 0xB15C, 0x76F7, 0xB15D, 0x76F8, 0xCFE0, 0x76F9, 0xEDEF, 0x76FA, 0xB15E, 0x76FB, 0xB15F, 0x76FC, 0xC5CE, 0x76FD, 0xB160, 0x76FE, 0xB6DC, 0x76FF, 0xB161, 0x7700, 0xB162, 0x7701, 0xCAA1, 0x7702, 0xB163, 0x7703, 0xB164, 0x7704, 0xEDED, 0x7705, 0xB165, 0x7706, 0xB166, 0x7707, 0xEDF0, 0x7708, 0xEDF1, 0x7709, 0xC3BC, 0x770A, 0xB167, 0x770B, 0xBFB4, 0x770C, 0xB168, 0x770D, 0xEDEE, 0x770E, 0xB169, 0x770F, 0xB16A, 0x7710, 0xB16B, 0x7711, 0xB16C, 0x7712, 0xB16D, 0x7713, 0xB16E, 0x7714, 0xB16F, 0x7715, 0xB170, 0x7716, 0xB171, 0x7717, 0xB172, 0x7718, 0xB173, 0x7719, 0xEDF4, 0x771A, 0xEDF2, 0x771B, 0xB174, 0x771C, 0xB175, 0x771D, 0xB176, 0x771E, 0xB177, 0x771F, 0xD5E6, 0x7720, 0xC3DF, 0x7721, 0xB178, 0x7722, 0xEDF3, 0x7723, 0xB179, 0x7724, 0xB17A, 0x7725, 0xB17B, 0x7726, 0xEDF6, 0x7727, 0xB17C, 0x7728, 0xD5A3, 0x7729, 0xD1A3, 0x772A, 0xB17D, 0x772B, 0xB17E, 0x772C, 0xB180, 0x772D, 0xEDF5, 0x772E, 0xB181, 0x772F, 0xC3D0, 0x7730, 0xB182, 0x7731, 0xB183, 0x7732, 0xB184, 0x7733, 0xB185, 0x7734, 0xB186, 0x7735, 0xEDF7, 0x7736, 0xBFF4, 0x7737, 0xBEEC, 0x7738, 0xEDF8, 0x7739, 0xB187, 0x773A, 0xCCF7, 0x773B, 0xB188, 0x773C, 0xD1DB, 0x773D, 0xB189, 0x773E, 0xB18A, 0x773F, 0xB18B, 0x7740, 0xD7C5, 0x7741, 0xD5F6, 0x7742, 0xB18C, 0x7743, 0xEDFC, 0x7744, 0xB18D, 0x7745, 0xB18E, 0x7746, 0xB18F, 0x7747, 0xEDFB, 0x7748, 0xB190, 0x7749, 0xB191, 0x774A, 0xB192, 0x774B, 0xB193, 0x774C, 0xB194, 0x774D, 0xB195, 0x774E, 0xB196, 0x774F, 0xB197, 0x7750, 0xEDF9, 0x7751, 0xEDFA, 0x7752, 0xB198, 0x7753, 0xB199, 0x7754, 0xB19A, 0x7755, 0xB19B, 0x7756, 0xB19C, 0x7757, 0xB19D, 0x7758, 0xB19E, 0x7759, 0xB19F, 0x775A, 0xEDFD, 0x775B, 0xBEA6, 0x775C, 0xB1A0, 0x775D, 0xB240, 0x775E, 0xB241, 0x775F, 0xB242, 0x7760, 0xB243, 0x7761, 0xCBAF, 0x7762, 0xEEA1, 0x7763, 0xB6BD, 0x7764, 0xB244, 0x7765, 0xEEA2, 0x7766, 0xC4C0, 0x7767, 0xB245, 0x7768, 0xEDFE, 0x7769, 0xB246, 0x776A, 0xB247, 0x776B, 0xBDDE, 0x776C, 0xB2C7, 0x776D, 0xB248, 0x776E, 0xB249, 0x776F, 0xB24A, 0x7770, 0xB24B, 0x7771, 0xB24C, 0x7772, 0xB24D, 0x7773, 0xB24E, 0x7774, 0xB24F, 0x7775, 0xB250, 0x7776, 0xB251, 0x7777, 0xB252, 0x7778, 0xB253, 0x7779, 0xB6C3, 0x777A, 0xB254, 0x777B, 0xB255, 0x777C, 0xB256, 0x777D, 0xEEA5, 0x777E, 0xD8BA, 0x777F, 0xEEA3, 0x7780, 0xEEA6, 0x7781, 0xB257, 0x7782, 0xB258, 0x7783, 0xB259, 0x7784, 0xC3E9, 0x7785, 0xB3F2, 0x7786, 0xB25A, 0x7787, 0xB25B, 0x7788, 0xB25C, 0x7789, 0xB25D, 0x778A, 0xB25E, 0x778B, 0xB25F, 0x778C, 0xEEA7, 0x778D, 0xEEA4, 0x778E, 0xCFB9, 0x778F, 0xB260, 0x7790, 0xB261, 0x7791, 0xEEA8, 0x7792, 0xC2F7, 0x7793, 0xB262, 0x7794, 0xB263, 0x7795, 0xB264, 0x7796, 0xB265, 0x7797, 0xB266, 0x7798, 0xB267, 0x7799, 0xB268, 0x779A, 0xB269, 0x779B, 0xB26A, 0x779C, 0xB26B, 0x779D, 0xB26C, 0x779E, 0xB26D, 0x779F, 0xEEA9, 0x77A0, 0xEEAA, 0x77A1, 0xB26E, 0x77A2, 0xDEAB, 0x77A3, 0xB26F, 0x77A4, 0xB270, 0x77A5, 0xC6B3, 0x77A6, 0xB271, 0x77A7, 0xC7C6, 0x77A8, 0xB272, 0x77A9, 0xD6F5, 0x77AA, 0xB5C9, 0x77AB, 0xB273, 0x77AC, 0xCBB2, 0x77AD, 0xB274, 0x77AE, 0xB275, 0x77AF, 0xB276, 0x77B0, 0xEEAB, 0x77B1, 0xB277, 0x77B2, 0xB278, 0x77B3, 0xCDAB, 0x77B4, 0xB279, 0x77B5, 0xEEAC, 0x77B6, 0xB27A, 0x77B7, 0xB27B, 0x77B8, 0xB27C, 0x77B9, 0xB27D, 0x77BA, 0xB27E, 0x77BB, 0xD5B0, 0x77BC, 0xB280, 0x77BD, 0xEEAD, 0x77BE, 0xB281, 0x77BF, 0xF6C4, 0x77C0, 0xB282, 0x77C1, 0xB283, 0x77C2, 0xB284, 0x77C3, 0xB285, 0x77C4, 0xB286, 0x77C5, 0xB287, 0x77C6, 0xB288, 0x77C7, 0xB289, 0x77C8, 0xB28A, 0x77C9, 0xB28B, 0x77CA, 0xB28C, 0x77CB, 0xB28D, 0x77CC, 0xB28E, 0x77CD, 0xDBC7, 0x77CE, 0xB28F, 0x77CF, 0xB290, 0x77D0, 0xB291, 0x77D1, 0xB292, 0x77D2, 0xB293, 0x77D3, 0xB294, 0x77D4, 0xB295, 0x77D5, 0xB296, 0x77D6, 0xB297, 0x77D7, 0xB4A3, 0x77D8, 0xB298, 0x77D9, 0xB299, 0x77DA, 0xB29A, 0x77DB, 0xC3AC, 0x77DC, 0xF1E6, 0x77DD, 0xB29B, 0x77DE, 0xB29C, 0x77DF, 0xB29D, 0x77E0, 0xB29E, 0x77E1, 0xB29F, 0x77E2, 0xCAB8, 0x77E3, 0xD2D3, 0x77E4, 0xB2A0, 0x77E5, 0xD6AA, 0x77E6, 0xB340, 0x77E7, 0xEFF2, 0x77E8, 0xB341, 0x77E9, 0xBED8, 0x77EA, 0xB342, 0x77EB, 0xBDC3, 0x77EC, 0xEFF3, 0x77ED, 0xB6CC, 0x77EE, 0xB0AB, 0x77EF, 0xB343, 0x77F0, 0xB344, 0x77F1, 0xB345, 0x77F2, 0xB346, 0x77F3, 0xCAAF, 0x77F4, 0xB347, 0x77F5, 0xB348, 0x77F6, 0xEDB6, 0x77F7, 0xB349, 0x77F8, 0xEDB7, 0x77F9, 0xB34A, 0x77FA, 0xB34B, 0x77FB, 0xB34C, 0x77FC, 0xB34D, 0x77FD, 0xCEF9, 0x77FE, 0xB7AF, 0x77FF, 0xBFF3, 0x7800, 0xEDB8, 0x7801, 0xC2EB, 0x7802, 0xC9B0, 0x7803, 0xB34E, 0x7804, 0xB34F, 0x7805, 0xB350, 0x7806, 0xB351, 0x7807, 0xB352, 0x7808, 0xB353, 0x7809, 0xEDB9, 0x780A, 0xB354, 0x780B, 0xB355, 0x780C, 0xC6F6, 0x780D, 0xBFB3, 0x780E, 0xB356, 0x780F, 0xB357, 0x7810, 0xB358, 0x7811, 0xEDBC, 0x7812, 0xC5F8, 0x7813, 0xB359, 0x7814, 0xD1D0, 0x7815, 0xB35A, 0x7816, 0xD7A9, 0x7817, 0xEDBA, 0x7818, 0xEDBB, 0x7819, 0xB35B, 0x781A, 0xD1E2, 0x781B, 0xB35C, 0x781C, 0xEDBF, 0x781D, 0xEDC0, 0x781E, 0xB35D, 0x781F, 0xEDC4, 0x7820, 0xB35E, 0x7821, 0xB35F, 0x7822, 0xB360, 0x7823, 0xEDC8, 0x7824, 0xB361, 0x7825, 0xEDC6, 0x7826, 0xEDCE, 0x7827, 0xD5E8, 0x7828, 0xB362, 0x7829, 0xEDC9, 0x782A, 0xB363, 0x782B, 0xB364, 0x782C, 0xEDC7, 0x782D, 0xEDBE, 0x782E, 0xB365, 0x782F, 0xB366, 0x7830, 0xC5E9, 0x7831, 0xB367, 0x7832, 0xB368, 0x7833, 0xB369, 0x7834, 0xC6C6, 0x7835, 0xB36A, 0x7836, 0xB36B, 0x7837, 0xC9E9, 0x7838, 0xD4D2, 0x7839, 0xEDC1, 0x783A, 0xEDC2, 0x783B, 0xEDC3, 0x783C, 0xEDC5, 0x783D, 0xB36C, 0x783E, 0xC0F9, 0x783F, 0xB36D, 0x7840, 0xB4A1, 0x7841, 0xB36E, 0x7842, 0xB36F, 0x7843, 0xB370, 0x7844, 0xB371, 0x7845, 0xB9E8, 0x7846, 0xB372, 0x7847, 0xEDD0, 0x7848, 0xB373, 0x7849, 0xB374, 0x784A, 0xB375, 0x784B, 0xB376, 0x784C, 0xEDD1, 0x784D, 0xB377, 0x784E, 0xEDCA, 0x784F, 0xB378, 0x7850, 0xEDCF, 0x7851, 0xB379, 0x7852, 0xCEF8, 0x7853, 0xB37A, 0x7854, 0xB37B, 0x7855, 0xCBB6, 0x7856, 0xEDCC, 0x7857, 0xEDCD, 0x7858, 0xB37C, 0x7859, 0xB37D, 0x785A, 0xB37E, 0x785B, 0xB380, 0x785C, 0xB381, 0x785D, 0xCFF5, 0x785E, 0xB382, 0x785F, 0xB383, 0x7860, 0xB384, 0x7861, 0xB385, 0x7862, 0xB386, 0x7863, 0xB387, 0x7864, 0xB388, 0x7865, 0xB389, 0x7866, 0xB38A, 0x7867, 0xB38B, 0x7868, 0xB38C, 0x7869, 0xB38D, 0x786A, 0xEDD2, 0x786B, 0xC1F2, 0x786C, 0xD3B2, 0x786D, 0xEDCB, 0x786E, 0xC8B7, 0x786F, 0xB38E, 0x7870, 0xB38F, 0x7871, 0xB390, 0x7872, 0xB391, 0x7873, 0xB392, 0x7874, 0xB393, 0x7875, 0xB394, 0x7876, 0xB395, 0x7877, 0xBCEF, 0x7878, 0xB396, 0x7879, 0xB397, 0x787A, 0xB398, 0x787B, 0xB399, 0x787C, 0xC5F0, 0x787D, 0xB39A, 0x787E, 0xB39B, 0x787F, 0xB39C, 0x7880, 0xB39D, 0x7881, 0xB39E, 0x7882, 0xB39F, 0x7883, 0xB3A0, 0x7884, 0xB440, 0x7885, 0xB441, 0x7886, 0xB442, 0x7887, 0xEDD6, 0x7888, 0xB443, 0x7889, 0xB5EF, 0x788A, 0xB444, 0x788B, 0xB445, 0x788C, 0xC2B5, 0x788D, 0xB0AD, 0x788E, 0xCBE9, 0x788F, 0xB446, 0x7890, 0xB447, 0x7891, 0xB1AE, 0x7892, 0xB448, 0x7893, 0xEDD4, 0x7894, 0xB449, 0x7895, 0xB44A, 0x7896, 0xB44B, 0x7897, 0xCDEB, 0x7898, 0xB5E2, 0x7899, 0xB44C, 0x789A, 0xEDD5, 0x789B, 0xEDD3, 0x789C, 0xEDD7, 0x789D, 0xB44D, 0x789E, 0xB44E, 0x789F, 0xB5FA, 0x78A0, 0xB44F, 0x78A1, 0xEDD8, 0x78A2, 0xB450, 0x78A3, 0xEDD9, 0x78A4, 0xB451, 0x78A5, 0xEDDC, 0x78A6, 0xB452, 0x78A7, 0xB1CC, 0x78A8, 0xB453, 0x78A9, 0xB454, 0x78AA, 0xB455, 0x78AB, 0xB456, 0x78AC, 0xB457, 0x78AD, 0xB458, 0x78AE, 0xB459, 0x78AF, 0xB45A, 0x78B0, 0xC5F6, 0x78B1, 0xBCEE, 0x78B2, 0xEDDA, 0x78B3, 0xCCBC, 0x78B4, 0xB2EA, 0x78B5, 0xB45B, 0x78B6, 0xB45C, 0x78B7, 0xB45D, 0x78B8, 0xB45E, 0x78B9, 0xEDDB, 0x78BA, 0xB45F, 0x78BB, 0xB460, 0x78BC, 0xB461, 0x78BD, 0xB462, 0x78BE, 0xC4EB, 0x78BF, 0xB463, 0x78C0, 0xB464, 0x78C1, 0xB4C5, 0x78C2, 0xB465, 0x78C3, 0xB466, 0x78C4, 0xB467, 0x78C5, 0xB0F5, 0x78C6, 0xB468, 0x78C7, 0xB469, 0x78C8, 0xB46A, 0x78C9, 0xEDDF, 0x78CA, 0xC0DA, 0x78CB, 0xB4E8, 0x78CC, 0xB46B, 0x78CD, 0xB46C, 0x78CE, 0xB46D, 0x78CF, 0xB46E, 0x78D0, 0xC5CD, 0x78D1, 0xB46F, 0x78D2, 0xB470, 0x78D3, 0xB471, 0x78D4, 0xEDDD, 0x78D5, 0xBFC4, 0x78D6, 0xB472, 0x78D7, 0xB473, 0x78D8, 0xB474, 0x78D9, 0xEDDE, 0x78DA, 0xB475, 0x78DB, 0xB476, 0x78DC, 0xB477, 0x78DD, 0xB478, 0x78DE, 0xB479, 0x78DF, 0xB47A, 0x78E0, 0xB47B, 0x78E1, 0xB47C, 0x78E2, 0xB47D, 0x78E3, 0xB47E, 0x78E4, 0xB480, 0x78E5, 0xB481, 0x78E6, 0xB482, 0x78E7, 0xB483, 0x78E8, 0xC4A5, 0x78E9, 0xB484, 0x78EA, 0xB485, 0x78EB, 0xB486, 0x78EC, 0xEDE0, 0x78ED, 0xB487, 0x78EE, 0xB488, 0x78EF, 0xB489, 0x78F0, 0xB48A, 0x78F1, 0xB48B, 0x78F2, 0xEDE1, 0x78F3, 0xB48C, 0x78F4, 0xEDE3, 0x78F5, 0xB48D, 0x78F6, 0xB48E, 0x78F7, 0xC1D7, 0x78F8, 0xB48F, 0x78F9, 0xB490, 0x78FA, 0xBBC7, 0x78FB, 0xB491, 0x78FC, 0xB492, 0x78FD, 0xB493, 0x78FE, 0xB494, 0x78FF, 0xB495, 0x7900, 0xB496, 0x7901, 0xBDB8, 0x7902, 0xB497, 0x7903, 0xB498, 0x7904, 0xB499, 0x7905, 0xEDE2, 0x7906, 0xB49A, 0x7907, 0xB49B, 0x7908, 0xB49C, 0x7909, 0xB49D, 0x790A, 0xB49E, 0x790B, 0xB49F, 0x790C, 0xB4A0, 0x790D, 0xB540, 0x790E, 0xB541, 0x790F, 0xB542, 0x7910, 0xB543, 0x7911, 0xB544, 0x7912, 0xB545, 0x7913, 0xEDE4, 0x7914, 0xB546, 0x7915, 0xB547, 0x7916, 0xB548, 0x7917, 0xB549, 0x7918, 0xB54A, 0x7919, 0xB54B, 0x791A, 0xB54C, 0x791B, 0xB54D, 0x791C, 0xB54E, 0x791D, 0xB54F, 0x791E, 0xEDE6, 0x791F, 0xB550, 0x7920, 0xB551, 0x7921, 0xB552, 0x7922, 0xB553, 0x7923, 0xB554, 0x7924, 0xEDE5, 0x7925, 0xB555, 0x7926, 0xB556, 0x7927, 0xB557, 0x7928, 0xB558, 0x7929, 0xB559, 0x792A, 0xB55A, 0x792B, 0xB55B, 0x792C, 0xB55C, 0x792D, 0xB55D, 0x792E, 0xB55E, 0x792F, 0xB55F, 0x7930, 0xB560, 0x7931, 0xB561, 0x7932, 0xB562, 0x7933, 0xB563, 0x7934, 0xEDE7, 0x7935, 0xB564, 0x7936, 0xB565, 0x7937, 0xB566, 0x7938, 0xB567, 0x7939, 0xB568, 0x793A, 0xCABE, 0x793B, 0xECEA, 0x793C, 0xC0F1, 0x793D, 0xB569, 0x793E, 0xC9E7, 0x793F, 0xB56A, 0x7940, 0xECEB, 0x7941, 0xC6EE, 0x7942, 0xB56B, 0x7943, 0xB56C, 0x7944, 0xB56D, 0x7945, 0xB56E, 0x7946, 0xECEC, 0x7947, 0xB56F, 0x7948, 0xC6ED, 0x7949, 0xECED, 0x794A, 0xB570, 0x794B, 0xB571, 0x794C, 0xB572, 0x794D, 0xB573, 0x794E, 0xB574, 0x794F, 0xB575, 0x7950, 0xB576, 0x7951, 0xB577, 0x7952, 0xB578, 0x7953, 0xECF0, 0x7954, 0xB579, 0x7955, 0xB57A, 0x7956, 0xD7E6, 0x7957, 0xECF3, 0x7958, 0xB57B, 0x7959, 0xB57C, 0x795A, 0xECF1, 0x795B, 0xECEE, 0x795C, 0xECEF, 0x795D, 0xD7A3, 0x795E, 0xC9F1, 0x795F, 0xCBEE, 0x7960, 0xECF4, 0x7961, 0xB57D, 0x7962, 0xECF2, 0x7963, 0xB57E, 0x7964, 0xB580, 0x7965, 0xCFE9, 0x7966, 0xB581, 0x7967, 0xECF6, 0x7968, 0xC6B1, 0x7969, 0xB582, 0x796A, 0xB583, 0x796B, 0xB584, 0x796C, 0xB585, 0x796D, 0xBCC0, 0x796E, 0xB586, 0x796F, 0xECF5, 0x7970, 0xB587, 0x7971, 0xB588, 0x7972, 0xB589, 0x7973, 0xB58A, 0x7974, 0xB58B, 0x7975, 0xB58C, 0x7976, 0xB58D, 0x7977, 0xB5BB, 0x7978, 0xBBF6, 0x7979, 0xB58E, 0x797A, 0xECF7, 0x797B, 0xB58F, 0x797C, 0xB590, 0x797D, 0xB591, 0x797E, 0xB592, 0x797F, 0xB593, 0x7980, 0xD9F7, 0x7981, 0xBDFB, 0x7982, 0xB594, 0x7983, 0xB595, 0x7984, 0xC2BB, 0x7985, 0xECF8, 0x7986, 0xB596, 0x7987, 0xB597, 0x7988, 0xB598, 0x7989, 0xB599, 0x798A, 0xECF9, 0x798B, 0xB59A, 0x798C, 0xB59B, 0x798D, 0xB59C, 0x798E, 0xB59D, 0x798F, 0xB8A3, 0x7990, 0xB59E, 0x7991, 0xB59F, 0x7992, 0xB5A0, 0x7993, 0xB640, 0x7994, 0xB641, 0x7995, 0xB642, 0x7996, 0xB643, 0x7997, 0xB644, 0x7998, 0xB645, 0x7999, 0xB646, 0x799A, 0xECFA, 0x799B, 0xB647, 0x799C, 0xB648, 0x799D, 0xB649, 0x799E, 0xB64A, 0x799F, 0xB64B, 0x79A0, 0xB64C, 0x79A1, 0xB64D, 0x79A2, 0xB64E, 0x79A3, 0xB64F, 0x79A4, 0xB650, 0x79A5, 0xB651, 0x79A6, 0xB652, 0x79A7, 0xECFB, 0x79A8, 0xB653, 0x79A9, 0xB654, 0x79AA, 0xB655, 0x79AB, 0xB656, 0x79AC, 0xB657, 0x79AD, 0xB658, 0x79AE, 0xB659, 0x79AF, 0xB65A, 0x79B0, 0xB65B, 0x79B1, 0xB65C, 0x79B2, 0xB65D, 0x79B3, 0xECFC, 0x79B4, 0xB65E, 0x79B5, 0xB65F, 0x79B6, 0xB660, 0x79B7, 0xB661, 0x79B8, 0xB662, 0x79B9, 0xD3ED, 0x79BA, 0xD8AE, 0x79BB, 0xC0EB, 0x79BC, 0xB663, 0x79BD, 0xC7DD, 0x79BE, 0xBACC, 0x79BF, 0xB664, 0x79C0, 0xD0E3, 0x79C1, 0xCBBD, 0x79C2, 0xB665, 0x79C3, 0xCDBA, 0x79C4, 0xB666, 0x79C5, 0xB667, 0x79C6, 0xB8D1, 0x79C7, 0xB668, 0x79C8, 0xB669, 0x79C9, 0xB1FC, 0x79CA, 0xB66A, 0x79CB, 0xC7EF, 0x79CC, 0xB66B, 0x79CD, 0xD6D6, 0x79CE, 0xB66C, 0x79CF, 0xB66D, 0x79D0, 0xB66E, 0x79D1, 0xBFC6, 0x79D2, 0xC3EB, 0x79D3, 0xB66F, 0x79D4, 0xB670, 0x79D5, 0xEFF5, 0x79D6, 0xB671, 0x79D7, 0xB672, 0x79D8, 0xC3D8, 0x79D9, 0xB673, 0x79DA, 0xB674, 0x79DB, 0xB675, 0x79DC, 0xB676, 0x79DD, 0xB677, 0x79DE, 0xB678, 0x79DF, 0xD7E2, 0x79E0, 0xB679, 0x79E1, 0xB67A, 0x79E2, 0xB67B, 0x79E3, 0xEFF7, 0x79E4, 0xB3D3, 0x79E5, 0xB67C, 0x79E6, 0xC7D8, 0x79E7, 0xD1ED, 0x79E8, 0xB67D, 0x79E9, 0xD6C8, 0x79EA, 0xB67E, 0x79EB, 0xEFF8, 0x79EC, 0xB680, 0x79ED, 0xEFF6, 0x79EE, 0xB681, 0x79EF, 0xBBFD, 0x79F0, 0xB3C6, 0x79F1, 0xB682, 0x79F2, 0xB683, 0x79F3, 0xB684, 0x79F4, 0xB685, 0x79F5, 0xB686, 0x79F6, 0xB687, 0x79F7, 0xB688, 0x79F8, 0xBDD5, 0x79F9, 0xB689, 0x79FA, 0xB68A, 0x79FB, 0xD2C6, 0x79FC, 0xB68B, 0x79FD, 0xBBE0, 0x79FE, 0xB68C, 0x79FF, 0xB68D, 0x7A00, 0xCFA1, 0x7A01, 0xB68E, 0x7A02, 0xEFFC, 0x7A03, 0xEFFB, 0x7A04, 0xB68F, 0x7A05, 0xB690, 0x7A06, 0xEFF9, 0x7A07, 0xB691, 0x7A08, 0xB692, 0x7A09, 0xB693, 0x7A0A, 0xB694, 0x7A0B, 0xB3CC, 0x7A0C, 0xB695, 0x7A0D, 0xC9D4, 0x7A0E, 0xCBB0, 0x7A0F, 0xB696, 0x7A10, 0xB697, 0x7A11, 0xB698, 0x7A12, 0xB699, 0x7A13, 0xB69A, 0x7A14, 0xEFFE, 0x7A15, 0xB69B, 0x7A16, 0xB69C, 0x7A17, 0xB0DE, 0x7A18, 0xB69D, 0x7A19, 0xB69E, 0x7A1A, 0xD6C9, 0x7A1B, 0xB69F, 0x7A1C, 0xB6A0, 0x7A1D, 0xB740, 0x7A1E, 0xEFFD, 0x7A1F, 0xB741, 0x7A20, 0xB3ED, 0x7A21, 0xB742, 0x7A22, 0xB743, 0x7A23, 0xF6D5, 0x7A24, 0xB744, 0x7A25, 0xB745, 0x7A26, 0xB746, 0x7A27, 0xB747, 0x7A28, 0xB748, 0x7A29, 0xB749, 0x7A2A, 0xB74A, 0x7A2B, 0xB74B, 0x7A2C, 0xB74C, 0x7A2D, 0xB74D, 0x7A2E, 0xB74E, 0x7A2F, 0xB74F, 0x7A30, 0xB750, 0x7A31, 0xB751, 0x7A32, 0xB752, 0x7A33, 0xCEC8, 0x7A34, 0xB753, 0x7A35, 0xB754, 0x7A36, 0xB755, 0x7A37, 0xF0A2, 0x7A38, 0xB756, 0x7A39, 0xF0A1, 0x7A3A, 0xB757, 0x7A3B, 0xB5BE, 0x7A3C, 0xBCDA, 0x7A3D, 0xBBFC, 0x7A3E, 0xB758, 0x7A3F, 0xB8E5, 0x7A40, 0xB759, 0x7A41, 0xB75A, 0x7A42, 0xB75B, 0x7A43, 0xB75C, 0x7A44, 0xB75D, 0x7A45, 0xB75E, 0x7A46, 0xC4C2, 0x7A47, 0xB75F, 0x7A48, 0xB760, 0x7A49, 0xB761, 0x7A4A, 0xB762, 0x7A4B, 0xB763, 0x7A4C, 0xB764, 0x7A4D, 0xB765, 0x7A4E, 0xB766, 0x7A4F, 0xB767, 0x7A50, 0xB768, 0x7A51, 0xF0A3, 0x7A52, 0xB769, 0x7A53, 0xB76A, 0x7A54, 0xB76B, 0x7A55, 0xB76C, 0x7A56, 0xB76D, 0x7A57, 0xCBEB, 0x7A58, 0xB76E, 0x7A59, 0xB76F, 0x7A5A, 0xB770, 0x7A5B, 0xB771, 0x7A5C, 0xB772, 0x7A5D, 0xB773, 0x7A5E, 0xB774, 0x7A5F, 0xB775, 0x7A60, 0xB776, 0x7A61, 0xB777, 0x7A62, 0xB778, 0x7A63, 0xB779, 0x7A64, 0xB77A, 0x7A65, 0xB77B, 0x7A66, 0xB77C, 0x7A67, 0xB77D, 0x7A68, 0xB77E, 0x7A69, 0xB780, 0x7A6A, 0xB781, 0x7A6B, 0xB782, 0x7A6C, 0xB783, 0x7A6D, 0xB784, 0x7A6E, 0xB785, 0x7A6F, 0xB786, 0x7A70, 0xF0A6, 0x7A71, 0xB787, 0x7A72, 0xB788, 0x7A73, 0xB789, 0x7A74, 0xD1A8, 0x7A75, 0xB78A, 0x7A76, 0xBEBF, 0x7A77, 0xC7EE, 0x7A78, 0xF1B6, 0x7A79, 0xF1B7, 0x7A7A, 0xBFD5, 0x7A7B, 0xB78B, 0x7A7C, 0xB78C, 0x7A7D, 0xB78D, 0x7A7E, 0xB78E, 0x7A7F, 0xB4A9, 0x7A80, 0xF1B8, 0x7A81, 0xCDBB, 0x7A82, 0xB78F, 0x7A83, 0xC7D4, 0x7A84, 0xD5AD, 0x7A85, 0xB790, 0x7A86, 0xF1B9, 0x7A87, 0xB791, 0x7A88, 0xF1BA, 0x7A89, 0xB792, 0x7A8A, 0xB793, 0x7A8B, 0xB794, 0x7A8C, 0xB795, 0x7A8D, 0xC7CF, 0x7A8E, 0xB796, 0x7A8F, 0xB797, 0x7A90, 0xB798, 0x7A91, 0xD2A4, 0x7A92, 0xD6CF, 0x7A93, 0xB799, 0x7A94, 0xB79A, 0x7A95, 0xF1BB, 0x7A96, 0xBDD1, 0x7A97, 0xB4B0, 0x7A98, 0xBEBD, 0x7A99, 0xB79B, 0x7A9A, 0xB79C, 0x7A9B, 0xB79D, 0x7A9C, 0xB4DC, 0x7A9D, 0xCED1, 0x7A9E, 0xB79E, 0x7A9F, 0xBFDF, 0x7AA0, 0xF1BD, 0x7AA1, 0xB79F, 0x7AA2, 0xB7A0, 0x7AA3, 0xB840, 0x7AA4, 0xB841, 0x7AA5, 0xBFFA, 0x7AA6, 0xF1BC, 0x7AA7, 0xB842, 0x7AA8, 0xF1BF, 0x7AA9, 0xB843, 0x7AAA, 0xB844, 0x7AAB, 0xB845, 0x7AAC, 0xF1BE, 0x7AAD, 0xF1C0, 0x7AAE, 0xB846, 0x7AAF, 0xB847, 0x7AB0, 0xB848, 0x7AB1, 0xB849, 0x7AB2, 0xB84A, 0x7AB3, 0xF1C1, 0x7AB4, 0xB84B, 0x7AB5, 0xB84C, 0x7AB6, 0xB84D, 0x7AB7, 0xB84E, 0x7AB8, 0xB84F, 0x7AB9, 0xB850, 0x7ABA, 0xB851, 0x7ABB, 0xB852, 0x7ABC, 0xB853, 0x7ABD, 0xB854, 0x7ABE, 0xB855, 0x7ABF, 0xC1FE, 0x7AC0, 0xB856, 0x7AC1, 0xB857, 0x7AC2, 0xB858, 0x7AC3, 0xB859, 0x7AC4, 0xB85A, 0x7AC5, 0xB85B, 0x7AC6, 0xB85C, 0x7AC7, 0xB85D, 0x7AC8, 0xB85E, 0x7AC9, 0xB85F, 0x7ACA, 0xB860, 0x7ACB, 0xC1A2, 0x7ACC, 0xB861, 0x7ACD, 0xB862, 0x7ACE, 0xB863, 0x7ACF, 0xB864, 0x7AD0, 0xB865, 0x7AD1, 0xB866, 0x7AD2, 0xB867, 0x7AD3, 0xB868, 0x7AD4, 0xB869, 0x7AD5, 0xB86A, 0x7AD6, 0xCAFA, 0x7AD7, 0xB86B, 0x7AD8, 0xB86C, 0x7AD9, 0xD5BE, 0x7ADA, 0xB86D, 0x7ADB, 0xB86E, 0x7ADC, 0xB86F, 0x7ADD, 0xB870, 0x7ADE, 0xBEBA, 0x7ADF, 0xBEB9, 0x7AE0, 0xD5C2, 0x7AE1, 0xB871, 0x7AE2, 0xB872, 0x7AE3, 0xBFA2, 0x7AE4, 0xB873, 0x7AE5, 0xCDAF, 0x7AE6, 0xF1B5, 0x7AE7, 0xB874, 0x7AE8, 0xB875, 0x7AE9, 0xB876, 0x7AEA, 0xB877, 0x7AEB, 0xB878, 0x7AEC, 0xB879, 0x7AED, 0xBDDF, 0x7AEE, 0xB87A, 0x7AEF, 0xB6CB, 0x7AF0, 0xB87B, 0x7AF1, 0xB87C, 0x7AF2, 0xB87D, 0x7AF3, 0xB87E, 0x7AF4, 0xB880, 0x7AF5, 0xB881, 0x7AF6, 0xB882, 0x7AF7, 0xB883, 0x7AF8, 0xB884, 0x7AF9, 0xD6F1, 0x7AFA, 0xF3C3, 0x7AFB, 0xB885, 0x7AFC, 0xB886, 0x7AFD, 0xF3C4, 0x7AFE, 0xB887, 0x7AFF, 0xB8CD, 0x7B00, 0xB888, 0x7B01, 0xB889, 0x7B02, 0xB88A, 0x7B03, 0xF3C6, 0x7B04, 0xF3C7, 0x7B05, 0xB88B, 0x7B06, 0xB0CA, 0x7B07, 0xB88C, 0x7B08, 0xF3C5, 0x7B09, 0xB88D, 0x7B0A, 0xF3C9, 0x7B0B, 0xCBF1, 0x7B0C, 0xB88E, 0x7B0D, 0xB88F, 0x7B0E, 0xB890, 0x7B0F, 0xF3CB, 0x7B10, 0xB891, 0x7B11, 0xD0A6, 0x7B12, 0xB892, 0x7B13, 0xB893, 0x7B14, 0xB1CA, 0x7B15, 0xF3C8, 0x7B16, 0xB894, 0x7B17, 0xB895, 0x7B18, 0xB896, 0x7B19, 0xF3CF, 0x7B1A, 0xB897, 0x7B1B, 0xB5D1, 0x7B1C, 0xB898, 0x7B1D, 0xB899, 0x7B1E, 0xF3D7, 0x7B1F, 0xB89A, 0x7B20, 0xF3D2, 0x7B21, 0xB89B, 0x7B22, 0xB89C, 0x7B23, 0xB89D, 0x7B24, 0xF3D4, 0x7B25, 0xF3D3, 0x7B26, 0xB7FB, 0x7B27, 0xB89E, 0x7B28, 0xB1BF, 0x7B29, 0xB89F, 0x7B2A, 0xF3CE, 0x7B2B, 0xF3CA, 0x7B2C, 0xB5DA, 0x7B2D, 0xB8A0, 0x7B2E, 0xF3D0, 0x7B2F, 0xB940, 0x7B30, 0xB941, 0x7B31, 0xF3D1, 0x7B32, 0xB942, 0x7B33, 0xF3D5, 0x7B34, 0xB943, 0x7B35, 0xB944, 0x7B36, 0xB945, 0x7B37, 0xB946, 0x7B38, 0xF3CD, 0x7B39, 0xB947, 0x7B3A, 0xBCE3, 0x7B3B, 0xB948, 0x7B3C, 0xC1FD, 0x7B3D, 0xB949, 0x7B3E, 0xF3D6, 0x7B3F, 0xB94A, 0x7B40, 0xB94B, 0x7B41, 0xB94C, 0x7B42, 0xB94D, 0x7B43, 0xB94E, 0x7B44, 0xB94F, 0x7B45, 0xF3DA, 0x7B46, 0xB950, 0x7B47, 0xF3CC, 0x7B48, 0xB951, 0x7B49, 0xB5C8, 0x7B4A, 0xB952, 0x7B4B, 0xBDEE, 0x7B4C, 0xF3DC, 0x7B4D, 0xB953, 0x7B4E, 0xB954, 0x7B4F, 0xB7A4, 0x7B50, 0xBFF0, 0x7B51, 0xD6FE, 0x7B52, 0xCDB2, 0x7B53, 0xB955, 0x7B54, 0xB4F0, 0x7B55, 0xB956, 0x7B56, 0xB2DF, 0x7B57, 0xB957, 0x7B58, 0xF3D8, 0x7B59, 0xB958, 0x7B5A, 0xF3D9, 0x7B5B, 0xC9B8, 0x7B5C, 0xB959, 0x7B5D, 0xF3DD, 0x7B5E, 0xB95A, 0x7B5F, 0xB95B, 0x7B60, 0xF3DE, 0x7B61, 0xB95C, 0x7B62, 0xF3E1, 0x7B63, 0xB95D, 0x7B64, 0xB95E, 0x7B65, 0xB95F, 0x7B66, 0xB960, 0x7B67, 0xB961, 0x7B68, 0xB962, 0x7B69, 0xB963, 0x7B6A, 0xB964, 0x7B6B, 0xB965, 0x7B6C, 0xB966, 0x7B6D, 0xB967, 0x7B6E, 0xF3DF, 0x7B6F, 0xB968, 0x7B70, 0xB969, 0x7B71, 0xF3E3, 0x7B72, 0xF3E2, 0x7B73, 0xB96A, 0x7B74, 0xB96B, 0x7B75, 0xF3DB, 0x7B76, 0xB96C, 0x7B77, 0xBFEA, 0x7B78, 0xB96D, 0x7B79, 0xB3EF, 0x7B7A, 0xB96E, 0x7B7B, 0xF3E0, 0x7B7C, 0xB96F, 0x7B7D, 0xB970, 0x7B7E, 0xC7A9, 0x7B7F, 0xB971, 0x7B80, 0xBCF2, 0x7B81, 0xB972, 0x7B82, 0xB973, 0x7B83, 0xB974, 0x7B84, 0xB975, 0x7B85, 0xF3EB, 0x7B86, 0xB976, 0x7B87, 0xB977, 0x7B88, 0xB978, 0x7B89, 0xB979, 0x7B8A, 0xB97A, 0x7B8B, 0xB97B, 0x7B8C, 0xB97C, 0x7B8D, 0xB9BF, 0x7B8E, 0xB97D, 0x7B8F, 0xB97E, 0x7B90, 0xF3E4, 0x7B91, 0xB980, 0x7B92, 0xB981, 0x7B93, 0xB982, 0x7B94, 0xB2AD, 0x7B95, 0xBBFE, 0x7B96, 0xB983, 0x7B97, 0xCBE3, 0x7B98, 0xB984, 0x7B99, 0xB985, 0x7B9A, 0xB986, 0x7B9B, 0xB987, 0x7B9C, 0xF3ED, 0x7B9D, 0xF3E9, 0x7B9E, 0xB988, 0x7B9F, 0xB989, 0x7BA0, 0xB98A, 0x7BA1, 0xB9DC, 0x7BA2, 0xF3EE, 0x7BA3, 0xB98B, 0x7BA4, 0xB98C, 0x7BA5, 0xB98D, 0x7BA6, 0xF3E5, 0x7BA7, 0xF3E6, 0x7BA8, 0xF3EA, 0x7BA9, 0xC2E1, 0x7BAA, 0xF3EC, 0x7BAB, 0xF3EF, 0x7BAC, 0xF3E8, 0x7BAD, 0xBCFD, 0x7BAE, 0xB98E, 0x7BAF, 0xB98F, 0x7BB0, 0xB990, 0x7BB1, 0xCFE4, 0x7BB2, 0xB991, 0x7BB3, 0xB992, 0x7BB4, 0xF3F0, 0x7BB5, 0xB993, 0x7BB6, 0xB994, 0x7BB7, 0xB995, 0x7BB8, 0xF3E7, 0x7BB9, 0xB996, 0x7BBA, 0xB997, 0x7BBB, 0xB998, 0x7BBC, 0xB999, 0x7BBD, 0xB99A, 0x7BBE, 0xB99B, 0x7BBF, 0xB99C, 0x7BC0, 0xB99D, 0x7BC1, 0xF3F2, 0x7BC2, 0xB99E, 0x7BC3, 0xB99F, 0x7BC4, 0xB9A0, 0x7BC5, 0xBA40, 0x7BC6, 0xD7AD, 0x7BC7, 0xC6AA, 0x7BC8, 0xBA41, 0x7BC9, 0xBA42, 0x7BCA, 0xBA43, 0x7BCB, 0xBA44, 0x7BCC, 0xF3F3, 0x7BCD, 0xBA45, 0x7BCE, 0xBA46, 0x7BCF, 0xBA47, 0x7BD0, 0xBA48, 0x7BD1, 0xF3F1, 0x7BD2, 0xBA49, 0x7BD3, 0xC2A8, 0x7BD4, 0xBA4A, 0x7BD5, 0xBA4B, 0x7BD6, 0xBA4C, 0x7BD7, 0xBA4D, 0x7BD8, 0xBA4E, 0x7BD9, 0xB8DD, 0x7BDA, 0xF3F5, 0x7BDB, 0xBA4F, 0x7BDC, 0xBA50, 0x7BDD, 0xF3F4, 0x7BDE, 0xBA51, 0x7BDF, 0xBA52, 0x7BE0, 0xBA53, 0x7BE1, 0xB4DB, 0x7BE2, 0xBA54, 0x7BE3, 0xBA55, 0x7BE4, 0xBA56, 0x7BE5, 0xF3F6, 0x7BE6, 0xF3F7, 0x7BE7, 0xBA57, 0x7BE8, 0xBA58, 0x7BE9, 0xBA59, 0x7BEA, 0xF3F8, 0x7BEB, 0xBA5A, 0x7BEC, 0xBA5B, 0x7BED, 0xBA5C, 0x7BEE, 0xC0BA, 0x7BEF, 0xBA5D, 0x7BF0, 0xBA5E, 0x7BF1, 0xC0E9, 0x7BF2, 0xBA5F, 0x7BF3, 0xBA60, 0x7BF4, 0xBA61, 0x7BF5, 0xBA62, 0x7BF6, 0xBA63, 0x7BF7, 0xC5F1, 0x7BF8, 0xBA64, 0x7BF9, 0xBA65, 0x7BFA, 0xBA66, 0x7BFB, 0xBA67, 0x7BFC, 0xF3FB, 0x7BFD, 0xBA68, 0x7BFE, 0xF3FA, 0x7BFF, 0xBA69, 0x7C00, 0xBA6A, 0x7C01, 0xBA6B, 0x7C02, 0xBA6C, 0x7C03, 0xBA6D, 0x7C04, 0xBA6E, 0x7C05, 0xBA6F, 0x7C06, 0xBA70, 0x7C07, 0xB4D8, 0x7C08, 0xBA71, 0x7C09, 0xBA72, 0x7C0A, 0xBA73, 0x7C0B, 0xF3FE, 0x7C0C, 0xF3F9, 0x7C0D, 0xBA74, 0x7C0E, 0xBA75, 0x7C0F, 0xF3FC, 0x7C10, 0xBA76, 0x7C11, 0xBA77, 0x7C12, 0xBA78, 0x7C13, 0xBA79, 0x7C14, 0xBA7A, 0x7C15, 0xBA7B, 0x7C16, 0xF3FD, 0x7C17, 0xBA7C, 0x7C18, 0xBA7D, 0x7C19, 0xBA7E, 0x7C1A, 0xBA80, 0x7C1B, 0xBA81, 0x7C1C, 0xBA82, 0x7C1D, 0xBA83, 0x7C1E, 0xBA84, 0x7C1F, 0xF4A1, 0x7C20, 0xBA85, 0x7C21, 0xBA86, 0x7C22, 0xBA87, 0x7C23, 0xBA88, 0x7C24, 0xBA89, 0x7C25, 0xBA8A, 0x7C26, 0xF4A3, 0x7C27, 0xBBC9, 0x7C28, 0xBA8B, 0x7C29, 0xBA8C, 0x7C2A, 0xF4A2, 0x7C2B, 0xBA8D, 0x7C2C, 0xBA8E, 0x7C2D, 0xBA8F, 0x7C2E, 0xBA90, 0x7C2F, 0xBA91, 0x7C30, 0xBA92, 0x7C31, 0xBA93, 0x7C32, 0xBA94, 0x7C33, 0xBA95, 0x7C34, 0xBA96, 0x7C35, 0xBA97, 0x7C36, 0xBA98, 0x7C37, 0xBA99, 0x7C38, 0xF4A4, 0x7C39, 0xBA9A, 0x7C3A, 0xBA9B, 0x7C3B, 0xBA9C, 0x7C3C, 0xBA9D, 0x7C3D, 0xBA9E, 0x7C3E, 0xBA9F, 0x7C3F, 0xB2BE, 0x7C40, 0xF4A6, 0x7C41, 0xF4A5, 0x7C42, 0xBAA0, 0x7C43, 0xBB40, 0x7C44, 0xBB41, 0x7C45, 0xBB42, 0x7C46, 0xBB43, 0x7C47, 0xBB44, 0x7C48, 0xBB45, 0x7C49, 0xBB46, 0x7C4A, 0xBB47, 0x7C4B, 0xBB48, 0x7C4C, 0xBB49, 0x7C4D, 0xBCAE, 0x7C4E, 0xBB4A, 0x7C4F, 0xBB4B, 0x7C50, 0xBB4C, 0x7C51, 0xBB4D, 0x7C52, 0xBB4E, 0x7C53, 0xBB4F, 0x7C54, 0xBB50, 0x7C55, 0xBB51, 0x7C56, 0xBB52, 0x7C57, 0xBB53, 0x7C58, 0xBB54, 0x7C59, 0xBB55, 0x7C5A, 0xBB56, 0x7C5B, 0xBB57, 0x7C5C, 0xBB58, 0x7C5D, 0xBB59, 0x7C5E, 0xBB5A, 0x7C5F, 0xBB5B, 0x7C60, 0xBB5C, 0x7C61, 0xBB5D, 0x7C62, 0xBB5E, 0x7C63, 0xBB5F, 0x7C64, 0xBB60, 0x7C65, 0xBB61, 0x7C66, 0xBB62, 0x7C67, 0xBB63, 0x7C68, 0xBB64, 0x7C69, 0xBB65, 0x7C6A, 0xBB66, 0x7C6B, 0xBB67, 0x7C6C, 0xBB68, 0x7C6D, 0xBB69, 0x7C6E, 0xBB6A, 0x7C6F, 0xBB6B, 0x7C70, 0xBB6C, 0x7C71, 0xBB6D, 0x7C72, 0xBB6E, 0x7C73, 0xC3D7, 0x7C74, 0xD9E1, 0x7C75, 0xBB6F, 0x7C76, 0xBB70, 0x7C77, 0xBB71, 0x7C78, 0xBB72, 0x7C79, 0xBB73, 0x7C7A, 0xBB74, 0x7C7B, 0xC0E0, 0x7C7C, 0xF4CC, 0x7C7D, 0xD7D1, 0x7C7E, 0xBB75, 0x7C7F, 0xBB76, 0x7C80, 0xBB77, 0x7C81, 0xBB78, 0x7C82, 0xBB79, 0x7C83, 0xBB7A, 0x7C84, 0xBB7B, 0x7C85, 0xBB7C, 0x7C86, 0xBB7D, 0x7C87, 0xBB7E, 0x7C88, 0xBB80, 0x7C89, 0xB7DB, 0x7C8A, 0xBB81, 0x7C8B, 0xBB82, 0x7C8C, 0xBB83, 0x7C8D, 0xBB84, 0x7C8E, 0xBB85, 0x7C8F, 0xBB86, 0x7C90, 0xBB87, 0x7C91, 0xF4CE, 0x7C92, 0xC1A3, 0x7C93, 0xBB88, 0x7C94, 0xBB89, 0x7C95, 0xC6C9, 0x7C96, 0xBB8A, 0x7C97, 0xB4D6, 0x7C98, 0xD5B3, 0x7C99, 0xBB8B, 0x7C9A, 0xBB8C, 0x7C9B, 0xBB8D, 0x7C9C, 0xF4D0, 0x7C9D, 0xF4CF, 0x7C9E, 0xF4D1, 0x7C9F, 0xCBDA, 0x7CA0, 0xBB8E, 0x7CA1, 0xBB8F, 0x7CA2, 0xF4D2, 0x7CA3, 0xBB90, 0x7CA4, 0xD4C1, 0x7CA5, 0xD6E0, 0x7CA6, 0xBB91, 0x7CA7, 0xBB92, 0x7CA8, 0xBB93, 0x7CA9, 0xBB94, 0x7CAA, 0xB7E0, 0x7CAB, 0xBB95, 0x7CAC, 0xBB96, 0x7CAD, 0xBB97, 0x7CAE, 0xC1B8, 0x7CAF, 0xBB98, 0x7CB0, 0xBB99, 0x7CB1, 0xC1BB, 0x7CB2, 0xF4D3, 0x7CB3, 0xBEAC, 0x7CB4, 0xBB9A, 0x7CB5, 0xBB9B, 0x7CB6, 0xBB9C, 0x7CB7, 0xBB9D, 0x7CB8, 0xBB9E, 0x7CB9, 0xB4E2, 0x7CBA, 0xBB9F, 0x7CBB, 0xBBA0, 0x7CBC, 0xF4D4, 0x7CBD, 0xF4D5, 0x7CBE, 0xBEAB, 0x7CBF, 0xBC40, 0x7CC0, 0xBC41, 0x7CC1, 0xF4D6, 0x7CC2, 0xBC42, 0x7CC3, 0xBC43, 0x7CC4, 0xBC44, 0x7CC5, 0xF4DB, 0x7CC6, 0xBC45, 0x7CC7, 0xF4D7, 0x7CC8, 0xF4DA, 0x7CC9, 0xBC46, 0x7CCA, 0xBAFD, 0x7CCB, 0xBC47, 0x7CCC, 0xF4D8, 0x7CCD, 0xF4D9, 0x7CCE, 0xBC48, 0x7CCF, 0xBC49, 0x7CD0, 0xBC4A, 0x7CD1, 0xBC4B, 0x7CD2, 0xBC4C, 0x7CD3, 0xBC4D, 0x7CD4, 0xBC4E, 0x7CD5, 0xB8E2, 0x7CD6, 0xCCC7, 0x7CD7, 0xF4DC, 0x7CD8, 0xBC4F, 0x7CD9, 0xB2DA, 0x7CDA, 0xBC50, 0x7CDB, 0xBC51, 0x7CDC, 0xC3D3, 0x7CDD, 0xBC52, 0x7CDE, 0xBC53, 0x7CDF, 0xD4E3, 0x7CE0, 0xBFB7, 0x7CE1, 0xBC54, 0x7CE2, 0xBC55, 0x7CE3, 0xBC56, 0x7CE4, 0xBC57, 0x7CE5, 0xBC58, 0x7CE6, 0xBC59, 0x7CE7, 0xBC5A, 0x7CE8, 0xF4DD, 0x7CE9, 0xBC5B, 0x7CEA, 0xBC5C, 0x7CEB, 0xBC5D, 0x7CEC, 0xBC5E, 0x7CED, 0xBC5F, 0x7CEE, 0xBC60, 0x7CEF, 0xC5B4, 0x7CF0, 0xBC61, 0x7CF1, 0xBC62, 0x7CF2, 0xBC63, 0x7CF3, 0xBC64, 0x7CF4, 0xBC65, 0x7CF5, 0xBC66, 0x7CF6, 0xBC67, 0x7CF7, 0xBC68, 0x7CF8, 0xF4E9, 0x7CF9, 0xBC69, 0x7CFA, 0xBC6A, 0x7CFB, 0xCFB5, 0x7CFC, 0xBC6B, 0x7CFD, 0xBC6C, 0x7CFE, 0xBC6D, 0x7CFF, 0xBC6E, 0x7D00, 0xBC6F, 0x7D01, 0xBC70, 0x7D02, 0xBC71, 0x7D03, 0xBC72, 0x7D04, 0xBC73, 0x7D05, 0xBC74, 0x7D06, 0xBC75, 0x7D07, 0xBC76, 0x7D08, 0xBC77, 0x7D09, 0xBC78, 0x7D0A, 0xCEC9, 0x7D0B, 0xBC79, 0x7D0C, 0xBC7A, 0x7D0D, 0xBC7B, 0x7D0E, 0xBC7C, 0x7D0F, 0xBC7D, 0x7D10, 0xBC7E, 0x7D11, 0xBC80, 0x7D12, 0xBC81, 0x7D13, 0xBC82, 0x7D14, 0xBC83, 0x7D15, 0xBC84, 0x7D16, 0xBC85, 0x7D17, 0xBC86, 0x7D18, 0xBC87, 0x7D19, 0xBC88, 0x7D1A, 0xBC89, 0x7D1B, 0xBC8A, 0x7D1C, 0xBC8B, 0x7D1D, 0xBC8C, 0x7D1E, 0xBC8D, 0x7D1F, 0xBC8E, 0x7D20, 0xCBD8, 0x7D21, 0xBC8F, 0x7D22, 0xCBF7, 0x7D23, 0xBC90, 0x7D24, 0xBC91, 0x7D25, 0xBC92, 0x7D26, 0xBC93, 0x7D27, 0xBDF4, 0x7D28, 0xBC94, 0x7D29, 0xBC95, 0x7D2A, 0xBC96, 0x7D2B, 0xD7CF, 0x7D2C, 0xBC97, 0x7D2D, 0xBC98, 0x7D2E, 0xBC99, 0x7D2F, 0xC0DB, 0x7D30, 0xBC9A, 0x7D31, 0xBC9B, 0x7D32, 0xBC9C, 0x7D33, 0xBC9D, 0x7D34, 0xBC9E, 0x7D35, 0xBC9F, 0x7D36, 0xBCA0, 0x7D37, 0xBD40, 0x7D38, 0xBD41, 0x7D39, 0xBD42, 0x7D3A, 0xBD43, 0x7D3B, 0xBD44, 0x7D3C, 0xBD45, 0x7D3D, 0xBD46, 0x7D3E, 0xBD47, 0x7D3F, 0xBD48, 0x7D40, 0xBD49, 0x7D41, 0xBD4A, 0x7D42, 0xBD4B, 0x7D43, 0xBD4C, 0x7D44, 0xBD4D, 0x7D45, 0xBD4E, 0x7D46, 0xBD4F, 0x7D47, 0xBD50, 0x7D48, 0xBD51, 0x7D49, 0xBD52, 0x7D4A, 0xBD53, 0x7D4B, 0xBD54, 0x7D4C, 0xBD55, 0x7D4D, 0xBD56, 0x7D4E, 0xBD57, 0x7D4F, 0xBD58, 0x7D50, 0xBD59, 0x7D51, 0xBD5A, 0x7D52, 0xBD5B, 0x7D53, 0xBD5C, 0x7D54, 0xBD5D, 0x7D55, 0xBD5E, 0x7D56, 0xBD5F, 0x7D57, 0xBD60, 0x7D58, 0xBD61, 0x7D59, 0xBD62, 0x7D5A, 0xBD63, 0x7D5B, 0xBD64, 0x7D5C, 0xBD65, 0x7D5D, 0xBD66, 0x7D5E, 0xBD67, 0x7D5F, 0xBD68, 0x7D60, 0xBD69, 0x7D61, 0xBD6A, 0x7D62, 0xBD6B, 0x7D63, 0xBD6C, 0x7D64, 0xBD6D, 0x7D65, 0xBD6E, 0x7D66, 0xBD6F, 0x7D67, 0xBD70, 0x7D68, 0xBD71, 0x7D69, 0xBD72, 0x7D6A, 0xBD73, 0x7D6B, 0xBD74, 0x7D6C, 0xBD75, 0x7D6D, 0xBD76, 0x7D6E, 0xD0F5, 0x7D6F, 0xBD77, 0x7D70, 0xBD78, 0x7D71, 0xBD79, 0x7D72, 0xBD7A, 0x7D73, 0xBD7B, 0x7D74, 0xBD7C, 0x7D75, 0xBD7D, 0x7D76, 0xBD7E, 0x7D77, 0xF4EA, 0x7D78, 0xBD80, 0x7D79, 0xBD81, 0x7D7A, 0xBD82, 0x7D7B, 0xBD83, 0x7D7C, 0xBD84, 0x7D7D, 0xBD85, 0x7D7E, 0xBD86, 0x7D7F, 0xBD87, 0x7D80, 0xBD88, 0x7D81, 0xBD89, 0x7D82, 0xBD8A, 0x7D83, 0xBD8B, 0x7D84, 0xBD8C, 0x7D85, 0xBD8D, 0x7D86, 0xBD8E, 0x7D87, 0xBD8F, 0x7D88, 0xBD90, 0x7D89, 0xBD91, 0x7D8A, 0xBD92, 0x7D8B, 0xBD93, 0x7D8C, 0xBD94, 0x7D8D, 0xBD95, 0x7D8E, 0xBD96, 0x7D8F, 0xBD97, 0x7D90, 0xBD98, 0x7D91, 0xBD99, 0x7D92, 0xBD9A, 0x7D93, 0xBD9B, 0x7D94, 0xBD9C, 0x7D95, 0xBD9D, 0x7D96, 0xBD9E, 0x7D97, 0xBD9F, 0x7D98, 0xBDA0, 0x7D99, 0xBE40, 0x7D9A, 0xBE41, 0x7D9B, 0xBE42, 0x7D9C, 0xBE43, 0x7D9D, 0xBE44, 0x7D9E, 0xBE45, 0x7D9F, 0xBE46, 0x7DA0, 0xBE47, 0x7DA1, 0xBE48, 0x7DA2, 0xBE49, 0x7DA3, 0xBE4A, 0x7DA4, 0xBE4B, 0x7DA5, 0xBE4C, 0x7DA6, 0xF4EB, 0x7DA7, 0xBE4D, 0x7DA8, 0xBE4E, 0x7DA9, 0xBE4F, 0x7DAA, 0xBE50, 0x7DAB, 0xBE51, 0x7DAC, 0xBE52, 0x7DAD, 0xBE53, 0x7DAE, 0xF4EC, 0x7DAF, 0xBE54, 0x7DB0, 0xBE55, 0x7DB1, 0xBE56, 0x7DB2, 0xBE57, 0x7DB3, 0xBE58, 0x7DB4, 0xBE59, 0x7DB5, 0xBE5A, 0x7DB6, 0xBE5B, 0x7DB7, 0xBE5C, 0x7DB8, 0xBE5D, 0x7DB9, 0xBE5E, 0x7DBA, 0xBE5F, 0x7DBB, 0xBE60, 0x7DBC, 0xBE61, 0x7DBD, 0xBE62, 0x7DBE, 0xBE63, 0x7DBF, 0xBE64, 0x7DC0, 0xBE65, 0x7DC1, 0xBE66, 0x7DC2, 0xBE67, 0x7DC3, 0xBE68, 0x7DC4, 0xBE69, 0x7DC5, 0xBE6A, 0x7DC6, 0xBE6B, 0x7DC7, 0xBE6C, 0x7DC8, 0xBE6D, 0x7DC9, 0xBE6E, 0x7DCA, 0xBE6F, 0x7DCB, 0xBE70, 0x7DCC, 0xBE71, 0x7DCD, 0xBE72, 0x7DCE, 0xBE73, 0x7DCF, 0xBE74, 0x7DD0, 0xBE75, 0x7DD1, 0xBE76, 0x7DD2, 0xBE77, 0x7DD3, 0xBE78, 0x7DD4, 0xBE79, 0x7DD5, 0xBE7A, 0x7DD6, 0xBE7B, 0x7DD7, 0xBE7C, 0x7DD8, 0xBE7D, 0x7DD9, 0xBE7E, 0x7DDA, 0xBE80, 0x7DDB, 0xBE81, 0x7DDC, 0xBE82, 0x7DDD, 0xBE83, 0x7DDE, 0xBE84, 0x7DDF, 0xBE85, 0x7DE0, 0xBE86, 0x7DE1, 0xBE87, 0x7DE2, 0xBE88, 0x7DE3, 0xBE89, 0x7DE4, 0xBE8A, 0x7DE5, 0xBE8B, 0x7DE6, 0xBE8C, 0x7DE7, 0xBE8D, 0x7DE8, 0xBE8E, 0x7DE9, 0xBE8F, 0x7DEA, 0xBE90, 0x7DEB, 0xBE91, 0x7DEC, 0xBE92, 0x7DED, 0xBE93, 0x7DEE, 0xBE94, 0x7DEF, 0xBE95, 0x7DF0, 0xBE96, 0x7DF1, 0xBE97, 0x7DF2, 0xBE98, 0x7DF3, 0xBE99, 0x7DF4, 0xBE9A, 0x7DF5, 0xBE9B, 0x7DF6, 0xBE9C, 0x7DF7, 0xBE9D, 0x7DF8, 0xBE9E, 0x7DF9, 0xBE9F, 0x7DFA, 0xBEA0, 0x7DFB, 0xBF40, 0x7DFC, 0xBF41, 0x7DFD, 0xBF42, 0x7DFE, 0xBF43, 0x7DFF, 0xBF44, 0x7E00, 0xBF45, 0x7E01, 0xBF46, 0x7E02, 0xBF47, 0x7E03, 0xBF48, 0x7E04, 0xBF49, 0x7E05, 0xBF4A, 0x7E06, 0xBF4B, 0x7E07, 0xBF4C, 0x7E08, 0xBF4D, 0x7E09, 0xBF4E, 0x7E0A, 0xBF4F, 0x7E0B, 0xBF50, 0x7E0C, 0xBF51, 0x7E0D, 0xBF52, 0x7E0E, 0xBF53, 0x7E0F, 0xBF54, 0x7E10, 0xBF55, 0x7E11, 0xBF56, 0x7E12, 0xBF57, 0x7E13, 0xBF58, 0x7E14, 0xBF59, 0x7E15, 0xBF5A, 0x7E16, 0xBF5B, 0x7E17, 0xBF5C, 0x7E18, 0xBF5D, 0x7E19, 0xBF5E, 0x7E1A, 0xBF5F, 0x7E1B, 0xBF60, 0x7E1C, 0xBF61, 0x7E1D, 0xBF62, 0x7E1E, 0xBF63, 0x7E1F, 0xBF64, 0x7E20, 0xBF65, 0x7E21, 0xBF66, 0x7E22, 0xBF67, 0x7E23, 0xBF68, 0x7E24, 0xBF69, 0x7E25, 0xBF6A, 0x7E26, 0xBF6B, 0x7E27, 0xBF6C, 0x7E28, 0xBF6D, 0x7E29, 0xBF6E, 0x7E2A, 0xBF6F, 0x7E2B, 0xBF70, 0x7E2C, 0xBF71, 0x7E2D, 0xBF72, 0x7E2E, 0xBF73, 0x7E2F, 0xBF74, 0x7E30, 0xBF75, 0x7E31, 0xBF76, 0x7E32, 0xBF77, 0x7E33, 0xBF78, 0x7E34, 0xBF79, 0x7E35, 0xBF7A, 0x7E36, 0xBF7B, 0x7E37, 0xBF7C, 0x7E38, 0xBF7D, 0x7E39, 0xBF7E, 0x7E3A, 0xBF80, 0x7E3B, 0xF7E3, 0x7E3C, 0xBF81, 0x7E3D, 0xBF82, 0x7E3E, 0xBF83, 0x7E3F, 0xBF84, 0x7E40, 0xBF85, 0x7E41, 0xB7B1, 0x7E42, 0xBF86, 0x7E43, 0xBF87, 0x7E44, 0xBF88, 0x7E45, 0xBF89, 0x7E46, 0xBF8A, 0x7E47, 0xF4ED, 0x7E48, 0xBF8B, 0x7E49, 0xBF8C, 0x7E4A, 0xBF8D, 0x7E4B, 0xBF8E, 0x7E4C, 0xBF8F, 0x7E4D, 0xBF90, 0x7E4E, 0xBF91, 0x7E4F, 0xBF92, 0x7E50, 0xBF93, 0x7E51, 0xBF94, 0x7E52, 0xBF95, 0x7E53, 0xBF96, 0x7E54, 0xBF97, 0x7E55, 0xBF98, 0x7E56, 0xBF99, 0x7E57, 0xBF9A, 0x7E58, 0xBF9B, 0x7E59, 0xBF9C, 0x7E5A, 0xBF9D, 0x7E5B, 0xBF9E, 0x7E5C, 0xBF9F, 0x7E5D, 0xBFA0, 0x7E5E, 0xC040, 0x7E5F, 0xC041, 0x7E60, 0xC042, 0x7E61, 0xC043, 0x7E62, 0xC044, 0x7E63, 0xC045, 0x7E64, 0xC046, 0x7E65, 0xC047, 0x7E66, 0xC048, 0x7E67, 0xC049, 0x7E68, 0xC04A, 0x7E69, 0xC04B, 0x7E6A, 0xC04C, 0x7E6B, 0xC04D, 0x7E6C, 0xC04E, 0x7E6D, 0xC04F, 0x7E6E, 0xC050, 0x7E6F, 0xC051, 0x7E70, 0xC052, 0x7E71, 0xC053, 0x7E72, 0xC054, 0x7E73, 0xC055, 0x7E74, 0xC056, 0x7E75, 0xC057, 0x7E76, 0xC058, 0x7E77, 0xC059, 0x7E78, 0xC05A, 0x7E79, 0xC05B, 0x7E7A, 0xC05C, 0x7E7B, 0xC05D, 0x7E7C, 0xC05E, 0x7E7D, 0xC05F, 0x7E7E, 0xC060, 0x7E7F, 0xC061, 0x7E80, 0xC062, 0x7E81, 0xC063, 0x7E82, 0xD7EB, 0x7E83, 0xC064, 0x7E84, 0xC065, 0x7E85, 0xC066, 0x7E86, 0xC067, 0x7E87, 0xC068, 0x7E88, 0xC069, 0x7E89, 0xC06A, 0x7E8A, 0xC06B, 0x7E8B, 0xC06C, 0x7E8C, 0xC06D, 0x7E8D, 0xC06E, 0x7E8E, 0xC06F, 0x7E8F, 0xC070, 0x7E90, 0xC071, 0x7E91, 0xC072, 0x7E92, 0xC073, 0x7E93, 0xC074, 0x7E94, 0xC075, 0x7E95, 0xC076, 0x7E96, 0xC077, 0x7E97, 0xC078, 0x7E98, 0xC079, 0x7E99, 0xC07A, 0x7E9A, 0xC07B, 0x7E9B, 0xF4EE, 0x7E9C, 0xC07C, 0x7E9D, 0xC07D, 0x7E9E, 0xC07E, 0x7E9F, 0xE6F9, 0x7EA0, 0xBEC0, 0x7EA1, 0xE6FA, 0x7EA2, 0xBAEC, 0x7EA3, 0xE6FB, 0x7EA4, 0xCFCB, 0x7EA5, 0xE6FC, 0x7EA6, 0xD4BC, 0x7EA7, 0xBCB6, 0x7EA8, 0xE6FD, 0x7EA9, 0xE6FE, 0x7EAA, 0xBCCD, 0x7EAB, 0xC8D2, 0x7EAC, 0xCEB3, 0x7EAD, 0xE7A1, 0x7EAE, 0xC080, 0x7EAF, 0xB4BF, 0x7EB0, 0xE7A2, 0x7EB1, 0xC9B4, 0x7EB2, 0xB8D9, 0x7EB3, 0xC4C9, 0x7EB4, 0xC081, 0x7EB5, 0xD7DD, 0x7EB6, 0xC2DA, 0x7EB7, 0xB7D7, 0x7EB8, 0xD6BD, 0x7EB9, 0xCEC6, 0x7EBA, 0xB7C4, 0x7EBB, 0xC082, 0x7EBC, 0xC083, 0x7EBD, 0xC5A6, 0x7EBE, 0xE7A3, 0x7EBF, 0xCFDF, 0x7EC0, 0xE7A4, 0x7EC1, 0xE7A5, 0x7EC2, 0xE7A6, 0x7EC3, 0xC1B7, 0x7EC4, 0xD7E9, 0x7EC5, 0xC9F0, 0x7EC6, 0xCFB8, 0x7EC7, 0xD6AF, 0x7EC8, 0xD6D5, 0x7EC9, 0xE7A7, 0x7ECA, 0xB0ED, 0x7ECB, 0xE7A8, 0x7ECC, 0xE7A9, 0x7ECD, 0xC9DC, 0x7ECE, 0xD2EF, 0x7ECF, 0xBEAD, 0x7ED0, 0xE7AA, 0x7ED1, 0xB0F3, 0x7ED2, 0xC8DE, 0x7ED3, 0xBDE1, 0x7ED4, 0xE7AB, 0x7ED5, 0xC8C6, 0x7ED6, 0xC084, 0x7ED7, 0xE7AC, 0x7ED8, 0xBBE6, 0x7ED9, 0xB8F8, 0x7EDA, 0xD1A4, 0x7EDB, 0xE7AD, 0x7EDC, 0xC2E7, 0x7EDD, 0xBEF8, 0x7EDE, 0xBDCA, 0x7EDF, 0xCDB3, 0x7EE0, 0xE7AE, 0x7EE1, 0xE7AF, 0x7EE2, 0xBEEE, 0x7EE3, 0xD0E5, 0x7EE4, 0xC085, 0x7EE5, 0xCBE7, 0x7EE6, 0xCCD0, 0x7EE7, 0xBCCC, 0x7EE8, 0xE7B0, 0x7EE9, 0xBCA8, 0x7EEA, 0xD0F7, 0x7EEB, 0xE7B1, 0x7EEC, 0xC086, 0x7EED, 0xD0F8, 0x7EEE, 0xE7B2, 0x7EEF, 0xE7B3, 0x7EF0, 0xB4C2, 0x7EF1, 0xE7B4, 0x7EF2, 0xE7B5, 0x7EF3, 0xC9FE, 0x7EF4, 0xCEAC, 0x7EF5, 0xC3E0, 0x7EF6, 0xE7B7, 0x7EF7, 0xB1C1, 0x7EF8, 0xB3F1, 0x7EF9, 0xC087, 0x7EFA, 0xE7B8, 0x7EFB, 0xE7B9, 0x7EFC, 0xD7DB, 0x7EFD, 0xD5C0, 0x7EFE, 0xE7BA, 0x7EFF, 0xC2CC, 0x7F00, 0xD7BA, 0x7F01, 0xE7BB, 0x7F02, 0xE7BC, 0x7F03, 0xE7BD, 0x7F04, 0xBCEA, 0x7F05, 0xC3E5, 0x7F06, 0xC0C2, 0x7F07, 0xE7BE, 0x7F08, 0xE7BF, 0x7F09, 0xBCA9, 0x7F0A, 0xC088, 0x7F0B, 0xE7C0, 0x7F0C, 0xE7C1, 0x7F0D, 0xE7B6, 0x7F0E, 0xB6D0, 0x7F0F, 0xE7C2, 0x7F10, 0xC089, 0x7F11, 0xE7C3, 0x7F12, 0xE7C4, 0x7F13, 0xBBBA, 0x7F14, 0xB5DE, 0x7F15, 0xC2C6, 0x7F16, 0xB1E0, 0x7F17, 0xE7C5, 0x7F18, 0xD4B5, 0x7F19, 0xE7C6, 0x7F1A, 0xB8BF, 0x7F1B, 0xE7C8, 0x7F1C, 0xE7C7, 0x7F1D, 0xB7EC, 0x7F1E, 0xC08A, 0x7F1F, 0xE7C9, 0x7F20, 0xB2F8, 0x7F21, 0xE7CA, 0x7F22, 0xE7CB, 0x7F23, 0xE7CC, 0x7F24, 0xE7CD, 0x7F25, 0xE7CE, 0x7F26, 0xE7CF, 0x7F27, 0xE7D0, 0x7F28, 0xD3A7, 0x7F29, 0xCBF5, 0x7F2A, 0xE7D1, 0x7F2B, 0xE7D2, 0x7F2C, 0xE7D3, 0x7F2D, 0xE7D4, 0x7F2E, 0xC9C9, 0x7F2F, 0xE7D5, 0x7F30, 0xE7D6, 0x7F31, 0xE7D7, 0x7F32, 0xE7D8, 0x7F33, 0xE7D9, 0x7F34, 0xBDC9, 0x7F35, 0xE7DA, 0x7F36, 0xF3BE, 0x7F37, 0xC08B, 0x7F38, 0xB8D7, 0x7F39, 0xC08C, 0x7F3A, 0xC8B1, 0x7F3B, 0xC08D, 0x7F3C, 0xC08E, 0x7F3D, 0xC08F, 0x7F3E, 0xC090, 0x7F3F, 0xC091, 0x7F40, 0xC092, 0x7F41, 0xC093, 0x7F42, 0xF3BF, 0x7F43, 0xC094, 0x7F44, 0xF3C0, 0x7F45, 0xF3C1, 0x7F46, 0xC095, 0x7F47, 0xC096, 0x7F48, 0xC097, 0x7F49, 0xC098, 0x7F4A, 0xC099, 0x7F4B, 0xC09A, 0x7F4C, 0xC09B, 0x7F4D, 0xC09C, 0x7F4E, 0xC09D, 0x7F4F, 0xC09E, 0x7F50, 0xB9DE, 0x7F51, 0xCDF8, 0x7F52, 0xC09F, 0x7F53, 0xC0A0, 0x7F54, 0xD8E8, 0x7F55, 0xBAB1, 0x7F56, 0xC140, 0x7F57, 0xC2DE, 0x7F58, 0xEEB7, 0x7F59, 0xC141, 0x7F5A, 0xB7A3, 0x7F5B, 0xC142, 0x7F5C, 0xC143, 0x7F5D, 0xC144, 0x7F5E, 0xC145, 0x7F5F, 0xEEB9, 0x7F60, 0xC146, 0x7F61, 0xEEB8, 0x7F62, 0xB0D5, 0x7F63, 0xC147, 0x7F64, 0xC148, 0x7F65, 0xC149, 0x7F66, 0xC14A, 0x7F67, 0xC14B, 0x7F68, 0xEEBB, 0x7F69, 0xD5D6, 0x7F6A, 0xD7EF, 0x7F6B, 0xC14C, 0x7F6C, 0xC14D, 0x7F6D, 0xC14E, 0x7F6E, 0xD6C3, 0x7F6F, 0xC14F, 0x7F70, 0xC150, 0x7F71, 0xEEBD, 0x7F72, 0xCAF0, 0x7F73, 0xC151, 0x7F74, 0xEEBC, 0x7F75, 0xC152, 0x7F76, 0xC153, 0x7F77, 0xC154, 0x7F78, 0xC155, 0x7F79, 0xEEBE, 0x7F7A, 0xC156, 0x7F7B, 0xC157, 0x7F7C, 0xC158, 0x7F7D, 0xC159, 0x7F7E, 0xEEC0, 0x7F7F, 0xC15A, 0x7F80, 0xC15B, 0x7F81, 0xEEBF, 0x7F82, 0xC15C, 0x7F83, 0xC15D, 0x7F84, 0xC15E, 0x7F85, 0xC15F, 0x7F86, 0xC160, 0x7F87, 0xC161, 0x7F88, 0xC162, 0x7F89, 0xC163, 0x7F8A, 0xD1F2, 0x7F8B, 0xC164, 0x7F8C, 0xC7BC, 0x7F8D, 0xC165, 0x7F8E, 0xC3C0, 0x7F8F, 0xC166, 0x7F90, 0xC167, 0x7F91, 0xC168, 0x7F92, 0xC169, 0x7F93, 0xC16A, 0x7F94, 0xB8E1, 0x7F95, 0xC16B, 0x7F96, 0xC16C, 0x7F97, 0xC16D, 0x7F98, 0xC16E, 0x7F99, 0xC16F, 0x7F9A, 0xC1E7, 0x7F9B, 0xC170, 0x7F9C, 0xC171, 0x7F9D, 0xF4C6, 0x7F9E, 0xD0DF, 0x7F9F, 0xF4C7, 0x7FA0, 0xC172, 0x7FA1, 0xCFDB, 0x7FA2, 0xC173, 0x7FA3, 0xC174, 0x7FA4, 0xC8BA, 0x7FA5, 0xC175, 0x7FA6, 0xC176, 0x7FA7, 0xF4C8, 0x7FA8, 0xC177, 0x7FA9, 0xC178, 0x7FAA, 0xC179, 0x7FAB, 0xC17A, 0x7FAC, 0xC17B, 0x7FAD, 0xC17C, 0x7FAE, 0xC17D, 0x7FAF, 0xF4C9, 0x7FB0, 0xF4CA, 0x7FB1, 0xC17E, 0x7FB2, 0xF4CB, 0x7FB3, 0xC180, 0x7FB4, 0xC181, 0x7FB5, 0xC182, 0x7FB6, 0xC183, 0x7FB7, 0xC184, 0x7FB8, 0xD9FA, 0x7FB9, 0xB8FE, 0x7FBA, 0xC185, 0x7FBB, 0xC186, 0x7FBC, 0xE5F1, 0x7FBD, 0xD3F0, 0x7FBE, 0xC187, 0x7FBF, 0xF4E0, 0x7FC0, 0xC188, 0x7FC1, 0xCECC, 0x7FC2, 0xC189, 0x7FC3, 0xC18A, 0x7FC4, 0xC18B, 0x7FC5, 0xB3E1, 0x7FC6, 0xC18C, 0x7FC7, 0xC18D, 0x7FC8, 0xC18E, 0x7FC9, 0xC18F, 0x7FCA, 0xF1B4, 0x7FCB, 0xC190, 0x7FCC, 0xD2EE, 0x7FCD, 0xC191, 0x7FCE, 0xF4E1, 0x7FCF, 0xC192, 0x7FD0, 0xC193, 0x7FD1, 0xC194, 0x7FD2, 0xC195, 0x7FD3, 0xC196, 0x7FD4, 0xCFE8, 0x7FD5, 0xF4E2, 0x7FD6, 0xC197, 0x7FD7, 0xC198, 0x7FD8, 0xC7CC, 0x7FD9, 0xC199, 0x7FDA, 0xC19A, 0x7FDB, 0xC19B, 0x7FDC, 0xC19C, 0x7FDD, 0xC19D, 0x7FDE, 0xC19E, 0x7FDF, 0xB5D4, 0x7FE0, 0xB4E4, 0x7FE1, 0xF4E4, 0x7FE2, 0xC19F, 0x7FE3, 0xC1A0, 0x7FE4, 0xC240, 0x7FE5, 0xF4E3, 0x7FE6, 0xF4E5, 0x7FE7, 0xC241, 0x7FE8, 0xC242, 0x7FE9, 0xF4E6, 0x7FEA, 0xC243, 0x7FEB, 0xC244, 0x7FEC, 0xC245, 0x7FED, 0xC246, 0x7FEE, 0xF4E7, 0x7FEF, 0xC247, 0x7FF0, 0xBAB2, 0x7FF1, 0xB0BF, 0x7FF2, 0xC248, 0x7FF3, 0xF4E8, 0x7FF4, 0xC249, 0x7FF5, 0xC24A, 0x7FF6, 0xC24B, 0x7FF7, 0xC24C, 0x7FF8, 0xC24D, 0x7FF9, 0xC24E, 0x7FFA, 0xC24F, 0x7FFB, 0xB7AD, 0x7FFC, 0xD2ED, 0x7FFD, 0xC250, 0x7FFE, 0xC251, 0x7FFF, 0xC252, 0x8000, 0xD2AB, 0x8001, 0xC0CF, 0x8002, 0xC253, 0x8003, 0xBFBC, 0x8004, 0xEBA3, 0x8005, 0xD5DF, 0x8006, 0xEAC8, 0x8007, 0xC254, 0x8008, 0xC255, 0x8009, 0xC256, 0x800A, 0xC257, 0x800B, 0xF1F3, 0x800C, 0xB6F8, 0x800D, 0xCBA3, 0x800E, 0xC258, 0x800F, 0xC259, 0x8010, 0xC4CD, 0x8011, 0xC25A, 0x8012, 0xF1E7, 0x8013, 0xC25B, 0x8014, 0xF1E8, 0x8015, 0xB8FB, 0x8016, 0xF1E9, 0x8017, 0xBAC4, 0x8018, 0xD4C5, 0x8019, 0xB0D2, 0x801A, 0xC25C, 0x801B, 0xC25D, 0x801C, 0xF1EA, 0x801D, 0xC25E, 0x801E, 0xC25F, 0x801F, 0xC260, 0x8020, 0xF1EB, 0x8021, 0xC261, 0x8022, 0xF1EC, 0x8023, 0xC262, 0x8024, 0xC263, 0x8025, 0xF1ED, 0x8026, 0xF1EE, 0x8027, 0xF1EF, 0x8028, 0xF1F1, 0x8029, 0xF1F0, 0x802A, 0xC5D5, 0x802B, 0xC264, 0x802C, 0xC265, 0x802D, 0xC266, 0x802E, 0xC267, 0x802F, 0xC268, 0x8030, 0xC269, 0x8031, 0xF1F2, 0x8032, 0xC26A, 0x8033, 0xB6FA, 0x8034, 0xC26B, 0x8035, 0xF1F4, 0x8036, 0xD2AE, 0x8037, 0xDEC7, 0x8038, 0xCBCA, 0x8039, 0xC26C, 0x803A, 0xC26D, 0x803B, 0xB3DC, 0x803C, 0xC26E, 0x803D, 0xB5A2, 0x803E, 0xC26F, 0x803F, 0xB9A2, 0x8040, 0xC270, 0x8041, 0xC271, 0x8042, 0xC4F4, 0x8043, 0xF1F5, 0x8044, 0xC272, 0x8045, 0xC273, 0x8046, 0xF1F6, 0x8047, 0xC274, 0x8048, 0xC275, 0x8049, 0xC276, 0x804A, 0xC1C4, 0x804B, 0xC1FB, 0x804C, 0xD6B0, 0x804D, 0xF1F7, 0x804E, 0xC277, 0x804F, 0xC278, 0x8050, 0xC279, 0x8051, 0xC27A, 0x8052, 0xF1F8, 0x8053, 0xC27B, 0x8054, 0xC1AA, 0x8055, 0xC27C, 0x8056, 0xC27D, 0x8057, 0xC27E, 0x8058, 0xC6B8, 0x8059, 0xC280, 0x805A, 0xBEDB, 0x805B, 0xC281, 0x805C, 0xC282, 0x805D, 0xC283, 0x805E, 0xC284, 0x805F, 0xC285, 0x8060, 0xC286, 0x8061, 0xC287, 0x8062, 0xC288, 0x8063, 0xC289, 0x8064, 0xC28A, 0x8065, 0xC28B, 0x8066, 0xC28C, 0x8067, 0xC28D, 0x8068, 0xC28E, 0x8069, 0xF1F9, 0x806A, 0xB4CF, 0x806B, 0xC28F, 0x806C, 0xC290, 0x806D, 0xC291, 0x806E, 0xC292, 0x806F, 0xC293, 0x8070, 0xC294, 0x8071, 0xF1FA, 0x8072, 0xC295, 0x8073, 0xC296, 0x8074, 0xC297, 0x8075, 0xC298, 0x8076, 0xC299, 0x8077, 0xC29A, 0x8078, 0xC29B, 0x8079, 0xC29C, 0x807A, 0xC29D, 0x807B, 0xC29E, 0x807C, 0xC29F, 0x807D, 0xC2A0, 0x807E, 0xC340, 0x807F, 0xEDB2, 0x8080, 0xEDB1, 0x8081, 0xC341, 0x8082, 0xC342, 0x8083, 0xCBE0, 0x8084, 0xD2DE, 0x8085, 0xC343, 0x8086, 0xCBC1, 0x8087, 0xD5D8, 0x8088, 0xC344, 0x8089, 0xC8E2, 0x808A, 0xC345, 0x808B, 0xC0DF, 0x808C, 0xBCA1, 0x808D, 0xC346, 0x808E, 0xC347, 0x808F, 0xC348, 0x8090, 0xC349, 0x8091, 0xC34A, 0x8092, 0xC34B, 0x8093, 0xEBC1, 0x8094, 0xC34C, 0x8095, 0xC34D, 0x8096, 0xD0A4, 0x8097, 0xC34E, 0x8098, 0xD6E2, 0x8099, 0xC34F, 0x809A, 0xB6C7, 0x809B, 0xB8D8, 0x809C, 0xEBC0, 0x809D, 0xB8CE, 0x809E, 0xC350, 0x809F, 0xEBBF, 0x80A0, 0xB3A6, 0x80A1, 0xB9C9, 0x80A2, 0xD6AB, 0x80A3, 0xC351, 0x80A4, 0xB7F4, 0x80A5, 0xB7CA, 0x80A6, 0xC352, 0x80A7, 0xC353, 0x80A8, 0xC354, 0x80A9, 0xBCE7, 0x80AA, 0xB7BE, 0x80AB, 0xEBC6, 0x80AC, 0xC355, 0x80AD, 0xEBC7, 0x80AE, 0xB0B9, 0x80AF, 0xBFCF, 0x80B0, 0xC356, 0x80B1, 0xEBC5, 0x80B2, 0xD3FD, 0x80B3, 0xC357, 0x80B4, 0xEBC8, 0x80B5, 0xC358, 0x80B6, 0xC359, 0x80B7, 0xEBC9, 0x80B8, 0xC35A, 0x80B9, 0xC35B, 0x80BA, 0xB7CE, 0x80BB, 0xC35C, 0x80BC, 0xEBC2, 0x80BD, 0xEBC4, 0x80BE, 0xC9F6, 0x80BF, 0xD6D7, 0x80C0, 0xD5CD, 0x80C1, 0xD0B2, 0x80C2, 0xEBCF, 0x80C3, 0xCEB8, 0x80C4, 0xEBD0, 0x80C5, 0xC35D, 0x80C6, 0xB5A8, 0x80C7, 0xC35E, 0x80C8, 0xC35F, 0x80C9, 0xC360, 0x80CA, 0xC361, 0x80CB, 0xC362, 0x80CC, 0xB1B3, 0x80CD, 0xEBD2, 0x80CE, 0xCCA5, 0x80CF, 0xC363, 0x80D0, 0xC364, 0x80D1, 0xC365, 0x80D2, 0xC366, 0x80D3, 0xC367, 0x80D4, 0xC368, 0x80D5, 0xC369, 0x80D6, 0xC5D6, 0x80D7, 0xEBD3, 0x80D8, 0xC36A, 0x80D9, 0xEBD1, 0x80DA, 0xC5DF, 0x80DB, 0xEBCE, 0x80DC, 0xCAA4, 0x80DD, 0xEBD5, 0x80DE, 0xB0FB, 0x80DF, 0xC36B, 0x80E0, 0xC36C, 0x80E1, 0xBAFA, 0x80E2, 0xC36D, 0x80E3, 0xC36E, 0x80E4, 0xD8B7, 0x80E5, 0xF1E3, 0x80E6, 0xC36F, 0x80E7, 0xEBCA, 0x80E8, 0xEBCB, 0x80E9, 0xEBCC, 0x80EA, 0xEBCD, 0x80EB, 0xEBD6, 0x80EC, 0xE6C0, 0x80ED, 0xEBD9, 0x80EE, 0xC370, 0x80EF, 0xBFE8, 0x80F0, 0xD2C8, 0x80F1, 0xEBD7, 0x80F2, 0xEBDC, 0x80F3, 0xB8EC, 0x80F4, 0xEBD8, 0x80F5, 0xC371, 0x80F6, 0xBDBA, 0x80F7, 0xC372, 0x80F8, 0xD0D8, 0x80F9, 0xC373, 0x80FA, 0xB0B7, 0x80FB, 0xC374, 0x80FC, 0xEBDD, 0x80FD, 0xC4DC, 0x80FE, 0xC375, 0x80FF, 0xC376, 0x8100, 0xC377, 0x8101, 0xC378, 0x8102, 0xD6AC, 0x8103, 0xC379, 0x8104, 0xC37A, 0x8105, 0xC37B, 0x8106, 0xB4E0, 0x8107, 0xC37C, 0x8108, 0xC37D, 0x8109, 0xC2F6, 0x810A, 0xBCB9, 0x810B, 0xC37E, 0x810C, 0xC380, 0x810D, 0xEBDA, 0x810E, 0xEBDB, 0x810F, 0xD4E0, 0x8110, 0xC6EA, 0x8111, 0xC4D4, 0x8112, 0xEBDF, 0x8113, 0xC5A7, 0x8114, 0xD9F5, 0x8115, 0xC381, 0x8116, 0xB2B1, 0x8117, 0xC382, 0x8118, 0xEBE4, 0x8119, 0xC383, 0x811A, 0xBDC5, 0x811B, 0xC384, 0x811C, 0xC385, 0x811D, 0xC386, 0x811E, 0xEBE2, 0x811F, 0xC387, 0x8120, 0xC388, 0x8121, 0xC389, 0x8122, 0xC38A, 0x8123, 0xC38B, 0x8124, 0xC38C, 0x8125, 0xC38D, 0x8126, 0xC38E, 0x8127, 0xC38F, 0x8128, 0xC390, 0x8129, 0xC391, 0x812A, 0xC392, 0x812B, 0xC393, 0x812C, 0xEBE3, 0x812D, 0xC394, 0x812E, 0xC395, 0x812F, 0xB8AC, 0x8130, 0xC396, 0x8131, 0xCDD1, 0x8132, 0xEBE5, 0x8133, 0xC397, 0x8134, 0xC398, 0x8135, 0xC399, 0x8136, 0xEBE1, 0x8137, 0xC39A, 0x8138, 0xC1B3, 0x8139, 0xC39B, 0x813A, 0xC39C, 0x813B, 0xC39D, 0x813C, 0xC39E, 0x813D, 0xC39F, 0x813E, 0xC6A2, 0x813F, 0xC3A0, 0x8140, 0xC440, 0x8141, 0xC441, 0x8142, 0xC442, 0x8143, 0xC443, 0x8144, 0xC444, 0x8145, 0xC445, 0x8146, 0xCCF3, 0x8147, 0xC446, 0x8148, 0xEBE6, 0x8149, 0xC447, 0x814A, 0xC0B0, 0x814B, 0xD2B8, 0x814C, 0xEBE7, 0x814D, 0xC448, 0x814E, 0xC449, 0x814F, 0xC44A, 0x8150, 0xB8AF, 0x8151, 0xB8AD, 0x8152, 0xC44B, 0x8153, 0xEBE8, 0x8154, 0xC7BB, 0x8155, 0xCDF3, 0x8156, 0xC44C, 0x8157, 0xC44D, 0x8158, 0xC44E, 0x8159, 0xEBEA, 0x815A, 0xEBEB, 0x815B, 0xC44F, 0x815C, 0xC450, 0x815D, 0xC451, 0x815E, 0xC452, 0x815F, 0xC453, 0x8160, 0xEBED, 0x8161, 0xC454, 0x8162, 0xC455, 0x8163, 0xC456, 0x8164, 0xC457, 0x8165, 0xD0C8, 0x8166, 0xC458, 0x8167, 0xEBF2, 0x8168, 0xC459, 0x8169, 0xEBEE, 0x816A, 0xC45A, 0x816B, 0xC45B, 0x816C, 0xC45C, 0x816D, 0xEBF1, 0x816E, 0xC8F9, 0x816F, 0xC45D, 0x8170, 0xD1FC, 0x8171, 0xEBEC, 0x8172, 0xC45E, 0x8173, 0xC45F, 0x8174, 0xEBE9, 0x8175, 0xC460, 0x8176, 0xC461, 0x8177, 0xC462, 0x8178, 0xC463, 0x8179, 0xB8B9, 0x817A, 0xCFD9, 0x817B, 0xC4E5, 0x817C, 0xEBEF, 0x817D, 0xEBF0, 0x817E, 0xCCDA, 0x817F, 0xCDC8, 0x8180, 0xB0F2, 0x8181, 0xC464, 0x8182, 0xEBF6, 0x8183, 0xC465, 0x8184, 0xC466, 0x8185, 0xC467, 0x8186, 0xC468, 0x8187, 0xC469, 0x8188, 0xEBF5, 0x8189, 0xC46A, 0x818A, 0xB2B2, 0x818B, 0xC46B, 0x818C, 0xC46C, 0x818D, 0xC46D, 0x818E, 0xC46E, 0x818F, 0xB8E0, 0x8190, 0xC46F, 0x8191, 0xEBF7, 0x8192, 0xC470, 0x8193, 0xC471, 0x8194, 0xC472, 0x8195, 0xC473, 0x8196, 0xC474, 0x8197, 0xC475, 0x8198, 0xB1EC, 0x8199, 0xC476, 0x819A, 0xC477, 0x819B, 0xCCC5, 0x819C, 0xC4A4, 0x819D, 0xCFA5, 0x819E, 0xC478, 0x819F, 0xC479, 0x81A0, 0xC47A, 0x81A1, 0xC47B, 0x81A2, 0xC47C, 0x81A3, 0xEBF9, 0x81A4, 0xC47D, 0x81A5, 0xC47E, 0x81A6, 0xECA2, 0x81A7, 0xC480, 0x81A8, 0xC5F2, 0x81A9, 0xC481, 0x81AA, 0xEBFA, 0x81AB, 0xC482, 0x81AC, 0xC483, 0x81AD, 0xC484, 0x81AE, 0xC485, 0x81AF, 0xC486, 0x81B0, 0xC487, 0x81B1, 0xC488, 0x81B2, 0xC489, 0x81B3, 0xC9C5, 0x81B4, 0xC48A, 0x81B5, 0xC48B, 0x81B6, 0xC48C, 0x81B7, 0xC48D, 0x81B8, 0xC48E, 0x81B9, 0xC48F, 0x81BA, 0xE2DF, 0x81BB, 0xEBFE, 0x81BC, 0xC490, 0x81BD, 0xC491, 0x81BE, 0xC492, 0x81BF, 0xC493, 0x81C0, 0xCDCE, 0x81C1, 0xECA1, 0x81C2, 0xB1DB, 0x81C3, 0xD3B7, 0x81C4, 0xC494, 0x81C5, 0xC495, 0x81C6, 0xD2DC, 0x81C7, 0xC496, 0x81C8, 0xC497, 0x81C9, 0xC498, 0x81CA, 0xEBFD, 0x81CB, 0xC499, 0x81CC, 0xEBFB, 0x81CD, 0xC49A, 0x81CE, 0xC49B, 0x81CF, 0xC49C, 0x81D0, 0xC49D, 0x81D1, 0xC49E, 0x81D2, 0xC49F, 0x81D3, 0xC4A0, 0x81D4, 0xC540, 0x81D5, 0xC541, 0x81D6, 0xC542, 0x81D7, 0xC543, 0x81D8, 0xC544, 0x81D9, 0xC545, 0x81DA, 0xC546, 0x81DB, 0xC547, 0x81DC, 0xC548, 0x81DD, 0xC549, 0x81DE, 0xC54A, 0x81DF, 0xC54B, 0x81E0, 0xC54C, 0x81E1, 0xC54D, 0x81E2, 0xC54E, 0x81E3, 0xB3BC, 0x81E4, 0xC54F, 0x81E5, 0xC550, 0x81E6, 0xC551, 0x81E7, 0xEAB0, 0x81E8, 0xC552, 0x81E9, 0xC553, 0x81EA, 0xD7D4, 0x81EB, 0xC554, 0x81EC, 0xF4AB, 0x81ED, 0xB3F4, 0x81EE, 0xC555, 0x81EF, 0xC556, 0x81F0, 0xC557, 0x81F1, 0xC558, 0x81F2, 0xC559, 0x81F3, 0xD6C1, 0x81F4, 0xD6C2, 0x81F5, 0xC55A, 0x81F6, 0xC55B, 0x81F7, 0xC55C, 0x81F8, 0xC55D, 0x81F9, 0xC55E, 0x81FA, 0xC55F, 0x81FB, 0xD5E9, 0x81FC, 0xBECA, 0x81FD, 0xC560, 0x81FE, 0xF4A7, 0x81FF, 0xC561, 0x8200, 0xD2A8, 0x8201, 0xF4A8, 0x8202, 0xF4A9, 0x8203, 0xC562, 0x8204, 0xF4AA, 0x8205, 0xBECB, 0x8206, 0xD3DF, 0x8207, 0xC563, 0x8208, 0xC564, 0x8209, 0xC565, 0x820A, 0xC566, 0x820B, 0xC567, 0x820C, 0xC9E0, 0x820D, 0xC9E1, 0x820E, 0xC568, 0x820F, 0xC569, 0x8210, 0xF3C2, 0x8211, 0xC56A, 0x8212, 0xCAE6, 0x8213, 0xC56B, 0x8214, 0xCCF2, 0x8215, 0xC56C, 0x8216, 0xC56D, 0x8217, 0xC56E, 0x8218, 0xC56F, 0x8219, 0xC570, 0x821A, 0xC571, 0x821B, 0xE2B6, 0x821C, 0xCBB4, 0x821D, 0xC572, 0x821E, 0xCEE8, 0x821F, 0xD6DB, 0x8220, 0xC573, 0x8221, 0xF4AD, 0x8222, 0xF4AE, 0x8223, 0xF4AF, 0x8224, 0xC574, 0x8225, 0xC575, 0x8226, 0xC576, 0x8227, 0xC577, 0x8228, 0xF4B2, 0x8229, 0xC578, 0x822A, 0xBABD, 0x822B, 0xF4B3, 0x822C, 0xB0E3, 0x822D, 0xF4B0, 0x822E, 0xC579, 0x822F, 0xF4B1, 0x8230, 0xBDA2, 0x8231, 0xB2D5, 0x8232, 0xC57A, 0x8233, 0xF4B6, 0x8234, 0xF4B7, 0x8235, 0xB6E6, 0x8236, 0xB2B0, 0x8237, 0xCFCF, 0x8238, 0xF4B4, 0x8239, 0xB4AC, 0x823A, 0xC57B, 0x823B, 0xF4B5, 0x823C, 0xC57C, 0x823D, 0xC57D, 0x823E, 0xF4B8, 0x823F, 0xC57E, 0x8240, 0xC580, 0x8241, 0xC581, 0x8242, 0xC582, 0x8243, 0xC583, 0x8244, 0xF4B9, 0x8245, 0xC584, 0x8246, 0xC585, 0x8247, 0xCDA7, 0x8248, 0xC586, 0x8249, 0xF4BA, 0x824A, 0xC587, 0x824B, 0xF4BB, 0x824C, 0xC588, 0x824D, 0xC589, 0x824E, 0xC58A, 0x824F, 0xF4BC, 0x8250, 0xC58B, 0x8251, 0xC58C, 0x8252, 0xC58D, 0x8253, 0xC58E, 0x8254, 0xC58F, 0x8255, 0xC590, 0x8256, 0xC591, 0x8257, 0xC592, 0x8258, 0xCBD2, 0x8259, 0xC593, 0x825A, 0xF4BD, 0x825B, 0xC594, 0x825C, 0xC595, 0x825D, 0xC596, 0x825E, 0xC597, 0x825F, 0xF4BE, 0x8260, 0xC598, 0x8261, 0xC599, 0x8262, 0xC59A, 0x8263, 0xC59B, 0x8264, 0xC59C, 0x8265, 0xC59D, 0x8266, 0xC59E, 0x8267, 0xC59F, 0x8268, 0xF4BF, 0x8269, 0xC5A0, 0x826A, 0xC640, 0x826B, 0xC641, 0x826C, 0xC642, 0x826D, 0xC643, 0x826E, 0xF4DE, 0x826F, 0xC1BC, 0x8270, 0xBCE8, 0x8271, 0xC644, 0x8272, 0xC9AB, 0x8273, 0xD1DE, 0x8274, 0xE5F5, 0x8275, 0xC645, 0x8276, 0xC646, 0x8277, 0xC647, 0x8278, 0xC648, 0x8279, 0xDCB3, 0x827A, 0xD2D5, 0x827B, 0xC649, 0x827C, 0xC64A, 0x827D, 0xDCB4, 0x827E, 0xB0AC, 0x827F, 0xDCB5, 0x8280, 0xC64B, 0x8281, 0xC64C, 0x8282, 0xBDDA, 0x8283, 0xC64D, 0x8284, 0xDCB9, 0x8285, 0xC64E, 0x8286, 0xC64F, 0x8287, 0xC650, 0x8288, 0xD8C2, 0x8289, 0xC651, 0x828A, 0xDCB7, 0x828B, 0xD3F3, 0x828C, 0xC652, 0x828D, 0xC9D6, 0x828E, 0xDCBA, 0x828F, 0xDCB6, 0x8290, 0xC653, 0x8291, 0xDCBB, 0x8292, 0xC3A2, 0x8293, 0xC654, 0x8294, 0xC655, 0x8295, 0xC656, 0x8296, 0xC657, 0x8297, 0xDCBC, 0x8298, 0xDCC5, 0x8299, 0xDCBD, 0x829A, 0xC658, 0x829B, 0xC659, 0x829C, 0xCEDF, 0x829D, 0xD6A5, 0x829E, 0xC65A, 0x829F, 0xDCCF, 0x82A0, 0xC65B, 0x82A1, 0xDCCD, 0x82A2, 0xC65C, 0x82A3, 0xC65D, 0x82A4, 0xDCD2, 0x82A5, 0xBDE6, 0x82A6, 0xC2AB, 0x82A7, 0xC65E, 0x82A8, 0xDCB8, 0x82A9, 0xDCCB, 0x82AA, 0xDCCE, 0x82AB, 0xDCBE, 0x82AC, 0xB7D2, 0x82AD, 0xB0C5, 0x82AE, 0xDCC7, 0x82AF, 0xD0BE, 0x82B0, 0xDCC1, 0x82B1, 0xBBA8, 0x82B2, 0xC65F, 0x82B3, 0xB7BC, 0x82B4, 0xDCCC, 0x82B5, 0xC660, 0x82B6, 0xC661, 0x82B7, 0xDCC6, 0x82B8, 0xDCBF, 0x82B9, 0xC7DB, 0x82BA, 0xC662, 0x82BB, 0xC663, 0x82BC, 0xC664, 0x82BD, 0xD1BF, 0x82BE, 0xDCC0, 0x82BF, 0xC665, 0x82C0, 0xC666, 0x82C1, 0xDCCA, 0x82C2, 0xC667, 0x82C3, 0xC668, 0x82C4, 0xDCD0, 0x82C5, 0xC669, 0x82C6, 0xC66A, 0x82C7, 0xCEAD, 0x82C8, 0xDCC2, 0x82C9, 0xC66B, 0x82CA, 0xDCC3, 0x82CB, 0xDCC8, 0x82CC, 0xDCC9, 0x82CD, 0xB2D4, 0x82CE, 0xDCD1, 0x82CF, 0xCBD5, 0x82D0, 0xC66C, 0x82D1, 0xD4B7, 0x82D2, 0xDCDB, 0x82D3, 0xDCDF, 0x82D4, 0xCCA6, 0x82D5, 0xDCE6, 0x82D6, 0xC66D, 0x82D7, 0xC3E7, 0x82D8, 0xDCDC, 0x82D9, 0xC66E, 0x82DA, 0xC66F, 0x82DB, 0xBFC1, 0x82DC, 0xDCD9, 0x82DD, 0xC670, 0x82DE, 0xB0FA, 0x82DF, 0xB9B6, 0x82E0, 0xDCE5, 0x82E1, 0xDCD3, 0x82E2, 0xC671, 0x82E3, 0xDCC4, 0x82E4, 0xDCD6, 0x82E5, 0xC8F4, 0x82E6, 0xBFE0, 0x82E7, 0xC672, 0x82E8, 0xC673, 0x82E9, 0xC674, 0x82EA, 0xC675, 0x82EB, 0xC9BB, 0x82EC, 0xC676, 0x82ED, 0xC677, 0x82EE, 0xC678, 0x82EF, 0xB1BD, 0x82F0, 0xC679, 0x82F1, 0xD3A2, 0x82F2, 0xC67A, 0x82F3, 0xC67B, 0x82F4, 0xDCDA, 0x82F5, 0xC67C, 0x82F6, 0xC67D, 0x82F7, 0xDCD5, 0x82F8, 0xC67E, 0x82F9, 0xC6BB, 0x82FA, 0xC680, 0x82FB, 0xDCDE, 0x82FC, 0xC681, 0x82FD, 0xC682, 0x82FE, 0xC683, 0x82FF, 0xC684, 0x8300, 0xC685, 0x8301, 0xD7C2, 0x8302, 0xC3AF, 0x8303, 0xB7B6, 0x8304, 0xC7D1, 0x8305, 0xC3A9, 0x8306, 0xDCE2, 0x8307, 0xDCD8, 0x8308, 0xDCEB, 0x8309, 0xDCD4, 0x830A, 0xC686, 0x830B, 0xC687, 0x830C, 0xDCDD, 0x830D, 0xC688, 0x830E, 0xBEA5, 0x830F, 0xDCD7, 0x8310, 0xC689, 0x8311, 0xDCE0, 0x8312, 0xC68A, 0x8313, 0xC68B, 0x8314, 0xDCE3, 0x8315, 0xDCE4, 0x8316, 0xC68C, 0x8317, 0xDCF8, 0x8318, 0xC68D, 0x8319, 0xC68E, 0x831A, 0xDCE1, 0x831B, 0xDDA2, 0x831C, 0xDCE7, 0x831D, 0xC68F, 0x831E, 0xC690, 0x831F, 0xC691, 0x8320, 0xC692, 0x8321, 0xC693, 0x8322, 0xC694, 0x8323, 0xC695, 0x8324, 0xC696, 0x8325, 0xC697, 0x8326, 0xC698, 0x8327, 0xBCEB, 0x8328, 0xB4C4, 0x8329, 0xC699, 0x832A, 0xC69A, 0x832B, 0xC3A3, 0x832C, 0xB2E7, 0x832D, 0xDCFA, 0x832E, 0xC69B, 0x832F, 0xDCF2, 0x8330, 0xC69C, 0x8331, 0xDCEF, 0x8332, 0xC69D, 0x8333, 0xDCFC, 0x8334, 0xDCEE, 0x8335, 0xD2F0, 0x8336, 0xB2E8, 0x8337, 0xC69E, 0x8338, 0xC8D7, 0x8339, 0xC8E3, 0x833A, 0xDCFB, 0x833B, 0xC69F, 0x833C, 0xDCED, 0x833D, 0xC6A0, 0x833E, 0xC740, 0x833F, 0xC741, 0x8340, 0xDCF7, 0x8341, 0xC742, 0x8342, 0xC743, 0x8343, 0xDCF5, 0x8344, 0xC744, 0x8345, 0xC745, 0x8346, 0xBEA3, 0x8347, 0xDCF4, 0x8348, 0xC746, 0x8349, 0xB2DD, 0x834A, 0xC747, 0x834B, 0xC748, 0x834C, 0xC749, 0x834D, 0xC74A, 0x834E, 0xC74B, 0x834F, 0xDCF3, 0x8350, 0xBCF6, 0x8351, 0xDCE8, 0x8352, 0xBBC4, 0x8353, 0xC74C, 0x8354, 0xC0F3, 0x8355, 0xC74D, 0x8356, 0xC74E, 0x8357, 0xC74F, 0x8358, 0xC750, 0x8359, 0xC751, 0x835A, 0xBCD4, 0x835B, 0xDCE9, 0x835C, 0xDCEA, 0x835D, 0xC752, 0x835E, 0xDCF1, 0x835F, 0xDCF6, 0x8360, 0xDCF9, 0x8361, 0xB5B4, 0x8362, 0xC753, 0x8363, 0xC8D9, 0x8364, 0xBBE7, 0x8365, 0xDCFE, 0x8366, 0xDCFD, 0x8367, 0xD3AB, 0x8368, 0xDDA1, 0x8369, 0xDDA3, 0x836A, 0xDDA5, 0x836B, 0xD2F1, 0x836C, 0xDDA4, 0x836D, 0xDDA6, 0x836E, 0xDDA7, 0x836F, 0xD2A9, 0x8370, 0xC754, 0x8371, 0xC755, 0x8372, 0xC756, 0x8373, 0xC757, 0x8374, 0xC758, 0x8375, 0xC759, 0x8376, 0xC75A, 0x8377, 0xBAC9, 0x8378, 0xDDA9, 0x8379, 0xC75B, 0x837A, 0xC75C, 0x837B, 0xDDB6, 0x837C, 0xDDB1, 0x837D, 0xDDB4, 0x837E, 0xC75D, 0x837F, 0xC75E, 0x8380, 0xC75F, 0x8381, 0xC760, 0x8382, 0xC761, 0x8383, 0xC762, 0x8384, 0xC763, 0x8385, 0xDDB0, 0x8386, 0xC6CE, 0x8387, 0xC764, 0x8388, 0xC765, 0x8389, 0xC0F2, 0x838A, 0xC766, 0x838B, 0xC767, 0x838C, 0xC768, 0x838D, 0xC769, 0x838E, 0xC9AF, 0x838F, 0xC76A, 0x8390, 0xC76B, 0x8391, 0xC76C, 0x8392, 0xDCEC, 0x8393, 0xDDAE, 0x8394, 0xC76D, 0x8395, 0xC76E, 0x8396, 0xC76F, 0x8397, 0xC770, 0x8398, 0xDDB7, 0x8399, 0xC771, 0x839A, 0xC772, 0x839B, 0xDCF0, 0x839C, 0xDDAF, 0x839D, 0xC773, 0x839E, 0xDDB8, 0x839F, 0xC774, 0x83A0, 0xDDAC, 0x83A1, 0xC775, 0x83A2, 0xC776, 0x83A3, 0xC777, 0x83A4, 0xC778, 0x83A5, 0xC779, 0x83A6, 0xC77A, 0x83A7, 0xC77B, 0x83A8, 0xDDB9, 0x83A9, 0xDDB3, 0x83AA, 0xDDAD, 0x83AB, 0xC4AA, 0x83AC, 0xC77C, 0x83AD, 0xC77D, 0x83AE, 0xC77E, 0x83AF, 0xC780, 0x83B0, 0xDDA8, 0x83B1, 0xC0B3, 0x83B2, 0xC1AB, 0x83B3, 0xDDAA, 0x83B4, 0xDDAB, 0x83B5, 0xC781, 0x83B6, 0xDDB2, 0x83B7, 0xBBF1, 0x83B8, 0xDDB5, 0x83B9, 0xD3A8, 0x83BA, 0xDDBA, 0x83BB, 0xC782, 0x83BC, 0xDDBB, 0x83BD, 0xC3A7, 0x83BE, 0xC783, 0x83BF, 0xC784, 0x83C0, 0xDDD2, 0x83C1, 0xDDBC, 0x83C2, 0xC785, 0x83C3, 0xC786, 0x83C4, 0xC787, 0x83C5, 0xDDD1, 0x83C6, 0xC788, 0x83C7, 0xB9BD, 0x83C8, 0xC789, 0x83C9, 0xC78A, 0x83CA, 0xBED5, 0x83CB, 0xC78B, 0x83CC, 0xBEFA, 0x83CD, 0xC78C, 0x83CE, 0xC78D, 0x83CF, 0xBACA, 0x83D0, 0xC78E, 0x83D1, 0xC78F, 0x83D2, 0xC790, 0x83D3, 0xC791, 0x83D4, 0xDDCA, 0x83D5, 0xC792, 0x83D6, 0xDDC5, 0x83D7, 0xC793, 0x83D8, 0xDDBF, 0x83D9, 0xC794, 0x83DA, 0xC795, 0x83DB, 0xC796, 0x83DC, 0xB2CB, 0x83DD, 0xDDC3, 0x83DE, 0xC797, 0x83DF, 0xDDCB, 0x83E0, 0xB2A4, 0x83E1, 0xDDD5, 0x83E2, 0xC798, 0x83E3, 0xC799, 0x83E4, 0xC79A, 0x83E5, 0xDDBE, 0x83E6, 0xC79B, 0x83E7, 0xC79C, 0x83E8, 0xC79D, 0x83E9, 0xC6D0, 0x83EA, 0xDDD0, 0x83EB, 0xC79E, 0x83EC, 0xC79F, 0x83ED, 0xC7A0, 0x83EE, 0xC840, 0x83EF, 0xC841, 0x83F0, 0xDDD4, 0x83F1, 0xC1E2, 0x83F2, 0xB7C6, 0x83F3, 0xC842, 0x83F4, 0xC843, 0x83F5, 0xC844, 0x83F6, 0xC845, 0x83F7, 0xC846, 0x83F8, 0xDDCE, 0x83F9, 0xDDCF, 0x83FA, 0xC847, 0x83FB, 0xC848, 0x83FC, 0xC849, 0x83FD, 0xDDC4, 0x83FE, 0xC84A, 0x83FF, 0xC84B, 0x8400, 0xC84C, 0x8401, 0xDDBD, 0x8402, 0xC84D, 0x8403, 0xDDCD, 0x8404, 0xCCD1, 0x8405, 0xC84E, 0x8406, 0xDDC9, 0x8407, 0xC84F, 0x8408, 0xC850, 0x8409, 0xC851, 0x840A, 0xC852, 0x840B, 0xDDC2, 0x840C, 0xC3C8, 0x840D, 0xC6BC, 0x840E, 0xCEAE, 0x840F, 0xDDCC, 0x8410, 0xC853, 0x8411, 0xDDC8, 0x8412, 0xC854, 0x8413, 0xC855, 0x8414, 0xC856, 0x8415, 0xC857, 0x8416, 0xC858, 0x8417, 0xC859, 0x8418, 0xDDC1, 0x8419, 0xC85A, 0x841A, 0xC85B, 0x841B, 0xC85C, 0x841C, 0xDDC6, 0x841D, 0xC2DC, 0x841E, 0xC85D, 0x841F, 0xC85E, 0x8420, 0xC85F, 0x8421, 0xC860, 0x8422, 0xC861, 0x8423, 0xC862, 0x8424, 0xD3A9, 0x8425, 0xD3AA, 0x8426, 0xDDD3, 0x8427, 0xCFF4, 0x8428, 0xC8F8, 0x8429, 0xC863, 0x842A, 0xC864, 0x842B, 0xC865, 0x842C, 0xC866, 0x842D, 0xC867, 0x842E, 0xC868, 0x842F, 0xC869, 0x8430, 0xC86A, 0x8431, 0xDDE6, 0x8432, 0xC86B, 0x8433, 0xC86C, 0x8434, 0xC86D, 0x8435, 0xC86E, 0x8436, 0xC86F, 0x8437, 0xC870, 0x8438, 0xDDC7, 0x8439, 0xC871, 0x843A, 0xC872, 0x843B, 0xC873, 0x843C, 0xDDE0, 0x843D, 0xC2E4, 0x843E, 0xC874, 0x843F, 0xC875, 0x8440, 0xC876, 0x8441, 0xC877, 0x8442, 0xC878, 0x8443, 0xC879, 0x8444, 0xC87A, 0x8445, 0xC87B, 0x8446, 0xDDE1, 0x8447, 0xC87C, 0x8448, 0xC87D, 0x8449, 0xC87E, 0x844A, 0xC880, 0x844B, 0xC881, 0x844C, 0xC882, 0x844D, 0xC883, 0x844E, 0xC884, 0x844F, 0xC885, 0x8450, 0xC886, 0x8451, 0xDDD7, 0x8452, 0xC887, 0x8453, 0xC888, 0x8454, 0xC889, 0x8455, 0xC88A, 0x8456, 0xC88B, 0x8457, 0xD6F8, 0x8458, 0xC88C, 0x8459, 0xDDD9, 0x845A, 0xDDD8, 0x845B, 0xB8F0, 0x845C, 0xDDD6, 0x845D, 0xC88D, 0x845E, 0xC88E, 0x845F, 0xC88F, 0x8460, 0xC890, 0x8461, 0xC6CF, 0x8462, 0xC891, 0x8463, 0xB6AD, 0x8464, 0xC892, 0x8465, 0xC893, 0x8466, 0xC894, 0x8467, 0xC895, 0x8468, 0xC896, 0x8469, 0xDDE2, 0x846A, 0xC897, 0x846B, 0xBAF9, 0x846C, 0xD4E1, 0x846D, 0xDDE7, 0x846E, 0xC898, 0x846F, 0xC899, 0x8470, 0xC89A, 0x8471, 0xB4D0, 0x8472, 0xC89B, 0x8473, 0xDDDA, 0x8474, 0xC89C, 0x8475, 0xBFFB, 0x8476, 0xDDE3, 0x8477, 0xC89D, 0x8478, 0xDDDF, 0x8479, 0xC89E, 0x847A, 0xDDDD, 0x847B, 0xC89F, 0x847C, 0xC8A0, 0x847D, 0xC940, 0x847E, 0xC941, 0x847F, 0xC942, 0x8480, 0xC943, 0x8481, 0xC944, 0x8482, 0xB5D9, 0x8483, 0xC945, 0x8484, 0xC946, 0x8485, 0xC947, 0x8486, 0xC948, 0x8487, 0xDDDB, 0x8488, 0xDDDC, 0x8489, 0xDDDE, 0x848A, 0xC949, 0x848B, 0xBDAF, 0x848C, 0xDDE4, 0x848D, 0xC94A, 0x848E, 0xDDE5, 0x848F, 0xC94B, 0x8490, 0xC94C, 0x8491, 0xC94D, 0x8492, 0xC94E, 0x8493, 0xC94F, 0x8494, 0xC950, 0x8495, 0xC951, 0x8496, 0xC952, 0x8497, 0xDDF5, 0x8498, 0xC953, 0x8499, 0xC3C9, 0x849A, 0xC954, 0x849B, 0xC955, 0x849C, 0xCBE2, 0x849D, 0xC956, 0x849E, 0xC957, 0x849F, 0xC958, 0x84A0, 0xC959, 0x84A1, 0xDDF2, 0x84A2, 0xC95A, 0x84A3, 0xC95B, 0x84A4, 0xC95C, 0x84A5, 0xC95D, 0x84A6, 0xC95E, 0x84A7, 0xC95F, 0x84A8, 0xC960, 0x84A9, 0xC961, 0x84AA, 0xC962, 0x84AB, 0xC963, 0x84AC, 0xC964, 0x84AD, 0xC965, 0x84AE, 0xC966, 0x84AF, 0xD8E1, 0x84B0, 0xC967, 0x84B1, 0xC968, 0x84B2, 0xC6D1, 0x84B3, 0xC969, 0x84B4, 0xDDF4, 0x84B5, 0xC96A, 0x84B6, 0xC96B, 0x84B7, 0xC96C, 0x84B8, 0xD5F4, 0x84B9, 0xDDF3, 0x84BA, 0xDDF0, 0x84BB, 0xC96D, 0x84BC, 0xC96E, 0x84BD, 0xDDEC, 0x84BE, 0xC96F, 0x84BF, 0xDDEF, 0x84C0, 0xC970, 0x84C1, 0xDDE8, 0x84C2, 0xC971, 0x84C3, 0xC972, 0x84C4, 0xD0EE, 0x84C5, 0xC973, 0x84C6, 0xC974, 0x84C7, 0xC975, 0x84C8, 0xC976, 0x84C9, 0xC8D8, 0x84CA, 0xDDEE, 0x84CB, 0xC977, 0x84CC, 0xC978, 0x84CD, 0xDDE9, 0x84CE, 0xC979, 0x84CF, 0xC97A, 0x84D0, 0xDDEA, 0x84D1, 0xCBF2, 0x84D2, 0xC97B, 0x84D3, 0xDDED, 0x84D4, 0xC97C, 0x84D5, 0xC97D, 0x84D6, 0xB1CD, 0x84D7, 0xC97E, 0x84D8, 0xC980, 0x84D9, 0xC981, 0x84DA, 0xC982, 0x84DB, 0xC983, 0x84DC, 0xC984, 0x84DD, 0xC0B6, 0x84DE, 0xC985, 0x84DF, 0xBCBB, 0x84E0, 0xDDF1, 0x84E1, 0xC986, 0x84E2, 0xC987, 0x84E3, 0xDDF7, 0x84E4, 0xC988, 0x84E5, 0xDDF6, 0x84E6, 0xDDEB, 0x84E7, 0xC989, 0x84E8, 0xC98A, 0x84E9, 0xC98B, 0x84EA, 0xC98C, 0x84EB, 0xC98D, 0x84EC, 0xC5EE, 0x84ED, 0xC98E, 0x84EE, 0xC98F, 0x84EF, 0xC990, 0x84F0, 0xDDFB, 0x84F1, 0xC991, 0x84F2, 0xC992, 0x84F3, 0xC993, 0x84F4, 0xC994, 0x84F5, 0xC995, 0x84F6, 0xC996, 0x84F7, 0xC997, 0x84F8, 0xC998, 0x84F9, 0xC999, 0x84FA, 0xC99A, 0x84FB, 0xC99B, 0x84FC, 0xDEA4, 0x84FD, 0xC99C, 0x84FE, 0xC99D, 0x84FF, 0xDEA3, 0x8500, 0xC99E, 0x8501, 0xC99F, 0x8502, 0xC9A0, 0x8503, 0xCA40, 0x8504, 0xCA41, 0x8505, 0xCA42, 0x8506, 0xCA43, 0x8507, 0xCA44, 0x8508, 0xCA45, 0x8509, 0xCA46, 0x850A, 0xCA47, 0x850B, 0xCA48, 0x850C, 0xDDF8, 0x850D, 0xCA49, 0x850E, 0xCA4A, 0x850F, 0xCA4B, 0x8510, 0xCA4C, 0x8511, 0xC3EF, 0x8512, 0xCA4D, 0x8513, 0xC2FB, 0x8514, 0xCA4E, 0x8515, 0xCA4F, 0x8516, 0xCA50, 0x8517, 0xD5E1, 0x8518, 0xCA51, 0x8519, 0xCA52, 0x851A, 0xCEB5, 0x851B, 0xCA53, 0x851C, 0xCA54, 0x851D, 0xCA55, 0x851E, 0xCA56, 0x851F, 0xDDFD, 0x8520, 0xCA57, 0x8521, 0xB2CC, 0x8522, 0xCA58, 0x8523, 0xCA59, 0x8524, 0xCA5A, 0x8525, 0xCA5B, 0x8526, 0xCA5C, 0x8527, 0xCA5D, 0x8528, 0xCA5E, 0x8529, 0xCA5F, 0x852A, 0xCA60, 0x852B, 0xC4E8, 0x852C, 0xCADF, 0x852D, 0xCA61, 0x852E, 0xCA62, 0x852F, 0xCA63, 0x8530, 0xCA64, 0x8531, 0xCA65, 0x8532, 0xCA66, 0x8533, 0xCA67, 0x8534, 0xCA68, 0x8535, 0xCA69, 0x8536, 0xCA6A, 0x8537, 0xC7BE, 0x8538, 0xDDFA, 0x8539, 0xDDFC, 0x853A, 0xDDFE, 0x853B, 0xDEA2, 0x853C, 0xB0AA, 0x853D, 0xB1CE, 0x853E, 0xCA6B, 0x853F, 0xCA6C, 0x8540, 0xCA6D, 0x8541, 0xCA6E, 0x8542, 0xCA6F, 0x8543, 0xDEAC, 0x8544, 0xCA70, 0x8545, 0xCA71, 0x8546, 0xCA72, 0x8547, 0xCA73, 0x8548, 0xDEA6, 0x8549, 0xBDB6, 0x854A, 0xC8EF, 0x854B, 0xCA74, 0x854C, 0xCA75, 0x854D, 0xCA76, 0x854E, 0xCA77, 0x854F, 0xCA78, 0x8550, 0xCA79, 0x8551, 0xCA7A, 0x8552, 0xCA7B, 0x8553, 0xCA7C, 0x8554, 0xCA7D, 0x8555, 0xCA7E, 0x8556, 0xDEA1, 0x8557, 0xCA80, 0x8558, 0xCA81, 0x8559, 0xDEA5, 0x855A, 0xCA82, 0x855B, 0xCA83, 0x855C, 0xCA84, 0x855D, 0xCA85, 0x855E, 0xDEA9, 0x855F, 0xCA86, 0x8560, 0xCA87, 0x8561, 0xCA88, 0x8562, 0xCA89, 0x8563, 0xCA8A, 0x8564, 0xDEA8, 0x8565, 0xCA8B, 0x8566, 0xCA8C, 0x8567, 0xCA8D, 0x8568, 0xDEA7, 0x8569, 0xCA8E, 0x856A, 0xCA8F, 0x856B, 0xCA90, 0x856C, 0xCA91, 0x856D, 0xCA92, 0x856E, 0xCA93, 0x856F, 0xCA94, 0x8570, 0xCA95, 0x8571, 0xCA96, 0x8572, 0xDEAD, 0x8573, 0xCA97, 0x8574, 0xD4CC, 0x8575, 0xCA98, 0x8576, 0xCA99, 0x8577, 0xCA9A, 0x8578, 0xCA9B, 0x8579, 0xDEB3, 0x857A, 0xDEAA, 0x857B, 0xDEAE, 0x857C, 0xCA9C, 0x857D, 0xCA9D, 0x857E, 0xC0D9, 0x857F, 0xCA9E, 0x8580, 0xCA9F, 0x8581, 0xCAA0, 0x8582, 0xCB40, 0x8583, 0xCB41, 0x8584, 0xB1A1, 0x8585, 0xDEB6, 0x8586, 0xCB42, 0x8587, 0xDEB1, 0x8588, 0xCB43, 0x8589, 0xCB44, 0x858A, 0xCB45, 0x858B, 0xCB46, 0x858C, 0xCB47, 0x858D, 0xCB48, 0x858E, 0xCB49, 0x858F, 0xDEB2, 0x8590, 0xCB4A, 0x8591, 0xCB4B, 0x8592, 0xCB4C, 0x8593, 0xCB4D, 0x8594, 0xCB4E, 0x8595, 0xCB4F, 0x8596, 0xCB50, 0x8597, 0xCB51, 0x8598, 0xCB52, 0x8599, 0xCB53, 0x859A, 0xCB54, 0x859B, 0xD1A6, 0x859C, 0xDEB5, 0x859D, 0xCB55, 0x859E, 0xCB56, 0x859F, 0xCB57, 0x85A0, 0xCB58, 0x85A1, 0xCB59, 0x85A2, 0xCB5A, 0x85A3, 0xCB5B, 0x85A4, 0xDEAF, 0x85A5, 0xCB5C, 0x85A6, 0xCB5D, 0x85A7, 0xCB5E, 0x85A8, 0xDEB0, 0x85A9, 0xCB5F, 0x85AA, 0xD0BD, 0x85AB, 0xCB60, 0x85AC, 0xCB61, 0x85AD, 0xCB62, 0x85AE, 0xDEB4, 0x85AF, 0xCAED, 0x85B0, 0xDEB9, 0x85B1, 0xCB63, 0x85B2, 0xCB64, 0x85B3, 0xCB65, 0x85B4, 0xCB66, 0x85B5, 0xCB67, 0x85B6, 0xCB68, 0x85B7, 0xDEB8, 0x85B8, 0xCB69, 0x85B9, 0xDEB7, 0x85BA, 0xCB6A, 0x85BB, 0xCB6B, 0x85BC, 0xCB6C, 0x85BD, 0xCB6D, 0x85BE, 0xCB6E, 0x85BF, 0xCB6F, 0x85C0, 0xCB70, 0x85C1, 0xDEBB, 0x85C2, 0xCB71, 0x85C3, 0xCB72, 0x85C4, 0xCB73, 0x85C5, 0xCB74, 0x85C6, 0xCB75, 0x85C7, 0xCB76, 0x85C8, 0xCB77, 0x85C9, 0xBDE5, 0x85CA, 0xCB78, 0x85CB, 0xCB79, 0x85CC, 0xCB7A, 0x85CD, 0xCB7B, 0x85CE, 0xCB7C, 0x85CF, 0xB2D8, 0x85D0, 0xC3EA, 0x85D1, 0xCB7D, 0x85D2, 0xCB7E, 0x85D3, 0xDEBA, 0x85D4, 0xCB80, 0x85D5, 0xC5BA, 0x85D6, 0xCB81, 0x85D7, 0xCB82, 0x85D8, 0xCB83, 0x85D9, 0xCB84, 0x85DA, 0xCB85, 0x85DB, 0xCB86, 0x85DC, 0xDEBC, 0x85DD, 0xCB87, 0x85DE, 0xCB88, 0x85DF, 0xCB89, 0x85E0, 0xCB8A, 0x85E1, 0xCB8B, 0x85E2, 0xCB8C, 0x85E3, 0xCB8D, 0x85E4, 0xCCD9, 0x85E5, 0xCB8E, 0x85E6, 0xCB8F, 0x85E7, 0xCB90, 0x85E8, 0xCB91, 0x85E9, 0xB7AA, 0x85EA, 0xCB92, 0x85EB, 0xCB93, 0x85EC, 0xCB94, 0x85ED, 0xCB95, 0x85EE, 0xCB96, 0x85EF, 0xCB97, 0x85F0, 0xCB98, 0x85F1, 0xCB99, 0x85F2, 0xCB9A, 0x85F3, 0xCB9B, 0x85F4, 0xCB9C, 0x85F5, 0xCB9D, 0x85F6, 0xCB9E, 0x85F7, 0xCB9F, 0x85F8, 0xCBA0, 0x85F9, 0xCC40, 0x85FA, 0xCC41, 0x85FB, 0xD4E5, 0x85FC, 0xCC42, 0x85FD, 0xCC43, 0x85FE, 0xCC44, 0x85FF, 0xDEBD, 0x8600, 0xCC45, 0x8601, 0xCC46, 0x8602, 0xCC47, 0x8603, 0xCC48, 0x8604, 0xCC49, 0x8605, 0xDEBF, 0x8606, 0xCC4A, 0x8607, 0xCC4B, 0x8608, 0xCC4C, 0x8609, 0xCC4D, 0x860A, 0xCC4E, 0x860B, 0xCC4F, 0x860C, 0xCC50, 0x860D, 0xCC51, 0x860E, 0xCC52, 0x860F, 0xCC53, 0x8610, 0xCC54, 0x8611, 0xC4A2, 0x8612, 0xCC55, 0x8613, 0xCC56, 0x8614, 0xCC57, 0x8615, 0xCC58, 0x8616, 0xDEC1, 0x8617, 0xCC59, 0x8618, 0xCC5A, 0x8619, 0xCC5B, 0x861A, 0xCC5C, 0x861B, 0xCC5D, 0x861C, 0xCC5E, 0x861D, 0xCC5F, 0x861E, 0xCC60, 0x861F, 0xCC61, 0x8620, 0xCC62, 0x8621, 0xCC63, 0x8622, 0xCC64, 0x8623, 0xCC65, 0x8624, 0xCC66, 0x8625, 0xCC67, 0x8626, 0xCC68, 0x8627, 0xDEBE, 0x8628, 0xCC69, 0x8629, 0xDEC0, 0x862A, 0xCC6A, 0x862B, 0xCC6B, 0x862C, 0xCC6C, 0x862D, 0xCC6D, 0x862E, 0xCC6E, 0x862F, 0xCC6F, 0x8630, 0xCC70, 0x8631, 0xCC71, 0x8632, 0xCC72, 0x8633, 0xCC73, 0x8634, 0xCC74, 0x8635, 0xCC75, 0x8636, 0xCC76, 0x8637, 0xCC77, 0x8638, 0xD5BA, 0x8639, 0xCC78, 0x863A, 0xCC79, 0x863B, 0xCC7A, 0x863C, 0xDEC2, 0x863D, 0xCC7B, 0x863E, 0xCC7C, 0x863F, 0xCC7D, 0x8640, 0xCC7E, 0x8641, 0xCC80, 0x8642, 0xCC81, 0x8643, 0xCC82, 0x8644, 0xCC83, 0x8645, 0xCC84, 0x8646, 0xCC85, 0x8647, 0xCC86, 0x8648, 0xCC87, 0x8649, 0xCC88, 0x864A, 0xCC89, 0x864B, 0xCC8A, 0x864C, 0xCC8B, 0x864D, 0xF2AE, 0x864E, 0xBBA2, 0x864F, 0xC2B2, 0x8650, 0xC5B0, 0x8651, 0xC2C7, 0x8652, 0xCC8C, 0x8653, 0xCC8D, 0x8654, 0xF2AF, 0x8655, 0xCC8E, 0x8656, 0xCC8F, 0x8657, 0xCC90, 0x8658, 0xCC91, 0x8659, 0xCC92, 0x865A, 0xD0E9, 0x865B, 0xCC93, 0x865C, 0xCC94, 0x865D, 0xCC95, 0x865E, 0xD3DD, 0x865F, 0xCC96, 0x8660, 0xCC97, 0x8661, 0xCC98, 0x8662, 0xEBBD, 0x8663, 0xCC99, 0x8664, 0xCC9A, 0x8665, 0xCC9B, 0x8666, 0xCC9C, 0x8667, 0xCC9D, 0x8668, 0xCC9E, 0x8669, 0xCC9F, 0x866A, 0xCCA0, 0x866B, 0xB3E6, 0x866C, 0xF2B0, 0x866D, 0xCD40, 0x866E, 0xF2B1, 0x866F, 0xCD41, 0x8670, 0xCD42, 0x8671, 0xCAAD, 0x8672, 0xCD43, 0x8673, 0xCD44, 0x8674, 0xCD45, 0x8675, 0xCD46, 0x8676, 0xCD47, 0x8677, 0xCD48, 0x8678, 0xCD49, 0x8679, 0xBAE7, 0x867A, 0xF2B3, 0x867B, 0xF2B5, 0x867C, 0xF2B4, 0x867D, 0xCBE4, 0x867E, 0xCFBA, 0x867F, 0xF2B2, 0x8680, 0xCAB4, 0x8681, 0xD2CF, 0x8682, 0xC2EC, 0x8683, 0xCD4A, 0x8684, 0xCD4B, 0x8685, 0xCD4C, 0x8686, 0xCD4D, 0x8687, 0xCD4E, 0x8688, 0xCD4F, 0x8689, 0xCD50, 0x868A, 0xCEC3, 0x868B, 0xF2B8, 0x868C, 0xB0F6, 0x868D, 0xF2B7, 0x868E, 0xCD51, 0x868F, 0xCD52, 0x8690, 0xCD53, 0x8691, 0xCD54, 0x8692, 0xCD55, 0x8693, 0xF2BE, 0x8694, 0xCD56, 0x8695, 0xB2CF, 0x8696, 0xCD57, 0x8697, 0xCD58, 0x8698, 0xCD59, 0x8699, 0xCD5A, 0x869A, 0xCD5B, 0x869B, 0xCD5C, 0x869C, 0xD1C1, 0x869D, 0xF2BA, 0x869E, 0xCD5D, 0x869F, 0xCD5E, 0x86A0, 0xCD5F, 0x86A1, 0xCD60, 0x86A2, 0xCD61, 0x86A3, 0xF2BC, 0x86A4, 0xD4E9, 0x86A5, 0xCD62, 0x86A6, 0xCD63, 0x86A7, 0xF2BB, 0x86A8, 0xF2B6, 0x86A9, 0xF2BF, 0x86AA, 0xF2BD, 0x86AB, 0xCD64, 0x86AC, 0xF2B9, 0x86AD, 0xCD65, 0x86AE, 0xCD66, 0x86AF, 0xF2C7, 0x86B0, 0xF2C4, 0x86B1, 0xF2C6, 0x86B2, 0xCD67, 0x86B3, 0xCD68, 0x86B4, 0xF2CA, 0x86B5, 0xF2C2, 0x86B6, 0xF2C0, 0x86B7, 0xCD69, 0x86B8, 0xCD6A, 0x86B9, 0xCD6B, 0x86BA, 0xF2C5, 0x86BB, 0xCD6C, 0x86BC, 0xCD6D, 0x86BD, 0xCD6E, 0x86BE, 0xCD6F, 0x86BF, 0xCD70, 0x86C0, 0xD6FB, 0x86C1, 0xCD71, 0x86C2, 0xCD72, 0x86C3, 0xCD73, 0x86C4, 0xF2C1, 0x86C5, 0xCD74, 0x86C6, 0xC7F9, 0x86C7, 0xC9DF, 0x86C8, 0xCD75, 0x86C9, 0xF2C8, 0x86CA, 0xB9C6, 0x86CB, 0xB5B0, 0x86CC, 0xCD76, 0x86CD, 0xCD77, 0x86CE, 0xF2C3, 0x86CF, 0xF2C9, 0x86D0, 0xF2D0, 0x86D1, 0xF2D6, 0x86D2, 0xCD78, 0x86D3, 0xCD79, 0x86D4, 0xBBD7, 0x86D5, 0xCD7A, 0x86D6, 0xCD7B, 0x86D7, 0xCD7C, 0x86D8, 0xF2D5, 0x86D9, 0xCDDC, 0x86DA, 0xCD7D, 0x86DB, 0xD6EB, 0x86DC, 0xCD7E, 0x86DD, 0xCD80, 0x86DE, 0xF2D2, 0x86DF, 0xF2D4, 0x86E0, 0xCD81, 0x86E1, 0xCD82, 0x86E2, 0xCD83, 0x86E3, 0xCD84, 0x86E4, 0xB8F2, 0x86E5, 0xCD85, 0x86E6, 0xCD86, 0x86E7, 0xCD87, 0x86E8, 0xCD88, 0x86E9, 0xF2CB, 0x86EA, 0xCD89, 0x86EB, 0xCD8A, 0x86EC, 0xCD8B, 0x86ED, 0xF2CE, 0x86EE, 0xC2F9, 0x86EF, 0xCD8C, 0x86F0, 0xD5DD, 0x86F1, 0xF2CC, 0x86F2, 0xF2CD, 0x86F3, 0xF2CF, 0x86F4, 0xF2D3, 0x86F5, 0xCD8D, 0x86F6, 0xCD8E, 0x86F7, 0xCD8F, 0x86F8, 0xF2D9, 0x86F9, 0xD3BC, 0x86FA, 0xCD90, 0x86FB, 0xCD91, 0x86FC, 0xCD92, 0x86FD, 0xCD93, 0x86FE, 0xB6EA, 0x86FF, 0xCD94, 0x8700, 0xCAF1, 0x8701, 0xCD95, 0x8702, 0xB7E4, 0x8703, 0xF2D7, 0x8704, 0xCD96, 0x8705, 0xCD97, 0x8706, 0xCD98, 0x8707, 0xF2D8, 0x8708, 0xF2DA, 0x8709, 0xF2DD, 0x870A, 0xF2DB, 0x870B, 0xCD99, 0x870C, 0xCD9A, 0x870D, 0xF2DC, 0x870E, 0xCD9B, 0x870F, 0xCD9C, 0x8710, 0xCD9D, 0x8711, 0xCD9E, 0x8712, 0xD1D1, 0x8713, 0xF2D1, 0x8714, 0xCD9F, 0x8715, 0xCDC9, 0x8716, 0xCDA0, 0x8717, 0xCECF, 0x8718, 0xD6A9, 0x8719, 0xCE40, 0x871A, 0xF2E3, 0x871B, 0xCE41, 0x871C, 0xC3DB, 0x871D, 0xCE42, 0x871E, 0xF2E0, 0x871F, 0xCE43, 0x8720, 0xCE44, 0x8721, 0xC0AF, 0x8722, 0xF2EC, 0x8723, 0xF2DE, 0x8724, 0xCE45, 0x8725, 0xF2E1, 0x8726, 0xCE46, 0x8727, 0xCE47, 0x8728, 0xCE48, 0x8729, 0xF2E8, 0x872A, 0xCE49, 0x872B, 0xCE4A, 0x872C, 0xCE4B, 0x872D, 0xCE4C, 0x872E, 0xF2E2, 0x872F, 0xCE4D, 0x8730, 0xCE4E, 0x8731, 0xF2E7, 0x8732, 0xCE4F, 0x8733, 0xCE50, 0x8734, 0xF2E6, 0x8735, 0xCE51, 0x8736, 0xCE52, 0x8737, 0xF2E9, 0x8738, 0xCE53, 0x8739, 0xCE54, 0x873A, 0xCE55, 0x873B, 0xF2DF, 0x873C, 0xCE56, 0x873D, 0xCE57, 0x873E, 0xF2E4, 0x873F, 0xF2EA, 0x8740, 0xCE58, 0x8741, 0xCE59, 0x8742, 0xCE5A, 0x8743, 0xCE5B, 0x8744, 0xCE5C, 0x8745, 0xCE5D, 0x8746, 0xCE5E, 0x8747, 0xD3AC, 0x8748, 0xF2E5, 0x8749, 0xB2F5, 0x874A, 0xCE5F, 0x874B, 0xCE60, 0x874C, 0xF2F2, 0x874D, 0xCE61, 0x874E, 0xD0AB, 0x874F, 0xCE62, 0x8750, 0xCE63, 0x8751, 0xCE64, 0x8752, 0xCE65, 0x8753, 0xF2F5, 0x8754, 0xCE66, 0x8755, 0xCE67, 0x8756, 0xCE68, 0x8757, 0xBBC8, 0x8758, 0xCE69, 0x8759, 0xF2F9, 0x875A, 0xCE6A, 0x875B, 0xCE6B, 0x875C, 0xCE6C, 0x875D, 0xCE6D, 0x875E, 0xCE6E, 0x875F, 0xCE6F, 0x8760, 0xF2F0, 0x8761, 0xCE70, 0x8762, 0xCE71, 0x8763, 0xF2F6, 0x8764, 0xF2F8, 0x8765, 0xF2FA, 0x8766, 0xCE72, 0x8767, 0xCE73, 0x8768, 0xCE74, 0x8769, 0xCE75, 0x876A, 0xCE76, 0x876B, 0xCE77, 0x876C, 0xCE78, 0x876D, 0xCE79, 0x876E, 0xF2F3, 0x876F, 0xCE7A, 0x8770, 0xF2F1, 0x8771, 0xCE7B, 0x8772, 0xCE7C, 0x8773, 0xCE7D, 0x8774, 0xBAFB, 0x8775, 0xCE7E, 0x8776, 0xB5FB, 0x8777, 0xCE80, 0x8778, 0xCE81, 0x8779, 0xCE82, 0x877A, 0xCE83, 0x877B, 0xF2EF, 0x877C, 0xF2F7, 0x877D, 0xF2ED, 0x877E, 0xF2EE, 0x877F, 0xCE84, 0x8780, 0xCE85, 0x8781, 0xCE86, 0x8782, 0xF2EB, 0x8783, 0xF3A6, 0x8784, 0xCE87, 0x8785, 0xF3A3, 0x8786, 0xCE88, 0x8787, 0xCE89, 0x8788, 0xF3A2, 0x8789, 0xCE8A, 0x878A, 0xCE8B, 0x878B, 0xF2F4, 0x878C, 0xCE8C, 0x878D, 0xC8DA, 0x878E, 0xCE8D, 0x878F, 0xCE8E, 0x8790, 0xCE8F, 0x8791, 0xCE90, 0x8792, 0xCE91, 0x8793, 0xF2FB, 0x8794, 0xCE92, 0x8795, 0xCE93, 0x8796, 0xCE94, 0x8797, 0xF3A5, 0x8798, 0xCE95, 0x8799, 0xCE96, 0x879A, 0xCE97, 0x879B, 0xCE98, 0x879C, 0xCE99, 0x879D, 0xCE9A, 0x879E, 0xCE9B, 0x879F, 0xC3F8, 0x87A0, 0xCE9C, 0x87A1, 0xCE9D, 0x87A2, 0xCE9E, 0x87A3, 0xCE9F, 0x87A4, 0xCEA0, 0x87A5, 0xCF40, 0x87A6, 0xCF41, 0x87A7, 0xCF42, 0x87A8, 0xF2FD, 0x87A9, 0xCF43, 0x87AA, 0xCF44, 0x87AB, 0xF3A7, 0x87AC, 0xF3A9, 0x87AD, 0xF3A4, 0x87AE, 0xCF45, 0x87AF, 0xF2FC, 0x87B0, 0xCF46, 0x87B1, 0xCF47, 0x87B2, 0xCF48, 0x87B3, 0xF3AB, 0x87B4, 0xCF49, 0x87B5, 0xF3AA, 0x87B6, 0xCF4A, 0x87B7, 0xCF4B, 0x87B8, 0xCF4C, 0x87B9, 0xCF4D, 0x87BA, 0xC2DD, 0x87BB, 0xCF4E, 0x87BC, 0xCF4F, 0x87BD, 0xF3AE, 0x87BE, 0xCF50, 0x87BF, 0xCF51, 0x87C0, 0xF3B0, 0x87C1, 0xCF52, 0x87C2, 0xCF53, 0x87C3, 0xCF54, 0x87C4, 0xCF55, 0x87C5, 0xCF56, 0x87C6, 0xF3A1, 0x87C7, 0xCF57, 0x87C8, 0xCF58, 0x87C9, 0xCF59, 0x87CA, 0xF3B1, 0x87CB, 0xF3AC, 0x87CC, 0xCF5A, 0x87CD, 0xCF5B, 0x87CE, 0xCF5C, 0x87CF, 0xCF5D, 0x87D0, 0xCF5E, 0x87D1, 0xF3AF, 0x87D2, 0xF2FE, 0x87D3, 0xF3AD, 0x87D4, 0xCF5F, 0x87D5, 0xCF60, 0x87D6, 0xCF61, 0x87D7, 0xCF62, 0x87D8, 0xCF63, 0x87D9, 0xCF64, 0x87DA, 0xCF65, 0x87DB, 0xF3B2, 0x87DC, 0xCF66, 0x87DD, 0xCF67, 0x87DE, 0xCF68, 0x87DF, 0xCF69, 0x87E0, 0xF3B4, 0x87E1, 0xCF6A, 0x87E2, 0xCF6B, 0x87E3, 0xCF6C, 0x87E4, 0xCF6D, 0x87E5, 0xF3A8, 0x87E6, 0xCF6E, 0x87E7, 0xCF6F, 0x87E8, 0xCF70, 0x87E9, 0xCF71, 0x87EA, 0xF3B3, 0x87EB, 0xCF72, 0x87EC, 0xCF73, 0x87ED, 0xCF74, 0x87EE, 0xF3B5, 0x87EF, 0xCF75, 0x87F0, 0xCF76, 0x87F1, 0xCF77, 0x87F2, 0xCF78, 0x87F3, 0xCF79, 0x87F4, 0xCF7A, 0x87F5, 0xCF7B, 0x87F6, 0xCF7C, 0x87F7, 0xCF7D, 0x87F8, 0xCF7E, 0x87F9, 0xD0B7, 0x87FA, 0xCF80, 0x87FB, 0xCF81, 0x87FC, 0xCF82, 0x87FD, 0xCF83, 0x87FE, 0xF3B8, 0x87FF, 0xCF84, 0x8800, 0xCF85, 0x8801, 0xCF86, 0x8802, 0xCF87, 0x8803, 0xD9F9, 0x8804, 0xCF88, 0x8805, 0xCF89, 0x8806, 0xCF8A, 0x8807, 0xCF8B, 0x8808, 0xCF8C, 0x8809, 0xCF8D, 0x880A, 0xF3B9, 0x880B, 0xCF8E, 0x880C, 0xCF8F, 0x880D, 0xCF90, 0x880E, 0xCF91, 0x880F, 0xCF92, 0x8810, 0xCF93, 0x8811, 0xCF94, 0x8812, 0xCF95, 0x8813, 0xF3B7, 0x8814, 0xCF96, 0x8815, 0xC8E4, 0x8816, 0xF3B6, 0x8817, 0xCF97, 0x8818, 0xCF98, 0x8819, 0xCF99, 0x881A, 0xCF9A, 0x881B, 0xF3BA, 0x881C, 0xCF9B, 0x881D, 0xCF9C, 0x881E, 0xCF9D, 0x881F, 0xCF9E, 0x8820, 0xCF9F, 0x8821, 0xF3BB, 0x8822, 0xB4C0, 0x8823, 0xCFA0, 0x8824, 0xD040, 0x8825, 0xD041, 0x8826, 0xD042, 0x8827, 0xD043, 0x8828, 0xD044, 0x8829, 0xD045, 0x882A, 0xD046, 0x882B, 0xD047, 0x882C, 0xD048, 0x882D, 0xD049, 0x882E, 0xD04A, 0x882F, 0xD04B, 0x8830, 0xD04C, 0x8831, 0xD04D, 0x8832, 0xEEC3, 0x8833, 0xD04E, 0x8834, 0xD04F, 0x8835, 0xD050, 0x8836, 0xD051, 0x8837, 0xD052, 0x8838, 0xD053, 0x8839, 0xF3BC, 0x883A, 0xD054, 0x883B, 0xD055, 0x883C, 0xF3BD, 0x883D, 0xD056, 0x883E, 0xD057, 0x883F, 0xD058, 0x8840, 0xD1AA, 0x8841, 0xD059, 0x8842, 0xD05A, 0x8843, 0xD05B, 0x8844, 0xF4AC, 0x8845, 0xD0C6, 0x8846, 0xD05C, 0x8847, 0xD05D, 0x8848, 0xD05E, 0x8849, 0xD05F, 0x884A, 0xD060, 0x884B, 0xD061, 0x884C, 0xD0D0, 0x884D, 0xD1DC, 0x884E, 0xD062, 0x884F, 0xD063, 0x8850, 0xD064, 0x8851, 0xD065, 0x8852, 0xD066, 0x8853, 0xD067, 0x8854, 0xCFCE, 0x8855, 0xD068, 0x8856, 0xD069, 0x8857, 0xBDD6, 0x8858, 0xD06A, 0x8859, 0xD1C3, 0x885A, 0xD06B, 0x885B, 0xD06C, 0x885C, 0xD06D, 0x885D, 0xD06E, 0x885E, 0xD06F, 0x885F, 0xD070, 0x8860, 0xD071, 0x8861, 0xBAE2, 0x8862, 0xE1E9, 0x8863, 0xD2C2, 0x8864, 0xF1C2, 0x8865, 0xB2B9, 0x8866, 0xD072, 0x8867, 0xD073, 0x8868, 0xB1ED, 0x8869, 0xF1C3, 0x886A, 0xD074, 0x886B, 0xC9C0, 0x886C, 0xB3C4, 0x886D, 0xD075, 0x886E, 0xD9F2, 0x886F, 0xD076, 0x8870, 0xCBA5, 0x8871, 0xD077, 0x8872, 0xF1C4, 0x8873, 0xD078, 0x8874, 0xD079, 0x8875, 0xD07A, 0x8876, 0xD07B, 0x8877, 0xD6D4, 0x8878, 0xD07C, 0x8879, 0xD07D, 0x887A, 0xD07E, 0x887B, 0xD080, 0x887C, 0xD081, 0x887D, 0xF1C5, 0x887E, 0xF4C0, 0x887F, 0xF1C6, 0x8880, 0xD082, 0x8881, 0xD4AC, 0x8882, 0xF1C7, 0x8883, 0xD083, 0x8884, 0xB0C0, 0x8885, 0xF4C1, 0x8886, 0xD084, 0x8887, 0xD085, 0x8888, 0xF4C2, 0x8889, 0xD086, 0x888A, 0xD087, 0x888B, 0xB4FC, 0x888C, 0xD088, 0x888D, 0xC5DB, 0x888E, 0xD089, 0x888F, 0xD08A, 0x8890, 0xD08B, 0x8891, 0xD08C, 0x8892, 0xCCBB, 0x8893, 0xD08D, 0x8894, 0xD08E, 0x8895, 0xD08F, 0x8896, 0xD0E4, 0x8897, 0xD090, 0x8898, 0xD091, 0x8899, 0xD092, 0x889A, 0xD093, 0x889B, 0xD094, 0x889C, 0xCDE0, 0x889D, 0xD095, 0x889E, 0xD096, 0x889F, 0xD097, 0x88A0, 0xD098, 0x88A1, 0xD099, 0x88A2, 0xF1C8, 0x88A3, 0xD09A, 0x88A4, 0xD9F3, 0x88A5, 0xD09B, 0x88A6, 0xD09C, 0x88A7, 0xD09D, 0x88A8, 0xD09E, 0x88A9, 0xD09F, 0x88AA, 0xD0A0, 0x88AB, 0xB1BB, 0x88AC, 0xD140, 0x88AD, 0xCFAE, 0x88AE, 0xD141, 0x88AF, 0xD142, 0x88B0, 0xD143, 0x88B1, 0xB8A4, 0x88B2, 0xD144, 0x88B3, 0xD145, 0x88B4, 0xD146, 0x88B5, 0xD147, 0x88B6, 0xD148, 0x88B7, 0xF1CA, 0x88B8, 0xD149, 0x88B9, 0xD14A, 0x88BA, 0xD14B, 0x88BB, 0xD14C, 0x88BC, 0xF1CB, 0x88BD, 0xD14D, 0x88BE, 0xD14E, 0x88BF, 0xD14F, 0x88C0, 0xD150, 0x88C1, 0xB2C3, 0x88C2, 0xC1D1, 0x88C3, 0xD151, 0x88C4, 0xD152, 0x88C5, 0xD7B0, 0x88C6, 0xF1C9, 0x88C7, 0xD153, 0x88C8, 0xD154, 0x88C9, 0xF1CC, 0x88CA, 0xD155, 0x88CB, 0xD156, 0x88CC, 0xD157, 0x88CD, 0xD158, 0x88CE, 0xF1CE, 0x88CF, 0xD159, 0x88D0, 0xD15A, 0x88D1, 0xD15B, 0x88D2, 0xD9F6, 0x88D3, 0xD15C, 0x88D4, 0xD2E1, 0x88D5, 0xD4A3, 0x88D6, 0xD15D, 0x88D7, 0xD15E, 0x88D8, 0xF4C3, 0x88D9, 0xC8B9, 0x88DA, 0xD15F, 0x88DB, 0xD160, 0x88DC, 0xD161, 0x88DD, 0xD162, 0x88DE, 0xD163, 0x88DF, 0xF4C4, 0x88E0, 0xD164, 0x88E1, 0xD165, 0x88E2, 0xF1CD, 0x88E3, 0xF1CF, 0x88E4, 0xBFE3, 0x88E5, 0xF1D0, 0x88E6, 0xD166, 0x88E7, 0xD167, 0x88E8, 0xF1D4, 0x88E9, 0xD168, 0x88EA, 0xD169, 0x88EB, 0xD16A, 0x88EC, 0xD16B, 0x88ED, 0xD16C, 0x88EE, 0xD16D, 0x88EF, 0xD16E, 0x88F0, 0xF1D6, 0x88F1, 0xF1D1, 0x88F2, 0xD16F, 0x88F3, 0xC9D1, 0x88F4, 0xC5E1, 0x88F5, 0xD170, 0x88F6, 0xD171, 0x88F7, 0xD172, 0x88F8, 0xC2E3, 0x88F9, 0xB9FC, 0x88FA, 0xD173, 0x88FB, 0xD174, 0x88FC, 0xF1D3, 0x88FD, 0xD175, 0x88FE, 0xF1D5, 0x88FF, 0xD176, 0x8900, 0xD177, 0x8901, 0xD178, 0x8902, 0xB9D3, 0x8903, 0xD179, 0x8904, 0xD17A, 0x8905, 0xD17B, 0x8906, 0xD17C, 0x8907, 0xD17D, 0x8908, 0xD17E, 0x8909, 0xD180, 0x890A, 0xF1DB, 0x890B, 0xD181, 0x890C, 0xD182, 0x890D, 0xD183, 0x890E, 0xD184, 0x890F, 0xD185, 0x8910, 0xBAD6, 0x8911, 0xD186, 0x8912, 0xB0FD, 0x8913, 0xF1D9, 0x8914, 0xD187, 0x8915, 0xD188, 0x8916, 0xD189, 0x8917, 0xD18A, 0x8918, 0xD18B, 0x8919, 0xF1D8, 0x891A, 0xF1D2, 0x891B, 0xF1DA, 0x891C, 0xD18C, 0x891D, 0xD18D, 0x891E, 0xD18E, 0x891F, 0xD18F, 0x8920, 0xD190, 0x8921, 0xF1D7, 0x8922, 0xD191, 0x8923, 0xD192, 0x8924, 0xD193, 0x8925, 0xC8EC, 0x8926, 0xD194, 0x8927, 0xD195, 0x8928, 0xD196, 0x8929, 0xD197, 0x892A, 0xCDCA, 0x892B, 0xF1DD, 0x892C, 0xD198, 0x892D, 0xD199, 0x892E, 0xD19A, 0x892F, 0xD19B, 0x8930, 0xE5BD, 0x8931, 0xD19C, 0x8932, 0xD19D, 0x8933, 0xD19E, 0x8934, 0xF1DC, 0x8935, 0xD19F, 0x8936, 0xF1DE, 0x8937, 0xD1A0, 0x8938, 0xD240, 0x8939, 0xD241, 0x893A, 0xD242, 0x893B, 0xD243, 0x893C, 0xD244, 0x893D, 0xD245, 0x893E, 0xD246, 0x893F, 0xD247, 0x8940, 0xD248, 0x8941, 0xF1DF, 0x8942, 0xD249, 0x8943, 0xD24A, 0x8944, 0xCFE5, 0x8945, 0xD24B, 0x8946, 0xD24C, 0x8947, 0xD24D, 0x8948, 0xD24E, 0x8949, 0xD24F, 0x894A, 0xD250, 0x894B, 0xD251, 0x894C, 0xD252, 0x894D, 0xD253, 0x894E, 0xD254, 0x894F, 0xD255, 0x8950, 0xD256, 0x8951, 0xD257, 0x8952, 0xD258, 0x8953, 0xD259, 0x8954, 0xD25A, 0x8955, 0xD25B, 0x8956, 0xD25C, 0x8957, 0xD25D, 0x8958, 0xD25E, 0x8959, 0xD25F, 0x895A, 0xD260, 0x895B, 0xD261, 0x895C, 0xD262, 0x895D, 0xD263, 0x895E, 0xF4C5, 0x895F, 0xBDF3, 0x8960, 0xD264, 0x8961, 0xD265, 0x8962, 0xD266, 0x8963, 0xD267, 0x8964, 0xD268, 0x8965, 0xD269, 0x8966, 0xF1E0, 0x8967, 0xD26A, 0x8968, 0xD26B, 0x8969, 0xD26C, 0x896A, 0xD26D, 0x896B, 0xD26E, 0x896C, 0xD26F, 0x896D, 0xD270, 0x896E, 0xD271, 0x896F, 0xD272, 0x8970, 0xD273, 0x8971, 0xD274, 0x8972, 0xD275, 0x8973, 0xD276, 0x8974, 0xD277, 0x8975, 0xD278, 0x8976, 0xD279, 0x8977, 0xD27A, 0x8978, 0xD27B, 0x8979, 0xD27C, 0x897A, 0xD27D, 0x897B, 0xF1E1, 0x897C, 0xD27E, 0x897D, 0xD280, 0x897E, 0xD281, 0x897F, 0xCEF7, 0x8980, 0xD282, 0x8981, 0xD2AA, 0x8982, 0xD283, 0x8983, 0xF1FB, 0x8984, 0xD284, 0x8985, 0xD285, 0x8986, 0xB8B2, 0x8987, 0xD286, 0x8988, 0xD287, 0x8989, 0xD288, 0x898A, 0xD289, 0x898B, 0xD28A, 0x898C, 0xD28B, 0x898D, 0xD28C, 0x898E, 0xD28D, 0x898F, 0xD28E, 0x8990, 0xD28F, 0x8991, 0xD290, 0x8992, 0xD291, 0x8993, 0xD292, 0x8994, 0xD293, 0x8995, 0xD294, 0x8996, 0xD295, 0x8997, 0xD296, 0x8998, 0xD297, 0x8999, 0xD298, 0x899A, 0xD299, 0x899B, 0xD29A, 0x899C, 0xD29B, 0x899D, 0xD29C, 0x899E, 0xD29D, 0x899F, 0xD29E, 0x89A0, 0xD29F, 0x89A1, 0xD2A0, 0x89A2, 0xD340, 0x89A3, 0xD341, 0x89A4, 0xD342, 0x89A5, 0xD343, 0x89A6, 0xD344, 0x89A7, 0xD345, 0x89A8, 0xD346, 0x89A9, 0xD347, 0x89AA, 0xD348, 0x89AB, 0xD349, 0x89AC, 0xD34A, 0x89AD, 0xD34B, 0x89AE, 0xD34C, 0x89AF, 0xD34D, 0x89B0, 0xD34E, 0x89B1, 0xD34F, 0x89B2, 0xD350, 0x89B3, 0xD351, 0x89B4, 0xD352, 0x89B5, 0xD353, 0x89B6, 0xD354, 0x89B7, 0xD355, 0x89B8, 0xD356, 0x89B9, 0xD357, 0x89BA, 0xD358, 0x89BB, 0xD359, 0x89BC, 0xD35A, 0x89BD, 0xD35B, 0x89BE, 0xD35C, 0x89BF, 0xD35D, 0x89C0, 0xD35E, 0x89C1, 0xBCFB, 0x89C2, 0xB9DB, 0x89C3, 0xD35F, 0x89C4, 0xB9E6, 0x89C5, 0xC3D9, 0x89C6, 0xCAD3, 0x89C7, 0xEAE8, 0x89C8, 0xC0C0, 0x89C9, 0xBEF5, 0x89CA, 0xEAE9, 0x89CB, 0xEAEA, 0x89CC, 0xEAEB, 0x89CD, 0xD360, 0x89CE, 0xEAEC, 0x89CF, 0xEAED, 0x89D0, 0xEAEE, 0x89D1, 0xEAEF, 0x89D2, 0xBDC7, 0x89D3, 0xD361, 0x89D4, 0xD362, 0x89D5, 0xD363, 0x89D6, 0xF5FB, 0x89D7, 0xD364, 0x89D8, 0xD365, 0x89D9, 0xD366, 0x89DA, 0xF5FD, 0x89DB, 0xD367, 0x89DC, 0xF5FE, 0x89DD, 0xD368, 0x89DE, 0xF5FC, 0x89DF, 0xD369, 0x89E0, 0xD36A, 0x89E1, 0xD36B, 0x89E2, 0xD36C, 0x89E3, 0xBDE2, 0x89E4, 0xD36D, 0x89E5, 0xF6A1, 0x89E6, 0xB4A5, 0x89E7, 0xD36E, 0x89E8, 0xD36F, 0x89E9, 0xD370, 0x89EA, 0xD371, 0x89EB, 0xF6A2, 0x89EC, 0xD372, 0x89ED, 0xD373, 0x89EE, 0xD374, 0x89EF, 0xF6A3, 0x89F0, 0xD375, 0x89F1, 0xD376, 0x89F2, 0xD377, 0x89F3, 0xECB2, 0x89F4, 0xD378, 0x89F5, 0xD379, 0x89F6, 0xD37A, 0x89F7, 0xD37B, 0x89F8, 0xD37C, 0x89F9, 0xD37D, 0x89FA, 0xD37E, 0x89FB, 0xD380, 0x89FC, 0xD381, 0x89FD, 0xD382, 0x89FE, 0xD383, 0x89FF, 0xD384, 0x8A00, 0xD1D4, 0x8A01, 0xD385, 0x8A02, 0xD386, 0x8A03, 0xD387, 0x8A04, 0xD388, 0x8A05, 0xD389, 0x8A06, 0xD38A, 0x8A07, 0xD9EA, 0x8A08, 0xD38B, 0x8A09, 0xD38C, 0x8A0A, 0xD38D, 0x8A0B, 0xD38E, 0x8A0C, 0xD38F, 0x8A0D, 0xD390, 0x8A0E, 0xD391, 0x8A0F, 0xD392, 0x8A10, 0xD393, 0x8A11, 0xD394, 0x8A12, 0xD395, 0x8A13, 0xD396, 0x8A14, 0xD397, 0x8A15, 0xD398, 0x8A16, 0xD399, 0x8A17, 0xD39A, 0x8A18, 0xD39B, 0x8A19, 0xD39C, 0x8A1A, 0xD39D, 0x8A1B, 0xD39E, 0x8A1C, 0xD39F, 0x8A1D, 0xD3A0, 0x8A1E, 0xD440, 0x8A1F, 0xD441, 0x8A20, 0xD442, 0x8A21, 0xD443, 0x8A22, 0xD444, 0x8A23, 0xD445, 0x8A24, 0xD446, 0x8A25, 0xD447, 0x8A26, 0xD448, 0x8A27, 0xD449, 0x8A28, 0xD44A, 0x8A29, 0xD44B, 0x8A2A, 0xD44C, 0x8A2B, 0xD44D, 0x8A2C, 0xD44E, 0x8A2D, 0xD44F, 0x8A2E, 0xD450, 0x8A2F, 0xD451, 0x8A30, 0xD452, 0x8A31, 0xD453, 0x8A32, 0xD454, 0x8A33, 0xD455, 0x8A34, 0xD456, 0x8A35, 0xD457, 0x8A36, 0xD458, 0x8A37, 0xD459, 0x8A38, 0xD45A, 0x8A39, 0xD45B, 0x8A3A, 0xD45C, 0x8A3B, 0xD45D, 0x8A3C, 0xD45E, 0x8A3D, 0xD45F, 0x8A3E, 0xF6A4, 0x8A3F, 0xD460, 0x8A40, 0xD461, 0x8A41, 0xD462, 0x8A42, 0xD463, 0x8A43, 0xD464, 0x8A44, 0xD465, 0x8A45, 0xD466, 0x8A46, 0xD467, 0x8A47, 0xD468, 0x8A48, 0xEEBA, 0x8A49, 0xD469, 0x8A4A, 0xD46A, 0x8A4B, 0xD46B, 0x8A4C, 0xD46C, 0x8A4D, 0xD46D, 0x8A4E, 0xD46E, 0x8A4F, 0xD46F, 0x8A50, 0xD470, 0x8A51, 0xD471, 0x8A52, 0xD472, 0x8A53, 0xD473, 0x8A54, 0xD474, 0x8A55, 0xD475, 0x8A56, 0xD476, 0x8A57, 0xD477, 0x8A58, 0xD478, 0x8A59, 0xD479, 0x8A5A, 0xD47A, 0x8A5B, 0xD47B, 0x8A5C, 0xD47C, 0x8A5D, 0xD47D, 0x8A5E, 0xD47E, 0x8A5F, 0xD480, 0x8A60, 0xD481, 0x8A61, 0xD482, 0x8A62, 0xD483, 0x8A63, 0xD484, 0x8A64, 0xD485, 0x8A65, 0xD486, 0x8A66, 0xD487, 0x8A67, 0xD488, 0x8A68, 0xD489, 0x8A69, 0xD48A, 0x8A6A, 0xD48B, 0x8A6B, 0xD48C, 0x8A6C, 0xD48D, 0x8A6D, 0xD48E, 0x8A6E, 0xD48F, 0x8A6F, 0xD490, 0x8A70, 0xD491, 0x8A71, 0xD492, 0x8A72, 0xD493, 0x8A73, 0xD494, 0x8A74, 0xD495, 0x8A75, 0xD496, 0x8A76, 0xD497, 0x8A77, 0xD498, 0x8A78, 0xD499, 0x8A79, 0xD5B2, 0x8A7A, 0xD49A, 0x8A7B, 0xD49B, 0x8A7C, 0xD49C, 0x8A7D, 0xD49D, 0x8A7E, 0xD49E, 0x8A7F, 0xD49F, 0x8A80, 0xD4A0, 0x8A81, 0xD540, 0x8A82, 0xD541, 0x8A83, 0xD542, 0x8A84, 0xD543, 0x8A85, 0xD544, 0x8A86, 0xD545, 0x8A87, 0xD546, 0x8A88, 0xD547, 0x8A89, 0xD3FE, 0x8A8A, 0xCCDC, 0x8A8B, 0xD548, 0x8A8C, 0xD549, 0x8A8D, 0xD54A, 0x8A8E, 0xD54B, 0x8A8F, 0xD54C, 0x8A90, 0xD54D, 0x8A91, 0xD54E, 0x8A92, 0xD54F, 0x8A93, 0xCAC4, 0x8A94, 0xD550, 0x8A95, 0xD551, 0x8A96, 0xD552, 0x8A97, 0xD553, 0x8A98, 0xD554, 0x8A99, 0xD555, 0x8A9A, 0xD556, 0x8A9B, 0xD557, 0x8A9C, 0xD558, 0x8A9D, 0xD559, 0x8A9E, 0xD55A, 0x8A9F, 0xD55B, 0x8AA0, 0xD55C, 0x8AA1, 0xD55D, 0x8AA2, 0xD55E, 0x8AA3, 0xD55F, 0x8AA4, 0xD560, 0x8AA5, 0xD561, 0x8AA6, 0xD562, 0x8AA7, 0xD563, 0x8AA8, 0xD564, 0x8AA9, 0xD565, 0x8AAA, 0xD566, 0x8AAB, 0xD567, 0x8AAC, 0xD568, 0x8AAD, 0xD569, 0x8AAE, 0xD56A, 0x8AAF, 0xD56B, 0x8AB0, 0xD56C, 0x8AB1, 0xD56D, 0x8AB2, 0xD56E, 0x8AB3, 0xD56F, 0x8AB4, 0xD570, 0x8AB5, 0xD571, 0x8AB6, 0xD572, 0x8AB7, 0xD573, 0x8AB8, 0xD574, 0x8AB9, 0xD575, 0x8ABA, 0xD576, 0x8ABB, 0xD577, 0x8ABC, 0xD578, 0x8ABD, 0xD579, 0x8ABE, 0xD57A, 0x8ABF, 0xD57B, 0x8AC0, 0xD57C, 0x8AC1, 0xD57D, 0x8AC2, 0xD57E, 0x8AC3, 0xD580, 0x8AC4, 0xD581, 0x8AC5, 0xD582, 0x8AC6, 0xD583, 0x8AC7, 0xD584, 0x8AC8, 0xD585, 0x8AC9, 0xD586, 0x8ACA, 0xD587, 0x8ACB, 0xD588, 0x8ACC, 0xD589, 0x8ACD, 0xD58A, 0x8ACE, 0xD58B, 0x8ACF, 0xD58C, 0x8AD0, 0xD58D, 0x8AD1, 0xD58E, 0x8AD2, 0xD58F, 0x8AD3, 0xD590, 0x8AD4, 0xD591, 0x8AD5, 0xD592, 0x8AD6, 0xD593, 0x8AD7, 0xD594, 0x8AD8, 0xD595, 0x8AD9, 0xD596, 0x8ADA, 0xD597, 0x8ADB, 0xD598, 0x8ADC, 0xD599, 0x8ADD, 0xD59A, 0x8ADE, 0xD59B, 0x8ADF, 0xD59C, 0x8AE0, 0xD59D, 0x8AE1, 0xD59E, 0x8AE2, 0xD59F, 0x8AE3, 0xD5A0, 0x8AE4, 0xD640, 0x8AE5, 0xD641, 0x8AE6, 0xD642, 0x8AE7, 0xD643, 0x8AE8, 0xD644, 0x8AE9, 0xD645, 0x8AEA, 0xD646, 0x8AEB, 0xD647, 0x8AEC, 0xD648, 0x8AED, 0xD649, 0x8AEE, 0xD64A, 0x8AEF, 0xD64B, 0x8AF0, 0xD64C, 0x8AF1, 0xD64D, 0x8AF2, 0xD64E, 0x8AF3, 0xD64F, 0x8AF4, 0xD650, 0x8AF5, 0xD651, 0x8AF6, 0xD652, 0x8AF7, 0xD653, 0x8AF8, 0xD654, 0x8AF9, 0xD655, 0x8AFA, 0xD656, 0x8AFB, 0xD657, 0x8AFC, 0xD658, 0x8AFD, 0xD659, 0x8AFE, 0xD65A, 0x8AFF, 0xD65B, 0x8B00, 0xD65C, 0x8B01, 0xD65D, 0x8B02, 0xD65E, 0x8B03, 0xD65F, 0x8B04, 0xD660, 0x8B05, 0xD661, 0x8B06, 0xD662, 0x8B07, 0xE5C0, 0x8B08, 0xD663, 0x8B09, 0xD664, 0x8B0A, 0xD665, 0x8B0B, 0xD666, 0x8B0C, 0xD667, 0x8B0D, 0xD668, 0x8B0E, 0xD669, 0x8B0F, 0xD66A, 0x8B10, 0xD66B, 0x8B11, 0xD66C, 0x8B12, 0xD66D, 0x8B13, 0xD66E, 0x8B14, 0xD66F, 0x8B15, 0xD670, 0x8B16, 0xD671, 0x8B17, 0xD672, 0x8B18, 0xD673, 0x8B19, 0xD674, 0x8B1A, 0xD675, 0x8B1B, 0xD676, 0x8B1C, 0xD677, 0x8B1D, 0xD678, 0x8B1E, 0xD679, 0x8B1F, 0xD67A, 0x8B20, 0xD67B, 0x8B21, 0xD67C, 0x8B22, 0xD67D, 0x8B23, 0xD67E, 0x8B24, 0xD680, 0x8B25, 0xD681, 0x8B26, 0xF6A5, 0x8B27, 0xD682, 0x8B28, 0xD683, 0x8B29, 0xD684, 0x8B2A, 0xD685, 0x8B2B, 0xD686, 0x8B2C, 0xD687, 0x8B2D, 0xD688, 0x8B2E, 0xD689, 0x8B2F, 0xD68A, 0x8B30, 0xD68B, 0x8B31, 0xD68C, 0x8B32, 0xD68D, 0x8B33, 0xD68E, 0x8B34, 0xD68F, 0x8B35, 0xD690, 0x8B36, 0xD691, 0x8B37, 0xD692, 0x8B38, 0xD693, 0x8B39, 0xD694, 0x8B3A, 0xD695, 0x8B3B, 0xD696, 0x8B3C, 0xD697, 0x8B3D, 0xD698, 0x8B3E, 0xD699, 0x8B3F, 0xD69A, 0x8B40, 0xD69B, 0x8B41, 0xD69C, 0x8B42, 0xD69D, 0x8B43, 0xD69E, 0x8B44, 0xD69F, 0x8B45, 0xD6A0, 0x8B46, 0xD740, 0x8B47, 0xD741, 0x8B48, 0xD742, 0x8B49, 0xD743, 0x8B4A, 0xD744, 0x8B4B, 0xD745, 0x8B4C, 0xD746, 0x8B4D, 0xD747, 0x8B4E, 0xD748, 0x8B4F, 0xD749, 0x8B50, 0xD74A, 0x8B51, 0xD74B, 0x8B52, 0xD74C, 0x8B53, 0xD74D, 0x8B54, 0xD74E, 0x8B55, 0xD74F, 0x8B56, 0xD750, 0x8B57, 0xD751, 0x8B58, 0xD752, 0x8B59, 0xD753, 0x8B5A, 0xD754, 0x8B5B, 0xD755, 0x8B5C, 0xD756, 0x8B5D, 0xD757, 0x8B5E, 0xD758, 0x8B5F, 0xD759, 0x8B60, 0xD75A, 0x8B61, 0xD75B, 0x8B62, 0xD75C, 0x8B63, 0xD75D, 0x8B64, 0xD75E, 0x8B65, 0xD75F, 0x8B66, 0xBEAF, 0x8B67, 0xD760, 0x8B68, 0xD761, 0x8B69, 0xD762, 0x8B6A, 0xD763, 0x8B6B, 0xD764, 0x8B6C, 0xC6A9, 0x8B6D, 0xD765, 0x8B6E, 0xD766, 0x8B6F, 0xD767, 0x8B70, 0xD768, 0x8B71, 0xD769, 0x8B72, 0xD76A, 0x8B73, 0xD76B, 0x8B74, 0xD76C, 0x8B75, 0xD76D, 0x8B76, 0xD76E, 0x8B77, 0xD76F, 0x8B78, 0xD770, 0x8B79, 0xD771, 0x8B7A, 0xD772, 0x8B7B, 0xD773, 0x8B7C, 0xD774, 0x8B7D, 0xD775, 0x8B7E, 0xD776, 0x8B7F, 0xD777, 0x8B80, 0xD778, 0x8B81, 0xD779, 0x8B82, 0xD77A, 0x8B83, 0xD77B, 0x8B84, 0xD77C, 0x8B85, 0xD77D, 0x8B86, 0xD77E, 0x8B87, 0xD780, 0x8B88, 0xD781, 0x8B89, 0xD782, 0x8B8A, 0xD783, 0x8B8B, 0xD784, 0x8B8C, 0xD785, 0x8B8D, 0xD786, 0x8B8E, 0xD787, 0x8B8F, 0xD788, 0x8B90, 0xD789, 0x8B91, 0xD78A, 0x8B92, 0xD78B, 0x8B93, 0xD78C, 0x8B94, 0xD78D, 0x8B95, 0xD78E, 0x8B96, 0xD78F, 0x8B97, 0xD790, 0x8B98, 0xD791, 0x8B99, 0xD792, 0x8B9A, 0xD793, 0x8B9B, 0xD794, 0x8B9C, 0xD795, 0x8B9D, 0xD796, 0x8B9E, 0xD797, 0x8B9F, 0xD798, 0x8BA0, 0xDAA5, 0x8BA1, 0xBCC6, 0x8BA2, 0xB6A9, 0x8BA3, 0xB8BC, 0x8BA4, 0xC8CF, 0x8BA5, 0xBCA5, 0x8BA6, 0xDAA6, 0x8BA7, 0xDAA7, 0x8BA8, 0xCCD6, 0x8BA9, 0xC8C3, 0x8BAA, 0xDAA8, 0x8BAB, 0xC6FD, 0x8BAC, 0xD799, 0x8BAD, 0xD1B5, 0x8BAE, 0xD2E9, 0x8BAF, 0xD1B6, 0x8BB0, 0xBCC7, 0x8BB1, 0xD79A, 0x8BB2, 0xBDB2, 0x8BB3, 0xBBE4, 0x8BB4, 0xDAA9, 0x8BB5, 0xDAAA, 0x8BB6, 0xD1C8, 0x8BB7, 0xDAAB, 0x8BB8, 0xD0ED, 0x8BB9, 0xB6EF, 0x8BBA, 0xC2DB, 0x8BBB, 0xD79B, 0x8BBC, 0xCBCF, 0x8BBD, 0xB7ED, 0x8BBE, 0xC9E8, 0x8BBF, 0xB7C3, 0x8BC0, 0xBEF7, 0x8BC1, 0xD6A4, 0x8BC2, 0xDAAC, 0x8BC3, 0xDAAD, 0x8BC4, 0xC6C0, 0x8BC5, 0xD7E7, 0x8BC6, 0xCAB6, 0x8BC7, 0xD79C, 0x8BC8, 0xD5A9, 0x8BC9, 0xCBDF, 0x8BCA, 0xD5EF, 0x8BCB, 0xDAAE, 0x8BCC, 0xD6DF, 0x8BCD, 0xB4CA, 0x8BCE, 0xDAB0, 0x8BCF, 0xDAAF, 0x8BD0, 0xD79D, 0x8BD1, 0xD2EB, 0x8BD2, 0xDAB1, 0x8BD3, 0xDAB2, 0x8BD4, 0xDAB3, 0x8BD5, 0xCAD4, 0x8BD6, 0xDAB4, 0x8BD7, 0xCAAB, 0x8BD8, 0xDAB5, 0x8BD9, 0xDAB6, 0x8BDA, 0xB3CF, 0x8BDB, 0xD6EF, 0x8BDC, 0xDAB7, 0x8BDD, 0xBBB0, 0x8BDE, 0xB5AE, 0x8BDF, 0xDAB8, 0x8BE0, 0xDAB9, 0x8BE1, 0xB9EE, 0x8BE2, 0xD1AF, 0x8BE3, 0xD2E8, 0x8BE4, 0xDABA, 0x8BE5, 0xB8C3, 0x8BE6, 0xCFEA, 0x8BE7, 0xB2EF, 0x8BE8, 0xDABB, 0x8BE9, 0xDABC, 0x8BEA, 0xD79E, 0x8BEB, 0xBDEB, 0x8BEC, 0xCEDC, 0x8BED, 0xD3EF, 0x8BEE, 0xDABD, 0x8BEF, 0xCEF3, 0x8BF0, 0xDABE, 0x8BF1, 0xD3D5, 0x8BF2, 0xBBE5, 0x8BF3, 0xDABF, 0x8BF4, 0xCBB5, 0x8BF5, 0xCBD0, 0x8BF6, 0xDAC0, 0x8BF7, 0xC7EB, 0x8BF8, 0xD6EE, 0x8BF9, 0xDAC1, 0x8BFA, 0xC5B5, 0x8BFB, 0xB6C1, 0x8BFC, 0xDAC2, 0x8BFD, 0xB7CC, 0x8BFE, 0xBFCE, 0x8BFF, 0xDAC3, 0x8C00, 0xDAC4, 0x8C01, 0xCBAD, 0x8C02, 0xDAC5, 0x8C03, 0xB5F7, 0x8C04, 0xDAC6, 0x8C05, 0xC1C2, 0x8C06, 0xD7BB, 0x8C07, 0xDAC7, 0x8C08, 0xCCB8, 0x8C09, 0xD79F, 0x8C0A, 0xD2EA, 0x8C0B, 0xC4B1, 0x8C0C, 0xDAC8, 0x8C0D, 0xB5FD, 0x8C0E, 0xBBD1, 0x8C0F, 0xDAC9, 0x8C10, 0xD0B3, 0x8C11, 0xDACA, 0x8C12, 0xDACB, 0x8C13, 0xCEBD, 0x8C14, 0xDACC, 0x8C15, 0xDACD, 0x8C16, 0xDACE, 0x8C17, 0xB2F7, 0x8C18, 0xDAD1, 0x8C19, 0xDACF, 0x8C1A, 0xD1E8, 0x8C1B, 0xDAD0, 0x8C1C, 0xC3D5, 0x8C1D, 0xDAD2, 0x8C1E, 0xD7A0, 0x8C1F, 0xDAD3, 0x8C20, 0xDAD4, 0x8C21, 0xDAD5, 0x8C22, 0xD0BB, 0x8C23, 0xD2A5, 0x8C24, 0xB0F9, 0x8C25, 0xDAD6, 0x8C26, 0xC7AB, 0x8C27, 0xDAD7, 0x8C28, 0xBDF7, 0x8C29, 0xC3A1, 0x8C2A, 0xDAD8, 0x8C2B, 0xDAD9, 0x8C2C, 0xC3FD, 0x8C2D, 0xCCB7, 0x8C2E, 0xDADA, 0x8C2F, 0xDADB, 0x8C30, 0xC0BE, 0x8C31, 0xC6D7, 0x8C32, 0xDADC, 0x8C33, 0xDADD, 0x8C34, 0xC7B4, 0x8C35, 0xDADE, 0x8C36, 0xDADF, 0x8C37, 0xB9C8, 0x8C38, 0xD840, 0x8C39, 0xD841, 0x8C3A, 0xD842, 0x8C3B, 0xD843, 0x8C3C, 0xD844, 0x8C3D, 0xD845, 0x8C3E, 0xD846, 0x8C3F, 0xD847, 0x8C40, 0xD848, 0x8C41, 0xBBED, 0x8C42, 0xD849, 0x8C43, 0xD84A, 0x8C44, 0xD84B, 0x8C45, 0xD84C, 0x8C46, 0xB6B9, 0x8C47, 0xF4F8, 0x8C48, 0xD84D, 0x8C49, 0xF4F9, 0x8C4A, 0xD84E, 0x8C4B, 0xD84F, 0x8C4C, 0xCDE3, 0x8C4D, 0xD850, 0x8C4E, 0xD851, 0x8C4F, 0xD852, 0x8C50, 0xD853, 0x8C51, 0xD854, 0x8C52, 0xD855, 0x8C53, 0xD856, 0x8C54, 0xD857, 0x8C55, 0xF5B9, 0x8C56, 0xD858, 0x8C57, 0xD859, 0x8C58, 0xD85A, 0x8C59, 0xD85B, 0x8C5A, 0xEBE0, 0x8C5B, 0xD85C, 0x8C5C, 0xD85D, 0x8C5D, 0xD85E, 0x8C5E, 0xD85F, 0x8C5F, 0xD860, 0x8C60, 0xD861, 0x8C61, 0xCFF3, 0x8C62, 0xBBBF, 0x8C63, 0xD862, 0x8C64, 0xD863, 0x8C65, 0xD864, 0x8C66, 0xD865, 0x8C67, 0xD866, 0x8C68, 0xD867, 0x8C69, 0xD868, 0x8C6A, 0xBAC0, 0x8C6B, 0xD4A5, 0x8C6C, 0xD869, 0x8C6D, 0xD86A, 0x8C6E, 0xD86B, 0x8C6F, 0xD86C, 0x8C70, 0xD86D, 0x8C71, 0xD86E, 0x8C72, 0xD86F, 0x8C73, 0xE1D9, 0x8C74, 0xD870, 0x8C75, 0xD871, 0x8C76, 0xD872, 0x8C77, 0xD873, 0x8C78, 0xF5F4, 0x8C79, 0xB1AA, 0x8C7A, 0xB2F2, 0x8C7B, 0xD874, 0x8C7C, 0xD875, 0x8C7D, 0xD876, 0x8C7E, 0xD877, 0x8C7F, 0xD878, 0x8C80, 0xD879, 0x8C81, 0xD87A, 0x8C82, 0xF5F5, 0x8C83, 0xD87B, 0x8C84, 0xD87C, 0x8C85, 0xF5F7, 0x8C86, 0xD87D, 0x8C87, 0xD87E, 0x8C88, 0xD880, 0x8C89, 0xBAD1, 0x8C8A, 0xF5F6, 0x8C8B, 0xD881, 0x8C8C, 0xC3B2, 0x8C8D, 0xD882, 0x8C8E, 0xD883, 0x8C8F, 0xD884, 0x8C90, 0xD885, 0x8C91, 0xD886, 0x8C92, 0xD887, 0x8C93, 0xD888, 0x8C94, 0xF5F9, 0x8C95, 0xD889, 0x8C96, 0xD88A, 0x8C97, 0xD88B, 0x8C98, 0xF5F8, 0x8C99, 0xD88C, 0x8C9A, 0xD88D, 0x8C9B, 0xD88E, 0x8C9C, 0xD88F, 0x8C9D, 0xD890, 0x8C9E, 0xD891, 0x8C9F, 0xD892, 0x8CA0, 0xD893, 0x8CA1, 0xD894, 0x8CA2, 0xD895, 0x8CA3, 0xD896, 0x8CA4, 0xD897, 0x8CA5, 0xD898, 0x8CA6, 0xD899, 0x8CA7, 0xD89A, 0x8CA8, 0xD89B, 0x8CA9, 0xD89C, 0x8CAA, 0xD89D, 0x8CAB, 0xD89E, 0x8CAC, 0xD89F, 0x8CAD, 0xD8A0, 0x8CAE, 0xD940, 0x8CAF, 0xD941, 0x8CB0, 0xD942, 0x8CB1, 0xD943, 0x8CB2, 0xD944, 0x8CB3, 0xD945, 0x8CB4, 0xD946, 0x8CB5, 0xD947, 0x8CB6, 0xD948, 0x8CB7, 0xD949, 0x8CB8, 0xD94A, 0x8CB9, 0xD94B, 0x8CBA, 0xD94C, 0x8CBB, 0xD94D, 0x8CBC, 0xD94E, 0x8CBD, 0xD94F, 0x8CBE, 0xD950, 0x8CBF, 0xD951, 0x8CC0, 0xD952, 0x8CC1, 0xD953, 0x8CC2, 0xD954, 0x8CC3, 0xD955, 0x8CC4, 0xD956, 0x8CC5, 0xD957, 0x8CC6, 0xD958, 0x8CC7, 0xD959, 0x8CC8, 0xD95A, 0x8CC9, 0xD95B, 0x8CCA, 0xD95C, 0x8CCB, 0xD95D, 0x8CCC, 0xD95E, 0x8CCD, 0xD95F, 0x8CCE, 0xD960, 0x8CCF, 0xD961, 0x8CD0, 0xD962, 0x8CD1, 0xD963, 0x8CD2, 0xD964, 0x8CD3, 0xD965, 0x8CD4, 0xD966, 0x8CD5, 0xD967, 0x8CD6, 0xD968, 0x8CD7, 0xD969, 0x8CD8, 0xD96A, 0x8CD9, 0xD96B, 0x8CDA, 0xD96C, 0x8CDB, 0xD96D, 0x8CDC, 0xD96E, 0x8CDD, 0xD96F, 0x8CDE, 0xD970, 0x8CDF, 0xD971, 0x8CE0, 0xD972, 0x8CE1, 0xD973, 0x8CE2, 0xD974, 0x8CE3, 0xD975, 0x8CE4, 0xD976, 0x8CE5, 0xD977, 0x8CE6, 0xD978, 0x8CE7, 0xD979, 0x8CE8, 0xD97A, 0x8CE9, 0xD97B, 0x8CEA, 0xD97C, 0x8CEB, 0xD97D, 0x8CEC, 0xD97E, 0x8CED, 0xD980, 0x8CEE, 0xD981, 0x8CEF, 0xD982, 0x8CF0, 0xD983, 0x8CF1, 0xD984, 0x8CF2, 0xD985, 0x8CF3, 0xD986, 0x8CF4, 0xD987, 0x8CF5, 0xD988, 0x8CF6, 0xD989, 0x8CF7, 0xD98A, 0x8CF8, 0xD98B, 0x8CF9, 0xD98C, 0x8CFA, 0xD98D, 0x8CFB, 0xD98E, 0x8CFC, 0xD98F, 0x8CFD, 0xD990, 0x8CFE, 0xD991, 0x8CFF, 0xD992, 0x8D00, 0xD993, 0x8D01, 0xD994, 0x8D02, 0xD995, 0x8D03, 0xD996, 0x8D04, 0xD997, 0x8D05, 0xD998, 0x8D06, 0xD999, 0x8D07, 0xD99A, 0x8D08, 0xD99B, 0x8D09, 0xD99C, 0x8D0A, 0xD99D, 0x8D0B, 0xD99E, 0x8D0C, 0xD99F, 0x8D0D, 0xD9A0, 0x8D0E, 0xDA40, 0x8D0F, 0xDA41, 0x8D10, 0xDA42, 0x8D11, 0xDA43, 0x8D12, 0xDA44, 0x8D13, 0xDA45, 0x8D14, 0xDA46, 0x8D15, 0xDA47, 0x8D16, 0xDA48, 0x8D17, 0xDA49, 0x8D18, 0xDA4A, 0x8D19, 0xDA4B, 0x8D1A, 0xDA4C, 0x8D1B, 0xDA4D, 0x8D1C, 0xDA4E, 0x8D1D, 0xB1B4, 0x8D1E, 0xD5EA, 0x8D1F, 0xB8BA, 0x8D20, 0xDA4F, 0x8D21, 0xB9B1, 0x8D22, 0xB2C6, 0x8D23, 0xD4F0, 0x8D24, 0xCFCD, 0x8D25, 0xB0DC, 0x8D26, 0xD5CB, 0x8D27, 0xBBF5, 0x8D28, 0xD6CA, 0x8D29, 0xB7B7, 0x8D2A, 0xCCB0, 0x8D2B, 0xC6B6, 0x8D2C, 0xB1E1, 0x8D2D, 0xB9BA, 0x8D2E, 0xD6FC, 0x8D2F, 0xB9E1, 0x8D30, 0xB7A1, 0x8D31, 0xBCFA, 0x8D32, 0xEADA, 0x8D33, 0xEADB, 0x8D34, 0xCCF9, 0x8D35, 0xB9F3, 0x8D36, 0xEADC, 0x8D37, 0xB4FB, 0x8D38, 0xC3B3, 0x8D39, 0xB7D1, 0x8D3A, 0xBAD8, 0x8D3B, 0xEADD, 0x8D3C, 0xD4F4, 0x8D3D, 0xEADE, 0x8D3E, 0xBCD6, 0x8D3F, 0xBBDF, 0x8D40, 0xEADF, 0x8D41, 0xC1DE, 0x8D42, 0xC2B8, 0x8D43, 0xD4DF, 0x8D44, 0xD7CA, 0x8D45, 0xEAE0, 0x8D46, 0xEAE1, 0x8D47, 0xEAE4, 0x8D48, 0xEAE2, 0x8D49, 0xEAE3, 0x8D4A, 0xC9DE, 0x8D4B, 0xB8B3, 0x8D4C, 0xB6C4, 0x8D4D, 0xEAE5, 0x8D4E, 0xCAEA, 0x8D4F, 0xC9CD, 0x8D50, 0xB4CD, 0x8D51, 0xDA50, 0x8D52, 0xDA51, 0x8D53, 0xE2D9, 0x8D54, 0xC5E2, 0x8D55, 0xEAE6, 0x8D56, 0xC0B5, 0x8D57, 0xDA52, 0x8D58, 0xD7B8, 0x8D59, 0xEAE7, 0x8D5A, 0xD7AC, 0x8D5B, 0xC8FC, 0x8D5C, 0xD8D3, 0x8D5D, 0xD8CD, 0x8D5E, 0xD4DE, 0x8D5F, 0xDA53, 0x8D60, 0xD4F9, 0x8D61, 0xC9C4, 0x8D62, 0xD3AE, 0x8D63, 0xB8D3, 0x8D64, 0xB3E0, 0x8D65, 0xDA54, 0x8D66, 0xC9E2, 0x8D67, 0xF4F6, 0x8D68, 0xDA55, 0x8D69, 0xDA56, 0x8D6A, 0xDA57, 0x8D6B, 0xBAD5, 0x8D6C, 0xDA58, 0x8D6D, 0xF4F7, 0x8D6E, 0xDA59, 0x8D6F, 0xDA5A, 0x8D70, 0xD7DF, 0x8D71, 0xDA5B, 0x8D72, 0xDA5C, 0x8D73, 0xF4F1, 0x8D74, 0xB8B0, 0x8D75, 0xD5D4, 0x8D76, 0xB8CF, 0x8D77, 0xC6F0, 0x8D78, 0xDA5D, 0x8D79, 0xDA5E, 0x8D7A, 0xDA5F, 0x8D7B, 0xDA60, 0x8D7C, 0xDA61, 0x8D7D, 0xDA62, 0x8D7E, 0xDA63, 0x8D7F, 0xDA64, 0x8D80, 0xDA65, 0x8D81, 0xB3C3, 0x8D82, 0xDA66, 0x8D83, 0xDA67, 0x8D84, 0xF4F2, 0x8D85, 0xB3AC, 0x8D86, 0xDA68, 0x8D87, 0xDA69, 0x8D88, 0xDA6A, 0x8D89, 0xDA6B, 0x8D8A, 0xD4BD, 0x8D8B, 0xC7F7, 0x8D8C, 0xDA6C, 0x8D8D, 0xDA6D, 0x8D8E, 0xDA6E, 0x8D8F, 0xDA6F, 0x8D90, 0xDA70, 0x8D91, 0xF4F4, 0x8D92, 0xDA71, 0x8D93, 0xDA72, 0x8D94, 0xF4F3, 0x8D95, 0xDA73, 0x8D96, 0xDA74, 0x8D97, 0xDA75, 0x8D98, 0xDA76, 0x8D99, 0xDA77, 0x8D9A, 0xDA78, 0x8D9B, 0xDA79, 0x8D9C, 0xDA7A, 0x8D9D, 0xDA7B, 0x8D9E, 0xDA7C, 0x8D9F, 0xCCCB, 0x8DA0, 0xDA7D, 0x8DA1, 0xDA7E, 0x8DA2, 0xDA80, 0x8DA3, 0xC8A4, 0x8DA4, 0xDA81, 0x8DA5, 0xDA82, 0x8DA6, 0xDA83, 0x8DA7, 0xDA84, 0x8DA8, 0xDA85, 0x8DA9, 0xDA86, 0x8DAA, 0xDA87, 0x8DAB, 0xDA88, 0x8DAC, 0xDA89, 0x8DAD, 0xDA8A, 0x8DAE, 0xDA8B, 0x8DAF, 0xDA8C, 0x8DB0, 0xDA8D, 0x8DB1, 0xF4F5, 0x8DB2, 0xDA8E, 0x8DB3, 0xD7E3, 0x8DB4, 0xC5BF, 0x8DB5, 0xF5C0, 0x8DB6, 0xDA8F, 0x8DB7, 0xDA90, 0x8DB8, 0xF5BB, 0x8DB9, 0xDA91, 0x8DBA, 0xF5C3, 0x8DBB, 0xDA92, 0x8DBC, 0xF5C2, 0x8DBD, 0xDA93, 0x8DBE, 0xD6BA, 0x8DBF, 0xF5C1, 0x8DC0, 0xDA94, 0x8DC1, 0xDA95, 0x8DC2, 0xDA96, 0x8DC3, 0xD4BE, 0x8DC4, 0xF5C4, 0x8DC5, 0xDA97, 0x8DC6, 0xF5CC, 0x8DC7, 0xDA98, 0x8DC8, 0xDA99, 0x8DC9, 0xDA9A, 0x8DCA, 0xDA9B, 0x8DCB, 0xB0CF, 0x8DCC, 0xB5F8, 0x8DCD, 0xDA9C, 0x8DCE, 0xF5C9, 0x8DCF, 0xF5CA, 0x8DD0, 0xDA9D, 0x8DD1, 0xC5DC, 0x8DD2, 0xDA9E, 0x8DD3, 0xDA9F, 0x8DD4, 0xDAA0, 0x8DD5, 0xDB40, 0x8DD6, 0xF5C5, 0x8DD7, 0xF5C6, 0x8DD8, 0xDB41, 0x8DD9, 0xDB42, 0x8DDA, 0xF5C7, 0x8DDB, 0xF5CB, 0x8DDC, 0xDB43, 0x8DDD, 0xBEE0, 0x8DDE, 0xF5C8, 0x8DDF, 0xB8FA, 0x8DE0, 0xDB44, 0x8DE1, 0xDB45, 0x8DE2, 0xDB46, 0x8DE3, 0xF5D0, 0x8DE4, 0xF5D3, 0x8DE5, 0xDB47, 0x8DE6, 0xDB48, 0x8DE7, 0xDB49, 0x8DE8, 0xBFE7, 0x8DE9, 0xDB4A, 0x8DEA, 0xB9F2, 0x8DEB, 0xF5BC, 0x8DEC, 0xF5CD, 0x8DED, 0xDB4B, 0x8DEE, 0xDB4C, 0x8DEF, 0xC2B7, 0x8DF0, 0xDB4D, 0x8DF1, 0xDB4E, 0x8DF2, 0xDB4F, 0x8DF3, 0xCCF8, 0x8DF4, 0xDB50, 0x8DF5, 0xBCF9, 0x8DF6, 0xDB51, 0x8DF7, 0xF5CE, 0x8DF8, 0xF5CF, 0x8DF9, 0xF5D1, 0x8DFA, 0xB6E5, 0x8DFB, 0xF5D2, 0x8DFC, 0xDB52, 0x8DFD, 0xF5D5, 0x8DFE, 0xDB53, 0x8DFF, 0xDB54, 0x8E00, 0xDB55, 0x8E01, 0xDB56, 0x8E02, 0xDB57, 0x8E03, 0xDB58, 0x8E04, 0xDB59, 0x8E05, 0xF5BD, 0x8E06, 0xDB5A, 0x8E07, 0xDB5B, 0x8E08, 0xDB5C, 0x8E09, 0xF5D4, 0x8E0A, 0xD3BB, 0x8E0B, 0xDB5D, 0x8E0C, 0xB3EC, 0x8E0D, 0xDB5E, 0x8E0E, 0xDB5F, 0x8E0F, 0xCCA4, 0x8E10, 0xDB60, 0x8E11, 0xDB61, 0x8E12, 0xDB62, 0x8E13, 0xDB63, 0x8E14, 0xF5D6, 0x8E15, 0xDB64, 0x8E16, 0xDB65, 0x8E17, 0xDB66, 0x8E18, 0xDB67, 0x8E19, 0xDB68, 0x8E1A, 0xDB69, 0x8E1B, 0xDB6A, 0x8E1C, 0xDB6B, 0x8E1D, 0xF5D7, 0x8E1E, 0xBEE1, 0x8E1F, 0xF5D8, 0x8E20, 0xDB6C, 0x8E21, 0xDB6D, 0x8E22, 0xCCDF, 0x8E23, 0xF5DB, 0x8E24, 0xDB6E, 0x8E25, 0xDB6F, 0x8E26, 0xDB70, 0x8E27, 0xDB71, 0x8E28, 0xDB72, 0x8E29, 0xB2C8, 0x8E2A, 0xD7D9, 0x8E2B, 0xDB73, 0x8E2C, 0xF5D9, 0x8E2D, 0xDB74, 0x8E2E, 0xF5DA, 0x8E2F, 0xF5DC, 0x8E30, 0xDB75, 0x8E31, 0xF5E2, 0x8E32, 0xDB76, 0x8E33, 0xDB77, 0x8E34, 0xDB78, 0x8E35, 0xF5E0, 0x8E36, 0xDB79, 0x8E37, 0xDB7A, 0x8E38, 0xDB7B, 0x8E39, 0xF5DF, 0x8E3A, 0xF5DD, 0x8E3B, 0xDB7C, 0x8E3C, 0xDB7D, 0x8E3D, 0xF5E1, 0x8E3E, 0xDB7E, 0x8E3F, 0xDB80, 0x8E40, 0xF5DE, 0x8E41, 0xF5E4, 0x8E42, 0xF5E5, 0x8E43, 0xDB81, 0x8E44, 0xCCE3, 0x8E45, 0xDB82, 0x8E46, 0xDB83, 0x8E47, 0xE5BF, 0x8E48, 0xB5B8, 0x8E49, 0xF5E3, 0x8E4A, 0xF5E8, 0x8E4B, 0xCCA3, 0x8E4C, 0xDB84, 0x8E4D, 0xDB85, 0x8E4E, 0xDB86, 0x8E4F, 0xDB87, 0x8E50, 0xDB88, 0x8E51, 0xF5E6, 0x8E52, 0xF5E7, 0x8E53, 0xDB89, 0x8E54, 0xDB8A, 0x8E55, 0xDB8B, 0x8E56, 0xDB8C, 0x8E57, 0xDB8D, 0x8E58, 0xDB8E, 0x8E59, 0xF5BE, 0x8E5A, 0xDB8F, 0x8E5B, 0xDB90, 0x8E5C, 0xDB91, 0x8E5D, 0xDB92, 0x8E5E, 0xDB93, 0x8E5F, 0xDB94, 0x8E60, 0xDB95, 0x8E61, 0xDB96, 0x8E62, 0xDB97, 0x8E63, 0xDB98, 0x8E64, 0xDB99, 0x8E65, 0xDB9A, 0x8E66, 0xB1C4, 0x8E67, 0xDB9B, 0x8E68, 0xDB9C, 0x8E69, 0xF5BF, 0x8E6A, 0xDB9D, 0x8E6B, 0xDB9E, 0x8E6C, 0xB5C5, 0x8E6D, 0xB2E4, 0x8E6E, 0xDB9F, 0x8E6F, 0xF5EC, 0x8E70, 0xF5E9, 0x8E71, 0xDBA0, 0x8E72, 0xB6D7, 0x8E73, 0xDC40, 0x8E74, 0xF5ED, 0x8E75, 0xDC41, 0x8E76, 0xF5EA, 0x8E77, 0xDC42, 0x8E78, 0xDC43, 0x8E79, 0xDC44, 0x8E7A, 0xDC45, 0x8E7B, 0xDC46, 0x8E7C, 0xF5EB, 0x8E7D, 0xDC47, 0x8E7E, 0xDC48, 0x8E7F, 0xB4DA, 0x8E80, 0xDC49, 0x8E81, 0xD4EA, 0x8E82, 0xDC4A, 0x8E83, 0xDC4B, 0x8E84, 0xDC4C, 0x8E85, 0xF5EE, 0x8E86, 0xDC4D, 0x8E87, 0xB3F9, 0x8E88, 0xDC4E, 0x8E89, 0xDC4F, 0x8E8A, 0xDC50, 0x8E8B, 0xDC51, 0x8E8C, 0xDC52, 0x8E8D, 0xDC53, 0x8E8E, 0xDC54, 0x8E8F, 0xF5EF, 0x8E90, 0xF5F1, 0x8E91, 0xDC55, 0x8E92, 0xDC56, 0x8E93, 0xDC57, 0x8E94, 0xF5F0, 0x8E95, 0xDC58, 0x8E96, 0xDC59, 0x8E97, 0xDC5A, 0x8E98, 0xDC5B, 0x8E99, 0xDC5C, 0x8E9A, 0xDC5D, 0x8E9B, 0xDC5E, 0x8E9C, 0xF5F2, 0x8E9D, 0xDC5F, 0x8E9E, 0xF5F3, 0x8E9F, 0xDC60, 0x8EA0, 0xDC61, 0x8EA1, 0xDC62, 0x8EA2, 0xDC63, 0x8EA3, 0xDC64, 0x8EA4, 0xDC65, 0x8EA5, 0xDC66, 0x8EA6, 0xDC67, 0x8EA7, 0xDC68, 0x8EA8, 0xDC69, 0x8EA9, 0xDC6A, 0x8EAA, 0xDC6B, 0x8EAB, 0xC9ED, 0x8EAC, 0xB9AA, 0x8EAD, 0xDC6C, 0x8EAE, 0xDC6D, 0x8EAF, 0xC7FB, 0x8EB0, 0xDC6E, 0x8EB1, 0xDC6F, 0x8EB2, 0xB6E3, 0x8EB3, 0xDC70, 0x8EB4, 0xDC71, 0x8EB5, 0xDC72, 0x8EB6, 0xDC73, 0x8EB7, 0xDC74, 0x8EB8, 0xDC75, 0x8EB9, 0xDC76, 0x8EBA, 0xCCC9, 0x8EBB, 0xDC77, 0x8EBC, 0xDC78, 0x8EBD, 0xDC79, 0x8EBE, 0xDC7A, 0x8EBF, 0xDC7B, 0x8EC0, 0xDC7C, 0x8EC1, 0xDC7D, 0x8EC2, 0xDC7E, 0x8EC3, 0xDC80, 0x8EC4, 0xDC81, 0x8EC5, 0xDC82, 0x8EC6, 0xDC83, 0x8EC7, 0xDC84, 0x8EC8, 0xDC85, 0x8EC9, 0xDC86, 0x8ECA, 0xDC87, 0x8ECB, 0xDC88, 0x8ECC, 0xDC89, 0x8ECD, 0xDC8A, 0x8ECE, 0xEAA6, 0x8ECF, 0xDC8B, 0x8ED0, 0xDC8C, 0x8ED1, 0xDC8D, 0x8ED2, 0xDC8E, 0x8ED3, 0xDC8F, 0x8ED4, 0xDC90, 0x8ED5, 0xDC91, 0x8ED6, 0xDC92, 0x8ED7, 0xDC93, 0x8ED8, 0xDC94, 0x8ED9, 0xDC95, 0x8EDA, 0xDC96, 0x8EDB, 0xDC97, 0x8EDC, 0xDC98, 0x8EDD, 0xDC99, 0x8EDE, 0xDC9A, 0x8EDF, 0xDC9B, 0x8EE0, 0xDC9C, 0x8EE1, 0xDC9D, 0x8EE2, 0xDC9E, 0x8EE3, 0xDC9F, 0x8EE4, 0xDCA0, 0x8EE5, 0xDD40, 0x8EE6, 0xDD41, 0x8EE7, 0xDD42, 0x8EE8, 0xDD43, 0x8EE9, 0xDD44, 0x8EEA, 0xDD45, 0x8EEB, 0xDD46, 0x8EEC, 0xDD47, 0x8EED, 0xDD48, 0x8EEE, 0xDD49, 0x8EEF, 0xDD4A, 0x8EF0, 0xDD4B, 0x8EF1, 0xDD4C, 0x8EF2, 0xDD4D, 0x8EF3, 0xDD4E, 0x8EF4, 0xDD4F, 0x8EF5, 0xDD50, 0x8EF6, 0xDD51, 0x8EF7, 0xDD52, 0x8EF8, 0xDD53, 0x8EF9, 0xDD54, 0x8EFA, 0xDD55, 0x8EFB, 0xDD56, 0x8EFC, 0xDD57, 0x8EFD, 0xDD58, 0x8EFE, 0xDD59, 0x8EFF, 0xDD5A, 0x8F00, 0xDD5B, 0x8F01, 0xDD5C, 0x8F02, 0xDD5D, 0x8F03, 0xDD5E, 0x8F04, 0xDD5F, 0x8F05, 0xDD60, 0x8F06, 0xDD61, 0x8F07, 0xDD62, 0x8F08, 0xDD63, 0x8F09, 0xDD64, 0x8F0A, 0xDD65, 0x8F0B, 0xDD66, 0x8F0C, 0xDD67, 0x8F0D, 0xDD68, 0x8F0E, 0xDD69, 0x8F0F, 0xDD6A, 0x8F10, 0xDD6B, 0x8F11, 0xDD6C, 0x8F12, 0xDD6D, 0x8F13, 0xDD6E, 0x8F14, 0xDD6F, 0x8F15, 0xDD70, 0x8F16, 0xDD71, 0x8F17, 0xDD72, 0x8F18, 0xDD73, 0x8F19, 0xDD74, 0x8F1A, 0xDD75, 0x8F1B, 0xDD76, 0x8F1C, 0xDD77, 0x8F1D, 0xDD78, 0x8F1E, 0xDD79, 0x8F1F, 0xDD7A, 0x8F20, 0xDD7B, 0x8F21, 0xDD7C, 0x8F22, 0xDD7D, 0x8F23, 0xDD7E, 0x8F24, 0xDD80, 0x8F25, 0xDD81, 0x8F26, 0xDD82, 0x8F27, 0xDD83, 0x8F28, 0xDD84, 0x8F29, 0xDD85, 0x8F2A, 0xDD86, 0x8F2B, 0xDD87, 0x8F2C, 0xDD88, 0x8F2D, 0xDD89, 0x8F2E, 0xDD8A, 0x8F2F, 0xDD8B, 0x8F30, 0xDD8C, 0x8F31, 0xDD8D, 0x8F32, 0xDD8E, 0x8F33, 0xDD8F, 0x8F34, 0xDD90, 0x8F35, 0xDD91, 0x8F36, 0xDD92, 0x8F37, 0xDD93, 0x8F38, 0xDD94, 0x8F39, 0xDD95, 0x8F3A, 0xDD96, 0x8F3B, 0xDD97, 0x8F3C, 0xDD98, 0x8F3D, 0xDD99, 0x8F3E, 0xDD9A, 0x8F3F, 0xDD9B, 0x8F40, 0xDD9C, 0x8F41, 0xDD9D, 0x8F42, 0xDD9E, 0x8F43, 0xDD9F, 0x8F44, 0xDDA0, 0x8F45, 0xDE40, 0x8F46, 0xDE41, 0x8F47, 0xDE42, 0x8F48, 0xDE43, 0x8F49, 0xDE44, 0x8F4A, 0xDE45, 0x8F4B, 0xDE46, 0x8F4C, 0xDE47, 0x8F4D, 0xDE48, 0x8F4E, 0xDE49, 0x8F4F, 0xDE4A, 0x8F50, 0xDE4B, 0x8F51, 0xDE4C, 0x8F52, 0xDE4D, 0x8F53, 0xDE4E, 0x8F54, 0xDE4F, 0x8F55, 0xDE50, 0x8F56, 0xDE51, 0x8F57, 0xDE52, 0x8F58, 0xDE53, 0x8F59, 0xDE54, 0x8F5A, 0xDE55, 0x8F5B, 0xDE56, 0x8F5C, 0xDE57, 0x8F5D, 0xDE58, 0x8F5E, 0xDE59, 0x8F5F, 0xDE5A, 0x8F60, 0xDE5B, 0x8F61, 0xDE5C, 0x8F62, 0xDE5D, 0x8F63, 0xDE5E, 0x8F64, 0xDE5F, 0x8F65, 0xDE60, 0x8F66, 0xB3B5, 0x8F67, 0xD4FE, 0x8F68, 0xB9EC, 0x8F69, 0xD0F9, 0x8F6A, 0xDE61, 0x8F6B, 0xE9ED, 0x8F6C, 0xD7AA, 0x8F6D, 0xE9EE, 0x8F6E, 0xC2D6, 0x8F6F, 0xC8ED, 0x8F70, 0xBAE4, 0x8F71, 0xE9EF, 0x8F72, 0xE9F0, 0x8F73, 0xE9F1, 0x8F74, 0xD6E1, 0x8F75, 0xE9F2, 0x8F76, 0xE9F3, 0x8F77, 0xE9F5, 0x8F78, 0xE9F4, 0x8F79, 0xE9F6, 0x8F7A, 0xE9F7, 0x8F7B, 0xC7E1, 0x8F7C, 0xE9F8, 0x8F7D, 0xD4D8, 0x8F7E, 0xE9F9, 0x8F7F, 0xBDCE, 0x8F80, 0xDE62, 0x8F81, 0xE9FA, 0x8F82, 0xE9FB, 0x8F83, 0xBDCF, 0x8F84, 0xE9FC, 0x8F85, 0xB8A8, 0x8F86, 0xC1BE, 0x8F87, 0xE9FD, 0x8F88, 0xB1B2, 0x8F89, 0xBBD4, 0x8F8A, 0xB9F5, 0x8F8B, 0xE9FE, 0x8F8C, 0xDE63, 0x8F8D, 0xEAA1, 0x8F8E, 0xEAA2, 0x8F8F, 0xEAA3, 0x8F90, 0xB7F8, 0x8F91, 0xBCAD, 0x8F92, 0xDE64, 0x8F93, 0xCAE4, 0x8F94, 0xE0CE, 0x8F95, 0xD4AF, 0x8F96, 0xCFBD, 0x8F97, 0xD5B7, 0x8F98, 0xEAA4, 0x8F99, 0xD5DE, 0x8F9A, 0xEAA5, 0x8F9B, 0xD0C1, 0x8F9C, 0xB9BC, 0x8F9D, 0xDE65, 0x8F9E, 0xB4C7, 0x8F9F, 0xB1D9, 0x8FA0, 0xDE66, 0x8FA1, 0xDE67, 0x8FA2, 0xDE68, 0x8FA3, 0xC0B1, 0x8FA4, 0xDE69, 0x8FA5, 0xDE6A, 0x8FA6, 0xDE6B, 0x8FA7, 0xDE6C, 0x8FA8, 0xB1E6, 0x8FA9, 0xB1E7, 0x8FAA, 0xDE6D, 0x8FAB, 0xB1E8, 0x8FAC, 0xDE6E, 0x8FAD, 0xDE6F, 0x8FAE, 0xDE70, 0x8FAF, 0xDE71, 0x8FB0, 0xB3BD, 0x8FB1, 0xC8E8, 0x8FB2, 0xDE72, 0x8FB3, 0xDE73, 0x8FB4, 0xDE74, 0x8FB5, 0xDE75, 0x8FB6, 0xE5C1, 0x8FB7, 0xDE76, 0x8FB8, 0xDE77, 0x8FB9, 0xB1DF, 0x8FBA, 0xDE78, 0x8FBB, 0xDE79, 0x8FBC, 0xDE7A, 0x8FBD, 0xC1C9, 0x8FBE, 0xB4EF, 0x8FBF, 0xDE7B, 0x8FC0, 0xDE7C, 0x8FC1, 0xC7A8, 0x8FC2, 0xD3D8, 0x8FC3, 0xDE7D, 0x8FC4, 0xC6F9, 0x8FC5, 0xD1B8, 0x8FC6, 0xDE7E, 0x8FC7, 0xB9FD, 0x8FC8, 0xC2F5, 0x8FC9, 0xDE80, 0x8FCA, 0xDE81, 0x8FCB, 0xDE82, 0x8FCC, 0xDE83, 0x8FCD, 0xDE84, 0x8FCE, 0xD3AD, 0x8FCF, 0xDE85, 0x8FD0, 0xD4CB, 0x8FD1, 0xBDFC, 0x8FD2, 0xDE86, 0x8FD3, 0xE5C2, 0x8FD4, 0xB7B5, 0x8FD5, 0xE5C3, 0x8FD6, 0xDE87, 0x8FD7, 0xDE88, 0x8FD8, 0xBBB9, 0x8FD9, 0xD5E2, 0x8FDA, 0xDE89, 0x8FDB, 0xBDF8, 0x8FDC, 0xD4B6, 0x8FDD, 0xCEA5, 0x8FDE, 0xC1AC, 0x8FDF, 0xB3D9, 0x8FE0, 0xDE8A, 0x8FE1, 0xDE8B, 0x8FE2, 0xCCF6, 0x8FE3, 0xDE8C, 0x8FE4, 0xE5C6, 0x8FE5, 0xE5C4, 0x8FE6, 0xE5C8, 0x8FE7, 0xDE8D, 0x8FE8, 0xE5CA, 0x8FE9, 0xE5C7, 0x8FEA, 0xB5CF, 0x8FEB, 0xC6C8, 0x8FEC, 0xDE8E, 0x8FED, 0xB5FC, 0x8FEE, 0xE5C5, 0x8FEF, 0xDE8F, 0x8FF0, 0xCAF6, 0x8FF1, 0xDE90, 0x8FF2, 0xDE91, 0x8FF3, 0xE5C9, 0x8FF4, 0xDE92, 0x8FF5, 0xDE93, 0x8FF6, 0xDE94, 0x8FF7, 0xC3D4, 0x8FF8, 0xB1C5, 0x8FF9, 0xBCA3, 0x8FFA, 0xDE95, 0x8FFB, 0xDE96, 0x8FFC, 0xDE97, 0x8FFD, 0xD7B7, 0x8FFE, 0xDE98, 0x8FFF, 0xDE99, 0x9000, 0xCDCB, 0x9001, 0xCBCD, 0x9002, 0xCACA, 0x9003, 0xCCD3, 0x9004, 0xE5CC, 0x9005, 0xE5CB, 0x9006, 0xC4E6, 0x9007, 0xDE9A, 0x9008, 0xDE9B, 0x9009, 0xD1A1, 0x900A, 0xD1B7, 0x900B, 0xE5CD, 0x900C, 0xDE9C, 0x900D, 0xE5D0, 0x900E, 0xDE9D, 0x900F, 0xCDB8, 0x9010, 0xD6F0, 0x9011, 0xE5CF, 0x9012, 0xB5DD, 0x9013, 0xDE9E, 0x9014, 0xCDBE, 0x9015, 0xDE9F, 0x9016, 0xE5D1, 0x9017, 0xB6BA, 0x9018, 0xDEA0, 0x9019, 0xDF40, 0x901A, 0xCDA8, 0x901B, 0xB9E4, 0x901C, 0xDF41, 0x901D, 0xCAC5, 0x901E, 0xB3D1, 0x901F, 0xCBD9, 0x9020, 0xD4EC, 0x9021, 0xE5D2, 0x9022, 0xB7EA, 0x9023, 0xDF42, 0x9024, 0xDF43, 0x9025, 0xDF44, 0x9026, 0xE5CE, 0x9027, 0xDF45, 0x9028, 0xDF46, 0x9029, 0xDF47, 0x902A, 0xDF48, 0x902B, 0xDF49, 0x902C, 0xDF4A, 0x902D, 0xE5D5, 0x902E, 0xB4FE, 0x902F, 0xE5D6, 0x9030, 0xDF4B, 0x9031, 0xDF4C, 0x9032, 0xDF4D, 0x9033, 0xDF4E, 0x9034, 0xDF4F, 0x9035, 0xE5D3, 0x9036, 0xE5D4, 0x9037, 0xDF50, 0x9038, 0xD2DD, 0x9039, 0xDF51, 0x903A, 0xDF52, 0x903B, 0xC2DF, 0x903C, 0xB1C6, 0x903D, 0xDF53, 0x903E, 0xD3E2, 0x903F, 0xDF54, 0x9040, 0xDF55, 0x9041, 0xB6DD, 0x9042, 0xCBEC, 0x9043, 0xDF56, 0x9044, 0xE5D7, 0x9045, 0xDF57, 0x9046, 0xDF58, 0x9047, 0xD3F6, 0x9048, 0xDF59, 0x9049, 0xDF5A, 0x904A, 0xDF5B, 0x904B, 0xDF5C, 0x904C, 0xDF5D, 0x904D, 0xB1E9, 0x904E, 0xDF5E, 0x904F, 0xB6F4, 0x9050, 0xE5DA, 0x9051, 0xE5D8, 0x9052, 0xE5D9, 0x9053, 0xB5C0, 0x9054, 0xDF5F, 0x9055, 0xDF60, 0x9056, 0xDF61, 0x9057, 0xD2C5, 0x9058, 0xE5DC, 0x9059, 0xDF62, 0x905A, 0xDF63, 0x905B, 0xE5DE, 0x905C, 0xDF64, 0x905D, 0xDF65, 0x905E, 0xDF66, 0x905F, 0xDF67, 0x9060, 0xDF68, 0x9061, 0xDF69, 0x9062, 0xE5DD, 0x9063, 0xC7B2, 0x9064, 0xDF6A, 0x9065, 0xD2A3, 0x9066, 0xDF6B, 0x9067, 0xDF6C, 0x9068, 0xE5DB, 0x9069, 0xDF6D, 0x906A, 0xDF6E, 0x906B, 0xDF6F, 0x906C, 0xDF70, 0x906D, 0xD4E2, 0x906E, 0xD5DA, 0x906F, 0xDF71, 0x9070, 0xDF72, 0x9071, 0xDF73, 0x9072, 0xDF74, 0x9073, 0xDF75, 0x9074, 0xE5E0, 0x9075, 0xD7F1, 0x9076, 0xDF76, 0x9077, 0xDF77, 0x9078, 0xDF78, 0x9079, 0xDF79, 0x907A, 0xDF7A, 0x907B, 0xDF7B, 0x907C, 0xDF7C, 0x907D, 0xE5E1, 0x907E, 0xDF7D, 0x907F, 0xB1DC, 0x9080, 0xD1FB, 0x9081, 0xDF7E, 0x9082, 0xE5E2, 0x9083, 0xE5E4, 0x9084, 0xDF80, 0x9085, 0xDF81, 0x9086, 0xDF82, 0x9087, 0xDF83, 0x9088, 0xE5E3, 0x9089, 0xDF84, 0x908A, 0xDF85, 0x908B, 0xE5E5, 0x908C, 0xDF86, 0x908D, 0xDF87, 0x908E, 0xDF88, 0x908F, 0xDF89, 0x9090, 0xDF8A, 0x9091, 0xD2D8, 0x9092, 0xDF8B, 0x9093, 0xB5CB, 0x9094, 0xDF8C, 0x9095, 0xE7DF, 0x9096, 0xDF8D, 0x9097, 0xDAF5, 0x9098, 0xDF8E, 0x9099, 0xDAF8, 0x909A, 0xDF8F, 0x909B, 0xDAF6, 0x909C, 0xDF90, 0x909D, 0xDAF7, 0x909E, 0xDF91, 0x909F, 0xDF92, 0x90A0, 0xDF93, 0x90A1, 0xDAFA, 0x90A2, 0xD0CF, 0x90A3, 0xC4C7, 0x90A4, 0xDF94, 0x90A5, 0xDF95, 0x90A6, 0xB0EE, 0x90A7, 0xDF96, 0x90A8, 0xDF97, 0x90A9, 0xDF98, 0x90AA, 0xD0B0, 0x90AB, 0xDF99, 0x90AC, 0xDAF9, 0x90AD, 0xDF9A, 0x90AE, 0xD3CA, 0x90AF, 0xBAAA, 0x90B0, 0xDBA2, 0x90B1, 0xC7F1, 0x90B2, 0xDF9B, 0x90B3, 0xDAFC, 0x90B4, 0xDAFB, 0x90B5, 0xC9DB, 0x90B6, 0xDAFD, 0x90B7, 0xDF9C, 0x90B8, 0xDBA1, 0x90B9, 0xD7DE, 0x90BA, 0xDAFE, 0x90BB, 0xC1DA, 0x90BC, 0xDF9D, 0x90BD, 0xDF9E, 0x90BE, 0xDBA5, 0x90BF, 0xDF9F, 0x90C0, 0xDFA0, 0x90C1, 0xD3F4, 0x90C2, 0xE040, 0x90C3, 0xE041, 0x90C4, 0xDBA7, 0x90C5, 0xDBA4, 0x90C6, 0xE042, 0x90C7, 0xDBA8, 0x90C8, 0xE043, 0x90C9, 0xE044, 0x90CA, 0xBDBC, 0x90CB, 0xE045, 0x90CC, 0xE046, 0x90CD, 0xE047, 0x90CE, 0xC0C9, 0x90CF, 0xDBA3, 0x90D0, 0xDBA6, 0x90D1, 0xD6A3, 0x90D2, 0xE048, 0x90D3, 0xDBA9, 0x90D4, 0xE049, 0x90D5, 0xE04A, 0x90D6, 0xE04B, 0x90D7, 0xDBAD, 0x90D8, 0xE04C, 0x90D9, 0xE04D, 0x90DA, 0xE04E, 0x90DB, 0xDBAE, 0x90DC, 0xDBAC, 0x90DD, 0xBAC2, 0x90DE, 0xE04F, 0x90DF, 0xE050, 0x90E0, 0xE051, 0x90E1, 0xBFA4, 0x90E2, 0xDBAB, 0x90E3, 0xE052, 0x90E4, 0xE053, 0x90E5, 0xE054, 0x90E6, 0xDBAA, 0x90E7, 0xD4C7, 0x90E8, 0xB2BF, 0x90E9, 0xE055, 0x90EA, 0xE056, 0x90EB, 0xDBAF, 0x90EC, 0xE057, 0x90ED, 0xB9F9, 0x90EE, 0xE058, 0x90EF, 0xDBB0, 0x90F0, 0xE059, 0x90F1, 0xE05A, 0x90F2, 0xE05B, 0x90F3, 0xE05C, 0x90F4, 0xB3BB, 0x90F5, 0xE05D, 0x90F6, 0xE05E, 0x90F7, 0xE05F, 0x90F8, 0xB5A6, 0x90F9, 0xE060, 0x90FA, 0xE061, 0x90FB, 0xE062, 0x90FC, 0xE063, 0x90FD, 0xB6BC, 0x90FE, 0xDBB1, 0x90FF, 0xE064, 0x9100, 0xE065, 0x9101, 0xE066, 0x9102, 0xB6F5, 0x9103, 0xE067, 0x9104, 0xDBB2, 0x9105, 0xE068, 0x9106, 0xE069, 0x9107, 0xE06A, 0x9108, 0xE06B, 0x9109, 0xE06C, 0x910A, 0xE06D, 0x910B, 0xE06E, 0x910C, 0xE06F, 0x910D, 0xE070, 0x910E, 0xE071, 0x910F, 0xE072, 0x9110, 0xE073, 0x9111, 0xE074, 0x9112, 0xE075, 0x9113, 0xE076, 0x9114, 0xE077, 0x9115, 0xE078, 0x9116, 0xE079, 0x9117, 0xE07A, 0x9118, 0xE07B, 0x9119, 0xB1C9, 0x911A, 0xE07C, 0x911B, 0xE07D, 0x911C, 0xE07E, 0x911D, 0xE080, 0x911E, 0xDBB4, 0x911F, 0xE081, 0x9120, 0xE082, 0x9121, 0xE083, 0x9122, 0xDBB3, 0x9123, 0xDBB5, 0x9124, 0xE084, 0x9125, 0xE085, 0x9126, 0xE086, 0x9127, 0xE087, 0x9128, 0xE088, 0x9129, 0xE089, 0x912A, 0xE08A, 0x912B, 0xE08B, 0x912C, 0xE08C, 0x912D, 0xE08D, 0x912E, 0xE08E, 0x912F, 0xDBB7, 0x9130, 0xE08F, 0x9131, 0xDBB6, 0x9132, 0xE090, 0x9133, 0xE091, 0x9134, 0xE092, 0x9135, 0xE093, 0x9136, 0xE094, 0x9137, 0xE095, 0x9138, 0xE096, 0x9139, 0xDBB8, 0x913A, 0xE097, 0x913B, 0xE098, 0x913C, 0xE099, 0x913D, 0xE09A, 0x913E, 0xE09B, 0x913F, 0xE09C, 0x9140, 0xE09D, 0x9141, 0xE09E, 0x9142, 0xE09F, 0x9143, 0xDBB9, 0x9144, 0xE0A0, 0x9145, 0xE140, 0x9146, 0xDBBA, 0x9147, 0xE141, 0x9148, 0xE142, 0x9149, 0xD3CF, 0x914A, 0xF4FA, 0x914B, 0xC7F5, 0x914C, 0xD7C3, 0x914D, 0xC5E4, 0x914E, 0xF4FC, 0x914F, 0xF4FD, 0x9150, 0xF4FB, 0x9151, 0xE143, 0x9152, 0xBEC6, 0x9153, 0xE144, 0x9154, 0xE145, 0x9155, 0xE146, 0x9156, 0xE147, 0x9157, 0xD0EF, 0x9158, 0xE148, 0x9159, 0xE149, 0x915A, 0xB7D3, 0x915B, 0xE14A, 0x915C, 0xE14B, 0x915D, 0xD4CD, 0x915E, 0xCCAA, 0x915F, 0xE14C, 0x9160, 0xE14D, 0x9161, 0xF5A2, 0x9162, 0xF5A1, 0x9163, 0xBAA8, 0x9164, 0xF4FE, 0x9165, 0xCBD6, 0x9166, 0xE14E, 0x9167, 0xE14F, 0x9168, 0xE150, 0x9169, 0xF5A4, 0x916A, 0xC0D2, 0x916B, 0xE151, 0x916C, 0xB3EA, 0x916D, 0xE152, 0x916E, 0xCDAA, 0x916F, 0xF5A5, 0x9170, 0xF5A3, 0x9171, 0xBDB4, 0x9172, 0xF5A8, 0x9173, 0xE153, 0x9174, 0xF5A9, 0x9175, 0xBDCD, 0x9176, 0xC3B8, 0x9177, 0xBFE1, 0x9178, 0xCBE1, 0x9179, 0xF5AA, 0x917A, 0xE154, 0x917B, 0xE155, 0x917C, 0xE156, 0x917D, 0xF5A6, 0x917E, 0xF5A7, 0x917F, 0xC4F0, 0x9180, 0xE157, 0x9181, 0xE158, 0x9182, 0xE159, 0x9183, 0xE15A, 0x9184, 0xE15B, 0x9185, 0xF5AC, 0x9186, 0xE15C, 0x9187, 0xB4BC, 0x9188, 0xE15D, 0x9189, 0xD7ED, 0x918A, 0xE15E, 0x918B, 0xB4D7, 0x918C, 0xF5AB, 0x918D, 0xF5AE, 0x918E, 0xE15F, 0x918F, 0xE160, 0x9190, 0xF5AD, 0x9191, 0xF5AF, 0x9192, 0xD0D1, 0x9193, 0xE161, 0x9194, 0xE162, 0x9195, 0xE163, 0x9196, 0xE164, 0x9197, 0xE165, 0x9198, 0xE166, 0x9199, 0xE167, 0x919A, 0xC3D1, 0x919B, 0xC8A9, 0x919C, 0xE168, 0x919D, 0xE169, 0x919E, 0xE16A, 0x919F, 0xE16B, 0x91A0, 0xE16C, 0x91A1, 0xE16D, 0x91A2, 0xF5B0, 0x91A3, 0xF5B1, 0x91A4, 0xE16E, 0x91A5, 0xE16F, 0x91A6, 0xE170, 0x91A7, 0xE171, 0x91A8, 0xE172, 0x91A9, 0xE173, 0x91AA, 0xF5B2, 0x91AB, 0xE174, 0x91AC, 0xE175, 0x91AD, 0xF5B3, 0x91AE, 0xF5B4, 0x91AF, 0xF5B5, 0x91B0, 0xE176, 0x91B1, 0xE177, 0x91B2, 0xE178, 0x91B3, 0xE179, 0x91B4, 0xF5B7, 0x91B5, 0xF5B6, 0x91B6, 0xE17A, 0x91B7, 0xE17B, 0x91B8, 0xE17C, 0x91B9, 0xE17D, 0x91BA, 0xF5B8, 0x91BB, 0xE17E, 0x91BC, 0xE180, 0x91BD, 0xE181, 0x91BE, 0xE182, 0x91BF, 0xE183, 0x91C0, 0xE184, 0x91C1, 0xE185, 0x91C2, 0xE186, 0x91C3, 0xE187, 0x91C4, 0xE188, 0x91C5, 0xE189, 0x91C6, 0xE18A, 0x91C7, 0xB2C9, 0x91C8, 0xE18B, 0x91C9, 0xD3D4, 0x91CA, 0xCACD, 0x91CB, 0xE18C, 0x91CC, 0xC0EF, 0x91CD, 0xD6D8, 0x91CE, 0xD2B0, 0x91CF, 0xC1BF, 0x91D0, 0xE18D, 0x91D1, 0xBDF0, 0x91D2, 0xE18E, 0x91D3, 0xE18F, 0x91D4, 0xE190, 0x91D5, 0xE191, 0x91D6, 0xE192, 0x91D7, 0xE193, 0x91D8, 0xE194, 0x91D9, 0xE195, 0x91DA, 0xE196, 0x91DB, 0xE197, 0x91DC, 0xB8AA, 0x91DD, 0xE198, 0x91DE, 0xE199, 0x91DF, 0xE19A, 0x91E0, 0xE19B, 0x91E1, 0xE19C, 0x91E2, 0xE19D, 0x91E3, 0xE19E, 0x91E4, 0xE19F, 0x91E5, 0xE1A0, 0x91E6, 0xE240, 0x91E7, 0xE241, 0x91E8, 0xE242, 0x91E9, 0xE243, 0x91EA, 0xE244, 0x91EB, 0xE245, 0x91EC, 0xE246, 0x91ED, 0xE247, 0x91EE, 0xE248, 0x91EF, 0xE249, 0x91F0, 0xE24A, 0x91F1, 0xE24B, 0x91F2, 0xE24C, 0x91F3, 0xE24D, 0x91F4, 0xE24E, 0x91F5, 0xE24F, 0x91F6, 0xE250, 0x91F7, 0xE251, 0x91F8, 0xE252, 0x91F9, 0xE253, 0x91FA, 0xE254, 0x91FB, 0xE255, 0x91FC, 0xE256, 0x91FD, 0xE257, 0x91FE, 0xE258, 0x91FF, 0xE259, 0x9200, 0xE25A, 0x9201, 0xE25B, 0x9202, 0xE25C, 0x9203, 0xE25D, 0x9204, 0xE25E, 0x9205, 0xE25F, 0x9206, 0xE260, 0x9207, 0xE261, 0x9208, 0xE262, 0x9209, 0xE263, 0x920A, 0xE264, 0x920B, 0xE265, 0x920C, 0xE266, 0x920D, 0xE267, 0x920E, 0xE268, 0x920F, 0xE269, 0x9210, 0xE26A, 0x9211, 0xE26B, 0x9212, 0xE26C, 0x9213, 0xE26D, 0x9214, 0xE26E, 0x9215, 0xE26F, 0x9216, 0xE270, 0x9217, 0xE271, 0x9218, 0xE272, 0x9219, 0xE273, 0x921A, 0xE274, 0x921B, 0xE275, 0x921C, 0xE276, 0x921D, 0xE277, 0x921E, 0xE278, 0x921F, 0xE279, 0x9220, 0xE27A, 0x9221, 0xE27B, 0x9222, 0xE27C, 0x9223, 0xE27D, 0x9224, 0xE27E, 0x9225, 0xE280, 0x9226, 0xE281, 0x9227, 0xE282, 0x9228, 0xE283, 0x9229, 0xE284, 0x922A, 0xE285, 0x922B, 0xE286, 0x922C, 0xE287, 0x922D, 0xE288, 0x922E, 0xE289, 0x922F, 0xE28A, 0x9230, 0xE28B, 0x9231, 0xE28C, 0x9232, 0xE28D, 0x9233, 0xE28E, 0x9234, 0xE28F, 0x9235, 0xE290, 0x9236, 0xE291, 0x9237, 0xE292, 0x9238, 0xE293, 0x9239, 0xE294, 0x923A, 0xE295, 0x923B, 0xE296, 0x923C, 0xE297, 0x923D, 0xE298, 0x923E, 0xE299, 0x923F, 0xE29A, 0x9240, 0xE29B, 0x9241, 0xE29C, 0x9242, 0xE29D, 0x9243, 0xE29E, 0x9244, 0xE29F, 0x9245, 0xE2A0, 0x9246, 0xE340, 0x9247, 0xE341, 0x9248, 0xE342, 0x9249, 0xE343, 0x924A, 0xE344, 0x924B, 0xE345, 0x924C, 0xE346, 0x924D, 0xE347, 0x924E, 0xE348, 0x924F, 0xE349, 0x9250, 0xE34A, 0x9251, 0xE34B, 0x9252, 0xE34C, 0x9253, 0xE34D, 0x9254, 0xE34E, 0x9255, 0xE34F, 0x9256, 0xE350, 0x9257, 0xE351, 0x9258, 0xE352, 0x9259, 0xE353, 0x925A, 0xE354, 0x925B, 0xE355, 0x925C, 0xE356, 0x925D, 0xE357, 0x925E, 0xE358, 0x925F, 0xE359, 0x9260, 0xE35A, 0x9261, 0xE35B, 0x9262, 0xE35C, 0x9263, 0xE35D, 0x9264, 0xE35E, 0x9265, 0xE35F, 0x9266, 0xE360, 0x9267, 0xE361, 0x9268, 0xE362, 0x9269, 0xE363, 0x926A, 0xE364, 0x926B, 0xE365, 0x926C, 0xE366, 0x926D, 0xE367, 0x926E, 0xE368, 0x926F, 0xE369, 0x9270, 0xE36A, 0x9271, 0xE36B, 0x9272, 0xE36C, 0x9273, 0xE36D, 0x9274, 0xBCF8, 0x9275, 0xE36E, 0x9276, 0xE36F, 0x9277, 0xE370, 0x9278, 0xE371, 0x9279, 0xE372, 0x927A, 0xE373, 0x927B, 0xE374, 0x927C, 0xE375, 0x927D, 0xE376, 0x927E, 0xE377, 0x927F, 0xE378, 0x9280, 0xE379, 0x9281, 0xE37A, 0x9282, 0xE37B, 0x9283, 0xE37C, 0x9284, 0xE37D, 0x9285, 0xE37E, 0x9286, 0xE380, 0x9287, 0xE381, 0x9288, 0xE382, 0x9289, 0xE383, 0x928A, 0xE384, 0x928B, 0xE385, 0x928C, 0xE386, 0x928D, 0xE387, 0x928E, 0xF6C6, 0x928F, 0xE388, 0x9290, 0xE389, 0x9291, 0xE38A, 0x9292, 0xE38B, 0x9293, 0xE38C, 0x9294, 0xE38D, 0x9295, 0xE38E, 0x9296, 0xE38F, 0x9297, 0xE390, 0x9298, 0xE391, 0x9299, 0xE392, 0x929A, 0xE393, 0x929B, 0xE394, 0x929C, 0xE395, 0x929D, 0xE396, 0x929E, 0xE397, 0x929F, 0xE398, 0x92A0, 0xE399, 0x92A1, 0xE39A, 0x92A2, 0xE39B, 0x92A3, 0xE39C, 0x92A4, 0xE39D, 0x92A5, 0xE39E, 0x92A6, 0xE39F, 0x92A7, 0xE3A0, 0x92A8, 0xE440, 0x92A9, 0xE441, 0x92AA, 0xE442, 0x92AB, 0xE443, 0x92AC, 0xE444, 0x92AD, 0xE445, 0x92AE, 0xF6C7, 0x92AF, 0xE446, 0x92B0, 0xE447, 0x92B1, 0xE448, 0x92B2, 0xE449, 0x92B3, 0xE44A, 0x92B4, 0xE44B, 0x92B5, 0xE44C, 0x92B6, 0xE44D, 0x92B7, 0xE44E, 0x92B8, 0xE44F, 0x92B9, 0xE450, 0x92BA, 0xE451, 0x92BB, 0xE452, 0x92BC, 0xE453, 0x92BD, 0xE454, 0x92BE, 0xE455, 0x92BF, 0xE456, 0x92C0, 0xE457, 0x92C1, 0xE458, 0x92C2, 0xE459, 0x92C3, 0xE45A, 0x92C4, 0xE45B, 0x92C5, 0xE45C, 0x92C6, 0xE45D, 0x92C7, 0xE45E, 0x92C8, 0xF6C8, 0x92C9, 0xE45F, 0x92CA, 0xE460, 0x92CB, 0xE461, 0x92CC, 0xE462, 0x92CD, 0xE463, 0x92CE, 0xE464, 0x92CF, 0xE465, 0x92D0, 0xE466, 0x92D1, 0xE467, 0x92D2, 0xE468, 0x92D3, 0xE469, 0x92D4, 0xE46A, 0x92D5, 0xE46B, 0x92D6, 0xE46C, 0x92D7, 0xE46D, 0x92D8, 0xE46E, 0x92D9, 0xE46F, 0x92DA, 0xE470, 0x92DB, 0xE471, 0x92DC, 0xE472, 0x92DD, 0xE473, 0x92DE, 0xE474, 0x92DF, 0xE475, 0x92E0, 0xE476, 0x92E1, 0xE477, 0x92E2, 0xE478, 0x92E3, 0xE479, 0x92E4, 0xE47A, 0x92E5, 0xE47B, 0x92E6, 0xE47C, 0x92E7, 0xE47D, 0x92E8, 0xE47E, 0x92E9, 0xE480, 0x92EA, 0xE481, 0x92EB, 0xE482, 0x92EC, 0xE483, 0x92ED, 0xE484, 0x92EE, 0xE485, 0x92EF, 0xE486, 0x92F0, 0xE487, 0x92F1, 0xE488, 0x92F2, 0xE489, 0x92F3, 0xE48A, 0x92F4, 0xE48B, 0x92F5, 0xE48C, 0x92F6, 0xE48D, 0x92F7, 0xE48E, 0x92F8, 0xE48F, 0x92F9, 0xE490, 0x92FA, 0xE491, 0x92FB, 0xE492, 0x92FC, 0xE493, 0x92FD, 0xE494, 0x92FE, 0xE495, 0x92FF, 0xE496, 0x9300, 0xE497, 0x9301, 0xE498, 0x9302, 0xE499, 0x9303, 0xE49A, 0x9304, 0xE49B, 0x9305, 0xE49C, 0x9306, 0xE49D, 0x9307, 0xE49E, 0x9308, 0xE49F, 0x9309, 0xE4A0, 0x930A, 0xE540, 0x930B, 0xE541, 0x930C, 0xE542, 0x930D, 0xE543, 0x930E, 0xE544, 0x930F, 0xE545, 0x9310, 0xE546, 0x9311, 0xE547, 0x9312, 0xE548, 0x9313, 0xE549, 0x9314, 0xE54A, 0x9315, 0xE54B, 0x9316, 0xE54C, 0x9317, 0xE54D, 0x9318, 0xE54E, 0x9319, 0xE54F, 0x931A, 0xE550, 0x931B, 0xE551, 0x931C, 0xE552, 0x931D, 0xE553, 0x931E, 0xE554, 0x931F, 0xE555, 0x9320, 0xE556, 0x9321, 0xE557, 0x9322, 0xE558, 0x9323, 0xE559, 0x9324, 0xE55A, 0x9325, 0xE55B, 0x9326, 0xE55C, 0x9327, 0xE55D, 0x9328, 0xE55E, 0x9329, 0xE55F, 0x932A, 0xE560, 0x932B, 0xE561, 0x932C, 0xE562, 0x932D, 0xE563, 0x932E, 0xE564, 0x932F, 0xE565, 0x9330, 0xE566, 0x9331, 0xE567, 0x9332, 0xE568, 0x9333, 0xE569, 0x9334, 0xE56A, 0x9335, 0xE56B, 0x9336, 0xE56C, 0x9337, 0xE56D, 0x9338, 0xE56E, 0x9339, 0xE56F, 0x933A, 0xE570, 0x933B, 0xE571, 0x933C, 0xE572, 0x933D, 0xE573, 0x933E, 0xF6C9, 0x933F, 0xE574, 0x9340, 0xE575, 0x9341, 0xE576, 0x9342, 0xE577, 0x9343, 0xE578, 0x9344, 0xE579, 0x9345, 0xE57A, 0x9346, 0xE57B, 0x9347, 0xE57C, 0x9348, 0xE57D, 0x9349, 0xE57E, 0x934A, 0xE580, 0x934B, 0xE581, 0x934C, 0xE582, 0x934D, 0xE583, 0x934E, 0xE584, 0x934F, 0xE585, 0x9350, 0xE586, 0x9351, 0xE587, 0x9352, 0xE588, 0x9353, 0xE589, 0x9354, 0xE58A, 0x9355, 0xE58B, 0x9356, 0xE58C, 0x9357, 0xE58D, 0x9358, 0xE58E, 0x9359, 0xE58F, 0x935A, 0xE590, 0x935B, 0xE591, 0x935C, 0xE592, 0x935D, 0xE593, 0x935E, 0xE594, 0x935F, 0xE595, 0x9360, 0xE596, 0x9361, 0xE597, 0x9362, 0xE598, 0x9363, 0xE599, 0x9364, 0xE59A, 0x9365, 0xE59B, 0x9366, 0xE59C, 0x9367, 0xE59D, 0x9368, 0xE59E, 0x9369, 0xE59F, 0x936A, 0xF6CA, 0x936B, 0xE5A0, 0x936C, 0xE640, 0x936D, 0xE641, 0x936E, 0xE642, 0x936F, 0xE643, 0x9370, 0xE644, 0x9371, 0xE645, 0x9372, 0xE646, 0x9373, 0xE647, 0x9374, 0xE648, 0x9375, 0xE649, 0x9376, 0xE64A, 0x9377, 0xE64B, 0x9378, 0xE64C, 0x9379, 0xE64D, 0x937A, 0xE64E, 0x937B, 0xE64F, 0x937C, 0xE650, 0x937D, 0xE651, 0x937E, 0xE652, 0x937F, 0xE653, 0x9380, 0xE654, 0x9381, 0xE655, 0x9382, 0xE656, 0x9383, 0xE657, 0x9384, 0xE658, 0x9385, 0xE659, 0x9386, 0xE65A, 0x9387, 0xE65B, 0x9388, 0xE65C, 0x9389, 0xE65D, 0x938A, 0xE65E, 0x938B, 0xE65F, 0x938C, 0xE660, 0x938D, 0xE661, 0x938E, 0xE662, 0x938F, 0xF6CC, 0x9390, 0xE663, 0x9391, 0xE664, 0x9392, 0xE665, 0x9393, 0xE666, 0x9394, 0xE667, 0x9395, 0xE668, 0x9396, 0xE669, 0x9397, 0xE66A, 0x9398, 0xE66B, 0x9399, 0xE66C, 0x939A, 0xE66D, 0x939B, 0xE66E, 0x939C, 0xE66F, 0x939D, 0xE670, 0x939E, 0xE671, 0x939F, 0xE672, 0x93A0, 0xE673, 0x93A1, 0xE674, 0x93A2, 0xE675, 0x93A3, 0xE676, 0x93A4, 0xE677, 0x93A5, 0xE678, 0x93A6, 0xE679, 0x93A7, 0xE67A, 0x93A8, 0xE67B, 0x93A9, 0xE67C, 0x93AA, 0xE67D, 0x93AB, 0xE67E, 0x93AC, 0xE680, 0x93AD, 0xE681, 0x93AE, 0xE682, 0x93AF, 0xE683, 0x93B0, 0xE684, 0x93B1, 0xE685, 0x93B2, 0xE686, 0x93B3, 0xE687, 0x93B4, 0xE688, 0x93B5, 0xE689, 0x93B6, 0xE68A, 0x93B7, 0xE68B, 0x93B8, 0xE68C, 0x93B9, 0xE68D, 0x93BA, 0xE68E, 0x93BB, 0xE68F, 0x93BC, 0xE690, 0x93BD, 0xE691, 0x93BE, 0xE692, 0x93BF, 0xE693, 0x93C0, 0xE694, 0x93C1, 0xE695, 0x93C2, 0xE696, 0x93C3, 0xE697, 0x93C4, 0xE698, 0x93C5, 0xE699, 0x93C6, 0xE69A, 0x93C7, 0xE69B, 0x93C8, 0xE69C, 0x93C9, 0xE69D, 0x93CA, 0xF6CB, 0x93CB, 0xE69E, 0x93CC, 0xE69F, 0x93CD, 0xE6A0, 0x93CE, 0xE740, 0x93CF, 0xE741, 0x93D0, 0xE742, 0x93D1, 0xE743, 0x93D2, 0xE744, 0x93D3, 0xE745, 0x93D4, 0xE746, 0x93D5, 0xE747, 0x93D6, 0xF7E9, 0x93D7, 0xE748, 0x93D8, 0xE749, 0x93D9, 0xE74A, 0x93DA, 0xE74B, 0x93DB, 0xE74C, 0x93DC, 0xE74D, 0x93DD, 0xE74E, 0x93DE, 0xE74F, 0x93DF, 0xE750, 0x93E0, 0xE751, 0x93E1, 0xE752, 0x93E2, 0xE753, 0x93E3, 0xE754, 0x93E4, 0xE755, 0x93E5, 0xE756, 0x93E6, 0xE757, 0x93E7, 0xE758, 0x93E8, 0xE759, 0x93E9, 0xE75A, 0x93EA, 0xE75B, 0x93EB, 0xE75C, 0x93EC, 0xE75D, 0x93ED, 0xE75E, 0x93EE, 0xE75F, 0x93EF, 0xE760, 0x93F0, 0xE761, 0x93F1, 0xE762, 0x93F2, 0xE763, 0x93F3, 0xE764, 0x93F4, 0xE765, 0x93F5, 0xE766, 0x93F6, 0xE767, 0x93F7, 0xE768, 0x93F8, 0xE769, 0x93F9, 0xE76A, 0x93FA, 0xE76B, 0x93FB, 0xE76C, 0x93FC, 0xE76D, 0x93FD, 0xE76E, 0x93FE, 0xE76F, 0x93FF, 0xE770, 0x9400, 0xE771, 0x9401, 0xE772, 0x9402, 0xE773, 0x9403, 0xE774, 0x9404, 0xE775, 0x9405, 0xE776, 0x9406, 0xE777, 0x9407, 0xE778, 0x9408, 0xE779, 0x9409, 0xE77A, 0x940A, 0xE77B, 0x940B, 0xE77C, 0x940C, 0xE77D, 0x940D, 0xE77E, 0x940E, 0xE780, 0x940F, 0xE781, 0x9410, 0xE782, 0x9411, 0xE783, 0x9412, 0xE784, 0x9413, 0xE785, 0x9414, 0xE786, 0x9415, 0xE787, 0x9416, 0xE788, 0x9417, 0xE789, 0x9418, 0xE78A, 0x9419, 0xE78B, 0x941A, 0xE78C, 0x941B, 0xE78D, 0x941C, 0xE78E, 0x941D, 0xE78F, 0x941E, 0xE790, 0x941F, 0xE791, 0x9420, 0xE792, 0x9421, 0xE793, 0x9422, 0xE794, 0x9423, 0xE795, 0x9424, 0xE796, 0x9425, 0xE797, 0x9426, 0xE798, 0x9427, 0xE799, 0x9428, 0xE79A, 0x9429, 0xE79B, 0x942A, 0xE79C, 0x942B, 0xE79D, 0x942C, 0xE79E, 0x942D, 0xE79F, 0x942E, 0xE7A0, 0x942F, 0xE840, 0x9430, 0xE841, 0x9431, 0xE842, 0x9432, 0xE843, 0x9433, 0xE844, 0x9434, 0xE845, 0x9435, 0xE846, 0x9436, 0xE847, 0x9437, 0xE848, 0x9438, 0xE849, 0x9439, 0xE84A, 0x943A, 0xE84B, 0x943B, 0xE84C, 0x943C, 0xE84D, 0x943D, 0xE84E, 0x943E, 0xF6CD, 0x943F, 0xE84F, 0x9440, 0xE850, 0x9441, 0xE851, 0x9442, 0xE852, 0x9443, 0xE853, 0x9444, 0xE854, 0x9445, 0xE855, 0x9446, 0xE856, 0x9447, 0xE857, 0x9448, 0xE858, 0x9449, 0xE859, 0x944A, 0xE85A, 0x944B, 0xE85B, 0x944C, 0xE85C, 0x944D, 0xE85D, 0x944E, 0xE85E, 0x944F, 0xE85F, 0x9450, 0xE860, 0x9451, 0xE861, 0x9452, 0xE862, 0x9453, 0xE863, 0x9454, 0xE864, 0x9455, 0xE865, 0x9456, 0xE866, 0x9457, 0xE867, 0x9458, 0xE868, 0x9459, 0xE869, 0x945A, 0xE86A, 0x945B, 0xE86B, 0x945C, 0xE86C, 0x945D, 0xE86D, 0x945E, 0xE86E, 0x945F, 0xE86F, 0x9460, 0xE870, 0x9461, 0xE871, 0x9462, 0xE872, 0x9463, 0xE873, 0x9464, 0xE874, 0x9465, 0xE875, 0x9466, 0xE876, 0x9467, 0xE877, 0x9468, 0xE878, 0x9469, 0xE879, 0x946A, 0xE87A, 0x946B, 0xF6CE, 0x946C, 0xE87B, 0x946D, 0xE87C, 0x946E, 0xE87D, 0x946F, 0xE87E, 0x9470, 0xE880, 0x9471, 0xE881, 0x9472, 0xE882, 0x9473, 0xE883, 0x9474, 0xE884, 0x9475, 0xE885, 0x9476, 0xE886, 0x9477, 0xE887, 0x9478, 0xE888, 0x9479, 0xE889, 0x947A, 0xE88A, 0x947B, 0xE88B, 0x947C, 0xE88C, 0x947D, 0xE88D, 0x947E, 0xE88E, 0x947F, 0xE88F, 0x9480, 0xE890, 0x9481, 0xE891, 0x9482, 0xE892, 0x9483, 0xE893, 0x9484, 0xE894, 0x9485, 0xEEC4, 0x9486, 0xEEC5, 0x9487, 0xEEC6, 0x9488, 0xD5EB, 0x9489, 0xB6A4, 0x948A, 0xEEC8, 0x948B, 0xEEC7, 0x948C, 0xEEC9, 0x948D, 0xEECA, 0x948E, 0xC7A5, 0x948F, 0xEECB, 0x9490, 0xEECC, 0x9491, 0xE895, 0x9492, 0xB7B0, 0x9493, 0xB5F6, 0x9494, 0xEECD, 0x9495, 0xEECF, 0x9496, 0xE896, 0x9497, 0xEECE, 0x9498, 0xE897, 0x9499, 0xB8C6, 0x949A, 0xEED0, 0x949B, 0xEED1, 0x949C, 0xEED2, 0x949D, 0xB6DB, 0x949E, 0xB3AE, 0x949F, 0xD6D3, 0x94A0, 0xC4C6, 0x94A1, 0xB1B5, 0x94A2, 0xB8D6, 0x94A3, 0xEED3, 0x94A4, 0xEED4, 0x94A5, 0xD4BF, 0x94A6, 0xC7D5, 0x94A7, 0xBEFB, 0x94A8, 0xCED9, 0x94A9, 0xB9B3, 0x94AA, 0xEED6, 0x94AB, 0xEED5, 0x94AC, 0xEED8, 0x94AD, 0xEED7, 0x94AE, 0xC5A5, 0x94AF, 0xEED9, 0x94B0, 0xEEDA, 0x94B1, 0xC7AE, 0x94B2, 0xEEDB, 0x94B3, 0xC7AF, 0x94B4, 0xEEDC, 0x94B5, 0xB2A7, 0x94B6, 0xEEDD, 0x94B7, 0xEEDE, 0x94B8, 0xEEDF, 0x94B9, 0xEEE0, 0x94BA, 0xEEE1, 0x94BB, 0xD7EA, 0x94BC, 0xEEE2, 0x94BD, 0xEEE3, 0x94BE, 0xBCD8, 0x94BF, 0xEEE4, 0x94C0, 0xD3CB, 0x94C1, 0xCCFA, 0x94C2, 0xB2AC, 0x94C3, 0xC1E5, 0x94C4, 0xEEE5, 0x94C5, 0xC7A6, 0x94C6, 0xC3AD, 0x94C7, 0xE898, 0x94C8, 0xEEE6, 0x94C9, 0xEEE7, 0x94CA, 0xEEE8, 0x94CB, 0xEEE9, 0x94CC, 0xEEEA, 0x94CD, 0xEEEB, 0x94CE, 0xEEEC, 0x94CF, 0xE899, 0x94D0, 0xEEED, 0x94D1, 0xEEEE, 0x94D2, 0xEEEF, 0x94D3, 0xE89A, 0x94D4, 0xE89B, 0x94D5, 0xEEF0, 0x94D6, 0xEEF1, 0x94D7, 0xEEF2, 0x94D8, 0xEEF4, 0x94D9, 0xEEF3, 0x94DA, 0xE89C, 0x94DB, 0xEEF5, 0x94DC, 0xCDAD, 0x94DD, 0xC2C1, 0x94DE, 0xEEF6, 0x94DF, 0xEEF7, 0x94E0, 0xEEF8, 0x94E1, 0xD5A1, 0x94E2, 0xEEF9, 0x94E3, 0xCFB3, 0x94E4, 0xEEFA, 0x94E5, 0xEEFB, 0x94E6, 0xE89D, 0x94E7, 0xEEFC, 0x94E8, 0xEEFD, 0x94E9, 0xEFA1, 0x94EA, 0xEEFE, 0x94EB, 0xEFA2, 0x94EC, 0xB8F5, 0x94ED, 0xC3FA, 0x94EE, 0xEFA3, 0x94EF, 0xEFA4, 0x94F0, 0xBDC2, 0x94F1, 0xD2BF, 0x94F2, 0xB2F9, 0x94F3, 0xEFA5, 0x94F4, 0xEFA6, 0x94F5, 0xEFA7, 0x94F6, 0xD2F8, 0x94F7, 0xEFA8, 0x94F8, 0xD6FD, 0x94F9, 0xEFA9, 0x94FA, 0xC6CC, 0x94FB, 0xE89E, 0x94FC, 0xEFAA, 0x94FD, 0xEFAB, 0x94FE, 0xC1B4, 0x94FF, 0xEFAC, 0x9500, 0xCFFA, 0x9501, 0xCBF8, 0x9502, 0xEFAE, 0x9503, 0xEFAD, 0x9504, 0xB3FA, 0x9505, 0xB9F8, 0x9506, 0xEFAF, 0x9507, 0xEFB0, 0x9508, 0xD0E2, 0x9509, 0xEFB1, 0x950A, 0xEFB2, 0x950B, 0xB7E6, 0x950C, 0xD0BF, 0x950D, 0xEFB3, 0x950E, 0xEFB4, 0x950F, 0xEFB5, 0x9510, 0xC8F1, 0x9511, 0xCCE0, 0x9512, 0xEFB6, 0x9513, 0xEFB7, 0x9514, 0xEFB8, 0x9515, 0xEFB9, 0x9516, 0xEFBA, 0x9517, 0xD5E0, 0x9518, 0xEFBB, 0x9519, 0xB4ED, 0x951A, 0xC3AA, 0x951B, 0xEFBC, 0x951C, 0xE89F, 0x951D, 0xEFBD, 0x951E, 0xEFBE, 0x951F, 0xEFBF, 0x9520, 0xE8A0, 0x9521, 0xCEFD, 0x9522, 0xEFC0, 0x9523, 0xC2E0, 0x9524, 0xB4B8, 0x9525, 0xD7B6, 0x9526, 0xBDF5, 0x9527, 0xE940, 0x9528, 0xCFC7, 0x9529, 0xEFC3, 0x952A, 0xEFC1, 0x952B, 0xEFC2, 0x952C, 0xEFC4, 0x952D, 0xB6A7, 0x952E, 0xBCFC, 0x952F, 0xBEE2, 0x9530, 0xC3CC, 0x9531, 0xEFC5, 0x9532, 0xEFC6, 0x9533, 0xE941, 0x9534, 0xEFC7, 0x9535, 0xEFCF, 0x9536, 0xEFC8, 0x9537, 0xEFC9, 0x9538, 0xEFCA, 0x9539, 0xC7C2, 0x953A, 0xEFF1, 0x953B, 0xB6CD, 0x953C, 0xEFCB, 0x953D, 0xE942, 0x953E, 0xEFCC, 0x953F, 0xEFCD, 0x9540, 0xB6C6, 0x9541, 0xC3BE, 0x9542, 0xEFCE, 0x9543, 0xE943, 0x9544, 0xEFD0, 0x9545, 0xEFD1, 0x9546, 0xEFD2, 0x9547, 0xD5F2, 0x9548, 0xE944, 0x9549, 0xEFD3, 0x954A, 0xC4F7, 0x954B, 0xE945, 0x954C, 0xEFD4, 0x954D, 0xC4F8, 0x954E, 0xEFD5, 0x954F, 0xEFD6, 0x9550, 0xB8E4, 0x9551, 0xB0F7, 0x9552, 0xEFD7, 0x9553, 0xEFD8, 0x9554, 0xEFD9, 0x9555, 0xE946, 0x9556, 0xEFDA, 0x9557, 0xEFDB, 0x9558, 0xEFDC, 0x9559, 0xEFDD, 0x955A, 0xE947, 0x955B, 0xEFDE, 0x955C, 0xBEB5, 0x955D, 0xEFE1, 0x955E, 0xEFDF, 0x955F, 0xEFE0, 0x9560, 0xE948, 0x9561, 0xEFE2, 0x9562, 0xEFE3, 0x9563, 0xC1CD, 0x9564, 0xEFE4, 0x9565, 0xEFE5, 0x9566, 0xEFE6, 0x9567, 0xEFE7, 0x9568, 0xEFE8, 0x9569, 0xEFE9, 0x956A, 0xEFEA, 0x956B, 0xEFEB, 0x956C, 0xEFEC, 0x956D, 0xC0D8, 0x956E, 0xE949, 0x956F, 0xEFED, 0x9570, 0xC1AD, 0x9571, 0xEFEE, 0x9572, 0xEFEF, 0x9573, 0xEFF0, 0x9574, 0xE94A, 0x9575, 0xE94B, 0x9576, 0xCFE2, 0x9577, 0xE94C, 0x9578, 0xE94D, 0x9579, 0xE94E, 0x957A, 0xE94F, 0x957B, 0xE950, 0x957C, 0xE951, 0x957D, 0xE952, 0x957E, 0xE953, 0x957F, 0xB3A4, 0x9580, 0xE954, 0x9581, 0xE955, 0x9582, 0xE956, 0x9583, 0xE957, 0x9584, 0xE958, 0x9585, 0xE959, 0x9586, 0xE95A, 0x9587, 0xE95B, 0x9588, 0xE95C, 0x9589, 0xE95D, 0x958A, 0xE95E, 0x958B, 0xE95F, 0x958C, 0xE960, 0x958D, 0xE961, 0x958E, 0xE962, 0x958F, 0xE963, 0x9590, 0xE964, 0x9591, 0xE965, 0x9592, 0xE966, 0x9593, 0xE967, 0x9594, 0xE968, 0x9595, 0xE969, 0x9596, 0xE96A, 0x9597, 0xE96B, 0x9598, 0xE96C, 0x9599, 0xE96D, 0x959A, 0xE96E, 0x959B, 0xE96F, 0x959C, 0xE970, 0x959D, 0xE971, 0x959E, 0xE972, 0x959F, 0xE973, 0x95A0, 0xE974, 0x95A1, 0xE975, 0x95A2, 0xE976, 0x95A3, 0xE977, 0x95A4, 0xE978, 0x95A5, 0xE979, 0x95A6, 0xE97A, 0x95A7, 0xE97B, 0x95A8, 0xE97C, 0x95A9, 0xE97D, 0x95AA, 0xE97E, 0x95AB, 0xE980, 0x95AC, 0xE981, 0x95AD, 0xE982, 0x95AE, 0xE983, 0x95AF, 0xE984, 0x95B0, 0xE985, 0x95B1, 0xE986, 0x95B2, 0xE987, 0x95B3, 0xE988, 0x95B4, 0xE989, 0x95B5, 0xE98A, 0x95B6, 0xE98B, 0x95B7, 0xE98C, 0x95B8, 0xE98D, 0x95B9, 0xE98E, 0x95BA, 0xE98F, 0x95BB, 0xE990, 0x95BC, 0xE991, 0x95BD, 0xE992, 0x95BE, 0xE993, 0x95BF, 0xE994, 0x95C0, 0xE995, 0x95C1, 0xE996, 0x95C2, 0xE997, 0x95C3, 0xE998, 0x95C4, 0xE999, 0x95C5, 0xE99A, 0x95C6, 0xE99B, 0x95C7, 0xE99C, 0x95C8, 0xE99D, 0x95C9, 0xE99E, 0x95CA, 0xE99F, 0x95CB, 0xE9A0, 0x95CC, 0xEA40, 0x95CD, 0xEA41, 0x95CE, 0xEA42, 0x95CF, 0xEA43, 0x95D0, 0xEA44, 0x95D1, 0xEA45, 0x95D2, 0xEA46, 0x95D3, 0xEA47, 0x95D4, 0xEA48, 0x95D5, 0xEA49, 0x95D6, 0xEA4A, 0x95D7, 0xEA4B, 0x95D8, 0xEA4C, 0x95D9, 0xEA4D, 0x95DA, 0xEA4E, 0x95DB, 0xEA4F, 0x95DC, 0xEA50, 0x95DD, 0xEA51, 0x95DE, 0xEA52, 0x95DF, 0xEA53, 0x95E0, 0xEA54, 0x95E1, 0xEA55, 0x95E2, 0xEA56, 0x95E3, 0xEA57, 0x95E4, 0xEA58, 0x95E5, 0xEA59, 0x95E6, 0xEA5A, 0x95E7, 0xEA5B, 0x95E8, 0xC3C5, 0x95E9, 0xE3C5, 0x95EA, 0xC9C1, 0x95EB, 0xE3C6, 0x95EC, 0xEA5C, 0x95ED, 0xB1D5, 0x95EE, 0xCECA, 0x95EF, 0xB4B3, 0x95F0, 0xC8F2, 0x95F1, 0xE3C7, 0x95F2, 0xCFD0, 0x95F3, 0xE3C8, 0x95F4, 0xBCE4, 0x95F5, 0xE3C9, 0x95F6, 0xE3CA, 0x95F7, 0xC3C6, 0x95F8, 0xD5A2, 0x95F9, 0xC4D6, 0x95FA, 0xB9EB, 0x95FB, 0xCEC5, 0x95FC, 0xE3CB, 0x95FD, 0xC3F6, 0x95FE, 0xE3CC, 0x95FF, 0xEA5D, 0x9600, 0xB7A7, 0x9601, 0xB8F3, 0x9602, 0xBAD2, 0x9603, 0xE3CD, 0x9604, 0xE3CE, 0x9605, 0xD4C4, 0x9606, 0xE3CF, 0x9607, 0xEA5E, 0x9608, 0xE3D0, 0x9609, 0xD1CB, 0x960A, 0xE3D1, 0x960B, 0xE3D2, 0x960C, 0xE3D3, 0x960D, 0xE3D4, 0x960E, 0xD1D6, 0x960F, 0xE3D5, 0x9610, 0xB2FB, 0x9611, 0xC0BB, 0x9612, 0xE3D6, 0x9613, 0xEA5F, 0x9614, 0xC0AB, 0x9615, 0xE3D7, 0x9616, 0xE3D8, 0x9617, 0xE3D9, 0x9618, 0xEA60, 0x9619, 0xE3DA, 0x961A, 0xE3DB, 0x961B, 0xEA61, 0x961C, 0xB8B7, 0x961D, 0xDAE2, 0x961E, 0xEA62, 0x961F, 0xB6D3, 0x9620, 0xEA63, 0x9621, 0xDAE4, 0x9622, 0xDAE3, 0x9623, 0xEA64, 0x9624, 0xEA65, 0x9625, 0xEA66, 0x9626, 0xEA67, 0x9627, 0xEA68, 0x9628, 0xEA69, 0x9629, 0xEA6A, 0x962A, 0xDAE6, 0x962B, 0xEA6B, 0x962C, 0xEA6C, 0x962D, 0xEA6D, 0x962E, 0xC8EE, 0x962F, 0xEA6E, 0x9630, 0xEA6F, 0x9631, 0xDAE5, 0x9632, 0xB7C0, 0x9633, 0xD1F4, 0x9634, 0xD2F5, 0x9635, 0xD5F3, 0x9636, 0xBDD7, 0x9637, 0xEA70, 0x9638, 0xEA71, 0x9639, 0xEA72, 0x963A, 0xEA73, 0x963B, 0xD7E8, 0x963C, 0xDAE8, 0x963D, 0xDAE7, 0x963E, 0xEA74, 0x963F, 0xB0A2, 0x9640, 0xCDD3, 0x9641, 0xEA75, 0x9642, 0xDAE9, 0x9643, 0xEA76, 0x9644, 0xB8BD, 0x9645, 0xBCCA, 0x9646, 0xC2BD, 0x9647, 0xC2A4, 0x9648, 0xB3C2, 0x9649, 0xDAEA, 0x964A, 0xEA77, 0x964B, 0xC2AA, 0x964C, 0xC4B0, 0x964D, 0xBDB5, 0x964E, 0xEA78, 0x964F, 0xEA79, 0x9650, 0xCFDE, 0x9651, 0xEA7A, 0x9652, 0xEA7B, 0x9653, 0xEA7C, 0x9654, 0xDAEB, 0x9655, 0xC9C2, 0x9656, 0xEA7D, 0x9657, 0xEA7E, 0x9658, 0xEA80, 0x9659, 0xEA81, 0x965A, 0xEA82, 0x965B, 0xB1DD, 0x965C, 0xEA83, 0x965D, 0xEA84, 0x965E, 0xEA85, 0x965F, 0xDAEC, 0x9660, 0xEA86, 0x9661, 0xB6B8, 0x9662, 0xD4BA, 0x9663, 0xEA87, 0x9664, 0xB3FD, 0x9665, 0xEA88, 0x9666, 0xEA89, 0x9667, 0xDAED, 0x9668, 0xD4C9, 0x9669, 0xCFD5, 0x966A, 0xC5E3, 0x966B, 0xEA8A, 0x966C, 0xDAEE, 0x966D, 0xEA8B, 0x966E, 0xEA8C, 0x966F, 0xEA8D, 0x9670, 0xEA8E, 0x9671, 0xEA8F, 0x9672, 0xDAEF, 0x9673, 0xEA90, 0x9674, 0xDAF0, 0x9675, 0xC1EA, 0x9676, 0xCCD5, 0x9677, 0xCFDD, 0x9678, 0xEA91, 0x9679, 0xEA92, 0x967A, 0xEA93, 0x967B, 0xEA94, 0x967C, 0xEA95, 0x967D, 0xEA96, 0x967E, 0xEA97, 0x967F, 0xEA98, 0x9680, 0xEA99, 0x9681, 0xEA9A, 0x9682, 0xEA9B, 0x9683, 0xEA9C, 0x9684, 0xEA9D, 0x9685, 0xD3E7, 0x9686, 0xC2A1, 0x9687, 0xEA9E, 0x9688, 0xDAF1, 0x9689, 0xEA9F, 0x968A, 0xEAA0, 0x968B, 0xCBE5, 0x968C, 0xEB40, 0x968D, 0xDAF2, 0x968E, 0xEB41, 0x968F, 0xCBE6, 0x9690, 0xD2FE, 0x9691, 0xEB42, 0x9692, 0xEB43, 0x9693, 0xEB44, 0x9694, 0xB8F4, 0x9695, 0xEB45, 0x9696, 0xEB46, 0x9697, 0xDAF3, 0x9698, 0xB0AF, 0x9699, 0xCFB6, 0x969A, 0xEB47, 0x969B, 0xEB48, 0x969C, 0xD5CF, 0x969D, 0xEB49, 0x969E, 0xEB4A, 0x969F, 0xEB4B, 0x96A0, 0xEB4C, 0x96A1, 0xEB4D, 0x96A2, 0xEB4E, 0x96A3, 0xEB4F, 0x96A4, 0xEB50, 0x96A5, 0xEB51, 0x96A6, 0xEB52, 0x96A7, 0xCBED, 0x96A8, 0xEB53, 0x96A9, 0xEB54, 0x96AA, 0xEB55, 0x96AB, 0xEB56, 0x96AC, 0xEB57, 0x96AD, 0xEB58, 0x96AE, 0xEB59, 0x96AF, 0xEB5A, 0x96B0, 0xDAF4, 0x96B1, 0xEB5B, 0x96B2, 0xEB5C, 0x96B3, 0xE3C4, 0x96B4, 0xEB5D, 0x96B5, 0xEB5E, 0x96B6, 0xC1A5, 0x96B7, 0xEB5F, 0x96B8, 0xEB60, 0x96B9, 0xF6BF, 0x96BA, 0xEB61, 0x96BB, 0xEB62, 0x96BC, 0xF6C0, 0x96BD, 0xF6C1, 0x96BE, 0xC4D1, 0x96BF, 0xEB63, 0x96C0, 0xC8B8, 0x96C1, 0xD1E3, 0x96C2, 0xEB64, 0x96C3, 0xEB65, 0x96C4, 0xD0DB, 0x96C5, 0xD1C5, 0x96C6, 0xBCAF, 0x96C7, 0xB9CD, 0x96C8, 0xEB66, 0x96C9, 0xEFF4, 0x96CA, 0xEB67, 0x96CB, 0xEB68, 0x96CC, 0xB4C6, 0x96CD, 0xD3BA, 0x96CE, 0xF6C2, 0x96CF, 0xB3FB, 0x96D0, 0xEB69, 0x96D1, 0xEB6A, 0x96D2, 0xF6C3, 0x96D3, 0xEB6B, 0x96D4, 0xEB6C, 0x96D5, 0xB5F1, 0x96D6, 0xEB6D, 0x96D7, 0xEB6E, 0x96D8, 0xEB6F, 0x96D9, 0xEB70, 0x96DA, 0xEB71, 0x96DB, 0xEB72, 0x96DC, 0xEB73, 0x96DD, 0xEB74, 0x96DE, 0xEB75, 0x96DF, 0xEB76, 0x96E0, 0xF6C5, 0x96E1, 0xEB77, 0x96E2, 0xEB78, 0x96E3, 0xEB79, 0x96E4, 0xEB7A, 0x96E5, 0xEB7B, 0x96E6, 0xEB7C, 0x96E7, 0xEB7D, 0x96E8, 0xD3EA, 0x96E9, 0xF6A7, 0x96EA, 0xD1A9, 0x96EB, 0xEB7E, 0x96EC, 0xEB80, 0x96ED, 0xEB81, 0x96EE, 0xEB82, 0x96EF, 0xF6A9, 0x96F0, 0xEB83, 0x96F1, 0xEB84, 0x96F2, 0xEB85, 0x96F3, 0xF6A8, 0x96F4, 0xEB86, 0x96F5, 0xEB87, 0x96F6, 0xC1E3, 0x96F7, 0xC0D7, 0x96F8, 0xEB88, 0x96F9, 0xB1A2, 0x96FA, 0xEB89, 0x96FB, 0xEB8A, 0x96FC, 0xEB8B, 0x96FD, 0xEB8C, 0x96FE, 0xCEED, 0x96FF, 0xEB8D, 0x9700, 0xD0E8, 0x9701, 0xF6AB, 0x9702, 0xEB8E, 0x9703, 0xEB8F, 0x9704, 0xCFF6, 0x9705, 0xEB90, 0x9706, 0xF6AA, 0x9707, 0xD5F0, 0x9708, 0xF6AC, 0x9709, 0xC3B9, 0x970A, 0xEB91, 0x970B, 0xEB92, 0x970C, 0xEB93, 0x970D, 0xBBF4, 0x970E, 0xF6AE, 0x970F, 0xF6AD, 0x9710, 0xEB94, 0x9711, 0xEB95, 0x9712, 0xEB96, 0x9713, 0xC4DE, 0x9714, 0xEB97, 0x9715, 0xEB98, 0x9716, 0xC1D8, 0x9717, 0xEB99, 0x9718, 0xEB9A, 0x9719, 0xEB9B, 0x971A, 0xEB9C, 0x971B, 0xEB9D, 0x971C, 0xCBAA, 0x971D, 0xEB9E, 0x971E, 0xCFBC, 0x971F, 0xEB9F, 0x9720, 0xEBA0, 0x9721, 0xEC40, 0x9722, 0xEC41, 0x9723, 0xEC42, 0x9724, 0xEC43, 0x9725, 0xEC44, 0x9726, 0xEC45, 0x9727, 0xEC46, 0x9728, 0xEC47, 0x9729, 0xEC48, 0x972A, 0xF6AF, 0x972B, 0xEC49, 0x972C, 0xEC4A, 0x972D, 0xF6B0, 0x972E, 0xEC4B, 0x972F, 0xEC4C, 0x9730, 0xF6B1, 0x9731, 0xEC4D, 0x9732, 0xC2B6, 0x9733, 0xEC4E, 0x9734, 0xEC4F, 0x9735, 0xEC50, 0x9736, 0xEC51, 0x9737, 0xEC52, 0x9738, 0xB0D4, 0x9739, 0xC5F9, 0x973A, 0xEC53, 0x973B, 0xEC54, 0x973C, 0xEC55, 0x973D, 0xEC56, 0x973E, 0xF6B2, 0x973F, 0xEC57, 0x9740, 0xEC58, 0x9741, 0xEC59, 0x9742, 0xEC5A, 0x9743, 0xEC5B, 0x9744, 0xEC5C, 0x9745, 0xEC5D, 0x9746, 0xEC5E, 0x9747, 0xEC5F, 0x9748, 0xEC60, 0x9749, 0xEC61, 0x974A, 0xEC62, 0x974B, 0xEC63, 0x974C, 0xEC64, 0x974D, 0xEC65, 0x974E, 0xEC66, 0x974F, 0xEC67, 0x9750, 0xEC68, 0x9751, 0xEC69, 0x9752, 0xC7E0, 0x9753, 0xF6A6, 0x9754, 0xEC6A, 0x9755, 0xEC6B, 0x9756, 0xBEB8, 0x9757, 0xEC6C, 0x9758, 0xEC6D, 0x9759, 0xBEB2, 0x975A, 0xEC6E, 0x975B, 0xB5E5, 0x975C, 0xEC6F, 0x975D, 0xEC70, 0x975E, 0xB7C7, 0x975F, 0xEC71, 0x9760, 0xBFBF, 0x9761, 0xC3D2, 0x9762, 0xC3E6, 0x9763, 0xEC72, 0x9764, 0xEC73, 0x9765, 0xD8CC, 0x9766, 0xEC74, 0x9767, 0xEC75, 0x9768, 0xEC76, 0x9769, 0xB8EF, 0x976A, 0xEC77, 0x976B, 0xEC78, 0x976C, 0xEC79, 0x976D, 0xEC7A, 0x976E, 0xEC7B, 0x976F, 0xEC7C, 0x9770, 0xEC7D, 0x9771, 0xEC7E, 0x9772, 0xEC80, 0x9773, 0xBDF9, 0x9774, 0xD1A5, 0x9775, 0xEC81, 0x9776, 0xB0D0, 0x9777, 0xEC82, 0x9778, 0xEC83, 0x9779, 0xEC84, 0x977A, 0xEC85, 0x977B, 0xEC86, 0x977C, 0xF7B0, 0x977D, 0xEC87, 0x977E, 0xEC88, 0x977F, 0xEC89, 0x9780, 0xEC8A, 0x9781, 0xEC8B, 0x9782, 0xEC8C, 0x9783, 0xEC8D, 0x9784, 0xEC8E, 0x9785, 0xF7B1, 0x9786, 0xEC8F, 0x9787, 0xEC90, 0x9788, 0xEC91, 0x9789, 0xEC92, 0x978A, 0xEC93, 0x978B, 0xD0AC, 0x978C, 0xEC94, 0x978D, 0xB0B0, 0x978E, 0xEC95, 0x978F, 0xEC96, 0x9790, 0xEC97, 0x9791, 0xF7B2, 0x9792, 0xF7B3, 0x9793, 0xEC98, 0x9794, 0xF7B4, 0x9795, 0xEC99, 0x9796, 0xEC9A, 0x9797, 0xEC9B, 0x9798, 0xC7CA, 0x9799, 0xEC9C, 0x979A, 0xEC9D, 0x979B, 0xEC9E, 0x979C, 0xEC9F, 0x979D, 0xECA0, 0x979E, 0xED40, 0x979F, 0xED41, 0x97A0, 0xBECF, 0x97A1, 0xED42, 0x97A2, 0xED43, 0x97A3, 0xF7B7, 0x97A4, 0xED44, 0x97A5, 0xED45, 0x97A6, 0xED46, 0x97A7, 0xED47, 0x97A8, 0xED48, 0x97A9, 0xED49, 0x97AA, 0xED4A, 0x97AB, 0xF7B6, 0x97AC, 0xED4B, 0x97AD, 0xB1DE, 0x97AE, 0xED4C, 0x97AF, 0xF7B5, 0x97B0, 0xED4D, 0x97B1, 0xED4E, 0x97B2, 0xF7B8, 0x97B3, 0xED4F, 0x97B4, 0xF7B9, 0x97B5, 0xED50, 0x97B6, 0xED51, 0x97B7, 0xED52, 0x97B8, 0xED53, 0x97B9, 0xED54, 0x97BA, 0xED55, 0x97BB, 0xED56, 0x97BC, 0xED57, 0x97BD, 0xED58, 0x97BE, 0xED59, 0x97BF, 0xED5A, 0x97C0, 0xED5B, 0x97C1, 0xED5C, 0x97C2, 0xED5D, 0x97C3, 0xED5E, 0x97C4, 0xED5F, 0x97C5, 0xED60, 0x97C6, 0xED61, 0x97C7, 0xED62, 0x97C8, 0xED63, 0x97C9, 0xED64, 0x97CA, 0xED65, 0x97CB, 0xED66, 0x97CC, 0xED67, 0x97CD, 0xED68, 0x97CE, 0xED69, 0x97CF, 0xED6A, 0x97D0, 0xED6B, 0x97D1, 0xED6C, 0x97D2, 0xED6D, 0x97D3, 0xED6E, 0x97D4, 0xED6F, 0x97D5, 0xED70, 0x97D6, 0xED71, 0x97D7, 0xED72, 0x97D8, 0xED73, 0x97D9, 0xED74, 0x97DA, 0xED75, 0x97DB, 0xED76, 0x97DC, 0xED77, 0x97DD, 0xED78, 0x97DE, 0xED79, 0x97DF, 0xED7A, 0x97E0, 0xED7B, 0x97E1, 0xED7C, 0x97E2, 0xED7D, 0x97E3, 0xED7E, 0x97E4, 0xED80, 0x97E5, 0xED81, 0x97E6, 0xCEA4, 0x97E7, 0xC8CD, 0x97E8, 0xED82, 0x97E9, 0xBAAB, 0x97EA, 0xE8B8, 0x97EB, 0xE8B9, 0x97EC, 0xE8BA, 0x97ED, 0xBEC2, 0x97EE, 0xED83, 0x97EF, 0xED84, 0x97F0, 0xED85, 0x97F1, 0xED86, 0x97F2, 0xED87, 0x97F3, 0xD2F4, 0x97F4, 0xED88, 0x97F5, 0xD4CF, 0x97F6, 0xC9D8, 0x97F7, 0xED89, 0x97F8, 0xED8A, 0x97F9, 0xED8B, 0x97FA, 0xED8C, 0x97FB, 0xED8D, 0x97FC, 0xED8E, 0x97FD, 0xED8F, 0x97FE, 0xED90, 0x97FF, 0xED91, 0x9800, 0xED92, 0x9801, 0xED93, 0x9802, 0xED94, 0x9803, 0xED95, 0x9804, 0xED96, 0x9805, 0xED97, 0x9806, 0xED98, 0x9807, 0xED99, 0x9808, 0xED9A, 0x9809, 0xED9B, 0x980A, 0xED9C, 0x980B, 0xED9D, 0x980C, 0xED9E, 0x980D, 0xED9F, 0x980E, 0xEDA0, 0x980F, 0xEE40, 0x9810, 0xEE41, 0x9811, 0xEE42, 0x9812, 0xEE43, 0x9813, 0xEE44, 0x9814, 0xEE45, 0x9815, 0xEE46, 0x9816, 0xEE47, 0x9817, 0xEE48, 0x9818, 0xEE49, 0x9819, 0xEE4A, 0x981A, 0xEE4B, 0x981B, 0xEE4C, 0x981C, 0xEE4D, 0x981D, 0xEE4E, 0x981E, 0xEE4F, 0x981F, 0xEE50, 0x9820, 0xEE51, 0x9821, 0xEE52, 0x9822, 0xEE53, 0x9823, 0xEE54, 0x9824, 0xEE55, 0x9825, 0xEE56, 0x9826, 0xEE57, 0x9827, 0xEE58, 0x9828, 0xEE59, 0x9829, 0xEE5A, 0x982A, 0xEE5B, 0x982B, 0xEE5C, 0x982C, 0xEE5D, 0x982D, 0xEE5E, 0x982E, 0xEE5F, 0x982F, 0xEE60, 0x9830, 0xEE61, 0x9831, 0xEE62, 0x9832, 0xEE63, 0x9833, 0xEE64, 0x9834, 0xEE65, 0x9835, 0xEE66, 0x9836, 0xEE67, 0x9837, 0xEE68, 0x9838, 0xEE69, 0x9839, 0xEE6A, 0x983A, 0xEE6B, 0x983B, 0xEE6C, 0x983C, 0xEE6D, 0x983D, 0xEE6E, 0x983E, 0xEE6F, 0x983F, 0xEE70, 0x9840, 0xEE71, 0x9841, 0xEE72, 0x9842, 0xEE73, 0x9843, 0xEE74, 0x9844, 0xEE75, 0x9845, 0xEE76, 0x9846, 0xEE77, 0x9847, 0xEE78, 0x9848, 0xEE79, 0x9849, 0xEE7A, 0x984A, 0xEE7B, 0x984B, 0xEE7C, 0x984C, 0xEE7D, 0x984D, 0xEE7E, 0x984E, 0xEE80, 0x984F, 0xEE81, 0x9850, 0xEE82, 0x9851, 0xEE83, 0x9852, 0xEE84, 0x9853, 0xEE85, 0x9854, 0xEE86, 0x9855, 0xEE87, 0x9856, 0xEE88, 0x9857, 0xEE89, 0x9858, 0xEE8A, 0x9859, 0xEE8B, 0x985A, 0xEE8C, 0x985B, 0xEE8D, 0x985C, 0xEE8E, 0x985D, 0xEE8F, 0x985E, 0xEE90, 0x985F, 0xEE91, 0x9860, 0xEE92, 0x9861, 0xEE93, 0x9862, 0xEE94, 0x9863, 0xEE95, 0x9864, 0xEE96, 0x9865, 0xEE97, 0x9866, 0xEE98, 0x9867, 0xEE99, 0x9868, 0xEE9A, 0x9869, 0xEE9B, 0x986A, 0xEE9C, 0x986B, 0xEE9D, 0x986C, 0xEE9E, 0x986D, 0xEE9F, 0x986E, 0xEEA0, 0x986F, 0xEF40, 0x9870, 0xEF41, 0x9871, 0xEF42, 0x9872, 0xEF43, 0x9873, 0xEF44, 0x9874, 0xEF45, 0x9875, 0xD2B3, 0x9876, 0xB6A5, 0x9877, 0xC7EA, 0x9878, 0xF1FC, 0x9879, 0xCFEE, 0x987A, 0xCBB3, 0x987B, 0xD0EB, 0x987C, 0xE7EF, 0x987D, 0xCDE7, 0x987E, 0xB9CB, 0x987F, 0xB6D9, 0x9880, 0xF1FD, 0x9881, 0xB0E4, 0x9882, 0xCBCC, 0x9883, 0xF1FE, 0x9884, 0xD4A4, 0x9885, 0xC2AD, 0x9886, 0xC1EC, 0x9887, 0xC6C4, 0x9888, 0xBEB1, 0x9889, 0xF2A1, 0x988A, 0xBCD5, 0x988B, 0xEF46, 0x988C, 0xF2A2, 0x988D, 0xF2A3, 0x988E, 0xEF47, 0x988F, 0xF2A4, 0x9890, 0xD2C3, 0x9891, 0xC6B5, 0x9892, 0xEF48, 0x9893, 0xCDC7, 0x9894, 0xF2A5, 0x9895, 0xEF49, 0x9896, 0xD3B1, 0x9897, 0xBFC5, 0x9898, 0xCCE2, 0x9899, 0xEF4A, 0x989A, 0xF2A6, 0x989B, 0xF2A7, 0x989C, 0xD1D5, 0x989D, 0xB6EE, 0x989E, 0xF2A8, 0x989F, 0xF2A9, 0x98A0, 0xB5DF, 0x98A1, 0xF2AA, 0x98A2, 0xF2AB, 0x98A3, 0xEF4B, 0x98A4, 0xB2FC, 0x98A5, 0xF2AC, 0x98A6, 0xF2AD, 0x98A7, 0xC8A7, 0x98A8, 0xEF4C, 0x98A9, 0xEF4D, 0x98AA, 0xEF4E, 0x98AB, 0xEF4F, 0x98AC, 0xEF50, 0x98AD, 0xEF51, 0x98AE, 0xEF52, 0x98AF, 0xEF53, 0x98B0, 0xEF54, 0x98B1, 0xEF55, 0x98B2, 0xEF56, 0x98B3, 0xEF57, 0x98B4, 0xEF58, 0x98B5, 0xEF59, 0x98B6, 0xEF5A, 0x98B7, 0xEF5B, 0x98B8, 0xEF5C, 0x98B9, 0xEF5D, 0x98BA, 0xEF5E, 0x98BB, 0xEF5F, 0x98BC, 0xEF60, 0x98BD, 0xEF61, 0x98BE, 0xEF62, 0x98BF, 0xEF63, 0x98C0, 0xEF64, 0x98C1, 0xEF65, 0x98C2, 0xEF66, 0x98C3, 0xEF67, 0x98C4, 0xEF68, 0x98C5, 0xEF69, 0x98C6, 0xEF6A, 0x98C7, 0xEF6B, 0x98C8, 0xEF6C, 0x98C9, 0xEF6D, 0x98CA, 0xEF6E, 0x98CB, 0xEF6F, 0x98CC, 0xEF70, 0x98CD, 0xEF71, 0x98CE, 0xB7E7, 0x98CF, 0xEF72, 0x98D0, 0xEF73, 0x98D1, 0xECA9, 0x98D2, 0xECAA, 0x98D3, 0xECAB, 0x98D4, 0xEF74, 0x98D5, 0xECAC, 0x98D6, 0xEF75, 0x98D7, 0xEF76, 0x98D8, 0xC6AE, 0x98D9, 0xECAD, 0x98DA, 0xECAE, 0x98DB, 0xEF77, 0x98DC, 0xEF78, 0x98DD, 0xEF79, 0x98DE, 0xB7C9, 0x98DF, 0xCAB3, 0x98E0, 0xEF7A, 0x98E1, 0xEF7B, 0x98E2, 0xEF7C, 0x98E3, 0xEF7D, 0x98E4, 0xEF7E, 0x98E5, 0xEF80, 0x98E6, 0xEF81, 0x98E7, 0xE2B8, 0x98E8, 0xF7CF, 0x98E9, 0xEF82, 0x98EA, 0xEF83, 0x98EB, 0xEF84, 0x98EC, 0xEF85, 0x98ED, 0xEF86, 0x98EE, 0xEF87, 0x98EF, 0xEF88, 0x98F0, 0xEF89, 0x98F1, 0xEF8A, 0x98F2, 0xEF8B, 0x98F3, 0xEF8C, 0x98F4, 0xEF8D, 0x98F5, 0xEF8E, 0x98F6, 0xEF8F, 0x98F7, 0xEF90, 0x98F8, 0xEF91, 0x98F9, 0xEF92, 0x98FA, 0xEF93, 0x98FB, 0xEF94, 0x98FC, 0xEF95, 0x98FD, 0xEF96, 0x98FE, 0xEF97, 0x98FF, 0xEF98, 0x9900, 0xEF99, 0x9901, 0xEF9A, 0x9902, 0xEF9B, 0x9903, 0xEF9C, 0x9904, 0xEF9D, 0x9905, 0xEF9E, 0x9906, 0xEF9F, 0x9907, 0xEFA0, 0x9908, 0xF040, 0x9909, 0xF041, 0x990A, 0xF042, 0x990B, 0xF043, 0x990C, 0xF044, 0x990D, 0xF7D0, 0x990E, 0xF045, 0x990F, 0xF046, 0x9910, 0xB2CD, 0x9911, 0xF047, 0x9912, 0xF048, 0x9913, 0xF049, 0x9914, 0xF04A, 0x9915, 0xF04B, 0x9916, 0xF04C, 0x9917, 0xF04D, 0x9918, 0xF04E, 0x9919, 0xF04F, 0x991A, 0xF050, 0x991B, 0xF051, 0x991C, 0xF052, 0x991D, 0xF053, 0x991E, 0xF054, 0x991F, 0xF055, 0x9920, 0xF056, 0x9921, 0xF057, 0x9922, 0xF058, 0x9923, 0xF059, 0x9924, 0xF05A, 0x9925, 0xF05B, 0x9926, 0xF05C, 0x9927, 0xF05D, 0x9928, 0xF05E, 0x9929, 0xF05F, 0x992A, 0xF060, 0x992B, 0xF061, 0x992C, 0xF062, 0x992D, 0xF063, 0x992E, 0xF7D1, 0x992F, 0xF064, 0x9930, 0xF065, 0x9931, 0xF066, 0x9932, 0xF067, 0x9933, 0xF068, 0x9934, 0xF069, 0x9935, 0xF06A, 0x9936, 0xF06B, 0x9937, 0xF06C, 0x9938, 0xF06D, 0x9939, 0xF06E, 0x993A, 0xF06F, 0x993B, 0xF070, 0x993C, 0xF071, 0x993D, 0xF072, 0x993E, 0xF073, 0x993F, 0xF074, 0x9940, 0xF075, 0x9941, 0xF076, 0x9942, 0xF077, 0x9943, 0xF078, 0x9944, 0xF079, 0x9945, 0xF07A, 0x9946, 0xF07B, 0x9947, 0xF07C, 0x9948, 0xF07D, 0x9949, 0xF07E, 0x994A, 0xF080, 0x994B, 0xF081, 0x994C, 0xF082, 0x994D, 0xF083, 0x994E, 0xF084, 0x994F, 0xF085, 0x9950, 0xF086, 0x9951, 0xF087, 0x9952, 0xF088, 0x9953, 0xF089, 0x9954, 0xF7D3, 0x9955, 0xF7D2, 0x9956, 0xF08A, 0x9957, 0xF08B, 0x9958, 0xF08C, 0x9959, 0xF08D, 0x995A, 0xF08E, 0x995B, 0xF08F, 0x995C, 0xF090, 0x995D, 0xF091, 0x995E, 0xF092, 0x995F, 0xF093, 0x9960, 0xF094, 0x9961, 0xF095, 0x9962, 0xF096, 0x9963, 0xE2BB, 0x9964, 0xF097, 0x9965, 0xBCA2, 0x9966, 0xF098, 0x9967, 0xE2BC, 0x9968, 0xE2BD, 0x9969, 0xE2BE, 0x996A, 0xE2BF, 0x996B, 0xE2C0, 0x996C, 0xE2C1, 0x996D, 0xB7B9, 0x996E, 0xD2FB, 0x996F, 0xBDA4, 0x9970, 0xCACE, 0x9971, 0xB1A5, 0x9972, 0xCBC7, 0x9973, 0xF099, 0x9974, 0xE2C2, 0x9975, 0xB6FC, 0x9976, 0xC8C4, 0x9977, 0xE2C3, 0x9978, 0xF09A, 0x9979, 0xF09B, 0x997A, 0xBDC8, 0x997B, 0xF09C, 0x997C, 0xB1FD, 0x997D, 0xE2C4, 0x997E, 0xF09D, 0x997F, 0xB6F6, 0x9980, 0xE2C5, 0x9981, 0xC4D9, 0x9982, 0xF09E, 0x9983, 0xF09F, 0x9984, 0xE2C6, 0x9985, 0xCFDA, 0x9986, 0xB9DD, 0x9987, 0xE2C7, 0x9988, 0xC0A1, 0x9989, 0xF0A0, 0x998A, 0xE2C8, 0x998B, 0xB2F6, 0x998C, 0xF140, 0x998D, 0xE2C9, 0x998E, 0xF141, 0x998F, 0xC1F3, 0x9990, 0xE2CA, 0x9991, 0xE2CB, 0x9992, 0xC2F8, 0x9993, 0xE2CC, 0x9994, 0xE2CD, 0x9995, 0xE2CE, 0x9996, 0xCAD7, 0x9997, 0xD8B8, 0x9998, 0xD9E5, 0x9999, 0xCFE3, 0x999A, 0xF142, 0x999B, 0xF143, 0x999C, 0xF144, 0x999D, 0xF145, 0x999E, 0xF146, 0x999F, 0xF147, 0x99A0, 0xF148, 0x99A1, 0xF149, 0x99A2, 0xF14A, 0x99A3, 0xF14B, 0x99A4, 0xF14C, 0x99A5, 0xF0A5, 0x99A6, 0xF14D, 0x99A7, 0xF14E, 0x99A8, 0xDCB0, 0x99A9, 0xF14F, 0x99AA, 0xF150, 0x99AB, 0xF151, 0x99AC, 0xF152, 0x99AD, 0xF153, 0x99AE, 0xF154, 0x99AF, 0xF155, 0x99B0, 0xF156, 0x99B1, 0xF157, 0x99B2, 0xF158, 0x99B3, 0xF159, 0x99B4, 0xF15A, 0x99B5, 0xF15B, 0x99B6, 0xF15C, 0x99B7, 0xF15D, 0x99B8, 0xF15E, 0x99B9, 0xF15F, 0x99BA, 0xF160, 0x99BB, 0xF161, 0x99BC, 0xF162, 0x99BD, 0xF163, 0x99BE, 0xF164, 0x99BF, 0xF165, 0x99C0, 0xF166, 0x99C1, 0xF167, 0x99C2, 0xF168, 0x99C3, 0xF169, 0x99C4, 0xF16A, 0x99C5, 0xF16B, 0x99C6, 0xF16C, 0x99C7, 0xF16D, 0x99C8, 0xF16E, 0x99C9, 0xF16F, 0x99CA, 0xF170, 0x99CB, 0xF171, 0x99CC, 0xF172, 0x99CD, 0xF173, 0x99CE, 0xF174, 0x99CF, 0xF175, 0x99D0, 0xF176, 0x99D1, 0xF177, 0x99D2, 0xF178, 0x99D3, 0xF179, 0x99D4, 0xF17A, 0x99D5, 0xF17B, 0x99D6, 0xF17C, 0x99D7, 0xF17D, 0x99D8, 0xF17E, 0x99D9, 0xF180, 0x99DA, 0xF181, 0x99DB, 0xF182, 0x99DC, 0xF183, 0x99DD, 0xF184, 0x99DE, 0xF185, 0x99DF, 0xF186, 0x99E0, 0xF187, 0x99E1, 0xF188, 0x99E2, 0xF189, 0x99E3, 0xF18A, 0x99E4, 0xF18B, 0x99E5, 0xF18C, 0x99E6, 0xF18D, 0x99E7, 0xF18E, 0x99E8, 0xF18F, 0x99E9, 0xF190, 0x99EA, 0xF191, 0x99EB, 0xF192, 0x99EC, 0xF193, 0x99ED, 0xF194, 0x99EE, 0xF195, 0x99EF, 0xF196, 0x99F0, 0xF197, 0x99F1, 0xF198, 0x99F2, 0xF199, 0x99F3, 0xF19A, 0x99F4, 0xF19B, 0x99F5, 0xF19C, 0x99F6, 0xF19D, 0x99F7, 0xF19E, 0x99F8, 0xF19F, 0x99F9, 0xF1A0, 0x99FA, 0xF240, 0x99FB, 0xF241, 0x99FC, 0xF242, 0x99FD, 0xF243, 0x99FE, 0xF244, 0x99FF, 0xF245, 0x9A00, 0xF246, 0x9A01, 0xF247, 0x9A02, 0xF248, 0x9A03, 0xF249, 0x9A04, 0xF24A, 0x9A05, 0xF24B, 0x9A06, 0xF24C, 0x9A07, 0xF24D, 0x9A08, 0xF24E, 0x9A09, 0xF24F, 0x9A0A, 0xF250, 0x9A0B, 0xF251, 0x9A0C, 0xF252, 0x9A0D, 0xF253, 0x9A0E, 0xF254, 0x9A0F, 0xF255, 0x9A10, 0xF256, 0x9A11, 0xF257, 0x9A12, 0xF258, 0x9A13, 0xF259, 0x9A14, 0xF25A, 0x9A15, 0xF25B, 0x9A16, 0xF25C, 0x9A17, 0xF25D, 0x9A18, 0xF25E, 0x9A19, 0xF25F, 0x9A1A, 0xF260, 0x9A1B, 0xF261, 0x9A1C, 0xF262, 0x9A1D, 0xF263, 0x9A1E, 0xF264, 0x9A1F, 0xF265, 0x9A20, 0xF266, 0x9A21, 0xF267, 0x9A22, 0xF268, 0x9A23, 0xF269, 0x9A24, 0xF26A, 0x9A25, 0xF26B, 0x9A26, 0xF26C, 0x9A27, 0xF26D, 0x9A28, 0xF26E, 0x9A29, 0xF26F, 0x9A2A, 0xF270, 0x9A2B, 0xF271, 0x9A2C, 0xF272, 0x9A2D, 0xF273, 0x9A2E, 0xF274, 0x9A2F, 0xF275, 0x9A30, 0xF276, 0x9A31, 0xF277, 0x9A32, 0xF278, 0x9A33, 0xF279, 0x9A34, 0xF27A, 0x9A35, 0xF27B, 0x9A36, 0xF27C, 0x9A37, 0xF27D, 0x9A38, 0xF27E, 0x9A39, 0xF280, 0x9A3A, 0xF281, 0x9A3B, 0xF282, 0x9A3C, 0xF283, 0x9A3D, 0xF284, 0x9A3E, 0xF285, 0x9A3F, 0xF286, 0x9A40, 0xF287, 0x9A41, 0xF288, 0x9A42, 0xF289, 0x9A43, 0xF28A, 0x9A44, 0xF28B, 0x9A45, 0xF28C, 0x9A46, 0xF28D, 0x9A47, 0xF28E, 0x9A48, 0xF28F, 0x9A49, 0xF290, 0x9A4A, 0xF291, 0x9A4B, 0xF292, 0x9A4C, 0xF293, 0x9A4D, 0xF294, 0x9A4E, 0xF295, 0x9A4F, 0xF296, 0x9A50, 0xF297, 0x9A51, 0xF298, 0x9A52, 0xF299, 0x9A53, 0xF29A, 0x9A54, 0xF29B, 0x9A55, 0xF29C, 0x9A56, 0xF29D, 0x9A57, 0xF29E, 0x9A58, 0xF29F, 0x9A59, 0xF2A0, 0x9A5A, 0xF340, 0x9A5B, 0xF341, 0x9A5C, 0xF342, 0x9A5D, 0xF343, 0x9A5E, 0xF344, 0x9A5F, 0xF345, 0x9A60, 0xF346, 0x9A61, 0xF347, 0x9A62, 0xF348, 0x9A63, 0xF349, 0x9A64, 0xF34A, 0x9A65, 0xF34B, 0x9A66, 0xF34C, 0x9A67, 0xF34D, 0x9A68, 0xF34E, 0x9A69, 0xF34F, 0x9A6A, 0xF350, 0x9A6B, 0xF351, 0x9A6C, 0xC2ED, 0x9A6D, 0xD4A6, 0x9A6E, 0xCDD4, 0x9A6F, 0xD1B1, 0x9A70, 0xB3DB, 0x9A71, 0xC7FD, 0x9A72, 0xF352, 0x9A73, 0xB2B5, 0x9A74, 0xC2BF, 0x9A75, 0xE6E0, 0x9A76, 0xCABB, 0x9A77, 0xE6E1, 0x9A78, 0xE6E2, 0x9A79, 0xBED4, 0x9A7A, 0xE6E3, 0x9A7B, 0xD7A4, 0x9A7C, 0xCDD5, 0x9A7D, 0xE6E5, 0x9A7E, 0xBCDD, 0x9A7F, 0xE6E4, 0x9A80, 0xE6E6, 0x9A81, 0xE6E7, 0x9A82, 0xC2EE, 0x9A83, 0xF353, 0x9A84, 0xBDBE, 0x9A85, 0xE6E8, 0x9A86, 0xC2E6, 0x9A87, 0xBAA7, 0x9A88, 0xE6E9, 0x9A89, 0xF354, 0x9A8A, 0xE6EA, 0x9A8B, 0xB3D2, 0x9A8C, 0xD1E9, 0x9A8D, 0xF355, 0x9A8E, 0xF356, 0x9A8F, 0xBFA5, 0x9A90, 0xE6EB, 0x9A91, 0xC6EF, 0x9A92, 0xE6EC, 0x9A93, 0xE6ED, 0x9A94, 0xF357, 0x9A95, 0xF358, 0x9A96, 0xE6EE, 0x9A97, 0xC6AD, 0x9A98, 0xE6EF, 0x9A99, 0xF359, 0x9A9A, 0xC9A7, 0x9A9B, 0xE6F0, 0x9A9C, 0xE6F1, 0x9A9D, 0xE6F2, 0x9A9E, 0xE5B9, 0x9A9F, 0xE6F3, 0x9AA0, 0xE6F4, 0x9AA1, 0xC2E2, 0x9AA2, 0xE6F5, 0x9AA3, 0xE6F6, 0x9AA4, 0xD6E8, 0x9AA5, 0xE6F7, 0x9AA6, 0xF35A, 0x9AA7, 0xE6F8, 0x9AA8, 0xB9C7, 0x9AA9, 0xF35B, 0x9AAA, 0xF35C, 0x9AAB, 0xF35D, 0x9AAC, 0xF35E, 0x9AAD, 0xF35F, 0x9AAE, 0xF360, 0x9AAF, 0xF361, 0x9AB0, 0xF7BB, 0x9AB1, 0xF7BA, 0x9AB2, 0xF362, 0x9AB3, 0xF363, 0x9AB4, 0xF364, 0x9AB5, 0xF365, 0x9AB6, 0xF7BE, 0x9AB7, 0xF7BC, 0x9AB8, 0xBAA1, 0x9AB9, 0xF366, 0x9ABA, 0xF7BF, 0x9ABB, 0xF367, 0x9ABC, 0xF7C0, 0x9ABD, 0xF368, 0x9ABE, 0xF369, 0x9ABF, 0xF36A, 0x9AC0, 0xF7C2, 0x9AC1, 0xF7C1, 0x9AC2, 0xF7C4, 0x9AC3, 0xF36B, 0x9AC4, 0xF36C, 0x9AC5, 0xF7C3, 0x9AC6, 0xF36D, 0x9AC7, 0xF36E, 0x9AC8, 0xF36F, 0x9AC9, 0xF370, 0x9ACA, 0xF371, 0x9ACB, 0xF7C5, 0x9ACC, 0xF7C6, 0x9ACD, 0xF372, 0x9ACE, 0xF373, 0x9ACF, 0xF374, 0x9AD0, 0xF375, 0x9AD1, 0xF7C7, 0x9AD2, 0xF376, 0x9AD3, 0xCBE8, 0x9AD4, 0xF377, 0x9AD5, 0xF378, 0x9AD6, 0xF379, 0x9AD7, 0xF37A, 0x9AD8, 0xB8DF, 0x9AD9, 0xF37B, 0x9ADA, 0xF37C, 0x9ADB, 0xF37D, 0x9ADC, 0xF37E, 0x9ADD, 0xF380, 0x9ADE, 0xF381, 0x9ADF, 0xF7D4, 0x9AE0, 0xF382, 0x9AE1, 0xF7D5, 0x9AE2, 0xF383, 0x9AE3, 0xF384, 0x9AE4, 0xF385, 0x9AE5, 0xF386, 0x9AE6, 0xF7D6, 0x9AE7, 0xF387, 0x9AE8, 0xF388, 0x9AE9, 0xF389, 0x9AEA, 0xF38A, 0x9AEB, 0xF7D8, 0x9AEC, 0xF38B, 0x9AED, 0xF7DA, 0x9AEE, 0xF38C, 0x9AEF, 0xF7D7, 0x9AF0, 0xF38D, 0x9AF1, 0xF38E, 0x9AF2, 0xF38F, 0x9AF3, 0xF390, 0x9AF4, 0xF391, 0x9AF5, 0xF392, 0x9AF6, 0xF393, 0x9AF7, 0xF394, 0x9AF8, 0xF395, 0x9AF9, 0xF7DB, 0x9AFA, 0xF396, 0x9AFB, 0xF7D9, 0x9AFC, 0xF397, 0x9AFD, 0xF398, 0x9AFE, 0xF399, 0x9AFF, 0xF39A, 0x9B00, 0xF39B, 0x9B01, 0xF39C, 0x9B02, 0xF39D, 0x9B03, 0xD7D7, 0x9B04, 0xF39E, 0x9B05, 0xF39F, 0x9B06, 0xF3A0, 0x9B07, 0xF440, 0x9B08, 0xF7DC, 0x9B09, 0xF441, 0x9B0A, 0xF442, 0x9B0B, 0xF443, 0x9B0C, 0xF444, 0x9B0D, 0xF445, 0x9B0E, 0xF446, 0x9B0F, 0xF7DD, 0x9B10, 0xF447, 0x9B11, 0xF448, 0x9B12, 0xF449, 0x9B13, 0xF7DE, 0x9B14, 0xF44A, 0x9B15, 0xF44B, 0x9B16, 0xF44C, 0x9B17, 0xF44D, 0x9B18, 0xF44E, 0x9B19, 0xF44F, 0x9B1A, 0xF450, 0x9B1B, 0xF451, 0x9B1C, 0xF452, 0x9B1D, 0xF453, 0x9B1E, 0xF454, 0x9B1F, 0xF7DF, 0x9B20, 0xF455, 0x9B21, 0xF456, 0x9B22, 0xF457, 0x9B23, 0xF7E0, 0x9B24, 0xF458, 0x9B25, 0xF459, 0x9B26, 0xF45A, 0x9B27, 0xF45B, 0x9B28, 0xF45C, 0x9B29, 0xF45D, 0x9B2A, 0xF45E, 0x9B2B, 0xF45F, 0x9B2C, 0xF460, 0x9B2D, 0xF461, 0x9B2E, 0xF462, 0x9B2F, 0xDBCB, 0x9B30, 0xF463, 0x9B31, 0xF464, 0x9B32, 0xD8AA, 0x9B33, 0xF465, 0x9B34, 0xF466, 0x9B35, 0xF467, 0x9B36, 0xF468, 0x9B37, 0xF469, 0x9B38, 0xF46A, 0x9B39, 0xF46B, 0x9B3A, 0xF46C, 0x9B3B, 0xE5F7, 0x9B3C, 0xB9ED, 0x9B3D, 0xF46D, 0x9B3E, 0xF46E, 0x9B3F, 0xF46F, 0x9B40, 0xF470, 0x9B41, 0xBFFD, 0x9B42, 0xBBEA, 0x9B43, 0xF7C9, 0x9B44, 0xC6C7, 0x9B45, 0xF7C8, 0x9B46, 0xF471, 0x9B47, 0xF7CA, 0x9B48, 0xF7CC, 0x9B49, 0xF7CB, 0x9B4A, 0xF472, 0x9B4B, 0xF473, 0x9B4C, 0xF474, 0x9B4D, 0xF7CD, 0x9B4E, 0xF475, 0x9B4F, 0xCEBA, 0x9B50, 0xF476, 0x9B51, 0xF7CE, 0x9B52, 0xF477, 0x9B53, 0xF478, 0x9B54, 0xC4A7, 0x9B55, 0xF479, 0x9B56, 0xF47A, 0x9B57, 0xF47B, 0x9B58, 0xF47C, 0x9B59, 0xF47D, 0x9B5A, 0xF47E, 0x9B5B, 0xF480, 0x9B5C, 0xF481, 0x9B5D, 0xF482, 0x9B5E, 0xF483, 0x9B5F, 0xF484, 0x9B60, 0xF485, 0x9B61, 0xF486, 0x9B62, 0xF487, 0x9B63, 0xF488, 0x9B64, 0xF489, 0x9B65, 0xF48A, 0x9B66, 0xF48B, 0x9B67, 0xF48C, 0x9B68, 0xF48D, 0x9B69, 0xF48E, 0x9B6A, 0xF48F, 0x9B6B, 0xF490, 0x9B6C, 0xF491, 0x9B6D, 0xF492, 0x9B6E, 0xF493, 0x9B6F, 0xF494, 0x9B70, 0xF495, 0x9B71, 0xF496, 0x9B72, 0xF497, 0x9B73, 0xF498, 0x9B74, 0xF499, 0x9B75, 0xF49A, 0x9B76, 0xF49B, 0x9B77, 0xF49C, 0x9B78, 0xF49D, 0x9B79, 0xF49E, 0x9B7A, 0xF49F, 0x9B7B, 0xF4A0, 0x9B7C, 0xF540, 0x9B7D, 0xF541, 0x9B7E, 0xF542, 0x9B7F, 0xF543, 0x9B80, 0xF544, 0x9B81, 0xF545, 0x9B82, 0xF546, 0x9B83, 0xF547, 0x9B84, 0xF548, 0x9B85, 0xF549, 0x9B86, 0xF54A, 0x9B87, 0xF54B, 0x9B88, 0xF54C, 0x9B89, 0xF54D, 0x9B8A, 0xF54E, 0x9B8B, 0xF54F, 0x9B8C, 0xF550, 0x9B8D, 0xF551, 0x9B8E, 0xF552, 0x9B8F, 0xF553, 0x9B90, 0xF554, 0x9B91, 0xF555, 0x9B92, 0xF556, 0x9B93, 0xF557, 0x9B94, 0xF558, 0x9B95, 0xF559, 0x9B96, 0xF55A, 0x9B97, 0xF55B, 0x9B98, 0xF55C, 0x9B99, 0xF55D, 0x9B9A, 0xF55E, 0x9B9B, 0xF55F, 0x9B9C, 0xF560, 0x9B9D, 0xF561, 0x9B9E, 0xF562, 0x9B9F, 0xF563, 0x9BA0, 0xF564, 0x9BA1, 0xF565, 0x9BA2, 0xF566, 0x9BA3, 0xF567, 0x9BA4, 0xF568, 0x9BA5, 0xF569, 0x9BA6, 0xF56A, 0x9BA7, 0xF56B, 0x9BA8, 0xF56C, 0x9BA9, 0xF56D, 0x9BAA, 0xF56E, 0x9BAB, 0xF56F, 0x9BAC, 0xF570, 0x9BAD, 0xF571, 0x9BAE, 0xF572, 0x9BAF, 0xF573, 0x9BB0, 0xF574, 0x9BB1, 0xF575, 0x9BB2, 0xF576, 0x9BB3, 0xF577, 0x9BB4, 0xF578, 0x9BB5, 0xF579, 0x9BB6, 0xF57A, 0x9BB7, 0xF57B, 0x9BB8, 0xF57C, 0x9BB9, 0xF57D, 0x9BBA, 0xF57E, 0x9BBB, 0xF580, 0x9BBC, 0xF581, 0x9BBD, 0xF582, 0x9BBE, 0xF583, 0x9BBF, 0xF584, 0x9BC0, 0xF585, 0x9BC1, 0xF586, 0x9BC2, 0xF587, 0x9BC3, 0xF588, 0x9BC4, 0xF589, 0x9BC5, 0xF58A, 0x9BC6, 0xF58B, 0x9BC7, 0xF58C, 0x9BC8, 0xF58D, 0x9BC9, 0xF58E, 0x9BCA, 0xF58F, 0x9BCB, 0xF590, 0x9BCC, 0xF591, 0x9BCD, 0xF592, 0x9BCE, 0xF593, 0x9BCF, 0xF594, 0x9BD0, 0xF595, 0x9BD1, 0xF596, 0x9BD2, 0xF597, 0x9BD3, 0xF598, 0x9BD4, 0xF599, 0x9BD5, 0xF59A, 0x9BD6, 0xF59B, 0x9BD7, 0xF59C, 0x9BD8, 0xF59D, 0x9BD9, 0xF59E, 0x9BDA, 0xF59F, 0x9BDB, 0xF5A0, 0x9BDC, 0xF640, 0x9BDD, 0xF641, 0x9BDE, 0xF642, 0x9BDF, 0xF643, 0x9BE0, 0xF644, 0x9BE1, 0xF645, 0x9BE2, 0xF646, 0x9BE3, 0xF647, 0x9BE4, 0xF648, 0x9BE5, 0xF649, 0x9BE6, 0xF64A, 0x9BE7, 0xF64B, 0x9BE8, 0xF64C, 0x9BE9, 0xF64D, 0x9BEA, 0xF64E, 0x9BEB, 0xF64F, 0x9BEC, 0xF650, 0x9BED, 0xF651, 0x9BEE, 0xF652, 0x9BEF, 0xF653, 0x9BF0, 0xF654, 0x9BF1, 0xF655, 0x9BF2, 0xF656, 0x9BF3, 0xF657, 0x9BF4, 0xF658, 0x9BF5, 0xF659, 0x9BF6, 0xF65A, 0x9BF7, 0xF65B, 0x9BF8, 0xF65C, 0x9BF9, 0xF65D, 0x9BFA, 0xF65E, 0x9BFB, 0xF65F, 0x9BFC, 0xF660, 0x9BFD, 0xF661, 0x9BFE, 0xF662, 0x9BFF, 0xF663, 0x9C00, 0xF664, 0x9C01, 0xF665, 0x9C02, 0xF666, 0x9C03, 0xF667, 0x9C04, 0xF668, 0x9C05, 0xF669, 0x9C06, 0xF66A, 0x9C07, 0xF66B, 0x9C08, 0xF66C, 0x9C09, 0xF66D, 0x9C0A, 0xF66E, 0x9C0B, 0xF66F, 0x9C0C, 0xF670, 0x9C0D, 0xF671, 0x9C0E, 0xF672, 0x9C0F, 0xF673, 0x9C10, 0xF674, 0x9C11, 0xF675, 0x9C12, 0xF676, 0x9C13, 0xF677, 0x9C14, 0xF678, 0x9C15, 0xF679, 0x9C16, 0xF67A, 0x9C17, 0xF67B, 0x9C18, 0xF67C, 0x9C19, 0xF67D, 0x9C1A, 0xF67E, 0x9C1B, 0xF680, 0x9C1C, 0xF681, 0x9C1D, 0xF682, 0x9C1E, 0xF683, 0x9C1F, 0xF684, 0x9C20, 0xF685, 0x9C21, 0xF686, 0x9C22, 0xF687, 0x9C23, 0xF688, 0x9C24, 0xF689, 0x9C25, 0xF68A, 0x9C26, 0xF68B, 0x9C27, 0xF68C, 0x9C28, 0xF68D, 0x9C29, 0xF68E, 0x9C2A, 0xF68F, 0x9C2B, 0xF690, 0x9C2C, 0xF691, 0x9C2D, 0xF692, 0x9C2E, 0xF693, 0x9C2F, 0xF694, 0x9C30, 0xF695, 0x9C31, 0xF696, 0x9C32, 0xF697, 0x9C33, 0xF698, 0x9C34, 0xF699, 0x9C35, 0xF69A, 0x9C36, 0xF69B, 0x9C37, 0xF69C, 0x9C38, 0xF69D, 0x9C39, 0xF69E, 0x9C3A, 0xF69F, 0x9C3B, 0xF6A0, 0x9C3C, 0xF740, 0x9C3D, 0xF741, 0x9C3E, 0xF742, 0x9C3F, 0xF743, 0x9C40, 0xF744, 0x9C41, 0xF745, 0x9C42, 0xF746, 0x9C43, 0xF747, 0x9C44, 0xF748, 0x9C45, 0xF749, 0x9C46, 0xF74A, 0x9C47, 0xF74B, 0x9C48, 0xF74C, 0x9C49, 0xF74D, 0x9C4A, 0xF74E, 0x9C4B, 0xF74F, 0x9C4C, 0xF750, 0x9C4D, 0xF751, 0x9C4E, 0xF752, 0x9C4F, 0xF753, 0x9C50, 0xF754, 0x9C51, 0xF755, 0x9C52, 0xF756, 0x9C53, 0xF757, 0x9C54, 0xF758, 0x9C55, 0xF759, 0x9C56, 0xF75A, 0x9C57, 0xF75B, 0x9C58, 0xF75C, 0x9C59, 0xF75D, 0x9C5A, 0xF75E, 0x9C5B, 0xF75F, 0x9C5C, 0xF760, 0x9C5D, 0xF761, 0x9C5E, 0xF762, 0x9C5F, 0xF763, 0x9C60, 0xF764, 0x9C61, 0xF765, 0x9C62, 0xF766, 0x9C63, 0xF767, 0x9C64, 0xF768, 0x9C65, 0xF769, 0x9C66, 0xF76A, 0x9C67, 0xF76B, 0x9C68, 0xF76C, 0x9C69, 0xF76D, 0x9C6A, 0xF76E, 0x9C6B, 0xF76F, 0x9C6C, 0xF770, 0x9C6D, 0xF771, 0x9C6E, 0xF772, 0x9C6F, 0xF773, 0x9C70, 0xF774, 0x9C71, 0xF775, 0x9C72, 0xF776, 0x9C73, 0xF777, 0x9C74, 0xF778, 0x9C75, 0xF779, 0x9C76, 0xF77A, 0x9C77, 0xF77B, 0x9C78, 0xF77C, 0x9C79, 0xF77D, 0x9C7A, 0xF77E, 0x9C7B, 0xF780, 0x9C7C, 0xD3E3, 0x9C7D, 0xF781, 0x9C7E, 0xF782, 0x9C7F, 0xF6CF, 0x9C80, 0xF783, 0x9C81, 0xC2B3, 0x9C82, 0xF6D0, 0x9C83, 0xF784, 0x9C84, 0xF785, 0x9C85, 0xF6D1, 0x9C86, 0xF6D2, 0x9C87, 0xF6D3, 0x9C88, 0xF6D4, 0x9C89, 0xF786, 0x9C8A, 0xF787, 0x9C8B, 0xF6D6, 0x9C8C, 0xF788, 0x9C8D, 0xB1AB, 0x9C8E, 0xF6D7, 0x9C8F, 0xF789, 0x9C90, 0xF6D8, 0x9C91, 0xF6D9, 0x9C92, 0xF6DA, 0x9C93, 0xF78A, 0x9C94, 0xF6DB, 0x9C95, 0xF6DC, 0x9C96, 0xF78B, 0x9C97, 0xF78C, 0x9C98, 0xF78D, 0x9C99, 0xF78E, 0x9C9A, 0xF6DD, 0x9C9B, 0xF6DE, 0x9C9C, 0xCFCA, 0x9C9D, 0xF78F, 0x9C9E, 0xF6DF, 0x9C9F, 0xF6E0, 0x9CA0, 0xF6E1, 0x9CA1, 0xF6E2, 0x9CA2, 0xF6E3, 0x9CA3, 0xF6E4, 0x9CA4, 0xC0F0, 0x9CA5, 0xF6E5, 0x9CA6, 0xF6E6, 0x9CA7, 0xF6E7, 0x9CA8, 0xF6E8, 0x9CA9, 0xF6E9, 0x9CAA, 0xF790, 0x9CAB, 0xF6EA, 0x9CAC, 0xF791, 0x9CAD, 0xF6EB, 0x9CAE, 0xF6EC, 0x9CAF, 0xF792, 0x9CB0, 0xF6ED, 0x9CB1, 0xF6EE, 0x9CB2, 0xF6EF, 0x9CB3, 0xF6F0, 0x9CB4, 0xF6F1, 0x9CB5, 0xF6F2, 0x9CB6, 0xF6F3, 0x9CB7, 0xF6F4, 0x9CB8, 0xBEA8, 0x9CB9, 0xF793, 0x9CBA, 0xF6F5, 0x9CBB, 0xF6F6, 0x9CBC, 0xF6F7, 0x9CBD, 0xF6F8, 0x9CBE, 0xF794, 0x9CBF, 0xF795, 0x9CC0, 0xF796, 0x9CC1, 0xF797, 0x9CC2, 0xF798, 0x9CC3, 0xC8FA, 0x9CC4, 0xF6F9, 0x9CC5, 0xF6FA, 0x9CC6, 0xF6FB, 0x9CC7, 0xF6FC, 0x9CC8, 0xF799, 0x9CC9, 0xF79A, 0x9CCA, 0xF6FD, 0x9CCB, 0xF6FE, 0x9CCC, 0xF7A1, 0x9CCD, 0xF7A2, 0x9CCE, 0xF7A3, 0x9CCF, 0xF7A4, 0x9CD0, 0xF7A5, 0x9CD1, 0xF79B, 0x9CD2, 0xF79C, 0x9CD3, 0xF7A6, 0x9CD4, 0xF7A7, 0x9CD5, 0xF7A8, 0x9CD6, 0xB1EE, 0x9CD7, 0xF7A9, 0x9CD8, 0xF7AA, 0x9CD9, 0xF7AB, 0x9CDA, 0xF79D, 0x9CDB, 0xF79E, 0x9CDC, 0xF7AC, 0x9CDD, 0xF7AD, 0x9CDE, 0xC1DB, 0x9CDF, 0xF7AE, 0x9CE0, 0xF79F, 0x9CE1, 0xF7A0, 0x9CE2, 0xF7AF, 0x9CE3, 0xF840, 0x9CE4, 0xF841, 0x9CE5, 0xF842, 0x9CE6, 0xF843, 0x9CE7, 0xF844, 0x9CE8, 0xF845, 0x9CE9, 0xF846, 0x9CEA, 0xF847, 0x9CEB, 0xF848, 0x9CEC, 0xF849, 0x9CED, 0xF84A, 0x9CEE, 0xF84B, 0x9CEF, 0xF84C, 0x9CF0, 0xF84D, 0x9CF1, 0xF84E, 0x9CF2, 0xF84F, 0x9CF3, 0xF850, 0x9CF4, 0xF851, 0x9CF5, 0xF852, 0x9CF6, 0xF853, 0x9CF7, 0xF854, 0x9CF8, 0xF855, 0x9CF9, 0xF856, 0x9CFA, 0xF857, 0x9CFB, 0xF858, 0x9CFC, 0xF859, 0x9CFD, 0xF85A, 0x9CFE, 0xF85B, 0x9CFF, 0xF85C, 0x9D00, 0xF85D, 0x9D01, 0xF85E, 0x9D02, 0xF85F, 0x9D03, 0xF860, 0x9D04, 0xF861, 0x9D05, 0xF862, 0x9D06, 0xF863, 0x9D07, 0xF864, 0x9D08, 0xF865, 0x9D09, 0xF866, 0x9D0A, 0xF867, 0x9D0B, 0xF868, 0x9D0C, 0xF869, 0x9D0D, 0xF86A, 0x9D0E, 0xF86B, 0x9D0F, 0xF86C, 0x9D10, 0xF86D, 0x9D11, 0xF86E, 0x9D12, 0xF86F, 0x9D13, 0xF870, 0x9D14, 0xF871, 0x9D15, 0xF872, 0x9D16, 0xF873, 0x9D17, 0xF874, 0x9D18, 0xF875, 0x9D19, 0xF876, 0x9D1A, 0xF877, 0x9D1B, 0xF878, 0x9D1C, 0xF879, 0x9D1D, 0xF87A, 0x9D1E, 0xF87B, 0x9D1F, 0xF87C, 0x9D20, 0xF87D, 0x9D21, 0xF87E, 0x9D22, 0xF880, 0x9D23, 0xF881, 0x9D24, 0xF882, 0x9D25, 0xF883, 0x9D26, 0xF884, 0x9D27, 0xF885, 0x9D28, 0xF886, 0x9D29, 0xF887, 0x9D2A, 0xF888, 0x9D2B, 0xF889, 0x9D2C, 0xF88A, 0x9D2D, 0xF88B, 0x9D2E, 0xF88C, 0x9D2F, 0xF88D, 0x9D30, 0xF88E, 0x9D31, 0xF88F, 0x9D32, 0xF890, 0x9D33, 0xF891, 0x9D34, 0xF892, 0x9D35, 0xF893, 0x9D36, 0xF894, 0x9D37, 0xF895, 0x9D38, 0xF896, 0x9D39, 0xF897, 0x9D3A, 0xF898, 0x9D3B, 0xF899, 0x9D3C, 0xF89A, 0x9D3D, 0xF89B, 0x9D3E, 0xF89C, 0x9D3F, 0xF89D, 0x9D40, 0xF89E, 0x9D41, 0xF89F, 0x9D42, 0xF8A0, 0x9D43, 0xF940, 0x9D44, 0xF941, 0x9D45, 0xF942, 0x9D46, 0xF943, 0x9D47, 0xF944, 0x9D48, 0xF945, 0x9D49, 0xF946, 0x9D4A, 0xF947, 0x9D4B, 0xF948, 0x9D4C, 0xF949, 0x9D4D, 0xF94A, 0x9D4E, 0xF94B, 0x9D4F, 0xF94C, 0x9D50, 0xF94D, 0x9D51, 0xF94E, 0x9D52, 0xF94F, 0x9D53, 0xF950, 0x9D54, 0xF951, 0x9D55, 0xF952, 0x9D56, 0xF953, 0x9D57, 0xF954, 0x9D58, 0xF955, 0x9D59, 0xF956, 0x9D5A, 0xF957, 0x9D5B, 0xF958, 0x9D5C, 0xF959, 0x9D5D, 0xF95A, 0x9D5E, 0xF95B, 0x9D5F, 0xF95C, 0x9D60, 0xF95D, 0x9D61, 0xF95E, 0x9D62, 0xF95F, 0x9D63, 0xF960, 0x9D64, 0xF961, 0x9D65, 0xF962, 0x9D66, 0xF963, 0x9D67, 0xF964, 0x9D68, 0xF965, 0x9D69, 0xF966, 0x9D6A, 0xF967, 0x9D6B, 0xF968, 0x9D6C, 0xF969, 0x9D6D, 0xF96A, 0x9D6E, 0xF96B, 0x9D6F, 0xF96C, 0x9D70, 0xF96D, 0x9D71, 0xF96E, 0x9D72, 0xF96F, 0x9D73, 0xF970, 0x9D74, 0xF971, 0x9D75, 0xF972, 0x9D76, 0xF973, 0x9D77, 0xF974, 0x9D78, 0xF975, 0x9D79, 0xF976, 0x9D7A, 0xF977, 0x9D7B, 0xF978, 0x9D7C, 0xF979, 0x9D7D, 0xF97A, 0x9D7E, 0xF97B, 0x9D7F, 0xF97C, 0x9D80, 0xF97D, 0x9D81, 0xF97E, 0x9D82, 0xF980, 0x9D83, 0xF981, 0x9D84, 0xF982, 0x9D85, 0xF983, 0x9D86, 0xF984, 0x9D87, 0xF985, 0x9D88, 0xF986, 0x9D89, 0xF987, 0x9D8A, 0xF988, 0x9D8B, 0xF989, 0x9D8C, 0xF98A, 0x9D8D, 0xF98B, 0x9D8E, 0xF98C, 0x9D8F, 0xF98D, 0x9D90, 0xF98E, 0x9D91, 0xF98F, 0x9D92, 0xF990, 0x9D93, 0xF991, 0x9D94, 0xF992, 0x9D95, 0xF993, 0x9D96, 0xF994, 0x9D97, 0xF995, 0x9D98, 0xF996, 0x9D99, 0xF997, 0x9D9A, 0xF998, 0x9D9B, 0xF999, 0x9D9C, 0xF99A, 0x9D9D, 0xF99B, 0x9D9E, 0xF99C, 0x9D9F, 0xF99D, 0x9DA0, 0xF99E, 0x9DA1, 0xF99F, 0x9DA2, 0xF9A0, 0x9DA3, 0xFA40, 0x9DA4, 0xFA41, 0x9DA5, 0xFA42, 0x9DA6, 0xFA43, 0x9DA7, 0xFA44, 0x9DA8, 0xFA45, 0x9DA9, 0xFA46, 0x9DAA, 0xFA47, 0x9DAB, 0xFA48, 0x9DAC, 0xFA49, 0x9DAD, 0xFA4A, 0x9DAE, 0xFA4B, 0x9DAF, 0xFA4C, 0x9DB0, 0xFA4D, 0x9DB1, 0xFA4E, 0x9DB2, 0xFA4F, 0x9DB3, 0xFA50, 0x9DB4, 0xFA51, 0x9DB5, 0xFA52, 0x9DB6, 0xFA53, 0x9DB7, 0xFA54, 0x9DB8, 0xFA55, 0x9DB9, 0xFA56, 0x9DBA, 0xFA57, 0x9DBB, 0xFA58, 0x9DBC, 0xFA59, 0x9DBD, 0xFA5A, 0x9DBE, 0xFA5B, 0x9DBF, 0xFA5C, 0x9DC0, 0xFA5D, 0x9DC1, 0xFA5E, 0x9DC2, 0xFA5F, 0x9DC3, 0xFA60, 0x9DC4, 0xFA61, 0x9DC5, 0xFA62, 0x9DC6, 0xFA63, 0x9DC7, 0xFA64, 0x9DC8, 0xFA65, 0x9DC9, 0xFA66, 0x9DCA, 0xFA67, 0x9DCB, 0xFA68, 0x9DCC, 0xFA69, 0x9DCD, 0xFA6A, 0x9DCE, 0xFA6B, 0x9DCF, 0xFA6C, 0x9DD0, 0xFA6D, 0x9DD1, 0xFA6E, 0x9DD2, 0xFA6F, 0x9DD3, 0xFA70, 0x9DD4, 0xFA71, 0x9DD5, 0xFA72, 0x9DD6, 0xFA73, 0x9DD7, 0xFA74, 0x9DD8, 0xFA75, 0x9DD9, 0xFA76, 0x9DDA, 0xFA77, 0x9DDB, 0xFA78, 0x9DDC, 0xFA79, 0x9DDD, 0xFA7A, 0x9DDE, 0xFA7B, 0x9DDF, 0xFA7C, 0x9DE0, 0xFA7D, 0x9DE1, 0xFA7E, 0x9DE2, 0xFA80, 0x9DE3, 0xFA81, 0x9DE4, 0xFA82, 0x9DE5, 0xFA83, 0x9DE6, 0xFA84, 0x9DE7, 0xFA85, 0x9DE8, 0xFA86, 0x9DE9, 0xFA87, 0x9DEA, 0xFA88, 0x9DEB, 0xFA89, 0x9DEC, 0xFA8A, 0x9DED, 0xFA8B, 0x9DEE, 0xFA8C, 0x9DEF, 0xFA8D, 0x9DF0, 0xFA8E, 0x9DF1, 0xFA8F, 0x9DF2, 0xFA90, 0x9DF3, 0xFA91, 0x9DF4, 0xFA92, 0x9DF5, 0xFA93, 0x9DF6, 0xFA94, 0x9DF7, 0xFA95, 0x9DF8, 0xFA96, 0x9DF9, 0xFA97, 0x9DFA, 0xFA98, 0x9DFB, 0xFA99, 0x9DFC, 0xFA9A, 0x9DFD, 0xFA9B, 0x9DFE, 0xFA9C, 0x9DFF, 0xFA9D, 0x9E00, 0xFA9E, 0x9E01, 0xFA9F, 0x9E02, 0xFAA0, 0x9E03, 0xFB40, 0x9E04, 0xFB41, 0x9E05, 0xFB42, 0x9E06, 0xFB43, 0x9E07, 0xFB44, 0x9E08, 0xFB45, 0x9E09, 0xFB46, 0x9E0A, 0xFB47, 0x9E0B, 0xFB48, 0x9E0C, 0xFB49, 0x9E0D, 0xFB4A, 0x9E0E, 0xFB4B, 0x9E0F, 0xFB4C, 0x9E10, 0xFB4D, 0x9E11, 0xFB4E, 0x9E12, 0xFB4F, 0x9E13, 0xFB50, 0x9E14, 0xFB51, 0x9E15, 0xFB52, 0x9E16, 0xFB53, 0x9E17, 0xFB54, 0x9E18, 0xFB55, 0x9E19, 0xFB56, 0x9E1A, 0xFB57, 0x9E1B, 0xFB58, 0x9E1C, 0xFB59, 0x9E1D, 0xFB5A, 0x9E1E, 0xFB5B, 0x9E1F, 0xC4F1, 0x9E20, 0xF0AF, 0x9E21, 0xBCA6, 0x9E22, 0xF0B0, 0x9E23, 0xC3F9, 0x9E24, 0xFB5C, 0x9E25, 0xC5B8, 0x9E26, 0xD1BB, 0x9E27, 0xFB5D, 0x9E28, 0xF0B1, 0x9E29, 0xF0B2, 0x9E2A, 0xF0B3, 0x9E2B, 0xF0B4, 0x9E2C, 0xF0B5, 0x9E2D, 0xD1BC, 0x9E2E, 0xFB5E, 0x9E2F, 0xD1EC, 0x9E30, 0xFB5F, 0x9E31, 0xF0B7, 0x9E32, 0xF0B6, 0x9E33, 0xD4A7, 0x9E34, 0xFB60, 0x9E35, 0xCDD2, 0x9E36, 0xF0B8, 0x9E37, 0xF0BA, 0x9E38, 0xF0B9, 0x9E39, 0xF0BB, 0x9E3A, 0xF0BC, 0x9E3B, 0xFB61, 0x9E3C, 0xFB62, 0x9E3D, 0xB8EB, 0x9E3E, 0xF0BD, 0x9E3F, 0xBAE8, 0x9E40, 0xFB63, 0x9E41, 0xF0BE, 0x9E42, 0xF0BF, 0x9E43, 0xBEE9, 0x9E44, 0xF0C0, 0x9E45, 0xB6EC, 0x9E46, 0xF0C1, 0x9E47, 0xF0C2, 0x9E48, 0xF0C3, 0x9E49, 0xF0C4, 0x9E4A, 0xC8B5, 0x9E4B, 0xF0C5, 0x9E4C, 0xF0C6, 0x9E4D, 0xFB64, 0x9E4E, 0xF0C7, 0x9E4F, 0xC5F4, 0x9E50, 0xFB65, 0x9E51, 0xF0C8, 0x9E52, 0xFB66, 0x9E53, 0xFB67, 0x9E54, 0xFB68, 0x9E55, 0xF0C9, 0x9E56, 0xFB69, 0x9E57, 0xF0CA, 0x9E58, 0xF7BD, 0x9E59, 0xFB6A, 0x9E5A, 0xF0CB, 0x9E5B, 0xF0CC, 0x9E5C, 0xF0CD, 0x9E5D, 0xFB6B, 0x9E5E, 0xF0CE, 0x9E5F, 0xFB6C, 0x9E60, 0xFB6D, 0x9E61, 0xFB6E, 0x9E62, 0xFB6F, 0x9E63, 0xF0CF, 0x9E64, 0xBAD7, 0x9E65, 0xFB70, 0x9E66, 0xF0D0, 0x9E67, 0xF0D1, 0x9E68, 0xF0D2, 0x9E69, 0xF0D3, 0x9E6A, 0xF0D4, 0x9E6B, 0xF0D5, 0x9E6C, 0xF0D6, 0x9E6D, 0xF0D8, 0x9E6E, 0xFB71, 0x9E6F, 0xFB72, 0x9E70, 0xD3A5, 0x9E71, 0xF0D7, 0x9E72, 0xFB73, 0x9E73, 0xF0D9, 0x9E74, 0xFB74, 0x9E75, 0xFB75, 0x9E76, 0xFB76, 0x9E77, 0xFB77, 0x9E78, 0xFB78, 0x9E79, 0xFB79, 0x9E7A, 0xFB7A, 0x9E7B, 0xFB7B, 0x9E7C, 0xFB7C, 0x9E7D, 0xFB7D, 0x9E7E, 0xF5BA, 0x9E7F, 0xC2B9, 0x9E80, 0xFB7E, 0x9E81, 0xFB80, 0x9E82, 0xF7E4, 0x9E83, 0xFB81, 0x9E84, 0xFB82, 0x9E85, 0xFB83, 0x9E86, 0xFB84, 0x9E87, 0xF7E5, 0x9E88, 0xF7E6, 0x9E89, 0xFB85, 0x9E8A, 0xFB86, 0x9E8B, 0xF7E7, 0x9E8C, 0xFB87, 0x9E8D, 0xFB88, 0x9E8E, 0xFB89, 0x9E8F, 0xFB8A, 0x9E90, 0xFB8B, 0x9E91, 0xFB8C, 0x9E92, 0xF7E8, 0x9E93, 0xC2B4, 0x9E94, 0xFB8D, 0x9E95, 0xFB8E, 0x9E96, 0xFB8F, 0x9E97, 0xFB90, 0x9E98, 0xFB91, 0x9E99, 0xFB92, 0x9E9A, 0xFB93, 0x9E9B, 0xFB94, 0x9E9C, 0xFB95, 0x9E9D, 0xF7EA, 0x9E9E, 0xFB96, 0x9E9F, 0xF7EB, 0x9EA0, 0xFB97, 0x9EA1, 0xFB98, 0x9EA2, 0xFB99, 0x9EA3, 0xFB9A, 0x9EA4, 0xFB9B, 0x9EA5, 0xFB9C, 0x9EA6, 0xC2F3, 0x9EA7, 0xFB9D, 0x9EA8, 0xFB9E, 0x9EA9, 0xFB9F, 0x9EAA, 0xFBA0, 0x9EAB, 0xFC40, 0x9EAC, 0xFC41, 0x9EAD, 0xFC42, 0x9EAE, 0xFC43, 0x9EAF, 0xFC44, 0x9EB0, 0xFC45, 0x9EB1, 0xFC46, 0x9EB2, 0xFC47, 0x9EB3, 0xFC48, 0x9EB4, 0xF4F0, 0x9EB5, 0xFC49, 0x9EB6, 0xFC4A, 0x9EB7, 0xFC4B, 0x9EB8, 0xF4EF, 0x9EB9, 0xFC4C, 0x9EBA, 0xFC4D, 0x9EBB, 0xC2E9, 0x9EBC, 0xFC4E, 0x9EBD, 0xF7E1, 0x9EBE, 0xF7E2, 0x9EBF, 0xFC4F, 0x9EC0, 0xFC50, 0x9EC1, 0xFC51, 0x9EC2, 0xFC52, 0x9EC3, 0xFC53, 0x9EC4, 0xBBC6, 0x9EC5, 0xFC54, 0x9EC6, 0xFC55, 0x9EC7, 0xFC56, 0x9EC8, 0xFC57, 0x9EC9, 0xD9E4, 0x9ECA, 0xFC58, 0x9ECB, 0xFC59, 0x9ECC, 0xFC5A, 0x9ECD, 0xCAF2, 0x9ECE, 0xC0E8, 0x9ECF, 0xF0A4, 0x9ED0, 0xFC5B, 0x9ED1, 0xBADA, 0x9ED2, 0xFC5C, 0x9ED3, 0xFC5D, 0x9ED4, 0xC7AD, 0x9ED5, 0xFC5E, 0x9ED6, 0xFC5F, 0x9ED7, 0xFC60, 0x9ED8, 0xC4AC, 0x9ED9, 0xFC61, 0x9EDA, 0xFC62, 0x9EDB, 0xF7EC, 0x9EDC, 0xF7ED, 0x9EDD, 0xF7EE, 0x9EDE, 0xFC63, 0x9EDF, 0xF7F0, 0x9EE0, 0xF7EF, 0x9EE1, 0xFC64, 0x9EE2, 0xF7F1, 0x9EE3, 0xFC65, 0x9EE4, 0xFC66, 0x9EE5, 0xF7F4, 0x9EE6, 0xFC67, 0x9EE7, 0xF7F3, 0x9EE8, 0xFC68, 0x9EE9, 0xF7F2, 0x9EEA, 0xF7F5, 0x9EEB, 0xFC69, 0x9EEC, 0xFC6A, 0x9EED, 0xFC6B, 0x9EEE, 0xFC6C, 0x9EEF, 0xF7F6, 0x9EF0, 0xFC6D, 0x9EF1, 0xFC6E, 0x9EF2, 0xFC6F, 0x9EF3, 0xFC70, 0x9EF4, 0xFC71, 0x9EF5, 0xFC72, 0x9EF6, 0xFC73, 0x9EF7, 0xFC74, 0x9EF8, 0xFC75, 0x9EF9, 0xEDE9, 0x9EFA, 0xFC76, 0x9EFB, 0xEDEA, 0x9EFC, 0xEDEB, 0x9EFD, 0xFC77, 0x9EFE, 0xF6BC, 0x9EFF, 0xFC78, 0x9F00, 0xFC79, 0x9F01, 0xFC7A, 0x9F02, 0xFC7B, 0x9F03, 0xFC7C, 0x9F04, 0xFC7D, 0x9F05, 0xFC7E, 0x9F06, 0xFC80, 0x9F07, 0xFC81, 0x9F08, 0xFC82, 0x9F09, 0xFC83, 0x9F0A, 0xFC84, 0x9F0B, 0xF6BD, 0x9F0C, 0xFC85, 0x9F0D, 0xF6BE, 0x9F0E, 0xB6A6, 0x9F0F, 0xFC86, 0x9F10, 0xD8BE, 0x9F11, 0xFC87, 0x9F12, 0xFC88, 0x9F13, 0xB9C4, 0x9F14, 0xFC89, 0x9F15, 0xFC8A, 0x9F16, 0xFC8B, 0x9F17, 0xD8BB, 0x9F18, 0xFC8C, 0x9F19, 0xDCB1, 0x9F1A, 0xFC8D, 0x9F1B, 0xFC8E, 0x9F1C, 0xFC8F, 0x9F1D, 0xFC90, 0x9F1E, 0xFC91, 0x9F1F, 0xFC92, 0x9F20, 0xCAF3, 0x9F21, 0xFC93, 0x9F22, 0xF7F7, 0x9F23, 0xFC94, 0x9F24, 0xFC95, 0x9F25, 0xFC96, 0x9F26, 0xFC97, 0x9F27, 0xFC98, 0x9F28, 0xFC99, 0x9F29, 0xFC9A, 0x9F2A, 0xFC9B, 0x9F2B, 0xFC9C, 0x9F2C, 0xF7F8, 0x9F2D, 0xFC9D, 0x9F2E, 0xFC9E, 0x9F2F, 0xF7F9, 0x9F30, 0xFC9F, 0x9F31, 0xFCA0, 0x9F32, 0xFD40, 0x9F33, 0xFD41, 0x9F34, 0xFD42, 0x9F35, 0xFD43, 0x9F36, 0xFD44, 0x9F37, 0xF7FB, 0x9F38, 0xFD45, 0x9F39, 0xF7FA, 0x9F3A, 0xFD46, 0x9F3B, 0xB1C7, 0x9F3C, 0xFD47, 0x9F3D, 0xF7FC, 0x9F3E, 0xF7FD, 0x9F3F, 0xFD48, 0x9F40, 0xFD49, 0x9F41, 0xFD4A, 0x9F42, 0xFD4B, 0x9F43, 0xFD4C, 0x9F44, 0xF7FE, 0x9F45, 0xFD4D, 0x9F46, 0xFD4E, 0x9F47, 0xFD4F, 0x9F48, 0xFD50, 0x9F49, 0xFD51, 0x9F4A, 0xFD52, 0x9F4B, 0xFD53, 0x9F4C, 0xFD54, 0x9F4D, 0xFD55, 0x9F4E, 0xFD56, 0x9F4F, 0xFD57, 0x9F50, 0xC6EB, 0x9F51, 0xECB4, 0x9F52, 0xFD58, 0x9F53, 0xFD59, 0x9F54, 0xFD5A, 0x9F55, 0xFD5B, 0x9F56, 0xFD5C, 0x9F57, 0xFD5D, 0x9F58, 0xFD5E, 0x9F59, 0xFD5F, 0x9F5A, 0xFD60, 0x9F5B, 0xFD61, 0x9F5C, 0xFD62, 0x9F5D, 0xFD63, 0x9F5E, 0xFD64, 0x9F5F, 0xFD65, 0x9F60, 0xFD66, 0x9F61, 0xFD67, 0x9F62, 0xFD68, 0x9F63, 0xFD69, 0x9F64, 0xFD6A, 0x9F65, 0xFD6B, 0x9F66, 0xFD6C, 0x9F67, 0xFD6D, 0x9F68, 0xFD6E, 0x9F69, 0xFD6F, 0x9F6A, 0xFD70, 0x9F6B, 0xFD71, 0x9F6C, 0xFD72, 0x9F6D, 0xFD73, 0x9F6E, 0xFD74, 0x9F6F, 0xFD75, 0x9F70, 0xFD76, 0x9F71, 0xFD77, 0x9F72, 0xFD78, 0x9F73, 0xFD79, 0x9F74, 0xFD7A, 0x9F75, 0xFD7B, 0x9F76, 0xFD7C, 0x9F77, 0xFD7D, 0x9F78, 0xFD7E, 0x9F79, 0xFD80, 0x9F7A, 0xFD81, 0x9F7B, 0xFD82, 0x9F7C, 0xFD83, 0x9F7D, 0xFD84, 0x9F7E, 0xFD85, 0x9F7F, 0xB3DD, 0x9F80, 0xF6B3, 0x9F81, 0xFD86, 0x9F82, 0xFD87, 0x9F83, 0xF6B4, 0x9F84, 0xC1E4, 0x9F85, 0xF6B5, 0x9F86, 0xF6B6, 0x9F87, 0xF6B7, 0x9F88, 0xF6B8, 0x9F89, 0xF6B9, 0x9F8A, 0xF6BA, 0x9F8B, 0xC8A3, 0x9F8C, 0xF6BB, 0x9F8D, 0xFD88, 0x9F8E, 0xFD89, 0x9F8F, 0xFD8A, 0x9F90, 0xFD8B, 0x9F91, 0xFD8C, 0x9F92, 0xFD8D, 0x9F93, 0xFD8E, 0x9F94, 0xFD8F, 0x9F95, 0xFD90, 0x9F96, 0xFD91, 0x9F97, 0xFD92, 0x9F98, 0xFD93, 0x9F99, 0xC1FA, 0x9F9A, 0xB9A8, 0x9F9B, 0xEDE8, 0x9F9C, 0xFD94, 0x9F9D, 0xFD95, 0x9F9E, 0xFD96, 0x9F9F, 0xB9EA, 0x9FA0, 0xD9DF, 0x9FA1, 0xFD97, 0x9FA2, 0xFD98, 0x9FA3, 0xFD99, 0x9FA4, 0xFD9A, 0x9FA5, 0xFD9B, 0xF92C, 0xFD9C, 0xF979, 0xFD9D, 0xF995, 0xFD9E, 0xF9E7, 0xFD9F, 0xF9F1, 0xFDA0, 0xFA0C, 0xFE40, 0xFA0D, 0xFE41, 0xFA0E, 0xFE42, 0xFA0F, 0xFE43, 0xFA11, 0xFE44, 0xFA13, 0xFE45, 0xFA14, 0xFE46, 0xFA18, 0xFE47, 0xFA1F, 0xFE48, 0xFA20, 0xFE49, 0xFA21, 0xFE4A, 0xFA23, 0xFE4B, 0xFA24, 0xFE4C, 0xFA27, 0xFE4D, 0xFA28, 0xFE4E, 0xFA29, 0xFE4F, 0xFE30, 0xA955, 0xFE31, 0xA6F2, 0xFE33, 0xA6F4, 0xFE34, 0xA6F5, 0xFE35, 0xA6E0, 0xFE36, 0xA6E1, 0xFE37, 0xA6F0, 0xFE38, 0xA6F1, 0xFE39, 0xA6E2, 0xFE3A, 0xA6E3, 0xFE3B, 0xA6EE, 0xFE3C, 0xA6EF, 0xFE3D, 0xA6E6, 0xFE3E, 0xA6E7, 0xFE3F, 0xA6E4, 0xFE40, 0xA6E5, 0xFE41, 0xA6E8, 0xFE42, 0xA6E9, 0xFE43, 0xA6EA, 0xFE44, 0xA6EB, 0xFE49, 0xA968, 0xFE4A, 0xA969, 0xFE4B, 0xA96A, 0xFE4C, 0xA96B, 0xFE4D, 0xA96C, 0xFE4E, 0xA96D, 0xFE4F, 0xA96E, 0xFE50, 0xA96F, 0xFE51, 0xA970, 0xFE52, 0xA971, 0xFE54, 0xA972, 0xFE55, 0xA973, 0xFE56, 0xA974, 0xFE57, 0xA975, 0xFE59, 0xA976, 0xFE5A, 0xA977, 0xFE5B, 0xA978, 0xFE5C, 0xA979, 0xFE5D, 0xA97A, 0xFE5E, 0xA97B, 0xFE5F, 0xA97C, 0xFE60, 0xA97D, 0xFE61, 0xA97E, 0xFE62, 0xA980, 0xFE63, 0xA981, 0xFE64, 0xA982, 0xFE65, 0xA983, 0xFE66, 0xA984, 0xFE68, 0xA985, 0xFE69, 0xA986, 0xFE6A, 0xA987, 0xFE6B, 0xA988, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA1E7, 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA3DC, 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, 0xFF5D, 0xA3FD, 0xFF5E, 0xA1AB, 0xFFE0, 0xA1E9, 0xFFE1, 0xA1EA, 0xFFE2, 0xA956, 0xFFE3, 0xA3FE, 0xFFE4, 0xA957, 0xFFE5, 0xA3A4, 0, 0 }; static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ 0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17, 0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F, 0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42, 0x8157, 0x4E44, 0x8158, 0x4E46, 0x8159, 0x4E4A, 0x815A, 0x4E51, 0x815B, 0x4E55, 0x815C, 0x4E57, 0x815D, 0x4E5A, 0x815E, 0x4E5B, 0x815F, 0x4E62, 0x8160, 0x4E63, 0x8161, 0x4E64, 0x8162, 0x4E65, 0x8163, 0x4E67, 0x8164, 0x4E68, 0x8165, 0x4E6A, 0x8166, 0x4E6B, 0x8167, 0x4E6C, 0x8168, 0x4E6D, 0x8169, 0x4E6E, 0x816A, 0x4E6F, 0x816B, 0x4E72, 0x816C, 0x4E74, 0x816D, 0x4E75, 0x816E, 0x4E76, 0x816F, 0x4E77, 0x8170, 0x4E78, 0x8171, 0x4E79, 0x8172, 0x4E7A, 0x8173, 0x4E7B, 0x8174, 0x4E7C, 0x8175, 0x4E7D, 0x8176, 0x4E7F, 0x8177, 0x4E80, 0x8178, 0x4E81, 0x8179, 0x4E82, 0x817A, 0x4E83, 0x817B, 0x4E84, 0x817C, 0x4E85, 0x817D, 0x4E87, 0x817E, 0x4E8A, 0x8180, 0x4E90, 0x8181, 0x4E96, 0x8182, 0x4E97, 0x8183, 0x4E99, 0x8184, 0x4E9C, 0x8185, 0x4E9D, 0x8186, 0x4E9E, 0x8187, 0x4EA3, 0x8188, 0x4EAA, 0x8189, 0x4EAF, 0x818A, 0x4EB0, 0x818B, 0x4EB1, 0x818C, 0x4EB4, 0x818D, 0x4EB6, 0x818E, 0x4EB7, 0x818F, 0x4EB8, 0x8190, 0x4EB9, 0x8191, 0x4EBC, 0x8192, 0x4EBD, 0x8193, 0x4EBE, 0x8194, 0x4EC8, 0x8195, 0x4ECC, 0x8196, 0x4ECF, 0x8197, 0x4ED0, 0x8198, 0x4ED2, 0x8199, 0x4EDA, 0x819A, 0x4EDB, 0x819B, 0x4EDC, 0x819C, 0x4EE0, 0x819D, 0x4EE2, 0x819E, 0x4EE6, 0x819F, 0x4EE7, 0x81A0, 0x4EE9, 0x81A1, 0x4EED, 0x81A2, 0x4EEE, 0x81A3, 0x4EEF, 0x81A4, 0x4EF1, 0x81A5, 0x4EF4, 0x81A6, 0x4EF8, 0x81A7, 0x4EF9, 0x81A8, 0x4EFA, 0x81A9, 0x4EFC, 0x81AA, 0x4EFE, 0x81AB, 0x4F00, 0x81AC, 0x4F02, 0x81AD, 0x4F03, 0x81AE, 0x4F04, 0x81AF, 0x4F05, 0x81B0, 0x4F06, 0x81B1, 0x4F07, 0x81B2, 0x4F08, 0x81B3, 0x4F0B, 0x81B4, 0x4F0C, 0x81B5, 0x4F12, 0x81B6, 0x4F13, 0x81B7, 0x4F14, 0x81B8, 0x4F15, 0x81B9, 0x4F16, 0x81BA, 0x4F1C, 0x81BB, 0x4F1D, 0x81BC, 0x4F21, 0x81BD, 0x4F23, 0x81BE, 0x4F28, 0x81BF, 0x4F29, 0x81C0, 0x4F2C, 0x81C1, 0x4F2D, 0x81C2, 0x4F2E, 0x81C3, 0x4F31, 0x81C4, 0x4F33, 0x81C5, 0x4F35, 0x81C6, 0x4F37, 0x81C7, 0x4F39, 0x81C8, 0x4F3B, 0x81C9, 0x4F3E, 0x81CA, 0x4F3F, 0x81CB, 0x4F40, 0x81CC, 0x4F41, 0x81CD, 0x4F42, 0x81CE, 0x4F44, 0x81CF, 0x4F45, 0x81D0, 0x4F47, 0x81D1, 0x4F48, 0x81D2, 0x4F49, 0x81D3, 0x4F4A, 0x81D4, 0x4F4B, 0x81D5, 0x4F4C, 0x81D6, 0x4F52, 0x81D7, 0x4F54, 0x81D8, 0x4F56, 0x81D9, 0x4F61, 0x81DA, 0x4F62, 0x81DB, 0x4F66, 0x81DC, 0x4F68, 0x81DD, 0x4F6A, 0x81DE, 0x4F6B, 0x81DF, 0x4F6D, 0x81E0, 0x4F6E, 0x81E1, 0x4F71, 0x81E2, 0x4F72, 0x81E3, 0x4F75, 0x81E4, 0x4F77, 0x81E5, 0x4F78, 0x81E6, 0x4F79, 0x81E7, 0x4F7A, 0x81E8, 0x4F7D, 0x81E9, 0x4F80, 0x81EA, 0x4F81, 0x81EB, 0x4F82, 0x81EC, 0x4F85, 0x81ED, 0x4F86, 0x81EE, 0x4F87, 0x81EF, 0x4F8A, 0x81F0, 0x4F8C, 0x81F1, 0x4F8E, 0x81F2, 0x4F90, 0x81F3, 0x4F92, 0x81F4, 0x4F93, 0x81F5, 0x4F95, 0x81F6, 0x4F96, 0x81F7, 0x4F98, 0x81F8, 0x4F99, 0x81F9, 0x4F9A, 0x81FA, 0x4F9C, 0x81FB, 0x4F9E, 0x81FC, 0x4F9F, 0x81FD, 0x4FA1, 0x81FE, 0x4FA2, 0x8240, 0x4FA4, 0x8241, 0x4FAB, 0x8242, 0x4FAD, 0x8243, 0x4FB0, 0x8244, 0x4FB1, 0x8245, 0x4FB2, 0x8246, 0x4FB3, 0x8247, 0x4FB4, 0x8248, 0x4FB6, 0x8249, 0x4FB7, 0x824A, 0x4FB8, 0x824B, 0x4FB9, 0x824C, 0x4FBA, 0x824D, 0x4FBB, 0x824E, 0x4FBC, 0x824F, 0x4FBD, 0x8250, 0x4FBE, 0x8251, 0x4FC0, 0x8252, 0x4FC1, 0x8253, 0x4FC2, 0x8254, 0x4FC6, 0x8255, 0x4FC7, 0x8256, 0x4FC8, 0x8257, 0x4FC9, 0x8258, 0x4FCB, 0x8259, 0x4FCC, 0x825A, 0x4FCD, 0x825B, 0x4FD2, 0x825C, 0x4FD3, 0x825D, 0x4FD4, 0x825E, 0x4FD5, 0x825F, 0x4FD6, 0x8260, 0x4FD9, 0x8261, 0x4FDB, 0x8262, 0x4FE0, 0x8263, 0x4FE2, 0x8264, 0x4FE4, 0x8265, 0x4FE5, 0x8266, 0x4FE7, 0x8267, 0x4FEB, 0x8268, 0x4FEC, 0x8269, 0x4FF0, 0x826A, 0x4FF2, 0x826B, 0x4FF4, 0x826C, 0x4FF5, 0x826D, 0x4FF6, 0x826E, 0x4FF7, 0x826F, 0x4FF9, 0x8270, 0x4FFB, 0x8271, 0x4FFC, 0x8272, 0x4FFD, 0x8273, 0x4FFF, 0x8274, 0x5000, 0x8275, 0x5001, 0x8276, 0x5002, 0x8277, 0x5003, 0x8278, 0x5004, 0x8279, 0x5005, 0x827A, 0x5006, 0x827B, 0x5007, 0x827C, 0x5008, 0x827D, 0x5009, 0x827E, 0x500A, 0x8280, 0x500B, 0x8281, 0x500E, 0x8282, 0x5010, 0x8283, 0x5011, 0x8284, 0x5013, 0x8285, 0x5015, 0x8286, 0x5016, 0x8287, 0x5017, 0x8288, 0x501B, 0x8289, 0x501D, 0x828A, 0x501E, 0x828B, 0x5020, 0x828C, 0x5022, 0x828D, 0x5023, 0x828E, 0x5024, 0x828F, 0x5027, 0x8290, 0x502B, 0x8291, 0x502F, 0x8292, 0x5030, 0x8293, 0x5031, 0x8294, 0x5032, 0x8295, 0x5033, 0x8296, 0x5034, 0x8297, 0x5035, 0x8298, 0x5036, 0x8299, 0x5037, 0x829A, 0x5038, 0x829B, 0x5039, 0x829C, 0x503B, 0x829D, 0x503D, 0x829E, 0x503F, 0x829F, 0x5040, 0x82A0, 0x5041, 0x82A1, 0x5042, 0x82A2, 0x5044, 0x82A3, 0x5045, 0x82A4, 0x5046, 0x82A5, 0x5049, 0x82A6, 0x504A, 0x82A7, 0x504B, 0x82A8, 0x504D, 0x82A9, 0x5050, 0x82AA, 0x5051, 0x82AB, 0x5052, 0x82AC, 0x5053, 0x82AD, 0x5054, 0x82AE, 0x5056, 0x82AF, 0x5057, 0x82B0, 0x5058, 0x82B1, 0x5059, 0x82B2, 0x505B, 0x82B3, 0x505D, 0x82B4, 0x505E, 0x82B5, 0x505F, 0x82B6, 0x5060, 0x82B7, 0x5061, 0x82B8, 0x5062, 0x82B9, 0x5063, 0x82BA, 0x5064, 0x82BB, 0x5066, 0x82BC, 0x5067, 0x82BD, 0x5068, 0x82BE, 0x5069, 0x82BF, 0x506A, 0x82C0, 0x506B, 0x82C1, 0x506D, 0x82C2, 0x506E, 0x82C3, 0x506F, 0x82C4, 0x5070, 0x82C5, 0x5071, 0x82C6, 0x5072, 0x82C7, 0x5073, 0x82C8, 0x5074, 0x82C9, 0x5075, 0x82CA, 0x5078, 0x82CB, 0x5079, 0x82CC, 0x507A, 0x82CD, 0x507C, 0x82CE, 0x507D, 0x82CF, 0x5081, 0x82D0, 0x5082, 0x82D1, 0x5083, 0x82D2, 0x5084, 0x82D3, 0x5086, 0x82D4, 0x5087, 0x82D5, 0x5089, 0x82D6, 0x508A, 0x82D7, 0x508B, 0x82D8, 0x508C, 0x82D9, 0x508E, 0x82DA, 0x508F, 0x82DB, 0x5090, 0x82DC, 0x5091, 0x82DD, 0x5092, 0x82DE, 0x5093, 0x82DF, 0x5094, 0x82E0, 0x5095, 0x82E1, 0x5096, 0x82E2, 0x5097, 0x82E3, 0x5098, 0x82E4, 0x5099, 0x82E5, 0x509A, 0x82E6, 0x509B, 0x82E7, 0x509C, 0x82E8, 0x509D, 0x82E9, 0x509E, 0x82EA, 0x509F, 0x82EB, 0x50A0, 0x82EC, 0x50A1, 0x82ED, 0x50A2, 0x82EE, 0x50A4, 0x82EF, 0x50A6, 0x82F0, 0x50AA, 0x82F1, 0x50AB, 0x82F2, 0x50AD, 0x82F3, 0x50AE, 0x82F4, 0x50AF, 0x82F5, 0x50B0, 0x82F6, 0x50B1, 0x82F7, 0x50B3, 0x82F8, 0x50B4, 0x82F9, 0x50B5, 0x82FA, 0x50B6, 0x82FB, 0x50B7, 0x82FC, 0x50B8, 0x82FD, 0x50B9, 0x82FE, 0x50BC, 0x8340, 0x50BD, 0x8341, 0x50BE, 0x8342, 0x50BF, 0x8343, 0x50C0, 0x8344, 0x50C1, 0x8345, 0x50C2, 0x8346, 0x50C3, 0x8347, 0x50C4, 0x8348, 0x50C5, 0x8349, 0x50C6, 0x834A, 0x50C7, 0x834B, 0x50C8, 0x834C, 0x50C9, 0x834D, 0x50CA, 0x834E, 0x50CB, 0x834F, 0x50CC, 0x8350, 0x50CD, 0x8351, 0x50CE, 0x8352, 0x50D0, 0x8353, 0x50D1, 0x8354, 0x50D2, 0x8355, 0x50D3, 0x8356, 0x50D4, 0x8357, 0x50D5, 0x8358, 0x50D7, 0x8359, 0x50D8, 0x835A, 0x50D9, 0x835B, 0x50DB, 0x835C, 0x50DC, 0x835D, 0x50DD, 0x835E, 0x50DE, 0x835F, 0x50DF, 0x8360, 0x50E0, 0x8361, 0x50E1, 0x8362, 0x50E2, 0x8363, 0x50E3, 0x8364, 0x50E4, 0x8365, 0x50E5, 0x8366, 0x50E8, 0x8367, 0x50E9, 0x8368, 0x50EA, 0x8369, 0x50EB, 0x836A, 0x50EF, 0x836B, 0x50F0, 0x836C, 0x50F1, 0x836D, 0x50F2, 0x836E, 0x50F4, 0x836F, 0x50F6, 0x8370, 0x50F7, 0x8371, 0x50F8, 0x8372, 0x50F9, 0x8373, 0x50FA, 0x8374, 0x50FC, 0x8375, 0x50FD, 0x8376, 0x50FE, 0x8377, 0x50FF, 0x8378, 0x5100, 0x8379, 0x5101, 0x837A, 0x5102, 0x837B, 0x5103, 0x837C, 0x5104, 0x837D, 0x5105, 0x837E, 0x5108, 0x8380, 0x5109, 0x8381, 0x510A, 0x8382, 0x510C, 0x8383, 0x510D, 0x8384, 0x510E, 0x8385, 0x510F, 0x8386, 0x5110, 0x8387, 0x5111, 0x8388, 0x5113, 0x8389, 0x5114, 0x838A, 0x5115, 0x838B, 0x5116, 0x838C, 0x5117, 0x838D, 0x5118, 0x838E, 0x5119, 0x838F, 0x511A, 0x8390, 0x511B, 0x8391, 0x511C, 0x8392, 0x511D, 0x8393, 0x511E, 0x8394, 0x511F, 0x8395, 0x5120, 0x8396, 0x5122, 0x8397, 0x5123, 0x8398, 0x5124, 0x8399, 0x5125, 0x839A, 0x5126, 0x839B, 0x5127, 0x839C, 0x5128, 0x839D, 0x5129, 0x839E, 0x512A, 0x839F, 0x512B, 0x83A0, 0x512C, 0x83A1, 0x512D, 0x83A2, 0x512E, 0x83A3, 0x512F, 0x83A4, 0x5130, 0x83A5, 0x5131, 0x83A6, 0x5132, 0x83A7, 0x5133, 0x83A8, 0x5134, 0x83A9, 0x5135, 0x83AA, 0x5136, 0x83AB, 0x5137, 0x83AC, 0x5138, 0x83AD, 0x5139, 0x83AE, 0x513A, 0x83AF, 0x513B, 0x83B0, 0x513C, 0x83B1, 0x513D, 0x83B2, 0x513E, 0x83B3, 0x5142, 0x83B4, 0x5147, 0x83B5, 0x514A, 0x83B6, 0x514C, 0x83B7, 0x514E, 0x83B8, 0x514F, 0x83B9, 0x5150, 0x83BA, 0x5152, 0x83BB, 0x5153, 0x83BC, 0x5157, 0x83BD, 0x5158, 0x83BE, 0x5159, 0x83BF, 0x515B, 0x83C0, 0x515D, 0x83C1, 0x515E, 0x83C2, 0x515F, 0x83C3, 0x5160, 0x83C4, 0x5161, 0x83C5, 0x5163, 0x83C6, 0x5164, 0x83C7, 0x5166, 0x83C8, 0x5167, 0x83C9, 0x5169, 0x83CA, 0x516A, 0x83CB, 0x516F, 0x83CC, 0x5172, 0x83CD, 0x517A, 0x83CE, 0x517E, 0x83CF, 0x517F, 0x83D0, 0x5183, 0x83D1, 0x5184, 0x83D2, 0x5186, 0x83D3, 0x5187, 0x83D4, 0x518A, 0x83D5, 0x518B, 0x83D6, 0x518E, 0x83D7, 0x518F, 0x83D8, 0x5190, 0x83D9, 0x5191, 0x83DA, 0x5193, 0x83DB, 0x5194, 0x83DC, 0x5198, 0x83DD, 0x519A, 0x83DE, 0x519D, 0x83DF, 0x519E, 0x83E0, 0x519F, 0x83E1, 0x51A1, 0x83E2, 0x51A3, 0x83E3, 0x51A6, 0x83E4, 0x51A7, 0x83E5, 0x51A8, 0x83E6, 0x51A9, 0x83E7, 0x51AA, 0x83E8, 0x51AD, 0x83E9, 0x51AE, 0x83EA, 0x51B4, 0x83EB, 0x51B8, 0x83EC, 0x51B9, 0x83ED, 0x51BA, 0x83EE, 0x51BE, 0x83EF, 0x51BF, 0x83F0, 0x51C1, 0x83F1, 0x51C2, 0x83F2, 0x51C3, 0x83F3, 0x51C5, 0x83F4, 0x51C8, 0x83F5, 0x51CA, 0x83F6, 0x51CD, 0x83F7, 0x51CE, 0x83F8, 0x51D0, 0x83F9, 0x51D2, 0x83FA, 0x51D3, 0x83FB, 0x51D4, 0x83FC, 0x51D5, 0x83FD, 0x51D6, 0x83FE, 0x51D7, 0x8440, 0x51D8, 0x8441, 0x51D9, 0x8442, 0x51DA, 0x8443, 0x51DC, 0x8444, 0x51DE, 0x8445, 0x51DF, 0x8446, 0x51E2, 0x8447, 0x51E3, 0x8448, 0x51E5, 0x8449, 0x51E6, 0x844A, 0x51E7, 0x844B, 0x51E8, 0x844C, 0x51E9, 0x844D, 0x51EA, 0x844E, 0x51EC, 0x844F, 0x51EE, 0x8450, 0x51F1, 0x8451, 0x51F2, 0x8452, 0x51F4, 0x8453, 0x51F7, 0x8454, 0x51FE, 0x8455, 0x5204, 0x8456, 0x5205, 0x8457, 0x5209, 0x8458, 0x520B, 0x8459, 0x520C, 0x845A, 0x520F, 0x845B, 0x5210, 0x845C, 0x5213, 0x845D, 0x5214, 0x845E, 0x5215, 0x845F, 0x521C, 0x8460, 0x521E, 0x8461, 0x521F, 0x8462, 0x5221, 0x8463, 0x5222, 0x8464, 0x5223, 0x8465, 0x5225, 0x8466, 0x5226, 0x8467, 0x5227, 0x8468, 0x522A, 0x8469, 0x522C, 0x846A, 0x522F, 0x846B, 0x5231, 0x846C, 0x5232, 0x846D, 0x5234, 0x846E, 0x5235, 0x846F, 0x523C, 0x8470, 0x523E, 0x8471, 0x5244, 0x8472, 0x5245, 0x8473, 0x5246, 0x8474, 0x5247, 0x8475, 0x5248, 0x8476, 0x5249, 0x8477, 0x524B, 0x8478, 0x524E, 0x8479, 0x524F, 0x847A, 0x5252, 0x847B, 0x5253, 0x847C, 0x5255, 0x847D, 0x5257, 0x847E, 0x5258, 0x8480, 0x5259, 0x8481, 0x525A, 0x8482, 0x525B, 0x8483, 0x525D, 0x8484, 0x525F, 0x8485, 0x5260, 0x8486, 0x5262, 0x8487, 0x5263, 0x8488, 0x5264, 0x8489, 0x5266, 0x848A, 0x5268, 0x848B, 0x526B, 0x848C, 0x526C, 0x848D, 0x526D, 0x848E, 0x526E, 0x848F, 0x5270, 0x8490, 0x5271, 0x8491, 0x5273, 0x8492, 0x5274, 0x8493, 0x5275, 0x8494, 0x5276, 0x8495, 0x5277, 0x8496, 0x5278, 0x8497, 0x5279, 0x8498, 0x527A, 0x8499, 0x527B, 0x849A, 0x527C, 0x849B, 0x527E, 0x849C, 0x5280, 0x849D, 0x5283, 0x849E, 0x5284, 0x849F, 0x5285, 0x84A0, 0x5286, 0x84A1, 0x5287, 0x84A2, 0x5289, 0x84A3, 0x528A, 0x84A4, 0x528B, 0x84A5, 0x528C, 0x84A6, 0x528D, 0x84A7, 0x528E, 0x84A8, 0x528F, 0x84A9, 0x5291, 0x84AA, 0x5292, 0x84AB, 0x5294, 0x84AC, 0x5295, 0x84AD, 0x5296, 0x84AE, 0x5297, 0x84AF, 0x5298, 0x84B0, 0x5299, 0x84B1, 0x529A, 0x84B2, 0x529C, 0x84B3, 0x52A4, 0x84B4, 0x52A5, 0x84B5, 0x52A6, 0x84B6, 0x52A7, 0x84B7, 0x52AE, 0x84B8, 0x52AF, 0x84B9, 0x52B0, 0x84BA, 0x52B4, 0x84BB, 0x52B5, 0x84BC, 0x52B6, 0x84BD, 0x52B7, 0x84BE, 0x52B8, 0x84BF, 0x52B9, 0x84C0, 0x52BA, 0x84C1, 0x52BB, 0x84C2, 0x52BC, 0x84C3, 0x52BD, 0x84C4, 0x52C0, 0x84C5, 0x52C1, 0x84C6, 0x52C2, 0x84C7, 0x52C4, 0x84C8, 0x52C5, 0x84C9, 0x52C6, 0x84CA, 0x52C8, 0x84CB, 0x52CA, 0x84CC, 0x52CC, 0x84CD, 0x52CD, 0x84CE, 0x52CE, 0x84CF, 0x52CF, 0x84D0, 0x52D1, 0x84D1, 0x52D3, 0x84D2, 0x52D4, 0x84D3, 0x52D5, 0x84D4, 0x52D7, 0x84D5, 0x52D9, 0x84D6, 0x52DA, 0x84D7, 0x52DB, 0x84D8, 0x52DC, 0x84D9, 0x52DD, 0x84DA, 0x52DE, 0x84DB, 0x52E0, 0x84DC, 0x52E1, 0x84DD, 0x52E2, 0x84DE, 0x52E3, 0x84DF, 0x52E5, 0x84E0, 0x52E6, 0x84E1, 0x52E7, 0x84E2, 0x52E8, 0x84E3, 0x52E9, 0x84E4, 0x52EA, 0x84E5, 0x52EB, 0x84E6, 0x52EC, 0x84E7, 0x52ED, 0x84E8, 0x52EE, 0x84E9, 0x52EF, 0x84EA, 0x52F1, 0x84EB, 0x52F2, 0x84EC, 0x52F3, 0x84ED, 0x52F4, 0x84EE, 0x52F5, 0x84EF, 0x52F6, 0x84F0, 0x52F7, 0x84F1, 0x52F8, 0x84F2, 0x52FB, 0x84F3, 0x52FC, 0x84F4, 0x52FD, 0x84F5, 0x5301, 0x84F6, 0x5302, 0x84F7, 0x5303, 0x84F8, 0x5304, 0x84F9, 0x5307, 0x84FA, 0x5309, 0x84FB, 0x530A, 0x84FC, 0x530B, 0x84FD, 0x530C, 0x84FE, 0x530E, 0x8540, 0x5311, 0x8541, 0x5312, 0x8542, 0x5313, 0x8543, 0x5314, 0x8544, 0x5318, 0x8545, 0x531B, 0x8546, 0x531C, 0x8547, 0x531E, 0x8548, 0x531F, 0x8549, 0x5322, 0x854A, 0x5324, 0x854B, 0x5325, 0x854C, 0x5327, 0x854D, 0x5328, 0x854E, 0x5329, 0x854F, 0x532B, 0x8550, 0x532C, 0x8551, 0x532D, 0x8552, 0x532F, 0x8553, 0x5330, 0x8554, 0x5331, 0x8555, 0x5332, 0x8556, 0x5333, 0x8557, 0x5334, 0x8558, 0x5335, 0x8559, 0x5336, 0x855A, 0x5337, 0x855B, 0x5338, 0x855C, 0x533C, 0x855D, 0x533D, 0x855E, 0x5340, 0x855F, 0x5342, 0x8560, 0x5344, 0x8561, 0x5346, 0x8562, 0x534B, 0x8563, 0x534C, 0x8564, 0x534D, 0x8565, 0x5350, 0x8566, 0x5354, 0x8567, 0x5358, 0x8568, 0x5359, 0x8569, 0x535B, 0x856A, 0x535D, 0x856B, 0x5365, 0x856C, 0x5368, 0x856D, 0x536A, 0x856E, 0x536C, 0x856F, 0x536D, 0x8570, 0x5372, 0x8571, 0x5376, 0x8572, 0x5379, 0x8573, 0x537B, 0x8574, 0x537C, 0x8575, 0x537D, 0x8576, 0x537E, 0x8577, 0x5380, 0x8578, 0x5381, 0x8579, 0x5383, 0x857A, 0x5387, 0x857B, 0x5388, 0x857C, 0x538A, 0x857D, 0x538E, 0x857E, 0x538F, 0x8580, 0x5390, 0x8581, 0x5391, 0x8582, 0x5392, 0x8583, 0x5393, 0x8584, 0x5394, 0x8585, 0x5396, 0x8586, 0x5397, 0x8587, 0x5399, 0x8588, 0x539B, 0x8589, 0x539C, 0x858A, 0x539E, 0x858B, 0x53A0, 0x858C, 0x53A1, 0x858D, 0x53A4, 0x858E, 0x53A7, 0x858F, 0x53AA, 0x8590, 0x53AB, 0x8591, 0x53AC, 0x8592, 0x53AD, 0x8593, 0x53AF, 0x8594, 0x53B0, 0x8595, 0x53B1, 0x8596, 0x53B2, 0x8597, 0x53B3, 0x8598, 0x53B4, 0x8599, 0x53B5, 0x859A, 0x53B7, 0x859B, 0x53B8, 0x859C, 0x53B9, 0x859D, 0x53BA, 0x859E, 0x53BC, 0x859F, 0x53BD, 0x85A0, 0x53BE, 0x85A1, 0x53C0, 0x85A2, 0x53C3, 0x85A3, 0x53C4, 0x85A4, 0x53C5, 0x85A5, 0x53C6, 0x85A6, 0x53C7, 0x85A7, 0x53CE, 0x85A8, 0x53CF, 0x85A9, 0x53D0, 0x85AA, 0x53D2, 0x85AB, 0x53D3, 0x85AC, 0x53D5, 0x85AD, 0x53DA, 0x85AE, 0x53DC, 0x85AF, 0x53DD, 0x85B0, 0x53DE, 0x85B1, 0x53E1, 0x85B2, 0x53E2, 0x85B3, 0x53E7, 0x85B4, 0x53F4, 0x85B5, 0x53FA, 0x85B6, 0x53FE, 0x85B7, 0x53FF, 0x85B8, 0x5400, 0x85B9, 0x5402, 0x85BA, 0x5405, 0x85BB, 0x5407, 0x85BC, 0x540B, 0x85BD, 0x5414, 0x85BE, 0x5418, 0x85BF, 0x5419, 0x85C0, 0x541A, 0x85C1, 0x541C, 0x85C2, 0x5422, 0x85C3, 0x5424, 0x85C4, 0x5425, 0x85C5, 0x542A, 0x85C6, 0x5430, 0x85C7, 0x5433, 0x85C8, 0x5436, 0x85C9, 0x5437, 0x85CA, 0x543A, 0x85CB, 0x543D, 0x85CC, 0x543F, 0x85CD, 0x5441, 0x85CE, 0x5442, 0x85CF, 0x5444, 0x85D0, 0x5445, 0x85D1, 0x5447, 0x85D2, 0x5449, 0x85D3, 0x544C, 0x85D4, 0x544D, 0x85D5, 0x544E, 0x85D6, 0x544F, 0x85D7, 0x5451, 0x85D8, 0x545A, 0x85D9, 0x545D, 0x85DA, 0x545E, 0x85DB, 0x545F, 0x85DC, 0x5460, 0x85DD, 0x5461, 0x85DE, 0x5463, 0x85DF, 0x5465, 0x85E0, 0x5467, 0x85E1, 0x5469, 0x85E2, 0x546A, 0x85E3, 0x546B, 0x85E4, 0x546C, 0x85E5, 0x546D, 0x85E6, 0x546E, 0x85E7, 0x546F, 0x85E8, 0x5470, 0x85E9, 0x5474, 0x85EA, 0x5479, 0x85EB, 0x547A, 0x85EC, 0x547E, 0x85ED, 0x547F, 0x85EE, 0x5481, 0x85EF, 0x5483, 0x85F0, 0x5485, 0x85F1, 0x5487, 0x85F2, 0x5488, 0x85F3, 0x5489, 0x85F4, 0x548A, 0x85F5, 0x548D, 0x85F6, 0x5491, 0x85F7, 0x5493, 0x85F8, 0x5497, 0x85F9, 0x5498, 0x85FA, 0x549C, 0x85FB, 0x549E, 0x85FC, 0x549F, 0x85FD, 0x54A0, 0x85FE, 0x54A1, 0x8640, 0x54A2, 0x8641, 0x54A5, 0x8642, 0x54AE, 0x8643, 0x54B0, 0x8644, 0x54B2, 0x8645, 0x54B5, 0x8646, 0x54B6, 0x8647, 0x54B7, 0x8648, 0x54B9, 0x8649, 0x54BA, 0x864A, 0x54BC, 0x864B, 0x54BE, 0x864C, 0x54C3, 0x864D, 0x54C5, 0x864E, 0x54CA, 0x864F, 0x54CB, 0x8650, 0x54D6, 0x8651, 0x54D8, 0x8652, 0x54DB, 0x8653, 0x54E0, 0x8654, 0x54E1, 0x8655, 0x54E2, 0x8656, 0x54E3, 0x8657, 0x54E4, 0x8658, 0x54EB, 0x8659, 0x54EC, 0x865A, 0x54EF, 0x865B, 0x54F0, 0x865C, 0x54F1, 0x865D, 0x54F4, 0x865E, 0x54F5, 0x865F, 0x54F6, 0x8660, 0x54F7, 0x8661, 0x54F8, 0x8662, 0x54F9, 0x8663, 0x54FB, 0x8664, 0x54FE, 0x8665, 0x5500, 0x8666, 0x5502, 0x8667, 0x5503, 0x8668, 0x5504, 0x8669, 0x5505, 0x866A, 0x5508, 0x866B, 0x550A, 0x866C, 0x550B, 0x866D, 0x550C, 0x866E, 0x550D, 0x866F, 0x550E, 0x8670, 0x5512, 0x8671, 0x5513, 0x8672, 0x5515, 0x8673, 0x5516, 0x8674, 0x5517, 0x8675, 0x5518, 0x8676, 0x5519, 0x8677, 0x551A, 0x8678, 0x551C, 0x8679, 0x551D, 0x867A, 0x551E, 0x867B, 0x551F, 0x867C, 0x5521, 0x867D, 0x5525, 0x867E, 0x5526, 0x8680, 0x5528, 0x8681, 0x5529, 0x8682, 0x552B, 0x8683, 0x552D, 0x8684, 0x5532, 0x8685, 0x5534, 0x8686, 0x5535, 0x8687, 0x5536, 0x8688, 0x5538, 0x8689, 0x5539, 0x868A, 0x553A, 0x868B, 0x553B, 0x868C, 0x553D, 0x868D, 0x5540, 0x868E, 0x5542, 0x868F, 0x5545, 0x8690, 0x5547, 0x8691, 0x5548, 0x8692, 0x554B, 0x8693, 0x554C, 0x8694, 0x554D, 0x8695, 0x554E, 0x8696, 0x554F, 0x8697, 0x5551, 0x8698, 0x5552, 0x8699, 0x5553, 0x869A, 0x5554, 0x869B, 0x5557, 0x869C, 0x5558, 0x869D, 0x5559, 0x869E, 0x555A, 0x869F, 0x555B, 0x86A0, 0x555D, 0x86A1, 0x555E, 0x86A2, 0x555F, 0x86A3, 0x5560, 0x86A4, 0x5562, 0x86A5, 0x5563, 0x86A6, 0x5568, 0x86A7, 0x5569, 0x86A8, 0x556B, 0x86A9, 0x556F, 0x86AA, 0x5570, 0x86AB, 0x5571, 0x86AC, 0x5572, 0x86AD, 0x5573, 0x86AE, 0x5574, 0x86AF, 0x5579, 0x86B0, 0x557A, 0x86B1, 0x557D, 0x86B2, 0x557F, 0x86B3, 0x5585, 0x86B4, 0x5586, 0x86B5, 0x558C, 0x86B6, 0x558D, 0x86B7, 0x558E, 0x86B8, 0x5590, 0x86B9, 0x5592, 0x86BA, 0x5593, 0x86BB, 0x5595, 0x86BC, 0x5596, 0x86BD, 0x5597, 0x86BE, 0x559A, 0x86BF, 0x559B, 0x86C0, 0x559E, 0x86C1, 0x55A0, 0x86C2, 0x55A1, 0x86C3, 0x55A2, 0x86C4, 0x55A3, 0x86C5, 0x55A4, 0x86C6, 0x55A5, 0x86C7, 0x55A6, 0x86C8, 0x55A8, 0x86C9, 0x55A9, 0x86CA, 0x55AA, 0x86CB, 0x55AB, 0x86CC, 0x55AC, 0x86CD, 0x55AD, 0x86CE, 0x55AE, 0x86CF, 0x55AF, 0x86D0, 0x55B0, 0x86D1, 0x55B2, 0x86D2, 0x55B4, 0x86D3, 0x55B6, 0x86D4, 0x55B8, 0x86D5, 0x55BA, 0x86D6, 0x55BC, 0x86D7, 0x55BF, 0x86D8, 0x55C0, 0x86D9, 0x55C1, 0x86DA, 0x55C2, 0x86DB, 0x55C3, 0x86DC, 0x55C6, 0x86DD, 0x55C7, 0x86DE, 0x55C8, 0x86DF, 0x55CA, 0x86E0, 0x55CB, 0x86E1, 0x55CE, 0x86E2, 0x55CF, 0x86E3, 0x55D0, 0x86E4, 0x55D5, 0x86E5, 0x55D7, 0x86E6, 0x55D8, 0x86E7, 0x55D9, 0x86E8, 0x55DA, 0x86E9, 0x55DB, 0x86EA, 0x55DE, 0x86EB, 0x55E0, 0x86EC, 0x55E2, 0x86ED, 0x55E7, 0x86EE, 0x55E9, 0x86EF, 0x55ED, 0x86F0, 0x55EE, 0x86F1, 0x55F0, 0x86F2, 0x55F1, 0x86F3, 0x55F4, 0x86F4, 0x55F6, 0x86F5, 0x55F8, 0x86F6, 0x55F9, 0x86F7, 0x55FA, 0x86F8, 0x55FB, 0x86F9, 0x55FC, 0x86FA, 0x55FF, 0x86FB, 0x5602, 0x86FC, 0x5603, 0x86FD, 0x5604, 0x86FE, 0x5605, 0x8740, 0x5606, 0x8741, 0x5607, 0x8742, 0x560A, 0x8743, 0x560B, 0x8744, 0x560D, 0x8745, 0x5610, 0x8746, 0x5611, 0x8747, 0x5612, 0x8748, 0x5613, 0x8749, 0x5614, 0x874A, 0x5615, 0x874B, 0x5616, 0x874C, 0x5617, 0x874D, 0x5619, 0x874E, 0x561A, 0x874F, 0x561C, 0x8750, 0x561D, 0x8751, 0x5620, 0x8752, 0x5621, 0x8753, 0x5622, 0x8754, 0x5625, 0x8755, 0x5626, 0x8756, 0x5628, 0x8757, 0x5629, 0x8758, 0x562A, 0x8759, 0x562B, 0x875A, 0x562E, 0x875B, 0x562F, 0x875C, 0x5630, 0x875D, 0x5633, 0x875E, 0x5635, 0x875F, 0x5637, 0x8760, 0x5638, 0x8761, 0x563A, 0x8762, 0x563C, 0x8763, 0x563D, 0x8764, 0x563E, 0x8765, 0x5640, 0x8766, 0x5641, 0x8767, 0x5642, 0x8768, 0x5643, 0x8769, 0x5644, 0x876A, 0x5645, 0x876B, 0x5646, 0x876C, 0x5647, 0x876D, 0x5648, 0x876E, 0x5649, 0x876F, 0x564A, 0x8770, 0x564B, 0x8771, 0x564F, 0x8772, 0x5650, 0x8773, 0x5651, 0x8774, 0x5652, 0x8775, 0x5653, 0x8776, 0x5655, 0x8777, 0x5656, 0x8778, 0x565A, 0x8779, 0x565B, 0x877A, 0x565D, 0x877B, 0x565E, 0x877C, 0x565F, 0x877D, 0x5660, 0x877E, 0x5661, 0x8780, 0x5663, 0x8781, 0x5665, 0x8782, 0x5666, 0x8783, 0x5667, 0x8784, 0x566D, 0x8785, 0x566E, 0x8786, 0x566F, 0x8787, 0x5670, 0x8788, 0x5672, 0x8789, 0x5673, 0x878A, 0x5674, 0x878B, 0x5675, 0x878C, 0x5677, 0x878D, 0x5678, 0x878E, 0x5679, 0x878F, 0x567A, 0x8790, 0x567D, 0x8791, 0x567E, 0x8792, 0x567F, 0x8793, 0x5680, 0x8794, 0x5681, 0x8795, 0x5682, 0x8796, 0x5683, 0x8797, 0x5684, 0x8798, 0x5687, 0x8799, 0x5688, 0x879A, 0x5689, 0x879B, 0x568A, 0x879C, 0x568B, 0x879D, 0x568C, 0x879E, 0x568D, 0x879F, 0x5690, 0x87A0, 0x5691, 0x87A1, 0x5692, 0x87A2, 0x5694, 0x87A3, 0x5695, 0x87A4, 0x5696, 0x87A5, 0x5697, 0x87A6, 0x5698, 0x87A7, 0x5699, 0x87A8, 0x569A, 0x87A9, 0x569B, 0x87AA, 0x569C, 0x87AB, 0x569D, 0x87AC, 0x569E, 0x87AD, 0x569F, 0x87AE, 0x56A0, 0x87AF, 0x56A1, 0x87B0, 0x56A2, 0x87B1, 0x56A4, 0x87B2, 0x56A5, 0x87B3, 0x56A6, 0x87B4, 0x56A7, 0x87B5, 0x56A8, 0x87B6, 0x56A9, 0x87B7, 0x56AA, 0x87B8, 0x56AB, 0x87B9, 0x56AC, 0x87BA, 0x56AD, 0x87BB, 0x56AE, 0x87BC, 0x56B0, 0x87BD, 0x56B1, 0x87BE, 0x56B2, 0x87BF, 0x56B3, 0x87C0, 0x56B4, 0x87C1, 0x56B5, 0x87C2, 0x56B6, 0x87C3, 0x56B8, 0x87C4, 0x56B9, 0x87C5, 0x56BA, 0x87C6, 0x56BB, 0x87C7, 0x56BD, 0x87C8, 0x56BE, 0x87C9, 0x56BF, 0x87CA, 0x56C0, 0x87CB, 0x56C1, 0x87CC, 0x56C2, 0x87CD, 0x56C3, 0x87CE, 0x56C4, 0x87CF, 0x56C5, 0x87D0, 0x56C6, 0x87D1, 0x56C7, 0x87D2, 0x56C8, 0x87D3, 0x56C9, 0x87D4, 0x56CB, 0x87D5, 0x56CC, 0x87D6, 0x56CD, 0x87D7, 0x56CE, 0x87D8, 0x56CF, 0x87D9, 0x56D0, 0x87DA, 0x56D1, 0x87DB, 0x56D2, 0x87DC, 0x56D3, 0x87DD, 0x56D5, 0x87DE, 0x56D6, 0x87DF, 0x56D8, 0x87E0, 0x56D9, 0x87E1, 0x56DC, 0x87E2, 0x56E3, 0x87E3, 0x56E5, 0x87E4, 0x56E6, 0x87E5, 0x56E7, 0x87E6, 0x56E8, 0x87E7, 0x56E9, 0x87E8, 0x56EA, 0x87E9, 0x56EC, 0x87EA, 0x56EE, 0x87EB, 0x56EF, 0x87EC, 0x56F2, 0x87ED, 0x56F3, 0x87EE, 0x56F6, 0x87EF, 0x56F7, 0x87F0, 0x56F8, 0x87F1, 0x56FB, 0x87F2, 0x56FC, 0x87F3, 0x5700, 0x87F4, 0x5701, 0x87F5, 0x5702, 0x87F6, 0x5705, 0x87F7, 0x5707, 0x87F8, 0x570B, 0x87F9, 0x570C, 0x87FA, 0x570D, 0x87FB, 0x570E, 0x87FC, 0x570F, 0x87FD, 0x5710, 0x87FE, 0x5711, 0x8840, 0x5712, 0x8841, 0x5713, 0x8842, 0x5714, 0x8843, 0x5715, 0x8844, 0x5716, 0x8845, 0x5717, 0x8846, 0x5718, 0x8847, 0x5719, 0x8848, 0x571A, 0x8849, 0x571B, 0x884A, 0x571D, 0x884B, 0x571E, 0x884C, 0x5720, 0x884D, 0x5721, 0x884E, 0x5722, 0x884F, 0x5724, 0x8850, 0x5725, 0x8851, 0x5726, 0x8852, 0x5727, 0x8853, 0x572B, 0x8854, 0x5731, 0x8855, 0x5732, 0x8856, 0x5734, 0x8857, 0x5735, 0x8858, 0x5736, 0x8859, 0x5737, 0x885A, 0x5738, 0x885B, 0x573C, 0x885C, 0x573D, 0x885D, 0x573F, 0x885E, 0x5741, 0x885F, 0x5743, 0x8860, 0x5744, 0x8861, 0x5745, 0x8862, 0x5746, 0x8863, 0x5748, 0x8864, 0x5749, 0x8865, 0x574B, 0x8866, 0x5752, 0x8867, 0x5753, 0x8868, 0x5754, 0x8869, 0x5755, 0x886A, 0x5756, 0x886B, 0x5758, 0x886C, 0x5759, 0x886D, 0x5762, 0x886E, 0x5763, 0x886F, 0x5765, 0x8870, 0x5767, 0x8871, 0x576C, 0x8872, 0x576E, 0x8873, 0x5770, 0x8874, 0x5771, 0x8875, 0x5772, 0x8876, 0x5774, 0x8877, 0x5775, 0x8878, 0x5778, 0x8879, 0x5779, 0x887A, 0x577A, 0x887B, 0x577D, 0x887C, 0x577E, 0x887D, 0x577F, 0x887E, 0x5780, 0x8880, 0x5781, 0x8881, 0x5787, 0x8882, 0x5788, 0x8883, 0x5789, 0x8884, 0x578A, 0x8885, 0x578D, 0x8886, 0x578E, 0x8887, 0x578F, 0x8888, 0x5790, 0x8889, 0x5791, 0x888A, 0x5794, 0x888B, 0x5795, 0x888C, 0x5796, 0x888D, 0x5797, 0x888E, 0x5798, 0x888F, 0x5799, 0x8890, 0x579A, 0x8891, 0x579C, 0x8892, 0x579D, 0x8893, 0x579E, 0x8894, 0x579F, 0x8895, 0x57A5, 0x8896, 0x57A8, 0x8897, 0x57AA, 0x8898, 0x57AC, 0x8899, 0x57AF, 0x889A, 0x57B0, 0x889B, 0x57B1, 0x889C, 0x57B3, 0x889D, 0x57B5, 0x889E, 0x57B6, 0x889F, 0x57B7, 0x88A0, 0x57B9, 0x88A1, 0x57BA, 0x88A2, 0x57BB, 0x88A3, 0x57BC, 0x88A4, 0x57BD, 0x88A5, 0x57BE, 0x88A6, 0x57BF, 0x88A7, 0x57C0, 0x88A8, 0x57C1, 0x88A9, 0x57C4, 0x88AA, 0x57C5, 0x88AB, 0x57C6, 0x88AC, 0x57C7, 0x88AD, 0x57C8, 0x88AE, 0x57C9, 0x88AF, 0x57CA, 0x88B0, 0x57CC, 0x88B1, 0x57CD, 0x88B2, 0x57D0, 0x88B3, 0x57D1, 0x88B4, 0x57D3, 0x88B5, 0x57D6, 0x88B6, 0x57D7, 0x88B7, 0x57DB, 0x88B8, 0x57DC, 0x88B9, 0x57DE, 0x88BA, 0x57E1, 0x88BB, 0x57E2, 0x88BC, 0x57E3, 0x88BD, 0x57E5, 0x88BE, 0x57E6, 0x88BF, 0x57E7, 0x88C0, 0x57E8, 0x88C1, 0x57E9, 0x88C2, 0x57EA, 0x88C3, 0x57EB, 0x88C4, 0x57EC, 0x88C5, 0x57EE, 0x88C6, 0x57F0, 0x88C7, 0x57F1, 0x88C8, 0x57F2, 0x88C9, 0x57F3, 0x88CA, 0x57F5, 0x88CB, 0x57F6, 0x88CC, 0x57F7, 0x88CD, 0x57FB, 0x88CE, 0x57FC, 0x88CF, 0x57FE, 0x88D0, 0x57FF, 0x88D1, 0x5801, 0x88D2, 0x5803, 0x88D3, 0x5804, 0x88D4, 0x5805, 0x88D5, 0x5808, 0x88D6, 0x5809, 0x88D7, 0x580A, 0x88D8, 0x580C, 0x88D9, 0x580E, 0x88DA, 0x580F, 0x88DB, 0x5810, 0x88DC, 0x5812, 0x88DD, 0x5813, 0x88DE, 0x5814, 0x88DF, 0x5816, 0x88E0, 0x5817, 0x88E1, 0x5818, 0x88E2, 0x581A, 0x88E3, 0x581B, 0x88E4, 0x581C, 0x88E5, 0x581D, 0x88E6, 0x581F, 0x88E7, 0x5822, 0x88E8, 0x5823, 0x88E9, 0x5825, 0x88EA, 0x5826, 0x88EB, 0x5827, 0x88EC, 0x5828, 0x88ED, 0x5829, 0x88EE, 0x582B, 0x88EF, 0x582C, 0x88F0, 0x582D, 0x88F1, 0x582E, 0x88F2, 0x582F, 0x88F3, 0x5831, 0x88F4, 0x5832, 0x88F5, 0x5833, 0x88F6, 0x5834, 0x88F7, 0x5836, 0x88F8, 0x5837, 0x88F9, 0x5838, 0x88FA, 0x5839, 0x88FB, 0x583A, 0x88FC, 0x583B, 0x88FD, 0x583C, 0x88FE, 0x583D, 0x8940, 0x583E, 0x8941, 0x583F, 0x8942, 0x5840, 0x8943, 0x5841, 0x8944, 0x5842, 0x8945, 0x5843, 0x8946, 0x5845, 0x8947, 0x5846, 0x8948, 0x5847, 0x8949, 0x5848, 0x894A, 0x5849, 0x894B, 0x584A, 0x894C, 0x584B, 0x894D, 0x584E, 0x894E, 0x584F, 0x894F, 0x5850, 0x8950, 0x5852, 0x8951, 0x5853, 0x8952, 0x5855, 0x8953, 0x5856, 0x8954, 0x5857, 0x8955, 0x5859, 0x8956, 0x585A, 0x8957, 0x585B, 0x8958, 0x585C, 0x8959, 0x585D, 0x895A, 0x585F, 0x895B, 0x5860, 0x895C, 0x5861, 0x895D, 0x5862, 0x895E, 0x5863, 0x895F, 0x5864, 0x8960, 0x5866, 0x8961, 0x5867, 0x8962, 0x5868, 0x8963, 0x5869, 0x8964, 0x586A, 0x8965, 0x586D, 0x8966, 0x586E, 0x8967, 0x586F, 0x8968, 0x5870, 0x8969, 0x5871, 0x896A, 0x5872, 0x896B, 0x5873, 0x896C, 0x5874, 0x896D, 0x5875, 0x896E, 0x5876, 0x896F, 0x5877, 0x8970, 0x5878, 0x8971, 0x5879, 0x8972, 0x587A, 0x8973, 0x587B, 0x8974, 0x587C, 0x8975, 0x587D, 0x8976, 0x587F, 0x8977, 0x5882, 0x8978, 0x5884, 0x8979, 0x5886, 0x897A, 0x5887, 0x897B, 0x5888, 0x897C, 0x588A, 0x897D, 0x588B, 0x897E, 0x588C, 0x8980, 0x588D, 0x8981, 0x588E, 0x8982, 0x588F, 0x8983, 0x5890, 0x8984, 0x5891, 0x8985, 0x5894, 0x8986, 0x5895, 0x8987, 0x5896, 0x8988, 0x5897, 0x8989, 0x5898, 0x898A, 0x589B, 0x898B, 0x589C, 0x898C, 0x589D, 0x898D, 0x58A0, 0x898E, 0x58A1, 0x898F, 0x58A2, 0x8990, 0x58A3, 0x8991, 0x58A4, 0x8992, 0x58A5, 0x8993, 0x58A6, 0x8994, 0x58A7, 0x8995, 0x58AA, 0x8996, 0x58AB, 0x8997, 0x58AC, 0x8998, 0x58AD, 0x8999, 0x58AE, 0x899A, 0x58AF, 0x899B, 0x58B0, 0x899C, 0x58B1, 0x899D, 0x58B2, 0x899E, 0x58B3, 0x899F, 0x58B4, 0x89A0, 0x58B5, 0x89A1, 0x58B6, 0x89A2, 0x58B7, 0x89A3, 0x58B8, 0x89A4, 0x58B9, 0x89A5, 0x58BA, 0x89A6, 0x58BB, 0x89A7, 0x58BD, 0x89A8, 0x58BE, 0x89A9, 0x58BF, 0x89AA, 0x58C0, 0x89AB, 0x58C2, 0x89AC, 0x58C3, 0x89AD, 0x58C4, 0x89AE, 0x58C6, 0x89AF, 0x58C7, 0x89B0, 0x58C8, 0x89B1, 0x58C9, 0x89B2, 0x58CA, 0x89B3, 0x58CB, 0x89B4, 0x58CC, 0x89B5, 0x58CD, 0x89B6, 0x58CE, 0x89B7, 0x58CF, 0x89B8, 0x58D0, 0x89B9, 0x58D2, 0x89BA, 0x58D3, 0x89BB, 0x58D4, 0x89BC, 0x58D6, 0x89BD, 0x58D7, 0x89BE, 0x58D8, 0x89BF, 0x58D9, 0x89C0, 0x58DA, 0x89C1, 0x58DB, 0x89C2, 0x58DC, 0x89C3, 0x58DD, 0x89C4, 0x58DE, 0x89C5, 0x58DF, 0x89C6, 0x58E0, 0x89C7, 0x58E1, 0x89C8, 0x58E2, 0x89C9, 0x58E3, 0x89CA, 0x58E5, 0x89CB, 0x58E6, 0x89CC, 0x58E7, 0x89CD, 0x58E8, 0x89CE, 0x58E9, 0x89CF, 0x58EA, 0x89D0, 0x58ED, 0x89D1, 0x58EF, 0x89D2, 0x58F1, 0x89D3, 0x58F2, 0x89D4, 0x58F4, 0x89D5, 0x58F5, 0x89D6, 0x58F7, 0x89D7, 0x58F8, 0x89D8, 0x58FA, 0x89D9, 0x58FB, 0x89DA, 0x58FC, 0x89DB, 0x58FD, 0x89DC, 0x58FE, 0x89DD, 0x58FF, 0x89DE, 0x5900, 0x89DF, 0x5901, 0x89E0, 0x5903, 0x89E1, 0x5905, 0x89E2, 0x5906, 0x89E3, 0x5908, 0x89E4, 0x5909, 0x89E5, 0x590A, 0x89E6, 0x590B, 0x89E7, 0x590C, 0x89E8, 0x590E, 0x89E9, 0x5910, 0x89EA, 0x5911, 0x89EB, 0x5912, 0x89EC, 0x5913, 0x89ED, 0x5917, 0x89EE, 0x5918, 0x89EF, 0x591B, 0x89F0, 0x591D, 0x89F1, 0x591E, 0x89F2, 0x5920, 0x89F3, 0x5921, 0x89F4, 0x5922, 0x89F5, 0x5923, 0x89F6, 0x5926, 0x89F7, 0x5928, 0x89F8, 0x592C, 0x89F9, 0x5930, 0x89FA, 0x5932, 0x89FB, 0x5933, 0x89FC, 0x5935, 0x89FD, 0x5936, 0x89FE, 0x593B, 0x8A40, 0x593D, 0x8A41, 0x593E, 0x8A42, 0x593F, 0x8A43, 0x5940, 0x8A44, 0x5943, 0x8A45, 0x5945, 0x8A46, 0x5946, 0x8A47, 0x594A, 0x8A48, 0x594C, 0x8A49, 0x594D, 0x8A4A, 0x5950, 0x8A4B, 0x5952, 0x8A4C, 0x5953, 0x8A4D, 0x5959, 0x8A4E, 0x595B, 0x8A4F, 0x595C, 0x8A50, 0x595D, 0x8A51, 0x595E, 0x8A52, 0x595F, 0x8A53, 0x5961, 0x8A54, 0x5963, 0x8A55, 0x5964, 0x8A56, 0x5966, 0x8A57, 0x5967, 0x8A58, 0x5968, 0x8A59, 0x5969, 0x8A5A, 0x596A, 0x8A5B, 0x596B, 0x8A5C, 0x596C, 0x8A5D, 0x596D, 0x8A5E, 0x596E, 0x8A5F, 0x596F, 0x8A60, 0x5970, 0x8A61, 0x5971, 0x8A62, 0x5972, 0x8A63, 0x5975, 0x8A64, 0x5977, 0x8A65, 0x597A, 0x8A66, 0x597B, 0x8A67, 0x597C, 0x8A68, 0x597E, 0x8A69, 0x597F, 0x8A6A, 0x5980, 0x8A6B, 0x5985, 0x8A6C, 0x5989, 0x8A6D, 0x598B, 0x8A6E, 0x598C, 0x8A6F, 0x598E, 0x8A70, 0x598F, 0x8A71, 0x5990, 0x8A72, 0x5991, 0x8A73, 0x5994, 0x8A74, 0x5995, 0x8A75, 0x5998, 0x8A76, 0x599A, 0x8A77, 0x599B, 0x8A78, 0x599C, 0x8A79, 0x599D, 0x8A7A, 0x599F, 0x8A7B, 0x59A0, 0x8A7C, 0x59A1, 0x8A7D, 0x59A2, 0x8A7E, 0x59A6, 0x8A80, 0x59A7, 0x8A81, 0x59AC, 0x8A82, 0x59AD, 0x8A83, 0x59B0, 0x8A84, 0x59B1, 0x8A85, 0x59B3, 0x8A86, 0x59B4, 0x8A87, 0x59B5, 0x8A88, 0x59B6, 0x8A89, 0x59B7, 0x8A8A, 0x59B8, 0x8A8B, 0x59BA, 0x8A8C, 0x59BC, 0x8A8D, 0x59BD, 0x8A8E, 0x59BF, 0x8A8F, 0x59C0, 0x8A90, 0x59C1, 0x8A91, 0x59C2, 0x8A92, 0x59C3, 0x8A93, 0x59C4, 0x8A94, 0x59C5, 0x8A95, 0x59C7, 0x8A96, 0x59C8, 0x8A97, 0x59C9, 0x8A98, 0x59CC, 0x8A99, 0x59CD, 0x8A9A, 0x59CE, 0x8A9B, 0x59CF, 0x8A9C, 0x59D5, 0x8A9D, 0x59D6, 0x8A9E, 0x59D9, 0x8A9F, 0x59DB, 0x8AA0, 0x59DE, 0x8AA1, 0x59DF, 0x8AA2, 0x59E0, 0x8AA3, 0x59E1, 0x8AA4, 0x59E2, 0x8AA5, 0x59E4, 0x8AA6, 0x59E6, 0x8AA7, 0x59E7, 0x8AA8, 0x59E9, 0x8AA9, 0x59EA, 0x8AAA, 0x59EB, 0x8AAB, 0x59ED, 0x8AAC, 0x59EE, 0x8AAD, 0x59EF, 0x8AAE, 0x59F0, 0x8AAF, 0x59F1, 0x8AB0, 0x59F2, 0x8AB1, 0x59F3, 0x8AB2, 0x59F4, 0x8AB3, 0x59F5, 0x8AB4, 0x59F6, 0x8AB5, 0x59F7, 0x8AB6, 0x59F8, 0x8AB7, 0x59FA, 0x8AB8, 0x59FC, 0x8AB9, 0x59FD, 0x8ABA, 0x59FE, 0x8ABB, 0x5A00, 0x8ABC, 0x5A02, 0x8ABD, 0x5A0A, 0x8ABE, 0x5A0B, 0x8ABF, 0x5A0D, 0x8AC0, 0x5A0E, 0x8AC1, 0x5A0F, 0x8AC2, 0x5A10, 0x8AC3, 0x5A12, 0x8AC4, 0x5A14, 0x8AC5, 0x5A15, 0x8AC6, 0x5A16, 0x8AC7, 0x5A17, 0x8AC8, 0x5A19, 0x8AC9, 0x5A1A, 0x8ACA, 0x5A1B, 0x8ACB, 0x5A1D, 0x8ACC, 0x5A1E, 0x8ACD, 0x5A21, 0x8ACE, 0x5A22, 0x8ACF, 0x5A24, 0x8AD0, 0x5A26, 0x8AD1, 0x5A27, 0x8AD2, 0x5A28, 0x8AD3, 0x5A2A, 0x8AD4, 0x5A2B, 0x8AD5, 0x5A2C, 0x8AD6, 0x5A2D, 0x8AD7, 0x5A2E, 0x8AD8, 0x5A2F, 0x8AD9, 0x5A30, 0x8ADA, 0x5A33, 0x8ADB, 0x5A35, 0x8ADC, 0x5A37, 0x8ADD, 0x5A38, 0x8ADE, 0x5A39, 0x8ADF, 0x5A3A, 0x8AE0, 0x5A3B, 0x8AE1, 0x5A3D, 0x8AE2, 0x5A3E, 0x8AE3, 0x5A3F, 0x8AE4, 0x5A41, 0x8AE5, 0x5A42, 0x8AE6, 0x5A43, 0x8AE7, 0x5A44, 0x8AE8, 0x5A45, 0x8AE9, 0x5A47, 0x8AEA, 0x5A48, 0x8AEB, 0x5A4B, 0x8AEC, 0x5A4C, 0x8AED, 0x5A4D, 0x8AEE, 0x5A4E, 0x8AEF, 0x5A4F, 0x8AF0, 0x5A50, 0x8AF1, 0x5A51, 0x8AF2, 0x5A52, 0x8AF3, 0x5A53, 0x8AF4, 0x5A54, 0x8AF5, 0x5A56, 0x8AF6, 0x5A57, 0x8AF7, 0x5A58, 0x8AF8, 0x5A59, 0x8AF9, 0x5A5B, 0x8AFA, 0x5A5C, 0x8AFB, 0x5A5D, 0x8AFC, 0x5A5E, 0x8AFD, 0x5A5F, 0x8AFE, 0x5A60, 0x8B40, 0x5A61, 0x8B41, 0x5A63, 0x8B42, 0x5A64, 0x8B43, 0x5A65, 0x8B44, 0x5A66, 0x8B45, 0x5A68, 0x8B46, 0x5A69, 0x8B47, 0x5A6B, 0x8B48, 0x5A6C, 0x8B49, 0x5A6D, 0x8B4A, 0x5A6E, 0x8B4B, 0x5A6F, 0x8B4C, 0x5A70, 0x8B4D, 0x5A71, 0x8B4E, 0x5A72, 0x8B4F, 0x5A73, 0x8B50, 0x5A78, 0x8B51, 0x5A79, 0x8B52, 0x5A7B, 0x8B53, 0x5A7C, 0x8B54, 0x5A7D, 0x8B55, 0x5A7E, 0x8B56, 0x5A80, 0x8B57, 0x5A81, 0x8B58, 0x5A82, 0x8B59, 0x5A83, 0x8B5A, 0x5A84, 0x8B5B, 0x5A85, 0x8B5C, 0x5A86, 0x8B5D, 0x5A87, 0x8B5E, 0x5A88, 0x8B5F, 0x5A89, 0x8B60, 0x5A8A, 0x8B61, 0x5A8B, 0x8B62, 0x5A8C, 0x8B63, 0x5A8D, 0x8B64, 0x5A8E, 0x8B65, 0x5A8F, 0x8B66, 0x5A90, 0x8B67, 0x5A91, 0x8B68, 0x5A93, 0x8B69, 0x5A94, 0x8B6A, 0x5A95, 0x8B6B, 0x5A96, 0x8B6C, 0x5A97, 0x8B6D, 0x5A98, 0x8B6E, 0x5A99, 0x8B6F, 0x5A9C, 0x8B70, 0x5A9D, 0x8B71, 0x5A9E, 0x8B72, 0x5A9F, 0x8B73, 0x5AA0, 0x8B74, 0x5AA1, 0x8B75, 0x5AA2, 0x8B76, 0x5AA3, 0x8B77, 0x5AA4, 0x8B78, 0x5AA5, 0x8B79, 0x5AA6, 0x8B7A, 0x5AA7, 0x8B7B, 0x5AA8, 0x8B7C, 0x5AA9, 0x8B7D, 0x5AAB, 0x8B7E, 0x5AAC, 0x8B80, 0x5AAD, 0x8B81, 0x5AAE, 0x8B82, 0x5AAF, 0x8B83, 0x5AB0, 0x8B84, 0x5AB1, 0x8B85, 0x5AB4, 0x8B86, 0x5AB6, 0x8B87, 0x5AB7, 0x8B88, 0x5AB9, 0x8B89, 0x5ABA, 0x8B8A, 0x5ABB, 0x8B8B, 0x5ABC, 0x8B8C, 0x5ABD, 0x8B8D, 0x5ABF, 0x8B8E, 0x5AC0, 0x8B8F, 0x5AC3, 0x8B90, 0x5AC4, 0x8B91, 0x5AC5, 0x8B92, 0x5AC6, 0x8B93, 0x5AC7, 0x8B94, 0x5AC8, 0x8B95, 0x5ACA, 0x8B96, 0x5ACB, 0x8B97, 0x5ACD, 0x8B98, 0x5ACE, 0x8B99, 0x5ACF, 0x8B9A, 0x5AD0, 0x8B9B, 0x5AD1, 0x8B9C, 0x5AD3, 0x8B9D, 0x5AD5, 0x8B9E, 0x5AD7, 0x8B9F, 0x5AD9, 0x8BA0, 0x5ADA, 0x8BA1, 0x5ADB, 0x8BA2, 0x5ADD, 0x8BA3, 0x5ADE, 0x8BA4, 0x5ADF, 0x8BA5, 0x5AE2, 0x8BA6, 0x5AE4, 0x8BA7, 0x5AE5, 0x8BA8, 0x5AE7, 0x8BA9, 0x5AE8, 0x8BAA, 0x5AEA, 0x8BAB, 0x5AEC, 0x8BAC, 0x5AED, 0x8BAD, 0x5AEE, 0x8BAE, 0x5AEF, 0x8BAF, 0x5AF0, 0x8BB0, 0x5AF2, 0x8BB1, 0x5AF3, 0x8BB2, 0x5AF4, 0x8BB3, 0x5AF5, 0x8BB4, 0x5AF6, 0x8BB5, 0x5AF7, 0x8BB6, 0x5AF8, 0x8BB7, 0x5AF9, 0x8BB8, 0x5AFA, 0x8BB9, 0x5AFB, 0x8BBA, 0x5AFC, 0x8BBB, 0x5AFD, 0x8BBC, 0x5AFE, 0x8BBD, 0x5AFF, 0x8BBE, 0x5B00, 0x8BBF, 0x5B01, 0x8BC0, 0x5B02, 0x8BC1, 0x5B03, 0x8BC2, 0x5B04, 0x8BC3, 0x5B05, 0x8BC4, 0x5B06, 0x8BC5, 0x5B07, 0x8BC6, 0x5B08, 0x8BC7, 0x5B0A, 0x8BC8, 0x5B0B, 0x8BC9, 0x5B0C, 0x8BCA, 0x5B0D, 0x8BCB, 0x5B0E, 0x8BCC, 0x5B0F, 0x8BCD, 0x5B10, 0x8BCE, 0x5B11, 0x8BCF, 0x5B12, 0x8BD0, 0x5B13, 0x8BD1, 0x5B14, 0x8BD2, 0x5B15, 0x8BD3, 0x5B18, 0x8BD4, 0x5B19, 0x8BD5, 0x5B1A, 0x8BD6, 0x5B1B, 0x8BD7, 0x5B1C, 0x8BD8, 0x5B1D, 0x8BD9, 0x5B1E, 0x8BDA, 0x5B1F, 0x8BDB, 0x5B20, 0x8BDC, 0x5B21, 0x8BDD, 0x5B22, 0x8BDE, 0x5B23, 0x8BDF, 0x5B24, 0x8BE0, 0x5B25, 0x8BE1, 0x5B26, 0x8BE2, 0x5B27, 0x8BE3, 0x5B28, 0x8BE4, 0x5B29, 0x8BE5, 0x5B2A, 0x8BE6, 0x5B2B, 0x8BE7, 0x5B2C, 0x8BE8, 0x5B2D, 0x8BE9, 0x5B2E, 0x8BEA, 0x5B2F, 0x8BEB, 0x5B30, 0x8BEC, 0x5B31, 0x8BED, 0x5B33, 0x8BEE, 0x5B35, 0x8BEF, 0x5B36, 0x8BF0, 0x5B38, 0x8BF1, 0x5B39, 0x8BF2, 0x5B3A, 0x8BF3, 0x5B3B, 0x8BF4, 0x5B3C, 0x8BF5, 0x5B3D, 0x8BF6, 0x5B3E, 0x8BF7, 0x5B3F, 0x8BF8, 0x5B41, 0x8BF9, 0x5B42, 0x8BFA, 0x5B43, 0x8BFB, 0x5B44, 0x8BFC, 0x5B45, 0x8BFD, 0x5B46, 0x8BFE, 0x5B47, 0x8C40, 0x5B48, 0x8C41, 0x5B49, 0x8C42, 0x5B4A, 0x8C43, 0x5B4B, 0x8C44, 0x5B4C, 0x8C45, 0x5B4D, 0x8C46, 0x5B4E, 0x8C47, 0x5B4F, 0x8C48, 0x5B52, 0x8C49, 0x5B56, 0x8C4A, 0x5B5E, 0x8C4B, 0x5B60, 0x8C4C, 0x5B61, 0x8C4D, 0x5B67, 0x8C4E, 0x5B68, 0x8C4F, 0x5B6B, 0x8C50, 0x5B6D, 0x8C51, 0x5B6E, 0x8C52, 0x5B6F, 0x8C53, 0x5B72, 0x8C54, 0x5B74, 0x8C55, 0x5B76, 0x8C56, 0x5B77, 0x8C57, 0x5B78, 0x8C58, 0x5B79, 0x8C59, 0x5B7B, 0x8C5A, 0x5B7C, 0x8C5B, 0x5B7E, 0x8C5C, 0x5B7F, 0x8C5D, 0x5B82, 0x8C5E, 0x5B86, 0x8C5F, 0x5B8A, 0x8C60, 0x5B8D, 0x8C61, 0x5B8E, 0x8C62, 0x5B90, 0x8C63, 0x5B91, 0x8C64, 0x5B92, 0x8C65, 0x5B94, 0x8C66, 0x5B96, 0x8C67, 0x5B9F, 0x8C68, 0x5BA7, 0x8C69, 0x5BA8, 0x8C6A, 0x5BA9, 0x8C6B, 0x5BAC, 0x8C6C, 0x5BAD, 0x8C6D, 0x5BAE, 0x8C6E, 0x5BAF, 0x8C6F, 0x5BB1, 0x8C70, 0x5BB2, 0x8C71, 0x5BB7, 0x8C72, 0x5BBA, 0x8C73, 0x5BBB, 0x8C74, 0x5BBC, 0x8C75, 0x5BC0, 0x8C76, 0x5BC1, 0x8C77, 0x5BC3, 0x8C78, 0x5BC8, 0x8C79, 0x5BC9, 0x8C7A, 0x5BCA, 0x8C7B, 0x5BCB, 0x8C7C, 0x5BCD, 0x8C7D, 0x5BCE, 0x8C7E, 0x5BCF, 0x8C80, 0x5BD1, 0x8C81, 0x5BD4, 0x8C82, 0x5BD5, 0x8C83, 0x5BD6, 0x8C84, 0x5BD7, 0x8C85, 0x5BD8, 0x8C86, 0x5BD9, 0x8C87, 0x5BDA, 0x8C88, 0x5BDB, 0x8C89, 0x5BDC, 0x8C8A, 0x5BE0, 0x8C8B, 0x5BE2, 0x8C8C, 0x5BE3, 0x8C8D, 0x5BE6, 0x8C8E, 0x5BE7, 0x8C8F, 0x5BE9, 0x8C90, 0x5BEA, 0x8C91, 0x5BEB, 0x8C92, 0x5BEC, 0x8C93, 0x5BED, 0x8C94, 0x5BEF, 0x8C95, 0x5BF1, 0x8C96, 0x5BF2, 0x8C97, 0x5BF3, 0x8C98, 0x5BF4, 0x8C99, 0x5BF5, 0x8C9A, 0x5BF6, 0x8C9B, 0x5BF7, 0x8C9C, 0x5BFD, 0x8C9D, 0x5BFE, 0x8C9E, 0x5C00, 0x8C9F, 0x5C02, 0x8CA0, 0x5C03, 0x8CA1, 0x5C05, 0x8CA2, 0x5C07, 0x8CA3, 0x5C08, 0x8CA4, 0x5C0B, 0x8CA5, 0x5C0C, 0x8CA6, 0x5C0D, 0x8CA7, 0x5C0E, 0x8CA8, 0x5C10, 0x8CA9, 0x5C12, 0x8CAA, 0x5C13, 0x8CAB, 0x5C17, 0x8CAC, 0x5C19, 0x8CAD, 0x5C1B, 0x8CAE, 0x5C1E, 0x8CAF, 0x5C1F, 0x8CB0, 0x5C20, 0x8CB1, 0x5C21, 0x8CB2, 0x5C23, 0x8CB3, 0x5C26, 0x8CB4, 0x5C28, 0x8CB5, 0x5C29, 0x8CB6, 0x5C2A, 0x8CB7, 0x5C2B, 0x8CB8, 0x5C2D, 0x8CB9, 0x5C2E, 0x8CBA, 0x5C2F, 0x8CBB, 0x5C30, 0x8CBC, 0x5C32, 0x8CBD, 0x5C33, 0x8CBE, 0x5C35, 0x8CBF, 0x5C36, 0x8CC0, 0x5C37, 0x8CC1, 0x5C43, 0x8CC2, 0x5C44, 0x8CC3, 0x5C46, 0x8CC4, 0x5C47, 0x8CC5, 0x5C4C, 0x8CC6, 0x5C4D, 0x8CC7, 0x5C52, 0x8CC8, 0x5C53, 0x8CC9, 0x5C54, 0x8CCA, 0x5C56, 0x8CCB, 0x5C57, 0x8CCC, 0x5C58, 0x8CCD, 0x5C5A, 0x8CCE, 0x5C5B, 0x8CCF, 0x5C5C, 0x8CD0, 0x5C5D, 0x8CD1, 0x5C5F, 0x8CD2, 0x5C62, 0x8CD3, 0x5C64, 0x8CD4, 0x5C67, 0x8CD5, 0x5C68, 0x8CD6, 0x5C69, 0x8CD7, 0x5C6A, 0x8CD8, 0x5C6B, 0x8CD9, 0x5C6C, 0x8CDA, 0x5C6D, 0x8CDB, 0x5C70, 0x8CDC, 0x5C72, 0x8CDD, 0x5C73, 0x8CDE, 0x5C74, 0x8CDF, 0x5C75, 0x8CE0, 0x5C76, 0x8CE1, 0x5C77, 0x8CE2, 0x5C78, 0x8CE3, 0x5C7B, 0x8CE4, 0x5C7C, 0x8CE5, 0x5C7D, 0x8CE6, 0x5C7E, 0x8CE7, 0x5C80, 0x8CE8, 0x5C83, 0x8CE9, 0x5C84, 0x8CEA, 0x5C85, 0x8CEB, 0x5C86, 0x8CEC, 0x5C87, 0x8CED, 0x5C89, 0x8CEE, 0x5C8A, 0x8CEF, 0x5C8B, 0x8CF0, 0x5C8E, 0x8CF1, 0x5C8F, 0x8CF2, 0x5C92, 0x8CF3, 0x5C93, 0x8CF4, 0x5C95, 0x8CF5, 0x5C9D, 0x8CF6, 0x5C9E, 0x8CF7, 0x5C9F, 0x8CF8, 0x5CA0, 0x8CF9, 0x5CA1, 0x8CFA, 0x5CA4, 0x8CFB, 0x5CA5, 0x8CFC, 0x5CA6, 0x8CFD, 0x5CA7, 0x8CFE, 0x5CA8, 0x8D40, 0x5CAA, 0x8D41, 0x5CAE, 0x8D42, 0x5CAF, 0x8D43, 0x5CB0, 0x8D44, 0x5CB2, 0x8D45, 0x5CB4, 0x8D46, 0x5CB6, 0x8D47, 0x5CB9, 0x8D48, 0x5CBA, 0x8D49, 0x5CBB, 0x8D4A, 0x5CBC, 0x8D4B, 0x5CBE, 0x8D4C, 0x5CC0, 0x8D4D, 0x5CC2, 0x8D4E, 0x5CC3, 0x8D4F, 0x5CC5, 0x8D50, 0x5CC6, 0x8D51, 0x5CC7, 0x8D52, 0x5CC8, 0x8D53, 0x5CC9, 0x8D54, 0x5CCA, 0x8D55, 0x5CCC, 0x8D56, 0x5CCD, 0x8D57, 0x5CCE, 0x8D58, 0x5CCF, 0x8D59, 0x5CD0, 0x8D5A, 0x5CD1, 0x8D5B, 0x5CD3, 0x8D5C, 0x5CD4, 0x8D5D, 0x5CD5, 0x8D5E, 0x5CD6, 0x8D5F, 0x5CD7, 0x8D60, 0x5CD8, 0x8D61, 0x5CDA, 0x8D62, 0x5CDB, 0x8D63, 0x5CDC, 0x8D64, 0x5CDD, 0x8D65, 0x5CDE, 0x8D66, 0x5CDF, 0x8D67, 0x5CE0, 0x8D68, 0x5CE2, 0x8D69, 0x5CE3, 0x8D6A, 0x5CE7, 0x8D6B, 0x5CE9, 0x8D6C, 0x5CEB, 0x8D6D, 0x5CEC, 0x8D6E, 0x5CEE, 0x8D6F, 0x5CEF, 0x8D70, 0x5CF1, 0x8D71, 0x5CF2, 0x8D72, 0x5CF3, 0x8D73, 0x5CF4, 0x8D74, 0x5CF5, 0x8D75, 0x5CF6, 0x8D76, 0x5CF7, 0x8D77, 0x5CF8, 0x8D78, 0x5CF9, 0x8D79, 0x5CFA, 0x8D7A, 0x5CFC, 0x8D7B, 0x5CFD, 0x8D7C, 0x5CFE, 0x8D7D, 0x5CFF, 0x8D7E, 0x5D00, 0x8D80, 0x5D01, 0x8D81, 0x5D04, 0x8D82, 0x5D05, 0x8D83, 0x5D08, 0x8D84, 0x5D09, 0x8D85, 0x5D0A, 0x8D86, 0x5D0B, 0x8D87, 0x5D0C, 0x8D88, 0x5D0D, 0x8D89, 0x5D0F, 0x8D8A, 0x5D10, 0x8D8B, 0x5D11, 0x8D8C, 0x5D12, 0x8D8D, 0x5D13, 0x8D8E, 0x5D15, 0x8D8F, 0x5D17, 0x8D90, 0x5D18, 0x8D91, 0x5D19, 0x8D92, 0x5D1A, 0x8D93, 0x5D1C, 0x8D94, 0x5D1D, 0x8D95, 0x5D1F, 0x8D96, 0x5D20, 0x8D97, 0x5D21, 0x8D98, 0x5D22, 0x8D99, 0x5D23, 0x8D9A, 0x5D25, 0x8D9B, 0x5D28, 0x8D9C, 0x5D2A, 0x8D9D, 0x5D2B, 0x8D9E, 0x5D2C, 0x8D9F, 0x5D2F, 0x8DA0, 0x5D30, 0x8DA1, 0x5D31, 0x8DA2, 0x5D32, 0x8DA3, 0x5D33, 0x8DA4, 0x5D35, 0x8DA5, 0x5D36, 0x8DA6, 0x5D37, 0x8DA7, 0x5D38, 0x8DA8, 0x5D39, 0x8DA9, 0x5D3A, 0x8DAA, 0x5D3B, 0x8DAB, 0x5D3C, 0x8DAC, 0x5D3F, 0x8DAD, 0x5D40, 0x8DAE, 0x5D41, 0x8DAF, 0x5D42, 0x8DB0, 0x5D43, 0x8DB1, 0x5D44, 0x8DB2, 0x5D45, 0x8DB3, 0x5D46, 0x8DB4, 0x5D48, 0x8DB5, 0x5D49, 0x8DB6, 0x5D4D, 0x8DB7, 0x5D4E, 0x8DB8, 0x5D4F, 0x8DB9, 0x5D50, 0x8DBA, 0x5D51, 0x8DBB, 0x5D52, 0x8DBC, 0x5D53, 0x8DBD, 0x5D54, 0x8DBE, 0x5D55, 0x8DBF, 0x5D56, 0x8DC0, 0x5D57, 0x8DC1, 0x5D59, 0x8DC2, 0x5D5A, 0x8DC3, 0x5D5C, 0x8DC4, 0x5D5E, 0x8DC5, 0x5D5F, 0x8DC6, 0x5D60, 0x8DC7, 0x5D61, 0x8DC8, 0x5D62, 0x8DC9, 0x5D63, 0x8DCA, 0x5D64, 0x8DCB, 0x5D65, 0x8DCC, 0x5D66, 0x8DCD, 0x5D67, 0x8DCE, 0x5D68, 0x8DCF, 0x5D6A, 0x8DD0, 0x5D6D, 0x8DD1, 0x5D6E, 0x8DD2, 0x5D70, 0x8DD3, 0x5D71, 0x8DD4, 0x5D72, 0x8DD5, 0x5D73, 0x8DD6, 0x5D75, 0x8DD7, 0x5D76, 0x8DD8, 0x5D77, 0x8DD9, 0x5D78, 0x8DDA, 0x5D79, 0x8DDB, 0x5D7A, 0x8DDC, 0x5D7B, 0x8DDD, 0x5D7C, 0x8DDE, 0x5D7D, 0x8DDF, 0x5D7E, 0x8DE0, 0x5D7F, 0x8DE1, 0x5D80, 0x8DE2, 0x5D81, 0x8DE3, 0x5D83, 0x8DE4, 0x5D84, 0x8DE5, 0x5D85, 0x8DE6, 0x5D86, 0x8DE7, 0x5D87, 0x8DE8, 0x5D88, 0x8DE9, 0x5D89, 0x8DEA, 0x5D8A, 0x8DEB, 0x5D8B, 0x8DEC, 0x5D8C, 0x8DED, 0x5D8D, 0x8DEE, 0x5D8E, 0x8DEF, 0x5D8F, 0x8DF0, 0x5D90, 0x8DF1, 0x5D91, 0x8DF2, 0x5D92, 0x8DF3, 0x5D93, 0x8DF4, 0x5D94, 0x8DF5, 0x5D95, 0x8DF6, 0x5D96, 0x8DF7, 0x5D97, 0x8DF8, 0x5D98, 0x8DF9, 0x5D9A, 0x8DFA, 0x5D9B, 0x8DFB, 0x5D9C, 0x8DFC, 0x5D9E, 0x8DFD, 0x5D9F, 0x8DFE, 0x5DA0, 0x8E40, 0x5DA1, 0x8E41, 0x5DA2, 0x8E42, 0x5DA3, 0x8E43, 0x5DA4, 0x8E44, 0x5DA5, 0x8E45, 0x5DA6, 0x8E46, 0x5DA7, 0x8E47, 0x5DA8, 0x8E48, 0x5DA9, 0x8E49, 0x5DAA, 0x8E4A, 0x5DAB, 0x8E4B, 0x5DAC, 0x8E4C, 0x5DAD, 0x8E4D, 0x5DAE, 0x8E4E, 0x5DAF, 0x8E4F, 0x5DB0, 0x8E50, 0x5DB1, 0x8E51, 0x5DB2, 0x8E52, 0x5DB3, 0x8E53, 0x5DB4, 0x8E54, 0x5DB5, 0x8E55, 0x5DB6, 0x8E56, 0x5DB8, 0x8E57, 0x5DB9, 0x8E58, 0x5DBA, 0x8E59, 0x5DBB, 0x8E5A, 0x5DBC, 0x8E5B, 0x5DBD, 0x8E5C, 0x5DBE, 0x8E5D, 0x5DBF, 0x8E5E, 0x5DC0, 0x8E5F, 0x5DC1, 0x8E60, 0x5DC2, 0x8E61, 0x5DC3, 0x8E62, 0x5DC4, 0x8E63, 0x5DC6, 0x8E64, 0x5DC7, 0x8E65, 0x5DC8, 0x8E66, 0x5DC9, 0x8E67, 0x5DCA, 0x8E68, 0x5DCB, 0x8E69, 0x5DCC, 0x8E6A, 0x5DCE, 0x8E6B, 0x5DCF, 0x8E6C, 0x5DD0, 0x8E6D, 0x5DD1, 0x8E6E, 0x5DD2, 0x8E6F, 0x5DD3, 0x8E70, 0x5DD4, 0x8E71, 0x5DD5, 0x8E72, 0x5DD6, 0x8E73, 0x5DD7, 0x8E74, 0x5DD8, 0x8E75, 0x5DD9, 0x8E76, 0x5DDA, 0x8E77, 0x5DDC, 0x8E78, 0x5DDF, 0x8E79, 0x5DE0, 0x8E7A, 0x5DE3, 0x8E7B, 0x5DE4, 0x8E7C, 0x5DEA, 0x8E7D, 0x5DEC, 0x8E7E, 0x5DED, 0x8E80, 0x5DF0, 0x8E81, 0x5DF5, 0x8E82, 0x5DF6, 0x8E83, 0x5DF8, 0x8E84, 0x5DF9, 0x8E85, 0x5DFA, 0x8E86, 0x5DFB, 0x8E87, 0x5DFC, 0x8E88, 0x5DFF, 0x8E89, 0x5E00, 0x8E8A, 0x5E04, 0x8E8B, 0x5E07, 0x8E8C, 0x5E09, 0x8E8D, 0x5E0A, 0x8E8E, 0x5E0B, 0x8E8F, 0x5E0D, 0x8E90, 0x5E0E, 0x8E91, 0x5E12, 0x8E92, 0x5E13, 0x8E93, 0x5E17, 0x8E94, 0x5E1E, 0x8E95, 0x5E1F, 0x8E96, 0x5E20, 0x8E97, 0x5E21, 0x8E98, 0x5E22, 0x8E99, 0x5E23, 0x8E9A, 0x5E24, 0x8E9B, 0x5E25, 0x8E9C, 0x5E28, 0x8E9D, 0x5E29, 0x8E9E, 0x5E2A, 0x8E9F, 0x5E2B, 0x8EA0, 0x5E2C, 0x8EA1, 0x5E2F, 0x8EA2, 0x5E30, 0x8EA3, 0x5E32, 0x8EA4, 0x5E33, 0x8EA5, 0x5E34, 0x8EA6, 0x5E35, 0x8EA7, 0x5E36, 0x8EA8, 0x5E39, 0x8EA9, 0x5E3A, 0x8EAA, 0x5E3E, 0x8EAB, 0x5E3F, 0x8EAC, 0x5E40, 0x8EAD, 0x5E41, 0x8EAE, 0x5E43, 0x8EAF, 0x5E46, 0x8EB0, 0x5E47, 0x8EB1, 0x5E48, 0x8EB2, 0x5E49, 0x8EB3, 0x5E4A, 0x8EB4, 0x5E4B, 0x8EB5, 0x5E4D, 0x8EB6, 0x5E4E, 0x8EB7, 0x5E4F, 0x8EB8, 0x5E50, 0x8EB9, 0x5E51, 0x8EBA, 0x5E52, 0x8EBB, 0x5E53, 0x8EBC, 0x5E56, 0x8EBD, 0x5E57, 0x8EBE, 0x5E58, 0x8EBF, 0x5E59, 0x8EC0, 0x5E5A, 0x8EC1, 0x5E5C, 0x8EC2, 0x5E5D, 0x8EC3, 0x5E5F, 0x8EC4, 0x5E60, 0x8EC5, 0x5E63, 0x8EC6, 0x5E64, 0x8EC7, 0x5E65, 0x8EC8, 0x5E66, 0x8EC9, 0x5E67, 0x8ECA, 0x5E68, 0x8ECB, 0x5E69, 0x8ECC, 0x5E6A, 0x8ECD, 0x5E6B, 0x8ECE, 0x5E6C, 0x8ECF, 0x5E6D, 0x8ED0, 0x5E6E, 0x8ED1, 0x5E6F, 0x8ED2, 0x5E70, 0x8ED3, 0x5E71, 0x8ED4, 0x5E75, 0x8ED5, 0x5E77, 0x8ED6, 0x5E79, 0x8ED7, 0x5E7E, 0x8ED8, 0x5E81, 0x8ED9, 0x5E82, 0x8EDA, 0x5E83, 0x8EDB, 0x5E85, 0x8EDC, 0x5E88, 0x8EDD, 0x5E89, 0x8EDE, 0x5E8C, 0x8EDF, 0x5E8D, 0x8EE0, 0x5E8E, 0x8EE1, 0x5E92, 0x8EE2, 0x5E98, 0x8EE3, 0x5E9B, 0x8EE4, 0x5E9D, 0x8EE5, 0x5EA1, 0x8EE6, 0x5EA2, 0x8EE7, 0x5EA3, 0x8EE8, 0x5EA4, 0x8EE9, 0x5EA8, 0x8EEA, 0x5EA9, 0x8EEB, 0x5EAA, 0x8EEC, 0x5EAB, 0x8EED, 0x5EAC, 0x8EEE, 0x5EAE, 0x8EEF, 0x5EAF, 0x8EF0, 0x5EB0, 0x8EF1, 0x5EB1, 0x8EF2, 0x5EB2, 0x8EF3, 0x5EB4, 0x8EF4, 0x5EBA, 0x8EF5, 0x5EBB, 0x8EF6, 0x5EBC, 0x8EF7, 0x5EBD, 0x8EF8, 0x5EBF, 0x8EF9, 0x5EC0, 0x8EFA, 0x5EC1, 0x8EFB, 0x5EC2, 0x8EFC, 0x5EC3, 0x8EFD, 0x5EC4, 0x8EFE, 0x5EC5, 0x8F40, 0x5EC6, 0x8F41, 0x5EC7, 0x8F42, 0x5EC8, 0x8F43, 0x5ECB, 0x8F44, 0x5ECC, 0x8F45, 0x5ECD, 0x8F46, 0x5ECE, 0x8F47, 0x5ECF, 0x8F48, 0x5ED0, 0x8F49, 0x5ED4, 0x8F4A, 0x5ED5, 0x8F4B, 0x5ED7, 0x8F4C, 0x5ED8, 0x8F4D, 0x5ED9, 0x8F4E, 0x5EDA, 0x8F4F, 0x5EDC, 0x8F50, 0x5EDD, 0x8F51, 0x5EDE, 0x8F52, 0x5EDF, 0x8F53, 0x5EE0, 0x8F54, 0x5EE1, 0x8F55, 0x5EE2, 0x8F56, 0x5EE3, 0x8F57, 0x5EE4, 0x8F58, 0x5EE5, 0x8F59, 0x5EE6, 0x8F5A, 0x5EE7, 0x8F5B, 0x5EE9, 0x8F5C, 0x5EEB, 0x8F5D, 0x5EEC, 0x8F5E, 0x5EED, 0x8F5F, 0x5EEE, 0x8F60, 0x5EEF, 0x8F61, 0x5EF0, 0x8F62, 0x5EF1, 0x8F63, 0x5EF2, 0x8F64, 0x5EF3, 0x8F65, 0x5EF5, 0x8F66, 0x5EF8, 0x8F67, 0x5EF9, 0x8F68, 0x5EFB, 0x8F69, 0x5EFC, 0x8F6A, 0x5EFD, 0x8F6B, 0x5F05, 0x8F6C, 0x5F06, 0x8F6D, 0x5F07, 0x8F6E, 0x5F09, 0x8F6F, 0x5F0C, 0x8F70, 0x5F0D, 0x8F71, 0x5F0E, 0x8F72, 0x5F10, 0x8F73, 0x5F12, 0x8F74, 0x5F14, 0x8F75, 0x5F16, 0x8F76, 0x5F19, 0x8F77, 0x5F1A, 0x8F78, 0x5F1C, 0x8F79, 0x5F1D, 0x8F7A, 0x5F1E, 0x8F7B, 0x5F21, 0x8F7C, 0x5F22, 0x8F7D, 0x5F23, 0x8F7E, 0x5F24, 0x8F80, 0x5F28, 0x8F81, 0x5F2B, 0x8F82, 0x5F2C, 0x8F83, 0x5F2E, 0x8F84, 0x5F30, 0x8F85, 0x5F32, 0x8F86, 0x5F33, 0x8F87, 0x5F34, 0x8F88, 0x5F35, 0x8F89, 0x5F36, 0x8F8A, 0x5F37, 0x8F8B, 0x5F38, 0x8F8C, 0x5F3B, 0x8F8D, 0x5F3D, 0x8F8E, 0x5F3E, 0x8F8F, 0x5F3F, 0x8F90, 0x5F41, 0x8F91, 0x5F42, 0x8F92, 0x5F43, 0x8F93, 0x5F44, 0x8F94, 0x5F45, 0x8F95, 0x5F46, 0x8F96, 0x5F47, 0x8F97, 0x5F48, 0x8F98, 0x5F49, 0x8F99, 0x5F4A, 0x8F9A, 0x5F4B, 0x8F9B, 0x5F4C, 0x8F9C, 0x5F4D, 0x8F9D, 0x5F4E, 0x8F9E, 0x5F4F, 0x8F9F, 0x5F51, 0x8FA0, 0x5F54, 0x8FA1, 0x5F59, 0x8FA2, 0x5F5A, 0x8FA3, 0x5F5B, 0x8FA4, 0x5F5C, 0x8FA5, 0x5F5E, 0x8FA6, 0x5F5F, 0x8FA7, 0x5F60, 0x8FA8, 0x5F63, 0x8FA9, 0x5F65, 0x8FAA, 0x5F67, 0x8FAB, 0x5F68, 0x8FAC, 0x5F6B, 0x8FAD, 0x5F6E, 0x8FAE, 0x5F6F, 0x8FAF, 0x5F72, 0x8FB0, 0x5F74, 0x8FB1, 0x5F75, 0x8FB2, 0x5F76, 0x8FB3, 0x5F78, 0x8FB4, 0x5F7A, 0x8FB5, 0x5F7D, 0x8FB6, 0x5F7E, 0x8FB7, 0x5F7F, 0x8FB8, 0x5F83, 0x8FB9, 0x5F86, 0x8FBA, 0x5F8D, 0x8FBB, 0x5F8E, 0x8FBC, 0x5F8F, 0x8FBD, 0x5F91, 0x8FBE, 0x5F93, 0x8FBF, 0x5F94, 0x8FC0, 0x5F96, 0x8FC1, 0x5F9A, 0x8FC2, 0x5F9B, 0x8FC3, 0x5F9D, 0x8FC4, 0x5F9E, 0x8FC5, 0x5F9F, 0x8FC6, 0x5FA0, 0x8FC7, 0x5FA2, 0x8FC8, 0x5FA3, 0x8FC9, 0x5FA4, 0x8FCA, 0x5FA5, 0x8FCB, 0x5FA6, 0x8FCC, 0x5FA7, 0x8FCD, 0x5FA9, 0x8FCE, 0x5FAB, 0x8FCF, 0x5FAC, 0x8FD0, 0x5FAF, 0x8FD1, 0x5FB0, 0x8FD2, 0x5FB1, 0x8FD3, 0x5FB2, 0x8FD4, 0x5FB3, 0x8FD5, 0x5FB4, 0x8FD6, 0x5FB6, 0x8FD7, 0x5FB8, 0x8FD8, 0x5FB9, 0x8FD9, 0x5FBA, 0x8FDA, 0x5FBB, 0x8FDB, 0x5FBE, 0x8FDC, 0x5FBF, 0x8FDD, 0x5FC0, 0x8FDE, 0x5FC1, 0x8FDF, 0x5FC2, 0x8FE0, 0x5FC7, 0x8FE1, 0x5FC8, 0x8FE2, 0x5FCA, 0x8FE3, 0x5FCB, 0x8FE4, 0x5FCE, 0x8FE5, 0x5FD3, 0x8FE6, 0x5FD4, 0x8FE7, 0x5FD5, 0x8FE8, 0x5FDA, 0x8FE9, 0x5FDB, 0x8FEA, 0x5FDC, 0x8FEB, 0x5FDE, 0x8FEC, 0x5FDF, 0x8FED, 0x5FE2, 0x8FEE, 0x5FE3, 0x8FEF, 0x5FE5, 0x8FF0, 0x5FE6, 0x8FF1, 0x5FE8, 0x8FF2, 0x5FE9, 0x8FF3, 0x5FEC, 0x8FF4, 0x5FEF, 0x8FF5, 0x5FF0, 0x8FF6, 0x5FF2, 0x8FF7, 0x5FF3, 0x8FF8, 0x5FF4, 0x8FF9, 0x5FF6, 0x8FFA, 0x5FF7, 0x8FFB, 0x5FF9, 0x8FFC, 0x5FFA, 0x8FFD, 0x5FFC, 0x8FFE, 0x6007, 0x9040, 0x6008, 0x9041, 0x6009, 0x9042, 0x600B, 0x9043, 0x600C, 0x9044, 0x6010, 0x9045, 0x6011, 0x9046, 0x6013, 0x9047, 0x6017, 0x9048, 0x6018, 0x9049, 0x601A, 0x904A, 0x601E, 0x904B, 0x601F, 0x904C, 0x6022, 0x904D, 0x6023, 0x904E, 0x6024, 0x904F, 0x602C, 0x9050, 0x602D, 0x9051, 0x602E, 0x9052, 0x6030, 0x9053, 0x6031, 0x9054, 0x6032, 0x9055, 0x6033, 0x9056, 0x6034, 0x9057, 0x6036, 0x9058, 0x6037, 0x9059, 0x6038, 0x905A, 0x6039, 0x905B, 0x603A, 0x905C, 0x603D, 0x905D, 0x603E, 0x905E, 0x6040, 0x905F, 0x6044, 0x9060, 0x6045, 0x9061, 0x6046, 0x9062, 0x6047, 0x9063, 0x6048, 0x9064, 0x6049, 0x9065, 0x604A, 0x9066, 0x604C, 0x9067, 0x604E, 0x9068, 0x604F, 0x9069, 0x6051, 0x906A, 0x6053, 0x906B, 0x6054, 0x906C, 0x6056, 0x906D, 0x6057, 0x906E, 0x6058, 0x906F, 0x605B, 0x9070, 0x605C, 0x9071, 0x605E, 0x9072, 0x605F, 0x9073, 0x6060, 0x9074, 0x6061, 0x9075, 0x6065, 0x9076, 0x6066, 0x9077, 0x606E, 0x9078, 0x6071, 0x9079, 0x6072, 0x907A, 0x6074, 0x907B, 0x6075, 0x907C, 0x6077, 0x907D, 0x607E, 0x907E, 0x6080, 0x9080, 0x6081, 0x9081, 0x6082, 0x9082, 0x6085, 0x9083, 0x6086, 0x9084, 0x6087, 0x9085, 0x6088, 0x9086, 0x608A, 0x9087, 0x608B, 0x9088, 0x608E, 0x9089, 0x608F, 0x908A, 0x6090, 0x908B, 0x6091, 0x908C, 0x6093, 0x908D, 0x6095, 0x908E, 0x6097, 0x908F, 0x6098, 0x9090, 0x6099, 0x9091, 0x609C, 0x9092, 0x609E, 0x9093, 0x60A1, 0x9094, 0x60A2, 0x9095, 0x60A4, 0x9096, 0x60A5, 0x9097, 0x60A7, 0x9098, 0x60A9, 0x9099, 0x60AA, 0x909A, 0x60AE, 0x909B, 0x60B0, 0x909C, 0x60B3, 0x909D, 0x60B5, 0x909E, 0x60B6, 0x909F, 0x60B7, 0x90A0, 0x60B9, 0x90A1, 0x60BA, 0x90A2, 0x60BD, 0x90A3, 0x60BE, 0x90A4, 0x60BF, 0x90A5, 0x60C0, 0x90A6, 0x60C1, 0x90A7, 0x60C2, 0x90A8, 0x60C3, 0x90A9, 0x60C4, 0x90AA, 0x60C7, 0x90AB, 0x60C8, 0x90AC, 0x60C9, 0x90AD, 0x60CC, 0x90AE, 0x60CD, 0x90AF, 0x60CE, 0x90B0, 0x60CF, 0x90B1, 0x60D0, 0x90B2, 0x60D2, 0x90B3, 0x60D3, 0x90B4, 0x60D4, 0x90B5, 0x60D6, 0x90B6, 0x60D7, 0x90B7, 0x60D9, 0x90B8, 0x60DB, 0x90B9, 0x60DE, 0x90BA, 0x60E1, 0x90BB, 0x60E2, 0x90BC, 0x60E3, 0x90BD, 0x60E4, 0x90BE, 0x60E5, 0x90BF, 0x60EA, 0x90C0, 0x60F1, 0x90C1, 0x60F2, 0x90C2, 0x60F5, 0x90C3, 0x60F7, 0x90C4, 0x60F8, 0x90C5, 0x60FB, 0x90C6, 0x60FC, 0x90C7, 0x60FD, 0x90C8, 0x60FE, 0x90C9, 0x60FF, 0x90CA, 0x6102, 0x90CB, 0x6103, 0x90CC, 0x6104, 0x90CD, 0x6105, 0x90CE, 0x6107, 0x90CF, 0x610A, 0x90D0, 0x610B, 0x90D1, 0x610C, 0x90D2, 0x6110, 0x90D3, 0x6111, 0x90D4, 0x6112, 0x90D5, 0x6113, 0x90D6, 0x6114, 0x90D7, 0x6116, 0x90D8, 0x6117, 0x90D9, 0x6118, 0x90DA, 0x6119, 0x90DB, 0x611B, 0x90DC, 0x611C, 0x90DD, 0x611D, 0x90DE, 0x611E, 0x90DF, 0x6121, 0x90E0, 0x6122, 0x90E1, 0x6125, 0x90E2, 0x6128, 0x90E3, 0x6129, 0x90E4, 0x612A, 0x90E5, 0x612C, 0x90E6, 0x612D, 0x90E7, 0x612E, 0x90E8, 0x612F, 0x90E9, 0x6130, 0x90EA, 0x6131, 0x90EB, 0x6132, 0x90EC, 0x6133, 0x90ED, 0x6134, 0x90EE, 0x6135, 0x90EF, 0x6136, 0x90F0, 0x6137, 0x90F1, 0x6138, 0x90F2, 0x6139, 0x90F3, 0x613A, 0x90F4, 0x613B, 0x90F5, 0x613C, 0x90F6, 0x613D, 0x90F7, 0x613E, 0x90F8, 0x6140, 0x90F9, 0x6141, 0x90FA, 0x6142, 0x90FB, 0x6143, 0x90FC, 0x6144, 0x90FD, 0x6145, 0x90FE, 0x6146, 0x9140, 0x6147, 0x9141, 0x6149, 0x9142, 0x614B, 0x9143, 0x614D, 0x9144, 0x614F, 0x9145, 0x6150, 0x9146, 0x6152, 0x9147, 0x6153, 0x9148, 0x6154, 0x9149, 0x6156, 0x914A, 0x6157, 0x914B, 0x6158, 0x914C, 0x6159, 0x914D, 0x615A, 0x914E, 0x615B, 0x914F, 0x615C, 0x9150, 0x615E, 0x9151, 0x615F, 0x9152, 0x6160, 0x9153, 0x6161, 0x9154, 0x6163, 0x9155, 0x6164, 0x9156, 0x6165, 0x9157, 0x6166, 0x9158, 0x6169, 0x9159, 0x616A, 0x915A, 0x616B, 0x915B, 0x616C, 0x915C, 0x616D, 0x915D, 0x616E, 0x915E, 0x616F, 0x915F, 0x6171, 0x9160, 0x6172, 0x9161, 0x6173, 0x9162, 0x6174, 0x9163, 0x6176, 0x9164, 0x6178, 0x9165, 0x6179, 0x9166, 0x617A, 0x9167, 0x617B, 0x9168, 0x617C, 0x9169, 0x617D, 0x916A, 0x617E, 0x916B, 0x617F, 0x916C, 0x6180, 0x916D, 0x6181, 0x916E, 0x6182, 0x916F, 0x6183, 0x9170, 0x6184, 0x9171, 0x6185, 0x9172, 0x6186, 0x9173, 0x6187, 0x9174, 0x6188, 0x9175, 0x6189, 0x9176, 0x618A, 0x9177, 0x618C, 0x9178, 0x618D, 0x9179, 0x618F, 0x917A, 0x6190, 0x917B, 0x6191, 0x917C, 0x6192, 0x917D, 0x6193, 0x917E, 0x6195, 0x9180, 0x6196, 0x9181, 0x6197, 0x9182, 0x6198, 0x9183, 0x6199, 0x9184, 0x619A, 0x9185, 0x619B, 0x9186, 0x619C, 0x9187, 0x619E, 0x9188, 0x619F, 0x9189, 0x61A0, 0x918A, 0x61A1, 0x918B, 0x61A2, 0x918C, 0x61A3, 0x918D, 0x61A4, 0x918E, 0x61A5, 0x918F, 0x61A6, 0x9190, 0x61AA, 0x9191, 0x61AB, 0x9192, 0x61AD, 0x9193, 0x61AE, 0x9194, 0x61AF, 0x9195, 0x61B0, 0x9196, 0x61B1, 0x9197, 0x61B2, 0x9198, 0x61B3, 0x9199, 0x61B4, 0x919A, 0x61B5, 0x919B, 0x61B6, 0x919C, 0x61B8, 0x919D, 0x61B9, 0x919E, 0x61BA, 0x919F, 0x61BB, 0x91A0, 0x61BC, 0x91A1, 0x61BD, 0x91A2, 0x61BF, 0x91A3, 0x61C0, 0x91A4, 0x61C1, 0x91A5, 0x61C3, 0x91A6, 0x61C4, 0x91A7, 0x61C5, 0x91A8, 0x61C6, 0x91A9, 0x61C7, 0x91AA, 0x61C9, 0x91AB, 0x61CC, 0x91AC, 0x61CD, 0x91AD, 0x61CE, 0x91AE, 0x61CF, 0x91AF, 0x61D0, 0x91B0, 0x61D3, 0x91B1, 0x61D5, 0x91B2, 0x61D6, 0x91B3, 0x61D7, 0x91B4, 0x61D8, 0x91B5, 0x61D9, 0x91B6, 0x61DA, 0x91B7, 0x61DB, 0x91B8, 0x61DC, 0x91B9, 0x61DD, 0x91BA, 0x61DE, 0x91BB, 0x61DF, 0x91BC, 0x61E0, 0x91BD, 0x61E1, 0x91BE, 0x61E2, 0x91BF, 0x61E3, 0x91C0, 0x61E4, 0x91C1, 0x61E5, 0x91C2, 0x61E7, 0x91C3, 0x61E8, 0x91C4, 0x61E9, 0x91C5, 0x61EA, 0x91C6, 0x61EB, 0x91C7, 0x61EC, 0x91C8, 0x61ED, 0x91C9, 0x61EE, 0x91CA, 0x61EF, 0x91CB, 0x61F0, 0x91CC, 0x61F1, 0x91CD, 0x61F2, 0x91CE, 0x61F3, 0x91CF, 0x61F4, 0x91D0, 0x61F6, 0x91D1, 0x61F7, 0x91D2, 0x61F8, 0x91D3, 0x61F9, 0x91D4, 0x61FA, 0x91D5, 0x61FB, 0x91D6, 0x61FC, 0x91D7, 0x61FD, 0x91D8, 0x61FE, 0x91D9, 0x6200, 0x91DA, 0x6201, 0x91DB, 0x6202, 0x91DC, 0x6203, 0x91DD, 0x6204, 0x91DE, 0x6205, 0x91DF, 0x6207, 0x91E0, 0x6209, 0x91E1, 0x6213, 0x91E2, 0x6214, 0x91E3, 0x6219, 0x91E4, 0x621C, 0x91E5, 0x621D, 0x91E6, 0x621E, 0x91E7, 0x6220, 0x91E8, 0x6223, 0x91E9, 0x6226, 0x91EA, 0x6227, 0x91EB, 0x6228, 0x91EC, 0x6229, 0x91ED, 0x622B, 0x91EE, 0x622D, 0x91EF, 0x622F, 0x91F0, 0x6230, 0x91F1, 0x6231, 0x91F2, 0x6232, 0x91F3, 0x6235, 0x91F4, 0x6236, 0x91F5, 0x6238, 0x91F6, 0x6239, 0x91F7, 0x623A, 0x91F8, 0x623B, 0x91F9, 0x623C, 0x91FA, 0x6242, 0x91FB, 0x6244, 0x91FC, 0x6245, 0x91FD, 0x6246, 0x91FE, 0x624A, 0x9240, 0x624F, 0x9241, 0x6250, 0x9242, 0x6255, 0x9243, 0x6256, 0x9244, 0x6257, 0x9245, 0x6259, 0x9246, 0x625A, 0x9247, 0x625C, 0x9248, 0x625D, 0x9249, 0x625E, 0x924A, 0x625F, 0x924B, 0x6260, 0x924C, 0x6261, 0x924D, 0x6262, 0x924E, 0x6264, 0x924F, 0x6265, 0x9250, 0x6268, 0x9251, 0x6271, 0x9252, 0x6272, 0x9253, 0x6274, 0x9254, 0x6275, 0x9255, 0x6277, 0x9256, 0x6278, 0x9257, 0x627A, 0x9258, 0x627B, 0x9259, 0x627D, 0x925A, 0x6281, 0x925B, 0x6282, 0x925C, 0x6283, 0x925D, 0x6285, 0x925E, 0x6286, 0x925F, 0x6287, 0x9260, 0x6288, 0x9261, 0x628B, 0x9262, 0x628C, 0x9263, 0x628D, 0x9264, 0x628E, 0x9265, 0x628F, 0x9266, 0x6290, 0x9267, 0x6294, 0x9268, 0x6299, 0x9269, 0x629C, 0x926A, 0x629D, 0x926B, 0x629E, 0x926C, 0x62A3, 0x926D, 0x62A6, 0x926E, 0x62A7, 0x926F, 0x62A9, 0x9270, 0x62AA, 0x9271, 0x62AD, 0x9272, 0x62AE, 0x9273, 0x62AF, 0x9274, 0x62B0, 0x9275, 0x62B2, 0x9276, 0x62B3, 0x9277, 0x62B4, 0x9278, 0x62B6, 0x9279, 0x62B7, 0x927A, 0x62B8, 0x927B, 0x62BA, 0x927C, 0x62BE, 0x927D, 0x62C0, 0x927E, 0x62C1, 0x9280, 0x62C3, 0x9281, 0x62CB, 0x9282, 0x62CF, 0x9283, 0x62D1, 0x9284, 0x62D5, 0x9285, 0x62DD, 0x9286, 0x62DE, 0x9287, 0x62E0, 0x9288, 0x62E1, 0x9289, 0x62E4, 0x928A, 0x62EA, 0x928B, 0x62EB, 0x928C, 0x62F0, 0x928D, 0x62F2, 0x928E, 0x62F5, 0x928F, 0x62F8, 0x9290, 0x62F9, 0x9291, 0x62FA, 0x9292, 0x62FB, 0x9293, 0x6300, 0x9294, 0x6303, 0x9295, 0x6304, 0x9296, 0x6305, 0x9297, 0x6306, 0x9298, 0x630A, 0x9299, 0x630B, 0x929A, 0x630C, 0x929B, 0x630D, 0x929C, 0x630F, 0x929D, 0x6310, 0x929E, 0x6312, 0x929F, 0x6313, 0x92A0, 0x6314, 0x92A1, 0x6315, 0x92A2, 0x6317, 0x92A3, 0x6318, 0x92A4, 0x6319, 0x92A5, 0x631C, 0x92A6, 0x6326, 0x92A7, 0x6327, 0x92A8, 0x6329, 0x92A9, 0x632C, 0x92AA, 0x632D, 0x92AB, 0x632E, 0x92AC, 0x6330, 0x92AD, 0x6331, 0x92AE, 0x6333, 0x92AF, 0x6334, 0x92B0, 0x6335, 0x92B1, 0x6336, 0x92B2, 0x6337, 0x92B3, 0x6338, 0x92B4, 0x633B, 0x92B5, 0x633C, 0x92B6, 0x633E, 0x92B7, 0x633F, 0x92B8, 0x6340, 0x92B9, 0x6341, 0x92BA, 0x6344, 0x92BB, 0x6347, 0x92BC, 0x6348, 0x92BD, 0x634A, 0x92BE, 0x6351, 0x92BF, 0x6352, 0x92C0, 0x6353, 0x92C1, 0x6354, 0x92C2, 0x6356, 0x92C3, 0x6357, 0x92C4, 0x6358, 0x92C5, 0x6359, 0x92C6, 0x635A, 0x92C7, 0x635B, 0x92C8, 0x635C, 0x92C9, 0x635D, 0x92CA, 0x6360, 0x92CB, 0x6364, 0x92CC, 0x6365, 0x92CD, 0x6366, 0x92CE, 0x6368, 0x92CF, 0x636A, 0x92D0, 0x636B, 0x92D1, 0x636C, 0x92D2, 0x636F, 0x92D3, 0x6370, 0x92D4, 0x6372, 0x92D5, 0x6373, 0x92D6, 0x6374, 0x92D7, 0x6375, 0x92D8, 0x6378, 0x92D9, 0x6379, 0x92DA, 0x637C, 0x92DB, 0x637D, 0x92DC, 0x637E, 0x92DD, 0x637F, 0x92DE, 0x6381, 0x92DF, 0x6383, 0x92E0, 0x6384, 0x92E1, 0x6385, 0x92E2, 0x6386, 0x92E3, 0x638B, 0x92E4, 0x638D, 0x92E5, 0x6391, 0x92E6, 0x6393, 0x92E7, 0x6394, 0x92E8, 0x6395, 0x92E9, 0x6397, 0x92EA, 0x6399, 0x92EB, 0x639A, 0x92EC, 0x639B, 0x92ED, 0x639C, 0x92EE, 0x639D, 0x92EF, 0x639E, 0x92F0, 0x639F, 0x92F1, 0x63A1, 0x92F2, 0x63A4, 0x92F3, 0x63A6, 0x92F4, 0x63AB, 0x92F5, 0x63AF, 0x92F6, 0x63B1, 0x92F7, 0x63B2, 0x92F8, 0x63B5, 0x92F9, 0x63B6, 0x92FA, 0x63B9, 0x92FB, 0x63BB, 0x92FC, 0x63BD, 0x92FD, 0x63BF, 0x92FE, 0x63C0, 0x9340, 0x63C1, 0x9341, 0x63C2, 0x9342, 0x63C3, 0x9343, 0x63C5, 0x9344, 0x63C7, 0x9345, 0x63C8, 0x9346, 0x63CA, 0x9347, 0x63CB, 0x9348, 0x63CC, 0x9349, 0x63D1, 0x934A, 0x63D3, 0x934B, 0x63D4, 0x934C, 0x63D5, 0x934D, 0x63D7, 0x934E, 0x63D8, 0x934F, 0x63D9, 0x9350, 0x63DA, 0x9351, 0x63DB, 0x9352, 0x63DC, 0x9353, 0x63DD, 0x9354, 0x63DF, 0x9355, 0x63E2, 0x9356, 0x63E4, 0x9357, 0x63E5, 0x9358, 0x63E6, 0x9359, 0x63E7, 0x935A, 0x63E8, 0x935B, 0x63EB, 0x935C, 0x63EC, 0x935D, 0x63EE, 0x935E, 0x63EF, 0x935F, 0x63F0, 0x9360, 0x63F1, 0x9361, 0x63F3, 0x9362, 0x63F5, 0x9363, 0x63F7, 0x9364, 0x63F9, 0x9365, 0x63FA, 0x9366, 0x63FB, 0x9367, 0x63FC, 0x9368, 0x63FE, 0x9369, 0x6403, 0x936A, 0x6404, 0x936B, 0x6406, 0x936C, 0x6407, 0x936D, 0x6408, 0x936E, 0x6409, 0x936F, 0x640A, 0x9370, 0x640D, 0x9371, 0x640E, 0x9372, 0x6411, 0x9373, 0x6412, 0x9374, 0x6415, 0x9375, 0x6416, 0x9376, 0x6417, 0x9377, 0x6418, 0x9378, 0x6419, 0x9379, 0x641A, 0x937A, 0x641D, 0x937B, 0x641F, 0x937C, 0x6422, 0x937D, 0x6423, 0x937E, 0x6424, 0x9380, 0x6425, 0x9381, 0x6427, 0x9382, 0x6428, 0x9383, 0x6429, 0x9384, 0x642B, 0x9385, 0x642E, 0x9386, 0x642F, 0x9387, 0x6430, 0x9388, 0x6431, 0x9389, 0x6432, 0x938A, 0x6433, 0x938B, 0x6435, 0x938C, 0x6436, 0x938D, 0x6437, 0x938E, 0x6438, 0x938F, 0x6439, 0x9390, 0x643B, 0x9391, 0x643C, 0x9392, 0x643E, 0x9393, 0x6440, 0x9394, 0x6442, 0x9395, 0x6443, 0x9396, 0x6449, 0x9397, 0x644B, 0x9398, 0x644C, 0x9399, 0x644D, 0x939A, 0x644E, 0x939B, 0x644F, 0x939C, 0x6450, 0x939D, 0x6451, 0x939E, 0x6453, 0x939F, 0x6455, 0x93A0, 0x6456, 0x93A1, 0x6457, 0x93A2, 0x6459, 0x93A3, 0x645A, 0x93A4, 0x645B, 0x93A5, 0x645C, 0x93A6, 0x645D, 0x93A7, 0x645F, 0x93A8, 0x6460, 0x93A9, 0x6461, 0x93AA, 0x6462, 0x93AB, 0x6463, 0x93AC, 0x6464, 0x93AD, 0x6465, 0x93AE, 0x6466, 0x93AF, 0x6468, 0x93B0, 0x646A, 0x93B1, 0x646B, 0x93B2, 0x646C, 0x93B3, 0x646E, 0x93B4, 0x646F, 0x93B5, 0x6470, 0x93B6, 0x6471, 0x93B7, 0x6472, 0x93B8, 0x6473, 0x93B9, 0x6474, 0x93BA, 0x6475, 0x93BB, 0x6476, 0x93BC, 0x6477, 0x93BD, 0x647B, 0x93BE, 0x647C, 0x93BF, 0x647D, 0x93C0, 0x647E, 0x93C1, 0x647F, 0x93C2, 0x6480, 0x93C3, 0x6481, 0x93C4, 0x6483, 0x93C5, 0x6486, 0x93C6, 0x6488, 0x93C7, 0x6489, 0x93C8, 0x648A, 0x93C9, 0x648B, 0x93CA, 0x648C, 0x93CB, 0x648D, 0x93CC, 0x648E, 0x93CD, 0x648F, 0x93CE, 0x6490, 0x93CF, 0x6493, 0x93D0, 0x6494, 0x93D1, 0x6497, 0x93D2, 0x6498, 0x93D3, 0x649A, 0x93D4, 0x649B, 0x93D5, 0x649C, 0x93D6, 0x649D, 0x93D7, 0x649F, 0x93D8, 0x64A0, 0x93D9, 0x64A1, 0x93DA, 0x64A2, 0x93DB, 0x64A3, 0x93DC, 0x64A5, 0x93DD, 0x64A6, 0x93DE, 0x64A7, 0x93DF, 0x64A8, 0x93E0, 0x64AA, 0x93E1, 0x64AB, 0x93E2, 0x64AF, 0x93E3, 0x64B1, 0x93E4, 0x64B2, 0x93E5, 0x64B3, 0x93E6, 0x64B4, 0x93E7, 0x64B6, 0x93E8, 0x64B9, 0x93E9, 0x64BB, 0x93EA, 0x64BD, 0x93EB, 0x64BE, 0x93EC, 0x64BF, 0x93ED, 0x64C1, 0x93EE, 0x64C3, 0x93EF, 0x64C4, 0x93F0, 0x64C6, 0x93F1, 0x64C7, 0x93F2, 0x64C8, 0x93F3, 0x64C9, 0x93F4, 0x64CA, 0x93F5, 0x64CB, 0x93F6, 0x64CC, 0x93F7, 0x64CF, 0x93F8, 0x64D1, 0x93F9, 0x64D3, 0x93FA, 0x64D4, 0x93FB, 0x64D5, 0x93FC, 0x64D6, 0x93FD, 0x64D9, 0x93FE, 0x64DA, 0x9440, 0x64DB, 0x9441, 0x64DC, 0x9442, 0x64DD, 0x9443, 0x64DF, 0x9444, 0x64E0, 0x9445, 0x64E1, 0x9446, 0x64E3, 0x9447, 0x64E5, 0x9448, 0x64E7, 0x9449, 0x64E8, 0x944A, 0x64E9, 0x944B, 0x64EA, 0x944C, 0x64EB, 0x944D, 0x64EC, 0x944E, 0x64ED, 0x944F, 0x64EE, 0x9450, 0x64EF, 0x9451, 0x64F0, 0x9452, 0x64F1, 0x9453, 0x64F2, 0x9454, 0x64F3, 0x9455, 0x64F4, 0x9456, 0x64F5, 0x9457, 0x64F6, 0x9458, 0x64F7, 0x9459, 0x64F8, 0x945A, 0x64F9, 0x945B, 0x64FA, 0x945C, 0x64FB, 0x945D, 0x64FC, 0x945E, 0x64FD, 0x945F, 0x64FE, 0x9460, 0x64FF, 0x9461, 0x6501, 0x9462, 0x6502, 0x9463, 0x6503, 0x9464, 0x6504, 0x9465, 0x6505, 0x9466, 0x6506, 0x9467, 0x6507, 0x9468, 0x6508, 0x9469, 0x650A, 0x946A, 0x650B, 0x946B, 0x650C, 0x946C, 0x650D, 0x946D, 0x650E, 0x946E, 0x650F, 0x946F, 0x6510, 0x9470, 0x6511, 0x9471, 0x6513, 0x9472, 0x6514, 0x9473, 0x6515, 0x9474, 0x6516, 0x9475, 0x6517, 0x9476, 0x6519, 0x9477, 0x651A, 0x9478, 0x651B, 0x9479, 0x651C, 0x947A, 0x651D, 0x947B, 0x651E, 0x947C, 0x651F, 0x947D, 0x6520, 0x947E, 0x6521, 0x9480, 0x6522, 0x9481, 0x6523, 0x9482, 0x6524, 0x9483, 0x6526, 0x9484, 0x6527, 0x9485, 0x6528, 0x9486, 0x6529, 0x9487, 0x652A, 0x9488, 0x652C, 0x9489, 0x652D, 0x948A, 0x6530, 0x948B, 0x6531, 0x948C, 0x6532, 0x948D, 0x6533, 0x948E, 0x6537, 0x948F, 0x653A, 0x9490, 0x653C, 0x9491, 0x653D, 0x9492, 0x6540, 0x9493, 0x6541, 0x9494, 0x6542, 0x9495, 0x6543, 0x9496, 0x6544, 0x9497, 0x6546, 0x9498, 0x6547, 0x9499, 0x654A, 0x949A, 0x654B, 0x949B, 0x654D, 0x949C, 0x654E, 0x949D, 0x6550, 0x949E, 0x6552, 0x949F, 0x6553, 0x94A0, 0x6554, 0x94A1, 0x6557, 0x94A2, 0x6558, 0x94A3, 0x655A, 0x94A4, 0x655C, 0x94A5, 0x655F, 0x94A6, 0x6560, 0x94A7, 0x6561, 0x94A8, 0x6564, 0x94A9, 0x6565, 0x94AA, 0x6567, 0x94AB, 0x6568, 0x94AC, 0x6569, 0x94AD, 0x656A, 0x94AE, 0x656D, 0x94AF, 0x656E, 0x94B0, 0x656F, 0x94B1, 0x6571, 0x94B2, 0x6573, 0x94B3, 0x6575, 0x94B4, 0x6576, 0x94B5, 0x6578, 0x94B6, 0x6579, 0x94B7, 0x657A, 0x94B8, 0x657B, 0x94B9, 0x657C, 0x94BA, 0x657D, 0x94BB, 0x657E, 0x94BC, 0x657F, 0x94BD, 0x6580, 0x94BE, 0x6581, 0x94BF, 0x6582, 0x94C0, 0x6583, 0x94C1, 0x6584, 0x94C2, 0x6585, 0x94C3, 0x6586, 0x94C4, 0x6588, 0x94C5, 0x6589, 0x94C6, 0x658A, 0x94C7, 0x658D, 0x94C8, 0x658E, 0x94C9, 0x658F, 0x94CA, 0x6592, 0x94CB, 0x6594, 0x94CC, 0x6595, 0x94CD, 0x6596, 0x94CE, 0x6598, 0x94CF, 0x659A, 0x94D0, 0x659D, 0x94D1, 0x659E, 0x94D2, 0x65A0, 0x94D3, 0x65A2, 0x94D4, 0x65A3, 0x94D5, 0x65A6, 0x94D6, 0x65A8, 0x94D7, 0x65AA, 0x94D8, 0x65AC, 0x94D9, 0x65AE, 0x94DA, 0x65B1, 0x94DB, 0x65B2, 0x94DC, 0x65B3, 0x94DD, 0x65B4, 0x94DE, 0x65B5, 0x94DF, 0x65B6, 0x94E0, 0x65B7, 0x94E1, 0x65B8, 0x94E2, 0x65BA, 0x94E3, 0x65BB, 0x94E4, 0x65BE, 0x94E5, 0x65BF, 0x94E6, 0x65C0, 0x94E7, 0x65C2, 0x94E8, 0x65C7, 0x94E9, 0x65C8, 0x94EA, 0x65C9, 0x94EB, 0x65CA, 0x94EC, 0x65CD, 0x94ED, 0x65D0, 0x94EE, 0x65D1, 0x94EF, 0x65D3, 0x94F0, 0x65D4, 0x94F1, 0x65D5, 0x94F2, 0x65D8, 0x94F3, 0x65D9, 0x94F4, 0x65DA, 0x94F5, 0x65DB, 0x94F6, 0x65DC, 0x94F7, 0x65DD, 0x94F8, 0x65DE, 0x94F9, 0x65DF, 0x94FA, 0x65E1, 0x94FB, 0x65E3, 0x94FC, 0x65E4, 0x94FD, 0x65EA, 0x94FE, 0x65EB, 0x9540, 0x65F2, 0x9541, 0x65F3, 0x9542, 0x65F4, 0x9543, 0x65F5, 0x9544, 0x65F8, 0x9545, 0x65F9, 0x9546, 0x65FB, 0x9547, 0x65FC, 0x9548, 0x65FD, 0x9549, 0x65FE, 0x954A, 0x65FF, 0x954B, 0x6601, 0x954C, 0x6604, 0x954D, 0x6605, 0x954E, 0x6607, 0x954F, 0x6608, 0x9550, 0x6609, 0x9551, 0x660B, 0x9552, 0x660D, 0x9553, 0x6610, 0x9554, 0x6611, 0x9555, 0x6612, 0x9556, 0x6616, 0x9557, 0x6617, 0x9558, 0x6618, 0x9559, 0x661A, 0x955A, 0x661B, 0x955B, 0x661C, 0x955C, 0x661E, 0x955D, 0x6621, 0x955E, 0x6622, 0x955F, 0x6623, 0x9560, 0x6624, 0x9561, 0x6626, 0x9562, 0x6629, 0x9563, 0x662A, 0x9564, 0x662B, 0x9565, 0x662C, 0x9566, 0x662E, 0x9567, 0x6630, 0x9568, 0x6632, 0x9569, 0x6633, 0x956A, 0x6637, 0x956B, 0x6638, 0x956C, 0x6639, 0x956D, 0x663A, 0x956E, 0x663B, 0x956F, 0x663D, 0x9570, 0x663F, 0x9571, 0x6640, 0x9572, 0x6642, 0x9573, 0x6644, 0x9574, 0x6645, 0x9575, 0x6646, 0x9576, 0x6647, 0x9577, 0x6648, 0x9578, 0x6649, 0x9579, 0x664A, 0x957A, 0x664D, 0x957B, 0x664E, 0x957C, 0x6650, 0x957D, 0x6651, 0x957E, 0x6658, 0x9580, 0x6659, 0x9581, 0x665B, 0x9582, 0x665C, 0x9583, 0x665D, 0x9584, 0x665E, 0x9585, 0x6660, 0x9586, 0x6662, 0x9587, 0x6663, 0x9588, 0x6665, 0x9589, 0x6667, 0x958A, 0x6669, 0x958B, 0x666A, 0x958C, 0x666B, 0x958D, 0x666C, 0x958E, 0x666D, 0x958F, 0x6671, 0x9590, 0x6672, 0x9591, 0x6673, 0x9592, 0x6675, 0x9593, 0x6678, 0x9594, 0x6679, 0x9595, 0x667B, 0x9596, 0x667C, 0x9597, 0x667D, 0x9598, 0x667F, 0x9599, 0x6680, 0x959A, 0x6681, 0x959B, 0x6683, 0x959C, 0x6685, 0x959D, 0x6686, 0x959E, 0x6688, 0x959F, 0x6689, 0x95A0, 0x668A, 0x95A1, 0x668B, 0x95A2, 0x668D, 0x95A3, 0x668E, 0x95A4, 0x668F, 0x95A5, 0x6690, 0x95A6, 0x6692, 0x95A7, 0x6693, 0x95A8, 0x6694, 0x95A9, 0x6695, 0x95AA, 0x6698, 0x95AB, 0x6699, 0x95AC, 0x669A, 0x95AD, 0x669B, 0x95AE, 0x669C, 0x95AF, 0x669E, 0x95B0, 0x669F, 0x95B1, 0x66A0, 0x95B2, 0x66A1, 0x95B3, 0x66A2, 0x95B4, 0x66A3, 0x95B5, 0x66A4, 0x95B6, 0x66A5, 0x95B7, 0x66A6, 0x95B8, 0x66A9, 0x95B9, 0x66AA, 0x95BA, 0x66AB, 0x95BB, 0x66AC, 0x95BC, 0x66AD, 0x95BD, 0x66AF, 0x95BE, 0x66B0, 0x95BF, 0x66B1, 0x95C0, 0x66B2, 0x95C1, 0x66B3, 0x95C2, 0x66B5, 0x95C3, 0x66B6, 0x95C4, 0x66B7, 0x95C5, 0x66B8, 0x95C6, 0x66BA, 0x95C7, 0x66BB, 0x95C8, 0x66BC, 0x95C9, 0x66BD, 0x95CA, 0x66BF, 0x95CB, 0x66C0, 0x95CC, 0x66C1, 0x95CD, 0x66C2, 0x95CE, 0x66C3, 0x95CF, 0x66C4, 0x95D0, 0x66C5, 0x95D1, 0x66C6, 0x95D2, 0x66C7, 0x95D3, 0x66C8, 0x95D4, 0x66C9, 0x95D5, 0x66CA, 0x95D6, 0x66CB, 0x95D7, 0x66CC, 0x95D8, 0x66CD, 0x95D9, 0x66CE, 0x95DA, 0x66CF, 0x95DB, 0x66D0, 0x95DC, 0x66D1, 0x95DD, 0x66D2, 0x95DE, 0x66D3, 0x95DF, 0x66D4, 0x95E0, 0x66D5, 0x95E1, 0x66D6, 0x95E2, 0x66D7, 0x95E3, 0x66D8, 0x95E4, 0x66DA, 0x95E5, 0x66DE, 0x95E6, 0x66DF, 0x95E7, 0x66E0, 0x95E8, 0x66E1, 0x95E9, 0x66E2, 0x95EA, 0x66E3, 0x95EB, 0x66E4, 0x95EC, 0x66E5, 0x95ED, 0x66E7, 0x95EE, 0x66E8, 0x95EF, 0x66EA, 0x95F0, 0x66EB, 0x95F1, 0x66EC, 0x95F2, 0x66ED, 0x95F3, 0x66EE, 0x95F4, 0x66EF, 0x95F5, 0x66F1, 0x95F6, 0x66F5, 0x95F7, 0x66F6, 0x95F8, 0x66F8, 0x95F9, 0x66FA, 0x95FA, 0x66FB, 0x95FB, 0x66FD, 0x95FC, 0x6701, 0x95FD, 0x6702, 0x95FE, 0x6703, 0x9640, 0x6704, 0x9641, 0x6705, 0x9642, 0x6706, 0x9643, 0x6707, 0x9644, 0x670C, 0x9645, 0x670E, 0x9646, 0x670F, 0x9647, 0x6711, 0x9648, 0x6712, 0x9649, 0x6713, 0x964A, 0x6716, 0x964B, 0x6718, 0x964C, 0x6719, 0x964D, 0x671A, 0x964E, 0x671C, 0x964F, 0x671E, 0x9650, 0x6720, 0x9651, 0x6721, 0x9652, 0x6722, 0x9653, 0x6723, 0x9654, 0x6724, 0x9655, 0x6725, 0x9656, 0x6727, 0x9657, 0x6729, 0x9658, 0x672E, 0x9659, 0x6730, 0x965A, 0x6732, 0x965B, 0x6733, 0x965C, 0x6736, 0x965D, 0x6737, 0x965E, 0x6738, 0x965F, 0x6739, 0x9660, 0x673B, 0x9661, 0x673C, 0x9662, 0x673E, 0x9663, 0x673F, 0x9664, 0x6741, 0x9665, 0x6744, 0x9666, 0x6745, 0x9667, 0x6747, 0x9668, 0x674A, 0x9669, 0x674B, 0x966A, 0x674D, 0x966B, 0x6752, 0x966C, 0x6754, 0x966D, 0x6755, 0x966E, 0x6757, 0x966F, 0x6758, 0x9670, 0x6759, 0x9671, 0x675A, 0x9672, 0x675B, 0x9673, 0x675D, 0x9674, 0x6762, 0x9675, 0x6763, 0x9676, 0x6764, 0x9677, 0x6766, 0x9678, 0x6767, 0x9679, 0x676B, 0x967A, 0x676C, 0x967B, 0x676E, 0x967C, 0x6771, 0x967D, 0x6774, 0x967E, 0x6776, 0x9680, 0x6778, 0x9681, 0x6779, 0x9682, 0x677A, 0x9683, 0x677B, 0x9684, 0x677D, 0x9685, 0x6780, 0x9686, 0x6782, 0x9687, 0x6783, 0x9688, 0x6785, 0x9689, 0x6786, 0x968A, 0x6788, 0x968B, 0x678A, 0x968C, 0x678C, 0x968D, 0x678D, 0x968E, 0x678E, 0x968F, 0x678F, 0x9690, 0x6791, 0x9691, 0x6792, 0x9692, 0x6793, 0x9693, 0x6794, 0x9694, 0x6796, 0x9695, 0x6799, 0x9696, 0x679B, 0x9697, 0x679F, 0x9698, 0x67A0, 0x9699, 0x67A1, 0x969A, 0x67A4, 0x969B, 0x67A6, 0x969C, 0x67A9, 0x969D, 0x67AC, 0x969E, 0x67AE, 0x969F, 0x67B1, 0x96A0, 0x67B2, 0x96A1, 0x67B4, 0x96A2, 0x67B9, 0x96A3, 0x67BA, 0x96A4, 0x67BB, 0x96A5, 0x67BC, 0x96A6, 0x67BD, 0x96A7, 0x67BE, 0x96A8, 0x67BF, 0x96A9, 0x67C0, 0x96AA, 0x67C2, 0x96AB, 0x67C5, 0x96AC, 0x67C6, 0x96AD, 0x67C7, 0x96AE, 0x67C8, 0x96AF, 0x67C9, 0x96B0, 0x67CA, 0x96B1, 0x67CB, 0x96B2, 0x67CC, 0x96B3, 0x67CD, 0x96B4, 0x67CE, 0x96B5, 0x67D5, 0x96B6, 0x67D6, 0x96B7, 0x67D7, 0x96B8, 0x67DB, 0x96B9, 0x67DF, 0x96BA, 0x67E1, 0x96BB, 0x67E3, 0x96BC, 0x67E4, 0x96BD, 0x67E6, 0x96BE, 0x67E7, 0x96BF, 0x67E8, 0x96C0, 0x67EA, 0x96C1, 0x67EB, 0x96C2, 0x67ED, 0x96C3, 0x67EE, 0x96C4, 0x67F2, 0x96C5, 0x67F5, 0x96C6, 0x67F6, 0x96C7, 0x67F7, 0x96C8, 0x67F8, 0x96C9, 0x67F9, 0x96CA, 0x67FA, 0x96CB, 0x67FB, 0x96CC, 0x67FC, 0x96CD, 0x67FE, 0x96CE, 0x6801, 0x96CF, 0x6802, 0x96D0, 0x6803, 0x96D1, 0x6804, 0x96D2, 0x6806, 0x96D3, 0x680D, 0x96D4, 0x6810, 0x96D5, 0x6812, 0x96D6, 0x6814, 0x96D7, 0x6815, 0x96D8, 0x6818, 0x96D9, 0x6819, 0x96DA, 0x681A, 0x96DB, 0x681B, 0x96DC, 0x681C, 0x96DD, 0x681E, 0x96DE, 0x681F, 0x96DF, 0x6820, 0x96E0, 0x6822, 0x96E1, 0x6823, 0x96E2, 0x6824, 0x96E3, 0x6825, 0x96E4, 0x6826, 0x96E5, 0x6827, 0x96E6, 0x6828, 0x96E7, 0x682B, 0x96E8, 0x682C, 0x96E9, 0x682D, 0x96EA, 0x682E, 0x96EB, 0x682F, 0x96EC, 0x6830, 0x96ED, 0x6831, 0x96EE, 0x6834, 0x96EF, 0x6835, 0x96F0, 0x6836, 0x96F1, 0x683A, 0x96F2, 0x683B, 0x96F3, 0x683F, 0x96F4, 0x6847, 0x96F5, 0x684B, 0x96F6, 0x684D, 0x96F7, 0x684F, 0x96F8, 0x6852, 0x96F9, 0x6856, 0x96FA, 0x6857, 0x96FB, 0x6858, 0x96FC, 0x6859, 0x96FD, 0x685A, 0x96FE, 0x685B, 0x9740, 0x685C, 0x9741, 0x685D, 0x9742, 0x685E, 0x9743, 0x685F, 0x9744, 0x686A, 0x9745, 0x686C, 0x9746, 0x686D, 0x9747, 0x686E, 0x9748, 0x686F, 0x9749, 0x6870, 0x974A, 0x6871, 0x974B, 0x6872, 0x974C, 0x6873, 0x974D, 0x6875, 0x974E, 0x6878, 0x974F, 0x6879, 0x9750, 0x687A, 0x9751, 0x687B, 0x9752, 0x687C, 0x9753, 0x687D, 0x9754, 0x687E, 0x9755, 0x687F, 0x9756, 0x6880, 0x9757, 0x6882, 0x9758, 0x6884, 0x9759, 0x6887, 0x975A, 0x6888, 0x975B, 0x6889, 0x975C, 0x688A, 0x975D, 0x688B, 0x975E, 0x688C, 0x975F, 0x688D, 0x9760, 0x688E, 0x9761, 0x6890, 0x9762, 0x6891, 0x9763, 0x6892, 0x9764, 0x6894, 0x9765, 0x6895, 0x9766, 0x6896, 0x9767, 0x6898, 0x9768, 0x6899, 0x9769, 0x689A, 0x976A, 0x689B, 0x976B, 0x689C, 0x976C, 0x689D, 0x976D, 0x689E, 0x976E, 0x689F, 0x976F, 0x68A0, 0x9770, 0x68A1, 0x9771, 0x68A3, 0x9772, 0x68A4, 0x9773, 0x68A5, 0x9774, 0x68A9, 0x9775, 0x68AA, 0x9776, 0x68AB, 0x9777, 0x68AC, 0x9778, 0x68AE, 0x9779, 0x68B1, 0x977A, 0x68B2, 0x977B, 0x68B4, 0x977C, 0x68B6, 0x977D, 0x68B7, 0x977E, 0x68B8, 0x9780, 0x68B9, 0x9781, 0x68BA, 0x9782, 0x68BB, 0x9783, 0x68BC, 0x9784, 0x68BD, 0x9785, 0x68BE, 0x9786, 0x68BF, 0x9787, 0x68C1, 0x9788, 0x68C3, 0x9789, 0x68C4, 0x978A, 0x68C5, 0x978B, 0x68C6, 0x978C, 0x68C7, 0x978D, 0x68C8, 0x978E, 0x68CA, 0x978F, 0x68CC, 0x9790, 0x68CE, 0x9791, 0x68CF, 0x9792, 0x68D0, 0x9793, 0x68D1, 0x9794, 0x68D3, 0x9795, 0x68D4, 0x9796, 0x68D6, 0x9797, 0x68D7, 0x9798, 0x68D9, 0x9799, 0x68DB, 0x979A, 0x68DC, 0x979B, 0x68DD, 0x979C, 0x68DE, 0x979D, 0x68DF, 0x979E, 0x68E1, 0x979F, 0x68E2, 0x97A0, 0x68E4, 0x97A1, 0x68E5, 0x97A2, 0x68E6, 0x97A3, 0x68E7, 0x97A4, 0x68E8, 0x97A5, 0x68E9, 0x97A6, 0x68EA, 0x97A7, 0x68EB, 0x97A8, 0x68EC, 0x97A9, 0x68ED, 0x97AA, 0x68EF, 0x97AB, 0x68F2, 0x97AC, 0x68F3, 0x97AD, 0x68F4, 0x97AE, 0x68F6, 0x97AF, 0x68F7, 0x97B0, 0x68F8, 0x97B1, 0x68FB, 0x97B2, 0x68FD, 0x97B3, 0x68FE, 0x97B4, 0x68FF, 0x97B5, 0x6900, 0x97B6, 0x6902, 0x97B7, 0x6903, 0x97B8, 0x6904, 0x97B9, 0x6906, 0x97BA, 0x6907, 0x97BB, 0x6908, 0x97BC, 0x6909, 0x97BD, 0x690A, 0x97BE, 0x690C, 0x97BF, 0x690F, 0x97C0, 0x6911, 0x97C1, 0x6913, 0x97C2, 0x6914, 0x97C3, 0x6915, 0x97C4, 0x6916, 0x97C5, 0x6917, 0x97C6, 0x6918, 0x97C7, 0x6919, 0x97C8, 0x691A, 0x97C9, 0x691B, 0x97CA, 0x691C, 0x97CB, 0x691D, 0x97CC, 0x691E, 0x97CD, 0x6921, 0x97CE, 0x6922, 0x97CF, 0x6923, 0x97D0, 0x6925, 0x97D1, 0x6926, 0x97D2, 0x6927, 0x97D3, 0x6928, 0x97D4, 0x6929, 0x97D5, 0x692A, 0x97D6, 0x692B, 0x97D7, 0x692C, 0x97D8, 0x692E, 0x97D9, 0x692F, 0x97DA, 0x6931, 0x97DB, 0x6932, 0x97DC, 0x6933, 0x97DD, 0x6935, 0x97DE, 0x6936, 0x97DF, 0x6937, 0x97E0, 0x6938, 0x97E1, 0x693A, 0x97E2, 0x693B, 0x97E3, 0x693C, 0x97E4, 0x693E, 0x97E5, 0x6940, 0x97E6, 0x6941, 0x97E7, 0x6943, 0x97E8, 0x6944, 0x97E9, 0x6945, 0x97EA, 0x6946, 0x97EB, 0x6947, 0x97EC, 0x6948, 0x97ED, 0x6949, 0x97EE, 0x694A, 0x97EF, 0x694B, 0x97F0, 0x694C, 0x97F1, 0x694D, 0x97F2, 0x694E, 0x97F3, 0x694F, 0x97F4, 0x6950, 0x97F5, 0x6951, 0x97F6, 0x6952, 0x97F7, 0x6953, 0x97F8, 0x6955, 0x97F9, 0x6956, 0x97FA, 0x6958, 0x97FB, 0x6959, 0x97FC, 0x695B, 0x97FD, 0x695C, 0x97FE, 0x695F, 0x9840, 0x6961, 0x9841, 0x6962, 0x9842, 0x6964, 0x9843, 0x6965, 0x9844, 0x6967, 0x9845, 0x6968, 0x9846, 0x6969, 0x9847, 0x696A, 0x9848, 0x696C, 0x9849, 0x696D, 0x984A, 0x696F, 0x984B, 0x6970, 0x984C, 0x6972, 0x984D, 0x6973, 0x984E, 0x6974, 0x984F, 0x6975, 0x9850, 0x6976, 0x9851, 0x697A, 0x9852, 0x697B, 0x9853, 0x697D, 0x9854, 0x697E, 0x9855, 0x697F, 0x9856, 0x6981, 0x9857, 0x6983, 0x9858, 0x6985, 0x9859, 0x698A, 0x985A, 0x698B, 0x985B, 0x698C, 0x985C, 0x698E, 0x985D, 0x698F, 0x985E, 0x6990, 0x985F, 0x6991, 0x9860, 0x6992, 0x9861, 0x6993, 0x9862, 0x6996, 0x9863, 0x6997, 0x9864, 0x6999, 0x9865, 0x699A, 0x9866, 0x699D, 0x9867, 0x699E, 0x9868, 0x699F, 0x9869, 0x69A0, 0x986A, 0x69A1, 0x986B, 0x69A2, 0x986C, 0x69A3, 0x986D, 0x69A4, 0x986E, 0x69A5, 0x986F, 0x69A6, 0x9870, 0x69A9, 0x9871, 0x69AA, 0x9872, 0x69AC, 0x9873, 0x69AE, 0x9874, 0x69AF, 0x9875, 0x69B0, 0x9876, 0x69B2, 0x9877, 0x69B3, 0x9878, 0x69B5, 0x9879, 0x69B6, 0x987A, 0x69B8, 0x987B, 0x69B9, 0x987C, 0x69BA, 0x987D, 0x69BC, 0x987E, 0x69BD, 0x9880, 0x69BE, 0x9881, 0x69BF, 0x9882, 0x69C0, 0x9883, 0x69C2, 0x9884, 0x69C3, 0x9885, 0x69C4, 0x9886, 0x69C5, 0x9887, 0x69C6, 0x9888, 0x69C7, 0x9889, 0x69C8, 0x988A, 0x69C9, 0x988B, 0x69CB, 0x988C, 0x69CD, 0x988D, 0x69CF, 0x988E, 0x69D1, 0x988F, 0x69D2, 0x9890, 0x69D3, 0x9891, 0x69D5, 0x9892, 0x69D6, 0x9893, 0x69D7, 0x9894, 0x69D8, 0x9895, 0x69D9, 0x9896, 0x69DA, 0x9897, 0x69DC, 0x9898, 0x69DD, 0x9899, 0x69DE, 0x989A, 0x69E1, 0x989B, 0x69E2, 0x989C, 0x69E3, 0x989D, 0x69E4, 0x989E, 0x69E5, 0x989F, 0x69E6, 0x98A0, 0x69E7, 0x98A1, 0x69E8, 0x98A2, 0x69E9, 0x98A3, 0x69EA, 0x98A4, 0x69EB, 0x98A5, 0x69EC, 0x98A6, 0x69EE, 0x98A7, 0x69EF, 0x98A8, 0x69F0, 0x98A9, 0x69F1, 0x98AA, 0x69F3, 0x98AB, 0x69F4, 0x98AC, 0x69F5, 0x98AD, 0x69F6, 0x98AE, 0x69F7, 0x98AF, 0x69F8, 0x98B0, 0x69F9, 0x98B1, 0x69FA, 0x98B2, 0x69FB, 0x98B3, 0x69FC, 0x98B4, 0x69FE, 0x98B5, 0x6A00, 0x98B6, 0x6A01, 0x98B7, 0x6A02, 0x98B8, 0x6A03, 0x98B9, 0x6A04, 0x98BA, 0x6A05, 0x98BB, 0x6A06, 0x98BC, 0x6A07, 0x98BD, 0x6A08, 0x98BE, 0x6A09, 0x98BF, 0x6A0B, 0x98C0, 0x6A0C, 0x98C1, 0x6A0D, 0x98C2, 0x6A0E, 0x98C3, 0x6A0F, 0x98C4, 0x6A10, 0x98C5, 0x6A11, 0x98C6, 0x6A12, 0x98C7, 0x6A13, 0x98C8, 0x6A14, 0x98C9, 0x6A15, 0x98CA, 0x6A16, 0x98CB, 0x6A19, 0x98CC, 0x6A1A, 0x98CD, 0x6A1B, 0x98CE, 0x6A1C, 0x98CF, 0x6A1D, 0x98D0, 0x6A1E, 0x98D1, 0x6A20, 0x98D2, 0x6A22, 0x98D3, 0x6A23, 0x98D4, 0x6A24, 0x98D5, 0x6A25, 0x98D6, 0x6A26, 0x98D7, 0x6A27, 0x98D8, 0x6A29, 0x98D9, 0x6A2B, 0x98DA, 0x6A2C, 0x98DB, 0x6A2D, 0x98DC, 0x6A2E, 0x98DD, 0x6A30, 0x98DE, 0x6A32, 0x98DF, 0x6A33, 0x98E0, 0x6A34, 0x98E1, 0x6A36, 0x98E2, 0x6A37, 0x98E3, 0x6A38, 0x98E4, 0x6A39, 0x98E5, 0x6A3A, 0x98E6, 0x6A3B, 0x98E7, 0x6A3C, 0x98E8, 0x6A3F, 0x98E9, 0x6A40, 0x98EA, 0x6A41, 0x98EB, 0x6A42, 0x98EC, 0x6A43, 0x98ED, 0x6A45, 0x98EE, 0x6A46, 0x98EF, 0x6A48, 0x98F0, 0x6A49, 0x98F1, 0x6A4A, 0x98F2, 0x6A4B, 0x98F3, 0x6A4C, 0x98F4, 0x6A4D, 0x98F5, 0x6A4E, 0x98F6, 0x6A4F, 0x98F7, 0x6A51, 0x98F8, 0x6A52, 0x98F9, 0x6A53, 0x98FA, 0x6A54, 0x98FB, 0x6A55, 0x98FC, 0x6A56, 0x98FD, 0x6A57, 0x98FE, 0x6A5A, 0x9940, 0x6A5C, 0x9941, 0x6A5D, 0x9942, 0x6A5E, 0x9943, 0x6A5F, 0x9944, 0x6A60, 0x9945, 0x6A62, 0x9946, 0x6A63, 0x9947, 0x6A64, 0x9948, 0x6A66, 0x9949, 0x6A67, 0x994A, 0x6A68, 0x994B, 0x6A69, 0x994C, 0x6A6A, 0x994D, 0x6A6B, 0x994E, 0x6A6C, 0x994F, 0x6A6D, 0x9950, 0x6A6E, 0x9951, 0x6A6F, 0x9952, 0x6A70, 0x9953, 0x6A72, 0x9954, 0x6A73, 0x9955, 0x6A74, 0x9956, 0x6A75, 0x9957, 0x6A76, 0x9958, 0x6A77, 0x9959, 0x6A78, 0x995A, 0x6A7A, 0x995B, 0x6A7B, 0x995C, 0x6A7D, 0x995D, 0x6A7E, 0x995E, 0x6A7F, 0x995F, 0x6A81, 0x9960, 0x6A82, 0x9961, 0x6A83, 0x9962, 0x6A85, 0x9963, 0x6A86, 0x9964, 0x6A87, 0x9965, 0x6A88, 0x9966, 0x6A89, 0x9967, 0x6A8A, 0x9968, 0x6A8B, 0x9969, 0x6A8C, 0x996A, 0x6A8D, 0x996B, 0x6A8F, 0x996C, 0x6A92, 0x996D, 0x6A93, 0x996E, 0x6A94, 0x996F, 0x6A95, 0x9970, 0x6A96, 0x9971, 0x6A98, 0x9972, 0x6A99, 0x9973, 0x6A9A, 0x9974, 0x6A9B, 0x9975, 0x6A9C, 0x9976, 0x6A9D, 0x9977, 0x6A9E, 0x9978, 0x6A9F, 0x9979, 0x6AA1, 0x997A, 0x6AA2, 0x997B, 0x6AA3, 0x997C, 0x6AA4, 0x997D, 0x6AA5, 0x997E, 0x6AA6, 0x9980, 0x6AA7, 0x9981, 0x6AA8, 0x9982, 0x6AAA, 0x9983, 0x6AAD, 0x9984, 0x6AAE, 0x9985, 0x6AAF, 0x9986, 0x6AB0, 0x9987, 0x6AB1, 0x9988, 0x6AB2, 0x9989, 0x6AB3, 0x998A, 0x6AB4, 0x998B, 0x6AB5, 0x998C, 0x6AB6, 0x998D, 0x6AB7, 0x998E, 0x6AB8, 0x998F, 0x6AB9, 0x9990, 0x6ABA, 0x9991, 0x6ABB, 0x9992, 0x6ABC, 0x9993, 0x6ABD, 0x9994, 0x6ABE, 0x9995, 0x6ABF, 0x9996, 0x6AC0, 0x9997, 0x6AC1, 0x9998, 0x6AC2, 0x9999, 0x6AC3, 0x999A, 0x6AC4, 0x999B, 0x6AC5, 0x999C, 0x6AC6, 0x999D, 0x6AC7, 0x999E, 0x6AC8, 0x999F, 0x6AC9, 0x99A0, 0x6ACA, 0x99A1, 0x6ACB, 0x99A2, 0x6ACC, 0x99A3, 0x6ACD, 0x99A4, 0x6ACE, 0x99A5, 0x6ACF, 0x99A6, 0x6AD0, 0x99A7, 0x6AD1, 0x99A8, 0x6AD2, 0x99A9, 0x6AD3, 0x99AA, 0x6AD4, 0x99AB, 0x6AD5, 0x99AC, 0x6AD6, 0x99AD, 0x6AD7, 0x99AE, 0x6AD8, 0x99AF, 0x6AD9, 0x99B0, 0x6ADA, 0x99B1, 0x6ADB, 0x99B2, 0x6ADC, 0x99B3, 0x6ADD, 0x99B4, 0x6ADE, 0x99B5, 0x6ADF, 0x99B6, 0x6AE0, 0x99B7, 0x6AE1, 0x99B8, 0x6AE2, 0x99B9, 0x6AE3, 0x99BA, 0x6AE4, 0x99BB, 0x6AE5, 0x99BC, 0x6AE6, 0x99BD, 0x6AE7, 0x99BE, 0x6AE8, 0x99BF, 0x6AE9, 0x99C0, 0x6AEA, 0x99C1, 0x6AEB, 0x99C2, 0x6AEC, 0x99C3, 0x6AED, 0x99C4, 0x6AEE, 0x99C5, 0x6AEF, 0x99C6, 0x6AF0, 0x99C7, 0x6AF1, 0x99C8, 0x6AF2, 0x99C9, 0x6AF3, 0x99CA, 0x6AF4, 0x99CB, 0x6AF5, 0x99CC, 0x6AF6, 0x99CD, 0x6AF7, 0x99CE, 0x6AF8, 0x99CF, 0x6AF9, 0x99D0, 0x6AFA, 0x99D1, 0x6AFB, 0x99D2, 0x6AFC, 0x99D3, 0x6AFD, 0x99D4, 0x6AFE, 0x99D5, 0x6AFF, 0x99D6, 0x6B00, 0x99D7, 0x6B01, 0x99D8, 0x6B02, 0x99D9, 0x6B03, 0x99DA, 0x6B04, 0x99DB, 0x6B05, 0x99DC, 0x6B06, 0x99DD, 0x6B07, 0x99DE, 0x6B08, 0x99DF, 0x6B09, 0x99E0, 0x6B0A, 0x99E1, 0x6B0B, 0x99E2, 0x6B0C, 0x99E3, 0x6B0D, 0x99E4, 0x6B0E, 0x99E5, 0x6B0F, 0x99E6, 0x6B10, 0x99E7, 0x6B11, 0x99E8, 0x6B12, 0x99E9, 0x6B13, 0x99EA, 0x6B14, 0x99EB, 0x6B15, 0x99EC, 0x6B16, 0x99ED, 0x6B17, 0x99EE, 0x6B18, 0x99EF, 0x6B19, 0x99F0, 0x6B1A, 0x99F1, 0x6B1B, 0x99F2, 0x6B1C, 0x99F3, 0x6B1D, 0x99F4, 0x6B1E, 0x99F5, 0x6B1F, 0x99F6, 0x6B25, 0x99F7, 0x6B26, 0x99F8, 0x6B28, 0x99F9, 0x6B29, 0x99FA, 0x6B2A, 0x99FB, 0x6B2B, 0x99FC, 0x6B2C, 0x99FD, 0x6B2D, 0x99FE, 0x6B2E, 0x9A40, 0x6B2F, 0x9A41, 0x6B30, 0x9A42, 0x6B31, 0x9A43, 0x6B33, 0x9A44, 0x6B34, 0x9A45, 0x6B35, 0x9A46, 0x6B36, 0x9A47, 0x6B38, 0x9A48, 0x6B3B, 0x9A49, 0x6B3C, 0x9A4A, 0x6B3D, 0x9A4B, 0x6B3F, 0x9A4C, 0x6B40, 0x9A4D, 0x6B41, 0x9A4E, 0x6B42, 0x9A4F, 0x6B44, 0x9A50, 0x6B45, 0x9A51, 0x6B48, 0x9A52, 0x6B4A, 0x9A53, 0x6B4B, 0x9A54, 0x6B4D, 0x9A55, 0x6B4E, 0x9A56, 0x6B4F, 0x9A57, 0x6B50, 0x9A58, 0x6B51, 0x9A59, 0x6B52, 0x9A5A, 0x6B53, 0x9A5B, 0x6B54, 0x9A5C, 0x6B55, 0x9A5D, 0x6B56, 0x9A5E, 0x6B57, 0x9A5F, 0x6B58, 0x9A60, 0x6B5A, 0x9A61, 0x6B5B, 0x9A62, 0x6B5C, 0x9A63, 0x6B5D, 0x9A64, 0x6B5E, 0x9A65, 0x6B5F, 0x9A66, 0x6B60, 0x9A67, 0x6B61, 0x9A68, 0x6B68, 0x9A69, 0x6B69, 0x9A6A, 0x6B6B, 0x9A6B, 0x6B6C, 0x9A6C, 0x6B6D, 0x9A6D, 0x6B6E, 0x9A6E, 0x6B6F, 0x9A6F, 0x6B70, 0x9A70, 0x6B71, 0x9A71, 0x6B72, 0x9A72, 0x6B73, 0x9A73, 0x6B74, 0x9A74, 0x6B75, 0x9A75, 0x6B76, 0x9A76, 0x6B77, 0x9A77, 0x6B78, 0x9A78, 0x6B7A, 0x9A79, 0x6B7D, 0x9A7A, 0x6B7E, 0x9A7B, 0x6B7F, 0x9A7C, 0x6B80, 0x9A7D, 0x6B85, 0x9A7E, 0x6B88, 0x9A80, 0x6B8C, 0x9A81, 0x6B8E, 0x9A82, 0x6B8F, 0x9A83, 0x6B90, 0x9A84, 0x6B91, 0x9A85, 0x6B94, 0x9A86, 0x6B95, 0x9A87, 0x6B97, 0x9A88, 0x6B98, 0x9A89, 0x6B99, 0x9A8A, 0x6B9C, 0x9A8B, 0x6B9D, 0x9A8C, 0x6B9E, 0x9A8D, 0x6B9F, 0x9A8E, 0x6BA0, 0x9A8F, 0x6BA2, 0x9A90, 0x6BA3, 0x9A91, 0x6BA4, 0x9A92, 0x6BA5, 0x9A93, 0x6BA6, 0x9A94, 0x6BA7, 0x9A95, 0x6BA8, 0x9A96, 0x6BA9, 0x9A97, 0x6BAB, 0x9A98, 0x6BAC, 0x9A99, 0x6BAD, 0x9A9A, 0x6BAE, 0x9A9B, 0x6BAF, 0x9A9C, 0x6BB0, 0x9A9D, 0x6BB1, 0x9A9E, 0x6BB2, 0x9A9F, 0x6BB6, 0x9AA0, 0x6BB8, 0x9AA1, 0x6BB9, 0x9AA2, 0x6BBA, 0x9AA3, 0x6BBB, 0x9AA4, 0x6BBC, 0x9AA5, 0x6BBD, 0x9AA6, 0x6BBE, 0x9AA7, 0x6BC0, 0x9AA8, 0x6BC3, 0x9AA9, 0x6BC4, 0x9AAA, 0x6BC6, 0x9AAB, 0x6BC7, 0x9AAC, 0x6BC8, 0x9AAD, 0x6BC9, 0x9AAE, 0x6BCA, 0x9AAF, 0x6BCC, 0x9AB0, 0x6BCE, 0x9AB1, 0x6BD0, 0x9AB2, 0x6BD1, 0x9AB3, 0x6BD8, 0x9AB4, 0x6BDA, 0x9AB5, 0x6BDC, 0x9AB6, 0x6BDD, 0x9AB7, 0x6BDE, 0x9AB8, 0x6BDF, 0x9AB9, 0x6BE0, 0x9ABA, 0x6BE2, 0x9ABB, 0x6BE3, 0x9ABC, 0x6BE4, 0x9ABD, 0x6BE5, 0x9ABE, 0x6BE6, 0x9ABF, 0x6BE7, 0x9AC0, 0x6BE8, 0x9AC1, 0x6BE9, 0x9AC2, 0x6BEC, 0x9AC3, 0x6BED, 0x9AC4, 0x6BEE, 0x9AC5, 0x6BF0, 0x9AC6, 0x6BF1, 0x9AC7, 0x6BF2, 0x9AC8, 0x6BF4, 0x9AC9, 0x6BF6, 0x9ACA, 0x6BF7, 0x9ACB, 0x6BF8, 0x9ACC, 0x6BFA, 0x9ACD, 0x6BFB, 0x9ACE, 0x6BFC, 0x9ACF, 0x6BFE, 0x9AD0, 0x6BFF, 0x9AD1, 0x6C00, 0x9AD2, 0x6C01, 0x9AD3, 0x6C02, 0x9AD4, 0x6C03, 0x9AD5, 0x6C04, 0x9AD6, 0x6C08, 0x9AD7, 0x6C09, 0x9AD8, 0x6C0A, 0x9AD9, 0x6C0B, 0x9ADA, 0x6C0C, 0x9ADB, 0x6C0E, 0x9ADC, 0x6C12, 0x9ADD, 0x6C17, 0x9ADE, 0x6C1C, 0x9ADF, 0x6C1D, 0x9AE0, 0x6C1E, 0x9AE1, 0x6C20, 0x9AE2, 0x6C23, 0x9AE3, 0x6C25, 0x9AE4, 0x6C2B, 0x9AE5, 0x6C2C, 0x9AE6, 0x6C2D, 0x9AE7, 0x6C31, 0x9AE8, 0x6C33, 0x9AE9, 0x6C36, 0x9AEA, 0x6C37, 0x9AEB, 0x6C39, 0x9AEC, 0x6C3A, 0x9AED, 0x6C3B, 0x9AEE, 0x6C3C, 0x9AEF, 0x6C3E, 0x9AF0, 0x6C3F, 0x9AF1, 0x6C43, 0x9AF2, 0x6C44, 0x9AF3, 0x6C45, 0x9AF4, 0x6C48, 0x9AF5, 0x6C4B, 0x9AF6, 0x6C4C, 0x9AF7, 0x6C4D, 0x9AF8, 0x6C4E, 0x9AF9, 0x6C4F, 0x9AFA, 0x6C51, 0x9AFB, 0x6C52, 0x9AFC, 0x6C53, 0x9AFD, 0x6C56, 0x9AFE, 0x6C58, 0x9B40, 0x6C59, 0x9B41, 0x6C5A, 0x9B42, 0x6C62, 0x9B43, 0x6C63, 0x9B44, 0x6C65, 0x9B45, 0x6C66, 0x9B46, 0x6C67, 0x9B47, 0x6C6B, 0x9B48, 0x6C6C, 0x9B49, 0x6C6D, 0x9B4A, 0x6C6E, 0x9B4B, 0x6C6F, 0x9B4C, 0x6C71, 0x9B4D, 0x6C73, 0x9B4E, 0x6C75, 0x9B4F, 0x6C77, 0x9B50, 0x6C78, 0x9B51, 0x6C7A, 0x9B52, 0x6C7B, 0x9B53, 0x6C7C, 0x9B54, 0x6C7F, 0x9B55, 0x6C80, 0x9B56, 0x6C84, 0x9B57, 0x6C87, 0x9B58, 0x6C8A, 0x9B59, 0x6C8B, 0x9B5A, 0x6C8D, 0x9B5B, 0x6C8E, 0x9B5C, 0x6C91, 0x9B5D, 0x6C92, 0x9B5E, 0x6C95, 0x9B5F, 0x6C96, 0x9B60, 0x6C97, 0x9B61, 0x6C98, 0x9B62, 0x6C9A, 0x9B63, 0x6C9C, 0x9B64, 0x6C9D, 0x9B65, 0x6C9E, 0x9B66, 0x6CA0, 0x9B67, 0x6CA2, 0x9B68, 0x6CA8, 0x9B69, 0x6CAC, 0x9B6A, 0x6CAF, 0x9B6B, 0x6CB0, 0x9B6C, 0x6CB4, 0x9B6D, 0x6CB5, 0x9B6E, 0x6CB6, 0x9B6F, 0x6CB7, 0x9B70, 0x6CBA, 0x9B71, 0x6CC0, 0x9B72, 0x6CC1, 0x9B73, 0x6CC2, 0x9B74, 0x6CC3, 0x9B75, 0x6CC6, 0x9B76, 0x6CC7, 0x9B77, 0x6CC8, 0x9B78, 0x6CCB, 0x9B79, 0x6CCD, 0x9B7A, 0x6CCE, 0x9B7B, 0x6CCF, 0x9B7C, 0x6CD1, 0x9B7D, 0x6CD2, 0x9B7E, 0x6CD8, 0x9B80, 0x6CD9, 0x9B81, 0x6CDA, 0x9B82, 0x6CDC, 0x9B83, 0x6CDD, 0x9B84, 0x6CDF, 0x9B85, 0x6CE4, 0x9B86, 0x6CE6, 0x9B87, 0x6CE7, 0x9B88, 0x6CE9, 0x9B89, 0x6CEC, 0x9B8A, 0x6CED, 0x9B8B, 0x6CF2, 0x9B8C, 0x6CF4, 0x9B8D, 0x6CF9, 0x9B8E, 0x6CFF, 0x9B8F, 0x6D00, 0x9B90, 0x6D02, 0x9B91, 0x6D03, 0x9B92, 0x6D05, 0x9B93, 0x6D06, 0x9B94, 0x6D08, 0x9B95, 0x6D09, 0x9B96, 0x6D0A, 0x9B97, 0x6D0D, 0x9B98, 0x6D0F, 0x9B99, 0x6D10, 0x9B9A, 0x6D11, 0x9B9B, 0x6D13, 0x9B9C, 0x6D14, 0x9B9D, 0x6D15, 0x9B9E, 0x6D16, 0x9B9F, 0x6D18, 0x9BA0, 0x6D1C, 0x9BA1, 0x6D1D, 0x9BA2, 0x6D1F, 0x9BA3, 0x6D20, 0x9BA4, 0x6D21, 0x9BA5, 0x6D22, 0x9BA6, 0x6D23, 0x9BA7, 0x6D24, 0x9BA8, 0x6D26, 0x9BA9, 0x6D28, 0x9BAA, 0x6D29, 0x9BAB, 0x6D2C, 0x9BAC, 0x6D2D, 0x9BAD, 0x6D2F, 0x9BAE, 0x6D30, 0x9BAF, 0x6D34, 0x9BB0, 0x6D36, 0x9BB1, 0x6D37, 0x9BB2, 0x6D38, 0x9BB3, 0x6D3A, 0x9BB4, 0x6D3F, 0x9BB5, 0x6D40, 0x9BB6, 0x6D42, 0x9BB7, 0x6D44, 0x9BB8, 0x6D49, 0x9BB9, 0x6D4C, 0x9BBA, 0x6D50, 0x9BBB, 0x6D55, 0x9BBC, 0x6D56, 0x9BBD, 0x6D57, 0x9BBE, 0x6D58, 0x9BBF, 0x6D5B, 0x9BC0, 0x6D5D, 0x9BC1, 0x6D5F, 0x9BC2, 0x6D61, 0x9BC3, 0x6D62, 0x9BC4, 0x6D64, 0x9BC5, 0x6D65, 0x9BC6, 0x6D67, 0x9BC7, 0x6D68, 0x9BC8, 0x6D6B, 0x9BC9, 0x6D6C, 0x9BCA, 0x6D6D, 0x9BCB, 0x6D70, 0x9BCC, 0x6D71, 0x9BCD, 0x6D72, 0x9BCE, 0x6D73, 0x9BCF, 0x6D75, 0x9BD0, 0x6D76, 0x9BD1, 0x6D79, 0x9BD2, 0x6D7A, 0x9BD3, 0x6D7B, 0x9BD4, 0x6D7D, 0x9BD5, 0x6D7E, 0x9BD6, 0x6D7F, 0x9BD7, 0x6D80, 0x9BD8, 0x6D81, 0x9BD9, 0x6D83, 0x9BDA, 0x6D84, 0x9BDB, 0x6D86, 0x9BDC, 0x6D87, 0x9BDD, 0x6D8A, 0x9BDE, 0x6D8B, 0x9BDF, 0x6D8D, 0x9BE0, 0x6D8F, 0x9BE1, 0x6D90, 0x9BE2, 0x6D92, 0x9BE3, 0x6D96, 0x9BE4, 0x6D97, 0x9BE5, 0x6D98, 0x9BE6, 0x6D99, 0x9BE7, 0x6D9A, 0x9BE8, 0x6D9C, 0x9BE9, 0x6DA2, 0x9BEA, 0x6DA5, 0x9BEB, 0x6DAC, 0x9BEC, 0x6DAD, 0x9BED, 0x6DB0, 0x9BEE, 0x6DB1, 0x9BEF, 0x6DB3, 0x9BF0, 0x6DB4, 0x9BF1, 0x6DB6, 0x9BF2, 0x6DB7, 0x9BF3, 0x6DB9, 0x9BF4, 0x6DBA, 0x9BF5, 0x6DBB, 0x9BF6, 0x6DBC, 0x9BF7, 0x6DBD, 0x9BF8, 0x6DBE, 0x9BF9, 0x6DC1, 0x9BFA, 0x6DC2, 0x9BFB, 0x6DC3, 0x9BFC, 0x6DC8, 0x9BFD, 0x6DC9, 0x9BFE, 0x6DCA, 0x9C40, 0x6DCD, 0x9C41, 0x6DCE, 0x9C42, 0x6DCF, 0x9C43, 0x6DD0, 0x9C44, 0x6DD2, 0x9C45, 0x6DD3, 0x9C46, 0x6DD4, 0x9C47, 0x6DD5, 0x9C48, 0x6DD7, 0x9C49, 0x6DDA, 0x9C4A, 0x6DDB, 0x9C4B, 0x6DDC, 0x9C4C, 0x6DDF, 0x9C4D, 0x6DE2, 0x9C4E, 0x6DE3, 0x9C4F, 0x6DE5, 0x9C50, 0x6DE7, 0x9C51, 0x6DE8, 0x9C52, 0x6DE9, 0x9C53, 0x6DEA, 0x9C54, 0x6DED, 0x9C55, 0x6DEF, 0x9C56, 0x6DF0, 0x9C57, 0x6DF2, 0x9C58, 0x6DF4, 0x9C59, 0x6DF5, 0x9C5A, 0x6DF6, 0x9C5B, 0x6DF8, 0x9C5C, 0x6DFA, 0x9C5D, 0x6DFD, 0x9C5E, 0x6DFE, 0x9C5F, 0x6DFF, 0x9C60, 0x6E00, 0x9C61, 0x6E01, 0x9C62, 0x6E02, 0x9C63, 0x6E03, 0x9C64, 0x6E04, 0x9C65, 0x6E06, 0x9C66, 0x6E07, 0x9C67, 0x6E08, 0x9C68, 0x6E09, 0x9C69, 0x6E0B, 0x9C6A, 0x6E0F, 0x9C6B, 0x6E12, 0x9C6C, 0x6E13, 0x9C6D, 0x6E15, 0x9C6E, 0x6E18, 0x9C6F, 0x6E19, 0x9C70, 0x6E1B, 0x9C71, 0x6E1C, 0x9C72, 0x6E1E, 0x9C73, 0x6E1F, 0x9C74, 0x6E22, 0x9C75, 0x6E26, 0x9C76, 0x6E27, 0x9C77, 0x6E28, 0x9C78, 0x6E2A, 0x9C79, 0x6E2C, 0x9C7A, 0x6E2E, 0x9C7B, 0x6E30, 0x9C7C, 0x6E31, 0x9C7D, 0x6E33, 0x9C7E, 0x6E35, 0x9C80, 0x6E36, 0x9C81, 0x6E37, 0x9C82, 0x6E39, 0x9C83, 0x6E3B, 0x9C84, 0x6E3C, 0x9C85, 0x6E3D, 0x9C86, 0x6E3E, 0x9C87, 0x6E3F, 0x9C88, 0x6E40, 0x9C89, 0x6E41, 0x9C8A, 0x6E42, 0x9C8B, 0x6E45, 0x9C8C, 0x6E46, 0x9C8D, 0x6E47, 0x9C8E, 0x6E48, 0x9C8F, 0x6E49, 0x9C90, 0x6E4A, 0x9C91, 0x6E4B, 0x9C92, 0x6E4C, 0x9C93, 0x6E4F, 0x9C94, 0x6E50, 0x9C95, 0x6E51, 0x9C96, 0x6E52, 0x9C97, 0x6E55, 0x9C98, 0x6E57, 0x9C99, 0x6E59, 0x9C9A, 0x6E5A, 0x9C9B, 0x6E5C, 0x9C9C, 0x6E5D, 0x9C9D, 0x6E5E, 0x9C9E, 0x6E60, 0x9C9F, 0x6E61, 0x9CA0, 0x6E62, 0x9CA1, 0x6E63, 0x9CA2, 0x6E64, 0x9CA3, 0x6E65, 0x9CA4, 0x6E66, 0x9CA5, 0x6E67, 0x9CA6, 0x6E68, 0x9CA7, 0x6E69, 0x9CA8, 0x6E6A, 0x9CA9, 0x6E6C, 0x9CAA, 0x6E6D, 0x9CAB, 0x6E6F, 0x9CAC, 0x6E70, 0x9CAD, 0x6E71, 0x9CAE, 0x6E72, 0x9CAF, 0x6E73, 0x9CB0, 0x6E74, 0x9CB1, 0x6E75, 0x9CB2, 0x6E76, 0x9CB3, 0x6E77, 0x9CB4, 0x6E78, 0x9CB5, 0x6E79, 0x9CB6, 0x6E7A, 0x9CB7, 0x6E7B, 0x9CB8, 0x6E7C, 0x9CB9, 0x6E7D, 0x9CBA, 0x6E80, 0x9CBB, 0x6E81, 0x9CBC, 0x6E82, 0x9CBD, 0x6E84, 0x9CBE, 0x6E87, 0x9CBF, 0x6E88, 0x9CC0, 0x6E8A, 0x9CC1, 0x6E8B, 0x9CC2, 0x6E8C, 0x9CC3, 0x6E8D, 0x9CC4, 0x6E8E, 0x9CC5, 0x6E91, 0x9CC6, 0x6E92, 0x9CC7, 0x6E93, 0x9CC8, 0x6E94, 0x9CC9, 0x6E95, 0x9CCA, 0x6E96, 0x9CCB, 0x6E97, 0x9CCC, 0x6E99, 0x9CCD, 0x6E9A, 0x9CCE, 0x6E9B, 0x9CCF, 0x6E9D, 0x9CD0, 0x6E9E, 0x9CD1, 0x6EA0, 0x9CD2, 0x6EA1, 0x9CD3, 0x6EA3, 0x9CD4, 0x6EA4, 0x9CD5, 0x6EA6, 0x9CD6, 0x6EA8, 0x9CD7, 0x6EA9, 0x9CD8, 0x6EAB, 0x9CD9, 0x6EAC, 0x9CDA, 0x6EAD, 0x9CDB, 0x6EAE, 0x9CDC, 0x6EB0, 0x9CDD, 0x6EB3, 0x9CDE, 0x6EB5, 0x9CDF, 0x6EB8, 0x9CE0, 0x6EB9, 0x9CE1, 0x6EBC, 0x9CE2, 0x6EBE, 0x9CE3, 0x6EBF, 0x9CE4, 0x6EC0, 0x9CE5, 0x6EC3, 0x9CE6, 0x6EC4, 0x9CE7, 0x6EC5, 0x9CE8, 0x6EC6, 0x9CE9, 0x6EC8, 0x9CEA, 0x6EC9, 0x9CEB, 0x6ECA, 0x9CEC, 0x6ECC, 0x9CED, 0x6ECD, 0x9CEE, 0x6ECE, 0x9CEF, 0x6ED0, 0x9CF0, 0x6ED2, 0x9CF1, 0x6ED6, 0x9CF2, 0x6ED8, 0x9CF3, 0x6ED9, 0x9CF4, 0x6EDB, 0x9CF5, 0x6EDC, 0x9CF6, 0x6EDD, 0x9CF7, 0x6EE3, 0x9CF8, 0x6EE7, 0x9CF9, 0x6EEA, 0x9CFA, 0x6EEB, 0x9CFB, 0x6EEC, 0x9CFC, 0x6EED, 0x9CFD, 0x6EEE, 0x9CFE, 0x6EEF, 0x9D40, 0x6EF0, 0x9D41, 0x6EF1, 0x9D42, 0x6EF2, 0x9D43, 0x6EF3, 0x9D44, 0x6EF5, 0x9D45, 0x6EF6, 0x9D46, 0x6EF7, 0x9D47, 0x6EF8, 0x9D48, 0x6EFA, 0x9D49, 0x6EFB, 0x9D4A, 0x6EFC, 0x9D4B, 0x6EFD, 0x9D4C, 0x6EFE, 0x9D4D, 0x6EFF, 0x9D4E, 0x6F00, 0x9D4F, 0x6F01, 0x9D50, 0x6F03, 0x9D51, 0x6F04, 0x9D52, 0x6F05, 0x9D53, 0x6F07, 0x9D54, 0x6F08, 0x9D55, 0x6F0A, 0x9D56, 0x6F0B, 0x9D57, 0x6F0C, 0x9D58, 0x6F0D, 0x9D59, 0x6F0E, 0x9D5A, 0x6F10, 0x9D5B, 0x6F11, 0x9D5C, 0x6F12, 0x9D5D, 0x6F16, 0x9D5E, 0x6F17, 0x9D5F, 0x6F18, 0x9D60, 0x6F19, 0x9D61, 0x6F1A, 0x9D62, 0x6F1B, 0x9D63, 0x6F1C, 0x9D64, 0x6F1D, 0x9D65, 0x6F1E, 0x9D66, 0x6F1F, 0x9D67, 0x6F21, 0x9D68, 0x6F22, 0x9D69, 0x6F23, 0x9D6A, 0x6F25, 0x9D6B, 0x6F26, 0x9D6C, 0x6F27, 0x9D6D, 0x6F28, 0x9D6E, 0x6F2C, 0x9D6F, 0x6F2E, 0x9D70, 0x6F30, 0x9D71, 0x6F32, 0x9D72, 0x6F34, 0x9D73, 0x6F35, 0x9D74, 0x6F37, 0x9D75, 0x6F38, 0x9D76, 0x6F39, 0x9D77, 0x6F3A, 0x9D78, 0x6F3B, 0x9D79, 0x6F3C, 0x9D7A, 0x6F3D, 0x9D7B, 0x6F3F, 0x9D7C, 0x6F40, 0x9D7D, 0x6F41, 0x9D7E, 0x6F42, 0x9D80, 0x6F43, 0x9D81, 0x6F44, 0x9D82, 0x6F45, 0x9D83, 0x6F48, 0x9D84, 0x6F49, 0x9D85, 0x6F4A, 0x9D86, 0x6F4C, 0x9D87, 0x6F4E, 0x9D88, 0x6F4F, 0x9D89, 0x6F50, 0x9D8A, 0x6F51, 0x9D8B, 0x6F52, 0x9D8C, 0x6F53, 0x9D8D, 0x6F54, 0x9D8E, 0x6F55, 0x9D8F, 0x6F56, 0x9D90, 0x6F57, 0x9D91, 0x6F59, 0x9D92, 0x6F5A, 0x9D93, 0x6F5B, 0x9D94, 0x6F5D, 0x9D95, 0x6F5F, 0x9D96, 0x6F60, 0x9D97, 0x6F61, 0x9D98, 0x6F63, 0x9D99, 0x6F64, 0x9D9A, 0x6F65, 0x9D9B, 0x6F67, 0x9D9C, 0x6F68, 0x9D9D, 0x6F69, 0x9D9E, 0x6F6A, 0x9D9F, 0x6F6B, 0x9DA0, 0x6F6C, 0x9DA1, 0x6F6F, 0x9DA2, 0x6F70, 0x9DA3, 0x6F71, 0x9DA4, 0x6F73, 0x9DA5, 0x6F75, 0x9DA6, 0x6F76, 0x9DA7, 0x6F77, 0x9DA8, 0x6F79, 0x9DA9, 0x6F7B, 0x9DAA, 0x6F7D, 0x9DAB, 0x6F7E, 0x9DAC, 0x6F7F, 0x9DAD, 0x6F80, 0x9DAE, 0x6F81, 0x9DAF, 0x6F82, 0x9DB0, 0x6F83, 0x9DB1, 0x6F85, 0x9DB2, 0x6F86, 0x9DB3, 0x6F87, 0x9DB4, 0x6F8A, 0x9DB5, 0x6F8B, 0x9DB6, 0x6F8F, 0x9DB7, 0x6F90, 0x9DB8, 0x6F91, 0x9DB9, 0x6F92, 0x9DBA, 0x6F93, 0x9DBB, 0x6F94, 0x9DBC, 0x6F95, 0x9DBD, 0x6F96, 0x9DBE, 0x6F97, 0x9DBF, 0x6F98, 0x9DC0, 0x6F99, 0x9DC1, 0x6F9A, 0x9DC2, 0x6F9B, 0x9DC3, 0x6F9D, 0x9DC4, 0x6F9E, 0x9DC5, 0x6F9F, 0x9DC6, 0x6FA0, 0x9DC7, 0x6FA2, 0x9DC8, 0x6FA3, 0x9DC9, 0x6FA4, 0x9DCA, 0x6FA5, 0x9DCB, 0x6FA6, 0x9DCC, 0x6FA8, 0x9DCD, 0x6FA9, 0x9DCE, 0x6FAA, 0x9DCF, 0x6FAB, 0x9DD0, 0x6FAC, 0x9DD1, 0x6FAD, 0x9DD2, 0x6FAE, 0x9DD3, 0x6FAF, 0x9DD4, 0x6FB0, 0x9DD5, 0x6FB1, 0x9DD6, 0x6FB2, 0x9DD7, 0x6FB4, 0x9DD8, 0x6FB5, 0x9DD9, 0x6FB7, 0x9DDA, 0x6FB8, 0x9DDB, 0x6FBA, 0x9DDC, 0x6FBB, 0x9DDD, 0x6FBC, 0x9DDE, 0x6FBD, 0x9DDF, 0x6FBE, 0x9DE0, 0x6FBF, 0x9DE1, 0x6FC1, 0x9DE2, 0x6FC3, 0x9DE3, 0x6FC4, 0x9DE4, 0x6FC5, 0x9DE5, 0x6FC6, 0x9DE6, 0x6FC7, 0x9DE7, 0x6FC8, 0x9DE8, 0x6FCA, 0x9DE9, 0x6FCB, 0x9DEA, 0x6FCC, 0x9DEB, 0x6FCD, 0x9DEC, 0x6FCE, 0x9DED, 0x6FCF, 0x9DEE, 0x6FD0, 0x9DEF, 0x6FD3, 0x9DF0, 0x6FD4, 0x9DF1, 0x6FD5, 0x9DF2, 0x6FD6, 0x9DF3, 0x6FD7, 0x9DF4, 0x6FD8, 0x9DF5, 0x6FD9, 0x9DF6, 0x6FDA, 0x9DF7, 0x6FDB, 0x9DF8, 0x6FDC, 0x9DF9, 0x6FDD, 0x9DFA, 0x6FDF, 0x9DFB, 0x6FE2, 0x9DFC, 0x6FE3, 0x9DFD, 0x6FE4, 0x9DFE, 0x6FE5, 0x9E40, 0x6FE6, 0x9E41, 0x6FE7, 0x9E42, 0x6FE8, 0x9E43, 0x6FE9, 0x9E44, 0x6FEA, 0x9E45, 0x6FEB, 0x9E46, 0x6FEC, 0x9E47, 0x6FED, 0x9E48, 0x6FF0, 0x9E49, 0x6FF1, 0x9E4A, 0x6FF2, 0x9E4B, 0x6FF3, 0x9E4C, 0x6FF4, 0x9E4D, 0x6FF5, 0x9E4E, 0x6FF6, 0x9E4F, 0x6FF7, 0x9E50, 0x6FF8, 0x9E51, 0x6FF9, 0x9E52, 0x6FFA, 0x9E53, 0x6FFB, 0x9E54, 0x6FFC, 0x9E55, 0x6FFD, 0x9E56, 0x6FFE, 0x9E57, 0x6FFF, 0x9E58, 0x7000, 0x9E59, 0x7001, 0x9E5A, 0x7002, 0x9E5B, 0x7003, 0x9E5C, 0x7004, 0x9E5D, 0x7005, 0x9E5E, 0x7006, 0x9E5F, 0x7007, 0x9E60, 0x7008, 0x9E61, 0x7009, 0x9E62, 0x700A, 0x9E63, 0x700B, 0x9E64, 0x700C, 0x9E65, 0x700D, 0x9E66, 0x700E, 0x9E67, 0x700F, 0x9E68, 0x7010, 0x9E69, 0x7012, 0x9E6A, 0x7013, 0x9E6B, 0x7014, 0x9E6C, 0x7015, 0x9E6D, 0x7016, 0x9E6E, 0x7017, 0x9E6F, 0x7018, 0x9E70, 0x7019, 0x9E71, 0x701C, 0x9E72, 0x701D, 0x9E73, 0x701E, 0x9E74, 0x701F, 0x9E75, 0x7020, 0x9E76, 0x7021, 0x9E77, 0x7022, 0x9E78, 0x7024, 0x9E79, 0x7025, 0x9E7A, 0x7026, 0x9E7B, 0x7027, 0x9E7C, 0x7028, 0x9E7D, 0x7029, 0x9E7E, 0x702A, 0x9E80, 0x702B, 0x9E81, 0x702C, 0x9E82, 0x702D, 0x9E83, 0x702E, 0x9E84, 0x702F, 0x9E85, 0x7030, 0x9E86, 0x7031, 0x9E87, 0x7032, 0x9E88, 0x7033, 0x9E89, 0x7034, 0x9E8A, 0x7036, 0x9E8B, 0x7037, 0x9E8C, 0x7038, 0x9E8D, 0x703A, 0x9E8E, 0x703B, 0x9E8F, 0x703C, 0x9E90, 0x703D, 0x9E91, 0x703E, 0x9E92, 0x703F, 0x9E93, 0x7040, 0x9E94, 0x7041, 0x9E95, 0x7042, 0x9E96, 0x7043, 0x9E97, 0x7044, 0x9E98, 0x7045, 0x9E99, 0x7046, 0x9E9A, 0x7047, 0x9E9B, 0x7048, 0x9E9C, 0x7049, 0x9E9D, 0x704A, 0x9E9E, 0x704B, 0x9E9F, 0x704D, 0x9EA0, 0x704E, 0x9EA1, 0x7050, 0x9EA2, 0x7051, 0x9EA3, 0x7052, 0x9EA4, 0x7053, 0x9EA5, 0x7054, 0x9EA6, 0x7055, 0x9EA7, 0x7056, 0x9EA8, 0x7057, 0x9EA9, 0x7058, 0x9EAA, 0x7059, 0x9EAB, 0x705A, 0x9EAC, 0x705B, 0x9EAD, 0x705C, 0x9EAE, 0x705D, 0x9EAF, 0x705F, 0x9EB0, 0x7060, 0x9EB1, 0x7061, 0x9EB2, 0x7062, 0x9EB3, 0x7063, 0x9EB4, 0x7064, 0x9EB5, 0x7065, 0x9EB6, 0x7066, 0x9EB7, 0x7067, 0x9EB8, 0x7068, 0x9EB9, 0x7069, 0x9EBA, 0x706A, 0x9EBB, 0x706E, 0x9EBC, 0x7071, 0x9EBD, 0x7072, 0x9EBE, 0x7073, 0x9EBF, 0x7074, 0x9EC0, 0x7077, 0x9EC1, 0x7079, 0x9EC2, 0x707A, 0x9EC3, 0x707B, 0x9EC4, 0x707D, 0x9EC5, 0x7081, 0x9EC6, 0x7082, 0x9EC7, 0x7083, 0x9EC8, 0x7084, 0x9EC9, 0x7086, 0x9ECA, 0x7087, 0x9ECB, 0x7088, 0x9ECC, 0x708B, 0x9ECD, 0x708C, 0x9ECE, 0x708D, 0x9ECF, 0x708F, 0x9ED0, 0x7090, 0x9ED1, 0x7091, 0x9ED2, 0x7093, 0x9ED3, 0x7097, 0x9ED4, 0x7098, 0x9ED5, 0x709A, 0x9ED6, 0x709B, 0x9ED7, 0x709E, 0x9ED8, 0x709F, 0x9ED9, 0x70A0, 0x9EDA, 0x70A1, 0x9EDB, 0x70A2, 0x9EDC, 0x70A3, 0x9EDD, 0x70A4, 0x9EDE, 0x70A5, 0x9EDF, 0x70A6, 0x9EE0, 0x70A7, 0x9EE1, 0x70A8, 0x9EE2, 0x70A9, 0x9EE3, 0x70AA, 0x9EE4, 0x70B0, 0x9EE5, 0x70B2, 0x9EE6, 0x70B4, 0x9EE7, 0x70B5, 0x9EE8, 0x70B6, 0x9EE9, 0x70BA, 0x9EEA, 0x70BE, 0x9EEB, 0x70BF, 0x9EEC, 0x70C4, 0x9EED, 0x70C5, 0x9EEE, 0x70C6, 0x9EEF, 0x70C7, 0x9EF0, 0x70C9, 0x9EF1, 0x70CB, 0x9EF2, 0x70CC, 0x9EF3, 0x70CD, 0x9EF4, 0x70CE, 0x9EF5, 0x70CF, 0x9EF6, 0x70D0, 0x9EF7, 0x70D1, 0x9EF8, 0x70D2, 0x9EF9, 0x70D3, 0x9EFA, 0x70D4, 0x9EFB, 0x70D5, 0x9EFC, 0x70D6, 0x9EFD, 0x70D7, 0x9EFE, 0x70DA, 0x9F40, 0x70DC, 0x9F41, 0x70DD, 0x9F42, 0x70DE, 0x9F43, 0x70E0, 0x9F44, 0x70E1, 0x9F45, 0x70E2, 0x9F46, 0x70E3, 0x9F47, 0x70E5, 0x9F48, 0x70EA, 0x9F49, 0x70EE, 0x9F4A, 0x70F0, 0x9F4B, 0x70F1, 0x9F4C, 0x70F2, 0x9F4D, 0x70F3, 0x9F4E, 0x70F4, 0x9F4F, 0x70F5, 0x9F50, 0x70F6, 0x9F51, 0x70F8, 0x9F52, 0x70FA, 0x9F53, 0x70FB, 0x9F54, 0x70FC, 0x9F55, 0x70FE, 0x9F56, 0x70FF, 0x9F57, 0x7100, 0x9F58, 0x7101, 0x9F59, 0x7102, 0x9F5A, 0x7103, 0x9F5B, 0x7104, 0x9F5C, 0x7105, 0x9F5D, 0x7106, 0x9F5E, 0x7107, 0x9F5F, 0x7108, 0x9F60, 0x710B, 0x9F61, 0x710C, 0x9F62, 0x710D, 0x9F63, 0x710E, 0x9F64, 0x710F, 0x9F65, 0x7111, 0x9F66, 0x7112, 0x9F67, 0x7114, 0x9F68, 0x7117, 0x9F69, 0x711B, 0x9F6A, 0x711C, 0x9F6B, 0x711D, 0x9F6C, 0x711E, 0x9F6D, 0x711F, 0x9F6E, 0x7120, 0x9F6F, 0x7121, 0x9F70, 0x7122, 0x9F71, 0x7123, 0x9F72, 0x7124, 0x9F73, 0x7125, 0x9F74, 0x7127, 0x9F75, 0x7128, 0x9F76, 0x7129, 0x9F77, 0x712A, 0x9F78, 0x712B, 0x9F79, 0x712C, 0x9F7A, 0x712D, 0x9F7B, 0x712E, 0x9F7C, 0x7132, 0x9F7D, 0x7133, 0x9F7E, 0x7134, 0x9F80, 0x7135, 0x9F81, 0x7137, 0x9F82, 0x7138, 0x9F83, 0x7139, 0x9F84, 0x713A, 0x9F85, 0x713B, 0x9F86, 0x713C, 0x9F87, 0x713D, 0x9F88, 0x713E, 0x9F89, 0x713F, 0x9F8A, 0x7140, 0x9F8B, 0x7141, 0x9F8C, 0x7142, 0x9F8D, 0x7143, 0x9F8E, 0x7144, 0x9F8F, 0x7146, 0x9F90, 0x7147, 0x9F91, 0x7148, 0x9F92, 0x7149, 0x9F93, 0x714B, 0x9F94, 0x714D, 0x9F95, 0x714F, 0x9F96, 0x7150, 0x9F97, 0x7151, 0x9F98, 0x7152, 0x9F99, 0x7153, 0x9F9A, 0x7154, 0x9F9B, 0x7155, 0x9F9C, 0x7156, 0x9F9D, 0x7157, 0x9F9E, 0x7158, 0x9F9F, 0x7159, 0x9FA0, 0x715A, 0x9FA1, 0x715B, 0x9FA2, 0x715D, 0x9FA3, 0x715F, 0x9FA4, 0x7160, 0x9FA5, 0x7161, 0x9FA6, 0x7162, 0x9FA7, 0x7163, 0x9FA8, 0x7165, 0x9FA9, 0x7169, 0x9FAA, 0x716A, 0x9FAB, 0x716B, 0x9FAC, 0x716C, 0x9FAD, 0x716D, 0x9FAE, 0x716F, 0x9FAF, 0x7170, 0x9FB0, 0x7171, 0x9FB1, 0x7174, 0x9FB2, 0x7175, 0x9FB3, 0x7176, 0x9FB4, 0x7177, 0x9FB5, 0x7179, 0x9FB6, 0x717B, 0x9FB7, 0x717C, 0x9FB8, 0x717E, 0x9FB9, 0x717F, 0x9FBA, 0x7180, 0x9FBB, 0x7181, 0x9FBC, 0x7182, 0x9FBD, 0x7183, 0x9FBE, 0x7185, 0x9FBF, 0x7186, 0x9FC0, 0x7187, 0x9FC1, 0x7188, 0x9FC2, 0x7189, 0x9FC3, 0x718B, 0x9FC4, 0x718C, 0x9FC5, 0x718D, 0x9FC6, 0x718E, 0x9FC7, 0x7190, 0x9FC8, 0x7191, 0x9FC9, 0x7192, 0x9FCA, 0x7193, 0x9FCB, 0x7195, 0x9FCC, 0x7196, 0x9FCD, 0x7197, 0x9FCE, 0x719A, 0x9FCF, 0x719B, 0x9FD0, 0x719C, 0x9FD1, 0x719D, 0x9FD2, 0x719E, 0x9FD3, 0x71A1, 0x9FD4, 0x71A2, 0x9FD5, 0x71A3, 0x9FD6, 0x71A4, 0x9FD7, 0x71A5, 0x9FD8, 0x71A6, 0x9FD9, 0x71A7, 0x9FDA, 0x71A9, 0x9FDB, 0x71AA, 0x9FDC, 0x71AB, 0x9FDD, 0x71AD, 0x9FDE, 0x71AE, 0x9FDF, 0x71AF, 0x9FE0, 0x71B0, 0x9FE1, 0x71B1, 0x9FE2, 0x71B2, 0x9FE3, 0x71B4, 0x9FE4, 0x71B6, 0x9FE5, 0x71B7, 0x9FE6, 0x71B8, 0x9FE7, 0x71BA, 0x9FE8, 0x71BB, 0x9FE9, 0x71BC, 0x9FEA, 0x71BD, 0x9FEB, 0x71BE, 0x9FEC, 0x71BF, 0x9FED, 0x71C0, 0x9FEE, 0x71C1, 0x9FEF, 0x71C2, 0x9FF0, 0x71C4, 0x9FF1, 0x71C5, 0x9FF2, 0x71C6, 0x9FF3, 0x71C7, 0x9FF4, 0x71C8, 0x9FF5, 0x71C9, 0x9FF6, 0x71CA, 0x9FF7, 0x71CB, 0x9FF8, 0x71CC, 0x9FF9, 0x71CD, 0x9FFA, 0x71CF, 0x9FFB, 0x71D0, 0x9FFC, 0x71D1, 0x9FFD, 0x71D2, 0x9FFE, 0x71D3, 0xA040, 0x71D6, 0xA041, 0x71D7, 0xA042, 0x71D8, 0xA043, 0x71D9, 0xA044, 0x71DA, 0xA045, 0x71DB, 0xA046, 0x71DC, 0xA047, 0x71DD, 0xA048, 0x71DE, 0xA049, 0x71DF, 0xA04A, 0x71E1, 0xA04B, 0x71E2, 0xA04C, 0x71E3, 0xA04D, 0x71E4, 0xA04E, 0x71E6, 0xA04F, 0x71E8, 0xA050, 0x71E9, 0xA051, 0x71EA, 0xA052, 0x71EB, 0xA053, 0x71EC, 0xA054, 0x71ED, 0xA055, 0x71EF, 0xA056, 0x71F0, 0xA057, 0x71F1, 0xA058, 0x71F2, 0xA059, 0x71F3, 0xA05A, 0x71F4, 0xA05B, 0x71F5, 0xA05C, 0x71F6, 0xA05D, 0x71F7, 0xA05E, 0x71F8, 0xA05F, 0x71FA, 0xA060, 0x71FB, 0xA061, 0x71FC, 0xA062, 0x71FD, 0xA063, 0x71FE, 0xA064, 0x71FF, 0xA065, 0x7200, 0xA066, 0x7201, 0xA067, 0x7202, 0xA068, 0x7203, 0xA069, 0x7204, 0xA06A, 0x7205, 0xA06B, 0x7207, 0xA06C, 0x7208, 0xA06D, 0x7209, 0xA06E, 0x720A, 0xA06F, 0x720B, 0xA070, 0x720C, 0xA071, 0x720D, 0xA072, 0x720E, 0xA073, 0x720F, 0xA074, 0x7210, 0xA075, 0x7211, 0xA076, 0x7212, 0xA077, 0x7213, 0xA078, 0x7214, 0xA079, 0x7215, 0xA07A, 0x7216, 0xA07B, 0x7217, 0xA07C, 0x7218, 0xA07D, 0x7219, 0xA07E, 0x721A, 0xA080, 0x721B, 0xA081, 0x721C, 0xA082, 0x721E, 0xA083, 0x721F, 0xA084, 0x7220, 0xA085, 0x7221, 0xA086, 0x7222, 0xA087, 0x7223, 0xA088, 0x7224, 0xA089, 0x7225, 0xA08A, 0x7226, 0xA08B, 0x7227, 0xA08C, 0x7229, 0xA08D, 0x722B, 0xA08E, 0x722D, 0xA08F, 0x722E, 0xA090, 0x722F, 0xA091, 0x7232, 0xA092, 0x7233, 0xA093, 0x7234, 0xA094, 0x723A, 0xA095, 0x723C, 0xA096, 0x723E, 0xA097, 0x7240, 0xA098, 0x7241, 0xA099, 0x7242, 0xA09A, 0x7243, 0xA09B, 0x7244, 0xA09C, 0x7245, 0xA09D, 0x7246, 0xA09E, 0x7249, 0xA09F, 0x724A, 0xA0A0, 0x724B, 0xA0A1, 0x724E, 0xA0A2, 0x724F, 0xA0A3, 0x7250, 0xA0A4, 0x7251, 0xA0A5, 0x7253, 0xA0A6, 0x7254, 0xA0A7, 0x7255, 0xA0A8, 0x7257, 0xA0A9, 0x7258, 0xA0AA, 0x725A, 0xA0AB, 0x725C, 0xA0AC, 0x725E, 0xA0AD, 0x7260, 0xA0AE, 0x7263, 0xA0AF, 0x7264, 0xA0B0, 0x7265, 0xA0B1, 0x7268, 0xA0B2, 0x726A, 0xA0B3, 0x726B, 0xA0B4, 0x726C, 0xA0B5, 0x726D, 0xA0B6, 0x7270, 0xA0B7, 0x7271, 0xA0B8, 0x7273, 0xA0B9, 0x7274, 0xA0BA, 0x7276, 0xA0BB, 0x7277, 0xA0BC, 0x7278, 0xA0BD, 0x727B, 0xA0BE, 0x727C, 0xA0BF, 0x727D, 0xA0C0, 0x7282, 0xA0C1, 0x7283, 0xA0C2, 0x7285, 0xA0C3, 0x7286, 0xA0C4, 0x7287, 0xA0C5, 0x7288, 0xA0C6, 0x7289, 0xA0C7, 0x728C, 0xA0C8, 0x728E, 0xA0C9, 0x7290, 0xA0CA, 0x7291, 0xA0CB, 0x7293, 0xA0CC, 0x7294, 0xA0CD, 0x7295, 0xA0CE, 0x7296, 0xA0CF, 0x7297, 0xA0D0, 0x7298, 0xA0D1, 0x7299, 0xA0D2, 0x729A, 0xA0D3, 0x729B, 0xA0D4, 0x729C, 0xA0D5, 0x729D, 0xA0D6, 0x729E, 0xA0D7, 0x72A0, 0xA0D8, 0x72A1, 0xA0D9, 0x72A2, 0xA0DA, 0x72A3, 0xA0DB, 0x72A4, 0xA0DC, 0x72A5, 0xA0DD, 0x72A6, 0xA0DE, 0x72A7, 0xA0DF, 0x72A8, 0xA0E0, 0x72A9, 0xA0E1, 0x72AA, 0xA0E2, 0x72AB, 0xA0E3, 0x72AE, 0xA0E4, 0x72B1, 0xA0E5, 0x72B2, 0xA0E6, 0x72B3, 0xA0E7, 0x72B5, 0xA0E8, 0x72BA, 0xA0E9, 0x72BB, 0xA0EA, 0x72BC, 0xA0EB, 0x72BD, 0xA0EC, 0x72BE, 0xA0ED, 0x72BF, 0xA0EE, 0x72C0, 0xA0EF, 0x72C5, 0xA0F0, 0x72C6, 0xA0F1, 0x72C7, 0xA0F2, 0x72C9, 0xA0F3, 0x72CA, 0xA0F4, 0x72CB, 0xA0F5, 0x72CC, 0xA0F6, 0x72CF, 0xA0F7, 0x72D1, 0xA0F8, 0x72D3, 0xA0F9, 0x72D4, 0xA0FA, 0x72D5, 0xA0FB, 0x72D6, 0xA0FC, 0x72D8, 0xA0FD, 0x72DA, 0xA0FE, 0x72DB, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, 0xA1A5, 0x02C9, 0xA1A6, 0x02C7, 0xA1A7, 0x00A8, 0xA1A8, 0x3003, 0xA1A9, 0x3005, 0xA1AA, 0x2014, 0xA1AB, 0xFF5E, 0xA1AC, 0x2016, 0xA1AD, 0x2026, 0xA1AE, 0x2018, 0xA1AF, 0x2019, 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3016, 0xA1BD, 0x3017, 0xA1BE, 0x3010, 0xA1BF, 0x3011, 0xA1C0, 0x00B1, 0xA1C1, 0x00D7, 0xA1C2, 0x00F7, 0xA1C3, 0x2236, 0xA1C4, 0x2227, 0xA1C5, 0x2228, 0xA1C6, 0x2211, 0xA1C7, 0x220F, 0xA1C8, 0x222A, 0xA1C9, 0x2229, 0xA1CA, 0x2208, 0xA1CB, 0x2237, 0xA1CC, 0x221A, 0xA1CD, 0x22A5, 0xA1CE, 0x2225, 0xA1CF, 0x2220, 0xA1D0, 0x2312, 0xA1D1, 0x2299, 0xA1D2, 0x222B, 0xA1D3, 0x222E, 0xA1D4, 0x2261, 0xA1D5, 0x224C, 0xA1D6, 0x2248, 0xA1D7, 0x223D, 0xA1D8, 0x221D, 0xA1D9, 0x2260, 0xA1DA, 0x226E, 0xA1DB, 0x226F, 0xA1DC, 0x2264, 0xA1DD, 0x2265, 0xA1DE, 0x221E, 0xA1DF, 0x2235, 0xA1E0, 0x2234, 0xA1E1, 0x2642, 0xA1E2, 0x2640, 0xA1E3, 0x00B0, 0xA1E4, 0x2032, 0xA1E5, 0x2033, 0xA1E6, 0x2103, 0xA1E7, 0xFF04, 0xA1E8, 0x00A4, 0xA1E9, 0xFFE0, 0xA1EA, 0xFFE1, 0xA1EB, 0x2030, 0xA1EC, 0x00A7, 0xA1ED, 0x2116, 0xA1EE, 0x2606, 0xA1EF, 0x2605, 0xA1F0, 0x25CB, 0xA1F1, 0x25CF, 0xA1F2, 0x25CE, 0xA1F3, 0x25C7, 0xA1F4, 0x25C6, 0xA1F5, 0x25A1, 0xA1F6, 0x25A0, 0xA1F7, 0x25B3, 0xA1F8, 0x25B2, 0xA1F9, 0x203B, 0xA1FA, 0x2192, 0xA1FB, 0x2190, 0xA1FC, 0x2191, 0xA1FD, 0x2193, 0xA1FE, 0x3013, 0xA2A1, 0x2170, 0xA2A2, 0x2171, 0xA2A3, 0x2172, 0xA2A4, 0x2173, 0xA2A5, 0x2174, 0xA2A6, 0x2175, 0xA2A7, 0x2176, 0xA2A8, 0x2177, 0xA2A9, 0x2178, 0xA2AA, 0x2179, 0xA2B1, 0x2488, 0xA2B2, 0x2489, 0xA2B3, 0x248A, 0xA2B4, 0x248B, 0xA2B5, 0x248C, 0xA2B6, 0x248D, 0xA2B7, 0x248E, 0xA2B8, 0x248F, 0xA2B9, 0x2490, 0xA2BA, 0x2491, 0xA2BB, 0x2492, 0xA2BC, 0x2493, 0xA2BD, 0x2494, 0xA2BE, 0x2495, 0xA2BF, 0x2496, 0xA2C0, 0x2497, 0xA2C1, 0x2498, 0xA2C2, 0x2499, 0xA2C3, 0x249A, 0xA2C4, 0x249B, 0xA2C5, 0x2474, 0xA2C6, 0x2475, 0xA2C7, 0x2476, 0xA2C8, 0x2477, 0xA2C9, 0x2478, 0xA2CA, 0x2479, 0xA2CB, 0x247A, 0xA2CC, 0x247B, 0xA2CD, 0x247C, 0xA2CE, 0x247D, 0xA2CF, 0x247E, 0xA2D0, 0x247F, 0xA2D1, 0x2480, 0xA2D2, 0x2481, 0xA2D3, 0x2482, 0xA2D4, 0x2483, 0xA2D5, 0x2484, 0xA2D6, 0x2485, 0xA2D7, 0x2486, 0xA2D8, 0x2487, 0xA2D9, 0x2460, 0xA2DA, 0x2461, 0xA2DB, 0x2462, 0xA2DC, 0x2463, 0xA2DD, 0x2464, 0xA2DE, 0x2465, 0xA2DF, 0x2466, 0xA2E0, 0x2467, 0xA2E1, 0x2468, 0xA2E2, 0x2469, 0xA2E5, 0x3220, 0xA2E6, 0x3221, 0xA2E7, 0x3222, 0xA2E8, 0x3223, 0xA2E9, 0x3224, 0xA2EA, 0x3225, 0xA2EB, 0x3226, 0xA2EC, 0x3227, 0xA2ED, 0x3228, 0xA2EE, 0x3229, 0xA2F1, 0x2160, 0xA2F2, 0x2161, 0xA2F3, 0x2162, 0xA2F4, 0x2163, 0xA2F5, 0x2164, 0xA2F6, 0x2165, 0xA2F7, 0x2166, 0xA2F8, 0x2167, 0xA2F9, 0x2168, 0xA2FA, 0x2169, 0xA2FB, 0x216A, 0xA2FC, 0x216B, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFFE5, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFF3C, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA4A1, 0x3041, 0xA4A2, 0x3042, 0xA4A3, 0x3043, 0xA4A4, 0x3044, 0xA4A5, 0x3045, 0xA4A6, 0x3046, 0xA4A7, 0x3047, 0xA4A8, 0x3048, 0xA4A9, 0x3049, 0xA4AA, 0x304A, 0xA4AB, 0x304B, 0xA4AC, 0x304C, 0xA4AD, 0x304D, 0xA4AE, 0x304E, 0xA4AF, 0x304F, 0xA4B0, 0x3050, 0xA4B1, 0x3051, 0xA4B2, 0x3052, 0xA4B3, 0x3053, 0xA4B4, 0x3054, 0xA4B5, 0x3055, 0xA4B6, 0x3056, 0xA4B7, 0x3057, 0xA4B8, 0x3058, 0xA4B9, 0x3059, 0xA4BA, 0x305A, 0xA4BB, 0x305B, 0xA4BC, 0x305C, 0xA4BD, 0x305D, 0xA4BE, 0x305E, 0xA4BF, 0x305F, 0xA4C0, 0x3060, 0xA4C1, 0x3061, 0xA4C2, 0x3062, 0xA4C3, 0x3063, 0xA4C4, 0x3064, 0xA4C5, 0x3065, 0xA4C6, 0x3066, 0xA4C7, 0x3067, 0xA4C8, 0x3068, 0xA4C9, 0x3069, 0xA4CA, 0x306A, 0xA4CB, 0x306B, 0xA4CC, 0x306C, 0xA4CD, 0x306D, 0xA4CE, 0x306E, 0xA4CF, 0x306F, 0xA4D0, 0x3070, 0xA4D1, 0x3071, 0xA4D2, 0x3072, 0xA4D3, 0x3073, 0xA4D4, 0x3074, 0xA4D5, 0x3075, 0xA4D6, 0x3076, 0xA4D7, 0x3077, 0xA4D8, 0x3078, 0xA4D9, 0x3079, 0xA4DA, 0x307A, 0xA4DB, 0x307B, 0xA4DC, 0x307C, 0xA4DD, 0x307D, 0xA4DE, 0x307E, 0xA4DF, 0x307F, 0xA4E0, 0x3080, 0xA4E1, 0x3081, 0xA4E2, 0x3082, 0xA4E3, 0x3083, 0xA4E4, 0x3084, 0xA4E5, 0x3085, 0xA4E6, 0x3086, 0xA4E7, 0x3087, 0xA4E8, 0x3088, 0xA4E9, 0x3089, 0xA4EA, 0x308A, 0xA4EB, 0x308B, 0xA4EC, 0x308C, 0xA4ED, 0x308D, 0xA4EE, 0x308E, 0xA4EF, 0x308F, 0xA4F0, 0x3090, 0xA4F1, 0x3091, 0xA4F2, 0x3092, 0xA4F3, 0x3093, 0xA5A1, 0x30A1, 0xA5A2, 0x30A2, 0xA5A3, 0x30A3, 0xA5A4, 0x30A4, 0xA5A5, 0x30A5, 0xA5A6, 0x30A6, 0xA5A7, 0x30A7, 0xA5A8, 0x30A8, 0xA5A9, 0x30A9, 0xA5AA, 0x30AA, 0xA5AB, 0x30AB, 0xA5AC, 0x30AC, 0xA5AD, 0x30AD, 0xA5AE, 0x30AE, 0xA5AF, 0x30AF, 0xA5B0, 0x30B0, 0xA5B1, 0x30B1, 0xA5B2, 0x30B2, 0xA5B3, 0x30B3, 0xA5B4, 0x30B4, 0xA5B5, 0x30B5, 0xA5B6, 0x30B6, 0xA5B7, 0x30B7, 0xA5B8, 0x30B8, 0xA5B9, 0x30B9, 0xA5BA, 0x30BA, 0xA5BB, 0x30BB, 0xA5BC, 0x30BC, 0xA5BD, 0x30BD, 0xA5BE, 0x30BE, 0xA5BF, 0x30BF, 0xA5C0, 0x30C0, 0xA5C1, 0x30C1, 0xA5C2, 0x30C2, 0xA5C3, 0x30C3, 0xA5C4, 0x30C4, 0xA5C5, 0x30C5, 0xA5C6, 0x30C6, 0xA5C7, 0x30C7, 0xA5C8, 0x30C8, 0xA5C9, 0x30C9, 0xA5CA, 0x30CA, 0xA5CB, 0x30CB, 0xA5CC, 0x30CC, 0xA5CD, 0x30CD, 0xA5CE, 0x30CE, 0xA5CF, 0x30CF, 0xA5D0, 0x30D0, 0xA5D1, 0x30D1, 0xA5D2, 0x30D2, 0xA5D3, 0x30D3, 0xA5D4, 0x30D4, 0xA5D5, 0x30D5, 0xA5D6, 0x30D6, 0xA5D7, 0x30D7, 0xA5D8, 0x30D8, 0xA5D9, 0x30D9, 0xA5DA, 0x30DA, 0xA5DB, 0x30DB, 0xA5DC, 0x30DC, 0xA5DD, 0x30DD, 0xA5DE, 0x30DE, 0xA5DF, 0x30DF, 0xA5E0, 0x30E0, 0xA5E1, 0x30E1, 0xA5E2, 0x30E2, 0xA5E3, 0x30E3, 0xA5E4, 0x30E4, 0xA5E5, 0x30E5, 0xA5E6, 0x30E6, 0xA5E7, 0x30E7, 0xA5E8, 0x30E8, 0xA5E9, 0x30E9, 0xA5EA, 0x30EA, 0xA5EB, 0x30EB, 0xA5EC, 0x30EC, 0xA5ED, 0x30ED, 0xA5EE, 0x30EE, 0xA5EF, 0x30EF, 0xA5F0, 0x30F0, 0xA5F1, 0x30F1, 0xA5F2, 0x30F2, 0xA5F3, 0x30F3, 0xA5F4, 0x30F4, 0xA5F5, 0x30F5, 0xA5F6, 0x30F6, 0xA6A1, 0x0391, 0xA6A2, 0x0392, 0xA6A3, 0x0393, 0xA6A4, 0x0394, 0xA6A5, 0x0395, 0xA6A6, 0x0396, 0xA6A7, 0x0397, 0xA6A8, 0x0398, 0xA6A9, 0x0399, 0xA6AA, 0x039A, 0xA6AB, 0x039B, 0xA6AC, 0x039C, 0xA6AD, 0x039D, 0xA6AE, 0x039E, 0xA6AF, 0x039F, 0xA6B0, 0x03A0, 0xA6B1, 0x03A1, 0xA6B2, 0x03A3, 0xA6B3, 0x03A4, 0xA6B4, 0x03A5, 0xA6B5, 0x03A6, 0xA6B6, 0x03A7, 0xA6B7, 0x03A8, 0xA6B8, 0x03A9, 0xA6C1, 0x03B1, 0xA6C2, 0x03B2, 0xA6C3, 0x03B3, 0xA6C4, 0x03B4, 0xA6C5, 0x03B5, 0xA6C6, 0x03B6, 0xA6C7, 0x03B7, 0xA6C8, 0x03B8, 0xA6C9, 0x03B9, 0xA6CA, 0x03BA, 0xA6CB, 0x03BB, 0xA6CC, 0x03BC, 0xA6CD, 0x03BD, 0xA6CE, 0x03BE, 0xA6CF, 0x03BF, 0xA6D0, 0x03C0, 0xA6D1, 0x03C1, 0xA6D2, 0x03C3, 0xA6D3, 0x03C4, 0xA6D4, 0x03C5, 0xA6D5, 0x03C6, 0xA6D6, 0x03C7, 0xA6D7, 0x03C8, 0xA6D8, 0x03C9, 0xA6E0, 0xFE35, 0xA6E1, 0xFE36, 0xA6E2, 0xFE39, 0xA6E3, 0xFE3A, 0xA6E4, 0xFE3F, 0xA6E5, 0xFE40, 0xA6E6, 0xFE3D, 0xA6E7, 0xFE3E, 0xA6E8, 0xFE41, 0xA6E9, 0xFE42, 0xA6EA, 0xFE43, 0xA6EB, 0xFE44, 0xA6EE, 0xFE3B, 0xA6EF, 0xFE3C, 0xA6F0, 0xFE37, 0xA6F1, 0xFE38, 0xA6F2, 0xFE31, 0xA6F4, 0xFE33, 0xA6F5, 0xFE34, 0xA7A1, 0x0410, 0xA7A2, 0x0411, 0xA7A3, 0x0412, 0xA7A4, 0x0413, 0xA7A5, 0x0414, 0xA7A6, 0x0415, 0xA7A7, 0x0401, 0xA7A8, 0x0416, 0xA7A9, 0x0417, 0xA7AA, 0x0418, 0xA7AB, 0x0419, 0xA7AC, 0x041A, 0xA7AD, 0x041B, 0xA7AE, 0x041C, 0xA7AF, 0x041D, 0xA7B0, 0x041E, 0xA7B1, 0x041F, 0xA7B2, 0x0420, 0xA7B3, 0x0421, 0xA7B4, 0x0422, 0xA7B5, 0x0423, 0xA7B6, 0x0424, 0xA7B7, 0x0425, 0xA7B8, 0x0426, 0xA7B9, 0x0427, 0xA7BA, 0x0428, 0xA7BB, 0x0429, 0xA7BC, 0x042A, 0xA7BD, 0x042B, 0xA7BE, 0x042C, 0xA7BF, 0x042D, 0xA7C0, 0x042E, 0xA7C1, 0x042F, 0xA7D1, 0x0430, 0xA7D2, 0x0431, 0xA7D3, 0x0432, 0xA7D4, 0x0433, 0xA7D5, 0x0434, 0xA7D6, 0x0435, 0xA7D7, 0x0451, 0xA7D8, 0x0436, 0xA7D9, 0x0437, 0xA7DA, 0x0438, 0xA7DB, 0x0439, 0xA7DC, 0x043A, 0xA7DD, 0x043B, 0xA7DE, 0x043C, 0xA7DF, 0x043D, 0xA7E0, 0x043E, 0xA7E1, 0x043F, 0xA7E2, 0x0440, 0xA7E3, 0x0441, 0xA7E4, 0x0442, 0xA7E5, 0x0443, 0xA7E6, 0x0444, 0xA7E7, 0x0445, 0xA7E8, 0x0446, 0xA7E9, 0x0447, 0xA7EA, 0x0448, 0xA7EB, 0x0449, 0xA7EC, 0x044A, 0xA7ED, 0x044B, 0xA7EE, 0x044C, 0xA7EF, 0x044D, 0xA7F0, 0x044E, 0xA7F1, 0x044F, 0xA840, 0x02CA, 0xA841, 0x02CB, 0xA842, 0x02D9, 0xA843, 0x2013, 0xA844, 0x2015, 0xA845, 0x2025, 0xA846, 0x2035, 0xA847, 0x2105, 0xA848, 0x2109, 0xA849, 0x2196, 0xA84A, 0x2197, 0xA84B, 0x2198, 0xA84C, 0x2199, 0xA84D, 0x2215, 0xA84E, 0x221F, 0xA84F, 0x2223, 0xA850, 0x2252, 0xA851, 0x2266, 0xA852, 0x2267, 0xA853, 0x22BF, 0xA854, 0x2550, 0xA855, 0x2551, 0xA856, 0x2552, 0xA857, 0x2553, 0xA858, 0x2554, 0xA859, 0x2555, 0xA85A, 0x2556, 0xA85B, 0x2557, 0xA85C, 0x2558, 0xA85D, 0x2559, 0xA85E, 0x255A, 0xA85F, 0x255B, 0xA860, 0x255C, 0xA861, 0x255D, 0xA862, 0x255E, 0xA863, 0x255F, 0xA864, 0x2560, 0xA865, 0x2561, 0xA866, 0x2562, 0xA867, 0x2563, 0xA868, 0x2564, 0xA869, 0x2565, 0xA86A, 0x2566, 0xA86B, 0x2567, 0xA86C, 0x2568, 0xA86D, 0x2569, 0xA86E, 0x256A, 0xA86F, 0x256B, 0xA870, 0x256C, 0xA871, 0x256D, 0xA872, 0x256E, 0xA873, 0x256F, 0xA874, 0x2570, 0xA875, 0x2571, 0xA876, 0x2572, 0xA877, 0x2573, 0xA878, 0x2581, 0xA879, 0x2582, 0xA87A, 0x2583, 0xA87B, 0x2584, 0xA87C, 0x2585, 0xA87D, 0x2586, 0xA87E, 0x2587, 0xA880, 0x2588, 0xA881, 0x2589, 0xA882, 0x258A, 0xA883, 0x258B, 0xA884, 0x258C, 0xA885, 0x258D, 0xA886, 0x258E, 0xA887, 0x258F, 0xA888, 0x2593, 0xA889, 0x2594, 0xA88A, 0x2595, 0xA88B, 0x25BC, 0xA88C, 0x25BD, 0xA88D, 0x25E2, 0xA88E, 0x25E3, 0xA88F, 0x25E4, 0xA890, 0x25E5, 0xA891, 0x2609, 0xA892, 0x2295, 0xA893, 0x3012, 0xA894, 0x301D, 0xA895, 0x301E, 0xA8A1, 0x0101, 0xA8A2, 0x00E1, 0xA8A3, 0x01CE, 0xA8A4, 0x00E0, 0xA8A5, 0x0113, 0xA8A6, 0x00E9, 0xA8A7, 0x011B, 0xA8A8, 0x00E8, 0xA8A9, 0x012B, 0xA8AA, 0x00ED, 0xA8AB, 0x01D0, 0xA8AC, 0x00EC, 0xA8AD, 0x014D, 0xA8AE, 0x00F3, 0xA8AF, 0x01D2, 0xA8B0, 0x00F2, 0xA8B1, 0x016B, 0xA8B2, 0x00FA, 0xA8B3, 0x01D4, 0xA8B4, 0x00F9, 0xA8B5, 0x01D6, 0xA8B6, 0x01D8, 0xA8B7, 0x01DA, 0xA8B8, 0x01DC, 0xA8B9, 0x00FC, 0xA8BA, 0x00EA, 0xA8BB, 0x0251, 0xA8BD, 0x0144, 0xA8BE, 0x0148, 0xA8C0, 0x0261, 0xA8C5, 0x3105, 0xA8C6, 0x3106, 0xA8C7, 0x3107, 0xA8C8, 0x3108, 0xA8C9, 0x3109, 0xA8CA, 0x310A, 0xA8CB, 0x310B, 0xA8CC, 0x310C, 0xA8CD, 0x310D, 0xA8CE, 0x310E, 0xA8CF, 0x310F, 0xA8D0, 0x3110, 0xA8D1, 0x3111, 0xA8D2, 0x3112, 0xA8D3, 0x3113, 0xA8D4, 0x3114, 0xA8D5, 0x3115, 0xA8D6, 0x3116, 0xA8D7, 0x3117, 0xA8D8, 0x3118, 0xA8D9, 0x3119, 0xA8DA, 0x311A, 0xA8DB, 0x311B, 0xA8DC, 0x311C, 0xA8DD, 0x311D, 0xA8DE, 0x311E, 0xA8DF, 0x311F, 0xA8E0, 0x3120, 0xA8E1, 0x3121, 0xA8E2, 0x3122, 0xA8E3, 0x3123, 0xA8E4, 0x3124, 0xA8E5, 0x3125, 0xA8E6, 0x3126, 0xA8E7, 0x3127, 0xA8E8, 0x3128, 0xA8E9, 0x3129, 0xA940, 0x3021, 0xA941, 0x3022, 0xA942, 0x3023, 0xA943, 0x3024, 0xA944, 0x3025, 0xA945, 0x3026, 0xA946, 0x3027, 0xA947, 0x3028, 0xA948, 0x3029, 0xA949, 0x32A3, 0xA94A, 0x338E, 0xA94B, 0x338F, 0xA94C, 0x339C, 0xA94D, 0x339D, 0xA94E, 0x339E, 0xA94F, 0x33A1, 0xA950, 0x33C4, 0xA951, 0x33CE, 0xA952, 0x33D1, 0xA953, 0x33D2, 0xA954, 0x33D5, 0xA955, 0xFE30, 0xA956, 0xFFE2, 0xA957, 0xFFE4, 0xA959, 0x2121, 0xA95A, 0x3231, 0xA95C, 0x2010, 0xA960, 0x30FC, 0xA961, 0x309B, 0xA962, 0x309C, 0xA963, 0x30FD, 0xA964, 0x30FE, 0xA965, 0x3006, 0xA966, 0x309D, 0xA967, 0x309E, 0xA968, 0xFE49, 0xA969, 0xFE4A, 0xA96A, 0xFE4B, 0xA96B, 0xFE4C, 0xA96C, 0xFE4D, 0xA96D, 0xFE4E, 0xA96E, 0xFE4F, 0xA96F, 0xFE50, 0xA970, 0xFE51, 0xA971, 0xFE52, 0xA972, 0xFE54, 0xA973, 0xFE55, 0xA974, 0xFE56, 0xA975, 0xFE57, 0xA976, 0xFE59, 0xA977, 0xFE5A, 0xA978, 0xFE5B, 0xA979, 0xFE5C, 0xA97A, 0xFE5D, 0xA97B, 0xFE5E, 0xA97C, 0xFE5F, 0xA97D, 0xFE60, 0xA97E, 0xFE61, 0xA980, 0xFE62, 0xA981, 0xFE63, 0xA982, 0xFE64, 0xA983, 0xFE65, 0xA984, 0xFE66, 0xA985, 0xFE68, 0xA986, 0xFE69, 0xA987, 0xFE6A, 0xA988, 0xFE6B, 0xA996, 0x3007, 0xA9A4, 0x2500, 0xA9A5, 0x2501, 0xA9A6, 0x2502, 0xA9A7, 0x2503, 0xA9A8, 0x2504, 0xA9A9, 0x2505, 0xA9AA, 0x2506, 0xA9AB, 0x2507, 0xA9AC, 0x2508, 0xA9AD, 0x2509, 0xA9AE, 0x250A, 0xA9AF, 0x250B, 0xA9B0, 0x250C, 0xA9B1, 0x250D, 0xA9B2, 0x250E, 0xA9B3, 0x250F, 0xA9B4, 0x2510, 0xA9B5, 0x2511, 0xA9B6, 0x2512, 0xA9B7, 0x2513, 0xA9B8, 0x2514, 0xA9B9, 0x2515, 0xA9BA, 0x2516, 0xA9BB, 0x2517, 0xA9BC, 0x2518, 0xA9BD, 0x2519, 0xA9BE, 0x251A, 0xA9BF, 0x251B, 0xA9C0, 0x251C, 0xA9C1, 0x251D, 0xA9C2, 0x251E, 0xA9C3, 0x251F, 0xA9C4, 0x2520, 0xA9C5, 0x2521, 0xA9C6, 0x2522, 0xA9C7, 0x2523, 0xA9C8, 0x2524, 0xA9C9, 0x2525, 0xA9CA, 0x2526, 0xA9CB, 0x2527, 0xA9CC, 0x2528, 0xA9CD, 0x2529, 0xA9CE, 0x252A, 0xA9CF, 0x252B, 0xA9D0, 0x252C, 0xA9D1, 0x252D, 0xA9D2, 0x252E, 0xA9D3, 0x252F, 0xA9D4, 0x2530, 0xA9D5, 0x2531, 0xA9D6, 0x2532, 0xA9D7, 0x2533, 0xA9D8, 0x2534, 0xA9D9, 0x2535, 0xA9DA, 0x2536, 0xA9DB, 0x2537, 0xA9DC, 0x2538, 0xA9DD, 0x2539, 0xA9DE, 0x253A, 0xA9DF, 0x253B, 0xA9E0, 0x253C, 0xA9E1, 0x253D, 0xA9E2, 0x253E, 0xA9E3, 0x253F, 0xA9E4, 0x2540, 0xA9E5, 0x2541, 0xA9E6, 0x2542, 0xA9E7, 0x2543, 0xA9E8, 0x2544, 0xA9E9, 0x2545, 0xA9EA, 0x2546, 0xA9EB, 0x2547, 0xA9EC, 0x2548, 0xA9ED, 0x2549, 0xA9EE, 0x254A, 0xA9EF, 0x254B, 0xAA40, 0x72DC, 0xAA41, 0x72DD, 0xAA42, 0x72DF, 0xAA43, 0x72E2, 0xAA44, 0x72E3, 0xAA45, 0x72E4, 0xAA46, 0x72E5, 0xAA47, 0x72E6, 0xAA48, 0x72E7, 0xAA49, 0x72EA, 0xAA4A, 0x72EB, 0xAA4B, 0x72F5, 0xAA4C, 0x72F6, 0xAA4D, 0x72F9, 0xAA4E, 0x72FD, 0xAA4F, 0x72FE, 0xAA50, 0x72FF, 0xAA51, 0x7300, 0xAA52, 0x7302, 0xAA53, 0x7304, 0xAA54, 0x7305, 0xAA55, 0x7306, 0xAA56, 0x7307, 0xAA57, 0x7308, 0xAA58, 0x7309, 0xAA59, 0x730B, 0xAA5A, 0x730C, 0xAA5B, 0x730D, 0xAA5C, 0x730F, 0xAA5D, 0x7310, 0xAA5E, 0x7311, 0xAA5F, 0x7312, 0xAA60, 0x7314, 0xAA61, 0x7318, 0xAA62, 0x7319, 0xAA63, 0x731A, 0xAA64, 0x731F, 0xAA65, 0x7320, 0xAA66, 0x7323, 0xAA67, 0x7324, 0xAA68, 0x7326, 0xAA69, 0x7327, 0xAA6A, 0x7328, 0xAA6B, 0x732D, 0xAA6C, 0x732F, 0xAA6D, 0x7330, 0xAA6E, 0x7332, 0xAA6F, 0x7333, 0xAA70, 0x7335, 0xAA71, 0x7336, 0xAA72, 0x733A, 0xAA73, 0x733B, 0xAA74, 0x733C, 0xAA75, 0x733D, 0xAA76, 0x7340, 0xAA77, 0x7341, 0xAA78, 0x7342, 0xAA79, 0x7343, 0xAA7A, 0x7344, 0xAA7B, 0x7345, 0xAA7C, 0x7346, 0xAA7D, 0x7347, 0xAA7E, 0x7348, 0xAA80, 0x7349, 0xAA81, 0x734A, 0xAA82, 0x734B, 0xAA83, 0x734C, 0xAA84, 0x734E, 0xAA85, 0x734F, 0xAA86, 0x7351, 0xAA87, 0x7353, 0xAA88, 0x7354, 0xAA89, 0x7355, 0xAA8A, 0x7356, 0xAA8B, 0x7358, 0xAA8C, 0x7359, 0xAA8D, 0x735A, 0xAA8E, 0x735B, 0xAA8F, 0x735C, 0xAA90, 0x735D, 0xAA91, 0x735E, 0xAA92, 0x735F, 0xAA93, 0x7361, 0xAA94, 0x7362, 0xAA95, 0x7363, 0xAA96, 0x7364, 0xAA97, 0x7365, 0xAA98, 0x7366, 0xAA99, 0x7367, 0xAA9A, 0x7368, 0xAA9B, 0x7369, 0xAA9C, 0x736A, 0xAA9D, 0x736B, 0xAA9E, 0x736E, 0xAA9F, 0x7370, 0xAAA0, 0x7371, 0xAB40, 0x7372, 0xAB41, 0x7373, 0xAB42, 0x7374, 0xAB43, 0x7375, 0xAB44, 0x7376, 0xAB45, 0x7377, 0xAB46, 0x7378, 0xAB47, 0x7379, 0xAB48, 0x737A, 0xAB49, 0x737B, 0xAB4A, 0x737C, 0xAB4B, 0x737D, 0xAB4C, 0x737F, 0xAB4D, 0x7380, 0xAB4E, 0x7381, 0xAB4F, 0x7382, 0xAB50, 0x7383, 0xAB51, 0x7385, 0xAB52, 0x7386, 0xAB53, 0x7388, 0xAB54, 0x738A, 0xAB55, 0x738C, 0xAB56, 0x738D, 0xAB57, 0x738F, 0xAB58, 0x7390, 0xAB59, 0x7392, 0xAB5A, 0x7393, 0xAB5B, 0x7394, 0xAB5C, 0x7395, 0xAB5D, 0x7397, 0xAB5E, 0x7398, 0xAB5F, 0x7399, 0xAB60, 0x739A, 0xAB61, 0x739C, 0xAB62, 0x739D, 0xAB63, 0x739E, 0xAB64, 0x73A0, 0xAB65, 0x73A1, 0xAB66, 0x73A3, 0xAB67, 0x73A4, 0xAB68, 0x73A5, 0xAB69, 0x73A6, 0xAB6A, 0x73A7, 0xAB6B, 0x73A8, 0xAB6C, 0x73AA, 0xAB6D, 0x73AC, 0xAB6E, 0x73AD, 0xAB6F, 0x73B1, 0xAB70, 0x73B4, 0xAB71, 0x73B5, 0xAB72, 0x73B6, 0xAB73, 0x73B8, 0xAB74, 0x73B9, 0xAB75, 0x73BC, 0xAB76, 0x73BD, 0xAB77, 0x73BE, 0xAB78, 0x73BF, 0xAB79, 0x73C1, 0xAB7A, 0x73C3, 0xAB7B, 0x73C4, 0xAB7C, 0x73C5, 0xAB7D, 0x73C6, 0xAB7E, 0x73C7, 0xAB80, 0x73CB, 0xAB81, 0x73CC, 0xAB82, 0x73CE, 0xAB83, 0x73D2, 0xAB84, 0x73D3, 0xAB85, 0x73D4, 0xAB86, 0x73D5, 0xAB87, 0x73D6, 0xAB88, 0x73D7, 0xAB89, 0x73D8, 0xAB8A, 0x73DA, 0xAB8B, 0x73DB, 0xAB8C, 0x73DC, 0xAB8D, 0x73DD, 0xAB8E, 0x73DF, 0xAB8F, 0x73E1, 0xAB90, 0x73E2, 0xAB91, 0x73E3, 0xAB92, 0x73E4, 0xAB93, 0x73E6, 0xAB94, 0x73E8, 0xAB95, 0x73EA, 0xAB96, 0x73EB, 0xAB97, 0x73EC, 0xAB98, 0x73EE, 0xAB99, 0x73EF, 0xAB9A, 0x73F0, 0xAB9B, 0x73F1, 0xAB9C, 0x73F3, 0xAB9D, 0x73F4, 0xAB9E, 0x73F5, 0xAB9F, 0x73F6, 0xABA0, 0x73F7, 0xAC40, 0x73F8, 0xAC41, 0x73F9, 0xAC42, 0x73FA, 0xAC43, 0x73FB, 0xAC44, 0x73FC, 0xAC45, 0x73FD, 0xAC46, 0x73FE, 0xAC47, 0x73FF, 0xAC48, 0x7400, 0xAC49, 0x7401, 0xAC4A, 0x7402, 0xAC4B, 0x7404, 0xAC4C, 0x7407, 0xAC4D, 0x7408, 0xAC4E, 0x740B, 0xAC4F, 0x740C, 0xAC50, 0x740D, 0xAC51, 0x740E, 0xAC52, 0x7411, 0xAC53, 0x7412, 0xAC54, 0x7413, 0xAC55, 0x7414, 0xAC56, 0x7415, 0xAC57, 0x7416, 0xAC58, 0x7417, 0xAC59, 0x7418, 0xAC5A, 0x7419, 0xAC5B, 0x741C, 0xAC5C, 0x741D, 0xAC5D, 0x741E, 0xAC5E, 0x741F, 0xAC5F, 0x7420, 0xAC60, 0x7421, 0xAC61, 0x7423, 0xAC62, 0x7424, 0xAC63, 0x7427, 0xAC64, 0x7429, 0xAC65, 0x742B, 0xAC66, 0x742D, 0xAC67, 0x742F, 0xAC68, 0x7431, 0xAC69, 0x7432, 0xAC6A, 0x7437, 0xAC6B, 0x7438, 0xAC6C, 0x7439, 0xAC6D, 0x743A, 0xAC6E, 0x743B, 0xAC6F, 0x743D, 0xAC70, 0x743E, 0xAC71, 0x743F, 0xAC72, 0x7440, 0xAC73, 0x7442, 0xAC74, 0x7443, 0xAC75, 0x7444, 0xAC76, 0x7445, 0xAC77, 0x7446, 0xAC78, 0x7447, 0xAC79, 0x7448, 0xAC7A, 0x7449, 0xAC7B, 0x744A, 0xAC7C, 0x744B, 0xAC7D, 0x744C, 0xAC7E, 0x744D, 0xAC80, 0x744E, 0xAC81, 0x744F, 0xAC82, 0x7450, 0xAC83, 0x7451, 0xAC84, 0x7452, 0xAC85, 0x7453, 0xAC86, 0x7454, 0xAC87, 0x7456, 0xAC88, 0x7458, 0xAC89, 0x745D, 0xAC8A, 0x7460, 0xAC8B, 0x7461, 0xAC8C, 0x7462, 0xAC8D, 0x7463, 0xAC8E, 0x7464, 0xAC8F, 0x7465, 0xAC90, 0x7466, 0xAC91, 0x7467, 0xAC92, 0x7468, 0xAC93, 0x7469, 0xAC94, 0x746A, 0xAC95, 0x746B, 0xAC96, 0x746C, 0xAC97, 0x746E, 0xAC98, 0x746F, 0xAC99, 0x7471, 0xAC9A, 0x7472, 0xAC9B, 0x7473, 0xAC9C, 0x7474, 0xAC9D, 0x7475, 0xAC9E, 0x7478, 0xAC9F, 0x7479, 0xACA0, 0x747A, 0xAD40, 0x747B, 0xAD41, 0x747C, 0xAD42, 0x747D, 0xAD43, 0x747F, 0xAD44, 0x7482, 0xAD45, 0x7484, 0xAD46, 0x7485, 0xAD47, 0x7486, 0xAD48, 0x7488, 0xAD49, 0x7489, 0xAD4A, 0x748A, 0xAD4B, 0x748C, 0xAD4C, 0x748D, 0xAD4D, 0x748F, 0xAD4E, 0x7491, 0xAD4F, 0x7492, 0xAD50, 0x7493, 0xAD51, 0x7494, 0xAD52, 0x7495, 0xAD53, 0x7496, 0xAD54, 0x7497, 0xAD55, 0x7498, 0xAD56, 0x7499, 0xAD57, 0x749A, 0xAD58, 0x749B, 0xAD59, 0x749D, 0xAD5A, 0x749F, 0xAD5B, 0x74A0, 0xAD5C, 0x74A1, 0xAD5D, 0x74A2, 0xAD5E, 0x74A3, 0xAD5F, 0x74A4, 0xAD60, 0x74A5, 0xAD61, 0x74A6, 0xAD62, 0x74AA, 0xAD63, 0x74AB, 0xAD64, 0x74AC, 0xAD65, 0x74AD, 0xAD66, 0x74AE, 0xAD67, 0x74AF, 0xAD68, 0x74B0, 0xAD69, 0x74B1, 0xAD6A, 0x74B2, 0xAD6B, 0x74B3, 0xAD6C, 0x74B4, 0xAD6D, 0x74B5, 0xAD6E, 0x74B6, 0xAD6F, 0x74B7, 0xAD70, 0x74B8, 0xAD71, 0x74B9, 0xAD72, 0x74BB, 0xAD73, 0x74BC, 0xAD74, 0x74BD, 0xAD75, 0x74BE, 0xAD76, 0x74BF, 0xAD77, 0x74C0, 0xAD78, 0x74C1, 0xAD79, 0x74C2, 0xAD7A, 0x74C3, 0xAD7B, 0x74C4, 0xAD7C, 0x74C5, 0xAD7D, 0x74C6, 0xAD7E, 0x74C7, 0xAD80, 0x74C8, 0xAD81, 0x74C9, 0xAD82, 0x74CA, 0xAD83, 0x74CB, 0xAD84, 0x74CC, 0xAD85, 0x74CD, 0xAD86, 0x74CE, 0xAD87, 0x74CF, 0xAD88, 0x74D0, 0xAD89, 0x74D1, 0xAD8A, 0x74D3, 0xAD8B, 0x74D4, 0xAD8C, 0x74D5, 0xAD8D, 0x74D6, 0xAD8E, 0x74D7, 0xAD8F, 0x74D8, 0xAD90, 0x74D9, 0xAD91, 0x74DA, 0xAD92, 0x74DB, 0xAD93, 0x74DD, 0xAD94, 0x74DF, 0xAD95, 0x74E1, 0xAD96, 0x74E5, 0xAD97, 0x74E7, 0xAD98, 0x74E8, 0xAD99, 0x74E9, 0xAD9A, 0x74EA, 0xAD9B, 0x74EB, 0xAD9C, 0x74EC, 0xAD9D, 0x74ED, 0xAD9E, 0x74F0, 0xAD9F, 0x74F1, 0xADA0, 0x74F2, 0xAE40, 0x74F3, 0xAE41, 0x74F5, 0xAE42, 0x74F8, 0xAE43, 0x74F9, 0xAE44, 0x74FA, 0xAE45, 0x74FB, 0xAE46, 0x74FC, 0xAE47, 0x74FD, 0xAE48, 0x74FE, 0xAE49, 0x7500, 0xAE4A, 0x7501, 0xAE4B, 0x7502, 0xAE4C, 0x7503, 0xAE4D, 0x7505, 0xAE4E, 0x7506, 0xAE4F, 0x7507, 0xAE50, 0x7508, 0xAE51, 0x7509, 0xAE52, 0x750A, 0xAE53, 0x750B, 0xAE54, 0x750C, 0xAE55, 0x750E, 0xAE56, 0x7510, 0xAE57, 0x7512, 0xAE58, 0x7514, 0xAE59, 0x7515, 0xAE5A, 0x7516, 0xAE5B, 0x7517, 0xAE5C, 0x751B, 0xAE5D, 0x751D, 0xAE5E, 0x751E, 0xAE5F, 0x7520, 0xAE60, 0x7521, 0xAE61, 0x7522, 0xAE62, 0x7523, 0xAE63, 0x7524, 0xAE64, 0x7526, 0xAE65, 0x7527, 0xAE66, 0x752A, 0xAE67, 0x752E, 0xAE68, 0x7534, 0xAE69, 0x7536, 0xAE6A, 0x7539, 0xAE6B, 0x753C, 0xAE6C, 0x753D, 0xAE6D, 0x753F, 0xAE6E, 0x7541, 0xAE6F, 0x7542, 0xAE70, 0x7543, 0xAE71, 0x7544, 0xAE72, 0x7546, 0xAE73, 0x7547, 0xAE74, 0x7549, 0xAE75, 0x754A, 0xAE76, 0x754D, 0xAE77, 0x7550, 0xAE78, 0x7551, 0xAE79, 0x7552, 0xAE7A, 0x7553, 0xAE7B, 0x7555, 0xAE7C, 0x7556, 0xAE7D, 0x7557, 0xAE7E, 0x7558, 0xAE80, 0x755D, 0xAE81, 0x755E, 0xAE82, 0x755F, 0xAE83, 0x7560, 0xAE84, 0x7561, 0xAE85, 0x7562, 0xAE86, 0x7563, 0xAE87, 0x7564, 0xAE88, 0x7567, 0xAE89, 0x7568, 0xAE8A, 0x7569, 0xAE8B, 0x756B, 0xAE8C, 0x756C, 0xAE8D, 0x756D, 0xAE8E, 0x756E, 0xAE8F, 0x756F, 0xAE90, 0x7570, 0xAE91, 0x7571, 0xAE92, 0x7573, 0xAE93, 0x7575, 0xAE94, 0x7576, 0xAE95, 0x7577, 0xAE96, 0x757A, 0xAE97, 0x757B, 0xAE98, 0x757C, 0xAE99, 0x757D, 0xAE9A, 0x757E, 0xAE9B, 0x7580, 0xAE9C, 0x7581, 0xAE9D, 0x7582, 0xAE9E, 0x7584, 0xAE9F, 0x7585, 0xAEA0, 0x7587, 0xAF40, 0x7588, 0xAF41, 0x7589, 0xAF42, 0x758A, 0xAF43, 0x758C, 0xAF44, 0x758D, 0xAF45, 0x758E, 0xAF46, 0x7590, 0xAF47, 0x7593, 0xAF48, 0x7595, 0xAF49, 0x7598, 0xAF4A, 0x759B, 0xAF4B, 0x759C, 0xAF4C, 0x759E, 0xAF4D, 0x75A2, 0xAF4E, 0x75A6, 0xAF4F, 0x75A7, 0xAF50, 0x75A8, 0xAF51, 0x75A9, 0xAF52, 0x75AA, 0xAF53, 0x75AD, 0xAF54, 0x75B6, 0xAF55, 0x75B7, 0xAF56, 0x75BA, 0xAF57, 0x75BB, 0xAF58, 0x75BF, 0xAF59, 0x75C0, 0xAF5A, 0x75C1, 0xAF5B, 0x75C6, 0xAF5C, 0x75CB, 0xAF5D, 0x75CC, 0xAF5E, 0x75CE, 0xAF5F, 0x75CF, 0xAF60, 0x75D0, 0xAF61, 0x75D1, 0xAF62, 0x75D3, 0xAF63, 0x75D7, 0xAF64, 0x75D9, 0xAF65, 0x75DA, 0xAF66, 0x75DC, 0xAF67, 0x75DD, 0xAF68, 0x75DF, 0xAF69, 0x75E0, 0xAF6A, 0x75E1, 0xAF6B, 0x75E5, 0xAF6C, 0x75E9, 0xAF6D, 0x75EC, 0xAF6E, 0x75ED, 0xAF6F, 0x75EE, 0xAF70, 0x75EF, 0xAF71, 0x75F2, 0xAF72, 0x75F3, 0xAF73, 0x75F5, 0xAF74, 0x75F6, 0xAF75, 0x75F7, 0xAF76, 0x75F8, 0xAF77, 0x75FA, 0xAF78, 0x75FB, 0xAF79, 0x75FD, 0xAF7A, 0x75FE, 0xAF7B, 0x7602, 0xAF7C, 0x7604, 0xAF7D, 0x7606, 0xAF7E, 0x7607, 0xAF80, 0x7608, 0xAF81, 0x7609, 0xAF82, 0x760B, 0xAF83, 0x760D, 0xAF84, 0x760E, 0xAF85, 0x760F, 0xAF86, 0x7611, 0xAF87, 0x7612, 0xAF88, 0x7613, 0xAF89, 0x7614, 0xAF8A, 0x7616, 0xAF8B, 0x761A, 0xAF8C, 0x761C, 0xAF8D, 0x761D, 0xAF8E, 0x761E, 0xAF8F, 0x7621, 0xAF90, 0x7623, 0xAF91, 0x7627, 0xAF92, 0x7628, 0xAF93, 0x762C, 0xAF94, 0x762E, 0xAF95, 0x762F, 0xAF96, 0x7631, 0xAF97, 0x7632, 0xAF98, 0x7636, 0xAF99, 0x7637, 0xAF9A, 0x7639, 0xAF9B, 0x763A, 0xAF9C, 0x763B, 0xAF9D, 0x763D, 0xAF9E, 0x7641, 0xAF9F, 0x7642, 0xAFA0, 0x7644, 0xB040, 0x7645, 0xB041, 0x7646, 0xB042, 0x7647, 0xB043, 0x7648, 0xB044, 0x7649, 0xB045, 0x764A, 0xB046, 0x764B, 0xB047, 0x764E, 0xB048, 0x764F, 0xB049, 0x7650, 0xB04A, 0x7651, 0xB04B, 0x7652, 0xB04C, 0x7653, 0xB04D, 0x7655, 0xB04E, 0x7657, 0xB04F, 0x7658, 0xB050, 0x7659, 0xB051, 0x765A, 0xB052, 0x765B, 0xB053, 0x765D, 0xB054, 0x765F, 0xB055, 0x7660, 0xB056, 0x7661, 0xB057, 0x7662, 0xB058, 0x7664, 0xB059, 0x7665, 0xB05A, 0x7666, 0xB05B, 0x7667, 0xB05C, 0x7668, 0xB05D, 0x7669, 0xB05E, 0x766A, 0xB05F, 0x766C, 0xB060, 0x766D, 0xB061, 0x766E, 0xB062, 0x7670, 0xB063, 0x7671, 0xB064, 0x7672, 0xB065, 0x7673, 0xB066, 0x7674, 0xB067, 0x7675, 0xB068, 0x7676, 0xB069, 0x7677, 0xB06A, 0x7679, 0xB06B, 0x767A, 0xB06C, 0x767C, 0xB06D, 0x767F, 0xB06E, 0x7680, 0xB06F, 0x7681, 0xB070, 0x7683, 0xB071, 0x7685, 0xB072, 0x7689, 0xB073, 0x768A, 0xB074, 0x768C, 0xB075, 0x768D, 0xB076, 0x768F, 0xB077, 0x7690, 0xB078, 0x7692, 0xB079, 0x7694, 0xB07A, 0x7695, 0xB07B, 0x7697, 0xB07C, 0x7698, 0xB07D, 0x769A, 0xB07E, 0x769B, 0xB080, 0x769C, 0xB081, 0x769D, 0xB082, 0x769E, 0xB083, 0x769F, 0xB084, 0x76A0, 0xB085, 0x76A1, 0xB086, 0x76A2, 0xB087, 0x76A3, 0xB088, 0x76A5, 0xB089, 0x76A6, 0xB08A, 0x76A7, 0xB08B, 0x76A8, 0xB08C, 0x76A9, 0xB08D, 0x76AA, 0xB08E, 0x76AB, 0xB08F, 0x76AC, 0xB090, 0x76AD, 0xB091, 0x76AF, 0xB092, 0x76B0, 0xB093, 0x76B3, 0xB094, 0x76B5, 0xB095, 0x76B6, 0xB096, 0x76B7, 0xB097, 0x76B8, 0xB098, 0x76B9, 0xB099, 0x76BA, 0xB09A, 0x76BB, 0xB09B, 0x76BC, 0xB09C, 0x76BD, 0xB09D, 0x76BE, 0xB09E, 0x76C0, 0xB09F, 0x76C1, 0xB0A0, 0x76C3, 0xB0A1, 0x554A, 0xB0A2, 0x963F, 0xB0A3, 0x57C3, 0xB0A4, 0x6328, 0xB0A5, 0x54CE, 0xB0A6, 0x5509, 0xB0A7, 0x54C0, 0xB0A8, 0x7691, 0xB0A9, 0x764C, 0xB0AA, 0x853C, 0xB0AB, 0x77EE, 0xB0AC, 0x827E, 0xB0AD, 0x788D, 0xB0AE, 0x7231, 0xB0AF, 0x9698, 0xB0B0, 0x978D, 0xB0B1, 0x6C28, 0xB0B2, 0x5B89, 0xB0B3, 0x4FFA, 0xB0B4, 0x6309, 0xB0B5, 0x6697, 0xB0B6, 0x5CB8, 0xB0B7, 0x80FA, 0xB0B8, 0x6848, 0xB0B9, 0x80AE, 0xB0BA, 0x6602, 0xB0BB, 0x76CE, 0xB0BC, 0x51F9, 0xB0BD, 0x6556, 0xB0BE, 0x71AC, 0xB0BF, 0x7FF1, 0xB0C0, 0x8884, 0xB0C1, 0x50B2, 0xB0C2, 0x5965, 0xB0C3, 0x61CA, 0xB0C4, 0x6FB3, 0xB0C5, 0x82AD, 0xB0C6, 0x634C, 0xB0C7, 0x6252, 0xB0C8, 0x53ED, 0xB0C9, 0x5427, 0xB0CA, 0x7B06, 0xB0CB, 0x516B, 0xB0CC, 0x75A4, 0xB0CD, 0x5DF4, 0xB0CE, 0x62D4, 0xB0CF, 0x8DCB, 0xB0D0, 0x9776, 0xB0D1, 0x628A, 0xB0D2, 0x8019, 0xB0D3, 0x575D, 0xB0D4, 0x9738, 0xB0D5, 0x7F62, 0xB0D6, 0x7238, 0xB0D7, 0x767D, 0xB0D8, 0x67CF, 0xB0D9, 0x767E, 0xB0DA, 0x6446, 0xB0DB, 0x4F70, 0xB0DC, 0x8D25, 0xB0DD, 0x62DC, 0xB0DE, 0x7A17, 0xB0DF, 0x6591, 0xB0E0, 0x73ED, 0xB0E1, 0x642C, 0xB0E2, 0x6273, 0xB0E3, 0x822C, 0xB0E4, 0x9881, 0xB0E5, 0x677F, 0xB0E6, 0x7248, 0xB0E7, 0x626E, 0xB0E8, 0x62CC, 0xB0E9, 0x4F34, 0xB0EA, 0x74E3, 0xB0EB, 0x534A, 0xB0EC, 0x529E, 0xB0ED, 0x7ECA, 0xB0EE, 0x90A6, 0xB0EF, 0x5E2E, 0xB0F0, 0x6886, 0xB0F1, 0x699C, 0xB0F2, 0x8180, 0xB0F3, 0x7ED1, 0xB0F4, 0x68D2, 0xB0F5, 0x78C5, 0xB0F6, 0x868C, 0xB0F7, 0x9551, 0xB0F8, 0x508D, 0xB0F9, 0x8C24, 0xB0FA, 0x82DE, 0xB0FB, 0x80DE, 0xB0FC, 0x5305, 0xB0FD, 0x8912, 0xB0FE, 0x5265, 0xB140, 0x76C4, 0xB141, 0x76C7, 0xB142, 0x76C9, 0xB143, 0x76CB, 0xB144, 0x76CC, 0xB145, 0x76D3, 0xB146, 0x76D5, 0xB147, 0x76D9, 0xB148, 0x76DA, 0xB149, 0x76DC, 0xB14A, 0x76DD, 0xB14B, 0x76DE, 0xB14C, 0x76E0, 0xB14D, 0x76E1, 0xB14E, 0x76E2, 0xB14F, 0x76E3, 0xB150, 0x76E4, 0xB151, 0x76E6, 0xB152, 0x76E7, 0xB153, 0x76E8, 0xB154, 0x76E9, 0xB155, 0x76EA, 0xB156, 0x76EB, 0xB157, 0x76EC, 0xB158, 0x76ED, 0xB159, 0x76F0, 0xB15A, 0x76F3, 0xB15B, 0x76F5, 0xB15C, 0x76F6, 0xB15D, 0x76F7, 0xB15E, 0x76FA, 0xB15F, 0x76FB, 0xB160, 0x76FD, 0xB161, 0x76FF, 0xB162, 0x7700, 0xB163, 0x7702, 0xB164, 0x7703, 0xB165, 0x7705, 0xB166, 0x7706, 0xB167, 0x770A, 0xB168, 0x770C, 0xB169, 0x770E, 0xB16A, 0x770F, 0xB16B, 0x7710, 0xB16C, 0x7711, 0xB16D, 0x7712, 0xB16E, 0x7713, 0xB16F, 0x7714, 0xB170, 0x7715, 0xB171, 0x7716, 0xB172, 0x7717, 0xB173, 0x7718, 0xB174, 0x771B, 0xB175, 0x771C, 0xB176, 0x771D, 0xB177, 0x771E, 0xB178, 0x7721, 0xB179, 0x7723, 0xB17A, 0x7724, 0xB17B, 0x7725, 0xB17C, 0x7727, 0xB17D, 0x772A, 0xB17E, 0x772B, 0xB180, 0x772C, 0xB181, 0x772E, 0xB182, 0x7730, 0xB183, 0x7731, 0xB184, 0x7732, 0xB185, 0x7733, 0xB186, 0x7734, 0xB187, 0x7739, 0xB188, 0x773B, 0xB189, 0x773D, 0xB18A, 0x773E, 0xB18B, 0x773F, 0xB18C, 0x7742, 0xB18D, 0x7744, 0xB18E, 0x7745, 0xB18F, 0x7746, 0xB190, 0x7748, 0xB191, 0x7749, 0xB192, 0x774A, 0xB193, 0x774B, 0xB194, 0x774C, 0xB195, 0x774D, 0xB196, 0x774E, 0xB197, 0x774F, 0xB198, 0x7752, 0xB199, 0x7753, 0xB19A, 0x7754, 0xB19B, 0x7755, 0xB19C, 0x7756, 0xB19D, 0x7757, 0xB19E, 0x7758, 0xB19F, 0x7759, 0xB1A0, 0x775C, 0xB1A1, 0x8584, 0xB1A2, 0x96F9, 0xB1A3, 0x4FDD, 0xB1A4, 0x5821, 0xB1A5, 0x9971, 0xB1A6, 0x5B9D, 0xB1A7, 0x62B1, 0xB1A8, 0x62A5, 0xB1A9, 0x66B4, 0xB1AA, 0x8C79, 0xB1AB, 0x9C8D, 0xB1AC, 0x7206, 0xB1AD, 0x676F, 0xB1AE, 0x7891, 0xB1AF, 0x60B2, 0xB1B0, 0x5351, 0xB1B1, 0x5317, 0xB1B2, 0x8F88, 0xB1B3, 0x80CC, 0xB1B4, 0x8D1D, 0xB1B5, 0x94A1, 0xB1B6, 0x500D, 0xB1B7, 0x72C8, 0xB1B8, 0x5907, 0xB1B9, 0x60EB, 0xB1BA, 0x7119, 0xB1BB, 0x88AB, 0xB1BC, 0x5954, 0xB1BD, 0x82EF, 0xB1BE, 0x672C, 0xB1BF, 0x7B28, 0xB1C0, 0x5D29, 0xB1C1, 0x7EF7, 0xB1C2, 0x752D, 0xB1C3, 0x6CF5, 0xB1C4, 0x8E66, 0xB1C5, 0x8FF8, 0xB1C6, 0x903C, 0xB1C7, 0x9F3B, 0xB1C8, 0x6BD4, 0xB1C9, 0x9119, 0xB1CA, 0x7B14, 0xB1CB, 0x5F7C, 0xB1CC, 0x78A7, 0xB1CD, 0x84D6, 0xB1CE, 0x853D, 0xB1CF, 0x6BD5, 0xB1D0, 0x6BD9, 0xB1D1, 0x6BD6, 0xB1D2, 0x5E01, 0xB1D3, 0x5E87, 0xB1D4, 0x75F9, 0xB1D5, 0x95ED, 0xB1D6, 0x655D, 0xB1D7, 0x5F0A, 0xB1D8, 0x5FC5, 0xB1D9, 0x8F9F, 0xB1DA, 0x58C1, 0xB1DB, 0x81C2, 0xB1DC, 0x907F, 0xB1DD, 0x965B, 0xB1DE, 0x97AD, 0xB1DF, 0x8FB9, 0xB1E0, 0x7F16, 0xB1E1, 0x8D2C, 0xB1E2, 0x6241, 0xB1E3, 0x4FBF, 0xB1E4, 0x53D8, 0xB1E5, 0x535E, 0xB1E6, 0x8FA8, 0xB1E7, 0x8FA9, 0xB1E8, 0x8FAB, 0xB1E9, 0x904D, 0xB1EA, 0x6807, 0xB1EB, 0x5F6A, 0xB1EC, 0x8198, 0xB1ED, 0x8868, 0xB1EE, 0x9CD6, 0xB1EF, 0x618B, 0xB1F0, 0x522B, 0xB1F1, 0x762A, 0xB1F2, 0x5F6C, 0xB1F3, 0x658C, 0xB1F4, 0x6FD2, 0xB1F5, 0x6EE8, 0xB1F6, 0x5BBE, 0xB1F7, 0x6448, 0xB1F8, 0x5175, 0xB1F9, 0x51B0, 0xB1FA, 0x67C4, 0xB1FB, 0x4E19, 0xB1FC, 0x79C9, 0xB1FD, 0x997C, 0xB1FE, 0x70B3, 0xB240, 0x775D, 0xB241, 0x775E, 0xB242, 0x775F, 0xB243, 0x7760, 0xB244, 0x7764, 0xB245, 0x7767, 0xB246, 0x7769, 0xB247, 0x776A, 0xB248, 0x776D, 0xB249, 0x776E, 0xB24A, 0x776F, 0xB24B, 0x7770, 0xB24C, 0x7771, 0xB24D, 0x7772, 0xB24E, 0x7773, 0xB24F, 0x7774, 0xB250, 0x7775, 0xB251, 0x7776, 0xB252, 0x7777, 0xB253, 0x7778, 0xB254, 0x777A, 0xB255, 0x777B, 0xB256, 0x777C, 0xB257, 0x7781, 0xB258, 0x7782, 0xB259, 0x7783, 0xB25A, 0x7786, 0xB25B, 0x7787, 0xB25C, 0x7788, 0xB25D, 0x7789, 0xB25E, 0x778A, 0xB25F, 0x778B, 0xB260, 0x778F, 0xB261, 0x7790, 0xB262, 0x7793, 0xB263, 0x7794, 0xB264, 0x7795, 0xB265, 0x7796, 0xB266, 0x7797, 0xB267, 0x7798, 0xB268, 0x7799, 0xB269, 0x779A, 0xB26A, 0x779B, 0xB26B, 0x779C, 0xB26C, 0x779D, 0xB26D, 0x779E, 0xB26E, 0x77A1, 0xB26F, 0x77A3, 0xB270, 0x77A4, 0xB271, 0x77A6, 0xB272, 0x77A8, 0xB273, 0x77AB, 0xB274, 0x77AD, 0xB275, 0x77AE, 0xB276, 0x77AF, 0xB277, 0x77B1, 0xB278, 0x77B2, 0xB279, 0x77B4, 0xB27A, 0x77B6, 0xB27B, 0x77B7, 0xB27C, 0x77B8, 0xB27D, 0x77B9, 0xB27E, 0x77BA, 0xB280, 0x77BC, 0xB281, 0x77BE, 0xB282, 0x77C0, 0xB283, 0x77C1, 0xB284, 0x77C2, 0xB285, 0x77C3, 0xB286, 0x77C4, 0xB287, 0x77C5, 0xB288, 0x77C6, 0xB289, 0x77C7, 0xB28A, 0x77C8, 0xB28B, 0x77C9, 0xB28C, 0x77CA, 0xB28D, 0x77CB, 0xB28E, 0x77CC, 0xB28F, 0x77CE, 0xB290, 0x77CF, 0xB291, 0x77D0, 0xB292, 0x77D1, 0xB293, 0x77D2, 0xB294, 0x77D3, 0xB295, 0x77D4, 0xB296, 0x77D5, 0xB297, 0x77D6, 0xB298, 0x77D8, 0xB299, 0x77D9, 0xB29A, 0x77DA, 0xB29B, 0x77DD, 0xB29C, 0x77DE, 0xB29D, 0x77DF, 0xB29E, 0x77E0, 0xB29F, 0x77E1, 0xB2A0, 0x77E4, 0xB2A1, 0x75C5, 0xB2A2, 0x5E76, 0xB2A3, 0x73BB, 0xB2A4, 0x83E0, 0xB2A5, 0x64AD, 0xB2A6, 0x62E8, 0xB2A7, 0x94B5, 0xB2A8, 0x6CE2, 0xB2A9, 0x535A, 0xB2AA, 0x52C3, 0xB2AB, 0x640F, 0xB2AC, 0x94C2, 0xB2AD, 0x7B94, 0xB2AE, 0x4F2F, 0xB2AF, 0x5E1B, 0xB2B0, 0x8236, 0xB2B1, 0x8116, 0xB2B2, 0x818A, 0xB2B3, 0x6E24, 0xB2B4, 0x6CCA, 0xB2B5, 0x9A73, 0xB2B6, 0x6355, 0xB2B7, 0x535C, 0xB2B8, 0x54FA, 0xB2B9, 0x8865, 0xB2BA, 0x57E0, 0xB2BB, 0x4E0D, 0xB2BC, 0x5E03, 0xB2BD, 0x6B65, 0xB2BE, 0x7C3F, 0xB2BF, 0x90E8, 0xB2C0, 0x6016, 0xB2C1, 0x64E6, 0xB2C2, 0x731C, 0xB2C3, 0x88C1, 0xB2C4, 0x6750, 0xB2C5, 0x624D, 0xB2C6, 0x8D22, 0xB2C7, 0x776C, 0xB2C8, 0x8E29, 0xB2C9, 0x91C7, 0xB2CA, 0x5F69, 0xB2CB, 0x83DC, 0xB2CC, 0x8521, 0xB2CD, 0x9910, 0xB2CE, 0x53C2, 0xB2CF, 0x8695, 0xB2D0, 0x6B8B, 0xB2D1, 0x60ED, 0xB2D2, 0x60E8, 0xB2D3, 0x707F, 0xB2D4, 0x82CD, 0xB2D5, 0x8231, 0xB2D6, 0x4ED3, 0xB2D7, 0x6CA7, 0xB2D8, 0x85CF, 0xB2D9, 0x64CD, 0xB2DA, 0x7CD9, 0xB2DB, 0x69FD, 0xB2DC, 0x66F9, 0xB2DD, 0x8349, 0xB2DE, 0x5395, 0xB2DF, 0x7B56, 0xB2E0, 0x4FA7, 0xB2E1, 0x518C, 0xB2E2, 0x6D4B, 0xB2E3, 0x5C42, 0xB2E4, 0x8E6D, 0xB2E5, 0x63D2, 0xB2E6, 0x53C9, 0xB2E7, 0x832C, 0xB2E8, 0x8336, 0xB2E9, 0x67E5, 0xB2EA, 0x78B4, 0xB2EB, 0x643D, 0xB2EC, 0x5BDF, 0xB2ED, 0x5C94, 0xB2EE, 0x5DEE, 0xB2EF, 0x8BE7, 0xB2F0, 0x62C6, 0xB2F1, 0x67F4, 0xB2F2, 0x8C7A, 0xB2F3, 0x6400, 0xB2F4, 0x63BA, 0xB2F5, 0x8749, 0xB2F6, 0x998B, 0xB2F7, 0x8C17, 0xB2F8, 0x7F20, 0xB2F9, 0x94F2, 0xB2FA, 0x4EA7, 0xB2FB, 0x9610, 0xB2FC, 0x98A4, 0xB2FD, 0x660C, 0xB2FE, 0x7316, 0xB340, 0x77E6, 0xB341, 0x77E8, 0xB342, 0x77EA, 0xB343, 0x77EF, 0xB344, 0x77F0, 0xB345, 0x77F1, 0xB346, 0x77F2, 0xB347, 0x77F4, 0xB348, 0x77F5, 0xB349, 0x77F7, 0xB34A, 0x77F9, 0xB34B, 0x77FA, 0xB34C, 0x77FB, 0xB34D, 0x77FC, 0xB34E, 0x7803, 0xB34F, 0x7804, 0xB350, 0x7805, 0xB351, 0x7806, 0xB352, 0x7807, 0xB353, 0x7808, 0xB354, 0x780A, 0xB355, 0x780B, 0xB356, 0x780E, 0xB357, 0x780F, 0xB358, 0x7810, 0xB359, 0x7813, 0xB35A, 0x7815, 0xB35B, 0x7819, 0xB35C, 0x781B, 0xB35D, 0x781E, 0xB35E, 0x7820, 0xB35F, 0x7821, 0xB360, 0x7822, 0xB361, 0x7824, 0xB362, 0x7828, 0xB363, 0x782A, 0xB364, 0x782B, 0xB365, 0x782E, 0xB366, 0x782F, 0xB367, 0x7831, 0xB368, 0x7832, 0xB369, 0x7833, 0xB36A, 0x7835, 0xB36B, 0x7836, 0xB36C, 0x783D, 0xB36D, 0x783F, 0xB36E, 0x7841, 0xB36F, 0x7842, 0xB370, 0x7843, 0xB371, 0x7844, 0xB372, 0x7846, 0xB373, 0x7848, 0xB374, 0x7849, 0xB375, 0x784A, 0xB376, 0x784B, 0xB377, 0x784D, 0xB378, 0x784F, 0xB379, 0x7851, 0xB37A, 0x7853, 0xB37B, 0x7854, 0xB37C, 0x7858, 0xB37D, 0x7859, 0xB37E, 0x785A, 0xB380, 0x785B, 0xB381, 0x785C, 0xB382, 0x785E, 0xB383, 0x785F, 0xB384, 0x7860, 0xB385, 0x7861, 0xB386, 0x7862, 0xB387, 0x7863, 0xB388, 0x7864, 0xB389, 0x7865, 0xB38A, 0x7866, 0xB38B, 0x7867, 0xB38C, 0x7868, 0xB38D, 0x7869, 0xB38E, 0x786F, 0xB38F, 0x7870, 0xB390, 0x7871, 0xB391, 0x7872, 0xB392, 0x7873, 0xB393, 0x7874, 0xB394, 0x7875, 0xB395, 0x7876, 0xB396, 0x7878, 0xB397, 0x7879, 0xB398, 0x787A, 0xB399, 0x787B, 0xB39A, 0x787D, 0xB39B, 0x787E, 0xB39C, 0x787F, 0xB39D, 0x7880, 0xB39E, 0x7881, 0xB39F, 0x7882, 0xB3A0, 0x7883, 0xB3A1, 0x573A, 0xB3A2, 0x5C1D, 0xB3A3, 0x5E38, 0xB3A4, 0x957F, 0xB3A5, 0x507F, 0xB3A6, 0x80A0, 0xB3A7, 0x5382, 0xB3A8, 0x655E, 0xB3A9, 0x7545, 0xB3AA, 0x5531, 0xB3AB, 0x5021, 0xB3AC, 0x8D85, 0xB3AD, 0x6284, 0xB3AE, 0x949E, 0xB3AF, 0x671D, 0xB3B0, 0x5632, 0xB3B1, 0x6F6E, 0xB3B2, 0x5DE2, 0xB3B3, 0x5435, 0xB3B4, 0x7092, 0xB3B5, 0x8F66, 0xB3B6, 0x626F, 0xB3B7, 0x64A4, 0xB3B8, 0x63A3, 0xB3B9, 0x5F7B, 0xB3BA, 0x6F88, 0xB3BB, 0x90F4, 0xB3BC, 0x81E3, 0xB3BD, 0x8FB0, 0xB3BE, 0x5C18, 0xB3BF, 0x6668, 0xB3C0, 0x5FF1, 0xB3C1, 0x6C89, 0xB3C2, 0x9648, 0xB3C3, 0x8D81, 0xB3C4, 0x886C, 0xB3C5, 0x6491, 0xB3C6, 0x79F0, 0xB3C7, 0x57CE, 0xB3C8, 0x6A59, 0xB3C9, 0x6210, 0xB3CA, 0x5448, 0xB3CB, 0x4E58, 0xB3CC, 0x7A0B, 0xB3CD, 0x60E9, 0xB3CE, 0x6F84, 0xB3CF, 0x8BDA, 0xB3D0, 0x627F, 0xB3D1, 0x901E, 0xB3D2, 0x9A8B, 0xB3D3, 0x79E4, 0xB3D4, 0x5403, 0xB3D5, 0x75F4, 0xB3D6, 0x6301, 0xB3D7, 0x5319, 0xB3D8, 0x6C60, 0xB3D9, 0x8FDF, 0xB3DA, 0x5F1B, 0xB3DB, 0x9A70, 0xB3DC, 0x803B, 0xB3DD, 0x9F7F, 0xB3DE, 0x4F88, 0xB3DF, 0x5C3A, 0xB3E0, 0x8D64, 0xB3E1, 0x7FC5, 0xB3E2, 0x65A5, 0xB3E3, 0x70BD, 0xB3E4, 0x5145, 0xB3E5, 0x51B2, 0xB3E6, 0x866B, 0xB3E7, 0x5D07, 0xB3E8, 0x5BA0, 0xB3E9, 0x62BD, 0xB3EA, 0x916C, 0xB3EB, 0x7574, 0xB3EC, 0x8E0C, 0xB3ED, 0x7A20, 0xB3EE, 0x6101, 0xB3EF, 0x7B79, 0xB3F0, 0x4EC7, 0xB3F1, 0x7EF8, 0xB3F2, 0x7785, 0xB3F3, 0x4E11, 0xB3F4, 0x81ED, 0xB3F5, 0x521D, 0xB3F6, 0x51FA, 0xB3F7, 0x6A71, 0xB3F8, 0x53A8, 0xB3F9, 0x8E87, 0xB3FA, 0x9504, 0xB3FB, 0x96CF, 0xB3FC, 0x6EC1, 0xB3FD, 0x9664, 0xB3FE, 0x695A, 0xB440, 0x7884, 0xB441, 0x7885, 0xB442, 0x7886, 0xB443, 0x7888, 0xB444, 0x788A, 0xB445, 0x788B, 0xB446, 0x788F, 0xB447, 0x7890, 0xB448, 0x7892, 0xB449, 0x7894, 0xB44A, 0x7895, 0xB44B, 0x7896, 0xB44C, 0x7899, 0xB44D, 0x789D, 0xB44E, 0x789E, 0xB44F, 0x78A0, 0xB450, 0x78A2, 0xB451, 0x78A4, 0xB452, 0x78A6, 0xB453, 0x78A8, 0xB454, 0x78A9, 0xB455, 0x78AA, 0xB456, 0x78AB, 0xB457, 0x78AC, 0xB458, 0x78AD, 0xB459, 0x78AE, 0xB45A, 0x78AF, 0xB45B, 0x78B5, 0xB45C, 0x78B6, 0xB45D, 0x78B7, 0xB45E, 0x78B8, 0xB45F, 0x78BA, 0xB460, 0x78BB, 0xB461, 0x78BC, 0xB462, 0x78BD, 0xB463, 0x78BF, 0xB464, 0x78C0, 0xB465, 0x78C2, 0xB466, 0x78C3, 0xB467, 0x78C4, 0xB468, 0x78C6, 0xB469, 0x78C7, 0xB46A, 0x78C8, 0xB46B, 0x78CC, 0xB46C, 0x78CD, 0xB46D, 0x78CE, 0xB46E, 0x78CF, 0xB46F, 0x78D1, 0xB470, 0x78D2, 0xB471, 0x78D3, 0xB472, 0x78D6, 0xB473, 0x78D7, 0xB474, 0x78D8, 0xB475, 0x78DA, 0xB476, 0x78DB, 0xB477, 0x78DC, 0xB478, 0x78DD, 0xB479, 0x78DE, 0xB47A, 0x78DF, 0xB47B, 0x78E0, 0xB47C, 0x78E1, 0xB47D, 0x78E2, 0xB47E, 0x78E3, 0xB480, 0x78E4, 0xB481, 0x78E5, 0xB482, 0x78E6, 0xB483, 0x78E7, 0xB484, 0x78E9, 0xB485, 0x78EA, 0xB486, 0x78EB, 0xB487, 0x78ED, 0xB488, 0x78EE, 0xB489, 0x78EF, 0xB48A, 0x78F0, 0xB48B, 0x78F1, 0xB48C, 0x78F3, 0xB48D, 0x78F5, 0xB48E, 0x78F6, 0xB48F, 0x78F8, 0xB490, 0x78F9, 0xB491, 0x78FB, 0xB492, 0x78FC, 0xB493, 0x78FD, 0xB494, 0x78FE, 0xB495, 0x78FF, 0xB496, 0x7900, 0xB497, 0x7902, 0xB498, 0x7903, 0xB499, 0x7904, 0xB49A, 0x7906, 0xB49B, 0x7907, 0xB49C, 0x7908, 0xB49D, 0x7909, 0xB49E, 0x790A, 0xB49F, 0x790B, 0xB4A0, 0x790C, 0xB4A1, 0x7840, 0xB4A2, 0x50A8, 0xB4A3, 0x77D7, 0xB4A4, 0x6410, 0xB4A5, 0x89E6, 0xB4A6, 0x5904, 0xB4A7, 0x63E3, 0xB4A8, 0x5DDD, 0xB4A9, 0x7A7F, 0xB4AA, 0x693D, 0xB4AB, 0x4F20, 0xB4AC, 0x8239, 0xB4AD, 0x5598, 0xB4AE, 0x4E32, 0xB4AF, 0x75AE, 0xB4B0, 0x7A97, 0xB4B1, 0x5E62, 0xB4B2, 0x5E8A, 0xB4B3, 0x95EF, 0xB4B4, 0x521B, 0xB4B5, 0x5439, 0xB4B6, 0x708A, 0xB4B7, 0x6376, 0xB4B8, 0x9524, 0xB4B9, 0x5782, 0xB4BA, 0x6625, 0xB4BB, 0x693F, 0xB4BC, 0x9187, 0xB4BD, 0x5507, 0xB4BE, 0x6DF3, 0xB4BF, 0x7EAF, 0xB4C0, 0x8822, 0xB4C1, 0x6233, 0xB4C2, 0x7EF0, 0xB4C3, 0x75B5, 0xB4C4, 0x8328, 0xB4C5, 0x78C1, 0xB4C6, 0x96CC, 0xB4C7, 0x8F9E, 0xB4C8, 0x6148, 0xB4C9, 0x74F7, 0xB4CA, 0x8BCD, 0xB4CB, 0x6B64, 0xB4CC, 0x523A, 0xB4CD, 0x8D50, 0xB4CE, 0x6B21, 0xB4CF, 0x806A, 0xB4D0, 0x8471, 0xB4D1, 0x56F1, 0xB4D2, 0x5306, 0xB4D3, 0x4ECE, 0xB4D4, 0x4E1B, 0xB4D5, 0x51D1, 0xB4D6, 0x7C97, 0xB4D7, 0x918B, 0xB4D8, 0x7C07, 0xB4D9, 0x4FC3, 0xB4DA, 0x8E7F, 0xB4DB, 0x7BE1, 0xB4DC, 0x7A9C, 0xB4DD, 0x6467, 0xB4DE, 0x5D14, 0xB4DF, 0x50AC, 0xB4E0, 0x8106, 0xB4E1, 0x7601, 0xB4E2, 0x7CB9, 0xB4E3, 0x6DEC, 0xB4E4, 0x7FE0, 0xB4E5, 0x6751, 0xB4E6, 0x5B58, 0xB4E7, 0x5BF8, 0xB4E8, 0x78CB, 0xB4E9, 0x64AE, 0xB4EA, 0x6413, 0xB4EB, 0x63AA, 0xB4EC, 0x632B, 0xB4ED, 0x9519, 0xB4EE, 0x642D, 0xB4EF, 0x8FBE, 0xB4F0, 0x7B54, 0xB4F1, 0x7629, 0xB4F2, 0x6253, 0xB4F3, 0x5927, 0xB4F4, 0x5446, 0xB4F5, 0x6B79, 0xB4F6, 0x50A3, 0xB4F7, 0x6234, 0xB4F8, 0x5E26, 0xB4F9, 0x6B86, 0xB4FA, 0x4EE3, 0xB4FB, 0x8D37, 0xB4FC, 0x888B, 0xB4FD, 0x5F85, 0xB4FE, 0x902E, 0xB540, 0x790D, 0xB541, 0x790E, 0xB542, 0x790F, 0xB543, 0x7910, 0xB544, 0x7911, 0xB545, 0x7912, 0xB546, 0x7914, 0xB547, 0x7915, 0xB548, 0x7916, 0xB549, 0x7917, 0xB54A, 0x7918, 0xB54B, 0x7919, 0xB54C, 0x791A, 0xB54D, 0x791B, 0xB54E, 0x791C, 0xB54F, 0x791D, 0xB550, 0x791F, 0xB551, 0x7920, 0xB552, 0x7921, 0xB553, 0x7922, 0xB554, 0x7923, 0xB555, 0x7925, 0xB556, 0x7926, 0xB557, 0x7927, 0xB558, 0x7928, 0xB559, 0x7929, 0xB55A, 0x792A, 0xB55B, 0x792B, 0xB55C, 0x792C, 0xB55D, 0x792D, 0xB55E, 0x792E, 0xB55F, 0x792F, 0xB560, 0x7930, 0xB561, 0x7931, 0xB562, 0x7932, 0xB563, 0x7933, 0xB564, 0x7935, 0xB565, 0x7936, 0xB566, 0x7937, 0xB567, 0x7938, 0xB568, 0x7939, 0xB569, 0x793D, 0xB56A, 0x793F, 0xB56B, 0x7942, 0xB56C, 0x7943, 0xB56D, 0x7944, 0xB56E, 0x7945, 0xB56F, 0x7947, 0xB570, 0x794A, 0xB571, 0x794B, 0xB572, 0x794C, 0xB573, 0x794D, 0xB574, 0x794E, 0xB575, 0x794F, 0xB576, 0x7950, 0xB577, 0x7951, 0xB578, 0x7952, 0xB579, 0x7954, 0xB57A, 0x7955, 0xB57B, 0x7958, 0xB57C, 0x7959, 0xB57D, 0x7961, 0xB57E, 0x7963, 0xB580, 0x7964, 0xB581, 0x7966, 0xB582, 0x7969, 0xB583, 0x796A, 0xB584, 0x796B, 0xB585, 0x796C, 0xB586, 0x796E, 0xB587, 0x7970, 0xB588, 0x7971, 0xB589, 0x7972, 0xB58A, 0x7973, 0xB58B, 0x7974, 0xB58C, 0x7975, 0xB58D, 0x7976, 0xB58E, 0x7979, 0xB58F, 0x797B, 0xB590, 0x797C, 0xB591, 0x797D, 0xB592, 0x797E, 0xB593, 0x797F, 0xB594, 0x7982, 0xB595, 0x7983, 0xB596, 0x7986, 0xB597, 0x7987, 0xB598, 0x7988, 0xB599, 0x7989, 0xB59A, 0x798B, 0xB59B, 0x798C, 0xB59C, 0x798D, 0xB59D, 0x798E, 0xB59E, 0x7990, 0xB59F, 0x7991, 0xB5A0, 0x7992, 0xB5A1, 0x6020, 0xB5A2, 0x803D, 0xB5A3, 0x62C5, 0xB5A4, 0x4E39, 0xB5A5, 0x5355, 0xB5A6, 0x90F8, 0xB5A7, 0x63B8, 0xB5A8, 0x80C6, 0xB5A9, 0x65E6, 0xB5AA, 0x6C2E, 0xB5AB, 0x4F46, 0xB5AC, 0x60EE, 0xB5AD, 0x6DE1, 0xB5AE, 0x8BDE, 0xB5AF, 0x5F39, 0xB5B0, 0x86CB, 0xB5B1, 0x5F53, 0xB5B2, 0x6321, 0xB5B3, 0x515A, 0xB5B4, 0x8361, 0xB5B5, 0x6863, 0xB5B6, 0x5200, 0xB5B7, 0x6363, 0xB5B8, 0x8E48, 0xB5B9, 0x5012, 0xB5BA, 0x5C9B, 0xB5BB, 0x7977, 0xB5BC, 0x5BFC, 0xB5BD, 0x5230, 0xB5BE, 0x7A3B, 0xB5BF, 0x60BC, 0xB5C0, 0x9053, 0xB5C1, 0x76D7, 0xB5C2, 0x5FB7, 0xB5C3, 0x5F97, 0xB5C4, 0x7684, 0xB5C5, 0x8E6C, 0xB5C6, 0x706F, 0xB5C7, 0x767B, 0xB5C8, 0x7B49, 0xB5C9, 0x77AA, 0xB5CA, 0x51F3, 0xB5CB, 0x9093, 0xB5CC, 0x5824, 0xB5CD, 0x4F4E, 0xB5CE, 0x6EF4, 0xB5CF, 0x8FEA, 0xB5D0, 0x654C, 0xB5D1, 0x7B1B, 0xB5D2, 0x72C4, 0xB5D3, 0x6DA4, 0xB5D4, 0x7FDF, 0xB5D5, 0x5AE1, 0xB5D6, 0x62B5, 0xB5D7, 0x5E95, 0xB5D8, 0x5730, 0xB5D9, 0x8482, 0xB5DA, 0x7B2C, 0xB5DB, 0x5E1D, 0xB5DC, 0x5F1F, 0xB5DD, 0x9012, 0xB5DE, 0x7F14, 0xB5DF, 0x98A0, 0xB5E0, 0x6382, 0xB5E1, 0x6EC7, 0xB5E2, 0x7898, 0xB5E3, 0x70B9, 0xB5E4, 0x5178, 0xB5E5, 0x975B, 0xB5E6, 0x57AB, 0xB5E7, 0x7535, 0xB5E8, 0x4F43, 0xB5E9, 0x7538, 0xB5EA, 0x5E97, 0xB5EB, 0x60E6, 0xB5EC, 0x5960, 0xB5ED, 0x6DC0, 0xB5EE, 0x6BBF, 0xB5EF, 0x7889, 0xB5F0, 0x53FC, 0xB5F1, 0x96D5, 0xB5F2, 0x51CB, 0xB5F3, 0x5201, 0xB5F4, 0x6389, 0xB5F5, 0x540A, 0xB5F6, 0x9493, 0xB5F7, 0x8C03, 0xB5F8, 0x8DCC, 0xB5F9, 0x7239, 0xB5FA, 0x789F, 0xB5FB, 0x8776, 0xB5FC, 0x8FED, 0xB5FD, 0x8C0D, 0xB5FE, 0x53E0, 0xB640, 0x7993, 0xB641, 0x7994, 0xB642, 0x7995, 0xB643, 0x7996, 0xB644, 0x7997, 0xB645, 0x7998, 0xB646, 0x7999, 0xB647, 0x799B, 0xB648, 0x799C, 0xB649, 0x799D, 0xB64A, 0x799E, 0xB64B, 0x799F, 0xB64C, 0x79A0, 0xB64D, 0x79A1, 0xB64E, 0x79A2, 0xB64F, 0x79A3, 0xB650, 0x79A4, 0xB651, 0x79A5, 0xB652, 0x79A6, 0xB653, 0x79A8, 0xB654, 0x79A9, 0xB655, 0x79AA, 0xB656, 0x79AB, 0xB657, 0x79AC, 0xB658, 0x79AD, 0xB659, 0x79AE, 0xB65A, 0x79AF, 0xB65B, 0x79B0, 0xB65C, 0x79B1, 0xB65D, 0x79B2, 0xB65E, 0x79B4, 0xB65F, 0x79B5, 0xB660, 0x79B6, 0xB661, 0x79B7, 0xB662, 0x79B8, 0xB663, 0x79BC, 0xB664, 0x79BF, 0xB665, 0x79C2, 0xB666, 0x79C4, 0xB667, 0x79C5, 0xB668, 0x79C7, 0xB669, 0x79C8, 0xB66A, 0x79CA, 0xB66B, 0x79CC, 0xB66C, 0x79CE, 0xB66D, 0x79CF, 0xB66E, 0x79D0, 0xB66F, 0x79D3, 0xB670, 0x79D4, 0xB671, 0x79D6, 0xB672, 0x79D7, 0xB673, 0x79D9, 0xB674, 0x79DA, 0xB675, 0x79DB, 0xB676, 0x79DC, 0xB677, 0x79DD, 0xB678, 0x79DE, 0xB679, 0x79E0, 0xB67A, 0x79E1, 0xB67B, 0x79E2, 0xB67C, 0x79E5, 0xB67D, 0x79E8, 0xB67E, 0x79EA, 0xB680, 0x79EC, 0xB681, 0x79EE, 0xB682, 0x79F1, 0xB683, 0x79F2, 0xB684, 0x79F3, 0xB685, 0x79F4, 0xB686, 0x79F5, 0xB687, 0x79F6, 0xB688, 0x79F7, 0xB689, 0x79F9, 0xB68A, 0x79FA, 0xB68B, 0x79FC, 0xB68C, 0x79FE, 0xB68D, 0x79FF, 0xB68E, 0x7A01, 0xB68F, 0x7A04, 0xB690, 0x7A05, 0xB691, 0x7A07, 0xB692, 0x7A08, 0xB693, 0x7A09, 0xB694, 0x7A0A, 0xB695, 0x7A0C, 0xB696, 0x7A0F, 0xB697, 0x7A10, 0xB698, 0x7A11, 0xB699, 0x7A12, 0xB69A, 0x7A13, 0xB69B, 0x7A15, 0xB69C, 0x7A16, 0xB69D, 0x7A18, 0xB69E, 0x7A19, 0xB69F, 0x7A1B, 0xB6A0, 0x7A1C, 0xB6A1, 0x4E01, 0xB6A2, 0x76EF, 0xB6A3, 0x53EE, 0xB6A4, 0x9489, 0xB6A5, 0x9876, 0xB6A6, 0x9F0E, 0xB6A7, 0x952D, 0xB6A8, 0x5B9A, 0xB6A9, 0x8BA2, 0xB6AA, 0x4E22, 0xB6AB, 0x4E1C, 0xB6AC, 0x51AC, 0xB6AD, 0x8463, 0xB6AE, 0x61C2, 0xB6AF, 0x52A8, 0xB6B0, 0x680B, 0xB6B1, 0x4F97, 0xB6B2, 0x606B, 0xB6B3, 0x51BB, 0xB6B4, 0x6D1E, 0xB6B5, 0x515C, 0xB6B6, 0x6296, 0xB6B7, 0x6597, 0xB6B8, 0x9661, 0xB6B9, 0x8C46, 0xB6BA, 0x9017, 0xB6BB, 0x75D8, 0xB6BC, 0x90FD, 0xB6BD, 0x7763, 0xB6BE, 0x6BD2, 0xB6BF, 0x728A, 0xB6C0, 0x72EC, 0xB6C1, 0x8BFB, 0xB6C2, 0x5835, 0xB6C3, 0x7779, 0xB6C4, 0x8D4C, 0xB6C5, 0x675C, 0xB6C6, 0x9540, 0xB6C7, 0x809A, 0xB6C8, 0x5EA6, 0xB6C9, 0x6E21, 0xB6CA, 0x5992, 0xB6CB, 0x7AEF, 0xB6CC, 0x77ED, 0xB6CD, 0x953B, 0xB6CE, 0x6BB5, 0xB6CF, 0x65AD, 0xB6D0, 0x7F0E, 0xB6D1, 0x5806, 0xB6D2, 0x5151, 0xB6D3, 0x961F, 0xB6D4, 0x5BF9, 0xB6D5, 0x58A9, 0xB6D6, 0x5428, 0xB6D7, 0x8E72, 0xB6D8, 0x6566, 0xB6D9, 0x987F, 0xB6DA, 0x56E4, 0xB6DB, 0x949D, 0xB6DC, 0x76FE, 0xB6DD, 0x9041, 0xB6DE, 0x6387, 0xB6DF, 0x54C6, 0xB6E0, 0x591A, 0xB6E1, 0x593A, 0xB6E2, 0x579B, 0xB6E3, 0x8EB2, 0xB6E4, 0x6735, 0xB6E5, 0x8DFA, 0xB6E6, 0x8235, 0xB6E7, 0x5241, 0xB6E8, 0x60F0, 0xB6E9, 0x5815, 0xB6EA, 0x86FE, 0xB6EB, 0x5CE8, 0xB6EC, 0x9E45, 0xB6ED, 0x4FC4, 0xB6EE, 0x989D, 0xB6EF, 0x8BB9, 0xB6F0, 0x5A25, 0xB6F1, 0x6076, 0xB6F2, 0x5384, 0xB6F3, 0x627C, 0xB6F4, 0x904F, 0xB6F5, 0x9102, 0xB6F6, 0x997F, 0xB6F7, 0x6069, 0xB6F8, 0x800C, 0xB6F9, 0x513F, 0xB6FA, 0x8033, 0xB6FB, 0x5C14, 0xB6FC, 0x9975, 0xB6FD, 0x6D31, 0xB6FE, 0x4E8C, 0xB740, 0x7A1D, 0xB741, 0x7A1F, 0xB742, 0x7A21, 0xB743, 0x7A22, 0xB744, 0x7A24, 0xB745, 0x7A25, 0xB746, 0x7A26, 0xB747, 0x7A27, 0xB748, 0x7A28, 0xB749, 0x7A29, 0xB74A, 0x7A2A, 0xB74B, 0x7A2B, 0xB74C, 0x7A2C, 0xB74D, 0x7A2D, 0xB74E, 0x7A2E, 0xB74F, 0x7A2F, 0xB750, 0x7A30, 0xB751, 0x7A31, 0xB752, 0x7A32, 0xB753, 0x7A34, 0xB754, 0x7A35, 0xB755, 0x7A36, 0xB756, 0x7A38, 0xB757, 0x7A3A, 0xB758, 0x7A3E, 0xB759, 0x7A40, 0xB75A, 0x7A41, 0xB75B, 0x7A42, 0xB75C, 0x7A43, 0xB75D, 0x7A44, 0xB75E, 0x7A45, 0xB75F, 0x7A47, 0xB760, 0x7A48, 0xB761, 0x7A49, 0xB762, 0x7A4A, 0xB763, 0x7A4B, 0xB764, 0x7A4C, 0xB765, 0x7A4D, 0xB766, 0x7A4E, 0xB767, 0x7A4F, 0xB768, 0x7A50, 0xB769, 0x7A52, 0xB76A, 0x7A53, 0xB76B, 0x7A54, 0xB76C, 0x7A55, 0xB76D, 0x7A56, 0xB76E, 0x7A58, 0xB76F, 0x7A59, 0xB770, 0x7A5A, 0xB771, 0x7A5B, 0xB772, 0x7A5C, 0xB773, 0x7A5D, 0xB774, 0x7A5E, 0xB775, 0x7A5F, 0xB776, 0x7A60, 0xB777, 0x7A61, 0xB778, 0x7A62, 0xB779, 0x7A63, 0xB77A, 0x7A64, 0xB77B, 0x7A65, 0xB77C, 0x7A66, 0xB77D, 0x7A67, 0xB77E, 0x7A68, 0xB780, 0x7A69, 0xB781, 0x7A6A, 0xB782, 0x7A6B, 0xB783, 0x7A6C, 0xB784, 0x7A6D, 0xB785, 0x7A6E, 0xB786, 0x7A6F, 0xB787, 0x7A71, 0xB788, 0x7A72, 0xB789, 0x7A73, 0xB78A, 0x7A75, 0xB78B, 0x7A7B, 0xB78C, 0x7A7C, 0xB78D, 0x7A7D, 0xB78E, 0x7A7E, 0xB78F, 0x7A82, 0xB790, 0x7A85, 0xB791, 0x7A87, 0xB792, 0x7A89, 0xB793, 0x7A8A, 0xB794, 0x7A8B, 0xB795, 0x7A8C, 0xB796, 0x7A8E, 0xB797, 0x7A8F, 0xB798, 0x7A90, 0xB799, 0x7A93, 0xB79A, 0x7A94, 0xB79B, 0x7A99, 0xB79C, 0x7A9A, 0xB79D, 0x7A9B, 0xB79E, 0x7A9E, 0xB79F, 0x7AA1, 0xB7A0, 0x7AA2, 0xB7A1, 0x8D30, 0xB7A2, 0x53D1, 0xB7A3, 0x7F5A, 0xB7A4, 0x7B4F, 0xB7A5, 0x4F10, 0xB7A6, 0x4E4F, 0xB7A7, 0x9600, 0xB7A8, 0x6CD5, 0xB7A9, 0x73D0, 0xB7AA, 0x85E9, 0xB7AB, 0x5E06, 0xB7AC, 0x756A, 0xB7AD, 0x7FFB, 0xB7AE, 0x6A0A, 0xB7AF, 0x77FE, 0xB7B0, 0x9492, 0xB7B1, 0x7E41, 0xB7B2, 0x51E1, 0xB7B3, 0x70E6, 0xB7B4, 0x53CD, 0xB7B5, 0x8FD4, 0xB7B6, 0x8303, 0xB7B7, 0x8D29, 0xB7B8, 0x72AF, 0xB7B9, 0x996D, 0xB7BA, 0x6CDB, 0xB7BB, 0x574A, 0xB7BC, 0x82B3, 0xB7BD, 0x65B9, 0xB7BE, 0x80AA, 0xB7BF, 0x623F, 0xB7C0, 0x9632, 0xB7C1, 0x59A8, 0xB7C2, 0x4EFF, 0xB7C3, 0x8BBF, 0xB7C4, 0x7EBA, 0xB7C5, 0x653E, 0xB7C6, 0x83F2, 0xB7C7, 0x975E, 0xB7C8, 0x5561, 0xB7C9, 0x98DE, 0xB7CA, 0x80A5, 0xB7CB, 0x532A, 0xB7CC, 0x8BFD, 0xB7CD, 0x5420, 0xB7CE, 0x80BA, 0xB7CF, 0x5E9F, 0xB7D0, 0x6CB8, 0xB7D1, 0x8D39, 0xB7D2, 0x82AC, 0xB7D3, 0x915A, 0xB7D4, 0x5429, 0xB7D5, 0x6C1B, 0xB7D6, 0x5206, 0xB7D7, 0x7EB7, 0xB7D8, 0x575F, 0xB7D9, 0x711A, 0xB7DA, 0x6C7E, 0xB7DB, 0x7C89, 0xB7DC, 0x594B, 0xB7DD, 0x4EFD, 0xB7DE, 0x5FFF, 0xB7DF, 0x6124, 0xB7E0, 0x7CAA, 0xB7E1, 0x4E30, 0xB7E2, 0x5C01, 0xB7E3, 0x67AB, 0xB7E4, 0x8702, 0xB7E5, 0x5CF0, 0xB7E6, 0x950B, 0xB7E7, 0x98CE, 0xB7E8, 0x75AF, 0xB7E9, 0x70FD, 0xB7EA, 0x9022, 0xB7EB, 0x51AF, 0xB7EC, 0x7F1D, 0xB7ED, 0x8BBD, 0xB7EE, 0x5949, 0xB7EF, 0x51E4, 0xB7F0, 0x4F5B, 0xB7F1, 0x5426, 0xB7F2, 0x592B, 0xB7F3, 0x6577, 0xB7F4, 0x80A4, 0xB7F5, 0x5B75, 0xB7F6, 0x6276, 0xB7F7, 0x62C2, 0xB7F8, 0x8F90, 0xB7F9, 0x5E45, 0xB7FA, 0x6C1F, 0xB7FB, 0x7B26, 0xB7FC, 0x4F0F, 0xB7FD, 0x4FD8, 0xB7FE, 0x670D, 0xB840, 0x7AA3, 0xB841, 0x7AA4, 0xB842, 0x7AA7, 0xB843, 0x7AA9, 0xB844, 0x7AAA, 0xB845, 0x7AAB, 0xB846, 0x7AAE, 0xB847, 0x7AAF, 0xB848, 0x7AB0, 0xB849, 0x7AB1, 0xB84A, 0x7AB2, 0xB84B, 0x7AB4, 0xB84C, 0x7AB5, 0xB84D, 0x7AB6, 0xB84E, 0x7AB7, 0xB84F, 0x7AB8, 0xB850, 0x7AB9, 0xB851, 0x7ABA, 0xB852, 0x7ABB, 0xB853, 0x7ABC, 0xB854, 0x7ABD, 0xB855, 0x7ABE, 0xB856, 0x7AC0, 0xB857, 0x7AC1, 0xB858, 0x7AC2, 0xB859, 0x7AC3, 0xB85A, 0x7AC4, 0xB85B, 0x7AC5, 0xB85C, 0x7AC6, 0xB85D, 0x7AC7, 0xB85E, 0x7AC8, 0xB85F, 0x7AC9, 0xB860, 0x7ACA, 0xB861, 0x7ACC, 0xB862, 0x7ACD, 0xB863, 0x7ACE, 0xB864, 0x7ACF, 0xB865, 0x7AD0, 0xB866, 0x7AD1, 0xB867, 0x7AD2, 0xB868, 0x7AD3, 0xB869, 0x7AD4, 0xB86A, 0x7AD5, 0xB86B, 0x7AD7, 0xB86C, 0x7AD8, 0xB86D, 0x7ADA, 0xB86E, 0x7ADB, 0xB86F, 0x7ADC, 0xB870, 0x7ADD, 0xB871, 0x7AE1, 0xB872, 0x7AE2, 0xB873, 0x7AE4, 0xB874, 0x7AE7, 0xB875, 0x7AE8, 0xB876, 0x7AE9, 0xB877, 0x7AEA, 0xB878, 0x7AEB, 0xB879, 0x7AEC, 0xB87A, 0x7AEE, 0xB87B, 0x7AF0, 0xB87C, 0x7AF1, 0xB87D, 0x7AF2, 0xB87E, 0x7AF3, 0xB880, 0x7AF4, 0xB881, 0x7AF5, 0xB882, 0x7AF6, 0xB883, 0x7AF7, 0xB884, 0x7AF8, 0xB885, 0x7AFB, 0xB886, 0x7AFC, 0xB887, 0x7AFE, 0xB888, 0x7B00, 0xB889, 0x7B01, 0xB88A, 0x7B02, 0xB88B, 0x7B05, 0xB88C, 0x7B07, 0xB88D, 0x7B09, 0xB88E, 0x7B0C, 0xB88F, 0x7B0D, 0xB890, 0x7B0E, 0xB891, 0x7B10, 0xB892, 0x7B12, 0xB893, 0x7B13, 0xB894, 0x7B16, 0xB895, 0x7B17, 0xB896, 0x7B18, 0xB897, 0x7B1A, 0xB898, 0x7B1C, 0xB899, 0x7B1D, 0xB89A, 0x7B1F, 0xB89B, 0x7B21, 0xB89C, 0x7B22, 0xB89D, 0x7B23, 0xB89E, 0x7B27, 0xB89F, 0x7B29, 0xB8A0, 0x7B2D, 0xB8A1, 0x6D6E, 0xB8A2, 0x6DAA, 0xB8A3, 0x798F, 0xB8A4, 0x88B1, 0xB8A5, 0x5F17, 0xB8A6, 0x752B, 0xB8A7, 0x629A, 0xB8A8, 0x8F85, 0xB8A9, 0x4FEF, 0xB8AA, 0x91DC, 0xB8AB, 0x65A7, 0xB8AC, 0x812F, 0xB8AD, 0x8151, 0xB8AE, 0x5E9C, 0xB8AF, 0x8150, 0xB8B0, 0x8D74, 0xB8B1, 0x526F, 0xB8B2, 0x8986, 0xB8B3, 0x8D4B, 0xB8B4, 0x590D, 0xB8B5, 0x5085, 0xB8B6, 0x4ED8, 0xB8B7, 0x961C, 0xB8B8, 0x7236, 0xB8B9, 0x8179, 0xB8BA, 0x8D1F, 0xB8BB, 0x5BCC, 0xB8BC, 0x8BA3, 0xB8BD, 0x9644, 0xB8BE, 0x5987, 0xB8BF, 0x7F1A, 0xB8C0, 0x5490, 0xB8C1, 0x5676, 0xB8C2, 0x560E, 0xB8C3, 0x8BE5, 0xB8C4, 0x6539, 0xB8C5, 0x6982, 0xB8C6, 0x9499, 0xB8C7, 0x76D6, 0xB8C8, 0x6E89, 0xB8C9, 0x5E72, 0xB8CA, 0x7518, 0xB8CB, 0x6746, 0xB8CC, 0x67D1, 0xB8CD, 0x7AFF, 0xB8CE, 0x809D, 0xB8CF, 0x8D76, 0xB8D0, 0x611F, 0xB8D1, 0x79C6, 0xB8D2, 0x6562, 0xB8D3, 0x8D63, 0xB8D4, 0x5188, 0xB8D5, 0x521A, 0xB8D6, 0x94A2, 0xB8D7, 0x7F38, 0xB8D8, 0x809B, 0xB8D9, 0x7EB2, 0xB8DA, 0x5C97, 0xB8DB, 0x6E2F, 0xB8DC, 0x6760, 0xB8DD, 0x7BD9, 0xB8DE, 0x768B, 0xB8DF, 0x9AD8, 0xB8E0, 0x818F, 0xB8E1, 0x7F94, 0xB8E2, 0x7CD5, 0xB8E3, 0x641E, 0xB8E4, 0x9550, 0xB8E5, 0x7A3F, 0xB8E6, 0x544A, 0xB8E7, 0x54E5, 0xB8E8, 0x6B4C, 0xB8E9, 0x6401, 0xB8EA, 0x6208, 0xB8EB, 0x9E3D, 0xB8EC, 0x80F3, 0xB8ED, 0x7599, 0xB8EE, 0x5272, 0xB8EF, 0x9769, 0xB8F0, 0x845B, 0xB8F1, 0x683C, 0xB8F2, 0x86E4, 0xB8F3, 0x9601, 0xB8F4, 0x9694, 0xB8F5, 0x94EC, 0xB8F6, 0x4E2A, 0xB8F7, 0x5404, 0xB8F8, 0x7ED9, 0xB8F9, 0x6839, 0xB8FA, 0x8DDF, 0xB8FB, 0x8015, 0xB8FC, 0x66F4, 0xB8FD, 0x5E9A, 0xB8FE, 0x7FB9, 0xB940, 0x7B2F, 0xB941, 0x7B30, 0xB942, 0x7B32, 0xB943, 0x7B34, 0xB944, 0x7B35, 0xB945, 0x7B36, 0xB946, 0x7B37, 0xB947, 0x7B39, 0xB948, 0x7B3B, 0xB949, 0x7B3D, 0xB94A, 0x7B3F, 0xB94B, 0x7B40, 0xB94C, 0x7B41, 0xB94D, 0x7B42, 0xB94E, 0x7B43, 0xB94F, 0x7B44, 0xB950, 0x7B46, 0xB951, 0x7B48, 0xB952, 0x7B4A, 0xB953, 0x7B4D, 0xB954, 0x7B4E, 0xB955, 0x7B53, 0xB956, 0x7B55, 0xB957, 0x7B57, 0xB958, 0x7B59, 0xB959, 0x7B5C, 0xB95A, 0x7B5E, 0xB95B, 0x7B5F, 0xB95C, 0x7B61, 0xB95D, 0x7B63, 0xB95E, 0x7B64, 0xB95F, 0x7B65, 0xB960, 0x7B66, 0xB961, 0x7B67, 0xB962, 0x7B68, 0xB963, 0x7B69, 0xB964, 0x7B6A, 0xB965, 0x7B6B, 0xB966, 0x7B6C, 0xB967, 0x7B6D, 0xB968, 0x7B6F, 0xB969, 0x7B70, 0xB96A, 0x7B73, 0xB96B, 0x7B74, 0xB96C, 0x7B76, 0xB96D, 0x7B78, 0xB96E, 0x7B7A, 0xB96F, 0x7B7C, 0xB970, 0x7B7D, 0xB971, 0x7B7F, 0xB972, 0x7B81, 0xB973, 0x7B82, 0xB974, 0x7B83, 0xB975, 0x7B84, 0xB976, 0x7B86, 0xB977, 0x7B87, 0xB978, 0x7B88, 0xB979, 0x7B89, 0xB97A, 0x7B8A, 0xB97B, 0x7B8B, 0xB97C, 0x7B8C, 0xB97D, 0x7B8E, 0xB97E, 0x7B8F, 0xB980, 0x7B91, 0xB981, 0x7B92, 0xB982, 0x7B93, 0xB983, 0x7B96, 0xB984, 0x7B98, 0xB985, 0x7B99, 0xB986, 0x7B9A, 0xB987, 0x7B9B, 0xB988, 0x7B9E, 0xB989, 0x7B9F, 0xB98A, 0x7BA0, 0xB98B, 0x7BA3, 0xB98C, 0x7BA4, 0xB98D, 0x7BA5, 0xB98E, 0x7BAE, 0xB98F, 0x7BAF, 0xB990, 0x7BB0, 0xB991, 0x7BB2, 0xB992, 0x7BB3, 0xB993, 0x7BB5, 0xB994, 0x7BB6, 0xB995, 0x7BB7, 0xB996, 0x7BB9, 0xB997, 0x7BBA, 0xB998, 0x7BBB, 0xB999, 0x7BBC, 0xB99A, 0x7BBD, 0xB99B, 0x7BBE, 0xB99C, 0x7BBF, 0xB99D, 0x7BC0, 0xB99E, 0x7BC2, 0xB99F, 0x7BC3, 0xB9A0, 0x7BC4, 0xB9A1, 0x57C2, 0xB9A2, 0x803F, 0xB9A3, 0x6897, 0xB9A4, 0x5DE5, 0xB9A5, 0x653B, 0xB9A6, 0x529F, 0xB9A7, 0x606D, 0xB9A8, 0x9F9A, 0xB9A9, 0x4F9B, 0xB9AA, 0x8EAC, 0xB9AB, 0x516C, 0xB9AC, 0x5BAB, 0xB9AD, 0x5F13, 0xB9AE, 0x5DE9, 0xB9AF, 0x6C5E, 0xB9B0, 0x62F1, 0xB9B1, 0x8D21, 0xB9B2, 0x5171, 0xB9B3, 0x94A9, 0xB9B4, 0x52FE, 0xB9B5, 0x6C9F, 0xB9B6, 0x82DF, 0xB9B7, 0x72D7, 0xB9B8, 0x57A2, 0xB9B9, 0x6784, 0xB9BA, 0x8D2D, 0xB9BB, 0x591F, 0xB9BC, 0x8F9C, 0xB9BD, 0x83C7, 0xB9BE, 0x5495, 0xB9BF, 0x7B8D, 0xB9C0, 0x4F30, 0xB9C1, 0x6CBD, 0xB9C2, 0x5B64, 0xB9C3, 0x59D1, 0xB9C4, 0x9F13, 0xB9C5, 0x53E4, 0xB9C6, 0x86CA, 0xB9C7, 0x9AA8, 0xB9C8, 0x8C37, 0xB9C9, 0x80A1, 0xB9CA, 0x6545, 0xB9CB, 0x987E, 0xB9CC, 0x56FA, 0xB9CD, 0x96C7, 0xB9CE, 0x522E, 0xB9CF, 0x74DC, 0xB9D0, 0x5250, 0xB9D1, 0x5BE1, 0xB9D2, 0x6302, 0xB9D3, 0x8902, 0xB9D4, 0x4E56, 0xB9D5, 0x62D0, 0xB9D6, 0x602A, 0xB9D7, 0x68FA, 0xB9D8, 0x5173, 0xB9D9, 0x5B98, 0xB9DA, 0x51A0, 0xB9DB, 0x89C2, 0xB9DC, 0x7BA1, 0xB9DD, 0x9986, 0xB9DE, 0x7F50, 0xB9DF, 0x60EF, 0xB9E0, 0x704C, 0xB9E1, 0x8D2F, 0xB9E2, 0x5149, 0xB9E3, 0x5E7F, 0xB9E4, 0x901B, 0xB9E5, 0x7470, 0xB9E6, 0x89C4, 0xB9E7, 0x572D, 0xB9E8, 0x7845, 0xB9E9, 0x5F52, 0xB9EA, 0x9F9F, 0xB9EB, 0x95FA, 0xB9EC, 0x8F68, 0xB9ED, 0x9B3C, 0xB9EE, 0x8BE1, 0xB9EF, 0x7678, 0xB9F0, 0x6842, 0xB9F1, 0x67DC, 0xB9F2, 0x8DEA, 0xB9F3, 0x8D35, 0xB9F4, 0x523D, 0xB9F5, 0x8F8A, 0xB9F6, 0x6EDA, 0xB9F7, 0x68CD, 0xB9F8, 0x9505, 0xB9F9, 0x90ED, 0xB9FA, 0x56FD, 0xB9FB, 0x679C, 0xB9FC, 0x88F9, 0xB9FD, 0x8FC7, 0xB9FE, 0x54C8, 0xBA40, 0x7BC5, 0xBA41, 0x7BC8, 0xBA42, 0x7BC9, 0xBA43, 0x7BCA, 0xBA44, 0x7BCB, 0xBA45, 0x7BCD, 0xBA46, 0x7BCE, 0xBA47, 0x7BCF, 0xBA48, 0x7BD0, 0xBA49, 0x7BD2, 0xBA4A, 0x7BD4, 0xBA4B, 0x7BD5, 0xBA4C, 0x7BD6, 0xBA4D, 0x7BD7, 0xBA4E, 0x7BD8, 0xBA4F, 0x7BDB, 0xBA50, 0x7BDC, 0xBA51, 0x7BDE, 0xBA52, 0x7BDF, 0xBA53, 0x7BE0, 0xBA54, 0x7BE2, 0xBA55, 0x7BE3, 0xBA56, 0x7BE4, 0xBA57, 0x7BE7, 0xBA58, 0x7BE8, 0xBA59, 0x7BE9, 0xBA5A, 0x7BEB, 0xBA5B, 0x7BEC, 0xBA5C, 0x7BED, 0xBA5D, 0x7BEF, 0xBA5E, 0x7BF0, 0xBA5F, 0x7BF2, 0xBA60, 0x7BF3, 0xBA61, 0x7BF4, 0xBA62, 0x7BF5, 0xBA63, 0x7BF6, 0xBA64, 0x7BF8, 0xBA65, 0x7BF9, 0xBA66, 0x7BFA, 0xBA67, 0x7BFB, 0xBA68, 0x7BFD, 0xBA69, 0x7BFF, 0xBA6A, 0x7C00, 0xBA6B, 0x7C01, 0xBA6C, 0x7C02, 0xBA6D, 0x7C03, 0xBA6E, 0x7C04, 0xBA6F, 0x7C05, 0xBA70, 0x7C06, 0xBA71, 0x7C08, 0xBA72, 0x7C09, 0xBA73, 0x7C0A, 0xBA74, 0x7C0D, 0xBA75, 0x7C0E, 0xBA76, 0x7C10, 0xBA77, 0x7C11, 0xBA78, 0x7C12, 0xBA79, 0x7C13, 0xBA7A, 0x7C14, 0xBA7B, 0x7C15, 0xBA7C, 0x7C17, 0xBA7D, 0x7C18, 0xBA7E, 0x7C19, 0xBA80, 0x7C1A, 0xBA81, 0x7C1B, 0xBA82, 0x7C1C, 0xBA83, 0x7C1D, 0xBA84, 0x7C1E, 0xBA85, 0x7C20, 0xBA86, 0x7C21, 0xBA87, 0x7C22, 0xBA88, 0x7C23, 0xBA89, 0x7C24, 0xBA8A, 0x7C25, 0xBA8B, 0x7C28, 0xBA8C, 0x7C29, 0xBA8D, 0x7C2B, 0xBA8E, 0x7C2C, 0xBA8F, 0x7C2D, 0xBA90, 0x7C2E, 0xBA91, 0x7C2F, 0xBA92, 0x7C30, 0xBA93, 0x7C31, 0xBA94, 0x7C32, 0xBA95, 0x7C33, 0xBA96, 0x7C34, 0xBA97, 0x7C35, 0xBA98, 0x7C36, 0xBA99, 0x7C37, 0xBA9A, 0x7C39, 0xBA9B, 0x7C3A, 0xBA9C, 0x7C3B, 0xBA9D, 0x7C3C, 0xBA9E, 0x7C3D, 0xBA9F, 0x7C3E, 0xBAA0, 0x7C42, 0xBAA1, 0x9AB8, 0xBAA2, 0x5B69, 0xBAA3, 0x6D77, 0xBAA4, 0x6C26, 0xBAA5, 0x4EA5, 0xBAA6, 0x5BB3, 0xBAA7, 0x9A87, 0xBAA8, 0x9163, 0xBAA9, 0x61A8, 0xBAAA, 0x90AF, 0xBAAB, 0x97E9, 0xBAAC, 0x542B, 0xBAAD, 0x6DB5, 0xBAAE, 0x5BD2, 0xBAAF, 0x51FD, 0xBAB0, 0x558A, 0xBAB1, 0x7F55, 0xBAB2, 0x7FF0, 0xBAB3, 0x64BC, 0xBAB4, 0x634D, 0xBAB5, 0x65F1, 0xBAB6, 0x61BE, 0xBAB7, 0x608D, 0xBAB8, 0x710A, 0xBAB9, 0x6C57, 0xBABA, 0x6C49, 0xBABB, 0x592F, 0xBABC, 0x676D, 0xBABD, 0x822A, 0xBABE, 0x58D5, 0xBABF, 0x568E, 0xBAC0, 0x8C6A, 0xBAC1, 0x6BEB, 0xBAC2, 0x90DD, 0xBAC3, 0x597D, 0xBAC4, 0x8017, 0xBAC5, 0x53F7, 0xBAC6, 0x6D69, 0xBAC7, 0x5475, 0xBAC8, 0x559D, 0xBAC9, 0x8377, 0xBACA, 0x83CF, 0xBACB, 0x6838, 0xBACC, 0x79BE, 0xBACD, 0x548C, 0xBACE, 0x4F55, 0xBACF, 0x5408, 0xBAD0, 0x76D2, 0xBAD1, 0x8C89, 0xBAD2, 0x9602, 0xBAD3, 0x6CB3, 0xBAD4, 0x6DB8, 0xBAD5, 0x8D6B, 0xBAD6, 0x8910, 0xBAD7, 0x9E64, 0xBAD8, 0x8D3A, 0xBAD9, 0x563F, 0xBADA, 0x9ED1, 0xBADB, 0x75D5, 0xBADC, 0x5F88, 0xBADD, 0x72E0, 0xBADE, 0x6068, 0xBADF, 0x54FC, 0xBAE0, 0x4EA8, 0xBAE1, 0x6A2A, 0xBAE2, 0x8861, 0xBAE3, 0x6052, 0xBAE4, 0x8F70, 0xBAE5, 0x54C4, 0xBAE6, 0x70D8, 0xBAE7, 0x8679, 0xBAE8, 0x9E3F, 0xBAE9, 0x6D2A, 0xBAEA, 0x5B8F, 0xBAEB, 0x5F18, 0xBAEC, 0x7EA2, 0xBAED, 0x5589, 0xBAEE, 0x4FAF, 0xBAEF, 0x7334, 0xBAF0, 0x543C, 0xBAF1, 0x539A, 0xBAF2, 0x5019, 0xBAF3, 0x540E, 0xBAF4, 0x547C, 0xBAF5, 0x4E4E, 0xBAF6, 0x5FFD, 0xBAF7, 0x745A, 0xBAF8, 0x58F6, 0xBAF9, 0x846B, 0xBAFA, 0x80E1, 0xBAFB, 0x8774, 0xBAFC, 0x72D0, 0xBAFD, 0x7CCA, 0xBAFE, 0x6E56, 0xBB40, 0x7C43, 0xBB41, 0x7C44, 0xBB42, 0x7C45, 0xBB43, 0x7C46, 0xBB44, 0x7C47, 0xBB45, 0x7C48, 0xBB46, 0x7C49, 0xBB47, 0x7C4A, 0xBB48, 0x7C4B, 0xBB49, 0x7C4C, 0xBB4A, 0x7C4E, 0xBB4B, 0x7C4F, 0xBB4C, 0x7C50, 0xBB4D, 0x7C51, 0xBB4E, 0x7C52, 0xBB4F, 0x7C53, 0xBB50, 0x7C54, 0xBB51, 0x7C55, 0xBB52, 0x7C56, 0xBB53, 0x7C57, 0xBB54, 0x7C58, 0xBB55, 0x7C59, 0xBB56, 0x7C5A, 0xBB57, 0x7C5B, 0xBB58, 0x7C5C, 0xBB59, 0x7C5D, 0xBB5A, 0x7C5E, 0xBB5B, 0x7C5F, 0xBB5C, 0x7C60, 0xBB5D, 0x7C61, 0xBB5E, 0x7C62, 0xBB5F, 0x7C63, 0xBB60, 0x7C64, 0xBB61, 0x7C65, 0xBB62, 0x7C66, 0xBB63, 0x7C67, 0xBB64, 0x7C68, 0xBB65, 0x7C69, 0xBB66, 0x7C6A, 0xBB67, 0x7C6B, 0xBB68, 0x7C6C, 0xBB69, 0x7C6D, 0xBB6A, 0x7C6E, 0xBB6B, 0x7C6F, 0xBB6C, 0x7C70, 0xBB6D, 0x7C71, 0xBB6E, 0x7C72, 0xBB6F, 0x7C75, 0xBB70, 0x7C76, 0xBB71, 0x7C77, 0xBB72, 0x7C78, 0xBB73, 0x7C79, 0xBB74, 0x7C7A, 0xBB75, 0x7C7E, 0xBB76, 0x7C7F, 0xBB77, 0x7C80, 0xBB78, 0x7C81, 0xBB79, 0x7C82, 0xBB7A, 0x7C83, 0xBB7B, 0x7C84, 0xBB7C, 0x7C85, 0xBB7D, 0x7C86, 0xBB7E, 0x7C87, 0xBB80, 0x7C88, 0xBB81, 0x7C8A, 0xBB82, 0x7C8B, 0xBB83, 0x7C8C, 0xBB84, 0x7C8D, 0xBB85, 0x7C8E, 0xBB86, 0x7C8F, 0xBB87, 0x7C90, 0xBB88, 0x7C93, 0xBB89, 0x7C94, 0xBB8A, 0x7C96, 0xBB8B, 0x7C99, 0xBB8C, 0x7C9A, 0xBB8D, 0x7C9B, 0xBB8E, 0x7CA0, 0xBB8F, 0x7CA1, 0xBB90, 0x7CA3, 0xBB91, 0x7CA6, 0xBB92, 0x7CA7, 0xBB93, 0x7CA8, 0xBB94, 0x7CA9, 0xBB95, 0x7CAB, 0xBB96, 0x7CAC, 0xBB97, 0x7CAD, 0xBB98, 0x7CAF, 0xBB99, 0x7CB0, 0xBB9A, 0x7CB4, 0xBB9B, 0x7CB5, 0xBB9C, 0x7CB6, 0xBB9D, 0x7CB7, 0xBB9E, 0x7CB8, 0xBB9F, 0x7CBA, 0xBBA0, 0x7CBB, 0xBBA1, 0x5F27, 0xBBA2, 0x864E, 0xBBA3, 0x552C, 0xBBA4, 0x62A4, 0xBBA5, 0x4E92, 0xBBA6, 0x6CAA, 0xBBA7, 0x6237, 0xBBA8, 0x82B1, 0xBBA9, 0x54D7, 0xBBAA, 0x534E, 0xBBAB, 0x733E, 0xBBAC, 0x6ED1, 0xBBAD, 0x753B, 0xBBAE, 0x5212, 0xBBAF, 0x5316, 0xBBB0, 0x8BDD, 0xBBB1, 0x69D0, 0xBBB2, 0x5F8A, 0xBBB3, 0x6000, 0xBBB4, 0x6DEE, 0xBBB5, 0x574F, 0xBBB6, 0x6B22, 0xBBB7, 0x73AF, 0xBBB8, 0x6853, 0xBBB9, 0x8FD8, 0xBBBA, 0x7F13, 0xBBBB, 0x6362, 0xBBBC, 0x60A3, 0xBBBD, 0x5524, 0xBBBE, 0x75EA, 0xBBBF, 0x8C62, 0xBBC0, 0x7115, 0xBBC1, 0x6DA3, 0xBBC2, 0x5BA6, 0xBBC3, 0x5E7B, 0xBBC4, 0x8352, 0xBBC5, 0x614C, 0xBBC6, 0x9EC4, 0xBBC7, 0x78FA, 0xBBC8, 0x8757, 0xBBC9, 0x7C27, 0xBBCA, 0x7687, 0xBBCB, 0x51F0, 0xBBCC, 0x60F6, 0xBBCD, 0x714C, 0xBBCE, 0x6643, 0xBBCF, 0x5E4C, 0xBBD0, 0x604D, 0xBBD1, 0x8C0E, 0xBBD2, 0x7070, 0xBBD3, 0x6325, 0xBBD4, 0x8F89, 0xBBD5, 0x5FBD, 0xBBD6, 0x6062, 0xBBD7, 0x86D4, 0xBBD8, 0x56DE, 0xBBD9, 0x6BC1, 0xBBDA, 0x6094, 0xBBDB, 0x6167, 0xBBDC, 0x5349, 0xBBDD, 0x60E0, 0xBBDE, 0x6666, 0xBBDF, 0x8D3F, 0xBBE0, 0x79FD, 0xBBE1, 0x4F1A, 0xBBE2, 0x70E9, 0xBBE3, 0x6C47, 0xBBE4, 0x8BB3, 0xBBE5, 0x8BF2, 0xBBE6, 0x7ED8, 0xBBE7, 0x8364, 0xBBE8, 0x660F, 0xBBE9, 0x5A5A, 0xBBEA, 0x9B42, 0xBBEB, 0x6D51, 0xBBEC, 0x6DF7, 0xBBED, 0x8C41, 0xBBEE, 0x6D3B, 0xBBEF, 0x4F19, 0xBBF0, 0x706B, 0xBBF1, 0x83B7, 0xBBF2, 0x6216, 0xBBF3, 0x60D1, 0xBBF4, 0x970D, 0xBBF5, 0x8D27, 0xBBF6, 0x7978, 0xBBF7, 0x51FB, 0xBBF8, 0x573E, 0xBBF9, 0x57FA, 0xBBFA, 0x673A, 0xBBFB, 0x7578, 0xBBFC, 0x7A3D, 0xBBFD, 0x79EF, 0xBBFE, 0x7B95, 0xBC40, 0x7CBF, 0xBC41, 0x7CC0, 0xBC42, 0x7CC2, 0xBC43, 0x7CC3, 0xBC44, 0x7CC4, 0xBC45, 0x7CC6, 0xBC46, 0x7CC9, 0xBC47, 0x7CCB, 0xBC48, 0x7CCE, 0xBC49, 0x7CCF, 0xBC4A, 0x7CD0, 0xBC4B, 0x7CD1, 0xBC4C, 0x7CD2, 0xBC4D, 0x7CD3, 0xBC4E, 0x7CD4, 0xBC4F, 0x7CD8, 0xBC50, 0x7CDA, 0xBC51, 0x7CDB, 0xBC52, 0x7CDD, 0xBC53, 0x7CDE, 0xBC54, 0x7CE1, 0xBC55, 0x7CE2, 0xBC56, 0x7CE3, 0xBC57, 0x7CE4, 0xBC58, 0x7CE5, 0xBC59, 0x7CE6, 0xBC5A, 0x7CE7, 0xBC5B, 0x7CE9, 0xBC5C, 0x7CEA, 0xBC5D, 0x7CEB, 0xBC5E, 0x7CEC, 0xBC5F, 0x7CED, 0xBC60, 0x7CEE, 0xBC61, 0x7CF0, 0xBC62, 0x7CF1, 0xBC63, 0x7CF2, 0xBC64, 0x7CF3, 0xBC65, 0x7CF4, 0xBC66, 0x7CF5, 0xBC67, 0x7CF6, 0xBC68, 0x7CF7, 0xBC69, 0x7CF9, 0xBC6A, 0x7CFA, 0xBC6B, 0x7CFC, 0xBC6C, 0x7CFD, 0xBC6D, 0x7CFE, 0xBC6E, 0x7CFF, 0xBC6F, 0x7D00, 0xBC70, 0x7D01, 0xBC71, 0x7D02, 0xBC72, 0x7D03, 0xBC73, 0x7D04, 0xBC74, 0x7D05, 0xBC75, 0x7D06, 0xBC76, 0x7D07, 0xBC77, 0x7D08, 0xBC78, 0x7D09, 0xBC79, 0x7D0B, 0xBC7A, 0x7D0C, 0xBC7B, 0x7D0D, 0xBC7C, 0x7D0E, 0xBC7D, 0x7D0F, 0xBC7E, 0x7D10, 0xBC80, 0x7D11, 0xBC81, 0x7D12, 0xBC82, 0x7D13, 0xBC83, 0x7D14, 0xBC84, 0x7D15, 0xBC85, 0x7D16, 0xBC86, 0x7D17, 0xBC87, 0x7D18, 0xBC88, 0x7D19, 0xBC89, 0x7D1A, 0xBC8A, 0x7D1B, 0xBC8B, 0x7D1C, 0xBC8C, 0x7D1D, 0xBC8D, 0x7D1E, 0xBC8E, 0x7D1F, 0xBC8F, 0x7D21, 0xBC90, 0x7D23, 0xBC91, 0x7D24, 0xBC92, 0x7D25, 0xBC93, 0x7D26, 0xBC94, 0x7D28, 0xBC95, 0x7D29, 0xBC96, 0x7D2A, 0xBC97, 0x7D2C, 0xBC98, 0x7D2D, 0xBC99, 0x7D2E, 0xBC9A, 0x7D30, 0xBC9B, 0x7D31, 0xBC9C, 0x7D32, 0xBC9D, 0x7D33, 0xBC9E, 0x7D34, 0xBC9F, 0x7D35, 0xBCA0, 0x7D36, 0xBCA1, 0x808C, 0xBCA2, 0x9965, 0xBCA3, 0x8FF9, 0xBCA4, 0x6FC0, 0xBCA5, 0x8BA5, 0xBCA6, 0x9E21, 0xBCA7, 0x59EC, 0xBCA8, 0x7EE9, 0xBCA9, 0x7F09, 0xBCAA, 0x5409, 0xBCAB, 0x6781, 0xBCAC, 0x68D8, 0xBCAD, 0x8F91, 0xBCAE, 0x7C4D, 0xBCAF, 0x96C6, 0xBCB0, 0x53CA, 0xBCB1, 0x6025, 0xBCB2, 0x75BE, 0xBCB3, 0x6C72, 0xBCB4, 0x5373, 0xBCB5, 0x5AC9, 0xBCB6, 0x7EA7, 0xBCB7, 0x6324, 0xBCB8, 0x51E0, 0xBCB9, 0x810A, 0xBCBA, 0x5DF1, 0xBCBB, 0x84DF, 0xBCBC, 0x6280, 0xBCBD, 0x5180, 0xBCBE, 0x5B63, 0xBCBF, 0x4F0E, 0xBCC0, 0x796D, 0xBCC1, 0x5242, 0xBCC2, 0x60B8, 0xBCC3, 0x6D4E, 0xBCC4, 0x5BC4, 0xBCC5, 0x5BC2, 0xBCC6, 0x8BA1, 0xBCC7, 0x8BB0, 0xBCC8, 0x65E2, 0xBCC9, 0x5FCC, 0xBCCA, 0x9645, 0xBCCB, 0x5993, 0xBCCC, 0x7EE7, 0xBCCD, 0x7EAA, 0xBCCE, 0x5609, 0xBCCF, 0x67B7, 0xBCD0, 0x5939, 0xBCD1, 0x4F73, 0xBCD2, 0x5BB6, 0xBCD3, 0x52A0, 0xBCD4, 0x835A, 0xBCD5, 0x988A, 0xBCD6, 0x8D3E, 0xBCD7, 0x7532, 0xBCD8, 0x94BE, 0xBCD9, 0x5047, 0xBCDA, 0x7A3C, 0xBCDB, 0x4EF7, 0xBCDC, 0x67B6, 0xBCDD, 0x9A7E, 0xBCDE, 0x5AC1, 0xBCDF, 0x6B7C, 0xBCE0, 0x76D1, 0xBCE1, 0x575A, 0xBCE2, 0x5C16, 0xBCE3, 0x7B3A, 0xBCE4, 0x95F4, 0xBCE5, 0x714E, 0xBCE6, 0x517C, 0xBCE7, 0x80A9, 0xBCE8, 0x8270, 0xBCE9, 0x5978, 0xBCEA, 0x7F04, 0xBCEB, 0x8327, 0xBCEC, 0x68C0, 0xBCED, 0x67EC, 0xBCEE, 0x78B1, 0xBCEF, 0x7877, 0xBCF0, 0x62E3, 0xBCF1, 0x6361, 0xBCF2, 0x7B80, 0xBCF3, 0x4FED, 0xBCF4, 0x526A, 0xBCF5, 0x51CF, 0xBCF6, 0x8350, 0xBCF7, 0x69DB, 0xBCF8, 0x9274, 0xBCF9, 0x8DF5, 0xBCFA, 0x8D31, 0xBCFB, 0x89C1, 0xBCFC, 0x952E, 0xBCFD, 0x7BAD, 0xBCFE, 0x4EF6, 0xBD40, 0x7D37, 0xBD41, 0x7D38, 0xBD42, 0x7D39, 0xBD43, 0x7D3A, 0xBD44, 0x7D3B, 0xBD45, 0x7D3C, 0xBD46, 0x7D3D, 0xBD47, 0x7D3E, 0xBD48, 0x7D3F, 0xBD49, 0x7D40, 0xBD4A, 0x7D41, 0xBD4B, 0x7D42, 0xBD4C, 0x7D43, 0xBD4D, 0x7D44, 0xBD4E, 0x7D45, 0xBD4F, 0x7D46, 0xBD50, 0x7D47, 0xBD51, 0x7D48, 0xBD52, 0x7D49, 0xBD53, 0x7D4A, 0xBD54, 0x7D4B, 0xBD55, 0x7D4C, 0xBD56, 0x7D4D, 0xBD57, 0x7D4E, 0xBD58, 0x7D4F, 0xBD59, 0x7D50, 0xBD5A, 0x7D51, 0xBD5B, 0x7D52, 0xBD5C, 0x7D53, 0xBD5D, 0x7D54, 0xBD5E, 0x7D55, 0xBD5F, 0x7D56, 0xBD60, 0x7D57, 0xBD61, 0x7D58, 0xBD62, 0x7D59, 0xBD63, 0x7D5A, 0xBD64, 0x7D5B, 0xBD65, 0x7D5C, 0xBD66, 0x7D5D, 0xBD67, 0x7D5E, 0xBD68, 0x7D5F, 0xBD69, 0x7D60, 0xBD6A, 0x7D61, 0xBD6B, 0x7D62, 0xBD6C, 0x7D63, 0xBD6D, 0x7D64, 0xBD6E, 0x7D65, 0xBD6F, 0x7D66, 0xBD70, 0x7D67, 0xBD71, 0x7D68, 0xBD72, 0x7D69, 0xBD73, 0x7D6A, 0xBD74, 0x7D6B, 0xBD75, 0x7D6C, 0xBD76, 0x7D6D, 0xBD77, 0x7D6F, 0xBD78, 0x7D70, 0xBD79, 0x7D71, 0xBD7A, 0x7D72, 0xBD7B, 0x7D73, 0xBD7C, 0x7D74, 0xBD7D, 0x7D75, 0xBD7E, 0x7D76, 0xBD80, 0x7D78, 0xBD81, 0x7D79, 0xBD82, 0x7D7A, 0xBD83, 0x7D7B, 0xBD84, 0x7D7C, 0xBD85, 0x7D7D, 0xBD86, 0x7D7E, 0xBD87, 0x7D7F, 0xBD88, 0x7D80, 0xBD89, 0x7D81, 0xBD8A, 0x7D82, 0xBD8B, 0x7D83, 0xBD8C, 0x7D84, 0xBD8D, 0x7D85, 0xBD8E, 0x7D86, 0xBD8F, 0x7D87, 0xBD90, 0x7D88, 0xBD91, 0x7D89, 0xBD92, 0x7D8A, 0xBD93, 0x7D8B, 0xBD94, 0x7D8C, 0xBD95, 0x7D8D, 0xBD96, 0x7D8E, 0xBD97, 0x7D8F, 0xBD98, 0x7D90, 0xBD99, 0x7D91, 0xBD9A, 0x7D92, 0xBD9B, 0x7D93, 0xBD9C, 0x7D94, 0xBD9D, 0x7D95, 0xBD9E, 0x7D96, 0xBD9F, 0x7D97, 0xBDA0, 0x7D98, 0xBDA1, 0x5065, 0xBDA2, 0x8230, 0xBDA3, 0x5251, 0xBDA4, 0x996F, 0xBDA5, 0x6E10, 0xBDA6, 0x6E85, 0xBDA7, 0x6DA7, 0xBDA8, 0x5EFA, 0xBDA9, 0x50F5, 0xBDAA, 0x59DC, 0xBDAB, 0x5C06, 0xBDAC, 0x6D46, 0xBDAD, 0x6C5F, 0xBDAE, 0x7586, 0xBDAF, 0x848B, 0xBDB0, 0x6868, 0xBDB1, 0x5956, 0xBDB2, 0x8BB2, 0xBDB3, 0x5320, 0xBDB4, 0x9171, 0xBDB5, 0x964D, 0xBDB6, 0x8549, 0xBDB7, 0x6912, 0xBDB8, 0x7901, 0xBDB9, 0x7126, 0xBDBA, 0x80F6, 0xBDBB, 0x4EA4, 0xBDBC, 0x90CA, 0xBDBD, 0x6D47, 0xBDBE, 0x9A84, 0xBDBF, 0x5A07, 0xBDC0, 0x56BC, 0xBDC1, 0x6405, 0xBDC2, 0x94F0, 0xBDC3, 0x77EB, 0xBDC4, 0x4FA5, 0xBDC5, 0x811A, 0xBDC6, 0x72E1, 0xBDC7, 0x89D2, 0xBDC8, 0x997A, 0xBDC9, 0x7F34, 0xBDCA, 0x7EDE, 0xBDCB, 0x527F, 0xBDCC, 0x6559, 0xBDCD, 0x9175, 0xBDCE, 0x8F7F, 0xBDCF, 0x8F83, 0xBDD0, 0x53EB, 0xBDD1, 0x7A96, 0xBDD2, 0x63ED, 0xBDD3, 0x63A5, 0xBDD4, 0x7686, 0xBDD5, 0x79F8, 0xBDD6, 0x8857, 0xBDD7, 0x9636, 0xBDD8, 0x622A, 0xBDD9, 0x52AB, 0xBDDA, 0x8282, 0xBDDB, 0x6854, 0xBDDC, 0x6770, 0xBDDD, 0x6377, 0xBDDE, 0x776B, 0xBDDF, 0x7AED, 0xBDE0, 0x6D01, 0xBDE1, 0x7ED3, 0xBDE2, 0x89E3, 0xBDE3, 0x59D0, 0xBDE4, 0x6212, 0xBDE5, 0x85C9, 0xBDE6, 0x82A5, 0xBDE7, 0x754C, 0xBDE8, 0x501F, 0xBDE9, 0x4ECB, 0xBDEA, 0x75A5, 0xBDEB, 0x8BEB, 0xBDEC, 0x5C4A, 0xBDED, 0x5DFE, 0xBDEE, 0x7B4B, 0xBDEF, 0x65A4, 0xBDF0, 0x91D1, 0xBDF1, 0x4ECA, 0xBDF2, 0x6D25, 0xBDF3, 0x895F, 0xBDF4, 0x7D27, 0xBDF5, 0x9526, 0xBDF6, 0x4EC5, 0xBDF7, 0x8C28, 0xBDF8, 0x8FDB, 0xBDF9, 0x9773, 0xBDFA, 0x664B, 0xBDFB, 0x7981, 0xBDFC, 0x8FD1, 0xBDFD, 0x70EC, 0xBDFE, 0x6D78, 0xBE40, 0x7D99, 0xBE41, 0x7D9A, 0xBE42, 0x7D9B, 0xBE43, 0x7D9C, 0xBE44, 0x7D9D, 0xBE45, 0x7D9E, 0xBE46, 0x7D9F, 0xBE47, 0x7DA0, 0xBE48, 0x7DA1, 0xBE49, 0x7DA2, 0xBE4A, 0x7DA3, 0xBE4B, 0x7DA4, 0xBE4C, 0x7DA5, 0xBE4D, 0x7DA7, 0xBE4E, 0x7DA8, 0xBE4F, 0x7DA9, 0xBE50, 0x7DAA, 0xBE51, 0x7DAB, 0xBE52, 0x7DAC, 0xBE53, 0x7DAD, 0xBE54, 0x7DAF, 0xBE55, 0x7DB0, 0xBE56, 0x7DB1, 0xBE57, 0x7DB2, 0xBE58, 0x7DB3, 0xBE59, 0x7DB4, 0xBE5A, 0x7DB5, 0xBE5B, 0x7DB6, 0xBE5C, 0x7DB7, 0xBE5D, 0x7DB8, 0xBE5E, 0x7DB9, 0xBE5F, 0x7DBA, 0xBE60, 0x7DBB, 0xBE61, 0x7DBC, 0xBE62, 0x7DBD, 0xBE63, 0x7DBE, 0xBE64, 0x7DBF, 0xBE65, 0x7DC0, 0xBE66, 0x7DC1, 0xBE67, 0x7DC2, 0xBE68, 0x7DC3, 0xBE69, 0x7DC4, 0xBE6A, 0x7DC5, 0xBE6B, 0x7DC6, 0xBE6C, 0x7DC7, 0xBE6D, 0x7DC8, 0xBE6E, 0x7DC9, 0xBE6F, 0x7DCA, 0xBE70, 0x7DCB, 0xBE71, 0x7DCC, 0xBE72, 0x7DCD, 0xBE73, 0x7DCE, 0xBE74, 0x7DCF, 0xBE75, 0x7DD0, 0xBE76, 0x7DD1, 0xBE77, 0x7DD2, 0xBE78, 0x7DD3, 0xBE79, 0x7DD4, 0xBE7A, 0x7DD5, 0xBE7B, 0x7DD6, 0xBE7C, 0x7DD7, 0xBE7D, 0x7DD8, 0xBE7E, 0x7DD9, 0xBE80, 0x7DDA, 0xBE81, 0x7DDB, 0xBE82, 0x7DDC, 0xBE83, 0x7DDD, 0xBE84, 0x7DDE, 0xBE85, 0x7DDF, 0xBE86, 0x7DE0, 0xBE87, 0x7DE1, 0xBE88, 0x7DE2, 0xBE89, 0x7DE3, 0xBE8A, 0x7DE4, 0xBE8B, 0x7DE5, 0xBE8C, 0x7DE6, 0xBE8D, 0x7DE7, 0xBE8E, 0x7DE8, 0xBE8F, 0x7DE9, 0xBE90, 0x7DEA, 0xBE91, 0x7DEB, 0xBE92, 0x7DEC, 0xBE93, 0x7DED, 0xBE94, 0x7DEE, 0xBE95, 0x7DEF, 0xBE96, 0x7DF0, 0xBE97, 0x7DF1, 0xBE98, 0x7DF2, 0xBE99, 0x7DF3, 0xBE9A, 0x7DF4, 0xBE9B, 0x7DF5, 0xBE9C, 0x7DF6, 0xBE9D, 0x7DF7, 0xBE9E, 0x7DF8, 0xBE9F, 0x7DF9, 0xBEA0, 0x7DFA, 0xBEA1, 0x5C3D, 0xBEA2, 0x52B2, 0xBEA3, 0x8346, 0xBEA4, 0x5162, 0xBEA5, 0x830E, 0xBEA6, 0x775B, 0xBEA7, 0x6676, 0xBEA8, 0x9CB8, 0xBEA9, 0x4EAC, 0xBEAA, 0x60CA, 0xBEAB, 0x7CBE, 0xBEAC, 0x7CB3, 0xBEAD, 0x7ECF, 0xBEAE, 0x4E95, 0xBEAF, 0x8B66, 0xBEB0, 0x666F, 0xBEB1, 0x9888, 0xBEB2, 0x9759, 0xBEB3, 0x5883, 0xBEB4, 0x656C, 0xBEB5, 0x955C, 0xBEB6, 0x5F84, 0xBEB7, 0x75C9, 0xBEB8, 0x9756, 0xBEB9, 0x7ADF, 0xBEBA, 0x7ADE, 0xBEBB, 0x51C0, 0xBEBC, 0x70AF, 0xBEBD, 0x7A98, 0xBEBE, 0x63EA, 0xBEBF, 0x7A76, 0xBEC0, 0x7EA0, 0xBEC1, 0x7396, 0xBEC2, 0x97ED, 0xBEC3, 0x4E45, 0xBEC4, 0x7078, 0xBEC5, 0x4E5D, 0xBEC6, 0x9152, 0xBEC7, 0x53A9, 0xBEC8, 0x6551, 0xBEC9, 0x65E7, 0xBECA, 0x81FC, 0xBECB, 0x8205, 0xBECC, 0x548E, 0xBECD, 0x5C31, 0xBECE, 0x759A, 0xBECF, 0x97A0, 0xBED0, 0x62D8, 0xBED1, 0x72D9, 0xBED2, 0x75BD, 0xBED3, 0x5C45, 0xBED4, 0x9A79, 0xBED5, 0x83CA, 0xBED6, 0x5C40, 0xBED7, 0x5480, 0xBED8, 0x77E9, 0xBED9, 0x4E3E, 0xBEDA, 0x6CAE, 0xBEDB, 0x805A, 0xBEDC, 0x62D2, 0xBEDD, 0x636E, 0xBEDE, 0x5DE8, 0xBEDF, 0x5177, 0xBEE0, 0x8DDD, 0xBEE1, 0x8E1E, 0xBEE2, 0x952F, 0xBEE3, 0x4FF1, 0xBEE4, 0x53E5, 0xBEE5, 0x60E7, 0xBEE6, 0x70AC, 0xBEE7, 0x5267, 0xBEE8, 0x6350, 0xBEE9, 0x9E43, 0xBEEA, 0x5A1F, 0xBEEB, 0x5026, 0xBEEC, 0x7737, 0xBEED, 0x5377, 0xBEEE, 0x7EE2, 0xBEEF, 0x6485, 0xBEF0, 0x652B, 0xBEF1, 0x6289, 0xBEF2, 0x6398, 0xBEF3, 0x5014, 0xBEF4, 0x7235, 0xBEF5, 0x89C9, 0xBEF6, 0x51B3, 0xBEF7, 0x8BC0, 0xBEF8, 0x7EDD, 0xBEF9, 0x5747, 0xBEFA, 0x83CC, 0xBEFB, 0x94A7, 0xBEFC, 0x519B, 0xBEFD, 0x541B, 0xBEFE, 0x5CFB, 0xBF40, 0x7DFB, 0xBF41, 0x7DFC, 0xBF42, 0x7DFD, 0xBF43, 0x7DFE, 0xBF44, 0x7DFF, 0xBF45, 0x7E00, 0xBF46, 0x7E01, 0xBF47, 0x7E02, 0xBF48, 0x7E03, 0xBF49, 0x7E04, 0xBF4A, 0x7E05, 0xBF4B, 0x7E06, 0xBF4C, 0x7E07, 0xBF4D, 0x7E08, 0xBF4E, 0x7E09, 0xBF4F, 0x7E0A, 0xBF50, 0x7E0B, 0xBF51, 0x7E0C, 0xBF52, 0x7E0D, 0xBF53, 0x7E0E, 0xBF54, 0x7E0F, 0xBF55, 0x7E10, 0xBF56, 0x7E11, 0xBF57, 0x7E12, 0xBF58, 0x7E13, 0xBF59, 0x7E14, 0xBF5A, 0x7E15, 0xBF5B, 0x7E16, 0xBF5C, 0x7E17, 0xBF5D, 0x7E18, 0xBF5E, 0x7E19, 0xBF5F, 0x7E1A, 0xBF60, 0x7E1B, 0xBF61, 0x7E1C, 0xBF62, 0x7E1D, 0xBF63, 0x7E1E, 0xBF64, 0x7E1F, 0xBF65, 0x7E20, 0xBF66, 0x7E21, 0xBF67, 0x7E22, 0xBF68, 0x7E23, 0xBF69, 0x7E24, 0xBF6A, 0x7E25, 0xBF6B, 0x7E26, 0xBF6C, 0x7E27, 0xBF6D, 0x7E28, 0xBF6E, 0x7E29, 0xBF6F, 0x7E2A, 0xBF70, 0x7E2B, 0xBF71, 0x7E2C, 0xBF72, 0x7E2D, 0xBF73, 0x7E2E, 0xBF74, 0x7E2F, 0xBF75, 0x7E30, 0xBF76, 0x7E31, 0xBF77, 0x7E32, 0xBF78, 0x7E33, 0xBF79, 0x7E34, 0xBF7A, 0x7E35, 0xBF7B, 0x7E36, 0xBF7C, 0x7E37, 0xBF7D, 0x7E38, 0xBF7E, 0x7E39, 0xBF80, 0x7E3A, 0xBF81, 0x7E3C, 0xBF82, 0x7E3D, 0xBF83, 0x7E3E, 0xBF84, 0x7E3F, 0xBF85, 0x7E40, 0xBF86, 0x7E42, 0xBF87, 0x7E43, 0xBF88, 0x7E44, 0xBF89, 0x7E45, 0xBF8A, 0x7E46, 0xBF8B, 0x7E48, 0xBF8C, 0x7E49, 0xBF8D, 0x7E4A, 0xBF8E, 0x7E4B, 0xBF8F, 0x7E4C, 0xBF90, 0x7E4D, 0xBF91, 0x7E4E, 0xBF92, 0x7E4F, 0xBF93, 0x7E50, 0xBF94, 0x7E51, 0xBF95, 0x7E52, 0xBF96, 0x7E53, 0xBF97, 0x7E54, 0xBF98, 0x7E55, 0xBF99, 0x7E56, 0xBF9A, 0x7E57, 0xBF9B, 0x7E58, 0xBF9C, 0x7E59, 0xBF9D, 0x7E5A, 0xBF9E, 0x7E5B, 0xBF9F, 0x7E5C, 0xBFA0, 0x7E5D, 0xBFA1, 0x4FCA, 0xBFA2, 0x7AE3, 0xBFA3, 0x6D5A, 0xBFA4, 0x90E1, 0xBFA5, 0x9A8F, 0xBFA6, 0x5580, 0xBFA7, 0x5496, 0xBFA8, 0x5361, 0xBFA9, 0x54AF, 0xBFAA, 0x5F00, 0xBFAB, 0x63E9, 0xBFAC, 0x6977, 0xBFAD, 0x51EF, 0xBFAE, 0x6168, 0xBFAF, 0x520A, 0xBFB0, 0x582A, 0xBFB1, 0x52D8, 0xBFB2, 0x574E, 0xBFB3, 0x780D, 0xBFB4, 0x770B, 0xBFB5, 0x5EB7, 0xBFB6, 0x6177, 0xBFB7, 0x7CE0, 0xBFB8, 0x625B, 0xBFB9, 0x6297, 0xBFBA, 0x4EA2, 0xBFBB, 0x7095, 0xBFBC, 0x8003, 0xBFBD, 0x62F7, 0xBFBE, 0x70E4, 0xBFBF, 0x9760, 0xBFC0, 0x5777, 0xBFC1, 0x82DB, 0xBFC2, 0x67EF, 0xBFC3, 0x68F5, 0xBFC4, 0x78D5, 0xBFC5, 0x9897, 0xBFC6, 0x79D1, 0xBFC7, 0x58F3, 0xBFC8, 0x54B3, 0xBFC9, 0x53EF, 0xBFCA, 0x6E34, 0xBFCB, 0x514B, 0xBFCC, 0x523B, 0xBFCD, 0x5BA2, 0xBFCE, 0x8BFE, 0xBFCF, 0x80AF, 0xBFD0, 0x5543, 0xBFD1, 0x57A6, 0xBFD2, 0x6073, 0xBFD3, 0x5751, 0xBFD4, 0x542D, 0xBFD5, 0x7A7A, 0xBFD6, 0x6050, 0xBFD7, 0x5B54, 0xBFD8, 0x63A7, 0xBFD9, 0x62A0, 0xBFDA, 0x53E3, 0xBFDB, 0x6263, 0xBFDC, 0x5BC7, 0xBFDD, 0x67AF, 0xBFDE, 0x54ED, 0xBFDF, 0x7A9F, 0xBFE0, 0x82E6, 0xBFE1, 0x9177, 0xBFE2, 0x5E93, 0xBFE3, 0x88E4, 0xBFE4, 0x5938, 0xBFE5, 0x57AE, 0xBFE6, 0x630E, 0xBFE7, 0x8DE8, 0xBFE8, 0x80EF, 0xBFE9, 0x5757, 0xBFEA, 0x7B77, 0xBFEB, 0x4FA9, 0xBFEC, 0x5FEB, 0xBFED, 0x5BBD, 0xBFEE, 0x6B3E, 0xBFEF, 0x5321, 0xBFF0, 0x7B50, 0xBFF1, 0x72C2, 0xBFF2, 0x6846, 0xBFF3, 0x77FF, 0xBFF4, 0x7736, 0xBFF5, 0x65F7, 0xBFF6, 0x51B5, 0xBFF7, 0x4E8F, 0xBFF8, 0x76D4, 0xBFF9, 0x5CBF, 0xBFFA, 0x7AA5, 0xBFFB, 0x8475, 0xBFFC, 0x594E, 0xBFFD, 0x9B41, 0xBFFE, 0x5080, 0xC040, 0x7E5E, 0xC041, 0x7E5F, 0xC042, 0x7E60, 0xC043, 0x7E61, 0xC044, 0x7E62, 0xC045, 0x7E63, 0xC046, 0x7E64, 0xC047, 0x7E65, 0xC048, 0x7E66, 0xC049, 0x7E67, 0xC04A, 0x7E68, 0xC04B, 0x7E69, 0xC04C, 0x7E6A, 0xC04D, 0x7E6B, 0xC04E, 0x7E6C, 0xC04F, 0x7E6D, 0xC050, 0x7E6E, 0xC051, 0x7E6F, 0xC052, 0x7E70, 0xC053, 0x7E71, 0xC054, 0x7E72, 0xC055, 0x7E73, 0xC056, 0x7E74, 0xC057, 0x7E75, 0xC058, 0x7E76, 0xC059, 0x7E77, 0xC05A, 0x7E78, 0xC05B, 0x7E79, 0xC05C, 0x7E7A, 0xC05D, 0x7E7B, 0xC05E, 0x7E7C, 0xC05F, 0x7E7D, 0xC060, 0x7E7E, 0xC061, 0x7E7F, 0xC062, 0x7E80, 0xC063, 0x7E81, 0xC064, 0x7E83, 0xC065, 0x7E84, 0xC066, 0x7E85, 0xC067, 0x7E86, 0xC068, 0x7E87, 0xC069, 0x7E88, 0xC06A, 0x7E89, 0xC06B, 0x7E8A, 0xC06C, 0x7E8B, 0xC06D, 0x7E8C, 0xC06E, 0x7E8D, 0xC06F, 0x7E8E, 0xC070, 0x7E8F, 0xC071, 0x7E90, 0xC072, 0x7E91, 0xC073, 0x7E92, 0xC074, 0x7E93, 0xC075, 0x7E94, 0xC076, 0x7E95, 0xC077, 0x7E96, 0xC078, 0x7E97, 0xC079, 0x7E98, 0xC07A, 0x7E99, 0xC07B, 0x7E9A, 0xC07C, 0x7E9C, 0xC07D, 0x7E9D, 0xC07E, 0x7E9E, 0xC080, 0x7EAE, 0xC081, 0x7EB4, 0xC082, 0x7EBB, 0xC083, 0x7EBC, 0xC084, 0x7ED6, 0xC085, 0x7EE4, 0xC086, 0x7EEC, 0xC087, 0x7EF9, 0xC088, 0x7F0A, 0xC089, 0x7F10, 0xC08A, 0x7F1E, 0xC08B, 0x7F37, 0xC08C, 0x7F39, 0xC08D, 0x7F3B, 0xC08E, 0x7F3C, 0xC08F, 0x7F3D, 0xC090, 0x7F3E, 0xC091, 0x7F3F, 0xC092, 0x7F40, 0xC093, 0x7F41, 0xC094, 0x7F43, 0xC095, 0x7F46, 0xC096, 0x7F47, 0xC097, 0x7F48, 0xC098, 0x7F49, 0xC099, 0x7F4A, 0xC09A, 0x7F4B, 0xC09B, 0x7F4C, 0xC09C, 0x7F4D, 0xC09D, 0x7F4E, 0xC09E, 0x7F4F, 0xC09F, 0x7F52, 0xC0A0, 0x7F53, 0xC0A1, 0x9988, 0xC0A2, 0x6127, 0xC0A3, 0x6E83, 0xC0A4, 0x5764, 0xC0A5, 0x6606, 0xC0A6, 0x6346, 0xC0A7, 0x56F0, 0xC0A8, 0x62EC, 0xC0A9, 0x6269, 0xC0AA, 0x5ED3, 0xC0AB, 0x9614, 0xC0AC, 0x5783, 0xC0AD, 0x62C9, 0xC0AE, 0x5587, 0xC0AF, 0x8721, 0xC0B0, 0x814A, 0xC0B1, 0x8FA3, 0xC0B2, 0x5566, 0xC0B3, 0x83B1, 0xC0B4, 0x6765, 0xC0B5, 0x8D56, 0xC0B6, 0x84DD, 0xC0B7, 0x5A6A, 0xC0B8, 0x680F, 0xC0B9, 0x62E6, 0xC0BA, 0x7BEE, 0xC0BB, 0x9611, 0xC0BC, 0x5170, 0xC0BD, 0x6F9C, 0xC0BE, 0x8C30, 0xC0BF, 0x63FD, 0xC0C0, 0x89C8, 0xC0C1, 0x61D2, 0xC0C2, 0x7F06, 0xC0C3, 0x70C2, 0xC0C4, 0x6EE5, 0xC0C5, 0x7405, 0xC0C6, 0x6994, 0xC0C7, 0x72FC, 0xC0C8, 0x5ECA, 0xC0C9, 0x90CE, 0xC0CA, 0x6717, 0xC0CB, 0x6D6A, 0xC0CC, 0x635E, 0xC0CD, 0x52B3, 0xC0CE, 0x7262, 0xC0CF, 0x8001, 0xC0D0, 0x4F6C, 0xC0D1, 0x59E5, 0xC0D2, 0x916A, 0xC0D3, 0x70D9, 0xC0D4, 0x6D9D, 0xC0D5, 0x52D2, 0xC0D6, 0x4E50, 0xC0D7, 0x96F7, 0xC0D8, 0x956D, 0xC0D9, 0x857E, 0xC0DA, 0x78CA, 0xC0DB, 0x7D2F, 0xC0DC, 0x5121, 0xC0DD, 0x5792, 0xC0DE, 0x64C2, 0xC0DF, 0x808B, 0xC0E0, 0x7C7B, 0xC0E1, 0x6CEA, 0xC0E2, 0x68F1, 0xC0E3, 0x695E, 0xC0E4, 0x51B7, 0xC0E5, 0x5398, 0xC0E6, 0x68A8, 0xC0E7, 0x7281, 0xC0E8, 0x9ECE, 0xC0E9, 0x7BF1, 0xC0EA, 0x72F8, 0xC0EB, 0x79BB, 0xC0EC, 0x6F13, 0xC0ED, 0x7406, 0xC0EE, 0x674E, 0xC0EF, 0x91CC, 0xC0F0, 0x9CA4, 0xC0F1, 0x793C, 0xC0F2, 0x8389, 0xC0F3, 0x8354, 0xC0F4, 0x540F, 0xC0F5, 0x6817, 0xC0F6, 0x4E3D, 0xC0F7, 0x5389, 0xC0F8, 0x52B1, 0xC0F9, 0x783E, 0xC0FA, 0x5386, 0xC0FB, 0x5229, 0xC0FC, 0x5088, 0xC0FD, 0x4F8B, 0xC0FE, 0x4FD0, 0xC140, 0x7F56, 0xC141, 0x7F59, 0xC142, 0x7F5B, 0xC143, 0x7F5C, 0xC144, 0x7F5D, 0xC145, 0x7F5E, 0xC146, 0x7F60, 0xC147, 0x7F63, 0xC148, 0x7F64, 0xC149, 0x7F65, 0xC14A, 0x7F66, 0xC14B, 0x7F67, 0xC14C, 0x7F6B, 0xC14D, 0x7F6C, 0xC14E, 0x7F6D, 0xC14F, 0x7F6F, 0xC150, 0x7F70, 0xC151, 0x7F73, 0xC152, 0x7F75, 0xC153, 0x7F76, 0xC154, 0x7F77, 0xC155, 0x7F78, 0xC156, 0x7F7A, 0xC157, 0x7F7B, 0xC158, 0x7F7C, 0xC159, 0x7F7D, 0xC15A, 0x7F7F, 0xC15B, 0x7F80, 0xC15C, 0x7F82, 0xC15D, 0x7F83, 0xC15E, 0x7F84, 0xC15F, 0x7F85, 0xC160, 0x7F86, 0xC161, 0x7F87, 0xC162, 0x7F88, 0xC163, 0x7F89, 0xC164, 0x7F8B, 0xC165, 0x7F8D, 0xC166, 0x7F8F, 0xC167, 0x7F90, 0xC168, 0x7F91, 0xC169, 0x7F92, 0xC16A, 0x7F93, 0xC16B, 0x7F95, 0xC16C, 0x7F96, 0xC16D, 0x7F97, 0xC16E, 0x7F98, 0xC16F, 0x7F99, 0xC170, 0x7F9B, 0xC171, 0x7F9C, 0xC172, 0x7FA0, 0xC173, 0x7FA2, 0xC174, 0x7FA3, 0xC175, 0x7FA5, 0xC176, 0x7FA6, 0xC177, 0x7FA8, 0xC178, 0x7FA9, 0xC179, 0x7FAA, 0xC17A, 0x7FAB, 0xC17B, 0x7FAC, 0xC17C, 0x7FAD, 0xC17D, 0x7FAE, 0xC17E, 0x7FB1, 0xC180, 0x7FB3, 0xC181, 0x7FB4, 0xC182, 0x7FB5, 0xC183, 0x7FB6, 0xC184, 0x7FB7, 0xC185, 0x7FBA, 0xC186, 0x7FBB, 0xC187, 0x7FBE, 0xC188, 0x7FC0, 0xC189, 0x7FC2, 0xC18A, 0x7FC3, 0xC18B, 0x7FC4, 0xC18C, 0x7FC6, 0xC18D, 0x7FC7, 0xC18E, 0x7FC8, 0xC18F, 0x7FC9, 0xC190, 0x7FCB, 0xC191, 0x7FCD, 0xC192, 0x7FCF, 0xC193, 0x7FD0, 0xC194, 0x7FD1, 0xC195, 0x7FD2, 0xC196, 0x7FD3, 0xC197, 0x7FD6, 0xC198, 0x7FD7, 0xC199, 0x7FD9, 0xC19A, 0x7FDA, 0xC19B, 0x7FDB, 0xC19C, 0x7FDC, 0xC19D, 0x7FDD, 0xC19E, 0x7FDE, 0xC19F, 0x7FE2, 0xC1A0, 0x7FE3, 0xC1A1, 0x75E2, 0xC1A2, 0x7ACB, 0xC1A3, 0x7C92, 0xC1A4, 0x6CA5, 0xC1A5, 0x96B6, 0xC1A6, 0x529B, 0xC1A7, 0x7483, 0xC1A8, 0x54E9, 0xC1A9, 0x4FE9, 0xC1AA, 0x8054, 0xC1AB, 0x83B2, 0xC1AC, 0x8FDE, 0xC1AD, 0x9570, 0xC1AE, 0x5EC9, 0xC1AF, 0x601C, 0xC1B0, 0x6D9F, 0xC1B1, 0x5E18, 0xC1B2, 0x655B, 0xC1B3, 0x8138, 0xC1B4, 0x94FE, 0xC1B5, 0x604B, 0xC1B6, 0x70BC, 0xC1B7, 0x7EC3, 0xC1B8, 0x7CAE, 0xC1B9, 0x51C9, 0xC1BA, 0x6881, 0xC1BB, 0x7CB1, 0xC1BC, 0x826F, 0xC1BD, 0x4E24, 0xC1BE, 0x8F86, 0xC1BF, 0x91CF, 0xC1C0, 0x667E, 0xC1C1, 0x4EAE, 0xC1C2, 0x8C05, 0xC1C3, 0x64A9, 0xC1C4, 0x804A, 0xC1C5, 0x50DA, 0xC1C6, 0x7597, 0xC1C7, 0x71CE, 0xC1C8, 0x5BE5, 0xC1C9, 0x8FBD, 0xC1CA, 0x6F66, 0xC1CB, 0x4E86, 0xC1CC, 0x6482, 0xC1CD, 0x9563, 0xC1CE, 0x5ED6, 0xC1CF, 0x6599, 0xC1D0, 0x5217, 0xC1D1, 0x88C2, 0xC1D2, 0x70C8, 0xC1D3, 0x52A3, 0xC1D4, 0x730E, 0xC1D5, 0x7433, 0xC1D6, 0x6797, 0xC1D7, 0x78F7, 0xC1D8, 0x9716, 0xC1D9, 0x4E34, 0xC1DA, 0x90BB, 0xC1DB, 0x9CDE, 0xC1DC, 0x6DCB, 0xC1DD, 0x51DB, 0xC1DE, 0x8D41, 0xC1DF, 0x541D, 0xC1E0, 0x62CE, 0xC1E1, 0x73B2, 0xC1E2, 0x83F1, 0xC1E3, 0x96F6, 0xC1E4, 0x9F84, 0xC1E5, 0x94C3, 0xC1E6, 0x4F36, 0xC1E7, 0x7F9A, 0xC1E8, 0x51CC, 0xC1E9, 0x7075, 0xC1EA, 0x9675, 0xC1EB, 0x5CAD, 0xC1EC, 0x9886, 0xC1ED, 0x53E6, 0xC1EE, 0x4EE4, 0xC1EF, 0x6E9C, 0xC1F0, 0x7409, 0xC1F1, 0x69B4, 0xC1F2, 0x786B, 0xC1F3, 0x998F, 0xC1F4, 0x7559, 0xC1F5, 0x5218, 0xC1F6, 0x7624, 0xC1F7, 0x6D41, 0xC1F8, 0x67F3, 0xC1F9, 0x516D, 0xC1FA, 0x9F99, 0xC1FB, 0x804B, 0xC1FC, 0x5499, 0xC1FD, 0x7B3C, 0xC1FE, 0x7ABF, 0xC240, 0x7FE4, 0xC241, 0x7FE7, 0xC242, 0x7FE8, 0xC243, 0x7FEA, 0xC244, 0x7FEB, 0xC245, 0x7FEC, 0xC246, 0x7FED, 0xC247, 0x7FEF, 0xC248, 0x7FF2, 0xC249, 0x7FF4, 0xC24A, 0x7FF5, 0xC24B, 0x7FF6, 0xC24C, 0x7FF7, 0xC24D, 0x7FF8, 0xC24E, 0x7FF9, 0xC24F, 0x7FFA, 0xC250, 0x7FFD, 0xC251, 0x7FFE, 0xC252, 0x7FFF, 0xC253, 0x8002, 0xC254, 0x8007, 0xC255, 0x8008, 0xC256, 0x8009, 0xC257, 0x800A, 0xC258, 0x800E, 0xC259, 0x800F, 0xC25A, 0x8011, 0xC25B, 0x8013, 0xC25C, 0x801A, 0xC25D, 0x801B, 0xC25E, 0x801D, 0xC25F, 0x801E, 0xC260, 0x801F, 0xC261, 0x8021, 0xC262, 0x8023, 0xC263, 0x8024, 0xC264, 0x802B, 0xC265, 0x802C, 0xC266, 0x802D, 0xC267, 0x802E, 0xC268, 0x802F, 0xC269, 0x8030, 0xC26A, 0x8032, 0xC26B, 0x8034, 0xC26C, 0x8039, 0xC26D, 0x803A, 0xC26E, 0x803C, 0xC26F, 0x803E, 0xC270, 0x8040, 0xC271, 0x8041, 0xC272, 0x8044, 0xC273, 0x8045, 0xC274, 0x8047, 0xC275, 0x8048, 0xC276, 0x8049, 0xC277, 0x804E, 0xC278, 0x804F, 0xC279, 0x8050, 0xC27A, 0x8051, 0xC27B, 0x8053, 0xC27C, 0x8055, 0xC27D, 0x8056, 0xC27E, 0x8057, 0xC280, 0x8059, 0xC281, 0x805B, 0xC282, 0x805C, 0xC283, 0x805D, 0xC284, 0x805E, 0xC285, 0x805F, 0xC286, 0x8060, 0xC287, 0x8061, 0xC288, 0x8062, 0xC289, 0x8063, 0xC28A, 0x8064, 0xC28B, 0x8065, 0xC28C, 0x8066, 0xC28D, 0x8067, 0xC28E, 0x8068, 0xC28F, 0x806B, 0xC290, 0x806C, 0xC291, 0x806D, 0xC292, 0x806E, 0xC293, 0x806F, 0xC294, 0x8070, 0xC295, 0x8072, 0xC296, 0x8073, 0xC297, 0x8074, 0xC298, 0x8075, 0xC299, 0x8076, 0xC29A, 0x8077, 0xC29B, 0x8078, 0xC29C, 0x8079, 0xC29D, 0x807A, 0xC29E, 0x807B, 0xC29F, 0x807C, 0xC2A0, 0x807D, 0xC2A1, 0x9686, 0xC2A2, 0x5784, 0xC2A3, 0x62E2, 0xC2A4, 0x9647, 0xC2A5, 0x697C, 0xC2A6, 0x5A04, 0xC2A7, 0x6402, 0xC2A8, 0x7BD3, 0xC2A9, 0x6F0F, 0xC2AA, 0x964B, 0xC2AB, 0x82A6, 0xC2AC, 0x5362, 0xC2AD, 0x9885, 0xC2AE, 0x5E90, 0xC2AF, 0x7089, 0xC2B0, 0x63B3, 0xC2B1, 0x5364, 0xC2B2, 0x864F, 0xC2B3, 0x9C81, 0xC2B4, 0x9E93, 0xC2B5, 0x788C, 0xC2B6, 0x9732, 0xC2B7, 0x8DEF, 0xC2B8, 0x8D42, 0xC2B9, 0x9E7F, 0xC2BA, 0x6F5E, 0xC2BB, 0x7984, 0xC2BC, 0x5F55, 0xC2BD, 0x9646, 0xC2BE, 0x622E, 0xC2BF, 0x9A74, 0xC2C0, 0x5415, 0xC2C1, 0x94DD, 0xC2C2, 0x4FA3, 0xC2C3, 0x65C5, 0xC2C4, 0x5C65, 0xC2C5, 0x5C61, 0xC2C6, 0x7F15, 0xC2C7, 0x8651, 0xC2C8, 0x6C2F, 0xC2C9, 0x5F8B, 0xC2CA, 0x7387, 0xC2CB, 0x6EE4, 0xC2CC, 0x7EFF, 0xC2CD, 0x5CE6, 0xC2CE, 0x631B, 0xC2CF, 0x5B6A, 0xC2D0, 0x6EE6, 0xC2D1, 0x5375, 0xC2D2, 0x4E71, 0xC2D3, 0x63A0, 0xC2D4, 0x7565, 0xC2D5, 0x62A1, 0xC2D6, 0x8F6E, 0xC2D7, 0x4F26, 0xC2D8, 0x4ED1, 0xC2D9, 0x6CA6, 0xC2DA, 0x7EB6, 0xC2DB, 0x8BBA, 0xC2DC, 0x841D, 0xC2DD, 0x87BA, 0xC2DE, 0x7F57, 0xC2DF, 0x903B, 0xC2E0, 0x9523, 0xC2E1, 0x7BA9, 0xC2E2, 0x9AA1, 0xC2E3, 0x88F8, 0xC2E4, 0x843D, 0xC2E5, 0x6D1B, 0xC2E6, 0x9A86, 0xC2E7, 0x7EDC, 0xC2E8, 0x5988, 0xC2E9, 0x9EBB, 0xC2EA, 0x739B, 0xC2EB, 0x7801, 0xC2EC, 0x8682, 0xC2ED, 0x9A6C, 0xC2EE, 0x9A82, 0xC2EF, 0x561B, 0xC2F0, 0x5417, 0xC2F1, 0x57CB, 0xC2F2, 0x4E70, 0xC2F3, 0x9EA6, 0xC2F4, 0x5356, 0xC2F5, 0x8FC8, 0xC2F6, 0x8109, 0xC2F7, 0x7792, 0xC2F8, 0x9992, 0xC2F9, 0x86EE, 0xC2FA, 0x6EE1, 0xC2FB, 0x8513, 0xC2FC, 0x66FC, 0xC2FD, 0x6162, 0xC2FE, 0x6F2B, 0xC340, 0x807E, 0xC341, 0x8081, 0xC342, 0x8082, 0xC343, 0x8085, 0xC344, 0x8088, 0xC345, 0x808A, 0xC346, 0x808D, 0xC347, 0x808E, 0xC348, 0x808F, 0xC349, 0x8090, 0xC34A, 0x8091, 0xC34B, 0x8092, 0xC34C, 0x8094, 0xC34D, 0x8095, 0xC34E, 0x8097, 0xC34F, 0x8099, 0xC350, 0x809E, 0xC351, 0x80A3, 0xC352, 0x80A6, 0xC353, 0x80A7, 0xC354, 0x80A8, 0xC355, 0x80AC, 0xC356, 0x80B0, 0xC357, 0x80B3, 0xC358, 0x80B5, 0xC359, 0x80B6, 0xC35A, 0x80B8, 0xC35B, 0x80B9, 0xC35C, 0x80BB, 0xC35D, 0x80C5, 0xC35E, 0x80C7, 0xC35F, 0x80C8, 0xC360, 0x80C9, 0xC361, 0x80CA, 0xC362, 0x80CB, 0xC363, 0x80CF, 0xC364, 0x80D0, 0xC365, 0x80D1, 0xC366, 0x80D2, 0xC367, 0x80D3, 0xC368, 0x80D4, 0xC369, 0x80D5, 0xC36A, 0x80D8, 0xC36B, 0x80DF, 0xC36C, 0x80E0, 0xC36D, 0x80E2, 0xC36E, 0x80E3, 0xC36F, 0x80E6, 0xC370, 0x80EE, 0xC371, 0x80F5, 0xC372, 0x80F7, 0xC373, 0x80F9, 0xC374, 0x80FB, 0xC375, 0x80FE, 0xC376, 0x80FF, 0xC377, 0x8100, 0xC378, 0x8101, 0xC379, 0x8103, 0xC37A, 0x8104, 0xC37B, 0x8105, 0xC37C, 0x8107, 0xC37D, 0x8108, 0xC37E, 0x810B, 0xC380, 0x810C, 0xC381, 0x8115, 0xC382, 0x8117, 0xC383, 0x8119, 0xC384, 0x811B, 0xC385, 0x811C, 0xC386, 0x811D, 0xC387, 0x811F, 0xC388, 0x8120, 0xC389, 0x8121, 0xC38A, 0x8122, 0xC38B, 0x8123, 0xC38C, 0x8124, 0xC38D, 0x8125, 0xC38E, 0x8126, 0xC38F, 0x8127, 0xC390, 0x8128, 0xC391, 0x8129, 0xC392, 0x812A, 0xC393, 0x812B, 0xC394, 0x812D, 0xC395, 0x812E, 0xC396, 0x8130, 0xC397, 0x8133, 0xC398, 0x8134, 0xC399, 0x8135, 0xC39A, 0x8137, 0xC39B, 0x8139, 0xC39C, 0x813A, 0xC39D, 0x813B, 0xC39E, 0x813C, 0xC39F, 0x813D, 0xC3A0, 0x813F, 0xC3A1, 0x8C29, 0xC3A2, 0x8292, 0xC3A3, 0x832B, 0xC3A4, 0x76F2, 0xC3A5, 0x6C13, 0xC3A6, 0x5FD9, 0xC3A7, 0x83BD, 0xC3A8, 0x732B, 0xC3A9, 0x8305, 0xC3AA, 0x951A, 0xC3AB, 0x6BDB, 0xC3AC, 0x77DB, 0xC3AD, 0x94C6, 0xC3AE, 0x536F, 0xC3AF, 0x8302, 0xC3B0, 0x5192, 0xC3B1, 0x5E3D, 0xC3B2, 0x8C8C, 0xC3B3, 0x8D38, 0xC3B4, 0x4E48, 0xC3B5, 0x73AB, 0xC3B6, 0x679A, 0xC3B7, 0x6885, 0xC3B8, 0x9176, 0xC3B9, 0x9709, 0xC3BA, 0x7164, 0xC3BB, 0x6CA1, 0xC3BC, 0x7709, 0xC3BD, 0x5A92, 0xC3BE, 0x9541, 0xC3BF, 0x6BCF, 0xC3C0, 0x7F8E, 0xC3C1, 0x6627, 0xC3C2, 0x5BD0, 0xC3C3, 0x59B9, 0xC3C4, 0x5A9A, 0xC3C5, 0x95E8, 0xC3C6, 0x95F7, 0xC3C7, 0x4EEC, 0xC3C8, 0x840C, 0xC3C9, 0x8499, 0xC3CA, 0x6AAC, 0xC3CB, 0x76DF, 0xC3CC, 0x9530, 0xC3CD, 0x731B, 0xC3CE, 0x68A6, 0xC3CF, 0x5B5F, 0xC3D0, 0x772F, 0xC3D1, 0x919A, 0xC3D2, 0x9761, 0xC3D3, 0x7CDC, 0xC3D4, 0x8FF7, 0xC3D5, 0x8C1C, 0xC3D6, 0x5F25, 0xC3D7, 0x7C73, 0xC3D8, 0x79D8, 0xC3D9, 0x89C5, 0xC3DA, 0x6CCC, 0xC3DB, 0x871C, 0xC3DC, 0x5BC6, 0xC3DD, 0x5E42, 0xC3DE, 0x68C9, 0xC3DF, 0x7720, 0xC3E0, 0x7EF5, 0xC3E1, 0x5195, 0xC3E2, 0x514D, 0xC3E3, 0x52C9, 0xC3E4, 0x5A29, 0xC3E5, 0x7F05, 0xC3E6, 0x9762, 0xC3E7, 0x82D7, 0xC3E8, 0x63CF, 0xC3E9, 0x7784, 0xC3EA, 0x85D0, 0xC3EB, 0x79D2, 0xC3EC, 0x6E3A, 0xC3ED, 0x5E99, 0xC3EE, 0x5999, 0xC3EF, 0x8511, 0xC3F0, 0x706D, 0xC3F1, 0x6C11, 0xC3F2, 0x62BF, 0xC3F3, 0x76BF, 0xC3F4, 0x654F, 0xC3F5, 0x60AF, 0xC3F6, 0x95FD, 0xC3F7, 0x660E, 0xC3F8, 0x879F, 0xC3F9, 0x9E23, 0xC3FA, 0x94ED, 0xC3FB, 0x540D, 0xC3FC, 0x547D, 0xC3FD, 0x8C2C, 0xC3FE, 0x6478, 0xC440, 0x8140, 0xC441, 0x8141, 0xC442, 0x8142, 0xC443, 0x8143, 0xC444, 0x8144, 0xC445, 0x8145, 0xC446, 0x8147, 0xC447, 0x8149, 0xC448, 0x814D, 0xC449, 0x814E, 0xC44A, 0x814F, 0xC44B, 0x8152, 0xC44C, 0x8156, 0xC44D, 0x8157, 0xC44E, 0x8158, 0xC44F, 0x815B, 0xC450, 0x815C, 0xC451, 0x815D, 0xC452, 0x815E, 0xC453, 0x815F, 0xC454, 0x8161, 0xC455, 0x8162, 0xC456, 0x8163, 0xC457, 0x8164, 0xC458, 0x8166, 0xC459, 0x8168, 0xC45A, 0x816A, 0xC45B, 0x816B, 0xC45C, 0x816C, 0xC45D, 0x816F, 0xC45E, 0x8172, 0xC45F, 0x8173, 0xC460, 0x8175, 0xC461, 0x8176, 0xC462, 0x8177, 0xC463, 0x8178, 0xC464, 0x8181, 0xC465, 0x8183, 0xC466, 0x8184, 0xC467, 0x8185, 0xC468, 0x8186, 0xC469, 0x8187, 0xC46A, 0x8189, 0xC46B, 0x818B, 0xC46C, 0x818C, 0xC46D, 0x818D, 0xC46E, 0x818E, 0xC46F, 0x8190, 0xC470, 0x8192, 0xC471, 0x8193, 0xC472, 0x8194, 0xC473, 0x8195, 0xC474, 0x8196, 0xC475, 0x8197, 0xC476, 0x8199, 0xC477, 0x819A, 0xC478, 0x819E, 0xC479, 0x819F, 0xC47A, 0x81A0, 0xC47B, 0x81A1, 0xC47C, 0x81A2, 0xC47D, 0x81A4, 0xC47E, 0x81A5, 0xC480, 0x81A7, 0xC481, 0x81A9, 0xC482, 0x81AB, 0xC483, 0x81AC, 0xC484, 0x81AD, 0xC485, 0x81AE, 0xC486, 0x81AF, 0xC487, 0x81B0, 0xC488, 0x81B1, 0xC489, 0x81B2, 0xC48A, 0x81B4, 0xC48B, 0x81B5, 0xC48C, 0x81B6, 0xC48D, 0x81B7, 0xC48E, 0x81B8, 0xC48F, 0x81B9, 0xC490, 0x81BC, 0xC491, 0x81BD, 0xC492, 0x81BE, 0xC493, 0x81BF, 0xC494, 0x81C4, 0xC495, 0x81C5, 0xC496, 0x81C7, 0xC497, 0x81C8, 0xC498, 0x81C9, 0xC499, 0x81CB, 0xC49A, 0x81CD, 0xC49B, 0x81CE, 0xC49C, 0x81CF, 0xC49D, 0x81D0, 0xC49E, 0x81D1, 0xC49F, 0x81D2, 0xC4A0, 0x81D3, 0xC4A1, 0x6479, 0xC4A2, 0x8611, 0xC4A3, 0x6A21, 0xC4A4, 0x819C, 0xC4A5, 0x78E8, 0xC4A6, 0x6469, 0xC4A7, 0x9B54, 0xC4A8, 0x62B9, 0xC4A9, 0x672B, 0xC4AA, 0x83AB, 0xC4AB, 0x58A8, 0xC4AC, 0x9ED8, 0xC4AD, 0x6CAB, 0xC4AE, 0x6F20, 0xC4AF, 0x5BDE, 0xC4B0, 0x964C, 0xC4B1, 0x8C0B, 0xC4B2, 0x725F, 0xC4B3, 0x67D0, 0xC4B4, 0x62C7, 0xC4B5, 0x7261, 0xC4B6, 0x4EA9, 0xC4B7, 0x59C6, 0xC4B8, 0x6BCD, 0xC4B9, 0x5893, 0xC4BA, 0x66AE, 0xC4BB, 0x5E55, 0xC4BC, 0x52DF, 0xC4BD, 0x6155, 0xC4BE, 0x6728, 0xC4BF, 0x76EE, 0xC4C0, 0x7766, 0xC4C1, 0x7267, 0xC4C2, 0x7A46, 0xC4C3, 0x62FF, 0xC4C4, 0x54EA, 0xC4C5, 0x5450, 0xC4C6, 0x94A0, 0xC4C7, 0x90A3, 0xC4C8, 0x5A1C, 0xC4C9, 0x7EB3, 0xC4CA, 0x6C16, 0xC4CB, 0x4E43, 0xC4CC, 0x5976, 0xC4CD, 0x8010, 0xC4CE, 0x5948, 0xC4CF, 0x5357, 0xC4D0, 0x7537, 0xC4D1, 0x96BE, 0xC4D2, 0x56CA, 0xC4D3, 0x6320, 0xC4D4, 0x8111, 0xC4D5, 0x607C, 0xC4D6, 0x95F9, 0xC4D7, 0x6DD6, 0xC4D8, 0x5462, 0xC4D9, 0x9981, 0xC4DA, 0x5185, 0xC4DB, 0x5AE9, 0xC4DC, 0x80FD, 0xC4DD, 0x59AE, 0xC4DE, 0x9713, 0xC4DF, 0x502A, 0xC4E0, 0x6CE5, 0xC4E1, 0x5C3C, 0xC4E2, 0x62DF, 0xC4E3, 0x4F60, 0xC4E4, 0x533F, 0xC4E5, 0x817B, 0xC4E6, 0x9006, 0xC4E7, 0x6EBA, 0xC4E8, 0x852B, 0xC4E9, 0x62C8, 0xC4EA, 0x5E74, 0xC4EB, 0x78BE, 0xC4EC, 0x64B5, 0xC4ED, 0x637B, 0xC4EE, 0x5FF5, 0xC4EF, 0x5A18, 0xC4F0, 0x917F, 0xC4F1, 0x9E1F, 0xC4F2, 0x5C3F, 0xC4F3, 0x634F, 0xC4F4, 0x8042, 0xC4F5, 0x5B7D, 0xC4F6, 0x556E, 0xC4F7, 0x954A, 0xC4F8, 0x954D, 0xC4F9, 0x6D85, 0xC4FA, 0x60A8, 0xC4FB, 0x67E0, 0xC4FC, 0x72DE, 0xC4FD, 0x51DD, 0xC4FE, 0x5B81, 0xC540, 0x81D4, 0xC541, 0x81D5, 0xC542, 0x81D6, 0xC543, 0x81D7, 0xC544, 0x81D8, 0xC545, 0x81D9, 0xC546, 0x81DA, 0xC547, 0x81DB, 0xC548, 0x81DC, 0xC549, 0x81DD, 0xC54A, 0x81DE, 0xC54B, 0x81DF, 0xC54C, 0x81E0, 0xC54D, 0x81E1, 0xC54E, 0x81E2, 0xC54F, 0x81E4, 0xC550, 0x81E5, 0xC551, 0x81E6, 0xC552, 0x81E8, 0xC553, 0x81E9, 0xC554, 0x81EB, 0xC555, 0x81EE, 0xC556, 0x81EF, 0xC557, 0x81F0, 0xC558, 0x81F1, 0xC559, 0x81F2, 0xC55A, 0x81F5, 0xC55B, 0x81F6, 0xC55C, 0x81F7, 0xC55D, 0x81F8, 0xC55E, 0x81F9, 0xC55F, 0x81FA, 0xC560, 0x81FD, 0xC561, 0x81FF, 0xC562, 0x8203, 0xC563, 0x8207, 0xC564, 0x8208, 0xC565, 0x8209, 0xC566, 0x820A, 0xC567, 0x820B, 0xC568, 0x820E, 0xC569, 0x820F, 0xC56A, 0x8211, 0xC56B, 0x8213, 0xC56C, 0x8215, 0xC56D, 0x8216, 0xC56E, 0x8217, 0xC56F, 0x8218, 0xC570, 0x8219, 0xC571, 0x821A, 0xC572, 0x821D, 0xC573, 0x8220, 0xC574, 0x8224, 0xC575, 0x8225, 0xC576, 0x8226, 0xC577, 0x8227, 0xC578, 0x8229, 0xC579, 0x822E, 0xC57A, 0x8232, 0xC57B, 0x823A, 0xC57C, 0x823C, 0xC57D, 0x823D, 0xC57E, 0x823F, 0xC580, 0x8240, 0xC581, 0x8241, 0xC582, 0x8242, 0xC583, 0x8243, 0xC584, 0x8245, 0xC585, 0x8246, 0xC586, 0x8248, 0xC587, 0x824A, 0xC588, 0x824C, 0xC589, 0x824D, 0xC58A, 0x824E, 0xC58B, 0x8250, 0xC58C, 0x8251, 0xC58D, 0x8252, 0xC58E, 0x8253, 0xC58F, 0x8254, 0xC590, 0x8255, 0xC591, 0x8256, 0xC592, 0x8257, 0xC593, 0x8259, 0xC594, 0x825B, 0xC595, 0x825C, 0xC596, 0x825D, 0xC597, 0x825E, 0xC598, 0x8260, 0xC599, 0x8261, 0xC59A, 0x8262, 0xC59B, 0x8263, 0xC59C, 0x8264, 0xC59D, 0x8265, 0xC59E, 0x8266, 0xC59F, 0x8267, 0xC5A0, 0x8269, 0xC5A1, 0x62E7, 0xC5A2, 0x6CDE, 0xC5A3, 0x725B, 0xC5A4, 0x626D, 0xC5A5, 0x94AE, 0xC5A6, 0x7EBD, 0xC5A7, 0x8113, 0xC5A8, 0x6D53, 0xC5A9, 0x519C, 0xC5AA, 0x5F04, 0xC5AB, 0x5974, 0xC5AC, 0x52AA, 0xC5AD, 0x6012, 0xC5AE, 0x5973, 0xC5AF, 0x6696, 0xC5B0, 0x8650, 0xC5B1, 0x759F, 0xC5B2, 0x632A, 0xC5B3, 0x61E6, 0xC5B4, 0x7CEF, 0xC5B5, 0x8BFA, 0xC5B6, 0x54E6, 0xC5B7, 0x6B27, 0xC5B8, 0x9E25, 0xC5B9, 0x6BB4, 0xC5BA, 0x85D5, 0xC5BB, 0x5455, 0xC5BC, 0x5076, 0xC5BD, 0x6CA4, 0xC5BE, 0x556A, 0xC5BF, 0x8DB4, 0xC5C0, 0x722C, 0xC5C1, 0x5E15, 0xC5C2, 0x6015, 0xC5C3, 0x7436, 0xC5C4, 0x62CD, 0xC5C5, 0x6392, 0xC5C6, 0x724C, 0xC5C7, 0x5F98, 0xC5C8, 0x6E43, 0xC5C9, 0x6D3E, 0xC5CA, 0x6500, 0xC5CB, 0x6F58, 0xC5CC, 0x76D8, 0xC5CD, 0x78D0, 0xC5CE, 0x76FC, 0xC5CF, 0x7554, 0xC5D0, 0x5224, 0xC5D1, 0x53DB, 0xC5D2, 0x4E53, 0xC5D3, 0x5E9E, 0xC5D4, 0x65C1, 0xC5D5, 0x802A, 0xC5D6, 0x80D6, 0xC5D7, 0x629B, 0xC5D8, 0x5486, 0xC5D9, 0x5228, 0xC5DA, 0x70AE, 0xC5DB, 0x888D, 0xC5DC, 0x8DD1, 0xC5DD, 0x6CE1, 0xC5DE, 0x5478, 0xC5DF, 0x80DA, 0xC5E0, 0x57F9, 0xC5E1, 0x88F4, 0xC5E2, 0x8D54, 0xC5E3, 0x966A, 0xC5E4, 0x914D, 0xC5E5, 0x4F69, 0xC5E6, 0x6C9B, 0xC5E7, 0x55B7, 0xC5E8, 0x76C6, 0xC5E9, 0x7830, 0xC5EA, 0x62A8, 0xC5EB, 0x70F9, 0xC5EC, 0x6F8E, 0xC5ED, 0x5F6D, 0xC5EE, 0x84EC, 0xC5EF, 0x68DA, 0xC5F0, 0x787C, 0xC5F1, 0x7BF7, 0xC5F2, 0x81A8, 0xC5F3, 0x670B, 0xC5F4, 0x9E4F, 0xC5F5, 0x6367, 0xC5F6, 0x78B0, 0xC5F7, 0x576F, 0xC5F8, 0x7812, 0xC5F9, 0x9739, 0xC5FA, 0x6279, 0xC5FB, 0x62AB, 0xC5FC, 0x5288, 0xC5FD, 0x7435, 0xC5FE, 0x6BD7, 0xC640, 0x826A, 0xC641, 0x826B, 0xC642, 0x826C, 0xC643, 0x826D, 0xC644, 0x8271, 0xC645, 0x8275, 0xC646, 0x8276, 0xC647, 0x8277, 0xC648, 0x8278, 0xC649, 0x827B, 0xC64A, 0x827C, 0xC64B, 0x8280, 0xC64C, 0x8281, 0xC64D, 0x8283, 0xC64E, 0x8285, 0xC64F, 0x8286, 0xC650, 0x8287, 0xC651, 0x8289, 0xC652, 0x828C, 0xC653, 0x8290, 0xC654, 0x8293, 0xC655, 0x8294, 0xC656, 0x8295, 0xC657, 0x8296, 0xC658, 0x829A, 0xC659, 0x829B, 0xC65A, 0x829E, 0xC65B, 0x82A0, 0xC65C, 0x82A2, 0xC65D, 0x82A3, 0xC65E, 0x82A7, 0xC65F, 0x82B2, 0xC660, 0x82B5, 0xC661, 0x82B6, 0xC662, 0x82BA, 0xC663, 0x82BB, 0xC664, 0x82BC, 0xC665, 0x82BF, 0xC666, 0x82C0, 0xC667, 0x82C2, 0xC668, 0x82C3, 0xC669, 0x82C5, 0xC66A, 0x82C6, 0xC66B, 0x82C9, 0xC66C, 0x82D0, 0xC66D, 0x82D6, 0xC66E, 0x82D9, 0xC66F, 0x82DA, 0xC670, 0x82DD, 0xC671, 0x82E2, 0xC672, 0x82E7, 0xC673, 0x82E8, 0xC674, 0x82E9, 0xC675, 0x82EA, 0xC676, 0x82EC, 0xC677, 0x82ED, 0xC678, 0x82EE, 0xC679, 0x82F0, 0xC67A, 0x82F2, 0xC67B, 0x82F3, 0xC67C, 0x82F5, 0xC67D, 0x82F6, 0xC67E, 0x82F8, 0xC680, 0x82FA, 0xC681, 0x82FC, 0xC682, 0x82FD, 0xC683, 0x82FE, 0xC684, 0x82FF, 0xC685, 0x8300, 0xC686, 0x830A, 0xC687, 0x830B, 0xC688, 0x830D, 0xC689, 0x8310, 0xC68A, 0x8312, 0xC68B, 0x8313, 0xC68C, 0x8316, 0xC68D, 0x8318, 0xC68E, 0x8319, 0xC68F, 0x831D, 0xC690, 0x831E, 0xC691, 0x831F, 0xC692, 0x8320, 0xC693, 0x8321, 0xC694, 0x8322, 0xC695, 0x8323, 0xC696, 0x8324, 0xC697, 0x8325, 0xC698, 0x8326, 0xC699, 0x8329, 0xC69A, 0x832A, 0xC69B, 0x832E, 0xC69C, 0x8330, 0xC69D, 0x8332, 0xC69E, 0x8337, 0xC69F, 0x833B, 0xC6A0, 0x833D, 0xC6A1, 0x5564, 0xC6A2, 0x813E, 0xC6A3, 0x75B2, 0xC6A4, 0x76AE, 0xC6A5, 0x5339, 0xC6A6, 0x75DE, 0xC6A7, 0x50FB, 0xC6A8, 0x5C41, 0xC6A9, 0x8B6C, 0xC6AA, 0x7BC7, 0xC6AB, 0x504F, 0xC6AC, 0x7247, 0xC6AD, 0x9A97, 0xC6AE, 0x98D8, 0xC6AF, 0x6F02, 0xC6B0, 0x74E2, 0xC6B1, 0x7968, 0xC6B2, 0x6487, 0xC6B3, 0x77A5, 0xC6B4, 0x62FC, 0xC6B5, 0x9891, 0xC6B6, 0x8D2B, 0xC6B7, 0x54C1, 0xC6B8, 0x8058, 0xC6B9, 0x4E52, 0xC6BA, 0x576A, 0xC6BB, 0x82F9, 0xC6BC, 0x840D, 0xC6BD, 0x5E73, 0xC6BE, 0x51ED, 0xC6BF, 0x74F6, 0xC6C0, 0x8BC4, 0xC6C1, 0x5C4F, 0xC6C2, 0x5761, 0xC6C3, 0x6CFC, 0xC6C4, 0x9887, 0xC6C5, 0x5A46, 0xC6C6, 0x7834, 0xC6C7, 0x9B44, 0xC6C8, 0x8FEB, 0xC6C9, 0x7C95, 0xC6CA, 0x5256, 0xC6CB, 0x6251, 0xC6CC, 0x94FA, 0xC6CD, 0x4EC6, 0xC6CE, 0x8386, 0xC6CF, 0x8461, 0xC6D0, 0x83E9, 0xC6D1, 0x84B2, 0xC6D2, 0x57D4, 0xC6D3, 0x6734, 0xC6D4, 0x5703, 0xC6D5, 0x666E, 0xC6D6, 0x6D66, 0xC6D7, 0x8C31, 0xC6D8, 0x66DD, 0xC6D9, 0x7011, 0xC6DA, 0x671F, 0xC6DB, 0x6B3A, 0xC6DC, 0x6816, 0xC6DD, 0x621A, 0xC6DE, 0x59BB, 0xC6DF, 0x4E03, 0xC6E0, 0x51C4, 0xC6E1, 0x6F06, 0xC6E2, 0x67D2, 0xC6E3, 0x6C8F, 0xC6E4, 0x5176, 0xC6E5, 0x68CB, 0xC6E6, 0x5947, 0xC6E7, 0x6B67, 0xC6E8, 0x7566, 0xC6E9, 0x5D0E, 0xC6EA, 0x8110, 0xC6EB, 0x9F50, 0xC6EC, 0x65D7, 0xC6ED, 0x7948, 0xC6EE, 0x7941, 0xC6EF, 0x9A91, 0xC6F0, 0x8D77, 0xC6F1, 0x5C82, 0xC6F2, 0x4E5E, 0xC6F3, 0x4F01, 0xC6F4, 0x542F, 0xC6F5, 0x5951, 0xC6F6, 0x780C, 0xC6F7, 0x5668, 0xC6F8, 0x6C14, 0xC6F9, 0x8FC4, 0xC6FA, 0x5F03, 0xC6FB, 0x6C7D, 0xC6FC, 0x6CE3, 0xC6FD, 0x8BAB, 0xC6FE, 0x6390, 0xC740, 0x833E, 0xC741, 0x833F, 0xC742, 0x8341, 0xC743, 0x8342, 0xC744, 0x8344, 0xC745, 0x8345, 0xC746, 0x8348, 0xC747, 0x834A, 0xC748, 0x834B, 0xC749, 0x834C, 0xC74A, 0x834D, 0xC74B, 0x834E, 0xC74C, 0x8353, 0xC74D, 0x8355, 0xC74E, 0x8356, 0xC74F, 0x8357, 0xC750, 0x8358, 0xC751, 0x8359, 0xC752, 0x835D, 0xC753, 0x8362, 0xC754, 0x8370, 0xC755, 0x8371, 0xC756, 0x8372, 0xC757, 0x8373, 0xC758, 0x8374, 0xC759, 0x8375, 0xC75A, 0x8376, 0xC75B, 0x8379, 0xC75C, 0x837A, 0xC75D, 0x837E, 0xC75E, 0x837F, 0xC75F, 0x8380, 0xC760, 0x8381, 0xC761, 0x8382, 0xC762, 0x8383, 0xC763, 0x8384, 0xC764, 0x8387, 0xC765, 0x8388, 0xC766, 0x838A, 0xC767, 0x838B, 0xC768, 0x838C, 0xC769, 0x838D, 0xC76A, 0x838F, 0xC76B, 0x8390, 0xC76C, 0x8391, 0xC76D, 0x8394, 0xC76E, 0x8395, 0xC76F, 0x8396, 0xC770, 0x8397, 0xC771, 0x8399, 0xC772, 0x839A, 0xC773, 0x839D, 0xC774, 0x839F, 0xC775, 0x83A1, 0xC776, 0x83A2, 0xC777, 0x83A3, 0xC778, 0x83A4, 0xC779, 0x83A5, 0xC77A, 0x83A6, 0xC77B, 0x83A7, 0xC77C, 0x83AC, 0xC77D, 0x83AD, 0xC77E, 0x83AE, 0xC780, 0x83AF, 0xC781, 0x83B5, 0xC782, 0x83BB, 0xC783, 0x83BE, 0xC784, 0x83BF, 0xC785, 0x83C2, 0xC786, 0x83C3, 0xC787, 0x83C4, 0xC788, 0x83C6, 0xC789, 0x83C8, 0xC78A, 0x83C9, 0xC78B, 0x83CB, 0xC78C, 0x83CD, 0xC78D, 0x83CE, 0xC78E, 0x83D0, 0xC78F, 0x83D1, 0xC790, 0x83D2, 0xC791, 0x83D3, 0xC792, 0x83D5, 0xC793, 0x83D7, 0xC794, 0x83D9, 0xC795, 0x83DA, 0xC796, 0x83DB, 0xC797, 0x83DE, 0xC798, 0x83E2, 0xC799, 0x83E3, 0xC79A, 0x83E4, 0xC79B, 0x83E6, 0xC79C, 0x83E7, 0xC79D, 0x83E8, 0xC79E, 0x83EB, 0xC79F, 0x83EC, 0xC7A0, 0x83ED, 0xC7A1, 0x6070, 0xC7A2, 0x6D3D, 0xC7A3, 0x7275, 0xC7A4, 0x6266, 0xC7A5, 0x948E, 0xC7A6, 0x94C5, 0xC7A7, 0x5343, 0xC7A8, 0x8FC1, 0xC7A9, 0x7B7E, 0xC7AA, 0x4EDF, 0xC7AB, 0x8C26, 0xC7AC, 0x4E7E, 0xC7AD, 0x9ED4, 0xC7AE, 0x94B1, 0xC7AF, 0x94B3, 0xC7B0, 0x524D, 0xC7B1, 0x6F5C, 0xC7B2, 0x9063, 0xC7B3, 0x6D45, 0xC7B4, 0x8C34, 0xC7B5, 0x5811, 0xC7B6, 0x5D4C, 0xC7B7, 0x6B20, 0xC7B8, 0x6B49, 0xC7B9, 0x67AA, 0xC7BA, 0x545B, 0xC7BB, 0x8154, 0xC7BC, 0x7F8C, 0xC7BD, 0x5899, 0xC7BE, 0x8537, 0xC7BF, 0x5F3A, 0xC7C0, 0x62A2, 0xC7C1, 0x6A47, 0xC7C2, 0x9539, 0xC7C3, 0x6572, 0xC7C4, 0x6084, 0xC7C5, 0x6865, 0xC7C6, 0x77A7, 0xC7C7, 0x4E54, 0xC7C8, 0x4FA8, 0xC7C9, 0x5DE7, 0xC7CA, 0x9798, 0xC7CB, 0x64AC, 0xC7CC, 0x7FD8, 0xC7CD, 0x5CED, 0xC7CE, 0x4FCF, 0xC7CF, 0x7A8D, 0xC7D0, 0x5207, 0xC7D1, 0x8304, 0xC7D2, 0x4E14, 0xC7D3, 0x602F, 0xC7D4, 0x7A83, 0xC7D5, 0x94A6, 0xC7D6, 0x4FB5, 0xC7D7, 0x4EB2, 0xC7D8, 0x79E6, 0xC7D9, 0x7434, 0xC7DA, 0x52E4, 0xC7DB, 0x82B9, 0xC7DC, 0x64D2, 0xC7DD, 0x79BD, 0xC7DE, 0x5BDD, 0xC7DF, 0x6C81, 0xC7E0, 0x9752, 0xC7E1, 0x8F7B, 0xC7E2, 0x6C22, 0xC7E3, 0x503E, 0xC7E4, 0x537F, 0xC7E5, 0x6E05, 0xC7E6, 0x64CE, 0xC7E7, 0x6674, 0xC7E8, 0x6C30, 0xC7E9, 0x60C5, 0xC7EA, 0x9877, 0xC7EB, 0x8BF7, 0xC7EC, 0x5E86, 0xC7ED, 0x743C, 0xC7EE, 0x7A77, 0xC7EF, 0x79CB, 0xC7F0, 0x4E18, 0xC7F1, 0x90B1, 0xC7F2, 0x7403, 0xC7F3, 0x6C42, 0xC7F4, 0x56DA, 0xC7F5, 0x914B, 0xC7F6, 0x6CC5, 0xC7F7, 0x8D8B, 0xC7F8, 0x533A, 0xC7F9, 0x86C6, 0xC7FA, 0x66F2, 0xC7FB, 0x8EAF, 0xC7FC, 0x5C48, 0xC7FD, 0x9A71, 0xC7FE, 0x6E20, 0xC840, 0x83EE, 0xC841, 0x83EF, 0xC842, 0x83F3, 0xC843, 0x83F4, 0xC844, 0x83F5, 0xC845, 0x83F6, 0xC846, 0x83F7, 0xC847, 0x83FA, 0xC848, 0x83FB, 0xC849, 0x83FC, 0xC84A, 0x83FE, 0xC84B, 0x83FF, 0xC84C, 0x8400, 0xC84D, 0x8402, 0xC84E, 0x8405, 0xC84F, 0x8407, 0xC850, 0x8408, 0xC851, 0x8409, 0xC852, 0x840A, 0xC853, 0x8410, 0xC854, 0x8412, 0xC855, 0x8413, 0xC856, 0x8414, 0xC857, 0x8415, 0xC858, 0x8416, 0xC859, 0x8417, 0xC85A, 0x8419, 0xC85B, 0x841A, 0xC85C, 0x841B, 0xC85D, 0x841E, 0xC85E, 0x841F, 0xC85F, 0x8420, 0xC860, 0x8421, 0xC861, 0x8422, 0xC862, 0x8423, 0xC863, 0x8429, 0xC864, 0x842A, 0xC865, 0x842B, 0xC866, 0x842C, 0xC867, 0x842D, 0xC868, 0x842E, 0xC869, 0x842F, 0xC86A, 0x8430, 0xC86B, 0x8432, 0xC86C, 0x8433, 0xC86D, 0x8434, 0xC86E, 0x8435, 0xC86F, 0x8436, 0xC870, 0x8437, 0xC871, 0x8439, 0xC872, 0x843A, 0xC873, 0x843B, 0xC874, 0x843E, 0xC875, 0x843F, 0xC876, 0x8440, 0xC877, 0x8441, 0xC878, 0x8442, 0xC879, 0x8443, 0xC87A, 0x8444, 0xC87B, 0x8445, 0xC87C, 0x8447, 0xC87D, 0x8448, 0xC87E, 0x8449, 0xC880, 0x844A, 0xC881, 0x844B, 0xC882, 0x844C, 0xC883, 0x844D, 0xC884, 0x844E, 0xC885, 0x844F, 0xC886, 0x8450, 0xC887, 0x8452, 0xC888, 0x8453, 0xC889, 0x8454, 0xC88A, 0x8455, 0xC88B, 0x8456, 0xC88C, 0x8458, 0xC88D, 0x845D, 0xC88E, 0x845E, 0xC88F, 0x845F, 0xC890, 0x8460, 0xC891, 0x8462, 0xC892, 0x8464, 0xC893, 0x8465, 0xC894, 0x8466, 0xC895, 0x8467, 0xC896, 0x8468, 0xC897, 0x846A, 0xC898, 0x846E, 0xC899, 0x846F, 0xC89A, 0x8470, 0xC89B, 0x8472, 0xC89C, 0x8474, 0xC89D, 0x8477, 0xC89E, 0x8479, 0xC89F, 0x847B, 0xC8A0, 0x847C, 0xC8A1, 0x53D6, 0xC8A2, 0x5A36, 0xC8A3, 0x9F8B, 0xC8A4, 0x8DA3, 0xC8A5, 0x53BB, 0xC8A6, 0x5708, 0xC8A7, 0x98A7, 0xC8A8, 0x6743, 0xC8A9, 0x919B, 0xC8AA, 0x6CC9, 0xC8AB, 0x5168, 0xC8AC, 0x75CA, 0xC8AD, 0x62F3, 0xC8AE, 0x72AC, 0xC8AF, 0x5238, 0xC8B0, 0x529D, 0xC8B1, 0x7F3A, 0xC8B2, 0x7094, 0xC8B3, 0x7638, 0xC8B4, 0x5374, 0xC8B5, 0x9E4A, 0xC8B6, 0x69B7, 0xC8B7, 0x786E, 0xC8B8, 0x96C0, 0xC8B9, 0x88D9, 0xC8BA, 0x7FA4, 0xC8BB, 0x7136, 0xC8BC, 0x71C3, 0xC8BD, 0x5189, 0xC8BE, 0x67D3, 0xC8BF, 0x74E4, 0xC8C0, 0x58E4, 0xC8C1, 0x6518, 0xC8C2, 0x56B7, 0xC8C3, 0x8BA9, 0xC8C4, 0x9976, 0xC8C5, 0x6270, 0xC8C6, 0x7ED5, 0xC8C7, 0x60F9, 0xC8C8, 0x70ED, 0xC8C9, 0x58EC, 0xC8CA, 0x4EC1, 0xC8CB, 0x4EBA, 0xC8CC, 0x5FCD, 0xC8CD, 0x97E7, 0xC8CE, 0x4EFB, 0xC8CF, 0x8BA4, 0xC8D0, 0x5203, 0xC8D1, 0x598A, 0xC8D2, 0x7EAB, 0xC8D3, 0x6254, 0xC8D4, 0x4ECD, 0xC8D5, 0x65E5, 0xC8D6, 0x620E, 0xC8D7, 0x8338, 0xC8D8, 0x84C9, 0xC8D9, 0x8363, 0xC8DA, 0x878D, 0xC8DB, 0x7194, 0xC8DC, 0x6EB6, 0xC8DD, 0x5BB9, 0xC8DE, 0x7ED2, 0xC8DF, 0x5197, 0xC8E0, 0x63C9, 0xC8E1, 0x67D4, 0xC8E2, 0x8089, 0xC8E3, 0x8339, 0xC8E4, 0x8815, 0xC8E5, 0x5112, 0xC8E6, 0x5B7A, 0xC8E7, 0x5982, 0xC8E8, 0x8FB1, 0xC8E9, 0x4E73, 0xC8EA, 0x6C5D, 0xC8EB, 0x5165, 0xC8EC, 0x8925, 0xC8ED, 0x8F6F, 0xC8EE, 0x962E, 0xC8EF, 0x854A, 0xC8F0, 0x745E, 0xC8F1, 0x9510, 0xC8F2, 0x95F0, 0xC8F3, 0x6DA6, 0xC8F4, 0x82E5, 0xC8F5, 0x5F31, 0xC8F6, 0x6492, 0xC8F7, 0x6D12, 0xC8F8, 0x8428, 0xC8F9, 0x816E, 0xC8FA, 0x9CC3, 0xC8FB, 0x585E, 0xC8FC, 0x8D5B, 0xC8FD, 0x4E09, 0xC8FE, 0x53C1, 0xC940, 0x847D, 0xC941, 0x847E, 0xC942, 0x847F, 0xC943, 0x8480, 0xC944, 0x8481, 0xC945, 0x8483, 0xC946, 0x8484, 0xC947, 0x8485, 0xC948, 0x8486, 0xC949, 0x848A, 0xC94A, 0x848D, 0xC94B, 0x848F, 0xC94C, 0x8490, 0xC94D, 0x8491, 0xC94E, 0x8492, 0xC94F, 0x8493, 0xC950, 0x8494, 0xC951, 0x8495, 0xC952, 0x8496, 0xC953, 0x8498, 0xC954, 0x849A, 0xC955, 0x849B, 0xC956, 0x849D, 0xC957, 0x849E, 0xC958, 0x849F, 0xC959, 0x84A0, 0xC95A, 0x84A2, 0xC95B, 0x84A3, 0xC95C, 0x84A4, 0xC95D, 0x84A5, 0xC95E, 0x84A6, 0xC95F, 0x84A7, 0xC960, 0x84A8, 0xC961, 0x84A9, 0xC962, 0x84AA, 0xC963, 0x84AB, 0xC964, 0x84AC, 0xC965, 0x84AD, 0xC966, 0x84AE, 0xC967, 0x84B0, 0xC968, 0x84B1, 0xC969, 0x84B3, 0xC96A, 0x84B5, 0xC96B, 0x84B6, 0xC96C, 0x84B7, 0xC96D, 0x84BB, 0xC96E, 0x84BC, 0xC96F, 0x84BE, 0xC970, 0x84C0, 0xC971, 0x84C2, 0xC972, 0x84C3, 0xC973, 0x84C5, 0xC974, 0x84C6, 0xC975, 0x84C7, 0xC976, 0x84C8, 0xC977, 0x84CB, 0xC978, 0x84CC, 0xC979, 0x84CE, 0xC97A, 0x84CF, 0xC97B, 0x84D2, 0xC97C, 0x84D4, 0xC97D, 0x84D5, 0xC97E, 0x84D7, 0xC980, 0x84D8, 0xC981, 0x84D9, 0xC982, 0x84DA, 0xC983, 0x84DB, 0xC984, 0x84DC, 0xC985, 0x84DE, 0xC986, 0x84E1, 0xC987, 0x84E2, 0xC988, 0x84E4, 0xC989, 0x84E7, 0xC98A, 0x84E8, 0xC98B, 0x84E9, 0xC98C, 0x84EA, 0xC98D, 0x84EB, 0xC98E, 0x84ED, 0xC98F, 0x84EE, 0xC990, 0x84EF, 0xC991, 0x84F1, 0xC992, 0x84F2, 0xC993, 0x84F3, 0xC994, 0x84F4, 0xC995, 0x84F5, 0xC996, 0x84F6, 0xC997, 0x84F7, 0xC998, 0x84F8, 0xC999, 0x84F9, 0xC99A, 0x84FA, 0xC99B, 0x84FB, 0xC99C, 0x84FD, 0xC99D, 0x84FE, 0xC99E, 0x8500, 0xC99F, 0x8501, 0xC9A0, 0x8502, 0xC9A1, 0x4F1E, 0xC9A2, 0x6563, 0xC9A3, 0x6851, 0xC9A4, 0x55D3, 0xC9A5, 0x4E27, 0xC9A6, 0x6414, 0xC9A7, 0x9A9A, 0xC9A8, 0x626B, 0xC9A9, 0x5AC2, 0xC9AA, 0x745F, 0xC9AB, 0x8272, 0xC9AC, 0x6DA9, 0xC9AD, 0x68EE, 0xC9AE, 0x50E7, 0xC9AF, 0x838E, 0xC9B0, 0x7802, 0xC9B1, 0x6740, 0xC9B2, 0x5239, 0xC9B3, 0x6C99, 0xC9B4, 0x7EB1, 0xC9B5, 0x50BB, 0xC9B6, 0x5565, 0xC9B7, 0x715E, 0xC9B8, 0x7B5B, 0xC9B9, 0x6652, 0xC9BA, 0x73CA, 0xC9BB, 0x82EB, 0xC9BC, 0x6749, 0xC9BD, 0x5C71, 0xC9BE, 0x5220, 0xC9BF, 0x717D, 0xC9C0, 0x886B, 0xC9C1, 0x95EA, 0xC9C2, 0x9655, 0xC9C3, 0x64C5, 0xC9C4, 0x8D61, 0xC9C5, 0x81B3, 0xC9C6, 0x5584, 0xC9C7, 0x6C55, 0xC9C8, 0x6247, 0xC9C9, 0x7F2E, 0xC9CA, 0x5892, 0xC9CB, 0x4F24, 0xC9CC, 0x5546, 0xC9CD, 0x8D4F, 0xC9CE, 0x664C, 0xC9CF, 0x4E0A, 0xC9D0, 0x5C1A, 0xC9D1, 0x88F3, 0xC9D2, 0x68A2, 0xC9D3, 0x634E, 0xC9D4, 0x7A0D, 0xC9D5, 0x70E7, 0xC9D6, 0x828D, 0xC9D7, 0x52FA, 0xC9D8, 0x97F6, 0xC9D9, 0x5C11, 0xC9DA, 0x54E8, 0xC9DB, 0x90B5, 0xC9DC, 0x7ECD, 0xC9DD, 0x5962, 0xC9DE, 0x8D4A, 0xC9DF, 0x86C7, 0xC9E0, 0x820C, 0xC9E1, 0x820D, 0xC9E2, 0x8D66, 0xC9E3, 0x6444, 0xC9E4, 0x5C04, 0xC9E5, 0x6151, 0xC9E6, 0x6D89, 0xC9E7, 0x793E, 0xC9E8, 0x8BBE, 0xC9E9, 0x7837, 0xC9EA, 0x7533, 0xC9EB, 0x547B, 0xC9EC, 0x4F38, 0xC9ED, 0x8EAB, 0xC9EE, 0x6DF1, 0xC9EF, 0x5A20, 0xC9F0, 0x7EC5, 0xC9F1, 0x795E, 0xC9F2, 0x6C88, 0xC9F3, 0x5BA1, 0xC9F4, 0x5A76, 0xC9F5, 0x751A, 0xC9F6, 0x80BE, 0xC9F7, 0x614E, 0xC9F8, 0x6E17, 0xC9F9, 0x58F0, 0xC9FA, 0x751F, 0xC9FB, 0x7525, 0xC9FC, 0x7272, 0xC9FD, 0x5347, 0xC9FE, 0x7EF3, 0xCA40, 0x8503, 0xCA41, 0x8504, 0xCA42, 0x8505, 0xCA43, 0x8506, 0xCA44, 0x8507, 0xCA45, 0x8508, 0xCA46, 0x8509, 0xCA47, 0x850A, 0xCA48, 0x850B, 0xCA49, 0x850D, 0xCA4A, 0x850E, 0xCA4B, 0x850F, 0xCA4C, 0x8510, 0xCA4D, 0x8512, 0xCA4E, 0x8514, 0xCA4F, 0x8515, 0xCA50, 0x8516, 0xCA51, 0x8518, 0xCA52, 0x8519, 0xCA53, 0x851B, 0xCA54, 0x851C, 0xCA55, 0x851D, 0xCA56, 0x851E, 0xCA57, 0x8520, 0xCA58, 0x8522, 0xCA59, 0x8523, 0xCA5A, 0x8524, 0xCA5B, 0x8525, 0xCA5C, 0x8526, 0xCA5D, 0x8527, 0xCA5E, 0x8528, 0xCA5F, 0x8529, 0xCA60, 0x852A, 0xCA61, 0x852D, 0xCA62, 0x852E, 0xCA63, 0x852F, 0xCA64, 0x8530, 0xCA65, 0x8531, 0xCA66, 0x8532, 0xCA67, 0x8533, 0xCA68, 0x8534, 0xCA69, 0x8535, 0xCA6A, 0x8536, 0xCA6B, 0x853E, 0xCA6C, 0x853F, 0xCA6D, 0x8540, 0xCA6E, 0x8541, 0xCA6F, 0x8542, 0xCA70, 0x8544, 0xCA71, 0x8545, 0xCA72, 0x8546, 0xCA73, 0x8547, 0xCA74, 0x854B, 0xCA75, 0x854C, 0xCA76, 0x854D, 0xCA77, 0x854E, 0xCA78, 0x854F, 0xCA79, 0x8550, 0xCA7A, 0x8551, 0xCA7B, 0x8552, 0xCA7C, 0x8553, 0xCA7D, 0x8554, 0xCA7E, 0x8555, 0xCA80, 0x8557, 0xCA81, 0x8558, 0xCA82, 0x855A, 0xCA83, 0x855B, 0xCA84, 0x855C, 0xCA85, 0x855D, 0xCA86, 0x855F, 0xCA87, 0x8560, 0xCA88, 0x8561, 0xCA89, 0x8562, 0xCA8A, 0x8563, 0xCA8B, 0x8565, 0xCA8C, 0x8566, 0xCA8D, 0x8567, 0xCA8E, 0x8569, 0xCA8F, 0x856A, 0xCA90, 0x856B, 0xCA91, 0x856C, 0xCA92, 0x856D, 0xCA93, 0x856E, 0xCA94, 0x856F, 0xCA95, 0x8570, 0xCA96, 0x8571, 0xCA97, 0x8573, 0xCA98, 0x8575, 0xCA99, 0x8576, 0xCA9A, 0x8577, 0xCA9B, 0x8578, 0xCA9C, 0x857C, 0xCA9D, 0x857D, 0xCA9E, 0x857F, 0xCA9F, 0x8580, 0xCAA0, 0x8581, 0xCAA1, 0x7701, 0xCAA2, 0x76DB, 0xCAA3, 0x5269, 0xCAA4, 0x80DC, 0xCAA5, 0x5723, 0xCAA6, 0x5E08, 0xCAA7, 0x5931, 0xCAA8, 0x72EE, 0xCAA9, 0x65BD, 0xCAAA, 0x6E7F, 0xCAAB, 0x8BD7, 0xCAAC, 0x5C38, 0xCAAD, 0x8671, 0xCAAE, 0x5341, 0xCAAF, 0x77F3, 0xCAB0, 0x62FE, 0xCAB1, 0x65F6, 0xCAB2, 0x4EC0, 0xCAB3, 0x98DF, 0xCAB4, 0x8680, 0xCAB5, 0x5B9E, 0xCAB6, 0x8BC6, 0xCAB7, 0x53F2, 0xCAB8, 0x77E2, 0xCAB9, 0x4F7F, 0xCABA, 0x5C4E, 0xCABB, 0x9A76, 0xCABC, 0x59CB, 0xCABD, 0x5F0F, 0xCABE, 0x793A, 0xCABF, 0x58EB, 0xCAC0, 0x4E16, 0xCAC1, 0x67FF, 0xCAC2, 0x4E8B, 0xCAC3, 0x62ED, 0xCAC4, 0x8A93, 0xCAC5, 0x901D, 0xCAC6, 0x52BF, 0xCAC7, 0x662F, 0xCAC8, 0x55DC, 0xCAC9, 0x566C, 0xCACA, 0x9002, 0xCACB, 0x4ED5, 0xCACC, 0x4F8D, 0xCACD, 0x91CA, 0xCACE, 0x9970, 0xCACF, 0x6C0F, 0xCAD0, 0x5E02, 0xCAD1, 0x6043, 0xCAD2, 0x5BA4, 0xCAD3, 0x89C6, 0xCAD4, 0x8BD5, 0xCAD5, 0x6536, 0xCAD6, 0x624B, 0xCAD7, 0x9996, 0xCAD8, 0x5B88, 0xCAD9, 0x5BFF, 0xCADA, 0x6388, 0xCADB, 0x552E, 0xCADC, 0x53D7, 0xCADD, 0x7626, 0xCADE, 0x517D, 0xCADF, 0x852C, 0xCAE0, 0x67A2, 0xCAE1, 0x68B3, 0xCAE2, 0x6B8A, 0xCAE3, 0x6292, 0xCAE4, 0x8F93, 0xCAE5, 0x53D4, 0xCAE6, 0x8212, 0xCAE7, 0x6DD1, 0xCAE8, 0x758F, 0xCAE9, 0x4E66, 0xCAEA, 0x8D4E, 0xCAEB, 0x5B70, 0xCAEC, 0x719F, 0xCAED, 0x85AF, 0xCAEE, 0x6691, 0xCAEF, 0x66D9, 0xCAF0, 0x7F72, 0xCAF1, 0x8700, 0xCAF2, 0x9ECD, 0xCAF3, 0x9F20, 0xCAF4, 0x5C5E, 0xCAF5, 0x672F, 0xCAF6, 0x8FF0, 0xCAF7, 0x6811, 0xCAF8, 0x675F, 0xCAF9, 0x620D, 0xCAFA, 0x7AD6, 0xCAFB, 0x5885, 0xCAFC, 0x5EB6, 0xCAFD, 0x6570, 0xCAFE, 0x6F31, 0xCB40, 0x8582, 0xCB41, 0x8583, 0xCB42, 0x8586, 0xCB43, 0x8588, 0xCB44, 0x8589, 0xCB45, 0x858A, 0xCB46, 0x858B, 0xCB47, 0x858C, 0xCB48, 0x858D, 0xCB49, 0x858E, 0xCB4A, 0x8590, 0xCB4B, 0x8591, 0xCB4C, 0x8592, 0xCB4D, 0x8593, 0xCB4E, 0x8594, 0xCB4F, 0x8595, 0xCB50, 0x8596, 0xCB51, 0x8597, 0xCB52, 0x8598, 0xCB53, 0x8599, 0xCB54, 0x859A, 0xCB55, 0x859D, 0xCB56, 0x859E, 0xCB57, 0x859F, 0xCB58, 0x85A0, 0xCB59, 0x85A1, 0xCB5A, 0x85A2, 0xCB5B, 0x85A3, 0xCB5C, 0x85A5, 0xCB5D, 0x85A6, 0xCB5E, 0x85A7, 0xCB5F, 0x85A9, 0xCB60, 0x85AB, 0xCB61, 0x85AC, 0xCB62, 0x85AD, 0xCB63, 0x85B1, 0xCB64, 0x85B2, 0xCB65, 0x85B3, 0xCB66, 0x85B4, 0xCB67, 0x85B5, 0xCB68, 0x85B6, 0xCB69, 0x85B8, 0xCB6A, 0x85BA, 0xCB6B, 0x85BB, 0xCB6C, 0x85BC, 0xCB6D, 0x85BD, 0xCB6E, 0x85BE, 0xCB6F, 0x85BF, 0xCB70, 0x85C0, 0xCB71, 0x85C2, 0xCB72, 0x85C3, 0xCB73, 0x85C4, 0xCB74, 0x85C5, 0xCB75, 0x85C6, 0xCB76, 0x85C7, 0xCB77, 0x85C8, 0xCB78, 0x85CA, 0xCB79, 0x85CB, 0xCB7A, 0x85CC, 0xCB7B, 0x85CD, 0xCB7C, 0x85CE, 0xCB7D, 0x85D1, 0xCB7E, 0x85D2, 0xCB80, 0x85D4, 0xCB81, 0x85D6, 0xCB82, 0x85D7, 0xCB83, 0x85D8, 0xCB84, 0x85D9, 0xCB85, 0x85DA, 0xCB86, 0x85DB, 0xCB87, 0x85DD, 0xCB88, 0x85DE, 0xCB89, 0x85DF, 0xCB8A, 0x85E0, 0xCB8B, 0x85E1, 0xCB8C, 0x85E2, 0xCB8D, 0x85E3, 0xCB8E, 0x85E5, 0xCB8F, 0x85E6, 0xCB90, 0x85E7, 0xCB91, 0x85E8, 0xCB92, 0x85EA, 0xCB93, 0x85EB, 0xCB94, 0x85EC, 0xCB95, 0x85ED, 0xCB96, 0x85EE, 0xCB97, 0x85EF, 0xCB98, 0x85F0, 0xCB99, 0x85F1, 0xCB9A, 0x85F2, 0xCB9B, 0x85F3, 0xCB9C, 0x85F4, 0xCB9D, 0x85F5, 0xCB9E, 0x85F6, 0xCB9F, 0x85F7, 0xCBA0, 0x85F8, 0xCBA1, 0x6055, 0xCBA2, 0x5237, 0xCBA3, 0x800D, 0xCBA4, 0x6454, 0xCBA5, 0x8870, 0xCBA6, 0x7529, 0xCBA7, 0x5E05, 0xCBA8, 0x6813, 0xCBA9, 0x62F4, 0xCBAA, 0x971C, 0xCBAB, 0x53CC, 0xCBAC, 0x723D, 0xCBAD, 0x8C01, 0xCBAE, 0x6C34, 0xCBAF, 0x7761, 0xCBB0, 0x7A0E, 0xCBB1, 0x542E, 0xCBB2, 0x77AC, 0xCBB3, 0x987A, 0xCBB4, 0x821C, 0xCBB5, 0x8BF4, 0xCBB6, 0x7855, 0xCBB7, 0x6714, 0xCBB8, 0x70C1, 0xCBB9, 0x65AF, 0xCBBA, 0x6495, 0xCBBB, 0x5636, 0xCBBC, 0x601D, 0xCBBD, 0x79C1, 0xCBBE, 0x53F8, 0xCBBF, 0x4E1D, 0xCBC0, 0x6B7B, 0xCBC1, 0x8086, 0xCBC2, 0x5BFA, 0xCBC3, 0x55E3, 0xCBC4, 0x56DB, 0xCBC5, 0x4F3A, 0xCBC6, 0x4F3C, 0xCBC7, 0x9972, 0xCBC8, 0x5DF3, 0xCBC9, 0x677E, 0xCBCA, 0x8038, 0xCBCB, 0x6002, 0xCBCC, 0x9882, 0xCBCD, 0x9001, 0xCBCE, 0x5B8B, 0xCBCF, 0x8BBC, 0xCBD0, 0x8BF5, 0xCBD1, 0x641C, 0xCBD2, 0x8258, 0xCBD3, 0x64DE, 0xCBD4, 0x55FD, 0xCBD5, 0x82CF, 0xCBD6, 0x9165, 0xCBD7, 0x4FD7, 0xCBD8, 0x7D20, 0xCBD9, 0x901F, 0xCBDA, 0x7C9F, 0xCBDB, 0x50F3, 0xCBDC, 0x5851, 0xCBDD, 0x6EAF, 0xCBDE, 0x5BBF, 0xCBDF, 0x8BC9, 0xCBE0, 0x8083, 0xCBE1, 0x9178, 0xCBE2, 0x849C, 0xCBE3, 0x7B97, 0xCBE4, 0x867D, 0xCBE5, 0x968B, 0xCBE6, 0x968F, 0xCBE7, 0x7EE5, 0xCBE8, 0x9AD3, 0xCBE9, 0x788E, 0xCBEA, 0x5C81, 0xCBEB, 0x7A57, 0xCBEC, 0x9042, 0xCBED, 0x96A7, 0xCBEE, 0x795F, 0xCBEF, 0x5B59, 0xCBF0, 0x635F, 0xCBF1, 0x7B0B, 0xCBF2, 0x84D1, 0xCBF3, 0x68AD, 0xCBF4, 0x5506, 0xCBF5, 0x7F29, 0xCBF6, 0x7410, 0xCBF7, 0x7D22, 0xCBF8, 0x9501, 0xCBF9, 0x6240, 0xCBFA, 0x584C, 0xCBFB, 0x4ED6, 0xCBFC, 0x5B83, 0xCBFD, 0x5979, 0xCBFE, 0x5854, 0xCC40, 0x85F9, 0xCC41, 0x85FA, 0xCC42, 0x85FC, 0xCC43, 0x85FD, 0xCC44, 0x85FE, 0xCC45, 0x8600, 0xCC46, 0x8601, 0xCC47, 0x8602, 0xCC48, 0x8603, 0xCC49, 0x8604, 0xCC4A, 0x8606, 0xCC4B, 0x8607, 0xCC4C, 0x8608, 0xCC4D, 0x8609, 0xCC4E, 0x860A, 0xCC4F, 0x860B, 0xCC50, 0x860C, 0xCC51, 0x860D, 0xCC52, 0x860E, 0xCC53, 0x860F, 0xCC54, 0x8610, 0xCC55, 0x8612, 0xCC56, 0x8613, 0xCC57, 0x8614, 0xCC58, 0x8615, 0xCC59, 0x8617, 0xCC5A, 0x8618, 0xCC5B, 0x8619, 0xCC5C, 0x861A, 0xCC5D, 0x861B, 0xCC5E, 0x861C, 0xCC5F, 0x861D, 0xCC60, 0x861E, 0xCC61, 0x861F, 0xCC62, 0x8620, 0xCC63, 0x8621, 0xCC64, 0x8622, 0xCC65, 0x8623, 0xCC66, 0x8624, 0xCC67, 0x8625, 0xCC68, 0x8626, 0xCC69, 0x8628, 0xCC6A, 0x862A, 0xCC6B, 0x862B, 0xCC6C, 0x862C, 0xCC6D, 0x862D, 0xCC6E, 0x862E, 0xCC6F, 0x862F, 0xCC70, 0x8630, 0xCC71, 0x8631, 0xCC72, 0x8632, 0xCC73, 0x8633, 0xCC74, 0x8634, 0xCC75, 0x8635, 0xCC76, 0x8636, 0xCC77, 0x8637, 0xCC78, 0x8639, 0xCC79, 0x863A, 0xCC7A, 0x863B, 0xCC7B, 0x863D, 0xCC7C, 0x863E, 0xCC7D, 0x863F, 0xCC7E, 0x8640, 0xCC80, 0x8641, 0xCC81, 0x8642, 0xCC82, 0x8643, 0xCC83, 0x8644, 0xCC84, 0x8645, 0xCC85, 0x8646, 0xCC86, 0x8647, 0xCC87, 0x8648, 0xCC88, 0x8649, 0xCC89, 0x864A, 0xCC8A, 0x864B, 0xCC8B, 0x864C, 0xCC8C, 0x8652, 0xCC8D, 0x8653, 0xCC8E, 0x8655, 0xCC8F, 0x8656, 0xCC90, 0x8657, 0xCC91, 0x8658, 0xCC92, 0x8659, 0xCC93, 0x865B, 0xCC94, 0x865C, 0xCC95, 0x865D, 0xCC96, 0x865F, 0xCC97, 0x8660, 0xCC98, 0x8661, 0xCC99, 0x8663, 0xCC9A, 0x8664, 0xCC9B, 0x8665, 0xCC9C, 0x8666, 0xCC9D, 0x8667, 0xCC9E, 0x8668, 0xCC9F, 0x8669, 0xCCA0, 0x866A, 0xCCA1, 0x736D, 0xCCA2, 0x631E, 0xCCA3, 0x8E4B, 0xCCA4, 0x8E0F, 0xCCA5, 0x80CE, 0xCCA6, 0x82D4, 0xCCA7, 0x62AC, 0xCCA8, 0x53F0, 0xCCA9, 0x6CF0, 0xCCAA, 0x915E, 0xCCAB, 0x592A, 0xCCAC, 0x6001, 0xCCAD, 0x6C70, 0xCCAE, 0x574D, 0xCCAF, 0x644A, 0xCCB0, 0x8D2A, 0xCCB1, 0x762B, 0xCCB2, 0x6EE9, 0xCCB3, 0x575B, 0xCCB4, 0x6A80, 0xCCB5, 0x75F0, 0xCCB6, 0x6F6D, 0xCCB7, 0x8C2D, 0xCCB8, 0x8C08, 0xCCB9, 0x5766, 0xCCBA, 0x6BEF, 0xCCBB, 0x8892, 0xCCBC, 0x78B3, 0xCCBD, 0x63A2, 0xCCBE, 0x53F9, 0xCCBF, 0x70AD, 0xCCC0, 0x6C64, 0xCCC1, 0x5858, 0xCCC2, 0x642A, 0xCCC3, 0x5802, 0xCCC4, 0x68E0, 0xCCC5, 0x819B, 0xCCC6, 0x5510, 0xCCC7, 0x7CD6, 0xCCC8, 0x5018, 0xCCC9, 0x8EBA, 0xCCCA, 0x6DCC, 0xCCCB, 0x8D9F, 0xCCCC, 0x70EB, 0xCCCD, 0x638F, 0xCCCE, 0x6D9B, 0xCCCF, 0x6ED4, 0xCCD0, 0x7EE6, 0xCCD1, 0x8404, 0xCCD2, 0x6843, 0xCCD3, 0x9003, 0xCCD4, 0x6DD8, 0xCCD5, 0x9676, 0xCCD6, 0x8BA8, 0xCCD7, 0x5957, 0xCCD8, 0x7279, 0xCCD9, 0x85E4, 0xCCDA, 0x817E, 0xCCDB, 0x75BC, 0xCCDC, 0x8A8A, 0xCCDD, 0x68AF, 0xCCDE, 0x5254, 0xCCDF, 0x8E22, 0xCCE0, 0x9511, 0xCCE1, 0x63D0, 0xCCE2, 0x9898, 0xCCE3, 0x8E44, 0xCCE4, 0x557C, 0xCCE5, 0x4F53, 0xCCE6, 0x66FF, 0xCCE7, 0x568F, 0xCCE8, 0x60D5, 0xCCE9, 0x6D95, 0xCCEA, 0x5243, 0xCCEB, 0x5C49, 0xCCEC, 0x5929, 0xCCED, 0x6DFB, 0xCCEE, 0x586B, 0xCCEF, 0x7530, 0xCCF0, 0x751C, 0xCCF1, 0x606C, 0xCCF2, 0x8214, 0xCCF3, 0x8146, 0xCCF4, 0x6311, 0xCCF5, 0x6761, 0xCCF6, 0x8FE2, 0xCCF7, 0x773A, 0xCCF8, 0x8DF3, 0xCCF9, 0x8D34, 0xCCFA, 0x94C1, 0xCCFB, 0x5E16, 0xCCFC, 0x5385, 0xCCFD, 0x542C, 0xCCFE, 0x70C3, 0xCD40, 0x866D, 0xCD41, 0x866F, 0xCD42, 0x8670, 0xCD43, 0x8672, 0xCD44, 0x8673, 0xCD45, 0x8674, 0xCD46, 0x8675, 0xCD47, 0x8676, 0xCD48, 0x8677, 0xCD49, 0x8678, 0xCD4A, 0x8683, 0xCD4B, 0x8684, 0xCD4C, 0x8685, 0xCD4D, 0x8686, 0xCD4E, 0x8687, 0xCD4F, 0x8688, 0xCD50, 0x8689, 0xCD51, 0x868E, 0xCD52, 0x868F, 0xCD53, 0x8690, 0xCD54, 0x8691, 0xCD55, 0x8692, 0xCD56, 0x8694, 0xCD57, 0x8696, 0xCD58, 0x8697, 0xCD59, 0x8698, 0xCD5A, 0x8699, 0xCD5B, 0x869A, 0xCD5C, 0x869B, 0xCD5D, 0x869E, 0xCD5E, 0x869F, 0xCD5F, 0x86A0, 0xCD60, 0x86A1, 0xCD61, 0x86A2, 0xCD62, 0x86A5, 0xCD63, 0x86A6, 0xCD64, 0x86AB, 0xCD65, 0x86AD, 0xCD66, 0x86AE, 0xCD67, 0x86B2, 0xCD68, 0x86B3, 0xCD69, 0x86B7, 0xCD6A, 0x86B8, 0xCD6B, 0x86B9, 0xCD6C, 0x86BB, 0xCD6D, 0x86BC, 0xCD6E, 0x86BD, 0xCD6F, 0x86BE, 0xCD70, 0x86BF, 0xCD71, 0x86C1, 0xCD72, 0x86C2, 0xCD73, 0x86C3, 0xCD74, 0x86C5, 0xCD75, 0x86C8, 0xCD76, 0x86CC, 0xCD77, 0x86CD, 0xCD78, 0x86D2, 0xCD79, 0x86D3, 0xCD7A, 0x86D5, 0xCD7B, 0x86D6, 0xCD7C, 0x86D7, 0xCD7D, 0x86DA, 0xCD7E, 0x86DC, 0xCD80, 0x86DD, 0xCD81, 0x86E0, 0xCD82, 0x86E1, 0xCD83, 0x86E2, 0xCD84, 0x86E3, 0xCD85, 0x86E5, 0xCD86, 0x86E6, 0xCD87, 0x86E7, 0xCD88, 0x86E8, 0xCD89, 0x86EA, 0xCD8A, 0x86EB, 0xCD8B, 0x86EC, 0xCD8C, 0x86EF, 0xCD8D, 0x86F5, 0xCD8E, 0x86F6, 0xCD8F, 0x86F7, 0xCD90, 0x86FA, 0xCD91, 0x86FB, 0xCD92, 0x86FC, 0xCD93, 0x86FD, 0xCD94, 0x86FF, 0xCD95, 0x8701, 0xCD96, 0x8704, 0xCD97, 0x8705, 0xCD98, 0x8706, 0xCD99, 0x870B, 0xCD9A, 0x870C, 0xCD9B, 0x870E, 0xCD9C, 0x870F, 0xCD9D, 0x8710, 0xCD9E, 0x8711, 0xCD9F, 0x8714, 0xCDA0, 0x8716, 0xCDA1, 0x6C40, 0xCDA2, 0x5EF7, 0xCDA3, 0x505C, 0xCDA4, 0x4EAD, 0xCDA5, 0x5EAD, 0xCDA6, 0x633A, 0xCDA7, 0x8247, 0xCDA8, 0x901A, 0xCDA9, 0x6850, 0xCDAA, 0x916E, 0xCDAB, 0x77B3, 0xCDAC, 0x540C, 0xCDAD, 0x94DC, 0xCDAE, 0x5F64, 0xCDAF, 0x7AE5, 0xCDB0, 0x6876, 0xCDB1, 0x6345, 0xCDB2, 0x7B52, 0xCDB3, 0x7EDF, 0xCDB4, 0x75DB, 0xCDB5, 0x5077, 0xCDB6, 0x6295, 0xCDB7, 0x5934, 0xCDB8, 0x900F, 0xCDB9, 0x51F8, 0xCDBA, 0x79C3, 0xCDBB, 0x7A81, 0xCDBC, 0x56FE, 0xCDBD, 0x5F92, 0xCDBE, 0x9014, 0xCDBF, 0x6D82, 0xCDC0, 0x5C60, 0xCDC1, 0x571F, 0xCDC2, 0x5410, 0xCDC3, 0x5154, 0xCDC4, 0x6E4D, 0xCDC5, 0x56E2, 0xCDC6, 0x63A8, 0xCDC7, 0x9893, 0xCDC8, 0x817F, 0xCDC9, 0x8715, 0xCDCA, 0x892A, 0xCDCB, 0x9000, 0xCDCC, 0x541E, 0xCDCD, 0x5C6F, 0xCDCE, 0x81C0, 0xCDCF, 0x62D6, 0xCDD0, 0x6258, 0xCDD1, 0x8131, 0xCDD2, 0x9E35, 0xCDD3, 0x9640, 0xCDD4, 0x9A6E, 0xCDD5, 0x9A7C, 0xCDD6, 0x692D, 0xCDD7, 0x59A5, 0xCDD8, 0x62D3, 0xCDD9, 0x553E, 0xCDDA, 0x6316, 0xCDDB, 0x54C7, 0xCDDC, 0x86D9, 0xCDDD, 0x6D3C, 0xCDDE, 0x5A03, 0xCDDF, 0x74E6, 0xCDE0, 0x889C, 0xCDE1, 0x6B6A, 0xCDE2, 0x5916, 0xCDE3, 0x8C4C, 0xCDE4, 0x5F2F, 0xCDE5, 0x6E7E, 0xCDE6, 0x73A9, 0xCDE7, 0x987D, 0xCDE8, 0x4E38, 0xCDE9, 0x70F7, 0xCDEA, 0x5B8C, 0xCDEB, 0x7897, 0xCDEC, 0x633D, 0xCDED, 0x665A, 0xCDEE, 0x7696, 0xCDEF, 0x60CB, 0xCDF0, 0x5B9B, 0xCDF1, 0x5A49, 0xCDF2, 0x4E07, 0xCDF3, 0x8155, 0xCDF4, 0x6C6A, 0xCDF5, 0x738B, 0xCDF6, 0x4EA1, 0xCDF7, 0x6789, 0xCDF8, 0x7F51, 0xCDF9, 0x5F80, 0xCDFA, 0x65FA, 0xCDFB, 0x671B, 0xCDFC, 0x5FD8, 0xCDFD, 0x5984, 0xCDFE, 0x5A01, 0xCE40, 0x8719, 0xCE41, 0x871B, 0xCE42, 0x871D, 0xCE43, 0x871F, 0xCE44, 0x8720, 0xCE45, 0x8724, 0xCE46, 0x8726, 0xCE47, 0x8727, 0xCE48, 0x8728, 0xCE49, 0x872A, 0xCE4A, 0x872B, 0xCE4B, 0x872C, 0xCE4C, 0x872D, 0xCE4D, 0x872F, 0xCE4E, 0x8730, 0xCE4F, 0x8732, 0xCE50, 0x8733, 0xCE51, 0x8735, 0xCE52, 0x8736, 0xCE53, 0x8738, 0xCE54, 0x8739, 0xCE55, 0x873A, 0xCE56, 0x873C, 0xCE57, 0x873D, 0xCE58, 0x8740, 0xCE59, 0x8741, 0xCE5A, 0x8742, 0xCE5B, 0x8743, 0xCE5C, 0x8744, 0xCE5D, 0x8745, 0xCE5E, 0x8746, 0xCE5F, 0x874A, 0xCE60, 0x874B, 0xCE61, 0x874D, 0xCE62, 0x874F, 0xCE63, 0x8750, 0xCE64, 0x8751, 0xCE65, 0x8752, 0xCE66, 0x8754, 0xCE67, 0x8755, 0xCE68, 0x8756, 0xCE69, 0x8758, 0xCE6A, 0x875A, 0xCE6B, 0x875B, 0xCE6C, 0x875C, 0xCE6D, 0x875D, 0xCE6E, 0x875E, 0xCE6F, 0x875F, 0xCE70, 0x8761, 0xCE71, 0x8762, 0xCE72, 0x8766, 0xCE73, 0x8767, 0xCE74, 0x8768, 0xCE75, 0x8769, 0xCE76, 0x876A, 0xCE77, 0x876B, 0xCE78, 0x876C, 0xCE79, 0x876D, 0xCE7A, 0x876F, 0xCE7B, 0x8771, 0xCE7C, 0x8772, 0xCE7D, 0x8773, 0xCE7E, 0x8775, 0xCE80, 0x8777, 0xCE81, 0x8778, 0xCE82, 0x8779, 0xCE83, 0x877A, 0xCE84, 0x877F, 0xCE85, 0x8780, 0xCE86, 0x8781, 0xCE87, 0x8784, 0xCE88, 0x8786, 0xCE89, 0x8787, 0xCE8A, 0x8789, 0xCE8B, 0x878A, 0xCE8C, 0x878C, 0xCE8D, 0x878E, 0xCE8E, 0x878F, 0xCE8F, 0x8790, 0xCE90, 0x8791, 0xCE91, 0x8792, 0xCE92, 0x8794, 0xCE93, 0x8795, 0xCE94, 0x8796, 0xCE95, 0x8798, 0xCE96, 0x8799, 0xCE97, 0x879A, 0xCE98, 0x879B, 0xCE99, 0x879C, 0xCE9A, 0x879D, 0xCE9B, 0x879E, 0xCE9C, 0x87A0, 0xCE9D, 0x87A1, 0xCE9E, 0x87A2, 0xCE9F, 0x87A3, 0xCEA0, 0x87A4, 0xCEA1, 0x5DCD, 0xCEA2, 0x5FAE, 0xCEA3, 0x5371, 0xCEA4, 0x97E6, 0xCEA5, 0x8FDD, 0xCEA6, 0x6845, 0xCEA7, 0x56F4, 0xCEA8, 0x552F, 0xCEA9, 0x60DF, 0xCEAA, 0x4E3A, 0xCEAB, 0x6F4D, 0xCEAC, 0x7EF4, 0xCEAD, 0x82C7, 0xCEAE, 0x840E, 0xCEAF, 0x59D4, 0xCEB0, 0x4F1F, 0xCEB1, 0x4F2A, 0xCEB2, 0x5C3E, 0xCEB3, 0x7EAC, 0xCEB4, 0x672A, 0xCEB5, 0x851A, 0xCEB6, 0x5473, 0xCEB7, 0x754F, 0xCEB8, 0x80C3, 0xCEB9, 0x5582, 0xCEBA, 0x9B4F, 0xCEBB, 0x4F4D, 0xCEBC, 0x6E2D, 0xCEBD, 0x8C13, 0xCEBE, 0x5C09, 0xCEBF, 0x6170, 0xCEC0, 0x536B, 0xCEC1, 0x761F, 0xCEC2, 0x6E29, 0xCEC3, 0x868A, 0xCEC4, 0x6587, 0xCEC5, 0x95FB, 0xCEC6, 0x7EB9, 0xCEC7, 0x543B, 0xCEC8, 0x7A33, 0xCEC9, 0x7D0A, 0xCECA, 0x95EE, 0xCECB, 0x55E1, 0xCECC, 0x7FC1, 0xCECD, 0x74EE, 0xCECE, 0x631D, 0xCECF, 0x8717, 0xCED0, 0x6DA1, 0xCED1, 0x7A9D, 0xCED2, 0x6211, 0xCED3, 0x65A1, 0xCED4, 0x5367, 0xCED5, 0x63E1, 0xCED6, 0x6C83, 0xCED7, 0x5DEB, 0xCED8, 0x545C, 0xCED9, 0x94A8, 0xCEDA, 0x4E4C, 0xCEDB, 0x6C61, 0xCEDC, 0x8BEC, 0xCEDD, 0x5C4B, 0xCEDE, 0x65E0, 0xCEDF, 0x829C, 0xCEE0, 0x68A7, 0xCEE1, 0x543E, 0xCEE2, 0x5434, 0xCEE3, 0x6BCB, 0xCEE4, 0x6B66, 0xCEE5, 0x4E94, 0xCEE6, 0x6342, 0xCEE7, 0x5348, 0xCEE8, 0x821E, 0xCEE9, 0x4F0D, 0xCEEA, 0x4FAE, 0xCEEB, 0x575E, 0xCEEC, 0x620A, 0xCEED, 0x96FE, 0xCEEE, 0x6664, 0xCEEF, 0x7269, 0xCEF0, 0x52FF, 0xCEF1, 0x52A1, 0xCEF2, 0x609F, 0xCEF3, 0x8BEF, 0xCEF4, 0x6614, 0xCEF5, 0x7199, 0xCEF6, 0x6790, 0xCEF7, 0x897F, 0xCEF8, 0x7852, 0xCEF9, 0x77FD, 0xCEFA, 0x6670, 0xCEFB, 0x563B, 0xCEFC, 0x5438, 0xCEFD, 0x9521, 0xCEFE, 0x727A, 0xCF40, 0x87A5, 0xCF41, 0x87A6, 0xCF42, 0x87A7, 0xCF43, 0x87A9, 0xCF44, 0x87AA, 0xCF45, 0x87AE, 0xCF46, 0x87B0, 0xCF47, 0x87B1, 0xCF48, 0x87B2, 0xCF49, 0x87B4, 0xCF4A, 0x87B6, 0xCF4B, 0x87B7, 0xCF4C, 0x87B8, 0xCF4D, 0x87B9, 0xCF4E, 0x87BB, 0xCF4F, 0x87BC, 0xCF50, 0x87BE, 0xCF51, 0x87BF, 0xCF52, 0x87C1, 0xCF53, 0x87C2, 0xCF54, 0x87C3, 0xCF55, 0x87C4, 0xCF56, 0x87C5, 0xCF57, 0x87C7, 0xCF58, 0x87C8, 0xCF59, 0x87C9, 0xCF5A, 0x87CC, 0xCF5B, 0x87CD, 0xCF5C, 0x87CE, 0xCF5D, 0x87CF, 0xCF5E, 0x87D0, 0xCF5F, 0x87D4, 0xCF60, 0x87D5, 0xCF61, 0x87D6, 0xCF62, 0x87D7, 0xCF63, 0x87D8, 0xCF64, 0x87D9, 0xCF65, 0x87DA, 0xCF66, 0x87DC, 0xCF67, 0x87DD, 0xCF68, 0x87DE, 0xCF69, 0x87DF, 0xCF6A, 0x87E1, 0xCF6B, 0x87E2, 0xCF6C, 0x87E3, 0xCF6D, 0x87E4, 0xCF6E, 0x87E6, 0xCF6F, 0x87E7, 0xCF70, 0x87E8, 0xCF71, 0x87E9, 0xCF72, 0x87EB, 0xCF73, 0x87EC, 0xCF74, 0x87ED, 0xCF75, 0x87EF, 0xCF76, 0x87F0, 0xCF77, 0x87F1, 0xCF78, 0x87F2, 0xCF79, 0x87F3, 0xCF7A, 0x87F4, 0xCF7B, 0x87F5, 0xCF7C, 0x87F6, 0xCF7D, 0x87F7, 0xCF7E, 0x87F8, 0xCF80, 0x87FA, 0xCF81, 0x87FB, 0xCF82, 0x87FC, 0xCF83, 0x87FD, 0xCF84, 0x87FF, 0xCF85, 0x8800, 0xCF86, 0x8801, 0xCF87, 0x8802, 0xCF88, 0x8804, 0xCF89, 0x8805, 0xCF8A, 0x8806, 0xCF8B, 0x8807, 0xCF8C, 0x8808, 0xCF8D, 0x8809, 0xCF8E, 0x880B, 0xCF8F, 0x880C, 0xCF90, 0x880D, 0xCF91, 0x880E, 0xCF92, 0x880F, 0xCF93, 0x8810, 0xCF94, 0x8811, 0xCF95, 0x8812, 0xCF96, 0x8814, 0xCF97, 0x8817, 0xCF98, 0x8818, 0xCF99, 0x8819, 0xCF9A, 0x881A, 0xCF9B, 0x881C, 0xCF9C, 0x881D, 0xCF9D, 0x881E, 0xCF9E, 0x881F, 0xCF9F, 0x8820, 0xCFA0, 0x8823, 0xCFA1, 0x7A00, 0xCFA2, 0x606F, 0xCFA3, 0x5E0C, 0xCFA4, 0x6089, 0xCFA5, 0x819D, 0xCFA6, 0x5915, 0xCFA7, 0x60DC, 0xCFA8, 0x7184, 0xCFA9, 0x70EF, 0xCFAA, 0x6EAA, 0xCFAB, 0x6C50, 0xCFAC, 0x7280, 0xCFAD, 0x6A84, 0xCFAE, 0x88AD, 0xCFAF, 0x5E2D, 0xCFB0, 0x4E60, 0xCFB1, 0x5AB3, 0xCFB2, 0x559C, 0xCFB3, 0x94E3, 0xCFB4, 0x6D17, 0xCFB5, 0x7CFB, 0xCFB6, 0x9699, 0xCFB7, 0x620F, 0xCFB8, 0x7EC6, 0xCFB9, 0x778E, 0xCFBA, 0x867E, 0xCFBB, 0x5323, 0xCFBC, 0x971E, 0xCFBD, 0x8F96, 0xCFBE, 0x6687, 0xCFBF, 0x5CE1, 0xCFC0, 0x4FA0, 0xCFC1, 0x72ED, 0xCFC2, 0x4E0B, 0xCFC3, 0x53A6, 0xCFC4, 0x590F, 0xCFC5, 0x5413, 0xCFC6, 0x6380, 0xCFC7, 0x9528, 0xCFC8, 0x5148, 0xCFC9, 0x4ED9, 0xCFCA, 0x9C9C, 0xCFCB, 0x7EA4, 0xCFCC, 0x54B8, 0xCFCD, 0x8D24, 0xCFCE, 0x8854, 0xCFCF, 0x8237, 0xCFD0, 0x95F2, 0xCFD1, 0x6D8E, 0xCFD2, 0x5F26, 0xCFD3, 0x5ACC, 0xCFD4, 0x663E, 0xCFD5, 0x9669, 0xCFD6, 0x73B0, 0xCFD7, 0x732E, 0xCFD8, 0x53BF, 0xCFD9, 0x817A, 0xCFDA, 0x9985, 0xCFDB, 0x7FA1, 0xCFDC, 0x5BAA, 0xCFDD, 0x9677, 0xCFDE, 0x9650, 0xCFDF, 0x7EBF, 0xCFE0, 0x76F8, 0xCFE1, 0x53A2, 0xCFE2, 0x9576, 0xCFE3, 0x9999, 0xCFE4, 0x7BB1, 0xCFE5, 0x8944, 0xCFE6, 0x6E58, 0xCFE7, 0x4E61, 0xCFE8, 0x7FD4, 0xCFE9, 0x7965, 0xCFEA, 0x8BE6, 0xCFEB, 0x60F3, 0xCFEC, 0x54CD, 0xCFED, 0x4EAB, 0xCFEE, 0x9879, 0xCFEF, 0x5DF7, 0xCFF0, 0x6A61, 0xCFF1, 0x50CF, 0xCFF2, 0x5411, 0xCFF3, 0x8C61, 0xCFF4, 0x8427, 0xCFF5, 0x785D, 0xCFF6, 0x9704, 0xCFF7, 0x524A, 0xCFF8, 0x54EE, 0xCFF9, 0x56A3, 0xCFFA, 0x9500, 0xCFFB, 0x6D88, 0xCFFC, 0x5BB5, 0xCFFD, 0x6DC6, 0xCFFE, 0x6653, 0xD040, 0x8824, 0xD041, 0x8825, 0xD042, 0x8826, 0xD043, 0x8827, 0xD044, 0x8828, 0xD045, 0x8829, 0xD046, 0x882A, 0xD047, 0x882B, 0xD048, 0x882C, 0xD049, 0x882D, 0xD04A, 0x882E, 0xD04B, 0x882F, 0xD04C, 0x8830, 0xD04D, 0x8831, 0xD04E, 0x8833, 0xD04F, 0x8834, 0xD050, 0x8835, 0xD051, 0x8836, 0xD052, 0x8837, 0xD053, 0x8838, 0xD054, 0x883A, 0xD055, 0x883B, 0xD056, 0x883D, 0xD057, 0x883E, 0xD058, 0x883F, 0xD059, 0x8841, 0xD05A, 0x8842, 0xD05B, 0x8843, 0xD05C, 0x8846, 0xD05D, 0x8847, 0xD05E, 0x8848, 0xD05F, 0x8849, 0xD060, 0x884A, 0xD061, 0x884B, 0xD062, 0x884E, 0xD063, 0x884F, 0xD064, 0x8850, 0xD065, 0x8851, 0xD066, 0x8852, 0xD067, 0x8853, 0xD068, 0x8855, 0xD069, 0x8856, 0xD06A, 0x8858, 0xD06B, 0x885A, 0xD06C, 0x885B, 0xD06D, 0x885C, 0xD06E, 0x885D, 0xD06F, 0x885E, 0xD070, 0x885F, 0xD071, 0x8860, 0xD072, 0x8866, 0xD073, 0x8867, 0xD074, 0x886A, 0xD075, 0x886D, 0xD076, 0x886F, 0xD077, 0x8871, 0xD078, 0x8873, 0xD079, 0x8874, 0xD07A, 0x8875, 0xD07B, 0x8876, 0xD07C, 0x8878, 0xD07D, 0x8879, 0xD07E, 0x887A, 0xD080, 0x887B, 0xD081, 0x887C, 0xD082, 0x8880, 0xD083, 0x8883, 0xD084, 0x8886, 0xD085, 0x8887, 0xD086, 0x8889, 0xD087, 0x888A, 0xD088, 0x888C, 0xD089, 0x888E, 0xD08A, 0x888F, 0xD08B, 0x8890, 0xD08C, 0x8891, 0xD08D, 0x8893, 0xD08E, 0x8894, 0xD08F, 0x8895, 0xD090, 0x8897, 0xD091, 0x8898, 0xD092, 0x8899, 0xD093, 0x889A, 0xD094, 0x889B, 0xD095, 0x889D, 0xD096, 0x889E, 0xD097, 0x889F, 0xD098, 0x88A0, 0xD099, 0x88A1, 0xD09A, 0x88A3, 0xD09B, 0x88A5, 0xD09C, 0x88A6, 0xD09D, 0x88A7, 0xD09E, 0x88A8, 0xD09F, 0x88A9, 0xD0A0, 0x88AA, 0xD0A1, 0x5C0F, 0xD0A2, 0x5B5D, 0xD0A3, 0x6821, 0xD0A4, 0x8096, 0xD0A5, 0x5578, 0xD0A6, 0x7B11, 0xD0A7, 0x6548, 0xD0A8, 0x6954, 0xD0A9, 0x4E9B, 0xD0AA, 0x6B47, 0xD0AB, 0x874E, 0xD0AC, 0x978B, 0xD0AD, 0x534F, 0xD0AE, 0x631F, 0xD0AF, 0x643A, 0xD0B0, 0x90AA, 0xD0B1, 0x659C, 0xD0B2, 0x80C1, 0xD0B3, 0x8C10, 0xD0B4, 0x5199, 0xD0B5, 0x68B0, 0xD0B6, 0x5378, 0xD0B7, 0x87F9, 0xD0B8, 0x61C8, 0xD0B9, 0x6CC4, 0xD0BA, 0x6CFB, 0xD0BB, 0x8C22, 0xD0BC, 0x5C51, 0xD0BD, 0x85AA, 0xD0BE, 0x82AF, 0xD0BF, 0x950C, 0xD0C0, 0x6B23, 0xD0C1, 0x8F9B, 0xD0C2, 0x65B0, 0xD0C3, 0x5FFB, 0xD0C4, 0x5FC3, 0xD0C5, 0x4FE1, 0xD0C6, 0x8845, 0xD0C7, 0x661F, 0xD0C8, 0x8165, 0xD0C9, 0x7329, 0xD0CA, 0x60FA, 0xD0CB, 0x5174, 0xD0CC, 0x5211, 0xD0CD, 0x578B, 0xD0CE, 0x5F62, 0xD0CF, 0x90A2, 0xD0D0, 0x884C, 0xD0D1, 0x9192, 0xD0D2, 0x5E78, 0xD0D3, 0x674F, 0xD0D4, 0x6027, 0xD0D5, 0x59D3, 0xD0D6, 0x5144, 0xD0D7, 0x51F6, 0xD0D8, 0x80F8, 0xD0D9, 0x5308, 0xD0DA, 0x6C79, 0xD0DB, 0x96C4, 0xD0DC, 0x718A, 0xD0DD, 0x4F11, 0xD0DE, 0x4FEE, 0xD0DF, 0x7F9E, 0xD0E0, 0x673D, 0xD0E1, 0x55C5, 0xD0E2, 0x9508, 0xD0E3, 0x79C0, 0xD0E4, 0x8896, 0xD0E5, 0x7EE3, 0xD0E6, 0x589F, 0xD0E7, 0x620C, 0xD0E8, 0x9700, 0xD0E9, 0x865A, 0xD0EA, 0x5618, 0xD0EB, 0x987B, 0xD0EC, 0x5F90, 0xD0ED, 0x8BB8, 0xD0EE, 0x84C4, 0xD0EF, 0x9157, 0xD0F0, 0x53D9, 0xD0F1, 0x65ED, 0xD0F2, 0x5E8F, 0xD0F3, 0x755C, 0xD0F4, 0x6064, 0xD0F5, 0x7D6E, 0xD0F6, 0x5A7F, 0xD0F7, 0x7EEA, 0xD0F8, 0x7EED, 0xD0F9, 0x8F69, 0xD0FA, 0x55A7, 0xD0FB, 0x5BA3, 0xD0FC, 0x60AC, 0xD0FD, 0x65CB, 0xD0FE, 0x7384, 0xD140, 0x88AC, 0xD141, 0x88AE, 0xD142, 0x88AF, 0xD143, 0x88B0, 0xD144, 0x88B2, 0xD145, 0x88B3, 0xD146, 0x88B4, 0xD147, 0x88B5, 0xD148, 0x88B6, 0xD149, 0x88B8, 0xD14A, 0x88B9, 0xD14B, 0x88BA, 0xD14C, 0x88BB, 0xD14D, 0x88BD, 0xD14E, 0x88BE, 0xD14F, 0x88BF, 0xD150, 0x88C0, 0xD151, 0x88C3, 0xD152, 0x88C4, 0xD153, 0x88C7, 0xD154, 0x88C8, 0xD155, 0x88CA, 0xD156, 0x88CB, 0xD157, 0x88CC, 0xD158, 0x88CD, 0xD159, 0x88CF, 0xD15A, 0x88D0, 0xD15B, 0x88D1, 0xD15C, 0x88D3, 0xD15D, 0x88D6, 0xD15E, 0x88D7, 0xD15F, 0x88DA, 0xD160, 0x88DB, 0xD161, 0x88DC, 0xD162, 0x88DD, 0xD163, 0x88DE, 0xD164, 0x88E0, 0xD165, 0x88E1, 0xD166, 0x88E6, 0xD167, 0x88E7, 0xD168, 0x88E9, 0xD169, 0x88EA, 0xD16A, 0x88EB, 0xD16B, 0x88EC, 0xD16C, 0x88ED, 0xD16D, 0x88EE, 0xD16E, 0x88EF, 0xD16F, 0x88F2, 0xD170, 0x88F5, 0xD171, 0x88F6, 0xD172, 0x88F7, 0xD173, 0x88FA, 0xD174, 0x88FB, 0xD175, 0x88FD, 0xD176, 0x88FF, 0xD177, 0x8900, 0xD178, 0x8901, 0xD179, 0x8903, 0xD17A, 0x8904, 0xD17B, 0x8905, 0xD17C, 0x8906, 0xD17D, 0x8907, 0xD17E, 0x8908, 0xD180, 0x8909, 0xD181, 0x890B, 0xD182, 0x890C, 0xD183, 0x890D, 0xD184, 0x890E, 0xD185, 0x890F, 0xD186, 0x8911, 0xD187, 0x8914, 0xD188, 0x8915, 0xD189, 0x8916, 0xD18A, 0x8917, 0xD18B, 0x8918, 0xD18C, 0x891C, 0xD18D, 0x891D, 0xD18E, 0x891E, 0xD18F, 0x891F, 0xD190, 0x8920, 0xD191, 0x8922, 0xD192, 0x8923, 0xD193, 0x8924, 0xD194, 0x8926, 0xD195, 0x8927, 0xD196, 0x8928, 0xD197, 0x8929, 0xD198, 0x892C, 0xD199, 0x892D, 0xD19A, 0x892E, 0xD19B, 0x892F, 0xD19C, 0x8931, 0xD19D, 0x8932, 0xD19E, 0x8933, 0xD19F, 0x8935, 0xD1A0, 0x8937, 0xD1A1, 0x9009, 0xD1A2, 0x7663, 0xD1A3, 0x7729, 0xD1A4, 0x7EDA, 0xD1A5, 0x9774, 0xD1A6, 0x859B, 0xD1A7, 0x5B66, 0xD1A8, 0x7A74, 0xD1A9, 0x96EA, 0xD1AA, 0x8840, 0xD1AB, 0x52CB, 0xD1AC, 0x718F, 0xD1AD, 0x5FAA, 0xD1AE, 0x65EC, 0xD1AF, 0x8BE2, 0xD1B0, 0x5BFB, 0xD1B1, 0x9A6F, 0xD1B2, 0x5DE1, 0xD1B3, 0x6B89, 0xD1B4, 0x6C5B, 0xD1B5, 0x8BAD, 0xD1B6, 0x8BAF, 0xD1B7, 0x900A, 0xD1B8, 0x8FC5, 0xD1B9, 0x538B, 0xD1BA, 0x62BC, 0xD1BB, 0x9E26, 0xD1BC, 0x9E2D, 0xD1BD, 0x5440, 0xD1BE, 0x4E2B, 0xD1BF, 0x82BD, 0xD1C0, 0x7259, 0xD1C1, 0x869C, 0xD1C2, 0x5D16, 0xD1C3, 0x8859, 0xD1C4, 0x6DAF, 0xD1C5, 0x96C5, 0xD1C6, 0x54D1, 0xD1C7, 0x4E9A, 0xD1C8, 0x8BB6, 0xD1C9, 0x7109, 0xD1CA, 0x54BD, 0xD1CB, 0x9609, 0xD1CC, 0x70DF, 0xD1CD, 0x6DF9, 0xD1CE, 0x76D0, 0xD1CF, 0x4E25, 0xD1D0, 0x7814, 0xD1D1, 0x8712, 0xD1D2, 0x5CA9, 0xD1D3, 0x5EF6, 0xD1D4, 0x8A00, 0xD1D5, 0x989C, 0xD1D6, 0x960E, 0xD1D7, 0x708E, 0xD1D8, 0x6CBF, 0xD1D9, 0x5944, 0xD1DA, 0x63A9, 0xD1DB, 0x773C, 0xD1DC, 0x884D, 0xD1DD, 0x6F14, 0xD1DE, 0x8273, 0xD1DF, 0x5830, 0xD1E0, 0x71D5, 0xD1E1, 0x538C, 0xD1E2, 0x781A, 0xD1E3, 0x96C1, 0xD1E4, 0x5501, 0xD1E5, 0x5F66, 0xD1E6, 0x7130, 0xD1E7, 0x5BB4, 0xD1E8, 0x8C1A, 0xD1E9, 0x9A8C, 0xD1EA, 0x6B83, 0xD1EB, 0x592E, 0xD1EC, 0x9E2F, 0xD1ED, 0x79E7, 0xD1EE, 0x6768, 0xD1EF, 0x626C, 0xD1F0, 0x4F6F, 0xD1F1, 0x75A1, 0xD1F2, 0x7F8A, 0xD1F3, 0x6D0B, 0xD1F4, 0x9633, 0xD1F5, 0x6C27, 0xD1F6, 0x4EF0, 0xD1F7, 0x75D2, 0xD1F8, 0x517B, 0xD1F9, 0x6837, 0xD1FA, 0x6F3E, 0xD1FB, 0x9080, 0xD1FC, 0x8170, 0xD1FD, 0x5996, 0xD1FE, 0x7476, 0xD240, 0x8938, 0xD241, 0x8939, 0xD242, 0x893A, 0xD243, 0x893B, 0xD244, 0x893C, 0xD245, 0x893D, 0xD246, 0x893E, 0xD247, 0x893F, 0xD248, 0x8940, 0xD249, 0x8942, 0xD24A, 0x8943, 0xD24B, 0x8945, 0xD24C, 0x8946, 0xD24D, 0x8947, 0xD24E, 0x8948, 0xD24F, 0x8949, 0xD250, 0x894A, 0xD251, 0x894B, 0xD252, 0x894C, 0xD253, 0x894D, 0xD254, 0x894E, 0xD255, 0x894F, 0xD256, 0x8950, 0xD257, 0x8951, 0xD258, 0x8952, 0xD259, 0x8953, 0xD25A, 0x8954, 0xD25B, 0x8955, 0xD25C, 0x8956, 0xD25D, 0x8957, 0xD25E, 0x8958, 0xD25F, 0x8959, 0xD260, 0x895A, 0xD261, 0x895B, 0xD262, 0x895C, 0xD263, 0x895D, 0xD264, 0x8960, 0xD265, 0x8961, 0xD266, 0x8962, 0xD267, 0x8963, 0xD268, 0x8964, 0xD269, 0x8965, 0xD26A, 0x8967, 0xD26B, 0x8968, 0xD26C, 0x8969, 0xD26D, 0x896A, 0xD26E, 0x896B, 0xD26F, 0x896C, 0xD270, 0x896D, 0xD271, 0x896E, 0xD272, 0x896F, 0xD273, 0x8970, 0xD274, 0x8971, 0xD275, 0x8972, 0xD276, 0x8973, 0xD277, 0x8974, 0xD278, 0x8975, 0xD279, 0x8976, 0xD27A, 0x8977, 0xD27B, 0x8978, 0xD27C, 0x8979, 0xD27D, 0x897A, 0xD27E, 0x897C, 0xD280, 0x897D, 0xD281, 0x897E, 0xD282, 0x8980, 0xD283, 0x8982, 0xD284, 0x8984, 0xD285, 0x8985, 0xD286, 0x8987, 0xD287, 0x8988, 0xD288, 0x8989, 0xD289, 0x898A, 0xD28A, 0x898B, 0xD28B, 0x898C, 0xD28C, 0x898D, 0xD28D, 0x898E, 0xD28E, 0x898F, 0xD28F, 0x8990, 0xD290, 0x8991, 0xD291, 0x8992, 0xD292, 0x8993, 0xD293, 0x8994, 0xD294, 0x8995, 0xD295, 0x8996, 0xD296, 0x8997, 0xD297, 0x8998, 0xD298, 0x8999, 0xD299, 0x899A, 0xD29A, 0x899B, 0xD29B, 0x899C, 0xD29C, 0x899D, 0xD29D, 0x899E, 0xD29E, 0x899F, 0xD29F, 0x89A0, 0xD2A0, 0x89A1, 0xD2A1, 0x6447, 0xD2A2, 0x5C27, 0xD2A3, 0x9065, 0xD2A4, 0x7A91, 0xD2A5, 0x8C23, 0xD2A6, 0x59DA, 0xD2A7, 0x54AC, 0xD2A8, 0x8200, 0xD2A9, 0x836F, 0xD2AA, 0x8981, 0xD2AB, 0x8000, 0xD2AC, 0x6930, 0xD2AD, 0x564E, 0xD2AE, 0x8036, 0xD2AF, 0x7237, 0xD2B0, 0x91CE, 0xD2B1, 0x51B6, 0xD2B2, 0x4E5F, 0xD2B3, 0x9875, 0xD2B4, 0x6396, 0xD2B5, 0x4E1A, 0xD2B6, 0x53F6, 0xD2B7, 0x66F3, 0xD2B8, 0x814B, 0xD2B9, 0x591C, 0xD2BA, 0x6DB2, 0xD2BB, 0x4E00, 0xD2BC, 0x58F9, 0xD2BD, 0x533B, 0xD2BE, 0x63D6, 0xD2BF, 0x94F1, 0xD2C0, 0x4F9D, 0xD2C1, 0x4F0A, 0xD2C2, 0x8863, 0xD2C3, 0x9890, 0xD2C4, 0x5937, 0xD2C5, 0x9057, 0xD2C6, 0x79FB, 0xD2C7, 0x4EEA, 0xD2C8, 0x80F0, 0xD2C9, 0x7591, 0xD2CA, 0x6C82, 0xD2CB, 0x5B9C, 0xD2CC, 0x59E8, 0xD2CD, 0x5F5D, 0xD2CE, 0x6905, 0xD2CF, 0x8681, 0xD2D0, 0x501A, 0xD2D1, 0x5DF2, 0xD2D2, 0x4E59, 0xD2D3, 0x77E3, 0xD2D4, 0x4EE5, 0xD2D5, 0x827A, 0xD2D6, 0x6291, 0xD2D7, 0x6613, 0xD2D8, 0x9091, 0xD2D9, 0x5C79, 0xD2DA, 0x4EBF, 0xD2DB, 0x5F79, 0xD2DC, 0x81C6, 0xD2DD, 0x9038, 0xD2DE, 0x8084, 0xD2DF, 0x75AB, 0xD2E0, 0x4EA6, 0xD2E1, 0x88D4, 0xD2E2, 0x610F, 0xD2E3, 0x6BC5, 0xD2E4, 0x5FC6, 0xD2E5, 0x4E49, 0xD2E6, 0x76CA, 0xD2E7, 0x6EA2, 0xD2E8, 0x8BE3, 0xD2E9, 0x8BAE, 0xD2EA, 0x8C0A, 0xD2EB, 0x8BD1, 0xD2EC, 0x5F02, 0xD2ED, 0x7FFC, 0xD2EE, 0x7FCC, 0xD2EF, 0x7ECE, 0xD2F0, 0x8335, 0xD2F1, 0x836B, 0xD2F2, 0x56E0, 0xD2F3, 0x6BB7, 0xD2F4, 0x97F3, 0xD2F5, 0x9634, 0xD2F6, 0x59FB, 0xD2F7, 0x541F, 0xD2F8, 0x94F6, 0xD2F9, 0x6DEB, 0xD2FA, 0x5BC5, 0xD2FB, 0x996E, 0xD2FC, 0x5C39, 0xD2FD, 0x5F15, 0xD2FE, 0x9690, 0xD340, 0x89A2, 0xD341, 0x89A3, 0xD342, 0x89A4, 0xD343, 0x89A5, 0xD344, 0x89A6, 0xD345, 0x89A7, 0xD346, 0x89A8, 0xD347, 0x89A9, 0xD348, 0x89AA, 0xD349, 0x89AB, 0xD34A, 0x89AC, 0xD34B, 0x89AD, 0xD34C, 0x89AE, 0xD34D, 0x89AF, 0xD34E, 0x89B0, 0xD34F, 0x89B1, 0xD350, 0x89B2, 0xD351, 0x89B3, 0xD352, 0x89B4, 0xD353, 0x89B5, 0xD354, 0x89B6, 0xD355, 0x89B7, 0xD356, 0x89B8, 0xD357, 0x89B9, 0xD358, 0x89BA, 0xD359, 0x89BB, 0xD35A, 0x89BC, 0xD35B, 0x89BD, 0xD35C, 0x89BE, 0xD35D, 0x89BF, 0xD35E, 0x89C0, 0xD35F, 0x89C3, 0xD360, 0x89CD, 0xD361, 0x89D3, 0xD362, 0x89D4, 0xD363, 0x89D5, 0xD364, 0x89D7, 0xD365, 0x89D8, 0xD366, 0x89D9, 0xD367, 0x89DB, 0xD368, 0x89DD, 0xD369, 0x89DF, 0xD36A, 0x89E0, 0xD36B, 0x89E1, 0xD36C, 0x89E2, 0xD36D, 0x89E4, 0xD36E, 0x89E7, 0xD36F, 0x89E8, 0xD370, 0x89E9, 0xD371, 0x89EA, 0xD372, 0x89EC, 0xD373, 0x89ED, 0xD374, 0x89EE, 0xD375, 0x89F0, 0xD376, 0x89F1, 0xD377, 0x89F2, 0xD378, 0x89F4, 0xD379, 0x89F5, 0xD37A, 0x89F6, 0xD37B, 0x89F7, 0xD37C, 0x89F8, 0xD37D, 0x89F9, 0xD37E, 0x89FA, 0xD380, 0x89FB, 0xD381, 0x89FC, 0xD382, 0x89FD, 0xD383, 0x89FE, 0xD384, 0x89FF, 0xD385, 0x8A01, 0xD386, 0x8A02, 0xD387, 0x8A03, 0xD388, 0x8A04, 0xD389, 0x8A05, 0xD38A, 0x8A06, 0xD38B, 0x8A08, 0xD38C, 0x8A09, 0xD38D, 0x8A0A, 0xD38E, 0x8A0B, 0xD38F, 0x8A0C, 0xD390, 0x8A0D, 0xD391, 0x8A0E, 0xD392, 0x8A0F, 0xD393, 0x8A10, 0xD394, 0x8A11, 0xD395, 0x8A12, 0xD396, 0x8A13, 0xD397, 0x8A14, 0xD398, 0x8A15, 0xD399, 0x8A16, 0xD39A, 0x8A17, 0xD39B, 0x8A18, 0xD39C, 0x8A19, 0xD39D, 0x8A1A, 0xD39E, 0x8A1B, 0xD39F, 0x8A1C, 0xD3A0, 0x8A1D, 0xD3A1, 0x5370, 0xD3A2, 0x82F1, 0xD3A3, 0x6A31, 0xD3A4, 0x5A74, 0xD3A5, 0x9E70, 0xD3A6, 0x5E94, 0xD3A7, 0x7F28, 0xD3A8, 0x83B9, 0xD3A9, 0x8424, 0xD3AA, 0x8425, 0xD3AB, 0x8367, 0xD3AC, 0x8747, 0xD3AD, 0x8FCE, 0xD3AE, 0x8D62, 0xD3AF, 0x76C8, 0xD3B0, 0x5F71, 0xD3B1, 0x9896, 0xD3B2, 0x786C, 0xD3B3, 0x6620, 0xD3B4, 0x54DF, 0xD3B5, 0x62E5, 0xD3B6, 0x4F63, 0xD3B7, 0x81C3, 0xD3B8, 0x75C8, 0xD3B9, 0x5EB8, 0xD3BA, 0x96CD, 0xD3BB, 0x8E0A, 0xD3BC, 0x86F9, 0xD3BD, 0x548F, 0xD3BE, 0x6CF3, 0xD3BF, 0x6D8C, 0xD3C0, 0x6C38, 0xD3C1, 0x607F, 0xD3C2, 0x52C7, 0xD3C3, 0x7528, 0xD3C4, 0x5E7D, 0xD3C5, 0x4F18, 0xD3C6, 0x60A0, 0xD3C7, 0x5FE7, 0xD3C8, 0x5C24, 0xD3C9, 0x7531, 0xD3CA, 0x90AE, 0xD3CB, 0x94C0, 0xD3CC, 0x72B9, 0xD3CD, 0x6CB9, 0xD3CE, 0x6E38, 0xD3CF, 0x9149, 0xD3D0, 0x6709, 0xD3D1, 0x53CB, 0xD3D2, 0x53F3, 0xD3D3, 0x4F51, 0xD3D4, 0x91C9, 0xD3D5, 0x8BF1, 0xD3D6, 0x53C8, 0xD3D7, 0x5E7C, 0xD3D8, 0x8FC2, 0xD3D9, 0x6DE4, 0xD3DA, 0x4E8E, 0xD3DB, 0x76C2, 0xD3DC, 0x6986, 0xD3DD, 0x865E, 0xD3DE, 0x611A, 0xD3DF, 0x8206, 0xD3E0, 0x4F59, 0xD3E1, 0x4FDE, 0xD3E2, 0x903E, 0xD3E3, 0x9C7C, 0xD3E4, 0x6109, 0xD3E5, 0x6E1D, 0xD3E6, 0x6E14, 0xD3E7, 0x9685, 0xD3E8, 0x4E88, 0xD3E9, 0x5A31, 0xD3EA, 0x96E8, 0xD3EB, 0x4E0E, 0xD3EC, 0x5C7F, 0xD3ED, 0x79B9, 0xD3EE, 0x5B87, 0xD3EF, 0x8BED, 0xD3F0, 0x7FBD, 0xD3F1, 0x7389, 0xD3F2, 0x57DF, 0xD3F3, 0x828B, 0xD3F4, 0x90C1, 0xD3F5, 0x5401, 0xD3F6, 0x9047, 0xD3F7, 0x55BB, 0xD3F8, 0x5CEA, 0xD3F9, 0x5FA1, 0xD3FA, 0x6108, 0xD3FB, 0x6B32, 0xD3FC, 0x72F1, 0xD3FD, 0x80B2, 0xD3FE, 0x8A89, 0xD440, 0x8A1E, 0xD441, 0x8A1F, 0xD442, 0x8A20, 0xD443, 0x8A21, 0xD444, 0x8A22, 0xD445, 0x8A23, 0xD446, 0x8A24, 0xD447, 0x8A25, 0xD448, 0x8A26, 0xD449, 0x8A27, 0xD44A, 0x8A28, 0xD44B, 0x8A29, 0xD44C, 0x8A2A, 0xD44D, 0x8A2B, 0xD44E, 0x8A2C, 0xD44F, 0x8A2D, 0xD450, 0x8A2E, 0xD451, 0x8A2F, 0xD452, 0x8A30, 0xD453, 0x8A31, 0xD454, 0x8A32, 0xD455, 0x8A33, 0xD456, 0x8A34, 0xD457, 0x8A35, 0xD458, 0x8A36, 0xD459, 0x8A37, 0xD45A, 0x8A38, 0xD45B, 0x8A39, 0xD45C, 0x8A3A, 0xD45D, 0x8A3B, 0xD45E, 0x8A3C, 0xD45F, 0x8A3D, 0xD460, 0x8A3F, 0xD461, 0x8A40, 0xD462, 0x8A41, 0xD463, 0x8A42, 0xD464, 0x8A43, 0xD465, 0x8A44, 0xD466, 0x8A45, 0xD467, 0x8A46, 0xD468, 0x8A47, 0xD469, 0x8A49, 0xD46A, 0x8A4A, 0xD46B, 0x8A4B, 0xD46C, 0x8A4C, 0xD46D, 0x8A4D, 0xD46E, 0x8A4E, 0xD46F, 0x8A4F, 0xD470, 0x8A50, 0xD471, 0x8A51, 0xD472, 0x8A52, 0xD473, 0x8A53, 0xD474, 0x8A54, 0xD475, 0x8A55, 0xD476, 0x8A56, 0xD477, 0x8A57, 0xD478, 0x8A58, 0xD479, 0x8A59, 0xD47A, 0x8A5A, 0xD47B, 0x8A5B, 0xD47C, 0x8A5C, 0xD47D, 0x8A5D, 0xD47E, 0x8A5E, 0xD480, 0x8A5F, 0xD481, 0x8A60, 0xD482, 0x8A61, 0xD483, 0x8A62, 0xD484, 0x8A63, 0xD485, 0x8A64, 0xD486, 0x8A65, 0xD487, 0x8A66, 0xD488, 0x8A67, 0xD489, 0x8A68, 0xD48A, 0x8A69, 0xD48B, 0x8A6A, 0xD48C, 0x8A6B, 0xD48D, 0x8A6C, 0xD48E, 0x8A6D, 0xD48F, 0x8A6E, 0xD490, 0x8A6F, 0xD491, 0x8A70, 0xD492, 0x8A71, 0xD493, 0x8A72, 0xD494, 0x8A73, 0xD495, 0x8A74, 0xD496, 0x8A75, 0xD497, 0x8A76, 0xD498, 0x8A77, 0xD499, 0x8A78, 0xD49A, 0x8A7A, 0xD49B, 0x8A7B, 0xD49C, 0x8A7C, 0xD49D, 0x8A7D, 0xD49E, 0x8A7E, 0xD49F, 0x8A7F, 0xD4A0, 0x8A80, 0xD4A1, 0x6D74, 0xD4A2, 0x5BD3, 0xD4A3, 0x88D5, 0xD4A4, 0x9884, 0xD4A5, 0x8C6B, 0xD4A6, 0x9A6D, 0xD4A7, 0x9E33, 0xD4A8, 0x6E0A, 0xD4A9, 0x51A4, 0xD4AA, 0x5143, 0xD4AB, 0x57A3, 0xD4AC, 0x8881, 0xD4AD, 0x539F, 0xD4AE, 0x63F4, 0xD4AF, 0x8F95, 0xD4B0, 0x56ED, 0xD4B1, 0x5458, 0xD4B2, 0x5706, 0xD4B3, 0x733F, 0xD4B4, 0x6E90, 0xD4B5, 0x7F18, 0xD4B6, 0x8FDC, 0xD4B7, 0x82D1, 0xD4B8, 0x613F, 0xD4B9, 0x6028, 0xD4BA, 0x9662, 0xD4BB, 0x66F0, 0xD4BC, 0x7EA6, 0xD4BD, 0x8D8A, 0xD4BE, 0x8DC3, 0xD4BF, 0x94A5, 0xD4C0, 0x5CB3, 0xD4C1, 0x7CA4, 0xD4C2, 0x6708, 0xD4C3, 0x60A6, 0xD4C4, 0x9605, 0xD4C5, 0x8018, 0xD4C6, 0x4E91, 0xD4C7, 0x90E7, 0xD4C8, 0x5300, 0xD4C9, 0x9668, 0xD4CA, 0x5141, 0xD4CB, 0x8FD0, 0xD4CC, 0x8574, 0xD4CD, 0x915D, 0xD4CE, 0x6655, 0xD4CF, 0x97F5, 0xD4D0, 0x5B55, 0xD4D1, 0x531D, 0xD4D2, 0x7838, 0xD4D3, 0x6742, 0xD4D4, 0x683D, 0xD4D5, 0x54C9, 0xD4D6, 0x707E, 0xD4D7, 0x5BB0, 0xD4D8, 0x8F7D, 0xD4D9, 0x518D, 0xD4DA, 0x5728, 0xD4DB, 0x54B1, 0xD4DC, 0x6512, 0xD4DD, 0x6682, 0xD4DE, 0x8D5E, 0xD4DF, 0x8D43, 0xD4E0, 0x810F, 0xD4E1, 0x846C, 0xD4E2, 0x906D, 0xD4E3, 0x7CDF, 0xD4E4, 0x51FF, 0xD4E5, 0x85FB, 0xD4E6, 0x67A3, 0xD4E7, 0x65E9, 0xD4E8, 0x6FA1, 0xD4E9, 0x86A4, 0xD4EA, 0x8E81, 0xD4EB, 0x566A, 0xD4EC, 0x9020, 0xD4ED, 0x7682, 0xD4EE, 0x7076, 0xD4EF, 0x71E5, 0xD4F0, 0x8D23, 0xD4F1, 0x62E9, 0xD4F2, 0x5219, 0xD4F3, 0x6CFD, 0xD4F4, 0x8D3C, 0xD4F5, 0x600E, 0xD4F6, 0x589E, 0xD4F7, 0x618E, 0xD4F8, 0x66FE, 0xD4F9, 0x8D60, 0xD4FA, 0x624E, 0xD4FB, 0x55B3, 0xD4FC, 0x6E23, 0xD4FD, 0x672D, 0xD4FE, 0x8F67, 0xD540, 0x8A81, 0xD541, 0x8A82, 0xD542, 0x8A83, 0xD543, 0x8A84, 0xD544, 0x8A85, 0xD545, 0x8A86, 0xD546, 0x8A87, 0xD547, 0x8A88, 0xD548, 0x8A8B, 0xD549, 0x8A8C, 0xD54A, 0x8A8D, 0xD54B, 0x8A8E, 0xD54C, 0x8A8F, 0xD54D, 0x8A90, 0xD54E, 0x8A91, 0xD54F, 0x8A92, 0xD550, 0x8A94, 0xD551, 0x8A95, 0xD552, 0x8A96, 0xD553, 0x8A97, 0xD554, 0x8A98, 0xD555, 0x8A99, 0xD556, 0x8A9A, 0xD557, 0x8A9B, 0xD558, 0x8A9C, 0xD559, 0x8A9D, 0xD55A, 0x8A9E, 0xD55B, 0x8A9F, 0xD55C, 0x8AA0, 0xD55D, 0x8AA1, 0xD55E, 0x8AA2, 0xD55F, 0x8AA3, 0xD560, 0x8AA4, 0xD561, 0x8AA5, 0xD562, 0x8AA6, 0xD563, 0x8AA7, 0xD564, 0x8AA8, 0xD565, 0x8AA9, 0xD566, 0x8AAA, 0xD567, 0x8AAB, 0xD568, 0x8AAC, 0xD569, 0x8AAD, 0xD56A, 0x8AAE, 0xD56B, 0x8AAF, 0xD56C, 0x8AB0, 0xD56D, 0x8AB1, 0xD56E, 0x8AB2, 0xD56F, 0x8AB3, 0xD570, 0x8AB4, 0xD571, 0x8AB5, 0xD572, 0x8AB6, 0xD573, 0x8AB7, 0xD574, 0x8AB8, 0xD575, 0x8AB9, 0xD576, 0x8ABA, 0xD577, 0x8ABB, 0xD578, 0x8ABC, 0xD579, 0x8ABD, 0xD57A, 0x8ABE, 0xD57B, 0x8ABF, 0xD57C, 0x8AC0, 0xD57D, 0x8AC1, 0xD57E, 0x8AC2, 0xD580, 0x8AC3, 0xD581, 0x8AC4, 0xD582, 0x8AC5, 0xD583, 0x8AC6, 0xD584, 0x8AC7, 0xD585, 0x8AC8, 0xD586, 0x8AC9, 0xD587, 0x8ACA, 0xD588, 0x8ACB, 0xD589, 0x8ACC, 0xD58A, 0x8ACD, 0xD58B, 0x8ACE, 0xD58C, 0x8ACF, 0xD58D, 0x8AD0, 0xD58E, 0x8AD1, 0xD58F, 0x8AD2, 0xD590, 0x8AD3, 0xD591, 0x8AD4, 0xD592, 0x8AD5, 0xD593, 0x8AD6, 0xD594, 0x8AD7, 0xD595, 0x8AD8, 0xD596, 0x8AD9, 0xD597, 0x8ADA, 0xD598, 0x8ADB, 0xD599, 0x8ADC, 0xD59A, 0x8ADD, 0xD59B, 0x8ADE, 0xD59C, 0x8ADF, 0xD59D, 0x8AE0, 0xD59E, 0x8AE1, 0xD59F, 0x8AE2, 0xD5A0, 0x8AE3, 0xD5A1, 0x94E1, 0xD5A2, 0x95F8, 0xD5A3, 0x7728, 0xD5A4, 0x6805, 0xD5A5, 0x69A8, 0xD5A6, 0x548B, 0xD5A7, 0x4E4D, 0xD5A8, 0x70B8, 0xD5A9, 0x8BC8, 0xD5AA, 0x6458, 0xD5AB, 0x658B, 0xD5AC, 0x5B85, 0xD5AD, 0x7A84, 0xD5AE, 0x503A, 0xD5AF, 0x5BE8, 0xD5B0, 0x77BB, 0xD5B1, 0x6BE1, 0xD5B2, 0x8A79, 0xD5B3, 0x7C98, 0xD5B4, 0x6CBE, 0xD5B5, 0x76CF, 0xD5B6, 0x65A9, 0xD5B7, 0x8F97, 0xD5B8, 0x5D2D, 0xD5B9, 0x5C55, 0xD5BA, 0x8638, 0xD5BB, 0x6808, 0xD5BC, 0x5360, 0xD5BD, 0x6218, 0xD5BE, 0x7AD9, 0xD5BF, 0x6E5B, 0xD5C0, 0x7EFD, 0xD5C1, 0x6A1F, 0xD5C2, 0x7AE0, 0xD5C3, 0x5F70, 0xD5C4, 0x6F33, 0xD5C5, 0x5F20, 0xD5C6, 0x638C, 0xD5C7, 0x6DA8, 0xD5C8, 0x6756, 0xD5C9, 0x4E08, 0xD5CA, 0x5E10, 0xD5CB, 0x8D26, 0xD5CC, 0x4ED7, 0xD5CD, 0x80C0, 0xD5CE, 0x7634, 0xD5CF, 0x969C, 0xD5D0, 0x62DB, 0xD5D1, 0x662D, 0xD5D2, 0x627E, 0xD5D3, 0x6CBC, 0xD5D4, 0x8D75, 0xD5D5, 0x7167, 0xD5D6, 0x7F69, 0xD5D7, 0x5146, 0xD5D8, 0x8087, 0xD5D9, 0x53EC, 0xD5DA, 0x906E, 0xD5DB, 0x6298, 0xD5DC, 0x54F2, 0xD5DD, 0x86F0, 0xD5DE, 0x8F99, 0xD5DF, 0x8005, 0xD5E0, 0x9517, 0xD5E1, 0x8517, 0xD5E2, 0x8FD9, 0xD5E3, 0x6D59, 0xD5E4, 0x73CD, 0xD5E5, 0x659F, 0xD5E6, 0x771F, 0xD5E7, 0x7504, 0xD5E8, 0x7827, 0xD5E9, 0x81FB, 0xD5EA, 0x8D1E, 0xD5EB, 0x9488, 0xD5EC, 0x4FA6, 0xD5ED, 0x6795, 0xD5EE, 0x75B9, 0xD5EF, 0x8BCA, 0xD5F0, 0x9707, 0xD5F1, 0x632F, 0xD5F2, 0x9547, 0xD5F3, 0x9635, 0xD5F4, 0x84B8, 0xD5F5, 0x6323, 0xD5F6, 0x7741, 0xD5F7, 0x5F81, 0xD5F8, 0x72F0, 0xD5F9, 0x4E89, 0xD5FA, 0x6014, 0xD5FB, 0x6574, 0xD5FC, 0x62EF, 0xD5FD, 0x6B63, 0xD5FE, 0x653F, 0xD640, 0x8AE4, 0xD641, 0x8AE5, 0xD642, 0x8AE6, 0xD643, 0x8AE7, 0xD644, 0x8AE8, 0xD645, 0x8AE9, 0xD646, 0x8AEA, 0xD647, 0x8AEB, 0xD648, 0x8AEC, 0xD649, 0x8AED, 0xD64A, 0x8AEE, 0xD64B, 0x8AEF, 0xD64C, 0x8AF0, 0xD64D, 0x8AF1, 0xD64E, 0x8AF2, 0xD64F, 0x8AF3, 0xD650, 0x8AF4, 0xD651, 0x8AF5, 0xD652, 0x8AF6, 0xD653, 0x8AF7, 0xD654, 0x8AF8, 0xD655, 0x8AF9, 0xD656, 0x8AFA, 0xD657, 0x8AFB, 0xD658, 0x8AFC, 0xD659, 0x8AFD, 0xD65A, 0x8AFE, 0xD65B, 0x8AFF, 0xD65C, 0x8B00, 0xD65D, 0x8B01, 0xD65E, 0x8B02, 0xD65F, 0x8B03, 0xD660, 0x8B04, 0xD661, 0x8B05, 0xD662, 0x8B06, 0xD663, 0x8B08, 0xD664, 0x8B09, 0xD665, 0x8B0A, 0xD666, 0x8B0B, 0xD667, 0x8B0C, 0xD668, 0x8B0D, 0xD669, 0x8B0E, 0xD66A, 0x8B0F, 0xD66B, 0x8B10, 0xD66C, 0x8B11, 0xD66D, 0x8B12, 0xD66E, 0x8B13, 0xD66F, 0x8B14, 0xD670, 0x8B15, 0xD671, 0x8B16, 0xD672, 0x8B17, 0xD673, 0x8B18, 0xD674, 0x8B19, 0xD675, 0x8B1A, 0xD676, 0x8B1B, 0xD677, 0x8B1C, 0xD678, 0x8B1D, 0xD679, 0x8B1E, 0xD67A, 0x8B1F, 0xD67B, 0x8B20, 0xD67C, 0x8B21, 0xD67D, 0x8B22, 0xD67E, 0x8B23, 0xD680, 0x8B24, 0xD681, 0x8B25, 0xD682, 0x8B27, 0xD683, 0x8B28, 0xD684, 0x8B29, 0xD685, 0x8B2A, 0xD686, 0x8B2B, 0xD687, 0x8B2C, 0xD688, 0x8B2D, 0xD689, 0x8B2E, 0xD68A, 0x8B2F, 0xD68B, 0x8B30, 0xD68C, 0x8B31, 0xD68D, 0x8B32, 0xD68E, 0x8B33, 0xD68F, 0x8B34, 0xD690, 0x8B35, 0xD691, 0x8B36, 0xD692, 0x8B37, 0xD693, 0x8B38, 0xD694, 0x8B39, 0xD695, 0x8B3A, 0xD696, 0x8B3B, 0xD697, 0x8B3C, 0xD698, 0x8B3D, 0xD699, 0x8B3E, 0xD69A, 0x8B3F, 0xD69B, 0x8B40, 0xD69C, 0x8B41, 0xD69D, 0x8B42, 0xD69E, 0x8B43, 0xD69F, 0x8B44, 0xD6A0, 0x8B45, 0xD6A1, 0x5E27, 0xD6A2, 0x75C7, 0xD6A3, 0x90D1, 0xD6A4, 0x8BC1, 0xD6A5, 0x829D, 0xD6A6, 0x679D, 0xD6A7, 0x652F, 0xD6A8, 0x5431, 0xD6A9, 0x8718, 0xD6AA, 0x77E5, 0xD6AB, 0x80A2, 0xD6AC, 0x8102, 0xD6AD, 0x6C41, 0xD6AE, 0x4E4B, 0xD6AF, 0x7EC7, 0xD6B0, 0x804C, 0xD6B1, 0x76F4, 0xD6B2, 0x690D, 0xD6B3, 0x6B96, 0xD6B4, 0x6267, 0xD6B5, 0x503C, 0xD6B6, 0x4F84, 0xD6B7, 0x5740, 0xD6B8, 0x6307, 0xD6B9, 0x6B62, 0xD6BA, 0x8DBE, 0xD6BB, 0x53EA, 0xD6BC, 0x65E8, 0xD6BD, 0x7EB8, 0xD6BE, 0x5FD7, 0xD6BF, 0x631A, 0xD6C0, 0x63B7, 0xD6C1, 0x81F3, 0xD6C2, 0x81F4, 0xD6C3, 0x7F6E, 0xD6C4, 0x5E1C, 0xD6C5, 0x5CD9, 0xD6C6, 0x5236, 0xD6C7, 0x667A, 0xD6C8, 0x79E9, 0xD6C9, 0x7A1A, 0xD6CA, 0x8D28, 0xD6CB, 0x7099, 0xD6CC, 0x75D4, 0xD6CD, 0x6EDE, 0xD6CE, 0x6CBB, 0xD6CF, 0x7A92, 0xD6D0, 0x4E2D, 0xD6D1, 0x76C5, 0xD6D2, 0x5FE0, 0xD6D3, 0x949F, 0xD6D4, 0x8877, 0xD6D5, 0x7EC8, 0xD6D6, 0x79CD, 0xD6D7, 0x80BF, 0xD6D8, 0x91CD, 0xD6D9, 0x4EF2, 0xD6DA, 0x4F17, 0xD6DB, 0x821F, 0xD6DC, 0x5468, 0xD6DD, 0x5DDE, 0xD6DE, 0x6D32, 0xD6DF, 0x8BCC, 0xD6E0, 0x7CA5, 0xD6E1, 0x8F74, 0xD6E2, 0x8098, 0xD6E3, 0x5E1A, 0xD6E4, 0x5492, 0xD6E5, 0x76B1, 0xD6E6, 0x5B99, 0xD6E7, 0x663C, 0xD6E8, 0x9AA4, 0xD6E9, 0x73E0, 0xD6EA, 0x682A, 0xD6EB, 0x86DB, 0xD6EC, 0x6731, 0xD6ED, 0x732A, 0xD6EE, 0x8BF8, 0xD6EF, 0x8BDB, 0xD6F0, 0x9010, 0xD6F1, 0x7AF9, 0xD6F2, 0x70DB, 0xD6F3, 0x716E, 0xD6F4, 0x62C4, 0xD6F5, 0x77A9, 0xD6F6, 0x5631, 0xD6F7, 0x4E3B, 0xD6F8, 0x8457, 0xD6F9, 0x67F1, 0xD6FA, 0x52A9, 0xD6FB, 0x86C0, 0xD6FC, 0x8D2E, 0xD6FD, 0x94F8, 0xD6FE, 0x7B51, 0xD740, 0x8B46, 0xD741, 0x8B47, 0xD742, 0x8B48, 0xD743, 0x8B49, 0xD744, 0x8B4A, 0xD745, 0x8B4B, 0xD746, 0x8B4C, 0xD747, 0x8B4D, 0xD748, 0x8B4E, 0xD749, 0x8B4F, 0xD74A, 0x8B50, 0xD74B, 0x8B51, 0xD74C, 0x8B52, 0xD74D, 0x8B53, 0xD74E, 0x8B54, 0xD74F, 0x8B55, 0xD750, 0x8B56, 0xD751, 0x8B57, 0xD752, 0x8B58, 0xD753, 0x8B59, 0xD754, 0x8B5A, 0xD755, 0x8B5B, 0xD756, 0x8B5C, 0xD757, 0x8B5D, 0xD758, 0x8B5E, 0xD759, 0x8B5F, 0xD75A, 0x8B60, 0xD75B, 0x8B61, 0xD75C, 0x8B62, 0xD75D, 0x8B63, 0xD75E, 0x8B64, 0xD75F, 0x8B65, 0xD760, 0x8B67, 0xD761, 0x8B68, 0xD762, 0x8B69, 0xD763, 0x8B6A, 0xD764, 0x8B6B, 0xD765, 0x8B6D, 0xD766, 0x8B6E, 0xD767, 0x8B6F, 0xD768, 0x8B70, 0xD769, 0x8B71, 0xD76A, 0x8B72, 0xD76B, 0x8B73, 0xD76C, 0x8B74, 0xD76D, 0x8B75, 0xD76E, 0x8B76, 0xD76F, 0x8B77, 0xD770, 0x8B78, 0xD771, 0x8B79, 0xD772, 0x8B7A, 0xD773, 0x8B7B, 0xD774, 0x8B7C, 0xD775, 0x8B7D, 0xD776, 0x8B7E, 0xD777, 0x8B7F, 0xD778, 0x8B80, 0xD779, 0x8B81, 0xD77A, 0x8B82, 0xD77B, 0x8B83, 0xD77C, 0x8B84, 0xD77D, 0x8B85, 0xD77E, 0x8B86, 0xD780, 0x8B87, 0xD781, 0x8B88, 0xD782, 0x8B89, 0xD783, 0x8B8A, 0xD784, 0x8B8B, 0xD785, 0x8B8C, 0xD786, 0x8B8D, 0xD787, 0x8B8E, 0xD788, 0x8B8F, 0xD789, 0x8B90, 0xD78A, 0x8B91, 0xD78B, 0x8B92, 0xD78C, 0x8B93, 0xD78D, 0x8B94, 0xD78E, 0x8B95, 0xD78F, 0x8B96, 0xD790, 0x8B97, 0xD791, 0x8B98, 0xD792, 0x8B99, 0xD793, 0x8B9A, 0xD794, 0x8B9B, 0xD795, 0x8B9C, 0xD796, 0x8B9D, 0xD797, 0x8B9E, 0xD798, 0x8B9F, 0xD799, 0x8BAC, 0xD79A, 0x8BB1, 0xD79B, 0x8BBB, 0xD79C, 0x8BC7, 0xD79D, 0x8BD0, 0xD79E, 0x8BEA, 0xD79F, 0x8C09, 0xD7A0, 0x8C1E, 0xD7A1, 0x4F4F, 0xD7A2, 0x6CE8, 0xD7A3, 0x795D, 0xD7A4, 0x9A7B, 0xD7A5, 0x6293, 0xD7A6, 0x722A, 0xD7A7, 0x62FD, 0xD7A8, 0x4E13, 0xD7A9, 0x7816, 0xD7AA, 0x8F6C, 0xD7AB, 0x64B0, 0xD7AC, 0x8D5A, 0xD7AD, 0x7BC6, 0xD7AE, 0x6869, 0xD7AF, 0x5E84, 0xD7B0, 0x88C5, 0xD7B1, 0x5986, 0xD7B2, 0x649E, 0xD7B3, 0x58EE, 0xD7B4, 0x72B6, 0xD7B5, 0x690E, 0xD7B6, 0x9525, 0xD7B7, 0x8FFD, 0xD7B8, 0x8D58, 0xD7B9, 0x5760, 0xD7BA, 0x7F00, 0xD7BB, 0x8C06, 0xD7BC, 0x51C6, 0xD7BD, 0x6349, 0xD7BE, 0x62D9, 0xD7BF, 0x5353, 0xD7C0, 0x684C, 0xD7C1, 0x7422, 0xD7C2, 0x8301, 0xD7C3, 0x914C, 0xD7C4, 0x5544, 0xD7C5, 0x7740, 0xD7C6, 0x707C, 0xD7C7, 0x6D4A, 0xD7C8, 0x5179, 0xD7C9, 0x54A8, 0xD7CA, 0x8D44, 0xD7CB, 0x59FF, 0xD7CC, 0x6ECB, 0xD7CD, 0x6DC4, 0xD7CE, 0x5B5C, 0xD7CF, 0x7D2B, 0xD7D0, 0x4ED4, 0xD7D1, 0x7C7D, 0xD7D2, 0x6ED3, 0xD7D3, 0x5B50, 0xD7D4, 0x81EA, 0xD7D5, 0x6E0D, 0xD7D6, 0x5B57, 0xD7D7, 0x9B03, 0xD7D8, 0x68D5, 0xD7D9, 0x8E2A, 0xD7DA, 0x5B97, 0xD7DB, 0x7EFC, 0xD7DC, 0x603B, 0xD7DD, 0x7EB5, 0xD7DE, 0x90B9, 0xD7DF, 0x8D70, 0xD7E0, 0x594F, 0xD7E1, 0x63CD, 0xD7E2, 0x79DF, 0xD7E3, 0x8DB3, 0xD7E4, 0x5352, 0xD7E5, 0x65CF, 0xD7E6, 0x7956, 0xD7E7, 0x8BC5, 0xD7E8, 0x963B, 0xD7E9, 0x7EC4, 0xD7EA, 0x94BB, 0xD7EB, 0x7E82, 0xD7EC, 0x5634, 0xD7ED, 0x9189, 0xD7EE, 0x6700, 0xD7EF, 0x7F6A, 0xD7F0, 0x5C0A, 0xD7F1, 0x9075, 0xD7F2, 0x6628, 0xD7F3, 0x5DE6, 0xD7F4, 0x4F50, 0xD7F5, 0x67DE, 0xD7F6, 0x505A, 0xD7F7, 0x4F5C, 0xD7F8, 0x5750, 0xD7F9, 0x5EA7, 0xD840, 0x8C38, 0xD841, 0x8C39, 0xD842, 0x8C3A, 0xD843, 0x8C3B, 0xD844, 0x8C3C, 0xD845, 0x8C3D, 0xD846, 0x8C3E, 0xD847, 0x8C3F, 0xD848, 0x8C40, 0xD849, 0x8C42, 0xD84A, 0x8C43, 0xD84B, 0x8C44, 0xD84C, 0x8C45, 0xD84D, 0x8C48, 0xD84E, 0x8C4A, 0xD84F, 0x8C4B, 0xD850, 0x8C4D, 0xD851, 0x8C4E, 0xD852, 0x8C4F, 0xD853, 0x8C50, 0xD854, 0x8C51, 0xD855, 0x8C52, 0xD856, 0x8C53, 0xD857, 0x8C54, 0xD858, 0x8C56, 0xD859, 0x8C57, 0xD85A, 0x8C58, 0xD85B, 0x8C59, 0xD85C, 0x8C5B, 0xD85D, 0x8C5C, 0xD85E, 0x8C5D, 0xD85F, 0x8C5E, 0xD860, 0x8C5F, 0xD861, 0x8C60, 0xD862, 0x8C63, 0xD863, 0x8C64, 0xD864, 0x8C65, 0xD865, 0x8C66, 0xD866, 0x8C67, 0xD867, 0x8C68, 0xD868, 0x8C69, 0xD869, 0x8C6C, 0xD86A, 0x8C6D, 0xD86B, 0x8C6E, 0xD86C, 0x8C6F, 0xD86D, 0x8C70, 0xD86E, 0x8C71, 0xD86F, 0x8C72, 0xD870, 0x8C74, 0xD871, 0x8C75, 0xD872, 0x8C76, 0xD873, 0x8C77, 0xD874, 0x8C7B, 0xD875, 0x8C7C, 0xD876, 0x8C7D, 0xD877, 0x8C7E, 0xD878, 0x8C7F, 0xD879, 0x8C80, 0xD87A, 0x8C81, 0xD87B, 0x8C83, 0xD87C, 0x8C84, 0xD87D, 0x8C86, 0xD87E, 0x8C87, 0xD880, 0x8C88, 0xD881, 0x8C8B, 0xD882, 0x8C8D, 0xD883, 0x8C8E, 0xD884, 0x8C8F, 0xD885, 0x8C90, 0xD886, 0x8C91, 0xD887, 0x8C92, 0xD888, 0x8C93, 0xD889, 0x8C95, 0xD88A, 0x8C96, 0xD88B, 0x8C97, 0xD88C, 0x8C99, 0xD88D, 0x8C9A, 0xD88E, 0x8C9B, 0xD88F, 0x8C9C, 0xD890, 0x8C9D, 0xD891, 0x8C9E, 0xD892, 0x8C9F, 0xD893, 0x8CA0, 0xD894, 0x8CA1, 0xD895, 0x8CA2, 0xD896, 0x8CA3, 0xD897, 0x8CA4, 0xD898, 0x8CA5, 0xD899, 0x8CA6, 0xD89A, 0x8CA7, 0xD89B, 0x8CA8, 0xD89C, 0x8CA9, 0xD89D, 0x8CAA, 0xD89E, 0x8CAB, 0xD89F, 0x8CAC, 0xD8A0, 0x8CAD, 0xD8A1, 0x4E8D, 0xD8A2, 0x4E0C, 0xD8A3, 0x5140, 0xD8A4, 0x4E10, 0xD8A5, 0x5EFF, 0xD8A6, 0x5345, 0xD8A7, 0x4E15, 0xD8A8, 0x4E98, 0xD8A9, 0x4E1E, 0xD8AA, 0x9B32, 0xD8AB, 0x5B6C, 0xD8AC, 0x5669, 0xD8AD, 0x4E28, 0xD8AE, 0x79BA, 0xD8AF, 0x4E3F, 0xD8B0, 0x5315, 0xD8B1, 0x4E47, 0xD8B2, 0x592D, 0xD8B3, 0x723B, 0xD8B4, 0x536E, 0xD8B5, 0x6C10, 0xD8B6, 0x56DF, 0xD8B7, 0x80E4, 0xD8B8, 0x9997, 0xD8B9, 0x6BD3, 0xD8BA, 0x777E, 0xD8BB, 0x9F17, 0xD8BC, 0x4E36, 0xD8BD, 0x4E9F, 0xD8BE, 0x9F10, 0xD8BF, 0x4E5C, 0xD8C0, 0x4E69, 0xD8C1, 0x4E93, 0xD8C2, 0x8288, 0xD8C3, 0x5B5B, 0xD8C4, 0x556C, 0xD8C5, 0x560F, 0xD8C6, 0x4EC4, 0xD8C7, 0x538D, 0xD8C8, 0x539D, 0xD8C9, 0x53A3, 0xD8CA, 0x53A5, 0xD8CB, 0x53AE, 0xD8CC, 0x9765, 0xD8CD, 0x8D5D, 0xD8CE, 0x531A, 0xD8CF, 0x53F5, 0xD8D0, 0x5326, 0xD8D1, 0x532E, 0xD8D2, 0x533E, 0xD8D3, 0x8D5C, 0xD8D4, 0x5366, 0xD8D5, 0x5363, 0xD8D6, 0x5202, 0xD8D7, 0x5208, 0xD8D8, 0x520E, 0xD8D9, 0x522D, 0xD8DA, 0x5233, 0xD8DB, 0x523F, 0xD8DC, 0x5240, 0xD8DD, 0x524C, 0xD8DE, 0x525E, 0xD8DF, 0x5261, 0xD8E0, 0x525C, 0xD8E1, 0x84AF, 0xD8E2, 0x527D, 0xD8E3, 0x5282, 0xD8E4, 0x5281, 0xD8E5, 0x5290, 0xD8E6, 0x5293, 0xD8E7, 0x5182, 0xD8E8, 0x7F54, 0xD8E9, 0x4EBB, 0xD8EA, 0x4EC3, 0xD8EB, 0x4EC9, 0xD8EC, 0x4EC2, 0xD8ED, 0x4EE8, 0xD8EE, 0x4EE1, 0xD8EF, 0x4EEB, 0xD8F0, 0x4EDE, 0xD8F1, 0x4F1B, 0xD8F2, 0x4EF3, 0xD8F3, 0x4F22, 0xD8F4, 0x4F64, 0xD8F5, 0x4EF5, 0xD8F6, 0x4F25, 0xD8F7, 0x4F27, 0xD8F8, 0x4F09, 0xD8F9, 0x4F2B, 0xD8FA, 0x4F5E, 0xD8FB, 0x4F67, 0xD8FC, 0x6538, 0xD8FD, 0x4F5A, 0xD8FE, 0x4F5D, 0xD940, 0x8CAE, 0xD941, 0x8CAF, 0xD942, 0x8CB0, 0xD943, 0x8CB1, 0xD944, 0x8CB2, 0xD945, 0x8CB3, 0xD946, 0x8CB4, 0xD947, 0x8CB5, 0xD948, 0x8CB6, 0xD949, 0x8CB7, 0xD94A, 0x8CB8, 0xD94B, 0x8CB9, 0xD94C, 0x8CBA, 0xD94D, 0x8CBB, 0xD94E, 0x8CBC, 0xD94F, 0x8CBD, 0xD950, 0x8CBE, 0xD951, 0x8CBF, 0xD952, 0x8CC0, 0xD953, 0x8CC1, 0xD954, 0x8CC2, 0xD955, 0x8CC3, 0xD956, 0x8CC4, 0xD957, 0x8CC5, 0xD958, 0x8CC6, 0xD959, 0x8CC7, 0xD95A, 0x8CC8, 0xD95B, 0x8CC9, 0xD95C, 0x8CCA, 0xD95D, 0x8CCB, 0xD95E, 0x8CCC, 0xD95F, 0x8CCD, 0xD960, 0x8CCE, 0xD961, 0x8CCF, 0xD962, 0x8CD0, 0xD963, 0x8CD1, 0xD964, 0x8CD2, 0xD965, 0x8CD3, 0xD966, 0x8CD4, 0xD967, 0x8CD5, 0xD968, 0x8CD6, 0xD969, 0x8CD7, 0xD96A, 0x8CD8, 0xD96B, 0x8CD9, 0xD96C, 0x8CDA, 0xD96D, 0x8CDB, 0xD96E, 0x8CDC, 0xD96F, 0x8CDD, 0xD970, 0x8CDE, 0xD971, 0x8CDF, 0xD972, 0x8CE0, 0xD973, 0x8CE1, 0xD974, 0x8CE2, 0xD975, 0x8CE3, 0xD976, 0x8CE4, 0xD977, 0x8CE5, 0xD978, 0x8CE6, 0xD979, 0x8CE7, 0xD97A, 0x8CE8, 0xD97B, 0x8CE9, 0xD97C, 0x8CEA, 0xD97D, 0x8CEB, 0xD97E, 0x8CEC, 0xD980, 0x8CED, 0xD981, 0x8CEE, 0xD982, 0x8CEF, 0xD983, 0x8CF0, 0xD984, 0x8CF1, 0xD985, 0x8CF2, 0xD986, 0x8CF3, 0xD987, 0x8CF4, 0xD988, 0x8CF5, 0xD989, 0x8CF6, 0xD98A, 0x8CF7, 0xD98B, 0x8CF8, 0xD98C, 0x8CF9, 0xD98D, 0x8CFA, 0xD98E, 0x8CFB, 0xD98F, 0x8CFC, 0xD990, 0x8CFD, 0xD991, 0x8CFE, 0xD992, 0x8CFF, 0xD993, 0x8D00, 0xD994, 0x8D01, 0xD995, 0x8D02, 0xD996, 0x8D03, 0xD997, 0x8D04, 0xD998, 0x8D05, 0xD999, 0x8D06, 0xD99A, 0x8D07, 0xD99B, 0x8D08, 0xD99C, 0x8D09, 0xD99D, 0x8D0A, 0xD99E, 0x8D0B, 0xD99F, 0x8D0C, 0xD9A0, 0x8D0D, 0xD9A1, 0x4F5F, 0xD9A2, 0x4F57, 0xD9A3, 0x4F32, 0xD9A4, 0x4F3D, 0xD9A5, 0x4F76, 0xD9A6, 0x4F74, 0xD9A7, 0x4F91, 0xD9A8, 0x4F89, 0xD9A9, 0x4F83, 0xD9AA, 0x4F8F, 0xD9AB, 0x4F7E, 0xD9AC, 0x4F7B, 0xD9AD, 0x4FAA, 0xD9AE, 0x4F7C, 0xD9AF, 0x4FAC, 0xD9B0, 0x4F94, 0xD9B1, 0x4FE6, 0xD9B2, 0x4FE8, 0xD9B3, 0x4FEA, 0xD9B4, 0x4FC5, 0xD9B5, 0x4FDA, 0xD9B6, 0x4FE3, 0xD9B7, 0x4FDC, 0xD9B8, 0x4FD1, 0xD9B9, 0x4FDF, 0xD9BA, 0x4FF8, 0xD9BB, 0x5029, 0xD9BC, 0x504C, 0xD9BD, 0x4FF3, 0xD9BE, 0x502C, 0xD9BF, 0x500F, 0xD9C0, 0x502E, 0xD9C1, 0x502D, 0xD9C2, 0x4FFE, 0xD9C3, 0x501C, 0xD9C4, 0x500C, 0xD9C5, 0x5025, 0xD9C6, 0x5028, 0xD9C7, 0x507E, 0xD9C8, 0x5043, 0xD9C9, 0x5055, 0xD9CA, 0x5048, 0xD9CB, 0x504E, 0xD9CC, 0x506C, 0xD9CD, 0x507B, 0xD9CE, 0x50A5, 0xD9CF, 0x50A7, 0xD9D0, 0x50A9, 0xD9D1, 0x50BA, 0xD9D2, 0x50D6, 0xD9D3, 0x5106, 0xD9D4, 0x50ED, 0xD9D5, 0x50EC, 0xD9D6, 0x50E6, 0xD9D7, 0x50EE, 0xD9D8, 0x5107, 0xD9D9, 0x510B, 0xD9DA, 0x4EDD, 0xD9DB, 0x6C3D, 0xD9DC, 0x4F58, 0xD9DD, 0x4F65, 0xD9DE, 0x4FCE, 0xD9DF, 0x9FA0, 0xD9E0, 0x6C46, 0xD9E1, 0x7C74, 0xD9E2, 0x516E, 0xD9E3, 0x5DFD, 0xD9E4, 0x9EC9, 0xD9E5, 0x9998, 0xD9E6, 0x5181, 0xD9E7, 0x5914, 0xD9E8, 0x52F9, 0xD9E9, 0x530D, 0xD9EA, 0x8A07, 0xD9EB, 0x5310, 0xD9EC, 0x51EB, 0xD9ED, 0x5919, 0xD9EE, 0x5155, 0xD9EF, 0x4EA0, 0xD9F0, 0x5156, 0xD9F1, 0x4EB3, 0xD9F2, 0x886E, 0xD9F3, 0x88A4, 0xD9F4, 0x4EB5, 0xD9F5, 0x8114, 0xD9F6, 0x88D2, 0xD9F7, 0x7980, 0xD9F8, 0x5B34, 0xD9F9, 0x8803, 0xD9FA, 0x7FB8, 0xD9FB, 0x51AB, 0xD9FC, 0x51B1, 0xD9FD, 0x51BD, 0xD9FE, 0x51BC, 0xDA40, 0x8D0E, 0xDA41, 0x8D0F, 0xDA42, 0x8D10, 0xDA43, 0x8D11, 0xDA44, 0x8D12, 0xDA45, 0x8D13, 0xDA46, 0x8D14, 0xDA47, 0x8D15, 0xDA48, 0x8D16, 0xDA49, 0x8D17, 0xDA4A, 0x8D18, 0xDA4B, 0x8D19, 0xDA4C, 0x8D1A, 0xDA4D, 0x8D1B, 0xDA4E, 0x8D1C, 0xDA4F, 0x8D20, 0xDA50, 0x8D51, 0xDA51, 0x8D52, 0xDA52, 0x8D57, 0xDA53, 0x8D5F, 0xDA54, 0x8D65, 0xDA55, 0x8D68, 0xDA56, 0x8D69, 0xDA57, 0x8D6A, 0xDA58, 0x8D6C, 0xDA59, 0x8D6E, 0xDA5A, 0x8D6F, 0xDA5B, 0x8D71, 0xDA5C, 0x8D72, 0xDA5D, 0x8D78, 0xDA5E, 0x8D79, 0xDA5F, 0x8D7A, 0xDA60, 0x8D7B, 0xDA61, 0x8D7C, 0xDA62, 0x8D7D, 0xDA63, 0x8D7E, 0xDA64, 0x8D7F, 0xDA65, 0x8D80, 0xDA66, 0x8D82, 0xDA67, 0x8D83, 0xDA68, 0x8D86, 0xDA69, 0x8D87, 0xDA6A, 0x8D88, 0xDA6B, 0x8D89, 0xDA6C, 0x8D8C, 0xDA6D, 0x8D8D, 0xDA6E, 0x8D8E, 0xDA6F, 0x8D8F, 0xDA70, 0x8D90, 0xDA71, 0x8D92, 0xDA72, 0x8D93, 0xDA73, 0x8D95, 0xDA74, 0x8D96, 0xDA75, 0x8D97, 0xDA76, 0x8D98, 0xDA77, 0x8D99, 0xDA78, 0x8D9A, 0xDA79, 0x8D9B, 0xDA7A, 0x8D9C, 0xDA7B, 0x8D9D, 0xDA7C, 0x8D9E, 0xDA7D, 0x8DA0, 0xDA7E, 0x8DA1, 0xDA80, 0x8DA2, 0xDA81, 0x8DA4, 0xDA82, 0x8DA5, 0xDA83, 0x8DA6, 0xDA84, 0x8DA7, 0xDA85, 0x8DA8, 0xDA86, 0x8DA9, 0xDA87, 0x8DAA, 0xDA88, 0x8DAB, 0xDA89, 0x8DAC, 0xDA8A, 0x8DAD, 0xDA8B, 0x8DAE, 0xDA8C, 0x8DAF, 0xDA8D, 0x8DB0, 0xDA8E, 0x8DB2, 0xDA8F, 0x8DB6, 0xDA90, 0x8DB7, 0xDA91, 0x8DB9, 0xDA92, 0x8DBB, 0xDA93, 0x8DBD, 0xDA94, 0x8DC0, 0xDA95, 0x8DC1, 0xDA96, 0x8DC2, 0xDA97, 0x8DC5, 0xDA98, 0x8DC7, 0xDA99, 0x8DC8, 0xDA9A, 0x8DC9, 0xDA9B, 0x8DCA, 0xDA9C, 0x8DCD, 0xDA9D, 0x8DD0, 0xDA9E, 0x8DD2, 0xDA9F, 0x8DD3, 0xDAA0, 0x8DD4, 0xDAA1, 0x51C7, 0xDAA2, 0x5196, 0xDAA3, 0x51A2, 0xDAA4, 0x51A5, 0xDAA5, 0x8BA0, 0xDAA6, 0x8BA6, 0xDAA7, 0x8BA7, 0xDAA8, 0x8BAA, 0xDAA9, 0x8BB4, 0xDAAA, 0x8BB5, 0xDAAB, 0x8BB7, 0xDAAC, 0x8BC2, 0xDAAD, 0x8BC3, 0xDAAE, 0x8BCB, 0xDAAF, 0x8BCF, 0xDAB0, 0x8BCE, 0xDAB1, 0x8BD2, 0xDAB2, 0x8BD3, 0xDAB3, 0x8BD4, 0xDAB4, 0x8BD6, 0xDAB5, 0x8BD8, 0xDAB6, 0x8BD9, 0xDAB7, 0x8BDC, 0xDAB8, 0x8BDF, 0xDAB9, 0x8BE0, 0xDABA, 0x8BE4, 0xDABB, 0x8BE8, 0xDABC, 0x8BE9, 0xDABD, 0x8BEE, 0xDABE, 0x8BF0, 0xDABF, 0x8BF3, 0xDAC0, 0x8BF6, 0xDAC1, 0x8BF9, 0xDAC2, 0x8BFC, 0xDAC3, 0x8BFF, 0xDAC4, 0x8C00, 0xDAC5, 0x8C02, 0xDAC6, 0x8C04, 0xDAC7, 0x8C07, 0xDAC8, 0x8C0C, 0xDAC9, 0x8C0F, 0xDACA, 0x8C11, 0xDACB, 0x8C12, 0xDACC, 0x8C14, 0xDACD, 0x8C15, 0xDACE, 0x8C16, 0xDACF, 0x8C19, 0xDAD0, 0x8C1B, 0xDAD1, 0x8C18, 0xDAD2, 0x8C1D, 0xDAD3, 0x8C1F, 0xDAD4, 0x8C20, 0xDAD5, 0x8C21, 0xDAD6, 0x8C25, 0xDAD7, 0x8C27, 0xDAD8, 0x8C2A, 0xDAD9, 0x8C2B, 0xDADA, 0x8C2E, 0xDADB, 0x8C2F, 0xDADC, 0x8C32, 0xDADD, 0x8C33, 0xDADE, 0x8C35, 0xDADF, 0x8C36, 0xDAE0, 0x5369, 0xDAE1, 0x537A, 0xDAE2, 0x961D, 0xDAE3, 0x9622, 0xDAE4, 0x9621, 0xDAE5, 0x9631, 0xDAE6, 0x962A, 0xDAE7, 0x963D, 0xDAE8, 0x963C, 0xDAE9, 0x9642, 0xDAEA, 0x9649, 0xDAEB, 0x9654, 0xDAEC, 0x965F, 0xDAED, 0x9667, 0xDAEE, 0x966C, 0xDAEF, 0x9672, 0xDAF0, 0x9674, 0xDAF1, 0x9688, 0xDAF2, 0x968D, 0xDAF3, 0x9697, 0xDAF4, 0x96B0, 0xDAF5, 0x9097, 0xDAF6, 0x909B, 0xDAF7, 0x909D, 0xDAF8, 0x9099, 0xDAF9, 0x90AC, 0xDAFA, 0x90A1, 0xDAFB, 0x90B4, 0xDAFC, 0x90B3, 0xDAFD, 0x90B6, 0xDAFE, 0x90BA, 0xDB40, 0x8DD5, 0xDB41, 0x8DD8, 0xDB42, 0x8DD9, 0xDB43, 0x8DDC, 0xDB44, 0x8DE0, 0xDB45, 0x8DE1, 0xDB46, 0x8DE2, 0xDB47, 0x8DE5, 0xDB48, 0x8DE6, 0xDB49, 0x8DE7, 0xDB4A, 0x8DE9, 0xDB4B, 0x8DED, 0xDB4C, 0x8DEE, 0xDB4D, 0x8DF0, 0xDB4E, 0x8DF1, 0xDB4F, 0x8DF2, 0xDB50, 0x8DF4, 0xDB51, 0x8DF6, 0xDB52, 0x8DFC, 0xDB53, 0x8DFE, 0xDB54, 0x8DFF, 0xDB55, 0x8E00, 0xDB56, 0x8E01, 0xDB57, 0x8E02, 0xDB58, 0x8E03, 0xDB59, 0x8E04, 0xDB5A, 0x8E06, 0xDB5B, 0x8E07, 0xDB5C, 0x8E08, 0xDB5D, 0x8E0B, 0xDB5E, 0x8E0D, 0xDB5F, 0x8E0E, 0xDB60, 0x8E10, 0xDB61, 0x8E11, 0xDB62, 0x8E12, 0xDB63, 0x8E13, 0xDB64, 0x8E15, 0xDB65, 0x8E16, 0xDB66, 0x8E17, 0xDB67, 0x8E18, 0xDB68, 0x8E19, 0xDB69, 0x8E1A, 0xDB6A, 0x8E1B, 0xDB6B, 0x8E1C, 0xDB6C, 0x8E20, 0xDB6D, 0x8E21, 0xDB6E, 0x8E24, 0xDB6F, 0x8E25, 0xDB70, 0x8E26, 0xDB71, 0x8E27, 0xDB72, 0x8E28, 0xDB73, 0x8E2B, 0xDB74, 0x8E2D, 0xDB75, 0x8E30, 0xDB76, 0x8E32, 0xDB77, 0x8E33, 0xDB78, 0x8E34, 0xDB79, 0x8E36, 0xDB7A, 0x8E37, 0xDB7B, 0x8E38, 0xDB7C, 0x8E3B, 0xDB7D, 0x8E3C, 0xDB7E, 0x8E3E, 0xDB80, 0x8E3F, 0xDB81, 0x8E43, 0xDB82, 0x8E45, 0xDB83, 0x8E46, 0xDB84, 0x8E4C, 0xDB85, 0x8E4D, 0xDB86, 0x8E4E, 0xDB87, 0x8E4F, 0xDB88, 0x8E50, 0xDB89, 0x8E53, 0xDB8A, 0x8E54, 0xDB8B, 0x8E55, 0xDB8C, 0x8E56, 0xDB8D, 0x8E57, 0xDB8E, 0x8E58, 0xDB8F, 0x8E5A, 0xDB90, 0x8E5B, 0xDB91, 0x8E5C, 0xDB92, 0x8E5D, 0xDB93, 0x8E5E, 0xDB94, 0x8E5F, 0xDB95, 0x8E60, 0xDB96, 0x8E61, 0xDB97, 0x8E62, 0xDB98, 0x8E63, 0xDB99, 0x8E64, 0xDB9A, 0x8E65, 0xDB9B, 0x8E67, 0xDB9C, 0x8E68, 0xDB9D, 0x8E6A, 0xDB9E, 0x8E6B, 0xDB9F, 0x8E6E, 0xDBA0, 0x8E71, 0xDBA1, 0x90B8, 0xDBA2, 0x90B0, 0xDBA3, 0x90CF, 0xDBA4, 0x90C5, 0xDBA5, 0x90BE, 0xDBA6, 0x90D0, 0xDBA7, 0x90C4, 0xDBA8, 0x90C7, 0xDBA9, 0x90D3, 0xDBAA, 0x90E6, 0xDBAB, 0x90E2, 0xDBAC, 0x90DC, 0xDBAD, 0x90D7, 0xDBAE, 0x90DB, 0xDBAF, 0x90EB, 0xDBB0, 0x90EF, 0xDBB1, 0x90FE, 0xDBB2, 0x9104, 0xDBB3, 0x9122, 0xDBB4, 0x911E, 0xDBB5, 0x9123, 0xDBB6, 0x9131, 0xDBB7, 0x912F, 0xDBB8, 0x9139, 0xDBB9, 0x9143, 0xDBBA, 0x9146, 0xDBBB, 0x520D, 0xDBBC, 0x5942, 0xDBBD, 0x52A2, 0xDBBE, 0x52AC, 0xDBBF, 0x52AD, 0xDBC0, 0x52BE, 0xDBC1, 0x54FF, 0xDBC2, 0x52D0, 0xDBC3, 0x52D6, 0xDBC4, 0x52F0, 0xDBC5, 0x53DF, 0xDBC6, 0x71EE, 0xDBC7, 0x77CD, 0xDBC8, 0x5EF4, 0xDBC9, 0x51F5, 0xDBCA, 0x51FC, 0xDBCB, 0x9B2F, 0xDBCC, 0x53B6, 0xDBCD, 0x5F01, 0xDBCE, 0x755A, 0xDBCF, 0x5DEF, 0xDBD0, 0x574C, 0xDBD1, 0x57A9, 0xDBD2, 0x57A1, 0xDBD3, 0x587E, 0xDBD4, 0x58BC, 0xDBD5, 0x58C5, 0xDBD6, 0x58D1, 0xDBD7, 0x5729, 0xDBD8, 0x572C, 0xDBD9, 0x572A, 0xDBDA, 0x5733, 0xDBDB, 0x5739, 0xDBDC, 0x572E, 0xDBDD, 0x572F, 0xDBDE, 0x575C, 0xDBDF, 0x573B, 0xDBE0, 0x5742, 0xDBE1, 0x5769, 0xDBE2, 0x5785, 0xDBE3, 0x576B, 0xDBE4, 0x5786, 0xDBE5, 0x577C, 0xDBE6, 0x577B, 0xDBE7, 0x5768, 0xDBE8, 0x576D, 0xDBE9, 0x5776, 0xDBEA, 0x5773, 0xDBEB, 0x57AD, 0xDBEC, 0x57A4, 0xDBED, 0x578C, 0xDBEE, 0x57B2, 0xDBEF, 0x57CF, 0xDBF0, 0x57A7, 0xDBF1, 0x57B4, 0xDBF2, 0x5793, 0xDBF3, 0x57A0, 0xDBF4, 0x57D5, 0xDBF5, 0x57D8, 0xDBF6, 0x57DA, 0xDBF7, 0x57D9, 0xDBF8, 0x57D2, 0xDBF9, 0x57B8, 0xDBFA, 0x57F4, 0xDBFB, 0x57EF, 0xDBFC, 0x57F8, 0xDBFD, 0x57E4, 0xDBFE, 0x57DD, 0xDC40, 0x8E73, 0xDC41, 0x8E75, 0xDC42, 0x8E77, 0xDC43, 0x8E78, 0xDC44, 0x8E79, 0xDC45, 0x8E7A, 0xDC46, 0x8E7B, 0xDC47, 0x8E7D, 0xDC48, 0x8E7E, 0xDC49, 0x8E80, 0xDC4A, 0x8E82, 0xDC4B, 0x8E83, 0xDC4C, 0x8E84, 0xDC4D, 0x8E86, 0xDC4E, 0x8E88, 0xDC4F, 0x8E89, 0xDC50, 0x8E8A, 0xDC51, 0x8E8B, 0xDC52, 0x8E8C, 0xDC53, 0x8E8D, 0xDC54, 0x8E8E, 0xDC55, 0x8E91, 0xDC56, 0x8E92, 0xDC57, 0x8E93, 0xDC58, 0x8E95, 0xDC59, 0x8E96, 0xDC5A, 0x8E97, 0xDC5B, 0x8E98, 0xDC5C, 0x8E99, 0xDC5D, 0x8E9A, 0xDC5E, 0x8E9B, 0xDC5F, 0x8E9D, 0xDC60, 0x8E9F, 0xDC61, 0x8EA0, 0xDC62, 0x8EA1, 0xDC63, 0x8EA2, 0xDC64, 0x8EA3, 0xDC65, 0x8EA4, 0xDC66, 0x8EA5, 0xDC67, 0x8EA6, 0xDC68, 0x8EA7, 0xDC69, 0x8EA8, 0xDC6A, 0x8EA9, 0xDC6B, 0x8EAA, 0xDC6C, 0x8EAD, 0xDC6D, 0x8EAE, 0xDC6E, 0x8EB0, 0xDC6F, 0x8EB1, 0xDC70, 0x8EB3, 0xDC71, 0x8EB4, 0xDC72, 0x8EB5, 0xDC73, 0x8EB6, 0xDC74, 0x8EB7, 0xDC75, 0x8EB8, 0xDC76, 0x8EB9, 0xDC77, 0x8EBB, 0xDC78, 0x8EBC, 0xDC79, 0x8EBD, 0xDC7A, 0x8EBE, 0xDC7B, 0x8EBF, 0xDC7C, 0x8EC0, 0xDC7D, 0x8EC1, 0xDC7E, 0x8EC2, 0xDC80, 0x8EC3, 0xDC81, 0x8EC4, 0xDC82, 0x8EC5, 0xDC83, 0x8EC6, 0xDC84, 0x8EC7, 0xDC85, 0x8EC8, 0xDC86, 0x8EC9, 0xDC87, 0x8ECA, 0xDC88, 0x8ECB, 0xDC89, 0x8ECC, 0xDC8A, 0x8ECD, 0xDC8B, 0x8ECF, 0xDC8C, 0x8ED0, 0xDC8D, 0x8ED1, 0xDC8E, 0x8ED2, 0xDC8F, 0x8ED3, 0xDC90, 0x8ED4, 0xDC91, 0x8ED5, 0xDC92, 0x8ED6, 0xDC93, 0x8ED7, 0xDC94, 0x8ED8, 0xDC95, 0x8ED9, 0xDC96, 0x8EDA, 0xDC97, 0x8EDB, 0xDC98, 0x8EDC, 0xDC99, 0x8EDD, 0xDC9A, 0x8EDE, 0xDC9B, 0x8EDF, 0xDC9C, 0x8EE0, 0xDC9D, 0x8EE1, 0xDC9E, 0x8EE2, 0xDC9F, 0x8EE3, 0xDCA0, 0x8EE4, 0xDCA1, 0x580B, 0xDCA2, 0x580D, 0xDCA3, 0x57FD, 0xDCA4, 0x57ED, 0xDCA5, 0x5800, 0xDCA6, 0x581E, 0xDCA7, 0x5819, 0xDCA8, 0x5844, 0xDCA9, 0x5820, 0xDCAA, 0x5865, 0xDCAB, 0x586C, 0xDCAC, 0x5881, 0xDCAD, 0x5889, 0xDCAE, 0x589A, 0xDCAF, 0x5880, 0xDCB0, 0x99A8, 0xDCB1, 0x9F19, 0xDCB2, 0x61FF, 0xDCB3, 0x8279, 0xDCB4, 0x827D, 0xDCB5, 0x827F, 0xDCB6, 0x828F, 0xDCB7, 0x828A, 0xDCB8, 0x82A8, 0xDCB9, 0x8284, 0xDCBA, 0x828E, 0xDCBB, 0x8291, 0xDCBC, 0x8297, 0xDCBD, 0x8299, 0xDCBE, 0x82AB, 0xDCBF, 0x82B8, 0xDCC0, 0x82BE, 0xDCC1, 0x82B0, 0xDCC2, 0x82C8, 0xDCC3, 0x82CA, 0xDCC4, 0x82E3, 0xDCC5, 0x8298, 0xDCC6, 0x82B7, 0xDCC7, 0x82AE, 0xDCC8, 0x82CB, 0xDCC9, 0x82CC, 0xDCCA, 0x82C1, 0xDCCB, 0x82A9, 0xDCCC, 0x82B4, 0xDCCD, 0x82A1, 0xDCCE, 0x82AA, 0xDCCF, 0x829F, 0xDCD0, 0x82C4, 0xDCD1, 0x82CE, 0xDCD2, 0x82A4, 0xDCD3, 0x82E1, 0xDCD4, 0x8309, 0xDCD5, 0x82F7, 0xDCD6, 0x82E4, 0xDCD7, 0x830F, 0xDCD8, 0x8307, 0xDCD9, 0x82DC, 0xDCDA, 0x82F4, 0xDCDB, 0x82D2, 0xDCDC, 0x82D8, 0xDCDD, 0x830C, 0xDCDE, 0x82FB, 0xDCDF, 0x82D3, 0xDCE0, 0x8311, 0xDCE1, 0x831A, 0xDCE2, 0x8306, 0xDCE3, 0x8314, 0xDCE4, 0x8315, 0xDCE5, 0x82E0, 0xDCE6, 0x82D5, 0xDCE7, 0x831C, 0xDCE8, 0x8351, 0xDCE9, 0x835B, 0xDCEA, 0x835C, 0xDCEB, 0x8308, 0xDCEC, 0x8392, 0xDCED, 0x833C, 0xDCEE, 0x8334, 0xDCEF, 0x8331, 0xDCF0, 0x839B, 0xDCF1, 0x835E, 0xDCF2, 0x832F, 0xDCF3, 0x834F, 0xDCF4, 0x8347, 0xDCF5, 0x8343, 0xDCF6, 0x835F, 0xDCF7, 0x8340, 0xDCF8, 0x8317, 0xDCF9, 0x8360, 0xDCFA, 0x832D, 0xDCFB, 0x833A, 0xDCFC, 0x8333, 0xDCFD, 0x8366, 0xDCFE, 0x8365, 0xDD40, 0x8EE5, 0xDD41, 0x8EE6, 0xDD42, 0x8EE7, 0xDD43, 0x8EE8, 0xDD44, 0x8EE9, 0xDD45, 0x8EEA, 0xDD46, 0x8EEB, 0xDD47, 0x8EEC, 0xDD48, 0x8EED, 0xDD49, 0x8EEE, 0xDD4A, 0x8EEF, 0xDD4B, 0x8EF0, 0xDD4C, 0x8EF1, 0xDD4D, 0x8EF2, 0xDD4E, 0x8EF3, 0xDD4F, 0x8EF4, 0xDD50, 0x8EF5, 0xDD51, 0x8EF6, 0xDD52, 0x8EF7, 0xDD53, 0x8EF8, 0xDD54, 0x8EF9, 0xDD55, 0x8EFA, 0xDD56, 0x8EFB, 0xDD57, 0x8EFC, 0xDD58, 0x8EFD, 0xDD59, 0x8EFE, 0xDD5A, 0x8EFF, 0xDD5B, 0x8F00, 0xDD5C, 0x8F01, 0xDD5D, 0x8F02, 0xDD5E, 0x8F03, 0xDD5F, 0x8F04, 0xDD60, 0x8F05, 0xDD61, 0x8F06, 0xDD62, 0x8F07, 0xDD63, 0x8F08, 0xDD64, 0x8F09, 0xDD65, 0x8F0A, 0xDD66, 0x8F0B, 0xDD67, 0x8F0C, 0xDD68, 0x8F0D, 0xDD69, 0x8F0E, 0xDD6A, 0x8F0F, 0xDD6B, 0x8F10, 0xDD6C, 0x8F11, 0xDD6D, 0x8F12, 0xDD6E, 0x8F13, 0xDD6F, 0x8F14, 0xDD70, 0x8F15, 0xDD71, 0x8F16, 0xDD72, 0x8F17, 0xDD73, 0x8F18, 0xDD74, 0x8F19, 0xDD75, 0x8F1A, 0xDD76, 0x8F1B, 0xDD77, 0x8F1C, 0xDD78, 0x8F1D, 0xDD79, 0x8F1E, 0xDD7A, 0x8F1F, 0xDD7B, 0x8F20, 0xDD7C, 0x8F21, 0xDD7D, 0x8F22, 0xDD7E, 0x8F23, 0xDD80, 0x8F24, 0xDD81, 0x8F25, 0xDD82, 0x8F26, 0xDD83, 0x8F27, 0xDD84, 0x8F28, 0xDD85, 0x8F29, 0xDD86, 0x8F2A, 0xDD87, 0x8F2B, 0xDD88, 0x8F2C, 0xDD89, 0x8F2D, 0xDD8A, 0x8F2E, 0xDD8B, 0x8F2F, 0xDD8C, 0x8F30, 0xDD8D, 0x8F31, 0xDD8E, 0x8F32, 0xDD8F, 0x8F33, 0xDD90, 0x8F34, 0xDD91, 0x8F35, 0xDD92, 0x8F36, 0xDD93, 0x8F37, 0xDD94, 0x8F38, 0xDD95, 0x8F39, 0xDD96, 0x8F3A, 0xDD97, 0x8F3B, 0xDD98, 0x8F3C, 0xDD99, 0x8F3D, 0xDD9A, 0x8F3E, 0xDD9B, 0x8F3F, 0xDD9C, 0x8F40, 0xDD9D, 0x8F41, 0xDD9E, 0x8F42, 0xDD9F, 0x8F43, 0xDDA0, 0x8F44, 0xDDA1, 0x8368, 0xDDA2, 0x831B, 0xDDA3, 0x8369, 0xDDA4, 0x836C, 0xDDA5, 0x836A, 0xDDA6, 0x836D, 0xDDA7, 0x836E, 0xDDA8, 0x83B0, 0xDDA9, 0x8378, 0xDDAA, 0x83B3, 0xDDAB, 0x83B4, 0xDDAC, 0x83A0, 0xDDAD, 0x83AA, 0xDDAE, 0x8393, 0xDDAF, 0x839C, 0xDDB0, 0x8385, 0xDDB1, 0x837C, 0xDDB2, 0x83B6, 0xDDB3, 0x83A9, 0xDDB4, 0x837D, 0xDDB5, 0x83B8, 0xDDB6, 0x837B, 0xDDB7, 0x8398, 0xDDB8, 0x839E, 0xDDB9, 0x83A8, 0xDDBA, 0x83BA, 0xDDBB, 0x83BC, 0xDDBC, 0x83C1, 0xDDBD, 0x8401, 0xDDBE, 0x83E5, 0xDDBF, 0x83D8, 0xDDC0, 0x5807, 0xDDC1, 0x8418, 0xDDC2, 0x840B, 0xDDC3, 0x83DD, 0xDDC4, 0x83FD, 0xDDC5, 0x83D6, 0xDDC6, 0x841C, 0xDDC7, 0x8438, 0xDDC8, 0x8411, 0xDDC9, 0x8406, 0xDDCA, 0x83D4, 0xDDCB, 0x83DF, 0xDDCC, 0x840F, 0xDDCD, 0x8403, 0xDDCE, 0x83F8, 0xDDCF, 0x83F9, 0xDDD0, 0x83EA, 0xDDD1, 0x83C5, 0xDDD2, 0x83C0, 0xDDD3, 0x8426, 0xDDD4, 0x83F0, 0xDDD5, 0x83E1, 0xDDD6, 0x845C, 0xDDD7, 0x8451, 0xDDD8, 0x845A, 0xDDD9, 0x8459, 0xDDDA, 0x8473, 0xDDDB, 0x8487, 0xDDDC, 0x8488, 0xDDDD, 0x847A, 0xDDDE, 0x8489, 0xDDDF, 0x8478, 0xDDE0, 0x843C, 0xDDE1, 0x8446, 0xDDE2, 0x8469, 0xDDE3, 0x8476, 0xDDE4, 0x848C, 0xDDE5, 0x848E, 0xDDE6, 0x8431, 0xDDE7, 0x846D, 0xDDE8, 0x84C1, 0xDDE9, 0x84CD, 0xDDEA, 0x84D0, 0xDDEB, 0x84E6, 0xDDEC, 0x84BD, 0xDDED, 0x84D3, 0xDDEE, 0x84CA, 0xDDEF, 0x84BF, 0xDDF0, 0x84BA, 0xDDF1, 0x84E0, 0xDDF2, 0x84A1, 0xDDF3, 0x84B9, 0xDDF4, 0x84B4, 0xDDF5, 0x8497, 0xDDF6, 0x84E5, 0xDDF7, 0x84E3, 0xDDF8, 0x850C, 0xDDF9, 0x750D, 0xDDFA, 0x8538, 0xDDFB, 0x84F0, 0xDDFC, 0x8539, 0xDDFD, 0x851F, 0xDDFE, 0x853A, 0xDE40, 0x8F45, 0xDE41, 0x8F46, 0xDE42, 0x8F47, 0xDE43, 0x8F48, 0xDE44, 0x8F49, 0xDE45, 0x8F4A, 0xDE46, 0x8F4B, 0xDE47, 0x8F4C, 0xDE48, 0x8F4D, 0xDE49, 0x8F4E, 0xDE4A, 0x8F4F, 0xDE4B, 0x8F50, 0xDE4C, 0x8F51, 0xDE4D, 0x8F52, 0xDE4E, 0x8F53, 0xDE4F, 0x8F54, 0xDE50, 0x8F55, 0xDE51, 0x8F56, 0xDE52, 0x8F57, 0xDE53, 0x8F58, 0xDE54, 0x8F59, 0xDE55, 0x8F5A, 0xDE56, 0x8F5B, 0xDE57, 0x8F5C, 0xDE58, 0x8F5D, 0xDE59, 0x8F5E, 0xDE5A, 0x8F5F, 0xDE5B, 0x8F60, 0xDE5C, 0x8F61, 0xDE5D, 0x8F62, 0xDE5E, 0x8F63, 0xDE5F, 0x8F64, 0xDE60, 0x8F65, 0xDE61, 0x8F6A, 0xDE62, 0x8F80, 0xDE63, 0x8F8C, 0xDE64, 0x8F92, 0xDE65, 0x8F9D, 0xDE66, 0x8FA0, 0xDE67, 0x8FA1, 0xDE68, 0x8FA2, 0xDE69, 0x8FA4, 0xDE6A, 0x8FA5, 0xDE6B, 0x8FA6, 0xDE6C, 0x8FA7, 0xDE6D, 0x8FAA, 0xDE6E, 0x8FAC, 0xDE6F, 0x8FAD, 0xDE70, 0x8FAE, 0xDE71, 0x8FAF, 0xDE72, 0x8FB2, 0xDE73, 0x8FB3, 0xDE74, 0x8FB4, 0xDE75, 0x8FB5, 0xDE76, 0x8FB7, 0xDE77, 0x8FB8, 0xDE78, 0x8FBA, 0xDE79, 0x8FBB, 0xDE7A, 0x8FBC, 0xDE7B, 0x8FBF, 0xDE7C, 0x8FC0, 0xDE7D, 0x8FC3, 0xDE7E, 0x8FC6, 0xDE80, 0x8FC9, 0xDE81, 0x8FCA, 0xDE82, 0x8FCB, 0xDE83, 0x8FCC, 0xDE84, 0x8FCD, 0xDE85, 0x8FCF, 0xDE86, 0x8FD2, 0xDE87, 0x8FD6, 0xDE88, 0x8FD7, 0xDE89, 0x8FDA, 0xDE8A, 0x8FE0, 0xDE8B, 0x8FE1, 0xDE8C, 0x8FE3, 0xDE8D, 0x8FE7, 0xDE8E, 0x8FEC, 0xDE8F, 0x8FEF, 0xDE90, 0x8FF1, 0xDE91, 0x8FF2, 0xDE92, 0x8FF4, 0xDE93, 0x8FF5, 0xDE94, 0x8FF6, 0xDE95, 0x8FFA, 0xDE96, 0x8FFB, 0xDE97, 0x8FFC, 0xDE98, 0x8FFE, 0xDE99, 0x8FFF, 0xDE9A, 0x9007, 0xDE9B, 0x9008, 0xDE9C, 0x900C, 0xDE9D, 0x900E, 0xDE9E, 0x9013, 0xDE9F, 0x9015, 0xDEA0, 0x9018, 0xDEA1, 0x8556, 0xDEA2, 0x853B, 0xDEA3, 0x84FF, 0xDEA4, 0x84FC, 0xDEA5, 0x8559, 0xDEA6, 0x8548, 0xDEA7, 0x8568, 0xDEA8, 0x8564, 0xDEA9, 0x855E, 0xDEAA, 0x857A, 0xDEAB, 0x77A2, 0xDEAC, 0x8543, 0xDEAD, 0x8572, 0xDEAE, 0x857B, 0xDEAF, 0x85A4, 0xDEB0, 0x85A8, 0xDEB1, 0x8587, 0xDEB2, 0x858F, 0xDEB3, 0x8579, 0xDEB4, 0x85AE, 0xDEB5, 0x859C, 0xDEB6, 0x8585, 0xDEB7, 0x85B9, 0xDEB8, 0x85B7, 0xDEB9, 0x85B0, 0xDEBA, 0x85D3, 0xDEBB, 0x85C1, 0xDEBC, 0x85DC, 0xDEBD, 0x85FF, 0xDEBE, 0x8627, 0xDEBF, 0x8605, 0xDEC0, 0x8629, 0xDEC1, 0x8616, 0xDEC2, 0x863C, 0xDEC3, 0x5EFE, 0xDEC4, 0x5F08, 0xDEC5, 0x593C, 0xDEC6, 0x5941, 0xDEC7, 0x8037, 0xDEC8, 0x5955, 0xDEC9, 0x595A, 0xDECA, 0x5958, 0xDECB, 0x530F, 0xDECC, 0x5C22, 0xDECD, 0x5C25, 0xDECE, 0x5C2C, 0xDECF, 0x5C34, 0xDED0, 0x624C, 0xDED1, 0x626A, 0xDED2, 0x629F, 0xDED3, 0x62BB, 0xDED4, 0x62CA, 0xDED5, 0x62DA, 0xDED6, 0x62D7, 0xDED7, 0x62EE, 0xDED8, 0x6322, 0xDED9, 0x62F6, 0xDEDA, 0x6339, 0xDEDB, 0x634B, 0xDEDC, 0x6343, 0xDEDD, 0x63AD, 0xDEDE, 0x63F6, 0xDEDF, 0x6371, 0xDEE0, 0x637A, 0xDEE1, 0x638E, 0xDEE2, 0x63B4, 0xDEE3, 0x636D, 0xDEE4, 0x63AC, 0xDEE5, 0x638A, 0xDEE6, 0x6369, 0xDEE7, 0x63AE, 0xDEE8, 0x63BC, 0xDEE9, 0x63F2, 0xDEEA, 0x63F8, 0xDEEB, 0x63E0, 0xDEEC, 0x63FF, 0xDEED, 0x63C4, 0xDEEE, 0x63DE, 0xDEEF, 0x63CE, 0xDEF0, 0x6452, 0xDEF1, 0x63C6, 0xDEF2, 0x63BE, 0xDEF3, 0x6445, 0xDEF4, 0x6441, 0xDEF5, 0x640B, 0xDEF6, 0x641B, 0xDEF7, 0x6420, 0xDEF8, 0x640C, 0xDEF9, 0x6426, 0xDEFA, 0x6421, 0xDEFB, 0x645E, 0xDEFC, 0x6484, 0xDEFD, 0x646D, 0xDEFE, 0x6496, 0xDF40, 0x9019, 0xDF41, 0x901C, 0xDF42, 0x9023, 0xDF43, 0x9024, 0xDF44, 0x9025, 0xDF45, 0x9027, 0xDF46, 0x9028, 0xDF47, 0x9029, 0xDF48, 0x902A, 0xDF49, 0x902B, 0xDF4A, 0x902C, 0xDF4B, 0x9030, 0xDF4C, 0x9031, 0xDF4D, 0x9032, 0xDF4E, 0x9033, 0xDF4F, 0x9034, 0xDF50, 0x9037, 0xDF51, 0x9039, 0xDF52, 0x903A, 0xDF53, 0x903D, 0xDF54, 0x903F, 0xDF55, 0x9040, 0xDF56, 0x9043, 0xDF57, 0x9045, 0xDF58, 0x9046, 0xDF59, 0x9048, 0xDF5A, 0x9049, 0xDF5B, 0x904A, 0xDF5C, 0x904B, 0xDF5D, 0x904C, 0xDF5E, 0x904E, 0xDF5F, 0x9054, 0xDF60, 0x9055, 0xDF61, 0x9056, 0xDF62, 0x9059, 0xDF63, 0x905A, 0xDF64, 0x905C, 0xDF65, 0x905D, 0xDF66, 0x905E, 0xDF67, 0x905F, 0xDF68, 0x9060, 0xDF69, 0x9061, 0xDF6A, 0x9064, 0xDF6B, 0x9066, 0xDF6C, 0x9067, 0xDF6D, 0x9069, 0xDF6E, 0x906A, 0xDF6F, 0x906B, 0xDF70, 0x906C, 0xDF71, 0x906F, 0xDF72, 0x9070, 0xDF73, 0x9071, 0xDF74, 0x9072, 0xDF75, 0x9073, 0xDF76, 0x9076, 0xDF77, 0x9077, 0xDF78, 0x9078, 0xDF79, 0x9079, 0xDF7A, 0x907A, 0xDF7B, 0x907B, 0xDF7C, 0x907C, 0xDF7D, 0x907E, 0xDF7E, 0x9081, 0xDF80, 0x9084, 0xDF81, 0x9085, 0xDF82, 0x9086, 0xDF83, 0x9087, 0xDF84, 0x9089, 0xDF85, 0x908A, 0xDF86, 0x908C, 0xDF87, 0x908D, 0xDF88, 0x908E, 0xDF89, 0x908F, 0xDF8A, 0x9090, 0xDF8B, 0x9092, 0xDF8C, 0x9094, 0xDF8D, 0x9096, 0xDF8E, 0x9098, 0xDF8F, 0x909A, 0xDF90, 0x909C, 0xDF91, 0x909E, 0xDF92, 0x909F, 0xDF93, 0x90A0, 0xDF94, 0x90A4, 0xDF95, 0x90A5, 0xDF96, 0x90A7, 0xDF97, 0x90A8, 0xDF98, 0x90A9, 0xDF99, 0x90AB, 0xDF9A, 0x90AD, 0xDF9B, 0x90B2, 0xDF9C, 0x90B7, 0xDF9D, 0x90BC, 0xDF9E, 0x90BD, 0xDF9F, 0x90BF, 0xDFA0, 0x90C0, 0xDFA1, 0x647A, 0xDFA2, 0x64B7, 0xDFA3, 0x64B8, 0xDFA4, 0x6499, 0xDFA5, 0x64BA, 0xDFA6, 0x64C0, 0xDFA7, 0x64D0, 0xDFA8, 0x64D7, 0xDFA9, 0x64E4, 0xDFAA, 0x64E2, 0xDFAB, 0x6509, 0xDFAC, 0x6525, 0xDFAD, 0x652E, 0xDFAE, 0x5F0B, 0xDFAF, 0x5FD2, 0xDFB0, 0x7519, 0xDFB1, 0x5F11, 0xDFB2, 0x535F, 0xDFB3, 0x53F1, 0xDFB4, 0x53FD, 0xDFB5, 0x53E9, 0xDFB6, 0x53E8, 0xDFB7, 0x53FB, 0xDFB8, 0x5412, 0xDFB9, 0x5416, 0xDFBA, 0x5406, 0xDFBB, 0x544B, 0xDFBC, 0x5452, 0xDFBD, 0x5453, 0xDFBE, 0x5454, 0xDFBF, 0x5456, 0xDFC0, 0x5443, 0xDFC1, 0x5421, 0xDFC2, 0x5457, 0xDFC3, 0x5459, 0xDFC4, 0x5423, 0xDFC5, 0x5432, 0xDFC6, 0x5482, 0xDFC7, 0x5494, 0xDFC8, 0x5477, 0xDFC9, 0x5471, 0xDFCA, 0x5464, 0xDFCB, 0x549A, 0xDFCC, 0x549B, 0xDFCD, 0x5484, 0xDFCE, 0x5476, 0xDFCF, 0x5466, 0xDFD0, 0x549D, 0xDFD1, 0x54D0, 0xDFD2, 0x54AD, 0xDFD3, 0x54C2, 0xDFD4, 0x54B4, 0xDFD5, 0x54D2, 0xDFD6, 0x54A7, 0xDFD7, 0x54A6, 0xDFD8, 0x54D3, 0xDFD9, 0x54D4, 0xDFDA, 0x5472, 0xDFDB, 0x54A3, 0xDFDC, 0x54D5, 0xDFDD, 0x54BB, 0xDFDE, 0x54BF, 0xDFDF, 0x54CC, 0xDFE0, 0x54D9, 0xDFE1, 0x54DA, 0xDFE2, 0x54DC, 0xDFE3, 0x54A9, 0xDFE4, 0x54AA, 0xDFE5, 0x54A4, 0xDFE6, 0x54DD, 0xDFE7, 0x54CF, 0xDFE8, 0x54DE, 0xDFE9, 0x551B, 0xDFEA, 0x54E7, 0xDFEB, 0x5520, 0xDFEC, 0x54FD, 0xDFED, 0x5514, 0xDFEE, 0x54F3, 0xDFEF, 0x5522, 0xDFF0, 0x5523, 0xDFF1, 0x550F, 0xDFF2, 0x5511, 0xDFF3, 0x5527, 0xDFF4, 0x552A, 0xDFF5, 0x5567, 0xDFF6, 0x558F, 0xDFF7, 0x55B5, 0xDFF8, 0x5549, 0xDFF9, 0x556D, 0xDFFA, 0x5541, 0xDFFB, 0x5555, 0xDFFC, 0x553F, 0xDFFD, 0x5550, 0xDFFE, 0x553C, 0xE040, 0x90C2, 0xE041, 0x90C3, 0xE042, 0x90C6, 0xE043, 0x90C8, 0xE044, 0x90C9, 0xE045, 0x90CB, 0xE046, 0x90CC, 0xE047, 0x90CD, 0xE048, 0x90D2, 0xE049, 0x90D4, 0xE04A, 0x90D5, 0xE04B, 0x90D6, 0xE04C, 0x90D8, 0xE04D, 0x90D9, 0xE04E, 0x90DA, 0xE04F, 0x90DE, 0xE050, 0x90DF, 0xE051, 0x90E0, 0xE052, 0x90E3, 0xE053, 0x90E4, 0xE054, 0x90E5, 0xE055, 0x90E9, 0xE056, 0x90EA, 0xE057, 0x90EC, 0xE058, 0x90EE, 0xE059, 0x90F0, 0xE05A, 0x90F1, 0xE05B, 0x90F2, 0xE05C, 0x90F3, 0xE05D, 0x90F5, 0xE05E, 0x90F6, 0xE05F, 0x90F7, 0xE060, 0x90F9, 0xE061, 0x90FA, 0xE062, 0x90FB, 0xE063, 0x90FC, 0xE064, 0x90FF, 0xE065, 0x9100, 0xE066, 0x9101, 0xE067, 0x9103, 0xE068, 0x9105, 0xE069, 0x9106, 0xE06A, 0x9107, 0xE06B, 0x9108, 0xE06C, 0x9109, 0xE06D, 0x910A, 0xE06E, 0x910B, 0xE06F, 0x910C, 0xE070, 0x910D, 0xE071, 0x910E, 0xE072, 0x910F, 0xE073, 0x9110, 0xE074, 0x9111, 0xE075, 0x9112, 0xE076, 0x9113, 0xE077, 0x9114, 0xE078, 0x9115, 0xE079, 0x9116, 0xE07A, 0x9117, 0xE07B, 0x9118, 0xE07C, 0x911A, 0xE07D, 0x911B, 0xE07E, 0x911C, 0xE080, 0x911D, 0xE081, 0x911F, 0xE082, 0x9120, 0xE083, 0x9121, 0xE084, 0x9124, 0xE085, 0x9125, 0xE086, 0x9126, 0xE087, 0x9127, 0xE088, 0x9128, 0xE089, 0x9129, 0xE08A, 0x912A, 0xE08B, 0x912B, 0xE08C, 0x912C, 0xE08D, 0x912D, 0xE08E, 0x912E, 0xE08F, 0x9130, 0xE090, 0x9132, 0xE091, 0x9133, 0xE092, 0x9134, 0xE093, 0x9135, 0xE094, 0x9136, 0xE095, 0x9137, 0xE096, 0x9138, 0xE097, 0x913A, 0xE098, 0x913B, 0xE099, 0x913C, 0xE09A, 0x913D, 0xE09B, 0x913E, 0xE09C, 0x913F, 0xE09D, 0x9140, 0xE09E, 0x9141, 0xE09F, 0x9142, 0xE0A0, 0x9144, 0xE0A1, 0x5537, 0xE0A2, 0x5556, 0xE0A3, 0x5575, 0xE0A4, 0x5576, 0xE0A5, 0x5577, 0xE0A6, 0x5533, 0xE0A7, 0x5530, 0xE0A8, 0x555C, 0xE0A9, 0x558B, 0xE0AA, 0x55D2, 0xE0AB, 0x5583, 0xE0AC, 0x55B1, 0xE0AD, 0x55B9, 0xE0AE, 0x5588, 0xE0AF, 0x5581, 0xE0B0, 0x559F, 0xE0B1, 0x557E, 0xE0B2, 0x55D6, 0xE0B3, 0x5591, 0xE0B4, 0x557B, 0xE0B5, 0x55DF, 0xE0B6, 0x55BD, 0xE0B7, 0x55BE, 0xE0B8, 0x5594, 0xE0B9, 0x5599, 0xE0BA, 0x55EA, 0xE0BB, 0x55F7, 0xE0BC, 0x55C9, 0xE0BD, 0x561F, 0xE0BE, 0x55D1, 0xE0BF, 0x55EB, 0xE0C0, 0x55EC, 0xE0C1, 0x55D4, 0xE0C2, 0x55E6, 0xE0C3, 0x55DD, 0xE0C4, 0x55C4, 0xE0C5, 0x55EF, 0xE0C6, 0x55E5, 0xE0C7, 0x55F2, 0xE0C8, 0x55F3, 0xE0C9, 0x55CC, 0xE0CA, 0x55CD, 0xE0CB, 0x55E8, 0xE0CC, 0x55F5, 0xE0CD, 0x55E4, 0xE0CE, 0x8F94, 0xE0CF, 0x561E, 0xE0D0, 0x5608, 0xE0D1, 0x560C, 0xE0D2, 0x5601, 0xE0D3, 0x5624, 0xE0D4, 0x5623, 0xE0D5, 0x55FE, 0xE0D6, 0x5600, 0xE0D7, 0x5627, 0xE0D8, 0x562D, 0xE0D9, 0x5658, 0xE0DA, 0x5639, 0xE0DB, 0x5657, 0xE0DC, 0x562C, 0xE0DD, 0x564D, 0xE0DE, 0x5662, 0xE0DF, 0x5659, 0xE0E0, 0x565C, 0xE0E1, 0x564C, 0xE0E2, 0x5654, 0xE0E3, 0x5686, 0xE0E4, 0x5664, 0xE0E5, 0x5671, 0xE0E6, 0x566B, 0xE0E7, 0x567B, 0xE0E8, 0x567C, 0xE0E9, 0x5685, 0xE0EA, 0x5693, 0xE0EB, 0x56AF, 0xE0EC, 0x56D4, 0xE0ED, 0x56D7, 0xE0EE, 0x56DD, 0xE0EF, 0x56E1, 0xE0F0, 0x56F5, 0xE0F1, 0x56EB, 0xE0F2, 0x56F9, 0xE0F3, 0x56FF, 0xE0F4, 0x5704, 0xE0F5, 0x570A, 0xE0F6, 0x5709, 0xE0F7, 0x571C, 0xE0F8, 0x5E0F, 0xE0F9, 0x5E19, 0xE0FA, 0x5E14, 0xE0FB, 0x5E11, 0xE0FC, 0x5E31, 0xE0FD, 0x5E3B, 0xE0FE, 0x5E3C, 0xE140, 0x9145, 0xE141, 0x9147, 0xE142, 0x9148, 0xE143, 0x9151, 0xE144, 0x9153, 0xE145, 0x9154, 0xE146, 0x9155, 0xE147, 0x9156, 0xE148, 0x9158, 0xE149, 0x9159, 0xE14A, 0x915B, 0xE14B, 0x915C, 0xE14C, 0x915F, 0xE14D, 0x9160, 0xE14E, 0x9166, 0xE14F, 0x9167, 0xE150, 0x9168, 0xE151, 0x916B, 0xE152, 0x916D, 0xE153, 0x9173, 0xE154, 0x917A, 0xE155, 0x917B, 0xE156, 0x917C, 0xE157, 0x9180, 0xE158, 0x9181, 0xE159, 0x9182, 0xE15A, 0x9183, 0xE15B, 0x9184, 0xE15C, 0x9186, 0xE15D, 0x9188, 0xE15E, 0x918A, 0xE15F, 0x918E, 0xE160, 0x918F, 0xE161, 0x9193, 0xE162, 0x9194, 0xE163, 0x9195, 0xE164, 0x9196, 0xE165, 0x9197, 0xE166, 0x9198, 0xE167, 0x9199, 0xE168, 0x919C, 0xE169, 0x919D, 0xE16A, 0x919E, 0xE16B, 0x919F, 0xE16C, 0x91A0, 0xE16D, 0x91A1, 0xE16E, 0x91A4, 0xE16F, 0x91A5, 0xE170, 0x91A6, 0xE171, 0x91A7, 0xE172, 0x91A8, 0xE173, 0x91A9, 0xE174, 0x91AB, 0xE175, 0x91AC, 0xE176, 0x91B0, 0xE177, 0x91B1, 0xE178, 0x91B2, 0xE179, 0x91B3, 0xE17A, 0x91B6, 0xE17B, 0x91B7, 0xE17C, 0x91B8, 0xE17D, 0x91B9, 0xE17E, 0x91BB, 0xE180, 0x91BC, 0xE181, 0x91BD, 0xE182, 0x91BE, 0xE183, 0x91BF, 0xE184, 0x91C0, 0xE185, 0x91C1, 0xE186, 0x91C2, 0xE187, 0x91C3, 0xE188, 0x91C4, 0xE189, 0x91C5, 0xE18A, 0x91C6, 0xE18B, 0x91C8, 0xE18C, 0x91CB, 0xE18D, 0x91D0, 0xE18E, 0x91D2, 0xE18F, 0x91D3, 0xE190, 0x91D4, 0xE191, 0x91D5, 0xE192, 0x91D6, 0xE193, 0x91D7, 0xE194, 0x91D8, 0xE195, 0x91D9, 0xE196, 0x91DA, 0xE197, 0x91DB, 0xE198, 0x91DD, 0xE199, 0x91DE, 0xE19A, 0x91DF, 0xE19B, 0x91E0, 0xE19C, 0x91E1, 0xE19D, 0x91E2, 0xE19E, 0x91E3, 0xE19F, 0x91E4, 0xE1A0, 0x91E5, 0xE1A1, 0x5E37, 0xE1A2, 0x5E44, 0xE1A3, 0x5E54, 0xE1A4, 0x5E5B, 0xE1A5, 0x5E5E, 0xE1A6, 0x5E61, 0xE1A7, 0x5C8C, 0xE1A8, 0x5C7A, 0xE1A9, 0x5C8D, 0xE1AA, 0x5C90, 0xE1AB, 0x5C96, 0xE1AC, 0x5C88, 0xE1AD, 0x5C98, 0xE1AE, 0x5C99, 0xE1AF, 0x5C91, 0xE1B0, 0x5C9A, 0xE1B1, 0x5C9C, 0xE1B2, 0x5CB5, 0xE1B3, 0x5CA2, 0xE1B4, 0x5CBD, 0xE1B5, 0x5CAC, 0xE1B6, 0x5CAB, 0xE1B7, 0x5CB1, 0xE1B8, 0x5CA3, 0xE1B9, 0x5CC1, 0xE1BA, 0x5CB7, 0xE1BB, 0x5CC4, 0xE1BC, 0x5CD2, 0xE1BD, 0x5CE4, 0xE1BE, 0x5CCB, 0xE1BF, 0x5CE5, 0xE1C0, 0x5D02, 0xE1C1, 0x5D03, 0xE1C2, 0x5D27, 0xE1C3, 0x5D26, 0xE1C4, 0x5D2E, 0xE1C5, 0x5D24, 0xE1C6, 0x5D1E, 0xE1C7, 0x5D06, 0xE1C8, 0x5D1B, 0xE1C9, 0x5D58, 0xE1CA, 0x5D3E, 0xE1CB, 0x5D34, 0xE1CC, 0x5D3D, 0xE1CD, 0x5D6C, 0xE1CE, 0x5D5B, 0xE1CF, 0x5D6F, 0xE1D0, 0x5D5D, 0xE1D1, 0x5D6B, 0xE1D2, 0x5D4B, 0xE1D3, 0x5D4A, 0xE1D4, 0x5D69, 0xE1D5, 0x5D74, 0xE1D6, 0x5D82, 0xE1D7, 0x5D99, 0xE1D8, 0x5D9D, 0xE1D9, 0x8C73, 0xE1DA, 0x5DB7, 0xE1DB, 0x5DC5, 0xE1DC, 0x5F73, 0xE1DD, 0x5F77, 0xE1DE, 0x5F82, 0xE1DF, 0x5F87, 0xE1E0, 0x5F89, 0xE1E1, 0x5F8C, 0xE1E2, 0x5F95, 0xE1E3, 0x5F99, 0xE1E4, 0x5F9C, 0xE1E5, 0x5FA8, 0xE1E6, 0x5FAD, 0xE1E7, 0x5FB5, 0xE1E8, 0x5FBC, 0xE1E9, 0x8862, 0xE1EA, 0x5F61, 0xE1EB, 0x72AD, 0xE1EC, 0x72B0, 0xE1ED, 0x72B4, 0xE1EE, 0x72B7, 0xE1EF, 0x72B8, 0xE1F0, 0x72C3, 0xE1F1, 0x72C1, 0xE1F2, 0x72CE, 0xE1F3, 0x72CD, 0xE1F4, 0x72D2, 0xE1F5, 0x72E8, 0xE1F6, 0x72EF, 0xE1F7, 0x72E9, 0xE1F8, 0x72F2, 0xE1F9, 0x72F4, 0xE1FA, 0x72F7, 0xE1FB, 0x7301, 0xE1FC, 0x72F3, 0xE1FD, 0x7303, 0xE1FE, 0x72FA, 0xE240, 0x91E6, 0xE241, 0x91E7, 0xE242, 0x91E8, 0xE243, 0x91E9, 0xE244, 0x91EA, 0xE245, 0x91EB, 0xE246, 0x91EC, 0xE247, 0x91ED, 0xE248, 0x91EE, 0xE249, 0x91EF, 0xE24A, 0x91F0, 0xE24B, 0x91F1, 0xE24C, 0x91F2, 0xE24D, 0x91F3, 0xE24E, 0x91F4, 0xE24F, 0x91F5, 0xE250, 0x91F6, 0xE251, 0x91F7, 0xE252, 0x91F8, 0xE253, 0x91F9, 0xE254, 0x91FA, 0xE255, 0x91FB, 0xE256, 0x91FC, 0xE257, 0x91FD, 0xE258, 0x91FE, 0xE259, 0x91FF, 0xE25A, 0x9200, 0xE25B, 0x9201, 0xE25C, 0x9202, 0xE25D, 0x9203, 0xE25E, 0x9204, 0xE25F, 0x9205, 0xE260, 0x9206, 0xE261, 0x9207, 0xE262, 0x9208, 0xE263, 0x9209, 0xE264, 0x920A, 0xE265, 0x920B, 0xE266, 0x920C, 0xE267, 0x920D, 0xE268, 0x920E, 0xE269, 0x920F, 0xE26A, 0x9210, 0xE26B, 0x9211, 0xE26C, 0x9212, 0xE26D, 0x9213, 0xE26E, 0x9214, 0xE26F, 0x9215, 0xE270, 0x9216, 0xE271, 0x9217, 0xE272, 0x9218, 0xE273, 0x9219, 0xE274, 0x921A, 0xE275, 0x921B, 0xE276, 0x921C, 0xE277, 0x921D, 0xE278, 0x921E, 0xE279, 0x921F, 0xE27A, 0x9220, 0xE27B, 0x9221, 0xE27C, 0x9222, 0xE27D, 0x9223, 0xE27E, 0x9224, 0xE280, 0x9225, 0xE281, 0x9226, 0xE282, 0x9227, 0xE283, 0x9228, 0xE284, 0x9229, 0xE285, 0x922A, 0xE286, 0x922B, 0xE287, 0x922C, 0xE288, 0x922D, 0xE289, 0x922E, 0xE28A, 0x922F, 0xE28B, 0x9230, 0xE28C, 0x9231, 0xE28D, 0x9232, 0xE28E, 0x9233, 0xE28F, 0x9234, 0xE290, 0x9235, 0xE291, 0x9236, 0xE292, 0x9237, 0xE293, 0x9238, 0xE294, 0x9239, 0xE295, 0x923A, 0xE296, 0x923B, 0xE297, 0x923C, 0xE298, 0x923D, 0xE299, 0x923E, 0xE29A, 0x923F, 0xE29B, 0x9240, 0xE29C, 0x9241, 0xE29D, 0x9242, 0xE29E, 0x9243, 0xE29F, 0x9244, 0xE2A0, 0x9245, 0xE2A1, 0x72FB, 0xE2A2, 0x7317, 0xE2A3, 0x7313, 0xE2A4, 0x7321, 0xE2A5, 0x730A, 0xE2A6, 0x731E, 0xE2A7, 0x731D, 0xE2A8, 0x7315, 0xE2A9, 0x7322, 0xE2AA, 0x7339, 0xE2AB, 0x7325, 0xE2AC, 0x732C, 0xE2AD, 0x7338, 0xE2AE, 0x7331, 0xE2AF, 0x7350, 0xE2B0, 0x734D, 0xE2B1, 0x7357, 0xE2B2, 0x7360, 0xE2B3, 0x736C, 0xE2B4, 0x736F, 0xE2B5, 0x737E, 0xE2B6, 0x821B, 0xE2B7, 0x5925, 0xE2B8, 0x98E7, 0xE2B9, 0x5924, 0xE2BA, 0x5902, 0xE2BB, 0x9963, 0xE2BC, 0x9967, 0xE2BD, 0x9968, 0xE2BE, 0x9969, 0xE2BF, 0x996A, 0xE2C0, 0x996B, 0xE2C1, 0x996C, 0xE2C2, 0x9974, 0xE2C3, 0x9977, 0xE2C4, 0x997D, 0xE2C5, 0x9980, 0xE2C6, 0x9984, 0xE2C7, 0x9987, 0xE2C8, 0x998A, 0xE2C9, 0x998D, 0xE2CA, 0x9990, 0xE2CB, 0x9991, 0xE2CC, 0x9993, 0xE2CD, 0x9994, 0xE2CE, 0x9995, 0xE2CF, 0x5E80, 0xE2D0, 0x5E91, 0xE2D1, 0x5E8B, 0xE2D2, 0x5E96, 0xE2D3, 0x5EA5, 0xE2D4, 0x5EA0, 0xE2D5, 0x5EB9, 0xE2D6, 0x5EB5, 0xE2D7, 0x5EBE, 0xE2D8, 0x5EB3, 0xE2D9, 0x8D53, 0xE2DA, 0x5ED2, 0xE2DB, 0x5ED1, 0xE2DC, 0x5EDB, 0xE2DD, 0x5EE8, 0xE2DE, 0x5EEA, 0xE2DF, 0x81BA, 0xE2E0, 0x5FC4, 0xE2E1, 0x5FC9, 0xE2E2, 0x5FD6, 0xE2E3, 0x5FCF, 0xE2E4, 0x6003, 0xE2E5, 0x5FEE, 0xE2E6, 0x6004, 0xE2E7, 0x5FE1, 0xE2E8, 0x5FE4, 0xE2E9, 0x5FFE, 0xE2EA, 0x6005, 0xE2EB, 0x6006, 0xE2EC, 0x5FEA, 0xE2ED, 0x5FED, 0xE2EE, 0x5FF8, 0xE2EF, 0x6019, 0xE2F0, 0x6035, 0xE2F1, 0x6026, 0xE2F2, 0x601B, 0xE2F3, 0x600F, 0xE2F4, 0x600D, 0xE2F5, 0x6029, 0xE2F6, 0x602B, 0xE2F7, 0x600A, 0xE2F8, 0x603F, 0xE2F9, 0x6021, 0xE2FA, 0x6078, 0xE2FB, 0x6079, 0xE2FC, 0x607B, 0xE2FD, 0x607A, 0xE2FE, 0x6042, 0xE340, 0x9246, 0xE341, 0x9247, 0xE342, 0x9248, 0xE343, 0x9249, 0xE344, 0x924A, 0xE345, 0x924B, 0xE346, 0x924C, 0xE347, 0x924D, 0xE348, 0x924E, 0xE349, 0x924F, 0xE34A, 0x9250, 0xE34B, 0x9251, 0xE34C, 0x9252, 0xE34D, 0x9253, 0xE34E, 0x9254, 0xE34F, 0x9255, 0xE350, 0x9256, 0xE351, 0x9257, 0xE352, 0x9258, 0xE353, 0x9259, 0xE354, 0x925A, 0xE355, 0x925B, 0xE356, 0x925C, 0xE357, 0x925D, 0xE358, 0x925E, 0xE359, 0x925F, 0xE35A, 0x9260, 0xE35B, 0x9261, 0xE35C, 0x9262, 0xE35D, 0x9263, 0xE35E, 0x9264, 0xE35F, 0x9265, 0xE360, 0x9266, 0xE361, 0x9267, 0xE362, 0x9268, 0xE363, 0x9269, 0xE364, 0x926A, 0xE365, 0x926B, 0xE366, 0x926C, 0xE367, 0x926D, 0xE368, 0x926E, 0xE369, 0x926F, 0xE36A, 0x9270, 0xE36B, 0x9271, 0xE36C, 0x9272, 0xE36D, 0x9273, 0xE36E, 0x9275, 0xE36F, 0x9276, 0xE370, 0x9277, 0xE371, 0x9278, 0xE372, 0x9279, 0xE373, 0x927A, 0xE374, 0x927B, 0xE375, 0x927C, 0xE376, 0x927D, 0xE377, 0x927E, 0xE378, 0x927F, 0xE379, 0x9280, 0xE37A, 0x9281, 0xE37B, 0x9282, 0xE37C, 0x9283, 0xE37D, 0x9284, 0xE37E, 0x9285, 0xE380, 0x9286, 0xE381, 0x9287, 0xE382, 0x9288, 0xE383, 0x9289, 0xE384, 0x928A, 0xE385, 0x928B, 0xE386, 0x928C, 0xE387, 0x928D, 0xE388, 0x928F, 0xE389, 0x9290, 0xE38A, 0x9291, 0xE38B, 0x9292, 0xE38C, 0x9293, 0xE38D, 0x9294, 0xE38E, 0x9295, 0xE38F, 0x9296, 0xE390, 0x9297, 0xE391, 0x9298, 0xE392, 0x9299, 0xE393, 0x929A, 0xE394, 0x929B, 0xE395, 0x929C, 0xE396, 0x929D, 0xE397, 0x929E, 0xE398, 0x929F, 0xE399, 0x92A0, 0xE39A, 0x92A1, 0xE39B, 0x92A2, 0xE39C, 0x92A3, 0xE39D, 0x92A4, 0xE39E, 0x92A5, 0xE39F, 0x92A6, 0xE3A0, 0x92A7, 0xE3A1, 0x606A, 0xE3A2, 0x607D, 0xE3A3, 0x6096, 0xE3A4, 0x609A, 0xE3A5, 0x60AD, 0xE3A6, 0x609D, 0xE3A7, 0x6083, 0xE3A8, 0x6092, 0xE3A9, 0x608C, 0xE3AA, 0x609B, 0xE3AB, 0x60EC, 0xE3AC, 0x60BB, 0xE3AD, 0x60B1, 0xE3AE, 0x60DD, 0xE3AF, 0x60D8, 0xE3B0, 0x60C6, 0xE3B1, 0x60DA, 0xE3B2, 0x60B4, 0xE3B3, 0x6120, 0xE3B4, 0x6126, 0xE3B5, 0x6115, 0xE3B6, 0x6123, 0xE3B7, 0x60F4, 0xE3B8, 0x6100, 0xE3B9, 0x610E, 0xE3BA, 0x612B, 0xE3BB, 0x614A, 0xE3BC, 0x6175, 0xE3BD, 0x61AC, 0xE3BE, 0x6194, 0xE3BF, 0x61A7, 0xE3C0, 0x61B7, 0xE3C1, 0x61D4, 0xE3C2, 0x61F5, 0xE3C3, 0x5FDD, 0xE3C4, 0x96B3, 0xE3C5, 0x95E9, 0xE3C6, 0x95EB, 0xE3C7, 0x95F1, 0xE3C8, 0x95F3, 0xE3C9, 0x95F5, 0xE3CA, 0x95F6, 0xE3CB, 0x95FC, 0xE3CC, 0x95FE, 0xE3CD, 0x9603, 0xE3CE, 0x9604, 0xE3CF, 0x9606, 0xE3D0, 0x9608, 0xE3D1, 0x960A, 0xE3D2, 0x960B, 0xE3D3, 0x960C, 0xE3D4, 0x960D, 0xE3D5, 0x960F, 0xE3D6, 0x9612, 0xE3D7, 0x9615, 0xE3D8, 0x9616, 0xE3D9, 0x9617, 0xE3DA, 0x9619, 0xE3DB, 0x961A, 0xE3DC, 0x4E2C, 0xE3DD, 0x723F, 0xE3DE, 0x6215, 0xE3DF, 0x6C35, 0xE3E0, 0x6C54, 0xE3E1, 0x6C5C, 0xE3E2, 0x6C4A, 0xE3E3, 0x6CA3, 0xE3E4, 0x6C85, 0xE3E5, 0x6C90, 0xE3E6, 0x6C94, 0xE3E7, 0x6C8C, 0xE3E8, 0x6C68, 0xE3E9, 0x6C69, 0xE3EA, 0x6C74, 0xE3EB, 0x6C76, 0xE3EC, 0x6C86, 0xE3ED, 0x6CA9, 0xE3EE, 0x6CD0, 0xE3EF, 0x6CD4, 0xE3F0, 0x6CAD, 0xE3F1, 0x6CF7, 0xE3F2, 0x6CF8, 0xE3F3, 0x6CF1, 0xE3F4, 0x6CD7, 0xE3F5, 0x6CB2, 0xE3F6, 0x6CE0, 0xE3F7, 0x6CD6, 0xE3F8, 0x6CFA, 0xE3F9, 0x6CEB, 0xE3FA, 0x6CEE, 0xE3FB, 0x6CB1, 0xE3FC, 0x6CD3, 0xE3FD, 0x6CEF, 0xE3FE, 0x6CFE, 0xE440, 0x92A8, 0xE441, 0x92A9, 0xE442, 0x92AA, 0xE443, 0x92AB, 0xE444, 0x92AC, 0xE445, 0x92AD, 0xE446, 0x92AF, 0xE447, 0x92B0, 0xE448, 0x92B1, 0xE449, 0x92B2, 0xE44A, 0x92B3, 0xE44B, 0x92B4, 0xE44C, 0x92B5, 0xE44D, 0x92B6, 0xE44E, 0x92B7, 0xE44F, 0x92B8, 0xE450, 0x92B9, 0xE451, 0x92BA, 0xE452, 0x92BB, 0xE453, 0x92BC, 0xE454, 0x92BD, 0xE455, 0x92BE, 0xE456, 0x92BF, 0xE457, 0x92C0, 0xE458, 0x92C1, 0xE459, 0x92C2, 0xE45A, 0x92C3, 0xE45B, 0x92C4, 0xE45C, 0x92C5, 0xE45D, 0x92C6, 0xE45E, 0x92C7, 0xE45F, 0x92C9, 0xE460, 0x92CA, 0xE461, 0x92CB, 0xE462, 0x92CC, 0xE463, 0x92CD, 0xE464, 0x92CE, 0xE465, 0x92CF, 0xE466, 0x92D0, 0xE467, 0x92D1, 0xE468, 0x92D2, 0xE469, 0x92D3, 0xE46A, 0x92D4, 0xE46B, 0x92D5, 0xE46C, 0x92D6, 0xE46D, 0x92D7, 0xE46E, 0x92D8, 0xE46F, 0x92D9, 0xE470, 0x92DA, 0xE471, 0x92DB, 0xE472, 0x92DC, 0xE473, 0x92DD, 0xE474, 0x92DE, 0xE475, 0x92DF, 0xE476, 0x92E0, 0xE477, 0x92E1, 0xE478, 0x92E2, 0xE479, 0x92E3, 0xE47A, 0x92E4, 0xE47B, 0x92E5, 0xE47C, 0x92E6, 0xE47D, 0x92E7, 0xE47E, 0x92E8, 0xE480, 0x92E9, 0xE481, 0x92EA, 0xE482, 0x92EB, 0xE483, 0x92EC, 0xE484, 0x92ED, 0xE485, 0x92EE, 0xE486, 0x92EF, 0xE487, 0x92F0, 0xE488, 0x92F1, 0xE489, 0x92F2, 0xE48A, 0x92F3, 0xE48B, 0x92F4, 0xE48C, 0x92F5, 0xE48D, 0x92F6, 0xE48E, 0x92F7, 0xE48F, 0x92F8, 0xE490, 0x92F9, 0xE491, 0x92FA, 0xE492, 0x92FB, 0xE493, 0x92FC, 0xE494, 0x92FD, 0xE495, 0x92FE, 0xE496, 0x92FF, 0xE497, 0x9300, 0xE498, 0x9301, 0xE499, 0x9302, 0xE49A, 0x9303, 0xE49B, 0x9304, 0xE49C, 0x9305, 0xE49D, 0x9306, 0xE49E, 0x9307, 0xE49F, 0x9308, 0xE4A0, 0x9309, 0xE4A1, 0x6D39, 0xE4A2, 0x6D27, 0xE4A3, 0x6D0C, 0xE4A4, 0x6D43, 0xE4A5, 0x6D48, 0xE4A6, 0x6D07, 0xE4A7, 0x6D04, 0xE4A8, 0x6D19, 0xE4A9, 0x6D0E, 0xE4AA, 0x6D2B, 0xE4AB, 0x6D4D, 0xE4AC, 0x6D2E, 0xE4AD, 0x6D35, 0xE4AE, 0x6D1A, 0xE4AF, 0x6D4F, 0xE4B0, 0x6D52, 0xE4B1, 0x6D54, 0xE4B2, 0x6D33, 0xE4B3, 0x6D91, 0xE4B4, 0x6D6F, 0xE4B5, 0x6D9E, 0xE4B6, 0x6DA0, 0xE4B7, 0x6D5E, 0xE4B8, 0x6D93, 0xE4B9, 0x6D94, 0xE4BA, 0x6D5C, 0xE4BB, 0x6D60, 0xE4BC, 0x6D7C, 0xE4BD, 0x6D63, 0xE4BE, 0x6E1A, 0xE4BF, 0x6DC7, 0xE4C0, 0x6DC5, 0xE4C1, 0x6DDE, 0xE4C2, 0x6E0E, 0xE4C3, 0x6DBF, 0xE4C4, 0x6DE0, 0xE4C5, 0x6E11, 0xE4C6, 0x6DE6, 0xE4C7, 0x6DDD, 0xE4C8, 0x6DD9, 0xE4C9, 0x6E16, 0xE4CA, 0x6DAB, 0xE4CB, 0x6E0C, 0xE4CC, 0x6DAE, 0xE4CD, 0x6E2B, 0xE4CE, 0x6E6E, 0xE4CF, 0x6E4E, 0xE4D0, 0x6E6B, 0xE4D1, 0x6EB2, 0xE4D2, 0x6E5F, 0xE4D3, 0x6E86, 0xE4D4, 0x6E53, 0xE4D5, 0x6E54, 0xE4D6, 0x6E32, 0xE4D7, 0x6E25, 0xE4D8, 0x6E44, 0xE4D9, 0x6EDF, 0xE4DA, 0x6EB1, 0xE4DB, 0x6E98, 0xE4DC, 0x6EE0, 0xE4DD, 0x6F2D, 0xE4DE, 0x6EE2, 0xE4DF, 0x6EA5, 0xE4E0, 0x6EA7, 0xE4E1, 0x6EBD, 0xE4E2, 0x6EBB, 0xE4E3, 0x6EB7, 0xE4E4, 0x6ED7, 0xE4E5, 0x6EB4, 0xE4E6, 0x6ECF, 0xE4E7, 0x6E8F, 0xE4E8, 0x6EC2, 0xE4E9, 0x6E9F, 0xE4EA, 0x6F62, 0xE4EB, 0x6F46, 0xE4EC, 0x6F47, 0xE4ED, 0x6F24, 0xE4EE, 0x6F15, 0xE4EF, 0x6EF9, 0xE4F0, 0x6F2F, 0xE4F1, 0x6F36, 0xE4F2, 0x6F4B, 0xE4F3, 0x6F74, 0xE4F4, 0x6F2A, 0xE4F5, 0x6F09, 0xE4F6, 0x6F29, 0xE4F7, 0x6F89, 0xE4F8, 0x6F8D, 0xE4F9, 0x6F8C, 0xE4FA, 0x6F78, 0xE4FB, 0x6F72, 0xE4FC, 0x6F7C, 0xE4FD, 0x6F7A, 0xE4FE, 0x6FD1, 0xE540, 0x930A, 0xE541, 0x930B, 0xE542, 0x930C, 0xE543, 0x930D, 0xE544, 0x930E, 0xE545, 0x930F, 0xE546, 0x9310, 0xE547, 0x9311, 0xE548, 0x9312, 0xE549, 0x9313, 0xE54A, 0x9314, 0xE54B, 0x9315, 0xE54C, 0x9316, 0xE54D, 0x9317, 0xE54E, 0x9318, 0xE54F, 0x9319, 0xE550, 0x931A, 0xE551, 0x931B, 0xE552, 0x931C, 0xE553, 0x931D, 0xE554, 0x931E, 0xE555, 0x931F, 0xE556, 0x9320, 0xE557, 0x9321, 0xE558, 0x9322, 0xE559, 0x9323, 0xE55A, 0x9324, 0xE55B, 0x9325, 0xE55C, 0x9326, 0xE55D, 0x9327, 0xE55E, 0x9328, 0xE55F, 0x9329, 0xE560, 0x932A, 0xE561, 0x932B, 0xE562, 0x932C, 0xE563, 0x932D, 0xE564, 0x932E, 0xE565, 0x932F, 0xE566, 0x9330, 0xE567, 0x9331, 0xE568, 0x9332, 0xE569, 0x9333, 0xE56A, 0x9334, 0xE56B, 0x9335, 0xE56C, 0x9336, 0xE56D, 0x9337, 0xE56E, 0x9338, 0xE56F, 0x9339, 0xE570, 0x933A, 0xE571, 0x933B, 0xE572, 0x933C, 0xE573, 0x933D, 0xE574, 0x933F, 0xE575, 0x9340, 0xE576, 0x9341, 0xE577, 0x9342, 0xE578, 0x9343, 0xE579, 0x9344, 0xE57A, 0x9345, 0xE57B, 0x9346, 0xE57C, 0x9347, 0xE57D, 0x9348, 0xE57E, 0x9349, 0xE580, 0x934A, 0xE581, 0x934B, 0xE582, 0x934C, 0xE583, 0x934D, 0xE584, 0x934E, 0xE585, 0x934F, 0xE586, 0x9350, 0xE587, 0x9351, 0xE588, 0x9352, 0xE589, 0x9353, 0xE58A, 0x9354, 0xE58B, 0x9355, 0xE58C, 0x9356, 0xE58D, 0x9357, 0xE58E, 0x9358, 0xE58F, 0x9359, 0xE590, 0x935A, 0xE591, 0x935B, 0xE592, 0x935C, 0xE593, 0x935D, 0xE594, 0x935E, 0xE595, 0x935F, 0xE596, 0x9360, 0xE597, 0x9361, 0xE598, 0x9362, 0xE599, 0x9363, 0xE59A, 0x9364, 0xE59B, 0x9365, 0xE59C, 0x9366, 0xE59D, 0x9367, 0xE59E, 0x9368, 0xE59F, 0x9369, 0xE5A0, 0x936B, 0xE5A1, 0x6FC9, 0xE5A2, 0x6FA7, 0xE5A3, 0x6FB9, 0xE5A4, 0x6FB6, 0xE5A5, 0x6FC2, 0xE5A6, 0x6FE1, 0xE5A7, 0x6FEE, 0xE5A8, 0x6FDE, 0xE5A9, 0x6FE0, 0xE5AA, 0x6FEF, 0xE5AB, 0x701A, 0xE5AC, 0x7023, 0xE5AD, 0x701B, 0xE5AE, 0x7039, 0xE5AF, 0x7035, 0xE5B0, 0x704F, 0xE5B1, 0x705E, 0xE5B2, 0x5B80, 0xE5B3, 0x5B84, 0xE5B4, 0x5B95, 0xE5B5, 0x5B93, 0xE5B6, 0x5BA5, 0xE5B7, 0x5BB8, 0xE5B8, 0x752F, 0xE5B9, 0x9A9E, 0xE5BA, 0x6434, 0xE5BB, 0x5BE4, 0xE5BC, 0x5BEE, 0xE5BD, 0x8930, 0xE5BE, 0x5BF0, 0xE5BF, 0x8E47, 0xE5C0, 0x8B07, 0xE5C1, 0x8FB6, 0xE5C2, 0x8FD3, 0xE5C3, 0x8FD5, 0xE5C4, 0x8FE5, 0xE5C5, 0x8FEE, 0xE5C6, 0x8FE4, 0xE5C7, 0x8FE9, 0xE5C8, 0x8FE6, 0xE5C9, 0x8FF3, 0xE5CA, 0x8FE8, 0xE5CB, 0x9005, 0xE5CC, 0x9004, 0xE5CD, 0x900B, 0xE5CE, 0x9026, 0xE5CF, 0x9011, 0xE5D0, 0x900D, 0xE5D1, 0x9016, 0xE5D2, 0x9021, 0xE5D3, 0x9035, 0xE5D4, 0x9036, 0xE5D5, 0x902D, 0xE5D6, 0x902F, 0xE5D7, 0x9044, 0xE5D8, 0x9051, 0xE5D9, 0x9052, 0xE5DA, 0x9050, 0xE5DB, 0x9068, 0xE5DC, 0x9058, 0xE5DD, 0x9062, 0xE5DE, 0x905B, 0xE5DF, 0x66B9, 0xE5E0, 0x9074, 0xE5E1, 0x907D, 0xE5E2, 0x9082, 0xE5E3, 0x9088, 0xE5E4, 0x9083, 0xE5E5, 0x908B, 0xE5E6, 0x5F50, 0xE5E7, 0x5F57, 0xE5E8, 0x5F56, 0xE5E9, 0x5F58, 0xE5EA, 0x5C3B, 0xE5EB, 0x54AB, 0xE5EC, 0x5C50, 0xE5ED, 0x5C59, 0xE5EE, 0x5B71, 0xE5EF, 0x5C63, 0xE5F0, 0x5C66, 0xE5F1, 0x7FBC, 0xE5F2, 0x5F2A, 0xE5F3, 0x5F29, 0xE5F4, 0x5F2D, 0xE5F5, 0x8274, 0xE5F6, 0x5F3C, 0xE5F7, 0x9B3B, 0xE5F8, 0x5C6E, 0xE5F9, 0x5981, 0xE5FA, 0x5983, 0xE5FB, 0x598D, 0xE5FC, 0x59A9, 0xE5FD, 0x59AA, 0xE5FE, 0x59A3, 0xE640, 0x936C, 0xE641, 0x936D, 0xE642, 0x936E, 0xE643, 0x936F, 0xE644, 0x9370, 0xE645, 0x9371, 0xE646, 0x9372, 0xE647, 0x9373, 0xE648, 0x9374, 0xE649, 0x9375, 0xE64A, 0x9376, 0xE64B, 0x9377, 0xE64C, 0x9378, 0xE64D, 0x9379, 0xE64E, 0x937A, 0xE64F, 0x937B, 0xE650, 0x937C, 0xE651, 0x937D, 0xE652, 0x937E, 0xE653, 0x937F, 0xE654, 0x9380, 0xE655, 0x9381, 0xE656, 0x9382, 0xE657, 0x9383, 0xE658, 0x9384, 0xE659, 0x9385, 0xE65A, 0x9386, 0xE65B, 0x9387, 0xE65C, 0x9388, 0xE65D, 0x9389, 0xE65E, 0x938A, 0xE65F, 0x938B, 0xE660, 0x938C, 0xE661, 0x938D, 0xE662, 0x938E, 0xE663, 0x9390, 0xE664, 0x9391, 0xE665, 0x9392, 0xE666, 0x9393, 0xE667, 0x9394, 0xE668, 0x9395, 0xE669, 0x9396, 0xE66A, 0x9397, 0xE66B, 0x9398, 0xE66C, 0x9399, 0xE66D, 0x939A, 0xE66E, 0x939B, 0xE66F, 0x939C, 0xE670, 0x939D, 0xE671, 0x939E, 0xE672, 0x939F, 0xE673, 0x93A0, 0xE674, 0x93A1, 0xE675, 0x93A2, 0xE676, 0x93A3, 0xE677, 0x93A4, 0xE678, 0x93A5, 0xE679, 0x93A6, 0xE67A, 0x93A7, 0xE67B, 0x93A8, 0xE67C, 0x93A9, 0xE67D, 0x93AA, 0xE67E, 0x93AB, 0xE680, 0x93AC, 0xE681, 0x93AD, 0xE682, 0x93AE, 0xE683, 0x93AF, 0xE684, 0x93B0, 0xE685, 0x93B1, 0xE686, 0x93B2, 0xE687, 0x93B3, 0xE688, 0x93B4, 0xE689, 0x93B5, 0xE68A, 0x93B6, 0xE68B, 0x93B7, 0xE68C, 0x93B8, 0xE68D, 0x93B9, 0xE68E, 0x93BA, 0xE68F, 0x93BB, 0xE690, 0x93BC, 0xE691, 0x93BD, 0xE692, 0x93BE, 0xE693, 0x93BF, 0xE694, 0x93C0, 0xE695, 0x93C1, 0xE696, 0x93C2, 0xE697, 0x93C3, 0xE698, 0x93C4, 0xE699, 0x93C5, 0xE69A, 0x93C6, 0xE69B, 0x93C7, 0xE69C, 0x93C8, 0xE69D, 0x93C9, 0xE69E, 0x93CB, 0xE69F, 0x93CC, 0xE6A0, 0x93CD, 0xE6A1, 0x5997, 0xE6A2, 0x59CA, 0xE6A3, 0x59AB, 0xE6A4, 0x599E, 0xE6A5, 0x59A4, 0xE6A6, 0x59D2, 0xE6A7, 0x59B2, 0xE6A8, 0x59AF, 0xE6A9, 0x59D7, 0xE6AA, 0x59BE, 0xE6AB, 0x5A05, 0xE6AC, 0x5A06, 0xE6AD, 0x59DD, 0xE6AE, 0x5A08, 0xE6AF, 0x59E3, 0xE6B0, 0x59D8, 0xE6B1, 0x59F9, 0xE6B2, 0x5A0C, 0xE6B3, 0x5A09, 0xE6B4, 0x5A32, 0xE6B5, 0x5A34, 0xE6B6, 0x5A11, 0xE6B7, 0x5A23, 0xE6B8, 0x5A13, 0xE6B9, 0x5A40, 0xE6BA, 0x5A67, 0xE6BB, 0x5A4A, 0xE6BC, 0x5A55, 0xE6BD, 0x5A3C, 0xE6BE, 0x5A62, 0xE6BF, 0x5A75, 0xE6C0, 0x80EC, 0xE6C1, 0x5AAA, 0xE6C2, 0x5A9B, 0xE6C3, 0x5A77, 0xE6C4, 0x5A7A, 0xE6C5, 0x5ABE, 0xE6C6, 0x5AEB, 0xE6C7, 0x5AB2, 0xE6C8, 0x5AD2, 0xE6C9, 0x5AD4, 0xE6CA, 0x5AB8, 0xE6CB, 0x5AE0, 0xE6CC, 0x5AE3, 0xE6CD, 0x5AF1, 0xE6CE, 0x5AD6, 0xE6CF, 0x5AE6, 0xE6D0, 0x5AD8, 0xE6D1, 0x5ADC, 0xE6D2, 0x5B09, 0xE6D3, 0x5B17, 0xE6D4, 0x5B16, 0xE6D5, 0x5B32, 0xE6D6, 0x5B37, 0xE6D7, 0x5B40, 0xE6D8, 0x5C15, 0xE6D9, 0x5C1C, 0xE6DA, 0x5B5A, 0xE6DB, 0x5B65, 0xE6DC, 0x5B73, 0xE6DD, 0x5B51, 0xE6DE, 0x5B53, 0xE6DF, 0x5B62, 0xE6E0, 0x9A75, 0xE6E1, 0x9A77, 0xE6E2, 0x9A78, 0xE6E3, 0x9A7A, 0xE6E4, 0x9A7F, 0xE6E5, 0x9A7D, 0xE6E6, 0x9A80, 0xE6E7, 0x9A81, 0xE6E8, 0x9A85, 0xE6E9, 0x9A88, 0xE6EA, 0x9A8A, 0xE6EB, 0x9A90, 0xE6EC, 0x9A92, 0xE6ED, 0x9A93, 0xE6EE, 0x9A96, 0xE6EF, 0x9A98, 0xE6F0, 0x9A9B, 0xE6F1, 0x9A9C, 0xE6F2, 0x9A9D, 0xE6F3, 0x9A9F, 0xE6F4, 0x9AA0, 0xE6F5, 0x9AA2, 0xE6F6, 0x9AA3, 0xE6F7, 0x9AA5, 0xE6F8, 0x9AA7, 0xE6F9, 0x7E9F, 0xE6FA, 0x7EA1, 0xE6FB, 0x7EA3, 0xE6FC, 0x7EA5, 0xE6FD, 0x7EA8, 0xE6FE, 0x7EA9, 0xE740, 0x93CE, 0xE741, 0x93CF, 0xE742, 0x93D0, 0xE743, 0x93D1, 0xE744, 0x93D2, 0xE745, 0x93D3, 0xE746, 0x93D4, 0xE747, 0x93D5, 0xE748, 0x93D7, 0xE749, 0x93D8, 0xE74A, 0x93D9, 0xE74B, 0x93DA, 0xE74C, 0x93DB, 0xE74D, 0x93DC, 0xE74E, 0x93DD, 0xE74F, 0x93DE, 0xE750, 0x93DF, 0xE751, 0x93E0, 0xE752, 0x93E1, 0xE753, 0x93E2, 0xE754, 0x93E3, 0xE755, 0x93E4, 0xE756, 0x93E5, 0xE757, 0x93E6, 0xE758, 0x93E7, 0xE759, 0x93E8, 0xE75A, 0x93E9, 0xE75B, 0x93EA, 0xE75C, 0x93EB, 0xE75D, 0x93EC, 0xE75E, 0x93ED, 0xE75F, 0x93EE, 0xE760, 0x93EF, 0xE761, 0x93F0, 0xE762, 0x93F1, 0xE763, 0x93F2, 0xE764, 0x93F3, 0xE765, 0x93F4, 0xE766, 0x93F5, 0xE767, 0x93F6, 0xE768, 0x93F7, 0xE769, 0x93F8, 0xE76A, 0x93F9, 0xE76B, 0x93FA, 0xE76C, 0x93FB, 0xE76D, 0x93FC, 0xE76E, 0x93FD, 0xE76F, 0x93FE, 0xE770, 0x93FF, 0xE771, 0x9400, 0xE772, 0x9401, 0xE773, 0x9402, 0xE774, 0x9403, 0xE775, 0x9404, 0xE776, 0x9405, 0xE777, 0x9406, 0xE778, 0x9407, 0xE779, 0x9408, 0xE77A, 0x9409, 0xE77B, 0x940A, 0xE77C, 0x940B, 0xE77D, 0x940C, 0xE77E, 0x940D, 0xE780, 0x940E, 0xE781, 0x940F, 0xE782, 0x9410, 0xE783, 0x9411, 0xE784, 0x9412, 0xE785, 0x9413, 0xE786, 0x9414, 0xE787, 0x9415, 0xE788, 0x9416, 0xE789, 0x9417, 0xE78A, 0x9418, 0xE78B, 0x9419, 0xE78C, 0x941A, 0xE78D, 0x941B, 0xE78E, 0x941C, 0xE78F, 0x941D, 0xE790, 0x941E, 0xE791, 0x941F, 0xE792, 0x9420, 0xE793, 0x9421, 0xE794, 0x9422, 0xE795, 0x9423, 0xE796, 0x9424, 0xE797, 0x9425, 0xE798, 0x9426, 0xE799, 0x9427, 0xE79A, 0x9428, 0xE79B, 0x9429, 0xE79C, 0x942A, 0xE79D, 0x942B, 0xE79E, 0x942C, 0xE79F, 0x942D, 0xE7A0, 0x942E, 0xE7A1, 0x7EAD, 0xE7A2, 0x7EB0, 0xE7A3, 0x7EBE, 0xE7A4, 0x7EC0, 0xE7A5, 0x7EC1, 0xE7A6, 0x7EC2, 0xE7A7, 0x7EC9, 0xE7A8, 0x7ECB, 0xE7A9, 0x7ECC, 0xE7AA, 0x7ED0, 0xE7AB, 0x7ED4, 0xE7AC, 0x7ED7, 0xE7AD, 0x7EDB, 0xE7AE, 0x7EE0, 0xE7AF, 0x7EE1, 0xE7B0, 0x7EE8, 0xE7B1, 0x7EEB, 0xE7B2, 0x7EEE, 0xE7B3, 0x7EEF, 0xE7B4, 0x7EF1, 0xE7B5, 0x7EF2, 0xE7B6, 0x7F0D, 0xE7B7, 0x7EF6, 0xE7B8, 0x7EFA, 0xE7B9, 0x7EFB, 0xE7BA, 0x7EFE, 0xE7BB, 0x7F01, 0xE7BC, 0x7F02, 0xE7BD, 0x7F03, 0xE7BE, 0x7F07, 0xE7BF, 0x7F08, 0xE7C0, 0x7F0B, 0xE7C1, 0x7F0C, 0xE7C2, 0x7F0F, 0xE7C3, 0x7F11, 0xE7C4, 0x7F12, 0xE7C5, 0x7F17, 0xE7C6, 0x7F19, 0xE7C7, 0x7F1C, 0xE7C8, 0x7F1B, 0xE7C9, 0x7F1F, 0xE7CA, 0x7F21, 0xE7CB, 0x7F22, 0xE7CC, 0x7F23, 0xE7CD, 0x7F24, 0xE7CE, 0x7F25, 0xE7CF, 0x7F26, 0xE7D0, 0x7F27, 0xE7D1, 0x7F2A, 0xE7D2, 0x7F2B, 0xE7D3, 0x7F2C, 0xE7D4, 0x7F2D, 0xE7D5, 0x7F2F, 0xE7D6, 0x7F30, 0xE7D7, 0x7F31, 0xE7D8, 0x7F32, 0xE7D9, 0x7F33, 0xE7DA, 0x7F35, 0xE7DB, 0x5E7A, 0xE7DC, 0x757F, 0xE7DD, 0x5DDB, 0xE7DE, 0x753E, 0xE7DF, 0x9095, 0xE7E0, 0x738E, 0xE7E1, 0x7391, 0xE7E2, 0x73AE, 0xE7E3, 0x73A2, 0xE7E4, 0x739F, 0xE7E5, 0x73CF, 0xE7E6, 0x73C2, 0xE7E7, 0x73D1, 0xE7E8, 0x73B7, 0xE7E9, 0x73B3, 0xE7EA, 0x73C0, 0xE7EB, 0x73C9, 0xE7EC, 0x73C8, 0xE7ED, 0x73E5, 0xE7EE, 0x73D9, 0xE7EF, 0x987C, 0xE7F0, 0x740A, 0xE7F1, 0x73E9, 0xE7F2, 0x73E7, 0xE7F3, 0x73DE, 0xE7F4, 0x73BA, 0xE7F5, 0x73F2, 0xE7F6, 0x740F, 0xE7F7, 0x742A, 0xE7F8, 0x745B, 0xE7F9, 0x7426, 0xE7FA, 0x7425, 0xE7FB, 0x7428, 0xE7FC, 0x7430, 0xE7FD, 0x742E, 0xE7FE, 0x742C, 0xE840, 0x942F, 0xE841, 0x9430, 0xE842, 0x9431, 0xE843, 0x9432, 0xE844, 0x9433, 0xE845, 0x9434, 0xE846, 0x9435, 0xE847, 0x9436, 0xE848, 0x9437, 0xE849, 0x9438, 0xE84A, 0x9439, 0xE84B, 0x943A, 0xE84C, 0x943B, 0xE84D, 0x943C, 0xE84E, 0x943D, 0xE84F, 0x943F, 0xE850, 0x9440, 0xE851, 0x9441, 0xE852, 0x9442, 0xE853, 0x9443, 0xE854, 0x9444, 0xE855, 0x9445, 0xE856, 0x9446, 0xE857, 0x9447, 0xE858, 0x9448, 0xE859, 0x9449, 0xE85A, 0x944A, 0xE85B, 0x944B, 0xE85C, 0x944C, 0xE85D, 0x944D, 0xE85E, 0x944E, 0xE85F, 0x944F, 0xE860, 0x9450, 0xE861, 0x9451, 0xE862, 0x9452, 0xE863, 0x9453, 0xE864, 0x9454, 0xE865, 0x9455, 0xE866, 0x9456, 0xE867, 0x9457, 0xE868, 0x9458, 0xE869, 0x9459, 0xE86A, 0x945A, 0xE86B, 0x945B, 0xE86C, 0x945C, 0xE86D, 0x945D, 0xE86E, 0x945E, 0xE86F, 0x945F, 0xE870, 0x9460, 0xE871, 0x9461, 0xE872, 0x9462, 0xE873, 0x9463, 0xE874, 0x9464, 0xE875, 0x9465, 0xE876, 0x9466, 0xE877, 0x9467, 0xE878, 0x9468, 0xE879, 0x9469, 0xE87A, 0x946A, 0xE87B, 0x946C, 0xE87C, 0x946D, 0xE87D, 0x946E, 0xE87E, 0x946F, 0xE880, 0x9470, 0xE881, 0x9471, 0xE882, 0x9472, 0xE883, 0x9473, 0xE884, 0x9474, 0xE885, 0x9475, 0xE886, 0x9476, 0xE887, 0x9477, 0xE888, 0x9478, 0xE889, 0x9479, 0xE88A, 0x947A, 0xE88B, 0x947B, 0xE88C, 0x947C, 0xE88D, 0x947D, 0xE88E, 0x947E, 0xE88F, 0x947F, 0xE890, 0x9480, 0xE891, 0x9481, 0xE892, 0x9482, 0xE893, 0x9483, 0xE894, 0x9484, 0xE895, 0x9491, 0xE896, 0x9496, 0xE897, 0x9498, 0xE898, 0x94C7, 0xE899, 0x94CF, 0xE89A, 0x94D3, 0xE89B, 0x94D4, 0xE89C, 0x94DA, 0xE89D, 0x94E6, 0xE89E, 0x94FB, 0xE89F, 0x951C, 0xE8A0, 0x9520, 0xE8A1, 0x741B, 0xE8A2, 0x741A, 0xE8A3, 0x7441, 0xE8A4, 0x745C, 0xE8A5, 0x7457, 0xE8A6, 0x7455, 0xE8A7, 0x7459, 0xE8A8, 0x7477, 0xE8A9, 0x746D, 0xE8AA, 0x747E, 0xE8AB, 0x749C, 0xE8AC, 0x748E, 0xE8AD, 0x7480, 0xE8AE, 0x7481, 0xE8AF, 0x7487, 0xE8B0, 0x748B, 0xE8B1, 0x749E, 0xE8B2, 0x74A8, 0xE8B3, 0x74A9, 0xE8B4, 0x7490, 0xE8B5, 0x74A7, 0xE8B6, 0x74D2, 0xE8B7, 0x74BA, 0xE8B8, 0x97EA, 0xE8B9, 0x97EB, 0xE8BA, 0x97EC, 0xE8BB, 0x674C, 0xE8BC, 0x6753, 0xE8BD, 0x675E, 0xE8BE, 0x6748, 0xE8BF, 0x6769, 0xE8C0, 0x67A5, 0xE8C1, 0x6787, 0xE8C2, 0x676A, 0xE8C3, 0x6773, 0xE8C4, 0x6798, 0xE8C5, 0x67A7, 0xE8C6, 0x6775, 0xE8C7, 0x67A8, 0xE8C8, 0x679E, 0xE8C9, 0x67AD, 0xE8CA, 0x678B, 0xE8CB, 0x6777, 0xE8CC, 0x677C, 0xE8CD, 0x67F0, 0xE8CE, 0x6809, 0xE8CF, 0x67D8, 0xE8D0, 0x680A, 0xE8D1, 0x67E9, 0xE8D2, 0x67B0, 0xE8D3, 0x680C, 0xE8D4, 0x67D9, 0xE8D5, 0x67B5, 0xE8D6, 0x67DA, 0xE8D7, 0x67B3, 0xE8D8, 0x67DD, 0xE8D9, 0x6800, 0xE8DA, 0x67C3, 0xE8DB, 0x67B8, 0xE8DC, 0x67E2, 0xE8DD, 0x680E, 0xE8DE, 0x67C1, 0xE8DF, 0x67FD, 0xE8E0, 0x6832, 0xE8E1, 0x6833, 0xE8E2, 0x6860, 0xE8E3, 0x6861, 0xE8E4, 0x684E, 0xE8E5, 0x6862, 0xE8E6, 0x6844, 0xE8E7, 0x6864, 0xE8E8, 0x6883, 0xE8E9, 0x681D, 0xE8EA, 0x6855, 0xE8EB, 0x6866, 0xE8EC, 0x6841, 0xE8ED, 0x6867, 0xE8EE, 0x6840, 0xE8EF, 0x683E, 0xE8F0, 0x684A, 0xE8F1, 0x6849, 0xE8F2, 0x6829, 0xE8F3, 0x68B5, 0xE8F4, 0x688F, 0xE8F5, 0x6874, 0xE8F6, 0x6877, 0xE8F7, 0x6893, 0xE8F8, 0x686B, 0xE8F9, 0x68C2, 0xE8FA, 0x696E, 0xE8FB, 0x68FC, 0xE8FC, 0x691F, 0xE8FD, 0x6920, 0xE8FE, 0x68F9, 0xE940, 0x9527, 0xE941, 0x9533, 0xE942, 0x953D, 0xE943, 0x9543, 0xE944, 0x9548, 0xE945, 0x954B, 0xE946, 0x9555, 0xE947, 0x955A, 0xE948, 0x9560, 0xE949, 0x956E, 0xE94A, 0x9574, 0xE94B, 0x9575, 0xE94C, 0x9577, 0xE94D, 0x9578, 0xE94E, 0x9579, 0xE94F, 0x957A, 0xE950, 0x957B, 0xE951, 0x957C, 0xE952, 0x957D, 0xE953, 0x957E, 0xE954, 0x9580, 0xE955, 0x9581, 0xE956, 0x9582, 0xE957, 0x9583, 0xE958, 0x9584, 0xE959, 0x9585, 0xE95A, 0x9586, 0xE95B, 0x9587, 0xE95C, 0x9588, 0xE95D, 0x9589, 0xE95E, 0x958A, 0xE95F, 0x958B, 0xE960, 0x958C, 0xE961, 0x958D, 0xE962, 0x958E, 0xE963, 0x958F, 0xE964, 0x9590, 0xE965, 0x9591, 0xE966, 0x9592, 0xE967, 0x9593, 0xE968, 0x9594, 0xE969, 0x9595, 0xE96A, 0x9596, 0xE96B, 0x9597, 0xE96C, 0x9598, 0xE96D, 0x9599, 0xE96E, 0x959A, 0xE96F, 0x959B, 0xE970, 0x959C, 0xE971, 0x959D, 0xE972, 0x959E, 0xE973, 0x959F, 0xE974, 0x95A0, 0xE975, 0x95A1, 0xE976, 0x95A2, 0xE977, 0x95A3, 0xE978, 0x95A4, 0xE979, 0x95A5, 0xE97A, 0x95A6, 0xE97B, 0x95A7, 0xE97C, 0x95A8, 0xE97D, 0x95A9, 0xE97E, 0x95AA, 0xE980, 0x95AB, 0xE981, 0x95AC, 0xE982, 0x95AD, 0xE983, 0x95AE, 0xE984, 0x95AF, 0xE985, 0x95B0, 0xE986, 0x95B1, 0xE987, 0x95B2, 0xE988, 0x95B3, 0xE989, 0x95B4, 0xE98A, 0x95B5, 0xE98B, 0x95B6, 0xE98C, 0x95B7, 0xE98D, 0x95B8, 0xE98E, 0x95B9, 0xE98F, 0x95BA, 0xE990, 0x95BB, 0xE991, 0x95BC, 0xE992, 0x95BD, 0xE993, 0x95BE, 0xE994, 0x95BF, 0xE995, 0x95C0, 0xE996, 0x95C1, 0xE997, 0x95C2, 0xE998, 0x95C3, 0xE999, 0x95C4, 0xE99A, 0x95C5, 0xE99B, 0x95C6, 0xE99C, 0x95C7, 0xE99D, 0x95C8, 0xE99E, 0x95C9, 0xE99F, 0x95CA, 0xE9A0, 0x95CB, 0xE9A1, 0x6924, 0xE9A2, 0x68F0, 0xE9A3, 0x690B, 0xE9A4, 0x6901, 0xE9A5, 0x6957, 0xE9A6, 0x68E3, 0xE9A7, 0x6910, 0xE9A8, 0x6971, 0xE9A9, 0x6939, 0xE9AA, 0x6960, 0xE9AB, 0x6942, 0xE9AC, 0x695D, 0xE9AD, 0x6984, 0xE9AE, 0x696B, 0xE9AF, 0x6980, 0xE9B0, 0x6998, 0xE9B1, 0x6978, 0xE9B2, 0x6934, 0xE9B3, 0x69CC, 0xE9B4, 0x6987, 0xE9B5, 0x6988, 0xE9B6, 0x69CE, 0xE9B7, 0x6989, 0xE9B8, 0x6966, 0xE9B9, 0x6963, 0xE9BA, 0x6979, 0xE9BB, 0x699B, 0xE9BC, 0x69A7, 0xE9BD, 0x69BB, 0xE9BE, 0x69AB, 0xE9BF, 0x69AD, 0xE9C0, 0x69D4, 0xE9C1, 0x69B1, 0xE9C2, 0x69C1, 0xE9C3, 0x69CA, 0xE9C4, 0x69DF, 0xE9C5, 0x6995, 0xE9C6, 0x69E0, 0xE9C7, 0x698D, 0xE9C8, 0x69FF, 0xE9C9, 0x6A2F, 0xE9CA, 0x69ED, 0xE9CB, 0x6A17, 0xE9CC, 0x6A18, 0xE9CD, 0x6A65, 0xE9CE, 0x69F2, 0xE9CF, 0x6A44, 0xE9D0, 0x6A3E, 0xE9D1, 0x6AA0, 0xE9D2, 0x6A50, 0xE9D3, 0x6A5B, 0xE9D4, 0x6A35, 0xE9D5, 0x6A8E, 0xE9D6, 0x6A79, 0xE9D7, 0x6A3D, 0xE9D8, 0x6A28, 0xE9D9, 0x6A58, 0xE9DA, 0x6A7C, 0xE9DB, 0x6A91, 0xE9DC, 0x6A90, 0xE9DD, 0x6AA9, 0xE9DE, 0x6A97, 0xE9DF, 0x6AAB, 0xE9E0, 0x7337, 0xE9E1, 0x7352, 0xE9E2, 0x6B81, 0xE9E3, 0x6B82, 0xE9E4, 0x6B87, 0xE9E5, 0x6B84, 0xE9E6, 0x6B92, 0xE9E7, 0x6B93, 0xE9E8, 0x6B8D, 0xE9E9, 0x6B9A, 0xE9EA, 0x6B9B, 0xE9EB, 0x6BA1, 0xE9EC, 0x6BAA, 0xE9ED, 0x8F6B, 0xE9EE, 0x8F6D, 0xE9EF, 0x8F71, 0xE9F0, 0x8F72, 0xE9F1, 0x8F73, 0xE9F2, 0x8F75, 0xE9F3, 0x8F76, 0xE9F4, 0x8F78, 0xE9F5, 0x8F77, 0xE9F6, 0x8F79, 0xE9F7, 0x8F7A, 0xE9F8, 0x8F7C, 0xE9F9, 0x8F7E, 0xE9FA, 0x8F81, 0xE9FB, 0x8F82, 0xE9FC, 0x8F84, 0xE9FD, 0x8F87, 0xE9FE, 0x8F8B, 0xEA40, 0x95CC, 0xEA41, 0x95CD, 0xEA42, 0x95CE, 0xEA43, 0x95CF, 0xEA44, 0x95D0, 0xEA45, 0x95D1, 0xEA46, 0x95D2, 0xEA47, 0x95D3, 0xEA48, 0x95D4, 0xEA49, 0x95D5, 0xEA4A, 0x95D6, 0xEA4B, 0x95D7, 0xEA4C, 0x95D8, 0xEA4D, 0x95D9, 0xEA4E, 0x95DA, 0xEA4F, 0x95DB, 0xEA50, 0x95DC, 0xEA51, 0x95DD, 0xEA52, 0x95DE, 0xEA53, 0x95DF, 0xEA54, 0x95E0, 0xEA55, 0x95E1, 0xEA56, 0x95E2, 0xEA57, 0x95E3, 0xEA58, 0x95E4, 0xEA59, 0x95E5, 0xEA5A, 0x95E6, 0xEA5B, 0x95E7, 0xEA5C, 0x95EC, 0xEA5D, 0x95FF, 0xEA5E, 0x9607, 0xEA5F, 0x9613, 0xEA60, 0x9618, 0xEA61, 0x961B, 0xEA62, 0x961E, 0xEA63, 0x9620, 0xEA64, 0x9623, 0xEA65, 0x9624, 0xEA66, 0x9625, 0xEA67, 0x9626, 0xEA68, 0x9627, 0xEA69, 0x9628, 0xEA6A, 0x9629, 0xEA6B, 0x962B, 0xEA6C, 0x962C, 0xEA6D, 0x962D, 0xEA6E, 0x962F, 0xEA6F, 0x9630, 0xEA70, 0x9637, 0xEA71, 0x9638, 0xEA72, 0x9639, 0xEA73, 0x963A, 0xEA74, 0x963E, 0xEA75, 0x9641, 0xEA76, 0x9643, 0xEA77, 0x964A, 0xEA78, 0x964E, 0xEA79, 0x964F, 0xEA7A, 0x9651, 0xEA7B, 0x9652, 0xEA7C, 0x9653, 0xEA7D, 0x9656, 0xEA7E, 0x9657, 0xEA80, 0x9658, 0xEA81, 0x9659, 0xEA82, 0x965A, 0xEA83, 0x965C, 0xEA84, 0x965D, 0xEA85, 0x965E, 0xEA86, 0x9660, 0xEA87, 0x9663, 0xEA88, 0x9665, 0xEA89, 0x9666, 0xEA8A, 0x966B, 0xEA8B, 0x966D, 0xEA8C, 0x966E, 0xEA8D, 0x966F, 0xEA8E, 0x9670, 0xEA8F, 0x9671, 0xEA90, 0x9673, 0xEA91, 0x9678, 0xEA92, 0x9679, 0xEA93, 0x967A, 0xEA94, 0x967B, 0xEA95, 0x967C, 0xEA96, 0x967D, 0xEA97, 0x967E, 0xEA98, 0x967F, 0xEA99, 0x9680, 0xEA9A, 0x9681, 0xEA9B, 0x9682, 0xEA9C, 0x9683, 0xEA9D, 0x9684, 0xEA9E, 0x9687, 0xEA9F, 0x9689, 0xEAA0, 0x968A, 0xEAA1, 0x8F8D, 0xEAA2, 0x8F8E, 0xEAA3, 0x8F8F, 0xEAA4, 0x8F98, 0xEAA5, 0x8F9A, 0xEAA6, 0x8ECE, 0xEAA7, 0x620B, 0xEAA8, 0x6217, 0xEAA9, 0x621B, 0xEAAA, 0x621F, 0xEAAB, 0x6222, 0xEAAC, 0x6221, 0xEAAD, 0x6225, 0xEAAE, 0x6224, 0xEAAF, 0x622C, 0xEAB0, 0x81E7, 0xEAB1, 0x74EF, 0xEAB2, 0x74F4, 0xEAB3, 0x74FF, 0xEAB4, 0x750F, 0xEAB5, 0x7511, 0xEAB6, 0x7513, 0xEAB7, 0x6534, 0xEAB8, 0x65EE, 0xEAB9, 0x65EF, 0xEABA, 0x65F0, 0xEABB, 0x660A, 0xEABC, 0x6619, 0xEABD, 0x6772, 0xEABE, 0x6603, 0xEABF, 0x6615, 0xEAC0, 0x6600, 0xEAC1, 0x7085, 0xEAC2, 0x66F7, 0xEAC3, 0x661D, 0xEAC4, 0x6634, 0xEAC5, 0x6631, 0xEAC6, 0x6636, 0xEAC7, 0x6635, 0xEAC8, 0x8006, 0xEAC9, 0x665F, 0xEACA, 0x6654, 0xEACB, 0x6641, 0xEACC, 0x664F, 0xEACD, 0x6656, 0xEACE, 0x6661, 0xEACF, 0x6657, 0xEAD0, 0x6677, 0xEAD1, 0x6684, 0xEAD2, 0x668C, 0xEAD3, 0x66A7, 0xEAD4, 0x669D, 0xEAD5, 0x66BE, 0xEAD6, 0x66DB, 0xEAD7, 0x66DC, 0xEAD8, 0x66E6, 0xEAD9, 0x66E9, 0xEADA, 0x8D32, 0xEADB, 0x8D33, 0xEADC, 0x8D36, 0xEADD, 0x8D3B, 0xEADE, 0x8D3D, 0xEADF, 0x8D40, 0xEAE0, 0x8D45, 0xEAE1, 0x8D46, 0xEAE2, 0x8D48, 0xEAE3, 0x8D49, 0xEAE4, 0x8D47, 0xEAE5, 0x8D4D, 0xEAE6, 0x8D55, 0xEAE7, 0x8D59, 0xEAE8, 0x89C7, 0xEAE9, 0x89CA, 0xEAEA, 0x89CB, 0xEAEB, 0x89CC, 0xEAEC, 0x89CE, 0xEAED, 0x89CF, 0xEAEE, 0x89D0, 0xEAEF, 0x89D1, 0xEAF0, 0x726E, 0xEAF1, 0x729F, 0xEAF2, 0x725D, 0xEAF3, 0x7266, 0xEAF4, 0x726F, 0xEAF5, 0x727E, 0xEAF6, 0x727F, 0xEAF7, 0x7284, 0xEAF8, 0x728B, 0xEAF9, 0x728D, 0xEAFA, 0x728F, 0xEAFB, 0x7292, 0xEAFC, 0x6308, 0xEAFD, 0x6332, 0xEAFE, 0x63B0, 0xEB40, 0x968C, 0xEB41, 0x968E, 0xEB42, 0x9691, 0xEB43, 0x9692, 0xEB44, 0x9693, 0xEB45, 0x9695, 0xEB46, 0x9696, 0xEB47, 0x969A, 0xEB48, 0x969B, 0xEB49, 0x969D, 0xEB4A, 0x969E, 0xEB4B, 0x969F, 0xEB4C, 0x96A0, 0xEB4D, 0x96A1, 0xEB4E, 0x96A2, 0xEB4F, 0x96A3, 0xEB50, 0x96A4, 0xEB51, 0x96A5, 0xEB52, 0x96A6, 0xEB53, 0x96A8, 0xEB54, 0x96A9, 0xEB55, 0x96AA, 0xEB56, 0x96AB, 0xEB57, 0x96AC, 0xEB58, 0x96AD, 0xEB59, 0x96AE, 0xEB5A, 0x96AF, 0xEB5B, 0x96B1, 0xEB5C, 0x96B2, 0xEB5D, 0x96B4, 0xEB5E, 0x96B5, 0xEB5F, 0x96B7, 0xEB60, 0x96B8, 0xEB61, 0x96BA, 0xEB62, 0x96BB, 0xEB63, 0x96BF, 0xEB64, 0x96C2, 0xEB65, 0x96C3, 0xEB66, 0x96C8, 0xEB67, 0x96CA, 0xEB68, 0x96CB, 0xEB69, 0x96D0, 0xEB6A, 0x96D1, 0xEB6B, 0x96D3, 0xEB6C, 0x96D4, 0xEB6D, 0x96D6, 0xEB6E, 0x96D7, 0xEB6F, 0x96D8, 0xEB70, 0x96D9, 0xEB71, 0x96DA, 0xEB72, 0x96DB, 0xEB73, 0x96DC, 0xEB74, 0x96DD, 0xEB75, 0x96DE, 0xEB76, 0x96DF, 0xEB77, 0x96E1, 0xEB78, 0x96E2, 0xEB79, 0x96E3, 0xEB7A, 0x96E4, 0xEB7B, 0x96E5, 0xEB7C, 0x96E6, 0xEB7D, 0x96E7, 0xEB7E, 0x96EB, 0xEB80, 0x96EC, 0xEB81, 0x96ED, 0xEB82, 0x96EE, 0xEB83, 0x96F0, 0xEB84, 0x96F1, 0xEB85, 0x96F2, 0xEB86, 0x96F4, 0xEB87, 0x96F5, 0xEB88, 0x96F8, 0xEB89, 0x96FA, 0xEB8A, 0x96FB, 0xEB8B, 0x96FC, 0xEB8C, 0x96FD, 0xEB8D, 0x96FF, 0xEB8E, 0x9702, 0xEB8F, 0x9703, 0xEB90, 0x9705, 0xEB91, 0x970A, 0xEB92, 0x970B, 0xEB93, 0x970C, 0xEB94, 0x9710, 0xEB95, 0x9711, 0xEB96, 0x9712, 0xEB97, 0x9714, 0xEB98, 0x9715, 0xEB99, 0x9717, 0xEB9A, 0x9718, 0xEB9B, 0x9719, 0xEB9C, 0x971A, 0xEB9D, 0x971B, 0xEB9E, 0x971D, 0xEB9F, 0x971F, 0xEBA0, 0x9720, 0xEBA1, 0x643F, 0xEBA2, 0x64D8, 0xEBA3, 0x8004, 0xEBA4, 0x6BEA, 0xEBA5, 0x6BF3, 0xEBA6, 0x6BFD, 0xEBA7, 0x6BF5, 0xEBA8, 0x6BF9, 0xEBA9, 0x6C05, 0xEBAA, 0x6C07, 0xEBAB, 0x6C06, 0xEBAC, 0x6C0D, 0xEBAD, 0x6C15, 0xEBAE, 0x6C18, 0xEBAF, 0x6C19, 0xEBB0, 0x6C1A, 0xEBB1, 0x6C21, 0xEBB2, 0x6C29, 0xEBB3, 0x6C24, 0xEBB4, 0x6C2A, 0xEBB5, 0x6C32, 0xEBB6, 0x6535, 0xEBB7, 0x6555, 0xEBB8, 0x656B, 0xEBB9, 0x724D, 0xEBBA, 0x7252, 0xEBBB, 0x7256, 0xEBBC, 0x7230, 0xEBBD, 0x8662, 0xEBBE, 0x5216, 0xEBBF, 0x809F, 0xEBC0, 0x809C, 0xEBC1, 0x8093, 0xEBC2, 0x80BC, 0xEBC3, 0x670A, 0xEBC4, 0x80BD, 0xEBC5, 0x80B1, 0xEBC6, 0x80AB, 0xEBC7, 0x80AD, 0xEBC8, 0x80B4, 0xEBC9, 0x80B7, 0xEBCA, 0x80E7, 0xEBCB, 0x80E8, 0xEBCC, 0x80E9, 0xEBCD, 0x80EA, 0xEBCE, 0x80DB, 0xEBCF, 0x80C2, 0xEBD0, 0x80C4, 0xEBD1, 0x80D9, 0xEBD2, 0x80CD, 0xEBD3, 0x80D7, 0xEBD4, 0x6710, 0xEBD5, 0x80DD, 0xEBD6, 0x80EB, 0xEBD7, 0x80F1, 0xEBD8, 0x80F4, 0xEBD9, 0x80ED, 0xEBDA, 0x810D, 0xEBDB, 0x810E, 0xEBDC, 0x80F2, 0xEBDD, 0x80FC, 0xEBDE, 0x6715, 0xEBDF, 0x8112, 0xEBE0, 0x8C5A, 0xEBE1, 0x8136, 0xEBE2, 0x811E, 0xEBE3, 0x812C, 0xEBE4, 0x8118, 0xEBE5, 0x8132, 0xEBE6, 0x8148, 0xEBE7, 0x814C, 0xEBE8, 0x8153, 0xEBE9, 0x8174, 0xEBEA, 0x8159, 0xEBEB, 0x815A, 0xEBEC, 0x8171, 0xEBED, 0x8160, 0xEBEE, 0x8169, 0xEBEF, 0x817C, 0xEBF0, 0x817D, 0xEBF1, 0x816D, 0xEBF2, 0x8167, 0xEBF3, 0x584D, 0xEBF4, 0x5AB5, 0xEBF5, 0x8188, 0xEBF6, 0x8182, 0xEBF7, 0x8191, 0xEBF8, 0x6ED5, 0xEBF9, 0x81A3, 0xEBFA, 0x81AA, 0xEBFB, 0x81CC, 0xEBFC, 0x6726, 0xEBFD, 0x81CA, 0xEBFE, 0x81BB, 0xEC40, 0x9721, 0xEC41, 0x9722, 0xEC42, 0x9723, 0xEC43, 0x9724, 0xEC44, 0x9725, 0xEC45, 0x9726, 0xEC46, 0x9727, 0xEC47, 0x9728, 0xEC48, 0x9729, 0xEC49, 0x972B, 0xEC4A, 0x972C, 0xEC4B, 0x972E, 0xEC4C, 0x972F, 0xEC4D, 0x9731, 0xEC4E, 0x9733, 0xEC4F, 0x9734, 0xEC50, 0x9735, 0xEC51, 0x9736, 0xEC52, 0x9737, 0xEC53, 0x973A, 0xEC54, 0x973B, 0xEC55, 0x973C, 0xEC56, 0x973D, 0xEC57, 0x973F, 0xEC58, 0x9740, 0xEC59, 0x9741, 0xEC5A, 0x9742, 0xEC5B, 0x9743, 0xEC5C, 0x9744, 0xEC5D, 0x9745, 0xEC5E, 0x9746, 0xEC5F, 0x9747, 0xEC60, 0x9748, 0xEC61, 0x9749, 0xEC62, 0x974A, 0xEC63, 0x974B, 0xEC64, 0x974C, 0xEC65, 0x974D, 0xEC66, 0x974E, 0xEC67, 0x974F, 0xEC68, 0x9750, 0xEC69, 0x9751, 0xEC6A, 0x9754, 0xEC6B, 0x9755, 0xEC6C, 0x9757, 0xEC6D, 0x9758, 0xEC6E, 0x975A, 0xEC6F, 0x975C, 0xEC70, 0x975D, 0xEC71, 0x975F, 0xEC72, 0x9763, 0xEC73, 0x9764, 0xEC74, 0x9766, 0xEC75, 0x9767, 0xEC76, 0x9768, 0xEC77, 0x976A, 0xEC78, 0x976B, 0xEC79, 0x976C, 0xEC7A, 0x976D, 0xEC7B, 0x976E, 0xEC7C, 0x976F, 0xEC7D, 0x9770, 0xEC7E, 0x9771, 0xEC80, 0x9772, 0xEC81, 0x9775, 0xEC82, 0x9777, 0xEC83, 0x9778, 0xEC84, 0x9779, 0xEC85, 0x977A, 0xEC86, 0x977B, 0xEC87, 0x977D, 0xEC88, 0x977E, 0xEC89, 0x977F, 0xEC8A, 0x9780, 0xEC8B, 0x9781, 0xEC8C, 0x9782, 0xEC8D, 0x9783, 0xEC8E, 0x9784, 0xEC8F, 0x9786, 0xEC90, 0x9787, 0xEC91, 0x9788, 0xEC92, 0x9789, 0xEC93, 0x978A, 0xEC94, 0x978C, 0xEC95, 0x978E, 0xEC96, 0x978F, 0xEC97, 0x9790, 0xEC98, 0x9793, 0xEC99, 0x9795, 0xEC9A, 0x9796, 0xEC9B, 0x9797, 0xEC9C, 0x9799, 0xEC9D, 0x979A, 0xEC9E, 0x979B, 0xEC9F, 0x979C, 0xECA0, 0x979D, 0xECA1, 0x81C1, 0xECA2, 0x81A6, 0xECA3, 0x6B24, 0xECA4, 0x6B37, 0xECA5, 0x6B39, 0xECA6, 0x6B43, 0xECA7, 0x6B46, 0xECA8, 0x6B59, 0xECA9, 0x98D1, 0xECAA, 0x98D2, 0xECAB, 0x98D3, 0xECAC, 0x98D5, 0xECAD, 0x98D9, 0xECAE, 0x98DA, 0xECAF, 0x6BB3, 0xECB0, 0x5F40, 0xECB1, 0x6BC2, 0xECB2, 0x89F3, 0xECB3, 0x6590, 0xECB4, 0x9F51, 0xECB5, 0x6593, 0xECB6, 0x65BC, 0xECB7, 0x65C6, 0xECB8, 0x65C4, 0xECB9, 0x65C3, 0xECBA, 0x65CC, 0xECBB, 0x65CE, 0xECBC, 0x65D2, 0xECBD, 0x65D6, 0xECBE, 0x7080, 0xECBF, 0x709C, 0xECC0, 0x7096, 0xECC1, 0x709D, 0xECC2, 0x70BB, 0xECC3, 0x70C0, 0xECC4, 0x70B7, 0xECC5, 0x70AB, 0xECC6, 0x70B1, 0xECC7, 0x70E8, 0xECC8, 0x70CA, 0xECC9, 0x7110, 0xECCA, 0x7113, 0xECCB, 0x7116, 0xECCC, 0x712F, 0xECCD, 0x7131, 0xECCE, 0x7173, 0xECCF, 0x715C, 0xECD0, 0x7168, 0xECD1, 0x7145, 0xECD2, 0x7172, 0xECD3, 0x714A, 0xECD4, 0x7178, 0xECD5, 0x717A, 0xECD6, 0x7198, 0xECD7, 0x71B3, 0xECD8, 0x71B5, 0xECD9, 0x71A8, 0xECDA, 0x71A0, 0xECDB, 0x71E0, 0xECDC, 0x71D4, 0xECDD, 0x71E7, 0xECDE, 0x71F9, 0xECDF, 0x721D, 0xECE0, 0x7228, 0xECE1, 0x706C, 0xECE2, 0x7118, 0xECE3, 0x7166, 0xECE4, 0x71B9, 0xECE5, 0x623E, 0xECE6, 0x623D, 0xECE7, 0x6243, 0xECE8, 0x6248, 0xECE9, 0x6249, 0xECEA, 0x793B, 0xECEB, 0x7940, 0xECEC, 0x7946, 0xECED, 0x7949, 0xECEE, 0x795B, 0xECEF, 0x795C, 0xECF0, 0x7953, 0xECF1, 0x795A, 0xECF2, 0x7962, 0xECF3, 0x7957, 0xECF4, 0x7960, 0xECF5, 0x796F, 0xECF6, 0x7967, 0xECF7, 0x797A, 0xECF8, 0x7985, 0xECF9, 0x798A, 0xECFA, 0x799A, 0xECFB, 0x79A7, 0xECFC, 0x79B3, 0xECFD, 0x5FD1, 0xECFE, 0x5FD0, 0xED40, 0x979E, 0xED41, 0x979F, 0xED42, 0x97A1, 0xED43, 0x97A2, 0xED44, 0x97A4, 0xED45, 0x97A5, 0xED46, 0x97A6, 0xED47, 0x97A7, 0xED48, 0x97A8, 0xED49, 0x97A9, 0xED4A, 0x97AA, 0xED4B, 0x97AC, 0xED4C, 0x97AE, 0xED4D, 0x97B0, 0xED4E, 0x97B1, 0xED4F, 0x97B3, 0xED50, 0x97B5, 0xED51, 0x97B6, 0xED52, 0x97B7, 0xED53, 0x97B8, 0xED54, 0x97B9, 0xED55, 0x97BA, 0xED56, 0x97BB, 0xED57, 0x97BC, 0xED58, 0x97BD, 0xED59, 0x97BE, 0xED5A, 0x97BF, 0xED5B, 0x97C0, 0xED5C, 0x97C1, 0xED5D, 0x97C2, 0xED5E, 0x97C3, 0xED5F, 0x97C4, 0xED60, 0x97C5, 0xED61, 0x97C6, 0xED62, 0x97C7, 0xED63, 0x97C8, 0xED64, 0x97C9, 0xED65, 0x97CA, 0xED66, 0x97CB, 0xED67, 0x97CC, 0xED68, 0x97CD, 0xED69, 0x97CE, 0xED6A, 0x97CF, 0xED6B, 0x97D0, 0xED6C, 0x97D1, 0xED6D, 0x97D2, 0xED6E, 0x97D3, 0xED6F, 0x97D4, 0xED70, 0x97D5, 0xED71, 0x97D6, 0xED72, 0x97D7, 0xED73, 0x97D8, 0xED74, 0x97D9, 0xED75, 0x97DA, 0xED76, 0x97DB, 0xED77, 0x97DC, 0xED78, 0x97DD, 0xED79, 0x97DE, 0xED7A, 0x97DF, 0xED7B, 0x97E0, 0xED7C, 0x97E1, 0xED7D, 0x97E2, 0xED7E, 0x97E3, 0xED80, 0x97E4, 0xED81, 0x97E5, 0xED82, 0x97E8, 0xED83, 0x97EE, 0xED84, 0x97EF, 0xED85, 0x97F0, 0xED86, 0x97F1, 0xED87, 0x97F2, 0xED88, 0x97F4, 0xED89, 0x97F7, 0xED8A, 0x97F8, 0xED8B, 0x97F9, 0xED8C, 0x97FA, 0xED8D, 0x97FB, 0xED8E, 0x97FC, 0xED8F, 0x97FD, 0xED90, 0x97FE, 0xED91, 0x97FF, 0xED92, 0x9800, 0xED93, 0x9801, 0xED94, 0x9802, 0xED95, 0x9803, 0xED96, 0x9804, 0xED97, 0x9805, 0xED98, 0x9806, 0xED99, 0x9807, 0xED9A, 0x9808, 0xED9B, 0x9809, 0xED9C, 0x980A, 0xED9D, 0x980B, 0xED9E, 0x980C, 0xED9F, 0x980D, 0xEDA0, 0x980E, 0xEDA1, 0x603C, 0xEDA2, 0x605D, 0xEDA3, 0x605A, 0xEDA4, 0x6067, 0xEDA5, 0x6041, 0xEDA6, 0x6059, 0xEDA7, 0x6063, 0xEDA8, 0x60AB, 0xEDA9, 0x6106, 0xEDAA, 0x610D, 0xEDAB, 0x615D, 0xEDAC, 0x61A9, 0xEDAD, 0x619D, 0xEDAE, 0x61CB, 0xEDAF, 0x61D1, 0xEDB0, 0x6206, 0xEDB1, 0x8080, 0xEDB2, 0x807F, 0xEDB3, 0x6C93, 0xEDB4, 0x6CF6, 0xEDB5, 0x6DFC, 0xEDB6, 0x77F6, 0xEDB7, 0x77F8, 0xEDB8, 0x7800, 0xEDB9, 0x7809, 0xEDBA, 0x7817, 0xEDBB, 0x7818, 0xEDBC, 0x7811, 0xEDBD, 0x65AB, 0xEDBE, 0x782D, 0xEDBF, 0x781C, 0xEDC0, 0x781D, 0xEDC1, 0x7839, 0xEDC2, 0x783A, 0xEDC3, 0x783B, 0xEDC4, 0x781F, 0xEDC5, 0x783C, 0xEDC6, 0x7825, 0xEDC7, 0x782C, 0xEDC8, 0x7823, 0xEDC9, 0x7829, 0xEDCA, 0x784E, 0xEDCB, 0x786D, 0xEDCC, 0x7856, 0xEDCD, 0x7857, 0xEDCE, 0x7826, 0xEDCF, 0x7850, 0xEDD0, 0x7847, 0xEDD1, 0x784C, 0xEDD2, 0x786A, 0xEDD3, 0x789B, 0xEDD4, 0x7893, 0xEDD5, 0x789A, 0xEDD6, 0x7887, 0xEDD7, 0x789C, 0xEDD8, 0x78A1, 0xEDD9, 0x78A3, 0xEDDA, 0x78B2, 0xEDDB, 0x78B9, 0xEDDC, 0x78A5, 0xEDDD, 0x78D4, 0xEDDE, 0x78D9, 0xEDDF, 0x78C9, 0xEDE0, 0x78EC, 0xEDE1, 0x78F2, 0xEDE2, 0x7905, 0xEDE3, 0x78F4, 0xEDE4, 0x7913, 0xEDE5, 0x7924, 0xEDE6, 0x791E, 0xEDE7, 0x7934, 0xEDE8, 0x9F9B, 0xEDE9, 0x9EF9, 0xEDEA, 0x9EFB, 0xEDEB, 0x9EFC, 0xEDEC, 0x76F1, 0xEDED, 0x7704, 0xEDEE, 0x770D, 0xEDEF, 0x76F9, 0xEDF0, 0x7707, 0xEDF1, 0x7708, 0xEDF2, 0x771A, 0xEDF3, 0x7722, 0xEDF4, 0x7719, 0xEDF5, 0x772D, 0xEDF6, 0x7726, 0xEDF7, 0x7735, 0xEDF8, 0x7738, 0xEDF9, 0x7750, 0xEDFA, 0x7751, 0xEDFB, 0x7747, 0xEDFC, 0x7743, 0xEDFD, 0x775A, 0xEDFE, 0x7768, 0xEE40, 0x980F, 0xEE41, 0x9810, 0xEE42, 0x9811, 0xEE43, 0x9812, 0xEE44, 0x9813, 0xEE45, 0x9814, 0xEE46, 0x9815, 0xEE47, 0x9816, 0xEE48, 0x9817, 0xEE49, 0x9818, 0xEE4A, 0x9819, 0xEE4B, 0x981A, 0xEE4C, 0x981B, 0xEE4D, 0x981C, 0xEE4E, 0x981D, 0xEE4F, 0x981E, 0xEE50, 0x981F, 0xEE51, 0x9820, 0xEE52, 0x9821, 0xEE53, 0x9822, 0xEE54, 0x9823, 0xEE55, 0x9824, 0xEE56, 0x9825, 0xEE57, 0x9826, 0xEE58, 0x9827, 0xEE59, 0x9828, 0xEE5A, 0x9829, 0xEE5B, 0x982A, 0xEE5C, 0x982B, 0xEE5D, 0x982C, 0xEE5E, 0x982D, 0xEE5F, 0x982E, 0xEE60, 0x982F, 0xEE61, 0x9830, 0xEE62, 0x9831, 0xEE63, 0x9832, 0xEE64, 0x9833, 0xEE65, 0x9834, 0xEE66, 0x9835, 0xEE67, 0x9836, 0xEE68, 0x9837, 0xEE69, 0x9838, 0xEE6A, 0x9839, 0xEE6B, 0x983A, 0xEE6C, 0x983B, 0xEE6D, 0x983C, 0xEE6E, 0x983D, 0xEE6F, 0x983E, 0xEE70, 0x983F, 0xEE71, 0x9840, 0xEE72, 0x9841, 0xEE73, 0x9842, 0xEE74, 0x9843, 0xEE75, 0x9844, 0xEE76, 0x9845, 0xEE77, 0x9846, 0xEE78, 0x9847, 0xEE79, 0x9848, 0xEE7A, 0x9849, 0xEE7B, 0x984A, 0xEE7C, 0x984B, 0xEE7D, 0x984C, 0xEE7E, 0x984D, 0xEE80, 0x984E, 0xEE81, 0x984F, 0xEE82, 0x9850, 0xEE83, 0x9851, 0xEE84, 0x9852, 0xEE85, 0x9853, 0xEE86, 0x9854, 0xEE87, 0x9855, 0xEE88, 0x9856, 0xEE89, 0x9857, 0xEE8A, 0x9858, 0xEE8B, 0x9859, 0xEE8C, 0x985A, 0xEE8D, 0x985B, 0xEE8E, 0x985C, 0xEE8F, 0x985D, 0xEE90, 0x985E, 0xEE91, 0x985F, 0xEE92, 0x9860, 0xEE93, 0x9861, 0xEE94, 0x9862, 0xEE95, 0x9863, 0xEE96, 0x9864, 0xEE97, 0x9865, 0xEE98, 0x9866, 0xEE99, 0x9867, 0xEE9A, 0x9868, 0xEE9B, 0x9869, 0xEE9C, 0x986A, 0xEE9D, 0x986B, 0xEE9E, 0x986C, 0xEE9F, 0x986D, 0xEEA0, 0x986E, 0xEEA1, 0x7762, 0xEEA2, 0x7765, 0xEEA3, 0x777F, 0xEEA4, 0x778D, 0xEEA5, 0x777D, 0xEEA6, 0x7780, 0xEEA7, 0x778C, 0xEEA8, 0x7791, 0xEEA9, 0x779F, 0xEEAA, 0x77A0, 0xEEAB, 0x77B0, 0xEEAC, 0x77B5, 0xEEAD, 0x77BD, 0xEEAE, 0x753A, 0xEEAF, 0x7540, 0xEEB0, 0x754E, 0xEEB1, 0x754B, 0xEEB2, 0x7548, 0xEEB3, 0x755B, 0xEEB4, 0x7572, 0xEEB5, 0x7579, 0xEEB6, 0x7583, 0xEEB7, 0x7F58, 0xEEB8, 0x7F61, 0xEEB9, 0x7F5F, 0xEEBA, 0x8A48, 0xEEBB, 0x7F68, 0xEEBC, 0x7F74, 0xEEBD, 0x7F71, 0xEEBE, 0x7F79, 0xEEBF, 0x7F81, 0xEEC0, 0x7F7E, 0xEEC1, 0x76CD, 0xEEC2, 0x76E5, 0xEEC3, 0x8832, 0xEEC4, 0x9485, 0xEEC5, 0x9486, 0xEEC6, 0x9487, 0xEEC7, 0x948B, 0xEEC8, 0x948A, 0xEEC9, 0x948C, 0xEECA, 0x948D, 0xEECB, 0x948F, 0xEECC, 0x9490, 0xEECD, 0x9494, 0xEECE, 0x9497, 0xEECF, 0x9495, 0xEED0, 0x949A, 0xEED1, 0x949B, 0xEED2, 0x949C, 0xEED3, 0x94A3, 0xEED4, 0x94A4, 0xEED5, 0x94AB, 0xEED6, 0x94AA, 0xEED7, 0x94AD, 0xEED8, 0x94AC, 0xEED9, 0x94AF, 0xEEDA, 0x94B0, 0xEEDB, 0x94B2, 0xEEDC, 0x94B4, 0xEEDD, 0x94B6, 0xEEDE, 0x94B7, 0xEEDF, 0x94B8, 0xEEE0, 0x94B9, 0xEEE1, 0x94BA, 0xEEE2, 0x94BC, 0xEEE3, 0x94BD, 0xEEE4, 0x94BF, 0xEEE5, 0x94C4, 0xEEE6, 0x94C8, 0xEEE7, 0x94C9, 0xEEE8, 0x94CA, 0xEEE9, 0x94CB, 0xEEEA, 0x94CC, 0xEEEB, 0x94CD, 0xEEEC, 0x94CE, 0xEEED, 0x94D0, 0xEEEE, 0x94D1, 0xEEEF, 0x94D2, 0xEEF0, 0x94D5, 0xEEF1, 0x94D6, 0xEEF2, 0x94D7, 0xEEF3, 0x94D9, 0xEEF4, 0x94D8, 0xEEF5, 0x94DB, 0xEEF6, 0x94DE, 0xEEF7, 0x94DF, 0xEEF8, 0x94E0, 0xEEF9, 0x94E2, 0xEEFA, 0x94E4, 0xEEFB, 0x94E5, 0xEEFC, 0x94E7, 0xEEFD, 0x94E8, 0xEEFE, 0x94EA, 0xEF40, 0x986F, 0xEF41, 0x9870, 0xEF42, 0x9871, 0xEF43, 0x9872, 0xEF44, 0x9873, 0xEF45, 0x9874, 0xEF46, 0x988B, 0xEF47, 0x988E, 0xEF48, 0x9892, 0xEF49, 0x9895, 0xEF4A, 0x9899, 0xEF4B, 0x98A3, 0xEF4C, 0x98A8, 0xEF4D, 0x98A9, 0xEF4E, 0x98AA, 0xEF4F, 0x98AB, 0xEF50, 0x98AC, 0xEF51, 0x98AD, 0xEF52, 0x98AE, 0xEF53, 0x98AF, 0xEF54, 0x98B0, 0xEF55, 0x98B1, 0xEF56, 0x98B2, 0xEF57, 0x98B3, 0xEF58, 0x98B4, 0xEF59, 0x98B5, 0xEF5A, 0x98B6, 0xEF5B, 0x98B7, 0xEF5C, 0x98B8, 0xEF5D, 0x98B9, 0xEF5E, 0x98BA, 0xEF5F, 0x98BB, 0xEF60, 0x98BC, 0xEF61, 0x98BD, 0xEF62, 0x98BE, 0xEF63, 0x98BF, 0xEF64, 0x98C0, 0xEF65, 0x98C1, 0xEF66, 0x98C2, 0xEF67, 0x98C3, 0xEF68, 0x98C4, 0xEF69, 0x98C5, 0xEF6A, 0x98C6, 0xEF6B, 0x98C7, 0xEF6C, 0x98C8, 0xEF6D, 0x98C9, 0xEF6E, 0x98CA, 0xEF6F, 0x98CB, 0xEF70, 0x98CC, 0xEF71, 0x98CD, 0xEF72, 0x98CF, 0xEF73, 0x98D0, 0xEF74, 0x98D4, 0xEF75, 0x98D6, 0xEF76, 0x98D7, 0xEF77, 0x98DB, 0xEF78, 0x98DC, 0xEF79, 0x98DD, 0xEF7A, 0x98E0, 0xEF7B, 0x98E1, 0xEF7C, 0x98E2, 0xEF7D, 0x98E3, 0xEF7E, 0x98E4, 0xEF80, 0x98E5, 0xEF81, 0x98E6, 0xEF82, 0x98E9, 0xEF83, 0x98EA, 0xEF84, 0x98EB, 0xEF85, 0x98EC, 0xEF86, 0x98ED, 0xEF87, 0x98EE, 0xEF88, 0x98EF, 0xEF89, 0x98F0, 0xEF8A, 0x98F1, 0xEF8B, 0x98F2, 0xEF8C, 0x98F3, 0xEF8D, 0x98F4, 0xEF8E, 0x98F5, 0xEF8F, 0x98F6, 0xEF90, 0x98F7, 0xEF91, 0x98F8, 0xEF92, 0x98F9, 0xEF93, 0x98FA, 0xEF94, 0x98FB, 0xEF95, 0x98FC, 0xEF96, 0x98FD, 0xEF97, 0x98FE, 0xEF98, 0x98FF, 0xEF99, 0x9900, 0xEF9A, 0x9901, 0xEF9B, 0x9902, 0xEF9C, 0x9903, 0xEF9D, 0x9904, 0xEF9E, 0x9905, 0xEF9F, 0x9906, 0xEFA0, 0x9907, 0xEFA1, 0x94E9, 0xEFA2, 0x94EB, 0xEFA3, 0x94EE, 0xEFA4, 0x94EF, 0xEFA5, 0x94F3, 0xEFA6, 0x94F4, 0xEFA7, 0x94F5, 0xEFA8, 0x94F7, 0xEFA9, 0x94F9, 0xEFAA, 0x94FC, 0xEFAB, 0x94FD, 0xEFAC, 0x94FF, 0xEFAD, 0x9503, 0xEFAE, 0x9502, 0xEFAF, 0x9506, 0xEFB0, 0x9507, 0xEFB1, 0x9509, 0xEFB2, 0x950A, 0xEFB3, 0x950D, 0xEFB4, 0x950E, 0xEFB5, 0x950F, 0xEFB6, 0x9512, 0xEFB7, 0x9513, 0xEFB8, 0x9514, 0xEFB9, 0x9515, 0xEFBA, 0x9516, 0xEFBB, 0x9518, 0xEFBC, 0x951B, 0xEFBD, 0x951D, 0xEFBE, 0x951E, 0xEFBF, 0x951F, 0xEFC0, 0x9522, 0xEFC1, 0x952A, 0xEFC2, 0x952B, 0xEFC3, 0x9529, 0xEFC4, 0x952C, 0xEFC5, 0x9531, 0xEFC6, 0x9532, 0xEFC7, 0x9534, 0xEFC8, 0x9536, 0xEFC9, 0x9537, 0xEFCA, 0x9538, 0xEFCB, 0x953C, 0xEFCC, 0x953E, 0xEFCD, 0x953F, 0xEFCE, 0x9542, 0xEFCF, 0x9535, 0xEFD0, 0x9544, 0xEFD1, 0x9545, 0xEFD2, 0x9546, 0xEFD3, 0x9549, 0xEFD4, 0x954C, 0xEFD5, 0x954E, 0xEFD6, 0x954F, 0xEFD7, 0x9552, 0xEFD8, 0x9553, 0xEFD9, 0x9554, 0xEFDA, 0x9556, 0xEFDB, 0x9557, 0xEFDC, 0x9558, 0xEFDD, 0x9559, 0xEFDE, 0x955B, 0xEFDF, 0x955E, 0xEFE0, 0x955F, 0xEFE1, 0x955D, 0xEFE2, 0x9561, 0xEFE3, 0x9562, 0xEFE4, 0x9564, 0xEFE5, 0x9565, 0xEFE6, 0x9566, 0xEFE7, 0x9567, 0xEFE8, 0x9568, 0xEFE9, 0x9569, 0xEFEA, 0x956A, 0xEFEB, 0x956B, 0xEFEC, 0x956C, 0xEFED, 0x956F, 0xEFEE, 0x9571, 0xEFEF, 0x9572, 0xEFF0, 0x9573, 0xEFF1, 0x953A, 0xEFF2, 0x77E7, 0xEFF3, 0x77EC, 0xEFF4, 0x96C9, 0xEFF5, 0x79D5, 0xEFF6, 0x79ED, 0xEFF7, 0x79E3, 0xEFF8, 0x79EB, 0xEFF9, 0x7A06, 0xEFFA, 0x5D47, 0xEFFB, 0x7A03, 0xEFFC, 0x7A02, 0xEFFD, 0x7A1E, 0xEFFE, 0x7A14, 0xF040, 0x9908, 0xF041, 0x9909, 0xF042, 0x990A, 0xF043, 0x990B, 0xF044, 0x990C, 0xF045, 0x990E, 0xF046, 0x990F, 0xF047, 0x9911, 0xF048, 0x9912, 0xF049, 0x9913, 0xF04A, 0x9914, 0xF04B, 0x9915, 0xF04C, 0x9916, 0xF04D, 0x9917, 0xF04E, 0x9918, 0xF04F, 0x9919, 0xF050, 0x991A, 0xF051, 0x991B, 0xF052, 0x991C, 0xF053, 0x991D, 0xF054, 0x991E, 0xF055, 0x991F, 0xF056, 0x9920, 0xF057, 0x9921, 0xF058, 0x9922, 0xF059, 0x9923, 0xF05A, 0x9924, 0xF05B, 0x9925, 0xF05C, 0x9926, 0xF05D, 0x9927, 0xF05E, 0x9928, 0xF05F, 0x9929, 0xF060, 0x992A, 0xF061, 0x992B, 0xF062, 0x992C, 0xF063, 0x992D, 0xF064, 0x992F, 0xF065, 0x9930, 0xF066, 0x9931, 0xF067, 0x9932, 0xF068, 0x9933, 0xF069, 0x9934, 0xF06A, 0x9935, 0xF06B, 0x9936, 0xF06C, 0x9937, 0xF06D, 0x9938, 0xF06E, 0x9939, 0xF06F, 0x993A, 0xF070, 0x993B, 0xF071, 0x993C, 0xF072, 0x993D, 0xF073, 0x993E, 0xF074, 0x993F, 0xF075, 0x9940, 0xF076, 0x9941, 0xF077, 0x9942, 0xF078, 0x9943, 0xF079, 0x9944, 0xF07A, 0x9945, 0xF07B, 0x9946, 0xF07C, 0x9947, 0xF07D, 0x9948, 0xF07E, 0x9949, 0xF080, 0x994A, 0xF081, 0x994B, 0xF082, 0x994C, 0xF083, 0x994D, 0xF084, 0x994E, 0xF085, 0x994F, 0xF086, 0x9950, 0xF087, 0x9951, 0xF088, 0x9952, 0xF089, 0x9953, 0xF08A, 0x9956, 0xF08B, 0x9957, 0xF08C, 0x9958, 0xF08D, 0x9959, 0xF08E, 0x995A, 0xF08F, 0x995B, 0xF090, 0x995C, 0xF091, 0x995D, 0xF092, 0x995E, 0xF093, 0x995F, 0xF094, 0x9960, 0xF095, 0x9961, 0xF096, 0x9962, 0xF097, 0x9964, 0xF098, 0x9966, 0xF099, 0x9973, 0xF09A, 0x9978, 0xF09B, 0x9979, 0xF09C, 0x997B, 0xF09D, 0x997E, 0xF09E, 0x9982, 0xF09F, 0x9983, 0xF0A0, 0x9989, 0xF0A1, 0x7A39, 0xF0A2, 0x7A37, 0xF0A3, 0x7A51, 0xF0A4, 0x9ECF, 0xF0A5, 0x99A5, 0xF0A6, 0x7A70, 0xF0A7, 0x7688, 0xF0A8, 0x768E, 0xF0A9, 0x7693, 0xF0AA, 0x7699, 0xF0AB, 0x76A4, 0xF0AC, 0x74DE, 0xF0AD, 0x74E0, 0xF0AE, 0x752C, 0xF0AF, 0x9E20, 0xF0B0, 0x9E22, 0xF0B1, 0x9E28, 0xF0B2, 0x9E29, 0xF0B3, 0x9E2A, 0xF0B4, 0x9E2B, 0xF0B5, 0x9E2C, 0xF0B6, 0x9E32, 0xF0B7, 0x9E31, 0xF0B8, 0x9E36, 0xF0B9, 0x9E38, 0xF0BA, 0x9E37, 0xF0BB, 0x9E39, 0xF0BC, 0x9E3A, 0xF0BD, 0x9E3E, 0xF0BE, 0x9E41, 0xF0BF, 0x9E42, 0xF0C0, 0x9E44, 0xF0C1, 0x9E46, 0xF0C2, 0x9E47, 0xF0C3, 0x9E48, 0xF0C4, 0x9E49, 0xF0C5, 0x9E4B, 0xF0C6, 0x9E4C, 0xF0C7, 0x9E4E, 0xF0C8, 0x9E51, 0xF0C9, 0x9E55, 0xF0CA, 0x9E57, 0xF0CB, 0x9E5A, 0xF0CC, 0x9E5B, 0xF0CD, 0x9E5C, 0xF0CE, 0x9E5E, 0xF0CF, 0x9E63, 0xF0D0, 0x9E66, 0xF0D1, 0x9E67, 0xF0D2, 0x9E68, 0xF0D3, 0x9E69, 0xF0D4, 0x9E6A, 0xF0D5, 0x9E6B, 0xF0D6, 0x9E6C, 0xF0D7, 0x9E71, 0xF0D8, 0x9E6D, 0xF0D9, 0x9E73, 0xF0DA, 0x7592, 0xF0DB, 0x7594, 0xF0DC, 0x7596, 0xF0DD, 0x75A0, 0xF0DE, 0x759D, 0xF0DF, 0x75AC, 0xF0E0, 0x75A3, 0xF0E1, 0x75B3, 0xF0E2, 0x75B4, 0xF0E3, 0x75B8, 0xF0E4, 0x75C4, 0xF0E5, 0x75B1, 0xF0E6, 0x75B0, 0xF0E7, 0x75C3, 0xF0E8, 0x75C2, 0xF0E9, 0x75D6, 0xF0EA, 0x75CD, 0xF0EB, 0x75E3, 0xF0EC, 0x75E8, 0xF0ED, 0x75E6, 0xF0EE, 0x75E4, 0xF0EF, 0x75EB, 0xF0F0, 0x75E7, 0xF0F1, 0x7603, 0xF0F2, 0x75F1, 0xF0F3, 0x75FC, 0xF0F4, 0x75FF, 0xF0F5, 0x7610, 0xF0F6, 0x7600, 0xF0F7, 0x7605, 0xF0F8, 0x760C, 0xF0F9, 0x7617, 0xF0FA, 0x760A, 0xF0FB, 0x7625, 0xF0FC, 0x7618, 0xF0FD, 0x7615, 0xF0FE, 0x7619, 0xF140, 0x998C, 0xF141, 0x998E, 0xF142, 0x999A, 0xF143, 0x999B, 0xF144, 0x999C, 0xF145, 0x999D, 0xF146, 0x999E, 0xF147, 0x999F, 0xF148, 0x99A0, 0xF149, 0x99A1, 0xF14A, 0x99A2, 0xF14B, 0x99A3, 0xF14C, 0x99A4, 0xF14D, 0x99A6, 0xF14E, 0x99A7, 0xF14F, 0x99A9, 0xF150, 0x99AA, 0xF151, 0x99AB, 0xF152, 0x99AC, 0xF153, 0x99AD, 0xF154, 0x99AE, 0xF155, 0x99AF, 0xF156, 0x99B0, 0xF157, 0x99B1, 0xF158, 0x99B2, 0xF159, 0x99B3, 0xF15A, 0x99B4, 0xF15B, 0x99B5, 0xF15C, 0x99B6, 0xF15D, 0x99B7, 0xF15E, 0x99B8, 0xF15F, 0x99B9, 0xF160, 0x99BA, 0xF161, 0x99BB, 0xF162, 0x99BC, 0xF163, 0x99BD, 0xF164, 0x99BE, 0xF165, 0x99BF, 0xF166, 0x99C0, 0xF167, 0x99C1, 0xF168, 0x99C2, 0xF169, 0x99C3, 0xF16A, 0x99C4, 0xF16B, 0x99C5, 0xF16C, 0x99C6, 0xF16D, 0x99C7, 0xF16E, 0x99C8, 0xF16F, 0x99C9, 0xF170, 0x99CA, 0xF171, 0x99CB, 0xF172, 0x99CC, 0xF173, 0x99CD, 0xF174, 0x99CE, 0xF175, 0x99CF, 0xF176, 0x99D0, 0xF177, 0x99D1, 0xF178, 0x99D2, 0xF179, 0x99D3, 0xF17A, 0x99D4, 0xF17B, 0x99D5, 0xF17C, 0x99D6, 0xF17D, 0x99D7, 0xF17E, 0x99D8, 0xF180, 0x99D9, 0xF181, 0x99DA, 0xF182, 0x99DB, 0xF183, 0x99DC, 0xF184, 0x99DD, 0xF185, 0x99DE, 0xF186, 0x99DF, 0xF187, 0x99E0, 0xF188, 0x99E1, 0xF189, 0x99E2, 0xF18A, 0x99E3, 0xF18B, 0x99E4, 0xF18C, 0x99E5, 0xF18D, 0x99E6, 0xF18E, 0x99E7, 0xF18F, 0x99E8, 0xF190, 0x99E9, 0xF191, 0x99EA, 0xF192, 0x99EB, 0xF193, 0x99EC, 0xF194, 0x99ED, 0xF195, 0x99EE, 0xF196, 0x99EF, 0xF197, 0x99F0, 0xF198, 0x99F1, 0xF199, 0x99F2, 0xF19A, 0x99F3, 0xF19B, 0x99F4, 0xF19C, 0x99F5, 0xF19D, 0x99F6, 0xF19E, 0x99F7, 0xF19F, 0x99F8, 0xF1A0, 0x99F9, 0xF1A1, 0x761B, 0xF1A2, 0x763C, 0xF1A3, 0x7622, 0xF1A4, 0x7620, 0xF1A5, 0x7640, 0xF1A6, 0x762D, 0xF1A7, 0x7630, 0xF1A8, 0x763F, 0xF1A9, 0x7635, 0xF1AA, 0x7643, 0xF1AB, 0x763E, 0xF1AC, 0x7633, 0xF1AD, 0x764D, 0xF1AE, 0x765E, 0xF1AF, 0x7654, 0xF1B0, 0x765C, 0xF1B1, 0x7656, 0xF1B2, 0x766B, 0xF1B3, 0x766F, 0xF1B4, 0x7FCA, 0xF1B5, 0x7AE6, 0xF1B6, 0x7A78, 0xF1B7, 0x7A79, 0xF1B8, 0x7A80, 0xF1B9, 0x7A86, 0xF1BA, 0x7A88, 0xF1BB, 0x7A95, 0xF1BC, 0x7AA6, 0xF1BD, 0x7AA0, 0xF1BE, 0x7AAC, 0xF1BF, 0x7AA8, 0xF1C0, 0x7AAD, 0xF1C1, 0x7AB3, 0xF1C2, 0x8864, 0xF1C3, 0x8869, 0xF1C4, 0x8872, 0xF1C5, 0x887D, 0xF1C6, 0x887F, 0xF1C7, 0x8882, 0xF1C8, 0x88A2, 0xF1C9, 0x88C6, 0xF1CA, 0x88B7, 0xF1CB, 0x88BC, 0xF1CC, 0x88C9, 0xF1CD, 0x88E2, 0xF1CE, 0x88CE, 0xF1CF, 0x88E3, 0xF1D0, 0x88E5, 0xF1D1, 0x88F1, 0xF1D2, 0x891A, 0xF1D3, 0x88FC, 0xF1D4, 0x88E8, 0xF1D5, 0x88FE, 0xF1D6, 0x88F0, 0xF1D7, 0x8921, 0xF1D8, 0x8919, 0xF1D9, 0x8913, 0xF1DA, 0x891B, 0xF1DB, 0x890A, 0xF1DC, 0x8934, 0xF1DD, 0x892B, 0xF1DE, 0x8936, 0xF1DF, 0x8941, 0xF1E0, 0x8966, 0xF1E1, 0x897B, 0xF1E2, 0x758B, 0xF1E3, 0x80E5, 0xF1E4, 0x76B2, 0xF1E5, 0x76B4, 0xF1E6, 0x77DC, 0xF1E7, 0x8012, 0xF1E8, 0x8014, 0xF1E9, 0x8016, 0xF1EA, 0x801C, 0xF1EB, 0x8020, 0xF1EC, 0x8022, 0xF1ED, 0x8025, 0xF1EE, 0x8026, 0xF1EF, 0x8027, 0xF1F0, 0x8029, 0xF1F1, 0x8028, 0xF1F2, 0x8031, 0xF1F3, 0x800B, 0xF1F4, 0x8035, 0xF1F5, 0x8043, 0xF1F6, 0x8046, 0xF1F7, 0x804D, 0xF1F8, 0x8052, 0xF1F9, 0x8069, 0xF1FA, 0x8071, 0xF1FB, 0x8983, 0xF1FC, 0x9878, 0xF1FD, 0x9880, 0xF1FE, 0x9883, 0xF240, 0x99FA, 0xF241, 0x99FB, 0xF242, 0x99FC, 0xF243, 0x99FD, 0xF244, 0x99FE, 0xF245, 0x99FF, 0xF246, 0x9A00, 0xF247, 0x9A01, 0xF248, 0x9A02, 0xF249, 0x9A03, 0xF24A, 0x9A04, 0xF24B, 0x9A05, 0xF24C, 0x9A06, 0xF24D, 0x9A07, 0xF24E, 0x9A08, 0xF24F, 0x9A09, 0xF250, 0x9A0A, 0xF251, 0x9A0B, 0xF252, 0x9A0C, 0xF253, 0x9A0D, 0xF254, 0x9A0E, 0xF255, 0x9A0F, 0xF256, 0x9A10, 0xF257, 0x9A11, 0xF258, 0x9A12, 0xF259, 0x9A13, 0xF25A, 0x9A14, 0xF25B, 0x9A15, 0xF25C, 0x9A16, 0xF25D, 0x9A17, 0xF25E, 0x9A18, 0xF25F, 0x9A19, 0xF260, 0x9A1A, 0xF261, 0x9A1B, 0xF262, 0x9A1C, 0xF263, 0x9A1D, 0xF264, 0x9A1E, 0xF265, 0x9A1F, 0xF266, 0x9A20, 0xF267, 0x9A21, 0xF268, 0x9A22, 0xF269, 0x9A23, 0xF26A, 0x9A24, 0xF26B, 0x9A25, 0xF26C, 0x9A26, 0xF26D, 0x9A27, 0xF26E, 0x9A28, 0xF26F, 0x9A29, 0xF270, 0x9A2A, 0xF271, 0x9A2B, 0xF272, 0x9A2C, 0xF273, 0x9A2D, 0xF274, 0x9A2E, 0xF275, 0x9A2F, 0xF276, 0x9A30, 0xF277, 0x9A31, 0xF278, 0x9A32, 0xF279, 0x9A33, 0xF27A, 0x9A34, 0xF27B, 0x9A35, 0xF27C, 0x9A36, 0xF27D, 0x9A37, 0xF27E, 0x9A38, 0xF280, 0x9A39, 0xF281, 0x9A3A, 0xF282, 0x9A3B, 0xF283, 0x9A3C, 0xF284, 0x9A3D, 0xF285, 0x9A3E, 0xF286, 0x9A3F, 0xF287, 0x9A40, 0xF288, 0x9A41, 0xF289, 0x9A42, 0xF28A, 0x9A43, 0xF28B, 0x9A44, 0xF28C, 0x9A45, 0xF28D, 0x9A46, 0xF28E, 0x9A47, 0xF28F, 0x9A48, 0xF290, 0x9A49, 0xF291, 0x9A4A, 0xF292, 0x9A4B, 0xF293, 0x9A4C, 0xF294, 0x9A4D, 0xF295, 0x9A4E, 0xF296, 0x9A4F, 0xF297, 0x9A50, 0xF298, 0x9A51, 0xF299, 0x9A52, 0xF29A, 0x9A53, 0xF29B, 0x9A54, 0xF29C, 0x9A55, 0xF29D, 0x9A56, 0xF29E, 0x9A57, 0xF29F, 0x9A58, 0xF2A0, 0x9A59, 0xF2A1, 0x9889, 0xF2A2, 0x988C, 0xF2A3, 0x988D, 0xF2A4, 0x988F, 0xF2A5, 0x9894, 0xF2A6, 0x989A, 0xF2A7, 0x989B, 0xF2A8, 0x989E, 0xF2A9, 0x989F, 0xF2AA, 0x98A1, 0xF2AB, 0x98A2, 0xF2AC, 0x98A5, 0xF2AD, 0x98A6, 0xF2AE, 0x864D, 0xF2AF, 0x8654, 0xF2B0, 0x866C, 0xF2B1, 0x866E, 0xF2B2, 0x867F, 0xF2B3, 0x867A, 0xF2B4, 0x867C, 0xF2B5, 0x867B, 0xF2B6, 0x86A8, 0xF2B7, 0x868D, 0xF2B8, 0x868B, 0xF2B9, 0x86AC, 0xF2BA, 0x869D, 0xF2BB, 0x86A7, 0xF2BC, 0x86A3, 0xF2BD, 0x86AA, 0xF2BE, 0x8693, 0xF2BF, 0x86A9, 0xF2C0, 0x86B6, 0xF2C1, 0x86C4, 0xF2C2, 0x86B5, 0xF2C3, 0x86CE, 0xF2C4, 0x86B0, 0xF2C5, 0x86BA, 0xF2C6, 0x86B1, 0xF2C7, 0x86AF, 0xF2C8, 0x86C9, 0xF2C9, 0x86CF, 0xF2CA, 0x86B4, 0xF2CB, 0x86E9, 0xF2CC, 0x86F1, 0xF2CD, 0x86F2, 0xF2CE, 0x86ED, 0xF2CF, 0x86F3, 0xF2D0, 0x86D0, 0xF2D1, 0x8713, 0xF2D2, 0x86DE, 0xF2D3, 0x86F4, 0xF2D4, 0x86DF, 0xF2D5, 0x86D8, 0xF2D6, 0x86D1, 0xF2D7, 0x8703, 0xF2D8, 0x8707, 0xF2D9, 0x86F8, 0xF2DA, 0x8708, 0xF2DB, 0x870A, 0xF2DC, 0x870D, 0xF2DD, 0x8709, 0xF2DE, 0x8723, 0xF2DF, 0x873B, 0xF2E0, 0x871E, 0xF2E1, 0x8725, 0xF2E2, 0x872E, 0xF2E3, 0x871A, 0xF2E4, 0x873E, 0xF2E5, 0x8748, 0xF2E6, 0x8734, 0xF2E7, 0x8731, 0xF2E8, 0x8729, 0xF2E9, 0x8737, 0xF2EA, 0x873F, 0xF2EB, 0x8782, 0xF2EC, 0x8722, 0xF2ED, 0x877D, 0xF2EE, 0x877E, 0xF2EF, 0x877B, 0xF2F0, 0x8760, 0xF2F1, 0x8770, 0xF2F2, 0x874C, 0xF2F3, 0x876E, 0xF2F4, 0x878B, 0xF2F5, 0x8753, 0xF2F6, 0x8763, 0xF2F7, 0x877C, 0xF2F8, 0x8764, 0xF2F9, 0x8759, 0xF2FA, 0x8765, 0xF2FB, 0x8793, 0xF2FC, 0x87AF, 0xF2FD, 0x87A8, 0xF2FE, 0x87D2, 0xF340, 0x9A5A, 0xF341, 0x9A5B, 0xF342, 0x9A5C, 0xF343, 0x9A5D, 0xF344, 0x9A5E, 0xF345, 0x9A5F, 0xF346, 0x9A60, 0xF347, 0x9A61, 0xF348, 0x9A62, 0xF349, 0x9A63, 0xF34A, 0x9A64, 0xF34B, 0x9A65, 0xF34C, 0x9A66, 0xF34D, 0x9A67, 0xF34E, 0x9A68, 0xF34F, 0x9A69, 0xF350, 0x9A6A, 0xF351, 0x9A6B, 0xF352, 0x9A72, 0xF353, 0x9A83, 0xF354, 0x9A89, 0xF355, 0x9A8D, 0xF356, 0x9A8E, 0xF357, 0x9A94, 0xF358, 0x9A95, 0xF359, 0x9A99, 0xF35A, 0x9AA6, 0xF35B, 0x9AA9, 0xF35C, 0x9AAA, 0xF35D, 0x9AAB, 0xF35E, 0x9AAC, 0xF35F, 0x9AAD, 0xF360, 0x9AAE, 0xF361, 0x9AAF, 0xF362, 0x9AB2, 0xF363, 0x9AB3, 0xF364, 0x9AB4, 0xF365, 0x9AB5, 0xF366, 0x9AB9, 0xF367, 0x9ABB, 0xF368, 0x9ABD, 0xF369, 0x9ABE, 0xF36A, 0x9ABF, 0xF36B, 0x9AC3, 0xF36C, 0x9AC4, 0xF36D, 0x9AC6, 0xF36E, 0x9AC7, 0xF36F, 0x9AC8, 0xF370, 0x9AC9, 0xF371, 0x9ACA, 0xF372, 0x9ACD, 0xF373, 0x9ACE, 0xF374, 0x9ACF, 0xF375, 0x9AD0, 0xF376, 0x9AD2, 0xF377, 0x9AD4, 0xF378, 0x9AD5, 0xF379, 0x9AD6, 0xF37A, 0x9AD7, 0xF37B, 0x9AD9, 0xF37C, 0x9ADA, 0xF37D, 0x9ADB, 0xF37E, 0x9ADC, 0xF380, 0x9ADD, 0xF381, 0x9ADE, 0xF382, 0x9AE0, 0xF383, 0x9AE2, 0xF384, 0x9AE3, 0xF385, 0x9AE4, 0xF386, 0x9AE5, 0xF387, 0x9AE7, 0xF388, 0x9AE8, 0xF389, 0x9AE9, 0xF38A, 0x9AEA, 0xF38B, 0x9AEC, 0xF38C, 0x9AEE, 0xF38D, 0x9AF0, 0xF38E, 0x9AF1, 0xF38F, 0x9AF2, 0xF390, 0x9AF3, 0xF391, 0x9AF4, 0xF392, 0x9AF5, 0xF393, 0x9AF6, 0xF394, 0x9AF7, 0xF395, 0x9AF8, 0xF396, 0x9AFA, 0xF397, 0x9AFC, 0xF398, 0x9AFD, 0xF399, 0x9AFE, 0xF39A, 0x9AFF, 0xF39B, 0x9B00, 0xF39C, 0x9B01, 0xF39D, 0x9B02, 0xF39E, 0x9B04, 0xF39F, 0x9B05, 0xF3A0, 0x9B06, 0xF3A1, 0x87C6, 0xF3A2, 0x8788, 0xF3A3, 0x8785, 0xF3A4, 0x87AD, 0xF3A5, 0x8797, 0xF3A6, 0x8783, 0xF3A7, 0x87AB, 0xF3A8, 0x87E5, 0xF3A9, 0x87AC, 0xF3AA, 0x87B5, 0xF3AB, 0x87B3, 0xF3AC, 0x87CB, 0xF3AD, 0x87D3, 0xF3AE, 0x87BD, 0xF3AF, 0x87D1, 0xF3B0, 0x87C0, 0xF3B1, 0x87CA, 0xF3B2, 0x87DB, 0xF3B3, 0x87EA, 0xF3B4, 0x87E0, 0xF3B5, 0x87EE, 0xF3B6, 0x8816, 0xF3B7, 0x8813, 0xF3B8, 0x87FE, 0xF3B9, 0x880A, 0xF3BA, 0x881B, 0xF3BB, 0x8821, 0xF3BC, 0x8839, 0xF3BD, 0x883C, 0xF3BE, 0x7F36, 0xF3BF, 0x7F42, 0xF3C0, 0x7F44, 0xF3C1, 0x7F45, 0xF3C2, 0x8210, 0xF3C3, 0x7AFA, 0xF3C4, 0x7AFD, 0xF3C5, 0x7B08, 0xF3C6, 0x7B03, 0xF3C7, 0x7B04, 0xF3C8, 0x7B15, 0xF3C9, 0x7B0A, 0xF3CA, 0x7B2B, 0xF3CB, 0x7B0F, 0xF3CC, 0x7B47, 0xF3CD, 0x7B38, 0xF3CE, 0x7B2A, 0xF3CF, 0x7B19, 0xF3D0, 0x7B2E, 0xF3D1, 0x7B31, 0xF3D2, 0x7B20, 0xF3D3, 0x7B25, 0xF3D4, 0x7B24, 0xF3D5, 0x7B33, 0xF3D6, 0x7B3E, 0xF3D7, 0x7B1E, 0xF3D8, 0x7B58, 0xF3D9, 0x7B5A, 0xF3DA, 0x7B45, 0xF3DB, 0x7B75, 0xF3DC, 0x7B4C, 0xF3DD, 0x7B5D, 0xF3DE, 0x7B60, 0xF3DF, 0x7B6E, 0xF3E0, 0x7B7B, 0xF3E1, 0x7B62, 0xF3E2, 0x7B72, 0xF3E3, 0x7B71, 0xF3E4, 0x7B90, 0xF3E5, 0x7BA6, 0xF3E6, 0x7BA7, 0xF3E7, 0x7BB8, 0xF3E8, 0x7BAC, 0xF3E9, 0x7B9D, 0xF3EA, 0x7BA8, 0xF3EB, 0x7B85, 0xF3EC, 0x7BAA, 0xF3ED, 0x7B9C, 0xF3EE, 0x7BA2, 0xF3EF, 0x7BAB, 0xF3F0, 0x7BB4, 0xF3F1, 0x7BD1, 0xF3F2, 0x7BC1, 0xF3F3, 0x7BCC, 0xF3F4, 0x7BDD, 0xF3F5, 0x7BDA, 0xF3F6, 0x7BE5, 0xF3F7, 0x7BE6, 0xF3F8, 0x7BEA, 0xF3F9, 0x7C0C, 0xF3FA, 0x7BFE, 0xF3FB, 0x7BFC, 0xF3FC, 0x7C0F, 0xF3FD, 0x7C16, 0xF3FE, 0x7C0B, 0xF440, 0x9B07, 0xF441, 0x9B09, 0xF442, 0x9B0A, 0xF443, 0x9B0B, 0xF444, 0x9B0C, 0xF445, 0x9B0D, 0xF446, 0x9B0E, 0xF447, 0x9B10, 0xF448, 0x9B11, 0xF449, 0x9B12, 0xF44A, 0x9B14, 0xF44B, 0x9B15, 0xF44C, 0x9B16, 0xF44D, 0x9B17, 0xF44E, 0x9B18, 0xF44F, 0x9B19, 0xF450, 0x9B1A, 0xF451, 0x9B1B, 0xF452, 0x9B1C, 0xF453, 0x9B1D, 0xF454, 0x9B1E, 0xF455, 0x9B20, 0xF456, 0x9B21, 0xF457, 0x9B22, 0xF458, 0x9B24, 0xF459, 0x9B25, 0xF45A, 0x9B26, 0xF45B, 0x9B27, 0xF45C, 0x9B28, 0xF45D, 0x9B29, 0xF45E, 0x9B2A, 0xF45F, 0x9B2B, 0xF460, 0x9B2C, 0xF461, 0x9B2D, 0xF462, 0x9B2E, 0xF463, 0x9B30, 0xF464, 0x9B31, 0xF465, 0x9B33, 0xF466, 0x9B34, 0xF467, 0x9B35, 0xF468, 0x9B36, 0xF469, 0x9B37, 0xF46A, 0x9B38, 0xF46B, 0x9B39, 0xF46C, 0x9B3A, 0xF46D, 0x9B3D, 0xF46E, 0x9B3E, 0xF46F, 0x9B3F, 0xF470, 0x9B40, 0xF471, 0x9B46, 0xF472, 0x9B4A, 0xF473, 0x9B4B, 0xF474, 0x9B4C, 0xF475, 0x9B4E, 0xF476, 0x9B50, 0xF477, 0x9B52, 0xF478, 0x9B53, 0xF479, 0x9B55, 0xF47A, 0x9B56, 0xF47B, 0x9B57, 0xF47C, 0x9B58, 0xF47D, 0x9B59, 0xF47E, 0x9B5A, 0xF480, 0x9B5B, 0xF481, 0x9B5C, 0xF482, 0x9B5D, 0xF483, 0x9B5E, 0xF484, 0x9B5F, 0xF485, 0x9B60, 0xF486, 0x9B61, 0xF487, 0x9B62, 0xF488, 0x9B63, 0xF489, 0x9B64, 0xF48A, 0x9B65, 0xF48B, 0x9B66, 0xF48C, 0x9B67, 0xF48D, 0x9B68, 0xF48E, 0x9B69, 0xF48F, 0x9B6A, 0xF490, 0x9B6B, 0xF491, 0x9B6C, 0xF492, 0x9B6D, 0xF493, 0x9B6E, 0xF494, 0x9B6F, 0xF495, 0x9B70, 0xF496, 0x9B71, 0xF497, 0x9B72, 0xF498, 0x9B73, 0xF499, 0x9B74, 0xF49A, 0x9B75, 0xF49B, 0x9B76, 0xF49C, 0x9B77, 0xF49D, 0x9B78, 0xF49E, 0x9B79, 0xF49F, 0x9B7A, 0xF4A0, 0x9B7B, 0xF4A1, 0x7C1F, 0xF4A2, 0x7C2A, 0xF4A3, 0x7C26, 0xF4A4, 0x7C38, 0xF4A5, 0x7C41, 0xF4A6, 0x7C40, 0xF4A7, 0x81FE, 0xF4A8, 0x8201, 0xF4A9, 0x8202, 0xF4AA, 0x8204, 0xF4AB, 0x81EC, 0xF4AC, 0x8844, 0xF4AD, 0x8221, 0xF4AE, 0x8222, 0xF4AF, 0x8223, 0xF4B0, 0x822D, 0xF4B1, 0x822F, 0xF4B2, 0x8228, 0xF4B3, 0x822B, 0xF4B4, 0x8238, 0xF4B5, 0x823B, 0xF4B6, 0x8233, 0xF4B7, 0x8234, 0xF4B8, 0x823E, 0xF4B9, 0x8244, 0xF4BA, 0x8249, 0xF4BB, 0x824B, 0xF4BC, 0x824F, 0xF4BD, 0x825A, 0xF4BE, 0x825F, 0xF4BF, 0x8268, 0xF4C0, 0x887E, 0xF4C1, 0x8885, 0xF4C2, 0x8888, 0xF4C3, 0x88D8, 0xF4C4, 0x88DF, 0xF4C5, 0x895E, 0xF4C6, 0x7F9D, 0xF4C7, 0x7F9F, 0xF4C8, 0x7FA7, 0xF4C9, 0x7FAF, 0xF4CA, 0x7FB0, 0xF4CB, 0x7FB2, 0xF4CC, 0x7C7C, 0xF4CD, 0x6549, 0xF4CE, 0x7C91, 0xF4CF, 0x7C9D, 0xF4D0, 0x7C9C, 0xF4D1, 0x7C9E, 0xF4D2, 0x7CA2, 0xF4D3, 0x7CB2, 0xF4D4, 0x7CBC, 0xF4D5, 0x7CBD, 0xF4D6, 0x7CC1, 0xF4D7, 0x7CC7, 0xF4D8, 0x7CCC, 0xF4D9, 0x7CCD, 0xF4DA, 0x7CC8, 0xF4DB, 0x7CC5, 0xF4DC, 0x7CD7, 0xF4DD, 0x7CE8, 0xF4DE, 0x826E, 0xF4DF, 0x66A8, 0xF4E0, 0x7FBF, 0xF4E1, 0x7FCE, 0xF4E2, 0x7FD5, 0xF4E3, 0x7FE5, 0xF4E4, 0x7FE1, 0xF4E5, 0x7FE6, 0xF4E6, 0x7FE9, 0xF4E7, 0x7FEE, 0xF4E8, 0x7FF3, 0xF4E9, 0x7CF8, 0xF4EA, 0x7D77, 0xF4EB, 0x7DA6, 0xF4EC, 0x7DAE, 0xF4ED, 0x7E47, 0xF4EE, 0x7E9B, 0xF4EF, 0x9EB8, 0xF4F0, 0x9EB4, 0xF4F1, 0x8D73, 0xF4F2, 0x8D84, 0xF4F3, 0x8D94, 0xF4F4, 0x8D91, 0xF4F5, 0x8DB1, 0xF4F6, 0x8D67, 0xF4F7, 0x8D6D, 0xF4F8, 0x8C47, 0xF4F9, 0x8C49, 0xF4FA, 0x914A, 0xF4FB, 0x9150, 0xF4FC, 0x914E, 0xF4FD, 0x914F, 0xF4FE, 0x9164, 0xF540, 0x9B7C, 0xF541, 0x9B7D, 0xF542, 0x9B7E, 0xF543, 0x9B7F, 0xF544, 0x9B80, 0xF545, 0x9B81, 0xF546, 0x9B82, 0xF547, 0x9B83, 0xF548, 0x9B84, 0xF549, 0x9B85, 0xF54A, 0x9B86, 0xF54B, 0x9B87, 0xF54C, 0x9B88, 0xF54D, 0x9B89, 0xF54E, 0x9B8A, 0xF54F, 0x9B8B, 0xF550, 0x9B8C, 0xF551, 0x9B8D, 0xF552, 0x9B8E, 0xF553, 0x9B8F, 0xF554, 0x9B90, 0xF555, 0x9B91, 0xF556, 0x9B92, 0xF557, 0x9B93, 0xF558, 0x9B94, 0xF559, 0x9B95, 0xF55A, 0x9B96, 0xF55B, 0x9B97, 0xF55C, 0x9B98, 0xF55D, 0x9B99, 0xF55E, 0x9B9A, 0xF55F, 0x9B9B, 0xF560, 0x9B9C, 0xF561, 0x9B9D, 0xF562, 0x9B9E, 0xF563, 0x9B9F, 0xF564, 0x9BA0, 0xF565, 0x9BA1, 0xF566, 0x9BA2, 0xF567, 0x9BA3, 0xF568, 0x9BA4, 0xF569, 0x9BA5, 0xF56A, 0x9BA6, 0xF56B, 0x9BA7, 0xF56C, 0x9BA8, 0xF56D, 0x9BA9, 0xF56E, 0x9BAA, 0xF56F, 0x9BAB, 0xF570, 0x9BAC, 0xF571, 0x9BAD, 0xF572, 0x9BAE, 0xF573, 0x9BAF, 0xF574, 0x9BB0, 0xF575, 0x9BB1, 0xF576, 0x9BB2, 0xF577, 0x9BB3, 0xF578, 0x9BB4, 0xF579, 0x9BB5, 0xF57A, 0x9BB6, 0xF57B, 0x9BB7, 0xF57C, 0x9BB8, 0xF57D, 0x9BB9, 0xF57E, 0x9BBA, 0xF580, 0x9BBB, 0xF581, 0x9BBC, 0xF582, 0x9BBD, 0xF583, 0x9BBE, 0xF584, 0x9BBF, 0xF585, 0x9BC0, 0xF586, 0x9BC1, 0xF587, 0x9BC2, 0xF588, 0x9BC3, 0xF589, 0x9BC4, 0xF58A, 0x9BC5, 0xF58B, 0x9BC6, 0xF58C, 0x9BC7, 0xF58D, 0x9BC8, 0xF58E, 0x9BC9, 0xF58F, 0x9BCA, 0xF590, 0x9BCB, 0xF591, 0x9BCC, 0xF592, 0x9BCD, 0xF593, 0x9BCE, 0xF594, 0x9BCF, 0xF595, 0x9BD0, 0xF596, 0x9BD1, 0xF597, 0x9BD2, 0xF598, 0x9BD3, 0xF599, 0x9BD4, 0xF59A, 0x9BD5, 0xF59B, 0x9BD6, 0xF59C, 0x9BD7, 0xF59D, 0x9BD8, 0xF59E, 0x9BD9, 0xF59F, 0x9BDA, 0xF5A0, 0x9BDB, 0xF5A1, 0x9162, 0xF5A2, 0x9161, 0xF5A3, 0x9170, 0xF5A4, 0x9169, 0xF5A5, 0x916F, 0xF5A6, 0x917D, 0xF5A7, 0x917E, 0xF5A8, 0x9172, 0xF5A9, 0x9174, 0xF5AA, 0x9179, 0xF5AB, 0x918C, 0xF5AC, 0x9185, 0xF5AD, 0x9190, 0xF5AE, 0x918D, 0xF5AF, 0x9191, 0xF5B0, 0x91A2, 0xF5B1, 0x91A3, 0xF5B2, 0x91AA, 0xF5B3, 0x91AD, 0xF5B4, 0x91AE, 0xF5B5, 0x91AF, 0xF5B6, 0x91B5, 0xF5B7, 0x91B4, 0xF5B8, 0x91BA, 0xF5B9, 0x8C55, 0xF5BA, 0x9E7E, 0xF5BB, 0x8DB8, 0xF5BC, 0x8DEB, 0xF5BD, 0x8E05, 0xF5BE, 0x8E59, 0xF5BF, 0x8E69, 0xF5C0, 0x8DB5, 0xF5C1, 0x8DBF, 0xF5C2, 0x8DBC, 0xF5C3, 0x8DBA, 0xF5C4, 0x8DC4, 0xF5C5, 0x8DD6, 0xF5C6, 0x8DD7, 0xF5C7, 0x8DDA, 0xF5C8, 0x8DDE, 0xF5C9, 0x8DCE, 0xF5CA, 0x8DCF, 0xF5CB, 0x8DDB, 0xF5CC, 0x8DC6, 0xF5CD, 0x8DEC, 0xF5CE, 0x8DF7, 0xF5CF, 0x8DF8, 0xF5D0, 0x8DE3, 0xF5D1, 0x8DF9, 0xF5D2, 0x8DFB, 0xF5D3, 0x8DE4, 0xF5D4, 0x8E09, 0xF5D5, 0x8DFD, 0xF5D6, 0x8E14, 0xF5D7, 0x8E1D, 0xF5D8, 0x8E1F, 0xF5D9, 0x8E2C, 0xF5DA, 0x8E2E, 0xF5DB, 0x8E23, 0xF5DC, 0x8E2F, 0xF5DD, 0x8E3A, 0xF5DE, 0x8E40, 0xF5DF, 0x8E39, 0xF5E0, 0x8E35, 0xF5E1, 0x8E3D, 0xF5E2, 0x8E31, 0xF5E3, 0x8E49, 0xF5E4, 0x8E41, 0xF5E5, 0x8E42, 0xF5E6, 0x8E51, 0xF5E7, 0x8E52, 0xF5E8, 0x8E4A, 0xF5E9, 0x8E70, 0xF5EA, 0x8E76, 0xF5EB, 0x8E7C, 0xF5EC, 0x8E6F, 0xF5ED, 0x8E74, 0xF5EE, 0x8E85, 0xF5EF, 0x8E8F, 0xF5F0, 0x8E94, 0xF5F1, 0x8E90, 0xF5F2, 0x8E9C, 0xF5F3, 0x8E9E, 0xF5F4, 0x8C78, 0xF5F5, 0x8C82, 0xF5F6, 0x8C8A, 0xF5F7, 0x8C85, 0xF5F8, 0x8C98, 0xF5F9, 0x8C94, 0xF5FA, 0x659B, 0xF5FB, 0x89D6, 0xF5FC, 0x89DE, 0xF5FD, 0x89DA, 0xF5FE, 0x89DC, 0xF640, 0x9BDC, 0xF641, 0x9BDD, 0xF642, 0x9BDE, 0xF643, 0x9BDF, 0xF644, 0x9BE0, 0xF645, 0x9BE1, 0xF646, 0x9BE2, 0xF647, 0x9BE3, 0xF648, 0x9BE4, 0xF649, 0x9BE5, 0xF64A, 0x9BE6, 0xF64B, 0x9BE7, 0xF64C, 0x9BE8, 0xF64D, 0x9BE9, 0xF64E, 0x9BEA, 0xF64F, 0x9BEB, 0xF650, 0x9BEC, 0xF651, 0x9BED, 0xF652, 0x9BEE, 0xF653, 0x9BEF, 0xF654, 0x9BF0, 0xF655, 0x9BF1, 0xF656, 0x9BF2, 0xF657, 0x9BF3, 0xF658, 0x9BF4, 0xF659, 0x9BF5, 0xF65A, 0x9BF6, 0xF65B, 0x9BF7, 0xF65C, 0x9BF8, 0xF65D, 0x9BF9, 0xF65E, 0x9BFA, 0xF65F, 0x9BFB, 0xF660, 0x9BFC, 0xF661, 0x9BFD, 0xF662, 0x9BFE, 0xF663, 0x9BFF, 0xF664, 0x9C00, 0xF665, 0x9C01, 0xF666, 0x9C02, 0xF667, 0x9C03, 0xF668, 0x9C04, 0xF669, 0x9C05, 0xF66A, 0x9C06, 0xF66B, 0x9C07, 0xF66C, 0x9C08, 0xF66D, 0x9C09, 0xF66E, 0x9C0A, 0xF66F, 0x9C0B, 0xF670, 0x9C0C, 0xF671, 0x9C0D, 0xF672, 0x9C0E, 0xF673, 0x9C0F, 0xF674, 0x9C10, 0xF675, 0x9C11, 0xF676, 0x9C12, 0xF677, 0x9C13, 0xF678, 0x9C14, 0xF679, 0x9C15, 0xF67A, 0x9C16, 0xF67B, 0x9C17, 0xF67C, 0x9C18, 0xF67D, 0x9C19, 0xF67E, 0x9C1A, 0xF680, 0x9C1B, 0xF681, 0x9C1C, 0xF682, 0x9C1D, 0xF683, 0x9C1E, 0xF684, 0x9C1F, 0xF685, 0x9C20, 0xF686, 0x9C21, 0xF687, 0x9C22, 0xF688, 0x9C23, 0xF689, 0x9C24, 0xF68A, 0x9C25, 0xF68B, 0x9C26, 0xF68C, 0x9C27, 0xF68D, 0x9C28, 0xF68E, 0x9C29, 0xF68F, 0x9C2A, 0xF690, 0x9C2B, 0xF691, 0x9C2C, 0xF692, 0x9C2D, 0xF693, 0x9C2E, 0xF694, 0x9C2F, 0xF695, 0x9C30, 0xF696, 0x9C31, 0xF697, 0x9C32, 0xF698, 0x9C33, 0xF699, 0x9C34, 0xF69A, 0x9C35, 0xF69B, 0x9C36, 0xF69C, 0x9C37, 0xF69D, 0x9C38, 0xF69E, 0x9C39, 0xF69F, 0x9C3A, 0xF6A0, 0x9C3B, 0xF6A1, 0x89E5, 0xF6A2, 0x89EB, 0xF6A3, 0x89EF, 0xF6A4, 0x8A3E, 0xF6A5, 0x8B26, 0xF6A6, 0x9753, 0xF6A7, 0x96E9, 0xF6A8, 0x96F3, 0xF6A9, 0x96EF, 0xF6AA, 0x9706, 0xF6AB, 0x9701, 0xF6AC, 0x9708, 0xF6AD, 0x970F, 0xF6AE, 0x970E, 0xF6AF, 0x972A, 0xF6B0, 0x972D, 0xF6B1, 0x9730, 0xF6B2, 0x973E, 0xF6B3, 0x9F80, 0xF6B4, 0x9F83, 0xF6B5, 0x9F85, 0xF6B6, 0x9F86, 0xF6B7, 0x9F87, 0xF6B8, 0x9F88, 0xF6B9, 0x9F89, 0xF6BA, 0x9F8A, 0xF6BB, 0x9F8C, 0xF6BC, 0x9EFE, 0xF6BD, 0x9F0B, 0xF6BE, 0x9F0D, 0xF6BF, 0x96B9, 0xF6C0, 0x96BC, 0xF6C1, 0x96BD, 0xF6C2, 0x96CE, 0xF6C3, 0x96D2, 0xF6C4, 0x77BF, 0xF6C5, 0x96E0, 0xF6C6, 0x928E, 0xF6C7, 0x92AE, 0xF6C8, 0x92C8, 0xF6C9, 0x933E, 0xF6CA, 0x936A, 0xF6CB, 0x93CA, 0xF6CC, 0x938F, 0xF6CD, 0x943E, 0xF6CE, 0x946B, 0xF6CF, 0x9C7F, 0xF6D0, 0x9C82, 0xF6D1, 0x9C85, 0xF6D2, 0x9C86, 0xF6D3, 0x9C87, 0xF6D4, 0x9C88, 0xF6D5, 0x7A23, 0xF6D6, 0x9C8B, 0xF6D7, 0x9C8E, 0xF6D8, 0x9C90, 0xF6D9, 0x9C91, 0xF6DA, 0x9C92, 0xF6DB, 0x9C94, 0xF6DC, 0x9C95, 0xF6DD, 0x9C9A, 0xF6DE, 0x9C9B, 0xF6DF, 0x9C9E, 0xF6E0, 0x9C9F, 0xF6E1, 0x9CA0, 0xF6E2, 0x9CA1, 0xF6E3, 0x9CA2, 0xF6E4, 0x9CA3, 0xF6E5, 0x9CA5, 0xF6E6, 0x9CA6, 0xF6E7, 0x9CA7, 0xF6E8, 0x9CA8, 0xF6E9, 0x9CA9, 0xF6EA, 0x9CAB, 0xF6EB, 0x9CAD, 0xF6EC, 0x9CAE, 0xF6ED, 0x9CB0, 0xF6EE, 0x9CB1, 0xF6EF, 0x9CB2, 0xF6F0, 0x9CB3, 0xF6F1, 0x9CB4, 0xF6F2, 0x9CB5, 0xF6F3, 0x9CB6, 0xF6F4, 0x9CB7, 0xF6F5, 0x9CBA, 0xF6F6, 0x9CBB, 0xF6F7, 0x9CBC, 0xF6F8, 0x9CBD, 0xF6F9, 0x9CC4, 0xF6FA, 0x9CC5, 0xF6FB, 0x9CC6, 0xF6FC, 0x9CC7, 0xF6FD, 0x9CCA, 0xF6FE, 0x9CCB, 0xF740, 0x9C3C, 0xF741, 0x9C3D, 0xF742, 0x9C3E, 0xF743, 0x9C3F, 0xF744, 0x9C40, 0xF745, 0x9C41, 0xF746, 0x9C42, 0xF747, 0x9C43, 0xF748, 0x9C44, 0xF749, 0x9C45, 0xF74A, 0x9C46, 0xF74B, 0x9C47, 0xF74C, 0x9C48, 0xF74D, 0x9C49, 0xF74E, 0x9C4A, 0xF74F, 0x9C4B, 0xF750, 0x9C4C, 0xF751, 0x9C4D, 0xF752, 0x9C4E, 0xF753, 0x9C4F, 0xF754, 0x9C50, 0xF755, 0x9C51, 0xF756, 0x9C52, 0xF757, 0x9C53, 0xF758, 0x9C54, 0xF759, 0x9C55, 0xF75A, 0x9C56, 0xF75B, 0x9C57, 0xF75C, 0x9C58, 0xF75D, 0x9C59, 0xF75E, 0x9C5A, 0xF75F, 0x9C5B, 0xF760, 0x9C5C, 0xF761, 0x9C5D, 0xF762, 0x9C5E, 0xF763, 0x9C5F, 0xF764, 0x9C60, 0xF765, 0x9C61, 0xF766, 0x9C62, 0xF767, 0x9C63, 0xF768, 0x9C64, 0xF769, 0x9C65, 0xF76A, 0x9C66, 0xF76B, 0x9C67, 0xF76C, 0x9C68, 0xF76D, 0x9C69, 0xF76E, 0x9C6A, 0xF76F, 0x9C6B, 0xF770, 0x9C6C, 0xF771, 0x9C6D, 0xF772, 0x9C6E, 0xF773, 0x9C6F, 0xF774, 0x9C70, 0xF775, 0x9C71, 0xF776, 0x9C72, 0xF777, 0x9C73, 0xF778, 0x9C74, 0xF779, 0x9C75, 0xF77A, 0x9C76, 0xF77B, 0x9C77, 0xF77C, 0x9C78, 0xF77D, 0x9C79, 0xF77E, 0x9C7A, 0xF780, 0x9C7B, 0xF781, 0x9C7D, 0xF782, 0x9C7E, 0xF783, 0x9C80, 0xF784, 0x9C83, 0xF785, 0x9C84, 0xF786, 0x9C89, 0xF787, 0x9C8A, 0xF788, 0x9C8C, 0xF789, 0x9C8F, 0xF78A, 0x9C93, 0xF78B, 0x9C96, 0xF78C, 0x9C97, 0xF78D, 0x9C98, 0xF78E, 0x9C99, 0xF78F, 0x9C9D, 0xF790, 0x9CAA, 0xF791, 0x9CAC, 0xF792, 0x9CAF, 0xF793, 0x9CB9, 0xF794, 0x9CBE, 0xF795, 0x9CBF, 0xF796, 0x9CC0, 0xF797, 0x9CC1, 0xF798, 0x9CC2, 0xF799, 0x9CC8, 0xF79A, 0x9CC9, 0xF79B, 0x9CD1, 0xF79C, 0x9CD2, 0xF79D, 0x9CDA, 0xF79E, 0x9CDB, 0xF79F, 0x9CE0, 0xF7A0, 0x9CE1, 0xF7A1, 0x9CCC, 0xF7A2, 0x9CCD, 0xF7A3, 0x9CCE, 0xF7A4, 0x9CCF, 0xF7A5, 0x9CD0, 0xF7A6, 0x9CD3, 0xF7A7, 0x9CD4, 0xF7A8, 0x9CD5, 0xF7A9, 0x9CD7, 0xF7AA, 0x9CD8, 0xF7AB, 0x9CD9, 0xF7AC, 0x9CDC, 0xF7AD, 0x9CDD, 0xF7AE, 0x9CDF, 0xF7AF, 0x9CE2, 0xF7B0, 0x977C, 0xF7B1, 0x9785, 0xF7B2, 0x9791, 0xF7B3, 0x9792, 0xF7B4, 0x9794, 0xF7B5, 0x97AF, 0xF7B6, 0x97AB, 0xF7B7, 0x97A3, 0xF7B8, 0x97B2, 0xF7B9, 0x97B4, 0xF7BA, 0x9AB1, 0xF7BB, 0x9AB0, 0xF7BC, 0x9AB7, 0xF7BD, 0x9E58, 0xF7BE, 0x9AB6, 0xF7BF, 0x9ABA, 0xF7C0, 0x9ABC, 0xF7C1, 0x9AC1, 0xF7C2, 0x9AC0, 0xF7C3, 0x9AC5, 0xF7C4, 0x9AC2, 0xF7C5, 0x9ACB, 0xF7C6, 0x9ACC, 0xF7C7, 0x9AD1, 0xF7C8, 0x9B45, 0xF7C9, 0x9B43, 0xF7CA, 0x9B47, 0xF7CB, 0x9B49, 0xF7CC, 0x9B48, 0xF7CD, 0x9B4D, 0xF7CE, 0x9B51, 0xF7CF, 0x98E8, 0xF7D0, 0x990D, 0xF7D1, 0x992E, 0xF7D2, 0x9955, 0xF7D3, 0x9954, 0xF7D4, 0x9ADF, 0xF7D5, 0x9AE1, 0xF7D6, 0x9AE6, 0xF7D7, 0x9AEF, 0xF7D8, 0x9AEB, 0xF7D9, 0x9AFB, 0xF7DA, 0x9AED, 0xF7DB, 0x9AF9, 0xF7DC, 0x9B08, 0xF7DD, 0x9B0F, 0xF7DE, 0x9B13, 0xF7DF, 0x9B1F, 0xF7E0, 0x9B23, 0xF7E1, 0x9EBD, 0xF7E2, 0x9EBE, 0xF7E3, 0x7E3B, 0xF7E4, 0x9E82, 0xF7E5, 0x9E87, 0xF7E6, 0x9E88, 0xF7E7, 0x9E8B, 0xF7E8, 0x9E92, 0xF7E9, 0x93D6, 0xF7EA, 0x9E9D, 0xF7EB, 0x9E9F, 0xF7EC, 0x9EDB, 0xF7ED, 0x9EDC, 0xF7EE, 0x9EDD, 0xF7EF, 0x9EE0, 0xF7F0, 0x9EDF, 0xF7F1, 0x9EE2, 0xF7F2, 0x9EE9, 0xF7F3, 0x9EE7, 0xF7F4, 0x9EE5, 0xF7F5, 0x9EEA, 0xF7F6, 0x9EEF, 0xF7F7, 0x9F22, 0xF7F8, 0x9F2C, 0xF7F9, 0x9F2F, 0xF7FA, 0x9F39, 0xF7FB, 0x9F37, 0xF7FC, 0x9F3D, 0xF7FD, 0x9F3E, 0xF7FE, 0x9F44, 0xF840, 0x9CE3, 0xF841, 0x9CE4, 0xF842, 0x9CE5, 0xF843, 0x9CE6, 0xF844, 0x9CE7, 0xF845, 0x9CE8, 0xF846, 0x9CE9, 0xF847, 0x9CEA, 0xF848, 0x9CEB, 0xF849, 0x9CEC, 0xF84A, 0x9CED, 0xF84B, 0x9CEE, 0xF84C, 0x9CEF, 0xF84D, 0x9CF0, 0xF84E, 0x9CF1, 0xF84F, 0x9CF2, 0xF850, 0x9CF3, 0xF851, 0x9CF4, 0xF852, 0x9CF5, 0xF853, 0x9CF6, 0xF854, 0x9CF7, 0xF855, 0x9CF8, 0xF856, 0x9CF9, 0xF857, 0x9CFA, 0xF858, 0x9CFB, 0xF859, 0x9CFC, 0xF85A, 0x9CFD, 0xF85B, 0x9CFE, 0xF85C, 0x9CFF, 0xF85D, 0x9D00, 0xF85E, 0x9D01, 0xF85F, 0x9D02, 0xF860, 0x9D03, 0xF861, 0x9D04, 0xF862, 0x9D05, 0xF863, 0x9D06, 0xF864, 0x9D07, 0xF865, 0x9D08, 0xF866, 0x9D09, 0xF867, 0x9D0A, 0xF868, 0x9D0B, 0xF869, 0x9D0C, 0xF86A, 0x9D0D, 0xF86B, 0x9D0E, 0xF86C, 0x9D0F, 0xF86D, 0x9D10, 0xF86E, 0x9D11, 0xF86F, 0x9D12, 0xF870, 0x9D13, 0xF871, 0x9D14, 0xF872, 0x9D15, 0xF873, 0x9D16, 0xF874, 0x9D17, 0xF875, 0x9D18, 0xF876, 0x9D19, 0xF877, 0x9D1A, 0xF878, 0x9D1B, 0xF879, 0x9D1C, 0xF87A, 0x9D1D, 0xF87B, 0x9D1E, 0xF87C, 0x9D1F, 0xF87D, 0x9D20, 0xF87E, 0x9D21, 0xF880, 0x9D22, 0xF881, 0x9D23, 0xF882, 0x9D24, 0xF883, 0x9D25, 0xF884, 0x9D26, 0xF885, 0x9D27, 0xF886, 0x9D28, 0xF887, 0x9D29, 0xF888, 0x9D2A, 0xF889, 0x9D2B, 0xF88A, 0x9D2C, 0xF88B, 0x9D2D, 0xF88C, 0x9D2E, 0xF88D, 0x9D2F, 0xF88E, 0x9D30, 0xF88F, 0x9D31, 0xF890, 0x9D32, 0xF891, 0x9D33, 0xF892, 0x9D34, 0xF893, 0x9D35, 0xF894, 0x9D36, 0xF895, 0x9D37, 0xF896, 0x9D38, 0xF897, 0x9D39, 0xF898, 0x9D3A, 0xF899, 0x9D3B, 0xF89A, 0x9D3C, 0xF89B, 0x9D3D, 0xF89C, 0x9D3E, 0xF89D, 0x9D3F, 0xF89E, 0x9D40, 0xF89F, 0x9D41, 0xF8A0, 0x9D42, 0xF940, 0x9D43, 0xF941, 0x9D44, 0xF942, 0x9D45, 0xF943, 0x9D46, 0xF944, 0x9D47, 0xF945, 0x9D48, 0xF946, 0x9D49, 0xF947, 0x9D4A, 0xF948, 0x9D4B, 0xF949, 0x9D4C, 0xF94A, 0x9D4D, 0xF94B, 0x9D4E, 0xF94C, 0x9D4F, 0xF94D, 0x9D50, 0xF94E, 0x9D51, 0xF94F, 0x9D52, 0xF950, 0x9D53, 0xF951, 0x9D54, 0xF952, 0x9D55, 0xF953, 0x9D56, 0xF954, 0x9D57, 0xF955, 0x9D58, 0xF956, 0x9D59, 0xF957, 0x9D5A, 0xF958, 0x9D5B, 0xF959, 0x9D5C, 0xF95A, 0x9D5D, 0xF95B, 0x9D5E, 0xF95C, 0x9D5F, 0xF95D, 0x9D60, 0xF95E, 0x9D61, 0xF95F, 0x9D62, 0xF960, 0x9D63, 0xF961, 0x9D64, 0xF962, 0x9D65, 0xF963, 0x9D66, 0xF964, 0x9D67, 0xF965, 0x9D68, 0xF966, 0x9D69, 0xF967, 0x9D6A, 0xF968, 0x9D6B, 0xF969, 0x9D6C, 0xF96A, 0x9D6D, 0xF96B, 0x9D6E, 0xF96C, 0x9D6F, 0xF96D, 0x9D70, 0xF96E, 0x9D71, 0xF96F, 0x9D72, 0xF970, 0x9D73, 0xF971, 0x9D74, 0xF972, 0x9D75, 0xF973, 0x9D76, 0xF974, 0x9D77, 0xF975, 0x9D78, 0xF976, 0x9D79, 0xF977, 0x9D7A, 0xF978, 0x9D7B, 0xF979, 0x9D7C, 0xF97A, 0x9D7D, 0xF97B, 0x9D7E, 0xF97C, 0x9D7F, 0xF97D, 0x9D80, 0xF97E, 0x9D81, 0xF980, 0x9D82, 0xF981, 0x9D83, 0xF982, 0x9D84, 0xF983, 0x9D85, 0xF984, 0x9D86, 0xF985, 0x9D87, 0xF986, 0x9D88, 0xF987, 0x9D89, 0xF988, 0x9D8A, 0xF989, 0x9D8B, 0xF98A, 0x9D8C, 0xF98B, 0x9D8D, 0xF98C, 0x9D8E, 0xF98D, 0x9D8F, 0xF98E, 0x9D90, 0xF98F, 0x9D91, 0xF990, 0x9D92, 0xF991, 0x9D93, 0xF992, 0x9D94, 0xF993, 0x9D95, 0xF994, 0x9D96, 0xF995, 0x9D97, 0xF996, 0x9D98, 0xF997, 0x9D99, 0xF998, 0x9D9A, 0xF999, 0x9D9B, 0xF99A, 0x9D9C, 0xF99B, 0x9D9D, 0xF99C, 0x9D9E, 0xF99D, 0x9D9F, 0xF99E, 0x9DA0, 0xF99F, 0x9DA1, 0xF9A0, 0x9DA2, 0xFA40, 0x9DA3, 0xFA41, 0x9DA4, 0xFA42, 0x9DA5, 0xFA43, 0x9DA6, 0xFA44, 0x9DA7, 0xFA45, 0x9DA8, 0xFA46, 0x9DA9, 0xFA47, 0x9DAA, 0xFA48, 0x9DAB, 0xFA49, 0x9DAC, 0xFA4A, 0x9DAD, 0xFA4B, 0x9DAE, 0xFA4C, 0x9DAF, 0xFA4D, 0x9DB0, 0xFA4E, 0x9DB1, 0xFA4F, 0x9DB2, 0xFA50, 0x9DB3, 0xFA51, 0x9DB4, 0xFA52, 0x9DB5, 0xFA53, 0x9DB6, 0xFA54, 0x9DB7, 0xFA55, 0x9DB8, 0xFA56, 0x9DB9, 0xFA57, 0x9DBA, 0xFA58, 0x9DBB, 0xFA59, 0x9DBC, 0xFA5A, 0x9DBD, 0xFA5B, 0x9DBE, 0xFA5C, 0x9DBF, 0xFA5D, 0x9DC0, 0xFA5E, 0x9DC1, 0xFA5F, 0x9DC2, 0xFA60, 0x9DC3, 0xFA61, 0x9DC4, 0xFA62, 0x9DC5, 0xFA63, 0x9DC6, 0xFA64, 0x9DC7, 0xFA65, 0x9DC8, 0xFA66, 0x9DC9, 0xFA67, 0x9DCA, 0xFA68, 0x9DCB, 0xFA69, 0x9DCC, 0xFA6A, 0x9DCD, 0xFA6B, 0x9DCE, 0xFA6C, 0x9DCF, 0xFA6D, 0x9DD0, 0xFA6E, 0x9DD1, 0xFA6F, 0x9DD2, 0xFA70, 0x9DD3, 0xFA71, 0x9DD4, 0xFA72, 0x9DD5, 0xFA73, 0x9DD6, 0xFA74, 0x9DD7, 0xFA75, 0x9DD8, 0xFA76, 0x9DD9, 0xFA77, 0x9DDA, 0xFA78, 0x9DDB, 0xFA79, 0x9DDC, 0xFA7A, 0x9DDD, 0xFA7B, 0x9DDE, 0xFA7C, 0x9DDF, 0xFA7D, 0x9DE0, 0xFA7E, 0x9DE1, 0xFA80, 0x9DE2, 0xFA81, 0x9DE3, 0xFA82, 0x9DE4, 0xFA83, 0x9DE5, 0xFA84, 0x9DE6, 0xFA85, 0x9DE7, 0xFA86, 0x9DE8, 0xFA87, 0x9DE9, 0xFA88, 0x9DEA, 0xFA89, 0x9DEB, 0xFA8A, 0x9DEC, 0xFA8B, 0x9DED, 0xFA8C, 0x9DEE, 0xFA8D, 0x9DEF, 0xFA8E, 0x9DF0, 0xFA8F, 0x9DF1, 0xFA90, 0x9DF2, 0xFA91, 0x9DF3, 0xFA92, 0x9DF4, 0xFA93, 0x9DF5, 0xFA94, 0x9DF6, 0xFA95, 0x9DF7, 0xFA96, 0x9DF8, 0xFA97, 0x9DF9, 0xFA98, 0x9DFA, 0xFA99, 0x9DFB, 0xFA9A, 0x9DFC, 0xFA9B, 0x9DFD, 0xFA9C, 0x9DFE, 0xFA9D, 0x9DFF, 0xFA9E, 0x9E00, 0xFA9F, 0x9E01, 0xFAA0, 0x9E02, 0xFB40, 0x9E03, 0xFB41, 0x9E04, 0xFB42, 0x9E05, 0xFB43, 0x9E06, 0xFB44, 0x9E07, 0xFB45, 0x9E08, 0xFB46, 0x9E09, 0xFB47, 0x9E0A, 0xFB48, 0x9E0B, 0xFB49, 0x9E0C, 0xFB4A, 0x9E0D, 0xFB4B, 0x9E0E, 0xFB4C, 0x9E0F, 0xFB4D, 0x9E10, 0xFB4E, 0x9E11, 0xFB4F, 0x9E12, 0xFB50, 0x9E13, 0xFB51, 0x9E14, 0xFB52, 0x9E15, 0xFB53, 0x9E16, 0xFB54, 0x9E17, 0xFB55, 0x9E18, 0xFB56, 0x9E19, 0xFB57, 0x9E1A, 0xFB58, 0x9E1B, 0xFB59, 0x9E1C, 0xFB5A, 0x9E1D, 0xFB5B, 0x9E1E, 0xFB5C, 0x9E24, 0xFB5D, 0x9E27, 0xFB5E, 0x9E2E, 0xFB5F, 0x9E30, 0xFB60, 0x9E34, 0xFB61, 0x9E3B, 0xFB62, 0x9E3C, 0xFB63, 0x9E40, 0xFB64, 0x9E4D, 0xFB65, 0x9E50, 0xFB66, 0x9E52, 0xFB67, 0x9E53, 0xFB68, 0x9E54, 0xFB69, 0x9E56, 0xFB6A, 0x9E59, 0xFB6B, 0x9E5D, 0xFB6C, 0x9E5F, 0xFB6D, 0x9E60, 0xFB6E, 0x9E61, 0xFB6F, 0x9E62, 0xFB70, 0x9E65, 0xFB71, 0x9E6E, 0xFB72, 0x9E6F, 0xFB73, 0x9E72, 0xFB74, 0x9E74, 0xFB75, 0x9E75, 0xFB76, 0x9E76, 0xFB77, 0x9E77, 0xFB78, 0x9E78, 0xFB79, 0x9E79, 0xFB7A, 0x9E7A, 0xFB7B, 0x9E7B, 0xFB7C, 0x9E7C, 0xFB7D, 0x9E7D, 0xFB7E, 0x9E80, 0xFB80, 0x9E81, 0xFB81, 0x9E83, 0xFB82, 0x9E84, 0xFB83, 0x9E85, 0xFB84, 0x9E86, 0xFB85, 0x9E89, 0xFB86, 0x9E8A, 0xFB87, 0x9E8C, 0xFB88, 0x9E8D, 0xFB89, 0x9E8E, 0xFB8A, 0x9E8F, 0xFB8B, 0x9E90, 0xFB8C, 0x9E91, 0xFB8D, 0x9E94, 0xFB8E, 0x9E95, 0xFB8F, 0x9E96, 0xFB90, 0x9E97, 0xFB91, 0x9E98, 0xFB92, 0x9E99, 0xFB93, 0x9E9A, 0xFB94, 0x9E9B, 0xFB95, 0x9E9C, 0xFB96, 0x9E9E, 0xFB97, 0x9EA0, 0xFB98, 0x9EA1, 0xFB99, 0x9EA2, 0xFB9A, 0x9EA3, 0xFB9B, 0x9EA4, 0xFB9C, 0x9EA5, 0xFB9D, 0x9EA7, 0xFB9E, 0x9EA8, 0xFB9F, 0x9EA9, 0xFBA0, 0x9EAA, 0xFC40, 0x9EAB, 0xFC41, 0x9EAC, 0xFC42, 0x9EAD, 0xFC43, 0x9EAE, 0xFC44, 0x9EAF, 0xFC45, 0x9EB0, 0xFC46, 0x9EB1, 0xFC47, 0x9EB2, 0xFC48, 0x9EB3, 0xFC49, 0x9EB5, 0xFC4A, 0x9EB6, 0xFC4B, 0x9EB7, 0xFC4C, 0x9EB9, 0xFC4D, 0x9EBA, 0xFC4E, 0x9EBC, 0xFC4F, 0x9EBF, 0xFC50, 0x9EC0, 0xFC51, 0x9EC1, 0xFC52, 0x9EC2, 0xFC53, 0x9EC3, 0xFC54, 0x9EC5, 0xFC55, 0x9EC6, 0xFC56, 0x9EC7, 0xFC57, 0x9EC8, 0xFC58, 0x9ECA, 0xFC59, 0x9ECB, 0xFC5A, 0x9ECC, 0xFC5B, 0x9ED0, 0xFC5C, 0x9ED2, 0xFC5D, 0x9ED3, 0xFC5E, 0x9ED5, 0xFC5F, 0x9ED6, 0xFC60, 0x9ED7, 0xFC61, 0x9ED9, 0xFC62, 0x9EDA, 0xFC63, 0x9EDE, 0xFC64, 0x9EE1, 0xFC65, 0x9EE3, 0xFC66, 0x9EE4, 0xFC67, 0x9EE6, 0xFC68, 0x9EE8, 0xFC69, 0x9EEB, 0xFC6A, 0x9EEC, 0xFC6B, 0x9EED, 0xFC6C, 0x9EEE, 0xFC6D, 0x9EF0, 0xFC6E, 0x9EF1, 0xFC6F, 0x9EF2, 0xFC70, 0x9EF3, 0xFC71, 0x9EF4, 0xFC72, 0x9EF5, 0xFC73, 0x9EF6, 0xFC74, 0x9EF7, 0xFC75, 0x9EF8, 0xFC76, 0x9EFA, 0xFC77, 0x9EFD, 0xFC78, 0x9EFF, 0xFC79, 0x9F00, 0xFC7A, 0x9F01, 0xFC7B, 0x9F02, 0xFC7C, 0x9F03, 0xFC7D, 0x9F04, 0xFC7E, 0x9F05, 0xFC80, 0x9F06, 0xFC81, 0x9F07, 0xFC82, 0x9F08, 0xFC83, 0x9F09, 0xFC84, 0x9F0A, 0xFC85, 0x9F0C, 0xFC86, 0x9F0F, 0xFC87, 0x9F11, 0xFC88, 0x9F12, 0xFC89, 0x9F14, 0xFC8A, 0x9F15, 0xFC8B, 0x9F16, 0xFC8C, 0x9F18, 0xFC8D, 0x9F1A, 0xFC8E, 0x9F1B, 0xFC8F, 0x9F1C, 0xFC90, 0x9F1D, 0xFC91, 0x9F1E, 0xFC92, 0x9F1F, 0xFC93, 0x9F21, 0xFC94, 0x9F23, 0xFC95, 0x9F24, 0xFC96, 0x9F25, 0xFC97, 0x9F26, 0xFC98, 0x9F27, 0xFC99, 0x9F28, 0xFC9A, 0x9F29, 0xFC9B, 0x9F2A, 0xFC9C, 0x9F2B, 0xFC9D, 0x9F2D, 0xFC9E, 0x9F2E, 0xFC9F, 0x9F30, 0xFCA0, 0x9F31, 0xFD40, 0x9F32, 0xFD41, 0x9F33, 0xFD42, 0x9F34, 0xFD43, 0x9F35, 0xFD44, 0x9F36, 0xFD45, 0x9F38, 0xFD46, 0x9F3A, 0xFD47, 0x9F3C, 0xFD48, 0x9F3F, 0xFD49, 0x9F40, 0xFD4A, 0x9F41, 0xFD4B, 0x9F42, 0xFD4C, 0x9F43, 0xFD4D, 0x9F45, 0xFD4E, 0x9F46, 0xFD4F, 0x9F47, 0xFD50, 0x9F48, 0xFD51, 0x9F49, 0xFD52, 0x9F4A, 0xFD53, 0x9F4B, 0xFD54, 0x9F4C, 0xFD55, 0x9F4D, 0xFD56, 0x9F4E, 0xFD57, 0x9F4F, 0xFD58, 0x9F52, 0xFD59, 0x9F53, 0xFD5A, 0x9F54, 0xFD5B, 0x9F55, 0xFD5C, 0x9F56, 0xFD5D, 0x9F57, 0xFD5E, 0x9F58, 0xFD5F, 0x9F59, 0xFD60, 0x9F5A, 0xFD61, 0x9F5B, 0xFD62, 0x9F5C, 0xFD63, 0x9F5D, 0xFD64, 0x9F5E, 0xFD65, 0x9F5F, 0xFD66, 0x9F60, 0xFD67, 0x9F61, 0xFD68, 0x9F62, 0xFD69, 0x9F63, 0xFD6A, 0x9F64, 0xFD6B, 0x9F65, 0xFD6C, 0x9F66, 0xFD6D, 0x9F67, 0xFD6E, 0x9F68, 0xFD6F, 0x9F69, 0xFD70, 0x9F6A, 0xFD71, 0x9F6B, 0xFD72, 0x9F6C, 0xFD73, 0x9F6D, 0xFD74, 0x9F6E, 0xFD75, 0x9F6F, 0xFD76, 0x9F70, 0xFD77, 0x9F71, 0xFD78, 0x9F72, 0xFD79, 0x9F73, 0xFD7A, 0x9F74, 0xFD7B, 0x9F75, 0xFD7C, 0x9F76, 0xFD7D, 0x9F77, 0xFD7E, 0x9F78, 0xFD80, 0x9F79, 0xFD81, 0x9F7A, 0xFD82, 0x9F7B, 0xFD83, 0x9F7C, 0xFD84, 0x9F7D, 0xFD85, 0x9F7E, 0xFD86, 0x9F81, 0xFD87, 0x9F82, 0xFD88, 0x9F8D, 0xFD89, 0x9F8E, 0xFD8A, 0x9F8F, 0xFD8B, 0x9F90, 0xFD8C, 0x9F91, 0xFD8D, 0x9F92, 0xFD8E, 0x9F93, 0xFD8F, 0x9F94, 0xFD90, 0x9F95, 0xFD91, 0x9F96, 0xFD92, 0x9F97, 0xFD93, 0x9F98, 0xFD94, 0x9F9C, 0xFD95, 0x9F9D, 0xFD96, 0x9F9E, 0xFD97, 0x9FA1, 0xFD98, 0x9FA2, 0xFD99, 0x9FA3, 0xFD9A, 0x9FA4, 0xFD9B, 0x9FA5, 0xFD9C, 0xF92C, 0xFD9D, 0xF979, 0xFD9E, 0xF995, 0xFD9F, 0xF9E7, 0xFDA0, 0xF9F1, 0xFE40, 0xFA0C, 0xFE41, 0xFA0D, 0xFE42, 0xFA0E, 0xFE43, 0xFA0F, 0xFE44, 0xFA11, 0xFE45, 0xFA13, 0xFE46, 0xFA14, 0xFE47, 0xFA18, 0xFE48, 0xFA1F, 0xFE49, 0xFA20, 0xFE4A, 0xFA21, 0xFE4B, 0xFA23, 0xFE4C, 0xFA24, 0xFE4D, 0xFA27, 0xFE4E, 0xFA28, 0xFE4F, 0xFA29, 0, 0 }; #endif #if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */ static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ 0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6, 0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6, 0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF, 0x00D8, 0xA8AA, 0x00DE, 0xA8AD, 0x00DF, 0xA9AC, 0x00E6, 0xA9A1, 0x00F0, 0xA9A3, 0x00F7, 0xA1C0, 0x00F8, 0xA9AA, 0x00FE, 0xA9AD, 0x0111, 0xA9A2, 0x0126, 0xA8A4, 0x0127, 0xA9A4, 0x0131, 0xA9A5, 0x0132, 0xA8A6, 0x0133, 0xA9A6, 0x0138, 0xA9A7, 0x013F, 0xA8A8, 0x0140, 0xA9A8, 0x0141, 0xA8A9, 0x0142, 0xA9A9, 0x0149, 0xA9B0, 0x014A, 0xA8AF, 0x014B, 0xA9AF, 0x0152, 0xA8AB, 0x0153, 0xA9AB, 0x0166, 0xA8AE, 0x0167, 0xA9AE, 0x02C7, 0xA2A7, 0x02D0, 0xA2B0, 0x02D8, 0xA2A8, 0x02D9, 0xA2AB, 0x02DA, 0xA2AA, 0x02DB, 0xA2AD, 0x02DD, 0xA2A9, 0x0391, 0xA5C1, 0x0392, 0xA5C2, 0x0393, 0xA5C3, 0x0394, 0xA5C4, 0x0395, 0xA5C5, 0x0396, 0xA5C6, 0x0397, 0xA5C7, 0x0398, 0xA5C8, 0x0399, 0xA5C9, 0x039A, 0xA5CA, 0x039B, 0xA5CB, 0x039C, 0xA5CC, 0x039D, 0xA5CD, 0x039E, 0xA5CE, 0x039F, 0xA5CF, 0x03A0, 0xA5D0, 0x03A1, 0xA5D1, 0x03A3, 0xA5D2, 0x03A4, 0xA5D3, 0x03A5, 0xA5D4, 0x03A6, 0xA5D5, 0x03A7, 0xA5D6, 0x03A8, 0xA5D7, 0x03A9, 0xA5D8, 0x03B1, 0xA5E1, 0x03B2, 0xA5E2, 0x03B3, 0xA5E3, 0x03B4, 0xA5E4, 0x03B5, 0xA5E5, 0x03B6, 0xA5E6, 0x03B7, 0xA5E7, 0x03B8, 0xA5E8, 0x03B9, 0xA5E9, 0x03BA, 0xA5EA, 0x03BB, 0xA5EB, 0x03BC, 0xA5EC, 0x03BD, 0xA5ED, 0x03BE, 0xA5EE, 0x03BF, 0xA5EF, 0x03C0, 0xA5F0, 0x03C1, 0xA5F1, 0x03C3, 0xA5F2, 0x03C4, 0xA5F3, 0x03C5, 0xA5F4, 0x03C6, 0xA5F5, 0x03C7, 0xA5F6, 0x03C8, 0xA5F7, 0x03C9, 0xA5F8, 0x0401, 0xACA7, 0x0410, 0xACA1, 0x0411, 0xACA2, 0x0412, 0xACA3, 0x0413, 0xACA4, 0x0414, 0xACA5, 0x0415, 0xACA6, 0x0416, 0xACA8, 0x0417, 0xACA9, 0x0418, 0xACAA, 0x0419, 0xACAB, 0x041A, 0xACAC, 0x041B, 0xACAD, 0x041C, 0xACAE, 0x041D, 0xACAF, 0x041E, 0xACB0, 0x041F, 0xACB1, 0x0420, 0xACB2, 0x0421, 0xACB3, 0x0422, 0xACB4, 0x0423, 0xACB5, 0x0424, 0xACB6, 0x0425, 0xACB7, 0x0426, 0xACB8, 0x0427, 0xACB9, 0x0428, 0xACBA, 0x0429, 0xACBB, 0x042A, 0xACBC, 0x042B, 0xACBD, 0x042C, 0xACBE, 0x042D, 0xACBF, 0x042E, 0xACC0, 0x042F, 0xACC1, 0x0430, 0xACD1, 0x0431, 0xACD2, 0x0432, 0xACD3, 0x0433, 0xACD4, 0x0434, 0xACD5, 0x0435, 0xACD6, 0x0436, 0xACD8, 0x0437, 0xACD9, 0x0438, 0xACDA, 0x0439, 0xACDB, 0x043A, 0xACDC, 0x043B, 0xACDD, 0x043C, 0xACDE, 0x043D, 0xACDF, 0x043E, 0xACE0, 0x043F, 0xACE1, 0x0440, 0xACE2, 0x0441, 0xACE3, 0x0442, 0xACE4, 0x0443, 0xACE5, 0x0444, 0xACE6, 0x0445, 0xACE7, 0x0446, 0xACE8, 0x0447, 0xACE9, 0x0448, 0xACEA, 0x0449, 0xACEB, 0x044A, 0xACEC, 0x044B, 0xACED, 0x044C, 0xACEE, 0x044D, 0xACEF, 0x044E, 0xACF0, 0x044F, 0xACF1, 0x0451, 0xACD7, 0x2015, 0xA1AA, 0x2018, 0xA1AE, 0x2019, 0xA1AF, 0x201C, 0xA1B0, 0x201D, 0xA1B1, 0x2020, 0xA2D3, 0x2021, 0xA2D4, 0x2025, 0xA1A5, 0x2026, 0xA1A6, 0x2030, 0xA2B6, 0x2032, 0xA1C7, 0x2033, 0xA1C8, 0x203B, 0xA1D8, 0x2074, 0xA9F9, 0x207F, 0xA9FA, 0x2081, 0xA9FB, 0x2082, 0xA9FC, 0x2083, 0xA9FD, 0x2084, 0xA9FE, 0x20AC, 0xA2E6, 0x2103, 0xA1C9, 0x2109, 0xA2B5, 0x2113, 0xA7A4, 0x2116, 0xA2E0, 0x2121, 0xA2E5, 0x2122, 0xA2E2, 0x2126, 0xA7D9, 0x212B, 0xA1CA, 0x2153, 0xA8F7, 0x2154, 0xA8F8, 0x215B, 0xA8FB, 0x215C, 0xA8FC, 0x215D, 0xA8FD, 0x215E, 0xA8FE, 0x2160, 0xA5B0, 0x2161, 0xA5B1, 0x2162, 0xA5B2, 0x2163, 0xA5B3, 0x2164, 0xA5B4, 0x2165, 0xA5B5, 0x2166, 0xA5B6, 0x2167, 0xA5B7, 0x2168, 0xA5B8, 0x2169, 0xA5B9, 0x2170, 0xA5A1, 0x2171, 0xA5A2, 0x2172, 0xA5A3, 0x2173, 0xA5A4, 0x2174, 0xA5A5, 0x2175, 0xA5A6, 0x2176, 0xA5A7, 0x2177, 0xA5A8, 0x2178, 0xA5A9, 0x2179, 0xA5AA, 0x2190, 0xA1E7, 0x2191, 0xA1E8, 0x2192, 0xA1E6, 0x2193, 0xA1E9, 0x2194, 0xA1EA, 0x2195, 0xA2D5, 0x2196, 0xA2D8, 0x2197, 0xA2D6, 0x2198, 0xA2D9, 0x2199, 0xA2D7, 0x21D2, 0xA2A1, 0x21D4, 0xA2A2, 0x2200, 0xA2A3, 0x2202, 0xA1D3, 0x2203, 0xA2A4, 0x2207, 0xA1D4, 0x2208, 0xA1F4, 0x220B, 0xA1F5, 0x220F, 0xA2B3, 0x2211, 0xA2B2, 0x221A, 0xA1EE, 0x221D, 0xA1F0, 0x221E, 0xA1C4, 0x2220, 0xA1D0, 0x2225, 0xA1AB, 0x2227, 0xA1FC, 0x2228, 0xA1FD, 0x2229, 0xA1FB, 0x222A, 0xA1FA, 0x222B, 0xA1F2, 0x222C, 0xA1F3, 0x222E, 0xA2B1, 0x2234, 0xA1C5, 0x2235, 0xA1F1, 0x223C, 0xA1AD, 0x223D, 0xA1EF, 0x2252, 0xA1D6, 0x2260, 0xA1C1, 0x2261, 0xA1D5, 0x2264, 0xA1C2, 0x2265, 0xA1C3, 0x226A, 0xA1EC, 0x226B, 0xA1ED, 0x2282, 0xA1F8, 0x2283, 0xA1F9, 0x2286, 0xA1F6, 0x2287, 0xA1F7, 0x2299, 0xA2C1, 0x22A5, 0xA1D1, 0x2312, 0xA1D2, 0x2460, 0xA8E7, 0x2461, 0xA8E8, 0x2462, 0xA8E9, 0x2463, 0xA8EA, 0x2464, 0xA8EB, 0x2465, 0xA8EC, 0x2466, 0xA8ED, 0x2467, 0xA8EE, 0x2468, 0xA8EF, 0x2469, 0xA8F0, 0x246A, 0xA8F1, 0x246B, 0xA8F2, 0x246C, 0xA8F3, 0x246D, 0xA8F4, 0x246E, 0xA8F5, 0x2474, 0xA9E7, 0x2475, 0xA9E8, 0x2476, 0xA9E9, 0x2477, 0xA9EA, 0x2478, 0xA9EB, 0x2479, 0xA9EC, 0x247A, 0xA9ED, 0x247B, 0xA9EE, 0x247C, 0xA9EF, 0x247D, 0xA9F0, 0x247E, 0xA9F1, 0x247F, 0xA9F2, 0x2480, 0xA9F3, 0x2481, 0xA9F4, 0x2482, 0xA9F5, 0x249C, 0xA9CD, 0x249D, 0xA9CE, 0x249E, 0xA9CF, 0x249F, 0xA9D0, 0x24A0, 0xA9D1, 0x24A1, 0xA9D2, 0x24A2, 0xA9D3, 0x24A3, 0xA9D4, 0x24A4, 0xA9D5, 0x24A5, 0xA9D6, 0x24A6, 0xA9D7, 0x24A7, 0xA9D8, 0x24A8, 0xA9D9, 0x24A9, 0xA9DA, 0x24AA, 0xA9DB, 0x24AB, 0xA9DC, 0x24AC, 0xA9DD, 0x24AD, 0xA9DE, 0x24AE, 0xA9DF, 0x24AF, 0xA9E0, 0x24B0, 0xA9E1, 0x24B1, 0xA9E2, 0x24B2, 0xA9E3, 0x24B3, 0xA9E4, 0x24B4, 0xA9E5, 0x24B5, 0xA9E6, 0x24D0, 0xA8CD, 0x24D1, 0xA8CE, 0x24D2, 0xA8CF, 0x24D3, 0xA8D0, 0x24D4, 0xA8D1, 0x24D5, 0xA8D2, 0x24D6, 0xA8D3, 0x24D7, 0xA8D4, 0x24D8, 0xA8D5, 0x24D9, 0xA8D6, 0x24DA, 0xA8D7, 0x24DB, 0xA8D8, 0x24DC, 0xA8D9, 0x24DD, 0xA8DA, 0x24DE, 0xA8DB, 0x24DF, 0xA8DC, 0x24E0, 0xA8DD, 0x24E1, 0xA8DE, 0x24E2, 0xA8DF, 0x24E3, 0xA8E0, 0x24E4, 0xA8E1, 0x24E5, 0xA8E2, 0x24E6, 0xA8E3, 0x24E7, 0xA8E4, 0x24E8, 0xA8E5, 0x24E9, 0xA8E6, 0x2500, 0xA6A1, 0x2501, 0xA6AC, 0x2502, 0xA6A2, 0x2503, 0xA6AD, 0x250C, 0xA6A3, 0x250D, 0xA6C8, 0x250E, 0xA6C7, 0x250F, 0xA6AE, 0x2510, 0xA6A4, 0x2511, 0xA6C2, 0x2512, 0xA6C1, 0x2513, 0xA6AF, 0x2514, 0xA6A6, 0x2515, 0xA6C6, 0x2516, 0xA6C5, 0x2517, 0xA6B1, 0x2518, 0xA6A5, 0x2519, 0xA6C4, 0x251A, 0xA6C3, 0x251B, 0xA6B0, 0x251C, 0xA6A7, 0x251D, 0xA6BC, 0x251E, 0xA6C9, 0x251F, 0xA6CA, 0x2520, 0xA6B7, 0x2521, 0xA6CB, 0x2522, 0xA6CC, 0x2523, 0xA6B2, 0x2524, 0xA6A9, 0x2525, 0xA6BE, 0x2526, 0xA6CD, 0x2527, 0xA6CE, 0x2528, 0xA6B9, 0x2529, 0xA6CF, 0x252A, 0xA6D0, 0x252B, 0xA6B4, 0x252C, 0xA6A8, 0x252D, 0xA6D1, 0x252E, 0xA6D2, 0x252F, 0xA6B8, 0x2530, 0xA6BD, 0x2531, 0xA6D3, 0x2532, 0xA6D4, 0x2533, 0xA6B3, 0x2534, 0xA6AA, 0x2535, 0xA6D5, 0x2536, 0xA6D6, 0x2537, 0xA6BA, 0x2538, 0xA6BF, 0x2539, 0xA6D7, 0x253A, 0xA6D8, 0x253B, 0xA6B5, 0x253C, 0xA6AB, 0x253D, 0xA6D9, 0x253E, 0xA6DA, 0x253F, 0xA6BB, 0x2540, 0xA6DB, 0x2541, 0xA6DC, 0x2542, 0xA6C0, 0x2543, 0xA6DD, 0x2544, 0xA6DE, 0x2545, 0xA6DF, 0x2546, 0xA6E0, 0x2547, 0xA6E1, 0x2548, 0xA6E2, 0x2549, 0xA6E3, 0x254A, 0xA6E4, 0x254B, 0xA6B6, 0x2592, 0xA2C6, 0x25A0, 0xA1E1, 0x25A1, 0xA1E0, 0x25A3, 0xA2C3, 0x25A4, 0xA2C7, 0x25A5, 0xA2C8, 0x25A6, 0xA2CB, 0x25A7, 0xA2CA, 0x25A8, 0xA2C9, 0x25A9, 0xA2CC, 0x25B2, 0xA1E3, 0x25B3, 0xA1E2, 0x25B6, 0xA2BA, 0x25B7, 0xA2B9, 0x25BC, 0xA1E5, 0x25BD, 0xA1E4, 0x25C0, 0xA2B8, 0x25C1, 0xA2B7, 0x25C6, 0xA1DF, 0x25C7, 0xA1DE, 0x25C8, 0xA2C2, 0x25CB, 0xA1DB, 0x25CE, 0xA1DD, 0x25CF, 0xA1DC, 0x25D0, 0xA2C4, 0x25D1, 0xA2C5, 0x2605, 0xA1DA, 0x2606, 0xA1D9, 0x260E, 0xA2CF, 0x260F, 0xA2CE, 0x261C, 0xA2D0, 0x261E, 0xA2D1, 0x2640, 0xA1CF, 0x2642, 0xA1CE, 0x2660, 0xA2BC, 0x2661, 0xA2BD, 0x2663, 0xA2C0, 0x2664, 0xA2BB, 0x2665, 0xA2BE, 0x2667, 0xA2BF, 0x2668, 0xA2CD, 0x2669, 0xA2DB, 0x266A, 0xA2DC, 0x266C, 0xA2DD, 0x266D, 0xA2DA, 0x3000, 0xA1A1, 0x3001, 0xA1A2, 0x3002, 0xA1A3, 0x3003, 0xA1A8, 0x3008, 0xA1B4, 0x3009, 0xA1B5, 0x300A, 0xA1B6, 0x300B, 0xA1B7, 0x300C, 0xA1B8, 0x300D, 0xA1B9, 0x300E, 0xA1BA, 0x300F, 0xA1BB, 0x3010, 0xA1BC, 0x3011, 0xA1BD, 0x3013, 0xA1EB, 0x3014, 0xA1B2, 0x3015, 0xA1B3, 0x3041, 0xAAA1, 0x3042, 0xAAA2, 0x3043, 0xAAA3, 0x3044, 0xAAA4, 0x3045, 0xAAA5, 0x3046, 0xAAA6, 0x3047, 0xAAA7, 0x3048, 0xAAA8, 0x3049, 0xAAA9, 0x304A, 0xAAAA, 0x304B, 0xAAAB, 0x304C, 0xAAAC, 0x304D, 0xAAAD, 0x304E, 0xAAAE, 0x304F, 0xAAAF, 0x3050, 0xAAB0, 0x3051, 0xAAB1, 0x3052, 0xAAB2, 0x3053, 0xAAB3, 0x3054, 0xAAB4, 0x3055, 0xAAB5, 0x3056, 0xAAB6, 0x3057, 0xAAB7, 0x3058, 0xAAB8, 0x3059, 0xAAB9, 0x305A, 0xAABA, 0x305B, 0xAABB, 0x305C, 0xAABC, 0x305D, 0xAABD, 0x305E, 0xAABE, 0x305F, 0xAABF, 0x3060, 0xAAC0, 0x3061, 0xAAC1, 0x3062, 0xAAC2, 0x3063, 0xAAC3, 0x3064, 0xAAC4, 0x3065, 0xAAC5, 0x3066, 0xAAC6, 0x3067, 0xAAC7, 0x3068, 0xAAC8, 0x3069, 0xAAC9, 0x306A, 0xAACA, 0x306B, 0xAACB, 0x306C, 0xAACC, 0x306D, 0xAACD, 0x306E, 0xAACE, 0x306F, 0xAACF, 0x3070, 0xAAD0, 0x3071, 0xAAD1, 0x3072, 0xAAD2, 0x3073, 0xAAD3, 0x3074, 0xAAD4, 0x3075, 0xAAD5, 0x3076, 0xAAD6, 0x3077, 0xAAD7, 0x3078, 0xAAD8, 0x3079, 0xAAD9, 0x307A, 0xAADA, 0x307B, 0xAADB, 0x307C, 0xAADC, 0x307D, 0xAADD, 0x307E, 0xAADE, 0x307F, 0xAADF, 0x3080, 0xAAE0, 0x3081, 0xAAE1, 0x3082, 0xAAE2, 0x3083, 0xAAE3, 0x3084, 0xAAE4, 0x3085, 0xAAE5, 0x3086, 0xAAE6, 0x3087, 0xAAE7, 0x3088, 0xAAE8, 0x3089, 0xAAE9, 0x308A, 0xAAEA, 0x308B, 0xAAEB, 0x308C, 0xAAEC, 0x308D, 0xAAED, 0x308E, 0xAAEE, 0x308F, 0xAAEF, 0x3090, 0xAAF0, 0x3091, 0xAAF1, 0x3092, 0xAAF2, 0x3093, 0xAAF3, 0x30A1, 0xABA1, 0x30A2, 0xABA2, 0x30A3, 0xABA3, 0x30A4, 0xABA4, 0x30A5, 0xABA5, 0x30A6, 0xABA6, 0x30A7, 0xABA7, 0x30A8, 0xABA8, 0x30A9, 0xABA9, 0x30AA, 0xABAA, 0x30AB, 0xABAB, 0x30AC, 0xABAC, 0x30AD, 0xABAD, 0x30AE, 0xABAE, 0x30AF, 0xABAF, 0x30B0, 0xABB0, 0x30B1, 0xABB1, 0x30B2, 0xABB2, 0x30B3, 0xABB3, 0x30B4, 0xABB4, 0x30B5, 0xABB5, 0x30B6, 0xABB6, 0x30B7, 0xABB7, 0x30B8, 0xABB8, 0x30B9, 0xABB9, 0x30BA, 0xABBA, 0x30BB, 0xABBB, 0x30BC, 0xABBC, 0x30BD, 0xABBD, 0x30BE, 0xABBE, 0x30BF, 0xABBF, 0x30C0, 0xABC0, 0x30C1, 0xABC1, 0x30C2, 0xABC2, 0x30C3, 0xABC3, 0x30C4, 0xABC4, 0x30C5, 0xABC5, 0x30C6, 0xABC6, 0x30C7, 0xABC7, 0x30C8, 0xABC8, 0x30C9, 0xABC9, 0x30CA, 0xABCA, 0x30CB, 0xABCB, 0x30CC, 0xABCC, 0x30CD, 0xABCD, 0x30CE, 0xABCE, 0x30CF, 0xABCF, 0x30D0, 0xABD0, 0x30D1, 0xABD1, 0x30D2, 0xABD2, 0x30D3, 0xABD3, 0x30D4, 0xABD4, 0x30D5, 0xABD5, 0x30D6, 0xABD6, 0x30D7, 0xABD7, 0x30D8, 0xABD8, 0x30D9, 0xABD9, 0x30DA, 0xABDA, 0x30DB, 0xABDB, 0x30DC, 0xABDC, 0x30DD, 0xABDD, 0x30DE, 0xABDE, 0x30DF, 0xABDF, 0x30E0, 0xABE0, 0x30E1, 0xABE1, 0x30E2, 0xABE2, 0x30E3, 0xABE3, 0x30E4, 0xABE4, 0x30E5, 0xABE5, 0x30E6, 0xABE6, 0x30E7, 0xABE7, 0x30E8, 0xABE8, 0x30E9, 0xABE9, 0x30EA, 0xABEA, 0x30EB, 0xABEB, 0x30EC, 0xABEC, 0x30ED, 0xABED, 0x30EE, 0xABEE, 0x30EF, 0xABEF, 0x30F0, 0xABF0, 0x30F1, 0xABF1, 0x30F2, 0xABF2, 0x30F3, 0xABF3, 0x30F4, 0xABF4, 0x30F5, 0xABF5, 0x30F6, 0xABF6, 0x3131, 0xA4A1, 0x3132, 0xA4A2, 0x3133, 0xA4A3, 0x3134, 0xA4A4, 0x3135, 0xA4A5, 0x3136, 0xA4A6, 0x3137, 0xA4A7, 0x3138, 0xA4A8, 0x3139, 0xA4A9, 0x313A, 0xA4AA, 0x313B, 0xA4AB, 0x313C, 0xA4AC, 0x313D, 0xA4AD, 0x313E, 0xA4AE, 0x313F, 0xA4AF, 0x3140, 0xA4B0, 0x3141, 0xA4B1, 0x3142, 0xA4B2, 0x3143, 0xA4B3, 0x3144, 0xA4B4, 0x3145, 0xA4B5, 0x3146, 0xA4B6, 0x3147, 0xA4B7, 0x3148, 0xA4B8, 0x3149, 0xA4B9, 0x314A, 0xA4BA, 0x314B, 0xA4BB, 0x314C, 0xA4BC, 0x314D, 0xA4BD, 0x314E, 0xA4BE, 0x314F, 0xA4BF, 0x3150, 0xA4C0, 0x3151, 0xA4C1, 0x3152, 0xA4C2, 0x3153, 0xA4C3, 0x3154, 0xA4C4, 0x3155, 0xA4C5, 0x3156, 0xA4C6, 0x3157, 0xA4C7, 0x3158, 0xA4C8, 0x3159, 0xA4C9, 0x315A, 0xA4CA, 0x315B, 0xA4CB, 0x315C, 0xA4CC, 0x315D, 0xA4CD, 0x315E, 0xA4CE, 0x315F, 0xA4CF, 0x3160, 0xA4D0, 0x3161, 0xA4D1, 0x3162, 0xA4D2, 0x3163, 0xA4D3, 0x3164, 0xA4D4, 0x3165, 0xA4D5, 0x3166, 0xA4D6, 0x3167, 0xA4D7, 0x3168, 0xA4D8, 0x3169, 0xA4D9, 0x316A, 0xA4DA, 0x316B, 0xA4DB, 0x316C, 0xA4DC, 0x316D, 0xA4DD, 0x316E, 0xA4DE, 0x316F, 0xA4DF, 0x3170, 0xA4E0, 0x3171, 0xA4E1, 0x3172, 0xA4E2, 0x3173, 0xA4E3, 0x3174, 0xA4E4, 0x3175, 0xA4E5, 0x3176, 0xA4E6, 0x3177, 0xA4E7, 0x3178, 0xA4E8, 0x3179, 0xA4E9, 0x317A, 0xA4EA, 0x317B, 0xA4EB, 0x317C, 0xA4EC, 0x317D, 0xA4ED, 0x317E, 0xA4EE, 0x317F, 0xA4EF, 0x3180, 0xA4F0, 0x3181, 0xA4F1, 0x3182, 0xA4F2, 0x3183, 0xA4F3, 0x3184, 0xA4F4, 0x3185, 0xA4F5, 0x3186, 0xA4F6, 0x3187, 0xA4F7, 0x3188, 0xA4F8, 0x3189, 0xA4F9, 0x318A, 0xA4FA, 0x318B, 0xA4FB, 0x318C, 0xA4FC, 0x318D, 0xA4FD, 0x318E, 0xA4FE, 0x3200, 0xA9B1, 0x3201, 0xA9B2, 0x3202, 0xA9B3, 0x3203, 0xA9B4, 0x3204, 0xA9B5, 0x3205, 0xA9B6, 0x3206, 0xA9B7, 0x3207, 0xA9B8, 0x3208, 0xA9B9, 0x3209, 0xA9BA, 0x320A, 0xA9BB, 0x320B, 0xA9BC, 0x320C, 0xA9BD, 0x320D, 0xA9BE, 0x320E, 0xA9BF, 0x320F, 0xA9C0, 0x3210, 0xA9C1, 0x3211, 0xA9C2, 0x3212, 0xA9C3, 0x3213, 0xA9C4, 0x3214, 0xA9C5, 0x3215, 0xA9C6, 0x3216, 0xA9C7, 0x3217, 0xA9C8, 0x3218, 0xA9C9, 0x3219, 0xA9CA, 0x321A, 0xA9CB, 0x321B, 0xA9CC, 0x321C, 0xA2DF, 0x3260, 0xA8B1, 0x3261, 0xA8B2, 0x3262, 0xA8B3, 0x3263, 0xA8B4, 0x3264, 0xA8B5, 0x3265, 0xA8B6, 0x3266, 0xA8B7, 0x3267, 0xA8B8, 0x3268, 0xA8B9, 0x3269, 0xA8BA, 0x326A, 0xA8BB, 0x326B, 0xA8BC, 0x326C, 0xA8BD, 0x326D, 0xA8BE, 0x326E, 0xA8BF, 0x326F, 0xA8C0, 0x3270, 0xA8C1, 0x3271, 0xA8C2, 0x3272, 0xA8C3, 0x3273, 0xA8C4, 0x3274, 0xA8C5, 0x3275, 0xA8C6, 0x3276, 0xA8C7, 0x3277, 0xA8C8, 0x3278, 0xA8C9, 0x3279, 0xA8CA, 0x327A, 0xA8CB, 0x327B, 0xA8CC, 0x327F, 0xA2DE, 0x3380, 0xA7C9, 0x3381, 0xA7CA, 0x3382, 0xA7CB, 0x3383, 0xA7CC, 0x3384, 0xA7CD, 0x3388, 0xA7BA, 0x3389, 0xA7BB, 0x338A, 0xA7DC, 0x338B, 0xA7DD, 0x338C, 0xA7DE, 0x338D, 0xA7B6, 0x338E, 0xA7B7, 0x338F, 0xA7B8, 0x3390, 0xA7D4, 0x3391, 0xA7D5, 0x3392, 0xA7D6, 0x3393, 0xA7D7, 0x3394, 0xA7D8, 0x3395, 0xA7A1, 0x3396, 0xA7A2, 0x3397, 0xA7A3, 0x3398, 0xA7A5, 0x3399, 0xA7AB, 0x339A, 0xA7AC, 0x339B, 0xA7AD, 0x339C, 0xA7AE, 0x339D, 0xA7AF, 0x339E, 0xA7B0, 0x339F, 0xA7B1, 0x33A0, 0xA7B2, 0x33A1, 0xA7B3, 0x33A2, 0xA7B4, 0x33A3, 0xA7A7, 0x33A4, 0xA7A8, 0x33A5, 0xA7A9, 0x33A6, 0xA7AA, 0x33A7, 0xA7BD, 0x33A8, 0xA7BE, 0x33A9, 0xA7E5, 0x33AA, 0xA7E6, 0x33AB, 0xA7E7, 0x33AC, 0xA7E8, 0x33AD, 0xA7E1, 0x33AE, 0xA7E2, 0x33AF, 0xA7E3, 0x33B0, 0xA7BF, 0x33B1, 0xA7C0, 0x33B2, 0xA7C1, 0x33B3, 0xA7C2, 0x33B4, 0xA7C3, 0x33B5, 0xA7C4, 0x33B6, 0xA7C5, 0x33B7, 0xA7C6, 0x33B8, 0xA7C7, 0x33B9, 0xA7C8, 0x33BA, 0xA7CE, 0x33BB, 0xA7CF, 0x33BC, 0xA7D0, 0x33BD, 0xA7D1, 0x33BE, 0xA7D2, 0x33BF, 0xA7D3, 0x33C0, 0xA7DA, 0x33C1, 0xA7DB, 0x33C2, 0xA2E3, 0x33C3, 0xA7EC, 0x33C4, 0xA7A6, 0x33C5, 0xA7E0, 0x33C6, 0xA7EF, 0x33C7, 0xA2E1, 0x33C8, 0xA7BC, 0x33C9, 0xA7ED, 0x33CA, 0xA7B5, 0x33CF, 0xA7B9, 0x33D0, 0xA7EA, 0x33D3, 0xA7EB, 0x33D6, 0xA7DF, 0x33D8, 0xA2E4, 0x33DB, 0xA7E4, 0x33DC, 0xA7EE, 0x33DD, 0xA7E9, 0x4E00, 0xECE9, 0x4E01, 0xEFCB, 0x4E03, 0xF6D2, 0x4E07, 0xD8B2, 0x4E08, 0xEDDB, 0x4E09, 0xDFB2, 0x4E0A, 0xDFBE, 0x4E0B, 0xF9BB, 0x4E0D, 0xDCF4, 0x4E11, 0xF5E4, 0x4E14, 0xF3A6, 0x4E15, 0xDDE0, 0x4E16, 0xE1A6, 0x4E18, 0xCEF8, 0x4E19, 0xDCB0, 0x4E1E, 0xE3AA, 0x4E2D, 0xF1E9, 0x4E32, 0xCDFA, 0x4E38, 0xFCAF, 0x4E39, 0xD3A1, 0x4E3B, 0xF1AB, 0x4E42, 0xE7D1, 0x4E43, 0xD2AC, 0x4E45, 0xCEF9, 0x4E4B, 0xF1FD, 0x4E4D, 0xDEBF, 0x4E4E, 0xFBBA, 0x4E4F, 0xF9B9, 0x4E56, 0xCED2, 0x4E58, 0xE3AB, 0x4E59, 0xEBE0, 0x4E5D, 0xCEFA, 0x4E5E, 0xCBF7, 0x4E5F, 0xE5A5, 0x4E6B, 0xCAE1, 0x4E6D, 0xD4CC, 0x4E73, 0xEAE1, 0x4E76, 0xDCE3, 0x4E77, 0xDFAD, 0x4E7E, 0xCBEB, 0x4E82, 0xD5AF, 0x4E86, 0xD6F5, 0x4E88, 0xE5F8, 0x4E8B, 0xDEC0, 0x4E8C, 0xECA3, 0x4E8E, 0xE9CD, 0x4E90, 0xEAA7, 0x4E91, 0xE9F6, 0x4E92, 0xFBBB, 0x4E94, 0xE7E9, 0x4E95, 0xEFCC, 0x4E98, 0xD0E6, 0x4E9B, 0xDEC1, 0x4E9E, 0xE4AC, 0x4EA1, 0xD8CC, 0x4EA2, 0xF9F1, 0x4EA4, 0xCEDF, 0x4EA5, 0xFAA4, 0x4EA6, 0xE6B2, 0x4EA8, 0xFAFB, 0x4EAB, 0xFABD, 0x4EAC, 0xCCC8, 0x4EAD, 0xEFCD, 0x4EAE, 0xD5D5, 0x4EB6, 0xD3A2, 0x4EBA, 0xECD1, 0x4EC0, 0xE4A7, 0x4EC1, 0xECD2, 0x4EC4, 0xF6B1, 0x4EC7, 0xCEFB, 0x4ECA, 0xD0D1, 0x4ECB, 0xCBBF, 0x4ECD, 0xEDA4, 0x4ED4, 0xEDA8, 0x4ED5, 0xDEC2, 0x4ED6, 0xF6E2, 0x4ED7, 0xEDDC, 0x4ED8, 0xDCF5, 0x4ED9, 0xE0B9, 0x4EDD, 0xD4CE, 0x4EDF, 0xF4B5, 0x4EE3, 0xD3DB, 0x4EE4, 0xD6B5, 0x4EE5, 0xECA4, 0x4EF0, 0xE4E6, 0x4EF2, 0xF1EA, 0x4EF6, 0xCBEC, 0x4EF7, 0xCBC0, 0x4EFB, 0xECF2, 0x4F01, 0xD0EA, 0x4F09, 0xF9F2, 0x4F0A, 0xECA5, 0x4F0B, 0xD0DF, 0x4F0D, 0xE7EA, 0x4F0E, 0xD0EB, 0x4F0F, 0xDCD1, 0x4F10, 0xDBE9, 0x4F11, 0xFDCC, 0x4F2F, 0xDBD7, 0x4F34, 0xDAE1, 0x4F36, 0xD6B6, 0x4F38, 0xE3DF, 0x4F3A, 0xDEC3, 0x4F3C, 0xDEC4, 0x4F3D, 0xCAA1, 0x4F43, 0xEEEC, 0x4F46, 0xD3A3, 0x4F47, 0xEEB7, 0x4F48, 0xF8CF, 0x4F4D, 0xEAC8, 0x4F4E, 0xEEB8, 0x4F4F, 0xF1AC, 0x4F50, 0xF1A5, 0x4F51, 0xE9CE, 0x4F55, 0xF9BC, 0x4F59, 0xE5F9, 0x4F5A, 0xECEA, 0x4F5B, 0xDDD6, 0x4F5C, 0xEDC2, 0x4F69, 0xF8A5, 0x4F6F, 0xE5BA, 0x4F70, 0xDBD8, 0x4F73, 0xCAA2, 0x4F76, 0xD1CD, 0x4F7A, 0xEEED, 0x4F7E, 0xECEB, 0x4F7F, 0xDEC5, 0x4F81, 0xE3E0, 0x4F83, 0xCAC9, 0x4F84, 0xF2E9, 0x4F86, 0xD5CE, 0x4F88, 0xF6B6, 0x4F8A, 0xCEC2, 0x4F8B, 0xD6C7, 0x4F8D, 0xE3B4, 0x4F8F, 0xF1AD, 0x4F91, 0xEAE2, 0x4F96, 0xD7C2, 0x4F98, 0xF3A7, 0x4F9B, 0xCDEA, 0x4F9D, 0xEBEE, 0x4FAE, 0xD9B2, 0x4FAF, 0xFDA5, 0x4FB5, 0xF6D5, 0x4FB6, 0xD5E2, 0x4FBF, 0xF8B5, 0x4FC2, 0xCCF5, 0x4FC3, 0xF5B5, 0x4FC4, 0xE4AD, 0x4FC9, 0xE7EB, 0x4FCA, 0xF1D5, 0x4FCE, 0xF0BB, 0x4FD1, 0xE9B5, 0x4FD3, 0xCCC9, 0x4FD4, 0xFAD5, 0x4FD7, 0xE1D4, 0x4FDA, 0xD7D6, 0x4FDD, 0xDCC1, 0x4FDF, 0xDEC6, 0x4FE0, 0xFAEF, 0x4FE1, 0xE3E1, 0x4FEE, 0xE1F3, 0x4FEF, 0xDCF6, 0x4FF1, 0xCEFC, 0x4FF3, 0xDBC4, 0x4FF5, 0xF8F1, 0x4FF8, 0xDCE4, 0x4FFA, 0xE5EF, 0x5002, 0xDCB1, 0x5006, 0xD5D6, 0x5009, 0xF3DA, 0x500B, 0xCBC1, 0x500D, 0xDBC3, 0x5011, 0xD9FA, 0x5012, 0xD3EE, 0x5016, 0xFAB8, 0x5019, 0xFDA6, 0x501A, 0xEBEF, 0x501C, 0xF4A6, 0x501E, 0xCCCA, 0x501F, 0xF3A8, 0x5021, 0xF3DB, 0x5023, 0xDBA7, 0x5024, 0xF6B7, 0x5026, 0xCFE6, 0x5027, 0xF0F2, 0x5028, 0xCBDA, 0x502A, 0xE7D2, 0x502B, 0xD7C3, 0x502C, 0xF6F0, 0x502D, 0xE8DE, 0x503B, 0xE5A6, 0x5043, 0xE5E7, 0x5047, 0xCAA3, 0x5048, 0xCCA7, 0x5049, 0xEAC9, 0x504F, 0xF8B6, 0x5055, 0xFAA5, 0x505A, 0xF1AE, 0x505C, 0xEFCE, 0x5065, 0xCBED, 0x5074, 0xF6B0, 0x5075, 0xEFCF, 0x5076, 0xE9CF, 0x5078, 0xF7DE, 0x5080, 0xCED3, 0x5085, 0xDCF7, 0x508D, 0xDBA8, 0x5091, 0xCBF8, 0x5098, 0xDFA1, 0x5099, 0xDDE1, 0x50AC, 0xF5CA, 0x50AD, 0xE9B6, 0x50B2, 0xE7EC, 0x50B3, 0xEEEE, 0x50B5, 0xF3F0, 0x50B7, 0xDFBF, 0x50BE, 0xCCCB, 0x50C5, 0xD0C1, 0x50C9, 0xF4D2, 0x50CA, 0xE0BA, 0x50CF, 0xDFC0, 0x50D1, 0xCEE0, 0x50D5, 0xDCD2, 0x50D6, 0xFDEA, 0x50DA, 0xD6F6, 0x50DE, 0xEACA, 0x50E5, 0xE8E9, 0x50E7, 0xE3AC, 0x50ED, 0xF3D0, 0x50F9, 0xCAA4, 0x50FB, 0xDBF8, 0x50FF, 0xDEC7, 0x5100, 0xEBF0, 0x5101, 0xF1D6, 0x5104, 0xE5E2, 0x5106, 0xCCCC, 0x5109, 0xCBFB, 0x5112, 0xEAE3, 0x511F, 0xDFC1, 0x5121, 0xD6ED, 0x512A, 0xE9D0, 0x5132, 0xEEB9, 0x5137, 0xD5E3, 0x513A, 0xD1D3, 0x513C, 0xE5F0, 0x5140, 0xE8B4, 0x5141, 0xEBC3, 0x5143, 0xEAAA, 0x5144, 0xFAFC, 0x5145, 0xF5F6, 0x5146, 0xF0BC, 0x5147, 0xFDD4, 0x5148, 0xE0BB, 0x5149, 0xCEC3, 0x514B, 0xD0BA, 0x514C, 0xF7BA, 0x514D, 0xD8F3, 0x514E, 0xF7CD, 0x5152, 0xE4AE, 0x515C, 0xD4DF, 0x5162, 0xD0E7, 0x5165, 0xECFD, 0x5167, 0xD2AE, 0x5168, 0xEEEF, 0x5169, 0xD5D7, 0x516A, 0xEAE4, 0x516B, 0xF8A2, 0x516C, 0xCDEB, 0x516D, 0xD7BF, 0x516E, 0xFBB1, 0x5171, 0xCDEC, 0x5175, 0xDCB2, 0x5176, 0xD0EC, 0x5177, 0xCEFD, 0x5178, 0xEEF0, 0x517C, 0xCCC2, 0x5180, 0xD0ED, 0x5186, 0xE5F7, 0x518A, 0xF3FC, 0x518D, 0xEEA2, 0x5192, 0xD9B3, 0x5195, 0xD8F4, 0x5197, 0xE9B7, 0x51A0, 0xCEAE, 0x51A5, 0xD9A2, 0x51AA, 0xD8F1, 0x51AC, 0xD4CF, 0x51B6, 0xE5A7, 0x51B7, 0xD5D2, 0x51BD, 0xD6A9, 0x51C4, 0xF4A2, 0x51C6, 0xF1D7, 0x51C9, 0xD5D8, 0x51CB, 0xF0BD, 0x51CC, 0xD7D0, 0x51CD, 0xD4D0, 0x51DC, 0xD7CF, 0x51DD, 0xEBEA, 0x51DE, 0xFDEB, 0x51E1, 0xDBED, 0x51F0, 0xFCC5, 0x51F1, 0xCBC2, 0x51F6, 0xFDD5, 0x51F8, 0xF4C8, 0x51F9, 0xE8EA, 0x51FA, 0xF5F3, 0x51FD, 0xF9DE, 0x5200, 0xD3EF, 0x5203, 0xECD3, 0x5206, 0xDDC2, 0x5207, 0xEFB7, 0x5208, 0xE7D4, 0x520A, 0xCACA, 0x520E, 0xD9FB, 0x5211, 0xFAFD, 0x5217, 0xD6AA, 0x521D, 0xF4F8, 0x5224, 0xF7F7, 0x5225, 0xDCAC, 0x5229, 0xD7D7, 0x522A, 0xDFA2, 0x522E, 0xCEBE, 0x5230, 0xD3F0, 0x5236, 0xF0A4, 0x5237, 0xE1EC, 0x5238, 0xCFE7, 0x5239, 0xF3CB, 0x523A, 0xEDA9, 0x523B, 0xCABE, 0x5243, 0xF4EF, 0x5247, 0xF6CE, 0x524A, 0xDEFB, 0x524B, 0xD0BB, 0x524C, 0xD5B7, 0x524D, 0xEEF1, 0x5254, 0xF4A8, 0x5256, 0xDCF8, 0x525B, 0xCBA7, 0x525D, 0xDACE, 0x5261, 0xE0E6, 0x5269, 0xEDA5, 0x526A, 0xEEF2, 0x526F, 0xDCF9, 0x5272, 0xF9DC, 0x5275, 0xF3DC, 0x527D, 0xF8F2, 0x527F, 0xF4F9, 0x5283, 0xFCF1, 0x5287, 0xD0BC, 0x5288, 0xDBF9, 0x5289, 0xD7B1, 0x528D, 0xCBFC, 0x5291, 0xF0A5, 0x5292, 0xCBFD, 0x529B, 0xD5F4, 0x529F, 0xCDED, 0x52A0, 0xCAA5, 0x52A3, 0xD6AB, 0x52A4, 0xD0C2, 0x52A9, 0xF0BE, 0x52AA, 0xD2BD, 0x52AB, 0xCCA4, 0x52BE, 0xFAB6, 0x52C1, 0xCCCD, 0x52C3, 0xDAFA, 0x52C5, 0xF6CF, 0x52C7, 0xE9B8, 0x52C9, 0xD8F5, 0x52CD, 0xCCCE, 0x52D2, 0xD7CD, 0x52D5, 0xD4D1, 0x52D6, 0xE9ED, 0x52D8, 0xCAEB, 0x52D9, 0xD9E2, 0x52DB, 0xFDB2, 0x52DD, 0xE3AD, 0x52DE, 0xD6CC, 0x52DF, 0xD9B4, 0x52E2, 0xE1A7, 0x52E3, 0xEED3, 0x52E4, 0xD0C3, 0x52F3, 0xFDB3, 0x52F5, 0xD5E4, 0x52F8, 0xCFE8, 0x52FA, 0xEDC3, 0x52FB, 0xD0B2, 0x52FE, 0xCEFE, 0x52FF, 0xDAA8, 0x5305, 0xF8D0, 0x5308, 0xFDD6, 0x530D, 0xF8D1, 0x530F, 0xF8D2, 0x5310, 0xDCD3, 0x5315, 0xDDE2, 0x5316, 0xFBF9, 0x5317, 0xDDC1, 0x5319, 0xE3B5, 0x5320, 0xEDDD, 0x5321, 0xCEC4, 0x5323, 0xCBA1, 0x532A, 0xDDE3, 0x532F, 0xFCDD, 0x5339, 0xF9AF, 0x533F, 0xD2FB, 0x5340, 0xCFA1, 0x5341, 0xE4A8, 0x5343, 0xF4B6, 0x5344, 0xECFE, 0x5347, 0xE3AE, 0x5348, 0xE7ED, 0x5349, 0xFDC1, 0x534A, 0xDAE2, 0x534D, 0xD8B3, 0x5351, 0xDDE4, 0x5352, 0xF0EF, 0x5353, 0xF6F1, 0x5354, 0xFAF0, 0x5357, 0xD1F5, 0x535A, 0xDACF, 0x535C, 0xDCD4, 0x535E, 0xDCA6, 0x5360, 0xEFBF, 0x5366, 0xCECF, 0x5368, 0xE0D9, 0x536F, 0xD9D6, 0x5370, 0xECD4, 0x5371, 0xEACB, 0x5374, 0xCABF, 0x5375, 0xD5B0, 0x5377, 0xCFE9, 0x537D, 0xF1ED, 0x537F, 0xCCCF, 0x5384, 0xE4F8, 0x5393, 0xE4ED, 0x5398, 0xD7D8, 0x539A, 0xFDA7, 0x539F, 0xEAAB, 0x53A0, 0xF6B2, 0x53A5, 0xCFF0, 0x53A6, 0xF9BD, 0x53AD, 0xE6F4, 0x53BB, 0xCBDB, 0x53C3, 0xF3D1, 0x53C8, 0xE9D1, 0x53C9, 0xF3A9, 0x53CA, 0xD0E0, 0x53CB, 0xE9D2, 0x53CD, 0xDAE3, 0x53D4, 0xE2D2, 0x53D6, 0xF6A2, 0x53D7, 0xE1F4, 0x53DB, 0xDAE4, 0x53E1, 0xE7D5, 0x53E2, 0xF5BF, 0x53E3, 0xCFA2, 0x53E4, 0xCDAF, 0x53E5, 0xCFA3, 0x53E9, 0xCDB0, 0x53EA, 0xF1FE, 0x53EB, 0xD0A3, 0x53EC, 0xE1AF, 0x53ED, 0xF8A3, 0x53EF, 0xCAA6, 0x53F0, 0xF7BB, 0x53F1, 0xF2EA, 0x53F2, 0xDEC8, 0x53F3, 0xE9D3, 0x53F8, 0xDEC9, 0x5403, 0xFDDE, 0x5404, 0xCAC0, 0x5408, 0xF9EA, 0x5409, 0xD1CE, 0x540A, 0xEED4, 0x540C, 0xD4D2, 0x540D, 0xD9A3, 0x540E, 0xFDA8, 0x540F, 0xD7D9, 0x5410, 0xF7CE, 0x5411, 0xFABE, 0x541B, 0xCFD6, 0x541D, 0xD7F0, 0x541F, 0xEBE1, 0x5420, 0xF8C5, 0x5426, 0xDCFA, 0x5429, 0xDDC3, 0x542B, 0xF9DF, 0x5433, 0xE7EF, 0x5438, 0xFDE5, 0x5439, 0xF6A3, 0x543B, 0xD9FC, 0x543C, 0xFDA9, 0x543E, 0xE7EE, 0x5442, 0xD5E5, 0x5448, 0xEFD0, 0x544A, 0xCDB1, 0x5451, 0xF7A2, 0x5468, 0xF1B2, 0x546A, 0xF1B1, 0x5471, 0xCDB2, 0x5473, 0xDAAB, 0x5475, 0xCAA7, 0x547B, 0xE3E2, 0x547C, 0xFBBC, 0x547D, 0xD9A4, 0x5480, 0xEEBA, 0x5486, 0xF8D3, 0x548C, 0xFBFA, 0x548E, 0xCFA4, 0x5490, 0xDCFB, 0x54A4, 0xF6E3, 0x54A8, 0xEDAA, 0x54AB, 0xF2A1, 0x54AC, 0xCEE1, 0x54B3, 0xFAA6, 0x54B8, 0xF9E0, 0x54BD, 0xECD6, 0x54C0, 0xE4EE, 0x54C1, 0xF9A1, 0x54C4, 0xFBEF, 0x54C8, 0xF9EB, 0x54C9, 0xEEA3, 0x54E1, 0xEAAC, 0x54E5, 0xCAA8, 0x54E8, 0xF4FA, 0x54ED, 0xCDD6, 0x54EE, 0xFCF6, 0x54F2, 0xF4C9, 0x54FA, 0xF8D4, 0x5504, 0xF8A6, 0x5506, 0xDECA, 0x5507, 0xF2C6, 0x550E, 0xD7DA, 0x5510, 0xD3D0, 0x551C, 0xD8C5, 0x552F, 0xEAE6, 0x5531, 0xF3DD, 0x5535, 0xE4DA, 0x553E, 0xF6E4, 0x5544, 0xF6F2, 0x5546, 0xDFC2, 0x554F, 0xD9FD, 0x5553, 0xCCF6, 0x5556, 0xD3BA, 0x555E, 0xE4AF, 0x5563, 0xF9E1, 0x557C, 0xF0A6, 0x5580, 0xCBD3, 0x5584, 0xE0BC, 0x5586, 0xF4CA, 0x5587, 0xD4FA, 0x5589, 0xFDAA, 0x558A, 0xF9E2, 0x5598, 0xF4B7, 0x5599, 0xFDC2, 0x559A, 0xFCB0, 0x559C, 0xFDEC, 0x559D, 0xCAE2, 0x55A7, 0xFDBD, 0x55A9, 0xEAE7, 0x55AA, 0xDFC3, 0x55AB, 0xD1D2, 0x55AC, 0xCEE2, 0x55AE, 0xD3A4, 0x55C5, 0xFDAB, 0x55C7, 0xDFE0, 0x55D4, 0xF2C7, 0x55DA, 0xE7F0, 0x55DC, 0xD0EE, 0x55DF, 0xF3AA, 0x55E3, 0xDECB, 0x55E4, 0xF6B8, 0x55FD, 0xE1F5, 0x55FE, 0xF1B3, 0x5606, 0xF7A3, 0x5609, 0xCAA9, 0x5614, 0xCFA5, 0x5617, 0xDFC4, 0x562F, 0xE1B0, 0x5632, 0xF0BF, 0x5634, 0xF6A4, 0x5636, 0xE3B6, 0x5653, 0xFAC6, 0x5668, 0xD0EF, 0x566B, 0xFDED, 0x5674, 0xDDC4, 0x5686, 0xFCF7, 0x56A5, 0xE6BF, 0x56AC, 0xDEAD, 0x56AE, 0xFABF, 0x56B4, 0xE5F1, 0x56BC, 0xEDC4, 0x56CA, 0xD2A5, 0x56CD, 0xFDEE, 0x56D1, 0xF5B6, 0x56DA, 0xE1F6, 0x56DB, 0xDECC, 0x56DE, 0xFCDE, 0x56E0, 0xECD7, 0x56F0, 0xCDDD, 0x56F9, 0xD6B7, 0x56FA, 0xCDB3, 0x5703, 0xF8D5, 0x5704, 0xE5D8, 0x5708, 0xCFEA, 0x570B, 0xCFD0, 0x570D, 0xEACC, 0x5712, 0xEAAE, 0x5713, 0xEAAD, 0x5716, 0xD3F1, 0x5718, 0xD3A5, 0x571F, 0xF7CF, 0x5728, 0xEEA4, 0x572D, 0xD0A4, 0x5730, 0xF2A2, 0x573B, 0xD0F0, 0x5740, 0xF2A3, 0x5742, 0xF7F8, 0x5747, 0xD0B3, 0x574A, 0xDBA9, 0x574D, 0xD3BB, 0x574E, 0xCAEC, 0x5750, 0xF1A6, 0x5751, 0xCBD5, 0x5761, 0xF7E7, 0x5764, 0xCDDE, 0x5766, 0xF7A4, 0x576A, 0xF8C0, 0x576E, 0xD3DD, 0x5770, 0xCCD0, 0x5775, 0xCFA6, 0x577C, 0xF6F3, 0x5782, 0xE1F7, 0x5788, 0xD3DC, 0x578B, 0xFAFE, 0x5793, 0xFAA7, 0x57A0, 0xEBD9, 0x57A2, 0xCFA7, 0x57A3, 0xEAAF, 0x57C3, 0xE4EF, 0x57C7, 0xE9B9, 0x57C8, 0xF1D8, 0x57CB, 0xD8D8, 0x57CE, 0xE0F2, 0x57DF, 0xE6B4, 0x57E0, 0xDCFC, 0x57F0, 0xF3F1, 0x57F4, 0xE3D0, 0x57F7, 0xF2FB, 0x57F9, 0xDBC6, 0x57FA, 0xD0F1, 0x57FC, 0xD0F2, 0x5800, 0xCFDC, 0x5802, 0xD3D1, 0x5805, 0xCCB1, 0x5806, 0xF7D8, 0x5808, 0xCBA8, 0x5809, 0xEBBC, 0x580A, 0xE4BE, 0x581E, 0xF4DC, 0x5821, 0xDCC2, 0x5824, 0xF0A7, 0x5827, 0xE6C0, 0x582A, 0xCAED, 0x582F, 0xE8EB, 0x5830, 0xE5E8, 0x5831, 0xDCC3, 0x5834, 0xEDDE, 0x5835, 0xD3F2, 0x583A, 0xCCF7, 0x584A, 0xCED4, 0x584B, 0xE7AB, 0x584F, 0xCBC3, 0x5851, 0xE1B1, 0x5854, 0xF7B2, 0x5857, 0xD3F3, 0x5858, 0xD3D2, 0x585A, 0xF5C0, 0x585E, 0xDFDD, 0x5861, 0xEEF3, 0x5862, 0xE7F1, 0x5864, 0xFDB4, 0x5875, 0xF2C8, 0x5879, 0xF3D2, 0x587C, 0xEEF4, 0x587E, 0xE2D3, 0x5883, 0xCCD1, 0x5885, 0xDFEA, 0x5889, 0xE9BA, 0x5893, 0xD9D7, 0x589C, 0xF5CD, 0x589E, 0xF1F2, 0x589F, 0xFAC7, 0x58A8, 0xD9F8, 0x58A9, 0xD4C2, 0x58AE, 0xF6E5, 0x58B3, 0xDDC5, 0x58BA, 0xE7F2, 0x58BB, 0xEDDF, 0x58BE, 0xCACB, 0x58C1, 0xDBFA, 0x58C5, 0xE8B5, 0x58C7, 0xD3A6, 0x58CE, 0xFDB5, 0x58D1, 0xF9C9, 0x58D3, 0xE4E2, 0x58D5, 0xFBBD, 0x58D8, 0xD7A4, 0x58D9, 0xCEC5, 0x58DE, 0xCED5, 0x58DF, 0xD6E6, 0x58E4, 0xE5BD, 0x58EB, 0xDECD, 0x58EC, 0xECF3, 0x58EF, 0xEDE0, 0x58F9, 0xECEC, 0x58FA, 0xFBBE, 0x58FB, 0xDFEB, 0x58FD, 0xE1F8, 0x590F, 0xF9BE, 0x5914, 0xD0F3, 0x5915, 0xE0AA, 0x5916, 0xE8E2, 0x5919, 0xE2D4, 0x591A, 0xD2FD, 0x591C, 0xE5A8, 0x5922, 0xD9D3, 0x5927, 0xD3DE, 0x5929, 0xF4B8, 0x592A, 0xF7BC, 0x592B, 0xDCFD, 0x592D, 0xE8EC, 0x592E, 0xE4E7, 0x5931, 0xE3F7, 0x5937, 0xECA8, 0x593E, 0xFAF1, 0x5944, 0xE5F2, 0x5947, 0xD0F4, 0x5948, 0xD2AF, 0x5949, 0xDCE5, 0x594E, 0xD0A5, 0x594F, 0xF1B4, 0x5950, 0xFCB1, 0x5951, 0xCCF8, 0x5954, 0xDDC6, 0x5955, 0xFAD1, 0x5957, 0xF7DF, 0x595A, 0xFAA8, 0x5960, 0xEEF5, 0x5962, 0xDECE, 0x5967, 0xE7F3, 0x596A, 0xF7AC, 0x596B, 0xEBC4, 0x596C, 0xEDE1, 0x596D, 0xE0AB, 0x596E, 0xDDC7, 0x5973, 0xD2B3, 0x5974, 0xD2BF, 0x5978, 0xCACC, 0x597D, 0xFBBF, 0x5982, 0xE5FD, 0x5983, 0xDDE5, 0x5984, 0xD8CD, 0x598A, 0xECF4, 0x5993, 0xD0F5, 0x5996, 0xE8ED, 0x5997, 0xD0D2, 0x5999, 0xD9D8, 0x59A5, 0xF6E6, 0x59A8, 0xDBAA, 0x59AC, 0xF7E0, 0x59B9, 0xD8D9, 0x59BB, 0xF4A3, 0x59BE, 0xF4DD, 0x59C3, 0xEFD1, 0x59C6, 0xD9B5, 0x59C9, 0xEDAB, 0x59CB, 0xE3B7, 0x59D0, 0xEEBB, 0x59D1, 0xCDB4, 0x59D3, 0xE0F3, 0x59D4, 0xEACD, 0x59D9, 0xECF5, 0x59DA, 0xE8EE, 0x59DC, 0xCBA9, 0x59DD, 0xF1AF, 0x59E6, 0xCACD, 0x59E8, 0xECA9, 0x59EA, 0xF2EB, 0x59EC, 0xFDEF, 0x59EE, 0xF9F3, 0x59F8, 0xE6C1, 0x59FB, 0xECD8, 0x59FF, 0xEDAC, 0x5A01, 0xEACE, 0x5A03, 0xE8DF, 0x5A11, 0xDECF, 0x5A18, 0xD2A6, 0x5A1B, 0xE7F4, 0x5A1C, 0xD1D6, 0x5A1F, 0xE6C2, 0x5A20, 0xE3E3, 0x5A25, 0xE4B0, 0x5A29, 0xD8B4, 0x5A36, 0xF6A5, 0x5A3C, 0xF3DE, 0x5A41, 0xD7A5, 0x5A46, 0xF7E8, 0x5A49, 0xE8C6, 0x5A5A, 0xFBE6, 0x5A62, 0xDDE6, 0x5A66, 0xDCFE, 0x5A92, 0xD8DA, 0x5A9A, 0xDAAC, 0x5A9B, 0xEAB0, 0x5AA4, 0xE3B8, 0x5AC1, 0xCAAA, 0x5AC2, 0xE1F9, 0x5AC4, 0xEAB1, 0x5AC9, 0xF2EC, 0x5ACC, 0xFAEE, 0x5AE1, 0xEED5, 0x5AE6, 0xF9F4, 0x5AE9, 0xD2EC, 0x5B05, 0xFBFB, 0x5B09, 0xFDF0, 0x5B0B, 0xE0BD, 0x5B0C, 0xCEE3, 0x5B16, 0xF8C6, 0x5B2A, 0xDEAE, 0x5B40, 0xDFC5, 0x5B43, 0xE5BE, 0x5B50, 0xEDAD, 0x5B51, 0xFAEA, 0x5B54, 0xCDEE, 0x5B55, 0xEDA6, 0x5B57, 0xEDAE, 0x5B58, 0xF0ED, 0x5B5A, 0xDDA1, 0x5B5C, 0xEDAF, 0x5B5D, 0xFCF8, 0x5B5F, 0xD8EB, 0x5B63, 0xCCF9, 0x5B64, 0xCDB5, 0x5B69, 0xFAA9, 0x5B6B, 0xE1DD, 0x5B70, 0xE2D5, 0x5B71, 0xEDCF, 0x5B75, 0xDDA2, 0x5B78, 0xF9CA, 0x5B7A, 0xEAE8, 0x5B7C, 0xE5ED, 0x5B85, 0xD3EB, 0x5B87, 0xE9D4, 0x5B88, 0xE1FA, 0x5B89, 0xE4CC, 0x5B8B, 0xE1E4, 0x5B8C, 0xE8C7, 0x5B8F, 0xCEDB, 0x5B93, 0xDCD5, 0x5B95, 0xF7B5, 0x5B96, 0xFCF3, 0x5B97, 0xF0F3, 0x5B98, 0xCEAF, 0x5B99, 0xF1B5, 0x5B9A, 0xEFD2, 0x5B9B, 0xE8C8, 0x5B9C, 0xEBF1, 0x5BA2, 0xCBD4, 0x5BA3, 0xE0BE, 0x5BA4, 0xE3F8, 0x5BA5, 0xEAE9, 0x5BA6, 0xFCB2, 0x5BAC, 0xE0F4, 0x5BAE, 0xCFE0, 0x5BB0, 0xEEA5, 0x5BB3, 0xFAAA, 0x5BB4, 0xE6C3, 0x5BB5, 0xE1B2, 0x5BB6, 0xCAAB, 0x5BB8, 0xE3E4, 0x5BB9, 0xE9BB, 0x5BBF, 0xE2D6, 0x5BC0, 0xF3F2, 0x5BC2, 0xEED6, 0x5BC3, 0xEAB2, 0x5BC4, 0xD0F6, 0x5BC5, 0xECD9, 0x5BC6, 0xDACB, 0x5BC7, 0xCFA8, 0x5BCC, 0xDDA3, 0x5BD0, 0xD8DB, 0x5BD2, 0xF9CE, 0x5BD3, 0xE9D5, 0x5BD4, 0xE3D1, 0x5BD7, 0xD2BC, 0x5BDE, 0xD8AC, 0x5BDF, 0xF3CC, 0x5BE1, 0xCDFB, 0x5BE2, 0xF6D6, 0x5BE4, 0xE7F5, 0x5BE5, 0xE8EF, 0x5BE6, 0xE3F9, 0x5BE7, 0xD2BB, 0x5BE8, 0xF3F3, 0x5BE9, 0xE3FB, 0x5BEB, 0xDED0, 0x5BEC, 0xCEB0, 0x5BEE, 0xD6F7, 0x5BEF, 0xF1D9, 0x5BF5, 0xF5C1, 0x5BF6, 0xDCC4, 0x5BF8, 0xF5BB, 0x5BFA, 0xDED1, 0x5C01, 0xDCE6, 0x5C04, 0xDED2, 0x5C07, 0xEDE2, 0x5C08, 0xEEF6, 0x5C09, 0xEACF, 0x5C0A, 0xF0EE, 0x5C0B, 0xE3FC, 0x5C0D, 0xD3DF, 0x5C0E, 0xD3F4, 0x5C0F, 0xE1B3, 0x5C11, 0xE1B4, 0x5C16, 0xF4D3, 0x5C19, 0xDFC6, 0x5C24, 0xE9D6, 0x5C28, 0xDBAB, 0x5C31, 0xF6A6, 0x5C38, 0xE3B9, 0x5C39, 0xEBC5, 0x5C3A, 0xF4A9, 0x5C3B, 0xCDB6, 0x5C3C, 0xD2F9, 0x5C3E, 0xDAAD, 0x5C3F, 0xD2E3, 0x5C40, 0xCFD1, 0x5C45, 0xCBDC, 0x5C46, 0xCCFA, 0x5C48, 0xCFDD, 0x5C4B, 0xE8A9, 0x5C4D, 0xE3BB, 0x5C4E, 0xE3BA, 0x5C51, 0xE0DA, 0x5C55, 0xEEF7, 0x5C5B, 0xDCB3, 0x5C60, 0xD3F5, 0x5C62, 0xD7A6, 0x5C64, 0xF6B5, 0x5C65, 0xD7DB, 0x5C6C, 0xE1D5, 0x5C6F, 0xD4EA, 0x5C71, 0xDFA3, 0x5C79, 0xFDDF, 0x5C90, 0xD0F7, 0x5C91, 0xEDD4, 0x5CA1, 0xCBAA, 0x5CA9, 0xE4DB, 0x5CAB, 0xE1FB, 0x5CAC, 0xCBA2, 0x5CB1, 0xD3E0, 0x5CB3, 0xE4BF, 0x5CB5, 0xFBC0, 0x5CB7, 0xDABE, 0x5CB8, 0xE4CD, 0x5CBA, 0xD6B9, 0x5CBE, 0xEFC0, 0x5CC0, 0xE1FC, 0x5CD9, 0xF6B9, 0x5CE0, 0xDFC7, 0x5CE8, 0xE4B1, 0x5CEF, 0xDCE7, 0x5CF0, 0xDCE8, 0x5CF4, 0xFAD6, 0x5CF6, 0xD3F6, 0x5CFB, 0xF1DA, 0x5CFD, 0xFAF2, 0x5D07, 0xE2FD, 0x5D0D, 0xD5CF, 0x5D0E, 0xD0F8, 0x5D11, 0xCDDF, 0x5D14, 0xF5CB, 0x5D16, 0xE4F0, 0x5D17, 0xCBAB, 0x5D19, 0xD7C4, 0x5D27, 0xE2FE, 0x5D29, 0xDDDA, 0x5D4B, 0xDAAE, 0x5D4C, 0xCAEE, 0x5D50, 0xD5B9, 0x5D69, 0xE3A1, 0x5D6C, 0xE8E3, 0x5D6F, 0xF3AB, 0x5D87, 0xCFA9, 0x5D8B, 0xD3F7, 0x5D9D, 0xD4F1, 0x5DA0, 0xCEE4, 0x5DA2, 0xE8F2, 0x5DAA, 0xE5F5, 0x5DB8, 0xE7AE, 0x5DBA, 0xD6BA, 0x5DBC, 0xDFEC, 0x5DBD, 0xE4C0, 0x5DCD, 0xE8E4, 0x5DD2, 0xD8B5, 0x5DD6, 0xE4DC, 0x5DDD, 0xF4B9, 0x5DDE, 0xF1B6, 0x5DE1, 0xE2DE, 0x5DE2, 0xE1B5, 0x5DE5, 0xCDEF, 0x5DE6, 0xF1A7, 0x5DE7, 0xCEE5, 0x5DE8, 0xCBDD, 0x5DEB, 0xD9E3, 0x5DEE, 0xF3AC, 0x5DF1, 0xD0F9, 0x5DF2, 0xECAB, 0x5DF3, 0xDED3, 0x5DF4, 0xF7E9, 0x5DF7, 0xF9F5, 0x5DFD, 0xE1DE, 0x5DFE, 0xCBEE, 0x5E02, 0xE3BC, 0x5E03, 0xF8D6, 0x5E06, 0xDBEE, 0x5E0C, 0xFDF1, 0x5E11, 0xF7B6, 0x5E16, 0xF4DE, 0x5E19, 0xF2ED, 0x5E1B, 0xDBD9, 0x5E1D, 0xF0A8, 0x5E25, 0xE1FD, 0x5E2B, 0xDED4, 0x5E2D, 0xE0AC, 0x5E33, 0xEDE3, 0x5E36, 0xD3E1, 0x5E38, 0xDFC8, 0x5E3D, 0xD9B6, 0x5E3F, 0xFDAC, 0x5E40, 0xEFD3, 0x5E44, 0xE4C1, 0x5E45, 0xF8EB, 0x5E47, 0xDBAC, 0x5E4C, 0xFCC6, 0x5E55, 0xD8AD, 0x5E5F, 0xF6BA, 0x5E61, 0xDBDF, 0x5E62, 0xD3D3, 0x5E63, 0xF8C7, 0x5E72, 0xCACE, 0x5E73, 0xF8C1, 0x5E74, 0xD2B4, 0x5E77, 0xDCB4, 0x5E78, 0xFAB9, 0x5E79, 0xCACF, 0x5E7B, 0xFCB3, 0x5E7C, 0xEAEA, 0x5E7D, 0xEAEB, 0x5E7E, 0xD0FA, 0x5E84, 0xEDE4, 0x5E87, 0xDDE7, 0x5E8A, 0xDFC9, 0x5E8F, 0xDFED, 0x5E95, 0xEEBC, 0x5E97, 0xEFC1, 0x5E9A, 0xCCD2, 0x5E9C, 0xDDA4, 0x5EA0, 0xDFCA, 0x5EA6, 0xD3F8, 0x5EA7, 0xF1A8, 0x5EAB, 0xCDB7, 0x5EAD, 0xEFD4, 0x5EB5, 0xE4DD, 0x5EB6, 0xDFEE, 0x5EB7, 0xCBAC, 0x5EB8, 0xE9BC, 0x5EBE, 0xEAEC, 0x5EC2, 0xDFCB, 0x5EC8, 0xF9BF, 0x5EC9, 0xD6AF, 0x5ECA, 0xD5C6, 0x5ED0, 0xCFAA, 0x5ED3, 0xCEA9, 0x5ED6, 0xD6F8, 0x5EDA, 0xF1B7, 0x5EDB, 0xEEF8, 0x5EDF, 0xD9D9, 0x5EE0, 0xF3DF, 0x5EE2, 0xF8C8, 0x5EE3, 0xCEC6, 0x5EEC, 0xD5E6, 0x5EF3, 0xF4E6, 0x5EF6, 0xE6C5, 0x5EF7, 0xEFD5, 0x5EFA, 0xCBEF, 0x5EFB, 0xFCDF, 0x5F01, 0xDCA7, 0x5F04, 0xD6E7, 0x5F0A, 0xF8C9, 0x5F0F, 0xE3D2, 0x5F11, 0xE3BD, 0x5F13, 0xCFE1, 0x5F14, 0xF0C0, 0x5F15, 0xECDA, 0x5F17, 0xDDD7, 0x5F18, 0xFBF0, 0x5F1B, 0xECAC, 0x5F1F, 0xF0A9, 0x5F26, 0xFAD7, 0x5F27, 0xFBC1, 0x5F29, 0xD2C0, 0x5F31, 0xE5B0, 0x5F35, 0xEDE5, 0x5F3A, 0xCBAD, 0x5F3C, 0xF9B0, 0x5F48, 0xF7A5, 0x5F4A, 0xCBAE, 0x5F4C, 0xDAAF, 0x5F4E, 0xD8B6, 0x5F56, 0xD3A7, 0x5F57, 0xFBB2, 0x5F59, 0xFDC4, 0x5F5B, 0xECAD, 0x5F62, 0xFBA1, 0x5F66, 0xE5E9, 0x5F67, 0xE9EE, 0x5F69, 0xF3F4, 0x5F6A, 0xF8F3, 0x5F6B, 0xF0C1, 0x5F6C, 0xDEAF, 0x5F6D, 0xF8B0, 0x5F70, 0xF3E0, 0x5F71, 0xE7AF, 0x5F77, 0xDBAD, 0x5F79, 0xE6B5, 0x5F7C, 0xF9A8, 0x5F7F, 0xDDD8, 0x5F80, 0xE8D9, 0x5F81, 0xEFD6, 0x5F85, 0xD3E2, 0x5F87, 0xE2DF, 0x5F8A, 0xFCE0, 0x5F8B, 0xD7C8, 0x5F8C, 0xFDAD, 0x5F90, 0xDFEF, 0x5F91, 0xCCD3, 0x5F92, 0xD3F9, 0x5F97, 0xD4F0, 0x5F98, 0xDBC7, 0x5F99, 0xDED5, 0x5F9E, 0xF0F4, 0x5FA0, 0xD5D0, 0x5FA1, 0xE5D9, 0x5FA8, 0xFCC7, 0x5FA9, 0xDCD6, 0x5FAA, 0xE2E0, 0x5FAE, 0xDAB0, 0x5FB5, 0xF3A3, 0x5FB7, 0xD3EC, 0x5FB9, 0xF4CB, 0x5FBD, 0xFDC5, 0x5FC3, 0xE3FD, 0x5FC5, 0xF9B1, 0x5FCC, 0xD0FB, 0x5FCD, 0xECDB, 0x5FD6, 0xF5BC, 0x5FD7, 0xF2A4, 0x5FD8, 0xD8CE, 0x5FD9, 0xD8CF, 0x5FE0, 0xF5F7, 0x5FEB, 0xF6E1, 0x5FF5, 0xD2B7, 0x5FFD, 0xFBEC, 0x5FFF, 0xDDC8, 0x600F, 0xE4E8, 0x6012, 0xD2C1, 0x6016, 0xF8D7, 0x601C, 0xD6BB, 0x601D, 0xDED6, 0x6020, 0xF7BD, 0x6021, 0xECAE, 0x6025, 0xD0E1, 0x6027, 0xE0F5, 0x6028, 0xEAB3, 0x602A, 0xCED6, 0x602F, 0xCCA5, 0x6041, 0xECF6, 0x6042, 0xE2E1, 0x6043, 0xE3BE, 0x604D, 0xFCC8, 0x6050, 0xCDF0, 0x6052, 0xF9F6, 0x6055, 0xDFF0, 0x6059, 0xE5BF, 0x605D, 0xCEBF, 0x6062, 0xFCE1, 0x6063, 0xEDB0, 0x6064, 0xFDD1, 0x6065, 0xF6BB, 0x6068, 0xF9CF, 0x6069, 0xEBDA, 0x606A, 0xCAC1, 0x606C, 0xD2B8, 0x606D, 0xCDF1, 0x606F, 0xE3D3, 0x6070, 0xFDE6, 0x6085, 0xE6ED, 0x6089, 0xE3FA, 0x608C, 0xF0AA, 0x608D, 0xF9D0, 0x6094, 0xFCE2, 0x6096, 0xF8A7, 0x609A, 0xE1E5, 0x609B, 0xEEF9, 0x609F, 0xE7F6, 0x60A0, 0xEAED, 0x60A3, 0xFCB4, 0x60A4, 0xF5C2, 0x60A7, 0xD7DC, 0x60B0, 0xF0F5, 0x60B2, 0xDDE8, 0x60B3, 0xD3ED, 0x60B4, 0xF5FC, 0x60B6, 0xDABF, 0x60B8, 0xCCFB, 0x60BC, 0xD3FA, 0x60BD, 0xF4A4, 0x60C5, 0xEFD7, 0x60C7, 0xD4C3, 0x60D1, 0xFBE3, 0x60DA, 0xFBED, 0x60DC, 0xE0AD, 0x60DF, 0xEAEE, 0x60E0, 0xFBB3, 0x60E1, 0xE4C2, 0x60F0, 0xF6E7, 0x60F1, 0xD2DD, 0x60F3, 0xDFCC, 0x60F6, 0xFCC9, 0x60F9, 0xE5A9, 0x60FA, 0xE0F6, 0x60FB, 0xF6B3, 0x6101, 0xE1FE, 0x6106, 0xCBF0, 0x6108, 0xEAEF, 0x6109, 0xEAF0, 0x610D, 0xDAC0, 0x610E, 0xF8B4, 0x610F, 0xEBF2, 0x6115, 0xE4C3, 0x611A, 0xE9D7, 0x611B, 0xE4F1, 0x611F, 0xCAEF, 0x6127, 0xCED7, 0x6130, 0xFCCA, 0x6134, 0xF3E1, 0x6137, 0xCBC4, 0x613C, 0xE3E5, 0x613E, 0xCBC5, 0x613F, 0xEAB4, 0x6142, 0xE9BD, 0x6144, 0xD7C9, 0x6147, 0xEBDB, 0x6148, 0xEDB1, 0x614A, 0xCCC3, 0x614B, 0xF7BE, 0x614C, 0xFCCB, 0x6153, 0xF8F4, 0x6155, 0xD9B7, 0x6158, 0xF3D3, 0x6159, 0xF3D4, 0x615D, 0xF7E4, 0x615F, 0xF7D1, 0x6162, 0xD8B7, 0x6163, 0xCEB1, 0x6164, 0xCAC2, 0x6167, 0xFBB4, 0x6168, 0xCBC6, 0x616B, 0xF0F6, 0x616E, 0xD5E7, 0x6170, 0xEAD0, 0x6176, 0xCCD4, 0x6177, 0xCBAF, 0x617D, 0xF4AA, 0x617E, 0xE9AF, 0x6181, 0xF5C3, 0x6182, 0xE9D8, 0x618A, 0xDDE9, 0x618E, 0xF1F3, 0x6190, 0xD5FB, 0x6191, 0xDEBB, 0x6194, 0xF4FB, 0x6198, 0xFDF3, 0x6199, 0xFDF2, 0x619A, 0xF7A6, 0x61A4, 0xDDC9, 0x61A7, 0xD4D3, 0x61A9, 0xCCA8, 0x61AB, 0xDAC1, 0x61AC, 0xCCD5, 0x61AE, 0xD9E4, 0x61B2, 0xFACA, 0x61B6, 0xE5E3, 0x61BA, 0xD3BC, 0x61BE, 0xCAF0, 0x61C3, 0xD0C4, 0x61C7, 0xCAD0, 0x61C8, 0xFAAB, 0x61C9, 0xEBEB, 0x61CA, 0xE7F8, 0x61CB, 0xD9E5, 0x61E6, 0xD1D7, 0x61F2, 0xF3A4, 0x61F6, 0xD4FB, 0x61F7, 0xFCE3, 0x61F8, 0xFAD8, 0x61FA, 0xF3D5, 0x61FC, 0xCFAB, 0x61FF, 0xEBF3, 0x6200, 0xD5FC, 0x6207, 0xD3D4, 0x6208, 0xCDFC, 0x620A, 0xD9E6, 0x620C, 0xE2F9, 0x620D, 0xE2A1, 0x620E, 0xEBD4, 0x6210, 0xE0F7, 0x6211, 0xE4B2, 0x6212, 0xCCFC, 0x6216, 0xFBE4, 0x621A, 0xF4AB, 0x621F, 0xD0BD, 0x6221, 0xCAF1, 0x622A, 0xEFB8, 0x622E, 0xD7C0, 0x6230, 0xEEFA, 0x6231, 0xFDF4, 0x6234, 0xD3E3, 0x6236, 0xFBC2, 0x623E, 0xD5E8, 0x623F, 0xDBAE, 0x6240, 0xE1B6, 0x6241, 0xF8B7, 0x6247, 0xE0BF, 0x6248, 0xFBC3, 0x6249, 0xDDEA, 0x624B, 0xE2A2, 0x624D, 0xEEA6, 0x6253, 0xF6E8, 0x6258, 0xF6F5, 0x626E, 0xDDCA, 0x6271, 0xD0E2, 0x6276, 0xDDA6, 0x6279, 0xDDEB, 0x627C, 0xE4F9, 0x627F, 0xE3AF, 0x6280, 0xD0FC, 0x6284, 0xF4FC, 0x6289, 0xCCBC, 0x628A, 0xF7EA, 0x6291, 0xE5E4, 0x6292, 0xDFF1, 0x6295, 0xF7E1, 0x6297, 0xF9F7, 0x6298, 0xEFB9, 0x629B, 0xF8D8, 0x62AB, 0xF9A9, 0x62B1, 0xF8D9, 0x62B5, 0xEEBD, 0x62B9, 0xD8C6, 0x62BC, 0xE4E3, 0x62BD, 0xF5CE, 0x62C2, 0xDDD9, 0x62C7, 0xD9E7, 0x62C8, 0xD2B9, 0x62C9, 0xD5C3, 0x62CC, 0xDAE5, 0x62CD, 0xDAD0, 0x62CF, 0xD1D9, 0x62D0, 0xCED8, 0x62D2, 0xCBDE, 0x62D3, 0xF4AC, 0x62D4, 0xDAFB, 0x62D6, 0xF6E9, 0x62D7, 0xE8F3, 0x62D8, 0xCFAC, 0x62D9, 0xF0F0, 0x62DB, 0xF4FD, 0x62DC, 0xDBC8, 0x62EC, 0xCEC0, 0x62ED, 0xE3D4, 0x62EE, 0xD1CF, 0x62EF, 0xF1F5, 0x62F1, 0xCDF2, 0x62F3, 0xCFEB, 0x62F7, 0xCDB8, 0x62FE, 0xE3A6, 0x62FF, 0xD1DA, 0x6301, 0xF2A5, 0x6307, 0xF2A6, 0x6309, 0xE4CE, 0x6311, 0xD3FB, 0x632B, 0xF1A9, 0x632F, 0xF2C9, 0x633A, 0xEFD8, 0x633B, 0xE6C9, 0x633D, 0xD8B8, 0x633E, 0xFAF3, 0x6349, 0xF3B5, 0x634C, 0xF8A4, 0x634F, 0xD1F3, 0x6350, 0xE6C8, 0x6355, 0xF8DA, 0x6367, 0xDCE9, 0x6368, 0xDED7, 0x636E, 0xCBDF, 0x6372, 0xCFEC, 0x6377, 0xF4DF, 0x637A, 0xD1F4, 0x637B, 0xD2BA, 0x637F, 0xDFF2, 0x6383, 0xE1B7, 0x6388, 0xE2A3, 0x6389, 0xD3FC, 0x638C, 0xEDE6, 0x6392, 0xDBC9, 0x6396, 0xE4FA, 0x6398, 0xCFDE, 0x639B, 0xCED0, 0x63A0, 0xD5D3, 0x63A1, 0xF3F5, 0x63A2, 0xF7AE, 0x63A5, 0xEFC8, 0x63A7, 0xCDF3, 0x63A8, 0xF5CF, 0x63A9, 0xE5F3, 0x63AA, 0xF0C2, 0x63C0, 0xCAD1, 0x63C4, 0xEAF1, 0x63C6, 0xD0A6, 0x63CF, 0xD9DA, 0x63D0, 0xF0AB, 0x63D6, 0xEBE7, 0x63DA, 0xE5C0, 0x63DB, 0xFCB5, 0x63E1, 0xE4C4, 0x63ED, 0xCCA9, 0x63EE, 0xFDC6, 0x63F4, 0xEAB5, 0x63F6, 0xE5AA, 0x63F7, 0xDFBA, 0x640D, 0xE1DF, 0x640F, 0xDAD1, 0x6414, 0xE1B8, 0x6416, 0xE8F4, 0x6417, 0xD3FD, 0x641C, 0xE2A4, 0x6422, 0xF2CA, 0x642C, 0xDAE6, 0x642D, 0xF7B3, 0x643A, 0xFDCD, 0x643E, 0xF3B6, 0x6458, 0xEED7, 0x6460, 0xF5C4, 0x6469, 0xD8A4, 0x646F, 0xF2A7, 0x6478, 0xD9B8, 0x6479, 0xD9B9, 0x647A, 0xEFC9, 0x6488, 0xD6CE, 0x6491, 0xF7CB, 0x6492, 0xDFAE, 0x6493, 0xE8F5, 0x649A, 0xD2B5, 0x649E, 0xD3D5, 0x64A4, 0xF4CC, 0x64A5, 0xDAFC, 0x64AB, 0xD9E8, 0x64AD, 0xF7EB, 0x64AE, 0xF5C9, 0x64B0, 0xF3BC, 0x64B2, 0xDAD2, 0x64BB, 0xD3B5, 0x64C1, 0xE8B6, 0x64C4, 0xD6CF, 0x64C5, 0xF4BA, 0x64C7, 0xF7C9, 0x64CA, 0xCCAA, 0x64CD, 0xF0C3, 0x64CE, 0xCCD6, 0x64D2, 0xD0D3, 0x64D4, 0xD3BD, 0x64D8, 0xDBFB, 0x64DA, 0xCBE0, 0x64E1, 0xD3E4, 0x64E2, 0xF6F7, 0x64E5, 0xD5BA, 0x64E6, 0xF3CD, 0x64E7, 0xCBE1, 0x64EC, 0xEBF4, 0x64F2, 0xF4AD, 0x64F4, 0xFCAA, 0x64FA, 0xF7EC, 0x64FE, 0xE8F6, 0x6500, 0xDAE7, 0x6504, 0xF7CC, 0x6518, 0xE5C1, 0x651D, 0xE0EE, 0x6523, 0xD5FD, 0x652A, 0xCEE6, 0x652B, 0xFCAB, 0x652C, 0xD5BB, 0x652F, 0xF2A8, 0x6536, 0xE2A5, 0x6537, 0xCDB9, 0x6538, 0xEAF2, 0x6539, 0xCBC7, 0x653B, 0xCDF4, 0x653E, 0xDBAF, 0x653F, 0xEFD9, 0x6545, 0xCDBA, 0x6548, 0xFCF9, 0x654D, 0xDFF3, 0x654E, 0xCEE7, 0x654F, 0xDAC2, 0x6551, 0xCFAD, 0x6556, 0xE7F9, 0x6557, 0xF8A8, 0x655E, 0xF3E2, 0x6562, 0xCAF2, 0x6563, 0xDFA4, 0x6566, 0xD4C4, 0x656C, 0xCCD7, 0x656D, 0xE5C2, 0x6572, 0xCDBB, 0x6574, 0xEFDA, 0x6575, 0xEED8, 0x6577, 0xDDA7, 0x6578, 0xE2A6, 0x657E, 0xE0C0, 0x6582, 0xD6B0, 0x6583, 0xF8CA, 0x6585, 0xFCFA, 0x6587, 0xD9FE, 0x658C, 0xDEB0, 0x6590, 0xDDEC, 0x6591, 0xDAE8, 0x6597, 0xD4E0, 0x6599, 0xD6F9, 0x659B, 0xCDD7, 0x659C, 0xDED8, 0x659F, 0xF2F8, 0x65A1, 0xE4D6, 0x65A4, 0xD0C5, 0x65A5, 0xF4AE, 0x65A7, 0xDDA8, 0x65AB, 0xEDC5, 0x65AC, 0xF3D6, 0x65AF, 0xDED9, 0x65B0, 0xE3E6, 0x65B7, 0xD3A8, 0x65B9, 0xDBB0, 0x65BC, 0xE5DA, 0x65BD, 0xE3BF, 0x65C1, 0xDBB1, 0x65C5, 0xD5E9, 0x65CB, 0xE0C1, 0x65CC, 0xEFDB, 0x65CF, 0xF0E9, 0x65D2, 0xD7B2, 0x65D7, 0xD0FD, 0x65E0, 0xD9E9, 0x65E3, 0xD0FE, 0x65E5, 0xECED, 0x65E6, 0xD3A9, 0x65E8, 0xF2A9, 0x65E9, 0xF0C4, 0x65EC, 0xE2E2, 0x65ED, 0xE9EF, 0x65F1, 0xF9D1, 0x65F4, 0xE9D9, 0x65FA, 0xE8DA, 0x65FB, 0xDAC3, 0x65FC, 0xDAC4, 0x65FD, 0xD4C5, 0x65FF, 0xE7FA, 0x6606, 0xCDE0, 0x6607, 0xE3B0, 0x6609, 0xDBB2, 0x660A, 0xFBC4, 0x660C, 0xF3E3, 0x660E, 0xD9A5, 0x660F, 0xFBE7, 0x6610, 0xDDCB, 0x6611, 0xD0D4, 0x6613, 0xE6B6, 0x6614, 0xE0AE, 0x6615, 0xFDDA, 0x661E, 0xDCB5, 0x661F, 0xE0F8, 0x6620, 0xE7B1, 0x6625, 0xF5F0, 0x6627, 0xD8DC, 0x6628, 0xEDC6, 0x662D, 0xE1B9, 0x662F, 0xE3C0, 0x6630, 0xF9C0, 0x6631, 0xE9F0, 0x6634, 0xD9DB, 0x6636, 0xF3E4, 0x663A, 0xDCB6, 0x663B, 0xE4E9, 0x6641, 0xF0C5, 0x6642, 0xE3C1, 0x6643, 0xFCCC, 0x6644, 0xFCCD, 0x6649, 0xF2CB, 0x664B, 0xF2CC, 0x664F, 0xE4CF, 0x6659, 0xF1DB, 0x665B, 0xFAD9, 0x665D, 0xF1B8, 0x665E, 0xFDF5, 0x665F, 0xE0F9, 0x6664, 0xE7FB, 0x6665, 0xFCB7, 0x6666, 0xFCE4, 0x6667, 0xFBC5, 0x6668, 0xE3E7, 0x6669, 0xD8B9, 0x666B, 0xF6F8, 0x666E, 0xDCC5, 0x666F, 0xCCD8, 0x6673, 0xE0AF, 0x6674, 0xF4E7, 0x6676, 0xEFDC, 0x6677, 0xCFFC, 0x6678, 0xEFDD, 0x667A, 0xF2AA, 0x6684, 0xFDBE, 0x6687, 0xCAAC, 0x6688, 0xFDBB, 0x6689, 0xFDC7, 0x668E, 0xE7B2, 0x6690, 0xEAD1, 0x6691, 0xDFF4, 0x6696, 0xD1EC, 0x6697, 0xE4DE, 0x6698, 0xE5C3, 0x669D, 0xD9A6, 0x66A0, 0xCDBC, 0x66A2, 0xF3E5, 0x66AB, 0xEDD5, 0x66AE, 0xD9BA, 0x66B2, 0xEDE7, 0x66B3, 0xFBB5, 0x66B4, 0xF8EC, 0x66B9, 0xE0E7, 0x66BB, 0xCCD9, 0x66BE, 0xD4C6, 0x66C4, 0xE7A5, 0x66C6, 0xD5F5, 0x66C7, 0xD3BE, 0x66C9, 0xFCFB, 0x66D6, 0xE4F2, 0x66D9, 0xDFF5, 0x66DC, 0xE8F8, 0x66DD, 0xF8ED, 0x66E0, 0xCEC7, 0x66E6, 0xFDF6, 0x66F0, 0xE8D8, 0x66F2, 0xCDD8, 0x66F3, 0xE7D6, 0x66F4, 0xCCDA, 0x66F7, 0xCAE3, 0x66F8, 0xDFF6, 0x66F9, 0xF0C7, 0x66FA, 0xF0C6, 0x66FC, 0xD8BA, 0x66FE, 0xF1F4, 0x66FF, 0xF4F0, 0x6700, 0xF5CC, 0x6703, 0xFCE5, 0x6708, 0xEAC5, 0x6709, 0xEAF3, 0x670B, 0xDDDB, 0x670D, 0xDCD7, 0x6714, 0xDEFD, 0x6715, 0xF2F9, 0x6717, 0xD5C7, 0x671B, 0xD8D0, 0x671D, 0xF0C8, 0x671E, 0xD1A1, 0x671F, 0xD1A2, 0x6726, 0xD9D4, 0x6727, 0xD6E8, 0x6728, 0xD9CA, 0x672A, 0xDAB1, 0x672B, 0xD8C7, 0x672C, 0xDCE2, 0x672D, 0xF3CE, 0x672E, 0xF5F4, 0x6731, 0xF1B9, 0x6734, 0xDAD3, 0x6736, 0xF6EA, 0x673A, 0xCFF5, 0x673D, 0xFDAE, 0x6746, 0xCAD2, 0x6749, 0xDFB4, 0x674E, 0xD7DD, 0x674F, 0xFABA, 0x6750, 0xEEA7, 0x6751, 0xF5BD, 0x6753, 0xF8F5, 0x6756, 0xEDE8, 0x675C, 0xD4E1, 0x675E, 0xD1A3, 0x675F, 0xE1D6, 0x676D, 0xF9F8, 0x676F, 0xDBCA, 0x6770, 0xCBF9, 0x6771, 0xD4D4, 0x6773, 0xD9DC, 0x6775, 0xEEBE, 0x6777, 0xF7ED, 0x677B, 0xD2EE, 0x677E, 0xE1E6, 0x677F, 0xF7F9, 0x6787, 0xDDED, 0x6789, 0xE8DB, 0x678B, 0xDBB3, 0x678F, 0xD1F7, 0x6790, 0xE0B0, 0x6793, 0xD4E2, 0x6795, 0xF6D7, 0x6797, 0xD7F9, 0x679A, 0xD8DD, 0x679C, 0xCDFD, 0x679D, 0xF2AB, 0x67AF, 0xCDBD, 0x67B0, 0xF8C2, 0x67B3, 0xF2AC, 0x67B6, 0xCAAD, 0x67B7, 0xCAAE, 0x67B8, 0xCFAE, 0x67BE, 0xE3C2, 0x67C4, 0xDCB7, 0x67CF, 0xDBDA, 0x67D0, 0xD9BB, 0x67D1, 0xCAF3, 0x67D2, 0xF6D3, 0x67D3, 0xE6F8, 0x67D4, 0xEAF5, 0x67DA, 0xEAF6, 0x67DD, 0xF6F9, 0x67E9, 0xCFAF, 0x67EC, 0xCAD3, 0x67EF, 0xCAAF, 0x67F0, 0xD2B0, 0x67F1, 0xF1BA, 0x67F3, 0xD7B3, 0x67F4, 0xE3C3, 0x67F5, 0xF3FD, 0x67F6, 0xDEDA, 0x67FB, 0xDEDB, 0x67FE, 0xEFDE, 0x6812, 0xE2E3, 0x6813, 0xEEFB, 0x6816, 0xDFF7, 0x6817, 0xD7CA, 0x6821, 0xCEE8, 0x6822, 0xDBDB, 0x682A, 0xF1BB, 0x682F, 0xE9F1, 0x6838, 0xFAB7, 0x6839, 0xD0C6, 0x683C, 0xCCAB, 0x683D, 0xEEA8, 0x6840, 0xCBFA, 0x6841, 0xF9F9, 0x6842, 0xCCFD, 0x6843, 0xD3FE, 0x6848, 0xE4D0, 0x684E, 0xF2EE, 0x6850, 0xD4D5, 0x6851, 0xDFCD, 0x6853, 0xFCB8, 0x6854, 0xD1D0, 0x686D, 0xF2CD, 0x6876, 0xF7D2, 0x687F, 0xCAD4, 0x6881, 0xD5D9, 0x6885, 0xD8DE, 0x688F, 0xCDD9, 0x6893, 0xEEA9, 0x6894, 0xF6BC, 0x6897, 0xCCDB, 0x689D, 0xF0C9, 0x689F, 0xFCFC, 0x68A1, 0xE8C9, 0x68A2, 0xF4FE, 0x68A7, 0xE7FC, 0x68A8, 0xD7DE, 0x68AD, 0xDEDC, 0x68AF, 0xF0AC, 0x68B0, 0xCCFE, 0x68B1, 0xCDE1, 0x68B3, 0xE1BA, 0x68B5, 0xDBEF, 0x68B6, 0xDAB2, 0x68C4, 0xD1A5, 0x68C5, 0xDCB8, 0x68C9, 0xD8F6, 0x68CB, 0xD1A4, 0x68CD, 0xCDE2, 0x68D2, 0xDCEA, 0x68D5, 0xF0F7, 0x68D7, 0xF0CA, 0x68D8, 0xD0BE, 0x68DA, 0xDDDC, 0x68DF, 0xD4D6, 0x68E0, 0xD3D6, 0x68E7, 0xEDD0, 0x68E8, 0xCDA1, 0x68EE, 0xDFB5, 0x68F2, 0xDFF8, 0x68F9, 0xD4A1, 0x68FA, 0xCEB2, 0x6900, 0xE8CA, 0x6905, 0xEBF5, 0x690D, 0xE3D5, 0x690E, 0xF5D0, 0x6912, 0xF5A1, 0x6927, 0xD9A7, 0x6930, 0xE5AB, 0x693D, 0xE6CB, 0x693F, 0xF5F1, 0x694A, 0xE5C5, 0x6953, 0xF9A3, 0x6954, 0xE0DB, 0x6955, 0xF6EB, 0x6957, 0xCBF1, 0x6959, 0xD9EA, 0x695A, 0xF5A2, 0x695E, 0xD7D1, 0x6960, 0xD1F8, 0x6961, 0xEAF8, 0x6962, 0xEAF9, 0x6963, 0xDAB3, 0x6968, 0xEFDF, 0x696B, 0xF1EF, 0x696D, 0xE5F6, 0x696E, 0xEEBF, 0x696F, 0xE2E4, 0x6975, 0xD0BF, 0x6977, 0xFAAC, 0x6978, 0xF5D1, 0x6979, 0xE7B3, 0x6995, 0xE9BE, 0x699B, 0xF2CE, 0x699C, 0xDBB4, 0x69A5, 0xFCCE, 0x69A7, 0xDDEE, 0x69AE, 0xE7B4, 0x69B4, 0xD7B4, 0x69BB, 0xF7B4, 0x69C1, 0xCDBE, 0x69C3, 0xDAE9, 0x69CB, 0xCFB0, 0x69CC, 0xF7D9, 0x69CD, 0xF3E6, 0x69D0, 0xCED9, 0x69E8, 0xCEAA, 0x69EA, 0xCBC8, 0x69FB, 0xD0A7, 0x69FD, 0xF0CB, 0x69FF, 0xD0C7, 0x6A02, 0xE4C5, 0x6A0A, 0xDBE0, 0x6A11, 0xD5DA, 0x6A13, 0xD7A7, 0x6A17, 0xEEC0, 0x6A19, 0xF8F6, 0x6A1E, 0xF5D2, 0x6A1F, 0xEDE9, 0x6A21, 0xD9BC, 0x6A23, 0xE5C6, 0x6A35, 0xF5A3, 0x6A38, 0xDAD4, 0x6A39, 0xE2A7, 0x6A3A, 0xFBFC, 0x6A3D, 0xF1DC, 0x6A44, 0xCAF4, 0x6A48, 0xE8FA, 0x6A4B, 0xCEE9, 0x6A52, 0xE9F8, 0x6A53, 0xE2E5, 0x6A58, 0xD0B9, 0x6A59, 0xD4F2, 0x6A5F, 0xD1A6, 0x6A61, 0xDFCE, 0x6A6B, 0xFCF4, 0x6A80, 0xD3AA, 0x6A84, 0xCCAC, 0x6A89, 0xEFE0, 0x6A8D, 0xE5E5, 0x6A8E, 0xD0D5, 0x6A97, 0xDBFC, 0x6A9C, 0xFCE6, 0x6AA2, 0xCBFE, 0x6AA3, 0xEDEA, 0x6AB3, 0xDEB1, 0x6ABB, 0xF9E3, 0x6AC2, 0xD4A2, 0x6AC3, 0xCFF6, 0x6AD3, 0xD6D0, 0x6ADA, 0xD5EA, 0x6ADB, 0xF1EE, 0x6AF6, 0xFACB, 0x6AFB, 0xE5A1, 0x6B04, 0xD5B1, 0x6B0A, 0xCFED, 0x6B0C, 0xEDEB, 0x6B12, 0xD5B2, 0x6B16, 0xD5BC, 0x6B20, 0xFDE2, 0x6B21, 0xF3AD, 0x6B23, 0xFDDB, 0x6B32, 0xE9B0, 0x6B3A, 0xD1A7, 0x6B3D, 0xFDE3, 0x6B3E, 0xCEB3, 0x6B46, 0xFDE4, 0x6B47, 0xFACE, 0x6B4C, 0xCAB0, 0x6B4E, 0xF7A7, 0x6B50, 0xCFB1, 0x6B5F, 0xE6A2, 0x6B61, 0xFCB6, 0x6B62, 0xF2AD, 0x6B63, 0xEFE1, 0x6B64, 0xF3AE, 0x6B65, 0xDCC6, 0x6B66, 0xD9EB, 0x6B6A, 0xE8E0, 0x6B72, 0xE1A8, 0x6B77, 0xD5F6, 0x6B78, 0xCFFD, 0x6B7B, 0xDEDD, 0x6B7F, 0xD9D1, 0x6B83, 0xE4EA, 0x6B84, 0xF2CF, 0x6B86, 0xF7BF, 0x6B89, 0xE2E6, 0x6B8A, 0xE2A8, 0x6B96, 0xE3D6, 0x6B98, 0xEDD1, 0x6B9E, 0xE9F9, 0x6BAE, 0xD6B1, 0x6BAF, 0xDEB2, 0x6BB2, 0xE0E8, 0x6BB5, 0xD3AB, 0x6BB7, 0xEBDC, 0x6BBA, 0xDFAF, 0x6BBC, 0xCAC3, 0x6BBF, 0xEEFC, 0x6BC1, 0xFDC3, 0x6BC5, 0xEBF6, 0x6BC6, 0xCFB2, 0x6BCB, 0xD9EC, 0x6BCD, 0xD9BD, 0x6BCF, 0xD8DF, 0x6BD2, 0xD4B8, 0x6BD3, 0xEBBE, 0x6BD4, 0xDDEF, 0x6BD6, 0xDDF0, 0x6BD7, 0xDDF1, 0x6BD8, 0xDDF2, 0x6BDB, 0xD9BE, 0x6BEB, 0xFBC6, 0x6BEC, 0xCFB3, 0x6C08, 0xEEFD, 0x6C0F, 0xE4AB, 0x6C11, 0xDAC5, 0x6C13, 0xD8EC, 0x6C23, 0xD1A8, 0x6C34, 0xE2A9, 0x6C37, 0xDEBC, 0x6C38, 0xE7B5, 0x6C3E, 0xDBF0, 0x6C40, 0xEFE2, 0x6C41, 0xF1F0, 0x6C42, 0xCFB4, 0x6C4E, 0xDBF1, 0x6C50, 0xE0B1, 0x6C55, 0xDFA5, 0x6C57, 0xF9D2, 0x6C5A, 0xE7FD, 0x6C5D, 0xE6A3, 0x6C5E, 0xFBF1, 0x6C5F, 0xCBB0, 0x6C60, 0xF2AE, 0x6C68, 0xCDE7, 0x6C6A, 0xE8DC, 0x6C6D, 0xE7D7, 0x6C70, 0xF7C0, 0x6C72, 0xD0E3, 0x6C76, 0xDAA1, 0x6C7A, 0xCCBD, 0x6C7D, 0xD1A9, 0x6C7E, 0xDDCC, 0x6C81, 0xE3FE, 0x6C82, 0xD1AA, 0x6C83, 0xE8AA, 0x6C85, 0xEAB6, 0x6C86, 0xF9FA, 0x6C87, 0xE6CC, 0x6C88, 0xF6D8, 0x6C8C, 0xD4C7, 0x6C90, 0xD9CB, 0x6C92, 0xD9D2, 0x6C93, 0xD3CB, 0x6C94, 0xD8F7, 0x6C95, 0xDAA9, 0x6C96, 0xF5F8, 0x6C99, 0xDEDE, 0x6C9A, 0xF2AF, 0x6C9B, 0xF8A9, 0x6CAB, 0xD8C8, 0x6CAE, 0xEEC1, 0x6CB3, 0xF9C1, 0x6CB8, 0xDDF3, 0x6CB9, 0xEAFA, 0x6CBB, 0xF6BD, 0x6CBC, 0xE1BB, 0x6CBD, 0xCDBF, 0x6CBE, 0xF4D4, 0x6CBF, 0xE6CD, 0x6CC1, 0xFCCF, 0x6CC2, 0xFBA2, 0x6CC4, 0xE0DC, 0x6CC9, 0xF4BB, 0x6CCA, 0xDAD5, 0x6CCC, 0xF9B2, 0x6CD3, 0xFBF2, 0x6CD5, 0xDBF6, 0x6CD7, 0xDEDF, 0x6CDB, 0xDBF2, 0x6CE1, 0xF8DC, 0x6CE2, 0xF7EE, 0x6CE3, 0xEBE8, 0x6CE5, 0xD2FA, 0x6CE8, 0xF1BC, 0x6CEB, 0xFADA, 0x6CEE, 0xDAEA, 0x6CEF, 0xDAC6, 0x6CF0, 0xF7C1, 0x6CF3, 0xE7B6, 0x6D0B, 0xE5C7, 0x6D0C, 0xD6AC, 0x6D11, 0xDCC7, 0x6D17, 0xE1A9, 0x6D19, 0xE2AA, 0x6D1B, 0xD5A6, 0x6D1E, 0xD4D7, 0x6D25, 0xF2D0, 0x6D27, 0xEAFB, 0x6D29, 0xE0DD, 0x6D2A, 0xFBF3, 0x6D32, 0xF1BD, 0x6D35, 0xE2E7, 0x6D36, 0xFDD7, 0x6D38, 0xCEC8, 0x6D39, 0xEAB7, 0x6D3B, 0xFCC0, 0x6D3D, 0xFDE7, 0x6D3E, 0xF7EF, 0x6D41, 0xD7B5, 0x6D59, 0xEFBA, 0x6D5A, 0xF1DD, 0x6D5C, 0xDEB3, 0x6D63, 0xE8CB, 0x6D66, 0xF8DD, 0x6D69, 0xFBC7, 0x6D6A, 0xD5C8, 0x6D6C, 0xD7DF, 0x6D6E, 0xDDA9, 0x6D74, 0xE9B1, 0x6D77, 0xFAAD, 0x6D78, 0xF6D9, 0x6D79, 0xFAF4, 0x6D7F, 0xF8AA, 0x6D85, 0xE6EE, 0x6D87, 0xCCDC, 0x6D88, 0xE1BC, 0x6D89, 0xE0EF, 0x6D8C, 0xE9BF, 0x6D8D, 0xFCFD, 0x6D8E, 0xE6CE, 0x6D91, 0xE1D7, 0x6D93, 0xE6CF, 0x6D95, 0xF4F1, 0x6DAF, 0xE4F3, 0x6DB2, 0xE4FB, 0x6DB5, 0xF9E4, 0x6DC0, 0xEFE3, 0x6DC3, 0xCFEE, 0x6DC4, 0xF6BE, 0x6DC5, 0xE0B2, 0x6DC6, 0xFCFE, 0x6DC7, 0xD1AB, 0x6DCB, 0xD7FA, 0x6DCF, 0xFBC8, 0x6DD1, 0xE2D7, 0x6DD8, 0xD4A3, 0x6DD9, 0xF0F8, 0x6DDA, 0xD7A8, 0x6DDE, 0xE1E7, 0x6DE1, 0xD3BF, 0x6DE8, 0xEFE4, 0x6DEA, 0xD7C5, 0x6DEB, 0xEBE2, 0x6DEE, 0xFCE7, 0x6DF1, 0xE4A2, 0x6DF3, 0xE2E8, 0x6DF5, 0xE6D0, 0x6DF7, 0xFBE8, 0x6DF8, 0xF4E8, 0x6DF9, 0xE5F4, 0x6DFA, 0xF4BC, 0x6DFB, 0xF4D5, 0x6E17, 0xDFB6, 0x6E19, 0xFCB9, 0x6E1A, 0xEEC2, 0x6E1B, 0xCAF5, 0x6E1F, 0xEFE5, 0x6E20, 0xCBE2, 0x6E21, 0xD4A4, 0x6E23, 0xDEE0, 0x6E24, 0xDAFD, 0x6E25, 0xE4C6, 0x6E26, 0xE8BE, 0x6E2B, 0xE0DE, 0x6E2C, 0xF6B4, 0x6E2D, 0xEAD2, 0x6E2F, 0xF9FB, 0x6E32, 0xE0C2, 0x6E34, 0xCAE4, 0x6E36, 0xE7B7, 0x6E38, 0xEAFD, 0x6E3A, 0xD9DD, 0x6E3C, 0xDAB4, 0x6E3D, 0xEEAA, 0x6E3E, 0xFBE9, 0x6E43, 0xDBCB, 0x6E44, 0xDAB5, 0x6E4A, 0xF1BE, 0x6E4D, 0xD3AC, 0x6E56, 0xFBC9, 0x6E58, 0xDFCF, 0x6E5B, 0xD3C0, 0x6E5C, 0xE3D7, 0x6E5E, 0xEFE6, 0x6E5F, 0xFCD0, 0x6E67, 0xE9C0, 0x6E6B, 0xF5D3, 0x6E6E, 0xECDC, 0x6E6F, 0xF7B7, 0x6E72, 0xEAB8, 0x6E73, 0xD1F9, 0x6E7A, 0xDCC8, 0x6E90, 0xEAB9, 0x6E96, 0xF1DE, 0x6E9C, 0xD7B6, 0x6E9D, 0xCFB5, 0x6E9F, 0xD9A8, 0x6EA2, 0xECEE, 0x6EA5, 0xDDAA, 0x6EAA, 0xCDA2, 0x6EAB, 0xE8AE, 0x6EAF, 0xE1BD, 0x6EB1, 0xF2D1, 0x6EB6, 0xE9C1, 0x6EBA, 0xD2FC, 0x6EC2, 0xDBB5, 0x6EC4, 0xF3E7, 0x6EC5, 0xD8FE, 0x6EC9, 0xFCD1, 0x6ECB, 0xEDB2, 0x6ECC, 0xF4AF, 0x6ECE, 0xFBA3, 0x6ED1, 0xFCC1, 0x6ED3, 0xEEAB, 0x6ED4, 0xD4A5, 0x6EEF, 0xF4F2, 0x6EF4, 0xEED9, 0x6EF8, 0xFBCA, 0x6EFE, 0xCDE3, 0x6EFF, 0xD8BB, 0x6F01, 0xE5DB, 0x6F02, 0xF8F7, 0x6F06, 0xF6D4, 0x6F0F, 0xD7A9, 0x6F11, 0xCBC9, 0x6F14, 0xE6D1, 0x6F15, 0xF0CC, 0x6F20, 0xD8AE, 0x6F22, 0xF9D3, 0x6F23, 0xD5FE, 0x6F2B, 0xD8BC, 0x6F2C, 0xF2B0, 0x6F31, 0xE2AB, 0x6F32, 0xF3E8, 0x6F38, 0xEFC2, 0x6F3F, 0xEDEC, 0x6F41, 0xE7B8, 0x6F51, 0xDAFE, 0x6F54, 0xCCBE, 0x6F57, 0xF2FC, 0x6F58, 0xDAEB, 0x6F5A, 0xE2D8, 0x6F5B, 0xEDD6, 0x6F5E, 0xD6D1, 0x6F5F, 0xE0B3, 0x6F62, 0xFCD2, 0x6F64, 0xEBC8, 0x6F6D, 0xD3C1, 0x6F6E, 0xF0CD, 0x6F70, 0xCFF7, 0x6F7A, 0xEDD2, 0x6F7C, 0xD4D8, 0x6F7D, 0xDCC9, 0x6F7E, 0xD7F1, 0x6F81, 0xDFBB, 0x6F84, 0xF3A5, 0x6F88, 0xF4CD, 0x6F8D, 0xF1BF, 0x6F8E, 0xF8B1, 0x6F90, 0xE9FA, 0x6F94, 0xFBCB, 0x6F97, 0xCAD5, 0x6FA3, 0xF9D4, 0x6FA4, 0xF7CA, 0x6FA7, 0xD6C8, 0x6FAE, 0xFCE8, 0x6FAF, 0xF3BD, 0x6FB1, 0xEEFE, 0x6FB3, 0xE7FE, 0x6FB9, 0xD3C2, 0x6FBE, 0xD3B6, 0x6FC0, 0xCCAD, 0x6FC1, 0xF6FA, 0x6FC2, 0xD6B2, 0x6FC3, 0xD2D8, 0x6FCA, 0xE7D8, 0x6FD5, 0xE3A5, 0x6FDA, 0xE7B9, 0x6FDF, 0xF0AD, 0x6FE0, 0xFBCC, 0x6FE1, 0xEBA1, 0x6FE4, 0xD4A6, 0x6FE9, 0xFBCD, 0x6FEB, 0xD5BD, 0x6FEC, 0xF1DF, 0x6FEF, 0xF6FB, 0x6FF1, 0xDEB4, 0x6FFE, 0xD5EB, 0x7001, 0xE5C8, 0x7005, 0xFBA4, 0x7006, 0xD4B9, 0x7009, 0xDEE1, 0x700B, 0xE4A3, 0x700F, 0xD7B7, 0x7011, 0xF8EE, 0x7015, 0xDEB5, 0x7018, 0xD6D2, 0x701A, 0xF9D5, 0x701B, 0xE7BA, 0x701C, 0xEBD5, 0x701D, 0xD5F7, 0x701E, 0xEFE7, 0x701F, 0xE1BE, 0x7023, 0xFAAE, 0x7027, 0xD6E9, 0x7028, 0xD6EE, 0x702F, 0xE7BB, 0x7037, 0xECCB, 0x703E, 0xD5B3, 0x704C, 0xCEB4, 0x7050, 0xFBA5, 0x7051, 0xE1EE, 0x7058, 0xF7A8, 0x705D, 0xFBCE, 0x7063, 0xD8BD, 0x706B, 0xFBFD, 0x7070, 0xFCE9, 0x7078, 0xCFB6, 0x707C, 0xEDC7, 0x707D, 0xEEAC, 0x7085, 0xCCDD, 0x708A, 0xF6A7, 0x708E, 0xE6FA, 0x7092, 0xF5A4, 0x7098, 0xFDDC, 0x7099, 0xEDB3, 0x709A, 0xCEC9, 0x70A1, 0xEFE8, 0x70A4, 0xE1BF, 0x70AB, 0xFADB, 0x70AC, 0xCBE3, 0x70AD, 0xF7A9, 0x70AF, 0xFBA6, 0x70B3, 0xDCB9, 0x70B7, 0xF1C0, 0x70B8, 0xEDC8, 0x70B9, 0xEFC3, 0x70C8, 0xD6AD, 0x70CB, 0xFDCE, 0x70CF, 0xE8A1, 0x70D8, 0xFBF4, 0x70D9, 0xD5A7, 0x70DD, 0xF1F6, 0x70DF, 0xE6D3, 0x70F1, 0xCCDE, 0x70F9, 0xF8B2, 0x70FD, 0xDCEB, 0x7104, 0xFDB6, 0x7109, 0xE5EA, 0x710C, 0xF1E0, 0x7119, 0xDBCC, 0x711A, 0xDDCD, 0x711E, 0xD4C8, 0x7121, 0xD9ED, 0x7126, 0xF5A5, 0x7130, 0xE6FB, 0x7136, 0xE6D4, 0x7147, 0xFDC8, 0x7149, 0xD6A1, 0x714A, 0xFDBF, 0x714C, 0xFCD3, 0x714E, 0xEFA1, 0x7150, 0xE7BC, 0x7156, 0xD1EE, 0x7159, 0xE6D5, 0x715C, 0xE9F2, 0x715E, 0xDFB0, 0x7164, 0xD8E0, 0x7165, 0xFCBA, 0x7166, 0xFDAF, 0x7167, 0xF0CE, 0x7169, 0xDBE1, 0x716C, 0xE5C9, 0x716E, 0xEDB4, 0x717D, 0xE0C3, 0x7184, 0xE3D8, 0x7189, 0xE9FB, 0x718A, 0xEAA8, 0x718F, 0xFDB7, 0x7192, 0xFBA7, 0x7194, 0xE9C2, 0x7199, 0xFDF7, 0x719F, 0xE2D9, 0x71A2, 0xDCEC, 0x71AC, 0xE8A2, 0x71B1, 0xE6F0, 0x71B9, 0xFDF8, 0x71BA, 0xFDF9, 0x71BE, 0xF6BF, 0x71C1, 0xE7A7, 0x71C3, 0xE6D7, 0x71C8, 0xD4F3, 0x71C9, 0xD4C9, 0x71CE, 0xD6FA, 0x71D0, 0xD7F2, 0x71D2, 0xE1C0, 0x71D4, 0xDBE2, 0x71D5, 0xE6D8, 0x71DF, 0xE7BD, 0x71E5, 0xF0CF, 0x71E6, 0xF3BE, 0x71E7, 0xE2AC, 0x71ED, 0xF5B7, 0x71EE, 0xE0F0, 0x71FB, 0xFDB8, 0x71FC, 0xE3E8, 0x71FE, 0xD4A7, 0x71FF, 0xE8FC, 0x7200, 0xFAD2, 0x7206, 0xF8EF, 0x7210, 0xD6D3, 0x721B, 0xD5B4, 0x722A, 0xF0D0, 0x722C, 0xF7F0, 0x722D, 0xEEB3, 0x7230, 0xEABA, 0x7232, 0xEAD3, 0x7235, 0xEDC9, 0x7236, 0xDDAB, 0x723A, 0xE5AC, 0x723B, 0xFDA1, 0x723D, 0xDFD0, 0x723E, 0xECB3, 0x7240, 0xDFD1, 0x7246, 0xEDED, 0x7247, 0xF8B8, 0x7248, 0xF7FA, 0x724C, 0xF8AB, 0x7252, 0xF4E0, 0x7258, 0xD4BA, 0x7259, 0xE4B3, 0x725B, 0xE9DA, 0x725D, 0xDEB6, 0x725F, 0xD9BF, 0x7261, 0xD9C0, 0x7262, 0xD6EF, 0x7267, 0xD9CC, 0x7269, 0xDAAA, 0x7272, 0xDFE5, 0x7279, 0xF7E5, 0x727D, 0xCCB2, 0x7280, 0xDFF9, 0x7281, 0xD7E0, 0x72A2, 0xD4BB, 0x72A7, 0xFDFA, 0x72AC, 0xCCB3, 0x72AF, 0xDBF3, 0x72C0, 0xDFD2, 0x72C2, 0xCECA, 0x72C4, 0xEEDA, 0x72CE, 0xE4E4, 0x72D0, 0xFBCF, 0x72D7, 0xCFB7, 0x72D9, 0xEEC3, 0x72E1, 0xCEEA, 0x72E9, 0xE2AD, 0x72F8, 0xD7E1, 0x72F9, 0xFAF5, 0x72FC, 0xD5C9, 0x72FD, 0xF8AC, 0x730A, 0xE7D9, 0x7316, 0xF3E9, 0x731B, 0xD8ED, 0x731C, 0xE3C4, 0x731D, 0xF0F1, 0x7325, 0xE8E5, 0x7329, 0xE0FA, 0x732A, 0xEEC4, 0x732B, 0xD9DE, 0x7336, 0xEBA2, 0x7337, 0xEBA3, 0x733E, 0xFCC2, 0x733F, 0xEABB, 0x7344, 0xE8AB, 0x7345, 0xDEE2, 0x7350, 0xEDEF, 0x7352, 0xE8A3, 0x7357, 0xCFF1, 0x7368, 0xD4BC, 0x736A, 0xFCEA, 0x7370, 0xE7BE, 0x7372, 0xFCF2, 0x7375, 0xD6B4, 0x7378, 0xE2AE, 0x737A, 0xD3B7, 0x737B, 0xFACC, 0x7384, 0xFADC, 0x7386, 0xEDB5, 0x7387, 0xE1E3, 0x7389, 0xE8AC, 0x738B, 0xE8DD, 0x738E, 0xEFE9, 0x7394, 0xF4BD, 0x7396, 0xCFB8, 0x7397, 0xE9DB, 0x7398, 0xD1AC, 0x739F, 0xDAC7, 0x73A7, 0xEBC9, 0x73A9, 0xE8CC, 0x73AD, 0xDEB7, 0x73B2, 0xD6BC, 0x73B3, 0xD3E5, 0x73B9, 0xFADD, 0x73C0, 0xDAD6, 0x73C2, 0xCAB1, 0x73C9, 0xDAC8, 0x73CA, 0xDFA6, 0x73CC, 0xF9B3, 0x73CD, 0xF2D2, 0x73CF, 0xCAC4, 0x73D6, 0xCECB, 0x73D9, 0xCDF5, 0x73DD, 0xFDB0, 0x73DE, 0xD5A8, 0x73E0, 0xF1C1, 0x73E3, 0xE2E9, 0x73E4, 0xDCCA, 0x73E5, 0xECB4, 0x73E6, 0xFAC0, 0x73E9, 0xFBA8, 0x73EA, 0xD0A8, 0x73ED, 0xDAEC, 0x73F7, 0xD9EE, 0x73F9, 0xE0FB, 0x73FD, 0xEFEA, 0x73FE, 0xFADE, 0x7401, 0xE0C4, 0x7403, 0xCFB9, 0x7405, 0xD5CA, 0x7406, 0xD7E2, 0x7407, 0xE2AF, 0x7409, 0xD7B8, 0x7413, 0xE8CD, 0x741B, 0xF6DA, 0x7420, 0xEFA2, 0x7421, 0xE2DA, 0x7422, 0xF6FC, 0x7425, 0xFBD0, 0x7426, 0xD1AD, 0x7428, 0xCDE4, 0x742A, 0xD1AE, 0x742B, 0xDCED, 0x742C, 0xE8CE, 0x742E, 0xF0F9, 0x742F, 0xCEB5, 0x7430, 0xE6FC, 0x7433, 0xD7FB, 0x7434, 0xD0D6, 0x7435, 0xDDF5, 0x7436, 0xF7F1, 0x7438, 0xF6FD, 0x743A, 0xDBF7, 0x743F, 0xFBEA, 0x7440, 0xE9DC, 0x7441, 0xD9C1, 0x7443, 0xF5F2, 0x7444, 0xE0C5, 0x744B, 0xEAD4, 0x7455, 0xF9C2, 0x7457, 0xEABC, 0x7459, 0xD2C5, 0x745A, 0xFBD1, 0x745B, 0xE7C0, 0x745C, 0xEBA5, 0x745E, 0xDFFA, 0x745F, 0xE3A2, 0x7460, 0xD7B9, 0x7462, 0xE9C3, 0x7464, 0xE8FD, 0x7465, 0xE8AF, 0x7468, 0xF2D3, 0x7469, 0xFBA9, 0x746A, 0xD8A5, 0x746F, 0xD5CB, 0x747E, 0xD0C8, 0x7482, 0xD1AF, 0x7483, 0xD7E3, 0x7487, 0xE0C6, 0x7489, 0xD6A2, 0x748B, 0xEDF0, 0x7498, 0xD7F3, 0x749C, 0xFCD4, 0x749E, 0xDAD7, 0x749F, 0xCCDF, 0x74A1, 0xF2D4, 0x74A3, 0xD1B0, 0x74A5, 0xCCE0, 0x74A7, 0xDBFD, 0x74A8, 0xF3BF, 0x74AA, 0xF0D1, 0x74B0, 0xFCBB, 0x74B2, 0xE2B0, 0x74B5, 0xE6A5, 0x74B9, 0xE2DB, 0x74BD, 0xDFDE, 0x74BF, 0xE0C7, 0x74C6, 0xF2EF, 0x74CA, 0xCCE1, 0x74CF, 0xD6EA, 0x74D4, 0xE7C2, 0x74D8, 0xCEB6, 0x74DA, 0xF3C0, 0x74DC, 0xCDFE, 0x74E0, 0xFBD2, 0x74E2, 0xF8F8, 0x74E3, 0xF7FB, 0x74E6, 0xE8BF, 0x74EE, 0xE8B7, 0x74F7, 0xEDB6, 0x7501, 0xDCBA, 0x7504, 0xCCB4, 0x7511, 0xF1F7, 0x7515, 0xE8B8, 0x7518, 0xCAF6, 0x751A, 0xE4A4, 0x751B, 0xF4D6, 0x751F, 0xDFE6, 0x7523, 0xDFA7, 0x7525, 0xDFE7, 0x7526, 0xE1C1, 0x7528, 0xE9C4, 0x752B, 0xDCCB, 0x752C, 0xE9C5, 0x7530, 0xEFA3, 0x7531, 0xEBA6, 0x7532, 0xCBA3, 0x7533, 0xE3E9, 0x7537, 0xD1FB, 0x7538, 0xEFA4, 0x753A, 0xEFEB, 0x7547, 0xD0B4, 0x754C, 0xCDA3, 0x754F, 0xE8E6, 0x7551, 0xEFA5, 0x7553, 0xD3CC, 0x7554, 0xDAED, 0x7559, 0xD7BA, 0x755B, 0xF2D5, 0x755C, 0xF5E5, 0x755D, 0xD9EF, 0x7562, 0xF9B4, 0x7565, 0xD5D4, 0x7566, 0xFDCF, 0x756A, 0xDBE3, 0x756F, 0xF1E1, 0x7570, 0xECB6, 0x7575, 0xFBFE, 0x7576, 0xD3D7, 0x7578, 0xD1B1, 0x757A, 0xCBB1, 0x757F, 0xD1B2, 0x7586, 0xCBB2, 0x7587, 0xF1C2, 0x758A, 0xF4E1, 0x758B, 0xF9B5, 0x758E, 0xE1C3, 0x758F, 0xE1C2, 0x7591, 0xEBF7, 0x759D, 0xDFA8, 0x75A5, 0xCBCA, 0x75AB, 0xE6B9, 0x75B1, 0xF8DE, 0x75B2, 0xF9AA, 0x75B3, 0xCAF7, 0x75B5, 0xEDB7, 0x75B8, 0xD3B8, 0x75B9, 0xF2D6, 0x75BC, 0xD4D9, 0x75BD, 0xEEC5, 0x75BE, 0xF2F0, 0x75C2, 0xCAB2, 0x75C5, 0xDCBB, 0x75C7, 0xF1F8, 0x75CD, 0xECB7, 0x75D2, 0xE5CA, 0x75D4, 0xF6C0, 0x75D5, 0xFDDD, 0x75D8, 0xD4E3, 0x75D9, 0xCCE2, 0x75DB, 0xF7D4, 0x75E2, 0xD7E5, 0x75F0, 0xD3C3, 0x75F2, 0xD8A6, 0x75F4, 0xF6C1, 0x75FA, 0xDDF6, 0x75FC, 0xCDC0, 0x7600, 0xE5DC, 0x760D, 0xE5CB, 0x7619, 0xE1C4, 0x761F, 0xE8B0, 0x7620, 0xF4B0, 0x7621, 0xF3EA, 0x7622, 0xDAEE, 0x7624, 0xD7BB, 0x7626, 0xE2B1, 0x763B, 0xD7AA, 0x7642, 0xD6FB, 0x764C, 0xE4DF, 0x764E, 0xCAD6, 0x7652, 0xEBA8, 0x7656, 0xDBFE, 0x7661, 0xF6C2, 0x7664, 0xEFBB, 0x7669, 0xD4FD, 0x766C, 0xE0C8, 0x7670, 0xE8B9, 0x7672, 0xEFA6, 0x7678, 0xCDA4, 0x767B, 0xD4F4, 0x767C, 0xDBA1, 0x767D, 0xDBDC, 0x767E, 0xDBDD, 0x7684, 0xEEDC, 0x7686, 0xCBCB, 0x7687, 0xFCD5, 0x768E, 0xCEEB, 0x7690, 0xCDC1, 0x7693, 0xFBD3, 0x76AE, 0xF9AB, 0x76BA, 0xF5D4, 0x76BF, 0xD9A9, 0x76C2, 0xE9DD, 0x76C3, 0xDBCD, 0x76C6, 0xDDCE, 0x76C8, 0xE7C3, 0x76CA, 0xECCC, 0x76D2, 0xF9EC, 0x76D6, 0xCBCC, 0x76DB, 0xE0FC, 0x76DC, 0xD4A8, 0x76DE, 0xEDD3, 0x76DF, 0xD8EF, 0x76E1, 0xF2D7, 0x76E3, 0xCAF8, 0x76E4, 0xDAEF, 0x76E7, 0xD6D4, 0x76EE, 0xD9CD, 0x76F2, 0xD8EE, 0x76F4, 0xF2C1, 0x76F8, 0xDFD3, 0x76FC, 0xDAF0, 0x76FE, 0xE2EA, 0x7701, 0xE0FD, 0x7704, 0xD8F8, 0x7708, 0xF7AF, 0x7709, 0xDAB6, 0x770B, 0xCAD7, 0x771E, 0xF2D8, 0x7720, 0xD8F9, 0x7729, 0xFADF, 0x7737, 0xCFEF, 0x7738, 0xD9C2, 0x773A, 0xF0D2, 0x773C, 0xE4D1, 0x7740, 0xF3B7, 0x774D, 0xFAE0, 0x775B, 0xEFEC, 0x7761, 0xE2B2, 0x7763, 0xD4BD, 0x7766, 0xD9CE, 0x776B, 0xF4E2, 0x7779, 0xD4A9, 0x777E, 0xCDC2, 0x777F, 0xE7DA, 0x778B, 0xF2D9, 0x7791, 0xD9AA, 0x779E, 0xD8BE, 0x77A5, 0xDCAD, 0x77AC, 0xE2EB, 0x77AD, 0xD6FC, 0x77B0, 0xCAF9, 0x77B3, 0xD4DA, 0x77BB, 0xF4D7, 0x77BC, 0xCCA1, 0x77BF, 0xCFBA, 0x77D7, 0xF5B8, 0x77DB, 0xD9C3, 0x77DC, 0xD0E8, 0x77E2, 0xE3C5, 0x77E3, 0xEBF8, 0x77E5, 0xF2B1, 0x77E9, 0xCFBB, 0x77ED, 0xD3AD, 0x77EE, 0xE8E1, 0x77EF, 0xCEEC, 0x77F3, 0xE0B4, 0x7802, 0xDEE3, 0x7812, 0xDDF7, 0x7825, 0xF2B2, 0x7826, 0xF3F6, 0x7827, 0xF6DB, 0x782C, 0xD7FE, 0x7832, 0xF8DF, 0x7834, 0xF7F2, 0x7845, 0xD0A9, 0x784F, 0xE6DA, 0x785D, 0xF5A6, 0x786B, 0xD7BC, 0x786C, 0xCCE3, 0x786F, 0xE6DB, 0x787C, 0xDDDD, 0x7881, 0xD1B3, 0x7887, 0xEFED, 0x788C, 0xD6DE, 0x788D, 0xE4F4, 0x788E, 0xE1EF, 0x7891, 0xDDF8, 0x7897, 0xE8CF, 0x78A3, 0xCAE5, 0x78A7, 0xDCA1, 0x78A9, 0xE0B5, 0x78BA, 0xFCAC, 0x78BB, 0xFCAD, 0x78BC, 0xD8A7, 0x78C1, 0xEDB8, 0x78C5, 0xDBB6, 0x78CA, 0xD6F0, 0x78CB, 0xF3AF, 0x78CE, 0xCDA5, 0x78D0, 0xDAF1, 0x78E8, 0xD8A8, 0x78EC, 0xCCE4, 0x78EF, 0xD1B4, 0x78F5, 0xCAD8, 0x78FB, 0xDAF2, 0x7901, 0xF5A7, 0x790E, 0xF5A8, 0x7916, 0xE6A6, 0x792A, 0xD5EC, 0x792B, 0xD5F8, 0x792C, 0xDAF3, 0x793A, 0xE3C6, 0x793E, 0xDEE4, 0x7940, 0xDEE5, 0x7941, 0xD1B5, 0x7947, 0xD1B6, 0x7948, 0xD1B7, 0x7949, 0xF2B3, 0x7950, 0xE9DE, 0x7956, 0xF0D3, 0x7957, 0xF2B4, 0x795A, 0xF0D4, 0x795B, 0xCBE4, 0x795C, 0xFBD4, 0x795D, 0xF5E6, 0x795E, 0xE3EA, 0x7960, 0xDEE6, 0x7965, 0xDFD4, 0x7968, 0xF8F9, 0x796D, 0xF0AE, 0x797A, 0xD1B8, 0x797F, 0xD6DF, 0x7981, 0xD0D7, 0x798D, 0xFCA1, 0x798E, 0xEFEE, 0x798F, 0xDCD8, 0x7991, 0xE9DF, 0x79A6, 0xE5DD, 0x79A7, 0xFDFB, 0x79AA, 0xE0C9, 0x79AE, 0xD6C9, 0x79B1, 0xD4AA, 0x79B3, 0xE5CC, 0x79B9, 0xE9E0, 0x79BD, 0xD0D8, 0x79BE, 0xFCA2, 0x79BF, 0xD4BE, 0x79C0, 0xE2B3, 0x79C1, 0xDEE7, 0x79C9, 0xDCBC, 0x79CA, 0xD2B6, 0x79CB, 0xF5D5, 0x79D1, 0xCEA1, 0x79D2, 0xF5A9, 0x79D5, 0xDDF9, 0x79D8, 0xDDFA, 0x79DF, 0xF0D5, 0x79E4, 0xF6DF, 0x79E6, 0xF2DA, 0x79E7, 0xE4EB, 0x79E9, 0xF2F1, 0x79FB, 0xECB9, 0x7A00, 0xFDFC, 0x7A05, 0xE1AA, 0x7A08, 0xCAD9, 0x7A0B, 0xEFEF, 0x7A0D, 0xF5AA, 0x7A14, 0xECF9, 0x7A17, 0xF8AD, 0x7A19, 0xF2C2, 0x7A1A, 0xF6C3, 0x7A1C, 0xD7D2, 0x7A1F, 0xF9A2, 0x7A20, 0xF0D6, 0x7A2E, 0xF0FA, 0x7A31, 0xF6E0, 0x7A36, 0xE9F3, 0x7A37, 0xF2C3, 0x7A3B, 0xD4AB, 0x7A3C, 0xCAB3, 0x7A3D, 0xCDA6, 0x7A3F, 0xCDC3, 0x7A40, 0xCDDA, 0x7A46, 0xD9CF, 0x7A49, 0xF6C4, 0x7A4D, 0xEEDD, 0x7A4E, 0xE7C4, 0x7A57, 0xE2B4, 0x7A61, 0xDFE2, 0x7A62, 0xE7DB, 0x7A69, 0xE8B1, 0x7A6B, 0xFCAE, 0x7A70, 0xE5CD, 0x7A74, 0xFAEB, 0x7A76, 0xCFBC, 0x7A79, 0xCFE2, 0x7A7A, 0xCDF6, 0x7A7D, 0xEFF0, 0x7A7F, 0xF4BE, 0x7A81, 0xD4CD, 0x7A84, 0xF3B8, 0x7A88, 0xE9A1, 0x7A92, 0xF2F2, 0x7A93, 0xF3EB, 0x7A95, 0xF0D7, 0x7A98, 0xCFD7, 0x7A9F, 0xCFDF, 0x7AA9, 0xE8C0, 0x7AAA, 0xE8C1, 0x7AAE, 0xCFE3, 0x7AAF, 0xE9A2, 0x7ABA, 0xD0AA, 0x7AC4, 0xF3C1, 0x7AC5, 0xD0AB, 0x7AC7, 0xD4E4, 0x7ACA, 0xEFBC, 0x7ACB, 0xD8A1, 0x7AD7, 0xD9DF, 0x7AD9, 0xF3D7, 0x7ADD, 0xDCBD, 0x7ADF, 0xCCE5, 0x7AE0, 0xEDF1, 0x7AE3, 0xF1E2, 0x7AE5, 0xD4DB, 0x7AEA, 0xE2B5, 0x7AED, 0xCAE6, 0x7AEF, 0xD3AE, 0x7AF6, 0xCCE6, 0x7AF9, 0xF1D3, 0x7AFA, 0xF5E7, 0x7AFF, 0xCADA, 0x7B0F, 0xFBEE, 0x7B11, 0xE1C5, 0x7B19, 0xDFE9, 0x7B1B, 0xEEDE, 0x7B1E, 0xF7C2, 0x7B20, 0xD8A2, 0x7B26, 0xDDAC, 0x7B2C, 0xF0AF, 0x7B2D, 0xD6BD, 0x7B39, 0xE1AB, 0x7B46, 0xF9B6, 0x7B49, 0xD4F5, 0x7B4B, 0xD0C9, 0x7B4C, 0xEFA7, 0x7B4D, 0xE2EC, 0x7B4F, 0xDBEA, 0x7B50, 0xCECC, 0x7B51, 0xF5E8, 0x7B52, 0xF7D5, 0x7B54, 0xD3CD, 0x7B56, 0xF3FE, 0x7B60, 0xD0B5, 0x7B6C, 0xE0FE, 0x7B6E, 0xDFFB, 0x7B75, 0xE6DD, 0x7B7D, 0xE8A4, 0x7B87, 0xCBCD, 0x7B8B, 0xEFA8, 0x7B8F, 0xEEB4, 0x7B94, 0xDAD8, 0x7B95, 0xD1B9, 0x7B97, 0xDFA9, 0x7B9A, 0xF3B0, 0x7B9D, 0xCCC4, 0x7BA1, 0xCEB7, 0x7BAD, 0xEFA9, 0x7BB1, 0xDFD5, 0x7BB4, 0xEDD7, 0x7BB8, 0xEEC6, 0x7BC0, 0xEFBD, 0x7BC1, 0xFCD6, 0x7BC4, 0xDBF4, 0x7BC6, 0xEFAA, 0x7BC7, 0xF8B9, 0x7BC9, 0xF5E9, 0x7BD2, 0xE3D9, 0x7BE0, 0xE1C6, 0x7BE4, 0xD4BF, 0x7BE9, 0xDEE8, 0x7C07, 0xF0EA, 0x7C12, 0xF3C2, 0x7C1E, 0xD3AF, 0x7C21, 0xCADB, 0x7C27, 0xFCD7, 0x7C2A, 0xEDD8, 0x7C2B, 0xE1C7, 0x7C3D, 0xF4D8, 0x7C3E, 0xD6B3, 0x7C3F, 0xDDAD, 0x7C43, 0xD5BE, 0x7C4C, 0xF1C3, 0x7C4D, 0xEEDF, 0x7C60, 0xD6EB, 0x7C64, 0xF4D9, 0x7C6C, 0xD7E6, 0x7C73, 0xDAB7, 0x7C83, 0xDDFB, 0x7C89, 0xDDCF, 0x7C92, 0xD8A3, 0x7C95, 0xDAD9, 0x7C97, 0xF0D8, 0x7C98, 0xEFC4, 0x7C9F, 0xE1D8, 0x7CA5, 0xF1D4, 0x7CA7, 0xEDF2, 0x7CAE, 0xD5DB, 0x7CB1, 0xD5DC, 0x7CB2, 0xF3C4, 0x7CB3, 0xCBD7, 0x7CB9, 0xE2B6, 0x7CBE, 0xEFF1, 0x7CCA, 0xFBD5, 0x7CD6, 0xD3D8, 0x7CDE, 0xDDD0, 0x7CDF, 0xF0D9, 0x7CE0, 0xCBB3, 0x7CE7, 0xD5DD, 0x7CFB, 0xCDA7, 0x7CFE, 0xD0AC, 0x7D00, 0xD1BA, 0x7D02, 0xF1C4, 0x7D04, 0xE5B3, 0x7D05, 0xFBF5, 0x7D06, 0xE9E1, 0x7D07, 0xFDE0, 0x7D08, 0xFCBC, 0x7D0A, 0xDAA2, 0x7D0B, 0xDAA3, 0x7D0D, 0xD2A1, 0x7D10, 0xD2EF, 0x7D14, 0xE2ED, 0x7D17, 0xDEE9, 0x7D18, 0xCEDC, 0x7D19, 0xF2B5, 0x7D1A, 0xD0E4, 0x7D1B, 0xDDD1, 0x7D20, 0xE1C8, 0x7D21, 0xDBB7, 0x7D22, 0xDFE3, 0x7D2B, 0xEDB9, 0x7D2C, 0xF1C5, 0x7D2E, 0xF3CF, 0x7D2F, 0xD7AB, 0x7D30, 0xE1AC, 0x7D33, 0xE3EB, 0x7D35, 0xEEC7, 0x7D39, 0xE1C9, 0x7D3A, 0xCAFA, 0x7D42, 0xF0FB, 0x7D43, 0xFAE1, 0x7D44, 0xF0DA, 0x7D45, 0xCCE7, 0x7D46, 0xDAF4, 0x7D50, 0xCCBF, 0x7D5E, 0xCEED, 0x7D61, 0xD5A9, 0x7D62, 0xFAE2, 0x7D66, 0xD0E5, 0x7D68, 0xEBD6, 0x7D6A, 0xECDF, 0x7D6E, 0xDFFC, 0x7D71, 0xF7D6, 0x7D72, 0xDEEA, 0x7D73, 0xCBB4, 0x7D76, 0xEFBE, 0x7D79, 0xCCB5, 0x7D7F, 0xCFBD, 0x7D8E, 0xEFF2, 0x7D8F, 0xE2B7, 0x7D93, 0xCCE8, 0x7D9C, 0xF0FC, 0x7DA0, 0xD6E0, 0x7DA2, 0xF1C6, 0x7DAC, 0xE2B8, 0x7DAD, 0xEBAB, 0x7DB1, 0xCBB5, 0x7DB2, 0xD8D1, 0x7DB4, 0xF4CE, 0x7DB5, 0xF3F7, 0x7DB8, 0xD7C6, 0x7DBA, 0xD1BB, 0x7DBB, 0xF7AA, 0x7DBD, 0xEDCA, 0x7DBE, 0xD7D3, 0x7DBF, 0xD8FA, 0x7DC7, 0xF6C5, 0x7DCA, 0xD1CC, 0x7DCB, 0xDDFC, 0x7DD6, 0xDFFD, 0x7DD8, 0xF9E5, 0x7DDA, 0xE0CA, 0x7DDD, 0xF2FD, 0x7DDE, 0xD3B0, 0x7DE0, 0xF4F3, 0x7DE1, 0xDAC9, 0x7DE3, 0xE6DE, 0x7DE8, 0xF8BA, 0x7DE9, 0xE8D0, 0x7DEC, 0xD8FB, 0x7DEF, 0xEAD5, 0x7DF4, 0xD6A3, 0x7DFB, 0xF6C6, 0x7E09, 0xF2DB, 0x7E0A, 0xE4FC, 0x7E15, 0xE8B2, 0x7E1B, 0xDADA, 0x7E1D, 0xF2DC, 0x7E1E, 0xFBD6, 0x7E1F, 0xE9B2, 0x7E21, 0xEEAD, 0x7E23, 0xFAE3, 0x7E2B, 0xDCEE, 0x7E2E, 0xF5EA, 0x7E2F, 0xE6E0, 0x7E31, 0xF0FD, 0x7E37, 0xD7AC, 0x7E3D, 0xF5C5, 0x7E3E, 0xEEE0, 0x7E41, 0xDBE5, 0x7E43, 0xDDDE, 0x7E46, 0xD9F0, 0x7E47, 0xE9A3, 0x7E52, 0xF1F9, 0x7E54, 0xF2C4, 0x7E55, 0xE0CB, 0x7E5E, 0xE9A4, 0x7E61, 0xE2B9, 0x7E69, 0xE3B1, 0x7E6A, 0xFCEB, 0x7E6B, 0xCDA8, 0x7E6D, 0xCCB6, 0x7E70, 0xF0DB, 0x7E79, 0xE6BA, 0x7E7C, 0xCDA9, 0x7E82, 0xF3C3, 0x7E8C, 0xE1D9, 0x7E8F, 0xEFAB, 0x7E93, 0xE7C5, 0x7E96, 0xE0E9, 0x7E98, 0xF3C5, 0x7E9B, 0xD4C0, 0x7E9C, 0xD5BF, 0x7F36, 0xDDAE, 0x7F38, 0xF9FC, 0x7F3A, 0xCCC0, 0x7F4C, 0xE5A2, 0x7F50, 0xCEB8, 0x7F54, 0xD8D2, 0x7F55, 0xF9D6, 0x7F6A, 0xF1AA, 0x7F6B, 0xCED1, 0x7F6E, 0xF6C7, 0x7F70, 0xDBEB, 0x7F72, 0xDFFE, 0x7F75, 0xD8E1, 0x7F77, 0xF7F3, 0x7F79, 0xD7E7, 0x7F85, 0xD4FE, 0x7F88, 0xD1BC, 0x7F8A, 0xE5CF, 0x7F8C, 0xCBB6, 0x7F8E, 0xDAB8, 0x7F94, 0xCDC4, 0x7F9A, 0xD6BE, 0x7F9E, 0xE2BA, 0x7FA4, 0xCFD8, 0x7FA8, 0xE0CC, 0x7FA9, 0xEBF9, 0x7FB2, 0xFDFD, 0x7FB8, 0xD7E8, 0x7FB9, 0xCBD8, 0x7FBD, 0xE9E2, 0x7FC1, 0xE8BA, 0x7FC5, 0xE3C7, 0x7FCA, 0xECCD, 0x7FCC, 0xECCE, 0x7FCE, 0xD6BF, 0x7FD2, 0xE3A7, 0x7FD4, 0xDFD6, 0x7FD5, 0xFDE8, 0x7FDF, 0xEEE1, 0x7FE0, 0xF6A8, 0x7FE1, 0xDDFD, 0x7FE9, 0xF8BB, 0x7FEB, 0xE8D1, 0x7FF0, 0xF9D7, 0x7FF9, 0xCEEE, 0x7FFC, 0xECCF, 0x8000, 0xE9A5, 0x8001, 0xD6D5, 0x8003, 0xCDC5, 0x8005, 0xEDBA, 0x8006, 0xD1BD, 0x8009, 0xCFBE, 0x800C, 0xECBB, 0x8010, 0xD2B1, 0x8015, 0xCCE9, 0x8017, 0xD9C4, 0x8018, 0xE9FC, 0x802D, 0xD1BE, 0x8033, 0xECBC, 0x8036, 0xE5AD, 0x803D, 0xF7B0, 0x803F, 0xCCEA, 0x8043, 0xD3C4, 0x8046, 0xD6C0, 0x804A, 0xD6FD, 0x8056, 0xE1A1, 0x8058, 0xDEBD, 0x805A, 0xF6A9, 0x805E, 0xDAA4, 0x806F, 0xD6A4, 0x8070, 0xF5C6, 0x8072, 0xE1A2, 0x8073, 0xE9C6, 0x8077, 0xF2C5, 0x807D, 0xF4E9, 0x807E, 0xD6EC, 0x807F, 0xEBD3, 0x8084, 0xECBD, 0x8085, 0xE2DC, 0x8086, 0xDEEB, 0x8087, 0xF0DC, 0x8089, 0xEBBF, 0x808B, 0xD7CE, 0x808C, 0xD1BF, 0x8096, 0xF5AB, 0x809B, 0xF9FD, 0x809D, 0xCADC, 0x80A1, 0xCDC6, 0x80A2, 0xF2B6, 0x80A5, 0xDDFE, 0x80A9, 0xCCB7, 0x80AA, 0xDBB8, 0x80AF, 0xD0E9, 0x80B1, 0xCEDD, 0x80B2, 0xEBC0, 0x80B4, 0xFDA2, 0x80BA, 0xF8CB, 0x80C3, 0xEAD6, 0x80C4, 0xF1B0, 0x80CC, 0xDBCE, 0x80CE, 0xF7C3, 0x80DA, 0xDBCF, 0x80DB, 0xCBA4, 0x80DE, 0xF8E0, 0x80E1, 0xFBD7, 0x80E4, 0xEBCA, 0x80E5, 0xE0A1, 0x80F1, 0xCECD, 0x80F4, 0xD4DC, 0x80F8, 0xFDD8, 0x80FD, 0xD2F6, 0x8102, 0xF2B7, 0x8105, 0xFAF6, 0x8106, 0xF6AA, 0x8107, 0xFAF7, 0x8108, 0xD8E6, 0x810A, 0xF4B1, 0x8118, 0xE8D2, 0x811A, 0xCAC5, 0x811B, 0xCCEB, 0x8123, 0xE2EE, 0x8129, 0xE2BB, 0x812B, 0xF7AD, 0x812F, 0xF8E1, 0x8139, 0xF3EC, 0x813E, 0xDEA1, 0x814B, 0xE4FD, 0x814E, 0xE3EC, 0x8150, 0xDDAF, 0x8151, 0xDDB0, 0x8154, 0xCBB7, 0x8155, 0xE8D3, 0x8165, 0xE1A3, 0x8166, 0xD2E0, 0x816B, 0xF0FE, 0x8170, 0xE9A6, 0x8171, 0xCBF2, 0x8178, 0xEDF3, 0x8179, 0xDCD9, 0x817A, 0xE0CD, 0x817F, 0xF7DA, 0x8180, 0xDBB9, 0x8188, 0xCCAE, 0x818A, 0xDADB, 0x818F, 0xCDC7, 0x819A, 0xDDB1, 0x819C, 0xD8AF, 0x819D, 0xE3A3, 0x81A0, 0xCEEF, 0x81A3, 0xF2F3, 0x81A8, 0xF8B3, 0x81B3, 0xE0CE, 0x81B5, 0xF5FD, 0x81BA, 0xEBEC, 0x81BD, 0xD3C5, 0x81BE, 0xFCEC, 0x81BF, 0xD2DB, 0x81C0, 0xD4EB, 0x81C2, 0xDEA2, 0x81C6, 0xE5E6, 0x81CD, 0xF0B0, 0x81D8, 0xD5C4, 0x81DF, 0xEDF4, 0x81E3, 0xE3ED, 0x81E5, 0xE8C2, 0x81E7, 0xEDF5, 0x81E8, 0xD7FC, 0x81EA, 0xEDBB, 0x81ED, 0xF6AB, 0x81F3, 0xF2B8, 0x81F4, 0xF6C8, 0x81FA, 0xD3E6, 0x81FB, 0xF2DD, 0x81FC, 0xCFBF, 0x81FE, 0xEBAC, 0x8205, 0xCFC0, 0x8207, 0xE6A8, 0x8208, 0xFDE9, 0x820A, 0xCFC1, 0x820C, 0xE0DF, 0x820D, 0xDEEC, 0x8212, 0xE0A2, 0x821B, 0xF4BF, 0x821C, 0xE2EF, 0x821E, 0xD9F1, 0x821F, 0xF1C7, 0x8221, 0xCBB8, 0x822A, 0xF9FE, 0x822B, 0xDBBA, 0x822C, 0xDAF5, 0x8235, 0xF6EC, 0x8236, 0xDADC, 0x8237, 0xFAE4, 0x8239, 0xE0CF, 0x8240, 0xDDB2, 0x8245, 0xE6A9, 0x8247, 0xEFF3, 0x8259, 0xF3ED, 0x8264, 0xEBFA, 0x8266, 0xF9E6, 0x826E, 0xCADD, 0x826F, 0xD5DE, 0x8271, 0xCADE, 0x8272, 0xDFE4, 0x8276, 0xE6FD, 0x8278, 0xF5AC, 0x827E, 0xE4F5, 0x828B, 0xE9E3, 0x828D, 0xEDCB, 0x828E, 0xCFE4, 0x8292, 0xD8D3, 0x8299, 0xDDB3, 0x829A, 0xD4EC, 0x829D, 0xF2B9, 0x829F, 0xDFB7, 0x82A5, 0xCBCE, 0x82A6, 0xFBD8, 0x82A9, 0xD0D9, 0x82AC, 0xDDD2, 0x82AD, 0xF7F4, 0x82AE, 0xE7DC, 0x82AF, 0xE4A5, 0x82B1, 0xFCA3, 0x82B3, 0xDBBB, 0x82B7, 0xF2BA, 0x82B8, 0xE9FD, 0x82B9, 0xD0CA, 0x82BB, 0xF5D6, 0x82BC, 0xD9C5, 0x82BD, 0xE4B4, 0x82BF, 0xEDA7, 0x82D1, 0xEABD, 0x82D2, 0xE6FE, 0x82D4, 0xF7C4, 0x82D5, 0xF5AD, 0x82D7, 0xD9E0, 0x82DB, 0xCAB4, 0x82DE, 0xF8E2, 0x82DF, 0xCFC2, 0x82E1, 0xECBE, 0x82E5, 0xE5B4, 0x82E6, 0xCDC8, 0x82E7, 0xEEC8, 0x82F1, 0xE7C8, 0x82FD, 0xCDC9, 0x82FE, 0xF9B7, 0x8301, 0xF1E8, 0x8302, 0xD9F2, 0x8303, 0xDBF5, 0x8304, 0xCAB5, 0x8305, 0xD9C6, 0x8309, 0xD8C9, 0x8317, 0xD9AB, 0x8328, 0xEDBC, 0x832B, 0xD8D4, 0x832F, 0xDCDA, 0x8331, 0xE2BC, 0x8334, 0xFCED, 0x8335, 0xECE0, 0x8336, 0xD2FE, 0x8338, 0xE9C7, 0x8339, 0xE6AA, 0x8340, 0xE2F0, 0x8347, 0xFABB, 0x8349, 0xF5AE, 0x834A, 0xFBAA, 0x834F, 0xECFB, 0x8351, 0xECBF, 0x8352, 0xFCD8, 0x8373, 0xD4E5, 0x8377, 0xF9C3, 0x837B, 0xEEE2, 0x8389, 0xD7E9, 0x838A, 0xEDF6, 0x838E, 0xDEED, 0x8396, 0xCCEC, 0x8398, 0xE3EE, 0x839E, 0xE8D4, 0x83A2, 0xFAF8, 0x83A9, 0xDDB4, 0x83AA, 0xE4B5, 0x83AB, 0xD8B0, 0x83BD, 0xD8D5, 0x83C1, 0xF4EA, 0x83C5, 0xCEB9, 0x83C9, 0xD6E1, 0x83CA, 0xCFD2, 0x83CC, 0xD0B6, 0x83D3, 0xCEA2, 0x83D6, 0xF3EE, 0x83DC, 0xF3F8, 0x83E9, 0xDCCC, 0x83EB, 0xD0CB, 0x83EF, 0xFCA4, 0x83F0, 0xCDCA, 0x83F1, 0xD7D4, 0x83F2, 0xDEA3, 0x83F4, 0xE4E0, 0x83F9, 0xEEC9, 0x83FD, 0xE2DD, 0x8403, 0xF5FE, 0x8404, 0xD4AC, 0x840A, 0xD5D1, 0x840C, 0xD8F0, 0x840D, 0xF8C3, 0x840E, 0xEAD7, 0x8429, 0xF5D7, 0x842C, 0xD8BF, 0x8431, 0xFDC0, 0x8438, 0xEBAD, 0x843D, 0xD5AA, 0x8449, 0xE7A8, 0x8457, 0xEECA, 0x845B, 0xCAE7, 0x8461, 0xF8E3, 0x8463, 0xD4DD, 0x8466, 0xEAD8, 0x846B, 0xFBD9, 0x846C, 0xEDF7, 0x846F, 0xE5B5, 0x8475, 0xD0AD, 0x847A, 0xF1F1, 0x8490, 0xE2BD, 0x8494, 0xE3C8, 0x8499, 0xD9D5, 0x849C, 0xDFAA, 0x84A1, 0xDBBC, 0x84B2, 0xF8E4, 0x84B8, 0xF1FA, 0x84BB, 0xE5B6, 0x84BC, 0xF3EF, 0x84BF, 0xFBDA, 0x84C0, 0xE1E0, 0x84C2, 0xD9AC, 0x84C4, 0xF5EB, 0x84C6, 0xE0B6, 0x84C9, 0xE9C8, 0x84CB, 0xCBCF, 0x84CD, 0xE3C9, 0x84D1, 0xDEEE, 0x84DA, 0xE2BE, 0x84EC, 0xDCEF, 0x84EE, 0xD6A5, 0x84F4, 0xE2F1, 0x84FC, 0xD6FE, 0x8511, 0xD9A1, 0x8513, 0xD8C0, 0x8514, 0xDCDB, 0x8517, 0xEDBD, 0x8518, 0xDFB8, 0x851A, 0xEAA5, 0x851E, 0xD7AD, 0x8521, 0xF3F9, 0x8523, 0xEDF8, 0x8525, 0xF5C7, 0x852C, 0xE1CA, 0x852D, 0xEBE3, 0x852F, 0xF2DE, 0x853D, 0xF8CC, 0x853F, 0xEAD9, 0x8541, 0xD3C6, 0x8543, 0xDBE6, 0x8549, 0xF5AF, 0x854E, 0xCEF0, 0x8553, 0xE9FE, 0x8559, 0xFBB6, 0x8563, 0xE2F2, 0x8568, 0xCFF2, 0x8569, 0xF7B9, 0x856A, 0xD9F3, 0x856D, 0xE1CB, 0x8584, 0xDADD, 0x8587, 0xDAB9, 0x858F, 0xEBFB, 0x8591, 0xCBB9, 0x8594, 0xEDF9, 0x859B, 0xE0E0, 0x85A6, 0xF4C0, 0x85A8, 0xFDBC, 0x85A9, 0xDFB1, 0x85AA, 0xE3EF, 0x85AF, 0xE0A3, 0x85B0, 0xFDB9, 0x85BA, 0xF0B1, 0x85C1, 0xCDCB, 0x85C9, 0xEDBE, 0x85CD, 0xD5C0, 0x85CE, 0xE3F0, 0x85CF, 0xEDFA, 0x85D5, 0xE9E4, 0x85DC, 0xD5ED, 0x85DD, 0xE7DD, 0x85E4, 0xD4F6, 0x85E5, 0xE5B7, 0x85E9, 0xDBE7, 0x85EA, 0xE2BF, 0x85F7, 0xEECB, 0x85FA, 0xD7F4, 0x85FB, 0xF0DD, 0x85FF, 0xCEAB, 0x8602, 0xE7DE, 0x8606, 0xD6D6, 0x8607, 0xE1CC, 0x860A, 0xE8B3, 0x8616, 0xE5EE, 0x8617, 0xDCA2, 0x861A, 0xE0D0, 0x862D, 0xD5B5, 0x863F, 0xD5A1, 0x864E, 0xFBDB, 0x8650, 0xF9CB, 0x8654, 0xCBF3, 0x8655, 0xF4A5, 0x865B, 0xFAC8, 0x865C, 0xD6D7, 0x865E, 0xE9E5, 0x865F, 0xFBDC, 0x8667, 0xFDD0, 0x8679, 0xFBF6, 0x868A, 0xDAA5, 0x868C, 0xDBBD, 0x8693, 0xECE2, 0x86A3, 0xCDF7, 0x86A4, 0xF0DE, 0x86A9, 0xF6C9, 0x86C7, 0xDEEF, 0x86CB, 0xD3B1, 0x86D4, 0xFCEE, 0x86D9, 0xE8C3, 0x86DB, 0xF1C8, 0x86DF, 0xCEF1, 0x86E4, 0xF9ED, 0x86ED, 0xF2F4, 0x86FE, 0xE4B6, 0x8700, 0xF5B9, 0x8702, 0xDCF0, 0x8703, 0xE3F1, 0x8708, 0xE8A5, 0x8718, 0xF2BB, 0x871A, 0xDEA4, 0x871C, 0xDACC, 0x874E, 0xCAE9, 0x8755, 0xE3DA, 0x8757, 0xFCD9, 0x875F, 0xEADA, 0x8766, 0xF9C4, 0x8768, 0xE3A4, 0x8774, 0xFBDD, 0x8776, 0xEFCA, 0x8778, 0xE8C4, 0x8782, 0xD5CC, 0x878D, 0xEBD7, 0x879F, 0xD9AD, 0x87A2, 0xFBAB, 0x87B3, 0xD3D9, 0x87BA, 0xD5A2, 0x87C4, 0xF6DE, 0x87E0, 0xDAF6, 0x87EC, 0xE0D1, 0x87EF, 0xE9A8, 0x87F2, 0xF5F9, 0x87F9, 0xFAAF, 0x87FB, 0xEBFC, 0x87FE, 0xE0EA, 0x8805, 0xE3B2, 0x881F, 0xD5C5, 0x8822, 0xF1E3, 0x8823, 0xD5EE, 0x8831, 0xCDCC, 0x8836, 0xEDD9, 0x883B, 0xD8C1, 0x8840, 0xFAEC, 0x8846, 0xF1EB, 0x884C, 0xFABC, 0x884D, 0xE6E2, 0x8852, 0xFAE5, 0x8853, 0xE2FA, 0x8857, 0xCAB6, 0x8859, 0xE4B7, 0x885B, 0xEADB, 0x885D, 0xF5FA, 0x8861, 0xFBAC, 0x8862, 0xCFC3, 0x8863, 0xEBFD, 0x8868, 0xF8FA, 0x886B, 0xDFB9, 0x8870, 0xE1F1, 0x8872, 0xD2A4, 0x8877, 0xF5FB, 0x887E, 0xD0DA, 0x887F, 0xD0DB, 0x8881, 0xEABE, 0x8882, 0xD9B1, 0x8888, 0xCAB7, 0x888B, 0xD3E7, 0x888D, 0xF8E5, 0x8892, 0xD3B2, 0x8896, 0xE2C0, 0x8897, 0xF2DF, 0x889E, 0xCDE5, 0x88AB, 0xF9AC, 0x88B4, 0xCDCD, 0x88C1, 0xEEAE, 0x88C2, 0xD6AE, 0x88CF, 0xD7EA, 0x88D4, 0xE7E0, 0x88D5, 0xEBAE, 0x88D9, 0xCFD9, 0x88DC, 0xDCCD, 0x88DD, 0xEDFB, 0x88DF, 0xDEF0, 0x88E1, 0xD7EB, 0x88E8, 0xDEA5, 0x88F3, 0xDFD7, 0x88F4, 0xDBD0, 0x88F5, 0xDBD1, 0x88F8, 0xD5A3, 0x88FD, 0xF0B2, 0x8907, 0xDCDC, 0x8910, 0xCAE8, 0x8912, 0xF8E6, 0x8913, 0xDCCE, 0x8918, 0xEADC, 0x8919, 0xDBD2, 0x8925, 0xE9B3, 0x892A, 0xF7DB, 0x8936, 0xE3A8, 0x8938, 0xD7AE, 0x893B, 0xE0E1, 0x8941, 0xCBBA, 0x8944, 0xE5D1, 0x895F, 0xD0DC, 0x8964, 0xD5C1, 0x896A, 0xD8CA, 0x8972, 0xE3A9, 0x897F, 0xE0A4, 0x8981, 0xE9A9, 0x8983, 0xD3C7, 0x8986, 0xDCDD, 0x8987, 0xF8AE, 0x898B, 0xCCB8, 0x898F, 0xD0AE, 0x8993, 0xD8F2, 0x8996, 0xE3CA, 0x89A1, 0xCCAF, 0x89A9, 0xD4AD, 0x89AA, 0xF6D1, 0x89B2, 0xD0CC, 0x89BA, 0xCAC6, 0x89BD, 0xD5C2, 0x89C0, 0xCEBA, 0x89D2, 0xCAC7, 0x89E3, 0xFAB0, 0x89F4, 0xDFD8, 0x89F8, 0xF5BA, 0x8A00, 0xE5EB, 0x8A02, 0xEFF4, 0x8A03, 0xDDB5, 0x8A08, 0xCDAA, 0x8A0A, 0xE3F2, 0x8A0C, 0xFBF7, 0x8A0E, 0xF7D0, 0x8A13, 0xFDBA, 0x8A16, 0xFDE1, 0x8A17, 0xF6FE, 0x8A18, 0xD1C0, 0x8A1B, 0xE8C5, 0x8A1D, 0xE4B8, 0x8A1F, 0xE1E8, 0x8A23, 0xCCC1, 0x8A25, 0xD2ED, 0x8A2A, 0xDBBE, 0x8A2D, 0xE0E2, 0x8A31, 0xFAC9, 0x8A34, 0xE1CD, 0x8A36, 0xCAB8, 0x8A3A, 0xF2E0, 0x8A3B, 0xF1C9, 0x8A50, 0xDEF1, 0x8A54, 0xF0DF, 0x8A55, 0xF8C4, 0x8A5B, 0xEECC, 0x8A5E, 0xDEF2, 0x8A60, 0xE7C9, 0x8A62, 0xE2F3, 0x8A63, 0xE7E1, 0x8A66, 0xE3CB, 0x8A69, 0xE3CC, 0x8A6D, 0xCFF8, 0x8A6E, 0xEFAC, 0x8A70, 0xFDFE, 0x8A71, 0xFCA5, 0x8A72, 0xFAB1, 0x8A73, 0xDFD9, 0x8A75, 0xE0D2, 0x8A79, 0xF4DA, 0x8A85, 0xF1CA, 0x8A87, 0xCEA3, 0x8A8C, 0xF2BC, 0x8A8D, 0xECE3, 0x8A93, 0xE0A5, 0x8A95, 0xF7AB, 0x8A98, 0xEBAF, 0x8A9E, 0xE5DE, 0x8AA0, 0xE1A4, 0x8AA1, 0xCDAB, 0x8AA3, 0xD9F4, 0x8AA4, 0xE8A6, 0x8AA5, 0xCDCE, 0x8AA6, 0xE1E9, 0x8AA8, 0xFCEF, 0x8AAA, 0xE0E3, 0x8AB0, 0xE2C1, 0x8AB2, 0xCEA4, 0x8AB9, 0xDEA6, 0x8ABC, 0xEBFE, 0x8ABE, 0xEBDD, 0x8ABF, 0xF0E0, 0x8AC2, 0xF4DB, 0x8AC4, 0xE2F4, 0x8AC7, 0xD3C8, 0x8ACB, 0xF4EB, 0x8ACD, 0xEEB5, 0x8ACF, 0xF5D8, 0x8AD2, 0xD5DF, 0x8AD6, 0xD6E5, 0x8ADB, 0xEBB0, 0x8ADC, 0xF4E3, 0x8AE1, 0xE3CD, 0x8AE6, 0xF4F4, 0x8AE7, 0xFAB2, 0x8AEA, 0xEFF5, 0x8AEB, 0xCADF, 0x8AED, 0xEBB1, 0x8AEE, 0xEDBF, 0x8AF1, 0xFDC9, 0x8AF6, 0xE4A6, 0x8AF7, 0xF9A4, 0x8AF8, 0xF0B3, 0x8AFA, 0xE5EC, 0x8AFE, 0xD1E7, 0x8B00, 0xD9C7, 0x8B01, 0xE4D7, 0x8B02, 0xEADD, 0x8B04, 0xD4F7, 0x8B0E, 0xDABA, 0x8B10, 0xDACD, 0x8B14, 0xF9CC, 0x8B16, 0xE1DA, 0x8B17, 0xDBBF, 0x8B19, 0xCCC5, 0x8B1A, 0xECD0, 0x8B1B, 0xCBBB, 0x8B1D, 0xDEF3, 0x8B20, 0xE9AA, 0x8B28, 0xD9C8, 0x8B2B, 0xEEE3, 0x8B2C, 0xD7BD, 0x8B33, 0xCFC4, 0x8B39, 0xD0CD, 0x8B41, 0xFCA6, 0x8B49, 0xF1FB, 0x8B4E, 0xFDD2, 0x8B4F, 0xD1C1, 0x8B58, 0xE3DB, 0x8B5A, 0xD3C9, 0x8B5C, 0xDCCF, 0x8B66, 0xCCED, 0x8B6C, 0xDEA7, 0x8B6F, 0xE6BB, 0x8B70, 0xECA1, 0x8B74, 0xCCB9, 0x8B77, 0xFBDE, 0x8B7D, 0xE7E2, 0x8B80, 0xD4C1, 0x8B8A, 0xDCA8, 0x8B90, 0xE2C2, 0x8B92, 0xF3D8, 0x8B93, 0xE5D3, 0x8B96, 0xF3D9, 0x8B9A, 0xF3C6, 0x8C37, 0xCDDB, 0x8C3F, 0xCDAC, 0x8C41, 0xFCC3, 0x8C46, 0xD4E7, 0x8C48, 0xD1C2, 0x8C4A, 0xF9A5, 0x8C4C, 0xE8D5, 0x8C55, 0xE3CE, 0x8C5A, 0xD4CA, 0x8C61, 0xDFDA, 0x8C6A, 0xFBDF, 0x8C6B, 0xE7E3, 0x8C79, 0xF8FB, 0x8C7A, 0xE3CF, 0x8C82, 0xF5B0, 0x8C8A, 0xD8E7, 0x8C8C, 0xD9C9, 0x8C9D, 0xF8AF, 0x8C9E, 0xEFF6, 0x8CA0, 0xDDB6, 0x8CA1, 0xEEAF, 0x8CA2, 0xCDF8, 0x8CA7, 0xDEB8, 0x8CA8, 0xFCA7, 0x8CA9, 0xF7FC, 0x8CAA, 0xF7B1, 0x8CAB, 0xCEBB, 0x8CAC, 0xF4A1, 0x8CAF, 0xEECD, 0x8CB0, 0xE1AE, 0x8CB3, 0xECC3, 0x8CB4, 0xCFFE, 0x8CB6, 0xF8BF, 0x8CB7, 0xD8E2, 0x8CB8, 0xD3E8, 0x8CBB, 0xDEA8, 0x8CBC, 0xF4E4, 0x8CBD, 0xECC2, 0x8CBF, 0xD9F5, 0x8CC0, 0xF9C5, 0x8CC1, 0xDDD3, 0x8CC2, 0xD6F1, 0x8CC3, 0xECFC, 0x8CC4, 0xFCF0, 0x8CC7, 0xEDC0, 0x8CC8, 0xCAB9, 0x8CCA, 0xEEE4, 0x8CD1, 0xF2E1, 0x8CD3, 0xDEB9, 0x8CDA, 0xD6F2, 0x8CDC, 0xDEF4, 0x8CDE, 0xDFDB, 0x8CE0, 0xDBD3, 0x8CE2, 0xFAE7, 0x8CE3, 0xD8E3, 0x8CE4, 0xF4C1, 0x8CE6, 0xDDB7, 0x8CEA, 0xF2F5, 0x8CED, 0xD4AE, 0x8CF4, 0xD6F3, 0x8CFB, 0xDDB8, 0x8CFC, 0xCFC5, 0x8CFD, 0xDFDF, 0x8D04, 0xF2BE, 0x8D05, 0xF6A1, 0x8D07, 0xEBCB, 0x8D08, 0xF1FC, 0x8D0A, 0xF3C7, 0x8D0D, 0xE0EB, 0x8D13, 0xEDFC, 0x8D16, 0xE1DB, 0x8D64, 0xEEE5, 0x8D66, 0xDEF5, 0x8D6B, 0xFAD3, 0x8D70, 0xF1CB, 0x8D73, 0xD0AF, 0x8D74, 0xDDB9, 0x8D77, 0xD1C3, 0x8D85, 0xF5B1, 0x8D8A, 0xEAC6, 0x8D99, 0xF0E1, 0x8DA3, 0xF6AC, 0x8DA8, 0xF5D9, 0x8DB3, 0xF0EB, 0x8DBA, 0xDDBA, 0x8DBE, 0xF2BF, 0x8DC6, 0xF7C5, 0x8DCB, 0xDBA2, 0x8DCC, 0xF2F6, 0x8DCF, 0xCABA, 0x8DDB, 0xF7F5, 0x8DDD, 0xCBE5, 0x8DE1, 0xEEE6, 0x8DE3, 0xE0D3, 0x8DE8, 0xCEA5, 0x8DEF, 0xD6D8, 0x8DF3, 0xD4AF, 0x8E0A, 0xE9C9, 0x8E0F, 0xD3CE, 0x8E10, 0xF4C2, 0x8E1E, 0xCBE6, 0x8E2A, 0xF1A1, 0x8E30, 0xEBB2, 0x8E35, 0xF1A2, 0x8E42, 0xEBB3, 0x8E44, 0xF0B4, 0x8E47, 0xCBF4, 0x8E48, 0xD4B0, 0x8E49, 0xF3B2, 0x8E4A, 0xFBB7, 0x8E59, 0xF5EC, 0x8E5F, 0xEEE7, 0x8E60, 0xF4B2, 0x8E74, 0xF5ED, 0x8E76, 0xCFF3, 0x8E81, 0xF0E2, 0x8E87, 0xEECE, 0x8E8A, 0xF1CC, 0x8E8D, 0xE5B8, 0x8EAA, 0xD7F5, 0x8EAB, 0xE3F3, 0x8EAC, 0xCFE5, 0x8EC0, 0xCFC6, 0x8ECA, 0xF3B3, 0x8ECB, 0xE4D8, 0x8ECC, 0xCFF9, 0x8ECD, 0xCFDA, 0x8ED2, 0xFACD, 0x8EDF, 0xE6E3, 0x8EEB, 0xF2E2, 0x8EF8, 0xF5EE, 0x8EFB, 0xCABB, 0x8EFE, 0xE3DC, 0x8F03, 0xCEF2, 0x8F05, 0xD6D9, 0x8F09, 0xEEB0, 0x8F12, 0xF4E5, 0x8F13, 0xD8C2, 0x8F14, 0xDCD0, 0x8F15, 0xCCEE, 0x8F1B, 0xD5E0, 0x8F1C, 0xF6CA, 0x8F1D, 0xFDCA, 0x8F1E, 0xD8D6, 0x8F1F, 0xF4CF, 0x8F26, 0xD6A6, 0x8F27, 0xDCBE, 0x8F29, 0xDBD4, 0x8F2A, 0xD7C7, 0x8F2F, 0xF2FE, 0x8F33, 0xF1CD, 0x8F38, 0xE2C3, 0x8F39, 0xDCDE, 0x8F3B, 0xDCDF, 0x8F3E, 0xEFAD, 0x8F3F, 0xE6AB, 0x8F44, 0xF9DD, 0x8F45, 0xEABF, 0x8F49, 0xEFAE, 0x8F4D, 0xF4D0, 0x8F4E, 0xCEF3, 0x8F5D, 0xE6AC, 0x8F5F, 0xCEDE, 0x8F62, 0xD5F9, 0x8F9B, 0xE3F4, 0x8F9C, 0xCDD0, 0x8FA3, 0xD5B8, 0x8FA6, 0xF7FD, 0x8FA8, 0xDCA9, 0x8FAD, 0xDEF6, 0x8FAF, 0xDCAA, 0x8FB0, 0xF2E3, 0x8FB1, 0xE9B4, 0x8FB2, 0xD2DC, 0x8FC2, 0xE9E6, 0x8FC5, 0xE3F6, 0x8FCE, 0xE7CA, 0x8FD1, 0xD0CE, 0x8FD4, 0xDAF7, 0x8FE6, 0xCABC, 0x8FEA, 0xEEE8, 0x8FEB, 0xDADE, 0x8FED, 0xF2F7, 0x8FF0, 0xE2FB, 0x8FF2, 0xCCA6, 0x8FF7, 0xDABB, 0x8FF9, 0xEEE9, 0x8FFD, 0xF5DA, 0x9000, 0xF7DC, 0x9001, 0xE1EA, 0x9002, 0xCEC1, 0x9003, 0xD4B1, 0x9005, 0xFDB1, 0x9006, 0xE6BD, 0x9008, 0xFBAD, 0x900B, 0xF8E7, 0x900D, 0xE1CE, 0x900F, 0xF7E2, 0x9010, 0xF5EF, 0x9011, 0xCFC7, 0x9014, 0xD4B2, 0x9015, 0xCCEF, 0x9017, 0xD4E8, 0x9019, 0xEECF, 0x901A, 0xF7D7, 0x901D, 0xE0A6, 0x901E, 0xD6C1, 0x901F, 0xE1DC, 0x9020, 0xF0E3, 0x9021, 0xF1E4, 0x9022, 0xDCF1, 0x9023, 0xD6A7, 0x902E, 0xF4F5, 0x9031, 0xF1CE, 0x9032, 0xF2E4, 0x9035, 0xD0B0, 0x9038, 0xECEF, 0x903C, 0xF9BA, 0x903E, 0xEBB5, 0x9041, 0xD4ED, 0x9042, 0xE2C4, 0x9047, 0xE9E7, 0x904A, 0xEBB4, 0x904B, 0xEAA1, 0x904D, 0xF8BC, 0x904E, 0xCEA6, 0x9050, 0xF9C6, 0x9051, 0xFCDA, 0x9053, 0xD4B3, 0x9054, 0xD3B9, 0x9055, 0xEADE, 0x9059, 0xE9AB, 0x905C, 0xE1E1, 0x905D, 0xD3CF, 0x905E, 0xF4F6, 0x9060, 0xEAC0, 0x9061, 0xE1CF, 0x9063, 0xCCBA, 0x9069, 0xEEEA, 0x906D, 0xF0E4, 0x906E, 0xF3B4, 0x906F, 0xD4EE, 0x9072, 0xF2C0, 0x9075, 0xF1E5, 0x9077, 0xF4C3, 0x9078, 0xE0D4, 0x907A, 0xEBB6, 0x907C, 0xD7A1, 0x907D, 0xCBE8, 0x907F, 0xF9AD, 0x9080, 0xE9AD, 0x9081, 0xD8E4, 0x9082, 0xFAB3, 0x9083, 0xE2C5, 0x9084, 0xFCBD, 0x9087, 0xECC4, 0x9088, 0xD8B1, 0x908A, 0xDCAB, 0x908F, 0xD5A4, 0x9091, 0xEBE9, 0x9095, 0xE8BB, 0x9099, 0xD8D7, 0x90A2, 0xFBAE, 0x90A3, 0xD1E1, 0x90A6, 0xDBC0, 0x90A8, 0xF5BE, 0x90AA, 0xDEF7, 0x90AF, 0xCAFB, 0x90B0, 0xF7C6, 0x90B1, 0xCFC8, 0x90B5, 0xE1D0, 0x90B8, 0xEED0, 0x90C1, 0xE9F4, 0x90CA, 0xCEF4, 0x90DE, 0xD5CD, 0x90E1, 0xCFDB, 0x90E8, 0xDDBB, 0x90ED, 0xCEAC, 0x90F5, 0xE9E8, 0x90FD, 0xD4B4, 0x9102, 0xE4C7, 0x9112, 0xF5DB, 0x9115, 0xFAC1, 0x9119, 0xDEA9, 0x9127, 0xD4F8, 0x912D, 0xEFF7, 0x9132, 0xD3B3, 0x9149, 0xEBB7, 0x914A, 0xEFF8, 0x914B, 0xF5DC, 0x914C, 0xEDCC, 0x914D, 0xDBD5, 0x914E, 0xF1CF, 0x9152, 0xF1D0, 0x9162, 0xF5B2, 0x9169, 0xD9AE, 0x916A, 0xD5AC, 0x916C, 0xE2C6, 0x9175, 0xFDA3, 0x9177, 0xFBE5, 0x9178, 0xDFAB, 0x9187, 0xE2F5, 0x9189, 0xF6AD, 0x918B, 0xF5B3, 0x918D, 0xF0B5, 0x9192, 0xE1A5, 0x919C, 0xF5DD, 0x91AB, 0xECA2, 0x91AC, 0xEDFD, 0x91AE, 0xF5B4, 0x91AF, 0xFBB8, 0x91B1, 0xDBA3, 0x91B4, 0xD6CA, 0x91B5, 0xCBD9, 0x91C0, 0xE5D4, 0x91C7, 0xF3FA, 0x91C9, 0xEBB8, 0x91CB, 0xE0B7, 0x91CC, 0xD7EC, 0x91CD, 0xF1EC, 0x91CE, 0xE5AF, 0x91CF, 0xD5E1, 0x91D0, 0xD7ED, 0x91D1, 0xD1D1, 0x91D7, 0xE1F2, 0x91D8, 0xEFF9, 0x91DC, 0xDDBC, 0x91DD, 0xF6DC, 0x91E3, 0xF0E5, 0x91E7, 0xF4C4, 0x91EA, 0xE9E9, 0x91F5, 0xF3FB, 0x920D, 0xD4EF, 0x9210, 0xCCA2, 0x9211, 0xF7FE, 0x9212, 0xDFBC, 0x9217, 0xEBCD, 0x921E, 0xD0B7, 0x9234, 0xD6C2, 0x923A, 0xE8AD, 0x923F, 0xEFAF, 0x9240, 0xCBA5, 0x9245, 0xCBE9, 0x9249, 0xFAE8, 0x9257, 0xCCC6, 0x925B, 0xE6E7, 0x925E, 0xEAC7, 0x9262, 0xDBA4, 0x9264, 0xCFC9, 0x9265, 0xE2FC, 0x9266, 0xEFFA, 0x9280, 0xEBDE, 0x9283, 0xF5C8, 0x9285, 0xD4DE, 0x9291, 0xE0D5, 0x9293, 0xEFB0, 0x9296, 0xE2C7, 0x9298, 0xD9AF, 0x929C, 0xF9E7, 0x92B3, 0xE7E5, 0x92B6, 0xCFCA, 0x92B7, 0xE1D1, 0x92B9, 0xE2C8, 0x92CC, 0xEFFB, 0x92CF, 0xFAF9, 0x92D2, 0xDCF2, 0x92E4, 0xE0A7, 0x92EA, 0xF8E8, 0x92F8, 0xCBEA, 0x92FC, 0xCBBC, 0x9304, 0xD6E2, 0x9310, 0xF5DE, 0x9318, 0xF5DF, 0x931A, 0xEEB6, 0x931E, 0xE2F6, 0x931F, 0xD3CA, 0x9320, 0xEFFC, 0x9321, 0xD1C4, 0x9322, 0xEFB1, 0x9324, 0xD1C5, 0x9326, 0xD0DE, 0x9328, 0xD9E1, 0x932B, 0xE0B8, 0x932E, 0xCDD1, 0x932F, 0xF3B9, 0x9348, 0xE7CC, 0x934A, 0xD6A8, 0x934B, 0xCEA7, 0x934D, 0xD4B5, 0x9354, 0xE4C8, 0x935B, 0xD3B4, 0x936E, 0xEBB9, 0x9375, 0xCBF5, 0x937C, 0xF6DD, 0x937E, 0xF1A3, 0x938C, 0xCCC7, 0x9394, 0xE9CA, 0x9396, 0xE1F0, 0x939A, 0xF5E0, 0x93A3, 0xFBAF, 0x93A7, 0xCBD1, 0x93AC, 0xFBE0, 0x93AD, 0xF2E5, 0x93B0, 0xECF0, 0x93C3, 0xF0EC, 0x93D1, 0xEEEB, 0x93DE, 0xE9CB, 0x93E1, 0xCCF0, 0x93E4, 0xD7AF, 0x93F6, 0xF3A1, 0x9404, 0xFCF5, 0x9418, 0xF1A4, 0x9425, 0xE0D6, 0x942B, 0xEFB2, 0x9435, 0xF4D1, 0x9438, 0xF7A1, 0x9444, 0xF1D1, 0x9451, 0xCAFC, 0x9452, 0xCAFD, 0x945B, 0xCECE, 0x947D, 0xF3C8, 0x947F, 0xF3BA, 0x9577, 0xEDFE, 0x9580, 0xDAA6, 0x9583, 0xE0EC, 0x9589, 0xF8CD, 0x958B, 0xCBD2, 0x958F, 0xEBCE, 0x9591, 0xF9D8, 0x9592, 0xF9D9, 0x9593, 0xCAE0, 0x9594, 0xDACA, 0x9598, 0xCBA6, 0x95A3, 0xCAC8, 0x95A4, 0xF9EE, 0x95A5, 0xDBEC, 0x95A8, 0xD0B1, 0x95AD, 0xD5EF, 0x95B1, 0xE6F3, 0x95BB, 0xE7A2, 0x95BC, 0xE4D9, 0x95C7, 0xE4E1, 0x95CA, 0xFCC4, 0x95D4, 0xF9EF, 0x95D5, 0xCFF4, 0x95D6, 0xF7E6, 0x95DC, 0xCEBC, 0x95E1, 0xF4C5, 0x95E2, 0xDCA3, 0x961C, 0xDDBD, 0x9621, 0xF4C6, 0x962A, 0xF8A1, 0x962E, 0xE8D6, 0x9632, 0xDBC1, 0x963B, 0xF0E6, 0x963F, 0xE4B9, 0x9640, 0xF6ED, 0x9642, 0xF9AE, 0x9644, 0xDDBE, 0x964B, 0xD7B0, 0x964C, 0xD8E8, 0x964D, 0xCBBD, 0x9650, 0xF9DA, 0x965B, 0xF8CE, 0x965C, 0xF9F0, 0x965D, 0xE0ED, 0x965E, 0xE3B3, 0x965F, 0xF4B3, 0x9662, 0xEAC2, 0x9663, 0xF2E6, 0x9664, 0xF0B6, 0x966A, 0xDBD6, 0x9670, 0xEBE4, 0x9673, 0xF2E7, 0x9675, 0xD7D5, 0x9676, 0xD4B6, 0x9677, 0xF9E8, 0x9678, 0xD7C1, 0x967D, 0xE5D5, 0x9685, 0xE9EA, 0x9686, 0xD7CC, 0x968A, 0xD3E9, 0x968B, 0xE2C9, 0x968D, 0xFCDB, 0x968E, 0xCDAD, 0x9694, 0xCCB0, 0x9695, 0xEAA2, 0x9698, 0xE4F6, 0x9699, 0xD0C0, 0x969B, 0xF0B7, 0x969C, 0xEEA1, 0x96A3, 0xD7F6, 0x96A7, 0xE2CA, 0x96A8, 0xE2CB, 0x96AA, 0xFACF, 0x96B1, 0xEBDF, 0x96B7, 0xD6CB, 0x96BB, 0xF4B4, 0x96C0, 0xEDCD, 0x96C1, 0xE4D2, 0x96C4, 0xEAA9, 0x96C5, 0xE4BA, 0x96C6, 0xF3A2, 0x96C7, 0xCDD2, 0x96C9, 0xF6CB, 0x96CB, 0xF1E6, 0x96CC, 0xEDC1, 0x96CD, 0xE8BC, 0x96CE, 0xEED1, 0x96D5, 0xF0E7, 0x96D6, 0xE2CC, 0x96D9, 0xE4AA, 0x96DB, 0xF5E1, 0x96DC, 0xEDDA, 0x96E2, 0xD7EE, 0x96E3, 0xD1F1, 0x96E8, 0xE9EB, 0x96E9, 0xE9EC, 0x96EA, 0xE0E4, 0x96EF, 0xDAA7, 0x96F0, 0xDDD4, 0x96F2, 0xEAA3, 0x96F6, 0xD6C3, 0x96F7, 0xD6F4, 0x96F9, 0xDADF, 0x96FB, 0xEFB3, 0x9700, 0xE2CD, 0x9706, 0xEFFD, 0x9707, 0xF2E8, 0x9711, 0xEFC5, 0x9713, 0xE7E7, 0x9716, 0xD7FD, 0x9719, 0xE7CE, 0x971C, 0xDFDC, 0x971E, 0xF9C7, 0x9727, 0xD9F6, 0x9730, 0xDFAC, 0x9732, 0xD6DA, 0x9739, 0xDCA4, 0x973D, 0xF0B8, 0x9742, 0xD5FA, 0x9744, 0xE4F7, 0x9748, 0xD6C4, 0x9751, 0xF4EC, 0x9756, 0xEFFE, 0x975C, 0xF0A1, 0x975E, 0xDEAA, 0x9761, 0xDABC, 0x9762, 0xD8FC, 0x9769, 0xFAD4, 0x976D, 0xECE5, 0x9774, 0xFCA8, 0x9777, 0xECE6, 0x977A, 0xD8CB, 0x978B, 0xFBB9, 0x978D, 0xE4D3, 0x978F, 0xCDF9, 0x97A0, 0xCFD3, 0x97A8, 0xCAEA, 0x97AB, 0xCFD4, 0x97AD, 0xF8BD, 0x97C6, 0xF4C7, 0x97CB, 0xEADF, 0x97D3, 0xF9DB, 0x97DC, 0xD4B7, 0x97F3, 0xEBE5, 0x97F6, 0xE1D2, 0x97FB, 0xEAA4, 0x97FF, 0xFAC2, 0x9800, 0xFBE1, 0x9801, 0xFAED, 0x9802, 0xF0A2, 0x9803, 0xCCF1, 0x9805, 0xFAA3, 0x9806, 0xE2F7, 0x9808, 0xE2CE, 0x980A, 0xE9F5, 0x980C, 0xE1EB, 0x9810, 0xE7E8, 0x9811, 0xE8D7, 0x9812, 0xDAF8, 0x9813, 0xD4CB, 0x9817, 0xF7F6, 0x9818, 0xD6C5, 0x982D, 0xD4E9, 0x9830, 0xFAFA, 0x9838, 0xCCF2, 0x9839, 0xF7DD, 0x983B, 0xDEBA, 0x9846, 0xCEA8, 0x984C, 0xF0B9, 0x984D, 0xE4FE, 0x984E, 0xE4C9, 0x9854, 0xE4D4, 0x9858, 0xEAC3, 0x985A, 0xEFB4, 0x985E, 0xD7BE, 0x9865, 0xFBE2, 0x9867, 0xCDD3, 0x986B, 0xEFB5, 0x986F, 0xFAE9, 0x98A8, 0xF9A6, 0x98AF, 0xDFBD, 0x98B1, 0xF7C7, 0x98C4, 0xF8FD, 0x98C7, 0xF8FC, 0x98DB, 0xDEAB, 0x98DC, 0xDBE8, 0x98DF, 0xE3DD, 0x98E1, 0xE1E2, 0x98E2, 0xD1C6, 0x98ED, 0xF6D0, 0x98EE, 0xEBE6, 0x98EF, 0xDAF9, 0x98F4, 0xECC7, 0x98FC, 0xDEF8, 0x98FD, 0xF8E9, 0x98FE, 0xE3DE, 0x9903, 0xCEF5, 0x9909, 0xFAC3, 0x990A, 0xE5D7, 0x990C, 0xECC8, 0x9910, 0xF3C9, 0x9913, 0xE4BB, 0x9918, 0xE6AE, 0x991E, 0xEFB6, 0x9920, 0xDCBF, 0x9928, 0xCEBD, 0x9945, 0xD8C3, 0x9949, 0xD0CF, 0x994B, 0xCFFA, 0x994C, 0xF3CA, 0x994D, 0xE0D7, 0x9951, 0xD1C7, 0x9952, 0xE9AE, 0x9954, 0xE8BD, 0x9957, 0xFAC4, 0x9996, 0xE2CF, 0x9999, 0xFAC5, 0x999D, 0xF9B8, 0x99A5, 0xDCE0, 0x99A8, 0xFBB0, 0x99AC, 0xD8A9, 0x99AD, 0xE5DF, 0x99AE, 0xF9A7, 0x99B1, 0xF6EE, 0x99B3, 0xF6CC, 0x99B4, 0xE2F8, 0x99B9, 0xECF1, 0x99C1, 0xDAE0, 0x99D0, 0xF1D2, 0x99D1, 0xD2CC, 0x99D2, 0xCFCB, 0x99D5, 0xCABD, 0x99D9, 0xDDBF, 0x99DD, 0xF6EF, 0x99DF, 0xDEF9, 0x99ED, 0xFAB4, 0x99F1, 0xD5AD, 0x99FF, 0xF1E7, 0x9A01, 0xDEBE, 0x9A08, 0xDCC0, 0x9A0E, 0xD1C8, 0x9A0F, 0xD1C9, 0x9A19, 0xF8BE, 0x9A2B, 0xCBF6, 0x9A30, 0xD4F9, 0x9A36, 0xF5E2, 0x9A37, 0xE1D3, 0x9A40, 0xD8E9, 0x9A43, 0xF8FE, 0x9A45, 0xCFCC, 0x9A4D, 0xFDA4, 0x9A55, 0xCEF6, 0x9A57, 0xFAD0, 0x9A5A, 0xCCF3, 0x9A5B, 0xE6BE, 0x9A5F, 0xF6AE, 0x9A62, 0xD5F0, 0x9A65, 0xD1CA, 0x9A69, 0xFCBE, 0x9A6A, 0xD5F1, 0x9AA8, 0xCDE9, 0x9AB8, 0xFAB5, 0x9AD3, 0xE2D0, 0x9AD4, 0xF4F7, 0x9AD8, 0xCDD4, 0x9AE5, 0xE7A3, 0x9AEE, 0xDBA5, 0x9B1A, 0xE2D1, 0x9B27, 0xD7A2, 0x9B2A, 0xF7E3, 0x9B31, 0xEAA6, 0x9B3C, 0xD0A1, 0x9B41, 0xCEDA, 0x9B42, 0xFBEB, 0x9B43, 0xDBA6, 0x9B44, 0xDBDE, 0x9B45, 0xD8E5, 0x9B4F, 0xEAE0, 0x9B54, 0xD8AA, 0x9B5A, 0xE5E0, 0x9B6F, 0xD6DB, 0x9B8E, 0xEFC6, 0x9B91, 0xF8EA, 0x9B9F, 0xE4D5, 0x9BAB, 0xCEF7, 0x9BAE, 0xE0D8, 0x9BC9, 0xD7EF, 0x9BD6, 0xF4ED, 0x9BE4, 0xCDE6, 0x9BE8, 0xCCF4, 0x9C0D, 0xF5E3, 0x9C10, 0xE4CA, 0x9C12, 0xDCE1, 0x9C15, 0xF9C8, 0x9C25, 0xFCBF, 0x9C32, 0xE8A7, 0x9C3B, 0xD8C4, 0x9C47, 0xCBBE, 0x9C49, 0xDCAE, 0x9C57, 0xD7F7, 0x9CE5, 0xF0E8, 0x9CE7, 0xDDC0, 0x9CE9, 0xCFCD, 0x9CF3, 0xDCF3, 0x9CF4, 0xD9B0, 0x9CF6, 0xE6E9, 0x9D09, 0xE4BC, 0x9D1B, 0xEAC4, 0x9D26, 0xE4EC, 0x9D28, 0xE4E5, 0x9D3B, 0xFBF8, 0x9D51, 0xCCBB, 0x9D5D, 0xE4BD, 0x9D60, 0xCDDC, 0x9D61, 0xD9F7, 0x9D6C, 0xDDDF, 0x9D72, 0xEDCE, 0x9DA9, 0xD9D0, 0x9DAF, 0xE5A3, 0x9DB4, 0xF9CD, 0x9DC4, 0xCDAE, 0x9DD7, 0xCFCE, 0x9DF2, 0xF6AF, 0x9DF8, 0xFDD3, 0x9DF9, 0xEBED, 0x9DFA, 0xD6DC, 0x9E1A, 0xE5A4, 0x9E1E, 0xD5B6, 0x9E75, 0xD6DD, 0x9E79, 0xF9E9, 0x9E7D, 0xE7A4, 0x9E7F, 0xD6E3, 0x9E92, 0xD1CB, 0x9E93, 0xD6E4, 0x9E97, 0xD5F2, 0x9E9D, 0xDEFA, 0x9E9F, 0xD7F8, 0x9EA5, 0xD8EA, 0x9EB4, 0xCFD5, 0x9EB5, 0xD8FD, 0x9EBB, 0xD8AB, 0x9EBE, 0xFDCB, 0x9EC3, 0xFCDC, 0x9ECD, 0xE0A8, 0x9ECE, 0xD5F3, 0x9ED1, 0xFDD9, 0x9ED4, 0xCCA3, 0x9ED8, 0xD9F9, 0x9EDB, 0xD3EA, 0x9EDC, 0xF5F5, 0x9EDE, 0xEFC7, 0x9EE8, 0xD3DA, 0x9EF4, 0xDABD, 0x9F07, 0xE8A8, 0x9F08, 0xDCAF, 0x9F0E, 0xF0A3, 0x9F13, 0xCDD5, 0x9F20, 0xE0A9, 0x9F3B, 0xDEAC, 0x9F4A, 0xF0BA, 0x9F4B, 0xEEB1, 0x9F4E, 0xEEB2, 0x9F52, 0xF6CD, 0x9F5F, 0xEED2, 0x9F61, 0xD6C6, 0x9F67, 0xE0E5, 0x9F6A, 0xF3BB, 0x9F6C, 0xE5E1, 0x9F77, 0xE4CB, 0x9F8D, 0xD7A3, 0x9F90, 0xDBC2, 0x9F95, 0xCAFE, 0x9F9C, 0xCFCF, 0xAC00, 0xB0A1, 0xAC01, 0xB0A2, 0xAC02, 0x8141, 0xAC03, 0x8142, 0xAC04, 0xB0A3, 0xAC05, 0x8143, 0xAC06, 0x8144, 0xAC07, 0xB0A4, 0xAC08, 0xB0A5, 0xAC09, 0xB0A6, 0xAC0A, 0xB0A7, 0xAC0B, 0x8145, 0xAC0C, 0x8146, 0xAC0D, 0x8147, 0xAC0E, 0x8148, 0xAC0F, 0x8149, 0xAC10, 0xB0A8, 0xAC11, 0xB0A9, 0xAC12, 0xB0AA, 0xAC13, 0xB0AB, 0xAC14, 0xB0AC, 0xAC15, 0xB0AD, 0xAC16, 0xB0AE, 0xAC17, 0xB0AF, 0xAC18, 0x814A, 0xAC19, 0xB0B0, 0xAC1A, 0xB0B1, 0xAC1B, 0xB0B2, 0xAC1C, 0xB0B3, 0xAC1D, 0xB0B4, 0xAC1E, 0x814B, 0xAC1F, 0x814C, 0xAC20, 0xB0B5, 0xAC21, 0x814D, 0xAC22, 0x814E, 0xAC23, 0x814F, 0xAC24, 0xB0B6, 0xAC25, 0x8150, 0xAC26, 0x8151, 0xAC27, 0x8152, 0xAC28, 0x8153, 0xAC29, 0x8154, 0xAC2A, 0x8155, 0xAC2B, 0x8156, 0xAC2C, 0xB0B7, 0xAC2D, 0xB0B8, 0xAC2E, 0x8157, 0xAC2F, 0xB0B9, 0xAC30, 0xB0BA, 0xAC31, 0xB0BB, 0xAC32, 0x8158, 0xAC33, 0x8159, 0xAC34, 0x815A, 0xAC35, 0x8161, 0xAC36, 0x8162, 0xAC37, 0x8163, 0xAC38, 0xB0BC, 0xAC39, 0xB0BD, 0xAC3A, 0x8164, 0xAC3B, 0x8165, 0xAC3C, 0xB0BE, 0xAC3D, 0x8166, 0xAC3E, 0x8167, 0xAC3F, 0x8168, 0xAC40, 0xB0BF, 0xAC41, 0x8169, 0xAC42, 0x816A, 0xAC43, 0x816B, 0xAC44, 0x816C, 0xAC45, 0x816D, 0xAC46, 0x816E, 0xAC47, 0x816F, 0xAC48, 0x8170, 0xAC49, 0x8171, 0xAC4A, 0x8172, 0xAC4B, 0xB0C0, 0xAC4C, 0x8173, 0xAC4D, 0xB0C1, 0xAC4E, 0x8174, 0xAC4F, 0x8175, 0xAC50, 0x8176, 0xAC51, 0x8177, 0xAC52, 0x8178, 0xAC53, 0x8179, 0xAC54, 0xB0C2, 0xAC55, 0x817A, 0xAC56, 0x8181, 0xAC57, 0x8182, 0xAC58, 0xB0C3, 0xAC59, 0x8183, 0xAC5A, 0x8184, 0xAC5B, 0x8185, 0xAC5C, 0xB0C4, 0xAC5D, 0x8186, 0xAC5E, 0x8187, 0xAC5F, 0x8188, 0xAC60, 0x8189, 0xAC61, 0x818A, 0xAC62, 0x818B, 0xAC63, 0x818C, 0xAC64, 0x818D, 0xAC65, 0x818E, 0xAC66, 0x818F, 0xAC67, 0x8190, 0xAC68, 0x8191, 0xAC69, 0x8192, 0xAC6A, 0x8193, 0xAC6B, 0x8194, 0xAC6C, 0x8195, 0xAC6D, 0x8196, 0xAC6E, 0x8197, 0xAC6F, 0x8198, 0xAC70, 0xB0C5, 0xAC71, 0xB0C6, 0xAC72, 0x8199, 0xAC73, 0x819A, 0xAC74, 0xB0C7, 0xAC75, 0x819B, 0xAC76, 0x819C, 0xAC77, 0xB0C8, 0xAC78, 0xB0C9, 0xAC79, 0x819D, 0xAC7A, 0xB0CA, 0xAC7B, 0x819E, 0xAC7C, 0x819F, 0xAC7D, 0x81A0, 0xAC7E, 0x81A1, 0xAC7F, 0x81A2, 0xAC80, 0xB0CB, 0xAC81, 0xB0CC, 0xAC82, 0x81A3, 0xAC83, 0xB0CD, 0xAC84, 0xB0CE, 0xAC85, 0xB0CF, 0xAC86, 0xB0D0, 0xAC87, 0x81A4, 0xAC88, 0x81A5, 0xAC89, 0xB0D1, 0xAC8A, 0xB0D2, 0xAC8B, 0xB0D3, 0xAC8C, 0xB0D4, 0xAC8D, 0x81A6, 0xAC8E, 0x81A7, 0xAC8F, 0x81A8, 0xAC90, 0xB0D5, 0xAC91, 0x81A9, 0xAC92, 0x81AA, 0xAC93, 0x81AB, 0xAC94, 0xB0D6, 0xAC95, 0x81AC, 0xAC96, 0x81AD, 0xAC97, 0x81AE, 0xAC98, 0x81AF, 0xAC99, 0x81B0, 0xAC9A, 0x81B1, 0xAC9B, 0x81B2, 0xAC9C, 0xB0D7, 0xAC9D, 0xB0D8, 0xAC9E, 0x81B3, 0xAC9F, 0xB0D9, 0xACA0, 0xB0DA, 0xACA1, 0xB0DB, 0xACA2, 0x81B4, 0xACA3, 0x81B5, 0xACA4, 0x81B6, 0xACA5, 0x81B7, 0xACA6, 0x81B8, 0xACA7, 0x81B9, 0xACA8, 0xB0DC, 0xACA9, 0xB0DD, 0xACAA, 0xB0DE, 0xACAB, 0x81BA, 0xACAC, 0xB0DF, 0xACAD, 0x81BB, 0xACAE, 0x81BC, 0xACAF, 0xB0E0, 0xACB0, 0xB0E1, 0xACB1, 0x81BD, 0xACB2, 0x81BE, 0xACB3, 0x81BF, 0xACB4, 0x81C0, 0xACB5, 0x81C1, 0xACB6, 0x81C2, 0xACB7, 0x81C3, 0xACB8, 0xB0E2, 0xACB9, 0xB0E3, 0xACBA, 0x81C4, 0xACBB, 0xB0E4, 0xACBC, 0xB0E5, 0xACBD, 0xB0E6, 0xACBE, 0x81C5, 0xACBF, 0x81C6, 0xACC0, 0x81C7, 0xACC1, 0xB0E7, 0xACC2, 0x81C8, 0xACC3, 0x81C9, 0xACC4, 0xB0E8, 0xACC5, 0x81CA, 0xACC6, 0x81CB, 0xACC7, 0x81CC, 0xACC8, 0xB0E9, 0xACC9, 0x81CD, 0xACCA, 0x81CE, 0xACCB, 0x81CF, 0xACCC, 0xB0EA, 0xACCD, 0x81D0, 0xACCE, 0x81D1, 0xACCF, 0x81D2, 0xACD0, 0x81D3, 0xACD1, 0x81D4, 0xACD2, 0x81D5, 0xACD3, 0x81D6, 0xACD4, 0x81D7, 0xACD5, 0xB0EB, 0xACD6, 0x81D8, 0xACD7, 0xB0EC, 0xACD8, 0x81D9, 0xACD9, 0x81DA, 0xACDA, 0x81DB, 0xACDB, 0x81DC, 0xACDC, 0x81DD, 0xACDD, 0x81DE, 0xACDE, 0x81DF, 0xACDF, 0x81E0, 0xACE0, 0xB0ED, 0xACE1, 0xB0EE, 0xACE2, 0x81E1, 0xACE3, 0x81E2, 0xACE4, 0xB0EF, 0xACE5, 0x81E3, 0xACE6, 0x81E4, 0xACE7, 0xB0F0, 0xACE8, 0xB0F1, 0xACE9, 0x81E5, 0xACEA, 0xB0F2, 0xACEB, 0x81E6, 0xACEC, 0xB0F3, 0xACED, 0x81E7, 0xACEE, 0x81E8, 0xACEF, 0xB0F4, 0xACF0, 0xB0F5, 0xACF1, 0xB0F6, 0xACF2, 0x81E9, 0xACF3, 0xB0F7, 0xACF4, 0x81EA, 0xACF5, 0xB0F8, 0xACF6, 0xB0F9, 0xACF7, 0x81EB, 0xACF8, 0x81EC, 0xACF9, 0x81ED, 0xACFA, 0x81EE, 0xACFB, 0x81EF, 0xACFC, 0xB0FA, 0xACFD, 0xB0FB, 0xACFE, 0x81F0, 0xACFF, 0x81F1, 0xAD00, 0xB0FC, 0xAD01, 0x81F2, 0xAD02, 0x81F3, 0xAD03, 0x81F4, 0xAD04, 0xB0FD, 0xAD05, 0x81F5, 0xAD06, 0xB0FE, 0xAD07, 0x81F6, 0xAD08, 0x81F7, 0xAD09, 0x81F8, 0xAD0A, 0x81F9, 0xAD0B, 0x81FA, 0xAD0C, 0xB1A1, 0xAD0D, 0xB1A2, 0xAD0E, 0x81FB, 0xAD0F, 0xB1A3, 0xAD10, 0x81FC, 0xAD11, 0xB1A4, 0xAD12, 0x81FD, 0xAD13, 0x81FE, 0xAD14, 0x8241, 0xAD15, 0x8242, 0xAD16, 0x8243, 0xAD17, 0x8244, 0xAD18, 0xB1A5, 0xAD19, 0x8245, 0xAD1A, 0x8246, 0xAD1B, 0x8247, 0xAD1C, 0xB1A6, 0xAD1D, 0x8248, 0xAD1E, 0x8249, 0xAD1F, 0x824A, 0xAD20, 0xB1A7, 0xAD21, 0x824B, 0xAD22, 0x824C, 0xAD23, 0x824D, 0xAD24, 0x824E, 0xAD25, 0x824F, 0xAD26, 0x8250, 0xAD27, 0x8251, 0xAD28, 0x8252, 0xAD29, 0xB1A8, 0xAD2A, 0x8253, 0xAD2B, 0x8254, 0xAD2C, 0xB1A9, 0xAD2D, 0xB1AA, 0xAD2E, 0x8255, 0xAD2F, 0x8256, 0xAD30, 0x8257, 0xAD31, 0x8258, 0xAD32, 0x8259, 0xAD33, 0x825A, 0xAD34, 0xB1AB, 0xAD35, 0xB1AC, 0xAD36, 0x8261, 0xAD37, 0x8262, 0xAD38, 0xB1AD, 0xAD39, 0x8263, 0xAD3A, 0x8264, 0xAD3B, 0x8265, 0xAD3C, 0xB1AE, 0xAD3D, 0x8266, 0xAD3E, 0x8267, 0xAD3F, 0x8268, 0xAD40, 0x8269, 0xAD41, 0x826A, 0xAD42, 0x826B, 0xAD43, 0x826C, 0xAD44, 0xB1AF, 0xAD45, 0xB1B0, 0xAD46, 0x826D, 0xAD47, 0xB1B1, 0xAD48, 0x826E, 0xAD49, 0xB1B2, 0xAD4A, 0x826F, 0xAD4B, 0x8270, 0xAD4C, 0x8271, 0xAD4D, 0x8272, 0xAD4E, 0x8273, 0xAD4F, 0x8274, 0xAD50, 0xB1B3, 0xAD51, 0x8275, 0xAD52, 0x8276, 0xAD53, 0x8277, 0xAD54, 0xB1B4, 0xAD55, 0x8278, 0xAD56, 0x8279, 0xAD57, 0x827A, 0xAD58, 0xB1B5, 0xAD59, 0x8281, 0xAD5A, 0x8282, 0xAD5B, 0x8283, 0xAD5C, 0x8284, 0xAD5D, 0x8285, 0xAD5E, 0x8286, 0xAD5F, 0x8287, 0xAD60, 0x8288, 0xAD61, 0xB1B6, 0xAD62, 0x8289, 0xAD63, 0xB1B7, 0xAD64, 0x828A, 0xAD65, 0x828B, 0xAD66, 0x828C, 0xAD67, 0x828D, 0xAD68, 0x828E, 0xAD69, 0x828F, 0xAD6A, 0x8290, 0xAD6B, 0x8291, 0xAD6C, 0xB1B8, 0xAD6D, 0xB1B9, 0xAD6E, 0x8292, 0xAD6F, 0x8293, 0xAD70, 0xB1BA, 0xAD71, 0x8294, 0xAD72, 0x8295, 0xAD73, 0xB1BB, 0xAD74, 0xB1BC, 0xAD75, 0xB1BD, 0xAD76, 0xB1BE, 0xAD77, 0x8296, 0xAD78, 0x8297, 0xAD79, 0x8298, 0xAD7A, 0x8299, 0xAD7B, 0xB1BF, 0xAD7C, 0xB1C0, 0xAD7D, 0xB1C1, 0xAD7E, 0x829A, 0xAD7F, 0xB1C2, 0xAD80, 0x829B, 0xAD81, 0xB1C3, 0xAD82, 0xB1C4, 0xAD83, 0x829C, 0xAD84, 0x829D, 0xAD85, 0x829E, 0xAD86, 0x829F, 0xAD87, 0x82A0, 0xAD88, 0xB1C5, 0xAD89, 0xB1C6, 0xAD8A, 0x82A1, 0xAD8B, 0x82A2, 0xAD8C, 0xB1C7, 0xAD8D, 0x82A3, 0xAD8E, 0x82A4, 0xAD8F, 0x82A5, 0xAD90, 0xB1C8, 0xAD91, 0x82A6, 0xAD92, 0x82A7, 0xAD93, 0x82A8, 0xAD94, 0x82A9, 0xAD95, 0x82AA, 0xAD96, 0x82AB, 0xAD97, 0x82AC, 0xAD98, 0x82AD, 0xAD99, 0x82AE, 0xAD9A, 0x82AF, 0xAD9B, 0x82B0, 0xAD9C, 0xB1C9, 0xAD9D, 0xB1CA, 0xAD9E, 0x82B1, 0xAD9F, 0x82B2, 0xADA0, 0x82B3, 0xADA1, 0x82B4, 0xADA2, 0x82B5, 0xADA3, 0x82B6, 0xADA4, 0xB1CB, 0xADA5, 0x82B7, 0xADA6, 0x82B8, 0xADA7, 0x82B9, 0xADA8, 0x82BA, 0xADA9, 0x82BB, 0xADAA, 0x82BC, 0xADAB, 0x82BD, 0xADAC, 0x82BE, 0xADAD, 0x82BF, 0xADAE, 0x82C0, 0xADAF, 0x82C1, 0xADB0, 0x82C2, 0xADB1, 0x82C3, 0xADB2, 0x82C4, 0xADB3, 0x82C5, 0xADB4, 0x82C6, 0xADB5, 0x82C7, 0xADB6, 0x82C8, 0xADB7, 0xB1CC, 0xADB8, 0x82C9, 0xADB9, 0x82CA, 0xADBA, 0x82CB, 0xADBB, 0x82CC, 0xADBC, 0x82CD, 0xADBD, 0x82CE, 0xADBE, 0x82CF, 0xADBF, 0x82D0, 0xADC0, 0xB1CD, 0xADC1, 0xB1CE, 0xADC2, 0x82D1, 0xADC3, 0x82D2, 0xADC4, 0xB1CF, 0xADC5, 0x82D3, 0xADC6, 0x82D4, 0xADC7, 0x82D5, 0xADC8, 0xB1D0, 0xADC9, 0x82D6, 0xADCA, 0x82D7, 0xADCB, 0x82D8, 0xADCC, 0x82D9, 0xADCD, 0x82DA, 0xADCE, 0x82DB, 0xADCF, 0x82DC, 0xADD0, 0xB1D1, 0xADD1, 0xB1D2, 0xADD2, 0x82DD, 0xADD3, 0xB1D3, 0xADD4, 0x82DE, 0xADD5, 0x82DF, 0xADD6, 0x82E0, 0xADD7, 0x82E1, 0xADD8, 0x82E2, 0xADD9, 0x82E3, 0xADDA, 0x82E4, 0xADDB, 0x82E5, 0xADDC, 0xB1D4, 0xADDD, 0x82E6, 0xADDE, 0x82E7, 0xADDF, 0x82E8, 0xADE0, 0xB1D5, 0xADE1, 0x82E9, 0xADE2, 0x82EA, 0xADE3, 0x82EB, 0xADE4, 0xB1D6, 0xADE5, 0x82EC, 0xADE6, 0x82ED, 0xADE7, 0x82EE, 0xADE8, 0x82EF, 0xADE9, 0x82F0, 0xADEA, 0x82F1, 0xADEB, 0x82F2, 0xADEC, 0x82F3, 0xADED, 0x82F4, 0xADEE, 0x82F5, 0xADEF, 0x82F6, 0xADF0, 0x82F7, 0xADF1, 0x82F8, 0xADF2, 0x82F9, 0xADF3, 0x82FA, 0xADF4, 0x82FB, 0xADF5, 0x82FC, 0xADF6, 0x82FD, 0xADF7, 0x82FE, 0xADF8, 0xB1D7, 0xADF9, 0xB1D8, 0xADFA, 0x8341, 0xADFB, 0x8342, 0xADFC, 0xB1D9, 0xADFD, 0x8343, 0xADFE, 0x8344, 0xADFF, 0xB1DA, 0xAE00, 0xB1DB, 0xAE01, 0xB1DC, 0xAE02, 0x8345, 0xAE03, 0x8346, 0xAE04, 0x8347, 0xAE05, 0x8348, 0xAE06, 0x8349, 0xAE07, 0x834A, 0xAE08, 0xB1DD, 0xAE09, 0xB1DE, 0xAE0A, 0x834B, 0xAE0B, 0xB1DF, 0xAE0C, 0x834C, 0xAE0D, 0xB1E0, 0xAE0E, 0x834D, 0xAE0F, 0x834E, 0xAE10, 0x834F, 0xAE11, 0x8350, 0xAE12, 0x8351, 0xAE13, 0x8352, 0xAE14, 0xB1E1, 0xAE15, 0x8353, 0xAE16, 0x8354, 0xAE17, 0x8355, 0xAE18, 0x8356, 0xAE19, 0x8357, 0xAE1A, 0x8358, 0xAE1B, 0x8359, 0xAE1C, 0x835A, 0xAE1D, 0x8361, 0xAE1E, 0x8362, 0xAE1F, 0x8363, 0xAE20, 0x8364, 0xAE21, 0x8365, 0xAE22, 0x8366, 0xAE23, 0x8367, 0xAE24, 0x8368, 0xAE25, 0x8369, 0xAE26, 0x836A, 0xAE27, 0x836B, 0xAE28, 0x836C, 0xAE29, 0x836D, 0xAE2A, 0x836E, 0xAE2B, 0x836F, 0xAE2C, 0x8370, 0xAE2D, 0x8371, 0xAE2E, 0x8372, 0xAE2F, 0x8373, 0xAE30, 0xB1E2, 0xAE31, 0xB1E3, 0xAE32, 0x8374, 0xAE33, 0x8375, 0xAE34, 0xB1E4, 0xAE35, 0x8376, 0xAE36, 0x8377, 0xAE37, 0xB1E5, 0xAE38, 0xB1E6, 0xAE39, 0x8378, 0xAE3A, 0xB1E7, 0xAE3B, 0x8379, 0xAE3C, 0x837A, 0xAE3D, 0x8381, 0xAE3E, 0x8382, 0xAE3F, 0x8383, 0xAE40, 0xB1E8, 0xAE41, 0xB1E9, 0xAE42, 0x8384, 0xAE43, 0xB1EA, 0xAE44, 0x8385, 0xAE45, 0xB1EB, 0xAE46, 0xB1EC, 0xAE47, 0x8386, 0xAE48, 0x8387, 0xAE49, 0x8388, 0xAE4A, 0xB1ED, 0xAE4B, 0x8389, 0xAE4C, 0xB1EE, 0xAE4D, 0xB1EF, 0xAE4E, 0xB1F0, 0xAE4F, 0x838A, 0xAE50, 0xB1F1, 0xAE51, 0x838B, 0xAE52, 0x838C, 0xAE53, 0x838D, 0xAE54, 0xB1F2, 0xAE55, 0x838E, 0xAE56, 0xB1F3, 0xAE57, 0x838F, 0xAE58, 0x8390, 0xAE59, 0x8391, 0xAE5A, 0x8392, 0xAE5B, 0x8393, 0xAE5C, 0xB1F4, 0xAE5D, 0xB1F5, 0xAE5E, 0x8394, 0xAE5F, 0xB1F6, 0xAE60, 0xB1F7, 0xAE61, 0xB1F8, 0xAE62, 0x8395, 0xAE63, 0x8396, 0xAE64, 0x8397, 0xAE65, 0xB1F9, 0xAE66, 0x8398, 0xAE67, 0x8399, 0xAE68, 0xB1FA, 0xAE69, 0xB1FB, 0xAE6A, 0x839A, 0xAE6B, 0x839B, 0xAE6C, 0xB1FC, 0xAE6D, 0x839C, 0xAE6E, 0x839D, 0xAE6F, 0x839E, 0xAE70, 0xB1FD, 0xAE71, 0x839F, 0xAE72, 0x83A0, 0xAE73, 0x83A1, 0xAE74, 0x83A2, 0xAE75, 0x83A3, 0xAE76, 0x83A4, 0xAE77, 0x83A5, 0xAE78, 0xB1FE, 0xAE79, 0xB2A1, 0xAE7A, 0x83A6, 0xAE7B, 0xB2A2, 0xAE7C, 0xB2A3, 0xAE7D, 0xB2A4, 0xAE7E, 0x83A7, 0xAE7F, 0x83A8, 0xAE80, 0x83A9, 0xAE81, 0x83AA, 0xAE82, 0x83AB, 0xAE83, 0x83AC, 0xAE84, 0xB2A5, 0xAE85, 0xB2A6, 0xAE86, 0x83AD, 0xAE87, 0x83AE, 0xAE88, 0x83AF, 0xAE89, 0x83B0, 0xAE8A, 0x83B1, 0xAE8B, 0x83B2, 0xAE8C, 0xB2A7, 0xAE8D, 0x83B3, 0xAE8E, 0x83B4, 0xAE8F, 0x83B5, 0xAE90, 0x83B6, 0xAE91, 0x83B7, 0xAE92, 0x83B8, 0xAE93, 0x83B9, 0xAE94, 0x83BA, 0xAE95, 0x83BB, 0xAE96, 0x83BC, 0xAE97, 0x83BD, 0xAE98, 0x83BE, 0xAE99, 0x83BF, 0xAE9A, 0x83C0, 0xAE9B, 0x83C1, 0xAE9C, 0x83C2, 0xAE9D, 0x83C3, 0xAE9E, 0x83C4, 0xAE9F, 0x83C5, 0xAEA0, 0x83C6, 0xAEA1, 0x83C7, 0xAEA2, 0x83C8, 0xAEA3, 0x83C9, 0xAEA4, 0x83CA, 0xAEA5, 0x83CB, 0xAEA6, 0x83CC, 0xAEA7, 0x83CD, 0xAEA8, 0x83CE, 0xAEA9, 0x83CF, 0xAEAA, 0x83D0, 0xAEAB, 0x83D1, 0xAEAC, 0x83D2, 0xAEAD, 0x83D3, 0xAEAE, 0x83D4, 0xAEAF, 0x83D5, 0xAEB0, 0x83D6, 0xAEB1, 0x83D7, 0xAEB2, 0x83D8, 0xAEB3, 0x83D9, 0xAEB4, 0x83DA, 0xAEB5, 0x83DB, 0xAEB6, 0x83DC, 0xAEB7, 0x83DD, 0xAEB8, 0x83DE, 0xAEB9, 0x83DF, 0xAEBA, 0x83E0, 0xAEBB, 0x83E1, 0xAEBC, 0xB2A8, 0xAEBD, 0xB2A9, 0xAEBE, 0xB2AA, 0xAEBF, 0x83E2, 0xAEC0, 0xB2AB, 0xAEC1, 0x83E3, 0xAEC2, 0x83E4, 0xAEC3, 0x83E5, 0xAEC4, 0xB2AC, 0xAEC5, 0x83E6, 0xAEC6, 0x83E7, 0xAEC7, 0x83E8, 0xAEC8, 0x83E9, 0xAEC9, 0x83EA, 0xAECA, 0x83EB, 0xAECB, 0x83EC, 0xAECC, 0xB2AD, 0xAECD, 0xB2AE, 0xAECE, 0x83ED, 0xAECF, 0xB2AF, 0xAED0, 0xB2B0, 0xAED1, 0xB2B1, 0xAED2, 0x83EE, 0xAED3, 0x83EF, 0xAED4, 0x83F0, 0xAED5, 0x83F1, 0xAED6, 0x83F2, 0xAED7, 0x83F3, 0xAED8, 0xB2B2, 0xAED9, 0xB2B3, 0xAEDA, 0x83F4, 0xAEDB, 0x83F5, 0xAEDC, 0xB2B4, 0xAEDD, 0x83F6, 0xAEDE, 0x83F7, 0xAEDF, 0x83F8, 0xAEE0, 0x83F9, 0xAEE1, 0x83FA, 0xAEE2, 0x83FB, 0xAEE3, 0x83FC, 0xAEE4, 0x83FD, 0xAEE5, 0x83FE, 0xAEE6, 0x8441, 0xAEE7, 0x8442, 0xAEE8, 0xB2B5, 0xAEE9, 0x8443, 0xAEEA, 0x8444, 0xAEEB, 0xB2B6, 0xAEEC, 0x8445, 0xAEED, 0xB2B7, 0xAEEE, 0x8446, 0xAEEF, 0x8447, 0xAEF0, 0x8448, 0xAEF1, 0x8449, 0xAEF2, 0x844A, 0xAEF3, 0x844B, 0xAEF4, 0xB2B8, 0xAEF5, 0x844C, 0xAEF6, 0x844D, 0xAEF7, 0x844E, 0xAEF8, 0xB2B9, 0xAEF9, 0x844F, 0xAEFA, 0x8450, 0xAEFB, 0x8451, 0xAEFC, 0xB2BA, 0xAEFD, 0x8452, 0xAEFE, 0x8453, 0xAEFF, 0x8454, 0xAF00, 0x8455, 0xAF01, 0x8456, 0xAF02, 0x8457, 0xAF03, 0x8458, 0xAF04, 0x8459, 0xAF05, 0x845A, 0xAF06, 0x8461, 0xAF07, 0xB2BB, 0xAF08, 0xB2BC, 0xAF09, 0x8462, 0xAF0A, 0x8463, 0xAF0B, 0x8464, 0xAF0C, 0x8465, 0xAF0D, 0xB2BD, 0xAF0E, 0x8466, 0xAF0F, 0x8467, 0xAF10, 0xB2BE, 0xAF11, 0x8468, 0xAF12, 0x8469, 0xAF13, 0x846A, 0xAF14, 0x846B, 0xAF15, 0x846C, 0xAF16, 0x846D, 0xAF17, 0x846E, 0xAF18, 0x846F, 0xAF19, 0x8470, 0xAF1A, 0x8471, 0xAF1B, 0x8472, 0xAF1C, 0x8473, 0xAF1D, 0x8474, 0xAF1E, 0x8475, 0xAF1F, 0x8476, 0xAF20, 0x8477, 0xAF21, 0x8478, 0xAF22, 0x8479, 0xAF23, 0x847A, 0xAF24, 0x8481, 0xAF25, 0x8482, 0xAF26, 0x8483, 0xAF27, 0x8484, 0xAF28, 0x8485, 0xAF29, 0x8486, 0xAF2A, 0x8487, 0xAF2B, 0x8488, 0xAF2C, 0xB2BF, 0xAF2D, 0xB2C0, 0xAF2E, 0x8489, 0xAF2F, 0x848A, 0xAF30, 0xB2C1, 0xAF31, 0x848B, 0xAF32, 0xB2C2, 0xAF33, 0x848C, 0xAF34, 0xB2C3, 0xAF35, 0x848D, 0xAF36, 0x848E, 0xAF37, 0x848F, 0xAF38, 0x8490, 0xAF39, 0x8491, 0xAF3A, 0x8492, 0xAF3B, 0x8493, 0xAF3C, 0xB2C4, 0xAF3D, 0xB2C5, 0xAF3E, 0x8494, 0xAF3F, 0xB2C6, 0xAF40, 0x8495, 0xAF41, 0xB2C7, 0xAF42, 0xB2C8, 0xAF43, 0xB2C9, 0xAF44, 0x8496, 0xAF45, 0x8497, 0xAF46, 0x8498, 0xAF47, 0x8499, 0xAF48, 0xB2CA, 0xAF49, 0xB2CB, 0xAF4A, 0x849A, 0xAF4B, 0x849B, 0xAF4C, 0x849C, 0xAF4D, 0x849D, 0xAF4E, 0x849E, 0xAF4F, 0x849F, 0xAF50, 0xB2CC, 0xAF51, 0x84A0, 0xAF52, 0x84A1, 0xAF53, 0x84A2, 0xAF54, 0x84A3, 0xAF55, 0x84A4, 0xAF56, 0x84A5, 0xAF57, 0x84A6, 0xAF58, 0x84A7, 0xAF59, 0x84A8, 0xAF5A, 0x84A9, 0xAF5B, 0x84AA, 0xAF5C, 0xB2CD, 0xAF5D, 0xB2CE, 0xAF5E, 0x84AB, 0xAF5F, 0x84AC, 0xAF60, 0x84AD, 0xAF61, 0x84AE, 0xAF62, 0x84AF, 0xAF63, 0x84B0, 0xAF64, 0xB2CF, 0xAF65, 0xB2D0, 0xAF66, 0x84B1, 0xAF67, 0x84B2, 0xAF68, 0x84B3, 0xAF69, 0x84B4, 0xAF6A, 0x84B5, 0xAF6B, 0x84B6, 0xAF6C, 0x84B7, 0xAF6D, 0x84B8, 0xAF6E, 0x84B9, 0xAF6F, 0x84BA, 0xAF70, 0x84BB, 0xAF71, 0x84BC, 0xAF72, 0x84BD, 0xAF73, 0x84BE, 0xAF74, 0x84BF, 0xAF75, 0x84C0, 0xAF76, 0x84C1, 0xAF77, 0x84C2, 0xAF78, 0x84C3, 0xAF79, 0xB2D1, 0xAF7A, 0x84C4, 0xAF7B, 0x84C5, 0xAF7C, 0x84C6, 0xAF7D, 0x84C7, 0xAF7E, 0x84C8, 0xAF7F, 0x84C9, 0xAF80, 0xB2D2, 0xAF81, 0x84CA, 0xAF82, 0x84CB, 0xAF83, 0x84CC, 0xAF84, 0xB2D3, 0xAF85, 0x84CD, 0xAF86, 0x84CE, 0xAF87, 0x84CF, 0xAF88, 0xB2D4, 0xAF89, 0x84D0, 0xAF8A, 0x84D1, 0xAF8B, 0x84D2, 0xAF8C, 0x84D3, 0xAF8D, 0x84D4, 0xAF8E, 0x84D5, 0xAF8F, 0x84D6, 0xAF90, 0xB2D5, 0xAF91, 0xB2D6, 0xAF92, 0x84D7, 0xAF93, 0x84D8, 0xAF94, 0x84D9, 0xAF95, 0xB2D7, 0xAF96, 0x84DA, 0xAF97, 0x84DB, 0xAF98, 0x84DC, 0xAF99, 0x84DD, 0xAF9A, 0x84DE, 0xAF9B, 0x84DF, 0xAF9C, 0xB2D8, 0xAF9D, 0x84E0, 0xAF9E, 0x84E1, 0xAF9F, 0x84E2, 0xAFA0, 0x84E3, 0xAFA1, 0x84E4, 0xAFA2, 0x84E5, 0xAFA3, 0x84E6, 0xAFA4, 0x84E7, 0xAFA5, 0x84E8, 0xAFA6, 0x84E9, 0xAFA7, 0x84EA, 0xAFA8, 0x84EB, 0xAFA9, 0x84EC, 0xAFAA, 0x84ED, 0xAFAB, 0x84EE, 0xAFAC, 0x84EF, 0xAFAD, 0x84F0, 0xAFAE, 0x84F1, 0xAFAF, 0x84F2, 0xAFB0, 0x84F3, 0xAFB1, 0x84F4, 0xAFB2, 0x84F5, 0xAFB3, 0x84F6, 0xAFB4, 0x84F7, 0xAFB5, 0x84F8, 0xAFB6, 0x84F9, 0xAFB7, 0x84FA, 0xAFB8, 0xB2D9, 0xAFB9, 0xB2DA, 0xAFBA, 0x84FB, 0xAFBB, 0x84FC, 0xAFBC, 0xB2DB, 0xAFBD, 0x84FD, 0xAFBE, 0x84FE, 0xAFBF, 0x8541, 0xAFC0, 0xB2DC, 0xAFC1, 0x8542, 0xAFC2, 0x8543, 0xAFC3, 0x8544, 0xAFC4, 0x8545, 0xAFC5, 0x8546, 0xAFC6, 0x8547, 0xAFC7, 0xB2DD, 0xAFC8, 0xB2DE, 0xAFC9, 0xB2DF, 0xAFCA, 0x8548, 0xAFCB, 0xB2E0, 0xAFCC, 0x8549, 0xAFCD, 0xB2E1, 0xAFCE, 0xB2E2, 0xAFCF, 0x854A, 0xAFD0, 0x854B, 0xAFD1, 0x854C, 0xAFD2, 0x854D, 0xAFD3, 0x854E, 0xAFD4, 0xB2E3, 0xAFD5, 0x854F, 0xAFD6, 0x8550, 0xAFD7, 0x8551, 0xAFD8, 0x8552, 0xAFD9, 0x8553, 0xAFDA, 0x8554, 0xAFDB, 0x8555, 0xAFDC, 0xB2E4, 0xAFDD, 0x8556, 0xAFDE, 0x8557, 0xAFDF, 0x8558, 0xAFE0, 0x8559, 0xAFE1, 0x855A, 0xAFE2, 0x8561, 0xAFE3, 0x8562, 0xAFE4, 0x8563, 0xAFE5, 0x8564, 0xAFE6, 0x8565, 0xAFE7, 0x8566, 0xAFE8, 0xB2E5, 0xAFE9, 0xB2E6, 0xAFEA, 0x8567, 0xAFEB, 0x8568, 0xAFEC, 0x8569, 0xAFED, 0x856A, 0xAFEE, 0x856B, 0xAFEF, 0x856C, 0xAFF0, 0xB2E7, 0xAFF1, 0xB2E8, 0xAFF2, 0x856D, 0xAFF3, 0x856E, 0xAFF4, 0xB2E9, 0xAFF5, 0x856F, 0xAFF6, 0x8570, 0xAFF7, 0x8571, 0xAFF8, 0xB2EA, 0xAFF9, 0x8572, 0xAFFA, 0x8573, 0xAFFB, 0x8574, 0xAFFC, 0x8575, 0xAFFD, 0x8576, 0xAFFE, 0x8577, 0xAFFF, 0x8578, 0xB000, 0xB2EB, 0xB001, 0xB2EC, 0xB002, 0x8579, 0xB003, 0x857A, 0xB004, 0xB2ED, 0xB005, 0x8581, 0xB006, 0x8582, 0xB007, 0x8583, 0xB008, 0x8584, 0xB009, 0x8585, 0xB00A, 0x8586, 0xB00B, 0x8587, 0xB00C, 0xB2EE, 0xB00D, 0x8588, 0xB00E, 0x8589, 0xB00F, 0x858A, 0xB010, 0xB2EF, 0xB011, 0x858B, 0xB012, 0x858C, 0xB013, 0x858D, 0xB014, 0xB2F0, 0xB015, 0x858E, 0xB016, 0x858F, 0xB017, 0x8590, 0xB018, 0x8591, 0xB019, 0x8592, 0xB01A, 0x8593, 0xB01B, 0x8594, 0xB01C, 0xB2F1, 0xB01D, 0xB2F2, 0xB01E, 0x8595, 0xB01F, 0x8596, 0xB020, 0x8597, 0xB021, 0x8598, 0xB022, 0x8599, 0xB023, 0x859A, 0xB024, 0x859B, 0xB025, 0x859C, 0xB026, 0x859D, 0xB027, 0x859E, 0xB028, 0xB2F3, 0xB029, 0x859F, 0xB02A, 0x85A0, 0xB02B, 0x85A1, 0xB02C, 0x85A2, 0xB02D, 0x85A3, 0xB02E, 0x85A4, 0xB02F, 0x85A5, 0xB030, 0x85A6, 0xB031, 0x85A7, 0xB032, 0x85A8, 0xB033, 0x85A9, 0xB034, 0x85AA, 0xB035, 0x85AB, 0xB036, 0x85AC, 0xB037, 0x85AD, 0xB038, 0x85AE, 0xB039, 0x85AF, 0xB03A, 0x85B0, 0xB03B, 0x85B1, 0xB03C, 0x85B2, 0xB03D, 0x85B3, 0xB03E, 0x85B4, 0xB03F, 0x85B5, 0xB040, 0x85B6, 0xB041, 0x85B7, 0xB042, 0x85B8, 0xB043, 0x85B9, 0xB044, 0xB2F4, 0xB045, 0xB2F5, 0xB046, 0x85BA, 0xB047, 0x85BB, 0xB048, 0xB2F6, 0xB049, 0x85BC, 0xB04A, 0xB2F7, 0xB04B, 0x85BD, 0xB04C, 0xB2F8, 0xB04D, 0x85BE, 0xB04E, 0xB2F9, 0xB04F, 0x85BF, 0xB050, 0x85C0, 0xB051, 0x85C1, 0xB052, 0x85C2, 0xB053, 0xB2FA, 0xB054, 0xB2FB, 0xB055, 0xB2FC, 0xB056, 0x85C3, 0xB057, 0xB2FD, 0xB058, 0x85C4, 0xB059, 0xB2FE, 0xB05A, 0x85C5, 0xB05B, 0x85C6, 0xB05C, 0x85C7, 0xB05D, 0xB3A1, 0xB05E, 0x85C8, 0xB05F, 0x85C9, 0xB060, 0x85CA, 0xB061, 0x85CB, 0xB062, 0x85CC, 0xB063, 0x85CD, 0xB064, 0x85CE, 0xB065, 0x85CF, 0xB066, 0x85D0, 0xB067, 0x85D1, 0xB068, 0x85D2, 0xB069, 0x85D3, 0xB06A, 0x85D4, 0xB06B, 0x85D5, 0xB06C, 0x85D6, 0xB06D, 0x85D7, 0xB06E, 0x85D8, 0xB06F, 0x85D9, 0xB070, 0x85DA, 0xB071, 0x85DB, 0xB072, 0x85DC, 0xB073, 0x85DD, 0xB074, 0x85DE, 0xB075, 0x85DF, 0xB076, 0x85E0, 0xB077, 0x85E1, 0xB078, 0x85E2, 0xB079, 0x85E3, 0xB07A, 0x85E4, 0xB07B, 0x85E5, 0xB07C, 0xB3A2, 0xB07D, 0xB3A3, 0xB07E, 0x85E6, 0xB07F, 0x85E7, 0xB080, 0xB3A4, 0xB081, 0x85E8, 0xB082, 0x85E9, 0xB083, 0x85EA, 0xB084, 0xB3A5, 0xB085, 0x85EB, 0xB086, 0x85EC, 0xB087, 0x85ED, 0xB088, 0x85EE, 0xB089, 0x85EF, 0xB08A, 0x85F0, 0xB08B, 0x85F1, 0xB08C, 0xB3A6, 0xB08D, 0xB3A7, 0xB08E, 0x85F2, 0xB08F, 0xB3A8, 0xB090, 0x85F3, 0xB091, 0xB3A9, 0xB092, 0x85F4, 0xB093, 0x85F5, 0xB094, 0x85F6, 0xB095, 0x85F7, 0xB096, 0x85F8, 0xB097, 0x85F9, 0xB098, 0xB3AA, 0xB099, 0xB3AB, 0xB09A, 0xB3AC, 0xB09B, 0x85FA, 0xB09C, 0xB3AD, 0xB09D, 0x85FB, 0xB09E, 0x85FC, 0xB09F, 0xB3AE, 0xB0A0, 0xB3AF, 0xB0A1, 0xB3B0, 0xB0A2, 0xB3B1, 0xB0A3, 0x85FD, 0xB0A4, 0x85FE, 0xB0A5, 0x8641, 0xB0A6, 0x8642, 0xB0A7, 0x8643, 0xB0A8, 0xB3B2, 0xB0A9, 0xB3B3, 0xB0AA, 0x8644, 0xB0AB, 0xB3B4, 0xB0AC, 0xB3B5, 0xB0AD, 0xB3B6, 0xB0AE, 0xB3B7, 0xB0AF, 0xB3B8, 0xB0B0, 0x8645, 0xB0B1, 0xB3B9, 0xB0B2, 0x8646, 0xB0B3, 0xB3BA, 0xB0B4, 0xB3BB, 0xB0B5, 0xB3BC, 0xB0B6, 0x8647, 0xB0B7, 0x8648, 0xB0B8, 0xB3BD, 0xB0B9, 0x8649, 0xB0BA, 0x864A, 0xB0BB, 0x864B, 0xB0BC, 0xB3BE, 0xB0BD, 0x864C, 0xB0BE, 0x864D, 0xB0BF, 0x864E, 0xB0C0, 0x864F, 0xB0C1, 0x8650, 0xB0C2, 0x8651, 0xB0C3, 0x8652, 0xB0C4, 0xB3BF, 0xB0C5, 0xB3C0, 0xB0C6, 0x8653, 0xB0C7, 0xB3C1, 0xB0C8, 0xB3C2, 0xB0C9, 0xB3C3, 0xB0CA, 0x8654, 0xB0CB, 0x8655, 0xB0CC, 0x8656, 0xB0CD, 0x8657, 0xB0CE, 0x8658, 0xB0CF, 0x8659, 0xB0D0, 0xB3C4, 0xB0D1, 0xB3C5, 0xB0D2, 0x865A, 0xB0D3, 0x8661, 0xB0D4, 0xB3C6, 0xB0D5, 0x8662, 0xB0D6, 0x8663, 0xB0D7, 0x8664, 0xB0D8, 0xB3C7, 0xB0D9, 0x8665, 0xB0DA, 0x8666, 0xB0DB, 0x8667, 0xB0DC, 0x8668, 0xB0DD, 0x8669, 0xB0DE, 0x866A, 0xB0DF, 0x866B, 0xB0E0, 0xB3C8, 0xB0E1, 0x866C, 0xB0E2, 0x866D, 0xB0E3, 0x866E, 0xB0E4, 0x866F, 0xB0E5, 0xB3C9, 0xB0E6, 0x8670, 0xB0E7, 0x8671, 0xB0E8, 0x8672, 0xB0E9, 0x8673, 0xB0EA, 0x8674, 0xB0EB, 0x8675, 0xB0EC, 0x8676, 0xB0ED, 0x8677, 0xB0EE, 0x8678, 0xB0EF, 0x8679, 0xB0F0, 0x867A, 0xB0F1, 0x8681, 0xB0F2, 0x8682, 0xB0F3, 0x8683, 0xB0F4, 0x8684, 0xB0F5, 0x8685, 0xB0F6, 0x8686, 0xB0F7, 0x8687, 0xB0F8, 0x8688, 0xB0F9, 0x8689, 0xB0FA, 0x868A, 0xB0FB, 0x868B, 0xB0FC, 0x868C, 0xB0FD, 0x868D, 0xB0FE, 0x868E, 0xB0FF, 0x868F, 0xB100, 0x8690, 0xB101, 0x8691, 0xB102, 0x8692, 0xB103, 0x8693, 0xB104, 0x8694, 0xB105, 0x8695, 0xB106, 0x8696, 0xB107, 0x8697, 0xB108, 0xB3CA, 0xB109, 0xB3CB, 0xB10A, 0x8698, 0xB10B, 0xB3CC, 0xB10C, 0xB3CD, 0xB10D, 0x8699, 0xB10E, 0x869A, 0xB10F, 0x869B, 0xB110, 0xB3CE, 0xB111, 0x869C, 0xB112, 0xB3CF, 0xB113, 0xB3D0, 0xB114, 0x869D, 0xB115, 0x869E, 0xB116, 0x869F, 0xB117, 0x86A0, 0xB118, 0xB3D1, 0xB119, 0xB3D2, 0xB11A, 0x86A1, 0xB11B, 0xB3D3, 0xB11C, 0xB3D4, 0xB11D, 0xB3D5, 0xB11E, 0x86A2, 0xB11F, 0x86A3, 0xB120, 0x86A4, 0xB121, 0x86A5, 0xB122, 0x86A6, 0xB123, 0xB3D6, 0xB124, 0xB3D7, 0xB125, 0xB3D8, 0xB126, 0x86A7, 0xB127, 0x86A8, 0xB128, 0xB3D9, 0xB129, 0x86A9, 0xB12A, 0x86AA, 0xB12B, 0x86AB, 0xB12C, 0xB3DA, 0xB12D, 0x86AC, 0xB12E, 0x86AD, 0xB12F, 0x86AE, 0xB130, 0x86AF, 0xB131, 0x86B0, 0xB132, 0x86B1, 0xB133, 0x86B2, 0xB134, 0xB3DB, 0xB135, 0xB3DC, 0xB136, 0x86B3, 0xB137, 0xB3DD, 0xB138, 0xB3DE, 0xB139, 0xB3DF, 0xB13A, 0x86B4, 0xB13B, 0x86B5, 0xB13C, 0x86B6, 0xB13D, 0x86B7, 0xB13E, 0x86B8, 0xB13F, 0x86B9, 0xB140, 0xB3E0, 0xB141, 0xB3E1, 0xB142, 0x86BA, 0xB143, 0x86BB, 0xB144, 0xB3E2, 0xB145, 0x86BC, 0xB146, 0x86BD, 0xB147, 0x86BE, 0xB148, 0xB3E3, 0xB149, 0x86BF, 0xB14A, 0x86C0, 0xB14B, 0x86C1, 0xB14C, 0x86C2, 0xB14D, 0x86C3, 0xB14E, 0x86C4, 0xB14F, 0x86C5, 0xB150, 0xB3E4, 0xB151, 0xB3E5, 0xB152, 0x86C6, 0xB153, 0x86C7, 0xB154, 0xB3E6, 0xB155, 0xB3E7, 0xB156, 0x86C8, 0xB157, 0x86C9, 0xB158, 0xB3E8, 0xB159, 0x86CA, 0xB15A, 0x86CB, 0xB15B, 0x86CC, 0xB15C, 0xB3E9, 0xB15D, 0x86CD, 0xB15E, 0x86CE, 0xB15F, 0x86CF, 0xB160, 0xB3EA, 0xB161, 0x86D0, 0xB162, 0x86D1, 0xB163, 0x86D2, 0xB164, 0x86D3, 0xB165, 0x86D4, 0xB166, 0x86D5, 0xB167, 0x86D6, 0xB168, 0x86D7, 0xB169, 0x86D8, 0xB16A, 0x86D9, 0xB16B, 0x86DA, 0xB16C, 0x86DB, 0xB16D, 0x86DC, 0xB16E, 0x86DD, 0xB16F, 0x86DE, 0xB170, 0x86DF, 0xB171, 0x86E0, 0xB172, 0x86E1, 0xB173, 0x86E2, 0xB174, 0x86E3, 0xB175, 0x86E4, 0xB176, 0x86E5, 0xB177, 0x86E6, 0xB178, 0xB3EB, 0xB179, 0xB3EC, 0xB17A, 0x86E7, 0xB17B, 0x86E8, 0xB17C, 0xB3ED, 0xB17D, 0x86E9, 0xB17E, 0x86EA, 0xB17F, 0x86EB, 0xB180, 0xB3EE, 0xB181, 0x86EC, 0xB182, 0xB3EF, 0xB183, 0x86ED, 0xB184, 0x86EE, 0xB185, 0x86EF, 0xB186, 0x86F0, 0xB187, 0x86F1, 0xB188, 0xB3F0, 0xB189, 0xB3F1, 0xB18A, 0x86F2, 0xB18B, 0xB3F2, 0xB18C, 0x86F3, 0xB18D, 0xB3F3, 0xB18E, 0x86F4, 0xB18F, 0x86F5, 0xB190, 0x86F6, 0xB191, 0x86F7, 0xB192, 0xB3F4, 0xB193, 0xB3F5, 0xB194, 0xB3F6, 0xB195, 0x86F8, 0xB196, 0x86F9, 0xB197, 0x86FA, 0xB198, 0xB3F7, 0xB199, 0x86FB, 0xB19A, 0x86FC, 0xB19B, 0x86FD, 0xB19C, 0xB3F8, 0xB19D, 0x86FE, 0xB19E, 0x8741, 0xB19F, 0x8742, 0xB1A0, 0x8743, 0xB1A1, 0x8744, 0xB1A2, 0x8745, 0xB1A3, 0x8746, 0xB1A4, 0x8747, 0xB1A5, 0x8748, 0xB1A6, 0x8749, 0xB1A7, 0x874A, 0xB1A8, 0xB3F9, 0xB1A9, 0x874B, 0xB1AA, 0x874C, 0xB1AB, 0x874D, 0xB1AC, 0x874E, 0xB1AD, 0x874F, 0xB1AE, 0x8750, 0xB1AF, 0x8751, 0xB1B0, 0x8752, 0xB1B1, 0x8753, 0xB1B2, 0x8754, 0xB1B3, 0x8755, 0xB1B4, 0x8756, 0xB1B5, 0x8757, 0xB1B6, 0x8758, 0xB1B7, 0x8759, 0xB1B8, 0x875A, 0xB1B9, 0x8761, 0xB1BA, 0x8762, 0xB1BB, 0x8763, 0xB1BC, 0x8764, 0xB1BD, 0x8765, 0xB1BE, 0x8766, 0xB1BF, 0x8767, 0xB1C0, 0x8768, 0xB1C1, 0x8769, 0xB1C2, 0x876A, 0xB1C3, 0x876B, 0xB1C4, 0x876C, 0xB1C5, 0x876D, 0xB1C6, 0x876E, 0xB1C7, 0x876F, 0xB1C8, 0x8770, 0xB1C9, 0x8771, 0xB1CA, 0x8772, 0xB1CB, 0x8773, 0xB1CC, 0xB3FA, 0xB1CD, 0x8774, 0xB1CE, 0x8775, 0xB1CF, 0x8776, 0xB1D0, 0xB3FB, 0xB1D1, 0x8777, 0xB1D2, 0x8778, 0xB1D3, 0x8779, 0xB1D4, 0xB3FC, 0xB1D5, 0x877A, 0xB1D6, 0x8781, 0xB1D7, 0x8782, 0xB1D8, 0x8783, 0xB1D9, 0x8784, 0xB1DA, 0x8785, 0xB1DB, 0x8786, 0xB1DC, 0xB3FD, 0xB1DD, 0xB3FE, 0xB1DE, 0x8787, 0xB1DF, 0xB4A1, 0xB1E0, 0x8788, 0xB1E1, 0x8789, 0xB1E2, 0x878A, 0xB1E3, 0x878B, 0xB1E4, 0x878C, 0xB1E5, 0x878D, 0xB1E6, 0x878E, 0xB1E7, 0x878F, 0xB1E8, 0xB4A2, 0xB1E9, 0xB4A3, 0xB1EA, 0x8790, 0xB1EB, 0x8791, 0xB1EC, 0xB4A4, 0xB1ED, 0x8792, 0xB1EE, 0x8793, 0xB1EF, 0x8794, 0xB1F0, 0xB4A5, 0xB1F1, 0x8795, 0xB1F2, 0x8796, 0xB1F3, 0x8797, 0xB1F4, 0x8798, 0xB1F5, 0x8799, 0xB1F6, 0x879A, 0xB1F7, 0x879B, 0xB1F8, 0x879C, 0xB1F9, 0xB4A6, 0xB1FA, 0x879D, 0xB1FB, 0xB4A7, 0xB1FC, 0x879E, 0xB1FD, 0xB4A8, 0xB1FE, 0x879F, 0xB1FF, 0x87A0, 0xB200, 0x87A1, 0xB201, 0x87A2, 0xB202, 0x87A3, 0xB203, 0x87A4, 0xB204, 0xB4A9, 0xB205, 0xB4AA, 0xB206, 0x87A5, 0xB207, 0x87A6, 0xB208, 0xB4AB, 0xB209, 0x87A7, 0xB20A, 0x87A8, 0xB20B, 0xB4AC, 0xB20C, 0xB4AD, 0xB20D, 0x87A9, 0xB20E, 0x87AA, 0xB20F, 0x87AB, 0xB210, 0x87AC, 0xB211, 0x87AD, 0xB212, 0x87AE, 0xB213, 0x87AF, 0xB214, 0xB4AE, 0xB215, 0xB4AF, 0xB216, 0x87B0, 0xB217, 0xB4B0, 0xB218, 0x87B1, 0xB219, 0xB4B1, 0xB21A, 0x87B2, 0xB21B, 0x87B3, 0xB21C, 0x87B4, 0xB21D, 0x87B5, 0xB21E, 0x87B6, 0xB21F, 0x87B7, 0xB220, 0xB4B2, 0xB221, 0x87B8, 0xB222, 0x87B9, 0xB223, 0x87BA, 0xB224, 0x87BB, 0xB225, 0x87BC, 0xB226, 0x87BD, 0xB227, 0x87BE, 0xB228, 0x87BF, 0xB229, 0x87C0, 0xB22A, 0x87C1, 0xB22B, 0x87C2, 0xB22C, 0x87C3, 0xB22D, 0x87C4, 0xB22E, 0x87C5, 0xB22F, 0x87C6, 0xB230, 0x87C7, 0xB231, 0x87C8, 0xB232, 0x87C9, 0xB233, 0x87CA, 0xB234, 0xB4B3, 0xB235, 0x87CB, 0xB236, 0x87CC, 0xB237, 0x87CD, 0xB238, 0x87CE, 0xB239, 0x87CF, 0xB23A, 0x87D0, 0xB23B, 0x87D1, 0xB23C, 0xB4B4, 0xB23D, 0x87D2, 0xB23E, 0x87D3, 0xB23F, 0x87D4, 0xB240, 0x87D5, 0xB241, 0x87D6, 0xB242, 0x87D7, 0xB243, 0x87D8, 0xB244, 0x87D9, 0xB245, 0x87DA, 0xB246, 0x87DB, 0xB247, 0x87DC, 0xB248, 0x87DD, 0xB249, 0x87DE, 0xB24A, 0x87DF, 0xB24B, 0x87E0, 0xB24C, 0x87E1, 0xB24D, 0x87E2, 0xB24E, 0x87E3, 0xB24F, 0x87E4, 0xB250, 0x87E5, 0xB251, 0x87E6, 0xB252, 0x87E7, 0xB253, 0x87E8, 0xB254, 0x87E9, 0xB255, 0x87EA, 0xB256, 0x87EB, 0xB257, 0x87EC, 0xB258, 0xB4B5, 0xB259, 0x87ED, 0xB25A, 0x87EE, 0xB25B, 0x87EF, 0xB25C, 0xB4B6, 0xB25D, 0x87F0, 0xB25E, 0x87F1, 0xB25F, 0x87F2, 0xB260, 0xB4B7, 0xB261, 0x87F3, 0xB262, 0x87F4, 0xB263, 0x87F5, 0xB264, 0x87F6, 0xB265, 0x87F7, 0xB266, 0x87F8, 0xB267, 0x87F9, 0xB268, 0xB4B8, 0xB269, 0xB4B9, 0xB26A, 0x87FA, 0xB26B, 0x87FB, 0xB26C, 0x87FC, 0xB26D, 0x87FD, 0xB26E, 0x87FE, 0xB26F, 0x8841, 0xB270, 0x8842, 0xB271, 0x8843, 0xB272, 0x8844, 0xB273, 0x8845, 0xB274, 0xB4BA, 0xB275, 0xB4BB, 0xB276, 0x8846, 0xB277, 0x8847, 0xB278, 0x8848, 0xB279, 0x8849, 0xB27A, 0x884A, 0xB27B, 0x884B, 0xB27C, 0xB4BC, 0xB27D, 0x884C, 0xB27E, 0x884D, 0xB27F, 0x884E, 0xB280, 0x884F, 0xB281, 0x8850, 0xB282, 0x8851, 0xB283, 0x8852, 0xB284, 0xB4BD, 0xB285, 0xB4BE, 0xB286, 0x8853, 0xB287, 0x8854, 0xB288, 0x8855, 0xB289, 0xB4BF, 0xB28A, 0x8856, 0xB28B, 0x8857, 0xB28C, 0x8858, 0xB28D, 0x8859, 0xB28E, 0x885A, 0xB28F, 0x8861, 0xB290, 0xB4C0, 0xB291, 0xB4C1, 0xB292, 0x8862, 0xB293, 0x8863, 0xB294, 0xB4C2, 0xB295, 0x8864, 0xB296, 0x8865, 0xB297, 0x8866, 0xB298, 0xB4C3, 0xB299, 0xB4C4, 0xB29A, 0xB4C5, 0xB29B, 0x8867, 0xB29C, 0x8868, 0xB29D, 0x8869, 0xB29E, 0x886A, 0xB29F, 0x886B, 0xB2A0, 0xB4C6, 0xB2A1, 0xB4C7, 0xB2A2, 0x886C, 0xB2A3, 0xB4C8, 0xB2A4, 0x886D, 0xB2A5, 0xB4C9, 0xB2A6, 0xB4CA, 0xB2A7, 0x886E, 0xB2A8, 0x886F, 0xB2A9, 0x8870, 0xB2AA, 0xB4CB, 0xB2AB, 0x8871, 0xB2AC, 0xB4CC, 0xB2AD, 0x8872, 0xB2AE, 0x8873, 0xB2AF, 0x8874, 0xB2B0, 0xB4CD, 0xB2B1, 0x8875, 0xB2B2, 0x8876, 0xB2B3, 0x8877, 0xB2B4, 0xB4CE, 0xB2B5, 0x8878, 0xB2B6, 0x8879, 0xB2B7, 0x887A, 0xB2B8, 0x8881, 0xB2B9, 0x8882, 0xB2BA, 0x8883, 0xB2BB, 0x8884, 0xB2BC, 0x8885, 0xB2BD, 0x8886, 0xB2BE, 0x8887, 0xB2BF, 0x8888, 0xB2C0, 0x8889, 0xB2C1, 0x888A, 0xB2C2, 0x888B, 0xB2C3, 0x888C, 0xB2C4, 0x888D, 0xB2C5, 0x888E, 0xB2C6, 0x888F, 0xB2C7, 0x8890, 0xB2C8, 0xB4CF, 0xB2C9, 0xB4D0, 0xB2CA, 0x8891, 0xB2CB, 0x8892, 0xB2CC, 0xB4D1, 0xB2CD, 0x8893, 0xB2CE, 0x8894, 0xB2CF, 0x8895, 0xB2D0, 0xB4D2, 0xB2D1, 0x8896, 0xB2D2, 0xB4D3, 0xB2D3, 0x8897, 0xB2D4, 0x8898, 0xB2D5, 0x8899, 0xB2D6, 0x889A, 0xB2D7, 0x889B, 0xB2D8, 0xB4D4, 0xB2D9, 0xB4D5, 0xB2DA, 0x889C, 0xB2DB, 0xB4D6, 0xB2DC, 0x889D, 0xB2DD, 0xB4D7, 0xB2DE, 0x889E, 0xB2DF, 0x889F, 0xB2E0, 0x88A0, 0xB2E1, 0x88A1, 0xB2E2, 0xB4D8, 0xB2E3, 0x88A2, 0xB2E4, 0xB4D9, 0xB2E5, 0xB4DA, 0xB2E6, 0xB4DB, 0xB2E7, 0x88A3, 0xB2E8, 0xB4DC, 0xB2E9, 0x88A4, 0xB2EA, 0x88A5, 0xB2EB, 0xB4DD, 0xB2EC, 0xB4DE, 0xB2ED, 0xB4DF, 0xB2EE, 0xB4E0, 0xB2EF, 0xB4E1, 0xB2F0, 0x88A6, 0xB2F1, 0x88A7, 0xB2F2, 0x88A8, 0xB2F3, 0xB4E2, 0xB2F4, 0xB4E3, 0xB2F5, 0xB4E4, 0xB2F6, 0x88A9, 0xB2F7, 0xB4E5, 0xB2F8, 0xB4E6, 0xB2F9, 0xB4E7, 0xB2FA, 0xB4E8, 0xB2FB, 0xB4E9, 0xB2FC, 0x88AA, 0xB2FD, 0x88AB, 0xB2FE, 0x88AC, 0xB2FF, 0xB4EA, 0xB300, 0xB4EB, 0xB301, 0xB4EC, 0xB302, 0x88AD, 0xB303, 0x88AE, 0xB304, 0xB4ED, 0xB305, 0x88AF, 0xB306, 0x88B0, 0xB307, 0x88B1, 0xB308, 0xB4EE, 0xB309, 0x88B2, 0xB30A, 0x88B3, 0xB30B, 0x88B4, 0xB30C, 0x88B5, 0xB30D, 0x88B6, 0xB30E, 0x88B7, 0xB30F, 0x88B8, 0xB310, 0xB4EF, 0xB311, 0xB4F0, 0xB312, 0x88B9, 0xB313, 0xB4F1, 0xB314, 0xB4F2, 0xB315, 0xB4F3, 0xB316, 0x88BA, 0xB317, 0x88BB, 0xB318, 0x88BC, 0xB319, 0x88BD, 0xB31A, 0x88BE, 0xB31B, 0x88BF, 0xB31C, 0xB4F4, 0xB31D, 0x88C0, 0xB31E, 0x88C1, 0xB31F, 0x88C2, 0xB320, 0x88C3, 0xB321, 0x88C4, 0xB322, 0x88C5, 0xB323, 0x88C6, 0xB324, 0x88C7, 0xB325, 0x88C8, 0xB326, 0x88C9, 0xB327, 0x88CA, 0xB328, 0x88CB, 0xB329, 0x88CC, 0xB32A, 0x88CD, 0xB32B, 0x88CE, 0xB32C, 0x88CF, 0xB32D, 0x88D0, 0xB32E, 0x88D1, 0xB32F, 0x88D2, 0xB330, 0x88D3, 0xB331, 0x88D4, 0xB332, 0x88D5, 0xB333, 0x88D6, 0xB334, 0x88D7, 0xB335, 0x88D8, 0xB336, 0x88D9, 0xB337, 0x88DA, 0xB338, 0x88DB, 0xB339, 0x88DC, 0xB33A, 0x88DD, 0xB33B, 0x88DE, 0xB33C, 0x88DF, 0xB33D, 0x88E0, 0xB33E, 0x88E1, 0xB33F, 0x88E2, 0xB340, 0x88E3, 0xB341, 0x88E4, 0xB342, 0x88E5, 0xB343, 0x88E6, 0xB344, 0x88E7, 0xB345, 0x88E8, 0xB346, 0x88E9, 0xB347, 0x88EA, 0xB348, 0x88EB, 0xB349, 0x88EC, 0xB34A, 0x88ED, 0xB34B, 0x88EE, 0xB34C, 0x88EF, 0xB34D, 0x88F0, 0xB34E, 0x88F1, 0xB34F, 0x88F2, 0xB350, 0x88F3, 0xB351, 0x88F4, 0xB352, 0x88F5, 0xB353, 0x88F6, 0xB354, 0xB4F5, 0xB355, 0xB4F6, 0xB356, 0xB4F7, 0xB357, 0x88F7, 0xB358, 0xB4F8, 0xB359, 0x88F8, 0xB35A, 0x88F9, 0xB35B, 0xB4F9, 0xB35C, 0xB4FA, 0xB35D, 0x88FA, 0xB35E, 0xB4FB, 0xB35F, 0xB4FC, 0xB360, 0x88FB, 0xB361, 0x88FC, 0xB362, 0x88FD, 0xB363, 0x88FE, 0xB364, 0xB4FD, 0xB365, 0xB4FE, 0xB366, 0x8941, 0xB367, 0xB5A1, 0xB368, 0x8942, 0xB369, 0xB5A2, 0xB36A, 0x8943, 0xB36B, 0xB5A3, 0xB36C, 0x8944, 0xB36D, 0x8945, 0xB36E, 0xB5A4, 0xB36F, 0x8946, 0xB370, 0xB5A5, 0xB371, 0xB5A6, 0xB372, 0x8947, 0xB373, 0x8948, 0xB374, 0xB5A7, 0xB375, 0x8949, 0xB376, 0x894A, 0xB377, 0x894B, 0xB378, 0xB5A8, 0xB379, 0x894C, 0xB37A, 0x894D, 0xB37B, 0x894E, 0xB37C, 0x894F, 0xB37D, 0x8950, 0xB37E, 0x8951, 0xB37F, 0x8952, 0xB380, 0xB5A9, 0xB381, 0xB5AA, 0xB382, 0x8953, 0xB383, 0xB5AB, 0xB384, 0xB5AC, 0xB385, 0xB5AD, 0xB386, 0x8954, 0xB387, 0x8955, 0xB388, 0x8956, 0xB389, 0x8957, 0xB38A, 0x8958, 0xB38B, 0x8959, 0xB38C, 0xB5AE, 0xB38D, 0x895A, 0xB38E, 0x8961, 0xB38F, 0x8962, 0xB390, 0xB5AF, 0xB391, 0x8963, 0xB392, 0x8964, 0xB393, 0x8965, 0xB394, 0xB5B0, 0xB395, 0x8966, 0xB396, 0x8967, 0xB397, 0x8968, 0xB398, 0x8969, 0xB399, 0x896A, 0xB39A, 0x896B, 0xB39B, 0x896C, 0xB39C, 0x896D, 0xB39D, 0x896E, 0xB39E, 0x896F, 0xB39F, 0x8970, 0xB3A0, 0xB5B1, 0xB3A1, 0xB5B2, 0xB3A2, 0x8971, 0xB3A3, 0x8972, 0xB3A4, 0x8973, 0xB3A5, 0x8974, 0xB3A6, 0x8975, 0xB3A7, 0x8976, 0xB3A8, 0xB5B3, 0xB3A9, 0x8977, 0xB3AA, 0x8978, 0xB3AB, 0x8979, 0xB3AC, 0xB5B4, 0xB3AD, 0x897A, 0xB3AE, 0x8981, 0xB3AF, 0x8982, 0xB3B0, 0x8983, 0xB3B1, 0x8984, 0xB3B2, 0x8985, 0xB3B3, 0x8986, 0xB3B4, 0x8987, 0xB3B5, 0x8988, 0xB3B6, 0x8989, 0xB3B7, 0x898A, 0xB3B8, 0x898B, 0xB3B9, 0x898C, 0xB3BA, 0x898D, 0xB3BB, 0x898E, 0xB3BC, 0x898F, 0xB3BD, 0x8990, 0xB3BE, 0x8991, 0xB3BF, 0x8992, 0xB3C0, 0x8993, 0xB3C1, 0x8994, 0xB3C2, 0x8995, 0xB3C3, 0x8996, 0xB3C4, 0xB5B5, 0xB3C5, 0xB5B6, 0xB3C6, 0x8997, 0xB3C7, 0x8998, 0xB3C8, 0xB5B7, 0xB3C9, 0x8999, 0xB3CA, 0x899A, 0xB3CB, 0xB5B8, 0xB3CC, 0xB5B9, 0xB3CD, 0x899B, 0xB3CE, 0xB5BA, 0xB3CF, 0x899C, 0xB3D0, 0xB5BB, 0xB3D1, 0x899D, 0xB3D2, 0x899E, 0xB3D3, 0x899F, 0xB3D4, 0xB5BC, 0xB3D5, 0xB5BD, 0xB3D6, 0x89A0, 0xB3D7, 0xB5BE, 0xB3D8, 0x89A1, 0xB3D9, 0xB5BF, 0xB3DA, 0x89A2, 0xB3DB, 0xB5C0, 0xB3DC, 0x89A3, 0xB3DD, 0xB5C1, 0xB3DE, 0x89A4, 0xB3DF, 0x89A5, 0xB3E0, 0xB5C2, 0xB3E1, 0x89A6, 0xB3E2, 0x89A7, 0xB3E3, 0x89A8, 0xB3E4, 0xB5C3, 0xB3E5, 0x89A9, 0xB3E6, 0x89AA, 0xB3E7, 0x89AB, 0xB3E8, 0xB5C4, 0xB3E9, 0x89AC, 0xB3EA, 0x89AD, 0xB3EB, 0x89AE, 0xB3EC, 0x89AF, 0xB3ED, 0x89B0, 0xB3EE, 0x89B1, 0xB3EF, 0x89B2, 0xB3F0, 0x89B3, 0xB3F1, 0x89B4, 0xB3F2, 0x89B5, 0xB3F3, 0x89B6, 0xB3F4, 0x89B7, 0xB3F5, 0x89B8, 0xB3F6, 0x89B9, 0xB3F7, 0x89BA, 0xB3F8, 0x89BB, 0xB3F9, 0x89BC, 0xB3FA, 0x89BD, 0xB3FB, 0x89BE, 0xB3FC, 0xB5C5, 0xB3FD, 0x89BF, 0xB3FE, 0x89C0, 0xB3FF, 0x89C1, 0xB400, 0x89C2, 0xB401, 0x89C3, 0xB402, 0x89C4, 0xB403, 0x89C5, 0xB404, 0x89C6, 0xB405, 0x89C7, 0xB406, 0x89C8, 0xB407, 0x89C9, 0xB408, 0x89CA, 0xB409, 0x89CB, 0xB40A, 0x89CC, 0xB40B, 0x89CD, 0xB40C, 0x89CE, 0xB40D, 0x89CF, 0xB40E, 0x89D0, 0xB40F, 0x89D1, 0xB410, 0xB5C6, 0xB411, 0x89D2, 0xB412, 0x89D3, 0xB413, 0x89D4, 0xB414, 0x89D5, 0xB415, 0x89D6, 0xB416, 0x89D7, 0xB417, 0x89D8, 0xB418, 0xB5C7, 0xB419, 0x89D9, 0xB41A, 0x89DA, 0xB41B, 0x89DB, 0xB41C, 0xB5C8, 0xB41D, 0x89DC, 0xB41E, 0x89DD, 0xB41F, 0x89DE, 0xB420, 0xB5C9, 0xB421, 0x89DF, 0xB422, 0x89E0, 0xB423, 0x89E1, 0xB424, 0x89E2, 0xB425, 0x89E3, 0xB426, 0x89E4, 0xB427, 0x89E5, 0xB428, 0xB5CA, 0xB429, 0xB5CB, 0xB42A, 0x89E6, 0xB42B, 0xB5CC, 0xB42C, 0x89E7, 0xB42D, 0x89E8, 0xB42E, 0x89E9, 0xB42F, 0x89EA, 0xB430, 0x89EB, 0xB431, 0x89EC, 0xB432, 0x89ED, 0xB433, 0x89EE, 0xB434, 0xB5CD, 0xB435, 0x89EF, 0xB436, 0x89F0, 0xB437, 0x89F1, 0xB438, 0x89F2, 0xB439, 0x89F3, 0xB43A, 0x89F4, 0xB43B, 0x89F5, 0xB43C, 0x89F6, 0xB43D, 0x89F7, 0xB43E, 0x89F8, 0xB43F, 0x89F9, 0xB440, 0x89FA, 0xB441, 0x89FB, 0xB442, 0x89FC, 0xB443, 0x89FD, 0xB444, 0x89FE, 0xB445, 0x8A41, 0xB446, 0x8A42, 0xB447, 0x8A43, 0xB448, 0x8A44, 0xB449, 0x8A45, 0xB44A, 0x8A46, 0xB44B, 0x8A47, 0xB44C, 0x8A48, 0xB44D, 0x8A49, 0xB44E, 0x8A4A, 0xB44F, 0x8A4B, 0xB450, 0xB5CE, 0xB451, 0xB5CF, 0xB452, 0x8A4C, 0xB453, 0x8A4D, 0xB454, 0xB5D0, 0xB455, 0x8A4E, 0xB456, 0x8A4F, 0xB457, 0x8A50, 0xB458, 0xB5D1, 0xB459, 0x8A51, 0xB45A, 0x8A52, 0xB45B, 0x8A53, 0xB45C, 0x8A54, 0xB45D, 0x8A55, 0xB45E, 0x8A56, 0xB45F, 0x8A57, 0xB460, 0xB5D2, 0xB461, 0xB5D3, 0xB462, 0x8A58, 0xB463, 0xB5D4, 0xB464, 0x8A59, 0xB465, 0xB5D5, 0xB466, 0x8A5A, 0xB467, 0x8A61, 0xB468, 0x8A62, 0xB469, 0x8A63, 0xB46A, 0x8A64, 0xB46B, 0x8A65, 0xB46C, 0xB5D6, 0xB46D, 0x8A66, 0xB46E, 0x8A67, 0xB46F, 0x8A68, 0xB470, 0x8A69, 0xB471, 0x8A6A, 0xB472, 0x8A6B, 0xB473, 0x8A6C, 0xB474, 0x8A6D, 0xB475, 0x8A6E, 0xB476, 0x8A6F, 0xB477, 0x8A70, 0xB478, 0x8A71, 0xB479, 0x8A72, 0xB47A, 0x8A73, 0xB47B, 0x8A74, 0xB47C, 0x8A75, 0xB47D, 0x8A76, 0xB47E, 0x8A77, 0xB47F, 0x8A78, 0xB480, 0xB5D7, 0xB481, 0x8A79, 0xB482, 0x8A7A, 0xB483, 0x8A81, 0xB484, 0x8A82, 0xB485, 0x8A83, 0xB486, 0x8A84, 0xB487, 0x8A85, 0xB488, 0xB5D8, 0xB489, 0x8A86, 0xB48A, 0x8A87, 0xB48B, 0x8A88, 0xB48C, 0x8A89, 0xB48D, 0x8A8A, 0xB48E, 0x8A8B, 0xB48F, 0x8A8C, 0xB490, 0x8A8D, 0xB491, 0x8A8E, 0xB492, 0x8A8F, 0xB493, 0x8A90, 0xB494, 0x8A91, 0xB495, 0x8A92, 0xB496, 0x8A93, 0xB497, 0x8A94, 0xB498, 0x8A95, 0xB499, 0x8A96, 0xB49A, 0x8A97, 0xB49B, 0x8A98, 0xB49C, 0x8A99, 0xB49D, 0xB5D9, 0xB49E, 0x8A9A, 0xB49F, 0x8A9B, 0xB4A0, 0x8A9C, 0xB4A1, 0x8A9D, 0xB4A2, 0x8A9E, 0xB4A3, 0x8A9F, 0xB4A4, 0xB5DA, 0xB4A5, 0x8AA0, 0xB4A6, 0x8AA1, 0xB4A7, 0x8AA2, 0xB4A8, 0xB5DB, 0xB4A9, 0x8AA3, 0xB4AA, 0x8AA4, 0xB4AB, 0x8AA5, 0xB4AC, 0xB5DC, 0xB4AD, 0x8AA6, 0xB4AE, 0x8AA7, 0xB4AF, 0x8AA8, 0xB4B0, 0x8AA9, 0xB4B1, 0x8AAA, 0xB4B2, 0x8AAB, 0xB4B3, 0x8AAC, 0xB4B4, 0x8AAD, 0xB4B5, 0xB5DD, 0xB4B6, 0x8AAE, 0xB4B7, 0xB5DE, 0xB4B8, 0x8AAF, 0xB4B9, 0xB5DF, 0xB4BA, 0x8AB0, 0xB4BB, 0x8AB1, 0xB4BC, 0x8AB2, 0xB4BD, 0x8AB3, 0xB4BE, 0x8AB4, 0xB4BF, 0x8AB5, 0xB4C0, 0xB5E0, 0xB4C1, 0x8AB6, 0xB4C2, 0x8AB7, 0xB4C3, 0x8AB8, 0xB4C4, 0xB5E1, 0xB4C5, 0x8AB9, 0xB4C6, 0x8ABA, 0xB4C7, 0x8ABB, 0xB4C8, 0xB5E2, 0xB4C9, 0x8ABC, 0xB4CA, 0x8ABD, 0xB4CB, 0x8ABE, 0xB4CC, 0x8ABF, 0xB4CD, 0x8AC0, 0xB4CE, 0x8AC1, 0xB4CF, 0x8AC2, 0xB4D0, 0xB5E3, 0xB4D1, 0x8AC3, 0xB4D2, 0x8AC4, 0xB4D3, 0x8AC5, 0xB4D4, 0x8AC6, 0xB4D5, 0xB5E4, 0xB4D6, 0x8AC7, 0xB4D7, 0x8AC8, 0xB4D8, 0x8AC9, 0xB4D9, 0x8ACA, 0xB4DA, 0x8ACB, 0xB4DB, 0x8ACC, 0xB4DC, 0xB5E5, 0xB4DD, 0xB5E6, 0xB4DE, 0x8ACD, 0xB4DF, 0x8ACE, 0xB4E0, 0xB5E7, 0xB4E1, 0x8ACF, 0xB4E2, 0x8AD0, 0xB4E3, 0xB5E8, 0xB4E4, 0xB5E9, 0xB4E5, 0x8AD1, 0xB4E6, 0xB5EA, 0xB4E7, 0x8AD2, 0xB4E8, 0x8AD3, 0xB4E9, 0x8AD4, 0xB4EA, 0x8AD5, 0xB4EB, 0x8AD6, 0xB4EC, 0xB5EB, 0xB4ED, 0xB5EC, 0xB4EE, 0x8AD7, 0xB4EF, 0xB5ED, 0xB4F0, 0x8AD8, 0xB4F1, 0xB5EE, 0xB4F2, 0x8AD9, 0xB4F3, 0x8ADA, 0xB4F4, 0x8ADB, 0xB4F5, 0x8ADC, 0xB4F6, 0x8ADD, 0xB4F7, 0x8ADE, 0xB4F8, 0xB5EF, 0xB4F9, 0x8ADF, 0xB4FA, 0x8AE0, 0xB4FB, 0x8AE1, 0xB4FC, 0x8AE2, 0xB4FD, 0x8AE3, 0xB4FE, 0x8AE4, 0xB4FF, 0x8AE5, 0xB500, 0x8AE6, 0xB501, 0x8AE7, 0xB502, 0x8AE8, 0xB503, 0x8AE9, 0xB504, 0x8AEA, 0xB505, 0x8AEB, 0xB506, 0x8AEC, 0xB507, 0x8AED, 0xB508, 0x8AEE, 0xB509, 0x8AEF, 0xB50A, 0x8AF0, 0xB50B, 0x8AF1, 0xB50C, 0x8AF2, 0xB50D, 0x8AF3, 0xB50E, 0x8AF4, 0xB50F, 0x8AF5, 0xB510, 0x8AF6, 0xB511, 0x8AF7, 0xB512, 0x8AF8, 0xB513, 0x8AF9, 0xB514, 0xB5F0, 0xB515, 0xB5F1, 0xB516, 0x8AFA, 0xB517, 0x8AFB, 0xB518, 0xB5F2, 0xB519, 0x8AFC, 0xB51A, 0x8AFD, 0xB51B, 0xB5F3, 0xB51C, 0xB5F4, 0xB51D, 0x8AFE, 0xB51E, 0x8B41, 0xB51F, 0x8B42, 0xB520, 0x8B43, 0xB521, 0x8B44, 0xB522, 0x8B45, 0xB523, 0x8B46, 0xB524, 0xB5F5, 0xB525, 0xB5F6, 0xB526, 0x8B47, 0xB527, 0xB5F7, 0xB528, 0xB5F8, 0xB529, 0xB5F9, 0xB52A, 0xB5FA, 0xB52B, 0x8B48, 0xB52C, 0x8B49, 0xB52D, 0x8B4A, 0xB52E, 0x8B4B, 0xB52F, 0x8B4C, 0xB530, 0xB5FB, 0xB531, 0xB5FC, 0xB532, 0x8B4D, 0xB533, 0x8B4E, 0xB534, 0xB5FD, 0xB535, 0x8B4F, 0xB536, 0x8B50, 0xB537, 0x8B51, 0xB538, 0xB5FE, 0xB539, 0x8B52, 0xB53A, 0x8B53, 0xB53B, 0x8B54, 0xB53C, 0x8B55, 0xB53D, 0x8B56, 0xB53E, 0x8B57, 0xB53F, 0x8B58, 0xB540, 0xB6A1, 0xB541, 0xB6A2, 0xB542, 0x8B59, 0xB543, 0xB6A3, 0xB544, 0xB6A4, 0xB545, 0xB6A5, 0xB546, 0x8B5A, 0xB547, 0x8B61, 0xB548, 0x8B62, 0xB549, 0x8B63, 0xB54A, 0x8B64, 0xB54B, 0xB6A6, 0xB54C, 0xB6A7, 0xB54D, 0xB6A8, 0xB54E, 0x8B65, 0xB54F, 0x8B66, 0xB550, 0xB6A9, 0xB551, 0x8B67, 0xB552, 0x8B68, 0xB553, 0x8B69, 0xB554, 0xB6AA, 0xB555, 0x8B6A, 0xB556, 0x8B6B, 0xB557, 0x8B6C, 0xB558, 0x8B6D, 0xB559, 0x8B6E, 0xB55A, 0x8B6F, 0xB55B, 0x8B70, 0xB55C, 0xB6AB, 0xB55D, 0xB6AC, 0xB55E, 0x8B71, 0xB55F, 0xB6AD, 0xB560, 0xB6AE, 0xB561, 0xB6AF, 0xB562, 0x8B72, 0xB563, 0x8B73, 0xB564, 0x8B74, 0xB565, 0x8B75, 0xB566, 0x8B76, 0xB567, 0x8B77, 0xB568, 0x8B78, 0xB569, 0x8B79, 0xB56A, 0x8B7A, 0xB56B, 0x8B81, 0xB56C, 0x8B82, 0xB56D, 0x8B83, 0xB56E, 0x8B84, 0xB56F, 0x8B85, 0xB570, 0x8B86, 0xB571, 0x8B87, 0xB572, 0x8B88, 0xB573, 0x8B89, 0xB574, 0x8B8A, 0xB575, 0x8B8B, 0xB576, 0x8B8C, 0xB577, 0x8B8D, 0xB578, 0x8B8E, 0xB579, 0x8B8F, 0xB57A, 0x8B90, 0xB57B, 0x8B91, 0xB57C, 0x8B92, 0xB57D, 0x8B93, 0xB57E, 0x8B94, 0xB57F, 0x8B95, 0xB580, 0x8B96, 0xB581, 0x8B97, 0xB582, 0x8B98, 0xB583, 0x8B99, 0xB584, 0x8B9A, 0xB585, 0x8B9B, 0xB586, 0x8B9C, 0xB587, 0x8B9D, 0xB588, 0x8B9E, 0xB589, 0x8B9F, 0xB58A, 0x8BA0, 0xB58B, 0x8BA1, 0xB58C, 0x8BA2, 0xB58D, 0x8BA3, 0xB58E, 0x8BA4, 0xB58F, 0x8BA5, 0xB590, 0x8BA6, 0xB591, 0x8BA7, 0xB592, 0x8BA8, 0xB593, 0x8BA9, 0xB594, 0x8BAA, 0xB595, 0x8BAB, 0xB596, 0x8BAC, 0xB597, 0x8BAD, 0xB598, 0x8BAE, 0xB599, 0x8BAF, 0xB59A, 0x8BB0, 0xB59B, 0x8BB1, 0xB59C, 0x8BB2, 0xB59D, 0x8BB3, 0xB59E, 0x8BB4, 0xB59F, 0x8BB5, 0xB5A0, 0xB6B0, 0xB5A1, 0xB6B1, 0xB5A2, 0x8BB6, 0xB5A3, 0x8BB7, 0xB5A4, 0xB6B2, 0xB5A5, 0x8BB8, 0xB5A6, 0x8BB9, 0xB5A7, 0x8BBA, 0xB5A8, 0xB6B3, 0xB5A9, 0x8BBB, 0xB5AA, 0xB6B4, 0xB5AB, 0xB6B5, 0xB5AC, 0x8BBC, 0xB5AD, 0x8BBD, 0xB5AE, 0x8BBE, 0xB5AF, 0x8BBF, 0xB5B0, 0xB6B6, 0xB5B1, 0xB6B7, 0xB5B2, 0x8BC0, 0xB5B3, 0xB6B8, 0xB5B4, 0xB6B9, 0xB5B5, 0xB6BA, 0xB5B6, 0x8BC1, 0xB5B7, 0x8BC2, 0xB5B8, 0x8BC3, 0xB5B9, 0x8BC4, 0xB5BA, 0x8BC5, 0xB5BB, 0xB6BB, 0xB5BC, 0xB6BC, 0xB5BD, 0xB6BD, 0xB5BE, 0x8BC6, 0xB5BF, 0x8BC7, 0xB5C0, 0xB6BE, 0xB5C1, 0x8BC8, 0xB5C2, 0x8BC9, 0xB5C3, 0x8BCA, 0xB5C4, 0xB6BF, 0xB5C5, 0x8BCB, 0xB5C6, 0x8BCC, 0xB5C7, 0x8BCD, 0xB5C8, 0x8BCE, 0xB5C9, 0x8BCF, 0xB5CA, 0x8BD0, 0xB5CB, 0x8BD1, 0xB5CC, 0xB6C0, 0xB5CD, 0xB6C1, 0xB5CE, 0x8BD2, 0xB5CF, 0xB6C2, 0xB5D0, 0xB6C3, 0xB5D1, 0xB6C4, 0xB5D2, 0x8BD3, 0xB5D3, 0x8BD4, 0xB5D4, 0x8BD5, 0xB5D5, 0x8BD6, 0xB5D6, 0x8BD7, 0xB5D7, 0x8BD8, 0xB5D8, 0xB6C5, 0xB5D9, 0x8BD9, 0xB5DA, 0x8BDA, 0xB5DB, 0x8BDB, 0xB5DC, 0x8BDC, 0xB5DD, 0x8BDD, 0xB5DE, 0x8BDE, 0xB5DF, 0x8BDF, 0xB5E0, 0x8BE0, 0xB5E1, 0x8BE1, 0xB5E2, 0x8BE2, 0xB5E3, 0x8BE3, 0xB5E4, 0x8BE4, 0xB5E5, 0x8BE5, 0xB5E6, 0x8BE6, 0xB5E7, 0x8BE7, 0xB5E8, 0x8BE8, 0xB5E9, 0x8BE9, 0xB5EA, 0x8BEA, 0xB5EB, 0x8BEB, 0xB5EC, 0xB6C6, 0xB5ED, 0x8BEC, 0xB5EE, 0x8BED, 0xB5EF, 0x8BEE, 0xB5F0, 0x8BEF, 0xB5F1, 0x8BF0, 0xB5F2, 0x8BF1, 0xB5F3, 0x8BF2, 0xB5F4, 0x8BF3, 0xB5F5, 0x8BF4, 0xB5F6, 0x8BF5, 0xB5F7, 0x8BF6, 0xB5F8, 0x8BF7, 0xB5F9, 0x8BF8, 0xB5FA, 0x8BF9, 0xB5FB, 0x8BFA, 0xB5FC, 0x8BFB, 0xB5FD, 0x8BFC, 0xB5FE, 0x8BFD, 0xB5FF, 0x8BFE, 0xB600, 0x8C41, 0xB601, 0x8C42, 0xB602, 0x8C43, 0xB603, 0x8C44, 0xB604, 0x8C45, 0xB605, 0x8C46, 0xB606, 0x8C47, 0xB607, 0x8C48, 0xB608, 0x8C49, 0xB609, 0x8C4A, 0xB60A, 0x8C4B, 0xB60B, 0x8C4C, 0xB60C, 0x8C4D, 0xB60D, 0x8C4E, 0xB60E, 0x8C4F, 0xB60F, 0x8C50, 0xB610, 0xB6C7, 0xB611, 0xB6C8, 0xB612, 0x8C51, 0xB613, 0x8C52, 0xB614, 0xB6C9, 0xB615, 0x8C53, 0xB616, 0x8C54, 0xB617, 0x8C55, 0xB618, 0xB6CA, 0xB619, 0x8C56, 0xB61A, 0x8C57, 0xB61B, 0x8C58, 0xB61C, 0x8C59, 0xB61D, 0x8C5A, 0xB61E, 0x8C61, 0xB61F, 0x8C62, 0xB620, 0x8C63, 0xB621, 0x8C64, 0xB622, 0x8C65, 0xB623, 0x8C66, 0xB624, 0x8C67, 0xB625, 0xB6CB, 0xB626, 0x8C68, 0xB627, 0x8C69, 0xB628, 0x8C6A, 0xB629, 0x8C6B, 0xB62A, 0x8C6C, 0xB62B, 0x8C6D, 0xB62C, 0xB6CC, 0xB62D, 0x8C6E, 0xB62E, 0x8C6F, 0xB62F, 0x8C70, 0xB630, 0x8C71, 0xB631, 0x8C72, 0xB632, 0x8C73, 0xB633, 0x8C74, 0xB634, 0xB6CD, 0xB635, 0x8C75, 0xB636, 0x8C76, 0xB637, 0x8C77, 0xB638, 0x8C78, 0xB639, 0x8C79, 0xB63A, 0x8C7A, 0xB63B, 0x8C81, 0xB63C, 0x8C82, 0xB63D, 0x8C83, 0xB63E, 0x8C84, 0xB63F, 0x8C85, 0xB640, 0x8C86, 0xB641, 0x8C87, 0xB642, 0x8C88, 0xB643, 0x8C89, 0xB644, 0x8C8A, 0xB645, 0x8C8B, 0xB646, 0x8C8C, 0xB647, 0x8C8D, 0xB648, 0xB6CE, 0xB649, 0x8C8E, 0xB64A, 0x8C8F, 0xB64B, 0x8C90, 0xB64C, 0x8C91, 0xB64D, 0x8C92, 0xB64E, 0x8C93, 0xB64F, 0x8C94, 0xB650, 0x8C95, 0xB651, 0x8C96, 0xB652, 0x8C97, 0xB653, 0x8C98, 0xB654, 0x8C99, 0xB655, 0x8C9A, 0xB656, 0x8C9B, 0xB657, 0x8C9C, 0xB658, 0x8C9D, 0xB659, 0x8C9E, 0xB65A, 0x8C9F, 0xB65B, 0x8CA0, 0xB65C, 0x8CA1, 0xB65D, 0x8CA2, 0xB65E, 0x8CA3, 0xB65F, 0x8CA4, 0xB660, 0x8CA5, 0xB661, 0x8CA6, 0xB662, 0x8CA7, 0xB663, 0x8CA8, 0xB664, 0xB6CF, 0xB665, 0x8CA9, 0xB666, 0x8CAA, 0xB667, 0x8CAB, 0xB668, 0xB6D0, 0xB669, 0x8CAC, 0xB66A, 0x8CAD, 0xB66B, 0x8CAE, 0xB66C, 0x8CAF, 0xB66D, 0x8CB0, 0xB66E, 0x8CB1, 0xB66F, 0x8CB2, 0xB670, 0x8CB3, 0xB671, 0x8CB4, 0xB672, 0x8CB5, 0xB673, 0x8CB6, 0xB674, 0x8CB7, 0xB675, 0x8CB8, 0xB676, 0x8CB9, 0xB677, 0x8CBA, 0xB678, 0x8CBB, 0xB679, 0x8CBC, 0xB67A, 0x8CBD, 0xB67B, 0x8CBE, 0xB67C, 0x8CBF, 0xB67D, 0x8CC0, 0xB67E, 0x8CC1, 0xB67F, 0x8CC2, 0xB680, 0x8CC3, 0xB681, 0x8CC4, 0xB682, 0x8CC5, 0xB683, 0x8CC6, 0xB684, 0x8CC7, 0xB685, 0x8CC8, 0xB686, 0x8CC9, 0xB687, 0x8CCA, 0xB688, 0x8CCB, 0xB689, 0x8CCC, 0xB68A, 0x8CCD, 0xB68B, 0x8CCE, 0xB68C, 0x8CCF, 0xB68D, 0x8CD0, 0xB68E, 0x8CD1, 0xB68F, 0x8CD2, 0xB690, 0x8CD3, 0xB691, 0x8CD4, 0xB692, 0x8CD5, 0xB693, 0x8CD6, 0xB694, 0x8CD7, 0xB695, 0x8CD8, 0xB696, 0x8CD9, 0xB697, 0x8CDA, 0xB698, 0x8CDB, 0xB699, 0x8CDC, 0xB69A, 0x8CDD, 0xB69B, 0x8CDE, 0xB69C, 0xB6D1, 0xB69D, 0xB6D2, 0xB69E, 0x8CDF, 0xB69F, 0x8CE0, 0xB6A0, 0xB6D3, 0xB6A1, 0x8CE1, 0xB6A2, 0x8CE2, 0xB6A3, 0x8CE3, 0xB6A4, 0xB6D4, 0xB6A5, 0x8CE4, 0xB6A6, 0x8CE5, 0xB6A7, 0x8CE6, 0xB6A8, 0x8CE7, 0xB6A9, 0x8CE8, 0xB6AA, 0x8CE9, 0xB6AB, 0xB6D5, 0xB6AC, 0xB6D6, 0xB6AD, 0x8CEA, 0xB6AE, 0x8CEB, 0xB6AF, 0x8CEC, 0xB6B0, 0x8CED, 0xB6B1, 0xB6D7, 0xB6B2, 0x8CEE, 0xB6B3, 0x8CEF, 0xB6B4, 0x8CF0, 0xB6B5, 0x8CF1, 0xB6B6, 0x8CF2, 0xB6B7, 0x8CF3, 0xB6B8, 0x8CF4, 0xB6B9, 0x8CF5, 0xB6BA, 0x8CF6, 0xB6BB, 0x8CF7, 0xB6BC, 0x8CF8, 0xB6BD, 0x8CF9, 0xB6BE, 0x8CFA, 0xB6BF, 0x8CFB, 0xB6C0, 0x8CFC, 0xB6C1, 0x8CFD, 0xB6C2, 0x8CFE, 0xB6C3, 0x8D41, 0xB6C4, 0x8D42, 0xB6C5, 0x8D43, 0xB6C6, 0x8D44, 0xB6C7, 0x8D45, 0xB6C8, 0x8D46, 0xB6C9, 0x8D47, 0xB6CA, 0x8D48, 0xB6CB, 0x8D49, 0xB6CC, 0x8D4A, 0xB6CD, 0x8D4B, 0xB6CE, 0x8D4C, 0xB6CF, 0x8D4D, 0xB6D0, 0x8D4E, 0xB6D1, 0x8D4F, 0xB6D2, 0x8D50, 0xB6D3, 0x8D51, 0xB6D4, 0xB6D8, 0xB6D5, 0x8D52, 0xB6D6, 0x8D53, 0xB6D7, 0x8D54, 0xB6D8, 0x8D55, 0xB6D9, 0x8D56, 0xB6DA, 0x8D57, 0xB6DB, 0x8D58, 0xB6DC, 0x8D59, 0xB6DD, 0x8D5A, 0xB6DE, 0x8D61, 0xB6DF, 0x8D62, 0xB6E0, 0x8D63, 0xB6E1, 0x8D64, 0xB6E2, 0x8D65, 0xB6E3, 0x8D66, 0xB6E4, 0x8D67, 0xB6E5, 0x8D68, 0xB6E6, 0x8D69, 0xB6E7, 0x8D6A, 0xB6E8, 0x8D6B, 0xB6E9, 0x8D6C, 0xB6EA, 0x8D6D, 0xB6EB, 0x8D6E, 0xB6EC, 0x8D6F, 0xB6ED, 0x8D70, 0xB6EE, 0x8D71, 0xB6EF, 0x8D72, 0xB6F0, 0xB6D9, 0xB6F1, 0x8D73, 0xB6F2, 0x8D74, 0xB6F3, 0x8D75, 0xB6F4, 0xB6DA, 0xB6F5, 0x8D76, 0xB6F6, 0x8D77, 0xB6F7, 0x8D78, 0xB6F8, 0xB6DB, 0xB6F9, 0x8D79, 0xB6FA, 0x8D7A, 0xB6FB, 0x8D81, 0xB6FC, 0x8D82, 0xB6FD, 0x8D83, 0xB6FE, 0x8D84, 0xB6FF, 0x8D85, 0xB700, 0xB6DC, 0xB701, 0xB6DD, 0xB702, 0x8D86, 0xB703, 0x8D87, 0xB704, 0x8D88, 0xB705, 0xB6DE, 0xB706, 0x8D89, 0xB707, 0x8D8A, 0xB708, 0x8D8B, 0xB709, 0x8D8C, 0xB70A, 0x8D8D, 0xB70B, 0x8D8E, 0xB70C, 0x8D8F, 0xB70D, 0x8D90, 0xB70E, 0x8D91, 0xB70F, 0x8D92, 0xB710, 0x8D93, 0xB711, 0x8D94, 0xB712, 0x8D95, 0xB713, 0x8D96, 0xB714, 0x8D97, 0xB715, 0x8D98, 0xB716, 0x8D99, 0xB717, 0x8D9A, 0xB718, 0x8D9B, 0xB719, 0x8D9C, 0xB71A, 0x8D9D, 0xB71B, 0x8D9E, 0xB71C, 0x8D9F, 0xB71D, 0x8DA0, 0xB71E, 0x8DA1, 0xB71F, 0x8DA2, 0xB720, 0x8DA3, 0xB721, 0x8DA4, 0xB722, 0x8DA5, 0xB723, 0x8DA6, 0xB724, 0x8DA7, 0xB725, 0x8DA8, 0xB726, 0x8DA9, 0xB727, 0x8DAA, 0xB728, 0xB6DF, 0xB729, 0xB6E0, 0xB72A, 0x8DAB, 0xB72B, 0x8DAC, 0xB72C, 0xB6E1, 0xB72D, 0x8DAD, 0xB72E, 0x8DAE, 0xB72F, 0xB6E2, 0xB730, 0xB6E3, 0xB731, 0x8DAF, 0xB732, 0x8DB0, 0xB733, 0x8DB1, 0xB734, 0x8DB2, 0xB735, 0x8DB3, 0xB736, 0x8DB4, 0xB737, 0x8DB5, 0xB738, 0xB6E4, 0xB739, 0xB6E5, 0xB73A, 0x8DB6, 0xB73B, 0xB6E6, 0xB73C, 0x8DB7, 0xB73D, 0x8DB8, 0xB73E, 0x8DB9, 0xB73F, 0x8DBA, 0xB740, 0x8DBB, 0xB741, 0x8DBC, 0xB742, 0x8DBD, 0xB743, 0x8DBE, 0xB744, 0xB6E7, 0xB745, 0x8DBF, 0xB746, 0x8DC0, 0xB747, 0x8DC1, 0xB748, 0xB6E8, 0xB749, 0x8DC2, 0xB74A, 0x8DC3, 0xB74B, 0x8DC4, 0xB74C, 0xB6E9, 0xB74D, 0x8DC5, 0xB74E, 0x8DC6, 0xB74F, 0x8DC7, 0xB750, 0x8DC8, 0xB751, 0x8DC9, 0xB752, 0x8DCA, 0xB753, 0x8DCB, 0xB754, 0xB6EA, 0xB755, 0xB6EB, 0xB756, 0x8DCC, 0xB757, 0x8DCD, 0xB758, 0x8DCE, 0xB759, 0x8DCF, 0xB75A, 0x8DD0, 0xB75B, 0x8DD1, 0xB75C, 0x8DD2, 0xB75D, 0x8DD3, 0xB75E, 0x8DD4, 0xB75F, 0x8DD5, 0xB760, 0xB6EC, 0xB761, 0x8DD6, 0xB762, 0x8DD7, 0xB763, 0x8DD8, 0xB764, 0xB6ED, 0xB765, 0x8DD9, 0xB766, 0x8DDA, 0xB767, 0x8DDB, 0xB768, 0xB6EE, 0xB769, 0x8DDC, 0xB76A, 0x8DDD, 0xB76B, 0x8DDE, 0xB76C, 0x8DDF, 0xB76D, 0x8DE0, 0xB76E, 0x8DE1, 0xB76F, 0x8DE2, 0xB770, 0xB6EF, 0xB771, 0xB6F0, 0xB772, 0x8DE3, 0xB773, 0xB6F1, 0xB774, 0x8DE4, 0xB775, 0xB6F2, 0xB776, 0x8DE5, 0xB777, 0x8DE6, 0xB778, 0x8DE7, 0xB779, 0x8DE8, 0xB77A, 0x8DE9, 0xB77B, 0x8DEA, 0xB77C, 0xB6F3, 0xB77D, 0xB6F4, 0xB77E, 0x8DEB, 0xB77F, 0x8DEC, 0xB780, 0xB6F5, 0xB781, 0x8DED, 0xB782, 0x8DEE, 0xB783, 0x8DEF, 0xB784, 0xB6F6, 0xB785, 0x8DF0, 0xB786, 0x8DF1, 0xB787, 0x8DF2, 0xB788, 0x8DF3, 0xB789, 0x8DF4, 0xB78A, 0x8DF5, 0xB78B, 0x8DF6, 0xB78C, 0xB6F7, 0xB78D, 0xB6F8, 0xB78E, 0x8DF7, 0xB78F, 0xB6F9, 0xB790, 0xB6FA, 0xB791, 0xB6FB, 0xB792, 0xB6FC, 0xB793, 0x8DF8, 0xB794, 0x8DF9, 0xB795, 0x8DFA, 0xB796, 0xB6FD, 0xB797, 0xB6FE, 0xB798, 0xB7A1, 0xB799, 0xB7A2, 0xB79A, 0x8DFB, 0xB79B, 0x8DFC, 0xB79C, 0xB7A3, 0xB79D, 0x8DFD, 0xB79E, 0x8DFE, 0xB79F, 0x8E41, 0xB7A0, 0xB7A4, 0xB7A1, 0x8E42, 0xB7A2, 0x8E43, 0xB7A3, 0x8E44, 0xB7A4, 0x8E45, 0xB7A5, 0x8E46, 0xB7A6, 0x8E47, 0xB7A7, 0x8E48, 0xB7A8, 0xB7A5, 0xB7A9, 0xB7A6, 0xB7AA, 0x8E49, 0xB7AB, 0xB7A7, 0xB7AC, 0xB7A8, 0xB7AD, 0xB7A9, 0xB7AE, 0x8E4A, 0xB7AF, 0x8E4B, 0xB7B0, 0x8E4C, 0xB7B1, 0x8E4D, 0xB7B2, 0x8E4E, 0xB7B3, 0x8E4F, 0xB7B4, 0xB7AA, 0xB7B5, 0xB7AB, 0xB7B6, 0x8E50, 0xB7B7, 0x8E51, 0xB7B8, 0xB7AC, 0xB7B9, 0x8E52, 0xB7BA, 0x8E53, 0xB7BB, 0x8E54, 0xB7BC, 0x8E55, 0xB7BD, 0x8E56, 0xB7BE, 0x8E57, 0xB7BF, 0x8E58, 0xB7C0, 0x8E59, 0xB7C1, 0x8E5A, 0xB7C2, 0x8E61, 0xB7C3, 0x8E62, 0xB7C4, 0x8E63, 0xB7C5, 0x8E64, 0xB7C6, 0x8E65, 0xB7C7, 0xB7AD, 0xB7C8, 0x8E66, 0xB7C9, 0xB7AE, 0xB7CA, 0x8E67, 0xB7CB, 0x8E68, 0xB7CC, 0x8E69, 0xB7CD, 0x8E6A, 0xB7CE, 0x8E6B, 0xB7CF, 0x8E6C, 0xB7D0, 0x8E6D, 0xB7D1, 0x8E6E, 0xB7D2, 0x8E6F, 0xB7D3, 0x8E70, 0xB7D4, 0x8E71, 0xB7D5, 0x8E72, 0xB7D6, 0x8E73, 0xB7D7, 0x8E74, 0xB7D8, 0x8E75, 0xB7D9, 0x8E76, 0xB7DA, 0x8E77, 0xB7DB, 0x8E78, 0xB7DC, 0x8E79, 0xB7DD, 0x8E7A, 0xB7DE, 0x8E81, 0xB7DF, 0x8E82, 0xB7E0, 0x8E83, 0xB7E1, 0x8E84, 0xB7E2, 0x8E85, 0xB7E3, 0x8E86, 0xB7E4, 0x8E87, 0xB7E5, 0x8E88, 0xB7E6, 0x8E89, 0xB7E7, 0x8E8A, 0xB7E8, 0x8E8B, 0xB7E9, 0x8E8C, 0xB7EA, 0x8E8D, 0xB7EB, 0x8E8E, 0xB7EC, 0xB7AF, 0xB7ED, 0xB7B0, 0xB7EE, 0x8E8F, 0xB7EF, 0x8E90, 0xB7F0, 0xB7B1, 0xB7F1, 0x8E91, 0xB7F2, 0x8E92, 0xB7F3, 0x8E93, 0xB7F4, 0xB7B2, 0xB7F5, 0x8E94, 0xB7F6, 0x8E95, 0xB7F7, 0x8E96, 0xB7F8, 0x8E97, 0xB7F9, 0x8E98, 0xB7FA, 0x8E99, 0xB7FB, 0x8E9A, 0xB7FC, 0xB7B3, 0xB7FD, 0xB7B4, 0xB7FE, 0x8E9B, 0xB7FF, 0xB7B5, 0xB800, 0xB7B6, 0xB801, 0xB7B7, 0xB802, 0x8E9C, 0xB803, 0x8E9D, 0xB804, 0x8E9E, 0xB805, 0x8E9F, 0xB806, 0x8EA0, 0xB807, 0xB7B8, 0xB808, 0xB7B9, 0xB809, 0xB7BA, 0xB80A, 0x8EA1, 0xB80B, 0x8EA2, 0xB80C, 0xB7BB, 0xB80D, 0x8EA3, 0xB80E, 0x8EA4, 0xB80F, 0x8EA5, 0xB810, 0xB7BC, 0xB811, 0x8EA6, 0xB812, 0x8EA7, 0xB813, 0x8EA8, 0xB814, 0x8EA9, 0xB815, 0x8EAA, 0xB816, 0x8EAB, 0xB817, 0x8EAC, 0xB818, 0xB7BD, 0xB819, 0xB7BE, 0xB81A, 0x8EAD, 0xB81B, 0xB7BF, 0xB81C, 0x8EAE, 0xB81D, 0xB7C0, 0xB81E, 0x8EAF, 0xB81F, 0x8EB0, 0xB820, 0x8EB1, 0xB821, 0x8EB2, 0xB822, 0x8EB3, 0xB823, 0x8EB4, 0xB824, 0xB7C1, 0xB825, 0xB7C2, 0xB826, 0x8EB5, 0xB827, 0x8EB6, 0xB828, 0xB7C3, 0xB829, 0x8EB7, 0xB82A, 0x8EB8, 0xB82B, 0x8EB9, 0xB82C, 0xB7C4, 0xB82D, 0x8EBA, 0xB82E, 0x8EBB, 0xB82F, 0x8EBC, 0xB830, 0x8EBD, 0xB831, 0x8EBE, 0xB832, 0x8EBF, 0xB833, 0x8EC0, 0xB834, 0xB7C5, 0xB835, 0xB7C6, 0xB836, 0x8EC1, 0xB837, 0xB7C7, 0xB838, 0xB7C8, 0xB839, 0xB7C9, 0xB83A, 0x8EC2, 0xB83B, 0x8EC3, 0xB83C, 0x8EC4, 0xB83D, 0x8EC5, 0xB83E, 0x8EC6, 0xB83F, 0x8EC7, 0xB840, 0xB7CA, 0xB841, 0x8EC8, 0xB842, 0x8EC9, 0xB843, 0x8ECA, 0xB844, 0xB7CB, 0xB845, 0x8ECB, 0xB846, 0x8ECC, 0xB847, 0x8ECD, 0xB848, 0x8ECE, 0xB849, 0x8ECF, 0xB84A, 0x8ED0, 0xB84B, 0x8ED1, 0xB84C, 0x8ED2, 0xB84D, 0x8ED3, 0xB84E, 0x8ED4, 0xB84F, 0x8ED5, 0xB850, 0x8ED6, 0xB851, 0xB7CC, 0xB852, 0x8ED7, 0xB853, 0xB7CD, 0xB854, 0x8ED8, 0xB855, 0x8ED9, 0xB856, 0x8EDA, 0xB857, 0x8EDB, 0xB858, 0x8EDC, 0xB859, 0x8EDD, 0xB85A, 0x8EDE, 0xB85B, 0x8EDF, 0xB85C, 0xB7CE, 0xB85D, 0xB7CF, 0xB85E, 0x8EE0, 0xB85F, 0x8EE1, 0xB860, 0xB7D0, 0xB861, 0x8EE2, 0xB862, 0x8EE3, 0xB863, 0x8EE4, 0xB864, 0xB7D1, 0xB865, 0x8EE5, 0xB866, 0x8EE6, 0xB867, 0x8EE7, 0xB868, 0x8EE8, 0xB869, 0x8EE9, 0xB86A, 0x8EEA, 0xB86B, 0x8EEB, 0xB86C, 0xB7D2, 0xB86D, 0xB7D3, 0xB86E, 0x8EEC, 0xB86F, 0xB7D4, 0xB870, 0x8EED, 0xB871, 0xB7D5, 0xB872, 0x8EEE, 0xB873, 0x8EEF, 0xB874, 0x8EF0, 0xB875, 0x8EF1, 0xB876, 0x8EF2, 0xB877, 0x8EF3, 0xB878, 0xB7D6, 0xB879, 0x8EF4, 0xB87A, 0x8EF5, 0xB87B, 0x8EF6, 0xB87C, 0xB7D7, 0xB87D, 0x8EF7, 0xB87E, 0x8EF8, 0xB87F, 0x8EF9, 0xB880, 0x8EFA, 0xB881, 0x8EFB, 0xB882, 0x8EFC, 0xB883, 0x8EFD, 0xB884, 0x8EFE, 0xB885, 0x8F41, 0xB886, 0x8F42, 0xB887, 0x8F43, 0xB888, 0x8F44, 0xB889, 0x8F45, 0xB88A, 0x8F46, 0xB88B, 0x8F47, 0xB88C, 0x8F48, 0xB88D, 0xB7D8, 0xB88E, 0x8F49, 0xB88F, 0x8F4A, 0xB890, 0x8F4B, 0xB891, 0x8F4C, 0xB892, 0x8F4D, 0xB893, 0x8F4E, 0xB894, 0x8F4F, 0xB895, 0x8F50, 0xB896, 0x8F51, 0xB897, 0x8F52, 0xB898, 0x8F53, 0xB899, 0x8F54, 0xB89A, 0x8F55, 0xB89B, 0x8F56, 0xB89C, 0x8F57, 0xB89D, 0x8F58, 0xB89E, 0x8F59, 0xB89F, 0x8F5A, 0xB8A0, 0x8F61, 0xB8A1, 0x8F62, 0xB8A2, 0x8F63, 0xB8A3, 0x8F64, 0xB8A4, 0x8F65, 0xB8A5, 0x8F66, 0xB8A6, 0x8F67, 0xB8A7, 0x8F68, 0xB8A8, 0xB7D9, 0xB8A9, 0x8F69, 0xB8AA, 0x8F6A, 0xB8AB, 0x8F6B, 0xB8AC, 0x8F6C, 0xB8AD, 0x8F6D, 0xB8AE, 0x8F6E, 0xB8AF, 0x8F6F, 0xB8B0, 0xB7DA, 0xB8B1, 0x8F70, 0xB8B2, 0x8F71, 0xB8B3, 0x8F72, 0xB8B4, 0xB7DB, 0xB8B5, 0x8F73, 0xB8B6, 0x8F74, 0xB8B7, 0x8F75, 0xB8B8, 0xB7DC, 0xB8B9, 0x8F76, 0xB8BA, 0x8F77, 0xB8BB, 0x8F78, 0xB8BC, 0x8F79, 0xB8BD, 0x8F7A, 0xB8BE, 0x8F81, 0xB8BF, 0x8F82, 0xB8C0, 0xB7DD, 0xB8C1, 0xB7DE, 0xB8C2, 0x8F83, 0xB8C3, 0xB7DF, 0xB8C4, 0x8F84, 0xB8C5, 0xB7E0, 0xB8C6, 0x8F85, 0xB8C7, 0x8F86, 0xB8C8, 0x8F87, 0xB8C9, 0x8F88, 0xB8CA, 0x8F89, 0xB8CB, 0x8F8A, 0xB8CC, 0xB7E1, 0xB8CD, 0x8F8B, 0xB8CE, 0x8F8C, 0xB8CF, 0x8F8D, 0xB8D0, 0xB7E2, 0xB8D1, 0x8F8E, 0xB8D2, 0x8F8F, 0xB8D3, 0x8F90, 0xB8D4, 0xB7E3, 0xB8D5, 0x8F91, 0xB8D6, 0x8F92, 0xB8D7, 0x8F93, 0xB8D8, 0x8F94, 0xB8D9, 0x8F95, 0xB8DA, 0x8F96, 0xB8DB, 0x8F97, 0xB8DC, 0x8F98, 0xB8DD, 0xB7E4, 0xB8DE, 0x8F99, 0xB8DF, 0xB7E5, 0xB8E0, 0x8F9A, 0xB8E1, 0xB7E6, 0xB8E2, 0x8F9B, 0xB8E3, 0x8F9C, 0xB8E4, 0x8F9D, 0xB8E5, 0x8F9E, 0xB8E6, 0x8F9F, 0xB8E7, 0x8FA0, 0xB8E8, 0xB7E7, 0xB8E9, 0xB7E8, 0xB8EA, 0x8FA1, 0xB8EB, 0x8FA2, 0xB8EC, 0xB7E9, 0xB8ED, 0x8FA3, 0xB8EE, 0x8FA4, 0xB8EF, 0x8FA5, 0xB8F0, 0xB7EA, 0xB8F1, 0x8FA6, 0xB8F2, 0x8FA7, 0xB8F3, 0x8FA8, 0xB8F4, 0x8FA9, 0xB8F5, 0x8FAA, 0xB8F6, 0x8FAB, 0xB8F7, 0x8FAC, 0xB8F8, 0xB7EB, 0xB8F9, 0xB7EC, 0xB8FA, 0x8FAD, 0xB8FB, 0xB7ED, 0xB8FC, 0x8FAE, 0xB8FD, 0xB7EE, 0xB8FE, 0x8FAF, 0xB8FF, 0x8FB0, 0xB900, 0x8FB1, 0xB901, 0x8FB2, 0xB902, 0x8FB3, 0xB903, 0x8FB4, 0xB904, 0xB7EF, 0xB905, 0x8FB5, 0xB906, 0x8FB6, 0xB907, 0x8FB7, 0xB908, 0x8FB8, 0xB909, 0x8FB9, 0xB90A, 0x8FBA, 0xB90B, 0x8FBB, 0xB90C, 0x8FBC, 0xB90D, 0x8FBD, 0xB90E, 0x8FBE, 0xB90F, 0x8FBF, 0xB910, 0x8FC0, 0xB911, 0x8FC1, 0xB912, 0x8FC2, 0xB913, 0x8FC3, 0xB914, 0x8FC4, 0xB915, 0x8FC5, 0xB916, 0x8FC6, 0xB917, 0x8FC7, 0xB918, 0xB7F0, 0xB919, 0x8FC8, 0xB91A, 0x8FC9, 0xB91B, 0x8FCA, 0xB91C, 0x8FCB, 0xB91D, 0x8FCC, 0xB91E, 0x8FCD, 0xB91F, 0x8FCE, 0xB920, 0xB7F1, 0xB921, 0x8FCF, 0xB922, 0x8FD0, 0xB923, 0x8FD1, 0xB924, 0x8FD2, 0xB925, 0x8FD3, 0xB926, 0x8FD4, 0xB927, 0x8FD5, 0xB928, 0x8FD6, 0xB929, 0x8FD7, 0xB92A, 0x8FD8, 0xB92B, 0x8FD9, 0xB92C, 0x8FDA, 0xB92D, 0x8FDB, 0xB92E, 0x8FDC, 0xB92F, 0x8FDD, 0xB930, 0x8FDE, 0xB931, 0x8FDF, 0xB932, 0x8FE0, 0xB933, 0x8FE1, 0xB934, 0x8FE2, 0xB935, 0x8FE3, 0xB936, 0x8FE4, 0xB937, 0x8FE5, 0xB938, 0x8FE6, 0xB939, 0x8FE7, 0xB93A, 0x8FE8, 0xB93B, 0x8FE9, 0xB93C, 0xB7F2, 0xB93D, 0xB7F3, 0xB93E, 0x8FEA, 0xB93F, 0x8FEB, 0xB940, 0xB7F4, 0xB941, 0x8FEC, 0xB942, 0x8FED, 0xB943, 0x8FEE, 0xB944, 0xB7F5, 0xB945, 0x8FEF, 0xB946, 0x8FF0, 0xB947, 0x8FF1, 0xB948, 0x8FF2, 0xB949, 0x8FF3, 0xB94A, 0x8FF4, 0xB94B, 0x8FF5, 0xB94C, 0xB7F6, 0xB94D, 0x8FF6, 0xB94E, 0x8FF7, 0xB94F, 0xB7F7, 0xB950, 0x8FF8, 0xB951, 0xB7F8, 0xB952, 0x8FF9, 0xB953, 0x8FFA, 0xB954, 0x8FFB, 0xB955, 0x8FFC, 0xB956, 0x8FFD, 0xB957, 0x8FFE, 0xB958, 0xB7F9, 0xB959, 0xB7FA, 0xB95A, 0x9041, 0xB95B, 0x9042, 0xB95C, 0xB7FB, 0xB95D, 0x9043, 0xB95E, 0x9044, 0xB95F, 0x9045, 0xB960, 0xB7FC, 0xB961, 0x9046, 0xB962, 0x9047, 0xB963, 0x9048, 0xB964, 0x9049, 0xB965, 0x904A, 0xB966, 0x904B, 0xB967, 0x904C, 0xB968, 0xB7FD, 0xB969, 0xB7FE, 0xB96A, 0x904D, 0xB96B, 0xB8A1, 0xB96C, 0x904E, 0xB96D, 0xB8A2, 0xB96E, 0x904F, 0xB96F, 0x9050, 0xB970, 0x9051, 0xB971, 0x9052, 0xB972, 0x9053, 0xB973, 0x9054, 0xB974, 0xB8A3, 0xB975, 0xB8A4, 0xB976, 0x9055, 0xB977, 0x9056, 0xB978, 0xB8A5, 0xB979, 0x9057, 0xB97A, 0x9058, 0xB97B, 0x9059, 0xB97C, 0xB8A6, 0xB97D, 0x905A, 0xB97E, 0x9061, 0xB97F, 0x9062, 0xB980, 0x9063, 0xB981, 0x9064, 0xB982, 0x9065, 0xB983, 0x9066, 0xB984, 0xB8A7, 0xB985, 0xB8A8, 0xB986, 0x9067, 0xB987, 0xB8A9, 0xB988, 0x9068, 0xB989, 0xB8AA, 0xB98A, 0xB8AB, 0xB98B, 0x9069, 0xB98C, 0x906A, 0xB98D, 0xB8AC, 0xB98E, 0xB8AD, 0xB98F, 0x906B, 0xB990, 0x906C, 0xB991, 0x906D, 0xB992, 0x906E, 0xB993, 0x906F, 0xB994, 0x9070, 0xB995, 0x9071, 0xB996, 0x9072, 0xB997, 0x9073, 0xB998, 0x9074, 0xB999, 0x9075, 0xB99A, 0x9076, 0xB99B, 0x9077, 0xB99C, 0x9078, 0xB99D, 0x9079, 0xB99E, 0x907A, 0xB99F, 0x9081, 0xB9A0, 0x9082, 0xB9A1, 0x9083, 0xB9A2, 0x9084, 0xB9A3, 0x9085, 0xB9A4, 0x9086, 0xB9A5, 0x9087, 0xB9A6, 0x9088, 0xB9A7, 0x9089, 0xB9A8, 0x908A, 0xB9A9, 0x908B, 0xB9AA, 0x908C, 0xB9AB, 0x908D, 0xB9AC, 0xB8AE, 0xB9AD, 0xB8AF, 0xB9AE, 0x908E, 0xB9AF, 0x908F, 0xB9B0, 0xB8B0, 0xB9B1, 0x9090, 0xB9B2, 0x9091, 0xB9B3, 0x9092, 0xB9B4, 0xB8B1, 0xB9B5, 0x9093, 0xB9B6, 0x9094, 0xB9B7, 0x9095, 0xB9B8, 0x9096, 0xB9B9, 0x9097, 0xB9BA, 0x9098, 0xB9BB, 0x9099, 0xB9BC, 0xB8B2, 0xB9BD, 0xB8B3, 0xB9BE, 0x909A, 0xB9BF, 0xB8B4, 0xB9C0, 0x909B, 0xB9C1, 0xB8B5, 0xB9C2, 0x909C, 0xB9C3, 0x909D, 0xB9C4, 0x909E, 0xB9C5, 0x909F, 0xB9C6, 0x90A0, 0xB9C7, 0x90A1, 0xB9C8, 0xB8B6, 0xB9C9, 0xB8B7, 0xB9CA, 0x90A2, 0xB9CB, 0x90A3, 0xB9CC, 0xB8B8, 0xB9CD, 0x90A4, 0xB9CE, 0xB8B9, 0xB9CF, 0xB8BA, 0xB9D0, 0xB8BB, 0xB9D1, 0xB8BC, 0xB9D2, 0xB8BD, 0xB9D3, 0x90A5, 0xB9D4, 0x90A6, 0xB9D5, 0x90A7, 0xB9D6, 0x90A8, 0xB9D7, 0x90A9, 0xB9D8, 0xB8BE, 0xB9D9, 0xB8BF, 0xB9DA, 0x90AA, 0xB9DB, 0xB8C0, 0xB9DC, 0x90AB, 0xB9DD, 0xB8C1, 0xB9DE, 0xB8C2, 0xB9DF, 0x90AC, 0xB9E0, 0x90AD, 0xB9E1, 0xB8C3, 0xB9E2, 0x90AE, 0xB9E3, 0xB8C4, 0xB9E4, 0xB8C5, 0xB9E5, 0xB8C6, 0xB9E6, 0x90AF, 0xB9E7, 0x90B0, 0xB9E8, 0xB8C7, 0xB9E9, 0x90B1, 0xB9EA, 0x90B2, 0xB9EB, 0x90B3, 0xB9EC, 0xB8C8, 0xB9ED, 0x90B4, 0xB9EE, 0x90B5, 0xB9EF, 0x90B6, 0xB9F0, 0x90B7, 0xB9F1, 0x90B8, 0xB9F2, 0x90B9, 0xB9F3, 0x90BA, 0xB9F4, 0xB8C9, 0xB9F5, 0xB8CA, 0xB9F6, 0x90BB, 0xB9F7, 0xB8CB, 0xB9F8, 0xB8CC, 0xB9F9, 0xB8CD, 0xB9FA, 0xB8CE, 0xB9FB, 0x90BC, 0xB9FC, 0x90BD, 0xB9FD, 0x90BE, 0xB9FE, 0x90BF, 0xB9FF, 0x90C0, 0xBA00, 0xB8CF, 0xBA01, 0xB8D0, 0xBA02, 0x90C1, 0xBA03, 0x90C2, 0xBA04, 0x90C3, 0xBA05, 0x90C4, 0xBA06, 0x90C5, 0xBA07, 0x90C6, 0xBA08, 0xB8D1, 0xBA09, 0x90C7, 0xBA0A, 0x90C8, 0xBA0B, 0x90C9, 0xBA0C, 0x90CA, 0xBA0D, 0x90CB, 0xBA0E, 0x90CC, 0xBA0F, 0x90CD, 0xBA10, 0x90CE, 0xBA11, 0x90CF, 0xBA12, 0x90D0, 0xBA13, 0x90D1, 0xBA14, 0x90D2, 0xBA15, 0xB8D2, 0xBA16, 0x90D3, 0xBA17, 0x90D4, 0xBA18, 0x90D5, 0xBA19, 0x90D6, 0xBA1A, 0x90D7, 0xBA1B, 0x90D8, 0xBA1C, 0x90D9, 0xBA1D, 0x90DA, 0xBA1E, 0x90DB, 0xBA1F, 0x90DC, 0xBA20, 0x90DD, 0xBA21, 0x90DE, 0xBA22, 0x90DF, 0xBA23, 0x90E0, 0xBA24, 0x90E1, 0xBA25, 0x90E2, 0xBA26, 0x90E3, 0xBA27, 0x90E4, 0xBA28, 0x90E5, 0xBA29, 0x90E6, 0xBA2A, 0x90E7, 0xBA2B, 0x90E8, 0xBA2C, 0x90E9, 0xBA2D, 0x90EA, 0xBA2E, 0x90EB, 0xBA2F, 0x90EC, 0xBA30, 0x90ED, 0xBA31, 0x90EE, 0xBA32, 0x90EF, 0xBA33, 0x90F0, 0xBA34, 0x90F1, 0xBA35, 0x90F2, 0xBA36, 0x90F3, 0xBA37, 0x90F4, 0xBA38, 0xB8D3, 0xBA39, 0xB8D4, 0xBA3A, 0x90F5, 0xBA3B, 0x90F6, 0xBA3C, 0xB8D5, 0xBA3D, 0x90F7, 0xBA3E, 0x90F8, 0xBA3F, 0x90F9, 0xBA40, 0xB8D6, 0xBA41, 0x90FA, 0xBA42, 0xB8D7, 0xBA43, 0x90FB, 0xBA44, 0x90FC, 0xBA45, 0x90FD, 0xBA46, 0x90FE, 0xBA47, 0x9141, 0xBA48, 0xB8D8, 0xBA49, 0xB8D9, 0xBA4A, 0x9142, 0xBA4B, 0xB8DA, 0xBA4C, 0x9143, 0xBA4D, 0xB8DB, 0xBA4E, 0xB8DC, 0xBA4F, 0x9144, 0xBA50, 0x9145, 0xBA51, 0x9146, 0xBA52, 0x9147, 0xBA53, 0xB8DD, 0xBA54, 0xB8DE, 0xBA55, 0xB8DF, 0xBA56, 0x9148, 0xBA57, 0x9149, 0xBA58, 0xB8E0, 0xBA59, 0x914A, 0xBA5A, 0x914B, 0xBA5B, 0x914C, 0xBA5C, 0xB8E1, 0xBA5D, 0x914D, 0xBA5E, 0x914E, 0xBA5F, 0x914F, 0xBA60, 0x9150, 0xBA61, 0x9151, 0xBA62, 0x9152, 0xBA63, 0x9153, 0xBA64, 0xB8E2, 0xBA65, 0xB8E3, 0xBA66, 0x9154, 0xBA67, 0xB8E4, 0xBA68, 0xB8E5, 0xBA69, 0xB8E6, 0xBA6A, 0x9155, 0xBA6B, 0x9156, 0xBA6C, 0x9157, 0xBA6D, 0x9158, 0xBA6E, 0x9159, 0xBA6F, 0x915A, 0xBA70, 0xB8E7, 0xBA71, 0xB8E8, 0xBA72, 0x9161, 0xBA73, 0x9162, 0xBA74, 0xB8E9, 0xBA75, 0x9163, 0xBA76, 0x9164, 0xBA77, 0x9165, 0xBA78, 0xB8EA, 0xBA79, 0x9166, 0xBA7A, 0x9167, 0xBA7B, 0x9168, 0xBA7C, 0x9169, 0xBA7D, 0x916A, 0xBA7E, 0x916B, 0xBA7F, 0x916C, 0xBA80, 0x916D, 0xBA81, 0x916E, 0xBA82, 0x916F, 0xBA83, 0xB8EB, 0xBA84, 0xB8EC, 0xBA85, 0xB8ED, 0xBA86, 0x9170, 0xBA87, 0xB8EE, 0xBA88, 0x9171, 0xBA89, 0x9172, 0xBA8A, 0x9173, 0xBA8B, 0x9174, 0xBA8C, 0xB8EF, 0xBA8D, 0x9175, 0xBA8E, 0x9176, 0xBA8F, 0x9177, 0xBA90, 0x9178, 0xBA91, 0x9179, 0xBA92, 0x917A, 0xBA93, 0x9181, 0xBA94, 0x9182, 0xBA95, 0x9183, 0xBA96, 0x9184, 0xBA97, 0x9185, 0xBA98, 0x9186, 0xBA99, 0x9187, 0xBA9A, 0x9188, 0xBA9B, 0x9189, 0xBA9C, 0x918A, 0xBA9D, 0x918B, 0xBA9E, 0x918C, 0xBA9F, 0x918D, 0xBAA0, 0x918E, 0xBAA1, 0x918F, 0xBAA2, 0x9190, 0xBAA3, 0x9191, 0xBAA4, 0x9192, 0xBAA5, 0x9193, 0xBAA6, 0x9194, 0xBAA7, 0x9195, 0xBAA8, 0xB8F0, 0xBAA9, 0xB8F1, 0xBAAA, 0x9196, 0xBAAB, 0xB8F2, 0xBAAC, 0xB8F3, 0xBAAD, 0x9197, 0xBAAE, 0x9198, 0xBAAF, 0x9199, 0xBAB0, 0xB8F4, 0xBAB1, 0x919A, 0xBAB2, 0xB8F5, 0xBAB3, 0x919B, 0xBAB4, 0x919C, 0xBAB5, 0x919D, 0xBAB6, 0x919E, 0xBAB7, 0x919F, 0xBAB8, 0xB8F6, 0xBAB9, 0xB8F7, 0xBABA, 0x91A0, 0xBABB, 0xB8F8, 0xBABC, 0x91A1, 0xBABD, 0xB8F9, 0xBABE, 0x91A2, 0xBABF, 0x91A3, 0xBAC0, 0x91A4, 0xBAC1, 0x91A5, 0xBAC2, 0x91A6, 0xBAC3, 0x91A7, 0xBAC4, 0xB8FA, 0xBAC5, 0x91A8, 0xBAC6, 0x91A9, 0xBAC7, 0x91AA, 0xBAC8, 0xB8FB, 0xBAC9, 0x91AB, 0xBACA, 0x91AC, 0xBACB, 0x91AD, 0xBACC, 0x91AE, 0xBACD, 0x91AF, 0xBACE, 0x91B0, 0xBACF, 0x91B1, 0xBAD0, 0x91B2, 0xBAD1, 0x91B3, 0xBAD2, 0x91B4, 0xBAD3, 0x91B5, 0xBAD4, 0x91B6, 0xBAD5, 0x91B7, 0xBAD6, 0x91B8, 0xBAD7, 0x91B9, 0xBAD8, 0xB8FC, 0xBAD9, 0xB8FD, 0xBADA, 0x91BA, 0xBADB, 0x91BB, 0xBADC, 0x91BC, 0xBADD, 0x91BD, 0xBADE, 0x91BE, 0xBADF, 0x91BF, 0xBAE0, 0x91C0, 0xBAE1, 0x91C1, 0xBAE2, 0x91C2, 0xBAE3, 0x91C3, 0xBAE4, 0x91C4, 0xBAE5, 0x91C5, 0xBAE6, 0x91C6, 0xBAE7, 0x91C7, 0xBAE8, 0x91C8, 0xBAE9, 0x91C9, 0xBAEA, 0x91CA, 0xBAEB, 0x91CB, 0xBAEC, 0x91CC, 0xBAED, 0x91CD, 0xBAEE, 0x91CE, 0xBAEF, 0x91CF, 0xBAF0, 0x91D0, 0xBAF1, 0x91D1, 0xBAF2, 0x91D2, 0xBAF3, 0x91D3, 0xBAF4, 0x91D4, 0xBAF5, 0x91D5, 0xBAF6, 0x91D6, 0xBAF7, 0x91D7, 0xBAF8, 0x91D8, 0xBAF9, 0x91D9, 0xBAFA, 0x91DA, 0xBAFB, 0x91DB, 0xBAFC, 0xB8FE, 0xBAFD, 0x91DC, 0xBAFE, 0x91DD, 0xBAFF, 0x91DE, 0xBB00, 0xB9A1, 0xBB01, 0x91DF, 0xBB02, 0x91E0, 0xBB03, 0x91E1, 0xBB04, 0xB9A2, 0xBB05, 0x91E2, 0xBB06, 0x91E3, 0xBB07, 0x91E4, 0xBB08, 0x91E5, 0xBB09, 0x91E6, 0xBB0A, 0x91E7, 0xBB0B, 0x91E8, 0xBB0C, 0x91E9, 0xBB0D, 0xB9A3, 0xBB0E, 0x91EA, 0xBB0F, 0xB9A4, 0xBB10, 0x91EB, 0xBB11, 0xB9A5, 0xBB12, 0x91EC, 0xBB13, 0x91ED, 0xBB14, 0x91EE, 0xBB15, 0x91EF, 0xBB16, 0x91F0, 0xBB17, 0x91F1, 0xBB18, 0xB9A6, 0xBB19, 0x91F2, 0xBB1A, 0x91F3, 0xBB1B, 0x91F4, 0xBB1C, 0xB9A7, 0xBB1D, 0x91F5, 0xBB1E, 0x91F6, 0xBB1F, 0x91F7, 0xBB20, 0xB9A8, 0xBB21, 0x91F8, 0xBB22, 0x91F9, 0xBB23, 0x91FA, 0xBB24, 0x91FB, 0xBB25, 0x91FC, 0xBB26, 0x91FD, 0xBB27, 0x91FE, 0xBB28, 0x9241, 0xBB29, 0xB9A9, 0xBB2A, 0x9242, 0xBB2B, 0xB9AA, 0xBB2C, 0x9243, 0xBB2D, 0x9244, 0xBB2E, 0x9245, 0xBB2F, 0x9246, 0xBB30, 0x9247, 0xBB31, 0x9248, 0xBB32, 0x9249, 0xBB33, 0x924A, 0xBB34, 0xB9AB, 0xBB35, 0xB9AC, 0xBB36, 0xB9AD, 0xBB37, 0x924B, 0xBB38, 0xB9AE, 0xBB39, 0x924C, 0xBB3A, 0x924D, 0xBB3B, 0xB9AF, 0xBB3C, 0xB9B0, 0xBB3D, 0xB9B1, 0xBB3E, 0xB9B2, 0xBB3F, 0x924E, 0xBB40, 0x924F, 0xBB41, 0x9250, 0xBB42, 0x9251, 0xBB43, 0x9252, 0xBB44, 0xB9B3, 0xBB45, 0xB9B4, 0xBB46, 0x9253, 0xBB47, 0xB9B5, 0xBB48, 0x9254, 0xBB49, 0xB9B6, 0xBB4A, 0x9255, 0xBB4B, 0x9256, 0xBB4C, 0x9257, 0xBB4D, 0xB9B7, 0xBB4E, 0x9258, 0xBB4F, 0xB9B8, 0xBB50, 0xB9B9, 0xBB51, 0x9259, 0xBB52, 0x925A, 0xBB53, 0x9261, 0xBB54, 0xB9BA, 0xBB55, 0x9262, 0xBB56, 0x9263, 0xBB57, 0x9264, 0xBB58, 0xB9BB, 0xBB59, 0x9265, 0xBB5A, 0x9266, 0xBB5B, 0x9267, 0xBB5C, 0x9268, 0xBB5D, 0x9269, 0xBB5E, 0x926A, 0xBB5F, 0x926B, 0xBB60, 0x926C, 0xBB61, 0xB9BC, 0xBB62, 0x926D, 0xBB63, 0xB9BD, 0xBB64, 0x926E, 0xBB65, 0x926F, 0xBB66, 0x9270, 0xBB67, 0x9271, 0xBB68, 0x9272, 0xBB69, 0x9273, 0xBB6A, 0x9274, 0xBB6B, 0x9275, 0xBB6C, 0xB9BE, 0xBB6D, 0x9276, 0xBB6E, 0x9277, 0xBB6F, 0x9278, 0xBB70, 0x9279, 0xBB71, 0x927A, 0xBB72, 0x9281, 0xBB73, 0x9282, 0xBB74, 0x9283, 0xBB75, 0x9284, 0xBB76, 0x9285, 0xBB77, 0x9286, 0xBB78, 0x9287, 0xBB79, 0x9288, 0xBB7A, 0x9289, 0xBB7B, 0x928A, 0xBB7C, 0x928B, 0xBB7D, 0x928C, 0xBB7E, 0x928D, 0xBB7F, 0x928E, 0xBB80, 0x928F, 0xBB81, 0x9290, 0xBB82, 0x9291, 0xBB83, 0x9292, 0xBB84, 0x9293, 0xBB85, 0x9294, 0xBB86, 0x9295, 0xBB87, 0x9296, 0xBB88, 0xB9BF, 0xBB89, 0x9297, 0xBB8A, 0x9298, 0xBB8B, 0x9299, 0xBB8C, 0xB9C0, 0xBB8D, 0x929A, 0xBB8E, 0x929B, 0xBB8F, 0x929C, 0xBB90, 0xB9C1, 0xBB91, 0x929D, 0xBB92, 0x929E, 0xBB93, 0x929F, 0xBB94, 0x92A0, 0xBB95, 0x92A1, 0xBB96, 0x92A2, 0xBB97, 0x92A3, 0xBB98, 0x92A4, 0xBB99, 0x92A5, 0xBB9A, 0x92A6, 0xBB9B, 0x92A7, 0xBB9C, 0x92A8, 0xBB9D, 0x92A9, 0xBB9E, 0x92AA, 0xBB9F, 0x92AB, 0xBBA0, 0x92AC, 0xBBA1, 0x92AD, 0xBBA2, 0x92AE, 0xBBA3, 0x92AF, 0xBBA4, 0xB9C2, 0xBBA5, 0x92B0, 0xBBA6, 0x92B1, 0xBBA7, 0x92B2, 0xBBA8, 0xB9C3, 0xBBA9, 0x92B3, 0xBBAA, 0x92B4, 0xBBAB, 0x92B5, 0xBBAC, 0xB9C4, 0xBBAD, 0x92B6, 0xBBAE, 0x92B7, 0xBBAF, 0x92B8, 0xBBB0, 0x92B9, 0xBBB1, 0x92BA, 0xBBB2, 0x92BB, 0xBBB3, 0x92BC, 0xBBB4, 0xB9C5, 0xBBB5, 0x92BD, 0xBBB6, 0x92BE, 0xBBB7, 0xB9C6, 0xBBB8, 0x92BF, 0xBBB9, 0x92C0, 0xBBBA, 0x92C1, 0xBBBB, 0x92C2, 0xBBBC, 0x92C3, 0xBBBD, 0x92C4, 0xBBBE, 0x92C5, 0xBBBF, 0x92C6, 0xBBC0, 0xB9C7, 0xBBC1, 0x92C7, 0xBBC2, 0x92C8, 0xBBC3, 0x92C9, 0xBBC4, 0xB9C8, 0xBBC5, 0x92CA, 0xBBC6, 0x92CB, 0xBBC7, 0x92CC, 0xBBC8, 0xB9C9, 0xBBC9, 0x92CD, 0xBBCA, 0x92CE, 0xBBCB, 0x92CF, 0xBBCC, 0x92D0, 0xBBCD, 0x92D1, 0xBBCE, 0x92D2, 0xBBCF, 0x92D3, 0xBBD0, 0xB9CA, 0xBBD1, 0x92D4, 0xBBD2, 0x92D5, 0xBBD3, 0xB9CB, 0xBBD4, 0x92D6, 0xBBD5, 0x92D7, 0xBBD6, 0x92D8, 0xBBD7, 0x92D9, 0xBBD8, 0x92DA, 0xBBD9, 0x92DB, 0xBBDA, 0x92DC, 0xBBDB, 0x92DD, 0xBBDC, 0x92DE, 0xBBDD, 0x92DF, 0xBBDE, 0x92E0, 0xBBDF, 0x92E1, 0xBBE0, 0x92E2, 0xBBE1, 0x92E3, 0xBBE2, 0x92E4, 0xBBE3, 0x92E5, 0xBBE4, 0x92E6, 0xBBE5, 0x92E7, 0xBBE6, 0x92E8, 0xBBE7, 0x92E9, 0xBBE8, 0x92EA, 0xBBE9, 0x92EB, 0xBBEA, 0x92EC, 0xBBEB, 0x92ED, 0xBBEC, 0x92EE, 0xBBED, 0x92EF, 0xBBEE, 0x92F0, 0xBBEF, 0x92F1, 0xBBF0, 0x92F2, 0xBBF1, 0x92F3, 0xBBF2, 0x92F4, 0xBBF3, 0x92F5, 0xBBF4, 0x92F6, 0xBBF5, 0x92F7, 0xBBF6, 0x92F8, 0xBBF7, 0x92F9, 0xBBF8, 0xB9CC, 0xBBF9, 0xB9CD, 0xBBFA, 0x92FA, 0xBBFB, 0x92FB, 0xBBFC, 0xB9CE, 0xBBFD, 0x92FC, 0xBBFE, 0x92FD, 0xBBFF, 0xB9CF, 0xBC00, 0xB9D0, 0xBC01, 0x92FE, 0xBC02, 0xB9D1, 0xBC03, 0x9341, 0xBC04, 0x9342, 0xBC05, 0x9343, 0xBC06, 0x9344, 0xBC07, 0x9345, 0xBC08, 0xB9D2, 0xBC09, 0xB9D3, 0xBC0A, 0x9346, 0xBC0B, 0xB9D4, 0xBC0C, 0xB9D5, 0xBC0D, 0xB9D6, 0xBC0E, 0x9347, 0xBC0F, 0xB9D7, 0xBC10, 0x9348, 0xBC11, 0xB9D8, 0xBC12, 0x9349, 0xBC13, 0x934A, 0xBC14, 0xB9D9, 0xBC15, 0xB9DA, 0xBC16, 0xB9DB, 0xBC17, 0xB9DC, 0xBC18, 0xB9DD, 0xBC19, 0x934B, 0xBC1A, 0x934C, 0xBC1B, 0xB9DE, 0xBC1C, 0xB9DF, 0xBC1D, 0xB9E0, 0xBC1E, 0xB9E1, 0xBC1F, 0xB9E2, 0xBC20, 0x934D, 0xBC21, 0x934E, 0xBC22, 0x934F, 0xBC23, 0x9350, 0xBC24, 0xB9E3, 0xBC25, 0xB9E4, 0xBC26, 0x9351, 0xBC27, 0xB9E5, 0xBC28, 0x9352, 0xBC29, 0xB9E6, 0xBC2A, 0x9353, 0xBC2B, 0x9354, 0xBC2C, 0x9355, 0xBC2D, 0xB9E7, 0xBC2E, 0x9356, 0xBC2F, 0x9357, 0xBC30, 0xB9E8, 0xBC31, 0xB9E9, 0xBC32, 0x9358, 0xBC33, 0x9359, 0xBC34, 0xB9EA, 0xBC35, 0x935A, 0xBC36, 0x9361, 0xBC37, 0x9362, 0xBC38, 0xB9EB, 0xBC39, 0x9363, 0xBC3A, 0x9364, 0xBC3B, 0x9365, 0xBC3C, 0x9366, 0xBC3D, 0x9367, 0xBC3E, 0x9368, 0xBC3F, 0x9369, 0xBC40, 0xB9EC, 0xBC41, 0xB9ED, 0xBC42, 0x936A, 0xBC43, 0xB9EE, 0xBC44, 0xB9EF, 0xBC45, 0xB9F0, 0xBC46, 0x936B, 0xBC47, 0x936C, 0xBC48, 0x936D, 0xBC49, 0xB9F1, 0xBC4A, 0x936E, 0xBC4B, 0x936F, 0xBC4C, 0xB9F2, 0xBC4D, 0xB9F3, 0xBC4E, 0x9370, 0xBC4F, 0x9371, 0xBC50, 0xB9F4, 0xBC51, 0x9372, 0xBC52, 0x9373, 0xBC53, 0x9374, 0xBC54, 0x9375, 0xBC55, 0x9376, 0xBC56, 0x9377, 0xBC57, 0x9378, 0xBC58, 0x9379, 0xBC59, 0x937A, 0xBC5A, 0x9381, 0xBC5B, 0x9382, 0xBC5C, 0x9383, 0xBC5D, 0xB9F5, 0xBC5E, 0x9384, 0xBC5F, 0x9385, 0xBC60, 0x9386, 0xBC61, 0x9387, 0xBC62, 0x9388, 0xBC63, 0x9389, 0xBC64, 0x938A, 0xBC65, 0x938B, 0xBC66, 0x938C, 0xBC67, 0x938D, 0xBC68, 0x938E, 0xBC69, 0x938F, 0xBC6A, 0x9390, 0xBC6B, 0x9391, 0xBC6C, 0x9392, 0xBC6D, 0x9393, 0xBC6E, 0x9394, 0xBC6F, 0x9395, 0xBC70, 0x9396, 0xBC71, 0x9397, 0xBC72, 0x9398, 0xBC73, 0x9399, 0xBC74, 0x939A, 0xBC75, 0x939B, 0xBC76, 0x939C, 0xBC77, 0x939D, 0xBC78, 0x939E, 0xBC79, 0x939F, 0xBC7A, 0x93A0, 0xBC7B, 0x93A1, 0xBC7C, 0x93A2, 0xBC7D, 0x93A3, 0xBC7E, 0x93A4, 0xBC7F, 0x93A5, 0xBC80, 0x93A6, 0xBC81, 0x93A7, 0xBC82, 0x93A8, 0xBC83, 0x93A9, 0xBC84, 0xB9F6, 0xBC85, 0xB9F7, 0xBC86, 0x93AA, 0xBC87, 0x93AB, 0xBC88, 0xB9F8, 0xBC89, 0x93AC, 0xBC8A, 0x93AD, 0xBC8B, 0xB9F9, 0xBC8C, 0xB9FA, 0xBC8D, 0x93AE, 0xBC8E, 0xB9FB, 0xBC8F, 0x93AF, 0xBC90, 0x93B0, 0xBC91, 0x93B1, 0xBC92, 0x93B2, 0xBC93, 0x93B3, 0xBC94, 0xB9FC, 0xBC95, 0xB9FD, 0xBC96, 0x93B4, 0xBC97, 0xB9FE, 0xBC98, 0x93B5, 0xBC99, 0xBAA1, 0xBC9A, 0xBAA2, 0xBC9B, 0x93B6, 0xBC9C, 0x93B7, 0xBC9D, 0x93B8, 0xBC9E, 0x93B9, 0xBC9F, 0x93BA, 0xBCA0, 0xBAA3, 0xBCA1, 0xBAA4, 0xBCA2, 0x93BB, 0xBCA3, 0x93BC, 0xBCA4, 0xBAA5, 0xBCA5, 0x93BD, 0xBCA6, 0x93BE, 0xBCA7, 0xBAA6, 0xBCA8, 0xBAA7, 0xBCA9, 0x93BF, 0xBCAA, 0x93C0, 0xBCAB, 0x93C1, 0xBCAC, 0x93C2, 0xBCAD, 0x93C3, 0xBCAE, 0x93C4, 0xBCAF, 0x93C5, 0xBCB0, 0xBAA8, 0xBCB1, 0xBAA9, 0xBCB2, 0x93C6, 0xBCB3, 0xBAAA, 0xBCB4, 0xBAAB, 0xBCB5, 0xBAAC, 0xBCB6, 0x93C7, 0xBCB7, 0x93C8, 0xBCB8, 0x93C9, 0xBCB9, 0x93CA, 0xBCBA, 0x93CB, 0xBCBB, 0x93CC, 0xBCBC, 0xBAAD, 0xBCBD, 0xBAAE, 0xBCBE, 0x93CD, 0xBCBF, 0x93CE, 0xBCC0, 0xBAAF, 0xBCC1, 0x93CF, 0xBCC2, 0x93D0, 0xBCC3, 0x93D1, 0xBCC4, 0xBAB0, 0xBCC5, 0x93D2, 0xBCC6, 0x93D3, 0xBCC7, 0x93D4, 0xBCC8, 0x93D5, 0xBCC9, 0x93D6, 0xBCCA, 0x93D7, 0xBCCB, 0x93D8, 0xBCCC, 0x93D9, 0xBCCD, 0xBAB1, 0xBCCE, 0x93DA, 0xBCCF, 0xBAB2, 0xBCD0, 0xBAB3, 0xBCD1, 0xBAB4, 0xBCD2, 0x93DB, 0xBCD3, 0x93DC, 0xBCD4, 0x93DD, 0xBCD5, 0xBAB5, 0xBCD6, 0x93DE, 0xBCD7, 0x93DF, 0xBCD8, 0xBAB6, 0xBCD9, 0x93E0, 0xBCDA, 0x93E1, 0xBCDB, 0x93E2, 0xBCDC, 0xBAB7, 0xBCDD, 0x93E3, 0xBCDE, 0x93E4, 0xBCDF, 0x93E5, 0xBCE0, 0x93E6, 0xBCE1, 0x93E7, 0xBCE2, 0x93E8, 0xBCE3, 0x93E9, 0xBCE4, 0x93EA, 0xBCE5, 0x93EB, 0xBCE6, 0x93EC, 0xBCE7, 0x93ED, 0xBCE8, 0x93EE, 0xBCE9, 0x93EF, 0xBCEA, 0x93F0, 0xBCEB, 0x93F1, 0xBCEC, 0x93F2, 0xBCED, 0x93F3, 0xBCEE, 0x93F4, 0xBCEF, 0x93F5, 0xBCF0, 0x93F6, 0xBCF1, 0x93F7, 0xBCF2, 0x93F8, 0xBCF3, 0x93F9, 0xBCF4, 0xBAB8, 0xBCF5, 0xBAB9, 0xBCF6, 0xBABA, 0xBCF7, 0x93FA, 0xBCF8, 0xBABB, 0xBCF9, 0x93FB, 0xBCFA, 0x93FC, 0xBCFB, 0x93FD, 0xBCFC, 0xBABC, 0xBCFD, 0x93FE, 0xBCFE, 0x9441, 0xBCFF, 0x9442, 0xBD00, 0x9443, 0xBD01, 0x9444, 0xBD02, 0x9445, 0xBD03, 0x9446, 0xBD04, 0xBABD, 0xBD05, 0xBABE, 0xBD06, 0x9447, 0xBD07, 0xBABF, 0xBD08, 0x9448, 0xBD09, 0xBAC0, 0xBD0A, 0x9449, 0xBD0B, 0x944A, 0xBD0C, 0x944B, 0xBD0D, 0x944C, 0xBD0E, 0x944D, 0xBD0F, 0x944E, 0xBD10, 0xBAC1, 0xBD11, 0x944F, 0xBD12, 0x9450, 0xBD13, 0x9451, 0xBD14, 0xBAC2, 0xBD15, 0x9452, 0xBD16, 0x9453, 0xBD17, 0x9454, 0xBD18, 0x9455, 0xBD19, 0x9456, 0xBD1A, 0x9457, 0xBD1B, 0x9458, 0xBD1C, 0x9459, 0xBD1D, 0x945A, 0xBD1E, 0x9461, 0xBD1F, 0x9462, 0xBD20, 0x9463, 0xBD21, 0x9464, 0xBD22, 0x9465, 0xBD23, 0x9466, 0xBD24, 0xBAC3, 0xBD25, 0x9467, 0xBD26, 0x9468, 0xBD27, 0x9469, 0xBD28, 0x946A, 0xBD29, 0x946B, 0xBD2A, 0x946C, 0xBD2B, 0x946D, 0xBD2C, 0xBAC4, 0xBD2D, 0x946E, 0xBD2E, 0x946F, 0xBD2F, 0x9470, 0xBD30, 0x9471, 0xBD31, 0x9472, 0xBD32, 0x9473, 0xBD33, 0x9474, 0xBD34, 0x9475, 0xBD35, 0x9476, 0xBD36, 0x9477, 0xBD37, 0x9478, 0xBD38, 0x9479, 0xBD39, 0x947A, 0xBD3A, 0x9481, 0xBD3B, 0x9482, 0xBD3C, 0x9483, 0xBD3D, 0x9484, 0xBD3E, 0x9485, 0xBD3F, 0x9486, 0xBD40, 0xBAC5, 0xBD41, 0x9487, 0xBD42, 0x9488, 0xBD43, 0x9489, 0xBD44, 0x948A, 0xBD45, 0x948B, 0xBD46, 0x948C, 0xBD47, 0x948D, 0xBD48, 0xBAC6, 0xBD49, 0xBAC7, 0xBD4A, 0x948E, 0xBD4B, 0x948F, 0xBD4C, 0xBAC8, 0xBD4D, 0x9490, 0xBD4E, 0x9491, 0xBD4F, 0x9492, 0xBD50, 0xBAC9, 0xBD51, 0x9493, 0xBD52, 0x9494, 0xBD53, 0x9495, 0xBD54, 0x9496, 0xBD55, 0x9497, 0xBD56, 0x9498, 0xBD57, 0x9499, 0xBD58, 0xBACA, 0xBD59, 0xBACB, 0xBD5A, 0x949A, 0xBD5B, 0x949B, 0xBD5C, 0x949C, 0xBD5D, 0x949D, 0xBD5E, 0x949E, 0xBD5F, 0x949F, 0xBD60, 0x94A0, 0xBD61, 0x94A1, 0xBD62, 0x94A2, 0xBD63, 0x94A3, 0xBD64, 0xBACC, 0xBD65, 0x94A4, 0xBD66, 0x94A5, 0xBD67, 0x94A6, 0xBD68, 0xBACD, 0xBD69, 0x94A7, 0xBD6A, 0x94A8, 0xBD6B, 0x94A9, 0xBD6C, 0x94AA, 0xBD6D, 0x94AB, 0xBD6E, 0x94AC, 0xBD6F, 0x94AD, 0xBD70, 0x94AE, 0xBD71, 0x94AF, 0xBD72, 0x94B0, 0xBD73, 0x94B1, 0xBD74, 0x94B2, 0xBD75, 0x94B3, 0xBD76, 0x94B4, 0xBD77, 0x94B5, 0xBD78, 0x94B6, 0xBD79, 0x94B7, 0xBD7A, 0x94B8, 0xBD7B, 0x94B9, 0xBD7C, 0x94BA, 0xBD7D, 0x94BB, 0xBD7E, 0x94BC, 0xBD7F, 0x94BD, 0xBD80, 0xBACE, 0xBD81, 0xBACF, 0xBD82, 0x94BE, 0xBD83, 0x94BF, 0xBD84, 0xBAD0, 0xBD85, 0x94C0, 0xBD86, 0x94C1, 0xBD87, 0xBAD1, 0xBD88, 0xBAD2, 0xBD89, 0xBAD3, 0xBD8A, 0xBAD4, 0xBD8B, 0x94C2, 0xBD8C, 0x94C3, 0xBD8D, 0x94C4, 0xBD8E, 0x94C5, 0xBD8F, 0x94C6, 0xBD90, 0xBAD5, 0xBD91, 0xBAD6, 0xBD92, 0x94C7, 0xBD93, 0xBAD7, 0xBD94, 0x94C8, 0xBD95, 0xBAD8, 0xBD96, 0x94C9, 0xBD97, 0x94CA, 0xBD98, 0x94CB, 0xBD99, 0xBAD9, 0xBD9A, 0xBADA, 0xBD9B, 0x94CC, 0xBD9C, 0xBADB, 0xBD9D, 0x94CD, 0xBD9E, 0x94CE, 0xBD9F, 0x94CF, 0xBDA0, 0x94D0, 0xBDA1, 0x94D1, 0xBDA2, 0x94D2, 0xBDA3, 0x94D3, 0xBDA4, 0xBADC, 0xBDA5, 0x94D4, 0xBDA6, 0x94D5, 0xBDA7, 0x94D6, 0xBDA8, 0x94D7, 0xBDA9, 0x94D8, 0xBDAA, 0x94D9, 0xBDAB, 0x94DA, 0xBDAC, 0x94DB, 0xBDAD, 0x94DC, 0xBDAE, 0x94DD, 0xBDAF, 0x94DE, 0xBDB0, 0xBADD, 0xBDB1, 0x94DF, 0xBDB2, 0x94E0, 0xBDB3, 0x94E1, 0xBDB4, 0x94E2, 0xBDB5, 0x94E3, 0xBDB6, 0x94E4, 0xBDB7, 0x94E5, 0xBDB8, 0xBADE, 0xBDB9, 0x94E6, 0xBDBA, 0x94E7, 0xBDBB, 0x94E8, 0xBDBC, 0x94E9, 0xBDBD, 0x94EA, 0xBDBE, 0x94EB, 0xBDBF, 0x94EC, 0xBDC0, 0x94ED, 0xBDC1, 0x94EE, 0xBDC2, 0x94EF, 0xBDC3, 0x94F0, 0xBDC4, 0x94F1, 0xBDC5, 0x94F2, 0xBDC6, 0x94F3, 0xBDC7, 0x94F4, 0xBDC8, 0x94F5, 0xBDC9, 0x94F6, 0xBDCA, 0x94F7, 0xBDCB, 0x94F8, 0xBDCC, 0x94F9, 0xBDCD, 0x94FA, 0xBDCE, 0x94FB, 0xBDCF, 0x94FC, 0xBDD0, 0x94FD, 0xBDD1, 0x94FE, 0xBDD2, 0x9541, 0xBDD3, 0x9542, 0xBDD4, 0xBADF, 0xBDD5, 0xBAE0, 0xBDD6, 0x9543, 0xBDD7, 0x9544, 0xBDD8, 0xBAE1, 0xBDD9, 0x9545, 0xBDDA, 0x9546, 0xBDDB, 0x9547, 0xBDDC, 0xBAE2, 0xBDDD, 0x9548, 0xBDDE, 0x9549, 0xBDDF, 0x954A, 0xBDE0, 0x954B, 0xBDE1, 0x954C, 0xBDE2, 0x954D, 0xBDE3, 0x954E, 0xBDE4, 0x954F, 0xBDE5, 0x9550, 0xBDE6, 0x9551, 0xBDE7, 0x9552, 0xBDE8, 0x9553, 0xBDE9, 0xBAE3, 0xBDEA, 0x9554, 0xBDEB, 0x9555, 0xBDEC, 0x9556, 0xBDED, 0x9557, 0xBDEE, 0x9558, 0xBDEF, 0x9559, 0xBDF0, 0xBAE4, 0xBDF1, 0x955A, 0xBDF2, 0x9561, 0xBDF3, 0x9562, 0xBDF4, 0xBAE5, 0xBDF5, 0x9563, 0xBDF6, 0x9564, 0xBDF7, 0x9565, 0xBDF8, 0xBAE6, 0xBDF9, 0x9566, 0xBDFA, 0x9567, 0xBDFB, 0x9568, 0xBDFC, 0x9569, 0xBDFD, 0x956A, 0xBDFE, 0x956B, 0xBDFF, 0x956C, 0xBE00, 0xBAE7, 0xBE01, 0x956D, 0xBE02, 0x956E, 0xBE03, 0xBAE8, 0xBE04, 0x956F, 0xBE05, 0xBAE9, 0xBE06, 0x9570, 0xBE07, 0x9571, 0xBE08, 0x9572, 0xBE09, 0x9573, 0xBE0A, 0x9574, 0xBE0B, 0x9575, 0xBE0C, 0xBAEA, 0xBE0D, 0xBAEB, 0xBE0E, 0x9576, 0xBE0F, 0x9577, 0xBE10, 0xBAEC, 0xBE11, 0x9578, 0xBE12, 0x9579, 0xBE13, 0x957A, 0xBE14, 0xBAED, 0xBE15, 0x9581, 0xBE16, 0x9582, 0xBE17, 0x9583, 0xBE18, 0x9584, 0xBE19, 0x9585, 0xBE1A, 0x9586, 0xBE1B, 0x9587, 0xBE1C, 0xBAEE, 0xBE1D, 0xBAEF, 0xBE1E, 0x9588, 0xBE1F, 0xBAF0, 0xBE20, 0x9589, 0xBE21, 0x958A, 0xBE22, 0x958B, 0xBE23, 0x958C, 0xBE24, 0x958D, 0xBE25, 0x958E, 0xBE26, 0x958F, 0xBE27, 0x9590, 0xBE28, 0x9591, 0xBE29, 0x9592, 0xBE2A, 0x9593, 0xBE2B, 0x9594, 0xBE2C, 0x9595, 0xBE2D, 0x9596, 0xBE2E, 0x9597, 0xBE2F, 0x9598, 0xBE30, 0x9599, 0xBE31, 0x959A, 0xBE32, 0x959B, 0xBE33, 0x959C, 0xBE34, 0x959D, 0xBE35, 0x959E, 0xBE36, 0x959F, 0xBE37, 0x95A0, 0xBE38, 0x95A1, 0xBE39, 0x95A2, 0xBE3A, 0x95A3, 0xBE3B, 0x95A4, 0xBE3C, 0x95A5, 0xBE3D, 0x95A6, 0xBE3E, 0x95A7, 0xBE3F, 0x95A8, 0xBE40, 0x95A9, 0xBE41, 0x95AA, 0xBE42, 0x95AB, 0xBE43, 0x95AC, 0xBE44, 0xBAF1, 0xBE45, 0xBAF2, 0xBE46, 0x95AD, 0xBE47, 0x95AE, 0xBE48, 0xBAF3, 0xBE49, 0x95AF, 0xBE4A, 0x95B0, 0xBE4B, 0x95B1, 0xBE4C, 0xBAF4, 0xBE4D, 0x95B2, 0xBE4E, 0xBAF5, 0xBE4F, 0x95B3, 0xBE50, 0x95B4, 0xBE51, 0x95B5, 0xBE52, 0x95B6, 0xBE53, 0x95B7, 0xBE54, 0xBAF6, 0xBE55, 0xBAF7, 0xBE56, 0x95B8, 0xBE57, 0xBAF8, 0xBE58, 0x95B9, 0xBE59, 0xBAF9, 0xBE5A, 0xBAFA, 0xBE5B, 0xBAFB, 0xBE5C, 0x95BA, 0xBE5D, 0x95BB, 0xBE5E, 0x95BC, 0xBE5F, 0x95BD, 0xBE60, 0xBAFC, 0xBE61, 0xBAFD, 0xBE62, 0x95BE, 0xBE63, 0x95BF, 0xBE64, 0xBAFE, 0xBE65, 0x95C0, 0xBE66, 0x95C1, 0xBE67, 0x95C2, 0xBE68, 0xBBA1, 0xBE69, 0x95C3, 0xBE6A, 0xBBA2, 0xBE6B, 0x95C4, 0xBE6C, 0x95C5, 0xBE6D, 0x95C6, 0xBE6E, 0x95C7, 0xBE6F, 0x95C8, 0xBE70, 0xBBA3, 0xBE71, 0xBBA4, 0xBE72, 0x95C9, 0xBE73, 0xBBA5, 0xBE74, 0xBBA6, 0xBE75, 0xBBA7, 0xBE76, 0x95CA, 0xBE77, 0x95CB, 0xBE78, 0x95CC, 0xBE79, 0x95CD, 0xBE7A, 0x95CE, 0xBE7B, 0xBBA8, 0xBE7C, 0xBBA9, 0xBE7D, 0xBBAA, 0xBE7E, 0x95CF, 0xBE7F, 0x95D0, 0xBE80, 0xBBAB, 0xBE81, 0x95D1, 0xBE82, 0x95D2, 0xBE83, 0x95D3, 0xBE84, 0xBBAC, 0xBE85, 0x95D4, 0xBE86, 0x95D5, 0xBE87, 0x95D6, 0xBE88, 0x95D7, 0xBE89, 0x95D8, 0xBE8A, 0x95D9, 0xBE8B, 0x95DA, 0xBE8C, 0xBBAD, 0xBE8D, 0xBBAE, 0xBE8E, 0x95DB, 0xBE8F, 0xBBAF, 0xBE90, 0xBBB0, 0xBE91, 0xBBB1, 0xBE92, 0x95DC, 0xBE93, 0x95DD, 0xBE94, 0x95DE, 0xBE95, 0x95DF, 0xBE96, 0x95E0, 0xBE97, 0x95E1, 0xBE98, 0xBBB2, 0xBE99, 0xBBB3, 0xBE9A, 0x95E2, 0xBE9B, 0x95E3, 0xBE9C, 0x95E4, 0xBE9D, 0x95E5, 0xBE9E, 0x95E6, 0xBE9F, 0x95E7, 0xBEA0, 0x95E8, 0xBEA1, 0x95E9, 0xBEA2, 0x95EA, 0xBEA3, 0x95EB, 0xBEA4, 0x95EC, 0xBEA5, 0x95ED, 0xBEA6, 0x95EE, 0xBEA7, 0x95EF, 0xBEA8, 0xBBB4, 0xBEA9, 0x95F0, 0xBEAA, 0x95F1, 0xBEAB, 0x95F2, 0xBEAC, 0x95F3, 0xBEAD, 0x95F4, 0xBEAE, 0x95F5, 0xBEAF, 0x95F6, 0xBEB0, 0x95F7, 0xBEB1, 0x95F8, 0xBEB2, 0x95F9, 0xBEB3, 0x95FA, 0xBEB4, 0x95FB, 0xBEB5, 0x95FC, 0xBEB6, 0x95FD, 0xBEB7, 0x95FE, 0xBEB8, 0x9641, 0xBEB9, 0x9642, 0xBEBA, 0x9643, 0xBEBB, 0x9644, 0xBEBC, 0x9645, 0xBEBD, 0x9646, 0xBEBE, 0x9647, 0xBEBF, 0x9648, 0xBEC0, 0x9649, 0xBEC1, 0x964A, 0xBEC2, 0x964B, 0xBEC3, 0x964C, 0xBEC4, 0x964D, 0xBEC5, 0x964E, 0xBEC6, 0x964F, 0xBEC7, 0x9650, 0xBEC8, 0x9651, 0xBEC9, 0x9652, 0xBECA, 0x9653, 0xBECB, 0x9654, 0xBECC, 0x9655, 0xBECD, 0x9656, 0xBECE, 0x9657, 0xBECF, 0x9658, 0xBED0, 0xBBB5, 0xBED1, 0xBBB6, 0xBED2, 0x9659, 0xBED3, 0x965A, 0xBED4, 0xBBB7, 0xBED5, 0x9661, 0xBED6, 0x9662, 0xBED7, 0xBBB8, 0xBED8, 0xBBB9, 0xBED9, 0x9663, 0xBEDA, 0x9664, 0xBEDB, 0x9665, 0xBEDC, 0x9666, 0xBEDD, 0x9667, 0xBEDE, 0x9668, 0xBEDF, 0x9669, 0xBEE0, 0xBBBA, 0xBEE1, 0x966A, 0xBEE2, 0x966B, 0xBEE3, 0xBBBB, 0xBEE4, 0xBBBC, 0xBEE5, 0xBBBD, 0xBEE6, 0x966C, 0xBEE7, 0x966D, 0xBEE8, 0x966E, 0xBEE9, 0x966F, 0xBEEA, 0x9670, 0xBEEB, 0x9671, 0xBEEC, 0xBBBE, 0xBEED, 0x9672, 0xBEEE, 0x9673, 0xBEEF, 0x9674, 0xBEF0, 0x9675, 0xBEF1, 0x9676, 0xBEF2, 0x9677, 0xBEF3, 0x9678, 0xBEF4, 0x9679, 0xBEF5, 0x967A, 0xBEF6, 0x9681, 0xBEF7, 0x9682, 0xBEF8, 0x9683, 0xBEF9, 0x9684, 0xBEFA, 0x9685, 0xBEFB, 0x9686, 0xBEFC, 0x9687, 0xBEFD, 0x9688, 0xBEFE, 0x9689, 0xBEFF, 0x968A, 0xBF00, 0x968B, 0xBF01, 0xBBBF, 0xBF02, 0x968C, 0xBF03, 0x968D, 0xBF04, 0x968E, 0xBF05, 0x968F, 0xBF06, 0x9690, 0xBF07, 0x9691, 0xBF08, 0xBBC0, 0xBF09, 0xBBC1, 0xBF0A, 0x9692, 0xBF0B, 0x9693, 0xBF0C, 0x9694, 0xBF0D, 0x9695, 0xBF0E, 0x9696, 0xBF0F, 0x9697, 0xBF10, 0x9698, 0xBF11, 0x9699, 0xBF12, 0x969A, 0xBF13, 0x969B, 0xBF14, 0x969C, 0xBF15, 0x969D, 0xBF16, 0x969E, 0xBF17, 0x969F, 0xBF18, 0xBBC2, 0xBF19, 0xBBC3, 0xBF1A, 0x96A0, 0xBF1B, 0xBBC4, 0xBF1C, 0xBBC5, 0xBF1D, 0xBBC6, 0xBF1E, 0x96A1, 0xBF1F, 0x96A2, 0xBF20, 0x96A3, 0xBF21, 0x96A4, 0xBF22, 0x96A5, 0xBF23, 0x96A6, 0xBF24, 0x96A7, 0xBF25, 0x96A8, 0xBF26, 0x96A9, 0xBF27, 0x96AA, 0xBF28, 0x96AB, 0xBF29, 0x96AC, 0xBF2A, 0x96AD, 0xBF2B, 0x96AE, 0xBF2C, 0x96AF, 0xBF2D, 0x96B0, 0xBF2E, 0x96B1, 0xBF2F, 0x96B2, 0xBF30, 0x96B3, 0xBF31, 0x96B4, 0xBF32, 0x96B5, 0xBF33, 0x96B6, 0xBF34, 0x96B7, 0xBF35, 0x96B8, 0xBF36, 0x96B9, 0xBF37, 0x96BA, 0xBF38, 0x96BB, 0xBF39, 0x96BC, 0xBF3A, 0x96BD, 0xBF3B, 0x96BE, 0xBF3C, 0x96BF, 0xBF3D, 0x96C0, 0xBF3E, 0x96C1, 0xBF3F, 0x96C2, 0xBF40, 0xBBC7, 0xBF41, 0xBBC8, 0xBF42, 0x96C3, 0xBF43, 0x96C4, 0xBF44, 0xBBC9, 0xBF45, 0x96C5, 0xBF46, 0x96C6, 0xBF47, 0x96C7, 0xBF48, 0xBBCA, 0xBF49, 0x96C8, 0xBF4A, 0x96C9, 0xBF4B, 0x96CA, 0xBF4C, 0x96CB, 0xBF4D, 0x96CC, 0xBF4E, 0x96CD, 0xBF4F, 0x96CE, 0xBF50, 0xBBCB, 0xBF51, 0xBBCC, 0xBF52, 0x96CF, 0xBF53, 0x96D0, 0xBF54, 0x96D1, 0xBF55, 0xBBCD, 0xBF56, 0x96D2, 0xBF57, 0x96D3, 0xBF58, 0x96D4, 0xBF59, 0x96D5, 0xBF5A, 0x96D6, 0xBF5B, 0x96D7, 0xBF5C, 0x96D8, 0xBF5D, 0x96D9, 0xBF5E, 0x96DA, 0xBF5F, 0x96DB, 0xBF60, 0x96DC, 0xBF61, 0x96DD, 0xBF62, 0x96DE, 0xBF63, 0x96DF, 0xBF64, 0x96E0, 0xBF65, 0x96E1, 0xBF66, 0x96E2, 0xBF67, 0x96E3, 0xBF68, 0x96E4, 0xBF69, 0x96E5, 0xBF6A, 0x96E6, 0xBF6B, 0x96E7, 0xBF6C, 0x96E8, 0xBF6D, 0x96E9, 0xBF6E, 0x96EA, 0xBF6F, 0x96EB, 0xBF70, 0x96EC, 0xBF71, 0x96ED, 0xBF72, 0x96EE, 0xBF73, 0x96EF, 0xBF74, 0x96F0, 0xBF75, 0x96F1, 0xBF76, 0x96F2, 0xBF77, 0x96F3, 0xBF78, 0x96F4, 0xBF79, 0x96F5, 0xBF7A, 0x96F6, 0xBF7B, 0x96F7, 0xBF7C, 0x96F8, 0xBF7D, 0x96F9, 0xBF7E, 0x96FA, 0xBF7F, 0x96FB, 0xBF80, 0x96FC, 0xBF81, 0x96FD, 0xBF82, 0x96FE, 0xBF83, 0x9741, 0xBF84, 0x9742, 0xBF85, 0x9743, 0xBF86, 0x9744, 0xBF87, 0x9745, 0xBF88, 0x9746, 0xBF89, 0x9747, 0xBF8A, 0x9748, 0xBF8B, 0x9749, 0xBF8C, 0x974A, 0xBF8D, 0x974B, 0xBF8E, 0x974C, 0xBF8F, 0x974D, 0xBF90, 0x974E, 0xBF91, 0x974F, 0xBF92, 0x9750, 0xBF93, 0x9751, 0xBF94, 0xBBCE, 0xBF95, 0x9752, 0xBF96, 0x9753, 0xBF97, 0x9754, 0xBF98, 0x9755, 0xBF99, 0x9756, 0xBF9A, 0x9757, 0xBF9B, 0x9758, 0xBF9C, 0x9759, 0xBF9D, 0x975A, 0xBF9E, 0x9761, 0xBF9F, 0x9762, 0xBFA0, 0x9763, 0xBFA1, 0x9764, 0xBFA2, 0x9765, 0xBFA3, 0x9766, 0xBFA4, 0x9767, 0xBFA5, 0x9768, 0xBFA6, 0x9769, 0xBFA7, 0x976A, 0xBFA8, 0x976B, 0xBFA9, 0x976C, 0xBFAA, 0x976D, 0xBFAB, 0x976E, 0xBFAC, 0x976F, 0xBFAD, 0x9770, 0xBFAE, 0x9771, 0xBFAF, 0x9772, 0xBFB0, 0xBBCF, 0xBFB1, 0x9773, 0xBFB2, 0x9774, 0xBFB3, 0x9775, 0xBFB4, 0x9776, 0xBFB5, 0x9777, 0xBFB6, 0x9778, 0xBFB7, 0x9779, 0xBFB8, 0x977A, 0xBFB9, 0x9781, 0xBFBA, 0x9782, 0xBFBB, 0x9783, 0xBFBC, 0x9784, 0xBFBD, 0x9785, 0xBFBE, 0x9786, 0xBFBF, 0x9787, 0xBFC0, 0x9788, 0xBFC1, 0x9789, 0xBFC2, 0x978A, 0xBFC3, 0x978B, 0xBFC4, 0x978C, 0xBFC5, 0xBBD0, 0xBFC6, 0x978D, 0xBFC7, 0x978E, 0xBFC8, 0x978F, 0xBFC9, 0x9790, 0xBFCA, 0x9791, 0xBFCB, 0x9792, 0xBFCC, 0xBBD1, 0xBFCD, 0xBBD2, 0xBFCE, 0x9793, 0xBFCF, 0x9794, 0xBFD0, 0xBBD3, 0xBFD1, 0x9795, 0xBFD2, 0x9796, 0xBFD3, 0x9797, 0xBFD4, 0xBBD4, 0xBFD5, 0x9798, 0xBFD6, 0x9799, 0xBFD7, 0x979A, 0xBFD8, 0x979B, 0xBFD9, 0x979C, 0xBFDA, 0x979D, 0xBFDB, 0x979E, 0xBFDC, 0xBBD5, 0xBFDD, 0x979F, 0xBFDE, 0x97A0, 0xBFDF, 0xBBD6, 0xBFE0, 0x97A1, 0xBFE1, 0xBBD7, 0xBFE2, 0x97A2, 0xBFE3, 0x97A3, 0xBFE4, 0x97A4, 0xBFE5, 0x97A5, 0xBFE6, 0x97A6, 0xBFE7, 0x97A7, 0xBFE8, 0x97A8, 0xBFE9, 0x97A9, 0xBFEA, 0x97AA, 0xBFEB, 0x97AB, 0xBFEC, 0x97AC, 0xBFED, 0x97AD, 0xBFEE, 0x97AE, 0xBFEF, 0x97AF, 0xBFF0, 0x97B0, 0xBFF1, 0x97B1, 0xBFF2, 0x97B2, 0xBFF3, 0x97B3, 0xBFF4, 0x97B4, 0xBFF5, 0x97B5, 0xBFF6, 0x97B6, 0xBFF7, 0x97B7, 0xBFF8, 0x97B8, 0xBFF9, 0x97B9, 0xBFFA, 0x97BA, 0xBFFB, 0x97BB, 0xBFFC, 0x97BC, 0xBFFD, 0x97BD, 0xBFFE, 0x97BE, 0xBFFF, 0x97BF, 0xC000, 0x97C0, 0xC001, 0x97C1, 0xC002, 0x97C2, 0xC003, 0x97C3, 0xC004, 0x97C4, 0xC005, 0x97C5, 0xC006, 0x97C6, 0xC007, 0x97C7, 0xC008, 0x97C8, 0xC009, 0x97C9, 0xC00A, 0x97CA, 0xC00B, 0x97CB, 0xC00C, 0x97CC, 0xC00D, 0x97CD, 0xC00E, 0x97CE, 0xC00F, 0x97CF, 0xC010, 0x97D0, 0xC011, 0x97D1, 0xC012, 0x97D2, 0xC013, 0x97D3, 0xC014, 0x97D4, 0xC015, 0x97D5, 0xC016, 0x97D6, 0xC017, 0x97D7, 0xC018, 0x97D8, 0xC019, 0x97D9, 0xC01A, 0x97DA, 0xC01B, 0x97DB, 0xC01C, 0x97DC, 0xC01D, 0x97DD, 0xC01E, 0x97DE, 0xC01F, 0x97DF, 0xC020, 0x97E0, 0xC021, 0x97E1, 0xC022, 0x97E2, 0xC023, 0x97E3, 0xC024, 0x97E4, 0xC025, 0x97E5, 0xC026, 0x97E6, 0xC027, 0x97E7, 0xC028, 0x97E8, 0xC029, 0x97E9, 0xC02A, 0x97EA, 0xC02B, 0x97EB, 0xC02C, 0x97EC, 0xC02D, 0x97ED, 0xC02E, 0x97EE, 0xC02F, 0x97EF, 0xC030, 0x97F0, 0xC031, 0x97F1, 0xC032, 0x97F2, 0xC033, 0x97F3, 0xC034, 0x97F4, 0xC035, 0x97F5, 0xC036, 0x97F6, 0xC037, 0x97F7, 0xC038, 0x97F8, 0xC039, 0x97F9, 0xC03A, 0x97FA, 0xC03B, 0x97FB, 0xC03C, 0xBBD8, 0xC03D, 0x97FC, 0xC03E, 0x97FD, 0xC03F, 0x97FE, 0xC040, 0x9841, 0xC041, 0x9842, 0xC042, 0x9843, 0xC043, 0x9844, 0xC044, 0x9845, 0xC045, 0x9846, 0xC046, 0x9847, 0xC047, 0x9848, 0xC048, 0x9849, 0xC049, 0x984A, 0xC04A, 0x984B, 0xC04B, 0x984C, 0xC04C, 0x984D, 0xC04D, 0x984E, 0xC04E, 0x984F, 0xC04F, 0x9850, 0xC050, 0x9851, 0xC051, 0xBBD9, 0xC052, 0x9852, 0xC053, 0x9853, 0xC054, 0x9854, 0xC055, 0x9855, 0xC056, 0x9856, 0xC057, 0x9857, 0xC058, 0xBBDA, 0xC059, 0x9858, 0xC05A, 0x9859, 0xC05B, 0x985A, 0xC05C, 0xBBDB, 0xC05D, 0x9861, 0xC05E, 0x9862, 0xC05F, 0x9863, 0xC060, 0xBBDC, 0xC061, 0x9864, 0xC062, 0x9865, 0xC063, 0x9866, 0xC064, 0x9867, 0xC065, 0x9868, 0xC066, 0x9869, 0xC067, 0x986A, 0xC068, 0xBBDD, 0xC069, 0xBBDE, 0xC06A, 0x986B, 0xC06B, 0x986C, 0xC06C, 0x986D, 0xC06D, 0x986E, 0xC06E, 0x986F, 0xC06F, 0x9870, 0xC070, 0x9871, 0xC071, 0x9872, 0xC072, 0x9873, 0xC073, 0x9874, 0xC074, 0x9875, 0xC075, 0x9876, 0xC076, 0x9877, 0xC077, 0x9878, 0xC078, 0x9879, 0xC079, 0x987A, 0xC07A, 0x9881, 0xC07B, 0x9882, 0xC07C, 0x9883, 0xC07D, 0x9884, 0xC07E, 0x9885, 0xC07F, 0x9886, 0xC080, 0x9887, 0xC081, 0x9888, 0xC082, 0x9889, 0xC083, 0x988A, 0xC084, 0x988B, 0xC085, 0x988C, 0xC086, 0x988D, 0xC087, 0x988E, 0xC088, 0x988F, 0xC089, 0x9890, 0xC08A, 0x9891, 0xC08B, 0x9892, 0xC08C, 0x9893, 0xC08D, 0x9894, 0xC08E, 0x9895, 0xC08F, 0x9896, 0xC090, 0xBBDF, 0xC091, 0xBBE0, 0xC092, 0x9897, 0xC093, 0x9898, 0xC094, 0xBBE1, 0xC095, 0x9899, 0xC096, 0x989A, 0xC097, 0x989B, 0xC098, 0xBBE2, 0xC099, 0x989C, 0xC09A, 0x989D, 0xC09B, 0x989E, 0xC09C, 0x989F, 0xC09D, 0x98A0, 0xC09E, 0x98A1, 0xC09F, 0x98A2, 0xC0A0, 0xBBE3, 0xC0A1, 0xBBE4, 0xC0A2, 0x98A3, 0xC0A3, 0xBBE5, 0xC0A4, 0x98A4, 0xC0A5, 0xBBE6, 0xC0A6, 0x98A5, 0xC0A7, 0x98A6, 0xC0A8, 0x98A7, 0xC0A9, 0x98A8, 0xC0AA, 0x98A9, 0xC0AB, 0x98AA, 0xC0AC, 0xBBE7, 0xC0AD, 0xBBE8, 0xC0AE, 0x98AB, 0xC0AF, 0xBBE9, 0xC0B0, 0xBBEA, 0xC0B1, 0x98AC, 0xC0B2, 0x98AD, 0xC0B3, 0xBBEB, 0xC0B4, 0xBBEC, 0xC0B5, 0xBBED, 0xC0B6, 0xBBEE, 0xC0B7, 0x98AE, 0xC0B8, 0x98AF, 0xC0B9, 0x98B0, 0xC0BA, 0x98B1, 0xC0BB, 0x98B2, 0xC0BC, 0xBBEF, 0xC0BD, 0xBBF0, 0xC0BE, 0x98B3, 0xC0BF, 0xBBF1, 0xC0C0, 0xBBF2, 0xC0C1, 0xBBF3, 0xC0C2, 0x98B4, 0xC0C3, 0x98B5, 0xC0C4, 0x98B6, 0xC0C5, 0xBBF4, 0xC0C6, 0x98B7, 0xC0C7, 0x98B8, 0xC0C8, 0xBBF5, 0xC0C9, 0xBBF6, 0xC0CA, 0x98B9, 0xC0CB, 0x98BA, 0xC0CC, 0xBBF7, 0xC0CD, 0x98BB, 0xC0CE, 0x98BC, 0xC0CF, 0x98BD, 0xC0D0, 0xBBF8, 0xC0D1, 0x98BE, 0xC0D2, 0x98BF, 0xC0D3, 0x98C0, 0xC0D4, 0x98C1, 0xC0D5, 0x98C2, 0xC0D6, 0x98C3, 0xC0D7, 0x98C4, 0xC0D8, 0xBBF9, 0xC0D9, 0xBBFA, 0xC0DA, 0x98C5, 0xC0DB, 0xBBFB, 0xC0DC, 0xBBFC, 0xC0DD, 0xBBFD, 0xC0DE, 0x98C6, 0xC0DF, 0x98C7, 0xC0E0, 0x98C8, 0xC0E1, 0x98C9, 0xC0E2, 0x98CA, 0xC0E3, 0x98CB, 0xC0E4, 0xBBFE, 0xC0E5, 0xBCA1, 0xC0E6, 0x98CC, 0xC0E7, 0x98CD, 0xC0E8, 0xBCA2, 0xC0E9, 0x98CE, 0xC0EA, 0x98CF, 0xC0EB, 0x98D0, 0xC0EC, 0xBCA3, 0xC0ED, 0x98D1, 0xC0EE, 0x98D2, 0xC0EF, 0x98D3, 0xC0F0, 0x98D4, 0xC0F1, 0x98D5, 0xC0F2, 0x98D6, 0xC0F3, 0x98D7, 0xC0F4, 0xBCA4, 0xC0F5, 0xBCA5, 0xC0F6, 0x98D8, 0xC0F7, 0xBCA6, 0xC0F8, 0x98D9, 0xC0F9, 0xBCA7, 0xC0FA, 0x98DA, 0xC0FB, 0x98DB, 0xC0FC, 0x98DC, 0xC0FD, 0x98DD, 0xC0FE, 0x98DE, 0xC0FF, 0x98DF, 0xC100, 0xBCA8, 0xC101, 0x98E0, 0xC102, 0x98E1, 0xC103, 0x98E2, 0xC104, 0xBCA9, 0xC105, 0x98E3, 0xC106, 0x98E4, 0xC107, 0x98E5, 0xC108, 0xBCAA, 0xC109, 0x98E6, 0xC10A, 0x98E7, 0xC10B, 0x98E8, 0xC10C, 0x98E9, 0xC10D, 0x98EA, 0xC10E, 0x98EB, 0xC10F, 0x98EC, 0xC110, 0xBCAB, 0xC111, 0x98ED, 0xC112, 0x98EE, 0xC113, 0x98EF, 0xC114, 0x98F0, 0xC115, 0xBCAC, 0xC116, 0x98F1, 0xC117, 0x98F2, 0xC118, 0x98F3, 0xC119, 0x98F4, 0xC11A, 0x98F5, 0xC11B, 0x98F6, 0xC11C, 0xBCAD, 0xC11D, 0xBCAE, 0xC11E, 0xBCAF, 0xC11F, 0xBCB0, 0xC120, 0xBCB1, 0xC121, 0x98F7, 0xC122, 0x98F8, 0xC123, 0xBCB2, 0xC124, 0xBCB3, 0xC125, 0x98F9, 0xC126, 0xBCB4, 0xC127, 0xBCB5, 0xC128, 0x98FA, 0xC129, 0x98FB, 0xC12A, 0x98FC, 0xC12B, 0x98FD, 0xC12C, 0xBCB6, 0xC12D, 0xBCB7, 0xC12E, 0x98FE, 0xC12F, 0xBCB8, 0xC130, 0xBCB9, 0xC131, 0xBCBA, 0xC132, 0x9941, 0xC133, 0x9942, 0xC134, 0x9943, 0xC135, 0x9944, 0xC136, 0xBCBB, 0xC137, 0x9945, 0xC138, 0xBCBC, 0xC139, 0xBCBD, 0xC13A, 0x9946, 0xC13B, 0x9947, 0xC13C, 0xBCBE, 0xC13D, 0x9948, 0xC13E, 0x9949, 0xC13F, 0x994A, 0xC140, 0xBCBF, 0xC141, 0x994B, 0xC142, 0x994C, 0xC143, 0x994D, 0xC144, 0x994E, 0xC145, 0x994F, 0xC146, 0x9950, 0xC147, 0x9951, 0xC148, 0xBCC0, 0xC149, 0xBCC1, 0xC14A, 0x9952, 0xC14B, 0xBCC2, 0xC14C, 0xBCC3, 0xC14D, 0xBCC4, 0xC14E, 0x9953, 0xC14F, 0x9954, 0xC150, 0x9955, 0xC151, 0x9956, 0xC152, 0x9957, 0xC153, 0x9958, 0xC154, 0xBCC5, 0xC155, 0xBCC6, 0xC156, 0x9959, 0xC157, 0x995A, 0xC158, 0xBCC7, 0xC159, 0x9961, 0xC15A, 0x9962, 0xC15B, 0x9963, 0xC15C, 0xBCC8, 0xC15D, 0x9964, 0xC15E, 0x9965, 0xC15F, 0x9966, 0xC160, 0x9967, 0xC161, 0x9968, 0xC162, 0x9969, 0xC163, 0x996A, 0xC164, 0xBCC9, 0xC165, 0xBCCA, 0xC166, 0x996B, 0xC167, 0xBCCB, 0xC168, 0xBCCC, 0xC169, 0xBCCD, 0xC16A, 0x996C, 0xC16B, 0x996D, 0xC16C, 0x996E, 0xC16D, 0x996F, 0xC16E, 0x9970, 0xC16F, 0x9971, 0xC170, 0xBCCE, 0xC171, 0x9972, 0xC172, 0x9973, 0xC173, 0x9974, 0xC174, 0xBCCF, 0xC175, 0x9975, 0xC176, 0x9976, 0xC177, 0x9977, 0xC178, 0xBCD0, 0xC179, 0x9978, 0xC17A, 0x9979, 0xC17B, 0x997A, 0xC17C, 0x9981, 0xC17D, 0x9982, 0xC17E, 0x9983, 0xC17F, 0x9984, 0xC180, 0x9985, 0xC181, 0x9986, 0xC182, 0x9987, 0xC183, 0x9988, 0xC184, 0x9989, 0xC185, 0xBCD1, 0xC186, 0x998A, 0xC187, 0x998B, 0xC188, 0x998C, 0xC189, 0x998D, 0xC18A, 0x998E, 0xC18B, 0x998F, 0xC18C, 0xBCD2, 0xC18D, 0xBCD3, 0xC18E, 0xBCD4, 0xC18F, 0x9990, 0xC190, 0xBCD5, 0xC191, 0x9991, 0xC192, 0x9992, 0xC193, 0x9993, 0xC194, 0xBCD6, 0xC195, 0x9994, 0xC196, 0xBCD7, 0xC197, 0x9995, 0xC198, 0x9996, 0xC199, 0x9997, 0xC19A, 0x9998, 0xC19B, 0x9999, 0xC19C, 0xBCD8, 0xC19D, 0xBCD9, 0xC19E, 0x999A, 0xC19F, 0xBCDA, 0xC1A0, 0x999B, 0xC1A1, 0xBCDB, 0xC1A2, 0x999C, 0xC1A3, 0x999D, 0xC1A4, 0x999E, 0xC1A5, 0xBCDC, 0xC1A6, 0x999F, 0xC1A7, 0x99A0, 0xC1A8, 0xBCDD, 0xC1A9, 0xBCDE, 0xC1AA, 0x99A1, 0xC1AB, 0x99A2, 0xC1AC, 0xBCDF, 0xC1AD, 0x99A3, 0xC1AE, 0x99A4, 0xC1AF, 0x99A5, 0xC1B0, 0xBCE0, 0xC1B1, 0x99A6, 0xC1B2, 0x99A7, 0xC1B3, 0x99A8, 0xC1B4, 0x99A9, 0xC1B5, 0x99AA, 0xC1B6, 0x99AB, 0xC1B7, 0x99AC, 0xC1B8, 0x99AD, 0xC1B9, 0x99AE, 0xC1BA, 0x99AF, 0xC1BB, 0x99B0, 0xC1BC, 0x99B1, 0xC1BD, 0xBCE1, 0xC1BE, 0x99B2, 0xC1BF, 0x99B3, 0xC1C0, 0x99B4, 0xC1C1, 0x99B5, 0xC1C2, 0x99B6, 0xC1C3, 0x99B7, 0xC1C4, 0xBCE2, 0xC1C5, 0x99B8, 0xC1C6, 0x99B9, 0xC1C7, 0x99BA, 0xC1C8, 0xBCE3, 0xC1C9, 0x99BB, 0xC1CA, 0x99BC, 0xC1CB, 0x99BD, 0xC1CC, 0xBCE4, 0xC1CD, 0x99BE, 0xC1CE, 0x99BF, 0xC1CF, 0x99C0, 0xC1D0, 0x99C1, 0xC1D1, 0x99C2, 0xC1D2, 0x99C3, 0xC1D3, 0x99C4, 0xC1D4, 0xBCE5, 0xC1D5, 0x99C5, 0xC1D6, 0x99C6, 0xC1D7, 0xBCE6, 0xC1D8, 0xBCE7, 0xC1D9, 0x99C7, 0xC1DA, 0x99C8, 0xC1DB, 0x99C9, 0xC1DC, 0x99CA, 0xC1DD, 0x99CB, 0xC1DE, 0x99CC, 0xC1DF, 0x99CD, 0xC1E0, 0xBCE8, 0xC1E1, 0x99CE, 0xC1E2, 0x99CF, 0xC1E3, 0x99D0, 0xC1E4, 0xBCE9, 0xC1E5, 0x99D1, 0xC1E6, 0x99D2, 0xC1E7, 0x99D3, 0xC1E8, 0xBCEA, 0xC1E9, 0x99D4, 0xC1EA, 0x99D5, 0xC1EB, 0x99D6, 0xC1EC, 0x99D7, 0xC1ED, 0x99D8, 0xC1EE, 0x99D9, 0xC1EF, 0x99DA, 0xC1F0, 0xBCEB, 0xC1F1, 0xBCEC, 0xC1F2, 0x99DB, 0xC1F3, 0xBCED, 0xC1F4, 0x99DC, 0xC1F5, 0x99DD, 0xC1F6, 0x99DE, 0xC1F7, 0x99DF, 0xC1F8, 0x99E0, 0xC1F9, 0x99E1, 0xC1FA, 0x99E2, 0xC1FB, 0x99E3, 0xC1FC, 0xBCEE, 0xC1FD, 0xBCEF, 0xC1FE, 0x99E4, 0xC1FF, 0x99E5, 0xC200, 0xBCF0, 0xC201, 0x99E6, 0xC202, 0x99E7, 0xC203, 0x99E8, 0xC204, 0xBCF1, 0xC205, 0x99E9, 0xC206, 0x99EA, 0xC207, 0x99EB, 0xC208, 0x99EC, 0xC209, 0x99ED, 0xC20A, 0x99EE, 0xC20B, 0x99EF, 0xC20C, 0xBCF2, 0xC20D, 0xBCF3, 0xC20E, 0x99F0, 0xC20F, 0xBCF4, 0xC210, 0x99F1, 0xC211, 0xBCF5, 0xC212, 0x99F2, 0xC213, 0x99F3, 0xC214, 0x99F4, 0xC215, 0x99F5, 0xC216, 0x99F6, 0xC217, 0x99F7, 0xC218, 0xBCF6, 0xC219, 0xBCF7, 0xC21A, 0x99F8, 0xC21B, 0x99F9, 0xC21C, 0xBCF8, 0xC21D, 0x99FA, 0xC21E, 0x99FB, 0xC21F, 0xBCF9, 0xC220, 0xBCFA, 0xC221, 0x99FC, 0xC222, 0x99FD, 0xC223, 0x99FE, 0xC224, 0x9A41, 0xC225, 0x9A42, 0xC226, 0x9A43, 0xC227, 0x9A44, 0xC228, 0xBCFB, 0xC229, 0xBCFC, 0xC22A, 0x9A45, 0xC22B, 0xBCFD, 0xC22C, 0x9A46, 0xC22D, 0xBCFE, 0xC22E, 0x9A47, 0xC22F, 0xBDA1, 0xC230, 0x9A48, 0xC231, 0xBDA2, 0xC232, 0xBDA3, 0xC233, 0x9A49, 0xC234, 0xBDA4, 0xC235, 0x9A4A, 0xC236, 0x9A4B, 0xC237, 0x9A4C, 0xC238, 0x9A4D, 0xC239, 0x9A4E, 0xC23A, 0x9A4F, 0xC23B, 0x9A50, 0xC23C, 0x9A51, 0xC23D, 0x9A52, 0xC23E, 0x9A53, 0xC23F, 0x9A54, 0xC240, 0x9A55, 0xC241, 0x9A56, 0xC242, 0x9A57, 0xC243, 0x9A58, 0xC244, 0x9A59, 0xC245, 0x9A5A, 0xC246, 0x9A61, 0xC247, 0x9A62, 0xC248, 0xBDA5, 0xC249, 0x9A63, 0xC24A, 0x9A64, 0xC24B, 0x9A65, 0xC24C, 0x9A66, 0xC24D, 0x9A67, 0xC24E, 0x9A68, 0xC24F, 0x9A69, 0xC250, 0xBDA6, 0xC251, 0xBDA7, 0xC252, 0x9A6A, 0xC253, 0x9A6B, 0xC254, 0xBDA8, 0xC255, 0x9A6C, 0xC256, 0x9A6D, 0xC257, 0x9A6E, 0xC258, 0xBDA9, 0xC259, 0x9A6F, 0xC25A, 0x9A70, 0xC25B, 0x9A71, 0xC25C, 0x9A72, 0xC25D, 0x9A73, 0xC25E, 0x9A74, 0xC25F, 0x9A75, 0xC260, 0xBDAA, 0xC261, 0x9A76, 0xC262, 0x9A77, 0xC263, 0x9A78, 0xC264, 0x9A79, 0xC265, 0xBDAB, 0xC266, 0x9A7A, 0xC267, 0x9A81, 0xC268, 0x9A82, 0xC269, 0x9A83, 0xC26A, 0x9A84, 0xC26B, 0x9A85, 0xC26C, 0xBDAC, 0xC26D, 0xBDAD, 0xC26E, 0x9A86, 0xC26F, 0x9A87, 0xC270, 0xBDAE, 0xC271, 0x9A88, 0xC272, 0x9A89, 0xC273, 0x9A8A, 0xC274, 0xBDAF, 0xC275, 0x9A8B, 0xC276, 0x9A8C, 0xC277, 0x9A8D, 0xC278, 0x9A8E, 0xC279, 0x9A8F, 0xC27A, 0x9A90, 0xC27B, 0x9A91, 0xC27C, 0xBDB0, 0xC27D, 0xBDB1, 0xC27E, 0x9A92, 0xC27F, 0xBDB2, 0xC280, 0x9A93, 0xC281, 0xBDB3, 0xC282, 0x9A94, 0xC283, 0x9A95, 0xC284, 0x9A96, 0xC285, 0x9A97, 0xC286, 0x9A98, 0xC287, 0x9A99, 0xC288, 0xBDB4, 0xC289, 0xBDB5, 0xC28A, 0x9A9A, 0xC28B, 0x9A9B, 0xC28C, 0x9A9C, 0xC28D, 0x9A9D, 0xC28E, 0x9A9E, 0xC28F, 0x9A9F, 0xC290, 0xBDB6, 0xC291, 0x9AA0, 0xC292, 0x9AA1, 0xC293, 0x9AA2, 0xC294, 0x9AA3, 0xC295, 0x9AA4, 0xC296, 0x9AA5, 0xC297, 0x9AA6, 0xC298, 0xBDB7, 0xC299, 0x9AA7, 0xC29A, 0x9AA8, 0xC29B, 0xBDB8, 0xC29C, 0x9AA9, 0xC29D, 0xBDB9, 0xC29E, 0x9AAA, 0xC29F, 0x9AAB, 0xC2A0, 0x9AAC, 0xC2A1, 0x9AAD, 0xC2A2, 0x9AAE, 0xC2A3, 0x9AAF, 0xC2A4, 0xBDBA, 0xC2A5, 0xBDBB, 0xC2A6, 0x9AB0, 0xC2A7, 0x9AB1, 0xC2A8, 0xBDBC, 0xC2A9, 0x9AB2, 0xC2AA, 0x9AB3, 0xC2AB, 0x9AB4, 0xC2AC, 0xBDBD, 0xC2AD, 0xBDBE, 0xC2AE, 0x9AB5, 0xC2AF, 0x9AB6, 0xC2B0, 0x9AB7, 0xC2B1, 0x9AB8, 0xC2B2, 0x9AB9, 0xC2B3, 0x9ABA, 0xC2B4, 0xBDBF, 0xC2B5, 0xBDC0, 0xC2B6, 0x9ABB, 0xC2B7, 0xBDC1, 0xC2B8, 0x9ABC, 0xC2B9, 0xBDC2, 0xC2BA, 0x9ABD, 0xC2BB, 0x9ABE, 0xC2BC, 0x9ABF, 0xC2BD, 0x9AC0, 0xC2BE, 0x9AC1, 0xC2BF, 0x9AC2, 0xC2C0, 0x9AC3, 0xC2C1, 0x9AC4, 0xC2C2, 0x9AC5, 0xC2C3, 0x9AC6, 0xC2C4, 0x9AC7, 0xC2C5, 0x9AC8, 0xC2C6, 0x9AC9, 0xC2C7, 0x9ACA, 0xC2C8, 0x9ACB, 0xC2C9, 0x9ACC, 0xC2CA, 0x9ACD, 0xC2CB, 0x9ACE, 0xC2CC, 0x9ACF, 0xC2CD, 0x9AD0, 0xC2CE, 0x9AD1, 0xC2CF, 0x9AD2, 0xC2D0, 0x9AD3, 0xC2D1, 0x9AD4, 0xC2D2, 0x9AD5, 0xC2D3, 0x9AD6, 0xC2D4, 0x9AD7, 0xC2D5, 0x9AD8, 0xC2D6, 0x9AD9, 0xC2D7, 0x9ADA, 0xC2D8, 0x9ADB, 0xC2D9, 0x9ADC, 0xC2DA, 0x9ADD, 0xC2DB, 0x9ADE, 0xC2DC, 0xBDC3, 0xC2DD, 0xBDC4, 0xC2DE, 0x9ADF, 0xC2DF, 0x9AE0, 0xC2E0, 0xBDC5, 0xC2E1, 0x9AE1, 0xC2E2, 0x9AE2, 0xC2E3, 0xBDC6, 0xC2E4, 0xBDC7, 0xC2E5, 0x9AE3, 0xC2E6, 0x9AE4, 0xC2E7, 0x9AE5, 0xC2E8, 0x9AE6, 0xC2E9, 0x9AE7, 0xC2EA, 0x9AE8, 0xC2EB, 0xBDC8, 0xC2EC, 0xBDC9, 0xC2ED, 0xBDCA, 0xC2EE, 0x9AE9, 0xC2EF, 0xBDCB, 0xC2F0, 0x9AEA, 0xC2F1, 0xBDCC, 0xC2F2, 0x9AEB, 0xC2F3, 0x9AEC, 0xC2F4, 0x9AED, 0xC2F5, 0x9AEE, 0xC2F6, 0xBDCD, 0xC2F7, 0x9AEF, 0xC2F8, 0xBDCE, 0xC2F9, 0xBDCF, 0xC2FA, 0x9AF0, 0xC2FB, 0xBDD0, 0xC2FC, 0xBDD1, 0xC2FD, 0x9AF1, 0xC2FE, 0x9AF2, 0xC2FF, 0x9AF3, 0xC300, 0xBDD2, 0xC301, 0x9AF4, 0xC302, 0x9AF5, 0xC303, 0x9AF6, 0xC304, 0x9AF7, 0xC305, 0x9AF8, 0xC306, 0x9AF9, 0xC307, 0x9AFA, 0xC308, 0xBDD3, 0xC309, 0xBDD4, 0xC30A, 0x9AFB, 0xC30B, 0x9AFC, 0xC30C, 0xBDD5, 0xC30D, 0xBDD6, 0xC30E, 0x9AFD, 0xC30F, 0x9AFE, 0xC310, 0x9B41, 0xC311, 0x9B42, 0xC312, 0x9B43, 0xC313, 0xBDD7, 0xC314, 0xBDD8, 0xC315, 0xBDD9, 0xC316, 0x9B44, 0xC317, 0x9B45, 0xC318, 0xBDDA, 0xC319, 0x9B46, 0xC31A, 0x9B47, 0xC31B, 0x9B48, 0xC31C, 0xBDDB, 0xC31D, 0x9B49, 0xC31E, 0x9B4A, 0xC31F, 0x9B4B, 0xC320, 0x9B4C, 0xC321, 0x9B4D, 0xC322, 0x9B4E, 0xC323, 0x9B4F, 0xC324, 0xBDDC, 0xC325, 0xBDDD, 0xC326, 0x9B50, 0xC327, 0x9B51, 0xC328, 0xBDDE, 0xC329, 0xBDDF, 0xC32A, 0x9B52, 0xC32B, 0x9B53, 0xC32C, 0x9B54, 0xC32D, 0x9B55, 0xC32E, 0x9B56, 0xC32F, 0x9B57, 0xC330, 0x9B58, 0xC331, 0x9B59, 0xC332, 0x9B5A, 0xC333, 0x9B61, 0xC334, 0x9B62, 0xC335, 0x9B63, 0xC336, 0x9B64, 0xC337, 0x9B65, 0xC338, 0x9B66, 0xC339, 0x9B67, 0xC33A, 0x9B68, 0xC33B, 0x9B69, 0xC33C, 0x9B6A, 0xC33D, 0x9B6B, 0xC33E, 0x9B6C, 0xC33F, 0x9B6D, 0xC340, 0x9B6E, 0xC341, 0x9B6F, 0xC342, 0x9B70, 0xC343, 0x9B71, 0xC344, 0x9B72, 0xC345, 0xBDE0, 0xC346, 0x9B73, 0xC347, 0x9B74, 0xC348, 0x9B75, 0xC349, 0x9B76, 0xC34A, 0x9B77, 0xC34B, 0x9B78, 0xC34C, 0x9B79, 0xC34D, 0x9B7A, 0xC34E, 0x9B81, 0xC34F, 0x9B82, 0xC350, 0x9B83, 0xC351, 0x9B84, 0xC352, 0x9B85, 0xC353, 0x9B86, 0xC354, 0x9B87, 0xC355, 0x9B88, 0xC356, 0x9B89, 0xC357, 0x9B8A, 0xC358, 0x9B8B, 0xC359, 0x9B8C, 0xC35A, 0x9B8D, 0xC35B, 0x9B8E, 0xC35C, 0x9B8F, 0xC35D, 0x9B90, 0xC35E, 0x9B91, 0xC35F, 0x9B92, 0xC360, 0x9B93, 0xC361, 0x9B94, 0xC362, 0x9B95, 0xC363, 0x9B96, 0xC364, 0x9B97, 0xC365, 0x9B98, 0xC366, 0x9B99, 0xC367, 0x9B9A, 0xC368, 0xBDE1, 0xC369, 0xBDE2, 0xC36A, 0x9B9B, 0xC36B, 0x9B9C, 0xC36C, 0xBDE3, 0xC36D, 0x9B9D, 0xC36E, 0x9B9E, 0xC36F, 0x9B9F, 0xC370, 0xBDE4, 0xC371, 0x9BA0, 0xC372, 0xBDE5, 0xC373, 0x9BA1, 0xC374, 0x9BA2, 0xC375, 0x9BA3, 0xC376, 0x9BA4, 0xC377, 0x9BA5, 0xC378, 0xBDE6, 0xC379, 0xBDE7, 0xC37A, 0x9BA6, 0xC37B, 0x9BA7, 0xC37C, 0xBDE8, 0xC37D, 0xBDE9, 0xC37E, 0x9BA8, 0xC37F, 0x9BA9, 0xC380, 0x9BAA, 0xC381, 0x9BAB, 0xC382, 0x9BAC, 0xC383, 0x9BAD, 0xC384, 0xBDEA, 0xC385, 0x9BAE, 0xC386, 0x9BAF, 0xC387, 0x9BB0, 0xC388, 0xBDEB, 0xC389, 0x9BB1, 0xC38A, 0x9BB2, 0xC38B, 0x9BB3, 0xC38C, 0xBDEC, 0xC38D, 0x9BB4, 0xC38E, 0x9BB5, 0xC38F, 0x9BB6, 0xC390, 0x9BB7, 0xC391, 0x9BB8, 0xC392, 0x9BB9, 0xC393, 0x9BBA, 0xC394, 0x9BBB, 0xC395, 0x9BBC, 0xC396, 0x9BBD, 0xC397, 0x9BBE, 0xC398, 0x9BBF, 0xC399, 0x9BC0, 0xC39A, 0x9BC1, 0xC39B, 0x9BC2, 0xC39C, 0x9BC3, 0xC39D, 0x9BC4, 0xC39E, 0x9BC5, 0xC39F, 0x9BC6, 0xC3A0, 0x9BC7, 0xC3A1, 0x9BC8, 0xC3A2, 0x9BC9, 0xC3A3, 0x9BCA, 0xC3A4, 0x9BCB, 0xC3A5, 0x9BCC, 0xC3A6, 0x9BCD, 0xC3A7, 0x9BCE, 0xC3A8, 0x9BCF, 0xC3A9, 0x9BD0, 0xC3AA, 0x9BD1, 0xC3AB, 0x9BD2, 0xC3AC, 0x9BD3, 0xC3AD, 0x9BD4, 0xC3AE, 0x9BD5, 0xC3AF, 0x9BD6, 0xC3B0, 0x9BD7, 0xC3B1, 0x9BD8, 0xC3B2, 0x9BD9, 0xC3B3, 0x9BDA, 0xC3B4, 0x9BDB, 0xC3B5, 0x9BDC, 0xC3B6, 0x9BDD, 0xC3B7, 0x9BDE, 0xC3B8, 0x9BDF, 0xC3B9, 0x9BE0, 0xC3BA, 0x9BE1, 0xC3BB, 0x9BE2, 0xC3BC, 0x9BE3, 0xC3BD, 0x9BE4, 0xC3BE, 0x9BE5, 0xC3BF, 0x9BE6, 0xC3C0, 0xBDED, 0xC3C1, 0x9BE7, 0xC3C2, 0x9BE8, 0xC3C3, 0x9BE9, 0xC3C4, 0x9BEA, 0xC3C5, 0x9BEB, 0xC3C6, 0x9BEC, 0xC3C7, 0x9BED, 0xC3C8, 0x9BEE, 0xC3C9, 0x9BEF, 0xC3CA, 0x9BF0, 0xC3CB, 0x9BF1, 0xC3CC, 0x9BF2, 0xC3CD, 0x9BF3, 0xC3CE, 0x9BF4, 0xC3CF, 0x9BF5, 0xC3D0, 0x9BF6, 0xC3D1, 0x9BF7, 0xC3D2, 0x9BF8, 0xC3D3, 0x9BF9, 0xC3D4, 0x9BFA, 0xC3D5, 0x9BFB, 0xC3D6, 0x9BFC, 0xC3D7, 0x9BFD, 0xC3D8, 0xBDEE, 0xC3D9, 0xBDEF, 0xC3DA, 0x9BFE, 0xC3DB, 0x9C41, 0xC3DC, 0xBDF0, 0xC3DD, 0x9C42, 0xC3DE, 0x9C43, 0xC3DF, 0xBDF1, 0xC3E0, 0xBDF2, 0xC3E1, 0x9C44, 0xC3E2, 0xBDF3, 0xC3E3, 0x9C45, 0xC3E4, 0x9C46, 0xC3E5, 0x9C47, 0xC3E6, 0x9C48, 0xC3E7, 0x9C49, 0xC3E8, 0xBDF4, 0xC3E9, 0xBDF5, 0xC3EA, 0x9C4A, 0xC3EB, 0x9C4B, 0xC3EC, 0x9C4C, 0xC3ED, 0xBDF6, 0xC3EE, 0x9C4D, 0xC3EF, 0x9C4E, 0xC3F0, 0x9C4F, 0xC3F1, 0x9C50, 0xC3F2, 0x9C51, 0xC3F3, 0x9C52, 0xC3F4, 0xBDF7, 0xC3F5, 0xBDF8, 0xC3F6, 0x9C53, 0xC3F7, 0x9C54, 0xC3F8, 0xBDF9, 0xC3F9, 0x9C55, 0xC3FA, 0x9C56, 0xC3FB, 0x9C57, 0xC3FC, 0x9C58, 0xC3FD, 0x9C59, 0xC3FE, 0x9C5A, 0xC3FF, 0x9C61, 0xC400, 0x9C62, 0xC401, 0x9C63, 0xC402, 0x9C64, 0xC403, 0x9C65, 0xC404, 0x9C66, 0xC405, 0x9C67, 0xC406, 0x9C68, 0xC407, 0x9C69, 0xC408, 0xBDFA, 0xC409, 0x9C6A, 0xC40A, 0x9C6B, 0xC40B, 0x9C6C, 0xC40C, 0x9C6D, 0xC40D, 0x9C6E, 0xC40E, 0x9C6F, 0xC40F, 0x9C70, 0xC410, 0xBDFB, 0xC411, 0x9C71, 0xC412, 0x9C72, 0xC413, 0x9C73, 0xC414, 0x9C74, 0xC415, 0x9C75, 0xC416, 0x9C76, 0xC417, 0x9C77, 0xC418, 0x9C78, 0xC419, 0x9C79, 0xC41A, 0x9C7A, 0xC41B, 0x9C81, 0xC41C, 0x9C82, 0xC41D, 0x9C83, 0xC41E, 0x9C84, 0xC41F, 0x9C85, 0xC420, 0x9C86, 0xC421, 0x9C87, 0xC422, 0x9C88, 0xC423, 0x9C89, 0xC424, 0xBDFC, 0xC425, 0x9C8A, 0xC426, 0x9C8B, 0xC427, 0x9C8C, 0xC428, 0x9C8D, 0xC429, 0x9C8E, 0xC42A, 0x9C8F, 0xC42B, 0x9C90, 0xC42C, 0xBDFD, 0xC42D, 0x9C91, 0xC42E, 0x9C92, 0xC42F, 0x9C93, 0xC430, 0xBDFE, 0xC431, 0x9C94, 0xC432, 0x9C95, 0xC433, 0x9C96, 0xC434, 0xBEA1, 0xC435, 0x9C97, 0xC436, 0x9C98, 0xC437, 0x9C99, 0xC438, 0x9C9A, 0xC439, 0x9C9B, 0xC43A, 0x9C9C, 0xC43B, 0x9C9D, 0xC43C, 0xBEA2, 0xC43D, 0xBEA3, 0xC43E, 0x9C9E, 0xC43F, 0x9C9F, 0xC440, 0x9CA0, 0xC441, 0x9CA1, 0xC442, 0x9CA2, 0xC443, 0x9CA3, 0xC444, 0x9CA4, 0xC445, 0x9CA5, 0xC446, 0x9CA6, 0xC447, 0x9CA7, 0xC448, 0xBEA4, 0xC449, 0x9CA8, 0xC44A, 0x9CA9, 0xC44B, 0x9CAA, 0xC44C, 0x9CAB, 0xC44D, 0x9CAC, 0xC44E, 0x9CAD, 0xC44F, 0x9CAE, 0xC450, 0x9CAF, 0xC451, 0x9CB0, 0xC452, 0x9CB1, 0xC453, 0x9CB2, 0xC454, 0x9CB3, 0xC455, 0x9CB4, 0xC456, 0x9CB5, 0xC457, 0x9CB6, 0xC458, 0x9CB7, 0xC459, 0x9CB8, 0xC45A, 0x9CB9, 0xC45B, 0x9CBA, 0xC45C, 0x9CBB, 0xC45D, 0x9CBC, 0xC45E, 0x9CBD, 0xC45F, 0x9CBE, 0xC460, 0x9CBF, 0xC461, 0x9CC0, 0xC462, 0x9CC1, 0xC463, 0x9CC2, 0xC464, 0xBEA5, 0xC465, 0xBEA6, 0xC466, 0x9CC3, 0xC467, 0x9CC4, 0xC468, 0xBEA7, 0xC469, 0x9CC5, 0xC46A, 0x9CC6, 0xC46B, 0x9CC7, 0xC46C, 0xBEA8, 0xC46D, 0x9CC8, 0xC46E, 0x9CC9, 0xC46F, 0x9CCA, 0xC470, 0x9CCB, 0xC471, 0x9CCC, 0xC472, 0x9CCD, 0xC473, 0x9CCE, 0xC474, 0xBEA9, 0xC475, 0xBEAA, 0xC476, 0x9CCF, 0xC477, 0x9CD0, 0xC478, 0x9CD1, 0xC479, 0xBEAB, 0xC47A, 0x9CD2, 0xC47B, 0x9CD3, 0xC47C, 0x9CD4, 0xC47D, 0x9CD5, 0xC47E, 0x9CD6, 0xC47F, 0x9CD7, 0xC480, 0xBEAC, 0xC481, 0x9CD8, 0xC482, 0x9CD9, 0xC483, 0x9CDA, 0xC484, 0x9CDB, 0xC485, 0x9CDC, 0xC486, 0x9CDD, 0xC487, 0x9CDE, 0xC488, 0x9CDF, 0xC489, 0x9CE0, 0xC48A, 0x9CE1, 0xC48B, 0x9CE2, 0xC48C, 0x9CE3, 0xC48D, 0x9CE4, 0xC48E, 0x9CE5, 0xC48F, 0x9CE6, 0xC490, 0x9CE7, 0xC491, 0x9CE8, 0xC492, 0x9CE9, 0xC493, 0x9CEA, 0xC494, 0xBEAD, 0xC495, 0x9CEB, 0xC496, 0x9CEC, 0xC497, 0x9CED, 0xC498, 0x9CEE, 0xC499, 0x9CEF, 0xC49A, 0x9CF0, 0xC49B, 0x9CF1, 0xC49C, 0xBEAE, 0xC49D, 0x9CF2, 0xC49E, 0x9CF3, 0xC49F, 0x9CF4, 0xC4A0, 0x9CF5, 0xC4A1, 0x9CF6, 0xC4A2, 0x9CF7, 0xC4A3, 0x9CF8, 0xC4A4, 0x9CF9, 0xC4A5, 0x9CFA, 0xC4A6, 0x9CFB, 0xC4A7, 0x9CFC, 0xC4A8, 0x9CFD, 0xC4A9, 0x9CFE, 0xC4AA, 0x9D41, 0xC4AB, 0x9D42, 0xC4AC, 0x9D43, 0xC4AD, 0x9D44, 0xC4AE, 0x9D45, 0xC4AF, 0x9D46, 0xC4B0, 0x9D47, 0xC4B1, 0x9D48, 0xC4B2, 0x9D49, 0xC4B3, 0x9D4A, 0xC4B4, 0x9D4B, 0xC4B5, 0x9D4C, 0xC4B6, 0x9D4D, 0xC4B7, 0x9D4E, 0xC4B8, 0xBEAF, 0xC4B9, 0x9D4F, 0xC4BA, 0x9D50, 0xC4BB, 0x9D51, 0xC4BC, 0xBEB0, 0xC4BD, 0x9D52, 0xC4BE, 0x9D53, 0xC4BF, 0x9D54, 0xC4C0, 0x9D55, 0xC4C1, 0x9D56, 0xC4C2, 0x9D57, 0xC4C3, 0x9D58, 0xC4C4, 0x9D59, 0xC4C5, 0x9D5A, 0xC4C6, 0x9D61, 0xC4C7, 0x9D62, 0xC4C8, 0x9D63, 0xC4C9, 0x9D64, 0xC4CA, 0x9D65, 0xC4CB, 0x9D66, 0xC4CC, 0x9D67, 0xC4CD, 0x9D68, 0xC4CE, 0x9D69, 0xC4CF, 0x9D6A, 0xC4D0, 0x9D6B, 0xC4D1, 0x9D6C, 0xC4D2, 0x9D6D, 0xC4D3, 0x9D6E, 0xC4D4, 0x9D6F, 0xC4D5, 0x9D70, 0xC4D6, 0x9D71, 0xC4D7, 0x9D72, 0xC4D8, 0x9D73, 0xC4D9, 0x9D74, 0xC4DA, 0x9D75, 0xC4DB, 0x9D76, 0xC4DC, 0x9D77, 0xC4DD, 0x9D78, 0xC4DE, 0x9D79, 0xC4DF, 0x9D7A, 0xC4E0, 0x9D81, 0xC4E1, 0x9D82, 0xC4E2, 0x9D83, 0xC4E3, 0x9D84, 0xC4E4, 0x9D85, 0xC4E5, 0x9D86, 0xC4E6, 0x9D87, 0xC4E7, 0x9D88, 0xC4E8, 0x9D89, 0xC4E9, 0xBEB1, 0xC4EA, 0x9D8A, 0xC4EB, 0x9D8B, 0xC4EC, 0x9D8C, 0xC4ED, 0x9D8D, 0xC4EE, 0x9D8E, 0xC4EF, 0x9D8F, 0xC4F0, 0xBEB2, 0xC4F1, 0xBEB3, 0xC4F2, 0x9D90, 0xC4F3, 0x9D91, 0xC4F4, 0xBEB4, 0xC4F5, 0x9D92, 0xC4F6, 0x9D93, 0xC4F7, 0x9D94, 0xC4F8, 0xBEB5, 0xC4F9, 0x9D95, 0xC4FA, 0xBEB6, 0xC4FB, 0x9D96, 0xC4FC, 0x9D97, 0xC4FD, 0x9D98, 0xC4FE, 0x9D99, 0xC4FF, 0xBEB7, 0xC500, 0xBEB8, 0xC501, 0xBEB9, 0xC502, 0x9D9A, 0xC503, 0x9D9B, 0xC504, 0x9D9C, 0xC505, 0x9D9D, 0xC506, 0x9D9E, 0xC507, 0x9D9F, 0xC508, 0x9DA0, 0xC509, 0x9DA1, 0xC50A, 0x9DA2, 0xC50B, 0x9DA3, 0xC50C, 0xBEBA, 0xC50D, 0x9DA4, 0xC50E, 0x9DA5, 0xC50F, 0x9DA6, 0xC510, 0xBEBB, 0xC511, 0x9DA7, 0xC512, 0x9DA8, 0xC513, 0x9DA9, 0xC514, 0xBEBC, 0xC515, 0x9DAA, 0xC516, 0x9DAB, 0xC517, 0x9DAC, 0xC518, 0x9DAD, 0xC519, 0x9DAE, 0xC51A, 0x9DAF, 0xC51B, 0x9DB0, 0xC51C, 0xBEBD, 0xC51D, 0x9DB1, 0xC51E, 0x9DB2, 0xC51F, 0x9DB3, 0xC520, 0x9DB4, 0xC521, 0x9DB5, 0xC522, 0x9DB6, 0xC523, 0x9DB7, 0xC524, 0x9DB8, 0xC525, 0x9DB9, 0xC526, 0x9DBA, 0xC527, 0x9DBB, 0xC528, 0xBEBE, 0xC529, 0xBEBF, 0xC52A, 0x9DBC, 0xC52B, 0x9DBD, 0xC52C, 0xBEC0, 0xC52D, 0x9DBE, 0xC52E, 0x9DBF, 0xC52F, 0x9DC0, 0xC530, 0xBEC1, 0xC531, 0x9DC1, 0xC532, 0x9DC2, 0xC533, 0x9DC3, 0xC534, 0x9DC4, 0xC535, 0x9DC5, 0xC536, 0x9DC6, 0xC537, 0x9DC7, 0xC538, 0xBEC2, 0xC539, 0xBEC3, 0xC53A, 0x9DC8, 0xC53B, 0xBEC4, 0xC53C, 0x9DC9, 0xC53D, 0xBEC5, 0xC53E, 0x9DCA, 0xC53F, 0x9DCB, 0xC540, 0x9DCC, 0xC541, 0x9DCD, 0xC542, 0x9DCE, 0xC543, 0x9DCF, 0xC544, 0xBEC6, 0xC545, 0xBEC7, 0xC546, 0x9DD0, 0xC547, 0x9DD1, 0xC548, 0xBEC8, 0xC549, 0xBEC9, 0xC54A, 0xBECA, 0xC54B, 0x9DD2, 0xC54C, 0xBECB, 0xC54D, 0xBECC, 0xC54E, 0xBECD, 0xC54F, 0x9DD3, 0xC550, 0x9DD4, 0xC551, 0x9DD5, 0xC552, 0x9DD6, 0xC553, 0xBECE, 0xC554, 0xBECF, 0xC555, 0xBED0, 0xC556, 0x9DD7, 0xC557, 0xBED1, 0xC558, 0xBED2, 0xC559, 0xBED3, 0xC55A, 0x9DD8, 0xC55B, 0x9DD9, 0xC55C, 0x9DDA, 0xC55D, 0xBED4, 0xC55E, 0xBED5, 0xC55F, 0x9DDB, 0xC560, 0xBED6, 0xC561, 0xBED7, 0xC562, 0x9DDC, 0xC563, 0x9DDD, 0xC564, 0xBED8, 0xC565, 0x9DDE, 0xC566, 0x9DDF, 0xC567, 0x9DE0, 0xC568, 0xBED9, 0xC569, 0x9DE1, 0xC56A, 0x9DE2, 0xC56B, 0x9DE3, 0xC56C, 0x9DE4, 0xC56D, 0x9DE5, 0xC56E, 0x9DE6, 0xC56F, 0x9DE7, 0xC570, 0xBEDA, 0xC571, 0xBEDB, 0xC572, 0x9DE8, 0xC573, 0xBEDC, 0xC574, 0xBEDD, 0xC575, 0xBEDE, 0xC576, 0x9DE9, 0xC577, 0x9DEA, 0xC578, 0x9DEB, 0xC579, 0x9DEC, 0xC57A, 0x9DED, 0xC57B, 0x9DEE, 0xC57C, 0xBEDF, 0xC57D, 0xBEE0, 0xC57E, 0x9DEF, 0xC57F, 0x9DF0, 0xC580, 0xBEE1, 0xC581, 0x9DF1, 0xC582, 0x9DF2, 0xC583, 0x9DF3, 0xC584, 0xBEE2, 0xC585, 0x9DF4, 0xC586, 0x9DF5, 0xC587, 0xBEE3, 0xC588, 0x9DF6, 0xC589, 0x9DF7, 0xC58A, 0x9DF8, 0xC58B, 0x9DF9, 0xC58C, 0xBEE4, 0xC58D, 0xBEE5, 0xC58E, 0x9DFA, 0xC58F, 0xBEE6, 0xC590, 0x9DFB, 0xC591, 0xBEE7, 0xC592, 0x9DFC, 0xC593, 0x9DFD, 0xC594, 0x9DFE, 0xC595, 0xBEE8, 0xC596, 0x9E41, 0xC597, 0xBEE9, 0xC598, 0xBEEA, 0xC599, 0x9E42, 0xC59A, 0x9E43, 0xC59B, 0x9E44, 0xC59C, 0xBEEB, 0xC59D, 0x9E45, 0xC59E, 0x9E46, 0xC59F, 0x9E47, 0xC5A0, 0xBEEC, 0xC5A1, 0x9E48, 0xC5A2, 0x9E49, 0xC5A3, 0x9E4A, 0xC5A4, 0x9E4B, 0xC5A5, 0x9E4C, 0xC5A6, 0x9E4D, 0xC5A7, 0x9E4E, 0xC5A8, 0x9E4F, 0xC5A9, 0xBEED, 0xC5AA, 0x9E50, 0xC5AB, 0x9E51, 0xC5AC, 0x9E52, 0xC5AD, 0x9E53, 0xC5AE, 0x9E54, 0xC5AF, 0x9E55, 0xC5B0, 0x9E56, 0xC5B1, 0x9E57, 0xC5B2, 0x9E58, 0xC5B3, 0x9E59, 0xC5B4, 0xBEEE, 0xC5B5, 0xBEEF, 0xC5B6, 0x9E5A, 0xC5B7, 0x9E61, 0xC5B8, 0xBEF0, 0xC5B9, 0xBEF1, 0xC5BA, 0x9E62, 0xC5BB, 0xBEF2, 0xC5BC, 0xBEF3, 0xC5BD, 0xBEF4, 0xC5BE, 0xBEF5, 0xC5BF, 0x9E63, 0xC5C0, 0x9E64, 0xC5C1, 0x9E65, 0xC5C2, 0x9E66, 0xC5C3, 0x9E67, 0xC5C4, 0xBEF6, 0xC5C5, 0xBEF7, 0xC5C6, 0xBEF8, 0xC5C7, 0xBEF9, 0xC5C8, 0xBEFA, 0xC5C9, 0xBEFB, 0xC5CA, 0xBEFC, 0xC5CB, 0x9E68, 0xC5CC, 0xBEFD, 0xC5CD, 0x9E69, 0xC5CE, 0xBEFE, 0xC5CF, 0x9E6A, 0xC5D0, 0xBFA1, 0xC5D1, 0xBFA2, 0xC5D2, 0x9E6B, 0xC5D3, 0x9E6C, 0xC5D4, 0xBFA3, 0xC5D5, 0x9E6D, 0xC5D6, 0x9E6E, 0xC5D7, 0x9E6F, 0xC5D8, 0xBFA4, 0xC5D9, 0x9E70, 0xC5DA, 0x9E71, 0xC5DB, 0x9E72, 0xC5DC, 0x9E73, 0xC5DD, 0x9E74, 0xC5DE, 0x9E75, 0xC5DF, 0x9E76, 0xC5E0, 0xBFA5, 0xC5E1, 0xBFA6, 0xC5E2, 0x9E77, 0xC5E3, 0xBFA7, 0xC5E4, 0x9E78, 0xC5E5, 0xBFA8, 0xC5E6, 0x9E79, 0xC5E7, 0x9E7A, 0xC5E8, 0x9E81, 0xC5E9, 0x9E82, 0xC5EA, 0x9E83, 0xC5EB, 0x9E84, 0xC5EC, 0xBFA9, 0xC5ED, 0xBFAA, 0xC5EE, 0xBFAB, 0xC5EF, 0x9E85, 0xC5F0, 0xBFAC, 0xC5F1, 0x9E86, 0xC5F2, 0x9E87, 0xC5F3, 0x9E88, 0xC5F4, 0xBFAD, 0xC5F5, 0x9E89, 0xC5F6, 0xBFAE, 0xC5F7, 0xBFAF, 0xC5F8, 0x9E8A, 0xC5F9, 0x9E8B, 0xC5FA, 0x9E8C, 0xC5FB, 0x9E8D, 0xC5FC, 0xBFB0, 0xC5FD, 0xBFB1, 0xC5FE, 0xBFB2, 0xC5FF, 0xBFB3, 0xC600, 0xBFB4, 0xC601, 0xBFB5, 0xC602, 0x9E8E, 0xC603, 0x9E8F, 0xC604, 0x9E90, 0xC605, 0xBFB6, 0xC606, 0xBFB7, 0xC607, 0xBFB8, 0xC608, 0xBFB9, 0xC609, 0x9E91, 0xC60A, 0x9E92, 0xC60B, 0x9E93, 0xC60C, 0xBFBA, 0xC60D, 0x9E94, 0xC60E, 0x9E95, 0xC60F, 0x9E96, 0xC610, 0xBFBB, 0xC611, 0x9E97, 0xC612, 0x9E98, 0xC613, 0x9E99, 0xC614, 0x9E9A, 0xC615, 0x9E9B, 0xC616, 0x9E9C, 0xC617, 0x9E9D, 0xC618, 0xBFBC, 0xC619, 0xBFBD, 0xC61A, 0x9E9E, 0xC61B, 0xBFBE, 0xC61C, 0xBFBF, 0xC61D, 0x9E9F, 0xC61E, 0x9EA0, 0xC61F, 0x9EA1, 0xC620, 0x9EA2, 0xC621, 0x9EA3, 0xC622, 0x9EA4, 0xC623, 0x9EA5, 0xC624, 0xBFC0, 0xC625, 0xBFC1, 0xC626, 0x9EA6, 0xC627, 0x9EA7, 0xC628, 0xBFC2, 0xC629, 0x9EA8, 0xC62A, 0x9EA9, 0xC62B, 0x9EAA, 0xC62C, 0xBFC3, 0xC62D, 0xBFC4, 0xC62E, 0xBFC5, 0xC62F, 0x9EAB, 0xC630, 0xBFC6, 0xC631, 0x9EAC, 0xC632, 0x9EAD, 0xC633, 0xBFC7, 0xC634, 0xBFC8, 0xC635, 0xBFC9, 0xC636, 0x9EAE, 0xC637, 0xBFCA, 0xC638, 0x9EAF, 0xC639, 0xBFCB, 0xC63A, 0x9EB0, 0xC63B, 0xBFCC, 0xC63C, 0x9EB1, 0xC63D, 0x9EB2, 0xC63E, 0x9EB3, 0xC63F, 0x9EB4, 0xC640, 0xBFCD, 0xC641, 0xBFCE, 0xC642, 0x9EB5, 0xC643, 0x9EB6, 0xC644, 0xBFCF, 0xC645, 0x9EB7, 0xC646, 0x9EB8, 0xC647, 0x9EB9, 0xC648, 0xBFD0, 0xC649, 0x9EBA, 0xC64A, 0x9EBB, 0xC64B, 0x9EBC, 0xC64C, 0x9EBD, 0xC64D, 0x9EBE, 0xC64E, 0x9EBF, 0xC64F, 0x9EC0, 0xC650, 0xBFD1, 0xC651, 0xBFD2, 0xC652, 0x9EC1, 0xC653, 0xBFD3, 0xC654, 0xBFD4, 0xC655, 0xBFD5, 0xC656, 0x9EC2, 0xC657, 0x9EC3, 0xC658, 0x9EC4, 0xC659, 0x9EC5, 0xC65A, 0x9EC6, 0xC65B, 0x9EC7, 0xC65C, 0xBFD6, 0xC65D, 0xBFD7, 0xC65E, 0x9EC8, 0xC65F, 0x9EC9, 0xC660, 0xBFD8, 0xC661, 0x9ECA, 0xC662, 0x9ECB, 0xC663, 0x9ECC, 0xC664, 0x9ECD, 0xC665, 0x9ECE, 0xC666, 0x9ECF, 0xC667, 0x9ED0, 0xC668, 0x9ED1, 0xC669, 0x9ED2, 0xC66A, 0x9ED3, 0xC66B, 0x9ED4, 0xC66C, 0xBFD9, 0xC66D, 0x9ED5, 0xC66E, 0x9ED6, 0xC66F, 0xBFDA, 0xC670, 0x9ED7, 0xC671, 0xBFDB, 0xC672, 0x9ED8, 0xC673, 0x9ED9, 0xC674, 0x9EDA, 0xC675, 0x9EDB, 0xC676, 0x9EDC, 0xC677, 0x9EDD, 0xC678, 0xBFDC, 0xC679, 0xBFDD, 0xC67A, 0x9EDE, 0xC67B, 0x9EDF, 0xC67C, 0xBFDE, 0xC67D, 0x9EE0, 0xC67E, 0x9EE1, 0xC67F, 0x9EE2, 0xC680, 0xBFDF, 0xC681, 0x9EE3, 0xC682, 0x9EE4, 0xC683, 0x9EE5, 0xC684, 0x9EE6, 0xC685, 0x9EE7, 0xC686, 0x9EE8, 0xC687, 0x9EE9, 0xC688, 0xBFE0, 0xC689, 0xBFE1, 0xC68A, 0x9EEA, 0xC68B, 0xBFE2, 0xC68C, 0x9EEB, 0xC68D, 0xBFE3, 0xC68E, 0x9EEC, 0xC68F, 0x9EED, 0xC690, 0x9EEE, 0xC691, 0x9EEF, 0xC692, 0x9EF0, 0xC693, 0x9EF1, 0xC694, 0xBFE4, 0xC695, 0xBFE5, 0xC696, 0x9EF2, 0xC697, 0x9EF3, 0xC698, 0xBFE6, 0xC699, 0x9EF4, 0xC69A, 0x9EF5, 0xC69B, 0x9EF6, 0xC69C, 0xBFE7, 0xC69D, 0x9EF7, 0xC69E, 0x9EF8, 0xC69F, 0x9EF9, 0xC6A0, 0x9EFA, 0xC6A1, 0x9EFB, 0xC6A2, 0x9EFC, 0xC6A3, 0x9EFD, 0xC6A4, 0xBFE8, 0xC6A5, 0xBFE9, 0xC6A6, 0x9EFE, 0xC6A7, 0xBFEA, 0xC6A8, 0x9F41, 0xC6A9, 0xBFEB, 0xC6AA, 0x9F42, 0xC6AB, 0x9F43, 0xC6AC, 0x9F44, 0xC6AD, 0x9F45, 0xC6AE, 0x9F46, 0xC6AF, 0x9F47, 0xC6B0, 0xBFEC, 0xC6B1, 0xBFED, 0xC6B2, 0x9F48, 0xC6B3, 0x9F49, 0xC6B4, 0xBFEE, 0xC6B5, 0x9F4A, 0xC6B6, 0x9F4B, 0xC6B7, 0x9F4C, 0xC6B8, 0xBFEF, 0xC6B9, 0xBFF0, 0xC6BA, 0xBFF1, 0xC6BB, 0x9F4D, 0xC6BC, 0x9F4E, 0xC6BD, 0x9F4F, 0xC6BE, 0x9F50, 0xC6BF, 0x9F51, 0xC6C0, 0xBFF2, 0xC6C1, 0xBFF3, 0xC6C2, 0x9F52, 0xC6C3, 0xBFF4, 0xC6C4, 0x9F53, 0xC6C5, 0xBFF5, 0xC6C6, 0x9F54, 0xC6C7, 0x9F55, 0xC6C8, 0x9F56, 0xC6C9, 0x9F57, 0xC6CA, 0x9F58, 0xC6CB, 0x9F59, 0xC6CC, 0xBFF6, 0xC6CD, 0xBFF7, 0xC6CE, 0x9F5A, 0xC6CF, 0x9F61, 0xC6D0, 0xBFF8, 0xC6D1, 0x9F62, 0xC6D2, 0x9F63, 0xC6D3, 0x9F64, 0xC6D4, 0xBFF9, 0xC6D5, 0x9F65, 0xC6D6, 0x9F66, 0xC6D7, 0x9F67, 0xC6D8, 0x9F68, 0xC6D9, 0x9F69, 0xC6DA, 0x9F6A, 0xC6DB, 0x9F6B, 0xC6DC, 0xBFFA, 0xC6DD, 0xBFFB, 0xC6DE, 0x9F6C, 0xC6DF, 0x9F6D, 0xC6E0, 0xBFFC, 0xC6E1, 0xBFFD, 0xC6E2, 0x9F6E, 0xC6E3, 0x9F6F, 0xC6E4, 0x9F70, 0xC6E5, 0x9F71, 0xC6E6, 0x9F72, 0xC6E7, 0x9F73, 0xC6E8, 0xBFFE, 0xC6E9, 0xC0A1, 0xC6EA, 0x9F74, 0xC6EB, 0x9F75, 0xC6EC, 0xC0A2, 0xC6ED, 0x9F76, 0xC6EE, 0x9F77, 0xC6EF, 0x9F78, 0xC6F0, 0xC0A3, 0xC6F1, 0x9F79, 0xC6F2, 0x9F7A, 0xC6F3, 0x9F81, 0xC6F4, 0x9F82, 0xC6F5, 0x9F83, 0xC6F6, 0x9F84, 0xC6F7, 0x9F85, 0xC6F8, 0xC0A4, 0xC6F9, 0xC0A5, 0xC6FA, 0x9F86, 0xC6FB, 0x9F87, 0xC6FC, 0x9F88, 0xC6FD, 0xC0A6, 0xC6FE, 0x9F89, 0xC6FF, 0x9F8A, 0xC700, 0x9F8B, 0xC701, 0x9F8C, 0xC702, 0x9F8D, 0xC703, 0x9F8E, 0xC704, 0xC0A7, 0xC705, 0xC0A8, 0xC706, 0x9F8F, 0xC707, 0x9F90, 0xC708, 0xC0A9, 0xC709, 0x9F91, 0xC70A, 0x9F92, 0xC70B, 0x9F93, 0xC70C, 0xC0AA, 0xC70D, 0x9F94, 0xC70E, 0x9F95, 0xC70F, 0x9F96, 0xC710, 0x9F97, 0xC711, 0x9F98, 0xC712, 0x9F99, 0xC713, 0x9F9A, 0xC714, 0xC0AB, 0xC715, 0xC0AC, 0xC716, 0x9F9B, 0xC717, 0xC0AD, 0xC718, 0x9F9C, 0xC719, 0xC0AE, 0xC71A, 0x9F9D, 0xC71B, 0x9F9E, 0xC71C, 0x9F9F, 0xC71D, 0x9FA0, 0xC71E, 0x9FA1, 0xC71F, 0x9FA2, 0xC720, 0xC0AF, 0xC721, 0xC0B0, 0xC722, 0x9FA3, 0xC723, 0x9FA4, 0xC724, 0xC0B1, 0xC725, 0x9FA5, 0xC726, 0x9FA6, 0xC727, 0x9FA7, 0xC728, 0xC0B2, 0xC729, 0x9FA8, 0xC72A, 0x9FA9, 0xC72B, 0x9FAA, 0xC72C, 0x9FAB, 0xC72D, 0x9FAC, 0xC72E, 0x9FAD, 0xC72F, 0x9FAE, 0xC730, 0xC0B3, 0xC731, 0xC0B4, 0xC732, 0x9FAF, 0xC733, 0xC0B5, 0xC734, 0x9FB0, 0xC735, 0xC0B6, 0xC736, 0x9FB1, 0xC737, 0xC0B7, 0xC738, 0x9FB2, 0xC739, 0x9FB3, 0xC73A, 0x9FB4, 0xC73B, 0x9FB5, 0xC73C, 0xC0B8, 0xC73D, 0xC0B9, 0xC73E, 0x9FB6, 0xC73F, 0x9FB7, 0xC740, 0xC0BA, 0xC741, 0x9FB8, 0xC742, 0x9FB9, 0xC743, 0x9FBA, 0xC744, 0xC0BB, 0xC745, 0x9FBB, 0xC746, 0x9FBC, 0xC747, 0x9FBD, 0xC748, 0x9FBE, 0xC749, 0x9FBF, 0xC74A, 0xC0BC, 0xC74B, 0x9FC0, 0xC74C, 0xC0BD, 0xC74D, 0xC0BE, 0xC74E, 0x9FC1, 0xC74F, 0xC0BF, 0xC750, 0x9FC2, 0xC751, 0xC0C0, 0xC752, 0xC0C1, 0xC753, 0xC0C2, 0xC754, 0xC0C3, 0xC755, 0xC0C4, 0xC756, 0xC0C5, 0xC757, 0xC0C6, 0xC758, 0xC0C7, 0xC759, 0x9FC3, 0xC75A, 0x9FC4, 0xC75B, 0x9FC5, 0xC75C, 0xC0C8, 0xC75D, 0x9FC6, 0xC75E, 0x9FC7, 0xC75F, 0x9FC8, 0xC760, 0xC0C9, 0xC761, 0x9FC9, 0xC762, 0x9FCA, 0xC763, 0x9FCB, 0xC764, 0x9FCC, 0xC765, 0x9FCD, 0xC766, 0x9FCE, 0xC767, 0x9FCF, 0xC768, 0xC0CA, 0xC769, 0x9FD0, 0xC76A, 0x9FD1, 0xC76B, 0xC0CB, 0xC76C, 0x9FD2, 0xC76D, 0x9FD3, 0xC76E, 0x9FD4, 0xC76F, 0x9FD5, 0xC770, 0x9FD6, 0xC771, 0x9FD7, 0xC772, 0x9FD8, 0xC773, 0x9FD9, 0xC774, 0xC0CC, 0xC775, 0xC0CD, 0xC776, 0x9FDA, 0xC777, 0x9FDB, 0xC778, 0xC0CE, 0xC779, 0x9FDC, 0xC77A, 0x9FDD, 0xC77B, 0x9FDE, 0xC77C, 0xC0CF, 0xC77D, 0xC0D0, 0xC77E, 0xC0D1, 0xC77F, 0x9FDF, 0xC780, 0x9FE0, 0xC781, 0x9FE1, 0xC782, 0x9FE2, 0xC783, 0xC0D2, 0xC784, 0xC0D3, 0xC785, 0xC0D4, 0xC786, 0x9FE3, 0xC787, 0xC0D5, 0xC788, 0xC0D6, 0xC789, 0xC0D7, 0xC78A, 0xC0D8, 0xC78B, 0x9FE4, 0xC78C, 0x9FE5, 0xC78D, 0x9FE6, 0xC78E, 0xC0D9, 0xC78F, 0x9FE7, 0xC790, 0xC0DA, 0xC791, 0xC0DB, 0xC792, 0x9FE8, 0xC793, 0x9FE9, 0xC794, 0xC0DC, 0xC795, 0x9FEA, 0xC796, 0xC0DD, 0xC797, 0xC0DE, 0xC798, 0xC0DF, 0xC799, 0x9FEB, 0xC79A, 0xC0E0, 0xC79B, 0x9FEC, 0xC79C, 0x9FED, 0xC79D, 0x9FEE, 0xC79E, 0x9FEF, 0xC79F, 0x9FF0, 0xC7A0, 0xC0E1, 0xC7A1, 0xC0E2, 0xC7A2, 0x9FF1, 0xC7A3, 0xC0E3, 0xC7A4, 0xC0E4, 0xC7A5, 0xC0E5, 0xC7A6, 0xC0E6, 0xC7A7, 0x9FF2, 0xC7A8, 0x9FF3, 0xC7A9, 0x9FF4, 0xC7AA, 0x9FF5, 0xC7AB, 0x9FF6, 0xC7AC, 0xC0E7, 0xC7AD, 0xC0E8, 0xC7AE, 0x9FF7, 0xC7AF, 0x9FF8, 0xC7B0, 0xC0E9, 0xC7B1, 0x9FF9, 0xC7B2, 0x9FFA, 0xC7B3, 0x9FFB, 0xC7B4, 0xC0EA, 0xC7B5, 0x9FFC, 0xC7B6, 0x9FFD, 0xC7B7, 0x9FFE, 0xC7B8, 0xA041, 0xC7B9, 0xA042, 0xC7BA, 0xA043, 0xC7BB, 0xA044, 0xC7BC, 0xC0EB, 0xC7BD, 0xC0EC, 0xC7BE, 0xA045, 0xC7BF, 0xC0ED, 0xC7C0, 0xC0EE, 0xC7C1, 0xC0EF, 0xC7C2, 0xA046, 0xC7C3, 0xA047, 0xC7C4, 0xA048, 0xC7C5, 0xA049, 0xC7C6, 0xA04A, 0xC7C7, 0xA04B, 0xC7C8, 0xC0F0, 0xC7C9, 0xC0F1, 0xC7CA, 0xA04C, 0xC7CB, 0xA04D, 0xC7CC, 0xC0F2, 0xC7CD, 0xA04E, 0xC7CE, 0xC0F3, 0xC7CF, 0xA04F, 0xC7D0, 0xC0F4, 0xC7D1, 0xA050, 0xC7D2, 0xA051, 0xC7D3, 0xA052, 0xC7D4, 0xA053, 0xC7D5, 0xA054, 0xC7D6, 0xA055, 0xC7D7, 0xA056, 0xC7D8, 0xC0F5, 0xC7D9, 0xA057, 0xC7DA, 0xA058, 0xC7DB, 0xA059, 0xC7DC, 0xA05A, 0xC7DD, 0xC0F6, 0xC7DE, 0xA061, 0xC7DF, 0xA062, 0xC7E0, 0xA063, 0xC7E1, 0xA064, 0xC7E2, 0xA065, 0xC7E3, 0xA066, 0xC7E4, 0xC0F7, 0xC7E5, 0xA067, 0xC7E6, 0xA068, 0xC7E7, 0xA069, 0xC7E8, 0xC0F8, 0xC7E9, 0xA06A, 0xC7EA, 0xA06B, 0xC7EB, 0xA06C, 0xC7EC, 0xC0F9, 0xC7ED, 0xA06D, 0xC7EE, 0xA06E, 0xC7EF, 0xA06F, 0xC7F0, 0xA070, 0xC7F1, 0xA071, 0xC7F2, 0xA072, 0xC7F3, 0xA073, 0xC7F4, 0xA074, 0xC7F5, 0xA075, 0xC7F6, 0xA076, 0xC7F7, 0xA077, 0xC7F8, 0xA078, 0xC7F9, 0xA079, 0xC7FA, 0xA07A, 0xC7FB, 0xA081, 0xC7FC, 0xA082, 0xC7FD, 0xA083, 0xC7FE, 0xA084, 0xC7FF, 0xA085, 0xC800, 0xC0FA, 0xC801, 0xC0FB, 0xC802, 0xA086, 0xC803, 0xA087, 0xC804, 0xC0FC, 0xC805, 0xA088, 0xC806, 0xA089, 0xC807, 0xA08A, 0xC808, 0xC0FD, 0xC809, 0xA08B, 0xC80A, 0xC0FE, 0xC80B, 0xA08C, 0xC80C, 0xA08D, 0xC80D, 0xA08E, 0xC80E, 0xA08F, 0xC80F, 0xA090, 0xC810, 0xC1A1, 0xC811, 0xC1A2, 0xC812, 0xA091, 0xC813, 0xC1A3, 0xC814, 0xA092, 0xC815, 0xC1A4, 0xC816, 0xC1A5, 0xC817, 0xA093, 0xC818, 0xA094, 0xC819, 0xA095, 0xC81A, 0xA096, 0xC81B, 0xA097, 0xC81C, 0xC1A6, 0xC81D, 0xC1A7, 0xC81E, 0xA098, 0xC81F, 0xA099, 0xC820, 0xC1A8, 0xC821, 0xA09A, 0xC822, 0xA09B, 0xC823, 0xA09C, 0xC824, 0xC1A9, 0xC825, 0xA09D, 0xC826, 0xA09E, 0xC827, 0xA09F, 0xC828, 0xA0A0, 0xC829, 0xA0A1, 0xC82A, 0xA0A2, 0xC82B, 0xA0A3, 0xC82C, 0xC1AA, 0xC82D, 0xC1AB, 0xC82E, 0xA0A4, 0xC82F, 0xC1AC, 0xC830, 0xA0A5, 0xC831, 0xC1AD, 0xC832, 0xA0A6, 0xC833, 0xA0A7, 0xC834, 0xA0A8, 0xC835, 0xA0A9, 0xC836, 0xA0AA, 0xC837, 0xA0AB, 0xC838, 0xC1AE, 0xC839, 0xA0AC, 0xC83A, 0xA0AD, 0xC83B, 0xA0AE, 0xC83C, 0xC1AF, 0xC83D, 0xA0AF, 0xC83E, 0xA0B0, 0xC83F, 0xA0B1, 0xC840, 0xC1B0, 0xC841, 0xA0B2, 0xC842, 0xA0B3, 0xC843, 0xA0B4, 0xC844, 0xA0B5, 0xC845, 0xA0B6, 0xC846, 0xA0B7, 0xC847, 0xA0B8, 0xC848, 0xC1B1, 0xC849, 0xC1B2, 0xC84A, 0xA0B9, 0xC84B, 0xA0BA, 0xC84C, 0xC1B3, 0xC84D, 0xC1B4, 0xC84E, 0xA0BB, 0xC84F, 0xA0BC, 0xC850, 0xA0BD, 0xC851, 0xA0BE, 0xC852, 0xA0BF, 0xC853, 0xA0C0, 0xC854, 0xC1B5, 0xC855, 0xA0C1, 0xC856, 0xA0C2, 0xC857, 0xA0C3, 0xC858, 0xA0C4, 0xC859, 0xA0C5, 0xC85A, 0xA0C6, 0xC85B, 0xA0C7, 0xC85C, 0xA0C8, 0xC85D, 0xA0C9, 0xC85E, 0xA0CA, 0xC85F, 0xA0CB, 0xC860, 0xA0CC, 0xC861, 0xA0CD, 0xC862, 0xA0CE, 0xC863, 0xA0CF, 0xC864, 0xA0D0, 0xC865, 0xA0D1, 0xC866, 0xA0D2, 0xC867, 0xA0D3, 0xC868, 0xA0D4, 0xC869, 0xA0D5, 0xC86A, 0xA0D6, 0xC86B, 0xA0D7, 0xC86C, 0xA0D8, 0xC86D, 0xA0D9, 0xC86E, 0xA0DA, 0xC86F, 0xA0DB, 0xC870, 0xC1B6, 0xC871, 0xC1B7, 0xC872, 0xA0DC, 0xC873, 0xA0DD, 0xC874, 0xC1B8, 0xC875, 0xA0DE, 0xC876, 0xA0DF, 0xC877, 0xA0E0, 0xC878, 0xC1B9, 0xC879, 0xA0E1, 0xC87A, 0xC1BA, 0xC87B, 0xA0E2, 0xC87C, 0xA0E3, 0xC87D, 0xA0E4, 0xC87E, 0xA0E5, 0xC87F, 0xA0E6, 0xC880, 0xC1BB, 0xC881, 0xC1BC, 0xC882, 0xA0E7, 0xC883, 0xC1BD, 0xC884, 0xA0E8, 0xC885, 0xC1BE, 0xC886, 0xC1BF, 0xC887, 0xC1C0, 0xC888, 0xA0E9, 0xC889, 0xA0EA, 0xC88A, 0xA0EB, 0xC88B, 0xC1C1, 0xC88C, 0xC1C2, 0xC88D, 0xC1C3, 0xC88E, 0xA0EC, 0xC88F, 0xA0ED, 0xC890, 0xA0EE, 0xC891, 0xA0EF, 0xC892, 0xA0F0, 0xC893, 0xA0F1, 0xC894, 0xC1C4, 0xC895, 0xA0F2, 0xC896, 0xA0F3, 0xC897, 0xA0F4, 0xC898, 0xA0F5, 0xC899, 0xA0F6, 0xC89A, 0xA0F7, 0xC89B, 0xA0F8, 0xC89C, 0xA0F9, 0xC89D, 0xC1C5, 0xC89E, 0xA0FA, 0xC89F, 0xC1C6, 0xC8A0, 0xA0FB, 0xC8A1, 0xC1C7, 0xC8A2, 0xA0FC, 0xC8A3, 0xA0FD, 0xC8A4, 0xA0FE, 0xC8A5, 0xA141, 0xC8A6, 0xA142, 0xC8A7, 0xA143, 0xC8A8, 0xC1C8, 0xC8A9, 0xA144, 0xC8AA, 0xA145, 0xC8AB, 0xA146, 0xC8AC, 0xA147, 0xC8AD, 0xA148, 0xC8AE, 0xA149, 0xC8AF, 0xA14A, 0xC8B0, 0xA14B, 0xC8B1, 0xA14C, 0xC8B2, 0xA14D, 0xC8B3, 0xA14E, 0xC8B4, 0xA14F, 0xC8B5, 0xA150, 0xC8B6, 0xA151, 0xC8B7, 0xA152, 0xC8B8, 0xA153, 0xC8B9, 0xA154, 0xC8BA, 0xA155, 0xC8BB, 0xA156, 0xC8BC, 0xC1C9, 0xC8BD, 0xC1CA, 0xC8BE, 0xA157, 0xC8BF, 0xA158, 0xC8C0, 0xA159, 0xC8C1, 0xA15A, 0xC8C2, 0xA161, 0xC8C3, 0xA162, 0xC8C4, 0xC1CB, 0xC8C5, 0xA163, 0xC8C6, 0xA164, 0xC8C7, 0xA165, 0xC8C8, 0xC1CC, 0xC8C9, 0xA166, 0xC8CA, 0xA167, 0xC8CB, 0xA168, 0xC8CC, 0xC1CD, 0xC8CD, 0xA169, 0xC8CE, 0xA16A, 0xC8CF, 0xA16B, 0xC8D0, 0xA16C, 0xC8D1, 0xA16D, 0xC8D2, 0xA16E, 0xC8D3, 0xA16F, 0xC8D4, 0xC1CE, 0xC8D5, 0xC1CF, 0xC8D6, 0xA170, 0xC8D7, 0xC1D0, 0xC8D8, 0xA171, 0xC8D9, 0xC1D1, 0xC8DA, 0xA172, 0xC8DB, 0xA173, 0xC8DC, 0xA174, 0xC8DD, 0xA175, 0xC8DE, 0xA176, 0xC8DF, 0xA177, 0xC8E0, 0xC1D2, 0xC8E1, 0xC1D3, 0xC8E2, 0xA178, 0xC8E3, 0xA179, 0xC8E4, 0xC1D4, 0xC8E5, 0xA17A, 0xC8E6, 0xA181, 0xC8E7, 0xA182, 0xC8E8, 0xA183, 0xC8E9, 0xA184, 0xC8EA, 0xA185, 0xC8EB, 0xA186, 0xC8EC, 0xA187, 0xC8ED, 0xA188, 0xC8EE, 0xA189, 0xC8EF, 0xA18A, 0xC8F0, 0xA18B, 0xC8F1, 0xA18C, 0xC8F2, 0xA18D, 0xC8F3, 0xA18E, 0xC8F4, 0xA18F, 0xC8F5, 0xC1D5, 0xC8F6, 0xA190, 0xC8F7, 0xA191, 0xC8F8, 0xA192, 0xC8F9, 0xA193, 0xC8FA, 0xA194, 0xC8FB, 0xA195, 0xC8FC, 0xC1D6, 0xC8FD, 0xC1D7, 0xC8FE, 0xA196, 0xC8FF, 0xA197, 0xC900, 0xC1D8, 0xC901, 0xA198, 0xC902, 0xA199, 0xC903, 0xA19A, 0xC904, 0xC1D9, 0xC905, 0xC1DA, 0xC906, 0xC1DB, 0xC907, 0xA19B, 0xC908, 0xA19C, 0xC909, 0xA19D, 0xC90A, 0xA19E, 0xC90B, 0xA19F, 0xC90C, 0xC1DC, 0xC90D, 0xC1DD, 0xC90E, 0xA1A0, 0xC90F, 0xC1DE, 0xC910, 0xA241, 0xC911, 0xC1DF, 0xC912, 0xA242, 0xC913, 0xA243, 0xC914, 0xA244, 0xC915, 0xA245, 0xC916, 0xA246, 0xC917, 0xA247, 0xC918, 0xC1E0, 0xC919, 0xA248, 0xC91A, 0xA249, 0xC91B, 0xA24A, 0xC91C, 0xA24B, 0xC91D, 0xA24C, 0xC91E, 0xA24D, 0xC91F, 0xA24E, 0xC920, 0xA24F, 0xC921, 0xA250, 0xC922, 0xA251, 0xC923, 0xA252, 0xC924, 0xA253, 0xC925, 0xA254, 0xC926, 0xA255, 0xC927, 0xA256, 0xC928, 0xA257, 0xC929, 0xA258, 0xC92A, 0xA259, 0xC92B, 0xA25A, 0xC92C, 0xC1E1, 0xC92D, 0xA261, 0xC92E, 0xA262, 0xC92F, 0xA263, 0xC930, 0xA264, 0xC931, 0xA265, 0xC932, 0xA266, 0xC933, 0xA267, 0xC934, 0xC1E2, 0xC935, 0xA268, 0xC936, 0xA269, 0xC937, 0xA26A, 0xC938, 0xA26B, 0xC939, 0xA26C, 0xC93A, 0xA26D, 0xC93B, 0xA26E, 0xC93C, 0xA26F, 0xC93D, 0xA270, 0xC93E, 0xA271, 0xC93F, 0xA272, 0xC940, 0xA273, 0xC941, 0xA274, 0xC942, 0xA275, 0xC943, 0xA276, 0xC944, 0xA277, 0xC945, 0xA278, 0xC946, 0xA279, 0xC947, 0xA27A, 0xC948, 0xA281, 0xC949, 0xA282, 0xC94A, 0xA283, 0xC94B, 0xA284, 0xC94C, 0xA285, 0xC94D, 0xA286, 0xC94E, 0xA287, 0xC94F, 0xA288, 0xC950, 0xC1E3, 0xC951, 0xC1E4, 0xC952, 0xA289, 0xC953, 0xA28A, 0xC954, 0xC1E5, 0xC955, 0xA28B, 0xC956, 0xA28C, 0xC957, 0xA28D, 0xC958, 0xC1E6, 0xC959, 0xA28E, 0xC95A, 0xA28F, 0xC95B, 0xA290, 0xC95C, 0xA291, 0xC95D, 0xA292, 0xC95E, 0xA293, 0xC95F, 0xA294, 0xC960, 0xC1E7, 0xC961, 0xC1E8, 0xC962, 0xA295, 0xC963, 0xC1E9, 0xC964, 0xA296, 0xC965, 0xA297, 0xC966, 0xA298, 0xC967, 0xA299, 0xC968, 0xA29A, 0xC969, 0xA29B, 0xC96A, 0xA29C, 0xC96B, 0xA29D, 0xC96C, 0xC1EA, 0xC96D, 0xA29E, 0xC96E, 0xA29F, 0xC96F, 0xA2A0, 0xC970, 0xC1EB, 0xC971, 0xA341, 0xC972, 0xA342, 0xC973, 0xA343, 0xC974, 0xC1EC, 0xC975, 0xA344, 0xC976, 0xA345, 0xC977, 0xA346, 0xC978, 0xA347, 0xC979, 0xA348, 0xC97A, 0xA349, 0xC97B, 0xA34A, 0xC97C, 0xC1ED, 0xC97D, 0xA34B, 0xC97E, 0xA34C, 0xC97F, 0xA34D, 0xC980, 0xA34E, 0xC981, 0xA34F, 0xC982, 0xA350, 0xC983, 0xA351, 0xC984, 0xA352, 0xC985, 0xA353, 0xC986, 0xA354, 0xC987, 0xA355, 0xC988, 0xC1EE, 0xC989, 0xC1EF, 0xC98A, 0xA356, 0xC98B, 0xA357, 0xC98C, 0xC1F0, 0xC98D, 0xA358, 0xC98E, 0xA359, 0xC98F, 0xA35A, 0xC990, 0xC1F1, 0xC991, 0xA361, 0xC992, 0xA362, 0xC993, 0xA363, 0xC994, 0xA364, 0xC995, 0xA365, 0xC996, 0xA366, 0xC997, 0xA367, 0xC998, 0xC1F2, 0xC999, 0xC1F3, 0xC99A, 0xA368, 0xC99B, 0xC1F4, 0xC99C, 0xA369, 0xC99D, 0xC1F5, 0xC99E, 0xA36A, 0xC99F, 0xA36B, 0xC9A0, 0xA36C, 0xC9A1, 0xA36D, 0xC9A2, 0xA36E, 0xC9A3, 0xA36F, 0xC9A4, 0xA370, 0xC9A5, 0xA371, 0xC9A6, 0xA372, 0xC9A7, 0xA373, 0xC9A8, 0xA374, 0xC9A9, 0xA375, 0xC9AA, 0xA376, 0xC9AB, 0xA377, 0xC9AC, 0xA378, 0xC9AD, 0xA379, 0xC9AE, 0xA37A, 0xC9AF, 0xA381, 0xC9B0, 0xA382, 0xC9B1, 0xA383, 0xC9B2, 0xA384, 0xC9B3, 0xA385, 0xC9B4, 0xA386, 0xC9B5, 0xA387, 0xC9B6, 0xA388, 0xC9B7, 0xA389, 0xC9B8, 0xA38A, 0xC9B9, 0xA38B, 0xC9BA, 0xA38C, 0xC9BB, 0xA38D, 0xC9BC, 0xA38E, 0xC9BD, 0xA38F, 0xC9BE, 0xA390, 0xC9BF, 0xA391, 0xC9C0, 0xC1F6, 0xC9C1, 0xC1F7, 0xC9C2, 0xA392, 0xC9C3, 0xA393, 0xC9C4, 0xC1F8, 0xC9C5, 0xA394, 0xC9C6, 0xA395, 0xC9C7, 0xC1F9, 0xC9C8, 0xC1FA, 0xC9C9, 0xA396, 0xC9CA, 0xC1FB, 0xC9CB, 0xA397, 0xC9CC, 0xA398, 0xC9CD, 0xA399, 0xC9CE, 0xA39A, 0xC9CF, 0xA39B, 0xC9D0, 0xC1FC, 0xC9D1, 0xC1FD, 0xC9D2, 0xA39C, 0xC9D3, 0xC1FE, 0xC9D4, 0xA39D, 0xC9D5, 0xC2A1, 0xC9D6, 0xC2A2, 0xC9D7, 0xA39E, 0xC9D8, 0xA39F, 0xC9D9, 0xC2A3, 0xC9DA, 0xC2A4, 0xC9DB, 0xA3A0, 0xC9DC, 0xC2A5, 0xC9DD, 0xC2A6, 0xC9DE, 0xA441, 0xC9DF, 0xA442, 0xC9E0, 0xC2A7, 0xC9E1, 0xA443, 0xC9E2, 0xC2A8, 0xC9E3, 0xA444, 0xC9E4, 0xC2A9, 0xC9E5, 0xA445, 0xC9E6, 0xA446, 0xC9E7, 0xC2AA, 0xC9E8, 0xA447, 0xC9E9, 0xA448, 0xC9EA, 0xA449, 0xC9EB, 0xA44A, 0xC9EC, 0xC2AB, 0xC9ED, 0xC2AC, 0xC9EE, 0xA44B, 0xC9EF, 0xC2AD, 0xC9F0, 0xC2AE, 0xC9F1, 0xC2AF, 0xC9F2, 0xA44C, 0xC9F3, 0xA44D, 0xC9F4, 0xA44E, 0xC9F5, 0xA44F, 0xC9F6, 0xA450, 0xC9F7, 0xA451, 0xC9F8, 0xC2B0, 0xC9F9, 0xC2B1, 0xC9FA, 0xA452, 0xC9FB, 0xA453, 0xC9FC, 0xC2B2, 0xC9FD, 0xA454, 0xC9FE, 0xA455, 0xC9FF, 0xA456, 0xCA00, 0xC2B3, 0xCA01, 0xA457, 0xCA02, 0xA458, 0xCA03, 0xA459, 0xCA04, 0xA45A, 0xCA05, 0xA461, 0xCA06, 0xA462, 0xCA07, 0xA463, 0xCA08, 0xC2B4, 0xCA09, 0xC2B5, 0xCA0A, 0xA464, 0xCA0B, 0xC2B6, 0xCA0C, 0xC2B7, 0xCA0D, 0xC2B8, 0xCA0E, 0xA465, 0xCA0F, 0xA466, 0xCA10, 0xA467, 0xCA11, 0xA468, 0xCA12, 0xA469, 0xCA13, 0xA46A, 0xCA14, 0xC2B9, 0xCA15, 0xA46B, 0xCA16, 0xA46C, 0xCA17, 0xA46D, 0xCA18, 0xC2BA, 0xCA19, 0xA46E, 0xCA1A, 0xA46F, 0xCA1B, 0xA470, 0xCA1C, 0xA471, 0xCA1D, 0xA472, 0xCA1E, 0xA473, 0xCA1F, 0xA474, 0xCA20, 0xA475, 0xCA21, 0xA476, 0xCA22, 0xA477, 0xCA23, 0xA478, 0xCA24, 0xA479, 0xCA25, 0xA47A, 0xCA26, 0xA481, 0xCA27, 0xA482, 0xCA28, 0xA483, 0xCA29, 0xC2BB, 0xCA2A, 0xA484, 0xCA2B, 0xA485, 0xCA2C, 0xA486, 0xCA2D, 0xA487, 0xCA2E, 0xA488, 0xCA2F, 0xA489, 0xCA30, 0xA48A, 0xCA31, 0xA48B, 0xCA32, 0xA48C, 0xCA33, 0xA48D, 0xCA34, 0xA48E, 0xCA35, 0xA48F, 0xCA36, 0xA490, 0xCA37, 0xA491, 0xCA38, 0xA492, 0xCA39, 0xA493, 0xCA3A, 0xA494, 0xCA3B, 0xA495, 0xCA3C, 0xA496, 0xCA3D, 0xA497, 0xCA3E, 0xA498, 0xCA3F, 0xA499, 0xCA40, 0xA49A, 0xCA41, 0xA49B, 0xCA42, 0xA49C, 0xCA43, 0xA49D, 0xCA44, 0xA49E, 0xCA45, 0xA49F, 0xCA46, 0xA4A0, 0xCA47, 0xA541, 0xCA48, 0xA542, 0xCA49, 0xA543, 0xCA4A, 0xA544, 0xCA4B, 0xA545, 0xCA4C, 0xC2BC, 0xCA4D, 0xC2BD, 0xCA4E, 0xA546, 0xCA4F, 0xA547, 0xCA50, 0xC2BE, 0xCA51, 0xA548, 0xCA52, 0xA549, 0xCA53, 0xA54A, 0xCA54, 0xC2BF, 0xCA55, 0xA54B, 0xCA56, 0xA54C, 0xCA57, 0xA54D, 0xCA58, 0xA54E, 0xCA59, 0xA54F, 0xCA5A, 0xA550, 0xCA5B, 0xA551, 0xCA5C, 0xC2C0, 0xCA5D, 0xC2C1, 0xCA5E, 0xA552, 0xCA5F, 0xC2C2, 0xCA60, 0xC2C3, 0xCA61, 0xC2C4, 0xCA62, 0xA553, 0xCA63, 0xA554, 0xCA64, 0xA555, 0xCA65, 0xA556, 0xCA66, 0xA557, 0xCA67, 0xA558, 0xCA68, 0xC2C5, 0xCA69, 0xA559, 0xCA6A, 0xA55A, 0xCA6B, 0xA561, 0xCA6C, 0xA562, 0xCA6D, 0xA563, 0xCA6E, 0xA564, 0xCA6F, 0xA565, 0xCA70, 0xA566, 0xCA71, 0xA567, 0xCA72, 0xA568, 0xCA73, 0xA569, 0xCA74, 0xA56A, 0xCA75, 0xA56B, 0xCA76, 0xA56C, 0xCA77, 0xA56D, 0xCA78, 0xA56E, 0xCA79, 0xA56F, 0xCA7A, 0xA570, 0xCA7B, 0xA571, 0xCA7C, 0xA572, 0xCA7D, 0xC2C6, 0xCA7E, 0xA573, 0xCA7F, 0xA574, 0xCA80, 0xA575, 0xCA81, 0xA576, 0xCA82, 0xA577, 0xCA83, 0xA578, 0xCA84, 0xC2C7, 0xCA85, 0xA579, 0xCA86, 0xA57A, 0xCA87, 0xA581, 0xCA88, 0xA582, 0xCA89, 0xA583, 0xCA8A, 0xA584, 0xCA8B, 0xA585, 0xCA8C, 0xA586, 0xCA8D, 0xA587, 0xCA8E, 0xA588, 0xCA8F, 0xA589, 0xCA90, 0xA58A, 0xCA91, 0xA58B, 0xCA92, 0xA58C, 0xCA93, 0xA58D, 0xCA94, 0xA58E, 0xCA95, 0xA58F, 0xCA96, 0xA590, 0xCA97, 0xA591, 0xCA98, 0xC2C8, 0xCA99, 0xA592, 0xCA9A, 0xA593, 0xCA9B, 0xA594, 0xCA9C, 0xA595, 0xCA9D, 0xA596, 0xCA9E, 0xA597, 0xCA9F, 0xA598, 0xCAA0, 0xA599, 0xCAA1, 0xA59A, 0xCAA2, 0xA59B, 0xCAA3, 0xA59C, 0xCAA4, 0xA59D, 0xCAA5, 0xA59E, 0xCAA6, 0xA59F, 0xCAA7, 0xA5A0, 0xCAA8, 0xA641, 0xCAA9, 0xA642, 0xCAAA, 0xA643, 0xCAAB, 0xA644, 0xCAAC, 0xA645, 0xCAAD, 0xA646, 0xCAAE, 0xA647, 0xCAAF, 0xA648, 0xCAB0, 0xA649, 0xCAB1, 0xA64A, 0xCAB2, 0xA64B, 0xCAB3, 0xA64C, 0xCAB4, 0xA64D, 0xCAB5, 0xA64E, 0xCAB6, 0xA64F, 0xCAB7, 0xA650, 0xCAB8, 0xA651, 0xCAB9, 0xA652, 0xCABA, 0xA653, 0xCABB, 0xA654, 0xCABC, 0xC2C9, 0xCABD, 0xC2CA, 0xCABE, 0xA655, 0xCABF, 0xA656, 0xCAC0, 0xC2CB, 0xCAC1, 0xA657, 0xCAC2, 0xA658, 0xCAC3, 0xA659, 0xCAC4, 0xC2CC, 0xCAC5, 0xA65A, 0xCAC6, 0xA661, 0xCAC7, 0xA662, 0xCAC8, 0xA663, 0xCAC9, 0xA664, 0xCACA, 0xA665, 0xCACB, 0xA666, 0xCACC, 0xC2CD, 0xCACD, 0xC2CE, 0xCACE, 0xA667, 0xCACF, 0xC2CF, 0xCAD0, 0xA668, 0xCAD1, 0xC2D0, 0xCAD2, 0xA669, 0xCAD3, 0xC2D1, 0xCAD4, 0xA66A, 0xCAD5, 0xA66B, 0xCAD6, 0xA66C, 0xCAD7, 0xA66D, 0xCAD8, 0xC2D2, 0xCAD9, 0xC2D3, 0xCADA, 0xA66E, 0xCADB, 0xA66F, 0xCADC, 0xA670, 0xCADD, 0xA671, 0xCADE, 0xA672, 0xCADF, 0xA673, 0xCAE0, 0xC2D4, 0xCAE1, 0xA674, 0xCAE2, 0xA675, 0xCAE3, 0xA676, 0xCAE4, 0xA677, 0xCAE5, 0xA678, 0xCAE6, 0xA679, 0xCAE7, 0xA67A, 0xCAE8, 0xA681, 0xCAE9, 0xA682, 0xCAEA, 0xA683, 0xCAEB, 0xA684, 0xCAEC, 0xC2D5, 0xCAED, 0xA685, 0xCAEE, 0xA686, 0xCAEF, 0xA687, 0xCAF0, 0xA688, 0xCAF1, 0xA689, 0xCAF2, 0xA68A, 0xCAF3, 0xA68B, 0xCAF4, 0xC2D6, 0xCAF5, 0xA68C, 0xCAF6, 0xA68D, 0xCAF7, 0xA68E, 0xCAF8, 0xA68F, 0xCAF9, 0xA690, 0xCAFA, 0xA691, 0xCAFB, 0xA692, 0xCAFC, 0xA693, 0xCAFD, 0xA694, 0xCAFE, 0xA695, 0xCAFF, 0xA696, 0xCB00, 0xA697, 0xCB01, 0xA698, 0xCB02, 0xA699, 0xCB03, 0xA69A, 0xCB04, 0xA69B, 0xCB05, 0xA69C, 0xCB06, 0xA69D, 0xCB07, 0xA69E, 0xCB08, 0xC2D7, 0xCB09, 0xA69F, 0xCB0A, 0xA6A0, 0xCB0B, 0xA741, 0xCB0C, 0xA742, 0xCB0D, 0xA743, 0xCB0E, 0xA744, 0xCB0F, 0xA745, 0xCB10, 0xC2D8, 0xCB11, 0xA746, 0xCB12, 0xA747, 0xCB13, 0xA748, 0xCB14, 0xC2D9, 0xCB15, 0xA749, 0xCB16, 0xA74A, 0xCB17, 0xA74B, 0xCB18, 0xC2DA, 0xCB19, 0xA74C, 0xCB1A, 0xA74D, 0xCB1B, 0xA74E, 0xCB1C, 0xA74F, 0xCB1D, 0xA750, 0xCB1E, 0xA751, 0xCB1F, 0xA752, 0xCB20, 0xC2DB, 0xCB21, 0xC2DC, 0xCB22, 0xA753, 0xCB23, 0xA754, 0xCB24, 0xA755, 0xCB25, 0xA756, 0xCB26, 0xA757, 0xCB27, 0xA758, 0xCB28, 0xA759, 0xCB29, 0xA75A, 0xCB2A, 0xA761, 0xCB2B, 0xA762, 0xCB2C, 0xA763, 0xCB2D, 0xA764, 0xCB2E, 0xA765, 0xCB2F, 0xA766, 0xCB30, 0xA767, 0xCB31, 0xA768, 0xCB32, 0xA769, 0xCB33, 0xA76A, 0xCB34, 0xA76B, 0xCB35, 0xA76C, 0xCB36, 0xA76D, 0xCB37, 0xA76E, 0xCB38, 0xA76F, 0xCB39, 0xA770, 0xCB3A, 0xA771, 0xCB3B, 0xA772, 0xCB3C, 0xA773, 0xCB3D, 0xA774, 0xCB3E, 0xA775, 0xCB3F, 0xA776, 0xCB40, 0xA777, 0xCB41, 0xC2DD, 0xCB42, 0xA778, 0xCB43, 0xA779, 0xCB44, 0xA77A, 0xCB45, 0xA781, 0xCB46, 0xA782, 0xCB47, 0xA783, 0xCB48, 0xC2DE, 0xCB49, 0xC2DF, 0xCB4A, 0xA784, 0xCB4B, 0xA785, 0xCB4C, 0xC2E0, 0xCB4D, 0xA786, 0xCB4E, 0xA787, 0xCB4F, 0xA788, 0xCB50, 0xC2E1, 0xCB51, 0xA789, 0xCB52, 0xA78A, 0xCB53, 0xA78B, 0xCB54, 0xA78C, 0xCB55, 0xA78D, 0xCB56, 0xA78E, 0xCB57, 0xA78F, 0xCB58, 0xC2E2, 0xCB59, 0xC2E3, 0xCB5A, 0xA790, 0xCB5B, 0xA791, 0xCB5C, 0xA792, 0xCB5D, 0xC2E4, 0xCB5E, 0xA793, 0xCB5F, 0xA794, 0xCB60, 0xA795, 0xCB61, 0xA796, 0xCB62, 0xA797, 0xCB63, 0xA798, 0xCB64, 0xC2E5, 0xCB65, 0xA799, 0xCB66, 0xA79A, 0xCB67, 0xA79B, 0xCB68, 0xA79C, 0xCB69, 0xA79D, 0xCB6A, 0xA79E, 0xCB6B, 0xA79F, 0xCB6C, 0xA7A0, 0xCB6D, 0xA841, 0xCB6E, 0xA842, 0xCB6F, 0xA843, 0xCB70, 0xA844, 0xCB71, 0xA845, 0xCB72, 0xA846, 0xCB73, 0xA847, 0xCB74, 0xA848, 0xCB75, 0xA849, 0xCB76, 0xA84A, 0xCB77, 0xA84B, 0xCB78, 0xC2E6, 0xCB79, 0xC2E7, 0xCB7A, 0xA84C, 0xCB7B, 0xA84D, 0xCB7C, 0xA84E, 0xCB7D, 0xA84F, 0xCB7E, 0xA850, 0xCB7F, 0xA851, 0xCB80, 0xA852, 0xCB81, 0xA853, 0xCB82, 0xA854, 0xCB83, 0xA855, 0xCB84, 0xA856, 0xCB85, 0xA857, 0xCB86, 0xA858, 0xCB87, 0xA859, 0xCB88, 0xA85A, 0xCB89, 0xA861, 0xCB8A, 0xA862, 0xCB8B, 0xA863, 0xCB8C, 0xA864, 0xCB8D, 0xA865, 0xCB8E, 0xA866, 0xCB8F, 0xA867, 0xCB90, 0xA868, 0xCB91, 0xA869, 0xCB92, 0xA86A, 0xCB93, 0xA86B, 0xCB94, 0xA86C, 0xCB95, 0xA86D, 0xCB96, 0xA86E, 0xCB97, 0xA86F, 0xCB98, 0xA870, 0xCB99, 0xA871, 0xCB9A, 0xA872, 0xCB9B, 0xA873, 0xCB9C, 0xC2E8, 0xCB9D, 0xA874, 0xCB9E, 0xA875, 0xCB9F, 0xA876, 0xCBA0, 0xA877, 0xCBA1, 0xA878, 0xCBA2, 0xA879, 0xCBA3, 0xA87A, 0xCBA4, 0xA881, 0xCBA5, 0xA882, 0xCBA6, 0xA883, 0xCBA7, 0xA884, 0xCBA8, 0xA885, 0xCBA9, 0xA886, 0xCBAA, 0xA887, 0xCBAB, 0xA888, 0xCBAC, 0xA889, 0xCBAD, 0xA88A, 0xCBAE, 0xA88B, 0xCBAF, 0xA88C, 0xCBB0, 0xA88D, 0xCBB1, 0xA88E, 0xCBB2, 0xA88F, 0xCBB3, 0xA890, 0xCBB4, 0xA891, 0xCBB5, 0xA892, 0xCBB6, 0xA893, 0xCBB7, 0xA894, 0xCBB8, 0xC2E9, 0xCBB9, 0xA895, 0xCBBA, 0xA896, 0xCBBB, 0xA897, 0xCBBC, 0xA898, 0xCBBD, 0xA899, 0xCBBE, 0xA89A, 0xCBBF, 0xA89B, 0xCBC0, 0xA89C, 0xCBC1, 0xA89D, 0xCBC2, 0xA89E, 0xCBC3, 0xA89F, 0xCBC4, 0xA8A0, 0xCBC5, 0xA941, 0xCBC6, 0xA942, 0xCBC7, 0xA943, 0xCBC8, 0xA944, 0xCBC9, 0xA945, 0xCBCA, 0xA946, 0xCBCB, 0xA947, 0xCBCC, 0xA948, 0xCBCD, 0xA949, 0xCBCE, 0xA94A, 0xCBCF, 0xA94B, 0xCBD0, 0xA94C, 0xCBD1, 0xA94D, 0xCBD2, 0xA94E, 0xCBD3, 0xA94F, 0xCBD4, 0xC2EA, 0xCBD5, 0xA950, 0xCBD6, 0xA951, 0xCBD7, 0xA952, 0xCBD8, 0xA953, 0xCBD9, 0xA954, 0xCBDA, 0xA955, 0xCBDB, 0xA956, 0xCBDC, 0xA957, 0xCBDD, 0xA958, 0xCBDE, 0xA959, 0xCBDF, 0xA95A, 0xCBE0, 0xA961, 0xCBE1, 0xA962, 0xCBE2, 0xA963, 0xCBE3, 0xA964, 0xCBE4, 0xC2EB, 0xCBE5, 0xA965, 0xCBE6, 0xA966, 0xCBE7, 0xC2EC, 0xCBE8, 0xA967, 0xCBE9, 0xC2ED, 0xCBEA, 0xA968, 0xCBEB, 0xA969, 0xCBEC, 0xA96A, 0xCBED, 0xA96B, 0xCBEE, 0xA96C, 0xCBEF, 0xA96D, 0xCBF0, 0xA96E, 0xCBF1, 0xA96F, 0xCBF2, 0xA970, 0xCBF3, 0xA971, 0xCBF4, 0xA972, 0xCBF5, 0xA973, 0xCBF6, 0xA974, 0xCBF7, 0xA975, 0xCBF8, 0xA976, 0xCBF9, 0xA977, 0xCBFA, 0xA978, 0xCBFB, 0xA979, 0xCBFC, 0xA97A, 0xCBFD, 0xA981, 0xCBFE, 0xA982, 0xCBFF, 0xA983, 0xCC00, 0xA984, 0xCC01, 0xA985, 0xCC02, 0xA986, 0xCC03, 0xA987, 0xCC04, 0xA988, 0xCC05, 0xA989, 0xCC06, 0xA98A, 0xCC07, 0xA98B, 0xCC08, 0xA98C, 0xCC09, 0xA98D, 0xCC0A, 0xA98E, 0xCC0B, 0xA98F, 0xCC0C, 0xC2EE, 0xCC0D, 0xC2EF, 0xCC0E, 0xA990, 0xCC0F, 0xA991, 0xCC10, 0xC2F0, 0xCC11, 0xA992, 0xCC12, 0xA993, 0xCC13, 0xA994, 0xCC14, 0xC2F1, 0xCC15, 0xA995, 0xCC16, 0xA996, 0xCC17, 0xA997, 0xCC18, 0xA998, 0xCC19, 0xA999, 0xCC1A, 0xA99A, 0xCC1B, 0xA99B, 0xCC1C, 0xC2F2, 0xCC1D, 0xC2F3, 0xCC1E, 0xA99C, 0xCC1F, 0xA99D, 0xCC20, 0xA99E, 0xCC21, 0xC2F4, 0xCC22, 0xC2F5, 0xCC23, 0xA99F, 0xCC24, 0xA9A0, 0xCC25, 0xAA41, 0xCC26, 0xAA42, 0xCC27, 0xC2F6, 0xCC28, 0xC2F7, 0xCC29, 0xC2F8, 0xCC2A, 0xAA43, 0xCC2B, 0xAA44, 0xCC2C, 0xC2F9, 0xCC2D, 0xAA45, 0xCC2E, 0xC2FA, 0xCC2F, 0xAA46, 0xCC30, 0xC2FB, 0xCC31, 0xAA47, 0xCC32, 0xAA48, 0xCC33, 0xAA49, 0xCC34, 0xAA4A, 0xCC35, 0xAA4B, 0xCC36, 0xAA4C, 0xCC37, 0xAA4D, 0xCC38, 0xC2FC, 0xCC39, 0xC2FD, 0xCC3A, 0xAA4E, 0xCC3B, 0xC2FE, 0xCC3C, 0xC3A1, 0xCC3D, 0xC3A2, 0xCC3E, 0xC3A3, 0xCC3F, 0xAA4F, 0xCC40, 0xAA50, 0xCC41, 0xAA51, 0xCC42, 0xAA52, 0xCC43, 0xAA53, 0xCC44, 0xC3A4, 0xCC45, 0xC3A5, 0xCC46, 0xAA54, 0xCC47, 0xAA55, 0xCC48, 0xC3A6, 0xCC49, 0xAA56, 0xCC4A, 0xAA57, 0xCC4B, 0xAA58, 0xCC4C, 0xC3A7, 0xCC4D, 0xAA59, 0xCC4E, 0xAA5A, 0xCC4F, 0xAA61, 0xCC50, 0xAA62, 0xCC51, 0xAA63, 0xCC52, 0xAA64, 0xCC53, 0xAA65, 0xCC54, 0xC3A8, 0xCC55, 0xC3A9, 0xCC56, 0xAA66, 0xCC57, 0xC3AA, 0xCC58, 0xC3AB, 0xCC59, 0xC3AC, 0xCC5A, 0xAA67, 0xCC5B, 0xAA68, 0xCC5C, 0xAA69, 0xCC5D, 0xAA6A, 0xCC5E, 0xAA6B, 0xCC5F, 0xAA6C, 0xCC60, 0xC3AD, 0xCC61, 0xAA6D, 0xCC62, 0xAA6E, 0xCC63, 0xAA6F, 0xCC64, 0xC3AE, 0xCC65, 0xAA70, 0xCC66, 0xC3AF, 0xCC67, 0xAA71, 0xCC68, 0xC3B0, 0xCC69, 0xAA72, 0xCC6A, 0xAA73, 0xCC6B, 0xAA74, 0xCC6C, 0xAA75, 0xCC6D, 0xAA76, 0xCC6E, 0xAA77, 0xCC6F, 0xAA78, 0xCC70, 0xC3B1, 0xCC71, 0xAA79, 0xCC72, 0xAA7A, 0xCC73, 0xAA81, 0xCC74, 0xAA82, 0xCC75, 0xC3B2, 0xCC76, 0xAA83, 0xCC77, 0xAA84, 0xCC78, 0xAA85, 0xCC79, 0xAA86, 0xCC7A, 0xAA87, 0xCC7B, 0xAA88, 0xCC7C, 0xAA89, 0xCC7D, 0xAA8A, 0xCC7E, 0xAA8B, 0xCC7F, 0xAA8C, 0xCC80, 0xAA8D, 0xCC81, 0xAA8E, 0xCC82, 0xAA8F, 0xCC83, 0xAA90, 0xCC84, 0xAA91, 0xCC85, 0xAA92, 0xCC86, 0xAA93, 0xCC87, 0xAA94, 0xCC88, 0xAA95, 0xCC89, 0xAA96, 0xCC8A, 0xAA97, 0xCC8B, 0xAA98, 0xCC8C, 0xAA99, 0xCC8D, 0xAA9A, 0xCC8E, 0xAA9B, 0xCC8F, 0xAA9C, 0xCC90, 0xAA9D, 0xCC91, 0xAA9E, 0xCC92, 0xAA9F, 0xCC93, 0xAAA0, 0xCC94, 0xAB41, 0xCC95, 0xAB42, 0xCC96, 0xAB43, 0xCC97, 0xAB44, 0xCC98, 0xC3B3, 0xCC99, 0xC3B4, 0xCC9A, 0xAB45, 0xCC9B, 0xAB46, 0xCC9C, 0xC3B5, 0xCC9D, 0xAB47, 0xCC9E, 0xAB48, 0xCC9F, 0xAB49, 0xCCA0, 0xC3B6, 0xCCA1, 0xAB4A, 0xCCA2, 0xAB4B, 0xCCA3, 0xAB4C, 0xCCA4, 0xAB4D, 0xCCA5, 0xAB4E, 0xCCA6, 0xAB4F, 0xCCA7, 0xAB50, 0xCCA8, 0xC3B7, 0xCCA9, 0xC3B8, 0xCCAA, 0xAB51, 0xCCAB, 0xC3B9, 0xCCAC, 0xC3BA, 0xCCAD, 0xC3BB, 0xCCAE, 0xAB52, 0xCCAF, 0xAB53, 0xCCB0, 0xAB54, 0xCCB1, 0xAB55, 0xCCB2, 0xAB56, 0xCCB3, 0xAB57, 0xCCB4, 0xC3BC, 0xCCB5, 0xC3BD, 0xCCB6, 0xAB58, 0xCCB7, 0xAB59, 0xCCB8, 0xC3BE, 0xCCB9, 0xAB5A, 0xCCBA, 0xAB61, 0xCCBB, 0xAB62, 0xCCBC, 0xC3BF, 0xCCBD, 0xAB63, 0xCCBE, 0xAB64, 0xCCBF, 0xAB65, 0xCCC0, 0xAB66, 0xCCC1, 0xAB67, 0xCCC2, 0xAB68, 0xCCC3, 0xAB69, 0xCCC4, 0xC3C0, 0xCCC5, 0xC3C1, 0xCCC6, 0xAB6A, 0xCCC7, 0xC3C2, 0xCCC8, 0xAB6B, 0xCCC9, 0xC3C3, 0xCCCA, 0xAB6C, 0xCCCB, 0xAB6D, 0xCCCC, 0xAB6E, 0xCCCD, 0xAB6F, 0xCCCE, 0xAB70, 0xCCCF, 0xAB71, 0xCCD0, 0xC3C4, 0xCCD1, 0xAB72, 0xCCD2, 0xAB73, 0xCCD3, 0xAB74, 0xCCD4, 0xC3C5, 0xCCD5, 0xAB75, 0xCCD6, 0xAB76, 0xCCD7, 0xAB77, 0xCCD8, 0xAB78, 0xCCD9, 0xAB79, 0xCCDA, 0xAB7A, 0xCCDB, 0xAB81, 0xCCDC, 0xAB82, 0xCCDD, 0xAB83, 0xCCDE, 0xAB84, 0xCCDF, 0xAB85, 0xCCE0, 0xAB86, 0xCCE1, 0xAB87, 0xCCE2, 0xAB88, 0xCCE3, 0xAB89, 0xCCE4, 0xC3C6, 0xCCE5, 0xAB8A, 0xCCE6, 0xAB8B, 0xCCE7, 0xAB8C, 0xCCE8, 0xAB8D, 0xCCE9, 0xAB8E, 0xCCEA, 0xAB8F, 0xCCEB, 0xAB90, 0xCCEC, 0xC3C7, 0xCCED, 0xAB91, 0xCCEE, 0xAB92, 0xCCEF, 0xAB93, 0xCCF0, 0xC3C8, 0xCCF1, 0xAB94, 0xCCF2, 0xAB95, 0xCCF3, 0xAB96, 0xCCF4, 0xAB97, 0xCCF5, 0xAB98, 0xCCF6, 0xAB99, 0xCCF7, 0xAB9A, 0xCCF8, 0xAB9B, 0xCCF9, 0xAB9C, 0xCCFA, 0xAB9D, 0xCCFB, 0xAB9E, 0xCCFC, 0xAB9F, 0xCCFD, 0xABA0, 0xCCFE, 0xAC41, 0xCCFF, 0xAC42, 0xCD00, 0xAC43, 0xCD01, 0xC3C9, 0xCD02, 0xAC44, 0xCD03, 0xAC45, 0xCD04, 0xAC46, 0xCD05, 0xAC47, 0xCD06, 0xAC48, 0xCD07, 0xAC49, 0xCD08, 0xC3CA, 0xCD09, 0xC3CB, 0xCD0A, 0xAC4A, 0xCD0B, 0xAC4B, 0xCD0C, 0xC3CC, 0xCD0D, 0xAC4C, 0xCD0E, 0xAC4D, 0xCD0F, 0xAC4E, 0xCD10, 0xC3CD, 0xCD11, 0xAC4F, 0xCD12, 0xAC50, 0xCD13, 0xAC51, 0xCD14, 0xAC52, 0xCD15, 0xAC53, 0xCD16, 0xAC54, 0xCD17, 0xAC55, 0xCD18, 0xC3CE, 0xCD19, 0xC3CF, 0xCD1A, 0xAC56, 0xCD1B, 0xC3D0, 0xCD1C, 0xAC57, 0xCD1D, 0xC3D1, 0xCD1E, 0xAC58, 0xCD1F, 0xAC59, 0xCD20, 0xAC5A, 0xCD21, 0xAC61, 0xCD22, 0xAC62, 0xCD23, 0xAC63, 0xCD24, 0xC3D2, 0xCD25, 0xAC64, 0xCD26, 0xAC65, 0xCD27, 0xAC66, 0xCD28, 0xC3D3, 0xCD29, 0xAC67, 0xCD2A, 0xAC68, 0xCD2B, 0xAC69, 0xCD2C, 0xC3D4, 0xCD2D, 0xAC6A, 0xCD2E, 0xAC6B, 0xCD2F, 0xAC6C, 0xCD30, 0xAC6D, 0xCD31, 0xAC6E, 0xCD32, 0xAC6F, 0xCD33, 0xAC70, 0xCD34, 0xAC71, 0xCD35, 0xAC72, 0xCD36, 0xAC73, 0xCD37, 0xAC74, 0xCD38, 0xAC75, 0xCD39, 0xC3D5, 0xCD3A, 0xAC76, 0xCD3B, 0xAC77, 0xCD3C, 0xAC78, 0xCD3D, 0xAC79, 0xCD3E, 0xAC7A, 0xCD3F, 0xAC81, 0xCD40, 0xAC82, 0xCD41, 0xAC83, 0xCD42, 0xAC84, 0xCD43, 0xAC85, 0xCD44, 0xAC86, 0xCD45, 0xAC87, 0xCD46, 0xAC88, 0xCD47, 0xAC89, 0xCD48, 0xAC8A, 0xCD49, 0xAC8B, 0xCD4A, 0xAC8C, 0xCD4B, 0xAC8D, 0xCD4C, 0xAC8E, 0xCD4D, 0xAC8F, 0xCD4E, 0xAC90, 0xCD4F, 0xAC91, 0xCD50, 0xAC92, 0xCD51, 0xAC93, 0xCD52, 0xAC94, 0xCD53, 0xAC95, 0xCD54, 0xAC96, 0xCD55, 0xAC97, 0xCD56, 0xAC98, 0xCD57, 0xAC99, 0xCD58, 0xAC9A, 0xCD59, 0xAC9B, 0xCD5A, 0xAC9C, 0xCD5B, 0xAC9D, 0xCD5C, 0xC3D6, 0xCD5D, 0xAC9E, 0xCD5E, 0xAC9F, 0xCD5F, 0xACA0, 0xCD60, 0xC3D7, 0xCD61, 0xAD41, 0xCD62, 0xAD42, 0xCD63, 0xAD43, 0xCD64, 0xC3D8, 0xCD65, 0xAD44, 0xCD66, 0xAD45, 0xCD67, 0xAD46, 0xCD68, 0xAD47, 0xCD69, 0xAD48, 0xCD6A, 0xAD49, 0xCD6B, 0xAD4A, 0xCD6C, 0xC3D9, 0xCD6D, 0xC3DA, 0xCD6E, 0xAD4B, 0xCD6F, 0xC3DB, 0xCD70, 0xAD4C, 0xCD71, 0xC3DC, 0xCD72, 0xAD4D, 0xCD73, 0xAD4E, 0xCD74, 0xAD4F, 0xCD75, 0xAD50, 0xCD76, 0xAD51, 0xCD77, 0xAD52, 0xCD78, 0xC3DD, 0xCD79, 0xAD53, 0xCD7A, 0xAD54, 0xCD7B, 0xAD55, 0xCD7C, 0xAD56, 0xCD7D, 0xAD57, 0xCD7E, 0xAD58, 0xCD7F, 0xAD59, 0xCD80, 0xAD5A, 0xCD81, 0xAD61, 0xCD82, 0xAD62, 0xCD83, 0xAD63, 0xCD84, 0xAD64, 0xCD85, 0xAD65, 0xCD86, 0xAD66, 0xCD87, 0xAD67, 0xCD88, 0xC3DE, 0xCD89, 0xAD68, 0xCD8A, 0xAD69, 0xCD8B, 0xAD6A, 0xCD8C, 0xAD6B, 0xCD8D, 0xAD6C, 0xCD8E, 0xAD6D, 0xCD8F, 0xAD6E, 0xCD90, 0xAD6F, 0xCD91, 0xAD70, 0xCD92, 0xAD71, 0xCD93, 0xAD72, 0xCD94, 0xC3DF, 0xCD95, 0xC3E0, 0xCD96, 0xAD73, 0xCD97, 0xAD74, 0xCD98, 0xC3E1, 0xCD99, 0xAD75, 0xCD9A, 0xAD76, 0xCD9B, 0xAD77, 0xCD9C, 0xC3E2, 0xCD9D, 0xAD78, 0xCD9E, 0xAD79, 0xCD9F, 0xAD7A, 0xCDA0, 0xAD81, 0xCDA1, 0xAD82, 0xCDA2, 0xAD83, 0xCDA3, 0xAD84, 0xCDA4, 0xC3E3, 0xCDA5, 0xC3E4, 0xCDA6, 0xAD85, 0xCDA7, 0xC3E5, 0xCDA8, 0xAD86, 0xCDA9, 0xC3E6, 0xCDAA, 0xAD87, 0xCDAB, 0xAD88, 0xCDAC, 0xAD89, 0xCDAD, 0xAD8A, 0xCDAE, 0xAD8B, 0xCDAF, 0xAD8C, 0xCDB0, 0xC3E7, 0xCDB1, 0xAD8D, 0xCDB2, 0xAD8E, 0xCDB3, 0xAD8F, 0xCDB4, 0xAD90, 0xCDB5, 0xAD91, 0xCDB6, 0xAD92, 0xCDB7, 0xAD93, 0xCDB8, 0xAD94, 0xCDB9, 0xAD95, 0xCDBA, 0xAD96, 0xCDBB, 0xAD97, 0xCDBC, 0xAD98, 0xCDBD, 0xAD99, 0xCDBE, 0xAD9A, 0xCDBF, 0xAD9B, 0xCDC0, 0xAD9C, 0xCDC1, 0xAD9D, 0xCDC2, 0xAD9E, 0xCDC3, 0xAD9F, 0xCDC4, 0xC3E8, 0xCDC5, 0xADA0, 0xCDC6, 0xAE41, 0xCDC7, 0xAE42, 0xCDC8, 0xAE43, 0xCDC9, 0xAE44, 0xCDCA, 0xAE45, 0xCDCB, 0xAE46, 0xCDCC, 0xC3E9, 0xCDCD, 0xAE47, 0xCDCE, 0xAE48, 0xCDCF, 0xAE49, 0xCDD0, 0xC3EA, 0xCDD1, 0xAE4A, 0xCDD2, 0xAE4B, 0xCDD3, 0xAE4C, 0xCDD4, 0xAE4D, 0xCDD5, 0xAE4E, 0xCDD6, 0xAE4F, 0xCDD7, 0xAE50, 0xCDD8, 0xAE51, 0xCDD9, 0xAE52, 0xCDDA, 0xAE53, 0xCDDB, 0xAE54, 0xCDDC, 0xAE55, 0xCDDD, 0xAE56, 0xCDDE, 0xAE57, 0xCDDF, 0xAE58, 0xCDE0, 0xAE59, 0xCDE1, 0xAE5A, 0xCDE2, 0xAE61, 0xCDE3, 0xAE62, 0xCDE4, 0xAE63, 0xCDE5, 0xAE64, 0xCDE6, 0xAE65, 0xCDE7, 0xAE66, 0xCDE8, 0xC3EB, 0xCDE9, 0xAE67, 0xCDEA, 0xAE68, 0xCDEB, 0xAE69, 0xCDEC, 0xC3EC, 0xCDED, 0xAE6A, 0xCDEE, 0xAE6B, 0xCDEF, 0xAE6C, 0xCDF0, 0xC3ED, 0xCDF1, 0xAE6D, 0xCDF2, 0xAE6E, 0xCDF3, 0xAE6F, 0xCDF4, 0xAE70, 0xCDF5, 0xAE71, 0xCDF6, 0xAE72, 0xCDF7, 0xAE73, 0xCDF8, 0xC3EE, 0xCDF9, 0xC3EF, 0xCDFA, 0xAE74, 0xCDFB, 0xC3F0, 0xCDFC, 0xAE75, 0xCDFD, 0xC3F1, 0xCDFE, 0xAE76, 0xCDFF, 0xAE77, 0xCE00, 0xAE78, 0xCE01, 0xAE79, 0xCE02, 0xAE7A, 0xCE03, 0xAE81, 0xCE04, 0xC3F2, 0xCE05, 0xAE82, 0xCE06, 0xAE83, 0xCE07, 0xAE84, 0xCE08, 0xC3F3, 0xCE09, 0xAE85, 0xCE0A, 0xAE86, 0xCE0B, 0xAE87, 0xCE0C, 0xC3F4, 0xCE0D, 0xAE88, 0xCE0E, 0xAE89, 0xCE0F, 0xAE8A, 0xCE10, 0xAE8B, 0xCE11, 0xAE8C, 0xCE12, 0xAE8D, 0xCE13, 0xAE8E, 0xCE14, 0xC3F5, 0xCE15, 0xAE8F, 0xCE16, 0xAE90, 0xCE17, 0xAE91, 0xCE18, 0xAE92, 0xCE19, 0xC3F6, 0xCE1A, 0xAE93, 0xCE1B, 0xAE94, 0xCE1C, 0xAE95, 0xCE1D, 0xAE96, 0xCE1E, 0xAE97, 0xCE1F, 0xAE98, 0xCE20, 0xC3F7, 0xCE21, 0xC3F8, 0xCE22, 0xAE99, 0xCE23, 0xAE9A, 0xCE24, 0xC3F9, 0xCE25, 0xAE9B, 0xCE26, 0xAE9C, 0xCE27, 0xAE9D, 0xCE28, 0xC3FA, 0xCE29, 0xAE9E, 0xCE2A, 0xAE9F, 0xCE2B, 0xAEA0, 0xCE2C, 0xAF41, 0xCE2D, 0xAF42, 0xCE2E, 0xAF43, 0xCE2F, 0xAF44, 0xCE30, 0xC3FB, 0xCE31, 0xC3FC, 0xCE32, 0xAF45, 0xCE33, 0xC3FD, 0xCE34, 0xAF46, 0xCE35, 0xC3FE, 0xCE36, 0xAF47, 0xCE37, 0xAF48, 0xCE38, 0xAF49, 0xCE39, 0xAF4A, 0xCE3A, 0xAF4B, 0xCE3B, 0xAF4C, 0xCE3C, 0xAF4D, 0xCE3D, 0xAF4E, 0xCE3E, 0xAF4F, 0xCE3F, 0xAF50, 0xCE40, 0xAF51, 0xCE41, 0xAF52, 0xCE42, 0xAF53, 0xCE43, 0xAF54, 0xCE44, 0xAF55, 0xCE45, 0xAF56, 0xCE46, 0xAF57, 0xCE47, 0xAF58, 0xCE48, 0xAF59, 0xCE49, 0xAF5A, 0xCE4A, 0xAF61, 0xCE4B, 0xAF62, 0xCE4C, 0xAF63, 0xCE4D, 0xAF64, 0xCE4E, 0xAF65, 0xCE4F, 0xAF66, 0xCE50, 0xAF67, 0xCE51, 0xAF68, 0xCE52, 0xAF69, 0xCE53, 0xAF6A, 0xCE54, 0xAF6B, 0xCE55, 0xAF6C, 0xCE56, 0xAF6D, 0xCE57, 0xAF6E, 0xCE58, 0xC4A1, 0xCE59, 0xC4A2, 0xCE5A, 0xAF6F, 0xCE5B, 0xAF70, 0xCE5C, 0xC4A3, 0xCE5D, 0xAF71, 0xCE5E, 0xAF72, 0xCE5F, 0xC4A4, 0xCE60, 0xC4A5, 0xCE61, 0xC4A6, 0xCE62, 0xAF73, 0xCE63, 0xAF74, 0xCE64, 0xAF75, 0xCE65, 0xAF76, 0xCE66, 0xAF77, 0xCE67, 0xAF78, 0xCE68, 0xC4A7, 0xCE69, 0xC4A8, 0xCE6A, 0xAF79, 0xCE6B, 0xC4A9, 0xCE6C, 0xAF7A, 0xCE6D, 0xC4AA, 0xCE6E, 0xAF81, 0xCE6F, 0xAF82, 0xCE70, 0xAF83, 0xCE71, 0xAF84, 0xCE72, 0xAF85, 0xCE73, 0xAF86, 0xCE74, 0xC4AB, 0xCE75, 0xC4AC, 0xCE76, 0xAF87, 0xCE77, 0xAF88, 0xCE78, 0xC4AD, 0xCE79, 0xAF89, 0xCE7A, 0xAF8A, 0xCE7B, 0xAF8B, 0xCE7C, 0xC4AE, 0xCE7D, 0xAF8C, 0xCE7E, 0xAF8D, 0xCE7F, 0xAF8E, 0xCE80, 0xAF8F, 0xCE81, 0xAF90, 0xCE82, 0xAF91, 0xCE83, 0xAF92, 0xCE84, 0xC4AF, 0xCE85, 0xC4B0, 0xCE86, 0xAF93, 0xCE87, 0xC4B1, 0xCE88, 0xAF94, 0xCE89, 0xC4B2, 0xCE8A, 0xAF95, 0xCE8B, 0xAF96, 0xCE8C, 0xAF97, 0xCE8D, 0xAF98, 0xCE8E, 0xAF99, 0xCE8F, 0xAF9A, 0xCE90, 0xC4B3, 0xCE91, 0xC4B4, 0xCE92, 0xAF9B, 0xCE93, 0xAF9C, 0xCE94, 0xC4B5, 0xCE95, 0xAF9D, 0xCE96, 0xAF9E, 0xCE97, 0xAF9F, 0xCE98, 0xC4B6, 0xCE99, 0xAFA0, 0xCE9A, 0xB041, 0xCE9B, 0xB042, 0xCE9C, 0xB043, 0xCE9D, 0xB044, 0xCE9E, 0xB045, 0xCE9F, 0xB046, 0xCEA0, 0xC4B7, 0xCEA1, 0xC4B8, 0xCEA2, 0xB047, 0xCEA3, 0xC4B9, 0xCEA4, 0xC4BA, 0xCEA5, 0xC4BB, 0xCEA6, 0xB048, 0xCEA7, 0xB049, 0xCEA8, 0xB04A, 0xCEA9, 0xB04B, 0xCEAA, 0xB04C, 0xCEAB, 0xB04D, 0xCEAC, 0xC4BC, 0xCEAD, 0xC4BD, 0xCEAE, 0xB04E, 0xCEAF, 0xB04F, 0xCEB0, 0xB050, 0xCEB1, 0xB051, 0xCEB2, 0xB052, 0xCEB3, 0xB053, 0xCEB4, 0xB054, 0xCEB5, 0xB055, 0xCEB6, 0xB056, 0xCEB7, 0xB057, 0xCEB8, 0xB058, 0xCEB9, 0xB059, 0xCEBA, 0xB05A, 0xCEBB, 0xB061, 0xCEBC, 0xB062, 0xCEBD, 0xB063, 0xCEBE, 0xB064, 0xCEBF, 0xB065, 0xCEC0, 0xB066, 0xCEC1, 0xC4BE, 0xCEC2, 0xB067, 0xCEC3, 0xB068, 0xCEC4, 0xB069, 0xCEC5, 0xB06A, 0xCEC6, 0xB06B, 0xCEC7, 0xB06C, 0xCEC8, 0xB06D, 0xCEC9, 0xB06E, 0xCECA, 0xB06F, 0xCECB, 0xB070, 0xCECC, 0xB071, 0xCECD, 0xB072, 0xCECE, 0xB073, 0xCECF, 0xB074, 0xCED0, 0xB075, 0xCED1, 0xB076, 0xCED2, 0xB077, 0xCED3, 0xB078, 0xCED4, 0xB079, 0xCED5, 0xB07A, 0xCED6, 0xB081, 0xCED7, 0xB082, 0xCED8, 0xB083, 0xCED9, 0xB084, 0xCEDA, 0xB085, 0xCEDB, 0xB086, 0xCEDC, 0xB087, 0xCEDD, 0xB088, 0xCEDE, 0xB089, 0xCEDF, 0xB08A, 0xCEE0, 0xB08B, 0xCEE1, 0xB08C, 0xCEE2, 0xB08D, 0xCEE3, 0xB08E, 0xCEE4, 0xC4BF, 0xCEE5, 0xC4C0, 0xCEE6, 0xB08F, 0xCEE7, 0xB090, 0xCEE8, 0xC4C1, 0xCEE9, 0xB091, 0xCEEA, 0xB092, 0xCEEB, 0xC4C2, 0xCEEC, 0xC4C3, 0xCEED, 0xB093, 0xCEEE, 0xB094, 0xCEEF, 0xB095, 0xCEF0, 0xB096, 0xCEF1, 0xB097, 0xCEF2, 0xB098, 0xCEF3, 0xB099, 0xCEF4, 0xC4C4, 0xCEF5, 0xC4C5, 0xCEF6, 0xB09A, 0xCEF7, 0xC4C6, 0xCEF8, 0xC4C7, 0xCEF9, 0xC4C8, 0xCEFA, 0xB09B, 0xCEFB, 0xB09C, 0xCEFC, 0xB09D, 0xCEFD, 0xB09E, 0xCEFE, 0xB09F, 0xCEFF, 0xB0A0, 0xCF00, 0xC4C9, 0xCF01, 0xC4CA, 0xCF02, 0xB141, 0xCF03, 0xB142, 0xCF04, 0xC4CB, 0xCF05, 0xB143, 0xCF06, 0xB144, 0xCF07, 0xB145, 0xCF08, 0xC4CC, 0xCF09, 0xB146, 0xCF0A, 0xB147, 0xCF0B, 0xB148, 0xCF0C, 0xB149, 0xCF0D, 0xB14A, 0xCF0E, 0xB14B, 0xCF0F, 0xB14C, 0xCF10, 0xC4CD, 0xCF11, 0xC4CE, 0xCF12, 0xB14D, 0xCF13, 0xC4CF, 0xCF14, 0xB14E, 0xCF15, 0xC4D0, 0xCF16, 0xB14F, 0xCF17, 0xB150, 0xCF18, 0xB151, 0xCF19, 0xB152, 0xCF1A, 0xB153, 0xCF1B, 0xB154, 0xCF1C, 0xC4D1, 0xCF1D, 0xB155, 0xCF1E, 0xB156, 0xCF1F, 0xB157, 0xCF20, 0xC4D2, 0xCF21, 0xB158, 0xCF22, 0xB159, 0xCF23, 0xB15A, 0xCF24, 0xC4D3, 0xCF25, 0xB161, 0xCF26, 0xB162, 0xCF27, 0xB163, 0xCF28, 0xB164, 0xCF29, 0xB165, 0xCF2A, 0xB166, 0xCF2B, 0xB167, 0xCF2C, 0xC4D4, 0xCF2D, 0xC4D5, 0xCF2E, 0xB168, 0xCF2F, 0xC4D6, 0xCF30, 0xC4D7, 0xCF31, 0xC4D8, 0xCF32, 0xB169, 0xCF33, 0xB16A, 0xCF34, 0xB16B, 0xCF35, 0xB16C, 0xCF36, 0xB16D, 0xCF37, 0xB16E, 0xCF38, 0xC4D9, 0xCF39, 0xB16F, 0xCF3A, 0xB170, 0xCF3B, 0xB171, 0xCF3C, 0xB172, 0xCF3D, 0xB173, 0xCF3E, 0xB174, 0xCF3F, 0xB175, 0xCF40, 0xB176, 0xCF41, 0xB177, 0xCF42, 0xB178, 0xCF43, 0xB179, 0xCF44, 0xB17A, 0xCF45, 0xB181, 0xCF46, 0xB182, 0xCF47, 0xB183, 0xCF48, 0xB184, 0xCF49, 0xB185, 0xCF4A, 0xB186, 0xCF4B, 0xB187, 0xCF4C, 0xB188, 0xCF4D, 0xB189, 0xCF4E, 0xB18A, 0xCF4F, 0xB18B, 0xCF50, 0xB18C, 0xCF51, 0xB18D, 0xCF52, 0xB18E, 0xCF53, 0xB18F, 0xCF54, 0xC4DA, 0xCF55, 0xC4DB, 0xCF56, 0xB190, 0xCF57, 0xB191, 0xCF58, 0xC4DC, 0xCF59, 0xB192, 0xCF5A, 0xB193, 0xCF5B, 0xB194, 0xCF5C, 0xC4DD, 0xCF5D, 0xB195, 0xCF5E, 0xB196, 0xCF5F, 0xB197, 0xCF60, 0xB198, 0xCF61, 0xB199, 0xCF62, 0xB19A, 0xCF63, 0xB19B, 0xCF64, 0xC4DE, 0xCF65, 0xC4DF, 0xCF66, 0xB19C, 0xCF67, 0xC4E0, 0xCF68, 0xB19D, 0xCF69, 0xC4E1, 0xCF6A, 0xB19E, 0xCF6B, 0xB19F, 0xCF6C, 0xB1A0, 0xCF6D, 0xB241, 0xCF6E, 0xB242, 0xCF6F, 0xB243, 0xCF70, 0xC4E2, 0xCF71, 0xC4E3, 0xCF72, 0xB244, 0xCF73, 0xB245, 0xCF74, 0xC4E4, 0xCF75, 0xB246, 0xCF76, 0xB247, 0xCF77, 0xB248, 0xCF78, 0xC4E5, 0xCF79, 0xB249, 0xCF7A, 0xB24A, 0xCF7B, 0xB24B, 0xCF7C, 0xB24C, 0xCF7D, 0xB24D, 0xCF7E, 0xB24E, 0xCF7F, 0xB24F, 0xCF80, 0xC4E6, 0xCF81, 0xB250, 0xCF82, 0xB251, 0xCF83, 0xB252, 0xCF84, 0xB253, 0xCF85, 0xC4E7, 0xCF86, 0xB254, 0xCF87, 0xB255, 0xCF88, 0xB256, 0xCF89, 0xB257, 0xCF8A, 0xB258, 0xCF8B, 0xB259, 0xCF8C, 0xC4E8, 0xCF8D, 0xB25A, 0xCF8E, 0xB261, 0xCF8F, 0xB262, 0xCF90, 0xB263, 0xCF91, 0xB264, 0xCF92, 0xB265, 0xCF93, 0xB266, 0xCF94, 0xB267, 0xCF95, 0xB268, 0xCF96, 0xB269, 0xCF97, 0xB26A, 0xCF98, 0xB26B, 0xCF99, 0xB26C, 0xCF9A, 0xB26D, 0xCF9B, 0xB26E, 0xCF9C, 0xB26F, 0xCF9D, 0xB270, 0xCF9E, 0xB271, 0xCF9F, 0xB272, 0xCFA0, 0xB273, 0xCFA1, 0xC4E9, 0xCFA2, 0xB274, 0xCFA3, 0xB275, 0xCFA4, 0xB276, 0xCFA5, 0xB277, 0xCFA6, 0xB278, 0xCFA7, 0xB279, 0xCFA8, 0xC4EA, 0xCFA9, 0xB27A, 0xCFAA, 0xB281, 0xCFAB, 0xB282, 0xCFAC, 0xB283, 0xCFAD, 0xB284, 0xCFAE, 0xB285, 0xCFAF, 0xB286, 0xCFB0, 0xC4EB, 0xCFB1, 0xB287, 0xCFB2, 0xB288, 0xCFB3, 0xB289, 0xCFB4, 0xB28A, 0xCFB5, 0xB28B, 0xCFB6, 0xB28C, 0xCFB7, 0xB28D, 0xCFB8, 0xB28E, 0xCFB9, 0xB28F, 0xCFBA, 0xB290, 0xCFBB, 0xB291, 0xCFBC, 0xB292, 0xCFBD, 0xB293, 0xCFBE, 0xB294, 0xCFBF, 0xB295, 0xCFC0, 0xB296, 0xCFC1, 0xB297, 0xCFC2, 0xB298, 0xCFC3, 0xB299, 0xCFC4, 0xC4EC, 0xCFC5, 0xB29A, 0xCFC6, 0xB29B, 0xCFC7, 0xB29C, 0xCFC8, 0xB29D, 0xCFC9, 0xB29E, 0xCFCA, 0xB29F, 0xCFCB, 0xB2A0, 0xCFCC, 0xB341, 0xCFCD, 0xB342, 0xCFCE, 0xB343, 0xCFCF, 0xB344, 0xCFD0, 0xB345, 0xCFD1, 0xB346, 0xCFD2, 0xB347, 0xCFD3, 0xB348, 0xCFD4, 0xB349, 0xCFD5, 0xB34A, 0xCFD6, 0xB34B, 0xCFD7, 0xB34C, 0xCFD8, 0xB34D, 0xCFD9, 0xB34E, 0xCFDA, 0xB34F, 0xCFDB, 0xB350, 0xCFDC, 0xB351, 0xCFDD, 0xB352, 0xCFDE, 0xB353, 0xCFDF, 0xB354, 0xCFE0, 0xC4ED, 0xCFE1, 0xC4EE, 0xCFE2, 0xB355, 0xCFE3, 0xB356, 0xCFE4, 0xC4EF, 0xCFE5, 0xB357, 0xCFE6, 0xB358, 0xCFE7, 0xB359, 0xCFE8, 0xC4F0, 0xCFE9, 0xB35A, 0xCFEA, 0xB361, 0xCFEB, 0xB362, 0xCFEC, 0xB363, 0xCFED, 0xB364, 0xCFEE, 0xB365, 0xCFEF, 0xB366, 0xCFF0, 0xC4F1, 0xCFF1, 0xC4F2, 0xCFF2, 0xB367, 0xCFF3, 0xC4F3, 0xCFF4, 0xB368, 0xCFF5, 0xC4F4, 0xCFF6, 0xB369, 0xCFF7, 0xB36A, 0xCFF8, 0xB36B, 0xCFF9, 0xB36C, 0xCFFA, 0xB36D, 0xCFFB, 0xB36E, 0xCFFC, 0xC4F5, 0xCFFD, 0xB36F, 0xCFFE, 0xB370, 0xCFFF, 0xB371, 0xD000, 0xC4F6, 0xD001, 0xB372, 0xD002, 0xB373, 0xD003, 0xB374, 0xD004, 0xC4F7, 0xD005, 0xB375, 0xD006, 0xB376, 0xD007, 0xB377, 0xD008, 0xB378, 0xD009, 0xB379, 0xD00A, 0xB37A, 0xD00B, 0xB381, 0xD00C, 0xB382, 0xD00D, 0xB383, 0xD00E, 0xB384, 0xD00F, 0xB385, 0xD010, 0xB386, 0xD011, 0xC4F8, 0xD012, 0xB387, 0xD013, 0xB388, 0xD014, 0xB389, 0xD015, 0xB38A, 0xD016, 0xB38B, 0xD017, 0xB38C, 0xD018, 0xC4F9, 0xD019, 0xB38D, 0xD01A, 0xB38E, 0xD01B, 0xB38F, 0xD01C, 0xB390, 0xD01D, 0xB391, 0xD01E, 0xB392, 0xD01F, 0xB393, 0xD020, 0xB394, 0xD021, 0xB395, 0xD022, 0xB396, 0xD023, 0xB397, 0xD024, 0xB398, 0xD025, 0xB399, 0xD026, 0xB39A, 0xD027, 0xB39B, 0xD028, 0xB39C, 0xD029, 0xB39D, 0xD02A, 0xB39E, 0xD02B, 0xB39F, 0xD02C, 0xB3A0, 0xD02D, 0xC4FA, 0xD02E, 0xB441, 0xD02F, 0xB442, 0xD030, 0xB443, 0xD031, 0xB444, 0xD032, 0xB445, 0xD033, 0xB446, 0xD034, 0xC4FB, 0xD035, 0xC4FC, 0xD036, 0xB447, 0xD037, 0xB448, 0xD038, 0xC4FD, 0xD039, 0xB449, 0xD03A, 0xB44A, 0xD03B, 0xB44B, 0xD03C, 0xC4FE, 0xD03D, 0xB44C, 0xD03E, 0xB44D, 0xD03F, 0xB44E, 0xD040, 0xB44F, 0xD041, 0xB450, 0xD042, 0xB451, 0xD043, 0xB452, 0xD044, 0xC5A1, 0xD045, 0xC5A2, 0xD046, 0xB453, 0xD047, 0xC5A3, 0xD048, 0xB454, 0xD049, 0xC5A4, 0xD04A, 0xB455, 0xD04B, 0xB456, 0xD04C, 0xB457, 0xD04D, 0xB458, 0xD04E, 0xB459, 0xD04F, 0xB45A, 0xD050, 0xC5A5, 0xD051, 0xB461, 0xD052, 0xB462, 0xD053, 0xB463, 0xD054, 0xC5A6, 0xD055, 0xB464, 0xD056, 0xB465, 0xD057, 0xB466, 0xD058, 0xC5A7, 0xD059, 0xB467, 0xD05A, 0xB468, 0xD05B, 0xB469, 0xD05C, 0xB46A, 0xD05D, 0xB46B, 0xD05E, 0xB46C, 0xD05F, 0xB46D, 0xD060, 0xC5A8, 0xD061, 0xB46E, 0xD062, 0xB46F, 0xD063, 0xB470, 0xD064, 0xB471, 0xD065, 0xB472, 0xD066, 0xB473, 0xD067, 0xB474, 0xD068, 0xB475, 0xD069, 0xB476, 0xD06A, 0xB477, 0xD06B, 0xB478, 0xD06C, 0xC5A9, 0xD06D, 0xC5AA, 0xD06E, 0xB479, 0xD06F, 0xB47A, 0xD070, 0xC5AB, 0xD071, 0xB481, 0xD072, 0xB482, 0xD073, 0xB483, 0xD074, 0xC5AC, 0xD075, 0xB484, 0xD076, 0xB485, 0xD077, 0xB486, 0xD078, 0xB487, 0xD079, 0xB488, 0xD07A, 0xB489, 0xD07B, 0xB48A, 0xD07C, 0xC5AD, 0xD07D, 0xC5AE, 0xD07E, 0xB48B, 0xD07F, 0xB48C, 0xD080, 0xB48D, 0xD081, 0xC5AF, 0xD082, 0xB48E, 0xD083, 0xB48F, 0xD084, 0xB490, 0xD085, 0xB491, 0xD086, 0xB492, 0xD087, 0xB493, 0xD088, 0xB494, 0xD089, 0xB495, 0xD08A, 0xB496, 0xD08B, 0xB497, 0xD08C, 0xB498, 0xD08D, 0xB499, 0xD08E, 0xB49A, 0xD08F, 0xB49B, 0xD090, 0xB49C, 0xD091, 0xB49D, 0xD092, 0xB49E, 0xD093, 0xB49F, 0xD094, 0xB4A0, 0xD095, 0xB541, 0xD096, 0xB542, 0xD097, 0xB543, 0xD098, 0xB544, 0xD099, 0xB545, 0xD09A, 0xB546, 0xD09B, 0xB547, 0xD09C, 0xB548, 0xD09D, 0xB549, 0xD09E, 0xB54A, 0xD09F, 0xB54B, 0xD0A0, 0xB54C, 0xD0A1, 0xB54D, 0xD0A2, 0xB54E, 0xD0A3, 0xB54F, 0xD0A4, 0xC5B0, 0xD0A5, 0xC5B1, 0xD0A6, 0xB550, 0xD0A7, 0xB551, 0xD0A8, 0xC5B2, 0xD0A9, 0xB552, 0xD0AA, 0xB553, 0xD0AB, 0xB554, 0xD0AC, 0xC5B3, 0xD0AD, 0xB555, 0xD0AE, 0xB556, 0xD0AF, 0xB557, 0xD0B0, 0xB558, 0xD0B1, 0xB559, 0xD0B2, 0xB55A, 0xD0B3, 0xB561, 0xD0B4, 0xC5B4, 0xD0B5, 0xC5B5, 0xD0B6, 0xB562, 0xD0B7, 0xC5B6, 0xD0B8, 0xB563, 0xD0B9, 0xC5B7, 0xD0BA, 0xB564, 0xD0BB, 0xB565, 0xD0BC, 0xB566, 0xD0BD, 0xB567, 0xD0BE, 0xB568, 0xD0BF, 0xB569, 0xD0C0, 0xC5B8, 0xD0C1, 0xC5B9, 0xD0C2, 0xB56A, 0xD0C3, 0xB56B, 0xD0C4, 0xC5BA, 0xD0C5, 0xB56C, 0xD0C6, 0xB56D, 0xD0C7, 0xB56E, 0xD0C8, 0xC5BB, 0xD0C9, 0xC5BC, 0xD0CA, 0xB56F, 0xD0CB, 0xB570, 0xD0CC, 0xB571, 0xD0CD, 0xB572, 0xD0CE, 0xB573, 0xD0CF, 0xB574, 0xD0D0, 0xC5BD, 0xD0D1, 0xC5BE, 0xD0D2, 0xB575, 0xD0D3, 0xC5BF, 0xD0D4, 0xC5C0, 0xD0D5, 0xC5C1, 0xD0D6, 0xB576, 0xD0D7, 0xB577, 0xD0D8, 0xB578, 0xD0D9, 0xB579, 0xD0DA, 0xB57A, 0xD0DB, 0xB581, 0xD0DC, 0xC5C2, 0xD0DD, 0xC5C3, 0xD0DE, 0xB582, 0xD0DF, 0xB583, 0xD0E0, 0xC5C4, 0xD0E1, 0xB584, 0xD0E2, 0xB585, 0xD0E3, 0xB586, 0xD0E4, 0xC5C5, 0xD0E5, 0xB587, 0xD0E6, 0xB588, 0xD0E7, 0xB589, 0xD0E8, 0xB58A, 0xD0E9, 0xB58B, 0xD0EA, 0xB58C, 0xD0EB, 0xB58D, 0xD0EC, 0xC5C6, 0xD0ED, 0xC5C7, 0xD0EE, 0xB58E, 0xD0EF, 0xC5C8, 0xD0F0, 0xC5C9, 0xD0F1, 0xC5CA, 0xD0F2, 0xB58F, 0xD0F3, 0xB590, 0xD0F4, 0xB591, 0xD0F5, 0xB592, 0xD0F6, 0xB593, 0xD0F7, 0xB594, 0xD0F8, 0xC5CB, 0xD0F9, 0xB595, 0xD0FA, 0xB596, 0xD0FB, 0xB597, 0xD0FC, 0xB598, 0xD0FD, 0xB599, 0xD0FE, 0xB59A, 0xD0FF, 0xB59B, 0xD100, 0xB59C, 0xD101, 0xB59D, 0xD102, 0xB59E, 0xD103, 0xB59F, 0xD104, 0xB5A0, 0xD105, 0xB641, 0xD106, 0xB642, 0xD107, 0xB643, 0xD108, 0xB644, 0xD109, 0xB645, 0xD10A, 0xB646, 0xD10B, 0xB647, 0xD10C, 0xB648, 0xD10D, 0xC5CC, 0xD10E, 0xB649, 0xD10F, 0xB64A, 0xD110, 0xB64B, 0xD111, 0xB64C, 0xD112, 0xB64D, 0xD113, 0xB64E, 0xD114, 0xB64F, 0xD115, 0xB650, 0xD116, 0xB651, 0xD117, 0xB652, 0xD118, 0xB653, 0xD119, 0xB654, 0xD11A, 0xB655, 0xD11B, 0xB656, 0xD11C, 0xB657, 0xD11D, 0xB658, 0xD11E, 0xB659, 0xD11F, 0xB65A, 0xD120, 0xB661, 0xD121, 0xB662, 0xD122, 0xB663, 0xD123, 0xB664, 0xD124, 0xB665, 0xD125, 0xB666, 0xD126, 0xB667, 0xD127, 0xB668, 0xD128, 0xB669, 0xD129, 0xB66A, 0xD12A, 0xB66B, 0xD12B, 0xB66C, 0xD12C, 0xB66D, 0xD12D, 0xB66E, 0xD12E, 0xB66F, 0xD12F, 0xB670, 0xD130, 0xC5CD, 0xD131, 0xC5CE, 0xD132, 0xB671, 0xD133, 0xB672, 0xD134, 0xC5CF, 0xD135, 0xB673, 0xD136, 0xB674, 0xD137, 0xB675, 0xD138, 0xC5D0, 0xD139, 0xB676, 0xD13A, 0xC5D1, 0xD13B, 0xB677, 0xD13C, 0xB678, 0xD13D, 0xB679, 0xD13E, 0xB67A, 0xD13F, 0xB681, 0xD140, 0xC5D2, 0xD141, 0xC5D3, 0xD142, 0xB682, 0xD143, 0xC5D4, 0xD144, 0xC5D5, 0xD145, 0xC5D6, 0xD146, 0xB683, 0xD147, 0xB684, 0xD148, 0xB685, 0xD149, 0xB686, 0xD14A, 0xB687, 0xD14B, 0xB688, 0xD14C, 0xC5D7, 0xD14D, 0xC5D8, 0xD14E, 0xB689, 0xD14F, 0xB68A, 0xD150, 0xC5D9, 0xD151, 0xB68B, 0xD152, 0xB68C, 0xD153, 0xB68D, 0xD154, 0xC5DA, 0xD155, 0xB68E, 0xD156, 0xB68F, 0xD157, 0xB690, 0xD158, 0xB691, 0xD159, 0xB692, 0xD15A, 0xB693, 0xD15B, 0xB694, 0xD15C, 0xC5DB, 0xD15D, 0xC5DC, 0xD15E, 0xB695, 0xD15F, 0xC5DD, 0xD160, 0xB696, 0xD161, 0xC5DE, 0xD162, 0xB697, 0xD163, 0xB698, 0xD164, 0xB699, 0xD165, 0xB69A, 0xD166, 0xB69B, 0xD167, 0xB69C, 0xD168, 0xC5DF, 0xD169, 0xB69D, 0xD16A, 0xB69E, 0xD16B, 0xB69F, 0xD16C, 0xC5E0, 0xD16D, 0xB6A0, 0xD16E, 0xB741, 0xD16F, 0xB742, 0xD170, 0xB743, 0xD171, 0xB744, 0xD172, 0xB745, 0xD173, 0xB746, 0xD174, 0xB747, 0xD175, 0xB748, 0xD176, 0xB749, 0xD177, 0xB74A, 0xD178, 0xB74B, 0xD179, 0xB74C, 0xD17A, 0xB74D, 0xD17B, 0xB74E, 0xD17C, 0xC5E1, 0xD17D, 0xB74F, 0xD17E, 0xB750, 0xD17F, 0xB751, 0xD180, 0xB752, 0xD181, 0xB753, 0xD182, 0xB754, 0xD183, 0xB755, 0xD184, 0xC5E2, 0xD185, 0xB756, 0xD186, 0xB757, 0xD187, 0xB758, 0xD188, 0xC5E3, 0xD189, 0xB759, 0xD18A, 0xB75A, 0xD18B, 0xB761, 0xD18C, 0xB762, 0xD18D, 0xB763, 0xD18E, 0xB764, 0xD18F, 0xB765, 0xD190, 0xB766, 0xD191, 0xB767, 0xD192, 0xB768, 0xD193, 0xB769, 0xD194, 0xB76A, 0xD195, 0xB76B, 0xD196, 0xB76C, 0xD197, 0xB76D, 0xD198, 0xB76E, 0xD199, 0xB76F, 0xD19A, 0xB770, 0xD19B, 0xB771, 0xD19C, 0xB772, 0xD19D, 0xB773, 0xD19E, 0xB774, 0xD19F, 0xB775, 0xD1A0, 0xC5E4, 0xD1A1, 0xC5E5, 0xD1A2, 0xB776, 0xD1A3, 0xB777, 0xD1A4, 0xC5E6, 0xD1A5, 0xB778, 0xD1A6, 0xB779, 0xD1A7, 0xB77A, 0xD1A8, 0xC5E7, 0xD1A9, 0xB781, 0xD1AA, 0xB782, 0xD1AB, 0xB783, 0xD1AC, 0xB784, 0xD1AD, 0xB785, 0xD1AE, 0xB786, 0xD1AF, 0xB787, 0xD1B0, 0xC5E8, 0xD1B1, 0xC5E9, 0xD1B2, 0xB788, 0xD1B3, 0xC5EA, 0xD1B4, 0xB789, 0xD1B5, 0xC5EB, 0xD1B6, 0xB78A, 0xD1B7, 0xB78B, 0xD1B8, 0xB78C, 0xD1B9, 0xB78D, 0xD1BA, 0xC5EC, 0xD1BB, 0xB78E, 0xD1BC, 0xC5ED, 0xD1BD, 0xB78F, 0xD1BE, 0xB790, 0xD1BF, 0xB791, 0xD1C0, 0xC5EE, 0xD1C1, 0xB792, 0xD1C2, 0xB793, 0xD1C3, 0xB794, 0xD1C4, 0xB795, 0xD1C5, 0xB796, 0xD1C6, 0xB797, 0xD1C7, 0xB798, 0xD1C8, 0xB799, 0xD1C9, 0xB79A, 0xD1CA, 0xB79B, 0xD1CB, 0xB79C, 0xD1CC, 0xB79D, 0xD1CD, 0xB79E, 0xD1CE, 0xB79F, 0xD1CF, 0xB7A0, 0xD1D0, 0xB841, 0xD1D1, 0xB842, 0xD1D2, 0xB843, 0xD1D3, 0xB844, 0xD1D4, 0xB845, 0xD1D5, 0xB846, 0xD1D6, 0xB847, 0xD1D7, 0xB848, 0xD1D8, 0xC5EF, 0xD1D9, 0xB849, 0xD1DA, 0xB84A, 0xD1DB, 0xB84B, 0xD1DC, 0xB84C, 0xD1DD, 0xB84D, 0xD1DE, 0xB84E, 0xD1DF, 0xB84F, 0xD1E0, 0xB850, 0xD1E1, 0xB851, 0xD1E2, 0xB852, 0xD1E3, 0xB853, 0xD1E4, 0xB854, 0xD1E5, 0xB855, 0xD1E6, 0xB856, 0xD1E7, 0xB857, 0xD1E8, 0xB858, 0xD1E9, 0xB859, 0xD1EA, 0xB85A, 0xD1EB, 0xB861, 0xD1EC, 0xB862, 0xD1ED, 0xB863, 0xD1EE, 0xB864, 0xD1EF, 0xB865, 0xD1F0, 0xB866, 0xD1F1, 0xB867, 0xD1F2, 0xB868, 0xD1F3, 0xB869, 0xD1F4, 0xC5F0, 0xD1F5, 0xB86A, 0xD1F6, 0xB86B, 0xD1F7, 0xB86C, 0xD1F8, 0xC5F1, 0xD1F9, 0xB86D, 0xD1FA, 0xB86E, 0xD1FB, 0xB86F, 0xD1FC, 0xB870, 0xD1FD, 0xB871, 0xD1FE, 0xB872, 0xD1FF, 0xB873, 0xD200, 0xB874, 0xD201, 0xB875, 0xD202, 0xB876, 0xD203, 0xB877, 0xD204, 0xB878, 0xD205, 0xB879, 0xD206, 0xB87A, 0xD207, 0xC5F2, 0xD208, 0xB881, 0xD209, 0xC5F3, 0xD20A, 0xB882, 0xD20B, 0xB883, 0xD20C, 0xB884, 0xD20D, 0xB885, 0xD20E, 0xB886, 0xD20F, 0xB887, 0xD210, 0xC5F4, 0xD211, 0xB888, 0xD212, 0xB889, 0xD213, 0xB88A, 0xD214, 0xB88B, 0xD215, 0xB88C, 0xD216, 0xB88D, 0xD217, 0xB88E, 0xD218, 0xB88F, 0xD219, 0xB890, 0xD21A, 0xB891, 0xD21B, 0xB892, 0xD21C, 0xB893, 0xD21D, 0xB894, 0xD21E, 0xB895, 0xD21F, 0xB896, 0xD220, 0xB897, 0xD221, 0xB898, 0xD222, 0xB899, 0xD223, 0xB89A, 0xD224, 0xB89B, 0xD225, 0xB89C, 0xD226, 0xB89D, 0xD227, 0xB89E, 0xD228, 0xB89F, 0xD229, 0xB8A0, 0xD22A, 0xB941, 0xD22B, 0xB942, 0xD22C, 0xC5F5, 0xD22D, 0xC5F6, 0xD22E, 0xB943, 0xD22F, 0xB944, 0xD230, 0xC5F7, 0xD231, 0xB945, 0xD232, 0xB946, 0xD233, 0xB947, 0xD234, 0xC5F8, 0xD235, 0xB948, 0xD236, 0xB949, 0xD237, 0xB94A, 0xD238, 0xB94B, 0xD239, 0xB94C, 0xD23A, 0xB94D, 0xD23B, 0xB94E, 0xD23C, 0xC5F9, 0xD23D, 0xC5FA, 0xD23E, 0xB94F, 0xD23F, 0xC5FB, 0xD240, 0xB950, 0xD241, 0xC5FC, 0xD242, 0xB951, 0xD243, 0xB952, 0xD244, 0xB953, 0xD245, 0xB954, 0xD246, 0xB955, 0xD247, 0xB956, 0xD248, 0xC5FD, 0xD249, 0xB957, 0xD24A, 0xB958, 0xD24B, 0xB959, 0xD24C, 0xB95A, 0xD24D, 0xB961, 0xD24E, 0xB962, 0xD24F, 0xB963, 0xD250, 0xB964, 0xD251, 0xB965, 0xD252, 0xB966, 0xD253, 0xB967, 0xD254, 0xB968, 0xD255, 0xB969, 0xD256, 0xB96A, 0xD257, 0xB96B, 0xD258, 0xB96C, 0xD259, 0xB96D, 0xD25A, 0xB96E, 0xD25B, 0xB96F, 0xD25C, 0xC5FE, 0xD25D, 0xB970, 0xD25E, 0xB971, 0xD25F, 0xB972, 0xD260, 0xB973, 0xD261, 0xB974, 0xD262, 0xB975, 0xD263, 0xB976, 0xD264, 0xC6A1, 0xD265, 0xB977, 0xD266, 0xB978, 0xD267, 0xB979, 0xD268, 0xB97A, 0xD269, 0xB981, 0xD26A, 0xB982, 0xD26B, 0xB983, 0xD26C, 0xB984, 0xD26D, 0xB985, 0xD26E, 0xB986, 0xD26F, 0xB987, 0xD270, 0xB988, 0xD271, 0xB989, 0xD272, 0xB98A, 0xD273, 0xB98B, 0xD274, 0xB98C, 0xD275, 0xB98D, 0xD276, 0xB98E, 0xD277, 0xB98F, 0xD278, 0xB990, 0xD279, 0xB991, 0xD27A, 0xB992, 0xD27B, 0xB993, 0xD27C, 0xB994, 0xD27D, 0xB995, 0xD27E, 0xB996, 0xD27F, 0xB997, 0xD280, 0xC6A2, 0xD281, 0xC6A3, 0xD282, 0xB998, 0xD283, 0xB999, 0xD284, 0xC6A4, 0xD285, 0xB99A, 0xD286, 0xB99B, 0xD287, 0xB99C, 0xD288, 0xC6A5, 0xD289, 0xB99D, 0xD28A, 0xB99E, 0xD28B, 0xB99F, 0xD28C, 0xB9A0, 0xD28D, 0xBA41, 0xD28E, 0xBA42, 0xD28F, 0xBA43, 0xD290, 0xC6A6, 0xD291, 0xC6A7, 0xD292, 0xBA44, 0xD293, 0xBA45, 0xD294, 0xBA46, 0xD295, 0xC6A8, 0xD296, 0xBA47, 0xD297, 0xBA48, 0xD298, 0xBA49, 0xD299, 0xBA4A, 0xD29A, 0xBA4B, 0xD29B, 0xBA4C, 0xD29C, 0xC6A9, 0xD29D, 0xBA4D, 0xD29E, 0xBA4E, 0xD29F, 0xBA4F, 0xD2A0, 0xC6AA, 0xD2A1, 0xBA50, 0xD2A2, 0xBA51, 0xD2A3, 0xBA52, 0xD2A4, 0xC6AB, 0xD2A5, 0xBA53, 0xD2A6, 0xBA54, 0xD2A7, 0xBA55, 0xD2A8, 0xBA56, 0xD2A9, 0xBA57, 0xD2AA, 0xBA58, 0xD2AB, 0xBA59, 0xD2AC, 0xC6AC, 0xD2AD, 0xBA5A, 0xD2AE, 0xBA61, 0xD2AF, 0xBA62, 0xD2B0, 0xBA63, 0xD2B1, 0xC6AD, 0xD2B2, 0xBA64, 0xD2B3, 0xBA65, 0xD2B4, 0xBA66, 0xD2B5, 0xBA67, 0xD2B6, 0xBA68, 0xD2B7, 0xBA69, 0xD2B8, 0xC6AE, 0xD2B9, 0xC6AF, 0xD2BA, 0xBA6A, 0xD2BB, 0xBA6B, 0xD2BC, 0xC6B0, 0xD2BD, 0xBA6C, 0xD2BE, 0xBA6D, 0xD2BF, 0xC6B1, 0xD2C0, 0xC6B2, 0xD2C1, 0xBA6E, 0xD2C2, 0xC6B3, 0xD2C3, 0xBA6F, 0xD2C4, 0xBA70, 0xD2C5, 0xBA71, 0xD2C6, 0xBA72, 0xD2C7, 0xBA73, 0xD2C8, 0xC6B4, 0xD2C9, 0xC6B5, 0xD2CA, 0xBA74, 0xD2CB, 0xC6B6, 0xD2CC, 0xBA75, 0xD2CD, 0xBA76, 0xD2CE, 0xBA77, 0xD2CF, 0xBA78, 0xD2D0, 0xBA79, 0xD2D1, 0xBA7A, 0xD2D2, 0xBA81, 0xD2D3, 0xBA82, 0xD2D4, 0xC6B7, 0xD2D5, 0xBA83, 0xD2D6, 0xBA84, 0xD2D7, 0xBA85, 0xD2D8, 0xC6B8, 0xD2D9, 0xBA86, 0xD2DA, 0xBA87, 0xD2DB, 0xBA88, 0xD2DC, 0xC6B9, 0xD2DD, 0xBA89, 0xD2DE, 0xBA8A, 0xD2DF, 0xBA8B, 0xD2E0, 0xBA8C, 0xD2E1, 0xBA8D, 0xD2E2, 0xBA8E, 0xD2E3, 0xBA8F, 0xD2E4, 0xC6BA, 0xD2E5, 0xC6BB, 0xD2E6, 0xBA90, 0xD2E7, 0xBA91, 0xD2E8, 0xBA92, 0xD2E9, 0xBA93, 0xD2EA, 0xBA94, 0xD2EB, 0xBA95, 0xD2EC, 0xBA96, 0xD2ED, 0xBA97, 0xD2EE, 0xBA98, 0xD2EF, 0xBA99, 0xD2F0, 0xC6BC, 0xD2F1, 0xC6BD, 0xD2F2, 0xBA9A, 0xD2F3, 0xBA9B, 0xD2F4, 0xC6BE, 0xD2F5, 0xBA9C, 0xD2F6, 0xBA9D, 0xD2F7, 0xBA9E, 0xD2F8, 0xC6BF, 0xD2F9, 0xBA9F, 0xD2FA, 0xBAA0, 0xD2FB, 0xBB41, 0xD2FC, 0xBB42, 0xD2FD, 0xBB43, 0xD2FE, 0xBB44, 0xD2FF, 0xBB45, 0xD300, 0xC6C0, 0xD301, 0xC6C1, 0xD302, 0xBB46, 0xD303, 0xC6C2, 0xD304, 0xBB47, 0xD305, 0xC6C3, 0xD306, 0xBB48, 0xD307, 0xBB49, 0xD308, 0xBB4A, 0xD309, 0xBB4B, 0xD30A, 0xBB4C, 0xD30B, 0xBB4D, 0xD30C, 0xC6C4, 0xD30D, 0xC6C5, 0xD30E, 0xC6C6, 0xD30F, 0xBB4E, 0xD310, 0xC6C7, 0xD311, 0xBB4F, 0xD312, 0xBB50, 0xD313, 0xBB51, 0xD314, 0xC6C8, 0xD315, 0xBB52, 0xD316, 0xC6C9, 0xD317, 0xBB53, 0xD318, 0xBB54, 0xD319, 0xBB55, 0xD31A, 0xBB56, 0xD31B, 0xBB57, 0xD31C, 0xC6CA, 0xD31D, 0xC6CB, 0xD31E, 0xBB58, 0xD31F, 0xC6CC, 0xD320, 0xC6CD, 0xD321, 0xC6CE, 0xD322, 0xBB59, 0xD323, 0xBB5A, 0xD324, 0xBB61, 0xD325, 0xC6CF, 0xD326, 0xBB62, 0xD327, 0xBB63, 0xD328, 0xC6D0, 0xD329, 0xC6D1, 0xD32A, 0xBB64, 0xD32B, 0xBB65, 0xD32C, 0xC6D2, 0xD32D, 0xBB66, 0xD32E, 0xBB67, 0xD32F, 0xBB68, 0xD330, 0xC6D3, 0xD331, 0xBB69, 0xD332, 0xBB6A, 0xD333, 0xBB6B, 0xD334, 0xBB6C, 0xD335, 0xBB6D, 0xD336, 0xBB6E, 0xD337, 0xBB6F, 0xD338, 0xC6D4, 0xD339, 0xC6D5, 0xD33A, 0xBB70, 0xD33B, 0xC6D6, 0xD33C, 0xC6D7, 0xD33D, 0xC6D8, 0xD33E, 0xBB71, 0xD33F, 0xBB72, 0xD340, 0xBB73, 0xD341, 0xBB74, 0xD342, 0xBB75, 0xD343, 0xBB76, 0xD344, 0xC6D9, 0xD345, 0xC6DA, 0xD346, 0xBB77, 0xD347, 0xBB78, 0xD348, 0xBB79, 0xD349, 0xBB7A, 0xD34A, 0xBB81, 0xD34B, 0xBB82, 0xD34C, 0xBB83, 0xD34D, 0xBB84, 0xD34E, 0xBB85, 0xD34F, 0xBB86, 0xD350, 0xBB87, 0xD351, 0xBB88, 0xD352, 0xBB89, 0xD353, 0xBB8A, 0xD354, 0xBB8B, 0xD355, 0xBB8C, 0xD356, 0xBB8D, 0xD357, 0xBB8E, 0xD358, 0xBB8F, 0xD359, 0xBB90, 0xD35A, 0xBB91, 0xD35B, 0xBB92, 0xD35C, 0xBB93, 0xD35D, 0xBB94, 0xD35E, 0xBB95, 0xD35F, 0xBB96, 0xD360, 0xBB97, 0xD361, 0xBB98, 0xD362, 0xBB99, 0xD363, 0xBB9A, 0xD364, 0xBB9B, 0xD365, 0xBB9C, 0xD366, 0xBB9D, 0xD367, 0xBB9E, 0xD368, 0xBB9F, 0xD369, 0xBBA0, 0xD36A, 0xBC41, 0xD36B, 0xBC42, 0xD36C, 0xBC43, 0xD36D, 0xBC44, 0xD36E, 0xBC45, 0xD36F, 0xBC46, 0xD370, 0xBC47, 0xD371, 0xBC48, 0xD372, 0xBC49, 0xD373, 0xBC4A, 0xD374, 0xBC4B, 0xD375, 0xBC4C, 0xD376, 0xBC4D, 0xD377, 0xBC4E, 0xD378, 0xBC4F, 0xD379, 0xBC50, 0xD37A, 0xBC51, 0xD37B, 0xBC52, 0xD37C, 0xC6DB, 0xD37D, 0xC6DC, 0xD37E, 0xBC53, 0xD37F, 0xBC54, 0xD380, 0xC6DD, 0xD381, 0xBC55, 0xD382, 0xBC56, 0xD383, 0xBC57, 0xD384, 0xC6DE, 0xD385, 0xBC58, 0xD386, 0xBC59, 0xD387, 0xBC5A, 0xD388, 0xBC61, 0xD389, 0xBC62, 0xD38A, 0xBC63, 0xD38B, 0xBC64, 0xD38C, 0xC6DF, 0xD38D, 0xC6E0, 0xD38E, 0xBC65, 0xD38F, 0xC6E1, 0xD390, 0xC6E2, 0xD391, 0xC6E3, 0xD392, 0xBC66, 0xD393, 0xBC67, 0xD394, 0xBC68, 0xD395, 0xBC69, 0xD396, 0xBC6A, 0xD397, 0xBC6B, 0xD398, 0xC6E4, 0xD399, 0xC6E5, 0xD39A, 0xBC6C, 0xD39B, 0xBC6D, 0xD39C, 0xC6E6, 0xD39D, 0xBC6E, 0xD39E, 0xBC6F, 0xD39F, 0xBC70, 0xD3A0, 0xC6E7, 0xD3A1, 0xBC71, 0xD3A2, 0xBC72, 0xD3A3, 0xBC73, 0xD3A4, 0xBC74, 0xD3A5, 0xBC75, 0xD3A6, 0xBC76, 0xD3A7, 0xBC77, 0xD3A8, 0xC6E8, 0xD3A9, 0xC6E9, 0xD3AA, 0xBC78, 0xD3AB, 0xC6EA, 0xD3AC, 0xBC79, 0xD3AD, 0xC6EB, 0xD3AE, 0xBC7A, 0xD3AF, 0xBC81, 0xD3B0, 0xBC82, 0xD3B1, 0xBC83, 0xD3B2, 0xBC84, 0xD3B3, 0xBC85, 0xD3B4, 0xC6EC, 0xD3B5, 0xBC86, 0xD3B6, 0xBC87, 0xD3B7, 0xBC88, 0xD3B8, 0xC6ED, 0xD3B9, 0xBC89, 0xD3BA, 0xBC8A, 0xD3BB, 0xBC8B, 0xD3BC, 0xC6EE, 0xD3BD, 0xBC8C, 0xD3BE, 0xBC8D, 0xD3BF, 0xBC8E, 0xD3C0, 0xBC8F, 0xD3C1, 0xBC90, 0xD3C2, 0xBC91, 0xD3C3, 0xBC92, 0xD3C4, 0xC6EF, 0xD3C5, 0xC6F0, 0xD3C6, 0xBC93, 0xD3C7, 0xBC94, 0xD3C8, 0xC6F1, 0xD3C9, 0xC6F2, 0xD3CA, 0xBC95, 0xD3CB, 0xBC96, 0xD3CC, 0xBC97, 0xD3CD, 0xBC98, 0xD3CE, 0xBC99, 0xD3CF, 0xBC9A, 0xD3D0, 0xC6F3, 0xD3D1, 0xBC9B, 0xD3D2, 0xBC9C, 0xD3D3, 0xBC9D, 0xD3D4, 0xBC9E, 0xD3D5, 0xBC9F, 0xD3D6, 0xBCA0, 0xD3D7, 0xBD41, 0xD3D8, 0xC6F4, 0xD3D9, 0xBD42, 0xD3DA, 0xBD43, 0xD3DB, 0xBD44, 0xD3DC, 0xBD45, 0xD3DD, 0xBD46, 0xD3DE, 0xBD47, 0xD3DF, 0xBD48, 0xD3E0, 0xBD49, 0xD3E1, 0xC6F5, 0xD3E2, 0xBD4A, 0xD3E3, 0xC6F6, 0xD3E4, 0xBD4B, 0xD3E5, 0xBD4C, 0xD3E6, 0xBD4D, 0xD3E7, 0xBD4E, 0xD3E8, 0xBD4F, 0xD3E9, 0xBD50, 0xD3EA, 0xBD51, 0xD3EB, 0xBD52, 0xD3EC, 0xC6F7, 0xD3ED, 0xC6F8, 0xD3EE, 0xBD53, 0xD3EF, 0xBD54, 0xD3F0, 0xC6F9, 0xD3F1, 0xBD55, 0xD3F2, 0xBD56, 0xD3F3, 0xBD57, 0xD3F4, 0xC6FA, 0xD3F5, 0xBD58, 0xD3F6, 0xBD59, 0xD3F7, 0xBD5A, 0xD3F8, 0xBD61, 0xD3F9, 0xBD62, 0xD3FA, 0xBD63, 0xD3FB, 0xBD64, 0xD3FC, 0xC6FB, 0xD3FD, 0xC6FC, 0xD3FE, 0xBD65, 0xD3FF, 0xC6FD, 0xD400, 0xBD66, 0xD401, 0xC6FE, 0xD402, 0xBD67, 0xD403, 0xBD68, 0xD404, 0xBD69, 0xD405, 0xBD6A, 0xD406, 0xBD6B, 0xD407, 0xBD6C, 0xD408, 0xC7A1, 0xD409, 0xBD6D, 0xD40A, 0xBD6E, 0xD40B, 0xBD6F, 0xD40C, 0xBD70, 0xD40D, 0xBD71, 0xD40E, 0xBD72, 0xD40F, 0xBD73, 0xD410, 0xBD74, 0xD411, 0xBD75, 0xD412, 0xBD76, 0xD413, 0xBD77, 0xD414, 0xBD78, 0xD415, 0xBD79, 0xD416, 0xBD7A, 0xD417, 0xBD81, 0xD418, 0xBD82, 0xD419, 0xBD83, 0xD41A, 0xBD84, 0xD41B, 0xBD85, 0xD41C, 0xBD86, 0xD41D, 0xC7A2, 0xD41E, 0xBD87, 0xD41F, 0xBD88, 0xD420, 0xBD89, 0xD421, 0xBD8A, 0xD422, 0xBD8B, 0xD423, 0xBD8C, 0xD424, 0xBD8D, 0xD425, 0xBD8E, 0xD426, 0xBD8F, 0xD427, 0xBD90, 0xD428, 0xBD91, 0xD429, 0xBD92, 0xD42A, 0xBD93, 0xD42B, 0xBD94, 0xD42C, 0xBD95, 0xD42D, 0xBD96, 0xD42E, 0xBD97, 0xD42F, 0xBD98, 0xD430, 0xBD99, 0xD431, 0xBD9A, 0xD432, 0xBD9B, 0xD433, 0xBD9C, 0xD434, 0xBD9D, 0xD435, 0xBD9E, 0xD436, 0xBD9F, 0xD437, 0xBDA0, 0xD438, 0xBE41, 0xD439, 0xBE42, 0xD43A, 0xBE43, 0xD43B, 0xBE44, 0xD43C, 0xBE45, 0xD43D, 0xBE46, 0xD43E, 0xBE47, 0xD43F, 0xBE48, 0xD440, 0xC7A3, 0xD441, 0xBE49, 0xD442, 0xBE4A, 0xD443, 0xBE4B, 0xD444, 0xC7A4, 0xD445, 0xBE4C, 0xD446, 0xBE4D, 0xD447, 0xBE4E, 0xD448, 0xBE4F, 0xD449, 0xBE50, 0xD44A, 0xBE51, 0xD44B, 0xBE52, 0xD44C, 0xBE53, 0xD44D, 0xBE54, 0xD44E, 0xBE55, 0xD44F, 0xBE56, 0xD450, 0xBE57, 0xD451, 0xBE58, 0xD452, 0xBE59, 0xD453, 0xBE5A, 0xD454, 0xBE61, 0xD455, 0xBE62, 0xD456, 0xBE63, 0xD457, 0xBE64, 0xD458, 0xBE65, 0xD459, 0xBE66, 0xD45A, 0xBE67, 0xD45B, 0xBE68, 0xD45C, 0xC7A5, 0xD45D, 0xBE69, 0xD45E, 0xBE6A, 0xD45F, 0xBE6B, 0xD460, 0xC7A6, 0xD461, 0xBE6C, 0xD462, 0xBE6D, 0xD463, 0xBE6E, 0xD464, 0xC7A7, 0xD465, 0xBE6F, 0xD466, 0xBE70, 0xD467, 0xBE71, 0xD468, 0xBE72, 0xD469, 0xBE73, 0xD46A, 0xBE74, 0xD46B, 0xBE75, 0xD46C, 0xBE76, 0xD46D, 0xC7A8, 0xD46E, 0xBE77, 0xD46F, 0xC7A9, 0xD470, 0xBE78, 0xD471, 0xBE79, 0xD472, 0xBE7A, 0xD473, 0xBE81, 0xD474, 0xBE82, 0xD475, 0xBE83, 0xD476, 0xBE84, 0xD477, 0xBE85, 0xD478, 0xC7AA, 0xD479, 0xC7AB, 0xD47A, 0xBE86, 0xD47B, 0xBE87, 0xD47C, 0xC7AC, 0xD47D, 0xBE88, 0xD47E, 0xBE89, 0xD47F, 0xC7AD, 0xD480, 0xC7AE, 0xD481, 0xBE8A, 0xD482, 0xC7AF, 0xD483, 0xBE8B, 0xD484, 0xBE8C, 0xD485, 0xBE8D, 0xD486, 0xBE8E, 0xD487, 0xBE8F, 0xD488, 0xC7B0, 0xD489, 0xC7B1, 0xD48A, 0xBE90, 0xD48B, 0xC7B2, 0xD48C, 0xBE91, 0xD48D, 0xC7B3, 0xD48E, 0xBE92, 0xD48F, 0xBE93, 0xD490, 0xBE94, 0xD491, 0xBE95, 0xD492, 0xBE96, 0xD493, 0xBE97, 0xD494, 0xC7B4, 0xD495, 0xBE98, 0xD496, 0xBE99, 0xD497, 0xBE9A, 0xD498, 0xBE9B, 0xD499, 0xBE9C, 0xD49A, 0xBE9D, 0xD49B, 0xBE9E, 0xD49C, 0xBE9F, 0xD49D, 0xBEA0, 0xD49E, 0xBF41, 0xD49F, 0xBF42, 0xD4A0, 0xBF43, 0xD4A1, 0xBF44, 0xD4A2, 0xBF45, 0xD4A3, 0xBF46, 0xD4A4, 0xBF47, 0xD4A5, 0xBF48, 0xD4A6, 0xBF49, 0xD4A7, 0xBF4A, 0xD4A8, 0xBF4B, 0xD4A9, 0xC7B5, 0xD4AA, 0xBF4C, 0xD4AB, 0xBF4D, 0xD4AC, 0xBF4E, 0xD4AD, 0xBF4F, 0xD4AE, 0xBF50, 0xD4AF, 0xBF51, 0xD4B0, 0xBF52, 0xD4B1, 0xBF53, 0xD4B2, 0xBF54, 0xD4B3, 0xBF55, 0xD4B4, 0xBF56, 0xD4B5, 0xBF57, 0xD4B6, 0xBF58, 0xD4B7, 0xBF59, 0xD4B8, 0xBF5A, 0xD4B9, 0xBF61, 0xD4BA, 0xBF62, 0xD4BB, 0xBF63, 0xD4BC, 0xBF64, 0xD4BD, 0xBF65, 0xD4BE, 0xBF66, 0xD4BF, 0xBF67, 0xD4C0, 0xBF68, 0xD4C1, 0xBF69, 0xD4C2, 0xBF6A, 0xD4C3, 0xBF6B, 0xD4C4, 0xBF6C, 0xD4C5, 0xBF6D, 0xD4C6, 0xBF6E, 0xD4C7, 0xBF6F, 0xD4C8, 0xBF70, 0xD4C9, 0xBF71, 0xD4CA, 0xBF72, 0xD4CB, 0xBF73, 0xD4CC, 0xC7B6, 0xD4CD, 0xBF74, 0xD4CE, 0xBF75, 0xD4CF, 0xBF76, 0xD4D0, 0xC7B7, 0xD4D1, 0xBF77, 0xD4D2, 0xBF78, 0xD4D3, 0xBF79, 0xD4D4, 0xC7B8, 0xD4D5, 0xBF7A, 0xD4D6, 0xBF81, 0xD4D7, 0xBF82, 0xD4D8, 0xBF83, 0xD4D9, 0xBF84, 0xD4DA, 0xBF85, 0xD4DB, 0xBF86, 0xD4DC, 0xC7B9, 0xD4DD, 0xBF87, 0xD4DE, 0xBF88, 0xD4DF, 0xC7BA, 0xD4E0, 0xBF89, 0xD4E1, 0xBF8A, 0xD4E2, 0xBF8B, 0xD4E3, 0xBF8C, 0xD4E4, 0xBF8D, 0xD4E5, 0xBF8E, 0xD4E6, 0xBF8F, 0xD4E7, 0xBF90, 0xD4E8, 0xC7BB, 0xD4E9, 0xBF91, 0xD4EA, 0xBF92, 0xD4EB, 0xBF93, 0xD4EC, 0xC7BC, 0xD4ED, 0xBF94, 0xD4EE, 0xBF95, 0xD4EF, 0xBF96, 0xD4F0, 0xC7BD, 0xD4F1, 0xBF97, 0xD4F2, 0xBF98, 0xD4F3, 0xBF99, 0xD4F4, 0xBF9A, 0xD4F5, 0xBF9B, 0xD4F6, 0xBF9C, 0xD4F7, 0xBF9D, 0xD4F8, 0xC7BE, 0xD4F9, 0xBF9E, 0xD4FA, 0xBF9F, 0xD4FB, 0xC7BF, 0xD4FC, 0xBFA0, 0xD4FD, 0xC7C0, 0xD4FE, 0xC041, 0xD4FF, 0xC042, 0xD500, 0xC043, 0xD501, 0xC044, 0xD502, 0xC045, 0xD503, 0xC046, 0xD504, 0xC7C1, 0xD505, 0xC047, 0xD506, 0xC048, 0xD507, 0xC049, 0xD508, 0xC7C2, 0xD509, 0xC04A, 0xD50A, 0xC04B, 0xD50B, 0xC04C, 0xD50C, 0xC7C3, 0xD50D, 0xC04D, 0xD50E, 0xC04E, 0xD50F, 0xC04F, 0xD510, 0xC050, 0xD511, 0xC051, 0xD512, 0xC052, 0xD513, 0xC053, 0xD514, 0xC7C4, 0xD515, 0xC7C5, 0xD516, 0xC054, 0xD517, 0xC7C6, 0xD518, 0xC055, 0xD519, 0xC056, 0xD51A, 0xC057, 0xD51B, 0xC058, 0xD51C, 0xC059, 0xD51D, 0xC05A, 0xD51E, 0xC061, 0xD51F, 0xC062, 0xD520, 0xC063, 0xD521, 0xC064, 0xD522, 0xC065, 0xD523, 0xC066, 0xD524, 0xC067, 0xD525, 0xC068, 0xD526, 0xC069, 0xD527, 0xC06A, 0xD528, 0xC06B, 0xD529, 0xC06C, 0xD52A, 0xC06D, 0xD52B, 0xC06E, 0xD52C, 0xC06F, 0xD52D, 0xC070, 0xD52E, 0xC071, 0xD52F, 0xC072, 0xD530, 0xC073, 0xD531, 0xC074, 0xD532, 0xC075, 0xD533, 0xC076, 0xD534, 0xC077, 0xD535, 0xC078, 0xD536, 0xC079, 0xD537, 0xC07A, 0xD538, 0xC081, 0xD539, 0xC082, 0xD53A, 0xC083, 0xD53B, 0xC084, 0xD53C, 0xC7C7, 0xD53D, 0xC7C8, 0xD53E, 0xC085, 0xD53F, 0xC086, 0xD540, 0xC7C9, 0xD541, 0xC087, 0xD542, 0xC088, 0xD543, 0xC089, 0xD544, 0xC7CA, 0xD545, 0xC08A, 0xD546, 0xC08B, 0xD547, 0xC08C, 0xD548, 0xC08D, 0xD549, 0xC08E, 0xD54A, 0xC08F, 0xD54B, 0xC090, 0xD54C, 0xC7CB, 0xD54D, 0xC7CC, 0xD54E, 0xC091, 0xD54F, 0xC7CD, 0xD550, 0xC092, 0xD551, 0xC7CE, 0xD552, 0xC093, 0xD553, 0xC094, 0xD554, 0xC095, 0xD555, 0xC096, 0xD556, 0xC097, 0xD557, 0xC098, 0xD558, 0xC7CF, 0xD559, 0xC7D0, 0xD55A, 0xC099, 0xD55B, 0xC09A, 0xD55C, 0xC7D1, 0xD55D, 0xC09B, 0xD55E, 0xC09C, 0xD55F, 0xC09D, 0xD560, 0xC7D2, 0xD561, 0xC09E, 0xD562, 0xC09F, 0xD563, 0xC0A0, 0xD564, 0xC141, 0xD565, 0xC7D3, 0xD566, 0xC142, 0xD567, 0xC143, 0xD568, 0xC7D4, 0xD569, 0xC7D5, 0xD56A, 0xC144, 0xD56B, 0xC7D6, 0xD56C, 0xC145, 0xD56D, 0xC7D7, 0xD56E, 0xC146, 0xD56F, 0xC147, 0xD570, 0xC148, 0xD571, 0xC149, 0xD572, 0xC14A, 0xD573, 0xC14B, 0xD574, 0xC7D8, 0xD575, 0xC7D9, 0xD576, 0xC14C, 0xD577, 0xC14D, 0xD578, 0xC7DA, 0xD579, 0xC14E, 0xD57A, 0xC14F, 0xD57B, 0xC150, 0xD57C, 0xC7DB, 0xD57D, 0xC151, 0xD57E, 0xC152, 0xD57F, 0xC153, 0xD580, 0xC154, 0xD581, 0xC155, 0xD582, 0xC156, 0xD583, 0xC157, 0xD584, 0xC7DC, 0xD585, 0xC7DD, 0xD586, 0xC158, 0xD587, 0xC7DE, 0xD588, 0xC7DF, 0xD589, 0xC7E0, 0xD58A, 0xC159, 0xD58B, 0xC15A, 0xD58C, 0xC161, 0xD58D, 0xC162, 0xD58E, 0xC163, 0xD58F, 0xC164, 0xD590, 0xC7E1, 0xD591, 0xC165, 0xD592, 0xC166, 0xD593, 0xC167, 0xD594, 0xC168, 0xD595, 0xC169, 0xD596, 0xC16A, 0xD597, 0xC16B, 0xD598, 0xC16C, 0xD599, 0xC16D, 0xD59A, 0xC16E, 0xD59B, 0xC16F, 0xD59C, 0xC170, 0xD59D, 0xC171, 0xD59E, 0xC172, 0xD59F, 0xC173, 0xD5A0, 0xC174, 0xD5A1, 0xC175, 0xD5A2, 0xC176, 0xD5A3, 0xC177, 0xD5A4, 0xC178, 0xD5A5, 0xC7E2, 0xD5A6, 0xC179, 0xD5A7, 0xC17A, 0xD5A8, 0xC181, 0xD5A9, 0xC182, 0xD5AA, 0xC183, 0xD5AB, 0xC184, 0xD5AC, 0xC185, 0xD5AD, 0xC186, 0xD5AE, 0xC187, 0xD5AF, 0xC188, 0xD5B0, 0xC189, 0xD5B1, 0xC18A, 0xD5B2, 0xC18B, 0xD5B3, 0xC18C, 0xD5B4, 0xC18D, 0xD5B5, 0xC18E, 0xD5B6, 0xC18F, 0xD5B7, 0xC190, 0xD5B8, 0xC191, 0xD5B9, 0xC192, 0xD5BA, 0xC193, 0xD5BB, 0xC194, 0xD5BC, 0xC195, 0xD5BD, 0xC196, 0xD5BE, 0xC197, 0xD5BF, 0xC198, 0xD5C0, 0xC199, 0xD5C1, 0xC19A, 0xD5C2, 0xC19B, 0xD5C3, 0xC19C, 0xD5C4, 0xC19D, 0xD5C5, 0xC19E, 0xD5C6, 0xC19F, 0xD5C7, 0xC1A0, 0xD5C8, 0xC7E3, 0xD5C9, 0xC7E4, 0xD5CA, 0xC241, 0xD5CB, 0xC242, 0xD5CC, 0xC7E5, 0xD5CD, 0xC243, 0xD5CE, 0xC244, 0xD5CF, 0xC245, 0xD5D0, 0xC7E6, 0xD5D1, 0xC246, 0xD5D2, 0xC7E7, 0xD5D3, 0xC247, 0xD5D4, 0xC248, 0xD5D5, 0xC249, 0xD5D6, 0xC24A, 0xD5D7, 0xC24B, 0xD5D8, 0xC7E8, 0xD5D9, 0xC7E9, 0xD5DA, 0xC24C, 0xD5DB, 0xC7EA, 0xD5DC, 0xC24D, 0xD5DD, 0xC7EB, 0xD5DE, 0xC24E, 0xD5DF, 0xC24F, 0xD5E0, 0xC250, 0xD5E1, 0xC251, 0xD5E2, 0xC252, 0xD5E3, 0xC253, 0xD5E4, 0xC7EC, 0xD5E5, 0xC7ED, 0xD5E6, 0xC254, 0xD5E7, 0xC255, 0xD5E8, 0xC7EE, 0xD5E9, 0xC256, 0xD5EA, 0xC257, 0xD5EB, 0xC258, 0xD5EC, 0xC7EF, 0xD5ED, 0xC259, 0xD5EE, 0xC25A, 0xD5EF, 0xC261, 0xD5F0, 0xC262, 0xD5F1, 0xC263, 0xD5F2, 0xC264, 0xD5F3, 0xC265, 0xD5F4, 0xC7F0, 0xD5F5, 0xC7F1, 0xD5F6, 0xC266, 0xD5F7, 0xC7F2, 0xD5F8, 0xC267, 0xD5F9, 0xC7F3, 0xD5FA, 0xC268, 0xD5FB, 0xC269, 0xD5FC, 0xC26A, 0xD5FD, 0xC26B, 0xD5FE, 0xC26C, 0xD5FF, 0xC26D, 0xD600, 0xC7F4, 0xD601, 0xC7F5, 0xD602, 0xC26E, 0xD603, 0xC26F, 0xD604, 0xC7F6, 0xD605, 0xC270, 0xD606, 0xC271, 0xD607, 0xC272, 0xD608, 0xC7F7, 0xD609, 0xC273, 0xD60A, 0xC274, 0xD60B, 0xC275, 0xD60C, 0xC276, 0xD60D, 0xC277, 0xD60E, 0xC278, 0xD60F, 0xC279, 0xD610, 0xC7F8, 0xD611, 0xC7F9, 0xD612, 0xC27A, 0xD613, 0xC7FA, 0xD614, 0xC7FB, 0xD615, 0xC7FC, 0xD616, 0xC281, 0xD617, 0xC282, 0xD618, 0xC283, 0xD619, 0xC284, 0xD61A, 0xC285, 0xD61B, 0xC286, 0xD61C, 0xC7FD, 0xD61D, 0xC287, 0xD61E, 0xC288, 0xD61F, 0xC289, 0xD620, 0xC7FE, 0xD621, 0xC28A, 0xD622, 0xC28B, 0xD623, 0xC28C, 0xD624, 0xC8A1, 0xD625, 0xC28D, 0xD626, 0xC28E, 0xD627, 0xC28F, 0xD628, 0xC290, 0xD629, 0xC291, 0xD62A, 0xC292, 0xD62B, 0xC293, 0xD62C, 0xC294, 0xD62D, 0xC8A2, 0xD62E, 0xC295, 0xD62F, 0xC296, 0xD630, 0xC297, 0xD631, 0xC298, 0xD632, 0xC299, 0xD633, 0xC29A, 0xD634, 0xC29B, 0xD635, 0xC29C, 0xD636, 0xC29D, 0xD637, 0xC29E, 0xD638, 0xC8A3, 0xD639, 0xC8A4, 0xD63A, 0xC29F, 0xD63B, 0xC2A0, 0xD63C, 0xC8A5, 0xD63D, 0xC341, 0xD63E, 0xC342, 0xD63F, 0xC343, 0xD640, 0xC8A6, 0xD641, 0xC344, 0xD642, 0xC345, 0xD643, 0xC346, 0xD644, 0xC347, 0xD645, 0xC8A7, 0xD646, 0xC348, 0xD647, 0xC349, 0xD648, 0xC8A8, 0xD649, 0xC8A9, 0xD64A, 0xC34A, 0xD64B, 0xC8AA, 0xD64C, 0xC34B, 0xD64D, 0xC8AB, 0xD64E, 0xC34C, 0xD64F, 0xC34D, 0xD650, 0xC34E, 0xD651, 0xC8AC, 0xD652, 0xC34F, 0xD653, 0xC350, 0xD654, 0xC8AD, 0xD655, 0xC8AE, 0xD656, 0xC351, 0xD657, 0xC352, 0xD658, 0xC8AF, 0xD659, 0xC353, 0xD65A, 0xC354, 0xD65B, 0xC355, 0xD65C, 0xC8B0, 0xD65D, 0xC356, 0xD65E, 0xC357, 0xD65F, 0xC358, 0xD660, 0xC359, 0xD661, 0xC35A, 0xD662, 0xC361, 0xD663, 0xC362, 0xD664, 0xC363, 0xD665, 0xC364, 0xD666, 0xC365, 0xD667, 0xC8B1, 0xD668, 0xC366, 0xD669, 0xC8B2, 0xD66A, 0xC367, 0xD66B, 0xC368, 0xD66C, 0xC369, 0xD66D, 0xC36A, 0xD66E, 0xC36B, 0xD66F, 0xC36C, 0xD670, 0xC8B3, 0xD671, 0xC8B4, 0xD672, 0xC36D, 0xD673, 0xC36E, 0xD674, 0xC8B5, 0xD675, 0xC36F, 0xD676, 0xC370, 0xD677, 0xC371, 0xD678, 0xC372, 0xD679, 0xC373, 0xD67A, 0xC374, 0xD67B, 0xC375, 0xD67C, 0xC376, 0xD67D, 0xC377, 0xD67E, 0xC378, 0xD67F, 0xC379, 0xD680, 0xC37A, 0xD681, 0xC381, 0xD682, 0xC382, 0xD683, 0xC8B6, 0xD684, 0xC383, 0xD685, 0xC8B7, 0xD686, 0xC384, 0xD687, 0xC385, 0xD688, 0xC386, 0xD689, 0xC387, 0xD68A, 0xC388, 0xD68B, 0xC389, 0xD68C, 0xC8B8, 0xD68D, 0xC8B9, 0xD68E, 0xC38A, 0xD68F, 0xC38B, 0xD690, 0xC8BA, 0xD691, 0xC38C, 0xD692, 0xC38D, 0xD693, 0xC38E, 0xD694, 0xC8BB, 0xD695, 0xC38F, 0xD696, 0xC390, 0xD697, 0xC391, 0xD698, 0xC392, 0xD699, 0xC393, 0xD69A, 0xC394, 0xD69B, 0xC395, 0xD69C, 0xC396, 0xD69D, 0xC8BC, 0xD69E, 0xC397, 0xD69F, 0xC8BD, 0xD6A0, 0xC398, 0xD6A1, 0xC8BE, 0xD6A2, 0xC399, 0xD6A3, 0xC39A, 0xD6A4, 0xC39B, 0xD6A5, 0xC39C, 0xD6A6, 0xC39D, 0xD6A7, 0xC39E, 0xD6A8, 0xC8BF, 0xD6A9, 0xC39F, 0xD6AA, 0xC3A0, 0xD6AB, 0xC441, 0xD6AC, 0xC8C0, 0xD6AD, 0xC442, 0xD6AE, 0xC443, 0xD6AF, 0xC444, 0xD6B0, 0xC8C1, 0xD6B1, 0xC445, 0xD6B2, 0xC446, 0xD6B3, 0xC447, 0xD6B4, 0xC448, 0xD6B5, 0xC449, 0xD6B6, 0xC44A, 0xD6B7, 0xC44B, 0xD6B8, 0xC44C, 0xD6B9, 0xC8C2, 0xD6BA, 0xC44D, 0xD6BB, 0xC8C3, 0xD6BC, 0xC44E, 0xD6BD, 0xC44F, 0xD6BE, 0xC450, 0xD6BF, 0xC451, 0xD6C0, 0xC452, 0xD6C1, 0xC453, 0xD6C2, 0xC454, 0xD6C3, 0xC455, 0xD6C4, 0xC8C4, 0xD6C5, 0xC8C5, 0xD6C6, 0xC456, 0xD6C7, 0xC457, 0xD6C8, 0xC8C6, 0xD6C9, 0xC458, 0xD6CA, 0xC459, 0xD6CB, 0xC45A, 0xD6CC, 0xC8C7, 0xD6CD, 0xC461, 0xD6CE, 0xC462, 0xD6CF, 0xC463, 0xD6D0, 0xC464, 0xD6D1, 0xC8C8, 0xD6D2, 0xC465, 0xD6D3, 0xC466, 0xD6D4, 0xC8C9, 0xD6D5, 0xC467, 0xD6D6, 0xC468, 0xD6D7, 0xC8CA, 0xD6D8, 0xC469, 0xD6D9, 0xC8CB, 0xD6DA, 0xC46A, 0xD6DB, 0xC46B, 0xD6DC, 0xC46C, 0xD6DD, 0xC46D, 0xD6DE, 0xC46E, 0xD6DF, 0xC46F, 0xD6E0, 0xC8CC, 0xD6E1, 0xC470, 0xD6E2, 0xC471, 0xD6E3, 0xC472, 0xD6E4, 0xC8CD, 0xD6E5, 0xC473, 0xD6E6, 0xC474, 0xD6E7, 0xC475, 0xD6E8, 0xC8CE, 0xD6E9, 0xC476, 0xD6EA, 0xC477, 0xD6EB, 0xC478, 0xD6EC, 0xC479, 0xD6ED, 0xC47A, 0xD6EE, 0xC481, 0xD6EF, 0xC482, 0xD6F0, 0xC8CF, 0xD6F1, 0xC483, 0xD6F2, 0xC484, 0xD6F3, 0xC485, 0xD6F4, 0xC486, 0xD6F5, 0xC8D0, 0xD6F6, 0xC487, 0xD6F7, 0xC488, 0xD6F8, 0xC489, 0xD6F9, 0xC48A, 0xD6FA, 0xC48B, 0xD6FB, 0xC48C, 0xD6FC, 0xC8D1, 0xD6FD, 0xC8D2, 0xD6FE, 0xC48D, 0xD6FF, 0xC48E, 0xD700, 0xC8D3, 0xD701, 0xC48F, 0xD702, 0xC490, 0xD703, 0xC491, 0xD704, 0xC8D4, 0xD705, 0xC492, 0xD706, 0xC493, 0xD707, 0xC494, 0xD708, 0xC495, 0xD709, 0xC496, 0xD70A, 0xC497, 0xD70B, 0xC498, 0xD70C, 0xC499, 0xD70D, 0xC49A, 0xD70E, 0xC49B, 0xD70F, 0xC49C, 0xD710, 0xC49D, 0xD711, 0xC8D5, 0xD712, 0xC49E, 0xD713, 0xC49F, 0xD714, 0xC4A0, 0xD715, 0xC541, 0xD716, 0xC542, 0xD717, 0xC543, 0xD718, 0xC8D6, 0xD719, 0xC8D7, 0xD71A, 0xC544, 0xD71B, 0xC545, 0xD71C, 0xC8D8, 0xD71D, 0xC546, 0xD71E, 0xC547, 0xD71F, 0xC548, 0xD720, 0xC8D9, 0xD721, 0xC549, 0xD722, 0xC54A, 0xD723, 0xC54B, 0xD724, 0xC54C, 0xD725, 0xC54D, 0xD726, 0xC54E, 0xD727, 0xC54F, 0xD728, 0xC8DA, 0xD729, 0xC8DB, 0xD72A, 0xC550, 0xD72B, 0xC8DC, 0xD72C, 0xC551, 0xD72D, 0xC8DD, 0xD72E, 0xC552, 0xD72F, 0xC553, 0xD730, 0xC554, 0xD731, 0xC555, 0xD732, 0xC556, 0xD733, 0xC557, 0xD734, 0xC8DE, 0xD735, 0xC8DF, 0xD736, 0xC558, 0xD737, 0xC559, 0xD738, 0xC8E0, 0xD739, 0xC55A, 0xD73A, 0xC561, 0xD73B, 0xC562, 0xD73C, 0xC8E1, 0xD73D, 0xC563, 0xD73E, 0xC564, 0xD73F, 0xC565, 0xD740, 0xC566, 0xD741, 0xC567, 0xD742, 0xC568, 0xD743, 0xC569, 0xD744, 0xC8E2, 0xD745, 0xC56A, 0xD746, 0xC56B, 0xD747, 0xC8E3, 0xD748, 0xC56C, 0xD749, 0xC8E4, 0xD74A, 0xC56D, 0xD74B, 0xC56E, 0xD74C, 0xC56F, 0xD74D, 0xC570, 0xD74E, 0xC571, 0xD74F, 0xC572, 0xD750, 0xC8E5, 0xD751, 0xC8E6, 0xD752, 0xC573, 0xD753, 0xC574, 0xD754, 0xC8E7, 0xD755, 0xC575, 0xD756, 0xC8E8, 0xD757, 0xC8E9, 0xD758, 0xC8EA, 0xD759, 0xC8EB, 0xD75A, 0xC576, 0xD75B, 0xC577, 0xD75C, 0xC578, 0xD75D, 0xC579, 0xD75E, 0xC57A, 0xD75F, 0xC581, 0xD760, 0xC8EC, 0xD761, 0xC8ED, 0xD762, 0xC582, 0xD763, 0xC8EE, 0xD764, 0xC583, 0xD765, 0xC8EF, 0xD766, 0xC584, 0xD767, 0xC585, 0xD768, 0xC586, 0xD769, 0xC8F0, 0xD76A, 0xC587, 0xD76B, 0xC588, 0xD76C, 0xC8F1, 0xD76D, 0xC589, 0xD76E, 0xC58A, 0xD76F, 0xC58B, 0xD770, 0xC8F2, 0xD771, 0xC58C, 0xD772, 0xC58D, 0xD773, 0xC58E, 0xD774, 0xC8F3, 0xD775, 0xC58F, 0xD776, 0xC590, 0xD777, 0xC591, 0xD778, 0xC592, 0xD779, 0xC593, 0xD77A, 0xC594, 0xD77B, 0xC595, 0xD77C, 0xC8F4, 0xD77D, 0xC8F5, 0xD77E, 0xC596, 0xD77F, 0xC597, 0xD780, 0xC598, 0xD781, 0xC8F6, 0xD782, 0xC599, 0xD783, 0xC59A, 0xD784, 0xC59B, 0xD785, 0xC59C, 0xD786, 0xC59D, 0xD787, 0xC59E, 0xD788, 0xC8F7, 0xD789, 0xC8F8, 0xD78A, 0xC59F, 0xD78B, 0xC5A0, 0xD78C, 0xC8F9, 0xD78D, 0xC641, 0xD78E, 0xC642, 0xD78F, 0xC643, 0xD790, 0xC8FA, 0xD791, 0xC644, 0xD792, 0xC645, 0xD793, 0xC646, 0xD794, 0xC647, 0xD795, 0xC648, 0xD796, 0xC649, 0xD797, 0xC64A, 0xD798, 0xC8FB, 0xD799, 0xC8FC, 0xD79A, 0xC64B, 0xD79B, 0xC8FD, 0xD79C, 0xC64C, 0xD79D, 0xC8FE, 0xD79E, 0xC64D, 0xD79F, 0xC64E, 0xD7A0, 0xC64F, 0xD7A1, 0xC650, 0xD7A2, 0xC651, 0xD7A3, 0xC652, 0xF900, 0xCBD0, 0xF901, 0xCBD6, 0xF902, 0xCBE7, 0xF903, 0xCDCF, 0xF904, 0xCDE8, 0xF905, 0xCEAD, 0xF906, 0xCFFB, 0xF907, 0xD0A2, 0xF908, 0xD0B8, 0xF909, 0xD0D0, 0xF90A, 0xD0DD, 0xF90B, 0xD1D4, 0xF90C, 0xD1D5, 0xF90D, 0xD1D8, 0xF90E, 0xD1DB, 0xF90F, 0xD1DC, 0xF910, 0xD1DD, 0xF911, 0xD1DE, 0xF912, 0xD1DF, 0xF913, 0xD1E0, 0xF914, 0xD1E2, 0xF915, 0xD1E3, 0xF916, 0xD1E4, 0xF917, 0xD1E5, 0xF918, 0xD1E6, 0xF919, 0xD1E8, 0xF91A, 0xD1E9, 0xF91B, 0xD1EA, 0xF91C, 0xD1EB, 0xF91D, 0xD1ED, 0xF91E, 0xD1EF, 0xF91F, 0xD1F0, 0xF920, 0xD1F2, 0xF921, 0xD1F6, 0xF922, 0xD1FA, 0xF923, 0xD1FC, 0xF924, 0xD1FD, 0xF925, 0xD1FE, 0xF926, 0xD2A2, 0xF927, 0xD2A3, 0xF928, 0xD2A7, 0xF929, 0xD2A8, 0xF92A, 0xD2A9, 0xF92B, 0xD2AA, 0xF92C, 0xD2AB, 0xF92D, 0xD2AD, 0xF92E, 0xD2B2, 0xF92F, 0xD2BE, 0xF930, 0xD2C2, 0xF931, 0xD2C3, 0xF932, 0xD2C4, 0xF933, 0xD2C6, 0xF934, 0xD2C7, 0xF935, 0xD2C8, 0xF936, 0xD2C9, 0xF937, 0xD2CA, 0xF938, 0xD2CB, 0xF939, 0xD2CD, 0xF93A, 0xD2CE, 0xF93B, 0xD2CF, 0xF93C, 0xD2D0, 0xF93D, 0xD2D1, 0xF93E, 0xD2D2, 0xF93F, 0xD2D3, 0xF940, 0xD2D4, 0xF941, 0xD2D5, 0xF942, 0xD2D6, 0xF943, 0xD2D7, 0xF944, 0xD2D9, 0xF945, 0xD2DA, 0xF946, 0xD2DE, 0xF947, 0xD2DF, 0xF948, 0xD2E1, 0xF949, 0xD2E2, 0xF94A, 0xD2E4, 0xF94B, 0xD2E5, 0xF94C, 0xD2E6, 0xF94D, 0xD2E7, 0xF94E, 0xD2E8, 0xF94F, 0xD2E9, 0xF950, 0xD2EA, 0xF951, 0xD2EB, 0xF952, 0xD2F0, 0xF953, 0xD2F1, 0xF954, 0xD2F2, 0xF955, 0xD2F3, 0xF956, 0xD2F4, 0xF957, 0xD2F5, 0xF958, 0xD2F7, 0xF959, 0xD2F8, 0xF95A, 0xD4E6, 0xF95B, 0xD4FC, 0xF95C, 0xD5A5, 0xF95D, 0xD5AB, 0xF95E, 0xD5AE, 0xF95F, 0xD6B8, 0xF960, 0xD6CD, 0xF961, 0xD7CB, 0xF962, 0xD7E4, 0xF963, 0xDBC5, 0xF964, 0xDBE4, 0xF965, 0xDCA5, 0xF966, 0xDDA5, 0xF967, 0xDDD5, 0xF968, 0xDDF4, 0xF969, 0xDEFC, 0xF96A, 0xDEFE, 0xF96B, 0xDFB3, 0xF96C, 0xDFE1, 0xF96D, 0xDFE8, 0xF96E, 0xE0F1, 0xF96F, 0xE1AD, 0xF970, 0xE1ED, 0xF971, 0xE3F5, 0xF972, 0xE4A1, 0xF973, 0xE4A9, 0xF974, 0xE5AE, 0xF975, 0xE5B1, 0xF976, 0xE5B2, 0xF977, 0xE5B9, 0xF978, 0xE5BB, 0xF979, 0xE5BC, 0xF97A, 0xE5C4, 0xF97B, 0xE5CE, 0xF97C, 0xE5D0, 0xF97D, 0xE5D2, 0xF97E, 0xE5D6, 0xF97F, 0xE5FA, 0xF980, 0xE5FB, 0xF981, 0xE5FC, 0xF982, 0xE5FE, 0xF983, 0xE6A1, 0xF984, 0xE6A4, 0xF985, 0xE6A7, 0xF986, 0xE6AD, 0xF987, 0xE6AF, 0xF988, 0xE6B0, 0xF989, 0xE6B1, 0xF98A, 0xE6B3, 0xF98B, 0xE6B7, 0xF98C, 0xE6B8, 0xF98D, 0xE6BC, 0xF98E, 0xE6C4, 0xF98F, 0xE6C6, 0xF990, 0xE6C7, 0xF991, 0xE6CA, 0xF992, 0xE6D2, 0xF993, 0xE6D6, 0xF994, 0xE6D9, 0xF995, 0xE6DC, 0xF996, 0xE6DF, 0xF997, 0xE6E1, 0xF998, 0xE6E4, 0xF999, 0xE6E5, 0xF99A, 0xE6E6, 0xF99B, 0xE6E8, 0xF99C, 0xE6EA, 0xF99D, 0xE6EB, 0xF99E, 0xE6EC, 0xF99F, 0xE6EF, 0xF9A0, 0xE6F1, 0xF9A1, 0xE6F2, 0xF9A2, 0xE6F5, 0xF9A3, 0xE6F6, 0xF9A4, 0xE6F7, 0xF9A5, 0xE6F9, 0xF9A6, 0xE7A1, 0xF9A7, 0xE7A6, 0xF9A8, 0xE7A9, 0xF9A9, 0xE7AA, 0xF9AA, 0xE7AC, 0xF9AB, 0xE7AD, 0xF9AC, 0xE7B0, 0xF9AD, 0xE7BF, 0xF9AE, 0xE7C1, 0xF9AF, 0xE7C6, 0xF9B0, 0xE7C7, 0xF9B1, 0xE7CB, 0xF9B2, 0xE7CD, 0xF9B3, 0xE7CF, 0xF9B4, 0xE7D0, 0xF9B5, 0xE7D3, 0xF9B6, 0xE7DF, 0xF9B7, 0xE7E4, 0xF9B8, 0xE7E6, 0xF9B9, 0xE7F7, 0xF9BA, 0xE8E7, 0xF9BB, 0xE8E8, 0xF9BC, 0xE8F0, 0xF9BD, 0xE8F1, 0xF9BE, 0xE8F7, 0xF9BF, 0xE8F9, 0xF9C0, 0xE8FB, 0xF9C1, 0xE8FE, 0xF9C2, 0xE9A7, 0xF9C3, 0xE9AC, 0xF9C4, 0xE9CC, 0xF9C5, 0xE9F7, 0xF9C6, 0xEAC1, 0xF9C7, 0xEAE5, 0xF9C8, 0xEAF4, 0xF9C9, 0xEAF7, 0xF9CA, 0xEAFC, 0xF9CB, 0xEAFE, 0xF9CC, 0xEBA4, 0xF9CD, 0xEBA7, 0xF9CE, 0xEBA9, 0xF9CF, 0xEBAA, 0xF9D0, 0xEBBA, 0xF9D1, 0xEBBB, 0xF9D2, 0xEBBD, 0xF9D3, 0xEBC1, 0xF9D4, 0xEBC2, 0xF9D5, 0xEBC6, 0xF9D6, 0xEBC7, 0xF9D7, 0xEBCC, 0xF9D8, 0xEBCF, 0xF9D9, 0xEBD0, 0xF9DA, 0xEBD1, 0xF9DB, 0xEBD2, 0xF9DC, 0xEBD8, 0xF9DD, 0xECA6, 0xF9DE, 0xECA7, 0xF9DF, 0xECAA, 0xF9E0, 0xECAF, 0xF9E1, 0xECB0, 0xF9E2, 0xECB1, 0xF9E3, 0xECB2, 0xF9E4, 0xECB5, 0xF9E5, 0xECB8, 0xF9E6, 0xECBA, 0xF9E7, 0xECC0, 0xF9E8, 0xECC1, 0xF9E9, 0xECC5, 0xF9EA, 0xECC6, 0xF9EB, 0xECC9, 0xF9EC, 0xECCA, 0xF9ED, 0xECD5, 0xF9EE, 0xECDD, 0xF9EF, 0xECDE, 0xF9F0, 0xECE1, 0xF9F1, 0xECE4, 0xF9F2, 0xECE7, 0xF9F3, 0xECE8, 0xF9F4, 0xECF7, 0xF9F5, 0xECF8, 0xF9F6, 0xECFA, 0xF9F7, 0xEDA1, 0xF9F8, 0xEDA2, 0xF9F9, 0xEDA3, 0xF9FA, 0xEDEE, 0xF9FB, 0xEEDB, 0xF9FC, 0xF2BD, 0xF9FD, 0xF2FA, 0xF9FE, 0xF3B1, 0xF9FF, 0xF4A7, 0xFA00, 0xF4EE, 0xFA01, 0xF6F4, 0xFA02, 0xF6F6, 0xFA03, 0xF7B8, 0xFA04, 0xF7C8, 0xFA05, 0xF7D3, 0xFA06, 0xF8DB, 0xFA07, 0xF8F0, 0xFA08, 0xFAA1, 0xFA09, 0xFAA2, 0xFA0A, 0xFAE6, 0xFA0B, 0xFCA9, 0xFF01, 0xA3A1, 0xFF02, 0xA3A2, 0xFF03, 0xA3A3, 0xFF04, 0xA3A4, 0xFF05, 0xA3A5, 0xFF06, 0xA3A6, 0xFF07, 0xA3A7, 0xFF08, 0xA3A8, 0xFF09, 0xA3A9, 0xFF0A, 0xA3AA, 0xFF0B, 0xA3AB, 0xFF0C, 0xA3AC, 0xFF0D, 0xA3AD, 0xFF0E, 0xA3AE, 0xFF0F, 0xA3AF, 0xFF10, 0xA3B0, 0xFF11, 0xA3B1, 0xFF12, 0xA3B2, 0xFF13, 0xA3B3, 0xFF14, 0xA3B4, 0xFF15, 0xA3B5, 0xFF16, 0xA3B6, 0xFF17, 0xA3B7, 0xFF18, 0xA3B8, 0xFF19, 0xA3B9, 0xFF1A, 0xA3BA, 0xFF1B, 0xA3BB, 0xFF1C, 0xA3BC, 0xFF1D, 0xA3BD, 0xFF1E, 0xA3BE, 0xFF1F, 0xA3BF, 0xFF20, 0xA3C0, 0xFF21, 0xA3C1, 0xFF22, 0xA3C2, 0xFF23, 0xA3C3, 0xFF24, 0xA3C4, 0xFF25, 0xA3C5, 0xFF26, 0xA3C6, 0xFF27, 0xA3C7, 0xFF28, 0xA3C8, 0xFF29, 0xA3C9, 0xFF2A, 0xA3CA, 0xFF2B, 0xA3CB, 0xFF2C, 0xA3CC, 0xFF2D, 0xA3CD, 0xFF2E, 0xA3CE, 0xFF2F, 0xA3CF, 0xFF30, 0xA3D0, 0xFF31, 0xA3D1, 0xFF32, 0xA3D2, 0xFF33, 0xA3D3, 0xFF34, 0xA3D4, 0xFF35, 0xA3D5, 0xFF36, 0xA3D6, 0xFF37, 0xA3D7, 0xFF38, 0xA3D8, 0xFF39, 0xA3D9, 0xFF3A, 0xA3DA, 0xFF3B, 0xA3DB, 0xFF3C, 0xA1AC, 0xFF3D, 0xA3DD, 0xFF3E, 0xA3DE, 0xFF3F, 0xA3DF, 0xFF40, 0xA3E0, 0xFF41, 0xA3E1, 0xFF42, 0xA3E2, 0xFF43, 0xA3E3, 0xFF44, 0xA3E4, 0xFF45, 0xA3E5, 0xFF46, 0xA3E6, 0xFF47, 0xA3E7, 0xFF48, 0xA3E8, 0xFF49, 0xA3E9, 0xFF4A, 0xA3EA, 0xFF4B, 0xA3EB, 0xFF4C, 0xA3EC, 0xFF4D, 0xA3ED, 0xFF4E, 0xA3EE, 0xFF4F, 0xA3EF, 0xFF50, 0xA3F0, 0xFF51, 0xA3F1, 0xFF52, 0xA3F2, 0xFF53, 0xA3F3, 0xFF54, 0xA3F4, 0xFF55, 0xA3F5, 0xFF56, 0xA3F6, 0xFF57, 0xA3F7, 0xFF58, 0xA3F8, 0xFF59, 0xA3F9, 0xFF5A, 0xA3FA, 0xFF5B, 0xA3FB, 0xFF5C, 0xA3FC, 0xFF5D, 0xA3FD, 0xFF5E, 0xA2A6, 0xFFE0, 0xA1CB, 0xFFE1, 0xA1CC, 0xFFE2, 0xA1FE, 0xFFE3, 0xA3FE, 0xFFE5, 0xA1CD, 0xFFE6, 0xA3DC, 0, 0 }; static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ 0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E, 0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25, 0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32, 0x8159, 0xAC33, 0x815A, 0xAC34, 0x8161, 0xAC35, 0x8162, 0xAC36, 0x8163, 0xAC37, 0x8164, 0xAC3A, 0x8165, 0xAC3B, 0x8166, 0xAC3D, 0x8167, 0xAC3E, 0x8168, 0xAC3F, 0x8169, 0xAC41, 0x816A, 0xAC42, 0x816B, 0xAC43, 0x816C, 0xAC44, 0x816D, 0xAC45, 0x816E, 0xAC46, 0x816F, 0xAC47, 0x8170, 0xAC48, 0x8171, 0xAC49, 0x8172, 0xAC4A, 0x8173, 0xAC4C, 0x8174, 0xAC4E, 0x8175, 0xAC4F, 0x8176, 0xAC50, 0x8177, 0xAC51, 0x8178, 0xAC52, 0x8179, 0xAC53, 0x817A, 0xAC55, 0x8181, 0xAC56, 0x8182, 0xAC57, 0x8183, 0xAC59, 0x8184, 0xAC5A, 0x8185, 0xAC5B, 0x8186, 0xAC5D, 0x8187, 0xAC5E, 0x8188, 0xAC5F, 0x8189, 0xAC60, 0x818A, 0xAC61, 0x818B, 0xAC62, 0x818C, 0xAC63, 0x818D, 0xAC64, 0x818E, 0xAC65, 0x818F, 0xAC66, 0x8190, 0xAC67, 0x8191, 0xAC68, 0x8192, 0xAC69, 0x8193, 0xAC6A, 0x8194, 0xAC6B, 0x8195, 0xAC6C, 0x8196, 0xAC6D, 0x8197, 0xAC6E, 0x8198, 0xAC6F, 0x8199, 0xAC72, 0x819A, 0xAC73, 0x819B, 0xAC75, 0x819C, 0xAC76, 0x819D, 0xAC79, 0x819E, 0xAC7B, 0x819F, 0xAC7C, 0x81A0, 0xAC7D, 0x81A1, 0xAC7E, 0x81A2, 0xAC7F, 0x81A3, 0xAC82, 0x81A4, 0xAC87, 0x81A5, 0xAC88, 0x81A6, 0xAC8D, 0x81A7, 0xAC8E, 0x81A8, 0xAC8F, 0x81A9, 0xAC91, 0x81AA, 0xAC92, 0x81AB, 0xAC93, 0x81AC, 0xAC95, 0x81AD, 0xAC96, 0x81AE, 0xAC97, 0x81AF, 0xAC98, 0x81B0, 0xAC99, 0x81B1, 0xAC9A, 0x81B2, 0xAC9B, 0x81B3, 0xAC9E, 0x81B4, 0xACA2, 0x81B5, 0xACA3, 0x81B6, 0xACA4, 0x81B7, 0xACA5, 0x81B8, 0xACA6, 0x81B9, 0xACA7, 0x81BA, 0xACAB, 0x81BB, 0xACAD, 0x81BC, 0xACAE, 0x81BD, 0xACB1, 0x81BE, 0xACB2, 0x81BF, 0xACB3, 0x81C0, 0xACB4, 0x81C1, 0xACB5, 0x81C2, 0xACB6, 0x81C3, 0xACB7, 0x81C4, 0xACBA, 0x81C5, 0xACBE, 0x81C6, 0xACBF, 0x81C7, 0xACC0, 0x81C8, 0xACC2, 0x81C9, 0xACC3, 0x81CA, 0xACC5, 0x81CB, 0xACC6, 0x81CC, 0xACC7, 0x81CD, 0xACC9, 0x81CE, 0xACCA, 0x81CF, 0xACCB, 0x81D0, 0xACCD, 0x81D1, 0xACCE, 0x81D2, 0xACCF, 0x81D3, 0xACD0, 0x81D4, 0xACD1, 0x81D5, 0xACD2, 0x81D6, 0xACD3, 0x81D7, 0xACD4, 0x81D8, 0xACD6, 0x81D9, 0xACD8, 0x81DA, 0xACD9, 0x81DB, 0xACDA, 0x81DC, 0xACDB, 0x81DD, 0xACDC, 0x81DE, 0xACDD, 0x81DF, 0xACDE, 0x81E0, 0xACDF, 0x81E1, 0xACE2, 0x81E2, 0xACE3, 0x81E3, 0xACE5, 0x81E4, 0xACE6, 0x81E5, 0xACE9, 0x81E6, 0xACEB, 0x81E7, 0xACED, 0x81E8, 0xACEE, 0x81E9, 0xACF2, 0x81EA, 0xACF4, 0x81EB, 0xACF7, 0x81EC, 0xACF8, 0x81ED, 0xACF9, 0x81EE, 0xACFA, 0x81EF, 0xACFB, 0x81F0, 0xACFE, 0x81F1, 0xACFF, 0x81F2, 0xAD01, 0x81F3, 0xAD02, 0x81F4, 0xAD03, 0x81F5, 0xAD05, 0x81F6, 0xAD07, 0x81F7, 0xAD08, 0x81F8, 0xAD09, 0x81F9, 0xAD0A, 0x81FA, 0xAD0B, 0x81FB, 0xAD0E, 0x81FC, 0xAD10, 0x81FD, 0xAD12, 0x81FE, 0xAD13, 0x8241, 0xAD14, 0x8242, 0xAD15, 0x8243, 0xAD16, 0x8244, 0xAD17, 0x8245, 0xAD19, 0x8246, 0xAD1A, 0x8247, 0xAD1B, 0x8248, 0xAD1D, 0x8249, 0xAD1E, 0x824A, 0xAD1F, 0x824B, 0xAD21, 0x824C, 0xAD22, 0x824D, 0xAD23, 0x824E, 0xAD24, 0x824F, 0xAD25, 0x8250, 0xAD26, 0x8251, 0xAD27, 0x8252, 0xAD28, 0x8253, 0xAD2A, 0x8254, 0xAD2B, 0x8255, 0xAD2E, 0x8256, 0xAD2F, 0x8257, 0xAD30, 0x8258, 0xAD31, 0x8259, 0xAD32, 0x825A, 0xAD33, 0x8261, 0xAD36, 0x8262, 0xAD37, 0x8263, 0xAD39, 0x8264, 0xAD3A, 0x8265, 0xAD3B, 0x8266, 0xAD3D, 0x8267, 0xAD3E, 0x8268, 0xAD3F, 0x8269, 0xAD40, 0x826A, 0xAD41, 0x826B, 0xAD42, 0x826C, 0xAD43, 0x826D, 0xAD46, 0x826E, 0xAD48, 0x826F, 0xAD4A, 0x8270, 0xAD4B, 0x8271, 0xAD4C, 0x8272, 0xAD4D, 0x8273, 0xAD4E, 0x8274, 0xAD4F, 0x8275, 0xAD51, 0x8276, 0xAD52, 0x8277, 0xAD53, 0x8278, 0xAD55, 0x8279, 0xAD56, 0x827A, 0xAD57, 0x8281, 0xAD59, 0x8282, 0xAD5A, 0x8283, 0xAD5B, 0x8284, 0xAD5C, 0x8285, 0xAD5D, 0x8286, 0xAD5E, 0x8287, 0xAD5F, 0x8288, 0xAD60, 0x8289, 0xAD62, 0x828A, 0xAD64, 0x828B, 0xAD65, 0x828C, 0xAD66, 0x828D, 0xAD67, 0x828E, 0xAD68, 0x828F, 0xAD69, 0x8290, 0xAD6A, 0x8291, 0xAD6B, 0x8292, 0xAD6E, 0x8293, 0xAD6F, 0x8294, 0xAD71, 0x8295, 0xAD72, 0x8296, 0xAD77, 0x8297, 0xAD78, 0x8298, 0xAD79, 0x8299, 0xAD7A, 0x829A, 0xAD7E, 0x829B, 0xAD80, 0x829C, 0xAD83, 0x829D, 0xAD84, 0x829E, 0xAD85, 0x829F, 0xAD86, 0x82A0, 0xAD87, 0x82A1, 0xAD8A, 0x82A2, 0xAD8B, 0x82A3, 0xAD8D, 0x82A4, 0xAD8E, 0x82A5, 0xAD8F, 0x82A6, 0xAD91, 0x82A7, 0xAD92, 0x82A8, 0xAD93, 0x82A9, 0xAD94, 0x82AA, 0xAD95, 0x82AB, 0xAD96, 0x82AC, 0xAD97, 0x82AD, 0xAD98, 0x82AE, 0xAD99, 0x82AF, 0xAD9A, 0x82B0, 0xAD9B, 0x82B1, 0xAD9E, 0x82B2, 0xAD9F, 0x82B3, 0xADA0, 0x82B4, 0xADA1, 0x82B5, 0xADA2, 0x82B6, 0xADA3, 0x82B7, 0xADA5, 0x82B8, 0xADA6, 0x82B9, 0xADA7, 0x82BA, 0xADA8, 0x82BB, 0xADA9, 0x82BC, 0xADAA, 0x82BD, 0xADAB, 0x82BE, 0xADAC, 0x82BF, 0xADAD, 0x82C0, 0xADAE, 0x82C1, 0xADAF, 0x82C2, 0xADB0, 0x82C3, 0xADB1, 0x82C4, 0xADB2, 0x82C5, 0xADB3, 0x82C6, 0xADB4, 0x82C7, 0xADB5, 0x82C8, 0xADB6, 0x82C9, 0xADB8, 0x82CA, 0xADB9, 0x82CB, 0xADBA, 0x82CC, 0xADBB, 0x82CD, 0xADBC, 0x82CE, 0xADBD, 0x82CF, 0xADBE, 0x82D0, 0xADBF, 0x82D1, 0xADC2, 0x82D2, 0xADC3, 0x82D3, 0xADC5, 0x82D4, 0xADC6, 0x82D5, 0xADC7, 0x82D6, 0xADC9, 0x82D7, 0xADCA, 0x82D8, 0xADCB, 0x82D9, 0xADCC, 0x82DA, 0xADCD, 0x82DB, 0xADCE, 0x82DC, 0xADCF, 0x82DD, 0xADD2, 0x82DE, 0xADD4, 0x82DF, 0xADD5, 0x82E0, 0xADD6, 0x82E1, 0xADD7, 0x82E2, 0xADD8, 0x82E3, 0xADD9, 0x82E4, 0xADDA, 0x82E5, 0xADDB, 0x82E6, 0xADDD, 0x82E7, 0xADDE, 0x82E8, 0xADDF, 0x82E9, 0xADE1, 0x82EA, 0xADE2, 0x82EB, 0xADE3, 0x82EC, 0xADE5, 0x82ED, 0xADE6, 0x82EE, 0xADE7, 0x82EF, 0xADE8, 0x82F0, 0xADE9, 0x82F1, 0xADEA, 0x82F2, 0xADEB, 0x82F3, 0xADEC, 0x82F4, 0xADED, 0x82F5, 0xADEE, 0x82F6, 0xADEF, 0x82F7, 0xADF0, 0x82F8, 0xADF1, 0x82F9, 0xADF2, 0x82FA, 0xADF3, 0x82FB, 0xADF4, 0x82FC, 0xADF5, 0x82FD, 0xADF6, 0x82FE, 0xADF7, 0x8341, 0xADFA, 0x8342, 0xADFB, 0x8343, 0xADFD, 0x8344, 0xADFE, 0x8345, 0xAE02, 0x8346, 0xAE03, 0x8347, 0xAE04, 0x8348, 0xAE05, 0x8349, 0xAE06, 0x834A, 0xAE07, 0x834B, 0xAE0A, 0x834C, 0xAE0C, 0x834D, 0xAE0E, 0x834E, 0xAE0F, 0x834F, 0xAE10, 0x8350, 0xAE11, 0x8351, 0xAE12, 0x8352, 0xAE13, 0x8353, 0xAE15, 0x8354, 0xAE16, 0x8355, 0xAE17, 0x8356, 0xAE18, 0x8357, 0xAE19, 0x8358, 0xAE1A, 0x8359, 0xAE1B, 0x835A, 0xAE1C, 0x8361, 0xAE1D, 0x8362, 0xAE1E, 0x8363, 0xAE1F, 0x8364, 0xAE20, 0x8365, 0xAE21, 0x8366, 0xAE22, 0x8367, 0xAE23, 0x8368, 0xAE24, 0x8369, 0xAE25, 0x836A, 0xAE26, 0x836B, 0xAE27, 0x836C, 0xAE28, 0x836D, 0xAE29, 0x836E, 0xAE2A, 0x836F, 0xAE2B, 0x8370, 0xAE2C, 0x8371, 0xAE2D, 0x8372, 0xAE2E, 0x8373, 0xAE2F, 0x8374, 0xAE32, 0x8375, 0xAE33, 0x8376, 0xAE35, 0x8377, 0xAE36, 0x8378, 0xAE39, 0x8379, 0xAE3B, 0x837A, 0xAE3C, 0x8381, 0xAE3D, 0x8382, 0xAE3E, 0x8383, 0xAE3F, 0x8384, 0xAE42, 0x8385, 0xAE44, 0x8386, 0xAE47, 0x8387, 0xAE48, 0x8388, 0xAE49, 0x8389, 0xAE4B, 0x838A, 0xAE4F, 0x838B, 0xAE51, 0x838C, 0xAE52, 0x838D, 0xAE53, 0x838E, 0xAE55, 0x838F, 0xAE57, 0x8390, 0xAE58, 0x8391, 0xAE59, 0x8392, 0xAE5A, 0x8393, 0xAE5B, 0x8394, 0xAE5E, 0x8395, 0xAE62, 0x8396, 0xAE63, 0x8397, 0xAE64, 0x8398, 0xAE66, 0x8399, 0xAE67, 0x839A, 0xAE6A, 0x839B, 0xAE6B, 0x839C, 0xAE6D, 0x839D, 0xAE6E, 0x839E, 0xAE6F, 0x839F, 0xAE71, 0x83A0, 0xAE72, 0x83A1, 0xAE73, 0x83A2, 0xAE74, 0x83A3, 0xAE75, 0x83A4, 0xAE76, 0x83A5, 0xAE77, 0x83A6, 0xAE7A, 0x83A7, 0xAE7E, 0x83A8, 0xAE7F, 0x83A9, 0xAE80, 0x83AA, 0xAE81, 0x83AB, 0xAE82, 0x83AC, 0xAE83, 0x83AD, 0xAE86, 0x83AE, 0xAE87, 0x83AF, 0xAE88, 0x83B0, 0xAE89, 0x83B1, 0xAE8A, 0x83B2, 0xAE8B, 0x83B3, 0xAE8D, 0x83B4, 0xAE8E, 0x83B5, 0xAE8F, 0x83B6, 0xAE90, 0x83B7, 0xAE91, 0x83B8, 0xAE92, 0x83B9, 0xAE93, 0x83BA, 0xAE94, 0x83BB, 0xAE95, 0x83BC, 0xAE96, 0x83BD, 0xAE97, 0x83BE, 0xAE98, 0x83BF, 0xAE99, 0x83C0, 0xAE9A, 0x83C1, 0xAE9B, 0x83C2, 0xAE9C, 0x83C3, 0xAE9D, 0x83C4, 0xAE9E, 0x83C5, 0xAE9F, 0x83C6, 0xAEA0, 0x83C7, 0xAEA1, 0x83C8, 0xAEA2, 0x83C9, 0xAEA3, 0x83CA, 0xAEA4, 0x83CB, 0xAEA5, 0x83CC, 0xAEA6, 0x83CD, 0xAEA7, 0x83CE, 0xAEA8, 0x83CF, 0xAEA9, 0x83D0, 0xAEAA, 0x83D1, 0xAEAB, 0x83D2, 0xAEAC, 0x83D3, 0xAEAD, 0x83D4, 0xAEAE, 0x83D5, 0xAEAF, 0x83D6, 0xAEB0, 0x83D7, 0xAEB1, 0x83D8, 0xAEB2, 0x83D9, 0xAEB3, 0x83DA, 0xAEB4, 0x83DB, 0xAEB5, 0x83DC, 0xAEB6, 0x83DD, 0xAEB7, 0x83DE, 0xAEB8, 0x83DF, 0xAEB9, 0x83E0, 0xAEBA, 0x83E1, 0xAEBB, 0x83E2, 0xAEBF, 0x83E3, 0xAEC1, 0x83E4, 0xAEC2, 0x83E5, 0xAEC3, 0x83E6, 0xAEC5, 0x83E7, 0xAEC6, 0x83E8, 0xAEC7, 0x83E9, 0xAEC8, 0x83EA, 0xAEC9, 0x83EB, 0xAECA, 0x83EC, 0xAECB, 0x83ED, 0xAECE, 0x83EE, 0xAED2, 0x83EF, 0xAED3, 0x83F0, 0xAED4, 0x83F1, 0xAED5, 0x83F2, 0xAED6, 0x83F3, 0xAED7, 0x83F4, 0xAEDA, 0x83F5, 0xAEDB, 0x83F6, 0xAEDD, 0x83F7, 0xAEDE, 0x83F8, 0xAEDF, 0x83F9, 0xAEE0, 0x83FA, 0xAEE1, 0x83FB, 0xAEE2, 0x83FC, 0xAEE3, 0x83FD, 0xAEE4, 0x83FE, 0xAEE5, 0x8441, 0xAEE6, 0x8442, 0xAEE7, 0x8443, 0xAEE9, 0x8444, 0xAEEA, 0x8445, 0xAEEC, 0x8446, 0xAEEE, 0x8447, 0xAEEF, 0x8448, 0xAEF0, 0x8449, 0xAEF1, 0x844A, 0xAEF2, 0x844B, 0xAEF3, 0x844C, 0xAEF5, 0x844D, 0xAEF6, 0x844E, 0xAEF7, 0x844F, 0xAEF9, 0x8450, 0xAEFA, 0x8451, 0xAEFB, 0x8452, 0xAEFD, 0x8453, 0xAEFE, 0x8454, 0xAEFF, 0x8455, 0xAF00, 0x8456, 0xAF01, 0x8457, 0xAF02, 0x8458, 0xAF03, 0x8459, 0xAF04, 0x845A, 0xAF05, 0x8461, 0xAF06, 0x8462, 0xAF09, 0x8463, 0xAF0A, 0x8464, 0xAF0B, 0x8465, 0xAF0C, 0x8466, 0xAF0E, 0x8467, 0xAF0F, 0x8468, 0xAF11, 0x8469, 0xAF12, 0x846A, 0xAF13, 0x846B, 0xAF14, 0x846C, 0xAF15, 0x846D, 0xAF16, 0x846E, 0xAF17, 0x846F, 0xAF18, 0x8470, 0xAF19, 0x8471, 0xAF1A, 0x8472, 0xAF1B, 0x8473, 0xAF1C, 0x8474, 0xAF1D, 0x8475, 0xAF1E, 0x8476, 0xAF1F, 0x8477, 0xAF20, 0x8478, 0xAF21, 0x8479, 0xAF22, 0x847A, 0xAF23, 0x8481, 0xAF24, 0x8482, 0xAF25, 0x8483, 0xAF26, 0x8484, 0xAF27, 0x8485, 0xAF28, 0x8486, 0xAF29, 0x8487, 0xAF2A, 0x8488, 0xAF2B, 0x8489, 0xAF2E, 0x848A, 0xAF2F, 0x848B, 0xAF31, 0x848C, 0xAF33, 0x848D, 0xAF35, 0x848E, 0xAF36, 0x848F, 0xAF37, 0x8490, 0xAF38, 0x8491, 0xAF39, 0x8492, 0xAF3A, 0x8493, 0xAF3B, 0x8494, 0xAF3E, 0x8495, 0xAF40, 0x8496, 0xAF44, 0x8497, 0xAF45, 0x8498, 0xAF46, 0x8499, 0xAF47, 0x849A, 0xAF4A, 0x849B, 0xAF4B, 0x849C, 0xAF4C, 0x849D, 0xAF4D, 0x849E, 0xAF4E, 0x849F, 0xAF4F, 0x84A0, 0xAF51, 0x84A1, 0xAF52, 0x84A2, 0xAF53, 0x84A3, 0xAF54, 0x84A4, 0xAF55, 0x84A5, 0xAF56, 0x84A6, 0xAF57, 0x84A7, 0xAF58, 0x84A8, 0xAF59, 0x84A9, 0xAF5A, 0x84AA, 0xAF5B, 0x84AB, 0xAF5E, 0x84AC, 0xAF5F, 0x84AD, 0xAF60, 0x84AE, 0xAF61, 0x84AF, 0xAF62, 0x84B0, 0xAF63, 0x84B1, 0xAF66, 0x84B2, 0xAF67, 0x84B3, 0xAF68, 0x84B4, 0xAF69, 0x84B5, 0xAF6A, 0x84B6, 0xAF6B, 0x84B7, 0xAF6C, 0x84B8, 0xAF6D, 0x84B9, 0xAF6E, 0x84BA, 0xAF6F, 0x84BB, 0xAF70, 0x84BC, 0xAF71, 0x84BD, 0xAF72, 0x84BE, 0xAF73, 0x84BF, 0xAF74, 0x84C0, 0xAF75, 0x84C1, 0xAF76, 0x84C2, 0xAF77, 0x84C3, 0xAF78, 0x84C4, 0xAF7A, 0x84C5, 0xAF7B, 0x84C6, 0xAF7C, 0x84C7, 0xAF7D, 0x84C8, 0xAF7E, 0x84C9, 0xAF7F, 0x84CA, 0xAF81, 0x84CB, 0xAF82, 0x84CC, 0xAF83, 0x84CD, 0xAF85, 0x84CE, 0xAF86, 0x84CF, 0xAF87, 0x84D0, 0xAF89, 0x84D1, 0xAF8A, 0x84D2, 0xAF8B, 0x84D3, 0xAF8C, 0x84D4, 0xAF8D, 0x84D5, 0xAF8E, 0x84D6, 0xAF8F, 0x84D7, 0xAF92, 0x84D8, 0xAF93, 0x84D9, 0xAF94, 0x84DA, 0xAF96, 0x84DB, 0xAF97, 0x84DC, 0xAF98, 0x84DD, 0xAF99, 0x84DE, 0xAF9A, 0x84DF, 0xAF9B, 0x84E0, 0xAF9D, 0x84E1, 0xAF9E, 0x84E2, 0xAF9F, 0x84E3, 0xAFA0, 0x84E4, 0xAFA1, 0x84E5, 0xAFA2, 0x84E6, 0xAFA3, 0x84E7, 0xAFA4, 0x84E8, 0xAFA5, 0x84E9, 0xAFA6, 0x84EA, 0xAFA7, 0x84EB, 0xAFA8, 0x84EC, 0xAFA9, 0x84ED, 0xAFAA, 0x84EE, 0xAFAB, 0x84EF, 0xAFAC, 0x84F0, 0xAFAD, 0x84F1, 0xAFAE, 0x84F2, 0xAFAF, 0x84F3, 0xAFB0, 0x84F4, 0xAFB1, 0x84F5, 0xAFB2, 0x84F6, 0xAFB3, 0x84F7, 0xAFB4, 0x84F8, 0xAFB5, 0x84F9, 0xAFB6, 0x84FA, 0xAFB7, 0x84FB, 0xAFBA, 0x84FC, 0xAFBB, 0x84FD, 0xAFBD, 0x84FE, 0xAFBE, 0x8541, 0xAFBF, 0x8542, 0xAFC1, 0x8543, 0xAFC2, 0x8544, 0xAFC3, 0x8545, 0xAFC4, 0x8546, 0xAFC5, 0x8547, 0xAFC6, 0x8548, 0xAFCA, 0x8549, 0xAFCC, 0x854A, 0xAFCF, 0x854B, 0xAFD0, 0x854C, 0xAFD1, 0x854D, 0xAFD2, 0x854E, 0xAFD3, 0x854F, 0xAFD5, 0x8550, 0xAFD6, 0x8551, 0xAFD7, 0x8552, 0xAFD8, 0x8553, 0xAFD9, 0x8554, 0xAFDA, 0x8555, 0xAFDB, 0x8556, 0xAFDD, 0x8557, 0xAFDE, 0x8558, 0xAFDF, 0x8559, 0xAFE0, 0x855A, 0xAFE1, 0x8561, 0xAFE2, 0x8562, 0xAFE3, 0x8563, 0xAFE4, 0x8564, 0xAFE5, 0x8565, 0xAFE6, 0x8566, 0xAFE7, 0x8567, 0xAFEA, 0x8568, 0xAFEB, 0x8569, 0xAFEC, 0x856A, 0xAFED, 0x856B, 0xAFEE, 0x856C, 0xAFEF, 0x856D, 0xAFF2, 0x856E, 0xAFF3, 0x856F, 0xAFF5, 0x8570, 0xAFF6, 0x8571, 0xAFF7, 0x8572, 0xAFF9, 0x8573, 0xAFFA, 0x8574, 0xAFFB, 0x8575, 0xAFFC, 0x8576, 0xAFFD, 0x8577, 0xAFFE, 0x8578, 0xAFFF, 0x8579, 0xB002, 0x857A, 0xB003, 0x8581, 0xB005, 0x8582, 0xB006, 0x8583, 0xB007, 0x8584, 0xB008, 0x8585, 0xB009, 0x8586, 0xB00A, 0x8587, 0xB00B, 0x8588, 0xB00D, 0x8589, 0xB00E, 0x858A, 0xB00F, 0x858B, 0xB011, 0x858C, 0xB012, 0x858D, 0xB013, 0x858E, 0xB015, 0x858F, 0xB016, 0x8590, 0xB017, 0x8591, 0xB018, 0x8592, 0xB019, 0x8593, 0xB01A, 0x8594, 0xB01B, 0x8595, 0xB01E, 0x8596, 0xB01F, 0x8597, 0xB020, 0x8598, 0xB021, 0x8599, 0xB022, 0x859A, 0xB023, 0x859B, 0xB024, 0x859C, 0xB025, 0x859D, 0xB026, 0x859E, 0xB027, 0x859F, 0xB029, 0x85A0, 0xB02A, 0x85A1, 0xB02B, 0x85A2, 0xB02C, 0x85A3, 0xB02D, 0x85A4, 0xB02E, 0x85A5, 0xB02F, 0x85A6, 0xB030, 0x85A7, 0xB031, 0x85A8, 0xB032, 0x85A9, 0xB033, 0x85AA, 0xB034, 0x85AB, 0xB035, 0x85AC, 0xB036, 0x85AD, 0xB037, 0x85AE, 0xB038, 0x85AF, 0xB039, 0x85B0, 0xB03A, 0x85B1, 0xB03B, 0x85B2, 0xB03C, 0x85B3, 0xB03D, 0x85B4, 0xB03E, 0x85B5, 0xB03F, 0x85B6, 0xB040, 0x85B7, 0xB041, 0x85B8, 0xB042, 0x85B9, 0xB043, 0x85BA, 0xB046, 0x85BB, 0xB047, 0x85BC, 0xB049, 0x85BD, 0xB04B, 0x85BE, 0xB04D, 0x85BF, 0xB04F, 0x85C0, 0xB050, 0x85C1, 0xB051, 0x85C2, 0xB052, 0x85C3, 0xB056, 0x85C4, 0xB058, 0x85C5, 0xB05A, 0x85C6, 0xB05B, 0x85C7, 0xB05C, 0x85C8, 0xB05E, 0x85C9, 0xB05F, 0x85CA, 0xB060, 0x85CB, 0xB061, 0x85CC, 0xB062, 0x85CD, 0xB063, 0x85CE, 0xB064, 0x85CF, 0xB065, 0x85D0, 0xB066, 0x85D1, 0xB067, 0x85D2, 0xB068, 0x85D3, 0xB069, 0x85D4, 0xB06A, 0x85D5, 0xB06B, 0x85D6, 0xB06C, 0x85D7, 0xB06D, 0x85D8, 0xB06E, 0x85D9, 0xB06F, 0x85DA, 0xB070, 0x85DB, 0xB071, 0x85DC, 0xB072, 0x85DD, 0xB073, 0x85DE, 0xB074, 0x85DF, 0xB075, 0x85E0, 0xB076, 0x85E1, 0xB077, 0x85E2, 0xB078, 0x85E3, 0xB079, 0x85E4, 0xB07A, 0x85E5, 0xB07B, 0x85E6, 0xB07E, 0x85E7, 0xB07F, 0x85E8, 0xB081, 0x85E9, 0xB082, 0x85EA, 0xB083, 0x85EB, 0xB085, 0x85EC, 0xB086, 0x85ED, 0xB087, 0x85EE, 0xB088, 0x85EF, 0xB089, 0x85F0, 0xB08A, 0x85F1, 0xB08B, 0x85F2, 0xB08E, 0x85F3, 0xB090, 0x85F4, 0xB092, 0x85F5, 0xB093, 0x85F6, 0xB094, 0x85F7, 0xB095, 0x85F8, 0xB096, 0x85F9, 0xB097, 0x85FA, 0xB09B, 0x85FB, 0xB09D, 0x85FC, 0xB09E, 0x85FD, 0xB0A3, 0x85FE, 0xB0A4, 0x8641, 0xB0A5, 0x8642, 0xB0A6, 0x8643, 0xB0A7, 0x8644, 0xB0AA, 0x8645, 0xB0B0, 0x8646, 0xB0B2, 0x8647, 0xB0B6, 0x8648, 0xB0B7, 0x8649, 0xB0B9, 0x864A, 0xB0BA, 0x864B, 0xB0BB, 0x864C, 0xB0BD, 0x864D, 0xB0BE, 0x864E, 0xB0BF, 0x864F, 0xB0C0, 0x8650, 0xB0C1, 0x8651, 0xB0C2, 0x8652, 0xB0C3, 0x8653, 0xB0C6, 0x8654, 0xB0CA, 0x8655, 0xB0CB, 0x8656, 0xB0CC, 0x8657, 0xB0CD, 0x8658, 0xB0CE, 0x8659, 0xB0CF, 0x865A, 0xB0D2, 0x8661, 0xB0D3, 0x8662, 0xB0D5, 0x8663, 0xB0D6, 0x8664, 0xB0D7, 0x8665, 0xB0D9, 0x8666, 0xB0DA, 0x8667, 0xB0DB, 0x8668, 0xB0DC, 0x8669, 0xB0DD, 0x866A, 0xB0DE, 0x866B, 0xB0DF, 0x866C, 0xB0E1, 0x866D, 0xB0E2, 0x866E, 0xB0E3, 0x866F, 0xB0E4, 0x8670, 0xB0E6, 0x8671, 0xB0E7, 0x8672, 0xB0E8, 0x8673, 0xB0E9, 0x8674, 0xB0EA, 0x8675, 0xB0EB, 0x8676, 0xB0EC, 0x8677, 0xB0ED, 0x8678, 0xB0EE, 0x8679, 0xB0EF, 0x867A, 0xB0F0, 0x8681, 0xB0F1, 0x8682, 0xB0F2, 0x8683, 0xB0F3, 0x8684, 0xB0F4, 0x8685, 0xB0F5, 0x8686, 0xB0F6, 0x8687, 0xB0F7, 0x8688, 0xB0F8, 0x8689, 0xB0F9, 0x868A, 0xB0FA, 0x868B, 0xB0FB, 0x868C, 0xB0FC, 0x868D, 0xB0FD, 0x868E, 0xB0FE, 0x868F, 0xB0FF, 0x8690, 0xB100, 0x8691, 0xB101, 0x8692, 0xB102, 0x8693, 0xB103, 0x8694, 0xB104, 0x8695, 0xB105, 0x8696, 0xB106, 0x8697, 0xB107, 0x8698, 0xB10A, 0x8699, 0xB10D, 0x869A, 0xB10E, 0x869B, 0xB10F, 0x869C, 0xB111, 0x869D, 0xB114, 0x869E, 0xB115, 0x869F, 0xB116, 0x86A0, 0xB117, 0x86A1, 0xB11A, 0x86A2, 0xB11E, 0x86A3, 0xB11F, 0x86A4, 0xB120, 0x86A5, 0xB121, 0x86A6, 0xB122, 0x86A7, 0xB126, 0x86A8, 0xB127, 0x86A9, 0xB129, 0x86AA, 0xB12A, 0x86AB, 0xB12B, 0x86AC, 0xB12D, 0x86AD, 0xB12E, 0x86AE, 0xB12F, 0x86AF, 0xB130, 0x86B0, 0xB131, 0x86B1, 0xB132, 0x86B2, 0xB133, 0x86B3, 0xB136, 0x86B4, 0xB13A, 0x86B5, 0xB13B, 0x86B6, 0xB13C, 0x86B7, 0xB13D, 0x86B8, 0xB13E, 0x86B9, 0xB13F, 0x86BA, 0xB142, 0x86BB, 0xB143, 0x86BC, 0xB145, 0x86BD, 0xB146, 0x86BE, 0xB147, 0x86BF, 0xB149, 0x86C0, 0xB14A, 0x86C1, 0xB14B, 0x86C2, 0xB14C, 0x86C3, 0xB14D, 0x86C4, 0xB14E, 0x86C5, 0xB14F, 0x86C6, 0xB152, 0x86C7, 0xB153, 0x86C8, 0xB156, 0x86C9, 0xB157, 0x86CA, 0xB159, 0x86CB, 0xB15A, 0x86CC, 0xB15B, 0x86CD, 0xB15D, 0x86CE, 0xB15E, 0x86CF, 0xB15F, 0x86D0, 0xB161, 0x86D1, 0xB162, 0x86D2, 0xB163, 0x86D3, 0xB164, 0x86D4, 0xB165, 0x86D5, 0xB166, 0x86D6, 0xB167, 0x86D7, 0xB168, 0x86D8, 0xB169, 0x86D9, 0xB16A, 0x86DA, 0xB16B, 0x86DB, 0xB16C, 0x86DC, 0xB16D, 0x86DD, 0xB16E, 0x86DE, 0xB16F, 0x86DF, 0xB170, 0x86E0, 0xB171, 0x86E1, 0xB172, 0x86E2, 0xB173, 0x86E3, 0xB174, 0x86E4, 0xB175, 0x86E5, 0xB176, 0x86E6, 0xB177, 0x86E7, 0xB17A, 0x86E8, 0xB17B, 0x86E9, 0xB17D, 0x86EA, 0xB17E, 0x86EB, 0xB17F, 0x86EC, 0xB181, 0x86ED, 0xB183, 0x86EE, 0xB184, 0x86EF, 0xB185, 0x86F0, 0xB186, 0x86F1, 0xB187, 0x86F2, 0xB18A, 0x86F3, 0xB18C, 0x86F4, 0xB18E, 0x86F5, 0xB18F, 0x86F6, 0xB190, 0x86F7, 0xB191, 0x86F8, 0xB195, 0x86F9, 0xB196, 0x86FA, 0xB197, 0x86FB, 0xB199, 0x86FC, 0xB19A, 0x86FD, 0xB19B, 0x86FE, 0xB19D, 0x8741, 0xB19E, 0x8742, 0xB19F, 0x8743, 0xB1A0, 0x8744, 0xB1A1, 0x8745, 0xB1A2, 0x8746, 0xB1A3, 0x8747, 0xB1A4, 0x8748, 0xB1A5, 0x8749, 0xB1A6, 0x874A, 0xB1A7, 0x874B, 0xB1A9, 0x874C, 0xB1AA, 0x874D, 0xB1AB, 0x874E, 0xB1AC, 0x874F, 0xB1AD, 0x8750, 0xB1AE, 0x8751, 0xB1AF, 0x8752, 0xB1B0, 0x8753, 0xB1B1, 0x8754, 0xB1B2, 0x8755, 0xB1B3, 0x8756, 0xB1B4, 0x8757, 0xB1B5, 0x8758, 0xB1B6, 0x8759, 0xB1B7, 0x875A, 0xB1B8, 0x8761, 0xB1B9, 0x8762, 0xB1BA, 0x8763, 0xB1BB, 0x8764, 0xB1BC, 0x8765, 0xB1BD, 0x8766, 0xB1BE, 0x8767, 0xB1BF, 0x8768, 0xB1C0, 0x8769, 0xB1C1, 0x876A, 0xB1C2, 0x876B, 0xB1C3, 0x876C, 0xB1C4, 0x876D, 0xB1C5, 0x876E, 0xB1C6, 0x876F, 0xB1C7, 0x8770, 0xB1C8, 0x8771, 0xB1C9, 0x8772, 0xB1CA, 0x8773, 0xB1CB, 0x8774, 0xB1CD, 0x8775, 0xB1CE, 0x8776, 0xB1CF, 0x8777, 0xB1D1, 0x8778, 0xB1D2, 0x8779, 0xB1D3, 0x877A, 0xB1D5, 0x8781, 0xB1D6, 0x8782, 0xB1D7, 0x8783, 0xB1D8, 0x8784, 0xB1D9, 0x8785, 0xB1DA, 0x8786, 0xB1DB, 0x8787, 0xB1DE, 0x8788, 0xB1E0, 0x8789, 0xB1E1, 0x878A, 0xB1E2, 0x878B, 0xB1E3, 0x878C, 0xB1E4, 0x878D, 0xB1E5, 0x878E, 0xB1E6, 0x878F, 0xB1E7, 0x8790, 0xB1EA, 0x8791, 0xB1EB, 0x8792, 0xB1ED, 0x8793, 0xB1EE, 0x8794, 0xB1EF, 0x8795, 0xB1F1, 0x8796, 0xB1F2, 0x8797, 0xB1F3, 0x8798, 0xB1F4, 0x8799, 0xB1F5, 0x879A, 0xB1F6, 0x879B, 0xB1F7, 0x879C, 0xB1F8, 0x879D, 0xB1FA, 0x879E, 0xB1FC, 0x879F, 0xB1FE, 0x87A0, 0xB1FF, 0x87A1, 0xB200, 0x87A2, 0xB201, 0x87A3, 0xB202, 0x87A4, 0xB203, 0x87A5, 0xB206, 0x87A6, 0xB207, 0x87A7, 0xB209, 0x87A8, 0xB20A, 0x87A9, 0xB20D, 0x87AA, 0xB20E, 0x87AB, 0xB20F, 0x87AC, 0xB210, 0x87AD, 0xB211, 0x87AE, 0xB212, 0x87AF, 0xB213, 0x87B0, 0xB216, 0x87B1, 0xB218, 0x87B2, 0xB21A, 0x87B3, 0xB21B, 0x87B4, 0xB21C, 0x87B5, 0xB21D, 0x87B6, 0xB21E, 0x87B7, 0xB21F, 0x87B8, 0xB221, 0x87B9, 0xB222, 0x87BA, 0xB223, 0x87BB, 0xB224, 0x87BC, 0xB225, 0x87BD, 0xB226, 0x87BE, 0xB227, 0x87BF, 0xB228, 0x87C0, 0xB229, 0x87C1, 0xB22A, 0x87C2, 0xB22B, 0x87C3, 0xB22C, 0x87C4, 0xB22D, 0x87C5, 0xB22E, 0x87C6, 0xB22F, 0x87C7, 0xB230, 0x87C8, 0xB231, 0x87C9, 0xB232, 0x87CA, 0xB233, 0x87CB, 0xB235, 0x87CC, 0xB236, 0x87CD, 0xB237, 0x87CE, 0xB238, 0x87CF, 0xB239, 0x87D0, 0xB23A, 0x87D1, 0xB23B, 0x87D2, 0xB23D, 0x87D3, 0xB23E, 0x87D4, 0xB23F, 0x87D5, 0xB240, 0x87D6, 0xB241, 0x87D7, 0xB242, 0x87D8, 0xB243, 0x87D9, 0xB244, 0x87DA, 0xB245, 0x87DB, 0xB246, 0x87DC, 0xB247, 0x87DD, 0xB248, 0x87DE, 0xB249, 0x87DF, 0xB24A, 0x87E0, 0xB24B, 0x87E1, 0xB24C, 0x87E2, 0xB24D, 0x87E3, 0xB24E, 0x87E4, 0xB24F, 0x87E5, 0xB250, 0x87E6, 0xB251, 0x87E7, 0xB252, 0x87E8, 0xB253, 0x87E9, 0xB254, 0x87EA, 0xB255, 0x87EB, 0xB256, 0x87EC, 0xB257, 0x87ED, 0xB259, 0x87EE, 0xB25A, 0x87EF, 0xB25B, 0x87F0, 0xB25D, 0x87F1, 0xB25E, 0x87F2, 0xB25F, 0x87F3, 0xB261, 0x87F4, 0xB262, 0x87F5, 0xB263, 0x87F6, 0xB264, 0x87F7, 0xB265, 0x87F8, 0xB266, 0x87F9, 0xB267, 0x87FA, 0xB26A, 0x87FB, 0xB26B, 0x87FC, 0xB26C, 0x87FD, 0xB26D, 0x87FE, 0xB26E, 0x8841, 0xB26F, 0x8842, 0xB270, 0x8843, 0xB271, 0x8844, 0xB272, 0x8845, 0xB273, 0x8846, 0xB276, 0x8847, 0xB277, 0x8848, 0xB278, 0x8849, 0xB279, 0x884A, 0xB27A, 0x884B, 0xB27B, 0x884C, 0xB27D, 0x884D, 0xB27E, 0x884E, 0xB27F, 0x884F, 0xB280, 0x8850, 0xB281, 0x8851, 0xB282, 0x8852, 0xB283, 0x8853, 0xB286, 0x8854, 0xB287, 0x8855, 0xB288, 0x8856, 0xB28A, 0x8857, 0xB28B, 0x8858, 0xB28C, 0x8859, 0xB28D, 0x885A, 0xB28E, 0x8861, 0xB28F, 0x8862, 0xB292, 0x8863, 0xB293, 0x8864, 0xB295, 0x8865, 0xB296, 0x8866, 0xB297, 0x8867, 0xB29B, 0x8868, 0xB29C, 0x8869, 0xB29D, 0x886A, 0xB29E, 0x886B, 0xB29F, 0x886C, 0xB2A2, 0x886D, 0xB2A4, 0x886E, 0xB2A7, 0x886F, 0xB2A8, 0x8870, 0xB2A9, 0x8871, 0xB2AB, 0x8872, 0xB2AD, 0x8873, 0xB2AE, 0x8874, 0xB2AF, 0x8875, 0xB2B1, 0x8876, 0xB2B2, 0x8877, 0xB2B3, 0x8878, 0xB2B5, 0x8879, 0xB2B6, 0x887A, 0xB2B7, 0x8881, 0xB2B8, 0x8882, 0xB2B9, 0x8883, 0xB2BA, 0x8884, 0xB2BB, 0x8885, 0xB2BC, 0x8886, 0xB2BD, 0x8887, 0xB2BE, 0x8888, 0xB2BF, 0x8889, 0xB2C0, 0x888A, 0xB2C1, 0x888B, 0xB2C2, 0x888C, 0xB2C3, 0x888D, 0xB2C4, 0x888E, 0xB2C5, 0x888F, 0xB2C6, 0x8890, 0xB2C7, 0x8891, 0xB2CA, 0x8892, 0xB2CB, 0x8893, 0xB2CD, 0x8894, 0xB2CE, 0x8895, 0xB2CF, 0x8896, 0xB2D1, 0x8897, 0xB2D3, 0x8898, 0xB2D4, 0x8899, 0xB2D5, 0x889A, 0xB2D6, 0x889B, 0xB2D7, 0x889C, 0xB2DA, 0x889D, 0xB2DC, 0x889E, 0xB2DE, 0x889F, 0xB2DF, 0x88A0, 0xB2E0, 0x88A1, 0xB2E1, 0x88A2, 0xB2E3, 0x88A3, 0xB2E7, 0x88A4, 0xB2E9, 0x88A5, 0xB2EA, 0x88A6, 0xB2F0, 0x88A7, 0xB2F1, 0x88A8, 0xB2F2, 0x88A9, 0xB2F6, 0x88AA, 0xB2FC, 0x88AB, 0xB2FD, 0x88AC, 0xB2FE, 0x88AD, 0xB302, 0x88AE, 0xB303, 0x88AF, 0xB305, 0x88B0, 0xB306, 0x88B1, 0xB307, 0x88B2, 0xB309, 0x88B3, 0xB30A, 0x88B4, 0xB30B, 0x88B5, 0xB30C, 0x88B6, 0xB30D, 0x88B7, 0xB30E, 0x88B8, 0xB30F, 0x88B9, 0xB312, 0x88BA, 0xB316, 0x88BB, 0xB317, 0x88BC, 0xB318, 0x88BD, 0xB319, 0x88BE, 0xB31A, 0x88BF, 0xB31B, 0x88C0, 0xB31D, 0x88C1, 0xB31E, 0x88C2, 0xB31F, 0x88C3, 0xB320, 0x88C4, 0xB321, 0x88C5, 0xB322, 0x88C6, 0xB323, 0x88C7, 0xB324, 0x88C8, 0xB325, 0x88C9, 0xB326, 0x88CA, 0xB327, 0x88CB, 0xB328, 0x88CC, 0xB329, 0x88CD, 0xB32A, 0x88CE, 0xB32B, 0x88CF, 0xB32C, 0x88D0, 0xB32D, 0x88D1, 0xB32E, 0x88D2, 0xB32F, 0x88D3, 0xB330, 0x88D4, 0xB331, 0x88D5, 0xB332, 0x88D6, 0xB333, 0x88D7, 0xB334, 0x88D8, 0xB335, 0x88D9, 0xB336, 0x88DA, 0xB337, 0x88DB, 0xB338, 0x88DC, 0xB339, 0x88DD, 0xB33A, 0x88DE, 0xB33B, 0x88DF, 0xB33C, 0x88E0, 0xB33D, 0x88E1, 0xB33E, 0x88E2, 0xB33F, 0x88E3, 0xB340, 0x88E4, 0xB341, 0x88E5, 0xB342, 0x88E6, 0xB343, 0x88E7, 0xB344, 0x88E8, 0xB345, 0x88E9, 0xB346, 0x88EA, 0xB347, 0x88EB, 0xB348, 0x88EC, 0xB349, 0x88ED, 0xB34A, 0x88EE, 0xB34B, 0x88EF, 0xB34C, 0x88F0, 0xB34D, 0x88F1, 0xB34E, 0x88F2, 0xB34F, 0x88F3, 0xB350, 0x88F4, 0xB351, 0x88F5, 0xB352, 0x88F6, 0xB353, 0x88F7, 0xB357, 0x88F8, 0xB359, 0x88F9, 0xB35A, 0x88FA, 0xB35D, 0x88FB, 0xB360, 0x88FC, 0xB361, 0x88FD, 0xB362, 0x88FE, 0xB363, 0x8941, 0xB366, 0x8942, 0xB368, 0x8943, 0xB36A, 0x8944, 0xB36C, 0x8945, 0xB36D, 0x8946, 0xB36F, 0x8947, 0xB372, 0x8948, 0xB373, 0x8949, 0xB375, 0x894A, 0xB376, 0x894B, 0xB377, 0x894C, 0xB379, 0x894D, 0xB37A, 0x894E, 0xB37B, 0x894F, 0xB37C, 0x8950, 0xB37D, 0x8951, 0xB37E, 0x8952, 0xB37F, 0x8953, 0xB382, 0x8954, 0xB386, 0x8955, 0xB387, 0x8956, 0xB388, 0x8957, 0xB389, 0x8958, 0xB38A, 0x8959, 0xB38B, 0x895A, 0xB38D, 0x8961, 0xB38E, 0x8962, 0xB38F, 0x8963, 0xB391, 0x8964, 0xB392, 0x8965, 0xB393, 0x8966, 0xB395, 0x8967, 0xB396, 0x8968, 0xB397, 0x8969, 0xB398, 0x896A, 0xB399, 0x896B, 0xB39A, 0x896C, 0xB39B, 0x896D, 0xB39C, 0x896E, 0xB39D, 0x896F, 0xB39E, 0x8970, 0xB39F, 0x8971, 0xB3A2, 0x8972, 0xB3A3, 0x8973, 0xB3A4, 0x8974, 0xB3A5, 0x8975, 0xB3A6, 0x8976, 0xB3A7, 0x8977, 0xB3A9, 0x8978, 0xB3AA, 0x8979, 0xB3AB, 0x897A, 0xB3AD, 0x8981, 0xB3AE, 0x8982, 0xB3AF, 0x8983, 0xB3B0, 0x8984, 0xB3B1, 0x8985, 0xB3B2, 0x8986, 0xB3B3, 0x8987, 0xB3B4, 0x8988, 0xB3B5, 0x8989, 0xB3B6, 0x898A, 0xB3B7, 0x898B, 0xB3B8, 0x898C, 0xB3B9, 0x898D, 0xB3BA, 0x898E, 0xB3BB, 0x898F, 0xB3BC, 0x8990, 0xB3BD, 0x8991, 0xB3BE, 0x8992, 0xB3BF, 0x8993, 0xB3C0, 0x8994, 0xB3C1, 0x8995, 0xB3C2, 0x8996, 0xB3C3, 0x8997, 0xB3C6, 0x8998, 0xB3C7, 0x8999, 0xB3C9, 0x899A, 0xB3CA, 0x899B, 0xB3CD, 0x899C, 0xB3CF, 0x899D, 0xB3D1, 0x899E, 0xB3D2, 0x899F, 0xB3D3, 0x89A0, 0xB3D6, 0x89A1, 0xB3D8, 0x89A2, 0xB3DA, 0x89A3, 0xB3DC, 0x89A4, 0xB3DE, 0x89A5, 0xB3DF, 0x89A6, 0xB3E1, 0x89A7, 0xB3E2, 0x89A8, 0xB3E3, 0x89A9, 0xB3E5, 0x89AA, 0xB3E6, 0x89AB, 0xB3E7, 0x89AC, 0xB3E9, 0x89AD, 0xB3EA, 0x89AE, 0xB3EB, 0x89AF, 0xB3EC, 0x89B0, 0xB3ED, 0x89B1, 0xB3EE, 0x89B2, 0xB3EF, 0x89B3, 0xB3F0, 0x89B4, 0xB3F1, 0x89B5, 0xB3F2, 0x89B6, 0xB3F3, 0x89B7, 0xB3F4, 0x89B8, 0xB3F5, 0x89B9, 0xB3F6, 0x89BA, 0xB3F7, 0x89BB, 0xB3F8, 0x89BC, 0xB3F9, 0x89BD, 0xB3FA, 0x89BE, 0xB3FB, 0x89BF, 0xB3FD, 0x89C0, 0xB3FE, 0x89C1, 0xB3FF, 0x89C2, 0xB400, 0x89C3, 0xB401, 0x89C4, 0xB402, 0x89C5, 0xB403, 0x89C6, 0xB404, 0x89C7, 0xB405, 0x89C8, 0xB406, 0x89C9, 0xB407, 0x89CA, 0xB408, 0x89CB, 0xB409, 0x89CC, 0xB40A, 0x89CD, 0xB40B, 0x89CE, 0xB40C, 0x89CF, 0xB40D, 0x89D0, 0xB40E, 0x89D1, 0xB40F, 0x89D2, 0xB411, 0x89D3, 0xB412, 0x89D4, 0xB413, 0x89D5, 0xB414, 0x89D6, 0xB415, 0x89D7, 0xB416, 0x89D8, 0xB417, 0x89D9, 0xB419, 0x89DA, 0xB41A, 0x89DB, 0xB41B, 0x89DC, 0xB41D, 0x89DD, 0xB41E, 0x89DE, 0xB41F, 0x89DF, 0xB421, 0x89E0, 0xB422, 0x89E1, 0xB423, 0x89E2, 0xB424, 0x89E3, 0xB425, 0x89E4, 0xB426, 0x89E5, 0xB427, 0x89E6, 0xB42A, 0x89E7, 0xB42C, 0x89E8, 0xB42D, 0x89E9, 0xB42E, 0x89EA, 0xB42F, 0x89EB, 0xB430, 0x89EC, 0xB431, 0x89ED, 0xB432, 0x89EE, 0xB433, 0x89EF, 0xB435, 0x89F0, 0xB436, 0x89F1, 0xB437, 0x89F2, 0xB438, 0x89F3, 0xB439, 0x89F4, 0xB43A, 0x89F5, 0xB43B, 0x89F6, 0xB43C, 0x89F7, 0xB43D, 0x89F8, 0xB43E, 0x89F9, 0xB43F, 0x89FA, 0xB440, 0x89FB, 0xB441, 0x89FC, 0xB442, 0x89FD, 0xB443, 0x89FE, 0xB444, 0x8A41, 0xB445, 0x8A42, 0xB446, 0x8A43, 0xB447, 0x8A44, 0xB448, 0x8A45, 0xB449, 0x8A46, 0xB44A, 0x8A47, 0xB44B, 0x8A48, 0xB44C, 0x8A49, 0xB44D, 0x8A4A, 0xB44E, 0x8A4B, 0xB44F, 0x8A4C, 0xB452, 0x8A4D, 0xB453, 0x8A4E, 0xB455, 0x8A4F, 0xB456, 0x8A50, 0xB457, 0x8A51, 0xB459, 0x8A52, 0xB45A, 0x8A53, 0xB45B, 0x8A54, 0xB45C, 0x8A55, 0xB45D, 0x8A56, 0xB45E, 0x8A57, 0xB45F, 0x8A58, 0xB462, 0x8A59, 0xB464, 0x8A5A, 0xB466, 0x8A61, 0xB467, 0x8A62, 0xB468, 0x8A63, 0xB469, 0x8A64, 0xB46A, 0x8A65, 0xB46B, 0x8A66, 0xB46D, 0x8A67, 0xB46E, 0x8A68, 0xB46F, 0x8A69, 0xB470, 0x8A6A, 0xB471, 0x8A6B, 0xB472, 0x8A6C, 0xB473, 0x8A6D, 0xB474, 0x8A6E, 0xB475, 0x8A6F, 0xB476, 0x8A70, 0xB477, 0x8A71, 0xB478, 0x8A72, 0xB479, 0x8A73, 0xB47A, 0x8A74, 0xB47B, 0x8A75, 0xB47C, 0x8A76, 0xB47D, 0x8A77, 0xB47E, 0x8A78, 0xB47F, 0x8A79, 0xB481, 0x8A7A, 0xB482, 0x8A81, 0xB483, 0x8A82, 0xB484, 0x8A83, 0xB485, 0x8A84, 0xB486, 0x8A85, 0xB487, 0x8A86, 0xB489, 0x8A87, 0xB48A, 0x8A88, 0xB48B, 0x8A89, 0xB48C, 0x8A8A, 0xB48D, 0x8A8B, 0xB48E, 0x8A8C, 0xB48F, 0x8A8D, 0xB490, 0x8A8E, 0xB491, 0x8A8F, 0xB492, 0x8A90, 0xB493, 0x8A91, 0xB494, 0x8A92, 0xB495, 0x8A93, 0xB496, 0x8A94, 0xB497, 0x8A95, 0xB498, 0x8A96, 0xB499, 0x8A97, 0xB49A, 0x8A98, 0xB49B, 0x8A99, 0xB49C, 0x8A9A, 0xB49E, 0x8A9B, 0xB49F, 0x8A9C, 0xB4A0, 0x8A9D, 0xB4A1, 0x8A9E, 0xB4A2, 0x8A9F, 0xB4A3, 0x8AA0, 0xB4A5, 0x8AA1, 0xB4A6, 0x8AA2, 0xB4A7, 0x8AA3, 0xB4A9, 0x8AA4, 0xB4AA, 0x8AA5, 0xB4AB, 0x8AA6, 0xB4AD, 0x8AA7, 0xB4AE, 0x8AA8, 0xB4AF, 0x8AA9, 0xB4B0, 0x8AAA, 0xB4B1, 0x8AAB, 0xB4B2, 0x8AAC, 0xB4B3, 0x8AAD, 0xB4B4, 0x8AAE, 0xB4B6, 0x8AAF, 0xB4B8, 0x8AB0, 0xB4BA, 0x8AB1, 0xB4BB, 0x8AB2, 0xB4BC, 0x8AB3, 0xB4BD, 0x8AB4, 0xB4BE, 0x8AB5, 0xB4BF, 0x8AB6, 0xB4C1, 0x8AB7, 0xB4C2, 0x8AB8, 0xB4C3, 0x8AB9, 0xB4C5, 0x8ABA, 0xB4C6, 0x8ABB, 0xB4C7, 0x8ABC, 0xB4C9, 0x8ABD, 0xB4CA, 0x8ABE, 0xB4CB, 0x8ABF, 0xB4CC, 0x8AC0, 0xB4CD, 0x8AC1, 0xB4CE, 0x8AC2, 0xB4CF, 0x8AC3, 0xB4D1, 0x8AC4, 0xB4D2, 0x8AC5, 0xB4D3, 0x8AC6, 0xB4D4, 0x8AC7, 0xB4D6, 0x8AC8, 0xB4D7, 0x8AC9, 0xB4D8, 0x8ACA, 0xB4D9, 0x8ACB, 0xB4DA, 0x8ACC, 0xB4DB, 0x8ACD, 0xB4DE, 0x8ACE, 0xB4DF, 0x8ACF, 0xB4E1, 0x8AD0, 0xB4E2, 0x8AD1, 0xB4E5, 0x8AD2, 0xB4E7, 0x8AD3, 0xB4E8, 0x8AD4, 0xB4E9, 0x8AD5, 0xB4EA, 0x8AD6, 0xB4EB, 0x8AD7, 0xB4EE, 0x8AD8, 0xB4F0, 0x8AD9, 0xB4F2, 0x8ADA, 0xB4F3, 0x8ADB, 0xB4F4, 0x8ADC, 0xB4F5, 0x8ADD, 0xB4F6, 0x8ADE, 0xB4F7, 0x8ADF, 0xB4F9, 0x8AE0, 0xB4FA, 0x8AE1, 0xB4FB, 0x8AE2, 0xB4FC, 0x8AE3, 0xB4FD, 0x8AE4, 0xB4FE, 0x8AE5, 0xB4FF, 0x8AE6, 0xB500, 0x8AE7, 0xB501, 0x8AE8, 0xB502, 0x8AE9, 0xB503, 0x8AEA, 0xB504, 0x8AEB, 0xB505, 0x8AEC, 0xB506, 0x8AED, 0xB507, 0x8AEE, 0xB508, 0x8AEF, 0xB509, 0x8AF0, 0xB50A, 0x8AF1, 0xB50B, 0x8AF2, 0xB50C, 0x8AF3, 0xB50D, 0x8AF4, 0xB50E, 0x8AF5, 0xB50F, 0x8AF6, 0xB510, 0x8AF7, 0xB511, 0x8AF8, 0xB512, 0x8AF9, 0xB513, 0x8AFA, 0xB516, 0x8AFB, 0xB517, 0x8AFC, 0xB519, 0x8AFD, 0xB51A, 0x8AFE, 0xB51D, 0x8B41, 0xB51E, 0x8B42, 0xB51F, 0x8B43, 0xB520, 0x8B44, 0xB521, 0x8B45, 0xB522, 0x8B46, 0xB523, 0x8B47, 0xB526, 0x8B48, 0xB52B, 0x8B49, 0xB52C, 0x8B4A, 0xB52D, 0x8B4B, 0xB52E, 0x8B4C, 0xB52F, 0x8B4D, 0xB532, 0x8B4E, 0xB533, 0x8B4F, 0xB535, 0x8B50, 0xB536, 0x8B51, 0xB537, 0x8B52, 0xB539, 0x8B53, 0xB53A, 0x8B54, 0xB53B, 0x8B55, 0xB53C, 0x8B56, 0xB53D, 0x8B57, 0xB53E, 0x8B58, 0xB53F, 0x8B59, 0xB542, 0x8B5A, 0xB546, 0x8B61, 0xB547, 0x8B62, 0xB548, 0x8B63, 0xB549, 0x8B64, 0xB54A, 0x8B65, 0xB54E, 0x8B66, 0xB54F, 0x8B67, 0xB551, 0x8B68, 0xB552, 0x8B69, 0xB553, 0x8B6A, 0xB555, 0x8B6B, 0xB556, 0x8B6C, 0xB557, 0x8B6D, 0xB558, 0x8B6E, 0xB559, 0x8B6F, 0xB55A, 0x8B70, 0xB55B, 0x8B71, 0xB55E, 0x8B72, 0xB562, 0x8B73, 0xB563, 0x8B74, 0xB564, 0x8B75, 0xB565, 0x8B76, 0xB566, 0x8B77, 0xB567, 0x8B78, 0xB568, 0x8B79, 0xB569, 0x8B7A, 0xB56A, 0x8B81, 0xB56B, 0x8B82, 0xB56C, 0x8B83, 0xB56D, 0x8B84, 0xB56E, 0x8B85, 0xB56F, 0x8B86, 0xB570, 0x8B87, 0xB571, 0x8B88, 0xB572, 0x8B89, 0xB573, 0x8B8A, 0xB574, 0x8B8B, 0xB575, 0x8B8C, 0xB576, 0x8B8D, 0xB577, 0x8B8E, 0xB578, 0x8B8F, 0xB579, 0x8B90, 0xB57A, 0x8B91, 0xB57B, 0x8B92, 0xB57C, 0x8B93, 0xB57D, 0x8B94, 0xB57E, 0x8B95, 0xB57F, 0x8B96, 0xB580, 0x8B97, 0xB581, 0x8B98, 0xB582, 0x8B99, 0xB583, 0x8B9A, 0xB584, 0x8B9B, 0xB585, 0x8B9C, 0xB586, 0x8B9D, 0xB587, 0x8B9E, 0xB588, 0x8B9F, 0xB589, 0x8BA0, 0xB58A, 0x8BA1, 0xB58B, 0x8BA2, 0xB58C, 0x8BA3, 0xB58D, 0x8BA4, 0xB58E, 0x8BA5, 0xB58F, 0x8BA6, 0xB590, 0x8BA7, 0xB591, 0x8BA8, 0xB592, 0x8BA9, 0xB593, 0x8BAA, 0xB594, 0x8BAB, 0xB595, 0x8BAC, 0xB596, 0x8BAD, 0xB597, 0x8BAE, 0xB598, 0x8BAF, 0xB599, 0x8BB0, 0xB59A, 0x8BB1, 0xB59B, 0x8BB2, 0xB59C, 0x8BB3, 0xB59D, 0x8BB4, 0xB59E, 0x8BB5, 0xB59F, 0x8BB6, 0xB5A2, 0x8BB7, 0xB5A3, 0x8BB8, 0xB5A5, 0x8BB9, 0xB5A6, 0x8BBA, 0xB5A7, 0x8BBB, 0xB5A9, 0x8BBC, 0xB5AC, 0x8BBD, 0xB5AD, 0x8BBE, 0xB5AE, 0x8BBF, 0xB5AF, 0x8BC0, 0xB5B2, 0x8BC1, 0xB5B6, 0x8BC2, 0xB5B7, 0x8BC3, 0xB5B8, 0x8BC4, 0xB5B9, 0x8BC5, 0xB5BA, 0x8BC6, 0xB5BE, 0x8BC7, 0xB5BF, 0x8BC8, 0xB5C1, 0x8BC9, 0xB5C2, 0x8BCA, 0xB5C3, 0x8BCB, 0xB5C5, 0x8BCC, 0xB5C6, 0x8BCD, 0xB5C7, 0x8BCE, 0xB5C8, 0x8BCF, 0xB5C9, 0x8BD0, 0xB5CA, 0x8BD1, 0xB5CB, 0x8BD2, 0xB5CE, 0x8BD3, 0xB5D2, 0x8BD4, 0xB5D3, 0x8BD5, 0xB5D4, 0x8BD6, 0xB5D5, 0x8BD7, 0xB5D6, 0x8BD8, 0xB5D7, 0x8BD9, 0xB5D9, 0x8BDA, 0xB5DA, 0x8BDB, 0xB5DB, 0x8BDC, 0xB5DC, 0x8BDD, 0xB5DD, 0x8BDE, 0xB5DE, 0x8BDF, 0xB5DF, 0x8BE0, 0xB5E0, 0x8BE1, 0xB5E1, 0x8BE2, 0xB5E2, 0x8BE3, 0xB5E3, 0x8BE4, 0xB5E4, 0x8BE5, 0xB5E5, 0x8BE6, 0xB5E6, 0x8BE7, 0xB5E7, 0x8BE8, 0xB5E8, 0x8BE9, 0xB5E9, 0x8BEA, 0xB5EA, 0x8BEB, 0xB5EB, 0x8BEC, 0xB5ED, 0x8BED, 0xB5EE, 0x8BEE, 0xB5EF, 0x8BEF, 0xB5F0, 0x8BF0, 0xB5F1, 0x8BF1, 0xB5F2, 0x8BF2, 0xB5F3, 0x8BF3, 0xB5F4, 0x8BF4, 0xB5F5, 0x8BF5, 0xB5F6, 0x8BF6, 0xB5F7, 0x8BF7, 0xB5F8, 0x8BF8, 0xB5F9, 0x8BF9, 0xB5FA, 0x8BFA, 0xB5FB, 0x8BFB, 0xB5FC, 0x8BFC, 0xB5FD, 0x8BFD, 0xB5FE, 0x8BFE, 0xB5FF, 0x8C41, 0xB600, 0x8C42, 0xB601, 0x8C43, 0xB602, 0x8C44, 0xB603, 0x8C45, 0xB604, 0x8C46, 0xB605, 0x8C47, 0xB606, 0x8C48, 0xB607, 0x8C49, 0xB608, 0x8C4A, 0xB609, 0x8C4B, 0xB60A, 0x8C4C, 0xB60B, 0x8C4D, 0xB60C, 0x8C4E, 0xB60D, 0x8C4F, 0xB60E, 0x8C50, 0xB60F, 0x8C51, 0xB612, 0x8C52, 0xB613, 0x8C53, 0xB615, 0x8C54, 0xB616, 0x8C55, 0xB617, 0x8C56, 0xB619, 0x8C57, 0xB61A, 0x8C58, 0xB61B, 0x8C59, 0xB61C, 0x8C5A, 0xB61D, 0x8C61, 0xB61E, 0x8C62, 0xB61F, 0x8C63, 0xB620, 0x8C64, 0xB621, 0x8C65, 0xB622, 0x8C66, 0xB623, 0x8C67, 0xB624, 0x8C68, 0xB626, 0x8C69, 0xB627, 0x8C6A, 0xB628, 0x8C6B, 0xB629, 0x8C6C, 0xB62A, 0x8C6D, 0xB62B, 0x8C6E, 0xB62D, 0x8C6F, 0xB62E, 0x8C70, 0xB62F, 0x8C71, 0xB630, 0x8C72, 0xB631, 0x8C73, 0xB632, 0x8C74, 0xB633, 0x8C75, 0xB635, 0x8C76, 0xB636, 0x8C77, 0xB637, 0x8C78, 0xB638, 0x8C79, 0xB639, 0x8C7A, 0xB63A, 0x8C81, 0xB63B, 0x8C82, 0xB63C, 0x8C83, 0xB63D, 0x8C84, 0xB63E, 0x8C85, 0xB63F, 0x8C86, 0xB640, 0x8C87, 0xB641, 0x8C88, 0xB642, 0x8C89, 0xB643, 0x8C8A, 0xB644, 0x8C8B, 0xB645, 0x8C8C, 0xB646, 0x8C8D, 0xB647, 0x8C8E, 0xB649, 0x8C8F, 0xB64A, 0x8C90, 0xB64B, 0x8C91, 0xB64C, 0x8C92, 0xB64D, 0x8C93, 0xB64E, 0x8C94, 0xB64F, 0x8C95, 0xB650, 0x8C96, 0xB651, 0x8C97, 0xB652, 0x8C98, 0xB653, 0x8C99, 0xB654, 0x8C9A, 0xB655, 0x8C9B, 0xB656, 0x8C9C, 0xB657, 0x8C9D, 0xB658, 0x8C9E, 0xB659, 0x8C9F, 0xB65A, 0x8CA0, 0xB65B, 0x8CA1, 0xB65C, 0x8CA2, 0xB65D, 0x8CA3, 0xB65E, 0x8CA4, 0xB65F, 0x8CA5, 0xB660, 0x8CA6, 0xB661, 0x8CA7, 0xB662, 0x8CA8, 0xB663, 0x8CA9, 0xB665, 0x8CAA, 0xB666, 0x8CAB, 0xB667, 0x8CAC, 0xB669, 0x8CAD, 0xB66A, 0x8CAE, 0xB66B, 0x8CAF, 0xB66C, 0x8CB0, 0xB66D, 0x8CB1, 0xB66E, 0x8CB2, 0xB66F, 0x8CB3, 0xB670, 0x8CB4, 0xB671, 0x8CB5, 0xB672, 0x8CB6, 0xB673, 0x8CB7, 0xB674, 0x8CB8, 0xB675, 0x8CB9, 0xB676, 0x8CBA, 0xB677, 0x8CBB, 0xB678, 0x8CBC, 0xB679, 0x8CBD, 0xB67A, 0x8CBE, 0xB67B, 0x8CBF, 0xB67C, 0x8CC0, 0xB67D, 0x8CC1, 0xB67E, 0x8CC2, 0xB67F, 0x8CC3, 0xB680, 0x8CC4, 0xB681, 0x8CC5, 0xB682, 0x8CC6, 0xB683, 0x8CC7, 0xB684, 0x8CC8, 0xB685, 0x8CC9, 0xB686, 0x8CCA, 0xB687, 0x8CCB, 0xB688, 0x8CCC, 0xB689, 0x8CCD, 0xB68A, 0x8CCE, 0xB68B, 0x8CCF, 0xB68C, 0x8CD0, 0xB68D, 0x8CD1, 0xB68E, 0x8CD2, 0xB68F, 0x8CD3, 0xB690, 0x8CD4, 0xB691, 0x8CD5, 0xB692, 0x8CD6, 0xB693, 0x8CD7, 0xB694, 0x8CD8, 0xB695, 0x8CD9, 0xB696, 0x8CDA, 0xB697, 0x8CDB, 0xB698, 0x8CDC, 0xB699, 0x8CDD, 0xB69A, 0x8CDE, 0xB69B, 0x8CDF, 0xB69E, 0x8CE0, 0xB69F, 0x8CE1, 0xB6A1, 0x8CE2, 0xB6A2, 0x8CE3, 0xB6A3, 0x8CE4, 0xB6A5, 0x8CE5, 0xB6A6, 0x8CE6, 0xB6A7, 0x8CE7, 0xB6A8, 0x8CE8, 0xB6A9, 0x8CE9, 0xB6AA, 0x8CEA, 0xB6AD, 0x8CEB, 0xB6AE, 0x8CEC, 0xB6AF, 0x8CED, 0xB6B0, 0x8CEE, 0xB6B2, 0x8CEF, 0xB6B3, 0x8CF0, 0xB6B4, 0x8CF1, 0xB6B5, 0x8CF2, 0xB6B6, 0x8CF3, 0xB6B7, 0x8CF4, 0xB6B8, 0x8CF5, 0xB6B9, 0x8CF6, 0xB6BA, 0x8CF7, 0xB6BB, 0x8CF8, 0xB6BC, 0x8CF9, 0xB6BD, 0x8CFA, 0xB6BE, 0x8CFB, 0xB6BF, 0x8CFC, 0xB6C0, 0x8CFD, 0xB6C1, 0x8CFE, 0xB6C2, 0x8D41, 0xB6C3, 0x8D42, 0xB6C4, 0x8D43, 0xB6C5, 0x8D44, 0xB6C6, 0x8D45, 0xB6C7, 0x8D46, 0xB6C8, 0x8D47, 0xB6C9, 0x8D48, 0xB6CA, 0x8D49, 0xB6CB, 0x8D4A, 0xB6CC, 0x8D4B, 0xB6CD, 0x8D4C, 0xB6CE, 0x8D4D, 0xB6CF, 0x8D4E, 0xB6D0, 0x8D4F, 0xB6D1, 0x8D50, 0xB6D2, 0x8D51, 0xB6D3, 0x8D52, 0xB6D5, 0x8D53, 0xB6D6, 0x8D54, 0xB6D7, 0x8D55, 0xB6D8, 0x8D56, 0xB6D9, 0x8D57, 0xB6DA, 0x8D58, 0xB6DB, 0x8D59, 0xB6DC, 0x8D5A, 0xB6DD, 0x8D61, 0xB6DE, 0x8D62, 0xB6DF, 0x8D63, 0xB6E0, 0x8D64, 0xB6E1, 0x8D65, 0xB6E2, 0x8D66, 0xB6E3, 0x8D67, 0xB6E4, 0x8D68, 0xB6E5, 0x8D69, 0xB6E6, 0x8D6A, 0xB6E7, 0x8D6B, 0xB6E8, 0x8D6C, 0xB6E9, 0x8D6D, 0xB6EA, 0x8D6E, 0xB6EB, 0x8D6F, 0xB6EC, 0x8D70, 0xB6ED, 0x8D71, 0xB6EE, 0x8D72, 0xB6EF, 0x8D73, 0xB6F1, 0x8D74, 0xB6F2, 0x8D75, 0xB6F3, 0x8D76, 0xB6F5, 0x8D77, 0xB6F6, 0x8D78, 0xB6F7, 0x8D79, 0xB6F9, 0x8D7A, 0xB6FA, 0x8D81, 0xB6FB, 0x8D82, 0xB6FC, 0x8D83, 0xB6FD, 0x8D84, 0xB6FE, 0x8D85, 0xB6FF, 0x8D86, 0xB702, 0x8D87, 0xB703, 0x8D88, 0xB704, 0x8D89, 0xB706, 0x8D8A, 0xB707, 0x8D8B, 0xB708, 0x8D8C, 0xB709, 0x8D8D, 0xB70A, 0x8D8E, 0xB70B, 0x8D8F, 0xB70C, 0x8D90, 0xB70D, 0x8D91, 0xB70E, 0x8D92, 0xB70F, 0x8D93, 0xB710, 0x8D94, 0xB711, 0x8D95, 0xB712, 0x8D96, 0xB713, 0x8D97, 0xB714, 0x8D98, 0xB715, 0x8D99, 0xB716, 0x8D9A, 0xB717, 0x8D9B, 0xB718, 0x8D9C, 0xB719, 0x8D9D, 0xB71A, 0x8D9E, 0xB71B, 0x8D9F, 0xB71C, 0x8DA0, 0xB71D, 0x8DA1, 0xB71E, 0x8DA2, 0xB71F, 0x8DA3, 0xB720, 0x8DA4, 0xB721, 0x8DA5, 0xB722, 0x8DA6, 0xB723, 0x8DA7, 0xB724, 0x8DA8, 0xB725, 0x8DA9, 0xB726, 0x8DAA, 0xB727, 0x8DAB, 0xB72A, 0x8DAC, 0xB72B, 0x8DAD, 0xB72D, 0x8DAE, 0xB72E, 0x8DAF, 0xB731, 0x8DB0, 0xB732, 0x8DB1, 0xB733, 0x8DB2, 0xB734, 0x8DB3, 0xB735, 0x8DB4, 0xB736, 0x8DB5, 0xB737, 0x8DB6, 0xB73A, 0x8DB7, 0xB73C, 0x8DB8, 0xB73D, 0x8DB9, 0xB73E, 0x8DBA, 0xB73F, 0x8DBB, 0xB740, 0x8DBC, 0xB741, 0x8DBD, 0xB742, 0x8DBE, 0xB743, 0x8DBF, 0xB745, 0x8DC0, 0xB746, 0x8DC1, 0xB747, 0x8DC2, 0xB749, 0x8DC3, 0xB74A, 0x8DC4, 0xB74B, 0x8DC5, 0xB74D, 0x8DC6, 0xB74E, 0x8DC7, 0xB74F, 0x8DC8, 0xB750, 0x8DC9, 0xB751, 0x8DCA, 0xB752, 0x8DCB, 0xB753, 0x8DCC, 0xB756, 0x8DCD, 0xB757, 0x8DCE, 0xB758, 0x8DCF, 0xB759, 0x8DD0, 0xB75A, 0x8DD1, 0xB75B, 0x8DD2, 0xB75C, 0x8DD3, 0xB75D, 0x8DD4, 0xB75E, 0x8DD5, 0xB75F, 0x8DD6, 0xB761, 0x8DD7, 0xB762, 0x8DD8, 0xB763, 0x8DD9, 0xB765, 0x8DDA, 0xB766, 0x8DDB, 0xB767, 0x8DDC, 0xB769, 0x8DDD, 0xB76A, 0x8DDE, 0xB76B, 0x8DDF, 0xB76C, 0x8DE0, 0xB76D, 0x8DE1, 0xB76E, 0x8DE2, 0xB76F, 0x8DE3, 0xB772, 0x8DE4, 0xB774, 0x8DE5, 0xB776, 0x8DE6, 0xB777, 0x8DE7, 0xB778, 0x8DE8, 0xB779, 0x8DE9, 0xB77A, 0x8DEA, 0xB77B, 0x8DEB, 0xB77E, 0x8DEC, 0xB77F, 0x8DED, 0xB781, 0x8DEE, 0xB782, 0x8DEF, 0xB783, 0x8DF0, 0xB785, 0x8DF1, 0xB786, 0x8DF2, 0xB787, 0x8DF3, 0xB788, 0x8DF4, 0xB789, 0x8DF5, 0xB78A, 0x8DF6, 0xB78B, 0x8DF7, 0xB78E, 0x8DF8, 0xB793, 0x8DF9, 0xB794, 0x8DFA, 0xB795, 0x8DFB, 0xB79A, 0x8DFC, 0xB79B, 0x8DFD, 0xB79D, 0x8DFE, 0xB79E, 0x8E41, 0xB79F, 0x8E42, 0xB7A1, 0x8E43, 0xB7A2, 0x8E44, 0xB7A3, 0x8E45, 0xB7A4, 0x8E46, 0xB7A5, 0x8E47, 0xB7A6, 0x8E48, 0xB7A7, 0x8E49, 0xB7AA, 0x8E4A, 0xB7AE, 0x8E4B, 0xB7AF, 0x8E4C, 0xB7B0, 0x8E4D, 0xB7B1, 0x8E4E, 0xB7B2, 0x8E4F, 0xB7B3, 0x8E50, 0xB7B6, 0x8E51, 0xB7B7, 0x8E52, 0xB7B9, 0x8E53, 0xB7BA, 0x8E54, 0xB7BB, 0x8E55, 0xB7BC, 0x8E56, 0xB7BD, 0x8E57, 0xB7BE, 0x8E58, 0xB7BF, 0x8E59, 0xB7C0, 0x8E5A, 0xB7C1, 0x8E61, 0xB7C2, 0x8E62, 0xB7C3, 0x8E63, 0xB7C4, 0x8E64, 0xB7C5, 0x8E65, 0xB7C6, 0x8E66, 0xB7C8, 0x8E67, 0xB7CA, 0x8E68, 0xB7CB, 0x8E69, 0xB7CC, 0x8E6A, 0xB7CD, 0x8E6B, 0xB7CE, 0x8E6C, 0xB7CF, 0x8E6D, 0xB7D0, 0x8E6E, 0xB7D1, 0x8E6F, 0xB7D2, 0x8E70, 0xB7D3, 0x8E71, 0xB7D4, 0x8E72, 0xB7D5, 0x8E73, 0xB7D6, 0x8E74, 0xB7D7, 0x8E75, 0xB7D8, 0x8E76, 0xB7D9, 0x8E77, 0xB7DA, 0x8E78, 0xB7DB, 0x8E79, 0xB7DC, 0x8E7A, 0xB7DD, 0x8E81, 0xB7DE, 0x8E82, 0xB7DF, 0x8E83, 0xB7E0, 0x8E84, 0xB7E1, 0x8E85, 0xB7E2, 0x8E86, 0xB7E3, 0x8E87, 0xB7E4, 0x8E88, 0xB7E5, 0x8E89, 0xB7E6, 0x8E8A, 0xB7E7, 0x8E8B, 0xB7E8, 0x8E8C, 0xB7E9, 0x8E8D, 0xB7EA, 0x8E8E, 0xB7EB, 0x8E8F, 0xB7EE, 0x8E90, 0xB7EF, 0x8E91, 0xB7F1, 0x8E92, 0xB7F2, 0x8E93, 0xB7F3, 0x8E94, 0xB7F5, 0x8E95, 0xB7F6, 0x8E96, 0xB7F7, 0x8E97, 0xB7F8, 0x8E98, 0xB7F9, 0x8E99, 0xB7FA, 0x8E9A, 0xB7FB, 0x8E9B, 0xB7FE, 0x8E9C, 0xB802, 0x8E9D, 0xB803, 0x8E9E, 0xB804, 0x8E9F, 0xB805, 0x8EA0, 0xB806, 0x8EA1, 0xB80A, 0x8EA2, 0xB80B, 0x8EA3, 0xB80D, 0x8EA4, 0xB80E, 0x8EA5, 0xB80F, 0x8EA6, 0xB811, 0x8EA7, 0xB812, 0x8EA8, 0xB813, 0x8EA9, 0xB814, 0x8EAA, 0xB815, 0x8EAB, 0xB816, 0x8EAC, 0xB817, 0x8EAD, 0xB81A, 0x8EAE, 0xB81C, 0x8EAF, 0xB81E, 0x8EB0, 0xB81F, 0x8EB1, 0xB820, 0x8EB2, 0xB821, 0x8EB3, 0xB822, 0x8EB4, 0xB823, 0x8EB5, 0xB826, 0x8EB6, 0xB827, 0x8EB7, 0xB829, 0x8EB8, 0xB82A, 0x8EB9, 0xB82B, 0x8EBA, 0xB82D, 0x8EBB, 0xB82E, 0x8EBC, 0xB82F, 0x8EBD, 0xB830, 0x8EBE, 0xB831, 0x8EBF, 0xB832, 0x8EC0, 0xB833, 0x8EC1, 0xB836, 0x8EC2, 0xB83A, 0x8EC3, 0xB83B, 0x8EC4, 0xB83C, 0x8EC5, 0xB83D, 0x8EC6, 0xB83E, 0x8EC7, 0xB83F, 0x8EC8, 0xB841, 0x8EC9, 0xB842, 0x8ECA, 0xB843, 0x8ECB, 0xB845, 0x8ECC, 0xB846, 0x8ECD, 0xB847, 0x8ECE, 0xB848, 0x8ECF, 0xB849, 0x8ED0, 0xB84A, 0x8ED1, 0xB84B, 0x8ED2, 0xB84C, 0x8ED3, 0xB84D, 0x8ED4, 0xB84E, 0x8ED5, 0xB84F, 0x8ED6, 0xB850, 0x8ED7, 0xB852, 0x8ED8, 0xB854, 0x8ED9, 0xB855, 0x8EDA, 0xB856, 0x8EDB, 0xB857, 0x8EDC, 0xB858, 0x8EDD, 0xB859, 0x8EDE, 0xB85A, 0x8EDF, 0xB85B, 0x8EE0, 0xB85E, 0x8EE1, 0xB85F, 0x8EE2, 0xB861, 0x8EE3, 0xB862, 0x8EE4, 0xB863, 0x8EE5, 0xB865, 0x8EE6, 0xB866, 0x8EE7, 0xB867, 0x8EE8, 0xB868, 0x8EE9, 0xB869, 0x8EEA, 0xB86A, 0x8EEB, 0xB86B, 0x8EEC, 0xB86E, 0x8EED, 0xB870, 0x8EEE, 0xB872, 0x8EEF, 0xB873, 0x8EF0, 0xB874, 0x8EF1, 0xB875, 0x8EF2, 0xB876, 0x8EF3, 0xB877, 0x8EF4, 0xB879, 0x8EF5, 0xB87A, 0x8EF6, 0xB87B, 0x8EF7, 0xB87D, 0x8EF8, 0xB87E, 0x8EF9, 0xB87F, 0x8EFA, 0xB880, 0x8EFB, 0xB881, 0x8EFC, 0xB882, 0x8EFD, 0xB883, 0x8EFE, 0xB884, 0x8F41, 0xB885, 0x8F42, 0xB886, 0x8F43, 0xB887, 0x8F44, 0xB888, 0x8F45, 0xB889, 0x8F46, 0xB88A, 0x8F47, 0xB88B, 0x8F48, 0xB88C, 0x8F49, 0xB88E, 0x8F4A, 0xB88F, 0x8F4B, 0xB890, 0x8F4C, 0xB891, 0x8F4D, 0xB892, 0x8F4E, 0xB893, 0x8F4F, 0xB894, 0x8F50, 0xB895, 0x8F51, 0xB896, 0x8F52, 0xB897, 0x8F53, 0xB898, 0x8F54, 0xB899, 0x8F55, 0xB89A, 0x8F56, 0xB89B, 0x8F57, 0xB89C, 0x8F58, 0xB89D, 0x8F59, 0xB89E, 0x8F5A, 0xB89F, 0x8F61, 0xB8A0, 0x8F62, 0xB8A1, 0x8F63, 0xB8A2, 0x8F64, 0xB8A3, 0x8F65, 0xB8A4, 0x8F66, 0xB8A5, 0x8F67, 0xB8A6, 0x8F68, 0xB8A7, 0x8F69, 0xB8A9, 0x8F6A, 0xB8AA, 0x8F6B, 0xB8AB, 0x8F6C, 0xB8AC, 0x8F6D, 0xB8AD, 0x8F6E, 0xB8AE, 0x8F6F, 0xB8AF, 0x8F70, 0xB8B1, 0x8F71, 0xB8B2, 0x8F72, 0xB8B3, 0x8F73, 0xB8B5, 0x8F74, 0xB8B6, 0x8F75, 0xB8B7, 0x8F76, 0xB8B9, 0x8F77, 0xB8BA, 0x8F78, 0xB8BB, 0x8F79, 0xB8BC, 0x8F7A, 0xB8BD, 0x8F81, 0xB8BE, 0x8F82, 0xB8BF, 0x8F83, 0xB8C2, 0x8F84, 0xB8C4, 0x8F85, 0xB8C6, 0x8F86, 0xB8C7, 0x8F87, 0xB8C8, 0x8F88, 0xB8C9, 0x8F89, 0xB8CA, 0x8F8A, 0xB8CB, 0x8F8B, 0xB8CD, 0x8F8C, 0xB8CE, 0x8F8D, 0xB8CF, 0x8F8E, 0xB8D1, 0x8F8F, 0xB8D2, 0x8F90, 0xB8D3, 0x8F91, 0xB8D5, 0x8F92, 0xB8D6, 0x8F93, 0xB8D7, 0x8F94, 0xB8D8, 0x8F95, 0xB8D9, 0x8F96, 0xB8DA, 0x8F97, 0xB8DB, 0x8F98, 0xB8DC, 0x8F99, 0xB8DE, 0x8F9A, 0xB8E0, 0x8F9B, 0xB8E2, 0x8F9C, 0xB8E3, 0x8F9D, 0xB8E4, 0x8F9E, 0xB8E5, 0x8F9F, 0xB8E6, 0x8FA0, 0xB8E7, 0x8FA1, 0xB8EA, 0x8FA2, 0xB8EB, 0x8FA3, 0xB8ED, 0x8FA4, 0xB8EE, 0x8FA5, 0xB8EF, 0x8FA6, 0xB8F1, 0x8FA7, 0xB8F2, 0x8FA8, 0xB8F3, 0x8FA9, 0xB8F4, 0x8FAA, 0xB8F5, 0x8FAB, 0xB8F6, 0x8FAC, 0xB8F7, 0x8FAD, 0xB8FA, 0x8FAE, 0xB8FC, 0x8FAF, 0xB8FE, 0x8FB0, 0xB8FF, 0x8FB1, 0xB900, 0x8FB2, 0xB901, 0x8FB3, 0xB902, 0x8FB4, 0xB903, 0x8FB5, 0xB905, 0x8FB6, 0xB906, 0x8FB7, 0xB907, 0x8FB8, 0xB908, 0x8FB9, 0xB909, 0x8FBA, 0xB90A, 0x8FBB, 0xB90B, 0x8FBC, 0xB90C, 0x8FBD, 0xB90D, 0x8FBE, 0xB90E, 0x8FBF, 0xB90F, 0x8FC0, 0xB910, 0x8FC1, 0xB911, 0x8FC2, 0xB912, 0x8FC3, 0xB913, 0x8FC4, 0xB914, 0x8FC5, 0xB915, 0x8FC6, 0xB916, 0x8FC7, 0xB917, 0x8FC8, 0xB919, 0x8FC9, 0xB91A, 0x8FCA, 0xB91B, 0x8FCB, 0xB91C, 0x8FCC, 0xB91D, 0x8FCD, 0xB91E, 0x8FCE, 0xB91F, 0x8FCF, 0xB921, 0x8FD0, 0xB922, 0x8FD1, 0xB923, 0x8FD2, 0xB924, 0x8FD3, 0xB925, 0x8FD4, 0xB926, 0x8FD5, 0xB927, 0x8FD6, 0xB928, 0x8FD7, 0xB929, 0x8FD8, 0xB92A, 0x8FD9, 0xB92B, 0x8FDA, 0xB92C, 0x8FDB, 0xB92D, 0x8FDC, 0xB92E, 0x8FDD, 0xB92F, 0x8FDE, 0xB930, 0x8FDF, 0xB931, 0x8FE0, 0xB932, 0x8FE1, 0xB933, 0x8FE2, 0xB934, 0x8FE3, 0xB935, 0x8FE4, 0xB936, 0x8FE5, 0xB937, 0x8FE6, 0xB938, 0x8FE7, 0xB939, 0x8FE8, 0xB93A, 0x8FE9, 0xB93B, 0x8FEA, 0xB93E, 0x8FEB, 0xB93F, 0x8FEC, 0xB941, 0x8FED, 0xB942, 0x8FEE, 0xB943, 0x8FEF, 0xB945, 0x8FF0, 0xB946, 0x8FF1, 0xB947, 0x8FF2, 0xB948, 0x8FF3, 0xB949, 0x8FF4, 0xB94A, 0x8FF5, 0xB94B, 0x8FF6, 0xB94D, 0x8FF7, 0xB94E, 0x8FF8, 0xB950, 0x8FF9, 0xB952, 0x8FFA, 0xB953, 0x8FFB, 0xB954, 0x8FFC, 0xB955, 0x8FFD, 0xB956, 0x8FFE, 0xB957, 0x9041, 0xB95A, 0x9042, 0xB95B, 0x9043, 0xB95D, 0x9044, 0xB95E, 0x9045, 0xB95F, 0x9046, 0xB961, 0x9047, 0xB962, 0x9048, 0xB963, 0x9049, 0xB964, 0x904A, 0xB965, 0x904B, 0xB966, 0x904C, 0xB967, 0x904D, 0xB96A, 0x904E, 0xB96C, 0x904F, 0xB96E, 0x9050, 0xB96F, 0x9051, 0xB970, 0x9052, 0xB971, 0x9053, 0xB972, 0x9054, 0xB973, 0x9055, 0xB976, 0x9056, 0xB977, 0x9057, 0xB979, 0x9058, 0xB97A, 0x9059, 0xB97B, 0x905A, 0xB97D, 0x9061, 0xB97E, 0x9062, 0xB97F, 0x9063, 0xB980, 0x9064, 0xB981, 0x9065, 0xB982, 0x9066, 0xB983, 0x9067, 0xB986, 0x9068, 0xB988, 0x9069, 0xB98B, 0x906A, 0xB98C, 0x906B, 0xB98F, 0x906C, 0xB990, 0x906D, 0xB991, 0x906E, 0xB992, 0x906F, 0xB993, 0x9070, 0xB994, 0x9071, 0xB995, 0x9072, 0xB996, 0x9073, 0xB997, 0x9074, 0xB998, 0x9075, 0xB999, 0x9076, 0xB99A, 0x9077, 0xB99B, 0x9078, 0xB99C, 0x9079, 0xB99D, 0x907A, 0xB99E, 0x9081, 0xB99F, 0x9082, 0xB9A0, 0x9083, 0xB9A1, 0x9084, 0xB9A2, 0x9085, 0xB9A3, 0x9086, 0xB9A4, 0x9087, 0xB9A5, 0x9088, 0xB9A6, 0x9089, 0xB9A7, 0x908A, 0xB9A8, 0x908B, 0xB9A9, 0x908C, 0xB9AA, 0x908D, 0xB9AB, 0x908E, 0xB9AE, 0x908F, 0xB9AF, 0x9090, 0xB9B1, 0x9091, 0xB9B2, 0x9092, 0xB9B3, 0x9093, 0xB9B5, 0x9094, 0xB9B6, 0x9095, 0xB9B7, 0x9096, 0xB9B8, 0x9097, 0xB9B9, 0x9098, 0xB9BA, 0x9099, 0xB9BB, 0x909A, 0xB9BE, 0x909B, 0xB9C0, 0x909C, 0xB9C2, 0x909D, 0xB9C3, 0x909E, 0xB9C4, 0x909F, 0xB9C5, 0x90A0, 0xB9C6, 0x90A1, 0xB9C7, 0x90A2, 0xB9CA, 0x90A3, 0xB9CB, 0x90A4, 0xB9CD, 0x90A5, 0xB9D3, 0x90A6, 0xB9D4, 0x90A7, 0xB9D5, 0x90A8, 0xB9D6, 0x90A9, 0xB9D7, 0x90AA, 0xB9DA, 0x90AB, 0xB9DC, 0x90AC, 0xB9DF, 0x90AD, 0xB9E0, 0x90AE, 0xB9E2, 0x90AF, 0xB9E6, 0x90B0, 0xB9E7, 0x90B1, 0xB9E9, 0x90B2, 0xB9EA, 0x90B3, 0xB9EB, 0x90B4, 0xB9ED, 0x90B5, 0xB9EE, 0x90B6, 0xB9EF, 0x90B7, 0xB9F0, 0x90B8, 0xB9F1, 0x90B9, 0xB9F2, 0x90BA, 0xB9F3, 0x90BB, 0xB9F6, 0x90BC, 0xB9FB, 0x90BD, 0xB9FC, 0x90BE, 0xB9FD, 0x90BF, 0xB9FE, 0x90C0, 0xB9FF, 0x90C1, 0xBA02, 0x90C2, 0xBA03, 0x90C3, 0xBA04, 0x90C4, 0xBA05, 0x90C5, 0xBA06, 0x90C6, 0xBA07, 0x90C7, 0xBA09, 0x90C8, 0xBA0A, 0x90C9, 0xBA0B, 0x90CA, 0xBA0C, 0x90CB, 0xBA0D, 0x90CC, 0xBA0E, 0x90CD, 0xBA0F, 0x90CE, 0xBA10, 0x90CF, 0xBA11, 0x90D0, 0xBA12, 0x90D1, 0xBA13, 0x90D2, 0xBA14, 0x90D3, 0xBA16, 0x90D4, 0xBA17, 0x90D5, 0xBA18, 0x90D6, 0xBA19, 0x90D7, 0xBA1A, 0x90D8, 0xBA1B, 0x90D9, 0xBA1C, 0x90DA, 0xBA1D, 0x90DB, 0xBA1E, 0x90DC, 0xBA1F, 0x90DD, 0xBA20, 0x90DE, 0xBA21, 0x90DF, 0xBA22, 0x90E0, 0xBA23, 0x90E1, 0xBA24, 0x90E2, 0xBA25, 0x90E3, 0xBA26, 0x90E4, 0xBA27, 0x90E5, 0xBA28, 0x90E6, 0xBA29, 0x90E7, 0xBA2A, 0x90E8, 0xBA2B, 0x90E9, 0xBA2C, 0x90EA, 0xBA2D, 0x90EB, 0xBA2E, 0x90EC, 0xBA2F, 0x90ED, 0xBA30, 0x90EE, 0xBA31, 0x90EF, 0xBA32, 0x90F0, 0xBA33, 0x90F1, 0xBA34, 0x90F2, 0xBA35, 0x90F3, 0xBA36, 0x90F4, 0xBA37, 0x90F5, 0xBA3A, 0x90F6, 0xBA3B, 0x90F7, 0xBA3D, 0x90F8, 0xBA3E, 0x90F9, 0xBA3F, 0x90FA, 0xBA41, 0x90FB, 0xBA43, 0x90FC, 0xBA44, 0x90FD, 0xBA45, 0x90FE, 0xBA46, 0x9141, 0xBA47, 0x9142, 0xBA4A, 0x9143, 0xBA4C, 0x9144, 0xBA4F, 0x9145, 0xBA50, 0x9146, 0xBA51, 0x9147, 0xBA52, 0x9148, 0xBA56, 0x9149, 0xBA57, 0x914A, 0xBA59, 0x914B, 0xBA5A, 0x914C, 0xBA5B, 0x914D, 0xBA5D, 0x914E, 0xBA5E, 0x914F, 0xBA5F, 0x9150, 0xBA60, 0x9151, 0xBA61, 0x9152, 0xBA62, 0x9153, 0xBA63, 0x9154, 0xBA66, 0x9155, 0xBA6A, 0x9156, 0xBA6B, 0x9157, 0xBA6C, 0x9158, 0xBA6D, 0x9159, 0xBA6E, 0x915A, 0xBA6F, 0x9161, 0xBA72, 0x9162, 0xBA73, 0x9163, 0xBA75, 0x9164, 0xBA76, 0x9165, 0xBA77, 0x9166, 0xBA79, 0x9167, 0xBA7A, 0x9168, 0xBA7B, 0x9169, 0xBA7C, 0x916A, 0xBA7D, 0x916B, 0xBA7E, 0x916C, 0xBA7F, 0x916D, 0xBA80, 0x916E, 0xBA81, 0x916F, 0xBA82, 0x9170, 0xBA86, 0x9171, 0xBA88, 0x9172, 0xBA89, 0x9173, 0xBA8A, 0x9174, 0xBA8B, 0x9175, 0xBA8D, 0x9176, 0xBA8E, 0x9177, 0xBA8F, 0x9178, 0xBA90, 0x9179, 0xBA91, 0x917A, 0xBA92, 0x9181, 0xBA93, 0x9182, 0xBA94, 0x9183, 0xBA95, 0x9184, 0xBA96, 0x9185, 0xBA97, 0x9186, 0xBA98, 0x9187, 0xBA99, 0x9188, 0xBA9A, 0x9189, 0xBA9B, 0x918A, 0xBA9C, 0x918B, 0xBA9D, 0x918C, 0xBA9E, 0x918D, 0xBA9F, 0x918E, 0xBAA0, 0x918F, 0xBAA1, 0x9190, 0xBAA2, 0x9191, 0xBAA3, 0x9192, 0xBAA4, 0x9193, 0xBAA5, 0x9194, 0xBAA6, 0x9195, 0xBAA7, 0x9196, 0xBAAA, 0x9197, 0xBAAD, 0x9198, 0xBAAE, 0x9199, 0xBAAF, 0x919A, 0xBAB1, 0x919B, 0xBAB3, 0x919C, 0xBAB4, 0x919D, 0xBAB5, 0x919E, 0xBAB6, 0x919F, 0xBAB7, 0x91A0, 0xBABA, 0x91A1, 0xBABC, 0x91A2, 0xBABE, 0x91A3, 0xBABF, 0x91A4, 0xBAC0, 0x91A5, 0xBAC1, 0x91A6, 0xBAC2, 0x91A7, 0xBAC3, 0x91A8, 0xBAC5, 0x91A9, 0xBAC6, 0x91AA, 0xBAC7, 0x91AB, 0xBAC9, 0x91AC, 0xBACA, 0x91AD, 0xBACB, 0x91AE, 0xBACC, 0x91AF, 0xBACD, 0x91B0, 0xBACE, 0x91B1, 0xBACF, 0x91B2, 0xBAD0, 0x91B3, 0xBAD1, 0x91B4, 0xBAD2, 0x91B5, 0xBAD3, 0x91B6, 0xBAD4, 0x91B7, 0xBAD5, 0x91B8, 0xBAD6, 0x91B9, 0xBAD7, 0x91BA, 0xBADA, 0x91BB, 0xBADB, 0x91BC, 0xBADC, 0x91BD, 0xBADD, 0x91BE, 0xBADE, 0x91BF, 0xBADF, 0x91C0, 0xBAE0, 0x91C1, 0xBAE1, 0x91C2, 0xBAE2, 0x91C3, 0xBAE3, 0x91C4, 0xBAE4, 0x91C5, 0xBAE5, 0x91C6, 0xBAE6, 0x91C7, 0xBAE7, 0x91C8, 0xBAE8, 0x91C9, 0xBAE9, 0x91CA, 0xBAEA, 0x91CB, 0xBAEB, 0x91CC, 0xBAEC, 0x91CD, 0xBAED, 0x91CE, 0xBAEE, 0x91CF, 0xBAEF, 0x91D0, 0xBAF0, 0x91D1, 0xBAF1, 0x91D2, 0xBAF2, 0x91D3, 0xBAF3, 0x91D4, 0xBAF4, 0x91D5, 0xBAF5, 0x91D6, 0xBAF6, 0x91D7, 0xBAF7, 0x91D8, 0xBAF8, 0x91D9, 0xBAF9, 0x91DA, 0xBAFA, 0x91DB, 0xBAFB, 0x91DC, 0xBAFD, 0x91DD, 0xBAFE, 0x91DE, 0xBAFF, 0x91DF, 0xBB01, 0x91E0, 0xBB02, 0x91E1, 0xBB03, 0x91E2, 0xBB05, 0x91E3, 0xBB06, 0x91E4, 0xBB07, 0x91E5, 0xBB08, 0x91E6, 0xBB09, 0x91E7, 0xBB0A, 0x91E8, 0xBB0B, 0x91E9, 0xBB0C, 0x91EA, 0xBB0E, 0x91EB, 0xBB10, 0x91EC, 0xBB12, 0x91ED, 0xBB13, 0x91EE, 0xBB14, 0x91EF, 0xBB15, 0x91F0, 0xBB16, 0x91F1, 0xBB17, 0x91F2, 0xBB19, 0x91F3, 0xBB1A, 0x91F4, 0xBB1B, 0x91F5, 0xBB1D, 0x91F6, 0xBB1E, 0x91F7, 0xBB1F, 0x91F8, 0xBB21, 0x91F9, 0xBB22, 0x91FA, 0xBB23, 0x91FB, 0xBB24, 0x91FC, 0xBB25, 0x91FD, 0xBB26, 0x91FE, 0xBB27, 0x9241, 0xBB28, 0x9242, 0xBB2A, 0x9243, 0xBB2C, 0x9244, 0xBB2D, 0x9245, 0xBB2E, 0x9246, 0xBB2F, 0x9247, 0xBB30, 0x9248, 0xBB31, 0x9249, 0xBB32, 0x924A, 0xBB33, 0x924B, 0xBB37, 0x924C, 0xBB39, 0x924D, 0xBB3A, 0x924E, 0xBB3F, 0x924F, 0xBB40, 0x9250, 0xBB41, 0x9251, 0xBB42, 0x9252, 0xBB43, 0x9253, 0xBB46, 0x9254, 0xBB48, 0x9255, 0xBB4A, 0x9256, 0xBB4B, 0x9257, 0xBB4C, 0x9258, 0xBB4E, 0x9259, 0xBB51, 0x925A, 0xBB52, 0x9261, 0xBB53, 0x9262, 0xBB55, 0x9263, 0xBB56, 0x9264, 0xBB57, 0x9265, 0xBB59, 0x9266, 0xBB5A, 0x9267, 0xBB5B, 0x9268, 0xBB5C, 0x9269, 0xBB5D, 0x926A, 0xBB5E, 0x926B, 0xBB5F, 0x926C, 0xBB60, 0x926D, 0xBB62, 0x926E, 0xBB64, 0x926F, 0xBB65, 0x9270, 0xBB66, 0x9271, 0xBB67, 0x9272, 0xBB68, 0x9273, 0xBB69, 0x9274, 0xBB6A, 0x9275, 0xBB6B, 0x9276, 0xBB6D, 0x9277, 0xBB6E, 0x9278, 0xBB6F, 0x9279, 0xBB70, 0x927A, 0xBB71, 0x9281, 0xBB72, 0x9282, 0xBB73, 0x9283, 0xBB74, 0x9284, 0xBB75, 0x9285, 0xBB76, 0x9286, 0xBB77, 0x9287, 0xBB78, 0x9288, 0xBB79, 0x9289, 0xBB7A, 0x928A, 0xBB7B, 0x928B, 0xBB7C, 0x928C, 0xBB7D, 0x928D, 0xBB7E, 0x928E, 0xBB7F, 0x928F, 0xBB80, 0x9290, 0xBB81, 0x9291, 0xBB82, 0x9292, 0xBB83, 0x9293, 0xBB84, 0x9294, 0xBB85, 0x9295, 0xBB86, 0x9296, 0xBB87, 0x9297, 0xBB89, 0x9298, 0xBB8A, 0x9299, 0xBB8B, 0x929A, 0xBB8D, 0x929B, 0xBB8E, 0x929C, 0xBB8F, 0x929D, 0xBB91, 0x929E, 0xBB92, 0x929F, 0xBB93, 0x92A0, 0xBB94, 0x92A1, 0xBB95, 0x92A2, 0xBB96, 0x92A3, 0xBB97, 0x92A4, 0xBB98, 0x92A5, 0xBB99, 0x92A6, 0xBB9A, 0x92A7, 0xBB9B, 0x92A8, 0xBB9C, 0x92A9, 0xBB9D, 0x92AA, 0xBB9E, 0x92AB, 0xBB9F, 0x92AC, 0xBBA0, 0x92AD, 0xBBA1, 0x92AE, 0xBBA2, 0x92AF, 0xBBA3, 0x92B0, 0xBBA5, 0x92B1, 0xBBA6, 0x92B2, 0xBBA7, 0x92B3, 0xBBA9, 0x92B4, 0xBBAA, 0x92B5, 0xBBAB, 0x92B6, 0xBBAD, 0x92B7, 0xBBAE, 0x92B8, 0xBBAF, 0x92B9, 0xBBB0, 0x92BA, 0xBBB1, 0x92BB, 0xBBB2, 0x92BC, 0xBBB3, 0x92BD, 0xBBB5, 0x92BE, 0xBBB6, 0x92BF, 0xBBB8, 0x92C0, 0xBBB9, 0x92C1, 0xBBBA, 0x92C2, 0xBBBB, 0x92C3, 0xBBBC, 0x92C4, 0xBBBD, 0x92C5, 0xBBBE, 0x92C6, 0xBBBF, 0x92C7, 0xBBC1, 0x92C8, 0xBBC2, 0x92C9, 0xBBC3, 0x92CA, 0xBBC5, 0x92CB, 0xBBC6, 0x92CC, 0xBBC7, 0x92CD, 0xBBC9, 0x92CE, 0xBBCA, 0x92CF, 0xBBCB, 0x92D0, 0xBBCC, 0x92D1, 0xBBCD, 0x92D2, 0xBBCE, 0x92D3, 0xBBCF, 0x92D4, 0xBBD1, 0x92D5, 0xBBD2, 0x92D6, 0xBBD4, 0x92D7, 0xBBD5, 0x92D8, 0xBBD6, 0x92D9, 0xBBD7, 0x92DA, 0xBBD8, 0x92DB, 0xBBD9, 0x92DC, 0xBBDA, 0x92DD, 0xBBDB, 0x92DE, 0xBBDC, 0x92DF, 0xBBDD, 0x92E0, 0xBBDE, 0x92E1, 0xBBDF, 0x92E2, 0xBBE0, 0x92E3, 0xBBE1, 0x92E4, 0xBBE2, 0x92E5, 0xBBE3, 0x92E6, 0xBBE4, 0x92E7, 0xBBE5, 0x92E8, 0xBBE6, 0x92E9, 0xBBE7, 0x92EA, 0xBBE8, 0x92EB, 0xBBE9, 0x92EC, 0xBBEA, 0x92ED, 0xBBEB, 0x92EE, 0xBBEC, 0x92EF, 0xBBED, 0x92F0, 0xBBEE, 0x92F1, 0xBBEF, 0x92F2, 0xBBF0, 0x92F3, 0xBBF1, 0x92F4, 0xBBF2, 0x92F5, 0xBBF3, 0x92F6, 0xBBF4, 0x92F7, 0xBBF5, 0x92F8, 0xBBF6, 0x92F9, 0xBBF7, 0x92FA, 0xBBFA, 0x92FB, 0xBBFB, 0x92FC, 0xBBFD, 0x92FD, 0xBBFE, 0x92FE, 0xBC01, 0x9341, 0xBC03, 0x9342, 0xBC04, 0x9343, 0xBC05, 0x9344, 0xBC06, 0x9345, 0xBC07, 0x9346, 0xBC0A, 0x9347, 0xBC0E, 0x9348, 0xBC10, 0x9349, 0xBC12, 0x934A, 0xBC13, 0x934B, 0xBC19, 0x934C, 0xBC1A, 0x934D, 0xBC20, 0x934E, 0xBC21, 0x934F, 0xBC22, 0x9350, 0xBC23, 0x9351, 0xBC26, 0x9352, 0xBC28, 0x9353, 0xBC2A, 0x9354, 0xBC2B, 0x9355, 0xBC2C, 0x9356, 0xBC2E, 0x9357, 0xBC2F, 0x9358, 0xBC32, 0x9359, 0xBC33, 0x935A, 0xBC35, 0x9361, 0xBC36, 0x9362, 0xBC37, 0x9363, 0xBC39, 0x9364, 0xBC3A, 0x9365, 0xBC3B, 0x9366, 0xBC3C, 0x9367, 0xBC3D, 0x9368, 0xBC3E, 0x9369, 0xBC3F, 0x936A, 0xBC42, 0x936B, 0xBC46, 0x936C, 0xBC47, 0x936D, 0xBC48, 0x936E, 0xBC4A, 0x936F, 0xBC4B, 0x9370, 0xBC4E, 0x9371, 0xBC4F, 0x9372, 0xBC51, 0x9373, 0xBC52, 0x9374, 0xBC53, 0x9375, 0xBC54, 0x9376, 0xBC55, 0x9377, 0xBC56, 0x9378, 0xBC57, 0x9379, 0xBC58, 0x937A, 0xBC59, 0x9381, 0xBC5A, 0x9382, 0xBC5B, 0x9383, 0xBC5C, 0x9384, 0xBC5E, 0x9385, 0xBC5F, 0x9386, 0xBC60, 0x9387, 0xBC61, 0x9388, 0xBC62, 0x9389, 0xBC63, 0x938A, 0xBC64, 0x938B, 0xBC65, 0x938C, 0xBC66, 0x938D, 0xBC67, 0x938E, 0xBC68, 0x938F, 0xBC69, 0x9390, 0xBC6A, 0x9391, 0xBC6B, 0x9392, 0xBC6C, 0x9393, 0xBC6D, 0x9394, 0xBC6E, 0x9395, 0xBC6F, 0x9396, 0xBC70, 0x9397, 0xBC71, 0x9398, 0xBC72, 0x9399, 0xBC73, 0x939A, 0xBC74, 0x939B, 0xBC75, 0x939C, 0xBC76, 0x939D, 0xBC77, 0x939E, 0xBC78, 0x939F, 0xBC79, 0x93A0, 0xBC7A, 0x93A1, 0xBC7B, 0x93A2, 0xBC7C, 0x93A3, 0xBC7D, 0x93A4, 0xBC7E, 0x93A5, 0xBC7F, 0x93A6, 0xBC80, 0x93A7, 0xBC81, 0x93A8, 0xBC82, 0x93A9, 0xBC83, 0x93AA, 0xBC86, 0x93AB, 0xBC87, 0x93AC, 0xBC89, 0x93AD, 0xBC8A, 0x93AE, 0xBC8D, 0x93AF, 0xBC8F, 0x93B0, 0xBC90, 0x93B1, 0xBC91, 0x93B2, 0xBC92, 0x93B3, 0xBC93, 0x93B4, 0xBC96, 0x93B5, 0xBC98, 0x93B6, 0xBC9B, 0x93B7, 0xBC9C, 0x93B8, 0xBC9D, 0x93B9, 0xBC9E, 0x93BA, 0xBC9F, 0x93BB, 0xBCA2, 0x93BC, 0xBCA3, 0x93BD, 0xBCA5, 0x93BE, 0xBCA6, 0x93BF, 0xBCA9, 0x93C0, 0xBCAA, 0x93C1, 0xBCAB, 0x93C2, 0xBCAC, 0x93C3, 0xBCAD, 0x93C4, 0xBCAE, 0x93C5, 0xBCAF, 0x93C6, 0xBCB2, 0x93C7, 0xBCB6, 0x93C8, 0xBCB7, 0x93C9, 0xBCB8, 0x93CA, 0xBCB9, 0x93CB, 0xBCBA, 0x93CC, 0xBCBB, 0x93CD, 0xBCBE, 0x93CE, 0xBCBF, 0x93CF, 0xBCC1, 0x93D0, 0xBCC2, 0x93D1, 0xBCC3, 0x93D2, 0xBCC5, 0x93D3, 0xBCC6, 0x93D4, 0xBCC7, 0x93D5, 0xBCC8, 0x93D6, 0xBCC9, 0x93D7, 0xBCCA, 0x93D8, 0xBCCB, 0x93D9, 0xBCCC, 0x93DA, 0xBCCE, 0x93DB, 0xBCD2, 0x93DC, 0xBCD3, 0x93DD, 0xBCD4, 0x93DE, 0xBCD6, 0x93DF, 0xBCD7, 0x93E0, 0xBCD9, 0x93E1, 0xBCDA, 0x93E2, 0xBCDB, 0x93E3, 0xBCDD, 0x93E4, 0xBCDE, 0x93E5, 0xBCDF, 0x93E6, 0xBCE0, 0x93E7, 0xBCE1, 0x93E8, 0xBCE2, 0x93E9, 0xBCE3, 0x93EA, 0xBCE4, 0x93EB, 0xBCE5, 0x93EC, 0xBCE6, 0x93ED, 0xBCE7, 0x93EE, 0xBCE8, 0x93EF, 0xBCE9, 0x93F0, 0xBCEA, 0x93F1, 0xBCEB, 0x93F2, 0xBCEC, 0x93F3, 0xBCED, 0x93F4, 0xBCEE, 0x93F5, 0xBCEF, 0x93F6, 0xBCF0, 0x93F7, 0xBCF1, 0x93F8, 0xBCF2, 0x93F9, 0xBCF3, 0x93FA, 0xBCF7, 0x93FB, 0xBCF9, 0x93FC, 0xBCFA, 0x93FD, 0xBCFB, 0x93FE, 0xBCFD, 0x9441, 0xBCFE, 0x9442, 0xBCFF, 0x9443, 0xBD00, 0x9444, 0xBD01, 0x9445, 0xBD02, 0x9446, 0xBD03, 0x9447, 0xBD06, 0x9448, 0xBD08, 0x9449, 0xBD0A, 0x944A, 0xBD0B, 0x944B, 0xBD0C, 0x944C, 0xBD0D, 0x944D, 0xBD0E, 0x944E, 0xBD0F, 0x944F, 0xBD11, 0x9450, 0xBD12, 0x9451, 0xBD13, 0x9452, 0xBD15, 0x9453, 0xBD16, 0x9454, 0xBD17, 0x9455, 0xBD18, 0x9456, 0xBD19, 0x9457, 0xBD1A, 0x9458, 0xBD1B, 0x9459, 0xBD1C, 0x945A, 0xBD1D, 0x9461, 0xBD1E, 0x9462, 0xBD1F, 0x9463, 0xBD20, 0x9464, 0xBD21, 0x9465, 0xBD22, 0x9466, 0xBD23, 0x9467, 0xBD25, 0x9468, 0xBD26, 0x9469, 0xBD27, 0x946A, 0xBD28, 0x946B, 0xBD29, 0x946C, 0xBD2A, 0x946D, 0xBD2B, 0x946E, 0xBD2D, 0x946F, 0xBD2E, 0x9470, 0xBD2F, 0x9471, 0xBD30, 0x9472, 0xBD31, 0x9473, 0xBD32, 0x9474, 0xBD33, 0x9475, 0xBD34, 0x9476, 0xBD35, 0x9477, 0xBD36, 0x9478, 0xBD37, 0x9479, 0xBD38, 0x947A, 0xBD39, 0x9481, 0xBD3A, 0x9482, 0xBD3B, 0x9483, 0xBD3C, 0x9484, 0xBD3D, 0x9485, 0xBD3E, 0x9486, 0xBD3F, 0x9487, 0xBD41, 0x9488, 0xBD42, 0x9489, 0xBD43, 0x948A, 0xBD44, 0x948B, 0xBD45, 0x948C, 0xBD46, 0x948D, 0xBD47, 0x948E, 0xBD4A, 0x948F, 0xBD4B, 0x9490, 0xBD4D, 0x9491, 0xBD4E, 0x9492, 0xBD4F, 0x9493, 0xBD51, 0x9494, 0xBD52, 0x9495, 0xBD53, 0x9496, 0xBD54, 0x9497, 0xBD55, 0x9498, 0xBD56, 0x9499, 0xBD57, 0x949A, 0xBD5A, 0x949B, 0xBD5B, 0x949C, 0xBD5C, 0x949D, 0xBD5D, 0x949E, 0xBD5E, 0x949F, 0xBD5F, 0x94A0, 0xBD60, 0x94A1, 0xBD61, 0x94A2, 0xBD62, 0x94A3, 0xBD63, 0x94A4, 0xBD65, 0x94A5, 0xBD66, 0x94A6, 0xBD67, 0x94A7, 0xBD69, 0x94A8, 0xBD6A, 0x94A9, 0xBD6B, 0x94AA, 0xBD6C, 0x94AB, 0xBD6D, 0x94AC, 0xBD6E, 0x94AD, 0xBD6F, 0x94AE, 0xBD70, 0x94AF, 0xBD71, 0x94B0, 0xBD72, 0x94B1, 0xBD73, 0x94B2, 0xBD74, 0x94B3, 0xBD75, 0x94B4, 0xBD76, 0x94B5, 0xBD77, 0x94B6, 0xBD78, 0x94B7, 0xBD79, 0x94B8, 0xBD7A, 0x94B9, 0xBD7B, 0x94BA, 0xBD7C, 0x94BB, 0xBD7D, 0x94BC, 0xBD7E, 0x94BD, 0xBD7F, 0x94BE, 0xBD82, 0x94BF, 0xBD83, 0x94C0, 0xBD85, 0x94C1, 0xBD86, 0x94C2, 0xBD8B, 0x94C3, 0xBD8C, 0x94C4, 0xBD8D, 0x94C5, 0xBD8E, 0x94C6, 0xBD8F, 0x94C7, 0xBD92, 0x94C8, 0xBD94, 0x94C9, 0xBD96, 0x94CA, 0xBD97, 0x94CB, 0xBD98, 0x94CC, 0xBD9B, 0x94CD, 0xBD9D, 0x94CE, 0xBD9E, 0x94CF, 0xBD9F, 0x94D0, 0xBDA0, 0x94D1, 0xBDA1, 0x94D2, 0xBDA2, 0x94D3, 0xBDA3, 0x94D4, 0xBDA5, 0x94D5, 0xBDA6, 0x94D6, 0xBDA7, 0x94D7, 0xBDA8, 0x94D8, 0xBDA9, 0x94D9, 0xBDAA, 0x94DA, 0xBDAB, 0x94DB, 0xBDAC, 0x94DC, 0xBDAD, 0x94DD, 0xBDAE, 0x94DE, 0xBDAF, 0x94DF, 0xBDB1, 0x94E0, 0xBDB2, 0x94E1, 0xBDB3, 0x94E2, 0xBDB4, 0x94E3, 0xBDB5, 0x94E4, 0xBDB6, 0x94E5, 0xBDB7, 0x94E6, 0xBDB9, 0x94E7, 0xBDBA, 0x94E8, 0xBDBB, 0x94E9, 0xBDBC, 0x94EA, 0xBDBD, 0x94EB, 0xBDBE, 0x94EC, 0xBDBF, 0x94ED, 0xBDC0, 0x94EE, 0xBDC1, 0x94EF, 0xBDC2, 0x94F0, 0xBDC3, 0x94F1, 0xBDC4, 0x94F2, 0xBDC5, 0x94F3, 0xBDC6, 0x94F4, 0xBDC7, 0x94F5, 0xBDC8, 0x94F6, 0xBDC9, 0x94F7, 0xBDCA, 0x94F8, 0xBDCB, 0x94F9, 0xBDCC, 0x94FA, 0xBDCD, 0x94FB, 0xBDCE, 0x94FC, 0xBDCF, 0x94FD, 0xBDD0, 0x94FE, 0xBDD1, 0x9541, 0xBDD2, 0x9542, 0xBDD3, 0x9543, 0xBDD6, 0x9544, 0xBDD7, 0x9545, 0xBDD9, 0x9546, 0xBDDA, 0x9547, 0xBDDB, 0x9548, 0xBDDD, 0x9549, 0xBDDE, 0x954A, 0xBDDF, 0x954B, 0xBDE0, 0x954C, 0xBDE1, 0x954D, 0xBDE2, 0x954E, 0xBDE3, 0x954F, 0xBDE4, 0x9550, 0xBDE5, 0x9551, 0xBDE6, 0x9552, 0xBDE7, 0x9553, 0xBDE8, 0x9554, 0xBDEA, 0x9555, 0xBDEB, 0x9556, 0xBDEC, 0x9557, 0xBDED, 0x9558, 0xBDEE, 0x9559, 0xBDEF, 0x955A, 0xBDF1, 0x9561, 0xBDF2, 0x9562, 0xBDF3, 0x9563, 0xBDF5, 0x9564, 0xBDF6, 0x9565, 0xBDF7, 0x9566, 0xBDF9, 0x9567, 0xBDFA, 0x9568, 0xBDFB, 0x9569, 0xBDFC, 0x956A, 0xBDFD, 0x956B, 0xBDFE, 0x956C, 0xBDFF, 0x956D, 0xBE01, 0x956E, 0xBE02, 0x956F, 0xBE04, 0x9570, 0xBE06, 0x9571, 0xBE07, 0x9572, 0xBE08, 0x9573, 0xBE09, 0x9574, 0xBE0A, 0x9575, 0xBE0B, 0x9576, 0xBE0E, 0x9577, 0xBE0F, 0x9578, 0xBE11, 0x9579, 0xBE12, 0x957A, 0xBE13, 0x9581, 0xBE15, 0x9582, 0xBE16, 0x9583, 0xBE17, 0x9584, 0xBE18, 0x9585, 0xBE19, 0x9586, 0xBE1A, 0x9587, 0xBE1B, 0x9588, 0xBE1E, 0x9589, 0xBE20, 0x958A, 0xBE21, 0x958B, 0xBE22, 0x958C, 0xBE23, 0x958D, 0xBE24, 0x958E, 0xBE25, 0x958F, 0xBE26, 0x9590, 0xBE27, 0x9591, 0xBE28, 0x9592, 0xBE29, 0x9593, 0xBE2A, 0x9594, 0xBE2B, 0x9595, 0xBE2C, 0x9596, 0xBE2D, 0x9597, 0xBE2E, 0x9598, 0xBE2F, 0x9599, 0xBE30, 0x959A, 0xBE31, 0x959B, 0xBE32, 0x959C, 0xBE33, 0x959D, 0xBE34, 0x959E, 0xBE35, 0x959F, 0xBE36, 0x95A0, 0xBE37, 0x95A1, 0xBE38, 0x95A2, 0xBE39, 0x95A3, 0xBE3A, 0x95A4, 0xBE3B, 0x95A5, 0xBE3C, 0x95A6, 0xBE3D, 0x95A7, 0xBE3E, 0x95A8, 0xBE3F, 0x95A9, 0xBE40, 0x95AA, 0xBE41, 0x95AB, 0xBE42, 0x95AC, 0xBE43, 0x95AD, 0xBE46, 0x95AE, 0xBE47, 0x95AF, 0xBE49, 0x95B0, 0xBE4A, 0x95B1, 0xBE4B, 0x95B2, 0xBE4D, 0x95B3, 0xBE4F, 0x95B4, 0xBE50, 0x95B5, 0xBE51, 0x95B6, 0xBE52, 0x95B7, 0xBE53, 0x95B8, 0xBE56, 0x95B9, 0xBE58, 0x95BA, 0xBE5C, 0x95BB, 0xBE5D, 0x95BC, 0xBE5E, 0x95BD, 0xBE5F, 0x95BE, 0xBE62, 0x95BF, 0xBE63, 0x95C0, 0xBE65, 0x95C1, 0xBE66, 0x95C2, 0xBE67, 0x95C3, 0xBE69, 0x95C4, 0xBE6B, 0x95C5, 0xBE6C, 0x95C6, 0xBE6D, 0x95C7, 0xBE6E, 0x95C8, 0xBE6F, 0x95C9, 0xBE72, 0x95CA, 0xBE76, 0x95CB, 0xBE77, 0x95CC, 0xBE78, 0x95CD, 0xBE79, 0x95CE, 0xBE7A, 0x95CF, 0xBE7E, 0x95D0, 0xBE7F, 0x95D1, 0xBE81, 0x95D2, 0xBE82, 0x95D3, 0xBE83, 0x95D4, 0xBE85, 0x95D5, 0xBE86, 0x95D6, 0xBE87, 0x95D7, 0xBE88, 0x95D8, 0xBE89, 0x95D9, 0xBE8A, 0x95DA, 0xBE8B, 0x95DB, 0xBE8E, 0x95DC, 0xBE92, 0x95DD, 0xBE93, 0x95DE, 0xBE94, 0x95DF, 0xBE95, 0x95E0, 0xBE96, 0x95E1, 0xBE97, 0x95E2, 0xBE9A, 0x95E3, 0xBE9B, 0x95E4, 0xBE9C, 0x95E5, 0xBE9D, 0x95E6, 0xBE9E, 0x95E7, 0xBE9F, 0x95E8, 0xBEA0, 0x95E9, 0xBEA1, 0x95EA, 0xBEA2, 0x95EB, 0xBEA3, 0x95EC, 0xBEA4, 0x95ED, 0xBEA5, 0x95EE, 0xBEA6, 0x95EF, 0xBEA7, 0x95F0, 0xBEA9, 0x95F1, 0xBEAA, 0x95F2, 0xBEAB, 0x95F3, 0xBEAC, 0x95F4, 0xBEAD, 0x95F5, 0xBEAE, 0x95F6, 0xBEAF, 0x95F7, 0xBEB0, 0x95F8, 0xBEB1, 0x95F9, 0xBEB2, 0x95FA, 0xBEB3, 0x95FB, 0xBEB4, 0x95FC, 0xBEB5, 0x95FD, 0xBEB6, 0x95FE, 0xBEB7, 0x9641, 0xBEB8, 0x9642, 0xBEB9, 0x9643, 0xBEBA, 0x9644, 0xBEBB, 0x9645, 0xBEBC, 0x9646, 0xBEBD, 0x9647, 0xBEBE, 0x9648, 0xBEBF, 0x9649, 0xBEC0, 0x964A, 0xBEC1, 0x964B, 0xBEC2, 0x964C, 0xBEC3, 0x964D, 0xBEC4, 0x964E, 0xBEC5, 0x964F, 0xBEC6, 0x9650, 0xBEC7, 0x9651, 0xBEC8, 0x9652, 0xBEC9, 0x9653, 0xBECA, 0x9654, 0xBECB, 0x9655, 0xBECC, 0x9656, 0xBECD, 0x9657, 0xBECE, 0x9658, 0xBECF, 0x9659, 0xBED2, 0x965A, 0xBED3, 0x9661, 0xBED5, 0x9662, 0xBED6, 0x9663, 0xBED9, 0x9664, 0xBEDA, 0x9665, 0xBEDB, 0x9666, 0xBEDC, 0x9667, 0xBEDD, 0x9668, 0xBEDE, 0x9669, 0xBEDF, 0x966A, 0xBEE1, 0x966B, 0xBEE2, 0x966C, 0xBEE6, 0x966D, 0xBEE7, 0x966E, 0xBEE8, 0x966F, 0xBEE9, 0x9670, 0xBEEA, 0x9671, 0xBEEB, 0x9672, 0xBEED, 0x9673, 0xBEEE, 0x9674, 0xBEEF, 0x9675, 0xBEF0, 0x9676, 0xBEF1, 0x9677, 0xBEF2, 0x9678, 0xBEF3, 0x9679, 0xBEF4, 0x967A, 0xBEF5, 0x9681, 0xBEF6, 0x9682, 0xBEF7, 0x9683, 0xBEF8, 0x9684, 0xBEF9, 0x9685, 0xBEFA, 0x9686, 0xBEFB, 0x9687, 0xBEFC, 0x9688, 0xBEFD, 0x9689, 0xBEFE, 0x968A, 0xBEFF, 0x968B, 0xBF00, 0x968C, 0xBF02, 0x968D, 0xBF03, 0x968E, 0xBF04, 0x968F, 0xBF05, 0x9690, 0xBF06, 0x9691, 0xBF07, 0x9692, 0xBF0A, 0x9693, 0xBF0B, 0x9694, 0xBF0C, 0x9695, 0xBF0D, 0x9696, 0xBF0E, 0x9697, 0xBF0F, 0x9698, 0xBF10, 0x9699, 0xBF11, 0x969A, 0xBF12, 0x969B, 0xBF13, 0x969C, 0xBF14, 0x969D, 0xBF15, 0x969E, 0xBF16, 0x969F, 0xBF17, 0x96A0, 0xBF1A, 0x96A1, 0xBF1E, 0x96A2, 0xBF1F, 0x96A3, 0xBF20, 0x96A4, 0xBF21, 0x96A5, 0xBF22, 0x96A6, 0xBF23, 0x96A7, 0xBF24, 0x96A8, 0xBF25, 0x96A9, 0xBF26, 0x96AA, 0xBF27, 0x96AB, 0xBF28, 0x96AC, 0xBF29, 0x96AD, 0xBF2A, 0x96AE, 0xBF2B, 0x96AF, 0xBF2C, 0x96B0, 0xBF2D, 0x96B1, 0xBF2E, 0x96B2, 0xBF2F, 0x96B3, 0xBF30, 0x96B4, 0xBF31, 0x96B5, 0xBF32, 0x96B6, 0xBF33, 0x96B7, 0xBF34, 0x96B8, 0xBF35, 0x96B9, 0xBF36, 0x96BA, 0xBF37, 0x96BB, 0xBF38, 0x96BC, 0xBF39, 0x96BD, 0xBF3A, 0x96BE, 0xBF3B, 0x96BF, 0xBF3C, 0x96C0, 0xBF3D, 0x96C1, 0xBF3E, 0x96C2, 0xBF3F, 0x96C3, 0xBF42, 0x96C4, 0xBF43, 0x96C5, 0xBF45, 0x96C6, 0xBF46, 0x96C7, 0xBF47, 0x96C8, 0xBF49, 0x96C9, 0xBF4A, 0x96CA, 0xBF4B, 0x96CB, 0xBF4C, 0x96CC, 0xBF4D, 0x96CD, 0xBF4E, 0x96CE, 0xBF4F, 0x96CF, 0xBF52, 0x96D0, 0xBF53, 0x96D1, 0xBF54, 0x96D2, 0xBF56, 0x96D3, 0xBF57, 0x96D4, 0xBF58, 0x96D5, 0xBF59, 0x96D6, 0xBF5A, 0x96D7, 0xBF5B, 0x96D8, 0xBF5C, 0x96D9, 0xBF5D, 0x96DA, 0xBF5E, 0x96DB, 0xBF5F, 0x96DC, 0xBF60, 0x96DD, 0xBF61, 0x96DE, 0xBF62, 0x96DF, 0xBF63, 0x96E0, 0xBF64, 0x96E1, 0xBF65, 0x96E2, 0xBF66, 0x96E3, 0xBF67, 0x96E4, 0xBF68, 0x96E5, 0xBF69, 0x96E6, 0xBF6A, 0x96E7, 0xBF6B, 0x96E8, 0xBF6C, 0x96E9, 0xBF6D, 0x96EA, 0xBF6E, 0x96EB, 0xBF6F, 0x96EC, 0xBF70, 0x96ED, 0xBF71, 0x96EE, 0xBF72, 0x96EF, 0xBF73, 0x96F0, 0xBF74, 0x96F1, 0xBF75, 0x96F2, 0xBF76, 0x96F3, 0xBF77, 0x96F4, 0xBF78, 0x96F5, 0xBF79, 0x96F6, 0xBF7A, 0x96F7, 0xBF7B, 0x96F8, 0xBF7C, 0x96F9, 0xBF7D, 0x96FA, 0xBF7E, 0x96FB, 0xBF7F, 0x96FC, 0xBF80, 0x96FD, 0xBF81, 0x96FE, 0xBF82, 0x9741, 0xBF83, 0x9742, 0xBF84, 0x9743, 0xBF85, 0x9744, 0xBF86, 0x9745, 0xBF87, 0x9746, 0xBF88, 0x9747, 0xBF89, 0x9748, 0xBF8A, 0x9749, 0xBF8B, 0x974A, 0xBF8C, 0x974B, 0xBF8D, 0x974C, 0xBF8E, 0x974D, 0xBF8F, 0x974E, 0xBF90, 0x974F, 0xBF91, 0x9750, 0xBF92, 0x9751, 0xBF93, 0x9752, 0xBF95, 0x9753, 0xBF96, 0x9754, 0xBF97, 0x9755, 0xBF98, 0x9756, 0xBF99, 0x9757, 0xBF9A, 0x9758, 0xBF9B, 0x9759, 0xBF9C, 0x975A, 0xBF9D, 0x9761, 0xBF9E, 0x9762, 0xBF9F, 0x9763, 0xBFA0, 0x9764, 0xBFA1, 0x9765, 0xBFA2, 0x9766, 0xBFA3, 0x9767, 0xBFA4, 0x9768, 0xBFA5, 0x9769, 0xBFA6, 0x976A, 0xBFA7, 0x976B, 0xBFA8, 0x976C, 0xBFA9, 0x976D, 0xBFAA, 0x976E, 0xBFAB, 0x976F, 0xBFAC, 0x9770, 0xBFAD, 0x9771, 0xBFAE, 0x9772, 0xBFAF, 0x9773, 0xBFB1, 0x9774, 0xBFB2, 0x9775, 0xBFB3, 0x9776, 0xBFB4, 0x9777, 0xBFB5, 0x9778, 0xBFB6, 0x9779, 0xBFB7, 0x977A, 0xBFB8, 0x9781, 0xBFB9, 0x9782, 0xBFBA, 0x9783, 0xBFBB, 0x9784, 0xBFBC, 0x9785, 0xBFBD, 0x9786, 0xBFBE, 0x9787, 0xBFBF, 0x9788, 0xBFC0, 0x9789, 0xBFC1, 0x978A, 0xBFC2, 0x978B, 0xBFC3, 0x978C, 0xBFC4, 0x978D, 0xBFC6, 0x978E, 0xBFC7, 0x978F, 0xBFC8, 0x9790, 0xBFC9, 0x9791, 0xBFCA, 0x9792, 0xBFCB, 0x9793, 0xBFCE, 0x9794, 0xBFCF, 0x9795, 0xBFD1, 0x9796, 0xBFD2, 0x9797, 0xBFD3, 0x9798, 0xBFD5, 0x9799, 0xBFD6, 0x979A, 0xBFD7, 0x979B, 0xBFD8, 0x979C, 0xBFD9, 0x979D, 0xBFDA, 0x979E, 0xBFDB, 0x979F, 0xBFDD, 0x97A0, 0xBFDE, 0x97A1, 0xBFE0, 0x97A2, 0xBFE2, 0x97A3, 0xBFE3, 0x97A4, 0xBFE4, 0x97A5, 0xBFE5, 0x97A6, 0xBFE6, 0x97A7, 0xBFE7, 0x97A8, 0xBFE8, 0x97A9, 0xBFE9, 0x97AA, 0xBFEA, 0x97AB, 0xBFEB, 0x97AC, 0xBFEC, 0x97AD, 0xBFED, 0x97AE, 0xBFEE, 0x97AF, 0xBFEF, 0x97B0, 0xBFF0, 0x97B1, 0xBFF1, 0x97B2, 0xBFF2, 0x97B3, 0xBFF3, 0x97B4, 0xBFF4, 0x97B5, 0xBFF5, 0x97B6, 0xBFF6, 0x97B7, 0xBFF7, 0x97B8, 0xBFF8, 0x97B9, 0xBFF9, 0x97BA, 0xBFFA, 0x97BB, 0xBFFB, 0x97BC, 0xBFFC, 0x97BD, 0xBFFD, 0x97BE, 0xBFFE, 0x97BF, 0xBFFF, 0x97C0, 0xC000, 0x97C1, 0xC001, 0x97C2, 0xC002, 0x97C3, 0xC003, 0x97C4, 0xC004, 0x97C5, 0xC005, 0x97C6, 0xC006, 0x97C7, 0xC007, 0x97C8, 0xC008, 0x97C9, 0xC009, 0x97CA, 0xC00A, 0x97CB, 0xC00B, 0x97CC, 0xC00C, 0x97CD, 0xC00D, 0x97CE, 0xC00E, 0x97CF, 0xC00F, 0x97D0, 0xC010, 0x97D1, 0xC011, 0x97D2, 0xC012, 0x97D3, 0xC013, 0x97D4, 0xC014, 0x97D5, 0xC015, 0x97D6, 0xC016, 0x97D7, 0xC017, 0x97D8, 0xC018, 0x97D9, 0xC019, 0x97DA, 0xC01A, 0x97DB, 0xC01B, 0x97DC, 0xC01C, 0x97DD, 0xC01D, 0x97DE, 0xC01E, 0x97DF, 0xC01F, 0x97E0, 0xC020, 0x97E1, 0xC021, 0x97E2, 0xC022, 0x97E3, 0xC023, 0x97E4, 0xC024, 0x97E5, 0xC025, 0x97E6, 0xC026, 0x97E7, 0xC027, 0x97E8, 0xC028, 0x97E9, 0xC029, 0x97EA, 0xC02A, 0x97EB, 0xC02B, 0x97EC, 0xC02C, 0x97ED, 0xC02D, 0x97EE, 0xC02E, 0x97EF, 0xC02F, 0x97F0, 0xC030, 0x97F1, 0xC031, 0x97F2, 0xC032, 0x97F3, 0xC033, 0x97F4, 0xC034, 0x97F5, 0xC035, 0x97F6, 0xC036, 0x97F7, 0xC037, 0x97F8, 0xC038, 0x97F9, 0xC039, 0x97FA, 0xC03A, 0x97FB, 0xC03B, 0x97FC, 0xC03D, 0x97FD, 0xC03E, 0x97FE, 0xC03F, 0x9841, 0xC040, 0x9842, 0xC041, 0x9843, 0xC042, 0x9844, 0xC043, 0x9845, 0xC044, 0x9846, 0xC045, 0x9847, 0xC046, 0x9848, 0xC047, 0x9849, 0xC048, 0x984A, 0xC049, 0x984B, 0xC04A, 0x984C, 0xC04B, 0x984D, 0xC04C, 0x984E, 0xC04D, 0x984F, 0xC04E, 0x9850, 0xC04F, 0x9851, 0xC050, 0x9852, 0xC052, 0x9853, 0xC053, 0x9854, 0xC054, 0x9855, 0xC055, 0x9856, 0xC056, 0x9857, 0xC057, 0x9858, 0xC059, 0x9859, 0xC05A, 0x985A, 0xC05B, 0x9861, 0xC05D, 0x9862, 0xC05E, 0x9863, 0xC05F, 0x9864, 0xC061, 0x9865, 0xC062, 0x9866, 0xC063, 0x9867, 0xC064, 0x9868, 0xC065, 0x9869, 0xC066, 0x986A, 0xC067, 0x986B, 0xC06A, 0x986C, 0xC06B, 0x986D, 0xC06C, 0x986E, 0xC06D, 0x986F, 0xC06E, 0x9870, 0xC06F, 0x9871, 0xC070, 0x9872, 0xC071, 0x9873, 0xC072, 0x9874, 0xC073, 0x9875, 0xC074, 0x9876, 0xC075, 0x9877, 0xC076, 0x9878, 0xC077, 0x9879, 0xC078, 0x987A, 0xC079, 0x9881, 0xC07A, 0x9882, 0xC07B, 0x9883, 0xC07C, 0x9884, 0xC07D, 0x9885, 0xC07E, 0x9886, 0xC07F, 0x9887, 0xC080, 0x9888, 0xC081, 0x9889, 0xC082, 0x988A, 0xC083, 0x988B, 0xC084, 0x988C, 0xC085, 0x988D, 0xC086, 0x988E, 0xC087, 0x988F, 0xC088, 0x9890, 0xC089, 0x9891, 0xC08A, 0x9892, 0xC08B, 0x9893, 0xC08C, 0x9894, 0xC08D, 0x9895, 0xC08E, 0x9896, 0xC08F, 0x9897, 0xC092, 0x9898, 0xC093, 0x9899, 0xC095, 0x989A, 0xC096, 0x989B, 0xC097, 0x989C, 0xC099, 0x989D, 0xC09A, 0x989E, 0xC09B, 0x989F, 0xC09C, 0x98A0, 0xC09D, 0x98A1, 0xC09E, 0x98A2, 0xC09F, 0x98A3, 0xC0A2, 0x98A4, 0xC0A4, 0x98A5, 0xC0A6, 0x98A6, 0xC0A7, 0x98A7, 0xC0A8, 0x98A8, 0xC0A9, 0x98A9, 0xC0AA, 0x98AA, 0xC0AB, 0x98AB, 0xC0AE, 0x98AC, 0xC0B1, 0x98AD, 0xC0B2, 0x98AE, 0xC0B7, 0x98AF, 0xC0B8, 0x98B0, 0xC0B9, 0x98B1, 0xC0BA, 0x98B2, 0xC0BB, 0x98B3, 0xC0BE, 0x98B4, 0xC0C2, 0x98B5, 0xC0C3, 0x98B6, 0xC0C4, 0x98B7, 0xC0C6, 0x98B8, 0xC0C7, 0x98B9, 0xC0CA, 0x98BA, 0xC0CB, 0x98BB, 0xC0CD, 0x98BC, 0xC0CE, 0x98BD, 0xC0CF, 0x98BE, 0xC0D1, 0x98BF, 0xC0D2, 0x98C0, 0xC0D3, 0x98C1, 0xC0D4, 0x98C2, 0xC0D5, 0x98C3, 0xC0D6, 0x98C4, 0xC0D7, 0x98C5, 0xC0DA, 0x98C6, 0xC0DE, 0x98C7, 0xC0DF, 0x98C8, 0xC0E0, 0x98C9, 0xC0E1, 0x98CA, 0xC0E2, 0x98CB, 0xC0E3, 0x98CC, 0xC0E6, 0x98CD, 0xC0E7, 0x98CE, 0xC0E9, 0x98CF, 0xC0EA, 0x98D0, 0xC0EB, 0x98D1, 0xC0ED, 0x98D2, 0xC0EE, 0x98D3, 0xC0EF, 0x98D4, 0xC0F0, 0x98D5, 0xC0F1, 0x98D6, 0xC0F2, 0x98D7, 0xC0F3, 0x98D8, 0xC0F6, 0x98D9, 0xC0F8, 0x98DA, 0xC0FA, 0x98DB, 0xC0FB, 0x98DC, 0xC0FC, 0x98DD, 0xC0FD, 0x98DE, 0xC0FE, 0x98DF, 0xC0FF, 0x98E0, 0xC101, 0x98E1, 0xC102, 0x98E2, 0xC103, 0x98E3, 0xC105, 0x98E4, 0xC106, 0x98E5, 0xC107, 0x98E6, 0xC109, 0x98E7, 0xC10A, 0x98E8, 0xC10B, 0x98E9, 0xC10C, 0x98EA, 0xC10D, 0x98EB, 0xC10E, 0x98EC, 0xC10F, 0x98ED, 0xC111, 0x98EE, 0xC112, 0x98EF, 0xC113, 0x98F0, 0xC114, 0x98F1, 0xC116, 0x98F2, 0xC117, 0x98F3, 0xC118, 0x98F4, 0xC119, 0x98F5, 0xC11A, 0x98F6, 0xC11B, 0x98F7, 0xC121, 0x98F8, 0xC122, 0x98F9, 0xC125, 0x98FA, 0xC128, 0x98FB, 0xC129, 0x98FC, 0xC12A, 0x98FD, 0xC12B, 0x98FE, 0xC12E, 0x9941, 0xC132, 0x9942, 0xC133, 0x9943, 0xC134, 0x9944, 0xC135, 0x9945, 0xC137, 0x9946, 0xC13A, 0x9947, 0xC13B, 0x9948, 0xC13D, 0x9949, 0xC13E, 0x994A, 0xC13F, 0x994B, 0xC141, 0x994C, 0xC142, 0x994D, 0xC143, 0x994E, 0xC144, 0x994F, 0xC145, 0x9950, 0xC146, 0x9951, 0xC147, 0x9952, 0xC14A, 0x9953, 0xC14E, 0x9954, 0xC14F, 0x9955, 0xC150, 0x9956, 0xC151, 0x9957, 0xC152, 0x9958, 0xC153, 0x9959, 0xC156, 0x995A, 0xC157, 0x9961, 0xC159, 0x9962, 0xC15A, 0x9963, 0xC15B, 0x9964, 0xC15D, 0x9965, 0xC15E, 0x9966, 0xC15F, 0x9967, 0xC160, 0x9968, 0xC161, 0x9969, 0xC162, 0x996A, 0xC163, 0x996B, 0xC166, 0x996C, 0xC16A, 0x996D, 0xC16B, 0x996E, 0xC16C, 0x996F, 0xC16D, 0x9970, 0xC16E, 0x9971, 0xC16F, 0x9972, 0xC171, 0x9973, 0xC172, 0x9974, 0xC173, 0x9975, 0xC175, 0x9976, 0xC176, 0x9977, 0xC177, 0x9978, 0xC179, 0x9979, 0xC17A, 0x997A, 0xC17B, 0x9981, 0xC17C, 0x9982, 0xC17D, 0x9983, 0xC17E, 0x9984, 0xC17F, 0x9985, 0xC180, 0x9986, 0xC181, 0x9987, 0xC182, 0x9988, 0xC183, 0x9989, 0xC184, 0x998A, 0xC186, 0x998B, 0xC187, 0x998C, 0xC188, 0x998D, 0xC189, 0x998E, 0xC18A, 0x998F, 0xC18B, 0x9990, 0xC18F, 0x9991, 0xC191, 0x9992, 0xC192, 0x9993, 0xC193, 0x9994, 0xC195, 0x9995, 0xC197, 0x9996, 0xC198, 0x9997, 0xC199, 0x9998, 0xC19A, 0x9999, 0xC19B, 0x999A, 0xC19E, 0x999B, 0xC1A0, 0x999C, 0xC1A2, 0x999D, 0xC1A3, 0x999E, 0xC1A4, 0x999F, 0xC1A6, 0x99A0, 0xC1A7, 0x99A1, 0xC1AA, 0x99A2, 0xC1AB, 0x99A3, 0xC1AD, 0x99A4, 0xC1AE, 0x99A5, 0xC1AF, 0x99A6, 0xC1B1, 0x99A7, 0xC1B2, 0x99A8, 0xC1B3, 0x99A9, 0xC1B4, 0x99AA, 0xC1B5, 0x99AB, 0xC1B6, 0x99AC, 0xC1B7, 0x99AD, 0xC1B8, 0x99AE, 0xC1B9, 0x99AF, 0xC1BA, 0x99B0, 0xC1BB, 0x99B1, 0xC1BC, 0x99B2, 0xC1BE, 0x99B3, 0xC1BF, 0x99B4, 0xC1C0, 0x99B5, 0xC1C1, 0x99B6, 0xC1C2, 0x99B7, 0xC1C3, 0x99B8, 0xC1C5, 0x99B9, 0xC1C6, 0x99BA, 0xC1C7, 0x99BB, 0xC1C9, 0x99BC, 0xC1CA, 0x99BD, 0xC1CB, 0x99BE, 0xC1CD, 0x99BF, 0xC1CE, 0x99C0, 0xC1CF, 0x99C1, 0xC1D0, 0x99C2, 0xC1D1, 0x99C3, 0xC1D2, 0x99C4, 0xC1D3, 0x99C5, 0xC1D5, 0x99C6, 0xC1D6, 0x99C7, 0xC1D9, 0x99C8, 0xC1DA, 0x99C9, 0xC1DB, 0x99CA, 0xC1DC, 0x99CB, 0xC1DD, 0x99CC, 0xC1DE, 0x99CD, 0xC1DF, 0x99CE, 0xC1E1, 0x99CF, 0xC1E2, 0x99D0, 0xC1E3, 0x99D1, 0xC1E5, 0x99D2, 0xC1E6, 0x99D3, 0xC1E7, 0x99D4, 0xC1E9, 0x99D5, 0xC1EA, 0x99D6, 0xC1EB, 0x99D7, 0xC1EC, 0x99D8, 0xC1ED, 0x99D9, 0xC1EE, 0x99DA, 0xC1EF, 0x99DB, 0xC1F2, 0x99DC, 0xC1F4, 0x99DD, 0xC1F5, 0x99DE, 0xC1F6, 0x99DF, 0xC1F7, 0x99E0, 0xC1F8, 0x99E1, 0xC1F9, 0x99E2, 0xC1FA, 0x99E3, 0xC1FB, 0x99E4, 0xC1FE, 0x99E5, 0xC1FF, 0x99E6, 0xC201, 0x99E7, 0xC202, 0x99E8, 0xC203, 0x99E9, 0xC205, 0x99EA, 0xC206, 0x99EB, 0xC207, 0x99EC, 0xC208, 0x99ED, 0xC209, 0x99EE, 0xC20A, 0x99EF, 0xC20B, 0x99F0, 0xC20E, 0x99F1, 0xC210, 0x99F2, 0xC212, 0x99F3, 0xC213, 0x99F4, 0xC214, 0x99F5, 0xC215, 0x99F6, 0xC216, 0x99F7, 0xC217, 0x99F8, 0xC21A, 0x99F9, 0xC21B, 0x99FA, 0xC21D, 0x99FB, 0xC21E, 0x99FC, 0xC221, 0x99FD, 0xC222, 0x99FE, 0xC223, 0x9A41, 0xC224, 0x9A42, 0xC225, 0x9A43, 0xC226, 0x9A44, 0xC227, 0x9A45, 0xC22A, 0x9A46, 0xC22C, 0x9A47, 0xC22E, 0x9A48, 0xC230, 0x9A49, 0xC233, 0x9A4A, 0xC235, 0x9A4B, 0xC236, 0x9A4C, 0xC237, 0x9A4D, 0xC238, 0x9A4E, 0xC239, 0x9A4F, 0xC23A, 0x9A50, 0xC23B, 0x9A51, 0xC23C, 0x9A52, 0xC23D, 0x9A53, 0xC23E, 0x9A54, 0xC23F, 0x9A55, 0xC240, 0x9A56, 0xC241, 0x9A57, 0xC242, 0x9A58, 0xC243, 0x9A59, 0xC244, 0x9A5A, 0xC245, 0x9A61, 0xC246, 0x9A62, 0xC247, 0x9A63, 0xC249, 0x9A64, 0xC24A, 0x9A65, 0xC24B, 0x9A66, 0xC24C, 0x9A67, 0xC24D, 0x9A68, 0xC24E, 0x9A69, 0xC24F, 0x9A6A, 0xC252, 0x9A6B, 0xC253, 0x9A6C, 0xC255, 0x9A6D, 0xC256, 0x9A6E, 0xC257, 0x9A6F, 0xC259, 0x9A70, 0xC25A, 0x9A71, 0xC25B, 0x9A72, 0xC25C, 0x9A73, 0xC25D, 0x9A74, 0xC25E, 0x9A75, 0xC25F, 0x9A76, 0xC261, 0x9A77, 0xC262, 0x9A78, 0xC263, 0x9A79, 0xC264, 0x9A7A, 0xC266, 0x9A81, 0xC267, 0x9A82, 0xC268, 0x9A83, 0xC269, 0x9A84, 0xC26A, 0x9A85, 0xC26B, 0x9A86, 0xC26E, 0x9A87, 0xC26F, 0x9A88, 0xC271, 0x9A89, 0xC272, 0x9A8A, 0xC273, 0x9A8B, 0xC275, 0x9A8C, 0xC276, 0x9A8D, 0xC277, 0x9A8E, 0xC278, 0x9A8F, 0xC279, 0x9A90, 0xC27A, 0x9A91, 0xC27B, 0x9A92, 0xC27E, 0x9A93, 0xC280, 0x9A94, 0xC282, 0x9A95, 0xC283, 0x9A96, 0xC284, 0x9A97, 0xC285, 0x9A98, 0xC286, 0x9A99, 0xC287, 0x9A9A, 0xC28A, 0x9A9B, 0xC28B, 0x9A9C, 0xC28C, 0x9A9D, 0xC28D, 0x9A9E, 0xC28E, 0x9A9F, 0xC28F, 0x9AA0, 0xC291, 0x9AA1, 0xC292, 0x9AA2, 0xC293, 0x9AA3, 0xC294, 0x9AA4, 0xC295, 0x9AA5, 0xC296, 0x9AA6, 0xC297, 0x9AA7, 0xC299, 0x9AA8, 0xC29A, 0x9AA9, 0xC29C, 0x9AAA, 0xC29E, 0x9AAB, 0xC29F, 0x9AAC, 0xC2A0, 0x9AAD, 0xC2A1, 0x9AAE, 0xC2A2, 0x9AAF, 0xC2A3, 0x9AB0, 0xC2A6, 0x9AB1, 0xC2A7, 0x9AB2, 0xC2A9, 0x9AB3, 0xC2AA, 0x9AB4, 0xC2AB, 0x9AB5, 0xC2AE, 0x9AB6, 0xC2AF, 0x9AB7, 0xC2B0, 0x9AB8, 0xC2B1, 0x9AB9, 0xC2B2, 0x9ABA, 0xC2B3, 0x9ABB, 0xC2B6, 0x9ABC, 0xC2B8, 0x9ABD, 0xC2BA, 0x9ABE, 0xC2BB, 0x9ABF, 0xC2BC, 0x9AC0, 0xC2BD, 0x9AC1, 0xC2BE, 0x9AC2, 0xC2BF, 0x9AC3, 0xC2C0, 0x9AC4, 0xC2C1, 0x9AC5, 0xC2C2, 0x9AC6, 0xC2C3, 0x9AC7, 0xC2C4, 0x9AC8, 0xC2C5, 0x9AC9, 0xC2C6, 0x9ACA, 0xC2C7, 0x9ACB, 0xC2C8, 0x9ACC, 0xC2C9, 0x9ACD, 0xC2CA, 0x9ACE, 0xC2CB, 0x9ACF, 0xC2CC, 0x9AD0, 0xC2CD, 0x9AD1, 0xC2CE, 0x9AD2, 0xC2CF, 0x9AD3, 0xC2D0, 0x9AD4, 0xC2D1, 0x9AD5, 0xC2D2, 0x9AD6, 0xC2D3, 0x9AD7, 0xC2D4, 0x9AD8, 0xC2D5, 0x9AD9, 0xC2D6, 0x9ADA, 0xC2D7, 0x9ADB, 0xC2D8, 0x9ADC, 0xC2D9, 0x9ADD, 0xC2DA, 0x9ADE, 0xC2DB, 0x9ADF, 0xC2DE, 0x9AE0, 0xC2DF, 0x9AE1, 0xC2E1, 0x9AE2, 0xC2E2, 0x9AE3, 0xC2E5, 0x9AE4, 0xC2E6, 0x9AE5, 0xC2E7, 0x9AE6, 0xC2E8, 0x9AE7, 0xC2E9, 0x9AE8, 0xC2EA, 0x9AE9, 0xC2EE, 0x9AEA, 0xC2F0, 0x9AEB, 0xC2F2, 0x9AEC, 0xC2F3, 0x9AED, 0xC2F4, 0x9AEE, 0xC2F5, 0x9AEF, 0xC2F7, 0x9AF0, 0xC2FA, 0x9AF1, 0xC2FD, 0x9AF2, 0xC2FE, 0x9AF3, 0xC2FF, 0x9AF4, 0xC301, 0x9AF5, 0xC302, 0x9AF6, 0xC303, 0x9AF7, 0xC304, 0x9AF8, 0xC305, 0x9AF9, 0xC306, 0x9AFA, 0xC307, 0x9AFB, 0xC30A, 0x9AFC, 0xC30B, 0x9AFD, 0xC30E, 0x9AFE, 0xC30F, 0x9B41, 0xC310, 0x9B42, 0xC311, 0x9B43, 0xC312, 0x9B44, 0xC316, 0x9B45, 0xC317, 0x9B46, 0xC319, 0x9B47, 0xC31A, 0x9B48, 0xC31B, 0x9B49, 0xC31D, 0x9B4A, 0xC31E, 0x9B4B, 0xC31F, 0x9B4C, 0xC320, 0x9B4D, 0xC321, 0x9B4E, 0xC322, 0x9B4F, 0xC323, 0x9B50, 0xC326, 0x9B51, 0xC327, 0x9B52, 0xC32A, 0x9B53, 0xC32B, 0x9B54, 0xC32C, 0x9B55, 0xC32D, 0x9B56, 0xC32E, 0x9B57, 0xC32F, 0x9B58, 0xC330, 0x9B59, 0xC331, 0x9B5A, 0xC332, 0x9B61, 0xC333, 0x9B62, 0xC334, 0x9B63, 0xC335, 0x9B64, 0xC336, 0x9B65, 0xC337, 0x9B66, 0xC338, 0x9B67, 0xC339, 0x9B68, 0xC33A, 0x9B69, 0xC33B, 0x9B6A, 0xC33C, 0x9B6B, 0xC33D, 0x9B6C, 0xC33E, 0x9B6D, 0xC33F, 0x9B6E, 0xC340, 0x9B6F, 0xC341, 0x9B70, 0xC342, 0x9B71, 0xC343, 0x9B72, 0xC344, 0x9B73, 0xC346, 0x9B74, 0xC347, 0x9B75, 0xC348, 0x9B76, 0xC349, 0x9B77, 0xC34A, 0x9B78, 0xC34B, 0x9B79, 0xC34C, 0x9B7A, 0xC34D, 0x9B81, 0xC34E, 0x9B82, 0xC34F, 0x9B83, 0xC350, 0x9B84, 0xC351, 0x9B85, 0xC352, 0x9B86, 0xC353, 0x9B87, 0xC354, 0x9B88, 0xC355, 0x9B89, 0xC356, 0x9B8A, 0xC357, 0x9B8B, 0xC358, 0x9B8C, 0xC359, 0x9B8D, 0xC35A, 0x9B8E, 0xC35B, 0x9B8F, 0xC35C, 0x9B90, 0xC35D, 0x9B91, 0xC35E, 0x9B92, 0xC35F, 0x9B93, 0xC360, 0x9B94, 0xC361, 0x9B95, 0xC362, 0x9B96, 0xC363, 0x9B97, 0xC364, 0x9B98, 0xC365, 0x9B99, 0xC366, 0x9B9A, 0xC367, 0x9B9B, 0xC36A, 0x9B9C, 0xC36B, 0x9B9D, 0xC36D, 0x9B9E, 0xC36E, 0x9B9F, 0xC36F, 0x9BA0, 0xC371, 0x9BA1, 0xC373, 0x9BA2, 0xC374, 0x9BA3, 0xC375, 0x9BA4, 0xC376, 0x9BA5, 0xC377, 0x9BA6, 0xC37A, 0x9BA7, 0xC37B, 0x9BA8, 0xC37E, 0x9BA9, 0xC37F, 0x9BAA, 0xC380, 0x9BAB, 0xC381, 0x9BAC, 0xC382, 0x9BAD, 0xC383, 0x9BAE, 0xC385, 0x9BAF, 0xC386, 0x9BB0, 0xC387, 0x9BB1, 0xC389, 0x9BB2, 0xC38A, 0x9BB3, 0xC38B, 0x9BB4, 0xC38D, 0x9BB5, 0xC38E, 0x9BB6, 0xC38F, 0x9BB7, 0xC390, 0x9BB8, 0xC391, 0x9BB9, 0xC392, 0x9BBA, 0xC393, 0x9BBB, 0xC394, 0x9BBC, 0xC395, 0x9BBD, 0xC396, 0x9BBE, 0xC397, 0x9BBF, 0xC398, 0x9BC0, 0xC399, 0x9BC1, 0xC39A, 0x9BC2, 0xC39B, 0x9BC3, 0xC39C, 0x9BC4, 0xC39D, 0x9BC5, 0xC39E, 0x9BC6, 0xC39F, 0x9BC7, 0xC3A0, 0x9BC8, 0xC3A1, 0x9BC9, 0xC3A2, 0x9BCA, 0xC3A3, 0x9BCB, 0xC3A4, 0x9BCC, 0xC3A5, 0x9BCD, 0xC3A6, 0x9BCE, 0xC3A7, 0x9BCF, 0xC3A8, 0x9BD0, 0xC3A9, 0x9BD1, 0xC3AA, 0x9BD2, 0xC3AB, 0x9BD3, 0xC3AC, 0x9BD4, 0xC3AD, 0x9BD5, 0xC3AE, 0x9BD6, 0xC3AF, 0x9BD7, 0xC3B0, 0x9BD8, 0xC3B1, 0x9BD9, 0xC3B2, 0x9BDA, 0xC3B3, 0x9BDB, 0xC3B4, 0x9BDC, 0xC3B5, 0x9BDD, 0xC3B6, 0x9BDE, 0xC3B7, 0x9BDF, 0xC3B8, 0x9BE0, 0xC3B9, 0x9BE1, 0xC3BA, 0x9BE2, 0xC3BB, 0x9BE3, 0xC3BC, 0x9BE4, 0xC3BD, 0x9BE5, 0xC3BE, 0x9BE6, 0xC3BF, 0x9BE7, 0xC3C1, 0x9BE8, 0xC3C2, 0x9BE9, 0xC3C3, 0x9BEA, 0xC3C4, 0x9BEB, 0xC3C5, 0x9BEC, 0xC3C6, 0x9BED, 0xC3C7, 0x9BEE, 0xC3C8, 0x9BEF, 0xC3C9, 0x9BF0, 0xC3CA, 0x9BF1, 0xC3CB, 0x9BF2, 0xC3CC, 0x9BF3, 0xC3CD, 0x9BF4, 0xC3CE, 0x9BF5, 0xC3CF, 0x9BF6, 0xC3D0, 0x9BF7, 0xC3D1, 0x9BF8, 0xC3D2, 0x9BF9, 0xC3D3, 0x9BFA, 0xC3D4, 0x9BFB, 0xC3D5, 0x9BFC, 0xC3D6, 0x9BFD, 0xC3D7, 0x9BFE, 0xC3DA, 0x9C41, 0xC3DB, 0x9C42, 0xC3DD, 0x9C43, 0xC3DE, 0x9C44, 0xC3E1, 0x9C45, 0xC3E3, 0x9C46, 0xC3E4, 0x9C47, 0xC3E5, 0x9C48, 0xC3E6, 0x9C49, 0xC3E7, 0x9C4A, 0xC3EA, 0x9C4B, 0xC3EB, 0x9C4C, 0xC3EC, 0x9C4D, 0xC3EE, 0x9C4E, 0xC3EF, 0x9C4F, 0xC3F0, 0x9C50, 0xC3F1, 0x9C51, 0xC3F2, 0x9C52, 0xC3F3, 0x9C53, 0xC3F6, 0x9C54, 0xC3F7, 0x9C55, 0xC3F9, 0x9C56, 0xC3FA, 0x9C57, 0xC3FB, 0x9C58, 0xC3FC, 0x9C59, 0xC3FD, 0x9C5A, 0xC3FE, 0x9C61, 0xC3FF, 0x9C62, 0xC400, 0x9C63, 0xC401, 0x9C64, 0xC402, 0x9C65, 0xC403, 0x9C66, 0xC404, 0x9C67, 0xC405, 0x9C68, 0xC406, 0x9C69, 0xC407, 0x9C6A, 0xC409, 0x9C6B, 0xC40A, 0x9C6C, 0xC40B, 0x9C6D, 0xC40C, 0x9C6E, 0xC40D, 0x9C6F, 0xC40E, 0x9C70, 0xC40F, 0x9C71, 0xC411, 0x9C72, 0xC412, 0x9C73, 0xC413, 0x9C74, 0xC414, 0x9C75, 0xC415, 0x9C76, 0xC416, 0x9C77, 0xC417, 0x9C78, 0xC418, 0x9C79, 0xC419, 0x9C7A, 0xC41A, 0x9C81, 0xC41B, 0x9C82, 0xC41C, 0x9C83, 0xC41D, 0x9C84, 0xC41E, 0x9C85, 0xC41F, 0x9C86, 0xC420, 0x9C87, 0xC421, 0x9C88, 0xC422, 0x9C89, 0xC423, 0x9C8A, 0xC425, 0x9C8B, 0xC426, 0x9C8C, 0xC427, 0x9C8D, 0xC428, 0x9C8E, 0xC429, 0x9C8F, 0xC42A, 0x9C90, 0xC42B, 0x9C91, 0xC42D, 0x9C92, 0xC42E, 0x9C93, 0xC42F, 0x9C94, 0xC431, 0x9C95, 0xC432, 0x9C96, 0xC433, 0x9C97, 0xC435, 0x9C98, 0xC436, 0x9C99, 0xC437, 0x9C9A, 0xC438, 0x9C9B, 0xC439, 0x9C9C, 0xC43A, 0x9C9D, 0xC43B, 0x9C9E, 0xC43E, 0x9C9F, 0xC43F, 0x9CA0, 0xC440, 0x9CA1, 0xC441, 0x9CA2, 0xC442, 0x9CA3, 0xC443, 0x9CA4, 0xC444, 0x9CA5, 0xC445, 0x9CA6, 0xC446, 0x9CA7, 0xC447, 0x9CA8, 0xC449, 0x9CA9, 0xC44A, 0x9CAA, 0xC44B, 0x9CAB, 0xC44C, 0x9CAC, 0xC44D, 0x9CAD, 0xC44E, 0x9CAE, 0xC44F, 0x9CAF, 0xC450, 0x9CB0, 0xC451, 0x9CB1, 0xC452, 0x9CB2, 0xC453, 0x9CB3, 0xC454, 0x9CB4, 0xC455, 0x9CB5, 0xC456, 0x9CB6, 0xC457, 0x9CB7, 0xC458, 0x9CB8, 0xC459, 0x9CB9, 0xC45A, 0x9CBA, 0xC45B, 0x9CBB, 0xC45C, 0x9CBC, 0xC45D, 0x9CBD, 0xC45E, 0x9CBE, 0xC45F, 0x9CBF, 0xC460, 0x9CC0, 0xC461, 0x9CC1, 0xC462, 0x9CC2, 0xC463, 0x9CC3, 0xC466, 0x9CC4, 0xC467, 0x9CC5, 0xC469, 0x9CC6, 0xC46A, 0x9CC7, 0xC46B, 0x9CC8, 0xC46D, 0x9CC9, 0xC46E, 0x9CCA, 0xC46F, 0x9CCB, 0xC470, 0x9CCC, 0xC471, 0x9CCD, 0xC472, 0x9CCE, 0xC473, 0x9CCF, 0xC476, 0x9CD0, 0xC477, 0x9CD1, 0xC478, 0x9CD2, 0xC47A, 0x9CD3, 0xC47B, 0x9CD4, 0xC47C, 0x9CD5, 0xC47D, 0x9CD6, 0xC47E, 0x9CD7, 0xC47F, 0x9CD8, 0xC481, 0x9CD9, 0xC482, 0x9CDA, 0xC483, 0x9CDB, 0xC484, 0x9CDC, 0xC485, 0x9CDD, 0xC486, 0x9CDE, 0xC487, 0x9CDF, 0xC488, 0x9CE0, 0xC489, 0x9CE1, 0xC48A, 0x9CE2, 0xC48B, 0x9CE3, 0xC48C, 0x9CE4, 0xC48D, 0x9CE5, 0xC48E, 0x9CE6, 0xC48F, 0x9CE7, 0xC490, 0x9CE8, 0xC491, 0x9CE9, 0xC492, 0x9CEA, 0xC493, 0x9CEB, 0xC495, 0x9CEC, 0xC496, 0x9CED, 0xC497, 0x9CEE, 0xC498, 0x9CEF, 0xC499, 0x9CF0, 0xC49A, 0x9CF1, 0xC49B, 0x9CF2, 0xC49D, 0x9CF3, 0xC49E, 0x9CF4, 0xC49F, 0x9CF5, 0xC4A0, 0x9CF6, 0xC4A1, 0x9CF7, 0xC4A2, 0x9CF8, 0xC4A3, 0x9CF9, 0xC4A4, 0x9CFA, 0xC4A5, 0x9CFB, 0xC4A6, 0x9CFC, 0xC4A7, 0x9CFD, 0xC4A8, 0x9CFE, 0xC4A9, 0x9D41, 0xC4AA, 0x9D42, 0xC4AB, 0x9D43, 0xC4AC, 0x9D44, 0xC4AD, 0x9D45, 0xC4AE, 0x9D46, 0xC4AF, 0x9D47, 0xC4B0, 0x9D48, 0xC4B1, 0x9D49, 0xC4B2, 0x9D4A, 0xC4B3, 0x9D4B, 0xC4B4, 0x9D4C, 0xC4B5, 0x9D4D, 0xC4B6, 0x9D4E, 0xC4B7, 0x9D4F, 0xC4B9, 0x9D50, 0xC4BA, 0x9D51, 0xC4BB, 0x9D52, 0xC4BD, 0x9D53, 0xC4BE, 0x9D54, 0xC4BF, 0x9D55, 0xC4C0, 0x9D56, 0xC4C1, 0x9D57, 0xC4C2, 0x9D58, 0xC4C3, 0x9D59, 0xC4C4, 0x9D5A, 0xC4C5, 0x9D61, 0xC4C6, 0x9D62, 0xC4C7, 0x9D63, 0xC4C8, 0x9D64, 0xC4C9, 0x9D65, 0xC4CA, 0x9D66, 0xC4CB, 0x9D67, 0xC4CC, 0x9D68, 0xC4CD, 0x9D69, 0xC4CE, 0x9D6A, 0xC4CF, 0x9D6B, 0xC4D0, 0x9D6C, 0xC4D1, 0x9D6D, 0xC4D2, 0x9D6E, 0xC4D3, 0x9D6F, 0xC4D4, 0x9D70, 0xC4D5, 0x9D71, 0xC4D6, 0x9D72, 0xC4D7, 0x9D73, 0xC4D8, 0x9D74, 0xC4D9, 0x9D75, 0xC4DA, 0x9D76, 0xC4DB, 0x9D77, 0xC4DC, 0x9D78, 0xC4DD, 0x9D79, 0xC4DE, 0x9D7A, 0xC4DF, 0x9D81, 0xC4E0, 0x9D82, 0xC4E1, 0x9D83, 0xC4E2, 0x9D84, 0xC4E3, 0x9D85, 0xC4E4, 0x9D86, 0xC4E5, 0x9D87, 0xC4E6, 0x9D88, 0xC4E7, 0x9D89, 0xC4E8, 0x9D8A, 0xC4EA, 0x9D8B, 0xC4EB, 0x9D8C, 0xC4EC, 0x9D8D, 0xC4ED, 0x9D8E, 0xC4EE, 0x9D8F, 0xC4EF, 0x9D90, 0xC4F2, 0x9D91, 0xC4F3, 0x9D92, 0xC4F5, 0x9D93, 0xC4F6, 0x9D94, 0xC4F7, 0x9D95, 0xC4F9, 0x9D96, 0xC4FB, 0x9D97, 0xC4FC, 0x9D98, 0xC4FD, 0x9D99, 0xC4FE, 0x9D9A, 0xC502, 0x9D9B, 0xC503, 0x9D9C, 0xC504, 0x9D9D, 0xC505, 0x9D9E, 0xC506, 0x9D9F, 0xC507, 0x9DA0, 0xC508, 0x9DA1, 0xC509, 0x9DA2, 0xC50A, 0x9DA3, 0xC50B, 0x9DA4, 0xC50D, 0x9DA5, 0xC50E, 0x9DA6, 0xC50F, 0x9DA7, 0xC511, 0x9DA8, 0xC512, 0x9DA9, 0xC513, 0x9DAA, 0xC515, 0x9DAB, 0xC516, 0x9DAC, 0xC517, 0x9DAD, 0xC518, 0x9DAE, 0xC519, 0x9DAF, 0xC51A, 0x9DB0, 0xC51B, 0x9DB1, 0xC51D, 0x9DB2, 0xC51E, 0x9DB3, 0xC51F, 0x9DB4, 0xC520, 0x9DB5, 0xC521, 0x9DB6, 0xC522, 0x9DB7, 0xC523, 0x9DB8, 0xC524, 0x9DB9, 0xC525, 0x9DBA, 0xC526, 0x9DBB, 0xC527, 0x9DBC, 0xC52A, 0x9DBD, 0xC52B, 0x9DBE, 0xC52D, 0x9DBF, 0xC52E, 0x9DC0, 0xC52F, 0x9DC1, 0xC531, 0x9DC2, 0xC532, 0x9DC3, 0xC533, 0x9DC4, 0xC534, 0x9DC5, 0xC535, 0x9DC6, 0xC536, 0x9DC7, 0xC537, 0x9DC8, 0xC53A, 0x9DC9, 0xC53C, 0x9DCA, 0xC53E, 0x9DCB, 0xC53F, 0x9DCC, 0xC540, 0x9DCD, 0xC541, 0x9DCE, 0xC542, 0x9DCF, 0xC543, 0x9DD0, 0xC546, 0x9DD1, 0xC547, 0x9DD2, 0xC54B, 0x9DD3, 0xC54F, 0x9DD4, 0xC550, 0x9DD5, 0xC551, 0x9DD6, 0xC552, 0x9DD7, 0xC556, 0x9DD8, 0xC55A, 0x9DD9, 0xC55B, 0x9DDA, 0xC55C, 0x9DDB, 0xC55F, 0x9DDC, 0xC562, 0x9DDD, 0xC563, 0x9DDE, 0xC565, 0x9DDF, 0xC566, 0x9DE0, 0xC567, 0x9DE1, 0xC569, 0x9DE2, 0xC56A, 0x9DE3, 0xC56B, 0x9DE4, 0xC56C, 0x9DE5, 0xC56D, 0x9DE6, 0xC56E, 0x9DE7, 0xC56F, 0x9DE8, 0xC572, 0x9DE9, 0xC576, 0x9DEA, 0xC577, 0x9DEB, 0xC578, 0x9DEC, 0xC579, 0x9DED, 0xC57A, 0x9DEE, 0xC57B, 0x9DEF, 0xC57E, 0x9DF0, 0xC57F, 0x9DF1, 0xC581, 0x9DF2, 0xC582, 0x9DF3, 0xC583, 0x9DF4, 0xC585, 0x9DF5, 0xC586, 0x9DF6, 0xC588, 0x9DF7, 0xC589, 0x9DF8, 0xC58A, 0x9DF9, 0xC58B, 0x9DFA, 0xC58E, 0x9DFB, 0xC590, 0x9DFC, 0xC592, 0x9DFD, 0xC593, 0x9DFE, 0xC594, 0x9E41, 0xC596, 0x9E42, 0xC599, 0x9E43, 0xC59A, 0x9E44, 0xC59B, 0x9E45, 0xC59D, 0x9E46, 0xC59E, 0x9E47, 0xC59F, 0x9E48, 0xC5A1, 0x9E49, 0xC5A2, 0x9E4A, 0xC5A3, 0x9E4B, 0xC5A4, 0x9E4C, 0xC5A5, 0x9E4D, 0xC5A6, 0x9E4E, 0xC5A7, 0x9E4F, 0xC5A8, 0x9E50, 0xC5AA, 0x9E51, 0xC5AB, 0x9E52, 0xC5AC, 0x9E53, 0xC5AD, 0x9E54, 0xC5AE, 0x9E55, 0xC5AF, 0x9E56, 0xC5B0, 0x9E57, 0xC5B1, 0x9E58, 0xC5B2, 0x9E59, 0xC5B3, 0x9E5A, 0xC5B6, 0x9E61, 0xC5B7, 0x9E62, 0xC5BA, 0x9E63, 0xC5BF, 0x9E64, 0xC5C0, 0x9E65, 0xC5C1, 0x9E66, 0xC5C2, 0x9E67, 0xC5C3, 0x9E68, 0xC5CB, 0x9E69, 0xC5CD, 0x9E6A, 0xC5CF, 0x9E6B, 0xC5D2, 0x9E6C, 0xC5D3, 0x9E6D, 0xC5D5, 0x9E6E, 0xC5D6, 0x9E6F, 0xC5D7, 0x9E70, 0xC5D9, 0x9E71, 0xC5DA, 0x9E72, 0xC5DB, 0x9E73, 0xC5DC, 0x9E74, 0xC5DD, 0x9E75, 0xC5DE, 0x9E76, 0xC5DF, 0x9E77, 0xC5E2, 0x9E78, 0xC5E4, 0x9E79, 0xC5E6, 0x9E7A, 0xC5E7, 0x9E81, 0xC5E8, 0x9E82, 0xC5E9, 0x9E83, 0xC5EA, 0x9E84, 0xC5EB, 0x9E85, 0xC5EF, 0x9E86, 0xC5F1, 0x9E87, 0xC5F2, 0x9E88, 0xC5F3, 0x9E89, 0xC5F5, 0x9E8A, 0xC5F8, 0x9E8B, 0xC5F9, 0x9E8C, 0xC5FA, 0x9E8D, 0xC5FB, 0x9E8E, 0xC602, 0x9E8F, 0xC603, 0x9E90, 0xC604, 0x9E91, 0xC609, 0x9E92, 0xC60A, 0x9E93, 0xC60B, 0x9E94, 0xC60D, 0x9E95, 0xC60E, 0x9E96, 0xC60F, 0x9E97, 0xC611, 0x9E98, 0xC612, 0x9E99, 0xC613, 0x9E9A, 0xC614, 0x9E9B, 0xC615, 0x9E9C, 0xC616, 0x9E9D, 0xC617, 0x9E9E, 0xC61A, 0x9E9F, 0xC61D, 0x9EA0, 0xC61E, 0x9EA1, 0xC61F, 0x9EA2, 0xC620, 0x9EA3, 0xC621, 0x9EA4, 0xC622, 0x9EA5, 0xC623, 0x9EA6, 0xC626, 0x9EA7, 0xC627, 0x9EA8, 0xC629, 0x9EA9, 0xC62A, 0x9EAA, 0xC62B, 0x9EAB, 0xC62F, 0x9EAC, 0xC631, 0x9EAD, 0xC632, 0x9EAE, 0xC636, 0x9EAF, 0xC638, 0x9EB0, 0xC63A, 0x9EB1, 0xC63C, 0x9EB2, 0xC63D, 0x9EB3, 0xC63E, 0x9EB4, 0xC63F, 0x9EB5, 0xC642, 0x9EB6, 0xC643, 0x9EB7, 0xC645, 0x9EB8, 0xC646, 0x9EB9, 0xC647, 0x9EBA, 0xC649, 0x9EBB, 0xC64A, 0x9EBC, 0xC64B, 0x9EBD, 0xC64C, 0x9EBE, 0xC64D, 0x9EBF, 0xC64E, 0x9EC0, 0xC64F, 0x9EC1, 0xC652, 0x9EC2, 0xC656, 0x9EC3, 0xC657, 0x9EC4, 0xC658, 0x9EC5, 0xC659, 0x9EC6, 0xC65A, 0x9EC7, 0xC65B, 0x9EC8, 0xC65E, 0x9EC9, 0xC65F, 0x9ECA, 0xC661, 0x9ECB, 0xC662, 0x9ECC, 0xC663, 0x9ECD, 0xC664, 0x9ECE, 0xC665, 0x9ECF, 0xC666, 0x9ED0, 0xC667, 0x9ED1, 0xC668, 0x9ED2, 0xC669, 0x9ED3, 0xC66A, 0x9ED4, 0xC66B, 0x9ED5, 0xC66D, 0x9ED6, 0xC66E, 0x9ED7, 0xC670, 0x9ED8, 0xC672, 0x9ED9, 0xC673, 0x9EDA, 0xC674, 0x9EDB, 0xC675, 0x9EDC, 0xC676, 0x9EDD, 0xC677, 0x9EDE, 0xC67A, 0x9EDF, 0xC67B, 0x9EE0, 0xC67D, 0x9EE1, 0xC67E, 0x9EE2, 0xC67F, 0x9EE3, 0xC681, 0x9EE4, 0xC682, 0x9EE5, 0xC683, 0x9EE6, 0xC684, 0x9EE7, 0xC685, 0x9EE8, 0xC686, 0x9EE9, 0xC687, 0x9EEA, 0xC68A, 0x9EEB, 0xC68C, 0x9EEC, 0xC68E, 0x9EED, 0xC68F, 0x9EEE, 0xC690, 0x9EEF, 0xC691, 0x9EF0, 0xC692, 0x9EF1, 0xC693, 0x9EF2, 0xC696, 0x9EF3, 0xC697, 0x9EF4, 0xC699, 0x9EF5, 0xC69A, 0x9EF6, 0xC69B, 0x9EF7, 0xC69D, 0x9EF8, 0xC69E, 0x9EF9, 0xC69F, 0x9EFA, 0xC6A0, 0x9EFB, 0xC6A1, 0x9EFC, 0xC6A2, 0x9EFD, 0xC6A3, 0x9EFE, 0xC6A6, 0x9F41, 0xC6A8, 0x9F42, 0xC6AA, 0x9F43, 0xC6AB, 0x9F44, 0xC6AC, 0x9F45, 0xC6AD, 0x9F46, 0xC6AE, 0x9F47, 0xC6AF, 0x9F48, 0xC6B2, 0x9F49, 0xC6B3, 0x9F4A, 0xC6B5, 0x9F4B, 0xC6B6, 0x9F4C, 0xC6B7, 0x9F4D, 0xC6BB, 0x9F4E, 0xC6BC, 0x9F4F, 0xC6BD, 0x9F50, 0xC6BE, 0x9F51, 0xC6BF, 0x9F52, 0xC6C2, 0x9F53, 0xC6C4, 0x9F54, 0xC6C6, 0x9F55, 0xC6C7, 0x9F56, 0xC6C8, 0x9F57, 0xC6C9, 0x9F58, 0xC6CA, 0x9F59, 0xC6CB, 0x9F5A, 0xC6CE, 0x9F61, 0xC6CF, 0x9F62, 0xC6D1, 0x9F63, 0xC6D2, 0x9F64, 0xC6D3, 0x9F65, 0xC6D5, 0x9F66, 0xC6D6, 0x9F67, 0xC6D7, 0x9F68, 0xC6D8, 0x9F69, 0xC6D9, 0x9F6A, 0xC6DA, 0x9F6B, 0xC6DB, 0x9F6C, 0xC6DE, 0x9F6D, 0xC6DF, 0x9F6E, 0xC6E2, 0x9F6F, 0xC6E3, 0x9F70, 0xC6E4, 0x9F71, 0xC6E5, 0x9F72, 0xC6E6, 0x9F73, 0xC6E7, 0x9F74, 0xC6EA, 0x9F75, 0xC6EB, 0x9F76, 0xC6ED, 0x9F77, 0xC6EE, 0x9F78, 0xC6EF, 0x9F79, 0xC6F1, 0x9F7A, 0xC6F2, 0x9F81, 0xC6F3, 0x9F82, 0xC6F4, 0x9F83, 0xC6F5, 0x9F84, 0xC6F6, 0x9F85, 0xC6F7, 0x9F86, 0xC6FA, 0x9F87, 0xC6FB, 0x9F88, 0xC6FC, 0x9F89, 0xC6FE, 0x9F8A, 0xC6FF, 0x9F8B, 0xC700, 0x9F8C, 0xC701, 0x9F8D, 0xC702, 0x9F8E, 0xC703, 0x9F8F, 0xC706, 0x9F90, 0xC707, 0x9F91, 0xC709, 0x9F92, 0xC70A, 0x9F93, 0xC70B, 0x9F94, 0xC70D, 0x9F95, 0xC70E, 0x9F96, 0xC70F, 0x9F97, 0xC710, 0x9F98, 0xC711, 0x9F99, 0xC712, 0x9F9A, 0xC713, 0x9F9B, 0xC716, 0x9F9C, 0xC718, 0x9F9D, 0xC71A, 0x9F9E, 0xC71B, 0x9F9F, 0xC71C, 0x9FA0, 0xC71D, 0x9FA1, 0xC71E, 0x9FA2, 0xC71F, 0x9FA3, 0xC722, 0x9FA4, 0xC723, 0x9FA5, 0xC725, 0x9FA6, 0xC726, 0x9FA7, 0xC727, 0x9FA8, 0xC729, 0x9FA9, 0xC72A, 0x9FAA, 0xC72B, 0x9FAB, 0xC72C, 0x9FAC, 0xC72D, 0x9FAD, 0xC72E, 0x9FAE, 0xC72F, 0x9FAF, 0xC732, 0x9FB0, 0xC734, 0x9FB1, 0xC736, 0x9FB2, 0xC738, 0x9FB3, 0xC739, 0x9FB4, 0xC73A, 0x9FB5, 0xC73B, 0x9FB6, 0xC73E, 0x9FB7, 0xC73F, 0x9FB8, 0xC741, 0x9FB9, 0xC742, 0x9FBA, 0xC743, 0x9FBB, 0xC745, 0x9FBC, 0xC746, 0x9FBD, 0xC747, 0x9FBE, 0xC748, 0x9FBF, 0xC749, 0x9FC0, 0xC74B, 0x9FC1, 0xC74E, 0x9FC2, 0xC750, 0x9FC3, 0xC759, 0x9FC4, 0xC75A, 0x9FC5, 0xC75B, 0x9FC6, 0xC75D, 0x9FC7, 0xC75E, 0x9FC8, 0xC75F, 0x9FC9, 0xC761, 0x9FCA, 0xC762, 0x9FCB, 0xC763, 0x9FCC, 0xC764, 0x9FCD, 0xC765, 0x9FCE, 0xC766, 0x9FCF, 0xC767, 0x9FD0, 0xC769, 0x9FD1, 0xC76A, 0x9FD2, 0xC76C, 0x9FD3, 0xC76D, 0x9FD4, 0xC76E, 0x9FD5, 0xC76F, 0x9FD6, 0xC770, 0x9FD7, 0xC771, 0x9FD8, 0xC772, 0x9FD9, 0xC773, 0x9FDA, 0xC776, 0x9FDB, 0xC777, 0x9FDC, 0xC779, 0x9FDD, 0xC77A, 0x9FDE, 0xC77B, 0x9FDF, 0xC77F, 0x9FE0, 0xC780, 0x9FE1, 0xC781, 0x9FE2, 0xC782, 0x9FE3, 0xC786, 0x9FE4, 0xC78B, 0x9FE5, 0xC78C, 0x9FE6, 0xC78D, 0x9FE7, 0xC78F, 0x9FE8, 0xC792, 0x9FE9, 0xC793, 0x9FEA, 0xC795, 0x9FEB, 0xC799, 0x9FEC, 0xC79B, 0x9FED, 0xC79C, 0x9FEE, 0xC79D, 0x9FEF, 0xC79E, 0x9FF0, 0xC79F, 0x9FF1, 0xC7A2, 0x9FF2, 0xC7A7, 0x9FF3, 0xC7A8, 0x9FF4, 0xC7A9, 0x9FF5, 0xC7AA, 0x9FF6, 0xC7AB, 0x9FF7, 0xC7AE, 0x9FF8, 0xC7AF, 0x9FF9, 0xC7B1, 0x9FFA, 0xC7B2, 0x9FFB, 0xC7B3, 0x9FFC, 0xC7B5, 0x9FFD, 0xC7B6, 0x9FFE, 0xC7B7, 0xA041, 0xC7B8, 0xA042, 0xC7B9, 0xA043, 0xC7BA, 0xA044, 0xC7BB, 0xA045, 0xC7BE, 0xA046, 0xC7C2, 0xA047, 0xC7C3, 0xA048, 0xC7C4, 0xA049, 0xC7C5, 0xA04A, 0xC7C6, 0xA04B, 0xC7C7, 0xA04C, 0xC7CA, 0xA04D, 0xC7CB, 0xA04E, 0xC7CD, 0xA04F, 0xC7CF, 0xA050, 0xC7D1, 0xA051, 0xC7D2, 0xA052, 0xC7D3, 0xA053, 0xC7D4, 0xA054, 0xC7D5, 0xA055, 0xC7D6, 0xA056, 0xC7D7, 0xA057, 0xC7D9, 0xA058, 0xC7DA, 0xA059, 0xC7DB, 0xA05A, 0xC7DC, 0xA061, 0xC7DE, 0xA062, 0xC7DF, 0xA063, 0xC7E0, 0xA064, 0xC7E1, 0xA065, 0xC7E2, 0xA066, 0xC7E3, 0xA067, 0xC7E5, 0xA068, 0xC7E6, 0xA069, 0xC7E7, 0xA06A, 0xC7E9, 0xA06B, 0xC7EA, 0xA06C, 0xC7EB, 0xA06D, 0xC7ED, 0xA06E, 0xC7EE, 0xA06F, 0xC7EF, 0xA070, 0xC7F0, 0xA071, 0xC7F1, 0xA072, 0xC7F2, 0xA073, 0xC7F3, 0xA074, 0xC7F4, 0xA075, 0xC7F5, 0xA076, 0xC7F6, 0xA077, 0xC7F7, 0xA078, 0xC7F8, 0xA079, 0xC7F9, 0xA07A, 0xC7FA, 0xA081, 0xC7FB, 0xA082, 0xC7FC, 0xA083, 0xC7FD, 0xA084, 0xC7FE, 0xA085, 0xC7FF, 0xA086, 0xC802, 0xA087, 0xC803, 0xA088, 0xC805, 0xA089, 0xC806, 0xA08A, 0xC807, 0xA08B, 0xC809, 0xA08C, 0xC80B, 0xA08D, 0xC80C, 0xA08E, 0xC80D, 0xA08F, 0xC80E, 0xA090, 0xC80F, 0xA091, 0xC812, 0xA092, 0xC814, 0xA093, 0xC817, 0xA094, 0xC818, 0xA095, 0xC819, 0xA096, 0xC81A, 0xA097, 0xC81B, 0xA098, 0xC81E, 0xA099, 0xC81F, 0xA09A, 0xC821, 0xA09B, 0xC822, 0xA09C, 0xC823, 0xA09D, 0xC825, 0xA09E, 0xC826, 0xA09F, 0xC827, 0xA0A0, 0xC828, 0xA0A1, 0xC829, 0xA0A2, 0xC82A, 0xA0A3, 0xC82B, 0xA0A4, 0xC82E, 0xA0A5, 0xC830, 0xA0A6, 0xC832, 0xA0A7, 0xC833, 0xA0A8, 0xC834, 0xA0A9, 0xC835, 0xA0AA, 0xC836, 0xA0AB, 0xC837, 0xA0AC, 0xC839, 0xA0AD, 0xC83A, 0xA0AE, 0xC83B, 0xA0AF, 0xC83D, 0xA0B0, 0xC83E, 0xA0B1, 0xC83F, 0xA0B2, 0xC841, 0xA0B3, 0xC842, 0xA0B4, 0xC843, 0xA0B5, 0xC844, 0xA0B6, 0xC845, 0xA0B7, 0xC846, 0xA0B8, 0xC847, 0xA0B9, 0xC84A, 0xA0BA, 0xC84B, 0xA0BB, 0xC84E, 0xA0BC, 0xC84F, 0xA0BD, 0xC850, 0xA0BE, 0xC851, 0xA0BF, 0xC852, 0xA0C0, 0xC853, 0xA0C1, 0xC855, 0xA0C2, 0xC856, 0xA0C3, 0xC857, 0xA0C4, 0xC858, 0xA0C5, 0xC859, 0xA0C6, 0xC85A, 0xA0C7, 0xC85B, 0xA0C8, 0xC85C, 0xA0C9, 0xC85D, 0xA0CA, 0xC85E, 0xA0CB, 0xC85F, 0xA0CC, 0xC860, 0xA0CD, 0xC861, 0xA0CE, 0xC862, 0xA0CF, 0xC863, 0xA0D0, 0xC864, 0xA0D1, 0xC865, 0xA0D2, 0xC866, 0xA0D3, 0xC867, 0xA0D4, 0xC868, 0xA0D5, 0xC869, 0xA0D6, 0xC86A, 0xA0D7, 0xC86B, 0xA0D8, 0xC86C, 0xA0D9, 0xC86D, 0xA0DA, 0xC86E, 0xA0DB, 0xC86F, 0xA0DC, 0xC872, 0xA0DD, 0xC873, 0xA0DE, 0xC875, 0xA0DF, 0xC876, 0xA0E0, 0xC877, 0xA0E1, 0xC879, 0xA0E2, 0xC87B, 0xA0E3, 0xC87C, 0xA0E4, 0xC87D, 0xA0E5, 0xC87E, 0xA0E6, 0xC87F, 0xA0E7, 0xC882, 0xA0E8, 0xC884, 0xA0E9, 0xC888, 0xA0EA, 0xC889, 0xA0EB, 0xC88A, 0xA0EC, 0xC88E, 0xA0ED, 0xC88F, 0xA0EE, 0xC890, 0xA0EF, 0xC891, 0xA0F0, 0xC892, 0xA0F1, 0xC893, 0xA0F2, 0xC895, 0xA0F3, 0xC896, 0xA0F4, 0xC897, 0xA0F5, 0xC898, 0xA0F6, 0xC899, 0xA0F7, 0xC89A, 0xA0F8, 0xC89B, 0xA0F9, 0xC89C, 0xA0FA, 0xC89E, 0xA0FB, 0xC8A0, 0xA0FC, 0xC8A2, 0xA0FD, 0xC8A3, 0xA0FE, 0xC8A4, 0xA141, 0xC8A5, 0xA142, 0xC8A6, 0xA143, 0xC8A7, 0xA144, 0xC8A9, 0xA145, 0xC8AA, 0xA146, 0xC8AB, 0xA147, 0xC8AC, 0xA148, 0xC8AD, 0xA149, 0xC8AE, 0xA14A, 0xC8AF, 0xA14B, 0xC8B0, 0xA14C, 0xC8B1, 0xA14D, 0xC8B2, 0xA14E, 0xC8B3, 0xA14F, 0xC8B4, 0xA150, 0xC8B5, 0xA151, 0xC8B6, 0xA152, 0xC8B7, 0xA153, 0xC8B8, 0xA154, 0xC8B9, 0xA155, 0xC8BA, 0xA156, 0xC8BB, 0xA157, 0xC8BE, 0xA158, 0xC8BF, 0xA159, 0xC8C0, 0xA15A, 0xC8C1, 0xA161, 0xC8C2, 0xA162, 0xC8C3, 0xA163, 0xC8C5, 0xA164, 0xC8C6, 0xA165, 0xC8C7, 0xA166, 0xC8C9, 0xA167, 0xC8CA, 0xA168, 0xC8CB, 0xA169, 0xC8CD, 0xA16A, 0xC8CE, 0xA16B, 0xC8CF, 0xA16C, 0xC8D0, 0xA16D, 0xC8D1, 0xA16E, 0xC8D2, 0xA16F, 0xC8D3, 0xA170, 0xC8D6, 0xA171, 0xC8D8, 0xA172, 0xC8DA, 0xA173, 0xC8DB, 0xA174, 0xC8DC, 0xA175, 0xC8DD, 0xA176, 0xC8DE, 0xA177, 0xC8DF, 0xA178, 0xC8E2, 0xA179, 0xC8E3, 0xA17A, 0xC8E5, 0xA181, 0xC8E6, 0xA182, 0xC8E7, 0xA183, 0xC8E8, 0xA184, 0xC8E9, 0xA185, 0xC8EA, 0xA186, 0xC8EB, 0xA187, 0xC8EC, 0xA188, 0xC8ED, 0xA189, 0xC8EE, 0xA18A, 0xC8EF, 0xA18B, 0xC8F0, 0xA18C, 0xC8F1, 0xA18D, 0xC8F2, 0xA18E, 0xC8F3, 0xA18F, 0xC8F4, 0xA190, 0xC8F6, 0xA191, 0xC8F7, 0xA192, 0xC8F8, 0xA193, 0xC8F9, 0xA194, 0xC8FA, 0xA195, 0xC8FB, 0xA196, 0xC8FE, 0xA197, 0xC8FF, 0xA198, 0xC901, 0xA199, 0xC902, 0xA19A, 0xC903, 0xA19B, 0xC907, 0xA19C, 0xC908, 0xA19D, 0xC909, 0xA19E, 0xC90A, 0xA19F, 0xC90B, 0xA1A0, 0xC90E, 0xA1A1, 0x3000, 0xA1A2, 0x3001, 0xA1A3, 0x3002, 0xA1A4, 0x00B7, 0xA1A5, 0x2025, 0xA1A6, 0x2026, 0xA1A7, 0x00A8, 0xA1A8, 0x3003, 0xA1A9, 0x00AD, 0xA1AA, 0x2015, 0xA1AB, 0x2225, 0xA1AC, 0xFF3C, 0xA1AD, 0x223C, 0xA1AE, 0x2018, 0xA1AF, 0x2019, 0xA1B0, 0x201C, 0xA1B1, 0x201D, 0xA1B2, 0x3014, 0xA1B3, 0x3015, 0xA1B4, 0x3008, 0xA1B5, 0x3009, 0xA1B6, 0x300A, 0xA1B7, 0x300B, 0xA1B8, 0x300C, 0xA1B9, 0x300D, 0xA1BA, 0x300E, 0xA1BB, 0x300F, 0xA1BC, 0x3010, 0xA1BD, 0x3011, 0xA1BE, 0x00B1, 0xA1BF, 0x00D7, 0xA1C0, 0x00F7, 0xA1C1, 0x2260, 0xA1C2, 0x2264, 0xA1C3, 0x2265, 0xA1C4, 0x221E, 0xA1C5, 0x2234, 0xA1C6, 0x00B0, 0xA1C7, 0x2032, 0xA1C8, 0x2033, 0xA1C9, 0x2103, 0xA1CA, 0x212B, 0xA1CB, 0xFFE0, 0xA1CC, 0xFFE1, 0xA1CD, 0xFFE5, 0xA1CE, 0x2642, 0xA1CF, 0x2640, 0xA1D0, 0x2220, 0xA1D1, 0x22A5, 0xA1D2, 0x2312, 0xA1D3, 0x2202, 0xA1D4, 0x2207, 0xA1D5, 0x2261, 0xA1D6, 0x2252, 0xA1D7, 0x00A7, 0xA1D8, 0x203B, 0xA1D9, 0x2606, 0xA1DA, 0x2605, 0xA1DB, 0x25CB, 0xA1DC, 0x25CF, 0xA1DD, 0x25CE, 0xA1DE, 0x25C7, 0xA1DF, 0x25C6, 0xA1E0, 0x25A1, 0xA1E1, 0x25A0, 0xA1E2, 0x25B3, 0xA1E3, 0x25B2, 0xA1E4, 0x25BD, 0xA1E5, 0x25BC, 0xA1E6, 0x2192, 0xA1E7, 0x2190, 0xA1E8, 0x2191, 0xA1E9, 0x2193, 0xA1EA, 0x2194, 0xA1EB, 0x3013, 0xA1EC, 0x226A, 0xA1ED, 0x226B, 0xA1EE, 0x221A, 0xA1EF, 0x223D, 0xA1F0, 0x221D, 0xA1F1, 0x2235, 0xA1F2, 0x222B, 0xA1F3, 0x222C, 0xA1F4, 0x2208, 0xA1F5, 0x220B, 0xA1F6, 0x2286, 0xA1F7, 0x2287, 0xA1F8, 0x2282, 0xA1F9, 0x2283, 0xA1FA, 0x222A, 0xA1FB, 0x2229, 0xA1FC, 0x2227, 0xA1FD, 0x2228, 0xA1FE, 0xFFE2, 0xA241, 0xC910, 0xA242, 0xC912, 0xA243, 0xC913, 0xA244, 0xC914, 0xA245, 0xC915, 0xA246, 0xC916, 0xA247, 0xC917, 0xA248, 0xC919, 0xA249, 0xC91A, 0xA24A, 0xC91B, 0xA24B, 0xC91C, 0xA24C, 0xC91D, 0xA24D, 0xC91E, 0xA24E, 0xC91F, 0xA24F, 0xC920, 0xA250, 0xC921, 0xA251, 0xC922, 0xA252, 0xC923, 0xA253, 0xC924, 0xA254, 0xC925, 0xA255, 0xC926, 0xA256, 0xC927, 0xA257, 0xC928, 0xA258, 0xC929, 0xA259, 0xC92A, 0xA25A, 0xC92B, 0xA261, 0xC92D, 0xA262, 0xC92E, 0xA263, 0xC92F, 0xA264, 0xC930, 0xA265, 0xC931, 0xA266, 0xC932, 0xA267, 0xC933, 0xA268, 0xC935, 0xA269, 0xC936, 0xA26A, 0xC937, 0xA26B, 0xC938, 0xA26C, 0xC939, 0xA26D, 0xC93A, 0xA26E, 0xC93B, 0xA26F, 0xC93C, 0xA270, 0xC93D, 0xA271, 0xC93E, 0xA272, 0xC93F, 0xA273, 0xC940, 0xA274, 0xC941, 0xA275, 0xC942, 0xA276, 0xC943, 0xA277, 0xC944, 0xA278, 0xC945, 0xA279, 0xC946, 0xA27A, 0xC947, 0xA281, 0xC948, 0xA282, 0xC949, 0xA283, 0xC94A, 0xA284, 0xC94B, 0xA285, 0xC94C, 0xA286, 0xC94D, 0xA287, 0xC94E, 0xA288, 0xC94F, 0xA289, 0xC952, 0xA28A, 0xC953, 0xA28B, 0xC955, 0xA28C, 0xC956, 0xA28D, 0xC957, 0xA28E, 0xC959, 0xA28F, 0xC95A, 0xA290, 0xC95B, 0xA291, 0xC95C, 0xA292, 0xC95D, 0xA293, 0xC95E, 0xA294, 0xC95F, 0xA295, 0xC962, 0xA296, 0xC964, 0xA297, 0xC965, 0xA298, 0xC966, 0xA299, 0xC967, 0xA29A, 0xC968, 0xA29B, 0xC969, 0xA29C, 0xC96A, 0xA29D, 0xC96B, 0xA29E, 0xC96D, 0xA29F, 0xC96E, 0xA2A0, 0xC96F, 0xA2A1, 0x21D2, 0xA2A2, 0x21D4, 0xA2A3, 0x2200, 0xA2A4, 0x2203, 0xA2A5, 0x00B4, 0xA2A6, 0xFF5E, 0xA2A7, 0x02C7, 0xA2A8, 0x02D8, 0xA2A9, 0x02DD, 0xA2AA, 0x02DA, 0xA2AB, 0x02D9, 0xA2AC, 0x00B8, 0xA2AD, 0x02DB, 0xA2AE, 0x00A1, 0xA2AF, 0x00BF, 0xA2B0, 0x02D0, 0xA2B1, 0x222E, 0xA2B2, 0x2211, 0xA2B3, 0x220F, 0xA2B4, 0x00A4, 0xA2B5, 0x2109, 0xA2B6, 0x2030, 0xA2B7, 0x25C1, 0xA2B8, 0x25C0, 0xA2B9, 0x25B7, 0xA2BA, 0x25B6, 0xA2BB, 0x2664, 0xA2BC, 0x2660, 0xA2BD, 0x2661, 0xA2BE, 0x2665, 0xA2BF, 0x2667, 0xA2C0, 0x2663, 0xA2C1, 0x2299, 0xA2C2, 0x25C8, 0xA2C3, 0x25A3, 0xA2C4, 0x25D0, 0xA2C5, 0x25D1, 0xA2C6, 0x2592, 0xA2C7, 0x25A4, 0xA2C8, 0x25A5, 0xA2C9, 0x25A8, 0xA2CA, 0x25A7, 0xA2CB, 0x25A6, 0xA2CC, 0x25A9, 0xA2CD, 0x2668, 0xA2CE, 0x260F, 0xA2CF, 0x260E, 0xA2D0, 0x261C, 0xA2D1, 0x261E, 0xA2D2, 0x00B6, 0xA2D3, 0x2020, 0xA2D4, 0x2021, 0xA2D5, 0x2195, 0xA2D6, 0x2197, 0xA2D7, 0x2199, 0xA2D8, 0x2196, 0xA2D9, 0x2198, 0xA2DA, 0x266D, 0xA2DB, 0x2669, 0xA2DC, 0x266A, 0xA2DD, 0x266C, 0xA2DE, 0x327F, 0xA2DF, 0x321C, 0xA2E0, 0x2116, 0xA2E1, 0x33C7, 0xA2E2, 0x2122, 0xA2E3, 0x33C2, 0xA2E4, 0x33D8, 0xA2E5, 0x2121, 0xA2E6, 0x20AC, 0xA2E7, 0x00AE, 0xA341, 0xC971, 0xA342, 0xC972, 0xA343, 0xC973, 0xA344, 0xC975, 0xA345, 0xC976, 0xA346, 0xC977, 0xA347, 0xC978, 0xA348, 0xC979, 0xA349, 0xC97A, 0xA34A, 0xC97B, 0xA34B, 0xC97D, 0xA34C, 0xC97E, 0xA34D, 0xC97F, 0xA34E, 0xC980, 0xA34F, 0xC981, 0xA350, 0xC982, 0xA351, 0xC983, 0xA352, 0xC984, 0xA353, 0xC985, 0xA354, 0xC986, 0xA355, 0xC987, 0xA356, 0xC98A, 0xA357, 0xC98B, 0xA358, 0xC98D, 0xA359, 0xC98E, 0xA35A, 0xC98F, 0xA361, 0xC991, 0xA362, 0xC992, 0xA363, 0xC993, 0xA364, 0xC994, 0xA365, 0xC995, 0xA366, 0xC996, 0xA367, 0xC997, 0xA368, 0xC99A, 0xA369, 0xC99C, 0xA36A, 0xC99E, 0xA36B, 0xC99F, 0xA36C, 0xC9A0, 0xA36D, 0xC9A1, 0xA36E, 0xC9A2, 0xA36F, 0xC9A3, 0xA370, 0xC9A4, 0xA371, 0xC9A5, 0xA372, 0xC9A6, 0xA373, 0xC9A7, 0xA374, 0xC9A8, 0xA375, 0xC9A9, 0xA376, 0xC9AA, 0xA377, 0xC9AB, 0xA378, 0xC9AC, 0xA379, 0xC9AD, 0xA37A, 0xC9AE, 0xA381, 0xC9AF, 0xA382, 0xC9B0, 0xA383, 0xC9B1, 0xA384, 0xC9B2, 0xA385, 0xC9B3, 0xA386, 0xC9B4, 0xA387, 0xC9B5, 0xA388, 0xC9B6, 0xA389, 0xC9B7, 0xA38A, 0xC9B8, 0xA38B, 0xC9B9, 0xA38C, 0xC9BA, 0xA38D, 0xC9BB, 0xA38E, 0xC9BC, 0xA38F, 0xC9BD, 0xA390, 0xC9BE, 0xA391, 0xC9BF, 0xA392, 0xC9C2, 0xA393, 0xC9C3, 0xA394, 0xC9C5, 0xA395, 0xC9C6, 0xA396, 0xC9C9, 0xA397, 0xC9CB, 0xA398, 0xC9CC, 0xA399, 0xC9CD, 0xA39A, 0xC9CE, 0xA39B, 0xC9CF, 0xA39C, 0xC9D2, 0xA39D, 0xC9D4, 0xA39E, 0xC9D7, 0xA39F, 0xC9D8, 0xA3A0, 0xC9DB, 0xA3A1, 0xFF01, 0xA3A2, 0xFF02, 0xA3A3, 0xFF03, 0xA3A4, 0xFF04, 0xA3A5, 0xFF05, 0xA3A6, 0xFF06, 0xA3A7, 0xFF07, 0xA3A8, 0xFF08, 0xA3A9, 0xFF09, 0xA3AA, 0xFF0A, 0xA3AB, 0xFF0B, 0xA3AC, 0xFF0C, 0xA3AD, 0xFF0D, 0xA3AE, 0xFF0E, 0xA3AF, 0xFF0F, 0xA3B0, 0xFF10, 0xA3B1, 0xFF11, 0xA3B2, 0xFF12, 0xA3B3, 0xFF13, 0xA3B4, 0xFF14, 0xA3B5, 0xFF15, 0xA3B6, 0xFF16, 0xA3B7, 0xFF17, 0xA3B8, 0xFF18, 0xA3B9, 0xFF19, 0xA3BA, 0xFF1A, 0xA3BB, 0xFF1B, 0xA3BC, 0xFF1C, 0xA3BD, 0xFF1D, 0xA3BE, 0xFF1E, 0xA3BF, 0xFF1F, 0xA3C0, 0xFF20, 0xA3C1, 0xFF21, 0xA3C2, 0xFF22, 0xA3C3, 0xFF23, 0xA3C4, 0xFF24, 0xA3C5, 0xFF25, 0xA3C6, 0xFF26, 0xA3C7, 0xFF27, 0xA3C8, 0xFF28, 0xA3C9, 0xFF29, 0xA3CA, 0xFF2A, 0xA3CB, 0xFF2B, 0xA3CC, 0xFF2C, 0xA3CD, 0xFF2D, 0xA3CE, 0xFF2E, 0xA3CF, 0xFF2F, 0xA3D0, 0xFF30, 0xA3D1, 0xFF31, 0xA3D2, 0xFF32, 0xA3D3, 0xFF33, 0xA3D4, 0xFF34, 0xA3D5, 0xFF35, 0xA3D6, 0xFF36, 0xA3D7, 0xFF37, 0xA3D8, 0xFF38, 0xA3D9, 0xFF39, 0xA3DA, 0xFF3A, 0xA3DB, 0xFF3B, 0xA3DC, 0xFFE6, 0xA3DD, 0xFF3D, 0xA3DE, 0xFF3E, 0xA3DF, 0xFF3F, 0xA3E0, 0xFF40, 0xA3E1, 0xFF41, 0xA3E2, 0xFF42, 0xA3E3, 0xFF43, 0xA3E4, 0xFF44, 0xA3E5, 0xFF45, 0xA3E6, 0xFF46, 0xA3E7, 0xFF47, 0xA3E8, 0xFF48, 0xA3E9, 0xFF49, 0xA3EA, 0xFF4A, 0xA3EB, 0xFF4B, 0xA3EC, 0xFF4C, 0xA3ED, 0xFF4D, 0xA3EE, 0xFF4E, 0xA3EF, 0xFF4F, 0xA3F0, 0xFF50, 0xA3F1, 0xFF51, 0xA3F2, 0xFF52, 0xA3F3, 0xFF53, 0xA3F4, 0xFF54, 0xA3F5, 0xFF55, 0xA3F6, 0xFF56, 0xA3F7, 0xFF57, 0xA3F8, 0xFF58, 0xA3F9, 0xFF59, 0xA3FA, 0xFF5A, 0xA3FB, 0xFF5B, 0xA3FC, 0xFF5C, 0xA3FD, 0xFF5D, 0xA3FE, 0xFFE3, 0xA441, 0xC9DE, 0xA442, 0xC9DF, 0xA443, 0xC9E1, 0xA444, 0xC9E3, 0xA445, 0xC9E5, 0xA446, 0xC9E6, 0xA447, 0xC9E8, 0xA448, 0xC9E9, 0xA449, 0xC9EA, 0xA44A, 0xC9EB, 0xA44B, 0xC9EE, 0xA44C, 0xC9F2, 0xA44D, 0xC9F3, 0xA44E, 0xC9F4, 0xA44F, 0xC9F5, 0xA450, 0xC9F6, 0xA451, 0xC9F7, 0xA452, 0xC9FA, 0xA453, 0xC9FB, 0xA454, 0xC9FD, 0xA455, 0xC9FE, 0xA456, 0xC9FF, 0xA457, 0xCA01, 0xA458, 0xCA02, 0xA459, 0xCA03, 0xA45A, 0xCA04, 0xA461, 0xCA05, 0xA462, 0xCA06, 0xA463, 0xCA07, 0xA464, 0xCA0A, 0xA465, 0xCA0E, 0xA466, 0xCA0F, 0xA467, 0xCA10, 0xA468, 0xCA11, 0xA469, 0xCA12, 0xA46A, 0xCA13, 0xA46B, 0xCA15, 0xA46C, 0xCA16, 0xA46D, 0xCA17, 0xA46E, 0xCA19, 0xA46F, 0xCA1A, 0xA470, 0xCA1B, 0xA471, 0xCA1C, 0xA472, 0xCA1D, 0xA473, 0xCA1E, 0xA474, 0xCA1F, 0xA475, 0xCA20, 0xA476, 0xCA21, 0xA477, 0xCA22, 0xA478, 0xCA23, 0xA479, 0xCA24, 0xA47A, 0xCA25, 0xA481, 0xCA26, 0xA482, 0xCA27, 0xA483, 0xCA28, 0xA484, 0xCA2A, 0xA485, 0xCA2B, 0xA486, 0xCA2C, 0xA487, 0xCA2D, 0xA488, 0xCA2E, 0xA489, 0xCA2F, 0xA48A, 0xCA30, 0xA48B, 0xCA31, 0xA48C, 0xCA32, 0xA48D, 0xCA33, 0xA48E, 0xCA34, 0xA48F, 0xCA35, 0xA490, 0xCA36, 0xA491, 0xCA37, 0xA492, 0xCA38, 0xA493, 0xCA39, 0xA494, 0xCA3A, 0xA495, 0xCA3B, 0xA496, 0xCA3C, 0xA497, 0xCA3D, 0xA498, 0xCA3E, 0xA499, 0xCA3F, 0xA49A, 0xCA40, 0xA49B, 0xCA41, 0xA49C, 0xCA42, 0xA49D, 0xCA43, 0xA49E, 0xCA44, 0xA49F, 0xCA45, 0xA4A0, 0xCA46, 0xA4A1, 0x3131, 0xA4A2, 0x3132, 0xA4A3, 0x3133, 0xA4A4, 0x3134, 0xA4A5, 0x3135, 0xA4A6, 0x3136, 0xA4A7, 0x3137, 0xA4A8, 0x3138, 0xA4A9, 0x3139, 0xA4AA, 0x313A, 0xA4AB, 0x313B, 0xA4AC, 0x313C, 0xA4AD, 0x313D, 0xA4AE, 0x313E, 0xA4AF, 0x313F, 0xA4B0, 0x3140, 0xA4B1, 0x3141, 0xA4B2, 0x3142, 0xA4B3, 0x3143, 0xA4B4, 0x3144, 0xA4B5, 0x3145, 0xA4B6, 0x3146, 0xA4B7, 0x3147, 0xA4B8, 0x3148, 0xA4B9, 0x3149, 0xA4BA, 0x314A, 0xA4BB, 0x314B, 0xA4BC, 0x314C, 0xA4BD, 0x314D, 0xA4BE, 0x314E, 0xA4BF, 0x314F, 0xA4C0, 0x3150, 0xA4C1, 0x3151, 0xA4C2, 0x3152, 0xA4C3, 0x3153, 0xA4C4, 0x3154, 0xA4C5, 0x3155, 0xA4C6, 0x3156, 0xA4C7, 0x3157, 0xA4C8, 0x3158, 0xA4C9, 0x3159, 0xA4CA, 0x315A, 0xA4CB, 0x315B, 0xA4CC, 0x315C, 0xA4CD, 0x315D, 0xA4CE, 0x315E, 0xA4CF, 0x315F, 0xA4D0, 0x3160, 0xA4D1, 0x3161, 0xA4D2, 0x3162, 0xA4D3, 0x3163, 0xA4D4, 0x3164, 0xA4D5, 0x3165, 0xA4D6, 0x3166, 0xA4D7, 0x3167, 0xA4D8, 0x3168, 0xA4D9, 0x3169, 0xA4DA, 0x316A, 0xA4DB, 0x316B, 0xA4DC, 0x316C, 0xA4DD, 0x316D, 0xA4DE, 0x316E, 0xA4DF, 0x316F, 0xA4E0, 0x3170, 0xA4E1, 0x3171, 0xA4E2, 0x3172, 0xA4E3, 0x3173, 0xA4E4, 0x3174, 0xA4E5, 0x3175, 0xA4E6, 0x3176, 0xA4E7, 0x3177, 0xA4E8, 0x3178, 0xA4E9, 0x3179, 0xA4EA, 0x317A, 0xA4EB, 0x317B, 0xA4EC, 0x317C, 0xA4ED, 0x317D, 0xA4EE, 0x317E, 0xA4EF, 0x317F, 0xA4F0, 0x3180, 0xA4F1, 0x3181, 0xA4F2, 0x3182, 0xA4F3, 0x3183, 0xA4F4, 0x3184, 0xA4F5, 0x3185, 0xA4F6, 0x3186, 0xA4F7, 0x3187, 0xA4F8, 0x3188, 0xA4F9, 0x3189, 0xA4FA, 0x318A, 0xA4FB, 0x318B, 0xA4FC, 0x318C, 0xA4FD, 0x318D, 0xA4FE, 0x318E, 0xA541, 0xCA47, 0xA542, 0xCA48, 0xA543, 0xCA49, 0xA544, 0xCA4A, 0xA545, 0xCA4B, 0xA546, 0xCA4E, 0xA547, 0xCA4F, 0xA548, 0xCA51, 0xA549, 0xCA52, 0xA54A, 0xCA53, 0xA54B, 0xCA55, 0xA54C, 0xCA56, 0xA54D, 0xCA57, 0xA54E, 0xCA58, 0xA54F, 0xCA59, 0xA550, 0xCA5A, 0xA551, 0xCA5B, 0xA552, 0xCA5E, 0xA553, 0xCA62, 0xA554, 0xCA63, 0xA555, 0xCA64, 0xA556, 0xCA65, 0xA557, 0xCA66, 0xA558, 0xCA67, 0xA559, 0xCA69, 0xA55A, 0xCA6A, 0xA561, 0xCA6B, 0xA562, 0xCA6C, 0xA563, 0xCA6D, 0xA564, 0xCA6E, 0xA565, 0xCA6F, 0xA566, 0xCA70, 0xA567, 0xCA71, 0xA568, 0xCA72, 0xA569, 0xCA73, 0xA56A, 0xCA74, 0xA56B, 0xCA75, 0xA56C, 0xCA76, 0xA56D, 0xCA77, 0xA56E, 0xCA78, 0xA56F, 0xCA79, 0xA570, 0xCA7A, 0xA571, 0xCA7B, 0xA572, 0xCA7C, 0xA573, 0xCA7E, 0xA574, 0xCA7F, 0xA575, 0xCA80, 0xA576, 0xCA81, 0xA577, 0xCA82, 0xA578, 0xCA83, 0xA579, 0xCA85, 0xA57A, 0xCA86, 0xA581, 0xCA87, 0xA582, 0xCA88, 0xA583, 0xCA89, 0xA584, 0xCA8A, 0xA585, 0xCA8B, 0xA586, 0xCA8C, 0xA587, 0xCA8D, 0xA588, 0xCA8E, 0xA589, 0xCA8F, 0xA58A, 0xCA90, 0xA58B, 0xCA91, 0xA58C, 0xCA92, 0xA58D, 0xCA93, 0xA58E, 0xCA94, 0xA58F, 0xCA95, 0xA590, 0xCA96, 0xA591, 0xCA97, 0xA592, 0xCA99, 0xA593, 0xCA9A, 0xA594, 0xCA9B, 0xA595, 0xCA9C, 0xA596, 0xCA9D, 0xA597, 0xCA9E, 0xA598, 0xCA9F, 0xA599, 0xCAA0, 0xA59A, 0xCAA1, 0xA59B, 0xCAA2, 0xA59C, 0xCAA3, 0xA59D, 0xCAA4, 0xA59E, 0xCAA5, 0xA59F, 0xCAA6, 0xA5A0, 0xCAA7, 0xA5A1, 0x2170, 0xA5A2, 0x2171, 0xA5A3, 0x2172, 0xA5A4, 0x2173, 0xA5A5, 0x2174, 0xA5A6, 0x2175, 0xA5A7, 0x2176, 0xA5A8, 0x2177, 0xA5A9, 0x2178, 0xA5AA, 0x2179, 0xA5B0, 0x2160, 0xA5B1, 0x2161, 0xA5B2, 0x2162, 0xA5B3, 0x2163, 0xA5B4, 0x2164, 0xA5B5, 0x2165, 0xA5B6, 0x2166, 0xA5B7, 0x2167, 0xA5B8, 0x2168, 0xA5B9, 0x2169, 0xA5C1, 0x0391, 0xA5C2, 0x0392, 0xA5C3, 0x0393, 0xA5C4, 0x0394, 0xA5C5, 0x0395, 0xA5C6, 0x0396, 0xA5C7, 0x0397, 0xA5C8, 0x0398, 0xA5C9, 0x0399, 0xA5CA, 0x039A, 0xA5CB, 0x039B, 0xA5CC, 0x039C, 0xA5CD, 0x039D, 0xA5CE, 0x039E, 0xA5CF, 0x039F, 0xA5D0, 0x03A0, 0xA5D1, 0x03A1, 0xA5D2, 0x03A3, 0xA5D3, 0x03A4, 0xA5D4, 0x03A5, 0xA5D5, 0x03A6, 0xA5D6, 0x03A7, 0xA5D7, 0x03A8, 0xA5D8, 0x03A9, 0xA5E1, 0x03B1, 0xA5E2, 0x03B2, 0xA5E3, 0x03B3, 0xA5E4, 0x03B4, 0xA5E5, 0x03B5, 0xA5E6, 0x03B6, 0xA5E7, 0x03B7, 0xA5E8, 0x03B8, 0xA5E9, 0x03B9, 0xA5EA, 0x03BA, 0xA5EB, 0x03BB, 0xA5EC, 0x03BC, 0xA5ED, 0x03BD, 0xA5EE, 0x03BE, 0xA5EF, 0x03BF, 0xA5F0, 0x03C0, 0xA5F1, 0x03C1, 0xA5F2, 0x03C3, 0xA5F3, 0x03C4, 0xA5F4, 0x03C5, 0xA5F5, 0x03C6, 0xA5F6, 0x03C7, 0xA5F7, 0x03C8, 0xA5F8, 0x03C9, 0xA641, 0xCAA8, 0xA642, 0xCAA9, 0xA643, 0xCAAA, 0xA644, 0xCAAB, 0xA645, 0xCAAC, 0xA646, 0xCAAD, 0xA647, 0xCAAE, 0xA648, 0xCAAF, 0xA649, 0xCAB0, 0xA64A, 0xCAB1, 0xA64B, 0xCAB2, 0xA64C, 0xCAB3, 0xA64D, 0xCAB4, 0xA64E, 0xCAB5, 0xA64F, 0xCAB6, 0xA650, 0xCAB7, 0xA651, 0xCAB8, 0xA652, 0xCAB9, 0xA653, 0xCABA, 0xA654, 0xCABB, 0xA655, 0xCABE, 0xA656, 0xCABF, 0xA657, 0xCAC1, 0xA658, 0xCAC2, 0xA659, 0xCAC3, 0xA65A, 0xCAC5, 0xA661, 0xCAC6, 0xA662, 0xCAC7, 0xA663, 0xCAC8, 0xA664, 0xCAC9, 0xA665, 0xCACA, 0xA666, 0xCACB, 0xA667, 0xCACE, 0xA668, 0xCAD0, 0xA669, 0xCAD2, 0xA66A, 0xCAD4, 0xA66B, 0xCAD5, 0xA66C, 0xCAD6, 0xA66D, 0xCAD7, 0xA66E, 0xCADA, 0xA66F, 0xCADB, 0xA670, 0xCADC, 0xA671, 0xCADD, 0xA672, 0xCADE, 0xA673, 0xCADF, 0xA674, 0xCAE1, 0xA675, 0xCAE2, 0xA676, 0xCAE3, 0xA677, 0xCAE4, 0xA678, 0xCAE5, 0xA679, 0xCAE6, 0xA67A, 0xCAE7, 0xA681, 0xCAE8, 0xA682, 0xCAE9, 0xA683, 0xCAEA, 0xA684, 0xCAEB, 0xA685, 0xCAED, 0xA686, 0xCAEE, 0xA687, 0xCAEF, 0xA688, 0xCAF0, 0xA689, 0xCAF1, 0xA68A, 0xCAF2, 0xA68B, 0xCAF3, 0xA68C, 0xCAF5, 0xA68D, 0xCAF6, 0xA68E, 0xCAF7, 0xA68F, 0xCAF8, 0xA690, 0xCAF9, 0xA691, 0xCAFA, 0xA692, 0xCAFB, 0xA693, 0xCAFC, 0xA694, 0xCAFD, 0xA695, 0xCAFE, 0xA696, 0xCAFF, 0xA697, 0xCB00, 0xA698, 0xCB01, 0xA699, 0xCB02, 0xA69A, 0xCB03, 0xA69B, 0xCB04, 0xA69C, 0xCB05, 0xA69D, 0xCB06, 0xA69E, 0xCB07, 0xA69F, 0xCB09, 0xA6A0, 0xCB0A, 0xA6A1, 0x2500, 0xA6A2, 0x2502, 0xA6A3, 0x250C, 0xA6A4, 0x2510, 0xA6A5, 0x2518, 0xA6A6, 0x2514, 0xA6A7, 0x251C, 0xA6A8, 0x252C, 0xA6A9, 0x2524, 0xA6AA, 0x2534, 0xA6AB, 0x253C, 0xA6AC, 0x2501, 0xA6AD, 0x2503, 0xA6AE, 0x250F, 0xA6AF, 0x2513, 0xA6B0, 0x251B, 0xA6B1, 0x2517, 0xA6B2, 0x2523, 0xA6B3, 0x2533, 0xA6B4, 0x252B, 0xA6B5, 0x253B, 0xA6B6, 0x254B, 0xA6B7, 0x2520, 0xA6B8, 0x252F, 0xA6B9, 0x2528, 0xA6BA, 0x2537, 0xA6BB, 0x253F, 0xA6BC, 0x251D, 0xA6BD, 0x2530, 0xA6BE, 0x2525, 0xA6BF, 0x2538, 0xA6C0, 0x2542, 0xA6C1, 0x2512, 0xA6C2, 0x2511, 0xA6C3, 0x251A, 0xA6C4, 0x2519, 0xA6C5, 0x2516, 0xA6C6, 0x2515, 0xA6C7, 0x250E, 0xA6C8, 0x250D, 0xA6C9, 0x251E, 0xA6CA, 0x251F, 0xA6CB, 0x2521, 0xA6CC, 0x2522, 0xA6CD, 0x2526, 0xA6CE, 0x2527, 0xA6CF, 0x2529, 0xA6D0, 0x252A, 0xA6D1, 0x252D, 0xA6D2, 0x252E, 0xA6D3, 0x2531, 0xA6D4, 0x2532, 0xA6D5, 0x2535, 0xA6D6, 0x2536, 0xA6D7, 0x2539, 0xA6D8, 0x253A, 0xA6D9, 0x253D, 0xA6DA, 0x253E, 0xA6DB, 0x2540, 0xA6DC, 0x2541, 0xA6DD, 0x2543, 0xA6DE, 0x2544, 0xA6DF, 0x2545, 0xA6E0, 0x2546, 0xA6E1, 0x2547, 0xA6E2, 0x2548, 0xA6E3, 0x2549, 0xA6E4, 0x254A, 0xA741, 0xCB0B, 0xA742, 0xCB0C, 0xA743, 0xCB0D, 0xA744, 0xCB0E, 0xA745, 0xCB0F, 0xA746, 0xCB11, 0xA747, 0xCB12, 0xA748, 0xCB13, 0xA749, 0xCB15, 0xA74A, 0xCB16, 0xA74B, 0xCB17, 0xA74C, 0xCB19, 0xA74D, 0xCB1A, 0xA74E, 0xCB1B, 0xA74F, 0xCB1C, 0xA750, 0xCB1D, 0xA751, 0xCB1E, 0xA752, 0xCB1F, 0xA753, 0xCB22, 0xA754, 0xCB23, 0xA755, 0xCB24, 0xA756, 0xCB25, 0xA757, 0xCB26, 0xA758, 0xCB27, 0xA759, 0xCB28, 0xA75A, 0xCB29, 0xA761, 0xCB2A, 0xA762, 0xCB2B, 0xA763, 0xCB2C, 0xA764, 0xCB2D, 0xA765, 0xCB2E, 0xA766, 0xCB2F, 0xA767, 0xCB30, 0xA768, 0xCB31, 0xA769, 0xCB32, 0xA76A, 0xCB33, 0xA76B, 0xCB34, 0xA76C, 0xCB35, 0xA76D, 0xCB36, 0xA76E, 0xCB37, 0xA76F, 0xCB38, 0xA770, 0xCB39, 0xA771, 0xCB3A, 0xA772, 0xCB3B, 0xA773, 0xCB3C, 0xA774, 0xCB3D, 0xA775, 0xCB3E, 0xA776, 0xCB3F, 0xA777, 0xCB40, 0xA778, 0xCB42, 0xA779, 0xCB43, 0xA77A, 0xCB44, 0xA781, 0xCB45, 0xA782, 0xCB46, 0xA783, 0xCB47, 0xA784, 0xCB4A, 0xA785, 0xCB4B, 0xA786, 0xCB4D, 0xA787, 0xCB4E, 0xA788, 0xCB4F, 0xA789, 0xCB51, 0xA78A, 0xCB52, 0xA78B, 0xCB53, 0xA78C, 0xCB54, 0xA78D, 0xCB55, 0xA78E, 0xCB56, 0xA78F, 0xCB57, 0xA790, 0xCB5A, 0xA791, 0xCB5B, 0xA792, 0xCB5C, 0xA793, 0xCB5E, 0xA794, 0xCB5F, 0xA795, 0xCB60, 0xA796, 0xCB61, 0xA797, 0xCB62, 0xA798, 0xCB63, 0xA799, 0xCB65, 0xA79A, 0xCB66, 0xA79B, 0xCB67, 0xA79C, 0xCB68, 0xA79D, 0xCB69, 0xA79E, 0xCB6A, 0xA79F, 0xCB6B, 0xA7A0, 0xCB6C, 0xA7A1, 0x3395, 0xA7A2, 0x3396, 0xA7A3, 0x3397, 0xA7A4, 0x2113, 0xA7A5, 0x3398, 0xA7A6, 0x33C4, 0xA7A7, 0x33A3, 0xA7A8, 0x33A4, 0xA7A9, 0x33A5, 0xA7AA, 0x33A6, 0xA7AB, 0x3399, 0xA7AC, 0x339A, 0xA7AD, 0x339B, 0xA7AE, 0x339C, 0xA7AF, 0x339D, 0xA7B0, 0x339E, 0xA7B1, 0x339F, 0xA7B2, 0x33A0, 0xA7B3, 0x33A1, 0xA7B4, 0x33A2, 0xA7B5, 0x33CA, 0xA7B6, 0x338D, 0xA7B7, 0x338E, 0xA7B8, 0x338F, 0xA7B9, 0x33CF, 0xA7BA, 0x3388, 0xA7BB, 0x3389, 0xA7BC, 0x33C8, 0xA7BD, 0x33A7, 0xA7BE, 0x33A8, 0xA7BF, 0x33B0, 0xA7C0, 0x33B1, 0xA7C1, 0x33B2, 0xA7C2, 0x33B3, 0xA7C3, 0x33B4, 0xA7C4, 0x33B5, 0xA7C5, 0x33B6, 0xA7C6, 0x33B7, 0xA7C7, 0x33B8, 0xA7C8, 0x33B9, 0xA7C9, 0x3380, 0xA7CA, 0x3381, 0xA7CB, 0x3382, 0xA7CC, 0x3383, 0xA7CD, 0x3384, 0xA7CE, 0x33BA, 0xA7CF, 0x33BB, 0xA7D0, 0x33BC, 0xA7D1, 0x33BD, 0xA7D2, 0x33BE, 0xA7D3, 0x33BF, 0xA7D4, 0x3390, 0xA7D5, 0x3391, 0xA7D6, 0x3392, 0xA7D7, 0x3393, 0xA7D8, 0x3394, 0xA7D9, 0x2126, 0xA7DA, 0x33C0, 0xA7DB, 0x33C1, 0xA7DC, 0x338A, 0xA7DD, 0x338B, 0xA7DE, 0x338C, 0xA7DF, 0x33D6, 0xA7E0, 0x33C5, 0xA7E1, 0x33AD, 0xA7E2, 0x33AE, 0xA7E3, 0x33AF, 0xA7E4, 0x33DB, 0xA7E5, 0x33A9, 0xA7E6, 0x33AA, 0xA7E7, 0x33AB, 0xA7E8, 0x33AC, 0xA7E9, 0x33DD, 0xA7EA, 0x33D0, 0xA7EB, 0x33D3, 0xA7EC, 0x33C3, 0xA7ED, 0x33C9, 0xA7EE, 0x33DC, 0xA7EF, 0x33C6, 0xA841, 0xCB6D, 0xA842, 0xCB6E, 0xA843, 0xCB6F, 0xA844, 0xCB70, 0xA845, 0xCB71, 0xA846, 0xCB72, 0xA847, 0xCB73, 0xA848, 0xCB74, 0xA849, 0xCB75, 0xA84A, 0xCB76, 0xA84B, 0xCB77, 0xA84C, 0xCB7A, 0xA84D, 0xCB7B, 0xA84E, 0xCB7C, 0xA84F, 0xCB7D, 0xA850, 0xCB7E, 0xA851, 0xCB7F, 0xA852, 0xCB80, 0xA853, 0xCB81, 0xA854, 0xCB82, 0xA855, 0xCB83, 0xA856, 0xCB84, 0xA857, 0xCB85, 0xA858, 0xCB86, 0xA859, 0xCB87, 0xA85A, 0xCB88, 0xA861, 0xCB89, 0xA862, 0xCB8A, 0xA863, 0xCB8B, 0xA864, 0xCB8C, 0xA865, 0xCB8D, 0xA866, 0xCB8E, 0xA867, 0xCB8F, 0xA868, 0xCB90, 0xA869, 0xCB91, 0xA86A, 0xCB92, 0xA86B, 0xCB93, 0xA86C, 0xCB94, 0xA86D, 0xCB95, 0xA86E, 0xCB96, 0xA86F, 0xCB97, 0xA870, 0xCB98, 0xA871, 0xCB99, 0xA872, 0xCB9A, 0xA873, 0xCB9B, 0xA874, 0xCB9D, 0xA875, 0xCB9E, 0xA876, 0xCB9F, 0xA877, 0xCBA0, 0xA878, 0xCBA1, 0xA879, 0xCBA2, 0xA87A, 0xCBA3, 0xA881, 0xCBA4, 0xA882, 0xCBA5, 0xA883, 0xCBA6, 0xA884, 0xCBA7, 0xA885, 0xCBA8, 0xA886, 0xCBA9, 0xA887, 0xCBAA, 0xA888, 0xCBAB, 0xA889, 0xCBAC, 0xA88A, 0xCBAD, 0xA88B, 0xCBAE, 0xA88C, 0xCBAF, 0xA88D, 0xCBB0, 0xA88E, 0xCBB1, 0xA88F, 0xCBB2, 0xA890, 0xCBB3, 0xA891, 0xCBB4, 0xA892, 0xCBB5, 0xA893, 0xCBB6, 0xA894, 0xCBB7, 0xA895, 0xCBB9, 0xA896, 0xCBBA, 0xA897, 0xCBBB, 0xA898, 0xCBBC, 0xA899, 0xCBBD, 0xA89A, 0xCBBE, 0xA89B, 0xCBBF, 0xA89C, 0xCBC0, 0xA89D, 0xCBC1, 0xA89E, 0xCBC2, 0xA89F, 0xCBC3, 0xA8A0, 0xCBC4, 0xA8A1, 0x00C6, 0xA8A2, 0x00D0, 0xA8A3, 0x00AA, 0xA8A4, 0x0126, 0xA8A6, 0x0132, 0xA8A8, 0x013F, 0xA8A9, 0x0141, 0xA8AA, 0x00D8, 0xA8AB, 0x0152, 0xA8AC, 0x00BA, 0xA8AD, 0x00DE, 0xA8AE, 0x0166, 0xA8AF, 0x014A, 0xA8B1, 0x3260, 0xA8B2, 0x3261, 0xA8B3, 0x3262, 0xA8B4, 0x3263, 0xA8B5, 0x3264, 0xA8B6, 0x3265, 0xA8B7, 0x3266, 0xA8B8, 0x3267, 0xA8B9, 0x3268, 0xA8BA, 0x3269, 0xA8BB, 0x326A, 0xA8BC, 0x326B, 0xA8BD, 0x326C, 0xA8BE, 0x326D, 0xA8BF, 0x326E, 0xA8C0, 0x326F, 0xA8C1, 0x3270, 0xA8C2, 0x3271, 0xA8C3, 0x3272, 0xA8C4, 0x3273, 0xA8C5, 0x3274, 0xA8C6, 0x3275, 0xA8C7, 0x3276, 0xA8C8, 0x3277, 0xA8C9, 0x3278, 0xA8CA, 0x3279, 0xA8CB, 0x327A, 0xA8CC, 0x327B, 0xA8CD, 0x24D0, 0xA8CE, 0x24D1, 0xA8CF, 0x24D2, 0xA8D0, 0x24D3, 0xA8D1, 0x24D4, 0xA8D2, 0x24D5, 0xA8D3, 0x24D6, 0xA8D4, 0x24D7, 0xA8D5, 0x24D8, 0xA8D6, 0x24D9, 0xA8D7, 0x24DA, 0xA8D8, 0x24DB, 0xA8D9, 0x24DC, 0xA8DA, 0x24DD, 0xA8DB, 0x24DE, 0xA8DC, 0x24DF, 0xA8DD, 0x24E0, 0xA8DE, 0x24E1, 0xA8DF, 0x24E2, 0xA8E0, 0x24E3, 0xA8E1, 0x24E4, 0xA8E2, 0x24E5, 0xA8E3, 0x24E6, 0xA8E4, 0x24E7, 0xA8E5, 0x24E8, 0xA8E6, 0x24E9, 0xA8E7, 0x2460, 0xA8E8, 0x2461, 0xA8E9, 0x2462, 0xA8EA, 0x2463, 0xA8EB, 0x2464, 0xA8EC, 0x2465, 0xA8ED, 0x2466, 0xA8EE, 0x2467, 0xA8EF, 0x2468, 0xA8F0, 0x2469, 0xA8F1, 0x246A, 0xA8F2, 0x246B, 0xA8F3, 0x246C, 0xA8F4, 0x246D, 0xA8F5, 0x246E, 0xA8F6, 0x00BD, 0xA8F7, 0x2153, 0xA8F8, 0x2154, 0xA8F9, 0x00BC, 0xA8FA, 0x00BE, 0xA8FB, 0x215B, 0xA8FC, 0x215C, 0xA8FD, 0x215D, 0xA8FE, 0x215E, 0xA941, 0xCBC5, 0xA942, 0xCBC6, 0xA943, 0xCBC7, 0xA944, 0xCBC8, 0xA945, 0xCBC9, 0xA946, 0xCBCA, 0xA947, 0xCBCB, 0xA948, 0xCBCC, 0xA949, 0xCBCD, 0xA94A, 0xCBCE, 0xA94B, 0xCBCF, 0xA94C, 0xCBD0, 0xA94D, 0xCBD1, 0xA94E, 0xCBD2, 0xA94F, 0xCBD3, 0xA950, 0xCBD5, 0xA951, 0xCBD6, 0xA952, 0xCBD7, 0xA953, 0xCBD8, 0xA954, 0xCBD9, 0xA955, 0xCBDA, 0xA956, 0xCBDB, 0xA957, 0xCBDC, 0xA958, 0xCBDD, 0xA959, 0xCBDE, 0xA95A, 0xCBDF, 0xA961, 0xCBE0, 0xA962, 0xCBE1, 0xA963, 0xCBE2, 0xA964, 0xCBE3, 0xA965, 0xCBE5, 0xA966, 0xCBE6, 0xA967, 0xCBE8, 0xA968, 0xCBEA, 0xA969, 0xCBEB, 0xA96A, 0xCBEC, 0xA96B, 0xCBED, 0xA96C, 0xCBEE, 0xA96D, 0xCBEF, 0xA96E, 0xCBF0, 0xA96F, 0xCBF1, 0xA970, 0xCBF2, 0xA971, 0xCBF3, 0xA972, 0xCBF4, 0xA973, 0xCBF5, 0xA974, 0xCBF6, 0xA975, 0xCBF7, 0xA976, 0xCBF8, 0xA977, 0xCBF9, 0xA978, 0xCBFA, 0xA979, 0xCBFB, 0xA97A, 0xCBFC, 0xA981, 0xCBFD, 0xA982, 0xCBFE, 0xA983, 0xCBFF, 0xA984, 0xCC00, 0xA985, 0xCC01, 0xA986, 0xCC02, 0xA987, 0xCC03, 0xA988, 0xCC04, 0xA989, 0xCC05, 0xA98A, 0xCC06, 0xA98B, 0xCC07, 0xA98C, 0xCC08, 0xA98D, 0xCC09, 0xA98E, 0xCC0A, 0xA98F, 0xCC0B, 0xA990, 0xCC0E, 0xA991, 0xCC0F, 0xA992, 0xCC11, 0xA993, 0xCC12, 0xA994, 0xCC13, 0xA995, 0xCC15, 0xA996, 0xCC16, 0xA997, 0xCC17, 0xA998, 0xCC18, 0xA999, 0xCC19, 0xA99A, 0xCC1A, 0xA99B, 0xCC1B, 0xA99C, 0xCC1E, 0xA99D, 0xCC1F, 0xA99E, 0xCC20, 0xA99F, 0xCC23, 0xA9A0, 0xCC24, 0xA9A1, 0x00E6, 0xA9A2, 0x0111, 0xA9A3, 0x00F0, 0xA9A4, 0x0127, 0xA9A5, 0x0131, 0xA9A6, 0x0133, 0xA9A7, 0x0138, 0xA9A8, 0x0140, 0xA9A9, 0x0142, 0xA9AA, 0x00F8, 0xA9AB, 0x0153, 0xA9AC, 0x00DF, 0xA9AD, 0x00FE, 0xA9AE, 0x0167, 0xA9AF, 0x014B, 0xA9B0, 0x0149, 0xA9B1, 0x3200, 0xA9B2, 0x3201, 0xA9B3, 0x3202, 0xA9B4, 0x3203, 0xA9B5, 0x3204, 0xA9B6, 0x3205, 0xA9B7, 0x3206, 0xA9B8, 0x3207, 0xA9B9, 0x3208, 0xA9BA, 0x3209, 0xA9BB, 0x320A, 0xA9BC, 0x320B, 0xA9BD, 0x320C, 0xA9BE, 0x320D, 0xA9BF, 0x320E, 0xA9C0, 0x320F, 0xA9C1, 0x3210, 0xA9C2, 0x3211, 0xA9C3, 0x3212, 0xA9C4, 0x3213, 0xA9C5, 0x3214, 0xA9C6, 0x3215, 0xA9C7, 0x3216, 0xA9C8, 0x3217, 0xA9C9, 0x3218, 0xA9CA, 0x3219, 0xA9CB, 0x321A, 0xA9CC, 0x321B, 0xA9CD, 0x249C, 0xA9CE, 0x249D, 0xA9CF, 0x249E, 0xA9D0, 0x249F, 0xA9D1, 0x24A0, 0xA9D2, 0x24A1, 0xA9D3, 0x24A2, 0xA9D4, 0x24A3, 0xA9D5, 0x24A4, 0xA9D6, 0x24A5, 0xA9D7, 0x24A6, 0xA9D8, 0x24A7, 0xA9D9, 0x24A8, 0xA9DA, 0x24A9, 0xA9DB, 0x24AA, 0xA9DC, 0x24AB, 0xA9DD, 0x24AC, 0xA9DE, 0x24AD, 0xA9DF, 0x24AE, 0xA9E0, 0x24AF, 0xA9E1, 0x24B0, 0xA9E2, 0x24B1, 0xA9E3, 0x24B2, 0xA9E4, 0x24B3, 0xA9E5, 0x24B4, 0xA9E6, 0x24B5, 0xA9E7, 0x2474, 0xA9E8, 0x2475, 0xA9E9, 0x2476, 0xA9EA, 0x2477, 0xA9EB, 0x2478, 0xA9EC, 0x2479, 0xA9ED, 0x247A, 0xA9EE, 0x247B, 0xA9EF, 0x247C, 0xA9F0, 0x247D, 0xA9F1, 0x247E, 0xA9F2, 0x247F, 0xA9F3, 0x2480, 0xA9F4, 0x2481, 0xA9F5, 0x2482, 0xA9F6, 0x00B9, 0xA9F7, 0x00B2, 0xA9F8, 0x00B3, 0xA9F9, 0x2074, 0xA9FA, 0x207F, 0xA9FB, 0x2081, 0xA9FC, 0x2082, 0xA9FD, 0x2083, 0xA9FE, 0x2084, 0xAA41, 0xCC25, 0xAA42, 0xCC26, 0xAA43, 0xCC2A, 0xAA44, 0xCC2B, 0xAA45, 0xCC2D, 0xAA46, 0xCC2F, 0xAA47, 0xCC31, 0xAA48, 0xCC32, 0xAA49, 0xCC33, 0xAA4A, 0xCC34, 0xAA4B, 0xCC35, 0xAA4C, 0xCC36, 0xAA4D, 0xCC37, 0xAA4E, 0xCC3A, 0xAA4F, 0xCC3F, 0xAA50, 0xCC40, 0xAA51, 0xCC41, 0xAA52, 0xCC42, 0xAA53, 0xCC43, 0xAA54, 0xCC46, 0xAA55, 0xCC47, 0xAA56, 0xCC49, 0xAA57, 0xCC4A, 0xAA58, 0xCC4B, 0xAA59, 0xCC4D, 0xAA5A, 0xCC4E, 0xAA61, 0xCC4F, 0xAA62, 0xCC50, 0xAA63, 0xCC51, 0xAA64, 0xCC52, 0xAA65, 0xCC53, 0xAA66, 0xCC56, 0xAA67, 0xCC5A, 0xAA68, 0xCC5B, 0xAA69, 0xCC5C, 0xAA6A, 0xCC5D, 0xAA6B, 0xCC5E, 0xAA6C, 0xCC5F, 0xAA6D, 0xCC61, 0xAA6E, 0xCC62, 0xAA6F, 0xCC63, 0xAA70, 0xCC65, 0xAA71, 0xCC67, 0xAA72, 0xCC69, 0xAA73, 0xCC6A, 0xAA74, 0xCC6B, 0xAA75, 0xCC6C, 0xAA76, 0xCC6D, 0xAA77, 0xCC6E, 0xAA78, 0xCC6F, 0xAA79, 0xCC71, 0xAA7A, 0xCC72, 0xAA81, 0xCC73, 0xAA82, 0xCC74, 0xAA83, 0xCC76, 0xAA84, 0xCC77, 0xAA85, 0xCC78, 0xAA86, 0xCC79, 0xAA87, 0xCC7A, 0xAA88, 0xCC7B, 0xAA89, 0xCC7C, 0xAA8A, 0xCC7D, 0xAA8B, 0xCC7E, 0xAA8C, 0xCC7F, 0xAA8D, 0xCC80, 0xAA8E, 0xCC81, 0xAA8F, 0xCC82, 0xAA90, 0xCC83, 0xAA91, 0xCC84, 0xAA92, 0xCC85, 0xAA93, 0xCC86, 0xAA94, 0xCC87, 0xAA95, 0xCC88, 0xAA96, 0xCC89, 0xAA97, 0xCC8A, 0xAA98, 0xCC8B, 0xAA99, 0xCC8C, 0xAA9A, 0xCC8D, 0xAA9B, 0xCC8E, 0xAA9C, 0xCC8F, 0xAA9D, 0xCC90, 0xAA9E, 0xCC91, 0xAA9F, 0xCC92, 0xAAA0, 0xCC93, 0xAAA1, 0x3041, 0xAAA2, 0x3042, 0xAAA3, 0x3043, 0xAAA4, 0x3044, 0xAAA5, 0x3045, 0xAAA6, 0x3046, 0xAAA7, 0x3047, 0xAAA8, 0x3048, 0xAAA9, 0x3049, 0xAAAA, 0x304A, 0xAAAB, 0x304B, 0xAAAC, 0x304C, 0xAAAD, 0x304D, 0xAAAE, 0x304E, 0xAAAF, 0x304F, 0xAAB0, 0x3050, 0xAAB1, 0x3051, 0xAAB2, 0x3052, 0xAAB3, 0x3053, 0xAAB4, 0x3054, 0xAAB5, 0x3055, 0xAAB6, 0x3056, 0xAAB7, 0x3057, 0xAAB8, 0x3058, 0xAAB9, 0x3059, 0xAABA, 0x305A, 0xAABB, 0x305B, 0xAABC, 0x305C, 0xAABD, 0x305D, 0xAABE, 0x305E, 0xAABF, 0x305F, 0xAAC0, 0x3060, 0xAAC1, 0x3061, 0xAAC2, 0x3062, 0xAAC3, 0x3063, 0xAAC4, 0x3064, 0xAAC5, 0x3065, 0xAAC6, 0x3066, 0xAAC7, 0x3067, 0xAAC8, 0x3068, 0xAAC9, 0x3069, 0xAACA, 0x306A, 0xAACB, 0x306B, 0xAACC, 0x306C, 0xAACD, 0x306D, 0xAACE, 0x306E, 0xAACF, 0x306F, 0xAAD0, 0x3070, 0xAAD1, 0x3071, 0xAAD2, 0x3072, 0xAAD3, 0x3073, 0xAAD4, 0x3074, 0xAAD5, 0x3075, 0xAAD6, 0x3076, 0xAAD7, 0x3077, 0xAAD8, 0x3078, 0xAAD9, 0x3079, 0xAADA, 0x307A, 0xAADB, 0x307B, 0xAADC, 0x307C, 0xAADD, 0x307D, 0xAADE, 0x307E, 0xAADF, 0x307F, 0xAAE0, 0x3080, 0xAAE1, 0x3081, 0xAAE2, 0x3082, 0xAAE3, 0x3083, 0xAAE4, 0x3084, 0xAAE5, 0x3085, 0xAAE6, 0x3086, 0xAAE7, 0x3087, 0xAAE8, 0x3088, 0xAAE9, 0x3089, 0xAAEA, 0x308A, 0xAAEB, 0x308B, 0xAAEC, 0x308C, 0xAAED, 0x308D, 0xAAEE, 0x308E, 0xAAEF, 0x308F, 0xAAF0, 0x3090, 0xAAF1, 0x3091, 0xAAF2, 0x3092, 0xAAF3, 0x3093, 0xAB41, 0xCC94, 0xAB42, 0xCC95, 0xAB43, 0xCC96, 0xAB44, 0xCC97, 0xAB45, 0xCC9A, 0xAB46, 0xCC9B, 0xAB47, 0xCC9D, 0xAB48, 0xCC9E, 0xAB49, 0xCC9F, 0xAB4A, 0xCCA1, 0xAB4B, 0xCCA2, 0xAB4C, 0xCCA3, 0xAB4D, 0xCCA4, 0xAB4E, 0xCCA5, 0xAB4F, 0xCCA6, 0xAB50, 0xCCA7, 0xAB51, 0xCCAA, 0xAB52, 0xCCAE, 0xAB53, 0xCCAF, 0xAB54, 0xCCB0, 0xAB55, 0xCCB1, 0xAB56, 0xCCB2, 0xAB57, 0xCCB3, 0xAB58, 0xCCB6, 0xAB59, 0xCCB7, 0xAB5A, 0xCCB9, 0xAB61, 0xCCBA, 0xAB62, 0xCCBB, 0xAB63, 0xCCBD, 0xAB64, 0xCCBE, 0xAB65, 0xCCBF, 0xAB66, 0xCCC0, 0xAB67, 0xCCC1, 0xAB68, 0xCCC2, 0xAB69, 0xCCC3, 0xAB6A, 0xCCC6, 0xAB6B, 0xCCC8, 0xAB6C, 0xCCCA, 0xAB6D, 0xCCCB, 0xAB6E, 0xCCCC, 0xAB6F, 0xCCCD, 0xAB70, 0xCCCE, 0xAB71, 0xCCCF, 0xAB72, 0xCCD1, 0xAB73, 0xCCD2, 0xAB74, 0xCCD3, 0xAB75, 0xCCD5, 0xAB76, 0xCCD6, 0xAB77, 0xCCD7, 0xAB78, 0xCCD8, 0xAB79, 0xCCD9, 0xAB7A, 0xCCDA, 0xAB81, 0xCCDB, 0xAB82, 0xCCDC, 0xAB83, 0xCCDD, 0xAB84, 0xCCDE, 0xAB85, 0xCCDF, 0xAB86, 0xCCE0, 0xAB87, 0xCCE1, 0xAB88, 0xCCE2, 0xAB89, 0xCCE3, 0xAB8A, 0xCCE5, 0xAB8B, 0xCCE6, 0xAB8C, 0xCCE7, 0xAB8D, 0xCCE8, 0xAB8E, 0xCCE9, 0xAB8F, 0xCCEA, 0xAB90, 0xCCEB, 0xAB91, 0xCCED, 0xAB92, 0xCCEE, 0xAB93, 0xCCEF, 0xAB94, 0xCCF1, 0xAB95, 0xCCF2, 0xAB96, 0xCCF3, 0xAB97, 0xCCF4, 0xAB98, 0xCCF5, 0xAB99, 0xCCF6, 0xAB9A, 0xCCF7, 0xAB9B, 0xCCF8, 0xAB9C, 0xCCF9, 0xAB9D, 0xCCFA, 0xAB9E, 0xCCFB, 0xAB9F, 0xCCFC, 0xABA0, 0xCCFD, 0xABA1, 0x30A1, 0xABA2, 0x30A2, 0xABA3, 0x30A3, 0xABA4, 0x30A4, 0xABA5, 0x30A5, 0xABA6, 0x30A6, 0xABA7, 0x30A7, 0xABA8, 0x30A8, 0xABA9, 0x30A9, 0xABAA, 0x30AA, 0xABAB, 0x30AB, 0xABAC, 0x30AC, 0xABAD, 0x30AD, 0xABAE, 0x30AE, 0xABAF, 0x30AF, 0xABB0, 0x30B0, 0xABB1, 0x30B1, 0xABB2, 0x30B2, 0xABB3, 0x30B3, 0xABB4, 0x30B4, 0xABB5, 0x30B5, 0xABB6, 0x30B6, 0xABB7, 0x30B7, 0xABB8, 0x30B8, 0xABB9, 0x30B9, 0xABBA, 0x30BA, 0xABBB, 0x30BB, 0xABBC, 0x30BC, 0xABBD, 0x30BD, 0xABBE, 0x30BE, 0xABBF, 0x30BF, 0xABC0, 0x30C0, 0xABC1, 0x30C1, 0xABC2, 0x30C2, 0xABC3, 0x30C3, 0xABC4, 0x30C4, 0xABC5, 0x30C5, 0xABC6, 0x30C6, 0xABC7, 0x30C7, 0xABC8, 0x30C8, 0xABC9, 0x30C9, 0xABCA, 0x30CA, 0xABCB, 0x30CB, 0xABCC, 0x30CC, 0xABCD, 0x30CD, 0xABCE, 0x30CE, 0xABCF, 0x30CF, 0xABD0, 0x30D0, 0xABD1, 0x30D1, 0xABD2, 0x30D2, 0xABD3, 0x30D3, 0xABD4, 0x30D4, 0xABD5, 0x30D5, 0xABD6, 0x30D6, 0xABD7, 0x30D7, 0xABD8, 0x30D8, 0xABD9, 0x30D9, 0xABDA, 0x30DA, 0xABDB, 0x30DB, 0xABDC, 0x30DC, 0xABDD, 0x30DD, 0xABDE, 0x30DE, 0xABDF, 0x30DF, 0xABE0, 0x30E0, 0xABE1, 0x30E1, 0xABE2, 0x30E2, 0xABE3, 0x30E3, 0xABE4, 0x30E4, 0xABE5, 0x30E5, 0xABE6, 0x30E6, 0xABE7, 0x30E7, 0xABE8, 0x30E8, 0xABE9, 0x30E9, 0xABEA, 0x30EA, 0xABEB, 0x30EB, 0xABEC, 0x30EC, 0xABED, 0x30ED, 0xABEE, 0x30EE, 0xABEF, 0x30EF, 0xABF0, 0x30F0, 0xABF1, 0x30F1, 0xABF2, 0x30F2, 0xABF3, 0x30F3, 0xABF4, 0x30F4, 0xABF5, 0x30F5, 0xABF6, 0x30F6, 0xAC41, 0xCCFE, 0xAC42, 0xCCFF, 0xAC43, 0xCD00, 0xAC44, 0xCD02, 0xAC45, 0xCD03, 0xAC46, 0xCD04, 0xAC47, 0xCD05, 0xAC48, 0xCD06, 0xAC49, 0xCD07, 0xAC4A, 0xCD0A, 0xAC4B, 0xCD0B, 0xAC4C, 0xCD0D, 0xAC4D, 0xCD0E, 0xAC4E, 0xCD0F, 0xAC4F, 0xCD11, 0xAC50, 0xCD12, 0xAC51, 0xCD13, 0xAC52, 0xCD14, 0xAC53, 0xCD15, 0xAC54, 0xCD16, 0xAC55, 0xCD17, 0xAC56, 0xCD1A, 0xAC57, 0xCD1C, 0xAC58, 0xCD1E, 0xAC59, 0xCD1F, 0xAC5A, 0xCD20, 0xAC61, 0xCD21, 0xAC62, 0xCD22, 0xAC63, 0xCD23, 0xAC64, 0xCD25, 0xAC65, 0xCD26, 0xAC66, 0xCD27, 0xAC67, 0xCD29, 0xAC68, 0xCD2A, 0xAC69, 0xCD2B, 0xAC6A, 0xCD2D, 0xAC6B, 0xCD2E, 0xAC6C, 0xCD2F, 0xAC6D, 0xCD30, 0xAC6E, 0xCD31, 0xAC6F, 0xCD32, 0xAC70, 0xCD33, 0xAC71, 0xCD34, 0xAC72, 0xCD35, 0xAC73, 0xCD36, 0xAC74, 0xCD37, 0xAC75, 0xCD38, 0xAC76, 0xCD3A, 0xAC77, 0xCD3B, 0xAC78, 0xCD3C, 0xAC79, 0xCD3D, 0xAC7A, 0xCD3E, 0xAC81, 0xCD3F, 0xAC82, 0xCD40, 0xAC83, 0xCD41, 0xAC84, 0xCD42, 0xAC85, 0xCD43, 0xAC86, 0xCD44, 0xAC87, 0xCD45, 0xAC88, 0xCD46, 0xAC89, 0xCD47, 0xAC8A, 0xCD48, 0xAC8B, 0xCD49, 0xAC8C, 0xCD4A, 0xAC8D, 0xCD4B, 0xAC8E, 0xCD4C, 0xAC8F, 0xCD4D, 0xAC90, 0xCD4E, 0xAC91, 0xCD4F, 0xAC92, 0xCD50, 0xAC93, 0xCD51, 0xAC94, 0xCD52, 0xAC95, 0xCD53, 0xAC96, 0xCD54, 0xAC97, 0xCD55, 0xAC98, 0xCD56, 0xAC99, 0xCD57, 0xAC9A, 0xCD58, 0xAC9B, 0xCD59, 0xAC9C, 0xCD5A, 0xAC9D, 0xCD5B, 0xAC9E, 0xCD5D, 0xAC9F, 0xCD5E, 0xACA0, 0xCD5F, 0xACA1, 0x0410, 0xACA2, 0x0411, 0xACA3, 0x0412, 0xACA4, 0x0413, 0xACA5, 0x0414, 0xACA6, 0x0415, 0xACA7, 0x0401, 0xACA8, 0x0416, 0xACA9, 0x0417, 0xACAA, 0x0418, 0xACAB, 0x0419, 0xACAC, 0x041A, 0xACAD, 0x041B, 0xACAE, 0x041C, 0xACAF, 0x041D, 0xACB0, 0x041E, 0xACB1, 0x041F, 0xACB2, 0x0420, 0xACB3, 0x0421, 0xACB4, 0x0422, 0xACB5, 0x0423, 0xACB6, 0x0424, 0xACB7, 0x0425, 0xACB8, 0x0426, 0xACB9, 0x0427, 0xACBA, 0x0428, 0xACBB, 0x0429, 0xACBC, 0x042A, 0xACBD, 0x042B, 0xACBE, 0x042C, 0xACBF, 0x042D, 0xACC0, 0x042E, 0xACC1, 0x042F, 0xACD1, 0x0430, 0xACD2, 0x0431, 0xACD3, 0x0432, 0xACD4, 0x0433, 0xACD5, 0x0434, 0xACD6, 0x0435, 0xACD7, 0x0451, 0xACD8, 0x0436, 0xACD9, 0x0437, 0xACDA, 0x0438, 0xACDB, 0x0439, 0xACDC, 0x043A, 0xACDD, 0x043B, 0xACDE, 0x043C, 0xACDF, 0x043D, 0xACE0, 0x043E, 0xACE1, 0x043F, 0xACE2, 0x0440, 0xACE3, 0x0441, 0xACE4, 0x0442, 0xACE5, 0x0443, 0xACE6, 0x0444, 0xACE7, 0x0445, 0xACE8, 0x0446, 0xACE9, 0x0447, 0xACEA, 0x0448, 0xACEB, 0x0449, 0xACEC, 0x044A, 0xACED, 0x044B, 0xACEE, 0x044C, 0xACEF, 0x044D, 0xACF0, 0x044E, 0xACF1, 0x044F, 0xAD41, 0xCD61, 0xAD42, 0xCD62, 0xAD43, 0xCD63, 0xAD44, 0xCD65, 0xAD45, 0xCD66, 0xAD46, 0xCD67, 0xAD47, 0xCD68, 0xAD48, 0xCD69, 0xAD49, 0xCD6A, 0xAD4A, 0xCD6B, 0xAD4B, 0xCD6E, 0xAD4C, 0xCD70, 0xAD4D, 0xCD72, 0xAD4E, 0xCD73, 0xAD4F, 0xCD74, 0xAD50, 0xCD75, 0xAD51, 0xCD76, 0xAD52, 0xCD77, 0xAD53, 0xCD79, 0xAD54, 0xCD7A, 0xAD55, 0xCD7B, 0xAD56, 0xCD7C, 0xAD57, 0xCD7D, 0xAD58, 0xCD7E, 0xAD59, 0xCD7F, 0xAD5A, 0xCD80, 0xAD61, 0xCD81, 0xAD62, 0xCD82, 0xAD63, 0xCD83, 0xAD64, 0xCD84, 0xAD65, 0xCD85, 0xAD66, 0xCD86, 0xAD67, 0xCD87, 0xAD68, 0xCD89, 0xAD69, 0xCD8A, 0xAD6A, 0xCD8B, 0xAD6B, 0xCD8C, 0xAD6C, 0xCD8D, 0xAD6D, 0xCD8E, 0xAD6E, 0xCD8F, 0xAD6F, 0xCD90, 0xAD70, 0xCD91, 0xAD71, 0xCD92, 0xAD72, 0xCD93, 0xAD73, 0xCD96, 0xAD74, 0xCD97, 0xAD75, 0xCD99, 0xAD76, 0xCD9A, 0xAD77, 0xCD9B, 0xAD78, 0xCD9D, 0xAD79, 0xCD9E, 0xAD7A, 0xCD9F, 0xAD81, 0xCDA0, 0xAD82, 0xCDA1, 0xAD83, 0xCDA2, 0xAD84, 0xCDA3, 0xAD85, 0xCDA6, 0xAD86, 0xCDA8, 0xAD87, 0xCDAA, 0xAD88, 0xCDAB, 0xAD89, 0xCDAC, 0xAD8A, 0xCDAD, 0xAD8B, 0xCDAE, 0xAD8C, 0xCDAF, 0xAD8D, 0xCDB1, 0xAD8E, 0xCDB2, 0xAD8F, 0xCDB3, 0xAD90, 0xCDB4, 0xAD91, 0xCDB5, 0xAD92, 0xCDB6, 0xAD93, 0xCDB7, 0xAD94, 0xCDB8, 0xAD95, 0xCDB9, 0xAD96, 0xCDBA, 0xAD97, 0xCDBB, 0xAD98, 0xCDBC, 0xAD99, 0xCDBD, 0xAD9A, 0xCDBE, 0xAD9B, 0xCDBF, 0xAD9C, 0xCDC0, 0xAD9D, 0xCDC1, 0xAD9E, 0xCDC2, 0xAD9F, 0xCDC3, 0xADA0, 0xCDC5, 0xAE41, 0xCDC6, 0xAE42, 0xCDC7, 0xAE43, 0xCDC8, 0xAE44, 0xCDC9, 0xAE45, 0xCDCA, 0xAE46, 0xCDCB, 0xAE47, 0xCDCD, 0xAE48, 0xCDCE, 0xAE49, 0xCDCF, 0xAE4A, 0xCDD1, 0xAE4B, 0xCDD2, 0xAE4C, 0xCDD3, 0xAE4D, 0xCDD4, 0xAE4E, 0xCDD5, 0xAE4F, 0xCDD6, 0xAE50, 0xCDD7, 0xAE51, 0xCDD8, 0xAE52, 0xCDD9, 0xAE53, 0xCDDA, 0xAE54, 0xCDDB, 0xAE55, 0xCDDC, 0xAE56, 0xCDDD, 0xAE57, 0xCDDE, 0xAE58, 0xCDDF, 0xAE59, 0xCDE0, 0xAE5A, 0xCDE1, 0xAE61, 0xCDE2, 0xAE62, 0xCDE3, 0xAE63, 0xCDE4, 0xAE64, 0xCDE5, 0xAE65, 0xCDE6, 0xAE66, 0xCDE7, 0xAE67, 0xCDE9, 0xAE68, 0xCDEA, 0xAE69, 0xCDEB, 0xAE6A, 0xCDED, 0xAE6B, 0xCDEE, 0xAE6C, 0xCDEF, 0xAE6D, 0xCDF1, 0xAE6E, 0xCDF2, 0xAE6F, 0xCDF3, 0xAE70, 0xCDF4, 0xAE71, 0xCDF5, 0xAE72, 0xCDF6, 0xAE73, 0xCDF7, 0xAE74, 0xCDFA, 0xAE75, 0xCDFC, 0xAE76, 0xCDFE, 0xAE77, 0xCDFF, 0xAE78, 0xCE00, 0xAE79, 0xCE01, 0xAE7A, 0xCE02, 0xAE81, 0xCE03, 0xAE82, 0xCE05, 0xAE83, 0xCE06, 0xAE84, 0xCE07, 0xAE85, 0xCE09, 0xAE86, 0xCE0A, 0xAE87, 0xCE0B, 0xAE88, 0xCE0D, 0xAE89, 0xCE0E, 0xAE8A, 0xCE0F, 0xAE8B, 0xCE10, 0xAE8C, 0xCE11, 0xAE8D, 0xCE12, 0xAE8E, 0xCE13, 0xAE8F, 0xCE15, 0xAE90, 0xCE16, 0xAE91, 0xCE17, 0xAE92, 0xCE18, 0xAE93, 0xCE1A, 0xAE94, 0xCE1B, 0xAE95, 0xCE1C, 0xAE96, 0xCE1D, 0xAE97, 0xCE1E, 0xAE98, 0xCE1F, 0xAE99, 0xCE22, 0xAE9A, 0xCE23, 0xAE9B, 0xCE25, 0xAE9C, 0xCE26, 0xAE9D, 0xCE27, 0xAE9E, 0xCE29, 0xAE9F, 0xCE2A, 0xAEA0, 0xCE2B, 0xAF41, 0xCE2C, 0xAF42, 0xCE2D, 0xAF43, 0xCE2E, 0xAF44, 0xCE2F, 0xAF45, 0xCE32, 0xAF46, 0xCE34, 0xAF47, 0xCE36, 0xAF48, 0xCE37, 0xAF49, 0xCE38, 0xAF4A, 0xCE39, 0xAF4B, 0xCE3A, 0xAF4C, 0xCE3B, 0xAF4D, 0xCE3C, 0xAF4E, 0xCE3D, 0xAF4F, 0xCE3E, 0xAF50, 0xCE3F, 0xAF51, 0xCE40, 0xAF52, 0xCE41, 0xAF53, 0xCE42, 0xAF54, 0xCE43, 0xAF55, 0xCE44, 0xAF56, 0xCE45, 0xAF57, 0xCE46, 0xAF58, 0xCE47, 0xAF59, 0xCE48, 0xAF5A, 0xCE49, 0xAF61, 0xCE4A, 0xAF62, 0xCE4B, 0xAF63, 0xCE4C, 0xAF64, 0xCE4D, 0xAF65, 0xCE4E, 0xAF66, 0xCE4F, 0xAF67, 0xCE50, 0xAF68, 0xCE51, 0xAF69, 0xCE52, 0xAF6A, 0xCE53, 0xAF6B, 0xCE54, 0xAF6C, 0xCE55, 0xAF6D, 0xCE56, 0xAF6E, 0xCE57, 0xAF6F, 0xCE5A, 0xAF70, 0xCE5B, 0xAF71, 0xCE5D, 0xAF72, 0xCE5E, 0xAF73, 0xCE62, 0xAF74, 0xCE63, 0xAF75, 0xCE64, 0xAF76, 0xCE65, 0xAF77, 0xCE66, 0xAF78, 0xCE67, 0xAF79, 0xCE6A, 0xAF7A, 0xCE6C, 0xAF81, 0xCE6E, 0xAF82, 0xCE6F, 0xAF83, 0xCE70, 0xAF84, 0xCE71, 0xAF85, 0xCE72, 0xAF86, 0xCE73, 0xAF87, 0xCE76, 0xAF88, 0xCE77, 0xAF89, 0xCE79, 0xAF8A, 0xCE7A, 0xAF8B, 0xCE7B, 0xAF8C, 0xCE7D, 0xAF8D, 0xCE7E, 0xAF8E, 0xCE7F, 0xAF8F, 0xCE80, 0xAF90, 0xCE81, 0xAF91, 0xCE82, 0xAF92, 0xCE83, 0xAF93, 0xCE86, 0xAF94, 0xCE88, 0xAF95, 0xCE8A, 0xAF96, 0xCE8B, 0xAF97, 0xCE8C, 0xAF98, 0xCE8D, 0xAF99, 0xCE8E, 0xAF9A, 0xCE8F, 0xAF9B, 0xCE92, 0xAF9C, 0xCE93, 0xAF9D, 0xCE95, 0xAF9E, 0xCE96, 0xAF9F, 0xCE97, 0xAFA0, 0xCE99, 0xB041, 0xCE9A, 0xB042, 0xCE9B, 0xB043, 0xCE9C, 0xB044, 0xCE9D, 0xB045, 0xCE9E, 0xB046, 0xCE9F, 0xB047, 0xCEA2, 0xB048, 0xCEA6, 0xB049, 0xCEA7, 0xB04A, 0xCEA8, 0xB04B, 0xCEA9, 0xB04C, 0xCEAA, 0xB04D, 0xCEAB, 0xB04E, 0xCEAE, 0xB04F, 0xCEAF, 0xB050, 0xCEB0, 0xB051, 0xCEB1, 0xB052, 0xCEB2, 0xB053, 0xCEB3, 0xB054, 0xCEB4, 0xB055, 0xCEB5, 0xB056, 0xCEB6, 0xB057, 0xCEB7, 0xB058, 0xCEB8, 0xB059, 0xCEB9, 0xB05A, 0xCEBA, 0xB061, 0xCEBB, 0xB062, 0xCEBC, 0xB063, 0xCEBD, 0xB064, 0xCEBE, 0xB065, 0xCEBF, 0xB066, 0xCEC0, 0xB067, 0xCEC2, 0xB068, 0xCEC3, 0xB069, 0xCEC4, 0xB06A, 0xCEC5, 0xB06B, 0xCEC6, 0xB06C, 0xCEC7, 0xB06D, 0xCEC8, 0xB06E, 0xCEC9, 0xB06F, 0xCECA, 0xB070, 0xCECB, 0xB071, 0xCECC, 0xB072, 0xCECD, 0xB073, 0xCECE, 0xB074, 0xCECF, 0xB075, 0xCED0, 0xB076, 0xCED1, 0xB077, 0xCED2, 0xB078, 0xCED3, 0xB079, 0xCED4, 0xB07A, 0xCED5, 0xB081, 0xCED6, 0xB082, 0xCED7, 0xB083, 0xCED8, 0xB084, 0xCED9, 0xB085, 0xCEDA, 0xB086, 0xCEDB, 0xB087, 0xCEDC, 0xB088, 0xCEDD, 0xB089, 0xCEDE, 0xB08A, 0xCEDF, 0xB08B, 0xCEE0, 0xB08C, 0xCEE1, 0xB08D, 0xCEE2, 0xB08E, 0xCEE3, 0xB08F, 0xCEE6, 0xB090, 0xCEE7, 0xB091, 0xCEE9, 0xB092, 0xCEEA, 0xB093, 0xCEED, 0xB094, 0xCEEE, 0xB095, 0xCEEF, 0xB096, 0xCEF0, 0xB097, 0xCEF1, 0xB098, 0xCEF2, 0xB099, 0xCEF3, 0xB09A, 0xCEF6, 0xB09B, 0xCEFA, 0xB09C, 0xCEFB, 0xB09D, 0xCEFC, 0xB09E, 0xCEFD, 0xB09F, 0xCEFE, 0xB0A0, 0xCEFF, 0xB0A1, 0xAC00, 0xB0A2, 0xAC01, 0xB0A3, 0xAC04, 0xB0A4, 0xAC07, 0xB0A5, 0xAC08, 0xB0A6, 0xAC09, 0xB0A7, 0xAC0A, 0xB0A8, 0xAC10, 0xB0A9, 0xAC11, 0xB0AA, 0xAC12, 0xB0AB, 0xAC13, 0xB0AC, 0xAC14, 0xB0AD, 0xAC15, 0xB0AE, 0xAC16, 0xB0AF, 0xAC17, 0xB0B0, 0xAC19, 0xB0B1, 0xAC1A, 0xB0B2, 0xAC1B, 0xB0B3, 0xAC1C, 0xB0B4, 0xAC1D, 0xB0B5, 0xAC20, 0xB0B6, 0xAC24, 0xB0B7, 0xAC2C, 0xB0B8, 0xAC2D, 0xB0B9, 0xAC2F, 0xB0BA, 0xAC30, 0xB0BB, 0xAC31, 0xB0BC, 0xAC38, 0xB0BD, 0xAC39, 0xB0BE, 0xAC3C, 0xB0BF, 0xAC40, 0xB0C0, 0xAC4B, 0xB0C1, 0xAC4D, 0xB0C2, 0xAC54, 0xB0C3, 0xAC58, 0xB0C4, 0xAC5C, 0xB0C5, 0xAC70, 0xB0C6, 0xAC71, 0xB0C7, 0xAC74, 0xB0C8, 0xAC77, 0xB0C9, 0xAC78, 0xB0CA, 0xAC7A, 0xB0CB, 0xAC80, 0xB0CC, 0xAC81, 0xB0CD, 0xAC83, 0xB0CE, 0xAC84, 0xB0CF, 0xAC85, 0xB0D0, 0xAC86, 0xB0D1, 0xAC89, 0xB0D2, 0xAC8A, 0xB0D3, 0xAC8B, 0xB0D4, 0xAC8C, 0xB0D5, 0xAC90, 0xB0D6, 0xAC94, 0xB0D7, 0xAC9C, 0xB0D8, 0xAC9D, 0xB0D9, 0xAC9F, 0xB0DA, 0xACA0, 0xB0DB, 0xACA1, 0xB0DC, 0xACA8, 0xB0DD, 0xACA9, 0xB0DE, 0xACAA, 0xB0DF, 0xACAC, 0xB0E0, 0xACAF, 0xB0E1, 0xACB0, 0xB0E2, 0xACB8, 0xB0E3, 0xACB9, 0xB0E4, 0xACBB, 0xB0E5, 0xACBC, 0xB0E6, 0xACBD, 0xB0E7, 0xACC1, 0xB0E8, 0xACC4, 0xB0E9, 0xACC8, 0xB0EA, 0xACCC, 0xB0EB, 0xACD5, 0xB0EC, 0xACD7, 0xB0ED, 0xACE0, 0xB0EE, 0xACE1, 0xB0EF, 0xACE4, 0xB0F0, 0xACE7, 0xB0F1, 0xACE8, 0xB0F2, 0xACEA, 0xB0F3, 0xACEC, 0xB0F4, 0xACEF, 0xB0F5, 0xACF0, 0xB0F6, 0xACF1, 0xB0F7, 0xACF3, 0xB0F8, 0xACF5, 0xB0F9, 0xACF6, 0xB0FA, 0xACFC, 0xB0FB, 0xACFD, 0xB0FC, 0xAD00, 0xB0FD, 0xAD04, 0xB0FE, 0xAD06, 0xB141, 0xCF02, 0xB142, 0xCF03, 0xB143, 0xCF05, 0xB144, 0xCF06, 0xB145, 0xCF07, 0xB146, 0xCF09, 0xB147, 0xCF0A, 0xB148, 0xCF0B, 0xB149, 0xCF0C, 0xB14A, 0xCF0D, 0xB14B, 0xCF0E, 0xB14C, 0xCF0F, 0xB14D, 0xCF12, 0xB14E, 0xCF14, 0xB14F, 0xCF16, 0xB150, 0xCF17, 0xB151, 0xCF18, 0xB152, 0xCF19, 0xB153, 0xCF1A, 0xB154, 0xCF1B, 0xB155, 0xCF1D, 0xB156, 0xCF1E, 0xB157, 0xCF1F, 0xB158, 0xCF21, 0xB159, 0xCF22, 0xB15A, 0xCF23, 0xB161, 0xCF25, 0xB162, 0xCF26, 0xB163, 0xCF27, 0xB164, 0xCF28, 0xB165, 0xCF29, 0xB166, 0xCF2A, 0xB167, 0xCF2B, 0xB168, 0xCF2E, 0xB169, 0xCF32, 0xB16A, 0xCF33, 0xB16B, 0xCF34, 0xB16C, 0xCF35, 0xB16D, 0xCF36, 0xB16E, 0xCF37, 0xB16F, 0xCF39, 0xB170, 0xCF3A, 0xB171, 0xCF3B, 0xB172, 0xCF3C, 0xB173, 0xCF3D, 0xB174, 0xCF3E, 0xB175, 0xCF3F, 0xB176, 0xCF40, 0xB177, 0xCF41, 0xB178, 0xCF42, 0xB179, 0xCF43, 0xB17A, 0xCF44, 0xB181, 0xCF45, 0xB182, 0xCF46, 0xB183, 0xCF47, 0xB184, 0xCF48, 0xB185, 0xCF49, 0xB186, 0xCF4A, 0xB187, 0xCF4B, 0xB188, 0xCF4C, 0xB189, 0xCF4D, 0xB18A, 0xCF4E, 0xB18B, 0xCF4F, 0xB18C, 0xCF50, 0xB18D, 0xCF51, 0xB18E, 0xCF52, 0xB18F, 0xCF53, 0xB190, 0xCF56, 0xB191, 0xCF57, 0xB192, 0xCF59, 0xB193, 0xCF5A, 0xB194, 0xCF5B, 0xB195, 0xCF5D, 0xB196, 0xCF5E, 0xB197, 0xCF5F, 0xB198, 0xCF60, 0xB199, 0xCF61, 0xB19A, 0xCF62, 0xB19B, 0xCF63, 0xB19C, 0xCF66, 0xB19D, 0xCF68, 0xB19E, 0xCF6A, 0xB19F, 0xCF6B, 0xB1A0, 0xCF6C, 0xB1A1, 0xAD0C, 0xB1A2, 0xAD0D, 0xB1A3, 0xAD0F, 0xB1A4, 0xAD11, 0xB1A5, 0xAD18, 0xB1A6, 0xAD1C, 0xB1A7, 0xAD20, 0xB1A8, 0xAD29, 0xB1A9, 0xAD2C, 0xB1AA, 0xAD2D, 0xB1AB, 0xAD34, 0xB1AC, 0xAD35, 0xB1AD, 0xAD38, 0xB1AE, 0xAD3C, 0xB1AF, 0xAD44, 0xB1B0, 0xAD45, 0xB1B1, 0xAD47, 0xB1B2, 0xAD49, 0xB1B3, 0xAD50, 0xB1B4, 0xAD54, 0xB1B5, 0xAD58, 0xB1B6, 0xAD61, 0xB1B7, 0xAD63, 0xB1B8, 0xAD6C, 0xB1B9, 0xAD6D, 0xB1BA, 0xAD70, 0xB1BB, 0xAD73, 0xB1BC, 0xAD74, 0xB1BD, 0xAD75, 0xB1BE, 0xAD76, 0xB1BF, 0xAD7B, 0xB1C0, 0xAD7C, 0xB1C1, 0xAD7D, 0xB1C2, 0xAD7F, 0xB1C3, 0xAD81, 0xB1C4, 0xAD82, 0xB1C5, 0xAD88, 0xB1C6, 0xAD89, 0xB1C7, 0xAD8C, 0xB1C8, 0xAD90, 0xB1C9, 0xAD9C, 0xB1CA, 0xAD9D, 0xB1CB, 0xADA4, 0xB1CC, 0xADB7, 0xB1CD, 0xADC0, 0xB1CE, 0xADC1, 0xB1CF, 0xADC4, 0xB1D0, 0xADC8, 0xB1D1, 0xADD0, 0xB1D2, 0xADD1, 0xB1D3, 0xADD3, 0xB1D4, 0xADDC, 0xB1D5, 0xADE0, 0xB1D6, 0xADE4, 0xB1D7, 0xADF8, 0xB1D8, 0xADF9, 0xB1D9, 0xADFC, 0xB1DA, 0xADFF, 0xB1DB, 0xAE00, 0xB1DC, 0xAE01, 0xB1DD, 0xAE08, 0xB1DE, 0xAE09, 0xB1DF, 0xAE0B, 0xB1E0, 0xAE0D, 0xB1E1, 0xAE14, 0xB1E2, 0xAE30, 0xB1E3, 0xAE31, 0xB1E4, 0xAE34, 0xB1E5, 0xAE37, 0xB1E6, 0xAE38, 0xB1E7, 0xAE3A, 0xB1E8, 0xAE40, 0xB1E9, 0xAE41, 0xB1EA, 0xAE43, 0xB1EB, 0xAE45, 0xB1EC, 0xAE46, 0xB1ED, 0xAE4A, 0xB1EE, 0xAE4C, 0xB1EF, 0xAE4D, 0xB1F0, 0xAE4E, 0xB1F1, 0xAE50, 0xB1F2, 0xAE54, 0xB1F3, 0xAE56, 0xB1F4, 0xAE5C, 0xB1F5, 0xAE5D, 0xB1F6, 0xAE5F, 0xB1F7, 0xAE60, 0xB1F8, 0xAE61, 0xB1F9, 0xAE65, 0xB1FA, 0xAE68, 0xB1FB, 0xAE69, 0xB1FC, 0xAE6C, 0xB1FD, 0xAE70, 0xB1FE, 0xAE78, 0xB241, 0xCF6D, 0xB242, 0xCF6E, 0xB243, 0xCF6F, 0xB244, 0xCF72, 0xB245, 0xCF73, 0xB246, 0xCF75, 0xB247, 0xCF76, 0xB248, 0xCF77, 0xB249, 0xCF79, 0xB24A, 0xCF7A, 0xB24B, 0xCF7B, 0xB24C, 0xCF7C, 0xB24D, 0xCF7D, 0xB24E, 0xCF7E, 0xB24F, 0xCF7F, 0xB250, 0xCF81, 0xB251, 0xCF82, 0xB252, 0xCF83, 0xB253, 0xCF84, 0xB254, 0xCF86, 0xB255, 0xCF87, 0xB256, 0xCF88, 0xB257, 0xCF89, 0xB258, 0xCF8A, 0xB259, 0xCF8B, 0xB25A, 0xCF8D, 0xB261, 0xCF8E, 0xB262, 0xCF8F, 0xB263, 0xCF90, 0xB264, 0xCF91, 0xB265, 0xCF92, 0xB266, 0xCF93, 0xB267, 0xCF94, 0xB268, 0xCF95, 0xB269, 0xCF96, 0xB26A, 0xCF97, 0xB26B, 0xCF98, 0xB26C, 0xCF99, 0xB26D, 0xCF9A, 0xB26E, 0xCF9B, 0xB26F, 0xCF9C, 0xB270, 0xCF9D, 0xB271, 0xCF9E, 0xB272, 0xCF9F, 0xB273, 0xCFA0, 0xB274, 0xCFA2, 0xB275, 0xCFA3, 0xB276, 0xCFA4, 0xB277, 0xCFA5, 0xB278, 0xCFA6, 0xB279, 0xCFA7, 0xB27A, 0xCFA9, 0xB281, 0xCFAA, 0xB282, 0xCFAB, 0xB283, 0xCFAC, 0xB284, 0xCFAD, 0xB285, 0xCFAE, 0xB286, 0xCFAF, 0xB287, 0xCFB1, 0xB288, 0xCFB2, 0xB289, 0xCFB3, 0xB28A, 0xCFB4, 0xB28B, 0xCFB5, 0xB28C, 0xCFB6, 0xB28D, 0xCFB7, 0xB28E, 0xCFB8, 0xB28F, 0xCFB9, 0xB290, 0xCFBA, 0xB291, 0xCFBB, 0xB292, 0xCFBC, 0xB293, 0xCFBD, 0xB294, 0xCFBE, 0xB295, 0xCFBF, 0xB296, 0xCFC0, 0xB297, 0xCFC1, 0xB298, 0xCFC2, 0xB299, 0xCFC3, 0xB29A, 0xCFC5, 0xB29B, 0xCFC6, 0xB29C, 0xCFC7, 0xB29D, 0xCFC8, 0xB29E, 0xCFC9, 0xB29F, 0xCFCA, 0xB2A0, 0xCFCB, 0xB2A1, 0xAE79, 0xB2A2, 0xAE7B, 0xB2A3, 0xAE7C, 0xB2A4, 0xAE7D, 0xB2A5, 0xAE84, 0xB2A6, 0xAE85, 0xB2A7, 0xAE8C, 0xB2A8, 0xAEBC, 0xB2A9, 0xAEBD, 0xB2AA, 0xAEBE, 0xB2AB, 0xAEC0, 0xB2AC, 0xAEC4, 0xB2AD, 0xAECC, 0xB2AE, 0xAECD, 0xB2AF, 0xAECF, 0xB2B0, 0xAED0, 0xB2B1, 0xAED1, 0xB2B2, 0xAED8, 0xB2B3, 0xAED9, 0xB2B4, 0xAEDC, 0xB2B5, 0xAEE8, 0xB2B6, 0xAEEB, 0xB2B7, 0xAEED, 0xB2B8, 0xAEF4, 0xB2B9, 0xAEF8, 0xB2BA, 0xAEFC, 0xB2BB, 0xAF07, 0xB2BC, 0xAF08, 0xB2BD, 0xAF0D, 0xB2BE, 0xAF10, 0xB2BF, 0xAF2C, 0xB2C0, 0xAF2D, 0xB2C1, 0xAF30, 0xB2C2, 0xAF32, 0xB2C3, 0xAF34, 0xB2C4, 0xAF3C, 0xB2C5, 0xAF3D, 0xB2C6, 0xAF3F, 0xB2C7, 0xAF41, 0xB2C8, 0xAF42, 0xB2C9, 0xAF43, 0xB2CA, 0xAF48, 0xB2CB, 0xAF49, 0xB2CC, 0xAF50, 0xB2CD, 0xAF5C, 0xB2CE, 0xAF5D, 0xB2CF, 0xAF64, 0xB2D0, 0xAF65, 0xB2D1, 0xAF79, 0xB2D2, 0xAF80, 0xB2D3, 0xAF84, 0xB2D4, 0xAF88, 0xB2D5, 0xAF90, 0xB2D6, 0xAF91, 0xB2D7, 0xAF95, 0xB2D8, 0xAF9C, 0xB2D9, 0xAFB8, 0xB2DA, 0xAFB9, 0xB2DB, 0xAFBC, 0xB2DC, 0xAFC0, 0xB2DD, 0xAFC7, 0xB2DE, 0xAFC8, 0xB2DF, 0xAFC9, 0xB2E0, 0xAFCB, 0xB2E1, 0xAFCD, 0xB2E2, 0xAFCE, 0xB2E3, 0xAFD4, 0xB2E4, 0xAFDC, 0xB2E5, 0xAFE8, 0xB2E6, 0xAFE9, 0xB2E7, 0xAFF0, 0xB2E8, 0xAFF1, 0xB2E9, 0xAFF4, 0xB2EA, 0xAFF8, 0xB2EB, 0xB000, 0xB2EC, 0xB001, 0xB2ED, 0xB004, 0xB2EE, 0xB00C, 0xB2EF, 0xB010, 0xB2F0, 0xB014, 0xB2F1, 0xB01C, 0xB2F2, 0xB01D, 0xB2F3, 0xB028, 0xB2F4, 0xB044, 0xB2F5, 0xB045, 0xB2F6, 0xB048, 0xB2F7, 0xB04A, 0xB2F8, 0xB04C, 0xB2F9, 0xB04E, 0xB2FA, 0xB053, 0xB2FB, 0xB054, 0xB2FC, 0xB055, 0xB2FD, 0xB057, 0xB2FE, 0xB059, 0xB341, 0xCFCC, 0xB342, 0xCFCD, 0xB343, 0xCFCE, 0xB344, 0xCFCF, 0xB345, 0xCFD0, 0xB346, 0xCFD1, 0xB347, 0xCFD2, 0xB348, 0xCFD3, 0xB349, 0xCFD4, 0xB34A, 0xCFD5, 0xB34B, 0xCFD6, 0xB34C, 0xCFD7, 0xB34D, 0xCFD8, 0xB34E, 0xCFD9, 0xB34F, 0xCFDA, 0xB350, 0xCFDB, 0xB351, 0xCFDC, 0xB352, 0xCFDD, 0xB353, 0xCFDE, 0xB354, 0xCFDF, 0xB355, 0xCFE2, 0xB356, 0xCFE3, 0xB357, 0xCFE5, 0xB358, 0xCFE6, 0xB359, 0xCFE7, 0xB35A, 0xCFE9, 0xB361, 0xCFEA, 0xB362, 0xCFEB, 0xB363, 0xCFEC, 0xB364, 0xCFED, 0xB365, 0xCFEE, 0xB366, 0xCFEF, 0xB367, 0xCFF2, 0xB368, 0xCFF4, 0xB369, 0xCFF6, 0xB36A, 0xCFF7, 0xB36B, 0xCFF8, 0xB36C, 0xCFF9, 0xB36D, 0xCFFA, 0xB36E, 0xCFFB, 0xB36F, 0xCFFD, 0xB370, 0xCFFE, 0xB371, 0xCFFF, 0xB372, 0xD001, 0xB373, 0xD002, 0xB374, 0xD003, 0xB375, 0xD005, 0xB376, 0xD006, 0xB377, 0xD007, 0xB378, 0xD008, 0xB379, 0xD009, 0xB37A, 0xD00A, 0xB381, 0xD00B, 0xB382, 0xD00C, 0xB383, 0xD00D, 0xB384, 0xD00E, 0xB385, 0xD00F, 0xB386, 0xD010, 0xB387, 0xD012, 0xB388, 0xD013, 0xB389, 0xD014, 0xB38A, 0xD015, 0xB38B, 0xD016, 0xB38C, 0xD017, 0xB38D, 0xD019, 0xB38E, 0xD01A, 0xB38F, 0xD01B, 0xB390, 0xD01C, 0xB391, 0xD01D, 0xB392, 0xD01E, 0xB393, 0xD01F, 0xB394, 0xD020, 0xB395, 0xD021, 0xB396, 0xD022, 0xB397, 0xD023, 0xB398, 0xD024, 0xB399, 0xD025, 0xB39A, 0xD026, 0xB39B, 0xD027, 0xB39C, 0xD028, 0xB39D, 0xD029, 0xB39E, 0xD02A, 0xB39F, 0xD02B, 0xB3A0, 0xD02C, 0xB3A1, 0xB05D, 0xB3A2, 0xB07C, 0xB3A3, 0xB07D, 0xB3A4, 0xB080, 0xB3A5, 0xB084, 0xB3A6, 0xB08C, 0xB3A7, 0xB08D, 0xB3A8, 0xB08F, 0xB3A9, 0xB091, 0xB3AA, 0xB098, 0xB3AB, 0xB099, 0xB3AC, 0xB09A, 0xB3AD, 0xB09C, 0xB3AE, 0xB09F, 0xB3AF, 0xB0A0, 0xB3B0, 0xB0A1, 0xB3B1, 0xB0A2, 0xB3B2, 0xB0A8, 0xB3B3, 0xB0A9, 0xB3B4, 0xB0AB, 0xB3B5, 0xB0AC, 0xB3B6, 0xB0AD, 0xB3B7, 0xB0AE, 0xB3B8, 0xB0AF, 0xB3B9, 0xB0B1, 0xB3BA, 0xB0B3, 0xB3BB, 0xB0B4, 0xB3BC, 0xB0B5, 0xB3BD, 0xB0B8, 0xB3BE, 0xB0BC, 0xB3BF, 0xB0C4, 0xB3C0, 0xB0C5, 0xB3C1, 0xB0C7, 0xB3C2, 0xB0C8, 0xB3C3, 0xB0C9, 0xB3C4, 0xB0D0, 0xB3C5, 0xB0D1, 0xB3C6, 0xB0D4, 0xB3C7, 0xB0D8, 0xB3C8, 0xB0E0, 0xB3C9, 0xB0E5, 0xB3CA, 0xB108, 0xB3CB, 0xB109, 0xB3CC, 0xB10B, 0xB3CD, 0xB10C, 0xB3CE, 0xB110, 0xB3CF, 0xB112, 0xB3D0, 0xB113, 0xB3D1, 0xB118, 0xB3D2, 0xB119, 0xB3D3, 0xB11B, 0xB3D4, 0xB11C, 0xB3D5, 0xB11D, 0xB3D6, 0xB123, 0xB3D7, 0xB124, 0xB3D8, 0xB125, 0xB3D9, 0xB128, 0xB3DA, 0xB12C, 0xB3DB, 0xB134, 0xB3DC, 0xB135, 0xB3DD, 0xB137, 0xB3DE, 0xB138, 0xB3DF, 0xB139, 0xB3E0, 0xB140, 0xB3E1, 0xB141, 0xB3E2, 0xB144, 0xB3E3, 0xB148, 0xB3E4, 0xB150, 0xB3E5, 0xB151, 0xB3E6, 0xB154, 0xB3E7, 0xB155, 0xB3E8, 0xB158, 0xB3E9, 0xB15C, 0xB3EA, 0xB160, 0xB3EB, 0xB178, 0xB3EC, 0xB179, 0xB3ED, 0xB17C, 0xB3EE, 0xB180, 0xB3EF, 0xB182, 0xB3F0, 0xB188, 0xB3F1, 0xB189, 0xB3F2, 0xB18B, 0xB3F3, 0xB18D, 0xB3F4, 0xB192, 0xB3F5, 0xB193, 0xB3F6, 0xB194, 0xB3F7, 0xB198, 0xB3F8, 0xB19C, 0xB3F9, 0xB1A8, 0xB3FA, 0xB1CC, 0xB3FB, 0xB1D0, 0xB3FC, 0xB1D4, 0xB3FD, 0xB1DC, 0xB3FE, 0xB1DD, 0xB441, 0xD02E, 0xB442, 0xD02F, 0xB443, 0xD030, 0xB444, 0xD031, 0xB445, 0xD032, 0xB446, 0xD033, 0xB447, 0xD036, 0xB448, 0xD037, 0xB449, 0xD039, 0xB44A, 0xD03A, 0xB44B, 0xD03B, 0xB44C, 0xD03D, 0xB44D, 0xD03E, 0xB44E, 0xD03F, 0xB44F, 0xD040, 0xB450, 0xD041, 0xB451, 0xD042, 0xB452, 0xD043, 0xB453, 0xD046, 0xB454, 0xD048, 0xB455, 0xD04A, 0xB456, 0xD04B, 0xB457, 0xD04C, 0xB458, 0xD04D, 0xB459, 0xD04E, 0xB45A, 0xD04F, 0xB461, 0xD051, 0xB462, 0xD052, 0xB463, 0xD053, 0xB464, 0xD055, 0xB465, 0xD056, 0xB466, 0xD057, 0xB467, 0xD059, 0xB468, 0xD05A, 0xB469, 0xD05B, 0xB46A, 0xD05C, 0xB46B, 0xD05D, 0xB46C, 0xD05E, 0xB46D, 0xD05F, 0xB46E, 0xD061, 0xB46F, 0xD062, 0xB470, 0xD063, 0xB471, 0xD064, 0xB472, 0xD065, 0xB473, 0xD066, 0xB474, 0xD067, 0xB475, 0xD068, 0xB476, 0xD069, 0xB477, 0xD06A, 0xB478, 0xD06B, 0xB479, 0xD06E, 0xB47A, 0xD06F, 0xB481, 0xD071, 0xB482, 0xD072, 0xB483, 0xD073, 0xB484, 0xD075, 0xB485, 0xD076, 0xB486, 0xD077, 0xB487, 0xD078, 0xB488, 0xD079, 0xB489, 0xD07A, 0xB48A, 0xD07B, 0xB48B, 0xD07E, 0xB48C, 0xD07F, 0xB48D, 0xD080, 0xB48E, 0xD082, 0xB48F, 0xD083, 0xB490, 0xD084, 0xB491, 0xD085, 0xB492, 0xD086, 0xB493, 0xD087, 0xB494, 0xD088, 0xB495, 0xD089, 0xB496, 0xD08A, 0xB497, 0xD08B, 0xB498, 0xD08C, 0xB499, 0xD08D, 0xB49A, 0xD08E, 0xB49B, 0xD08F, 0xB49C, 0xD090, 0xB49D, 0xD091, 0xB49E, 0xD092, 0xB49F, 0xD093, 0xB4A0, 0xD094, 0xB4A1, 0xB1DF, 0xB4A2, 0xB1E8, 0xB4A3, 0xB1E9, 0xB4A4, 0xB1EC, 0xB4A5, 0xB1F0, 0xB4A6, 0xB1F9, 0xB4A7, 0xB1FB, 0xB4A8, 0xB1FD, 0xB4A9, 0xB204, 0xB4AA, 0xB205, 0xB4AB, 0xB208, 0xB4AC, 0xB20B, 0xB4AD, 0xB20C, 0xB4AE, 0xB214, 0xB4AF, 0xB215, 0xB4B0, 0xB217, 0xB4B1, 0xB219, 0xB4B2, 0xB220, 0xB4B3, 0xB234, 0xB4B4, 0xB23C, 0xB4B5, 0xB258, 0xB4B6, 0xB25C, 0xB4B7, 0xB260, 0xB4B8, 0xB268, 0xB4B9, 0xB269, 0xB4BA, 0xB274, 0xB4BB, 0xB275, 0xB4BC, 0xB27C, 0xB4BD, 0xB284, 0xB4BE, 0xB285, 0xB4BF, 0xB289, 0xB4C0, 0xB290, 0xB4C1, 0xB291, 0xB4C2, 0xB294, 0xB4C3, 0xB298, 0xB4C4, 0xB299, 0xB4C5, 0xB29A, 0xB4C6, 0xB2A0, 0xB4C7, 0xB2A1, 0xB4C8, 0xB2A3, 0xB4C9, 0xB2A5, 0xB4CA, 0xB2A6, 0xB4CB, 0xB2AA, 0xB4CC, 0xB2AC, 0xB4CD, 0xB2B0, 0xB4CE, 0xB2B4, 0xB4CF, 0xB2C8, 0xB4D0, 0xB2C9, 0xB4D1, 0xB2CC, 0xB4D2, 0xB2D0, 0xB4D3, 0xB2D2, 0xB4D4, 0xB2D8, 0xB4D5, 0xB2D9, 0xB4D6, 0xB2DB, 0xB4D7, 0xB2DD, 0xB4D8, 0xB2E2, 0xB4D9, 0xB2E4, 0xB4DA, 0xB2E5, 0xB4DB, 0xB2E6, 0xB4DC, 0xB2E8, 0xB4DD, 0xB2EB, 0xB4DE, 0xB2EC, 0xB4DF, 0xB2ED, 0xB4E0, 0xB2EE, 0xB4E1, 0xB2EF, 0xB4E2, 0xB2F3, 0xB4E3, 0xB2F4, 0xB4E4, 0xB2F5, 0xB4E5, 0xB2F7, 0xB4E6, 0xB2F8, 0xB4E7, 0xB2F9, 0xB4E8, 0xB2FA, 0xB4E9, 0xB2FB, 0xB4EA, 0xB2FF, 0xB4EB, 0xB300, 0xB4EC, 0xB301, 0xB4ED, 0xB304, 0xB4EE, 0xB308, 0xB4EF, 0xB310, 0xB4F0, 0xB311, 0xB4F1, 0xB313, 0xB4F2, 0xB314, 0xB4F3, 0xB315, 0xB4F4, 0xB31C, 0xB4F5, 0xB354, 0xB4F6, 0xB355, 0xB4F7, 0xB356, 0xB4F8, 0xB358, 0xB4F9, 0xB35B, 0xB4FA, 0xB35C, 0xB4FB, 0xB35E, 0xB4FC, 0xB35F, 0xB4FD, 0xB364, 0xB4FE, 0xB365, 0xB541, 0xD095, 0xB542, 0xD096, 0xB543, 0xD097, 0xB544, 0xD098, 0xB545, 0xD099, 0xB546, 0xD09A, 0xB547, 0xD09B, 0xB548, 0xD09C, 0xB549, 0xD09D, 0xB54A, 0xD09E, 0xB54B, 0xD09F, 0xB54C, 0xD0A0, 0xB54D, 0xD0A1, 0xB54E, 0xD0A2, 0xB54F, 0xD0A3, 0xB550, 0xD0A6, 0xB551, 0xD0A7, 0xB552, 0xD0A9, 0xB553, 0xD0AA, 0xB554, 0xD0AB, 0xB555, 0xD0AD, 0xB556, 0xD0AE, 0xB557, 0xD0AF, 0xB558, 0xD0B0, 0xB559, 0xD0B1, 0xB55A, 0xD0B2, 0xB561, 0xD0B3, 0xB562, 0xD0B6, 0xB563, 0xD0B8, 0xB564, 0xD0BA, 0xB565, 0xD0BB, 0xB566, 0xD0BC, 0xB567, 0xD0BD, 0xB568, 0xD0BE, 0xB569, 0xD0BF, 0xB56A, 0xD0C2, 0xB56B, 0xD0C3, 0xB56C, 0xD0C5, 0xB56D, 0xD0C6, 0xB56E, 0xD0C7, 0xB56F, 0xD0CA, 0xB570, 0xD0CB, 0xB571, 0xD0CC, 0xB572, 0xD0CD, 0xB573, 0xD0CE, 0xB574, 0xD0CF, 0xB575, 0xD0D2, 0xB576, 0xD0D6, 0xB577, 0xD0D7, 0xB578, 0xD0D8, 0xB579, 0xD0D9, 0xB57A, 0xD0DA, 0xB581, 0xD0DB, 0xB582, 0xD0DE, 0xB583, 0xD0DF, 0xB584, 0xD0E1, 0xB585, 0xD0E2, 0xB586, 0xD0E3, 0xB587, 0xD0E5, 0xB588, 0xD0E6, 0xB589, 0xD0E7, 0xB58A, 0xD0E8, 0xB58B, 0xD0E9, 0xB58C, 0xD0EA, 0xB58D, 0xD0EB, 0xB58E, 0xD0EE, 0xB58F, 0xD0F2, 0xB590, 0xD0F3, 0xB591, 0xD0F4, 0xB592, 0xD0F5, 0xB593, 0xD0F6, 0xB594, 0xD0F7, 0xB595, 0xD0F9, 0xB596, 0xD0FA, 0xB597, 0xD0FB, 0xB598, 0xD0FC, 0xB599, 0xD0FD, 0xB59A, 0xD0FE, 0xB59B, 0xD0FF, 0xB59C, 0xD100, 0xB59D, 0xD101, 0xB59E, 0xD102, 0xB59F, 0xD103, 0xB5A0, 0xD104, 0xB5A1, 0xB367, 0xB5A2, 0xB369, 0xB5A3, 0xB36B, 0xB5A4, 0xB36E, 0xB5A5, 0xB370, 0xB5A6, 0xB371, 0xB5A7, 0xB374, 0xB5A8, 0xB378, 0xB5A9, 0xB380, 0xB5AA, 0xB381, 0xB5AB, 0xB383, 0xB5AC, 0xB384, 0xB5AD, 0xB385, 0xB5AE, 0xB38C, 0xB5AF, 0xB390, 0xB5B0, 0xB394, 0xB5B1, 0xB3A0, 0xB5B2, 0xB3A1, 0xB5B3, 0xB3A8, 0xB5B4, 0xB3AC, 0xB5B5, 0xB3C4, 0xB5B6, 0xB3C5, 0xB5B7, 0xB3C8, 0xB5B8, 0xB3CB, 0xB5B9, 0xB3CC, 0xB5BA, 0xB3CE, 0xB5BB, 0xB3D0, 0xB5BC, 0xB3D4, 0xB5BD, 0xB3D5, 0xB5BE, 0xB3D7, 0xB5BF, 0xB3D9, 0xB5C0, 0xB3DB, 0xB5C1, 0xB3DD, 0xB5C2, 0xB3E0, 0xB5C3, 0xB3E4, 0xB5C4, 0xB3E8, 0xB5C5, 0xB3FC, 0xB5C6, 0xB410, 0xB5C7, 0xB418, 0xB5C8, 0xB41C, 0xB5C9, 0xB420, 0xB5CA, 0xB428, 0xB5CB, 0xB429, 0xB5CC, 0xB42B, 0xB5CD, 0xB434, 0xB5CE, 0xB450, 0xB5CF, 0xB451, 0xB5D0, 0xB454, 0xB5D1, 0xB458, 0xB5D2, 0xB460, 0xB5D3, 0xB461, 0xB5D4, 0xB463, 0xB5D5, 0xB465, 0xB5D6, 0xB46C, 0xB5D7, 0xB480, 0xB5D8, 0xB488, 0xB5D9, 0xB49D, 0xB5DA, 0xB4A4, 0xB5DB, 0xB4A8, 0xB5DC, 0xB4AC, 0xB5DD, 0xB4B5, 0xB5DE, 0xB4B7, 0xB5DF, 0xB4B9, 0xB5E0, 0xB4C0, 0xB5E1, 0xB4C4, 0xB5E2, 0xB4C8, 0xB5E3, 0xB4D0, 0xB5E4, 0xB4D5, 0xB5E5, 0xB4DC, 0xB5E6, 0xB4DD, 0xB5E7, 0xB4E0, 0xB5E8, 0xB4E3, 0xB5E9, 0xB4E4, 0xB5EA, 0xB4E6, 0xB5EB, 0xB4EC, 0xB5EC, 0xB4ED, 0xB5ED, 0xB4EF, 0xB5EE, 0xB4F1, 0xB5EF, 0xB4F8, 0xB5F0, 0xB514, 0xB5F1, 0xB515, 0xB5F2, 0xB518, 0xB5F3, 0xB51B, 0xB5F4, 0xB51C, 0xB5F5, 0xB524, 0xB5F6, 0xB525, 0xB5F7, 0xB527, 0xB5F8, 0xB528, 0xB5F9, 0xB529, 0xB5FA, 0xB52A, 0xB5FB, 0xB530, 0xB5FC, 0xB531, 0xB5FD, 0xB534, 0xB5FE, 0xB538, 0xB641, 0xD105, 0xB642, 0xD106, 0xB643, 0xD107, 0xB644, 0xD108, 0xB645, 0xD109, 0xB646, 0xD10A, 0xB647, 0xD10B, 0xB648, 0xD10C, 0xB649, 0xD10E, 0xB64A, 0xD10F, 0xB64B, 0xD110, 0xB64C, 0xD111, 0xB64D, 0xD112, 0xB64E, 0xD113, 0xB64F, 0xD114, 0xB650, 0xD115, 0xB651, 0xD116, 0xB652, 0xD117, 0xB653, 0xD118, 0xB654, 0xD119, 0xB655, 0xD11A, 0xB656, 0xD11B, 0xB657, 0xD11C, 0xB658, 0xD11D, 0xB659, 0xD11E, 0xB65A, 0xD11F, 0xB661, 0xD120, 0xB662, 0xD121, 0xB663, 0xD122, 0xB664, 0xD123, 0xB665, 0xD124, 0xB666, 0xD125, 0xB667, 0xD126, 0xB668, 0xD127, 0xB669, 0xD128, 0xB66A, 0xD129, 0xB66B, 0xD12A, 0xB66C, 0xD12B, 0xB66D, 0xD12C, 0xB66E, 0xD12D, 0xB66F, 0xD12E, 0xB670, 0xD12F, 0xB671, 0xD132, 0xB672, 0xD133, 0xB673, 0xD135, 0xB674, 0xD136, 0xB675, 0xD137, 0xB676, 0xD139, 0xB677, 0xD13B, 0xB678, 0xD13C, 0xB679, 0xD13D, 0xB67A, 0xD13E, 0xB681, 0xD13F, 0xB682, 0xD142, 0xB683, 0xD146, 0xB684, 0xD147, 0xB685, 0xD148, 0xB686, 0xD149, 0xB687, 0xD14A, 0xB688, 0xD14B, 0xB689, 0xD14E, 0xB68A, 0xD14F, 0xB68B, 0xD151, 0xB68C, 0xD152, 0xB68D, 0xD153, 0xB68E, 0xD155, 0xB68F, 0xD156, 0xB690, 0xD157, 0xB691, 0xD158, 0xB692, 0xD159, 0xB693, 0xD15A, 0xB694, 0xD15B, 0xB695, 0xD15E, 0xB696, 0xD160, 0xB697, 0xD162, 0xB698, 0xD163, 0xB699, 0xD164, 0xB69A, 0xD165, 0xB69B, 0xD166, 0xB69C, 0xD167, 0xB69D, 0xD169, 0xB69E, 0xD16A, 0xB69F, 0xD16B, 0xB6A0, 0xD16D, 0xB6A1, 0xB540, 0xB6A2, 0xB541, 0xB6A3, 0xB543, 0xB6A4, 0xB544, 0xB6A5, 0xB545, 0xB6A6, 0xB54B, 0xB6A7, 0xB54C, 0xB6A8, 0xB54D, 0xB6A9, 0xB550, 0xB6AA, 0xB554, 0xB6AB, 0xB55C, 0xB6AC, 0xB55D, 0xB6AD, 0xB55F, 0xB6AE, 0xB560, 0xB6AF, 0xB561, 0xB6B0, 0xB5A0, 0xB6B1, 0xB5A1, 0xB6B2, 0xB5A4, 0xB6B3, 0xB5A8, 0xB6B4, 0xB5AA, 0xB6B5, 0xB5AB, 0xB6B6, 0xB5B0, 0xB6B7, 0xB5B1, 0xB6B8, 0xB5B3, 0xB6B9, 0xB5B4, 0xB6BA, 0xB5B5, 0xB6BB, 0xB5BB, 0xB6BC, 0xB5BC, 0xB6BD, 0xB5BD, 0xB6BE, 0xB5C0, 0xB6BF, 0xB5C4, 0xB6C0, 0xB5CC, 0xB6C1, 0xB5CD, 0xB6C2, 0xB5CF, 0xB6C3, 0xB5D0, 0xB6C4, 0xB5D1, 0xB6C5, 0xB5D8, 0xB6C6, 0xB5EC, 0xB6C7, 0xB610, 0xB6C8, 0xB611, 0xB6C9, 0xB614, 0xB6CA, 0xB618, 0xB6CB, 0xB625, 0xB6CC, 0xB62C, 0xB6CD, 0xB634, 0xB6CE, 0xB648, 0xB6CF, 0xB664, 0xB6D0, 0xB668, 0xB6D1, 0xB69C, 0xB6D2, 0xB69D, 0xB6D3, 0xB6A0, 0xB6D4, 0xB6A4, 0xB6D5, 0xB6AB, 0xB6D6, 0xB6AC, 0xB6D7, 0xB6B1, 0xB6D8, 0xB6D4, 0xB6D9, 0xB6F0, 0xB6DA, 0xB6F4, 0xB6DB, 0xB6F8, 0xB6DC, 0xB700, 0xB6DD, 0xB701, 0xB6DE, 0xB705, 0xB6DF, 0xB728, 0xB6E0, 0xB729, 0xB6E1, 0xB72C, 0xB6E2, 0xB72F, 0xB6E3, 0xB730, 0xB6E4, 0xB738, 0xB6E5, 0xB739, 0xB6E6, 0xB73B, 0xB6E7, 0xB744, 0xB6E8, 0xB748, 0xB6E9, 0xB74C, 0xB6EA, 0xB754, 0xB6EB, 0xB755, 0xB6EC, 0xB760, 0xB6ED, 0xB764, 0xB6EE, 0xB768, 0xB6EF, 0xB770, 0xB6F0, 0xB771, 0xB6F1, 0xB773, 0xB6F2, 0xB775, 0xB6F3, 0xB77C, 0xB6F4, 0xB77D, 0xB6F5, 0xB780, 0xB6F6, 0xB784, 0xB6F7, 0xB78C, 0xB6F8, 0xB78D, 0xB6F9, 0xB78F, 0xB6FA, 0xB790, 0xB6FB, 0xB791, 0xB6FC, 0xB792, 0xB6FD, 0xB796, 0xB6FE, 0xB797, 0xB741, 0xD16E, 0xB742, 0xD16F, 0xB743, 0xD170, 0xB744, 0xD171, 0xB745, 0xD172, 0xB746, 0xD173, 0xB747, 0xD174, 0xB748, 0xD175, 0xB749, 0xD176, 0xB74A, 0xD177, 0xB74B, 0xD178, 0xB74C, 0xD179, 0xB74D, 0xD17A, 0xB74E, 0xD17B, 0xB74F, 0xD17D, 0xB750, 0xD17E, 0xB751, 0xD17F, 0xB752, 0xD180, 0xB753, 0xD181, 0xB754, 0xD182, 0xB755, 0xD183, 0xB756, 0xD185, 0xB757, 0xD186, 0xB758, 0xD187, 0xB759, 0xD189, 0xB75A, 0xD18A, 0xB761, 0xD18B, 0xB762, 0xD18C, 0xB763, 0xD18D, 0xB764, 0xD18E, 0xB765, 0xD18F, 0xB766, 0xD190, 0xB767, 0xD191, 0xB768, 0xD192, 0xB769, 0xD193, 0xB76A, 0xD194, 0xB76B, 0xD195, 0xB76C, 0xD196, 0xB76D, 0xD197, 0xB76E, 0xD198, 0xB76F, 0xD199, 0xB770, 0xD19A, 0xB771, 0xD19B, 0xB772, 0xD19C, 0xB773, 0xD19D, 0xB774, 0xD19E, 0xB775, 0xD19F, 0xB776, 0xD1A2, 0xB777, 0xD1A3, 0xB778, 0xD1A5, 0xB779, 0xD1A6, 0xB77A, 0xD1A7, 0xB781, 0xD1A9, 0xB782, 0xD1AA, 0xB783, 0xD1AB, 0xB784, 0xD1AC, 0xB785, 0xD1AD, 0xB786, 0xD1AE, 0xB787, 0xD1AF, 0xB788, 0xD1B2, 0xB789, 0xD1B4, 0xB78A, 0xD1B6, 0xB78B, 0xD1B7, 0xB78C, 0xD1B8, 0xB78D, 0xD1B9, 0xB78E, 0xD1BB, 0xB78F, 0xD1BD, 0xB790, 0xD1BE, 0xB791, 0xD1BF, 0xB792, 0xD1C1, 0xB793, 0xD1C2, 0xB794, 0xD1C3, 0xB795, 0xD1C4, 0xB796, 0xD1C5, 0xB797, 0xD1C6, 0xB798, 0xD1C7, 0xB799, 0xD1C8, 0xB79A, 0xD1C9, 0xB79B, 0xD1CA, 0xB79C, 0xD1CB, 0xB79D, 0xD1CC, 0xB79E, 0xD1CD, 0xB79F, 0xD1CE, 0xB7A0, 0xD1CF, 0xB7A1, 0xB798, 0xB7A2, 0xB799, 0xB7A3, 0xB79C, 0xB7A4, 0xB7A0, 0xB7A5, 0xB7A8, 0xB7A6, 0xB7A9, 0xB7A7, 0xB7AB, 0xB7A8, 0xB7AC, 0xB7A9, 0xB7AD, 0xB7AA, 0xB7B4, 0xB7AB, 0xB7B5, 0xB7AC, 0xB7B8, 0xB7AD, 0xB7C7, 0xB7AE, 0xB7C9, 0xB7AF, 0xB7EC, 0xB7B0, 0xB7ED, 0xB7B1, 0xB7F0, 0xB7B2, 0xB7F4, 0xB7B3, 0xB7FC, 0xB7B4, 0xB7FD, 0xB7B5, 0xB7FF, 0xB7B6, 0xB800, 0xB7B7, 0xB801, 0xB7B8, 0xB807, 0xB7B9, 0xB808, 0xB7BA, 0xB809, 0xB7BB, 0xB80C, 0xB7BC, 0xB810, 0xB7BD, 0xB818, 0xB7BE, 0xB819, 0xB7BF, 0xB81B, 0xB7C0, 0xB81D, 0xB7C1, 0xB824, 0xB7C2, 0xB825, 0xB7C3, 0xB828, 0xB7C4, 0xB82C, 0xB7C5, 0xB834, 0xB7C6, 0xB835, 0xB7C7, 0xB837, 0xB7C8, 0xB838, 0xB7C9, 0xB839, 0xB7CA, 0xB840, 0xB7CB, 0xB844, 0xB7CC, 0xB851, 0xB7CD, 0xB853, 0xB7CE, 0xB85C, 0xB7CF, 0xB85D, 0xB7D0, 0xB860, 0xB7D1, 0xB864, 0xB7D2, 0xB86C, 0xB7D3, 0xB86D, 0xB7D4, 0xB86F, 0xB7D5, 0xB871, 0xB7D6, 0xB878, 0xB7D7, 0xB87C, 0xB7D8, 0xB88D, 0xB7D9, 0xB8A8, 0xB7DA, 0xB8B0, 0xB7DB, 0xB8B4, 0xB7DC, 0xB8B8, 0xB7DD, 0xB8C0, 0xB7DE, 0xB8C1, 0xB7DF, 0xB8C3, 0xB7E0, 0xB8C5, 0xB7E1, 0xB8CC, 0xB7E2, 0xB8D0, 0xB7E3, 0xB8D4, 0xB7E4, 0xB8DD, 0xB7E5, 0xB8DF, 0xB7E6, 0xB8E1, 0xB7E7, 0xB8E8, 0xB7E8, 0xB8E9, 0xB7E9, 0xB8EC, 0xB7EA, 0xB8F0, 0xB7EB, 0xB8F8, 0xB7EC, 0xB8F9, 0xB7ED, 0xB8FB, 0xB7EE, 0xB8FD, 0xB7EF, 0xB904, 0xB7F0, 0xB918, 0xB7F1, 0xB920, 0xB7F2, 0xB93C, 0xB7F3, 0xB93D, 0xB7F4, 0xB940, 0xB7F5, 0xB944, 0xB7F6, 0xB94C, 0xB7F7, 0xB94F, 0xB7F8, 0xB951, 0xB7F9, 0xB958, 0xB7FA, 0xB959, 0xB7FB, 0xB95C, 0xB7FC, 0xB960, 0xB7FD, 0xB968, 0xB7FE, 0xB969, 0xB841, 0xD1D0, 0xB842, 0xD1D1, 0xB843, 0xD1D2, 0xB844, 0xD1D3, 0xB845, 0xD1D4, 0xB846, 0xD1D5, 0xB847, 0xD1D6, 0xB848, 0xD1D7, 0xB849, 0xD1D9, 0xB84A, 0xD1DA, 0xB84B, 0xD1DB, 0xB84C, 0xD1DC, 0xB84D, 0xD1DD, 0xB84E, 0xD1DE, 0xB84F, 0xD1DF, 0xB850, 0xD1E0, 0xB851, 0xD1E1, 0xB852, 0xD1E2, 0xB853, 0xD1E3, 0xB854, 0xD1E4, 0xB855, 0xD1E5, 0xB856, 0xD1E6, 0xB857, 0xD1E7, 0xB858, 0xD1E8, 0xB859, 0xD1E9, 0xB85A, 0xD1EA, 0xB861, 0xD1EB, 0xB862, 0xD1EC, 0xB863, 0xD1ED, 0xB864, 0xD1EE, 0xB865, 0xD1EF, 0xB866, 0xD1F0, 0xB867, 0xD1F1, 0xB868, 0xD1F2, 0xB869, 0xD1F3, 0xB86A, 0xD1F5, 0xB86B, 0xD1F6, 0xB86C, 0xD1F7, 0xB86D, 0xD1F9, 0xB86E, 0xD1FA, 0xB86F, 0xD1FB, 0xB870, 0xD1FC, 0xB871, 0xD1FD, 0xB872, 0xD1FE, 0xB873, 0xD1FF, 0xB874, 0xD200, 0xB875, 0xD201, 0xB876, 0xD202, 0xB877, 0xD203, 0xB878, 0xD204, 0xB879, 0xD205, 0xB87A, 0xD206, 0xB881, 0xD208, 0xB882, 0xD20A, 0xB883, 0xD20B, 0xB884, 0xD20C, 0xB885, 0xD20D, 0xB886, 0xD20E, 0xB887, 0xD20F, 0xB888, 0xD211, 0xB889, 0xD212, 0xB88A, 0xD213, 0xB88B, 0xD214, 0xB88C, 0xD215, 0xB88D, 0xD216, 0xB88E, 0xD217, 0xB88F, 0xD218, 0xB890, 0xD219, 0xB891, 0xD21A, 0xB892, 0xD21B, 0xB893, 0xD21C, 0xB894, 0xD21D, 0xB895, 0xD21E, 0xB896, 0xD21F, 0xB897, 0xD220, 0xB898, 0xD221, 0xB899, 0xD222, 0xB89A, 0xD223, 0xB89B, 0xD224, 0xB89C, 0xD225, 0xB89D, 0xD226, 0xB89E, 0xD227, 0xB89F, 0xD228, 0xB8A0, 0xD229, 0xB8A1, 0xB96B, 0xB8A2, 0xB96D, 0xB8A3, 0xB974, 0xB8A4, 0xB975, 0xB8A5, 0xB978, 0xB8A6, 0xB97C, 0xB8A7, 0xB984, 0xB8A8, 0xB985, 0xB8A9, 0xB987, 0xB8AA, 0xB989, 0xB8AB, 0xB98A, 0xB8AC, 0xB98D, 0xB8AD, 0xB98E, 0xB8AE, 0xB9AC, 0xB8AF, 0xB9AD, 0xB8B0, 0xB9B0, 0xB8B1, 0xB9B4, 0xB8B2, 0xB9BC, 0xB8B3, 0xB9BD, 0xB8B4, 0xB9BF, 0xB8B5, 0xB9C1, 0xB8B6, 0xB9C8, 0xB8B7, 0xB9C9, 0xB8B8, 0xB9CC, 0xB8B9, 0xB9CE, 0xB8BA, 0xB9CF, 0xB8BB, 0xB9D0, 0xB8BC, 0xB9D1, 0xB8BD, 0xB9D2, 0xB8BE, 0xB9D8, 0xB8BF, 0xB9D9, 0xB8C0, 0xB9DB, 0xB8C1, 0xB9DD, 0xB8C2, 0xB9DE, 0xB8C3, 0xB9E1, 0xB8C4, 0xB9E3, 0xB8C5, 0xB9E4, 0xB8C6, 0xB9E5, 0xB8C7, 0xB9E8, 0xB8C8, 0xB9EC, 0xB8C9, 0xB9F4, 0xB8CA, 0xB9F5, 0xB8CB, 0xB9F7, 0xB8CC, 0xB9F8, 0xB8CD, 0xB9F9, 0xB8CE, 0xB9FA, 0xB8CF, 0xBA00, 0xB8D0, 0xBA01, 0xB8D1, 0xBA08, 0xB8D2, 0xBA15, 0xB8D3, 0xBA38, 0xB8D4, 0xBA39, 0xB8D5, 0xBA3C, 0xB8D6, 0xBA40, 0xB8D7, 0xBA42, 0xB8D8, 0xBA48, 0xB8D9, 0xBA49, 0xB8DA, 0xBA4B, 0xB8DB, 0xBA4D, 0xB8DC, 0xBA4E, 0xB8DD, 0xBA53, 0xB8DE, 0xBA54, 0xB8DF, 0xBA55, 0xB8E0, 0xBA58, 0xB8E1, 0xBA5C, 0xB8E2, 0xBA64, 0xB8E3, 0xBA65, 0xB8E4, 0xBA67, 0xB8E5, 0xBA68, 0xB8E6, 0xBA69, 0xB8E7, 0xBA70, 0xB8E8, 0xBA71, 0xB8E9, 0xBA74, 0xB8EA, 0xBA78, 0xB8EB, 0xBA83, 0xB8EC, 0xBA84, 0xB8ED, 0xBA85, 0xB8EE, 0xBA87, 0xB8EF, 0xBA8C, 0xB8F0, 0xBAA8, 0xB8F1, 0xBAA9, 0xB8F2, 0xBAAB, 0xB8F3, 0xBAAC, 0xB8F4, 0xBAB0, 0xB8F5, 0xBAB2, 0xB8F6, 0xBAB8, 0xB8F7, 0xBAB9, 0xB8F8, 0xBABB, 0xB8F9, 0xBABD, 0xB8FA, 0xBAC4, 0xB8FB, 0xBAC8, 0xB8FC, 0xBAD8, 0xB8FD, 0xBAD9, 0xB8FE, 0xBAFC, 0xB941, 0xD22A, 0xB942, 0xD22B, 0xB943, 0xD22E, 0xB944, 0xD22F, 0xB945, 0xD231, 0xB946, 0xD232, 0xB947, 0xD233, 0xB948, 0xD235, 0xB949, 0xD236, 0xB94A, 0xD237, 0xB94B, 0xD238, 0xB94C, 0xD239, 0xB94D, 0xD23A, 0xB94E, 0xD23B, 0xB94F, 0xD23E, 0xB950, 0xD240, 0xB951, 0xD242, 0xB952, 0xD243, 0xB953, 0xD244, 0xB954, 0xD245, 0xB955, 0xD246, 0xB956, 0xD247, 0xB957, 0xD249, 0xB958, 0xD24A, 0xB959, 0xD24B, 0xB95A, 0xD24C, 0xB961, 0xD24D, 0xB962, 0xD24E, 0xB963, 0xD24F, 0xB964, 0xD250, 0xB965, 0xD251, 0xB966, 0xD252, 0xB967, 0xD253, 0xB968, 0xD254, 0xB969, 0xD255, 0xB96A, 0xD256, 0xB96B, 0xD257, 0xB96C, 0xD258, 0xB96D, 0xD259, 0xB96E, 0xD25A, 0xB96F, 0xD25B, 0xB970, 0xD25D, 0xB971, 0xD25E, 0xB972, 0xD25F, 0xB973, 0xD260, 0xB974, 0xD261, 0xB975, 0xD262, 0xB976, 0xD263, 0xB977, 0xD265, 0xB978, 0xD266, 0xB979, 0xD267, 0xB97A, 0xD268, 0xB981, 0xD269, 0xB982, 0xD26A, 0xB983, 0xD26B, 0xB984, 0xD26C, 0xB985, 0xD26D, 0xB986, 0xD26E, 0xB987, 0xD26F, 0xB988, 0xD270, 0xB989, 0xD271, 0xB98A, 0xD272, 0xB98B, 0xD273, 0xB98C, 0xD274, 0xB98D, 0xD275, 0xB98E, 0xD276, 0xB98F, 0xD277, 0xB990, 0xD278, 0xB991, 0xD279, 0xB992, 0xD27A, 0xB993, 0xD27B, 0xB994, 0xD27C, 0xB995, 0xD27D, 0xB996, 0xD27E, 0xB997, 0xD27F, 0xB998, 0xD282, 0xB999, 0xD283, 0xB99A, 0xD285, 0xB99B, 0xD286, 0xB99C, 0xD287, 0xB99D, 0xD289, 0xB99E, 0xD28A, 0xB99F, 0xD28B, 0xB9A0, 0xD28C, 0xB9A1, 0xBB00, 0xB9A2, 0xBB04, 0xB9A3, 0xBB0D, 0xB9A4, 0xBB0F, 0xB9A5, 0xBB11, 0xB9A6, 0xBB18, 0xB9A7, 0xBB1C, 0xB9A8, 0xBB20, 0xB9A9, 0xBB29, 0xB9AA, 0xBB2B, 0xB9AB, 0xBB34, 0xB9AC, 0xBB35, 0xB9AD, 0xBB36, 0xB9AE, 0xBB38, 0xB9AF, 0xBB3B, 0xB9B0, 0xBB3C, 0xB9B1, 0xBB3D, 0xB9B2, 0xBB3E, 0xB9B3, 0xBB44, 0xB9B4, 0xBB45, 0xB9B5, 0xBB47, 0xB9B6, 0xBB49, 0xB9B7, 0xBB4D, 0xB9B8, 0xBB4F, 0xB9B9, 0xBB50, 0xB9BA, 0xBB54, 0xB9BB, 0xBB58, 0xB9BC, 0xBB61, 0xB9BD, 0xBB63, 0xB9BE, 0xBB6C, 0xB9BF, 0xBB88, 0xB9C0, 0xBB8C, 0xB9C1, 0xBB90, 0xB9C2, 0xBBA4, 0xB9C3, 0xBBA8, 0xB9C4, 0xBBAC, 0xB9C5, 0xBBB4, 0xB9C6, 0xBBB7, 0xB9C7, 0xBBC0, 0xB9C8, 0xBBC4, 0xB9C9, 0xBBC8, 0xB9CA, 0xBBD0, 0xB9CB, 0xBBD3, 0xB9CC, 0xBBF8, 0xB9CD, 0xBBF9, 0xB9CE, 0xBBFC, 0xB9CF, 0xBBFF, 0xB9D0, 0xBC00, 0xB9D1, 0xBC02, 0xB9D2, 0xBC08, 0xB9D3, 0xBC09, 0xB9D4, 0xBC0B, 0xB9D5, 0xBC0C, 0xB9D6, 0xBC0D, 0xB9D7, 0xBC0F, 0xB9D8, 0xBC11, 0xB9D9, 0xBC14, 0xB9DA, 0xBC15, 0xB9DB, 0xBC16, 0xB9DC, 0xBC17, 0xB9DD, 0xBC18, 0xB9DE, 0xBC1B, 0xB9DF, 0xBC1C, 0xB9E0, 0xBC1D, 0xB9E1, 0xBC1E, 0xB9E2, 0xBC1F, 0xB9E3, 0xBC24, 0xB9E4, 0xBC25, 0xB9E5, 0xBC27, 0xB9E6, 0xBC29, 0xB9E7, 0xBC2D, 0xB9E8, 0xBC30, 0xB9E9, 0xBC31, 0xB9EA, 0xBC34, 0xB9EB, 0xBC38, 0xB9EC, 0xBC40, 0xB9ED, 0xBC41, 0xB9EE, 0xBC43, 0xB9EF, 0xBC44, 0xB9F0, 0xBC45, 0xB9F1, 0xBC49, 0xB9F2, 0xBC4C, 0xB9F3, 0xBC4D, 0xB9F4, 0xBC50, 0xB9F5, 0xBC5D, 0xB9F6, 0xBC84, 0xB9F7, 0xBC85, 0xB9F8, 0xBC88, 0xB9F9, 0xBC8B, 0xB9FA, 0xBC8C, 0xB9FB, 0xBC8E, 0xB9FC, 0xBC94, 0xB9FD, 0xBC95, 0xB9FE, 0xBC97, 0xBA41, 0xD28D, 0xBA42, 0xD28E, 0xBA43, 0xD28F, 0xBA44, 0xD292, 0xBA45, 0xD293, 0xBA46, 0xD294, 0xBA47, 0xD296, 0xBA48, 0xD297, 0xBA49, 0xD298, 0xBA4A, 0xD299, 0xBA4B, 0xD29A, 0xBA4C, 0xD29B, 0xBA4D, 0xD29D, 0xBA4E, 0xD29E, 0xBA4F, 0xD29F, 0xBA50, 0xD2A1, 0xBA51, 0xD2A2, 0xBA52, 0xD2A3, 0xBA53, 0xD2A5, 0xBA54, 0xD2A6, 0xBA55, 0xD2A7, 0xBA56, 0xD2A8, 0xBA57, 0xD2A9, 0xBA58, 0xD2AA, 0xBA59, 0xD2AB, 0xBA5A, 0xD2AD, 0xBA61, 0xD2AE, 0xBA62, 0xD2AF, 0xBA63, 0xD2B0, 0xBA64, 0xD2B2, 0xBA65, 0xD2B3, 0xBA66, 0xD2B4, 0xBA67, 0xD2B5, 0xBA68, 0xD2B6, 0xBA69, 0xD2B7, 0xBA6A, 0xD2BA, 0xBA6B, 0xD2BB, 0xBA6C, 0xD2BD, 0xBA6D, 0xD2BE, 0xBA6E, 0xD2C1, 0xBA6F, 0xD2C3, 0xBA70, 0xD2C4, 0xBA71, 0xD2C5, 0xBA72, 0xD2C6, 0xBA73, 0xD2C7, 0xBA74, 0xD2CA, 0xBA75, 0xD2CC, 0xBA76, 0xD2CD, 0xBA77, 0xD2CE, 0xBA78, 0xD2CF, 0xBA79, 0xD2D0, 0xBA7A, 0xD2D1, 0xBA81, 0xD2D2, 0xBA82, 0xD2D3, 0xBA83, 0xD2D5, 0xBA84, 0xD2D6, 0xBA85, 0xD2D7, 0xBA86, 0xD2D9, 0xBA87, 0xD2DA, 0xBA88, 0xD2DB, 0xBA89, 0xD2DD, 0xBA8A, 0xD2DE, 0xBA8B, 0xD2DF, 0xBA8C, 0xD2E0, 0xBA8D, 0xD2E1, 0xBA8E, 0xD2E2, 0xBA8F, 0xD2E3, 0xBA90, 0xD2E6, 0xBA91, 0xD2E7, 0xBA92, 0xD2E8, 0xBA93, 0xD2E9, 0xBA94, 0xD2EA, 0xBA95, 0xD2EB, 0xBA96, 0xD2EC, 0xBA97, 0xD2ED, 0xBA98, 0xD2EE, 0xBA99, 0xD2EF, 0xBA9A, 0xD2F2, 0xBA9B, 0xD2F3, 0xBA9C, 0xD2F5, 0xBA9D, 0xD2F6, 0xBA9E, 0xD2F7, 0xBA9F, 0xD2F9, 0xBAA0, 0xD2FA, 0xBAA1, 0xBC99, 0xBAA2, 0xBC9A, 0xBAA3, 0xBCA0, 0xBAA4, 0xBCA1, 0xBAA5, 0xBCA4, 0xBAA6, 0xBCA7, 0xBAA7, 0xBCA8, 0xBAA8, 0xBCB0, 0xBAA9, 0xBCB1, 0xBAAA, 0xBCB3, 0xBAAB, 0xBCB4, 0xBAAC, 0xBCB5, 0xBAAD, 0xBCBC, 0xBAAE, 0xBCBD, 0xBAAF, 0xBCC0, 0xBAB0, 0xBCC4, 0xBAB1, 0xBCCD, 0xBAB2, 0xBCCF, 0xBAB3, 0xBCD0, 0xBAB4, 0xBCD1, 0xBAB5, 0xBCD5, 0xBAB6, 0xBCD8, 0xBAB7, 0xBCDC, 0xBAB8, 0xBCF4, 0xBAB9, 0xBCF5, 0xBABA, 0xBCF6, 0xBABB, 0xBCF8, 0xBABC, 0xBCFC, 0xBABD, 0xBD04, 0xBABE, 0xBD05, 0xBABF, 0xBD07, 0xBAC0, 0xBD09, 0xBAC1, 0xBD10, 0xBAC2, 0xBD14, 0xBAC3, 0xBD24, 0xBAC4, 0xBD2C, 0xBAC5, 0xBD40, 0xBAC6, 0xBD48, 0xBAC7, 0xBD49, 0xBAC8, 0xBD4C, 0xBAC9, 0xBD50, 0xBACA, 0xBD58, 0xBACB, 0xBD59, 0xBACC, 0xBD64, 0xBACD, 0xBD68, 0xBACE, 0xBD80, 0xBACF, 0xBD81, 0xBAD0, 0xBD84, 0xBAD1, 0xBD87, 0xBAD2, 0xBD88, 0xBAD3, 0xBD89, 0xBAD4, 0xBD8A, 0xBAD5, 0xBD90, 0xBAD6, 0xBD91, 0xBAD7, 0xBD93, 0xBAD8, 0xBD95, 0xBAD9, 0xBD99, 0xBADA, 0xBD9A, 0xBADB, 0xBD9C, 0xBADC, 0xBDA4, 0xBADD, 0xBDB0, 0xBADE, 0xBDB8, 0xBADF, 0xBDD4, 0xBAE0, 0xBDD5, 0xBAE1, 0xBDD8, 0xBAE2, 0xBDDC, 0xBAE3, 0xBDE9, 0xBAE4, 0xBDF0, 0xBAE5, 0xBDF4, 0xBAE6, 0xBDF8, 0xBAE7, 0xBE00, 0xBAE8, 0xBE03, 0xBAE9, 0xBE05, 0xBAEA, 0xBE0C, 0xBAEB, 0xBE0D, 0xBAEC, 0xBE10, 0xBAED, 0xBE14, 0xBAEE, 0xBE1C, 0xBAEF, 0xBE1D, 0xBAF0, 0xBE1F, 0xBAF1, 0xBE44, 0xBAF2, 0xBE45, 0xBAF3, 0xBE48, 0xBAF4, 0xBE4C, 0xBAF5, 0xBE4E, 0xBAF6, 0xBE54, 0xBAF7, 0xBE55, 0xBAF8, 0xBE57, 0xBAF9, 0xBE59, 0xBAFA, 0xBE5A, 0xBAFB, 0xBE5B, 0xBAFC, 0xBE60, 0xBAFD, 0xBE61, 0xBAFE, 0xBE64, 0xBB41, 0xD2FB, 0xBB42, 0xD2FC, 0xBB43, 0xD2FD, 0xBB44, 0xD2FE, 0xBB45, 0xD2FF, 0xBB46, 0xD302, 0xBB47, 0xD304, 0xBB48, 0xD306, 0xBB49, 0xD307, 0xBB4A, 0xD308, 0xBB4B, 0xD309, 0xBB4C, 0xD30A, 0xBB4D, 0xD30B, 0xBB4E, 0xD30F, 0xBB4F, 0xD311, 0xBB50, 0xD312, 0xBB51, 0xD313, 0xBB52, 0xD315, 0xBB53, 0xD317, 0xBB54, 0xD318, 0xBB55, 0xD319, 0xBB56, 0xD31A, 0xBB57, 0xD31B, 0xBB58, 0xD31E, 0xBB59, 0xD322, 0xBB5A, 0xD323, 0xBB61, 0xD324, 0xBB62, 0xD326, 0xBB63, 0xD327, 0xBB64, 0xD32A, 0xBB65, 0xD32B, 0xBB66, 0xD32D, 0xBB67, 0xD32E, 0xBB68, 0xD32F, 0xBB69, 0xD331, 0xBB6A, 0xD332, 0xBB6B, 0xD333, 0xBB6C, 0xD334, 0xBB6D, 0xD335, 0xBB6E, 0xD336, 0xBB6F, 0xD337, 0xBB70, 0xD33A, 0xBB71, 0xD33E, 0xBB72, 0xD33F, 0xBB73, 0xD340, 0xBB74, 0xD341, 0xBB75, 0xD342, 0xBB76, 0xD343, 0xBB77, 0xD346, 0xBB78, 0xD347, 0xBB79, 0xD348, 0xBB7A, 0xD349, 0xBB81, 0xD34A, 0xBB82, 0xD34B, 0xBB83, 0xD34C, 0xBB84, 0xD34D, 0xBB85, 0xD34E, 0xBB86, 0xD34F, 0xBB87, 0xD350, 0xBB88, 0xD351, 0xBB89, 0xD352, 0xBB8A, 0xD353, 0xBB8B, 0xD354, 0xBB8C, 0xD355, 0xBB8D, 0xD356, 0xBB8E, 0xD357, 0xBB8F, 0xD358, 0xBB90, 0xD359, 0xBB91, 0xD35A, 0xBB92, 0xD35B, 0xBB93, 0xD35C, 0xBB94, 0xD35D, 0xBB95, 0xD35E, 0xBB96, 0xD35F, 0xBB97, 0xD360, 0xBB98, 0xD361, 0xBB99, 0xD362, 0xBB9A, 0xD363, 0xBB9B, 0xD364, 0xBB9C, 0xD365, 0xBB9D, 0xD366, 0xBB9E, 0xD367, 0xBB9F, 0xD368, 0xBBA0, 0xD369, 0xBBA1, 0xBE68, 0xBBA2, 0xBE6A, 0xBBA3, 0xBE70, 0xBBA4, 0xBE71, 0xBBA5, 0xBE73, 0xBBA6, 0xBE74, 0xBBA7, 0xBE75, 0xBBA8, 0xBE7B, 0xBBA9, 0xBE7C, 0xBBAA, 0xBE7D, 0xBBAB, 0xBE80, 0xBBAC, 0xBE84, 0xBBAD, 0xBE8C, 0xBBAE, 0xBE8D, 0xBBAF, 0xBE8F, 0xBBB0, 0xBE90, 0xBBB1, 0xBE91, 0xBBB2, 0xBE98, 0xBBB3, 0xBE99, 0xBBB4, 0xBEA8, 0xBBB5, 0xBED0, 0xBBB6, 0xBED1, 0xBBB7, 0xBED4, 0xBBB8, 0xBED7, 0xBBB9, 0xBED8, 0xBBBA, 0xBEE0, 0xBBBB, 0xBEE3, 0xBBBC, 0xBEE4, 0xBBBD, 0xBEE5, 0xBBBE, 0xBEEC, 0xBBBF, 0xBF01, 0xBBC0, 0xBF08, 0xBBC1, 0xBF09, 0xBBC2, 0xBF18, 0xBBC3, 0xBF19, 0xBBC4, 0xBF1B, 0xBBC5, 0xBF1C, 0xBBC6, 0xBF1D, 0xBBC7, 0xBF40, 0xBBC8, 0xBF41, 0xBBC9, 0xBF44, 0xBBCA, 0xBF48, 0xBBCB, 0xBF50, 0xBBCC, 0xBF51, 0xBBCD, 0xBF55, 0xBBCE, 0xBF94, 0xBBCF, 0xBFB0, 0xBBD0, 0xBFC5, 0xBBD1, 0xBFCC, 0xBBD2, 0xBFCD, 0xBBD3, 0xBFD0, 0xBBD4, 0xBFD4, 0xBBD5, 0xBFDC, 0xBBD6, 0xBFDF, 0xBBD7, 0xBFE1, 0xBBD8, 0xC03C, 0xBBD9, 0xC051, 0xBBDA, 0xC058, 0xBBDB, 0xC05C, 0xBBDC, 0xC060, 0xBBDD, 0xC068, 0xBBDE, 0xC069, 0xBBDF, 0xC090, 0xBBE0, 0xC091, 0xBBE1, 0xC094, 0xBBE2, 0xC098, 0xBBE3, 0xC0A0, 0xBBE4, 0xC0A1, 0xBBE5, 0xC0A3, 0xBBE6, 0xC0A5, 0xBBE7, 0xC0AC, 0xBBE8, 0xC0AD, 0xBBE9, 0xC0AF, 0xBBEA, 0xC0B0, 0xBBEB, 0xC0B3, 0xBBEC, 0xC0B4, 0xBBED, 0xC0B5, 0xBBEE, 0xC0B6, 0xBBEF, 0xC0BC, 0xBBF0, 0xC0BD, 0xBBF1, 0xC0BF, 0xBBF2, 0xC0C0, 0xBBF3, 0xC0C1, 0xBBF4, 0xC0C5, 0xBBF5, 0xC0C8, 0xBBF6, 0xC0C9, 0xBBF7, 0xC0CC, 0xBBF8, 0xC0D0, 0xBBF9, 0xC0D8, 0xBBFA, 0xC0D9, 0xBBFB, 0xC0DB, 0xBBFC, 0xC0DC, 0xBBFD, 0xC0DD, 0xBBFE, 0xC0E4, 0xBC41, 0xD36A, 0xBC42, 0xD36B, 0xBC43, 0xD36C, 0xBC44, 0xD36D, 0xBC45, 0xD36E, 0xBC46, 0xD36F, 0xBC47, 0xD370, 0xBC48, 0xD371, 0xBC49, 0xD372, 0xBC4A, 0xD373, 0xBC4B, 0xD374, 0xBC4C, 0xD375, 0xBC4D, 0xD376, 0xBC4E, 0xD377, 0xBC4F, 0xD378, 0xBC50, 0xD379, 0xBC51, 0xD37A, 0xBC52, 0xD37B, 0xBC53, 0xD37E, 0xBC54, 0xD37F, 0xBC55, 0xD381, 0xBC56, 0xD382, 0xBC57, 0xD383, 0xBC58, 0xD385, 0xBC59, 0xD386, 0xBC5A, 0xD387, 0xBC61, 0xD388, 0xBC62, 0xD389, 0xBC63, 0xD38A, 0xBC64, 0xD38B, 0xBC65, 0xD38E, 0xBC66, 0xD392, 0xBC67, 0xD393, 0xBC68, 0xD394, 0xBC69, 0xD395, 0xBC6A, 0xD396, 0xBC6B, 0xD397, 0xBC6C, 0xD39A, 0xBC6D, 0xD39B, 0xBC6E, 0xD39D, 0xBC6F, 0xD39E, 0xBC70, 0xD39F, 0xBC71, 0xD3A1, 0xBC72, 0xD3A2, 0xBC73, 0xD3A3, 0xBC74, 0xD3A4, 0xBC75, 0xD3A5, 0xBC76, 0xD3A6, 0xBC77, 0xD3A7, 0xBC78, 0xD3AA, 0xBC79, 0xD3AC, 0xBC7A, 0xD3AE, 0xBC81, 0xD3AF, 0xBC82, 0xD3B0, 0xBC83, 0xD3B1, 0xBC84, 0xD3B2, 0xBC85, 0xD3B3, 0xBC86, 0xD3B5, 0xBC87, 0xD3B6, 0xBC88, 0xD3B7, 0xBC89, 0xD3B9, 0xBC8A, 0xD3BA, 0xBC8B, 0xD3BB, 0xBC8C, 0xD3BD, 0xBC8D, 0xD3BE, 0xBC8E, 0xD3BF, 0xBC8F, 0xD3C0, 0xBC90, 0xD3C1, 0xBC91, 0xD3C2, 0xBC92, 0xD3C3, 0xBC93, 0xD3C6, 0xBC94, 0xD3C7, 0xBC95, 0xD3CA, 0xBC96, 0xD3CB, 0xBC97, 0xD3CC, 0xBC98, 0xD3CD, 0xBC99, 0xD3CE, 0xBC9A, 0xD3CF, 0xBC9B, 0xD3D1, 0xBC9C, 0xD3D2, 0xBC9D, 0xD3D3, 0xBC9E, 0xD3D4, 0xBC9F, 0xD3D5, 0xBCA0, 0xD3D6, 0xBCA1, 0xC0E5, 0xBCA2, 0xC0E8, 0xBCA3, 0xC0EC, 0xBCA4, 0xC0F4, 0xBCA5, 0xC0F5, 0xBCA6, 0xC0F7, 0xBCA7, 0xC0F9, 0xBCA8, 0xC100, 0xBCA9, 0xC104, 0xBCAA, 0xC108, 0xBCAB, 0xC110, 0xBCAC, 0xC115, 0xBCAD, 0xC11C, 0xBCAE, 0xC11D, 0xBCAF, 0xC11E, 0xBCB0, 0xC11F, 0xBCB1, 0xC120, 0xBCB2, 0xC123, 0xBCB3, 0xC124, 0xBCB4, 0xC126, 0xBCB5, 0xC127, 0xBCB6, 0xC12C, 0xBCB7, 0xC12D, 0xBCB8, 0xC12F, 0xBCB9, 0xC130, 0xBCBA, 0xC131, 0xBCBB, 0xC136, 0xBCBC, 0xC138, 0xBCBD, 0xC139, 0xBCBE, 0xC13C, 0xBCBF, 0xC140, 0xBCC0, 0xC148, 0xBCC1, 0xC149, 0xBCC2, 0xC14B, 0xBCC3, 0xC14C, 0xBCC4, 0xC14D, 0xBCC5, 0xC154, 0xBCC6, 0xC155, 0xBCC7, 0xC158, 0xBCC8, 0xC15C, 0xBCC9, 0xC164, 0xBCCA, 0xC165, 0xBCCB, 0xC167, 0xBCCC, 0xC168, 0xBCCD, 0xC169, 0xBCCE, 0xC170, 0xBCCF, 0xC174, 0xBCD0, 0xC178, 0xBCD1, 0xC185, 0xBCD2, 0xC18C, 0xBCD3, 0xC18D, 0xBCD4, 0xC18E, 0xBCD5, 0xC190, 0xBCD6, 0xC194, 0xBCD7, 0xC196, 0xBCD8, 0xC19C, 0xBCD9, 0xC19D, 0xBCDA, 0xC19F, 0xBCDB, 0xC1A1, 0xBCDC, 0xC1A5, 0xBCDD, 0xC1A8, 0xBCDE, 0xC1A9, 0xBCDF, 0xC1AC, 0xBCE0, 0xC1B0, 0xBCE1, 0xC1BD, 0xBCE2, 0xC1C4, 0xBCE3, 0xC1C8, 0xBCE4, 0xC1CC, 0xBCE5, 0xC1D4, 0xBCE6, 0xC1D7, 0xBCE7, 0xC1D8, 0xBCE8, 0xC1E0, 0xBCE9, 0xC1E4, 0xBCEA, 0xC1E8, 0xBCEB, 0xC1F0, 0xBCEC, 0xC1F1, 0xBCED, 0xC1F3, 0xBCEE, 0xC1FC, 0xBCEF, 0xC1FD, 0xBCF0, 0xC200, 0xBCF1, 0xC204, 0xBCF2, 0xC20C, 0xBCF3, 0xC20D, 0xBCF4, 0xC20F, 0xBCF5, 0xC211, 0xBCF6, 0xC218, 0xBCF7, 0xC219, 0xBCF8, 0xC21C, 0xBCF9, 0xC21F, 0xBCFA, 0xC220, 0xBCFB, 0xC228, 0xBCFC, 0xC229, 0xBCFD, 0xC22B, 0xBCFE, 0xC22D, 0xBD41, 0xD3D7, 0xBD42, 0xD3D9, 0xBD43, 0xD3DA, 0xBD44, 0xD3DB, 0xBD45, 0xD3DC, 0xBD46, 0xD3DD, 0xBD47, 0xD3DE, 0xBD48, 0xD3DF, 0xBD49, 0xD3E0, 0xBD4A, 0xD3E2, 0xBD4B, 0xD3E4, 0xBD4C, 0xD3E5, 0xBD4D, 0xD3E6, 0xBD4E, 0xD3E7, 0xBD4F, 0xD3E8, 0xBD50, 0xD3E9, 0xBD51, 0xD3EA, 0xBD52, 0xD3EB, 0xBD53, 0xD3EE, 0xBD54, 0xD3EF, 0xBD55, 0xD3F1, 0xBD56, 0xD3F2, 0xBD57, 0xD3F3, 0xBD58, 0xD3F5, 0xBD59, 0xD3F6, 0xBD5A, 0xD3F7, 0xBD61, 0xD3F8, 0xBD62, 0xD3F9, 0xBD63, 0xD3FA, 0xBD64, 0xD3FB, 0xBD65, 0xD3FE, 0xBD66, 0xD400, 0xBD67, 0xD402, 0xBD68, 0xD403, 0xBD69, 0xD404, 0xBD6A, 0xD405, 0xBD6B, 0xD406, 0xBD6C, 0xD407, 0xBD6D, 0xD409, 0xBD6E, 0xD40A, 0xBD6F, 0xD40B, 0xBD70, 0xD40C, 0xBD71, 0xD40D, 0xBD72, 0xD40E, 0xBD73, 0xD40F, 0xBD74, 0xD410, 0xBD75, 0xD411, 0xBD76, 0xD412, 0xBD77, 0xD413, 0xBD78, 0xD414, 0xBD79, 0xD415, 0xBD7A, 0xD416, 0xBD81, 0xD417, 0xBD82, 0xD418, 0xBD83, 0xD419, 0xBD84, 0xD41A, 0xBD85, 0xD41B, 0xBD86, 0xD41C, 0xBD87, 0xD41E, 0xBD88, 0xD41F, 0xBD89, 0xD420, 0xBD8A, 0xD421, 0xBD8B, 0xD422, 0xBD8C, 0xD423, 0xBD8D, 0xD424, 0xBD8E, 0xD425, 0xBD8F, 0xD426, 0xBD90, 0xD427, 0xBD91, 0xD428, 0xBD92, 0xD429, 0xBD93, 0xD42A, 0xBD94, 0xD42B, 0xBD95, 0xD42C, 0xBD96, 0xD42D, 0xBD97, 0xD42E, 0xBD98, 0xD42F, 0xBD99, 0xD430, 0xBD9A, 0xD431, 0xBD9B, 0xD432, 0xBD9C, 0xD433, 0xBD9D, 0xD434, 0xBD9E, 0xD435, 0xBD9F, 0xD436, 0xBDA0, 0xD437, 0xBDA1, 0xC22F, 0xBDA2, 0xC231, 0xBDA3, 0xC232, 0xBDA4, 0xC234, 0xBDA5, 0xC248, 0xBDA6, 0xC250, 0xBDA7, 0xC251, 0xBDA8, 0xC254, 0xBDA9, 0xC258, 0xBDAA, 0xC260, 0xBDAB, 0xC265, 0xBDAC, 0xC26C, 0xBDAD, 0xC26D, 0xBDAE, 0xC270, 0xBDAF, 0xC274, 0xBDB0, 0xC27C, 0xBDB1, 0xC27D, 0xBDB2, 0xC27F, 0xBDB3, 0xC281, 0xBDB4, 0xC288, 0xBDB5, 0xC289, 0xBDB6, 0xC290, 0xBDB7, 0xC298, 0xBDB8, 0xC29B, 0xBDB9, 0xC29D, 0xBDBA, 0xC2A4, 0xBDBB, 0xC2A5, 0xBDBC, 0xC2A8, 0xBDBD, 0xC2AC, 0xBDBE, 0xC2AD, 0xBDBF, 0xC2B4, 0xBDC0, 0xC2B5, 0xBDC1, 0xC2B7, 0xBDC2, 0xC2B9, 0xBDC3, 0xC2DC, 0xBDC4, 0xC2DD, 0xBDC5, 0xC2E0, 0xBDC6, 0xC2E3, 0xBDC7, 0xC2E4, 0xBDC8, 0xC2EB, 0xBDC9, 0xC2EC, 0xBDCA, 0xC2ED, 0xBDCB, 0xC2EF, 0xBDCC, 0xC2F1, 0xBDCD, 0xC2F6, 0xBDCE, 0xC2F8, 0xBDCF, 0xC2F9, 0xBDD0, 0xC2FB, 0xBDD1, 0xC2FC, 0xBDD2, 0xC300, 0xBDD3, 0xC308, 0xBDD4, 0xC309, 0xBDD5, 0xC30C, 0xBDD6, 0xC30D, 0xBDD7, 0xC313, 0xBDD8, 0xC314, 0xBDD9, 0xC315, 0xBDDA, 0xC318, 0xBDDB, 0xC31C, 0xBDDC, 0xC324, 0xBDDD, 0xC325, 0xBDDE, 0xC328, 0xBDDF, 0xC329, 0xBDE0, 0xC345, 0xBDE1, 0xC368, 0xBDE2, 0xC369, 0xBDE3, 0xC36C, 0xBDE4, 0xC370, 0xBDE5, 0xC372, 0xBDE6, 0xC378, 0xBDE7, 0xC379, 0xBDE8, 0xC37C, 0xBDE9, 0xC37D, 0xBDEA, 0xC384, 0xBDEB, 0xC388, 0xBDEC, 0xC38C, 0xBDED, 0xC3C0, 0xBDEE, 0xC3D8, 0xBDEF, 0xC3D9, 0xBDF0, 0xC3DC, 0xBDF1, 0xC3DF, 0xBDF2, 0xC3E0, 0xBDF3, 0xC3E2, 0xBDF4, 0xC3E8, 0xBDF5, 0xC3E9, 0xBDF6, 0xC3ED, 0xBDF7, 0xC3F4, 0xBDF8, 0xC3F5, 0xBDF9, 0xC3F8, 0xBDFA, 0xC408, 0xBDFB, 0xC410, 0xBDFC, 0xC424, 0xBDFD, 0xC42C, 0xBDFE, 0xC430, 0xBE41, 0xD438, 0xBE42, 0xD439, 0xBE43, 0xD43A, 0xBE44, 0xD43B, 0xBE45, 0xD43C, 0xBE46, 0xD43D, 0xBE47, 0xD43E, 0xBE48, 0xD43F, 0xBE49, 0xD441, 0xBE4A, 0xD442, 0xBE4B, 0xD443, 0xBE4C, 0xD445, 0xBE4D, 0xD446, 0xBE4E, 0xD447, 0xBE4F, 0xD448, 0xBE50, 0xD449, 0xBE51, 0xD44A, 0xBE52, 0xD44B, 0xBE53, 0xD44C, 0xBE54, 0xD44D, 0xBE55, 0xD44E, 0xBE56, 0xD44F, 0xBE57, 0xD450, 0xBE58, 0xD451, 0xBE59, 0xD452, 0xBE5A, 0xD453, 0xBE61, 0xD454, 0xBE62, 0xD455, 0xBE63, 0xD456, 0xBE64, 0xD457, 0xBE65, 0xD458, 0xBE66, 0xD459, 0xBE67, 0xD45A, 0xBE68, 0xD45B, 0xBE69, 0xD45D, 0xBE6A, 0xD45E, 0xBE6B, 0xD45F, 0xBE6C, 0xD461, 0xBE6D, 0xD462, 0xBE6E, 0xD463, 0xBE6F, 0xD465, 0xBE70, 0xD466, 0xBE71, 0xD467, 0xBE72, 0xD468, 0xBE73, 0xD469, 0xBE74, 0xD46A, 0xBE75, 0xD46B, 0xBE76, 0xD46C, 0xBE77, 0xD46E, 0xBE78, 0xD470, 0xBE79, 0xD471, 0xBE7A, 0xD472, 0xBE81, 0xD473, 0xBE82, 0xD474, 0xBE83, 0xD475, 0xBE84, 0xD476, 0xBE85, 0xD477, 0xBE86, 0xD47A, 0xBE87, 0xD47B, 0xBE88, 0xD47D, 0xBE89, 0xD47E, 0xBE8A, 0xD481, 0xBE8B, 0xD483, 0xBE8C, 0xD484, 0xBE8D, 0xD485, 0xBE8E, 0xD486, 0xBE8F, 0xD487, 0xBE90, 0xD48A, 0xBE91, 0xD48C, 0xBE92, 0xD48E, 0xBE93, 0xD48F, 0xBE94, 0xD490, 0xBE95, 0xD491, 0xBE96, 0xD492, 0xBE97, 0xD493, 0xBE98, 0xD495, 0xBE99, 0xD496, 0xBE9A, 0xD497, 0xBE9B, 0xD498, 0xBE9C, 0xD499, 0xBE9D, 0xD49A, 0xBE9E, 0xD49B, 0xBE9F, 0xD49C, 0xBEA0, 0xD49D, 0xBEA1, 0xC434, 0xBEA2, 0xC43C, 0xBEA3, 0xC43D, 0xBEA4, 0xC448, 0xBEA5, 0xC464, 0xBEA6, 0xC465, 0xBEA7, 0xC468, 0xBEA8, 0xC46C, 0xBEA9, 0xC474, 0xBEAA, 0xC475, 0xBEAB, 0xC479, 0xBEAC, 0xC480, 0xBEAD, 0xC494, 0xBEAE, 0xC49C, 0xBEAF, 0xC4B8, 0xBEB0, 0xC4BC, 0xBEB1, 0xC4E9, 0xBEB2, 0xC4F0, 0xBEB3, 0xC4F1, 0xBEB4, 0xC4F4, 0xBEB5, 0xC4F8, 0xBEB6, 0xC4FA, 0xBEB7, 0xC4FF, 0xBEB8, 0xC500, 0xBEB9, 0xC501, 0xBEBA, 0xC50C, 0xBEBB, 0xC510, 0xBEBC, 0xC514, 0xBEBD, 0xC51C, 0xBEBE, 0xC528, 0xBEBF, 0xC529, 0xBEC0, 0xC52C, 0xBEC1, 0xC530, 0xBEC2, 0xC538, 0xBEC3, 0xC539, 0xBEC4, 0xC53B, 0xBEC5, 0xC53D, 0xBEC6, 0xC544, 0xBEC7, 0xC545, 0xBEC8, 0xC548, 0xBEC9, 0xC549, 0xBECA, 0xC54A, 0xBECB, 0xC54C, 0xBECC, 0xC54D, 0xBECD, 0xC54E, 0xBECE, 0xC553, 0xBECF, 0xC554, 0xBED0, 0xC555, 0xBED1, 0xC557, 0xBED2, 0xC558, 0xBED3, 0xC559, 0xBED4, 0xC55D, 0xBED5, 0xC55E, 0xBED6, 0xC560, 0xBED7, 0xC561, 0xBED8, 0xC564, 0xBED9, 0xC568, 0xBEDA, 0xC570, 0xBEDB, 0xC571, 0xBEDC, 0xC573, 0xBEDD, 0xC574, 0xBEDE, 0xC575, 0xBEDF, 0xC57C, 0xBEE0, 0xC57D, 0xBEE1, 0xC580, 0xBEE2, 0xC584, 0xBEE3, 0xC587, 0xBEE4, 0xC58C, 0xBEE5, 0xC58D, 0xBEE6, 0xC58F, 0xBEE7, 0xC591, 0xBEE8, 0xC595, 0xBEE9, 0xC597, 0xBEEA, 0xC598, 0xBEEB, 0xC59C, 0xBEEC, 0xC5A0, 0xBEED, 0xC5A9, 0xBEEE, 0xC5B4, 0xBEEF, 0xC5B5, 0xBEF0, 0xC5B8, 0xBEF1, 0xC5B9, 0xBEF2, 0xC5BB, 0xBEF3, 0xC5BC, 0xBEF4, 0xC5BD, 0xBEF5, 0xC5BE, 0xBEF6, 0xC5C4, 0xBEF7, 0xC5C5, 0xBEF8, 0xC5C6, 0xBEF9, 0xC5C7, 0xBEFA, 0xC5C8, 0xBEFB, 0xC5C9, 0xBEFC, 0xC5CA, 0xBEFD, 0xC5CC, 0xBEFE, 0xC5CE, 0xBF41, 0xD49E, 0xBF42, 0xD49F, 0xBF43, 0xD4A0, 0xBF44, 0xD4A1, 0xBF45, 0xD4A2, 0xBF46, 0xD4A3, 0xBF47, 0xD4A4, 0xBF48, 0xD4A5, 0xBF49, 0xD4A6, 0xBF4A, 0xD4A7, 0xBF4B, 0xD4A8, 0xBF4C, 0xD4AA, 0xBF4D, 0xD4AB, 0xBF4E, 0xD4AC, 0xBF4F, 0xD4AD, 0xBF50, 0xD4AE, 0xBF51, 0xD4AF, 0xBF52, 0xD4B0, 0xBF53, 0xD4B1, 0xBF54, 0xD4B2, 0xBF55, 0xD4B3, 0xBF56, 0xD4B4, 0xBF57, 0xD4B5, 0xBF58, 0xD4B6, 0xBF59, 0xD4B7, 0xBF5A, 0xD4B8, 0xBF61, 0xD4B9, 0xBF62, 0xD4BA, 0xBF63, 0xD4BB, 0xBF64, 0xD4BC, 0xBF65, 0xD4BD, 0xBF66, 0xD4BE, 0xBF67, 0xD4BF, 0xBF68, 0xD4C0, 0xBF69, 0xD4C1, 0xBF6A, 0xD4C2, 0xBF6B, 0xD4C3, 0xBF6C, 0xD4C4, 0xBF6D, 0xD4C5, 0xBF6E, 0xD4C6, 0xBF6F, 0xD4C7, 0xBF70, 0xD4C8, 0xBF71, 0xD4C9, 0xBF72, 0xD4CA, 0xBF73, 0xD4CB, 0xBF74, 0xD4CD, 0xBF75, 0xD4CE, 0xBF76, 0xD4CF, 0xBF77, 0xD4D1, 0xBF78, 0xD4D2, 0xBF79, 0xD4D3, 0xBF7A, 0xD4D5, 0xBF81, 0xD4D6, 0xBF82, 0xD4D7, 0xBF83, 0xD4D8, 0xBF84, 0xD4D9, 0xBF85, 0xD4DA, 0xBF86, 0xD4DB, 0xBF87, 0xD4DD, 0xBF88, 0xD4DE, 0xBF89, 0xD4E0, 0xBF8A, 0xD4E1, 0xBF8B, 0xD4E2, 0xBF8C, 0xD4E3, 0xBF8D, 0xD4E4, 0xBF8E, 0xD4E5, 0xBF8F, 0xD4E6, 0xBF90, 0xD4E7, 0xBF91, 0xD4E9, 0xBF92, 0xD4EA, 0xBF93, 0xD4EB, 0xBF94, 0xD4ED, 0xBF95, 0xD4EE, 0xBF96, 0xD4EF, 0xBF97, 0xD4F1, 0xBF98, 0xD4F2, 0xBF99, 0xD4F3, 0xBF9A, 0xD4F4, 0xBF9B, 0xD4F5, 0xBF9C, 0xD4F6, 0xBF9D, 0xD4F7, 0xBF9E, 0xD4F9, 0xBF9F, 0xD4FA, 0xBFA0, 0xD4FC, 0xBFA1, 0xC5D0, 0xBFA2, 0xC5D1, 0xBFA3, 0xC5D4, 0xBFA4, 0xC5D8, 0xBFA5, 0xC5E0, 0xBFA6, 0xC5E1, 0xBFA7, 0xC5E3, 0xBFA8, 0xC5E5, 0xBFA9, 0xC5EC, 0xBFAA, 0xC5ED, 0xBFAB, 0xC5EE, 0xBFAC, 0xC5F0, 0xBFAD, 0xC5F4, 0xBFAE, 0xC5F6, 0xBFAF, 0xC5F7, 0xBFB0, 0xC5FC, 0xBFB1, 0xC5FD, 0xBFB2, 0xC5FE, 0xBFB3, 0xC5FF, 0xBFB4, 0xC600, 0xBFB5, 0xC601, 0xBFB6, 0xC605, 0xBFB7, 0xC606, 0xBFB8, 0xC607, 0xBFB9, 0xC608, 0xBFBA, 0xC60C, 0xBFBB, 0xC610, 0xBFBC, 0xC618, 0xBFBD, 0xC619, 0xBFBE, 0xC61B, 0xBFBF, 0xC61C, 0xBFC0, 0xC624, 0xBFC1, 0xC625, 0xBFC2, 0xC628, 0xBFC3, 0xC62C, 0xBFC4, 0xC62D, 0xBFC5, 0xC62E, 0xBFC6, 0xC630, 0xBFC7, 0xC633, 0xBFC8, 0xC634, 0xBFC9, 0xC635, 0xBFCA, 0xC637, 0xBFCB, 0xC639, 0xBFCC, 0xC63B, 0xBFCD, 0xC640, 0xBFCE, 0xC641, 0xBFCF, 0xC644, 0xBFD0, 0xC648, 0xBFD1, 0xC650, 0xBFD2, 0xC651, 0xBFD3, 0xC653, 0xBFD4, 0xC654, 0xBFD5, 0xC655, 0xBFD6, 0xC65C, 0xBFD7, 0xC65D, 0xBFD8, 0xC660, 0xBFD9, 0xC66C, 0xBFDA, 0xC66F, 0xBFDB, 0xC671, 0xBFDC, 0xC678, 0xBFDD, 0xC679, 0xBFDE, 0xC67C, 0xBFDF, 0xC680, 0xBFE0, 0xC688, 0xBFE1, 0xC689, 0xBFE2, 0xC68B, 0xBFE3, 0xC68D, 0xBFE4, 0xC694, 0xBFE5, 0xC695, 0xBFE6, 0xC698, 0xBFE7, 0xC69C, 0xBFE8, 0xC6A4, 0xBFE9, 0xC6A5, 0xBFEA, 0xC6A7, 0xBFEB, 0xC6A9, 0xBFEC, 0xC6B0, 0xBFED, 0xC6B1, 0xBFEE, 0xC6B4, 0xBFEF, 0xC6B8, 0xBFF0, 0xC6B9, 0xBFF1, 0xC6BA, 0xBFF2, 0xC6C0, 0xBFF3, 0xC6C1, 0xBFF4, 0xC6C3, 0xBFF5, 0xC6C5, 0xBFF6, 0xC6CC, 0xBFF7, 0xC6CD, 0xBFF8, 0xC6D0, 0xBFF9, 0xC6D4, 0xBFFA, 0xC6DC, 0xBFFB, 0xC6DD, 0xBFFC, 0xC6E0, 0xBFFD, 0xC6E1, 0xBFFE, 0xC6E8, 0xC041, 0xD4FE, 0xC042, 0xD4FF, 0xC043, 0xD500, 0xC044, 0xD501, 0xC045, 0xD502, 0xC046, 0xD503, 0xC047, 0xD505, 0xC048, 0xD506, 0xC049, 0xD507, 0xC04A, 0xD509, 0xC04B, 0xD50A, 0xC04C, 0xD50B, 0xC04D, 0xD50D, 0xC04E, 0xD50E, 0xC04F, 0xD50F, 0xC050, 0xD510, 0xC051, 0xD511, 0xC052, 0xD512, 0xC053, 0xD513, 0xC054, 0xD516, 0xC055, 0xD518, 0xC056, 0xD519, 0xC057, 0xD51A, 0xC058, 0xD51B, 0xC059, 0xD51C, 0xC05A, 0xD51D, 0xC061, 0xD51E, 0xC062, 0xD51F, 0xC063, 0xD520, 0xC064, 0xD521, 0xC065, 0xD522, 0xC066, 0xD523, 0xC067, 0xD524, 0xC068, 0xD525, 0xC069, 0xD526, 0xC06A, 0xD527, 0xC06B, 0xD528, 0xC06C, 0xD529, 0xC06D, 0xD52A, 0xC06E, 0xD52B, 0xC06F, 0xD52C, 0xC070, 0xD52D, 0xC071, 0xD52E, 0xC072, 0xD52F, 0xC073, 0xD530, 0xC074, 0xD531, 0xC075, 0xD532, 0xC076, 0xD533, 0xC077, 0xD534, 0xC078, 0xD535, 0xC079, 0xD536, 0xC07A, 0xD537, 0xC081, 0xD538, 0xC082, 0xD539, 0xC083, 0xD53A, 0xC084, 0xD53B, 0xC085, 0xD53E, 0xC086, 0xD53F, 0xC087, 0xD541, 0xC088, 0xD542, 0xC089, 0xD543, 0xC08A, 0xD545, 0xC08B, 0xD546, 0xC08C, 0xD547, 0xC08D, 0xD548, 0xC08E, 0xD549, 0xC08F, 0xD54A, 0xC090, 0xD54B, 0xC091, 0xD54E, 0xC092, 0xD550, 0xC093, 0xD552, 0xC094, 0xD553, 0xC095, 0xD554, 0xC096, 0xD555, 0xC097, 0xD556, 0xC098, 0xD557, 0xC099, 0xD55A, 0xC09A, 0xD55B, 0xC09B, 0xD55D, 0xC09C, 0xD55E, 0xC09D, 0xD55F, 0xC09E, 0xD561, 0xC09F, 0xD562, 0xC0A0, 0xD563, 0xC0A1, 0xC6E9, 0xC0A2, 0xC6EC, 0xC0A3, 0xC6F0, 0xC0A4, 0xC6F8, 0xC0A5, 0xC6F9, 0xC0A6, 0xC6FD, 0xC0A7, 0xC704, 0xC0A8, 0xC705, 0xC0A9, 0xC708, 0xC0AA, 0xC70C, 0xC0AB, 0xC714, 0xC0AC, 0xC715, 0xC0AD, 0xC717, 0xC0AE, 0xC719, 0xC0AF, 0xC720, 0xC0B0, 0xC721, 0xC0B1, 0xC724, 0xC0B2, 0xC728, 0xC0B3, 0xC730, 0xC0B4, 0xC731, 0xC0B5, 0xC733, 0xC0B6, 0xC735, 0xC0B7, 0xC737, 0xC0B8, 0xC73C, 0xC0B9, 0xC73D, 0xC0BA, 0xC740, 0xC0BB, 0xC744, 0xC0BC, 0xC74A, 0xC0BD, 0xC74C, 0xC0BE, 0xC74D, 0xC0BF, 0xC74F, 0xC0C0, 0xC751, 0xC0C1, 0xC752, 0xC0C2, 0xC753, 0xC0C3, 0xC754, 0xC0C4, 0xC755, 0xC0C5, 0xC756, 0xC0C6, 0xC757, 0xC0C7, 0xC758, 0xC0C8, 0xC75C, 0xC0C9, 0xC760, 0xC0CA, 0xC768, 0xC0CB, 0xC76B, 0xC0CC, 0xC774, 0xC0CD, 0xC775, 0xC0CE, 0xC778, 0xC0CF, 0xC77C, 0xC0D0, 0xC77D, 0xC0D1, 0xC77E, 0xC0D2, 0xC783, 0xC0D3, 0xC784, 0xC0D4, 0xC785, 0xC0D5, 0xC787, 0xC0D6, 0xC788, 0xC0D7, 0xC789, 0xC0D8, 0xC78A, 0xC0D9, 0xC78E, 0xC0DA, 0xC790, 0xC0DB, 0xC791, 0xC0DC, 0xC794, 0xC0DD, 0xC796, 0xC0DE, 0xC797, 0xC0DF, 0xC798, 0xC0E0, 0xC79A, 0xC0E1, 0xC7A0, 0xC0E2, 0xC7A1, 0xC0E3, 0xC7A3, 0xC0E4, 0xC7A4, 0xC0E5, 0xC7A5, 0xC0E6, 0xC7A6, 0xC0E7, 0xC7AC, 0xC0E8, 0xC7AD, 0xC0E9, 0xC7B0, 0xC0EA, 0xC7B4, 0xC0EB, 0xC7BC, 0xC0EC, 0xC7BD, 0xC0ED, 0xC7BF, 0xC0EE, 0xC7C0, 0xC0EF, 0xC7C1, 0xC0F0, 0xC7C8, 0xC0F1, 0xC7C9, 0xC0F2, 0xC7CC, 0xC0F3, 0xC7CE, 0xC0F4, 0xC7D0, 0xC0F5, 0xC7D8, 0xC0F6, 0xC7DD, 0xC0F7, 0xC7E4, 0xC0F8, 0xC7E8, 0xC0F9, 0xC7EC, 0xC0FA, 0xC800, 0xC0FB, 0xC801, 0xC0FC, 0xC804, 0xC0FD, 0xC808, 0xC0FE, 0xC80A, 0xC141, 0xD564, 0xC142, 0xD566, 0xC143, 0xD567, 0xC144, 0xD56A, 0xC145, 0xD56C, 0xC146, 0xD56E, 0xC147, 0xD56F, 0xC148, 0xD570, 0xC149, 0xD571, 0xC14A, 0xD572, 0xC14B, 0xD573, 0xC14C, 0xD576, 0xC14D, 0xD577, 0xC14E, 0xD579, 0xC14F, 0xD57A, 0xC150, 0xD57B, 0xC151, 0xD57D, 0xC152, 0xD57E, 0xC153, 0xD57F, 0xC154, 0xD580, 0xC155, 0xD581, 0xC156, 0xD582, 0xC157, 0xD583, 0xC158, 0xD586, 0xC159, 0xD58A, 0xC15A, 0xD58B, 0xC161, 0xD58C, 0xC162, 0xD58D, 0xC163, 0xD58E, 0xC164, 0xD58F, 0xC165, 0xD591, 0xC166, 0xD592, 0xC167, 0xD593, 0xC168, 0xD594, 0xC169, 0xD595, 0xC16A, 0xD596, 0xC16B, 0xD597, 0xC16C, 0xD598, 0xC16D, 0xD599, 0xC16E, 0xD59A, 0xC16F, 0xD59B, 0xC170, 0xD59C, 0xC171, 0xD59D, 0xC172, 0xD59E, 0xC173, 0xD59F, 0xC174, 0xD5A0, 0xC175, 0xD5A1, 0xC176, 0xD5A2, 0xC177, 0xD5A3, 0xC178, 0xD5A4, 0xC179, 0xD5A6, 0xC17A, 0xD5A7, 0xC181, 0xD5A8, 0xC182, 0xD5A9, 0xC183, 0xD5AA, 0xC184, 0xD5AB, 0xC185, 0xD5AC, 0xC186, 0xD5AD, 0xC187, 0xD5AE, 0xC188, 0xD5AF, 0xC189, 0xD5B0, 0xC18A, 0xD5B1, 0xC18B, 0xD5B2, 0xC18C, 0xD5B3, 0xC18D, 0xD5B4, 0xC18E, 0xD5B5, 0xC18F, 0xD5B6, 0xC190, 0xD5B7, 0xC191, 0xD5B8, 0xC192, 0xD5B9, 0xC193, 0xD5BA, 0xC194, 0xD5BB, 0xC195, 0xD5BC, 0xC196, 0xD5BD, 0xC197, 0xD5BE, 0xC198, 0xD5BF, 0xC199, 0xD5C0, 0xC19A, 0xD5C1, 0xC19B, 0xD5C2, 0xC19C, 0xD5C3, 0xC19D, 0xD5C4, 0xC19E, 0xD5C5, 0xC19F, 0xD5C6, 0xC1A0, 0xD5C7, 0xC1A1, 0xC810, 0xC1A2, 0xC811, 0xC1A3, 0xC813, 0xC1A4, 0xC815, 0xC1A5, 0xC816, 0xC1A6, 0xC81C, 0xC1A7, 0xC81D, 0xC1A8, 0xC820, 0xC1A9, 0xC824, 0xC1AA, 0xC82C, 0xC1AB, 0xC82D, 0xC1AC, 0xC82F, 0xC1AD, 0xC831, 0xC1AE, 0xC838, 0xC1AF, 0xC83C, 0xC1B0, 0xC840, 0xC1B1, 0xC848, 0xC1B2, 0xC849, 0xC1B3, 0xC84C, 0xC1B4, 0xC84D, 0xC1B5, 0xC854, 0xC1B6, 0xC870, 0xC1B7, 0xC871, 0xC1B8, 0xC874, 0xC1B9, 0xC878, 0xC1BA, 0xC87A, 0xC1BB, 0xC880, 0xC1BC, 0xC881, 0xC1BD, 0xC883, 0xC1BE, 0xC885, 0xC1BF, 0xC886, 0xC1C0, 0xC887, 0xC1C1, 0xC88B, 0xC1C2, 0xC88C, 0xC1C3, 0xC88D, 0xC1C4, 0xC894, 0xC1C5, 0xC89D, 0xC1C6, 0xC89F, 0xC1C7, 0xC8A1, 0xC1C8, 0xC8A8, 0xC1C9, 0xC8BC, 0xC1CA, 0xC8BD, 0xC1CB, 0xC8C4, 0xC1CC, 0xC8C8, 0xC1CD, 0xC8CC, 0xC1CE, 0xC8D4, 0xC1CF, 0xC8D5, 0xC1D0, 0xC8D7, 0xC1D1, 0xC8D9, 0xC1D2, 0xC8E0, 0xC1D3, 0xC8E1, 0xC1D4, 0xC8E4, 0xC1D5, 0xC8F5, 0xC1D6, 0xC8FC, 0xC1D7, 0xC8FD, 0xC1D8, 0xC900, 0xC1D9, 0xC904, 0xC1DA, 0xC905, 0xC1DB, 0xC906, 0xC1DC, 0xC90C, 0xC1DD, 0xC90D, 0xC1DE, 0xC90F, 0xC1DF, 0xC911, 0xC1E0, 0xC918, 0xC1E1, 0xC92C, 0xC1E2, 0xC934, 0xC1E3, 0xC950, 0xC1E4, 0xC951, 0xC1E5, 0xC954, 0xC1E6, 0xC958, 0xC1E7, 0xC960, 0xC1E8, 0xC961, 0xC1E9, 0xC963, 0xC1EA, 0xC96C, 0xC1EB, 0xC970, 0xC1EC, 0xC974, 0xC1ED, 0xC97C, 0xC1EE, 0xC988, 0xC1EF, 0xC989, 0xC1F0, 0xC98C, 0xC1F1, 0xC990, 0xC1F2, 0xC998, 0xC1F3, 0xC999, 0xC1F4, 0xC99B, 0xC1F5, 0xC99D, 0xC1F6, 0xC9C0, 0xC1F7, 0xC9C1, 0xC1F8, 0xC9C4, 0xC1F9, 0xC9C7, 0xC1FA, 0xC9C8, 0xC1FB, 0xC9CA, 0xC1FC, 0xC9D0, 0xC1FD, 0xC9D1, 0xC1FE, 0xC9D3, 0xC241, 0xD5CA, 0xC242, 0xD5CB, 0xC243, 0xD5CD, 0xC244, 0xD5CE, 0xC245, 0xD5CF, 0xC246, 0xD5D1, 0xC247, 0xD5D3, 0xC248, 0xD5D4, 0xC249, 0xD5D5, 0xC24A, 0xD5D6, 0xC24B, 0xD5D7, 0xC24C, 0xD5DA, 0xC24D, 0xD5DC, 0xC24E, 0xD5DE, 0xC24F, 0xD5DF, 0xC250, 0xD5E0, 0xC251, 0xD5E1, 0xC252, 0xD5E2, 0xC253, 0xD5E3, 0xC254, 0xD5E6, 0xC255, 0xD5E7, 0xC256, 0xD5E9, 0xC257, 0xD5EA, 0xC258, 0xD5EB, 0xC259, 0xD5ED, 0xC25A, 0xD5EE, 0xC261, 0xD5EF, 0xC262, 0xD5F0, 0xC263, 0xD5F1, 0xC264, 0xD5F2, 0xC265, 0xD5F3, 0xC266, 0xD5F6, 0xC267, 0xD5F8, 0xC268, 0xD5FA, 0xC269, 0xD5FB, 0xC26A, 0xD5FC, 0xC26B, 0xD5FD, 0xC26C, 0xD5FE, 0xC26D, 0xD5FF, 0xC26E, 0xD602, 0xC26F, 0xD603, 0xC270, 0xD605, 0xC271, 0xD606, 0xC272, 0xD607, 0xC273, 0xD609, 0xC274, 0xD60A, 0xC275, 0xD60B, 0xC276, 0xD60C, 0xC277, 0xD60D, 0xC278, 0xD60E, 0xC279, 0xD60F, 0xC27A, 0xD612, 0xC281, 0xD616, 0xC282, 0xD617, 0xC283, 0xD618, 0xC284, 0xD619, 0xC285, 0xD61A, 0xC286, 0xD61B, 0xC287, 0xD61D, 0xC288, 0xD61E, 0xC289, 0xD61F, 0xC28A, 0xD621, 0xC28B, 0xD622, 0xC28C, 0xD623, 0xC28D, 0xD625, 0xC28E, 0xD626, 0xC28F, 0xD627, 0xC290, 0xD628, 0xC291, 0xD629, 0xC292, 0xD62A, 0xC293, 0xD62B, 0xC294, 0xD62C, 0xC295, 0xD62E, 0xC296, 0xD62F, 0xC297, 0xD630, 0xC298, 0xD631, 0xC299, 0xD632, 0xC29A, 0xD633, 0xC29B, 0xD634, 0xC29C, 0xD635, 0xC29D, 0xD636, 0xC29E, 0xD637, 0xC29F, 0xD63A, 0xC2A0, 0xD63B, 0xC2A1, 0xC9D5, 0xC2A2, 0xC9D6, 0xC2A3, 0xC9D9, 0xC2A4, 0xC9DA, 0xC2A5, 0xC9DC, 0xC2A6, 0xC9DD, 0xC2A7, 0xC9E0, 0xC2A8, 0xC9E2, 0xC2A9, 0xC9E4, 0xC2AA, 0xC9E7, 0xC2AB, 0xC9EC, 0xC2AC, 0xC9ED, 0xC2AD, 0xC9EF, 0xC2AE, 0xC9F0, 0xC2AF, 0xC9F1, 0xC2B0, 0xC9F8, 0xC2B1, 0xC9F9, 0xC2B2, 0xC9FC, 0xC2B3, 0xCA00, 0xC2B4, 0xCA08, 0xC2B5, 0xCA09, 0xC2B6, 0xCA0B, 0xC2B7, 0xCA0C, 0xC2B8, 0xCA0D, 0xC2B9, 0xCA14, 0xC2BA, 0xCA18, 0xC2BB, 0xCA29, 0xC2BC, 0xCA4C, 0xC2BD, 0xCA4D, 0xC2BE, 0xCA50, 0xC2BF, 0xCA54, 0xC2C0, 0xCA5C, 0xC2C1, 0xCA5D, 0xC2C2, 0xCA5F, 0xC2C3, 0xCA60, 0xC2C4, 0xCA61, 0xC2C5, 0xCA68, 0xC2C6, 0xCA7D, 0xC2C7, 0xCA84, 0xC2C8, 0xCA98, 0xC2C9, 0xCABC, 0xC2CA, 0xCABD, 0xC2CB, 0xCAC0, 0xC2CC, 0xCAC4, 0xC2CD, 0xCACC, 0xC2CE, 0xCACD, 0xC2CF, 0xCACF, 0xC2D0, 0xCAD1, 0xC2D1, 0xCAD3, 0xC2D2, 0xCAD8, 0xC2D3, 0xCAD9, 0xC2D4, 0xCAE0, 0xC2D5, 0xCAEC, 0xC2D6, 0xCAF4, 0xC2D7, 0xCB08, 0xC2D8, 0xCB10, 0xC2D9, 0xCB14, 0xC2DA, 0xCB18, 0xC2DB, 0xCB20, 0xC2DC, 0xCB21, 0xC2DD, 0xCB41, 0xC2DE, 0xCB48, 0xC2DF, 0xCB49, 0xC2E0, 0xCB4C, 0xC2E1, 0xCB50, 0xC2E2, 0xCB58, 0xC2E3, 0xCB59, 0xC2E4, 0xCB5D, 0xC2E5, 0xCB64, 0xC2E6, 0xCB78, 0xC2E7, 0xCB79, 0xC2E8, 0xCB9C, 0xC2E9, 0xCBB8, 0xC2EA, 0xCBD4, 0xC2EB, 0xCBE4, 0xC2EC, 0xCBE7, 0xC2ED, 0xCBE9, 0xC2EE, 0xCC0C, 0xC2EF, 0xCC0D, 0xC2F0, 0xCC10, 0xC2F1, 0xCC14, 0xC2F2, 0xCC1C, 0xC2F3, 0xCC1D, 0xC2F4, 0xCC21, 0xC2F5, 0xCC22, 0xC2F6, 0xCC27, 0xC2F7, 0xCC28, 0xC2F8, 0xCC29, 0xC2F9, 0xCC2C, 0xC2FA, 0xCC2E, 0xC2FB, 0xCC30, 0xC2FC, 0xCC38, 0xC2FD, 0xCC39, 0xC2FE, 0xCC3B, 0xC341, 0xD63D, 0xC342, 0xD63E, 0xC343, 0xD63F, 0xC344, 0xD641, 0xC345, 0xD642, 0xC346, 0xD643, 0xC347, 0xD644, 0xC348, 0xD646, 0xC349, 0xD647, 0xC34A, 0xD64A, 0xC34B, 0xD64C, 0xC34C, 0xD64E, 0xC34D, 0xD64F, 0xC34E, 0xD650, 0xC34F, 0xD652, 0xC350, 0xD653, 0xC351, 0xD656, 0xC352, 0xD657, 0xC353, 0xD659, 0xC354, 0xD65A, 0xC355, 0xD65B, 0xC356, 0xD65D, 0xC357, 0xD65E, 0xC358, 0xD65F, 0xC359, 0xD660, 0xC35A, 0xD661, 0xC361, 0xD662, 0xC362, 0xD663, 0xC363, 0xD664, 0xC364, 0xD665, 0xC365, 0xD666, 0xC366, 0xD668, 0xC367, 0xD66A, 0xC368, 0xD66B, 0xC369, 0xD66C, 0xC36A, 0xD66D, 0xC36B, 0xD66E, 0xC36C, 0xD66F, 0xC36D, 0xD672, 0xC36E, 0xD673, 0xC36F, 0xD675, 0xC370, 0xD676, 0xC371, 0xD677, 0xC372, 0xD678, 0xC373, 0xD679, 0xC374, 0xD67A, 0xC375, 0xD67B, 0xC376, 0xD67C, 0xC377, 0xD67D, 0xC378, 0xD67E, 0xC379, 0xD67F, 0xC37A, 0xD680, 0xC381, 0xD681, 0xC382, 0xD682, 0xC383, 0xD684, 0xC384, 0xD686, 0xC385, 0xD687, 0xC386, 0xD688, 0xC387, 0xD689, 0xC388, 0xD68A, 0xC389, 0xD68B, 0xC38A, 0xD68E, 0xC38B, 0xD68F, 0xC38C, 0xD691, 0xC38D, 0xD692, 0xC38E, 0xD693, 0xC38F, 0xD695, 0xC390, 0xD696, 0xC391, 0xD697, 0xC392, 0xD698, 0xC393, 0xD699, 0xC394, 0xD69A, 0xC395, 0xD69B, 0xC396, 0xD69C, 0xC397, 0xD69E, 0xC398, 0xD6A0, 0xC399, 0xD6A2, 0xC39A, 0xD6A3, 0xC39B, 0xD6A4, 0xC39C, 0xD6A5, 0xC39D, 0xD6A6, 0xC39E, 0xD6A7, 0xC39F, 0xD6A9, 0xC3A0, 0xD6AA, 0xC3A1, 0xCC3C, 0xC3A2, 0xCC3D, 0xC3A3, 0xCC3E, 0xC3A4, 0xCC44, 0xC3A5, 0xCC45, 0xC3A6, 0xCC48, 0xC3A7, 0xCC4C, 0xC3A8, 0xCC54, 0xC3A9, 0xCC55, 0xC3AA, 0xCC57, 0xC3AB, 0xCC58, 0xC3AC, 0xCC59, 0xC3AD, 0xCC60, 0xC3AE, 0xCC64, 0xC3AF, 0xCC66, 0xC3B0, 0xCC68, 0xC3B1, 0xCC70, 0xC3B2, 0xCC75, 0xC3B3, 0xCC98, 0xC3B4, 0xCC99, 0xC3B5, 0xCC9C, 0xC3B6, 0xCCA0, 0xC3B7, 0xCCA8, 0xC3B8, 0xCCA9, 0xC3B9, 0xCCAB, 0xC3BA, 0xCCAC, 0xC3BB, 0xCCAD, 0xC3BC, 0xCCB4, 0xC3BD, 0xCCB5, 0xC3BE, 0xCCB8, 0xC3BF, 0xCCBC, 0xC3C0, 0xCCC4, 0xC3C1, 0xCCC5, 0xC3C2, 0xCCC7, 0xC3C3, 0xCCC9, 0xC3C4, 0xCCD0, 0xC3C5, 0xCCD4, 0xC3C6, 0xCCE4, 0xC3C7, 0xCCEC, 0xC3C8, 0xCCF0, 0xC3C9, 0xCD01, 0xC3CA, 0xCD08, 0xC3CB, 0xCD09, 0xC3CC, 0xCD0C, 0xC3CD, 0xCD10, 0xC3CE, 0xCD18, 0xC3CF, 0xCD19, 0xC3D0, 0xCD1B, 0xC3D1, 0xCD1D, 0xC3D2, 0xCD24, 0xC3D3, 0xCD28, 0xC3D4, 0xCD2C, 0xC3D5, 0xCD39, 0xC3D6, 0xCD5C, 0xC3D7, 0xCD60, 0xC3D8, 0xCD64, 0xC3D9, 0xCD6C, 0xC3DA, 0xCD6D, 0xC3DB, 0xCD6F, 0xC3DC, 0xCD71, 0xC3DD, 0xCD78, 0xC3DE, 0xCD88, 0xC3DF, 0xCD94, 0xC3E0, 0xCD95, 0xC3E1, 0xCD98, 0xC3E2, 0xCD9C, 0xC3E3, 0xCDA4, 0xC3E4, 0xCDA5, 0xC3E5, 0xCDA7, 0xC3E6, 0xCDA9, 0xC3E7, 0xCDB0, 0xC3E8, 0xCDC4, 0xC3E9, 0xCDCC, 0xC3EA, 0xCDD0, 0xC3EB, 0xCDE8, 0xC3EC, 0xCDEC, 0xC3ED, 0xCDF0, 0xC3EE, 0xCDF8, 0xC3EF, 0xCDF9, 0xC3F0, 0xCDFB, 0xC3F1, 0xCDFD, 0xC3F2, 0xCE04, 0xC3F3, 0xCE08, 0xC3F4, 0xCE0C, 0xC3F5, 0xCE14, 0xC3F6, 0xCE19, 0xC3F7, 0xCE20, 0xC3F8, 0xCE21, 0xC3F9, 0xCE24, 0xC3FA, 0xCE28, 0xC3FB, 0xCE30, 0xC3FC, 0xCE31, 0xC3FD, 0xCE33, 0xC3FE, 0xCE35, 0xC441, 0xD6AB, 0xC442, 0xD6AD, 0xC443, 0xD6AE, 0xC444, 0xD6AF, 0xC445, 0xD6B1, 0xC446, 0xD6B2, 0xC447, 0xD6B3, 0xC448, 0xD6B4, 0xC449, 0xD6B5, 0xC44A, 0xD6B6, 0xC44B, 0xD6B7, 0xC44C, 0xD6B8, 0xC44D, 0xD6BA, 0xC44E, 0xD6BC, 0xC44F, 0xD6BD, 0xC450, 0xD6BE, 0xC451, 0xD6BF, 0xC452, 0xD6C0, 0xC453, 0xD6C1, 0xC454, 0xD6C2, 0xC455, 0xD6C3, 0xC456, 0xD6C6, 0xC457, 0xD6C7, 0xC458, 0xD6C9, 0xC459, 0xD6CA, 0xC45A, 0xD6CB, 0xC461, 0xD6CD, 0xC462, 0xD6CE, 0xC463, 0xD6CF, 0xC464, 0xD6D0, 0xC465, 0xD6D2, 0xC466, 0xD6D3, 0xC467, 0xD6D5, 0xC468, 0xD6D6, 0xC469, 0xD6D8, 0xC46A, 0xD6DA, 0xC46B, 0xD6DB, 0xC46C, 0xD6DC, 0xC46D, 0xD6DD, 0xC46E, 0xD6DE, 0xC46F, 0xD6DF, 0xC470, 0xD6E1, 0xC471, 0xD6E2, 0xC472, 0xD6E3, 0xC473, 0xD6E5, 0xC474, 0xD6E6, 0xC475, 0xD6E7, 0xC476, 0xD6E9, 0xC477, 0xD6EA, 0xC478, 0xD6EB, 0xC479, 0xD6EC, 0xC47A, 0xD6ED, 0xC481, 0xD6EE, 0xC482, 0xD6EF, 0xC483, 0xD6F1, 0xC484, 0xD6F2, 0xC485, 0xD6F3, 0xC486, 0xD6F4, 0xC487, 0xD6F6, 0xC488, 0xD6F7, 0xC489, 0xD6F8, 0xC48A, 0xD6F9, 0xC48B, 0xD6FA, 0xC48C, 0xD6FB, 0xC48D, 0xD6FE, 0xC48E, 0xD6FF, 0xC48F, 0xD701, 0xC490, 0xD702, 0xC491, 0xD703, 0xC492, 0xD705, 0xC493, 0xD706, 0xC494, 0xD707, 0xC495, 0xD708, 0xC496, 0xD709, 0xC497, 0xD70A, 0xC498, 0xD70B, 0xC499, 0xD70C, 0xC49A, 0xD70D, 0xC49B, 0xD70E, 0xC49C, 0xD70F, 0xC49D, 0xD710, 0xC49E, 0xD712, 0xC49F, 0xD713, 0xC4A0, 0xD714, 0xC4A1, 0xCE58, 0xC4A2, 0xCE59, 0xC4A3, 0xCE5C, 0xC4A4, 0xCE5F, 0xC4A5, 0xCE60, 0xC4A6, 0xCE61, 0xC4A7, 0xCE68, 0xC4A8, 0xCE69, 0xC4A9, 0xCE6B, 0xC4AA, 0xCE6D, 0xC4AB, 0xCE74, 0xC4AC, 0xCE75, 0xC4AD, 0xCE78, 0xC4AE, 0xCE7C, 0xC4AF, 0xCE84, 0xC4B0, 0xCE85, 0xC4B1, 0xCE87, 0xC4B2, 0xCE89, 0xC4B3, 0xCE90, 0xC4B4, 0xCE91, 0xC4B5, 0xCE94, 0xC4B6, 0xCE98, 0xC4B7, 0xCEA0, 0xC4B8, 0xCEA1, 0xC4B9, 0xCEA3, 0xC4BA, 0xCEA4, 0xC4BB, 0xCEA5, 0xC4BC, 0xCEAC, 0xC4BD, 0xCEAD, 0xC4BE, 0xCEC1, 0xC4BF, 0xCEE4, 0xC4C0, 0xCEE5, 0xC4C1, 0xCEE8, 0xC4C2, 0xCEEB, 0xC4C3, 0xCEEC, 0xC4C4, 0xCEF4, 0xC4C5, 0xCEF5, 0xC4C6, 0xCEF7, 0xC4C7, 0xCEF8, 0xC4C8, 0xCEF9, 0xC4C9, 0xCF00, 0xC4CA, 0xCF01, 0xC4CB, 0xCF04, 0xC4CC, 0xCF08, 0xC4CD, 0xCF10, 0xC4CE, 0xCF11, 0xC4CF, 0xCF13, 0xC4D0, 0xCF15, 0xC4D1, 0xCF1C, 0xC4D2, 0xCF20, 0xC4D3, 0xCF24, 0xC4D4, 0xCF2C, 0xC4D5, 0xCF2D, 0xC4D6, 0xCF2F, 0xC4D7, 0xCF30, 0xC4D8, 0xCF31, 0xC4D9, 0xCF38, 0xC4DA, 0xCF54, 0xC4DB, 0xCF55, 0xC4DC, 0xCF58, 0xC4DD, 0xCF5C, 0xC4DE, 0xCF64, 0xC4DF, 0xCF65, 0xC4E0, 0xCF67, 0xC4E1, 0xCF69, 0xC4E2, 0xCF70, 0xC4E3, 0xCF71, 0xC4E4, 0xCF74, 0xC4E5, 0xCF78, 0xC4E6, 0xCF80, 0xC4E7, 0xCF85, 0xC4E8, 0xCF8C, 0xC4E9, 0xCFA1, 0xC4EA, 0xCFA8, 0xC4EB, 0xCFB0, 0xC4EC, 0xCFC4, 0xC4ED, 0xCFE0, 0xC4EE, 0xCFE1, 0xC4EF, 0xCFE4, 0xC4F0, 0xCFE8, 0xC4F1, 0xCFF0, 0xC4F2, 0xCFF1, 0xC4F3, 0xCFF3, 0xC4F4, 0xCFF5, 0xC4F5, 0xCFFC, 0xC4F6, 0xD000, 0xC4F7, 0xD004, 0xC4F8, 0xD011, 0xC4F9, 0xD018, 0xC4FA, 0xD02D, 0xC4FB, 0xD034, 0xC4FC, 0xD035, 0xC4FD, 0xD038, 0xC4FE, 0xD03C, 0xC541, 0xD715, 0xC542, 0xD716, 0xC543, 0xD717, 0xC544, 0xD71A, 0xC545, 0xD71B, 0xC546, 0xD71D, 0xC547, 0xD71E, 0xC548, 0xD71F, 0xC549, 0xD721, 0xC54A, 0xD722, 0xC54B, 0xD723, 0xC54C, 0xD724, 0xC54D, 0xD725, 0xC54E, 0xD726, 0xC54F, 0xD727, 0xC550, 0xD72A, 0xC551, 0xD72C, 0xC552, 0xD72E, 0xC553, 0xD72F, 0xC554, 0xD730, 0xC555, 0xD731, 0xC556, 0xD732, 0xC557, 0xD733, 0xC558, 0xD736, 0xC559, 0xD737, 0xC55A, 0xD739, 0xC561, 0xD73A, 0xC562, 0xD73B, 0xC563, 0xD73D, 0xC564, 0xD73E, 0xC565, 0xD73F, 0xC566, 0xD740, 0xC567, 0xD741, 0xC568, 0xD742, 0xC569, 0xD743, 0xC56A, 0xD745, 0xC56B, 0xD746, 0xC56C, 0xD748, 0xC56D, 0xD74A, 0xC56E, 0xD74B, 0xC56F, 0xD74C, 0xC570, 0xD74D, 0xC571, 0xD74E, 0xC572, 0xD74F, 0xC573, 0xD752, 0xC574, 0xD753, 0xC575, 0xD755, 0xC576, 0xD75A, 0xC577, 0xD75B, 0xC578, 0xD75C, 0xC579, 0xD75D, 0xC57A, 0xD75E, 0xC581, 0xD75F, 0xC582, 0xD762, 0xC583, 0xD764, 0xC584, 0xD766, 0xC585, 0xD767, 0xC586, 0xD768, 0xC587, 0xD76A, 0xC588, 0xD76B, 0xC589, 0xD76D, 0xC58A, 0xD76E, 0xC58B, 0xD76F, 0xC58C, 0xD771, 0xC58D, 0xD772, 0xC58E, 0xD773, 0xC58F, 0xD775, 0xC590, 0xD776, 0xC591, 0xD777, 0xC592, 0xD778, 0xC593, 0xD779, 0xC594, 0xD77A, 0xC595, 0xD77B, 0xC596, 0xD77E, 0xC597, 0xD77F, 0xC598, 0xD780, 0xC599, 0xD782, 0xC59A, 0xD783, 0xC59B, 0xD784, 0xC59C, 0xD785, 0xC59D, 0xD786, 0xC59E, 0xD787, 0xC59F, 0xD78A, 0xC5A0, 0xD78B, 0xC5A1, 0xD044, 0xC5A2, 0xD045, 0xC5A3, 0xD047, 0xC5A4, 0xD049, 0xC5A5, 0xD050, 0xC5A6, 0xD054, 0xC5A7, 0xD058, 0xC5A8, 0xD060, 0xC5A9, 0xD06C, 0xC5AA, 0xD06D, 0xC5AB, 0xD070, 0xC5AC, 0xD074, 0xC5AD, 0xD07C, 0xC5AE, 0xD07D, 0xC5AF, 0xD081, 0xC5B0, 0xD0A4, 0xC5B1, 0xD0A5, 0xC5B2, 0xD0A8, 0xC5B3, 0xD0AC, 0xC5B4, 0xD0B4, 0xC5B5, 0xD0B5, 0xC5B6, 0xD0B7, 0xC5B7, 0xD0B9, 0xC5B8, 0xD0C0, 0xC5B9, 0xD0C1, 0xC5BA, 0xD0C4, 0xC5BB, 0xD0C8, 0xC5BC, 0xD0C9, 0xC5BD, 0xD0D0, 0xC5BE, 0xD0D1, 0xC5BF, 0xD0D3, 0xC5C0, 0xD0D4, 0xC5C1, 0xD0D5, 0xC5C2, 0xD0DC, 0xC5C3, 0xD0DD, 0xC5C4, 0xD0E0, 0xC5C5, 0xD0E4, 0xC5C6, 0xD0EC, 0xC5C7, 0xD0ED, 0xC5C8, 0xD0EF, 0xC5C9, 0xD0F0, 0xC5CA, 0xD0F1, 0xC5CB, 0xD0F8, 0xC5CC, 0xD10D, 0xC5CD, 0xD130, 0xC5CE, 0xD131, 0xC5CF, 0xD134, 0xC5D0, 0xD138, 0xC5D1, 0xD13A, 0xC5D2, 0xD140, 0xC5D3, 0xD141, 0xC5D4, 0xD143, 0xC5D5, 0xD144, 0xC5D6, 0xD145, 0xC5D7, 0xD14C, 0xC5D8, 0xD14D, 0xC5D9, 0xD150, 0xC5DA, 0xD154, 0xC5DB, 0xD15C, 0xC5DC, 0xD15D, 0xC5DD, 0xD15F, 0xC5DE, 0xD161, 0xC5DF, 0xD168, 0xC5E0, 0xD16C, 0xC5E1, 0xD17C, 0xC5E2, 0xD184, 0xC5E3, 0xD188, 0xC5E4, 0xD1A0, 0xC5E5, 0xD1A1, 0xC5E6, 0xD1A4, 0xC5E7, 0xD1A8, 0xC5E8, 0xD1B0, 0xC5E9, 0xD1B1, 0xC5EA, 0xD1B3, 0xC5EB, 0xD1B5, 0xC5EC, 0xD1BA, 0xC5ED, 0xD1BC, 0xC5EE, 0xD1C0, 0xC5EF, 0xD1D8, 0xC5F0, 0xD1F4, 0xC5F1, 0xD1F8, 0xC5F2, 0xD207, 0xC5F3, 0xD209, 0xC5F4, 0xD210, 0xC5F5, 0xD22C, 0xC5F6, 0xD22D, 0xC5F7, 0xD230, 0xC5F8, 0xD234, 0xC5F9, 0xD23C, 0xC5FA, 0xD23D, 0xC5FB, 0xD23F, 0xC5FC, 0xD241, 0xC5FD, 0xD248, 0xC5FE, 0xD25C, 0xC641, 0xD78D, 0xC642, 0xD78E, 0xC643, 0xD78F, 0xC644, 0xD791, 0xC645, 0xD792, 0xC646, 0xD793, 0xC647, 0xD794, 0xC648, 0xD795, 0xC649, 0xD796, 0xC64A, 0xD797, 0xC64B, 0xD79A, 0xC64C, 0xD79C, 0xC64D, 0xD79E, 0xC64E, 0xD79F, 0xC64F, 0xD7A0, 0xC650, 0xD7A1, 0xC651, 0xD7A2, 0xC652, 0xD7A3, 0xC6A1, 0xD264, 0xC6A2, 0xD280, 0xC6A3, 0xD281, 0xC6A4, 0xD284, 0xC6A5, 0xD288, 0xC6A6, 0xD290, 0xC6A7, 0xD291, 0xC6A8, 0xD295, 0xC6A9, 0xD29C, 0xC6AA, 0xD2A0, 0xC6AB, 0xD2A4, 0xC6AC, 0xD2AC, 0xC6AD, 0xD2B1, 0xC6AE, 0xD2B8, 0xC6AF, 0xD2B9, 0xC6B0, 0xD2BC, 0xC6B1, 0xD2BF, 0xC6B2, 0xD2C0, 0xC6B3, 0xD2C2, 0xC6B4, 0xD2C8, 0xC6B5, 0xD2C9, 0xC6B6, 0xD2CB, 0xC6B7, 0xD2D4, 0xC6B8, 0xD2D8, 0xC6B9, 0xD2DC, 0xC6BA, 0xD2E4, 0xC6BB, 0xD2E5, 0xC6BC, 0xD2F0, 0xC6BD, 0xD2F1, 0xC6BE, 0xD2F4, 0xC6BF, 0xD2F8, 0xC6C0, 0xD300, 0xC6C1, 0xD301, 0xC6C2, 0xD303, 0xC6C3, 0xD305, 0xC6C4, 0xD30C, 0xC6C5, 0xD30D, 0xC6C6, 0xD30E, 0xC6C7, 0xD310, 0xC6C8, 0xD314, 0xC6C9, 0xD316, 0xC6CA, 0xD31C, 0xC6CB, 0xD31D, 0xC6CC, 0xD31F, 0xC6CD, 0xD320, 0xC6CE, 0xD321, 0xC6CF, 0xD325, 0xC6D0, 0xD328, 0xC6D1, 0xD329, 0xC6D2, 0xD32C, 0xC6D3, 0xD330, 0xC6D4, 0xD338, 0xC6D5, 0xD339, 0xC6D6, 0xD33B, 0xC6D7, 0xD33C, 0xC6D8, 0xD33D, 0xC6D9, 0xD344, 0xC6DA, 0xD345, 0xC6DB, 0xD37C, 0xC6DC, 0xD37D, 0xC6DD, 0xD380, 0xC6DE, 0xD384, 0xC6DF, 0xD38C, 0xC6E0, 0xD38D, 0xC6E1, 0xD38F, 0xC6E2, 0xD390, 0xC6E3, 0xD391, 0xC6E4, 0xD398, 0xC6E5, 0xD399, 0xC6E6, 0xD39C, 0xC6E7, 0xD3A0, 0xC6E8, 0xD3A8, 0xC6E9, 0xD3A9, 0xC6EA, 0xD3AB, 0xC6EB, 0xD3AD, 0xC6EC, 0xD3B4, 0xC6ED, 0xD3B8, 0xC6EE, 0xD3BC, 0xC6EF, 0xD3C4, 0xC6F0, 0xD3C5, 0xC6F1, 0xD3C8, 0xC6F2, 0xD3C9, 0xC6F3, 0xD3D0, 0xC6F4, 0xD3D8, 0xC6F5, 0xD3E1, 0xC6F6, 0xD3E3, 0xC6F7, 0xD3EC, 0xC6F8, 0xD3ED, 0xC6F9, 0xD3F0, 0xC6FA, 0xD3F4, 0xC6FB, 0xD3FC, 0xC6FC, 0xD3FD, 0xC6FD, 0xD3FF, 0xC6FE, 0xD401, 0xC7A1, 0xD408, 0xC7A2, 0xD41D, 0xC7A3, 0xD440, 0xC7A4, 0xD444, 0xC7A5, 0xD45C, 0xC7A6, 0xD460, 0xC7A7, 0xD464, 0xC7A8, 0xD46D, 0xC7A9, 0xD46F, 0xC7AA, 0xD478, 0xC7AB, 0xD479, 0xC7AC, 0xD47C, 0xC7AD, 0xD47F, 0xC7AE, 0xD480, 0xC7AF, 0xD482, 0xC7B0, 0xD488, 0xC7B1, 0xD489, 0xC7B2, 0xD48B, 0xC7B3, 0xD48D, 0xC7B4, 0xD494, 0xC7B5, 0xD4A9, 0xC7B6, 0xD4CC, 0xC7B7, 0xD4D0, 0xC7B8, 0xD4D4, 0xC7B9, 0xD4DC, 0xC7BA, 0xD4DF, 0xC7BB, 0xD4E8, 0xC7BC, 0xD4EC, 0xC7BD, 0xD4F0, 0xC7BE, 0xD4F8, 0xC7BF, 0xD4FB, 0xC7C0, 0xD4FD, 0xC7C1, 0xD504, 0xC7C2, 0xD508, 0xC7C3, 0xD50C, 0xC7C4, 0xD514, 0xC7C5, 0xD515, 0xC7C6, 0xD517, 0xC7C7, 0xD53C, 0xC7C8, 0xD53D, 0xC7C9, 0xD540, 0xC7CA, 0xD544, 0xC7CB, 0xD54C, 0xC7CC, 0xD54D, 0xC7CD, 0xD54F, 0xC7CE, 0xD551, 0xC7CF, 0xD558, 0xC7D0, 0xD559, 0xC7D1, 0xD55C, 0xC7D2, 0xD560, 0xC7D3, 0xD565, 0xC7D4, 0xD568, 0xC7D5, 0xD569, 0xC7D6, 0xD56B, 0xC7D7, 0xD56D, 0xC7D8, 0xD574, 0xC7D9, 0xD575, 0xC7DA, 0xD578, 0xC7DB, 0xD57C, 0xC7DC, 0xD584, 0xC7DD, 0xD585, 0xC7DE, 0xD587, 0xC7DF, 0xD588, 0xC7E0, 0xD589, 0xC7E1, 0xD590, 0xC7E2, 0xD5A5, 0xC7E3, 0xD5C8, 0xC7E4, 0xD5C9, 0xC7E5, 0xD5CC, 0xC7E6, 0xD5D0, 0xC7E7, 0xD5D2, 0xC7E8, 0xD5D8, 0xC7E9, 0xD5D9, 0xC7EA, 0xD5DB, 0xC7EB, 0xD5DD, 0xC7EC, 0xD5E4, 0xC7ED, 0xD5E5, 0xC7EE, 0xD5E8, 0xC7EF, 0xD5EC, 0xC7F0, 0xD5F4, 0xC7F1, 0xD5F5, 0xC7F2, 0xD5F7, 0xC7F3, 0xD5F9, 0xC7F4, 0xD600, 0xC7F5, 0xD601, 0xC7F6, 0xD604, 0xC7F7, 0xD608, 0xC7F8, 0xD610, 0xC7F9, 0xD611, 0xC7FA, 0xD613, 0xC7FB, 0xD614, 0xC7FC, 0xD615, 0xC7FD, 0xD61C, 0xC7FE, 0xD620, 0xC8A1, 0xD624, 0xC8A2, 0xD62D, 0xC8A3, 0xD638, 0xC8A4, 0xD639, 0xC8A5, 0xD63C, 0xC8A6, 0xD640, 0xC8A7, 0xD645, 0xC8A8, 0xD648, 0xC8A9, 0xD649, 0xC8AA, 0xD64B, 0xC8AB, 0xD64D, 0xC8AC, 0xD651, 0xC8AD, 0xD654, 0xC8AE, 0xD655, 0xC8AF, 0xD658, 0xC8B0, 0xD65C, 0xC8B1, 0xD667, 0xC8B2, 0xD669, 0xC8B3, 0xD670, 0xC8B4, 0xD671, 0xC8B5, 0xD674, 0xC8B6, 0xD683, 0xC8B7, 0xD685, 0xC8B8, 0xD68C, 0xC8B9, 0xD68D, 0xC8BA, 0xD690, 0xC8BB, 0xD694, 0xC8BC, 0xD69D, 0xC8BD, 0xD69F, 0xC8BE, 0xD6A1, 0xC8BF, 0xD6A8, 0xC8C0, 0xD6AC, 0xC8C1, 0xD6B0, 0xC8C2, 0xD6B9, 0xC8C3, 0xD6BB, 0xC8C4, 0xD6C4, 0xC8C5, 0xD6C5, 0xC8C6, 0xD6C8, 0xC8C7, 0xD6CC, 0xC8C8, 0xD6D1, 0xC8C9, 0xD6D4, 0xC8CA, 0xD6D7, 0xC8CB, 0xD6D9, 0xC8CC, 0xD6E0, 0xC8CD, 0xD6E4, 0xC8CE, 0xD6E8, 0xC8CF, 0xD6F0, 0xC8D0, 0xD6F5, 0xC8D1, 0xD6FC, 0xC8D2, 0xD6FD, 0xC8D3, 0xD700, 0xC8D4, 0xD704, 0xC8D5, 0xD711, 0xC8D6, 0xD718, 0xC8D7, 0xD719, 0xC8D8, 0xD71C, 0xC8D9, 0xD720, 0xC8DA, 0xD728, 0xC8DB, 0xD729, 0xC8DC, 0xD72B, 0xC8DD, 0xD72D, 0xC8DE, 0xD734, 0xC8DF, 0xD735, 0xC8E0, 0xD738, 0xC8E1, 0xD73C, 0xC8E2, 0xD744, 0xC8E3, 0xD747, 0xC8E4, 0xD749, 0xC8E5, 0xD750, 0xC8E6, 0xD751, 0xC8E7, 0xD754, 0xC8E8, 0xD756, 0xC8E9, 0xD757, 0xC8EA, 0xD758, 0xC8EB, 0xD759, 0xC8EC, 0xD760, 0xC8ED, 0xD761, 0xC8EE, 0xD763, 0xC8EF, 0xD765, 0xC8F0, 0xD769, 0xC8F1, 0xD76C, 0xC8F2, 0xD770, 0xC8F3, 0xD774, 0xC8F4, 0xD77C, 0xC8F5, 0xD77D, 0xC8F6, 0xD781, 0xC8F7, 0xD788, 0xC8F8, 0xD789, 0xC8F9, 0xD78C, 0xC8FA, 0xD790, 0xC8FB, 0xD798, 0xC8FC, 0xD799, 0xC8FD, 0xD79B, 0xC8FE, 0xD79D, 0xCAA1, 0x4F3D, 0xCAA2, 0x4F73, 0xCAA3, 0x5047, 0xCAA4, 0x50F9, 0xCAA5, 0x52A0, 0xCAA6, 0x53EF, 0xCAA7, 0x5475, 0xCAA8, 0x54E5, 0xCAA9, 0x5609, 0xCAAA, 0x5AC1, 0xCAAB, 0x5BB6, 0xCAAC, 0x6687, 0xCAAD, 0x67B6, 0xCAAE, 0x67B7, 0xCAAF, 0x67EF, 0xCAB0, 0x6B4C, 0xCAB1, 0x73C2, 0xCAB2, 0x75C2, 0xCAB3, 0x7A3C, 0xCAB4, 0x82DB, 0xCAB5, 0x8304, 0xCAB6, 0x8857, 0xCAB7, 0x8888, 0xCAB8, 0x8A36, 0xCAB9, 0x8CC8, 0xCABA, 0x8DCF, 0xCABB, 0x8EFB, 0xCABC, 0x8FE6, 0xCABD, 0x99D5, 0xCABE, 0x523B, 0xCABF, 0x5374, 0xCAC0, 0x5404, 0xCAC1, 0x606A, 0xCAC2, 0x6164, 0xCAC3, 0x6BBC, 0xCAC4, 0x73CF, 0xCAC5, 0x811A, 0xCAC6, 0x89BA, 0xCAC7, 0x89D2, 0xCAC8, 0x95A3, 0xCAC9, 0x4F83, 0xCACA, 0x520A, 0xCACB, 0x58BE, 0xCACC, 0x5978, 0xCACD, 0x59E6, 0xCACE, 0x5E72, 0xCACF, 0x5E79, 0xCAD0, 0x61C7, 0xCAD1, 0x63C0, 0xCAD2, 0x6746, 0xCAD3, 0x67EC, 0xCAD4, 0x687F, 0xCAD5, 0x6F97, 0xCAD6, 0x764E, 0xCAD7, 0x770B, 0xCAD8, 0x78F5, 0xCAD9, 0x7A08, 0xCADA, 0x7AFF, 0xCADB, 0x7C21, 0xCADC, 0x809D, 0xCADD, 0x826E, 0xCADE, 0x8271, 0xCADF, 0x8AEB, 0xCAE0, 0x9593, 0xCAE1, 0x4E6B, 0xCAE2, 0x559D, 0xCAE3, 0x66F7, 0xCAE4, 0x6E34, 0xCAE5, 0x78A3, 0xCAE6, 0x7AED, 0xCAE7, 0x845B, 0xCAE8, 0x8910, 0xCAE9, 0x874E, 0xCAEA, 0x97A8, 0xCAEB, 0x52D8, 0xCAEC, 0x574E, 0xCAED, 0x582A, 0xCAEE, 0x5D4C, 0xCAEF, 0x611F, 0xCAF0, 0x61BE, 0xCAF1, 0x6221, 0xCAF2, 0x6562, 0xCAF3, 0x67D1, 0xCAF4, 0x6A44, 0xCAF5, 0x6E1B, 0xCAF6, 0x7518, 0xCAF7, 0x75B3, 0xCAF8, 0x76E3, 0xCAF9, 0x77B0, 0xCAFA, 0x7D3A, 0xCAFB, 0x90AF, 0xCAFC, 0x9451, 0xCAFD, 0x9452, 0xCAFE, 0x9F95, 0xCBA1, 0x5323, 0xCBA2, 0x5CAC, 0xCBA3, 0x7532, 0xCBA4, 0x80DB, 0xCBA5, 0x9240, 0xCBA6, 0x9598, 0xCBA7, 0x525B, 0xCBA8, 0x5808, 0xCBA9, 0x59DC, 0xCBAA, 0x5CA1, 0xCBAB, 0x5D17, 0xCBAC, 0x5EB7, 0xCBAD, 0x5F3A, 0xCBAE, 0x5F4A, 0xCBAF, 0x6177, 0xCBB0, 0x6C5F, 0xCBB1, 0x757A, 0xCBB2, 0x7586, 0xCBB3, 0x7CE0, 0xCBB4, 0x7D73, 0xCBB5, 0x7DB1, 0xCBB6, 0x7F8C, 0xCBB7, 0x8154, 0xCBB8, 0x8221, 0xCBB9, 0x8591, 0xCBBA, 0x8941, 0xCBBB, 0x8B1B, 0xCBBC, 0x92FC, 0xCBBD, 0x964D, 0xCBBE, 0x9C47, 0xCBBF, 0x4ECB, 0xCBC0, 0x4EF7, 0xCBC1, 0x500B, 0xCBC2, 0x51F1, 0xCBC3, 0x584F, 0xCBC4, 0x6137, 0xCBC5, 0x613E, 0xCBC6, 0x6168, 0xCBC7, 0x6539, 0xCBC8, 0x69EA, 0xCBC9, 0x6F11, 0xCBCA, 0x75A5, 0xCBCB, 0x7686, 0xCBCC, 0x76D6, 0xCBCD, 0x7B87, 0xCBCE, 0x82A5, 0xCBCF, 0x84CB, 0xCBD0, 0xF900, 0xCBD1, 0x93A7, 0xCBD2, 0x958B, 0xCBD3, 0x5580, 0xCBD4, 0x5BA2, 0xCBD5, 0x5751, 0xCBD6, 0xF901, 0xCBD7, 0x7CB3, 0xCBD8, 0x7FB9, 0xCBD9, 0x91B5, 0xCBDA, 0x5028, 0xCBDB, 0x53BB, 0xCBDC, 0x5C45, 0xCBDD, 0x5DE8, 0xCBDE, 0x62D2, 0xCBDF, 0x636E, 0xCBE0, 0x64DA, 0xCBE1, 0x64E7, 0xCBE2, 0x6E20, 0xCBE3, 0x70AC, 0xCBE4, 0x795B, 0xCBE5, 0x8DDD, 0xCBE6, 0x8E1E, 0xCBE7, 0xF902, 0xCBE8, 0x907D, 0xCBE9, 0x9245, 0xCBEA, 0x92F8, 0xCBEB, 0x4E7E, 0xCBEC, 0x4EF6, 0xCBED, 0x5065, 0xCBEE, 0x5DFE, 0xCBEF, 0x5EFA, 0xCBF0, 0x6106, 0xCBF1, 0x6957, 0xCBF2, 0x8171, 0xCBF3, 0x8654, 0xCBF4, 0x8E47, 0xCBF5, 0x9375, 0xCBF6, 0x9A2B, 0xCBF7, 0x4E5E, 0xCBF8, 0x5091, 0xCBF9, 0x6770, 0xCBFA, 0x6840, 0xCBFB, 0x5109, 0xCBFC, 0x528D, 0xCBFD, 0x5292, 0xCBFE, 0x6AA2, 0xCCA1, 0x77BC, 0xCCA2, 0x9210, 0xCCA3, 0x9ED4, 0xCCA4, 0x52AB, 0xCCA5, 0x602F, 0xCCA6, 0x8FF2, 0xCCA7, 0x5048, 0xCCA8, 0x61A9, 0xCCA9, 0x63ED, 0xCCAA, 0x64CA, 0xCCAB, 0x683C, 0xCCAC, 0x6A84, 0xCCAD, 0x6FC0, 0xCCAE, 0x8188, 0xCCAF, 0x89A1, 0xCCB0, 0x9694, 0xCCB1, 0x5805, 0xCCB2, 0x727D, 0xCCB3, 0x72AC, 0xCCB4, 0x7504, 0xCCB5, 0x7D79, 0xCCB6, 0x7E6D, 0xCCB7, 0x80A9, 0xCCB8, 0x898B, 0xCCB9, 0x8B74, 0xCCBA, 0x9063, 0xCCBB, 0x9D51, 0xCCBC, 0x6289, 0xCCBD, 0x6C7A, 0xCCBE, 0x6F54, 0xCCBF, 0x7D50, 0xCCC0, 0x7F3A, 0xCCC1, 0x8A23, 0xCCC2, 0x517C, 0xCCC3, 0x614A, 0xCCC4, 0x7B9D, 0xCCC5, 0x8B19, 0xCCC6, 0x9257, 0xCCC7, 0x938C, 0xCCC8, 0x4EAC, 0xCCC9, 0x4FD3, 0xCCCA, 0x501E, 0xCCCB, 0x50BE, 0xCCCC, 0x5106, 0xCCCD, 0x52C1, 0xCCCE, 0x52CD, 0xCCCF, 0x537F, 0xCCD0, 0x5770, 0xCCD1, 0x5883, 0xCCD2, 0x5E9A, 0xCCD3, 0x5F91, 0xCCD4, 0x6176, 0xCCD5, 0x61AC, 0xCCD6, 0x64CE, 0xCCD7, 0x656C, 0xCCD8, 0x666F, 0xCCD9, 0x66BB, 0xCCDA, 0x66F4, 0xCCDB, 0x6897, 0xCCDC, 0x6D87, 0xCCDD, 0x7085, 0xCCDE, 0x70F1, 0xCCDF, 0x749F, 0xCCE0, 0x74A5, 0xCCE1, 0x74CA, 0xCCE2, 0x75D9, 0xCCE3, 0x786C, 0xCCE4, 0x78EC, 0xCCE5, 0x7ADF, 0xCCE6, 0x7AF6, 0xCCE7, 0x7D45, 0xCCE8, 0x7D93, 0xCCE9, 0x8015, 0xCCEA, 0x803F, 0xCCEB, 0x811B, 0xCCEC, 0x8396, 0xCCED, 0x8B66, 0xCCEE, 0x8F15, 0xCCEF, 0x9015, 0xCCF0, 0x93E1, 0xCCF1, 0x9803, 0xCCF2, 0x9838, 0xCCF3, 0x9A5A, 0xCCF4, 0x9BE8, 0xCCF5, 0x4FC2, 0xCCF6, 0x5553, 0xCCF7, 0x583A, 0xCCF8, 0x5951, 0xCCF9, 0x5B63, 0xCCFA, 0x5C46, 0xCCFB, 0x60B8, 0xCCFC, 0x6212, 0xCCFD, 0x6842, 0xCCFE, 0x68B0, 0xCDA1, 0x68E8, 0xCDA2, 0x6EAA, 0xCDA3, 0x754C, 0xCDA4, 0x7678, 0xCDA5, 0x78CE, 0xCDA6, 0x7A3D, 0xCDA7, 0x7CFB, 0xCDA8, 0x7E6B, 0xCDA9, 0x7E7C, 0xCDAA, 0x8A08, 0xCDAB, 0x8AA1, 0xCDAC, 0x8C3F, 0xCDAD, 0x968E, 0xCDAE, 0x9DC4, 0xCDAF, 0x53E4, 0xCDB0, 0x53E9, 0xCDB1, 0x544A, 0xCDB2, 0x5471, 0xCDB3, 0x56FA, 0xCDB4, 0x59D1, 0xCDB5, 0x5B64, 0xCDB6, 0x5C3B, 0xCDB7, 0x5EAB, 0xCDB8, 0x62F7, 0xCDB9, 0x6537, 0xCDBA, 0x6545, 0xCDBB, 0x6572, 0xCDBC, 0x66A0, 0xCDBD, 0x67AF, 0xCDBE, 0x69C1, 0xCDBF, 0x6CBD, 0xCDC0, 0x75FC, 0xCDC1, 0x7690, 0xCDC2, 0x777E, 0xCDC3, 0x7A3F, 0xCDC4, 0x7F94, 0xCDC5, 0x8003, 0xCDC6, 0x80A1, 0xCDC7, 0x818F, 0xCDC8, 0x82E6, 0xCDC9, 0x82FD, 0xCDCA, 0x83F0, 0xCDCB, 0x85C1, 0xCDCC, 0x8831, 0xCDCD, 0x88B4, 0xCDCE, 0x8AA5, 0xCDCF, 0xF903, 0xCDD0, 0x8F9C, 0xCDD1, 0x932E, 0xCDD2, 0x96C7, 0xCDD3, 0x9867, 0xCDD4, 0x9AD8, 0xCDD5, 0x9F13, 0xCDD6, 0x54ED, 0xCDD7, 0x659B, 0xCDD8, 0x66F2, 0xCDD9, 0x688F, 0xCDDA, 0x7A40, 0xCDDB, 0x8C37, 0xCDDC, 0x9D60, 0xCDDD, 0x56F0, 0xCDDE, 0x5764, 0xCDDF, 0x5D11, 0xCDE0, 0x6606, 0xCDE1, 0x68B1, 0xCDE2, 0x68CD, 0xCDE3, 0x6EFE, 0xCDE4, 0x7428, 0xCDE5, 0x889E, 0xCDE6, 0x9BE4, 0xCDE7, 0x6C68, 0xCDE8, 0xF904, 0xCDE9, 0x9AA8, 0xCDEA, 0x4F9B, 0xCDEB, 0x516C, 0xCDEC, 0x5171, 0xCDED, 0x529F, 0xCDEE, 0x5B54, 0xCDEF, 0x5DE5, 0xCDF0, 0x6050, 0xCDF1, 0x606D, 0xCDF2, 0x62F1, 0xCDF3, 0x63A7, 0xCDF4, 0x653B, 0xCDF5, 0x73D9, 0xCDF6, 0x7A7A, 0xCDF7, 0x86A3, 0xCDF8, 0x8CA2, 0xCDF9, 0x978F, 0xCDFA, 0x4E32, 0xCDFB, 0x5BE1, 0xCDFC, 0x6208, 0xCDFD, 0x679C, 0xCDFE, 0x74DC, 0xCEA1, 0x79D1, 0xCEA2, 0x83D3, 0xCEA3, 0x8A87, 0xCEA4, 0x8AB2, 0xCEA5, 0x8DE8, 0xCEA6, 0x904E, 0xCEA7, 0x934B, 0xCEA8, 0x9846, 0xCEA9, 0x5ED3, 0xCEAA, 0x69E8, 0xCEAB, 0x85FF, 0xCEAC, 0x90ED, 0xCEAD, 0xF905, 0xCEAE, 0x51A0, 0xCEAF, 0x5B98, 0xCEB0, 0x5BEC, 0xCEB1, 0x6163, 0xCEB2, 0x68FA, 0xCEB3, 0x6B3E, 0xCEB4, 0x704C, 0xCEB5, 0x742F, 0xCEB6, 0x74D8, 0xCEB7, 0x7BA1, 0xCEB8, 0x7F50, 0xCEB9, 0x83C5, 0xCEBA, 0x89C0, 0xCEBB, 0x8CAB, 0xCEBC, 0x95DC, 0xCEBD, 0x9928, 0xCEBE, 0x522E, 0xCEBF, 0x605D, 0xCEC0, 0x62EC, 0xCEC1, 0x9002, 0xCEC2, 0x4F8A, 0xCEC3, 0x5149, 0xCEC4, 0x5321, 0xCEC5, 0x58D9, 0xCEC6, 0x5EE3, 0xCEC7, 0x66E0, 0xCEC8, 0x6D38, 0xCEC9, 0x709A, 0xCECA, 0x72C2, 0xCECB, 0x73D6, 0xCECC, 0x7B50, 0xCECD, 0x80F1, 0xCECE, 0x945B, 0xCECF, 0x5366, 0xCED0, 0x639B, 0xCED1, 0x7F6B, 0xCED2, 0x4E56, 0xCED3, 0x5080, 0xCED4, 0x584A, 0xCED5, 0x58DE, 0xCED6, 0x602A, 0xCED7, 0x6127, 0xCED8, 0x62D0, 0xCED9, 0x69D0, 0xCEDA, 0x9B41, 0xCEDB, 0x5B8F, 0xCEDC, 0x7D18, 0xCEDD, 0x80B1, 0xCEDE, 0x8F5F, 0xCEDF, 0x4EA4, 0xCEE0, 0x50D1, 0xCEE1, 0x54AC, 0xCEE2, 0x55AC, 0xCEE3, 0x5B0C, 0xCEE4, 0x5DA0, 0xCEE5, 0x5DE7, 0xCEE6, 0x652A, 0xCEE7, 0x654E, 0xCEE8, 0x6821, 0xCEE9, 0x6A4B, 0xCEEA, 0x72E1, 0xCEEB, 0x768E, 0xCEEC, 0x77EF, 0xCEED, 0x7D5E, 0xCEEE, 0x7FF9, 0xCEEF, 0x81A0, 0xCEF0, 0x854E, 0xCEF1, 0x86DF, 0xCEF2, 0x8F03, 0xCEF3, 0x8F4E, 0xCEF4, 0x90CA, 0xCEF5, 0x9903, 0xCEF6, 0x9A55, 0xCEF7, 0x9BAB, 0xCEF8, 0x4E18, 0xCEF9, 0x4E45, 0xCEFA, 0x4E5D, 0xCEFB, 0x4EC7, 0xCEFC, 0x4FF1, 0xCEFD, 0x5177, 0xCEFE, 0x52FE, 0xCFA1, 0x5340, 0xCFA2, 0x53E3, 0xCFA3, 0x53E5, 0xCFA4, 0x548E, 0xCFA5, 0x5614, 0xCFA6, 0x5775, 0xCFA7, 0x57A2, 0xCFA8, 0x5BC7, 0xCFA9, 0x5D87, 0xCFAA, 0x5ED0, 0xCFAB, 0x61FC, 0xCFAC, 0x62D8, 0xCFAD, 0x6551, 0xCFAE, 0x67B8, 0xCFAF, 0x67E9, 0xCFB0, 0x69CB, 0xCFB1, 0x6B50, 0xCFB2, 0x6BC6, 0xCFB3, 0x6BEC, 0xCFB4, 0x6C42, 0xCFB5, 0x6E9D, 0xCFB6, 0x7078, 0xCFB7, 0x72D7, 0xCFB8, 0x7396, 0xCFB9, 0x7403, 0xCFBA, 0x77BF, 0xCFBB, 0x77E9, 0xCFBC, 0x7A76, 0xCFBD, 0x7D7F, 0xCFBE, 0x8009, 0xCFBF, 0x81FC, 0xCFC0, 0x8205, 0xCFC1, 0x820A, 0xCFC2, 0x82DF, 0xCFC3, 0x8862, 0xCFC4, 0x8B33, 0xCFC5, 0x8CFC, 0xCFC6, 0x8EC0, 0xCFC7, 0x9011, 0xCFC8, 0x90B1, 0xCFC9, 0x9264, 0xCFCA, 0x92B6, 0xCFCB, 0x99D2, 0xCFCC, 0x9A45, 0xCFCD, 0x9CE9, 0xCFCE, 0x9DD7, 0xCFCF, 0x9F9C, 0xCFD0, 0x570B, 0xCFD1, 0x5C40, 0xCFD2, 0x83CA, 0xCFD3, 0x97A0, 0xCFD4, 0x97AB, 0xCFD5, 0x9EB4, 0xCFD6, 0x541B, 0xCFD7, 0x7A98, 0xCFD8, 0x7FA4, 0xCFD9, 0x88D9, 0xCFDA, 0x8ECD, 0xCFDB, 0x90E1, 0xCFDC, 0x5800, 0xCFDD, 0x5C48, 0xCFDE, 0x6398, 0xCFDF, 0x7A9F, 0xCFE0, 0x5BAE, 0xCFE1, 0x5F13, 0xCFE2, 0x7A79, 0xCFE3, 0x7AAE, 0xCFE4, 0x828E, 0xCFE5, 0x8EAC, 0xCFE6, 0x5026, 0xCFE7, 0x5238, 0xCFE8, 0x52F8, 0xCFE9, 0x5377, 0xCFEA, 0x5708, 0xCFEB, 0x62F3, 0xCFEC, 0x6372, 0xCFED, 0x6B0A, 0xCFEE, 0x6DC3, 0xCFEF, 0x7737, 0xCFF0, 0x53A5, 0xCFF1, 0x7357, 0xCFF2, 0x8568, 0xCFF3, 0x8E76, 0xCFF4, 0x95D5, 0xCFF5, 0x673A, 0xCFF6, 0x6AC3, 0xCFF7, 0x6F70, 0xCFF8, 0x8A6D, 0xCFF9, 0x8ECC, 0xCFFA, 0x994B, 0xCFFB, 0xF906, 0xCFFC, 0x6677, 0xCFFD, 0x6B78, 0xCFFE, 0x8CB4, 0xD0A1, 0x9B3C, 0xD0A2, 0xF907, 0xD0A3, 0x53EB, 0xD0A4, 0x572D, 0xD0A5, 0x594E, 0xD0A6, 0x63C6, 0xD0A7, 0x69FB, 0xD0A8, 0x73EA, 0xD0A9, 0x7845, 0xD0AA, 0x7ABA, 0xD0AB, 0x7AC5, 0xD0AC, 0x7CFE, 0xD0AD, 0x8475, 0xD0AE, 0x898F, 0xD0AF, 0x8D73, 0xD0B0, 0x9035, 0xD0B1, 0x95A8, 0xD0B2, 0x52FB, 0xD0B3, 0x5747, 0xD0B4, 0x7547, 0xD0B5, 0x7B60, 0xD0B6, 0x83CC, 0xD0B7, 0x921E, 0xD0B8, 0xF908, 0xD0B9, 0x6A58, 0xD0BA, 0x514B, 0xD0BB, 0x524B, 0xD0BC, 0x5287, 0xD0BD, 0x621F, 0xD0BE, 0x68D8, 0xD0BF, 0x6975, 0xD0C0, 0x9699, 0xD0C1, 0x50C5, 0xD0C2, 0x52A4, 0xD0C3, 0x52E4, 0xD0C4, 0x61C3, 0xD0C5, 0x65A4, 0xD0C6, 0x6839, 0xD0C7, 0x69FF, 0xD0C8, 0x747E, 0xD0C9, 0x7B4B, 0xD0CA, 0x82B9, 0xD0CB, 0x83EB, 0xD0CC, 0x89B2, 0xD0CD, 0x8B39, 0xD0CE, 0x8FD1, 0xD0CF, 0x9949, 0xD0D0, 0xF909, 0xD0D1, 0x4ECA, 0xD0D2, 0x5997, 0xD0D3, 0x64D2, 0xD0D4, 0x6611, 0xD0D5, 0x6A8E, 0xD0D6, 0x7434, 0xD0D7, 0x7981, 0xD0D8, 0x79BD, 0xD0D9, 0x82A9, 0xD0DA, 0x887E, 0xD0DB, 0x887F, 0xD0DC, 0x895F, 0xD0DD, 0xF90A, 0xD0DE, 0x9326, 0xD0DF, 0x4F0B, 0xD0E0, 0x53CA, 0xD0E1, 0x6025, 0xD0E2, 0x6271, 0xD0E3, 0x6C72, 0xD0E4, 0x7D1A, 0xD0E5, 0x7D66, 0xD0E6, 0x4E98, 0xD0E7, 0x5162, 0xD0E8, 0x77DC, 0xD0E9, 0x80AF, 0xD0EA, 0x4F01, 0xD0EB, 0x4F0E, 0xD0EC, 0x5176, 0xD0ED, 0x5180, 0xD0EE, 0x55DC, 0xD0EF, 0x5668, 0xD0F0, 0x573B, 0xD0F1, 0x57FA, 0xD0F2, 0x57FC, 0xD0F3, 0x5914, 0xD0F4, 0x5947, 0xD0F5, 0x5993, 0xD0F6, 0x5BC4, 0xD0F7, 0x5C90, 0xD0F8, 0x5D0E, 0xD0F9, 0x5DF1, 0xD0FA, 0x5E7E, 0xD0FB, 0x5FCC, 0xD0FC, 0x6280, 0xD0FD, 0x65D7, 0xD0FE, 0x65E3, 0xD1A1, 0x671E, 0xD1A2, 0x671F, 0xD1A3, 0x675E, 0xD1A4, 0x68CB, 0xD1A5, 0x68C4, 0xD1A6, 0x6A5F, 0xD1A7, 0x6B3A, 0xD1A8, 0x6C23, 0xD1A9, 0x6C7D, 0xD1AA, 0x6C82, 0xD1AB, 0x6DC7, 0xD1AC, 0x7398, 0xD1AD, 0x7426, 0xD1AE, 0x742A, 0xD1AF, 0x7482, 0xD1B0, 0x74A3, 0xD1B1, 0x7578, 0xD1B2, 0x757F, 0xD1B3, 0x7881, 0xD1B4, 0x78EF, 0xD1B5, 0x7941, 0xD1B6, 0x7947, 0xD1B7, 0x7948, 0xD1B8, 0x797A, 0xD1B9, 0x7B95, 0xD1BA, 0x7D00, 0xD1BB, 0x7DBA, 0xD1BC, 0x7F88, 0xD1BD, 0x8006, 0xD1BE, 0x802D, 0xD1BF, 0x808C, 0xD1C0, 0x8A18, 0xD1C1, 0x8B4F, 0xD1C2, 0x8C48, 0xD1C3, 0x8D77, 0xD1C4, 0x9321, 0xD1C5, 0x9324, 0xD1C6, 0x98E2, 0xD1C7, 0x9951, 0xD1C8, 0x9A0E, 0xD1C9, 0x9A0F, 0xD1CA, 0x9A65, 0xD1CB, 0x9E92, 0xD1CC, 0x7DCA, 0xD1CD, 0x4F76, 0xD1CE, 0x5409, 0xD1CF, 0x62EE, 0xD1D0, 0x6854, 0xD1D1, 0x91D1, 0xD1D2, 0x55AB, 0xD1D3, 0x513A, 0xD1D4, 0xF90B, 0xD1D5, 0xF90C, 0xD1D6, 0x5A1C, 0xD1D7, 0x61E6, 0xD1D8, 0xF90D, 0xD1D9, 0x62CF, 0xD1DA, 0x62FF, 0xD1DB, 0xF90E, 0xD1DC, 0xF90F, 0xD1DD, 0xF910, 0xD1DE, 0xF911, 0xD1DF, 0xF912, 0xD1E0, 0xF913, 0xD1E1, 0x90A3, 0xD1E2, 0xF914, 0xD1E3, 0xF915, 0xD1E4, 0xF916, 0xD1E5, 0xF917, 0xD1E6, 0xF918, 0xD1E7, 0x8AFE, 0xD1E8, 0xF919, 0xD1E9, 0xF91A, 0xD1EA, 0xF91B, 0xD1EB, 0xF91C, 0xD1EC, 0x6696, 0xD1ED, 0xF91D, 0xD1EE, 0x7156, 0xD1EF, 0xF91E, 0xD1F0, 0xF91F, 0xD1F1, 0x96E3, 0xD1F2, 0xF920, 0xD1F3, 0x634F, 0xD1F4, 0x637A, 0xD1F5, 0x5357, 0xD1F6, 0xF921, 0xD1F7, 0x678F, 0xD1F8, 0x6960, 0xD1F9, 0x6E73, 0xD1FA, 0xF922, 0xD1FB, 0x7537, 0xD1FC, 0xF923, 0xD1FD, 0xF924, 0xD1FE, 0xF925, 0xD2A1, 0x7D0D, 0xD2A2, 0xF926, 0xD2A3, 0xF927, 0xD2A4, 0x8872, 0xD2A5, 0x56CA, 0xD2A6, 0x5A18, 0xD2A7, 0xF928, 0xD2A8, 0xF929, 0xD2A9, 0xF92A, 0xD2AA, 0xF92B, 0xD2AB, 0xF92C, 0xD2AC, 0x4E43, 0xD2AD, 0xF92D, 0xD2AE, 0x5167, 0xD2AF, 0x5948, 0xD2B0, 0x67F0, 0xD2B1, 0x8010, 0xD2B2, 0xF92E, 0xD2B3, 0x5973, 0xD2B4, 0x5E74, 0xD2B5, 0x649A, 0xD2B6, 0x79CA, 0xD2B7, 0x5FF5, 0xD2B8, 0x606C, 0xD2B9, 0x62C8, 0xD2BA, 0x637B, 0xD2BB, 0x5BE7, 0xD2BC, 0x5BD7, 0xD2BD, 0x52AA, 0xD2BE, 0xF92F, 0xD2BF, 0x5974, 0xD2C0, 0x5F29, 0xD2C1, 0x6012, 0xD2C2, 0xF930, 0xD2C3, 0xF931, 0xD2C4, 0xF932, 0xD2C5, 0x7459, 0xD2C6, 0xF933, 0xD2C7, 0xF934, 0xD2C8, 0xF935, 0xD2C9, 0xF936, 0xD2CA, 0xF937, 0xD2CB, 0xF938, 0xD2CC, 0x99D1, 0xD2CD, 0xF939, 0xD2CE, 0xF93A, 0xD2CF, 0xF93B, 0xD2D0, 0xF93C, 0xD2D1, 0xF93D, 0xD2D2, 0xF93E, 0xD2D3, 0xF93F, 0xD2D4, 0xF940, 0xD2D5, 0xF941, 0xD2D6, 0xF942, 0xD2D7, 0xF943, 0xD2D8, 0x6FC3, 0xD2D9, 0xF944, 0xD2DA, 0xF945, 0xD2DB, 0x81BF, 0xD2DC, 0x8FB2, 0xD2DD, 0x60F1, 0xD2DE, 0xF946, 0xD2DF, 0xF947, 0xD2E0, 0x8166, 0xD2E1, 0xF948, 0xD2E2, 0xF949, 0xD2E3, 0x5C3F, 0xD2E4, 0xF94A, 0xD2E5, 0xF94B, 0xD2E6, 0xF94C, 0xD2E7, 0xF94D, 0xD2E8, 0xF94E, 0xD2E9, 0xF94F, 0xD2EA, 0xF950, 0xD2EB, 0xF951, 0xD2EC, 0x5AE9, 0xD2ED, 0x8A25, 0xD2EE, 0x677B, 0xD2EF, 0x7D10, 0xD2F0, 0xF952, 0xD2F1, 0xF953, 0xD2F2, 0xF954, 0xD2F3, 0xF955, 0xD2F4, 0xF956, 0xD2F5, 0xF957, 0xD2F6, 0x80FD, 0xD2F7, 0xF958, 0xD2F8, 0xF959, 0xD2F9, 0x5C3C, 0xD2FA, 0x6CE5, 0xD2FB, 0x533F, 0xD2FC, 0x6EBA, 0xD2FD, 0x591A, 0xD2FE, 0x8336, 0xD3A1, 0x4E39, 0xD3A2, 0x4EB6, 0xD3A3, 0x4F46, 0xD3A4, 0x55AE, 0xD3A5, 0x5718, 0xD3A6, 0x58C7, 0xD3A7, 0x5F56, 0xD3A8, 0x65B7, 0xD3A9, 0x65E6, 0xD3AA, 0x6A80, 0xD3AB, 0x6BB5, 0xD3AC, 0x6E4D, 0xD3AD, 0x77ED, 0xD3AE, 0x7AEF, 0xD3AF, 0x7C1E, 0xD3B0, 0x7DDE, 0xD3B1, 0x86CB, 0xD3B2, 0x8892, 0xD3B3, 0x9132, 0xD3B4, 0x935B, 0xD3B5, 0x64BB, 0xD3B6, 0x6FBE, 0xD3B7, 0x737A, 0xD3B8, 0x75B8, 0xD3B9, 0x9054, 0xD3BA, 0x5556, 0xD3BB, 0x574D, 0xD3BC, 0x61BA, 0xD3BD, 0x64D4, 0xD3BE, 0x66C7, 0xD3BF, 0x6DE1, 0xD3C0, 0x6E5B, 0xD3C1, 0x6F6D, 0xD3C2, 0x6FB9, 0xD3C3, 0x75F0, 0xD3C4, 0x8043, 0xD3C5, 0x81BD, 0xD3C6, 0x8541, 0xD3C7, 0x8983, 0xD3C8, 0x8AC7, 0xD3C9, 0x8B5A, 0xD3CA, 0x931F, 0xD3CB, 0x6C93, 0xD3CC, 0x7553, 0xD3CD, 0x7B54, 0xD3CE, 0x8E0F, 0xD3CF, 0x905D, 0xD3D0, 0x5510, 0xD3D1, 0x5802, 0xD3D2, 0x5858, 0xD3D3, 0x5E62, 0xD3D4, 0x6207, 0xD3D5, 0x649E, 0xD3D6, 0x68E0, 0xD3D7, 0x7576, 0xD3D8, 0x7CD6, 0xD3D9, 0x87B3, 0xD3DA, 0x9EE8, 0xD3DB, 0x4EE3, 0xD3DC, 0x5788, 0xD3DD, 0x576E, 0xD3DE, 0x5927, 0xD3DF, 0x5C0D, 0xD3E0, 0x5CB1, 0xD3E1, 0x5E36, 0xD3E2, 0x5F85, 0xD3E3, 0x6234, 0xD3E4, 0x64E1, 0xD3E5, 0x73B3, 0xD3E6, 0x81FA, 0xD3E7, 0x888B, 0xD3E8, 0x8CB8, 0xD3E9, 0x968A, 0xD3EA, 0x9EDB, 0xD3EB, 0x5B85, 0xD3EC, 0x5FB7, 0xD3ED, 0x60B3, 0xD3EE, 0x5012, 0xD3EF, 0x5200, 0xD3F0, 0x5230, 0xD3F1, 0x5716, 0xD3F2, 0x5835, 0xD3F3, 0x5857, 0xD3F4, 0x5C0E, 0xD3F5, 0x5C60, 0xD3F6, 0x5CF6, 0xD3F7, 0x5D8B, 0xD3F8, 0x5EA6, 0xD3F9, 0x5F92, 0xD3FA, 0x60BC, 0xD3FB, 0x6311, 0xD3FC, 0x6389, 0xD3FD, 0x6417, 0xD3FE, 0x6843, 0xD4A1, 0x68F9, 0xD4A2, 0x6AC2, 0xD4A3, 0x6DD8, 0xD4A4, 0x6E21, 0xD4A5, 0x6ED4, 0xD4A6, 0x6FE4, 0xD4A7, 0x71FE, 0xD4A8, 0x76DC, 0xD4A9, 0x7779, 0xD4AA, 0x79B1, 0xD4AB, 0x7A3B, 0xD4AC, 0x8404, 0xD4AD, 0x89A9, 0xD4AE, 0x8CED, 0xD4AF, 0x8DF3, 0xD4B0, 0x8E48, 0xD4B1, 0x9003, 0xD4B2, 0x9014, 0xD4B3, 0x9053, 0xD4B4, 0x90FD, 0xD4B5, 0x934D, 0xD4B6, 0x9676, 0xD4B7, 0x97DC, 0xD4B8, 0x6BD2, 0xD4B9, 0x7006, 0xD4BA, 0x7258, 0xD4BB, 0x72A2, 0xD4BC, 0x7368, 0xD4BD, 0x7763, 0xD4BE, 0x79BF, 0xD4BF, 0x7BE4, 0xD4C0, 0x7E9B, 0xD4C1, 0x8B80, 0xD4C2, 0x58A9, 0xD4C3, 0x60C7, 0xD4C4, 0x6566, 0xD4C5, 0x65FD, 0xD4C6, 0x66BE, 0xD4C7, 0x6C8C, 0xD4C8, 0x711E, 0xD4C9, 0x71C9, 0xD4CA, 0x8C5A, 0xD4CB, 0x9813, 0xD4CC, 0x4E6D, 0xD4CD, 0x7A81, 0xD4CE, 0x4EDD, 0xD4CF, 0x51AC, 0xD4D0, 0x51CD, 0xD4D1, 0x52D5, 0xD4D2, 0x540C, 0xD4D3, 0x61A7, 0xD4D4, 0x6771, 0xD4D5, 0x6850, 0xD4D6, 0x68DF, 0xD4D7, 0x6D1E, 0xD4D8, 0x6F7C, 0xD4D9, 0x75BC, 0xD4DA, 0x77B3, 0xD4DB, 0x7AE5, 0xD4DC, 0x80F4, 0xD4DD, 0x8463, 0xD4DE, 0x9285, 0xD4DF, 0x515C, 0xD4E0, 0x6597, 0xD4E1, 0x675C, 0xD4E2, 0x6793, 0xD4E3, 0x75D8, 0xD4E4, 0x7AC7, 0xD4E5, 0x8373, 0xD4E6, 0xF95A, 0xD4E7, 0x8C46, 0xD4E8, 0x9017, 0xD4E9, 0x982D, 0xD4EA, 0x5C6F, 0xD4EB, 0x81C0, 0xD4EC, 0x829A, 0xD4ED, 0x9041, 0xD4EE, 0x906F, 0xD4EF, 0x920D, 0xD4F0, 0x5F97, 0xD4F1, 0x5D9D, 0xD4F2, 0x6A59, 0xD4F3, 0x71C8, 0xD4F4, 0x767B, 0xD4F5, 0x7B49, 0xD4F6, 0x85E4, 0xD4F7, 0x8B04, 0xD4F8, 0x9127, 0xD4F9, 0x9A30, 0xD4FA, 0x5587, 0xD4FB, 0x61F6, 0xD4FC, 0xF95B, 0xD4FD, 0x7669, 0xD4FE, 0x7F85, 0xD5A1, 0x863F, 0xD5A2, 0x87BA, 0xD5A3, 0x88F8, 0xD5A4, 0x908F, 0xD5A5, 0xF95C, 0xD5A6, 0x6D1B, 0xD5A7, 0x70D9, 0xD5A8, 0x73DE, 0xD5A9, 0x7D61, 0xD5AA, 0x843D, 0xD5AB, 0xF95D, 0xD5AC, 0x916A, 0xD5AD, 0x99F1, 0xD5AE, 0xF95E, 0xD5AF, 0x4E82, 0xD5B0, 0x5375, 0xD5B1, 0x6B04, 0xD5B2, 0x6B12, 0xD5B3, 0x703E, 0xD5B4, 0x721B, 0xD5B5, 0x862D, 0xD5B6, 0x9E1E, 0xD5B7, 0x524C, 0xD5B8, 0x8FA3, 0xD5B9, 0x5D50, 0xD5BA, 0x64E5, 0xD5BB, 0x652C, 0xD5BC, 0x6B16, 0xD5BD, 0x6FEB, 0xD5BE, 0x7C43, 0xD5BF, 0x7E9C, 0xD5C0, 0x85CD, 0xD5C1, 0x8964, 0xD5C2, 0x89BD, 0xD5C3, 0x62C9, 0xD5C4, 0x81D8, 0xD5C5, 0x881F, 0xD5C6, 0x5ECA, 0xD5C7, 0x6717, 0xD5C8, 0x6D6A, 0xD5C9, 0x72FC, 0xD5CA, 0x7405, 0xD5CB, 0x746F, 0xD5CC, 0x8782, 0xD5CD, 0x90DE, 0xD5CE, 0x4F86, 0xD5CF, 0x5D0D, 0xD5D0, 0x5FA0, 0xD5D1, 0x840A, 0xD5D2, 0x51B7, 0xD5D3, 0x63A0, 0xD5D4, 0x7565, 0xD5D5, 0x4EAE, 0xD5D6, 0x5006, 0xD5D7, 0x5169, 0xD5D8, 0x51C9, 0xD5D9, 0x6881, 0xD5DA, 0x6A11, 0xD5DB, 0x7CAE, 0xD5DC, 0x7CB1, 0xD5DD, 0x7CE7, 0xD5DE, 0x826F, 0xD5DF, 0x8AD2, 0xD5E0, 0x8F1B, 0xD5E1, 0x91CF, 0xD5E2, 0x4FB6, 0xD5E3, 0x5137, 0xD5E4, 0x52F5, 0xD5E5, 0x5442, 0xD5E6, 0x5EEC, 0xD5E7, 0x616E, 0xD5E8, 0x623E, 0xD5E9, 0x65C5, 0xD5EA, 0x6ADA, 0xD5EB, 0x6FFE, 0xD5EC, 0x792A, 0xD5ED, 0x85DC, 0xD5EE, 0x8823, 0xD5EF, 0x95AD, 0xD5F0, 0x9A62, 0xD5F1, 0x9A6A, 0xD5F2, 0x9E97, 0xD5F3, 0x9ECE, 0xD5F4, 0x529B, 0xD5F5, 0x66C6, 0xD5F6, 0x6B77, 0xD5F7, 0x701D, 0xD5F8, 0x792B, 0xD5F9, 0x8F62, 0xD5FA, 0x9742, 0xD5FB, 0x6190, 0xD5FC, 0x6200, 0xD5FD, 0x6523, 0xD5FE, 0x6F23, 0xD6A1, 0x7149, 0xD6A2, 0x7489, 0xD6A3, 0x7DF4, 0xD6A4, 0x806F, 0xD6A5, 0x84EE, 0xD6A6, 0x8F26, 0xD6A7, 0x9023, 0xD6A8, 0x934A, 0xD6A9, 0x51BD, 0xD6AA, 0x5217, 0xD6AB, 0x52A3, 0xD6AC, 0x6D0C, 0xD6AD, 0x70C8, 0xD6AE, 0x88C2, 0xD6AF, 0x5EC9, 0xD6B0, 0x6582, 0xD6B1, 0x6BAE, 0xD6B2, 0x6FC2, 0xD6B3, 0x7C3E, 0xD6B4, 0x7375, 0xD6B5, 0x4EE4, 0xD6B6, 0x4F36, 0xD6B7, 0x56F9, 0xD6B8, 0xF95F, 0xD6B9, 0x5CBA, 0xD6BA, 0x5DBA, 0xD6BB, 0x601C, 0xD6BC, 0x73B2, 0xD6BD, 0x7B2D, 0xD6BE, 0x7F9A, 0xD6BF, 0x7FCE, 0xD6C0, 0x8046, 0xD6C1, 0x901E, 0xD6C2, 0x9234, 0xD6C3, 0x96F6, 0xD6C4, 0x9748, 0xD6C5, 0x9818, 0xD6C6, 0x9F61, 0xD6C7, 0x4F8B, 0xD6C8, 0x6FA7, 0xD6C9, 0x79AE, 0xD6CA, 0x91B4, 0xD6CB, 0x96B7, 0xD6CC, 0x52DE, 0xD6CD, 0xF960, 0xD6CE, 0x6488, 0xD6CF, 0x64C4, 0xD6D0, 0x6AD3, 0xD6D1, 0x6F5E, 0xD6D2, 0x7018, 0xD6D3, 0x7210, 0xD6D4, 0x76E7, 0xD6D5, 0x8001, 0xD6D6, 0x8606, 0xD6D7, 0x865C, 0xD6D8, 0x8DEF, 0xD6D9, 0x8F05, 0xD6DA, 0x9732, 0xD6DB, 0x9B6F, 0xD6DC, 0x9DFA, 0xD6DD, 0x9E75, 0xD6DE, 0x788C, 0xD6DF, 0x797F, 0xD6E0, 0x7DA0, 0xD6E1, 0x83C9, 0xD6E2, 0x9304, 0xD6E3, 0x9E7F, 0xD6E4, 0x9E93, 0xD6E5, 0x8AD6, 0xD6E6, 0x58DF, 0xD6E7, 0x5F04, 0xD6E8, 0x6727, 0xD6E9, 0x7027, 0xD6EA, 0x74CF, 0xD6EB, 0x7C60, 0xD6EC, 0x807E, 0xD6ED, 0x5121, 0xD6EE, 0x7028, 0xD6EF, 0x7262, 0xD6F0, 0x78CA, 0xD6F1, 0x8CC2, 0xD6F2, 0x8CDA, 0xD6F3, 0x8CF4, 0xD6F4, 0x96F7, 0xD6F5, 0x4E86, 0xD6F6, 0x50DA, 0xD6F7, 0x5BEE, 0xD6F8, 0x5ED6, 0xD6F9, 0x6599, 0xD6FA, 0x71CE, 0xD6FB, 0x7642, 0xD6FC, 0x77AD, 0xD6FD, 0x804A, 0xD6FE, 0x84FC, 0xD7A1, 0x907C, 0xD7A2, 0x9B27, 0xD7A3, 0x9F8D, 0xD7A4, 0x58D8, 0xD7A5, 0x5A41, 0xD7A6, 0x5C62, 0xD7A7, 0x6A13, 0xD7A8, 0x6DDA, 0xD7A9, 0x6F0F, 0xD7AA, 0x763B, 0xD7AB, 0x7D2F, 0xD7AC, 0x7E37, 0xD7AD, 0x851E, 0xD7AE, 0x8938, 0xD7AF, 0x93E4, 0xD7B0, 0x964B, 0xD7B1, 0x5289, 0xD7B2, 0x65D2, 0xD7B3, 0x67F3, 0xD7B4, 0x69B4, 0xD7B5, 0x6D41, 0xD7B6, 0x6E9C, 0xD7B7, 0x700F, 0xD7B8, 0x7409, 0xD7B9, 0x7460, 0xD7BA, 0x7559, 0xD7BB, 0x7624, 0xD7BC, 0x786B, 0xD7BD, 0x8B2C, 0xD7BE, 0x985E, 0xD7BF, 0x516D, 0xD7C0, 0x622E, 0xD7C1, 0x9678, 0xD7C2, 0x4F96, 0xD7C3, 0x502B, 0xD7C4, 0x5D19, 0xD7C5, 0x6DEA, 0xD7C6, 0x7DB8, 0xD7C7, 0x8F2A, 0xD7C8, 0x5F8B, 0xD7C9, 0x6144, 0xD7CA, 0x6817, 0xD7CB, 0xF961, 0xD7CC, 0x9686, 0xD7CD, 0x52D2, 0xD7CE, 0x808B, 0xD7CF, 0x51DC, 0xD7D0, 0x51CC, 0xD7D1, 0x695E, 0xD7D2, 0x7A1C, 0xD7D3, 0x7DBE, 0xD7D4, 0x83F1, 0xD7D5, 0x9675, 0xD7D6, 0x4FDA, 0xD7D7, 0x5229, 0xD7D8, 0x5398, 0xD7D9, 0x540F, 0xD7DA, 0x550E, 0xD7DB, 0x5C65, 0xD7DC, 0x60A7, 0xD7DD, 0x674E, 0xD7DE, 0x68A8, 0xD7DF, 0x6D6C, 0xD7E0, 0x7281, 0xD7E1, 0x72F8, 0xD7E2, 0x7406, 0xD7E3, 0x7483, 0xD7E4, 0xF962, 0xD7E5, 0x75E2, 0xD7E6, 0x7C6C, 0xD7E7, 0x7F79, 0xD7E8, 0x7FB8, 0xD7E9, 0x8389, 0xD7EA, 0x88CF, 0xD7EB, 0x88E1, 0xD7EC, 0x91CC, 0xD7ED, 0x91D0, 0xD7EE, 0x96E2, 0xD7EF, 0x9BC9, 0xD7F0, 0x541D, 0xD7F1, 0x6F7E, 0xD7F2, 0x71D0, 0xD7F3, 0x7498, 0xD7F4, 0x85FA, 0xD7F5, 0x8EAA, 0xD7F6, 0x96A3, 0xD7F7, 0x9C57, 0xD7F8, 0x9E9F, 0xD7F9, 0x6797, 0xD7FA, 0x6DCB, 0xD7FB, 0x7433, 0xD7FC, 0x81E8, 0xD7FD, 0x9716, 0xD7FE, 0x782C, 0xD8A1, 0x7ACB, 0xD8A2, 0x7B20, 0xD8A3, 0x7C92, 0xD8A4, 0x6469, 0xD8A5, 0x746A, 0xD8A6, 0x75F2, 0xD8A7, 0x78BC, 0xD8A8, 0x78E8, 0xD8A9, 0x99AC, 0xD8AA, 0x9B54, 0xD8AB, 0x9EBB, 0xD8AC, 0x5BDE, 0xD8AD, 0x5E55, 0xD8AE, 0x6F20, 0xD8AF, 0x819C, 0xD8B0, 0x83AB, 0xD8B1, 0x9088, 0xD8B2, 0x4E07, 0xD8B3, 0x534D, 0xD8B4, 0x5A29, 0xD8B5, 0x5DD2, 0xD8B6, 0x5F4E, 0xD8B7, 0x6162, 0xD8B8, 0x633D, 0xD8B9, 0x6669, 0xD8BA, 0x66FC, 0xD8BB, 0x6EFF, 0xD8BC, 0x6F2B, 0xD8BD, 0x7063, 0xD8BE, 0x779E, 0xD8BF, 0x842C, 0xD8C0, 0x8513, 0xD8C1, 0x883B, 0xD8C2, 0x8F13, 0xD8C3, 0x9945, 0xD8C4, 0x9C3B, 0xD8C5, 0x551C, 0xD8C6, 0x62B9, 0xD8C7, 0x672B, 0xD8C8, 0x6CAB, 0xD8C9, 0x8309, 0xD8CA, 0x896A, 0xD8CB, 0x977A, 0xD8CC, 0x4EA1, 0xD8CD, 0x5984, 0xD8CE, 0x5FD8, 0xD8CF, 0x5FD9, 0xD8D0, 0x671B, 0xD8D1, 0x7DB2, 0xD8D2, 0x7F54, 0xD8D3, 0x8292, 0xD8D4, 0x832B, 0xD8D5, 0x83BD, 0xD8D6, 0x8F1E, 0xD8D7, 0x9099, 0xD8D8, 0x57CB, 0xD8D9, 0x59B9, 0xD8DA, 0x5A92, 0xD8DB, 0x5BD0, 0xD8DC, 0x6627, 0xD8DD, 0x679A, 0xD8DE, 0x6885, 0xD8DF, 0x6BCF, 0xD8E0, 0x7164, 0xD8E1, 0x7F75, 0xD8E2, 0x8CB7, 0xD8E3, 0x8CE3, 0xD8E4, 0x9081, 0xD8E5, 0x9B45, 0xD8E6, 0x8108, 0xD8E7, 0x8C8A, 0xD8E8, 0x964C, 0xD8E9, 0x9A40, 0xD8EA, 0x9EA5, 0xD8EB, 0x5B5F, 0xD8EC, 0x6C13, 0xD8ED, 0x731B, 0xD8EE, 0x76F2, 0xD8EF, 0x76DF, 0xD8F0, 0x840C, 0xD8F1, 0x51AA, 0xD8F2, 0x8993, 0xD8F3, 0x514D, 0xD8F4, 0x5195, 0xD8F5, 0x52C9, 0xD8F6, 0x68C9, 0xD8F7, 0x6C94, 0xD8F8, 0x7704, 0xD8F9, 0x7720, 0xD8FA, 0x7DBF, 0xD8FB, 0x7DEC, 0xD8FC, 0x9762, 0xD8FD, 0x9EB5, 0xD8FE, 0x6EC5, 0xD9A1, 0x8511, 0xD9A2, 0x51A5, 0xD9A3, 0x540D, 0xD9A4, 0x547D, 0xD9A5, 0x660E, 0xD9A6, 0x669D, 0xD9A7, 0x6927, 0xD9A8, 0x6E9F, 0xD9A9, 0x76BF, 0xD9AA, 0x7791, 0xD9AB, 0x8317, 0xD9AC, 0x84C2, 0xD9AD, 0x879F, 0xD9AE, 0x9169, 0xD9AF, 0x9298, 0xD9B0, 0x9CF4, 0xD9B1, 0x8882, 0xD9B2, 0x4FAE, 0xD9B3, 0x5192, 0xD9B4, 0x52DF, 0xD9B5, 0x59C6, 0xD9B6, 0x5E3D, 0xD9B7, 0x6155, 0xD9B8, 0x6478, 0xD9B9, 0x6479, 0xD9BA, 0x66AE, 0xD9BB, 0x67D0, 0xD9BC, 0x6A21, 0xD9BD, 0x6BCD, 0xD9BE, 0x6BDB, 0xD9BF, 0x725F, 0xD9C0, 0x7261, 0xD9C1, 0x7441, 0xD9C2, 0x7738, 0xD9C3, 0x77DB, 0xD9C4, 0x8017, 0xD9C5, 0x82BC, 0xD9C6, 0x8305, 0xD9C7, 0x8B00, 0xD9C8, 0x8B28, 0xD9C9, 0x8C8C, 0xD9CA, 0x6728, 0xD9CB, 0x6C90, 0xD9CC, 0x7267, 0xD9CD, 0x76EE, 0xD9CE, 0x7766, 0xD9CF, 0x7A46, 0xD9D0, 0x9DA9, 0xD9D1, 0x6B7F, 0xD9D2, 0x6C92, 0xD9D3, 0x5922, 0xD9D4, 0x6726, 0xD9D5, 0x8499, 0xD9D6, 0x536F, 0xD9D7, 0x5893, 0xD9D8, 0x5999, 0xD9D9, 0x5EDF, 0xD9DA, 0x63CF, 0xD9DB, 0x6634, 0xD9DC, 0x6773, 0xD9DD, 0x6E3A, 0xD9DE, 0x732B, 0xD9DF, 0x7AD7, 0xD9E0, 0x82D7, 0xD9E1, 0x9328, 0xD9E2, 0x52D9, 0xD9E3, 0x5DEB, 0xD9E4, 0x61AE, 0xD9E5, 0x61CB, 0xD9E6, 0x620A, 0xD9E7, 0x62C7, 0xD9E8, 0x64AB, 0xD9E9, 0x65E0, 0xD9EA, 0x6959, 0xD9EB, 0x6B66, 0xD9EC, 0x6BCB, 0xD9ED, 0x7121, 0xD9EE, 0x73F7, 0xD9EF, 0x755D, 0xD9F0, 0x7E46, 0xD9F1, 0x821E, 0xD9F2, 0x8302, 0xD9F3, 0x856A, 0xD9F4, 0x8AA3, 0xD9F5, 0x8CBF, 0xD9F6, 0x9727, 0xD9F7, 0x9D61, 0xD9F8, 0x58A8, 0xD9F9, 0x9ED8, 0xD9FA, 0x5011, 0xD9FB, 0x520E, 0xD9FC, 0x543B, 0xD9FD, 0x554F, 0xD9FE, 0x6587, 0xDAA1, 0x6C76, 0xDAA2, 0x7D0A, 0xDAA3, 0x7D0B, 0xDAA4, 0x805E, 0xDAA5, 0x868A, 0xDAA6, 0x9580, 0xDAA7, 0x96EF, 0xDAA8, 0x52FF, 0xDAA9, 0x6C95, 0xDAAA, 0x7269, 0xDAAB, 0x5473, 0xDAAC, 0x5A9A, 0xDAAD, 0x5C3E, 0xDAAE, 0x5D4B, 0xDAAF, 0x5F4C, 0xDAB0, 0x5FAE, 0xDAB1, 0x672A, 0xDAB2, 0x68B6, 0xDAB3, 0x6963, 0xDAB4, 0x6E3C, 0xDAB5, 0x6E44, 0xDAB6, 0x7709, 0xDAB7, 0x7C73, 0xDAB8, 0x7F8E, 0xDAB9, 0x8587, 0xDABA, 0x8B0E, 0xDABB, 0x8FF7, 0xDABC, 0x9761, 0xDABD, 0x9EF4, 0xDABE, 0x5CB7, 0xDABF, 0x60B6, 0xDAC0, 0x610D, 0xDAC1, 0x61AB, 0xDAC2, 0x654F, 0xDAC3, 0x65FB, 0xDAC4, 0x65FC, 0xDAC5, 0x6C11, 0xDAC6, 0x6CEF, 0xDAC7, 0x739F, 0xDAC8, 0x73C9, 0xDAC9, 0x7DE1, 0xDACA, 0x9594, 0xDACB, 0x5BC6, 0xDACC, 0x871C, 0xDACD, 0x8B10, 0xDACE, 0x525D, 0xDACF, 0x535A, 0xDAD0, 0x62CD, 0xDAD1, 0x640F, 0xDAD2, 0x64B2, 0xDAD3, 0x6734, 0xDAD4, 0x6A38, 0xDAD5, 0x6CCA, 0xDAD6, 0x73C0, 0xDAD7, 0x749E, 0xDAD8, 0x7B94, 0xDAD9, 0x7C95, 0xDADA, 0x7E1B, 0xDADB, 0x818A, 0xDADC, 0x8236, 0xDADD, 0x8584, 0xDADE, 0x8FEB, 0xDADF, 0x96F9, 0xDAE0, 0x99C1, 0xDAE1, 0x4F34, 0xDAE2, 0x534A, 0xDAE3, 0x53CD, 0xDAE4, 0x53DB, 0xDAE5, 0x62CC, 0xDAE6, 0x642C, 0xDAE7, 0x6500, 0xDAE8, 0x6591, 0xDAE9, 0x69C3, 0xDAEA, 0x6CEE, 0xDAEB, 0x6F58, 0xDAEC, 0x73ED, 0xDAED, 0x7554, 0xDAEE, 0x7622, 0xDAEF, 0x76E4, 0xDAF0, 0x76FC, 0xDAF1, 0x78D0, 0xDAF2, 0x78FB, 0xDAF3, 0x792C, 0xDAF4, 0x7D46, 0xDAF5, 0x822C, 0xDAF6, 0x87E0, 0xDAF7, 0x8FD4, 0xDAF8, 0x9812, 0xDAF9, 0x98EF, 0xDAFA, 0x52C3, 0xDAFB, 0x62D4, 0xDAFC, 0x64A5, 0xDAFD, 0x6E24, 0xDAFE, 0x6F51, 0xDBA1, 0x767C, 0xDBA2, 0x8DCB, 0xDBA3, 0x91B1, 0xDBA4, 0x9262, 0xDBA5, 0x9AEE, 0xDBA6, 0x9B43, 0xDBA7, 0x5023, 0xDBA8, 0x508D, 0xDBA9, 0x574A, 0xDBAA, 0x59A8, 0xDBAB, 0x5C28, 0xDBAC, 0x5E47, 0xDBAD, 0x5F77, 0xDBAE, 0x623F, 0xDBAF, 0x653E, 0xDBB0, 0x65B9, 0xDBB1, 0x65C1, 0xDBB2, 0x6609, 0xDBB3, 0x678B, 0xDBB4, 0x699C, 0xDBB5, 0x6EC2, 0xDBB6, 0x78C5, 0xDBB7, 0x7D21, 0xDBB8, 0x80AA, 0xDBB9, 0x8180, 0xDBBA, 0x822B, 0xDBBB, 0x82B3, 0xDBBC, 0x84A1, 0xDBBD, 0x868C, 0xDBBE, 0x8A2A, 0xDBBF, 0x8B17, 0xDBC0, 0x90A6, 0xDBC1, 0x9632, 0xDBC2, 0x9F90, 0xDBC3, 0x500D, 0xDBC4, 0x4FF3, 0xDBC5, 0xF963, 0xDBC6, 0x57F9, 0xDBC7, 0x5F98, 0xDBC8, 0x62DC, 0xDBC9, 0x6392, 0xDBCA, 0x676F, 0xDBCB, 0x6E43, 0xDBCC, 0x7119, 0xDBCD, 0x76C3, 0xDBCE, 0x80CC, 0xDBCF, 0x80DA, 0xDBD0, 0x88F4, 0xDBD1, 0x88F5, 0xDBD2, 0x8919, 0xDBD3, 0x8CE0, 0xDBD4, 0x8F29, 0xDBD5, 0x914D, 0xDBD6, 0x966A, 0xDBD7, 0x4F2F, 0xDBD8, 0x4F70, 0xDBD9, 0x5E1B, 0xDBDA, 0x67CF, 0xDBDB, 0x6822, 0xDBDC, 0x767D, 0xDBDD, 0x767E, 0xDBDE, 0x9B44, 0xDBDF, 0x5E61, 0xDBE0, 0x6A0A, 0xDBE1, 0x7169, 0xDBE2, 0x71D4, 0xDBE3, 0x756A, 0xDBE4, 0xF964, 0xDBE5, 0x7E41, 0xDBE6, 0x8543, 0xDBE7, 0x85E9, 0xDBE8, 0x98DC, 0xDBE9, 0x4F10, 0xDBEA, 0x7B4F, 0xDBEB, 0x7F70, 0xDBEC, 0x95A5, 0xDBED, 0x51E1, 0xDBEE, 0x5E06, 0xDBEF, 0x68B5, 0xDBF0, 0x6C3E, 0xDBF1, 0x6C4E, 0xDBF2, 0x6CDB, 0xDBF3, 0x72AF, 0xDBF4, 0x7BC4, 0xDBF5, 0x8303, 0xDBF6, 0x6CD5, 0xDBF7, 0x743A, 0xDBF8, 0x50FB, 0xDBF9, 0x5288, 0xDBFA, 0x58C1, 0xDBFB, 0x64D8, 0xDBFC, 0x6A97, 0xDBFD, 0x74A7, 0xDBFE, 0x7656, 0xDCA1, 0x78A7, 0xDCA2, 0x8617, 0xDCA3, 0x95E2, 0xDCA4, 0x9739, 0xDCA5, 0xF965, 0xDCA6, 0x535E, 0xDCA7, 0x5F01, 0xDCA8, 0x8B8A, 0xDCA9, 0x8FA8, 0xDCAA, 0x8FAF, 0xDCAB, 0x908A, 0xDCAC, 0x5225, 0xDCAD, 0x77A5, 0xDCAE, 0x9C49, 0xDCAF, 0x9F08, 0xDCB0, 0x4E19, 0xDCB1, 0x5002, 0xDCB2, 0x5175, 0xDCB3, 0x5C5B, 0xDCB4, 0x5E77, 0xDCB5, 0x661E, 0xDCB6, 0x663A, 0xDCB7, 0x67C4, 0xDCB8, 0x68C5, 0xDCB9, 0x70B3, 0xDCBA, 0x7501, 0xDCBB, 0x75C5, 0xDCBC, 0x79C9, 0xDCBD, 0x7ADD, 0xDCBE, 0x8F27, 0xDCBF, 0x9920, 0xDCC0, 0x9A08, 0xDCC1, 0x4FDD, 0xDCC2, 0x5821, 0xDCC3, 0x5831, 0xDCC4, 0x5BF6, 0xDCC5, 0x666E, 0xDCC6, 0x6B65, 0xDCC7, 0x6D11, 0xDCC8, 0x6E7A, 0xDCC9, 0x6F7D, 0xDCCA, 0x73E4, 0xDCCB, 0x752B, 0xDCCC, 0x83E9, 0xDCCD, 0x88DC, 0xDCCE, 0x8913, 0xDCCF, 0x8B5C, 0xDCD0, 0x8F14, 0xDCD1, 0x4F0F, 0xDCD2, 0x50D5, 0xDCD3, 0x5310, 0xDCD4, 0x535C, 0xDCD5, 0x5B93, 0xDCD6, 0x5FA9, 0xDCD7, 0x670D, 0xDCD8, 0x798F, 0xDCD9, 0x8179, 0xDCDA, 0x832F, 0xDCDB, 0x8514, 0xDCDC, 0x8907, 0xDCDD, 0x8986, 0xDCDE, 0x8F39, 0xDCDF, 0x8F3B, 0xDCE0, 0x99A5, 0xDCE1, 0x9C12, 0xDCE2, 0x672C, 0xDCE3, 0x4E76, 0xDCE4, 0x4FF8, 0xDCE5, 0x5949, 0xDCE6, 0x5C01, 0xDCE7, 0x5CEF, 0xDCE8, 0x5CF0, 0xDCE9, 0x6367, 0xDCEA, 0x68D2, 0xDCEB, 0x70FD, 0xDCEC, 0x71A2, 0xDCED, 0x742B, 0xDCEE, 0x7E2B, 0xDCEF, 0x84EC, 0xDCF0, 0x8702, 0xDCF1, 0x9022, 0xDCF2, 0x92D2, 0xDCF3, 0x9CF3, 0xDCF4, 0x4E0D, 0xDCF5, 0x4ED8, 0xDCF6, 0x4FEF, 0xDCF7, 0x5085, 0xDCF8, 0x5256, 0xDCF9, 0x526F, 0xDCFA, 0x5426, 0xDCFB, 0x5490, 0xDCFC, 0x57E0, 0xDCFD, 0x592B, 0xDCFE, 0x5A66, 0xDDA1, 0x5B5A, 0xDDA2, 0x5B75, 0xDDA3, 0x5BCC, 0xDDA4, 0x5E9C, 0xDDA5, 0xF966, 0xDDA6, 0x6276, 0xDDA7, 0x6577, 0xDDA8, 0x65A7, 0xDDA9, 0x6D6E, 0xDDAA, 0x6EA5, 0xDDAB, 0x7236, 0xDDAC, 0x7B26, 0xDDAD, 0x7C3F, 0xDDAE, 0x7F36, 0xDDAF, 0x8150, 0xDDB0, 0x8151, 0xDDB1, 0x819A, 0xDDB2, 0x8240, 0xDDB3, 0x8299, 0xDDB4, 0x83A9, 0xDDB5, 0x8A03, 0xDDB6, 0x8CA0, 0xDDB7, 0x8CE6, 0xDDB8, 0x8CFB, 0xDDB9, 0x8D74, 0xDDBA, 0x8DBA, 0xDDBB, 0x90E8, 0xDDBC, 0x91DC, 0xDDBD, 0x961C, 0xDDBE, 0x9644, 0xDDBF, 0x99D9, 0xDDC0, 0x9CE7, 0xDDC1, 0x5317, 0xDDC2, 0x5206, 0xDDC3, 0x5429, 0xDDC4, 0x5674, 0xDDC5, 0x58B3, 0xDDC6, 0x5954, 0xDDC7, 0x596E, 0xDDC8, 0x5FFF, 0xDDC9, 0x61A4, 0xDDCA, 0x626E, 0xDDCB, 0x6610, 0xDDCC, 0x6C7E, 0xDDCD, 0x711A, 0xDDCE, 0x76C6, 0xDDCF, 0x7C89, 0xDDD0, 0x7CDE, 0xDDD1, 0x7D1B, 0xDDD2, 0x82AC, 0xDDD3, 0x8CC1, 0xDDD4, 0x96F0, 0xDDD5, 0xF967, 0xDDD6, 0x4F5B, 0xDDD7, 0x5F17, 0xDDD8, 0x5F7F, 0xDDD9, 0x62C2, 0xDDDA, 0x5D29, 0xDDDB, 0x670B, 0xDDDC, 0x68DA, 0xDDDD, 0x787C, 0xDDDE, 0x7E43, 0xDDDF, 0x9D6C, 0xDDE0, 0x4E15, 0xDDE1, 0x5099, 0xDDE2, 0x5315, 0xDDE3, 0x532A, 0xDDE4, 0x5351, 0xDDE5, 0x5983, 0xDDE6, 0x5A62, 0xDDE7, 0x5E87, 0xDDE8, 0x60B2, 0xDDE9, 0x618A, 0xDDEA, 0x6249, 0xDDEB, 0x6279, 0xDDEC, 0x6590, 0xDDED, 0x6787, 0xDDEE, 0x69A7, 0xDDEF, 0x6BD4, 0xDDF0, 0x6BD6, 0xDDF1, 0x6BD7, 0xDDF2, 0x6BD8, 0xDDF3, 0x6CB8, 0xDDF4, 0xF968, 0xDDF5, 0x7435, 0xDDF6, 0x75FA, 0xDDF7, 0x7812, 0xDDF8, 0x7891, 0xDDF9, 0x79D5, 0xDDFA, 0x79D8, 0xDDFB, 0x7C83, 0xDDFC, 0x7DCB, 0xDDFD, 0x7FE1, 0xDDFE, 0x80A5, 0xDEA1, 0x813E, 0xDEA2, 0x81C2, 0xDEA3, 0x83F2, 0xDEA4, 0x871A, 0xDEA5, 0x88E8, 0xDEA6, 0x8AB9, 0xDEA7, 0x8B6C, 0xDEA8, 0x8CBB, 0xDEA9, 0x9119, 0xDEAA, 0x975E, 0xDEAB, 0x98DB, 0xDEAC, 0x9F3B, 0xDEAD, 0x56AC, 0xDEAE, 0x5B2A, 0xDEAF, 0x5F6C, 0xDEB0, 0x658C, 0xDEB1, 0x6AB3, 0xDEB2, 0x6BAF, 0xDEB3, 0x6D5C, 0xDEB4, 0x6FF1, 0xDEB5, 0x7015, 0xDEB6, 0x725D, 0xDEB7, 0x73AD, 0xDEB8, 0x8CA7, 0xDEB9, 0x8CD3, 0xDEBA, 0x983B, 0xDEBB, 0x6191, 0xDEBC, 0x6C37, 0xDEBD, 0x8058, 0xDEBE, 0x9A01, 0xDEBF, 0x4E4D, 0xDEC0, 0x4E8B, 0xDEC1, 0x4E9B, 0xDEC2, 0x4ED5, 0xDEC3, 0x4F3A, 0xDEC4, 0x4F3C, 0xDEC5, 0x4F7F, 0xDEC6, 0x4FDF, 0xDEC7, 0x50FF, 0xDEC8, 0x53F2, 0xDEC9, 0x53F8, 0xDECA, 0x5506, 0xDECB, 0x55E3, 0xDECC, 0x56DB, 0xDECD, 0x58EB, 0xDECE, 0x5962, 0xDECF, 0x5A11, 0xDED0, 0x5BEB, 0xDED1, 0x5BFA, 0xDED2, 0x5C04, 0xDED3, 0x5DF3, 0xDED4, 0x5E2B, 0xDED5, 0x5F99, 0xDED6, 0x601D, 0xDED7, 0x6368, 0xDED8, 0x659C, 0xDED9, 0x65AF, 0xDEDA, 0x67F6, 0xDEDB, 0x67FB, 0xDEDC, 0x68AD, 0xDEDD, 0x6B7B, 0xDEDE, 0x6C99, 0xDEDF, 0x6CD7, 0xDEE0, 0x6E23, 0xDEE1, 0x7009, 0xDEE2, 0x7345, 0xDEE3, 0x7802, 0xDEE4, 0x793E, 0xDEE5, 0x7940, 0xDEE6, 0x7960, 0xDEE7, 0x79C1, 0xDEE8, 0x7BE9, 0xDEE9, 0x7D17, 0xDEEA, 0x7D72, 0xDEEB, 0x8086, 0xDEEC, 0x820D, 0xDEED, 0x838E, 0xDEEE, 0x84D1, 0xDEEF, 0x86C7, 0xDEF0, 0x88DF, 0xDEF1, 0x8A50, 0xDEF2, 0x8A5E, 0xDEF3, 0x8B1D, 0xDEF4, 0x8CDC, 0xDEF5, 0x8D66, 0xDEF6, 0x8FAD, 0xDEF7, 0x90AA, 0xDEF8, 0x98FC, 0xDEF9, 0x99DF, 0xDEFA, 0x9E9D, 0xDEFB, 0x524A, 0xDEFC, 0xF969, 0xDEFD, 0x6714, 0xDEFE, 0xF96A, 0xDFA1, 0x5098, 0xDFA2, 0x522A, 0xDFA3, 0x5C71, 0xDFA4, 0x6563, 0xDFA5, 0x6C55, 0xDFA6, 0x73CA, 0xDFA7, 0x7523, 0xDFA8, 0x759D, 0xDFA9, 0x7B97, 0xDFAA, 0x849C, 0xDFAB, 0x9178, 0xDFAC, 0x9730, 0xDFAD, 0x4E77, 0xDFAE, 0x6492, 0xDFAF, 0x6BBA, 0xDFB0, 0x715E, 0xDFB1, 0x85A9, 0xDFB2, 0x4E09, 0xDFB3, 0xF96B, 0xDFB4, 0x6749, 0xDFB5, 0x68EE, 0xDFB6, 0x6E17, 0xDFB7, 0x829F, 0xDFB8, 0x8518, 0xDFB9, 0x886B, 0xDFBA, 0x63F7, 0xDFBB, 0x6F81, 0xDFBC, 0x9212, 0xDFBD, 0x98AF, 0xDFBE, 0x4E0A, 0xDFBF, 0x50B7, 0xDFC0, 0x50CF, 0xDFC1, 0x511F, 0xDFC2, 0x5546, 0xDFC3, 0x55AA, 0xDFC4, 0x5617, 0xDFC5, 0x5B40, 0xDFC6, 0x5C19, 0xDFC7, 0x5CE0, 0xDFC8, 0x5E38, 0xDFC9, 0x5E8A, 0xDFCA, 0x5EA0, 0xDFCB, 0x5EC2, 0xDFCC, 0x60F3, 0xDFCD, 0x6851, 0xDFCE, 0x6A61, 0xDFCF, 0x6E58, 0xDFD0, 0x723D, 0xDFD1, 0x7240, 0xDFD2, 0x72C0, 0xDFD3, 0x76F8, 0xDFD4, 0x7965, 0xDFD5, 0x7BB1, 0xDFD6, 0x7FD4, 0xDFD7, 0x88F3, 0xDFD8, 0x89F4, 0xDFD9, 0x8A73, 0xDFDA, 0x8C61, 0xDFDB, 0x8CDE, 0xDFDC, 0x971C, 0xDFDD, 0x585E, 0xDFDE, 0x74BD, 0xDFDF, 0x8CFD, 0xDFE0, 0x55C7, 0xDFE1, 0xF96C, 0xDFE2, 0x7A61, 0xDFE3, 0x7D22, 0xDFE4, 0x8272, 0xDFE5, 0x7272, 0xDFE6, 0x751F, 0xDFE7, 0x7525, 0xDFE8, 0xF96D, 0xDFE9, 0x7B19, 0xDFEA, 0x5885, 0xDFEB, 0x58FB, 0xDFEC, 0x5DBC, 0xDFED, 0x5E8F, 0xDFEE, 0x5EB6, 0xDFEF, 0x5F90, 0xDFF0, 0x6055, 0xDFF1, 0x6292, 0xDFF2, 0x637F, 0xDFF3, 0x654D, 0xDFF4, 0x6691, 0xDFF5, 0x66D9, 0xDFF6, 0x66F8, 0xDFF7, 0x6816, 0xDFF8, 0x68F2, 0xDFF9, 0x7280, 0xDFFA, 0x745E, 0xDFFB, 0x7B6E, 0xDFFC, 0x7D6E, 0xDFFD, 0x7DD6, 0xDFFE, 0x7F72, 0xE0A1, 0x80E5, 0xE0A2, 0x8212, 0xE0A3, 0x85AF, 0xE0A4, 0x897F, 0xE0A5, 0x8A93, 0xE0A6, 0x901D, 0xE0A7, 0x92E4, 0xE0A8, 0x9ECD, 0xE0A9, 0x9F20, 0xE0AA, 0x5915, 0xE0AB, 0x596D, 0xE0AC, 0x5E2D, 0xE0AD, 0x60DC, 0xE0AE, 0x6614, 0xE0AF, 0x6673, 0xE0B0, 0x6790, 0xE0B1, 0x6C50, 0xE0B2, 0x6DC5, 0xE0B3, 0x6F5F, 0xE0B4, 0x77F3, 0xE0B5, 0x78A9, 0xE0B6, 0x84C6, 0xE0B7, 0x91CB, 0xE0B8, 0x932B, 0xE0B9, 0x4ED9, 0xE0BA, 0x50CA, 0xE0BB, 0x5148, 0xE0BC, 0x5584, 0xE0BD, 0x5B0B, 0xE0BE, 0x5BA3, 0xE0BF, 0x6247, 0xE0C0, 0x657E, 0xE0C1, 0x65CB, 0xE0C2, 0x6E32, 0xE0C3, 0x717D, 0xE0C4, 0x7401, 0xE0C5, 0x7444, 0xE0C6, 0x7487, 0xE0C7, 0x74BF, 0xE0C8, 0x766C, 0xE0C9, 0x79AA, 0xE0CA, 0x7DDA, 0xE0CB, 0x7E55, 0xE0CC, 0x7FA8, 0xE0CD, 0x817A, 0xE0CE, 0x81B3, 0xE0CF, 0x8239, 0xE0D0, 0x861A, 0xE0D1, 0x87EC, 0xE0D2, 0x8A75, 0xE0D3, 0x8DE3, 0xE0D4, 0x9078, 0xE0D5, 0x9291, 0xE0D6, 0x9425, 0xE0D7, 0x994D, 0xE0D8, 0x9BAE, 0xE0D9, 0x5368, 0xE0DA, 0x5C51, 0xE0DB, 0x6954, 0xE0DC, 0x6CC4, 0xE0DD, 0x6D29, 0xE0DE, 0x6E2B, 0xE0DF, 0x820C, 0xE0E0, 0x859B, 0xE0E1, 0x893B, 0xE0E2, 0x8A2D, 0xE0E3, 0x8AAA, 0xE0E4, 0x96EA, 0xE0E5, 0x9F67, 0xE0E6, 0x5261, 0xE0E7, 0x66B9, 0xE0E8, 0x6BB2, 0xE0E9, 0x7E96, 0xE0EA, 0x87FE, 0xE0EB, 0x8D0D, 0xE0EC, 0x9583, 0xE0ED, 0x965D, 0xE0EE, 0x651D, 0xE0EF, 0x6D89, 0xE0F0, 0x71EE, 0xE0F1, 0xF96E, 0xE0F2, 0x57CE, 0xE0F3, 0x59D3, 0xE0F4, 0x5BAC, 0xE0F5, 0x6027, 0xE0F6, 0x60FA, 0xE0F7, 0x6210, 0xE0F8, 0x661F, 0xE0F9, 0x665F, 0xE0FA, 0x7329, 0xE0FB, 0x73F9, 0xE0FC, 0x76DB, 0xE0FD, 0x7701, 0xE0FE, 0x7B6C, 0xE1A1, 0x8056, 0xE1A2, 0x8072, 0xE1A3, 0x8165, 0xE1A4, 0x8AA0, 0xE1A5, 0x9192, 0xE1A6, 0x4E16, 0xE1A7, 0x52E2, 0xE1A8, 0x6B72, 0xE1A9, 0x6D17, 0xE1AA, 0x7A05, 0xE1AB, 0x7B39, 0xE1AC, 0x7D30, 0xE1AD, 0xF96F, 0xE1AE, 0x8CB0, 0xE1AF, 0x53EC, 0xE1B0, 0x562F, 0xE1B1, 0x5851, 0xE1B2, 0x5BB5, 0xE1B3, 0x5C0F, 0xE1B4, 0x5C11, 0xE1B5, 0x5DE2, 0xE1B6, 0x6240, 0xE1B7, 0x6383, 0xE1B8, 0x6414, 0xE1B9, 0x662D, 0xE1BA, 0x68B3, 0xE1BB, 0x6CBC, 0xE1BC, 0x6D88, 0xE1BD, 0x6EAF, 0xE1BE, 0x701F, 0xE1BF, 0x70A4, 0xE1C0, 0x71D2, 0xE1C1, 0x7526, 0xE1C2, 0x758F, 0xE1C3, 0x758E, 0xE1C4, 0x7619, 0xE1C5, 0x7B11, 0xE1C6, 0x7BE0, 0xE1C7, 0x7C2B, 0xE1C8, 0x7D20, 0xE1C9, 0x7D39, 0xE1CA, 0x852C, 0xE1CB, 0x856D, 0xE1CC, 0x8607, 0xE1CD, 0x8A34, 0xE1CE, 0x900D, 0xE1CF, 0x9061, 0xE1D0, 0x90B5, 0xE1D1, 0x92B7, 0xE1D2, 0x97F6, 0xE1D3, 0x9A37, 0xE1D4, 0x4FD7, 0xE1D5, 0x5C6C, 0xE1D6, 0x675F, 0xE1D7, 0x6D91, 0xE1D8, 0x7C9F, 0xE1D9, 0x7E8C, 0xE1DA, 0x8B16, 0xE1DB, 0x8D16, 0xE1DC, 0x901F, 0xE1DD, 0x5B6B, 0xE1DE, 0x5DFD, 0xE1DF, 0x640D, 0xE1E0, 0x84C0, 0xE1E1, 0x905C, 0xE1E2, 0x98E1, 0xE1E3, 0x7387, 0xE1E4, 0x5B8B, 0xE1E5, 0x609A, 0xE1E6, 0x677E, 0xE1E7, 0x6DDE, 0xE1E8, 0x8A1F, 0xE1E9, 0x8AA6, 0xE1EA, 0x9001, 0xE1EB, 0x980C, 0xE1EC, 0x5237, 0xE1ED, 0xF970, 0xE1EE, 0x7051, 0xE1EF, 0x788E, 0xE1F0, 0x9396, 0xE1F1, 0x8870, 0xE1F2, 0x91D7, 0xE1F3, 0x4FEE, 0xE1F4, 0x53D7, 0xE1F5, 0x55FD, 0xE1F6, 0x56DA, 0xE1F7, 0x5782, 0xE1F8, 0x58FD, 0xE1F9, 0x5AC2, 0xE1FA, 0x5B88, 0xE1FB, 0x5CAB, 0xE1FC, 0x5CC0, 0xE1FD, 0x5E25, 0xE1FE, 0x6101, 0xE2A1, 0x620D, 0xE2A2, 0x624B, 0xE2A3, 0x6388, 0xE2A4, 0x641C, 0xE2A5, 0x6536, 0xE2A6, 0x6578, 0xE2A7, 0x6A39, 0xE2A8, 0x6B8A, 0xE2A9, 0x6C34, 0xE2AA, 0x6D19, 0xE2AB, 0x6F31, 0xE2AC, 0x71E7, 0xE2AD, 0x72E9, 0xE2AE, 0x7378, 0xE2AF, 0x7407, 0xE2B0, 0x74B2, 0xE2B1, 0x7626, 0xE2B2, 0x7761, 0xE2B3, 0x79C0, 0xE2B4, 0x7A57, 0xE2B5, 0x7AEA, 0xE2B6, 0x7CB9, 0xE2B7, 0x7D8F, 0xE2B8, 0x7DAC, 0xE2B9, 0x7E61, 0xE2BA, 0x7F9E, 0xE2BB, 0x8129, 0xE2BC, 0x8331, 0xE2BD, 0x8490, 0xE2BE, 0x84DA, 0xE2BF, 0x85EA, 0xE2C0, 0x8896, 0xE2C1, 0x8AB0, 0xE2C2, 0x8B90, 0xE2C3, 0x8F38, 0xE2C4, 0x9042, 0xE2C5, 0x9083, 0xE2C6, 0x916C, 0xE2C7, 0x9296, 0xE2C8, 0x92B9, 0xE2C9, 0x968B, 0xE2CA, 0x96A7, 0xE2CB, 0x96A8, 0xE2CC, 0x96D6, 0xE2CD, 0x9700, 0xE2CE, 0x9808, 0xE2CF, 0x9996, 0xE2D0, 0x9AD3, 0xE2D1, 0x9B1A, 0xE2D2, 0x53D4, 0xE2D3, 0x587E, 0xE2D4, 0x5919, 0xE2D5, 0x5B70, 0xE2D6, 0x5BBF, 0xE2D7, 0x6DD1, 0xE2D8, 0x6F5A, 0xE2D9, 0x719F, 0xE2DA, 0x7421, 0xE2DB, 0x74B9, 0xE2DC, 0x8085, 0xE2DD, 0x83FD, 0xE2DE, 0x5DE1, 0xE2DF, 0x5F87, 0xE2E0, 0x5FAA, 0xE2E1, 0x6042, 0xE2E2, 0x65EC, 0xE2E3, 0x6812, 0xE2E4, 0x696F, 0xE2E5, 0x6A53, 0xE2E6, 0x6B89, 0xE2E7, 0x6D35, 0xE2E8, 0x6DF3, 0xE2E9, 0x73E3, 0xE2EA, 0x76FE, 0xE2EB, 0x77AC, 0xE2EC, 0x7B4D, 0xE2ED, 0x7D14, 0xE2EE, 0x8123, 0xE2EF, 0x821C, 0xE2F0, 0x8340, 0xE2F1, 0x84F4, 0xE2F2, 0x8563, 0xE2F3, 0x8A62, 0xE2F4, 0x8AC4, 0xE2F5, 0x9187, 0xE2F6, 0x931E, 0xE2F7, 0x9806, 0xE2F8, 0x99B4, 0xE2F9, 0x620C, 0xE2FA, 0x8853, 0xE2FB, 0x8FF0, 0xE2FC, 0x9265, 0xE2FD, 0x5D07, 0xE2FE, 0x5D27, 0xE3A1, 0x5D69, 0xE3A2, 0x745F, 0xE3A3, 0x819D, 0xE3A4, 0x8768, 0xE3A5, 0x6FD5, 0xE3A6, 0x62FE, 0xE3A7, 0x7FD2, 0xE3A8, 0x8936, 0xE3A9, 0x8972, 0xE3AA, 0x4E1E, 0xE3AB, 0x4E58, 0xE3AC, 0x50E7, 0xE3AD, 0x52DD, 0xE3AE, 0x5347, 0xE3AF, 0x627F, 0xE3B0, 0x6607, 0xE3B1, 0x7E69, 0xE3B2, 0x8805, 0xE3B3, 0x965E, 0xE3B4, 0x4F8D, 0xE3B5, 0x5319, 0xE3B6, 0x5636, 0xE3B7, 0x59CB, 0xE3B8, 0x5AA4, 0xE3B9, 0x5C38, 0xE3BA, 0x5C4E, 0xE3BB, 0x5C4D, 0xE3BC, 0x5E02, 0xE3BD, 0x5F11, 0xE3BE, 0x6043, 0xE3BF, 0x65BD, 0xE3C0, 0x662F, 0xE3C1, 0x6642, 0xE3C2, 0x67BE, 0xE3C3, 0x67F4, 0xE3C4, 0x731C, 0xE3C5, 0x77E2, 0xE3C6, 0x793A, 0xE3C7, 0x7FC5, 0xE3C8, 0x8494, 0xE3C9, 0x84CD, 0xE3CA, 0x8996, 0xE3CB, 0x8A66, 0xE3CC, 0x8A69, 0xE3CD, 0x8AE1, 0xE3CE, 0x8C55, 0xE3CF, 0x8C7A, 0xE3D0, 0x57F4, 0xE3D1, 0x5BD4, 0xE3D2, 0x5F0F, 0xE3D3, 0x606F, 0xE3D4, 0x62ED, 0xE3D5, 0x690D, 0xE3D6, 0x6B96, 0xE3D7, 0x6E5C, 0xE3D8, 0x7184, 0xE3D9, 0x7BD2, 0xE3DA, 0x8755, 0xE3DB, 0x8B58, 0xE3DC, 0x8EFE, 0xE3DD, 0x98DF, 0xE3DE, 0x98FE, 0xE3DF, 0x4F38, 0xE3E0, 0x4F81, 0xE3E1, 0x4FE1, 0xE3E2, 0x547B, 0xE3E3, 0x5A20, 0xE3E4, 0x5BB8, 0xE3E5, 0x613C, 0xE3E6, 0x65B0, 0xE3E7, 0x6668, 0xE3E8, 0x71FC, 0xE3E9, 0x7533, 0xE3EA, 0x795E, 0xE3EB, 0x7D33, 0xE3EC, 0x814E, 0xE3ED, 0x81E3, 0xE3EE, 0x8398, 0xE3EF, 0x85AA, 0xE3F0, 0x85CE, 0xE3F1, 0x8703, 0xE3F2, 0x8A0A, 0xE3F3, 0x8EAB, 0xE3F4, 0x8F9B, 0xE3F5, 0xF971, 0xE3F6, 0x8FC5, 0xE3F7, 0x5931, 0xE3F8, 0x5BA4, 0xE3F9, 0x5BE6, 0xE3FA, 0x6089, 0xE3FB, 0x5BE9, 0xE3FC, 0x5C0B, 0xE3FD, 0x5FC3, 0xE3FE, 0x6C81, 0xE4A1, 0xF972, 0xE4A2, 0x6DF1, 0xE4A3, 0x700B, 0xE4A4, 0x751A, 0xE4A5, 0x82AF, 0xE4A6, 0x8AF6, 0xE4A7, 0x4EC0, 0xE4A8, 0x5341, 0xE4A9, 0xF973, 0xE4AA, 0x96D9, 0xE4AB, 0x6C0F, 0xE4AC, 0x4E9E, 0xE4AD, 0x4FC4, 0xE4AE, 0x5152, 0xE4AF, 0x555E, 0xE4B0, 0x5A25, 0xE4B1, 0x5CE8, 0xE4B2, 0x6211, 0xE4B3, 0x7259, 0xE4B4, 0x82BD, 0xE4B5, 0x83AA, 0xE4B6, 0x86FE, 0xE4B7, 0x8859, 0xE4B8, 0x8A1D, 0xE4B9, 0x963F, 0xE4BA, 0x96C5, 0xE4BB, 0x9913, 0xE4BC, 0x9D09, 0xE4BD, 0x9D5D, 0xE4BE, 0x580A, 0xE4BF, 0x5CB3, 0xE4C0, 0x5DBD, 0xE4C1, 0x5E44, 0xE4C2, 0x60E1, 0xE4C3, 0x6115, 0xE4C4, 0x63E1, 0xE4C5, 0x6A02, 0xE4C6, 0x6E25, 0xE4C7, 0x9102, 0xE4C8, 0x9354, 0xE4C9, 0x984E, 0xE4CA, 0x9C10, 0xE4CB, 0x9F77, 0xE4CC, 0x5B89, 0xE4CD, 0x5CB8, 0xE4CE, 0x6309, 0xE4CF, 0x664F, 0xE4D0, 0x6848, 0xE4D1, 0x773C, 0xE4D2, 0x96C1, 0xE4D3, 0x978D, 0xE4D4, 0x9854, 0xE4D5, 0x9B9F, 0xE4D6, 0x65A1, 0xE4D7, 0x8B01, 0xE4D8, 0x8ECB, 0xE4D9, 0x95BC, 0xE4DA, 0x5535, 0xE4DB, 0x5CA9, 0xE4DC, 0x5DD6, 0xE4DD, 0x5EB5, 0xE4DE, 0x6697, 0xE4DF, 0x764C, 0xE4E0, 0x83F4, 0xE4E1, 0x95C7, 0xE4E2, 0x58D3, 0xE4E3, 0x62BC, 0xE4E4, 0x72CE, 0xE4E5, 0x9D28, 0xE4E6, 0x4EF0, 0xE4E7, 0x592E, 0xE4E8, 0x600F, 0xE4E9, 0x663B, 0xE4EA, 0x6B83, 0xE4EB, 0x79E7, 0xE4EC, 0x9D26, 0xE4ED, 0x5393, 0xE4EE, 0x54C0, 0xE4EF, 0x57C3, 0xE4F0, 0x5D16, 0xE4F1, 0x611B, 0xE4F2, 0x66D6, 0xE4F3, 0x6DAF, 0xE4F4, 0x788D, 0xE4F5, 0x827E, 0xE4F6, 0x9698, 0xE4F7, 0x9744, 0xE4F8, 0x5384, 0xE4F9, 0x627C, 0xE4FA, 0x6396, 0xE4FB, 0x6DB2, 0xE4FC, 0x7E0A, 0xE4FD, 0x814B, 0xE4FE, 0x984D, 0xE5A1, 0x6AFB, 0xE5A2, 0x7F4C, 0xE5A3, 0x9DAF, 0xE5A4, 0x9E1A, 0xE5A5, 0x4E5F, 0xE5A6, 0x503B, 0xE5A7, 0x51B6, 0xE5A8, 0x591C, 0xE5A9, 0x60F9, 0xE5AA, 0x63F6, 0xE5AB, 0x6930, 0xE5AC, 0x723A, 0xE5AD, 0x8036, 0xE5AE, 0xF974, 0xE5AF, 0x91CE, 0xE5B0, 0x5F31, 0xE5B1, 0xF975, 0xE5B2, 0xF976, 0xE5B3, 0x7D04, 0xE5B4, 0x82E5, 0xE5B5, 0x846F, 0xE5B6, 0x84BB, 0xE5B7, 0x85E5, 0xE5B8, 0x8E8D, 0xE5B9, 0xF977, 0xE5BA, 0x4F6F, 0xE5BB, 0xF978, 0xE5BC, 0xF979, 0xE5BD, 0x58E4, 0xE5BE, 0x5B43, 0xE5BF, 0x6059, 0xE5C0, 0x63DA, 0xE5C1, 0x6518, 0xE5C2, 0x656D, 0xE5C3, 0x6698, 0xE5C4, 0xF97A, 0xE5C5, 0x694A, 0xE5C6, 0x6A23, 0xE5C7, 0x6D0B, 0xE5C8, 0x7001, 0xE5C9, 0x716C, 0xE5CA, 0x75D2, 0xE5CB, 0x760D, 0xE5CC, 0x79B3, 0xE5CD, 0x7A70, 0xE5CE, 0xF97B, 0xE5CF, 0x7F8A, 0xE5D0, 0xF97C, 0xE5D1, 0x8944, 0xE5D2, 0xF97D, 0xE5D3, 0x8B93, 0xE5D4, 0x91C0, 0xE5D5, 0x967D, 0xE5D6, 0xF97E, 0xE5D7, 0x990A, 0xE5D8, 0x5704, 0xE5D9, 0x5FA1, 0xE5DA, 0x65BC, 0xE5DB, 0x6F01, 0xE5DC, 0x7600, 0xE5DD, 0x79A6, 0xE5DE, 0x8A9E, 0xE5DF, 0x99AD, 0xE5E0, 0x9B5A, 0xE5E1, 0x9F6C, 0xE5E2, 0x5104, 0xE5E3, 0x61B6, 0xE5E4, 0x6291, 0xE5E5, 0x6A8D, 0xE5E6, 0x81C6, 0xE5E7, 0x5043, 0xE5E8, 0x5830, 0xE5E9, 0x5F66, 0xE5EA, 0x7109, 0xE5EB, 0x8A00, 0xE5EC, 0x8AFA, 0xE5ED, 0x5B7C, 0xE5EE, 0x8616, 0xE5EF, 0x4FFA, 0xE5F0, 0x513C, 0xE5F1, 0x56B4, 0xE5F2, 0x5944, 0xE5F3, 0x63A9, 0xE5F4, 0x6DF9, 0xE5F5, 0x5DAA, 0xE5F6, 0x696D, 0xE5F7, 0x5186, 0xE5F8, 0x4E88, 0xE5F9, 0x4F59, 0xE5FA, 0xF97F, 0xE5FB, 0xF980, 0xE5FC, 0xF981, 0xE5FD, 0x5982, 0xE5FE, 0xF982, 0xE6A1, 0xF983, 0xE6A2, 0x6B5F, 0xE6A3, 0x6C5D, 0xE6A4, 0xF984, 0xE6A5, 0x74B5, 0xE6A6, 0x7916, 0xE6A7, 0xF985, 0xE6A8, 0x8207, 0xE6A9, 0x8245, 0xE6AA, 0x8339, 0xE6AB, 0x8F3F, 0xE6AC, 0x8F5D, 0xE6AD, 0xF986, 0xE6AE, 0x9918, 0xE6AF, 0xF987, 0xE6B0, 0xF988, 0xE6B1, 0xF989, 0xE6B2, 0x4EA6, 0xE6B3, 0xF98A, 0xE6B4, 0x57DF, 0xE6B5, 0x5F79, 0xE6B6, 0x6613, 0xE6B7, 0xF98B, 0xE6B8, 0xF98C, 0xE6B9, 0x75AB, 0xE6BA, 0x7E79, 0xE6BB, 0x8B6F, 0xE6BC, 0xF98D, 0xE6BD, 0x9006, 0xE6BE, 0x9A5B, 0xE6BF, 0x56A5, 0xE6C0, 0x5827, 0xE6C1, 0x59F8, 0xE6C2, 0x5A1F, 0xE6C3, 0x5BB4, 0xE6C4, 0xF98E, 0xE6C5, 0x5EF6, 0xE6C6, 0xF98F, 0xE6C7, 0xF990, 0xE6C8, 0x6350, 0xE6C9, 0x633B, 0xE6CA, 0xF991, 0xE6CB, 0x693D, 0xE6CC, 0x6C87, 0xE6CD, 0x6CBF, 0xE6CE, 0x6D8E, 0xE6CF, 0x6D93, 0xE6D0, 0x6DF5, 0xE6D1, 0x6F14, 0xE6D2, 0xF992, 0xE6D3, 0x70DF, 0xE6D4, 0x7136, 0xE6D5, 0x7159, 0xE6D6, 0xF993, 0xE6D7, 0x71C3, 0xE6D8, 0x71D5, 0xE6D9, 0xF994, 0xE6DA, 0x784F, 0xE6DB, 0x786F, 0xE6DC, 0xF995, 0xE6DD, 0x7B75, 0xE6DE, 0x7DE3, 0xE6DF, 0xF996, 0xE6E0, 0x7E2F, 0xE6E1, 0xF997, 0xE6E2, 0x884D, 0xE6E3, 0x8EDF, 0xE6E4, 0xF998, 0xE6E5, 0xF999, 0xE6E6, 0xF99A, 0xE6E7, 0x925B, 0xE6E8, 0xF99B, 0xE6E9, 0x9CF6, 0xE6EA, 0xF99C, 0xE6EB, 0xF99D, 0xE6EC, 0xF99E, 0xE6ED, 0x6085, 0xE6EE, 0x6D85, 0xE6EF, 0xF99F, 0xE6F0, 0x71B1, 0xE6F1, 0xF9A0, 0xE6F2, 0xF9A1, 0xE6F3, 0x95B1, 0xE6F4, 0x53AD, 0xE6F5, 0xF9A2, 0xE6F6, 0xF9A3, 0xE6F7, 0xF9A4, 0xE6F8, 0x67D3, 0xE6F9, 0xF9A5, 0xE6FA, 0x708E, 0xE6FB, 0x7130, 0xE6FC, 0x7430, 0xE6FD, 0x8276, 0xE6FE, 0x82D2, 0xE7A1, 0xF9A6, 0xE7A2, 0x95BB, 0xE7A3, 0x9AE5, 0xE7A4, 0x9E7D, 0xE7A5, 0x66C4, 0xE7A6, 0xF9A7, 0xE7A7, 0x71C1, 0xE7A8, 0x8449, 0xE7A9, 0xF9A8, 0xE7AA, 0xF9A9, 0xE7AB, 0x584B, 0xE7AC, 0xF9AA, 0xE7AD, 0xF9AB, 0xE7AE, 0x5DB8, 0xE7AF, 0x5F71, 0xE7B0, 0xF9AC, 0xE7B1, 0x6620, 0xE7B2, 0x668E, 0xE7B3, 0x6979, 0xE7B4, 0x69AE, 0xE7B5, 0x6C38, 0xE7B6, 0x6CF3, 0xE7B7, 0x6E36, 0xE7B8, 0x6F41, 0xE7B9, 0x6FDA, 0xE7BA, 0x701B, 0xE7BB, 0x702F, 0xE7BC, 0x7150, 0xE7BD, 0x71DF, 0xE7BE, 0x7370, 0xE7BF, 0xF9AD, 0xE7C0, 0x745B, 0xE7C1, 0xF9AE, 0xE7C2, 0x74D4, 0xE7C3, 0x76C8, 0xE7C4, 0x7A4E, 0xE7C5, 0x7E93, 0xE7C6, 0xF9AF, 0xE7C7, 0xF9B0, 0xE7C8, 0x82F1, 0xE7C9, 0x8A60, 0xE7CA, 0x8FCE, 0xE7CB, 0xF9B1, 0xE7CC, 0x9348, 0xE7CD, 0xF9B2, 0xE7CE, 0x9719, 0xE7CF, 0xF9B3, 0xE7D0, 0xF9B4, 0xE7D1, 0x4E42, 0xE7D2, 0x502A, 0xE7D3, 0xF9B5, 0xE7D4, 0x5208, 0xE7D5, 0x53E1, 0xE7D6, 0x66F3, 0xE7D7, 0x6C6D, 0xE7D8, 0x6FCA, 0xE7D9, 0x730A, 0xE7DA, 0x777F, 0xE7DB, 0x7A62, 0xE7DC, 0x82AE, 0xE7DD, 0x85DD, 0xE7DE, 0x8602, 0xE7DF, 0xF9B6, 0xE7E0, 0x88D4, 0xE7E1, 0x8A63, 0xE7E2, 0x8B7D, 0xE7E3, 0x8C6B, 0xE7E4, 0xF9B7, 0xE7E5, 0x92B3, 0xE7E6, 0xF9B8, 0xE7E7, 0x9713, 0xE7E8, 0x9810, 0xE7E9, 0x4E94, 0xE7EA, 0x4F0D, 0xE7EB, 0x4FC9, 0xE7EC, 0x50B2, 0xE7ED, 0x5348, 0xE7EE, 0x543E, 0xE7EF, 0x5433, 0xE7F0, 0x55DA, 0xE7F1, 0x5862, 0xE7F2, 0x58BA, 0xE7F3, 0x5967, 0xE7F4, 0x5A1B, 0xE7F5, 0x5BE4, 0xE7F6, 0x609F, 0xE7F7, 0xF9B9, 0xE7F8, 0x61CA, 0xE7F9, 0x6556, 0xE7FA, 0x65FF, 0xE7FB, 0x6664, 0xE7FC, 0x68A7, 0xE7FD, 0x6C5A, 0xE7FE, 0x6FB3, 0xE8A1, 0x70CF, 0xE8A2, 0x71AC, 0xE8A3, 0x7352, 0xE8A4, 0x7B7D, 0xE8A5, 0x8708, 0xE8A6, 0x8AA4, 0xE8A7, 0x9C32, 0xE8A8, 0x9F07, 0xE8A9, 0x5C4B, 0xE8AA, 0x6C83, 0xE8AB, 0x7344, 0xE8AC, 0x7389, 0xE8AD, 0x923A, 0xE8AE, 0x6EAB, 0xE8AF, 0x7465, 0xE8B0, 0x761F, 0xE8B1, 0x7A69, 0xE8B2, 0x7E15, 0xE8B3, 0x860A, 0xE8B4, 0x5140, 0xE8B5, 0x58C5, 0xE8B6, 0x64C1, 0xE8B7, 0x74EE, 0xE8B8, 0x7515, 0xE8B9, 0x7670, 0xE8BA, 0x7FC1, 0xE8BB, 0x9095, 0xE8BC, 0x96CD, 0xE8BD, 0x9954, 0xE8BE, 0x6E26, 0xE8BF, 0x74E6, 0xE8C0, 0x7AA9, 0xE8C1, 0x7AAA, 0xE8C2, 0x81E5, 0xE8C3, 0x86D9, 0xE8C4, 0x8778, 0xE8C5, 0x8A1B, 0xE8C6, 0x5A49, 0xE8C7, 0x5B8C, 0xE8C8, 0x5B9B, 0xE8C9, 0x68A1, 0xE8CA, 0x6900, 0xE8CB, 0x6D63, 0xE8CC, 0x73A9, 0xE8CD, 0x7413, 0xE8CE, 0x742C, 0xE8CF, 0x7897, 0xE8D0, 0x7DE9, 0xE8D1, 0x7FEB, 0xE8D2, 0x8118, 0xE8D3, 0x8155, 0xE8D4, 0x839E, 0xE8D5, 0x8C4C, 0xE8D6, 0x962E, 0xE8D7, 0x9811, 0xE8D8, 0x66F0, 0xE8D9, 0x5F80, 0xE8DA, 0x65FA, 0xE8DB, 0x6789, 0xE8DC, 0x6C6A, 0xE8DD, 0x738B, 0xE8DE, 0x502D, 0xE8DF, 0x5A03, 0xE8E0, 0x6B6A, 0xE8E1, 0x77EE, 0xE8E2, 0x5916, 0xE8E3, 0x5D6C, 0xE8E4, 0x5DCD, 0xE8E5, 0x7325, 0xE8E6, 0x754F, 0xE8E7, 0xF9BA, 0xE8E8, 0xF9BB, 0xE8E9, 0x50E5, 0xE8EA, 0x51F9, 0xE8EB, 0x582F, 0xE8EC, 0x592D, 0xE8ED, 0x5996, 0xE8EE, 0x59DA, 0xE8EF, 0x5BE5, 0xE8F0, 0xF9BC, 0xE8F1, 0xF9BD, 0xE8F2, 0x5DA2, 0xE8F3, 0x62D7, 0xE8F4, 0x6416, 0xE8F5, 0x6493, 0xE8F6, 0x64FE, 0xE8F7, 0xF9BE, 0xE8F8, 0x66DC, 0xE8F9, 0xF9BF, 0xE8FA, 0x6A48, 0xE8FB, 0xF9C0, 0xE8FC, 0x71FF, 0xE8FD, 0x7464, 0xE8FE, 0xF9C1, 0xE9A1, 0x7A88, 0xE9A2, 0x7AAF, 0xE9A3, 0x7E47, 0xE9A4, 0x7E5E, 0xE9A5, 0x8000, 0xE9A6, 0x8170, 0xE9A7, 0xF9C2, 0xE9A8, 0x87EF, 0xE9A9, 0x8981, 0xE9AA, 0x8B20, 0xE9AB, 0x9059, 0xE9AC, 0xF9C3, 0xE9AD, 0x9080, 0xE9AE, 0x9952, 0xE9AF, 0x617E, 0xE9B0, 0x6B32, 0xE9B1, 0x6D74, 0xE9B2, 0x7E1F, 0xE9B3, 0x8925, 0xE9B4, 0x8FB1, 0xE9B5, 0x4FD1, 0xE9B6, 0x50AD, 0xE9B7, 0x5197, 0xE9B8, 0x52C7, 0xE9B9, 0x57C7, 0xE9BA, 0x5889, 0xE9BB, 0x5BB9, 0xE9BC, 0x5EB8, 0xE9BD, 0x6142, 0xE9BE, 0x6995, 0xE9BF, 0x6D8C, 0xE9C0, 0x6E67, 0xE9C1, 0x6EB6, 0xE9C2, 0x7194, 0xE9C3, 0x7462, 0xE9C4, 0x7528, 0xE9C5, 0x752C, 0xE9C6, 0x8073, 0xE9C7, 0x8338, 0xE9C8, 0x84C9, 0xE9C9, 0x8E0A, 0xE9CA, 0x9394, 0xE9CB, 0x93DE, 0xE9CC, 0xF9C4, 0xE9CD, 0x4E8E, 0xE9CE, 0x4F51, 0xE9CF, 0x5076, 0xE9D0, 0x512A, 0xE9D1, 0x53C8, 0xE9D2, 0x53CB, 0xE9D3, 0x53F3, 0xE9D4, 0x5B87, 0xE9D5, 0x5BD3, 0xE9D6, 0x5C24, 0xE9D7, 0x611A, 0xE9D8, 0x6182, 0xE9D9, 0x65F4, 0xE9DA, 0x725B, 0xE9DB, 0x7397, 0xE9DC, 0x7440, 0xE9DD, 0x76C2, 0xE9DE, 0x7950, 0xE9DF, 0x7991, 0xE9E0, 0x79B9, 0xE9E1, 0x7D06, 0xE9E2, 0x7FBD, 0xE9E3, 0x828B, 0xE9E4, 0x85D5, 0xE9E5, 0x865E, 0xE9E6, 0x8FC2, 0xE9E7, 0x9047, 0xE9E8, 0x90F5, 0xE9E9, 0x91EA, 0xE9EA, 0x9685, 0xE9EB, 0x96E8, 0xE9EC, 0x96E9, 0xE9ED, 0x52D6, 0xE9EE, 0x5F67, 0xE9EF, 0x65ED, 0xE9F0, 0x6631, 0xE9F1, 0x682F, 0xE9F2, 0x715C, 0xE9F3, 0x7A36, 0xE9F4, 0x90C1, 0xE9F5, 0x980A, 0xE9F6, 0x4E91, 0xE9F7, 0xF9C5, 0xE9F8, 0x6A52, 0xE9F9, 0x6B9E, 0xE9FA, 0x6F90, 0xE9FB, 0x7189, 0xE9FC, 0x8018, 0xE9FD, 0x82B8, 0xE9FE, 0x8553, 0xEAA1, 0x904B, 0xEAA2, 0x9695, 0xEAA3, 0x96F2, 0xEAA4, 0x97FB, 0xEAA5, 0x851A, 0xEAA6, 0x9B31, 0xEAA7, 0x4E90, 0xEAA8, 0x718A, 0xEAA9, 0x96C4, 0xEAAA, 0x5143, 0xEAAB, 0x539F, 0xEAAC, 0x54E1, 0xEAAD, 0x5713, 0xEAAE, 0x5712, 0xEAAF, 0x57A3, 0xEAB0, 0x5A9B, 0xEAB1, 0x5AC4, 0xEAB2, 0x5BC3, 0xEAB3, 0x6028, 0xEAB4, 0x613F, 0xEAB5, 0x63F4, 0xEAB6, 0x6C85, 0xEAB7, 0x6D39, 0xEAB8, 0x6E72, 0xEAB9, 0x6E90, 0xEABA, 0x7230, 0xEABB, 0x733F, 0xEABC, 0x7457, 0xEABD, 0x82D1, 0xEABE, 0x8881, 0xEABF, 0x8F45, 0xEAC0, 0x9060, 0xEAC1, 0xF9C6, 0xEAC2, 0x9662, 0xEAC3, 0x9858, 0xEAC4, 0x9D1B, 0xEAC5, 0x6708, 0xEAC6, 0x8D8A, 0xEAC7, 0x925E, 0xEAC8, 0x4F4D, 0xEAC9, 0x5049, 0xEACA, 0x50DE, 0xEACB, 0x5371, 0xEACC, 0x570D, 0xEACD, 0x59D4, 0xEACE, 0x5A01, 0xEACF, 0x5C09, 0xEAD0, 0x6170, 0xEAD1, 0x6690, 0xEAD2, 0x6E2D, 0xEAD3, 0x7232, 0xEAD4, 0x744B, 0xEAD5, 0x7DEF, 0xEAD6, 0x80C3, 0xEAD7, 0x840E, 0xEAD8, 0x8466, 0xEAD9, 0x853F, 0xEADA, 0x875F, 0xEADB, 0x885B, 0xEADC, 0x8918, 0xEADD, 0x8B02, 0xEADE, 0x9055, 0xEADF, 0x97CB, 0xEAE0, 0x9B4F, 0xEAE1, 0x4E73, 0xEAE2, 0x4F91, 0xEAE3, 0x5112, 0xEAE4, 0x516A, 0xEAE5, 0xF9C7, 0xEAE6, 0x552F, 0xEAE7, 0x55A9, 0xEAE8, 0x5B7A, 0xEAE9, 0x5BA5, 0xEAEA, 0x5E7C, 0xEAEB, 0x5E7D, 0xEAEC, 0x5EBE, 0xEAED, 0x60A0, 0xEAEE, 0x60DF, 0xEAEF, 0x6108, 0xEAF0, 0x6109, 0xEAF1, 0x63C4, 0xEAF2, 0x6538, 0xEAF3, 0x6709, 0xEAF4, 0xF9C8, 0xEAF5, 0x67D4, 0xEAF6, 0x67DA, 0xEAF7, 0xF9C9, 0xEAF8, 0x6961, 0xEAF9, 0x6962, 0xEAFA, 0x6CB9, 0xEAFB, 0x6D27, 0xEAFC, 0xF9CA, 0xEAFD, 0x6E38, 0xEAFE, 0xF9CB, 0xEBA1, 0x6FE1, 0xEBA2, 0x7336, 0xEBA3, 0x7337, 0xEBA4, 0xF9CC, 0xEBA5, 0x745C, 0xEBA6, 0x7531, 0xEBA7, 0xF9CD, 0xEBA8, 0x7652, 0xEBA9, 0xF9CE, 0xEBAA, 0xF9CF, 0xEBAB, 0x7DAD, 0xEBAC, 0x81FE, 0xEBAD, 0x8438, 0xEBAE, 0x88D5, 0xEBAF, 0x8A98, 0xEBB0, 0x8ADB, 0xEBB1, 0x8AED, 0xEBB2, 0x8E30, 0xEBB3, 0x8E42, 0xEBB4, 0x904A, 0xEBB5, 0x903E, 0xEBB6, 0x907A, 0xEBB7, 0x9149, 0xEBB8, 0x91C9, 0xEBB9, 0x936E, 0xEBBA, 0xF9D0, 0xEBBB, 0xF9D1, 0xEBBC, 0x5809, 0xEBBD, 0xF9D2, 0xEBBE, 0x6BD3, 0xEBBF, 0x8089, 0xEBC0, 0x80B2, 0xEBC1, 0xF9D3, 0xEBC2, 0xF9D4, 0xEBC3, 0x5141, 0xEBC4, 0x596B, 0xEBC5, 0x5C39, 0xEBC6, 0xF9D5, 0xEBC7, 0xF9D6, 0xEBC8, 0x6F64, 0xEBC9, 0x73A7, 0xEBCA, 0x80E4, 0xEBCB, 0x8D07, 0xEBCC, 0xF9D7, 0xEBCD, 0x9217, 0xEBCE, 0x958F, 0xEBCF, 0xF9D8, 0xEBD0, 0xF9D9, 0xEBD1, 0xF9DA, 0xEBD2, 0xF9DB, 0xEBD3, 0x807F, 0xEBD4, 0x620E, 0xEBD5, 0x701C, 0xEBD6, 0x7D68, 0xEBD7, 0x878D, 0xEBD8, 0xF9DC, 0xEBD9, 0x57A0, 0xEBDA, 0x6069, 0xEBDB, 0x6147, 0xEBDC, 0x6BB7, 0xEBDD, 0x8ABE, 0xEBDE, 0x9280, 0xEBDF, 0x96B1, 0xEBE0, 0x4E59, 0xEBE1, 0x541F, 0xEBE2, 0x6DEB, 0xEBE3, 0x852D, 0xEBE4, 0x9670, 0xEBE5, 0x97F3, 0xEBE6, 0x98EE, 0xEBE7, 0x63D6, 0xEBE8, 0x6CE3, 0xEBE9, 0x9091, 0xEBEA, 0x51DD, 0xEBEB, 0x61C9, 0xEBEC, 0x81BA, 0xEBED, 0x9DF9, 0xEBEE, 0x4F9D, 0xEBEF, 0x501A, 0xEBF0, 0x5100, 0xEBF1, 0x5B9C, 0xEBF2, 0x610F, 0xEBF3, 0x61FF, 0xEBF4, 0x64EC, 0xEBF5, 0x6905, 0xEBF6, 0x6BC5, 0xEBF7, 0x7591, 0xEBF8, 0x77E3, 0xEBF9, 0x7FA9, 0xEBFA, 0x8264, 0xEBFB, 0x858F, 0xEBFC, 0x87FB, 0xEBFD, 0x8863, 0xEBFE, 0x8ABC, 0xECA1, 0x8B70, 0xECA2, 0x91AB, 0xECA3, 0x4E8C, 0xECA4, 0x4EE5, 0xECA5, 0x4F0A, 0xECA6, 0xF9DD, 0xECA7, 0xF9DE, 0xECA8, 0x5937, 0xECA9, 0x59E8, 0xECAA, 0xF9DF, 0xECAB, 0x5DF2, 0xECAC, 0x5F1B, 0xECAD, 0x5F5B, 0xECAE, 0x6021, 0xECAF, 0xF9E0, 0xECB0, 0xF9E1, 0xECB1, 0xF9E2, 0xECB2, 0xF9E3, 0xECB3, 0x723E, 0xECB4, 0x73E5, 0xECB5, 0xF9E4, 0xECB6, 0x7570, 0xECB7, 0x75CD, 0xECB8, 0xF9E5, 0xECB9, 0x79FB, 0xECBA, 0xF9E6, 0xECBB, 0x800C, 0xECBC, 0x8033, 0xECBD, 0x8084, 0xECBE, 0x82E1, 0xECBF, 0x8351, 0xECC0, 0xF9E7, 0xECC1, 0xF9E8, 0xECC2, 0x8CBD, 0xECC3, 0x8CB3, 0xECC4, 0x9087, 0xECC5, 0xF9E9, 0xECC6, 0xF9EA, 0xECC7, 0x98F4, 0xECC8, 0x990C, 0xECC9, 0xF9EB, 0xECCA, 0xF9EC, 0xECCB, 0x7037, 0xECCC, 0x76CA, 0xECCD, 0x7FCA, 0xECCE, 0x7FCC, 0xECCF, 0x7FFC, 0xECD0, 0x8B1A, 0xECD1, 0x4EBA, 0xECD2, 0x4EC1, 0xECD3, 0x5203, 0xECD4, 0x5370, 0xECD5, 0xF9ED, 0xECD6, 0x54BD, 0xECD7, 0x56E0, 0xECD8, 0x59FB, 0xECD9, 0x5BC5, 0xECDA, 0x5F15, 0xECDB, 0x5FCD, 0xECDC, 0x6E6E, 0xECDD, 0xF9EE, 0xECDE, 0xF9EF, 0xECDF, 0x7D6A, 0xECE0, 0x8335, 0xECE1, 0xF9F0, 0xECE2, 0x8693, 0xECE3, 0x8A8D, 0xECE4, 0xF9F1, 0xECE5, 0x976D, 0xECE6, 0x9777, 0xECE7, 0xF9F2, 0xECE8, 0xF9F3, 0xECE9, 0x4E00, 0xECEA, 0x4F5A, 0xECEB, 0x4F7E, 0xECEC, 0x58F9, 0xECED, 0x65E5, 0xECEE, 0x6EA2, 0xECEF, 0x9038, 0xECF0, 0x93B0, 0xECF1, 0x99B9, 0xECF2, 0x4EFB, 0xECF3, 0x58EC, 0xECF4, 0x598A, 0xECF5, 0x59D9, 0xECF6, 0x6041, 0xECF7, 0xF9F4, 0xECF8, 0xF9F5, 0xECF9, 0x7A14, 0xECFA, 0xF9F6, 0xECFB, 0x834F, 0xECFC, 0x8CC3, 0xECFD, 0x5165, 0xECFE, 0x5344, 0xEDA1, 0xF9F7, 0xEDA2, 0xF9F8, 0xEDA3, 0xF9F9, 0xEDA4, 0x4ECD, 0xEDA5, 0x5269, 0xEDA6, 0x5B55, 0xEDA7, 0x82BF, 0xEDA8, 0x4ED4, 0xEDA9, 0x523A, 0xEDAA, 0x54A8, 0xEDAB, 0x59C9, 0xEDAC, 0x59FF, 0xEDAD, 0x5B50, 0xEDAE, 0x5B57, 0xEDAF, 0x5B5C, 0xEDB0, 0x6063, 0xEDB1, 0x6148, 0xEDB2, 0x6ECB, 0xEDB3, 0x7099, 0xEDB4, 0x716E, 0xEDB5, 0x7386, 0xEDB6, 0x74F7, 0xEDB7, 0x75B5, 0xEDB8, 0x78C1, 0xEDB9, 0x7D2B, 0xEDBA, 0x8005, 0xEDBB, 0x81EA, 0xEDBC, 0x8328, 0xEDBD, 0x8517, 0xEDBE, 0x85C9, 0xEDBF, 0x8AEE, 0xEDC0, 0x8CC7, 0xEDC1, 0x96CC, 0xEDC2, 0x4F5C, 0xEDC3, 0x52FA, 0xEDC4, 0x56BC, 0xEDC5, 0x65AB, 0xEDC6, 0x6628, 0xEDC7, 0x707C, 0xEDC8, 0x70B8, 0xEDC9, 0x7235, 0xEDCA, 0x7DBD, 0xEDCB, 0x828D, 0xEDCC, 0x914C, 0xEDCD, 0x96C0, 0xEDCE, 0x9D72, 0xEDCF, 0x5B71, 0xEDD0, 0x68E7, 0xEDD1, 0x6B98, 0xEDD2, 0x6F7A, 0xEDD3, 0x76DE, 0xEDD4, 0x5C91, 0xEDD5, 0x66AB, 0xEDD6, 0x6F5B, 0xEDD7, 0x7BB4, 0xEDD8, 0x7C2A, 0xEDD9, 0x8836, 0xEDDA, 0x96DC, 0xEDDB, 0x4E08, 0xEDDC, 0x4ED7, 0xEDDD, 0x5320, 0xEDDE, 0x5834, 0xEDDF, 0x58BB, 0xEDE0, 0x58EF, 0xEDE1, 0x596C, 0xEDE2, 0x5C07, 0xEDE3, 0x5E33, 0xEDE4, 0x5E84, 0xEDE5, 0x5F35, 0xEDE6, 0x638C, 0xEDE7, 0x66B2, 0xEDE8, 0x6756, 0xEDE9, 0x6A1F, 0xEDEA, 0x6AA3, 0xEDEB, 0x6B0C, 0xEDEC, 0x6F3F, 0xEDED, 0x7246, 0xEDEE, 0xF9FA, 0xEDEF, 0x7350, 0xEDF0, 0x748B, 0xEDF1, 0x7AE0, 0xEDF2, 0x7CA7, 0xEDF3, 0x8178, 0xEDF4, 0x81DF, 0xEDF5, 0x81E7, 0xEDF6, 0x838A, 0xEDF7, 0x846C, 0xEDF8, 0x8523, 0xEDF9, 0x8594, 0xEDFA, 0x85CF, 0xEDFB, 0x88DD, 0xEDFC, 0x8D13, 0xEDFD, 0x91AC, 0xEDFE, 0x9577, 0xEEA1, 0x969C, 0xEEA2, 0x518D, 0xEEA3, 0x54C9, 0xEEA4, 0x5728, 0xEEA5, 0x5BB0, 0xEEA6, 0x624D, 0xEEA7, 0x6750, 0xEEA8, 0x683D, 0xEEA9, 0x6893, 0xEEAA, 0x6E3D, 0xEEAB, 0x6ED3, 0xEEAC, 0x707D, 0xEEAD, 0x7E21, 0xEEAE, 0x88C1, 0xEEAF, 0x8CA1, 0xEEB0, 0x8F09, 0xEEB1, 0x9F4B, 0xEEB2, 0x9F4E, 0xEEB3, 0x722D, 0xEEB4, 0x7B8F, 0xEEB5, 0x8ACD, 0xEEB6, 0x931A, 0xEEB7, 0x4F47, 0xEEB8, 0x4F4E, 0xEEB9, 0x5132, 0xEEBA, 0x5480, 0xEEBB, 0x59D0, 0xEEBC, 0x5E95, 0xEEBD, 0x62B5, 0xEEBE, 0x6775, 0xEEBF, 0x696E, 0xEEC0, 0x6A17, 0xEEC1, 0x6CAE, 0xEEC2, 0x6E1A, 0xEEC3, 0x72D9, 0xEEC4, 0x732A, 0xEEC5, 0x75BD, 0xEEC6, 0x7BB8, 0xEEC7, 0x7D35, 0xEEC8, 0x82E7, 0xEEC9, 0x83F9, 0xEECA, 0x8457, 0xEECB, 0x85F7, 0xEECC, 0x8A5B, 0xEECD, 0x8CAF, 0xEECE, 0x8E87, 0xEECF, 0x9019, 0xEED0, 0x90B8, 0xEED1, 0x96CE, 0xEED2, 0x9F5F, 0xEED3, 0x52E3, 0xEED4, 0x540A, 0xEED5, 0x5AE1, 0xEED6, 0x5BC2, 0xEED7, 0x6458, 0xEED8, 0x6575, 0xEED9, 0x6EF4, 0xEEDA, 0x72C4, 0xEEDB, 0xF9FB, 0xEEDC, 0x7684, 0xEEDD, 0x7A4D, 0xEEDE, 0x7B1B, 0xEEDF, 0x7C4D, 0xEEE0, 0x7E3E, 0xEEE1, 0x7FDF, 0xEEE2, 0x837B, 0xEEE3, 0x8B2B, 0xEEE4, 0x8CCA, 0xEEE5, 0x8D64, 0xEEE6, 0x8DE1, 0xEEE7, 0x8E5F, 0xEEE8, 0x8FEA, 0xEEE9, 0x8FF9, 0xEEEA, 0x9069, 0xEEEB, 0x93D1, 0xEEEC, 0x4F43, 0xEEED, 0x4F7A, 0xEEEE, 0x50B3, 0xEEEF, 0x5168, 0xEEF0, 0x5178, 0xEEF1, 0x524D, 0xEEF2, 0x526A, 0xEEF3, 0x5861, 0xEEF4, 0x587C, 0xEEF5, 0x5960, 0xEEF6, 0x5C08, 0xEEF7, 0x5C55, 0xEEF8, 0x5EDB, 0xEEF9, 0x609B, 0xEEFA, 0x6230, 0xEEFB, 0x6813, 0xEEFC, 0x6BBF, 0xEEFD, 0x6C08, 0xEEFE, 0x6FB1, 0xEFA1, 0x714E, 0xEFA2, 0x7420, 0xEFA3, 0x7530, 0xEFA4, 0x7538, 0xEFA5, 0x7551, 0xEFA6, 0x7672, 0xEFA7, 0x7B4C, 0xEFA8, 0x7B8B, 0xEFA9, 0x7BAD, 0xEFAA, 0x7BC6, 0xEFAB, 0x7E8F, 0xEFAC, 0x8A6E, 0xEFAD, 0x8F3E, 0xEFAE, 0x8F49, 0xEFAF, 0x923F, 0xEFB0, 0x9293, 0xEFB1, 0x9322, 0xEFB2, 0x942B, 0xEFB3, 0x96FB, 0xEFB4, 0x985A, 0xEFB5, 0x986B, 0xEFB6, 0x991E, 0xEFB7, 0x5207, 0xEFB8, 0x622A, 0xEFB9, 0x6298, 0xEFBA, 0x6D59, 0xEFBB, 0x7664, 0xEFBC, 0x7ACA, 0xEFBD, 0x7BC0, 0xEFBE, 0x7D76, 0xEFBF, 0x5360, 0xEFC0, 0x5CBE, 0xEFC1, 0x5E97, 0xEFC2, 0x6F38, 0xEFC3, 0x70B9, 0xEFC4, 0x7C98, 0xEFC5, 0x9711, 0xEFC6, 0x9B8E, 0xEFC7, 0x9EDE, 0xEFC8, 0x63A5, 0xEFC9, 0x647A, 0xEFCA, 0x8776, 0xEFCB, 0x4E01, 0xEFCC, 0x4E95, 0xEFCD, 0x4EAD, 0xEFCE, 0x505C, 0xEFCF, 0x5075, 0xEFD0, 0x5448, 0xEFD1, 0x59C3, 0xEFD2, 0x5B9A, 0xEFD3, 0x5E40, 0xEFD4, 0x5EAD, 0xEFD5, 0x5EF7, 0xEFD6, 0x5F81, 0xEFD7, 0x60C5, 0xEFD8, 0x633A, 0xEFD9, 0x653F, 0xEFDA, 0x6574, 0xEFDB, 0x65CC, 0xEFDC, 0x6676, 0xEFDD, 0x6678, 0xEFDE, 0x67FE, 0xEFDF, 0x6968, 0xEFE0, 0x6A89, 0xEFE1, 0x6B63, 0xEFE2, 0x6C40, 0xEFE3, 0x6DC0, 0xEFE4, 0x6DE8, 0xEFE5, 0x6E1F, 0xEFE6, 0x6E5E, 0xEFE7, 0x701E, 0xEFE8, 0x70A1, 0xEFE9, 0x738E, 0xEFEA, 0x73FD, 0xEFEB, 0x753A, 0xEFEC, 0x775B, 0xEFED, 0x7887, 0xEFEE, 0x798E, 0xEFEF, 0x7A0B, 0xEFF0, 0x7A7D, 0xEFF1, 0x7CBE, 0xEFF2, 0x7D8E, 0xEFF3, 0x8247, 0xEFF4, 0x8A02, 0xEFF5, 0x8AEA, 0xEFF6, 0x8C9E, 0xEFF7, 0x912D, 0xEFF8, 0x914A, 0xEFF9, 0x91D8, 0xEFFA, 0x9266, 0xEFFB, 0x92CC, 0xEFFC, 0x9320, 0xEFFD, 0x9706, 0xEFFE, 0x9756, 0xF0A1, 0x975C, 0xF0A2, 0x9802, 0xF0A3, 0x9F0E, 0xF0A4, 0x5236, 0xF0A5, 0x5291, 0xF0A6, 0x557C, 0xF0A7, 0x5824, 0xF0A8, 0x5E1D, 0xF0A9, 0x5F1F, 0xF0AA, 0x608C, 0xF0AB, 0x63D0, 0xF0AC, 0x68AF, 0xF0AD, 0x6FDF, 0xF0AE, 0x796D, 0xF0AF, 0x7B2C, 0xF0B0, 0x81CD, 0xF0B1, 0x85BA, 0xF0B2, 0x88FD, 0xF0B3, 0x8AF8, 0xF0B4, 0x8E44, 0xF0B5, 0x918D, 0xF0B6, 0x9664, 0xF0B7, 0x969B, 0xF0B8, 0x973D, 0xF0B9, 0x984C, 0xF0BA, 0x9F4A, 0xF0BB, 0x4FCE, 0xF0BC, 0x5146, 0xF0BD, 0x51CB, 0xF0BE, 0x52A9, 0xF0BF, 0x5632, 0xF0C0, 0x5F14, 0xF0C1, 0x5F6B, 0xF0C2, 0x63AA, 0xF0C3, 0x64CD, 0xF0C4, 0x65E9, 0xF0C5, 0x6641, 0xF0C6, 0x66FA, 0xF0C7, 0x66F9, 0xF0C8, 0x671D, 0xF0C9, 0x689D, 0xF0CA, 0x68D7, 0xF0CB, 0x69FD, 0xF0CC, 0x6F15, 0xF0CD, 0x6F6E, 0xF0CE, 0x7167, 0xF0CF, 0x71E5, 0xF0D0, 0x722A, 0xF0D1, 0x74AA, 0xF0D2, 0x773A, 0xF0D3, 0x7956, 0xF0D4, 0x795A, 0xF0D5, 0x79DF, 0xF0D6, 0x7A20, 0xF0D7, 0x7A95, 0xF0D8, 0x7C97, 0xF0D9, 0x7CDF, 0xF0DA, 0x7D44, 0xF0DB, 0x7E70, 0xF0DC, 0x8087, 0xF0DD, 0x85FB, 0xF0DE, 0x86A4, 0xF0DF, 0x8A54, 0xF0E0, 0x8ABF, 0xF0E1, 0x8D99, 0xF0E2, 0x8E81, 0xF0E3, 0x9020, 0xF0E4, 0x906D, 0xF0E5, 0x91E3, 0xF0E6, 0x963B, 0xF0E7, 0x96D5, 0xF0E8, 0x9CE5, 0xF0E9, 0x65CF, 0xF0EA, 0x7C07, 0xF0EB, 0x8DB3, 0xF0EC, 0x93C3, 0xF0ED, 0x5B58, 0xF0EE, 0x5C0A, 0xF0EF, 0x5352, 0xF0F0, 0x62D9, 0xF0F1, 0x731D, 0xF0F2, 0x5027, 0xF0F3, 0x5B97, 0xF0F4, 0x5F9E, 0xF0F5, 0x60B0, 0xF0F6, 0x616B, 0xF0F7, 0x68D5, 0xF0F8, 0x6DD9, 0xF0F9, 0x742E, 0xF0FA, 0x7A2E, 0xF0FB, 0x7D42, 0xF0FC, 0x7D9C, 0xF0FD, 0x7E31, 0xF0FE, 0x816B, 0xF1A1, 0x8E2A, 0xF1A2, 0x8E35, 0xF1A3, 0x937E, 0xF1A4, 0x9418, 0xF1A5, 0x4F50, 0xF1A6, 0x5750, 0xF1A7, 0x5DE6, 0xF1A8, 0x5EA7, 0xF1A9, 0x632B, 0xF1AA, 0x7F6A, 0xF1AB, 0x4E3B, 0xF1AC, 0x4F4F, 0xF1AD, 0x4F8F, 0xF1AE, 0x505A, 0xF1AF, 0x59DD, 0xF1B0, 0x80C4, 0xF1B1, 0x546A, 0xF1B2, 0x5468, 0xF1B3, 0x55FE, 0xF1B4, 0x594F, 0xF1B5, 0x5B99, 0xF1B6, 0x5DDE, 0xF1B7, 0x5EDA, 0xF1B8, 0x665D, 0xF1B9, 0x6731, 0xF1BA, 0x67F1, 0xF1BB, 0x682A, 0xF1BC, 0x6CE8, 0xF1BD, 0x6D32, 0xF1BE, 0x6E4A, 0xF1BF, 0x6F8D, 0xF1C0, 0x70B7, 0xF1C1, 0x73E0, 0xF1C2, 0x7587, 0xF1C3, 0x7C4C, 0xF1C4, 0x7D02, 0xF1C5, 0x7D2C, 0xF1C6, 0x7DA2, 0xF1C7, 0x821F, 0xF1C8, 0x86DB, 0xF1C9, 0x8A3B, 0xF1CA, 0x8A85, 0xF1CB, 0x8D70, 0xF1CC, 0x8E8A, 0xF1CD, 0x8F33, 0xF1CE, 0x9031, 0xF1CF, 0x914E, 0xF1D0, 0x9152, 0xF1D1, 0x9444, 0xF1D2, 0x99D0, 0xF1D3, 0x7AF9, 0xF1D4, 0x7CA5, 0xF1D5, 0x4FCA, 0xF1D6, 0x5101, 0xF1D7, 0x51C6, 0xF1D8, 0x57C8, 0xF1D9, 0x5BEF, 0xF1DA, 0x5CFB, 0xF1DB, 0x6659, 0xF1DC, 0x6A3D, 0xF1DD, 0x6D5A, 0xF1DE, 0x6E96, 0xF1DF, 0x6FEC, 0xF1E0, 0x710C, 0xF1E1, 0x756F, 0xF1E2, 0x7AE3, 0xF1E3, 0x8822, 0xF1E4, 0x9021, 0xF1E5, 0x9075, 0xF1E6, 0x96CB, 0xF1E7, 0x99FF, 0xF1E8, 0x8301, 0xF1E9, 0x4E2D, 0xF1EA, 0x4EF2, 0xF1EB, 0x8846, 0xF1EC, 0x91CD, 0xF1ED, 0x537D, 0xF1EE, 0x6ADB, 0xF1EF, 0x696B, 0xF1F0, 0x6C41, 0xF1F1, 0x847A, 0xF1F2, 0x589E, 0xF1F3, 0x618E, 0xF1F4, 0x66FE, 0xF1F5, 0x62EF, 0xF1F6, 0x70DD, 0xF1F7, 0x7511, 0xF1F8, 0x75C7, 0xF1F9, 0x7E52, 0xF1FA, 0x84B8, 0xF1FB, 0x8B49, 0xF1FC, 0x8D08, 0xF1FD, 0x4E4B, 0xF1FE, 0x53EA, 0xF2A1, 0x54AB, 0xF2A2, 0x5730, 0xF2A3, 0x5740, 0xF2A4, 0x5FD7, 0xF2A5, 0x6301, 0xF2A6, 0x6307, 0xF2A7, 0x646F, 0xF2A8, 0x652F, 0xF2A9, 0x65E8, 0xF2AA, 0x667A, 0xF2AB, 0x679D, 0xF2AC, 0x67B3, 0xF2AD, 0x6B62, 0xF2AE, 0x6C60, 0xF2AF, 0x6C9A, 0xF2B0, 0x6F2C, 0xF2B1, 0x77E5, 0xF2B2, 0x7825, 0xF2B3, 0x7949, 0xF2B4, 0x7957, 0xF2B5, 0x7D19, 0xF2B6, 0x80A2, 0xF2B7, 0x8102, 0xF2B8, 0x81F3, 0xF2B9, 0x829D, 0xF2BA, 0x82B7, 0xF2BB, 0x8718, 0xF2BC, 0x8A8C, 0xF2BD, 0xF9FC, 0xF2BE, 0x8D04, 0xF2BF, 0x8DBE, 0xF2C0, 0x9072, 0xF2C1, 0x76F4, 0xF2C2, 0x7A19, 0xF2C3, 0x7A37, 0xF2C4, 0x7E54, 0xF2C5, 0x8077, 0xF2C6, 0x5507, 0xF2C7, 0x55D4, 0xF2C8, 0x5875, 0xF2C9, 0x632F, 0xF2CA, 0x6422, 0xF2CB, 0x6649, 0xF2CC, 0x664B, 0xF2CD, 0x686D, 0xF2CE, 0x699B, 0xF2CF, 0x6B84, 0xF2D0, 0x6D25, 0xF2D1, 0x6EB1, 0xF2D2, 0x73CD, 0xF2D3, 0x7468, 0xF2D4, 0x74A1, 0xF2D5, 0x755B, 0xF2D6, 0x75B9, 0xF2D7, 0x76E1, 0xF2D8, 0x771E, 0xF2D9, 0x778B, 0xF2DA, 0x79E6, 0xF2DB, 0x7E09, 0xF2DC, 0x7E1D, 0xF2DD, 0x81FB, 0xF2DE, 0x852F, 0xF2DF, 0x8897, 0xF2E0, 0x8A3A, 0xF2E1, 0x8CD1, 0xF2E2, 0x8EEB, 0xF2E3, 0x8FB0, 0xF2E4, 0x9032, 0xF2E5, 0x93AD, 0xF2E6, 0x9663, 0xF2E7, 0x9673, 0xF2E8, 0x9707, 0xF2E9, 0x4F84, 0xF2EA, 0x53F1, 0xF2EB, 0x59EA, 0xF2EC, 0x5AC9, 0xF2ED, 0x5E19, 0xF2EE, 0x684E, 0xF2EF, 0x74C6, 0xF2F0, 0x75BE, 0xF2F1, 0x79E9, 0xF2F2, 0x7A92, 0xF2F3, 0x81A3, 0xF2F4, 0x86ED, 0xF2F5, 0x8CEA, 0xF2F6, 0x8DCC, 0xF2F7, 0x8FED, 0xF2F8, 0x659F, 0xF2F9, 0x6715, 0xF2FA, 0xF9FD, 0xF2FB, 0x57F7, 0xF2FC, 0x6F57, 0xF2FD, 0x7DDD, 0xF2FE, 0x8F2F, 0xF3A1, 0x93F6, 0xF3A2, 0x96C6, 0xF3A3, 0x5FB5, 0xF3A4, 0x61F2, 0xF3A5, 0x6F84, 0xF3A6, 0x4E14, 0xF3A7, 0x4F98, 0xF3A8, 0x501F, 0xF3A9, 0x53C9, 0xF3AA, 0x55DF, 0xF3AB, 0x5D6F, 0xF3AC, 0x5DEE, 0xF3AD, 0x6B21, 0xF3AE, 0x6B64, 0xF3AF, 0x78CB, 0xF3B0, 0x7B9A, 0xF3B1, 0xF9FE, 0xF3B2, 0x8E49, 0xF3B3, 0x8ECA, 0xF3B4, 0x906E, 0xF3B5, 0x6349, 0xF3B6, 0x643E, 0xF3B7, 0x7740, 0xF3B8, 0x7A84, 0xF3B9, 0x932F, 0xF3BA, 0x947F, 0xF3BB, 0x9F6A, 0xF3BC, 0x64B0, 0xF3BD, 0x6FAF, 0xF3BE, 0x71E6, 0xF3BF, 0x74A8, 0xF3C0, 0x74DA, 0xF3C1, 0x7AC4, 0xF3C2, 0x7C12, 0xF3C3, 0x7E82, 0xF3C4, 0x7CB2, 0xF3C5, 0x7E98, 0xF3C6, 0x8B9A, 0xF3C7, 0x8D0A, 0xF3C8, 0x947D, 0xF3C9, 0x9910, 0xF3CA, 0x994C, 0xF3CB, 0x5239, 0xF3CC, 0x5BDF, 0xF3CD, 0x64E6, 0xF3CE, 0x672D, 0xF3CF, 0x7D2E, 0xF3D0, 0x50ED, 0xF3D1, 0x53C3, 0xF3D2, 0x5879, 0xF3D3, 0x6158, 0xF3D4, 0x6159, 0xF3D5, 0x61FA, 0xF3D6, 0x65AC, 0xF3D7, 0x7AD9, 0xF3D8, 0x8B92, 0xF3D9, 0x8B96, 0xF3DA, 0x5009, 0xF3DB, 0x5021, 0xF3DC, 0x5275, 0xF3DD, 0x5531, 0xF3DE, 0x5A3C, 0xF3DF, 0x5EE0, 0xF3E0, 0x5F70, 0xF3E1, 0x6134, 0xF3E2, 0x655E, 0xF3E3, 0x660C, 0xF3E4, 0x6636, 0xF3E5, 0x66A2, 0xF3E6, 0x69CD, 0xF3E7, 0x6EC4, 0xF3E8, 0x6F32, 0xF3E9, 0x7316, 0xF3EA, 0x7621, 0xF3EB, 0x7A93, 0xF3EC, 0x8139, 0xF3ED, 0x8259, 0xF3EE, 0x83D6, 0xF3EF, 0x84BC, 0xF3F0, 0x50B5, 0xF3F1, 0x57F0, 0xF3F2, 0x5BC0, 0xF3F3, 0x5BE8, 0xF3F4, 0x5F69, 0xF3F5, 0x63A1, 0xF3F6, 0x7826, 0xF3F7, 0x7DB5, 0xF3F8, 0x83DC, 0xF3F9, 0x8521, 0xF3FA, 0x91C7, 0xF3FB, 0x91F5, 0xF3FC, 0x518A, 0xF3FD, 0x67F5, 0xF3FE, 0x7B56, 0xF4A1, 0x8CAC, 0xF4A2, 0x51C4, 0xF4A3, 0x59BB, 0xF4A4, 0x60BD, 0xF4A5, 0x8655, 0xF4A6, 0x501C, 0xF4A7, 0xF9FF, 0xF4A8, 0x5254, 0xF4A9, 0x5C3A, 0xF4AA, 0x617D, 0xF4AB, 0x621A, 0xF4AC, 0x62D3, 0xF4AD, 0x64F2, 0xF4AE, 0x65A5, 0xF4AF, 0x6ECC, 0xF4B0, 0x7620, 0xF4B1, 0x810A, 0xF4B2, 0x8E60, 0xF4B3, 0x965F, 0xF4B4, 0x96BB, 0xF4B5, 0x4EDF, 0xF4B6, 0x5343, 0xF4B7, 0x5598, 0xF4B8, 0x5929, 0xF4B9, 0x5DDD, 0xF4BA, 0x64C5, 0xF4BB, 0x6CC9, 0xF4BC, 0x6DFA, 0xF4BD, 0x7394, 0xF4BE, 0x7A7F, 0xF4BF, 0x821B, 0xF4C0, 0x85A6, 0xF4C1, 0x8CE4, 0xF4C2, 0x8E10, 0xF4C3, 0x9077, 0xF4C4, 0x91E7, 0xF4C5, 0x95E1, 0xF4C6, 0x9621, 0xF4C7, 0x97C6, 0xF4C8, 0x51F8, 0xF4C9, 0x54F2, 0xF4CA, 0x5586, 0xF4CB, 0x5FB9, 0xF4CC, 0x64A4, 0xF4CD, 0x6F88, 0xF4CE, 0x7DB4, 0xF4CF, 0x8F1F, 0xF4D0, 0x8F4D, 0xF4D1, 0x9435, 0xF4D2, 0x50C9, 0xF4D3, 0x5C16, 0xF4D4, 0x6CBE, 0xF4D5, 0x6DFB, 0xF4D6, 0x751B, 0xF4D7, 0x77BB, 0xF4D8, 0x7C3D, 0xF4D9, 0x7C64, 0xF4DA, 0x8A79, 0xF4DB, 0x8AC2, 0xF4DC, 0x581E, 0xF4DD, 0x59BE, 0xF4DE, 0x5E16, 0xF4DF, 0x6377, 0xF4E0, 0x7252, 0xF4E1, 0x758A, 0xF4E2, 0x776B, 0xF4E3, 0x8ADC, 0xF4E4, 0x8CBC, 0xF4E5, 0x8F12, 0xF4E6, 0x5EF3, 0xF4E7, 0x6674, 0xF4E8, 0x6DF8, 0xF4E9, 0x807D, 0xF4EA, 0x83C1, 0xF4EB, 0x8ACB, 0xF4EC, 0x9751, 0xF4ED, 0x9BD6, 0xF4EE, 0xFA00, 0xF4EF, 0x5243, 0xF4F0, 0x66FF, 0xF4F1, 0x6D95, 0xF4F2, 0x6EEF, 0xF4F3, 0x7DE0, 0xF4F4, 0x8AE6, 0xF4F5, 0x902E, 0xF4F6, 0x905E, 0xF4F7, 0x9AD4, 0xF4F8, 0x521D, 0xF4F9, 0x527F, 0xF4FA, 0x54E8, 0xF4FB, 0x6194, 0xF4FC, 0x6284, 0xF4FD, 0x62DB, 0xF4FE, 0x68A2, 0xF5A1, 0x6912, 0xF5A2, 0x695A, 0xF5A3, 0x6A35, 0xF5A4, 0x7092, 0xF5A5, 0x7126, 0xF5A6, 0x785D, 0xF5A7, 0x7901, 0xF5A8, 0x790E, 0xF5A9, 0x79D2, 0xF5AA, 0x7A0D, 0xF5AB, 0x8096, 0xF5AC, 0x8278, 0xF5AD, 0x82D5, 0xF5AE, 0x8349, 0xF5AF, 0x8549, 0xF5B0, 0x8C82, 0xF5B1, 0x8D85, 0xF5B2, 0x9162, 0xF5B3, 0x918B, 0xF5B4, 0x91AE, 0xF5B5, 0x4FC3, 0xF5B6, 0x56D1, 0xF5B7, 0x71ED, 0xF5B8, 0x77D7, 0xF5B9, 0x8700, 0xF5BA, 0x89F8, 0xF5BB, 0x5BF8, 0xF5BC, 0x5FD6, 0xF5BD, 0x6751, 0xF5BE, 0x90A8, 0xF5BF, 0x53E2, 0xF5C0, 0x585A, 0xF5C1, 0x5BF5, 0xF5C2, 0x60A4, 0xF5C3, 0x6181, 0xF5C4, 0x6460, 0xF5C5, 0x7E3D, 0xF5C6, 0x8070, 0xF5C7, 0x8525, 0xF5C8, 0x9283, 0xF5C9, 0x64AE, 0xF5CA, 0x50AC, 0xF5CB, 0x5D14, 0xF5CC, 0x6700, 0xF5CD, 0x589C, 0xF5CE, 0x62BD, 0xF5CF, 0x63A8, 0xF5D0, 0x690E, 0xF5D1, 0x6978, 0xF5D2, 0x6A1E, 0xF5D3, 0x6E6B, 0xF5D4, 0x76BA, 0xF5D5, 0x79CB, 0xF5D6, 0x82BB, 0xF5D7, 0x8429, 0xF5D8, 0x8ACF, 0xF5D9, 0x8DA8, 0xF5DA, 0x8FFD, 0xF5DB, 0x9112, 0xF5DC, 0x914B, 0xF5DD, 0x919C, 0xF5DE, 0x9310, 0xF5DF, 0x9318, 0xF5E0, 0x939A, 0xF5E1, 0x96DB, 0xF5E2, 0x9A36, 0xF5E3, 0x9C0D, 0xF5E4, 0x4E11, 0xF5E5, 0x755C, 0xF5E6, 0x795D, 0xF5E7, 0x7AFA, 0xF5E8, 0x7B51, 0xF5E9, 0x7BC9, 0xF5EA, 0x7E2E, 0xF5EB, 0x84C4, 0xF5EC, 0x8E59, 0xF5ED, 0x8E74, 0xF5EE, 0x8EF8, 0xF5EF, 0x9010, 0xF5F0, 0x6625, 0xF5F1, 0x693F, 0xF5F2, 0x7443, 0xF5F3, 0x51FA, 0xF5F4, 0x672E, 0xF5F5, 0x9EDC, 0xF5F6, 0x5145, 0xF5F7, 0x5FE0, 0xF5F8, 0x6C96, 0xF5F9, 0x87F2, 0xF5FA, 0x885D, 0xF5FB, 0x8877, 0xF5FC, 0x60B4, 0xF5FD, 0x81B5, 0xF5FE, 0x8403, 0xF6A1, 0x8D05, 0xF6A2, 0x53D6, 0xF6A3, 0x5439, 0xF6A4, 0x5634, 0xF6A5, 0x5A36, 0xF6A6, 0x5C31, 0xF6A7, 0x708A, 0xF6A8, 0x7FE0, 0xF6A9, 0x805A, 0xF6AA, 0x8106, 0xF6AB, 0x81ED, 0xF6AC, 0x8DA3, 0xF6AD, 0x9189, 0xF6AE, 0x9A5F, 0xF6AF, 0x9DF2, 0xF6B0, 0x5074, 0xF6B1, 0x4EC4, 0xF6B2, 0x53A0, 0xF6B3, 0x60FB, 0xF6B4, 0x6E2C, 0xF6B5, 0x5C64, 0xF6B6, 0x4F88, 0xF6B7, 0x5024, 0xF6B8, 0x55E4, 0xF6B9, 0x5CD9, 0xF6BA, 0x5E5F, 0xF6BB, 0x6065, 0xF6BC, 0x6894, 0xF6BD, 0x6CBB, 0xF6BE, 0x6DC4, 0xF6BF, 0x71BE, 0xF6C0, 0x75D4, 0xF6C1, 0x75F4, 0xF6C2, 0x7661, 0xF6C3, 0x7A1A, 0xF6C4, 0x7A49, 0xF6C5, 0x7DC7, 0xF6C6, 0x7DFB, 0xF6C7, 0x7F6E, 0xF6C8, 0x81F4, 0xF6C9, 0x86A9, 0xF6CA, 0x8F1C, 0xF6CB, 0x96C9, 0xF6CC, 0x99B3, 0xF6CD, 0x9F52, 0xF6CE, 0x5247, 0xF6CF, 0x52C5, 0xF6D0, 0x98ED, 0xF6D1, 0x89AA, 0xF6D2, 0x4E03, 0xF6D3, 0x67D2, 0xF6D4, 0x6F06, 0xF6D5, 0x4FB5, 0xF6D6, 0x5BE2, 0xF6D7, 0x6795, 0xF6D8, 0x6C88, 0xF6D9, 0x6D78, 0xF6DA, 0x741B, 0xF6DB, 0x7827, 0xF6DC, 0x91DD, 0xF6DD, 0x937C, 0xF6DE, 0x87C4, 0xF6DF, 0x79E4, 0xF6E0, 0x7A31, 0xF6E1, 0x5FEB, 0xF6E2, 0x4ED6, 0xF6E3, 0x54A4, 0xF6E4, 0x553E, 0xF6E5, 0x58AE, 0xF6E6, 0x59A5, 0xF6E7, 0x60F0, 0xF6E8, 0x6253, 0xF6E9, 0x62D6, 0xF6EA, 0x6736, 0xF6EB, 0x6955, 0xF6EC, 0x8235, 0xF6ED, 0x9640, 0xF6EE, 0x99B1, 0xF6EF, 0x99DD, 0xF6F0, 0x502C, 0xF6F1, 0x5353, 0xF6F2, 0x5544, 0xF6F3, 0x577C, 0xF6F4, 0xFA01, 0xF6F5, 0x6258, 0xF6F6, 0xFA02, 0xF6F7, 0x64E2, 0xF6F8, 0x666B, 0xF6F9, 0x67DD, 0xF6FA, 0x6FC1, 0xF6FB, 0x6FEF, 0xF6FC, 0x7422, 0xF6FD, 0x7438, 0xF6FE, 0x8A17, 0xF7A1, 0x9438, 0xF7A2, 0x5451, 0xF7A3, 0x5606, 0xF7A4, 0x5766, 0xF7A5, 0x5F48, 0xF7A6, 0x619A, 0xF7A7, 0x6B4E, 0xF7A8, 0x7058, 0xF7A9, 0x70AD, 0xF7AA, 0x7DBB, 0xF7AB, 0x8A95, 0xF7AC, 0x596A, 0xF7AD, 0x812B, 0xF7AE, 0x63A2, 0xF7AF, 0x7708, 0xF7B0, 0x803D, 0xF7B1, 0x8CAA, 0xF7B2, 0x5854, 0xF7B3, 0x642D, 0xF7B4, 0x69BB, 0xF7B5, 0x5B95, 0xF7B6, 0x5E11, 0xF7B7, 0x6E6F, 0xF7B8, 0xFA03, 0xF7B9, 0x8569, 0xF7BA, 0x514C, 0xF7BB, 0x53F0, 0xF7BC, 0x592A, 0xF7BD, 0x6020, 0xF7BE, 0x614B, 0xF7BF, 0x6B86, 0xF7C0, 0x6C70, 0xF7C1, 0x6CF0, 0xF7C2, 0x7B1E, 0xF7C3, 0x80CE, 0xF7C4, 0x82D4, 0xF7C5, 0x8DC6, 0xF7C6, 0x90B0, 0xF7C7, 0x98B1, 0xF7C8, 0xFA04, 0xF7C9, 0x64C7, 0xF7CA, 0x6FA4, 0xF7CB, 0x6491, 0xF7CC, 0x6504, 0xF7CD, 0x514E, 0xF7CE, 0x5410, 0xF7CF, 0x571F, 0xF7D0, 0x8A0E, 0xF7D1, 0x615F, 0xF7D2, 0x6876, 0xF7D3, 0xFA05, 0xF7D4, 0x75DB, 0xF7D5, 0x7B52, 0xF7D6, 0x7D71, 0xF7D7, 0x901A, 0xF7D8, 0x5806, 0xF7D9, 0x69CC, 0xF7DA, 0x817F, 0xF7DB, 0x892A, 0xF7DC, 0x9000, 0xF7DD, 0x9839, 0xF7DE, 0x5078, 0xF7DF, 0x5957, 0xF7E0, 0x59AC, 0xF7E1, 0x6295, 0xF7E2, 0x900F, 0xF7E3, 0x9B2A, 0xF7E4, 0x615D, 0xF7E5, 0x7279, 0xF7E6, 0x95D6, 0xF7E7, 0x5761, 0xF7E8, 0x5A46, 0xF7E9, 0x5DF4, 0xF7EA, 0x628A, 0xF7EB, 0x64AD, 0xF7EC, 0x64FA, 0xF7ED, 0x6777, 0xF7EE, 0x6CE2, 0xF7EF, 0x6D3E, 0xF7F0, 0x722C, 0xF7F1, 0x7436, 0xF7F2, 0x7834, 0xF7F3, 0x7F77, 0xF7F4, 0x82AD, 0xF7F5, 0x8DDB, 0xF7F6, 0x9817, 0xF7F7, 0x5224, 0xF7F8, 0x5742, 0xF7F9, 0x677F, 0xF7FA, 0x7248, 0xF7FB, 0x74E3, 0xF7FC, 0x8CA9, 0xF7FD, 0x8FA6, 0xF7FE, 0x9211, 0xF8A1, 0x962A, 0xF8A2, 0x516B, 0xF8A3, 0x53ED, 0xF8A4, 0x634C, 0xF8A5, 0x4F69, 0xF8A6, 0x5504, 0xF8A7, 0x6096, 0xF8A8, 0x6557, 0xF8A9, 0x6C9B, 0xF8AA, 0x6D7F, 0xF8AB, 0x724C, 0xF8AC, 0x72FD, 0xF8AD, 0x7A17, 0xF8AE, 0x8987, 0xF8AF, 0x8C9D, 0xF8B0, 0x5F6D, 0xF8B1, 0x6F8E, 0xF8B2, 0x70F9, 0xF8B3, 0x81A8, 0xF8B4, 0x610E, 0xF8B5, 0x4FBF, 0xF8B6, 0x504F, 0xF8B7, 0x6241, 0xF8B8, 0x7247, 0xF8B9, 0x7BC7, 0xF8BA, 0x7DE8, 0xF8BB, 0x7FE9, 0xF8BC, 0x904D, 0xF8BD, 0x97AD, 0xF8BE, 0x9A19, 0xF8BF, 0x8CB6, 0xF8C0, 0x576A, 0xF8C1, 0x5E73, 0xF8C2, 0x67B0, 0xF8C3, 0x840D, 0xF8C4, 0x8A55, 0xF8C5, 0x5420, 0xF8C6, 0x5B16, 0xF8C7, 0x5E63, 0xF8C8, 0x5EE2, 0xF8C9, 0x5F0A, 0xF8CA, 0x6583, 0xF8CB, 0x80BA, 0xF8CC, 0x853D, 0xF8CD, 0x9589, 0xF8CE, 0x965B, 0xF8CF, 0x4F48, 0xF8D0, 0x5305, 0xF8D1, 0x530D, 0xF8D2, 0x530F, 0xF8D3, 0x5486, 0xF8D4, 0x54FA, 0xF8D5, 0x5703, 0xF8D6, 0x5E03, 0xF8D7, 0x6016, 0xF8D8, 0x629B, 0xF8D9, 0x62B1, 0xF8DA, 0x6355, 0xF8DB, 0xFA06, 0xF8DC, 0x6CE1, 0xF8DD, 0x6D66, 0xF8DE, 0x75B1, 0xF8DF, 0x7832, 0xF8E0, 0x80DE, 0xF8E1, 0x812F, 0xF8E2, 0x82DE, 0xF8E3, 0x8461, 0xF8E4, 0x84B2, 0xF8E5, 0x888D, 0xF8E6, 0x8912, 0xF8E7, 0x900B, 0xF8E8, 0x92EA, 0xF8E9, 0x98FD, 0xF8EA, 0x9B91, 0xF8EB, 0x5E45, 0xF8EC, 0x66B4, 0xF8ED, 0x66DD, 0xF8EE, 0x7011, 0xF8EF, 0x7206, 0xF8F0, 0xFA07, 0xF8F1, 0x4FF5, 0xF8F2, 0x527D, 0xF8F3, 0x5F6A, 0xF8F4, 0x6153, 0xF8F5, 0x6753, 0xF8F6, 0x6A19, 0xF8F7, 0x6F02, 0xF8F8, 0x74E2, 0xF8F9, 0x7968, 0xF8FA, 0x8868, 0xF8FB, 0x8C79, 0xF8FC, 0x98C7, 0xF8FD, 0x98C4, 0xF8FE, 0x9A43, 0xF9A1, 0x54C1, 0xF9A2, 0x7A1F, 0xF9A3, 0x6953, 0xF9A4, 0x8AF7, 0xF9A5, 0x8C4A, 0xF9A6, 0x98A8, 0xF9A7, 0x99AE, 0xF9A8, 0x5F7C, 0xF9A9, 0x62AB, 0xF9AA, 0x75B2, 0xF9AB, 0x76AE, 0xF9AC, 0x88AB, 0xF9AD, 0x907F, 0xF9AE, 0x9642, 0xF9AF, 0x5339, 0xF9B0, 0x5F3C, 0xF9B1, 0x5FC5, 0xF9B2, 0x6CCC, 0xF9B3, 0x73CC, 0xF9B4, 0x7562, 0xF9B5, 0x758B, 0xF9B6, 0x7B46, 0xF9B7, 0x82FE, 0xF9B8, 0x999D, 0xF9B9, 0x4E4F, 0xF9BA, 0x903C, 0xF9BB, 0x4E0B, 0xF9BC, 0x4F55, 0xF9BD, 0x53A6, 0xF9BE, 0x590F, 0xF9BF, 0x5EC8, 0xF9C0, 0x6630, 0xF9C1, 0x6CB3, 0xF9C2, 0x7455, 0xF9C3, 0x8377, 0xF9C4, 0x8766, 0xF9C5, 0x8CC0, 0xF9C6, 0x9050, 0xF9C7, 0x971E, 0xF9C8, 0x9C15, 0xF9C9, 0x58D1, 0xF9CA, 0x5B78, 0xF9CB, 0x8650, 0xF9CC, 0x8B14, 0xF9CD, 0x9DB4, 0xF9CE, 0x5BD2, 0xF9CF, 0x6068, 0xF9D0, 0x608D, 0xF9D1, 0x65F1, 0xF9D2, 0x6C57, 0xF9D3, 0x6F22, 0xF9D4, 0x6FA3, 0xF9D5, 0x701A, 0xF9D6, 0x7F55, 0xF9D7, 0x7FF0, 0xF9D8, 0x9591, 0xF9D9, 0x9592, 0xF9DA, 0x9650, 0xF9DB, 0x97D3, 0xF9DC, 0x5272, 0xF9DD, 0x8F44, 0xF9DE, 0x51FD, 0xF9DF, 0x542B, 0xF9E0, 0x54B8, 0xF9E1, 0x5563, 0xF9E2, 0x558A, 0xF9E3, 0x6ABB, 0xF9E4, 0x6DB5, 0xF9E5, 0x7DD8, 0xF9E6, 0x8266, 0xF9E7, 0x929C, 0xF9E8, 0x9677, 0xF9E9, 0x9E79, 0xF9EA, 0x5408, 0xF9EB, 0x54C8, 0xF9EC, 0x76D2, 0xF9ED, 0x86E4, 0xF9EE, 0x95A4, 0xF9EF, 0x95D4, 0xF9F0, 0x965C, 0xF9F1, 0x4EA2, 0xF9F2, 0x4F09, 0xF9F3, 0x59EE, 0xF9F4, 0x5AE6, 0xF9F5, 0x5DF7, 0xF9F6, 0x6052, 0xF9F7, 0x6297, 0xF9F8, 0x676D, 0xF9F9, 0x6841, 0xF9FA, 0x6C86, 0xF9FB, 0x6E2F, 0xF9FC, 0x7F38, 0xF9FD, 0x809B, 0xF9FE, 0x822A, 0xFAA1, 0xFA08, 0xFAA2, 0xFA09, 0xFAA3, 0x9805, 0xFAA4, 0x4EA5, 0xFAA5, 0x5055, 0xFAA6, 0x54B3, 0xFAA7, 0x5793, 0xFAA8, 0x595A, 0xFAA9, 0x5B69, 0xFAAA, 0x5BB3, 0xFAAB, 0x61C8, 0xFAAC, 0x6977, 0xFAAD, 0x6D77, 0xFAAE, 0x7023, 0xFAAF, 0x87F9, 0xFAB0, 0x89E3, 0xFAB1, 0x8A72, 0xFAB2, 0x8AE7, 0xFAB3, 0x9082, 0xFAB4, 0x99ED, 0xFAB5, 0x9AB8, 0xFAB6, 0x52BE, 0xFAB7, 0x6838, 0xFAB8, 0x5016, 0xFAB9, 0x5E78, 0xFABA, 0x674F, 0xFABB, 0x8347, 0xFABC, 0x884C, 0xFABD, 0x4EAB, 0xFABE, 0x5411, 0xFABF, 0x56AE, 0xFAC0, 0x73E6, 0xFAC1, 0x9115, 0xFAC2, 0x97FF, 0xFAC3, 0x9909, 0xFAC4, 0x9957, 0xFAC5, 0x9999, 0xFAC6, 0x5653, 0xFAC7, 0x589F, 0xFAC8, 0x865B, 0xFAC9, 0x8A31, 0xFACA, 0x61B2, 0xFACB, 0x6AF6, 0xFACC, 0x737B, 0xFACD, 0x8ED2, 0xFACE, 0x6B47, 0xFACF, 0x96AA, 0xFAD0, 0x9A57, 0xFAD1, 0x5955, 0xFAD2, 0x7200, 0xFAD3, 0x8D6B, 0xFAD4, 0x9769, 0xFAD5, 0x4FD4, 0xFAD6, 0x5CF4, 0xFAD7, 0x5F26, 0xFAD8, 0x61F8, 0xFAD9, 0x665B, 0xFADA, 0x6CEB, 0xFADB, 0x70AB, 0xFADC, 0x7384, 0xFADD, 0x73B9, 0xFADE, 0x73FE, 0xFADF, 0x7729, 0xFAE0, 0x774D, 0xFAE1, 0x7D43, 0xFAE2, 0x7D62, 0xFAE3, 0x7E23, 0xFAE4, 0x8237, 0xFAE5, 0x8852, 0xFAE6, 0xFA0A, 0xFAE7, 0x8CE2, 0xFAE8, 0x9249, 0xFAE9, 0x986F, 0xFAEA, 0x5B51, 0xFAEB, 0x7A74, 0xFAEC, 0x8840, 0xFAED, 0x9801, 0xFAEE, 0x5ACC, 0xFAEF, 0x4FE0, 0xFAF0, 0x5354, 0xFAF1, 0x593E, 0xFAF2, 0x5CFD, 0xFAF3, 0x633E, 0xFAF4, 0x6D79, 0xFAF5, 0x72F9, 0xFAF6, 0x8105, 0xFAF7, 0x8107, 0xFAF8, 0x83A2, 0xFAF9, 0x92CF, 0xFAFA, 0x9830, 0xFAFB, 0x4EA8, 0xFAFC, 0x5144, 0xFAFD, 0x5211, 0xFAFE, 0x578B, 0xFBA1, 0x5F62, 0xFBA2, 0x6CC2, 0xFBA3, 0x6ECE, 0xFBA4, 0x7005, 0xFBA5, 0x7050, 0xFBA6, 0x70AF, 0xFBA7, 0x7192, 0xFBA8, 0x73E9, 0xFBA9, 0x7469, 0xFBAA, 0x834A, 0xFBAB, 0x87A2, 0xFBAC, 0x8861, 0xFBAD, 0x9008, 0xFBAE, 0x90A2, 0xFBAF, 0x93A3, 0xFBB0, 0x99A8, 0xFBB1, 0x516E, 0xFBB2, 0x5F57, 0xFBB3, 0x60E0, 0xFBB4, 0x6167, 0xFBB5, 0x66B3, 0xFBB6, 0x8559, 0xFBB7, 0x8E4A, 0xFBB8, 0x91AF, 0xFBB9, 0x978B, 0xFBBA, 0x4E4E, 0xFBBB, 0x4E92, 0xFBBC, 0x547C, 0xFBBD, 0x58D5, 0xFBBE, 0x58FA, 0xFBBF, 0x597D, 0xFBC0, 0x5CB5, 0xFBC1, 0x5F27, 0xFBC2, 0x6236, 0xFBC3, 0x6248, 0xFBC4, 0x660A, 0xFBC5, 0x6667, 0xFBC6, 0x6BEB, 0xFBC7, 0x6D69, 0xFBC8, 0x6DCF, 0xFBC9, 0x6E56, 0xFBCA, 0x6EF8, 0xFBCB, 0x6F94, 0xFBCC, 0x6FE0, 0xFBCD, 0x6FE9, 0xFBCE, 0x705D, 0xFBCF, 0x72D0, 0xFBD0, 0x7425, 0xFBD1, 0x745A, 0xFBD2, 0x74E0, 0xFBD3, 0x7693, 0xFBD4, 0x795C, 0xFBD5, 0x7CCA, 0xFBD6, 0x7E1E, 0xFBD7, 0x80E1, 0xFBD8, 0x82A6, 0xFBD9, 0x846B, 0xFBDA, 0x84BF, 0xFBDB, 0x864E, 0xFBDC, 0x865F, 0xFBDD, 0x8774, 0xFBDE, 0x8B77, 0xFBDF, 0x8C6A, 0xFBE0, 0x93AC, 0xFBE1, 0x9800, 0xFBE2, 0x9865, 0xFBE3, 0x60D1, 0xFBE4, 0x6216, 0xFBE5, 0x9177, 0xFBE6, 0x5A5A, 0xFBE7, 0x660F, 0xFBE8, 0x6DF7, 0xFBE9, 0x6E3E, 0xFBEA, 0x743F, 0xFBEB, 0x9B42, 0xFBEC, 0x5FFD, 0xFBED, 0x60DA, 0xFBEE, 0x7B0F, 0xFBEF, 0x54C4, 0xFBF0, 0x5F18, 0xFBF1, 0x6C5E, 0xFBF2, 0x6CD3, 0xFBF3, 0x6D2A, 0xFBF4, 0x70D8, 0xFBF5, 0x7D05, 0xFBF6, 0x8679, 0xFBF7, 0x8A0C, 0xFBF8, 0x9D3B, 0xFBF9, 0x5316, 0xFBFA, 0x548C, 0xFBFB, 0x5B05, 0xFBFC, 0x6A3A, 0xFBFD, 0x706B, 0xFBFE, 0x7575, 0xFCA1, 0x798D, 0xFCA2, 0x79BE, 0xFCA3, 0x82B1, 0xFCA4, 0x83EF, 0xFCA5, 0x8A71, 0xFCA6, 0x8B41, 0xFCA7, 0x8CA8, 0xFCA8, 0x9774, 0xFCA9, 0xFA0B, 0xFCAA, 0x64F4, 0xFCAB, 0x652B, 0xFCAC, 0x78BA, 0xFCAD, 0x78BB, 0xFCAE, 0x7A6B, 0xFCAF, 0x4E38, 0xFCB0, 0x559A, 0xFCB1, 0x5950, 0xFCB2, 0x5BA6, 0xFCB3, 0x5E7B, 0xFCB4, 0x60A3, 0xFCB5, 0x63DB, 0xFCB6, 0x6B61, 0xFCB7, 0x6665, 0xFCB8, 0x6853, 0xFCB9, 0x6E19, 0xFCBA, 0x7165, 0xFCBB, 0x74B0, 0xFCBC, 0x7D08, 0xFCBD, 0x9084, 0xFCBE, 0x9A69, 0xFCBF, 0x9C25, 0xFCC0, 0x6D3B, 0xFCC1, 0x6ED1, 0xFCC2, 0x733E, 0xFCC3, 0x8C41, 0xFCC4, 0x95CA, 0xFCC5, 0x51F0, 0xFCC6, 0x5E4C, 0xFCC7, 0x5FA8, 0xFCC8, 0x604D, 0xFCC9, 0x60F6, 0xFCCA, 0x6130, 0xFCCB, 0x614C, 0xFCCC, 0x6643, 0xFCCD, 0x6644, 0xFCCE, 0x69A5, 0xFCCF, 0x6CC1, 0xFCD0, 0x6E5F, 0xFCD1, 0x6EC9, 0xFCD2, 0x6F62, 0xFCD3, 0x714C, 0xFCD4, 0x749C, 0xFCD5, 0x7687, 0xFCD6, 0x7BC1, 0xFCD7, 0x7C27, 0xFCD8, 0x8352, 0xFCD9, 0x8757, 0xFCDA, 0x9051, 0xFCDB, 0x968D, 0xFCDC, 0x9EC3, 0xFCDD, 0x532F, 0xFCDE, 0x56DE, 0xFCDF, 0x5EFB, 0xFCE0, 0x5F8A, 0xFCE1, 0x6062, 0xFCE2, 0x6094, 0xFCE3, 0x61F7, 0xFCE4, 0x6666, 0xFCE5, 0x6703, 0xFCE6, 0x6A9C, 0xFCE7, 0x6DEE, 0xFCE8, 0x6FAE, 0xFCE9, 0x7070, 0xFCEA, 0x736A, 0xFCEB, 0x7E6A, 0xFCEC, 0x81BE, 0xFCED, 0x8334, 0xFCEE, 0x86D4, 0xFCEF, 0x8AA8, 0xFCF0, 0x8CC4, 0xFCF1, 0x5283, 0xFCF2, 0x7372, 0xFCF3, 0x5B96, 0xFCF4, 0x6A6B, 0xFCF5, 0x9404, 0xFCF6, 0x54EE, 0xFCF7, 0x5686, 0xFCF8, 0x5B5D, 0xFCF9, 0x6548, 0xFCFA, 0x6585, 0xFCFB, 0x66C9, 0xFCFC, 0x689F, 0xFCFD, 0x6D8D, 0xFCFE, 0x6DC6, 0xFDA1, 0x723B, 0xFDA2, 0x80B4, 0xFDA3, 0x9175, 0xFDA4, 0x9A4D, 0xFDA5, 0x4FAF, 0xFDA6, 0x5019, 0xFDA7, 0x539A, 0xFDA8, 0x540E, 0xFDA9, 0x543C, 0xFDAA, 0x5589, 0xFDAB, 0x55C5, 0xFDAC, 0x5E3F, 0xFDAD, 0x5F8C, 0xFDAE, 0x673D, 0xFDAF, 0x7166, 0xFDB0, 0x73DD, 0xFDB1, 0x9005, 0xFDB2, 0x52DB, 0xFDB3, 0x52F3, 0xFDB4, 0x5864, 0xFDB5, 0x58CE, 0xFDB6, 0x7104, 0xFDB7, 0x718F, 0xFDB8, 0x71FB, 0xFDB9, 0x85B0, 0xFDBA, 0x8A13, 0xFDBB, 0x6688, 0xFDBC, 0x85A8, 0xFDBD, 0x55A7, 0xFDBE, 0x6684, 0xFDBF, 0x714A, 0xFDC0, 0x8431, 0xFDC1, 0x5349, 0xFDC2, 0x5599, 0xFDC3, 0x6BC1, 0xFDC4, 0x5F59, 0xFDC5, 0x5FBD, 0xFDC6, 0x63EE, 0xFDC7, 0x6689, 0xFDC8, 0x7147, 0xFDC9, 0x8AF1, 0xFDCA, 0x8F1D, 0xFDCB, 0x9EBE, 0xFDCC, 0x4F11, 0xFDCD, 0x643A, 0xFDCE, 0x70CB, 0xFDCF, 0x7566, 0xFDD0, 0x8667, 0xFDD1, 0x6064, 0xFDD2, 0x8B4E, 0xFDD3, 0x9DF8, 0xFDD4, 0x5147, 0xFDD5, 0x51F6, 0xFDD6, 0x5308, 0xFDD7, 0x6D36, 0xFDD8, 0x80F8, 0xFDD9, 0x9ED1, 0xFDDA, 0x6615, 0xFDDB, 0x6B23, 0xFDDC, 0x7098, 0xFDDD, 0x75D5, 0xFDDE, 0x5403, 0xFDDF, 0x5C79, 0xFDE0, 0x7D07, 0xFDE1, 0x8A16, 0xFDE2, 0x6B20, 0xFDE3, 0x6B3D, 0xFDE4, 0x6B46, 0xFDE5, 0x5438, 0xFDE6, 0x6070, 0xFDE7, 0x6D3D, 0xFDE8, 0x7FD5, 0xFDE9, 0x8208, 0xFDEA, 0x50D6, 0xFDEB, 0x51DE, 0xFDEC, 0x559C, 0xFDED, 0x566B, 0xFDEE, 0x56CD, 0xFDEF, 0x59EC, 0xFDF0, 0x5B09, 0xFDF1, 0x5E0C, 0xFDF2, 0x6199, 0xFDF3, 0x6198, 0xFDF4, 0x6231, 0xFDF5, 0x665E, 0xFDF6, 0x66E6, 0xFDF7, 0x7199, 0xFDF8, 0x71B9, 0xFDF9, 0x71BA, 0xFDFA, 0x72A7, 0xFDFB, 0x79A7, 0xFDFC, 0x7A00, 0xFDFD, 0x7FB2, 0xFDFE, 0x8A70, 0, 0 }; #endif #if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */ static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ 0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE, 0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346, 0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E, 0x039C, 0xA34F, 0x039D, 0xA350, 0x039E, 0xA351, 0x039F, 0xA352, 0x03A0, 0xA353, 0x03A1, 0xA354, 0x03A3, 0xA355, 0x03A4, 0xA356, 0x03A5, 0xA357, 0x03A6, 0xA358, 0x03A7, 0xA359, 0x03A8, 0xA35A, 0x03A9, 0xA35B, 0x03B1, 0xA35C, 0x03B2, 0xA35D, 0x03B3, 0xA35E, 0x03B4, 0xA35F, 0x03B5, 0xA360, 0x03B6, 0xA361, 0x03B7, 0xA362, 0x03B8, 0xA363, 0x03B9, 0xA364, 0x03BA, 0xA365, 0x03BB, 0xA366, 0x03BC, 0xA367, 0x03BD, 0xA368, 0x03BE, 0xA369, 0x03BF, 0xA36A, 0x03C0, 0xA36B, 0x03C1, 0xA36C, 0x03C3, 0xA36D, 0x03C4, 0xA36E, 0x03C5, 0xA36F, 0x03C6, 0xA370, 0x03C7, 0xA371, 0x03C8, 0xA372, 0x03C9, 0xA373, 0x2013, 0xA156, 0x2014, 0xA158, 0x2018, 0xA1A5, 0x2019, 0xA1A6, 0x201C, 0xA1A7, 0x201D, 0xA1A8, 0x2025, 0xA14C, 0x2026, 0xA14B, 0x2027, 0xA145, 0x2032, 0xA1AC, 0x2035, 0xA1AB, 0x203B, 0xA1B0, 0x20AC, 0xA3E1, 0x2103, 0xA24A, 0x2105, 0xA1C1, 0x2109, 0xA24B, 0x2160, 0xA2B9, 0x2161, 0xA2BA, 0x2162, 0xA2BB, 0x2163, 0xA2BC, 0x2164, 0xA2BD, 0x2165, 0xA2BE, 0x2166, 0xA2BF, 0x2167, 0xA2C0, 0x2168, 0xA2C1, 0x2169, 0xA2C2, 0x2190, 0xA1F6, 0x2191, 0xA1F4, 0x2192, 0xA1F7, 0x2193, 0xA1F5, 0x2196, 0xA1F8, 0x2197, 0xA1F9, 0x2198, 0xA1FB, 0x2199, 0xA1FA, 0x2215, 0xA241, 0x221A, 0xA1D4, 0x221E, 0xA1DB, 0x221F, 0xA1E8, 0x2220, 0xA1E7, 0x2223, 0xA1FD, 0x2225, 0xA1FC, 0x2229, 0xA1E4, 0x222A, 0xA1E5, 0x222B, 0xA1EC, 0x222E, 0xA1ED, 0x2234, 0xA1EF, 0x2235, 0xA1EE, 0x2252, 0xA1DC, 0x2260, 0xA1DA, 0x2261, 0xA1DD, 0x2266, 0xA1D8, 0x2267, 0xA1D9, 0x2295, 0xA1F2, 0x2299, 0xA1F3, 0x22A5, 0xA1E6, 0x22BF, 0xA1E9, 0x2500, 0xA277, 0x2502, 0xA278, 0x250C, 0xA27A, 0x2510, 0xA27B, 0x2514, 0xA27C, 0x2518, 0xA27D, 0x251C, 0xA275, 0x2524, 0xA274, 0x252C, 0xA273, 0x2534, 0xA272, 0x253C, 0xA271, 0x2550, 0xA2A4, 0x2550, 0xF9F9, 0x2551, 0xF9F8, 0x2552, 0xF9E6, 0x2553, 0xF9EF, 0x2554, 0xF9DD, 0x2555, 0xF9E8, 0x2556, 0xF9F1, 0x2557, 0xF9DF, 0x2558, 0xF9EC, 0x2559, 0xF9F5, 0x255A, 0xF9E3, 0x255B, 0xF9EE, 0x255C, 0xF9F7, 0x255D, 0xF9E5, 0x255E, 0xA2A5, 0x255E, 0xF9E9, 0x255F, 0xF9F2, 0x2560, 0xF9E0, 0x2561, 0xA2A7, 0x2561, 0xF9EB, 0x2562, 0xF9F4, 0x2563, 0xF9E2, 0x2564, 0xF9E7, 0x2565, 0xF9F0, 0x2566, 0xF9DE, 0x2567, 0xF9ED, 0x2568, 0xF9F6, 0x2569, 0xF9E4, 0x256A, 0xA2A6, 0x256A, 0xF9EA, 0x256B, 0xF9F3, 0x256C, 0xF9E1, 0x256D, 0xA27E, 0x256D, 0xF9FA, 0x256E, 0xA2A1, 0x256E, 0xF9FB, 0x256F, 0xA2A3, 0x256F, 0xF9FD, 0x2570, 0xA2A2, 0x2570, 0xF9FC, 0x2571, 0xA2AC, 0x2572, 0xA2AD, 0x2573, 0xA2AE, 0x2574, 0xA15A, 0x2581, 0xA262, 0x2582, 0xA263, 0x2583, 0xA264, 0x2584, 0xA265, 0x2585, 0xA266, 0x2586, 0xA267, 0x2587, 0xA268, 0x2588, 0xA269, 0x2589, 0xA270, 0x258A, 0xA26F, 0x258B, 0xA26E, 0x258C, 0xA26D, 0x258D, 0xA26C, 0x258E, 0xA26B, 0x258F, 0xA26A, 0x2593, 0xF9FE, 0x2594, 0xA276, 0x2595, 0xA279, 0x25A0, 0xA1BD, 0x25A1, 0xA1BC, 0x25B2, 0xA1B6, 0x25B3, 0xA1B5, 0x25BC, 0xA1BF, 0x25BD, 0xA1BE, 0x25C6, 0xA1BB, 0x25C7, 0xA1BA, 0x25CB, 0xA1B3, 0x25CE, 0xA1B7, 0x25CF, 0xA1B4, 0x25E2, 0xA2A8, 0x25E3, 0xA2A9, 0x25E4, 0xA2AB, 0x25E5, 0xA2AA, 0x2605, 0xA1B9, 0x2606, 0xA1B8, 0x2640, 0xA1F0, 0x2642, 0xA1F1, 0x3000, 0xA140, 0x3001, 0xA142, 0x3002, 0xA143, 0x3003, 0xA1B2, 0x3008, 0xA171, 0x3009, 0xA172, 0x300A, 0xA16D, 0x300B, 0xA16E, 0x300C, 0xA175, 0x300D, 0xA176, 0x300E, 0xA179, 0x300F, 0xA17A, 0x3010, 0xA169, 0x3011, 0xA16A, 0x3012, 0xA245, 0x3014, 0xA165, 0x3015, 0xA166, 0x301D, 0xA1A9, 0x301E, 0xA1AA, 0x3021, 0xA2C3, 0x3022, 0xA2C4, 0x3023, 0xA2C5, 0x3024, 0xA2C6, 0x3025, 0xA2C7, 0x3026, 0xA2C8, 0x3027, 0xA2C9, 0x3028, 0xA2CA, 0x3029, 0xA2CB, 0x3105, 0xA374, 0x3106, 0xA375, 0x3107, 0xA376, 0x3108, 0xA377, 0x3109, 0xA378, 0x310A, 0xA379, 0x310B, 0xA37A, 0x310C, 0xA37B, 0x310D, 0xA37C, 0x310E, 0xA37D, 0x310F, 0xA37E, 0x3110, 0xA3A1, 0x3111, 0xA3A2, 0x3112, 0xA3A3, 0x3113, 0xA3A4, 0x3114, 0xA3A5, 0x3115, 0xA3A6, 0x3116, 0xA3A7, 0x3117, 0xA3A8, 0x3118, 0xA3A9, 0x3119, 0xA3AA, 0x311A, 0xA3AB, 0x311B, 0xA3AC, 0x311C, 0xA3AD, 0x311D, 0xA3AE, 0x311E, 0xA3AF, 0x311F, 0xA3B0, 0x3120, 0xA3B1, 0x3121, 0xA3B2, 0x3122, 0xA3B3, 0x3123, 0xA3B4, 0x3124, 0xA3B5, 0x3125, 0xA3B6, 0x3126, 0xA3B7, 0x3127, 0xA3B8, 0x3128, 0xA3B9, 0x3129, 0xA3BA, 0x32A3, 0xA1C0, 0x338E, 0xA255, 0x338F, 0xA256, 0x339C, 0xA250, 0x339D, 0xA251, 0x339E, 0xA252, 0x33A1, 0xA254, 0x33C4, 0xA257, 0x33CE, 0xA253, 0x33D1, 0xA1EB, 0x33D2, 0xA1EA, 0x33D5, 0xA24F, 0x4E00, 0xA440, 0x4E01, 0xA442, 0x4E03, 0xA443, 0x4E07, 0xC945, 0x4E08, 0xA456, 0x4E09, 0xA454, 0x4E0A, 0xA457, 0x4E0B, 0xA455, 0x4E0C, 0xC946, 0x4E0D, 0xA4A3, 0x4E0E, 0xC94F, 0x4E0F, 0xC94D, 0x4E10, 0xA4A2, 0x4E11, 0xA4A1, 0x4E14, 0xA542, 0x4E15, 0xA541, 0x4E16, 0xA540, 0x4E18, 0xA543, 0x4E19, 0xA4FE, 0x4E1E, 0xA5E0, 0x4E1F, 0xA5E1, 0x4E26, 0xA8C3, 0x4E2B, 0xA458, 0x4E2D, 0xA4A4, 0x4E2E, 0xC950, 0x4E30, 0xA4A5, 0x4E31, 0xC963, 0x4E32, 0xA6EA, 0x4E33, 0xCBB1, 0x4E38, 0xA459, 0x4E39, 0xA4A6, 0x4E3B, 0xA544, 0x4E3C, 0xC964, 0x4E42, 0xC940, 0x4E43, 0xA444, 0x4E45, 0xA45B, 0x4E47, 0xC947, 0x4E48, 0xA45C, 0x4E4B, 0xA4A7, 0x4E4D, 0xA545, 0x4E4E, 0xA547, 0x4E4F, 0xA546, 0x4E52, 0xA5E2, 0x4E53, 0xA5E3, 0x4E56, 0xA8C4, 0x4E58, 0xADBC, 0x4E59, 0xA441, 0x4E5C, 0xC941, 0x4E5D, 0xA445, 0x4E5E, 0xA45E, 0x4E5F, 0xA45D, 0x4E69, 0xA5E4, 0x4E73, 0xA8C5, 0x4E7E, 0xB0AE, 0x4E7F, 0xD44B, 0x4E82, 0xB6C3, 0x4E83, 0xDCB1, 0x4E84, 0xDCB2, 0x4E86, 0xA446, 0x4E88, 0xA4A9, 0x4E8B, 0xA8C6, 0x4E8C, 0xA447, 0x4E8D, 0xC948, 0x4E8E, 0xA45F, 0x4E91, 0xA4AA, 0x4E92, 0xA4AC, 0x4E93, 0xC951, 0x4E94, 0xA4AD, 0x4E95, 0xA4AB, 0x4E99, 0xA5E5, 0x4E9B, 0xA8C7, 0x4E9E, 0xA8C8, 0x4E9F, 0xAB45, 0x4EA1, 0xA460, 0x4EA2, 0xA4AE, 0x4EA4, 0xA5E6, 0x4EA5, 0xA5E8, 0x4EA6, 0xA5E7, 0x4EA8, 0xA6EB, 0x4EAB, 0xA8C9, 0x4EAC, 0xA8CA, 0x4EAD, 0xAB46, 0x4EAE, 0xAB47, 0x4EB3, 0xADBD, 0x4EB6, 0xDCB3, 0x4EB9, 0xF6D6, 0x4EBA, 0xA448, 0x4EC0, 0xA4B0, 0x4EC1, 0xA4AF, 0x4EC2, 0xC952, 0x4EC3, 0xA4B1, 0x4EC4, 0xA4B7, 0x4EC6, 0xA4B2, 0x4EC7, 0xA4B3, 0x4EC8, 0xC954, 0x4EC9, 0xC953, 0x4ECA, 0xA4B5, 0x4ECB, 0xA4B6, 0x4ECD, 0xA4B4, 0x4ED4, 0xA54A, 0x4ED5, 0xA54B, 0x4ED6, 0xA54C, 0x4ED7, 0xA54D, 0x4ED8, 0xA549, 0x4ED9, 0xA550, 0x4EDA, 0xC96A, 0x4EDC, 0xC966, 0x4EDD, 0xC969, 0x4EDE, 0xA551, 0x4EDF, 0xA561, 0x4EE1, 0xC968, 0x4EE3, 0xA54E, 0x4EE4, 0xA54F, 0x4EE5, 0xA548, 0x4EE8, 0xC965, 0x4EE9, 0xC967, 0x4EF0, 0xA5F5, 0x4EF1, 0xC9B0, 0x4EF2, 0xA5F2, 0x4EF3, 0xA5F6, 0x4EF4, 0xC9BA, 0x4EF5, 0xC9AE, 0x4EF6, 0xA5F3, 0x4EF7, 0xC9B2, 0x4EFB, 0xA5F4, 0x4EFD, 0xA5F7, 0x4EFF, 0xA5E9, 0x4F00, 0xC9B1, 0x4F01, 0xA5F8, 0x4F02, 0xC9B5, 0x4F04, 0xC9B9, 0x4F05, 0xC9B6, 0x4F08, 0xC9B3, 0x4F09, 0xA5EA, 0x4F0A, 0xA5EC, 0x4F0B, 0xA5F9, 0x4F0D, 0xA5EE, 0x4F0E, 0xC9AB, 0x4F0F, 0xA5F1, 0x4F10, 0xA5EF, 0x4F11, 0xA5F0, 0x4F12, 0xC9BB, 0x4F13, 0xC9B8, 0x4F14, 0xC9AF, 0x4F15, 0xA5ED, 0x4F18, 0xC9AC, 0x4F19, 0xA5EB, 0x4F1D, 0xC9B4, 0x4F22, 0xC9B7, 0x4F2C, 0xC9AD, 0x4F2D, 0xCA66, 0x4F2F, 0xA742, 0x4F30, 0xA6F4, 0x4F33, 0xCA67, 0x4F34, 0xA6F1, 0x4F36, 0xA744, 0x4F38, 0xA6F9, 0x4F3A, 0xA6F8, 0x4F3B, 0xCA5B, 0x4F3C, 0xA6FC, 0x4F3D, 0xA6F7, 0x4F3E, 0xCA60, 0x4F3F, 0xCA68, 0x4F41, 0xCA64, 0x4F43, 0xA6FA, 0x4F46, 0xA6FD, 0x4F47, 0xA6EE, 0x4F48, 0xA747, 0x4F49, 0xCA5D, 0x4F4C, 0xCBBD, 0x4F4D, 0xA6EC, 0x4F4E, 0xA743, 0x4F4F, 0xA6ED, 0x4F50, 0xA6F5, 0x4F51, 0xA6F6, 0x4F52, 0xCA62, 0x4F53, 0xCA5E, 0x4F54, 0xA6FB, 0x4F55, 0xA6F3, 0x4F56, 0xCA5A, 0x4F57, 0xA6EF, 0x4F58, 0xCA65, 0x4F59, 0xA745, 0x4F5A, 0xA748, 0x4F5B, 0xA6F2, 0x4F5C, 0xA740, 0x4F5D, 0xA746, 0x4F5E, 0xA6F0, 0x4F5F, 0xCA63, 0x4F60, 0xA741, 0x4F61, 0xCA69, 0x4F62, 0xCA5C, 0x4F63, 0xA6FE, 0x4F64, 0xCA5F, 0x4F67, 0xCA61, 0x4F69, 0xA8D8, 0x4F6A, 0xCBBF, 0x4F6B, 0xCBCB, 0x4F6C, 0xA8D0, 0x4F6E, 0xCBCC, 0x4F6F, 0xA8CB, 0x4F70, 0xA8D5, 0x4F73, 0xA8CE, 0x4F74, 0xCBB9, 0x4F75, 0xA8D6, 0x4F76, 0xCBB8, 0x4F77, 0xCBBC, 0x4F78, 0xCBC3, 0x4F79, 0xCBC1, 0x4F7A, 0xA8DE, 0x4F7B, 0xA8D9, 0x4F7C, 0xCBB3, 0x4F7D, 0xCBB5, 0x4F7E, 0xA8DB, 0x4F7F, 0xA8CF, 0x4F80, 0xCBB6, 0x4F81, 0xCBC2, 0x4F82, 0xCBC9, 0x4F83, 0xA8D4, 0x4F84, 0xCBBB, 0x4F85, 0xCBB4, 0x4F86, 0xA8D3, 0x4F87, 0xCBB7, 0x4F88, 0xA8D7, 0x4F89, 0xCBBA, 0x4F8B, 0xA8D2, 0x4F8D, 0xA8CD, 0x4F8F, 0xA8DC, 0x4F90, 0xCBC4, 0x4F91, 0xA8DD, 0x4F92, 0xCBC8, 0x4F94, 0xCBC6, 0x4F95, 0xCBCA, 0x4F96, 0xA8DA, 0x4F97, 0xCBBE, 0x4F98, 0xCBB2, 0x4F9A, 0xCBC0, 0x4F9B, 0xA8D1, 0x4F9C, 0xCBC5, 0x4F9D, 0xA8CC, 0x4F9E, 0xCBC7, 0x4FAE, 0xAB56, 0x4FAF, 0xAB4A, 0x4FB2, 0xCDE0, 0x4FB3, 0xCDE8, 0x4FB5, 0xAB49, 0x4FB6, 0xAB51, 0x4FB7, 0xAB5D, 0x4FB9, 0xCDEE, 0x4FBA, 0xCDEC, 0x4FBB, 0xCDE7, 0x4FBF, 0xAB4B, 0x4FC0, 0xCDED, 0x4FC1, 0xCDE3, 0x4FC2, 0xAB59, 0x4FC3, 0xAB50, 0x4FC4, 0xAB58, 0x4FC5, 0xCDDE, 0x4FC7, 0xCDEA, 0x4FC9, 0xCDE1, 0x4FCA, 0xAB54, 0x4FCB, 0xCDE2, 0x4FCD, 0xCDDD, 0x4FCE, 0xAB5B, 0x4FCF, 0xAB4E, 0x4FD0, 0xAB57, 0x4FD1, 0xAB4D, 0x4FD3, 0xCDDF, 0x4FD4, 0xCDE4, 0x4FD6, 0xCDEB, 0x4FD7, 0xAB55, 0x4FD8, 0xAB52, 0x4FD9, 0xCDE6, 0x4FDA, 0xAB5A, 0x4FDB, 0xCDE9, 0x4FDC, 0xCDE5, 0x4FDD, 0xAB4F, 0x4FDE, 0xAB5C, 0x4FDF, 0xAB53, 0x4FE0, 0xAB4C, 0x4FE1, 0xAB48, 0x4FEC, 0xCDEF, 0x4FEE, 0xADD7, 0x4FEF, 0xADC1, 0x4FF1, 0xADD1, 0x4FF3, 0xADD6, 0x4FF4, 0xD0D0, 0x4FF5, 0xD0CF, 0x4FF6, 0xD0D4, 0x4FF7, 0xD0D5, 0x4FF8, 0xADC4, 0x4FFA, 0xADCD, 0x4FFE, 0xADDA, 0x5000, 0xADCE, 0x5005, 0xD0C9, 0x5006, 0xADC7, 0x5007, 0xD0CA, 0x5009, 0xADDC, 0x500B, 0xADD3, 0x500C, 0xADBE, 0x500D, 0xADBF, 0x500E, 0xD0DD, 0x500F, 0xB0BF, 0x5011, 0xADCC, 0x5012, 0xADCB, 0x5013, 0xD0CB, 0x5014, 0xADCF, 0x5015, 0xD45B, 0x5016, 0xADC6, 0x5017, 0xD0D6, 0x5018, 0xADD5, 0x5019, 0xADD4, 0x501A, 0xADCA, 0x501B, 0xD0CE, 0x501C, 0xD0D7, 0x501E, 0xD0C8, 0x501F, 0xADC9, 0x5020, 0xD0D8, 0x5021, 0xADD2, 0x5022, 0xD0CC, 0x5023, 0xADC0, 0x5025, 0xADC3, 0x5026, 0xADC2, 0x5027, 0xD0D9, 0x5028, 0xADD0, 0x5029, 0xADC5, 0x502A, 0xADD9, 0x502B, 0xADDB, 0x502C, 0xD0D3, 0x502D, 0xADD8, 0x502F, 0xD0DB, 0x5030, 0xD0CD, 0x5031, 0xD0DC, 0x5033, 0xD0D1, 0x5035, 0xD0DA, 0x5037, 0xD0D2, 0x503C, 0xADC8, 0x5040, 0xD463, 0x5041, 0xD457, 0x5043, 0xB0B3, 0x5045, 0xD45C, 0x5046, 0xD462, 0x5047, 0xB0B2, 0x5048, 0xD455, 0x5049, 0xB0B6, 0x504A, 0xD459, 0x504B, 0xD452, 0x504C, 0xB0B4, 0x504D, 0xD456, 0x504E, 0xB0B9, 0x504F, 0xB0BE, 0x5051, 0xD467, 0x5053, 0xD451, 0x5055, 0xB0BA, 0x5057, 0xD466, 0x505A, 0xB0B5, 0x505B, 0xD458, 0x505C, 0xB0B1, 0x505D, 0xD453, 0x505E, 0xD44F, 0x505F, 0xD45D, 0x5060, 0xD450, 0x5061, 0xD44E, 0x5062, 0xD45A, 0x5063, 0xD460, 0x5064, 0xD461, 0x5065, 0xB0B7, 0x5068, 0xD85B, 0x5069, 0xD45E, 0x506A, 0xD44D, 0x506B, 0xD45F, 0x506D, 0xB0C1, 0x506E, 0xD464, 0x506F, 0xB0C0, 0x5070, 0xD44C, 0x5072, 0xD454, 0x5073, 0xD465, 0x5074, 0xB0BC, 0x5075, 0xB0BB, 0x5076, 0xB0B8, 0x5077, 0xB0BD, 0x507A, 0xB0AF, 0x507D, 0xB0B0, 0x5080, 0xB3C8, 0x5082, 0xD85E, 0x5083, 0xD857, 0x5085, 0xB3C5, 0x5087, 0xD85F, 0x508B, 0xD855, 0x508C, 0xD858, 0x508D, 0xB3C4, 0x508E, 0xD859, 0x5091, 0xB3C7, 0x5092, 0xD85D, 0x5094, 0xD853, 0x5095, 0xD852, 0x5096, 0xB3C9, 0x5098, 0xB3CA, 0x5099, 0xB3C6, 0x509A, 0xB3CB, 0x509B, 0xD851, 0x509C, 0xD85C, 0x509D, 0xD85A, 0x509E, 0xD854, 0x50A2, 0xB3C3, 0x50A3, 0xD856, 0x50AC, 0xB6CA, 0x50AD, 0xB6C4, 0x50AE, 0xDCB7, 0x50AF, 0xB6CD, 0x50B0, 0xDCBD, 0x50B1, 0xDCC0, 0x50B2, 0xB6C6, 0x50B3, 0xB6C7, 0x50B4, 0xDCBA, 0x50B5, 0xB6C5, 0x50B6, 0xDCC3, 0x50B7, 0xB6CB, 0x50B8, 0xDCC4, 0x50BA, 0xDCBF, 0x50BB, 0xB6CC, 0x50BD, 0xDCB4, 0x50BE, 0xB6C9, 0x50BF, 0xDCB5, 0x50C1, 0xDCBE, 0x50C2, 0xDCBC, 0x50C4, 0xDCB8, 0x50C5, 0xB6C8, 0x50C6, 0xDCB6, 0x50C7, 0xB6CE, 0x50C8, 0xDCBB, 0x50C9, 0xDCC2, 0x50CA, 0xDCB9, 0x50CB, 0xDCC1, 0x50CE, 0xB9B6, 0x50CF, 0xB9B3, 0x50D1, 0xB9B4, 0x50D3, 0xE0F9, 0x50D4, 0xE0F1, 0x50D5, 0xB9B2, 0x50D6, 0xB9AF, 0x50D7, 0xE0F2, 0x50DA, 0xB9B1, 0x50DB, 0xE0F5, 0x50DD, 0xE0F7, 0x50E0, 0xE0FE, 0x50E3, 0xE0FD, 0x50E4, 0xE0F8, 0x50E5, 0xB9AE, 0x50E6, 0xE0F0, 0x50E7, 0xB9AC, 0x50E8, 0xE0F3, 0x50E9, 0xB9B7, 0x50EA, 0xE0F6, 0x50EC, 0xE0FA, 0x50ED, 0xB9B0, 0x50EE, 0xB9AD, 0x50EF, 0xE0FC, 0x50F0, 0xE0FB, 0x50F1, 0xB9B5, 0x50F3, 0xE0F4, 0x50F5, 0xBBF8, 0x50F6, 0xE4EC, 0x50F8, 0xE4E9, 0x50F9, 0xBBF9, 0x50FB, 0xBBF7, 0x50FD, 0xE4F0, 0x50FE, 0xE4ED, 0x50FF, 0xE4E6, 0x5100, 0xBBF6, 0x5102, 0xBBFA, 0x5103, 0xE4E7, 0x5104, 0xBBF5, 0x5105, 0xBBFD, 0x5106, 0xE4EA, 0x5107, 0xE4EB, 0x5108, 0xBBFB, 0x5109, 0xBBFC, 0x510A, 0xE4F1, 0x510B, 0xE4EE, 0x510C, 0xE4EF, 0x5110, 0xBEAA, 0x5111, 0xE8F8, 0x5112, 0xBEA7, 0x5113, 0xE8F5, 0x5114, 0xBEA9, 0x5115, 0xBEAB, 0x5117, 0xE8F6, 0x5118, 0xBEA8, 0x511A, 0xE8F7, 0x511C, 0xE8F4, 0x511F, 0xC076, 0x5120, 0xECBD, 0x5121, 0xC077, 0x5122, 0xECBB, 0x5124, 0xECBC, 0x5125, 0xECBA, 0x5126, 0xECB9, 0x5129, 0xECBE, 0x512A, 0xC075, 0x512D, 0xEFB8, 0x512E, 0xEFB9, 0x5130, 0xE4E8, 0x5131, 0xEFB7, 0x5132, 0xC078, 0x5133, 0xC35F, 0x5134, 0xF1EB, 0x5135, 0xF1EC, 0x5137, 0xC4D7, 0x5138, 0xC4D8, 0x5139, 0xF5C1, 0x513A, 0xF5C0, 0x513B, 0xC56C, 0x513C, 0xC56B, 0x513D, 0xF7D0, 0x513F, 0xA449, 0x5140, 0xA461, 0x5141, 0xA4B9, 0x5143, 0xA4B8, 0x5144, 0xA553, 0x5145, 0xA552, 0x5146, 0xA5FC, 0x5147, 0xA5FB, 0x5148, 0xA5FD, 0x5149, 0xA5FA, 0x514B, 0xA74A, 0x514C, 0xA749, 0x514D, 0xA74B, 0x5152, 0xA8E0, 0x5154, 0xA8DF, 0x5155, 0xA8E1, 0x5157, 0xAB5E, 0x5159, 0xA259, 0x515A, 0xD0DE, 0x515B, 0xA25A, 0x515C, 0xB0C2, 0x515D, 0xA25C, 0x515E, 0xA25B, 0x515F, 0xD860, 0x5161, 0xA25D, 0x5162, 0xB9B8, 0x5163, 0xA25E, 0x5165, 0xA44A, 0x5167, 0xA4BA, 0x5168, 0xA5FE, 0x5169, 0xA8E2, 0x516B, 0xA44B, 0x516C, 0xA4BD, 0x516D, 0xA4BB, 0x516E, 0xA4BC, 0x5171, 0xA640, 0x5175, 0xA74C, 0x5176, 0xA8E4, 0x5177, 0xA8E3, 0x5178, 0xA8E5, 0x517C, 0xADDD, 0x5180, 0xBEAC, 0x5187, 0xC94E, 0x5189, 0xA554, 0x518A, 0xA555, 0x518D, 0xA641, 0x518F, 0xCA6A, 0x5191, 0xAB60, 0x5192, 0xAB5F, 0x5193, 0xD0E0, 0x5194, 0xD0DF, 0x5195, 0xB0C3, 0x5197, 0xA4BE, 0x5198, 0xC955, 0x519E, 0xCBCD, 0x51A0, 0xAB61, 0x51A2, 0xADE0, 0x51A4, 0xADDE, 0x51A5, 0xADDF, 0x51AA, 0xBEAD, 0x51AC, 0xA556, 0x51B0, 0xA642, 0x51B1, 0xC9BC, 0x51B6, 0xA74D, 0x51B7, 0xA74E, 0x51B9, 0xCA6B, 0x51BC, 0xCBCE, 0x51BD, 0xA8E6, 0x51BE, 0xCBCF, 0x51C4, 0xD0E2, 0x51C5, 0xD0E3, 0x51C6, 0xADE3, 0x51C8, 0xD0E4, 0x51CA, 0xD0E1, 0x51CB, 0xADE4, 0x51CC, 0xADE2, 0x51CD, 0xADE1, 0x51CE, 0xD0E5, 0x51D0, 0xD468, 0x51D4, 0xD861, 0x51D7, 0xDCC5, 0x51D8, 0xE140, 0x51DC, 0xBBFE, 0x51DD, 0xBEAE, 0x51DE, 0xE8F9, 0x51E0, 0xA44C, 0x51E1, 0xA45A, 0x51F0, 0xB0C4, 0x51F1, 0xB3CD, 0x51F3, 0xB9B9, 0x51F5, 0xC942, 0x51F6, 0xA4BF, 0x51F8, 0xA559, 0x51F9, 0xA557, 0x51FA, 0xA558, 0x51FD, 0xA8E7, 0x5200, 0xA44D, 0x5201, 0xA44E, 0x5203, 0xA462, 0x5206, 0xA4C0, 0x5207, 0xA4C1, 0x5208, 0xA4C2, 0x5209, 0xC9BE, 0x520A, 0xA55A, 0x520C, 0xC96B, 0x520E, 0xA646, 0x5210, 0xC9BF, 0x5211, 0xA644, 0x5212, 0xA645, 0x5213, 0xC9BD, 0x5216, 0xA647, 0x5217, 0xA643, 0x521C, 0xCA6C, 0x521D, 0xAAEC, 0x521E, 0xCA6D, 0x5221, 0xCA6E, 0x5224, 0xA750, 0x5225, 0xA74F, 0x5228, 0xA753, 0x5229, 0xA751, 0x522A, 0xA752, 0x522E, 0xA8ED, 0x5230, 0xA8EC, 0x5231, 0xCBD4, 0x5232, 0xCBD1, 0x5233, 0xCBD2, 0x5235, 0xCBD0, 0x5236, 0xA8EE, 0x5237, 0xA8EA, 0x5238, 0xA8E9, 0x523A, 0xA8EB, 0x523B, 0xA8E8, 0x5241, 0xA8EF, 0x5243, 0xAB63, 0x5244, 0xCDF0, 0x5246, 0xCBD3, 0x5247, 0xAB68, 0x5249, 0xCDF1, 0x524A, 0xAB64, 0x524B, 0xAB67, 0x524C, 0xAB66, 0x524D, 0xAB65, 0x524E, 0xAB62, 0x5252, 0xD0E8, 0x5254, 0xADE7, 0x5255, 0xD0EB, 0x5256, 0xADE5, 0x525A, 0xD0E7, 0x525B, 0xADE8, 0x525C, 0xADE6, 0x525D, 0xADE9, 0x525E, 0xD0E9, 0x525F, 0xD0EA, 0x5261, 0xD0E6, 0x5262, 0xD0EC, 0x5269, 0xB3D1, 0x526A, 0xB0C5, 0x526B, 0xD469, 0x526C, 0xD46B, 0x526D, 0xD46A, 0x526E, 0xD46C, 0x526F, 0xB0C6, 0x5272, 0xB3CE, 0x5274, 0xB3CF, 0x5275, 0xB3D0, 0x5277, 0xB6D0, 0x5278, 0xDCC7, 0x527A, 0xDCC6, 0x527B, 0xDCC8, 0x527C, 0xDCC9, 0x527D, 0xB6D1, 0x527F, 0xB6CF, 0x5280, 0xE141, 0x5281, 0xE142, 0x5282, 0xB9BB, 0x5283, 0xB9BA, 0x5284, 0xE35A, 0x5287, 0xBC40, 0x5288, 0xBC41, 0x5289, 0xBC42, 0x528A, 0xBC44, 0x528B, 0xE4F2, 0x528C, 0xE4F3, 0x528D, 0xBC43, 0x5291, 0xBEAF, 0x5293, 0xBEB0, 0x5296, 0xF1ED, 0x5297, 0xF5C3, 0x5298, 0xF5C2, 0x5299, 0xF7D1, 0x529B, 0xA44F, 0x529F, 0xA55C, 0x52A0, 0xA55B, 0x52A3, 0xA648, 0x52A6, 0xC9C0, 0x52A9, 0xA755, 0x52AA, 0xA756, 0x52AB, 0xA754, 0x52AC, 0xA757, 0x52AD, 0xCA6F, 0x52AE, 0xCA70, 0x52BB, 0xA8F1, 0x52BC, 0xCBD5, 0x52BE, 0xA8F0, 0x52C0, 0xCDF2, 0x52C1, 0xAB6C, 0x52C2, 0xCDF3, 0x52C3, 0xAB6B, 0x52C7, 0xAB69, 0x52C9, 0xAB6A, 0x52CD, 0xD0ED, 0x52D2, 0xB0C7, 0x52D3, 0xD46E, 0x52D5, 0xB0CA, 0x52D6, 0xD46D, 0x52D7, 0xB1E5, 0x52D8, 0xB0C9, 0x52D9, 0xB0C8, 0x52DB, 0xB3D4, 0x52DD, 0xB3D3, 0x52DE, 0xB3D2, 0x52DF, 0xB6D2, 0x52E2, 0xB6D5, 0x52E3, 0xB6D6, 0x52E4, 0xB6D4, 0x52E6, 0xB6D3, 0x52E9, 0xE143, 0x52EB, 0xE144, 0x52EF, 0xE4F5, 0x52F0, 0xBC45, 0x52F1, 0xE4F4, 0x52F3, 0xBEB1, 0x52F4, 0xECBF, 0x52F5, 0xC079, 0x52F7, 0xF1EE, 0x52F8, 0xC455, 0x52FA, 0xA463, 0x52FB, 0xA4C3, 0x52FC, 0xC956, 0x52FE, 0xA4C4, 0x52FF, 0xA4C5, 0x5305, 0xA55D, 0x5306, 0xA55E, 0x5308, 0xA649, 0x5309, 0xCA71, 0x530A, 0xCBD6, 0x530B, 0xCBD7, 0x530D, 0xAB6D, 0x530E, 0xD0EE, 0x530F, 0xB0CC, 0x5310, 0xB0CB, 0x5311, 0xD863, 0x5312, 0xD862, 0x5315, 0xA450, 0x5316, 0xA4C6, 0x5317, 0xA55F, 0x5319, 0xB0CD, 0x531A, 0xC943, 0x531C, 0xC96C, 0x531D, 0xA560, 0x531F, 0xC9C2, 0x5320, 0xA64B, 0x5321, 0xA64A, 0x5322, 0xC9C1, 0x5323, 0xA758, 0x532A, 0xADEA, 0x532D, 0xD46F, 0x532F, 0xB6D7, 0x5330, 0xE145, 0x5331, 0xB9BC, 0x5334, 0xE8FA, 0x5337, 0xF3FD, 0x5339, 0xA4C7, 0x533C, 0xCBD8, 0x533D, 0xCDF4, 0x533E, 0xB0D0, 0x533F, 0xB0CE, 0x5340, 0xB0CF, 0x5341, 0xA2CC, 0x5341, 0xA451, 0x5343, 0xA464, 0x5344, 0xA2CD, 0x5345, 0xA2CE, 0x5345, 0xA4CA, 0x5347, 0xA4C9, 0x5348, 0xA4C8, 0x5349, 0xA563, 0x534A, 0xA562, 0x534C, 0xC96D, 0x534D, 0xC9C3, 0x5351, 0xA8F5, 0x5352, 0xA8F2, 0x5353, 0xA8F4, 0x5354, 0xA8F3, 0x5357, 0xAB6E, 0x535A, 0xB3D5, 0x535C, 0xA452, 0x535E, 0xA4CB, 0x5360, 0xA565, 0x5361, 0xA564, 0x5363, 0xCA72, 0x5366, 0xA8F6, 0x536C, 0xC957, 0x536E, 0xA567, 0x536F, 0xA566, 0x5370, 0xA64C, 0x5371, 0xA64D, 0x5372, 0xCA73, 0x5373, 0xA759, 0x5375, 0xA75A, 0x5377, 0xA8F7, 0x5378, 0xA8F8, 0x5379, 0xA8F9, 0x537B, 0xAB6F, 0x537C, 0xCDF5, 0x537F, 0xADEB, 0x5382, 0xC944, 0x5384, 0xA4CC, 0x538A, 0xC9C4, 0x538E, 0xCA74, 0x538F, 0xCA75, 0x5392, 0xCBD9, 0x5394, 0xCBDA, 0x5396, 0xCDF7, 0x5397, 0xCDF6, 0x5398, 0xCDF9, 0x5399, 0xCDF8, 0x539A, 0xAB70, 0x539C, 0xD470, 0x539D, 0xADED, 0x539E, 0xD0EF, 0x539F, 0xADEC, 0x53A4, 0xD864, 0x53A5, 0xB3D6, 0x53A7, 0xD865, 0x53AC, 0xE146, 0x53AD, 0xB9BD, 0x53B2, 0xBC46, 0x53B4, 0xF1EF, 0x53B9, 0xC958, 0x53BB, 0xA568, 0x53C3, 0xB0D1, 0x53C8, 0xA453, 0x53C9, 0xA465, 0x53CA, 0xA4CE, 0x53CB, 0xA4CD, 0x53CD, 0xA4CF, 0x53D4, 0xA8FB, 0x53D6, 0xA8FA, 0x53D7, 0xA8FC, 0x53DB, 0xAB71, 0x53DF, 0xADEE, 0x53E1, 0xE8FB, 0x53E2, 0xC24F, 0x53E3, 0xA466, 0x53E4, 0xA56A, 0x53E5, 0xA579, 0x53E6, 0xA574, 0x53E8, 0xA56F, 0x53E9, 0xA56E, 0x53EA, 0xA575, 0x53EB, 0xA573, 0x53EC, 0xA56C, 0x53ED, 0xA57A, 0x53EE, 0xA56D, 0x53EF, 0xA569, 0x53F0, 0xA578, 0x53F1, 0xA577, 0x53F2, 0xA576, 0x53F3, 0xA56B, 0x53F5, 0xA572, 0x53F8, 0xA571, 0x53FB, 0xA57B, 0x53FC, 0xA570, 0x5401, 0xA653, 0x5403, 0xA659, 0x5404, 0xA655, 0x5406, 0xA65B, 0x5407, 0xC9C5, 0x5408, 0xA658, 0x5409, 0xA64E, 0x540A, 0xA651, 0x540B, 0xA654, 0x540C, 0xA650, 0x540D, 0xA657, 0x540E, 0xA65A, 0x540F, 0xA64F, 0x5410, 0xA652, 0x5411, 0xA656, 0x5412, 0xA65C, 0x5418, 0xCA7E, 0x5419, 0xCA7B, 0x541B, 0xA767, 0x541C, 0xCA7C, 0x541D, 0xA75B, 0x541E, 0xA75D, 0x541F, 0xA775, 0x5420, 0xA770, 0x5424, 0xCAA5, 0x5425, 0xCA7D, 0x5426, 0xA75F, 0x5427, 0xA761, 0x5428, 0xCAA4, 0x5429, 0xA768, 0x542A, 0xCA78, 0x542B, 0xA774, 0x542C, 0xA776, 0x542D, 0xA75C, 0x542E, 0xA76D, 0x5430, 0xCA76, 0x5431, 0xA773, 0x5433, 0xA764, 0x5435, 0xA76E, 0x5436, 0xA76F, 0x5437, 0xCA77, 0x5438, 0xA76C, 0x5439, 0xA76A, 0x543B, 0xA76B, 0x543C, 0xA771, 0x543D, 0xCAA1, 0x543E, 0xA75E, 0x5440, 0xA772, 0x5441, 0xCAA3, 0x5442, 0xA766, 0x5443, 0xA763, 0x5445, 0xCA7A, 0x5446, 0xA762, 0x5447, 0xCAA6, 0x5448, 0xA765, 0x544A, 0xA769, 0x544E, 0xA760, 0x544F, 0xCAA2, 0x5454, 0xCA79, 0x5460, 0xCBEB, 0x5461, 0xCBEA, 0x5462, 0xA94F, 0x5463, 0xCBED, 0x5464, 0xCBEF, 0x5465, 0xCBE4, 0x5466, 0xCBE7, 0x5467, 0xCBEE, 0x5468, 0xA950, 0x546B, 0xCBE1, 0x546C, 0xCBE5, 0x546F, 0xCBE9, 0x5470, 0xCE49, 0x5471, 0xA94B, 0x5472, 0xCE4D, 0x5473, 0xA8FD, 0x5474, 0xCBE6, 0x5475, 0xA8FE, 0x5476, 0xA94C, 0x5477, 0xA945, 0x5478, 0xA941, 0x547A, 0xCBE2, 0x547B, 0xA944, 0x547C, 0xA949, 0x547D, 0xA952, 0x547E, 0xCBE3, 0x547F, 0xCBDC, 0x5480, 0xA943, 0x5481, 0xCBDD, 0x5482, 0xCBDF, 0x5484, 0xA946, 0x5486, 0xA948, 0x5487, 0xCBDB, 0x5488, 0xCBE0, 0x548B, 0xA951, 0x548C, 0xA94D, 0x548D, 0xCBE8, 0x548E, 0xA953, 0x5490, 0xA94A, 0x5491, 0xCBDE, 0x5492, 0xA947, 0x5495, 0xA942, 0x5496, 0xA940, 0x5498, 0xCBEC, 0x549A, 0xA94E, 0x54A0, 0xCE48, 0x54A1, 0xCDFB, 0x54A2, 0xCE4B, 0x54A5, 0xCDFD, 0x54A6, 0xAB78, 0x54A7, 0xABA8, 0x54A8, 0xAB74, 0x54A9, 0xABA7, 0x54AA, 0xAB7D, 0x54AB, 0xABA4, 0x54AC, 0xAB72, 0x54AD, 0xCDFC, 0x54AE, 0xCE43, 0x54AF, 0xABA3, 0x54B0, 0xCE4F, 0x54B1, 0xABA5, 0x54B3, 0xAB79, 0x54B6, 0xCE45, 0x54B7, 0xCE42, 0x54B8, 0xAB77, 0x54BA, 0xCDFA, 0x54BB, 0xABA6, 0x54BC, 0xCE4A, 0x54BD, 0xAB7C, 0x54BE, 0xCE4C, 0x54BF, 0xABA9, 0x54C0, 0xAB73, 0x54C1, 0xAB7E, 0x54C2, 0xAB7B, 0x54C3, 0xCE40, 0x54C4, 0xABA1, 0x54C5, 0xCE46, 0x54C6, 0xCE47, 0x54C7, 0xAB7A, 0x54C8, 0xABA2, 0x54C9, 0xAB76, 0x54CE, 0xAB75, 0x54CF, 0xCDFE, 0x54D6, 0xCE44, 0x54DE, 0xCE4E, 0x54E0, 0xD144, 0x54E1, 0xADFB, 0x54E2, 0xD0F1, 0x54E4, 0xD0F6, 0x54E5, 0xADF4, 0x54E6, 0xAE40, 0x54E7, 0xD0F4, 0x54E8, 0xADEF, 0x54E9, 0xADF9, 0x54EA, 0xADFE, 0x54EB, 0xD0FB, 0x54ED, 0xADFA, 0x54EE, 0xADFD, 0x54F1, 0xD0FE, 0x54F2, 0xADF5, 0x54F3, 0xD0F5, 0x54F7, 0xD142, 0x54F8, 0xD143, 0x54FA, 0xADF7, 0x54FB, 0xD141, 0x54FC, 0xADF3, 0x54FD, 0xAE43, 0x54FF, 0xD0F8, 0x5501, 0xADF1, 0x5503, 0xD146, 0x5504, 0xD0F9, 0x5505, 0xD0FD, 0x5506, 0xADF6, 0x5507, 0xAE42, 0x5508, 0xD0FA, 0x5509, 0xADFC, 0x550A, 0xD140, 0x550B, 0xD147, 0x550C, 0xD4A1, 0x550E, 0xD145, 0x550F, 0xAE44, 0x5510, 0xADF0, 0x5511, 0xD0FC, 0x5512, 0xD0F3, 0x5514, 0xADF8, 0x5517, 0xD0F2, 0x551A, 0xD0F7, 0x5526, 0xD0F0, 0x5527, 0xAE41, 0x552A, 0xD477, 0x552C, 0xB0E4, 0x552D, 0xD4A7, 0x552E, 0xB0E2, 0x552F, 0xB0DF, 0x5530, 0xD47C, 0x5531, 0xB0DB, 0x5532, 0xD4A2, 0x5533, 0xB0E6, 0x5534, 0xD476, 0x5535, 0xD47B, 0x5536, 0xD47A, 0x5537, 0xADF2, 0x5538, 0xB0E1, 0x5539, 0xD4A5, 0x553B, 0xD4A8, 0x553C, 0xD473, 0x553E, 0xB3E8, 0x5540, 0xD4A9, 0x5541, 0xB0E7, 0x5543, 0xB0D9, 0x5544, 0xB0D6, 0x5545, 0xD47E, 0x5546, 0xB0D3, 0x5548, 0xD4A6, 0x554A, 0xB0DA, 0x554B, 0xD4AA, 0x554D, 0xD474, 0x554E, 0xD4A4, 0x554F, 0xB0DD, 0x5550, 0xD475, 0x5551, 0xD478, 0x5552, 0xD47D, 0x5555, 0xB0DE, 0x5556, 0xB0DC, 0x5557, 0xB0E8, 0x555C, 0xB0E3, 0x555E, 0xB0D7, 0x555F, 0xB1D2, 0x5561, 0xB0D8, 0x5562, 0xD479, 0x5563, 0xB0E5, 0x5564, 0xB0E0, 0x5565, 0xD4A3, 0x5566, 0xB0D5, 0x556A, 0xB0D4, 0x5575, 0xD471, 0x5576, 0xD472, 0x5577, 0xD86A, 0x557B, 0xB3D7, 0x557C, 0xB3DA, 0x557D, 0xD875, 0x557E, 0xB3EE, 0x557F, 0xD878, 0x5580, 0xB3D8, 0x5581, 0xD871, 0x5582, 0xB3DE, 0x5583, 0xB3E4, 0x5584, 0xB5BD, 0x5587, 0xB3E2, 0x5588, 0xD86E, 0x5589, 0xB3EF, 0x558A, 0xB3DB, 0x558B, 0xB3E3, 0x558C, 0xD876, 0x558D, 0xDCD7, 0x558E, 0xD87B, 0x558F, 0xD86F, 0x5591, 0xD866, 0x5592, 0xD873, 0x5593, 0xD86D, 0x5594, 0xB3E1, 0x5595, 0xD879, 0x5598, 0xB3DD, 0x5599, 0xB3F1, 0x559A, 0xB3EA, 0x559C, 0xB3DF, 0x559D, 0xB3DC, 0x559F, 0xB3E7, 0x55A1, 0xD87A, 0x55A2, 0xD86C, 0x55A3, 0xD872, 0x55A4, 0xD874, 0x55A5, 0xD868, 0x55A6, 0xD877, 0x55A7, 0xB3D9, 0x55A8, 0xD867, 0x55AA, 0xB3E0, 0x55AB, 0xB3F0, 0x55AC, 0xB3EC, 0x55AD, 0xD869, 0x55AE, 0xB3E6, 0x55B1, 0xB3ED, 0x55B2, 0xB3E9, 0x55B3, 0xB3E5, 0x55B5, 0xD870, 0x55BB, 0xB3EB, 0x55BF, 0xDCD5, 0x55C0, 0xDCD1, 0x55C2, 0xDCE0, 0x55C3, 0xDCCA, 0x55C4, 0xDCD3, 0x55C5, 0xB6E5, 0x55C6, 0xB6E6, 0x55C7, 0xB6DE, 0x55C8, 0xDCDC, 0x55C9, 0xB6E8, 0x55CA, 0xDCCF, 0x55CB, 0xDCCE, 0x55CC, 0xDCCC, 0x55CD, 0xDCDE, 0x55CE, 0xB6DC, 0x55CF, 0xDCD8, 0x55D0, 0xDCCD, 0x55D1, 0xB6DF, 0x55D2, 0xDCD6, 0x55D3, 0xB6DA, 0x55D4, 0xDCD2, 0x55D5, 0xDCD9, 0x55D6, 0xDCDB, 0x55D9, 0xDCDF, 0x55DA, 0xB6E3, 0x55DB, 0xDCCB, 0x55DC, 0xB6DD, 0x55DD, 0xDCD0, 0x55DF, 0xB6D8, 0x55E1, 0xB6E4, 0x55E2, 0xDCDA, 0x55E3, 0xB6E0, 0x55E4, 0xB6E1, 0x55E5, 0xB6E7, 0x55E6, 0xB6DB, 0x55E7, 0xA25F, 0x55E8, 0xB6D9, 0x55E9, 0xDCD4, 0x55EF, 0xB6E2, 0x55F2, 0xDCDD, 0x55F6, 0xB9CD, 0x55F7, 0xB9C8, 0x55F9, 0xE155, 0x55FA, 0xE151, 0x55FC, 0xE14B, 0x55FD, 0xB9C2, 0x55FE, 0xB9BE, 0x55FF, 0xE154, 0x5600, 0xB9BF, 0x5601, 0xE14E, 0x5602, 0xE150, 0x5604, 0xE153, 0x5606, 0xB9C4, 0x5608, 0xB9CB, 0x5609, 0xB9C5, 0x560C, 0xE149, 0x560D, 0xB9C6, 0x560E, 0xB9C7, 0x560F, 0xE14C, 0x5610, 0xB9CC, 0x5612, 0xE14A, 0x5613, 0xE14F, 0x5614, 0xB9C3, 0x5615, 0xE148, 0x5616, 0xB9C9, 0x5617, 0xB9C1, 0x561B, 0xB9C0, 0x561C, 0xE14D, 0x561D, 0xE152, 0x561F, 0xB9CA, 0x5627, 0xE147, 0x5629, 0xBC4D, 0x562A, 0xE547, 0x562C, 0xE544, 0x562E, 0xBC47, 0x562F, 0xBC53, 0x5630, 0xBC54, 0x5632, 0xBC4A, 0x5633, 0xE542, 0x5634, 0xBC4C, 0x5635, 0xE4F9, 0x5636, 0xBC52, 0x5638, 0xE546, 0x5639, 0xBC49, 0x563A, 0xE548, 0x563B, 0xBC48, 0x563D, 0xE543, 0x563E, 0xE545, 0x563F, 0xBC4B, 0x5640, 0xE541, 0x5641, 0xE4FA, 0x5642, 0xE4F7, 0x5645, 0xD86B, 0x5646, 0xE4FD, 0x5648, 0xE4F6, 0x5649, 0xE4FC, 0x564A, 0xE4FB, 0x564C, 0xE4F8, 0x564E, 0xBC4F, 0x5653, 0xBC4E, 0x5657, 0xBC50, 0x5658, 0xE4FE, 0x5659, 0xBEB2, 0x565A, 0xE540, 0x565E, 0xE945, 0x5660, 0xE8FD, 0x5662, 0xBEBE, 0x5663, 0xE942, 0x5664, 0xBEB6, 0x5665, 0xBEBA, 0x5666, 0xE941, 0x5668, 0xBEB9, 0x5669, 0xBEB5, 0x566A, 0xBEB8, 0x566B, 0xBEB3, 0x566C, 0xBEBD, 0x566D, 0xE943, 0x566E, 0xE8FE, 0x566F, 0xBEBC, 0x5670, 0xE8FC, 0x5671, 0xBEBB, 0x5672, 0xE944, 0x5673, 0xE940, 0x5674, 0xBC51, 0x5676, 0xBEBF, 0x5677, 0xE946, 0x5678, 0xBEB7, 0x5679, 0xBEB4, 0x567E, 0xECC6, 0x567F, 0xECC8, 0x5680, 0xC07B, 0x5681, 0xECC9, 0x5682, 0xECC7, 0x5683, 0xECC5, 0x5684, 0xECC4, 0x5685, 0xC07D, 0x5686, 0xECC3, 0x5687, 0xC07E, 0x568C, 0xECC1, 0x568D, 0xECC2, 0x568E, 0xC07A, 0x568F, 0xC0A1, 0x5690, 0xC07C, 0x5693, 0xECC0, 0x5695, 0xC250, 0x5697, 0xEFBC, 0x5698, 0xEFBA, 0x5699, 0xEFBF, 0x569A, 0xEFBD, 0x569C, 0xEFBB, 0x569D, 0xEFBE, 0x56A5, 0xC360, 0x56A6, 0xF1F2, 0x56A7, 0xF1F3, 0x56A8, 0xC456, 0x56AA, 0xF1F4, 0x56AB, 0xF1F0, 0x56AC, 0xF1F5, 0x56AD, 0xF1F1, 0x56AE, 0xC251, 0x56B2, 0xF3FE, 0x56B3, 0xF441, 0x56B4, 0xC459, 0x56B5, 0xF440, 0x56B6, 0xC458, 0x56B7, 0xC457, 0x56BC, 0xC45A, 0x56BD, 0xF5C5, 0x56BE, 0xF5C6, 0x56C0, 0xC4DA, 0x56C1, 0xC4D9, 0x56C2, 0xC4DB, 0x56C3, 0xF5C4, 0x56C5, 0xF6D8, 0x56C6, 0xF6D7, 0x56C8, 0xC56D, 0x56C9, 0xC56F, 0x56CA, 0xC56E, 0x56CB, 0xF6D9, 0x56CC, 0xC5C8, 0x56CD, 0xF8A6, 0x56D1, 0xC5F1, 0x56D3, 0xF8A5, 0x56D4, 0xF8EE, 0x56D7, 0xC949, 0x56DA, 0xA57D, 0x56DB, 0xA57C, 0x56DD, 0xA65F, 0x56DE, 0xA65E, 0x56DF, 0xC9C7, 0x56E0, 0xA65D, 0x56E1, 0xC9C6, 0x56E4, 0xA779, 0x56E5, 0xCAA9, 0x56E7, 0xCAA8, 0x56EA, 0xA777, 0x56EB, 0xA77A, 0x56EE, 0xCAA7, 0x56F0, 0xA778, 0x56F7, 0xCBF0, 0x56F9, 0xCBF1, 0x56FA, 0xA954, 0x56FF, 0xABAA, 0x5701, 0xD148, 0x5702, 0xD149, 0x5703, 0xAE45, 0x5704, 0xAE46, 0x5707, 0xD4AC, 0x5708, 0xB0E9, 0x5709, 0xB0EB, 0x570A, 0xD4AB, 0x570B, 0xB0EA, 0x570C, 0xD87C, 0x570D, 0xB3F2, 0x5712, 0xB6E9, 0x5713, 0xB6EA, 0x5714, 0xDCE1, 0x5716, 0xB9CF, 0x5718, 0xB9CE, 0x571A, 0xE549, 0x571B, 0xE948, 0x571C, 0xE947, 0x571E, 0xF96B, 0x571F, 0xA467, 0x5720, 0xC959, 0x5722, 0xC96E, 0x5723, 0xC96F, 0x5728, 0xA662, 0x5729, 0xA666, 0x572A, 0xC9C9, 0x572C, 0xA664, 0x572D, 0xA663, 0x572E, 0xC9C8, 0x572F, 0xA665, 0x5730, 0xA661, 0x5733, 0xA660, 0x5734, 0xC9CA, 0x573B, 0xA7A6, 0x573E, 0xA7A3, 0x5740, 0xA77D, 0x5741, 0xCAAA, 0x5745, 0xCAAB, 0x5747, 0xA7A1, 0x5749, 0xCAAD, 0x574A, 0xA77B, 0x574B, 0xCAAE, 0x574C, 0xCAAC, 0x574D, 0xA77E, 0x574E, 0xA7A2, 0x574F, 0xA7A5, 0x5750, 0xA7A4, 0x5751, 0xA77C, 0x5752, 0xCAAF, 0x5761, 0xA959, 0x5762, 0xCBFE, 0x5764, 0xA95B, 0x5766, 0xA95A, 0x5768, 0xCC40, 0x5769, 0xA958, 0x576A, 0xA957, 0x576B, 0xCBF5, 0x576D, 0xCBF4, 0x576F, 0xCBF2, 0x5770, 0xCBF7, 0x5771, 0xCBF6, 0x5772, 0xCBF3, 0x5773, 0xCBFC, 0x5774, 0xCBFD, 0x5775, 0xCBFA, 0x5776, 0xCBF8, 0x5777, 0xA956, 0x577B, 0xCBFB, 0x577C, 0xA95C, 0x577D, 0xCC41, 0x5780, 0xCBF9, 0x5782, 0xABAB, 0x5783, 0xA955, 0x578B, 0xABAC, 0x578C, 0xCE54, 0x578F, 0xCE5A, 0x5793, 0xABB2, 0x5794, 0xCE58, 0x5795, 0xCE5E, 0x5797, 0xCE55, 0x5798, 0xCE59, 0x5799, 0xCE5B, 0x579A, 0xCE5D, 0x579B, 0xCE57, 0x579D, 0xCE56, 0x579E, 0xCE51, 0x579F, 0xCE52, 0x57A0, 0xABAD, 0x57A2, 0xABAF, 0x57A3, 0xABAE, 0x57A4, 0xCE53, 0x57A5, 0xCE5C, 0x57AE, 0xABB1, 0x57B5, 0xCE50, 0x57B6, 0xD153, 0x57B8, 0xD152, 0x57B9, 0xD157, 0x57BA, 0xD14E, 0x57BC, 0xD151, 0x57BD, 0xD150, 0x57BF, 0xD154, 0x57C1, 0xD158, 0x57C2, 0xAE47, 0x57C3, 0xAE4A, 0x57C6, 0xD14F, 0x57C7, 0xD155, 0x57CB, 0xAE49, 0x57CC, 0xD14A, 0x57CE, 0xABB0, 0x57CF, 0xD4BA, 0x57D0, 0xD156, 0x57D2, 0xD14D, 0x57D4, 0xAE48, 0x57D5, 0xD14C, 0x57DC, 0xD4B1, 0x57DF, 0xB0EC, 0x57E0, 0xB0F0, 0x57E1, 0xD4C1, 0x57E2, 0xD4AF, 0x57E3, 0xD4BD, 0x57E4, 0xB0F1, 0x57E5, 0xD4BF, 0x57E7, 0xD4C5, 0x57E9, 0xD4C9, 0x57EC, 0xD4C0, 0x57ED, 0xD4B4, 0x57EE, 0xD4BC, 0x57F0, 0xD4CA, 0x57F1, 0xD4C8, 0x57F2, 0xD4BE, 0x57F3, 0xD4B9, 0x57F4, 0xD4B2, 0x57F5, 0xD8A6, 0x57F6, 0xD4B0, 0x57F7, 0xB0F5, 0x57F8, 0xD4B7, 0x57F9, 0xB0F6, 0x57FA, 0xB0F2, 0x57FB, 0xD4AD, 0x57FC, 0xD4C3, 0x57FD, 0xD4B5, 0x5800, 0xD4B3, 0x5801, 0xD4C6, 0x5802, 0xB0F3, 0x5804, 0xD4CC, 0x5805, 0xB0ED, 0x5806, 0xB0EF, 0x5807, 0xD4BB, 0x5808, 0xD4B6, 0x5809, 0xAE4B, 0x580A, 0xB0EE, 0x580B, 0xD4B8, 0x580C, 0xD4C7, 0x580D, 0xD4CB, 0x580E, 0xD4C2, 0x5810, 0xD4C4, 0x5814, 0xD4AE, 0x5819, 0xD8A1, 0x581B, 0xD8AA, 0x581C, 0xD8A9, 0x581D, 0xB3FA, 0x581E, 0xD8A2, 0x5820, 0xB3FB, 0x5821, 0xB3F9, 0x5823, 0xD8A4, 0x5824, 0xB3F6, 0x5825, 0xD8A8, 0x5827, 0xD8A3, 0x5828, 0xD8A5, 0x5829, 0xD87D, 0x582A, 0xB3F4, 0x582C, 0xD8B2, 0x582D, 0xD8B1, 0x582E, 0xD8AE, 0x582F, 0xB3F3, 0x5830, 0xB3F7, 0x5831, 0xB3F8, 0x5832, 0xD14B, 0x5833, 0xD8AB, 0x5834, 0xB3F5, 0x5835, 0xB0F4, 0x5836, 0xD8AD, 0x5837, 0xD87E, 0x5838, 0xD8B0, 0x5839, 0xD8AF, 0x583B, 0xD8B3, 0x583D, 0xDCEF, 0x583F, 0xD8AC, 0x5848, 0xD8A7, 0x5849, 0xDCE7, 0x584A, 0xB6F4, 0x584B, 0xB6F7, 0x584C, 0xB6F2, 0x584D, 0xDCE6, 0x584E, 0xDCEA, 0x584F, 0xDCE5, 0x5851, 0xB6EC, 0x5852, 0xB6F6, 0x5853, 0xDCE2, 0x5854, 0xB6F0, 0x5855, 0xDCE9, 0x5857, 0xB6EE, 0x5858, 0xB6ED, 0x5859, 0xDCEC, 0x585A, 0xB6EF, 0x585B, 0xDCEE, 0x585D, 0xDCEB, 0x585E, 0xB6EB, 0x5862, 0xB6F5, 0x5863, 0xDCF0, 0x5864, 0xDCE4, 0x5865, 0xDCED, 0x5868, 0xDCE3, 0x586B, 0xB6F1, 0x586D, 0xB6F3, 0x586F, 0xDCE8, 0x5871, 0xDCF1, 0x5874, 0xE15D, 0x5875, 0xB9D0, 0x5876, 0xE163, 0x5879, 0xB9D5, 0x587A, 0xE15F, 0x587B, 0xE166, 0x587C, 0xE157, 0x587D, 0xB9D7, 0x587E, 0xB9D1, 0x587F, 0xE15C, 0x5880, 0xBC55, 0x5881, 0xE15B, 0x5882, 0xE164, 0x5883, 0xB9D2, 0x5885, 0xB9D6, 0x5886, 0xE15A, 0x5887, 0xE160, 0x5888, 0xE165, 0x5889, 0xE156, 0x588A, 0xB9D4, 0x588B, 0xE15E, 0x588E, 0xE162, 0x588F, 0xE168, 0x5890, 0xE158, 0x5891, 0xE161, 0x5893, 0xB9D3, 0x5894, 0xE167, 0x5898, 0xE159, 0x589C, 0xBC59, 0x589D, 0xE54B, 0x589E, 0xBC57, 0x589F, 0xBC56, 0x58A0, 0xE54D, 0x58A1, 0xE552, 0x58A3, 0xE54E, 0x58A5, 0xE551, 0x58A6, 0xBC5C, 0x58A8, 0xBEA5, 0x58A9, 0xBC5B, 0x58AB, 0xE54A, 0x58AC, 0xE550, 0x58AE, 0xBC5A, 0x58AF, 0xE54F, 0x58B1, 0xE54C, 0x58B3, 0xBC58, 0x58BA, 0xE94D, 0x58BB, 0xF9D9, 0x58BC, 0xE94F, 0x58BD, 0xE94A, 0x58BE, 0xBEC1, 0x58BF, 0xE94C, 0x58C1, 0xBEC0, 0x58C2, 0xE94E, 0x58C5, 0xBEC3, 0x58C6, 0xE950, 0x58C7, 0xBEC2, 0x58C8, 0xE949, 0x58C9, 0xE94B, 0x58CE, 0xC0A5, 0x58CF, 0xECCC, 0x58D1, 0xC0A4, 0x58D2, 0xECCD, 0x58D3, 0xC0A3, 0x58D4, 0xECCB, 0x58D5, 0xC0A2, 0x58D6, 0xECCA, 0x58D8, 0xC253, 0x58D9, 0xC252, 0x58DA, 0xF1F6, 0x58DB, 0xF1F8, 0x58DD, 0xF1F7, 0x58DE, 0xC361, 0x58DF, 0xC362, 0x58E2, 0xC363, 0x58E3, 0xF442, 0x58E4, 0xC45B, 0x58E7, 0xF7D3, 0x58E8, 0xF7D2, 0x58E9, 0xC5F2, 0x58EB, 0xA468, 0x58EC, 0xA4D0, 0x58EF, 0xA7A7, 0x58F4, 0xCE5F, 0x58F9, 0xB3FC, 0x58FA, 0xB3FD, 0x58FC, 0xDCF2, 0x58FD, 0xB9D8, 0x58FE, 0xE169, 0x58FF, 0xE553, 0x5903, 0xC95A, 0x5906, 0xCAB0, 0x590C, 0xCC42, 0x590D, 0xCE60, 0x590E, 0xD159, 0x590F, 0xAE4C, 0x5912, 0xF1F9, 0x5914, 0xC4DC, 0x5915, 0xA469, 0x5916, 0xA57E, 0x5917, 0xC970, 0x5919, 0xA667, 0x591A, 0xA668, 0x591C, 0xA95D, 0x5920, 0xB0F7, 0x5922, 0xB9DA, 0x5924, 0xB9DB, 0x5925, 0xB9D9, 0x5927, 0xA46A, 0x5929, 0xA4D1, 0x592A, 0xA4D3, 0x592B, 0xA4D2, 0x592C, 0xC95B, 0x592D, 0xA4D4, 0x592E, 0xA5A1, 0x592F, 0xC971, 0x5931, 0xA5A2, 0x5937, 0xA669, 0x5938, 0xA66A, 0x593C, 0xC9CB, 0x593E, 0xA7A8, 0x5940, 0xCAB1, 0x5944, 0xA961, 0x5945, 0xCC43, 0x5947, 0xA95F, 0x5948, 0xA960, 0x5949, 0xA95E, 0x594A, 0xD15A, 0x594E, 0xABB6, 0x594F, 0xABB5, 0x5950, 0xABB7, 0x5951, 0xABB4, 0x5953, 0xCE61, 0x5954, 0xA962, 0x5955, 0xABB3, 0x5957, 0xAE4D, 0x5958, 0xAE4E, 0x595A, 0xAE4F, 0x595C, 0xD4CD, 0x5960, 0xB3FE, 0x5961, 0xD8B4, 0x5962, 0xB0F8, 0x5967, 0xB6F8, 0x5969, 0xB9DD, 0x596A, 0xB9DC, 0x596B, 0xE16A, 0x596D, 0xBC5D, 0x596E, 0xBEC4, 0x5970, 0xEFC0, 0x5971, 0xF6DA, 0x5972, 0xF7D4, 0x5973, 0xA46B, 0x5974, 0xA5A3, 0x5976, 0xA5A4, 0x5977, 0xC9D1, 0x5978, 0xA66C, 0x5979, 0xA66F, 0x597B, 0xC9CF, 0x597C, 0xC9CD, 0x597D, 0xA66E, 0x597E, 0xC9D0, 0x597F, 0xC9D2, 0x5980, 0xC9CC, 0x5981, 0xA671, 0x5982, 0xA670, 0x5983, 0xA66D, 0x5984, 0xA66B, 0x5985, 0xC9CE, 0x598A, 0xA7B3, 0x598D, 0xA7B0, 0x598E, 0xCAB6, 0x598F, 0xCAB9, 0x5990, 0xCAB8, 0x5992, 0xA7AA, 0x5993, 0xA7B2, 0x5996, 0xA7AF, 0x5997, 0xCAB5, 0x5998, 0xCAB3, 0x5999, 0xA7AE, 0x599D, 0xA7A9, 0x599E, 0xA7AC, 0x59A0, 0xCAB4, 0x59A1, 0xCABB, 0x59A2, 0xCAB7, 0x59A3, 0xA7AD, 0x59A4, 0xA7B1, 0x59A5, 0xA7B4, 0x59A6, 0xCAB2, 0x59A7, 0xCABA, 0x59A8, 0xA7AB, 0x59AE, 0xA967, 0x59AF, 0xA96F, 0x59B1, 0xCC4F, 0x59B2, 0xCC48, 0x59B3, 0xA970, 0x59B4, 0xCC53, 0x59B5, 0xCC44, 0x59B6, 0xCC4B, 0x59B9, 0xA966, 0x59BA, 0xCC45, 0x59BB, 0xA964, 0x59BC, 0xCC4C, 0x59BD, 0xCC50, 0x59BE, 0xA963, 0x59C0, 0xCC51, 0x59C1, 0xCC4A, 0x59C3, 0xCC4D, 0x59C5, 0xA972, 0x59C6, 0xA969, 0x59C7, 0xCC54, 0x59C8, 0xCC52, 0x59CA, 0xA96E, 0x59CB, 0xA96C, 0x59CC, 0xCC49, 0x59CD, 0xA96B, 0x59CE, 0xCC47, 0x59CF, 0xCC46, 0x59D0, 0xA96A, 0x59D1, 0xA968, 0x59D2, 0xA971, 0x59D3, 0xA96D, 0x59D4, 0xA965, 0x59D6, 0xCC4E, 0x59D8, 0xABB9, 0x59DA, 0xABC0, 0x59DB, 0xCE6F, 0x59DC, 0xABB8, 0x59DD, 0xCE67, 0x59DE, 0xCE63, 0x59E0, 0xCE73, 0x59E1, 0xCE62, 0x59E3, 0xABBB, 0x59E4, 0xCE6C, 0x59E5, 0xABBE, 0x59E6, 0xABC1, 0x59E8, 0xABBC, 0x59E9, 0xCE70, 0x59EA, 0xABBF, 0x59EC, 0xAE56, 0x59ED, 0xCE76, 0x59EE, 0xCE64, 0x59F1, 0xCE66, 0x59F2, 0xCE6D, 0x59F3, 0xCE71, 0x59F4, 0xCE75, 0x59F5, 0xCE72, 0x59F6, 0xCE6B, 0x59F7, 0xCE6E, 0x59FA, 0xCE68, 0x59FB, 0xABC3, 0x59FC, 0xCE6A, 0x59FD, 0xCE69, 0x59FE, 0xCE74, 0x59FF, 0xABBA, 0x5A00, 0xCE65, 0x5A01, 0xABC2, 0x5A03, 0xABBD, 0x5A09, 0xAE5C, 0x5A0A, 0xD162, 0x5A0C, 0xAE5B, 0x5A0F, 0xD160, 0x5A11, 0xAE50, 0x5A13, 0xAE55, 0x5A15, 0xD15F, 0x5A16, 0xD15C, 0x5A17, 0xD161, 0x5A18, 0xAE51, 0x5A19, 0xD15B, 0x5A1B, 0xAE54, 0x5A1C, 0xAE52, 0x5A1E, 0xD163, 0x5A1F, 0xAE53, 0x5A20, 0xAE57, 0x5A23, 0xAE58, 0x5A25, 0xAE5A, 0x5A29, 0xAE59, 0x5A2D, 0xD15D, 0x5A2E, 0xD15E, 0x5A33, 0xD164, 0x5A35, 0xD4D4, 0x5A36, 0xB0F9, 0x5A37, 0xD8C2, 0x5A38, 0xD4D3, 0x5A39, 0xD4E6, 0x5A3C, 0xB140, 0x5A3E, 0xD4E4, 0x5A40, 0xB0FE, 0x5A41, 0xB0FA, 0x5A42, 0xD4ED, 0x5A43, 0xD4DD, 0x5A44, 0xD4E0, 0x5A46, 0xB143, 0x5A47, 0xD4EA, 0x5A48, 0xD4E2, 0x5A49, 0xB0FB, 0x5A4A, 0xB144, 0x5A4C, 0xD4E7, 0x5A4D, 0xD4E5, 0x5A50, 0xD4D6, 0x5A51, 0xD4EB, 0x5A52, 0xD4DF, 0x5A53, 0xD4DA, 0x5A55, 0xD4D0, 0x5A56, 0xD4EC, 0x5A57, 0xD4DC, 0x5A58, 0xD4CF, 0x5A5A, 0xB142, 0x5A5B, 0xD4E1, 0x5A5C, 0xD4EE, 0x5A5D, 0xD4DE, 0x5A5E, 0xD4D2, 0x5A5F, 0xD4D7, 0x5A60, 0xD4CE, 0x5A62, 0xB141, 0x5A64, 0xD4DB, 0x5A65, 0xD4D8, 0x5A66, 0xB0FC, 0x5A67, 0xD4D1, 0x5A69, 0xD4E9, 0x5A6A, 0xB0FD, 0x5A6C, 0xD4D9, 0x5A6D, 0xD4D5, 0x5A70, 0xD4E8, 0x5A77, 0xB440, 0x5A78, 0xD8BB, 0x5A7A, 0xD8B8, 0x5A7B, 0xD8C9, 0x5A7C, 0xD8BD, 0x5A7D, 0xD8CA, 0x5A7F, 0xB442, 0x5A83, 0xD8C6, 0x5A84, 0xD8C3, 0x5A8A, 0xD8C4, 0x5A8B, 0xD8C7, 0x5A8C, 0xD8CB, 0x5A8E, 0xD4E3, 0x5A8F, 0xD8CD, 0x5A90, 0xDD47, 0x5A92, 0xB443, 0x5A93, 0xD8CE, 0x5A94, 0xD8B6, 0x5A95, 0xD8C0, 0x5A97, 0xD8C5, 0x5A9A, 0xB441, 0x5A9B, 0xB444, 0x5A9C, 0xD8CC, 0x5A9D, 0xD8CF, 0x5A9E, 0xD8BA, 0x5A9F, 0xD8B7, 0x5AA2, 0xD8B9, 0x5AA5, 0xD8BE, 0x5AA6, 0xD8BC, 0x5AA7, 0xB445, 0x5AA9, 0xD8C8, 0x5AAC, 0xD8BF, 0x5AAE, 0xD8C1, 0x5AAF, 0xD8B5, 0x5AB0, 0xDCFA, 0x5AB1, 0xDCF8, 0x5AB2, 0xB742, 0x5AB3, 0xB740, 0x5AB4, 0xDD43, 0x5AB5, 0xDCF9, 0x5AB6, 0xDD44, 0x5AB7, 0xDD40, 0x5AB8, 0xDCF7, 0x5AB9, 0xDD46, 0x5ABA, 0xDCF6, 0x5ABB, 0xDCFD, 0x5ABC, 0xB6FE, 0x5ABD, 0xB6FD, 0x5ABE, 0xB6FC, 0x5ABF, 0xDCFB, 0x5AC0, 0xDD41, 0x5AC1, 0xB6F9, 0x5AC2, 0xB741, 0x5AC4, 0xDCF4, 0x5AC6, 0xDCFE, 0x5AC7, 0xDCF3, 0x5AC8, 0xDCFC, 0x5AC9, 0xB6FA, 0x5ACA, 0xDD42, 0x5ACB, 0xDCF5, 0x5ACC, 0xB6FB, 0x5ACD, 0xDD45, 0x5AD5, 0xE16E, 0x5AD6, 0xB9E2, 0x5AD7, 0xB9E1, 0x5AD8, 0xB9E3, 0x5AD9, 0xE17A, 0x5ADA, 0xE170, 0x5ADB, 0xE176, 0x5ADC, 0xE16B, 0x5ADD, 0xE179, 0x5ADE, 0xE178, 0x5ADF, 0xE17C, 0x5AE0, 0xE175, 0x5AE1, 0xB9DE, 0x5AE2, 0xE174, 0x5AE3, 0xB9E4, 0x5AE5, 0xE16D, 0x5AE6, 0xB9DF, 0x5AE8, 0xE17B, 0x5AE9, 0xB9E0, 0x5AEA, 0xE16F, 0x5AEB, 0xE172, 0x5AEC, 0xE177, 0x5AED, 0xE171, 0x5AEE, 0xE16C, 0x5AF3, 0xE173, 0x5AF4, 0xE555, 0x5AF5, 0xBC61, 0x5AF6, 0xE558, 0x5AF7, 0xE557, 0x5AF8, 0xE55A, 0x5AF9, 0xE55C, 0x5AFA, 0xF9DC, 0x5AFB, 0xBC5F, 0x5AFD, 0xE556, 0x5AFF, 0xE554, 0x5B01, 0xE55D, 0x5B02, 0xE55B, 0x5B03, 0xE559, 0x5B05, 0xE55F, 0x5B07, 0xE55E, 0x5B08, 0xBC63, 0x5B09, 0xBC5E, 0x5B0B, 0xBC60, 0x5B0C, 0xBC62, 0x5B0F, 0xE560, 0x5B10, 0xE957, 0x5B13, 0xE956, 0x5B14, 0xE955, 0x5B16, 0xE958, 0x5B17, 0xE951, 0x5B19, 0xE952, 0x5B1A, 0xE95A, 0x5B1B, 0xE953, 0x5B1D, 0xBEC5, 0x5B1E, 0xE95C, 0x5B20, 0xE95B, 0x5B21, 0xE954, 0x5B23, 0xECD1, 0x5B24, 0xC0A8, 0x5B25, 0xECCF, 0x5B26, 0xECD4, 0x5B27, 0xECD3, 0x5B28, 0xE959, 0x5B2A, 0xC0A7, 0x5B2C, 0xECD2, 0x5B2D, 0xECCE, 0x5B2E, 0xECD6, 0x5B2F, 0xECD5, 0x5B30, 0xC0A6, 0x5B32, 0xECD0, 0x5B34, 0xBEC6, 0x5B38, 0xC254, 0x5B3C, 0xEFC1, 0x5B3D, 0xF1FA, 0x5B3E, 0xF1FB, 0x5B3F, 0xF1FC, 0x5B40, 0xC45C, 0x5B43, 0xC45D, 0x5B45, 0xF443, 0x5B47, 0xF5C8, 0x5B48, 0xF5C7, 0x5B4B, 0xF6DB, 0x5B4C, 0xF6DC, 0x5B4D, 0xF7D5, 0x5B4E, 0xF8A7, 0x5B50, 0xA46C, 0x5B51, 0xA46D, 0x5B53, 0xA46E, 0x5B54, 0xA4D5, 0x5B55, 0xA5A5, 0x5B56, 0xC9D3, 0x5B57, 0xA672, 0x5B58, 0xA673, 0x5B5A, 0xA7B7, 0x5B5B, 0xA7B8, 0x5B5C, 0xA7B6, 0x5B5D, 0xA7B5, 0x5B5F, 0xA973, 0x5B62, 0xCC55, 0x5B63, 0xA975, 0x5B64, 0xA974, 0x5B65, 0xCC56, 0x5B69, 0xABC4, 0x5B6B, 0xAE5D, 0x5B6C, 0xD165, 0x5B6E, 0xD4F0, 0x5B70, 0xB145, 0x5B71, 0xB447, 0x5B72, 0xD4EF, 0x5B73, 0xB446, 0x5B75, 0xB9E5, 0x5B77, 0xE17D, 0x5B78, 0xBEC7, 0x5B7A, 0xC0A9, 0x5B7B, 0xECD7, 0x5B7D, 0xC45E, 0x5B7F, 0xC570, 0x5B81, 0xC972, 0x5B83, 0xA5A6, 0x5B84, 0xC973, 0x5B85, 0xA676, 0x5B87, 0xA674, 0x5B88, 0xA675, 0x5B89, 0xA677, 0x5B8B, 0xA7BA, 0x5B8C, 0xA7B9, 0x5B8E, 0xCABC, 0x5B8F, 0xA7BB, 0x5B92, 0xCABD, 0x5B93, 0xCC57, 0x5B95, 0xCC58, 0x5B97, 0xA976, 0x5B98, 0xA978, 0x5B99, 0xA97A, 0x5B9A, 0xA977, 0x5B9B, 0xA97B, 0x5B9C, 0xA979, 0x5BA2, 0xABC8, 0x5BA3, 0xABC5, 0x5BA4, 0xABC7, 0x5BA5, 0xABC9, 0x5BA6, 0xABC6, 0x5BA7, 0xD166, 0x5BA8, 0xCE77, 0x5BAC, 0xD168, 0x5BAD, 0xD167, 0x5BAE, 0xAE63, 0x5BB0, 0xAE5F, 0x5BB3, 0xAE60, 0x5BB4, 0xAE62, 0x5BB5, 0xAE64, 0x5BB6, 0xAE61, 0x5BB8, 0xAE66, 0x5BB9, 0xAE65, 0x5BBF, 0xB14A, 0x5BC0, 0xD4F2, 0x5BC1, 0xD4F1, 0x5BC2, 0xB149, 0x5BC4, 0xB148, 0x5BC5, 0xB147, 0x5BC6, 0xB14B, 0x5BC7, 0xB146, 0x5BCA, 0xD8D5, 0x5BCB, 0xD8D2, 0x5BCC, 0xB449, 0x5BCD, 0xD8D1, 0x5BCE, 0xD8D6, 0x5BD0, 0xB44B, 0x5BD1, 0xD8D4, 0x5BD2, 0xB448, 0x5BD3, 0xB44A, 0x5BD4, 0xD8D3, 0x5BD6, 0xDD48, 0x5BD8, 0xDD49, 0x5BD9, 0xDD4A, 0x5BDE, 0xB9E6, 0x5BDF, 0xB9EE, 0x5BE0, 0xE17E, 0x5BE1, 0xB9E8, 0x5BE2, 0xB9EC, 0x5BE3, 0xE1A1, 0x5BE4, 0xB9ED, 0x5BE5, 0xB9E9, 0x5BE6, 0xB9EA, 0x5BE7, 0xB9E7, 0x5BE8, 0xB9EB, 0x5BE9, 0xBC66, 0x5BEA, 0xD8D0, 0x5BEB, 0xBC67, 0x5BEC, 0xBC65, 0x5BEE, 0xBC64, 0x5BEF, 0xE95D, 0x5BF0, 0xBEC8, 0x5BF1, 0xECD8, 0x5BF2, 0xECD9, 0x5BF5, 0xC364, 0x5BF6, 0xC45F, 0x5BF8, 0xA46F, 0x5BFA, 0xA678, 0x5C01, 0xABCA, 0x5C03, 0xD169, 0x5C04, 0xAE67, 0x5C07, 0xB14E, 0x5C08, 0xB14D, 0x5C09, 0xB14C, 0x5C0A, 0xB44C, 0x5C0B, 0xB44D, 0x5C0C, 0xD8D7, 0x5C0D, 0xB9EF, 0x5C0E, 0xBEC9, 0x5C0F, 0xA470, 0x5C10, 0xC95C, 0x5C11, 0xA4D6, 0x5C12, 0xC974, 0x5C15, 0xC9D4, 0x5C16, 0xA679, 0x5C1A, 0xA97C, 0x5C1F, 0xDD4B, 0x5C22, 0xA471, 0x5C24, 0xA4D7, 0x5C25, 0xC9D5, 0x5C28, 0xCABE, 0x5C2A, 0xCABF, 0x5C2C, 0xA7BC, 0x5C30, 0xD8D8, 0x5C31, 0xB44E, 0x5C33, 0xDD4C, 0x5C37, 0xC0AA, 0x5C38, 0xA472, 0x5C39, 0xA4A8, 0x5C3A, 0xA4D8, 0x5C3B, 0xC975, 0x5C3C, 0xA5A7, 0x5C3E, 0xA7C0, 0x5C3F, 0xA7BF, 0x5C40, 0xA7BD, 0x5C41, 0xA7BE, 0x5C44, 0xCC59, 0x5C45, 0xA97E, 0x5C46, 0xA9A1, 0x5C47, 0xCC5A, 0x5C48, 0xA97D, 0x5C4B, 0xABCE, 0x5C4C, 0xCE78, 0x5C4D, 0xABCD, 0x5C4E, 0xABCB, 0x5C4F, 0xABCC, 0x5C50, 0xAE6A, 0x5C51, 0xAE68, 0x5C54, 0xD16B, 0x5C55, 0xAE69, 0x5C56, 0xD16A, 0x5C58, 0xAE5E, 0x5C59, 0xD4F3, 0x5C5C, 0xB150, 0x5C5D, 0xB151, 0x5C60, 0xB14F, 0x5C62, 0xB9F0, 0x5C63, 0xE1A2, 0x5C64, 0xBC68, 0x5C65, 0xBC69, 0x5C67, 0xE561, 0x5C68, 0xC0AB, 0x5C69, 0xEFC2, 0x5C6A, 0xEFC3, 0x5C6C, 0xC4DD, 0x5C6D, 0xF8A8, 0x5C6E, 0xC94B, 0x5C6F, 0xA4D9, 0x5C71, 0xA473, 0x5C73, 0xC977, 0x5C74, 0xC976, 0x5C79, 0xA67A, 0x5C7A, 0xC9D7, 0x5C7B, 0xC9D8, 0x5C7C, 0xC9D6, 0x5C7E, 0xC9D9, 0x5C86, 0xCAC7, 0x5C88, 0xCAC2, 0x5C89, 0xCAC4, 0x5C8A, 0xCAC6, 0x5C8B, 0xCAC3, 0x5C8C, 0xA7C4, 0x5C8D, 0xCAC0, 0x5C8F, 0xCAC1, 0x5C90, 0xA7C1, 0x5C91, 0xA7C2, 0x5C92, 0xCAC5, 0x5C93, 0xCAC8, 0x5C94, 0xA7C3, 0x5C95, 0xCAC9, 0x5C9D, 0xCC68, 0x5C9F, 0xCC62, 0x5CA0, 0xCC5D, 0x5CA1, 0xA9A3, 0x5CA2, 0xCC65, 0x5CA3, 0xCC63, 0x5CA4, 0xCC5C, 0x5CA5, 0xCC69, 0x5CA6, 0xCC6C, 0x5CA7, 0xCC67, 0x5CA8, 0xCC60, 0x5CA9, 0xA9A5, 0x5CAA, 0xCC66, 0x5CAB, 0xA9A6, 0x5CAC, 0xCC61, 0x5CAD, 0xCC64, 0x5CAE, 0xCC5B, 0x5CAF, 0xCC5F, 0x5CB0, 0xCC6B, 0x5CB1, 0xA9A7, 0x5CB3, 0xA9A8, 0x5CB5, 0xCC5E, 0x5CB6, 0xCC6A, 0x5CB7, 0xA9A2, 0x5CB8, 0xA9A4, 0x5CC6, 0xCEAB, 0x5CC7, 0xCEA4, 0x5CC8, 0xCEAA, 0x5CC9, 0xCEA3, 0x5CCA, 0xCEA5, 0x5CCB, 0xCE7D, 0x5CCC, 0xCE7B, 0x5CCE, 0xCEAC, 0x5CCF, 0xCEA9, 0x5CD0, 0xCE79, 0x5CD2, 0xABD0, 0x5CD3, 0xCEA7, 0x5CD4, 0xCEA8, 0x5CD6, 0xCEA6, 0x5CD7, 0xCE7C, 0x5CD8, 0xCE7A, 0x5CD9, 0xABCF, 0x5CDA, 0xCEA2, 0x5CDB, 0xCE7E, 0x5CDE, 0xCEA1, 0x5CDF, 0xCEAD, 0x5CE8, 0xAE6F, 0x5CEA, 0xAE6E, 0x5CEC, 0xD16C, 0x5CED, 0xAE6B, 0x5CEE, 0xD16E, 0x5CF0, 0xAE70, 0x5CF1, 0xD16F, 0x5CF4, 0xAE73, 0x5CF6, 0xAE71, 0x5CF7, 0xD170, 0x5CF8, 0xCEAE, 0x5CF9, 0xD172, 0x5CFB, 0xAE6D, 0x5CFD, 0xAE6C, 0x5CFF, 0xD16D, 0x5D00, 0xD171, 0x5D01, 0xAE72, 0x5D06, 0xB153, 0x5D07, 0xB152, 0x5D0B, 0xD4F5, 0x5D0C, 0xD4F9, 0x5D0D, 0xD4FB, 0x5D0E, 0xB154, 0x5D0F, 0xD4FE, 0x5D11, 0xB158, 0x5D12, 0xD541, 0x5D14, 0xB15A, 0x5D16, 0xB156, 0x5D17, 0xB15E, 0x5D19, 0xB15B, 0x5D1A, 0xD4F7, 0x5D1B, 0xB155, 0x5D1D, 0xD4F6, 0x5D1E, 0xD4F4, 0x5D1F, 0xD543, 0x5D20, 0xD4F8, 0x5D22, 0xB157, 0x5D23, 0xD542, 0x5D24, 0xB15C, 0x5D25, 0xD4FD, 0x5D26, 0xD4FC, 0x5D27, 0xB15D, 0x5D28, 0xD4FA, 0x5D29, 0xB159, 0x5D2E, 0xD544, 0x5D30, 0xD540, 0x5D31, 0xD8E7, 0x5D32, 0xD8EE, 0x5D33, 0xD8E3, 0x5D34, 0xB451, 0x5D35, 0xD8DF, 0x5D36, 0xD8EF, 0x5D37, 0xD8D9, 0x5D38, 0xD8EC, 0x5D39, 0xD8EA, 0x5D3A, 0xD8E4, 0x5D3C, 0xD8ED, 0x5D3D, 0xD8E6, 0x5D3F, 0xD8DE, 0x5D40, 0xD8F0, 0x5D41, 0xD8DC, 0x5D42, 0xD8E9, 0x5D43, 0xD8DA, 0x5D45, 0xD8F1, 0x5D47, 0xB452, 0x5D49, 0xD8EB, 0x5D4A, 0xDD4F, 0x5D4B, 0xD8DD, 0x5D4C, 0xB44F, 0x5D4E, 0xD8E1, 0x5D50, 0xB450, 0x5D51, 0xD8E0, 0x5D52, 0xD8E5, 0x5D55, 0xD8E2, 0x5D59, 0xD8E8, 0x5D5E, 0xDD53, 0x5D62, 0xDD56, 0x5D63, 0xDD4E, 0x5D65, 0xDD50, 0x5D67, 0xDD55, 0x5D68, 0xDD54, 0x5D69, 0xB743, 0x5D6B, 0xD8DB, 0x5D6C, 0xDD52, 0x5D6F, 0xB744, 0x5D71, 0xDD4D, 0x5D72, 0xDD51, 0x5D77, 0xE1A9, 0x5D79, 0xE1B0, 0x5D7A, 0xE1A7, 0x5D7C, 0xE1AE, 0x5D7D, 0xE1A5, 0x5D7E, 0xE1AD, 0x5D7F, 0xE1B1, 0x5D80, 0xE1A4, 0x5D81, 0xE1A8, 0x5D82, 0xE1A3, 0x5D84, 0xB9F1, 0x5D86, 0xE1A6, 0x5D87, 0xB9F2, 0x5D88, 0xE1AC, 0x5D89, 0xE1AB, 0x5D8A, 0xE1AA, 0x5D8D, 0xE1AF, 0x5D92, 0xE565, 0x5D93, 0xE567, 0x5D94, 0xBC6B, 0x5D95, 0xE568, 0x5D97, 0xE563, 0x5D99, 0xE562, 0x5D9A, 0xE56C, 0x5D9C, 0xE56A, 0x5D9D, 0xBC6A, 0x5D9E, 0xE56D, 0x5D9F, 0xE564, 0x5DA0, 0xE569, 0x5DA1, 0xE56B, 0x5DA2, 0xE566, 0x5DA7, 0xE961, 0x5DA8, 0xE966, 0x5DA9, 0xE960, 0x5DAA, 0xE965, 0x5DAC, 0xE95E, 0x5DAD, 0xE968, 0x5DAE, 0xE964, 0x5DAF, 0xE969, 0x5DB0, 0xE963, 0x5DB1, 0xE95F, 0x5DB2, 0xE967, 0x5DB4, 0xE96A, 0x5DB5, 0xE962, 0x5DB7, 0xECDA, 0x5DB8, 0xC0AF, 0x5DBA, 0xC0AD, 0x5DBC, 0xC0AC, 0x5DBD, 0xC0AE, 0x5DC0, 0xEFC4, 0x5DC2, 0xF172, 0x5DC3, 0xF1FD, 0x5DC6, 0xF444, 0x5DC7, 0xF445, 0x5DC9, 0xC460, 0x5DCB, 0xF5C9, 0x5DCD, 0xC4DE, 0x5DCF, 0xF5CA, 0x5DD1, 0xF6DE, 0x5DD2, 0xC572, 0x5DD4, 0xC571, 0x5DD5, 0xF6DD, 0x5DD6, 0xC5C9, 0x5DD8, 0xF7D6, 0x5DDD, 0xA474, 0x5DDE, 0xA67B, 0x5DDF, 0xC9DA, 0x5DE0, 0xCACA, 0x5DE1, 0xA8B5, 0x5DE2, 0xB15F, 0x5DE5, 0xA475, 0x5DE6, 0xA5AA, 0x5DE7, 0xA5A9, 0x5DE8, 0xA5A8, 0x5DEB, 0xA7C5, 0x5DEE, 0xAE74, 0x5DF0, 0xDD57, 0x5DF1, 0xA476, 0x5DF2, 0xA477, 0x5DF3, 0xA478, 0x5DF4, 0xA4DA, 0x5DF7, 0xABD1, 0x5DF9, 0xCEAF, 0x5DFD, 0xB453, 0x5DFE, 0xA479, 0x5DFF, 0xC95D, 0x5E02, 0xA5AB, 0x5E03, 0xA5AC, 0x5E04, 0xC978, 0x5E06, 0xA67C, 0x5E0A, 0xCACB, 0x5E0C, 0xA7C6, 0x5E0E, 0xCACC, 0x5E11, 0xA9AE, 0x5E14, 0xCC6E, 0x5E15, 0xA9AC, 0x5E16, 0xA9AB, 0x5E17, 0xCC6D, 0x5E18, 0xA9A9, 0x5E19, 0xCC6F, 0x5E1A, 0xA9AA, 0x5E1B, 0xA9AD, 0x5E1D, 0xABD2, 0x5E1F, 0xABD4, 0x5E20, 0xCEB3, 0x5E21, 0xCEB0, 0x5E22, 0xCEB1, 0x5E23, 0xCEB2, 0x5E24, 0xCEB4, 0x5E25, 0xABD3, 0x5E28, 0xD174, 0x5E29, 0xD173, 0x5E2B, 0xAE76, 0x5E2D, 0xAE75, 0x5E33, 0xB162, 0x5E34, 0xD546, 0x5E36, 0xB161, 0x5E37, 0xB163, 0x5E38, 0xB160, 0x5E3D, 0xB455, 0x5E3E, 0xD545, 0x5E40, 0xB456, 0x5E41, 0xD8F3, 0x5E43, 0xB457, 0x5E44, 0xD8F2, 0x5E45, 0xB454, 0x5E4A, 0xDD5A, 0x5E4B, 0xDD5C, 0x5E4C, 0xB745, 0x5E4D, 0xDD5B, 0x5E4E, 0xDD59, 0x5E4F, 0xDD58, 0x5E53, 0xE1B4, 0x5E54, 0xB9F7, 0x5E55, 0xB9F5, 0x5E57, 0xB9F6, 0x5E58, 0xE1B2, 0x5E59, 0xE1B3, 0x5E5B, 0xB9F3, 0x5E5C, 0xE571, 0x5E5D, 0xE56F, 0x5E5F, 0xBC6D, 0x5E60, 0xE570, 0x5E61, 0xBC6E, 0x5E62, 0xBC6C, 0x5E63, 0xB9F4, 0x5E66, 0xE96D, 0x5E67, 0xE96B, 0x5E68, 0xE96C, 0x5E69, 0xE56E, 0x5E6A, 0xECDC, 0x5E6B, 0xC0B0, 0x5E6C, 0xECDB, 0x5E6D, 0xEFC5, 0x5E6E, 0xEFC6, 0x5E6F, 0xE96E, 0x5E70, 0xF1FE, 0x5E72, 0xA47A, 0x5E73, 0xA5AD, 0x5E74, 0xA67E, 0x5E75, 0xC9DB, 0x5E76, 0xA67D, 0x5E78, 0xA9AF, 0x5E79, 0xB746, 0x5E7B, 0xA4DB, 0x5E7C, 0xA5AE, 0x5E7D, 0xABD5, 0x5E7E, 0xB458, 0x5E80, 0xC979, 0x5E82, 0xC97A, 0x5E84, 0xC9DC, 0x5E87, 0xA7C8, 0x5E88, 0xCAD0, 0x5E89, 0xCACE, 0x5E8A, 0xA7C9, 0x5E8B, 0xCACD, 0x5E8C, 0xCACF, 0x5E8D, 0xCAD1, 0x5E8F, 0xA7C7, 0x5E95, 0xA9B3, 0x5E96, 0xA9B4, 0x5E97, 0xA9B1, 0x5E9A, 0xA9B0, 0x5E9B, 0xCEB8, 0x5E9C, 0xA9B2, 0x5EA0, 0xABD6, 0x5EA2, 0xCEB7, 0x5EA3, 0xCEB9, 0x5EA4, 0xCEB6, 0x5EA5, 0xCEBA, 0x5EA6, 0xABD7, 0x5EA7, 0xAE79, 0x5EA8, 0xD175, 0x5EAA, 0xD177, 0x5EAB, 0xAE77, 0x5EAC, 0xD178, 0x5EAD, 0xAE78, 0x5EAE, 0xD176, 0x5EB0, 0xCEB5, 0x5EB1, 0xD547, 0x5EB2, 0xD54A, 0x5EB3, 0xD54B, 0x5EB4, 0xD548, 0x5EB5, 0xB167, 0x5EB6, 0xB166, 0x5EB7, 0xB164, 0x5EB8, 0xB165, 0x5EB9, 0xD549, 0x5EBE, 0xB168, 0x5EC1, 0xB45A, 0x5EC2, 0xB45B, 0x5EC4, 0xB45C, 0x5EC5, 0xDD5D, 0x5EC6, 0xDD5F, 0x5EC7, 0xDD61, 0x5EC8, 0xB748, 0x5EC9, 0xB747, 0x5ECA, 0xB459, 0x5ECB, 0xDD60, 0x5ECC, 0xDD5E, 0x5ECE, 0xE1B8, 0x5ED1, 0xE1B6, 0x5ED2, 0xE1BC, 0x5ED3, 0xB9F8, 0x5ED4, 0xE1BD, 0x5ED5, 0xE1BA, 0x5ED6, 0xB9F9, 0x5ED7, 0xE1B7, 0x5ED8, 0xE1B5, 0x5ED9, 0xE1BB, 0x5EDA, 0xBC70, 0x5EDB, 0xE573, 0x5EDC, 0xE1B9, 0x5EDD, 0xBC72, 0x5EDE, 0xE574, 0x5EDF, 0xBC71, 0x5EE0, 0xBC74, 0x5EE1, 0xE575, 0x5EE2, 0xBC6F, 0x5EE3, 0xBC73, 0x5EE5, 0xE973, 0x5EE6, 0xE971, 0x5EE7, 0xE970, 0x5EE8, 0xE972, 0x5EE9, 0xE96F, 0x5EEC, 0xC366, 0x5EEE, 0xF446, 0x5EEF, 0xF447, 0x5EF1, 0xF5CB, 0x5EF2, 0xF6DF, 0x5EF3, 0xC655, 0x5EF6, 0xA9B5, 0x5EF7, 0xA7CA, 0x5EFA, 0xABD8, 0x5EFE, 0xA47B, 0x5EFF, 0xA4DC, 0x5F01, 0xA5AF, 0x5F02, 0xC9DD, 0x5F04, 0xA7CB, 0x5F05, 0xCAD2, 0x5F07, 0xCEBB, 0x5F08, 0xABD9, 0x5F0A, 0xB9FA, 0x5F0B, 0xA47C, 0x5F0F, 0xA6A1, 0x5F12, 0xB749, 0x5F13, 0xA47D, 0x5F14, 0xA4DD, 0x5F15, 0xA4DE, 0x5F17, 0xA5B1, 0x5F18, 0xA5B0, 0x5F1A, 0xC9DE, 0x5F1B, 0xA6A2, 0x5F1D, 0xCAD3, 0x5F1F, 0xA7CC, 0x5F22, 0xCC71, 0x5F23, 0xCC72, 0x5F24, 0xCC73, 0x5F26, 0xA9B6, 0x5F27, 0xA9B7, 0x5F28, 0xCC70, 0x5F29, 0xA9B8, 0x5F2D, 0xABDA, 0x5F2E, 0xCEBC, 0x5F30, 0xD17A, 0x5F31, 0xAE7A, 0x5F33, 0xD179, 0x5F35, 0xB169, 0x5F36, 0xD54C, 0x5F37, 0xB16A, 0x5F38, 0xD54D, 0x5F3C, 0xB45D, 0x5F40, 0xDD62, 0x5F43, 0xE1BF, 0x5F44, 0xE1BE, 0x5F46, 0xB9FB, 0x5F48, 0xBC75, 0x5F49, 0xE576, 0x5F4A, 0xBECA, 0x5F4B, 0xE974, 0x5F4C, 0xC0B1, 0x5F4E, 0xC573, 0x5F4F, 0xF7D8, 0x5F54, 0xCC74, 0x5F56, 0xCEBD, 0x5F57, 0xB16B, 0x5F58, 0xD8F4, 0x5F59, 0xB74A, 0x5F5D, 0xC255, 0x5F62, 0xA7CE, 0x5F64, 0xA7CD, 0x5F65, 0xABDB, 0x5F67, 0xD17B, 0x5F69, 0xB16D, 0x5F6A, 0xB343, 0x5F6B, 0xB16E, 0x5F6C, 0xB16C, 0x5F6D, 0xB45E, 0x5F6F, 0xE1C0, 0x5F70, 0xB9FC, 0x5F71, 0xBC76, 0x5F73, 0xC94C, 0x5F74, 0xC9DF, 0x5F76, 0xCAD5, 0x5F77, 0xA7CF, 0x5F78, 0xCAD4, 0x5F79, 0xA7D0, 0x5F7C, 0xA9BC, 0x5F7D, 0xCC77, 0x5F7E, 0xCC76, 0x5F7F, 0xA9BB, 0x5F80, 0xA9B9, 0x5F81, 0xA9BA, 0x5F82, 0xCC75, 0x5F85, 0xABDD, 0x5F86, 0xCEBE, 0x5F87, 0xABE0, 0x5F88, 0xABDC, 0x5F89, 0xABE2, 0x5F8A, 0xABDE, 0x5F8B, 0xABDF, 0x5F8C, 0xABE1, 0x5F90, 0xAE7D, 0x5F91, 0xAE7C, 0x5F92, 0xAE7B, 0x5F96, 0xD54F, 0x5F97, 0xB16F, 0x5F98, 0xB172, 0x5F99, 0xB170, 0x5F9B, 0xD54E, 0x5F9C, 0xB175, 0x5F9E, 0xB171, 0x5F9F, 0xD550, 0x5FA0, 0xB174, 0x5FA1, 0xB173, 0x5FA5, 0xD8F6, 0x5FA6, 0xD8F5, 0x5FA8, 0xB461, 0x5FA9, 0xB45F, 0x5FAA, 0xB460, 0x5FAB, 0xD8F7, 0x5FAC, 0xB74B, 0x5FAD, 0xDD64, 0x5FAE, 0xB74C, 0x5FAF, 0xDD63, 0x5FB2, 0xE577, 0x5FB5, 0xBC78, 0x5FB6, 0xE1C1, 0x5FB7, 0xBC77, 0x5FB9, 0xB9FD, 0x5FBB, 0xECDE, 0x5FBC, 0xE975, 0x5FBD, 0xC0B2, 0x5FBE, 0xECDD, 0x5FBF, 0xF240, 0x5FC0, 0xF448, 0x5FC1, 0xF449, 0x5FC3, 0xA4DF, 0x5FC5, 0xA5B2, 0x5FC9, 0xC97B, 0x5FCC, 0xA7D2, 0x5FCD, 0xA7D4, 0x5FCF, 0xC9E2, 0x5FD0, 0xCAD8, 0x5FD1, 0xCAD7, 0x5FD2, 0xCAD6, 0x5FD4, 0xC9E1, 0x5FD5, 0xC9E0, 0x5FD6, 0xA6A4, 0x5FD7, 0xA7D3, 0x5FD8, 0xA7D1, 0x5FD9, 0xA6A3, 0x5FDD, 0xA9BD, 0x5FDE, 0xCC78, 0x5FE0, 0xA9BE, 0x5FE1, 0xCADD, 0x5FE3, 0xCADF, 0x5FE4, 0xCADE, 0x5FE5, 0xCC79, 0x5FE8, 0xCADA, 0x5FEA, 0xA7D8, 0x5FEB, 0xA7D6, 0x5FED, 0xCAD9, 0x5FEE, 0xCADB, 0x5FEF, 0xCAE1, 0x5FF1, 0xA7D5, 0x5FF3, 0xCADC, 0x5FF4, 0xCAE5, 0x5FF5, 0xA9C0, 0x5FF7, 0xCAE2, 0x5FF8, 0xA7D7, 0x5FFA, 0xCAE0, 0x5FFB, 0xCAE3, 0x5FFD, 0xA9BF, 0x5FFF, 0xA9C1, 0x6000, 0xCAE4, 0x6009, 0xCCAF, 0x600A, 0xCCA2, 0x600B, 0xCC7E, 0x600C, 0xCCAE, 0x600D, 0xCCA9, 0x600E, 0xABE7, 0x600F, 0xA9C2, 0x6010, 0xCCAA, 0x6011, 0xCCAD, 0x6012, 0xABE3, 0x6013, 0xCCAC, 0x6014, 0xA9C3, 0x6015, 0xA9C8, 0x6016, 0xA9C6, 0x6017, 0xCCA3, 0x6019, 0xCC7C, 0x601A, 0xCCA5, 0x601B, 0xA9CD, 0x601C, 0xCCB0, 0x601D, 0xABE4, 0x601E, 0xCCA6, 0x6020, 0xABE5, 0x6021, 0xA9C9, 0x6022, 0xCCA8, 0x6024, 0xCECD, 0x6025, 0xABE6, 0x6026, 0xCC7B, 0x6027, 0xA9CA, 0x6028, 0xABE8, 0x6029, 0xA9CB, 0x602A, 0xA9C7, 0x602B, 0xA9CC, 0x602C, 0xCCA7, 0x602D, 0xCC7A, 0x602E, 0xCCAB, 0x602F, 0xA9C4, 0x6032, 0xCC7D, 0x6033, 0xCCA4, 0x6034, 0xCCA1, 0x6035, 0xA9C5, 0x6037, 0xCEBF, 0x6039, 0xCEC0, 0x6040, 0xCECA, 0x6041, 0xD1A1, 0x6042, 0xCECB, 0x6043, 0xABEE, 0x6044, 0xCECE, 0x6045, 0xCEC4, 0x6046, 0xABED, 0x6047, 0xCEC6, 0x6049, 0xCEC7, 0x604C, 0xCEC9, 0x604D, 0xABE9, 0x6050, 0xAEA3, 0x6052, 0xF9DA, 0x6053, 0xCEC5, 0x6054, 0xCEC1, 0x6055, 0xAEA4, 0x6058, 0xCECF, 0x6059, 0xAE7E, 0x605A, 0xD17D, 0x605B, 0xCEC8, 0x605D, 0xD17C, 0x605E, 0xCEC3, 0x605F, 0xCECC, 0x6062, 0xABEC, 0x6063, 0xAEA1, 0x6064, 0xABF2, 0x6065, 0xAEA2, 0x6066, 0xCED0, 0x6067, 0xD17E, 0x6068, 0xABEB, 0x6069, 0xAEA6, 0x606A, 0xABF1, 0x606B, 0xABF0, 0x606C, 0xABEF, 0x606D, 0xAEA5, 0x606E, 0xCED1, 0x606F, 0xAEA7, 0x6070, 0xABEA, 0x6072, 0xCEC2, 0x607F, 0xB176, 0x6080, 0xD1A4, 0x6081, 0xD1A6, 0x6083, 0xD1A8, 0x6084, 0xAEA8, 0x6085, 0xAEAE, 0x6086, 0xD553, 0x6087, 0xD1AC, 0x6088, 0xD1A3, 0x6089, 0xB178, 0x608A, 0xD551, 0x608C, 0xAEAD, 0x608D, 0xAEAB, 0x608E, 0xD1AE, 0x6090, 0xD552, 0x6092, 0xD1A5, 0x6094, 0xAEAC, 0x6095, 0xD1A9, 0x6096, 0xAEAF, 0x6097, 0xD1AB, 0x609A, 0xAEAA, 0x609B, 0xD1AA, 0x609C, 0xD1AD, 0x609D, 0xD1A7, 0x609F, 0xAEA9, 0x60A0, 0xB179, 0x60A2, 0xD1A2, 0x60A3, 0xB177, 0x60A8, 0xB17A, 0x60B0, 0xD555, 0x60B1, 0xD55E, 0x60B2, 0xB464, 0x60B4, 0xB17C, 0x60B5, 0xB1A3, 0x60B6, 0xB465, 0x60B7, 0xD560, 0x60B8, 0xB1AA, 0x60B9, 0xD8F9, 0x60BA, 0xD556, 0x60BB, 0xB1A2, 0x60BC, 0xB1A5, 0x60BD, 0xB17E, 0x60BE, 0xD554, 0x60BF, 0xD562, 0x60C0, 0xD565, 0x60C1, 0xD949, 0x60C3, 0xD563, 0x60C4, 0xD8FD, 0x60C5, 0xB1A1, 0x60C6, 0xB1A8, 0x60C7, 0xB1AC, 0x60C8, 0xD55D, 0x60C9, 0xD8F8, 0x60CA, 0xD561, 0x60CB, 0xB17B, 0x60CC, 0xD8FA, 0x60CD, 0xD564, 0x60CE, 0xD8FC, 0x60CF, 0xD559, 0x60D1, 0xB462, 0x60D3, 0xD557, 0x60D4, 0xD558, 0x60D5, 0xB1A7, 0x60D8, 0xB1A6, 0x60D9, 0xD55B, 0x60DA, 0xB1AB, 0x60DB, 0xD55F, 0x60DC, 0xB1A4, 0x60DD, 0xD55C, 0x60DF, 0xB1A9, 0x60E0, 0xB466, 0x60E1, 0xB463, 0x60E2, 0xD8FB, 0x60E4, 0xD55A, 0x60E6, 0xB17D, 0x60F0, 0xB46B, 0x60F1, 0xB46F, 0x60F2, 0xD940, 0x60F3, 0xB751, 0x60F4, 0xB46D, 0x60F5, 0xD944, 0x60F6, 0xB471, 0x60F7, 0xDD65, 0x60F8, 0xD946, 0x60F9, 0xB753, 0x60FA, 0xB469, 0x60FB, 0xB46C, 0x60FC, 0xD947, 0x60FE, 0xD948, 0x60FF, 0xD94E, 0x6100, 0xB473, 0x6101, 0xB754, 0x6103, 0xD94A, 0x6104, 0xD94F, 0x6105, 0xD943, 0x6106, 0xB75E, 0x6108, 0xB755, 0x6109, 0xB472, 0x610A, 0xD941, 0x610B, 0xD950, 0x610D, 0xB75D, 0x610E, 0xB470, 0x610F, 0xB74E, 0x6110, 0xD94D, 0x6112, 0xB474, 0x6113, 0xD945, 0x6114, 0xD8FE, 0x6115, 0xB46A, 0x6116, 0xD942, 0x6118, 0xD94B, 0x611A, 0xB74D, 0x611B, 0xB752, 0x611C, 0xB467, 0x611D, 0xD94C, 0x611F, 0xB750, 0x6123, 0xB468, 0x6127, 0xB75C, 0x6128, 0xE1C3, 0x6129, 0xDD70, 0x612B, 0xDD68, 0x612C, 0xE1C2, 0x612E, 0xDD6C, 0x612F, 0xDD6E, 0x6132, 0xDD6B, 0x6134, 0xB75B, 0x6136, 0xDD6A, 0x6137, 0xB75F, 0x613B, 0xE1D2, 0x613E, 0xB75A, 0x613F, 0xBA40, 0x6140, 0xDD71, 0x6141, 0xE1C4, 0x6144, 0xB758, 0x6145, 0xDD69, 0x6146, 0xDD6D, 0x6147, 0xB9FE, 0x6148, 0xB74F, 0x6149, 0xDD66, 0x614A, 0xDD67, 0x614B, 0xBA41, 0x614C, 0xB757, 0x614D, 0xB759, 0x614E, 0xB756, 0x614F, 0xDD6F, 0x6152, 0xE1C8, 0x6153, 0xE1C9, 0x6154, 0xE1CE, 0x6155, 0xBC7D, 0x6156, 0xE1D5, 0x6158, 0xBA47, 0x615A, 0xBA46, 0x615B, 0xE1D0, 0x615D, 0xBC7C, 0x615E, 0xE1C5, 0x615F, 0xBA45, 0x6161, 0xE1D4, 0x6162, 0xBA43, 0x6163, 0xBA44, 0x6165, 0xE1D1, 0x6166, 0xE5AA, 0x6167, 0xBC7A, 0x6168, 0xB46E, 0x616A, 0xE1D3, 0x616B, 0xBCA3, 0x616C, 0xE1CB, 0x616E, 0xBC7B, 0x6170, 0xBCA2, 0x6171, 0xE1C6, 0x6172, 0xE1CA, 0x6173, 0xE1C7, 0x6174, 0xE1CD, 0x6175, 0xBA48, 0x6176, 0xBC79, 0x6177, 0xBA42, 0x6179, 0xE57A, 0x617A, 0xE1CF, 0x617C, 0xBCA1, 0x617E, 0xBCA4, 0x6180, 0xE1CC, 0x6182, 0xBC7E, 0x6183, 0xE579, 0x6189, 0xE57E, 0x618A, 0xBECE, 0x618B, 0xE578, 0x618C, 0xE9A3, 0x618D, 0xE5A9, 0x618E, 0xBCA8, 0x6190, 0xBCA6, 0x6191, 0xBECC, 0x6192, 0xE5A6, 0x6193, 0xE5A2, 0x6194, 0xBCAC, 0x6196, 0xE978, 0x619A, 0xBCAA, 0x619B, 0xE5A1, 0x619D, 0xE976, 0x619F, 0xE5A5, 0x61A1, 0xE5A8, 0x61A2, 0xE57D, 0x61A4, 0xBCAB, 0x61A7, 0xBCA5, 0x61A8, 0xE977, 0x61A9, 0xBECD, 0x61AA, 0xE5A7, 0x61AB, 0xBCA7, 0x61AC, 0xBCA9, 0x61AD, 0xE5A4, 0x61AE, 0xBCAD, 0x61AF, 0xE5A3, 0x61B0, 0xE57C, 0x61B1, 0xE57B, 0x61B2, 0xBECB, 0x61B3, 0xE5AB, 0x61B4, 0xE97A, 0x61B5, 0xECE0, 0x61B6, 0xBED0, 0x61B8, 0xE9A2, 0x61BA, 0xE97E, 0x61BC, 0xECE1, 0x61BE, 0xBED1, 0x61BF, 0xE9A1, 0x61C1, 0xE97C, 0x61C2, 0xC0B4, 0x61C3, 0xECDF, 0x61C5, 0xE979, 0x61C6, 0xE97B, 0x61C7, 0xC0B5, 0x61C8, 0xBED3, 0x61C9, 0xC0B3, 0x61CA, 0xBED2, 0x61CB, 0xC0B7, 0x61CC, 0xE97D, 0x61CD, 0xBECF, 0x61D6, 0xEFCF, 0x61D8, 0xEFC7, 0x61DE, 0xECE7, 0x61DF, 0xEFC8, 0x61E0, 0xECE3, 0x61E3, 0xC256, 0x61E4, 0xECE5, 0x61E5, 0xECE4, 0x61E6, 0xC0B6, 0x61E7, 0xECE2, 0x61E8, 0xECE6, 0x61E9, 0xEFD0, 0x61EA, 0xEFCC, 0x61EB, 0xEFCE, 0x61ED, 0xEFC9, 0x61EE, 0xEFCA, 0x61F0, 0xEFCD, 0x61F1, 0xEFCB, 0x61F2, 0xC367, 0x61F5, 0xC36A, 0x61F6, 0xC369, 0x61F7, 0xC368, 0x61F8, 0xC461, 0x61F9, 0xF44A, 0x61FA, 0xC462, 0x61FB, 0xF241, 0x61FC, 0xC4DF, 0x61FD, 0xF5CC, 0x61FE, 0xC4E0, 0x61FF, 0xC574, 0x6200, 0xC5CA, 0x6201, 0xF7D9, 0x6203, 0xF7DA, 0x6204, 0xF7DB, 0x6207, 0xF9BA, 0x6208, 0xA4E0, 0x6209, 0xC97C, 0x620A, 0xA5B3, 0x620C, 0xA6A6, 0x620D, 0xA6A7, 0x620E, 0xA6A5, 0x6210, 0xA6A8, 0x6211, 0xA7DA, 0x6212, 0xA7D9, 0x6214, 0xCCB1, 0x6215, 0xA9CF, 0x6216, 0xA9CE, 0x6219, 0xD1AF, 0x621A, 0xB1AD, 0x621B, 0xB1AE, 0x621F, 0xB475, 0x6220, 0xDD72, 0x6221, 0xB760, 0x6222, 0xB761, 0x6223, 0xDD74, 0x6224, 0xDD76, 0x6225, 0xDD75, 0x6227, 0xE1D7, 0x6229, 0xE1D6, 0x622A, 0xBA49, 0x622B, 0xE1D8, 0x622D, 0xE5AC, 0x622E, 0xBCAE, 0x6230, 0xBED4, 0x6232, 0xC0B8, 0x6233, 0xC257, 0x6234, 0xC0B9, 0x6236, 0xA4E1, 0x623A, 0xCAE6, 0x623D, 0xCCB2, 0x623E, 0xA9D1, 0x623F, 0xA9D0, 0x6240, 0xA9D2, 0x6241, 0xABF3, 0x6242, 0xCED2, 0x6243, 0xCED3, 0x6246, 0xD1B0, 0x6247, 0xAEB0, 0x6248, 0xB1AF, 0x6249, 0xB476, 0x624A, 0xD951, 0x624B, 0xA4E2, 0x624D, 0xA47E, 0x624E, 0xA4E3, 0x6250, 0xC97D, 0x6251, 0xA5B7, 0x6252, 0xA5B6, 0x6253, 0xA5B4, 0x6254, 0xA5B5, 0x6258, 0xA6AB, 0x6259, 0xC9E9, 0x625A, 0xC9EB, 0x625B, 0xA6AA, 0x625C, 0xC9E3, 0x625E, 0xC9E4, 0x6260, 0xC9EA, 0x6261, 0xC9E6, 0x6262, 0xC9E8, 0x6263, 0xA6A9, 0x6264, 0xC9E5, 0x6265, 0xC9EC, 0x6266, 0xC9E7, 0x626D, 0xA7E1, 0x626E, 0xA7EA, 0x626F, 0xA7E8, 0x6270, 0xCAF0, 0x6271, 0xCAED, 0x6272, 0xCAF5, 0x6273, 0xA7E6, 0x6274, 0xCAF6, 0x6276, 0xA7DF, 0x6277, 0xCAF3, 0x6279, 0xA7E5, 0x627A, 0xCAEF, 0x627B, 0xCAEE, 0x627C, 0xA7E3, 0x627D, 0xCAF4, 0x627E, 0xA7E4, 0x627F, 0xA9D3, 0x6280, 0xA7DE, 0x6281, 0xCAF1, 0x6283, 0xCAE7, 0x6284, 0xA7DB, 0x6286, 0xA7EE, 0x6287, 0xCAEC, 0x6288, 0xCAF2, 0x6289, 0xA7E0, 0x628A, 0xA7E2, 0x628C, 0xCAE8, 0x628E, 0xCAE9, 0x628F, 0xCAEA, 0x6291, 0xA7ED, 0x6292, 0xA7E7, 0x6293, 0xA7EC, 0x6294, 0xCAEB, 0x6295, 0xA7EB, 0x6296, 0xA7DD, 0x6297, 0xA7DC, 0x6298, 0xA7E9, 0x62A8, 0xA9E1, 0x62A9, 0xCCBE, 0x62AA, 0xCCB7, 0x62AB, 0xA9DC, 0x62AC, 0xA9EF, 0x62AD, 0xCCB3, 0x62AE, 0xCCBA, 0x62AF, 0xCCBC, 0x62B0, 0xCCBF, 0x62B1, 0xA9EA, 0x62B3, 0xCCBB, 0x62B4, 0xCCB4, 0x62B5, 0xA9E8, 0x62B6, 0xCCB8, 0x62B8, 0xCCC0, 0x62B9, 0xA9D9, 0x62BB, 0xCCBD, 0x62BC, 0xA9E3, 0x62BD, 0xA9E2, 0x62BE, 0xCCB6, 0x62BF, 0xA9D7, 0x62C2, 0xA9D8, 0x62C4, 0xA9D6, 0x62C6, 0xA9EE, 0x62C7, 0xA9E6, 0x62C8, 0xA9E0, 0x62C9, 0xA9D4, 0x62CA, 0xCCB9, 0x62CB, 0xA9DF, 0x62CC, 0xA9D5, 0x62CD, 0xA9E7, 0x62CE, 0xA9F0, 0x62CF, 0xCED4, 0x62D0, 0xA9E4, 0x62D1, 0xCCB5, 0x62D2, 0xA9DA, 0x62D3, 0xA9DD, 0x62D4, 0xA9DE, 0x62D6, 0xA9EC, 0x62D7, 0xA9ED, 0x62D8, 0xA9EB, 0x62D9, 0xA9E5, 0x62DA, 0xA9E9, 0x62DB, 0xA9DB, 0x62DC, 0xABF4, 0x62EB, 0xCEDA, 0x62EC, 0xAC41, 0x62ED, 0xABF8, 0x62EE, 0xABFA, 0x62EF, 0xAC40, 0x62F0, 0xCEE6, 0x62F1, 0xABFD, 0x62F2, 0xD1B1, 0x62F3, 0xAEB1, 0x62F4, 0xAC43, 0x62F5, 0xCED7, 0x62F6, 0xCEDF, 0x62F7, 0xABFE, 0x62F8, 0xCEDE, 0x62F9, 0xCEDB, 0x62FA, 0xCEE3, 0x62FB, 0xCEE5, 0x62FC, 0xABF7, 0x62FD, 0xABFB, 0x62FE, 0xAC42, 0x62FF, 0xAEB3, 0x6300, 0xCEE0, 0x6301, 0xABF9, 0x6302, 0xAC45, 0x6303, 0xCED9, 0x6307, 0xABFC, 0x6308, 0xAEB2, 0x6309, 0xABF6, 0x630B, 0xCED6, 0x630C, 0xCEDD, 0x630D, 0xCED5, 0x630E, 0xCED8, 0x630F, 0xCEDC, 0x6310, 0xD1B2, 0x6311, 0xAC44, 0x6313, 0xCEE1, 0x6314, 0xCEE2, 0x6315, 0xCEE4, 0x6316, 0xABF5, 0x6328, 0xAEC1, 0x6329, 0xD1BE, 0x632A, 0xAEBF, 0x632B, 0xAEC0, 0x632C, 0xD1B4, 0x632D, 0xD1C4, 0x632F, 0xAEB6, 0x6332, 0xD566, 0x6333, 0xD1C6, 0x6334, 0xD1C0, 0x6336, 0xD1B7, 0x6338, 0xD1C9, 0x6339, 0xD1BA, 0x633A, 0xAEBC, 0x633B, 0xD57D, 0x633C, 0xD1BD, 0x633D, 0xAEBE, 0x633E, 0xAEB5, 0x6340, 0xD1CB, 0x6341, 0xD1BF, 0x6342, 0xAEB8, 0x6343, 0xD1B8, 0x6344, 0xD1B5, 0x6345, 0xD1B6, 0x6346, 0xAEB9, 0x6347, 0xD1C5, 0x6348, 0xD1CC, 0x6349, 0xAEBB, 0x634A, 0xD1BC, 0x634B, 0xD1BB, 0x634C, 0xAEC3, 0x634D, 0xAEC2, 0x634E, 0xAEB4, 0x634F, 0xAEBA, 0x6350, 0xAEBD, 0x6351, 0xD1C8, 0x6354, 0xD1C2, 0x6355, 0xAEB7, 0x6356, 0xD1B3, 0x6357, 0xD1CA, 0x6358, 0xD1C1, 0x6359, 0xD1C3, 0x635A, 0xD1C7, 0x6365, 0xD567, 0x6367, 0xB1B7, 0x6368, 0xB1CB, 0x6369, 0xB1CA, 0x636B, 0xB1BF, 0x636D, 0xD579, 0x636E, 0xD575, 0x636F, 0xD572, 0x6370, 0xD5A6, 0x6371, 0xB1BA, 0x6372, 0xB1B2, 0x6375, 0xD577, 0x6376, 0xB4A8, 0x6377, 0xB1B6, 0x6378, 0xD5A1, 0x637A, 0xB1CC, 0x637B, 0xB1C9, 0x637C, 0xD57B, 0x637D, 0xD56A, 0x6380, 0xB1C8, 0x6381, 0xD5A3, 0x6382, 0xD569, 0x6383, 0xB1BD, 0x6384, 0xB1C1, 0x6385, 0xD5A2, 0x6387, 0xD573, 0x6388, 0xB1C2, 0x6389, 0xB1BC, 0x638A, 0xD568, 0x638C, 0xB478, 0x638D, 0xD5A5, 0x638E, 0xD571, 0x638F, 0xB1C7, 0x6390, 0xD574, 0x6391, 0xD5A4, 0x6392, 0xB1C6, 0x6394, 0xD952, 0x6396, 0xB1B3, 0x6397, 0xD56F, 0x6398, 0xB1B8, 0x6399, 0xB1C3, 0x639B, 0xB1BE, 0x639C, 0xD578, 0x639D, 0xD56E, 0x639E, 0xD56C, 0x639F, 0xD57E, 0x63A0, 0xB1B0, 0x63A1, 0xB1C4, 0x63A2, 0xB1B4, 0x63A3, 0xB477, 0x63A4, 0xD57C, 0x63A5, 0xB1B5, 0x63A7, 0xB1B1, 0x63A8, 0xB1C0, 0x63A9, 0xB1BB, 0x63AA, 0xB1B9, 0x63AB, 0xD570, 0x63AC, 0xB1C5, 0x63AD, 0xD56D, 0x63AE, 0xD57A, 0x63AF, 0xD576, 0x63B0, 0xD954, 0x63B1, 0xD953, 0x63BD, 0xD56B, 0x63BE, 0xD964, 0x63C0, 0xB47A, 0x63C2, 0xD96A, 0x63C3, 0xD959, 0x63C4, 0xD967, 0x63C5, 0xDD77, 0x63C6, 0xB47D, 0x63C7, 0xD96B, 0x63C8, 0xD96E, 0x63C9, 0xB47C, 0x63CA, 0xD95C, 0x63CB, 0xD96D, 0x63CC, 0xD96C, 0x63CD, 0xB47E, 0x63CE, 0xD955, 0x63CF, 0xB479, 0x63D0, 0xB4A3, 0x63D2, 0xB4A1, 0x63D3, 0xD969, 0x63D5, 0xD95F, 0x63D6, 0xB4A5, 0x63D7, 0xD970, 0x63D8, 0xD968, 0x63D9, 0xD971, 0x63DA, 0xB4AD, 0x63DB, 0xB4AB, 0x63DC, 0xD966, 0x63DD, 0xD965, 0x63DF, 0xD963, 0x63E0, 0xD95D, 0x63E1, 0xB4A4, 0x63E3, 0xB4A2, 0x63E4, 0xD1B9, 0x63E5, 0xD956, 0x63E7, 0xDDB7, 0x63E8, 0xD957, 0x63E9, 0xB47B, 0x63EA, 0xB4AA, 0x63EB, 0xDD79, 0x63ED, 0xB4A6, 0x63EE, 0xB4A7, 0x63EF, 0xD958, 0x63F0, 0xD96F, 0x63F1, 0xDD78, 0x63F2, 0xD960, 0x63F3, 0xD95B, 0x63F4, 0xB4A9, 0x63F5, 0xD961, 0x63F6, 0xD95E, 0x63F9, 0xB4AE, 0x6406, 0xB770, 0x6409, 0xDD7C, 0x640A, 0xDDB1, 0x640B, 0xDDB6, 0x640C, 0xDDAA, 0x640D, 0xB76C, 0x640E, 0xDDBB, 0x640F, 0xB769, 0x6410, 0xDD7A, 0x6412, 0xDD7B, 0x6413, 0xB762, 0x6414, 0xB76B, 0x6415, 0xDDA4, 0x6416, 0xB76E, 0x6417, 0xB76F, 0x6418, 0xDDA5, 0x641A, 0xDDB2, 0x641B, 0xDDB8, 0x641C, 0xB76A, 0x641E, 0xB764, 0x641F, 0xDDA3, 0x6420, 0xDD7D, 0x6421, 0xDDBA, 0x6422, 0xDDA8, 0x6423, 0xDDA9, 0x6424, 0xDD7E, 0x6425, 0xDDB4, 0x6426, 0xDDAB, 0x6427, 0xDDB5, 0x6428, 0xDDAD, 0x642A, 0xB765, 0x642B, 0xE1D9, 0x642C, 0xB768, 0x642D, 0xB766, 0x642E, 0xDDB9, 0x642F, 0xDDB0, 0x6430, 0xDDAC, 0x6433, 0xDDA1, 0x6434, 0xBA53, 0x6435, 0xDDAF, 0x6436, 0xB76D, 0x6437, 0xDDA7, 0x6439, 0xDDA6, 0x643D, 0xB767, 0x643E, 0xB763, 0x643F, 0xE1EE, 0x6440, 0xDDB3, 0x6441, 0xDDAE, 0x6443, 0xDDA2, 0x644B, 0xE1E9, 0x644D, 0xE1DA, 0x644E, 0xE1E5, 0x6450, 0xE1EC, 0x6451, 0xBA51, 0x6452, 0xB4AC, 0x6453, 0xE1EA, 0x6454, 0xBA4C, 0x6458, 0xBA4B, 0x6459, 0xE1F1, 0x645B, 0xE1DB, 0x645C, 0xE1E8, 0x645D, 0xE1DC, 0x645E, 0xE1E7, 0x645F, 0xBA4F, 0x6460, 0xE1EB, 0x6461, 0xD962, 0x6465, 0xE1F2, 0x6466, 0xE1E3, 0x6467, 0xBA52, 0x6468, 0xE5BA, 0x6469, 0xBCAF, 0x646B, 0xE1F0, 0x646C, 0xE1EF, 0x646D, 0xBA54, 0x646E, 0xE5AD, 0x646F, 0xBCB0, 0x6470, 0xE5AE, 0x6472, 0xE1DF, 0x6473, 0xE1E0, 0x6474, 0xE1DD, 0x6475, 0xE1E2, 0x6476, 0xE1DE, 0x6477, 0xE1F3, 0x6478, 0xBA4E, 0x6479, 0xBCB1, 0x647A, 0xBA50, 0x647B, 0xBA55, 0x647D, 0xE1E1, 0x647F, 0xE1ED, 0x6482, 0xE1E6, 0x6485, 0xE5B1, 0x6487, 0xBA4A, 0x6488, 0xBCB4, 0x6489, 0xE9AA, 0x648A, 0xE5B6, 0x648B, 0xE5B5, 0x648C, 0xE5B7, 0x648F, 0xE5B4, 0x6490, 0xBCB5, 0x6492, 0xBCBB, 0x6493, 0xBCB8, 0x6495, 0xBCB9, 0x6496, 0xE5AF, 0x6497, 0xE5B2, 0x6498, 0xE5BC, 0x6499, 0xBCC1, 0x649A, 0xBCBF, 0x649C, 0xE5B3, 0x649D, 0xD95A, 0x649E, 0xBCB2, 0x649F, 0xE5B9, 0x64A0, 0xE5B0, 0x64A2, 0xBCC2, 0x64A3, 0xE5B8, 0x64A4, 0xBA4D, 0x64A5, 0xBCB7, 0x64A6, 0xE1E4, 0x64A9, 0xBCBA, 0x64AB, 0xBCBE, 0x64AC, 0xBCC0, 0x64AD, 0xBCBD, 0x64AE, 0xBCBC, 0x64B0, 0xBCB6, 0x64B1, 0xE5BB, 0x64B2, 0xBCB3, 0x64B3, 0xBCC3, 0x64BB, 0xBED8, 0x64BC, 0xBED9, 0x64BD, 0xE9A9, 0x64BE, 0xBEE2, 0x64BF, 0xBEDF, 0x64C1, 0xBED6, 0x64C2, 0xBEDD, 0x64C3, 0xE9AB, 0x64C4, 0xBEDB, 0x64C5, 0xBED5, 0x64C7, 0xBEDC, 0x64C9, 0xE9A8, 0x64CA, 0xC0BB, 0x64CB, 0xBED7, 0x64CD, 0xBEDE, 0x64CE, 0xC0BA, 0x64CF, 0xE9A7, 0x64D0, 0xE9A6, 0x64D2, 0xBEE0, 0x64D4, 0xBEE1, 0x64D6, 0xE9A5, 0x64D7, 0xE9A4, 0x64D8, 0xC0BC, 0x64D9, 0xE9AE, 0x64DA, 0xBEDA, 0x64DB, 0xE9AC, 0x64E0, 0xC0BD, 0x64E2, 0xC0C2, 0x64E3, 0xECEA, 0x64E4, 0xECEC, 0x64E6, 0xC0BF, 0x64E8, 0xECED, 0x64E9, 0xECE9, 0x64EB, 0xECEB, 0x64EC, 0xC0C0, 0x64ED, 0xC0C3, 0x64EF, 0xECE8, 0x64F0, 0xC0BE, 0x64F1, 0xC0C1, 0x64F2, 0xC259, 0x64F3, 0xE9AD, 0x64F4, 0xC258, 0x64F7, 0xC25E, 0x64F8, 0xEFD4, 0x64FA, 0xC25C, 0x64FB, 0xC25D, 0x64FC, 0xEFD7, 0x64FD, 0xEFD3, 0x64FE, 0xC25A, 0x64FF, 0xEFD1, 0x6500, 0xC36B, 0x6501, 0xEFD5, 0x6503, 0xEFD6, 0x6504, 0xEFD2, 0x6506, 0xC25B, 0x6507, 0xF242, 0x6509, 0xF245, 0x650C, 0xF246, 0x650D, 0xF244, 0x650E, 0xF247, 0x650F, 0xC36C, 0x6510, 0xF243, 0x6513, 0xF44E, 0x6514, 0xC464, 0x6515, 0xF44D, 0x6516, 0xF44C, 0x6517, 0xF44B, 0x6518, 0xC463, 0x6519, 0xC465, 0x651B, 0xF5CD, 0x651C, 0xC4E2, 0x651D, 0xC4E1, 0x6520, 0xF6E1, 0x6521, 0xF6E0, 0x6522, 0xF6E3, 0x6523, 0xC5CB, 0x6524, 0xC575, 0x6525, 0xF7DD, 0x6526, 0xF6E2, 0x6529, 0xF7DC, 0x652A, 0xC5CD, 0x652B, 0xC5CC, 0x652C, 0xC5F3, 0x652D, 0xF8A9, 0x652E, 0xF8EF, 0x652F, 0xA4E4, 0x6532, 0xD972, 0x6533, 0xE9AF, 0x6536, 0xA6AC, 0x6537, 0xCAF7, 0x6538, 0xA7F1, 0x6539, 0xA7EF, 0x653B, 0xA7F0, 0x653D, 0xCCC1, 0x653E, 0xA9F1, 0x653F, 0xAC46, 0x6541, 0xCEE7, 0x6543, 0xCEE8, 0x6545, 0xAC47, 0x6546, 0xD1CE, 0x6548, 0xAEC4, 0x6549, 0xAEC5, 0x654A, 0xD1CD, 0x654F, 0xB1D3, 0x6551, 0xB1CF, 0x6553, 0xD5A7, 0x6554, 0xB1D6, 0x6555, 0xB1D5, 0x6556, 0xB1CE, 0x6557, 0xB1D1, 0x6558, 0xB1D4, 0x6559, 0xB1D0, 0x655C, 0xD976, 0x655D, 0xB1CD, 0x655E, 0xB4AF, 0x6562, 0xB4B1, 0x6563, 0xB4B2, 0x6564, 0xD975, 0x6565, 0xD978, 0x6566, 0xB4B0, 0x6567, 0xD973, 0x6568, 0xD977, 0x656A, 0xD974, 0x656C, 0xB771, 0x656F, 0xDDBC, 0x6572, 0xBA56, 0x6573, 0xE1F4, 0x6574, 0xBEE3, 0x6575, 0xBCC4, 0x6576, 0xE5BD, 0x6577, 0xBCC5, 0x6578, 0xBCC6, 0x6579, 0xE5BF, 0x657A, 0xE5BE, 0x657B, 0xE5C0, 0x657C, 0xE9B1, 0x657F, 0xE9B0, 0x6580, 0xECEF, 0x6581, 0xECEE, 0x6582, 0xC0C4, 0x6583, 0xC0C5, 0x6584, 0xF248, 0x6587, 0xA4E5, 0x658C, 0xD979, 0x6590, 0xB4B4, 0x6591, 0xB4B3, 0x6592, 0xDDBD, 0x6594, 0xEFD8, 0x6595, 0xC4E3, 0x6596, 0xF7DE, 0x6597, 0xA4E6, 0x6599, 0xAEC6, 0x659B, 0xB1D8, 0x659C, 0xB1D7, 0x659D, 0xD97A, 0x659E, 0xD97B, 0x659F, 0xB772, 0x65A0, 0xE1F5, 0x65A1, 0xBA57, 0x65A2, 0xE9B2, 0x65A4, 0xA4E7, 0x65A5, 0xA5B8, 0x65A7, 0xA9F2, 0x65A8, 0xCCC2, 0x65AA, 0xCEE9, 0x65AB, 0xAC48, 0x65AC, 0xB1D9, 0x65AE, 0xD97C, 0x65AF, 0xB4B5, 0x65B0, 0xB773, 0x65B2, 0xE5C1, 0x65B3, 0xE5C2, 0x65B6, 0xECF0, 0x65B7, 0xC25F, 0x65B8, 0xF8F0, 0x65B9, 0xA4E8, 0x65BB, 0xCCC3, 0x65BC, 0xA9F3, 0x65BD, 0xAC49, 0x65BF, 0xCEEA, 0x65C1, 0xAEC7, 0x65C2, 0xD1D2, 0x65C3, 0xD1D0, 0x65C4, 0xD1D1, 0x65C5, 0xAEC8, 0x65C6, 0xD1CF, 0x65CB, 0xB1DB, 0x65CC, 0xB1DC, 0x65CD, 0xD5A8, 0x65CE, 0xB1DD, 0x65CF, 0xB1DA, 0x65D0, 0xD97D, 0x65D2, 0xD97E, 0x65D3, 0xDDBE, 0x65D6, 0xBA59, 0x65D7, 0xBA58, 0x65DA, 0xECF1, 0x65DB, 0xEFD9, 0x65DD, 0xF24A, 0x65DE, 0xF249, 0x65DF, 0xF44F, 0x65E1, 0xC95E, 0x65E2, 0xAC4A, 0x65E5, 0xA4E9, 0x65E6, 0xA5B9, 0x65E8, 0xA6AE, 0x65E9, 0xA6AD, 0x65EC, 0xA6AF, 0x65ED, 0xA6B0, 0x65EE, 0xC9EE, 0x65EF, 0xC9ED, 0x65F0, 0xCAF8, 0x65F1, 0xA7F2, 0x65F2, 0xCAFB, 0x65F3, 0xCAFA, 0x65F4, 0xCAF9, 0x65F5, 0xCAFC, 0x65FA, 0xA9F4, 0x65FB, 0xCCC9, 0x65FC, 0xCCC5, 0x65FD, 0xCCCE, 0x6600, 0xA9FB, 0x6602, 0xA9F9, 0x6603, 0xCCCA, 0x6604, 0xCCC6, 0x6605, 0xCCCD, 0x6606, 0xA9F8, 0x6607, 0xAA40, 0x6608, 0xCCC8, 0x6609, 0xCCC4, 0x660A, 0xA9FE, 0x660B, 0xCCCB, 0x660C, 0xA9F7, 0x660D, 0xCCCC, 0x660E, 0xA9FA, 0x660F, 0xA9FC, 0x6610, 0xCCD0, 0x6611, 0xCCCF, 0x6612, 0xCCC7, 0x6613, 0xA9F6, 0x6614, 0xA9F5, 0x6615, 0xA9FD, 0x661C, 0xCEEF, 0x661D, 0xCEF5, 0x661F, 0xAC50, 0x6620, 0xAC4D, 0x6621, 0xCEEC, 0x6622, 0xCEF1, 0x6624, 0xAC53, 0x6625, 0xAC4B, 0x6626, 0xCEF0, 0x6627, 0xAC4E, 0x6628, 0xAC51, 0x662B, 0xCEF3, 0x662D, 0xAC4C, 0x662E, 0xCEF8, 0x662F, 0xAC4F, 0x6631, 0xAC52, 0x6632, 0xCEED, 0x6633, 0xCEF2, 0x6634, 0xCEF6, 0x6635, 0xCEEE, 0x6636, 0xCEEB, 0x6639, 0xCEF7, 0x663A, 0xCEF4, 0x6641, 0xAED0, 0x6642, 0xAEC9, 0x6643, 0xAECC, 0x6645, 0xAECF, 0x6647, 0xD1D5, 0x6649, 0xAECA, 0x664A, 0xD1D3, 0x664C, 0xAECE, 0x664F, 0xAECB, 0x6651, 0xD1D6, 0x6652, 0xAECD, 0x6659, 0xD5AC, 0x665A, 0xB1DF, 0x665B, 0xD5AB, 0x665C, 0xD5AD, 0x665D, 0xB1DE, 0x665E, 0xB1E3, 0x665F, 0xD1D4, 0x6661, 0xD5AA, 0x6662, 0xD5AE, 0x6664, 0xB1E0, 0x6665, 0xD5A9, 0x6666, 0xB1E2, 0x6668, 0xB1E1, 0x666A, 0xD9A7, 0x666C, 0xD9A2, 0x666E, 0xB4B6, 0x666F, 0xB4BA, 0x6670, 0xB4B7, 0x6671, 0xD9A5, 0x6672, 0xD9A8, 0x6674, 0xB4B8, 0x6676, 0xB4B9, 0x6677, 0xB4BE, 0x6678, 0xDDC7, 0x6679, 0xD9A6, 0x667A, 0xB4BC, 0x667B, 0xD9A3, 0x667C, 0xD9A1, 0x667E, 0xB4BD, 0x6680, 0xD9A4, 0x6684, 0xB779, 0x6686, 0xDDBF, 0x6687, 0xB776, 0x6688, 0xB777, 0x6689, 0xB775, 0x668A, 0xDDC4, 0x668B, 0xDDC3, 0x668C, 0xDDC0, 0x668D, 0xB77B, 0x6690, 0xDDC2, 0x6691, 0xB4BB, 0x6694, 0xDDC6, 0x6695, 0xDDC1, 0x6696, 0xB778, 0x6697, 0xB774, 0x6698, 0xB77A, 0x6699, 0xDDC5, 0x669D, 0xBA5C, 0x669F, 0xE1F8, 0x66A0, 0xE1F7, 0x66A1, 0xE1F6, 0x66A2, 0xBA5A, 0x66A8, 0xBA5B, 0x66A9, 0xE5C5, 0x66AA, 0xE5C8, 0x66AB, 0xBCC8, 0x66AE, 0xBCC7, 0x66AF, 0xE5C9, 0x66B0, 0xE5C4, 0x66B1, 0xBCCA, 0x66B2, 0xE5C6, 0x66B4, 0xBCC9, 0x66B5, 0xE5C3, 0x66B7, 0xE5C7, 0x66B8, 0xBEE9, 0x66B9, 0xBEE6, 0x66BA, 0xE9BB, 0x66BB, 0xE9BA, 0x66BD, 0xE9B9, 0x66BE, 0xE9B4, 0x66C0, 0xE9B5, 0x66C4, 0xBEE7, 0x66C6, 0xBEE4, 0x66C7, 0xBEE8, 0x66C8, 0xE9B3, 0x66C9, 0xBEE5, 0x66CA, 0xE9B6, 0x66CB, 0xE9B7, 0x66CC, 0xE9BC, 0x66CF, 0xE9B8, 0x66D2, 0xECF2, 0x66D6, 0xC0C7, 0x66D8, 0xEFDC, 0x66D9, 0xC0C6, 0x66DA, 0xEFDA, 0x66DB, 0xEFDB, 0x66DC, 0xC260, 0x66DD, 0xC36E, 0x66DE, 0xF24B, 0x66E0, 0xC36D, 0x66E3, 0xF451, 0x66E4, 0xF452, 0x66E6, 0xC466, 0x66E8, 0xF450, 0x66E9, 0xC4E4, 0x66EB, 0xF7DF, 0x66EC, 0xC5CE, 0x66ED, 0xF8AA, 0x66EE, 0xF8AB, 0x66F0, 0xA4EA, 0x66F2, 0xA6B1, 0x66F3, 0xA6B2, 0x66F4, 0xA7F3, 0x66F6, 0xCCD1, 0x66F7, 0xAC54, 0x66F8, 0xAED1, 0x66F9, 0xB1E4, 0x66FC, 0xB0D2, 0x66FE, 0xB4BF, 0x66FF, 0xB4C0, 0x6700, 0xB3CC, 0x6701, 0xD9A9, 0x6703, 0xB77C, 0x6704, 0xE1FA, 0x6705, 0xE1F9, 0x6708, 0xA4EB, 0x6709, 0xA6B3, 0x670A, 0xCCD2, 0x670B, 0xAA42, 0x670D, 0xAA41, 0x670F, 0xCEF9, 0x6710, 0xCEFA, 0x6712, 0xD1D7, 0x6713, 0xD1D8, 0x6714, 0xAED2, 0x6715, 0xAED3, 0x6717, 0xAED4, 0x6718, 0xD5AF, 0x671B, 0xB1E6, 0x671D, 0xB4C2, 0x671F, 0xB4C1, 0x6720, 0xDDC8, 0x6721, 0xDF7A, 0x6722, 0xE1FB, 0x6723, 0xE9BD, 0x6726, 0xC261, 0x6727, 0xC467, 0x6728, 0xA4EC, 0x672A, 0xA5BC, 0x672B, 0xA5BD, 0x672C, 0xA5BB, 0x672D, 0xA5BE, 0x672E, 0xA5BA, 0x6731, 0xA6B6, 0x6733, 0xC9F6, 0x6734, 0xA6B5, 0x6735, 0xA6B7, 0x6738, 0xC9F1, 0x6739, 0xC9F0, 0x673A, 0xC9F3, 0x673B, 0xC9F2, 0x673C, 0xC9F5, 0x673D, 0xA6B4, 0x673E, 0xC9EF, 0x673F, 0xC9F4, 0x6745, 0xCAFD, 0x6746, 0xA7FD, 0x6747, 0xCAFE, 0x6748, 0xCB43, 0x6749, 0xA7FC, 0x674B, 0xCB47, 0x674C, 0xCB42, 0x674D, 0xCB45, 0x674E, 0xA7F5, 0x674F, 0xA7F6, 0x6750, 0xA7F7, 0x6751, 0xA7F8, 0x6753, 0xA840, 0x6755, 0xCB41, 0x6756, 0xA7FA, 0x6757, 0xA841, 0x6759, 0xCB40, 0x675A, 0xCB46, 0x675C, 0xA7F9, 0x675D, 0xCB44, 0x675E, 0xA7FB, 0x675F, 0xA7F4, 0x6760, 0xA7FE, 0x676A, 0xAA57, 0x676C, 0xCCD4, 0x676D, 0xAA43, 0x676F, 0xAA4D, 0x6770, 0xAA4E, 0x6771, 0xAA46, 0x6772, 0xAA58, 0x6773, 0xAA48, 0x6774, 0xCCDC, 0x6775, 0xAA53, 0x6776, 0xCCD7, 0x6777, 0xAA49, 0x6778, 0xCCE6, 0x6779, 0xCCE7, 0x677A, 0xCCDF, 0x677B, 0xCCD8, 0x677C, 0xAA56, 0x677D, 0xCCE4, 0x677E, 0xAA51, 0x677F, 0xAA4F, 0x6781, 0xCCE5, 0x6783, 0xCCE3, 0x6784, 0xCCDB, 0x6785, 0xCCD3, 0x6786, 0xCCDA, 0x6787, 0xAA4A, 0x6789, 0xAA50, 0x678B, 0xAA44, 0x678C, 0xCCDE, 0x678D, 0xCCDD, 0x678E, 0xCCD5, 0x6790, 0xAA52, 0x6791, 0xCCE1, 0x6792, 0xCCD6, 0x6793, 0xAA55, 0x6794, 0xCCE8, 0x6795, 0xAA45, 0x6797, 0xAA4C, 0x6798, 0xCCD9, 0x6799, 0xCCE2, 0x679A, 0xAA54, 0x679C, 0xAA47, 0x679D, 0xAA4B, 0x679F, 0xCCE0, 0x67AE, 0xCF5B, 0x67AF, 0xAC5C, 0x67B0, 0xAC69, 0x67B2, 0xCF56, 0x67B3, 0xCF4C, 0x67B4, 0xAC62, 0x67B5, 0xCF4A, 0x67B6, 0xAC5B, 0x67B7, 0xCF45, 0x67B8, 0xAC65, 0x67B9, 0xCF52, 0x67BA, 0xCEFE, 0x67BB, 0xCF41, 0x67C0, 0xCF44, 0x67C1, 0xCEFB, 0x67C2, 0xCF51, 0x67C3, 0xCF61, 0x67C4, 0xAC60, 0x67C5, 0xCF46, 0x67C6, 0xCF58, 0x67C8, 0xCEFD, 0x67C9, 0xCF5F, 0x67CA, 0xCF60, 0x67CB, 0xCF63, 0x67CC, 0xCF5A, 0x67CD, 0xCF4B, 0x67CE, 0xCF53, 0x67CF, 0xAC66, 0x67D0, 0xAC59, 0x67D1, 0xAC61, 0x67D2, 0xAC6D, 0x67D3, 0xAC56, 0x67D4, 0xAC58, 0x67D8, 0xCF43, 0x67D9, 0xAC6A, 0x67DA, 0xAC63, 0x67DB, 0xCF5D, 0x67DC, 0xCF40, 0x67DD, 0xAC6C, 0x67DE, 0xAC67, 0x67DF, 0xCF49, 0x67E2, 0xAC6B, 0x67E3, 0xCF50, 0x67E4, 0xCF48, 0x67E5, 0xAC64, 0x67E6, 0xCF5C, 0x67E7, 0xCF54, 0x67E9, 0xAC5E, 0x67EA, 0xCF62, 0x67EB, 0xCF47, 0x67EC, 0xAC5A, 0x67ED, 0xCF59, 0x67EE, 0xCF4F, 0x67EF, 0xAC5F, 0x67F0, 0xCF55, 0x67F1, 0xAC57, 0x67F2, 0xCEFC, 0x67F3, 0xAC68, 0x67F4, 0xAEE3, 0x67F5, 0xAC5D, 0x67F6, 0xCF4E, 0x67F7, 0xCF4D, 0x67F8, 0xCF42, 0x67FA, 0xCF5E, 0x67FC, 0xCF57, 0x67FF, 0xAC55, 0x6812, 0xD1EC, 0x6813, 0xAEEA, 0x6814, 0xD1ED, 0x6816, 0xD1E1, 0x6817, 0xAEDF, 0x6818, 0xAEEB, 0x681A, 0xD1DA, 0x681C, 0xD1E3, 0x681D, 0xD1EB, 0x681F, 0xD1D9, 0x6820, 0xD1F4, 0x6821, 0xAED5, 0x6825, 0xD1F3, 0x6826, 0xD1EE, 0x6828, 0xD1EF, 0x6829, 0xAEDD, 0x682A, 0xAEE8, 0x682B, 0xD1E5, 0x682D, 0xD1E6, 0x682E, 0xD1F0, 0x682F, 0xD1E7, 0x6831, 0xD1E2, 0x6832, 0xD1DC, 0x6833, 0xD1DD, 0x6834, 0xD1EA, 0x6835, 0xD1E4, 0x6838, 0xAED6, 0x6839, 0xAEDA, 0x683A, 0xD1F2, 0x683B, 0xD1DE, 0x683C, 0xAEE6, 0x683D, 0xAEE2, 0x6840, 0xAEE5, 0x6841, 0xAEEC, 0x6842, 0xAEDB, 0x6843, 0xAEE7, 0x6844, 0xD1E9, 0x6845, 0xAEE9, 0x6846, 0xAED8, 0x6848, 0xAED7, 0x6849, 0xD1DB, 0x684B, 0xD1DF, 0x684C, 0xAEE0, 0x684D, 0xD1F1, 0x684E, 0xD1E8, 0x684F, 0xD1E0, 0x6850, 0xAEE4, 0x6851, 0xAEE1, 0x6853, 0xAED9, 0x6854, 0xAEDC, 0x686B, 0xD5C4, 0x686D, 0xD5B4, 0x686E, 0xD5B5, 0x686F, 0xD5B9, 0x6871, 0xD5C8, 0x6872, 0xD5C5, 0x6874, 0xD5BE, 0x6875, 0xD5BD, 0x6876, 0xB1ED, 0x6877, 0xD5C1, 0x6878, 0xD5D0, 0x6879, 0xD5B0, 0x687B, 0xD5D1, 0x687C, 0xD5C3, 0x687D, 0xD5D5, 0x687E, 0xD5C9, 0x687F, 0xB1EC, 0x6880, 0xD5C7, 0x6881, 0xB1E7, 0x6882, 0xB1FC, 0x6883, 0xB1F2, 0x6885, 0xB1F6, 0x6886, 0xB1F5, 0x6887, 0xD5B1, 0x6889, 0xD5CE, 0x688A, 0xD5D4, 0x688B, 0xD5CC, 0x688C, 0xD5D3, 0x688F, 0xD5C0, 0x6890, 0xD5B2, 0x6891, 0xD5D2, 0x6892, 0xD5C2, 0x6893, 0xB1EA, 0x6894, 0xB1F7, 0x6896, 0xD5CB, 0x6897, 0xB1F0, 0x689B, 0xD5CA, 0x689C, 0xD5B3, 0x689D, 0xB1F8, 0x689F, 0xB1FA, 0x68A0, 0xD5CD, 0x68A1, 0xB1FB, 0x68A2, 0xB1E9, 0x68A3, 0xD5BA, 0x68A4, 0xD5CF, 0x68A7, 0xB1EF, 0x68A8, 0xB1F9, 0x68A9, 0xD5BC, 0x68AA, 0xD5C6, 0x68AB, 0xD5B7, 0x68AC, 0xD5BB, 0x68AD, 0xB1F4, 0x68AE, 0xD5B6, 0x68AF, 0xB1E8, 0x68B0, 0xB1F1, 0x68B1, 0xB1EE, 0x68B2, 0xD5BF, 0x68B3, 0xAEDE, 0x68B4, 0xD9C0, 0x68B5, 0xB1EB, 0x68C4, 0xB1F3, 0x68C6, 0xD9C3, 0x68C7, 0xD9D9, 0x68C8, 0xD9CE, 0x68C9, 0xB4D6, 0x68CB, 0xB4D1, 0x68CC, 0xD9BD, 0x68CD, 0xB4D2, 0x68CE, 0xD9CD, 0x68D0, 0xD9C6, 0x68D1, 0xD9D3, 0x68D2, 0xB4CE, 0x68D3, 0xD9AB, 0x68D4, 0xD9D5, 0x68D5, 0xB4C4, 0x68D6, 0xD9B3, 0x68D7, 0xB4C7, 0x68D8, 0xB4C6, 0x68DA, 0xB4D7, 0x68DC, 0xD9AD, 0x68DD, 0xD9CF, 0x68DE, 0xD9D0, 0x68DF, 0xB4C9, 0x68E0, 0xB4C5, 0x68E1, 0xD9BB, 0x68E3, 0xB4D0, 0x68E4, 0xD9B6, 0x68E6, 0xD9D1, 0x68E7, 0xB4CC, 0x68E8, 0xD9C9, 0x68E9, 0xD9D6, 0x68EA, 0xD9B0, 0x68EB, 0xD9B5, 0x68EC, 0xD9AF, 0x68EE, 0xB4CB, 0x68EF, 0xD9C2, 0x68F0, 0xDDDE, 0x68F1, 0xD9B1, 0x68F2, 0xB4CF, 0x68F3, 0xD9BA, 0x68F4, 0xD9D2, 0x68F5, 0xB4CA, 0x68F6, 0xD9B7, 0x68F7, 0xD9B4, 0x68F8, 0xD9C5, 0x68F9, 0xB4CD, 0x68FA, 0xB4C3, 0x68FB, 0xB4D9, 0x68FC, 0xD9C8, 0x68FD, 0xD9C7, 0x6904, 0xD9AC, 0x6905, 0xB4C8, 0x6906, 0xD9D4, 0x6907, 0xD9BC, 0x6908, 0xD9BE, 0x690A, 0xD9CB, 0x690B, 0xD9CA, 0x690C, 0xD9AA, 0x690D, 0xB4D3, 0x690E, 0xB4D5, 0x690F, 0xD9B2, 0x6910, 0xD9B9, 0x6911, 0xD9C1, 0x6912, 0xB4D4, 0x6913, 0xD9B8, 0x6914, 0xD9C4, 0x6915, 0xD9D7, 0x6917, 0xD9CC, 0x6925, 0xD9D8, 0x692A, 0xD9AE, 0x692F, 0xDDF2, 0x6930, 0xB7A6, 0x6932, 0xDDF0, 0x6933, 0xDDDB, 0x6934, 0xDDE0, 0x6935, 0xDDD9, 0x6937, 0xDDEC, 0x6938, 0xDDCB, 0x6939, 0xDDD2, 0x693B, 0xDDEA, 0x693C, 0xDDF4, 0x693D, 0xDDDC, 0x693F, 0xDDCF, 0x6940, 0xDDE2, 0x6941, 0xDDE7, 0x6942, 0xDDD3, 0x6944, 0xDDE4, 0x6945, 0xDDD0, 0x6948, 0xDDD7, 0x6949, 0xDDD8, 0x694A, 0xB7A8, 0x694B, 0xDDEB, 0x694C, 0xDDE9, 0x694E, 0xDDCC, 0x694F, 0xDDEE, 0x6951, 0xDDEF, 0x6952, 0xDDF1, 0x6953, 0xB7AC, 0x6954, 0xB7A4, 0x6956, 0xD5B8, 0x6957, 0xDDD4, 0x6958, 0xDDE6, 0x6959, 0xDDD5, 0x695A, 0xB7A1, 0x695B, 0xB7B1, 0x695C, 0xDDED, 0x695D, 0xB7AF, 0x695E, 0xB7AB, 0x695F, 0xDDCA, 0x6960, 0xB7A3, 0x6962, 0xDDCD, 0x6963, 0xB7B0, 0x6965, 0xDDDD, 0x6966, 0xDDC9, 0x6968, 0xB7A9, 0x6969, 0xDDE1, 0x696A, 0xDDD1, 0x696B, 0xB7AA, 0x696C, 0xDDDA, 0x696D, 0xB77E, 0x696E, 0xB4D8, 0x696F, 0xDDE3, 0x6970, 0xD9BF, 0x6971, 0xDDCE, 0x6974, 0xDDE8, 0x6975, 0xB7A5, 0x6976, 0xDDE5, 0x6977, 0xB7A2, 0x6978, 0xDDDF, 0x6979, 0xB7AD, 0x697A, 0xDDD6, 0x697B, 0xDDF3, 0x6982, 0xB7A7, 0x6983, 0xDEC6, 0x6986, 0xB7AE, 0x698D, 0xE24A, 0x698E, 0xE248, 0x6990, 0xE25E, 0x6991, 0xE246, 0x6993, 0xE258, 0x6994, 0xB77D, 0x6995, 0xBA5F, 0x6996, 0xE242, 0x6997, 0xE25D, 0x6999, 0xE247, 0x699A, 0xE255, 0x699B, 0xBA64, 0x699C, 0xBA5D, 0x699E, 0xE25B, 0x69A0, 0xE240, 0x69A1, 0xE25A, 0x69A3, 0xBA6F, 0x69A4, 0xE251, 0x69A5, 0xE261, 0x69A6, 0xBA6D, 0x69A7, 0xE249, 0x69A8, 0xBA5E, 0x69A9, 0xE24B, 0x69AA, 0xE259, 0x69AB, 0xBA67, 0x69AC, 0xE244, 0x69AD, 0xBA6B, 0x69AE, 0xBA61, 0x69AF, 0xE24D, 0x69B0, 0xE243, 0x69B1, 0xE1FC, 0x69B3, 0xE257, 0x69B4, 0xBA68, 0x69B5, 0xE260, 0x69B6, 0xE1FD, 0x69B7, 0xBA65, 0x69B9, 0xE253, 0x69BB, 0xBA66, 0x69BC, 0xE245, 0x69BD, 0xE250, 0x69BE, 0xE24C, 0x69BF, 0xE24E, 0x69C1, 0xBA60, 0x69C2, 0xE25F, 0x69C3, 0xBA6E, 0x69C4, 0xE24F, 0x69C6, 0xE262, 0x69C9, 0xE1FE, 0x69CA, 0xE254, 0x69CB, 0xBA63, 0x69CC, 0xBA6C, 0x69CD, 0xBA6A, 0x69CE, 0xE241, 0x69CF, 0xE256, 0x69D0, 0xBA69, 0x69D3, 0xBA62, 0x69D4, 0xE252, 0x69D9, 0xE25C, 0x69E2, 0xE5D5, 0x69E4, 0xE5D1, 0x69E5, 0xE5CD, 0x69E6, 0xE5E1, 0x69E7, 0xE5DE, 0x69E8, 0xBCCD, 0x69EB, 0xE5E5, 0x69EC, 0xE5D4, 0x69ED, 0xBCD8, 0x69EE, 0xE5DB, 0x69F1, 0xE5D0, 0x69F2, 0xE5DA, 0x69F3, 0xBCD5, 0x69F4, 0xE5EE, 0x69F6, 0xE5EB, 0x69F7, 0xE5DD, 0x69F8, 0xE5CE, 0x69FB, 0xE5E2, 0x69FC, 0xE5E4, 0x69FD, 0xBCD1, 0x69FE, 0xE5D8, 0x69FF, 0xE5D3, 0x6A00, 0xE5CA, 0x6A01, 0xBCCE, 0x6A02, 0xBCD6, 0x6A04, 0xE5E7, 0x6A05, 0xBCD7, 0x6A06, 0xE5CB, 0x6A07, 0xE5ED, 0x6A08, 0xE5E0, 0x6A09, 0xE5E6, 0x6A0A, 0xBCD4, 0x6A0D, 0xE5E3, 0x6A0F, 0xE5EA, 0x6A11, 0xBCD9, 0x6A13, 0xBCD3, 0x6A14, 0xE5DC, 0x6A15, 0xE5CF, 0x6A16, 0xE5EF, 0x6A17, 0xE5CC, 0x6A18, 0xE5E8, 0x6A19, 0xBCD0, 0x6A1B, 0xE5D6, 0x6A1D, 0xE5D7, 0x6A1E, 0xBCCF, 0x6A1F, 0xBCCC, 0x6A20, 0xE5D2, 0x6A21, 0xBCD2, 0x6A23, 0xBCCB, 0x6A25, 0xE5E9, 0x6A26, 0xE5EC, 0x6A27, 0xE5D9, 0x6A28, 0xE9CA, 0x6A32, 0xE9C2, 0x6A34, 0xE9BE, 0x6A35, 0xBEF6, 0x6A38, 0xBEEB, 0x6A39, 0xBEF0, 0x6A3A, 0xBEEC, 0x6A3B, 0xE9CC, 0x6A3C, 0xE9D7, 0x6A3D, 0xBEEA, 0x6A3E, 0xE9C4, 0x6A3F, 0xE9CD, 0x6A40, 0xE5DF, 0x6A41, 0xE9CE, 0x6A44, 0xBEF1, 0x6A46, 0xE9DD, 0x6A47, 0xBEF5, 0x6A48, 0xBEF8, 0x6A49, 0xE9C0, 0x6A4B, 0xBEF4, 0x6A4D, 0xE9DB, 0x6A4E, 0xE9DC, 0x6A4F, 0xE9D2, 0x6A50, 0xE9D1, 0x6A51, 0xE9C9, 0x6A54, 0xE9D3, 0x6A55, 0xE9DA, 0x6A56, 0xE9D9, 0x6A58, 0xBEEF, 0x6A59, 0xBEED, 0x6A5A, 0xE9CB, 0x6A5B, 0xE9C8, 0x6A5D, 0xE9C5, 0x6A5E, 0xE9D8, 0x6A5F, 0xBEF7, 0x6A60, 0xE9D6, 0x6A61, 0xBEF3, 0x6A62, 0xBEF2, 0x6A64, 0xE9D0, 0x6A66, 0xE9BF, 0x6A67, 0xE9C1, 0x6A68, 0xE9C3, 0x6A69, 0xE9D5, 0x6A6A, 0xE9CF, 0x6A6B, 0xBEEE, 0x6A6D, 0xE9C6, 0x6A6F, 0xE9D4, 0x6A76, 0xE9C7, 0x6A7E, 0xC0CF, 0x6A7F, 0xED45, 0x6A80, 0xC0C8, 0x6A81, 0xECF5, 0x6A83, 0xED41, 0x6A84, 0xC0CA, 0x6A85, 0xED48, 0x6A87, 0xECFC, 0x6A89, 0xECF7, 0x6A8C, 0xED49, 0x6A8D, 0xECF3, 0x6A8E, 0xECFE, 0x6A90, 0xC0D1, 0x6A91, 0xED44, 0x6A92, 0xED4A, 0x6A93, 0xECFD, 0x6A94, 0xC0C9, 0x6A95, 0xED40, 0x6A96, 0xECF4, 0x6A97, 0xC0D0, 0x6A9A, 0xED47, 0x6A9B, 0xECF9, 0x6A9C, 0xC0CC, 0x6A9E, 0xECFB, 0x6A9F, 0xECF8, 0x6AA0, 0xC0D2, 0x6AA1, 0xECFA, 0x6AA2, 0xC0CB, 0x6AA3, 0xC0CE, 0x6AA4, 0xED43, 0x6AA5, 0xECF6, 0x6AA6, 0xED46, 0x6AA8, 0xED42, 0x6AAC, 0xC263, 0x6AAD, 0xEFE7, 0x6AAE, 0xC268, 0x6AAF, 0xC269, 0x6AB3, 0xC262, 0x6AB4, 0xEFE6, 0x6AB6, 0xEFE3, 0x6AB7, 0xEFE4, 0x6AB8, 0xC266, 0x6AB9, 0xEFDE, 0x6ABA, 0xEFE2, 0x6ABB, 0xC265, 0x6ABD, 0xEFDF, 0x6AC2, 0xC267, 0x6AC3, 0xC264, 0x6AC5, 0xEFDD, 0x6AC6, 0xEFE1, 0x6AC7, 0xEFE5, 0x6ACB, 0xF251, 0x6ACC, 0xF24E, 0x6ACD, 0xF257, 0x6ACF, 0xF256, 0x6AD0, 0xF254, 0x6AD1, 0xF24F, 0x6AD3, 0xC372, 0x6AD9, 0xF250, 0x6ADA, 0xC371, 0x6ADB, 0xC0CD, 0x6ADC, 0xF253, 0x6ADD, 0xC370, 0x6ADE, 0xF258, 0x6ADF, 0xF252, 0x6AE0, 0xF24D, 0x6AE1, 0xEFE0, 0x6AE5, 0xC36F, 0x6AE7, 0xF24C, 0x6AE8, 0xF456, 0x6AEA, 0xF455, 0x6AEB, 0xF255, 0x6AEC, 0xC468, 0x6AEE, 0xF459, 0x6AEF, 0xF45A, 0x6AF0, 0xF454, 0x6AF1, 0xF458, 0x6AF3, 0xF453, 0x6AF8, 0xF5D1, 0x6AF9, 0xF457, 0x6AFA, 0xC4E7, 0x6AFB, 0xC4E5, 0x6AFC, 0xF5CF, 0x6B00, 0xF5D2, 0x6B02, 0xF5CE, 0x6B03, 0xF5D0, 0x6B04, 0xC4E6, 0x6B08, 0xF6E5, 0x6B09, 0xF6E6, 0x6B0A, 0xC576, 0x6B0B, 0xF6E4, 0x6B0F, 0xF7E2, 0x6B10, 0xC5CF, 0x6B11, 0xF7E0, 0x6B12, 0xF7E1, 0x6B13, 0xF8AC, 0x6B16, 0xC656, 0x6B17, 0xF8F3, 0x6B18, 0xF8F1, 0x6B19, 0xF8F2, 0x6B1A, 0xF8F4, 0x6B1E, 0xF9BB, 0x6B20, 0xA4ED, 0x6B21, 0xA6B8, 0x6B23, 0xAA59, 0x6B25, 0xCCE9, 0x6B28, 0xCF64, 0x6B2C, 0xD1F5, 0x6B2D, 0xD1F7, 0x6B2F, 0xD1F6, 0x6B31, 0xD1F8, 0x6B32, 0xB1FD, 0x6B33, 0xD5D7, 0x6B34, 0xD1F9, 0x6B36, 0xD5D6, 0x6B37, 0xD5D8, 0x6B38, 0xD5D9, 0x6B39, 0xD9DA, 0x6B3A, 0xB4DB, 0x6B3B, 0xD9DB, 0x6B3C, 0xD9DD, 0x6B3D, 0xB4DC, 0x6B3E, 0xB4DA, 0x6B3F, 0xD9DC, 0x6B41, 0xDDFA, 0x6B42, 0xDDF8, 0x6B43, 0xDDF7, 0x6B45, 0xDDF6, 0x6B46, 0xDDF5, 0x6B47, 0xB7B2, 0x6B48, 0xDDF9, 0x6B49, 0xBA70, 0x6B4A, 0xE263, 0x6B4B, 0xE265, 0x6B4C, 0xBA71, 0x6B4D, 0xE264, 0x6B4E, 0xBCDB, 0x6B50, 0xBCDA, 0x6B51, 0xE5F0, 0x6B54, 0xE9DF, 0x6B55, 0xE9DE, 0x6B56, 0xE9E0, 0x6B59, 0xBEF9, 0x6B5B, 0xED4B, 0x6B5C, 0xC0D3, 0x6B5E, 0xEFE8, 0x6B5F, 0xC26A, 0x6B60, 0xF259, 0x6B61, 0xC577, 0x6B62, 0xA4EE, 0x6B63, 0xA5BF, 0x6B64, 0xA6B9, 0x6B65, 0xA842, 0x6B66, 0xAA5A, 0x6B67, 0xAA5B, 0x6B6A, 0xAC6E, 0x6B6D, 0xD1FA, 0x6B72, 0xB7B3, 0x6B76, 0xE6D1, 0x6B77, 0xBEFA, 0x6B78, 0xC26B, 0x6B79, 0xA4EF, 0x6B7B, 0xA6BA, 0x6B7E, 0xCCEB, 0x6B7F, 0xAA5C, 0x6B80, 0xCCEA, 0x6B82, 0xCF65, 0x6B83, 0xAC6F, 0x6B84, 0xCF66, 0x6B86, 0xAC70, 0x6B88, 0xD1FC, 0x6B89, 0xAEEE, 0x6B8A, 0xAEED, 0x6B8C, 0xD5DE, 0x6B8D, 0xD5DC, 0x6B8E, 0xD5DD, 0x6B8F, 0xD5DB, 0x6B91, 0xD5DA, 0x6B94, 0xD9DE, 0x6B95, 0xD9E1, 0x6B96, 0xB4DE, 0x6B97, 0xD9DF, 0x6B98, 0xB4DD, 0x6B99, 0xD9E0, 0x6B9B, 0xDDFB, 0x6B9E, 0xE266, 0x6B9F, 0xE267, 0x6BA0, 0xE268, 0x6BA2, 0xE5F3, 0x6BA3, 0xE5F2, 0x6BA4, 0xBCDC, 0x6BA5, 0xE5F1, 0x6BA6, 0xE5F4, 0x6BA7, 0xE9E1, 0x6BAA, 0xE9E2, 0x6BAB, 0xE9E3, 0x6BAD, 0xED4C, 0x6BAE, 0xC0D4, 0x6BAF, 0xC26C, 0x6BB0, 0xF25A, 0x6BB2, 0xC4E8, 0x6BB3, 0xC95F, 0x6BB5, 0xAC71, 0x6BB6, 0xCF67, 0x6BB7, 0xAEEF, 0x6BBA, 0xB1FE, 0x6BBC, 0xB4DF, 0x6BBD, 0xD9E2, 0x6BBF, 0xB7B5, 0x6BC0, 0xB7B4, 0x6BC3, 0xE269, 0x6BC4, 0xE26A, 0x6BC5, 0xBCDD, 0x6BC6, 0xBCDE, 0x6BC7, 0xE9E5, 0x6BC8, 0xE9E4, 0x6BC9, 0xEFE9, 0x6BCA, 0xF7E3, 0x6BCB, 0xA4F0, 0x6BCC, 0xC960, 0x6BCD, 0xA5C0, 0x6BCF, 0xA843, 0x6BD0, 0xCB48, 0x6BD2, 0xAC72, 0x6BD3, 0xB7B6, 0x6BD4, 0xA4F1, 0x6BD6, 0xCF68, 0x6BD7, 0xAC73, 0x6BD8, 0xCF69, 0x6BDA, 0xC0D5, 0x6BDB, 0xA4F2, 0x6BDE, 0xCCEC, 0x6BE0, 0xCF6A, 0x6BE2, 0xD242, 0x6BE3, 0xD241, 0x6BE4, 0xD1FE, 0x6BE6, 0xD1FD, 0x6BE7, 0xD243, 0x6BE8, 0xD240, 0x6BEB, 0xB240, 0x6BEC, 0xB241, 0x6BEF, 0xB4E0, 0x6BF0, 0xD9E3, 0x6BF2, 0xD9E4, 0x6BF3, 0xD9E5, 0x6BF7, 0xDE41, 0x6BF8, 0xDE42, 0x6BF9, 0xDE40, 0x6BFB, 0xDDFD, 0x6BFC, 0xDDFE, 0x6BFD, 0xB7B7, 0x6BFE, 0xE26B, 0x6BFF, 0xE5F7, 0x6C00, 0xE5F6, 0x6C01, 0xE5F5, 0x6C02, 0xE5F8, 0x6C03, 0xE9E7, 0x6C04, 0xE9E6, 0x6C05, 0xBEFB, 0x6C06, 0xE9E8, 0x6C08, 0xC0D6, 0x6C09, 0xED4D, 0x6C0B, 0xEFEA, 0x6C0C, 0xF25B, 0x6C0D, 0xF6E7, 0x6C0F, 0xA4F3, 0x6C10, 0xA5C2, 0x6C11, 0xA5C1, 0x6C13, 0xAA5D, 0x6C14, 0xC961, 0x6C15, 0xC97E, 0x6C16, 0xA6BB, 0x6C18, 0xC9F7, 0x6C19, 0xCB49, 0x6C1A, 0xCB4A, 0x6C1B, 0xAA5E, 0x6C1D, 0xCCED, 0x6C1F, 0xAC74, 0x6C20, 0xCF6B, 0x6C21, 0xCF6C, 0x6C23, 0xAEF0, 0x6C24, 0xAEF4, 0x6C25, 0xD244, 0x6C26, 0xAEF3, 0x6C27, 0xAEF1, 0x6C28, 0xAEF2, 0x6C2A, 0xD5DF, 0x6C2B, 0xB242, 0x6C2C, 0xB4E3, 0x6C2E, 0xB4E1, 0x6C2F, 0xB4E2, 0x6C30, 0xD9E6, 0x6C33, 0xBA72, 0x6C34, 0xA4F4, 0x6C36, 0xC9A1, 0x6C38, 0xA5C3, 0x6C3B, 0xC9A4, 0x6C3E, 0xA5C6, 0x6C3F, 0xC9A3, 0x6C40, 0xA5C5, 0x6C41, 0xA5C4, 0x6C42, 0xA844, 0x6C43, 0xC9A2, 0x6C46, 0xC9F8, 0x6C4A, 0xC9FC, 0x6C4B, 0xC9FE, 0x6C4C, 0xCA40, 0x6C4D, 0xA6C5, 0x6C4E, 0xA6C6, 0x6C4F, 0xC9FB, 0x6C50, 0xA6C1, 0x6C52, 0xC9F9, 0x6C54, 0xC9FD, 0x6C55, 0xA6C2, 0x6C57, 0xA6BD, 0x6C59, 0xA6BE, 0x6C5B, 0xA6C4, 0x6C5C, 0xC9FA, 0x6C5D, 0xA6BC, 0x6C5E, 0xA845, 0x6C5F, 0xA6BF, 0x6C60, 0xA6C0, 0x6C61, 0xA6C3, 0x6C65, 0xCB5B, 0x6C66, 0xCB59, 0x6C67, 0xCB4C, 0x6C68, 0xA851, 0x6C69, 0xCB53, 0x6C6A, 0xA84C, 0x6C6B, 0xCB4D, 0x6C6D, 0xCB55, 0x6C6F, 0xCB52, 0x6C70, 0xA84F, 0x6C71, 0xCB51, 0x6C72, 0xA856, 0x6C73, 0xCB5A, 0x6C74, 0xA858, 0x6C76, 0xA85A, 0x6C78, 0xCB4B, 0x6C7A, 0xA84D, 0x6C7B, 0xCB5C, 0x6C7D, 0xA854, 0x6C7E, 0xA857, 0x6C80, 0xCD45, 0x6C81, 0xA847, 0x6C82, 0xA85E, 0x6C83, 0xA855, 0x6C84, 0xCB4E, 0x6C85, 0xA84A, 0x6C86, 0xA859, 0x6C87, 0xCB56, 0x6C88, 0xA848, 0x6C89, 0xA849, 0x6C8A, 0xCD43, 0x6C8B, 0xCB4F, 0x6C8C, 0xA850, 0x6C8D, 0xA85B, 0x6C8E, 0xCB5D, 0x6C8F, 0xCB50, 0x6C90, 0xA84E, 0x6C92, 0xA853, 0x6C93, 0xCCEE, 0x6C94, 0xA85C, 0x6C95, 0xCB57, 0x6C96, 0xA852, 0x6C98, 0xA85D, 0x6C99, 0xA846, 0x6C9A, 0xCB54, 0x6C9B, 0xA84B, 0x6C9C, 0xCB58, 0x6C9D, 0xCD44, 0x6CAB, 0xAA6A, 0x6CAC, 0xAA7A, 0x6CAD, 0xCCF5, 0x6CAE, 0xAA71, 0x6CB0, 0xCD4B, 0x6CB1, 0xAA62, 0x6CB3, 0xAA65, 0x6CB4, 0xCD42, 0x6CB6, 0xCCF3, 0x6CB7, 0xCCF7, 0x6CB8, 0xAA6D, 0x6CB9, 0xAA6F, 0x6CBA, 0xCCFA, 0x6CBB, 0xAA76, 0x6CBC, 0xAA68, 0x6CBD, 0xAA66, 0x6CBE, 0xAA67, 0x6CBF, 0xAA75, 0x6CC0, 0xCD47, 0x6CC1, 0xAA70, 0x6CC2, 0xCCF9, 0x6CC3, 0xCCFB, 0x6CC4, 0xAA6E, 0x6CC5, 0xAA73, 0x6CC6, 0xCCFC, 0x6CC7, 0xCD4A, 0x6CC9, 0xAC75, 0x6CCA, 0xAA79, 0x6CCC, 0xAA63, 0x6CCD, 0xCD49, 0x6CCF, 0xCD4D, 0x6CD0, 0xCCF8, 0x6CD1, 0xCD4F, 0x6CD2, 0xCD40, 0x6CD3, 0xAA6C, 0x6CD4, 0xCCF4, 0x6CD5, 0xAA6B, 0x6CD6, 0xAA7D, 0x6CD7, 0xAA72, 0x6CD9, 0xCCF2, 0x6CDA, 0xCF75, 0x6CDB, 0xAA78, 0x6CDC, 0xAA7C, 0x6CDD, 0xCD41, 0x6CDE, 0xCD46, 0x6CE0, 0xAA7E, 0x6CE1, 0xAA77, 0x6CE2, 0xAA69, 0x6CE3, 0xAA5F, 0x6CE5, 0xAA64, 0x6CE7, 0xCCF6, 0x6CE8, 0xAA60, 0x6CE9, 0xCD4E, 0x6CEB, 0xCCF0, 0x6CEC, 0xCCEF, 0x6CED, 0xCCFD, 0x6CEE, 0xCCF1, 0x6CEF, 0xAA7B, 0x6CF0, 0xAEF5, 0x6CF1, 0xAA74, 0x6CF2, 0xCCFE, 0x6CF3, 0xAA61, 0x6CF5, 0xACA6, 0x6CF9, 0xCD4C, 0x6D00, 0xCF7C, 0x6D01, 0xCFA1, 0x6D03, 0xCFA4, 0x6D04, 0xCF77, 0x6D07, 0xCFA7, 0x6D08, 0xCFAA, 0x6D09, 0xCFAC, 0x6D0A, 0xCF74, 0x6D0B, 0xAC76, 0x6D0C, 0xAC7B, 0x6D0D, 0xD249, 0x6D0E, 0xACAD, 0x6D0F, 0xCFA5, 0x6D10, 0xCFAD, 0x6D11, 0xCF7B, 0x6D12, 0xCF73, 0x6D16, 0xD264, 0x6D17, 0xAC7E, 0x6D18, 0xCFA2, 0x6D19, 0xCF78, 0x6D1A, 0xCF7A, 0x6D1B, 0xACA5, 0x6D1D, 0xCF7D, 0x6D1E, 0xAC7D, 0x6D1F, 0xCF70, 0x6D20, 0xCFA8, 0x6D22, 0xCFAB, 0x6D25, 0xAC7A, 0x6D27, 0xACA8, 0x6D28, 0xCF6D, 0x6D29, 0xACAA, 0x6D2A, 0xAC78, 0x6D2B, 0xACAE, 0x6D2C, 0xCFA9, 0x6D2D, 0xCF6F, 0x6D2E, 0xACAB, 0x6D2F, 0xD25E, 0x6D30, 0xCD48, 0x6D31, 0xAC7C, 0x6D32, 0xAC77, 0x6D33, 0xCF76, 0x6D34, 0xCF6E, 0x6D35, 0xACAC, 0x6D36, 0xACA4, 0x6D37, 0xCFA3, 0x6D38, 0xACA9, 0x6D39, 0xACA7, 0x6D3A, 0xCF79, 0x6D3B, 0xACA1, 0x6D3C, 0xCF71, 0x6D3D, 0xACA2, 0x6D3E, 0xACA3, 0x6D3F, 0xCF72, 0x6D40, 0xCFA6, 0x6D41, 0xAC79, 0x6D42, 0xCF7E, 0x6D58, 0xD24C, 0x6D59, 0xAEFD, 0x6D5A, 0xAF43, 0x6D5E, 0xD255, 0x6D5F, 0xD25B, 0x6D60, 0xD257, 0x6D61, 0xD24A, 0x6D62, 0xD24D, 0x6D63, 0xD246, 0x6D64, 0xD247, 0x6D65, 0xAF4A, 0x6D66, 0xAEFA, 0x6D67, 0xD256, 0x6D68, 0xD25F, 0x6D69, 0xAF45, 0x6D6A, 0xAEF6, 0x6D6C, 0xAF40, 0x6D6D, 0xD24E, 0x6D6E, 0xAF42, 0x6D6F, 0xD24F, 0x6D70, 0xD259, 0x6D74, 0xAF44, 0x6D75, 0xD268, 0x6D76, 0xD248, 0x6D77, 0xAEFC, 0x6D78, 0xAEFB, 0x6D79, 0xAF48, 0x6D7A, 0xD245, 0x6D7B, 0xD266, 0x6D7C, 0xD25A, 0x6D7D, 0xD267, 0x6D7E, 0xD261, 0x6D7F, 0xD253, 0x6D80, 0xD262, 0x6D82, 0xD25C, 0x6D83, 0xD265, 0x6D84, 0xD263, 0x6D85, 0xAF49, 0x6D86, 0xD254, 0x6D87, 0xAEF9, 0x6D88, 0xAEF8, 0x6D89, 0xAF41, 0x6D8A, 0xAF47, 0x6D8B, 0xD260, 0x6D8C, 0xAF46, 0x6D8D, 0xD251, 0x6D8E, 0xB243, 0x6D90, 0xD269, 0x6D91, 0xD250, 0x6D92, 0xD24B, 0x6D93, 0xAEFE, 0x6D94, 0xAF4B, 0x6D95, 0xAEF7, 0x6D97, 0xD258, 0x6D98, 0xD25D, 0x6DAA, 0xB265, 0x6DAB, 0xD5E1, 0x6DAC, 0xD5E5, 0x6DAE, 0xB252, 0x6DAF, 0xB250, 0x6DB2, 0xB247, 0x6DB3, 0xD5E3, 0x6DB4, 0xD5E2, 0x6DB5, 0xB25B, 0x6DB7, 0xD5E8, 0x6DB8, 0xB255, 0x6DBA, 0xD5FA, 0x6DBB, 0xD647, 0x6DBC, 0xB244, 0x6DBD, 0xD5F7, 0x6DBE, 0xD5F0, 0x6DBF, 0xB267, 0x6DC0, 0xD5E0, 0x6DC2, 0xD5FC, 0x6DC4, 0xB264, 0x6DC5, 0xB258, 0x6DC6, 0xB263, 0x6DC7, 0xB24E, 0x6DC8, 0xD5EC, 0x6DC9, 0xD5FE, 0x6DCA, 0xD5F6, 0x6DCB, 0xB24F, 0x6DCC, 0xB249, 0x6DCD, 0xD645, 0x6DCF, 0xD5FD, 0x6DD0, 0xD640, 0x6DD1, 0xB251, 0x6DD2, 0xB259, 0x6DD3, 0xD642, 0x6DD4, 0xD5EA, 0x6DD5, 0xD5FB, 0x6DD6, 0xD5EF, 0x6DD7, 0xD644, 0x6DD8, 0xB25E, 0x6DD9, 0xB246, 0x6DDA, 0xB25C, 0x6DDB, 0xD5F4, 0x6DDC, 0xD5F2, 0x6DDD, 0xD5F3, 0x6DDE, 0xB253, 0x6DDF, 0xD5EE, 0x6DE0, 0xD5ED, 0x6DE1, 0xB248, 0x6DE2, 0xD5E7, 0x6DE3, 0xD646, 0x6DE4, 0xB24A, 0x6DE5, 0xD5F1, 0x6DE6, 0xB268, 0x6DE8, 0xB262, 0x6DE9, 0xD5E6, 0x6DEA, 0xB25F, 0x6DEB, 0xB25D, 0x6DEC, 0xB266, 0x6DED, 0xD5F8, 0x6DEE, 0xB261, 0x6DEF, 0xD252, 0x6DF0, 0xD5F9, 0x6DF1, 0xB260, 0x6DF2, 0xD641, 0x6DF3, 0xB245, 0x6DF4, 0xD5F5, 0x6DF5, 0xB257, 0x6DF6, 0xD5E9, 0x6DF7, 0xB256, 0x6DF9, 0xB254, 0x6DFA, 0xB24C, 0x6DFB, 0xB24B, 0x6DFC, 0xD9E7, 0x6DFD, 0xD643, 0x6E00, 0xD5EB, 0x6E03, 0xD9FC, 0x6E05, 0xB24D, 0x6E19, 0xB541, 0x6E1A, 0xB25A, 0x6E1B, 0xB4EE, 0x6E1C, 0xD9F6, 0x6E1D, 0xB4FC, 0x6E1F, 0xD9EA, 0x6E20, 0xB4EB, 0x6E21, 0xB4E7, 0x6E22, 0xDA49, 0x6E23, 0xB4ED, 0x6E24, 0xB4F1, 0x6E25, 0xB4EC, 0x6E26, 0xB4F5, 0x6E27, 0xDA4D, 0x6E28, 0xDA44, 0x6E2B, 0xD9F1, 0x6E2C, 0xB4FA, 0x6E2D, 0xB4F4, 0x6E2E, 0xD9FD, 0x6E2F, 0xB4E4, 0x6E30, 0xDA4A, 0x6E31, 0xDA43, 0x6E32, 0xB4E8, 0x6E33, 0xD9F7, 0x6E34, 0xB4F7, 0x6E35, 0xDA55, 0x6E36, 0xDA56, 0x6E38, 0xB4E5, 0x6E39, 0xDA48, 0x6E3A, 0xB4F9, 0x6E3B, 0xD9FB, 0x6E3C, 0xD9ED, 0x6E3D, 0xD9EE, 0x6E3E, 0xB4FD, 0x6E3F, 0xD9F2, 0x6E40, 0xD9F9, 0x6E41, 0xD9F3, 0x6E43, 0xB4FB, 0x6E44, 0xB544, 0x6E45, 0xD9EF, 0x6E46, 0xD9E8, 0x6E47, 0xD9E9, 0x6E49, 0xD9EB, 0x6E4A, 0xB4EA, 0x6E4B, 0xD9F8, 0x6E4D, 0xB4F8, 0x6E4E, 0xB542, 0x6E51, 0xD9FA, 0x6E52, 0xDA53, 0x6E53, 0xDA4B, 0x6E54, 0xB4E6, 0x6E55, 0xDA51, 0x6E56, 0xB4F2, 0x6E58, 0xB4F0, 0x6E5A, 0xDA57, 0x6E5B, 0xB4EF, 0x6E5C, 0xDA41, 0x6E5D, 0xD9F4, 0x6E5E, 0xD9FE, 0x6E5F, 0xB547, 0x6E60, 0xDA45, 0x6E61, 0xDA42, 0x6E62, 0xD9F0, 0x6E63, 0xB543, 0x6E64, 0xDA4F, 0x6E65, 0xDA4C, 0x6E66, 0xDA54, 0x6E67, 0xB4E9, 0x6E68, 0xDA40, 0x6E69, 0xB546, 0x6E6B, 0xDA47, 0x6E6E, 0xB4F3, 0x6E6F, 0xB4F6, 0x6E71, 0xDA46, 0x6E72, 0xB545, 0x6E73, 0xD9F5, 0x6E74, 0xD5E4, 0x6E77, 0xDA50, 0x6E78, 0xDA4E, 0x6E79, 0xDA52, 0x6E88, 0xD9EC, 0x6E89, 0xB540, 0x6E8D, 0xDE61, 0x6E8E, 0xDE60, 0x6E8F, 0xDE46, 0x6E90, 0xB7BD, 0x6E92, 0xDE5F, 0x6E93, 0xDE49, 0x6E94, 0xDE4A, 0x6E96, 0xB7C7, 0x6E97, 0xDE68, 0x6E98, 0xB7C2, 0x6E99, 0xDE5E, 0x6E9B, 0xDE43, 0x6E9C, 0xB7C8, 0x6E9D, 0xB7BE, 0x6E9E, 0xDE52, 0x6E9F, 0xDE48, 0x6EA0, 0xDE4B, 0x6EA1, 0xDE63, 0x6EA2, 0xB7B8, 0x6EA3, 0xDE6A, 0x6EA4, 0xDE62, 0x6EA5, 0xB7C1, 0x6EA6, 0xDE57, 0x6EA7, 0xB7CC, 0x6EAA, 0xB7CB, 0x6EAB, 0xB7C5, 0x6EAE, 0xDE69, 0x6EAF, 0xB7B9, 0x6EB0, 0xDE55, 0x6EB1, 0xDE4C, 0x6EB2, 0xDE59, 0x6EB3, 0xDE65, 0x6EB4, 0xB7CD, 0x6EB6, 0xB7BB, 0x6EB7, 0xDE54, 0x6EB9, 0xDE4D, 0x6EBA, 0xB7C4, 0x6EBC, 0xB7C3, 0x6EBD, 0xDE50, 0x6EBE, 0xDE5A, 0x6EBF, 0xDE64, 0x6EC0, 0xDE47, 0x6EC1, 0xDE51, 0x6EC2, 0xB7BC, 0x6EC3, 0xDE5B, 0x6EC4, 0xB7C9, 0x6EC5, 0xB7C0, 0x6EC6, 0xDE4E, 0x6EC7, 0xB7BF, 0x6EC8, 0xDE45, 0x6EC9, 0xDE53, 0x6ECA, 0xDE67, 0x6ECB, 0xB4FE, 0x6ECC, 0xBAB0, 0x6ECD, 0xDE56, 0x6ECE, 0xE26C, 0x6ECF, 0xDE58, 0x6ED0, 0xDE66, 0x6ED1, 0xB7C6, 0x6ED2, 0xDE4F, 0x6ED3, 0xB7BA, 0x6ED4, 0xB7CA, 0x6ED5, 0xBCF0, 0x6ED6, 0xDE44, 0x6ED8, 0xDE5D, 0x6EDC, 0xDE5C, 0x6EEB, 0xE2AA, 0x6EEC, 0xBAAD, 0x6EED, 0xE27D, 0x6EEE, 0xE2A4, 0x6EEF, 0xBAA2, 0x6EF1, 0xE26E, 0x6EF2, 0xBAAF, 0x6EF4, 0xBA77, 0x6EF5, 0xE26D, 0x6EF6, 0xE2B0, 0x6EF7, 0xBAB1, 0x6EF8, 0xE271, 0x6EF9, 0xE2A3, 0x6EFB, 0xE273, 0x6EFC, 0xE2B3, 0x6EFD, 0xE2AF, 0x6EFE, 0xBA75, 0x6EFF, 0xBAA1, 0x6F00, 0xE653, 0x6F01, 0xBAAE, 0x6F02, 0xBA7D, 0x6F03, 0xE26F, 0x6F05, 0xE2AE, 0x6F06, 0xBAA3, 0x6F07, 0xE2AB, 0x6F08, 0xE2B8, 0x6F09, 0xE275, 0x6F0A, 0xE27E, 0x6F0D, 0xE2B6, 0x6F0E, 0xE2AC, 0x6F0F, 0xBA7C, 0x6F12, 0xE27C, 0x6F13, 0xBA76, 0x6F14, 0xBA74, 0x6F15, 0xBAA8, 0x6F18, 0xE27A, 0x6F19, 0xE277, 0x6F1A, 0xE278, 0x6F1C, 0xE2B2, 0x6F1E, 0xE2B7, 0x6F1F, 0xE2B5, 0x6F20, 0xBA7A, 0x6F21, 0xE2B9, 0x6F22, 0xBA7E, 0x6F23, 0xBAA7, 0x6F25, 0xE270, 0x6F26, 0xE5FA, 0x6F27, 0xE279, 0x6F29, 0xBA78, 0x6F2A, 0xBAAC, 0x6F2B, 0xBAA9, 0x6F2C, 0xBA7B, 0x6F2D, 0xE2A5, 0x6F2E, 0xE274, 0x6F2F, 0xBAAA, 0x6F30, 0xE2A7, 0x6F31, 0xBAA4, 0x6F32, 0xBAA6, 0x6F33, 0xBA73, 0x6F35, 0xE2A9, 0x6F36, 0xE2A1, 0x6F37, 0xE272, 0x6F38, 0xBAA5, 0x6F39, 0xE2B1, 0x6F3A, 0xE2B4, 0x6F3B, 0xE27B, 0x6F3C, 0xE2A8, 0x6F3E, 0xBA79, 0x6F3F, 0xBCDF, 0x6F40, 0xE2A6, 0x6F41, 0xE5F9, 0x6F43, 0xE2AD, 0x6F4E, 0xE276, 0x6F4F, 0xE644, 0x6F50, 0xE64E, 0x6F51, 0xBCE2, 0x6F52, 0xE64D, 0x6F53, 0xE659, 0x6F54, 0xBCE4, 0x6F55, 0xE64B, 0x6F57, 0xE64F, 0x6F58, 0xBCEF, 0x6F5A, 0xE646, 0x6F5B, 0xBCE7, 0x6F5D, 0xE652, 0x6F5E, 0xE9F0, 0x6F5F, 0xBCF3, 0x6F60, 0xBCF2, 0x6F61, 0xE654, 0x6F62, 0xE643, 0x6F63, 0xE65E, 0x6F64, 0xBCED, 0x6F66, 0xBCE3, 0x6F67, 0xE657, 0x6F69, 0xE65B, 0x6F6A, 0xE660, 0x6F6B, 0xE655, 0x6F6C, 0xE649, 0x6F6D, 0xBCE6, 0x6F6E, 0xBCE9, 0x6F6F, 0xBCF1, 0x6F70, 0xBCEC, 0x6F72, 0xE64C, 0x6F73, 0xE2A2, 0x6F76, 0xE648, 0x6F77, 0xE65F, 0x6F78, 0xBCE8, 0x6F7A, 0xBCEB, 0x6F7B, 0xE661, 0x6F7C, 0xBCE0, 0x6F7D, 0xE656, 0x6F7E, 0xE5FB, 0x6F7F, 0xE65C, 0x6F80, 0xC0DF, 0x6F82, 0xE64A, 0x6F84, 0xBCE1, 0x6F85, 0xE645, 0x6F86, 0xBCE5, 0x6F87, 0xE5FC, 0x6F88, 0xBAAB, 0x6F89, 0xE641, 0x6F8B, 0xE65A, 0x6F8C, 0xE642, 0x6F8D, 0xE640, 0x6F8E, 0xBCEA, 0x6F90, 0xE658, 0x6F92, 0xE5FE, 0x6F93, 0xE651, 0x6F94, 0xE650, 0x6F95, 0xE65D, 0x6F96, 0xE647, 0x6F97, 0xBCEE, 0x6F9E, 0xE9F3, 0x6FA0, 0xBF49, 0x6FA1, 0xBEFE, 0x6FA2, 0xEA40, 0x6FA3, 0xE9EB, 0x6FA4, 0xBF41, 0x6FA5, 0xE9F7, 0x6FA6, 0xBF48, 0x6FA7, 0xBF43, 0x6FA8, 0xE9F5, 0x6FA9, 0xED4F, 0x6FAA, 0xE9FB, 0x6FAB, 0xEA42, 0x6FAC, 0xE9FA, 0x6FAD, 0xE9E9, 0x6FAE, 0xE9F8, 0x6FAF, 0xEA44, 0x6FB0, 0xEA46, 0x6FB1, 0xBEFD, 0x6FB2, 0xEA45, 0x6FB3, 0xBF44, 0x6FB4, 0xBF4A, 0x6FB6, 0xBF47, 0x6FB8, 0xE9FE, 0x6FB9, 0xBF46, 0x6FBA, 0xE9F9, 0x6FBC, 0xE9ED, 0x6FBD, 0xE9F2, 0x6FBF, 0xE9FD, 0x6FC0, 0xBF45, 0x6FC1, 0xBF42, 0x6FC2, 0xBEFC, 0x6FC3, 0xBF40, 0x6FC4, 0xE9F1, 0x6FC6, 0xE5FD, 0x6FC7, 0xE9EC, 0x6FC8, 0xE9EF, 0x6FC9, 0xEA41, 0x6FCA, 0xE9F4, 0x6FCB, 0xE9EA, 0x6FCC, 0xED4E, 0x6FCD, 0xEA43, 0x6FCE, 0xE9EE, 0x6FCF, 0xE9FC, 0x6FD4, 0xED51, 0x6FD5, 0xC0E3, 0x6FD8, 0xC0D7, 0x6FDB, 0xC0DB, 0x6FDC, 0xED53, 0x6FDD, 0xED59, 0x6FDE, 0xED57, 0x6FDF, 0xC0D9, 0x6FE0, 0xC0DA, 0x6FE1, 0xC0E1, 0x6FE2, 0xED5A, 0x6FE3, 0xED52, 0x6FE4, 0xC0DC, 0x6FE6, 0xED56, 0x6FE7, 0xED55, 0x6FE8, 0xED5B, 0x6FE9, 0xC0E2, 0x6FEB, 0xC0DD, 0x6FEC, 0xC0E0, 0x6FED, 0xED54, 0x6FEE, 0xC0E4, 0x6FEF, 0xC0DE, 0x6FF0, 0xC0E5, 0x6FF1, 0xC0D8, 0x6FF2, 0xED58, 0x6FF4, 0xED50, 0x6FF7, 0xEFF7, 0x6FFA, 0xC271, 0x6FFB, 0xEFF4, 0x6FFC, 0xEFF6, 0x6FFE, 0xC26F, 0x6FFF, 0xEFF2, 0x7000, 0xEFF3, 0x7001, 0xEFEE, 0x7004, 0xE9F6, 0x7005, 0xEFEF, 0x7006, 0xC270, 0x7007, 0xEFEB, 0x7009, 0xC26D, 0x700A, 0xEFF8, 0x700B, 0xC26E, 0x700C, 0xEFEC, 0x700D, 0xEFED, 0x700E, 0xEFF1, 0x700F, 0xC273, 0x7011, 0xC272, 0x7014, 0xEFF0, 0x7015, 0xC378, 0x7016, 0xF25F, 0x7017, 0xF265, 0x7018, 0xC379, 0x7019, 0xF25C, 0x701A, 0xC376, 0x701B, 0xC373, 0x701C, 0xF267, 0x701D, 0xC377, 0x701F, 0xC374, 0x7020, 0xF25E, 0x7021, 0xF261, 0x7022, 0xF262, 0x7023, 0xF263, 0x7024, 0xF266, 0x7026, 0xEFF5, 0x7027, 0xF25D, 0x7028, 0xC375, 0x7029, 0xF264, 0x702A, 0xF268, 0x702B, 0xF260, 0x702F, 0xF45D, 0x7030, 0xC46A, 0x7031, 0xF460, 0x7032, 0xC46B, 0x7033, 0xF468, 0x7034, 0xF45F, 0x7035, 0xF45C, 0x7037, 0xF45E, 0x7038, 0xF462, 0x7039, 0xF465, 0x703A, 0xF464, 0x703B, 0xF467, 0x703C, 0xF45B, 0x703E, 0xC469, 0x703F, 0xF463, 0x7040, 0xF466, 0x7041, 0xF469, 0x7042, 0xF461, 0x7043, 0xF5D3, 0x7044, 0xF5D4, 0x7045, 0xF5D8, 0x7046, 0xF5D9, 0x7048, 0xF5D6, 0x7049, 0xF5D7, 0x704A, 0xF5D5, 0x704C, 0xC4E9, 0x7051, 0xC578, 0x7052, 0xF6EB, 0x7055, 0xF6E8, 0x7056, 0xF6E9, 0x7057, 0xF6EA, 0x7058, 0xC579, 0x705A, 0xF7E5, 0x705B, 0xF7E4, 0x705D, 0xF8AF, 0x705E, 0xC5F4, 0x705F, 0xF8AD, 0x7060, 0xF8B0, 0x7061, 0xF8AE, 0x7062, 0xF8F5, 0x7063, 0xC657, 0x7064, 0xC665, 0x7065, 0xF9A3, 0x7066, 0xF96C, 0x7068, 0xF9A2, 0x7069, 0xF9D0, 0x706A, 0xF9D1, 0x706B, 0xA4F5, 0x7070, 0xA6C7, 0x7071, 0xCA41, 0x7074, 0xCB5E, 0x7076, 0xA85F, 0x7078, 0xA862, 0x707A, 0xCB5F, 0x707C, 0xA860, 0x707D, 0xA861, 0x7082, 0xCD58, 0x7083, 0xCD5A, 0x7084, 0xCD55, 0x7085, 0xCD52, 0x7086, 0xCD54, 0x708A, 0xAAA4, 0x708E, 0xAAA2, 0x7091, 0xCD56, 0x7092, 0xAAA3, 0x7093, 0xCD53, 0x7094, 0xCD50, 0x7095, 0xAAA1, 0x7096, 0xCD57, 0x7098, 0xCD51, 0x7099, 0xAAA5, 0x709A, 0xCD59, 0x709F, 0xCFAF, 0x70A1, 0xCFB3, 0x70A4, 0xACB7, 0x70A9, 0xCFB6, 0x70AB, 0xACAF, 0x70AC, 0xACB2, 0x70AD, 0xACB4, 0x70AE, 0xACB6, 0x70AF, 0xACB3, 0x70B0, 0xCFB2, 0x70B1, 0xCFB1, 0x70B3, 0xACB1, 0x70B4, 0xCFB4, 0x70B5, 0xCFB5, 0x70B7, 0xCFAE, 0x70B8, 0xACB5, 0x70BA, 0xACB0, 0x70BE, 0xCFB0, 0x70C5, 0xD277, 0x70C6, 0xD278, 0x70C7, 0xD279, 0x70C8, 0xAF50, 0x70CA, 0xAF4C, 0x70CB, 0xD26E, 0x70CD, 0xD276, 0x70CE, 0xD27B, 0x70CF, 0xAF51, 0x70D1, 0xD26C, 0x70D2, 0xD272, 0x70D3, 0xD26B, 0x70D4, 0xD275, 0x70D7, 0xD271, 0x70D8, 0xAF4D, 0x70D9, 0xAF4F, 0x70DA, 0xD27A, 0x70DC, 0xD26A, 0x70DD, 0xD26D, 0x70DE, 0xD273, 0x70E0, 0xD274, 0x70E1, 0xD27C, 0x70E2, 0xD270, 0x70E4, 0xAF4E, 0x70EF, 0xB26D, 0x70F0, 0xD64E, 0x70F3, 0xD650, 0x70F4, 0xD64C, 0x70F6, 0xD658, 0x70F7, 0xD64A, 0x70F8, 0xD657, 0x70F9, 0xB269, 0x70FA, 0xD648, 0x70FB, 0xDA5B, 0x70FC, 0xD652, 0x70FD, 0xB26C, 0x70FF, 0xD653, 0x7100, 0xD656, 0x7102, 0xD65A, 0x7104, 0xD64F, 0x7106, 0xD654, 0x7109, 0xB26A, 0x710A, 0xB26B, 0x710B, 0xD659, 0x710C, 0xD64D, 0x710D, 0xD649, 0x710E, 0xD65B, 0x7110, 0xD651, 0x7113, 0xD655, 0x7117, 0xD64B, 0x7119, 0xB548, 0x711A, 0xB549, 0x711B, 0xDA65, 0x711C, 0xB54F, 0x711E, 0xDA59, 0x711F, 0xDA62, 0x7120, 0xDA58, 0x7121, 0xB54C, 0x7122, 0xDA60, 0x7123, 0xDA5E, 0x7125, 0xDA5F, 0x7126, 0xB54A, 0x7128, 0xDA63, 0x712E, 0xDA5C, 0x712F, 0xDA5A, 0x7130, 0xB54B, 0x7131, 0xDA5D, 0x7132, 0xDA61, 0x7136, 0xB54D, 0x713A, 0xDA64, 0x7141, 0xDE70, 0x7142, 0xDE77, 0x7143, 0xDE79, 0x7144, 0xDEA1, 0x7146, 0xB7DA, 0x7147, 0xDE6B, 0x7149, 0xB7D2, 0x714B, 0xDE7A, 0x714C, 0xB7D7, 0x714D, 0xDEA2, 0x714E, 0xB7CE, 0x7150, 0xDE7D, 0x7152, 0xDE6D, 0x7153, 0xDE7E, 0x7154, 0xDE6C, 0x7156, 0xB7DC, 0x7158, 0xDE78, 0x7159, 0xB7CF, 0x715A, 0xDEA3, 0x715C, 0xB7D4, 0x715D, 0xDE71, 0x715E, 0xB7D9, 0x715F, 0xDE7C, 0x7160, 0xDE6F, 0x7161, 0xDE76, 0x7162, 0xDE72, 0x7163, 0xDE6E, 0x7164, 0xB7D1, 0x7165, 0xB7D8, 0x7166, 0xB7D6, 0x7167, 0xB7D3, 0x7168, 0xB7DB, 0x7169, 0xB7D0, 0x716A, 0xDE75, 0x716C, 0xB7D5, 0x716E, 0xB54E, 0x7170, 0xDE7B, 0x7172, 0xDE73, 0x7178, 0xDE74, 0x717B, 0xE2C1, 0x717D, 0xBAB4, 0x7180, 0xE2BD, 0x7181, 0xE2C3, 0x7182, 0xE2BF, 0x7184, 0xBAB6, 0x7185, 0xE2BE, 0x7186, 0xE2C2, 0x7187, 0xE2BA, 0x7189, 0xE2BC, 0x718A, 0xBAB5, 0x718F, 0xE2C0, 0x7190, 0xE2BB, 0x7192, 0xBAB7, 0x7194, 0xBAB2, 0x7197, 0xE2C4, 0x7199, 0xBAB3, 0x719A, 0xE667, 0x719B, 0xE664, 0x719C, 0xE670, 0x719D, 0xE66A, 0x719E, 0xE66C, 0x719F, 0xBCF4, 0x71A0, 0xE666, 0x71A1, 0xE66E, 0x71A4, 0xE66D, 0x71A5, 0xE66B, 0x71A7, 0xE671, 0x71A8, 0xBCF7, 0x71A9, 0xE668, 0x71AA, 0xE66F, 0x71AC, 0xBCF5, 0x71AF, 0xE663, 0x71B0, 0xE665, 0x71B1, 0xBCF6, 0x71B2, 0xE662, 0x71B3, 0xE672, 0x71B5, 0xE669, 0x71B8, 0xEA4A, 0x71B9, 0xBF51, 0x71BC, 0xEA55, 0x71BD, 0xEA53, 0x71BE, 0xBF4B, 0x71BF, 0xEA49, 0x71C0, 0xEA4C, 0x71C1, 0xEA4D, 0x71C2, 0xEA48, 0x71C3, 0xBF55, 0x71C4, 0xBF56, 0x71C5, 0xEA47, 0x71C6, 0xEA56, 0x71C7, 0xEA51, 0x71C8, 0xBF4F, 0x71C9, 0xBF4C, 0x71CA, 0xEA50, 0x71CB, 0xEA4E, 0x71CE, 0xBF52, 0x71CF, 0xEA52, 0x71D0, 0xBF4D, 0x71D2, 0xBF4E, 0x71D4, 0xEA4F, 0x71D5, 0xBF50, 0x71D6, 0xEA4B, 0x71D8, 0xEA54, 0x71D9, 0xBF53, 0x71DA, 0xEA57, 0x71DB, 0xEA58, 0x71DC, 0xBF54, 0x71DF, 0xC0E7, 0x71E0, 0xC0EE, 0x71E1, 0xED5C, 0x71E2, 0xED62, 0x71E4, 0xED60, 0x71E5, 0xC0EA, 0x71E6, 0xC0E9, 0x71E7, 0xC0E6, 0x71E8, 0xED5E, 0x71EC, 0xC0EC, 0x71ED, 0xC0EB, 0x71EE, 0xC0E8, 0x71F0, 0xED61, 0x71F1, 0xED5D, 0x71F2, 0xED5F, 0x71F4, 0xC0ED, 0x71F8, 0xC277, 0x71F9, 0xEFFB, 0x71FB, 0xC274, 0x71FC, 0xC275, 0x71FD, 0xEFFD, 0x71FE, 0xC276, 0x71FF, 0xEFFA, 0x7201, 0xEFF9, 0x7202, 0xF26C, 0x7203, 0xEFFC, 0x7205, 0xF26D, 0x7206, 0xC37A, 0x7207, 0xF26B, 0x720A, 0xF26A, 0x720C, 0xF269, 0x720D, 0xC37B, 0x7210, 0xC46C, 0x7213, 0xF46A, 0x7214, 0xF46B, 0x7219, 0xF5DC, 0x721A, 0xF5DB, 0x721B, 0xC4EA, 0x721D, 0xF5DA, 0x721E, 0xF6EC, 0x721F, 0xF6ED, 0x7222, 0xF7E6, 0x7223, 0xF8B1, 0x7226, 0xF8F6, 0x7227, 0xF9BC, 0x7228, 0xC679, 0x7229, 0xF9C6, 0x722A, 0xA4F6, 0x722C, 0xAAA6, 0x722D, 0xAAA7, 0x7230, 0xACB8, 0x7235, 0xC0EF, 0x7236, 0xA4F7, 0x7238, 0xAAA8, 0x7239, 0xAF52, 0x723A, 0xB7DD, 0x723B, 0xA4F8, 0x723D, 0xB26E, 0x723E, 0xBAB8, 0x723F, 0xC962, 0x7241, 0xCFB7, 0x7242, 0xD27D, 0x7244, 0xE2C5, 0x7246, 0xC0F0, 0x7247, 0xA4F9, 0x7248, 0xAAA9, 0x7249, 0xCFB8, 0x724A, 0xCFB9, 0x724B, 0xDA66, 0x724C, 0xB550, 0x724F, 0xDEA4, 0x7252, 0xB7DE, 0x7253, 0xE2C6, 0x7256, 0xBCF8, 0x7258, 0xC37C, 0x7259, 0xA4FA, 0x725A, 0xDA67, 0x725B, 0xA4FB, 0x725D, 0xA6C9, 0x725E, 0xCA42, 0x725F, 0xA6C8, 0x7260, 0xA865, 0x7261, 0xA864, 0x7262, 0xA863, 0x7263, 0xCB60, 0x7267, 0xAAAA, 0x7269, 0xAAAB, 0x726A, 0xCD5B, 0x726C, 0xCFBA, 0x726E, 0xCFBD, 0x726F, 0xACBA, 0x7270, 0xCFBB, 0x7272, 0xACB9, 0x7273, 0xCFBC, 0x7274, 0xACBB, 0x7276, 0xD2A2, 0x7277, 0xD2A1, 0x7278, 0xD27E, 0x7279, 0xAF53, 0x727B, 0xD65D, 0x727C, 0xD65E, 0x727D, 0xB26F, 0x727E, 0xD65C, 0x727F, 0xD65F, 0x7280, 0xB552, 0x7281, 0xB270, 0x7284, 0xB551, 0x7285, 0xDA6B, 0x7286, 0xDA6A, 0x7288, 0xDA68, 0x7289, 0xDA69, 0x728B, 0xDA6C, 0x728C, 0xDEA6, 0x728D, 0xDEA5, 0x728E, 0xDEA9, 0x7290, 0xDEA8, 0x7291, 0xDEA7, 0x7292, 0xBAB9, 0x7293, 0xE2C9, 0x7295, 0xE2C8, 0x7296, 0xBABA, 0x7297, 0xE2C7, 0x7298, 0xE673, 0x729A, 0xE674, 0x729B, 0xBCF9, 0x729D, 0xEA59, 0x729E, 0xEA5A, 0x72A1, 0xF272, 0x72A2, 0xC37D, 0x72A3, 0xF271, 0x72A4, 0xF270, 0x72A5, 0xF26E, 0x72A6, 0xF26F, 0x72A7, 0xC4EB, 0x72A8, 0xF46C, 0x72A9, 0xF6EE, 0x72AA, 0xF8F7, 0x72AC, 0xA4FC, 0x72AE, 0xC9A5, 0x72AF, 0xA5C7, 0x72B0, 0xC9A6, 0x72B4, 0xCA43, 0x72B5, 0xCA44, 0x72BA, 0xCB66, 0x72BD, 0xCB62, 0x72BF, 0xCB61, 0x72C0, 0xAAAC, 0x72C1, 0xCB65, 0x72C2, 0xA867, 0x72C3, 0xCB63, 0x72C4, 0xA866, 0x72C5, 0xCB67, 0x72C6, 0xCB64, 0x72C9, 0xCD5F, 0x72CA, 0xCFBE, 0x72CB, 0xCD5D, 0x72CC, 0xCD64, 0x72CE, 0xAAAD, 0x72D0, 0xAAB0, 0x72D1, 0xCD65, 0x72D2, 0xCD61, 0x72D4, 0xCD62, 0x72D6, 0xCD5C, 0x72D7, 0xAAAF, 0x72D8, 0xCD5E, 0x72D9, 0xAAAE, 0x72DA, 0xCD63, 0x72DC, 0xCD60, 0x72DF, 0xCFC2, 0x72E0, 0xACBD, 0x72E1, 0xACBE, 0x72E3, 0xCFC5, 0x72E4, 0xCFBF, 0x72E6, 0xCFC4, 0x72E8, 0xCFC0, 0x72E9, 0xACBC, 0x72EA, 0xCFC3, 0x72EB, 0xCFC1, 0x72F3, 0xD2A8, 0x72F4, 0xD2A5, 0x72F6, 0xD2A7, 0x72F7, 0xAF58, 0x72F8, 0xAF57, 0x72F9, 0xAF55, 0x72FA, 0xD2A4, 0x72FB, 0xD2A9, 0x72FC, 0xAF54, 0x72FD, 0xAF56, 0x72FE, 0xD2A6, 0x72FF, 0xD667, 0x7300, 0xD2A3, 0x7301, 0xD2AA, 0x7307, 0xD662, 0x7308, 0xD666, 0x730A, 0xD665, 0x730B, 0xDA6E, 0x730C, 0xDA79, 0x730F, 0xD668, 0x7311, 0xD663, 0x7312, 0xDA6D, 0x7313, 0xB274, 0x7316, 0xB273, 0x7317, 0xD661, 0x7318, 0xD664, 0x7319, 0xB275, 0x731B, 0xB272, 0x731C, 0xB271, 0x731D, 0xD660, 0x731E, 0xD669, 0x7322, 0xDA70, 0x7323, 0xDA77, 0x7325, 0xB554, 0x7326, 0xDA76, 0x7327, 0xDA73, 0x7329, 0xB556, 0x732D, 0xDA75, 0x7330, 0xDA6F, 0x7331, 0xDA71, 0x7332, 0xDA74, 0x7333, 0xDA72, 0x7334, 0xB555, 0x7335, 0xDA78, 0x7336, 0xB553, 0x7337, 0xB7DF, 0x733A, 0xDEAD, 0x733B, 0xDEAC, 0x733C, 0xDEAA, 0x733E, 0xB7E2, 0x733F, 0xB7E1, 0x7340, 0xDEAE, 0x7342, 0xDEAB, 0x7343, 0xE2CA, 0x7344, 0xBABB, 0x7345, 0xB7E0, 0x7349, 0xDEB0, 0x734A, 0xDEAF, 0x734C, 0xE2CD, 0x734D, 0xE2CB, 0x734E, 0xBCFA, 0x7350, 0xBABC, 0x7351, 0xE2CC, 0x7352, 0xE676, 0x7357, 0xBCFB, 0x7358, 0xE675, 0x7359, 0xE67E, 0x735A, 0xE67D, 0x735B, 0xE67B, 0x735D, 0xE67A, 0x735E, 0xE677, 0x735F, 0xE678, 0x7360, 0xE679, 0x7361, 0xE67C, 0x7362, 0xE6A1, 0x7365, 0xEA5F, 0x7366, 0xEA5C, 0x7367, 0xEA5D, 0x7368, 0xBF57, 0x7369, 0xEA5B, 0x736A, 0xEA61, 0x736B, 0xEA60, 0x736C, 0xEA5E, 0x736E, 0xED64, 0x736F, 0xED65, 0x7370, 0xC0F1, 0x7372, 0xC0F2, 0x7373, 0xED63, 0x7375, 0xC279, 0x7376, 0xEFFE, 0x7377, 0xC278, 0x7378, 0xC37E, 0x737A, 0xC3A1, 0x737B, 0xC46D, 0x737C, 0xF46E, 0x737D, 0xF46D, 0x737E, 0xF5DD, 0x737F, 0xF6EF, 0x7380, 0xC57A, 0x7381, 0xF7E8, 0x7382, 0xF7E7, 0x7383, 0xF7E9, 0x7384, 0xA5C8, 0x7385, 0xCFC6, 0x7386, 0xAF59, 0x7387, 0xB276, 0x7388, 0xD66A, 0x7389, 0xA5C9, 0x738A, 0xC9A7, 0x738B, 0xA4FD, 0x738E, 0xCA45, 0x7392, 0xCB6C, 0x7393, 0xCB6A, 0x7394, 0xCB6B, 0x7395, 0xCB68, 0x7396, 0xA868, 0x7397, 0xCB69, 0x739D, 0xCD6D, 0x739F, 0xAAB3, 0x73A0, 0xCD6B, 0x73A1, 0xCD67, 0x73A2, 0xCD6A, 0x73A4, 0xCD66, 0x73A5, 0xAAB5, 0x73A6, 0xCD69, 0x73A8, 0xAAB2, 0x73A9, 0xAAB1, 0x73AB, 0xAAB4, 0x73AC, 0xCD6C, 0x73AD, 0xCD68, 0x73B2, 0xACC2, 0x73B3, 0xACC5, 0x73B4, 0xCFCE, 0x73B5, 0xCFCD, 0x73B6, 0xCFCC, 0x73B7, 0xACBF, 0x73B8, 0xCFD5, 0x73B9, 0xCFCB, 0x73BB, 0xACC1, 0x73BC, 0xD2AF, 0x73BE, 0xCFD2, 0x73BF, 0xCFD0, 0x73C0, 0xACC4, 0x73C2, 0xCFC8, 0x73C3, 0xCFD3, 0x73C5, 0xCFCA, 0x73C6, 0xCFD4, 0x73C7, 0xCFD1, 0x73C8, 0xCFC9, 0x73CA, 0xACC0, 0x73CB, 0xCFD6, 0x73CC, 0xCFC7, 0x73CD, 0xACC3, 0x73D2, 0xD2B4, 0x73D3, 0xD2AB, 0x73D4, 0xD2B6, 0x73D6, 0xD2AE, 0x73D7, 0xD2B9, 0x73D8, 0xD2BA, 0x73D9, 0xD2AC, 0x73DA, 0xD2B8, 0x73DB, 0xD2B5, 0x73DC, 0xD2B3, 0x73DD, 0xD2B7, 0x73DE, 0xAF5F, 0x73E0, 0xAF5D, 0x73E3, 0xD2B1, 0x73E5, 0xD2AD, 0x73E7, 0xD2B0, 0x73E8, 0xD2BB, 0x73E9, 0xD2B2, 0x73EA, 0xAF5E, 0x73EB, 0xCFCF, 0x73ED, 0xAF5A, 0x73EE, 0xAF5C, 0x73F4, 0xD678, 0x73F5, 0xD66D, 0x73F6, 0xD66B, 0x73F8, 0xD66C, 0x73FA, 0xD673, 0x73FC, 0xD674, 0x73FD, 0xD670, 0x73FE, 0xB27B, 0x73FF, 0xD675, 0x7400, 0xD672, 0x7401, 0xD66F, 0x7403, 0xB279, 0x7404, 0xD66E, 0x7405, 0xB277, 0x7406, 0xB27A, 0x7407, 0xD671, 0x7408, 0xD679, 0x7409, 0xAF5B, 0x740A, 0xB278, 0x740B, 0xD677, 0x740C, 0xD676, 0x740D, 0xB27C, 0x7416, 0xDA7E, 0x741A, 0xDAA1, 0x741B, 0xB560, 0x741D, 0xDAA7, 0x7420, 0xDAA9, 0x7421, 0xDAA2, 0x7422, 0xB55A, 0x7423, 0xDAA6, 0x7424, 0xDAA5, 0x7425, 0xB55B, 0x7426, 0xB561, 0x7428, 0xB562, 0x7429, 0xDAA8, 0x742A, 0xB558, 0x742B, 0xDA7D, 0x742C, 0xDA7B, 0x742D, 0xDAA3, 0x742E, 0xDA7A, 0x742F, 0xB55F, 0x7430, 0xDA7C, 0x7431, 0xDAA4, 0x7432, 0xDAAA, 0x7433, 0xB559, 0x7434, 0xB55E, 0x7435, 0xB55C, 0x7436, 0xB55D, 0x743A, 0xB557, 0x743F, 0xB7E9, 0x7440, 0xDEB7, 0x7441, 0xB7E8, 0x7442, 0xDEBB, 0x7444, 0xDEB1, 0x7446, 0xDEBC, 0x744A, 0xDEB2, 0x744B, 0xDEB3, 0x744D, 0xDEBD, 0x744E, 0xDEBA, 0x744F, 0xDEB8, 0x7450, 0xDEB9, 0x7451, 0xDEB5, 0x7452, 0xDEB4, 0x7454, 0xDEBE, 0x7455, 0xB7E5, 0x7457, 0xDEB6, 0x7459, 0xB7EA, 0x745A, 0xB7E4, 0x745B, 0xB7EB, 0x745C, 0xB7EC, 0x745E, 0xB7E7, 0x745F, 0xB7E6, 0x7462, 0xE2CE, 0x7463, 0xBABE, 0x7464, 0xBABD, 0x7467, 0xE2D3, 0x7469, 0xBCFC, 0x746A, 0xBABF, 0x746D, 0xBAC1, 0x746E, 0xE2D4, 0x746F, 0xB7E3, 0x7470, 0xBAC0, 0x7471, 0xE2D0, 0x7472, 0xE2D2, 0x7473, 0xE2CF, 0x7475, 0xE2D1, 0x7479, 0xE6AB, 0x747C, 0xE6AA, 0x747D, 0xE6A7, 0x747E, 0xBD40, 0x747F, 0xEA62, 0x7480, 0xBD41, 0x7481, 0xE6A6, 0x7483, 0xBCFE, 0x7485, 0xE6A8, 0x7486, 0xE6A5, 0x7487, 0xE6A2, 0x7488, 0xE6A9, 0x7489, 0xE6A3, 0x748A, 0xE6A4, 0x748B, 0xBCFD, 0x7490, 0xED69, 0x7492, 0xEA66, 0x7494, 0xEA65, 0x7495, 0xEA67, 0x7497, 0xED66, 0x7498, 0xBF5A, 0x749A, 0xEA63, 0x749C, 0xBF58, 0x749E, 0xBF5C, 0x749F, 0xBF5B, 0x74A0, 0xEA64, 0x74A1, 0xEA68, 0x74A3, 0xBF59, 0x74A5, 0xED6D, 0x74A6, 0xC0F5, 0x74A7, 0xC27A, 0x74A8, 0xC0F6, 0x74A9, 0xC0F3, 0x74AA, 0xED6A, 0x74AB, 0xED68, 0x74AD, 0xED6B, 0x74AF, 0xED6E, 0x74B0, 0xC0F4, 0x74B1, 0xED6C, 0x74B2, 0xED67, 0x74B5, 0xF042, 0x74B6, 0xF045, 0x74B7, 0xF275, 0x74B8, 0xF040, 0x74BA, 0xF46F, 0x74BB, 0xF046, 0x74BD, 0xC3A2, 0x74BE, 0xF044, 0x74BF, 0xC27B, 0x74C0, 0xF041, 0x74C1, 0xF043, 0x74C2, 0xF047, 0x74C3, 0xF276, 0x74C5, 0xF274, 0x74CA, 0xC3A3, 0x74CB, 0xF273, 0x74CF, 0xC46E, 0x74D4, 0xC4ED, 0x74D5, 0xF6F1, 0x74D6, 0xC4EC, 0x74D7, 0xF6F3, 0x74D8, 0xF6F0, 0x74D9, 0xF6F2, 0x74DA, 0xC5D0, 0x74DB, 0xF8B2, 0x74DC, 0xA5CA, 0x74DD, 0xCD6E, 0x74DE, 0xD2BC, 0x74DF, 0xD2BD, 0x74E0, 0xB27D, 0x74E1, 0xDEBF, 0x74E2, 0xBF5D, 0x74E3, 0xC3A4, 0x74E4, 0xC57B, 0x74E5, 0xF8B3, 0x74E6, 0xA5CB, 0x74E8, 0xCD6F, 0x74E9, 0xA260, 0x74EC, 0xCFD7, 0x74EE, 0xCFD8, 0x74F4, 0xD2BE, 0x74F5, 0xD2BF, 0x74F6, 0xB27E, 0x74F7, 0xB2A1, 0x74FB, 0xDAAB, 0x74FD, 0xDEC2, 0x74FE, 0xDEC1, 0x74FF, 0xDEC0, 0x7500, 0xE2D5, 0x7502, 0xE2D6, 0x7503, 0xE2D7, 0x7504, 0xBAC2, 0x7507, 0xE6AD, 0x7508, 0xE6AC, 0x750B, 0xEA69, 0x750C, 0xBF5E, 0x750D, 0xBF5F, 0x750F, 0xED72, 0x7510, 0xED6F, 0x7511, 0xED70, 0x7512, 0xED71, 0x7513, 0xF049, 0x7514, 0xF048, 0x7515, 0xC27C, 0x7516, 0xF277, 0x7517, 0xF5DE, 0x7518, 0xA5CC, 0x751A, 0xACC6, 0x751C, 0xB2A2, 0x751D, 0xDEC3, 0x751F, 0xA5CD, 0x7521, 0xD2C0, 0x7522, 0xB2A3, 0x7525, 0xB563, 0x7526, 0xB564, 0x7528, 0xA5CE, 0x7529, 0xA5CF, 0x752A, 0xCA46, 0x752B, 0xA86A, 0x752C, 0xA869, 0x752D, 0xACC7, 0x752E, 0xCFD9, 0x752F, 0xDAAC, 0x7530, 0xA5D0, 0x7531, 0xA5D1, 0x7532, 0xA5D2, 0x7533, 0xA5D3, 0x7537, 0xA86B, 0x7538, 0xA86C, 0x7539, 0xCB6E, 0x753A, 0xCB6D, 0x753D, 0xAAB6, 0x753E, 0xCD72, 0x753F, 0xCD70, 0x7540, 0xCD71, 0x7547, 0xCFDA, 0x7548, 0xCFDB, 0x754B, 0xACCB, 0x754C, 0xACC9, 0x754E, 0xACCA, 0x754F, 0xACC8, 0x7554, 0xAF60, 0x7559, 0xAF64, 0x755A, 0xAF63, 0x755B, 0xD2C1, 0x755C, 0xAF62, 0x755D, 0xAF61, 0x755F, 0xD2C2, 0x7562, 0xB2A6, 0x7563, 0xD67B, 0x7564, 0xD67A, 0x7565, 0xB2A4, 0x7566, 0xB2A5, 0x756A, 0xB566, 0x756B, 0xB565, 0x756C, 0xDAAE, 0x756F, 0xDAAD, 0x7570, 0xB2A7, 0x7576, 0xB7ED, 0x7577, 0xDEC5, 0x7578, 0xB7EE, 0x7579, 0xDEC4, 0x757D, 0xE2D8, 0x757E, 0xE6AE, 0x757F, 0xBD42, 0x7580, 0xEA6A, 0x7584, 0xED73, 0x7586, 0xC3A6, 0x7587, 0xC3A5, 0x758A, 0xC57C, 0x758B, 0xA5D4, 0x758C, 0xCD73, 0x758F, 0xB2A8, 0x7590, 0xE2D9, 0x7591, 0xBAC3, 0x7594, 0xCB6F, 0x7595, 0xCB70, 0x7598, 0xCD74, 0x7599, 0xAAB8, 0x759A, 0xAAB9, 0x759D, 0xAAB7, 0x75A2, 0xACCF, 0x75A3, 0xACD0, 0x75A4, 0xACCD, 0x75A5, 0xACCE, 0x75A7, 0xCFDC, 0x75AA, 0xCFDD, 0x75AB, 0xACCC, 0x75B0, 0xD2C3, 0x75B2, 0xAF68, 0x75B3, 0xAF69, 0x75B5, 0xB2AB, 0x75B6, 0xD2C9, 0x75B8, 0xAF6E, 0x75B9, 0xAF6C, 0x75BA, 0xD2CA, 0x75BB, 0xD2C5, 0x75BC, 0xAF6B, 0x75BD, 0xAF6A, 0x75BE, 0xAF65, 0x75BF, 0xD2C8, 0x75C0, 0xD2C7, 0x75C1, 0xD2C4, 0x75C2, 0xAF6D, 0x75C4, 0xD2C6, 0x75C5, 0xAF66, 0x75C7, 0xAF67, 0x75CA, 0xB2AC, 0x75CB, 0xD6A1, 0x75CC, 0xD6A2, 0x75CD, 0xB2AD, 0x75CE, 0xD67C, 0x75CF, 0xD67E, 0x75D0, 0xD6A4, 0x75D1, 0xD6A3, 0x75D2, 0xD67D, 0x75D4, 0xB2A9, 0x75D5, 0xB2AA, 0x75D7, 0xDAB6, 0x75D8, 0xB56B, 0x75D9, 0xB56A, 0x75DA, 0xDAB0, 0x75DB, 0xB568, 0x75DD, 0xDAB3, 0x75DE, 0xB56C, 0x75DF, 0xDAB4, 0x75E0, 0xB56D, 0x75E1, 0xDAB1, 0x75E2, 0xB567, 0x75E3, 0xB569, 0x75E4, 0xDAB5, 0x75E6, 0xDAB2, 0x75E7, 0xDAAF, 0x75ED, 0xDED2, 0x75EF, 0xDEC7, 0x75F0, 0xB7F0, 0x75F1, 0xB7F3, 0x75F2, 0xB7F2, 0x75F3, 0xB7F7, 0x75F4, 0xB7F6, 0x75F5, 0xDED3, 0x75F6, 0xDED1, 0x75F7, 0xDECA, 0x75F8, 0xDECE, 0x75F9, 0xDECD, 0x75FA, 0xB7F4, 0x75FB, 0xDED0, 0x75FC, 0xDECC, 0x75FD, 0xDED4, 0x75FE, 0xDECB, 0x75FF, 0xB7F5, 0x7600, 0xB7EF, 0x7601, 0xB7F1, 0x7603, 0xDEC9, 0x7608, 0xE2DB, 0x7609, 0xBAC7, 0x760A, 0xE2DF, 0x760B, 0xBAC6, 0x760C, 0xE2DC, 0x760D, 0xBAC5, 0x760F, 0xDEC8, 0x7610, 0xDECF, 0x7611, 0xE2DE, 0x7613, 0xBAC8, 0x7614, 0xE2E0, 0x7615, 0xE2DD, 0x7616, 0xE2DA, 0x7619, 0xE6B1, 0x761A, 0xE6B5, 0x761B, 0xE6B7, 0x761C, 0xE6B3, 0x761D, 0xE6B2, 0x761E, 0xE6B0, 0x761F, 0xBD45, 0x7620, 0xBD43, 0x7621, 0xBD48, 0x7622, 0xBD49, 0x7623, 0xE6B4, 0x7624, 0xBD46, 0x7625, 0xE6AF, 0x7626, 0xBD47, 0x7627, 0xBAC4, 0x7628, 0xE6B6, 0x7629, 0xBD44, 0x762D, 0xEA6C, 0x762F, 0xEA6B, 0x7630, 0xEA73, 0x7631, 0xEA6D, 0x7632, 0xEA72, 0x7633, 0xEA6F, 0x7634, 0xBF60, 0x7635, 0xEA71, 0x7638, 0xBF61, 0x763A, 0xBF62, 0x763C, 0xEA70, 0x763D, 0xEA6E, 0x7642, 0xC0F8, 0x7643, 0xED74, 0x7646, 0xC0F7, 0x7647, 0xED77, 0x7648, 0xED75, 0x7649, 0xED76, 0x764C, 0xC0F9, 0x7650, 0xF04D, 0x7652, 0xC2A1, 0x7653, 0xF04E, 0x7656, 0xC27D, 0x7657, 0xF04F, 0x7658, 0xC27E, 0x7659, 0xF04C, 0x765A, 0xF050, 0x765C, 0xF04A, 0x765F, 0xC3A7, 0x7660, 0xF278, 0x7661, 0xC3A8, 0x7662, 0xC46F, 0x7664, 0xF04B, 0x7665, 0xC470, 0x7669, 0xC4EE, 0x766A, 0xF5DF, 0x766C, 0xC57E, 0x766D, 0xF6F4, 0x766E, 0xC57D, 0x7670, 0xF7EA, 0x7671, 0xC5F5, 0x7672, 0xC5F6, 0x7675, 0xF9CC, 0x7678, 0xACD1, 0x7679, 0xCFDE, 0x767B, 0xB56E, 0x767C, 0xB56F, 0x767D, 0xA5D5, 0x767E, 0xA6CA, 0x767F, 0xCA47, 0x7681, 0xCB71, 0x7682, 0xA86D, 0x7684, 0xAABA, 0x7686, 0xACD2, 0x7687, 0xACD3, 0x7688, 0xACD4, 0x7689, 0xD6A6, 0x768A, 0xD2CB, 0x768B, 0xAF6F, 0x768E, 0xB2AE, 0x768F, 0xD6A5, 0x7692, 0xDAB8, 0x7693, 0xB571, 0x7695, 0xDAB7, 0x7696, 0xB570, 0x7699, 0xDED5, 0x769A, 0xBD4A, 0x769B, 0xE6BB, 0x769C, 0xE6B8, 0x769D, 0xE6B9, 0x769E, 0xE6BA, 0x76A4, 0xED78, 0x76A6, 0xF051, 0x76AA, 0xF471, 0x76AB, 0xF470, 0x76AD, 0xF6F5, 0x76AE, 0xA5D6, 0x76AF, 0xCD75, 0x76B0, 0xAF70, 0x76B4, 0xB572, 0x76B5, 0xDED6, 0x76B8, 0xE2E1, 0x76BA, 0xBD4B, 0x76BB, 0xEA74, 0x76BD, 0xF052, 0x76BE, 0xF472, 0x76BF, 0xA5D7, 0x76C2, 0xAABB, 0x76C3, 0xACD7, 0x76C4, 0xCFDF, 0x76C5, 0xACD8, 0x76C6, 0xACD6, 0x76C8, 0xACD5, 0x76C9, 0xD2CC, 0x76CA, 0xAF71, 0x76CD, 0xAF72, 0x76CE, 0xAF73, 0x76D2, 0xB2B0, 0x76D3, 0xD6A7, 0x76D4, 0xB2AF, 0x76DA, 0xDAB9, 0x76DB, 0xB2B1, 0x76DC, 0xB573, 0x76DD, 0xDED7, 0x76DE, 0xB7F8, 0x76DF, 0xB7F9, 0x76E1, 0xBAC9, 0x76E3, 0xBACA, 0x76E4, 0xBD4C, 0x76E5, 0xBF64, 0x76E6, 0xEA75, 0x76E7, 0xBF63, 0x76E9, 0xED79, 0x76EA, 0xC0FA, 0x76EC, 0xF053, 0x76ED, 0xF473, 0x76EE, 0xA5D8, 0x76EF, 0xA86E, 0x76F0, 0xCD78, 0x76F1, 0xCD77, 0x76F2, 0xAABC, 0x76F3, 0xCD76, 0x76F4, 0xAABD, 0x76F5, 0xCD79, 0x76F7, 0xCFE5, 0x76F8, 0xACDB, 0x76F9, 0xACDA, 0x76FA, 0xCFE7, 0x76FB, 0xCFE6, 0x76FC, 0xACDF, 0x76FE, 0xACDE, 0x7701, 0xACD9, 0x7703, 0xCFE1, 0x7704, 0xCFE2, 0x7705, 0xCFE3, 0x7707, 0xACE0, 0x7708, 0xCFE0, 0x7709, 0xACDC, 0x770A, 0xCFE4, 0x770B, 0xACDD, 0x7710, 0xD2CF, 0x7711, 0xD2D3, 0x7712, 0xD2D1, 0x7713, 0xD2D0, 0x7715, 0xD2D4, 0x7719, 0xD2D5, 0x771A, 0xD2D6, 0x771B, 0xD2CE, 0x771D, 0xD2CD, 0x771F, 0xAF75, 0x7720, 0xAF76, 0x7722, 0xD2D7, 0x7723, 0xD2D2, 0x7725, 0xD6B0, 0x7727, 0xD2D8, 0x7728, 0xAF77, 0x7729, 0xAF74, 0x772D, 0xD6AA, 0x772F, 0xD6A9, 0x7731, 0xD6AB, 0x7732, 0xD6AC, 0x7733, 0xD6AE, 0x7734, 0xD6AD, 0x7735, 0xD6B2, 0x7736, 0xB2B5, 0x7737, 0xB2B2, 0x7738, 0xB2B6, 0x7739, 0xD6A8, 0x773A, 0xB2B7, 0x773B, 0xD6B1, 0x773C, 0xB2B4, 0x773D, 0xD6AF, 0x773E, 0xB2B3, 0x7744, 0xDABC, 0x7745, 0xDABE, 0x7746, 0xDABA, 0x7747, 0xDABB, 0x774A, 0xDABF, 0x774B, 0xDAC1, 0x774C, 0xDAC2, 0x774D, 0xDABD, 0x774E, 0xDAC0, 0x774F, 0xB574, 0x7752, 0xDEDB, 0x7754, 0xDEE0, 0x7755, 0xDED8, 0x7756, 0xDEDC, 0x7759, 0xDEE1, 0x775A, 0xDEDD, 0x775B, 0xB7FA, 0x775C, 0xB843, 0x775E, 0xB7FD, 0x775F, 0xDED9, 0x7760, 0xDEDA, 0x7761, 0xBACE, 0x7762, 0xB846, 0x7763, 0xB7FE, 0x7765, 0xB844, 0x7766, 0xB7FC, 0x7767, 0xDEDF, 0x7768, 0xB845, 0x7769, 0xDEDE, 0x776A, 0xB841, 0x776B, 0xB7FB, 0x776C, 0xB842, 0x776D, 0xDEE2, 0x776E, 0xE2E6, 0x776F, 0xE2E8, 0x7779, 0xB840, 0x777C, 0xE2E3, 0x777D, 0xBACC, 0x777E, 0xE2E9, 0x777F, 0xBACD, 0x7780, 0xE2E7, 0x7781, 0xE2E2, 0x7782, 0xE2E5, 0x7783, 0xE2EA, 0x7784, 0xBACB, 0x7785, 0xE2E4, 0x7787, 0xBD4E, 0x7788, 0xE6BF, 0x7789, 0xE6BE, 0x778B, 0xBD51, 0x778C, 0xBD4F, 0x778D, 0xE6BC, 0x778E, 0xBD4D, 0x778F, 0xE6BD, 0x7791, 0xBD50, 0x7795, 0xEA7D, 0x7797, 0xEAA1, 0x7799, 0xEA7E, 0x779A, 0xEA76, 0x779B, 0xEA7A, 0x779C, 0xEA79, 0x779D, 0xEA77, 0x779E, 0xBF66, 0x779F, 0xBF67, 0x77A0, 0xBF65, 0x77A1, 0xEA78, 0x77A2, 0xEA7B, 0x77A3, 0xEA7C, 0x77A5, 0xBF68, 0x77A7, 0xC140, 0x77A8, 0xEDA3, 0x77AA, 0xC0FC, 0x77AB, 0xED7B, 0x77AC, 0xC0FE, 0x77AD, 0xC141, 0x77B0, 0xC0FD, 0x77B1, 0xEDA2, 0x77B2, 0xED7C, 0x77B3, 0xC0FB, 0x77B4, 0xEDA1, 0x77B5, 0xED7A, 0x77B6, 0xED7E, 0x77B7, 0xED7D, 0x77BA, 0xF055, 0x77BB, 0xC2A4, 0x77BC, 0xC2A5, 0x77BD, 0xC2A2, 0x77BF, 0xC2A3, 0x77C2, 0xF054, 0x77C4, 0xF27B, 0x77C7, 0xC3A9, 0x77C9, 0xF279, 0x77CA, 0xF27A, 0x77CC, 0xF474, 0x77CD, 0xF477, 0x77CE, 0xF475, 0x77CF, 0xF476, 0x77D0, 0xF5E0, 0x77D3, 0xC4EF, 0x77D4, 0xF7EB, 0x77D5, 0xF8B4, 0x77D7, 0xC5F7, 0x77D8, 0xF8F8, 0x77D9, 0xF8F9, 0x77DA, 0xC666, 0x77DB, 0xA5D9, 0x77DC, 0xACE1, 0x77DE, 0xDAC3, 0x77E0, 0xDEE3, 0x77E2, 0xA5DA, 0x77E3, 0xA86F, 0x77E5, 0xAABE, 0x77E7, 0xCFE8, 0x77E8, 0xCFE9, 0x77E9, 0xAF78, 0x77EC, 0xDAC4, 0x77ED, 0xB575, 0x77EE, 0xB847, 0x77EF, 0xC142, 0x77F0, 0xEDA4, 0x77F1, 0xF27C, 0x77F2, 0xF478, 0x77F3, 0xA5DB, 0x77F7, 0xCDA1, 0x77F8, 0xCD7A, 0x77F9, 0xCD7C, 0x77FA, 0xCD7E, 0x77FB, 0xCD7D, 0x77FC, 0xCD7B, 0x77FD, 0xAABF, 0x7802, 0xACE2, 0x7803, 0xCFF2, 0x7805, 0xCFED, 0x7806, 0xCFEA, 0x7809, 0xCFF1, 0x780C, 0xACE4, 0x780D, 0xACE5, 0x780E, 0xCFF0, 0x780F, 0xCFEF, 0x7810, 0xCFEE, 0x7811, 0xCFEB, 0x7812, 0xCFEC, 0x7813, 0xCFF3, 0x7814, 0xACE3, 0x781D, 0xAF7C, 0x781F, 0xAFA4, 0x7820, 0xAFA3, 0x7821, 0xD2E1, 0x7822, 0xD2DB, 0x7823, 0xD2D9, 0x7825, 0xAFA1, 0x7826, 0xD6B9, 0x7827, 0xAF7A, 0x7828, 0xD2DE, 0x7829, 0xD2E2, 0x782A, 0xD2E4, 0x782B, 0xD2E0, 0x782C, 0xD2DA, 0x782D, 0xAFA2, 0x782E, 0xD2DF, 0x782F, 0xD2DD, 0x7830, 0xAF79, 0x7831, 0xD2E5, 0x7832, 0xAFA5, 0x7833, 0xD2E3, 0x7834, 0xAF7D, 0x7835, 0xD2DC, 0x7837, 0xAF7E, 0x7838, 0xAF7B, 0x7843, 0xB2B9, 0x7845, 0xD6BA, 0x7848, 0xD6B3, 0x7849, 0xD6B5, 0x784A, 0xD6B7, 0x784C, 0xD6B8, 0x784D, 0xD6B6, 0x784E, 0xB2BA, 0x7850, 0xD6BB, 0x7852, 0xD6B4, 0x785C, 0xDAC8, 0x785D, 0xB576, 0x785E, 0xDAD0, 0x7860, 0xDAC5, 0x7862, 0xDAD1, 0x7864, 0xDAC6, 0x7865, 0xDAC7, 0x7868, 0xDACF, 0x7869, 0xDACE, 0x786A, 0xDACB, 0x786B, 0xB2B8, 0x786C, 0xB577, 0x786D, 0xDAC9, 0x786E, 0xDACC, 0x786F, 0xB578, 0x7870, 0xDACD, 0x7871, 0xDACA, 0x7879, 0xDEEE, 0x787B, 0xDEF2, 0x787C, 0xB84E, 0x787E, 0xE2F0, 0x787F, 0xB851, 0x7880, 0xDEF0, 0x7881, 0xF9D6, 0x7883, 0xDEED, 0x7884, 0xDEE8, 0x7885, 0xDEEA, 0x7886, 0xDEEB, 0x7887, 0xDEE4, 0x7889, 0xB84D, 0x788C, 0xB84C, 0x788E, 0xB848, 0x788F, 0xDEE7, 0x7891, 0xB84F, 0x7893, 0xB850, 0x7894, 0xDEE6, 0x7895, 0xDEE9, 0x7896, 0xDEF1, 0x7897, 0xB84A, 0x7898, 0xB84B, 0x7899, 0xDEEF, 0x789A, 0xDEE5, 0x789E, 0xE2F2, 0x789F, 0xBAD0, 0x78A0, 0xE2F4, 0x78A1, 0xDEEC, 0x78A2, 0xE2F6, 0x78A3, 0xBAD4, 0x78A4, 0xE2F7, 0x78A5, 0xE2F3, 0x78A7, 0xBAD1, 0x78A8, 0xE2EF, 0x78A9, 0xBAD3, 0x78AA, 0xE2EC, 0x78AB, 0xE2F1, 0x78AC, 0xE2F5, 0x78AD, 0xE2EE, 0x78B0, 0xB849, 0x78B2, 0xE2EB, 0x78B3, 0xBAD2, 0x78B4, 0xE2ED, 0x78BA, 0xBD54, 0x78BB, 0xE6C1, 0x78BC, 0xBD58, 0x78BE, 0xBD56, 0x78C1, 0xBACF, 0x78C3, 0xE6C8, 0x78C4, 0xE6C9, 0x78C5, 0xBD53, 0x78C8, 0xE6C7, 0x78C9, 0xE6CA, 0x78CA, 0xBD55, 0x78CB, 0xBD52, 0x78CC, 0xE6C3, 0x78CD, 0xE6C0, 0x78CE, 0xE6C5, 0x78CF, 0xE6C2, 0x78D0, 0xBD59, 0x78D1, 0xE6C4, 0x78D4, 0xE6C6, 0x78D5, 0xBD57, 0x78DA, 0xBF6A, 0x78DB, 0xEAA8, 0x78DD, 0xEAA2, 0x78DE, 0xEAA6, 0x78DF, 0xEAAC, 0x78E0, 0xEAAD, 0x78E1, 0xEAA9, 0x78E2, 0xEAAA, 0x78E3, 0xEAA7, 0x78E5, 0xEAA4, 0x78E7, 0xBF6C, 0x78E8, 0xBF69, 0x78E9, 0xEAA3, 0x78EA, 0xEAA5, 0x78EC, 0xBF6B, 0x78ED, 0xEAAB, 0x78EF, 0xC146, 0x78F2, 0xEDAA, 0x78F3, 0xEDA5, 0x78F4, 0xC145, 0x78F7, 0xC143, 0x78F9, 0xEDAC, 0x78FA, 0xC144, 0x78FB, 0xEDA8, 0x78FC, 0xEDA9, 0x78FD, 0xEDA6, 0x78FE, 0xEDAD, 0x78FF, 0xF056, 0x7901, 0xC147, 0x7902, 0xEDA7, 0x7904, 0xEDAE, 0x7905, 0xEDAB, 0x7909, 0xF05A, 0x790C, 0xF057, 0x790E, 0xC2A6, 0x7910, 0xF05B, 0x7911, 0xF05D, 0x7912, 0xF05C, 0x7913, 0xF058, 0x7914, 0xF059, 0x7917, 0xF2A3, 0x7919, 0xC3AA, 0x791B, 0xF27E, 0x791C, 0xF2A2, 0x791D, 0xF27D, 0x791E, 0xF2A4, 0x7921, 0xF2A1, 0x7923, 0xF47A, 0x7924, 0xF47D, 0x7925, 0xF479, 0x7926, 0xC471, 0x7927, 0xF47B, 0x7928, 0xF47C, 0x7929, 0xF47E, 0x792A, 0xC472, 0x792B, 0xC474, 0x792C, 0xC473, 0x792D, 0xF5E1, 0x792F, 0xF5E3, 0x7931, 0xF5E2, 0x7935, 0xF6F6, 0x7938, 0xF8B5, 0x7939, 0xF8FA, 0x793A, 0xA5DC, 0x793D, 0xCB72, 0x793E, 0xAAC0, 0x793F, 0xCDA3, 0x7940, 0xAAC1, 0x7941, 0xAAC2, 0x7942, 0xCDA2, 0x7944, 0xCFF8, 0x7945, 0xCFF7, 0x7946, 0xACE6, 0x7947, 0xACE9, 0x7948, 0xACE8, 0x7949, 0xACE7, 0x794A, 0xCFF4, 0x794B, 0xCFF6, 0x794C, 0xCFF5, 0x794F, 0xD2E8, 0x7950, 0xAFA7, 0x7951, 0xD2EC, 0x7952, 0xD2EB, 0x7953, 0xD2EA, 0x7954, 0xD2E6, 0x7955, 0xAFA6, 0x7956, 0xAFAA, 0x7957, 0xAFAD, 0x795A, 0xAFAE, 0x795B, 0xD2E7, 0x795C, 0xD2E9, 0x795D, 0xAFAC, 0x795E, 0xAFAB, 0x795F, 0xAFA9, 0x7960, 0xAFA8, 0x7961, 0xD6C2, 0x7963, 0xD6C0, 0x7964, 0xD6BC, 0x7965, 0xB2BB, 0x7967, 0xD6BD, 0x7968, 0xB2BC, 0x7969, 0xD6BE, 0x796A, 0xD6BF, 0x796B, 0xD6C1, 0x796D, 0xB2BD, 0x7970, 0xDAD5, 0x7972, 0xDAD4, 0x7973, 0xDAD3, 0x7974, 0xDAD2, 0x7979, 0xDEF6, 0x797A, 0xB852, 0x797C, 0xDEF3, 0x797D, 0xDEF5, 0x797F, 0xB853, 0x7981, 0xB854, 0x7982, 0xDEF4, 0x7988, 0xE341, 0x798A, 0xE2F9, 0x798B, 0xE2FA, 0x798D, 0xBAD7, 0x798E, 0xBAD5, 0x798F, 0xBAD6, 0x7990, 0xE343, 0x7992, 0xE342, 0x7993, 0xE2FE, 0x7994, 0xE2FD, 0x7995, 0xE2FC, 0x7996, 0xE2FB, 0x7997, 0xE340, 0x7998, 0xE2F8, 0x799A, 0xE6CB, 0x799B, 0xE6D0, 0x799C, 0xE6CE, 0x79A0, 0xE6CD, 0x79A1, 0xE6CC, 0x79A2, 0xE6CF, 0x79A4, 0xEAAE, 0x79A6, 0xBF6D, 0x79A7, 0xC148, 0x79A8, 0xEDB0, 0x79AA, 0xC149, 0x79AB, 0xEDAF, 0x79AC, 0xF05F, 0x79AD, 0xF05E, 0x79AE, 0xC2A7, 0x79B0, 0xF2A5, 0x79B1, 0xC3AB, 0x79B2, 0xF4A1, 0x79B3, 0xC5A1, 0x79B4, 0xF6F7, 0x79B6, 0xF8B7, 0x79B7, 0xF8B6, 0x79B8, 0xC9A8, 0x79B9, 0xACEA, 0x79BA, 0xACEB, 0x79BB, 0xD6C3, 0x79BD, 0xB856, 0x79BE, 0xA5DD, 0x79BF, 0xA872, 0x79C0, 0xA871, 0x79C1, 0xA870, 0x79C5, 0xCDA4, 0x79C8, 0xAAC4, 0x79C9, 0xAAC3, 0x79CB, 0xACEE, 0x79CD, 0xCFFA, 0x79CE, 0xCFFD, 0x79CF, 0xCFFB, 0x79D1, 0xACEC, 0x79D2, 0xACED, 0x79D5, 0xCFF9, 0x79D6, 0xCFFC, 0x79D8, 0xAFB5, 0x79DC, 0xD2F3, 0x79DD, 0xD2F5, 0x79DE, 0xD2F4, 0x79DF, 0xAFB2, 0x79E0, 0xD2EF, 0x79E3, 0xAFB0, 0x79E4, 0xAFAF, 0x79E6, 0xAFB3, 0x79E7, 0xAFB1, 0x79E9, 0xAFB4, 0x79EA, 0xD2F2, 0x79EB, 0xD2ED, 0x79EC, 0xD2EE, 0x79ED, 0xD2F1, 0x79EE, 0xD2F0, 0x79F6, 0xD6C6, 0x79F7, 0xD6C7, 0x79F8, 0xD6C5, 0x79FA, 0xD6C4, 0x79FB, 0xB2BE, 0x7A00, 0xB57D, 0x7A02, 0xDAD6, 0x7A03, 0xDAD8, 0x7A04, 0xDADA, 0x7A05, 0xB57C, 0x7A08, 0xB57A, 0x7A0A, 0xDAD7, 0x7A0B, 0xB57B, 0x7A0C, 0xDAD9, 0x7A0D, 0xB579, 0x7A10, 0xDF41, 0x7A11, 0xDEF7, 0x7A12, 0xDEFA, 0x7A13, 0xDEFE, 0x7A14, 0xB85A, 0x7A15, 0xDEFC, 0x7A17, 0xDEFB, 0x7A18, 0xDEF8, 0x7A19, 0xDEF9, 0x7A1A, 0xB858, 0x7A1B, 0xDF40, 0x7A1C, 0xB857, 0x7A1E, 0xB85C, 0x7A1F, 0xB85B, 0x7A20, 0xB859, 0x7A22, 0xDEFD, 0x7A26, 0xE349, 0x7A28, 0xE348, 0x7A2B, 0xE344, 0x7A2E, 0xBAD8, 0x7A2F, 0xE347, 0x7A30, 0xE346, 0x7A31, 0xBAD9, 0x7A37, 0xBD5E, 0x7A39, 0xE6D2, 0x7A3B, 0xBD5F, 0x7A3C, 0xBD5B, 0x7A3D, 0xBD5D, 0x7A3F, 0xBD5A, 0x7A40, 0xBD5C, 0x7A44, 0xEAAF, 0x7A46, 0xBF70, 0x7A47, 0xEAB1, 0x7A48, 0xEAB0, 0x7A4A, 0xE345, 0x7A4B, 0xBF72, 0x7A4C, 0xBF71, 0x7A4D, 0xBF6E, 0x7A4E, 0xBF6F, 0x7A54, 0xEDB5, 0x7A56, 0xEDB3, 0x7A57, 0xC14A, 0x7A58, 0xEDB4, 0x7A5A, 0xEDB6, 0x7A5B, 0xEDB2, 0x7A5C, 0xEDB1, 0x7A5F, 0xF060, 0x7A60, 0xC2AA, 0x7A61, 0xC2A8, 0x7A62, 0xC2A9, 0x7A67, 0xF2A6, 0x7A68, 0xF2A7, 0x7A69, 0xC3AD, 0x7A6B, 0xC3AC, 0x7A6C, 0xF4A3, 0x7A6D, 0xF4A4, 0x7A6E, 0xF4A2, 0x7A70, 0xF6F8, 0x7A71, 0xF6F9, 0x7A74, 0xA5DE, 0x7A75, 0xCA48, 0x7A76, 0xA873, 0x7A78, 0xCDA5, 0x7A79, 0xAAC6, 0x7A7A, 0xAAC5, 0x7A7B, 0xCDA6, 0x7A7E, 0xD040, 0x7A7F, 0xACEF, 0x7A80, 0xCFFE, 0x7A81, 0xACF0, 0x7A84, 0xAFB6, 0x7A85, 0xD2F8, 0x7A86, 0xD2F6, 0x7A87, 0xD2FC, 0x7A88, 0xAFB7, 0x7A89, 0xD2F7, 0x7A8A, 0xD2FB, 0x7A8B, 0xD2F9, 0x7A8C, 0xD2FA, 0x7A8F, 0xD6C8, 0x7A90, 0xD6CA, 0x7A92, 0xB2BF, 0x7A94, 0xD6C9, 0x7A95, 0xB2C0, 0x7A96, 0xB5A2, 0x7A97, 0xB5A1, 0x7A98, 0xB57E, 0x7A99, 0xDADB, 0x7A9E, 0xDF44, 0x7A9F, 0xB85D, 0x7AA0, 0xB85E, 0x7AA2, 0xDF43, 0x7AA3, 0xDF42, 0x7AA8, 0xE34A, 0x7AA9, 0xBADB, 0x7AAA, 0xBADA, 0x7AAB, 0xE34B, 0x7AAC, 0xE34C, 0x7AAE, 0xBD61, 0x7AAF, 0xBD60, 0x7AB1, 0xEAB5, 0x7AB2, 0xE6D3, 0x7AB3, 0xE6D5, 0x7AB4, 0xE6D4, 0x7AB5, 0xEAB4, 0x7AB6, 0xEAB2, 0x7AB7, 0xEAB6, 0x7AB8, 0xEAB3, 0x7ABA, 0xBF73, 0x7ABE, 0xEDB7, 0x7ABF, 0xC14B, 0x7AC0, 0xEDB8, 0x7AC1, 0xEDB9, 0x7AC4, 0xC2AB, 0x7AC5, 0xC2AC, 0x7AC7, 0xC475, 0x7ACA, 0xC5D1, 0x7ACB, 0xA5DF, 0x7AD1, 0xD041, 0x7AD8, 0xD2FD, 0x7AD9, 0xAFB8, 0x7ADF, 0xB3BA, 0x7AE0, 0xB3B9, 0x7AE3, 0xB5A4, 0x7AE4, 0xDADD, 0x7AE5, 0xB5A3, 0x7AE6, 0xDADC, 0x7AEB, 0xDF45, 0x7AED, 0xBADC, 0x7AEE, 0xE34D, 0x7AEF, 0xBADD, 0x7AF6, 0xC476, 0x7AF7, 0xF4A5, 0x7AF9, 0xA6CB, 0x7AFA, 0xAAC7, 0x7AFB, 0xCDA7, 0x7AFD, 0xACF2, 0x7AFF, 0xACF1, 0x7B00, 0xD042, 0x7B01, 0xD043, 0x7B04, 0xD340, 0x7B05, 0xD342, 0x7B06, 0xAFB9, 0x7B08, 0xD344, 0x7B09, 0xD347, 0x7B0A, 0xD345, 0x7B0E, 0xD346, 0x7B0F, 0xD343, 0x7B10, 0xD2FE, 0x7B11, 0xAFBA, 0x7B12, 0xD348, 0x7B13, 0xD341, 0x7B18, 0xD6D3, 0x7B19, 0xB2C6, 0x7B1A, 0xD6DC, 0x7B1B, 0xB2C3, 0x7B1D, 0xD6D5, 0x7B1E, 0xB2C7, 0x7B20, 0xB2C1, 0x7B22, 0xD6D0, 0x7B23, 0xD6DD, 0x7B24, 0xD6D1, 0x7B25, 0xD6CE, 0x7B26, 0xB2C5, 0x7B28, 0xB2C2, 0x7B2A, 0xD6D4, 0x7B2B, 0xD6D7, 0x7B2C, 0xB2C4, 0x7B2D, 0xD6D8, 0x7B2E, 0xB2C8, 0x7B2F, 0xD6D9, 0x7B30, 0xD6CF, 0x7B31, 0xD6D6, 0x7B32, 0xD6DA, 0x7B33, 0xD6D2, 0x7B34, 0xD6CD, 0x7B35, 0xD6CB, 0x7B38, 0xD6DB, 0x7B3B, 0xDADF, 0x7B40, 0xDAE4, 0x7B44, 0xDAE0, 0x7B45, 0xDAE6, 0x7B46, 0xB5A7, 0x7B47, 0xD6CC, 0x7B48, 0xDAE1, 0x7B49, 0xB5A5, 0x7B4A, 0xDADE, 0x7B4B, 0xB5AC, 0x7B4C, 0xDAE2, 0x7B4D, 0xB5AB, 0x7B4E, 0xDAE3, 0x7B4F, 0xB5AD, 0x7B50, 0xB5A8, 0x7B51, 0xB5AE, 0x7B52, 0xB5A9, 0x7B54, 0xB5AA, 0x7B56, 0xB5A6, 0x7B58, 0xDAE5, 0x7B60, 0xB861, 0x7B61, 0xDF50, 0x7B63, 0xDF53, 0x7B64, 0xDF47, 0x7B65, 0xDF4C, 0x7B66, 0xDF46, 0x7B67, 0xB863, 0x7B69, 0xDF4A, 0x7B6D, 0xDF48, 0x7B6E, 0xB862, 0x7B70, 0xDF4F, 0x7B71, 0xDF4E, 0x7B72, 0xDF4B, 0x7B73, 0xDF4D, 0x7B74, 0xDF49, 0x7B75, 0xBAE1, 0x7B76, 0xDF52, 0x7B77, 0xB85F, 0x7B78, 0xDF51, 0x7B82, 0xE35D, 0x7B84, 0xBAE8, 0x7B85, 0xE358, 0x7B87, 0xBAE7, 0x7B88, 0xE34E, 0x7B8A, 0xE350, 0x7B8B, 0xBAE0, 0x7B8C, 0xE355, 0x7B8D, 0xE354, 0x7B8E, 0xE357, 0x7B8F, 0xBAE5, 0x7B90, 0xE352, 0x7B91, 0xE351, 0x7B94, 0xBAE4, 0x7B95, 0xBADF, 0x7B96, 0xE353, 0x7B97, 0xBAE2, 0x7B98, 0xE359, 0x7B99, 0xE35B, 0x7B9B, 0xE356, 0x7B9C, 0xE34F, 0x7B9D, 0xBAE3, 0x7BA0, 0xBD69, 0x7BA1, 0xBADE, 0x7BA4, 0xE35C, 0x7BAC, 0xE6D9, 0x7BAD, 0xBD62, 0x7BAF, 0xE6DB, 0x7BB1, 0xBD63, 0x7BB4, 0xBD65, 0x7BB5, 0xE6DE, 0x7BB7, 0xE6D6, 0x7BB8, 0xBAE6, 0x7BB9, 0xE6DC, 0x7BBE, 0xE6D8, 0x7BC0, 0xB860, 0x7BC1, 0xBD68, 0x7BC4, 0xBD64, 0x7BC6, 0xBD66, 0x7BC7, 0xBD67, 0x7BC9, 0xBF76, 0x7BCA, 0xE6DD, 0x7BCB, 0xE6D7, 0x7BCC, 0xBD6A, 0x7BCE, 0xE6DA, 0x7BD4, 0xEAC0, 0x7BD5, 0xEABB, 0x7BD8, 0xEAC5, 0x7BD9, 0xBF74, 0x7BDA, 0xEABD, 0x7BDB, 0xBF78, 0x7BDC, 0xEAC3, 0x7BDD, 0xEABA, 0x7BDE, 0xEAB7, 0x7BDF, 0xEAC6, 0x7BE0, 0xC151, 0x7BE1, 0xBF79, 0x7BE2, 0xEAC2, 0x7BE3, 0xEAB8, 0x7BE4, 0xBF77, 0x7BE5, 0xEABC, 0x7BE6, 0xBF7B, 0x7BE7, 0xEAB9, 0x7BE8, 0xEABE, 0x7BE9, 0xBF7A, 0x7BEA, 0xEAC1, 0x7BEB, 0xEAC4, 0x7BF0, 0xEDCB, 0x7BF1, 0xEDCC, 0x7BF2, 0xEDBC, 0x7BF3, 0xEDC3, 0x7BF4, 0xEDC1, 0x7BF7, 0xC14F, 0x7BF8, 0xEDC8, 0x7BF9, 0xEABF, 0x7BFB, 0xEDBF, 0x7BFD, 0xEDC9, 0x7BFE, 0xC14E, 0x7BFF, 0xEDBE, 0x7C00, 0xEDBD, 0x7C01, 0xEDC7, 0x7C02, 0xEDC4, 0x7C03, 0xEDC6, 0x7C05, 0xEDBA, 0x7C06, 0xEDCA, 0x7C07, 0xC14C, 0x7C09, 0xEDC5, 0x7C0A, 0xEDCE, 0x7C0B, 0xEDC2, 0x7C0C, 0xC150, 0x7C0D, 0xC14D, 0x7C0E, 0xEDC0, 0x7C0F, 0xEDBB, 0x7C10, 0xEDCD, 0x7C11, 0xBF75, 0x7C19, 0xF063, 0x7C1C, 0xF061, 0x7C1D, 0xF067, 0x7C1E, 0xC2B0, 0x7C1F, 0xF065, 0x7C20, 0xF064, 0x7C21, 0xC2B2, 0x7C22, 0xF06A, 0x7C23, 0xC2B1, 0x7C25, 0xF06B, 0x7C26, 0xF068, 0x7C27, 0xC2AE, 0x7C28, 0xF069, 0x7C29, 0xF062, 0x7C2A, 0xC2AF, 0x7C2B, 0xC2AD, 0x7C2C, 0xF2AB, 0x7C2D, 0xF066, 0x7C30, 0xF06C, 0x7C33, 0xF2A8, 0x7C37, 0xC3B2, 0x7C38, 0xC3B0, 0x7C39, 0xF2AA, 0x7C3B, 0xF2AC, 0x7C3C, 0xF2A9, 0x7C3D, 0xC3B1, 0x7C3E, 0xC3AE, 0x7C3F, 0xC3AF, 0x7C40, 0xC3B3, 0x7C43, 0xC478, 0x7C45, 0xF4AA, 0x7C47, 0xF4A9, 0x7C48, 0xF4A7, 0x7C49, 0xF4A6, 0x7C4A, 0xF4A8, 0x7C4C, 0xC477, 0x7C4D, 0xC479, 0x7C50, 0xC4F0, 0x7C53, 0xF5E5, 0x7C54, 0xF5E4, 0x7C57, 0xF6FA, 0x7C59, 0xF6FC, 0x7C5A, 0xF6FE, 0x7C5B, 0xF6FD, 0x7C5C, 0xF6FB, 0x7C5F, 0xC5A3, 0x7C60, 0xC5A2, 0x7C63, 0xC5D3, 0x7C64, 0xC5D2, 0x7C65, 0xC5D4, 0x7C66, 0xF7ED, 0x7C67, 0xF7EC, 0x7C69, 0xF8FB, 0x7C6A, 0xF8B8, 0x7C6B, 0xF8FC, 0x7C6C, 0xC658, 0x7C6E, 0xC659, 0x7C6F, 0xF96D, 0x7C72, 0xC67E, 0x7C73, 0xA6CC, 0x7C75, 0xCDA8, 0x7C78, 0xD045, 0x7C79, 0xD046, 0x7C7A, 0xD044, 0x7C7D, 0xACF3, 0x7C7F, 0xD047, 0x7C80, 0xD048, 0x7C81, 0xD049, 0x7C84, 0xD349, 0x7C85, 0xD34F, 0x7C88, 0xD34D, 0x7C89, 0xAFBB, 0x7C8A, 0xD34B, 0x7C8C, 0xD34C, 0x7C8D, 0xD34E, 0x7C91, 0xD34A, 0x7C92, 0xB2C9, 0x7C94, 0xD6DE, 0x7C95, 0xB2CB, 0x7C96, 0xD6E0, 0x7C97, 0xB2CA, 0x7C98, 0xD6DF, 0x7C9E, 0xDAE8, 0x7C9F, 0xB5AF, 0x7CA1, 0xDAEA, 0x7CA2, 0xDAE7, 0x7CA3, 0xD6E1, 0x7CA5, 0xB5B0, 0x7CA7, 0xF9DB, 0x7CA8, 0xDAE9, 0x7CAF, 0xDF56, 0x7CB1, 0xB864, 0x7CB2, 0xDF54, 0x7CB3, 0xB865, 0x7CB4, 0xDF55, 0x7CB5, 0xB866, 0x7CB9, 0xBAE9, 0x7CBA, 0xE361, 0x7CBB, 0xE35E, 0x7CBC, 0xE360, 0x7CBD, 0xBAEA, 0x7CBE, 0xBAEB, 0x7CBF, 0xE35F, 0x7CC5, 0xE6DF, 0x7CC8, 0xE6E0, 0x7CCA, 0xBD6B, 0x7CCB, 0xE6E2, 0x7CCC, 0xE6E1, 0x7CCE, 0xA261, 0x7CD0, 0xEACA, 0x7CD1, 0xEACB, 0x7CD2, 0xEAC7, 0x7CD4, 0xEAC8, 0x7CD5, 0xBF7C, 0x7CD6, 0xBF7D, 0x7CD7, 0xEAC9, 0x7CD9, 0xC157, 0x7CDC, 0xC153, 0x7CDD, 0xC158, 0x7CDE, 0xC154, 0x7CDF, 0xC156, 0x7CE0, 0xC152, 0x7CE2, 0xC155, 0x7CE7, 0xC2B3, 0x7CE8, 0xEDCF, 0x7CEA, 0xF2AE, 0x7CEC, 0xF2AD, 0x7CEE, 0xF4AB, 0x7CEF, 0xC47A, 0x7CF0, 0xC47B, 0x7CF1, 0xF741, 0x7CF2, 0xF5E6, 0x7CF4, 0xF740, 0x7CF6, 0xF8FD, 0x7CF7, 0xF9A4, 0x7CF8, 0xA6CD, 0x7CFB, 0xA874, 0x7CFD, 0xCDA9, 0x7CFE, 0xAAC8, 0x7D00, 0xACF6, 0x7D01, 0xD04C, 0x7D02, 0xACF4, 0x7D03, 0xD04A, 0x7D04, 0xACF9, 0x7D05, 0xACF5, 0x7D06, 0xACFA, 0x7D07, 0xACF8, 0x7D08, 0xD04B, 0x7D09, 0xACF7, 0x7D0A, 0xAFBF, 0x7D0B, 0xAFBE, 0x7D0C, 0xD35A, 0x7D0D, 0xAFC7, 0x7D0E, 0xD353, 0x7D0F, 0xD359, 0x7D10, 0xAFC3, 0x7D11, 0xD352, 0x7D12, 0xD358, 0x7D13, 0xD356, 0x7D14, 0xAFC2, 0x7D15, 0xAFC4, 0x7D16, 0xD355, 0x7D17, 0xAFBD, 0x7D18, 0xD354, 0x7D19, 0xAFC8, 0x7D1A, 0xAFC5, 0x7D1B, 0xAFC9, 0x7D1C, 0xAFC6, 0x7D1D, 0xD351, 0x7D1E, 0xD350, 0x7D1F, 0xD357, 0x7D20, 0xAFC0, 0x7D21, 0xAFBC, 0x7D22, 0xAFC1, 0x7D28, 0xD6F0, 0x7D29, 0xD6E9, 0x7D2B, 0xB5B5, 0x7D2C, 0xD6E8, 0x7D2E, 0xB2CF, 0x7D2F, 0xB2D6, 0x7D30, 0xB2D3, 0x7D31, 0xB2D9, 0x7D32, 0xB2D8, 0x7D33, 0xB2D4, 0x7D35, 0xD6E2, 0x7D36, 0xD6E5, 0x7D38, 0xD6E4, 0x7D39, 0xB2D0, 0x7D3A, 0xD6E6, 0x7D3B, 0xD6EF, 0x7D3C, 0xB2D1, 0x7D3D, 0xD6E3, 0x7D3E, 0xD6EC, 0x7D3F, 0xD6ED, 0x7D40, 0xB2D2, 0x7D41, 0xD6EA, 0x7D42, 0xB2D7, 0x7D43, 0xB2CD, 0x7D44, 0xB2D5, 0x7D45, 0xD6E7, 0x7D46, 0xB2CC, 0x7D47, 0xD6EB, 0x7D4A, 0xD6EE, 0x7D4E, 0xDAFB, 0x7D4F, 0xDAF2, 0x7D50, 0xB5B2, 0x7D51, 0xDAF9, 0x7D52, 0xDAF6, 0x7D53, 0xDAEE, 0x7D54, 0xDAF7, 0x7D55, 0xB5B4, 0x7D56, 0xDAEF, 0x7D58, 0xDAEB, 0x7D5B, 0xB86C, 0x7D5C, 0xDAF4, 0x7D5E, 0xB5B1, 0x7D5F, 0xDAFA, 0x7D61, 0xB5B8, 0x7D62, 0xB5BA, 0x7D63, 0xDAED, 0x7D66, 0xB5B9, 0x7D67, 0xDAF0, 0x7D68, 0xB5B3, 0x7D69, 0xDAF8, 0x7D6A, 0xDAF1, 0x7D6B, 0xDAF5, 0x7D6D, 0xDAF3, 0x7D6E, 0xB5B6, 0x7D6F, 0xDAEC, 0x7D70, 0xB5BB, 0x7D71, 0xB2CE, 0x7D72, 0xB5B7, 0x7D73, 0xB5BC, 0x7D79, 0xB868, 0x7D7A, 0xDF5D, 0x7D7B, 0xDF5F, 0x7D7C, 0xDF61, 0x7D7D, 0xDF65, 0x7D7F, 0xDF5B, 0x7D80, 0xDF59, 0x7D81, 0xB86A, 0x7D83, 0xDF60, 0x7D84, 0xDF64, 0x7D85, 0xDF5C, 0x7D86, 0xDF58, 0x7D88, 0xDF57, 0x7D8C, 0xDF62, 0x7D8D, 0xDF5A, 0x7D8E, 0xDF5E, 0x7D8F, 0xB86B, 0x7D91, 0xB869, 0x7D92, 0xDF66, 0x7D93, 0xB867, 0x7D94, 0xDF63, 0x7D96, 0xE372, 0x7D9C, 0xBAEE, 0x7D9D, 0xE36A, 0x7D9E, 0xBD78, 0x7D9F, 0xE374, 0x7DA0, 0xBAF1, 0x7DA1, 0xE378, 0x7DA2, 0xBAF7, 0x7DA3, 0xE365, 0x7DA6, 0xE375, 0x7DA7, 0xE362, 0x7DA9, 0xE377, 0x7DAA, 0xE366, 0x7DAC, 0xBAFE, 0x7DAD, 0xBAFB, 0x7DAE, 0xE376, 0x7DAF, 0xE370, 0x7DB0, 0xBAED, 0x7DB1, 0xBAF5, 0x7DB2, 0xBAF4, 0x7DB4, 0xBAF3, 0x7DB5, 0xBAF9, 0x7DB7, 0xE363, 0x7DB8, 0xBAFA, 0x7DB9, 0xE371, 0x7DBA, 0xBAF6, 0x7DBB, 0xBAEC, 0x7DBC, 0xE373, 0x7DBD, 0xBAEF, 0x7DBE, 0xBAF0, 0x7DBF, 0xBAF8, 0x7DC0, 0xE368, 0x7DC1, 0xE367, 0x7DC2, 0xE364, 0x7DC4, 0xE36C, 0x7DC5, 0xE369, 0x7DC6, 0xE36D, 0x7DC7, 0xBAFD, 0x7DC9, 0xE379, 0x7DCA, 0xBAF2, 0x7DCB, 0xE36E, 0x7DCC, 0xE36F, 0x7DCE, 0xE36B, 0x7DD2, 0xBAFC, 0x7DD7, 0xE6E7, 0x7DD8, 0xBD70, 0x7DD9, 0xBD79, 0x7DDA, 0xBD75, 0x7DDB, 0xE6E4, 0x7DDD, 0xBD72, 0x7DDE, 0xBD76, 0x7DDF, 0xE6F0, 0x7DE0, 0xBD6C, 0x7DE1, 0xE6E8, 0x7DE3, 0xBD74, 0x7DE6, 0xE6EB, 0x7DE7, 0xE6E6, 0x7DE8, 0xBD73, 0x7DE9, 0xBD77, 0x7DEA, 0xE6E5, 0x7DEC, 0xBD71, 0x7DEE, 0xE6EF, 0x7DEF, 0xBD6E, 0x7DF0, 0xE6EE, 0x7DF1, 0xE6ED, 0x7DF2, 0xBD7A, 0x7DF3, 0xE572, 0x7DF4, 0xBD6D, 0x7DF6, 0xE6EC, 0x7DF7, 0xE6E3, 0x7DF9, 0xBD7B, 0x7DFA, 0xE6EA, 0x7DFB, 0xBD6F, 0x7E03, 0xE6E9, 0x7E08, 0xBFA2, 0x7E09, 0xBFA7, 0x7E0A, 0xBF7E, 0x7E0B, 0xEAD8, 0x7E0C, 0xEACF, 0x7E0D, 0xEADB, 0x7E0E, 0xEAD3, 0x7E0F, 0xEAD9, 0x7E10, 0xBFA8, 0x7E11, 0xBFA1, 0x7E12, 0xEACC, 0x7E13, 0xEAD2, 0x7E14, 0xEADC, 0x7E15, 0xEAD5, 0x7E16, 0xEADA, 0x7E17, 0xEACE, 0x7E1A, 0xEAD6, 0x7E1B, 0xBFA3, 0x7E1C, 0xEAD4, 0x7E1D, 0xBFA6, 0x7E1E, 0xBFA5, 0x7E1F, 0xEAD0, 0x7E20, 0xEAD1, 0x7E21, 0xEACD, 0x7E22, 0xEAD7, 0x7E23, 0xBFA4, 0x7E24, 0xEADE, 0x7E25, 0xEADD, 0x7E29, 0xEDDA, 0x7E2A, 0xEDD6, 0x7E2B, 0xC15F, 0x7E2D, 0xEDD0, 0x7E2E, 0xC159, 0x7E2F, 0xC169, 0x7E30, 0xEDDC, 0x7E31, 0xC161, 0x7E32, 0xC15D, 0x7E33, 0xEDD3, 0x7E34, 0xC164, 0x7E35, 0xC167, 0x7E36, 0xEDDE, 0x7E37, 0xC15C, 0x7E38, 0xEDD5, 0x7E39, 0xC165, 0x7E3A, 0xEDE0, 0x7E3B, 0xEDDD, 0x7E3C, 0xEDD1, 0x7E3D, 0xC160, 0x7E3E, 0xC15A, 0x7E3F, 0xC168, 0x7E40, 0xEDD8, 0x7E41, 0xC163, 0x7E42, 0xEDD2, 0x7E43, 0xC15E, 0x7E44, 0xEDDF, 0x7E45, 0xC162, 0x7E46, 0xC15B, 0x7E47, 0xEDD9, 0x7E48, 0xC166, 0x7E49, 0xEDD7, 0x7E4C, 0xEDDB, 0x7E50, 0xF06E, 0x7E51, 0xF074, 0x7E52, 0xC2B9, 0x7E53, 0xF077, 0x7E54, 0xC2B4, 0x7E55, 0xC2B5, 0x7E56, 0xF06F, 0x7E57, 0xF076, 0x7E58, 0xF071, 0x7E59, 0xC2BA, 0x7E5A, 0xC2B7, 0x7E5C, 0xF06D, 0x7E5E, 0xC2B6, 0x7E5F, 0xF073, 0x7E60, 0xF075, 0x7E61, 0xC2B8, 0x7E62, 0xF072, 0x7E63, 0xF070, 0x7E68, 0xF2B8, 0x7E69, 0xC3B7, 0x7E6A, 0xC3B8, 0x7E6B, 0xC3B4, 0x7E6D, 0xC3B5, 0x7E6F, 0xF2B4, 0x7E70, 0xF2B2, 0x7E72, 0xF2B6, 0x7E73, 0xC3BA, 0x7E74, 0xF2B7, 0x7E75, 0xF2B0, 0x7E76, 0xF2AF, 0x7E77, 0xF2B3, 0x7E78, 0xF2B1, 0x7E79, 0xC3B6, 0x7E7A, 0xF2B5, 0x7E7B, 0xF4AC, 0x7E7C, 0xC47E, 0x7E7D, 0xC47D, 0x7E7E, 0xF4AD, 0x7E80, 0xF4AF, 0x7E81, 0xF4AE, 0x7E82, 0xC4A1, 0x7E86, 0xF5EB, 0x7E87, 0xF5E8, 0x7E88, 0xF5E9, 0x7E8A, 0xF5E7, 0x7E8B, 0xF5EA, 0x7E8C, 0xC4F2, 0x7E8D, 0xF5EC, 0x7E8F, 0xC4F1, 0x7E91, 0xF742, 0x7E93, 0xC5D5, 0x7E94, 0xC5D7, 0x7E95, 0xF7EE, 0x7E96, 0xC5D6, 0x7E97, 0xF8B9, 0x7E98, 0xF940, 0x7E99, 0xF942, 0x7E9A, 0xF8FE, 0x7E9B, 0xF941, 0x7E9C, 0xC66C, 0x7F36, 0xA6CE, 0x7F38, 0xACFB, 0x7F39, 0xD26F, 0x7F3A, 0xAFCA, 0x7F3D, 0xB2DA, 0x7F3E, 0xDAFC, 0x7F3F, 0xDAFD, 0x7F43, 0xEADF, 0x7F44, 0xC16A, 0x7F45, 0xEDE1, 0x7F48, 0xC2BB, 0x7F4A, 0xF2BA, 0x7F4B, 0xF2B9, 0x7F4C, 0xC4A2, 0x7F4D, 0xF5ED, 0x7F4F, 0xF743, 0x7F50, 0xC5F8, 0x7F51, 0xCA49, 0x7F54, 0xAAC9, 0x7F55, 0xA875, 0x7F58, 0xD04D, 0x7F5B, 0xD360, 0x7F5C, 0xD35B, 0x7F5D, 0xD35F, 0x7F5E, 0xD35D, 0x7F5F, 0xAFCB, 0x7F60, 0xD35E, 0x7F61, 0xD35C, 0x7F63, 0xD6F1, 0x7F65, 0xDAFE, 0x7F66, 0xDB40, 0x7F67, 0xDF69, 0x7F68, 0xDF6A, 0x7F69, 0xB86E, 0x7F6A, 0xB86F, 0x7F6B, 0xDF68, 0x7F6C, 0xDF6B, 0x7F6D, 0xDF67, 0x7F6E, 0xB86D, 0x7F70, 0xBB40, 0x7F72, 0xB870, 0x7F73, 0xE37A, 0x7F75, 0xBD7C, 0x7F76, 0xE6F1, 0x7F77, 0xBD7D, 0x7F79, 0xBFA9, 0x7F7A, 0xEAE2, 0x7F7B, 0xEAE0, 0x7F7C, 0xEAE1, 0x7F7D, 0xEDE4, 0x7F7E, 0xEDE3, 0x7F7F, 0xEDE2, 0x7F83, 0xF2BB, 0x7F85, 0xC3B9, 0x7F86, 0xF2BC, 0x7F87, 0xF744, 0x7F88, 0xC5F9, 0x7F89, 0xF8BA, 0x7F8A, 0xA6CF, 0x7F8B, 0xAACB, 0x7F8C, 0xAACA, 0x7F8D, 0xD04F, 0x7F8E, 0xACFC, 0x7F91, 0xD04E, 0x7F92, 0xD362, 0x7F94, 0xAFCC, 0x7F95, 0xD6F2, 0x7F96, 0xD361, 0x7F9A, 0xB2DC, 0x7F9B, 0xD6F5, 0x7F9C, 0xD6F3, 0x7F9D, 0xD6F4, 0x7F9E, 0xB2DB, 0x7FA0, 0xDB42, 0x7FA1, 0xDB43, 0x7FA2, 0xDB41, 0x7FA4, 0xB873, 0x7FA5, 0xDF6D, 0x7FA6, 0xDF6C, 0x7FA7, 0xDF6E, 0x7FA8, 0xB872, 0x7FA9, 0xB871, 0x7FAC, 0xE6F2, 0x7FAD, 0xE6F4, 0x7FAF, 0xBD7E, 0x7FB0, 0xE6F3, 0x7FB1, 0xEAE3, 0x7FB2, 0xBFAA, 0x7FB3, 0xF079, 0x7FB5, 0xF078, 0x7FB6, 0xC3BB, 0x7FB7, 0xF2BD, 0x7FB8, 0xC3BD, 0x7FB9, 0xC3BC, 0x7FBA, 0xF4B0, 0x7FBB, 0xF5EE, 0x7FBC, 0xC4F3, 0x7FBD, 0xA6D0, 0x7FBE, 0xD050, 0x7FBF, 0xACFD, 0x7FC0, 0xD365, 0x7FC1, 0xAFCE, 0x7FC2, 0xD364, 0x7FC3, 0xD363, 0x7FC5, 0xAFCD, 0x7FC7, 0xD6FB, 0x7FC9, 0xD6FD, 0x7FCA, 0xD6F6, 0x7FCB, 0xD6F7, 0x7FCC, 0xB2DD, 0x7FCD, 0xD6F8, 0x7FCE, 0xB2DE, 0x7FCF, 0xD6FC, 0x7FD0, 0xD6F9, 0x7FD1, 0xD6FA, 0x7FD2, 0xB2DF, 0x7FD4, 0xB5BE, 0x7FD5, 0xB5BF, 0x7FD7, 0xDB44, 0x7FDB, 0xDF6F, 0x7FDC, 0xDF70, 0x7FDE, 0xE37E, 0x7FDF, 0xBB43, 0x7FE0, 0xBB41, 0x7FE1, 0xBB42, 0x7FE2, 0xE37B, 0x7FE3, 0xE37C, 0x7FE5, 0xE37D, 0x7FE6, 0xE6F9, 0x7FE8, 0xE6FA, 0x7FE9, 0xBDA1, 0x7FEA, 0xE6F7, 0x7FEB, 0xE6F6, 0x7FEC, 0xE6F8, 0x7FED, 0xE6F5, 0x7FEE, 0xBFAD, 0x7FEF, 0xEAE4, 0x7FF0, 0xBFAB, 0x7FF1, 0xBFAC, 0x7FF2, 0xEDE6, 0x7FF3, 0xC16B, 0x7FF4, 0xEDE5, 0x7FF5, 0xEFA8, 0x7FF7, 0xF07A, 0x7FF8, 0xF07B, 0x7FF9, 0xC2BC, 0x7FFB, 0xC2BD, 0x7FFC, 0xC16C, 0x7FFD, 0xF2BE, 0x7FFE, 0xF2BF, 0x7FFF, 0xF4B1, 0x8000, 0xC4A3, 0x8001, 0xA6D1, 0x8003, 0xA6D2, 0x8004, 0xACFE, 0x8005, 0xAACC, 0x8006, 0xAFCF, 0x8007, 0xD051, 0x800B, 0xB5C0, 0x800C, 0xA6D3, 0x800D, 0xAD41, 0x800E, 0xD052, 0x800F, 0xD053, 0x8010, 0xAD40, 0x8011, 0xAD42, 0x8012, 0xA6D4, 0x8014, 0xD054, 0x8015, 0xAFD1, 0x8016, 0xD366, 0x8017, 0xAFD3, 0x8018, 0xAFD0, 0x8019, 0xAFD2, 0x801B, 0xD741, 0x801C, 0xB2E0, 0x801E, 0xD740, 0x801F, 0xD6FE, 0x8021, 0xDF71, 0x8024, 0xE3A1, 0x8026, 0xBDA2, 0x8028, 0xBFAE, 0x8029, 0xEAE6, 0x802A, 0xEAE5, 0x802C, 0xEDE7, 0x8030, 0xF5EF, 0x8033, 0xA6D5, 0x8034, 0xCB73, 0x8035, 0xCDAA, 0x8036, 0xAD43, 0x8037, 0xD055, 0x8039, 0xD368, 0x803D, 0xAFD4, 0x803E, 0xD367, 0x803F, 0xAFD5, 0x8043, 0xD743, 0x8046, 0xB2E2, 0x8047, 0xD742, 0x8048, 0xD744, 0x804A, 0xB2E1, 0x804F, 0xDB46, 0x8050, 0xDB47, 0x8051, 0xDB45, 0x8052, 0xB5C1, 0x8056, 0xB874, 0x8058, 0xB875, 0x805A, 0xBB45, 0x805C, 0xE3A3, 0x805D, 0xE3A2, 0x805E, 0xBB44, 0x8064, 0xE6FB, 0x8067, 0xE6FC, 0x806C, 0xEAE7, 0x806F, 0xC170, 0x8070, 0xC16F, 0x8071, 0xC16D, 0x8072, 0xC16E, 0x8073, 0xC171, 0x8075, 0xF07C, 0x8076, 0xC2BF, 0x8077, 0xC2BE, 0x8078, 0xF2C0, 0x8079, 0xF4B2, 0x807D, 0xC5A5, 0x807E, 0xC5A4, 0x807F, 0xA6D6, 0x8082, 0xD1FB, 0x8084, 0xB877, 0x8085, 0xB5C2, 0x8086, 0xB876, 0x8087, 0xBB46, 0x8089, 0xA6D7, 0x808A, 0xC9A9, 0x808B, 0xA6D8, 0x808C, 0xA6D9, 0x808F, 0xCDAB, 0x8090, 0xCB76, 0x8092, 0xCB77, 0x8093, 0xA877, 0x8095, 0xCB74, 0x8096, 0xA876, 0x8098, 0xA879, 0x8099, 0xCB75, 0x809A, 0xA87B, 0x809B, 0xA87A, 0x809C, 0xCB78, 0x809D, 0xA878, 0x80A1, 0xAAD1, 0x80A2, 0xAACF, 0x80A3, 0xCDAD, 0x80A5, 0xAACE, 0x80A9, 0xAAD3, 0x80AA, 0xAAD5, 0x80AB, 0xAAD2, 0x80AD, 0xCDB0, 0x80AE, 0xCDAC, 0x80AF, 0xAAD6, 0x80B1, 0xAAD0, 0x80B2, 0xA87C, 0x80B4, 0xAAD4, 0x80B5, 0xCDAF, 0x80B8, 0xCDAE, 0x80BA, 0xAACD, 0x80C2, 0xD05B, 0x80C3, 0xAD47, 0x80C4, 0xAD48, 0x80C5, 0xD05D, 0x80C7, 0xD057, 0x80C8, 0xD05A, 0x80C9, 0xD063, 0x80CA, 0xD061, 0x80CC, 0xAD49, 0x80CD, 0xD067, 0x80CE, 0xAD4C, 0x80CF, 0xD064, 0x80D0, 0xD05C, 0x80D1, 0xD059, 0x80D4, 0xDB49, 0x80D5, 0xD062, 0x80D6, 0xAD44, 0x80D7, 0xD065, 0x80D8, 0xD056, 0x80D9, 0xD05F, 0x80DA, 0xAD46, 0x80DB, 0xAD4B, 0x80DC, 0xD060, 0x80DD, 0xAD4F, 0x80DE, 0xAD4D, 0x80E0, 0xD058, 0x80E1, 0xAD4A, 0x80E3, 0xD05E, 0x80E4, 0xAD4E, 0x80E5, 0xAD45, 0x80E6, 0xD066, 0x80ED, 0xAFDA, 0x80EF, 0xAFE3, 0x80F0, 0xAFD8, 0x80F1, 0xAFD6, 0x80F2, 0xD36A, 0x80F3, 0xAFDE, 0x80F4, 0xAFDB, 0x80F5, 0xD36C, 0x80F8, 0xAFDD, 0x80F9, 0xD36B, 0x80FA, 0xD369, 0x80FB, 0xD36E, 0x80FC, 0xAFE2, 0x80FD, 0xAFE0, 0x80FE, 0xDB48, 0x8100, 0xD36F, 0x8101, 0xD36D, 0x8102, 0xAFD7, 0x8105, 0xAFD9, 0x8106, 0xAFDC, 0x8108, 0xAFDF, 0x810A, 0xAFE1, 0x8115, 0xD74E, 0x8116, 0xB2E4, 0x8118, 0xD745, 0x8119, 0xD747, 0x811B, 0xD748, 0x811D, 0xD750, 0x811E, 0xD74C, 0x811F, 0xD74A, 0x8121, 0xD74D, 0x8122, 0xD751, 0x8123, 0xB2E5, 0x8124, 0xB2E9, 0x8125, 0xD746, 0x8127, 0xD74F, 0x8129, 0xB2E7, 0x812B, 0xB2E6, 0x812C, 0xD74B, 0x812D, 0xD749, 0x812F, 0xB2E3, 0x8130, 0xB2E8, 0x8139, 0xB5C8, 0x813A, 0xDB51, 0x813D, 0xDB4F, 0x813E, 0xB5CA, 0x8143, 0xDB4A, 0x8144, 0xDFA1, 0x8146, 0xB5C9, 0x8147, 0xDB4E, 0x814A, 0xDB4B, 0x814B, 0xB5C5, 0x814C, 0xB5CB, 0x814D, 0xDB50, 0x814E, 0xB5C7, 0x814F, 0xDB4D, 0x8150, 0xBB47, 0x8151, 0xB5C6, 0x8152, 0xDB4C, 0x8153, 0xB5CC, 0x8154, 0xB5C4, 0x8155, 0xB5C3, 0x815B, 0xDF77, 0x815C, 0xDF75, 0x815E, 0xDF7B, 0x8160, 0xDF73, 0x8161, 0xDFA2, 0x8162, 0xDF78, 0x8164, 0xDF72, 0x8165, 0xB87B, 0x8166, 0xB8A3, 0x8167, 0xDF7D, 0x8169, 0xDF76, 0x816B, 0xB87E, 0x816E, 0xB87C, 0x816F, 0xDF7E, 0x8170, 0xB879, 0x8171, 0xB878, 0x8172, 0xDF79, 0x8173, 0xB87D, 0x8174, 0xB5CD, 0x8176, 0xDF7C, 0x8177, 0xDF74, 0x8178, 0xB87A, 0x8179, 0xB8A1, 0x817A, 0xB8A2, 0x817F, 0xBB4C, 0x8180, 0xBB48, 0x8182, 0xBB4D, 0x8183, 0xE3A6, 0x8186, 0xE3A5, 0x8187, 0xE3A7, 0x8188, 0xBB4A, 0x8189, 0xE3A4, 0x818A, 0xBB4B, 0x818B, 0xE3AA, 0x818C, 0xE3A9, 0x818D, 0xE3A8, 0x818F, 0xBB49, 0x8195, 0xE741, 0x8197, 0xE744, 0x8198, 0xBDA8, 0x8199, 0xE743, 0x819A, 0xBDA7, 0x819B, 0xBDA3, 0x819C, 0xBDA4, 0x819D, 0xBDA5, 0x819E, 0xE740, 0x819F, 0xE6FE, 0x81A0, 0xBDA6, 0x81A2, 0xE742, 0x81A3, 0xE6FD, 0x81A6, 0xEAE9, 0x81A7, 0xEAF3, 0x81A8, 0xBFB1, 0x81A9, 0xBFB0, 0x81AB, 0xEAED, 0x81AC, 0xEAEF, 0x81AE, 0xEAEA, 0x81B0, 0xEAEE, 0x81B1, 0xEAE8, 0x81B2, 0xEAF1, 0x81B3, 0xBFAF, 0x81B4, 0xEAF0, 0x81B5, 0xEAEC, 0x81B7, 0xEAF2, 0x81B9, 0xEAEB, 0x81BA, 0xC174, 0x81BB, 0xEDE8, 0x81BC, 0xEDEE, 0x81BD, 0xC178, 0x81BE, 0xC17A, 0x81BF, 0xC177, 0x81C0, 0xC176, 0x81C2, 0xC175, 0x81C3, 0xC173, 0x81C4, 0xEDE9, 0x81C5, 0xEDEC, 0x81C6, 0xC172, 0x81C7, 0xEDED, 0x81C9, 0xC179, 0x81CA, 0xEDEB, 0x81CC, 0xEDEA, 0x81CD, 0xC2C0, 0x81CF, 0xC2C1, 0x81D0, 0xF0A1, 0x81D1, 0xF07D, 0x81D2, 0xF07E, 0x81D5, 0xF2C2, 0x81D7, 0xF2C1, 0x81D8, 0xC3BE, 0x81D9, 0xF4B4, 0x81DA, 0xC4A4, 0x81DB, 0xF4B3, 0x81DD, 0xF5F0, 0x81DE, 0xF745, 0x81DF, 0xC5A6, 0x81E0, 0xF943, 0x81E1, 0xF944, 0x81E2, 0xC5D8, 0x81E3, 0xA6DA, 0x81E5, 0xAAD7, 0x81E6, 0xDB52, 0x81E7, 0xBB4E, 0x81E8, 0xC17B, 0x81E9, 0xEDEF, 0x81EA, 0xA6DB, 0x81EC, 0xAFE5, 0x81ED, 0xAFE4, 0x81EE, 0xDB53, 0x81F2, 0xEAF4, 0x81F3, 0xA6DC, 0x81F4, 0xAD50, 0x81F7, 0xDB54, 0x81F8, 0xDB55, 0x81F9, 0xDB56, 0x81FA, 0xBB4F, 0x81FB, 0xBFB2, 0x81FC, 0xA6DD, 0x81FE, 0xAAD8, 0x81FF, 0xD068, 0x8200, 0xAFE6, 0x8201, 0xD370, 0x8202, 0xB2EA, 0x8204, 0xDB57, 0x8205, 0xB8A4, 0x8207, 0xBB50, 0x8208, 0xBFB3, 0x8209, 0xC17C, 0x820A, 0xC2C2, 0x820B, 0xF4B5, 0x820C, 0xA6DE, 0x820D, 0xAAD9, 0x8210, 0xAFE7, 0x8211, 0xD752, 0x8212, 0xB5CE, 0x8214, 0xBB51, 0x8215, 0xE3AB, 0x8216, 0xE745, 0x821B, 0xA6DF, 0x821C, 0xB5CF, 0x821D, 0xDFA3, 0x821E, 0xBB52, 0x821F, 0xA6E0, 0x8220, 0xCDB1, 0x8221, 0xD069, 0x8222, 0xAD51, 0x8225, 0xD372, 0x8228, 0xAFEA, 0x822A, 0xAFE8, 0x822B, 0xAFE9, 0x822C, 0xAFEB, 0x822F, 0xD371, 0x8232, 0xD757, 0x8233, 0xD754, 0x8234, 0xD756, 0x8235, 0xB2EB, 0x8236, 0xB2ED, 0x8237, 0xB2EC, 0x8238, 0xD753, 0x8239, 0xB2EE, 0x823A, 0xD755, 0x823C, 0xDB58, 0x823D, 0xDB59, 0x823F, 0xDB5A, 0x8240, 0xDFA6, 0x8242, 0xDFA7, 0x8244, 0xDFA5, 0x8245, 0xDFA8, 0x8247, 0xB8A5, 0x8249, 0xDFA4, 0x824B, 0xBB53, 0x824E, 0xE74A, 0x824F, 0xE746, 0x8250, 0xE749, 0x8251, 0xE74B, 0x8252, 0xE748, 0x8253, 0xE747, 0x8255, 0xEAF5, 0x8256, 0xEAF6, 0x8257, 0xEAF7, 0x8258, 0xBFB4, 0x8259, 0xBFB5, 0x825A, 0xEDF1, 0x825B, 0xEDF0, 0x825C, 0xEDF2, 0x825E, 0xF0A3, 0x825F, 0xF0A2, 0x8261, 0xF2C4, 0x8263, 0xF2C5, 0x8264, 0xF2C3, 0x8266, 0xC4A5, 0x8268, 0xF4B6, 0x8269, 0xF4B7, 0x826B, 0xF746, 0x826C, 0xF7EF, 0x826D, 0xF8BB, 0x826E, 0xA6E1, 0x826F, 0xA87D, 0x8271, 0xC17D, 0x8272, 0xA6E2, 0x8274, 0xD758, 0x8275, 0xDB5B, 0x8277, 0xC641, 0x8278, 0xCA4A, 0x827C, 0xCA4B, 0x827D, 0xCA4D, 0x827E, 0xA6E3, 0x827F, 0xCA4E, 0x8280, 0xCA4C, 0x8283, 0xCBA2, 0x8284, 0xCBA3, 0x8285, 0xCB7B, 0x828A, 0xCBA1, 0x828B, 0xA8A1, 0x828D, 0xA8A2, 0x828E, 0xCB7C, 0x828F, 0xCB7A, 0x8290, 0xCB79, 0x8291, 0xCB7D, 0x8292, 0xA87E, 0x8293, 0xCB7E, 0x8294, 0xD06A, 0x8298, 0xCDB6, 0x8299, 0xAADC, 0x829A, 0xCDB5, 0x829B, 0xCDB7, 0x829D, 0xAADB, 0x829E, 0xCDBC, 0x829F, 0xAADF, 0x82A0, 0xCDB2, 0x82A1, 0xCDC0, 0x82A2, 0xCDC6, 0x82A3, 0xAAE6, 0x82A4, 0xCDC3, 0x82A5, 0xAAE3, 0x82A7, 0xCDB9, 0x82A8, 0xCDBF, 0x82A9, 0xCDC1, 0x82AB, 0xCDB4, 0x82AC, 0xAAE2, 0x82AD, 0xAADD, 0x82AE, 0xCDBA, 0x82AF, 0xAAE4, 0x82B0, 0xAAE7, 0x82B1, 0xAAE1, 0x82B3, 0xAADA, 0x82B4, 0xCDBE, 0x82B5, 0xCDB8, 0x82B6, 0xCDC5, 0x82B7, 0xAAE9, 0x82B8, 0xAAE5, 0x82B9, 0xAAE0, 0x82BA, 0xCDBD, 0x82BB, 0xAFEC, 0x82BC, 0xCDBB, 0x82BD, 0xAADE, 0x82BE, 0xAAE8, 0x82C0, 0xCDB3, 0x82C2, 0xCDC2, 0x82C3, 0xCDC4, 0x82D1, 0xAD62, 0x82D2, 0xAD5C, 0x82D3, 0xAD64, 0x82D4, 0xAD61, 0x82D5, 0xD071, 0x82D6, 0xD074, 0x82D7, 0xAD5D, 0x82D9, 0xD06B, 0x82DB, 0xAD56, 0x82DC, 0xAD60, 0x82DE, 0xAD63, 0x82DF, 0xAD65, 0x82E0, 0xD0A2, 0x82E1, 0xD077, 0x82E3, 0xAD55, 0x82E4, 0xD0A1, 0x82E5, 0xAD59, 0x82E6, 0xAD57, 0x82E7, 0xAD52, 0x82E8, 0xD06F, 0x82EA, 0xD07E, 0x82EB, 0xD073, 0x82EC, 0xD076, 0x82ED, 0xD0A5, 0x82EF, 0xAD66, 0x82F0, 0xD07D, 0x82F1, 0xAD5E, 0x82F2, 0xD078, 0x82F3, 0xD0A4, 0x82F4, 0xD075, 0x82F5, 0xD079, 0x82F6, 0xD07C, 0x82F9, 0xD06D, 0x82FA, 0xD0A3, 0x82FB, 0xD07B, 0x82FE, 0xD06C, 0x8300, 0xD070, 0x8301, 0xAD5F, 0x8302, 0xAD5A, 0x8303, 0xAD53, 0x8304, 0xAD58, 0x8305, 0xAD54, 0x8306, 0xAD67, 0x8307, 0xD06E, 0x8308, 0xD3A5, 0x8309, 0xAD5B, 0x830C, 0xD07A, 0x830D, 0xCE41, 0x8316, 0xD3A8, 0x8317, 0xAFFA, 0x8319, 0xD376, 0x831B, 0xD3A3, 0x831C, 0xD37D, 0x831E, 0xD3B2, 0x8320, 0xD3AA, 0x8322, 0xD37E, 0x8324, 0xD3A9, 0x8325, 0xD378, 0x8326, 0xD37C, 0x8327, 0xD3B5, 0x8328, 0xAFFD, 0x8329, 0xD3AD, 0x832A, 0xD3A4, 0x832B, 0xAFED, 0x832C, 0xD3B3, 0x832D, 0xD374, 0x832F, 0xD3AC, 0x8331, 0xAFFC, 0x8332, 0xAFF7, 0x8333, 0xD373, 0x8334, 0xAFF5, 0x8335, 0xAFF4, 0x8336, 0xAFF9, 0x8337, 0xD3AB, 0x8338, 0xAFF1, 0x8339, 0xAFF8, 0x833A, 0xD072, 0x833B, 0xDB5C, 0x833C, 0xD3A6, 0x833F, 0xD37A, 0x8340, 0xAFFB, 0x8341, 0xD37B, 0x8342, 0xD3A1, 0x8343, 0xAFFE, 0x8344, 0xD375, 0x8345, 0xD3AF, 0x8347, 0xD3AE, 0x8348, 0xD3B6, 0x8349, 0xAFF3, 0x834A, 0xAFF0, 0x834B, 0xD3B4, 0x834C, 0xD3B0, 0x834D, 0xD3A7, 0x834E, 0xD3A2, 0x834F, 0xAFF6, 0x8350, 0xAFF2, 0x8351, 0xD377, 0x8352, 0xAFEE, 0x8353, 0xD3B1, 0x8354, 0xAFEF, 0x8356, 0xD379, 0x8373, 0xD75E, 0x8374, 0xD760, 0x8375, 0xD765, 0x8376, 0xD779, 0x8377, 0xB2FC, 0x8378, 0xB2F2, 0x837A, 0xD75D, 0x837B, 0xB2FD, 0x837C, 0xB2FE, 0x837D, 0xD768, 0x837E, 0xD76F, 0x837F, 0xD775, 0x8381, 0xD762, 0x8383, 0xD769, 0x8386, 0xB340, 0x8387, 0xD777, 0x8388, 0xD772, 0x8389, 0xB2FA, 0x838A, 0xB2F8, 0x838B, 0xD76E, 0x838C, 0xD76A, 0x838D, 0xD75C, 0x838E, 0xB2EF, 0x838F, 0xD761, 0x8390, 0xD759, 0x8392, 0xB2F7, 0x8393, 0xB2F9, 0x8394, 0xD766, 0x8395, 0xD763, 0x8396, 0xB2F4, 0x8397, 0xD773, 0x8398, 0xB2F1, 0x8399, 0xD764, 0x839A, 0xD77A, 0x839B, 0xD76C, 0x839D, 0xD76B, 0x839E, 0xB2F0, 0x83A0, 0xB2FB, 0x83A2, 0xB2F3, 0x83A3, 0xD75A, 0x83A4, 0xD75F, 0x83A5, 0xD770, 0x83A6, 0xD776, 0x83A7, 0xB341, 0x83A8, 0xD75B, 0x83A9, 0xD767, 0x83AA, 0xD76D, 0x83AB, 0xB2F6, 0x83AE, 0xD778, 0x83AF, 0xD771, 0x83B0, 0xD774, 0x83BD, 0xB2F5, 0x83BF, 0xDB6C, 0x83C0, 0xDB60, 0x83C1, 0xB5D7, 0x83C2, 0xDB7D, 0x83C3, 0xDBA7, 0x83C4, 0xDBAA, 0x83C5, 0xB5D5, 0x83C6, 0xDB68, 0x83C7, 0xDBA3, 0x83C8, 0xDB69, 0x83C9, 0xDB77, 0x83CA, 0xB5E2, 0x83CB, 0xDB73, 0x83CC, 0xB5DF, 0x83CE, 0xDB74, 0x83CF, 0xDB5D, 0x83D1, 0xDBA4, 0x83D4, 0xB5E8, 0x83D5, 0xDBA1, 0x83D6, 0xDB75, 0x83D7, 0xDBAC, 0x83D8, 0xDB70, 0x83D9, 0xDFC8, 0x83DB, 0xDBAF, 0x83DC, 0xB5E6, 0x83DD, 0xDB6E, 0x83DE, 0xDB7A, 0x83DF, 0xB5E9, 0x83E0, 0xB5D4, 0x83E1, 0xDB72, 0x83E2, 0xDBAD, 0x83E3, 0xDB6B, 0x83E4, 0xDB64, 0x83E5, 0xDB6F, 0x83E7, 0xDB63, 0x83E8, 0xDB61, 0x83E9, 0xB5D0, 0x83EA, 0xDBA5, 0x83EB, 0xDB6A, 0x83EC, 0xDBA8, 0x83EE, 0xDBA9, 0x83EF, 0xB5D8, 0x83F0, 0xB5DD, 0x83F1, 0xB5D9, 0x83F2, 0xB5E1, 0x83F3, 0xDB7E, 0x83F4, 0xB5DA, 0x83F5, 0xDB76, 0x83F6, 0xDB66, 0x83F8, 0xB5D2, 0x83F9, 0xDB5E, 0x83FA, 0xDBA2, 0x83FB, 0xDBAB, 0x83FC, 0xDB65, 0x83FD, 0xB5E0, 0x83FE, 0xDBB0, 0x83FF, 0xDB71, 0x8401, 0xDB6D, 0x8403, 0xB5D1, 0x8404, 0xB5E5, 0x8406, 0xDB7C, 0x8407, 0xB5E7, 0x8409, 0xDB78, 0x840A, 0xB5DC, 0x840B, 0xB5D6, 0x840C, 0xB5DE, 0x840D, 0xB5D3, 0x840E, 0xB5E4, 0x840F, 0xDB79, 0x8410, 0xDB67, 0x8411, 0xDB7B, 0x8412, 0xDB62, 0x8413, 0xDBA6, 0x841B, 0xDBAE, 0x8423, 0xDB5F, 0x8429, 0xDFC7, 0x842B, 0xDFDD, 0x842C, 0xB855, 0x842D, 0xDFCC, 0x842F, 0xDFCA, 0x8430, 0xDFB5, 0x8431, 0xB8A9, 0x8432, 0xDFC5, 0x8433, 0xDFD9, 0x8434, 0xDFC1, 0x8435, 0xB8B1, 0x8436, 0xDFD8, 0x8437, 0xDFBF, 0x8438, 0xB5E3, 0x8439, 0xDFCF, 0x843A, 0xDFC0, 0x843B, 0xDFD6, 0x843C, 0xB8B0, 0x843D, 0xB8A8, 0x843F, 0xDFAA, 0x8440, 0xDFB2, 0x8442, 0xDFCB, 0x8443, 0xDFC3, 0x8444, 0xDFDC, 0x8445, 0xDFC6, 0x8446, 0xB8B6, 0x8447, 0xDFD7, 0x8449, 0xB8AD, 0x844B, 0xDFC9, 0x844C, 0xDFD1, 0x844D, 0xDFB6, 0x844E, 0xDFD0, 0x8450, 0xDFE1, 0x8451, 0xDFB1, 0x8452, 0xDFD2, 0x8454, 0xDFDF, 0x8456, 0xDFAB, 0x8457, 0xB5DB, 0x8459, 0xDFB9, 0x845A, 0xDFB8, 0x845B, 0xB8AF, 0x845D, 0xDFBC, 0x845E, 0xDFBE, 0x845F, 0xDFCD, 0x8460, 0xDFDE, 0x8461, 0xB8B2, 0x8463, 0xB8B3, 0x8465, 0xDFB0, 0x8466, 0xB8AB, 0x8467, 0xDFB4, 0x8468, 0xDFDA, 0x8469, 0xB8B4, 0x846B, 0xB8AC, 0x846C, 0xB8AE, 0x846D, 0xB8B5, 0x846E, 0xDFE0, 0x846F, 0xDFD3, 0x8470, 0xDFCE, 0x8473, 0xDFBB, 0x8474, 0xDFBA, 0x8475, 0xB8AA, 0x8476, 0xDFAC, 0x8477, 0xB8A7, 0x8478, 0xDFC4, 0x8479, 0xDFAD, 0x847A, 0xDFC2, 0x847D, 0xDFB7, 0x847E, 0xDFDB, 0x8482, 0xB8A6, 0x8486, 0xDFB3, 0x848D, 0xDFAF, 0x848E, 0xDFD5, 0x848F, 0xDFAE, 0x8490, 0xBB60, 0x8491, 0xE3D3, 0x8494, 0xE3C2, 0x8497, 0xE3AC, 0x8498, 0xE3CA, 0x8499, 0xBB58, 0x849A, 0xE3BB, 0x849B, 0xE3C5, 0x849C, 0xBB5B, 0x849D, 0xE3BE, 0x849E, 0xBB59, 0x849F, 0xE3AF, 0x84A0, 0xE3CD, 0x84A1, 0xE3AE, 0x84A2, 0xE3C1, 0x84A4, 0xE3AD, 0x84A7, 0xE3BF, 0x84A8, 0xE3C8, 0x84A9, 0xE3C6, 0x84AA, 0xE3BA, 0x84AB, 0xE3B5, 0x84AC, 0xE3B3, 0x84AE, 0xE3B4, 0x84AF, 0xE3C7, 0x84B0, 0xE3D2, 0x84B1, 0xE3BC, 0x84B2, 0xBB5A, 0x84B4, 0xE3B7, 0x84B6, 0xE3CB, 0x84B8, 0xBB5D, 0x84B9, 0xE3B6, 0x84BA, 0xE3B0, 0x84BB, 0xE3C0, 0x84BC, 0xBB61, 0x84BF, 0xBB55, 0x84C0, 0xBB5E, 0x84C1, 0xE3B8, 0x84C2, 0xE3B2, 0x84C4, 0xBB57, 0x84C5, 0xDFD4, 0x84C6, 0xBB56, 0x84C7, 0xE3C3, 0x84C9, 0xBB54, 0x84CA, 0xBB63, 0x84CB, 0xBB5C, 0x84CC, 0xE3C4, 0x84CD, 0xE3B9, 0x84CE, 0xE3B1, 0x84CF, 0xE3CC, 0x84D0, 0xE3BD, 0x84D1, 0xBB62, 0x84D2, 0xE3D0, 0x84D3, 0xBB5F, 0x84D4, 0xE3CF, 0x84D6, 0xE3C9, 0x84D7, 0xE3CE, 0x84DB, 0xE3D1, 0x84E7, 0xE773, 0x84E8, 0xE774, 0x84E9, 0xE767, 0x84EA, 0xE766, 0x84EB, 0xE762, 0x84EC, 0xBDB4, 0x84EE, 0xBDAC, 0x84EF, 0xE776, 0x84F0, 0xE775, 0x84F1, 0xDFA9, 0x84F2, 0xE75F, 0x84F3, 0xE763, 0x84F4, 0xE75D, 0x84F6, 0xE770, 0x84F7, 0xE761, 0x84F9, 0xE777, 0x84FA, 0xE75A, 0x84FB, 0xE758, 0x84FC, 0xE764, 0x84FD, 0xE76E, 0x84FE, 0xE769, 0x84FF, 0xBDB6, 0x8500, 0xE74F, 0x8502, 0xE76D, 0x8506, 0xBDB7, 0x8507, 0xDFBD, 0x8508, 0xE75B, 0x8509, 0xE752, 0x850A, 0xE755, 0x850B, 0xE77B, 0x850C, 0xE75C, 0x850D, 0xE753, 0x850E, 0xE751, 0x850F, 0xE74E, 0x8511, 0xBDB0, 0x8512, 0xE765, 0x8513, 0xBDAF, 0x8514, 0xBDB3, 0x8515, 0xE760, 0x8516, 0xE768, 0x8517, 0xBDA9, 0x8518, 0xE778, 0x8519, 0xE77C, 0x851A, 0xBDAB, 0x851C, 0xE757, 0x851D, 0xE76B, 0x851E, 0xE76F, 0x851F, 0xE754, 0x8520, 0xE779, 0x8521, 0xBDB2, 0x8523, 0xBDB1, 0x8524, 0xE74C, 0x8525, 0xBDB5, 0x8526, 0xE772, 0x8527, 0xE756, 0x8528, 0xE76A, 0x8529, 0xE750, 0x852A, 0xE75E, 0x852B, 0xE759, 0x852C, 0xBDAD, 0x852D, 0xBDAE, 0x852E, 0xE76C, 0x852F, 0xE77D, 0x8530, 0xE77A, 0x8531, 0xE771, 0x853B, 0xE74D, 0x853D, 0xBDAA, 0x853E, 0xEB49, 0x8540, 0xEB40, 0x8541, 0xEB43, 0x8543, 0xBFBB, 0x8544, 0xEB45, 0x8545, 0xEAF9, 0x8546, 0xEB41, 0x8547, 0xEB47, 0x8548, 0xBFB8, 0x8549, 0xBFBC, 0x854A, 0xBFB6, 0x854D, 0xEAFB, 0x854E, 0xEB4C, 0x8551, 0xEB46, 0x8553, 0xEAFC, 0x8554, 0xEB55, 0x8555, 0xEB4F, 0x8556, 0xEAF8, 0x8557, 0xEE46, 0x8558, 0xEAFE, 0x8559, 0xBFB7, 0x855B, 0xEB4A, 0x855D, 0xEB54, 0x855E, 0xBFBF, 0x8560, 0xEB51, 0x8561, 0xEAFD, 0x8562, 0xEB44, 0x8563, 0xEB48, 0x8564, 0xEB42, 0x8565, 0xEB56, 0x8566, 0xEB53, 0x8567, 0xEB50, 0x8568, 0xBFB9, 0x8569, 0xBFBA, 0x856A, 0xBFBE, 0x856B, 0xEAFA, 0x856C, 0xEB57, 0x856D, 0xBFBD, 0x856E, 0xEB4D, 0x8571, 0xEB4B, 0x8575, 0xEB4E, 0x8576, 0xEE53, 0x8577, 0xEE40, 0x8578, 0xEE45, 0x8579, 0xEE52, 0x857A, 0xEE44, 0x857B, 0xEDFB, 0x857C, 0xEE41, 0x857E, 0xC1A2, 0x8580, 0xEDF4, 0x8581, 0xEE4D, 0x8582, 0xEE4F, 0x8583, 0xEDF3, 0x8584, 0xC1A1, 0x8585, 0xEE51, 0x8586, 0xEE49, 0x8587, 0xC1A8, 0x8588, 0xEE50, 0x8589, 0xEE42, 0x858A, 0xC1AA, 0x858B, 0xEDF9, 0x858C, 0xEB52, 0x858D, 0xEE4A, 0x858E, 0xEE47, 0x858F, 0xEDF5, 0x8590, 0xEE55, 0x8591, 0xC1A4, 0x8594, 0xC1A5, 0x8595, 0xEDF7, 0x8596, 0xEE48, 0x8598, 0xEE54, 0x8599, 0xEE4B, 0x859A, 0xEDFD, 0x859B, 0xC1A7, 0x859C, 0xC1A3, 0x859D, 0xEE4C, 0x859E, 0xEDFE, 0x859F, 0xEE56, 0x85A0, 0xEDF8, 0x85A1, 0xEE43, 0x85A2, 0xEE4E, 0x85A3, 0xEDFA, 0x85A4, 0xEDFC, 0x85A6, 0xC2CB, 0x85A7, 0xEDF6, 0x85A8, 0xC1A9, 0x85A9, 0xC2C4, 0x85AA, 0xC17E, 0x85AF, 0xC1A6, 0x85B0, 0xC2C8, 0x85B1, 0xF0B3, 0x85B3, 0xF0A9, 0x85B4, 0xF0A4, 0x85B5, 0xF0AA, 0x85B6, 0xF0B4, 0x85B7, 0xF0B8, 0x85B8, 0xF0B7, 0x85B9, 0xC2CA, 0x85BA, 0xC2C9, 0x85BD, 0xF0AB, 0x85BE, 0xF0B9, 0x85BF, 0xF0AE, 0x85C0, 0xF0A6, 0x85C2, 0xF0A8, 0x85C3, 0xF0A7, 0x85C4, 0xF0AD, 0x85C5, 0xF0B2, 0x85C6, 0xF0A5, 0x85C7, 0xF0AC, 0x85C8, 0xF0B1, 0x85C9, 0xC2C7, 0x85CB, 0xF0AF, 0x85CD, 0xC2C5, 0x85CE, 0xF0B0, 0x85CF, 0xC2C3, 0x85D0, 0xC2C6, 0x85D1, 0xF2D5, 0x85D2, 0xF0B5, 0x85D5, 0xC3C2, 0x85D7, 0xF2CD, 0x85D8, 0xF2D1, 0x85D9, 0xF2C9, 0x85DA, 0xF2CC, 0x85DC, 0xF2D4, 0x85DD, 0xC3C0, 0x85DE, 0xF2D9, 0x85DF, 0xF2D2, 0x85E1, 0xF2CA, 0x85E2, 0xF2DA, 0x85E3, 0xF2D3, 0x85E4, 0xC3C3, 0x85E5, 0xC3C4, 0x85E6, 0xF2D7, 0x85E8, 0xF2CB, 0x85E9, 0xC3BF, 0x85EA, 0xC3C1, 0x85EB, 0xF2C6, 0x85EC, 0xF2CE, 0x85ED, 0xF2C8, 0x85EF, 0xF2D8, 0x85F0, 0xF2D6, 0x85F1, 0xF2C7, 0x85F2, 0xF2CF, 0x85F6, 0xF4BE, 0x85F7, 0xC3C5, 0x85F8, 0xF2D0, 0x85F9, 0xC4A7, 0x85FA, 0xC4A9, 0x85FB, 0xC4A6, 0x85FD, 0xF4C3, 0x85FE, 0xF4BB, 0x85FF, 0xF4B9, 0x8600, 0xF4BD, 0x8601, 0xF4BA, 0x8604, 0xF4BF, 0x8605, 0xF4C1, 0x8606, 0xC4AA, 0x8607, 0xC4AC, 0x8609, 0xF4C0, 0x860A, 0xC4AD, 0x860B, 0xC4AB, 0x860C, 0xF4C2, 0x8611, 0xC4A8, 0x8617, 0xC4F4, 0x8618, 0xF5F1, 0x8619, 0xF5F7, 0x861A, 0xC4F6, 0x861B, 0xF4BC, 0x861C, 0xF5F6, 0x861E, 0xF5FD, 0x861F, 0xF5F4, 0x8620, 0xF5FB, 0x8621, 0xF5FA, 0x8622, 0xF4B8, 0x8623, 0xF5F5, 0x8624, 0xF0B6, 0x8625, 0xF5FE, 0x8626, 0xF5F3, 0x8627, 0xF5F8, 0x8629, 0xF5FC, 0x862A, 0xF5F2, 0x862C, 0xF74A, 0x862D, 0xC4F5, 0x862E, 0xF5F9, 0x8631, 0xF7F4, 0x8632, 0xF74B, 0x8633, 0xF749, 0x8634, 0xF747, 0x8635, 0xF748, 0x8636, 0xF74C, 0x8638, 0xC5D9, 0x8639, 0xF7F2, 0x863A, 0xF7F0, 0x863B, 0xF7F5, 0x863C, 0xF7F3, 0x863E, 0xF7F6, 0x863F, 0xC5DA, 0x8640, 0xF7F1, 0x8643, 0xF8BC, 0x8646, 0xF945, 0x8647, 0xF946, 0x8648, 0xF947, 0x864B, 0xF9C7, 0x864C, 0xF9BD, 0x864D, 0xCA4F, 0x864E, 0xAAEA, 0x8650, 0xAD68, 0x8652, 0xD3B8, 0x8653, 0xD3B7, 0x8654, 0xB040, 0x8655, 0xB342, 0x8656, 0xD77C, 0x8659, 0xD77B, 0x865B, 0xB5EA, 0x865C, 0xB8B8, 0x865E, 0xB8B7, 0x865F, 0xB8B9, 0x8661, 0xE3D4, 0x8662, 0xE77E, 0x8663, 0xEB58, 0x8664, 0xEB5A, 0x8665, 0xEB59, 0x8667, 0xC1AB, 0x8668, 0xEE57, 0x8669, 0xF0BA, 0x866A, 0xF9A5, 0x866B, 0xA6E4, 0x866D, 0xCDC9, 0x866E, 0xCDCA, 0x866F, 0xCDC8, 0x8670, 0xCDC7, 0x8671, 0xAAEB, 0x8673, 0xD0A9, 0x8674, 0xD0A7, 0x8677, 0xD0A6, 0x8679, 0xAD69, 0x867A, 0xAD6B, 0x867B, 0xAD6A, 0x867C, 0xD0A8, 0x8685, 0xD3C4, 0x8686, 0xD3C1, 0x8687, 0xD3BF, 0x868A, 0xB041, 0x868B, 0xD3C2, 0x868C, 0xB046, 0x868D, 0xD3BC, 0x868E, 0xD3CB, 0x8690, 0xD3CD, 0x8691, 0xD3BD, 0x8693, 0xB043, 0x8694, 0xD3CE, 0x8695, 0xD3C9, 0x8696, 0xD3BB, 0x8697, 0xD3C0, 0x8698, 0xD3CA, 0x8699, 0xD3C6, 0x869A, 0xD3C3, 0x869C, 0xB048, 0x869D, 0xD3CC, 0x869E, 0xD3BE, 0x86A1, 0xD3C7, 0x86A2, 0xD3B9, 0x86A3, 0xB047, 0x86A4, 0xB044, 0x86A5, 0xD3C5, 0x86A7, 0xD3C8, 0x86A8, 0xD3BA, 0x86A9, 0xB045, 0x86AA, 0xB042, 0x86AF, 0xB34C, 0x86B0, 0xD7A5, 0x86B1, 0xB34B, 0x86B3, 0xD7A8, 0x86B4, 0xD7AB, 0x86B5, 0xB348, 0x86B6, 0xB346, 0x86B7, 0xD77E, 0x86B8, 0xD7A9, 0x86B9, 0xD7A7, 0x86BA, 0xD7A4, 0x86BB, 0xD7AC, 0x86BC, 0xD7AD, 0x86BD, 0xD7AF, 0x86BE, 0xD7B0, 0x86BF, 0xD77D, 0x86C0, 0xB345, 0x86C1, 0xD7A2, 0x86C2, 0xD7A1, 0x86C3, 0xD7AE, 0x86C4, 0xB347, 0x86C5, 0xD7A3, 0x86C6, 0xB349, 0x86C7, 0xB344, 0x86C8, 0xD7A6, 0x86C9, 0xB34D, 0x86CB, 0xB34A, 0x86CC, 0xD7AA, 0x86D0, 0xB5F1, 0x86D1, 0xDBBF, 0x86D3, 0xDBB4, 0x86D4, 0xB5EE, 0x86D6, 0xDFE7, 0x86D7, 0xDBBD, 0x86D8, 0xDBB1, 0x86D9, 0xB5EC, 0x86DA, 0xDBB6, 0x86DB, 0xB5EF, 0x86DC, 0xDBBA, 0x86DD, 0xDBB8, 0x86DE, 0xB5F2, 0x86DF, 0xB5EB, 0x86E2, 0xDBB2, 0x86E3, 0xDBB5, 0x86E4, 0xB5F0, 0x86E6, 0xDBB3, 0x86E8, 0xDBBE, 0x86E9, 0xDBBC, 0x86EA, 0xDBB7, 0x86EB, 0xDBB9, 0x86EC, 0xDBBB, 0x86ED, 0xB5ED, 0x86F5, 0xDFE8, 0x86F6, 0xDFEE, 0x86F7, 0xDFE4, 0x86F8, 0xDFEA, 0x86F9, 0xB8BA, 0x86FA, 0xDFE6, 0x86FB, 0xB8C0, 0x86FE, 0xB8BF, 0x8700, 0xB8BE, 0x8701, 0xDFED, 0x8702, 0xB8C1, 0x8703, 0xB8C2, 0x8704, 0xDFE3, 0x8705, 0xDFF0, 0x8706, 0xB8C3, 0x8707, 0xB8BD, 0x8708, 0xB8BC, 0x8709, 0xDFEC, 0x870A, 0xB8C4, 0x870B, 0xDFE2, 0x870C, 0xDFE5, 0x870D, 0xDFEF, 0x870E, 0xDFEB, 0x8711, 0xE3F4, 0x8712, 0xE3E9, 0x8713, 0xB8BB, 0x8718, 0xBB6A, 0x8719, 0xE3DD, 0x871A, 0xE3F2, 0x871B, 0xE3DE, 0x871C, 0xBB65, 0x871E, 0xE3DB, 0x8720, 0xE3E4, 0x8721, 0xE3DC, 0x8722, 0xBB67, 0x8723, 0xE3D6, 0x8724, 0xE3F1, 0x8725, 0xBB68, 0x8726, 0xE3EE, 0x8727, 0xE3EF, 0x8728, 0xE3D7, 0x8729, 0xBB6D, 0x872A, 0xE3E6, 0x872C, 0xE3E0, 0x872D, 0xE3E7, 0x872E, 0xE3DA, 0x8730, 0xE3F3, 0x8731, 0xE3EB, 0x8732, 0xE3E5, 0x8733, 0xE3D5, 0x8734, 0xBB69, 0x8735, 0xE3EC, 0x8737, 0xBB6C, 0x8738, 0xE3F0, 0x873A, 0xE3EA, 0x873B, 0xBB66, 0x873C, 0xE3E8, 0x873E, 0xE3E2, 0x873F, 0xBB64, 0x8740, 0xE3D9, 0x8741, 0xE3E1, 0x8742, 0xE3ED, 0x8743, 0xE3DF, 0x8746, 0xE3E3, 0x874C, 0xBDC1, 0x874D, 0xDFE9, 0x874E, 0xE7B2, 0x874F, 0xE7BB, 0x8750, 0xE7B1, 0x8751, 0xE7AD, 0x8752, 0xE7AA, 0x8753, 0xBDC2, 0x8754, 0xE7A8, 0x8755, 0xBB6B, 0x8756, 0xE7A1, 0x8757, 0xBDC0, 0x8758, 0xE7A7, 0x8759, 0xBDBF, 0x875A, 0xE7AC, 0x875B, 0xE7A9, 0x875C, 0xE7B9, 0x875D, 0xE7B4, 0x875E, 0xE7AE, 0x875F, 0xE7B3, 0x8760, 0xBDBB, 0x8761, 0xE7AB, 0x8762, 0xE7BE, 0x8763, 0xE7A2, 0x8764, 0xE7A3, 0x8765, 0xE7BA, 0x8766, 0xBDBC, 0x8767, 0xE7BF, 0x8768, 0xBDBE, 0x8769, 0xE7C0, 0x876A, 0xE7B0, 0x876B, 0xE3D8, 0x876C, 0xE7B6, 0x876D, 0xE7AF, 0x876E, 0xE7B8, 0x876F, 0xE7B5, 0x8773, 0xE7A6, 0x8774, 0xBDB9, 0x8775, 0xE7BD, 0x8776, 0xBDBA, 0x8777, 0xE7A4, 0x8778, 0xBDBD, 0x8779, 0xEB64, 0x877A, 0xE7B7, 0x877B, 0xE7BC, 0x8781, 0xEB61, 0x8782, 0xBDB8, 0x8783, 0xBFC0, 0x8784, 0xEB6B, 0x8785, 0xEB67, 0x8787, 0xEB65, 0x8788, 0xEB60, 0x8789, 0xEB6F, 0x878D, 0xBFC4, 0x878F, 0xEB5C, 0x8790, 0xEB68, 0x8791, 0xEB69, 0x8792, 0xEB5F, 0x8793, 0xEB5E, 0x8794, 0xEB6C, 0x8796, 0xEB62, 0x8797, 0xEB5D, 0x8798, 0xEB63, 0x879A, 0xEB6E, 0x879B, 0xEB5B, 0x879C, 0xEB6D, 0x879D, 0xEB6A, 0x879E, 0xBFC2, 0x879F, 0xBFC1, 0x87A2, 0xBFC3, 0x87A3, 0xEB66, 0x87A4, 0xF0CB, 0x87AA, 0xEE59, 0x87AB, 0xC1B1, 0x87AC, 0xEE5D, 0x87AD, 0xEE5A, 0x87AE, 0xEE61, 0x87AF, 0xEE67, 0x87B0, 0xEE5C, 0x87B2, 0xEE70, 0x87B3, 0xC1AE, 0x87B4, 0xEE6A, 0x87B5, 0xEE5F, 0x87B6, 0xEE6B, 0x87B7, 0xEE66, 0x87B8, 0xEE6D, 0x87B9, 0xEE5E, 0x87BA, 0xC1B3, 0x87BB, 0xC1B2, 0x87BC, 0xEE60, 0x87BD, 0xEE6E, 0x87BE, 0xEE58, 0x87BF, 0xEE6C, 0x87C0, 0xC1AC, 0x87C2, 0xEE64, 0x87C3, 0xEE63, 0x87C4, 0xEE68, 0x87C5, 0xEE5B, 0x87C6, 0xC1B0, 0x87C8, 0xC1B4, 0x87C9, 0xEE62, 0x87CA, 0xEE69, 0x87CB, 0xC1B5, 0x87CC, 0xEE65, 0x87D1, 0xC1AD, 0x87D2, 0xC1AF, 0x87D3, 0xF0C7, 0x87D4, 0xF0C5, 0x87D7, 0xF0CC, 0x87D8, 0xF0C9, 0x87D9, 0xF0CD, 0x87DB, 0xF0BE, 0x87DC, 0xF0C6, 0x87DD, 0xF0D1, 0x87DE, 0xEE6F, 0x87DF, 0xF0C2, 0x87E0, 0xC2CF, 0x87E1, 0xE7A5, 0x87E2, 0xF0BD, 0x87E3, 0xF0CA, 0x87E4, 0xF0C4, 0x87E5, 0xF0C1, 0x87E6, 0xF0BC, 0x87E7, 0xF0BB, 0x87E8, 0xF0D0, 0x87EA, 0xF0C0, 0x87EB, 0xF0BF, 0x87EC, 0xC2CD, 0x87ED, 0xF0C8, 0x87EF, 0xC2CC, 0x87F2, 0xC2CE, 0x87F3, 0xF0C3, 0x87F4, 0xF0CF, 0x87F6, 0xF2DE, 0x87F7, 0xF2DF, 0x87F9, 0xC3C9, 0x87FA, 0xF2DC, 0x87FB, 0xC3C6, 0x87FC, 0xF2E4, 0x87FE, 0xC3CA, 0x87FF, 0xF2E6, 0x8800, 0xF2DB, 0x8801, 0xF0CE, 0x8802, 0xF2E8, 0x8803, 0xF2DD, 0x8805, 0xC3C7, 0x8806, 0xF2E3, 0x8808, 0xF2E5, 0x8809, 0xF2E0, 0x880A, 0xF2E7, 0x880B, 0xF2E2, 0x880C, 0xF2E1, 0x880D, 0xC3C8, 0x8810, 0xF4C5, 0x8811, 0xF4C6, 0x8813, 0xF4C8, 0x8814, 0xC4AE, 0x8815, 0xC4AF, 0x8816, 0xF4C9, 0x8817, 0xF4C7, 0x8819, 0xF4C4, 0x881B, 0xF642, 0x881C, 0xF645, 0x881D, 0xF641, 0x881F, 0xC4FA, 0x8820, 0xF643, 0x8821, 0xC4F9, 0x8822, 0xC4F8, 0x8823, 0xC4F7, 0x8824, 0xF644, 0x8825, 0xF751, 0x8826, 0xF74F, 0x8828, 0xF74E, 0x8829, 0xF640, 0x882A, 0xF750, 0x882B, 0xF646, 0x882C, 0xF74D, 0x882E, 0xF7F9, 0x882F, 0xF7D7, 0x8830, 0xF7F7, 0x8831, 0xC5DB, 0x8832, 0xF7F8, 0x8833, 0xF7FA, 0x8835, 0xF8BF, 0x8836, 0xC5FA, 0x8837, 0xF8BE, 0x8838, 0xF8BD, 0x8839, 0xC5FB, 0x883B, 0xC65A, 0x883C, 0xF96E, 0x883D, 0xF9A7, 0x883E, 0xF9A6, 0x883F, 0xF9A8, 0x8840, 0xA6E5, 0x8841, 0xD0AA, 0x8843, 0xD3CF, 0x8844, 0xD3D0, 0x8848, 0xDBC0, 0x884A, 0xF647, 0x884B, 0xF8C0, 0x884C, 0xA6E6, 0x884D, 0xAD6C, 0x884E, 0xD0AB, 0x8852, 0xD7B1, 0x8853, 0xB34E, 0x8855, 0xDBC2, 0x8856, 0xDBC1, 0x8857, 0xB5F3, 0x8859, 0xB8C5, 0x885A, 0xE7C1, 0x885B, 0xBDC3, 0x885D, 0xBDC4, 0x8861, 0xBFC5, 0x8862, 0xC5FC, 0x8863, 0xA6E7, 0x8867, 0xD0AC, 0x8868, 0xAAED, 0x8869, 0xD0AE, 0x886A, 0xD0AD, 0x886B, 0xAD6D, 0x886D, 0xD3D1, 0x886F, 0xD3D8, 0x8870, 0xB049, 0x8871, 0xD3D6, 0x8872, 0xD3D4, 0x8874, 0xD3DB, 0x8875, 0xD3D2, 0x8876, 0xD3D3, 0x8877, 0xB04A, 0x8879, 0xB04E, 0x887C, 0xD3DC, 0x887D, 0xB04D, 0x887E, 0xD3DA, 0x887F, 0xD3D7, 0x8880, 0xD3D5, 0x8881, 0xB04B, 0x8882, 0xB04C, 0x8883, 0xD3D9, 0x8888, 0xB350, 0x8889, 0xD7B2, 0x888B, 0xB355, 0x888C, 0xD7C2, 0x888D, 0xB354, 0x888E, 0xD7C4, 0x8891, 0xD7B8, 0x8892, 0xB352, 0x8893, 0xD7C3, 0x8895, 0xD7B3, 0x8896, 0xB353, 0x8897, 0xD7BF, 0x8898, 0xD7BB, 0x8899, 0xD7BD, 0x889A, 0xD7B7, 0x889B, 0xD7BE, 0x889E, 0xB34F, 0x889F, 0xD7BA, 0x88A1, 0xD7B9, 0x88A2, 0xD7B5, 0x88A4, 0xD7C0, 0x88A7, 0xD7BC, 0x88A8, 0xD7B4, 0x88AA, 0xD7B6, 0x88AB, 0xB351, 0x88AC, 0xD7C1, 0x88B1, 0xB5F6, 0x88B2, 0xDBCD, 0x88B6, 0xDBC9, 0x88B7, 0xDBCB, 0x88B8, 0xDBC6, 0x88B9, 0xDBC5, 0x88BA, 0xDBC3, 0x88BC, 0xDBCA, 0x88BD, 0xDBCC, 0x88BE, 0xDBC8, 0x88C0, 0xDBC7, 0x88C1, 0xB5F4, 0x88C2, 0xB5F5, 0x88C9, 0xDBCF, 0x88CA, 0xB8CD, 0x88CB, 0xDFF2, 0x88CC, 0xDFF8, 0x88CD, 0xDFF3, 0x88CE, 0xDFF4, 0x88CF, 0xF9D8, 0x88D0, 0xDFF9, 0x88D2, 0xB8CF, 0x88D4, 0xB8C7, 0x88D5, 0xB8CE, 0x88D6, 0xDFF1, 0x88D7, 0xDBC4, 0x88D8, 0xB8CA, 0x88D9, 0xB8C8, 0x88DA, 0xDFF7, 0x88DB, 0xDFF6, 0x88DC, 0xB8C9, 0x88DD, 0xB8CB, 0x88DE, 0xDFF5, 0x88DF, 0xB8C6, 0x88E1, 0xB8CC, 0x88E7, 0xE3F6, 0x88E8, 0xBB74, 0x88EB, 0xE442, 0x88EC, 0xE441, 0x88EE, 0xE3FB, 0x88EF, 0xBB76, 0x88F0, 0xE440, 0x88F1, 0xE3F7, 0x88F2, 0xE3F8, 0x88F3, 0xBB6E, 0x88F4, 0xBB70, 0x88F6, 0xE3FD, 0x88F7, 0xE3F5, 0x88F8, 0xBB72, 0x88F9, 0xBB71, 0x88FA, 0xE3F9, 0x88FB, 0xE3FE, 0x88FC, 0xE3FC, 0x88FD, 0xBB73, 0x88FE, 0xE3FA, 0x8901, 0xDBCE, 0x8902, 0xBB6F, 0x8905, 0xE7C2, 0x8906, 0xE7C9, 0x8907, 0xBDC6, 0x8909, 0xE7CD, 0x890A, 0xBDCA, 0x890B, 0xE7C5, 0x890C, 0xE7C3, 0x890E, 0xE7CC, 0x8910, 0xBDC5, 0x8911, 0xE7CB, 0x8912, 0xBDC7, 0x8913, 0xBDC8, 0x8914, 0xE7C4, 0x8915, 0xBDC9, 0x8916, 0xE7CA, 0x8917, 0xE7C6, 0x8918, 0xE7C7, 0x8919, 0xE7C8, 0x891A, 0xBB75, 0x891E, 0xEB70, 0x891F, 0xEB7C, 0x8921, 0xBFCA, 0x8922, 0xEB77, 0x8923, 0xEB79, 0x8925, 0xBFC8, 0x8926, 0xEB71, 0x8927, 0xEB75, 0x8929, 0xEB78, 0x892A, 0xBFC6, 0x892B, 0xBFC9, 0x892C, 0xEB7B, 0x892D, 0xEB73, 0x892E, 0xEB74, 0x892F, 0xEB7A, 0x8930, 0xEB72, 0x8931, 0xEB76, 0x8932, 0xBFC7, 0x8933, 0xEE72, 0x8935, 0xEE71, 0x8936, 0xC1B7, 0x8937, 0xEE77, 0x8938, 0xC1B9, 0x893B, 0xC1B6, 0x893C, 0xEE73, 0x893D, 0xC1BA, 0x893E, 0xEE74, 0x8941, 0xEE75, 0x8942, 0xEE78, 0x8944, 0xC1B8, 0x8946, 0xF0D6, 0x8949, 0xF0D9, 0x894B, 0xF0D3, 0x894C, 0xF0D5, 0x894F, 0xF0D4, 0x8950, 0xF0D7, 0x8951, 0xF0D8, 0x8952, 0xEE76, 0x8953, 0xF0D2, 0x8956, 0xC3CD, 0x8957, 0xF2EC, 0x8958, 0xF2EF, 0x8959, 0xF2F1, 0x895A, 0xF2EA, 0x895B, 0xF2EB, 0x895C, 0xF2EE, 0x895D, 0xF2F0, 0x895E, 0xC3CE, 0x895F, 0xC3CC, 0x8960, 0xC3CB, 0x8961, 0xF2ED, 0x8962, 0xF2E9, 0x8963, 0xF4CA, 0x8964, 0xC4B0, 0x8966, 0xF4CB, 0x8969, 0xF649, 0x896A, 0xC4FB, 0x896B, 0xF64B, 0x896C, 0xC4FC, 0x896D, 0xF648, 0x896E, 0xF64A, 0x896F, 0xC5A8, 0x8971, 0xF752, 0x8972, 0xC5A7, 0x8973, 0xF7FD, 0x8974, 0xF7FC, 0x8976, 0xF7FB, 0x8979, 0xF948, 0x897A, 0xF949, 0x897B, 0xF94B, 0x897C, 0xF94A, 0x897E, 0xCA50, 0x897F, 0xA6E8, 0x8981, 0xAD6E, 0x8982, 0xD7C5, 0x8983, 0xB5F7, 0x8985, 0xDFFA, 0x8986, 0xC2D0, 0x8988, 0xF2F2, 0x898B, 0xA8A3, 0x898F, 0xB357, 0x8993, 0xB356, 0x8995, 0xDBD0, 0x8996, 0xB5F8, 0x8997, 0xDBD2, 0x8998, 0xDBD1, 0x899B, 0xDFFB, 0x899C, 0xB8D0, 0x899D, 0xE443, 0x899E, 0xE446, 0x899F, 0xE445, 0x89A1, 0xE444, 0x89A2, 0xE7CE, 0x89A3, 0xE7D0, 0x89A4, 0xE7CF, 0x89A6, 0xBFCC, 0x89AA, 0xBFCB, 0x89AC, 0xC1BB, 0x89AD, 0xEE79, 0x89AE, 0xEE7B, 0x89AF, 0xEE7A, 0x89B2, 0xC2D1, 0x89B6, 0xF2F4, 0x89B7, 0xF2F3, 0x89B9, 0xF4CC, 0x89BA, 0xC4B1, 0x89BD, 0xC4FD, 0x89BE, 0xF754, 0x89BF, 0xF753, 0x89C0, 0xC65B, 0x89D2, 0xA8A4, 0x89D3, 0xD0AF, 0x89D4, 0xAD6F, 0x89D5, 0xD7C8, 0x89D6, 0xD7C6, 0x89D9, 0xD7C7, 0x89DA, 0xDBD4, 0x89DB, 0xDBD5, 0x89DC, 0xE043, 0x89DD, 0xDBD3, 0x89DF, 0xDFFC, 0x89E0, 0xE041, 0x89E1, 0xE040, 0x89E2, 0xE042, 0x89E3, 0xB8D1, 0x89E4, 0xDFFE, 0x89E5, 0xDFFD, 0x89E6, 0xE044, 0x89E8, 0xE449, 0x89E9, 0xE447, 0x89EB, 0xE448, 0x89EC, 0xE7D3, 0x89ED, 0xE7D1, 0x89F0, 0xE7D2, 0x89F1, 0xEB7D, 0x89F2, 0xEE7C, 0x89F3, 0xEE7D, 0x89F4, 0xC2D2, 0x89F6, 0xF2F5, 0x89F7, 0xF4CD, 0x89F8, 0xC4B2, 0x89FA, 0xF64C, 0x89FB, 0xF755, 0x89FC, 0xC5A9, 0x89FE, 0xF7FE, 0x89FF, 0xF94C, 0x8A00, 0xA8A5, 0x8A02, 0xAD71, 0x8A03, 0xAD72, 0x8A04, 0xD0B0, 0x8A07, 0xD0B1, 0x8A08, 0xAD70, 0x8A0A, 0xB054, 0x8A0C, 0xB052, 0x8A0E, 0xB051, 0x8A0F, 0xB058, 0x8A10, 0xB050, 0x8A11, 0xB059, 0x8A12, 0xD3DD, 0x8A13, 0xB056, 0x8A15, 0xB053, 0x8A16, 0xB057, 0x8A17, 0xB055, 0x8A18, 0xB04F, 0x8A1B, 0xB35F, 0x8A1D, 0xB359, 0x8A1E, 0xD7CC, 0x8A1F, 0xB35E, 0x8A22, 0xB360, 0x8A23, 0xB35A, 0x8A25, 0xB35B, 0x8A27, 0xD7CA, 0x8A2A, 0xB358, 0x8A2C, 0xD7CB, 0x8A2D, 0xB35D, 0x8A30, 0xD7C9, 0x8A31, 0xB35C, 0x8A34, 0xB644, 0x8A36, 0xB646, 0x8A39, 0xDBD8, 0x8A3A, 0xB645, 0x8A3B, 0xB5F9, 0x8A3C, 0xB5FD, 0x8A3E, 0xB8E4, 0x8A3F, 0xE049, 0x8A40, 0xDBDA, 0x8A41, 0xB5FE, 0x8A44, 0xDBDD, 0x8A45, 0xDBDE, 0x8A46, 0xB643, 0x8A48, 0xDBE0, 0x8A4A, 0xDBE2, 0x8A4C, 0xDBE3, 0x8A4D, 0xDBD7, 0x8A4E, 0xDBD6, 0x8A4F, 0xDBE4, 0x8A50, 0xB642, 0x8A51, 0xDBE1, 0x8A52, 0xDBDF, 0x8A54, 0xB640, 0x8A55, 0xB5FB, 0x8A56, 0xB647, 0x8A57, 0xDBDB, 0x8A58, 0xDBDC, 0x8A59, 0xDBD9, 0x8A5B, 0xB641, 0x8A5E, 0xB5FC, 0x8A60, 0xB5FA, 0x8A61, 0xE048, 0x8A62, 0xB8DF, 0x8A63, 0xB8DA, 0x8A66, 0xB8D5, 0x8A68, 0xB8E5, 0x8A69, 0xB8D6, 0x8A6B, 0xB8D2, 0x8A6C, 0xB8E1, 0x8A6D, 0xB8DE, 0x8A6E, 0xB8E0, 0x8A70, 0xB8D7, 0x8A71, 0xB8DC, 0x8A72, 0xB8D3, 0x8A73, 0xB8D4, 0x8A74, 0xE050, 0x8A75, 0xE04D, 0x8A76, 0xE045, 0x8A77, 0xE04A, 0x8A79, 0xB8E2, 0x8A7A, 0xE051, 0x8A7B, 0xB8E3, 0x8A7C, 0xB8D9, 0x8A7F, 0xE047, 0x8A81, 0xE04F, 0x8A82, 0xE04B, 0x8A83, 0xE04E, 0x8A84, 0xE04C, 0x8A85, 0xB8DD, 0x8A86, 0xE046, 0x8A87, 0xB8D8, 0x8A8B, 0xE44C, 0x8A8C, 0xBB78, 0x8A8D, 0xBB7B, 0x8A8F, 0xE44E, 0x8A91, 0xBBA5, 0x8A92, 0xE44D, 0x8A93, 0xBB7D, 0x8A95, 0xBDCF, 0x8A96, 0xE44F, 0x8A98, 0xBBA4, 0x8A99, 0xE44B, 0x8A9A, 0xBBA6, 0x8A9E, 0xBB79, 0x8AA0, 0xB8DB, 0x8AA1, 0xBB7C, 0x8AA3, 0xBB7A, 0x8AA4, 0xBB7E, 0x8AA5, 0xBBA2, 0x8AA6, 0xBB77, 0x8AA7, 0xBBA7, 0x8AA8, 0xBBA3, 0x8AAA, 0xBBA1, 0x8AAB, 0xE44A, 0x8AB0, 0xBDD6, 0x8AB2, 0xBDD2, 0x8AB6, 0xBDD9, 0x8AB8, 0xE7D6, 0x8AB9, 0xBDDA, 0x8ABA, 0xE7E2, 0x8ABB, 0xE7DB, 0x8ABC, 0xBDCB, 0x8ABD, 0xE7E3, 0x8ABE, 0xE7DD, 0x8ABF, 0xBDD5, 0x8AC0, 0xE7DE, 0x8AC2, 0xBDD4, 0x8AC3, 0xE7E1, 0x8AC4, 0xBDCE, 0x8AC5, 0xE7DF, 0x8AC6, 0xE7D5, 0x8AC7, 0xBDCD, 0x8AC8, 0xEBAA, 0x8AC9, 0xBDD3, 0x8ACB, 0xBDD0, 0x8ACD, 0xBDD8, 0x8ACF, 0xE7D4, 0x8AD1, 0xE7D8, 0x8AD2, 0xBDCC, 0x8AD3, 0xE7D7, 0x8AD4, 0xE7D9, 0x8AD5, 0xE7DA, 0x8AD6, 0xBDD7, 0x8AD7, 0xE7DC, 0x8AD8, 0xE7E0, 0x8AD9, 0xE7E4, 0x8ADB, 0xBDDB, 0x8ADC, 0xBFD2, 0x8ADD, 0xEBA5, 0x8ADE, 0xEBAB, 0x8ADF, 0xEBA8, 0x8AE0, 0xEB7E, 0x8AE1, 0xEBAC, 0x8AE2, 0xEBA1, 0x8AE4, 0xEBA7, 0x8AE6, 0xBFCD, 0x8AE7, 0xBFD3, 0x8AE8, 0xEBAD, 0x8AEB, 0xBFCF, 0x8AED, 0xBFD9, 0x8AEE, 0xBFD4, 0x8AEF, 0xEBAF, 0x8AF0, 0xEBA9, 0x8AF1, 0xBFD0, 0x8AF2, 0xEBA2, 0x8AF3, 0xBFDA, 0x8AF4, 0xEBA3, 0x8AF5, 0xEBA4, 0x8AF6, 0xBFDB, 0x8AF7, 0xBFD8, 0x8AF8, 0xBDD1, 0x8AFA, 0xBFCE, 0x8AFB, 0xEBB0, 0x8AFC, 0xBFDC, 0x8AFE, 0xBFD5, 0x8AFF, 0xEBAE, 0x8B00, 0xBFD1, 0x8B01, 0xBFD6, 0x8B02, 0xBFD7, 0x8B04, 0xC1C3, 0x8B05, 0xEEA4, 0x8B06, 0xEEAD, 0x8B07, 0xEEAA, 0x8B08, 0xEEAC, 0x8B0A, 0xC1C0, 0x8B0B, 0xEEA5, 0x8B0D, 0xEEAB, 0x8B0E, 0xC1BC, 0x8B0F, 0xEEA7, 0x8B10, 0xC1C4, 0x8B11, 0xEEA3, 0x8B12, 0xEEA8, 0x8B13, 0xEEAF, 0x8B14, 0xEBA6, 0x8B15, 0xEEA9, 0x8B16, 0xEEA2, 0x8B17, 0xC1BD, 0x8B18, 0xEEA1, 0x8B19, 0xC1BE, 0x8B1A, 0xEEB0, 0x8B1B, 0xC1BF, 0x8B1C, 0xEEAE, 0x8B1D, 0xC1C2, 0x8B1E, 0xEE7E, 0x8B20, 0xC1C1, 0x8B22, 0xEEA6, 0x8B23, 0xF0DC, 0x8B24, 0xF0EA, 0x8B25, 0xF0E5, 0x8B26, 0xF0E7, 0x8B27, 0xF0DB, 0x8B28, 0xC2D3, 0x8B2A, 0xF0DA, 0x8B2B, 0xC2D6, 0x8B2C, 0xC2D5, 0x8B2E, 0xF0E9, 0x8B2F, 0xF0E1, 0x8B30, 0xF0DE, 0x8B31, 0xF0E4, 0x8B33, 0xF0DD, 0x8B35, 0xF0DF, 0x8B36, 0xF0E8, 0x8B37, 0xF0E6, 0x8B39, 0xC2D4, 0x8B3A, 0xF0ED, 0x8B3B, 0xF0EB, 0x8B3C, 0xF0E2, 0x8B3D, 0xF0EC, 0x8B3E, 0xF0E3, 0x8B40, 0xF2F9, 0x8B41, 0xC3CF, 0x8B42, 0xF341, 0x8B45, 0xF64F, 0x8B46, 0xC3D6, 0x8B47, 0xF0E0, 0x8B48, 0xF2F7, 0x8B49, 0xC3D2, 0x8B4A, 0xF2F8, 0x8B4B, 0xF2FD, 0x8B4E, 0xC3D4, 0x8B4F, 0xC3D5, 0x8B50, 0xF2F6, 0x8B51, 0xF340, 0x8B52, 0xF342, 0x8B53, 0xF2FA, 0x8B54, 0xF2FC, 0x8B55, 0xF2FE, 0x8B56, 0xF2FB, 0x8B57, 0xF343, 0x8B58, 0xC3D1, 0x8B59, 0xC3D7, 0x8B5A, 0xC3D3, 0x8B5C, 0xC3D0, 0x8B5D, 0xF4D0, 0x8B5F, 0xC4B7, 0x8B60, 0xF4CE, 0x8B63, 0xF4D2, 0x8B65, 0xF4D3, 0x8B66, 0xC4B5, 0x8B67, 0xF4D4, 0x8B68, 0xF4D1, 0x8B6A, 0xF4CF, 0x8B6B, 0xC4B8, 0x8B6C, 0xC4B4, 0x8B6D, 0xF4D5, 0x8B6F, 0xC4B6, 0x8B70, 0xC4B3, 0x8B74, 0xC4FE, 0x8B77, 0xC540, 0x8B78, 0xF64E, 0x8B79, 0xF64D, 0x8B7A, 0xF650, 0x8B7B, 0xF651, 0x8B7D, 0xC541, 0x8B7E, 0xF756, 0x8B7F, 0xF75B, 0x8B80, 0xC5AA, 0x8B82, 0xF758, 0x8B84, 0xF757, 0x8B85, 0xF75A, 0x8B86, 0xF759, 0x8B88, 0xF843, 0x8B8A, 0xC5DC, 0x8B8B, 0xF842, 0x8B8C, 0xF840, 0x8B8E, 0xF841, 0x8B92, 0xC5FE, 0x8B93, 0xC5FD, 0x8B94, 0xF8C1, 0x8B95, 0xF8C2, 0x8B96, 0xC640, 0x8B98, 0xF94D, 0x8B99, 0xF94E, 0x8B9A, 0xC667, 0x8B9C, 0xC66D, 0x8B9E, 0xF9A9, 0x8B9F, 0xF9C8, 0x8C37, 0xA8A6, 0x8C39, 0xD7CD, 0x8C3B, 0xD7CE, 0x8C3C, 0xE052, 0x8C3D, 0xE450, 0x8C3E, 0xE7E5, 0x8C3F, 0xC1C6, 0x8C41, 0xC1C5, 0x8C42, 0xF0EE, 0x8C43, 0xF344, 0x8C45, 0xF844, 0x8C46, 0xA8A7, 0x8C47, 0xD3DE, 0x8C48, 0xB05A, 0x8C49, 0xB361, 0x8C4A, 0xE054, 0x8C4B, 0xE053, 0x8C4C, 0xBDDC, 0x8C4D, 0xE7E6, 0x8C4E, 0xBDDD, 0x8C4F, 0xEEB1, 0x8C50, 0xC2D7, 0x8C54, 0xC676, 0x8C55, 0xA8A8, 0x8C56, 0xCDCB, 0x8C57, 0xD3DF, 0x8C5A, 0xB362, 0x8C5C, 0xD7CF, 0x8C5D, 0xD7D0, 0x8C5F, 0xDBE5, 0x8C61, 0xB648, 0x8C62, 0xB8E6, 0x8C64, 0xE056, 0x8C65, 0xE055, 0x8C66, 0xE057, 0x8C68, 0xE451, 0x8C69, 0xE452, 0x8C6A, 0xBBA8, 0x8C6B, 0xBFDD, 0x8C6C, 0xBDDE, 0x8C6D, 0xBFDE, 0x8C6F, 0xEEB5, 0x8C70, 0xEEB2, 0x8C71, 0xEEB4, 0x8C72, 0xEEB3, 0x8C73, 0xC1C7, 0x8C75, 0xF0EF, 0x8C76, 0xF346, 0x8C77, 0xF345, 0x8C78, 0xCBA4, 0x8C79, 0xB05C, 0x8C7A, 0xB05B, 0x8C7B, 0xD3E0, 0x8C7D, 0xD7D1, 0x8C80, 0xDBE7, 0x8C81, 0xDBE6, 0x8C82, 0xB649, 0x8C84, 0xE059, 0x8C85, 0xE05A, 0x8C86, 0xE058, 0x8C89, 0xB8E8, 0x8C8A, 0xB8E7, 0x8C8C, 0xBBAA, 0x8C8D, 0xBBA9, 0x8C8F, 0xE7E7, 0x8C90, 0xEBB3, 0x8C91, 0xEBB1, 0x8C92, 0xEBB2, 0x8C93, 0xBFDF, 0x8C94, 0xEEB7, 0x8C95, 0xEEB6, 0x8C97, 0xF0F2, 0x8C98, 0xF0F1, 0x8C99, 0xF0F0, 0x8C9A, 0xF347, 0x8C9C, 0xF9AA, 0x8C9D, 0xA8A9, 0x8C9E, 0xAD73, 0x8CA0, 0xAD74, 0x8CA1, 0xB05D, 0x8CA2, 0xB05E, 0x8CA3, 0xD3E2, 0x8CA4, 0xD3E1, 0x8CA5, 0xD7D2, 0x8CA7, 0xB368, 0x8CA8, 0xB366, 0x8CA9, 0xB363, 0x8CAA, 0xB367, 0x8CAB, 0xB365, 0x8CAC, 0xB364, 0x8CAF, 0xB64A, 0x8CB0, 0xDBEA, 0x8CB2, 0xB8ED, 0x8CB3, 0xB64C, 0x8CB4, 0xB651, 0x8CB5, 0xDBEC, 0x8CB6, 0xB653, 0x8CB7, 0xB652, 0x8CB8, 0xB655, 0x8CB9, 0xDBEB, 0x8CBA, 0xDBE8, 0x8CBB, 0xB64F, 0x8CBC, 0xB64B, 0x8CBD, 0xB64D, 0x8CBE, 0xDBE9, 0x8CBF, 0xB654, 0x8CC0, 0xB650, 0x8CC1, 0xB64E, 0x8CC2, 0xB8EF, 0x8CC3, 0xB8EE, 0x8CC4, 0xB8EC, 0x8CC5, 0xB8F0, 0x8CC7, 0xB8EA, 0x8CC8, 0xB8EB, 0x8CCA, 0xB8E9, 0x8CCC, 0xE05B, 0x8CCF, 0xE454, 0x8CD1, 0xBBAC, 0x8CD2, 0xBBAD, 0x8CD3, 0xBBAB, 0x8CD5, 0xE453, 0x8CD7, 0xE455, 0x8CD9, 0xE7EA, 0x8CDA, 0xE7EC, 0x8CDC, 0xBDE7, 0x8CDD, 0xE7ED, 0x8CDE, 0xBDE0, 0x8CDF, 0xE7E9, 0x8CE0, 0xBDDF, 0x8CE1, 0xBDE9, 0x8CE2, 0xBDE5, 0x8CE3, 0xBDE6, 0x8CE4, 0xBDE2, 0x8CE5, 0xE7E8, 0x8CE6, 0xBDE1, 0x8CE7, 0xE7EE, 0x8CE8, 0xE7EB, 0x8CEA, 0xBDE8, 0x8CEC, 0xBDE3, 0x8CED, 0xBDE4, 0x8CEE, 0xEBB5, 0x8CF0, 0xEBB7, 0x8CF1, 0xEBB6, 0x8CF3, 0xEBB8, 0x8CF4, 0xBFE0, 0x8CF5, 0xEBB4, 0x8CF8, 0xC1CB, 0x8CF9, 0xEEB8, 0x8CFA, 0xC1C8, 0x8CFB, 0xC1CC, 0x8CFC, 0xC1CA, 0x8CFD, 0xC1C9, 0x8CFE, 0xF0F3, 0x8D00, 0xF0F6, 0x8D02, 0xF0F5, 0x8D04, 0xF0F4, 0x8D05, 0xC2D8, 0x8D06, 0xF348, 0x8D07, 0xF349, 0x8D08, 0xC3D8, 0x8D09, 0xF34A, 0x8D0A, 0xC3D9, 0x8D0D, 0xC4BA, 0x8D0F, 0xC4B9, 0x8D10, 0xF652, 0x8D13, 0xC542, 0x8D14, 0xF653, 0x8D15, 0xF75C, 0x8D16, 0xC5AB, 0x8D17, 0xC5AC, 0x8D19, 0xF845, 0x8D1B, 0xC642, 0x8D64, 0xA8AA, 0x8D66, 0xB36A, 0x8D67, 0xB369, 0x8D68, 0xE05C, 0x8D69, 0xE05D, 0x8D6B, 0xBBAE, 0x8D6C, 0xEBB9, 0x8D6D, 0xBDEA, 0x8D6E, 0xEBBA, 0x8D6F, 0xEEB9, 0x8D70, 0xA8AB, 0x8D72, 0xD0B2, 0x8D73, 0xAD76, 0x8D74, 0xAD75, 0x8D76, 0xD3E3, 0x8D77, 0xB05F, 0x8D78, 0xD3E4, 0x8D79, 0xD7D5, 0x8D7B, 0xD7D4, 0x8D7D, 0xD7D3, 0x8D80, 0xDBEE, 0x8D81, 0xB658, 0x8D84, 0xDBED, 0x8D85, 0xB657, 0x8D89, 0xDBEF, 0x8D8A, 0xB656, 0x8D8C, 0xE05F, 0x8D8D, 0xE062, 0x8D8E, 0xE060, 0x8D8F, 0xE061, 0x8D90, 0xE065, 0x8D91, 0xE05E, 0x8D92, 0xE066, 0x8D93, 0xE063, 0x8D94, 0xE064, 0x8D95, 0xBBB0, 0x8D96, 0xE456, 0x8D99, 0xBBAF, 0x8D9B, 0xE7F2, 0x8D9C, 0xE7F0, 0x8D9F, 0xBDEB, 0x8DA0, 0xE7EF, 0x8DA1, 0xE7F1, 0x8DA3, 0xBDEC, 0x8DA5, 0xEBBB, 0x8DA7, 0xEBBC, 0x8DA8, 0xC1CD, 0x8DAA, 0xF34C, 0x8DAB, 0xF34E, 0x8DAC, 0xF34B, 0x8DAD, 0xF34D, 0x8DAE, 0xF4D6, 0x8DAF, 0xF654, 0x8DB2, 0xF96F, 0x8DB3, 0xA8AC, 0x8DB4, 0xAD77, 0x8DB5, 0xD3E5, 0x8DB6, 0xD3E7, 0x8DB7, 0xD3E6, 0x8DB9, 0xD7D8, 0x8DBA, 0xB36C, 0x8DBC, 0xD7D6, 0x8DBE, 0xB36B, 0x8DBF, 0xD7D9, 0x8DC1, 0xD7DA, 0x8DC2, 0xD7D7, 0x8DC5, 0xDBFB, 0x8DC6, 0xB660, 0x8DC7, 0xDBF3, 0x8DC8, 0xDBF9, 0x8DCB, 0xB65B, 0x8DCC, 0xB65E, 0x8DCD, 0xDBF2, 0x8DCE, 0xB659, 0x8DCF, 0xDBF6, 0x8DD0, 0xE06C, 0x8DD1, 0xB65D, 0x8DD3, 0xDBF1, 0x8DD5, 0xDBF7, 0x8DD6, 0xDBF4, 0x8DD7, 0xDBFA, 0x8DD8, 0xDBF0, 0x8DD9, 0xDBF8, 0x8DDA, 0xB65C, 0x8DDB, 0xB65F, 0x8DDC, 0xDBF5, 0x8DDD, 0xB65A, 0x8DDF, 0xB8F2, 0x8DE0, 0xE068, 0x8DE1, 0xB8F1, 0x8DE2, 0xE06F, 0x8DE3, 0xE06E, 0x8DE4, 0xB8F8, 0x8DE6, 0xB8F9, 0x8DE7, 0xE070, 0x8DE8, 0xB8F3, 0x8DE9, 0xE06D, 0x8DEA, 0xB8F7, 0x8DEB, 0xE072, 0x8DEC, 0xE069, 0x8DEE, 0xE06B, 0x8DEF, 0xB8F4, 0x8DF0, 0xE067, 0x8DF1, 0xE06A, 0x8DF2, 0xE071, 0x8DF3, 0xB8F5, 0x8DF4, 0xE073, 0x8DFA, 0xB8F6, 0x8DFC, 0xBBB1, 0x8DFD, 0xE45B, 0x8DFE, 0xE461, 0x8DFF, 0xE459, 0x8E00, 0xE462, 0x8E02, 0xE458, 0x8E03, 0xE45D, 0x8E04, 0xE463, 0x8E05, 0xE460, 0x8E06, 0xE45F, 0x8E07, 0xE45E, 0x8E09, 0xE457, 0x8E0A, 0xE45C, 0x8E0D, 0xE45A, 0x8E0F, 0xBDF1, 0x8E10, 0xBDEE, 0x8E11, 0xE7FB, 0x8E12, 0xE841, 0x8E13, 0xE843, 0x8E14, 0xE840, 0x8E15, 0xE7F8, 0x8E16, 0xE7FA, 0x8E17, 0xE845, 0x8E18, 0xE842, 0x8E19, 0xE7FC, 0x8E1A, 0xE846, 0x8E1B, 0xE7F9, 0x8E1C, 0xE844, 0x8E1D, 0xBDEF, 0x8E1E, 0xBDF5, 0x8E1F, 0xBDF3, 0x8E20, 0xE7F3, 0x8E21, 0xBDF4, 0x8E22, 0xBDF0, 0x8E23, 0xE7F4, 0x8E24, 0xE7F6, 0x8E25, 0xE7F5, 0x8E26, 0xE7FD, 0x8E27, 0xE7FE, 0x8E29, 0xBDF2, 0x8E2B, 0xBDED, 0x8E2E, 0xE7F7, 0x8E30, 0xEBC6, 0x8E31, 0xBFE2, 0x8E33, 0xEBBD, 0x8E34, 0xBFE3, 0x8E35, 0xBFE6, 0x8E36, 0xEBC2, 0x8E38, 0xEBBF, 0x8E39, 0xBFE5, 0x8E3C, 0xEBC3, 0x8E3D, 0xEBC4, 0x8E3E, 0xEBBE, 0x8E3F, 0xEBC7, 0x8E40, 0xEBC0, 0x8E41, 0xEBC5, 0x8E42, 0xBFE4, 0x8E44, 0xBFE1, 0x8E45, 0xEBC1, 0x8E47, 0xEEBF, 0x8E48, 0xC1D0, 0x8E49, 0xC1CE, 0x8E4A, 0xC1D1, 0x8E4B, 0xC1CF, 0x8E4C, 0xEEBE, 0x8E4D, 0xEEBB, 0x8E4E, 0xEEBA, 0x8E50, 0xEEBD, 0x8E53, 0xEEBC, 0x8E54, 0xF145, 0x8E55, 0xC2DE, 0x8E56, 0xF0FB, 0x8E57, 0xF0FA, 0x8E59, 0xC2D9, 0x8E5A, 0xF141, 0x8E5B, 0xF140, 0x8E5C, 0xF0F7, 0x8E5D, 0xF143, 0x8E5E, 0xF0FC, 0x8E5F, 0xC2DD, 0x8E60, 0xF0F9, 0x8E61, 0xF142, 0x8E62, 0xF0F8, 0x8E63, 0xC2DA, 0x8E64, 0xC2DC, 0x8E65, 0xF0FD, 0x8E66, 0xC2DB, 0x8E67, 0xF0FE, 0x8E69, 0xF144, 0x8E6A, 0xF352, 0x8E6C, 0xC3DE, 0x8E6D, 0xF34F, 0x8E6F, 0xF353, 0x8E72, 0xC3DB, 0x8E73, 0xF351, 0x8E74, 0xC3E0, 0x8E76, 0xC3DD, 0x8E78, 0xF350, 0x8E7A, 0xC3DF, 0x8E7B, 0xF354, 0x8E7C, 0xC3DA, 0x8E81, 0xC4BC, 0x8E82, 0xC4BE, 0x8E84, 0xF4D9, 0x8E85, 0xC4BD, 0x8E86, 0xF4D7, 0x8E87, 0xC3DC, 0x8E88, 0xF4D8, 0x8E89, 0xC4BB, 0x8E8A, 0xC543, 0x8E8B, 0xC545, 0x8E8C, 0xF656, 0x8E8D, 0xC544, 0x8E8E, 0xF655, 0x8E90, 0xF761, 0x8E91, 0xC5AD, 0x8E92, 0xF760, 0x8E93, 0xC5AE, 0x8E94, 0xF75E, 0x8E95, 0xF75D, 0x8E96, 0xF762, 0x8E97, 0xF763, 0x8E98, 0xF846, 0x8E9A, 0xF75F, 0x8E9D, 0xF8C6, 0x8E9E, 0xF8C3, 0x8E9F, 0xF8C4, 0x8EA0, 0xF8C5, 0x8EA1, 0xC65C, 0x8EA3, 0xF951, 0x8EA4, 0xF950, 0x8EA5, 0xF94F, 0x8EA6, 0xF970, 0x8EA8, 0xF9BE, 0x8EA9, 0xF9AB, 0x8EAA, 0xC66E, 0x8EAB, 0xA8AD, 0x8EAC, 0xB060, 0x8EB2, 0xB8FA, 0x8EBA, 0xBDF6, 0x8EBD, 0xEBC8, 0x8EC0, 0xC2DF, 0x8EC2, 0xF355, 0x8EC9, 0xF9AC, 0x8ECA, 0xA8AE, 0x8ECB, 0xAAEE, 0x8ECC, 0xAD79, 0x8ECD, 0xAD78, 0x8ECF, 0xB063, 0x8ED1, 0xD3E8, 0x8ED2, 0xB061, 0x8ED3, 0xD3E9, 0x8ED4, 0xB062, 0x8ED7, 0xD7DF, 0x8ED8, 0xD7DB, 0x8EDB, 0xB36D, 0x8EDC, 0xD7DE, 0x8EDD, 0xD7DD, 0x8EDE, 0xD7DC, 0x8EDF, 0xB36E, 0x8EE0, 0xD7E0, 0x8EE1, 0xD7E1, 0x8EE5, 0xDC43, 0x8EE6, 0xDC41, 0x8EE7, 0xDC45, 0x8EE8, 0xDC46, 0x8EE9, 0xDC4C, 0x8EEB, 0xDC48, 0x8EEC, 0xDC4A, 0x8EEE, 0xDC42, 0x8EEF, 0xDBFC, 0x8EF1, 0xDC49, 0x8EF4, 0xDC4B, 0x8EF5, 0xDC44, 0x8EF6, 0xDC47, 0x8EF7, 0xDBFD, 0x8EF8, 0xB662, 0x8EF9, 0xDC40, 0x8EFA, 0xDBFE, 0x8EFB, 0xB661, 0x8EFC, 0xB663, 0x8EFE, 0xB8FD, 0x8EFF, 0xE075, 0x8F00, 0xE077, 0x8F01, 0xE076, 0x8F02, 0xE07B, 0x8F03, 0xB8FB, 0x8F05, 0xE078, 0x8F06, 0xE074, 0x8F07, 0xE079, 0x8F08, 0xE07A, 0x8F09, 0xB8FC, 0x8F0A, 0xB8FE, 0x8F0B, 0xE07C, 0x8F0D, 0xE467, 0x8F0E, 0xE466, 0x8F10, 0xE464, 0x8F11, 0xE465, 0x8F12, 0xBBB3, 0x8F13, 0xBBB5, 0x8F14, 0xBBB2, 0x8F15, 0xBBB4, 0x8F16, 0xE84D, 0x8F17, 0xE84E, 0x8F18, 0xE849, 0x8F1A, 0xE84A, 0x8F1B, 0xBDF8, 0x8F1C, 0xBDFD, 0x8F1D, 0xBDF7, 0x8F1E, 0xBDFE, 0x8F1F, 0xBDF9, 0x8F20, 0xE84B, 0x8F23, 0xE84C, 0x8F24, 0xE848, 0x8F25, 0xBE40, 0x8F26, 0xBDFB, 0x8F29, 0xBDFA, 0x8F2A, 0xBDFC, 0x8F2C, 0xE847, 0x8F2E, 0xEBCA, 0x8F2F, 0xBFE8, 0x8F32, 0xEBCC, 0x8F33, 0xBFEA, 0x8F34, 0xEBCF, 0x8F35, 0xEBCB, 0x8F36, 0xEBC9, 0x8F37, 0xEBCE, 0x8F38, 0xBFE9, 0x8F39, 0xEBCD, 0x8F3B, 0xBFE7, 0x8F3E, 0xC1D3, 0x8F3F, 0xC1D6, 0x8F40, 0xEEC1, 0x8F42, 0xC1D4, 0x8F43, 0xEEC0, 0x8F44, 0xC1D2, 0x8F45, 0xC1D5, 0x8F46, 0xF146, 0x8F47, 0xF147, 0x8F48, 0xF148, 0x8F49, 0xC2E0, 0x8F4B, 0xF149, 0x8F4D, 0xC2E1, 0x8F4E, 0xC3E2, 0x8F4F, 0xF358, 0x8F50, 0xF359, 0x8F51, 0xF357, 0x8F52, 0xF356, 0x8F53, 0xF35A, 0x8F54, 0xC3E1, 0x8F55, 0xF4DD, 0x8F56, 0xF4DB, 0x8F57, 0xF4DC, 0x8F58, 0xF4DE, 0x8F59, 0xF4DA, 0x8F5A, 0xF4DF, 0x8F5B, 0xF658, 0x8F5D, 0xF659, 0x8F5E, 0xF657, 0x8F5F, 0xC546, 0x8F60, 0xF764, 0x8F61, 0xC5AF, 0x8F62, 0xF765, 0x8F63, 0xF848, 0x8F64, 0xF847, 0x8F9B, 0xA8AF, 0x8F9C, 0xB664, 0x8F9F, 0xB940, 0x8FA3, 0xBBB6, 0x8FA6, 0xBFEC, 0x8FA8, 0xBFEB, 0x8FAD, 0xC3E3, 0x8FAE, 0xC47C, 0x8FAF, 0xC547, 0x8FB0, 0xA8B0, 0x8FB1, 0xB064, 0x8FB2, 0xB941, 0x8FB4, 0xF35B, 0x8FBF, 0xCBA6, 0x8FC2, 0xA8B1, 0x8FC4, 0xA8B4, 0x8FC5, 0xA8B3, 0x8FC6, 0xA8B2, 0x8FC9, 0xCBA5, 0x8FCB, 0xCDCD, 0x8FCD, 0xCDCF, 0x8FCE, 0xAAEF, 0x8FD1, 0xAAF1, 0x8FD2, 0xCDCC, 0x8FD3, 0xCDCE, 0x8FD4, 0xAAF0, 0x8FD5, 0xCDD1, 0x8FD6, 0xCDD0, 0x8FD7, 0xCDD2, 0x8FE0, 0xD0B6, 0x8FE1, 0xD0B4, 0x8FE2, 0xAD7C, 0x8FE3, 0xD0B3, 0x8FE4, 0xADA3, 0x8FE5, 0xAD7E, 0x8FE6, 0xAD7B, 0x8FE8, 0xADA4, 0x8FEA, 0xAD7D, 0x8FEB, 0xADA2, 0x8FED, 0xADA1, 0x8FEE, 0xD0B5, 0x8FF0, 0xAD7A, 0x8FF4, 0xB06A, 0x8FF5, 0xD3EB, 0x8FF6, 0xD3F1, 0x8FF7, 0xB067, 0x8FF8, 0xB06E, 0x8FFA, 0xB069, 0x8FFB, 0xD3EE, 0x8FFC, 0xD3F0, 0x8FFD, 0xB06C, 0x8FFE, 0xD3EA, 0x8FFF, 0xD3ED, 0x9000, 0xB068, 0x9001, 0xB065, 0x9002, 0xD3EC, 0x9003, 0xB06B, 0x9004, 0xD3EF, 0x9005, 0xB06D, 0x9006, 0xB066, 0x900B, 0xD7E3, 0x900C, 0xD7E6, 0x900D, 0xB370, 0x900F, 0xB37A, 0x9010, 0xB376, 0x9011, 0xD7E4, 0x9014, 0xB37E, 0x9015, 0xB377, 0x9016, 0xB37C, 0x9017, 0xB372, 0x9019, 0xB36F, 0x901A, 0xB371, 0x901B, 0xB37D, 0x901C, 0xD7E5, 0x901D, 0xB375, 0x901E, 0xB378, 0x901F, 0xB374, 0x9020, 0xB379, 0x9021, 0xD7E7, 0x9022, 0xB37B, 0x9023, 0xB373, 0x9024, 0xD7E2, 0x902D, 0xDC4D, 0x902E, 0xB665, 0x902F, 0xDC4F, 0x9031, 0xB667, 0x9032, 0xB669, 0x9034, 0xDC4E, 0x9035, 0xB666, 0x9036, 0xB66A, 0x9038, 0xB668, 0x903C, 0xB947, 0x903D, 0xE0A3, 0x903E, 0xB94F, 0x903F, 0xE07E, 0x9041, 0xB950, 0x9042, 0xB945, 0x9044, 0xE0A1, 0x9047, 0xB94A, 0x9049, 0xE0A2, 0x904A, 0xB943, 0x904B, 0xB942, 0x904D, 0xB94D, 0x904E, 0xB94C, 0x904F, 0xB94B, 0x9050, 0xB949, 0x9051, 0xB94E, 0x9052, 0xE07D, 0x9053, 0xB944, 0x9054, 0xB946, 0x9055, 0xB948, 0x9058, 0xBBB8, 0x9059, 0xBBBB, 0x905B, 0xBBBF, 0x905C, 0xBBB9, 0x905D, 0xBBBE, 0x905E, 0xBBBC, 0x9060, 0xBBB7, 0x9062, 0xBBBD, 0x9063, 0xBBBA, 0x9067, 0xE852, 0x9068, 0xBE43, 0x9069, 0xBE41, 0x906B, 0xE853, 0x906D, 0xBE44, 0x906E, 0xBE42, 0x906F, 0xE851, 0x9070, 0xE850, 0x9072, 0xBFF0, 0x9073, 0xE84F, 0x9074, 0xBFEE, 0x9075, 0xBFED, 0x9076, 0xEBD0, 0x9077, 0xBE45, 0x9078, 0xBFEF, 0x9079, 0xEBD1, 0x907A, 0xBFF2, 0x907B, 0xEBD2, 0x907C, 0xBFF1, 0x907D, 0xC1D8, 0x907E, 0xEEC3, 0x907F, 0xC1D7, 0x9080, 0xC1DC, 0x9081, 0xC1DA, 0x9082, 0xC1DB, 0x9083, 0xC2E3, 0x9084, 0xC1D9, 0x9085, 0xEEC2, 0x9086, 0xEBD3, 0x9087, 0xC2E2, 0x9088, 0xC2E4, 0x908A, 0xC3E4, 0x908B, 0xC3E5, 0x908D, 0xF4E0, 0x908F, 0xC5DE, 0x9090, 0xC5DD, 0x9091, 0xA8B6, 0x9094, 0xCA55, 0x9095, 0xB06F, 0x9097, 0xCA52, 0x9098, 0xCA53, 0x9099, 0xCA51, 0x909B, 0xCA54, 0x909E, 0xCBAA, 0x909F, 0xCBA7, 0x90A0, 0xCBAC, 0x90A1, 0xCBA8, 0x90A2, 0xA8B7, 0x90A3, 0xA8BA, 0x90A5, 0xCBA9, 0x90A6, 0xA8B9, 0x90A7, 0xCBAB, 0x90AA, 0xA8B8, 0x90AF, 0xCDD5, 0x90B0, 0xCDD7, 0x90B1, 0xAAF4, 0x90B2, 0xCDD3, 0x90B3, 0xCDD6, 0x90B4, 0xCDD4, 0x90B5, 0xAAF2, 0x90B6, 0xAAF5, 0x90B8, 0xAAF3, 0x90BD, 0xD0B8, 0x90BE, 0xD0BC, 0x90BF, 0xD0B9, 0x90C1, 0xADA7, 0x90C3, 0xADA8, 0x90C5, 0xD0BB, 0x90C7, 0xD0BD, 0x90C8, 0xD0BF, 0x90CA, 0xADA5, 0x90CB, 0xD0BE, 0x90CE, 0xADA6, 0x90D4, 0xD7EE, 0x90D5, 0xD0BA, 0x90D6, 0xD3F2, 0x90D7, 0xD3FB, 0x90D8, 0xD3F9, 0x90D9, 0xD3F4, 0x90DA, 0xD3F5, 0x90DB, 0xD3FA, 0x90DC, 0xD3FC, 0x90DD, 0xB071, 0x90DF, 0xD3F7, 0x90E0, 0xD3F3, 0x90E1, 0xB070, 0x90E2, 0xB072, 0x90E3, 0xD3F6, 0x90E4, 0xD3FD, 0x90E5, 0xD3F8, 0x90E8, 0xB3A1, 0x90E9, 0xD7F1, 0x90EA, 0xD7E9, 0x90EB, 0xD7EF, 0x90EC, 0xD7F0, 0x90ED, 0xB3A2, 0x90EF, 0xD7E8, 0x90F0, 0xD7EA, 0x90F1, 0xD0B7, 0x90F2, 0xD7EC, 0x90F3, 0xD7ED, 0x90F4, 0xD7EB, 0x90F5, 0xB66C, 0x90F9, 0xDC56, 0x90FA, 0xEBD4, 0x90FB, 0xDC57, 0x90FC, 0xDC54, 0x90FD, 0xB3A3, 0x90FE, 0xB66E, 0x90FF, 0xDC53, 0x9100, 0xDC59, 0x9101, 0xDC58, 0x9102, 0xB66B, 0x9103, 0xDC5C, 0x9104, 0xDC52, 0x9105, 0xDC5B, 0x9106, 0xDC50, 0x9107, 0xDC5A, 0x9108, 0xDC55, 0x9109, 0xB66D, 0x910B, 0xE0AA, 0x910D, 0xE0A5, 0x910E, 0xE0AB, 0x910F, 0xE0A6, 0x9110, 0xE0A4, 0x9111, 0xE0A7, 0x9112, 0xB951, 0x9114, 0xE0A9, 0x9116, 0xE0A8, 0x9117, 0xB952, 0x9118, 0xBBC1, 0x9119, 0xBBC0, 0x911A, 0xE46E, 0x911B, 0xE471, 0x911C, 0xE469, 0x911D, 0xE46D, 0x911E, 0xBBC2, 0x911F, 0xE46C, 0x9120, 0xE46A, 0x9121, 0xE470, 0x9122, 0xE46B, 0x9123, 0xE468, 0x9124, 0xE46F, 0x9126, 0xE859, 0x9127, 0xBE48, 0x9128, 0xF14A, 0x9129, 0xE856, 0x912A, 0xE857, 0x912B, 0xE855, 0x912C, 0xDC51, 0x912D, 0xBE47, 0x912E, 0xE85A, 0x912F, 0xE854, 0x9130, 0xBE46, 0x9131, 0xBE49, 0x9132, 0xE858, 0x9133, 0xEBD5, 0x9134, 0xBFF3, 0x9135, 0xEBD6, 0x9136, 0xEBD7, 0x9138, 0xEEC4, 0x9139, 0xC1DD, 0x913A, 0xF14B, 0x913B, 0xF14C, 0x913E, 0xF14D, 0x913F, 0xF35D, 0x9140, 0xF35C, 0x9141, 0xF4E2, 0x9143, 0xF4E1, 0x9144, 0xF65B, 0x9145, 0xF65C, 0x9146, 0xF65A, 0x9147, 0xF766, 0x9148, 0xC5B0, 0x9149, 0xA8BB, 0x914A, 0xADAA, 0x914B, 0xADA9, 0x914C, 0xB075, 0x914D, 0xB074, 0x914E, 0xD440, 0x914F, 0xD441, 0x9150, 0xD3FE, 0x9152, 0xB073, 0x9153, 0xD7F5, 0x9155, 0xD7F6, 0x9156, 0xD7F2, 0x9157, 0xB3A4, 0x9158, 0xD7F3, 0x915A, 0xD7F4, 0x915F, 0xDC5F, 0x9160, 0xDC61, 0x9161, 0xDC5D, 0x9162, 0xDC60, 0x9163, 0xB66F, 0x9164, 0xDC5E, 0x9165, 0xB670, 0x9168, 0xDD73, 0x9169, 0xB955, 0x916A, 0xB954, 0x916C, 0xB953, 0x916E, 0xE0AC, 0x916F, 0xE0AD, 0x9172, 0xE473, 0x9173, 0xE475, 0x9174, 0xBBC6, 0x9175, 0xBBC3, 0x9177, 0xBBC5, 0x9178, 0xBBC4, 0x9179, 0xE474, 0x917A, 0xE472, 0x9180, 0xE861, 0x9181, 0xE85E, 0x9182, 0xE85F, 0x9183, 0xBE4D, 0x9184, 0xE860, 0x9185, 0xE85B, 0x9186, 0xE85C, 0x9187, 0xBE4A, 0x9189, 0xBE4B, 0x918A, 0xE85D, 0x918B, 0xBE4C, 0x918D, 0xEBDB, 0x918F, 0xEBDC, 0x9190, 0xEBD9, 0x9191, 0xEBDA, 0x9192, 0xBFF4, 0x9193, 0xEBD8, 0x9199, 0xEEC8, 0x919A, 0xEEC5, 0x919B, 0xEEC7, 0x919C, 0xC1E0, 0x919D, 0xEECB, 0x919E, 0xC1DF, 0x919F, 0xEEC9, 0x91A0, 0xEECC, 0x91A1, 0xEECA, 0x91A2, 0xEEC6, 0x91A3, 0xC1DE, 0x91A5, 0xF14F, 0x91A7, 0xF150, 0x91A8, 0xF14E, 0x91AA, 0xF152, 0x91AB, 0xC2E5, 0x91AC, 0xC2E6, 0x91AD, 0xF35F, 0x91AE, 0xC3E7, 0x91AF, 0xF151, 0x91B0, 0xF35E, 0x91B1, 0xC3E6, 0x91B2, 0xF4E5, 0x91B3, 0xF4E6, 0x91B4, 0xC4BF, 0x91B5, 0xF4E4, 0x91B7, 0xF4E3, 0x91B9, 0xF65D, 0x91BA, 0xC548, 0x91BC, 0xF849, 0x91BD, 0xF8C8, 0x91BE, 0xF8C7, 0x91C0, 0xC643, 0x91C1, 0xC65D, 0x91C2, 0xF8C9, 0x91C3, 0xF971, 0x91C5, 0xC66F, 0x91C6, 0xA8BC, 0x91C7, 0xAAF6, 0x91C9, 0xB956, 0x91CB, 0xC4C0, 0x91CC, 0xA8BD, 0x91CD, 0xADAB, 0x91CE, 0xB3A5, 0x91CF, 0xB671, 0x91D0, 0xC2E7, 0x91D1, 0xAAF7, 0x91D3, 0xD0C1, 0x91D4, 0xD0C0, 0x91D5, 0xD442, 0x91D7, 0xB078, 0x91D8, 0xB076, 0x91D9, 0xB07A, 0x91DA, 0xD444, 0x91DC, 0xB079, 0x91DD, 0xB077, 0x91E2, 0xD443, 0x91E3, 0xB3A8, 0x91E4, 0xD7FC, 0x91E6, 0xB3A7, 0x91E7, 0xB3A9, 0x91E8, 0xD842, 0x91E9, 0xB3AB, 0x91EA, 0xD7FE, 0x91EB, 0xD840, 0x91EC, 0xD7F7, 0x91ED, 0xB3AA, 0x91EE, 0xD843, 0x91F1, 0xD7F9, 0x91F3, 0xD7FA, 0x91F4, 0xD7F8, 0x91F5, 0xB3A6, 0x91F7, 0xD841, 0x91F8, 0xD7FB, 0x91F9, 0xD7FD, 0x91FD, 0xDC6D, 0x91FF, 0xDC6C, 0x9200, 0xDC6A, 0x9201, 0xDC62, 0x9202, 0xDC71, 0x9203, 0xDC65, 0x9204, 0xDC6F, 0x9205, 0xDC76, 0x9206, 0xDC6E, 0x9207, 0xB679, 0x9209, 0xB675, 0x920A, 0xDC63, 0x920C, 0xDC69, 0x920D, 0xB677, 0x920F, 0xDC68, 0x9210, 0xB678, 0x9211, 0xB67A, 0x9212, 0xDC6B, 0x9214, 0xB672, 0x9215, 0xB673, 0x9216, 0xDC77, 0x9217, 0xDC75, 0x9219, 0xDC74, 0x921A, 0xDC66, 0x921C, 0xDC72, 0x921E, 0xB676, 0x9223, 0xB674, 0x9224, 0xDC73, 0x9225, 0xDC64, 0x9226, 0xDC67, 0x9227, 0xDC70, 0x922D, 0xE4BA, 0x922E, 0xE0B7, 0x9230, 0xE0B0, 0x9231, 0xE0C3, 0x9232, 0xE0CC, 0x9233, 0xE0B3, 0x9234, 0xB961, 0x9236, 0xE0C0, 0x9237, 0xB957, 0x9238, 0xB959, 0x9239, 0xB965, 0x923A, 0xE0B1, 0x923D, 0xB95A, 0x923E, 0xB95C, 0x923F, 0xB966, 0x9240, 0xB95B, 0x9245, 0xB964, 0x9246, 0xE0B9, 0x9248, 0xE0AE, 0x9249, 0xB962, 0x924A, 0xE0B8, 0x924B, 0xB95E, 0x924C, 0xE0CA, 0x924D, 0xB963, 0x924E, 0xE0C8, 0x924F, 0xE0BC, 0x9250, 0xE0C6, 0x9251, 0xB960, 0x9252, 0xE0AF, 0x9253, 0xE0C9, 0x9254, 0xE0C4, 0x9256, 0xE0CB, 0x9257, 0xB958, 0x925A, 0xB967, 0x925B, 0xB95D, 0x925E, 0xE0B5, 0x9260, 0xE0BD, 0x9261, 0xE0C1, 0x9263, 0xE0C5, 0x9264, 0xB95F, 0x9265, 0xE0B4, 0x9266, 0xE0B2, 0x9267, 0xE0BE, 0x926C, 0xE0BB, 0x926D, 0xE0BA, 0x926F, 0xE0BF, 0x9270, 0xE0C2, 0x9272, 0xE0C7, 0x9276, 0xE478, 0x9278, 0xBBC7, 0x9279, 0xE4A4, 0x927A, 0xE47A, 0x927B, 0xBBCC, 0x927C, 0xBBD0, 0x927D, 0xE4AD, 0x927E, 0xE4B5, 0x927F, 0xE4A6, 0x9280, 0xBBC8, 0x9282, 0xE4AA, 0x9283, 0xE0B6, 0x9285, 0xBBC9, 0x9286, 0xE4B1, 0x9287, 0xE4B6, 0x9288, 0xE4AE, 0x928A, 0xE4B0, 0x928B, 0xE4B9, 0x928C, 0xE4B2, 0x928D, 0xE47E, 0x928E, 0xE4A9, 0x9291, 0xBBD1, 0x9293, 0xBBCD, 0x9294, 0xE47C, 0x9295, 0xE4AB, 0x9296, 0xBBCB, 0x9297, 0xE4A5, 0x9298, 0xBBCA, 0x9299, 0xE4B3, 0x929A, 0xE4A2, 0x929B, 0xE479, 0x929C, 0xBBCE, 0x929D, 0xE4B8, 0x92A0, 0xE47B, 0x92A1, 0xE4AF, 0x92A2, 0xE4AC, 0x92A3, 0xE4A7, 0x92A4, 0xE477, 0x92A5, 0xE476, 0x92A6, 0xE4A1, 0x92A7, 0xE4B4, 0x92A8, 0xBBCF, 0x92A9, 0xE4B7, 0x92AA, 0xE47D, 0x92AB, 0xE4A3, 0x92AC, 0xBE52, 0x92B2, 0xBE5A, 0x92B3, 0xBE55, 0x92B4, 0xE8A4, 0x92B5, 0xE8A1, 0x92B6, 0xE867, 0x92B7, 0xBE50, 0x92B9, 0xF9D7, 0x92BB, 0xBE4F, 0x92BC, 0xBE56, 0x92C0, 0xE865, 0x92C1, 0xBE54, 0x92C2, 0xE871, 0x92C3, 0xE863, 0x92C4, 0xE864, 0x92C5, 0xBE4E, 0x92C6, 0xE8A3, 0x92C7, 0xBE58, 0x92C8, 0xE874, 0x92C9, 0xE879, 0x92CA, 0xE873, 0x92CB, 0xEBEE, 0x92CC, 0xE86F, 0x92CD, 0xE877, 0x92CE, 0xE875, 0x92CF, 0xE868, 0x92D0, 0xE862, 0x92D1, 0xE87D, 0x92D2, 0xBE57, 0x92D3, 0xE87E, 0x92D5, 0xE878, 0x92D7, 0xE86D, 0x92D8, 0xE86B, 0x92D9, 0xE866, 0x92DD, 0xE86E, 0x92DE, 0xE87B, 0x92DF, 0xE86A, 0x92E0, 0xE87A, 0x92E1, 0xE8A2, 0x92E4, 0xBE53, 0x92E6, 0xE876, 0x92E7, 0xE87C, 0x92E8, 0xE872, 0x92E9, 0xE86C, 0x92EA, 0xBE51, 0x92EE, 0xE4A8, 0x92EF, 0xE870, 0x92F0, 0xBE59, 0x92F1, 0xE869, 0x92F7, 0xEBF4, 0x92F8, 0xBFF7, 0x92F9, 0xEBF3, 0x92FA, 0xEBF0, 0x92FB, 0xEC44, 0x92FC, 0xBFFB, 0x92FE, 0xEC41, 0x92FF, 0xEBF8, 0x9300, 0xEC43, 0x9301, 0xEBE9, 0x9302, 0xEBF6, 0x9304, 0xBFFD, 0x9306, 0xEBE1, 0x9308, 0xEBDF, 0x9309, 0xEC42, 0x930B, 0xEC40, 0x930C, 0xEBFE, 0x930D, 0xEBED, 0x930E, 0xEBEC, 0x930F, 0xEBE2, 0x9310, 0xC040, 0x9312, 0xEBE8, 0x9313, 0xEBF2, 0x9314, 0xEBFD, 0x9315, 0xC043, 0x9316, 0xEC45, 0x9318, 0xC1E8, 0x9319, 0xC045, 0x931A, 0xBFFE, 0x931B, 0xEBE6, 0x931D, 0xEBEF, 0x931E, 0xEBDE, 0x931F, 0xEBE0, 0x9320, 0xBFF5, 0x9321, 0xC042, 0x9322, 0xBFFA, 0x9323, 0xEBE7, 0x9324, 0xEBF7, 0x9325, 0xEBF1, 0x9326, 0xC041, 0x9327, 0xEBDD, 0x9328, 0xC1E3, 0x9329, 0xEBF9, 0x932A, 0xEBFC, 0x932B, 0xBFFC, 0x932D, 0xEBEB, 0x932E, 0xC044, 0x932F, 0xBFF9, 0x9333, 0xBFF8, 0x9334, 0xEBF5, 0x9335, 0xEBFB, 0x9336, 0xBFF6, 0x9338, 0xEBE4, 0x9339, 0xEBFA, 0x933C, 0xEBE5, 0x9346, 0xEBEA, 0x9347, 0xEED2, 0x9349, 0xEED7, 0x934A, 0xC1E5, 0x934B, 0xC1E7, 0x934C, 0xEEDD, 0x934D, 0xC1E1, 0x934E, 0xEEEC, 0x934F, 0xEEE3, 0x9350, 0xEED8, 0x9351, 0xEED9, 0x9352, 0xEEE2, 0x9354, 0xC1EE, 0x9355, 0xEEE1, 0x9356, 0xEED1, 0x9357, 0xEEE0, 0x9358, 0xEED4, 0x9359, 0xEEED, 0x935A, 0xC1ED, 0x935B, 0xC1EB, 0x935C, 0xEED5, 0x935E, 0xEEE8, 0x9360, 0xEEDA, 0x9361, 0xEEE7, 0x9363, 0xEEE9, 0x9364, 0xEED0, 0x9365, 0xC1E6, 0x9367, 0xEEEA, 0x936A, 0xEEDE, 0x936C, 0xC1EA, 0x936D, 0xEEDB, 0x9370, 0xC1EC, 0x9371, 0xEEE4, 0x9375, 0xC1E4, 0x9376, 0xEED6, 0x9377, 0xEEE5, 0x9379, 0xEEDF, 0x937A, 0xEBE3, 0x937B, 0xEEE6, 0x937C, 0xEED3, 0x937E, 0xC1E9, 0x9380, 0xEEEB, 0x9382, 0xC1E2, 0x9383, 0xEECE, 0x9388, 0xF160, 0x9389, 0xF159, 0x938A, 0xC2E9, 0x938C, 0xF154, 0x938D, 0xF163, 0x938E, 0xF15B, 0x938F, 0xEEDC, 0x9391, 0xF165, 0x9392, 0xF155, 0x9394, 0xC2E8, 0x9395, 0xF15F, 0x9396, 0xC2EA, 0x9397, 0xC2F2, 0x9398, 0xC2F0, 0x9399, 0xF161, 0x939A, 0xC2F1, 0x939B, 0xF157, 0x939D, 0xF158, 0x939E, 0xF15D, 0x939F, 0xF162, 0x93A1, 0xEECD, 0x93A2, 0xC2EB, 0x93A3, 0xF16A, 0x93A4, 0xF167, 0x93A5, 0xF16B, 0x93A6, 0xF15E, 0x93A7, 0xF15A, 0x93A8, 0xF168, 0x93A9, 0xF36A, 0x93AA, 0xF15C, 0x93AC, 0xC2EE, 0x93AE, 0xC2ED, 0x93AF, 0xEECF, 0x93B0, 0xC2EF, 0x93B1, 0xF164, 0x93B2, 0xF166, 0x93B3, 0xC2EC, 0x93B4, 0xF169, 0x93B5, 0xF153, 0x93B7, 0xF156, 0x93C0, 0xF373, 0x93C2, 0xF363, 0x93C3, 0xC3EB, 0x93C4, 0xF371, 0x93C7, 0xF361, 0x93C8, 0xC3EC, 0x93CA, 0xF36C, 0x93CC, 0xF368, 0x93CD, 0xC3F1, 0x93CE, 0xF372, 0x93CF, 0xF362, 0x93D0, 0xF365, 0x93D1, 0xC3E9, 0x93D2, 0xF374, 0x93D4, 0xF36D, 0x93D5, 0xF370, 0x93D6, 0xC3EF, 0x93D7, 0xC3F4, 0x93D8, 0xC3F2, 0x93D9, 0xF369, 0x93DA, 0xF364, 0x93DC, 0xC3ED, 0x93DD, 0xC3EE, 0x93DE, 0xF360, 0x93DF, 0xC3EA, 0x93E1, 0xC3E8, 0x93E2, 0xC3F0, 0x93E3, 0xF36F, 0x93E4, 0xC3F3, 0x93E6, 0xF36B, 0x93E7, 0xF375, 0x93E8, 0xC3F5, 0x93EC, 0xF367, 0x93EE, 0xF36E, 0x93F5, 0xF4F3, 0x93F6, 0xF542, 0x93F7, 0xF4F5, 0x93F8, 0xF4FC, 0x93F9, 0xF366, 0x93FA, 0xF4FA, 0x93FB, 0xF4E9, 0x93FC, 0xF540, 0x93FD, 0xC4C3, 0x93FE, 0xF4ED, 0x93FF, 0xF4FE, 0x9400, 0xF4F4, 0x9403, 0xC4C2, 0x9406, 0xF544, 0x9407, 0xF4F6, 0x9409, 0xF4FB, 0x940A, 0xF4FD, 0x940B, 0xF4E7, 0x940C, 0xF541, 0x940D, 0xF4F2, 0x940E, 0xF4F7, 0x940F, 0xF4EB, 0x9410, 0xF4EF, 0x9411, 0xF543, 0x9412, 0xF4F9, 0x9413, 0xF4E8, 0x9414, 0xF4EC, 0x9415, 0xF4EE, 0x9416, 0xF4F8, 0x9418, 0xC4C1, 0x9419, 0xF4F1, 0x9420, 0xF4EA, 0x9428, 0xF4F0, 0x9429, 0xF661, 0x942A, 0xF666, 0x942B, 0xC54F, 0x942C, 0xF668, 0x942E, 0xC549, 0x9430, 0xF664, 0x9431, 0xF66A, 0x9432, 0xC54E, 0x9433, 0xC54A, 0x9435, 0xC54B, 0x9436, 0xF660, 0x9437, 0xF667, 0x9438, 0xC54D, 0x9439, 0xF665, 0x943A, 0xC54C, 0x943B, 0xF65F, 0x943C, 0xF663, 0x943D, 0xF662, 0x943F, 0xF65E, 0x9440, 0xF669, 0x9444, 0xC5B1, 0x9445, 0xF76D, 0x9446, 0xF770, 0x9447, 0xF76C, 0x9448, 0xF76E, 0x9449, 0xF76F, 0x944A, 0xF769, 0x944B, 0xF76A, 0x944C, 0xF767, 0x944F, 0xF76B, 0x9450, 0xF768, 0x9451, 0xC5B2, 0x9452, 0xC5B3, 0x9455, 0xF84B, 0x9457, 0xF84D, 0x945D, 0xF84C, 0x945E, 0xF84E, 0x9460, 0xC5E0, 0x9462, 0xF84A, 0x9463, 0xC5DF, 0x9464, 0xC5E1, 0x9468, 0xF8CB, 0x9469, 0xF8CC, 0x946A, 0xC644, 0x946B, 0xF8CA, 0x946D, 0xF953, 0x946E, 0xF952, 0x946F, 0xF954, 0x9470, 0xC65F, 0x9471, 0xF955, 0x9472, 0xC65E, 0x9473, 0xF956, 0x9474, 0xF972, 0x9475, 0xF975, 0x9476, 0xF974, 0x9477, 0xC668, 0x9478, 0xF973, 0x947C, 0xC672, 0x947D, 0xC670, 0x947E, 0xC671, 0x947F, 0xC677, 0x9480, 0xF9C0, 0x9481, 0xF9C1, 0x9482, 0xF9BF, 0x9483, 0xF9C9, 0x9577, 0xAAF8, 0x957A, 0xD844, 0x957B, 0xDC78, 0x957C, 0xE8A5, 0x957D, 0xF376, 0x9580, 0xAAF9, 0x9582, 0xADAC, 0x9583, 0xB07B, 0x9586, 0xD845, 0x9588, 0xD846, 0x9589, 0xB3AC, 0x958B, 0xB67D, 0x958C, 0xDC7A, 0x958D, 0xDC79, 0x958E, 0xB6A3, 0x958F, 0xB67C, 0x9590, 0xDC7B, 0x9591, 0xB67E, 0x9592, 0xB6A2, 0x9593, 0xB6A1, 0x9594, 0xB67B, 0x9598, 0xB968, 0x959B, 0xE0D0, 0x959C, 0xE0CE, 0x959E, 0xE0CF, 0x959F, 0xE0CD, 0x95A1, 0xBBD2, 0x95A3, 0xBBD5, 0x95A4, 0xBBD7, 0x95A5, 0xBBD6, 0x95A8, 0xBBD3, 0x95A9, 0xBBD4, 0x95AB, 0xE8A7, 0x95AC, 0xE8A6, 0x95AD, 0xBE5B, 0x95AE, 0xE8A8, 0x95B0, 0xE8A9, 0x95B1, 0xBE5C, 0x95B5, 0xEC4D, 0x95B6, 0xEC4B, 0x95B7, 0xEEF3, 0x95B9, 0xEC49, 0x95BA, 0xEC4A, 0x95BB, 0xC046, 0x95BC, 0xEC46, 0x95BD, 0xEC4E, 0x95BE, 0xEC48, 0x95BF, 0xEC4C, 0x95C0, 0xEEEF, 0x95C3, 0xEEF1, 0x95C5, 0xEEF2, 0x95C6, 0xC1F3, 0x95C7, 0xEEEE, 0x95C8, 0xC1F2, 0x95C9, 0xEEF0, 0x95CA, 0xC1EF, 0x95CB, 0xC1F0, 0x95CC, 0xC1F1, 0x95CD, 0xEC47, 0x95D0, 0xC2F5, 0x95D1, 0xF16E, 0x95D2, 0xF16C, 0x95D3, 0xF16D, 0x95D4, 0xC2F3, 0x95D5, 0xC2F6, 0x95D6, 0xC2F4, 0x95DA, 0xF377, 0x95DB, 0xF378, 0x95DC, 0xC3F6, 0x95DE, 0xF545, 0x95DF, 0xF547, 0x95E0, 0xF546, 0x95E1, 0xC4C4, 0x95E2, 0xC550, 0x95E3, 0xF66D, 0x95E4, 0xF66C, 0x95E5, 0xF66B, 0x961C, 0xAAFA, 0x961E, 0xC9AA, 0x9620, 0xCA58, 0x9621, 0xA6E9, 0x9622, 0xCA56, 0x9623, 0xCA59, 0x9624, 0xCA57, 0x9628, 0xCBAE, 0x962A, 0xA8C1, 0x962C, 0xA8C2, 0x962D, 0xCBB0, 0x962E, 0xA8BF, 0x962F, 0xCBAF, 0x9630, 0xCBAD, 0x9631, 0xA8C0, 0x9632, 0xA8BE, 0x9639, 0xCDD8, 0x963A, 0xCDDB, 0x963B, 0xAAFD, 0x963C, 0xCDDA, 0x963D, 0xCDD9, 0x963F, 0xAAFC, 0x9640, 0xAAFB, 0x9642, 0xAB40, 0x9643, 0xCDDC, 0x9644, 0xAAFE, 0x964A, 0xD0C6, 0x964B, 0xADAE, 0x964C, 0xADAF, 0x964D, 0xADB0, 0x964E, 0xD0C7, 0x964F, 0xD0C3, 0x9650, 0xADAD, 0x9651, 0xD0C4, 0x9653, 0xD0C5, 0x9654, 0xD0C2, 0x9658, 0xB0A4, 0x965B, 0xB0A1, 0x965C, 0xD445, 0x965D, 0xB0A2, 0x965E, 0xB0A5, 0x965F, 0xD446, 0x9661, 0xB07E, 0x9662, 0xB07C, 0x9663, 0xB07D, 0x9664, 0xB0A3, 0x966A, 0xB3AD, 0x966B, 0xD849, 0x966C, 0xB3B5, 0x966D, 0xD848, 0x966F, 0xD84B, 0x9670, 0xB3B1, 0x9671, 0xD84A, 0x9672, 0xB6AB, 0x9673, 0xB3AF, 0x9674, 0xB3B2, 0x9675, 0xB3AE, 0x9676, 0xB3B3, 0x9677, 0xB3B4, 0x9678, 0xB3B0, 0x967C, 0xD847, 0x967D, 0xB6A7, 0x967E, 0xDC7D, 0x9680, 0xDCA3, 0x9683, 0xDCA2, 0x9684, 0xB6AC, 0x9685, 0xB6A8, 0x9686, 0xB6A9, 0x9687, 0xDC7C, 0x9688, 0xDC7E, 0x9689, 0xDCA1, 0x968A, 0xB6A4, 0x968B, 0xB6A6, 0x968D, 0xB6AA, 0x968E, 0xB6A5, 0x9691, 0xE0D3, 0x9692, 0xE0D1, 0x9693, 0xE0D2, 0x9694, 0xB96A, 0x9695, 0xB96B, 0x9697, 0xE0D4, 0x9698, 0xB969, 0x9699, 0xBBD8, 0x969B, 0xBBDA, 0x969C, 0xBBD9, 0x969E, 0xE4BB, 0x96A1, 0xE4BC, 0x96A2, 0xE8AB, 0x96A4, 0xE8AA, 0x96A7, 0xC047, 0x96A8, 0xC048, 0x96A9, 0xEC4F, 0x96AA, 0xC049, 0x96AC, 0xEEF6, 0x96AE, 0xEEF4, 0x96B0, 0xEEF5, 0x96B1, 0xC1F4, 0x96B3, 0xF16F, 0x96B4, 0xC3F7, 0x96B8, 0xC1F5, 0x96B9, 0xAB41, 0x96BB, 0xB0A6, 0x96BC, 0xD447, 0x96BF, 0xD84C, 0x96C0, 0xB3B6, 0x96C1, 0xB6AD, 0x96C2, 0xDCA4, 0x96C3, 0xDCA6, 0x96C4, 0xB6AF, 0x96C5, 0xB6AE, 0x96C6, 0xB6B0, 0x96C7, 0xB6B1, 0x96C8, 0xDCA5, 0x96C9, 0xB96E, 0x96CA, 0xB96F, 0x96CB, 0xB96D, 0x96CC, 0xBBDB, 0x96CD, 0xB96C, 0x96CE, 0xE0D5, 0x96D2, 0xBBDC, 0x96D3, 0xE8AC, 0x96D4, 0xEC50, 0x96D5, 0xC04A, 0x96D6, 0xC1F6, 0x96D7, 0xF170, 0x96D8, 0xF174, 0x96D9, 0xC2F9, 0x96DA, 0xF171, 0x96DB, 0xC2FA, 0x96DC, 0xC2F8, 0x96DD, 0xF175, 0x96DE, 0xC2FB, 0x96DF, 0xF173, 0x96E1, 0xF379, 0x96E2, 0xC2F7, 0x96E3, 0xC3F8, 0x96E5, 0xF8CD, 0x96E8, 0xAB42, 0x96E9, 0xB3B8, 0x96EA, 0xB3B7, 0x96EF, 0xB6B2, 0x96F0, 0xDCA8, 0x96F1, 0xDCA7, 0x96F2, 0xB6B3, 0x96F5, 0xE0D9, 0x96F6, 0xB973, 0x96F7, 0xB970, 0x96F8, 0xE0D8, 0x96F9, 0xB972, 0x96FA, 0xE0D6, 0x96FB, 0xB971, 0x96FD, 0xE0D7, 0x96FF, 0xE4BD, 0x9700, 0xBBDD, 0x9702, 0xE8AF, 0x9704, 0xBE5D, 0x9705, 0xE8AD, 0x9706, 0xBE5E, 0x9707, 0xBE5F, 0x9708, 0xE8AE, 0x9709, 0xBE60, 0x970B, 0xEC51, 0x970D, 0xC04E, 0x970E, 0xC04B, 0x970F, 0xC050, 0x9710, 0xEC53, 0x9711, 0xC04C, 0x9712, 0xEC52, 0x9713, 0xC04F, 0x9716, 0xC04D, 0x9718, 0xEEF9, 0x9719, 0xEEFB, 0x971C, 0xC1F7, 0x971D, 0xEEFA, 0x971E, 0xC1F8, 0x971F, 0xEEF8, 0x9720, 0xEEF7, 0x9722, 0xF177, 0x9723, 0xF176, 0x9724, 0xC2FC, 0x9725, 0xF178, 0x9726, 0xF37E, 0x9727, 0xC3FA, 0x9728, 0xF37D, 0x9729, 0xF37A, 0x972A, 0xC3F9, 0x972B, 0xF37B, 0x972C, 0xF37C, 0x972E, 0xF548, 0x972F, 0xF549, 0x9730, 0xC4C5, 0x9732, 0xC553, 0x9735, 0xF66E, 0x9738, 0xC551, 0x9739, 0xC552, 0x973A, 0xF66F, 0x973D, 0xC5B4, 0x973E, 0xC5B5, 0x973F, 0xF771, 0x9742, 0xC645, 0x9743, 0xF8CF, 0x9744, 0xC647, 0x9746, 0xF8CE, 0x9747, 0xF8D0, 0x9748, 0xC646, 0x9749, 0xF957, 0x974B, 0xF9AD, 0x9752, 0xAB43, 0x9756, 0xB974, 0x9758, 0xE4BE, 0x975A, 0xE8B0, 0x975B, 0xC051, 0x975C, 0xC052, 0x975E, 0xAB44, 0x9760, 0xBE61, 0x9761, 0xC3FB, 0x9762, 0xADB1, 0x9766, 0xC053, 0x9768, 0xC5E2, 0x9769, 0xADB2, 0x976A, 0xD84D, 0x976C, 0xDCA9, 0x976E, 0xDCAB, 0x9770, 0xDCAA, 0x9772, 0xE0DD, 0x9773, 0xE0DA, 0x9774, 0xB975, 0x9776, 0xB976, 0x9777, 0xE0DB, 0x9778, 0xE0DC, 0x977A, 0xE4C0, 0x977B, 0xE4C5, 0x977C, 0xBBDE, 0x977D, 0xE4BF, 0x977E, 0xE4C1, 0x977F, 0xE4C8, 0x9780, 0xE4C3, 0x9781, 0xE4C7, 0x9782, 0xE4C4, 0x9783, 0xE4C2, 0x9784, 0xE4C6, 0x9785, 0xBBDF, 0x9788, 0xE8B3, 0x978A, 0xE8B1, 0x978B, 0xBE63, 0x978D, 0xBE62, 0x978E, 0xE8B2, 0x978F, 0xBE64, 0x9794, 0xEC56, 0x9797, 0xEC55, 0x9798, 0xC054, 0x9799, 0xEC54, 0x979A, 0xEEFC, 0x979C, 0xEEFE, 0x979D, 0xEF41, 0x979E, 0xEF40, 0x97A0, 0xC1F9, 0x97A1, 0xEEFD, 0x97A2, 0xF1A1, 0x97A3, 0xC2FD, 0x97A4, 0xF17D, 0x97A5, 0xF1A2, 0x97A6, 0xC2FE, 0x97A8, 0xF17B, 0x97AA, 0xF17E, 0x97AB, 0xF17C, 0x97AC, 0xF179, 0x97AD, 0xC340, 0x97AE, 0xF17A, 0x97B3, 0xF3A1, 0x97B6, 0xF3A3, 0x97B7, 0xF3A2, 0x97B9, 0xF54A, 0x97BB, 0xF54B, 0x97BF, 0xF670, 0x97C1, 0xC5B7, 0x97C3, 0xC5B6, 0x97C4, 0xF84F, 0x97C5, 0xF850, 0x97C6, 0xC648, 0x97C7, 0xF8D1, 0x97C9, 0xC669, 0x97CB, 0xADB3, 0x97CC, 0xB6B4, 0x97CD, 0xE4CA, 0x97CE, 0xE4C9, 0x97CF, 0xE8B5, 0x97D0, 0xE8B4, 0x97D3, 0xC1FA, 0x97D4, 0xEF43, 0x97D5, 0xEF42, 0x97D6, 0xF1A5, 0x97D7, 0xF1A3, 0x97D8, 0xF1A6, 0x97D9, 0xF1A4, 0x97DC, 0xC3FC, 0x97DD, 0xF3A4, 0x97DE, 0xF3A5, 0x97DF, 0xF3A6, 0x97E1, 0xF671, 0x97E3, 0xF772, 0x97E5, 0xF8D2, 0x97ED, 0xADB4, 0x97F0, 0xEC57, 0x97F1, 0xEF44, 0x97F3, 0xADB5, 0x97F6, 0xBBE0, 0x97F8, 0xEC58, 0x97F9, 0xC341, 0x97FA, 0xF1A7, 0x97FB, 0xC3FD, 0x97FD, 0xF54C, 0x97FE, 0xF54D, 0x97FF, 0xC554, 0x9800, 0xF851, 0x9801, 0xADB6, 0x9802, 0xB3BB, 0x9803, 0xB3BC, 0x9804, 0xD84E, 0x9805, 0xB6B5, 0x9806, 0xB6B6, 0x9807, 0xDCAC, 0x9808, 0xB6B7, 0x980A, 0xB97A, 0x980C, 0xB97C, 0x980D, 0xE0DF, 0x980E, 0xE0E0, 0x980F, 0xE0DE, 0x9810, 0xB977, 0x9811, 0xB978, 0x9812, 0xB97B, 0x9813, 0xB979, 0x9816, 0xE4CB, 0x9817, 0xBBE1, 0x9818, 0xBBE2, 0x981B, 0xE8BC, 0x981C, 0xBE67, 0x981D, 0xE8B7, 0x981E, 0xE8B6, 0x9820, 0xE8BB, 0x9821, 0xBE65, 0x9824, 0xC05B, 0x9826, 0xE8B8, 0x9827, 0xE8BD, 0x9828, 0xE8BA, 0x9829, 0xE8B9, 0x982B, 0xBE66, 0x982D, 0xC059, 0x982F, 0xEC5A, 0x9830, 0xC055, 0x9832, 0xEC5B, 0x9835, 0xEC59, 0x9837, 0xC058, 0x9838, 0xC056, 0x9839, 0xC05A, 0x983B, 0xC057, 0x9841, 0xEF45, 0x9843, 0xEF4A, 0x9844, 0xEF46, 0x9845, 0xEF49, 0x9846, 0xC1FB, 0x9848, 0xEDD4, 0x9849, 0xEF48, 0x984A, 0xEF47, 0x984C, 0xC344, 0x984D, 0xC342, 0x984E, 0xC345, 0x984F, 0xC343, 0x9850, 0xF1A8, 0x9851, 0xF1A9, 0x9852, 0xF1AA, 0x9853, 0xC346, 0x9857, 0xF3AA, 0x9858, 0xC440, 0x9859, 0xF3A8, 0x985B, 0xC441, 0x985C, 0xF3A7, 0x985D, 0xF3A9, 0x985E, 0xC3FE, 0x985F, 0xF551, 0x9860, 0xF54E, 0x9862, 0xF54F, 0x9863, 0xF550, 0x9864, 0xF672, 0x9865, 0xC556, 0x9867, 0xC555, 0x9869, 0xF774, 0x986A, 0xF773, 0x986B, 0xC5B8, 0x986F, 0xC5E3, 0x9870, 0xC649, 0x9871, 0xC660, 0x9872, 0xF958, 0x9873, 0xF9AE, 0x9874, 0xF9AF, 0x98A8, 0xADB7, 0x98A9, 0xDCAD, 0x98AC, 0xE0E1, 0x98AD, 0xE4CC, 0x98AE, 0xE4CD, 0x98AF, 0xBBE3, 0x98B1, 0xBBE4, 0x98B2, 0xE8BE, 0x98B3, 0xBE68, 0x98B6, 0xC1FC, 0x98B8, 0xF1AB, 0x98BA, 0xC347, 0x98BB, 0xF3AD, 0x98BC, 0xC442, 0x98BD, 0xF3AC, 0x98BE, 0xF3AE, 0x98BF, 0xF3AB, 0x98C0, 0xF675, 0x98C1, 0xF552, 0x98C2, 0xF553, 0x98C4, 0xC4C6, 0x98C6, 0xF674, 0x98C9, 0xF673, 0x98CB, 0xF775, 0x98CC, 0xF9B0, 0x98DB, 0xADB8, 0x98DF, 0xADB9, 0x98E2, 0xB0A7, 0x98E3, 0xD448, 0x98E5, 0xD84F, 0x98E7, 0xB6B8, 0x98E9, 0xB6BB, 0x98EA, 0xB6B9, 0x98EB, 0xDCAE, 0x98ED, 0xB6BD, 0x98EF, 0xB6BA, 0x98F2, 0xB6BC, 0x98F4, 0xB97E, 0x98F6, 0xE0E2, 0x98F9, 0xE0E3, 0x98FA, 0xE8C0, 0x98FC, 0xB97D, 0x98FD, 0xB9A1, 0x98FE, 0xB9A2, 0x9900, 0xE4CF, 0x9902, 0xE4CE, 0x9903, 0xBBE5, 0x9905, 0xBBE6, 0x9907, 0xE4D0, 0x9908, 0xE8BF, 0x9909, 0xBBE8, 0x990A, 0xBE69, 0x990C, 0xBBE7, 0x9910, 0xC05C, 0x9911, 0xE8C1, 0x9912, 0xBE6B, 0x9913, 0xBE6A, 0x9914, 0xE8C2, 0x9915, 0xE8C5, 0x9916, 0xE8C3, 0x9917, 0xE8C4, 0x9918, 0xBE6C, 0x991A, 0xC061, 0x991B, 0xC05F, 0x991E, 0xC05E, 0x991F, 0xEC5D, 0x9921, 0xC060, 0x9924, 0xEC5C, 0x9925, 0xEF4B, 0x9927, 0xEC5E, 0x9928, 0xC05D, 0x9929, 0xEC5F, 0x992A, 0xEF4E, 0x992B, 0xEF4C, 0x992C, 0xEF4D, 0x992D, 0xEF52, 0x992E, 0xC34B, 0x992F, 0xEF51, 0x9930, 0xEF54, 0x9931, 0xEF53, 0x9932, 0xEF50, 0x9933, 0xEF4F, 0x9935, 0xC1FD, 0x993A, 0xF1AE, 0x993C, 0xF1AD, 0x993D, 0xC34A, 0x993E, 0xC348, 0x993F, 0xC349, 0x9941, 0xF1AC, 0x9943, 0xF3B1, 0x9945, 0xC443, 0x9947, 0xF3B0, 0x9948, 0xF3AF, 0x9949, 0xC444, 0x994B, 0xF558, 0x994C, 0xF557, 0x994E, 0xF555, 0x9950, 0xF554, 0x9951, 0xC4C8, 0x9952, 0xC4C7, 0x9953, 0xF559, 0x9954, 0xF776, 0x9955, 0xC5B9, 0x9956, 0xF677, 0x9957, 0xC557, 0x9958, 0xF676, 0x9959, 0xF556, 0x995B, 0xF777, 0x995C, 0xC5E4, 0x995E, 0xC661, 0x995F, 0xF959, 0x9961, 0xF9B1, 0x9996, 0xADBA, 0x9997, 0xD850, 0x9998, 0xEF55, 0x9999, 0xADBB, 0x999C, 0xE4D2, 0x999D, 0xE4D1, 0x999E, 0xEC60, 0x99A1, 0xEF57, 0x99A3, 0xEF56, 0x99A5, 0xC34C, 0x99A6, 0xF3B2, 0x99A7, 0xF3B3, 0x99A8, 0xC4C9, 0x99AB, 0xF9B2, 0x99AC, 0xB0A8, 0x99AD, 0xB6BF, 0x99AE, 0xB6BE, 0x99AF, 0xE0E4, 0x99B0, 0xE0E6, 0x99B1, 0xB9A4, 0x99B2, 0xE0E5, 0x99B3, 0xB9A3, 0x99B4, 0xB9A5, 0x99B5, 0xE0E7, 0x99B9, 0xE4D4, 0x99BA, 0xE4D6, 0x99BB, 0xE4D5, 0x99BD, 0xE4D8, 0x99C1, 0xBBE9, 0x99C2, 0xE4D7, 0x99C3, 0xE4D3, 0x99C7, 0xE4D9, 0x99C9, 0xE8CC, 0x99CB, 0xE8CF, 0x99CC, 0xE8D1, 0x99CD, 0xE8C7, 0x99CE, 0xE8CB, 0x99CF, 0xE8C8, 0x99D0, 0xBE6E, 0x99D1, 0xBE71, 0x99D2, 0xBE73, 0x99D3, 0xE8C9, 0x99D4, 0xE8CA, 0x99D5, 0xBE72, 0x99D6, 0xE8CD, 0x99D7, 0xE8D0, 0x99D8, 0xE8CE, 0x99D9, 0xBE74, 0x99DB, 0xBE70, 0x99DC, 0xE8C6, 0x99DD, 0xBE6D, 0x99DF, 0xBE6F, 0x99E2, 0xC063, 0x99E3, 0xEC66, 0x99E4, 0xEC64, 0x99E5, 0xEC63, 0x99E7, 0xEC69, 0x99E9, 0xEC68, 0x99EA, 0xEC67, 0x99EC, 0xEC62, 0x99ED, 0xC062, 0x99EE, 0xEC61, 0x99F0, 0xEC65, 0x99F1, 0xC064, 0x99F4, 0xEF5A, 0x99F6, 0xEF5E, 0x99F7, 0xEF5B, 0x99F8, 0xEF5D, 0x99F9, 0xEF5C, 0x99FA, 0xEF59, 0x99FB, 0xEF5F, 0x99FC, 0xEF62, 0x99FD, 0xEF60, 0x99FE, 0xEF61, 0x99FF, 0xC240, 0x9A01, 0xC1FE, 0x9A02, 0xEF58, 0x9A03, 0xEF63, 0x9A04, 0xF1B3, 0x9A05, 0xF1B6, 0x9A06, 0xF1B8, 0x9A07, 0xF1B7, 0x9A09, 0xF1B1, 0x9A0A, 0xF1B5, 0x9A0B, 0xF1B0, 0x9A0D, 0xF1B2, 0x9A0E, 0xC34D, 0x9A0F, 0xF1AF, 0x9A11, 0xF1B4, 0x9A14, 0xF3C0, 0x9A15, 0xF3B5, 0x9A16, 0xC445, 0x9A19, 0xC446, 0x9A1A, 0xF3B4, 0x9A1B, 0xF3B9, 0x9A1C, 0xF3BF, 0x9A1D, 0xF3B7, 0x9A1E, 0xF3BE, 0x9A20, 0xF3BB, 0x9A22, 0xF3BA, 0x9A23, 0xF3BD, 0x9A24, 0xF3B8, 0x9A25, 0xF3B6, 0x9A27, 0xF3BC, 0x9A29, 0xF560, 0x9A2A, 0xF55E, 0x9A2B, 0xC4CA, 0x9A2C, 0xF55D, 0x9A2D, 0xF563, 0x9A2E, 0xF561, 0x9A30, 0xC4CB, 0x9A31, 0xF55C, 0x9A32, 0xF55A, 0x9A34, 0xF55B, 0x9A35, 0xC4CD, 0x9A36, 0xF55F, 0x9A37, 0xC4CC, 0x9A38, 0xF562, 0x9A39, 0xF678, 0x9A3A, 0xF67E, 0x9A3D, 0xF679, 0x9A3E, 0xC55B, 0x9A3F, 0xF6A1, 0x9A40, 0xC55A, 0x9A41, 0xF67D, 0x9A42, 0xF67C, 0x9A43, 0xC559, 0x9A44, 0xF67B, 0x9A45, 0xC558, 0x9A46, 0xF67A, 0x9A48, 0xF77D, 0x9A49, 0xF7A1, 0x9A4A, 0xF77E, 0x9A4C, 0xF77B, 0x9A4D, 0xC5BB, 0x9A4E, 0xF778, 0x9A4F, 0xF77C, 0x9A50, 0xF7A3, 0x9A52, 0xF7A2, 0x9A53, 0xF779, 0x9A54, 0xF77A, 0x9A55, 0xC5BA, 0x9A56, 0xF852, 0x9A57, 0xC5E7, 0x9A59, 0xF853, 0x9A5A, 0xC5E5, 0x9A5B, 0xC5E6, 0x9A5E, 0xF8D3, 0x9A5F, 0xC64A, 0x9A60, 0xF976, 0x9A62, 0xC66A, 0x9A64, 0xF9B3, 0x9A65, 0xC66B, 0x9A66, 0xF9B4, 0x9A67, 0xF9B5, 0x9A68, 0xF9C3, 0x9A69, 0xF9C2, 0x9A6A, 0xC67A, 0x9A6B, 0xF9CD, 0x9AA8, 0xB0A9, 0x9AAB, 0xE0E9, 0x9AAD, 0xE0E8, 0x9AAF, 0xBBEA, 0x9AB0, 0xBBEB, 0x9AB1, 0xE4DA, 0x9AB3, 0xE8D2, 0x9AB4, 0xEC6C, 0x9AB7, 0xBE75, 0x9AB8, 0xC065, 0x9AB9, 0xEC6A, 0x9ABB, 0xEC6D, 0x9ABC, 0xC066, 0x9ABE, 0xEF64, 0x9ABF, 0xEC6B, 0x9AC0, 0xF1B9, 0x9AC1, 0xC34E, 0x9AC2, 0xF3C1, 0x9AC6, 0xF566, 0x9AC7, 0xF564, 0x9ACA, 0xF565, 0x9ACD, 0xF6A2, 0x9ACF, 0xC55C, 0x9AD0, 0xF7A4, 0x9AD1, 0xC5EA, 0x9AD2, 0xC5BC, 0x9AD3, 0xC5E8, 0x9AD4, 0xC5E9, 0x9AD5, 0xF8D4, 0x9AD6, 0xC662, 0x9AD8, 0xB0AA, 0x9ADC, 0xF1BA, 0x9ADF, 0xD449, 0x9AE1, 0xB9A6, 0x9AE3, 0xE4DB, 0x9AE6, 0xBBEC, 0x9AE7, 0xE4DC, 0x9AEB, 0xE8D4, 0x9AEC, 0xE8D3, 0x9AED, 0xC068, 0x9AEE, 0xBE76, 0x9AEF, 0xBE77, 0x9AF1, 0xE8D7, 0x9AF2, 0xE8D6, 0x9AF3, 0xE8D5, 0x9AF6, 0xEC6E, 0x9AF7, 0xEC71, 0x9AF9, 0xEC70, 0x9AFA, 0xEC6F, 0x9AFB, 0xC067, 0x9AFC, 0xEF68, 0x9AFD, 0xEF66, 0x9AFE, 0xEF65, 0x9B01, 0xEF67, 0x9B03, 0xC34F, 0x9B04, 0xF1BC, 0x9B05, 0xF1BD, 0x9B06, 0xC350, 0x9B08, 0xF1BB, 0x9B0A, 0xF3C3, 0x9B0B, 0xF3C2, 0x9B0C, 0xF3C5, 0x9B0D, 0xC447, 0x9B0E, 0xF3C4, 0x9B10, 0xF567, 0x9B11, 0xF569, 0x9B12, 0xF568, 0x9B15, 0xF6A3, 0x9B16, 0xF6A6, 0x9B17, 0xF6A4, 0x9B18, 0xF6A5, 0x9B19, 0xF7A5, 0x9B1A, 0xC5BD, 0x9B1E, 0xF854, 0x9B1F, 0xF855, 0x9B20, 0xF856, 0x9B22, 0xC64B, 0x9B23, 0xC663, 0x9B24, 0xF9B6, 0x9B25, 0xB0AB, 0x9B27, 0xBE78, 0x9B28, 0xC069, 0x9B29, 0xF1BE, 0x9B2B, 0xF7A6, 0x9B2E, 0xF9C4, 0x9B2F, 0xD44A, 0x9B31, 0xC67B, 0x9B32, 0xB0AC, 0x9B33, 0xEC72, 0x9B35, 0xF1BF, 0x9B37, 0xF3C6, 0x9B3A, 0xF6A7, 0x9B3B, 0xF7A7, 0x9B3C, 0xB0AD, 0x9B3E, 0xE4DD, 0x9B3F, 0xE4DE, 0x9B41, 0xBBED, 0x9B42, 0xBBEE, 0x9B43, 0xE8D9, 0x9B44, 0xBE7A, 0x9B45, 0xBE79, 0x9B46, 0xE8D8, 0x9B48, 0xEF69, 0x9B4A, 0xF1C0, 0x9B4B, 0xF1C2, 0x9B4C, 0xF1C1, 0x9B4D, 0xC353, 0x9B4E, 0xC352, 0x9B4F, 0xC351, 0x9B51, 0xC55E, 0x9B52, 0xF6A8, 0x9B54, 0xC55D, 0x9B55, 0xF7A9, 0x9B56, 0xF7A8, 0x9B58, 0xC64C, 0x9B59, 0xF8D5, 0x9B5A, 0xB3BD, 0x9B5B, 0xE0EA, 0x9B5F, 0xE4E1, 0x9B60, 0xE4DF, 0x9B61, 0xE4E0, 0x9B64, 0xE8E2, 0x9B66, 0xE8DD, 0x9B67, 0xE8DA, 0x9B68, 0xE8E1, 0x9B6C, 0xE8E3, 0x9B6F, 0xBE7C, 0x9B70, 0xE8E0, 0x9B71, 0xE8DC, 0x9B74, 0xE8DB, 0x9B75, 0xE8DF, 0x9B76, 0xE8DE, 0x9B77, 0xBE7B, 0x9B7A, 0xEC7D, 0x9B7B, 0xEC78, 0x9B7C, 0xEC76, 0x9B7D, 0xECA1, 0x9B7E, 0xEC77, 0x9B80, 0xEC73, 0x9B82, 0xEC79, 0x9B85, 0xEC74, 0x9B86, 0xEF72, 0x9B87, 0xEC75, 0x9B88, 0xECA2, 0x9B90, 0xEC7C, 0x9B91, 0xC06A, 0x9B92, 0xEC7B, 0x9B93, 0xEC7A, 0x9B95, 0xEC7E, 0x9B9A, 0xEF6A, 0x9B9B, 0xEF6D, 0x9B9E, 0xEF6C, 0x9BA0, 0xEF74, 0x9BA1, 0xEF6F, 0x9BA2, 0xEF73, 0x9BA4, 0xEF71, 0x9BA5, 0xEF70, 0x9BA6, 0xEF6E, 0x9BA8, 0xEF6B, 0x9BAA, 0xC243, 0x9BAB, 0xC242, 0x9BAD, 0xC244, 0x9BAE, 0xC241, 0x9BAF, 0xEF75, 0x9BB5, 0xF1C8, 0x9BB6, 0xF1CB, 0x9BB8, 0xF1C9, 0x9BB9, 0xF1CD, 0x9BBD, 0xF1CE, 0x9BBF, 0xF1C6, 0x9BC0, 0xC358, 0x9BC1, 0xF1C7, 0x9BC3, 0xF1C5, 0x9BC4, 0xF1CC, 0x9BC6, 0xF1C4, 0x9BC7, 0xF1C3, 0x9BC8, 0xC357, 0x9BC9, 0xC355, 0x9BCA, 0xC354, 0x9BD3, 0xF1CA, 0x9BD4, 0xF3CF, 0x9BD5, 0xF3D5, 0x9BD6, 0xC44A, 0x9BD7, 0xF3D0, 0x9BD9, 0xF3D3, 0x9BDA, 0xF3D7, 0x9BDB, 0xC44B, 0x9BDC, 0xF3D2, 0x9BDE, 0xF3CA, 0x9BE0, 0xF3C9, 0x9BE1, 0xF3D6, 0x9BE2, 0xF3CD, 0x9BE4, 0xF3CB, 0x9BE5, 0xF3D4, 0x9BE6, 0xF3CC, 0x9BE7, 0xC449, 0x9BE8, 0xC448, 0x9BEA, 0xF3C7, 0x9BEB, 0xF3C8, 0x9BEC, 0xF3D1, 0x9BF0, 0xF3CE, 0x9BF7, 0xF56C, 0x9BF8, 0xF56F, 0x9BFD, 0xC356, 0x9C05, 0xF56D, 0x9C06, 0xF573, 0x9C07, 0xF571, 0x9C08, 0xF56B, 0x9C09, 0xF576, 0x9C0B, 0xF56A, 0x9C0D, 0xC4CF, 0x9C0E, 0xF572, 0x9C12, 0xF56E, 0x9C13, 0xC4CE, 0x9C14, 0xF575, 0x9C17, 0xF574, 0x9C1C, 0xF6AB, 0x9C1D, 0xF6AA, 0x9C21, 0xF6B1, 0x9C23, 0xF6AD, 0x9C24, 0xF6B0, 0x9C25, 0xC560, 0x9C28, 0xF6AE, 0x9C29, 0xF6AF, 0x9C2B, 0xF6A9, 0x9C2C, 0xF6AC, 0x9C2D, 0xC55F, 0x9C31, 0xC5BF, 0x9C32, 0xF7B4, 0x9C33, 0xF7AF, 0x9C34, 0xF7B3, 0x9C36, 0xF7B6, 0x9C37, 0xF7B2, 0x9C39, 0xF7AE, 0x9C3B, 0xC5C1, 0x9C3C, 0xF7B1, 0x9C3D, 0xF7B5, 0x9C3E, 0xC5C0, 0x9C3F, 0xF7AC, 0x9C40, 0xF570, 0x9C41, 0xF7B0, 0x9C44, 0xF7AD, 0x9C46, 0xF7AA, 0x9C48, 0xF7AB, 0x9C49, 0xC5BE, 0x9C4A, 0xF85A, 0x9C4B, 0xF85C, 0x9C4C, 0xF85F, 0x9C4D, 0xF85B, 0x9C4E, 0xF860, 0x9C50, 0xF859, 0x9C52, 0xF857, 0x9C54, 0xC5EB, 0x9C55, 0xF85D, 0x9C56, 0xC5ED, 0x9C57, 0xC5EC, 0x9C58, 0xF858, 0x9C59, 0xF85E, 0x9C5E, 0xF8DA, 0x9C5F, 0xC64D, 0x9C60, 0xF8DB, 0x9C62, 0xF8D9, 0x9C63, 0xF8D6, 0x9C66, 0xF8D8, 0x9C67, 0xF8D7, 0x9C68, 0xF95A, 0x9C6D, 0xF95C, 0x9C6E, 0xF95B, 0x9C71, 0xF979, 0x9C73, 0xF978, 0x9C74, 0xF977, 0x9C75, 0xF97A, 0x9C77, 0xC673, 0x9C78, 0xC674, 0x9C79, 0xF9CA, 0x9C7A, 0xF9CE, 0x9CE5, 0xB3BE, 0x9CE6, 0xDCAF, 0x9CE7, 0xE0ED, 0x9CE9, 0xB9A7, 0x9CEA, 0xE0EB, 0x9CED, 0xE0EC, 0x9CF1, 0xE4E2, 0x9CF2, 0xE4E3, 0x9CF3, 0xBBF1, 0x9CF4, 0xBBEF, 0x9CF5, 0xE4E4, 0x9CF6, 0xBBF0, 0x9CF7, 0xE8E8, 0x9CF9, 0xE8EB, 0x9CFA, 0xE8E5, 0x9CFB, 0xE8EC, 0x9CFC, 0xE8E4, 0x9CFD, 0xE8E6, 0x9CFF, 0xE8E7, 0x9D00, 0xE8EA, 0x9D03, 0xBEA1, 0x9D04, 0xE8EF, 0x9D05, 0xE8EE, 0x9D06, 0xBE7D, 0x9D07, 0xE8E9, 0x9D08, 0xE8ED, 0x9D09, 0xBE7E, 0x9D10, 0xECAC, 0x9D12, 0xC06F, 0x9D14, 0xECA7, 0x9D15, 0xC06B, 0x9D17, 0xECA4, 0x9D18, 0xECAA, 0x9D19, 0xECAD, 0x9D1B, 0xC070, 0x9D1D, 0xECA9, 0x9D1E, 0xECA6, 0x9D1F, 0xECAE, 0x9D20, 0xECA5, 0x9D22, 0xECAB, 0x9D23, 0xC06C, 0x9D25, 0xECA3, 0x9D26, 0xC06D, 0x9D28, 0xC06E, 0x9D29, 0xECA8, 0x9D2D, 0xEFA9, 0x9D2E, 0xEF7A, 0x9D2F, 0xEF7B, 0x9D30, 0xEF7E, 0x9D31, 0xEF7C, 0x9D33, 0xEF76, 0x9D36, 0xEF79, 0x9D37, 0xEFA5, 0x9D38, 0xEF7D, 0x9D3B, 0xC245, 0x9D3D, 0xEFA7, 0x9D3E, 0xEFA4, 0x9D3F, 0xC246, 0x9D40, 0xEFA6, 0x9D41, 0xEF77, 0x9D42, 0xEFA2, 0x9D43, 0xEFA3, 0x9D45, 0xEFA1, 0x9D4A, 0xF1D2, 0x9D4B, 0xF1D4, 0x9D4C, 0xF1D7, 0x9D4F, 0xF1D1, 0x9D51, 0xC359, 0x9D52, 0xF1D9, 0x9D53, 0xF1D0, 0x9D54, 0xF1DA, 0x9D56, 0xF1D6, 0x9D57, 0xF1D8, 0x9D58, 0xF1DC, 0x9D59, 0xF1D5, 0x9D5A, 0xF1DD, 0x9D5B, 0xF1D3, 0x9D5C, 0xF1CF, 0x9D5D, 0xC35A, 0x9D5F, 0xF1DB, 0x9D60, 0xC35B, 0x9D61, 0xC44D, 0x9D67, 0xEF78, 0x9D68, 0xF3F1, 0x9D69, 0xF3E8, 0x9D6A, 0xC44F, 0x9D6B, 0xF3E4, 0x9D6C, 0xC450, 0x9D6F, 0xF3ED, 0x9D70, 0xF3E7, 0x9D71, 0xF3DD, 0x9D72, 0xC44E, 0x9D73, 0xF3EA, 0x9D74, 0xF3E5, 0x9D75, 0xF3E6, 0x9D77, 0xF3D8, 0x9D78, 0xF3DF, 0x9D79, 0xF3EE, 0x9D7B, 0xF3EB, 0x9D7D, 0xF3E3, 0x9D7F, 0xF3EF, 0x9D80, 0xF3DE, 0x9D81, 0xF3D9, 0x9D82, 0xF3EC, 0x9D84, 0xF3DB, 0x9D85, 0xF3E9, 0x9D86, 0xF3E0, 0x9D87, 0xF3F0, 0x9D88, 0xF3DC, 0x9D89, 0xC44C, 0x9D8A, 0xF3DA, 0x9D8B, 0xF3E1, 0x9D8C, 0xF3E2, 0x9D90, 0xF57D, 0x9D92, 0xF57B, 0x9D94, 0xF5A2, 0x9D96, 0xF5AE, 0x9D97, 0xF5A5, 0x9D98, 0xF57C, 0x9D99, 0xF578, 0x9D9A, 0xF5A7, 0x9D9B, 0xF57E, 0x9D9C, 0xF5A3, 0x9D9D, 0xF57A, 0x9D9E, 0xF5AA, 0x9D9F, 0xF577, 0x9DA0, 0xF5A1, 0x9DA1, 0xF5A6, 0x9DA2, 0xF5A8, 0x9DA3, 0xF5AB, 0x9DA4, 0xF579, 0x9DA6, 0xF5AF, 0x9DA7, 0xF5B0, 0x9DA8, 0xF5A9, 0x9DA9, 0xF5AD, 0x9DAA, 0xF5A4, 0x9DAC, 0xF6C1, 0x9DAD, 0xF6C4, 0x9DAF, 0xC561, 0x9DB1, 0xF6C3, 0x9DB2, 0xF6C8, 0x9DB3, 0xF6C6, 0x9DB4, 0xC562, 0x9DB5, 0xF6BD, 0x9DB6, 0xF6B3, 0x9DB7, 0xF6B2, 0x9DB8, 0xC564, 0x9DB9, 0xF6BF, 0x9DBA, 0xF6C0, 0x9DBB, 0xF6BC, 0x9DBC, 0xF6B4, 0x9DBE, 0xF6B9, 0x9DBF, 0xF5AC, 0x9DC1, 0xF6B5, 0x9DC2, 0xC563, 0x9DC3, 0xF6BB, 0x9DC5, 0xF6BA, 0x9DC7, 0xF6B6, 0x9DC8, 0xF6C2, 0x9DCA, 0xF6B7, 0x9DCB, 0xF7BB, 0x9DCC, 0xF6C5, 0x9DCD, 0xF6C7, 0x9DCE, 0xF6BE, 0x9DCF, 0xF6B8, 0x9DD0, 0xF7BC, 0x9DD1, 0xF7BE, 0x9DD2, 0xF7B8, 0x9DD3, 0xC5C2, 0x9DD5, 0xF7C5, 0x9DD6, 0xF7C3, 0x9DD7, 0xC5C3, 0x9DD8, 0xF7C2, 0x9DD9, 0xF7C1, 0x9DDA, 0xF7BA, 0x9DDB, 0xF7B7, 0x9DDC, 0xF7BD, 0x9DDD, 0xF7C6, 0x9DDE, 0xF7B9, 0x9DDF, 0xF7BF, 0x9DE1, 0xF869, 0x9DE2, 0xF86E, 0x9DE3, 0xF864, 0x9DE4, 0xF867, 0x9DE5, 0xC5EE, 0x9DE6, 0xF86B, 0x9DE8, 0xF872, 0x9DE9, 0xF7C0, 0x9DEB, 0xF865, 0x9DEC, 0xF86F, 0x9DED, 0xF873, 0x9DEE, 0xF86A, 0x9DEF, 0xF863, 0x9DF0, 0xF86D, 0x9DF2, 0xF86C, 0x9DF3, 0xF871, 0x9DF4, 0xF870, 0x9DF5, 0xF7C4, 0x9DF6, 0xF868, 0x9DF7, 0xF862, 0x9DF8, 0xF866, 0x9DF9, 0xC64E, 0x9DFA, 0xC64F, 0x9DFB, 0xF861, 0x9DFD, 0xF8E6, 0x9DFE, 0xF8DD, 0x9DFF, 0xF8E5, 0x9E00, 0xF8E2, 0x9E01, 0xF8E3, 0x9E02, 0xF8DC, 0x9E03, 0xF8DF, 0x9E04, 0xF8E7, 0x9E05, 0xF8E1, 0x9E06, 0xF8E0, 0x9E07, 0xF8DE, 0x9E09, 0xF8E4, 0x9E0B, 0xF95D, 0x9E0D, 0xF95E, 0x9E0F, 0xF960, 0x9E10, 0xF95F, 0x9E11, 0xF962, 0x9E12, 0xF961, 0x9E13, 0xF97C, 0x9E14, 0xF97B, 0x9E15, 0xF9B7, 0x9E17, 0xF9B8, 0x9E19, 0xF9C5, 0x9E1A, 0xC678, 0x9E1B, 0xC67C, 0x9E1D, 0xF9CF, 0x9E1E, 0xC67D, 0x9E75, 0xB3BF, 0x9E79, 0xC4D0, 0x9E7A, 0xF6C9, 0x9E7C, 0xC650, 0x9E7D, 0xC651, 0x9E7F, 0xB3C0, 0x9E80, 0xE0EE, 0x9E82, 0xB9A8, 0x9E83, 0xE8F0, 0x9E86, 0xECB0, 0x9E87, 0xECB1, 0x9E88, 0xECAF, 0x9E89, 0xEFAB, 0x9E8A, 0xEFAA, 0x9E8B, 0xC247, 0x9E8C, 0xF1DF, 0x9E8D, 0xEFAC, 0x9E8E, 0xF1DE, 0x9E91, 0xF3F3, 0x9E92, 0xC451, 0x9E93, 0xC453, 0x9E94, 0xF3F2, 0x9E97, 0xC452, 0x9E99, 0xF5B1, 0x9E9A, 0xF5B3, 0x9E9B, 0xF5B2, 0x9E9C, 0xF6CA, 0x9E9D, 0xC565, 0x9E9F, 0xC5EF, 0x9EA0, 0xF8E8, 0x9EA1, 0xF963, 0x9EA4, 0xF9D2, 0x9EA5, 0xB3C1, 0x9EA7, 0xE4E5, 0x9EA9, 0xBEA2, 0x9EAD, 0xECB3, 0x9EAE, 0xECB2, 0x9EB0, 0xEFAD, 0x9EB4, 0xC454, 0x9EB5, 0xC4D1, 0x9EB6, 0xF7C7, 0x9EB7, 0xF9CB, 0x9EBB, 0xB3C2, 0x9EBC, 0xBBF2, 0x9EBE, 0xBEA3, 0x9EC0, 0xF3F4, 0x9EC2, 0xF874, 0x9EC3, 0xB6C0, 0x9EC8, 0xEFAE, 0x9ECC, 0xC664, 0x9ECD, 0xB6C1, 0x9ECE, 0xBEA4, 0x9ECF, 0xC248, 0x9ED0, 0xF875, 0x9ED1, 0xB6C2, 0x9ED3, 0xE8F1, 0x9ED4, 0xC072, 0x9ED5, 0xECB4, 0x9ED6, 0xECB5, 0x9ED8, 0xC071, 0x9EDA, 0xEFAF, 0x9EDB, 0xC24C, 0x9EDC, 0xC24A, 0x9EDD, 0xC24B, 0x9EDE, 0xC249, 0x9EDF, 0xF1E0, 0x9EE0, 0xC35C, 0x9EE4, 0xF5B5, 0x9EE5, 0xF5B4, 0x9EE6, 0xF5B7, 0x9EE7, 0xF5B6, 0x9EE8, 0xC4D2, 0x9EEB, 0xF6CB, 0x9EED, 0xF6CD, 0x9EEE, 0xF6CC, 0x9EEF, 0xC566, 0x9EF0, 0xF7C8, 0x9EF2, 0xF876, 0x9EF3, 0xF877, 0x9EF4, 0xC5F0, 0x9EF5, 0xF964, 0x9EF6, 0xF97D, 0x9EF7, 0xC675, 0x9EF9, 0xDCB0, 0x9EFA, 0xECB6, 0x9EFB, 0xEFB0, 0x9EFC, 0xF3F5, 0x9EFD, 0xE0EF, 0x9EFF, 0xEFB1, 0x9F00, 0xF1E2, 0x9F01, 0xF1E1, 0x9F06, 0xF878, 0x9F07, 0xC652, 0x9F09, 0xF965, 0x9F0A, 0xF97E, 0x9F0E, 0xB9A9, 0x9F0F, 0xE8F2, 0x9F10, 0xE8F3, 0x9F12, 0xECB7, 0x9F13, 0xB9AA, 0x9F15, 0xC35D, 0x9F16, 0xF1E3, 0x9F18, 0xF6CF, 0x9F19, 0xC567, 0x9F1A, 0xF6D0, 0x9F1B, 0xF6CE, 0x9F1C, 0xF879, 0x9F1E, 0xF8E9, 0x9F20, 0xB9AB, 0x9F22, 0xEFB4, 0x9F23, 0xEFB3, 0x9F24, 0xEFB2, 0x9F25, 0xF1E4, 0x9F28, 0xF1E8, 0x9F29, 0xF1E7, 0x9F2A, 0xF1E6, 0x9F2B, 0xF1E5, 0x9F2C, 0xC35E, 0x9F2D, 0xF3F6, 0x9F2E, 0xF5B9, 0x9F2F, 0xC4D3, 0x9F30, 0xF5B8, 0x9F31, 0xF6D1, 0x9F32, 0xF7CB, 0x9F33, 0xF7CA, 0x9F34, 0xC5C4, 0x9F35, 0xF7C9, 0x9F36, 0xF87C, 0x9F37, 0xF87B, 0x9F38, 0xF87A, 0x9F3B, 0xBBF3, 0x9F3D, 0xECB8, 0x9F3E, 0xC24D, 0x9F40, 0xF3F7, 0x9F41, 0xF3F8, 0x9F42, 0xF7CC, 0x9F43, 0xF87D, 0x9F46, 0xF8EA, 0x9F47, 0xF966, 0x9F48, 0xF9B9, 0x9F49, 0xF9D4, 0x9F4A, 0xBBF4, 0x9F4B, 0xC24E, 0x9F4C, 0xF1E9, 0x9F4D, 0xF3F9, 0x9F4E, 0xF6D2, 0x9F4F, 0xF87E, 0x9F52, 0xBEA6, 0x9F54, 0xEFB5, 0x9F55, 0xF1EA, 0x9F56, 0xF3FA, 0x9F57, 0xF3FB, 0x9F58, 0xF3FC, 0x9F59, 0xF5BE, 0x9F5B, 0xF5BA, 0x9F5C, 0xC568, 0x9F5D, 0xF5BD, 0x9F5E, 0xF5BC, 0x9F5F, 0xC4D4, 0x9F60, 0xF5BB, 0x9F61, 0xC4D6, 0x9F63, 0xC4D5, 0x9F64, 0xF6D4, 0x9F65, 0xF6D3, 0x9F66, 0xC569, 0x9F67, 0xC56A, 0x9F6A, 0xC5C6, 0x9F6B, 0xF7CD, 0x9F6C, 0xC5C5, 0x9F6E, 0xF8A3, 0x9F6F, 0xF8A4, 0x9F70, 0xF8A2, 0x9F71, 0xF8A1, 0x9F72, 0xC654, 0x9F74, 0xF8EB, 0x9F75, 0xF8EC, 0x9F76, 0xF8ED, 0x9F77, 0xC653, 0x9F78, 0xF967, 0x9F79, 0xF96A, 0x9F7A, 0xF969, 0x9F7B, 0xF968, 0x9F7E, 0xF9D3, 0x9F8D, 0xC073, 0x9F90, 0xC365, 0x9F91, 0xF5BF, 0x9F92, 0xF6D5, 0x9F94, 0xC5C7, 0x9F95, 0xF7CE, 0x9F98, 0xF9D5, 0x9F9C, 0xC074, 0x9FA0, 0xEFB6, 0x9FA2, 0xF7CF, 0x9FA4, 0xF9A1, 0xFA0C, 0xC94A, 0xFA0D, 0xDDFC, 0xFE30, 0xA14A, 0xFE31, 0xA157, 0xFE33, 0xA159, 0xFE34, 0xA15B, 0xFE35, 0xA15F, 0xFE36, 0xA160, 0xFE37, 0xA163, 0xFE38, 0xA164, 0xFE39, 0xA167, 0xFE3A, 0xA168, 0xFE3B, 0xA16B, 0xFE3C, 0xA16C, 0xFE3D, 0xA16F, 0xFE3E, 0xA170, 0xFE3F, 0xA173, 0xFE40, 0xA174, 0xFE41, 0xA177, 0xFE42, 0xA178, 0xFE43, 0xA17B, 0xFE44, 0xA17C, 0xFE49, 0xA1C6, 0xFE4A, 0xA1C7, 0xFE4B, 0xA1CA, 0xFE4C, 0xA1CB, 0xFE4D, 0xA1C8, 0xFE4E, 0xA1C9, 0xFE4F, 0xA15C, 0xFE50, 0xA14D, 0xFE51, 0xA14E, 0xFE52, 0xA14F, 0xFE54, 0xA151, 0xFE55, 0xA152, 0xFE56, 0xA153, 0xFE57, 0xA154, 0xFE59, 0xA17D, 0xFE5A, 0xA17E, 0xFE5B, 0xA1A1, 0xFE5C, 0xA1A2, 0xFE5D, 0xA1A3, 0xFE5E, 0xA1A4, 0xFE5F, 0xA1CC, 0xFE60, 0xA1CD, 0xFE61, 0xA1CE, 0xFE62, 0xA1DE, 0xFE63, 0xA1DF, 0xFE64, 0xA1E0, 0xFE65, 0xA1E1, 0xFE66, 0xA1E2, 0xFE68, 0xA242, 0xFE69, 0xA24C, 0xFE6A, 0xA24D, 0xFE6B, 0xA24E, 0xFF01, 0xA149, 0xFF03, 0xA1AD, 0xFF04, 0xA243, 0xFF05, 0xA248, 0xFF06, 0xA1AE, 0xFF08, 0xA15D, 0xFF09, 0xA15E, 0xFF0A, 0xA1AF, 0xFF0B, 0xA1CF, 0xFF0C, 0xA141, 0xFF0D, 0xA1D0, 0xFF0E, 0xA144, 0xFF0F, 0xA1FE, 0xFF10, 0xA2AF, 0xFF11, 0xA2B0, 0xFF12, 0xA2B1, 0xFF13, 0xA2B2, 0xFF14, 0xA2B3, 0xFF15, 0xA2B4, 0xFF16, 0xA2B5, 0xFF17, 0xA2B6, 0xFF18, 0xA2B7, 0xFF19, 0xA2B8, 0xFF1A, 0xA147, 0xFF1B, 0xA146, 0xFF1C, 0xA1D5, 0xFF1D, 0xA1D7, 0xFF1E, 0xA1D6, 0xFF1F, 0xA148, 0xFF20, 0xA249, 0xFF21, 0xA2CF, 0xFF22, 0xA2D0, 0xFF23, 0xA2D1, 0xFF24, 0xA2D2, 0xFF25, 0xA2D3, 0xFF26, 0xA2D4, 0xFF27, 0xA2D5, 0xFF28, 0xA2D6, 0xFF29, 0xA2D7, 0xFF2A, 0xA2D8, 0xFF2B, 0xA2D9, 0xFF2C, 0xA2DA, 0xFF2D, 0xA2DB, 0xFF2E, 0xA2DC, 0xFF2F, 0xA2DD, 0xFF30, 0xA2DE, 0xFF31, 0xA2DF, 0xFF32, 0xA2E0, 0xFF33, 0xA2E1, 0xFF34, 0xA2E2, 0xFF35, 0xA2E3, 0xFF36, 0xA2E4, 0xFF37, 0xA2E5, 0xFF38, 0xA2E6, 0xFF39, 0xA2E7, 0xFF3A, 0xA2E8, 0xFF3C, 0xA240, 0xFF3F, 0xA1C4, 0xFF41, 0xA2E9, 0xFF42, 0xA2EA, 0xFF43, 0xA2EB, 0xFF44, 0xA2EC, 0xFF45, 0xA2ED, 0xFF46, 0xA2EE, 0xFF47, 0xA2EF, 0xFF48, 0xA2F0, 0xFF49, 0xA2F1, 0xFF4A, 0xA2F2, 0xFF4B, 0xA2F3, 0xFF4C, 0xA2F4, 0xFF4D, 0xA2F5, 0xFF4E, 0xA2F6, 0xFF4F, 0xA2F7, 0xFF50, 0xA2F8, 0xFF51, 0xA2F9, 0xFF52, 0xA2FA, 0xFF53, 0xA2FB, 0xFF54, 0xA2FC, 0xFF55, 0xA2FD, 0xFF56, 0xA2FE, 0xFF57, 0xA340, 0xFF58, 0xA341, 0xFF59, 0xA342, 0xFF5A, 0xA343, 0xFF5B, 0xA161, 0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0 }; static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ 0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A, 0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52, 0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31, 0xA158, 0x2014, 0xA159, 0xFE33, 0xA15A, 0x2574, 0xA15B, 0xFE34, 0xA15C, 0xFE4F, 0xA15D, 0xFF08, 0xA15E, 0xFF09, 0xA15F, 0xFE35, 0xA160, 0xFE36, 0xA161, 0xFF5B, 0xA162, 0xFF5D, 0xA163, 0xFE37, 0xA164, 0xFE38, 0xA165, 0x3014, 0xA166, 0x3015, 0xA167, 0xFE39, 0xA168, 0xFE3A, 0xA169, 0x3010, 0xA16A, 0x3011, 0xA16B, 0xFE3B, 0xA16C, 0xFE3C, 0xA16D, 0x300A, 0xA16E, 0x300B, 0xA16F, 0xFE3D, 0xA170, 0xFE3E, 0xA171, 0x3008, 0xA172, 0x3009, 0xA173, 0xFE3F, 0xA174, 0xFE40, 0xA175, 0x300C, 0xA176, 0x300D, 0xA177, 0xFE41, 0xA178, 0xFE42, 0xA179, 0x300E, 0xA17A, 0x300F, 0xA17B, 0xFE43, 0xA17C, 0xFE44, 0xA17D, 0xFE59, 0xA17E, 0xFE5A, 0xA1A1, 0xFE5B, 0xA1A2, 0xFE5C, 0xA1A3, 0xFE5D, 0xA1A4, 0xFE5E, 0xA1A5, 0x2018, 0xA1A6, 0x2019, 0xA1A7, 0x201C, 0xA1A8, 0x201D, 0xA1A9, 0x301D, 0xA1AA, 0x301E, 0xA1AB, 0x2035, 0xA1AC, 0x2032, 0xA1AD, 0xFF03, 0xA1AE, 0xFF06, 0xA1AF, 0xFF0A, 0xA1B0, 0x203B, 0xA1B1, 0x00A7, 0xA1B2, 0x3003, 0xA1B3, 0x25CB, 0xA1B4, 0x25CF, 0xA1B5, 0x25B3, 0xA1B6, 0x25B2, 0xA1B7, 0x25CE, 0xA1B8, 0x2606, 0xA1B9, 0x2605, 0xA1BA, 0x25C7, 0xA1BB, 0x25C6, 0xA1BC, 0x25A1, 0xA1BD, 0x25A0, 0xA1BE, 0x25BD, 0xA1BF, 0x25BC, 0xA1C0, 0x32A3, 0xA1C1, 0x2105, 0xA1C2, 0x00AF, 0xA1C3, 0xFFE3, 0xA1C4, 0xFF3F, 0xA1C5, 0x02CD, 0xA1C6, 0xFE49, 0xA1C7, 0xFE4A, 0xA1C8, 0xFE4D, 0xA1C9, 0xFE4E, 0xA1CA, 0xFE4B, 0xA1CB, 0xFE4C, 0xA1CC, 0xFE5F, 0xA1CD, 0xFE60, 0xA1CE, 0xFE61, 0xA1CF, 0xFF0B, 0xA1D0, 0xFF0D, 0xA1D1, 0x00D7, 0xA1D2, 0x00F7, 0xA1D3, 0x00B1, 0xA1D4, 0x221A, 0xA1D5, 0xFF1C, 0xA1D6, 0xFF1E, 0xA1D7, 0xFF1D, 0xA1D8, 0x2266, 0xA1D9, 0x2267, 0xA1DA, 0x2260, 0xA1DB, 0x221E, 0xA1DC, 0x2252, 0xA1DD, 0x2261, 0xA1DE, 0xFE62, 0xA1DF, 0xFE63, 0xA1E0, 0xFE64, 0xA1E1, 0xFE65, 0xA1E2, 0xFE66, 0xA1E3, 0xFF5E, 0xA1E4, 0x2229, 0xA1E5, 0x222A, 0xA1E6, 0x22A5, 0xA1E7, 0x2220, 0xA1E8, 0x221F, 0xA1E9, 0x22BF, 0xA1EA, 0x33D2, 0xA1EB, 0x33D1, 0xA1EC, 0x222B, 0xA1ED, 0x222E, 0xA1EE, 0x2235, 0xA1EF, 0x2234, 0xA1F0, 0x2640, 0xA1F1, 0x2642, 0xA1F2, 0x2295, 0xA1F3, 0x2299, 0xA1F4, 0x2191, 0xA1F5, 0x2193, 0xA1F6, 0x2190, 0xA1F7, 0x2192, 0xA1F8, 0x2196, 0xA1F9, 0x2197, 0xA1FA, 0x2199, 0xA1FB, 0x2198, 0xA1FC, 0x2225, 0xA1FD, 0x2223, 0xA1FE, 0xFF0F, 0xA240, 0xFF3C, 0xA241, 0x2215, 0xA242, 0xFE68, 0xA243, 0xFF04, 0xA244, 0xFFE5, 0xA245, 0x3012, 0xA246, 0xFFE0, 0xA247, 0xFFE1, 0xA248, 0xFF05, 0xA249, 0xFF20, 0xA24A, 0x2103, 0xA24B, 0x2109, 0xA24C, 0xFE69, 0xA24D, 0xFE6A, 0xA24E, 0xFE6B, 0xA24F, 0x33D5, 0xA250, 0x339C, 0xA251, 0x339D, 0xA252, 0x339E, 0xA253, 0x33CE, 0xA254, 0x33A1, 0xA255, 0x338E, 0xA256, 0x338F, 0xA257, 0x33C4, 0xA258, 0x00B0, 0xA259, 0x5159, 0xA25A, 0x515B, 0xA25B, 0x515E, 0xA25C, 0x515D, 0xA25D, 0x5161, 0xA25E, 0x5163, 0xA25F, 0x55E7, 0xA260, 0x74E9, 0xA261, 0x7CCE, 0xA262, 0x2581, 0xA263, 0x2582, 0xA264, 0x2583, 0xA265, 0x2584, 0xA266, 0x2585, 0xA267, 0x2586, 0xA268, 0x2587, 0xA269, 0x2588, 0xA26A, 0x258F, 0xA26B, 0x258E, 0xA26C, 0x258D, 0xA26D, 0x258C, 0xA26E, 0x258B, 0xA26F, 0x258A, 0xA270, 0x2589, 0xA271, 0x253C, 0xA272, 0x2534, 0xA273, 0x252C, 0xA274, 0x2524, 0xA275, 0x251C, 0xA276, 0x2594, 0xA277, 0x2500, 0xA278, 0x2502, 0xA279, 0x2595, 0xA27A, 0x250C, 0xA27B, 0x2510, 0xA27C, 0x2514, 0xA27D, 0x2518, 0xA27E, 0x256D, 0xA2A1, 0x256E, 0xA2A2, 0x2570, 0xA2A3, 0x256F, 0xA2A4, 0x2550, 0xA2A5, 0x255E, 0xA2A6, 0x256A, 0xA2A7, 0x2561, 0xA2A8, 0x25E2, 0xA2A9, 0x25E3, 0xA2AA, 0x25E5, 0xA2AB, 0x25E4, 0xA2AC, 0x2571, 0xA2AD, 0x2572, 0xA2AE, 0x2573, 0xA2AF, 0xFF10, 0xA2B0, 0xFF11, 0xA2B1, 0xFF12, 0xA2B2, 0xFF13, 0xA2B3, 0xFF14, 0xA2B4, 0xFF15, 0xA2B5, 0xFF16, 0xA2B6, 0xFF17, 0xA2B7, 0xFF18, 0xA2B8, 0xFF19, 0xA2B9, 0x2160, 0xA2BA, 0x2161, 0xA2BB, 0x2162, 0xA2BC, 0x2163, 0xA2BD, 0x2164, 0xA2BE, 0x2165, 0xA2BF, 0x2166, 0xA2C0, 0x2167, 0xA2C1, 0x2168, 0xA2C2, 0x2169, 0xA2C3, 0x3021, 0xA2C4, 0x3022, 0xA2C5, 0x3023, 0xA2C6, 0x3024, 0xA2C7, 0x3025, 0xA2C8, 0x3026, 0xA2C9, 0x3027, 0xA2CA, 0x3028, 0xA2CB, 0x3029, 0xA2CC, 0x5341, 0xA2CD, 0x5344, 0xA2CE, 0x5345, 0xA2CF, 0xFF21, 0xA2D0, 0xFF22, 0xA2D1, 0xFF23, 0xA2D2, 0xFF24, 0xA2D3, 0xFF25, 0xA2D4, 0xFF26, 0xA2D5, 0xFF27, 0xA2D6, 0xFF28, 0xA2D7, 0xFF29, 0xA2D8, 0xFF2A, 0xA2D9, 0xFF2B, 0xA2DA, 0xFF2C, 0xA2DB, 0xFF2D, 0xA2DC, 0xFF2E, 0xA2DD, 0xFF2F, 0xA2DE, 0xFF30, 0xA2DF, 0xFF31, 0xA2E0, 0xFF32, 0xA2E1, 0xFF33, 0xA2E2, 0xFF34, 0xA2E3, 0xFF35, 0xA2E4, 0xFF36, 0xA2E5, 0xFF37, 0xA2E6, 0xFF38, 0xA2E7, 0xFF39, 0xA2E8, 0xFF3A, 0xA2E9, 0xFF41, 0xA2EA, 0xFF42, 0xA2EB, 0xFF43, 0xA2EC, 0xFF44, 0xA2ED, 0xFF45, 0xA2EE, 0xFF46, 0xA2EF, 0xFF47, 0xA2F0, 0xFF48, 0xA2F1, 0xFF49, 0xA2F2, 0xFF4A, 0xA2F3, 0xFF4B, 0xA2F4, 0xFF4C, 0xA2F5, 0xFF4D, 0xA2F6, 0xFF4E, 0xA2F7, 0xFF4F, 0xA2F8, 0xFF50, 0xA2F9, 0xFF51, 0xA2FA, 0xFF52, 0xA2FB, 0xFF53, 0xA2FC, 0xFF54, 0xA2FD, 0xFF55, 0xA2FE, 0xFF56, 0xA340, 0xFF57, 0xA341, 0xFF58, 0xA342, 0xFF59, 0xA343, 0xFF5A, 0xA344, 0x0391, 0xA345, 0x0392, 0xA346, 0x0393, 0xA347, 0x0394, 0xA348, 0x0395, 0xA349, 0x0396, 0xA34A, 0x0397, 0xA34B, 0x0398, 0xA34C, 0x0399, 0xA34D, 0x039A, 0xA34E, 0x039B, 0xA34F, 0x039C, 0xA350, 0x039D, 0xA351, 0x039E, 0xA352, 0x039F, 0xA353, 0x03A0, 0xA354, 0x03A1, 0xA355, 0x03A3, 0xA356, 0x03A4, 0xA357, 0x03A5, 0xA358, 0x03A6, 0xA359, 0x03A7, 0xA35A, 0x03A8, 0xA35B, 0x03A9, 0xA35C, 0x03B1, 0xA35D, 0x03B2, 0xA35E, 0x03B3, 0xA35F, 0x03B4, 0xA360, 0x03B5, 0xA361, 0x03B6, 0xA362, 0x03B7, 0xA363, 0x03B8, 0xA364, 0x03B9, 0xA365, 0x03BA, 0xA366, 0x03BB, 0xA367, 0x03BC, 0xA368, 0x03BD, 0xA369, 0x03BE, 0xA36A, 0x03BF, 0xA36B, 0x03C0, 0xA36C, 0x03C1, 0xA36D, 0x03C3, 0xA36E, 0x03C4, 0xA36F, 0x03C5, 0xA370, 0x03C6, 0xA371, 0x03C7, 0xA372, 0x03C8, 0xA373, 0x03C9, 0xA374, 0x3105, 0xA375, 0x3106, 0xA376, 0x3107, 0xA377, 0x3108, 0xA378, 0x3109, 0xA379, 0x310A, 0xA37A, 0x310B, 0xA37B, 0x310C, 0xA37C, 0x310D, 0xA37D, 0x310E, 0xA37E, 0x310F, 0xA3A1, 0x3110, 0xA3A2, 0x3111, 0xA3A3, 0x3112, 0xA3A4, 0x3113, 0xA3A5, 0x3114, 0xA3A6, 0x3115, 0xA3A7, 0x3116, 0xA3A8, 0x3117, 0xA3A9, 0x3118, 0xA3AA, 0x3119, 0xA3AB, 0x311A, 0xA3AC, 0x311B, 0xA3AD, 0x311C, 0xA3AE, 0x311D, 0xA3AF, 0x311E, 0xA3B0, 0x311F, 0xA3B1, 0x3120, 0xA3B2, 0x3121, 0xA3B3, 0x3122, 0xA3B4, 0x3123, 0xA3B5, 0x3124, 0xA3B6, 0x3125, 0xA3B7, 0x3126, 0xA3B8, 0x3127, 0xA3B9, 0x3128, 0xA3BA, 0x3129, 0xA3BB, 0x02D9, 0xA3BC, 0x02C9, 0xA3BD, 0x02CA, 0xA3BE, 0x02C7, 0xA3BF, 0x02CB, 0xA3E1, 0x20AC, 0xA440, 0x4E00, 0xA441, 0x4E59, 0xA442, 0x4E01, 0xA443, 0x4E03, 0xA444, 0x4E43, 0xA445, 0x4E5D, 0xA446, 0x4E86, 0xA447, 0x4E8C, 0xA448, 0x4EBA, 0xA449, 0x513F, 0xA44A, 0x5165, 0xA44B, 0x516B, 0xA44C, 0x51E0, 0xA44D, 0x5200, 0xA44E, 0x5201, 0xA44F, 0x529B, 0xA450, 0x5315, 0xA451, 0x5341, 0xA452, 0x535C, 0xA453, 0x53C8, 0xA454, 0x4E09, 0xA455, 0x4E0B, 0xA456, 0x4E08, 0xA457, 0x4E0A, 0xA458, 0x4E2B, 0xA459, 0x4E38, 0xA45A, 0x51E1, 0xA45B, 0x4E45, 0xA45C, 0x4E48, 0xA45D, 0x4E5F, 0xA45E, 0x4E5E, 0xA45F, 0x4E8E, 0xA460, 0x4EA1, 0xA461, 0x5140, 0xA462, 0x5203, 0xA463, 0x52FA, 0xA464, 0x5343, 0xA465, 0x53C9, 0xA466, 0x53E3, 0xA467, 0x571F, 0xA468, 0x58EB, 0xA469, 0x5915, 0xA46A, 0x5927, 0xA46B, 0x5973, 0xA46C, 0x5B50, 0xA46D, 0x5B51, 0xA46E, 0x5B53, 0xA46F, 0x5BF8, 0xA470, 0x5C0F, 0xA471, 0x5C22, 0xA472, 0x5C38, 0xA473, 0x5C71, 0xA474, 0x5DDD, 0xA475, 0x5DE5, 0xA476, 0x5DF1, 0xA477, 0x5DF2, 0xA478, 0x5DF3, 0xA479, 0x5DFE, 0xA47A, 0x5E72, 0xA47B, 0x5EFE, 0xA47C, 0x5F0B, 0xA47D, 0x5F13, 0xA47E, 0x624D, 0xA4A1, 0x4E11, 0xA4A2, 0x4E10, 0xA4A3, 0x4E0D, 0xA4A4, 0x4E2D, 0xA4A5, 0x4E30, 0xA4A6, 0x4E39, 0xA4A7, 0x4E4B, 0xA4A8, 0x5C39, 0xA4A9, 0x4E88, 0xA4AA, 0x4E91, 0xA4AB, 0x4E95, 0xA4AC, 0x4E92, 0xA4AD, 0x4E94, 0xA4AE, 0x4EA2, 0xA4AF, 0x4EC1, 0xA4B0, 0x4EC0, 0xA4B1, 0x4EC3, 0xA4B2, 0x4EC6, 0xA4B3, 0x4EC7, 0xA4B4, 0x4ECD, 0xA4B5, 0x4ECA, 0xA4B6, 0x4ECB, 0xA4B7, 0x4EC4, 0xA4B8, 0x5143, 0xA4B9, 0x5141, 0xA4BA, 0x5167, 0xA4BB, 0x516D, 0xA4BC, 0x516E, 0xA4BD, 0x516C, 0xA4BE, 0x5197, 0xA4BF, 0x51F6, 0xA4C0, 0x5206, 0xA4C1, 0x5207, 0xA4C2, 0x5208, 0xA4C3, 0x52FB, 0xA4C4, 0x52FE, 0xA4C5, 0x52FF, 0xA4C6, 0x5316, 0xA4C7, 0x5339, 0xA4C8, 0x5348, 0xA4C9, 0x5347, 0xA4CA, 0x5345, 0xA4CB, 0x535E, 0xA4CC, 0x5384, 0xA4CD, 0x53CB, 0xA4CE, 0x53CA, 0xA4CF, 0x53CD, 0xA4D0, 0x58EC, 0xA4D1, 0x5929, 0xA4D2, 0x592B, 0xA4D3, 0x592A, 0xA4D4, 0x592D, 0xA4D5, 0x5B54, 0xA4D6, 0x5C11, 0xA4D7, 0x5C24, 0xA4D8, 0x5C3A, 0xA4D9, 0x5C6F, 0xA4DA, 0x5DF4, 0xA4DB, 0x5E7B, 0xA4DC, 0x5EFF, 0xA4DD, 0x5F14, 0xA4DE, 0x5F15, 0xA4DF, 0x5FC3, 0xA4E0, 0x6208, 0xA4E1, 0x6236, 0xA4E2, 0x624B, 0xA4E3, 0x624E, 0xA4E4, 0x652F, 0xA4E5, 0x6587, 0xA4E6, 0x6597, 0xA4E7, 0x65A4, 0xA4E8, 0x65B9, 0xA4E9, 0x65E5, 0xA4EA, 0x66F0, 0xA4EB, 0x6708, 0xA4EC, 0x6728, 0xA4ED, 0x6B20, 0xA4EE, 0x6B62, 0xA4EF, 0x6B79, 0xA4F0, 0x6BCB, 0xA4F1, 0x6BD4, 0xA4F2, 0x6BDB, 0xA4F3, 0x6C0F, 0xA4F4, 0x6C34, 0xA4F5, 0x706B, 0xA4F6, 0x722A, 0xA4F7, 0x7236, 0xA4F8, 0x723B, 0xA4F9, 0x7247, 0xA4FA, 0x7259, 0xA4FB, 0x725B, 0xA4FC, 0x72AC, 0xA4FD, 0x738B, 0xA4FE, 0x4E19, 0xA540, 0x4E16, 0xA541, 0x4E15, 0xA542, 0x4E14, 0xA543, 0x4E18, 0xA544, 0x4E3B, 0xA545, 0x4E4D, 0xA546, 0x4E4F, 0xA547, 0x4E4E, 0xA548, 0x4EE5, 0xA549, 0x4ED8, 0xA54A, 0x4ED4, 0xA54B, 0x4ED5, 0xA54C, 0x4ED6, 0xA54D, 0x4ED7, 0xA54E, 0x4EE3, 0xA54F, 0x4EE4, 0xA550, 0x4ED9, 0xA551, 0x4EDE, 0xA552, 0x5145, 0xA553, 0x5144, 0xA554, 0x5189, 0xA555, 0x518A, 0xA556, 0x51AC, 0xA557, 0x51F9, 0xA558, 0x51FA, 0xA559, 0x51F8, 0xA55A, 0x520A, 0xA55B, 0x52A0, 0xA55C, 0x529F, 0xA55D, 0x5305, 0xA55E, 0x5306, 0xA55F, 0x5317, 0xA560, 0x531D, 0xA561, 0x4EDF, 0xA562, 0x534A, 0xA563, 0x5349, 0xA564, 0x5361, 0xA565, 0x5360, 0xA566, 0x536F, 0xA567, 0x536E, 0xA568, 0x53BB, 0xA569, 0x53EF, 0xA56A, 0x53E4, 0xA56B, 0x53F3, 0xA56C, 0x53EC, 0xA56D, 0x53EE, 0xA56E, 0x53E9, 0xA56F, 0x53E8, 0xA570, 0x53FC, 0xA571, 0x53F8, 0xA572, 0x53F5, 0xA573, 0x53EB, 0xA574, 0x53E6, 0xA575, 0x53EA, 0xA576, 0x53F2, 0xA577, 0x53F1, 0xA578, 0x53F0, 0xA579, 0x53E5, 0xA57A, 0x53ED, 0xA57B, 0x53FB, 0xA57C, 0x56DB, 0xA57D, 0x56DA, 0xA57E, 0x5916, 0xA5A1, 0x592E, 0xA5A2, 0x5931, 0xA5A3, 0x5974, 0xA5A4, 0x5976, 0xA5A5, 0x5B55, 0xA5A6, 0x5B83, 0xA5A7, 0x5C3C, 0xA5A8, 0x5DE8, 0xA5A9, 0x5DE7, 0xA5AA, 0x5DE6, 0xA5AB, 0x5E02, 0xA5AC, 0x5E03, 0xA5AD, 0x5E73, 0xA5AE, 0x5E7C, 0xA5AF, 0x5F01, 0xA5B0, 0x5F18, 0xA5B1, 0x5F17, 0xA5B2, 0x5FC5, 0xA5B3, 0x620A, 0xA5B4, 0x6253, 0xA5B5, 0x6254, 0xA5B6, 0x6252, 0xA5B7, 0x6251, 0xA5B8, 0x65A5, 0xA5B9, 0x65E6, 0xA5BA, 0x672E, 0xA5BB, 0x672C, 0xA5BC, 0x672A, 0xA5BD, 0x672B, 0xA5BE, 0x672D, 0xA5BF, 0x6B63, 0xA5C0, 0x6BCD, 0xA5C1, 0x6C11, 0xA5C2, 0x6C10, 0xA5C3, 0x6C38, 0xA5C4, 0x6C41, 0xA5C5, 0x6C40, 0xA5C6, 0x6C3E, 0xA5C7, 0x72AF, 0xA5C8, 0x7384, 0xA5C9, 0x7389, 0xA5CA, 0x74DC, 0xA5CB, 0x74E6, 0xA5CC, 0x7518, 0xA5CD, 0x751F, 0xA5CE, 0x7528, 0xA5CF, 0x7529, 0xA5D0, 0x7530, 0xA5D1, 0x7531, 0xA5D2, 0x7532, 0xA5D3, 0x7533, 0xA5D4, 0x758B, 0xA5D5, 0x767D, 0xA5D6, 0x76AE, 0xA5D7, 0x76BF, 0xA5D8, 0x76EE, 0xA5D9, 0x77DB, 0xA5DA, 0x77E2, 0xA5DB, 0x77F3, 0xA5DC, 0x793A, 0xA5DD, 0x79BE, 0xA5DE, 0x7A74, 0xA5DF, 0x7ACB, 0xA5E0, 0x4E1E, 0xA5E1, 0x4E1F, 0xA5E2, 0x4E52, 0xA5E3, 0x4E53, 0xA5E4, 0x4E69, 0xA5E5, 0x4E99, 0xA5E6, 0x4EA4, 0xA5E7, 0x4EA6, 0xA5E8, 0x4EA5, 0xA5E9, 0x4EFF, 0xA5EA, 0x4F09, 0xA5EB, 0x4F19, 0xA5EC, 0x4F0A, 0xA5ED, 0x4F15, 0xA5EE, 0x4F0D, 0xA5EF, 0x4F10, 0xA5F0, 0x4F11, 0xA5F1, 0x4F0F, 0xA5F2, 0x4EF2, 0xA5F3, 0x4EF6, 0xA5F4, 0x4EFB, 0xA5F5, 0x4EF0, 0xA5F6, 0x4EF3, 0xA5F7, 0x4EFD, 0xA5F8, 0x4F01, 0xA5F9, 0x4F0B, 0xA5FA, 0x5149, 0xA5FB, 0x5147, 0xA5FC, 0x5146, 0xA5FD, 0x5148, 0xA5FE, 0x5168, 0xA640, 0x5171, 0xA641, 0x518D, 0xA642, 0x51B0, 0xA643, 0x5217, 0xA644, 0x5211, 0xA645, 0x5212, 0xA646, 0x520E, 0xA647, 0x5216, 0xA648, 0x52A3, 0xA649, 0x5308, 0xA64A, 0x5321, 0xA64B, 0x5320, 0xA64C, 0x5370, 0xA64D, 0x5371, 0xA64E, 0x5409, 0xA64F, 0x540F, 0xA650, 0x540C, 0xA651, 0x540A, 0xA652, 0x5410, 0xA653, 0x5401, 0xA654, 0x540B, 0xA655, 0x5404, 0xA656, 0x5411, 0xA657, 0x540D, 0xA658, 0x5408, 0xA659, 0x5403, 0xA65A, 0x540E, 0xA65B, 0x5406, 0xA65C, 0x5412, 0xA65D, 0x56E0, 0xA65E, 0x56DE, 0xA65F, 0x56DD, 0xA660, 0x5733, 0xA661, 0x5730, 0xA662, 0x5728, 0xA663, 0x572D, 0xA664, 0x572C, 0xA665, 0x572F, 0xA666, 0x5729, 0xA667, 0x5919, 0xA668, 0x591A, 0xA669, 0x5937, 0xA66A, 0x5938, 0xA66B, 0x5984, 0xA66C, 0x5978, 0xA66D, 0x5983, 0xA66E, 0x597D, 0xA66F, 0x5979, 0xA670, 0x5982, 0xA671, 0x5981, 0xA672, 0x5B57, 0xA673, 0x5B58, 0xA674, 0x5B87, 0xA675, 0x5B88, 0xA676, 0x5B85, 0xA677, 0x5B89, 0xA678, 0x5BFA, 0xA679, 0x5C16, 0xA67A, 0x5C79, 0xA67B, 0x5DDE, 0xA67C, 0x5E06, 0xA67D, 0x5E76, 0xA67E, 0x5E74, 0xA6A1, 0x5F0F, 0xA6A2, 0x5F1B, 0xA6A3, 0x5FD9, 0xA6A4, 0x5FD6, 0xA6A5, 0x620E, 0xA6A6, 0x620C, 0xA6A7, 0x620D, 0xA6A8, 0x6210, 0xA6A9, 0x6263, 0xA6AA, 0x625B, 0xA6AB, 0x6258, 0xA6AC, 0x6536, 0xA6AD, 0x65E9, 0xA6AE, 0x65E8, 0xA6AF, 0x65EC, 0xA6B0, 0x65ED, 0xA6B1, 0x66F2, 0xA6B2, 0x66F3, 0xA6B3, 0x6709, 0xA6B4, 0x673D, 0xA6B5, 0x6734, 0xA6B6, 0x6731, 0xA6B7, 0x6735, 0xA6B8, 0x6B21, 0xA6B9, 0x6B64, 0xA6BA, 0x6B7B, 0xA6BB, 0x6C16, 0xA6BC, 0x6C5D, 0xA6BD, 0x6C57, 0xA6BE, 0x6C59, 0xA6BF, 0x6C5F, 0xA6C0, 0x6C60, 0xA6C1, 0x6C50, 0xA6C2, 0x6C55, 0xA6C3, 0x6C61, 0xA6C4, 0x6C5B, 0xA6C5, 0x6C4D, 0xA6C6, 0x6C4E, 0xA6C7, 0x7070, 0xA6C8, 0x725F, 0xA6C9, 0x725D, 0xA6CA, 0x767E, 0xA6CB, 0x7AF9, 0xA6CC, 0x7C73, 0xA6CD, 0x7CF8, 0xA6CE, 0x7F36, 0xA6CF, 0x7F8A, 0xA6D0, 0x7FBD, 0xA6D1, 0x8001, 0xA6D2, 0x8003, 0xA6D3, 0x800C, 0xA6D4, 0x8012, 0xA6D5, 0x8033, 0xA6D6, 0x807F, 0xA6D7, 0x8089, 0xA6D8, 0x808B, 0xA6D9, 0x808C, 0xA6DA, 0x81E3, 0xA6DB, 0x81EA, 0xA6DC, 0x81F3, 0xA6DD, 0x81FC, 0xA6DE, 0x820C, 0xA6DF, 0x821B, 0xA6E0, 0x821F, 0xA6E1, 0x826E, 0xA6E2, 0x8272, 0xA6E3, 0x827E, 0xA6E4, 0x866B, 0xA6E5, 0x8840, 0xA6E6, 0x884C, 0xA6E7, 0x8863, 0xA6E8, 0x897F, 0xA6E9, 0x9621, 0xA6EA, 0x4E32, 0xA6EB, 0x4EA8, 0xA6EC, 0x4F4D, 0xA6ED, 0x4F4F, 0xA6EE, 0x4F47, 0xA6EF, 0x4F57, 0xA6F0, 0x4F5E, 0xA6F1, 0x4F34, 0xA6F2, 0x4F5B, 0xA6F3, 0x4F55, 0xA6F4, 0x4F30, 0xA6F5, 0x4F50, 0xA6F6, 0x4F51, 0xA6F7, 0x4F3D, 0xA6F8, 0x4F3A, 0xA6F9, 0x4F38, 0xA6FA, 0x4F43, 0xA6FB, 0x4F54, 0xA6FC, 0x4F3C, 0xA6FD, 0x4F46, 0xA6FE, 0x4F63, 0xA740, 0x4F5C, 0xA741, 0x4F60, 0xA742, 0x4F2F, 0xA743, 0x4F4E, 0xA744, 0x4F36, 0xA745, 0x4F59, 0xA746, 0x4F5D, 0xA747, 0x4F48, 0xA748, 0x4F5A, 0xA749, 0x514C, 0xA74A, 0x514B, 0xA74B, 0x514D, 0xA74C, 0x5175, 0xA74D, 0x51B6, 0xA74E, 0x51B7, 0xA74F, 0x5225, 0xA750, 0x5224, 0xA751, 0x5229, 0xA752, 0x522A, 0xA753, 0x5228, 0xA754, 0x52AB, 0xA755, 0x52A9, 0xA756, 0x52AA, 0xA757, 0x52AC, 0xA758, 0x5323, 0xA759, 0x5373, 0xA75A, 0x5375, 0xA75B, 0x541D, 0xA75C, 0x542D, 0xA75D, 0x541E, 0xA75E, 0x543E, 0xA75F, 0x5426, 0xA760, 0x544E, 0xA761, 0x5427, 0xA762, 0x5446, 0xA763, 0x5443, 0xA764, 0x5433, 0xA765, 0x5448, 0xA766, 0x5442, 0xA767, 0x541B, 0xA768, 0x5429, 0xA769, 0x544A, 0xA76A, 0x5439, 0xA76B, 0x543B, 0xA76C, 0x5438, 0xA76D, 0x542E, 0xA76E, 0x5435, 0xA76F, 0x5436, 0xA770, 0x5420, 0xA771, 0x543C, 0xA772, 0x5440, 0xA773, 0x5431, 0xA774, 0x542B, 0xA775, 0x541F, 0xA776, 0x542C, 0xA777, 0x56EA, 0xA778, 0x56F0, 0xA779, 0x56E4, 0xA77A, 0x56EB, 0xA77B, 0x574A, 0xA77C, 0x5751, 0xA77D, 0x5740, 0xA77E, 0x574D, 0xA7A1, 0x5747, 0xA7A2, 0x574E, 0xA7A3, 0x573E, 0xA7A4, 0x5750, 0xA7A5, 0x574F, 0xA7A6, 0x573B, 0xA7A7, 0x58EF, 0xA7A8, 0x593E, 0xA7A9, 0x599D, 0xA7AA, 0x5992, 0xA7AB, 0x59A8, 0xA7AC, 0x599E, 0xA7AD, 0x59A3, 0xA7AE, 0x5999, 0xA7AF, 0x5996, 0xA7B0, 0x598D, 0xA7B1, 0x59A4, 0xA7B2, 0x5993, 0xA7B3, 0x598A, 0xA7B4, 0x59A5, 0xA7B5, 0x5B5D, 0xA7B6, 0x5B5C, 0xA7B7, 0x5B5A, 0xA7B8, 0x5B5B, 0xA7B9, 0x5B8C, 0xA7BA, 0x5B8B, 0xA7BB, 0x5B8F, 0xA7BC, 0x5C2C, 0xA7BD, 0x5C40, 0xA7BE, 0x5C41, 0xA7BF, 0x5C3F, 0xA7C0, 0x5C3E, 0xA7C1, 0x5C90, 0xA7C2, 0x5C91, 0xA7C3, 0x5C94, 0xA7C4, 0x5C8C, 0xA7C5, 0x5DEB, 0xA7C6, 0x5E0C, 0xA7C7, 0x5E8F, 0xA7C8, 0x5E87, 0xA7C9, 0x5E8A, 0xA7CA, 0x5EF7, 0xA7CB, 0x5F04, 0xA7CC, 0x5F1F, 0xA7CD, 0x5F64, 0xA7CE, 0x5F62, 0xA7CF, 0x5F77, 0xA7D0, 0x5F79, 0xA7D1, 0x5FD8, 0xA7D2, 0x5FCC, 0xA7D3, 0x5FD7, 0xA7D4, 0x5FCD, 0xA7D5, 0x5FF1, 0xA7D6, 0x5FEB, 0xA7D7, 0x5FF8, 0xA7D8, 0x5FEA, 0xA7D9, 0x6212, 0xA7DA, 0x6211, 0xA7DB, 0x6284, 0xA7DC, 0x6297, 0xA7DD, 0x6296, 0xA7DE, 0x6280, 0xA7DF, 0x6276, 0xA7E0, 0x6289, 0xA7E1, 0x626D, 0xA7E2, 0x628A, 0xA7E3, 0x627C, 0xA7E4, 0x627E, 0xA7E5, 0x6279, 0xA7E6, 0x6273, 0xA7E7, 0x6292, 0xA7E8, 0x626F, 0xA7E9, 0x6298, 0xA7EA, 0x626E, 0xA7EB, 0x6295, 0xA7EC, 0x6293, 0xA7ED, 0x6291, 0xA7EE, 0x6286, 0xA7EF, 0x6539, 0xA7F0, 0x653B, 0xA7F1, 0x6538, 0xA7F2, 0x65F1, 0xA7F3, 0x66F4, 0xA7F4, 0x675F, 0xA7F5, 0x674E, 0xA7F6, 0x674F, 0xA7F7, 0x6750, 0xA7F8, 0x6751, 0xA7F9, 0x675C, 0xA7FA, 0x6756, 0xA7FB, 0x675E, 0xA7FC, 0x6749, 0xA7FD, 0x6746, 0xA7FE, 0x6760, 0xA840, 0x6753, 0xA841, 0x6757, 0xA842, 0x6B65, 0xA843, 0x6BCF, 0xA844, 0x6C42, 0xA845, 0x6C5E, 0xA846, 0x6C99, 0xA847, 0x6C81, 0xA848, 0x6C88, 0xA849, 0x6C89, 0xA84A, 0x6C85, 0xA84B, 0x6C9B, 0xA84C, 0x6C6A, 0xA84D, 0x6C7A, 0xA84E, 0x6C90, 0xA84F, 0x6C70, 0xA850, 0x6C8C, 0xA851, 0x6C68, 0xA852, 0x6C96, 0xA853, 0x6C92, 0xA854, 0x6C7D, 0xA855, 0x6C83, 0xA856, 0x6C72, 0xA857, 0x6C7E, 0xA858, 0x6C74, 0xA859, 0x6C86, 0xA85A, 0x6C76, 0xA85B, 0x6C8D, 0xA85C, 0x6C94, 0xA85D, 0x6C98, 0xA85E, 0x6C82, 0xA85F, 0x7076, 0xA860, 0x707C, 0xA861, 0x707D, 0xA862, 0x7078, 0xA863, 0x7262, 0xA864, 0x7261, 0xA865, 0x7260, 0xA866, 0x72C4, 0xA867, 0x72C2, 0xA868, 0x7396, 0xA869, 0x752C, 0xA86A, 0x752B, 0xA86B, 0x7537, 0xA86C, 0x7538, 0xA86D, 0x7682, 0xA86E, 0x76EF, 0xA86F, 0x77E3, 0xA870, 0x79C1, 0xA871, 0x79C0, 0xA872, 0x79BF, 0xA873, 0x7A76, 0xA874, 0x7CFB, 0xA875, 0x7F55, 0xA876, 0x8096, 0xA877, 0x8093, 0xA878, 0x809D, 0xA879, 0x8098, 0xA87A, 0x809B, 0xA87B, 0x809A, 0xA87C, 0x80B2, 0xA87D, 0x826F, 0xA87E, 0x8292, 0xA8A1, 0x828B, 0xA8A2, 0x828D, 0xA8A3, 0x898B, 0xA8A4, 0x89D2, 0xA8A5, 0x8A00, 0xA8A6, 0x8C37, 0xA8A7, 0x8C46, 0xA8A8, 0x8C55, 0xA8A9, 0x8C9D, 0xA8AA, 0x8D64, 0xA8AB, 0x8D70, 0xA8AC, 0x8DB3, 0xA8AD, 0x8EAB, 0xA8AE, 0x8ECA, 0xA8AF, 0x8F9B, 0xA8B0, 0x8FB0, 0xA8B1, 0x8FC2, 0xA8B2, 0x8FC6, 0xA8B3, 0x8FC5, 0xA8B4, 0x8FC4, 0xA8B5, 0x5DE1, 0xA8B6, 0x9091, 0xA8B7, 0x90A2, 0xA8B8, 0x90AA, 0xA8B9, 0x90A6, 0xA8BA, 0x90A3, 0xA8BB, 0x9149, 0xA8BC, 0x91C6, 0xA8BD, 0x91CC, 0xA8BE, 0x9632, 0xA8BF, 0x962E, 0xA8C0, 0x9631, 0xA8C1, 0x962A, 0xA8C2, 0x962C, 0xA8C3, 0x4E26, 0xA8C4, 0x4E56, 0xA8C5, 0x4E73, 0xA8C6, 0x4E8B, 0xA8C7, 0x4E9B, 0xA8C8, 0x4E9E, 0xA8C9, 0x4EAB, 0xA8CA, 0x4EAC, 0xA8CB, 0x4F6F, 0xA8CC, 0x4F9D, 0xA8CD, 0x4F8D, 0xA8CE, 0x4F73, 0xA8CF, 0x4F7F, 0xA8D0, 0x4F6C, 0xA8D1, 0x4F9B, 0xA8D2, 0x4F8B, 0xA8D3, 0x4F86, 0xA8D4, 0x4F83, 0xA8D5, 0x4F70, 0xA8D6, 0x4F75, 0xA8D7, 0x4F88, 0xA8D8, 0x4F69, 0xA8D9, 0x4F7B, 0xA8DA, 0x4F96, 0xA8DB, 0x4F7E, 0xA8DC, 0x4F8F, 0xA8DD, 0x4F91, 0xA8DE, 0x4F7A, 0xA8DF, 0x5154, 0xA8E0, 0x5152, 0xA8E1, 0x5155, 0xA8E2, 0x5169, 0xA8E3, 0x5177, 0xA8E4, 0x5176, 0xA8E5, 0x5178, 0xA8E6, 0x51BD, 0xA8E7, 0x51FD, 0xA8E8, 0x523B, 0xA8E9, 0x5238, 0xA8EA, 0x5237, 0xA8EB, 0x523A, 0xA8EC, 0x5230, 0xA8ED, 0x522E, 0xA8EE, 0x5236, 0xA8EF, 0x5241, 0xA8F0, 0x52BE, 0xA8F1, 0x52BB, 0xA8F2, 0x5352, 0xA8F3, 0x5354, 0xA8F4, 0x5353, 0xA8F5, 0x5351, 0xA8F6, 0x5366, 0xA8F7, 0x5377, 0xA8F8, 0x5378, 0xA8F9, 0x5379, 0xA8FA, 0x53D6, 0xA8FB, 0x53D4, 0xA8FC, 0x53D7, 0xA8FD, 0x5473, 0xA8FE, 0x5475, 0xA940, 0x5496, 0xA941, 0x5478, 0xA942, 0x5495, 0xA943, 0x5480, 0xA944, 0x547B, 0xA945, 0x5477, 0xA946, 0x5484, 0xA947, 0x5492, 0xA948, 0x5486, 0xA949, 0x547C, 0xA94A, 0x5490, 0xA94B, 0x5471, 0xA94C, 0x5476, 0xA94D, 0x548C, 0xA94E, 0x549A, 0xA94F, 0x5462, 0xA950, 0x5468, 0xA951, 0x548B, 0xA952, 0x547D, 0xA953, 0x548E, 0xA954, 0x56FA, 0xA955, 0x5783, 0xA956, 0x5777, 0xA957, 0x576A, 0xA958, 0x5769, 0xA959, 0x5761, 0xA95A, 0x5766, 0xA95B, 0x5764, 0xA95C, 0x577C, 0xA95D, 0x591C, 0xA95E, 0x5949, 0xA95F, 0x5947, 0xA960, 0x5948, 0xA961, 0x5944, 0xA962, 0x5954, 0xA963, 0x59BE, 0xA964, 0x59BB, 0xA965, 0x59D4, 0xA966, 0x59B9, 0xA967, 0x59AE, 0xA968, 0x59D1, 0xA969, 0x59C6, 0xA96A, 0x59D0, 0xA96B, 0x59CD, 0xA96C, 0x59CB, 0xA96D, 0x59D3, 0xA96E, 0x59CA, 0xA96F, 0x59AF, 0xA970, 0x59B3, 0xA971, 0x59D2, 0xA972, 0x59C5, 0xA973, 0x5B5F, 0xA974, 0x5B64, 0xA975, 0x5B63, 0xA976, 0x5B97, 0xA977, 0x5B9A, 0xA978, 0x5B98, 0xA979, 0x5B9C, 0xA97A, 0x5B99, 0xA97B, 0x5B9B, 0xA97C, 0x5C1A, 0xA97D, 0x5C48, 0xA97E, 0x5C45, 0xA9A1, 0x5C46, 0xA9A2, 0x5CB7, 0xA9A3, 0x5CA1, 0xA9A4, 0x5CB8, 0xA9A5, 0x5CA9, 0xA9A6, 0x5CAB, 0xA9A7, 0x5CB1, 0xA9A8, 0x5CB3, 0xA9A9, 0x5E18, 0xA9AA, 0x5E1A, 0xA9AB, 0x5E16, 0xA9AC, 0x5E15, 0xA9AD, 0x5E1B, 0xA9AE, 0x5E11, 0xA9AF, 0x5E78, 0xA9B0, 0x5E9A, 0xA9B1, 0x5E97, 0xA9B2, 0x5E9C, 0xA9B3, 0x5E95, 0xA9B4, 0x5E96, 0xA9B5, 0x5EF6, 0xA9B6, 0x5F26, 0xA9B7, 0x5F27, 0xA9B8, 0x5F29, 0xA9B9, 0x5F80, 0xA9BA, 0x5F81, 0xA9BB, 0x5F7F, 0xA9BC, 0x5F7C, 0xA9BD, 0x5FDD, 0xA9BE, 0x5FE0, 0xA9BF, 0x5FFD, 0xA9C0, 0x5FF5, 0xA9C1, 0x5FFF, 0xA9C2, 0x600F, 0xA9C3, 0x6014, 0xA9C4, 0x602F, 0xA9C5, 0x6035, 0xA9C6, 0x6016, 0xA9C7, 0x602A, 0xA9C8, 0x6015, 0xA9C9, 0x6021, 0xA9CA, 0x6027, 0xA9CB, 0x6029, 0xA9CC, 0x602B, 0xA9CD, 0x601B, 0xA9CE, 0x6216, 0xA9CF, 0x6215, 0xA9D0, 0x623F, 0xA9D1, 0x623E, 0xA9D2, 0x6240, 0xA9D3, 0x627F, 0xA9D4, 0x62C9, 0xA9D5, 0x62CC, 0xA9D6, 0x62C4, 0xA9D7, 0x62BF, 0xA9D8, 0x62C2, 0xA9D9, 0x62B9, 0xA9DA, 0x62D2, 0xA9DB, 0x62DB, 0xA9DC, 0x62AB, 0xA9DD, 0x62D3, 0xA9DE, 0x62D4, 0xA9DF, 0x62CB, 0xA9E0, 0x62C8, 0xA9E1, 0x62A8, 0xA9E2, 0x62BD, 0xA9E3, 0x62BC, 0xA9E4, 0x62D0, 0xA9E5, 0x62D9, 0xA9E6, 0x62C7, 0xA9E7, 0x62CD, 0xA9E8, 0x62B5, 0xA9E9, 0x62DA, 0xA9EA, 0x62B1, 0xA9EB, 0x62D8, 0xA9EC, 0x62D6, 0xA9ED, 0x62D7, 0xA9EE, 0x62C6, 0xA9EF, 0x62AC, 0xA9F0, 0x62CE, 0xA9F1, 0x653E, 0xA9F2, 0x65A7, 0xA9F3, 0x65BC, 0xA9F4, 0x65FA, 0xA9F5, 0x6614, 0xA9F6, 0x6613, 0xA9F7, 0x660C, 0xA9F8, 0x6606, 0xA9F9, 0x6602, 0xA9FA, 0x660E, 0xA9FB, 0x6600, 0xA9FC, 0x660F, 0xA9FD, 0x6615, 0xA9FE, 0x660A, 0xAA40, 0x6607, 0xAA41, 0x670D, 0xAA42, 0x670B, 0xAA43, 0x676D, 0xAA44, 0x678B, 0xAA45, 0x6795, 0xAA46, 0x6771, 0xAA47, 0x679C, 0xAA48, 0x6773, 0xAA49, 0x6777, 0xAA4A, 0x6787, 0xAA4B, 0x679D, 0xAA4C, 0x6797, 0xAA4D, 0x676F, 0xAA4E, 0x6770, 0xAA4F, 0x677F, 0xAA50, 0x6789, 0xAA51, 0x677E, 0xAA52, 0x6790, 0xAA53, 0x6775, 0xAA54, 0x679A, 0xAA55, 0x6793, 0xAA56, 0x677C, 0xAA57, 0x676A, 0xAA58, 0x6772, 0xAA59, 0x6B23, 0xAA5A, 0x6B66, 0xAA5B, 0x6B67, 0xAA5C, 0x6B7F, 0xAA5D, 0x6C13, 0xAA5E, 0x6C1B, 0xAA5F, 0x6CE3, 0xAA60, 0x6CE8, 0xAA61, 0x6CF3, 0xAA62, 0x6CB1, 0xAA63, 0x6CCC, 0xAA64, 0x6CE5, 0xAA65, 0x6CB3, 0xAA66, 0x6CBD, 0xAA67, 0x6CBE, 0xAA68, 0x6CBC, 0xAA69, 0x6CE2, 0xAA6A, 0x6CAB, 0xAA6B, 0x6CD5, 0xAA6C, 0x6CD3, 0xAA6D, 0x6CB8, 0xAA6E, 0x6CC4, 0xAA6F, 0x6CB9, 0xAA70, 0x6CC1, 0xAA71, 0x6CAE, 0xAA72, 0x6CD7, 0xAA73, 0x6CC5, 0xAA74, 0x6CF1, 0xAA75, 0x6CBF, 0xAA76, 0x6CBB, 0xAA77, 0x6CE1, 0xAA78, 0x6CDB, 0xAA79, 0x6CCA, 0xAA7A, 0x6CAC, 0xAA7B, 0x6CEF, 0xAA7C, 0x6CDC, 0xAA7D, 0x6CD6, 0xAA7E, 0x6CE0, 0xAAA1, 0x7095, 0xAAA2, 0x708E, 0xAAA3, 0x7092, 0xAAA4, 0x708A, 0xAAA5, 0x7099, 0xAAA6, 0x722C, 0xAAA7, 0x722D, 0xAAA8, 0x7238, 0xAAA9, 0x7248, 0xAAAA, 0x7267, 0xAAAB, 0x7269, 0xAAAC, 0x72C0, 0xAAAD, 0x72CE, 0xAAAE, 0x72D9, 0xAAAF, 0x72D7, 0xAAB0, 0x72D0, 0xAAB1, 0x73A9, 0xAAB2, 0x73A8, 0xAAB3, 0x739F, 0xAAB4, 0x73AB, 0xAAB5, 0x73A5, 0xAAB6, 0x753D, 0xAAB7, 0x759D, 0xAAB8, 0x7599, 0xAAB9, 0x759A, 0xAABA, 0x7684, 0xAABB, 0x76C2, 0xAABC, 0x76F2, 0xAABD, 0x76F4, 0xAABE, 0x77E5, 0xAABF, 0x77FD, 0xAAC0, 0x793E, 0xAAC1, 0x7940, 0xAAC2, 0x7941, 0xAAC3, 0x79C9, 0xAAC4, 0x79C8, 0xAAC5, 0x7A7A, 0xAAC6, 0x7A79, 0xAAC7, 0x7AFA, 0xAAC8, 0x7CFE, 0xAAC9, 0x7F54, 0xAACA, 0x7F8C, 0xAACB, 0x7F8B, 0xAACC, 0x8005, 0xAACD, 0x80BA, 0xAACE, 0x80A5, 0xAACF, 0x80A2, 0xAAD0, 0x80B1, 0xAAD1, 0x80A1, 0xAAD2, 0x80AB, 0xAAD3, 0x80A9, 0xAAD4, 0x80B4, 0xAAD5, 0x80AA, 0xAAD6, 0x80AF, 0xAAD7, 0x81E5, 0xAAD8, 0x81FE, 0xAAD9, 0x820D, 0xAADA, 0x82B3, 0xAADB, 0x829D, 0xAADC, 0x8299, 0xAADD, 0x82AD, 0xAADE, 0x82BD, 0xAADF, 0x829F, 0xAAE0, 0x82B9, 0xAAE1, 0x82B1, 0xAAE2, 0x82AC, 0xAAE3, 0x82A5, 0xAAE4, 0x82AF, 0xAAE5, 0x82B8, 0xAAE6, 0x82A3, 0xAAE7, 0x82B0, 0xAAE8, 0x82BE, 0xAAE9, 0x82B7, 0xAAEA, 0x864E, 0xAAEB, 0x8671, 0xAAEC, 0x521D, 0xAAED, 0x8868, 0xAAEE, 0x8ECB, 0xAAEF, 0x8FCE, 0xAAF0, 0x8FD4, 0xAAF1, 0x8FD1, 0xAAF2, 0x90B5, 0xAAF3, 0x90B8, 0xAAF4, 0x90B1, 0xAAF5, 0x90B6, 0xAAF6, 0x91C7, 0xAAF7, 0x91D1, 0xAAF8, 0x9577, 0xAAF9, 0x9580, 0xAAFA, 0x961C, 0xAAFB, 0x9640, 0xAAFC, 0x963F, 0xAAFD, 0x963B, 0xAAFE, 0x9644, 0xAB40, 0x9642, 0xAB41, 0x96B9, 0xAB42, 0x96E8, 0xAB43, 0x9752, 0xAB44, 0x975E, 0xAB45, 0x4E9F, 0xAB46, 0x4EAD, 0xAB47, 0x4EAE, 0xAB48, 0x4FE1, 0xAB49, 0x4FB5, 0xAB4A, 0x4FAF, 0xAB4B, 0x4FBF, 0xAB4C, 0x4FE0, 0xAB4D, 0x4FD1, 0xAB4E, 0x4FCF, 0xAB4F, 0x4FDD, 0xAB50, 0x4FC3, 0xAB51, 0x4FB6, 0xAB52, 0x4FD8, 0xAB53, 0x4FDF, 0xAB54, 0x4FCA, 0xAB55, 0x4FD7, 0xAB56, 0x4FAE, 0xAB57, 0x4FD0, 0xAB58, 0x4FC4, 0xAB59, 0x4FC2, 0xAB5A, 0x4FDA, 0xAB5B, 0x4FCE, 0xAB5C, 0x4FDE, 0xAB5D, 0x4FB7, 0xAB5E, 0x5157, 0xAB5F, 0x5192, 0xAB60, 0x5191, 0xAB61, 0x51A0, 0xAB62, 0x524E, 0xAB63, 0x5243, 0xAB64, 0x524A, 0xAB65, 0x524D, 0xAB66, 0x524C, 0xAB67, 0x524B, 0xAB68, 0x5247, 0xAB69, 0x52C7, 0xAB6A, 0x52C9, 0xAB6B, 0x52C3, 0xAB6C, 0x52C1, 0xAB6D, 0x530D, 0xAB6E, 0x5357, 0xAB6F, 0x537B, 0xAB70, 0x539A, 0xAB71, 0x53DB, 0xAB72, 0x54AC, 0xAB73, 0x54C0, 0xAB74, 0x54A8, 0xAB75, 0x54CE, 0xAB76, 0x54C9, 0xAB77, 0x54B8, 0xAB78, 0x54A6, 0xAB79, 0x54B3, 0xAB7A, 0x54C7, 0xAB7B, 0x54C2, 0xAB7C, 0x54BD, 0xAB7D, 0x54AA, 0xAB7E, 0x54C1, 0xABA1, 0x54C4, 0xABA2, 0x54C8, 0xABA3, 0x54AF, 0xABA4, 0x54AB, 0xABA5, 0x54B1, 0xABA6, 0x54BB, 0xABA7, 0x54A9, 0xABA8, 0x54A7, 0xABA9, 0x54BF, 0xABAA, 0x56FF, 0xABAB, 0x5782, 0xABAC, 0x578B, 0xABAD, 0x57A0, 0xABAE, 0x57A3, 0xABAF, 0x57A2, 0xABB0, 0x57CE, 0xABB1, 0x57AE, 0xABB2, 0x5793, 0xABB3, 0x5955, 0xABB4, 0x5951, 0xABB5, 0x594F, 0xABB6, 0x594E, 0xABB7, 0x5950, 0xABB8, 0x59DC, 0xABB9, 0x59D8, 0xABBA, 0x59FF, 0xABBB, 0x59E3, 0xABBC, 0x59E8, 0xABBD, 0x5A03, 0xABBE, 0x59E5, 0xABBF, 0x59EA, 0xABC0, 0x59DA, 0xABC1, 0x59E6, 0xABC2, 0x5A01, 0xABC3, 0x59FB, 0xABC4, 0x5B69, 0xABC5, 0x5BA3, 0xABC6, 0x5BA6, 0xABC7, 0x5BA4, 0xABC8, 0x5BA2, 0xABC9, 0x5BA5, 0xABCA, 0x5C01, 0xABCB, 0x5C4E, 0xABCC, 0x5C4F, 0xABCD, 0x5C4D, 0xABCE, 0x5C4B, 0xABCF, 0x5CD9, 0xABD0, 0x5CD2, 0xABD1, 0x5DF7, 0xABD2, 0x5E1D, 0xABD3, 0x5E25, 0xABD4, 0x5E1F, 0xABD5, 0x5E7D, 0xABD6, 0x5EA0, 0xABD7, 0x5EA6, 0xABD8, 0x5EFA, 0xABD9, 0x5F08, 0xABDA, 0x5F2D, 0xABDB, 0x5F65, 0xABDC, 0x5F88, 0xABDD, 0x5F85, 0xABDE, 0x5F8A, 0xABDF, 0x5F8B, 0xABE0, 0x5F87, 0xABE1, 0x5F8C, 0xABE2, 0x5F89, 0xABE3, 0x6012, 0xABE4, 0x601D, 0xABE5, 0x6020, 0xABE6, 0x6025, 0xABE7, 0x600E, 0xABE8, 0x6028, 0xABE9, 0x604D, 0xABEA, 0x6070, 0xABEB, 0x6068, 0xABEC, 0x6062, 0xABED, 0x6046, 0xABEE, 0x6043, 0xABEF, 0x606C, 0xABF0, 0x606B, 0xABF1, 0x606A, 0xABF2, 0x6064, 0xABF3, 0x6241, 0xABF4, 0x62DC, 0xABF5, 0x6316, 0xABF6, 0x6309, 0xABF7, 0x62FC, 0xABF8, 0x62ED, 0xABF9, 0x6301, 0xABFA, 0x62EE, 0xABFB, 0x62FD, 0xABFC, 0x6307, 0xABFD, 0x62F1, 0xABFE, 0x62F7, 0xAC40, 0x62EF, 0xAC41, 0x62EC, 0xAC42, 0x62FE, 0xAC43, 0x62F4, 0xAC44, 0x6311, 0xAC45, 0x6302, 0xAC46, 0x653F, 0xAC47, 0x6545, 0xAC48, 0x65AB, 0xAC49, 0x65BD, 0xAC4A, 0x65E2, 0xAC4B, 0x6625, 0xAC4C, 0x662D, 0xAC4D, 0x6620, 0xAC4E, 0x6627, 0xAC4F, 0x662F, 0xAC50, 0x661F, 0xAC51, 0x6628, 0xAC52, 0x6631, 0xAC53, 0x6624, 0xAC54, 0x66F7, 0xAC55, 0x67FF, 0xAC56, 0x67D3, 0xAC57, 0x67F1, 0xAC58, 0x67D4, 0xAC59, 0x67D0, 0xAC5A, 0x67EC, 0xAC5B, 0x67B6, 0xAC5C, 0x67AF, 0xAC5D, 0x67F5, 0xAC5E, 0x67E9, 0xAC5F, 0x67EF, 0xAC60, 0x67C4, 0xAC61, 0x67D1, 0xAC62, 0x67B4, 0xAC63, 0x67DA, 0xAC64, 0x67E5, 0xAC65, 0x67B8, 0xAC66, 0x67CF, 0xAC67, 0x67DE, 0xAC68, 0x67F3, 0xAC69, 0x67B0, 0xAC6A, 0x67D9, 0xAC6B, 0x67E2, 0xAC6C, 0x67DD, 0xAC6D, 0x67D2, 0xAC6E, 0x6B6A, 0xAC6F, 0x6B83, 0xAC70, 0x6B86, 0xAC71, 0x6BB5, 0xAC72, 0x6BD2, 0xAC73, 0x6BD7, 0xAC74, 0x6C1F, 0xAC75, 0x6CC9, 0xAC76, 0x6D0B, 0xAC77, 0x6D32, 0xAC78, 0x6D2A, 0xAC79, 0x6D41, 0xAC7A, 0x6D25, 0xAC7B, 0x6D0C, 0xAC7C, 0x6D31, 0xAC7D, 0x6D1E, 0xAC7E, 0x6D17, 0xACA1, 0x6D3B, 0xACA2, 0x6D3D, 0xACA3, 0x6D3E, 0xACA4, 0x6D36, 0xACA5, 0x6D1B, 0xACA6, 0x6CF5, 0xACA7, 0x6D39, 0xACA8, 0x6D27, 0xACA9, 0x6D38, 0xACAA, 0x6D29, 0xACAB, 0x6D2E, 0xACAC, 0x6D35, 0xACAD, 0x6D0E, 0xACAE, 0x6D2B, 0xACAF, 0x70AB, 0xACB0, 0x70BA, 0xACB1, 0x70B3, 0xACB2, 0x70AC, 0xACB3, 0x70AF, 0xACB4, 0x70AD, 0xACB5, 0x70B8, 0xACB6, 0x70AE, 0xACB7, 0x70A4, 0xACB8, 0x7230, 0xACB9, 0x7272, 0xACBA, 0x726F, 0xACBB, 0x7274, 0xACBC, 0x72E9, 0xACBD, 0x72E0, 0xACBE, 0x72E1, 0xACBF, 0x73B7, 0xACC0, 0x73CA, 0xACC1, 0x73BB, 0xACC2, 0x73B2, 0xACC3, 0x73CD, 0xACC4, 0x73C0, 0xACC5, 0x73B3, 0xACC6, 0x751A, 0xACC7, 0x752D, 0xACC8, 0x754F, 0xACC9, 0x754C, 0xACCA, 0x754E, 0xACCB, 0x754B, 0xACCC, 0x75AB, 0xACCD, 0x75A4, 0xACCE, 0x75A5, 0xACCF, 0x75A2, 0xACD0, 0x75A3, 0xACD1, 0x7678, 0xACD2, 0x7686, 0xACD3, 0x7687, 0xACD4, 0x7688, 0xACD5, 0x76C8, 0xACD6, 0x76C6, 0xACD7, 0x76C3, 0xACD8, 0x76C5, 0xACD9, 0x7701, 0xACDA, 0x76F9, 0xACDB, 0x76F8, 0xACDC, 0x7709, 0xACDD, 0x770B, 0xACDE, 0x76FE, 0xACDF, 0x76FC, 0xACE0, 0x7707, 0xACE1, 0x77DC, 0xACE2, 0x7802, 0xACE3, 0x7814, 0xACE4, 0x780C, 0xACE5, 0x780D, 0xACE6, 0x7946, 0xACE7, 0x7949, 0xACE8, 0x7948, 0xACE9, 0x7947, 0xACEA, 0x79B9, 0xACEB, 0x79BA, 0xACEC, 0x79D1, 0xACED, 0x79D2, 0xACEE, 0x79CB, 0xACEF, 0x7A7F, 0xACF0, 0x7A81, 0xACF1, 0x7AFF, 0xACF2, 0x7AFD, 0xACF3, 0x7C7D, 0xACF4, 0x7D02, 0xACF5, 0x7D05, 0xACF6, 0x7D00, 0xACF7, 0x7D09, 0xACF8, 0x7D07, 0xACF9, 0x7D04, 0xACFA, 0x7D06, 0xACFB, 0x7F38, 0xACFC, 0x7F8E, 0xACFD, 0x7FBF, 0xACFE, 0x8004, 0xAD40, 0x8010, 0xAD41, 0x800D, 0xAD42, 0x8011, 0xAD43, 0x8036, 0xAD44, 0x80D6, 0xAD45, 0x80E5, 0xAD46, 0x80DA, 0xAD47, 0x80C3, 0xAD48, 0x80C4, 0xAD49, 0x80CC, 0xAD4A, 0x80E1, 0xAD4B, 0x80DB, 0xAD4C, 0x80CE, 0xAD4D, 0x80DE, 0xAD4E, 0x80E4, 0xAD4F, 0x80DD, 0xAD50, 0x81F4, 0xAD51, 0x8222, 0xAD52, 0x82E7, 0xAD53, 0x8303, 0xAD54, 0x8305, 0xAD55, 0x82E3, 0xAD56, 0x82DB, 0xAD57, 0x82E6, 0xAD58, 0x8304, 0xAD59, 0x82E5, 0xAD5A, 0x8302, 0xAD5B, 0x8309, 0xAD5C, 0x82D2, 0xAD5D, 0x82D7, 0xAD5E, 0x82F1, 0xAD5F, 0x8301, 0xAD60, 0x82DC, 0xAD61, 0x82D4, 0xAD62, 0x82D1, 0xAD63, 0x82DE, 0xAD64, 0x82D3, 0xAD65, 0x82DF, 0xAD66, 0x82EF, 0xAD67, 0x8306, 0xAD68, 0x8650, 0xAD69, 0x8679, 0xAD6A, 0x867B, 0xAD6B, 0x867A, 0xAD6C, 0x884D, 0xAD6D, 0x886B, 0xAD6E, 0x8981, 0xAD6F, 0x89D4, 0xAD70, 0x8A08, 0xAD71, 0x8A02, 0xAD72, 0x8A03, 0xAD73, 0x8C9E, 0xAD74, 0x8CA0, 0xAD75, 0x8D74, 0xAD76, 0x8D73, 0xAD77, 0x8DB4, 0xAD78, 0x8ECD, 0xAD79, 0x8ECC, 0xAD7A, 0x8FF0, 0xAD7B, 0x8FE6, 0xAD7C, 0x8FE2, 0xAD7D, 0x8FEA, 0xAD7E, 0x8FE5, 0xADA1, 0x8FED, 0xADA2, 0x8FEB, 0xADA3, 0x8FE4, 0xADA4, 0x8FE8, 0xADA5, 0x90CA, 0xADA6, 0x90CE, 0xADA7, 0x90C1, 0xADA8, 0x90C3, 0xADA9, 0x914B, 0xADAA, 0x914A, 0xADAB, 0x91CD, 0xADAC, 0x9582, 0xADAD, 0x9650, 0xADAE, 0x964B, 0xADAF, 0x964C, 0xADB0, 0x964D, 0xADB1, 0x9762, 0xADB2, 0x9769, 0xADB3, 0x97CB, 0xADB4, 0x97ED, 0xADB5, 0x97F3, 0xADB6, 0x9801, 0xADB7, 0x98A8, 0xADB8, 0x98DB, 0xADB9, 0x98DF, 0xADBA, 0x9996, 0xADBB, 0x9999, 0xADBC, 0x4E58, 0xADBD, 0x4EB3, 0xADBE, 0x500C, 0xADBF, 0x500D, 0xADC0, 0x5023, 0xADC1, 0x4FEF, 0xADC2, 0x5026, 0xADC3, 0x5025, 0xADC4, 0x4FF8, 0xADC5, 0x5029, 0xADC6, 0x5016, 0xADC7, 0x5006, 0xADC8, 0x503C, 0xADC9, 0x501F, 0xADCA, 0x501A, 0xADCB, 0x5012, 0xADCC, 0x5011, 0xADCD, 0x4FFA, 0xADCE, 0x5000, 0xADCF, 0x5014, 0xADD0, 0x5028, 0xADD1, 0x4FF1, 0xADD2, 0x5021, 0xADD3, 0x500B, 0xADD4, 0x5019, 0xADD5, 0x5018, 0xADD6, 0x4FF3, 0xADD7, 0x4FEE, 0xADD8, 0x502D, 0xADD9, 0x502A, 0xADDA, 0x4FFE, 0xADDB, 0x502B, 0xADDC, 0x5009, 0xADDD, 0x517C, 0xADDE, 0x51A4, 0xADDF, 0x51A5, 0xADE0, 0x51A2, 0xADE1, 0x51CD, 0xADE2, 0x51CC, 0xADE3, 0x51C6, 0xADE4, 0x51CB, 0xADE5, 0x5256, 0xADE6, 0x525C, 0xADE7, 0x5254, 0xADE8, 0x525B, 0xADE9, 0x525D, 0xADEA, 0x532A, 0xADEB, 0x537F, 0xADEC, 0x539F, 0xADED, 0x539D, 0xADEE, 0x53DF, 0xADEF, 0x54E8, 0xADF0, 0x5510, 0xADF1, 0x5501, 0xADF2, 0x5537, 0xADF3, 0x54FC, 0xADF4, 0x54E5, 0xADF5, 0x54F2, 0xADF6, 0x5506, 0xADF7, 0x54FA, 0xADF8, 0x5514, 0xADF9, 0x54E9, 0xADFA, 0x54ED, 0xADFB, 0x54E1, 0xADFC, 0x5509, 0xADFD, 0x54EE, 0xADFE, 0x54EA, 0xAE40, 0x54E6, 0xAE41, 0x5527, 0xAE42, 0x5507, 0xAE43, 0x54FD, 0xAE44, 0x550F, 0xAE45, 0x5703, 0xAE46, 0x5704, 0xAE47, 0x57C2, 0xAE48, 0x57D4, 0xAE49, 0x57CB, 0xAE4A, 0x57C3, 0xAE4B, 0x5809, 0xAE4C, 0x590F, 0xAE4D, 0x5957, 0xAE4E, 0x5958, 0xAE4F, 0x595A, 0xAE50, 0x5A11, 0xAE51, 0x5A18, 0xAE52, 0x5A1C, 0xAE53, 0x5A1F, 0xAE54, 0x5A1B, 0xAE55, 0x5A13, 0xAE56, 0x59EC, 0xAE57, 0x5A20, 0xAE58, 0x5A23, 0xAE59, 0x5A29, 0xAE5A, 0x5A25, 0xAE5B, 0x5A0C, 0xAE5C, 0x5A09, 0xAE5D, 0x5B6B, 0xAE5E, 0x5C58, 0xAE5F, 0x5BB0, 0xAE60, 0x5BB3, 0xAE61, 0x5BB6, 0xAE62, 0x5BB4, 0xAE63, 0x5BAE, 0xAE64, 0x5BB5, 0xAE65, 0x5BB9, 0xAE66, 0x5BB8, 0xAE67, 0x5C04, 0xAE68, 0x5C51, 0xAE69, 0x5C55, 0xAE6A, 0x5C50, 0xAE6B, 0x5CED, 0xAE6C, 0x5CFD, 0xAE6D, 0x5CFB, 0xAE6E, 0x5CEA, 0xAE6F, 0x5CE8, 0xAE70, 0x5CF0, 0xAE71, 0x5CF6, 0xAE72, 0x5D01, 0xAE73, 0x5CF4, 0xAE74, 0x5DEE, 0xAE75, 0x5E2D, 0xAE76, 0x5E2B, 0xAE77, 0x5EAB, 0xAE78, 0x5EAD, 0xAE79, 0x5EA7, 0xAE7A, 0x5F31, 0xAE7B, 0x5F92, 0xAE7C, 0x5F91, 0xAE7D, 0x5F90, 0xAE7E, 0x6059, 0xAEA1, 0x6063, 0xAEA2, 0x6065, 0xAEA3, 0x6050, 0xAEA4, 0x6055, 0xAEA5, 0x606D, 0xAEA6, 0x6069, 0xAEA7, 0x606F, 0xAEA8, 0x6084, 0xAEA9, 0x609F, 0xAEAA, 0x609A, 0xAEAB, 0x608D, 0xAEAC, 0x6094, 0xAEAD, 0x608C, 0xAEAE, 0x6085, 0xAEAF, 0x6096, 0xAEB0, 0x6247, 0xAEB1, 0x62F3, 0xAEB2, 0x6308, 0xAEB3, 0x62FF, 0xAEB4, 0x634E, 0xAEB5, 0x633E, 0xAEB6, 0x632F, 0xAEB7, 0x6355, 0xAEB8, 0x6342, 0xAEB9, 0x6346, 0xAEBA, 0x634F, 0xAEBB, 0x6349, 0xAEBC, 0x633A, 0xAEBD, 0x6350, 0xAEBE, 0x633D, 0xAEBF, 0x632A, 0xAEC0, 0x632B, 0xAEC1, 0x6328, 0xAEC2, 0x634D, 0xAEC3, 0x634C, 0xAEC4, 0x6548, 0xAEC5, 0x6549, 0xAEC6, 0x6599, 0xAEC7, 0x65C1, 0xAEC8, 0x65C5, 0xAEC9, 0x6642, 0xAECA, 0x6649, 0xAECB, 0x664F, 0xAECC, 0x6643, 0xAECD, 0x6652, 0xAECE, 0x664C, 0xAECF, 0x6645, 0xAED0, 0x6641, 0xAED1, 0x66F8, 0xAED2, 0x6714, 0xAED3, 0x6715, 0xAED4, 0x6717, 0xAED5, 0x6821, 0xAED6, 0x6838, 0xAED7, 0x6848, 0xAED8, 0x6846, 0xAED9, 0x6853, 0xAEDA, 0x6839, 0xAEDB, 0x6842, 0xAEDC, 0x6854, 0xAEDD, 0x6829, 0xAEDE, 0x68B3, 0xAEDF, 0x6817, 0xAEE0, 0x684C, 0xAEE1, 0x6851, 0xAEE2, 0x683D, 0xAEE3, 0x67F4, 0xAEE4, 0x6850, 0xAEE5, 0x6840, 0xAEE6, 0x683C, 0xAEE7, 0x6843, 0xAEE8, 0x682A, 0xAEE9, 0x6845, 0xAEEA, 0x6813, 0xAEEB, 0x6818, 0xAEEC, 0x6841, 0xAEED, 0x6B8A, 0xAEEE, 0x6B89, 0xAEEF, 0x6BB7, 0xAEF0, 0x6C23, 0xAEF1, 0x6C27, 0xAEF2, 0x6C28, 0xAEF3, 0x6C26, 0xAEF4, 0x6C24, 0xAEF5, 0x6CF0, 0xAEF6, 0x6D6A, 0xAEF7, 0x6D95, 0xAEF8, 0x6D88, 0xAEF9, 0x6D87, 0xAEFA, 0x6D66, 0xAEFB, 0x6D78, 0xAEFC, 0x6D77, 0xAEFD, 0x6D59, 0xAEFE, 0x6D93, 0xAF40, 0x6D6C, 0xAF41, 0x6D89, 0xAF42, 0x6D6E, 0xAF43, 0x6D5A, 0xAF44, 0x6D74, 0xAF45, 0x6D69, 0xAF46, 0x6D8C, 0xAF47, 0x6D8A, 0xAF48, 0x6D79, 0xAF49, 0x6D85, 0xAF4A, 0x6D65, 0xAF4B, 0x6D94, 0xAF4C, 0x70CA, 0xAF4D, 0x70D8, 0xAF4E, 0x70E4, 0xAF4F, 0x70D9, 0xAF50, 0x70C8, 0xAF51, 0x70CF, 0xAF52, 0x7239, 0xAF53, 0x7279, 0xAF54, 0x72FC, 0xAF55, 0x72F9, 0xAF56, 0x72FD, 0xAF57, 0x72F8, 0xAF58, 0x72F7, 0xAF59, 0x7386, 0xAF5A, 0x73ED, 0xAF5B, 0x7409, 0xAF5C, 0x73EE, 0xAF5D, 0x73E0, 0xAF5E, 0x73EA, 0xAF5F, 0x73DE, 0xAF60, 0x7554, 0xAF61, 0x755D, 0xAF62, 0x755C, 0xAF63, 0x755A, 0xAF64, 0x7559, 0xAF65, 0x75BE, 0xAF66, 0x75C5, 0xAF67, 0x75C7, 0xAF68, 0x75B2, 0xAF69, 0x75B3, 0xAF6A, 0x75BD, 0xAF6B, 0x75BC, 0xAF6C, 0x75B9, 0xAF6D, 0x75C2, 0xAF6E, 0x75B8, 0xAF6F, 0x768B, 0xAF70, 0x76B0, 0xAF71, 0x76CA, 0xAF72, 0x76CD, 0xAF73, 0x76CE, 0xAF74, 0x7729, 0xAF75, 0x771F, 0xAF76, 0x7720, 0xAF77, 0x7728, 0xAF78, 0x77E9, 0xAF79, 0x7830, 0xAF7A, 0x7827, 0xAF7B, 0x7838, 0xAF7C, 0x781D, 0xAF7D, 0x7834, 0xAF7E, 0x7837, 0xAFA1, 0x7825, 0xAFA2, 0x782D, 0xAFA3, 0x7820, 0xAFA4, 0x781F, 0xAFA5, 0x7832, 0xAFA6, 0x7955, 0xAFA7, 0x7950, 0xAFA8, 0x7960, 0xAFA9, 0x795F, 0xAFAA, 0x7956, 0xAFAB, 0x795E, 0xAFAC, 0x795D, 0xAFAD, 0x7957, 0xAFAE, 0x795A, 0xAFAF, 0x79E4, 0xAFB0, 0x79E3, 0xAFB1, 0x79E7, 0xAFB2, 0x79DF, 0xAFB3, 0x79E6, 0xAFB4, 0x79E9, 0xAFB5, 0x79D8, 0xAFB6, 0x7A84, 0xAFB7, 0x7A88, 0xAFB8, 0x7AD9, 0xAFB9, 0x7B06, 0xAFBA, 0x7B11, 0xAFBB, 0x7C89, 0xAFBC, 0x7D21, 0xAFBD, 0x7D17, 0xAFBE, 0x7D0B, 0xAFBF, 0x7D0A, 0xAFC0, 0x7D20, 0xAFC1, 0x7D22, 0xAFC2, 0x7D14, 0xAFC3, 0x7D10, 0xAFC4, 0x7D15, 0xAFC5, 0x7D1A, 0xAFC6, 0x7D1C, 0xAFC7, 0x7D0D, 0xAFC8, 0x7D19, 0xAFC9, 0x7D1B, 0xAFCA, 0x7F3A, 0xAFCB, 0x7F5F, 0xAFCC, 0x7F94, 0xAFCD, 0x7FC5, 0xAFCE, 0x7FC1, 0xAFCF, 0x8006, 0xAFD0, 0x8018, 0xAFD1, 0x8015, 0xAFD2, 0x8019, 0xAFD3, 0x8017, 0xAFD4, 0x803D, 0xAFD5, 0x803F, 0xAFD6, 0x80F1, 0xAFD7, 0x8102, 0xAFD8, 0x80F0, 0xAFD9, 0x8105, 0xAFDA, 0x80ED, 0xAFDB, 0x80F4, 0xAFDC, 0x8106, 0xAFDD, 0x80F8, 0xAFDE, 0x80F3, 0xAFDF, 0x8108, 0xAFE0, 0x80FD, 0xAFE1, 0x810A, 0xAFE2, 0x80FC, 0xAFE3, 0x80EF, 0xAFE4, 0x81ED, 0xAFE5, 0x81EC, 0xAFE6, 0x8200, 0xAFE7, 0x8210, 0xAFE8, 0x822A, 0xAFE9, 0x822B, 0xAFEA, 0x8228, 0xAFEB, 0x822C, 0xAFEC, 0x82BB, 0xAFED, 0x832B, 0xAFEE, 0x8352, 0xAFEF, 0x8354, 0xAFF0, 0x834A, 0xAFF1, 0x8338, 0xAFF2, 0x8350, 0xAFF3, 0x8349, 0xAFF4, 0x8335, 0xAFF5, 0x8334, 0xAFF6, 0x834F, 0xAFF7, 0x8332, 0xAFF8, 0x8339, 0xAFF9, 0x8336, 0xAFFA, 0x8317, 0xAFFB, 0x8340, 0xAFFC, 0x8331, 0xAFFD, 0x8328, 0xAFFE, 0x8343, 0xB040, 0x8654, 0xB041, 0x868A, 0xB042, 0x86AA, 0xB043, 0x8693, 0xB044, 0x86A4, 0xB045, 0x86A9, 0xB046, 0x868C, 0xB047, 0x86A3, 0xB048, 0x869C, 0xB049, 0x8870, 0xB04A, 0x8877, 0xB04B, 0x8881, 0xB04C, 0x8882, 0xB04D, 0x887D, 0xB04E, 0x8879, 0xB04F, 0x8A18, 0xB050, 0x8A10, 0xB051, 0x8A0E, 0xB052, 0x8A0C, 0xB053, 0x8A15, 0xB054, 0x8A0A, 0xB055, 0x8A17, 0xB056, 0x8A13, 0xB057, 0x8A16, 0xB058, 0x8A0F, 0xB059, 0x8A11, 0xB05A, 0x8C48, 0xB05B, 0x8C7A, 0xB05C, 0x8C79, 0xB05D, 0x8CA1, 0xB05E, 0x8CA2, 0xB05F, 0x8D77, 0xB060, 0x8EAC, 0xB061, 0x8ED2, 0xB062, 0x8ED4, 0xB063, 0x8ECF, 0xB064, 0x8FB1, 0xB065, 0x9001, 0xB066, 0x9006, 0xB067, 0x8FF7, 0xB068, 0x9000, 0xB069, 0x8FFA, 0xB06A, 0x8FF4, 0xB06B, 0x9003, 0xB06C, 0x8FFD, 0xB06D, 0x9005, 0xB06E, 0x8FF8, 0xB06F, 0x9095, 0xB070, 0x90E1, 0xB071, 0x90DD, 0xB072, 0x90E2, 0xB073, 0x9152, 0xB074, 0x914D, 0xB075, 0x914C, 0xB076, 0x91D8, 0xB077, 0x91DD, 0xB078, 0x91D7, 0xB079, 0x91DC, 0xB07A, 0x91D9, 0xB07B, 0x9583, 0xB07C, 0x9662, 0xB07D, 0x9663, 0xB07E, 0x9661, 0xB0A1, 0x965B, 0xB0A2, 0x965D, 0xB0A3, 0x9664, 0xB0A4, 0x9658, 0xB0A5, 0x965E, 0xB0A6, 0x96BB, 0xB0A7, 0x98E2, 0xB0A8, 0x99AC, 0xB0A9, 0x9AA8, 0xB0AA, 0x9AD8, 0xB0AB, 0x9B25, 0xB0AC, 0x9B32, 0xB0AD, 0x9B3C, 0xB0AE, 0x4E7E, 0xB0AF, 0x507A, 0xB0B0, 0x507D, 0xB0B1, 0x505C, 0xB0B2, 0x5047, 0xB0B3, 0x5043, 0xB0B4, 0x504C, 0xB0B5, 0x505A, 0xB0B6, 0x5049, 0xB0B7, 0x5065, 0xB0B8, 0x5076, 0xB0B9, 0x504E, 0xB0BA, 0x5055, 0xB0BB, 0x5075, 0xB0BC, 0x5074, 0xB0BD, 0x5077, 0xB0BE, 0x504F, 0xB0BF, 0x500F, 0xB0C0, 0x506F, 0xB0C1, 0x506D, 0xB0C2, 0x515C, 0xB0C3, 0x5195, 0xB0C4, 0x51F0, 0xB0C5, 0x526A, 0xB0C6, 0x526F, 0xB0C7, 0x52D2, 0xB0C8, 0x52D9, 0xB0C9, 0x52D8, 0xB0CA, 0x52D5, 0xB0CB, 0x5310, 0xB0CC, 0x530F, 0xB0CD, 0x5319, 0xB0CE, 0x533F, 0xB0CF, 0x5340, 0xB0D0, 0x533E, 0xB0D1, 0x53C3, 0xB0D2, 0x66FC, 0xB0D3, 0x5546, 0xB0D4, 0x556A, 0xB0D5, 0x5566, 0xB0D6, 0x5544, 0xB0D7, 0x555E, 0xB0D8, 0x5561, 0xB0D9, 0x5543, 0xB0DA, 0x554A, 0xB0DB, 0x5531, 0xB0DC, 0x5556, 0xB0DD, 0x554F, 0xB0DE, 0x5555, 0xB0DF, 0x552F, 0xB0E0, 0x5564, 0xB0E1, 0x5538, 0xB0E2, 0x552E, 0xB0E3, 0x555C, 0xB0E4, 0x552C, 0xB0E5, 0x5563, 0xB0E6, 0x5533, 0xB0E7, 0x5541, 0xB0E8, 0x5557, 0xB0E9, 0x5708, 0xB0EA, 0x570B, 0xB0EB, 0x5709, 0xB0EC, 0x57DF, 0xB0ED, 0x5805, 0xB0EE, 0x580A, 0xB0EF, 0x5806, 0xB0F0, 0x57E0, 0xB0F1, 0x57E4, 0xB0F2, 0x57FA, 0xB0F3, 0x5802, 0xB0F4, 0x5835, 0xB0F5, 0x57F7, 0xB0F6, 0x57F9, 0xB0F7, 0x5920, 0xB0F8, 0x5962, 0xB0F9, 0x5A36, 0xB0FA, 0x5A41, 0xB0FB, 0x5A49, 0xB0FC, 0x5A66, 0xB0FD, 0x5A6A, 0xB0FE, 0x5A40, 0xB140, 0x5A3C, 0xB141, 0x5A62, 0xB142, 0x5A5A, 0xB143, 0x5A46, 0xB144, 0x5A4A, 0xB145, 0x5B70, 0xB146, 0x5BC7, 0xB147, 0x5BC5, 0xB148, 0x5BC4, 0xB149, 0x5BC2, 0xB14A, 0x5BBF, 0xB14B, 0x5BC6, 0xB14C, 0x5C09, 0xB14D, 0x5C08, 0xB14E, 0x5C07, 0xB14F, 0x5C60, 0xB150, 0x5C5C, 0xB151, 0x5C5D, 0xB152, 0x5D07, 0xB153, 0x5D06, 0xB154, 0x5D0E, 0xB155, 0x5D1B, 0xB156, 0x5D16, 0xB157, 0x5D22, 0xB158, 0x5D11, 0xB159, 0x5D29, 0xB15A, 0x5D14, 0xB15B, 0x5D19, 0xB15C, 0x5D24, 0xB15D, 0x5D27, 0xB15E, 0x5D17, 0xB15F, 0x5DE2, 0xB160, 0x5E38, 0xB161, 0x5E36, 0xB162, 0x5E33, 0xB163, 0x5E37, 0xB164, 0x5EB7, 0xB165, 0x5EB8, 0xB166, 0x5EB6, 0xB167, 0x5EB5, 0xB168, 0x5EBE, 0xB169, 0x5F35, 0xB16A, 0x5F37, 0xB16B, 0x5F57, 0xB16C, 0x5F6C, 0xB16D, 0x5F69, 0xB16E, 0x5F6B, 0xB16F, 0x5F97, 0xB170, 0x5F99, 0xB171, 0x5F9E, 0xB172, 0x5F98, 0xB173, 0x5FA1, 0xB174, 0x5FA0, 0xB175, 0x5F9C, 0xB176, 0x607F, 0xB177, 0x60A3, 0xB178, 0x6089, 0xB179, 0x60A0, 0xB17A, 0x60A8, 0xB17B, 0x60CB, 0xB17C, 0x60B4, 0xB17D, 0x60E6, 0xB17E, 0x60BD, 0xB1A1, 0x60C5, 0xB1A2, 0x60BB, 0xB1A3, 0x60B5, 0xB1A4, 0x60DC, 0xB1A5, 0x60BC, 0xB1A6, 0x60D8, 0xB1A7, 0x60D5, 0xB1A8, 0x60C6, 0xB1A9, 0x60DF, 0xB1AA, 0x60B8, 0xB1AB, 0x60DA, 0xB1AC, 0x60C7, 0xB1AD, 0x621A, 0xB1AE, 0x621B, 0xB1AF, 0x6248, 0xB1B0, 0x63A0, 0xB1B1, 0x63A7, 0xB1B2, 0x6372, 0xB1B3, 0x6396, 0xB1B4, 0x63A2, 0xB1B5, 0x63A5, 0xB1B6, 0x6377, 0xB1B7, 0x6367, 0xB1B8, 0x6398, 0xB1B9, 0x63AA, 0xB1BA, 0x6371, 0xB1BB, 0x63A9, 0xB1BC, 0x6389, 0xB1BD, 0x6383, 0xB1BE, 0x639B, 0xB1BF, 0x636B, 0xB1C0, 0x63A8, 0xB1C1, 0x6384, 0xB1C2, 0x6388, 0xB1C3, 0x6399, 0xB1C4, 0x63A1, 0xB1C5, 0x63AC, 0xB1C6, 0x6392, 0xB1C7, 0x638F, 0xB1C8, 0x6380, 0xB1C9, 0x637B, 0xB1CA, 0x6369, 0xB1CB, 0x6368, 0xB1CC, 0x637A, 0xB1CD, 0x655D, 0xB1CE, 0x6556, 0xB1CF, 0x6551, 0xB1D0, 0x6559, 0xB1D1, 0x6557, 0xB1D2, 0x555F, 0xB1D3, 0x654F, 0xB1D4, 0x6558, 0xB1D5, 0x6555, 0xB1D6, 0x6554, 0xB1D7, 0x659C, 0xB1D8, 0x659B, 0xB1D9, 0x65AC, 0xB1DA, 0x65CF, 0xB1DB, 0x65CB, 0xB1DC, 0x65CC, 0xB1DD, 0x65CE, 0xB1DE, 0x665D, 0xB1DF, 0x665A, 0xB1E0, 0x6664, 0xB1E1, 0x6668, 0xB1E2, 0x6666, 0xB1E3, 0x665E, 0xB1E4, 0x66F9, 0xB1E5, 0x52D7, 0xB1E6, 0x671B, 0xB1E7, 0x6881, 0xB1E8, 0x68AF, 0xB1E9, 0x68A2, 0xB1EA, 0x6893, 0xB1EB, 0x68B5, 0xB1EC, 0x687F, 0xB1ED, 0x6876, 0xB1EE, 0x68B1, 0xB1EF, 0x68A7, 0xB1F0, 0x6897, 0xB1F1, 0x68B0, 0xB1F2, 0x6883, 0xB1F3, 0x68C4, 0xB1F4, 0x68AD, 0xB1F5, 0x6886, 0xB1F6, 0x6885, 0xB1F7, 0x6894, 0xB1F8, 0x689D, 0xB1F9, 0x68A8, 0xB1FA, 0x689F, 0xB1FB, 0x68A1, 0xB1FC, 0x6882, 0xB1FD, 0x6B32, 0xB1FE, 0x6BBA, 0xB240, 0x6BEB, 0xB241, 0x6BEC, 0xB242, 0x6C2B, 0xB243, 0x6D8E, 0xB244, 0x6DBC, 0xB245, 0x6DF3, 0xB246, 0x6DD9, 0xB247, 0x6DB2, 0xB248, 0x6DE1, 0xB249, 0x6DCC, 0xB24A, 0x6DE4, 0xB24B, 0x6DFB, 0xB24C, 0x6DFA, 0xB24D, 0x6E05, 0xB24E, 0x6DC7, 0xB24F, 0x6DCB, 0xB250, 0x6DAF, 0xB251, 0x6DD1, 0xB252, 0x6DAE, 0xB253, 0x6DDE, 0xB254, 0x6DF9, 0xB255, 0x6DB8, 0xB256, 0x6DF7, 0xB257, 0x6DF5, 0xB258, 0x6DC5, 0xB259, 0x6DD2, 0xB25A, 0x6E1A, 0xB25B, 0x6DB5, 0xB25C, 0x6DDA, 0xB25D, 0x6DEB, 0xB25E, 0x6DD8, 0xB25F, 0x6DEA, 0xB260, 0x6DF1, 0xB261, 0x6DEE, 0xB262, 0x6DE8, 0xB263, 0x6DC6, 0xB264, 0x6DC4, 0xB265, 0x6DAA, 0xB266, 0x6DEC, 0xB267, 0x6DBF, 0xB268, 0x6DE6, 0xB269, 0x70F9, 0xB26A, 0x7109, 0xB26B, 0x710A, 0xB26C, 0x70FD, 0xB26D, 0x70EF, 0xB26E, 0x723D, 0xB26F, 0x727D, 0xB270, 0x7281, 0xB271, 0x731C, 0xB272, 0x731B, 0xB273, 0x7316, 0xB274, 0x7313, 0xB275, 0x7319, 0xB276, 0x7387, 0xB277, 0x7405, 0xB278, 0x740A, 0xB279, 0x7403, 0xB27A, 0x7406, 0xB27B, 0x73FE, 0xB27C, 0x740D, 0xB27D, 0x74E0, 0xB27E, 0x74F6, 0xB2A1, 0x74F7, 0xB2A2, 0x751C, 0xB2A3, 0x7522, 0xB2A4, 0x7565, 0xB2A5, 0x7566, 0xB2A6, 0x7562, 0xB2A7, 0x7570, 0xB2A8, 0x758F, 0xB2A9, 0x75D4, 0xB2AA, 0x75D5, 0xB2AB, 0x75B5, 0xB2AC, 0x75CA, 0xB2AD, 0x75CD, 0xB2AE, 0x768E, 0xB2AF, 0x76D4, 0xB2B0, 0x76D2, 0xB2B1, 0x76DB, 0xB2B2, 0x7737, 0xB2B3, 0x773E, 0xB2B4, 0x773C, 0xB2B5, 0x7736, 0xB2B6, 0x7738, 0xB2B7, 0x773A, 0xB2B8, 0x786B, 0xB2B9, 0x7843, 0xB2BA, 0x784E, 0xB2BB, 0x7965, 0xB2BC, 0x7968, 0xB2BD, 0x796D, 0xB2BE, 0x79FB, 0xB2BF, 0x7A92, 0xB2C0, 0x7A95, 0xB2C1, 0x7B20, 0xB2C2, 0x7B28, 0xB2C3, 0x7B1B, 0xB2C4, 0x7B2C, 0xB2C5, 0x7B26, 0xB2C6, 0x7B19, 0xB2C7, 0x7B1E, 0xB2C8, 0x7B2E, 0xB2C9, 0x7C92, 0xB2CA, 0x7C97, 0xB2CB, 0x7C95, 0xB2CC, 0x7D46, 0xB2CD, 0x7D43, 0xB2CE, 0x7D71, 0xB2CF, 0x7D2E, 0xB2D0, 0x7D39, 0xB2D1, 0x7D3C, 0xB2D2, 0x7D40, 0xB2D3, 0x7D30, 0xB2D4, 0x7D33, 0xB2D5, 0x7D44, 0xB2D6, 0x7D2F, 0xB2D7, 0x7D42, 0xB2D8, 0x7D32, 0xB2D9, 0x7D31, 0xB2DA, 0x7F3D, 0xB2DB, 0x7F9E, 0xB2DC, 0x7F9A, 0xB2DD, 0x7FCC, 0xB2DE, 0x7FCE, 0xB2DF, 0x7FD2, 0xB2E0, 0x801C, 0xB2E1, 0x804A, 0xB2E2, 0x8046, 0xB2E3, 0x812F, 0xB2E4, 0x8116, 0xB2E5, 0x8123, 0xB2E6, 0x812B, 0xB2E7, 0x8129, 0xB2E8, 0x8130, 0xB2E9, 0x8124, 0xB2EA, 0x8202, 0xB2EB, 0x8235, 0xB2EC, 0x8237, 0xB2ED, 0x8236, 0xB2EE, 0x8239, 0xB2EF, 0x838E, 0xB2F0, 0x839E, 0xB2F1, 0x8398, 0xB2F2, 0x8378, 0xB2F3, 0x83A2, 0xB2F4, 0x8396, 0xB2F5, 0x83BD, 0xB2F6, 0x83AB, 0xB2F7, 0x8392, 0xB2F8, 0x838A, 0xB2F9, 0x8393, 0xB2FA, 0x8389, 0xB2FB, 0x83A0, 0xB2FC, 0x8377, 0xB2FD, 0x837B, 0xB2FE, 0x837C, 0xB340, 0x8386, 0xB341, 0x83A7, 0xB342, 0x8655, 0xB343, 0x5F6A, 0xB344, 0x86C7, 0xB345, 0x86C0, 0xB346, 0x86B6, 0xB347, 0x86C4, 0xB348, 0x86B5, 0xB349, 0x86C6, 0xB34A, 0x86CB, 0xB34B, 0x86B1, 0xB34C, 0x86AF, 0xB34D, 0x86C9, 0xB34E, 0x8853, 0xB34F, 0x889E, 0xB350, 0x8888, 0xB351, 0x88AB, 0xB352, 0x8892, 0xB353, 0x8896, 0xB354, 0x888D, 0xB355, 0x888B, 0xB356, 0x8993, 0xB357, 0x898F, 0xB358, 0x8A2A, 0xB359, 0x8A1D, 0xB35A, 0x8A23, 0xB35B, 0x8A25, 0xB35C, 0x8A31, 0xB35D, 0x8A2D, 0xB35E, 0x8A1F, 0xB35F, 0x8A1B, 0xB360, 0x8A22, 0xB361, 0x8C49, 0xB362, 0x8C5A, 0xB363, 0x8CA9, 0xB364, 0x8CAC, 0xB365, 0x8CAB, 0xB366, 0x8CA8, 0xB367, 0x8CAA, 0xB368, 0x8CA7, 0xB369, 0x8D67, 0xB36A, 0x8D66, 0xB36B, 0x8DBE, 0xB36C, 0x8DBA, 0xB36D, 0x8EDB, 0xB36E, 0x8EDF, 0xB36F, 0x9019, 0xB370, 0x900D, 0xB371, 0x901A, 0xB372, 0x9017, 0xB373, 0x9023, 0xB374, 0x901F, 0xB375, 0x901D, 0xB376, 0x9010, 0xB377, 0x9015, 0xB378, 0x901E, 0xB379, 0x9020, 0xB37A, 0x900F, 0xB37B, 0x9022, 0xB37C, 0x9016, 0xB37D, 0x901B, 0xB37E, 0x9014, 0xB3A1, 0x90E8, 0xB3A2, 0x90ED, 0xB3A3, 0x90FD, 0xB3A4, 0x9157, 0xB3A5, 0x91CE, 0xB3A6, 0x91F5, 0xB3A7, 0x91E6, 0xB3A8, 0x91E3, 0xB3A9, 0x91E7, 0xB3AA, 0x91ED, 0xB3AB, 0x91E9, 0xB3AC, 0x9589, 0xB3AD, 0x966A, 0xB3AE, 0x9675, 0xB3AF, 0x9673, 0xB3B0, 0x9678, 0xB3B1, 0x9670, 0xB3B2, 0x9674, 0xB3B3, 0x9676, 0xB3B4, 0x9677, 0xB3B5, 0x966C, 0xB3B6, 0x96C0, 0xB3B7, 0x96EA, 0xB3B8, 0x96E9, 0xB3B9, 0x7AE0, 0xB3BA, 0x7ADF, 0xB3BB, 0x9802, 0xB3BC, 0x9803, 0xB3BD, 0x9B5A, 0xB3BE, 0x9CE5, 0xB3BF, 0x9E75, 0xB3C0, 0x9E7F, 0xB3C1, 0x9EA5, 0xB3C2, 0x9EBB, 0xB3C3, 0x50A2, 0xB3C4, 0x508D, 0xB3C5, 0x5085, 0xB3C6, 0x5099, 0xB3C7, 0x5091, 0xB3C8, 0x5080, 0xB3C9, 0x5096, 0xB3CA, 0x5098, 0xB3CB, 0x509A, 0xB3CC, 0x6700, 0xB3CD, 0x51F1, 0xB3CE, 0x5272, 0xB3CF, 0x5274, 0xB3D0, 0x5275, 0xB3D1, 0x5269, 0xB3D2, 0x52DE, 0xB3D3, 0x52DD, 0xB3D4, 0x52DB, 0xB3D5, 0x535A, 0xB3D6, 0x53A5, 0xB3D7, 0x557B, 0xB3D8, 0x5580, 0xB3D9, 0x55A7, 0xB3DA, 0x557C, 0xB3DB, 0x558A, 0xB3DC, 0x559D, 0xB3DD, 0x5598, 0xB3DE, 0x5582, 0xB3DF, 0x559C, 0xB3E0, 0x55AA, 0xB3E1, 0x5594, 0xB3E2, 0x5587, 0xB3E3, 0x558B, 0xB3E4, 0x5583, 0xB3E5, 0x55B3, 0xB3E6, 0x55AE, 0xB3E7, 0x559F, 0xB3E8, 0x553E, 0xB3E9, 0x55B2, 0xB3EA, 0x559A, 0xB3EB, 0x55BB, 0xB3EC, 0x55AC, 0xB3ED, 0x55B1, 0xB3EE, 0x557E, 0xB3EF, 0x5589, 0xB3F0, 0x55AB, 0xB3F1, 0x5599, 0xB3F2, 0x570D, 0xB3F3, 0x582F, 0xB3F4, 0x582A, 0xB3F5, 0x5834, 0xB3F6, 0x5824, 0xB3F7, 0x5830, 0xB3F8, 0x5831, 0xB3F9, 0x5821, 0xB3FA, 0x581D, 0xB3FB, 0x5820, 0xB3FC, 0x58F9, 0xB3FD, 0x58FA, 0xB3FE, 0x5960, 0xB440, 0x5A77, 0xB441, 0x5A9A, 0xB442, 0x5A7F, 0xB443, 0x5A92, 0xB444, 0x5A9B, 0xB445, 0x5AA7, 0xB446, 0x5B73, 0xB447, 0x5B71, 0xB448, 0x5BD2, 0xB449, 0x5BCC, 0xB44A, 0x5BD3, 0xB44B, 0x5BD0, 0xB44C, 0x5C0A, 0xB44D, 0x5C0B, 0xB44E, 0x5C31, 0xB44F, 0x5D4C, 0xB450, 0x5D50, 0xB451, 0x5D34, 0xB452, 0x5D47, 0xB453, 0x5DFD, 0xB454, 0x5E45, 0xB455, 0x5E3D, 0xB456, 0x5E40, 0xB457, 0x5E43, 0xB458, 0x5E7E, 0xB459, 0x5ECA, 0xB45A, 0x5EC1, 0xB45B, 0x5EC2, 0xB45C, 0x5EC4, 0xB45D, 0x5F3C, 0xB45E, 0x5F6D, 0xB45F, 0x5FA9, 0xB460, 0x5FAA, 0xB461, 0x5FA8, 0xB462, 0x60D1, 0xB463, 0x60E1, 0xB464, 0x60B2, 0xB465, 0x60B6, 0xB466, 0x60E0, 0xB467, 0x611C, 0xB468, 0x6123, 0xB469, 0x60FA, 0xB46A, 0x6115, 0xB46B, 0x60F0, 0xB46C, 0x60FB, 0xB46D, 0x60F4, 0xB46E, 0x6168, 0xB46F, 0x60F1, 0xB470, 0x610E, 0xB471, 0x60F6, 0xB472, 0x6109, 0xB473, 0x6100, 0xB474, 0x6112, 0xB475, 0x621F, 0xB476, 0x6249, 0xB477, 0x63A3, 0xB478, 0x638C, 0xB479, 0x63CF, 0xB47A, 0x63C0, 0xB47B, 0x63E9, 0xB47C, 0x63C9, 0xB47D, 0x63C6, 0xB47E, 0x63CD, 0xB4A1, 0x63D2, 0xB4A2, 0x63E3, 0xB4A3, 0x63D0, 0xB4A4, 0x63E1, 0xB4A5, 0x63D6, 0xB4A6, 0x63ED, 0xB4A7, 0x63EE, 0xB4A8, 0x6376, 0xB4A9, 0x63F4, 0xB4AA, 0x63EA, 0xB4AB, 0x63DB, 0xB4AC, 0x6452, 0xB4AD, 0x63DA, 0xB4AE, 0x63F9, 0xB4AF, 0x655E, 0xB4B0, 0x6566, 0xB4B1, 0x6562, 0xB4B2, 0x6563, 0xB4B3, 0x6591, 0xB4B4, 0x6590, 0xB4B5, 0x65AF, 0xB4B6, 0x666E, 0xB4B7, 0x6670, 0xB4B8, 0x6674, 0xB4B9, 0x6676, 0xB4BA, 0x666F, 0xB4BB, 0x6691, 0xB4BC, 0x667A, 0xB4BD, 0x667E, 0xB4BE, 0x6677, 0xB4BF, 0x66FE, 0xB4C0, 0x66FF, 0xB4C1, 0x671F, 0xB4C2, 0x671D, 0xB4C3, 0x68FA, 0xB4C4, 0x68D5, 0xB4C5, 0x68E0, 0xB4C6, 0x68D8, 0xB4C7, 0x68D7, 0xB4C8, 0x6905, 0xB4C9, 0x68DF, 0xB4CA, 0x68F5, 0xB4CB, 0x68EE, 0xB4CC, 0x68E7, 0xB4CD, 0x68F9, 0xB4CE, 0x68D2, 0xB4CF, 0x68F2, 0xB4D0, 0x68E3, 0xB4D1, 0x68CB, 0xB4D2, 0x68CD, 0xB4D3, 0x690D, 0xB4D4, 0x6912, 0xB4D5, 0x690E, 0xB4D6, 0x68C9, 0xB4D7, 0x68DA, 0xB4D8, 0x696E, 0xB4D9, 0x68FB, 0xB4DA, 0x6B3E, 0xB4DB, 0x6B3A, 0xB4DC, 0x6B3D, 0xB4DD, 0x6B98, 0xB4DE, 0x6B96, 0xB4DF, 0x6BBC, 0xB4E0, 0x6BEF, 0xB4E1, 0x6C2E, 0xB4E2, 0x6C2F, 0xB4E3, 0x6C2C, 0xB4E4, 0x6E2F, 0xB4E5, 0x6E38, 0xB4E6, 0x6E54, 0xB4E7, 0x6E21, 0xB4E8, 0x6E32, 0xB4E9, 0x6E67, 0xB4EA, 0x6E4A, 0xB4EB, 0x6E20, 0xB4EC, 0x6E25, 0xB4ED, 0x6E23, 0xB4EE, 0x6E1B, 0xB4EF, 0x6E5B, 0xB4F0, 0x6E58, 0xB4F1, 0x6E24, 0xB4F2, 0x6E56, 0xB4F3, 0x6E6E, 0xB4F4, 0x6E2D, 0xB4F5, 0x6E26, 0xB4F6, 0x6E6F, 0xB4F7, 0x6E34, 0xB4F8, 0x6E4D, 0xB4F9, 0x6E3A, 0xB4FA, 0x6E2C, 0xB4FB, 0x6E43, 0xB4FC, 0x6E1D, 0xB4FD, 0x6E3E, 0xB4FE, 0x6ECB, 0xB540, 0x6E89, 0xB541, 0x6E19, 0xB542, 0x6E4E, 0xB543, 0x6E63, 0xB544, 0x6E44, 0xB545, 0x6E72, 0xB546, 0x6E69, 0xB547, 0x6E5F, 0xB548, 0x7119, 0xB549, 0x711A, 0xB54A, 0x7126, 0xB54B, 0x7130, 0xB54C, 0x7121, 0xB54D, 0x7136, 0xB54E, 0x716E, 0xB54F, 0x711C, 0xB550, 0x724C, 0xB551, 0x7284, 0xB552, 0x7280, 0xB553, 0x7336, 0xB554, 0x7325, 0xB555, 0x7334, 0xB556, 0x7329, 0xB557, 0x743A, 0xB558, 0x742A, 0xB559, 0x7433, 0xB55A, 0x7422, 0xB55B, 0x7425, 0xB55C, 0x7435, 0xB55D, 0x7436, 0xB55E, 0x7434, 0xB55F, 0x742F, 0xB560, 0x741B, 0xB561, 0x7426, 0xB562, 0x7428, 0xB563, 0x7525, 0xB564, 0x7526, 0xB565, 0x756B, 0xB566, 0x756A, 0xB567, 0x75E2, 0xB568, 0x75DB, 0xB569, 0x75E3, 0xB56A, 0x75D9, 0xB56B, 0x75D8, 0xB56C, 0x75DE, 0xB56D, 0x75E0, 0xB56E, 0x767B, 0xB56F, 0x767C, 0xB570, 0x7696, 0xB571, 0x7693, 0xB572, 0x76B4, 0xB573, 0x76DC, 0xB574, 0x774F, 0xB575, 0x77ED, 0xB576, 0x785D, 0xB577, 0x786C, 0xB578, 0x786F, 0xB579, 0x7A0D, 0xB57A, 0x7A08, 0xB57B, 0x7A0B, 0xB57C, 0x7A05, 0xB57D, 0x7A00, 0xB57E, 0x7A98, 0xB5A1, 0x7A97, 0xB5A2, 0x7A96, 0xB5A3, 0x7AE5, 0xB5A4, 0x7AE3, 0xB5A5, 0x7B49, 0xB5A6, 0x7B56, 0xB5A7, 0x7B46, 0xB5A8, 0x7B50, 0xB5A9, 0x7B52, 0xB5AA, 0x7B54, 0xB5AB, 0x7B4D, 0xB5AC, 0x7B4B, 0xB5AD, 0x7B4F, 0xB5AE, 0x7B51, 0xB5AF, 0x7C9F, 0xB5B0, 0x7CA5, 0xB5B1, 0x7D5E, 0xB5B2, 0x7D50, 0xB5B3, 0x7D68, 0xB5B4, 0x7D55, 0xB5B5, 0x7D2B, 0xB5B6, 0x7D6E, 0xB5B7, 0x7D72, 0xB5B8, 0x7D61, 0xB5B9, 0x7D66, 0xB5BA, 0x7D62, 0xB5BB, 0x7D70, 0xB5BC, 0x7D73, 0xB5BD, 0x5584, 0xB5BE, 0x7FD4, 0xB5BF, 0x7FD5, 0xB5C0, 0x800B, 0xB5C1, 0x8052, 0xB5C2, 0x8085, 0xB5C3, 0x8155, 0xB5C4, 0x8154, 0xB5C5, 0x814B, 0xB5C6, 0x8151, 0xB5C7, 0x814E, 0xB5C8, 0x8139, 0xB5C9, 0x8146, 0xB5CA, 0x813E, 0xB5CB, 0x814C, 0xB5CC, 0x8153, 0xB5CD, 0x8174, 0xB5CE, 0x8212, 0xB5CF, 0x821C, 0xB5D0, 0x83E9, 0xB5D1, 0x8403, 0xB5D2, 0x83F8, 0xB5D3, 0x840D, 0xB5D4, 0x83E0, 0xB5D5, 0x83C5, 0xB5D6, 0x840B, 0xB5D7, 0x83C1, 0xB5D8, 0x83EF, 0xB5D9, 0x83F1, 0xB5DA, 0x83F4, 0xB5DB, 0x8457, 0xB5DC, 0x840A, 0xB5DD, 0x83F0, 0xB5DE, 0x840C, 0xB5DF, 0x83CC, 0xB5E0, 0x83FD, 0xB5E1, 0x83F2, 0xB5E2, 0x83CA, 0xB5E3, 0x8438, 0xB5E4, 0x840E, 0xB5E5, 0x8404, 0xB5E6, 0x83DC, 0xB5E7, 0x8407, 0xB5E8, 0x83D4, 0xB5E9, 0x83DF, 0xB5EA, 0x865B, 0xB5EB, 0x86DF, 0xB5EC, 0x86D9, 0xB5ED, 0x86ED, 0xB5EE, 0x86D4, 0xB5EF, 0x86DB, 0xB5F0, 0x86E4, 0xB5F1, 0x86D0, 0xB5F2, 0x86DE, 0xB5F3, 0x8857, 0xB5F4, 0x88C1, 0xB5F5, 0x88C2, 0xB5F6, 0x88B1, 0xB5F7, 0x8983, 0xB5F8, 0x8996, 0xB5F9, 0x8A3B, 0xB5FA, 0x8A60, 0xB5FB, 0x8A55, 0xB5FC, 0x8A5E, 0xB5FD, 0x8A3C, 0xB5FE, 0x8A41, 0xB640, 0x8A54, 0xB641, 0x8A5B, 0xB642, 0x8A50, 0xB643, 0x8A46, 0xB644, 0x8A34, 0xB645, 0x8A3A, 0xB646, 0x8A36, 0xB647, 0x8A56, 0xB648, 0x8C61, 0xB649, 0x8C82, 0xB64A, 0x8CAF, 0xB64B, 0x8CBC, 0xB64C, 0x8CB3, 0xB64D, 0x8CBD, 0xB64E, 0x8CC1, 0xB64F, 0x8CBB, 0xB650, 0x8CC0, 0xB651, 0x8CB4, 0xB652, 0x8CB7, 0xB653, 0x8CB6, 0xB654, 0x8CBF, 0xB655, 0x8CB8, 0xB656, 0x8D8A, 0xB657, 0x8D85, 0xB658, 0x8D81, 0xB659, 0x8DCE, 0xB65A, 0x8DDD, 0xB65B, 0x8DCB, 0xB65C, 0x8DDA, 0xB65D, 0x8DD1, 0xB65E, 0x8DCC, 0xB65F, 0x8DDB, 0xB660, 0x8DC6, 0xB661, 0x8EFB, 0xB662, 0x8EF8, 0xB663, 0x8EFC, 0xB664, 0x8F9C, 0xB665, 0x902E, 0xB666, 0x9035, 0xB667, 0x9031, 0xB668, 0x9038, 0xB669, 0x9032, 0xB66A, 0x9036, 0xB66B, 0x9102, 0xB66C, 0x90F5, 0xB66D, 0x9109, 0xB66E, 0x90FE, 0xB66F, 0x9163, 0xB670, 0x9165, 0xB671, 0x91CF, 0xB672, 0x9214, 0xB673, 0x9215, 0xB674, 0x9223, 0xB675, 0x9209, 0xB676, 0x921E, 0xB677, 0x920D, 0xB678, 0x9210, 0xB679, 0x9207, 0xB67A, 0x9211, 0xB67B, 0x9594, 0xB67C, 0x958F, 0xB67D, 0x958B, 0xB67E, 0x9591, 0xB6A1, 0x9593, 0xB6A2, 0x9592, 0xB6A3, 0x958E, 0xB6A4, 0x968A, 0xB6A5, 0x968E, 0xB6A6, 0x968B, 0xB6A7, 0x967D, 0xB6A8, 0x9685, 0xB6A9, 0x9686, 0xB6AA, 0x968D, 0xB6AB, 0x9672, 0xB6AC, 0x9684, 0xB6AD, 0x96C1, 0xB6AE, 0x96C5, 0xB6AF, 0x96C4, 0xB6B0, 0x96C6, 0xB6B1, 0x96C7, 0xB6B2, 0x96EF, 0xB6B3, 0x96F2, 0xB6B4, 0x97CC, 0xB6B5, 0x9805, 0xB6B6, 0x9806, 0xB6B7, 0x9808, 0xB6B8, 0x98E7, 0xB6B9, 0x98EA, 0xB6BA, 0x98EF, 0xB6BB, 0x98E9, 0xB6BC, 0x98F2, 0xB6BD, 0x98ED, 0xB6BE, 0x99AE, 0xB6BF, 0x99AD, 0xB6C0, 0x9EC3, 0xB6C1, 0x9ECD, 0xB6C2, 0x9ED1, 0xB6C3, 0x4E82, 0xB6C4, 0x50AD, 0xB6C5, 0x50B5, 0xB6C6, 0x50B2, 0xB6C7, 0x50B3, 0xB6C8, 0x50C5, 0xB6C9, 0x50BE, 0xB6CA, 0x50AC, 0xB6CB, 0x50B7, 0xB6CC, 0x50BB, 0xB6CD, 0x50AF, 0xB6CE, 0x50C7, 0xB6CF, 0x527F, 0xB6D0, 0x5277, 0xB6D1, 0x527D, 0xB6D2, 0x52DF, 0xB6D3, 0x52E6, 0xB6D4, 0x52E4, 0xB6D5, 0x52E2, 0xB6D6, 0x52E3, 0xB6D7, 0x532F, 0xB6D8, 0x55DF, 0xB6D9, 0x55E8, 0xB6DA, 0x55D3, 0xB6DB, 0x55E6, 0xB6DC, 0x55CE, 0xB6DD, 0x55DC, 0xB6DE, 0x55C7, 0xB6DF, 0x55D1, 0xB6E0, 0x55E3, 0xB6E1, 0x55E4, 0xB6E2, 0x55EF, 0xB6E3, 0x55DA, 0xB6E4, 0x55E1, 0xB6E5, 0x55C5, 0xB6E6, 0x55C6, 0xB6E7, 0x55E5, 0xB6E8, 0x55C9, 0xB6E9, 0x5712, 0xB6EA, 0x5713, 0xB6EB, 0x585E, 0xB6EC, 0x5851, 0xB6ED, 0x5858, 0xB6EE, 0x5857, 0xB6EF, 0x585A, 0xB6F0, 0x5854, 0xB6F1, 0x586B, 0xB6F2, 0x584C, 0xB6F3, 0x586D, 0xB6F4, 0x584A, 0xB6F5, 0x5862, 0xB6F6, 0x5852, 0xB6F7, 0x584B, 0xB6F8, 0x5967, 0xB6F9, 0x5AC1, 0xB6FA, 0x5AC9, 0xB6FB, 0x5ACC, 0xB6FC, 0x5ABE, 0xB6FD, 0x5ABD, 0xB6FE, 0x5ABC, 0xB740, 0x5AB3, 0xB741, 0x5AC2, 0xB742, 0x5AB2, 0xB743, 0x5D69, 0xB744, 0x5D6F, 0xB745, 0x5E4C, 0xB746, 0x5E79, 0xB747, 0x5EC9, 0xB748, 0x5EC8, 0xB749, 0x5F12, 0xB74A, 0x5F59, 0xB74B, 0x5FAC, 0xB74C, 0x5FAE, 0xB74D, 0x611A, 0xB74E, 0x610F, 0xB74F, 0x6148, 0xB750, 0x611F, 0xB751, 0x60F3, 0xB752, 0x611B, 0xB753, 0x60F9, 0xB754, 0x6101, 0xB755, 0x6108, 0xB756, 0x614E, 0xB757, 0x614C, 0xB758, 0x6144, 0xB759, 0x614D, 0xB75A, 0x613E, 0xB75B, 0x6134, 0xB75C, 0x6127, 0xB75D, 0x610D, 0xB75E, 0x6106, 0xB75F, 0x6137, 0xB760, 0x6221, 0xB761, 0x6222, 0xB762, 0x6413, 0xB763, 0x643E, 0xB764, 0x641E, 0xB765, 0x642A, 0xB766, 0x642D, 0xB767, 0x643D, 0xB768, 0x642C, 0xB769, 0x640F, 0xB76A, 0x641C, 0xB76B, 0x6414, 0xB76C, 0x640D, 0xB76D, 0x6436, 0xB76E, 0x6416, 0xB76F, 0x6417, 0xB770, 0x6406, 0xB771, 0x656C, 0xB772, 0x659F, 0xB773, 0x65B0, 0xB774, 0x6697, 0xB775, 0x6689, 0xB776, 0x6687, 0xB777, 0x6688, 0xB778, 0x6696, 0xB779, 0x6684, 0xB77A, 0x6698, 0xB77B, 0x668D, 0xB77C, 0x6703, 0xB77D, 0x6994, 0xB77E, 0x696D, 0xB7A1, 0x695A, 0xB7A2, 0x6977, 0xB7A3, 0x6960, 0xB7A4, 0x6954, 0xB7A5, 0x6975, 0xB7A6, 0x6930, 0xB7A7, 0x6982, 0xB7A8, 0x694A, 0xB7A9, 0x6968, 0xB7AA, 0x696B, 0xB7AB, 0x695E, 0xB7AC, 0x6953, 0xB7AD, 0x6979, 0xB7AE, 0x6986, 0xB7AF, 0x695D, 0xB7B0, 0x6963, 0xB7B1, 0x695B, 0xB7B2, 0x6B47, 0xB7B3, 0x6B72, 0xB7B4, 0x6BC0, 0xB7B5, 0x6BBF, 0xB7B6, 0x6BD3, 0xB7B7, 0x6BFD, 0xB7B8, 0x6EA2, 0xB7B9, 0x6EAF, 0xB7BA, 0x6ED3, 0xB7BB, 0x6EB6, 0xB7BC, 0x6EC2, 0xB7BD, 0x6E90, 0xB7BE, 0x6E9D, 0xB7BF, 0x6EC7, 0xB7C0, 0x6EC5, 0xB7C1, 0x6EA5, 0xB7C2, 0x6E98, 0xB7C3, 0x6EBC, 0xB7C4, 0x6EBA, 0xB7C5, 0x6EAB, 0xB7C6, 0x6ED1, 0xB7C7, 0x6E96, 0xB7C8, 0x6E9C, 0xB7C9, 0x6EC4, 0xB7CA, 0x6ED4, 0xB7CB, 0x6EAA, 0xB7CC, 0x6EA7, 0xB7CD, 0x6EB4, 0xB7CE, 0x714E, 0xB7CF, 0x7159, 0xB7D0, 0x7169, 0xB7D1, 0x7164, 0xB7D2, 0x7149, 0xB7D3, 0x7167, 0xB7D4, 0x715C, 0xB7D5, 0x716C, 0xB7D6, 0x7166, 0xB7D7, 0x714C, 0xB7D8, 0x7165, 0xB7D9, 0x715E, 0xB7DA, 0x7146, 0xB7DB, 0x7168, 0xB7DC, 0x7156, 0xB7DD, 0x723A, 0xB7DE, 0x7252, 0xB7DF, 0x7337, 0xB7E0, 0x7345, 0xB7E1, 0x733F, 0xB7E2, 0x733E, 0xB7E3, 0x746F, 0xB7E4, 0x745A, 0xB7E5, 0x7455, 0xB7E6, 0x745F, 0xB7E7, 0x745E, 0xB7E8, 0x7441, 0xB7E9, 0x743F, 0xB7EA, 0x7459, 0xB7EB, 0x745B, 0xB7EC, 0x745C, 0xB7ED, 0x7576, 0xB7EE, 0x7578, 0xB7EF, 0x7600, 0xB7F0, 0x75F0, 0xB7F1, 0x7601, 0xB7F2, 0x75F2, 0xB7F3, 0x75F1, 0xB7F4, 0x75FA, 0xB7F5, 0x75FF, 0xB7F6, 0x75F4, 0xB7F7, 0x75F3, 0xB7F8, 0x76DE, 0xB7F9, 0x76DF, 0xB7FA, 0x775B, 0xB7FB, 0x776B, 0xB7FC, 0x7766, 0xB7FD, 0x775E, 0xB7FE, 0x7763, 0xB840, 0x7779, 0xB841, 0x776A, 0xB842, 0x776C, 0xB843, 0x775C, 0xB844, 0x7765, 0xB845, 0x7768, 0xB846, 0x7762, 0xB847, 0x77EE, 0xB848, 0x788E, 0xB849, 0x78B0, 0xB84A, 0x7897, 0xB84B, 0x7898, 0xB84C, 0x788C, 0xB84D, 0x7889, 0xB84E, 0x787C, 0xB84F, 0x7891, 0xB850, 0x7893, 0xB851, 0x787F, 0xB852, 0x797A, 0xB853, 0x797F, 0xB854, 0x7981, 0xB855, 0x842C, 0xB856, 0x79BD, 0xB857, 0x7A1C, 0xB858, 0x7A1A, 0xB859, 0x7A20, 0xB85A, 0x7A14, 0xB85B, 0x7A1F, 0xB85C, 0x7A1E, 0xB85D, 0x7A9F, 0xB85E, 0x7AA0, 0xB85F, 0x7B77, 0xB860, 0x7BC0, 0xB861, 0x7B60, 0xB862, 0x7B6E, 0xB863, 0x7B67, 0xB864, 0x7CB1, 0xB865, 0x7CB3, 0xB866, 0x7CB5, 0xB867, 0x7D93, 0xB868, 0x7D79, 0xB869, 0x7D91, 0xB86A, 0x7D81, 0xB86B, 0x7D8F, 0xB86C, 0x7D5B, 0xB86D, 0x7F6E, 0xB86E, 0x7F69, 0xB86F, 0x7F6A, 0xB870, 0x7F72, 0xB871, 0x7FA9, 0xB872, 0x7FA8, 0xB873, 0x7FA4, 0xB874, 0x8056, 0xB875, 0x8058, 0xB876, 0x8086, 0xB877, 0x8084, 0xB878, 0x8171, 0xB879, 0x8170, 0xB87A, 0x8178, 0xB87B, 0x8165, 0xB87C, 0x816E, 0xB87D, 0x8173, 0xB87E, 0x816B, 0xB8A1, 0x8179, 0xB8A2, 0x817A, 0xB8A3, 0x8166, 0xB8A4, 0x8205, 0xB8A5, 0x8247, 0xB8A6, 0x8482, 0xB8A7, 0x8477, 0xB8A8, 0x843D, 0xB8A9, 0x8431, 0xB8AA, 0x8475, 0xB8AB, 0x8466, 0xB8AC, 0x846B, 0xB8AD, 0x8449, 0xB8AE, 0x846C, 0xB8AF, 0x845B, 0xB8B0, 0x843C, 0xB8B1, 0x8435, 0xB8B2, 0x8461, 0xB8B3, 0x8463, 0xB8B4, 0x8469, 0xB8B5, 0x846D, 0xB8B6, 0x8446, 0xB8B7, 0x865E, 0xB8B8, 0x865C, 0xB8B9, 0x865F, 0xB8BA, 0x86F9, 0xB8BB, 0x8713, 0xB8BC, 0x8708, 0xB8BD, 0x8707, 0xB8BE, 0x8700, 0xB8BF, 0x86FE, 0xB8C0, 0x86FB, 0xB8C1, 0x8702, 0xB8C2, 0x8703, 0xB8C3, 0x8706, 0xB8C4, 0x870A, 0xB8C5, 0x8859, 0xB8C6, 0x88DF, 0xB8C7, 0x88D4, 0xB8C8, 0x88D9, 0xB8C9, 0x88DC, 0xB8CA, 0x88D8, 0xB8CB, 0x88DD, 0xB8CC, 0x88E1, 0xB8CD, 0x88CA, 0xB8CE, 0x88D5, 0xB8CF, 0x88D2, 0xB8D0, 0x899C, 0xB8D1, 0x89E3, 0xB8D2, 0x8A6B, 0xB8D3, 0x8A72, 0xB8D4, 0x8A73, 0xB8D5, 0x8A66, 0xB8D6, 0x8A69, 0xB8D7, 0x8A70, 0xB8D8, 0x8A87, 0xB8D9, 0x8A7C, 0xB8DA, 0x8A63, 0xB8DB, 0x8AA0, 0xB8DC, 0x8A71, 0xB8DD, 0x8A85, 0xB8DE, 0x8A6D, 0xB8DF, 0x8A62, 0xB8E0, 0x8A6E, 0xB8E1, 0x8A6C, 0xB8E2, 0x8A79, 0xB8E3, 0x8A7B, 0xB8E4, 0x8A3E, 0xB8E5, 0x8A68, 0xB8E6, 0x8C62, 0xB8E7, 0x8C8A, 0xB8E8, 0x8C89, 0xB8E9, 0x8CCA, 0xB8EA, 0x8CC7, 0xB8EB, 0x8CC8, 0xB8EC, 0x8CC4, 0xB8ED, 0x8CB2, 0xB8EE, 0x8CC3, 0xB8EF, 0x8CC2, 0xB8F0, 0x8CC5, 0xB8F1, 0x8DE1, 0xB8F2, 0x8DDF, 0xB8F3, 0x8DE8, 0xB8F4, 0x8DEF, 0xB8F5, 0x8DF3, 0xB8F6, 0x8DFA, 0xB8F7, 0x8DEA, 0xB8F8, 0x8DE4, 0xB8F9, 0x8DE6, 0xB8FA, 0x8EB2, 0xB8FB, 0x8F03, 0xB8FC, 0x8F09, 0xB8FD, 0x8EFE, 0xB8FE, 0x8F0A, 0xB940, 0x8F9F, 0xB941, 0x8FB2, 0xB942, 0x904B, 0xB943, 0x904A, 0xB944, 0x9053, 0xB945, 0x9042, 0xB946, 0x9054, 0xB947, 0x903C, 0xB948, 0x9055, 0xB949, 0x9050, 0xB94A, 0x9047, 0xB94B, 0x904F, 0xB94C, 0x904E, 0xB94D, 0x904D, 0xB94E, 0x9051, 0xB94F, 0x903E, 0xB950, 0x9041, 0xB951, 0x9112, 0xB952, 0x9117, 0xB953, 0x916C, 0xB954, 0x916A, 0xB955, 0x9169, 0xB956, 0x91C9, 0xB957, 0x9237, 0xB958, 0x9257, 0xB959, 0x9238, 0xB95A, 0x923D, 0xB95B, 0x9240, 0xB95C, 0x923E, 0xB95D, 0x925B, 0xB95E, 0x924B, 0xB95F, 0x9264, 0xB960, 0x9251, 0xB961, 0x9234, 0xB962, 0x9249, 0xB963, 0x924D, 0xB964, 0x9245, 0xB965, 0x9239, 0xB966, 0x923F, 0xB967, 0x925A, 0xB968, 0x9598, 0xB969, 0x9698, 0xB96A, 0x9694, 0xB96B, 0x9695, 0xB96C, 0x96CD, 0xB96D, 0x96CB, 0xB96E, 0x96C9, 0xB96F, 0x96CA, 0xB970, 0x96F7, 0xB971, 0x96FB, 0xB972, 0x96F9, 0xB973, 0x96F6, 0xB974, 0x9756, 0xB975, 0x9774, 0xB976, 0x9776, 0xB977, 0x9810, 0xB978, 0x9811, 0xB979, 0x9813, 0xB97A, 0x980A, 0xB97B, 0x9812, 0xB97C, 0x980C, 0xB97D, 0x98FC, 0xB97E, 0x98F4, 0xB9A1, 0x98FD, 0xB9A2, 0x98FE, 0xB9A3, 0x99B3, 0xB9A4, 0x99B1, 0xB9A5, 0x99B4, 0xB9A6, 0x9AE1, 0xB9A7, 0x9CE9, 0xB9A8, 0x9E82, 0xB9A9, 0x9F0E, 0xB9AA, 0x9F13, 0xB9AB, 0x9F20, 0xB9AC, 0x50E7, 0xB9AD, 0x50EE, 0xB9AE, 0x50E5, 0xB9AF, 0x50D6, 0xB9B0, 0x50ED, 0xB9B1, 0x50DA, 0xB9B2, 0x50D5, 0xB9B3, 0x50CF, 0xB9B4, 0x50D1, 0xB9B5, 0x50F1, 0xB9B6, 0x50CE, 0xB9B7, 0x50E9, 0xB9B8, 0x5162, 0xB9B9, 0x51F3, 0xB9BA, 0x5283, 0xB9BB, 0x5282, 0xB9BC, 0x5331, 0xB9BD, 0x53AD, 0xB9BE, 0x55FE, 0xB9BF, 0x5600, 0xB9C0, 0x561B, 0xB9C1, 0x5617, 0xB9C2, 0x55FD, 0xB9C3, 0x5614, 0xB9C4, 0x5606, 0xB9C5, 0x5609, 0xB9C6, 0x560D, 0xB9C7, 0x560E, 0xB9C8, 0x55F7, 0xB9C9, 0x5616, 0xB9CA, 0x561F, 0xB9CB, 0x5608, 0xB9CC, 0x5610, 0xB9CD, 0x55F6, 0xB9CE, 0x5718, 0xB9CF, 0x5716, 0xB9D0, 0x5875, 0xB9D1, 0x587E, 0xB9D2, 0x5883, 0xB9D3, 0x5893, 0xB9D4, 0x588A, 0xB9D5, 0x5879, 0xB9D6, 0x5885, 0xB9D7, 0x587D, 0xB9D8, 0x58FD, 0xB9D9, 0x5925, 0xB9DA, 0x5922, 0xB9DB, 0x5924, 0xB9DC, 0x596A, 0xB9DD, 0x5969, 0xB9DE, 0x5AE1, 0xB9DF, 0x5AE6, 0xB9E0, 0x5AE9, 0xB9E1, 0x5AD7, 0xB9E2, 0x5AD6, 0xB9E3, 0x5AD8, 0xB9E4, 0x5AE3, 0xB9E5, 0x5B75, 0xB9E6, 0x5BDE, 0xB9E7, 0x5BE7, 0xB9E8, 0x5BE1, 0xB9E9, 0x5BE5, 0xB9EA, 0x5BE6, 0xB9EB, 0x5BE8, 0xB9EC, 0x5BE2, 0xB9ED, 0x5BE4, 0xB9EE, 0x5BDF, 0xB9EF, 0x5C0D, 0xB9F0, 0x5C62, 0xB9F1, 0x5D84, 0xB9F2, 0x5D87, 0xB9F3, 0x5E5B, 0xB9F4, 0x5E63, 0xB9F5, 0x5E55, 0xB9F6, 0x5E57, 0xB9F7, 0x5E54, 0xB9F8, 0x5ED3, 0xB9F9, 0x5ED6, 0xB9FA, 0x5F0A, 0xB9FB, 0x5F46, 0xB9FC, 0x5F70, 0xB9FD, 0x5FB9, 0xB9FE, 0x6147, 0xBA40, 0x613F, 0xBA41, 0x614B, 0xBA42, 0x6177, 0xBA43, 0x6162, 0xBA44, 0x6163, 0xBA45, 0x615F, 0xBA46, 0x615A, 0xBA47, 0x6158, 0xBA48, 0x6175, 0xBA49, 0x622A, 0xBA4A, 0x6487, 0xBA4B, 0x6458, 0xBA4C, 0x6454, 0xBA4D, 0x64A4, 0xBA4E, 0x6478, 0xBA4F, 0x645F, 0xBA50, 0x647A, 0xBA51, 0x6451, 0xBA52, 0x6467, 0xBA53, 0x6434, 0xBA54, 0x646D, 0xBA55, 0x647B, 0xBA56, 0x6572, 0xBA57, 0x65A1, 0xBA58, 0x65D7, 0xBA59, 0x65D6, 0xBA5A, 0x66A2, 0xBA5B, 0x66A8, 0xBA5C, 0x669D, 0xBA5D, 0x699C, 0xBA5E, 0x69A8, 0xBA5F, 0x6995, 0xBA60, 0x69C1, 0xBA61, 0x69AE, 0xBA62, 0x69D3, 0xBA63, 0x69CB, 0xBA64, 0x699B, 0xBA65, 0x69B7, 0xBA66, 0x69BB, 0xBA67, 0x69AB, 0xBA68, 0x69B4, 0xBA69, 0x69D0, 0xBA6A, 0x69CD, 0xBA6B, 0x69AD, 0xBA6C, 0x69CC, 0xBA6D, 0x69A6, 0xBA6E, 0x69C3, 0xBA6F, 0x69A3, 0xBA70, 0x6B49, 0xBA71, 0x6B4C, 0xBA72, 0x6C33, 0xBA73, 0x6F33, 0xBA74, 0x6F14, 0xBA75, 0x6EFE, 0xBA76, 0x6F13, 0xBA77, 0x6EF4, 0xBA78, 0x6F29, 0xBA79, 0x6F3E, 0xBA7A, 0x6F20, 0xBA7B, 0x6F2C, 0xBA7C, 0x6F0F, 0xBA7D, 0x6F02, 0xBA7E, 0x6F22, 0xBAA1, 0x6EFF, 0xBAA2, 0x6EEF, 0xBAA3, 0x6F06, 0xBAA4, 0x6F31, 0xBAA5, 0x6F38, 0xBAA6, 0x6F32, 0xBAA7, 0x6F23, 0xBAA8, 0x6F15, 0xBAA9, 0x6F2B, 0xBAAA, 0x6F2F, 0xBAAB, 0x6F88, 0xBAAC, 0x6F2A, 0xBAAD, 0x6EEC, 0xBAAE, 0x6F01, 0xBAAF, 0x6EF2, 0xBAB0, 0x6ECC, 0xBAB1, 0x6EF7, 0xBAB2, 0x7194, 0xBAB3, 0x7199, 0xBAB4, 0x717D, 0xBAB5, 0x718A, 0xBAB6, 0x7184, 0xBAB7, 0x7192, 0xBAB8, 0x723E, 0xBAB9, 0x7292, 0xBABA, 0x7296, 0xBABB, 0x7344, 0xBABC, 0x7350, 0xBABD, 0x7464, 0xBABE, 0x7463, 0xBABF, 0x746A, 0xBAC0, 0x7470, 0xBAC1, 0x746D, 0xBAC2, 0x7504, 0xBAC3, 0x7591, 0xBAC4, 0x7627, 0xBAC5, 0x760D, 0xBAC6, 0x760B, 0xBAC7, 0x7609, 0xBAC8, 0x7613, 0xBAC9, 0x76E1, 0xBACA, 0x76E3, 0xBACB, 0x7784, 0xBACC, 0x777D, 0xBACD, 0x777F, 0xBACE, 0x7761, 0xBACF, 0x78C1, 0xBAD0, 0x789F, 0xBAD1, 0x78A7, 0xBAD2, 0x78B3, 0xBAD3, 0x78A9, 0xBAD4, 0x78A3, 0xBAD5, 0x798E, 0xBAD6, 0x798F, 0xBAD7, 0x798D, 0xBAD8, 0x7A2E, 0xBAD9, 0x7A31, 0xBADA, 0x7AAA, 0xBADB, 0x7AA9, 0xBADC, 0x7AED, 0xBADD, 0x7AEF, 0xBADE, 0x7BA1, 0xBADF, 0x7B95, 0xBAE0, 0x7B8B, 0xBAE1, 0x7B75, 0xBAE2, 0x7B97, 0xBAE3, 0x7B9D, 0xBAE4, 0x7B94, 0xBAE5, 0x7B8F, 0xBAE6, 0x7BB8, 0xBAE7, 0x7B87, 0xBAE8, 0x7B84, 0xBAE9, 0x7CB9, 0xBAEA, 0x7CBD, 0xBAEB, 0x7CBE, 0xBAEC, 0x7DBB, 0xBAED, 0x7DB0, 0xBAEE, 0x7D9C, 0xBAEF, 0x7DBD, 0xBAF0, 0x7DBE, 0xBAF1, 0x7DA0, 0xBAF2, 0x7DCA, 0xBAF3, 0x7DB4, 0xBAF4, 0x7DB2, 0xBAF5, 0x7DB1, 0xBAF6, 0x7DBA, 0xBAF7, 0x7DA2, 0xBAF8, 0x7DBF, 0xBAF9, 0x7DB5, 0xBAFA, 0x7DB8, 0xBAFB, 0x7DAD, 0xBAFC, 0x7DD2, 0xBAFD, 0x7DC7, 0xBAFE, 0x7DAC, 0xBB40, 0x7F70, 0xBB41, 0x7FE0, 0xBB42, 0x7FE1, 0xBB43, 0x7FDF, 0xBB44, 0x805E, 0xBB45, 0x805A, 0xBB46, 0x8087, 0xBB47, 0x8150, 0xBB48, 0x8180, 0xBB49, 0x818F, 0xBB4A, 0x8188, 0xBB4B, 0x818A, 0xBB4C, 0x817F, 0xBB4D, 0x8182, 0xBB4E, 0x81E7, 0xBB4F, 0x81FA, 0xBB50, 0x8207, 0xBB51, 0x8214, 0xBB52, 0x821E, 0xBB53, 0x824B, 0xBB54, 0x84C9, 0xBB55, 0x84BF, 0xBB56, 0x84C6, 0xBB57, 0x84C4, 0xBB58, 0x8499, 0xBB59, 0x849E, 0xBB5A, 0x84B2, 0xBB5B, 0x849C, 0xBB5C, 0x84CB, 0xBB5D, 0x84B8, 0xBB5E, 0x84C0, 0xBB5F, 0x84D3, 0xBB60, 0x8490, 0xBB61, 0x84BC, 0xBB62, 0x84D1, 0xBB63, 0x84CA, 0xBB64, 0x873F, 0xBB65, 0x871C, 0xBB66, 0x873B, 0xBB67, 0x8722, 0xBB68, 0x8725, 0xBB69, 0x8734, 0xBB6A, 0x8718, 0xBB6B, 0x8755, 0xBB6C, 0x8737, 0xBB6D, 0x8729, 0xBB6E, 0x88F3, 0xBB6F, 0x8902, 0xBB70, 0x88F4, 0xBB71, 0x88F9, 0xBB72, 0x88F8, 0xBB73, 0x88FD, 0xBB74, 0x88E8, 0xBB75, 0x891A, 0xBB76, 0x88EF, 0xBB77, 0x8AA6, 0xBB78, 0x8A8C, 0xBB79, 0x8A9E, 0xBB7A, 0x8AA3, 0xBB7B, 0x8A8D, 0xBB7C, 0x8AA1, 0xBB7D, 0x8A93, 0xBB7E, 0x8AA4, 0xBBA1, 0x8AAA, 0xBBA2, 0x8AA5, 0xBBA3, 0x8AA8, 0xBBA4, 0x8A98, 0xBBA5, 0x8A91, 0xBBA6, 0x8A9A, 0xBBA7, 0x8AA7, 0xBBA8, 0x8C6A, 0xBBA9, 0x8C8D, 0xBBAA, 0x8C8C, 0xBBAB, 0x8CD3, 0xBBAC, 0x8CD1, 0xBBAD, 0x8CD2, 0xBBAE, 0x8D6B, 0xBBAF, 0x8D99, 0xBBB0, 0x8D95, 0xBBB1, 0x8DFC, 0xBBB2, 0x8F14, 0xBBB3, 0x8F12, 0xBBB4, 0x8F15, 0xBBB5, 0x8F13, 0xBBB6, 0x8FA3, 0xBBB7, 0x9060, 0xBBB8, 0x9058, 0xBBB9, 0x905C, 0xBBBA, 0x9063, 0xBBBB, 0x9059, 0xBBBC, 0x905E, 0xBBBD, 0x9062, 0xBBBE, 0x905D, 0xBBBF, 0x905B, 0xBBC0, 0x9119, 0xBBC1, 0x9118, 0xBBC2, 0x911E, 0xBBC3, 0x9175, 0xBBC4, 0x9178, 0xBBC5, 0x9177, 0xBBC6, 0x9174, 0xBBC7, 0x9278, 0xBBC8, 0x9280, 0xBBC9, 0x9285, 0xBBCA, 0x9298, 0xBBCB, 0x9296, 0xBBCC, 0x927B, 0xBBCD, 0x9293, 0xBBCE, 0x929C, 0xBBCF, 0x92A8, 0xBBD0, 0x927C, 0xBBD1, 0x9291, 0xBBD2, 0x95A1, 0xBBD3, 0x95A8, 0xBBD4, 0x95A9, 0xBBD5, 0x95A3, 0xBBD6, 0x95A5, 0xBBD7, 0x95A4, 0xBBD8, 0x9699, 0xBBD9, 0x969C, 0xBBDA, 0x969B, 0xBBDB, 0x96CC, 0xBBDC, 0x96D2, 0xBBDD, 0x9700, 0xBBDE, 0x977C, 0xBBDF, 0x9785, 0xBBE0, 0x97F6, 0xBBE1, 0x9817, 0xBBE2, 0x9818, 0xBBE3, 0x98AF, 0xBBE4, 0x98B1, 0xBBE5, 0x9903, 0xBBE6, 0x9905, 0xBBE7, 0x990C, 0xBBE8, 0x9909, 0xBBE9, 0x99C1, 0xBBEA, 0x9AAF, 0xBBEB, 0x9AB0, 0xBBEC, 0x9AE6, 0xBBED, 0x9B41, 0xBBEE, 0x9B42, 0xBBEF, 0x9CF4, 0xBBF0, 0x9CF6, 0xBBF1, 0x9CF3, 0xBBF2, 0x9EBC, 0xBBF3, 0x9F3B, 0xBBF4, 0x9F4A, 0xBBF5, 0x5104, 0xBBF6, 0x5100, 0xBBF7, 0x50FB, 0xBBF8, 0x50F5, 0xBBF9, 0x50F9, 0xBBFA, 0x5102, 0xBBFB, 0x5108, 0xBBFC, 0x5109, 0xBBFD, 0x5105, 0xBBFE, 0x51DC, 0xBC40, 0x5287, 0xBC41, 0x5288, 0xBC42, 0x5289, 0xBC43, 0x528D, 0xBC44, 0x528A, 0xBC45, 0x52F0, 0xBC46, 0x53B2, 0xBC47, 0x562E, 0xBC48, 0x563B, 0xBC49, 0x5639, 0xBC4A, 0x5632, 0xBC4B, 0x563F, 0xBC4C, 0x5634, 0xBC4D, 0x5629, 0xBC4E, 0x5653, 0xBC4F, 0x564E, 0xBC50, 0x5657, 0xBC51, 0x5674, 0xBC52, 0x5636, 0xBC53, 0x562F, 0xBC54, 0x5630, 0xBC55, 0x5880, 0xBC56, 0x589F, 0xBC57, 0x589E, 0xBC58, 0x58B3, 0xBC59, 0x589C, 0xBC5A, 0x58AE, 0xBC5B, 0x58A9, 0xBC5C, 0x58A6, 0xBC5D, 0x596D, 0xBC5E, 0x5B09, 0xBC5F, 0x5AFB, 0xBC60, 0x5B0B, 0xBC61, 0x5AF5, 0xBC62, 0x5B0C, 0xBC63, 0x5B08, 0xBC64, 0x5BEE, 0xBC65, 0x5BEC, 0xBC66, 0x5BE9, 0xBC67, 0x5BEB, 0xBC68, 0x5C64, 0xBC69, 0x5C65, 0xBC6A, 0x5D9D, 0xBC6B, 0x5D94, 0xBC6C, 0x5E62, 0xBC6D, 0x5E5F, 0xBC6E, 0x5E61, 0xBC6F, 0x5EE2, 0xBC70, 0x5EDA, 0xBC71, 0x5EDF, 0xBC72, 0x5EDD, 0xBC73, 0x5EE3, 0xBC74, 0x5EE0, 0xBC75, 0x5F48, 0xBC76, 0x5F71, 0xBC77, 0x5FB7, 0xBC78, 0x5FB5, 0xBC79, 0x6176, 0xBC7A, 0x6167, 0xBC7B, 0x616E, 0xBC7C, 0x615D, 0xBC7D, 0x6155, 0xBC7E, 0x6182, 0xBCA1, 0x617C, 0xBCA2, 0x6170, 0xBCA3, 0x616B, 0xBCA4, 0x617E, 0xBCA5, 0x61A7, 0xBCA6, 0x6190, 0xBCA7, 0x61AB, 0xBCA8, 0x618E, 0xBCA9, 0x61AC, 0xBCAA, 0x619A, 0xBCAB, 0x61A4, 0xBCAC, 0x6194, 0xBCAD, 0x61AE, 0xBCAE, 0x622E, 0xBCAF, 0x6469, 0xBCB0, 0x646F, 0xBCB1, 0x6479, 0xBCB2, 0x649E, 0xBCB3, 0x64B2, 0xBCB4, 0x6488, 0xBCB5, 0x6490, 0xBCB6, 0x64B0, 0xBCB7, 0x64A5, 0xBCB8, 0x6493, 0xBCB9, 0x6495, 0xBCBA, 0x64A9, 0xBCBB, 0x6492, 0xBCBC, 0x64AE, 0xBCBD, 0x64AD, 0xBCBE, 0x64AB, 0xBCBF, 0x649A, 0xBCC0, 0x64AC, 0xBCC1, 0x6499, 0xBCC2, 0x64A2, 0xBCC3, 0x64B3, 0xBCC4, 0x6575, 0xBCC5, 0x6577, 0xBCC6, 0x6578, 0xBCC7, 0x66AE, 0xBCC8, 0x66AB, 0xBCC9, 0x66B4, 0xBCCA, 0x66B1, 0xBCCB, 0x6A23, 0xBCCC, 0x6A1F, 0xBCCD, 0x69E8, 0xBCCE, 0x6A01, 0xBCCF, 0x6A1E, 0xBCD0, 0x6A19, 0xBCD1, 0x69FD, 0xBCD2, 0x6A21, 0xBCD3, 0x6A13, 0xBCD4, 0x6A0A, 0xBCD5, 0x69F3, 0xBCD6, 0x6A02, 0xBCD7, 0x6A05, 0xBCD8, 0x69ED, 0xBCD9, 0x6A11, 0xBCDA, 0x6B50, 0xBCDB, 0x6B4E, 0xBCDC, 0x6BA4, 0xBCDD, 0x6BC5, 0xBCDE, 0x6BC6, 0xBCDF, 0x6F3F, 0xBCE0, 0x6F7C, 0xBCE1, 0x6F84, 0xBCE2, 0x6F51, 0xBCE3, 0x6F66, 0xBCE4, 0x6F54, 0xBCE5, 0x6F86, 0xBCE6, 0x6F6D, 0xBCE7, 0x6F5B, 0xBCE8, 0x6F78, 0xBCE9, 0x6F6E, 0xBCEA, 0x6F8E, 0xBCEB, 0x6F7A, 0xBCEC, 0x6F70, 0xBCED, 0x6F64, 0xBCEE, 0x6F97, 0xBCEF, 0x6F58, 0xBCF0, 0x6ED5, 0xBCF1, 0x6F6F, 0xBCF2, 0x6F60, 0xBCF3, 0x6F5F, 0xBCF4, 0x719F, 0xBCF5, 0x71AC, 0xBCF6, 0x71B1, 0xBCF7, 0x71A8, 0xBCF8, 0x7256, 0xBCF9, 0x729B, 0xBCFA, 0x734E, 0xBCFB, 0x7357, 0xBCFC, 0x7469, 0xBCFD, 0x748B, 0xBCFE, 0x7483, 0xBD40, 0x747E, 0xBD41, 0x7480, 0xBD42, 0x757F, 0xBD43, 0x7620, 0xBD44, 0x7629, 0xBD45, 0x761F, 0xBD46, 0x7624, 0xBD47, 0x7626, 0xBD48, 0x7621, 0xBD49, 0x7622, 0xBD4A, 0x769A, 0xBD4B, 0x76BA, 0xBD4C, 0x76E4, 0xBD4D, 0x778E, 0xBD4E, 0x7787, 0xBD4F, 0x778C, 0xBD50, 0x7791, 0xBD51, 0x778B, 0xBD52, 0x78CB, 0xBD53, 0x78C5, 0xBD54, 0x78BA, 0xBD55, 0x78CA, 0xBD56, 0x78BE, 0xBD57, 0x78D5, 0xBD58, 0x78BC, 0xBD59, 0x78D0, 0xBD5A, 0x7A3F, 0xBD5B, 0x7A3C, 0xBD5C, 0x7A40, 0xBD5D, 0x7A3D, 0xBD5E, 0x7A37, 0xBD5F, 0x7A3B, 0xBD60, 0x7AAF, 0xBD61, 0x7AAE, 0xBD62, 0x7BAD, 0xBD63, 0x7BB1, 0xBD64, 0x7BC4, 0xBD65, 0x7BB4, 0xBD66, 0x7BC6, 0xBD67, 0x7BC7, 0xBD68, 0x7BC1, 0xBD69, 0x7BA0, 0xBD6A, 0x7BCC, 0xBD6B, 0x7CCA, 0xBD6C, 0x7DE0, 0xBD6D, 0x7DF4, 0xBD6E, 0x7DEF, 0xBD6F, 0x7DFB, 0xBD70, 0x7DD8, 0xBD71, 0x7DEC, 0xBD72, 0x7DDD, 0xBD73, 0x7DE8, 0xBD74, 0x7DE3, 0xBD75, 0x7DDA, 0xBD76, 0x7DDE, 0xBD77, 0x7DE9, 0xBD78, 0x7D9E, 0xBD79, 0x7DD9, 0xBD7A, 0x7DF2, 0xBD7B, 0x7DF9, 0xBD7C, 0x7F75, 0xBD7D, 0x7F77, 0xBD7E, 0x7FAF, 0xBDA1, 0x7FE9, 0xBDA2, 0x8026, 0xBDA3, 0x819B, 0xBDA4, 0x819C, 0xBDA5, 0x819D, 0xBDA6, 0x81A0, 0xBDA7, 0x819A, 0xBDA8, 0x8198, 0xBDA9, 0x8517, 0xBDAA, 0x853D, 0xBDAB, 0x851A, 0xBDAC, 0x84EE, 0xBDAD, 0x852C, 0xBDAE, 0x852D, 0xBDAF, 0x8513, 0xBDB0, 0x8511, 0xBDB1, 0x8523, 0xBDB2, 0x8521, 0xBDB3, 0x8514, 0xBDB4, 0x84EC, 0xBDB5, 0x8525, 0xBDB6, 0x84FF, 0xBDB7, 0x8506, 0xBDB8, 0x8782, 0xBDB9, 0x8774, 0xBDBA, 0x8776, 0xBDBB, 0x8760, 0xBDBC, 0x8766, 0xBDBD, 0x8778, 0xBDBE, 0x8768, 0xBDBF, 0x8759, 0xBDC0, 0x8757, 0xBDC1, 0x874C, 0xBDC2, 0x8753, 0xBDC3, 0x885B, 0xBDC4, 0x885D, 0xBDC5, 0x8910, 0xBDC6, 0x8907, 0xBDC7, 0x8912, 0xBDC8, 0x8913, 0xBDC9, 0x8915, 0xBDCA, 0x890A, 0xBDCB, 0x8ABC, 0xBDCC, 0x8AD2, 0xBDCD, 0x8AC7, 0xBDCE, 0x8AC4, 0xBDCF, 0x8A95, 0xBDD0, 0x8ACB, 0xBDD1, 0x8AF8, 0xBDD2, 0x8AB2, 0xBDD3, 0x8AC9, 0xBDD4, 0x8AC2, 0xBDD5, 0x8ABF, 0xBDD6, 0x8AB0, 0xBDD7, 0x8AD6, 0xBDD8, 0x8ACD, 0xBDD9, 0x8AB6, 0xBDDA, 0x8AB9, 0xBDDB, 0x8ADB, 0xBDDC, 0x8C4C, 0xBDDD, 0x8C4E, 0xBDDE, 0x8C6C, 0xBDDF, 0x8CE0, 0xBDE0, 0x8CDE, 0xBDE1, 0x8CE6, 0xBDE2, 0x8CE4, 0xBDE3, 0x8CEC, 0xBDE4, 0x8CED, 0xBDE5, 0x8CE2, 0xBDE6, 0x8CE3, 0xBDE7, 0x8CDC, 0xBDE8, 0x8CEA, 0xBDE9, 0x8CE1, 0xBDEA, 0x8D6D, 0xBDEB, 0x8D9F, 0xBDEC, 0x8DA3, 0xBDED, 0x8E2B, 0xBDEE, 0x8E10, 0xBDEF, 0x8E1D, 0xBDF0, 0x8E22, 0xBDF1, 0x8E0F, 0xBDF2, 0x8E29, 0xBDF3, 0x8E1F, 0xBDF4, 0x8E21, 0xBDF5, 0x8E1E, 0xBDF6, 0x8EBA, 0xBDF7, 0x8F1D, 0xBDF8, 0x8F1B, 0xBDF9, 0x8F1F, 0xBDFA, 0x8F29, 0xBDFB, 0x8F26, 0xBDFC, 0x8F2A, 0xBDFD, 0x8F1C, 0xBDFE, 0x8F1E, 0xBE40, 0x8F25, 0xBE41, 0x9069, 0xBE42, 0x906E, 0xBE43, 0x9068, 0xBE44, 0x906D, 0xBE45, 0x9077, 0xBE46, 0x9130, 0xBE47, 0x912D, 0xBE48, 0x9127, 0xBE49, 0x9131, 0xBE4A, 0x9187, 0xBE4B, 0x9189, 0xBE4C, 0x918B, 0xBE4D, 0x9183, 0xBE4E, 0x92C5, 0xBE4F, 0x92BB, 0xBE50, 0x92B7, 0xBE51, 0x92EA, 0xBE52, 0x92AC, 0xBE53, 0x92E4, 0xBE54, 0x92C1, 0xBE55, 0x92B3, 0xBE56, 0x92BC, 0xBE57, 0x92D2, 0xBE58, 0x92C7, 0xBE59, 0x92F0, 0xBE5A, 0x92B2, 0xBE5B, 0x95AD, 0xBE5C, 0x95B1, 0xBE5D, 0x9704, 0xBE5E, 0x9706, 0xBE5F, 0x9707, 0xBE60, 0x9709, 0xBE61, 0x9760, 0xBE62, 0x978D, 0xBE63, 0x978B, 0xBE64, 0x978F, 0xBE65, 0x9821, 0xBE66, 0x982B, 0xBE67, 0x981C, 0xBE68, 0x98B3, 0xBE69, 0x990A, 0xBE6A, 0x9913, 0xBE6B, 0x9912, 0xBE6C, 0x9918, 0xBE6D, 0x99DD, 0xBE6E, 0x99D0, 0xBE6F, 0x99DF, 0xBE70, 0x99DB, 0xBE71, 0x99D1, 0xBE72, 0x99D5, 0xBE73, 0x99D2, 0xBE74, 0x99D9, 0xBE75, 0x9AB7, 0xBE76, 0x9AEE, 0xBE77, 0x9AEF, 0xBE78, 0x9B27, 0xBE79, 0x9B45, 0xBE7A, 0x9B44, 0xBE7B, 0x9B77, 0xBE7C, 0x9B6F, 0xBE7D, 0x9D06, 0xBE7E, 0x9D09, 0xBEA1, 0x9D03, 0xBEA2, 0x9EA9, 0xBEA3, 0x9EBE, 0xBEA4, 0x9ECE, 0xBEA5, 0x58A8, 0xBEA6, 0x9F52, 0xBEA7, 0x5112, 0xBEA8, 0x5118, 0xBEA9, 0x5114, 0xBEAA, 0x5110, 0xBEAB, 0x5115, 0xBEAC, 0x5180, 0xBEAD, 0x51AA, 0xBEAE, 0x51DD, 0xBEAF, 0x5291, 0xBEB0, 0x5293, 0xBEB1, 0x52F3, 0xBEB2, 0x5659, 0xBEB3, 0x566B, 0xBEB4, 0x5679, 0xBEB5, 0x5669, 0xBEB6, 0x5664, 0xBEB7, 0x5678, 0xBEB8, 0x566A, 0xBEB9, 0x5668, 0xBEBA, 0x5665, 0xBEBB, 0x5671, 0xBEBC, 0x566F, 0xBEBD, 0x566C, 0xBEBE, 0x5662, 0xBEBF, 0x5676, 0xBEC0, 0x58C1, 0xBEC1, 0x58BE, 0xBEC2, 0x58C7, 0xBEC3, 0x58C5, 0xBEC4, 0x596E, 0xBEC5, 0x5B1D, 0xBEC6, 0x5B34, 0xBEC7, 0x5B78, 0xBEC8, 0x5BF0, 0xBEC9, 0x5C0E, 0xBECA, 0x5F4A, 0xBECB, 0x61B2, 0xBECC, 0x6191, 0xBECD, 0x61A9, 0xBECE, 0x618A, 0xBECF, 0x61CD, 0xBED0, 0x61B6, 0xBED1, 0x61BE, 0xBED2, 0x61CA, 0xBED3, 0x61C8, 0xBED4, 0x6230, 0xBED5, 0x64C5, 0xBED6, 0x64C1, 0xBED7, 0x64CB, 0xBED8, 0x64BB, 0xBED9, 0x64BC, 0xBEDA, 0x64DA, 0xBEDB, 0x64C4, 0xBEDC, 0x64C7, 0xBEDD, 0x64C2, 0xBEDE, 0x64CD, 0xBEDF, 0x64BF, 0xBEE0, 0x64D2, 0xBEE1, 0x64D4, 0xBEE2, 0x64BE, 0xBEE3, 0x6574, 0xBEE4, 0x66C6, 0xBEE5, 0x66C9, 0xBEE6, 0x66B9, 0xBEE7, 0x66C4, 0xBEE8, 0x66C7, 0xBEE9, 0x66B8, 0xBEEA, 0x6A3D, 0xBEEB, 0x6A38, 0xBEEC, 0x6A3A, 0xBEED, 0x6A59, 0xBEEE, 0x6A6B, 0xBEEF, 0x6A58, 0xBEF0, 0x6A39, 0xBEF1, 0x6A44, 0xBEF2, 0x6A62, 0xBEF3, 0x6A61, 0xBEF4, 0x6A4B, 0xBEF5, 0x6A47, 0xBEF6, 0x6A35, 0xBEF7, 0x6A5F, 0xBEF8, 0x6A48, 0xBEF9, 0x6B59, 0xBEFA, 0x6B77, 0xBEFB, 0x6C05, 0xBEFC, 0x6FC2, 0xBEFD, 0x6FB1, 0xBEFE, 0x6FA1, 0xBF40, 0x6FC3, 0xBF41, 0x6FA4, 0xBF42, 0x6FC1, 0xBF43, 0x6FA7, 0xBF44, 0x6FB3, 0xBF45, 0x6FC0, 0xBF46, 0x6FB9, 0xBF47, 0x6FB6, 0xBF48, 0x6FA6, 0xBF49, 0x6FA0, 0xBF4A, 0x6FB4, 0xBF4B, 0x71BE, 0xBF4C, 0x71C9, 0xBF4D, 0x71D0, 0xBF4E, 0x71D2, 0xBF4F, 0x71C8, 0xBF50, 0x71D5, 0xBF51, 0x71B9, 0xBF52, 0x71CE, 0xBF53, 0x71D9, 0xBF54, 0x71DC, 0xBF55, 0x71C3, 0xBF56, 0x71C4, 0xBF57, 0x7368, 0xBF58, 0x749C, 0xBF59, 0x74A3, 0xBF5A, 0x7498, 0xBF5B, 0x749F, 0xBF5C, 0x749E, 0xBF5D, 0x74E2, 0xBF5E, 0x750C, 0xBF5F, 0x750D, 0xBF60, 0x7634, 0xBF61, 0x7638, 0xBF62, 0x763A, 0xBF63, 0x76E7, 0xBF64, 0x76E5, 0xBF65, 0x77A0, 0xBF66, 0x779E, 0xBF67, 0x779F, 0xBF68, 0x77A5, 0xBF69, 0x78E8, 0xBF6A, 0x78DA, 0xBF6B, 0x78EC, 0xBF6C, 0x78E7, 0xBF6D, 0x79A6, 0xBF6E, 0x7A4D, 0xBF6F, 0x7A4E, 0xBF70, 0x7A46, 0xBF71, 0x7A4C, 0xBF72, 0x7A4B, 0xBF73, 0x7ABA, 0xBF74, 0x7BD9, 0xBF75, 0x7C11, 0xBF76, 0x7BC9, 0xBF77, 0x7BE4, 0xBF78, 0x7BDB, 0xBF79, 0x7BE1, 0xBF7A, 0x7BE9, 0xBF7B, 0x7BE6, 0xBF7C, 0x7CD5, 0xBF7D, 0x7CD6, 0xBF7E, 0x7E0A, 0xBFA1, 0x7E11, 0xBFA2, 0x7E08, 0xBFA3, 0x7E1B, 0xBFA4, 0x7E23, 0xBFA5, 0x7E1E, 0xBFA6, 0x7E1D, 0xBFA7, 0x7E09, 0xBFA8, 0x7E10, 0xBFA9, 0x7F79, 0xBFAA, 0x7FB2, 0xBFAB, 0x7FF0, 0xBFAC, 0x7FF1, 0xBFAD, 0x7FEE, 0xBFAE, 0x8028, 0xBFAF, 0x81B3, 0xBFB0, 0x81A9, 0xBFB1, 0x81A8, 0xBFB2, 0x81FB, 0xBFB3, 0x8208, 0xBFB4, 0x8258, 0xBFB5, 0x8259, 0xBFB6, 0x854A, 0xBFB7, 0x8559, 0xBFB8, 0x8548, 0xBFB9, 0x8568, 0xBFBA, 0x8569, 0xBFBB, 0x8543, 0xBFBC, 0x8549, 0xBFBD, 0x856D, 0xBFBE, 0x856A, 0xBFBF, 0x855E, 0xBFC0, 0x8783, 0xBFC1, 0x879F, 0xBFC2, 0x879E, 0xBFC3, 0x87A2, 0xBFC4, 0x878D, 0xBFC5, 0x8861, 0xBFC6, 0x892A, 0xBFC7, 0x8932, 0xBFC8, 0x8925, 0xBFC9, 0x892B, 0xBFCA, 0x8921, 0xBFCB, 0x89AA, 0xBFCC, 0x89A6, 0xBFCD, 0x8AE6, 0xBFCE, 0x8AFA, 0xBFCF, 0x8AEB, 0xBFD0, 0x8AF1, 0xBFD1, 0x8B00, 0xBFD2, 0x8ADC, 0xBFD3, 0x8AE7, 0xBFD4, 0x8AEE, 0xBFD5, 0x8AFE, 0xBFD6, 0x8B01, 0xBFD7, 0x8B02, 0xBFD8, 0x8AF7, 0xBFD9, 0x8AED, 0xBFDA, 0x8AF3, 0xBFDB, 0x8AF6, 0xBFDC, 0x8AFC, 0xBFDD, 0x8C6B, 0xBFDE, 0x8C6D, 0xBFDF, 0x8C93, 0xBFE0, 0x8CF4, 0xBFE1, 0x8E44, 0xBFE2, 0x8E31, 0xBFE3, 0x8E34, 0xBFE4, 0x8E42, 0xBFE5, 0x8E39, 0xBFE6, 0x8E35, 0xBFE7, 0x8F3B, 0xBFE8, 0x8F2F, 0xBFE9, 0x8F38, 0xBFEA, 0x8F33, 0xBFEB, 0x8FA8, 0xBFEC, 0x8FA6, 0xBFED, 0x9075, 0xBFEE, 0x9074, 0xBFEF, 0x9078, 0xBFF0, 0x9072, 0xBFF1, 0x907C, 0xBFF2, 0x907A, 0xBFF3, 0x9134, 0xBFF4, 0x9192, 0xBFF5, 0x9320, 0xBFF6, 0x9336, 0xBFF7, 0x92F8, 0xBFF8, 0x9333, 0xBFF9, 0x932F, 0xBFFA, 0x9322, 0xBFFB, 0x92FC, 0xBFFC, 0x932B, 0xBFFD, 0x9304, 0xBFFE, 0x931A, 0xC040, 0x9310, 0xC041, 0x9326, 0xC042, 0x9321, 0xC043, 0x9315, 0xC044, 0x932E, 0xC045, 0x9319, 0xC046, 0x95BB, 0xC047, 0x96A7, 0xC048, 0x96A8, 0xC049, 0x96AA, 0xC04A, 0x96D5, 0xC04B, 0x970E, 0xC04C, 0x9711, 0xC04D, 0x9716, 0xC04E, 0x970D, 0xC04F, 0x9713, 0xC050, 0x970F, 0xC051, 0x975B, 0xC052, 0x975C, 0xC053, 0x9766, 0xC054, 0x9798, 0xC055, 0x9830, 0xC056, 0x9838, 0xC057, 0x983B, 0xC058, 0x9837, 0xC059, 0x982D, 0xC05A, 0x9839, 0xC05B, 0x9824, 0xC05C, 0x9910, 0xC05D, 0x9928, 0xC05E, 0x991E, 0xC05F, 0x991B, 0xC060, 0x9921, 0xC061, 0x991A, 0xC062, 0x99ED, 0xC063, 0x99E2, 0xC064, 0x99F1, 0xC065, 0x9AB8, 0xC066, 0x9ABC, 0xC067, 0x9AFB, 0xC068, 0x9AED, 0xC069, 0x9B28, 0xC06A, 0x9B91, 0xC06B, 0x9D15, 0xC06C, 0x9D23, 0xC06D, 0x9D26, 0xC06E, 0x9D28, 0xC06F, 0x9D12, 0xC070, 0x9D1B, 0xC071, 0x9ED8, 0xC072, 0x9ED4, 0xC073, 0x9F8D, 0xC074, 0x9F9C, 0xC075, 0x512A, 0xC076, 0x511F, 0xC077, 0x5121, 0xC078, 0x5132, 0xC079, 0x52F5, 0xC07A, 0x568E, 0xC07B, 0x5680, 0xC07C, 0x5690, 0xC07D, 0x5685, 0xC07E, 0x5687, 0xC0A1, 0x568F, 0xC0A2, 0x58D5, 0xC0A3, 0x58D3, 0xC0A4, 0x58D1, 0xC0A5, 0x58CE, 0xC0A6, 0x5B30, 0xC0A7, 0x5B2A, 0xC0A8, 0x5B24, 0xC0A9, 0x5B7A, 0xC0AA, 0x5C37, 0xC0AB, 0x5C68, 0xC0AC, 0x5DBC, 0xC0AD, 0x5DBA, 0xC0AE, 0x5DBD, 0xC0AF, 0x5DB8, 0xC0B0, 0x5E6B, 0xC0B1, 0x5F4C, 0xC0B2, 0x5FBD, 0xC0B3, 0x61C9, 0xC0B4, 0x61C2, 0xC0B5, 0x61C7, 0xC0B6, 0x61E6, 0xC0B7, 0x61CB, 0xC0B8, 0x6232, 0xC0B9, 0x6234, 0xC0BA, 0x64CE, 0xC0BB, 0x64CA, 0xC0BC, 0x64D8, 0xC0BD, 0x64E0, 0xC0BE, 0x64F0, 0xC0BF, 0x64E6, 0xC0C0, 0x64EC, 0xC0C1, 0x64F1, 0xC0C2, 0x64E2, 0xC0C3, 0x64ED, 0xC0C4, 0x6582, 0xC0C5, 0x6583, 0xC0C6, 0x66D9, 0xC0C7, 0x66D6, 0xC0C8, 0x6A80, 0xC0C9, 0x6A94, 0xC0CA, 0x6A84, 0xC0CB, 0x6AA2, 0xC0CC, 0x6A9C, 0xC0CD, 0x6ADB, 0xC0CE, 0x6AA3, 0xC0CF, 0x6A7E, 0xC0D0, 0x6A97, 0xC0D1, 0x6A90, 0xC0D2, 0x6AA0, 0xC0D3, 0x6B5C, 0xC0D4, 0x6BAE, 0xC0D5, 0x6BDA, 0xC0D6, 0x6C08, 0xC0D7, 0x6FD8, 0xC0D8, 0x6FF1, 0xC0D9, 0x6FDF, 0xC0DA, 0x6FE0, 0xC0DB, 0x6FDB, 0xC0DC, 0x6FE4, 0xC0DD, 0x6FEB, 0xC0DE, 0x6FEF, 0xC0DF, 0x6F80, 0xC0E0, 0x6FEC, 0xC0E1, 0x6FE1, 0xC0E2, 0x6FE9, 0xC0E3, 0x6FD5, 0xC0E4, 0x6FEE, 0xC0E5, 0x6FF0, 0xC0E6, 0x71E7, 0xC0E7, 0x71DF, 0xC0E8, 0x71EE, 0xC0E9, 0x71E6, 0xC0EA, 0x71E5, 0xC0EB, 0x71ED, 0xC0EC, 0x71EC, 0xC0ED, 0x71F4, 0xC0EE, 0x71E0, 0xC0EF, 0x7235, 0xC0F0, 0x7246, 0xC0F1, 0x7370, 0xC0F2, 0x7372, 0xC0F3, 0x74A9, 0xC0F4, 0x74B0, 0xC0F5, 0x74A6, 0xC0F6, 0x74A8, 0xC0F7, 0x7646, 0xC0F8, 0x7642, 0xC0F9, 0x764C, 0xC0FA, 0x76EA, 0xC0FB, 0x77B3, 0xC0FC, 0x77AA, 0xC0FD, 0x77B0, 0xC0FE, 0x77AC, 0xC140, 0x77A7, 0xC141, 0x77AD, 0xC142, 0x77EF, 0xC143, 0x78F7, 0xC144, 0x78FA, 0xC145, 0x78F4, 0xC146, 0x78EF, 0xC147, 0x7901, 0xC148, 0x79A7, 0xC149, 0x79AA, 0xC14A, 0x7A57, 0xC14B, 0x7ABF, 0xC14C, 0x7C07, 0xC14D, 0x7C0D, 0xC14E, 0x7BFE, 0xC14F, 0x7BF7, 0xC150, 0x7C0C, 0xC151, 0x7BE0, 0xC152, 0x7CE0, 0xC153, 0x7CDC, 0xC154, 0x7CDE, 0xC155, 0x7CE2, 0xC156, 0x7CDF, 0xC157, 0x7CD9, 0xC158, 0x7CDD, 0xC159, 0x7E2E, 0xC15A, 0x7E3E, 0xC15B, 0x7E46, 0xC15C, 0x7E37, 0xC15D, 0x7E32, 0xC15E, 0x7E43, 0xC15F, 0x7E2B, 0xC160, 0x7E3D, 0xC161, 0x7E31, 0xC162, 0x7E45, 0xC163, 0x7E41, 0xC164, 0x7E34, 0xC165, 0x7E39, 0xC166, 0x7E48, 0xC167, 0x7E35, 0xC168, 0x7E3F, 0xC169, 0x7E2F, 0xC16A, 0x7F44, 0xC16B, 0x7FF3, 0xC16C, 0x7FFC, 0xC16D, 0x8071, 0xC16E, 0x8072, 0xC16F, 0x8070, 0xC170, 0x806F, 0xC171, 0x8073, 0xC172, 0x81C6, 0xC173, 0x81C3, 0xC174, 0x81BA, 0xC175, 0x81C2, 0xC176, 0x81C0, 0xC177, 0x81BF, 0xC178, 0x81BD, 0xC179, 0x81C9, 0xC17A, 0x81BE, 0xC17B, 0x81E8, 0xC17C, 0x8209, 0xC17D, 0x8271, 0xC17E, 0x85AA, 0xC1A1, 0x8584, 0xC1A2, 0x857E, 0xC1A3, 0x859C, 0xC1A4, 0x8591, 0xC1A5, 0x8594, 0xC1A6, 0x85AF, 0xC1A7, 0x859B, 0xC1A8, 0x8587, 0xC1A9, 0x85A8, 0xC1AA, 0x858A, 0xC1AB, 0x8667, 0xC1AC, 0x87C0, 0xC1AD, 0x87D1, 0xC1AE, 0x87B3, 0xC1AF, 0x87D2, 0xC1B0, 0x87C6, 0xC1B1, 0x87AB, 0xC1B2, 0x87BB, 0xC1B3, 0x87BA, 0xC1B4, 0x87C8, 0xC1B5, 0x87CB, 0xC1B6, 0x893B, 0xC1B7, 0x8936, 0xC1B8, 0x8944, 0xC1B9, 0x8938, 0xC1BA, 0x893D, 0xC1BB, 0x89AC, 0xC1BC, 0x8B0E, 0xC1BD, 0x8B17, 0xC1BE, 0x8B19, 0xC1BF, 0x8B1B, 0xC1C0, 0x8B0A, 0xC1C1, 0x8B20, 0xC1C2, 0x8B1D, 0xC1C3, 0x8B04, 0xC1C4, 0x8B10, 0xC1C5, 0x8C41, 0xC1C6, 0x8C3F, 0xC1C7, 0x8C73, 0xC1C8, 0x8CFA, 0xC1C9, 0x8CFD, 0xC1CA, 0x8CFC, 0xC1CB, 0x8CF8, 0xC1CC, 0x8CFB, 0xC1CD, 0x8DA8, 0xC1CE, 0x8E49, 0xC1CF, 0x8E4B, 0xC1D0, 0x8E48, 0xC1D1, 0x8E4A, 0xC1D2, 0x8F44, 0xC1D3, 0x8F3E, 0xC1D4, 0x8F42, 0xC1D5, 0x8F45, 0xC1D6, 0x8F3F, 0xC1D7, 0x907F, 0xC1D8, 0x907D, 0xC1D9, 0x9084, 0xC1DA, 0x9081, 0xC1DB, 0x9082, 0xC1DC, 0x9080, 0xC1DD, 0x9139, 0xC1DE, 0x91A3, 0xC1DF, 0x919E, 0xC1E0, 0x919C, 0xC1E1, 0x934D, 0xC1E2, 0x9382, 0xC1E3, 0x9328, 0xC1E4, 0x9375, 0xC1E5, 0x934A, 0xC1E6, 0x9365, 0xC1E7, 0x934B, 0xC1E8, 0x9318, 0xC1E9, 0x937E, 0xC1EA, 0x936C, 0xC1EB, 0x935B, 0xC1EC, 0x9370, 0xC1ED, 0x935A, 0xC1EE, 0x9354, 0xC1EF, 0x95CA, 0xC1F0, 0x95CB, 0xC1F1, 0x95CC, 0xC1F2, 0x95C8, 0xC1F3, 0x95C6, 0xC1F4, 0x96B1, 0xC1F5, 0x96B8, 0xC1F6, 0x96D6, 0xC1F7, 0x971C, 0xC1F8, 0x971E, 0xC1F9, 0x97A0, 0xC1FA, 0x97D3, 0xC1FB, 0x9846, 0xC1FC, 0x98B6, 0xC1FD, 0x9935, 0xC1FE, 0x9A01, 0xC240, 0x99FF, 0xC241, 0x9BAE, 0xC242, 0x9BAB, 0xC243, 0x9BAA, 0xC244, 0x9BAD, 0xC245, 0x9D3B, 0xC246, 0x9D3F, 0xC247, 0x9E8B, 0xC248, 0x9ECF, 0xC249, 0x9EDE, 0xC24A, 0x9EDC, 0xC24B, 0x9EDD, 0xC24C, 0x9EDB, 0xC24D, 0x9F3E, 0xC24E, 0x9F4B, 0xC24F, 0x53E2, 0xC250, 0x5695, 0xC251, 0x56AE, 0xC252, 0x58D9, 0xC253, 0x58D8, 0xC254, 0x5B38, 0xC255, 0x5F5D, 0xC256, 0x61E3, 0xC257, 0x6233, 0xC258, 0x64F4, 0xC259, 0x64F2, 0xC25A, 0x64FE, 0xC25B, 0x6506, 0xC25C, 0x64FA, 0xC25D, 0x64FB, 0xC25E, 0x64F7, 0xC25F, 0x65B7, 0xC260, 0x66DC, 0xC261, 0x6726, 0xC262, 0x6AB3, 0xC263, 0x6AAC, 0xC264, 0x6AC3, 0xC265, 0x6ABB, 0xC266, 0x6AB8, 0xC267, 0x6AC2, 0xC268, 0x6AAE, 0xC269, 0x6AAF, 0xC26A, 0x6B5F, 0xC26B, 0x6B78, 0xC26C, 0x6BAF, 0xC26D, 0x7009, 0xC26E, 0x700B, 0xC26F, 0x6FFE, 0xC270, 0x7006, 0xC271, 0x6FFA, 0xC272, 0x7011, 0xC273, 0x700F, 0xC274, 0x71FB, 0xC275, 0x71FC, 0xC276, 0x71FE, 0xC277, 0x71F8, 0xC278, 0x7377, 0xC279, 0x7375, 0xC27A, 0x74A7, 0xC27B, 0x74BF, 0xC27C, 0x7515, 0xC27D, 0x7656, 0xC27E, 0x7658, 0xC2A1, 0x7652, 0xC2A2, 0x77BD, 0xC2A3, 0x77BF, 0xC2A4, 0x77BB, 0xC2A5, 0x77BC, 0xC2A6, 0x790E, 0xC2A7, 0x79AE, 0xC2A8, 0x7A61, 0xC2A9, 0x7A62, 0xC2AA, 0x7A60, 0xC2AB, 0x7AC4, 0xC2AC, 0x7AC5, 0xC2AD, 0x7C2B, 0xC2AE, 0x7C27, 0xC2AF, 0x7C2A, 0xC2B0, 0x7C1E, 0xC2B1, 0x7C23, 0xC2B2, 0x7C21, 0xC2B3, 0x7CE7, 0xC2B4, 0x7E54, 0xC2B5, 0x7E55, 0xC2B6, 0x7E5E, 0xC2B7, 0x7E5A, 0xC2B8, 0x7E61, 0xC2B9, 0x7E52, 0xC2BA, 0x7E59, 0xC2BB, 0x7F48, 0xC2BC, 0x7FF9, 0xC2BD, 0x7FFB, 0xC2BE, 0x8077, 0xC2BF, 0x8076, 0xC2C0, 0x81CD, 0xC2C1, 0x81CF, 0xC2C2, 0x820A, 0xC2C3, 0x85CF, 0xC2C4, 0x85A9, 0xC2C5, 0x85CD, 0xC2C6, 0x85D0, 0xC2C7, 0x85C9, 0xC2C8, 0x85B0, 0xC2C9, 0x85BA, 0xC2CA, 0x85B9, 0xC2CB, 0x85A6, 0xC2CC, 0x87EF, 0xC2CD, 0x87EC, 0xC2CE, 0x87F2, 0xC2CF, 0x87E0, 0xC2D0, 0x8986, 0xC2D1, 0x89B2, 0xC2D2, 0x89F4, 0xC2D3, 0x8B28, 0xC2D4, 0x8B39, 0xC2D5, 0x8B2C, 0xC2D6, 0x8B2B, 0xC2D7, 0x8C50, 0xC2D8, 0x8D05, 0xC2D9, 0x8E59, 0xC2DA, 0x8E63, 0xC2DB, 0x8E66, 0xC2DC, 0x8E64, 0xC2DD, 0x8E5F, 0xC2DE, 0x8E55, 0xC2DF, 0x8EC0, 0xC2E0, 0x8F49, 0xC2E1, 0x8F4D, 0xC2E2, 0x9087, 0xC2E3, 0x9083, 0xC2E4, 0x9088, 0xC2E5, 0x91AB, 0xC2E6, 0x91AC, 0xC2E7, 0x91D0, 0xC2E8, 0x9394, 0xC2E9, 0x938A, 0xC2EA, 0x9396, 0xC2EB, 0x93A2, 0xC2EC, 0x93B3, 0xC2ED, 0x93AE, 0xC2EE, 0x93AC, 0xC2EF, 0x93B0, 0xC2F0, 0x9398, 0xC2F1, 0x939A, 0xC2F2, 0x9397, 0xC2F3, 0x95D4, 0xC2F4, 0x95D6, 0xC2F5, 0x95D0, 0xC2F6, 0x95D5, 0xC2F7, 0x96E2, 0xC2F8, 0x96DC, 0xC2F9, 0x96D9, 0xC2FA, 0x96DB, 0xC2FB, 0x96DE, 0xC2FC, 0x9724, 0xC2FD, 0x97A3, 0xC2FE, 0x97A6, 0xC340, 0x97AD, 0xC341, 0x97F9, 0xC342, 0x984D, 0xC343, 0x984F, 0xC344, 0x984C, 0xC345, 0x984E, 0xC346, 0x9853, 0xC347, 0x98BA, 0xC348, 0x993E, 0xC349, 0x993F, 0xC34A, 0x993D, 0xC34B, 0x992E, 0xC34C, 0x99A5, 0xC34D, 0x9A0E, 0xC34E, 0x9AC1, 0xC34F, 0x9B03, 0xC350, 0x9B06, 0xC351, 0x9B4F, 0xC352, 0x9B4E, 0xC353, 0x9B4D, 0xC354, 0x9BCA, 0xC355, 0x9BC9, 0xC356, 0x9BFD, 0xC357, 0x9BC8, 0xC358, 0x9BC0, 0xC359, 0x9D51, 0xC35A, 0x9D5D, 0xC35B, 0x9D60, 0xC35C, 0x9EE0, 0xC35D, 0x9F15, 0xC35E, 0x9F2C, 0xC35F, 0x5133, 0xC360, 0x56A5, 0xC361, 0x58DE, 0xC362, 0x58DF, 0xC363, 0x58E2, 0xC364, 0x5BF5, 0xC365, 0x9F90, 0xC366, 0x5EEC, 0xC367, 0x61F2, 0xC368, 0x61F7, 0xC369, 0x61F6, 0xC36A, 0x61F5, 0xC36B, 0x6500, 0xC36C, 0x650F, 0xC36D, 0x66E0, 0xC36E, 0x66DD, 0xC36F, 0x6AE5, 0xC370, 0x6ADD, 0xC371, 0x6ADA, 0xC372, 0x6AD3, 0xC373, 0x701B, 0xC374, 0x701F, 0xC375, 0x7028, 0xC376, 0x701A, 0xC377, 0x701D, 0xC378, 0x7015, 0xC379, 0x7018, 0xC37A, 0x7206, 0xC37B, 0x720D, 0xC37C, 0x7258, 0xC37D, 0x72A2, 0xC37E, 0x7378, 0xC3A1, 0x737A, 0xC3A2, 0x74BD, 0xC3A3, 0x74CA, 0xC3A4, 0x74E3, 0xC3A5, 0x7587, 0xC3A6, 0x7586, 0xC3A7, 0x765F, 0xC3A8, 0x7661, 0xC3A9, 0x77C7, 0xC3AA, 0x7919, 0xC3AB, 0x79B1, 0xC3AC, 0x7A6B, 0xC3AD, 0x7A69, 0xC3AE, 0x7C3E, 0xC3AF, 0x7C3F, 0xC3B0, 0x7C38, 0xC3B1, 0x7C3D, 0xC3B2, 0x7C37, 0xC3B3, 0x7C40, 0xC3B4, 0x7E6B, 0xC3B5, 0x7E6D, 0xC3B6, 0x7E79, 0xC3B7, 0x7E69, 0xC3B8, 0x7E6A, 0xC3B9, 0x7F85, 0xC3BA, 0x7E73, 0xC3BB, 0x7FB6, 0xC3BC, 0x7FB9, 0xC3BD, 0x7FB8, 0xC3BE, 0x81D8, 0xC3BF, 0x85E9, 0xC3C0, 0x85DD, 0xC3C1, 0x85EA, 0xC3C2, 0x85D5, 0xC3C3, 0x85E4, 0xC3C4, 0x85E5, 0xC3C5, 0x85F7, 0xC3C6, 0x87FB, 0xC3C7, 0x8805, 0xC3C8, 0x880D, 0xC3C9, 0x87F9, 0xC3CA, 0x87FE, 0xC3CB, 0x8960, 0xC3CC, 0x895F, 0xC3CD, 0x8956, 0xC3CE, 0x895E, 0xC3CF, 0x8B41, 0xC3D0, 0x8B5C, 0xC3D1, 0x8B58, 0xC3D2, 0x8B49, 0xC3D3, 0x8B5A, 0xC3D4, 0x8B4E, 0xC3D5, 0x8B4F, 0xC3D6, 0x8B46, 0xC3D7, 0x8B59, 0xC3D8, 0x8D08, 0xC3D9, 0x8D0A, 0xC3DA, 0x8E7C, 0xC3DB, 0x8E72, 0xC3DC, 0x8E87, 0xC3DD, 0x8E76, 0xC3DE, 0x8E6C, 0xC3DF, 0x8E7A, 0xC3E0, 0x8E74, 0xC3E1, 0x8F54, 0xC3E2, 0x8F4E, 0xC3E3, 0x8FAD, 0xC3E4, 0x908A, 0xC3E5, 0x908B, 0xC3E6, 0x91B1, 0xC3E7, 0x91AE, 0xC3E8, 0x93E1, 0xC3E9, 0x93D1, 0xC3EA, 0x93DF, 0xC3EB, 0x93C3, 0xC3EC, 0x93C8, 0xC3ED, 0x93DC, 0xC3EE, 0x93DD, 0xC3EF, 0x93D6, 0xC3F0, 0x93E2, 0xC3F1, 0x93CD, 0xC3F2, 0x93D8, 0xC3F3, 0x93E4, 0xC3F4, 0x93D7, 0xC3F5, 0x93E8, 0xC3F6, 0x95DC, 0xC3F7, 0x96B4, 0xC3F8, 0x96E3, 0xC3F9, 0x972A, 0xC3FA, 0x9727, 0xC3FB, 0x9761, 0xC3FC, 0x97DC, 0xC3FD, 0x97FB, 0xC3FE, 0x985E, 0xC440, 0x9858, 0xC441, 0x985B, 0xC442, 0x98BC, 0xC443, 0x9945, 0xC444, 0x9949, 0xC445, 0x9A16, 0xC446, 0x9A19, 0xC447, 0x9B0D, 0xC448, 0x9BE8, 0xC449, 0x9BE7, 0xC44A, 0x9BD6, 0xC44B, 0x9BDB, 0xC44C, 0x9D89, 0xC44D, 0x9D61, 0xC44E, 0x9D72, 0xC44F, 0x9D6A, 0xC450, 0x9D6C, 0xC451, 0x9E92, 0xC452, 0x9E97, 0xC453, 0x9E93, 0xC454, 0x9EB4, 0xC455, 0x52F8, 0xC456, 0x56A8, 0xC457, 0x56B7, 0xC458, 0x56B6, 0xC459, 0x56B4, 0xC45A, 0x56BC, 0xC45B, 0x58E4, 0xC45C, 0x5B40, 0xC45D, 0x5B43, 0xC45E, 0x5B7D, 0xC45F, 0x5BF6, 0xC460, 0x5DC9, 0xC461, 0x61F8, 0xC462, 0x61FA, 0xC463, 0x6518, 0xC464, 0x6514, 0xC465, 0x6519, 0xC466, 0x66E6, 0xC467, 0x6727, 0xC468, 0x6AEC, 0xC469, 0x703E, 0xC46A, 0x7030, 0xC46B, 0x7032, 0xC46C, 0x7210, 0xC46D, 0x737B, 0xC46E, 0x74CF, 0xC46F, 0x7662, 0xC470, 0x7665, 0xC471, 0x7926, 0xC472, 0x792A, 0xC473, 0x792C, 0xC474, 0x792B, 0xC475, 0x7AC7, 0xC476, 0x7AF6, 0xC477, 0x7C4C, 0xC478, 0x7C43, 0xC479, 0x7C4D, 0xC47A, 0x7CEF, 0xC47B, 0x7CF0, 0xC47C, 0x8FAE, 0xC47D, 0x7E7D, 0xC47E, 0x7E7C, 0xC4A1, 0x7E82, 0xC4A2, 0x7F4C, 0xC4A3, 0x8000, 0xC4A4, 0x81DA, 0xC4A5, 0x8266, 0xC4A6, 0x85FB, 0xC4A7, 0x85F9, 0xC4A8, 0x8611, 0xC4A9, 0x85FA, 0xC4AA, 0x8606, 0xC4AB, 0x860B, 0xC4AC, 0x8607, 0xC4AD, 0x860A, 0xC4AE, 0x8814, 0xC4AF, 0x8815, 0xC4B0, 0x8964, 0xC4B1, 0x89BA, 0xC4B2, 0x89F8, 0xC4B3, 0x8B70, 0xC4B4, 0x8B6C, 0xC4B5, 0x8B66, 0xC4B6, 0x8B6F, 0xC4B7, 0x8B5F, 0xC4B8, 0x8B6B, 0xC4B9, 0x8D0F, 0xC4BA, 0x8D0D, 0xC4BB, 0x8E89, 0xC4BC, 0x8E81, 0xC4BD, 0x8E85, 0xC4BE, 0x8E82, 0xC4BF, 0x91B4, 0xC4C0, 0x91CB, 0xC4C1, 0x9418, 0xC4C2, 0x9403, 0xC4C3, 0x93FD, 0xC4C4, 0x95E1, 0xC4C5, 0x9730, 0xC4C6, 0x98C4, 0xC4C7, 0x9952, 0xC4C8, 0x9951, 0xC4C9, 0x99A8, 0xC4CA, 0x9A2B, 0xC4CB, 0x9A30, 0xC4CC, 0x9A37, 0xC4CD, 0x9A35, 0xC4CE, 0x9C13, 0xC4CF, 0x9C0D, 0xC4D0, 0x9E79, 0xC4D1, 0x9EB5, 0xC4D2, 0x9EE8, 0xC4D3, 0x9F2F, 0xC4D4, 0x9F5F, 0xC4D5, 0x9F63, 0xC4D6, 0x9F61, 0xC4D7, 0x5137, 0xC4D8, 0x5138, 0xC4D9, 0x56C1, 0xC4DA, 0x56C0, 0xC4DB, 0x56C2, 0xC4DC, 0x5914, 0xC4DD, 0x5C6C, 0xC4DE, 0x5DCD, 0xC4DF, 0x61FC, 0xC4E0, 0x61FE, 0xC4E1, 0x651D, 0xC4E2, 0x651C, 0xC4E3, 0x6595, 0xC4E4, 0x66E9, 0xC4E5, 0x6AFB, 0xC4E6, 0x6B04, 0xC4E7, 0x6AFA, 0xC4E8, 0x6BB2, 0xC4E9, 0x704C, 0xC4EA, 0x721B, 0xC4EB, 0x72A7, 0xC4EC, 0x74D6, 0xC4ED, 0x74D4, 0xC4EE, 0x7669, 0xC4EF, 0x77D3, 0xC4F0, 0x7C50, 0xC4F1, 0x7E8F, 0xC4F2, 0x7E8C, 0xC4F3, 0x7FBC, 0xC4F4, 0x8617, 0xC4F5, 0x862D, 0xC4F6, 0x861A, 0xC4F7, 0x8823, 0xC4F8, 0x8822, 0xC4F9, 0x8821, 0xC4FA, 0x881F, 0xC4FB, 0x896A, 0xC4FC, 0x896C, 0xC4FD, 0x89BD, 0xC4FE, 0x8B74, 0xC540, 0x8B77, 0xC541, 0x8B7D, 0xC542, 0x8D13, 0xC543, 0x8E8A, 0xC544, 0x8E8D, 0xC545, 0x8E8B, 0xC546, 0x8F5F, 0xC547, 0x8FAF, 0xC548, 0x91BA, 0xC549, 0x942E, 0xC54A, 0x9433, 0xC54B, 0x9435, 0xC54C, 0x943A, 0xC54D, 0x9438, 0xC54E, 0x9432, 0xC54F, 0x942B, 0xC550, 0x95E2, 0xC551, 0x9738, 0xC552, 0x9739, 0xC553, 0x9732, 0xC554, 0x97FF, 0xC555, 0x9867, 0xC556, 0x9865, 0xC557, 0x9957, 0xC558, 0x9A45, 0xC559, 0x9A43, 0xC55A, 0x9A40, 0xC55B, 0x9A3E, 0xC55C, 0x9ACF, 0xC55D, 0x9B54, 0xC55E, 0x9B51, 0xC55F, 0x9C2D, 0xC560, 0x9C25, 0xC561, 0x9DAF, 0xC562, 0x9DB4, 0xC563, 0x9DC2, 0xC564, 0x9DB8, 0xC565, 0x9E9D, 0xC566, 0x9EEF, 0xC567, 0x9F19, 0xC568, 0x9F5C, 0xC569, 0x9F66, 0xC56A, 0x9F67, 0xC56B, 0x513C, 0xC56C, 0x513B, 0xC56D, 0x56C8, 0xC56E, 0x56CA, 0xC56F, 0x56C9, 0xC570, 0x5B7F, 0xC571, 0x5DD4, 0xC572, 0x5DD2, 0xC573, 0x5F4E, 0xC574, 0x61FF, 0xC575, 0x6524, 0xC576, 0x6B0A, 0xC577, 0x6B61, 0xC578, 0x7051, 0xC579, 0x7058, 0xC57A, 0x7380, 0xC57B, 0x74E4, 0xC57C, 0x758A, 0xC57D, 0x766E, 0xC57E, 0x766C, 0xC5A1, 0x79B3, 0xC5A2, 0x7C60, 0xC5A3, 0x7C5F, 0xC5A4, 0x807E, 0xC5A5, 0x807D, 0xC5A6, 0x81DF, 0xC5A7, 0x8972, 0xC5A8, 0x896F, 0xC5A9, 0x89FC, 0xC5AA, 0x8B80, 0xC5AB, 0x8D16, 0xC5AC, 0x8D17, 0xC5AD, 0x8E91, 0xC5AE, 0x8E93, 0xC5AF, 0x8F61, 0xC5B0, 0x9148, 0xC5B1, 0x9444, 0xC5B2, 0x9451, 0xC5B3, 0x9452, 0xC5B4, 0x973D, 0xC5B5, 0x973E, 0xC5B6, 0x97C3, 0xC5B7, 0x97C1, 0xC5B8, 0x986B, 0xC5B9, 0x9955, 0xC5BA, 0x9A55, 0xC5BB, 0x9A4D, 0xC5BC, 0x9AD2, 0xC5BD, 0x9B1A, 0xC5BE, 0x9C49, 0xC5BF, 0x9C31, 0xC5C0, 0x9C3E, 0xC5C1, 0x9C3B, 0xC5C2, 0x9DD3, 0xC5C3, 0x9DD7, 0xC5C4, 0x9F34, 0xC5C5, 0x9F6C, 0xC5C6, 0x9F6A, 0xC5C7, 0x9F94, 0xC5C8, 0x56CC, 0xC5C9, 0x5DD6, 0xC5CA, 0x6200, 0xC5CB, 0x6523, 0xC5CC, 0x652B, 0xC5CD, 0x652A, 0xC5CE, 0x66EC, 0xC5CF, 0x6B10, 0xC5D0, 0x74DA, 0xC5D1, 0x7ACA, 0xC5D2, 0x7C64, 0xC5D3, 0x7C63, 0xC5D4, 0x7C65, 0xC5D5, 0x7E93, 0xC5D6, 0x7E96, 0xC5D7, 0x7E94, 0xC5D8, 0x81E2, 0xC5D9, 0x8638, 0xC5DA, 0x863F, 0xC5DB, 0x8831, 0xC5DC, 0x8B8A, 0xC5DD, 0x9090, 0xC5DE, 0x908F, 0xC5DF, 0x9463, 0xC5E0, 0x9460, 0xC5E1, 0x9464, 0xC5E2, 0x9768, 0xC5E3, 0x986F, 0xC5E4, 0x995C, 0xC5E5, 0x9A5A, 0xC5E6, 0x9A5B, 0xC5E7, 0x9A57, 0xC5E8, 0x9AD3, 0xC5E9, 0x9AD4, 0xC5EA, 0x9AD1, 0xC5EB, 0x9C54, 0xC5EC, 0x9C57, 0xC5ED, 0x9C56, 0xC5EE, 0x9DE5, 0xC5EF, 0x9E9F, 0xC5F0, 0x9EF4, 0xC5F1, 0x56D1, 0xC5F2, 0x58E9, 0xC5F3, 0x652C, 0xC5F4, 0x705E, 0xC5F5, 0x7671, 0xC5F6, 0x7672, 0xC5F7, 0x77D7, 0xC5F8, 0x7F50, 0xC5F9, 0x7F88, 0xC5FA, 0x8836, 0xC5FB, 0x8839, 0xC5FC, 0x8862, 0xC5FD, 0x8B93, 0xC5FE, 0x8B92, 0xC640, 0x8B96, 0xC641, 0x8277, 0xC642, 0x8D1B, 0xC643, 0x91C0, 0xC644, 0x946A, 0xC645, 0x9742, 0xC646, 0x9748, 0xC647, 0x9744, 0xC648, 0x97C6, 0xC649, 0x9870, 0xC64A, 0x9A5F, 0xC64B, 0x9B22, 0xC64C, 0x9B58, 0xC64D, 0x9C5F, 0xC64E, 0x9DF9, 0xC64F, 0x9DFA, 0xC650, 0x9E7C, 0xC651, 0x9E7D, 0xC652, 0x9F07, 0xC653, 0x9F77, 0xC654, 0x9F72, 0xC655, 0x5EF3, 0xC656, 0x6B16, 0xC657, 0x7063, 0xC658, 0x7C6C, 0xC659, 0x7C6E, 0xC65A, 0x883B, 0xC65B, 0x89C0, 0xC65C, 0x8EA1, 0xC65D, 0x91C1, 0xC65E, 0x9472, 0xC65F, 0x9470, 0xC660, 0x9871, 0xC661, 0x995E, 0xC662, 0x9AD6, 0xC663, 0x9B23, 0xC664, 0x9ECC, 0xC665, 0x7064, 0xC666, 0x77DA, 0xC667, 0x8B9A, 0xC668, 0x9477, 0xC669, 0x97C9, 0xC66A, 0x9A62, 0xC66B, 0x9A65, 0xC66C, 0x7E9C, 0xC66D, 0x8B9C, 0xC66E, 0x8EAA, 0xC66F, 0x91C5, 0xC670, 0x947D, 0xC671, 0x947E, 0xC672, 0x947C, 0xC673, 0x9C77, 0xC674, 0x9C78, 0xC675, 0x9EF7, 0xC676, 0x8C54, 0xC677, 0x947F, 0xC678, 0x9E1A, 0xC679, 0x7228, 0xC67A, 0x9A6A, 0xC67B, 0x9B31, 0xC67C, 0x9E1B, 0xC67D, 0x9E1E, 0xC67E, 0x7C72, 0xC940, 0x4E42, 0xC941, 0x4E5C, 0xC942, 0x51F5, 0xC943, 0x531A, 0xC944, 0x5382, 0xC945, 0x4E07, 0xC946, 0x4E0C, 0xC947, 0x4E47, 0xC948, 0x4E8D, 0xC949, 0x56D7, 0xC94A, 0xFA0C, 0xC94B, 0x5C6E, 0xC94C, 0x5F73, 0xC94D, 0x4E0F, 0xC94E, 0x5187, 0xC94F, 0x4E0E, 0xC950, 0x4E2E, 0xC951, 0x4E93, 0xC952, 0x4EC2, 0xC953, 0x4EC9, 0xC954, 0x4EC8, 0xC955, 0x5198, 0xC956, 0x52FC, 0xC957, 0x536C, 0xC958, 0x53B9, 0xC959, 0x5720, 0xC95A, 0x5903, 0xC95B, 0x592C, 0xC95C, 0x5C10, 0xC95D, 0x5DFF, 0xC95E, 0x65E1, 0xC95F, 0x6BB3, 0xC960, 0x6BCC, 0xC961, 0x6C14, 0xC962, 0x723F, 0xC963, 0x4E31, 0xC964, 0x4E3C, 0xC965, 0x4EE8, 0xC966, 0x4EDC, 0xC967, 0x4EE9, 0xC968, 0x4EE1, 0xC969, 0x4EDD, 0xC96A, 0x4EDA, 0xC96B, 0x520C, 0xC96C, 0x531C, 0xC96D, 0x534C, 0xC96E, 0x5722, 0xC96F, 0x5723, 0xC970, 0x5917, 0xC971, 0x592F, 0xC972, 0x5B81, 0xC973, 0x5B84, 0xC974, 0x5C12, 0xC975, 0x5C3B, 0xC976, 0x5C74, 0xC977, 0x5C73, 0xC978, 0x5E04, 0xC979, 0x5E80, 0xC97A, 0x5E82, 0xC97B, 0x5FC9, 0xC97C, 0x6209, 0xC97D, 0x6250, 0xC97E, 0x6C15, 0xC9A1, 0x6C36, 0xC9A2, 0x6C43, 0xC9A3, 0x6C3F, 0xC9A4, 0x6C3B, 0xC9A5, 0x72AE, 0xC9A6, 0x72B0, 0xC9A7, 0x738A, 0xC9A8, 0x79B8, 0xC9A9, 0x808A, 0xC9AA, 0x961E, 0xC9AB, 0x4F0E, 0xC9AC, 0x4F18, 0xC9AD, 0x4F2C, 0xC9AE, 0x4EF5, 0xC9AF, 0x4F14, 0xC9B0, 0x4EF1, 0xC9B1, 0x4F00, 0xC9B2, 0x4EF7, 0xC9B3, 0x4F08, 0xC9B4, 0x4F1D, 0xC9B5, 0x4F02, 0xC9B6, 0x4F05, 0xC9B7, 0x4F22, 0xC9B8, 0x4F13, 0xC9B9, 0x4F04, 0xC9BA, 0x4EF4, 0xC9BB, 0x4F12, 0xC9BC, 0x51B1, 0xC9BD, 0x5213, 0xC9BE, 0x5209, 0xC9BF, 0x5210, 0xC9C0, 0x52A6, 0xC9C1, 0x5322, 0xC9C2, 0x531F, 0xC9C3, 0x534D, 0xC9C4, 0x538A, 0xC9C5, 0x5407, 0xC9C6, 0x56E1, 0xC9C7, 0x56DF, 0xC9C8, 0x572E, 0xC9C9, 0x572A, 0xC9CA, 0x5734, 0xC9CB, 0x593C, 0xC9CC, 0x5980, 0xC9CD, 0x597C, 0xC9CE, 0x5985, 0xC9CF, 0x597B, 0xC9D0, 0x597E, 0xC9D1, 0x5977, 0xC9D2, 0x597F, 0xC9D3, 0x5B56, 0xC9D4, 0x5C15, 0xC9D5, 0x5C25, 0xC9D6, 0x5C7C, 0xC9D7, 0x5C7A, 0xC9D8, 0x5C7B, 0xC9D9, 0x5C7E, 0xC9DA, 0x5DDF, 0xC9DB, 0x5E75, 0xC9DC, 0x5E84, 0xC9DD, 0x5F02, 0xC9DE, 0x5F1A, 0xC9DF, 0x5F74, 0xC9E0, 0x5FD5, 0xC9E1, 0x5FD4, 0xC9E2, 0x5FCF, 0xC9E3, 0x625C, 0xC9E4, 0x625E, 0xC9E5, 0x6264, 0xC9E6, 0x6261, 0xC9E7, 0x6266, 0xC9E8, 0x6262, 0xC9E9, 0x6259, 0xC9EA, 0x6260, 0xC9EB, 0x625A, 0xC9EC, 0x6265, 0xC9ED, 0x65EF, 0xC9EE, 0x65EE, 0xC9EF, 0x673E, 0xC9F0, 0x6739, 0xC9F1, 0x6738, 0xC9F2, 0x673B, 0xC9F3, 0x673A, 0xC9F4, 0x673F, 0xC9F5, 0x673C, 0xC9F6, 0x6733, 0xC9F7, 0x6C18, 0xC9F8, 0x6C46, 0xC9F9, 0x6C52, 0xC9FA, 0x6C5C, 0xC9FB, 0x6C4F, 0xC9FC, 0x6C4A, 0xC9FD, 0x6C54, 0xC9FE, 0x6C4B, 0xCA40, 0x6C4C, 0xCA41, 0x7071, 0xCA42, 0x725E, 0xCA43, 0x72B4, 0xCA44, 0x72B5, 0xCA45, 0x738E, 0xCA46, 0x752A, 0xCA47, 0x767F, 0xCA48, 0x7A75, 0xCA49, 0x7F51, 0xCA4A, 0x8278, 0xCA4B, 0x827C, 0xCA4C, 0x8280, 0xCA4D, 0x827D, 0xCA4E, 0x827F, 0xCA4F, 0x864D, 0xCA50, 0x897E, 0xCA51, 0x9099, 0xCA52, 0x9097, 0xCA53, 0x9098, 0xCA54, 0x909B, 0xCA55, 0x9094, 0xCA56, 0x9622, 0xCA57, 0x9624, 0xCA58, 0x9620, 0xCA59, 0x9623, 0xCA5A, 0x4F56, 0xCA5B, 0x4F3B, 0xCA5C, 0x4F62, 0xCA5D, 0x4F49, 0xCA5E, 0x4F53, 0xCA5F, 0x4F64, 0xCA60, 0x4F3E, 0xCA61, 0x4F67, 0xCA62, 0x4F52, 0xCA63, 0x4F5F, 0xCA64, 0x4F41, 0xCA65, 0x4F58, 0xCA66, 0x4F2D, 0xCA67, 0x4F33, 0xCA68, 0x4F3F, 0xCA69, 0x4F61, 0xCA6A, 0x518F, 0xCA6B, 0x51B9, 0xCA6C, 0x521C, 0xCA6D, 0x521E, 0xCA6E, 0x5221, 0xCA6F, 0x52AD, 0xCA70, 0x52AE, 0xCA71, 0x5309, 0xCA72, 0x5363, 0xCA73, 0x5372, 0xCA74, 0x538E, 0xCA75, 0x538F, 0xCA76, 0x5430, 0xCA77, 0x5437, 0xCA78, 0x542A, 0xCA79, 0x5454, 0xCA7A, 0x5445, 0xCA7B, 0x5419, 0xCA7C, 0x541C, 0xCA7D, 0x5425, 0xCA7E, 0x5418, 0xCAA1, 0x543D, 0xCAA2, 0x544F, 0xCAA3, 0x5441, 0xCAA4, 0x5428, 0xCAA5, 0x5424, 0xCAA6, 0x5447, 0xCAA7, 0x56EE, 0xCAA8, 0x56E7, 0xCAA9, 0x56E5, 0xCAAA, 0x5741, 0xCAAB, 0x5745, 0xCAAC, 0x574C, 0xCAAD, 0x5749, 0xCAAE, 0x574B, 0xCAAF, 0x5752, 0xCAB0, 0x5906, 0xCAB1, 0x5940, 0xCAB2, 0x59A6, 0xCAB3, 0x5998, 0xCAB4, 0x59A0, 0xCAB5, 0x5997, 0xCAB6, 0x598E, 0xCAB7, 0x59A2, 0xCAB8, 0x5990, 0xCAB9, 0x598F, 0xCABA, 0x59A7, 0xCABB, 0x59A1, 0xCABC, 0x5B8E, 0xCABD, 0x5B92, 0xCABE, 0x5C28, 0xCABF, 0x5C2A, 0xCAC0, 0x5C8D, 0xCAC1, 0x5C8F, 0xCAC2, 0x5C88, 0xCAC3, 0x5C8B, 0xCAC4, 0x5C89, 0xCAC5, 0x5C92, 0xCAC6, 0x5C8A, 0xCAC7, 0x5C86, 0xCAC8, 0x5C93, 0xCAC9, 0x5C95, 0xCACA, 0x5DE0, 0xCACB, 0x5E0A, 0xCACC, 0x5E0E, 0xCACD, 0x5E8B, 0xCACE, 0x5E89, 0xCACF, 0x5E8C, 0xCAD0, 0x5E88, 0xCAD1, 0x5E8D, 0xCAD2, 0x5F05, 0xCAD3, 0x5F1D, 0xCAD4, 0x5F78, 0xCAD5, 0x5F76, 0xCAD6, 0x5FD2, 0xCAD7, 0x5FD1, 0xCAD8, 0x5FD0, 0xCAD9, 0x5FED, 0xCADA, 0x5FE8, 0xCADB, 0x5FEE, 0xCADC, 0x5FF3, 0xCADD, 0x5FE1, 0xCADE, 0x5FE4, 0xCADF, 0x5FE3, 0xCAE0, 0x5FFA, 0xCAE1, 0x5FEF, 0xCAE2, 0x5FF7, 0xCAE3, 0x5FFB, 0xCAE4, 0x6000, 0xCAE5, 0x5FF4, 0xCAE6, 0x623A, 0xCAE7, 0x6283, 0xCAE8, 0x628C, 0xCAE9, 0x628E, 0xCAEA, 0x628F, 0xCAEB, 0x6294, 0xCAEC, 0x6287, 0xCAED, 0x6271, 0xCAEE, 0x627B, 0xCAEF, 0x627A, 0xCAF0, 0x6270, 0xCAF1, 0x6281, 0xCAF2, 0x6288, 0xCAF3, 0x6277, 0xCAF4, 0x627D, 0xCAF5, 0x6272, 0xCAF6, 0x6274, 0xCAF7, 0x6537, 0xCAF8, 0x65F0, 0xCAF9, 0x65F4, 0xCAFA, 0x65F3, 0xCAFB, 0x65F2, 0xCAFC, 0x65F5, 0xCAFD, 0x6745, 0xCAFE, 0x6747, 0xCB40, 0x6759, 0xCB41, 0x6755, 0xCB42, 0x674C, 0xCB43, 0x6748, 0xCB44, 0x675D, 0xCB45, 0x674D, 0xCB46, 0x675A, 0xCB47, 0x674B, 0xCB48, 0x6BD0, 0xCB49, 0x6C19, 0xCB4A, 0x6C1A, 0xCB4B, 0x6C78, 0xCB4C, 0x6C67, 0xCB4D, 0x6C6B, 0xCB4E, 0x6C84, 0xCB4F, 0x6C8B, 0xCB50, 0x6C8F, 0xCB51, 0x6C71, 0xCB52, 0x6C6F, 0xCB53, 0x6C69, 0xCB54, 0x6C9A, 0xCB55, 0x6C6D, 0xCB56, 0x6C87, 0xCB57, 0x6C95, 0xCB58, 0x6C9C, 0xCB59, 0x6C66, 0xCB5A, 0x6C73, 0xCB5B, 0x6C65, 0xCB5C, 0x6C7B, 0xCB5D, 0x6C8E, 0xCB5E, 0x7074, 0xCB5F, 0x707A, 0xCB60, 0x7263, 0xCB61, 0x72BF, 0xCB62, 0x72BD, 0xCB63, 0x72C3, 0xCB64, 0x72C6, 0xCB65, 0x72C1, 0xCB66, 0x72BA, 0xCB67, 0x72C5, 0xCB68, 0x7395, 0xCB69, 0x7397, 0xCB6A, 0x7393, 0xCB6B, 0x7394, 0xCB6C, 0x7392, 0xCB6D, 0x753A, 0xCB6E, 0x7539, 0xCB6F, 0x7594, 0xCB70, 0x7595, 0xCB71, 0x7681, 0xCB72, 0x793D, 0xCB73, 0x8034, 0xCB74, 0x8095, 0xCB75, 0x8099, 0xCB76, 0x8090, 0xCB77, 0x8092, 0xCB78, 0x809C, 0xCB79, 0x8290, 0xCB7A, 0x828F, 0xCB7B, 0x8285, 0xCB7C, 0x828E, 0xCB7D, 0x8291, 0xCB7E, 0x8293, 0xCBA1, 0x828A, 0xCBA2, 0x8283, 0xCBA3, 0x8284, 0xCBA4, 0x8C78, 0xCBA5, 0x8FC9, 0xCBA6, 0x8FBF, 0xCBA7, 0x909F, 0xCBA8, 0x90A1, 0xCBA9, 0x90A5, 0xCBAA, 0x909E, 0xCBAB, 0x90A7, 0xCBAC, 0x90A0, 0xCBAD, 0x9630, 0xCBAE, 0x9628, 0xCBAF, 0x962F, 0xCBB0, 0x962D, 0xCBB1, 0x4E33, 0xCBB2, 0x4F98, 0xCBB3, 0x4F7C, 0xCBB4, 0x4F85, 0xCBB5, 0x4F7D, 0xCBB6, 0x4F80, 0xCBB7, 0x4F87, 0xCBB8, 0x4F76, 0xCBB9, 0x4F74, 0xCBBA, 0x4F89, 0xCBBB, 0x4F84, 0xCBBC, 0x4F77, 0xCBBD, 0x4F4C, 0xCBBE, 0x4F97, 0xCBBF, 0x4F6A, 0xCBC0, 0x4F9A, 0xCBC1, 0x4F79, 0xCBC2, 0x4F81, 0xCBC3, 0x4F78, 0xCBC4, 0x4F90, 0xCBC5, 0x4F9C, 0xCBC6, 0x4F94, 0xCBC7, 0x4F9E, 0xCBC8, 0x4F92, 0xCBC9, 0x4F82, 0xCBCA, 0x4F95, 0xCBCB, 0x4F6B, 0xCBCC, 0x4F6E, 0xCBCD, 0x519E, 0xCBCE, 0x51BC, 0xCBCF, 0x51BE, 0xCBD0, 0x5235, 0xCBD1, 0x5232, 0xCBD2, 0x5233, 0xCBD3, 0x5246, 0xCBD4, 0x5231, 0xCBD5, 0x52BC, 0xCBD6, 0x530A, 0xCBD7, 0x530B, 0xCBD8, 0x533C, 0xCBD9, 0x5392, 0xCBDA, 0x5394, 0xCBDB, 0x5487, 0xCBDC, 0x547F, 0xCBDD, 0x5481, 0xCBDE, 0x5491, 0xCBDF, 0x5482, 0xCBE0, 0x5488, 0xCBE1, 0x546B, 0xCBE2, 0x547A, 0xCBE3, 0x547E, 0xCBE4, 0x5465, 0xCBE5, 0x546C, 0xCBE6, 0x5474, 0xCBE7, 0x5466, 0xCBE8, 0x548D, 0xCBE9, 0x546F, 0xCBEA, 0x5461, 0xCBEB, 0x5460, 0xCBEC, 0x5498, 0xCBED, 0x5463, 0xCBEE, 0x5467, 0xCBEF, 0x5464, 0xCBF0, 0x56F7, 0xCBF1, 0x56F9, 0xCBF2, 0x576F, 0xCBF3, 0x5772, 0xCBF4, 0x576D, 0xCBF5, 0x576B, 0xCBF6, 0x5771, 0xCBF7, 0x5770, 0xCBF8, 0x5776, 0xCBF9, 0x5780, 0xCBFA, 0x5775, 0xCBFB, 0x577B, 0xCBFC, 0x5773, 0xCBFD, 0x5774, 0xCBFE, 0x5762, 0xCC40, 0x5768, 0xCC41, 0x577D, 0xCC42, 0x590C, 0xCC43, 0x5945, 0xCC44, 0x59B5, 0xCC45, 0x59BA, 0xCC46, 0x59CF, 0xCC47, 0x59CE, 0xCC48, 0x59B2, 0xCC49, 0x59CC, 0xCC4A, 0x59C1, 0xCC4B, 0x59B6, 0xCC4C, 0x59BC, 0xCC4D, 0x59C3, 0xCC4E, 0x59D6, 0xCC4F, 0x59B1, 0xCC50, 0x59BD, 0xCC51, 0x59C0, 0xCC52, 0x59C8, 0xCC53, 0x59B4, 0xCC54, 0x59C7, 0xCC55, 0x5B62, 0xCC56, 0x5B65, 0xCC57, 0x5B93, 0xCC58, 0x5B95, 0xCC59, 0x5C44, 0xCC5A, 0x5C47, 0xCC5B, 0x5CAE, 0xCC5C, 0x5CA4, 0xCC5D, 0x5CA0, 0xCC5E, 0x5CB5, 0xCC5F, 0x5CAF, 0xCC60, 0x5CA8, 0xCC61, 0x5CAC, 0xCC62, 0x5C9F, 0xCC63, 0x5CA3, 0xCC64, 0x5CAD, 0xCC65, 0x5CA2, 0xCC66, 0x5CAA, 0xCC67, 0x5CA7, 0xCC68, 0x5C9D, 0xCC69, 0x5CA5, 0xCC6A, 0x5CB6, 0xCC6B, 0x5CB0, 0xCC6C, 0x5CA6, 0xCC6D, 0x5E17, 0xCC6E, 0x5E14, 0xCC6F, 0x5E19, 0xCC70, 0x5F28, 0xCC71, 0x5F22, 0xCC72, 0x5F23, 0xCC73, 0x5F24, 0xCC74, 0x5F54, 0xCC75, 0x5F82, 0xCC76, 0x5F7E, 0xCC77, 0x5F7D, 0xCC78, 0x5FDE, 0xCC79, 0x5FE5, 0xCC7A, 0x602D, 0xCC7B, 0x6026, 0xCC7C, 0x6019, 0xCC7D, 0x6032, 0xCC7E, 0x600B, 0xCCA1, 0x6034, 0xCCA2, 0x600A, 0xCCA3, 0x6017, 0xCCA4, 0x6033, 0xCCA5, 0x601A, 0xCCA6, 0x601E, 0xCCA7, 0x602C, 0xCCA8, 0x6022, 0xCCA9, 0x600D, 0xCCAA, 0x6010, 0xCCAB, 0x602E, 0xCCAC, 0x6013, 0xCCAD, 0x6011, 0xCCAE, 0x600C, 0xCCAF, 0x6009, 0xCCB0, 0x601C, 0xCCB1, 0x6214, 0xCCB2, 0x623D, 0xCCB3, 0x62AD, 0xCCB4, 0x62B4, 0xCCB5, 0x62D1, 0xCCB6, 0x62BE, 0xCCB7, 0x62AA, 0xCCB8, 0x62B6, 0xCCB9, 0x62CA, 0xCCBA, 0x62AE, 0xCCBB, 0x62B3, 0xCCBC, 0x62AF, 0xCCBD, 0x62BB, 0xCCBE, 0x62A9, 0xCCBF, 0x62B0, 0xCCC0, 0x62B8, 0xCCC1, 0x653D, 0xCCC2, 0x65A8, 0xCCC3, 0x65BB, 0xCCC4, 0x6609, 0xCCC5, 0x65FC, 0xCCC6, 0x6604, 0xCCC7, 0x6612, 0xCCC8, 0x6608, 0xCCC9, 0x65FB, 0xCCCA, 0x6603, 0xCCCB, 0x660B, 0xCCCC, 0x660D, 0xCCCD, 0x6605, 0xCCCE, 0x65FD, 0xCCCF, 0x6611, 0xCCD0, 0x6610, 0xCCD1, 0x66F6, 0xCCD2, 0x670A, 0xCCD3, 0x6785, 0xCCD4, 0x676C, 0xCCD5, 0x678E, 0xCCD6, 0x6792, 0xCCD7, 0x6776, 0xCCD8, 0x677B, 0xCCD9, 0x6798, 0xCCDA, 0x6786, 0xCCDB, 0x6784, 0xCCDC, 0x6774, 0xCCDD, 0x678D, 0xCCDE, 0x678C, 0xCCDF, 0x677A, 0xCCE0, 0x679F, 0xCCE1, 0x6791, 0xCCE2, 0x6799, 0xCCE3, 0x6783, 0xCCE4, 0x677D, 0xCCE5, 0x6781, 0xCCE6, 0x6778, 0xCCE7, 0x6779, 0xCCE8, 0x6794, 0xCCE9, 0x6B25, 0xCCEA, 0x6B80, 0xCCEB, 0x6B7E, 0xCCEC, 0x6BDE, 0xCCED, 0x6C1D, 0xCCEE, 0x6C93, 0xCCEF, 0x6CEC, 0xCCF0, 0x6CEB, 0xCCF1, 0x6CEE, 0xCCF2, 0x6CD9, 0xCCF3, 0x6CB6, 0xCCF4, 0x6CD4, 0xCCF5, 0x6CAD, 0xCCF6, 0x6CE7, 0xCCF7, 0x6CB7, 0xCCF8, 0x6CD0, 0xCCF9, 0x6CC2, 0xCCFA, 0x6CBA, 0xCCFB, 0x6CC3, 0xCCFC, 0x6CC6, 0xCCFD, 0x6CED, 0xCCFE, 0x6CF2, 0xCD40, 0x6CD2, 0xCD41, 0x6CDD, 0xCD42, 0x6CB4, 0xCD43, 0x6C8A, 0xCD44, 0x6C9D, 0xCD45, 0x6C80, 0xCD46, 0x6CDE, 0xCD47, 0x6CC0, 0xCD48, 0x6D30, 0xCD49, 0x6CCD, 0xCD4A, 0x6CC7, 0xCD4B, 0x6CB0, 0xCD4C, 0x6CF9, 0xCD4D, 0x6CCF, 0xCD4E, 0x6CE9, 0xCD4F, 0x6CD1, 0xCD50, 0x7094, 0xCD51, 0x7098, 0xCD52, 0x7085, 0xCD53, 0x7093, 0xCD54, 0x7086, 0xCD55, 0x7084, 0xCD56, 0x7091, 0xCD57, 0x7096, 0xCD58, 0x7082, 0xCD59, 0x709A, 0xCD5A, 0x7083, 0xCD5B, 0x726A, 0xCD5C, 0x72D6, 0xCD5D, 0x72CB, 0xCD5E, 0x72D8, 0xCD5F, 0x72C9, 0xCD60, 0x72DC, 0xCD61, 0x72D2, 0xCD62, 0x72D4, 0xCD63, 0x72DA, 0xCD64, 0x72CC, 0xCD65, 0x72D1, 0xCD66, 0x73A4, 0xCD67, 0x73A1, 0xCD68, 0x73AD, 0xCD69, 0x73A6, 0xCD6A, 0x73A2, 0xCD6B, 0x73A0, 0xCD6C, 0x73AC, 0xCD6D, 0x739D, 0xCD6E, 0x74DD, 0xCD6F, 0x74E8, 0xCD70, 0x753F, 0xCD71, 0x7540, 0xCD72, 0x753E, 0xCD73, 0x758C, 0xCD74, 0x7598, 0xCD75, 0x76AF, 0xCD76, 0x76F3, 0xCD77, 0x76F1, 0xCD78, 0x76F0, 0xCD79, 0x76F5, 0xCD7A, 0x77F8, 0xCD7B, 0x77FC, 0xCD7C, 0x77F9, 0xCD7D, 0x77FB, 0xCD7E, 0x77FA, 0xCDA1, 0x77F7, 0xCDA2, 0x7942, 0xCDA3, 0x793F, 0xCDA4, 0x79C5, 0xCDA5, 0x7A78, 0xCDA6, 0x7A7B, 0xCDA7, 0x7AFB, 0xCDA8, 0x7C75, 0xCDA9, 0x7CFD, 0xCDAA, 0x8035, 0xCDAB, 0x808F, 0xCDAC, 0x80AE, 0xCDAD, 0x80A3, 0xCDAE, 0x80B8, 0xCDAF, 0x80B5, 0xCDB0, 0x80AD, 0xCDB1, 0x8220, 0xCDB2, 0x82A0, 0xCDB3, 0x82C0, 0xCDB4, 0x82AB, 0xCDB5, 0x829A, 0xCDB6, 0x8298, 0xCDB7, 0x829B, 0xCDB8, 0x82B5, 0xCDB9, 0x82A7, 0xCDBA, 0x82AE, 0xCDBB, 0x82BC, 0xCDBC, 0x829E, 0xCDBD, 0x82BA, 0xCDBE, 0x82B4, 0xCDBF, 0x82A8, 0xCDC0, 0x82A1, 0xCDC1, 0x82A9, 0xCDC2, 0x82C2, 0xCDC3, 0x82A4, 0xCDC4, 0x82C3, 0xCDC5, 0x82B6, 0xCDC6, 0x82A2, 0xCDC7, 0x8670, 0xCDC8, 0x866F, 0xCDC9, 0x866D, 0xCDCA, 0x866E, 0xCDCB, 0x8C56, 0xCDCC, 0x8FD2, 0xCDCD, 0x8FCB, 0xCDCE, 0x8FD3, 0xCDCF, 0x8FCD, 0xCDD0, 0x8FD6, 0xCDD1, 0x8FD5, 0xCDD2, 0x8FD7, 0xCDD3, 0x90B2, 0xCDD4, 0x90B4, 0xCDD5, 0x90AF, 0xCDD6, 0x90B3, 0xCDD7, 0x90B0, 0xCDD8, 0x9639, 0xCDD9, 0x963D, 0xCDDA, 0x963C, 0xCDDB, 0x963A, 0xCDDC, 0x9643, 0xCDDD, 0x4FCD, 0xCDDE, 0x4FC5, 0xCDDF, 0x4FD3, 0xCDE0, 0x4FB2, 0xCDE1, 0x4FC9, 0xCDE2, 0x4FCB, 0xCDE3, 0x4FC1, 0xCDE4, 0x4FD4, 0xCDE5, 0x4FDC, 0xCDE6, 0x4FD9, 0xCDE7, 0x4FBB, 0xCDE8, 0x4FB3, 0xCDE9, 0x4FDB, 0xCDEA, 0x4FC7, 0xCDEB, 0x4FD6, 0xCDEC, 0x4FBA, 0xCDED, 0x4FC0, 0xCDEE, 0x4FB9, 0xCDEF, 0x4FEC, 0xCDF0, 0x5244, 0xCDF1, 0x5249, 0xCDF2, 0x52C0, 0xCDF3, 0x52C2, 0xCDF4, 0x533D, 0xCDF5, 0x537C, 0xCDF6, 0x5397, 0xCDF7, 0x5396, 0xCDF8, 0x5399, 0xCDF9, 0x5398, 0xCDFA, 0x54BA, 0xCDFB, 0x54A1, 0xCDFC, 0x54AD, 0xCDFD, 0x54A5, 0xCDFE, 0x54CF, 0xCE40, 0x54C3, 0xCE41, 0x830D, 0xCE42, 0x54B7, 0xCE43, 0x54AE, 0xCE44, 0x54D6, 0xCE45, 0x54B6, 0xCE46, 0x54C5, 0xCE47, 0x54C6, 0xCE48, 0x54A0, 0xCE49, 0x5470, 0xCE4A, 0x54BC, 0xCE4B, 0x54A2, 0xCE4C, 0x54BE, 0xCE4D, 0x5472, 0xCE4E, 0x54DE, 0xCE4F, 0x54B0, 0xCE50, 0x57B5, 0xCE51, 0x579E, 0xCE52, 0x579F, 0xCE53, 0x57A4, 0xCE54, 0x578C, 0xCE55, 0x5797, 0xCE56, 0x579D, 0xCE57, 0x579B, 0xCE58, 0x5794, 0xCE59, 0x5798, 0xCE5A, 0x578F, 0xCE5B, 0x5799, 0xCE5C, 0x57A5, 0xCE5D, 0x579A, 0xCE5E, 0x5795, 0xCE5F, 0x58F4, 0xCE60, 0x590D, 0xCE61, 0x5953, 0xCE62, 0x59E1, 0xCE63, 0x59DE, 0xCE64, 0x59EE, 0xCE65, 0x5A00, 0xCE66, 0x59F1, 0xCE67, 0x59DD, 0xCE68, 0x59FA, 0xCE69, 0x59FD, 0xCE6A, 0x59FC, 0xCE6B, 0x59F6, 0xCE6C, 0x59E4, 0xCE6D, 0x59F2, 0xCE6E, 0x59F7, 0xCE6F, 0x59DB, 0xCE70, 0x59E9, 0xCE71, 0x59F3, 0xCE72, 0x59F5, 0xCE73, 0x59E0, 0xCE74, 0x59FE, 0xCE75, 0x59F4, 0xCE76, 0x59ED, 0xCE77, 0x5BA8, 0xCE78, 0x5C4C, 0xCE79, 0x5CD0, 0xCE7A, 0x5CD8, 0xCE7B, 0x5CCC, 0xCE7C, 0x5CD7, 0xCE7D, 0x5CCB, 0xCE7E, 0x5CDB, 0xCEA1, 0x5CDE, 0xCEA2, 0x5CDA, 0xCEA3, 0x5CC9, 0xCEA4, 0x5CC7, 0xCEA5, 0x5CCA, 0xCEA6, 0x5CD6, 0xCEA7, 0x5CD3, 0xCEA8, 0x5CD4, 0xCEA9, 0x5CCF, 0xCEAA, 0x5CC8, 0xCEAB, 0x5CC6, 0xCEAC, 0x5CCE, 0xCEAD, 0x5CDF, 0xCEAE, 0x5CF8, 0xCEAF, 0x5DF9, 0xCEB0, 0x5E21, 0xCEB1, 0x5E22, 0xCEB2, 0x5E23, 0xCEB3, 0x5E20, 0xCEB4, 0x5E24, 0xCEB5, 0x5EB0, 0xCEB6, 0x5EA4, 0xCEB7, 0x5EA2, 0xCEB8, 0x5E9B, 0xCEB9, 0x5EA3, 0xCEBA, 0x5EA5, 0xCEBB, 0x5F07, 0xCEBC, 0x5F2E, 0xCEBD, 0x5F56, 0xCEBE, 0x5F86, 0xCEBF, 0x6037, 0xCEC0, 0x6039, 0xCEC1, 0x6054, 0xCEC2, 0x6072, 0xCEC3, 0x605E, 0xCEC4, 0x6045, 0xCEC5, 0x6053, 0xCEC6, 0x6047, 0xCEC7, 0x6049, 0xCEC8, 0x605B, 0xCEC9, 0x604C, 0xCECA, 0x6040, 0xCECB, 0x6042, 0xCECC, 0x605F, 0xCECD, 0x6024, 0xCECE, 0x6044, 0xCECF, 0x6058, 0xCED0, 0x6066, 0xCED1, 0x606E, 0xCED2, 0x6242, 0xCED3, 0x6243, 0xCED4, 0x62CF, 0xCED5, 0x630D, 0xCED6, 0x630B, 0xCED7, 0x62F5, 0xCED8, 0x630E, 0xCED9, 0x6303, 0xCEDA, 0x62EB, 0xCEDB, 0x62F9, 0xCEDC, 0x630F, 0xCEDD, 0x630C, 0xCEDE, 0x62F8, 0xCEDF, 0x62F6, 0xCEE0, 0x6300, 0xCEE1, 0x6313, 0xCEE2, 0x6314, 0xCEE3, 0x62FA, 0xCEE4, 0x6315, 0xCEE5, 0x62FB, 0xCEE6, 0x62F0, 0xCEE7, 0x6541, 0xCEE8, 0x6543, 0xCEE9, 0x65AA, 0xCEEA, 0x65BF, 0xCEEB, 0x6636, 0xCEEC, 0x6621, 0xCEED, 0x6632, 0xCEEE, 0x6635, 0xCEEF, 0x661C, 0xCEF0, 0x6626, 0xCEF1, 0x6622, 0xCEF2, 0x6633, 0xCEF3, 0x662B, 0xCEF4, 0x663A, 0xCEF5, 0x661D, 0xCEF6, 0x6634, 0xCEF7, 0x6639, 0xCEF8, 0x662E, 0xCEF9, 0x670F, 0xCEFA, 0x6710, 0xCEFB, 0x67C1, 0xCEFC, 0x67F2, 0xCEFD, 0x67C8, 0xCEFE, 0x67BA, 0xCF40, 0x67DC, 0xCF41, 0x67BB, 0xCF42, 0x67F8, 0xCF43, 0x67D8, 0xCF44, 0x67C0, 0xCF45, 0x67B7, 0xCF46, 0x67C5, 0xCF47, 0x67EB, 0xCF48, 0x67E4, 0xCF49, 0x67DF, 0xCF4A, 0x67B5, 0xCF4B, 0x67CD, 0xCF4C, 0x67B3, 0xCF4D, 0x67F7, 0xCF4E, 0x67F6, 0xCF4F, 0x67EE, 0xCF50, 0x67E3, 0xCF51, 0x67C2, 0xCF52, 0x67B9, 0xCF53, 0x67CE, 0xCF54, 0x67E7, 0xCF55, 0x67F0, 0xCF56, 0x67B2, 0xCF57, 0x67FC, 0xCF58, 0x67C6, 0xCF59, 0x67ED, 0xCF5A, 0x67CC, 0xCF5B, 0x67AE, 0xCF5C, 0x67E6, 0xCF5D, 0x67DB, 0xCF5E, 0x67FA, 0xCF5F, 0x67C9, 0xCF60, 0x67CA, 0xCF61, 0x67C3, 0xCF62, 0x67EA, 0xCF63, 0x67CB, 0xCF64, 0x6B28, 0xCF65, 0x6B82, 0xCF66, 0x6B84, 0xCF67, 0x6BB6, 0xCF68, 0x6BD6, 0xCF69, 0x6BD8, 0xCF6A, 0x6BE0, 0xCF6B, 0x6C20, 0xCF6C, 0x6C21, 0xCF6D, 0x6D28, 0xCF6E, 0x6D34, 0xCF6F, 0x6D2D, 0xCF70, 0x6D1F, 0xCF71, 0x6D3C, 0xCF72, 0x6D3F, 0xCF73, 0x6D12, 0xCF74, 0x6D0A, 0xCF75, 0x6CDA, 0xCF76, 0x6D33, 0xCF77, 0x6D04, 0xCF78, 0x6D19, 0xCF79, 0x6D3A, 0xCF7A, 0x6D1A, 0xCF7B, 0x6D11, 0xCF7C, 0x6D00, 0xCF7D, 0x6D1D, 0xCF7E, 0x6D42, 0xCFA1, 0x6D01, 0xCFA2, 0x6D18, 0xCFA3, 0x6D37, 0xCFA4, 0x6D03, 0xCFA5, 0x6D0F, 0xCFA6, 0x6D40, 0xCFA7, 0x6D07, 0xCFA8, 0x6D20, 0xCFA9, 0x6D2C, 0xCFAA, 0x6D08, 0xCFAB, 0x6D22, 0xCFAC, 0x6D09, 0xCFAD, 0x6D10, 0xCFAE, 0x70B7, 0xCFAF, 0x709F, 0xCFB0, 0x70BE, 0xCFB1, 0x70B1, 0xCFB2, 0x70B0, 0xCFB3, 0x70A1, 0xCFB4, 0x70B4, 0xCFB5, 0x70B5, 0xCFB6, 0x70A9, 0xCFB7, 0x7241, 0xCFB8, 0x7249, 0xCFB9, 0x724A, 0xCFBA, 0x726C, 0xCFBB, 0x7270, 0xCFBC, 0x7273, 0xCFBD, 0x726E, 0xCFBE, 0x72CA, 0xCFBF, 0x72E4, 0xCFC0, 0x72E8, 0xCFC1, 0x72EB, 0xCFC2, 0x72DF, 0xCFC3, 0x72EA, 0xCFC4, 0x72E6, 0xCFC5, 0x72E3, 0xCFC6, 0x7385, 0xCFC7, 0x73CC, 0xCFC8, 0x73C2, 0xCFC9, 0x73C8, 0xCFCA, 0x73C5, 0xCFCB, 0x73B9, 0xCFCC, 0x73B6, 0xCFCD, 0x73B5, 0xCFCE, 0x73B4, 0xCFCF, 0x73EB, 0xCFD0, 0x73BF, 0xCFD1, 0x73C7, 0xCFD2, 0x73BE, 0xCFD3, 0x73C3, 0xCFD4, 0x73C6, 0xCFD5, 0x73B8, 0xCFD6, 0x73CB, 0xCFD7, 0x74EC, 0xCFD8, 0x74EE, 0xCFD9, 0x752E, 0xCFDA, 0x7547, 0xCFDB, 0x7548, 0xCFDC, 0x75A7, 0xCFDD, 0x75AA, 0xCFDE, 0x7679, 0xCFDF, 0x76C4, 0xCFE0, 0x7708, 0xCFE1, 0x7703, 0xCFE2, 0x7704, 0xCFE3, 0x7705, 0xCFE4, 0x770A, 0xCFE5, 0x76F7, 0xCFE6, 0x76FB, 0xCFE7, 0x76FA, 0xCFE8, 0x77E7, 0xCFE9, 0x77E8, 0xCFEA, 0x7806, 0xCFEB, 0x7811, 0xCFEC, 0x7812, 0xCFED, 0x7805, 0xCFEE, 0x7810, 0xCFEF, 0x780F, 0xCFF0, 0x780E, 0xCFF1, 0x7809, 0xCFF2, 0x7803, 0xCFF3, 0x7813, 0xCFF4, 0x794A, 0xCFF5, 0x794C, 0xCFF6, 0x794B, 0xCFF7, 0x7945, 0xCFF8, 0x7944, 0xCFF9, 0x79D5, 0xCFFA, 0x79CD, 0xCFFB, 0x79CF, 0xCFFC, 0x79D6, 0xCFFD, 0x79CE, 0xCFFE, 0x7A80, 0xD040, 0x7A7E, 0xD041, 0x7AD1, 0xD042, 0x7B00, 0xD043, 0x7B01, 0xD044, 0x7C7A, 0xD045, 0x7C78, 0xD046, 0x7C79, 0xD047, 0x7C7F, 0xD048, 0x7C80, 0xD049, 0x7C81, 0xD04A, 0x7D03, 0xD04B, 0x7D08, 0xD04C, 0x7D01, 0xD04D, 0x7F58, 0xD04E, 0x7F91, 0xD04F, 0x7F8D, 0xD050, 0x7FBE, 0xD051, 0x8007, 0xD052, 0x800E, 0xD053, 0x800F, 0xD054, 0x8014, 0xD055, 0x8037, 0xD056, 0x80D8, 0xD057, 0x80C7, 0xD058, 0x80E0, 0xD059, 0x80D1, 0xD05A, 0x80C8, 0xD05B, 0x80C2, 0xD05C, 0x80D0, 0xD05D, 0x80C5, 0xD05E, 0x80E3, 0xD05F, 0x80D9, 0xD060, 0x80DC, 0xD061, 0x80CA, 0xD062, 0x80D5, 0xD063, 0x80C9, 0xD064, 0x80CF, 0xD065, 0x80D7, 0xD066, 0x80E6, 0xD067, 0x80CD, 0xD068, 0x81FF, 0xD069, 0x8221, 0xD06A, 0x8294, 0xD06B, 0x82D9, 0xD06C, 0x82FE, 0xD06D, 0x82F9, 0xD06E, 0x8307, 0xD06F, 0x82E8, 0xD070, 0x8300, 0xD071, 0x82D5, 0xD072, 0x833A, 0xD073, 0x82EB, 0xD074, 0x82D6, 0xD075, 0x82F4, 0xD076, 0x82EC, 0xD077, 0x82E1, 0xD078, 0x82F2, 0xD079, 0x82F5, 0xD07A, 0x830C, 0xD07B, 0x82FB, 0xD07C, 0x82F6, 0xD07D, 0x82F0, 0xD07E, 0x82EA, 0xD0A1, 0x82E4, 0xD0A2, 0x82E0, 0xD0A3, 0x82FA, 0xD0A4, 0x82F3, 0xD0A5, 0x82ED, 0xD0A6, 0x8677, 0xD0A7, 0x8674, 0xD0A8, 0x867C, 0xD0A9, 0x8673, 0xD0AA, 0x8841, 0xD0AB, 0x884E, 0xD0AC, 0x8867, 0xD0AD, 0x886A, 0xD0AE, 0x8869, 0xD0AF, 0x89D3, 0xD0B0, 0x8A04, 0xD0B1, 0x8A07, 0xD0B2, 0x8D72, 0xD0B3, 0x8FE3, 0xD0B4, 0x8FE1, 0xD0B5, 0x8FEE, 0xD0B6, 0x8FE0, 0xD0B7, 0x90F1, 0xD0B8, 0x90BD, 0xD0B9, 0x90BF, 0xD0BA, 0x90D5, 0xD0BB, 0x90C5, 0xD0BC, 0x90BE, 0xD0BD, 0x90C7, 0xD0BE, 0x90CB, 0xD0BF, 0x90C8, 0xD0C0, 0x91D4, 0xD0C1, 0x91D3, 0xD0C2, 0x9654, 0xD0C3, 0x964F, 0xD0C4, 0x9651, 0xD0C5, 0x9653, 0xD0C6, 0x964A, 0xD0C7, 0x964E, 0xD0C8, 0x501E, 0xD0C9, 0x5005, 0xD0CA, 0x5007, 0xD0CB, 0x5013, 0xD0CC, 0x5022, 0xD0CD, 0x5030, 0xD0CE, 0x501B, 0xD0CF, 0x4FF5, 0xD0D0, 0x4FF4, 0xD0D1, 0x5033, 0xD0D2, 0x5037, 0xD0D3, 0x502C, 0xD0D4, 0x4FF6, 0xD0D5, 0x4FF7, 0xD0D6, 0x5017, 0xD0D7, 0x501C, 0xD0D8, 0x5020, 0xD0D9, 0x5027, 0xD0DA, 0x5035, 0xD0DB, 0x502F, 0xD0DC, 0x5031, 0xD0DD, 0x500E, 0xD0DE, 0x515A, 0xD0DF, 0x5194, 0xD0E0, 0x5193, 0xD0E1, 0x51CA, 0xD0E2, 0x51C4, 0xD0E3, 0x51C5, 0xD0E4, 0x51C8, 0xD0E5, 0x51CE, 0xD0E6, 0x5261, 0xD0E7, 0x525A, 0xD0E8, 0x5252, 0xD0E9, 0x525E, 0xD0EA, 0x525F, 0xD0EB, 0x5255, 0xD0EC, 0x5262, 0xD0ED, 0x52CD, 0xD0EE, 0x530E, 0xD0EF, 0x539E, 0xD0F0, 0x5526, 0xD0F1, 0x54E2, 0xD0F2, 0x5517, 0xD0F3, 0x5512, 0xD0F4, 0x54E7, 0xD0F5, 0x54F3, 0xD0F6, 0x54E4, 0xD0F7, 0x551A, 0xD0F8, 0x54FF, 0xD0F9, 0x5504, 0xD0FA, 0x5508, 0xD0FB, 0x54EB, 0xD0FC, 0x5511, 0xD0FD, 0x5505, 0xD0FE, 0x54F1, 0xD140, 0x550A, 0xD141, 0x54FB, 0xD142, 0x54F7, 0xD143, 0x54F8, 0xD144, 0x54E0, 0xD145, 0x550E, 0xD146, 0x5503, 0xD147, 0x550B, 0xD148, 0x5701, 0xD149, 0x5702, 0xD14A, 0x57CC, 0xD14B, 0x5832, 0xD14C, 0x57D5, 0xD14D, 0x57D2, 0xD14E, 0x57BA, 0xD14F, 0x57C6, 0xD150, 0x57BD, 0xD151, 0x57BC, 0xD152, 0x57B8, 0xD153, 0x57B6, 0xD154, 0x57BF, 0xD155, 0x57C7, 0xD156, 0x57D0, 0xD157, 0x57B9, 0xD158, 0x57C1, 0xD159, 0x590E, 0xD15A, 0x594A, 0xD15B, 0x5A19, 0xD15C, 0x5A16, 0xD15D, 0x5A2D, 0xD15E, 0x5A2E, 0xD15F, 0x5A15, 0xD160, 0x5A0F, 0xD161, 0x5A17, 0xD162, 0x5A0A, 0xD163, 0x5A1E, 0xD164, 0x5A33, 0xD165, 0x5B6C, 0xD166, 0x5BA7, 0xD167, 0x5BAD, 0xD168, 0x5BAC, 0xD169, 0x5C03, 0xD16A, 0x5C56, 0xD16B, 0x5C54, 0xD16C, 0x5CEC, 0xD16D, 0x5CFF, 0xD16E, 0x5CEE, 0xD16F, 0x5CF1, 0xD170, 0x5CF7, 0xD171, 0x5D00, 0xD172, 0x5CF9, 0xD173, 0x5E29, 0xD174, 0x5E28, 0xD175, 0x5EA8, 0xD176, 0x5EAE, 0xD177, 0x5EAA, 0xD178, 0x5EAC, 0xD179, 0x5F33, 0xD17A, 0x5F30, 0xD17B, 0x5F67, 0xD17C, 0x605D, 0xD17D, 0x605A, 0xD17E, 0x6067, 0xD1A1, 0x6041, 0xD1A2, 0x60A2, 0xD1A3, 0x6088, 0xD1A4, 0x6080, 0xD1A5, 0x6092, 0xD1A6, 0x6081, 0xD1A7, 0x609D, 0xD1A8, 0x6083, 0xD1A9, 0x6095, 0xD1AA, 0x609B, 0xD1AB, 0x6097, 0xD1AC, 0x6087, 0xD1AD, 0x609C, 0xD1AE, 0x608E, 0xD1AF, 0x6219, 0xD1B0, 0x6246, 0xD1B1, 0x62F2, 0xD1B2, 0x6310, 0xD1B3, 0x6356, 0xD1B4, 0x632C, 0xD1B5, 0x6344, 0xD1B6, 0x6345, 0xD1B7, 0x6336, 0xD1B8, 0x6343, 0xD1B9, 0x63E4, 0xD1BA, 0x6339, 0xD1BB, 0x634B, 0xD1BC, 0x634A, 0xD1BD, 0x633C, 0xD1BE, 0x6329, 0xD1BF, 0x6341, 0xD1C0, 0x6334, 0xD1C1, 0x6358, 0xD1C2, 0x6354, 0xD1C3, 0x6359, 0xD1C4, 0x632D, 0xD1C5, 0x6347, 0xD1C6, 0x6333, 0xD1C7, 0x635A, 0xD1C8, 0x6351, 0xD1C9, 0x6338, 0xD1CA, 0x6357, 0xD1CB, 0x6340, 0xD1CC, 0x6348, 0xD1CD, 0x654A, 0xD1CE, 0x6546, 0xD1CF, 0x65C6, 0xD1D0, 0x65C3, 0xD1D1, 0x65C4, 0xD1D2, 0x65C2, 0xD1D3, 0x664A, 0xD1D4, 0x665F, 0xD1D5, 0x6647, 0xD1D6, 0x6651, 0xD1D7, 0x6712, 0xD1D8, 0x6713, 0xD1D9, 0x681F, 0xD1DA, 0x681A, 0xD1DB, 0x6849, 0xD1DC, 0x6832, 0xD1DD, 0x6833, 0xD1DE, 0x683B, 0xD1DF, 0x684B, 0xD1E0, 0x684F, 0xD1E1, 0x6816, 0xD1E2, 0x6831, 0xD1E3, 0x681C, 0xD1E4, 0x6835, 0xD1E5, 0x682B, 0xD1E6, 0x682D, 0xD1E7, 0x682F, 0xD1E8, 0x684E, 0xD1E9, 0x6844, 0xD1EA, 0x6834, 0xD1EB, 0x681D, 0xD1EC, 0x6812, 0xD1ED, 0x6814, 0xD1EE, 0x6826, 0xD1EF, 0x6828, 0xD1F0, 0x682E, 0xD1F1, 0x684D, 0xD1F2, 0x683A, 0xD1F3, 0x6825, 0xD1F4, 0x6820, 0xD1F5, 0x6B2C, 0xD1F6, 0x6B2F, 0xD1F7, 0x6B2D, 0xD1F8, 0x6B31, 0xD1F9, 0x6B34, 0xD1FA, 0x6B6D, 0xD1FB, 0x8082, 0xD1FC, 0x6B88, 0xD1FD, 0x6BE6, 0xD1FE, 0x6BE4, 0xD240, 0x6BE8, 0xD241, 0x6BE3, 0xD242, 0x6BE2, 0xD243, 0x6BE7, 0xD244, 0x6C25, 0xD245, 0x6D7A, 0xD246, 0x6D63, 0xD247, 0x6D64, 0xD248, 0x6D76, 0xD249, 0x6D0D, 0xD24A, 0x6D61, 0xD24B, 0x6D92, 0xD24C, 0x6D58, 0xD24D, 0x6D62, 0xD24E, 0x6D6D, 0xD24F, 0x6D6F, 0xD250, 0x6D91, 0xD251, 0x6D8D, 0xD252, 0x6DEF, 0xD253, 0x6D7F, 0xD254, 0x6D86, 0xD255, 0x6D5E, 0xD256, 0x6D67, 0xD257, 0x6D60, 0xD258, 0x6D97, 0xD259, 0x6D70, 0xD25A, 0x6D7C, 0xD25B, 0x6D5F, 0xD25C, 0x6D82, 0xD25D, 0x6D98, 0xD25E, 0x6D2F, 0xD25F, 0x6D68, 0xD260, 0x6D8B, 0xD261, 0x6D7E, 0xD262, 0x6D80, 0xD263, 0x6D84, 0xD264, 0x6D16, 0xD265, 0x6D83, 0xD266, 0x6D7B, 0xD267, 0x6D7D, 0xD268, 0x6D75, 0xD269, 0x6D90, 0xD26A, 0x70DC, 0xD26B, 0x70D3, 0xD26C, 0x70D1, 0xD26D, 0x70DD, 0xD26E, 0x70CB, 0xD26F, 0x7F39, 0xD270, 0x70E2, 0xD271, 0x70D7, 0xD272, 0x70D2, 0xD273, 0x70DE, 0xD274, 0x70E0, 0xD275, 0x70D4, 0xD276, 0x70CD, 0xD277, 0x70C5, 0xD278, 0x70C6, 0xD279, 0x70C7, 0xD27A, 0x70DA, 0xD27B, 0x70CE, 0xD27C, 0x70E1, 0xD27D, 0x7242, 0xD27E, 0x7278, 0xD2A1, 0x7277, 0xD2A2, 0x7276, 0xD2A3, 0x7300, 0xD2A4, 0x72FA, 0xD2A5, 0x72F4, 0xD2A6, 0x72FE, 0xD2A7, 0x72F6, 0xD2A8, 0x72F3, 0xD2A9, 0x72FB, 0xD2AA, 0x7301, 0xD2AB, 0x73D3, 0xD2AC, 0x73D9, 0xD2AD, 0x73E5, 0xD2AE, 0x73D6, 0xD2AF, 0x73BC, 0xD2B0, 0x73E7, 0xD2B1, 0x73E3, 0xD2B2, 0x73E9, 0xD2B3, 0x73DC, 0xD2B4, 0x73D2, 0xD2B5, 0x73DB, 0xD2B6, 0x73D4, 0xD2B7, 0x73DD, 0xD2B8, 0x73DA, 0xD2B9, 0x73D7, 0xD2BA, 0x73D8, 0xD2BB, 0x73E8, 0xD2BC, 0x74DE, 0xD2BD, 0x74DF, 0xD2BE, 0x74F4, 0xD2BF, 0x74F5, 0xD2C0, 0x7521, 0xD2C1, 0x755B, 0xD2C2, 0x755F, 0xD2C3, 0x75B0, 0xD2C4, 0x75C1, 0xD2C5, 0x75BB, 0xD2C6, 0x75C4, 0xD2C7, 0x75C0, 0xD2C8, 0x75BF, 0xD2C9, 0x75B6, 0xD2CA, 0x75BA, 0xD2CB, 0x768A, 0xD2CC, 0x76C9, 0xD2CD, 0x771D, 0xD2CE, 0x771B, 0xD2CF, 0x7710, 0xD2D0, 0x7713, 0xD2D1, 0x7712, 0xD2D2, 0x7723, 0xD2D3, 0x7711, 0xD2D4, 0x7715, 0xD2D5, 0x7719, 0xD2D6, 0x771A, 0xD2D7, 0x7722, 0xD2D8, 0x7727, 0xD2D9, 0x7823, 0xD2DA, 0x782C, 0xD2DB, 0x7822, 0xD2DC, 0x7835, 0xD2DD, 0x782F, 0xD2DE, 0x7828, 0xD2DF, 0x782E, 0xD2E0, 0x782B, 0xD2E1, 0x7821, 0xD2E2, 0x7829, 0xD2E3, 0x7833, 0xD2E4, 0x782A, 0xD2E5, 0x7831, 0xD2E6, 0x7954, 0xD2E7, 0x795B, 0xD2E8, 0x794F, 0xD2E9, 0x795C, 0xD2EA, 0x7953, 0xD2EB, 0x7952, 0xD2EC, 0x7951, 0xD2ED, 0x79EB, 0xD2EE, 0x79EC, 0xD2EF, 0x79E0, 0xD2F0, 0x79EE, 0xD2F1, 0x79ED, 0xD2F2, 0x79EA, 0xD2F3, 0x79DC, 0xD2F4, 0x79DE, 0xD2F5, 0x79DD, 0xD2F6, 0x7A86, 0xD2F7, 0x7A89, 0xD2F8, 0x7A85, 0xD2F9, 0x7A8B, 0xD2FA, 0x7A8C, 0xD2FB, 0x7A8A, 0xD2FC, 0x7A87, 0xD2FD, 0x7AD8, 0xD2FE, 0x7B10, 0xD340, 0x7B04, 0xD341, 0x7B13, 0xD342, 0x7B05, 0xD343, 0x7B0F, 0xD344, 0x7B08, 0xD345, 0x7B0A, 0xD346, 0x7B0E, 0xD347, 0x7B09, 0xD348, 0x7B12, 0xD349, 0x7C84, 0xD34A, 0x7C91, 0xD34B, 0x7C8A, 0xD34C, 0x7C8C, 0xD34D, 0x7C88, 0xD34E, 0x7C8D, 0xD34F, 0x7C85, 0xD350, 0x7D1E, 0xD351, 0x7D1D, 0xD352, 0x7D11, 0xD353, 0x7D0E, 0xD354, 0x7D18, 0xD355, 0x7D16, 0xD356, 0x7D13, 0xD357, 0x7D1F, 0xD358, 0x7D12, 0xD359, 0x7D0F, 0xD35A, 0x7D0C, 0xD35B, 0x7F5C, 0xD35C, 0x7F61, 0xD35D, 0x7F5E, 0xD35E, 0x7F60, 0xD35F, 0x7F5D, 0xD360, 0x7F5B, 0xD361, 0x7F96, 0xD362, 0x7F92, 0xD363, 0x7FC3, 0xD364, 0x7FC2, 0xD365, 0x7FC0, 0xD366, 0x8016, 0xD367, 0x803E, 0xD368, 0x8039, 0xD369, 0x80FA, 0xD36A, 0x80F2, 0xD36B, 0x80F9, 0xD36C, 0x80F5, 0xD36D, 0x8101, 0xD36E, 0x80FB, 0xD36F, 0x8100, 0xD370, 0x8201, 0xD371, 0x822F, 0xD372, 0x8225, 0xD373, 0x8333, 0xD374, 0x832D, 0xD375, 0x8344, 0xD376, 0x8319, 0xD377, 0x8351, 0xD378, 0x8325, 0xD379, 0x8356, 0xD37A, 0x833F, 0xD37B, 0x8341, 0xD37C, 0x8326, 0xD37D, 0x831C, 0xD37E, 0x8322, 0xD3A1, 0x8342, 0xD3A2, 0x834E, 0xD3A3, 0x831B, 0xD3A4, 0x832A, 0xD3A5, 0x8308, 0xD3A6, 0x833C, 0xD3A7, 0x834D, 0xD3A8, 0x8316, 0xD3A9, 0x8324, 0xD3AA, 0x8320, 0xD3AB, 0x8337, 0xD3AC, 0x832F, 0xD3AD, 0x8329, 0xD3AE, 0x8347, 0xD3AF, 0x8345, 0xD3B0, 0x834C, 0xD3B1, 0x8353, 0xD3B2, 0x831E, 0xD3B3, 0x832C, 0xD3B4, 0x834B, 0xD3B5, 0x8327, 0xD3B6, 0x8348, 0xD3B7, 0x8653, 0xD3B8, 0x8652, 0xD3B9, 0x86A2, 0xD3BA, 0x86A8, 0xD3BB, 0x8696, 0xD3BC, 0x868D, 0xD3BD, 0x8691, 0xD3BE, 0x869E, 0xD3BF, 0x8687, 0xD3C0, 0x8697, 0xD3C1, 0x8686, 0xD3C2, 0x868B, 0xD3C3, 0x869A, 0xD3C4, 0x8685, 0xD3C5, 0x86A5, 0xD3C6, 0x8699, 0xD3C7, 0x86A1, 0xD3C8, 0x86A7, 0xD3C9, 0x8695, 0xD3CA, 0x8698, 0xD3CB, 0x868E, 0xD3CC, 0x869D, 0xD3CD, 0x8690, 0xD3CE, 0x8694, 0xD3CF, 0x8843, 0xD3D0, 0x8844, 0xD3D1, 0x886D, 0xD3D2, 0x8875, 0xD3D3, 0x8876, 0xD3D4, 0x8872, 0xD3D5, 0x8880, 0xD3D6, 0x8871, 0xD3D7, 0x887F, 0xD3D8, 0x886F, 0xD3D9, 0x8883, 0xD3DA, 0x887E, 0xD3DB, 0x8874, 0xD3DC, 0x887C, 0xD3DD, 0x8A12, 0xD3DE, 0x8C47, 0xD3DF, 0x8C57, 0xD3E0, 0x8C7B, 0xD3E1, 0x8CA4, 0xD3E2, 0x8CA3, 0xD3E3, 0x8D76, 0xD3E4, 0x8D78, 0xD3E5, 0x8DB5, 0xD3E6, 0x8DB7, 0xD3E7, 0x8DB6, 0xD3E8, 0x8ED1, 0xD3E9, 0x8ED3, 0xD3EA, 0x8FFE, 0xD3EB, 0x8FF5, 0xD3EC, 0x9002, 0xD3ED, 0x8FFF, 0xD3EE, 0x8FFB, 0xD3EF, 0x9004, 0xD3F0, 0x8FFC, 0xD3F1, 0x8FF6, 0xD3F2, 0x90D6, 0xD3F3, 0x90E0, 0xD3F4, 0x90D9, 0xD3F5, 0x90DA, 0xD3F6, 0x90E3, 0xD3F7, 0x90DF, 0xD3F8, 0x90E5, 0xD3F9, 0x90D8, 0xD3FA, 0x90DB, 0xD3FB, 0x90D7, 0xD3FC, 0x90DC, 0xD3FD, 0x90E4, 0xD3FE, 0x9150, 0xD440, 0x914E, 0xD441, 0x914F, 0xD442, 0x91D5, 0xD443, 0x91E2, 0xD444, 0x91DA, 0xD445, 0x965C, 0xD446, 0x965F, 0xD447, 0x96BC, 0xD448, 0x98E3, 0xD449, 0x9ADF, 0xD44A, 0x9B2F, 0xD44B, 0x4E7F, 0xD44C, 0x5070, 0xD44D, 0x506A, 0xD44E, 0x5061, 0xD44F, 0x505E, 0xD450, 0x5060, 0xD451, 0x5053, 0xD452, 0x504B, 0xD453, 0x505D, 0xD454, 0x5072, 0xD455, 0x5048, 0xD456, 0x504D, 0xD457, 0x5041, 0xD458, 0x505B, 0xD459, 0x504A, 0xD45A, 0x5062, 0xD45B, 0x5015, 0xD45C, 0x5045, 0xD45D, 0x505F, 0xD45E, 0x5069, 0xD45F, 0x506B, 0xD460, 0x5063, 0xD461, 0x5064, 0xD462, 0x5046, 0xD463, 0x5040, 0xD464, 0x506E, 0xD465, 0x5073, 0xD466, 0x5057, 0xD467, 0x5051, 0xD468, 0x51D0, 0xD469, 0x526B, 0xD46A, 0x526D, 0xD46B, 0x526C, 0xD46C, 0x526E, 0xD46D, 0x52D6, 0xD46E, 0x52D3, 0xD46F, 0x532D, 0xD470, 0x539C, 0xD471, 0x5575, 0xD472, 0x5576, 0xD473, 0x553C, 0xD474, 0x554D, 0xD475, 0x5550, 0xD476, 0x5534, 0xD477, 0x552A, 0xD478, 0x5551, 0xD479, 0x5562, 0xD47A, 0x5536, 0xD47B, 0x5535, 0xD47C, 0x5530, 0xD47D, 0x5552, 0xD47E, 0x5545, 0xD4A1, 0x550C, 0xD4A2, 0x5532, 0xD4A3, 0x5565, 0xD4A4, 0x554E, 0xD4A5, 0x5539, 0xD4A6, 0x5548, 0xD4A7, 0x552D, 0xD4A8, 0x553B, 0xD4A9, 0x5540, 0xD4AA, 0x554B, 0xD4AB, 0x570A, 0xD4AC, 0x5707, 0xD4AD, 0x57FB, 0xD4AE, 0x5814, 0xD4AF, 0x57E2, 0xD4B0, 0x57F6, 0xD4B1, 0x57DC, 0xD4B2, 0x57F4, 0xD4B3, 0x5800, 0xD4B4, 0x57ED, 0xD4B5, 0x57FD, 0xD4B6, 0x5808, 0xD4B7, 0x57F8, 0xD4B8, 0x580B, 0xD4B9, 0x57F3, 0xD4BA, 0x57CF, 0xD4BB, 0x5807, 0xD4BC, 0x57EE, 0xD4BD, 0x57E3, 0xD4BE, 0x57F2, 0xD4BF, 0x57E5, 0xD4C0, 0x57EC, 0xD4C1, 0x57E1, 0xD4C2, 0x580E, 0xD4C3, 0x57FC, 0xD4C4, 0x5810, 0xD4C5, 0x57E7, 0xD4C6, 0x5801, 0xD4C7, 0x580C, 0xD4C8, 0x57F1, 0xD4C9, 0x57E9, 0xD4CA, 0x57F0, 0xD4CB, 0x580D, 0xD4CC, 0x5804, 0xD4CD, 0x595C, 0xD4CE, 0x5A60, 0xD4CF, 0x5A58, 0xD4D0, 0x5A55, 0xD4D1, 0x5A67, 0xD4D2, 0x5A5E, 0xD4D3, 0x5A38, 0xD4D4, 0x5A35, 0xD4D5, 0x5A6D, 0xD4D6, 0x5A50, 0xD4D7, 0x5A5F, 0xD4D8, 0x5A65, 0xD4D9, 0x5A6C, 0xD4DA, 0x5A53, 0xD4DB, 0x5A64, 0xD4DC, 0x5A57, 0xD4DD, 0x5A43, 0xD4DE, 0x5A5D, 0xD4DF, 0x5A52, 0xD4E0, 0x5A44, 0xD4E1, 0x5A5B, 0xD4E2, 0x5A48, 0xD4E3, 0x5A8E, 0xD4E4, 0x5A3E, 0xD4E5, 0x5A4D, 0xD4E6, 0x5A39, 0xD4E7, 0x5A4C, 0xD4E8, 0x5A70, 0xD4E9, 0x5A69, 0xD4EA, 0x5A47, 0xD4EB, 0x5A51, 0xD4EC, 0x5A56, 0xD4ED, 0x5A42, 0xD4EE, 0x5A5C, 0xD4EF, 0x5B72, 0xD4F0, 0x5B6E, 0xD4F1, 0x5BC1, 0xD4F2, 0x5BC0, 0xD4F3, 0x5C59, 0xD4F4, 0x5D1E, 0xD4F5, 0x5D0B, 0xD4F6, 0x5D1D, 0xD4F7, 0x5D1A, 0xD4F8, 0x5D20, 0xD4F9, 0x5D0C, 0xD4FA, 0x5D28, 0xD4FB, 0x5D0D, 0xD4FC, 0x5D26, 0xD4FD, 0x5D25, 0xD4FE, 0x5D0F, 0xD540, 0x5D30, 0xD541, 0x5D12, 0xD542, 0x5D23, 0xD543, 0x5D1F, 0xD544, 0x5D2E, 0xD545, 0x5E3E, 0xD546, 0x5E34, 0xD547, 0x5EB1, 0xD548, 0x5EB4, 0xD549, 0x5EB9, 0xD54A, 0x5EB2, 0xD54B, 0x5EB3, 0xD54C, 0x5F36, 0xD54D, 0x5F38, 0xD54E, 0x5F9B, 0xD54F, 0x5F96, 0xD550, 0x5F9F, 0xD551, 0x608A, 0xD552, 0x6090, 0xD553, 0x6086, 0xD554, 0x60BE, 0xD555, 0x60B0, 0xD556, 0x60BA, 0xD557, 0x60D3, 0xD558, 0x60D4, 0xD559, 0x60CF, 0xD55A, 0x60E4, 0xD55B, 0x60D9, 0xD55C, 0x60DD, 0xD55D, 0x60C8, 0xD55E, 0x60B1, 0xD55F, 0x60DB, 0xD560, 0x60B7, 0xD561, 0x60CA, 0xD562, 0x60BF, 0xD563, 0x60C3, 0xD564, 0x60CD, 0xD565, 0x60C0, 0xD566, 0x6332, 0xD567, 0x6365, 0xD568, 0x638A, 0xD569, 0x6382, 0xD56A, 0x637D, 0xD56B, 0x63BD, 0xD56C, 0x639E, 0xD56D, 0x63AD, 0xD56E, 0x639D, 0xD56F, 0x6397, 0xD570, 0x63AB, 0xD571, 0x638E, 0xD572, 0x636F, 0xD573, 0x6387, 0xD574, 0x6390, 0xD575, 0x636E, 0xD576, 0x63AF, 0xD577, 0x6375, 0xD578, 0x639C, 0xD579, 0x636D, 0xD57A, 0x63AE, 0xD57B, 0x637C, 0xD57C, 0x63A4, 0xD57D, 0x633B, 0xD57E, 0x639F, 0xD5A1, 0x6378, 0xD5A2, 0x6385, 0xD5A3, 0x6381, 0xD5A4, 0x6391, 0xD5A5, 0x638D, 0xD5A6, 0x6370, 0xD5A7, 0x6553, 0xD5A8, 0x65CD, 0xD5A9, 0x6665, 0xD5AA, 0x6661, 0xD5AB, 0x665B, 0xD5AC, 0x6659, 0xD5AD, 0x665C, 0xD5AE, 0x6662, 0xD5AF, 0x6718, 0xD5B0, 0x6879, 0xD5B1, 0x6887, 0xD5B2, 0x6890, 0xD5B3, 0x689C, 0xD5B4, 0x686D, 0xD5B5, 0x686E, 0xD5B6, 0x68AE, 0xD5B7, 0x68AB, 0xD5B8, 0x6956, 0xD5B9, 0x686F, 0xD5BA, 0x68A3, 0xD5BB, 0x68AC, 0xD5BC, 0x68A9, 0xD5BD, 0x6875, 0xD5BE, 0x6874, 0xD5BF, 0x68B2, 0xD5C0, 0x688F, 0xD5C1, 0x6877, 0xD5C2, 0x6892, 0xD5C3, 0x687C, 0xD5C4, 0x686B, 0xD5C5, 0x6872, 0xD5C6, 0x68AA, 0xD5C7, 0x6880, 0xD5C8, 0x6871, 0xD5C9, 0x687E, 0xD5CA, 0x689B, 0xD5CB, 0x6896, 0xD5CC, 0x688B, 0xD5CD, 0x68A0, 0xD5CE, 0x6889, 0xD5CF, 0x68A4, 0xD5D0, 0x6878, 0xD5D1, 0x687B, 0xD5D2, 0x6891, 0xD5D3, 0x688C, 0xD5D4, 0x688A, 0xD5D5, 0x687D, 0xD5D6, 0x6B36, 0xD5D7, 0x6B33, 0xD5D8, 0x6B37, 0xD5D9, 0x6B38, 0xD5DA, 0x6B91, 0xD5DB, 0x6B8F, 0xD5DC, 0x6B8D, 0xD5DD, 0x6B8E, 0xD5DE, 0x6B8C, 0xD5DF, 0x6C2A, 0xD5E0, 0x6DC0, 0xD5E1, 0x6DAB, 0xD5E2, 0x6DB4, 0xD5E3, 0x6DB3, 0xD5E4, 0x6E74, 0xD5E5, 0x6DAC, 0xD5E6, 0x6DE9, 0xD5E7, 0x6DE2, 0xD5E8, 0x6DB7, 0xD5E9, 0x6DF6, 0xD5EA, 0x6DD4, 0xD5EB, 0x6E00, 0xD5EC, 0x6DC8, 0xD5ED, 0x6DE0, 0xD5EE, 0x6DDF, 0xD5EF, 0x6DD6, 0xD5F0, 0x6DBE, 0xD5F1, 0x6DE5, 0xD5F2, 0x6DDC, 0xD5F3, 0x6DDD, 0xD5F4, 0x6DDB, 0xD5F5, 0x6DF4, 0xD5F6, 0x6DCA, 0xD5F7, 0x6DBD, 0xD5F8, 0x6DED, 0xD5F9, 0x6DF0, 0xD5FA, 0x6DBA, 0xD5FB, 0x6DD5, 0xD5FC, 0x6DC2, 0xD5FD, 0x6DCF, 0xD5FE, 0x6DC9, 0xD640, 0x6DD0, 0xD641, 0x6DF2, 0xD642, 0x6DD3, 0xD643, 0x6DFD, 0xD644, 0x6DD7, 0xD645, 0x6DCD, 0xD646, 0x6DE3, 0xD647, 0x6DBB, 0xD648, 0x70FA, 0xD649, 0x710D, 0xD64A, 0x70F7, 0xD64B, 0x7117, 0xD64C, 0x70F4, 0xD64D, 0x710C, 0xD64E, 0x70F0, 0xD64F, 0x7104, 0xD650, 0x70F3, 0xD651, 0x7110, 0xD652, 0x70FC, 0xD653, 0x70FF, 0xD654, 0x7106, 0xD655, 0x7113, 0xD656, 0x7100, 0xD657, 0x70F8, 0xD658, 0x70F6, 0xD659, 0x710B, 0xD65A, 0x7102, 0xD65B, 0x710E, 0xD65C, 0x727E, 0xD65D, 0x727B, 0xD65E, 0x727C, 0xD65F, 0x727F, 0xD660, 0x731D, 0xD661, 0x7317, 0xD662, 0x7307, 0xD663, 0x7311, 0xD664, 0x7318, 0xD665, 0x730A, 0xD666, 0x7308, 0xD667, 0x72FF, 0xD668, 0x730F, 0xD669, 0x731E, 0xD66A, 0x7388, 0xD66B, 0x73F6, 0xD66C, 0x73F8, 0xD66D, 0x73F5, 0xD66E, 0x7404, 0xD66F, 0x7401, 0xD670, 0x73FD, 0xD671, 0x7407, 0xD672, 0x7400, 0xD673, 0x73FA, 0xD674, 0x73FC, 0xD675, 0x73FF, 0xD676, 0x740C, 0xD677, 0x740B, 0xD678, 0x73F4, 0xD679, 0x7408, 0xD67A, 0x7564, 0xD67B, 0x7563, 0xD67C, 0x75CE, 0xD67D, 0x75D2, 0xD67E, 0x75CF, 0xD6A1, 0x75CB, 0xD6A2, 0x75CC, 0xD6A3, 0x75D1, 0xD6A4, 0x75D0, 0xD6A5, 0x768F, 0xD6A6, 0x7689, 0xD6A7, 0x76D3, 0xD6A8, 0x7739, 0xD6A9, 0x772F, 0xD6AA, 0x772D, 0xD6AB, 0x7731, 0xD6AC, 0x7732, 0xD6AD, 0x7734, 0xD6AE, 0x7733, 0xD6AF, 0x773D, 0xD6B0, 0x7725, 0xD6B1, 0x773B, 0xD6B2, 0x7735, 0xD6B3, 0x7848, 0xD6B4, 0x7852, 0xD6B5, 0x7849, 0xD6B6, 0x784D, 0xD6B7, 0x784A, 0xD6B8, 0x784C, 0xD6B9, 0x7826, 0xD6BA, 0x7845, 0xD6BB, 0x7850, 0xD6BC, 0x7964, 0xD6BD, 0x7967, 0xD6BE, 0x7969, 0xD6BF, 0x796A, 0xD6C0, 0x7963, 0xD6C1, 0x796B, 0xD6C2, 0x7961, 0xD6C3, 0x79BB, 0xD6C4, 0x79FA, 0xD6C5, 0x79F8, 0xD6C6, 0x79F6, 0xD6C7, 0x79F7, 0xD6C8, 0x7A8F, 0xD6C9, 0x7A94, 0xD6CA, 0x7A90, 0xD6CB, 0x7B35, 0xD6CC, 0x7B47, 0xD6CD, 0x7B34, 0xD6CE, 0x7B25, 0xD6CF, 0x7B30, 0xD6D0, 0x7B22, 0xD6D1, 0x7B24, 0xD6D2, 0x7B33, 0xD6D3, 0x7B18, 0xD6D4, 0x7B2A, 0xD6D5, 0x7B1D, 0xD6D6, 0x7B31, 0xD6D7, 0x7B2B, 0xD6D8, 0x7B2D, 0xD6D9, 0x7B2F, 0xD6DA, 0x7B32, 0xD6DB, 0x7B38, 0xD6DC, 0x7B1A, 0xD6DD, 0x7B23, 0xD6DE, 0x7C94, 0xD6DF, 0x7C98, 0xD6E0, 0x7C96, 0xD6E1, 0x7CA3, 0xD6E2, 0x7D35, 0xD6E3, 0x7D3D, 0xD6E4, 0x7D38, 0xD6E5, 0x7D36, 0xD6E6, 0x7D3A, 0xD6E7, 0x7D45, 0xD6E8, 0x7D2C, 0xD6E9, 0x7D29, 0xD6EA, 0x7D41, 0xD6EB, 0x7D47, 0xD6EC, 0x7D3E, 0xD6ED, 0x7D3F, 0xD6EE, 0x7D4A, 0xD6EF, 0x7D3B, 0xD6F0, 0x7D28, 0xD6F1, 0x7F63, 0xD6F2, 0x7F95, 0xD6F3, 0x7F9C, 0xD6F4, 0x7F9D, 0xD6F5, 0x7F9B, 0xD6F6, 0x7FCA, 0xD6F7, 0x7FCB, 0xD6F8, 0x7FCD, 0xD6F9, 0x7FD0, 0xD6FA, 0x7FD1, 0xD6FB, 0x7FC7, 0xD6FC, 0x7FCF, 0xD6FD, 0x7FC9, 0xD6FE, 0x801F, 0xD740, 0x801E, 0xD741, 0x801B, 0xD742, 0x8047, 0xD743, 0x8043, 0xD744, 0x8048, 0xD745, 0x8118, 0xD746, 0x8125, 0xD747, 0x8119, 0xD748, 0x811B, 0xD749, 0x812D, 0xD74A, 0x811F, 0xD74B, 0x812C, 0xD74C, 0x811E, 0xD74D, 0x8121, 0xD74E, 0x8115, 0xD74F, 0x8127, 0xD750, 0x811D, 0xD751, 0x8122, 0xD752, 0x8211, 0xD753, 0x8238, 0xD754, 0x8233, 0xD755, 0x823A, 0xD756, 0x8234, 0xD757, 0x8232, 0xD758, 0x8274, 0xD759, 0x8390, 0xD75A, 0x83A3, 0xD75B, 0x83A8, 0xD75C, 0x838D, 0xD75D, 0x837A, 0xD75E, 0x8373, 0xD75F, 0x83A4, 0xD760, 0x8374, 0xD761, 0x838F, 0xD762, 0x8381, 0xD763, 0x8395, 0xD764, 0x8399, 0xD765, 0x8375, 0xD766, 0x8394, 0xD767, 0x83A9, 0xD768, 0x837D, 0xD769, 0x8383, 0xD76A, 0x838C, 0xD76B, 0x839D, 0xD76C, 0x839B, 0xD76D, 0x83AA, 0xD76E, 0x838B, 0xD76F, 0x837E, 0xD770, 0x83A5, 0xD771, 0x83AF, 0xD772, 0x8388, 0xD773, 0x8397, 0xD774, 0x83B0, 0xD775, 0x837F, 0xD776, 0x83A6, 0xD777, 0x8387, 0xD778, 0x83AE, 0xD779, 0x8376, 0xD77A, 0x839A, 0xD77B, 0x8659, 0xD77C, 0x8656, 0xD77D, 0x86BF, 0xD77E, 0x86B7, 0xD7A1, 0x86C2, 0xD7A2, 0x86C1, 0xD7A3, 0x86C5, 0xD7A4, 0x86BA, 0xD7A5, 0x86B0, 0xD7A6, 0x86C8, 0xD7A7, 0x86B9, 0xD7A8, 0x86B3, 0xD7A9, 0x86B8, 0xD7AA, 0x86CC, 0xD7AB, 0x86B4, 0xD7AC, 0x86BB, 0xD7AD, 0x86BC, 0xD7AE, 0x86C3, 0xD7AF, 0x86BD, 0xD7B0, 0x86BE, 0xD7B1, 0x8852, 0xD7B2, 0x8889, 0xD7B3, 0x8895, 0xD7B4, 0x88A8, 0xD7B5, 0x88A2, 0xD7B6, 0x88AA, 0xD7B7, 0x889A, 0xD7B8, 0x8891, 0xD7B9, 0x88A1, 0xD7BA, 0x889F, 0xD7BB, 0x8898, 0xD7BC, 0x88A7, 0xD7BD, 0x8899, 0xD7BE, 0x889B, 0xD7BF, 0x8897, 0xD7C0, 0x88A4, 0xD7C1, 0x88AC, 0xD7C2, 0x888C, 0xD7C3, 0x8893, 0xD7C4, 0x888E, 0xD7C5, 0x8982, 0xD7C6, 0x89D6, 0xD7C7, 0x89D9, 0xD7C8, 0x89D5, 0xD7C9, 0x8A30, 0xD7CA, 0x8A27, 0xD7CB, 0x8A2C, 0xD7CC, 0x8A1E, 0xD7CD, 0x8C39, 0xD7CE, 0x8C3B, 0xD7CF, 0x8C5C, 0xD7D0, 0x8C5D, 0xD7D1, 0x8C7D, 0xD7D2, 0x8CA5, 0xD7D3, 0x8D7D, 0xD7D4, 0x8D7B, 0xD7D5, 0x8D79, 0xD7D6, 0x8DBC, 0xD7D7, 0x8DC2, 0xD7D8, 0x8DB9, 0xD7D9, 0x8DBF, 0xD7DA, 0x8DC1, 0xD7DB, 0x8ED8, 0xD7DC, 0x8EDE, 0xD7DD, 0x8EDD, 0xD7DE, 0x8EDC, 0xD7DF, 0x8ED7, 0xD7E0, 0x8EE0, 0xD7E1, 0x8EE1, 0xD7E2, 0x9024, 0xD7E3, 0x900B, 0xD7E4, 0x9011, 0xD7E5, 0x901C, 0xD7E6, 0x900C, 0xD7E7, 0x9021, 0xD7E8, 0x90EF, 0xD7E9, 0x90EA, 0xD7EA, 0x90F0, 0xD7EB, 0x90F4, 0xD7EC, 0x90F2, 0xD7ED, 0x90F3, 0xD7EE, 0x90D4, 0xD7EF, 0x90EB, 0xD7F0, 0x90EC, 0xD7F1, 0x90E9, 0xD7F2, 0x9156, 0xD7F3, 0x9158, 0xD7F4, 0x915A, 0xD7F5, 0x9153, 0xD7F6, 0x9155, 0xD7F7, 0x91EC, 0xD7F8, 0x91F4, 0xD7F9, 0x91F1, 0xD7FA, 0x91F3, 0xD7FB, 0x91F8, 0xD7FC, 0x91E4, 0xD7FD, 0x91F9, 0xD7FE, 0x91EA, 0xD840, 0x91EB, 0xD841, 0x91F7, 0xD842, 0x91E8, 0xD843, 0x91EE, 0xD844, 0x957A, 0xD845, 0x9586, 0xD846, 0x9588, 0xD847, 0x967C, 0xD848, 0x966D, 0xD849, 0x966B, 0xD84A, 0x9671, 0xD84B, 0x966F, 0xD84C, 0x96BF, 0xD84D, 0x976A, 0xD84E, 0x9804, 0xD84F, 0x98E5, 0xD850, 0x9997, 0xD851, 0x509B, 0xD852, 0x5095, 0xD853, 0x5094, 0xD854, 0x509E, 0xD855, 0x508B, 0xD856, 0x50A3, 0xD857, 0x5083, 0xD858, 0x508C, 0xD859, 0x508E, 0xD85A, 0x509D, 0xD85B, 0x5068, 0xD85C, 0x509C, 0xD85D, 0x5092, 0xD85E, 0x5082, 0xD85F, 0x5087, 0xD860, 0x515F, 0xD861, 0x51D4, 0xD862, 0x5312, 0xD863, 0x5311, 0xD864, 0x53A4, 0xD865, 0x53A7, 0xD866, 0x5591, 0xD867, 0x55A8, 0xD868, 0x55A5, 0xD869, 0x55AD, 0xD86A, 0x5577, 0xD86B, 0x5645, 0xD86C, 0x55A2, 0xD86D, 0x5593, 0xD86E, 0x5588, 0xD86F, 0x558F, 0xD870, 0x55B5, 0xD871, 0x5581, 0xD872, 0x55A3, 0xD873, 0x5592, 0xD874, 0x55A4, 0xD875, 0x557D, 0xD876, 0x558C, 0xD877, 0x55A6, 0xD878, 0x557F, 0xD879, 0x5595, 0xD87A, 0x55A1, 0xD87B, 0x558E, 0xD87C, 0x570C, 0xD87D, 0x5829, 0xD87E, 0x5837, 0xD8A1, 0x5819, 0xD8A2, 0x581E, 0xD8A3, 0x5827, 0xD8A4, 0x5823, 0xD8A5, 0x5828, 0xD8A6, 0x57F5, 0xD8A7, 0x5848, 0xD8A8, 0x5825, 0xD8A9, 0x581C, 0xD8AA, 0x581B, 0xD8AB, 0x5833, 0xD8AC, 0x583F, 0xD8AD, 0x5836, 0xD8AE, 0x582E, 0xD8AF, 0x5839, 0xD8B0, 0x5838, 0xD8B1, 0x582D, 0xD8B2, 0x582C, 0xD8B3, 0x583B, 0xD8B4, 0x5961, 0xD8B5, 0x5AAF, 0xD8B6, 0x5A94, 0xD8B7, 0x5A9F, 0xD8B8, 0x5A7A, 0xD8B9, 0x5AA2, 0xD8BA, 0x5A9E, 0xD8BB, 0x5A78, 0xD8BC, 0x5AA6, 0xD8BD, 0x5A7C, 0xD8BE, 0x5AA5, 0xD8BF, 0x5AAC, 0xD8C0, 0x5A95, 0xD8C1, 0x5AAE, 0xD8C2, 0x5A37, 0xD8C3, 0x5A84, 0xD8C4, 0x5A8A, 0xD8C5, 0x5A97, 0xD8C6, 0x5A83, 0xD8C7, 0x5A8B, 0xD8C8, 0x5AA9, 0xD8C9, 0x5A7B, 0xD8CA, 0x5A7D, 0xD8CB, 0x5A8C, 0xD8CC, 0x5A9C, 0xD8CD, 0x5A8F, 0xD8CE, 0x5A93, 0xD8CF, 0x5A9D, 0xD8D0, 0x5BEA, 0xD8D1, 0x5BCD, 0xD8D2, 0x5BCB, 0xD8D3, 0x5BD4, 0xD8D4, 0x5BD1, 0xD8D5, 0x5BCA, 0xD8D6, 0x5BCE, 0xD8D7, 0x5C0C, 0xD8D8, 0x5C30, 0xD8D9, 0x5D37, 0xD8DA, 0x5D43, 0xD8DB, 0x5D6B, 0xD8DC, 0x5D41, 0xD8DD, 0x5D4B, 0xD8DE, 0x5D3F, 0xD8DF, 0x5D35, 0xD8E0, 0x5D51, 0xD8E1, 0x5D4E, 0xD8E2, 0x5D55, 0xD8E3, 0x5D33, 0xD8E4, 0x5D3A, 0xD8E5, 0x5D52, 0xD8E6, 0x5D3D, 0xD8E7, 0x5D31, 0xD8E8, 0x5D59, 0xD8E9, 0x5D42, 0xD8EA, 0x5D39, 0xD8EB, 0x5D49, 0xD8EC, 0x5D38, 0xD8ED, 0x5D3C, 0xD8EE, 0x5D32, 0xD8EF, 0x5D36, 0xD8F0, 0x5D40, 0xD8F1, 0x5D45, 0xD8F2, 0x5E44, 0xD8F3, 0x5E41, 0xD8F4, 0x5F58, 0xD8F5, 0x5FA6, 0xD8F6, 0x5FA5, 0xD8F7, 0x5FAB, 0xD8F8, 0x60C9, 0xD8F9, 0x60B9, 0xD8FA, 0x60CC, 0xD8FB, 0x60E2, 0xD8FC, 0x60CE, 0xD8FD, 0x60C4, 0xD8FE, 0x6114, 0xD940, 0x60F2, 0xD941, 0x610A, 0xD942, 0x6116, 0xD943, 0x6105, 0xD944, 0x60F5, 0xD945, 0x6113, 0xD946, 0x60F8, 0xD947, 0x60FC, 0xD948, 0x60FE, 0xD949, 0x60C1, 0xD94A, 0x6103, 0xD94B, 0x6118, 0xD94C, 0x611D, 0xD94D, 0x6110, 0xD94E, 0x60FF, 0xD94F, 0x6104, 0xD950, 0x610B, 0xD951, 0x624A, 0xD952, 0x6394, 0xD953, 0x63B1, 0xD954, 0x63B0, 0xD955, 0x63CE, 0xD956, 0x63E5, 0xD957, 0x63E8, 0xD958, 0x63EF, 0xD959, 0x63C3, 0xD95A, 0x649D, 0xD95B, 0x63F3, 0xD95C, 0x63CA, 0xD95D, 0x63E0, 0xD95E, 0x63F6, 0xD95F, 0x63D5, 0xD960, 0x63F2, 0xD961, 0x63F5, 0xD962, 0x6461, 0xD963, 0x63DF, 0xD964, 0x63BE, 0xD965, 0x63DD, 0xD966, 0x63DC, 0xD967, 0x63C4, 0xD968, 0x63D8, 0xD969, 0x63D3, 0xD96A, 0x63C2, 0xD96B, 0x63C7, 0xD96C, 0x63CC, 0xD96D, 0x63CB, 0xD96E, 0x63C8, 0xD96F, 0x63F0, 0xD970, 0x63D7, 0xD971, 0x63D9, 0xD972, 0x6532, 0xD973, 0x6567, 0xD974, 0x656A, 0xD975, 0x6564, 0xD976, 0x655C, 0xD977, 0x6568, 0xD978, 0x6565, 0xD979, 0x658C, 0xD97A, 0x659D, 0xD97B, 0x659E, 0xD97C, 0x65AE, 0xD97D, 0x65D0, 0xD97E, 0x65D2, 0xD9A1, 0x667C, 0xD9A2, 0x666C, 0xD9A3, 0x667B, 0xD9A4, 0x6680, 0xD9A5, 0x6671, 0xD9A6, 0x6679, 0xD9A7, 0x666A, 0xD9A8, 0x6672, 0xD9A9, 0x6701, 0xD9AA, 0x690C, 0xD9AB, 0x68D3, 0xD9AC, 0x6904, 0xD9AD, 0x68DC, 0xD9AE, 0x692A, 0xD9AF, 0x68EC, 0xD9B0, 0x68EA, 0xD9B1, 0x68F1, 0xD9B2, 0x690F, 0xD9B3, 0x68D6, 0xD9B4, 0x68F7, 0xD9B5, 0x68EB, 0xD9B6, 0x68E4, 0xD9B7, 0x68F6, 0xD9B8, 0x6913, 0xD9B9, 0x6910, 0xD9BA, 0x68F3, 0xD9BB, 0x68E1, 0xD9BC, 0x6907, 0xD9BD, 0x68CC, 0xD9BE, 0x6908, 0xD9BF, 0x6970, 0xD9C0, 0x68B4, 0xD9C1, 0x6911, 0xD9C2, 0x68EF, 0xD9C3, 0x68C6, 0xD9C4, 0x6914, 0xD9C5, 0x68F8, 0xD9C6, 0x68D0, 0xD9C7, 0x68FD, 0xD9C8, 0x68FC, 0xD9C9, 0x68E8, 0xD9CA, 0x690B, 0xD9CB, 0x690A, 0xD9CC, 0x6917, 0xD9CD, 0x68CE, 0xD9CE, 0x68C8, 0xD9CF, 0x68DD, 0xD9D0, 0x68DE, 0xD9D1, 0x68E6, 0xD9D2, 0x68F4, 0xD9D3, 0x68D1, 0xD9D4, 0x6906, 0xD9D5, 0x68D4, 0xD9D6, 0x68E9, 0xD9D7, 0x6915, 0xD9D8, 0x6925, 0xD9D9, 0x68C7, 0xD9DA, 0x6B39, 0xD9DB, 0x6B3B, 0xD9DC, 0x6B3F, 0xD9DD, 0x6B3C, 0xD9DE, 0x6B94, 0xD9DF, 0x6B97, 0xD9E0, 0x6B99, 0xD9E1, 0x6B95, 0xD9E2, 0x6BBD, 0xD9E3, 0x6BF0, 0xD9E4, 0x6BF2, 0xD9E5, 0x6BF3, 0xD9E6, 0x6C30, 0xD9E7, 0x6DFC, 0xD9E8, 0x6E46, 0xD9E9, 0x6E47, 0xD9EA, 0x6E1F, 0xD9EB, 0x6E49, 0xD9EC, 0x6E88, 0xD9ED, 0x6E3C, 0xD9EE, 0x6E3D, 0xD9EF, 0x6E45, 0xD9F0, 0x6E62, 0xD9F1, 0x6E2B, 0xD9F2, 0x6E3F, 0xD9F3, 0x6E41, 0xD9F4, 0x6E5D, 0xD9F5, 0x6E73, 0xD9F6, 0x6E1C, 0xD9F7, 0x6E33, 0xD9F8, 0x6E4B, 0xD9F9, 0x6E40, 0xD9FA, 0x6E51, 0xD9FB, 0x6E3B, 0xD9FC, 0x6E03, 0xD9FD, 0x6E2E, 0xD9FE, 0x6E5E, 0xDA40, 0x6E68, 0xDA41, 0x6E5C, 0xDA42, 0x6E61, 0xDA43, 0x6E31, 0xDA44, 0x6E28, 0xDA45, 0x6E60, 0xDA46, 0x6E71, 0xDA47, 0x6E6B, 0xDA48, 0x6E39, 0xDA49, 0x6E22, 0xDA4A, 0x6E30, 0xDA4B, 0x6E53, 0xDA4C, 0x6E65, 0xDA4D, 0x6E27, 0xDA4E, 0x6E78, 0xDA4F, 0x6E64, 0xDA50, 0x6E77, 0xDA51, 0x6E55, 0xDA52, 0x6E79, 0xDA53, 0x6E52, 0xDA54, 0x6E66, 0xDA55, 0x6E35, 0xDA56, 0x6E36, 0xDA57, 0x6E5A, 0xDA58, 0x7120, 0xDA59, 0x711E, 0xDA5A, 0x712F, 0xDA5B, 0x70FB, 0xDA5C, 0x712E, 0xDA5D, 0x7131, 0xDA5E, 0x7123, 0xDA5F, 0x7125, 0xDA60, 0x7122, 0xDA61, 0x7132, 0xDA62, 0x711F, 0xDA63, 0x7128, 0xDA64, 0x713A, 0xDA65, 0x711B, 0xDA66, 0x724B, 0xDA67, 0x725A, 0xDA68, 0x7288, 0xDA69, 0x7289, 0xDA6A, 0x7286, 0xDA6B, 0x7285, 0xDA6C, 0x728B, 0xDA6D, 0x7312, 0xDA6E, 0x730B, 0xDA6F, 0x7330, 0xDA70, 0x7322, 0xDA71, 0x7331, 0xDA72, 0x7333, 0xDA73, 0x7327, 0xDA74, 0x7332, 0xDA75, 0x732D, 0xDA76, 0x7326, 0xDA77, 0x7323, 0xDA78, 0x7335, 0xDA79, 0x730C, 0xDA7A, 0x742E, 0xDA7B, 0x742C, 0xDA7C, 0x7430, 0xDA7D, 0x742B, 0xDA7E, 0x7416, 0xDAA1, 0x741A, 0xDAA2, 0x7421, 0xDAA3, 0x742D, 0xDAA4, 0x7431, 0xDAA5, 0x7424, 0xDAA6, 0x7423, 0xDAA7, 0x741D, 0xDAA8, 0x7429, 0xDAA9, 0x7420, 0xDAAA, 0x7432, 0xDAAB, 0x74FB, 0xDAAC, 0x752F, 0xDAAD, 0x756F, 0xDAAE, 0x756C, 0xDAAF, 0x75E7, 0xDAB0, 0x75DA, 0xDAB1, 0x75E1, 0xDAB2, 0x75E6, 0xDAB3, 0x75DD, 0xDAB4, 0x75DF, 0xDAB5, 0x75E4, 0xDAB6, 0x75D7, 0xDAB7, 0x7695, 0xDAB8, 0x7692, 0xDAB9, 0x76DA, 0xDABA, 0x7746, 0xDABB, 0x7747, 0xDABC, 0x7744, 0xDABD, 0x774D, 0xDABE, 0x7745, 0xDABF, 0x774A, 0xDAC0, 0x774E, 0xDAC1, 0x774B, 0xDAC2, 0x774C, 0xDAC3, 0x77DE, 0xDAC4, 0x77EC, 0xDAC5, 0x7860, 0xDAC6, 0x7864, 0xDAC7, 0x7865, 0xDAC8, 0x785C, 0xDAC9, 0x786D, 0xDACA, 0x7871, 0xDACB, 0x786A, 0xDACC, 0x786E, 0xDACD, 0x7870, 0xDACE, 0x7869, 0xDACF, 0x7868, 0xDAD0, 0x785E, 0xDAD1, 0x7862, 0xDAD2, 0x7974, 0xDAD3, 0x7973, 0xDAD4, 0x7972, 0xDAD5, 0x7970, 0xDAD6, 0x7A02, 0xDAD7, 0x7A0A, 0xDAD8, 0x7A03, 0xDAD9, 0x7A0C, 0xDADA, 0x7A04, 0xDADB, 0x7A99, 0xDADC, 0x7AE6, 0xDADD, 0x7AE4, 0xDADE, 0x7B4A, 0xDADF, 0x7B3B, 0xDAE0, 0x7B44, 0xDAE1, 0x7B48, 0xDAE2, 0x7B4C, 0xDAE3, 0x7B4E, 0xDAE4, 0x7B40, 0xDAE5, 0x7B58, 0xDAE6, 0x7B45, 0xDAE7, 0x7CA2, 0xDAE8, 0x7C9E, 0xDAE9, 0x7CA8, 0xDAEA, 0x7CA1, 0xDAEB, 0x7D58, 0xDAEC, 0x7D6F, 0xDAED, 0x7D63, 0xDAEE, 0x7D53, 0xDAEF, 0x7D56, 0xDAF0, 0x7D67, 0xDAF1, 0x7D6A, 0xDAF2, 0x7D4F, 0xDAF3, 0x7D6D, 0xDAF4, 0x7D5C, 0xDAF5, 0x7D6B, 0xDAF6, 0x7D52, 0xDAF7, 0x7D54, 0xDAF8, 0x7D69, 0xDAF9, 0x7D51, 0xDAFA, 0x7D5F, 0xDAFB, 0x7D4E, 0xDAFC, 0x7F3E, 0xDAFD, 0x7F3F, 0xDAFE, 0x7F65, 0xDB40, 0x7F66, 0xDB41, 0x7FA2, 0xDB42, 0x7FA0, 0xDB43, 0x7FA1, 0xDB44, 0x7FD7, 0xDB45, 0x8051, 0xDB46, 0x804F, 0xDB47, 0x8050, 0xDB48, 0x80FE, 0xDB49, 0x80D4, 0xDB4A, 0x8143, 0xDB4B, 0x814A, 0xDB4C, 0x8152, 0xDB4D, 0x814F, 0xDB4E, 0x8147, 0xDB4F, 0x813D, 0xDB50, 0x814D, 0xDB51, 0x813A, 0xDB52, 0x81E6, 0xDB53, 0x81EE, 0xDB54, 0x81F7, 0xDB55, 0x81F8, 0xDB56, 0x81F9, 0xDB57, 0x8204, 0xDB58, 0x823C, 0xDB59, 0x823D, 0xDB5A, 0x823F, 0xDB5B, 0x8275, 0xDB5C, 0x833B, 0xDB5D, 0x83CF, 0xDB5E, 0x83F9, 0xDB5F, 0x8423, 0xDB60, 0x83C0, 0xDB61, 0x83E8, 0xDB62, 0x8412, 0xDB63, 0x83E7, 0xDB64, 0x83E4, 0xDB65, 0x83FC, 0xDB66, 0x83F6, 0xDB67, 0x8410, 0xDB68, 0x83C6, 0xDB69, 0x83C8, 0xDB6A, 0x83EB, 0xDB6B, 0x83E3, 0xDB6C, 0x83BF, 0xDB6D, 0x8401, 0xDB6E, 0x83DD, 0xDB6F, 0x83E5, 0xDB70, 0x83D8, 0xDB71, 0x83FF, 0xDB72, 0x83E1, 0xDB73, 0x83CB, 0xDB74, 0x83CE, 0xDB75, 0x83D6, 0xDB76, 0x83F5, 0xDB77, 0x83C9, 0xDB78, 0x8409, 0xDB79, 0x840F, 0xDB7A, 0x83DE, 0xDB7B, 0x8411, 0xDB7C, 0x8406, 0xDB7D, 0x83C2, 0xDB7E, 0x83F3, 0xDBA1, 0x83D5, 0xDBA2, 0x83FA, 0xDBA3, 0x83C7, 0xDBA4, 0x83D1, 0xDBA5, 0x83EA, 0xDBA6, 0x8413, 0xDBA7, 0x83C3, 0xDBA8, 0x83EC, 0xDBA9, 0x83EE, 0xDBAA, 0x83C4, 0xDBAB, 0x83FB, 0xDBAC, 0x83D7, 0xDBAD, 0x83E2, 0xDBAE, 0x841B, 0xDBAF, 0x83DB, 0xDBB0, 0x83FE, 0xDBB1, 0x86D8, 0xDBB2, 0x86E2, 0xDBB3, 0x86E6, 0xDBB4, 0x86D3, 0xDBB5, 0x86E3, 0xDBB6, 0x86DA, 0xDBB7, 0x86EA, 0xDBB8, 0x86DD, 0xDBB9, 0x86EB, 0xDBBA, 0x86DC, 0xDBBB, 0x86EC, 0xDBBC, 0x86E9, 0xDBBD, 0x86D7, 0xDBBE, 0x86E8, 0xDBBF, 0x86D1, 0xDBC0, 0x8848, 0xDBC1, 0x8856, 0xDBC2, 0x8855, 0xDBC3, 0x88BA, 0xDBC4, 0x88D7, 0xDBC5, 0x88B9, 0xDBC6, 0x88B8, 0xDBC7, 0x88C0, 0xDBC8, 0x88BE, 0xDBC9, 0x88B6, 0xDBCA, 0x88BC, 0xDBCB, 0x88B7, 0xDBCC, 0x88BD, 0xDBCD, 0x88B2, 0xDBCE, 0x8901, 0xDBCF, 0x88C9, 0xDBD0, 0x8995, 0xDBD1, 0x8998, 0xDBD2, 0x8997, 0xDBD3, 0x89DD, 0xDBD4, 0x89DA, 0xDBD5, 0x89DB, 0xDBD6, 0x8A4E, 0xDBD7, 0x8A4D, 0xDBD8, 0x8A39, 0xDBD9, 0x8A59, 0xDBDA, 0x8A40, 0xDBDB, 0x8A57, 0xDBDC, 0x8A58, 0xDBDD, 0x8A44, 0xDBDE, 0x8A45, 0xDBDF, 0x8A52, 0xDBE0, 0x8A48, 0xDBE1, 0x8A51, 0xDBE2, 0x8A4A, 0xDBE3, 0x8A4C, 0xDBE4, 0x8A4F, 0xDBE5, 0x8C5F, 0xDBE6, 0x8C81, 0xDBE7, 0x8C80, 0xDBE8, 0x8CBA, 0xDBE9, 0x8CBE, 0xDBEA, 0x8CB0, 0xDBEB, 0x8CB9, 0xDBEC, 0x8CB5, 0xDBED, 0x8D84, 0xDBEE, 0x8D80, 0xDBEF, 0x8D89, 0xDBF0, 0x8DD8, 0xDBF1, 0x8DD3, 0xDBF2, 0x8DCD, 0xDBF3, 0x8DC7, 0xDBF4, 0x8DD6, 0xDBF5, 0x8DDC, 0xDBF6, 0x8DCF, 0xDBF7, 0x8DD5, 0xDBF8, 0x8DD9, 0xDBF9, 0x8DC8, 0xDBFA, 0x8DD7, 0xDBFB, 0x8DC5, 0xDBFC, 0x8EEF, 0xDBFD, 0x8EF7, 0xDBFE, 0x8EFA, 0xDC40, 0x8EF9, 0xDC41, 0x8EE6, 0xDC42, 0x8EEE, 0xDC43, 0x8EE5, 0xDC44, 0x8EF5, 0xDC45, 0x8EE7, 0xDC46, 0x8EE8, 0xDC47, 0x8EF6, 0xDC48, 0x8EEB, 0xDC49, 0x8EF1, 0xDC4A, 0x8EEC, 0xDC4B, 0x8EF4, 0xDC4C, 0x8EE9, 0xDC4D, 0x902D, 0xDC4E, 0x9034, 0xDC4F, 0x902F, 0xDC50, 0x9106, 0xDC51, 0x912C, 0xDC52, 0x9104, 0xDC53, 0x90FF, 0xDC54, 0x90FC, 0xDC55, 0x9108, 0xDC56, 0x90F9, 0xDC57, 0x90FB, 0xDC58, 0x9101, 0xDC59, 0x9100, 0xDC5A, 0x9107, 0xDC5B, 0x9105, 0xDC5C, 0x9103, 0xDC5D, 0x9161, 0xDC5E, 0x9164, 0xDC5F, 0x915F, 0xDC60, 0x9162, 0xDC61, 0x9160, 0xDC62, 0x9201, 0xDC63, 0x920A, 0xDC64, 0x9225, 0xDC65, 0x9203, 0xDC66, 0x921A, 0xDC67, 0x9226, 0xDC68, 0x920F, 0xDC69, 0x920C, 0xDC6A, 0x9200, 0xDC6B, 0x9212, 0xDC6C, 0x91FF, 0xDC6D, 0x91FD, 0xDC6E, 0x9206, 0xDC6F, 0x9204, 0xDC70, 0x9227, 0xDC71, 0x9202, 0xDC72, 0x921C, 0xDC73, 0x9224, 0xDC74, 0x9219, 0xDC75, 0x9217, 0xDC76, 0x9205, 0xDC77, 0x9216, 0xDC78, 0x957B, 0xDC79, 0x958D, 0xDC7A, 0x958C, 0xDC7B, 0x9590, 0xDC7C, 0x9687, 0xDC7D, 0x967E, 0xDC7E, 0x9688, 0xDCA1, 0x9689, 0xDCA2, 0x9683, 0xDCA3, 0x9680, 0xDCA4, 0x96C2, 0xDCA5, 0x96C8, 0xDCA6, 0x96C3, 0xDCA7, 0x96F1, 0xDCA8, 0x96F0, 0xDCA9, 0x976C, 0xDCAA, 0x9770, 0xDCAB, 0x976E, 0xDCAC, 0x9807, 0xDCAD, 0x98A9, 0xDCAE, 0x98EB, 0xDCAF, 0x9CE6, 0xDCB0, 0x9EF9, 0xDCB1, 0x4E83, 0xDCB2, 0x4E84, 0xDCB3, 0x4EB6, 0xDCB4, 0x50BD, 0xDCB5, 0x50BF, 0xDCB6, 0x50C6, 0xDCB7, 0x50AE, 0xDCB8, 0x50C4, 0xDCB9, 0x50CA, 0xDCBA, 0x50B4, 0xDCBB, 0x50C8, 0xDCBC, 0x50C2, 0xDCBD, 0x50B0, 0xDCBE, 0x50C1, 0xDCBF, 0x50BA, 0xDCC0, 0x50B1, 0xDCC1, 0x50CB, 0xDCC2, 0x50C9, 0xDCC3, 0x50B6, 0xDCC4, 0x50B8, 0xDCC5, 0x51D7, 0xDCC6, 0x527A, 0xDCC7, 0x5278, 0xDCC8, 0x527B, 0xDCC9, 0x527C, 0xDCCA, 0x55C3, 0xDCCB, 0x55DB, 0xDCCC, 0x55CC, 0xDCCD, 0x55D0, 0xDCCE, 0x55CB, 0xDCCF, 0x55CA, 0xDCD0, 0x55DD, 0xDCD1, 0x55C0, 0xDCD2, 0x55D4, 0xDCD3, 0x55C4, 0xDCD4, 0x55E9, 0xDCD5, 0x55BF, 0xDCD6, 0x55D2, 0xDCD7, 0x558D, 0xDCD8, 0x55CF, 0xDCD9, 0x55D5, 0xDCDA, 0x55E2, 0xDCDB, 0x55D6, 0xDCDC, 0x55C8, 0xDCDD, 0x55F2, 0xDCDE, 0x55CD, 0xDCDF, 0x55D9, 0xDCE0, 0x55C2, 0xDCE1, 0x5714, 0xDCE2, 0x5853, 0xDCE3, 0x5868, 0xDCE4, 0x5864, 0xDCE5, 0x584F, 0xDCE6, 0x584D, 0xDCE7, 0x5849, 0xDCE8, 0x586F, 0xDCE9, 0x5855, 0xDCEA, 0x584E, 0xDCEB, 0x585D, 0xDCEC, 0x5859, 0xDCED, 0x5865, 0xDCEE, 0x585B, 0xDCEF, 0x583D, 0xDCF0, 0x5863, 0xDCF1, 0x5871, 0xDCF2, 0x58FC, 0xDCF3, 0x5AC7, 0xDCF4, 0x5AC4, 0xDCF5, 0x5ACB, 0xDCF6, 0x5ABA, 0xDCF7, 0x5AB8, 0xDCF8, 0x5AB1, 0xDCF9, 0x5AB5, 0xDCFA, 0x5AB0, 0xDCFB, 0x5ABF, 0xDCFC, 0x5AC8, 0xDCFD, 0x5ABB, 0xDCFE, 0x5AC6, 0xDD40, 0x5AB7, 0xDD41, 0x5AC0, 0xDD42, 0x5ACA, 0xDD43, 0x5AB4, 0xDD44, 0x5AB6, 0xDD45, 0x5ACD, 0xDD46, 0x5AB9, 0xDD47, 0x5A90, 0xDD48, 0x5BD6, 0xDD49, 0x5BD8, 0xDD4A, 0x5BD9, 0xDD4B, 0x5C1F, 0xDD4C, 0x5C33, 0xDD4D, 0x5D71, 0xDD4E, 0x5D63, 0xDD4F, 0x5D4A, 0xDD50, 0x5D65, 0xDD51, 0x5D72, 0xDD52, 0x5D6C, 0xDD53, 0x5D5E, 0xDD54, 0x5D68, 0xDD55, 0x5D67, 0xDD56, 0x5D62, 0xDD57, 0x5DF0, 0xDD58, 0x5E4F, 0xDD59, 0x5E4E, 0xDD5A, 0x5E4A, 0xDD5B, 0x5E4D, 0xDD5C, 0x5E4B, 0xDD5D, 0x5EC5, 0xDD5E, 0x5ECC, 0xDD5F, 0x5EC6, 0xDD60, 0x5ECB, 0xDD61, 0x5EC7, 0xDD62, 0x5F40, 0xDD63, 0x5FAF, 0xDD64, 0x5FAD, 0xDD65, 0x60F7, 0xDD66, 0x6149, 0xDD67, 0x614A, 0xDD68, 0x612B, 0xDD69, 0x6145, 0xDD6A, 0x6136, 0xDD6B, 0x6132, 0xDD6C, 0x612E, 0xDD6D, 0x6146, 0xDD6E, 0x612F, 0xDD6F, 0x614F, 0xDD70, 0x6129, 0xDD71, 0x6140, 0xDD72, 0x6220, 0xDD73, 0x9168, 0xDD74, 0x6223, 0xDD75, 0x6225, 0xDD76, 0x6224, 0xDD77, 0x63C5, 0xDD78, 0x63F1, 0xDD79, 0x63EB, 0xDD7A, 0x6410, 0xDD7B, 0x6412, 0xDD7C, 0x6409, 0xDD7D, 0x6420, 0xDD7E, 0x6424, 0xDDA1, 0x6433, 0xDDA2, 0x6443, 0xDDA3, 0x641F, 0xDDA4, 0x6415, 0xDDA5, 0x6418, 0xDDA6, 0x6439, 0xDDA7, 0x6437, 0xDDA8, 0x6422, 0xDDA9, 0x6423, 0xDDAA, 0x640C, 0xDDAB, 0x6426, 0xDDAC, 0x6430, 0xDDAD, 0x6428, 0xDDAE, 0x6441, 0xDDAF, 0x6435, 0xDDB0, 0x642F, 0xDDB1, 0x640A, 0xDDB2, 0x641A, 0xDDB3, 0x6440, 0xDDB4, 0x6425, 0xDDB5, 0x6427, 0xDDB6, 0x640B, 0xDDB7, 0x63E7, 0xDDB8, 0x641B, 0xDDB9, 0x642E, 0xDDBA, 0x6421, 0xDDBB, 0x640E, 0xDDBC, 0x656F, 0xDDBD, 0x6592, 0xDDBE, 0x65D3, 0xDDBF, 0x6686, 0xDDC0, 0x668C, 0xDDC1, 0x6695, 0xDDC2, 0x6690, 0xDDC3, 0x668B, 0xDDC4, 0x668A, 0xDDC5, 0x6699, 0xDDC6, 0x6694, 0xDDC7, 0x6678, 0xDDC8, 0x6720, 0xDDC9, 0x6966, 0xDDCA, 0x695F, 0xDDCB, 0x6938, 0xDDCC, 0x694E, 0xDDCD, 0x6962, 0xDDCE, 0x6971, 0xDDCF, 0x693F, 0xDDD0, 0x6945, 0xDDD1, 0x696A, 0xDDD2, 0x6939, 0xDDD3, 0x6942, 0xDDD4, 0x6957, 0xDDD5, 0x6959, 0xDDD6, 0x697A, 0xDDD7, 0x6948, 0xDDD8, 0x6949, 0xDDD9, 0x6935, 0xDDDA, 0x696C, 0xDDDB, 0x6933, 0xDDDC, 0x693D, 0xDDDD, 0x6965, 0xDDDE, 0x68F0, 0xDDDF, 0x6978, 0xDDE0, 0x6934, 0xDDE1, 0x6969, 0xDDE2, 0x6940, 0xDDE3, 0x696F, 0xDDE4, 0x6944, 0xDDE5, 0x6976, 0xDDE6, 0x6958, 0xDDE7, 0x6941, 0xDDE8, 0x6974, 0xDDE9, 0x694C, 0xDDEA, 0x693B, 0xDDEB, 0x694B, 0xDDEC, 0x6937, 0xDDED, 0x695C, 0xDDEE, 0x694F, 0xDDEF, 0x6951, 0xDDF0, 0x6932, 0xDDF1, 0x6952, 0xDDF2, 0x692F, 0xDDF3, 0x697B, 0xDDF4, 0x693C, 0xDDF5, 0x6B46, 0xDDF6, 0x6B45, 0xDDF7, 0x6B43, 0xDDF8, 0x6B42, 0xDDF9, 0x6B48, 0xDDFA, 0x6B41, 0xDDFB, 0x6B9B, 0xDDFC, 0xFA0D, 0xDDFD, 0x6BFB, 0xDDFE, 0x6BFC, 0xDE40, 0x6BF9, 0xDE41, 0x6BF7, 0xDE42, 0x6BF8, 0xDE43, 0x6E9B, 0xDE44, 0x6ED6, 0xDE45, 0x6EC8, 0xDE46, 0x6E8F, 0xDE47, 0x6EC0, 0xDE48, 0x6E9F, 0xDE49, 0x6E93, 0xDE4A, 0x6E94, 0xDE4B, 0x6EA0, 0xDE4C, 0x6EB1, 0xDE4D, 0x6EB9, 0xDE4E, 0x6EC6, 0xDE4F, 0x6ED2, 0xDE50, 0x6EBD, 0xDE51, 0x6EC1, 0xDE52, 0x6E9E, 0xDE53, 0x6EC9, 0xDE54, 0x6EB7, 0xDE55, 0x6EB0, 0xDE56, 0x6ECD, 0xDE57, 0x6EA6, 0xDE58, 0x6ECF, 0xDE59, 0x6EB2, 0xDE5A, 0x6EBE, 0xDE5B, 0x6EC3, 0xDE5C, 0x6EDC, 0xDE5D, 0x6ED8, 0xDE5E, 0x6E99, 0xDE5F, 0x6E92, 0xDE60, 0x6E8E, 0xDE61, 0x6E8D, 0xDE62, 0x6EA4, 0xDE63, 0x6EA1, 0xDE64, 0x6EBF, 0xDE65, 0x6EB3, 0xDE66, 0x6ED0, 0xDE67, 0x6ECA, 0xDE68, 0x6E97, 0xDE69, 0x6EAE, 0xDE6A, 0x6EA3, 0xDE6B, 0x7147, 0xDE6C, 0x7154, 0xDE6D, 0x7152, 0xDE6E, 0x7163, 0xDE6F, 0x7160, 0xDE70, 0x7141, 0xDE71, 0x715D, 0xDE72, 0x7162, 0xDE73, 0x7172, 0xDE74, 0x7178, 0xDE75, 0x716A, 0xDE76, 0x7161, 0xDE77, 0x7142, 0xDE78, 0x7158, 0xDE79, 0x7143, 0xDE7A, 0x714B, 0xDE7B, 0x7170, 0xDE7C, 0x715F, 0xDE7D, 0x7150, 0xDE7E, 0x7153, 0xDEA1, 0x7144, 0xDEA2, 0x714D, 0xDEA3, 0x715A, 0xDEA4, 0x724F, 0xDEA5, 0x728D, 0xDEA6, 0x728C, 0xDEA7, 0x7291, 0xDEA8, 0x7290, 0xDEA9, 0x728E, 0xDEAA, 0x733C, 0xDEAB, 0x7342, 0xDEAC, 0x733B, 0xDEAD, 0x733A, 0xDEAE, 0x7340, 0xDEAF, 0x734A, 0xDEB0, 0x7349, 0xDEB1, 0x7444, 0xDEB2, 0x744A, 0xDEB3, 0x744B, 0xDEB4, 0x7452, 0xDEB5, 0x7451, 0xDEB6, 0x7457, 0xDEB7, 0x7440, 0xDEB8, 0x744F, 0xDEB9, 0x7450, 0xDEBA, 0x744E, 0xDEBB, 0x7442, 0xDEBC, 0x7446, 0xDEBD, 0x744D, 0xDEBE, 0x7454, 0xDEBF, 0x74E1, 0xDEC0, 0x74FF, 0xDEC1, 0x74FE, 0xDEC2, 0x74FD, 0xDEC3, 0x751D, 0xDEC4, 0x7579, 0xDEC5, 0x7577, 0xDEC6, 0x6983, 0xDEC7, 0x75EF, 0xDEC8, 0x760F, 0xDEC9, 0x7603, 0xDECA, 0x75F7, 0xDECB, 0x75FE, 0xDECC, 0x75FC, 0xDECD, 0x75F9, 0xDECE, 0x75F8, 0xDECF, 0x7610, 0xDED0, 0x75FB, 0xDED1, 0x75F6, 0xDED2, 0x75ED, 0xDED3, 0x75F5, 0xDED4, 0x75FD, 0xDED5, 0x7699, 0xDED6, 0x76B5, 0xDED7, 0x76DD, 0xDED8, 0x7755, 0xDED9, 0x775F, 0xDEDA, 0x7760, 0xDEDB, 0x7752, 0xDEDC, 0x7756, 0xDEDD, 0x775A, 0xDEDE, 0x7769, 0xDEDF, 0x7767, 0xDEE0, 0x7754, 0xDEE1, 0x7759, 0xDEE2, 0x776D, 0xDEE3, 0x77E0, 0xDEE4, 0x7887, 0xDEE5, 0x789A, 0xDEE6, 0x7894, 0xDEE7, 0x788F, 0xDEE8, 0x7884, 0xDEE9, 0x7895, 0xDEEA, 0x7885, 0xDEEB, 0x7886, 0xDEEC, 0x78A1, 0xDEED, 0x7883, 0xDEEE, 0x7879, 0xDEEF, 0x7899, 0xDEF0, 0x7880, 0xDEF1, 0x7896, 0xDEF2, 0x787B, 0xDEF3, 0x797C, 0xDEF4, 0x7982, 0xDEF5, 0x797D, 0xDEF6, 0x7979, 0xDEF7, 0x7A11, 0xDEF8, 0x7A18, 0xDEF9, 0x7A19, 0xDEFA, 0x7A12, 0xDEFB, 0x7A17, 0xDEFC, 0x7A15, 0xDEFD, 0x7A22, 0xDEFE, 0x7A13, 0xDF40, 0x7A1B, 0xDF41, 0x7A10, 0xDF42, 0x7AA3, 0xDF43, 0x7AA2, 0xDF44, 0x7A9E, 0xDF45, 0x7AEB, 0xDF46, 0x7B66, 0xDF47, 0x7B64, 0xDF48, 0x7B6D, 0xDF49, 0x7B74, 0xDF4A, 0x7B69, 0xDF4B, 0x7B72, 0xDF4C, 0x7B65, 0xDF4D, 0x7B73, 0xDF4E, 0x7B71, 0xDF4F, 0x7B70, 0xDF50, 0x7B61, 0xDF51, 0x7B78, 0xDF52, 0x7B76, 0xDF53, 0x7B63, 0xDF54, 0x7CB2, 0xDF55, 0x7CB4, 0xDF56, 0x7CAF, 0xDF57, 0x7D88, 0xDF58, 0x7D86, 0xDF59, 0x7D80, 0xDF5A, 0x7D8D, 0xDF5B, 0x7D7F, 0xDF5C, 0x7D85, 0xDF5D, 0x7D7A, 0xDF5E, 0x7D8E, 0xDF5F, 0x7D7B, 0xDF60, 0x7D83, 0xDF61, 0x7D7C, 0xDF62, 0x7D8C, 0xDF63, 0x7D94, 0xDF64, 0x7D84, 0xDF65, 0x7D7D, 0xDF66, 0x7D92, 0xDF67, 0x7F6D, 0xDF68, 0x7F6B, 0xDF69, 0x7F67, 0xDF6A, 0x7F68, 0xDF6B, 0x7F6C, 0xDF6C, 0x7FA6, 0xDF6D, 0x7FA5, 0xDF6E, 0x7FA7, 0xDF6F, 0x7FDB, 0xDF70, 0x7FDC, 0xDF71, 0x8021, 0xDF72, 0x8164, 0xDF73, 0x8160, 0xDF74, 0x8177, 0xDF75, 0x815C, 0xDF76, 0x8169, 0xDF77, 0x815B, 0xDF78, 0x8162, 0xDF79, 0x8172, 0xDF7A, 0x6721, 0xDF7B, 0x815E, 0xDF7C, 0x8176, 0xDF7D, 0x8167, 0xDF7E, 0x816F, 0xDFA1, 0x8144, 0xDFA2, 0x8161, 0xDFA3, 0x821D, 0xDFA4, 0x8249, 0xDFA5, 0x8244, 0xDFA6, 0x8240, 0xDFA7, 0x8242, 0xDFA8, 0x8245, 0xDFA9, 0x84F1, 0xDFAA, 0x843F, 0xDFAB, 0x8456, 0xDFAC, 0x8476, 0xDFAD, 0x8479, 0xDFAE, 0x848F, 0xDFAF, 0x848D, 0xDFB0, 0x8465, 0xDFB1, 0x8451, 0xDFB2, 0x8440, 0xDFB3, 0x8486, 0xDFB4, 0x8467, 0xDFB5, 0x8430, 0xDFB6, 0x844D, 0xDFB7, 0x847D, 0xDFB8, 0x845A, 0xDFB9, 0x8459, 0xDFBA, 0x8474, 0xDFBB, 0x8473, 0xDFBC, 0x845D, 0xDFBD, 0x8507, 0xDFBE, 0x845E, 0xDFBF, 0x8437, 0xDFC0, 0x843A, 0xDFC1, 0x8434, 0xDFC2, 0x847A, 0xDFC3, 0x8443, 0xDFC4, 0x8478, 0xDFC5, 0x8432, 0xDFC6, 0x8445, 0xDFC7, 0x8429, 0xDFC8, 0x83D9, 0xDFC9, 0x844B, 0xDFCA, 0x842F, 0xDFCB, 0x8442, 0xDFCC, 0x842D, 0xDFCD, 0x845F, 0xDFCE, 0x8470, 0xDFCF, 0x8439, 0xDFD0, 0x844E, 0xDFD1, 0x844C, 0xDFD2, 0x8452, 0xDFD3, 0x846F, 0xDFD4, 0x84C5, 0xDFD5, 0x848E, 0xDFD6, 0x843B, 0xDFD7, 0x8447, 0xDFD8, 0x8436, 0xDFD9, 0x8433, 0xDFDA, 0x8468, 0xDFDB, 0x847E, 0xDFDC, 0x8444, 0xDFDD, 0x842B, 0xDFDE, 0x8460, 0xDFDF, 0x8454, 0xDFE0, 0x846E, 0xDFE1, 0x8450, 0xDFE2, 0x870B, 0xDFE3, 0x8704, 0xDFE4, 0x86F7, 0xDFE5, 0x870C, 0xDFE6, 0x86FA, 0xDFE7, 0x86D6, 0xDFE8, 0x86F5, 0xDFE9, 0x874D, 0xDFEA, 0x86F8, 0xDFEB, 0x870E, 0xDFEC, 0x8709, 0xDFED, 0x8701, 0xDFEE, 0x86F6, 0xDFEF, 0x870D, 0xDFF0, 0x8705, 0xDFF1, 0x88D6, 0xDFF2, 0x88CB, 0xDFF3, 0x88CD, 0xDFF4, 0x88CE, 0xDFF5, 0x88DE, 0xDFF6, 0x88DB, 0xDFF7, 0x88DA, 0xDFF8, 0x88CC, 0xDFF9, 0x88D0, 0xDFFA, 0x8985, 0xDFFB, 0x899B, 0xDFFC, 0x89DF, 0xDFFD, 0x89E5, 0xDFFE, 0x89E4, 0xE040, 0x89E1, 0xE041, 0x89E0, 0xE042, 0x89E2, 0xE043, 0x89DC, 0xE044, 0x89E6, 0xE045, 0x8A76, 0xE046, 0x8A86, 0xE047, 0x8A7F, 0xE048, 0x8A61, 0xE049, 0x8A3F, 0xE04A, 0x8A77, 0xE04B, 0x8A82, 0xE04C, 0x8A84, 0xE04D, 0x8A75, 0xE04E, 0x8A83, 0xE04F, 0x8A81, 0xE050, 0x8A74, 0xE051, 0x8A7A, 0xE052, 0x8C3C, 0xE053, 0x8C4B, 0xE054, 0x8C4A, 0xE055, 0x8C65, 0xE056, 0x8C64, 0xE057, 0x8C66, 0xE058, 0x8C86, 0xE059, 0x8C84, 0xE05A, 0x8C85, 0xE05B, 0x8CCC, 0xE05C, 0x8D68, 0xE05D, 0x8D69, 0xE05E, 0x8D91, 0xE05F, 0x8D8C, 0xE060, 0x8D8E, 0xE061, 0x8D8F, 0xE062, 0x8D8D, 0xE063, 0x8D93, 0xE064, 0x8D94, 0xE065, 0x8D90, 0xE066, 0x8D92, 0xE067, 0x8DF0, 0xE068, 0x8DE0, 0xE069, 0x8DEC, 0xE06A, 0x8DF1, 0xE06B, 0x8DEE, 0xE06C, 0x8DD0, 0xE06D, 0x8DE9, 0xE06E, 0x8DE3, 0xE06F, 0x8DE2, 0xE070, 0x8DE7, 0xE071, 0x8DF2, 0xE072, 0x8DEB, 0xE073, 0x8DF4, 0xE074, 0x8F06, 0xE075, 0x8EFF, 0xE076, 0x8F01, 0xE077, 0x8F00, 0xE078, 0x8F05, 0xE079, 0x8F07, 0xE07A, 0x8F08, 0xE07B, 0x8F02, 0xE07C, 0x8F0B, 0xE07D, 0x9052, 0xE07E, 0x903F, 0xE0A1, 0x9044, 0xE0A2, 0x9049, 0xE0A3, 0x903D, 0xE0A4, 0x9110, 0xE0A5, 0x910D, 0xE0A6, 0x910F, 0xE0A7, 0x9111, 0xE0A8, 0x9116, 0xE0A9, 0x9114, 0xE0AA, 0x910B, 0xE0AB, 0x910E, 0xE0AC, 0x916E, 0xE0AD, 0x916F, 0xE0AE, 0x9248, 0xE0AF, 0x9252, 0xE0B0, 0x9230, 0xE0B1, 0x923A, 0xE0B2, 0x9266, 0xE0B3, 0x9233, 0xE0B4, 0x9265, 0xE0B5, 0x925E, 0xE0B6, 0x9283, 0xE0B7, 0x922E, 0xE0B8, 0x924A, 0xE0B9, 0x9246, 0xE0BA, 0x926D, 0xE0BB, 0x926C, 0xE0BC, 0x924F, 0xE0BD, 0x9260, 0xE0BE, 0x9267, 0xE0BF, 0x926F, 0xE0C0, 0x9236, 0xE0C1, 0x9261, 0xE0C2, 0x9270, 0xE0C3, 0x9231, 0xE0C4, 0x9254, 0xE0C5, 0x9263, 0xE0C6, 0x9250, 0xE0C7, 0x9272, 0xE0C8, 0x924E, 0xE0C9, 0x9253, 0xE0CA, 0x924C, 0xE0CB, 0x9256, 0xE0CC, 0x9232, 0xE0CD, 0x959F, 0xE0CE, 0x959C, 0xE0CF, 0x959E, 0xE0D0, 0x959B, 0xE0D1, 0x9692, 0xE0D2, 0x9693, 0xE0D3, 0x9691, 0xE0D4, 0x9697, 0xE0D5, 0x96CE, 0xE0D6, 0x96FA, 0xE0D7, 0x96FD, 0xE0D8, 0x96F8, 0xE0D9, 0x96F5, 0xE0DA, 0x9773, 0xE0DB, 0x9777, 0xE0DC, 0x9778, 0xE0DD, 0x9772, 0xE0DE, 0x980F, 0xE0DF, 0x980D, 0xE0E0, 0x980E, 0xE0E1, 0x98AC, 0xE0E2, 0x98F6, 0xE0E3, 0x98F9, 0xE0E4, 0x99AF, 0xE0E5, 0x99B2, 0xE0E6, 0x99B0, 0xE0E7, 0x99B5, 0xE0E8, 0x9AAD, 0xE0E9, 0x9AAB, 0xE0EA, 0x9B5B, 0xE0EB, 0x9CEA, 0xE0EC, 0x9CED, 0xE0ED, 0x9CE7, 0xE0EE, 0x9E80, 0xE0EF, 0x9EFD, 0xE0F0, 0x50E6, 0xE0F1, 0x50D4, 0xE0F2, 0x50D7, 0xE0F3, 0x50E8, 0xE0F4, 0x50F3, 0xE0F5, 0x50DB, 0xE0F6, 0x50EA, 0xE0F7, 0x50DD, 0xE0F8, 0x50E4, 0xE0F9, 0x50D3, 0xE0FA, 0x50EC, 0xE0FB, 0x50F0, 0xE0FC, 0x50EF, 0xE0FD, 0x50E3, 0xE0FE, 0x50E0, 0xE140, 0x51D8, 0xE141, 0x5280, 0xE142, 0x5281, 0xE143, 0x52E9, 0xE144, 0x52EB, 0xE145, 0x5330, 0xE146, 0x53AC, 0xE147, 0x5627, 0xE148, 0x5615, 0xE149, 0x560C, 0xE14A, 0x5612, 0xE14B, 0x55FC, 0xE14C, 0x560F, 0xE14D, 0x561C, 0xE14E, 0x5601, 0xE14F, 0x5613, 0xE150, 0x5602, 0xE151, 0x55FA, 0xE152, 0x561D, 0xE153, 0x5604, 0xE154, 0x55FF, 0xE155, 0x55F9, 0xE156, 0x5889, 0xE157, 0x587C, 0xE158, 0x5890, 0xE159, 0x5898, 0xE15A, 0x5886, 0xE15B, 0x5881, 0xE15C, 0x587F, 0xE15D, 0x5874, 0xE15E, 0x588B, 0xE15F, 0x587A, 0xE160, 0x5887, 0xE161, 0x5891, 0xE162, 0x588E, 0xE163, 0x5876, 0xE164, 0x5882, 0xE165, 0x5888, 0xE166, 0x587B, 0xE167, 0x5894, 0xE168, 0x588F, 0xE169, 0x58FE, 0xE16A, 0x596B, 0xE16B, 0x5ADC, 0xE16C, 0x5AEE, 0xE16D, 0x5AE5, 0xE16E, 0x5AD5, 0xE16F, 0x5AEA, 0xE170, 0x5ADA, 0xE171, 0x5AED, 0xE172, 0x5AEB, 0xE173, 0x5AF3, 0xE174, 0x5AE2, 0xE175, 0x5AE0, 0xE176, 0x5ADB, 0xE177, 0x5AEC, 0xE178, 0x5ADE, 0xE179, 0x5ADD, 0xE17A, 0x5AD9, 0xE17B, 0x5AE8, 0xE17C, 0x5ADF, 0xE17D, 0x5B77, 0xE17E, 0x5BE0, 0xE1A1, 0x5BE3, 0xE1A2, 0x5C63, 0xE1A3, 0x5D82, 0xE1A4, 0x5D80, 0xE1A5, 0x5D7D, 0xE1A6, 0x5D86, 0xE1A7, 0x5D7A, 0xE1A8, 0x5D81, 0xE1A9, 0x5D77, 0xE1AA, 0x5D8A, 0xE1AB, 0x5D89, 0xE1AC, 0x5D88, 0xE1AD, 0x5D7E, 0xE1AE, 0x5D7C, 0xE1AF, 0x5D8D, 0xE1B0, 0x5D79, 0xE1B1, 0x5D7F, 0xE1B2, 0x5E58, 0xE1B3, 0x5E59, 0xE1B4, 0x5E53, 0xE1B5, 0x5ED8, 0xE1B6, 0x5ED1, 0xE1B7, 0x5ED7, 0xE1B8, 0x5ECE, 0xE1B9, 0x5EDC, 0xE1BA, 0x5ED5, 0xE1BB, 0x5ED9, 0xE1BC, 0x5ED2, 0xE1BD, 0x5ED4, 0xE1BE, 0x5F44, 0xE1BF, 0x5F43, 0xE1C0, 0x5F6F, 0xE1C1, 0x5FB6, 0xE1C2, 0x612C, 0xE1C3, 0x6128, 0xE1C4, 0x6141, 0xE1C5, 0x615E, 0xE1C6, 0x6171, 0xE1C7, 0x6173, 0xE1C8, 0x6152, 0xE1C9, 0x6153, 0xE1CA, 0x6172, 0xE1CB, 0x616C, 0xE1CC, 0x6180, 0xE1CD, 0x6174, 0xE1CE, 0x6154, 0xE1CF, 0x617A, 0xE1D0, 0x615B, 0xE1D1, 0x6165, 0xE1D2, 0x613B, 0xE1D3, 0x616A, 0xE1D4, 0x6161, 0xE1D5, 0x6156, 0xE1D6, 0x6229, 0xE1D7, 0x6227, 0xE1D8, 0x622B, 0xE1D9, 0x642B, 0xE1DA, 0x644D, 0xE1DB, 0x645B, 0xE1DC, 0x645D, 0xE1DD, 0x6474, 0xE1DE, 0x6476, 0xE1DF, 0x6472, 0xE1E0, 0x6473, 0xE1E1, 0x647D, 0xE1E2, 0x6475, 0xE1E3, 0x6466, 0xE1E4, 0x64A6, 0xE1E5, 0x644E, 0xE1E6, 0x6482, 0xE1E7, 0x645E, 0xE1E8, 0x645C, 0xE1E9, 0x644B, 0xE1EA, 0x6453, 0xE1EB, 0x6460, 0xE1EC, 0x6450, 0xE1ED, 0x647F, 0xE1EE, 0x643F, 0xE1EF, 0x646C, 0xE1F0, 0x646B, 0xE1F1, 0x6459, 0xE1F2, 0x6465, 0xE1F3, 0x6477, 0xE1F4, 0x6573, 0xE1F5, 0x65A0, 0xE1F6, 0x66A1, 0xE1F7, 0x66A0, 0xE1F8, 0x669F, 0xE1F9, 0x6705, 0xE1FA, 0x6704, 0xE1FB, 0x6722, 0xE1FC, 0x69B1, 0xE1FD, 0x69B6, 0xE1FE, 0x69C9, 0xE240, 0x69A0, 0xE241, 0x69CE, 0xE242, 0x6996, 0xE243, 0x69B0, 0xE244, 0x69AC, 0xE245, 0x69BC, 0xE246, 0x6991, 0xE247, 0x6999, 0xE248, 0x698E, 0xE249, 0x69A7, 0xE24A, 0x698D, 0xE24B, 0x69A9, 0xE24C, 0x69BE, 0xE24D, 0x69AF, 0xE24E, 0x69BF, 0xE24F, 0x69C4, 0xE250, 0x69BD, 0xE251, 0x69A4, 0xE252, 0x69D4, 0xE253, 0x69B9, 0xE254, 0x69CA, 0xE255, 0x699A, 0xE256, 0x69CF, 0xE257, 0x69B3, 0xE258, 0x6993, 0xE259, 0x69AA, 0xE25A, 0x69A1, 0xE25B, 0x699E, 0xE25C, 0x69D9, 0xE25D, 0x6997, 0xE25E, 0x6990, 0xE25F, 0x69C2, 0xE260, 0x69B5, 0xE261, 0x69A5, 0xE262, 0x69C6, 0xE263, 0x6B4A, 0xE264, 0x6B4D, 0xE265, 0x6B4B, 0xE266, 0x6B9E, 0xE267, 0x6B9F, 0xE268, 0x6BA0, 0xE269, 0x6BC3, 0xE26A, 0x6BC4, 0xE26B, 0x6BFE, 0xE26C, 0x6ECE, 0xE26D, 0x6EF5, 0xE26E, 0x6EF1, 0xE26F, 0x6F03, 0xE270, 0x6F25, 0xE271, 0x6EF8, 0xE272, 0x6F37, 0xE273, 0x6EFB, 0xE274, 0x6F2E, 0xE275, 0x6F09, 0xE276, 0x6F4E, 0xE277, 0x6F19, 0xE278, 0x6F1A, 0xE279, 0x6F27, 0xE27A, 0x6F18, 0xE27B, 0x6F3B, 0xE27C, 0x6F12, 0xE27D, 0x6EED, 0xE27E, 0x6F0A, 0xE2A1, 0x6F36, 0xE2A2, 0x6F73, 0xE2A3, 0x6EF9, 0xE2A4, 0x6EEE, 0xE2A5, 0x6F2D, 0xE2A6, 0x6F40, 0xE2A7, 0x6F30, 0xE2A8, 0x6F3C, 0xE2A9, 0x6F35, 0xE2AA, 0x6EEB, 0xE2AB, 0x6F07, 0xE2AC, 0x6F0E, 0xE2AD, 0x6F43, 0xE2AE, 0x6F05, 0xE2AF, 0x6EFD, 0xE2B0, 0x6EF6, 0xE2B1, 0x6F39, 0xE2B2, 0x6F1C, 0xE2B3, 0x6EFC, 0xE2B4, 0x6F3A, 0xE2B5, 0x6F1F, 0xE2B6, 0x6F0D, 0xE2B7, 0x6F1E, 0xE2B8, 0x6F08, 0xE2B9, 0x6F21, 0xE2BA, 0x7187, 0xE2BB, 0x7190, 0xE2BC, 0x7189, 0xE2BD, 0x7180, 0xE2BE, 0x7185, 0xE2BF, 0x7182, 0xE2C0, 0x718F, 0xE2C1, 0x717B, 0xE2C2, 0x7186, 0xE2C3, 0x7181, 0xE2C4, 0x7197, 0xE2C5, 0x7244, 0xE2C6, 0x7253, 0xE2C7, 0x7297, 0xE2C8, 0x7295, 0xE2C9, 0x7293, 0xE2CA, 0x7343, 0xE2CB, 0x734D, 0xE2CC, 0x7351, 0xE2CD, 0x734C, 0xE2CE, 0x7462, 0xE2CF, 0x7473, 0xE2D0, 0x7471, 0xE2D1, 0x7475, 0xE2D2, 0x7472, 0xE2D3, 0x7467, 0xE2D4, 0x746E, 0xE2D5, 0x7500, 0xE2D6, 0x7502, 0xE2D7, 0x7503, 0xE2D8, 0x757D, 0xE2D9, 0x7590, 0xE2DA, 0x7616, 0xE2DB, 0x7608, 0xE2DC, 0x760C, 0xE2DD, 0x7615, 0xE2DE, 0x7611, 0xE2DF, 0x760A, 0xE2E0, 0x7614, 0xE2E1, 0x76B8, 0xE2E2, 0x7781, 0xE2E3, 0x777C, 0xE2E4, 0x7785, 0xE2E5, 0x7782, 0xE2E6, 0x776E, 0xE2E7, 0x7780, 0xE2E8, 0x776F, 0xE2E9, 0x777E, 0xE2EA, 0x7783, 0xE2EB, 0x78B2, 0xE2EC, 0x78AA, 0xE2ED, 0x78B4, 0xE2EE, 0x78AD, 0xE2EF, 0x78A8, 0xE2F0, 0x787E, 0xE2F1, 0x78AB, 0xE2F2, 0x789E, 0xE2F3, 0x78A5, 0xE2F4, 0x78A0, 0xE2F5, 0x78AC, 0xE2F6, 0x78A2, 0xE2F7, 0x78A4, 0xE2F8, 0x7998, 0xE2F9, 0x798A, 0xE2FA, 0x798B, 0xE2FB, 0x7996, 0xE2FC, 0x7995, 0xE2FD, 0x7994, 0xE2FE, 0x7993, 0xE340, 0x7997, 0xE341, 0x7988, 0xE342, 0x7992, 0xE343, 0x7990, 0xE344, 0x7A2B, 0xE345, 0x7A4A, 0xE346, 0x7A30, 0xE347, 0x7A2F, 0xE348, 0x7A28, 0xE349, 0x7A26, 0xE34A, 0x7AA8, 0xE34B, 0x7AAB, 0xE34C, 0x7AAC, 0xE34D, 0x7AEE, 0xE34E, 0x7B88, 0xE34F, 0x7B9C, 0xE350, 0x7B8A, 0xE351, 0x7B91, 0xE352, 0x7B90, 0xE353, 0x7B96, 0xE354, 0x7B8D, 0xE355, 0x7B8C, 0xE356, 0x7B9B, 0xE357, 0x7B8E, 0xE358, 0x7B85, 0xE359, 0x7B98, 0xE35A, 0x5284, 0xE35B, 0x7B99, 0xE35C, 0x7BA4, 0xE35D, 0x7B82, 0xE35E, 0x7CBB, 0xE35F, 0x7CBF, 0xE360, 0x7CBC, 0xE361, 0x7CBA, 0xE362, 0x7DA7, 0xE363, 0x7DB7, 0xE364, 0x7DC2, 0xE365, 0x7DA3, 0xE366, 0x7DAA, 0xE367, 0x7DC1, 0xE368, 0x7DC0, 0xE369, 0x7DC5, 0xE36A, 0x7D9D, 0xE36B, 0x7DCE, 0xE36C, 0x7DC4, 0xE36D, 0x7DC6, 0xE36E, 0x7DCB, 0xE36F, 0x7DCC, 0xE370, 0x7DAF, 0xE371, 0x7DB9, 0xE372, 0x7D96, 0xE373, 0x7DBC, 0xE374, 0x7D9F, 0xE375, 0x7DA6, 0xE376, 0x7DAE, 0xE377, 0x7DA9, 0xE378, 0x7DA1, 0xE379, 0x7DC9, 0xE37A, 0x7F73, 0xE37B, 0x7FE2, 0xE37C, 0x7FE3, 0xE37D, 0x7FE5, 0xE37E, 0x7FDE, 0xE3A1, 0x8024, 0xE3A2, 0x805D, 0xE3A3, 0x805C, 0xE3A4, 0x8189, 0xE3A5, 0x8186, 0xE3A6, 0x8183, 0xE3A7, 0x8187, 0xE3A8, 0x818D, 0xE3A9, 0x818C, 0xE3AA, 0x818B, 0xE3AB, 0x8215, 0xE3AC, 0x8497, 0xE3AD, 0x84A4, 0xE3AE, 0x84A1, 0xE3AF, 0x849F, 0xE3B0, 0x84BA, 0xE3B1, 0x84CE, 0xE3B2, 0x84C2, 0xE3B3, 0x84AC, 0xE3B4, 0x84AE, 0xE3B5, 0x84AB, 0xE3B6, 0x84B9, 0xE3B7, 0x84B4, 0xE3B8, 0x84C1, 0xE3B9, 0x84CD, 0xE3BA, 0x84AA, 0xE3BB, 0x849A, 0xE3BC, 0x84B1, 0xE3BD, 0x84D0, 0xE3BE, 0x849D, 0xE3BF, 0x84A7, 0xE3C0, 0x84BB, 0xE3C1, 0x84A2, 0xE3C2, 0x8494, 0xE3C3, 0x84C7, 0xE3C4, 0x84CC, 0xE3C5, 0x849B, 0xE3C6, 0x84A9, 0xE3C7, 0x84AF, 0xE3C8, 0x84A8, 0xE3C9, 0x84D6, 0xE3CA, 0x8498, 0xE3CB, 0x84B6, 0xE3CC, 0x84CF, 0xE3CD, 0x84A0, 0xE3CE, 0x84D7, 0xE3CF, 0x84D4, 0xE3D0, 0x84D2, 0xE3D1, 0x84DB, 0xE3D2, 0x84B0, 0xE3D3, 0x8491, 0xE3D4, 0x8661, 0xE3D5, 0x8733, 0xE3D6, 0x8723, 0xE3D7, 0x8728, 0xE3D8, 0x876B, 0xE3D9, 0x8740, 0xE3DA, 0x872E, 0xE3DB, 0x871E, 0xE3DC, 0x8721, 0xE3DD, 0x8719, 0xE3DE, 0x871B, 0xE3DF, 0x8743, 0xE3E0, 0x872C, 0xE3E1, 0x8741, 0xE3E2, 0x873E, 0xE3E3, 0x8746, 0xE3E4, 0x8720, 0xE3E5, 0x8732, 0xE3E6, 0x872A, 0xE3E7, 0x872D, 0xE3E8, 0x873C, 0xE3E9, 0x8712, 0xE3EA, 0x873A, 0xE3EB, 0x8731, 0xE3EC, 0x8735, 0xE3ED, 0x8742, 0xE3EE, 0x8726, 0xE3EF, 0x8727, 0xE3F0, 0x8738, 0xE3F1, 0x8724, 0xE3F2, 0x871A, 0xE3F3, 0x8730, 0xE3F4, 0x8711, 0xE3F5, 0x88F7, 0xE3F6, 0x88E7, 0xE3F7, 0x88F1, 0xE3F8, 0x88F2, 0xE3F9, 0x88FA, 0xE3FA, 0x88FE, 0xE3FB, 0x88EE, 0xE3FC, 0x88FC, 0xE3FD, 0x88F6, 0xE3FE, 0x88FB, 0xE440, 0x88F0, 0xE441, 0x88EC, 0xE442, 0x88EB, 0xE443, 0x899D, 0xE444, 0x89A1, 0xE445, 0x899F, 0xE446, 0x899E, 0xE447, 0x89E9, 0xE448, 0x89EB, 0xE449, 0x89E8, 0xE44A, 0x8AAB, 0xE44B, 0x8A99, 0xE44C, 0x8A8B, 0xE44D, 0x8A92, 0xE44E, 0x8A8F, 0xE44F, 0x8A96, 0xE450, 0x8C3D, 0xE451, 0x8C68, 0xE452, 0x8C69, 0xE453, 0x8CD5, 0xE454, 0x8CCF, 0xE455, 0x8CD7, 0xE456, 0x8D96, 0xE457, 0x8E09, 0xE458, 0x8E02, 0xE459, 0x8DFF, 0xE45A, 0x8E0D, 0xE45B, 0x8DFD, 0xE45C, 0x8E0A, 0xE45D, 0x8E03, 0xE45E, 0x8E07, 0xE45F, 0x8E06, 0xE460, 0x8E05, 0xE461, 0x8DFE, 0xE462, 0x8E00, 0xE463, 0x8E04, 0xE464, 0x8F10, 0xE465, 0x8F11, 0xE466, 0x8F0E, 0xE467, 0x8F0D, 0xE468, 0x9123, 0xE469, 0x911C, 0xE46A, 0x9120, 0xE46B, 0x9122, 0xE46C, 0x911F, 0xE46D, 0x911D, 0xE46E, 0x911A, 0xE46F, 0x9124, 0xE470, 0x9121, 0xE471, 0x911B, 0xE472, 0x917A, 0xE473, 0x9172, 0xE474, 0x9179, 0xE475, 0x9173, 0xE476, 0x92A5, 0xE477, 0x92A4, 0xE478, 0x9276, 0xE479, 0x929B, 0xE47A, 0x927A, 0xE47B, 0x92A0, 0xE47C, 0x9294, 0xE47D, 0x92AA, 0xE47E, 0x928D, 0xE4A1, 0x92A6, 0xE4A2, 0x929A, 0xE4A3, 0x92AB, 0xE4A4, 0x9279, 0xE4A5, 0x9297, 0xE4A6, 0x927F, 0xE4A7, 0x92A3, 0xE4A8, 0x92EE, 0xE4A9, 0x928E, 0xE4AA, 0x9282, 0xE4AB, 0x9295, 0xE4AC, 0x92A2, 0xE4AD, 0x927D, 0xE4AE, 0x9288, 0xE4AF, 0x92A1, 0xE4B0, 0x928A, 0xE4B1, 0x9286, 0xE4B2, 0x928C, 0xE4B3, 0x9299, 0xE4B4, 0x92A7, 0xE4B5, 0x927E, 0xE4B6, 0x9287, 0xE4B7, 0x92A9, 0xE4B8, 0x929D, 0xE4B9, 0x928B, 0xE4BA, 0x922D, 0xE4BB, 0x969E, 0xE4BC, 0x96A1, 0xE4BD, 0x96FF, 0xE4BE, 0x9758, 0xE4BF, 0x977D, 0xE4C0, 0x977A, 0xE4C1, 0x977E, 0xE4C2, 0x9783, 0xE4C3, 0x9780, 0xE4C4, 0x9782, 0xE4C5, 0x977B, 0xE4C6, 0x9784, 0xE4C7, 0x9781, 0xE4C8, 0x977F, 0xE4C9, 0x97CE, 0xE4CA, 0x97CD, 0xE4CB, 0x9816, 0xE4CC, 0x98AD, 0xE4CD, 0x98AE, 0xE4CE, 0x9902, 0xE4CF, 0x9900, 0xE4D0, 0x9907, 0xE4D1, 0x999D, 0xE4D2, 0x999C, 0xE4D3, 0x99C3, 0xE4D4, 0x99B9, 0xE4D5, 0x99BB, 0xE4D6, 0x99BA, 0xE4D7, 0x99C2, 0xE4D8, 0x99BD, 0xE4D9, 0x99C7, 0xE4DA, 0x9AB1, 0xE4DB, 0x9AE3, 0xE4DC, 0x9AE7, 0xE4DD, 0x9B3E, 0xE4DE, 0x9B3F, 0xE4DF, 0x9B60, 0xE4E0, 0x9B61, 0xE4E1, 0x9B5F, 0xE4E2, 0x9CF1, 0xE4E3, 0x9CF2, 0xE4E4, 0x9CF5, 0xE4E5, 0x9EA7, 0xE4E6, 0x50FF, 0xE4E7, 0x5103, 0xE4E8, 0x5130, 0xE4E9, 0x50F8, 0xE4EA, 0x5106, 0xE4EB, 0x5107, 0xE4EC, 0x50F6, 0xE4ED, 0x50FE, 0xE4EE, 0x510B, 0xE4EF, 0x510C, 0xE4F0, 0x50FD, 0xE4F1, 0x510A, 0xE4F2, 0x528B, 0xE4F3, 0x528C, 0xE4F4, 0x52F1, 0xE4F5, 0x52EF, 0xE4F6, 0x5648, 0xE4F7, 0x5642, 0xE4F8, 0x564C, 0xE4F9, 0x5635, 0xE4FA, 0x5641, 0xE4FB, 0x564A, 0xE4FC, 0x5649, 0xE4FD, 0x5646, 0xE4FE, 0x5658, 0xE540, 0x565A, 0xE541, 0x5640, 0xE542, 0x5633, 0xE543, 0x563D, 0xE544, 0x562C, 0xE545, 0x563E, 0xE546, 0x5638, 0xE547, 0x562A, 0xE548, 0x563A, 0xE549, 0x571A, 0xE54A, 0x58AB, 0xE54B, 0x589D, 0xE54C, 0x58B1, 0xE54D, 0x58A0, 0xE54E, 0x58A3, 0xE54F, 0x58AF, 0xE550, 0x58AC, 0xE551, 0x58A5, 0xE552, 0x58A1, 0xE553, 0x58FF, 0xE554, 0x5AFF, 0xE555, 0x5AF4, 0xE556, 0x5AFD, 0xE557, 0x5AF7, 0xE558, 0x5AF6, 0xE559, 0x5B03, 0xE55A, 0x5AF8, 0xE55B, 0x5B02, 0xE55C, 0x5AF9, 0xE55D, 0x5B01, 0xE55E, 0x5B07, 0xE55F, 0x5B05, 0xE560, 0x5B0F, 0xE561, 0x5C67, 0xE562, 0x5D99, 0xE563, 0x5D97, 0xE564, 0x5D9F, 0xE565, 0x5D92, 0xE566, 0x5DA2, 0xE567, 0x5D93, 0xE568, 0x5D95, 0xE569, 0x5DA0, 0xE56A, 0x5D9C, 0xE56B, 0x5DA1, 0xE56C, 0x5D9A, 0xE56D, 0x5D9E, 0xE56E, 0x5E69, 0xE56F, 0x5E5D, 0xE570, 0x5E60, 0xE571, 0x5E5C, 0xE572, 0x7DF3, 0xE573, 0x5EDB, 0xE574, 0x5EDE, 0xE575, 0x5EE1, 0xE576, 0x5F49, 0xE577, 0x5FB2, 0xE578, 0x618B, 0xE579, 0x6183, 0xE57A, 0x6179, 0xE57B, 0x61B1, 0xE57C, 0x61B0, 0xE57D, 0x61A2, 0xE57E, 0x6189, 0xE5A1, 0x619B, 0xE5A2, 0x6193, 0xE5A3, 0x61AF, 0xE5A4, 0x61AD, 0xE5A5, 0x619F, 0xE5A6, 0x6192, 0xE5A7, 0x61AA, 0xE5A8, 0x61A1, 0xE5A9, 0x618D, 0xE5AA, 0x6166, 0xE5AB, 0x61B3, 0xE5AC, 0x622D, 0xE5AD, 0x646E, 0xE5AE, 0x6470, 0xE5AF, 0x6496, 0xE5B0, 0x64A0, 0xE5B1, 0x6485, 0xE5B2, 0x6497, 0xE5B3, 0x649C, 0xE5B4, 0x648F, 0xE5B5, 0x648B, 0xE5B6, 0x648A, 0xE5B7, 0x648C, 0xE5B8, 0x64A3, 0xE5B9, 0x649F, 0xE5BA, 0x6468, 0xE5BB, 0x64B1, 0xE5BC, 0x6498, 0xE5BD, 0x6576, 0xE5BE, 0x657A, 0xE5BF, 0x6579, 0xE5C0, 0x657B, 0xE5C1, 0x65B2, 0xE5C2, 0x65B3, 0xE5C3, 0x66B5, 0xE5C4, 0x66B0, 0xE5C5, 0x66A9, 0xE5C6, 0x66B2, 0xE5C7, 0x66B7, 0xE5C8, 0x66AA, 0xE5C9, 0x66AF, 0xE5CA, 0x6A00, 0xE5CB, 0x6A06, 0xE5CC, 0x6A17, 0xE5CD, 0x69E5, 0xE5CE, 0x69F8, 0xE5CF, 0x6A15, 0xE5D0, 0x69F1, 0xE5D1, 0x69E4, 0xE5D2, 0x6A20, 0xE5D3, 0x69FF, 0xE5D4, 0x69EC, 0xE5D5, 0x69E2, 0xE5D6, 0x6A1B, 0xE5D7, 0x6A1D, 0xE5D8, 0x69FE, 0xE5D9, 0x6A27, 0xE5DA, 0x69F2, 0xE5DB, 0x69EE, 0xE5DC, 0x6A14, 0xE5DD, 0x69F7, 0xE5DE, 0x69E7, 0xE5DF, 0x6A40, 0xE5E0, 0x6A08, 0xE5E1, 0x69E6, 0xE5E2, 0x69FB, 0xE5E3, 0x6A0D, 0xE5E4, 0x69FC, 0xE5E5, 0x69EB, 0xE5E6, 0x6A09, 0xE5E7, 0x6A04, 0xE5E8, 0x6A18, 0xE5E9, 0x6A25, 0xE5EA, 0x6A0F, 0xE5EB, 0x69F6, 0xE5EC, 0x6A26, 0xE5ED, 0x6A07, 0xE5EE, 0x69F4, 0xE5EF, 0x6A16, 0xE5F0, 0x6B51, 0xE5F1, 0x6BA5, 0xE5F2, 0x6BA3, 0xE5F3, 0x6BA2, 0xE5F4, 0x6BA6, 0xE5F5, 0x6C01, 0xE5F6, 0x6C00, 0xE5F7, 0x6BFF, 0xE5F8, 0x6C02, 0xE5F9, 0x6F41, 0xE5FA, 0x6F26, 0xE5FB, 0x6F7E, 0xE5FC, 0x6F87, 0xE5FD, 0x6FC6, 0xE5FE, 0x6F92, 0xE640, 0x6F8D, 0xE641, 0x6F89, 0xE642, 0x6F8C, 0xE643, 0x6F62, 0xE644, 0x6F4F, 0xE645, 0x6F85, 0xE646, 0x6F5A, 0xE647, 0x6F96, 0xE648, 0x6F76, 0xE649, 0x6F6C, 0xE64A, 0x6F82, 0xE64B, 0x6F55, 0xE64C, 0x6F72, 0xE64D, 0x6F52, 0xE64E, 0x6F50, 0xE64F, 0x6F57, 0xE650, 0x6F94, 0xE651, 0x6F93, 0xE652, 0x6F5D, 0xE653, 0x6F00, 0xE654, 0x6F61, 0xE655, 0x6F6B, 0xE656, 0x6F7D, 0xE657, 0x6F67, 0xE658, 0x6F90, 0xE659, 0x6F53, 0xE65A, 0x6F8B, 0xE65B, 0x6F69, 0xE65C, 0x6F7F, 0xE65D, 0x6F95, 0xE65E, 0x6F63, 0xE65F, 0x6F77, 0xE660, 0x6F6A, 0xE661, 0x6F7B, 0xE662, 0x71B2, 0xE663, 0x71AF, 0xE664, 0x719B, 0xE665, 0x71B0, 0xE666, 0x71A0, 0xE667, 0x719A, 0xE668, 0x71A9, 0xE669, 0x71B5, 0xE66A, 0x719D, 0xE66B, 0x71A5, 0xE66C, 0x719E, 0xE66D, 0x71A4, 0xE66E, 0x71A1, 0xE66F, 0x71AA, 0xE670, 0x719C, 0xE671, 0x71A7, 0xE672, 0x71B3, 0xE673, 0x7298, 0xE674, 0x729A, 0xE675, 0x7358, 0xE676, 0x7352, 0xE677, 0x735E, 0xE678, 0x735F, 0xE679, 0x7360, 0xE67A, 0x735D, 0xE67B, 0x735B, 0xE67C, 0x7361, 0xE67D, 0x735A, 0xE67E, 0x7359, 0xE6A1, 0x7362, 0xE6A2, 0x7487, 0xE6A3, 0x7489, 0xE6A4, 0x748A, 0xE6A5, 0x7486, 0xE6A6, 0x7481, 0xE6A7, 0x747D, 0xE6A8, 0x7485, 0xE6A9, 0x7488, 0xE6AA, 0x747C, 0xE6AB, 0x7479, 0xE6AC, 0x7508, 0xE6AD, 0x7507, 0xE6AE, 0x757E, 0xE6AF, 0x7625, 0xE6B0, 0x761E, 0xE6B1, 0x7619, 0xE6B2, 0x761D, 0xE6B3, 0x761C, 0xE6B4, 0x7623, 0xE6B5, 0x761A, 0xE6B6, 0x7628, 0xE6B7, 0x761B, 0xE6B8, 0x769C, 0xE6B9, 0x769D, 0xE6BA, 0x769E, 0xE6BB, 0x769B, 0xE6BC, 0x778D, 0xE6BD, 0x778F, 0xE6BE, 0x7789, 0xE6BF, 0x7788, 0xE6C0, 0x78CD, 0xE6C1, 0x78BB, 0xE6C2, 0x78CF, 0xE6C3, 0x78CC, 0xE6C4, 0x78D1, 0xE6C5, 0x78CE, 0xE6C6, 0x78D4, 0xE6C7, 0x78C8, 0xE6C8, 0x78C3, 0xE6C9, 0x78C4, 0xE6CA, 0x78C9, 0xE6CB, 0x799A, 0xE6CC, 0x79A1, 0xE6CD, 0x79A0, 0xE6CE, 0x799C, 0xE6CF, 0x79A2, 0xE6D0, 0x799B, 0xE6D1, 0x6B76, 0xE6D2, 0x7A39, 0xE6D3, 0x7AB2, 0xE6D4, 0x7AB4, 0xE6D5, 0x7AB3, 0xE6D6, 0x7BB7, 0xE6D7, 0x7BCB, 0xE6D8, 0x7BBE, 0xE6D9, 0x7BAC, 0xE6DA, 0x7BCE, 0xE6DB, 0x7BAF, 0xE6DC, 0x7BB9, 0xE6DD, 0x7BCA, 0xE6DE, 0x7BB5, 0xE6DF, 0x7CC5, 0xE6E0, 0x7CC8, 0xE6E1, 0x7CCC, 0xE6E2, 0x7CCB, 0xE6E3, 0x7DF7, 0xE6E4, 0x7DDB, 0xE6E5, 0x7DEA, 0xE6E6, 0x7DE7, 0xE6E7, 0x7DD7, 0xE6E8, 0x7DE1, 0xE6E9, 0x7E03, 0xE6EA, 0x7DFA, 0xE6EB, 0x7DE6, 0xE6EC, 0x7DF6, 0xE6ED, 0x7DF1, 0xE6EE, 0x7DF0, 0xE6EF, 0x7DEE, 0xE6F0, 0x7DDF, 0xE6F1, 0x7F76, 0xE6F2, 0x7FAC, 0xE6F3, 0x7FB0, 0xE6F4, 0x7FAD, 0xE6F5, 0x7FED, 0xE6F6, 0x7FEB, 0xE6F7, 0x7FEA, 0xE6F8, 0x7FEC, 0xE6F9, 0x7FE6, 0xE6FA, 0x7FE8, 0xE6FB, 0x8064, 0xE6FC, 0x8067, 0xE6FD, 0x81A3, 0xE6FE, 0x819F, 0xE740, 0x819E, 0xE741, 0x8195, 0xE742, 0x81A2, 0xE743, 0x8199, 0xE744, 0x8197, 0xE745, 0x8216, 0xE746, 0x824F, 0xE747, 0x8253, 0xE748, 0x8252, 0xE749, 0x8250, 0xE74A, 0x824E, 0xE74B, 0x8251, 0xE74C, 0x8524, 0xE74D, 0x853B, 0xE74E, 0x850F, 0xE74F, 0x8500, 0xE750, 0x8529, 0xE751, 0x850E, 0xE752, 0x8509, 0xE753, 0x850D, 0xE754, 0x851F, 0xE755, 0x850A, 0xE756, 0x8527, 0xE757, 0x851C, 0xE758, 0x84FB, 0xE759, 0x852B, 0xE75A, 0x84FA, 0xE75B, 0x8508, 0xE75C, 0x850C, 0xE75D, 0x84F4, 0xE75E, 0x852A, 0xE75F, 0x84F2, 0xE760, 0x8515, 0xE761, 0x84F7, 0xE762, 0x84EB, 0xE763, 0x84F3, 0xE764, 0x84FC, 0xE765, 0x8512, 0xE766, 0x84EA, 0xE767, 0x84E9, 0xE768, 0x8516, 0xE769, 0x84FE, 0xE76A, 0x8528, 0xE76B, 0x851D, 0xE76C, 0x852E, 0xE76D, 0x8502, 0xE76E, 0x84FD, 0xE76F, 0x851E, 0xE770, 0x84F6, 0xE771, 0x8531, 0xE772, 0x8526, 0xE773, 0x84E7, 0xE774, 0x84E8, 0xE775, 0x84F0, 0xE776, 0x84EF, 0xE777, 0x84F9, 0xE778, 0x8518, 0xE779, 0x8520, 0xE77A, 0x8530, 0xE77B, 0x850B, 0xE77C, 0x8519, 0xE77D, 0x852F, 0xE77E, 0x8662, 0xE7A1, 0x8756, 0xE7A2, 0x8763, 0xE7A3, 0x8764, 0xE7A4, 0x8777, 0xE7A5, 0x87E1, 0xE7A6, 0x8773, 0xE7A7, 0x8758, 0xE7A8, 0x8754, 0xE7A9, 0x875B, 0xE7AA, 0x8752, 0xE7AB, 0x8761, 0xE7AC, 0x875A, 0xE7AD, 0x8751, 0xE7AE, 0x875E, 0xE7AF, 0x876D, 0xE7B0, 0x876A, 0xE7B1, 0x8750, 0xE7B2, 0x874E, 0xE7B3, 0x875F, 0xE7B4, 0x875D, 0xE7B5, 0x876F, 0xE7B6, 0x876C, 0xE7B7, 0x877A, 0xE7B8, 0x876E, 0xE7B9, 0x875C, 0xE7BA, 0x8765, 0xE7BB, 0x874F, 0xE7BC, 0x877B, 0xE7BD, 0x8775, 0xE7BE, 0x8762, 0xE7BF, 0x8767, 0xE7C0, 0x8769, 0xE7C1, 0x885A, 0xE7C2, 0x8905, 0xE7C3, 0x890C, 0xE7C4, 0x8914, 0xE7C5, 0x890B, 0xE7C6, 0x8917, 0xE7C7, 0x8918, 0xE7C8, 0x8919, 0xE7C9, 0x8906, 0xE7CA, 0x8916, 0xE7CB, 0x8911, 0xE7CC, 0x890E, 0xE7CD, 0x8909, 0xE7CE, 0x89A2, 0xE7CF, 0x89A4, 0xE7D0, 0x89A3, 0xE7D1, 0x89ED, 0xE7D2, 0x89F0, 0xE7D3, 0x89EC, 0xE7D4, 0x8ACF, 0xE7D5, 0x8AC6, 0xE7D6, 0x8AB8, 0xE7D7, 0x8AD3, 0xE7D8, 0x8AD1, 0xE7D9, 0x8AD4, 0xE7DA, 0x8AD5, 0xE7DB, 0x8ABB, 0xE7DC, 0x8AD7, 0xE7DD, 0x8ABE, 0xE7DE, 0x8AC0, 0xE7DF, 0x8AC5, 0xE7E0, 0x8AD8, 0xE7E1, 0x8AC3, 0xE7E2, 0x8ABA, 0xE7E3, 0x8ABD, 0xE7E4, 0x8AD9, 0xE7E5, 0x8C3E, 0xE7E6, 0x8C4D, 0xE7E7, 0x8C8F, 0xE7E8, 0x8CE5, 0xE7E9, 0x8CDF, 0xE7EA, 0x8CD9, 0xE7EB, 0x8CE8, 0xE7EC, 0x8CDA, 0xE7ED, 0x8CDD, 0xE7EE, 0x8CE7, 0xE7EF, 0x8DA0, 0xE7F0, 0x8D9C, 0xE7F1, 0x8DA1, 0xE7F2, 0x8D9B, 0xE7F3, 0x8E20, 0xE7F4, 0x8E23, 0xE7F5, 0x8E25, 0xE7F6, 0x8E24, 0xE7F7, 0x8E2E, 0xE7F8, 0x8E15, 0xE7F9, 0x8E1B, 0xE7FA, 0x8E16, 0xE7FB, 0x8E11, 0xE7FC, 0x8E19, 0xE7FD, 0x8E26, 0xE7FE, 0x8E27, 0xE840, 0x8E14, 0xE841, 0x8E12, 0xE842, 0x8E18, 0xE843, 0x8E13, 0xE844, 0x8E1C, 0xE845, 0x8E17, 0xE846, 0x8E1A, 0xE847, 0x8F2C, 0xE848, 0x8F24, 0xE849, 0x8F18, 0xE84A, 0x8F1A, 0xE84B, 0x8F20, 0xE84C, 0x8F23, 0xE84D, 0x8F16, 0xE84E, 0x8F17, 0xE84F, 0x9073, 0xE850, 0x9070, 0xE851, 0x906F, 0xE852, 0x9067, 0xE853, 0x906B, 0xE854, 0x912F, 0xE855, 0x912B, 0xE856, 0x9129, 0xE857, 0x912A, 0xE858, 0x9132, 0xE859, 0x9126, 0xE85A, 0x912E, 0xE85B, 0x9185, 0xE85C, 0x9186, 0xE85D, 0x918A, 0xE85E, 0x9181, 0xE85F, 0x9182, 0xE860, 0x9184, 0xE861, 0x9180, 0xE862, 0x92D0, 0xE863, 0x92C3, 0xE864, 0x92C4, 0xE865, 0x92C0, 0xE866, 0x92D9, 0xE867, 0x92B6, 0xE868, 0x92CF, 0xE869, 0x92F1, 0xE86A, 0x92DF, 0xE86B, 0x92D8, 0xE86C, 0x92E9, 0xE86D, 0x92D7, 0xE86E, 0x92DD, 0xE86F, 0x92CC, 0xE870, 0x92EF, 0xE871, 0x92C2, 0xE872, 0x92E8, 0xE873, 0x92CA, 0xE874, 0x92C8, 0xE875, 0x92CE, 0xE876, 0x92E6, 0xE877, 0x92CD, 0xE878, 0x92D5, 0xE879, 0x92C9, 0xE87A, 0x92E0, 0xE87B, 0x92DE, 0xE87C, 0x92E7, 0xE87D, 0x92D1, 0xE87E, 0x92D3, 0xE8A1, 0x92B5, 0xE8A2, 0x92E1, 0xE8A3, 0x92C6, 0xE8A4, 0x92B4, 0xE8A5, 0x957C, 0xE8A6, 0x95AC, 0xE8A7, 0x95AB, 0xE8A8, 0x95AE, 0xE8A9, 0x95B0, 0xE8AA, 0x96A4, 0xE8AB, 0x96A2, 0xE8AC, 0x96D3, 0xE8AD, 0x9705, 0xE8AE, 0x9708, 0xE8AF, 0x9702, 0xE8B0, 0x975A, 0xE8B1, 0x978A, 0xE8B2, 0x978E, 0xE8B3, 0x9788, 0xE8B4, 0x97D0, 0xE8B5, 0x97CF, 0xE8B6, 0x981E, 0xE8B7, 0x981D, 0xE8B8, 0x9826, 0xE8B9, 0x9829, 0xE8BA, 0x9828, 0xE8BB, 0x9820, 0xE8BC, 0x981B, 0xE8BD, 0x9827, 0xE8BE, 0x98B2, 0xE8BF, 0x9908, 0xE8C0, 0x98FA, 0xE8C1, 0x9911, 0xE8C2, 0x9914, 0xE8C3, 0x9916, 0xE8C4, 0x9917, 0xE8C5, 0x9915, 0xE8C6, 0x99DC, 0xE8C7, 0x99CD, 0xE8C8, 0x99CF, 0xE8C9, 0x99D3, 0xE8CA, 0x99D4, 0xE8CB, 0x99CE, 0xE8CC, 0x99C9, 0xE8CD, 0x99D6, 0xE8CE, 0x99D8, 0xE8CF, 0x99CB, 0xE8D0, 0x99D7, 0xE8D1, 0x99CC, 0xE8D2, 0x9AB3, 0xE8D3, 0x9AEC, 0xE8D4, 0x9AEB, 0xE8D5, 0x9AF3, 0xE8D6, 0x9AF2, 0xE8D7, 0x9AF1, 0xE8D8, 0x9B46, 0xE8D9, 0x9B43, 0xE8DA, 0x9B67, 0xE8DB, 0x9B74, 0xE8DC, 0x9B71, 0xE8DD, 0x9B66, 0xE8DE, 0x9B76, 0xE8DF, 0x9B75, 0xE8E0, 0x9B70, 0xE8E1, 0x9B68, 0xE8E2, 0x9B64, 0xE8E3, 0x9B6C, 0xE8E4, 0x9CFC, 0xE8E5, 0x9CFA, 0xE8E6, 0x9CFD, 0xE8E7, 0x9CFF, 0xE8E8, 0x9CF7, 0xE8E9, 0x9D07, 0xE8EA, 0x9D00, 0xE8EB, 0x9CF9, 0xE8EC, 0x9CFB, 0xE8ED, 0x9D08, 0xE8EE, 0x9D05, 0xE8EF, 0x9D04, 0xE8F0, 0x9E83, 0xE8F1, 0x9ED3, 0xE8F2, 0x9F0F, 0xE8F3, 0x9F10, 0xE8F4, 0x511C, 0xE8F5, 0x5113, 0xE8F6, 0x5117, 0xE8F7, 0x511A, 0xE8F8, 0x5111, 0xE8F9, 0x51DE, 0xE8FA, 0x5334, 0xE8FB, 0x53E1, 0xE8FC, 0x5670, 0xE8FD, 0x5660, 0xE8FE, 0x566E, 0xE940, 0x5673, 0xE941, 0x5666, 0xE942, 0x5663, 0xE943, 0x566D, 0xE944, 0x5672, 0xE945, 0x565E, 0xE946, 0x5677, 0xE947, 0x571C, 0xE948, 0x571B, 0xE949, 0x58C8, 0xE94A, 0x58BD, 0xE94B, 0x58C9, 0xE94C, 0x58BF, 0xE94D, 0x58BA, 0xE94E, 0x58C2, 0xE94F, 0x58BC, 0xE950, 0x58C6, 0xE951, 0x5B17, 0xE952, 0x5B19, 0xE953, 0x5B1B, 0xE954, 0x5B21, 0xE955, 0x5B14, 0xE956, 0x5B13, 0xE957, 0x5B10, 0xE958, 0x5B16, 0xE959, 0x5B28, 0xE95A, 0x5B1A, 0xE95B, 0x5B20, 0xE95C, 0x5B1E, 0xE95D, 0x5BEF, 0xE95E, 0x5DAC, 0xE95F, 0x5DB1, 0xE960, 0x5DA9, 0xE961, 0x5DA7, 0xE962, 0x5DB5, 0xE963, 0x5DB0, 0xE964, 0x5DAE, 0xE965, 0x5DAA, 0xE966, 0x5DA8, 0xE967, 0x5DB2, 0xE968, 0x5DAD, 0xE969, 0x5DAF, 0xE96A, 0x5DB4, 0xE96B, 0x5E67, 0xE96C, 0x5E68, 0xE96D, 0x5E66, 0xE96E, 0x5E6F, 0xE96F, 0x5EE9, 0xE970, 0x5EE7, 0xE971, 0x5EE6, 0xE972, 0x5EE8, 0xE973, 0x5EE5, 0xE974, 0x5F4B, 0xE975, 0x5FBC, 0xE976, 0x619D, 0xE977, 0x61A8, 0xE978, 0x6196, 0xE979, 0x61C5, 0xE97A, 0x61B4, 0xE97B, 0x61C6, 0xE97C, 0x61C1, 0xE97D, 0x61CC, 0xE97E, 0x61BA, 0xE9A1, 0x61BF, 0xE9A2, 0x61B8, 0xE9A3, 0x618C, 0xE9A4, 0x64D7, 0xE9A5, 0x64D6, 0xE9A6, 0x64D0, 0xE9A7, 0x64CF, 0xE9A8, 0x64C9, 0xE9A9, 0x64BD, 0xE9AA, 0x6489, 0xE9AB, 0x64C3, 0xE9AC, 0x64DB, 0xE9AD, 0x64F3, 0xE9AE, 0x64D9, 0xE9AF, 0x6533, 0xE9B0, 0x657F, 0xE9B1, 0x657C, 0xE9B2, 0x65A2, 0xE9B3, 0x66C8, 0xE9B4, 0x66BE, 0xE9B5, 0x66C0, 0xE9B6, 0x66CA, 0xE9B7, 0x66CB, 0xE9B8, 0x66CF, 0xE9B9, 0x66BD, 0xE9BA, 0x66BB, 0xE9BB, 0x66BA, 0xE9BC, 0x66CC, 0xE9BD, 0x6723, 0xE9BE, 0x6A34, 0xE9BF, 0x6A66, 0xE9C0, 0x6A49, 0xE9C1, 0x6A67, 0xE9C2, 0x6A32, 0xE9C3, 0x6A68, 0xE9C4, 0x6A3E, 0xE9C5, 0x6A5D, 0xE9C6, 0x6A6D, 0xE9C7, 0x6A76, 0xE9C8, 0x6A5B, 0xE9C9, 0x6A51, 0xE9CA, 0x6A28, 0xE9CB, 0x6A5A, 0xE9CC, 0x6A3B, 0xE9CD, 0x6A3F, 0xE9CE, 0x6A41, 0xE9CF, 0x6A6A, 0xE9D0, 0x6A64, 0xE9D1, 0x6A50, 0xE9D2, 0x6A4F, 0xE9D3, 0x6A54, 0xE9D4, 0x6A6F, 0xE9D5, 0x6A69, 0xE9D6, 0x6A60, 0xE9D7, 0x6A3C, 0xE9D8, 0x6A5E, 0xE9D9, 0x6A56, 0xE9DA, 0x6A55, 0xE9DB, 0x6A4D, 0xE9DC, 0x6A4E, 0xE9DD, 0x6A46, 0xE9DE, 0x6B55, 0xE9DF, 0x6B54, 0xE9E0, 0x6B56, 0xE9E1, 0x6BA7, 0xE9E2, 0x6BAA, 0xE9E3, 0x6BAB, 0xE9E4, 0x6BC8, 0xE9E5, 0x6BC7, 0xE9E6, 0x6C04, 0xE9E7, 0x6C03, 0xE9E8, 0x6C06, 0xE9E9, 0x6FAD, 0xE9EA, 0x6FCB, 0xE9EB, 0x6FA3, 0xE9EC, 0x6FC7, 0xE9ED, 0x6FBC, 0xE9EE, 0x6FCE, 0xE9EF, 0x6FC8, 0xE9F0, 0x6F5E, 0xE9F1, 0x6FC4, 0xE9F2, 0x6FBD, 0xE9F3, 0x6F9E, 0xE9F4, 0x6FCA, 0xE9F5, 0x6FA8, 0xE9F6, 0x7004, 0xE9F7, 0x6FA5, 0xE9F8, 0x6FAE, 0xE9F9, 0x6FBA, 0xE9FA, 0x6FAC, 0xE9FB, 0x6FAA, 0xE9FC, 0x6FCF, 0xE9FD, 0x6FBF, 0xE9FE, 0x6FB8, 0xEA40, 0x6FA2, 0xEA41, 0x6FC9, 0xEA42, 0x6FAB, 0xEA43, 0x6FCD, 0xEA44, 0x6FAF, 0xEA45, 0x6FB2, 0xEA46, 0x6FB0, 0xEA47, 0x71C5, 0xEA48, 0x71C2, 0xEA49, 0x71BF, 0xEA4A, 0x71B8, 0xEA4B, 0x71D6, 0xEA4C, 0x71C0, 0xEA4D, 0x71C1, 0xEA4E, 0x71CB, 0xEA4F, 0x71D4, 0xEA50, 0x71CA, 0xEA51, 0x71C7, 0xEA52, 0x71CF, 0xEA53, 0x71BD, 0xEA54, 0x71D8, 0xEA55, 0x71BC, 0xEA56, 0x71C6, 0xEA57, 0x71DA, 0xEA58, 0x71DB, 0xEA59, 0x729D, 0xEA5A, 0x729E, 0xEA5B, 0x7369, 0xEA5C, 0x7366, 0xEA5D, 0x7367, 0xEA5E, 0x736C, 0xEA5F, 0x7365, 0xEA60, 0x736B, 0xEA61, 0x736A, 0xEA62, 0x747F, 0xEA63, 0x749A, 0xEA64, 0x74A0, 0xEA65, 0x7494, 0xEA66, 0x7492, 0xEA67, 0x7495, 0xEA68, 0x74A1, 0xEA69, 0x750B, 0xEA6A, 0x7580, 0xEA6B, 0x762F, 0xEA6C, 0x762D, 0xEA6D, 0x7631, 0xEA6E, 0x763D, 0xEA6F, 0x7633, 0xEA70, 0x763C, 0xEA71, 0x7635, 0xEA72, 0x7632, 0xEA73, 0x7630, 0xEA74, 0x76BB, 0xEA75, 0x76E6, 0xEA76, 0x779A, 0xEA77, 0x779D, 0xEA78, 0x77A1, 0xEA79, 0x779C, 0xEA7A, 0x779B, 0xEA7B, 0x77A2, 0xEA7C, 0x77A3, 0xEA7D, 0x7795, 0xEA7E, 0x7799, 0xEAA1, 0x7797, 0xEAA2, 0x78DD, 0xEAA3, 0x78E9, 0xEAA4, 0x78E5, 0xEAA5, 0x78EA, 0xEAA6, 0x78DE, 0xEAA7, 0x78E3, 0xEAA8, 0x78DB, 0xEAA9, 0x78E1, 0xEAAA, 0x78E2, 0xEAAB, 0x78ED, 0xEAAC, 0x78DF, 0xEAAD, 0x78E0, 0xEAAE, 0x79A4, 0xEAAF, 0x7A44, 0xEAB0, 0x7A48, 0xEAB1, 0x7A47, 0xEAB2, 0x7AB6, 0xEAB3, 0x7AB8, 0xEAB4, 0x7AB5, 0xEAB5, 0x7AB1, 0xEAB6, 0x7AB7, 0xEAB7, 0x7BDE, 0xEAB8, 0x7BE3, 0xEAB9, 0x7BE7, 0xEABA, 0x7BDD, 0xEABB, 0x7BD5, 0xEABC, 0x7BE5, 0xEABD, 0x7BDA, 0xEABE, 0x7BE8, 0xEABF, 0x7BF9, 0xEAC0, 0x7BD4, 0xEAC1, 0x7BEA, 0xEAC2, 0x7BE2, 0xEAC3, 0x7BDC, 0xEAC4, 0x7BEB, 0xEAC5, 0x7BD8, 0xEAC6, 0x7BDF, 0xEAC7, 0x7CD2, 0xEAC8, 0x7CD4, 0xEAC9, 0x7CD7, 0xEACA, 0x7CD0, 0xEACB, 0x7CD1, 0xEACC, 0x7E12, 0xEACD, 0x7E21, 0xEACE, 0x7E17, 0xEACF, 0x7E0C, 0xEAD0, 0x7E1F, 0xEAD1, 0x7E20, 0xEAD2, 0x7E13, 0xEAD3, 0x7E0E, 0xEAD4, 0x7E1C, 0xEAD5, 0x7E15, 0xEAD6, 0x7E1A, 0xEAD7, 0x7E22, 0xEAD8, 0x7E0B, 0xEAD9, 0x7E0F, 0xEADA, 0x7E16, 0xEADB, 0x7E0D, 0xEADC, 0x7E14, 0xEADD, 0x7E25, 0xEADE, 0x7E24, 0xEADF, 0x7F43, 0xEAE0, 0x7F7B, 0xEAE1, 0x7F7C, 0xEAE2, 0x7F7A, 0xEAE3, 0x7FB1, 0xEAE4, 0x7FEF, 0xEAE5, 0x802A, 0xEAE6, 0x8029, 0xEAE7, 0x806C, 0xEAE8, 0x81B1, 0xEAE9, 0x81A6, 0xEAEA, 0x81AE, 0xEAEB, 0x81B9, 0xEAEC, 0x81B5, 0xEAED, 0x81AB, 0xEAEE, 0x81B0, 0xEAEF, 0x81AC, 0xEAF0, 0x81B4, 0xEAF1, 0x81B2, 0xEAF2, 0x81B7, 0xEAF3, 0x81A7, 0xEAF4, 0x81F2, 0xEAF5, 0x8255, 0xEAF6, 0x8256, 0xEAF7, 0x8257, 0xEAF8, 0x8556, 0xEAF9, 0x8545, 0xEAFA, 0x856B, 0xEAFB, 0x854D, 0xEAFC, 0x8553, 0xEAFD, 0x8561, 0xEAFE, 0x8558, 0xEB40, 0x8540, 0xEB41, 0x8546, 0xEB42, 0x8564, 0xEB43, 0x8541, 0xEB44, 0x8562, 0xEB45, 0x8544, 0xEB46, 0x8551, 0xEB47, 0x8547, 0xEB48, 0x8563, 0xEB49, 0x853E, 0xEB4A, 0x855B, 0xEB4B, 0x8571, 0xEB4C, 0x854E, 0xEB4D, 0x856E, 0xEB4E, 0x8575, 0xEB4F, 0x8555, 0xEB50, 0x8567, 0xEB51, 0x8560, 0xEB52, 0x858C, 0xEB53, 0x8566, 0xEB54, 0x855D, 0xEB55, 0x8554, 0xEB56, 0x8565, 0xEB57, 0x856C, 0xEB58, 0x8663, 0xEB59, 0x8665, 0xEB5A, 0x8664, 0xEB5B, 0x879B, 0xEB5C, 0x878F, 0xEB5D, 0x8797, 0xEB5E, 0x8793, 0xEB5F, 0x8792, 0xEB60, 0x8788, 0xEB61, 0x8781, 0xEB62, 0x8796, 0xEB63, 0x8798, 0xEB64, 0x8779, 0xEB65, 0x8787, 0xEB66, 0x87A3, 0xEB67, 0x8785, 0xEB68, 0x8790, 0xEB69, 0x8791, 0xEB6A, 0x879D, 0xEB6B, 0x8784, 0xEB6C, 0x8794, 0xEB6D, 0x879C, 0xEB6E, 0x879A, 0xEB6F, 0x8789, 0xEB70, 0x891E, 0xEB71, 0x8926, 0xEB72, 0x8930, 0xEB73, 0x892D, 0xEB74, 0x892E, 0xEB75, 0x8927, 0xEB76, 0x8931, 0xEB77, 0x8922, 0xEB78, 0x8929, 0xEB79, 0x8923, 0xEB7A, 0x892F, 0xEB7B, 0x892C, 0xEB7C, 0x891F, 0xEB7D, 0x89F1, 0xEB7E, 0x8AE0, 0xEBA1, 0x8AE2, 0xEBA2, 0x8AF2, 0xEBA3, 0x8AF4, 0xEBA4, 0x8AF5, 0xEBA5, 0x8ADD, 0xEBA6, 0x8B14, 0xEBA7, 0x8AE4, 0xEBA8, 0x8ADF, 0xEBA9, 0x8AF0, 0xEBAA, 0x8AC8, 0xEBAB, 0x8ADE, 0xEBAC, 0x8AE1, 0xEBAD, 0x8AE8, 0xEBAE, 0x8AFF, 0xEBAF, 0x8AEF, 0xEBB0, 0x8AFB, 0xEBB1, 0x8C91, 0xEBB2, 0x8C92, 0xEBB3, 0x8C90, 0xEBB4, 0x8CF5, 0xEBB5, 0x8CEE, 0xEBB6, 0x8CF1, 0xEBB7, 0x8CF0, 0xEBB8, 0x8CF3, 0xEBB9, 0x8D6C, 0xEBBA, 0x8D6E, 0xEBBB, 0x8DA5, 0xEBBC, 0x8DA7, 0xEBBD, 0x8E33, 0xEBBE, 0x8E3E, 0xEBBF, 0x8E38, 0xEBC0, 0x8E40, 0xEBC1, 0x8E45, 0xEBC2, 0x8E36, 0xEBC3, 0x8E3C, 0xEBC4, 0x8E3D, 0xEBC5, 0x8E41, 0xEBC6, 0x8E30, 0xEBC7, 0x8E3F, 0xEBC8, 0x8EBD, 0xEBC9, 0x8F36, 0xEBCA, 0x8F2E, 0xEBCB, 0x8F35, 0xEBCC, 0x8F32, 0xEBCD, 0x8F39, 0xEBCE, 0x8F37, 0xEBCF, 0x8F34, 0xEBD0, 0x9076, 0xEBD1, 0x9079, 0xEBD2, 0x907B, 0xEBD3, 0x9086, 0xEBD4, 0x90FA, 0xEBD5, 0x9133, 0xEBD6, 0x9135, 0xEBD7, 0x9136, 0xEBD8, 0x9193, 0xEBD9, 0x9190, 0xEBDA, 0x9191, 0xEBDB, 0x918D, 0xEBDC, 0x918F, 0xEBDD, 0x9327, 0xEBDE, 0x931E, 0xEBDF, 0x9308, 0xEBE0, 0x931F, 0xEBE1, 0x9306, 0xEBE2, 0x930F, 0xEBE3, 0x937A, 0xEBE4, 0x9338, 0xEBE5, 0x933C, 0xEBE6, 0x931B, 0xEBE7, 0x9323, 0xEBE8, 0x9312, 0xEBE9, 0x9301, 0xEBEA, 0x9346, 0xEBEB, 0x932D, 0xEBEC, 0x930E, 0xEBED, 0x930D, 0xEBEE, 0x92CB, 0xEBEF, 0x931D, 0xEBF0, 0x92FA, 0xEBF1, 0x9325, 0xEBF2, 0x9313, 0xEBF3, 0x92F9, 0xEBF4, 0x92F7, 0xEBF5, 0x9334, 0xEBF6, 0x9302, 0xEBF7, 0x9324, 0xEBF8, 0x92FF, 0xEBF9, 0x9329, 0xEBFA, 0x9339, 0xEBFB, 0x9335, 0xEBFC, 0x932A, 0xEBFD, 0x9314, 0xEBFE, 0x930C, 0xEC40, 0x930B, 0xEC41, 0x92FE, 0xEC42, 0x9309, 0xEC43, 0x9300, 0xEC44, 0x92FB, 0xEC45, 0x9316, 0xEC46, 0x95BC, 0xEC47, 0x95CD, 0xEC48, 0x95BE, 0xEC49, 0x95B9, 0xEC4A, 0x95BA, 0xEC4B, 0x95B6, 0xEC4C, 0x95BF, 0xEC4D, 0x95B5, 0xEC4E, 0x95BD, 0xEC4F, 0x96A9, 0xEC50, 0x96D4, 0xEC51, 0x970B, 0xEC52, 0x9712, 0xEC53, 0x9710, 0xEC54, 0x9799, 0xEC55, 0x9797, 0xEC56, 0x9794, 0xEC57, 0x97F0, 0xEC58, 0x97F8, 0xEC59, 0x9835, 0xEC5A, 0x982F, 0xEC5B, 0x9832, 0xEC5C, 0x9924, 0xEC5D, 0x991F, 0xEC5E, 0x9927, 0xEC5F, 0x9929, 0xEC60, 0x999E, 0xEC61, 0x99EE, 0xEC62, 0x99EC, 0xEC63, 0x99E5, 0xEC64, 0x99E4, 0xEC65, 0x99F0, 0xEC66, 0x99E3, 0xEC67, 0x99EA, 0xEC68, 0x99E9, 0xEC69, 0x99E7, 0xEC6A, 0x9AB9, 0xEC6B, 0x9ABF, 0xEC6C, 0x9AB4, 0xEC6D, 0x9ABB, 0xEC6E, 0x9AF6, 0xEC6F, 0x9AFA, 0xEC70, 0x9AF9, 0xEC71, 0x9AF7, 0xEC72, 0x9B33, 0xEC73, 0x9B80, 0xEC74, 0x9B85, 0xEC75, 0x9B87, 0xEC76, 0x9B7C, 0xEC77, 0x9B7E, 0xEC78, 0x9B7B, 0xEC79, 0x9B82, 0xEC7A, 0x9B93, 0xEC7B, 0x9B92, 0xEC7C, 0x9B90, 0xEC7D, 0x9B7A, 0xEC7E, 0x9B95, 0xECA1, 0x9B7D, 0xECA2, 0x9B88, 0xECA3, 0x9D25, 0xECA4, 0x9D17, 0xECA5, 0x9D20, 0xECA6, 0x9D1E, 0xECA7, 0x9D14, 0xECA8, 0x9D29, 0xECA9, 0x9D1D, 0xECAA, 0x9D18, 0xECAB, 0x9D22, 0xECAC, 0x9D10, 0xECAD, 0x9D19, 0xECAE, 0x9D1F, 0xECAF, 0x9E88, 0xECB0, 0x9E86, 0xECB1, 0x9E87, 0xECB2, 0x9EAE, 0xECB3, 0x9EAD, 0xECB4, 0x9ED5, 0xECB5, 0x9ED6, 0xECB6, 0x9EFA, 0xECB7, 0x9F12, 0xECB8, 0x9F3D, 0xECB9, 0x5126, 0xECBA, 0x5125, 0xECBB, 0x5122, 0xECBC, 0x5124, 0xECBD, 0x5120, 0xECBE, 0x5129, 0xECBF, 0x52F4, 0xECC0, 0x5693, 0xECC1, 0x568C, 0xECC2, 0x568D, 0xECC3, 0x5686, 0xECC4, 0x5684, 0xECC5, 0x5683, 0xECC6, 0x567E, 0xECC7, 0x5682, 0xECC8, 0x567F, 0xECC9, 0x5681, 0xECCA, 0x58D6, 0xECCB, 0x58D4, 0xECCC, 0x58CF, 0xECCD, 0x58D2, 0xECCE, 0x5B2D, 0xECCF, 0x5B25, 0xECD0, 0x5B32, 0xECD1, 0x5B23, 0xECD2, 0x5B2C, 0xECD3, 0x5B27, 0xECD4, 0x5B26, 0xECD5, 0x5B2F, 0xECD6, 0x5B2E, 0xECD7, 0x5B7B, 0xECD8, 0x5BF1, 0xECD9, 0x5BF2, 0xECDA, 0x5DB7, 0xECDB, 0x5E6C, 0xECDC, 0x5E6A, 0xECDD, 0x5FBE, 0xECDE, 0x5FBB, 0xECDF, 0x61C3, 0xECE0, 0x61B5, 0xECE1, 0x61BC, 0xECE2, 0x61E7, 0xECE3, 0x61E0, 0xECE4, 0x61E5, 0xECE5, 0x61E4, 0xECE6, 0x61E8, 0xECE7, 0x61DE, 0xECE8, 0x64EF, 0xECE9, 0x64E9, 0xECEA, 0x64E3, 0xECEB, 0x64EB, 0xECEC, 0x64E4, 0xECED, 0x64E8, 0xECEE, 0x6581, 0xECEF, 0x6580, 0xECF0, 0x65B6, 0xECF1, 0x65DA, 0xECF2, 0x66D2, 0xECF3, 0x6A8D, 0xECF4, 0x6A96, 0xECF5, 0x6A81, 0xECF6, 0x6AA5, 0xECF7, 0x6A89, 0xECF8, 0x6A9F, 0xECF9, 0x6A9B, 0xECFA, 0x6AA1, 0xECFB, 0x6A9E, 0xECFC, 0x6A87, 0xECFD, 0x6A93, 0xECFE, 0x6A8E, 0xED40, 0x6A95, 0xED41, 0x6A83, 0xED42, 0x6AA8, 0xED43, 0x6AA4, 0xED44, 0x6A91, 0xED45, 0x6A7F, 0xED46, 0x6AA6, 0xED47, 0x6A9A, 0xED48, 0x6A85, 0xED49, 0x6A8C, 0xED4A, 0x6A92, 0xED4B, 0x6B5B, 0xED4C, 0x6BAD, 0xED4D, 0x6C09, 0xED4E, 0x6FCC, 0xED4F, 0x6FA9, 0xED50, 0x6FF4, 0xED51, 0x6FD4, 0xED52, 0x6FE3, 0xED53, 0x6FDC, 0xED54, 0x6FED, 0xED55, 0x6FE7, 0xED56, 0x6FE6, 0xED57, 0x6FDE, 0xED58, 0x6FF2, 0xED59, 0x6FDD, 0xED5A, 0x6FE2, 0xED5B, 0x6FE8, 0xED5C, 0x71E1, 0xED5D, 0x71F1, 0xED5E, 0x71E8, 0xED5F, 0x71F2, 0xED60, 0x71E4, 0xED61, 0x71F0, 0xED62, 0x71E2, 0xED63, 0x7373, 0xED64, 0x736E, 0xED65, 0x736F, 0xED66, 0x7497, 0xED67, 0x74B2, 0xED68, 0x74AB, 0xED69, 0x7490, 0xED6A, 0x74AA, 0xED6B, 0x74AD, 0xED6C, 0x74B1, 0xED6D, 0x74A5, 0xED6E, 0x74AF, 0xED6F, 0x7510, 0xED70, 0x7511, 0xED71, 0x7512, 0xED72, 0x750F, 0xED73, 0x7584, 0xED74, 0x7643, 0xED75, 0x7648, 0xED76, 0x7649, 0xED77, 0x7647, 0xED78, 0x76A4, 0xED79, 0x76E9, 0xED7A, 0x77B5, 0xED7B, 0x77AB, 0xED7C, 0x77B2, 0xED7D, 0x77B7, 0xED7E, 0x77B6, 0xEDA1, 0x77B4, 0xEDA2, 0x77B1, 0xEDA3, 0x77A8, 0xEDA4, 0x77F0, 0xEDA5, 0x78F3, 0xEDA6, 0x78FD, 0xEDA7, 0x7902, 0xEDA8, 0x78FB, 0xEDA9, 0x78FC, 0xEDAA, 0x78F2, 0xEDAB, 0x7905, 0xEDAC, 0x78F9, 0xEDAD, 0x78FE, 0xEDAE, 0x7904, 0xEDAF, 0x79AB, 0xEDB0, 0x79A8, 0xEDB1, 0x7A5C, 0xEDB2, 0x7A5B, 0xEDB3, 0x7A56, 0xEDB4, 0x7A58, 0xEDB5, 0x7A54, 0xEDB6, 0x7A5A, 0xEDB7, 0x7ABE, 0xEDB8, 0x7AC0, 0xEDB9, 0x7AC1, 0xEDBA, 0x7C05, 0xEDBB, 0x7C0F, 0xEDBC, 0x7BF2, 0xEDBD, 0x7C00, 0xEDBE, 0x7BFF, 0xEDBF, 0x7BFB, 0xEDC0, 0x7C0E, 0xEDC1, 0x7BF4, 0xEDC2, 0x7C0B, 0xEDC3, 0x7BF3, 0xEDC4, 0x7C02, 0xEDC5, 0x7C09, 0xEDC6, 0x7C03, 0xEDC7, 0x7C01, 0xEDC8, 0x7BF8, 0xEDC9, 0x7BFD, 0xEDCA, 0x7C06, 0xEDCB, 0x7BF0, 0xEDCC, 0x7BF1, 0xEDCD, 0x7C10, 0xEDCE, 0x7C0A, 0xEDCF, 0x7CE8, 0xEDD0, 0x7E2D, 0xEDD1, 0x7E3C, 0xEDD2, 0x7E42, 0xEDD3, 0x7E33, 0xEDD4, 0x9848, 0xEDD5, 0x7E38, 0xEDD6, 0x7E2A, 0xEDD7, 0x7E49, 0xEDD8, 0x7E40, 0xEDD9, 0x7E47, 0xEDDA, 0x7E29, 0xEDDB, 0x7E4C, 0xEDDC, 0x7E30, 0xEDDD, 0x7E3B, 0xEDDE, 0x7E36, 0xEDDF, 0x7E44, 0xEDE0, 0x7E3A, 0xEDE1, 0x7F45, 0xEDE2, 0x7F7F, 0xEDE3, 0x7F7E, 0xEDE4, 0x7F7D, 0xEDE5, 0x7FF4, 0xEDE6, 0x7FF2, 0xEDE7, 0x802C, 0xEDE8, 0x81BB, 0xEDE9, 0x81C4, 0xEDEA, 0x81CC, 0xEDEB, 0x81CA, 0xEDEC, 0x81C5, 0xEDED, 0x81C7, 0xEDEE, 0x81BC, 0xEDEF, 0x81E9, 0xEDF0, 0x825B, 0xEDF1, 0x825A, 0xEDF2, 0x825C, 0xEDF3, 0x8583, 0xEDF4, 0x8580, 0xEDF5, 0x858F, 0xEDF6, 0x85A7, 0xEDF7, 0x8595, 0xEDF8, 0x85A0, 0xEDF9, 0x858B, 0xEDFA, 0x85A3, 0xEDFB, 0x857B, 0xEDFC, 0x85A4, 0xEDFD, 0x859A, 0xEDFE, 0x859E, 0xEE40, 0x8577, 0xEE41, 0x857C, 0xEE42, 0x8589, 0xEE43, 0x85A1, 0xEE44, 0x857A, 0xEE45, 0x8578, 0xEE46, 0x8557, 0xEE47, 0x858E, 0xEE48, 0x8596, 0xEE49, 0x8586, 0xEE4A, 0x858D, 0xEE4B, 0x8599, 0xEE4C, 0x859D, 0xEE4D, 0x8581, 0xEE4E, 0x85A2, 0xEE4F, 0x8582, 0xEE50, 0x8588, 0xEE51, 0x8585, 0xEE52, 0x8579, 0xEE53, 0x8576, 0xEE54, 0x8598, 0xEE55, 0x8590, 0xEE56, 0x859F, 0xEE57, 0x8668, 0xEE58, 0x87BE, 0xEE59, 0x87AA, 0xEE5A, 0x87AD, 0xEE5B, 0x87C5, 0xEE5C, 0x87B0, 0xEE5D, 0x87AC, 0xEE5E, 0x87B9, 0xEE5F, 0x87B5, 0xEE60, 0x87BC, 0xEE61, 0x87AE, 0xEE62, 0x87C9, 0xEE63, 0x87C3, 0xEE64, 0x87C2, 0xEE65, 0x87CC, 0xEE66, 0x87B7, 0xEE67, 0x87AF, 0xEE68, 0x87C4, 0xEE69, 0x87CA, 0xEE6A, 0x87B4, 0xEE6B, 0x87B6, 0xEE6C, 0x87BF, 0xEE6D, 0x87B8, 0xEE6E, 0x87BD, 0xEE6F, 0x87DE, 0xEE70, 0x87B2, 0xEE71, 0x8935, 0xEE72, 0x8933, 0xEE73, 0x893C, 0xEE74, 0x893E, 0xEE75, 0x8941, 0xEE76, 0x8952, 0xEE77, 0x8937, 0xEE78, 0x8942, 0xEE79, 0x89AD, 0xEE7A, 0x89AF, 0xEE7B, 0x89AE, 0xEE7C, 0x89F2, 0xEE7D, 0x89F3, 0xEE7E, 0x8B1E, 0xEEA1, 0x8B18, 0xEEA2, 0x8B16, 0xEEA3, 0x8B11, 0xEEA4, 0x8B05, 0xEEA5, 0x8B0B, 0xEEA6, 0x8B22, 0xEEA7, 0x8B0F, 0xEEA8, 0x8B12, 0xEEA9, 0x8B15, 0xEEAA, 0x8B07, 0xEEAB, 0x8B0D, 0xEEAC, 0x8B08, 0xEEAD, 0x8B06, 0xEEAE, 0x8B1C, 0xEEAF, 0x8B13, 0xEEB0, 0x8B1A, 0xEEB1, 0x8C4F, 0xEEB2, 0x8C70, 0xEEB3, 0x8C72, 0xEEB4, 0x8C71, 0xEEB5, 0x8C6F, 0xEEB6, 0x8C95, 0xEEB7, 0x8C94, 0xEEB8, 0x8CF9, 0xEEB9, 0x8D6F, 0xEEBA, 0x8E4E, 0xEEBB, 0x8E4D, 0xEEBC, 0x8E53, 0xEEBD, 0x8E50, 0xEEBE, 0x8E4C, 0xEEBF, 0x8E47, 0xEEC0, 0x8F43, 0xEEC1, 0x8F40, 0xEEC2, 0x9085, 0xEEC3, 0x907E, 0xEEC4, 0x9138, 0xEEC5, 0x919A, 0xEEC6, 0x91A2, 0xEEC7, 0x919B, 0xEEC8, 0x9199, 0xEEC9, 0x919F, 0xEECA, 0x91A1, 0xEECB, 0x919D, 0xEECC, 0x91A0, 0xEECD, 0x93A1, 0xEECE, 0x9383, 0xEECF, 0x93AF, 0xEED0, 0x9364, 0xEED1, 0x9356, 0xEED2, 0x9347, 0xEED3, 0x937C, 0xEED4, 0x9358, 0xEED5, 0x935C, 0xEED6, 0x9376, 0xEED7, 0x9349, 0xEED8, 0x9350, 0xEED9, 0x9351, 0xEEDA, 0x9360, 0xEEDB, 0x936D, 0xEEDC, 0x938F, 0xEEDD, 0x934C, 0xEEDE, 0x936A, 0xEEDF, 0x9379, 0xEEE0, 0x9357, 0xEEE1, 0x9355, 0xEEE2, 0x9352, 0xEEE3, 0x934F, 0xEEE4, 0x9371, 0xEEE5, 0x9377, 0xEEE6, 0x937B, 0xEEE7, 0x9361, 0xEEE8, 0x935E, 0xEEE9, 0x9363, 0xEEEA, 0x9367, 0xEEEB, 0x9380, 0xEEEC, 0x934E, 0xEEED, 0x9359, 0xEEEE, 0x95C7, 0xEEEF, 0x95C0, 0xEEF0, 0x95C9, 0xEEF1, 0x95C3, 0xEEF2, 0x95C5, 0xEEF3, 0x95B7, 0xEEF4, 0x96AE, 0xEEF5, 0x96B0, 0xEEF6, 0x96AC, 0xEEF7, 0x9720, 0xEEF8, 0x971F, 0xEEF9, 0x9718, 0xEEFA, 0x971D, 0xEEFB, 0x9719, 0xEEFC, 0x979A, 0xEEFD, 0x97A1, 0xEEFE, 0x979C, 0xEF40, 0x979E, 0xEF41, 0x979D, 0xEF42, 0x97D5, 0xEF43, 0x97D4, 0xEF44, 0x97F1, 0xEF45, 0x9841, 0xEF46, 0x9844, 0xEF47, 0x984A, 0xEF48, 0x9849, 0xEF49, 0x9845, 0xEF4A, 0x9843, 0xEF4B, 0x9925, 0xEF4C, 0x992B, 0xEF4D, 0x992C, 0xEF4E, 0x992A, 0xEF4F, 0x9933, 0xEF50, 0x9932, 0xEF51, 0x992F, 0xEF52, 0x992D, 0xEF53, 0x9931, 0xEF54, 0x9930, 0xEF55, 0x9998, 0xEF56, 0x99A3, 0xEF57, 0x99A1, 0xEF58, 0x9A02, 0xEF59, 0x99FA, 0xEF5A, 0x99F4, 0xEF5B, 0x99F7, 0xEF5C, 0x99F9, 0xEF5D, 0x99F8, 0xEF5E, 0x99F6, 0xEF5F, 0x99FB, 0xEF60, 0x99FD, 0xEF61, 0x99FE, 0xEF62, 0x99FC, 0xEF63, 0x9A03, 0xEF64, 0x9ABE, 0xEF65, 0x9AFE, 0xEF66, 0x9AFD, 0xEF67, 0x9B01, 0xEF68, 0x9AFC, 0xEF69, 0x9B48, 0xEF6A, 0x9B9A, 0xEF6B, 0x9BA8, 0xEF6C, 0x9B9E, 0xEF6D, 0x9B9B, 0xEF6E, 0x9BA6, 0xEF6F, 0x9BA1, 0xEF70, 0x9BA5, 0xEF71, 0x9BA4, 0xEF72, 0x9B86, 0xEF73, 0x9BA2, 0xEF74, 0x9BA0, 0xEF75, 0x9BAF, 0xEF76, 0x9D33, 0xEF77, 0x9D41, 0xEF78, 0x9D67, 0xEF79, 0x9D36, 0xEF7A, 0x9D2E, 0xEF7B, 0x9D2F, 0xEF7C, 0x9D31, 0xEF7D, 0x9D38, 0xEF7E, 0x9D30, 0xEFA1, 0x9D45, 0xEFA2, 0x9D42, 0xEFA3, 0x9D43, 0xEFA4, 0x9D3E, 0xEFA5, 0x9D37, 0xEFA6, 0x9D40, 0xEFA7, 0x9D3D, 0xEFA8, 0x7FF5, 0xEFA9, 0x9D2D, 0xEFAA, 0x9E8A, 0xEFAB, 0x9E89, 0xEFAC, 0x9E8D, 0xEFAD, 0x9EB0, 0xEFAE, 0x9EC8, 0xEFAF, 0x9EDA, 0xEFB0, 0x9EFB, 0xEFB1, 0x9EFF, 0xEFB2, 0x9F24, 0xEFB3, 0x9F23, 0xEFB4, 0x9F22, 0xEFB5, 0x9F54, 0xEFB6, 0x9FA0, 0xEFB7, 0x5131, 0xEFB8, 0x512D, 0xEFB9, 0x512E, 0xEFBA, 0x5698, 0xEFBB, 0x569C, 0xEFBC, 0x5697, 0xEFBD, 0x569A, 0xEFBE, 0x569D, 0xEFBF, 0x5699, 0xEFC0, 0x5970, 0xEFC1, 0x5B3C, 0xEFC2, 0x5C69, 0xEFC3, 0x5C6A, 0xEFC4, 0x5DC0, 0xEFC5, 0x5E6D, 0xEFC6, 0x5E6E, 0xEFC7, 0x61D8, 0xEFC8, 0x61DF, 0xEFC9, 0x61ED, 0xEFCA, 0x61EE, 0xEFCB, 0x61F1, 0xEFCC, 0x61EA, 0xEFCD, 0x61F0, 0xEFCE, 0x61EB, 0xEFCF, 0x61D6, 0xEFD0, 0x61E9, 0xEFD1, 0x64FF, 0xEFD2, 0x6504, 0xEFD3, 0x64FD, 0xEFD4, 0x64F8, 0xEFD5, 0x6501, 0xEFD6, 0x6503, 0xEFD7, 0x64FC, 0xEFD8, 0x6594, 0xEFD9, 0x65DB, 0xEFDA, 0x66DA, 0xEFDB, 0x66DB, 0xEFDC, 0x66D8, 0xEFDD, 0x6AC5, 0xEFDE, 0x6AB9, 0xEFDF, 0x6ABD, 0xEFE0, 0x6AE1, 0xEFE1, 0x6AC6, 0xEFE2, 0x6ABA, 0xEFE3, 0x6AB6, 0xEFE4, 0x6AB7, 0xEFE5, 0x6AC7, 0xEFE6, 0x6AB4, 0xEFE7, 0x6AAD, 0xEFE8, 0x6B5E, 0xEFE9, 0x6BC9, 0xEFEA, 0x6C0B, 0xEFEB, 0x7007, 0xEFEC, 0x700C, 0xEFED, 0x700D, 0xEFEE, 0x7001, 0xEFEF, 0x7005, 0xEFF0, 0x7014, 0xEFF1, 0x700E, 0xEFF2, 0x6FFF, 0xEFF3, 0x7000, 0xEFF4, 0x6FFB, 0xEFF5, 0x7026, 0xEFF6, 0x6FFC, 0xEFF7, 0x6FF7, 0xEFF8, 0x700A, 0xEFF9, 0x7201, 0xEFFA, 0x71FF, 0xEFFB, 0x71F9, 0xEFFC, 0x7203, 0xEFFD, 0x71FD, 0xEFFE, 0x7376, 0xF040, 0x74B8, 0xF041, 0x74C0, 0xF042, 0x74B5, 0xF043, 0x74C1, 0xF044, 0x74BE, 0xF045, 0x74B6, 0xF046, 0x74BB, 0xF047, 0x74C2, 0xF048, 0x7514, 0xF049, 0x7513, 0xF04A, 0x765C, 0xF04B, 0x7664, 0xF04C, 0x7659, 0xF04D, 0x7650, 0xF04E, 0x7653, 0xF04F, 0x7657, 0xF050, 0x765A, 0xF051, 0x76A6, 0xF052, 0x76BD, 0xF053, 0x76EC, 0xF054, 0x77C2, 0xF055, 0x77BA, 0xF056, 0x78FF, 0xF057, 0x790C, 0xF058, 0x7913, 0xF059, 0x7914, 0xF05A, 0x7909, 0xF05B, 0x7910, 0xF05C, 0x7912, 0xF05D, 0x7911, 0xF05E, 0x79AD, 0xF05F, 0x79AC, 0xF060, 0x7A5F, 0xF061, 0x7C1C, 0xF062, 0x7C29, 0xF063, 0x7C19, 0xF064, 0x7C20, 0xF065, 0x7C1F, 0xF066, 0x7C2D, 0xF067, 0x7C1D, 0xF068, 0x7C26, 0xF069, 0x7C28, 0xF06A, 0x7C22, 0xF06B, 0x7C25, 0xF06C, 0x7C30, 0xF06D, 0x7E5C, 0xF06E, 0x7E50, 0xF06F, 0x7E56, 0xF070, 0x7E63, 0xF071, 0x7E58, 0xF072, 0x7E62, 0xF073, 0x7E5F, 0xF074, 0x7E51, 0xF075, 0x7E60, 0xF076, 0x7E57, 0xF077, 0x7E53, 0xF078, 0x7FB5, 0xF079, 0x7FB3, 0xF07A, 0x7FF7, 0xF07B, 0x7FF8, 0xF07C, 0x8075, 0xF07D, 0x81D1, 0xF07E, 0x81D2, 0xF0A1, 0x81D0, 0xF0A2, 0x825F, 0xF0A3, 0x825E, 0xF0A4, 0x85B4, 0xF0A5, 0x85C6, 0xF0A6, 0x85C0, 0xF0A7, 0x85C3, 0xF0A8, 0x85C2, 0xF0A9, 0x85B3, 0xF0AA, 0x85B5, 0xF0AB, 0x85BD, 0xF0AC, 0x85C7, 0xF0AD, 0x85C4, 0xF0AE, 0x85BF, 0xF0AF, 0x85CB, 0xF0B0, 0x85CE, 0xF0B1, 0x85C8, 0xF0B2, 0x85C5, 0xF0B3, 0x85B1, 0xF0B4, 0x85B6, 0xF0B5, 0x85D2, 0xF0B6, 0x8624, 0xF0B7, 0x85B8, 0xF0B8, 0x85B7, 0xF0B9, 0x85BE, 0xF0BA, 0x8669, 0xF0BB, 0x87E7, 0xF0BC, 0x87E6, 0xF0BD, 0x87E2, 0xF0BE, 0x87DB, 0xF0BF, 0x87EB, 0xF0C0, 0x87EA, 0xF0C1, 0x87E5, 0xF0C2, 0x87DF, 0xF0C3, 0x87F3, 0xF0C4, 0x87E4, 0xF0C5, 0x87D4, 0xF0C6, 0x87DC, 0xF0C7, 0x87D3, 0xF0C8, 0x87ED, 0xF0C9, 0x87D8, 0xF0CA, 0x87E3, 0xF0CB, 0x87A4, 0xF0CC, 0x87D7, 0xF0CD, 0x87D9, 0xF0CE, 0x8801, 0xF0CF, 0x87F4, 0xF0D0, 0x87E8, 0xF0D1, 0x87DD, 0xF0D2, 0x8953, 0xF0D3, 0x894B, 0xF0D4, 0x894F, 0xF0D5, 0x894C, 0xF0D6, 0x8946, 0xF0D7, 0x8950, 0xF0D8, 0x8951, 0xF0D9, 0x8949, 0xF0DA, 0x8B2A, 0xF0DB, 0x8B27, 0xF0DC, 0x8B23, 0xF0DD, 0x8B33, 0xF0DE, 0x8B30, 0xF0DF, 0x8B35, 0xF0E0, 0x8B47, 0xF0E1, 0x8B2F, 0xF0E2, 0x8B3C, 0xF0E3, 0x8B3E, 0xF0E4, 0x8B31, 0xF0E5, 0x8B25, 0xF0E6, 0x8B37, 0xF0E7, 0x8B26, 0xF0E8, 0x8B36, 0xF0E9, 0x8B2E, 0xF0EA, 0x8B24, 0xF0EB, 0x8B3B, 0xF0EC, 0x8B3D, 0xF0ED, 0x8B3A, 0xF0EE, 0x8C42, 0xF0EF, 0x8C75, 0xF0F0, 0x8C99, 0xF0F1, 0x8C98, 0xF0F2, 0x8C97, 0xF0F3, 0x8CFE, 0xF0F4, 0x8D04, 0xF0F5, 0x8D02, 0xF0F6, 0x8D00, 0xF0F7, 0x8E5C, 0xF0F8, 0x8E62, 0xF0F9, 0x8E60, 0xF0FA, 0x8E57, 0xF0FB, 0x8E56, 0xF0FC, 0x8E5E, 0xF0FD, 0x8E65, 0xF0FE, 0x8E67, 0xF140, 0x8E5B, 0xF141, 0x8E5A, 0xF142, 0x8E61, 0xF143, 0x8E5D, 0xF144, 0x8E69, 0xF145, 0x8E54, 0xF146, 0x8F46, 0xF147, 0x8F47, 0xF148, 0x8F48, 0xF149, 0x8F4B, 0xF14A, 0x9128, 0xF14B, 0x913A, 0xF14C, 0x913B, 0xF14D, 0x913E, 0xF14E, 0x91A8, 0xF14F, 0x91A5, 0xF150, 0x91A7, 0xF151, 0x91AF, 0xF152, 0x91AA, 0xF153, 0x93B5, 0xF154, 0x938C, 0xF155, 0x9392, 0xF156, 0x93B7, 0xF157, 0x939B, 0xF158, 0x939D, 0xF159, 0x9389, 0xF15A, 0x93A7, 0xF15B, 0x938E, 0xF15C, 0x93AA, 0xF15D, 0x939E, 0xF15E, 0x93A6, 0xF15F, 0x9395, 0xF160, 0x9388, 0xF161, 0x9399, 0xF162, 0x939F, 0xF163, 0x938D, 0xF164, 0x93B1, 0xF165, 0x9391, 0xF166, 0x93B2, 0xF167, 0x93A4, 0xF168, 0x93A8, 0xF169, 0x93B4, 0xF16A, 0x93A3, 0xF16B, 0x93A5, 0xF16C, 0x95D2, 0xF16D, 0x95D3, 0xF16E, 0x95D1, 0xF16F, 0x96B3, 0xF170, 0x96D7, 0xF171, 0x96DA, 0xF172, 0x5DC2, 0xF173, 0x96DF, 0xF174, 0x96D8, 0xF175, 0x96DD, 0xF176, 0x9723, 0xF177, 0x9722, 0xF178, 0x9725, 0xF179, 0x97AC, 0xF17A, 0x97AE, 0xF17B, 0x97A8, 0xF17C, 0x97AB, 0xF17D, 0x97A4, 0xF17E, 0x97AA, 0xF1A1, 0x97A2, 0xF1A2, 0x97A5, 0xF1A3, 0x97D7, 0xF1A4, 0x97D9, 0xF1A5, 0x97D6, 0xF1A6, 0x97D8, 0xF1A7, 0x97FA, 0xF1A8, 0x9850, 0xF1A9, 0x9851, 0xF1AA, 0x9852, 0xF1AB, 0x98B8, 0xF1AC, 0x9941, 0xF1AD, 0x993C, 0xF1AE, 0x993A, 0xF1AF, 0x9A0F, 0xF1B0, 0x9A0B, 0xF1B1, 0x9A09, 0xF1B2, 0x9A0D, 0xF1B3, 0x9A04, 0xF1B4, 0x9A11, 0xF1B5, 0x9A0A, 0xF1B6, 0x9A05, 0xF1B7, 0x9A07, 0xF1B8, 0x9A06, 0xF1B9, 0x9AC0, 0xF1BA, 0x9ADC, 0xF1BB, 0x9B08, 0xF1BC, 0x9B04, 0xF1BD, 0x9B05, 0xF1BE, 0x9B29, 0xF1BF, 0x9B35, 0xF1C0, 0x9B4A, 0xF1C1, 0x9B4C, 0xF1C2, 0x9B4B, 0xF1C3, 0x9BC7, 0xF1C4, 0x9BC6, 0xF1C5, 0x9BC3, 0xF1C6, 0x9BBF, 0xF1C7, 0x9BC1, 0xF1C8, 0x9BB5, 0xF1C9, 0x9BB8, 0xF1CA, 0x9BD3, 0xF1CB, 0x9BB6, 0xF1CC, 0x9BC4, 0xF1CD, 0x9BB9, 0xF1CE, 0x9BBD, 0xF1CF, 0x9D5C, 0xF1D0, 0x9D53, 0xF1D1, 0x9D4F, 0xF1D2, 0x9D4A, 0xF1D3, 0x9D5B, 0xF1D4, 0x9D4B, 0xF1D5, 0x9D59, 0xF1D6, 0x9D56, 0xF1D7, 0x9D4C, 0xF1D8, 0x9D57, 0xF1D9, 0x9D52, 0xF1DA, 0x9D54, 0xF1DB, 0x9D5F, 0xF1DC, 0x9D58, 0xF1DD, 0x9D5A, 0xF1DE, 0x9E8E, 0xF1DF, 0x9E8C, 0xF1E0, 0x9EDF, 0xF1E1, 0x9F01, 0xF1E2, 0x9F00, 0xF1E3, 0x9F16, 0xF1E4, 0x9F25, 0xF1E5, 0x9F2B, 0xF1E6, 0x9F2A, 0xF1E7, 0x9F29, 0xF1E8, 0x9F28, 0xF1E9, 0x9F4C, 0xF1EA, 0x9F55, 0xF1EB, 0x5134, 0xF1EC, 0x5135, 0xF1ED, 0x5296, 0xF1EE, 0x52F7, 0xF1EF, 0x53B4, 0xF1F0, 0x56AB, 0xF1F1, 0x56AD, 0xF1F2, 0x56A6, 0xF1F3, 0x56A7, 0xF1F4, 0x56AA, 0xF1F5, 0x56AC, 0xF1F6, 0x58DA, 0xF1F7, 0x58DD, 0xF1F8, 0x58DB, 0xF1F9, 0x5912, 0xF1FA, 0x5B3D, 0xF1FB, 0x5B3E, 0xF1FC, 0x5B3F, 0xF1FD, 0x5DC3, 0xF1FE, 0x5E70, 0xF240, 0x5FBF, 0xF241, 0x61FB, 0xF242, 0x6507, 0xF243, 0x6510, 0xF244, 0x650D, 0xF245, 0x6509, 0xF246, 0x650C, 0xF247, 0x650E, 0xF248, 0x6584, 0xF249, 0x65DE, 0xF24A, 0x65DD, 0xF24B, 0x66DE, 0xF24C, 0x6AE7, 0xF24D, 0x6AE0, 0xF24E, 0x6ACC, 0xF24F, 0x6AD1, 0xF250, 0x6AD9, 0xF251, 0x6ACB, 0xF252, 0x6ADF, 0xF253, 0x6ADC, 0xF254, 0x6AD0, 0xF255, 0x6AEB, 0xF256, 0x6ACF, 0xF257, 0x6ACD, 0xF258, 0x6ADE, 0xF259, 0x6B60, 0xF25A, 0x6BB0, 0xF25B, 0x6C0C, 0xF25C, 0x7019, 0xF25D, 0x7027, 0xF25E, 0x7020, 0xF25F, 0x7016, 0xF260, 0x702B, 0xF261, 0x7021, 0xF262, 0x7022, 0xF263, 0x7023, 0xF264, 0x7029, 0xF265, 0x7017, 0xF266, 0x7024, 0xF267, 0x701C, 0xF268, 0x702A, 0xF269, 0x720C, 0xF26A, 0x720A, 0xF26B, 0x7207, 0xF26C, 0x7202, 0xF26D, 0x7205, 0xF26E, 0x72A5, 0xF26F, 0x72A6, 0xF270, 0x72A4, 0xF271, 0x72A3, 0xF272, 0x72A1, 0xF273, 0x74CB, 0xF274, 0x74C5, 0xF275, 0x74B7, 0xF276, 0x74C3, 0xF277, 0x7516, 0xF278, 0x7660, 0xF279, 0x77C9, 0xF27A, 0x77CA, 0xF27B, 0x77C4, 0xF27C, 0x77F1, 0xF27D, 0x791D, 0xF27E, 0x791B, 0xF2A1, 0x7921, 0xF2A2, 0x791C, 0xF2A3, 0x7917, 0xF2A4, 0x791E, 0xF2A5, 0x79B0, 0xF2A6, 0x7A67, 0xF2A7, 0x7A68, 0xF2A8, 0x7C33, 0xF2A9, 0x7C3C, 0xF2AA, 0x7C39, 0xF2AB, 0x7C2C, 0xF2AC, 0x7C3B, 0xF2AD, 0x7CEC, 0xF2AE, 0x7CEA, 0xF2AF, 0x7E76, 0xF2B0, 0x7E75, 0xF2B1, 0x7E78, 0xF2B2, 0x7E70, 0xF2B3, 0x7E77, 0xF2B4, 0x7E6F, 0xF2B5, 0x7E7A, 0xF2B6, 0x7E72, 0xF2B7, 0x7E74, 0xF2B8, 0x7E68, 0xF2B9, 0x7F4B, 0xF2BA, 0x7F4A, 0xF2BB, 0x7F83, 0xF2BC, 0x7F86, 0xF2BD, 0x7FB7, 0xF2BE, 0x7FFD, 0xF2BF, 0x7FFE, 0xF2C0, 0x8078, 0xF2C1, 0x81D7, 0xF2C2, 0x81D5, 0xF2C3, 0x8264, 0xF2C4, 0x8261, 0xF2C5, 0x8263, 0xF2C6, 0x85EB, 0xF2C7, 0x85F1, 0xF2C8, 0x85ED, 0xF2C9, 0x85D9, 0xF2CA, 0x85E1, 0xF2CB, 0x85E8, 0xF2CC, 0x85DA, 0xF2CD, 0x85D7, 0xF2CE, 0x85EC, 0xF2CF, 0x85F2, 0xF2D0, 0x85F8, 0xF2D1, 0x85D8, 0xF2D2, 0x85DF, 0xF2D3, 0x85E3, 0xF2D4, 0x85DC, 0xF2D5, 0x85D1, 0xF2D6, 0x85F0, 0xF2D7, 0x85E6, 0xF2D8, 0x85EF, 0xF2D9, 0x85DE, 0xF2DA, 0x85E2, 0xF2DB, 0x8800, 0xF2DC, 0x87FA, 0xF2DD, 0x8803, 0xF2DE, 0x87F6, 0xF2DF, 0x87F7, 0xF2E0, 0x8809, 0xF2E1, 0x880C, 0xF2E2, 0x880B, 0xF2E3, 0x8806, 0xF2E4, 0x87FC, 0xF2E5, 0x8808, 0xF2E6, 0x87FF, 0xF2E7, 0x880A, 0xF2E8, 0x8802, 0xF2E9, 0x8962, 0xF2EA, 0x895A, 0xF2EB, 0x895B, 0xF2EC, 0x8957, 0xF2ED, 0x8961, 0xF2EE, 0x895C, 0xF2EF, 0x8958, 0xF2F0, 0x895D, 0xF2F1, 0x8959, 0xF2F2, 0x8988, 0xF2F3, 0x89B7, 0xF2F4, 0x89B6, 0xF2F5, 0x89F6, 0xF2F6, 0x8B50, 0xF2F7, 0x8B48, 0xF2F8, 0x8B4A, 0xF2F9, 0x8B40, 0xF2FA, 0x8B53, 0xF2FB, 0x8B56, 0xF2FC, 0x8B54, 0xF2FD, 0x8B4B, 0xF2FE, 0x8B55, 0xF340, 0x8B51, 0xF341, 0x8B42, 0xF342, 0x8B52, 0xF343, 0x8B57, 0xF344, 0x8C43, 0xF345, 0x8C77, 0xF346, 0x8C76, 0xF347, 0x8C9A, 0xF348, 0x8D06, 0xF349, 0x8D07, 0xF34A, 0x8D09, 0xF34B, 0x8DAC, 0xF34C, 0x8DAA, 0xF34D, 0x8DAD, 0xF34E, 0x8DAB, 0xF34F, 0x8E6D, 0xF350, 0x8E78, 0xF351, 0x8E73, 0xF352, 0x8E6A, 0xF353, 0x8E6F, 0xF354, 0x8E7B, 0xF355, 0x8EC2, 0xF356, 0x8F52, 0xF357, 0x8F51, 0xF358, 0x8F4F, 0xF359, 0x8F50, 0xF35A, 0x8F53, 0xF35B, 0x8FB4, 0xF35C, 0x9140, 0xF35D, 0x913F, 0xF35E, 0x91B0, 0xF35F, 0x91AD, 0xF360, 0x93DE, 0xF361, 0x93C7, 0xF362, 0x93CF, 0xF363, 0x93C2, 0xF364, 0x93DA, 0xF365, 0x93D0, 0xF366, 0x93F9, 0xF367, 0x93EC, 0xF368, 0x93CC, 0xF369, 0x93D9, 0xF36A, 0x93A9, 0xF36B, 0x93E6, 0xF36C, 0x93CA, 0xF36D, 0x93D4, 0xF36E, 0x93EE, 0xF36F, 0x93E3, 0xF370, 0x93D5, 0xF371, 0x93C4, 0xF372, 0x93CE, 0xF373, 0x93C0, 0xF374, 0x93D2, 0xF375, 0x93E7, 0xF376, 0x957D, 0xF377, 0x95DA, 0xF378, 0x95DB, 0xF379, 0x96E1, 0xF37A, 0x9729, 0xF37B, 0x972B, 0xF37C, 0x972C, 0xF37D, 0x9728, 0xF37E, 0x9726, 0xF3A1, 0x97B3, 0xF3A2, 0x97B7, 0xF3A3, 0x97B6, 0xF3A4, 0x97DD, 0xF3A5, 0x97DE, 0xF3A6, 0x97DF, 0xF3A7, 0x985C, 0xF3A8, 0x9859, 0xF3A9, 0x985D, 0xF3AA, 0x9857, 0xF3AB, 0x98BF, 0xF3AC, 0x98BD, 0xF3AD, 0x98BB, 0xF3AE, 0x98BE, 0xF3AF, 0x9948, 0xF3B0, 0x9947, 0xF3B1, 0x9943, 0xF3B2, 0x99A6, 0xF3B3, 0x99A7, 0xF3B4, 0x9A1A, 0xF3B5, 0x9A15, 0xF3B6, 0x9A25, 0xF3B7, 0x9A1D, 0xF3B8, 0x9A24, 0xF3B9, 0x9A1B, 0xF3BA, 0x9A22, 0xF3BB, 0x9A20, 0xF3BC, 0x9A27, 0xF3BD, 0x9A23, 0xF3BE, 0x9A1E, 0xF3BF, 0x9A1C, 0xF3C0, 0x9A14, 0xF3C1, 0x9AC2, 0xF3C2, 0x9B0B, 0xF3C3, 0x9B0A, 0xF3C4, 0x9B0E, 0xF3C5, 0x9B0C, 0xF3C6, 0x9B37, 0xF3C7, 0x9BEA, 0xF3C8, 0x9BEB, 0xF3C9, 0x9BE0, 0xF3CA, 0x9BDE, 0xF3CB, 0x9BE4, 0xF3CC, 0x9BE6, 0xF3CD, 0x9BE2, 0xF3CE, 0x9BF0, 0xF3CF, 0x9BD4, 0xF3D0, 0x9BD7, 0xF3D1, 0x9BEC, 0xF3D2, 0x9BDC, 0xF3D3, 0x9BD9, 0xF3D4, 0x9BE5, 0xF3D5, 0x9BD5, 0xF3D6, 0x9BE1, 0xF3D7, 0x9BDA, 0xF3D8, 0x9D77, 0xF3D9, 0x9D81, 0xF3DA, 0x9D8A, 0xF3DB, 0x9D84, 0xF3DC, 0x9D88, 0xF3DD, 0x9D71, 0xF3DE, 0x9D80, 0xF3DF, 0x9D78, 0xF3E0, 0x9D86, 0xF3E1, 0x9D8B, 0xF3E2, 0x9D8C, 0xF3E3, 0x9D7D, 0xF3E4, 0x9D6B, 0xF3E5, 0x9D74, 0xF3E6, 0x9D75, 0xF3E7, 0x9D70, 0xF3E8, 0x9D69, 0xF3E9, 0x9D85, 0xF3EA, 0x9D73, 0xF3EB, 0x9D7B, 0xF3EC, 0x9D82, 0xF3ED, 0x9D6F, 0xF3EE, 0x9D79, 0xF3EF, 0x9D7F, 0xF3F0, 0x9D87, 0xF3F1, 0x9D68, 0xF3F2, 0x9E94, 0xF3F3, 0x9E91, 0xF3F4, 0x9EC0, 0xF3F5, 0x9EFC, 0xF3F6, 0x9F2D, 0xF3F7, 0x9F40, 0xF3F8, 0x9F41, 0xF3F9, 0x9F4D, 0xF3FA, 0x9F56, 0xF3FB, 0x9F57, 0xF3FC, 0x9F58, 0xF3FD, 0x5337, 0xF3FE, 0x56B2, 0xF440, 0x56B5, 0xF441, 0x56B3, 0xF442, 0x58E3, 0xF443, 0x5B45, 0xF444, 0x5DC6, 0xF445, 0x5DC7, 0xF446, 0x5EEE, 0xF447, 0x5EEF, 0xF448, 0x5FC0, 0xF449, 0x5FC1, 0xF44A, 0x61F9, 0xF44B, 0x6517, 0xF44C, 0x6516, 0xF44D, 0x6515, 0xF44E, 0x6513, 0xF44F, 0x65DF, 0xF450, 0x66E8, 0xF451, 0x66E3, 0xF452, 0x66E4, 0xF453, 0x6AF3, 0xF454, 0x6AF0, 0xF455, 0x6AEA, 0xF456, 0x6AE8, 0xF457, 0x6AF9, 0xF458, 0x6AF1, 0xF459, 0x6AEE, 0xF45A, 0x6AEF, 0xF45B, 0x703C, 0xF45C, 0x7035, 0xF45D, 0x702F, 0xF45E, 0x7037, 0xF45F, 0x7034, 0xF460, 0x7031, 0xF461, 0x7042, 0xF462, 0x7038, 0xF463, 0x703F, 0xF464, 0x703A, 0xF465, 0x7039, 0xF466, 0x7040, 0xF467, 0x703B, 0xF468, 0x7033, 0xF469, 0x7041, 0xF46A, 0x7213, 0xF46B, 0x7214, 0xF46C, 0x72A8, 0xF46D, 0x737D, 0xF46E, 0x737C, 0xF46F, 0x74BA, 0xF470, 0x76AB, 0xF471, 0x76AA, 0xF472, 0x76BE, 0xF473, 0x76ED, 0xF474, 0x77CC, 0xF475, 0x77CE, 0xF476, 0x77CF, 0xF477, 0x77CD, 0xF478, 0x77F2, 0xF479, 0x7925, 0xF47A, 0x7923, 0xF47B, 0x7927, 0xF47C, 0x7928, 0xF47D, 0x7924, 0xF47E, 0x7929, 0xF4A1, 0x79B2, 0xF4A2, 0x7A6E, 0xF4A3, 0x7A6C, 0xF4A4, 0x7A6D, 0xF4A5, 0x7AF7, 0xF4A6, 0x7C49, 0xF4A7, 0x7C48, 0xF4A8, 0x7C4A, 0xF4A9, 0x7C47, 0xF4AA, 0x7C45, 0xF4AB, 0x7CEE, 0xF4AC, 0x7E7B, 0xF4AD, 0x7E7E, 0xF4AE, 0x7E81, 0xF4AF, 0x7E80, 0xF4B0, 0x7FBA, 0xF4B1, 0x7FFF, 0xF4B2, 0x8079, 0xF4B3, 0x81DB, 0xF4B4, 0x81D9, 0xF4B5, 0x820B, 0xF4B6, 0x8268, 0xF4B7, 0x8269, 0xF4B8, 0x8622, 0xF4B9, 0x85FF, 0xF4BA, 0x8601, 0xF4BB, 0x85FE, 0xF4BC, 0x861B, 0xF4BD, 0x8600, 0xF4BE, 0x85F6, 0xF4BF, 0x8604, 0xF4C0, 0x8609, 0xF4C1, 0x8605, 0xF4C2, 0x860C, 0xF4C3, 0x85FD, 0xF4C4, 0x8819, 0xF4C5, 0x8810, 0xF4C6, 0x8811, 0xF4C7, 0x8817, 0xF4C8, 0x8813, 0xF4C9, 0x8816, 0xF4CA, 0x8963, 0xF4CB, 0x8966, 0xF4CC, 0x89B9, 0xF4CD, 0x89F7, 0xF4CE, 0x8B60, 0xF4CF, 0x8B6A, 0xF4D0, 0x8B5D, 0xF4D1, 0x8B68, 0xF4D2, 0x8B63, 0xF4D3, 0x8B65, 0xF4D4, 0x8B67, 0xF4D5, 0x8B6D, 0xF4D6, 0x8DAE, 0xF4D7, 0x8E86, 0xF4D8, 0x8E88, 0xF4D9, 0x8E84, 0xF4DA, 0x8F59, 0xF4DB, 0x8F56, 0xF4DC, 0x8F57, 0xF4DD, 0x8F55, 0xF4DE, 0x8F58, 0xF4DF, 0x8F5A, 0xF4E0, 0x908D, 0xF4E1, 0x9143, 0xF4E2, 0x9141, 0xF4E3, 0x91B7, 0xF4E4, 0x91B5, 0xF4E5, 0x91B2, 0xF4E6, 0x91B3, 0xF4E7, 0x940B, 0xF4E8, 0x9413, 0xF4E9, 0x93FB, 0xF4EA, 0x9420, 0xF4EB, 0x940F, 0xF4EC, 0x9414, 0xF4ED, 0x93FE, 0xF4EE, 0x9415, 0xF4EF, 0x9410, 0xF4F0, 0x9428, 0xF4F1, 0x9419, 0xF4F2, 0x940D, 0xF4F3, 0x93F5, 0xF4F4, 0x9400, 0xF4F5, 0x93F7, 0xF4F6, 0x9407, 0xF4F7, 0x940E, 0xF4F8, 0x9416, 0xF4F9, 0x9412, 0xF4FA, 0x93FA, 0xF4FB, 0x9409, 0xF4FC, 0x93F8, 0xF4FD, 0x940A, 0xF4FE, 0x93FF, 0xF540, 0x93FC, 0xF541, 0x940C, 0xF542, 0x93F6, 0xF543, 0x9411, 0xF544, 0x9406, 0xF545, 0x95DE, 0xF546, 0x95E0, 0xF547, 0x95DF, 0xF548, 0x972E, 0xF549, 0x972F, 0xF54A, 0x97B9, 0xF54B, 0x97BB, 0xF54C, 0x97FD, 0xF54D, 0x97FE, 0xF54E, 0x9860, 0xF54F, 0x9862, 0xF550, 0x9863, 0xF551, 0x985F, 0xF552, 0x98C1, 0xF553, 0x98C2, 0xF554, 0x9950, 0xF555, 0x994E, 0xF556, 0x9959, 0xF557, 0x994C, 0xF558, 0x994B, 0xF559, 0x9953, 0xF55A, 0x9A32, 0xF55B, 0x9A34, 0xF55C, 0x9A31, 0xF55D, 0x9A2C, 0xF55E, 0x9A2A, 0xF55F, 0x9A36, 0xF560, 0x9A29, 0xF561, 0x9A2E, 0xF562, 0x9A38, 0xF563, 0x9A2D, 0xF564, 0x9AC7, 0xF565, 0x9ACA, 0xF566, 0x9AC6, 0xF567, 0x9B10, 0xF568, 0x9B12, 0xF569, 0x9B11, 0xF56A, 0x9C0B, 0xF56B, 0x9C08, 0xF56C, 0x9BF7, 0xF56D, 0x9C05, 0xF56E, 0x9C12, 0xF56F, 0x9BF8, 0xF570, 0x9C40, 0xF571, 0x9C07, 0xF572, 0x9C0E, 0xF573, 0x9C06, 0xF574, 0x9C17, 0xF575, 0x9C14, 0xF576, 0x9C09, 0xF577, 0x9D9F, 0xF578, 0x9D99, 0xF579, 0x9DA4, 0xF57A, 0x9D9D, 0xF57B, 0x9D92, 0xF57C, 0x9D98, 0xF57D, 0x9D90, 0xF57E, 0x9D9B, 0xF5A1, 0x9DA0, 0xF5A2, 0x9D94, 0xF5A3, 0x9D9C, 0xF5A4, 0x9DAA, 0xF5A5, 0x9D97, 0xF5A6, 0x9DA1, 0xF5A7, 0x9D9A, 0xF5A8, 0x9DA2, 0xF5A9, 0x9DA8, 0xF5AA, 0x9D9E, 0xF5AB, 0x9DA3, 0xF5AC, 0x9DBF, 0xF5AD, 0x9DA9, 0xF5AE, 0x9D96, 0xF5AF, 0x9DA6, 0xF5B0, 0x9DA7, 0xF5B1, 0x9E99, 0xF5B2, 0x9E9B, 0xF5B3, 0x9E9A, 0xF5B4, 0x9EE5, 0xF5B5, 0x9EE4, 0xF5B6, 0x9EE7, 0xF5B7, 0x9EE6, 0xF5B8, 0x9F30, 0xF5B9, 0x9F2E, 0xF5BA, 0x9F5B, 0xF5BB, 0x9F60, 0xF5BC, 0x9F5E, 0xF5BD, 0x9F5D, 0xF5BE, 0x9F59, 0xF5BF, 0x9F91, 0xF5C0, 0x513A, 0xF5C1, 0x5139, 0xF5C2, 0x5298, 0xF5C3, 0x5297, 0xF5C4, 0x56C3, 0xF5C5, 0x56BD, 0xF5C6, 0x56BE, 0xF5C7, 0x5B48, 0xF5C8, 0x5B47, 0xF5C9, 0x5DCB, 0xF5CA, 0x5DCF, 0xF5CB, 0x5EF1, 0xF5CC, 0x61FD, 0xF5CD, 0x651B, 0xF5CE, 0x6B02, 0xF5CF, 0x6AFC, 0xF5D0, 0x6B03, 0xF5D1, 0x6AF8, 0xF5D2, 0x6B00, 0xF5D3, 0x7043, 0xF5D4, 0x7044, 0xF5D5, 0x704A, 0xF5D6, 0x7048, 0xF5D7, 0x7049, 0xF5D8, 0x7045, 0xF5D9, 0x7046, 0xF5DA, 0x721D, 0xF5DB, 0x721A, 0xF5DC, 0x7219, 0xF5DD, 0x737E, 0xF5DE, 0x7517, 0xF5DF, 0x766A, 0xF5E0, 0x77D0, 0xF5E1, 0x792D, 0xF5E2, 0x7931, 0xF5E3, 0x792F, 0xF5E4, 0x7C54, 0xF5E5, 0x7C53, 0xF5E6, 0x7CF2, 0xF5E7, 0x7E8A, 0xF5E8, 0x7E87, 0xF5E9, 0x7E88, 0xF5EA, 0x7E8B, 0xF5EB, 0x7E86, 0xF5EC, 0x7E8D, 0xF5ED, 0x7F4D, 0xF5EE, 0x7FBB, 0xF5EF, 0x8030, 0xF5F0, 0x81DD, 0xF5F1, 0x8618, 0xF5F2, 0x862A, 0xF5F3, 0x8626, 0xF5F4, 0x861F, 0xF5F5, 0x8623, 0xF5F6, 0x861C, 0xF5F7, 0x8619, 0xF5F8, 0x8627, 0xF5F9, 0x862E, 0xF5FA, 0x8621, 0xF5FB, 0x8620, 0xF5FC, 0x8629, 0xF5FD, 0x861E, 0xF5FE, 0x8625, 0xF640, 0x8829, 0xF641, 0x881D, 0xF642, 0x881B, 0xF643, 0x8820, 0xF644, 0x8824, 0xF645, 0x881C, 0xF646, 0x882B, 0xF647, 0x884A, 0xF648, 0x896D, 0xF649, 0x8969, 0xF64A, 0x896E, 0xF64B, 0x896B, 0xF64C, 0x89FA, 0xF64D, 0x8B79, 0xF64E, 0x8B78, 0xF64F, 0x8B45, 0xF650, 0x8B7A, 0xF651, 0x8B7B, 0xF652, 0x8D10, 0xF653, 0x8D14, 0xF654, 0x8DAF, 0xF655, 0x8E8E, 0xF656, 0x8E8C, 0xF657, 0x8F5E, 0xF658, 0x8F5B, 0xF659, 0x8F5D, 0xF65A, 0x9146, 0xF65B, 0x9144, 0xF65C, 0x9145, 0xF65D, 0x91B9, 0xF65E, 0x943F, 0xF65F, 0x943B, 0xF660, 0x9436, 0xF661, 0x9429, 0xF662, 0x943D, 0xF663, 0x943C, 0xF664, 0x9430, 0xF665, 0x9439, 0xF666, 0x942A, 0xF667, 0x9437, 0xF668, 0x942C, 0xF669, 0x9440, 0xF66A, 0x9431, 0xF66B, 0x95E5, 0xF66C, 0x95E4, 0xF66D, 0x95E3, 0xF66E, 0x9735, 0xF66F, 0x973A, 0xF670, 0x97BF, 0xF671, 0x97E1, 0xF672, 0x9864, 0xF673, 0x98C9, 0xF674, 0x98C6, 0xF675, 0x98C0, 0xF676, 0x9958, 0xF677, 0x9956, 0xF678, 0x9A39, 0xF679, 0x9A3D, 0xF67A, 0x9A46, 0xF67B, 0x9A44, 0xF67C, 0x9A42, 0xF67D, 0x9A41, 0xF67E, 0x9A3A, 0xF6A1, 0x9A3F, 0xF6A2, 0x9ACD, 0xF6A3, 0x9B15, 0xF6A4, 0x9B17, 0xF6A5, 0x9B18, 0xF6A6, 0x9B16, 0xF6A7, 0x9B3A, 0xF6A8, 0x9B52, 0xF6A9, 0x9C2B, 0xF6AA, 0x9C1D, 0xF6AB, 0x9C1C, 0xF6AC, 0x9C2C, 0xF6AD, 0x9C23, 0xF6AE, 0x9C28, 0xF6AF, 0x9C29, 0xF6B0, 0x9C24, 0xF6B1, 0x9C21, 0xF6B2, 0x9DB7, 0xF6B3, 0x9DB6, 0xF6B4, 0x9DBC, 0xF6B5, 0x9DC1, 0xF6B6, 0x9DC7, 0xF6B7, 0x9DCA, 0xF6B8, 0x9DCF, 0xF6B9, 0x9DBE, 0xF6BA, 0x9DC5, 0xF6BB, 0x9DC3, 0xF6BC, 0x9DBB, 0xF6BD, 0x9DB5, 0xF6BE, 0x9DCE, 0xF6BF, 0x9DB9, 0xF6C0, 0x9DBA, 0xF6C1, 0x9DAC, 0xF6C2, 0x9DC8, 0xF6C3, 0x9DB1, 0xF6C4, 0x9DAD, 0xF6C5, 0x9DCC, 0xF6C6, 0x9DB3, 0xF6C7, 0x9DCD, 0xF6C8, 0x9DB2, 0xF6C9, 0x9E7A, 0xF6CA, 0x9E9C, 0xF6CB, 0x9EEB, 0xF6CC, 0x9EEE, 0xF6CD, 0x9EED, 0xF6CE, 0x9F1B, 0xF6CF, 0x9F18, 0xF6D0, 0x9F1A, 0xF6D1, 0x9F31, 0xF6D2, 0x9F4E, 0xF6D3, 0x9F65, 0xF6D4, 0x9F64, 0xF6D5, 0x9F92, 0xF6D6, 0x4EB9, 0xF6D7, 0x56C6, 0xF6D8, 0x56C5, 0xF6D9, 0x56CB, 0xF6DA, 0x5971, 0xF6DB, 0x5B4B, 0xF6DC, 0x5B4C, 0xF6DD, 0x5DD5, 0xF6DE, 0x5DD1, 0xF6DF, 0x5EF2, 0xF6E0, 0x6521, 0xF6E1, 0x6520, 0xF6E2, 0x6526, 0xF6E3, 0x6522, 0xF6E4, 0x6B0B, 0xF6E5, 0x6B08, 0xF6E6, 0x6B09, 0xF6E7, 0x6C0D, 0xF6E8, 0x7055, 0xF6E9, 0x7056, 0xF6EA, 0x7057, 0xF6EB, 0x7052, 0xF6EC, 0x721E, 0xF6ED, 0x721F, 0xF6EE, 0x72A9, 0xF6EF, 0x737F, 0xF6F0, 0x74D8, 0xF6F1, 0x74D5, 0xF6F2, 0x74D9, 0xF6F3, 0x74D7, 0xF6F4, 0x766D, 0xF6F5, 0x76AD, 0xF6F6, 0x7935, 0xF6F7, 0x79B4, 0xF6F8, 0x7A70, 0xF6F9, 0x7A71, 0xF6FA, 0x7C57, 0xF6FB, 0x7C5C, 0xF6FC, 0x7C59, 0xF6FD, 0x7C5B, 0xF6FE, 0x7C5A, 0xF740, 0x7CF4, 0xF741, 0x7CF1, 0xF742, 0x7E91, 0xF743, 0x7F4F, 0xF744, 0x7F87, 0xF745, 0x81DE, 0xF746, 0x826B, 0xF747, 0x8634, 0xF748, 0x8635, 0xF749, 0x8633, 0xF74A, 0x862C, 0xF74B, 0x8632, 0xF74C, 0x8636, 0xF74D, 0x882C, 0xF74E, 0x8828, 0xF74F, 0x8826, 0xF750, 0x882A, 0xF751, 0x8825, 0xF752, 0x8971, 0xF753, 0x89BF, 0xF754, 0x89BE, 0xF755, 0x89FB, 0xF756, 0x8B7E, 0xF757, 0x8B84, 0xF758, 0x8B82, 0xF759, 0x8B86, 0xF75A, 0x8B85, 0xF75B, 0x8B7F, 0xF75C, 0x8D15, 0xF75D, 0x8E95, 0xF75E, 0x8E94, 0xF75F, 0x8E9A, 0xF760, 0x8E92, 0xF761, 0x8E90, 0xF762, 0x8E96, 0xF763, 0x8E97, 0xF764, 0x8F60, 0xF765, 0x8F62, 0xF766, 0x9147, 0xF767, 0x944C, 0xF768, 0x9450, 0xF769, 0x944A, 0xF76A, 0x944B, 0xF76B, 0x944F, 0xF76C, 0x9447, 0xF76D, 0x9445, 0xF76E, 0x9448, 0xF76F, 0x9449, 0xF770, 0x9446, 0xF771, 0x973F, 0xF772, 0x97E3, 0xF773, 0x986A, 0xF774, 0x9869, 0xF775, 0x98CB, 0xF776, 0x9954, 0xF777, 0x995B, 0xF778, 0x9A4E, 0xF779, 0x9A53, 0xF77A, 0x9A54, 0xF77B, 0x9A4C, 0xF77C, 0x9A4F, 0xF77D, 0x9A48, 0xF77E, 0x9A4A, 0xF7A1, 0x9A49, 0xF7A2, 0x9A52, 0xF7A3, 0x9A50, 0xF7A4, 0x9AD0, 0xF7A5, 0x9B19, 0xF7A6, 0x9B2B, 0xF7A7, 0x9B3B, 0xF7A8, 0x9B56, 0xF7A9, 0x9B55, 0xF7AA, 0x9C46, 0xF7AB, 0x9C48, 0xF7AC, 0x9C3F, 0xF7AD, 0x9C44, 0xF7AE, 0x9C39, 0xF7AF, 0x9C33, 0xF7B0, 0x9C41, 0xF7B1, 0x9C3C, 0xF7B2, 0x9C37, 0xF7B3, 0x9C34, 0xF7B4, 0x9C32, 0xF7B5, 0x9C3D, 0xF7B6, 0x9C36, 0xF7B7, 0x9DDB, 0xF7B8, 0x9DD2, 0xF7B9, 0x9DDE, 0xF7BA, 0x9DDA, 0xF7BB, 0x9DCB, 0xF7BC, 0x9DD0, 0xF7BD, 0x9DDC, 0xF7BE, 0x9DD1, 0xF7BF, 0x9DDF, 0xF7C0, 0x9DE9, 0xF7C1, 0x9DD9, 0xF7C2, 0x9DD8, 0xF7C3, 0x9DD6, 0xF7C4, 0x9DF5, 0xF7C5, 0x9DD5, 0xF7C6, 0x9DDD, 0xF7C7, 0x9EB6, 0xF7C8, 0x9EF0, 0xF7C9, 0x9F35, 0xF7CA, 0x9F33, 0xF7CB, 0x9F32, 0xF7CC, 0x9F42, 0xF7CD, 0x9F6B, 0xF7CE, 0x9F95, 0xF7CF, 0x9FA2, 0xF7D0, 0x513D, 0xF7D1, 0x5299, 0xF7D2, 0x58E8, 0xF7D3, 0x58E7, 0xF7D4, 0x5972, 0xF7D5, 0x5B4D, 0xF7D6, 0x5DD8, 0xF7D7, 0x882F, 0xF7D8, 0x5F4F, 0xF7D9, 0x6201, 0xF7DA, 0x6203, 0xF7DB, 0x6204, 0xF7DC, 0x6529, 0xF7DD, 0x6525, 0xF7DE, 0x6596, 0xF7DF, 0x66EB, 0xF7E0, 0x6B11, 0xF7E1, 0x6B12, 0xF7E2, 0x6B0F, 0xF7E3, 0x6BCA, 0xF7E4, 0x705B, 0xF7E5, 0x705A, 0xF7E6, 0x7222, 0xF7E7, 0x7382, 0xF7E8, 0x7381, 0xF7E9, 0x7383, 0xF7EA, 0x7670, 0xF7EB, 0x77D4, 0xF7EC, 0x7C67, 0xF7ED, 0x7C66, 0xF7EE, 0x7E95, 0xF7EF, 0x826C, 0xF7F0, 0x863A, 0xF7F1, 0x8640, 0xF7F2, 0x8639, 0xF7F3, 0x863C, 0xF7F4, 0x8631, 0xF7F5, 0x863B, 0xF7F6, 0x863E, 0xF7F7, 0x8830, 0xF7F8, 0x8832, 0xF7F9, 0x882E, 0xF7FA, 0x8833, 0xF7FB, 0x8976, 0xF7FC, 0x8974, 0xF7FD, 0x8973, 0xF7FE, 0x89FE, 0xF840, 0x8B8C, 0xF841, 0x8B8E, 0xF842, 0x8B8B, 0xF843, 0x8B88, 0xF844, 0x8C45, 0xF845, 0x8D19, 0xF846, 0x8E98, 0xF847, 0x8F64, 0xF848, 0x8F63, 0xF849, 0x91BC, 0xF84A, 0x9462, 0xF84B, 0x9455, 0xF84C, 0x945D, 0xF84D, 0x9457, 0xF84E, 0x945E, 0xF84F, 0x97C4, 0xF850, 0x97C5, 0xF851, 0x9800, 0xF852, 0x9A56, 0xF853, 0x9A59, 0xF854, 0x9B1E, 0xF855, 0x9B1F, 0xF856, 0x9B20, 0xF857, 0x9C52, 0xF858, 0x9C58, 0xF859, 0x9C50, 0xF85A, 0x9C4A, 0xF85B, 0x9C4D, 0xF85C, 0x9C4B, 0xF85D, 0x9C55, 0xF85E, 0x9C59, 0xF85F, 0x9C4C, 0xF860, 0x9C4E, 0xF861, 0x9DFB, 0xF862, 0x9DF7, 0xF863, 0x9DEF, 0xF864, 0x9DE3, 0xF865, 0x9DEB, 0xF866, 0x9DF8, 0xF867, 0x9DE4, 0xF868, 0x9DF6, 0xF869, 0x9DE1, 0xF86A, 0x9DEE, 0xF86B, 0x9DE6, 0xF86C, 0x9DF2, 0xF86D, 0x9DF0, 0xF86E, 0x9DE2, 0xF86F, 0x9DEC, 0xF870, 0x9DF4, 0xF871, 0x9DF3, 0xF872, 0x9DE8, 0xF873, 0x9DED, 0xF874, 0x9EC2, 0xF875, 0x9ED0, 0xF876, 0x9EF2, 0xF877, 0x9EF3, 0xF878, 0x9F06, 0xF879, 0x9F1C, 0xF87A, 0x9F38, 0xF87B, 0x9F37, 0xF87C, 0x9F36, 0xF87D, 0x9F43, 0xF87E, 0x9F4F, 0xF8A1, 0x9F71, 0xF8A2, 0x9F70, 0xF8A3, 0x9F6E, 0xF8A4, 0x9F6F, 0xF8A5, 0x56D3, 0xF8A6, 0x56CD, 0xF8A7, 0x5B4E, 0xF8A8, 0x5C6D, 0xF8A9, 0x652D, 0xF8AA, 0x66ED, 0xF8AB, 0x66EE, 0xF8AC, 0x6B13, 0xF8AD, 0x705F, 0xF8AE, 0x7061, 0xF8AF, 0x705D, 0xF8B0, 0x7060, 0xF8B1, 0x7223, 0xF8B2, 0x74DB, 0xF8B3, 0x74E5, 0xF8B4, 0x77D5, 0xF8B5, 0x7938, 0xF8B6, 0x79B7, 0xF8B7, 0x79B6, 0xF8B8, 0x7C6A, 0xF8B9, 0x7E97, 0xF8BA, 0x7F89, 0xF8BB, 0x826D, 0xF8BC, 0x8643, 0xF8BD, 0x8838, 0xF8BE, 0x8837, 0xF8BF, 0x8835, 0xF8C0, 0x884B, 0xF8C1, 0x8B94, 0xF8C2, 0x8B95, 0xF8C3, 0x8E9E, 0xF8C4, 0x8E9F, 0xF8C5, 0x8EA0, 0xF8C6, 0x8E9D, 0xF8C7, 0x91BE, 0xF8C8, 0x91BD, 0xF8C9, 0x91C2, 0xF8CA, 0x946B, 0xF8CB, 0x9468, 0xF8CC, 0x9469, 0xF8CD, 0x96E5, 0xF8CE, 0x9746, 0xF8CF, 0x9743, 0xF8D0, 0x9747, 0xF8D1, 0x97C7, 0xF8D2, 0x97E5, 0xF8D3, 0x9A5E, 0xF8D4, 0x9AD5, 0xF8D5, 0x9B59, 0xF8D6, 0x9C63, 0xF8D7, 0x9C67, 0xF8D8, 0x9C66, 0xF8D9, 0x9C62, 0xF8DA, 0x9C5E, 0xF8DB, 0x9C60, 0xF8DC, 0x9E02, 0xF8DD, 0x9DFE, 0xF8DE, 0x9E07, 0xF8DF, 0x9E03, 0xF8E0, 0x9E06, 0xF8E1, 0x9E05, 0xF8E2, 0x9E00, 0xF8E3, 0x9E01, 0xF8E4, 0x9E09, 0xF8E5, 0x9DFF, 0xF8E6, 0x9DFD, 0xF8E7, 0x9E04, 0xF8E8, 0x9EA0, 0xF8E9, 0x9F1E, 0xF8EA, 0x9F46, 0xF8EB, 0x9F74, 0xF8EC, 0x9F75, 0xF8ED, 0x9F76, 0xF8EE, 0x56D4, 0xF8EF, 0x652E, 0xF8F0, 0x65B8, 0xF8F1, 0x6B18, 0xF8F2, 0x6B19, 0xF8F3, 0x6B17, 0xF8F4, 0x6B1A, 0xF8F5, 0x7062, 0xF8F6, 0x7226, 0xF8F7, 0x72AA, 0xF8F8, 0x77D8, 0xF8F9, 0x77D9, 0xF8FA, 0x7939, 0xF8FB, 0x7C69, 0xF8FC, 0x7C6B, 0xF8FD, 0x7CF6, 0xF8FE, 0x7E9A, 0xF940, 0x7E98, 0xF941, 0x7E9B, 0xF942, 0x7E99, 0xF943, 0x81E0, 0xF944, 0x81E1, 0xF945, 0x8646, 0xF946, 0x8647, 0xF947, 0x8648, 0xF948, 0x8979, 0xF949, 0x897A, 0xF94A, 0x897C, 0xF94B, 0x897B, 0xF94C, 0x89FF, 0xF94D, 0x8B98, 0xF94E, 0x8B99, 0xF94F, 0x8EA5, 0xF950, 0x8EA4, 0xF951, 0x8EA3, 0xF952, 0x946E, 0xF953, 0x946D, 0xF954, 0x946F, 0xF955, 0x9471, 0xF956, 0x9473, 0xF957, 0x9749, 0xF958, 0x9872, 0xF959, 0x995F, 0xF95A, 0x9C68, 0xF95B, 0x9C6E, 0xF95C, 0x9C6D, 0xF95D, 0x9E0B, 0xF95E, 0x9E0D, 0xF95F, 0x9E10, 0xF960, 0x9E0F, 0xF961, 0x9E12, 0xF962, 0x9E11, 0xF963, 0x9EA1, 0xF964, 0x9EF5, 0xF965, 0x9F09, 0xF966, 0x9F47, 0xF967, 0x9F78, 0xF968, 0x9F7B, 0xF969, 0x9F7A, 0xF96A, 0x9F79, 0xF96B, 0x571E, 0xF96C, 0x7066, 0xF96D, 0x7C6F, 0xF96E, 0x883C, 0xF96F, 0x8DB2, 0xF970, 0x8EA6, 0xF971, 0x91C3, 0xF972, 0x9474, 0xF973, 0x9478, 0xF974, 0x9476, 0xF975, 0x9475, 0xF976, 0x9A60, 0xF977, 0x9C74, 0xF978, 0x9C73, 0xF979, 0x9C71, 0xF97A, 0x9C75, 0xF97B, 0x9E14, 0xF97C, 0x9E13, 0xF97D, 0x9EF6, 0xF97E, 0x9F0A, 0xF9A1, 0x9FA4, 0xF9A2, 0x7068, 0xF9A3, 0x7065, 0xF9A4, 0x7CF7, 0xF9A5, 0x866A, 0xF9A6, 0x883E, 0xF9A7, 0x883D, 0xF9A8, 0x883F, 0xF9A9, 0x8B9E, 0xF9AA, 0x8C9C, 0xF9AB, 0x8EA9, 0xF9AC, 0x8EC9, 0xF9AD, 0x974B, 0xF9AE, 0x9873, 0xF9AF, 0x9874, 0xF9B0, 0x98CC, 0xF9B1, 0x9961, 0xF9B2, 0x99AB, 0xF9B3, 0x9A64, 0xF9B4, 0x9A66, 0xF9B5, 0x9A67, 0xF9B6, 0x9B24, 0xF9B7, 0x9E15, 0xF9B8, 0x9E17, 0xF9B9, 0x9F48, 0xF9BA, 0x6207, 0xF9BB, 0x6B1E, 0xF9BC, 0x7227, 0xF9BD, 0x864C, 0xF9BE, 0x8EA8, 0xF9BF, 0x9482, 0xF9C0, 0x9480, 0xF9C1, 0x9481, 0xF9C2, 0x9A69, 0xF9C3, 0x9A68, 0xF9C4, 0x9B2E, 0xF9C5, 0x9E19, 0xF9C6, 0x7229, 0xF9C7, 0x864B, 0xF9C8, 0x8B9F, 0xF9C9, 0x9483, 0xF9CA, 0x9C79, 0xF9CB, 0x9EB7, 0xF9CC, 0x7675, 0xF9CD, 0x9A6B, 0xF9CE, 0x9C7A, 0xF9CF, 0x9E1D, 0xF9D0, 0x7069, 0xF9D1, 0x706A, 0xF9D2, 0x9EA4, 0xF9D3, 0x9F7E, 0xF9D4, 0x9F49, 0xF9D5, 0x9F98, 0xF9D6, 0x7881, 0xF9D7, 0x92B9, 0xF9D8, 0x88CF, 0xF9D9, 0x58BB, 0xF9DA, 0x6052, 0xF9DB, 0x7CA7, 0xF9DC, 0x5AFA, 0xF9DD, 0x2554, 0xF9DE, 0x2566, 0xF9DF, 0x2557, 0xF9E0, 0x2560, 0xF9E1, 0x256C, 0xF9E2, 0x2563, 0xF9E3, 0x255A, 0xF9E4, 0x2569, 0xF9E5, 0x255D, 0xF9E6, 0x2552, 0xF9E7, 0x2564, 0xF9E8, 0x2555, 0xF9E9, 0x255E, 0xF9EA, 0x256A, 0xF9EB, 0x2561, 0xF9EC, 0x2558, 0xF9ED, 0x2567, 0xF9EE, 0x255B, 0xF9EF, 0x2553, 0xF9F0, 0x2565, 0xF9F1, 0x2556, 0xF9F2, 0x255F, 0xF9F3, 0x256B, 0xF9F4, 0x2562, 0xF9F5, 0x2559, 0xF9F6, 0x2568, 0xF9F7, 0x255C, 0xF9F8, 0x2551, 0xF9F9, 0x2550, 0xF9FA, 0x256D, 0xF9FB, 0x256E, 0xF9FC, 0x2570, 0xF9FD, 0x256F, 0xF9FE, 0x2593, 0, 0 }; #endif #if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 }; #endif #if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; #endif #if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 }; #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* SBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { WCHAR c = 0; const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (oem < 0x100) c = p[oem - 0x80]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for static code page configuration */ /* DBCS fixed code page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ uc = (WCHAR)uni; p = CVTBL(uni2oem, FF_CODE_PAGE); hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i = 0, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ p = CVTBL(oem2uni, FF_CODE_PAGE); hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } return c; } #endif /*------------------------------------------------------------------------*/ /* OEM <==> Unicode conversions for dynamic code page configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ DWORD uni, /* UTF-16 encoded character to be converted */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0, uc; UINT i, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ if (uni < 0x10000) { /* Is it in BMP? */ uc = (WCHAR)uni; p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ p = cp_table[i]; if (p) { /* Is it valid code page ? */ for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ c = (c + 0x80) & 0xFF; } } else { /* DBCS */ switch (cp) { /* Get conversion table */ case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; } if (p) { /* Is it valid code page? */ li = 0; for (n = 16; n; n--) { /* Find OEM code */ i = li + (hi - li) / 2; if (uc == p[i * 2]) break; if (uc > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } } return c; } WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */ WORD cp /* Code page for the conversion */ ) { const WCHAR *p; WCHAR c = 0; UINT i, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ p = 0; if (cp < 900) { /* SBCS */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ p = cp_table[i]; if (p) { /* Is it a valid CP ? */ if (oem < 0x100) c = p[oem - 0x80]; } } else { /* DBCS */ switch (cp) { case 932 : p = oem2uni932; hi = sizeof oem2uni932 / 4 - 1; break; case 936 : p = oem2uni936; hi = sizeof oem2uni936 / 4 - 1; break; case 949 : p = oem2uni949; hi = sizeof oem2uni949 / 4 - 1; break; case 950 : p = oem2uni950; hi = sizeof oem2uni950 / 4 - 1; break; } if (p) { li = 0; for (n = 16; n; n--) { i = li + (hi - li) / 2; if (oem == p[i * 2]) break; if (oem > p[i * 2]) { li = i; } else { hi = i; } } if (n != 0) c = p[i * 2 + 1]; } } } return c; } #endif /*------------------------------------------------------------------------*/ /* Unicode up-case conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { const WORD *p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, /* Latin Extended-A */ 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, 0x0000 /* EOT */ }; static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ 0x1E00,0x0196, 0x1EA0,0x015A, /* Greek Extended */ 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ 0x2170,0x0210, 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ 0x24D0,0x051A, 0x2C30,0x042F, /* Latin Extended-C */ 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ 0x2D00,0x0826, /* Full-width */ 0xFF41,0x031A, 0x0000 /* EOT */ }; if (uni < 0x10000) { /* Is it in BMP? */ uc = (WORD)uni; p = uc < 0x1000 ? cvt1 : cvt2; for (;;) { bc = *p++; /* Get the block base */ if (bc == 0 || uc < bc) break; /* Not matched? */ nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ if (uc < bc + nc) { /* In the block? */ switch (cmd) { case 0: uc = p[uc - bc]; break; /* Table conversion */ case 1: uc -= (uc - bc) & 1; break; /* Case pairs */ case 2: uc -= 16; break; /* Shift -16 */ case 3: uc -= 32; break; /* Shift -32 */ case 4: uc -= 48; break; /* Shift -48 */ case 5: uc -= 26; break; /* Shift -26 */ case 6: uc += 8; break; /* Shift +8 */ case 7: uc -= 80; break; /* Shift -80 */ case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */ } break; } if (cmd == 0) p += nc; /* Skip table if needed */ } uni = uc; } return uni; } #endif /* #if FF_USE_LFN */ ================================================ FILE: fusee/program/source/fatfs/fusee_diskio.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "diskio_cpp.h" #include "../fusee_sd_card.hpp" #include "../fusee_emummc.hpp" bool diskio_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) { return R_SUCCEEDED(::ams::nxboot::ReadSdCard(dst, size, sector_index, sector_count)); } bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size) { return R_SUCCEEDED(::ams::nxboot::WriteSdCard(sector_index, sector_count, src, size)); } bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count) { return false; } bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size) { return false; } ================================================ FILE: fusee/program/source/fs/fusee_fs_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../fatfs/ff.h" #include "fusee_fs_api.hpp" namespace ams::fs { static_assert(sizeof(DirectoryEntry) == sizeof(FILINFO)); namespace { constexpr size_t MaxFiles = 8 + 64; constexpr size_t MaxDirectories = 2; constinit bool g_is_sd_mounted = false; alignas(0x10) constinit FATFS g_sd_fs = {}; alignas(0x10) constinit FIL g_files[MaxFiles] = {}; alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {}; constinit bool g_files_opened[MaxFiles] = {}; constinit bool g_dirs_opened[MaxFiles] = {}; constinit int g_open_modes[MaxFiles] = {}; Result TranslateFatFsError(FRESULT res) { switch (res) { case FR_OK: R_SUCCEED(); case FR_DISK_ERR: R_THROW(fs::ResultMmcAccessFailed()); case FR_INT_ERR: R_THROW(fs::ResultPreconditionViolation()); case FR_NOT_READY: R_THROW(fs::ResultMmcAccessFailed()); case FR_NO_FILE: R_THROW(fs::ResultPathNotFound()); case FR_NO_PATH: R_THROW(fs::ResultPathNotFound()); case FR_INVALID_NAME: R_THROW(fs::ResultInvalidPath()); case FR_DENIED: R_THROW(fs::ResultPermissionDenied()); case FR_EXIST: R_THROW(fs::ResultPathAlreadyExists()); case FR_INVALID_OBJECT: R_THROW(fs::ResultInvalidArgument()); case FR_WRITE_PROTECTED: R_THROW(fs::ResultWriteNotPermitted()); case FR_INVALID_DRIVE: R_THROW(fs::ResultInvalidMountName()); case FR_NOT_ENABLED: R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */ case FR_NO_FILESYSTEM: R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */ case FR_TIMEOUT: R_THROW(fs::ResultTargetLocked()); /* BAD/TODO */ case FR_LOCKED: R_THROW(fs::ResultTargetLocked()); case FR_NOT_ENOUGH_CORE: R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */ case FR_TOO_MANY_OPEN_FILES: R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */ case FR_INVALID_PARAMETER: R_THROW(fs::ResultInvalidArgument()); default: R_THROW(fs::ResultInternal()); } } int TranslateToFatFsMode(int mode) { int fmode = FA_OPEN_EXISTING; if ((mode & OpenMode_Read) != 0) { fmode |= FA_READ; } if ((mode & OpenMode_Write) != 0) { fmode |= FA_WRITE; } if ((mode & OpenMode_AllowAppend) != 0) { fmode |= FA_OPEN_APPEND; } return fmode; } FIL *GetInternalFile(FileHandle handle) { return static_cast<FIL *>(handle._handle); } DIR *GetInternalDirectory(DirectoryHandle handle) { return static_cast<DIR *>(handle._handle); } ALWAYS_INLINE size_t GetFileIndex(FIL *fp) { const size_t file_index = (fp - g_files); AMS_ASSERT(file_index < MaxFiles); return file_index; } ALWAYS_INLINE size_t GetDirectoryIndex(DIR *dp) { const size_t dir_index = (dp - g_dirs); AMS_ASSERT(dir_index < MaxDirectories); return dir_index; } } bool MountSdCard() { AMS_ASSERT(!g_is_sd_mounted); g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc:", 1) == FR_OK; return g_is_sd_mounted; } void UnmountSdCard() { AMS_ASSERT(g_is_sd_mounted); f_unmount("sdmc:"); g_is_sd_mounted = false; } Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path) { /* Get the file info. */ FILINFO info; R_TRY(TranslateFatFsError(f_stat(path, std::addressof(info)))); /* Handle the file. */ *out_entry_type = (info.fattrib & AM_DIR) ? DirectoryEntryType_Directory : DirectoryEntryType_File; *out_archive = (info.fattrib & AM_ARC); R_SUCCEED(); } Result CreateFile(const char *path, s64 size) { /* Create the file. */ FIL fp; R_TRY(TranslateFatFsError(f_open(std::addressof(fp), path, FA_CREATE_NEW | FA_READ | FA_WRITE))); /* Ensure that we close the file when we're done with it. */ ON_SCOPE_EXIT { f_close(std::addressof(fp)); }; /* Expand the file. */ R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1))); R_SUCCEED(); } Result CreateDirectory(const char *path) { R_RETURN(TranslateFatFsError(f_mkdir(path))); } Result OpenFile(FileHandle *out_file, const char *path, int mode) { /* Find a free file. */ for (size_t i = 0; i < MaxFiles; ++i) { if (!g_files_opened[i]) { /* Open the file. */ FIL *fp = std::addressof(g_files[i]); R_TRY(TranslateFatFsError(f_open(fp, path, TranslateToFatFsMode(mode)))); /* Set the output. */ out_file->_handle = fp; g_files_opened[i] = true; g_open_modes[i] = mode; R_SUCCEED(); } } R_THROW(fs::ResultOpenCountLimit()); } Result OpenDirectory(DirectoryHandle *out_dir, const char *path) { /* Find a free directory. */ for (size_t i = 0; i < MaxDirectories; ++i) { if (!g_dirs_opened[i]) { /* Open the file. */ DIR *dp = std::addressof(g_dirs[i]); R_TRY(TranslateFatFsError(f_opendir(dp, path))); /* Set the output. */ out_dir->_handle = dp; g_dirs_opened[i] = true; R_SUCCEED(); } } R_THROW(fs::ResultOpenCountLimit()); } Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries) { DIR * const dp = GetInternalDirectory(handle); s64 count = 0; while (count < max_entries) { R_TRY(TranslateFatFsError(f_readdir(dp, reinterpret_cast<FILINFO *>(out_entries + count)))); if (out_entries[count].file_name[0] == '\x00') { break; } ++count; } *out_count = count; R_SUCCEED(); } void CloseDirectory(DirectoryHandle handle) { const size_t index = GetDirectoryIndex(GetInternalDirectory(handle)); f_closedir(std::addressof(g_dirs[index])); g_dirs_opened[index] = false; } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { /* Option is unused. */ AMS_UNUSED(option); /* Seek to the offset we're reading at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Read the data. */ UINT br; R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br)))); /* Check that we read the correct amount. */ R_UNLESS(br == size, fs::ResultOutOfRange()); R_SUCCEED(); } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) { R_RETURN(ReadFile(handle, offset, buffer, size, fs::ReadOption::None)); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { /* Option is unused. */ AMS_UNUSED(option); /* Seek to the offset we're reading at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Read the data. */ UINT br; R_TRY(TranslateFatFsError(f_read(GetInternalFile(handle), buffer, size, std::addressof(br)))); /* Set the output size. */ *out = br; R_SUCCEED(); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) { R_RETURN(ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None)); } Result GetFileSize(s64 *out, FileHandle handle) { FIL *fp = GetInternalFile(handle); *out = f_size(fp); R_SUCCEED(); } Result FlushFile(FileHandle handle) { R_RETURN(TranslateFatFsError(f_sync(GetInternalFile(handle)))); } Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { /* Seek to the offset we're writing at. */ R_TRY(TranslateFatFsError(f_lseek(GetInternalFile(handle), offset))); /* Write the data. */ UINT bw; R_TRY(TranslateFatFsError(f_write(GetInternalFile(handle), buffer, size, std::addressof(bw)))); /* Check that we wrote the correct amount. */ R_UNLESS(bw == size, fs::ResultOutOfRange()); /* If we should, flush the file. */ if (option.HasFlushFlag()) { R_TRY(FlushFile(handle)); } R_SUCCEED(); } Result SetFileSize(FileHandle handle, s64 size) { FIL *fp = GetInternalFile(handle); /* Check if we have nothing to do. */ const size_t fsize = f_size(fp); R_SUCCEED_IF(static_cast<FSIZE_t>(size) == fsize); /* NOTE/TODO: This may not preserve file data. Do this in a way that does? */ /* Truncate the file. */ R_TRY(TranslateFatFsError(f_truncate(fp))); /* Expand the file. */ R_TRY(TranslateFatFsError(f_expand(fp, size, 1))); /* Ensure the file is synchronized. */ R_TRY(FlushFile(handle)); /* Check that our expansion succeeded. */ AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size)); R_SUCCEED(); } int GetFileOpenMode(FileHandle handle) { return g_open_modes[GetFileIndex(GetInternalFile(handle))]; } void CloseFile(FileHandle handle) { const size_t index = GetFileIndex(GetInternalFile(handle)); f_close(std::addressof(g_files[index])); g_open_modes[index] = 0; g_files_opened[index] = false; } } ================================================ FILE: fusee/program/source/fs/fusee_fs_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::fs { enum OpenMode { OpenMode_Read = (1 << 0), OpenMode_Write = (1 << 1), OpenMode_AllowAppend = (1 << 2), OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write), OpenMode_All = (OpenMode_ReadWrite | OpenMode_AllowAppend), }; struct ReadOption { u32 _value; static const ReadOption None; }; inline constexpr const ReadOption ReadOption::None = {0}; inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32)); struct WriteOption { u32 _value; constexpr inline bool HasFlushFlag() const { return _value & 1; } static const WriteOption None; static const WriteOption Flush; }; inline constexpr const WriteOption WriteOption::None = {0}; inline constexpr const WriteOption WriteOption::Flush = {1}; inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32)); enum DirectoryEntryType { DirectoryEntryType_Directory = 0, DirectoryEntryType_File = 1, }; struct DirectoryEntry { u64 file_size; u16 file_date; u16 file_time; u8 file_attr; char altname[13]; char file_name[0x100]; }; constexpr ALWAYS_INLINE DirectoryEntryType GetEntryType(const DirectoryEntry &entry) { return (entry.file_attr & 0x10) ? DirectoryEntryType_Directory : DirectoryEntryType_File; } struct FileHandle { void *_handle; }; struct DirectoryHandle { void *_handle; }; bool MountSdCard(); void UnmountSdCard(); Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path); Result CreateFile(const char *path, s64 size); Result CreateDirectory(const char *path); Result OpenFile(FileHandle *out_file, const char *path, int mode); Result OpenDirectory(DirectoryHandle *out_dir, const char *path); Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries); void CloseDirectory(DirectoryHandle handle); Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size); Result GetFileSize(s64 *out, FileHandle handle); Result FlushFile(FileHandle handle); Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option); Result SetFileSize(FileHandle handle, s64 size); int GetFileOpenMode(FileHandle handle); void CloseFile(FileHandle handle); } ================================================ FILE: fusee/program/source/fs/fusee_fs_file_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_fs_storage.hpp" namespace ams::fs { Result FileHandleStorage::UpdateSize() { R_SUCCEED_IF(m_size != InvalidSize); R_RETURN(GetFileSize(std::addressof(m_size), m_handle)); } Result FileHandleStorage::Read(s64 offset, void *buffer, size_t size) { /* Immediately succeed if there's nothing to read. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(ReadFile(m_handle, offset, buffer, size, fs::ReadOption())); } Result FileHandleStorage::Write(s64 offset, const void *buffer, size_t size) { /* Immediately succeed if there's nothing to write. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(WriteFile(m_handle, offset, buffer, size, fs::WriteOption())); } Result FileHandleStorage::Flush() { R_RETURN(FlushFile(m_handle)); } Result FileHandleStorage::GetSize(s64 *out_size) { R_TRY(this->UpdateSize()); *out_size = m_size; R_SUCCEED(); } Result FileHandleStorage::SetSize(s64 size) { m_size = InvalidSize; R_RETURN(SetFileSize(m_handle, size)); } } ================================================ FILE: fusee/program/source/fs/fusee_fs_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "fusee_fs_api.hpp" namespace ams::fs { class IStorage { public: virtual Result Read(s64 offset, void *buffer, size_t size) = 0; virtual Result Write(s64 offset, const void *buffer, size_t size) = 0; virtual Result Flush() = 0; virtual Result SetSize(s64 size) = 0; virtual Result GetSize(s64 *out) = 0; public: static inline Result CheckAccessRange(s64 offset, s64 size, s64 total_size) { R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); R_UNLESS(offset + size <= total_size, fs::ResultOutOfRange()); R_SUCCEED(); } static ALWAYS_INLINE Result CheckAccessRange(s64 offset, size_t size, s64 total_size) { R_RETURN(CheckAccessRange(offset, static_cast<s64>(size), total_size)); } static inline Result CheckOffsetAndSize(s64 offset, s64 size) { R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); R_SUCCEED(); } static ALWAYS_INLINE Result CheckOffsetAndSize(s64 offset, size_t size) { R_RETURN(CheckOffsetAndSize(offset, static_cast<s64>(size))); } static inline Result CheckOffsetAndSizeWithResult(s64 offset, s64 size, Result fail_result) { R_TRY_CATCH(CheckOffsetAndSize(offset, size)) { R_CONVERT_ALL(fail_result); } R_END_TRY_CATCH; R_SUCCEED(); } static ALWAYS_INLINE Result CheckOffsetAndSizeWithResult(s64 offset, size_t size, Result fail_result) { R_RETURN(CheckOffsetAndSizeWithResult(offset, static_cast<s64>(size), fail_result)); } }; class ReadOnlyStorageAdapter : public IStorage { private: IStorage &m_storage; public: ReadOnlyStorageAdapter(IStorage &s) : m_storage(s) { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(m_storage.Read(offset, buffer, size)); } virtual Result Flush() override { R_RETURN(m_storage.Flush()); } virtual Result GetSize(s64 *out) override { R_RETURN(m_storage.GetSize(out)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result SetSize(s64 size) override { R_THROW(fs::ResultUnsupportedOperation()); } }; class SubStorage : public IStorage { private: IStorage &m_storage; s64 m_offset; s64 m_size; public: SubStorage(IStorage &s, s64 o, s64 sz) : m_storage(s), m_offset(o), m_size(sz) { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and read. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(m_storage.Read(m_offset + offset, buffer, size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override{ /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and write. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(m_storage.Write(m_offset + offset, buffer, size)); } virtual Result Flush() override { R_RETURN(m_storage.Flush()); } virtual Result GetSize(s64 *out) override { *out = m_size; R_SUCCEED(); } virtual Result SetSize(s64 size) override { R_THROW(fs::ResultUnsupportedSetSizeForNotResizableSubStorage()); } }; class FileHandleStorage : public IStorage { private: static constexpr s64 InvalidSize = -1; private: FileHandle m_handle; s64 m_size; public: constexpr explicit FileHandleStorage(FileHandle handle) : m_handle(handle), m_size(InvalidSize) { /* ... */ } ~FileHandleStorage() { fs::CloseFile(m_handle); } protected: Result UpdateSize(); public: virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; virtual Result GetSize(s64 *out_size) override; virtual Result SetSize(s64 size) override; }; } ================================================ FILE: fusee/program/source/fusee_cpu.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_cpu.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t FLOW = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); constexpr inline const uintptr_t EVP = secmon::MemoryRegionPhysicalDeviceExceptionVectors.GetAddress(); constexpr inline const uintptr_t SYSTEM = secmon::MemoryRegionPhysicalDeviceSystem.GetAddress(); bool IsPartitionPowered(u32 mask) { return (reg::Read(PMC + APBDEV_PMC_PWRGATE_STATUS) & mask) == mask; } void PowerOnPartition(u32 status_mask, u32 toggle_mask) { /* Check if the partition is already powered on. */ if (IsPartitionPowered(status_mask)) { return; } /* Wait for PWRGATE_TOGGLE to be idle. */ auto timeout = 5000; while (true) { if (reg::HasValue(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, DISABLE))) { break; } util::WaitMicroSeconds(1); if ((--timeout) < 0) { return; } } /* Toggle on the desired partition. */ reg::SetField(toggle_mask, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, ENABLE)); reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, toggle_mask); /* Wait for the partition to be powered. */ timeout = 5000; while (true) { if (IsPartitionPowered(status_mask)) { break; } util::WaitMicroSeconds(1); if ((--timeout) < 0) { return; } } } } void SetupCpu(uintptr_t entrypoint) { /* Set ACTIVE_CLUSTER to FAST. */ reg::ReadWrite(FLOW + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, FAST)); /* Enable VDD_CPU. */ pmic::EnableVddCpu(fuse::GetRegulator()); /* Enable clock to the cpu. */ { /* Initialize PllX */ if (!reg::HasValue(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, CLK_RST_REG_BITS_ENUM(PLLX_BASE_PLLX_ENABLE, ENABLE))) { /* Disable IDDQ. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLX_MISC3, CLK_RST_REG_BITS_VALUE(PLLX_MISC3_PLLX_IDDQ, 0)); /* Wait two microseconds. */ util::WaitMicroSeconds(2); /* Configure PLLX dividers. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, 0x80404E02); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, 0x00404E02); /* Set PLLX_LOCK_ENABLE. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLX_MISC, CLK_RST_REG_BITS_ENUM(PLLX_MISC_PLLX_LOCK_ENABLE, ENABLE)); /* Enable PLLX. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, 0x40404E02); } /* Wait for PLLX to be locked. */ while (!reg::HasValue(CLKRST + CLK_RST_CONTROLLER_PLLX_BASE, CLK_RST_REG_BITS_ENUM(PLLX_BASE_PLLX_LOCK, LOCK))) { /* ... */ } /* Select MSELECT clock source as PLLP_OUT0 with divider of 4. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT, CLK_RST_REG_BITS_ENUM (CLK_SOURCE_MSELECT_MSELECT_CLK_SRC, PLLP_OUT0), CLK_RST_REG_BITS_VALUE(CLK_SOURCE_MSELECT_MSELECT_CLK_DIVISOR, 6)); /* Enable clock to MSELECT. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_V_CLK_ENB_MSELECT, ENABLE)); /* Configure CCLK_BURST_POLICY. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IDLE_SOURCE, PLLX_OUT0_LJ), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_RUN_SOURCE, PLLX_OUT0_LJ), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_IRQ_SOURCE, PLLX_OUT0_LJ), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CWAKEUP_FIQ_SOURCE, PLLX_OUT0_LJ), CLK_RST_REG_BITS_ENUM(CCLK_BURST_POLICY_CPU_STATE, RUN)); /* Configure SUPER_CCLK_DIVIDER. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_CCLK_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB, ENABLE), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_FIQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_COP_IRQ, NO_IMPACT), CLK_RST_REG_BITS_ENUM (SUPER_CCLK_DIVIDER_SUPER_CDIV_DIS_FROM_CPU_IRQ, NO_IMPACT), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVIDEND, 0), CLK_RST_REG_BITS_VALUE(SUPER_CCLK_DIVIDER_SUPER_CDIV_DIVISOR, 0)); /* Enable CPUG. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_SET_SET_CLK_ENB_CPUG, ENABLE)); } /* Enable coresight. */ clkrst::EnableCsiteClock(); /* Restore PROD setting to CPU_SOFTRST_CTRL2 by clearing CAR2PMC_CPU_ACK_WIDTH. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2, CLK_RST_REG_BITS_VALUE(CPU_SOFTRST_CTRL2_CAR2PMC_CPU_ACK_WIDTH, 0)); /* Power on cpu rails. */ { PowerOnPartition(reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CRAIL, ON)), reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_PARTID, CRAIL))); PowerOnPartition(reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_STATUS_C0NC, ON)), reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_PARTID, C0NC))); PowerOnPartition(reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_STATUS_CE0, ON)), reg::EncodeValue(PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_PARTID, CE0))); } /* Do RAM Repair. */ { reg::Write(FLOW + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_REQ, ENABLE)); while (!reg::HasValue(FLOW + FLOW_CTLR_RAM_REPAIR, FLOW_REG_BITS_ENUM(RAM_REPAIR_STS, DONE))) { /* ... */ } } /* Configure CPU reset vector. */ reg::Write(EVP + EVP_CPU_RESET_VECTOR, 0); reg::Write(SYSTEM + SB_AA64_RESET_LOW, entrypoint | 0x1); reg::Write(SYSTEM + SB_AA64_RESET_HIGH, 0); reg::Write(SYSTEM + SB_CSR, SB_REG_BITS_ENUM(CSR_NS_RST_VEC_WR_DIS, DISABLE)); reg::Read(SYSTEM + SB_CSR); } void StartCpu() { /* NOTE: Here nintendo sets CPU_STRICT_TZ_APERTURE_CHECK, which we will not set. */ /* Clear MSELECT reset. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_REG_BITS_ENUM(RST_DEVICES_V_SWR_MSELECT_RST, DISABLE)); /* Take non-cpu out of reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, ENABLE)); /* Clear cpu reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CPURESET0, ENABLE), CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_CORERESET0, ENABLE), CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_PRESETDBG, ENABLE), CLK_RST_REG_BITS_ENUM(RST_CPUG_CMPLX_CLR_CLR_L2RESET, ENABLE)); } } ================================================ FILE: fusee/program/source/fusee_cpu.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { void SetupCpu(uintptr_t entrypoint); void StartCpu(); } ================================================ FILE: fusee/program/source/fusee_crt0.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_exception_handler.hpp" extern "C" void __libc_init_array(); namespace ams::nxboot::crt0 { namespace { ALWAYS_INLINE void SetExceptionVector(u32 which, uintptr_t impl) { reg::Write(secmon::MemoryRegionPhysicalDeviceExceptionVectors.GetAddress() + 0x200 + sizeof(u32) * which, static_cast<u32>(impl)); } } void Initialize() { /* TODO: Collect timing information? */ /* Setup exception vectors. */ { SetExceptionVector(0, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler0)); SetExceptionVector(1, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler1)); SetExceptionVector(2, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler2)); SetExceptionVector(3, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler3)); SetExceptionVector(4, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler4)); SetExceptionVector(5, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler5)); SetExceptionVector(6, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler6)); SetExceptionVector(7, reinterpret_cast<uintptr_t>(::ams::nxboot::ExceptionHandler7)); } /* Call init array. */ __libc_init_array(); } } ================================================ FILE: fusee/program/source/fusee_display.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_registers_di.hpp" #include "fusee_display.hpp" #include "fusee_print.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { namespace { #include "fusee_display_config.inc" } namespace { /* Helpful defines. */ constexpr int DsiWaitForCommandMilliSecondsMax = 250; constexpr int DsiWaitForCommandCompletionMilliSeconds = 5; constexpr int DsiWaitForHostControlMilliSecondsMax = 150; constexpr inline int I2cAddressMax77620Pmic = 0x3C; constexpr size_t GPIO_PORT3_CNF_0 = 0x200; constexpr size_t GPIO_PORT3_OE_0 = 0x210; constexpr size_t GPIO_PORT3_OUT_0 = 0x220; constexpr size_t GPIO_PORT6_CNF_1 = 0x504; constexpr size_t GPIO_PORT6_OE_1 = 0x514; constexpr size_t GPIO_PORT6_OUT_1 = 0x524; /* Globals. */ constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc .GetAddress(); constexpr inline const uintptr_t g_disp1_regs = secmon::MemoryRegionPhysicalDeviceDisp1 .GetAddress(); constexpr inline const uintptr_t g_dsi_regs = secmon::MemoryRegionPhysicalDeviceDsi .GetAddress(); constexpr inline const uintptr_t g_clk_rst_regs = secmon::MemoryRegionPhysicalDeviceClkRst .GetAddress(); constexpr inline const uintptr_t g_gpio_regs = secmon::MemoryRegionPhysicalDeviceGpio .GetAddress(); constexpr inline const uintptr_t g_apb_misc_regs = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t g_mipi_cal_regs = secmon::MemoryRegionPhysicalDeviceMipiCal.GetAddress(); constinit u32 *g_frame_buffer = nullptr; constinit u32 g_lcd_vendor = 0; constinit bool g_display_initialized = false; inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) { for (size_t i = 0; i < num_writes; i++) { reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value); } } inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) { switch (fuse::GetSocType()) { case fuse::SocType_Erista: DoRegisterWrites(base_address, reg_writes_erista, num_writes_erista); break; case fuse::SocType_Mariko: DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } inline void DoSleepOrRegisterWrites(uintptr_t base_address, const SleepOrRegisterWrite *reg_writes, size_t num_writes) { for (size_t i = 0; i < num_writes; i++) { switch (reg_writes[i].kind) { case SleepOrRegisterWriteKind_Write: reg::Write(base_address + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value); break; case SleepOrRegisterWriteKind_Sleep: util::WaitMicroSeconds(reg_writes[i].offset * UINT64_C(1000)); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } } void WaitDsiTrigger() { const u32 timeout = util::GetMicroSeconds() + (DsiWaitForCommandMilliSecondsMax * 1000u); while (true) { if (util::GetMicroSeconds() >= timeout) { break; } if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) { break; } } util::WaitMicroSeconds(DsiWaitForCommandCompletionMilliSeconds * 1000u); } void WaitDsiHostControl() { const u32 timeout = util::GetMicroSeconds() + (DsiWaitForHostControlMilliSecondsMax * 1000u); while (true) { if (util::GetMicroSeconds() >= timeout) { break; } if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) { break; } } } void EnableBacklightForVendor2050ForAula(int brightness) { /* Enable FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 2); /* Configure DSI_LINE_TYPE as FOUR */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 9); /* Set and wait for FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ } /* Configure display brightness. */ const u32 brightness_val = ((0x7FF * brightness) / 100); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, (brightness_val & 0x700) | ((brightness_val & 0xFF) << 16) | 0x51); /* Set and wait for FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); while ((reg::Read(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS) & 2) != 0) { /* ... */ } /* Set client sync point block reset. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 1); util::WaitMicroSeconds(300'000ul); /* Clear client sync point block resest. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_INCR_SYNCPT_CNTRL, 0); util::WaitMicroSeconds(300'000ul); /* Clear DSI_LINE_TYPE config. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0); /* Disable FRAME_END_INT */ reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_ENABLE, 0); reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_INT_STATUS, 2); } void EnableBacklightForGeneric(int brightness) { AMS_UNUSED(brightness); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } #define DO_REGISTER_WRITES(base_address, writes) DoRegisterWrites(base_address, writes, util::size(writes)) #define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, util::size(writes##Erista), writes##Mariko, util::size(writes##Mariko)) #define DO_SLEEP_OR_REGISTER_WRITES(base_address, writes) DoSleepOrRegisterWrites(base_address, writes, util::size(writes)) void InitializeFrameBuffer() { if (g_frame_buffer == nullptr) { g_frame_buffer = reinterpret_cast<u32 *>(0xC0400000); } hw::FlushDataCache(g_frame_buffer, FrameBufferSize); } [[maybe_unused]] void FinalizeFrameBuffer() { /* We don't actually support finalizing the framebuffer, so do nothing here. */ } constexpr const char *GetErrorDescription(u32 error_desc) { switch (error_desc) { case 0x100: return "Instruction Abort"; case 0x101: return "Data Abort"; case 0x102: return "PC Misalignment"; case 0x103: return "SP Misalignment"; case 0x104: return "Trap"; case 0x106: return "SError"; case 0x301: return "Bad SVC"; case 0xF00: return "Kernel Panic"; case 0xFFD: return "Stack overflow"; case 0xFFE: return "std::abort() called"; default: return "Unknown"; } } void PrintSuggestedErrorFix(const ams::impl::FatalErrorContext *f_ctx) { /* Try to recognize certain errors automatically, and suggest fixes for them. */ const char *suggestion = nullptr; constexpr u64 ProgramIdAmsMitm = UINT64_C(0x010041544D530000); constexpr u64 ProgramIdBoot = UINT64_C(0x0100000000000005); if (f_ctx->error_desc == 0xFFE) { if (f_ctx->program_id == ProgramIdAmsMitm) { /* When a user has archive bits set improperly, attempting to create an automatic backup will fail */ /* to create the file path with error 0x202 */ if (f_ctx->gprs[0] == fs::ResultPathNotFound().GetValue()) { /* When the archive bit error is occurring, it manifests as failure to create automatic backup. */ /* Thus, we can search the stack for the automatic backups path. */ const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */; const int prefix_len = std::strlen(automatic_backups_prefix); for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) { if (std::memcmp(&f_ctx->stack_dump[i], automatic_backups_prefix, prefix_len) == 0) { suggestion = "The atmosphere directory may improperly have archive bits set.\n" "Please try running an archive bit fixer tool (for example, the one in Hekate).\n"; break; } } } else if (f_ctx->gprs[0] == fs::ResultExFatUnavailable().GetValue()) { /* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */ /* be returned on attempt to access the SD card. */ suggestion = "Your console has non-exFAT firmware installed, but your SD card\n" "is formatted as exFAT. Format your SD card as FAT32, or manually\n" "flash exFAT firmware to package2.\n"; } } else if (f_ctx->program_id == ProgramIdBoot) { /* 9.x -> 10.x updated the API for SvcQueryIoMapping. */ /* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */ /* (older kernel in package2, for some reason). */ for (size_t i = 0; i < 8; ++i) { if (f_ctx->gprs[i] == svc::ResultNotFound().GetValue()) { suggestion = "A partial update may have been improperly performed.\n" "To fix, try manually flashing latest package2 to MMC.\n" "\n" "For help doing this, seek support in the ReSwitched or\n" "Nintendo Homebrew discord servers.\n"; break; } } } } else if (f_ctx->error_desc == 0xF00) { /* Kernel Panic */ suggestion = "Please contact SciresM#0524 on Discord, or create an issue on the Atmosphere\n" "GitHub issue tracker. Thank you very much for helping to test mesosphere.\n"; } /* If we found a suggestion, print it. */ if (suggestion != nullptr) { Print("%s", suggestion); } } } bool IsDisplayInitialized() { return g_display_initialized; } void InitializeDisplay() { if (IsDisplayInitialized()) { return; } /* Setup the framebuffer. */ InitializeFrameBuffer(); /* Get the hardware type. */ const auto hw_type = fuse::GetHardwareType(); /* Turn on DSI/voltage rail. */ { if (fuse::GetSocType() == fuse::SocType_Mariko) { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x18, 0x3A); } i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, 0x23, 0xD0); } /* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */ reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_MIPI_CAL_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_CLR_CLR_DSI_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_MIPI_CAL, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_SET_SET_CLK_ENB_DSI, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_HOST1X_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_DISP1_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_HOST1X, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_SET_SET_CLK_ENB_DISP1, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_SET_SET_CLK_ENB_UART_FST_MIPI_CAL, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_DIVISOR, 10), CLK_RST_REG_BITS_ENUM (CLK_SOURCE_UART_FST_MIPI_CAL_UART_FST_MIPI_CAL_CLK_SRC, PLLP_OUT3)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_SET_SET_CLK_ENB_DSIA_LP, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_DIVISOR, 10), CLK_RST_REG_BITS_ENUM (CLK_SOURCE_DSIA_LP_DSIA_LP_CLK_SRC, PLLP_OUT0)); /* Set IO_DPD_REQ to DPD_OFF. */ reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD_REQ, PMC_REG_BITS_ENUM(IO_DPD_REQ_CODE, DPD_OFF)); reg::ReadWrite(PMC + APBDEV_PMC_IO_DPD2_REQ, PMC_REG_BITS_ENUM(IO_DPD2_REQ_CODE, DPD_OFF)); /* Configure LCD pinmux tristate + passthrough. */ reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); if (hw_type == fuse::HardwareType_Aula) { /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4); } else { /* Configure LCD power, VDD. */ reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2); } /* Configure display interface and display. */ reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0); if (fuse::GetSocType() == fuse::SocType_Mariko) { reg::Write(g_mipi_cal_regs + MIPI_CAL_MIPI_BIAS_PAD_CFG0, 0); reg::Write(g_apb_misc_regs + APB_MISC_GP_DSI_PAD_CONTROL, 0); } /* Execute configs. */ DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01); DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc01); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init01); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init02); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init03); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init04); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init05); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init06); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init07); util::WaitMicroSeconds(10'000ul); /* Enable backlight reset. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4); util::WaitMicroSeconds(60'000ul); if (hw_type == fuse::HardwareType_Aula) { reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x40103); } else { reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204); } reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); WaitDsiTrigger(); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); WaitDsiTrigger(); reg::Write(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC); WaitDsiHostControl(); util::WaitMicroSeconds(5'000ul); /* Parse LCD vendor. */ { u32 host_response[3]; for (size_t i = 0; i < util::size(host_response); i++) { host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA); } /* The last word from host response is: Bits 0-7: FAB Bits 8-15: REV Bits 16-23: Minor REV */ u32 lcd_vendor; if ((host_response[2] & 0xFF) == 0x10) { lcd_vendor = 0; } else { lcd_vendor = (host_response[2] >> 8) & 0xFF00; } g_lcd_vendor = (lcd_vendor & 0xFFFFFF00) | (host_response[2] & 0xFF); } /* LCD vendor specific configuration. */ switch (g_lcd_vendor) { case 0x10: /* Japan Display Inc screens. */ DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigJdiSpecificInit01); break; case 0xF20: /* Innolux first revision screens. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0xF30: /* AUO first revision screens. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0x2050: /* Unknown (hardware type 5) screen. */ reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(180'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xA015); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x205315); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x339); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x51); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(5'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; case 0x1020: /* Innolux second revision screen. */ case 0x1030: /* AUO second revision screen. */ case 0x1040: /* Unknown second revision screen. */ default: reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); util::WaitMicroSeconds(120'000ul); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); break; } util::WaitMicroSeconds(20'000ul); DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld02); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init08); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_SLEEP_OR_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09); reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4)); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10); util::WaitMicroSeconds(10'000ul); /* Configure MIPI CAL. */ DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal01); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03); DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04); if (fuse::GetSocType() == fuse::SocType_Mariko) { /* On Mariko the above configurations are executed twice, for some reason. */ DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal02); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init11); DO_SOC_DEPENDENT_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal03); DO_REGISTER_WRITES(g_mipi_cal_regs, DisplayConfigMipiCal04); } util::WaitMicroSeconds(10'000ul); /* Write DISP1, FrameBuffer config. */ DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigDc02); DO_SLEEP_OR_REGISTER_WRITES(g_disp1_regs, DisplayConfigFrameBuffer); if (g_lcd_vendor != 0x2050) { util::WaitMicroSeconds(35'000ul); } g_display_initialized = true; } void FinalizeDisplay() { if (!IsDisplayInitialized()) { return; } /* TODO: What other configuration is needed, if any? */ /* Configure LCD pinmux tristate + passthrough. */ reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_NFC_INT, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_PWM, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_BL_EN, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); reg::ClearBits(g_apb_misc_regs + PINMUX_AUX_LCD_RST, reg::EncodeMask(PINMUX_REG_BITS_MASK(AUX_TRISTATE))); if (fuse::GetHardwareType() == fuse::HardwareType_Aula) { /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x4); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x4); } else { /* Configure LCD power, VDD. */ reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); /* Configure LCD backlight. */ reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2); } /* Disable the LCD backlight. */ if (g_lcd_vendor == 0x2050) { /* TODO: We're not sure display is alive. How to manage this? */ /* This is probably incorrect backlight disable for hw-type 5. */ reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } else { reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); } /* Disable backlight RST/Voltage. */ reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4); if (g_lcd_vendor == 0x2050) { util::WaitMicroSeconds(30'000ul); } else { util::WaitMicroSeconds(10'000ul); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); util::WaitMicroSeconds(10'000ul); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); util::WaitMicroSeconds(10'000ul); } /* Cut clock to DSI. */ reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_MIPI_CAL_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_SET_SET_DSI_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_MIPI_CAL, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLR_CLR_CLK_ENB_DSI, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_HOST1X_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_DISP1_RST, ENABLE)); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_HOST1X, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLR_CLR_CLK_ENB_DISP1, ENABLE)); reg::Write(g_dsi_regs + sizeof(u32) * DSI_PAD_CONTROL_0, (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF))); reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0); g_display_initialized = false; } void ShowDisplay() { /* Enable backlight. */ constexpr auto DisplayBrightness = 100; if (g_lcd_vendor == 0x2050) { EnableBacklightForVendor2050ForAula(DisplayBrightness); } else { EnableBacklightForGeneric(DisplayBrightness); } } u16 GetDisplayLcdVendor() { return g_lcd_vendor; } void ShowFatalError(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) { /* If needed, initialize the display. */ if (!IsDisplayInitialized()) { InitializeDisplay(); } /* Initialize the console. */ InitializeConsole(g_frame_buffer); { Print("%s\n", "A fatal error occurred when running Atmosph\xe8re."); Print("Program ID: %016" PRIx64 "\n", f_ctx->program_id); Print("Error Desc: %s (0x%" PRIx32 ")\n", GetErrorDescription(f_ctx->error_desc), f_ctx->error_desc); Print("\n"); if (R_SUCCEEDED(save_result)) { Print("Report saved to /atmosphere/fatal_errors/report_%016" PRIx64 ".bin\n", f_ctx->report_identifier); } else { Print("Failed to save report to the SD card! (%08" PRIx32 ")\n", save_result.GetValue()); } PrintSuggestedErrorFix(f_ctx); Print("\nPress POWER to reboot.\n"); } /* Ensure the device will see consistent data. */ hw::FlushDataCache(g_frame_buffer, FrameBufferSize); /* Show the console. */ ShowDisplay(); } void ShowFatalError(const char *fmt, ...) { /* If needed, initialize the display. */ if (!IsDisplayInitialized()) { InitializeDisplay(); } /* Initialize the console. */ InitializeConsole(g_frame_buffer); { Print("%s\n", "A fatal error occurred when running Fus" "\xe9" "e."); { std::va_list vl; va_start(vl, fmt); VPrint(fmt, vl); va_end(vl); } Print("\n"); Print("\nPress POWER to reboot.\n"); } /* Ensure the device will see consistent data. */ hw::FlushDataCache(g_frame_buffer, FrameBufferSize); /* Show the console. */ ShowDisplay(); WaitForReboot(); } } ================================================ FILE: fusee/program/source/fusee_display.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { constexpr inline size_t FrameBufferHeight = 768; constexpr inline size_t FrameBufferWidth = 1280; constexpr inline size_t FrameBufferSize = FrameBufferHeight * FrameBufferWidth * sizeof(u32); bool IsDisplayInitialized(); void InitializeDisplay(); void FinalizeDisplay(); u16 GetDisplayLcdVendor(); void ShowDisplay(); } ================================================ FILE: fusee/program/source/fusee_display_config.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ struct RegisterWrite { u32 offset; u32 value; }; enum SleepOrRegisterWriteKind : u16 { SleepOrRegisterWriteKind_Write = 0, SleepOrRegisterWriteKind_Sleep = 1, }; struct SleepOrRegisterWrite { SleepOrRegisterWriteKind kind; u16 offset; u32 value; }; constexpr const RegisterWrite DisplayConfigPlld01Erista[] = { {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, }; constexpr const RegisterWrite DisplayConfigPlld01Mariko[] = { {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, }; constexpr const SleepOrRegisterWrite DisplayConfigDc01[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_REG_ACT_CONTROL, 0x54}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_DISP_DC_MCCIF_FIFOCTRL, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_POWER_CONTROL, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL}, {SleepOrRegisterWriteKind_Write, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 0x9}, // 9: SYNCPT {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0}, {SleepOrRegisterWriteKind_Write, 0x4E4, 0}, {SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} }; constexpr const RegisterWrite DisplayConfigDsi01Init01[] = { {sizeof(u32) * DSI_WR_DATA, 0x0}, {sizeof(u32) * DSI_INT_ENABLE, 0x0}, {sizeof(u32) * DSI_INT_STATUS, 0x0}, {sizeof(u32) * DSI_INT_MASK, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_0, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_1, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_2, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init02Erista[] = { {sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init02Mariko[] = { {sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init03[] = { {sizeof(u32) * DSI_DCS_CMDS, 0}, {sizeof(u32) * DSI_PKT_SEQ_0_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_1_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_2_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_3_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_4_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_5_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_0_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_1_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_2_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_3_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_4_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_5_HI, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init04Erista[] = { /* No register writes. */ }; constexpr const RegisterWrite DisplayConfigDsi01Init04Mariko[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0}, {sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init05[] = { {sizeof(u32) * DSI_PAD_CONTROL_CD, 0}, {sizeof(u32) * DSI_SOL_DELAY, 0x18}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}, {sizeof(u32) * DSI_PKT_LEN_0_1, 0}, {sizeof(u32) * DSI_PKT_LEN_2_3, 0}, {sizeof(u32) * DSI_PKT_LEN_4_5, 0}, {sizeof(u32) * DSI_PKT_LEN_6_7, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init06[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30109}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x765) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_PAD_CONTROL_0, DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0)}, // Enable {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init07[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30118}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF)}, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x40}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_TX_CRC, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} }; constexpr const RegisterWrite DisplayConfigDsiPhyTimingErista[] = { {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601}, }; constexpr const RegisterWrite DisplayConfigDsiPhyTimingMariko[] = { {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603}, }; constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1939}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAAAAAEB}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAAEBAAAA}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xAA}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1BD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2739}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2BD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFD8}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xFFFFFF}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xBD15}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x6D915}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x1105}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Sleep, 180, 0}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2905}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, }; constexpr const RegisterWrite DisplayConfigPlld02Erista[] = { {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, }; constexpr const RegisterWrite DisplayConfigPlld02Mariko[] = { {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, }; constexpr const RegisterWrite DisplayConfigDsi01Init08[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const SleepOrRegisterWrite DisplayConfigDsi01Init09[] = { {SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_1, 0x40A0E05}, {SleepOrRegisterWriteKind_Write, DSI_PHY_TIMING_2, 0x30172}, {SleepOrRegisterWriteKind_Write, DSI_BTA_TIMING, 0x190A14}, {SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xA40)}, {SleepOrRegisterWriteKind_Write, DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x5A2F) | DSI_TIMEOUT_TA(0x2000)}, {SleepOrRegisterWriteKind_Write, DSI_TO_TALLY, 0}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_0_LO, 0x40000208}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_2_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_4_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_1_LO, 0x40000308}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_LO, 0x3F3B2B08}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_3_HI, 0x2CC}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_LO, 0x3F3B2B08}, {SleepOrRegisterWriteKind_Write, DSI_PKT_SEQ_5_HI, 0x2CC}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_0_1, 0xCE0000}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_2_3, 0x87001A2}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_4_5, 0x190}, {SleepOrRegisterWriteKind_Write, DSI_PKT_LEN_6_7, 0x190}, {SleepOrRegisterWriteKind_Write, DSI_HOST_CONTROL, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Init10[] = { {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_CONTROL, 0}, {sizeof(u32) * DSI_SOL_DELAY, 6}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_FIFO_SEL | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_HS_CLK_CTRL | DSI_CONTROL_FORMAT(3) | DSI_CONTROL_LANES(3) | DSI_CONTROL_VIDEO_ENABLE}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} }; constexpr const RegisterWrite DisplayConfigDsi01Init11Erista[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3)}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0} }; constexpr const RegisterWrite DisplayConfigDsi01Init11Mariko[] = { {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_4, 0x77777}, {sizeof(u32) * DSI_PAD_CONTROL_5_MARIKO, 0x77777}, {sizeof(u32) * DSI_PAD_CONTROL_6_MARIKO, DSI_PAD_PREEMP_PD_CLK(0x1) | DSI_PAD_PREEMP_PU_CLK(0x1) | DSI_PAD_PREEMP_PD(0x01) | DSI_PAD_PREEMP_PU(0x1)}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal01[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, {MIPI_CAL_CIL_MIPI_CAL_STATUS, 0xF3F10000}, {MIPI_CAL_MIPI_BIAS_PAD_CFG0, 1}, {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal02Erista[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0x300}, }; constexpr const RegisterWrite DisplayConfigMipiCal02Mariko[] = { {MIPI_CAL_MIPI_BIAS_PAD_CFG2, 0x10010}, {MIPI_CAL_MIPI_BIAS_PAD_CFG1, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal03Erista[] = { {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200200}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x200002}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x200002}, {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal03Mariko[] = { {MIPI_CAL_DSIA_MIPI_CAL_CONFIG, 0x200006}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG, 0x200006}, {MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2, 0x260000}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0x260000}, {MIPI_CAL_CILA_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILB_MIPI_CAL_CONFIG, 0}, }; constexpr const RegisterWrite DisplayConfigMipiCal04[] = { {MIPI_CAL_CILC_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILD_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILE_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_CILF_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSIC_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSID_MIPI_CAL_CONFIG, 0}, {MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_DSID_MIPI_CAL_CONFIG_2, 0}, {MIPI_CAL_MIPI_CAL_CTRL, 0x2A000001}, }; constexpr const SleepOrRegisterWrite DisplayConfigDc02[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_DV_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, /* Setup default YUV colorspace conversion coefficients */ {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_YOF, 0xF0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KYRGB, 0x12A}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUR, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVR, 0x198}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUG, 0x39B}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVG, 0x32F}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KUB, 0x204}, {SleepOrRegisterWriteKind_Write, DC_WIN_CSC_KVB, 0}, /* End of color coefficients */ {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(1), 0x1000000}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_POLARITY(3), 0}, {SleepOrRegisterWriteKind_Write, 0x4E4, 0}, {SleepOrRegisterWriteKind_Write, DC_COM_CRC_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, 0x716, 0x10000FF}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, /* Set Display timings */ {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_TIMING_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_REF_TO_SYNC, (1 << 16)}, // h_ref_to_sync = 0, v_ref_to_sync = 1. {SleepOrRegisterWriteKind_Write, DC_DISP_SYNC_WIDTH, 0x10048}, {SleepOrRegisterWriteKind_Write, DC_DISP_BACK_PORCH, 0x90048}, {SleepOrRegisterWriteKind_Write, DC_DISP_ACTIVE, 0x50002D0}, {SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. /* End of Display timings */ {SleepOrRegisterWriteKind_Write, DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {SleepOrRegisterWriteKind_Write, DC_COM_PIN_OUTPUT_ENABLE(1), 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DATA_ENABLE_OPTIONS, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT_DF1P1C}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, READ_MUX | WRITE_MUX}, {SleepOrRegisterWriteKind_Write, DC_DISP_FRONT_PORCH, 0xA0088}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {SleepOrRegisterWriteKind_Write, DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_ACCESS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_CLOCK_CONTROL, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(4)}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_COLOR_CONTROL, BASE_COLOR_SIZE_888}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND_OPTION0, 0} }; constexpr u32 DisplayConfigFrameBufferAddress = 0xC0400000; constexpr const SleepOrRegisterWrite DisplayConfigFrameBuffer[] = { {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, //Enable window A. {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_COLOR_DEPTH, WIN_COLOR_DEPTH_B8G8R8A8}, //T_A8R8G8B8 //NX Default: T_A8B8G8R8, WIN_COLOR_DEPTH_R8G8B8A8 {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_POSITION, 0}, //(0,0) {SleepOrRegisterWriteKind_Write, DC_WIN_H_INITIAL_DDA, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_V_INITIAL_DDA, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_PRESCALED_SIZE, V_PRESCALED_SIZE(1280) | H_PRESCALED_SIZE(2880)}, //Pre-scaled size: 1280x2880 bytes. {SleepOrRegisterWriteKind_Write, DC_WIN_DDA_INC, V_DDA_INC(0x1000) | H_DDA_INC(0x1000)}, {SleepOrRegisterWriteKind_Write, DC_WIN_SIZE, V_SIZE(1280) | H_SIZE(720)}, //Window size: 1280 vertical lines x 720 horizontal pixels. {SleepOrRegisterWriteKind_Write, DC_WIN_LINE_STRIDE, 0x6000C00}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {SleepOrRegisterWriteKind_Write, DC_WIN_BUFFER_CONTROL, 0}, {SleepOrRegisterWriteKind_Write, DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. {SleepOrRegisterWriteKind_Write, DC_WINBUF_START_ADDR, DisplayConfigFrameBufferAddress}, //Framebuffer address. {SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_H_OFFSET, 0}, {SleepOrRegisterWriteKind_Write, DC_WINBUF_ADDR_V_OFFSET, 0}, {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, 0}, {SleepOrRegisterWriteKind_Write, DC_DISP_DISP_WIN_OPTIONS, DSI_ENABLE}, //DSI_ENABLE {SleepOrRegisterWriteKind_Write, DC_WIN_WIN_OPTIONS, WIN_ENABLE}, //Enable window AD. {SleepOrRegisterWriteKind_Write, DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_C_DISPLAY}, //DISPLAY_CTRL_MODE: continuous display. {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE}, //General update; window A update. {SleepOrRegisterWriteKind_Write, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. }; constexpr const RegisterWrite DisplayConfigDc01Fini01[] = { {sizeof(u32) * DC_DISP_FRONT_PORCH, 0xA0088}, {sizeof(u32) * DC_CMD_INT_MASK, 0}, {sizeof(u32) * DC_CMD_STATE_ACCESS, 0}, {sizeof(u32) * DC_CMD_INT_ENABLE, 0}, {sizeof(u32) * DC_CMD_CONT_SYNCPT_VSYNC, 0}, {sizeof(u32) * DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {sizeof(u32) * DC_CMD_GENERAL_INCR_SYNCPT, 0x301}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, }; constexpr const RegisterWrite DisplayConfigDsi01Fini01[] = { {sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0}, }; constexpr const RegisterWrite DisplayConfigDsi01Fini02[] = { {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30118}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_TIMEOUT_0, DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(0xFFFF) }, {sizeof(u32) * DSI_TIMEOUT_1, DSI_TIMEOUT_PR(0x1343) | DSI_TIMEOUT_TA(0x2000)}, {sizeof(u32) * DSI_TO_TALLY, 0}, {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}, {sizeof(u32) * DSI_CONTROL, DSI_CONTROL_LANES(3) | DSI_CONTROL_HOST_ENABLE}, {sizeof(u32) * DSI_POWER_CONTROL, DSI_POWER_CONTROL_ENABLE}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x40}, {sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_TX_CRC, 0}, {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} }; constexpr const SleepOrRegisterWrite DisplayConfigJdiSpecificFini01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2139}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x4F0F41B1}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xF179A433}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2D81}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, }; constexpr const SleepOrRegisterWrite DisplayConfigAuoRev1SpecificFini01[] = { {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D5}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x2C39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x191919D6}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x19191919}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB39}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x711148B1}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x71143209}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x114D31}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {SleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0xB9}, {SleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {SleepOrRegisterWriteKind_Sleep, 5, 0}, }; ================================================ FILE: fusee/program/source/fusee_emummc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_emummc.hpp" #include "fusee_mmc.hpp" #include "fusee_sd_card.hpp" #include "fusee_fatal.hpp" #include "fusee_malloc.hpp" #include "fs/fusee_fs_api.hpp" #include "fs/fusee_fs_storage.hpp" namespace ams::nxboot { namespace { class SdCardStorage : public fs::IStorage { public: virtual Result Read(s64 offset, void *buffer, size_t size) override { if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast<u64>(offset), static_cast<u64>(size)); } R_RETURN(ReadSdCard(buffer, size, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); } virtual Result Flush() override { R_SUCCEED(); } virtual Result GetSize(s64 *out) override { u32 num_sectors; R_TRY(GetSdCardMemoryCapacity(std::addressof(num_sectors))); *out = static_cast<s64>(num_sectors) * static_cast<s64>(sdmmc::SectorSize); R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result SetSize(s64 size) override { R_THROW(fs::ResultUnsupportedOperation()); } }; template<sdmmc::MmcPartition Partition> class MmcPartitionStorage : public fs::IStorage { public: constexpr MmcPartitionStorage() { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast<u64>(offset), static_cast<u64>(size)); } R_RETURN(ReadMmc(buffer, size, Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); } virtual Result Flush() override { R_SUCCEED(); } virtual Result GetSize(s64 *out) override { u32 num_sectors; R_TRY(GetMmcMemoryCapacity(std::addressof(num_sectors), Partition)); *out = num_sectors * sdmmc::SectorSize; R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result SetSize(s64 size) override { R_THROW(fs::ResultUnsupportedOperation()); } }; using MmcBoot0Storage = MmcPartitionStorage<sdmmc::MmcPartition_BootPartition1>; using MmcUserStorage = MmcPartitionStorage<sdmmc::MmcPartition_UserData>; constinit char g_emummc_path[0x300]; class EmummcFileStorage : public fs::IStorage { private: s64 m_file_size; fs::FileHandle m_handles[64]; bool m_open[64]; int m_file_path_ofs; private: void EnsureFile(int id) { if (!m_open[id]) { /* Update path. */ g_emummc_path[m_file_path_ofs + 1] = '0' + (id % 10); g_emummc_path[m_file_path_ofs + 0] = '0' + (id / 10); /* Open new file. */ const Result result = fs::OpenFile(m_handles + id, g_emummc_path, fs::OpenMode_Read); if (R_FAILED(result)) { ShowFatalError("Failed to open emummc user %02d file: 0x%08" PRIx32 "!\n", id, result.GetValue()); } m_open[id] = true; } } public: EmummcFileStorage(fs::FileHandle user00, int ofs) : m_file_path_ofs(ofs) { const Result result = fs::GetFileSize(std::addressof(m_file_size), user00); if (R_FAILED(result)) { ShowFatalError("Failed to get emummc file size: 0x%08" PRIx32 "!\n", result.GetValue()); } for (size_t i = 0; i < util::size(m_handles); ++i) { m_open[i] = false; } m_handles[0] = user00; m_open[0] = true; } virtual Result Read(s64 offset, void *buffer, size_t size) override { int file = offset / m_file_size; s64 subofs = offset % m_file_size; u8 *cur_dst = static_cast<u8 *>(buffer); for (/* ... */; size > 0; ++file) { /* Ensure the current file is open. */ EnsureFile(file); /* Perform the current read. */ const size_t cur_size = std::min<size_t>(m_file_size - subofs, size); R_TRY(fs::ReadFile(m_handles[file], subofs, cur_dst, cur_size)); /* Advance. */ cur_dst += cur_size; size -= cur_size; subofs = 0; } R_SUCCEED(); } virtual Result Flush() override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result GetSize(s64 *out) override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_THROW(fs::ResultUnsupportedOperation()); } virtual Result SetSize(s64 size) override { R_THROW(fs::ResultUnsupportedOperation()); } }; constinit SdCardStorage g_sd_card_storage; constinit MmcBoot0Storage g_mmc_boot0_storage; constinit MmcUserStorage g_mmc_user_storage; constinit fs::IStorage *g_boot0_storage = nullptr; constinit fs::IStorage *g_user_storage = nullptr; constinit fs::SubStorage *g_package2_storage = nullptr; struct Guid { u32 data1; u16 data2; u16 data3; u8 data4[8]; }; static_assert(sizeof(Guid) == 0x10); struct GptHeader { char signature[8]; u32 revision; u32 header_size; u32 header_crc32; u32 reserved0; u64 my_lba; u64 alt_lba; u64 first_usable_lba; u64 last_usable_lba; Guid disk_guid; u64 partition_entry_lba; u32 number_of_partition_entries; u32 size_of_partition_entry; u32 partition_entry_array_crc32; u32 reserved1; }; static_assert(sizeof(GptHeader) == 0x60); struct GptPartitionEntry { Guid partition_type_guid; Guid unique_partition_guid; u64 starting_lba; u64 ending_lba; u64 attributes; char partition_name[0x48]; }; static_assert(sizeof(GptPartitionEntry) == 0x80); struct Gpt { GptHeader header; u8 padding[0x1A0]; GptPartitionEntry entries[128]; }; static_assert(sizeof(Gpt) == 16_KB + 0x200); constexpr const u16 Package2PartitionName[] = { 'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0 }; } void InitializeEmummc(bool emummc_enabled, const secmon::EmummcConfiguration &emummc_cfg) { Result result; if (emummc_enabled) { /* Get sd card size. */ s64 sd_card_size; if (R_FAILED((result = g_sd_card_storage.GetSize(std::addressof(sd_card_size))))) { ShowFatalError("Failed to get sd card size: 0x%08" PRIx32 "!\n", result.GetValue()); } if (emummc_cfg.base_cfg.type == secmon::EmummcType_Partition) { const s64 partition_start = emummc_cfg.partition_cfg.start_sector * sdmmc::SectorSize; g_boot0_storage = AllocateObject<fs::SubStorage>(g_sd_card_storage, partition_start, 4_MB); g_user_storage = AllocateObject<fs::SubStorage>(g_sd_card_storage, partition_start + 8_MB, sd_card_size - (partition_start + 8_MB)); } else if (emummc_cfg.base_cfg.type == secmon::EmummcType_File) { /* Get the base emummc path. */ std::memcpy(g_emummc_path, emummc_cfg.file_cfg.path.str, sizeof(emummc_cfg.file_cfg.path.str)); /* Get path length. */ auto len = std::strlen(g_emummc_path); /* Append emmc. */ std::memcpy(g_emummc_path + len, "/eMMC", 6); len += 5; /* Open boot0. */ fs::FileHandle boot0_file; std::memcpy(g_emummc_path + len, "/boot0", 7); if (R_FAILED((result = fs::OpenFile(std::addressof(boot0_file), g_emummc_path, fs::OpenMode_Read)))) { ShowFatalError("Failed to open emummc boot0 file: 0x%08" PRIx32 "!\n", result.GetValue()); } /* Open boot1. */ g_emummc_path[len + 5] = '1'; { fs::DirectoryEntryType entry_type; bool is_archive; if (R_FAILED((result = fs::GetEntryType(std::addressof(entry_type), std::addressof(is_archive), g_emummc_path)))) { ShowFatalError("Failed to find emummc boot1 file: 0x%08" PRIx32 "!\n", result.GetValue()); } if (entry_type != fs::DirectoryEntryType_File) { ShowFatalError("emummc boot1 file is not a file!\n"); } } /* Open userdata. */ std::memcpy(g_emummc_path + len, "/00", 4); fs::FileHandle user00_file; if (R_FAILED((result = fs::OpenFile(std::addressof(user00_file), g_emummc_path, fs::OpenMode_Read)))) { ShowFatalError("Failed to open emummc user %02d file: 0x%08" PRIx32 "!\n", 0, result.GetValue()); } /* Create partitions. */ g_boot0_storage = AllocateObject<fs::FileHandleStorage>(boot0_file); g_user_storage = AllocateObject<EmummcFileStorage>(user00_file, len + 1); } else { ShowFatalError("Unknown emummc type %d\n", static_cast<int>(emummc_cfg.base_cfg.type)); } } else { /* Initialize access to mmc. */ { const Result result = InitializeMmc(); if (R_FAILED(result)) { ShowFatalError("Failed to initialize mmc: 0x%08" PRIx32 "\n", result.GetValue()); } } /* Create storages. */ g_boot0_storage = std::addressof(g_mmc_boot0_storage); g_user_storage = std::addressof(g_mmc_user_storage); } if (g_boot0_storage == nullptr) { ShowFatalError("Failed to initialize BOOT0\n"); } if (g_user_storage == nullptr) { ShowFatalError("Failed to initialize Raw EMMC\n"); } /* Read the GPT. */ Gpt *gpt = static_cast<Gpt *>(AllocateAligned(sizeof(Gpt), 0x200)); { const Result result = g_user_storage->Read(0x200, gpt, sizeof(*gpt)); if (R_FAILED(result)) { ShowFatalError("Failed to read GPT: 0x%08" PRIx32 "\n", result.GetValue()); } } /* Check the GPT. */ if (std::memcmp(gpt->header.signature, "EFI PART", 8) != 0) { ShowFatalError("Invalid GPT signature\n"); } if (gpt->header.number_of_partition_entries > util::size(gpt->entries)) { ShowFatalError("Too many GPT entries\n"); } /* Create system storage. */ for (u32 i = 0; i < gpt->header.number_of_partition_entries; ++i) { if (gpt->entries[i].starting_lba < gpt->header.first_usable_lba) { continue; } const s64 offset = INT64_C(0x200) * gpt->entries[i].starting_lba; const u64 size = UINT64_C(0x200) * (gpt->entries[i].ending_lba + 1 - gpt->entries[i].starting_lba); if (std::memcmp(gpt->entries[i].partition_name, Package2PartitionName, sizeof(Package2PartitionName)) == 0) { g_package2_storage = AllocateObject<fs::SubStorage>(*g_user_storage, offset, size); } } /* Check that we created package2 storage. */ if (g_package2_storage == nullptr) { ShowFatalError("Failed to initialize Package2\n"); } } Result ReadBoot0(s64 offset, void *dst, size_t size) { R_RETURN(g_boot0_storage->Read(offset, dst, size)); } Result ReadPackage2(s64 offset, void *dst, size_t size) { R_RETURN(g_package2_storage->Read(offset, dst, size)); } } ================================================ FILE: fusee/program/source/fusee_emummc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/secmon/secmon_emummc_context.hpp> namespace ams::nxboot { void InitializeEmummc(bool emummc_enabled, const secmon::EmummcConfiguration &emummc_cfg); Result ReadBoot0(s64 offset, void *dst, size_t size); Result ReadPackage2(s64 offset, void *dst, size_t size); Result ReadSystem(s64 offset, void *dst, size_t size); } ================================================ FILE: fusee/program/source/fusee_exception_handler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_exception_handler.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { NORETURN void ExceptionHandlerImpl(s32 which, u32 lr, u32 svc_lr) { ShowFatalError("Exception: which=%" PRId32 ", lr=%p, svc_lr=%p\n", which, reinterpret_cast<void *>(lr), reinterpret_cast<void *>(svc_lr)); } } namespace ams::diag { NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { AMS_UNUSED(expr, func, line, file); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr)); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { AMS_UNUSED(expr, func, line, file, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr)); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) { AMS_UNUSED(expr, func, line, file, result, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast<void *>(lr), result != nullptr ? result->GetValue() : 0); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exception_info, const char *format, ...) { AMS_UNUSED(expr, func, line, file, result, exception_info, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast<void *>(lr), result != nullptr ? result->GetValue() : 0); } NORETURN void AbortImpl() { u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr)); } NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { AMS_UNUSED(type, expr, func, file, line); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast<void *>(lr)); } NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { AMS_UNUSED(type, expr, func, file, line, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast<void *>(lr)); } } ================================================ FILE: fusee/program/source/fusee_exception_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot { NORETURN void ExceptionHandler(); NORETURN void ExceptionHandler0(); NORETURN void ExceptionHandler1(); NORETURN void ExceptionHandler2(); NORETURN void ExceptionHandler3(); NORETURN void ExceptionHandler4(); NORETURN void ExceptionHandler5(); NORETURN void ExceptionHandler6(); NORETURN void ExceptionHandler7(); } ================================================ FILE: fusee/program/source/fusee_exception_handler_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .text._ZN3ams6nxboot17ExceptionHandlerNEl, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandlerNEl .type _ZN3ams6nxboot17ExceptionHandlerNEl, %function _ZN3ams6nxboot17ExceptionHandlerNEl: /* Get the normal return address. */ mov r1, lr /* Get the SVC return address. */ msr cpsr_cf, #0xD3 mov r2, lr /* Invoke the exception handler in abort mode. */ msr cpsr_cf, #0xD7 b _ZN3ams6nxboot20ExceptionHandlerImplElmm .section .text._ZN3ams6nxboot16ExceptionHandlerEv, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot16ExceptionHandlerEv .type _ZN3ams6nxboot16ExceptionHandlerEv, %function _ZN3ams6nxboot16ExceptionHandlerEv: mov r0, #-1 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler0Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler0Ev .type _ZN3ams6nxboot17ExceptionHandler0Ev, %function _ZN3ams6nxboot17ExceptionHandler0Ev: mov r0, #0 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler1Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler1Ev .type _ZN3ams6nxboot17ExceptionHandler1Ev, %function _ZN3ams6nxboot17ExceptionHandler1Ev: mov r0, #1 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler2Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler2Ev .type _ZN3ams6nxboot17ExceptionHandler2Ev, %function _ZN3ams6nxboot17ExceptionHandler2Ev: mov r0, #2 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler3Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler3Ev .type _ZN3ams6nxboot17ExceptionHandler3Ev, %function _ZN3ams6nxboot17ExceptionHandler3Ev: mov r0, #3 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler4Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler4Ev .type _ZN3ams6nxboot17ExceptionHandler4Ev, %function _ZN3ams6nxboot17ExceptionHandler4Ev: mov r0, #4 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler5Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler5Ev .type _ZN3ams6nxboot17ExceptionHandler5Ev, %function _ZN3ams6nxboot17ExceptionHandler5Ev: mov r0, #5 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler6Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler6Ev .type _ZN3ams6nxboot17ExceptionHandler6Ev, %function _ZN3ams6nxboot17ExceptionHandler6Ev: mov r0, #6 b _ZN3ams6nxboot17ExceptionHandlerNEl .section .text._ZN3ams6nxboot17ExceptionHandler7Ev, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot17ExceptionHandler7Ev .type _ZN3ams6nxboot17ExceptionHandler7Ev, %function _ZN3ams6nxboot17ExceptionHandler7Ev: mov r0, #7 b _ZN3ams6nxboot17ExceptionHandlerNEl ================================================ FILE: fusee/program/source/fusee_external_package.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "fusee_display.hpp" namespace ams::nxboot { constexpr inline const size_t ExternalPackageSize = 8_MB; constexpr inline const size_t InitialProcessStorageSizeMax = 3_MB / 8; struct ExternalPackageContentMeta { u32 offset; u32 size; u8 type; u8 flags[3]; u32 pad; char name[0x10]; }; static_assert(sizeof(ExternalPackageContentMeta) == 0x20); struct ExternalPackageKipMeta { u64 program_id; u32 offset; u32 size; se::Sha256Hash hash; }; static_assert(sizeof(ExternalPackageKipMeta) == 0x30); struct ExternalPackageHeader { static constexpr u32 Magic = util::FourCC<'P', 'K', '3', '1'>::Code; static constexpr u32 LegacyMagic = util::FourCC<'F','S','S','0'>::Code; u32 magic; /* Previously entrypoint. */ u32 metadata_offset; u32 flags; u32 meso_size; u32 num_kips; u32 reserved1[3]; u32 legacy_magic; u32 total_size; u32 reserved2; /* Previously crt0 offset. */ u32 content_header_offset; u32 num_content_headers; u32 supported_hos_version; u32 release_version; u32 git_revision; ExternalPackageContentMeta content_metas[(0x400 - 0x40) / sizeof(ExternalPackageContentMeta)]; ExternalPackageKipMeta emummc_meta; ExternalPackageKipMeta kip_metas[8]; u8 reserved3[0x800 - (0x400 + 9 * sizeof(ExternalPackageKipMeta))]; }; static_assert(sizeof(ExternalPackageHeader) == 0x800); struct ExternalPackage { ExternalPackageHeader header; /* 0x000000-0x000800 */ u8 warmboot[0x1800]; /* 0x000800-0x002000 */ u8 tsec_keygen[0x2000]; /* 0x002000-0x004000 */ u8 mariko_fatal[0x1C000]; /* 0x004000-0x020000 */ u8 ovl_mtc_erista[0x14000]; /* 0x020000-0x034000 */ u8 ovl_mtc_mariko[0x14000]; /* 0x034000-0x048000 */ u8 exosphere[0xE000]; /* 0x048000-0x056000 */ u8 mesosphere[0xAA000]; /* 0x056000-0x100000 */ u8 kips[3_MB]; /* 0x100000-0x400000 */ u8 splash_screen_fb[FrameBufferSize]; /* 0x400000-0x7C0000 */ u8 fusee[0x20000]; /* 0x7C0000-0x7E0000 */ u8 reboot_stub[0x1000]; /* 0x7E0000-0x7E1000 */ u8 reserved[0x1F000]; /* 0x7E1000-0x800000 */ }; static_assert(sizeof(ExternalPackage) == ExternalPackageSize); ALWAYS_INLINE const ExternalPackage &GetExternalPackage() { return *reinterpret_cast<const ExternalPackage *>(0xC0000000); } } ================================================ FILE: fusee/program/source/fusee_fatal.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_fatal.hpp" #include "fusee_external_package.hpp" #include "fs/fusee_fs_api.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); Result SaveFatalErrorContext(const ams::impl::FatalErrorContext *ctx) { /* Create and open the file. */ fs::FileHandle file; { /* Generate the file path. */ char path[0x40]; util::TSNPrintf(path, sizeof(path), "sdmc:/atmosphere/fatal_errors/report_%016" PRIx64 ".bin", ctx->report_identifier); /* Create the file. */ R_TRY(fs::CreateFile(path, sizeof(*ctx))); /* Open the file. */ R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_ReadWrite)); } /* Ensure we close the file when done with it. */ ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Write the context to the file. */ R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush)); R_SUCCEED(); } } NORETURN void RebootToSelf() { /* Patch SDRAM init to perform an SVC immediately after second write. */ reg::Write(PMC + APBDEV_PMC_SCRATCH45, 0x2E38DFFF); reg::Write(PMC + APBDEV_PMC_SCRATCH46, 0x6001DC28); /* Set SVC handler to jump to reboot stub in IRAM. */ reg::Write(PMC + APBDEV_PMC_SCRATCH33, 0x4003F000); reg::Write(PMC + APBDEV_PMC_SCRATCH40, 0x6000F208); /* Set boot as warmboot. */ reg::Write(PMC + APBDEV_PMC_SCRATCH0, (1 << 0)); /* Copy reboot stub into high IRAM. */ std::memcpy(reinterpret_cast<void *>(0x4003F000), GetExternalPackage().reboot_stub, sizeof(GetExternalPackage().reboot_stub)); /* Copy our main payload into low IRAM. */ std::memcpy(reinterpret_cast<void *>(0x40010000), GetExternalPackage().fusee, sizeof(GetExternalPackage().fusee)); /* Reboot. */ reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE)); /* Wait for the reboot to take. */ AMS_INFINITE_LOOP(); } void SaveAndShowFatalError() { /* Get the context (at static location in memory). */ ams::impl::FatalErrorContext *f_ctx = reinterpret_cast<ams::impl::FatalErrorContext *>(0x4003E000); /* Check for valid magic. */ if (f_ctx->magic != ams::impl::FatalErrorContext::Magic) { return; } /* Show the fatal error. */ ShowFatalError(f_ctx, SaveFatalErrorContext(f_ctx)); /* Clear the magic. */ f_ctx->magic = ~f_ctx->magic; /* Wait for reboot. */ WaitForReboot(); } void WaitForReboot() { /* Wait for power button to be pressed. */ while (!pmic::IsPowerButtonPressed()) { util::WaitMicroSeconds(100); } /* If not erista, just do a normal reboot. */ if (fuse::GetSocType() != fuse::SocType_Erista) { /* Reboot. */ pmic::ShutdownSystem(true); /* Wait for our reboot to complete. */ AMS_INFINITE_LOOP(); } /* Reboot to self, if we can. */ if (GetExternalPackage().header.magic == ExternalPackageHeader::Magic) { RebootToSelf(); } else { /* Just do a normal reboot. */ pmic::ShutdownSystem(true); /* Wait for our reboot to complete. */ AMS_INFINITE_LOOP(); } } } ================================================ FILE: fusee/program/source/fusee_fatal.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { NORETURN void ShowFatalError(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void ShowFatalError(const ams::impl::FatalErrorContext *f_ctx, const Result save_result); void SaveAndShowFatalError(); NORETURN void WaitForReboot(); } ================================================ FILE: fusee/program/source/fusee_font.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * (C) Copyright 2000 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it * * SPDX-License-Identifier: GPL-2.0+ * * This file contains an 8x16 bitmap font for code page 437. */ constexpr inline const size_t FontWidth = 8; constexpr inline const size_t FontHeight = 16; constexpr inline const u8 FontData[] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 1 0x01 '^A' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x81, /* 10000001 */ 0xa5, /* 10100101 */ 0x81, /* 10000001 */ 0x81, /* 10000001 */ 0xbd, /* 10111101 */ 0x99, /* 10011001 */ 0x81, /* 10000001 */ 0x81, /* 10000001 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 2 0x02 '^B' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xff, /* 11111111 */ 0xdb, /* 11011011 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xc3, /* 11000011 */ 0xe7, /* 11100111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 3 0x03 '^C' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 4 0x04 '^D' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 5 0x05 '^E' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0xe7, /* 11100111 */ 0xe7, /* 11100111 */ 0xe7, /* 11100111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 6 0x06 '^F' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 7 0x07 '^G' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 8 0x08 '^H' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xe7, /* 11100111 */ 0xc3, /* 11000011 */ 0xc3, /* 11000011 */ 0xe7, /* 11100111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 9 0x09 '^I' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x42, /* 01000010 */ 0x42, /* 01000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 10 0x0a '^J' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xc3, /* 11000011 */ 0x99, /* 10011001 */ 0xbd, /* 10111101 */ 0xbd, /* 10111101 */ 0x99, /* 10011001 */ 0xc3, /* 11000011 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 11 0x0b '^K' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x0e, /* 00001110 */ 0x1a, /* 00011010 */ 0x32, /* 00110010 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 12 0x0c '^L' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 13 0x0d '^M' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x33, /* 00110011 */ 0x3f, /* 00111111 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x70, /* 01110000 */ 0xf0, /* 11110000 */ 0xe0, /* 11100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 14 0x0e '^N' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7f, /* 01111111 */ 0x63, /* 01100011 */ 0x7f, /* 01111111 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x63, /* 01100011 */ 0x67, /* 01100111 */ 0xe7, /* 11100111 */ 0xe6, /* 11100110 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 15 0x0f '^O' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xdb, /* 11011011 */ 0x3c, /* 00111100 */ 0xe7, /* 11100111 */ 0x3c, /* 00111100 */ 0xdb, /* 11011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 16 0x10 '^P' */ 0x00, /* 00000000 */ 0x80, /* 10000000 */ 0xc0, /* 11000000 */ 0xe0, /* 11100000 */ 0xf0, /* 11110000 */ 0xf8, /* 11111000 */ 0xfe, /* 11111110 */ 0xf8, /* 11111000 */ 0xf0, /* 11110000 */ 0xe0, /* 11100000 */ 0xc0, /* 11000000 */ 0x80, /* 10000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 17 0x11 '^Q' */ 0x00, /* 00000000 */ 0x02, /* 00000010 */ 0x06, /* 00000110 */ 0x0e, /* 00001110 */ 0x1e, /* 00011110 */ 0x3e, /* 00111110 */ 0xfe, /* 11111110 */ 0x3e, /* 00111110 */ 0x1e, /* 00011110 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x02, /* 00000010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 18 0x12 '^R' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 19 0x13 '^S' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 20 0x14 '^T' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7f, /* 01111111 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0x7b, /* 01111011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 21 0x15 '^U' */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 22 0x16 '^V' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 23 0x17 '^W' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 24 0x18 '^X' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 25 0x19 '^Y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 26 0x1a '^Z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0xfe, /* 11111110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 27 0x1b '^[' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xfe, /* 11111110 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 28 0x1c '^\' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 29 0x1d '^]' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x28, /* 00101000 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x28, /* 00101000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 30 0x1e '^^' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0x7c, /* 01111100 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 31 0x1f '^_' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0x7c, /* 01111100 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 32 0x20 ' ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 33 0x21 '!' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 34 0x22 '"' */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x24, /* 00100100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 35 0x23 '#' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 36 0x24 '$' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0x7c, /* 01111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x86, /* 10000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 37 0x25 '%' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc2, /* 11000010 */ 0xc6, /* 11000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0x86, /* 10000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 38 0x26 '&' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 39 0x27 ''' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 40 0x28 '(' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 41 0x29 ')' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 42 0x2a '*' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0xff, /* 11111111 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 43 0x2b '+' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 44 0x2c ',' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 45 0x2d '-' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 46 0x2e '.' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 47 0x2f '/' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x02, /* 00000010 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x80, /* 10000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 48 0x30 '0' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 49 0x31 '1' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x38, /* 00111000 */ 0x78, /* 01111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 50 0x32 '2' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 51 0x33 '3' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x3c, /* 00111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 52 0x34 '4' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x1c, /* 00011100 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xfe, /* 11111110 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x1e, /* 00011110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 53 0x35 '5' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfc, /* 11111100 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 54 0x36 '6' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xfc, /* 11111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 55 0x37 '7' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 56 0x38 '8' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 57 0x39 '9' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 58 0x3a ':' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 59 0x3b ';' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 60 0x3c '<' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 61 0x3d '=' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 62 0x3e '>' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 63 0x3f '?' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 64 0x40 '@' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xde, /* 11011110 */ 0xde, /* 11011110 */ 0xde, /* 11011110 */ 0xdc, /* 11011100 */ 0xc0, /* 11000000 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 65 0x41 'A' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 66 0x42 'B' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xfc, /* 11111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 67 0x43 'C' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc2, /* 11000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 68 0x44 'D' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 69 0x45 'E' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x60, /* 01100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 70 0x46 'F' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 71 0x47 'G' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xde, /* 11011110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x66, /* 01100110 */ 0x3a, /* 00111010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 72 0x48 'H' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 73 0x49 'I' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 74 0x4a 'J' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 75 0x4b 'K' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe6, /* 11100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x78, /* 01111000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 76 0x4c 'L' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf0, /* 11110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 77 0x4d 'M' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xee, /* 11101110 */ 0xfe, /* 11111110 */ 0xfe, /* 11111110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 78 0x4e 'N' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xe6, /* 11100110 */ 0xf6, /* 11110110 */ 0xfe, /* 11111110 */ 0xde, /* 11011110 */ 0xce, /* 11001110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 79 0x4f 'O' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 80 0x50 'P' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 81 0x51 'Q' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xde, /* 11011110 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0x0e, /* 00001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 82 0x52 'R' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfc, /* 11111100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 83 0x53 'S' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 84 0x54 'T' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x5a, /* 01011010 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 85 0x55 'U' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 86 0x56 'V' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 87 0x57 'W' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xfe, /* 11111110 */ 0xee, /* 11101110 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 88 0x58 'X' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x7c, /* 01111100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x7c, /* 01111100 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 89 0x59 'Y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 90 0x5a 'Z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x86, /* 10000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc2, /* 11000010 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 91 0x5b '[' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 92 0x5c '\' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x80, /* 10000000 */ 0xc0, /* 11000000 */ 0xe0, /* 11100000 */ 0x70, /* 01110000 */ 0x38, /* 00111000 */ 0x1c, /* 00011100 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x02, /* 00000010 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 93 0x5d ']' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 94 0x5e '^' */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 95 0x5f '_' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 96 0x60 '`' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 97 0x61 'a' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 98 0x62 'b' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 99 0x63 'c' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 100 0x64 'd' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 101 0x65 'e' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 102 0x66 'f' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x36, /* 00110110 */ 0x32, /* 00110010 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 103 0x67 'g' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0xcc, /* 11001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ /* 104 0x68 'h' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x6c, /* 01101100 */ 0x76, /* 01110110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 105 0x69 'i' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 106 0x6a 'j' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ /* 107 0x6b 'k' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xe0, /* 11100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x78, /* 01111000 */ 0x78, /* 01111000 */ 0x6c, /* 01101100 */ 0x66, /* 01100110 */ 0xe6, /* 11100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 108 0x6c 'l' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 109 0x6d 'm' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xec, /* 11101100 */ 0xfe, /* 11111110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 110 0x6e 'n' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 111 0x6f 'o' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 112 0x70 'p' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ /* 113 0x71 'q' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x7c, /* 01111100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x1e, /* 00011110 */ 0x00, /* 00000000 */ /* 114 0x72 'r' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x76, /* 01110110 */ 0x66, /* 01100110 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 115 0x73 's' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x38, /* 00111000 */ 0x0c, /* 00001100 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 116 0x74 't' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0xfc, /* 11111100 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x36, /* 00110110 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 117 0x75 'u' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 118 0x76 'v' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 119 0x77 'w' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xd6, /* 11010110 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 120 0x78 'x' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 121 0x79 'y' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ /* 122 0x7a 'z' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xcc, /* 11001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 123 0x7b '{' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x0e, /* 00001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 124 0x7c '|' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 125 0x7d '}' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x70, /* 01110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x0e, /* 00001110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 126 0x7e '~' */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 127 0x7f '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 128 0x80 '€' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0xc2, /* 11000010 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc2, /* 11000010 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 129 0x81 '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 130 0x82 '‚' */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 131 0x83 'ƒ' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 132 0x84 '„' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 133 0x85 '…' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 134 0x86 '†' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 135 0x87 '‡' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 136 0x88 'ˆ' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 137 0x89 '‰' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 138 0x8a 'Š' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 139 0x8b '‹' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 140 0x8c 'Œ' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 141 0x8d '' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 142 0x8e 'Ž' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 143 0x8f '' */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 144 0x90 '' */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x66, /* 01100110 */ 0x62, /* 01100010 */ 0x68, /* 01101000 */ 0x78, /* 01111000 */ 0x68, /* 01101000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 145 0x91 '‘' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xec, /* 11101100 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x7e, /* 01111110 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x6e, /* 01101110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 146 0x92 '’' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3e, /* 00111110 */ 0x6c, /* 01101100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xfe, /* 11111110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xce, /* 11001110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 147 0x93 '“' */ 0x00, /* 00000000 */ 0x10, /* 00010000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 148 0x94 '”' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 149 0x95 '•' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 150 0x96 '–' */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 151 0x97 '—' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 152 0x98 '˜' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7e, /* 01111110 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x78, /* 01111000 */ 0x00, /* 00000000 */ /* 153 0x99 '™' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 154 0x9a 'š' */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 155 0x9b '›' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 156 0x9c 'œ' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x64, /* 01100100 */ 0x60, /* 01100000 */ 0xf0, /* 11110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xe6, /* 11100110 */ 0xfc, /* 11111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 157 0x9d '' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 158 0x9e 'ž' */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xf8, /* 11111000 */ 0xc4, /* 11000100 */ 0xcc, /* 11001100 */ 0xde, /* 11011110 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 159 0x9f 'Ÿ' */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x1b, /* 00011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 160 0xa0 ' ' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0x0c, /* 00001100 */ 0x7c, /* 01111100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 161 0xa1 '¡' */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 162 0xa2 '¢' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 163 0xa3 '£' */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x00, /* 00000000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 164 0xa4 '¤' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0xdc, /* 11011100 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 165 0xa5 '¥' */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0xc6, /* 11000110 */ 0xe6, /* 11100110 */ 0xf6, /* 11110110 */ 0xfe, /* 11111110 */ 0xde, /* 11011110 */ 0xce, /* 11001110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 166 0xa6 '¦' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x3e, /* 00111110 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 167 0xa7 '§' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 168 0xa8 '¨' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 169 0xa9 '©' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 170 0xaa 'ª' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 171 0xab '«' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0xe0, /* 11100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xdc, /* 11011100 */ 0x86, /* 10000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x3e, /* 00111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 172 0xac '¬' */ 0x00, /* 00000000 */ 0x60, /* 01100000 */ 0xe0, /* 11100000 */ 0x62, /* 01100010 */ 0x66, /* 01100110 */ 0x6c, /* 01101100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x66, /* 01100110 */ 0xce, /* 11001110 */ 0x9a, /* 10011010 */ 0x3f, /* 00111111 */ 0x06, /* 00000110 */ 0x06, /* 00000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 173 0xad '­' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x3c, /* 00111100 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 174 0xae '®' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x36, /* 00110110 */ 0x6c, /* 01101100 */ 0xd8, /* 11011000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 175 0xaf '¯' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xd8, /* 11011000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x6c, /* 01101100 */ 0xd8, /* 11011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 176 0xb0 '°' */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ 0x11, /* 00010001 */ 0x44, /* 01000100 */ /* 177 0xb1 '±' */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ 0x55, /* 01010101 */ 0xaa, /* 10101010 */ /* 178 0xb2 '²' */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ 0xdd, /* 11011101 */ 0x77, /* 01110111 */ /* 179 0xb3 '³' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 180 0xb4 '´' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 181 0xb5 'µ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 182 0xb6 '¶' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 183 0xb7 '·' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 184 0xb8 '¸' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 185 0xb9 '¹' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x06, /* 00000110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 186 0xba 'º' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 187 0xbb '»' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x06, /* 00000110 */ 0xf6, /* 11110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 188 0xbc '¼' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf6, /* 11110110 */ 0x06, /* 00000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 189 0xbd '½' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 190 0xbe '¾' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 191 0xbf '¿' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xf8, /* 11111000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 192 0xc0 'À' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 193 0xc1 'Á' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 194 0xc2 'Â' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 195 0xc3 'Ã' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 196 0xc4 'Ä' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 197 0xc5 'Å' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 198 0xc6 'Æ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 199 0xc7 'Ç' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 200 0xc8 'È' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x30, /* 00110000 */ 0x3f, /* 00111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 201 0xc9 'É' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x30, /* 00110000 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 202 0xca 'Ê' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf7, /* 11110111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 203 0xcb 'Ë' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xf7, /* 11110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 204 0xcc 'Ì' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x37, /* 00110111 */ 0x30, /* 00110000 */ 0x37, /* 00110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 205 0xcd 'Í' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 206 0xce 'Î' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xf7, /* 11110111 */ 0x00, /* 00000000 */ 0xf7, /* 11110111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 207 0xcf 'Ï' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 208 0xd0 'Ð' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 209 0xd1 'Ñ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 210 0xd2 'Ò' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 211 0xd3 'Ó' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x3f, /* 00111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 212 0xd4 'Ô' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 213 0xd5 'Õ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 214 0xd6 'Ö' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x3f, /* 00111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 215 0xd7 '×' */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0xff, /* 11111111 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ /* 216 0xd8 'Ø' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0xff, /* 11111111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 217 0xd9 'Ù' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xf8, /* 11111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 218 0xda 'Ú' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1f, /* 00011111 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 219 0xdb 'Û' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 220 0xdc 'Ü' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ /* 221 0xdd 'Ý' */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ 0xf0, /* 11110000 */ /* 222 0xde 'Þ' */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ 0x0f, /* 00001111 */ /* 223 0xdf 'ß' */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0xff, /* 11111111 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 224 0xe0 'à' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xdc, /* 11011100 */ 0x76, /* 01110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 225 0xe1 'á' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x78, /* 01111000 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xcc, /* 11001100 */ 0xd8, /* 11011000 */ 0xcc, /* 11001100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xcc, /* 11001100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 226 0xe2 'â' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 227 0xe3 'ã' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 228 0xe4 'ä' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0xc6, /* 11000110 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 229 0xe5 'å' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 230 0xe6 'æ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ /* 231 0xe7 'ç' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 232 0xe8 'è' */ 0x00, /* 00000000 */ 0x40, /* 01000000*/ 0xe0, /* 01110000 */ 0x1c, /* 00011100 */ 0x06, /* 00000110 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 233 0xe9 'é' */ 0x00, /* 00000000 */ 0x02, /* 00000010*/ 0x0e, /* 00001110 */ 0x78, /* 00111000 */ 0xc0, /* 01100000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xfe, /* 11111110 */ 0xc0, /* 11000000 */ 0xc0, /* 11000000 */ 0xc6, /* 11000110 */ 0x7c, /* 01111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 234 0xea 'ê' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0xee, /* 11101110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 235 0xeb 'ë' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1e, /* 00011110 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x3e, /* 00111110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x66, /* 01100110 */ 0x3c, /* 00111100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 236 0xec 'ì' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 237 0xed 'í' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x03, /* 00000011 */ 0x06, /* 00000110 */ 0x7e, /* 01111110 */ 0xdb, /* 11011011 */ 0xdb, /* 11011011 */ 0xf3, /* 11110011 */ 0x7e, /* 01111110 */ 0x60, /* 01100000 */ 0xc0, /* 11000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 238 0xee 'î' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x1c, /* 00011100 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x7c, /* 01111100 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 239 0xef 'ï' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7c, /* 01111100 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0xc6, /* 11000110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 240 0xf0 'ð' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0xfe, /* 11111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 241 0xf1 'ñ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x7e, /* 01111110 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 242 0xf2 'ò' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x06, /* 00000110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 243 0xf3 'ó' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x30, /* 00110000 */ 0x60, /* 01100000 */ 0x30, /* 00110000 */ 0x18, /* 00011000 */ 0x0c, /* 00001100 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 244 0xf4 'ô' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x0e, /* 00001110 */ 0x1b, /* 00011011 */ 0x1b, /* 00011011 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ /* 245 0xf5 'õ' */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0xd8, /* 11011000 */ 0x70, /* 01110000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 246 0xf6 'ö' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 247 0xf7 '÷' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x76, /* 01110110 */ 0xdc, /* 11011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 248 0xf8 'ø' */ 0x00, /* 00000000 */ 0x38, /* 00111000 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x38, /* 00111000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 249 0xf9 'ù' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 250 0xfa 'ú' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x18, /* 00011000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 251 0xfb 'û' */ 0x00, /* 00000000 */ 0x0f, /* 00001111 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0x0c, /* 00001100 */ 0xec, /* 11101100 */ 0x6c, /* 01101100 */ 0x6c, /* 01101100 */ 0x3c, /* 00111100 */ 0x1c, /* 00011100 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 252 0xfc 'ü' */ 0x00, /* 00000000 */ 0x6c, /* 01101100 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x36, /* 00110110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 253 0xfd 'ý' */ 0x00, /* 00000000 */ 0x3c, /* 00111100 */ 0x66, /* 01100110 */ 0x0c, /* 00001100 */ 0x18, /* 00011000 */ 0x32, /* 00110010 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 254 0xfe 'þ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x7e, /* 01111110 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ /* 255 0xff 'ÿ' */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ 0x00, /* 00000000 */ }; constexpr inline u32 FontDrawTable[16][4] = { { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x00000000, 0x00ffffff }, { 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 }, { 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff }, { 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 }, { 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff }, { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 }, { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff }, { 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 }, { 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff }, { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 }, { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff }, { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 }, { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff }, { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 }, { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff } }; ================================================ FILE: fusee/program/source/fusee_ini.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_ini.hpp" #include "fusee_malloc.hpp" #include "fs/fusee_fs_api.hpp" namespace ams::nxboot { namespace { constexpr s64 IniFileSizeMax = 64_KB; constexpr bool IsWhiteSpace(char c) { return c == ' ' || c == '\r'; } } ParseIniResult ParseIniFile(IniSectionList &out_sections, const char *ini_path) { /* Open the ini file. */ fs::FileHandle file; if (R_FAILED(fs::OpenFile(std::addressof(file), ini_path, fs::OpenMode_Read))) { return ParseIniResult_NoFile; } ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Get file size. */ s64 file_size; if (R_FAILED(fs::GetFileSize(std::addressof(file_size), file))) { return ParseIniResult_NoFile; } /* Cap file size. */ file_size = std::min(IniFileSizeMax, file_size); /* Allocate memory for file. */ char *buffer = static_cast<char *>(AllocateAligned(util::AlignUp(file_size + 1, 0x10), 0x10)); buffer[file_size] = '\x00'; /* Read file. */ if (R_FAILED(fs::ReadFile(file, 0, buffer, file_size))) { return ParseIniResult_NoFile; } /* Parse the file. */ enum class State { Newline, Comment, SectionName, Key, KvSpace, KvSpace2, Value, TrailingSpace, }; char *sec_start, *key_start, *val_start, *val_end; IniSection *cur_sec = nullptr; State state = State::Newline; for (int i = 0; i < file_size; ++i) { const char c = buffer[i]; switch (state) { case State::Newline: if (c == '[') { sec_start = buffer + i + 1; state = State::SectionName; } else if (c == ';' || c == '#') { state = State::Comment; } else if (IsWhiteSpace(c) || c == '\n') { state = State::Newline; } else if (cur_sec != nullptr) { key_start = buffer + i; state = State::Key; } else { return ParseIniResult_InvalidFormat; } break; case State::Comment: if (c == '\n') { state = State::Newline; } break; case State::SectionName: if (c == '\n') { return ParseIniResult_InvalidFormat; } else if (c == ']') { cur_sec = AllocateObject<IniSection>(); cur_sec->name = sec_start; buffer[i] = '\x00'; out_sections.push_back(*cur_sec); state = State::TrailingSpace; } break; case State::Key: if (c == '\n') { return ParseIniResult_InvalidFormat; } else if (IsWhiteSpace(c)) { buffer[i] = '\x00'; state = State::KvSpace; } else if (c == '=') { buffer[i] = '\x00'; state = State::KvSpace2; } break; case State::KvSpace: if (c == '=') { state = State::KvSpace2; } else if (!IsWhiteSpace(c)) { return ParseIniResult_InvalidFormat; } break; case State::KvSpace2: if (c == '\n') { buffer[i] = '\x00'; auto *entry = AllocateObject<IniKeyValueEntry>(); entry->key = key_start; entry->value = buffer + i; cur_sec->kv_list.push_back(*entry); state = State::Newline; } else if (!IsWhiteSpace(c)) { val_start = buffer + i; val_end = buffer + i + 1; state = State::Value; } break; case State::Value: if (c == '\r' || c == '\n') { buffer[i] = '\x00'; *val_end = '\x00'; auto *entry = AllocateObject<IniKeyValueEntry>(); entry->key = key_start; entry->value = val_start; cur_sec->kv_list.push_back(*entry); state = (c == '\n') ? State::Newline : State::TrailingSpace; } else if (c != ' ') { val_end = buffer + i + 1; } break; case State::TrailingSpace: if (c == '\n') { state = State::Newline; } else if (!IsWhiteSpace(c)) { return ParseIniResult_InvalidFormat; } break; } } /* Accept value-state. */ if (state == State::Value) { auto *entry = AllocateObject<IniKeyValueEntry>(); entry->key = key_start; entry->value = val_start; cur_sec->kv_list.push_back(*entry); return ParseIniResult_Success; } else if (state == State::TrailingSpace || state == State::Comment || state == State::Newline) { return ParseIniResult_Success; } else { return ParseIniResult_InvalidFormat; } } } ================================================ FILE: fusee/program/source/fusee_ini.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { struct IniKeyValueEntry { util::IntrusiveListNode list_node; char *key; char *value; }; using IniKeyValueList = typename util::IntrusiveListMemberTraits<&IniKeyValueEntry::list_node>::ListType; struct IniSection { util::IntrusiveListNode list_node; IniKeyValueList kv_list; char *name; }; using IniSectionList = typename util::IntrusiveListMemberTraits<&IniSection::list_node>::ListType; enum ParseIniResult { ParseIniResult_Success, ParseIniResult_NoFile, ParseIniResult_InvalidFormat, }; ParseIniResult ParseIniFile(IniSectionList &out_sections, const char *ini_path); } ================================================ FILE: fusee/program/source/fusee_key_derivation.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_key_derivation.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { namespace { alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ 0xEB, 0xF3, 0x5B, 0x2D, 0x4A, 0x2D, 0xCE, 0x45, 0x3A, 0x6F, 0x61, 0x38, 0x0B, 0x00, 0x3B, 0x46 }; alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ 0x11, 0x1C, 0x13, 0x90, 0xD9, 0x5E, 0xB0, 0xA2, 0xE3, 0xD0, 0x0E, 0x5D, 0xC4, 0xFB, 0x9E, 0xDB }; alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = { /* TODO: Update on next change of keys. */ 0x66, 0xC8, 0xCB, 0x3D, 0xEC, 0xF4, 0x59, 0x73, 0x54, 0x88, 0xE1, 0x2E, 0xE6, 0x3D, 0x68, 0x46 }; alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = { 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }; alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySource[se::AesBlockSize] = { 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceKeySource[se::AesBlockSize] = { 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKeySourceKekSource[se::AesBlockSize] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSource[se::AesBlockSize] = { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKeySourceSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { { 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D }, /* 4.x Device Master Key Source Source. */ { 0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C }, /* 5.x Device Master Key Source Source. */ { 0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4 }, /* 6.x Device Master Key Source Source. */ { 0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17 }, /* 6.2.0 Device Master Key Source Source. */ { 0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D }, /* 7.0.0 Device Master Key Source Source. */ { 0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE }, /* 8.1.0 Device Master Key Source Source. */ { 0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49 }, /* 9.0.0 Device Master Key Source Source. */ { 0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94 }, /* 9.1.0 Device Master Key Source Source. */ { 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 }, /* 12.1.0 Device Master Key Source Source. */ { 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.0 Device Master Key Source Source. */ { 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, /* 14.0.0 Device Master Key Source Source. */ { 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */ { 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, /* 16.0.0 Device Master Key Source Source. */ { 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, /* 17.0.0 Device Master Key Source Source. */ { 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, /* 18.0.0 Device Master Key Source Source. */ { 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, /* 19.0.0 Device Master Key Source Source. */ { 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, /* 20.0.0 Device Master Key Source Source. */ { 0xF9, 0x62, 0x05, 0x99, 0xE0, 0xB9, 0xA6, 0x9B, 0x9D, 0xAA, 0xB4, 0x12, 0x0B, 0x0F, 0xF5, 0x8F }, /* 21.0.0 Device Master Key Source Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { { 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D }, /* 4.x Device Master Kek Source. */ { 0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E }, /* 5.x Device Master Kek Source. */ { 0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF }, /* 6.x Device Master Kek Source. */ { 0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB }, /* 6.2.0 Device Master Kek Source. */ { 0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E }, /* 7.0.0 Device Master Kek Source. */ { 0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D }, /* 8.1.0 Device Master Kek Source. */ { 0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED }, /* 9.0.0 Device Master Kek Source. */ { 0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36 }, /* 9.1.0 Device Master Kek Source. */ { 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 }, /* 12.1.0 Device Master Kek Source. */ { 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.0 Device Master Kek Source. */ { 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, /* 14.0.0 Device Master Kek Source. */ { 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */ { 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, /* 16.0.0 Device Master Kek Source. */ { 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, /* 17.0.0 Device Master Kek Source. */ { 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, /* 18.0.0 Device Master Kek Source. */ { 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, /* 19.0.0 Device Master Kek Source. */ { 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, /* 20.0.0 Device Master Kek Source. */ { 0x92, 0xBF, 0x37, 0x80, 0x0E, 0x79, 0x56, 0x8C, 0x57, 0x75, 0x72, 0x0A, 0x48, 0xD8, 0x15, 0x39 }, /* 21.0.0 Device Master Kek Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = { { 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 }, /* 4.x Device Master Kek Source. */ { 0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8 }, /* 5.x Device Master Kek Source. */ { 0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5 }, /* 6.x Device Master Kek Source. */ { 0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38 }, /* 6.2.0 Device Master Kek Source. */ { 0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE }, /* 7.0.0 Device Master Kek Source. */ { 0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87 }, /* 8.1.0 Device Master Kek Source. */ { 0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F }, /* 9.0.0 Device Master Kek Source. */ { 0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B }, /* 9.1.0 Device Master Kek Source. */ { 0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB }, /* 12.1.0 Device Master Kek Source. */ { 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.0 Device Master Kek Source. */ { 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA }, /* 14.0.0 Device Master Kek Source. */ { 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */ { 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F }, /* 16.0.0 Device Master Kek Source. */ { 0x4E, 0xCE, 0x7B, 0x2A, 0xEA, 0x2E, 0x3D, 0x16, 0xD5, 0x2A, 0xDE, 0xF6, 0xF8, 0x6A, 0x7D, 0x43 }, /* 17.0.0 Device Master Kek Source. */ { 0x3B, 0x00, 0x89, 0xD7, 0xA9, 0x9E, 0xB7, 0x70, 0x86, 0x00, 0xC3, 0x49, 0x52, 0x8C, 0xA4, 0xAF }, /* 18.0.0 Device Master Kek Source. */ { 0xAE, 0x78, 0x36, 0xB6, 0x91, 0xEB, 0xAF, 0x9C, 0x18, 0xF1, 0xC0, 0xD5, 0x8A, 0x0C, 0x7C, 0xA1 }, /* 19.0.0 Device Master Kek Source. */ { 0x09, 0x12, 0x4F, 0x26, 0x90, 0xB9, 0xA6, 0xF5, 0xA5, 0x18, 0x74, 0xB6, 0x8D, 0x80, 0x59, 0x3D }, /* 20.0.0 Device Master Kek Source. */ { 0x7A, 0x4C, 0x38, 0xB7, 0x03, 0x6B, 0x1E, 0x81, 0x20, 0x53, 0x14, 0x99, 0xA4, 0x21, 0x92, 0x9F }, /* 21.0.0 Device Master Kek Source. */ }; alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = { { 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D }, /* Zeroes encrypted with Master Key 00. */ { 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD }, /* Master key 00 encrypted with Master key 01. */ { 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 }, /* Master key 01 encrypted with Master key 02. */ { 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 }, /* Master key 02 encrypted with Master key 03. */ { 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 }, /* Master key 03 encrypted with Master key 04. */ { 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE }, /* Master key 04 encrypted with Master key 05. */ { 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 }, /* Master key 05 encrypted with Master key 06. */ { 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F }, /* Master key 06 encrypted with Master key 07. */ { 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, /* Master key 07 encrypted with Master key 08. */ { 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, /* Master key 08 encrypted with Master key 09. */ { 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, /* Master key 09 encrypted with Master key 0A. */ { 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, /* Master key 0A encrypted with Master key 0B. */ { 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */ { 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, /* Master key 0C encrypted with Master key 0D. */ { 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */ { 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, /* Master key 0E encrypted with Master key 0F. */ { 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, /* Master key 0F encrypted with Master key 10. */ { 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, /* Master key 10 encrypted with Master key 11. */ { 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, /* Master key 11 encrypted with Master key 12. */ { 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, /* Master key 12 encrypted with Master key 13. */ { 0xF7, 0x92, 0xC0, 0xEC, 0xF3, 0xA4, 0x8C, 0xB7, 0x0D, 0xB3, 0xF3, 0xAB, 0x10, 0x9B, 0x18, 0xBA }, /* Master key 13 encrypted with Master key 14. */ }; alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = { { 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE }, /* Zeroes encrypted with Master Key 00. */ { 0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23 }, /* Master key 00 encrypted with Master key 01. */ { 0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D }, /* Master key 01 encrypted with Master key 02. */ { 0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3 }, /* Master key 02 encrypted with Master key 03. */ { 0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA }, /* Master key 03 encrypted with Master key 04. */ { 0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC }, /* Master key 04 encrypted with Master key 05. */ { 0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E }, /* Master key 05 encrypted with Master key 06. */ { 0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19 }, /* Master key 06 encrypted with Master key 07. */ { 0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04 }, /* Master key 07 encrypted with Master key 08. */ { 0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE }, /* Master key 08 encrypted with Master key 09. */ { 0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4 }, /* Master key 09 encrypted with Master key 0A. */ { 0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C }, /* Master key 0A encrypted with Master key 0B. */ { 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */ { 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, /* Master key 0C encrypted with Master key 0D. */ { 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */ { 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, /* Master key 0E encrypted with Master key 0F. */ { 0x39, 0x1E, 0x7E, 0xF8, 0x7E, 0x73, 0xEA, 0x6F, 0xAF, 0x00, 0x3A, 0xB4, 0xAA, 0xB8, 0xB7, 0x59 }, /* Master key 0F encrypted with Master key 10. */ { 0x0C, 0x75, 0x39, 0x15, 0x53, 0xEA, 0x81, 0x11, 0xA3, 0xE0, 0xDC, 0x3D, 0x0E, 0x76, 0xC6, 0xB8 }, /* Master key 10 encrypted with Master key 11. */ { 0x90, 0x64, 0xF9, 0x08, 0x29, 0x88, 0xD4, 0xDC, 0x73, 0xA4, 0xA1, 0x13, 0x9E, 0x59, 0x85, 0xA0 }, /* Master key 11 encrypted with Master key 12. */ { 0x94, 0x46, 0x3B, 0xFA, 0x7D, 0xB9, 0xE2, 0x94, 0xC2, 0x9D, 0xB9, 0xA4, 0xB2, 0x56, 0xCA, 0xFE }, /* Master key 12 encrypted with Master key 13. */ { 0x74, 0xB2, 0x5F, 0xA0, 0x4B, 0x74, 0x6D, 0x47, 0x5B, 0xA9, 0xF5, 0x26, 0x46, 0xD7, 0x4B, 0x6E }, /* Master key 13 encrypted with Master key 14. */ }; alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {}; alignas(se::AesBlockSize) constinit u8 DeviceMasterKeys[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {}; void DeriveMasterKeys(bool is_prod) { /* Decrypt the vector chain from current generation to start. */ int slot = pkg1::AesKeySlot_BootloaderMaster; for (int i = pkg1::KeyGeneration_Current; i > pkg1::KeyGeneration_1_0_0; --i) { /* Decrypt the old master key. */ se::DecryptAes128(MasterKeys[i - 1], se::AesBlockSize, slot, is_prod ? MasterKeySources[i] : MasterKeySourcesDev[i], se::AesBlockSize); /* Set the old master key into a temporary keyslot. */ se::SetAesKey(pkg1::AesKeySlot_BootloaderTemporary, MasterKeys[i - 1], se::AesBlockSize); /* Perform the next decryption with the older master key. */ slot = pkg1::AesKeySlot_BootloaderTemporary; } /* Decrypt the final vector. */ alignas(se::AesBlockSize) u8 test_vector[se::AesBlockSize]; se::DecryptAes128(test_vector, se::AesBlockSize, pkg1::AesKeySlot_BootloaderTemporary, is_prod ? MasterKeySources[pkg1::KeyGeneration_1_0_0] : MasterKeySourcesDev[pkg1::KeyGeneration_1_0_0], se::AesBlockSize); /* Verify the vector chain. */ alignas(se::AesBlockSize) constexpr u8 ZeroBlock[se::AesBlockSize] = {}; if (!crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize)) { ShowFatalError("Failed to derive master keys!\n"); } } void DeriveDeviceMasterKeys(fuse::SocType soc_type, bool is_prod) { alignas(se::AesBlockSize) u8 work_block[se::AesBlockSize]; /* Iterate for all generations. */ for (int i = 0; i < pkg1::OldDeviceMasterKeyCount; ++i) { const int generation = pkg1::KeyGeneration_4_0_0 + i; /* Load the first master key into the temporary keyslot keyslot. */ se::SetAesKey(pkg1::AesKeySlot_BootloaderTemporary, MasterKeys[pkg1::KeyGeneration_1_0_0], se::AesBlockSize); /* Decrypt the device master kek for the generation. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderTemporary, pkg1::AesKeySlot_BootloaderTemporary, is_prod ? DeviceMasterKekSources[i] : DeviceMasterKekSourcesDev[i], se::AesBlockSize); /* Decrypt the device master key source into the work block. */ se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_DeviceMasterKeySourceKekErista, DeviceMasterKeySourceSources[i], se::AesBlockSize); if (generation == pkg1::KeyGeneration_Current) { se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderDeviceMaster, pkg1::AesKeySlot_BootloaderTemporary, work_block, se::AesBlockSize); /* If on erista, derive the current device master key into the DeviceMaster key slot. */ if (soc_type == fuse::SocType_Erista) { se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_BootloaderTemporary, work_block, se::AesBlockSize); } } else { /* Decrypt the device master key. */ se::DecryptAes128(DeviceMasterKeys[i], se::AesBlockSize, pkg1::AesKeySlot_BootloaderTemporary, work_block, se::AesBlockSize); /* If on mariko, ensure that we derive device key 0 here. */ if (soc_type == fuse::SocType_Mariko && i == 0) { se::SetAesKey(pkg1::AesKeySlot_Device, DeviceMasterKeys[i], se::AesBlockSize); } } } } alignas(se::AesBlockSize) constexpr inline const u8 GeneratePersonalizedAesKeyKekKekSource[se::AesBlockSize] = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 }; alignas(se::AesBlockSize) constexpr inline const u8 GeneratePersonalizedAesKeyKeyKekSource[se::AesBlockSize] = { 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8 }; void GeneratePersonalizedAesKeyForBis(int slot, const void *kek_source, const void *key_source, int generation) { /* Derive kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderTemporary, PrepareDeviceMasterKey(generation), GeneratePersonalizedAesKeyKekKekSource, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderTemporary, pkg1::AesKeySlot_BootloaderTemporary, kek_source, se::AesBlockSize); /* Derive key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderTemporary, pkg1::AesKeySlot_BootloaderTemporary, GeneratePersonalizedAesKeyKeyKekSource, se::AesBlockSize); se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_BootloaderTemporary, key_source, se::AesBlockSize); } alignas(se::AesBlockSize) constexpr inline const u8 BisKekSource[se::AesBlockSize] = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F }; alignas(se::AesBlockSize) constexpr inline const u8 BisPartitionSystemKeySources[2][se::AesBlockSize] = { { 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C }, { 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4 }, }; void DeriveBisPartitionSystemKeys() { /* Determine key generation. */ const int key_generation = std::max<int>(0, static_cast<int>(fuse::GetDeviceUniqueKeyGeneration()) - 1); /* Generate desired keys. */ GeneratePersonalizedAesKeyForBis(pkg1::AesKeySlot_BootloaderSystem0, BisKekSource, BisPartitionSystemKeySources[0], key_generation); GeneratePersonalizedAesKeyForBis(pkg1::AesKeySlot_BootloaderSystem1, BisKekSource, BisPartitionSystemKeySources[1], key_generation); } } void DeriveKeysErista() { /* Get work buffer. */ alignas(se::AesBlockSize) u8 work_buffer[se::AesBlockSize]; /* Get whether we're using dev keys. */ const bool is_prod = fuse::GetHardwareState() == fuse::HardwareState_Production; /* Derive Keyblob Key. */ se::DecryptAes128(work_buffer, se::AesBlockSize, pkg1::AesKeySlot_Tsec, KeyblobKeySource, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_Device, pkg1::AesKeySlot_SecureBoot, work_buffer, se::AesBlockSize); /* Derive Master Kek. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_MasterKek, is_prod ? pkg1::AesKeySlot_TsecRoot : pkg1::AesKeySlot_TsecRootDev, EristaMasterKekSource, se::AesBlockSize); /* Derive Master Key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderMaster, pkg1::AesKeySlot_MasterKek, MasterKeySource, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, MasterKeySource, se::AesBlockSize); /* Derive Device Master Key Source Kek, Device Key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMasterKeySourceKekErista, pkg1::AesKeySlot_Device, DeviceMasterKeySourceKekSource, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_Device, pkg1::AesKeySlot_Device, DeviceKeySource, se::AesBlockSize); /* Derive all master keys. */ DeriveMasterKeys(is_prod); /* Derive all device master keys. */ DeriveDeviceMasterKeys(fuse::SocType_Erista, is_prod); /* Derive system partition keys. */ DeriveBisPartitionSystemKeys(); } void DeriveKeysMariko() { /* Get whether we're using dev keys. */ const bool is_prod = fuse::GetHardwareState() == fuse::HardwareState_Production; /* Derive Device Master Key Source Kek, Master Key. */ se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMasterKeySourceKekErista, pkg1::AesKeySlot_SecureBoot, DeviceMasterKeySourceKekSource, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderMaster, pkg1::AesKeySlot_MarikoKek, is_prod ? MarikoMasterKekSource : MarikoMasterKekSourceDev, se::AesBlockSize); se::SetEncryptedAesKey128(pkg1::AesKeySlot_BootloaderMaster, pkg1::AesKeySlot_BootloaderMaster, MasterKeySource, se::AesBlockSize); /* Derive all master keys. */ DeriveMasterKeys(is_prod); /* Derive all device master keys. */ DeriveDeviceMasterKeys(fuse::SocType_Mariko, is_prod); /* Derive system partition keys. */ DeriveBisPartitionSystemKeys(); } int PrepareMasterKey(int generation) { if (generation == pkg1::KeyGeneration_Current) { return pkg1::AesKeySlot_BootloaderMaster; } se::SetAesKey(pkg1::AesKeySlot_BootloaderTemporary, MasterKeys[generation], se::AesBlockSize); return pkg1::AesKeySlot_BootloaderTemporary; } int PrepareDeviceMasterKey(int generation) { if (generation == pkg1::KeyGeneration_1_0_0) { return pkg1::AesKeySlot_Device; } if (generation == pkg1::KeyGeneration_Current) { return pkg1::AesKeySlot_BootloaderDeviceMaster; } const int index = std::max(0, generation - pkg1::KeyGeneration_4_0_0); se::SetAesKey(pkg1::AesKeySlot_BootloaderTemporary, DeviceMasterKeys[index], se::AesBlockSize); return pkg1::AesKeySlot_BootloaderTemporary; } } ================================================ FILE: fusee/program/source/fusee_key_derivation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { void DeriveKeysErista(); void DeriveKeysMariko(); int PrepareMasterKey(int generation); int PrepareDeviceMasterKey(int generation); } ================================================ FILE: fusee/program/source/fusee_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_display.hpp" #include "sein/fusee_secure_initialize.hpp" #include "sdram/fusee_sdram.hpp" #include "mtc/fusee_mtc.hpp" #include "fs/fusee_fs_api.hpp" #include "fusee_overlay_manager.hpp" #include "fusee_sd_card.hpp" #include "fusee_fatal.hpp" #include "fusee_external_package.hpp" #include "fusee_setup_horizon.hpp" #include "fusee_secmon_sync.hpp" namespace ams::nxboot { namespace { constexpr const char ExternalPackageFilePath[] = "sdmc:/atmosphere/package3"; constinit fs::FileHandle g_package_file; void OpenExternalPackage() { Result result; /* Open external package. */ if (R_FAILED((result = fs::OpenFile(std::addressof(g_package_file), ExternalPackageFilePath, fs::OpenMode_Read)))) { ShowFatalError("Failed to open %s!\n", ExternalPackageFilePath); } /* Get file size. */ s64 file_size; if (R_FAILED((result = fs::GetFileSize(std::addressof(file_size), g_package_file)))) { ShowFatalError("Failed to get package3 size: 0x%08" PRIx32 "\n", result.GetValue()); } /* Check file size. */ if (static_cast<size_t>(file_size) != ExternalPackageSize) { ShowFatalError("package3 seems corrupted (size 0x%zx != 0x%zx)", static_cast<size_t>(file_size), ExternalPackageSize); } } void ReadFullExternalPackage() { Result result; if (R_FAILED((result = fs::ReadFile(g_package_file, 0, const_cast<void *>(static_cast<const void *>(std::addressof(GetExternalPackage()))), ExternalPackageSize)))) { ShowFatalError("Failed to read %s!\n", ExternalPackageFilePath); } } void CloseExternalPackage() { fs::CloseFile(g_package_file); } } void Main() { /* Perform secure hardware initialization. */ SecureInitialize(true); /* Overclock the bpmp. */ clkrst::SetBpmpClockRate(fuse::GetSocType() == fuse::SocType_Mariko ? clkrst::BpmpClockRate_589MHz : clkrst::BpmpClockRate_576MHz); /* Initialize Sdram. */ InitializeSdram(); /* Initialize cache. */ hw::InitializeDataCache(); /* Initialize SD card. */ { Result result = InitializeSdCard(); if (R_FAILED(result)) { ShowFatalError("Failed to initialize the SD card: 0x%08" PRIx32 "\n", result.GetValue()); } } /* Mount SD card. */ if (!fs::MountSdCard()) { ShowFatalError("Failed to mount the SD card."); } /* If we have a fatal error, save and display it. */ SaveAndShowFatalError(); /* Open the external package. */ OpenExternalPackage(); /* Load the memory training overlay. */ LoadOverlay(g_package_file, OverlayId_MemoryTraining); /* Do memory training. */ DoMemoryTraining(); /* Read the rest of the archive file. */ ReadFullExternalPackage(); /* Save the memory training overlay. */ SaveMemoryTrainingOverlay(); /* Initialize display (splash screen will be visible from this point onwards). */ InitializeDisplay(); ShowDisplay(); /* Close the external package. */ CloseExternalPackage(); /* Perform rest of the boot process. */ SetupAndStartHorizon(); /* Restore the memory training overlay. */ RestoreMemoryTrainingOverlay(); /* Restore memory clock rate. */ RestoreMemoryClockRate(); /* Restore secure monitor code. */ RestoreSecureMonitorOverlay(); /* Finalize display. */ FinalizeDisplay(); /* Finalize sd card. */ FinalizeSdCard(); /* Finalize the data cache. */ hw::FinalizeDataCache(); /* Downclock the bpmp. */ clkrst::SetBpmpClockRate(clkrst::BpmpClockRate_408MHz); /* Signal to the secure monitor that we're done. */ SetBootloaderState(pkg1::BootloaderState_Done); /* Halt ourselves. */ while (true) { reg::Write(secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress() + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_JTAG, ENABLED)); } } } ================================================ FILE: fusee/program/source/fusee_malloc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_malloc.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { namespace { constinit uintptr_t g_heap_address = 0xC1000000; } void *AllocateMemory(size_t size) { /* Get the current heap address. */ void * const allocated = reinterpret_cast<void *>(g_heap_address); /* Advance the current heap address. */ g_heap_address += size; /* Return the allocated chunk. */ return allocated; } } ================================================ FILE: fusee/program/source/fusee_malloc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { void *AllocateMemory(size_t size); ALWAYS_INLINE void *AllocateAligned(size_t size, size_t align) { return reinterpret_cast<void *>(util::AlignUp(reinterpret_cast<uintptr_t>(AllocateMemory(size + align)), align)); } template<typename T, typename... Args> requires std::constructible_from<T, Args...> inline T *AllocateObject(Args &&... args) { T * const obj = static_cast<T *>(AllocateAligned(sizeof(T), alignof(T))); std::construct_at(obj, std::forward<Args>(args)...); return obj; } } ================================================ FILE: fusee/program/source/fusee_mmc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_mmc.hpp" namespace ams::nxboot { namespace { constexpr inline auto MmcPort = sdmmc::Port_Mmc0; alignas(0x10) constinit u8 g_mmc_work_buffer[sdmmc::MmcWorkBufferSize]; constinit inline auto g_mmc_partition = sdmmc::MmcPartition_Unknown; Result SelectMmcPartition(sdmmc::MmcPartition partition) { /* Change partition, if we need to. */ if (partition != g_mmc_partition) { R_TRY(sdmmc::SelectMmcPartition(MmcPort, partition)); g_mmc_partition = partition; } R_SUCCEED(); } } Result InitializeMmc() { /* Initialize the mmc. */ sdmmc::Initialize(MmcPort); /* Set the mmc work buffer. */ sdmmc::SetMmcWorkBuffer(MmcPort, g_mmc_work_buffer, sizeof(g_mmc_work_buffer)); /* Activate the mmc. */ R_RETURN(sdmmc::Activate(MmcPort)); } Result CheckMmcConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) { R_RETURN(sdmmc::CheckMmcConnection(out_sm, out_bw, MmcPort)); } Result GetMmcMemoryCapacity(u32 *out_num_sectors, sdmmc::MmcPartition partition) { if (partition == sdmmc::MmcPartition_UserData) { R_RETURN(sdmmc::GetDeviceMemoryCapacity(out_num_sectors, MmcPort)); } else { R_RETURN(sdmmc::GetMmcBootPartitionCapacity(out_num_sectors, MmcPort)); } } Result ReadMmc(void *dst, size_t size, sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count) { R_TRY(SelectMmcPartition(partition)); R_RETURN(sdmmc::Read(dst, size, MmcPort, sector_index, sector_count)); } Result WriteMmc(sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count, const void *src, size_t size) { R_TRY(SelectMmcPartition(partition)); R_RETURN(sdmmc::Write(MmcPort, sector_index, sector_count, src, size)); } } ================================================ FILE: fusee/program/source/fusee_mmc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { Result InitializeMmc(); Result CheckMmcConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw); Result GetMmcMemoryCapacity(u32 *out_num_sectors, sdmmc::MmcPartition partition); Result ReadMmc(void *dst, size_t size, sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count); Result WriteMmc(sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count, const void *src, size_t size); } ================================================ FILE: fusee/program/source/fusee_overlay_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_overlay_manager.hpp" #include "fusee_external_package.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { namespace { constinit u8 g_secmon_debug_storage[secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetSize()]; ALWAYS_INLINE void *GetOverlayDestination() { return reinterpret_cast<void *>(0x4002C000); } void LoadMemoryTrainingOverlay(fs::FileHandle archive_file) { Result result; u32 verif_hash; u32 store_hash; if (fuse::GetSocType() == fuse::SocType_Erista) { result = fs::ReadFile(archive_file, AMS_OFFSETOF(ExternalPackage, ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_erista)); verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-2]; store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_erista) / sizeof(u32)) - 1]; } else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { result = fs::ReadFile(archive_file, AMS_OFFSETOF(ExternalPackage, ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko)); verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-1]; store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_mariko) / sizeof(u32)) - 1]; } if (R_FAILED(result)) { ShowFatalError("Failed to load MTC overlay: 0x%08" PRIx32 "\n", result.GetValue()); } if (verif_hash != store_hash) { ShowFatalError("Incorrect fusee version! (program=0x%08" PRIx32 ", mtc=0x%08" PRIx32 ")\n", verif_hash, store_hash); } } } void LoadOverlay(fs::FileHandle archive_file, OverlayId ovl) { switch (ovl) { case OverlayId_MemoryTraining: LoadMemoryTrainingOverlay(archive_file); break; } } void SaveMemoryTrainingOverlay() { if (fuse::GetSocType() == fuse::SocType_Erista) { /* NOTE: Erista does not do memory clock restoration. */ /* std::memcpy(const_cast<u8 *>(GetExternalPackage().ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_erista)); */ } else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { std::memcpy(const_cast<u8 *>(GetExternalPackage().ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko) - 0x2000); } } void RestoreMemoryTrainingOverlay() { if (fuse::GetSocType() == fuse::SocType_Erista) { /* NOTE: Erista does not do memory clock restoration. */ /* std::memcpy(GetOverlayDestination(), GetExternalPackage().ovl_mtc_erista, sizeof(ExternalPackage{}.ovl_mtc_erista)); */ } else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { std::memcpy(g_secmon_debug_storage, secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetPointer<void>(), sizeof(g_secmon_debug_storage)); std::memcpy(GetOverlayDestination(), GetExternalPackage().ovl_mtc_mariko, sizeof(ExternalPackage{}.ovl_mtc_mariko) - 0x2000); } } void RestoreSecureMonitorOverlay() { if (fuse::GetSocType() == fuse::SocType_Erista) { /* NOTE: Erista does not do memory clock restoration. */ } else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { std::memcpy(secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetPointer<void>(), g_secmon_debug_storage, sizeof(g_secmon_debug_storage)); } } } ================================================ FILE: fusee/program/source/fusee_overlay_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "fs/fusee_fs_api.hpp" namespace ams::nxboot { enum OverlayId { /* OverlayId_SecureInitializer = 0, */ OverlayId_MemoryTraining = 1, }; void LoadOverlay(fs::FileHandle archive_file, OverlayId ovl); void SaveMemoryTrainingOverlay(); void RestoreMemoryTrainingOverlay(); void RestoreSecureMonitorOverlay(); } ================================================ FILE: fusee/program/source/fusee_package2.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_package2.hpp" #include "fusee_key_derivation.hpp" #include "fusee_fatal.hpp" namespace ams::nxboot { namespace { alignas(se::AesBlockSize) constexpr inline const u8 Package2KeySource[se::AesBlockSize] = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; void PreparePackage2Key(int pkg2_slot, int key_generation) { /* Get keyslot for the desired master key. */ const int master_slot = PrepareMasterKey(key_generation); /* Load the package2 key into the desired keyslot. */ se::SetEncryptedAesKey128(pkg2_slot, master_slot, Package2KeySource, sizeof(Package2KeySource)); } void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv, size_t iv_size, u8 key_generation) { /* Ensure that the SE sees consistent data. */ hw::FlushDataCache(src, src_size); if (src != dst) { hw::FlushDataCache(dst, dst_size); } /* Load the package2 key into the temporary keyslot. */ PreparePackage2Key(pkg1::AesKeySlot_Temporary, key_generation); /* Decrypt the data. */ se::ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Temporary, src, src_size, iv, iv_size); /* Clear the keyslot we just used. */ se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary); /* Ensure that the cpu sees consistent data. */ hw::InvalidateDataCache(dst, dst_size); } void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src) { constexpr int IvSize = 0x10; /* Decrypt the header. */ DecryptPackage2(dst, sizeof(*dst), std::addressof(src), sizeof(src), std::addressof(src), IvSize, src.GetKeyGeneration()); /* Copy back the iv, which encodes encrypted metadata. */ std::memcpy(dst, std::addressof(src), IvSize); } bool VerifyPackage2Meta(const pkg2::Package2Meta &meta) { /* Get the obfuscated metadata. */ const size_t size = meta.GetSize(); const u8 key_generation = meta.GetKeyGeneration(); /* Check that size is big enough for the header. */ if (size <= sizeof(pkg2::Package2Header)) { return false; } /* Check that the size isn't larger than what we allow. */ if (size > pkg2::Package2SizeMax) { return false; } /* Check that the key generation is one that we can use. */ static_assert(pkg1::KeyGeneration_Count == 21); if (key_generation >= pkg1::KeyGeneration_Count) { return false; } /* Check the magic number. */ if (!crypto::IsSameBytes(meta.magic, pkg2::Package2Meta::Magic::String, sizeof(meta.magic))) { return false; } /* Check the payload alignments. */ if ((meta.entrypoint % pkg2::PayloadAlignment) != 0) { return false; } for (int i = 0; i < pkg2::PayloadCount; ++i) { if ((meta.payload_sizes[i] % pkg2::PayloadAlignment) != 0) { return false; } } /* Check that the sizes sum to the total. */ if (size != sizeof(pkg2::Package2Header) + meta.payload_sizes[0] + meta.payload_sizes[1] + meta.payload_sizes[2]) { return false; } /* Check that the payloads do not overflow. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { if (meta.payload_offsets[i] > meta.payload_offsets[i] + meta.payload_sizes[i]) { return false; } } /* Verify that no payloads overlap. */ for (int i = 0; i < pkg2::PayloadCount - 1; ++i) { for (int j = i + 1; j < pkg2::PayloadCount; ++j) { if (util::HasOverlap(meta.payload_offsets[i], meta.payload_sizes[i], meta.payload_offsets[j], meta.payload_sizes[j])) { return false; } } } /* Check whether any payload contains the entrypoint. */ for (int i = 0; i < pkg2::PayloadCount; ++i) { if (util::Contains(meta.payload_offsets[i], meta.payload_sizes[i], meta.entrypoint)) { return true; } } /* No payload contains the entrypoint, so we're not valid. */ return false; } } void DecryptPackage2(u8 *package2) { /* Decrypt package2 header. */ pkg2::Package2Header *header = reinterpret_cast<pkg2::Package2Header *>(package2); { pkg2::Package2Header tmp = *header; DecryptPackage2Header(std::addressof(header->meta), tmp.meta); } /* Check package2 magic. */ if (!VerifyPackage2Meta(header->meta)) { ShowFatalError("Package2 meta is invalid!\n"); } /* Decrypt package2 payloads. */ u8 *payload = package2 + sizeof(*header); const u8 key_generation = header->meta.GetKeyGeneration(); for (int i = 0; i < pkg2::PayloadCount; ++i) { if (header->meta.payload_sizes[i] == 0) { continue; } DecryptPackage2(payload, header->meta.payload_sizes[i], payload, header->meta.payload_sizes[i], header->meta.payload_ivs[i], sizeof(header->meta.payload_ivs[i]), key_generation); payload += header->meta.payload_sizes[i]; } } } ================================================ FILE: fusee/program/source/fusee_package2.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { void DecryptPackage2(u8 *package2); } ================================================ FILE: fusee/program/source/fusee_print.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_display.hpp" #include "fusee_print.hpp" namespace ams::nxboot { namespace { #include "fusee_font.inc" constexpr inline const u32 TextColor = 0xFFA0A0A0; constexpr inline const size_t ConsoleWidth = FrameBufferWidth / FontWidth; constexpr inline const size_t ConsoleHeight = FrameBufferHeight / FontHeight; constinit u32 *g_frame_buffer = nullptr; constinit size_t g_col = 1; constinit size_t g_row = 0; void SetPixel(size_t x, size_t y, u32 color) { g_frame_buffer[(FrameBufferWidth - x) * FrameBufferHeight + y] = color; } void PutCarriageReturn() { g_col = 1; } void PutNewLine() { g_col = 1; ++g_row; /* TODO: Support scrolling? */ } void PutCharImpl(const char c) { /* Get the character data for the font. */ const u8 * cdata = FontData + c * (FontHeight * util::DivideUp(FontWidth, BITSIZEOF(u8))); /* Determine where to start drawing. */ const size_t x = g_col * FontWidth; const size_t y = g_row * FontHeight; for (size_t cur_y = 0; cur_y < FontHeight; ++cur_y) { size_t cur_x = 0; int wbits = FontWidth; while (wbits > 0) { const auto bits = *(cdata++); SetPixel(x + cur_x + 0, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][0] & TextColor); SetPixel(x + cur_x + 1, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][1] & TextColor); SetPixel(x + cur_x + 2, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][2] & TextColor); SetPixel(x + cur_x + 3, y + cur_y, FontDrawTable[(bits >> 4) & 0xF][3] & TextColor); SetPixel(x + cur_x + 4, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][0] & TextColor); SetPixel(x + cur_x + 5, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][1] & TextColor); SetPixel(x + cur_x + 6, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][2] & TextColor); SetPixel(x + cur_x + 7, y + cur_y, FontDrawTable[(bits >> 0) & 0xF][3] & TextColor); cur_x += BITSIZEOF(u8); wbits -= BITSIZEOF(u8); } } } void PutChar(const char c) { switch (c) { case '\r': PutCarriageReturn(); break; case '\n': PutNewLine(); break; default: PutCharImpl(c); if ((++g_col) >= ConsoleWidth) { PutNewLine(); } } } } void InitializeConsole(u32 *frame_buffer) { /* Setup the console variables. */ g_frame_buffer = frame_buffer; g_col = 1; g_row = 0; /* Clear the console. */ std::memset(g_frame_buffer, 0, FrameBufferSize); } void VPrint(const char *fmt, std::va_list vl) { /* Generate the string. */ char log_str[1_KB]; util::TVSNPrintf(log_str, sizeof(log_str), fmt, vl); /* Print each character. */ const size_t len = std::strlen(log_str); for (size_t i = 0; i < len; ++i) { PutChar(log_str[i]); } } void Print(const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); VPrint(fmt, vl); va_end(vl); } } ================================================ FILE: fusee/program/source/fusee_print.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { void InitializeConsole(u32 *frame_buffer); void Print(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void VPrint(const char *fmt, std::va_list vl); } ================================================ FILE: fusee/program/source/fusee_registers_di.hpp ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (C) 2018 CTCaer * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 #define SYNCPT_CNTRL_NO_STALL (1 << 8) #define SYNCPT_CNTRL_SOFT_RESET (1 << 0) #define DC_CMD_CONT_SYNCPT_VSYNC 0x28 #define SYNCPT_VSYNC_ENABLE (1 << 8) #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 #define DC_CMD_DISPLAY_COMMAND 0x32 #define DISP_CTRL_MODE_STOP (0 << 5) #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) #define DISP_CTRL_MODE_MASK (3 << 5) #define DC_CMD_DISPLAY_POWER_CONTROL 0x36 #define PW0_ENABLE (1 << 0) #define PW1_ENABLE (1 << 2) #define PW2_ENABLE (1 << 4) #define PW3_ENABLE (1 << 6) #define PW4_ENABLE (1 << 8) #define PM0_ENABLE (1 << 16) #define PM1_ENABLE (1 << 18) #define DC_CMD_INT_STATUS 0x37 #define DC_CMD_INT_MASK 0x38 #define DC_CMD_INT_ENABLE 0x39 #define DC_CMD_STATE_ACCESS 0x40 #define READ_MUX (1 << 0) #define WRITE_MUX (1 << 2) #define DC_CMD_STATE_CONTROL 0x41 #define GENERAL_ACT_REQ (1 << 0) #define WIN_A_ACT_REQ (1 << 1) #define WIN_B_ACT_REQ (1 << 2) #define WIN_C_ACT_REQ (1 << 3) #define CURSOR_ACT_REQ (1 << 7) #define GENERAL_UPDATE (1 << 8) #define WIN_A_UPDATE (1 << 9) #define WIN_B_UPDATE (1 << 10) #define WIN_C_UPDATE (1 << 11) #define CURSOR_UPDATE (1 << 15) #define NC_HOST_TRIG (1 << 24) #define DC_CMD_DISPLAY_WINDOW_HEADER 0x42 #define WINDOW_A_SELECT (1 << 4) #define WINDOW_B_SELECT (1 << 5) #define WINDOW_C_SELECT (1 << 6) #define DC_CMD_REG_ACT_CONTROL 0x043 #define DC_COM_CRC_CONTROL 0x300 #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) #define DC_COM_DSC_TOP_CTL 0x33E #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) #define DSI_ENABLE (1 << 29) #define SOR1_TIMING_CYA (1 << 27) #define SOR1_ENABLE (1 << 26) #define SOR_ENABLE (1 << 25) #define CURSOR_ENABLE (1 << 16) #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 #define DC_DISP_DISP_TIMING_OPTIONS 0x405 #define DC_DISP_REF_TO_SYNC 0x406 #define DC_DISP_SYNC_WIDTH 0x407 #define DC_DISP_BACK_PORCH 0x408 #define DC_DISP_ACTIVE 0x409 #define DC_DISP_FRONT_PORCH 0x40A #define DC_DISP_DISP_CLOCK_CONTROL 0x42E #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) #define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) #define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) #define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) #define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) #define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) #define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) #define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) #define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) #define DC_DISP_DISP_INTERFACE_CONTROL 0x42F #define DISP_DATA_FORMAT_DF1P1C (0 << 0) #define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) #define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) #define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) #define DISP_DATA_FORMAT_DF2S (4 << 0) #define DISP_DATA_FORMAT_DF3S (5 << 0) #define DISP_DATA_FORMAT_DFSPI (6 << 0) #define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) #define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) #define DISP_ALIGNMENT_MSB (0 << 8) #define DISP_ALIGNMENT_LSB (1 << 8) #define DISP_ORDER_RED_BLUE (0 << 9) #define DISP_ORDER_BLUE_RED (1 << 9) #define DC_DISP_DISP_COLOR_CONTROL 0x430 #define DITHER_CONTROL_MASK (3 << 8) #define DITHER_CONTROL_DISABLE (0 << 8) #define DITHER_CONTROL_ORDERED (2 << 8) #define DITHER_CONTROL_ERRDIFF (3 << 8) #define BASE_COLOR_SIZE_MASK (0xf << 0) #define BASE_COLOR_SIZE_666 (0 << 0) #define BASE_COLOR_SIZE_111 (1 << 0) #define BASE_COLOR_SIZE_222 (2 << 0) #define BASE_COLOR_SIZE_333 (3 << 0) #define BASE_COLOR_SIZE_444 (4 << 0) #define BASE_COLOR_SIZE_555 (5 << 0) #define BASE_COLOR_SIZE_565 (6 << 0) #define BASE_COLOR_SIZE_332 (7 << 0) #define BASE_COLOR_SIZE_888 (8 << 0) #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 #define SC1_H_QUALIFIER_NONE (1 << 16) #define SC0_H_QUALIFIER_NONE (1 << 0) #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 #define DE_SELECT_ACTIVE_BLANK (0 << 0) #define DE_SELECT_ACTIVE (1 << 0) #define DE_SELECT_ACTIVE_IS (2 << 0) #define DE_CONTROL_ONECLK (0 << 2) #define DE_CONTROL_NORMAL (1 << 2) #define DE_CONTROL_EARLY_EXT (2 << 2) #define DE_CONTROL_EARLY (3 << 2) #define DE_CONTROL_ACTIVE_BLANK (4 << 2) #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 #define DC_DISP_SD_BL_PARAMETERS 0x4D7 #define DC_DISP_SD_BL_CONTROL 0x4DC #define DC_DISP_BLEND_BACKGROUND_COLOR 0x4E4 #define DC_WIN_CSC_YOF 0x611 #define DC_WIN_CSC_KYRGB 0x612 #define DC_WIN_CSC_KUR 0x613 #define DC_WIN_CSC_KVR 0x614 #define DC_WIN_CSC_KUG 0x615 #define DC_WIN_CSC_KVG 0x616 #define DC_WIN_CSC_KUB 0x617 #define DC_WIN_CSC_KVB 0x618 #define DC_WIN_AD_WIN_OPTIONS 0xB80 #define DC_WIN_BD_WIN_OPTIONS 0xD80 #define DC_WIN_CD_WIN_OPTIONS 0xF80 // The following registers are A/B/C shadows of the 0xB80/0xD80/0xF80 registers (see DISPLAY_WINDOW_HEADER). #define DC_WIN_WIN_OPTIONS 0x700 #define H_DIRECTION (1 << 0) #define V_DIRECTION (1 << 2) #define SCAN_COLUMN (1 << 4) #define COLOR_EXPAND (1 << 6) #define CSC_ENABLE (1 << 18) #define WIN_ENABLE (1 << 30) #define DC_WIN_COLOR_DEPTH 0x703 #define WIN_COLOR_DEPTH_P1 0x0 #define WIN_COLOR_DEPTH_P2 0x1 #define WIN_COLOR_DEPTH_P4 0x2 #define WIN_COLOR_DEPTH_P8 0x3 #define WIN_COLOR_DEPTH_B4G4R4A4 0x4 #define WIN_COLOR_DEPTH_B5G5R5A 0x5 #define WIN_COLOR_DEPTH_B5G6R5 0x6 #define WIN_COLOR_DEPTH_AB5G5R5 0x7 #define WIN_COLOR_DEPTH_B8G8R8A8 0xC #define WIN_COLOR_DEPTH_R8G8B8A8 0xD #define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 0xE #define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 0xF #define WIN_COLOR_DEPTH_YCbCr422 0x10 #define WIN_COLOR_DEPTH_YUV422 0x11 #define WIN_COLOR_DEPTH_YCbCr420P 0x12 #define WIN_COLOR_DEPTH_YUV420P 0x13 #define WIN_COLOR_DEPTH_YCbCr422P 0x14 #define WIN_COLOR_DEPTH_YUV422P 0x15 #define WIN_COLOR_DEPTH_YCbCr422R 0x16 #define WIN_COLOR_DEPTH_YUV422R 0x17 #define WIN_COLOR_DEPTH_YCbCr422RA 0x18 #define WIN_COLOR_DEPTH_YUV422RA 0x19 #define DC_WIN_BUFFER_CONTROL 0x702 #define DC_WIN_POSITION 0x704 #define DC_WIN_SIZE 0x705 #define H_SIZE(x) (((x) & 0x1fff) << 0) #define V_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_PRESCALED_SIZE 0x706 #define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) #define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_H_INITIAL_DDA 0x707 #define DC_WIN_V_INITIAL_DDA 0x708 #define DC_WIN_DDA_INC 0x709 #define H_DDA_INC(x) (((x) & 0xffff) << 0) #define V_DDA_INC(x) (((x) & 0xffff) << 16) #define DC_WIN_LINE_STRIDE 0x70A #define LINE_STRIDE(x) (x) #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E // The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 #define DC_WINBUF_ADDR_V_OFFSET 0x808 #define DC_WINBUF_SURFACE_KIND 0x80B #define PITCH (0 << 0) #define TILED (1 << 0) #define BLOCK (2 << 0) #define BLOCK_HEIGHT(x) (((x) & 0x7) << 4) /*! Display serial interface registers. */ #define _DSIREG(reg) ((reg) * 4) #define DSI_INCR_SYNCPT_CNTRL 0x1 #define DSI_RD_DATA 0x9 #define DSI_WR_DATA 0xA #define DSI_POWER_CONTROL 0xB #define DSI_POWER_CONTROL_ENABLE 1 #define DSI_INT_ENABLE 0xC #define DSI_INT_STATUS 0xD #define DSI_INT_MASK 0xE #define DSI_HOST_CONTROL 0xF #define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) #define DSI_HOST_CONTROL_CRC_RESET (1 << 20) #define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) #define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) #define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) #define DSI_HOST_CONTROL_RAW (1 << 6) #define DSI_HOST_CONTROL_HS (1 << 5) #define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) #define DSI_HOST_CONTROL_IMM_BTA (1 << 3) #define DSI_HOST_CONTROL_PKT_BTA (1 << 2) #define DSI_HOST_CONTROL_CS (1 << 1) #define DSI_HOST_CONTROL_ECC (1 << 0) #define DSI_CONTROL 0x10 #define DSI_CONTROL_HS_CLK_CTRL (1 << 20) #define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) #define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) #define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) #define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) #define DSI_CONTROL_DCS_ENABLE (1 << 3) #define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) #define DSI_CONTROL_VIDEO_ENABLE (1 << 1) #define DSI_CONTROL_HOST_ENABLE (1 << 0) #define DSI_SOL_DELAY 0x11 #define DSI_MAX_THRESHOLD 0x12 #define DSI_TRIGGER 0x13 #define DSI_TRIGGER_HOST (1 << 1) #define DSI_TRIGGER_VIDEO (1 << 0) #define DSI_TX_CRC 0x14 #define DSI_STATUS 0x15 #define DSI_INIT_SEQ_CONTROL 0x1A #define DSI_INIT_SEQ_DATA_0 0x1B #define DSI_INIT_SEQ_DATA_1 0x1C #define DSI_INIT_SEQ_DATA_2 0x1D #define DSI_INIT_SEQ_DATA_3 0x1E #define DSI_PKT_SEQ_0_LO 0x23 #define DSI_PKT_SEQ_0_HI 0x24 #define DSI_PKT_SEQ_1_LO 0x25 #define DSI_PKT_SEQ_1_HI 0x26 #define DSI_PKT_SEQ_2_LO 0x27 #define DSI_PKT_SEQ_2_HI 0x28 #define DSI_PKT_SEQ_3_LO 0x29 #define DSI_PKT_SEQ_3_HI 0x2A #define DSI_PKT_SEQ_4_LO 0x2B #define DSI_PKT_SEQ_4_HI 0x2C #define DSI_PKT_SEQ_5_LO 0x2D #define DSI_PKT_SEQ_5_HI 0x2E #define DSI_DCS_CMDS 0x33 #define DSI_PKT_LEN_0_1 0x34 #define DSI_PKT_LEN_2_3 0x35 #define DSI_PKT_LEN_4_5 0x36 #define DSI_PKT_LEN_6_7 0x37 #define DSI_PHY_TIMING_0 0x3C #define DSI_PHY_TIMING_1 0x3D #define DSI_PHY_TIMING_2 0x3E #define DSI_BTA_TIMING 0x3F #define DSI_TIMEOUT_0 0x44 #define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) #define DSI_TIMEOUT_1 0x45 #define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) #define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) #define DSI_TO_TALLY 0x46 #define DSI_PAD_CONTROL_0 0x4B #define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) #define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) #define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) #define DSI_PAD_CONTROL_CD 0x4c #define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_PAD_CONTROL_1 0x4F #define DSI_PAD_CONTROL_2 0x50 #define DSI_PAD_CONTROL_3 0x51 #define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12) #define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8) #define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) #define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) #define DSI_PAD_CONTROL_4 0x52 #define DSI_PAD_CONTROL_5_MARIKO 0x53 #define DSI_PAD_CONTROL_6_MARIKO 0x54 #define DSI_PAD_CONTROL_7_MARIKO 0x55 #define DSI_INIT_SEQ_DATA_15 0x5F #define DSI_INIT_SEQ_DATA_15_MARIKO 0x62 #define NV_PVIC_THI_SLCG_OVERRIDE_LOW_A 0x8C ================================================ FILE: fusee/program/source/fusee_sd_card.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_sd_card.hpp" namespace ams::nxboot { namespace { constexpr inline auto SdCardPort = sdmmc::Port_SdCard0; constexpr inline const uintptr_t APB = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); alignas(0x10) constinit u8 g_sd_work_buffer[sdmmc::SdCardWorkBufferSize]; void ConfigureInitialSdCardPinmux() { /* Normally, these pints get configured by boot sysmodule during initial pinmux config. */ /* However, they're required to access the SD card, so we must do them ahead of time. */ reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_CLK, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CLK_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_CMD, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_CMD_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_DAT3, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT3_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_DAT2, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT2_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_DAT1, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT1_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_SDMMC1_DAT0, PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, SDMMC1)); reg::ReadWrite(APB + PINMUX_AUX_DMIC3_CLK, PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_SDMMC1_DAT0_PM, RSVD2)); } } Result InitializeSdCard() { /* Perform initial pinmux config to enable sd card access. */ ConfigureInitialSdCardPinmux(); /* Initialize the SD card. */ sdmmc::Initialize(SdCardPort); /* Set the SD card work buffer. */ sdmmc::SetSdCardWorkBuffer(SdCardPort, g_sd_work_buffer, sizeof(g_sd_work_buffer)); /* Activate the SD card. */ R_RETURN(sdmmc::Activate(SdCardPort)); } void FinalizeSdCard() { /* Deactivate the SD card. */ sdmmc::Deactivate(SdCardPort); /* Finalize the SD card. */ sdmmc::Finalize(SdCardPort); } Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) { R_RETURN(sdmmc::CheckSdCardConnection(out_sm, out_bw, SdCardPort)); } Result GetSdCardMemoryCapacity(u32 *out_num_sectors) { R_RETURN(sdmmc::GetDeviceMemoryCapacity(out_num_sectors, SdCardPort)); } Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) { R_RETURN(sdmmc::Read(dst, size, SdCardPort, sector_index, sector_count)); } Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) { R_RETURN(sdmmc::Write(SdCardPort, sector_index, sector_count, src, size)); } } ================================================ FILE: fusee/program/source/fusee_sd_card.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { Result InitializeSdCard(); Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw); Result GetSdCardMemoryCapacity(u32 *out_num_sectors); Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count); Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size); void FinalizeSdCard(); } ================================================ FILE: fusee/program/source/fusee_secmon_sync.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_secmon_sync.hpp" namespace ams::nxboot { namespace { ALWAYS_INLINE pkg1::SecureMonitorParameters &GetSecureMonitorParameters() { return *secmon::MemoryRegionPhysicalDeviceBootloaderParams.GetPointer<pkg1::SecureMonitorParameters>(); } } void InitializeSecureMonitorMailbox() { std::memset(std::addressof(GetSecureMonitorParameters()), 0, sizeof(GetSecureMonitorParameters())); } void WaitSecureMonitorState(pkg1::SecureMonitorState state) { auto &secmon_params = GetSecureMonitorParameters(); while (secmon_params.secmon_state != state) { hw::InvalidateDataCache(std::addressof(secmon_params.secmon_state), sizeof(secmon_params.secmon_state)); util::WaitMicroSeconds(1); } } void SetBootloaderState(pkg1::BootloaderState state) { auto &secmon_params = GetSecureMonitorParameters(); secmon_params.bootloader_state = state; hw::FlushDataCache(std::addressof(secmon_params.bootloader_state), sizeof(secmon_params.bootloader_state)); } } ================================================ FILE: fusee/program/source/fusee_secmon_sync.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot { void InitializeSecureMonitorMailbox(); void WaitSecureMonitorState(pkg1::SecureMonitorState state); void SetBootloaderState(pkg1::BootloaderState state); } ================================================ FILE: fusee/program/source/fusee_setup_horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include <exosphere/secmon/secmon_monitor_context.hpp> #include "fusee_key_derivation.hpp" #include "fusee_external_package.hpp" #include "fusee_setup_horizon.hpp" #include "fusee_ini.hpp" #include "fusee_emummc.hpp" #include "fusee_mmc.hpp" #include "fusee_cpu.hpp" #include "fusee_fatal.hpp" #include "fusee_package2.hpp" #include "fusee_malloc.hpp" #include "fusee_secmon_sync.hpp" #include "fusee_stratosphere.hpp" #include "fs/fusee_fs_api.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); constinit secmon::EmummcConfiguration g_emummc_cfg = {}; void DeriveAllKeys(const fuse::SocType soc_type) { /* If on erista, run the TSEC keygen firmware. */ if (soc_type == fuse::SocType_Erista) { clkrst::SetBpmpClockRate(clkrst::BpmpClockRate_408MHz); if (!tsec::RunTsecFirmware(GetExternalPackage().tsec_keygen, sizeof(GetExternalPackage().tsec_keygen))) { ShowFatalError("Failed to run tsec_keygen firmware!\n"); } clkrst::SetBpmpClockRate(clkrst::BpmpClockRate_576MHz); } /* Derive master/device keys. */ if (soc_type == fuse::SocType_Erista) { DeriveKeysErista(); } else /* if (soc_type == fuse::SocType_Mariko) */ { DeriveKeysMariko(); } } bool ParseIniSafe(IniSectionList &out_sections, const char *ini_path) { const auto result = ParseIniFile(out_sections, ini_path); if (result == ParseIniResult_Success) { return true; } else if (result == ParseIniResult_NoFile) { return false; } else { ShowFatalError("Failed to parse %s!\n", ini_path); } } u32 ParseHexInteger(const char *s) { u32 x = 0; if (s[0] == '0' && s[1] == 'x') { s += 2; } while (true) { const char c = *(s++); if (c == '\x00') { return x; } else { x <<= 4; if ('0' <= c && c <= '9') { x |= (c - '0'); } else if ('a' <= c && c <= 'f') { x |= (c - 'a') + 10; } else if ('A' <= c && c <= 'F') { x |= (c - 'A') + 10; } } } } u32 ParseDecimalInteger(const char *s) { u32 x = 0; while (true) { const char c = *(s++); if (c == '\x00') { return x; } else { x *= 10; if ('0' <= c && c <= '9') { x += c - '0'; } } } } bool IsDirectoryExist(const char *path) { fs::DirectoryEntryType entry_type; bool archive; return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory; } bool IsFileExist(const char *path) { fs::DirectoryEntryType entry_type; bool archive; return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_File; } bool ConfigureEmummc() { /* Set magic. */ g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic; /* Parse ini. */ bool enabled = false; u32 id = 0; u32 sector = 0; const char *path = ""; const char *n_path = ""; { IniSectionList sections; if (ParseIniSafe(sections, "sdmc:/emummc/emummc.ini")) { for (const auto §ion : sections) { /* We only care about the [emummc] section. */ if (std::strcmp(section.name, "emummc")) { continue; } /* Handle individual fields. */ for (const auto &entry : section.kv_list) { if (std::strcmp(entry.key, "enabled") == 0) { enabled = entry.value[0] != '0'; } else if (std::strcmp(entry.key, "id") == 0) { id = ParseHexInteger(entry.value); } else if (std::strcmp(entry.key, "sector") == 0) { sector = ParseHexInteger(entry.value); } else if (std::strcmp(entry.key, "path") == 0) { path = entry.value; } else if (std::strcmp(entry.key, "nintendo_path") == 0) { n_path = entry.value; } } } } } /* Set values parsed from config. */ g_emummc_cfg.base_cfg.id = id; std::strncpy(g_emummc_cfg.emu_dir_path.str, n_path, sizeof(g_emummc_cfg.emu_dir_path.str)); g_emummc_cfg.emu_dir_path.str[sizeof(g_emummc_cfg.emu_dir_path.str) - 1] = '\x00'; if (enabled) { if (sector > 0) { g_emummc_cfg.base_cfg.type = secmon::EmummcType_Partition; g_emummc_cfg.partition_cfg.start_sector = sector; } else if (path[0] != '\x00' && IsDirectoryExist(path)) { g_emummc_cfg.base_cfg.type = secmon::EmummcType_File; std::strncpy(g_emummc_cfg.file_cfg.path.str, path, sizeof(g_emummc_cfg.file_cfg.path.str)); g_emummc_cfg.file_cfg.path.str[sizeof(g_emummc_cfg.file_cfg.path.str) - 1] = '\x00'; } else { ShowFatalError("Invalid emummc setting!\n"); } } return enabled; } u8 *LoadPackage1(fuse::SocType soc_type) { u8 *package1 = static_cast<u8 *>(AllocateAligned(0x40000, 0x1000)); const Result result = ReadBoot0(0x100000, package1, 0x40000); if (R_FAILED(result)) { ShowFatalError("Failed to read boot0: 0x%08" PRIx32 "!\n", result.GetValue()); } if (soc_type == fuse::SocType_Mariko) { package1 += 0x170; se::DecryptAes128Cbc(package1 + 0x20, 0x40000 - (0x20 + 0x170), pkg1::AesKeySlot_MarikoBek, package1 + 0x20, 0x40000 - (0x20 + 0x170), package1 + 0x10, se::AesBlockSize); hw::InvalidateDataCache(package1 + 0x20, 0x40000 - (0x20 + 0x170)); if (std::memcmp(package1, package1 + 0x20, 0x20) != 0) { ShowFatalError("Package1 seems corrupt!\n"); } } return package1; } ams::TargetFirmware GetApproximateTargetFirmware(const u8 *package1) { /* Get an approximation of the target firmware. */ switch (package1[0x1F]) { case 0x01: return ams::TargetFirmware_1_0_0; case 0x02: return ams::TargetFirmware_2_0_0; case 0x04: return ams::TargetFirmware_3_0_0; case 0x07: return ams::TargetFirmware_4_0_0; case 0x0B: return ams::TargetFirmware_5_0_0; case 0x0E: if (std::memcmp(package1 + 0x10, "20180802", 8) == 0) { return ams::TargetFirmware_6_0_0; } else if (std::memcmp(package1 + 0x10, "20181107", 8) == 0) { return ams::TargetFirmware_6_2_0; } break; case 0x0F: return ams::TargetFirmware_7_0_0; case 0x10: if (std::memcmp(package1 + 0x10, "20190314", 8) == 0) { return ams::TargetFirmware_8_0_0; } else if (std::memcmp(package1 + 0x10, "20190531", 8) == 0) { return ams::TargetFirmware_8_1_0; } else if (std::memcmp(package1 + 0x10, "20190809", 8) == 0) { return ams::TargetFirmware_9_0_0; } else if (std::memcmp(package1 + 0x10, "20191021", 8) == 0) { return ams::TargetFirmware_9_1_0; } else if (std::memcmp(package1 + 0x10, "20200303", 8) == 0) { return ams::TargetFirmware_10_0_0; } else if (std::memcmp(package1 + 0x10, "20201030", 8) == 0) { return ams::TargetFirmware_11_0_0; } else if (std::memcmp(package1 + 0x10, "20210129", 8) == 0) { return ams::TargetFirmware_12_0_0; } else if (std::memcmp(package1 + 0x10, "20210422", 8) == 0) { return ams::TargetFirmware_12_0_2; } else if (std::memcmp(package1 + 0x10, "20210607", 8) == 0) { return ams::TargetFirmware_12_1_0; } else if (std::memcmp(package1 + 0x10, "20210805", 8) == 0) { return ams::TargetFirmware_13_0_0; } else if (std::memcmp(package1 + 0x10, "20220105", 8) == 0) { return ams::TargetFirmware_13_2_1; } else if (std::memcmp(package1 + 0x10, "20220209", 8) == 0) { return ams::TargetFirmware_14_0_0; } else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) { return ams::TargetFirmware_15_0_0; } else if (std::memcmp(package1 + 0x10, "20230111", 8) == 0) { return ams::TargetFirmware_16_0_0; } else if (std::memcmp(package1 + 0x10, "20230906", 8) == 0) { return ams::TargetFirmware_17_0_0; } else if (std::memcmp(package1 + 0x10, "20240207", 8) == 0) { return ams::TargetFirmware_18_0_0; } else if (std::memcmp(package1 + 0x10, "20240808", 8) == 0) { return ams::TargetFirmware_19_0_0; } else if (std::memcmp(package1 + 0x10, "20250206", 8) == 0) { return ams::TargetFirmware_20_0_0; } else if (std::memcmp(package1 + 0x10, "20251009", 8) == 0) { return ams::TargetFirmware_21_0_0; } break; default: break; } ShowFatalError("Unable to identify package1!\n"); } u8 *LoadBootConfigAndPackage2() { Result result; /* Load boot config. */ if (R_FAILED((result = ReadPackage2(0, secmon::MemoryRegionPhysicalIramBootConfig.GetPointer<void>(), secmon::MemoryRegionPhysicalIramBootConfig.GetSize())))) { ShowFatalError("Failed to read boot config: 0x%08" PRIx32 "!\n", result.GetValue()); } /* Read package2 header. */ u8 *package2; size_t package2_size; { constexpr s64 Package2Offset = AMS_OFFSETOF(pkg2::StorageLayout, package2_header); pkg2::Package2Header header; if (R_FAILED((result = ReadPackage2(Package2Offset, std::addressof(header), sizeof(header))))) { ShowFatalError("Failed to read package2 header: 0x%08" PRIx32 "!\n", result.GetValue()); } package2_size = header.meta.GetSize(); package2 = static_cast<u8 *>(AllocateAligned(util::AlignUp(package2_size, 0x4000), 0x4000)); if (R_FAILED((result = ReadPackage2(Package2Offset, package2, util::AlignUp(package2_size, 0x4000))))) { ShowFatalError("Failed to read package2: 0x%08" PRIx32 "!\n", result.GetValue()); } } /* Decrypt package2. */ DecryptPackage2(package2); return package2; } constexpr inline const u8 PkcModulusErista[0x100] = { 0xF7, 0x86, 0x47, 0xAB, 0x71, 0x89, 0x81, 0xB5, 0xCF, 0x0C, 0xB0, 0xE8, 0x48, 0xA7, 0xFD, 0xAD, 0xCB, 0x4E, 0x4A, 0x52, 0x0B, 0x1A, 0x8E, 0xDE, 0x41, 0x87, 0x6F, 0xB7, 0x31, 0x05, 0x5F, 0xAA, 0xEA, 0x97, 0x76, 0x21, 0x20, 0x2B, 0x40, 0x48, 0x76, 0x55, 0x35, 0x03, 0xFE, 0x7F, 0x67, 0x62, 0xFD, 0x4E, 0xE1, 0x22, 0xF8, 0xF0, 0x97, 0x39, 0xEF, 0xEA, 0x47, 0x89, 0x3C, 0xDB, 0xF0, 0x02, 0xAD, 0x0C, 0x96, 0xCA, 0x82, 0xAB, 0xB3, 0xCB, 0x98, 0xC8, 0xDC, 0xC6, 0xAC, 0x5C, 0x93, 0x3B, 0x84, 0x3D, 0x51, 0x91, 0x9E, 0xC1, 0x29, 0x22, 0x95, 0xF0, 0xA1, 0x51, 0xBA, 0xAF, 0x5D, 0xC3, 0xAB, 0x04, 0x1B, 0x43, 0x61, 0x7D, 0xEA, 0x65, 0x95, 0x24, 0x3C, 0x51, 0x3E, 0x8F, 0xDB, 0xDB, 0xC1, 0xC4, 0x2D, 0x04, 0x29, 0x5A, 0xD7, 0x34, 0x6B, 0xCC, 0xF1, 0x06, 0xF9, 0xC9, 0xE1, 0xF9, 0x61, 0x52, 0xE2, 0x05, 0x51, 0xB1, 0x3D, 0x88, 0xF9, 0xA9, 0x27, 0xA5, 0x6F, 0x4D, 0xE7, 0x22, 0x48, 0xA5, 0xF8, 0x12, 0xA2, 0xC2, 0x5A, 0xA0, 0xBF, 0xC8, 0x76, 0x4B, 0x66, 0xFE, 0x1C, 0x73, 0x00, 0x29, 0x26, 0xCD, 0x18, 0x4F, 0xC2, 0xB0, 0x51, 0x77, 0x2E, 0x91, 0x09, 0x1B, 0x41, 0x5D, 0x89, 0x5E, 0xEE, 0x24, 0x22, 0x47, 0xE5, 0xE5, 0xF1, 0x86, 0x99, 0x67, 0x08, 0x28, 0x42, 0xF0, 0x58, 0x62, 0x54, 0xC6, 0x5B, 0xDC, 0xE6, 0x80, 0x85, 0x6F, 0xE2, 0x72, 0xB9, 0x7E, 0x36, 0x64, 0x48, 0x85, 0x10, 0xA4, 0x75, 0x38, 0x79, 0x76, 0x8B, 0x51, 0xD5, 0x87, 0xC3, 0x02, 0xC9, 0x1B, 0x93, 0x22, 0x49, 0xEA, 0xAB, 0xA0, 0xB5, 0xB1, 0x3C, 0x10, 0xC4, 0x71, 0xF0, 0xF1, 0x81, 0x1A, 0x3A, 0x9C, 0xFC, 0x51, 0x61, 0xB1, 0x4B, 0x18, 0xB2, 0x3D, 0xAA, 0xD6, 0xAC, 0x72, 0x26, 0xB7 }; constexpr inline const u8 PkcModulusDevelopmentErista[0x100] = { 0x37, 0x84, 0x14, 0xB3, 0x78, 0xA4, 0x7F, 0xD8, 0x71, 0x45, 0xCD, 0x90, 0x51, 0x51, 0xBF, 0x2C, 0x27, 0x03, 0x30, 0x46, 0xBE, 0x8F, 0x99, 0x3E, 0x9F, 0x36, 0x4D, 0xEB, 0xF7, 0x0E, 0x81, 0x7F, 0xE4, 0x6B, 0xA8, 0x42, 0x8A, 0xA5, 0x4F, 0x76, 0xCC, 0xCB, 0xC5, 0x31, 0xA8, 0x5A, 0x70, 0x51, 0x34, 0xBF, 0x1E, 0x8D, 0x6E, 0xCF, 0x05, 0x84, 0xCF, 0x8B, 0xE5, 0x9C, 0x3A, 0xA5, 0xCD, 0x1A, 0x9C, 0xAC, 0x59, 0x30, 0x09, 0x21, 0x3C, 0xBE, 0x07, 0x5C, 0x8D, 0x1C, 0xD1, 0xA3, 0xC9, 0x8F, 0x26, 0xE2, 0x99, 0xB2, 0x3C, 0x28, 0xAD, 0x63, 0x0F, 0xF5, 0xA0, 0x1C, 0xA2, 0x34, 0xC4, 0x0E, 0xDB, 0xD7, 0xE1, 0xA9, 0x5E, 0xE9, 0xA5, 0xA8, 0x64, 0x3A, 0xFC, 0x48, 0xB5, 0x97, 0xDF, 0x55, 0x7C, 0x9A, 0xD2, 0x8C, 0x32, 0x36, 0x1D, 0xC5, 0xA0, 0xC5, 0x66, 0xDF, 0x8A, 0xAD, 0x76, 0x18, 0x46, 0x3E, 0xDF, 0xD8, 0xEF, 0xB9, 0xE5, 0xDC, 0xCD, 0x08, 0x59, 0xBC, 0x36, 0x68, 0xD6, 0xFC, 0x3F, 0xFA, 0x11, 0x00, 0x0D, 0x50, 0xE0, 0x69, 0x0F, 0x70, 0x78, 0x7E, 0xD1, 0xA5, 0x85, 0xCD, 0x13, 0xBC, 0x42, 0x74, 0x33, 0x0C, 0x11, 0x24, 0x1E, 0x33, 0xD5, 0x31, 0xB7, 0x3E, 0x48, 0x94, 0xCC, 0x81, 0x29, 0x1E, 0xB1, 0xCF, 0x4C, 0x36, 0x7F, 0xE1, 0x1C, 0x15, 0xD4, 0x3F, 0xFB, 0x12, 0xC2, 0x73, 0x22, 0x16, 0x52, 0xE0, 0x5C, 0x4C, 0x94, 0xE0, 0x87, 0x47, 0xEA, 0xD0, 0x9F, 0x42, 0x9B, 0xAC, 0xB6, 0xB5, 0xB6, 0x34, 0xE4, 0x55, 0x49, 0xD7, 0xC0, 0xAE, 0xD4, 0x22, 0xB3, 0x5C, 0x87, 0x64, 0x42, 0xEC, 0x11, 0x6D, 0xBC, 0x09, 0xC0, 0x80, 0x07, 0xD0, 0xBD, 0xBA, 0x45, 0xFE, 0xD5, 0x52, 0xDA, 0xEC, 0x41, 0xA4, 0xAD, 0x7B, 0x36, 0x86, 0x18, 0xB4, 0x5B, 0xD1, 0x30, 0xBB }; void LoadWarmbootFirmware(fuse::SocType soc_type, ams::TargetFirmware target_firmware, const u8 *package1) { u8 *warmboot_dst = secmon::MemoryRegionPhysicalIramWarmbootBin.GetPointer<u8>(); size_t warmboot_size = std::min(sizeof(GetExternalPackage().warmboot), secmon::MemoryRegionPhysicalIramWarmbootBin.GetSize()); if (soc_type == fuse::SocType_Erista) { /* Copy the ams warmboot binary. */ std::memcpy(warmboot_dst, GetExternalPackage().warmboot, warmboot_size); /* Set the rsa modulus. */ if (fuse::GetHardwareState() == fuse::HardwareState_Production) { std::memcpy(warmboot_dst + 0x10, PkcModulusErista, sizeof(PkcModulusErista)); } else { std::memcpy(warmboot_dst + 0x10, PkcModulusDevelopmentErista, sizeof(PkcModulusDevelopmentErista)); } /* Set the target firmware. */ std::memcpy(warmboot_dst + 0x248, std::addressof(target_firmware), sizeof(target_firmware)); } else /* if (soc_type == fuse::SocType_Mariko) */ { /* Declare path for mariko warmboot files. */ char warmboot_path[0x80] = "sdmc:/warmboot_mariko/wb_xx.bin"; auto UpdateWarmbootPath = [&warmboot_path](u8 fuses) { warmboot_path[0x19] = "0123456789abcdef"[(fuses >> 4) & 0xF]; warmboot_path[0x1A] = "0123456789abcdef"[(fuses >> 0) & 0xF]; }; /* Get expected/burnt fuse counts. */ const u32 expected_fuses = fuse::GetExpectedFuseVersion(target_firmware); const u32 burnt_fuses = fuse::GetFuseVersion(); u32 used_fuses = expected_fuses; /* Get warmboot from package1. */ const u8 *warmboot_src = nullptr; size_t warmboot_src_size = 0; { const u32 *package1_pk11 = reinterpret_cast<const u32 *>(package1 + (target_firmware >= ams::TargetFirmware_6_2_0 ? 0x7000 : 0x4000)); if (std::memcmp(package1_pk11, "PK11", 4) != 0) { ShowFatalError("Invalid package1 magic!\n"); } const u32 *package1_pk11_data = reinterpret_cast<const u32 *>(package1_pk11 + (0x20 / sizeof(u32))); for (size_t i = 0; i < 3; ++i) { switch (*package1_pk11_data) { case 0xD5034FDF: package1_pk11_data += package1_pk11[6] / sizeof(u32); break; case 0xE328F0C0: case 0xF0C0A7F0: package1_pk11_data += package1_pk11[4] / sizeof(u32); break; default: warmboot_src = reinterpret_cast<const u8 *>(package1_pk11_data); i = 3; break; } } warmboot_src_size = *package1_pk11_data; if (!(0x800 <= warmboot_src_size && warmboot_src_size < 0x1000)) { ShowFatalError("Package1 warmboot firmware seems invalid!\n"); } /* If we should, save the current warmboot firmware. */ UpdateWarmbootPath(expected_fuses); if (!IsFileExist(warmboot_path)) { /* Try to create the directory/file, allowing them to fail (if already exist). */ static_cast<void>(fs::CreateDirectory("sdmc:/warmboot_mariko")); static_cast<void>(fs::CreateFile(warmboot_path, warmboot_src_size)); Result result; fs::FileHandle file; if (R_FAILED((result = fs::OpenFile(std::addressof(file), warmboot_path, fs::OpenMode_ReadWrite)))) { ShowFatalError("Failed to save %s!\n", warmboot_path); } ON_SCOPE_EXIT { fs::CloseFile(file); }; if (R_FAILED((result = fs::WriteFile(file, 0, warmboot_src, warmboot_src_size, fs::WriteOption::Flush)))) { ShowFatalError("Failed to save %s!\n", warmboot_path); } } /* If we need to, find a cached warmboot firmware that we can use. */ if (burnt_fuses > expected_fuses) { warmboot_src = nullptr; warmboot_src_size = 0; for (u32 attempt = burnt_fuses; attempt <= 32; ++attempt) { /* Open the current cache file. */ UpdateWarmbootPath(attempt); fs::FileHandle file; if (R_FAILED(fs::OpenFile(std::addressof(file), warmboot_path, fs::OpenMode_Read))) { continue; } ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Get the size. */ s64 size; if (R_FAILED(fs::GetFileSize(std::addressof(size), file)) || !(0x800 <= size && size < 0x1000)) { continue; } /* Allocate memory. */ warmboot_src_size = static_cast<size_t>(size); void *tmp = AllocateAligned(warmboot_src_size, 0x10); /* Read the file. */ if (R_FAILED(fs::ReadFile(file, 0, tmp, warmboot_src_size))) { continue; } /* Use the cached file. */ used_fuses = attempt; warmboot_src = static_cast<const u8 *>(tmp); break; } } /* Check that we found a firmware. */ if (warmboot_src == nullptr) { ShowFatalError("Failed to locate warmboot firmware!\n"); } /* Copy the warmboot firmware. */ std::memcpy(warmboot_dst, warmboot_src, std::min(warmboot_size, warmboot_src_size)); /* Set the warmboot firmware magic. */ switch (used_fuses) { case 7: reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH32, 0x87); case 8: reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH32, 0xA8); default: reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH32, (0x108 + 0x21 * (used_fuses - 8))); break; } reg::SetBits(PMC + APBDEV_PMC_SEC_DISABLE3, (1 << 16)); } } } void ConfigureExosphere(fuse::SocType soc_type, ams::TargetFirmware target_firmware, bool emummc_enabled, u32 fs_version) { /* Get monitor configuration. */ auto &storage_ctx = *secmon::MemoryRegionPhysicalDramMonitorConfiguration.GetPointer<secmon::SecureMonitorStorageConfiguration>(); std::memset(std::addressof(storage_ctx), 0, sizeof(storage_ctx)); /* Set magic. */ storage_ctx.magic = secmon::SecureMonitorStorageConfiguration::Magic; /* Set some defaults. */ storage_ctx.target_firmware = target_firmware; storage_ctx.lcd_vendor = GetDisplayLcdVendor(); storage_ctx.emummc_cfg = g_emummc_cfg; storage_ctx.flags[0] = secmon::SecureMonitorConfigurationFlag_Default; storage_ctx.flags[1] = secmon::SecureMonitorConfigurationFlag_None; storage_ctx.log_port = uart::Port_ReservedDebug; storage_ctx.log_baud_rate = 115200; /* Set the fs version. */ storage_ctx.emummc_cfg.base_cfg.fs_version = fs_version; /* Parse fields from exosphere.ini */ { IniSectionList sections; if (ParseIniSafe(sections, "sdmc:/exosphere.ini")) { for (const auto §ion : sections) { /* We only care about the [exosphere] section. */ if (std::strcmp(section.name, "exosphere")) { continue; } /* Handle individual fields. */ for (const auto &entry : section.kv_list) { if (std::strcmp(entry.key, "debugmode") == 0) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel; } } else if (std::strcmp(entry.key, "debugmode_user") == 0) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser; } } else if (std::strcmp(entry.key, "disable_user_exception_handlers") == 0) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers; } } else if (std::strcmp(entry.key, "enable_user_pmu_access") == 0) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess; } } else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) { if (!emummc_enabled) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; } } } else if (std::strcmp(entry.key, "blank_prodinfo_emummc") == 0) { if (emummc_enabled) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; } } } else if (std::strcmp(entry.key, "allow_writing_to_cal_sysmmc") == 0) { if (entry.value[0] == '1') { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc; } else { storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc; } } else if (std::strcmp(entry.key, "log_port") == 0) { const u32 log_port = ParseDecimalInteger(entry.value); if (0 <= log_port && log_port < 4) { storage_ctx.log_port = log_port; } } else if (std::strcmp(entry.key, "log_baud_rate") == 0) { storage_ctx.log_baud_rate = ParseDecimalInteger(entry.value); } else if (std::strcmp(entry.key, "log_inverted") == 0) { if (entry.value[0] == '1') { storage_ctx.log_flags |= uart::Flag_Inverted; } } } } } } /* Parse usb setting from system_settings.ini */ { IniSectionList sections; if (ParseIniSafe(sections, "sdmc:/atmosphere/config/system_settings.ini")) { for (const auto §ion : sections) { /* We only care about the [usb] section. */ if (std::strcmp(section.name, "usb")) { continue; } /* Handle individual fields. */ for (const auto &entry : section.kv_list) { if (std::strcmp(entry.key, "usb30_force_enabled") == 0) { if (std::strcmp(entry.value, "u8!0x1") == 0) { storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ForceEnableUsb30; } } } } } } /* Copy exosphere. */ void *exosphere_dst = reinterpret_cast<void *>(0x40030000); bool use_sd_exo = false; { /* Try to use an sd card file, if present. */ fs::FileHandle exo_file; if (R_SUCCEEDED(fs::OpenFile(std::addressof(exo_file), "sdmc:/atmosphere/exosphere.bin", fs::OpenMode_Read))) { ON_SCOPE_EXIT { fs::CloseFile(exo_file); }; /* Note that we're using sd_exo. */ use_sd_exo = true; Result result; /* Get the size. */ s64 size; if (R_FAILED((result = fs::GetFileSize(std::addressof(size), exo_file))) || size > sizeof(GetExternalPackage().exosphere)) { ShowFatalError("Invalid SD exosphere size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast<u64>(size)); } /* Read the file. */ if (R_FAILED((result = fs::ReadFile(exo_file, 0, exosphere_dst, size)))) { ShowFatalError("Failed to read SD exosphere: 0x%08" PRIx32 "!\n", result.GetValue()); } } } if (!use_sd_exo) { std::memcpy(exosphere_dst, GetExternalPackage().exosphere, sizeof(GetExternalPackage().exosphere)); } /* Copy mariko fatal. */ if (soc_type == fuse::SocType_Mariko) { u8 *mariko_fatal_dst = secmon::MemoryRegionPhysicalMarikoProgramImage.GetPointer<u8>(); bool use_sd_mariko_fatal = false; { /* Try to use an sd card file, if present. */ fs::FileHandle mariko_program_file; if (R_SUCCEEDED(fs::OpenFile(std::addressof(mariko_program_file), "sdmc:/atmosphere/mariko_fatal.bin", fs::OpenMode_Read))) { ON_SCOPE_EXIT { fs::CloseFile(mariko_program_file); }; /* Note that we're using sd mariko fatal. */ use_sd_mariko_fatal = true; Result result; /* Get the size. */ s64 size; if (R_FAILED((result = fs::GetFileSize(std::addressof(size), mariko_program_file))) || size > sizeof(GetExternalPackage().mariko_fatal)) { ShowFatalError("Invalid SD mariko_fatal size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast<u64>(size)); } /* Read the file. */ if (R_FAILED((result = fs::ReadFile(mariko_program_file, 0, mariko_fatal_dst, size)))) { ShowFatalError("Failed to read SD mariko_fatal: 0x%08" PRIx32 "!\n", result.GetValue()); } /* Clear the remainder. */ std::memset(mariko_fatal_dst + size, 0, sizeof(GetExternalPackage().mariko_fatal) - size); } } if (!use_sd_mariko_fatal) { std::memcpy(mariko_fatal_dst, GetExternalPackage().mariko_fatal, sizeof(GetExternalPackage().mariko_fatal)); } } /* Setup the CPU to boot exosphere. */ SetupCpu(reinterpret_cast<uintptr_t>(exosphere_dst)); /* Initialize bootloader parameters. */ InitializeSecureMonitorMailbox(); /* Set our bootloader state. */ SetBootloaderState(pkg1::BootloaderState_LoadedBootConfig); /* Ensure that the CPU will see consistent data. */ hw::FlushEntireDataCache(); } bool IsNogcEnabled(ams::TargetFirmware target_firmware) { /* First parse from ini. */ { IniSectionList sections; if (ParseIniSafe(sections, "sdmc:/atmosphere/config/stratosphere.ini")) { for (const auto §ion : sections) { /* We only care about the [stratosphere] section. */ if (std::strcmp(section.name, "stratosphere")) { continue; } /* Handle individual fields. */ for (const auto &entry : section.kv_list) { if (std::strcmp(entry.key, "nogc") == 0) { return entry.value[0] == '1'; } } } } } /* That failed, so try to decide automatically. */ const auto fuse_version = fuse::GetFuseVersion(); if (target_firmware >= ams::TargetFirmware_12_0_2 && fuse_version < fuse::GetExpectedFuseVersion(ams::TargetFirmware_12_0_2)) { return true; } if (target_firmware >= ams::TargetFirmware_11_0_0 && fuse_version < fuse::GetExpectedFuseVersion(ams::TargetFirmware_11_0_0)) { return true; } if (target_firmware >= ams::TargetFirmware_9_0_0 && fuse_version < fuse::GetExpectedFuseVersion(ams::TargetFirmware_9_0_0)) { return true; } if (target_firmware >= ams::TargetFirmware_4_0_0 && fuse_version < fuse::GetExpectedFuseVersion(ams::TargetFirmware_4_0_0)) { return true; } return false; } } void SetupAndStartHorizon() { /* Get soc type. */ const auto soc_type = fuse::GetSocType(); /* Derive all keys. */ DeriveAllKeys(soc_type); /* Determine whether we're using emummc. */ const bool emummc_enabled = ConfigureEmummc(); /* Initialize emummc. */ /* NOTE: SYSTEM:/ accessible past this point. */ InitializeEmummc(emummc_enabled, g_emummc_cfg); /* Read bootloader. */ const u8 * const package1 = LoadPackage1(soc_type); /* Get target firmware. */ const auto target_firmware = GetApproximateTargetFirmware(package1); /* Read/decrypt package2. */ u8 * const package2 = LoadBootConfigAndPackage2(); /* Setup warmboot firmware. */ LoadWarmbootFirmware(soc_type, target_firmware, package1); /* Decide whether to use nogc patches. */ const bool nogc_enabled = IsNogcEnabled(target_firmware); /* Decide what KIPs/patches we're loading. */ const auto fs_version = ConfigureStratosphere(package2, target_firmware, emummc_enabled, nogc_enabled); /* Setup exosphere. */ ConfigureExosphere(soc_type, target_firmware, emummc_enabled, fs_version); /* Start CPU. */ StartCpu(); /* Build modified package2. */ RebuildPackage2(target_firmware, emummc_enabled); /* Wait for confirmation that exosphere is ready. */ WaitSecureMonitorState(pkg1::SecureMonitorState_Initialized); } } ================================================ FILE: fusee/program/source/fusee_setup_horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot { void SetupAndStartHorizon(); } ================================================ FILE: fusee/program/source/fusee_start.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ .section .crt0._ZN3ams6nxboot5StartEv, "ax", %progbits .arm .align 5 .global _ZN3ams6nxboot5StartEv .type _ZN3ams6nxboot5StartEv, %function _ZN3ams6nxboot5StartEv: /* Setup all registers as = 0. */ msr cpsr_f, #0xC0 mov r0, #0 mov r1, #0 mov r2, #0 mov r3, #0 mov r4, #0 mov r5, #0 mov r6, #0 mov r7, #0 mov r8, #0 mov r9, #0 mov r10, #0 mov r11, #0 mov r12, #0 /* Setup all modes as pointing to our exception handler. */ msr cpsr_cf, #0xDF ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv msr cpsr_cf, #0xD2 ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv msr cpsr_cf, #0xD1 ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv msr cpsr_cf, #0xD7 ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv msr cpsr_cf, #0xDB ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv msr cpsr_cf, #0xD3 ldr sp, =0x40001000 ldr lr, =_ZN3ams6nxboot16ExceptionHandlerEv /* Perform runtime initialization. */ bl _ZN3ams6nxboot4crt010InitializeEv /* Perform nx boot procedure. */ bl _ZN3ams6nxboot4MainEv ================================================ FILE: fusee/program/source/fusee_stratosphere.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_stratosphere.hpp" #include "fusee_fatal.hpp" #include "fusee_malloc.hpp" #include "fusee_external_package.hpp" #include "fs/fusee_fs_api.hpp" namespace ams::nxboot { namespace { constexpr u32 MesoshereMetadataLayout0Magic = util::FourCC<'M','S','S','0'>::Code; constexpr u32 MesoshereMetadataLayout1Magic = util::FourCC<'M','S','S','1'>::Code; struct InitialProcessBinaryHeader { static constexpr u32 Magic = util::FourCC<'I','N','I','1'>::Code; u32 magic; u32 size; u32 num_processes; u32 reserved; }; struct InitialProcessHeader { static constexpr u32 Magic = util::FourCC<'K','I','P','1'>::Code; u32 magic; u8 name[12]; u64 program_id; u32 version; u8 priority; u8 ideal_core_id; u8 _1E; u8 flags; u32 rx_address; u32 rx_size; u32 rx_compressed_size; u32 affinity_mask; u32 ro_address; u32 ro_size; u32 ro_compressed_size; u32 stack_size; u32 rw_address; u32 rw_size; u32 rw_compressed_size; u32 _4C; u32 bss_address; u32 bss_size; u32 pad[(0x80 - 0x58) / sizeof(u32)]; u32 capabilities[0x80 / sizeof(u32)]; }; static_assert(sizeof(InitialProcessHeader) == 0x100); struct PatchMeta { PatchMeta *next; bool is_memset; u32 start_segment; u32 rel_offset; const void *data; u32 size; }; struct alignas(0x10) InitialProcessMeta { InitialProcessMeta *next = nullptr; const InitialProcessHeader *kip; u32 kip_size; PatchMeta *patches_head; PatchMeta *patches_tail; u32 patch_segments; u64 program_id; se::Sha256Hash kip_hash; }; static_assert(sizeof(InitialProcessMeta) == 0x40); static_assert(alignof(InitialProcessMeta) == 0x10); constexpr inline const u64 FsProgramId = 0x0100000000000000; enum FsVersion { FsVersion_1_0_0 = 0, FsVersion_2_0_0, FsVersion_2_0_0_Exfat, FsVersion_2_1_0, FsVersion_2_1_0_Exfat, FsVersion_3_0_0, FsVersion_3_0_0_Exfat, FsVersion_3_0_1, FsVersion_3_0_1_Exfat, FsVersion_4_0_0, FsVersion_4_0_0_Exfat, FsVersion_4_1_0, FsVersion_4_1_0_Exfat, FsVersion_5_0_0, FsVersion_5_0_0_Exfat, FsVersion_5_1_0, FsVersion_5_1_0_Exfat, FsVersion_6_0_0, FsVersion_6_0_0_Exfat, FsVersion_7_0_0, FsVersion_7_0_0_Exfat, FsVersion_8_0_0, FsVersion_8_0_0_Exfat, FsVersion_8_1_0, FsVersion_8_1_0_Exfat, FsVersion_9_0_0, FsVersion_9_0_0_Exfat, FsVersion_9_1_0, FsVersion_9_1_0_Exfat, FsVersion_10_0_0, FsVersion_10_0_0_Exfat, FsVersion_10_2_0, FsVersion_10_2_0_Exfat, FsVersion_11_0_0, FsVersion_11_0_0_Exfat, FsVersion_12_0_0, FsVersion_12_0_0_Exfat, FsVersion_12_0_3, FsVersion_12_0_3_Exfat, FsVersion_13_0_0, FsVersion_13_0_0_Exfat, FsVersion_13_1_0, FsVersion_13_1_0_Exfat, FsVersion_14_0_0, FsVersion_14_0_0_Exfat, FsVersion_15_0_0, FsVersion_15_0_0_Exfat, FsVersion_16_0_0, FsVersion_16_0_0_Exfat, FsVersion_16_0_3, FsVersion_16_0_3_Exfat, FsVersion_17_0_0, FsVersion_17_0_0_Exfat, FsVersion_18_0_0, FsVersion_18_0_0_Exfat, FsVersion_18_1_0, FsVersion_18_1_0_Exfat, FsVersion_19_0_0, FsVersion_19_0_0_Exfat, FsVersion_20_0_0, FsVersion_20_0_0_Exfat, FsVersion_20_1_0, FsVersion_20_1_0_Exfat, FsVersion_21_0_0, FsVersion_21_0_0_Exfat, FsVersion_21_2_0, FsVersion_21_2_0_Exfat, FsVersion_Count, }; constexpr const u8 FsHashes[FsVersion_Count][8] = { { 0xDE, 0x9F, 0xDD, 0xA4, 0x08, 0x5D, 0xD5, 0xFE }, /* FsVersion_1_0_0 */ { 0xCD, 0x7B, 0xBE, 0x18, 0xD6, 0x13, 0x0B, 0x28 }, /* FsVersion_2_0_0 */ { 0xE7, 0x66, 0x92, 0xDF, 0xAA, 0x04, 0x20, 0xE9 }, /* FsVersion_2_0_0_Exfat */ { 0x0D, 0x70, 0x05, 0x62, 0x7B, 0x07, 0x76, 0x7C }, /* FsVersion_2_1_0 */ { 0xDB, 0xD8, 0x5F, 0xCA, 0xCC, 0x19, 0x3D, 0xA8 }, /* FsVersion_2_1_0_Exfat */ { 0xA8, 0x6D, 0xA5, 0xE8, 0x7E, 0xF1, 0x09, 0x7B }, /* FsVersion_3_0_0 */ { 0x98, 0x1C, 0x57, 0xE7, 0xF0, 0x2F, 0x70, 0xF7 }, /* FsVersion_3_0_0_Exfat */ { 0x57, 0x39, 0x7C, 0x06, 0x3F, 0x10, 0xB6, 0x31 }, /* FsVersion_3_0_1 */ { 0x07, 0x30, 0x99, 0xD7, 0xC6, 0xAD, 0x7D, 0x89 }, /* FsVersion_3_0_1_Exfat */ { 0x06, 0xE9, 0x07, 0x19, 0x59, 0x5A, 0x01, 0x0C }, /* FsVersion_4_0_0 */ { 0x54, 0x9B, 0x0F, 0x8D, 0x6F, 0x72, 0xC4, 0xE9 }, /* FsVersion_4_0_0_Exfat */ { 0x80, 0x96, 0xAF, 0x7C, 0x6A, 0x35, 0xAA, 0x82 }, /* FsVersion_4_1_0 */ { 0x02, 0xD5, 0xAB, 0xAA, 0xFD, 0x20, 0xC8, 0xB0 }, /* FsVersion_4_1_0_Exfat */ { 0xA6, 0xF2, 0x7A, 0xD9, 0xAC, 0x7C, 0x73, 0xAD }, /* FsVersion_5_0_0 */ { 0xCE, 0x3E, 0xCB, 0xA2, 0xF2, 0xF0, 0x62, 0xF5 }, /* FsVersion_5_0_0_Exfat */ { 0x76, 0xF8, 0x74, 0x02, 0xC9, 0x38, 0x7C, 0x0F }, /* FsVersion_5_1_0 */ { 0x10, 0xB2, 0xD8, 0x16, 0x05, 0x48, 0x85, 0x99 }, /* FsVersion_5_1_0_Exfat */ { 0x3A, 0x57, 0x4D, 0x43, 0x61, 0x86, 0x19, 0x1D }, /* FsVersion_6_0_0 */ { 0x33, 0x05, 0x53, 0xF6, 0xB5, 0xFB, 0x55, 0xC4 }, /* FsVersion_6_0_0_Exfat */ { 0x2A, 0xDB, 0xE9, 0x7E, 0x9B, 0x5F, 0x41, 0x77 }, /* FsVersion_7_0_0 */ { 0x2C, 0xCE, 0x65, 0x9C, 0xEC, 0x53, 0x6A, 0x8E }, /* FsVersion_7_0_0_Exfat */ { 0xB2, 0xF5, 0x17, 0x6B, 0x35, 0x48, 0x36, 0x4D }, /* FsVersion_8_0_0 */ { 0xDB, 0xD9, 0x41, 0xC0, 0xC5, 0x3C, 0x52, 0xCC }, /* FsVersion_8_0_0_Exfat */ { 0x6B, 0x09, 0xB6, 0x7B, 0x29, 0xC0, 0x20, 0x24 }, /* FsVersion_8_1_0 */ { 0xB4, 0xCA, 0xE1, 0xF2, 0x49, 0x65, 0xD9, 0x2E }, /* FsVersion_8_1_0_Exfat */ { 0x46, 0x87, 0x40, 0x76, 0x1E, 0x19, 0x3E, 0xB7 }, /* FsVersion_9_0_0 */ { 0x7C, 0x95, 0x13, 0x76, 0xE5, 0xC1, 0x2D, 0xF8 }, /* FsVersion_9_0_0_Exfat */ { 0xB5, 0xE7, 0xA6, 0x4C, 0x6F, 0x5C, 0x4F, 0xE3 }, /* FsVersion_9_1_0 */ { 0xF1, 0x96, 0xD1, 0x44, 0xD0, 0x44, 0x45, 0xB6 }, /* FsVersion_9_1_0_Exfat */ { 0x3E, 0xEB, 0xD9, 0xB7, 0xBC, 0xD1, 0xB5, 0xE0 }, /* FsVersion_10_0_0 */ { 0x81, 0x7E, 0xA2, 0xB0, 0xB7, 0x02, 0xC1, 0xF3 }, /* FsVersion_10_0_0_Exfat */ { 0xA9, 0x52, 0xB6, 0x57, 0xAD, 0xF9, 0xC2, 0xBA }, /* FsVersion_10_2_0 */ { 0x16, 0x0D, 0x3E, 0x10, 0x4E, 0xAD, 0x61, 0x76 }, /* FsVersion_10_2_0_Exfat */ { 0xE3, 0x99, 0x15, 0x6E, 0x84, 0x4E, 0xB0, 0xAA }, /* FsVersion_11_0_0 */ { 0x0B, 0xA1, 0x5B, 0xB3, 0x04, 0xB5, 0x05, 0x63 }, /* FsVersion_11_0_0_Exfat */ { 0xDC, 0x2A, 0x08, 0x49, 0x96, 0xBB, 0x3C, 0x01 }, /* FsVersion_12_0_0 */ { 0xD5, 0xA5, 0xBF, 0x36, 0x64, 0x0C, 0x49, 0xEA }, /* FsVersion_12_0_0_Exfat */ { 0xC8, 0x67, 0x62, 0xBE, 0x19, 0xA5, 0x1F, 0xA0 }, /* FsVersion_12_0_3 */ { 0xE1, 0xE8, 0xD3, 0xD6, 0xA2, 0xFE, 0x0B, 0x10 }, /* FsVersion_12_0_3_Exfat */ { 0x7D, 0x20, 0x05, 0x47, 0x17, 0x8A, 0x83, 0x6A }, /* FsVersion_13_0_0 */ { 0x51, 0xEB, 0xFA, 0x9C, 0xCF, 0x66, 0xC0, 0x9E }, /* FsVersion_13_0_0_Exfat */ { 0x91, 0xBA, 0x65, 0xA2, 0x1C, 0x1D, 0x50, 0xAE }, /* FsVersion_13_1_0 */ { 0x76, 0x38, 0x27, 0xEE, 0x9C, 0x20, 0x7E, 0x5B }, /* FsVersion_13_1_0_Exfat */ { 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */ { 0xD4, 0x88, 0xD1, 0xF2, 0x92, 0x17, 0x35, 0x5C }, /* FsVersion_14_0_0_Exfat */ { 0xD0, 0xD4, 0x49, 0x18, 0x14, 0xB5, 0x62, 0xAF }, /* FsVersion_15_0_0 */ { 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */ { 0x56, 0xE8, 0x56, 0x56, 0x6C, 0x38, 0xD8, 0xBE }, /* FsVersion_16_0_0 */ { 0xCF, 0xAB, 0x45, 0x0C, 0x2C, 0x53, 0x9D, 0xA9 }, /* FsVersion_16_0_0_Exfat */ { 0x39, 0xEE, 0x1F, 0x1E, 0x0E, 0xA7, 0x32, 0x5D }, /* FsVersion_16_0_3 */ { 0x62, 0xC6, 0x5E, 0xFD, 0x9A, 0xBF, 0x7C, 0x43 }, /* FsVersion_16_0_3_Exfat */ { 0x27, 0x07, 0x3B, 0xF0, 0xA1, 0xB8, 0xCE, 0x61 }, /* FsVersion_17_0_0 */ { 0xEE, 0x0F, 0x4B, 0xAC, 0x6D, 0x1F, 0xFC, 0x4B }, /* FsVersion_17_0_0_Exfat */ { 0x79, 0x5F, 0x5A, 0x5E, 0xB0, 0xC6, 0x77, 0x9E }, /* FsVersion_18_0_0 */ { 0x1E, 0x2C, 0x64, 0xB1, 0xCC, 0xE2, 0x78, 0x24 }, /* FsVersion_18_0_0_Exfat */ { 0xA3, 0x39, 0xF0, 0x1C, 0x95, 0xBF, 0xA7, 0x68 }, /* FsVersion_18_1_0 */ { 0x20, 0x4C, 0xBA, 0x86, 0xDE, 0x08, 0x44, 0x6A }, /* FsVersion_18_1_0_Exfat */ { 0xD9, 0x4C, 0x68, 0x15, 0xF8, 0xF5, 0x0A, 0x20 }, /* FsVersion_19_0_0 */ { 0xED, 0xA8, 0x78, 0x68, 0xA4, 0x49, 0x07, 0x50 }, /* FsVersion_19_0_0_Exfat */ { 0x63, 0x54, 0x96, 0x9E, 0x60, 0xA7, 0x97, 0x7B }, /* FsVersion_20_0_0 */ { 0x47, 0x41, 0x07, 0x10, 0x65, 0x4F, 0xA4, 0x3F }, /* FsVersion_20_0_0_Exfat */ { 0xED, 0x34, 0xB4, 0x50, 0x58, 0x4A, 0x5B, 0x43 }, /* FsVersion_20_1_0 */ { 0xA5, 0x1A, 0xA4, 0x92, 0x6C, 0x41, 0x87, 0x59 }, /* FsVersion_20_1_0_Exfat */ { 0xEE, 0x4B, 0x30, 0x12, 0xA6, 0x84, 0x02, 0x25 }, /* FsVersion_21_0_0 */ { 0x6E, 0x2B, 0xD9, 0xBA, 0xA3, 0xB9, 0x10, 0xF1 }, /* FsVersion_21_0_0_Exfat */ { 0xAF, 0x1D, 0xBD, 0xC7, 0x82, 0x98, 0x3C, 0xBD }, /* FsVersion_21_2_0 */ { 0x56, 0x25, 0x17, 0xA1, 0x92, 0xC3, 0xC8, 0xF0 }, /* FsVersion_21_2_0_Exfat */ }; const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) { if (target_firmware >= ams::TargetFirmware_17_0_0) { const u32 *data_32 = reinterpret_cast<const u32 *>(data); const u32 branch_target = (data_32[0] & 0x00FFFFFF); for (size_t i = branch_target; i < branch_target + 0x1000 / sizeof(u32); ++i) { const u32 ini_offset = (i * sizeof(u32)) + data_32[i]; if (data_32[i + 1] == 0 && ini_offset <= header->meta.payload_sizes[0] && std::memcmp(data + ini_offset, "INI1", 4) == 0) { return reinterpret_cast<const InitialProcessBinaryHeader *>(data + ini_offset); } } return nullptr; } else if (target_firmware >= ams::TargetFirmware_8_0_0) { /* Try to find initial process binary. */ const u32 *data_32 = reinterpret_cast<const u32 *>(data); for (size_t i = 0; i < 0x1000 / sizeof(u32); ++i) { if (data_32[i] == 0 && data_32[i + 8] <= header->meta.payload_sizes[0] && std::memcmp(data + data_32[i + 8], "INI1", 4) == 0) { return reinterpret_cast<const InitialProcessBinaryHeader *>(data + data_32[i + 8]); } } return nullptr; } else { return reinterpret_cast<const InitialProcessBinaryHeader *>(data + header->meta.payload_sizes[0]); } } constexpr size_t GetInitialProcessSize(const InitialProcessHeader *kip) { return sizeof(*kip) + kip->rx_compressed_size + kip->ro_compressed_size + kip->rw_compressed_size; } const InitialProcessHeader *FindInitialProcessInBinary(const InitialProcessBinaryHeader *ini, u64 program_id) { const u8 *data = reinterpret_cast<const u8 *>(ini + 1); for (u32 i = 0; i < ini->num_processes; ++i) { const InitialProcessHeader *kip = reinterpret_cast<const InitialProcessHeader *>(data); if (kip->magic != InitialProcessHeader::Magic) { return nullptr; } if (kip->program_id == program_id) { return kip; } data += GetInitialProcessSize(kip); } return nullptr; } FsVersion GetFsVersion(const se::Sha256Hash &fs_hash) { for (size_t i = 0; i < util::size(FsHashes); ++i) { if (std::memcmp(fs_hash.bytes, FsHashes[i], sizeof(FsHashes[i])) == 0) { return static_cast<FsVersion>(i); } } return FsVersion_Count; } constinit InitialProcessMeta g_initial_process_meta = {}; constinit size_t g_initial_process_binary_size = 0; void AddInitialProcessImpl(InitialProcessMeta *meta, const InitialProcessHeader *kip, const se::Sha256Hash *hash) { /* Set the meta's fields. */ meta->next = nullptr; meta->program_id = kip->program_id; meta->kip = kip; meta->kip_size = GetInitialProcessSize(kip); /* Copy or calculate hash. */ if (hash != nullptr) { std::memcpy(std::addressof(meta->kip_hash), hash, sizeof(meta->kip_hash)); } else { se::CalculateSha256(std::addressof(meta->kip_hash), kip, meta->kip_size); } /* Clear patches. */ meta->patches_head = nullptr; meta->patches_tail = nullptr; meta->patch_segments = 0; /* Increase the initial process binary's size. */ g_initial_process_binary_size += meta->kip_size; } bool AddInitialProcess(const InitialProcessHeader *kip, const se::Sha256Hash *hash = nullptr) { /* Check kip magic. */ if (kip->magic != InitialProcessHeader::Magic) { ShowFatalError("KIP seems corrupted!\n"); } /* Handle the initial case. */ if (g_initial_process_binary_size == 0) { AddInitialProcessImpl(std::addressof(g_initial_process_meta), kip, hash); return true; } /* Check if we've already added the program id. */ InitialProcessMeta *cur = std::addressof(g_initial_process_meta); while (true) { if (cur->program_id == kip->program_id) { return false; } if (cur->next != nullptr) { cur = cur->next; } else { break; } } /* Allocate an initial process meta. */ auto *new_meta = static_cast<InitialProcessMeta *>(AllocateAligned(sizeof(InitialProcessMeta), alignof(InitialProcessMeta))); /* Insert the new meta. */ cur->next = new_meta; AddInitialProcessImpl(new_meta, kip, hash); return true; } InitialProcessMeta *FindInitialProcess(u64 program_id) { for (InitialProcessMeta *cur = std::addressof(g_initial_process_meta); cur != nullptr; cur = cur->next) { if (cur->program_id == program_id) { return cur; } } return nullptr; } u32 GetPatchSegments(const InitialProcessHeader *kip, u32 offset, size_t size) { /* Create segment mask. */ u32 segments = 0; /* Get the segment extents. */ const u32 rx_start = kip->rx_address; const u32 ro_start = kip->ro_address; const u32 rw_start = kip->rw_address; const u32 rx_end = ro_start; const u32 ro_end = rw_start; const u32 rw_end = rw_start + kip->rw_size; /* If the offset is below the kip header, ignore it. */ if (offset < sizeof(*kip)) { return segments; } /* Adjust the offset in bounds. */ offset -= sizeof(*kip); /* Check if the offset strays out of bounds. */ if (offset + size > rw_end) { return segments; } /* Set bits for the affected segments. */ if (util::HasOverlap(offset, size, rx_start, rx_end - rx_start)) { segments |= (1 << 0); } if (util::HasOverlap(offset, size, ro_start, ro_end - ro_start)) { segments |= (1 << 1); } if (util::HasOverlap(offset, size, rw_start, rw_end - rw_start)) { segments |= (1 << 2); } return segments; } void AddPatch(InitialProcessMeta *meta, u32 offset, const void *data, size_t data_size, bool is_memset = false) { /* Determine the segment. */ const u32 segments = GetPatchSegments(meta->kip, offset, data_size); /* If the patch hits no segments, we don't need it. */ if (segments == 0) { return; } /* Update patch segments. */ meta->patch_segments |= segments; /* Adjust offset. */ const u32 start_segment = util::CountTrailingZeros(segments); offset -= sizeof(*meta->kip); switch (start_segment) { case 0: offset -= meta->kip->rx_address; break; case 1: offset -= meta->kip->ro_address; break; case 2: offset -= meta->kip->rw_address; break; } /* Create patch. */ auto *new_patch = static_cast<PatchMeta *>(AllocateAligned(sizeof(PatchMeta), alignof(PatchMeta))); new_patch->next = nullptr; new_patch->is_memset = is_memset; new_patch->start_segment = start_segment; new_patch->rel_offset = offset; new_patch->data = data; new_patch->size = data_size; /* Add the patch. */ if (meta->patches_head == nullptr) { meta->patches_head = new_patch; } else { meta->patches_tail->next = new_patch; } meta->patches_tail = new_patch; } constexpr const u8 NogcPatch0[] = { 0x80 }; constexpr const u8 NogcPatch1[] = { 0xE0, 0x03, 0x1F, 0x2A, 0xC0, 0x03, 0x5F, 0xD6, }; void AddNogcPatches(InitialProcessMeta *fs_meta, FsVersion fs_version) { switch (fs_version) { case FsVersion_1_0_0: case FsVersion_2_0_0: case FsVersion_2_0_0_Exfat: case FsVersion_2_1_0: case FsVersion_2_1_0_Exfat: case FsVersion_3_0_0: case FsVersion_3_0_0_Exfat: case FsVersion_3_0_1: case FsVersion_3_0_1_Exfat: /* There were no lotus firmware updates prior to 4.0.0. */ /* TODO: Implement patches, regardless? */ break; case FsVersion_4_0_0: case FsVersion_4_0_0_Exfat: AddPatch(fs_meta, 0x0A3539, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x0AAC44, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_4_1_0: case FsVersion_4_1_0_Exfat: AddPatch(fs_meta, 0x0A35BD, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x0AACA8, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_5_0_0: case FsVersion_5_0_0_Exfat: AddPatch(fs_meta, 0x0CF4C5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x0D74A0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_5_1_0: case FsVersion_5_1_0_Exfat: AddPatch(fs_meta, 0x0CF895, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x0D7870, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_6_0_0: AddPatch(fs_meta, 0x1539F5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x12CD20, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_6_0_0_Exfat: AddPatch(fs_meta, 0x15F0F5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x138420, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_7_0_0: AddPatch(fs_meta, 0x15C005, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x134260, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_7_0_0_Exfat: AddPatch(fs_meta, 0x1675B5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x13F810, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_8_0_0: case FsVersion_8_1_0: AddPatch(fs_meta, 0x15EC95, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x136900, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_8_0_0_Exfat: case FsVersion_8_1_0_Exfat: AddPatch(fs_meta, 0x16A245, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x141EB0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_9_0_0: case FsVersion_9_0_0_Exfat: AddPatch(fs_meta, 0x143369, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x129520, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_9_1_0: case FsVersion_9_1_0_Exfat: AddPatch(fs_meta, 0x143379, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x129530, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_10_0_0: case FsVersion_10_0_0_Exfat: AddPatch(fs_meta, 0x14DF09, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x13BF90, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_10_2_0: case FsVersion_10_2_0_Exfat: AddPatch(fs_meta, 0x14E369, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x13C3F0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_11_0_0: case FsVersion_11_0_0_Exfat: AddPatch(fs_meta, 0x156FB9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1399B4, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_12_0_0: case FsVersion_12_0_0_Exfat: AddPatch(fs_meta, 0x155469, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x13EB24, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_12_0_3: case FsVersion_12_0_3_Exfat: AddPatch(fs_meta, 0x155579, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x13EC34, NogcPatch1, sizeof(NogcPatch1)); case FsVersion_13_0_0: case FsVersion_13_0_0_Exfat: AddPatch(fs_meta, 0x159119, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1426D0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_13_1_0: case FsVersion_13_1_0_Exfat: AddPatch(fs_meta, 0x1590B9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x142670, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_14_0_0: AddPatch(fs_meta, 0x18A3E9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x164330, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_14_0_0_Exfat: AddPatch(fs_meta, 0x195769, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16F6B0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_15_0_0: AddPatch(fs_meta, 0x184259, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x15EDE4, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_15_0_0_Exfat: AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_16_0_0: AddPatch(fs_meta, 0x1866D9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x160C70, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_16_0_0_Exfat: AddPatch(fs_meta, 0x1913B9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16B950, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_16_0_3: AddPatch(fs_meta, 0x186729, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x160CC0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_16_0_3_Exfat: AddPatch(fs_meta, 0x191409, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16B9A0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_17_0_0: AddPatch(fs_meta, 0x18B149, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x165200, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_17_0_0_Exfat: AddPatch(fs_meta, 0x195FA9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x170060, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_18_0_0: AddPatch(fs_meta, 0x18AF49, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x164B50, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_18_0_0_Exfat: AddPatch(fs_meta, 0x195FD9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16FBE0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_18_1_0: AddPatch(fs_meta, 0x18AF49, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x164B50, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_18_1_0_Exfat: AddPatch(fs_meta, 0x195FD9, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16FBE0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_19_0_0: AddPatch(fs_meta, 0x195C75, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x195E75, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x16F170, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_19_0_0_Exfat: AddPatch(fs_meta, 0x1A14A5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1A16A5, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x17A9A0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_20_0_0: case FsVersion_20_1_0: AddPatch(fs_meta, 0x1A7E25, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1A8025, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x17C250, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_20_0_0_Exfat: case FsVersion_20_1_0_Exfat: AddPatch(fs_meta, 0x1B3745, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1B3945, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x187B70, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_21_0_0: case FsVersion_21_2_0: AddPatch(fs_meta, 0x1AC9ED, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1ACA05 , NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x17FBE0, NogcPatch1, sizeof(NogcPatch1)); break; case FsVersion_21_0_0_Exfat: case FsVersion_21_2_0_Exfat: AddPatch(fs_meta, 0x1B7B4D, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x1B7B65, NogcPatch0, sizeof(NogcPatch0)); AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1)); break; default: break; } } struct BlzSegmentFlags { using Offset = util::BitPack16::Field<0, 12, u32>; using Size = util::BitPack16::Field<Offset::Next, 4, u32>; }; void BlzUncompress(void *_end) { /* Parse the footer, endian agnostic. */ static_assert(sizeof(u32) == 4); static_assert(sizeof(u16) == 2); static_assert(sizeof(u8) == 1); u8 *end = static_cast<u8 *>(_end); const u32 total_size = (end[-12] << 0) | (end[-11] << 8) | (end[-10] << 16) | (end[- 9] << 24); const u32 footer_size = (end[- 8] << 0) | (end[- 7] << 8) | (end[- 6] << 16) | (end[- 5] << 24); const u32 additional_size = (end[- 4] << 0) | (end[- 3] << 8) | (end[- 2] << 16) | (end[- 1] << 24); /* Prepare to decompress. */ u8 *cmp_start = end - total_size; u32 cmp_ofs = total_size - footer_size; u32 out_ofs = total_size + additional_size; /* Decompress. */ while (out_ofs) { u8 control = cmp_start[--cmp_ofs]; /* Each bit in the control byte is a flag indicating compressed or not compressed. */ for (size_t i = 0; i < 8 && out_ofs; ++i, control <<= 1) { if (control & 0x80) { /* NOTE: Nintendo does not check if it's possible to decompress. */ /* As such, we will leave the following as a debug assertion, and not a release assertion. */ AMS_AUDIT(cmp_ofs >= sizeof(u16)); cmp_ofs -= sizeof(u16); /* Extract segment bounds. */ const util::BitPack16 seg_flags{static_cast<u16>((cmp_start[cmp_ofs] << 0) | (cmp_start[cmp_ofs + 1] << 8))}; const u32 seg_ofs = seg_flags.Get<BlzSegmentFlags::Offset>() + 3; const u32 seg_size = std::min(seg_flags.Get<BlzSegmentFlags::Size>() + 3, out_ofs); AMS_AUDIT(out_ofs + seg_ofs <= total_size + additional_size); /* Copy the data. */ out_ofs -= seg_size; for (size_t j = 0; j < seg_size; j++) { cmp_start[out_ofs + j] = cmp_start[out_ofs + seg_ofs + j]; } } else { /* NOTE: Nintendo does not check if it's possible to copy. */ /* As such, we will leave the following as a debug assertion, and not a release assertion. */ AMS_AUDIT(cmp_ofs >= sizeof(u8)); cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; } } } } void *ReadFile(s64 *out_size, const char *path, size_t align = 0x10) { fs::FileHandle file; if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) { ON_SCOPE_EXIT { fs::CloseFile(file); }; Result result; /* Get the kip size. */ if (R_FAILED((result = fs::GetFileSize(out_size, file)))) { ShowFatalError("Failed to get size (0x%08" PRIx32 ") of %s!\n", result.GetValue(), path); } /* Allocate file. */ void *data = AllocateAligned(*out_size, std::max<size_t>(align, 0x10)); /* Read the file. */ if (R_FAILED((result = fs::ReadFile(file, 0, data, *out_size)))) { ShowFatalError("Failed to read (0x%08" PRIx32 ") %s!\n", result.GetValue(), path); } return data; } else { return nullptr; } } } u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled) { /* Load KIPs off the SD card. */ { /* Create kip dir path. */ char kip_path[0x120]; std::memcpy(kip_path, "sdmc:/atmosphere/kips", 0x16); fs::DirectoryHandle kip_dir; if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(kip_dir), kip_path))) { ON_SCOPE_EXIT { fs::CloseDirectory(kip_dir); }; s64 count; fs::DirectoryEntry entries[1]; while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, kip_dir, util::size(entries))) && count > 0) { /* Check that file is a file. */ if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_File) { continue; } /* Get filename length. */ const int name_len = std::strlen(entries[0].file_name); /* Adjust kip path. */ kip_path[0x15] = '/'; std::memcpy(kip_path + 0x16, entries[0].file_name, name_len + 1); /* Check that file is ".kip" or ".kip1" file. */ const int path_len = 0x16 + name_len; if (std::memcmp(kip_path + path_len - 4, ".kip", 5) != 0 && std::memcmp(kip_path + path_len - 5, ".kip1", 6) != 0) { continue; } /* Read the kip. */ s64 file_size; if (InitialProcessHeader *kip = static_cast<InitialProcessHeader *>(ReadFile(std::addressof(file_size), kip_path, alignof(InitialProcessHeader))); kip != nullptr) { /* If the kip is valid, add it. */ if (kip->magic == InitialProcessHeader::Magic && file_size == GetInitialProcessSize(kip)) { AddInitialProcess(kip); } } } } } /* Add the stratosphere kips. */ { const auto &external_package = GetExternalPackage(); for (u32 i = 0; i < external_package.header.num_kips; ++i) { const auto &meta = external_package.header.kip_metas[i]; AddInitialProcess(reinterpret_cast<const InitialProcessHeader *>(external_package.kips + meta.offset), std::addressof(meta.hash)); } } /* Get meta for FS process. */ auto *fs_meta = FindInitialProcess(FsProgramId); if (fs_meta == nullptr) { /* Get nintendo header/data. */ const pkg2::Package2Header *nn_header = reinterpret_cast<const pkg2::Package2Header *>(nn_package2); const u8 *nn_data = nn_package2 + sizeof(*nn_header); /* Get Nintendo INI1. */ const InitialProcessBinaryHeader *nn_ini = FindInitialProcessBinary(nn_header, nn_data, target_firmware); if (nn_ini == nullptr || nn_ini->magic != InitialProcessBinaryHeader::Magic) { ShowFatalError("Failed to find INI1!\n"); } /* Find FS KIP. */ const InitialProcessHeader *nn_fs_kip = FindInitialProcessInBinary(nn_ini, FsProgramId); if (nn_fs_kip == nullptr) { ShowFatalError("Failed to find FS!\n"); } /* Add to binary. */ AddInitialProcess(nn_fs_kip); /* Re-find meta. */ fs_meta = FindInitialProcess(FsProgramId); } /* Check that we found FS. */ if (fs_meta == nullptr) { ShowFatalError("Failed to find FS!\n"); } /* Get FS version. */ const auto fs_version = GetFsVersion(fs_meta->kip_hash); if (fs_version >= FsVersion_Count) { if (emummc_enabled || nogc_enabled) { ShowFatalError("Failed to identify FS!\n"); } } /* If emummc is enabled, we need to decompress fs .text. */ if (emummc_enabled) { fs_meta->patch_segments |= (1 << 0); } /* Parse/prepare relevant nogc/kip patches. */ { /* Add nogc patches. */ if (nogc_enabled) { AddNogcPatches(fs_meta, fs_version); } /* TODO ams.tma2: add mount_host patches. */ } /* Return the fs version we're using. */ return static_cast<u32>(fs_version); } void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled) { /* Get the external package. */ const auto &external_package = GetExternalPackage(); /* Clear package2 header. */ auto *package2 = secmon::MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>(); std::memset(package2, 0, sizeof(*package2)); /* Get payload data pointer. */ u8 * const payload_data = reinterpret_cast<u8 *>(package2 + 1); /* Useful values. */ constexpr u32 KernelPayloadBase = 0x60000; /* Set fields. */ package2->meta.key_generation = pkg1::KeyGeneration_Current; std::memcpy(package2->meta.magic, pkg2::Package2Meta::Magic::String, sizeof(package2->meta.magic)); package2->meta.entrypoint = KernelPayloadBase; package2->meta.bootloader_version = pkg2::CurrentBootloaderVersion; package2->meta.package2_version = pkg2::MinimumValidDataVersion; /* Load mesosphere. */ s64 meso_size; if (void *sd_meso = ReadFile(std::addressof(meso_size), "sdmc:/atmosphere/mesosphere.bin"); sd_meso != nullptr) { std::memcpy(payload_data, sd_meso, meso_size); } else { meso_size = external_package.header.meso_size; std::memcpy(payload_data, external_package.mesosphere, meso_size); } /* Read emummc, if needed. */ const InitialProcessHeader *emummc; s64 emummc_size; if (emummc_enabled) { emummc = static_cast<const InitialProcessHeader *>(ReadFile(std::addressof(emummc_size), "sdmc:/atmosphere/emummc.kip")); if (emummc == nullptr) { emummc = reinterpret_cast<const InitialProcessHeader *>(external_package.kips + external_package.header.emummc_meta.offset); emummc_size = external_package.header.emummc_meta.size; } } /* Set the embedded ini pointer. */ const u32 magic = *reinterpret_cast<const u32 *>(payload_data + 4); if (magic == MesoshereMetadataLayout0Magic) { std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size)); } else if (magic == MesoshereMetadataLayout1Magic) { if (const u32 meta_offset = *reinterpret_cast<const u32 *>(payload_data + 8); meta_offset <= meso_size - sizeof(meso_size)) { s64 relative_offset = meso_size - meta_offset; std::memcpy(payload_data + meta_offset, std::addressof(relative_offset), sizeof(relative_offset)); } else { ShowFatalError("Invalid mesosphere metadata layout!\n"); } } else { ShowFatalError("Unknown mesosphere metadata version!\n"); } /* Get the ini pointer. */ InitialProcessBinaryHeader * const ini = reinterpret_cast<InitialProcessBinaryHeader *>(payload_data + meso_size); /* Set ini fields. */ ini->magic = InitialProcessBinaryHeader::Magic; ini->num_processes = 0; ini->reserved = 0; /* Iterate all processes. */ u8 * const dst_kip_start = reinterpret_cast<u8 *>(ini + 1); u8 * dst_kip_cur = dst_kip_start; for (InitialProcessMeta *meta = std::addressof(g_initial_process_meta); meta != nullptr; meta = meta->next) { /* Get the current kip. */ const auto *src_kip = meta->kip; auto *dst_kip = reinterpret_cast<InitialProcessHeader *>(dst_kip_cur); /* Copy the kip header */ std::memcpy(dst_kip, src_kip, sizeof(*src_kip)); const u8 *src_kip_data = reinterpret_cast<const u8 *>(src_kip + 1); u8 *dst_kip_data = reinterpret_cast< u8 *>(dst_kip + 1); /* If necessary, inject emummc. */ u32 addl_text_offset = 0; if (dst_kip->program_id == FsProgramId && emummc_enabled) { /* Get emummc extents. */ addl_text_offset = emummc->bss_address + emummc->bss_size; if ((emummc->flags & 7) || !util::IsAligned(addl_text_offset, 0x1000)) { ShowFatalError("Invalid emummc kip!\n"); } /* Copy emummc capabilities. */ { std::memcpy(dst_kip->capabilities, emummc->capabilities, sizeof(emummc->capabilities)); if (target_firmware <= ams::TargetFirmware_1_0_0) { for (size_t i = 0; i < util::size(dst_kip->capabilities); ++i) { if (dst_kip->capabilities[i] == 0xFFFFFFFF) { dst_kip->capabilities[i] = 0x07000E7F; break; } } } } /* Update section headers. */ dst_kip->ro_address += addl_text_offset; dst_kip->rw_address += addl_text_offset; dst_kip->bss_address += addl_text_offset; /* Get emummc sections. */ const u8 *emummc_data = reinterpret_cast<const u8 *>(emummc + 1); /* Copy emummc sections. */ std::memcpy(dst_kip_data + emummc->rx_address, emummc_data, emummc->rx_compressed_size); std::memcpy(dst_kip_data + emummc->ro_address, emummc_data + emummc->rx_compressed_size, emummc->ro_compressed_size); std::memcpy(dst_kip_data + emummc->rw_address, emummc_data + emummc->rx_compressed_size + emummc->ro_compressed_size, emummc->rw_compressed_size); std::memset(dst_kip_data + emummc->bss_address, 0, emummc->bss_size); /* Advance. */ dst_kip_data += addl_text_offset; } /* Prepare to process segments. */ u8 *dst_rx_data, *dst_ro_data, *dst_rw_data; /* Process .text. */ { dst_rx_data = dst_kip_data; std::memcpy(dst_kip_data, src_kip_data, src_kip->rx_compressed_size); /* Uncompress, if necessary. */ if ((meta->patch_segments & src_kip->flags) & (1 << 0)) { BlzUncompress(dst_kip_data + dst_kip->rx_compressed_size); dst_kip->rx_compressed_size = dst_kip->rx_size; } /* Advance. */ dst_kip_data += dst_kip->rx_compressed_size; src_kip_data += src_kip->rx_compressed_size; /* Account for potential emummc. */ dst_kip->rx_size += addl_text_offset; dst_kip->rx_compressed_size += addl_text_offset; } /* Process .rodata. */ { dst_ro_data = dst_kip_data; std::memcpy(dst_kip_data, src_kip_data, src_kip->ro_compressed_size); /* Uncompress, if necessary. */ if ((meta->patch_segments & src_kip->flags) & (1 << 1)) { BlzUncompress(dst_kip_data + dst_kip->ro_compressed_size); dst_kip->ro_compressed_size = dst_kip->ro_size; } /* Advance. */ dst_kip_data += dst_kip->ro_compressed_size; src_kip_data += src_kip->ro_compressed_size; } /* Process .rwdata. */ { dst_rw_data = dst_kip_data; std::memcpy(dst_kip_data, src_kip_data, src_kip->rw_compressed_size); /* Uncompress, if necessary. */ if ((meta->patch_segments & src_kip->flags) & (1 << 2)) { BlzUncompress(dst_kip_data + dst_kip->rw_compressed_size); dst_kip->rw_compressed_size = dst_kip->rw_size; } /* Advance. */ dst_kip_data += dst_kip->rw_compressed_size; src_kip_data += src_kip->rw_compressed_size; } /* Adjust flags. */ dst_kip->flags &= ~meta->patch_segments; /* Apply patches. */ for (auto *patch = meta->patches_head; patch != nullptr; patch = patch->next) { /* Get the destination segment. */ u8 *patch_dst_segment; switch (patch->start_segment) { case 0: patch_dst_segment = dst_rx_data; break; case 1: patch_dst_segment = dst_ro_data; break; case 2: patch_dst_segment = dst_rw_data; break; default: ShowFatalError("Unknown patch segment %" PRIu32 "\n", patch->start_segment); break; } /* Get the destination. */ u8 * const patch_dst = patch_dst_segment + patch->rel_offset; /* Apply the patch. */ if (patch->is_memset) { const u8 val = *static_cast<const u8 *>(patch->data); std::memset(patch_dst, val, patch->size); } else { std::memcpy(patch_dst, patch->data, patch->size); } } /* Advance. */ dst_kip_cur += GetInitialProcessSize(dst_kip); /* Increment num kips. */ ++ini->num_processes; } /* Set INI size. */ ini->size = sizeof(*ini) + (dst_kip_cur - dst_kip_start); if (ini->size > 12_MB) { ShowFatalError("INI is too big! (0x%08" PRIx32 ")\n", ini->size); } /* Set the payload size/offset. */ package2->meta.payload_offsets[0] = KernelPayloadBase; package2->meta.payload_sizes[0] = util::AlignUp(meso_size + ini->size, 0x10); /* Set total size. */ package2->meta.package2_size = sizeof(*package2) + package2->meta.payload_sizes[0]; } } ================================================ FILE: fusee/program/source/fusee_stratosphere.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled); void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled); } ================================================ FILE: fusee/program/source/fusee_uncompress.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_uncompress.hpp" namespace ams::nxboot { namespace { class Lz4Uncompressor { private: const u8 *m_src; size_t m_src_size; size_t m_src_offset; u8 *m_dst; size_t m_dst_size; size_t m_dst_offset; public: Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) { /* ... */ } void Uncompress() { while (true) { /* Read a control byte. */ const u8 control = this->ReadByte(); /* Copy what it specifies we should copy. */ this->Copy(this->GetCopySize(control >> 4)); /* If we've exceeded size, we're done. */ if (m_src_offset >= m_src_size) { break; } /* Read the wide copy offset. */ u16 wide_offset = this->ReadByte(); AMS_ABORT_UNLESS(this->CanRead()); wide_offset |= (this->ReadByte() << 8); /* Determine the copy size. */ const size_t wide_copy_size = this->GetCopySize(control & 0xF); /* Copy bytes. */ const size_t end_offset = m_dst_offset + wide_copy_size + 4; for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) { AMS_ABORT_UNLESS(wide_offset <= cur_offset); m_dst[cur_offset] = m_dst[cur_offset - wide_offset]; } } } private: u8 ReadByte() { return m_src[m_src_offset++]; } bool CanRead() const { return m_src_offset < m_src_size; } size_t GetCopySize(u8 control) { size_t size = control; if (control >= 0xF) { do { AMS_ABORT_UNLESS(this->CanRead()); control = this->ReadByte(); size += control; } while (control == 0xFF); } return size; } void Copy(size_t size) { __builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size); m_dst_offset += size; m_src_offset += size; } }; } void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Create an execute a decompressor. */ Lz4Uncompressor(dst, dst_size, src, src_size).Uncompress(); } } ================================================ FILE: fusee/program/source/fusee_uncompress.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <vapours.hpp> #pragma once namespace ams::nxboot { void Uncompress(void *dst, size_t dst_size, const void *src, size_t src_size); } ================================================ FILE: fusee/program/source/mtc/fusee_mtc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::nxboot { void DoMemoryTrainingErista(int index, void *mtc_tables_buffer); void DoMemoryTrainingMariko(bool *out_did_training, int index, void *mtc_tables_buffer); void RestoreMemoryClockRateMariko(void *mtc_tables_buffer); namespace { alignas(4) constinit u8 g_mtc_tables_buffer[0x26C0]; constinit bool g_did_training_mariko = false; constexpr const u8 MemoryTrainingTableIndex_Invalid = std::numeric_limits<u8>::max(); constexpr const u8 MemoryTrainingTableIndices[] = { /* DramId_EristaIcosaSamsung4gb */ 0x00, /* DramId_EristaIcosaHynix4gb */ 0x02, /* DramId_EristaIcosaMicron4gb */ 0x03, /* DramId_MarikoIowaHynix1y4gb */ 0x10, /* DramId_EristaIcosaSamsung6gb */ 0x01, /* DramId_MarikoHoagHynix1y4gb */ 0x10, /* DramId_MarikoAulaHynix1y4gb */ 0x10, /* DramId_MarikoIowax1x2Samsung4gb */ 0x00, /* DramId_MarikoIowaSamsung4gb */ 0x05, /* DramId_MarikoIowaSamsung8gb */ 0x06, /* DramId_MarikoIowaHynix4gb */ 0x07, /* DramId_MarikoIowaMicron4gb */ 0x08, /* DramId_MarikoHoagSamsung4gb */ 0x05, /* DramId_MarikoHoagSamsung8gb */ 0x06, /* DramId_MarikoHoagHynix4gb */ 0x07, /* DramId_MarikoHoagMicron4gb */ 0x08, /* DramId_MarikoIowaSamsung4gbY */ 0x09, /* DramId_MarikoIowaSamsung1y4gbX */ 0x0C, /* DramId_MarikoIowaSamsung1y8gbX */ 0x0D, /* DramId_MarikoHoagSamsung1y4gbX */ 0x0C, /* DramId_MarikoIowaSamsung1z4gb */ 0x12, /* DramId_MarikoHoagSamsung1z4gb */ 0x12, /* DramId_MarikoAulaSamsung1z4gb */ 0x12, /* DramId_MarikoHoagSamsung1y8gbX */ 0x0D, /* DramId_MarikoAulaSamsung1y4gbX */ 0x0C, /* DramId_MarikoIowaMicron1y4gb */ 0x0F, /* DramId_MarikoHoagMicron1y4gb */ 0x0F, /* DramId_MarikoAulaMicron1y4gb */ 0x0F, /* DramId_MarikoAulaSamsung1y8gbX */ 0x0D, /* DramId_MarikoIowaHynix1a4gb */ 0x13, /* DramId_MarikoHoagHynix1a4gb */ 0x13, /* DramId_MarikoAulaHynix1a4gb */ 0x13, /* DramId_MarikoIowaMicron1a4gb */ 0x14, /* DramId_MarikoHoagMicron1a4gb */ 0x14, /* DramId_MarikoAulaMicron1a4gb */ 0x14, }; int GetMemoryTrainingTableIndex() { if (const auto dram_id = fuse::GetDramId(); dram_id < util::size(MemoryTrainingTableIndices) && MemoryTrainingTableIndices[dram_id] != MemoryTrainingTableIndex_Invalid) { return static_cast<int>(MemoryTrainingTableIndices[dram_id]); } else { return -1; } } } void DoMemoryTraining() { const auto index = GetMemoryTrainingTableIndex(); if (fuse::GetSocType() == fuse::SocType_Erista) { DoMemoryTrainingErista(index, g_mtc_tables_buffer); } else { DoMemoryTrainingMariko(std::addressof(g_did_training_mariko), index, g_mtc_tables_buffer); } } void RestoreMemoryClockRate() { /* NOTE: This resolves an off-by-one issue in PCV's detection of memory clock rate on Mariko. */ if (fuse::GetSocType() == fuse::SocType_Mariko && g_did_training_mariko) { RestoreMemoryClockRateMariko(g_mtc_tables_buffer); } } } ================================================ FILE: fusee/program/source/mtc/fusee_mtc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { void DoMemoryTraining(); void RestoreMemoryClockRate(); } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_erista.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../fusee_fatal.hpp" #include "fusee_mtc.hpp" #include "fusee_mtc_timing_table_erista.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t MC = MC_BASE; constexpr inline const uintptr_t EMC = EMC_BASE; constexpr inline const uintptr_t EMC0 = EMC0_BASE; constexpr inline const uintptr_t EMC1 = EMC1_BASE; static constinit bool g_next_pll = false; static constinit bool g_did_first_training = false; static constinit bool g_fsp_for_next_freq = false; #include "fusee_mtc_tables_erista.inc" #include "fusee_mtc_ram_training_pattern.inc" #define DECLARE_OFFSET_HANDLER(BASE, REG, NAME) REG, #define DECLARE_REGISTER_HANDLER(BASE, REG, NAME) BASE + REG, constexpr inline const u16 BurstRegistersOffsets[] = { FOREACH_BURST_REG(DECLARE_OFFSET_HANDLER) }; constexpr inline const u32 TrimRegisters[] = { FOREACH_TRIM_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 BurstMcRegisters[] = { FOREACH_BURST_MC_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 LaScaleRegisters[] = { FOREACH_LA_SCALE_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelTrimRegisters[] = { FOREACH_PER_CHANNEL_TRIM_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelBurstRegisters[] = { FOREACH_PER_CHANNEL_BURST_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelVrefRegisters[] = { FOREACH_PER_CHANNEL_VREF_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelTrainingModRegisters[] = { FOREACH_PER_CHANNEL_TRAINING_MOD_REG(DECLARE_REGISTER_HANDLER) }; using EmcDvfsTimingTable = erista::EmcDvfsTimingTable; EmcDvfsTimingTable *GetEmcDvfsTimingTables(int index, void *mtc_tables_buffer) { switch (index) { case 0: case 3: //std::memcpy(mtc_tables_buffer, T210SdevEmcDvfsTableS4gb01, sizeof(T210SdevEmcDvfsTableS4gb01)); return reinterpret_cast<EmcDvfsTimingTable *>(const_cast<u8 *>(T210SdevEmcDvfsTableS4gb01)); case 1: //std::memcpy(mtc_tables_buffer, T210SdevEmcDvfsTableS6gb01, sizeof(T210SdevEmcDvfsTableS6gb01)); return reinterpret_cast<EmcDvfsTimingTable *>(const_cast<u8 *>(T210SdevEmcDvfsTableS6gb01)); case 2: //std::memcpy(mtc_tables_buffer, T210SdevEmcDvfsTableH4gb01, sizeof(T210SdevEmcDvfsTableH4gb01)); return reinterpret_cast<EmcDvfsTimingTable *>(const_cast<u8 *>(T210SdevEmcDvfsTableH4gb01)); default: ShowFatalError("Unknown EmcDvfsTimingTableIndex: %d\n", index); } } bool IsSamePll(u32 next_2x, u32 prev_2x) { if (next_2x == prev_2x) { return true; } else if ((next_2x == PLLM_OUT0 || next_2x == PLLM_UD) && (prev_2x == PLLM_OUT0 || prev_2x == PLLM_UD)) { return true; } else { return false; } } bool PllReprogram(u32 next_rate_khz, u32 next_clk_src, u32 prev_rate_khz, u32 prev_clk_src) { /* Get current pll/divp value. */ u32 pll_base, pll_p; switch (reg::GetValue(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLM_UD: case PLLM_OUT0: pll_base = reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE); pll_p = reg::GetField(pll_base, CLK_RST_REG_BITS_MASK(PLLM_BASE_PLLM_DIVP)); break; case PLLMB_UD: case PLLMB_OUT0: pll_base = reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE); pll_p = reg::GetField(pll_base, CLK_RST_REG_BITS_MASK(PLLMB_BASE_PLLMB_DIVP)); break; default: pll_base = 0; pll_p = 0; } /* Check pll divp. */ if (pll_p > 5) { ShowFatalError("Invalid PLL divp: %" PRIu32 "\n", pll_p); } /* Get clk src/divisor. */ const u32 next_2x = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); const u32 prev_2x = reg::GetField(prev_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); u32 next_div = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR)); u32 prev_div = reg::GetField(prev_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR)); /* Update divisor, if necessary. */ if (next_2x == PLLM_UD || next_2x == PLLMB_UD) { next_div = 0; } if (prev_2x == PLLM_UD || prev_2x == PLLMB_UD) { prev_div = 0; } /* If the pll is different, reprogramming is necessary. */ if (!IsSamePll(next_2x, prev_2x)) { return true; } /* Return whether the ratios are different. */ const float next_freq = next_rate_khz * (1 + (next_div >> 1) + (0.5 * (next_div & 1))) * (pll_p + 1); const float prev_freq = prev_rate_khz * (1 + (prev_div >> 1) + (0.5 * (prev_div & 1))) * (pll_p + 1); const float ratio = prev_freq / next_freq; return ratio > 1.01 || ratio < 0.99; } u32 ProgramPllm(u32 next_rate_khz, u32 next_clk_src, bool is_pllmb) { /* Hardcode values for 1600MHz. */ u32 divn, divm, divp; if (next_rate_khz == 1600000) { divn = 0x7D; divm = 0x03; divp = 0x00; } else if (next_rate_khz == 800000) { divn = 0x7D; divm = 0x03; divp = 0x01; } else { ShowFatalError("Unexpected ProgramPllm next rate %" PRIu32 "\n", next_rate_khz); } const auto next_2x = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); if (is_pllmb) { /* Set divisors. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, CLK_RST_REG_BITS_VALUE(PLLMB_BASE_PLLMB_DIVM, divm), CLK_RST_REG_BITS_VALUE(PLLMB_BASE_PLLMB_DIVN, divn), CLK_RST_REG_BITS_VALUE(PLLMB_BASE_PLLMB_DIVP, divp)); reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE); /* Set enable. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, CLK_RST_REG_BITS_ENUM(PLLMB_BASE_PLLMB_ENABLE, ENABLE)); /* Adjust next clock source. */ if (next_2x == PLLM_UD) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_UD)); } else if (next_2x == PLLM_OUT0) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_OUT0)); } /* Wait for pll to lock. */ while (!reg::HasValue(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, CLK_RST_REG_BITS_ENUM(PLLMB_BASE_PLLMB_LOCK, LOCK))) { /* ... */ } } else { /* Set divisors. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVM, divm), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVN, divn), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVP, divp)); reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE); /* Set LKCDET. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC2, CLK_RST_REG_BITS_ENUM(PLLM_MISC2_PLLM_EN_LCKDET, ENABLE)); /* Set enable. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_ENUM(PLLM_BASE_PLLM_ENABLE, ENABLE)); /* Adjust next clock source. */ if (next_2x == PLLM_UD) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLM_UD)); } else if (next_2x == PLLM_OUT0) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLM_OUT0)); } /* Wait for pll to lock. */ while (!reg::HasValue(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_ENUM(PLLM_BASE_PLLM_LOCK, LOCK))) { /* ... */ } } return next_clk_src; } u32 GetDllState(EmcDvfsTimingTable *timing) { return (!(timing->emc_emrs & 0x1)) ? DLL_ON : DLL_OFF; } int WaitForUpdate(u32 reg_offset, u32 mask, bool updated, u32 fbio_cfg7) { constexpr int StatusUpdateTimeout = 1000; int result = 0; if (true /* reg::HasValue(fbio_cfg7, EMC_REG_BITS_ENUM(FBIO_CFG7_CH0_ENABLE, ENABLE)) */) { bool success = false; for (int i = 0; i < StatusUpdateTimeout; ++i) { if (((reg::Read(EMC + reg_offset) & mask) != 0) == updated) { success = true; break; } util::WaitMicroSeconds(1); } result |= success ? 0 : 4; } if (reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE) { bool success = false; for (int i = 0; i < StatusUpdateTimeout; ++i) { if (((reg::Read(EMC1 + reg_offset) & mask) != 0) == updated) { success = true; break; } util::WaitMicroSeconds(1); } result |= success ? 0 : 4; } return result; } void TimingUpdate(u32 fbio_cfg7) { /* Trigger the timing update event. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); /* Wait for the update to finish. */ WaitForUpdate(EMC_EMC_STATUS, 0x800000, false, fbio_cfg7); } void DllDisable(u32 fbio_cfg7) { /* Disable dll. */ reg::ClearBits(EMC + EMC_CFG_DIG_DLL, 0x1); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait until CFG_DLL_EN is cleared. */ WaitForUpdate(EMC_CFG_DIG_DLL, 0x1, false, fbio_cfg7); } void DllEnableStall(u32 fbio_cfg7) { /* Enable DLL */ uint32_t emc_cfg_dig_dll = (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x89; reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait until CFG_DLL_EN is set for EMC */ WaitForUpdate(EMC_CFG_DIG_DLL, 0x1, true, fbio_cfg7); } void ChangeDllSrc(EmcDvfsTimingTable *dst_timing, u32 next_clk_src) { u32 dll_setting = ((next_clk_src & 0xE00000FF) | (dst_timing->dll_clk_src & 0x1FFFFF00)) & 0xFFFFF3FF; switch (reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLMB_UD: dll_setting |= 0x400; /* PLLM_VCOB */ break; case PLLM_UD: dll_setting |= 0x000; /* PLLM_VCOA */ break; default: dll_setting |= 0x800; /* EMC_DLL_SWITCH_OUT */ break; } reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL, dll_setting); reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X); util::WaitMicroSeconds(2); if (dst_timing->clk_out_enb_x_0_clk_enb_emc_dll) { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_EMC_DLL, ENABLE)); } else { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_EMC_DLL, ENABLE)); } reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X); util::WaitMicroSeconds(2); } void SetShadowBypass(u32 val) { reg::ReadWrite(EMC + EMC_DBG, EMC_REG_BITS_VALUE(DBG_WRITE_MUX, val)); } u32 DllPrelock(EmcDvfsTimingTable *dst_timing, bool training_enabled, u32 next_clk_src) { /* Check for dual channel LPDDR4 */ u32 fbio_cfg7 = reg::Read(EMC + EMC_FBIO_CFG7); uint32_t emc_dig_dll_status = 0; uint32_t emc_cfg_dig_dll = (reg::Read(EMC1 + EMC_CFG_DIG_DLL) & 0xFFFFF824) | 0x3C8; /* Update EMC_CFG_DIG_DLL_0 */ reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait until CFG_DLL_EN is cleared for EMC */ WaitForUpdate(EMC_CFG_DIG_DLL, 0x1, false, fbio_cfg7); reg::Write(EMC + EMC_DLL_CFG_0, dst_timing->burst_regs.emc_dll_cfg_0); reg::Write(EMC + EMC_DLL_CFG_1, dst_timing->burst_regs.emc_dll_cfg_1); /* Configure the clock and reset controller for EMC DLL */ ChangeDllSrc(dst_timing, next_clk_src); /* Enable DLL */ reg::SetBits(EMC + EMC_CFG_DIG_DLL, 0x1); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait until CFG_DLL_EN is set for EMC */ WaitForUpdate(EMC_CFG_DIG_DLL, 0x1, true, fbio_cfg7); /* Wait until DLL_PRIV_UPDATED or DLL_LOCK have been cleared */ do { emc_dig_dll_status = reg::Read(EMC + EMC_DIG_DLL_STATUS); } while ((~emc_dig_dll_status & 0x28000) != 0); if (training_enabled) { /* Set WRITE_MUX to ACTIVE */ SetShadowBypass(ACTIVE); /* Disable DLL */ reg::ClearBits(EMC + EMC_CFG_DIG_DLL, 0x1); /* Set WRITE_MUX to ASSEMBLY */ SetShadowBypass(ASSEMBLY); /* Wait until CFG_DLL_EN is cleared for EMC */ WaitForUpdate(EMC_CFG_DIG_DLL, 0x1, false, fbio_cfg7); } /* Return the DLL_OUT value */ return (reg::Read(EMC1 + EMC_DIG_DLL_STATUS) & 0x7FF); } void CcfifoWrite(u32 addr, u32 data, u32 wait) { reg::Write(EMC + EMC_CCFIFO_DATA, data); reg::Write(EMC + EMC_CCFIFO_ADDR, (addr & 0xFFFF) | ((wait & 0x7FFF) << 16) | 0x80000000); } u32 ActualOscClocks(u32 in) { if (in < 0x40) { return in * 0x10; } else if (in < 0x80) { return 0x800; } else if (in < 0xC0) { return 0x1000; } else { return 0x2000; } } void StartPeriodicCompensation() { reg::Write(EMC + EMC_MPC, 0x4B); reg::Read(EMC + EMC_MPC); } u32 UpdateClockTreeDelay(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 dram_dev_num, u32 fbio_cfg7, int type) { uint32_t mrr_req = 0, mrr_data = 0; uint32_t temp0_0 = 0, temp0_1 = 0, temp1_0 = 0, temp1_1 = 0; int tdel = 0, tmdel = 0, adel = 0; uint32_t cval; uint32_t src_timing_rate_mhz = (src_timing->rate_khz / 1000); uint32_t dst_timing_rate_mhz = (dst_timing->rate_khz / 1000); bool dvfs_pt1 = (type == DVFS_PT1); bool training_pt1 = (type == TRAINING_PT1); bool dvfs_update = (type == DVFS_UPDATE); bool training_update = (type == TRAINING_UPDATE); bool periodic_training_update = (type == PERIODIC_TRAINING_UPDATE); const bool dual_channel = reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE; /* Dev0 MSB. */ if (dvfs_pt1 || training_pt1 || periodic_training_update) { mrr_req = ((2 << 30) | (19 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, 0x100000, true, fbio_cfg7); mrr_data = ((reg::Read(EMC + EMC_MRR) & 0xFFFF) << 0); temp0_0 = ((mrr_data & 0xff) << 8); temp0_1 = (mrr_data & 0xff00); if (dual_channel) { mrr_data = ((reg::Read(EMC1 + EMC_MRR) & 0xFFFF) << 0); temp1_0 = ((mrr_data & 0xff) << 8); temp1_1 = (mrr_data & 0xff00); } /* Dev0 LSB. */ mrr_req = ((mrr_req & ~0xFF0000) | (18 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, 0x100000, true, fbio_cfg7); mrr_data = ((reg::Read(EMC + EMC_MRR) & 0xFFFF) << 0); temp0_0 |= (mrr_data & 0xff); temp0_1 |= ((mrr_data & 0xff00) >> 8); if (dual_channel) { mrr_data = ((reg::Read(EMC1 + EMC_MRR) & 0xFFFF) << 0); temp1_0 |= (mrr_data & 0xff); temp1_1 |= ((mrr_data & 0xff00) >> 8); } } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp0_0)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d0u0, cval); else if (dvfs_update) __AVERAGE_PTFV(c0d0u0); else if (training_update) __AVERAGE_WRITE_PTFV(c0d0u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d0u0, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c0d0u0 - __MOVAVG_AC(dst_timing, c0d0u0)); tmdel = (tdel < 0) ? -1 * tdel : tdel; adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d0u0 = __MOVAVG_AC(dst_timing, c0d0u0); } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp0_1)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d0u1, cval); else if (dvfs_update) __AVERAGE_PTFV(c0d0u1); else if (training_update) __AVERAGE_WRITE_PTFV(c0d0u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d0u1, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c0d0u1 - __MOVAVG_AC(dst_timing, c0d0u1); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d0u1 = __MOVAVG_AC(dst_timing, c0d0u1); } if (dual_channel) { cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp1_0)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d0u0, cval); else if (dvfs_update) __AVERAGE_PTFV(c1d0u0); else if (training_update) __AVERAGE_WRITE_PTFV(c1d0u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d0u0, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c1d0u0 - __MOVAVG_AC(dst_timing, c1d0u0); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d0u0 = __MOVAVG_AC(dst_timing, c1d0u0); } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp1_1)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d0u1, cval); else if (dvfs_update) __AVERAGE_PTFV(c1d0u1); else if (training_update) __AVERAGE_WRITE_PTFV(c1d0u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d0u1, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c1d0u1 - __MOVAVG_AC(dst_timing, c1d0u1); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d0u1 = __MOVAVG_AC(dst_timing, c1d0u1); } } if (dram_dev_num != TWO_RANK) return adel; /* Dev1 MSB. */ if (dvfs_pt1 || training_pt1 || periodic_training_update) { mrr_req = ((1 << 30) | (19 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, 0x100000, true, fbio_cfg7); mrr_data = ((reg::Read(EMC + EMC_MRR) & 0xFFFF) << 0); temp0_0 = ((mrr_data & 0xff) << 8); temp0_1 = (mrr_data & 0xff00); if (dual_channel) { mrr_data = ((reg::Read(EMC1 + EMC_MRR) & 0xFFFF) << 0); temp1_0 = ((mrr_data & 0xff) << 8); temp1_1 = (mrr_data & 0xff00); } /* Dev1 LSB. */ mrr_req = ((mrr_req & ~0xFF0000) | (18 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, 0x100000, true, fbio_cfg7); mrr_data = ((reg::Read(EMC + EMC_MRR) & 0xFFFF) << 0); temp0_0 |= (mrr_data & 0xff); temp0_1 |= ((mrr_data & 0xff00) >> 8); if (dual_channel) { mrr_data = ((reg::Read(EMC1 + EMC_MRR) & 0xFFFF) << 0); temp1_0 |= (mrr_data & 0xff); temp1_1 |= ((mrr_data & 0xff00) >> 8); } } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp0_0)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d1u0, cval); else if (dvfs_update) __AVERAGE_PTFV(c0d1u0); else if (training_update) __AVERAGE_WRITE_PTFV(c0d1u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d1u0, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c0d1u0 - __MOVAVG_AC(dst_timing, c0d1u0); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d1u0 = __MOVAVG_AC(dst_timing, c0d1u0); } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp0_1)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d1u1, cval); else if (dvfs_update) __AVERAGE_PTFV(c0d1u1); else if (training_update) __AVERAGE_WRITE_PTFV(c0d1u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d1u1, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c0d1u1 - __MOVAVG_AC(dst_timing, c0d1u1); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d1u1 = __MOVAVG_AC(dst_timing, c0d1u1); } if (dual_channel) { cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp1_0)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d1u0, cval); else if (dvfs_update) __AVERAGE_PTFV(c1d1u0); else if (training_update) __AVERAGE_WRITE_PTFV(c1d1u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d1u0, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c1d1u0 - __MOVAVG_AC(dst_timing, c1d1u0); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d1u0 = __MOVAVG_AC(dst_timing, c1d1u0); } cval = ((1000000 * ActualOscClocks(src_timing->run_clocks)) / (src_timing_rate_mhz * 2 * temp1_1)); if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d1u1, cval); else if (dvfs_update) __AVERAGE_PTFV(c1d1u1); else if (training_update) __AVERAGE_WRITE_PTFV(c1d1u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d1u1, cval); if (dvfs_update || training_update || periodic_training_update) { tdel = dst_timing->current_dram_clktree_c1d1u1 - __MOVAVG_AC(dst_timing, c1d1u1); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if ((tmdel * 128 * dst_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d1u1 = __MOVAVG_AC(dst_timing, c1d1u1); } } if (training_update) { dst_timing->trained_dram_clktree_c0d0u0 = dst_timing->current_dram_clktree_c0d0u0; dst_timing->trained_dram_clktree_c0d0u1 = dst_timing->current_dram_clktree_c0d0u1; dst_timing->trained_dram_clktree_c0d1u0 = dst_timing->current_dram_clktree_c0d1u0; dst_timing->trained_dram_clktree_c0d1u1 = dst_timing->current_dram_clktree_c0d1u1; dst_timing->trained_dram_clktree_c1d0u0 = dst_timing->current_dram_clktree_c1d0u0; dst_timing->trained_dram_clktree_c1d0u1 = dst_timing->current_dram_clktree_c1d0u1; dst_timing->trained_dram_clktree_c1d1u0 = dst_timing->current_dram_clktree_c1d1u0; dst_timing->trained_dram_clktree_c1d1u1 = dst_timing->current_dram_clktree_c1d1u1; } return adel; } u32 PeriodicCompensationHandler(int type, u32 dram_dev_num, u32 fbio_cfg7, EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing) { #define __COPY_EMA(nt, lt, dev) \ ({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \ (nt)->ptfv_dvfs_samples; }) uint32_t adel = 0; uint32_t samples = dst_timing->ptfv_dvfs_samples; uint32_t samples_write = dst_timing->ptfv_write_samples; uint32_t delay = 2 + (1000 * ActualOscClocks(src_timing->run_clocks) / src_timing->rate_khz); if (!dst_timing->periodic_training) return 0; if (type == DVFS_SEQUENCE) { if (src_timing->periodic_training && (dst_timing->ptfv_config_ctrl & 1)) { /* * If the previous frequency was using periodic * calibration then we can reuse the previous * frequencies EMA data. */ __COPY_EMA(dst_timing, src_timing, c0d0u0); __COPY_EMA(dst_timing, src_timing, c0d0u1); __COPY_EMA(dst_timing, src_timing, c1d0u0); __COPY_EMA(dst_timing, src_timing, c1d0u1); __COPY_EMA(dst_timing, src_timing, c0d1u0); __COPY_EMA(dst_timing, src_timing, c0d1u1); __COPY_EMA(dst_timing, src_timing, c1d1u0); __COPY_EMA(dst_timing, src_timing, c1d1u1); } else { /* Reset the EMA.*/ __MOVAVG(dst_timing, c0d0u0) = 0; __MOVAVG(dst_timing, c0d0u1) = 0; __MOVAVG(dst_timing, c1d0u0) = 0; __MOVAVG(dst_timing, c1d0u1) = 0; __MOVAVG(dst_timing, c0d1u0) = 0; __MOVAVG(dst_timing, c0d1u1) = 0; __MOVAVG(dst_timing, c1d1u0) = 0; __MOVAVG(dst_timing, c1d1u1) = 0; for (uint32_t i = 0; i < samples; i++) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); /* Generate next sample of data. */ adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, fbio_cfg7, DVFS_PT1); } } adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, fbio_cfg7, DVFS_UPDATE); } else if (type == WRITE_TRAINING_SEQUENCE) { /* Reset the EMA.*/ __MOVAVG(dst_timing, c0d0u0) = 0; __MOVAVG(dst_timing, c0d0u1) = 0; __MOVAVG(dst_timing, c1d0u0) = 0; __MOVAVG(dst_timing, c1d0u1) = 0; __MOVAVG(dst_timing, c0d1u0) = 0; __MOVAVG(dst_timing, c0d1u1) = 0; __MOVAVG(dst_timing, c1d1u0) = 0; __MOVAVG(dst_timing, c1d1u1) = 0; for (uint32_t i = 0; i < samples_write; i++) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); /* Generate next sample of data. */ UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, fbio_cfg7, TRAINING_PT1); } adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, fbio_cfg7, TRAINING_UPDATE); } else if (type == PERIODIC_TRAINING_SEQUENCE) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, fbio_cfg7, PERIODIC_TRAINING_UPDATE); } return adel; } uint32_t ApplyPeriodicCompensationTrimmer(EmcDvfsTimingTable *dst_timing, uint32_t offset) { #define TRIM_REG(chan, rank, reg, byte) \ ((EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## reg ## \ _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte ## _MASK & \ dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank ## rank ## _ ## reg ) >> \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## reg ## \ _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte ## _SHIFT) \ + \ (((EMC_DATA_BRLSHFT_ ## rank ## _RANK ## rank ## _BYTE ## \ byte ## _DATA_BRLSHFT_MASK & \ dst_timing->trim_perch_regs.emc ## chan ## _data_brlshft_ ## rank ) >> \ EMC_DATA_BRLSHFT_ ## rank ## _RANK ## rank ## _BYTE ## \ byte ## _DATA_BRLSHFT_SHIFT) * 64) #define CALC_TEMP(rank, reg, byte1, byte2, n) \ ((adj[n] << EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## \ reg ## _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte1 ## _SHIFT) & \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## reg ## \ _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte1 ## _MASK) \ | \ ((adj[n + 1] << EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## \ reg ## _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte2 ## _SHIFT) & \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK ## rank ## _ ## reg ## \ _OB_DDLL_LONG_DQ_RANK ## rank ## _BYTE ## byte2 ## _MASK) \ uint32_t temp = 0; uint32_t dst_rate_mhz = dst_timing->rate_khz / 1000; int tree_delta[4] = {0}; u32 tree_delta_taps[4] = {0}; int adj[] = { static_cast<int>(TRIM_REG(0, 0, 0, 0)), static_cast<int>(TRIM_REG(0, 0, 0, 1)), static_cast<int>(TRIM_REG(0, 0, 1, 2)), static_cast<int>(TRIM_REG(0, 0, 1, 3)), static_cast<int>(TRIM_REG(1, 0, 2, 4)), static_cast<int>(TRIM_REG(1, 0, 2, 5)), static_cast<int>(TRIM_REG(1, 0, 3, 6)), static_cast<int>(TRIM_REG(1, 0, 3, 7)), static_cast<int>(TRIM_REG(0, 1, 0, 0)), static_cast<int>(TRIM_REG(0, 1, 0, 1)), static_cast<int>(TRIM_REG(0, 1, 1, 2)), static_cast<int>(TRIM_REG(0, 1, 1, 3)), static_cast<int>(TRIM_REG(1, 1, 2, 4)), static_cast<int>(TRIM_REG(1, 1, 2, 5)), static_cast<int>(TRIM_REG(1, 1, 3, 6)), static_cast<int>(TRIM_REG(1, 1, 3, 7)) }; switch (offset) { case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3: case EMC_DATA_BRLSHFT_0: tree_delta[0] = 128 * (dst_timing->current_dram_clktree_c0d0u0 - dst_timing->trained_dram_clktree_c0d0u0); tree_delta[1] = 128 * (dst_timing->current_dram_clktree_c0d0u1 - dst_timing->trained_dram_clktree_c0d0u1); tree_delta[2] = 128 * (dst_timing->current_dram_clktree_c1d0u0 - dst_timing->trained_dram_clktree_c1d0u0); tree_delta[3] = 128 * (dst_timing->current_dram_clktree_c1d0u1 - dst_timing->trained_dram_clktree_c1d0u1); tree_delta_taps[0] = (tree_delta[0] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[1] = (tree_delta[1] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[2] = (tree_delta[2] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[3] = (tree_delta[3] * static_cast<int>(dst_rate_mhz)) / 1000000; for (int i = 0; i < 4; i++) { if ((tree_delta_taps[i] > dst_timing->tree_margin) || (tree_delta_taps[i] < (-1 * dst_timing->tree_margin))) { adj[i * 2] = adj[i * 2] + tree_delta_taps[i]; adj[i * 2 + 1] = adj[i * 2 + 1] + tree_delta_taps[i]; } } if (offset == EMC_DATA_BRLSHFT_0) { for (int i = 0; i < 8; i++) { adj[i] = adj[i] / 64; } } else { for (int i = 0; i < 8; i++) { adj[i] = adj[i] % 64; } } break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2: case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3: case EMC_DATA_BRLSHFT_1: tree_delta[0] = 128 * (dst_timing->current_dram_clktree_c0d1u0 - dst_timing->trained_dram_clktree_c0d1u0); tree_delta[1] = 128 * (dst_timing->current_dram_clktree_c0d1u1 - dst_timing->trained_dram_clktree_c0d1u1); tree_delta[2] = 128 * (dst_timing->current_dram_clktree_c1d1u0 - dst_timing->trained_dram_clktree_c1d1u0); tree_delta[3] = 128 * (dst_timing->current_dram_clktree_c1d1u1 - dst_timing->trained_dram_clktree_c1d1u1); tree_delta_taps[0] = (tree_delta[0] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[1] = (tree_delta[1] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[2] = (tree_delta[2] * static_cast<int>(dst_rate_mhz)) / 1000000; tree_delta_taps[3] = (tree_delta[3] * static_cast<int>(dst_rate_mhz)) / 1000000; for (int i = 0; i < 4; i++) { if ((tree_delta_taps[i] > dst_timing->tree_margin) || (tree_delta_taps[i] < (-1 * dst_timing->tree_margin))) { adj[8 + i * 2] = adj[8 + i * 2] + tree_delta_taps[i]; adj[8 + i * 2 + 1] = adj[8 + i * 2 + 1] + tree_delta_taps[i]; } } if (offset == EMC_DATA_BRLSHFT_1) { for (int i = 0; i < 8; i++) { adj[i + 8] = adj[i + 8] / 64; } } else { for (int i = 0; i < 8; i++) { adj[i + 8] = adj[i + 8] % 64; } } break; } switch (offset) { case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0: temp = CALC_TEMP(0, 0, 0, 1, 0); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1: temp = CALC_TEMP(0, 1, 2, 3, 2); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2: temp = CALC_TEMP(0, 2, 4, 5, 4); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3: temp = CALC_TEMP(0, 3, 6, 7, 6); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0: temp = CALC_TEMP(1, 0, 0, 1, 8); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1: temp = CALC_TEMP(1, 1, 2, 3, 10); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2: temp = CALC_TEMP(1, 2, 4, 5, 12); break; case EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3: temp = CALC_TEMP(1, 3, 6, 7, 14); break; case EMC_DATA_BRLSHFT_0: temp = ((adj[0] << EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_MASK) | ((adj[1] << EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_MASK) | ((adj[2] << EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_MASK) | ((adj[3] << EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_MASK) | ((adj[4] << EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_MASK) | ((adj[5] << EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_MASK) | ((adj[6] << EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_MASK) | ((adj[7] << EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_MASK); break; case EMC_DATA_BRLSHFT_1: temp = ((adj[8] << EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_MASK) | ((adj[9] << EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_MASK) | ((adj[10] << EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_MASK) | ((adj[11] << EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_MASK) | ((adj[12] << EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_MASK) | ((adj[13] << EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_MASK) | ((adj[14] << EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_MASK) | ((adj[15] << EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT) & EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_MASK); break; default: break; } #undef TRIM_REG #undef CALC_TEMP return temp; } uint32_t DvfsPowerRampDown(bool flip_backward, EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, uint32_t clk) { uint32_t ramp_down_wait = 0; uint32_t seq_wait = 0; uint32_t pmacro_cmd_pad = 0; uint32_t pmacro_dq_pad = 0; uint32_t pmacro_cfg5 = 0; uint32_t pmacro_rfu1 = 0; uint32_t pmacro_common_tx = 0; if (flip_backward) { pmacro_cmd_pad = dst_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = dst_timing->burst_regs.emc_fbio_cfg5; pmacro_common_tx = dst_timing->burst_regs.emc_pmacro_common_pad_tx_ctrl; } else { pmacro_cmd_pad = src_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = ((dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & 0x101) | src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl); pmacro_rfu1 = src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = src_timing->burst_regs.emc_fbio_cfg5; pmacro_common_tx = src_timing->burst_regs.emc_pmacro_common_pad_tx_ctrl; } pmacro_cmd_pad |= (1 << 26); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, 0); CcfifoWrite(EMC_FBIO_CFG5, pmacro_cfg5 | (1 << 8), 12); ramp_down_wait = clk * 12; seq_wait = (100000 / clk) + 1; if (clk < (1000000 / 1000)) { if (clk < (1000000 / 2400)) { pmacro_cmd_pad &= ~((1 << 1) | (1 << 24)); pmacro_cmd_pad |= (1 << 9) | (1 << 16); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, seq_wait); ramp_down_wait += 100000; pmacro_dq_pad &= ~((1 << 1) | (1 << 24)); pmacro_dq_pad |= (1 << 9) | (1 << 16); CcfifoWrite(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x01120112, 0); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x01120112, seq_wait); ramp_down_wait += 100000; } CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x01bf01bf, seq_wait); ramp_down_wait += 100000; if (clk < (1000000 / 2400)) { pmacro_cmd_pad &= ~((1 << 1) | (1 << 24) | (1 << 9) | (1 << 16)); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, seq_wait); ramp_down_wait += 100000; pmacro_dq_pad &= ~((1 << 1) | (1 << 24) | (1 << 9) | (1 << 16)); CcfifoWrite(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x07ff07ff, 0); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x07ff07ff, seq_wait); ramp_down_wait += 100000; } } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & ~0x07ff07ff, seq_wait + 19); ramp_down_wait += (100000 + (20 * clk)); } if (clk < (1000000 / 600)) { ramp_down_wait += 100000; CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & ~0x5, seq_wait); ramp_down_wait += 100000; CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & ~0xf, seq_wait); ramp_down_wait += 100000; CcfifoWrite(0, 0, seq_wait); ramp_down_wait += 100000; } else { CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & ~0xf, seq_wait); } return ramp_down_wait; } uint32_t DvfsPowerRampUp(bool flip_backward, EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, uint32_t training, uint32_t clk) { uint32_t ramp_up_wait = 0; uint32_t pmacro_cmd_pad = 0; uint32_t pmacro_dq_pad = 0; uint32_t pmacro_cfg5 = 0; uint32_t pmacro_rfu1 = 0; uint32_t pmacro_common_tx = 0; if (flip_backward) { pmacro_cmd_pad = src_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = src_timing->burst_regs.emc_fbio_cfg5; pmacro_common_tx = src_timing->burst_regs.emc_pmacro_common_pad_tx_ctrl; } else if (training & 3) { pmacro_cmd_pad = dst_timing->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = dst_timing->shadow_regs_ca_train.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = dst_timing->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = dst_timing->shadow_regs_ca_train.emc_fbio_cfg5; pmacro_common_tx = dst_timing->shadow_regs_ca_train.emc_pmacro_common_pad_tx_ctrl; } else if (training & 0xC) { pmacro_cmd_pad = dst_timing->shadow_regs_quse_train.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = dst_timing->shadow_regs_quse_train.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = dst_timing->shadow_regs_quse_train.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = dst_timing->shadow_regs_quse_train.emc_fbio_cfg5; pmacro_common_tx = dst_timing->shadow_regs_quse_train.emc_pmacro_common_pad_tx_ctrl; } else if (training & 0xF0) { pmacro_cmd_pad = dst_timing->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = dst_timing->shadow_regs_rdwr_train.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = dst_timing->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = dst_timing->shadow_regs_rdwr_train.emc_fbio_cfg5; pmacro_common_tx = dst_timing->shadow_regs_rdwr_train.emc_pmacro_common_pad_tx_ctrl; } else { pmacro_cmd_pad = dst_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; pmacro_dq_pad = dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; pmacro_rfu1 = dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; pmacro_cfg5 = dst_timing->burst_regs.emc_fbio_cfg5; pmacro_common_tx = dst_timing->burst_regs.emc_pmacro_common_pad_tx_ctrl; } pmacro_cmd_pad |= (1 << 26); if (clk < 1000000 / 600) { CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xa, 0); CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx & 0xf, (100000 / clk) + 1); ramp_up_wait += 100000; } else { CcfifoWrite(EMC_PMACRO_COMMON_PAD_TX_CTRL, pmacro_common_tx | 0x8, 0); } if (clk < 1000000 / 1000) { if (clk < 1000000 / 2400) { pmacro_cmd_pad |= ((1 << 9) | (1 << 16)); pmacro_cmd_pad &= ~((1 << 1) | (1 << 24)); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, (100000 / clk) + 1); ramp_up_wait += 100000; pmacro_dq_pad |= ((1 << 9) | (1 << 16)); pmacro_dq_pad &= ~((1 << 1) | (1 << 24)); CcfifoWrite(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xfe40fe40, 0); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xfe40fe40, (100000 / clk) + 1); ramp_up_wait += 100000; } CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 & 0xfeedfeed, (100000 / clk) + 1); ramp_up_wait += 100000; if (clk < 1000000 / 2400) { pmacro_cmd_pad |= ((1 << 9) | (1 << 16) | (1 << 1) | (1 << 24)); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, (100000 / clk) + 1); ramp_up_wait += 100000; pmacro_dq_pad |= ((1 << 9) | (1 << 16) | (1 << 1) | (1 << 24)); CcfifoWrite(EMC_PMACRO_DATA_PAD_TX_CTRL, pmacro_dq_pad, 0); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, 0); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1, (100000 / clk) + 1); ramp_up_wait += 100000; } CcfifoWrite(EMC_FBIO_CFG5, pmacro_cfg5 & ~(1 << 8), (100000 / clk) + 10); ramp_up_wait += (100000 + (10 * clk)); } else if (clk < 1000000 / 600) { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x06000600, (100000 / clk) + 1); CcfifoWrite(EMC_FBIO_CFG5, pmacro_cfg5 & ~(1 << 8), (100000 / clk) + 10); ramp_up_wait += (100000 + 10 * clk); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, pmacro_rfu1 | 0x00000600, 0); CcfifoWrite(EMC_FBIO_CFG5, pmacro_cfg5 & ~(1 << 8), 12); ramp_up_wait += (12 * clk); } pmacro_cmd_pad &= ~(1 << 26); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, pmacro_cmd_pad, 5); return ramp_up_wait; } void FreqChange(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 training, u32 next_clk_src) { /* Extract training values. */ const bool train_ca = (training & CA_TRAINING); const bool train_ca_vref = (training & CA_VREF_TRAINING); const bool train_quse = (training & QUSE_TRAINING); const bool train_quse_vref = (training & QUSE_VREF_TRAINING); const bool train_wr = (training & WRITE_TRAINING); const bool train_wr_vref = (training & WRITE_VREF_TRAINING); const bool train_rd = (training & READ_TRAINING); const bool train_rd_vref = (training & READ_VREF_TRAINING); const bool train_second_rank = (training & TRAIN_SECOND_RANK); const bool train_bit_level = (training & BIT_LEVEL_TRAINING); /* Check if we should do training. */ const bool training_enabled = (training & (CA_TRAINING | CA_VREF_TRAINING | QUSE_TRAINING | WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING)); /* Declare variables. */ bool skip_zqcal = false; bool compensate_trimmer_applicable = false; uint32_t zqcal_before_cc_cutoff = 2400; /* In picoseconds */ int zq_latch_dvfs_wait_time; uint32_t mr13_catr_enable; uint32_t mr13_flip_fspwr; uint32_t mr13_flip_fspop; int next_push, next_dq_e_ivref, next_dqs_e_ivref; uint32_t zq_wait_long; uint32_t zq_wait_short; uint32_t tRTM; uint32_t RP_war; uint32_t R2P_war; uint32_t TRPab_war; int nRTP; uint32_t deltaTWATM; uint32_t W2P_war; uint32_t tRPST; uint32_t mrw_req; uint32_t adel = 0; uint32_t dst_rate_mhz = dst_timing->rate_khz / 1000; /* Set some common values needed. */ const int dram_type = reg::GetValue(EMC + EMC_FBIO_CFG5, EMC_REG_BITS_MASK(FBIO_CFG5_DRAM_TYPE)); const int dram_dev_num = (reg::Read(MC + MC_EMEM_ADR_CFG) & 1) + 1; const bool shared_zq_resistor = ((src_timing->burst_regs.emc_zcal_wait_cnt >> 31) & 1); const u32 fbio_cfg7 = src_timing->burst_regs.emc_fbio_cfg7; const bool is_lpddr3 = (dram_type == DRAM_TYPE_LPDDR2) && ((dst_timing->burst_regs.emc_fbio_cfg5 >> 25) & 1); bool opt_zcal_en_cc = ((dst_timing->burst_regs.emc_zcal_interval && !src_timing->burst_regs.emc_zcal_interval) || (dram_type == DRAM_TYPE_LPDDR4)); bool opt_war_200024907 = (dram_type == DRAM_TYPE_LPDDR4); bool opt_do_sw_qrst = false; bool opt_cc_short_zcal = true; bool opt_short_zcal = true; bool save_restore_clkstop_pd = true; uint32_t opt_dll_mode = (dram_type == DRAM_TYPE_DDR4) ? GetDllState(dst_timing) : DLL_OFF; uint32_t opt_dvfs_mode = MAN_SR; uint32_t emc_auto_cal_config = reg::Read(EMC + EMC_AUTO_CAL_CONFIG); /* In picoseconds. */ uint32_t source_clock_period = 1000000000 / src_timing->rate_khz; uint32_t destination_clock_period = 1000000000 / dst_timing->rate_khz; uint32_t tFC_lpddr4 = 1000 * dst_timing->dram_timings.t_fc_lpddr4; uint32_t tZQCAL_lpddr4 = 1000000; int tZQCAL_lpddr4_fc_adj = (source_clock_period > zqcal_before_cc_cutoff) ? tZQCAL_lpddr4 / destination_clock_period : (tZQCAL_lpddr4 - tFC_lpddr4) / destination_clock_period; g_fsp_for_next_freq = !g_fsp_for_next_freq; uint32_t emc_dbg_o = reg::Read(EMC + EMC_DBG); uint32_t emc_pin_o = reg::Read(EMC + EMC_PIN); uint32_t emc_cfg_pipe_clk_o = reg::Read(EMC + EMC_CFG_PIPE_CLK); uint32_t emc_dbg = emc_dbg_o; uint32_t emc_cfg = dst_timing->burst_regs.emc_cfg & 0x0FFFFFFF; uint32_t emc_sel_dpd_ctrl = dst_timing->emc_sel_dpd_ctrl & 0xFFFFFEC3; /* Step 1.1: Disable DLL. */ DllDisable(fbio_cfg7); /* Step 1.2: Disable AUTOCAL. */ emc_auto_cal_config = dst_timing->emc_auto_cal_config; u32 auto_cal_en = (emc_auto_cal_config & (1 << 29)); emc_auto_cal_config &= 0x7FFFF9FF; emc_auto_cal_config |= 0x600; reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); /* Step 1.3: Disable other power features. */ SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_CFG, emc_cfg); reg::Write(EMC + EMC_SEL_DPD_CTRL, emc_sel_dpd_ctrl); SetShadowBypass(ASSEMBLY); /* Skip this if training_enabled is set. */ if (!training_enabled && dst_timing->periodic_training) { /* Wait for DRAM to get out of power down. */ if (dram_dev_num == TWO_RANK) { WaitForUpdate(EMC_EMC_STATUS, 0x30, false, fbio_cfg7); } else { WaitForUpdate(EMC_EMC_STATUS, 0x10, false, fbio_cfg7); } /* Wait for DRAM to get out of self refresh. */ WaitForUpdate(EMC_EMC_STATUS, 0x300, false, fbio_cfg7); /* Reset all clock tree values. */ dst_timing->current_dram_clktree_c0d0u0 = dst_timing->trained_dram_clktree_c0d0u0; dst_timing->current_dram_clktree_c0d0u1 = dst_timing->trained_dram_clktree_c0d0u1; dst_timing->current_dram_clktree_c0d1u0 = dst_timing->trained_dram_clktree_c0d1u0; dst_timing->current_dram_clktree_c0d1u1 = dst_timing->trained_dram_clktree_c0d1u1; dst_timing->current_dram_clktree_c1d0u0 = dst_timing->trained_dram_clktree_c1d0u0; dst_timing->current_dram_clktree_c1d0u1 = dst_timing->trained_dram_clktree_c1d0u1; dst_timing->current_dram_clktree_c1d1u0 = dst_timing->trained_dram_clktree_c1d1u0; dst_timing->current_dram_clktree_c1d1u1 = dst_timing->trained_dram_clktree_c1d1u1; /* Do DVFS_SEQUENCE. */ adel = PeriodicCompensationHandler(DVFS_SEQUENCE, dram_dev_num, fbio_cfg7, src_timing, dst_timing); /* Check if we should use compensate trimmer. */ compensate_trimmer_applicable = dst_timing->periodic_training && ((adel * 128 * dst_rate_mhz) / 1000000) > dst_timing->tree_margin; } reg::Write(EMC + EMC_INTSTATUS, 0x10); SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_CFG, emc_cfg); reg::Write(EMC + EMC_SEL_DPD_CTRL, emc_sel_dpd_ctrl); reg::Write(EMC + EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o | 0x1); reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, dst_timing->emc_fdpd_ctrl_cmd_no_ramp & ~0x1); uint32_t bg_regulator_mode_change = ((dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & (1 << 2)) ^ (src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & (1 << 2))) || ((dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & (1 << 0)) ^ (src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & (1 << 0))); uint32_t enable_bg_regulator = (dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & (1 << 0)) == 0; /* Check if we need to change BG the regulator. */ if (bg_regulator_mode_change) { if (enable_bg_regulator) { reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 0)); } else { reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 2)); } } /* Check if we need to turn on VREF generator. */ if ((((!(src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 0)))) && ((dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 0)))) || ((!(src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 8))) && ((dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 8))))) { uint32_t pad_tx_ctrl = dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; uint32_t last_pad_tx_ctrl = src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; next_dqs_e_ivref = pad_tx_ctrl & (1 << 8); next_dq_e_ivref = pad_tx_ctrl & (1 << 0); next_push = (last_pad_tx_ctrl & ~(1 << 0) & ~(1 << 8)) | next_dq_e_ivref | next_dqs_e_ivref; reg::Write(EMC + EMC_PMACRO_DATA_PAD_TX_CTRL, next_push); util::WaitMicroSeconds(1); } else if (bg_regulator_mode_change) { util::WaitMicroSeconds(1); } SetShadowBypass(ASSEMBLY); /* Step 2: * Prelock the DLL. */ if (dst_timing->burst_regs.emc_cfg_dig_dll & 0x1) { DllPrelock(dst_timing, training_enabled, next_clk_src); } else { ChangeDllSrc(dst_timing, next_clk_src); DllDisable(fbio_cfg7); } /* Step 3: * Prepare autocal for the clock change. */ SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_AUTO_CAL_CONFIG2, dst_timing->emc_auto_cal_config2); reg::Write(EMC + EMC_AUTO_CAL_CONFIG3, dst_timing->emc_auto_cal_config3); reg::Write(EMC + EMC_AUTO_CAL_CONFIG4, dst_timing->emc_auto_cal_config4); reg::Write(EMC + EMC_AUTO_CAL_CONFIG5, dst_timing->emc_auto_cal_config5); reg::Write(EMC + EMC_AUTO_CAL_CONFIG6, dst_timing->emc_auto_cal_config6); reg::Write(EMC + EMC_AUTO_CAL_CONFIG7, dst_timing->emc_auto_cal_config7); reg::Write(EMC + EMC_AUTO_CAL_CONFIG8, dst_timing->emc_auto_cal_config8); SetShadowBypass(ASSEMBLY); emc_auto_cal_config |= (0x1 | auto_cal_en); reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); /* Step 4: * Update EMC_CFG. */ if ((source_clock_period > 50000) && (dram_type == DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_SELF_REF, 1, 0); } else { reg::Write(EMC + EMC_CFG_2, dst_timing->emc_cfg_2); } /* Step 5: * Prepare reference variables for ZQCAL regs. */ uint32_t emc_zcal_interval = src_timing->burst_regs.emc_zcal_interval; emc_zcal_interval &= 0xFF000000; uint32_t emc_zcal_wait_cnt_old = src_timing->burst_regs.emc_zcal_wait_cnt; uint32_t emc_zcal_wait_cnt_new = dst_timing->burst_regs.emc_zcal_wait_cnt; emc_zcal_wait_cnt_old &= ~0x7ff; emc_zcal_wait_cnt_new &= ~0x7ff; if (dram_type == DRAM_TYPE_LPDDR4) { zq_wait_long = std::max<u32>(1, util::DivideUp(1000000, destination_clock_period)); } else if (dram_type == DRAM_TYPE_LPDDR2 || is_lpddr3) { zq_wait_long = std::max<u32>(dst_timing->min_mrs_wait, util::DivideUp(360000, destination_clock_period)) + 4; } else if (dram_type == DRAM_TYPE_DDR4) { zq_wait_long = std::max<u32>(256, util::DivideUp(320000, destination_clock_period) + 2); } else { zq_wait_long = 0; } if (dram_type == DRAM_TYPE_LPDDR2 || is_lpddr3) { zq_wait_short = std::max<u32>(std::max<u32>(dst_timing->min_mrs_wait, 6), util::DivideUp(90000, destination_clock_period)) + 4; } else if (dram_type == DRAM_TYPE_DDR4) { zq_wait_short = std::max<u32>(64, util::DivideUp(80000, destination_clock_period)) + 2; } else { zq_wait_short = 0; } /* TODO: Actually use the reference variables. */ AMS_UNUSED(zq_wait_long, zq_wait_short); /* Step 6: * Training code. */ if ((train_ca || train_ca_vref) && (dram_dev_num == TWO_RANK)) { reg::Write(EMC + EMC_PIN, 0x107); } /* Step 7: * Program FSP reference registers and send MRWs to new FSPWR. */ /* Step 7.1: Bug 200024907 - Patch RP R2P */ if (opt_war_200024907) { nRTP = 16; if (source_clock_period >= 1000000/1866) /* 535.91 ps */ nRTP = 14; if (source_clock_period >= 1000000/1600) /* 625.00 ps */ nRTP = 12; if (source_clock_period >= 1000000/1333) /* 750.19 ps */ nRTP = 10; if (source_clock_period >= 1000000/1066) /* 938.09 ps */ nRTP = 8; deltaTWATM = std::max<u32>(util::DivideUp(7500, source_clock_period), 8); /* * Originally there was a + .5 in the tRPST calculation. * However since we can't do FP in the kernel and the tRTM * computation was in a floating point ceiling function, adding * one to tRTP should be ok. There is no other source of non * integer values, so the result was always going to be * something for the form: f_ceil(N + .5) = N + 1; */ tRPST = ((src_timing->emc_mrw & 0x80) >> 7); tRTM = src_timing->dram_timings.rl + util::DivideUp(3600, source_clock_period) + std::max<u32>(util::DivideUp(7500, source_clock_period), 8) + tRPST + 1 + nRTP; if (src_timing->burst_regs.emc_rp < tRTM) { if (tRTM > (src_timing->burst_regs.emc_r2p + src_timing->burst_regs.emc_rp)) { R2P_war = tRTM - src_timing->burst_regs.emc_rp; RP_war = src_timing->burst_regs.emc_rp; TRPab_war = src_timing->burst_regs.emc_trpab; if (R2P_war > 63) { RP_war = R2P_war + src_timing->burst_regs.emc_rp - 63; if (TRPab_war < RP_war) TRPab_war = RP_war; R2P_war = 63; } } else { R2P_war = src_timing-> burst_regs.emc_r2p; RP_war = src_timing->burst_regs.emc_rp; TRPab_war = src_timing->burst_regs.emc_trpab; } if (RP_war < deltaTWATM) { W2P_war = src_timing->burst_regs.emc_w2p + deltaTWATM - RP_war; if (W2P_war > 63) { RP_war = RP_war + W2P_war - 63; if (TRPab_war < RP_war) TRPab_war = RP_war; W2P_war = 63; } } else { W2P_war = src_timing->burst_regs.emc_w2p; } if ((src_timing->burst_regs.emc_w2p != W2P_war) || (src_timing->burst_regs.emc_r2p != R2P_war) || (src_timing->burst_regs.emc_rp != RP_war) || (src_timing->burst_regs.emc_trpab != TRPab_war)) { SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_RP, RP_war); reg::Write(EMC + EMC_R2P, R2P_war); reg::Write(EMC + EMC_W2P, W2P_war); reg::Write(EMC + EMC_TRPAB, TRPab_war); SetShadowBypass(ASSEMBLY); util::WaitMicroSeconds(1); } } } if (!g_fsp_for_next_freq) { mr13_flip_fspwr = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x80; mr13_flip_fspop = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x00; } else { mr13_flip_fspwr = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x40; mr13_flip_fspop = (dst_timing->emc_mrw3 & 0xffffff3f) | 0xc0; } mr13_catr_enable = (mr13_flip_fspwr & 0xFFFFFFFE) | 0x01; if (dram_dev_num == TWO_RANK) { if (train_ca || train_ca_vref) { if (train_second_rank) { mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x80000000; mr13_catr_enable = (mr13_catr_enable & 0x3FFFFFFF)| 0x40000000; } else { mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | 0x40000000; mr13_catr_enable = (mr13_catr_enable & 0x3FFFFFFF) | 0x80000000; } } else { if (train_second_rank) { mr13_catr_enable = (mr13_catr_enable & 0x3FFFFFFF) | 0x40000000; } else { mr13_catr_enable = (mr13_catr_enable & 0x3FFFFFFF) | 0x80000000; } } } if (dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_MRW3, mr13_flip_fspwr); reg::Write(EMC + EMC_MRW, dst_timing->emc_mrw); reg::Write(EMC + EMC_MRW2, dst_timing->emc_mrw2); } /* Step 8: * Program the shadow registers. */ /* Set burst registers. */ for (u32 i = 0; i < dst_timing->num_burst; i++) { uint32_t var = 0; uint32_t wval = 0; if (!BurstRegistersOffsets[i]) { continue; } var = BurstRegistersOffsets[i]; if (train_ca || train_ca_vref) { wval = dst_timing->shadow_regs_ca_train_arr[i]; } else if (train_quse || train_quse_vref) { wval = dst_timing->shadow_regs_quse_train_arr[i]; } else if (train_wr || train_wr_vref || train_rd || train_rd_vref) { wval = dst_timing->shadow_regs_rdwr_train_arr[i]; } else { wval = dst_timing->burst_regs_arr[i]; } if (dram_type != DRAM_TYPE_LPDDR4 && (var == EMC_MRW6 || var == EMC_MRW7 || var == EMC_MRW8 || var == EMC_MRW9 || var == EMC_MRW10 || var == EMC_MRW11 || var == EMC_MRW12 || var == EMC_MRW13 || var == EMC_MRW14 || var == EMC_MRW15 || var == EMC_TRAINING_CTRL)) { continue; } if (var == EMC_CFG) { wval &= (dram_type == DRAM_TYPE_LPDDR4) ? 0x0FFFFFFF : 0xCFFFFFFF; } else if ((var == EMC_ZCAL_INTERVAL) && opt_zcal_en_cc) { wval = 0; /* EMC_ZCAL_INTERVAL reset value. */ } else if (var == EMC_PMACRO_AUTOCAL_CFG_COMMON) { wval |= (1 << 16); } else if (var == EMC_PMACRO_DATA_PAD_TX_CTRL) { wval &= 0xFEFEFDFD; } else if (var == EMC_PMACRO_CMD_PAD_TX_CTRL) { wval &= 0xFAFEFDFD; wval |= 0x04000000; } else if (var == EMC_PMACRO_BRICK_CTRL_RFU1) { wval &= 0xf800f800; } else if (var == EMC_PMACRO_COMMON_PAD_TX_CTRL) { wval &= 0xfffffff0; } else if (var == EMC_TRAINING_CTRL) { wval |= train_second_rank ? (1 << 14) : 0; } reg::Write(EMC + var, wval); } if (dram_type == DRAM_TYPE_LPDDR4) { /* Use the current timing when training. */ if (training_enabled) { mrw_req = (23 << 16) | (src_timing->run_clocks & 0xFF); } else { mrw_req = (23 << 16) | (dst_timing->run_clocks & 0xFF); } reg::Write(EMC + EMC_MRW, mrw_req); } /* Per channel burst registers. */ const bool dual_channel = reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE; for (u32 i = 0; i < dst_timing->num_burst_per_ch; i++) { if (!PerChannelBurstRegisters[i]) { continue; } const u32 addr = PerChannelBurstRegisters[i]; const u32 base = addr & ~0xFFF; const u32 off = addr & 0xFFF; if (dram_type != DRAM_TYPE_LPDDR4 && (off == EMC_MRW6 || off == EMC_MRW7 || off == EMC_MRW8 || off == EMC_MRW9 || off == EMC_MRW10 || off == EMC_MRW11 || off == EMC_MRW12 || off == EMC_MRW13 || off == EMC_MRW14 || off == EMC_MRW15) ) { continue; } /* Filter out second channel if not in DUAL_CHANNEL mode. */ if (!dual_channel && base == EMC1) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->burst_perch_regs_arr[i]); } /* Vref regs. */ for (u32 i = 0; i < dst_timing->vref_num; i++) { if (!PerChannelVrefRegisters[i]) { continue; } const u32 addr = PerChannelVrefRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out second channel if not in DUAL_CHANNEL mode. */ if (!dual_channel && base == EMC1) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->vref_perch_regs_arr[i]); } /* Training regs. */ if (training_enabled) { for (u32 i = 0; i < dst_timing->training_mod_num; i++) { if (!PerChannelTrainingModRegisters[i]) { continue; } const u32 addr = PerChannelTrainingModRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out second channel if not in DUAL_CHANNEL mode. */ if (!dual_channel && base == EMC1) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->training_mod_regs_arr[i]); } } /* Trimmers. */ for (u32 i = 0; i < dst_timing->num_trim; i++) { if (!TrimRegisters[i]) { continue; } const u32 addr = TrimRegisters[i]; const u32 ofs = addr & 0xFFF; u32 wval = dst_timing->trim_regs_arr[i]; if (compensate_trimmer_applicable && (ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 || ofs == EMC_DATA_BRLSHFT_0 || ofs == EMC_DATA_BRLSHFT_1)) { wval = ApplyPeriodicCompensationTrimmer(dst_timing, ofs); } /* Write the value. */ reg::Write(addr, wval); } /* Per-channel trimmers. */ for (u32 i = 0; i < dst_timing->num_trim_per_ch; i++) { if (!PerChannelTrimRegisters[i]) { continue; } const u32 addr = PerChannelTrimRegisters[i]; const u32 base = addr & ~0xFFF; const u32 ofs = addr & 0xFFF; /* Filter out second channel if not in DUAL_CHANNEL mode. */ if (!dual_channel && base == EMC1) { continue; } u32 wval = dst_timing->trim_perch_regs_arr[i]; if (compensate_trimmer_applicable && (ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 || ofs == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 || ofs == EMC_DATA_BRLSHFT_0 || ofs == EMC_DATA_BRLSHFT_1)) { wval = ApplyPeriodicCompensationTrimmer(dst_timing, ofs); } /* Write the value. */ reg::Write(addr, wval); } if (training_enabled) { if (train_wr && dst_timing->periodic_training && (dram_type == DRAM_TYPE_LPDDR4)) { PeriodicCompensationHandler(WRITE_TRAINING_SEQUENCE, dram_dev_num, fbio_cfg7, src_timing, dst_timing); } } else { /* Write burst_mc_regs. */ for (u32 i = 0; i < dst_timing->num_mc_regs; i++) { reg::Write(BurstMcRegisters[i], dst_timing->burst_mc_regs_arr[i]); } } /* Registers to be programmed on the faster clock. */ if (!training_enabled && (dst_timing->rate_khz < src_timing->rate_khz)) { for (u32 i = 0; i < dst_timing->num_up_down; i++) { reg::Write(LaScaleRegisters[i], dst_timing->la_scale_regs_arr[i]); } } /* Step 9: * LPDDR4 section A. */ if (dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_ZCAL_INTERVAL, emc_zcal_interval); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, emc_zcal_wait_cnt_new); reg::Write(EMC + EMC_DBG, emc_dbg_o | 0x40000002); reg::Write(EMC + EMC_ZCAL_INTERVAL, emc_zcal_interval); reg::Write(EMC + EMC_DBG, emc_dbg_o); if (training_enabled) { SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_COMMON, dst_timing->burst_regs.emc_pmacro_autocal_cfg_common | (1 << 16)); if (train_ca || train_ca_vref) { reg::Write(EMC + EMC_FBIO_CFG5, src_timing->burst_regs.emc_fbio_cfg5 | (1 << 27)); } SetShadowBypass(ASSEMBLY); if (dual_channel) { CcfifoWrite(EMC_CFG_SYNC, 0, 0); } /* Change CFG_SWAP. */ CcfifoWrite(EMC_DBG, ((emc_dbg_o & 0xF3FFFFFF) | 0x4000000), 0); } } /* Step 10: * LPDDR4 and DDR3 common section. */ if (opt_dvfs_mode == MAN_SR || dram_type == DRAM_TYPE_LPDDR4) { if (dram_type == DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_SELF_REF, 0x101, 0); } else { CcfifoWrite(EMC_SELF_REF, 0x1, 0); } if (!(train_ca || train_ca_vref) && (dram_type == DRAM_TYPE_LPDDR4) && (source_clock_period <= zqcal_before_cc_cutoff)) { CcfifoWrite(EMC_MRW3, mr13_flip_fspwr ^ 0x40, 0); CcfifoWrite(EMC_MRW6, (dst_timing->burst_regs.emc_mrw6 & 0xFFFF3F3F) | (src_timing->burst_regs.emc_mrw6 & 0x0000C0C0), 0); CcfifoWrite(EMC_MRW14, (dst_timing->burst_regs.emc_mrw14 & 0xFFFF0707) | (src_timing->burst_regs.emc_mrw14 & 0x00003838), 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_MRW7, (dst_timing->burst_regs.emc_mrw7 & 0xFFFF3F3F) | (src_timing->burst_regs.emc_mrw7 & 0x0000C0C0), 0); CcfifoWrite(EMC_MRW15, (dst_timing->burst_regs.emc_mrw15 & 0xFFFF0707) | (src_timing->burst_regs.emc_mrw15 & 0x00003838), 0); } if (opt_zcal_en_cc) { if ((dram_dev_num == ONE_RANK) || shared_zq_resistor) { CcfifoWrite(EMC_ZQ_CAL, 2 << 30 | (1 << 0), 0); } else { CcfifoWrite(EMC_ZQ_CAL, (1 << 0), 0); } } } } emc_dbg = emc_dbg_o; if (dram_type == DRAM_TYPE_LPDDR4) { if (training_enabled) { /* Change CFG_SWAP. */ emc_dbg = ((emc_dbg_o & 0xF3FFFFFF) | 0x4000000 | (1 << 30)); CcfifoWrite(EMC_DBG, emc_dbg, 0); } if (train_ca || train_ca_vref) { CcfifoWrite(EMC_PMACRO_DATA_RX_TERM_MODE, src_timing->burst_regs.emc_pmacro_data_rx_term_mode & 0xFFFFFCCC, 0); if ((dram_dev_num == TWO_RANK) && train_second_rank) { CcfifoWrite(EMC_MRW3, mr13_flip_fspop | 0x8, (1000 * src_timing->dram_timings.t_rp) / source_clock_period); CcfifoWrite(EMC_MRW3, mr13_catr_enable | 0x8, 0); } else { CcfifoWrite(EMC_MRW3, mr13_catr_enable | 0x8, (1000 * src_timing->dram_timings.t_rp) / source_clock_period); } CcfifoWrite(EMC_TR_CTRL_0, 0x15A, 0); CcfifoWrite(EMC_INTSTATUS, 0, 1000000 / source_clock_period); } else { CcfifoWrite(EMC_MRW3, mr13_flip_fspop | 0x8, (1000 * src_timing->dram_timings.t_rp) / source_clock_period); CcfifoWrite(EMC_INTSTATUS, 0, tFC_lpddr4 / source_clock_period); } } bool ref_b4_sref_en = false; bool cya_issue_pc_ref = false; bool cya_allow_ref_cc = false; if ((dram_type == DRAM_TYPE_LPDDR4) || (opt_dvfs_mode != MAN_SR)) { uint32_t t = 30 + (cya_allow_ref_cc ? (4000 * src_timing->dram_timings.t_rfc) + ((1000 * src_timing->dram_timings.t_rp) / source_clock_period) : 0); CcfifoWrite(EMC_PIN, emc_pin_o & 0xFFFFFFF8, t); } uint32_t ref_delay_mult = 1; ref_delay_mult += ref_b4_sref_en ? 1 : 0; ref_delay_mult += cya_allow_ref_cc ? 1 : 0; ref_delay_mult += cya_issue_pc_ref ? 1 : 0; uint32_t ref_delay = ref_delay_mult * ((1000 * src_timing->dram_timings.t_rp / source_clock_period) + (1000 * src_timing->dram_timings.t_rfc / source_clock_period)) + 20; /* Step 11: * Ramp down. */ CcfifoWrite(EMC_CFG_SYNC, 0, (dram_type == DRAM_TYPE_LPDDR4) ? 0 : ref_delay); CcfifoWrite(EMC_DBG, emc_dbg | ((1 << 1) | (1 << 30)), 0); uint32_t ramp_down_wait = DvfsPowerRampDown(false, src_timing, dst_timing, source_clock_period); /* Step 12: * Trigger the clock change. */ CcfifoWrite(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); if (!training_enabled) { CcfifoWrite(EMC_DBG, (emc_dbg & ~(1 << 30)) | (1 << 1), 0); } /* Step 13: * Ramp up. */ uint32_t ramp_up_wait = DvfsPowerRampUp(false, src_timing, dst_timing, training, destination_clock_period); CcfifoWrite(EMC_DBG, emc_dbg, 0); /* Step 14: * Bringup CKE pins. */ if ((dram_type == DRAM_TYPE_LPDDR4)) { uint32_t r = emc_pin_o & 0xFFFFFFF8; if (train_ca || train_ca_vref) { if (dram_dev_num == TWO_RANK) { if (train_second_rank) { CcfifoWrite(EMC_PIN, r | 5, 0); } else { CcfifoWrite(EMC_PIN, r | 6, 0); } } else { CcfifoWrite(EMC_PIN, r, 0); } } else if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_PIN, r | 7, 0); } else { CcfifoWrite(EMC_PIN, r | 1, 0); } } /* Step 15: * Calculate zqlatch wait time; has dependency on ramping times. */ if (source_clock_period <= zqcal_before_cc_cutoff) { int t = (int)(ramp_up_wait + ramp_down_wait) / (int)destination_clock_period; zq_latch_dvfs_wait_time = (int)tZQCAL_lpddr4_fc_adj - t; } else { zq_latch_dvfs_wait_time = tZQCAL_lpddr4_fc_adj - util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period); } if (!(train_ca || train_ca_vref) && (dram_type == DRAM_TYPE_LPDDR4) && opt_zcal_en_cc) { if (dram_dev_num == ONE_RANK) { if (source_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); } if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); CcfifoWrite(EMC_SELF_REF, 0x100, 0); CcfifoWrite(EMC_REF, 0, 0); } CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), std::max<int>(0, zq_latch_dvfs_wait_time)); } else if (shared_zq_resistor) { if (source_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); } CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), std::max<int>(0, zq_latch_dvfs_wait_time) + util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), 0); if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, 0); CcfifoWrite(EMC_SELF_REF, 0x100, 0); CcfifoWrite(EMC_REF, 0, 0); } CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), tZQCAL_lpddr4 / destination_clock_period); } else { if (source_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (1 << 0), util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); } if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xF3FFFFF7) | 0xC000000, util::DivideUp(1000 * dst_timing->dram_timings.t_pdex, destination_clock_period)); CcfifoWrite(EMC_SELF_REF, 0x100, 0); CcfifoWrite(EMC_REF, 0, 0); } CcfifoWrite(EMC_ZQ_CAL, (1 << 1), std::max<int>(0, zq_latch_dvfs_wait_time)); } } /* WAR: delay for zqlatch */ CcfifoWrite(EMC_INTSTATUS, 0, 10); /* Step 16: * LPDDR4 Conditional Training Kickoff. */ if (training_enabled && (dram_type == DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_INTSTATUS, 0, (1020000 / destination_clock_period)); uint32_t train_cmd = 0; if (train_ca) train_cmd |= (1 << 1); /* CA */ if (train_ca_vref) train_cmd |= (1 << 5); /* CA_VREF */ if (train_quse) train_cmd |= (1 << 4); /* QUSE */ if (train_quse_vref) train_cmd |= (1 << 8); /* QUSE_VREF */ if (train_wr) train_cmd |= (1 << 3); /* WR */ if (train_wr_vref) train_cmd |= (1 << 6); /* WR_VREF */ if (train_rd) train_cmd |= (1 << 2); /* RD */ if (train_rd_vref) train_cmd |= (1 << 7); /* RD_VREF */ train_cmd |= (1 << 31); /* GO */ CcfifoWrite(EMC_TRAINING_CMD, train_cmd, 0); if (bg_regulator_mode_change) { if (enable_bg_regulator) CcfifoWrite(EMC_PMACRO_BG_BIAS_CTRL_0, src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 0), 0); else CcfifoWrite(EMC_PMACRO_BG_BIAS_CTRL_0, src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 2), 0); } CcfifoWrite(EMC_SWITCH_BACK_CTRL, 1, 0); if (!(train_ca || train_ca_vref) || train_second_rank) { CcfifoWrite(EMC_MRW3, mr13_flip_fspop ^ 0xC0, 0); CcfifoWrite(EMC_INTSTATUS, 0, (1000000 / destination_clock_period)); } CcfifoWrite(EMC_PIN, emc_pin_o & 0xFFFFFFF8, 0); CcfifoWrite(EMC_CFG_SYNC, 0, 0); CcfifoWrite(EMC_DBG, emc_dbg | ((1 << 30) | (1 << 1)), 0); DvfsPowerRampDown(true, src_timing, dst_timing, destination_clock_period); CcfifoWrite(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); CcfifoWrite(EMC_DBG, (emc_dbg & ~(1 << 30)) | (1 << 1), 0); DvfsPowerRampUp(true, src_timing, dst_timing, training, source_clock_period); CcfifoWrite(EMC_DBG, emc_dbg, 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_PIN, emc_pin_o | 7, 0); } else { CcfifoWrite(EMC_PIN, ((emc_pin_o & 0xFFFFFFF8) | 1), 0); } if (train_ca || train_ca_vref) { CcfifoWrite(EMC_TR_CTRL_0, 0x4A, (200000 / source_clock_period)); CcfifoWrite(EMC_TR_CTRL_0, 0x40, (1000000 / source_clock_period)); CcfifoWrite(EMC_MRW3, mr13_catr_enable & 0xFFFFFFFE, 0); CcfifoWrite(EMC_INTSTATUS, 0, (1000000 / source_clock_period)); CcfifoWrite(EMC_PMACRO_DATA_RX_TERM_MODE, src_timing->burst_regs.emc_pmacro_data_rx_term_mode, 0); } CcfifoWrite(EMC_DBG, emc_dbg_o, 0); if (opt_zcal_en_cc) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), (1000000 / source_clock_period)); if (dram_dev_num == TWO_RANK) { if (shared_zq_resistor) { if (!(train_ca || train_ca_vref) || train_second_rank) { CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), (1000000 / source_clock_period)); if (!(train_ca || train_ca_vref)) CcfifoWrite(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); } CcfifoWrite(EMC_SELF_REF, 0x100, 0); skip_zqcal = true; } else { if ((train_ca || train_ca_vref) && !train_second_rank) { CcfifoWrite(EMC_SELF_REF, 0x100, 0); skip_zqcal = true; } else { CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), (1000000 / source_clock_period)); } } } } if (!skip_zqcal) { if (!(train_ca || train_ca_vref)) CcfifoWrite(EMC_MRW3, ((mr13_flip_fspop ^ 0xC0) & 0xF3FFFFF7) | 0xC000000, 0); CcfifoWrite(EMC_SELF_REF, 0x100, 0); } } if (!skip_zqcal) { /* Step 17: * MANSR exit self refresh. */ if ((opt_dvfs_mode == MAN_SR) && (dram_type != DRAM_TYPE_LPDDR4)) CcfifoWrite(EMC_SELF_REF, 0, 0); /* Step 18: * Send MRWs to LPDDR3/DDR3. */ if (dram_type == DRAM_TYPE_LPDDR2) { CcfifoWrite(EMC_MRW2, dst_timing->emc_mrw2, 0); CcfifoWrite(EMC_MRW, dst_timing->emc_mrw, 0); if (is_lpddr3) { CcfifoWrite(EMC_MRW4, dst_timing->emc_mrw4, 0); } } else if (dram_type == DRAM_TYPE_DDR4) { if (opt_dll_mode == DLL_ON) { CcfifoWrite(EMC_EMRS, dst_timing->emc_emrs & ~(1 << 26), 0); } CcfifoWrite(EMC_EMRS2, dst_timing->emc_emrs2 & ~(1 << 26), 0); CcfifoWrite(EMC_MRS, dst_timing->emc_mrs | (1 << 26), 0); } /* Step 19: * ZQCAL for LPDDR3/DDR3 */ if (opt_zcal_en_cc) { if (dram_type == DRAM_TYPE_LPDDR2) { uint32_t r; uint32_t zq_op = opt_cc_short_zcal ? 0x56 : 0xAB; uint32_t zcal_wait_time_ps = opt_cc_short_zcal ? 90000 : 360000; uint32_t zcal_wait_time_clocks = util::DivideUp(zcal_wait_time_ps, destination_clock_period); r = (zcal_wait_time_clocks << 16) | (zcal_wait_time_clocks << 0); CcfifoWrite(EMC_MRS_WAIT_CNT2, r, 0); CcfifoWrite(EMC_MRW, (2 << 30) | (1 << 27) | (10 << 16) | (zq_op << 0), 0); if (dram_dev_num == TWO_RANK) { r = (1 << 30) | (1 << 27) | (10 << 16) | (zq_op << 0); CcfifoWrite(EMC_MRW, r, 0); } } else if (dram_type == DRAM_TYPE_DDR4) { uint32_t zq_op = opt_cc_short_zcal ? 0 : (1 << 4); CcfifoWrite(EMC_ZQ_CAL, zq_op | (2 << 30) | (1 << 0), 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_ZQ_CAL, zq_op | (1 << 30) | (1 << 0), 0); } } } } if (bg_regulator_mode_change) { SetShadowBypass(ACTIVE); uint32_t bg_regulator_switch_complete_wait_clks = ramp_up_wait > 1250000 ? 0 : (1250000 - ramp_up_wait) / destination_clock_period; if (training_enabled) { bg_regulator_switch_complete_wait_clks = (1250000 / source_clock_period); CcfifoWrite(EMC_PMACRO_BG_BIAS_CTRL_0, src_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks); } else { CcfifoWrite(EMC_PMACRO_BG_BIAS_CTRL_0, dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0, bg_regulator_switch_complete_wait_clks); } SetShadowBypass(ASSEMBLY); } /* Step 20: * Issue ref and optional QRST. */ if (training_enabled || (dram_type != DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_REF, 0, 0); } if (opt_do_sw_qrst) { CcfifoWrite(EMC_ISSUE_QRST, 1, 0); CcfifoWrite(EMC_ISSUE_QRST, 0, 2); } /* Step 21: * Restore ZCAL and ZCAL interval. */ if (save_restore_clkstop_pd || opt_zcal_en_cc) { SetShadowBypass(ACTIVE); if (opt_zcal_en_cc) { if (training_enabled) { CcfifoWrite(EMC_ZCAL_INTERVAL, src_timing->burst_regs.emc_zcal_interval, 0); } else if (dram_type != DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_ZCAL_INTERVAL, dst_timing->burst_regs.emc_zcal_interval, 0); } } if (save_restore_clkstop_pd) { CcfifoWrite(EMC_CFG, dst_timing->burst_regs.emc_cfg & ~(1 << 28), 0); } if (training_enabled && (dram_type == DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_SEL_DPD_CTRL, src_timing->emc_sel_dpd_ctrl, 0); } SetShadowBypass(ASSEMBLY); } /* Step 22: * Restore EMC_CFG_PIPE_CLK. */ CcfifoWrite(EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o, 0); if (bg_regulator_mode_change) { if (enable_bg_regulator) { reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 2)); } else { reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, dst_timing->burst_regs.emc_pmacro_bg_bias_ctrl_0 & ~(1 << 0)); } } /* Step 23: * Do clock change. */ if (training_enabled) { u32 cur_clk_src = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE, cur_clk_src); ChangeDllSrc(src_timing, cur_clk_src); } uint32_t cfg_dig_dll_tmp = (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFFF24) | 0x88; reg::Write(EMC + EMC_CFG_DIG_DLL, cfg_dig_dll_tmp); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, next_clk_src); WaitForUpdate(EMC_INTSTATUS, 0x10, true, fbio_cfg7); /* Step 24: * Save training results. */ if (training_enabled) { uint32_t emc_dbg_tmp = reg::Read(EMC + EMC_DBG); reg::Write(EMC + EMC_DBG, emc_dbg_tmp | 1); /* Set READ_MUX to ASSEMBLY. */ /* Save CA results. */ if (train_ca) { dst_timing->trim_perch_regs.emc0_cmd_brlshft_0 = reg::Read(EMC0 + EMC_CMD_BRLSHFT_0); dst_timing->trim_perch_regs.emc1_cmd_brlshft_1 = dual_channel ? reg::Read(EMC1 + EMC_CMD_BRLSHFT_1): 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5) : 0; if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2 = reg::Read(EMC + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2); } } /* Save CA_VREF results. */ if (train_ca_vref) { dst_timing->burst_perch_regs.emc0_mrw10 = (reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF) & 0xFFFF) | 0x880C0000; dst_timing->burst_perch_regs.emc1_mrw10 = (dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF) & 0xFFFF : 0) | 0x880C0000; if (dram_dev_num == TWO_RANK) { dst_timing->burst_perch_regs.emc0_mrw11 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF) >> 16) & 0xFF) | (reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF) >> 24 << 8) | (0x480C0000 & 0xFFFFFF00); dst_timing->burst_perch_regs.emc1_mrw11 = (((dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF) : 0) >> 16) & 0xFF) | ((dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF) : 0) >> 24 << 8) | (0x480C0000 & 0xFFFFFF00); } else { dst_timing->burst_perch_regs.emc0_mrw11 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF) >> 16) & 0xFF) | (reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF) >> 24 << 8) | (0xC80C0000 & 0xFFFFFF00); dst_timing->burst_perch_regs.emc1_mrw11 = (((dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF) : 0) >> 16) & 0xFF) | ((dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF) : 0) >> 24 << 8) | (0xC80C0000 & 0xFFFFFF00); } } /* Save QUSE results. */ if (train_quse || train_rd) { dst_timing->trim_perch_regs.emc0_quse_brlshft_0 = reg::Read(EMC0 + EMC_QUSE_BRLSHFT_0); dst_timing->trim_perch_regs.emc1_quse_brlshft_1 = dual_channel ? reg::Read(EMC1 + EMC_QUSE_BRLSHFT_1) : 0; dst_timing->trim_regs.emc_pmacro_quse_ddll_rank0_0 = reg::Read(EMC0 + EMC_PMACRO_QUSE_DDLL_RANK0_0); dst_timing->trim_regs.emc_pmacro_quse_ddll_rank0_1= reg::Read(EMC0 + EMC_PMACRO_QUSE_DDLL_RANK0_1); dst_timing->trim_regs.emc_pmacro_quse_ddll_rank0_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_QUSE_DDLL_RANK0_2) : 0; dst_timing->trim_regs.emc_pmacro_quse_ddll_rank0_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_QUSE_DDLL_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_perch_regs.emc0_quse_brlshft_2 = reg::Read(EMC0 + EMC_QUSE_BRLSHFT_2); dst_timing->trim_perch_regs.emc1_quse_brlshft_3 = dual_channel ? reg::Read(EMC1 + EMC_QUSE_BRLSHFT_3) : 0; dst_timing->trim_regs.emc_pmacro_quse_ddll_rank1_0 = reg::Read(EMC0 + EMC_PMACRO_QUSE_DDLL_RANK1_0); dst_timing->trim_regs.emc_pmacro_quse_ddll_rank1_1 = reg::Read(EMC0 + EMC_PMACRO_QUSE_DDLL_RANK1_1); dst_timing->trim_regs.emc_pmacro_quse_ddll_rank1_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_QUSE_DDLL_RANK1_2) : 0; dst_timing->trim_regs.emc_pmacro_quse_ddll_rank1_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_QUSE_DDLL_RANK1_3) : 0; } } /* Save QUSE_VREF results. */ if (train_quse_vref) { if (dram_dev_num == TWO_RANK) { uint32_t emc0_opt_dqs_array[4] = {0}; uint32_t emc1_opt_dqs_array[4] = {0}; uint32_t emc1_training_opt_dqs_ib_vref_rank0_val = dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) : 0; uint32_t emc1_training_opt_dqs_ib_vref_rank1_val = dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) : 0; for (int i = 0; i < 4; i++) { emc0_opt_dqs_array[i] = (reg::Read(EMC0 + EMC_TRAINING_OPT_DQS_IB_VREF_RANK0) >> (8 * i)) & 0xFF; emc1_opt_dqs_array[i] = (emc1_training_opt_dqs_ib_vref_rank0_val >> (8 * i)) & 0xFF; } uint32_t ib_vref_dqs_0 = 0; uint32_t ib_vref_dqs_1 = 0; for (int i = 0; i < 4; i++) { ib_vref_dqs_0 |= (emc0_opt_dqs_array[i] + ((reg::Read(EMC0 + EMC_TRAINING_OPT_DQS_IB_VREF_RANK1) >> (8 * i)) & 0xFF)) >> 1 << (8 * i); ib_vref_dqs_1 |= (emc1_opt_dqs_array[i] + ((emc1_training_opt_dqs_ib_vref_rank1_val >> (8 * i)) & 0xFF)) >> 1 << (8 * i); } dst_timing->trim_regs.emc_pmacro_ib_vref_dqs_0 = ib_vref_dqs_0; dst_timing->trim_regs.emc_pmacro_ib_vref_dqs_1 = ib_vref_dqs_1; } else { dst_timing->trim_regs.emc_pmacro_ib_vref_dqs_0 = reg::Read(EMC + EMC_PMACRO_IB_VREF_DQS_0); dst_timing->trim_regs.emc_pmacro_ib_vref_dqs_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_VREF_DQS_1) : 0; } } /* Save RD results. */ if (train_rd) { dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) : 0; } if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; } } /* Save RD_VREF results. */ if (train_rd_vref) { uint8_t ib_vref_dq_byte0_icr = (reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) + (dst_timing->save_restore_mod_regs[0] & 0x7F); if (dst_timing->save_restore_mod_regs[0] & 0x80000000) ib_vref_dq_byte0_icr = (reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) & 0x7F) - (dst_timing->save_restore_mod_regs[0] & 0x7F); uint8_t ib_vref_dq_byte1_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) + (dst_timing->save_restore_mod_regs[1] & 0x7F); if (dst_timing->save_restore_mod_regs[1] & 0x80000000) ib_vref_dq_byte1_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 8) & 0x7F) - (dst_timing->save_restore_mod_regs[1] & 0x7F); uint8_t ib_vref_dq_byte2_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) + (dst_timing->save_restore_mod_regs[2] & 0x7F); if (dst_timing->save_restore_mod_regs[2] & 0x80000000) ib_vref_dq_byte2_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 16) & 0x7F) - (dst_timing->save_restore_mod_regs[2] & 0x7F); uint8_t ib_vref_dq_byte3_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) + (dst_timing->save_restore_mod_regs[3] & 0x7F); if (dst_timing->save_restore_mod_regs[3] & 0x80000000) ib_vref_dq_byte3_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_0) >> 24) & 0x7F) - (dst_timing->save_restore_mod_regs[3] & 0x7F); dst_timing->trim_regs.emc_pmacro_ib_vref_dq_0 = ((ib_vref_dq_byte0_icr & 0x7F) | (ib_vref_dq_byte1_icr & 0x7F) << 8) | ((ib_vref_dq_byte2_icr & 0x7F) << 16) | ((ib_vref_dq_byte3_icr & 0x7F) << 24); uint8_t ib_vref_dq_byte4_icr = (reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) + (dst_timing->save_restore_mod_regs[4] & 0x7F); if (dst_timing->save_restore_mod_regs[4] & 0x80000000) ib_vref_dq_byte4_icr = (reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) & 0x7F) - (dst_timing->save_restore_mod_regs[4] & 0x7F); uint8_t ib_vref_dq_byte5_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) + (dst_timing->save_restore_mod_regs[5] & 0x7F); if (dst_timing->save_restore_mod_regs[5] & 0x80000000) ib_vref_dq_byte5_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 8) & 0x7F) - (dst_timing->save_restore_mod_regs[5] & 0x7F); uint8_t ib_vref_dq_byte6_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) + (dst_timing->save_restore_mod_regs[6] & 0x7F); if (dst_timing->save_restore_mod_regs[6] & 0x80000000) ib_vref_dq_byte6_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 16) & 0x7F) - (dst_timing->save_restore_mod_regs[6] & 0x7F); uint8_t ib_vref_dq_byte7_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) + (dst_timing->save_restore_mod_regs[7] & 0x7F); if (dst_timing->save_restore_mod_regs[7] & 0x80000000) ib_vref_dq_byte7_icr = ((reg::Read(EMC + EMC_PMACRO_IB_VREF_DQ_1) >> 24) & 0x7F) - (dst_timing->save_restore_mod_regs[7] & 0x7F); dst_timing->trim_regs.emc_pmacro_ib_vref_dq_1 = ((ib_vref_dq_byte4_icr & 0x7F) | (ib_vref_dq_byte5_icr & 0x7F) << 8) | ((ib_vref_dq_byte6_icr & 0x7F) << 16) | ((ib_vref_dq_byte7_icr & 0x7F) << 24); } } /* Save WR results. */ if (train_wr) { dst_timing->trim_perch_regs.emc0_data_brlshft_0 = reg::Read(EMC0 + EMC_DATA_BRLSHFT_0); dst_timing->trim_perch_regs.emc1_data_brlshft_0 = dual_channel ? reg::Read(EMC1 + EMC_DATA_BRLSHFT_0) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_perch_regs.emc0_data_brlshft_1 = reg::Read(EMC0 + EMC_DATA_BRLSHFT_1); dst_timing->trim_perch_regs.emc1_data_brlshft_1 = dual_channel ? reg::Read(EMC1 + EMC_DATA_BRLSHFT_1) : 0; } dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) : 0; } if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2) : 0; if (dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1) : 0; dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2 = dual_channel ? reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2) : 0; } } /* Save WR_VREF results. */ if (train_wr_vref) { uint32_t emc1_ranks_sub_partitions = dual_channel ? reg::Read(EMC1 + EMC_TRAINING_OPT_DQ_OB_VREF) : 0; uint8_t emc0_ib_vref_dq_byte8_modded_plus = dst_timing->save_restore_mod_regs[8] + reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF); if (dst_timing->save_restore_mod_regs[8] & 0x80000000) emc0_ib_vref_dq_byte8_modded_plus = reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) - dst_timing->save_restore_mod_regs[8]; uint8_t emc0_mrw12_op_sp1 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) + dst_timing->save_restore_mod_regs[9]; if (dst_timing->save_restore_mod_regs[9] & 0x80000000) emc0_mrw12_op_sp1 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) & 0xFFFF) >> 8) - dst_timing->save_restore_mod_regs[9]; uint8_t emc0_mrw13_op_sp0 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) + dst_timing->save_restore_mod_regs[8]; if (dst_timing->save_restore_mod_regs[8] & 0x80000000) emc0_mrw13_op_sp0 = ((reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) >> 16) & 0xFF) - dst_timing->save_restore_mod_regs[8]; uint8_t emc0_ib_vref_dq_byte9_modded_a_plus = dst_timing->save_restore_mod_regs[9] + (reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) >> 24); if (dst_timing->save_restore_mod_regs[9] & 0x80000000) emc0_ib_vref_dq_byte9_modded_a_plus = (reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF) >> 24) - (uint8_t)dst_timing->save_restore_mod_regs[9]; uint8_t emc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions + dst_timing->save_restore_mod_regs[10]; if (dst_timing->save_restore_mod_regs[10] & 0x80000000) emc0_ib_vref_dq_byte10_modded_plus = emc1_ranks_sub_partitions - dst_timing->save_restore_mod_regs[10]; uint8_t emc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) + dst_timing->save_restore_mod_regs[11]; if (dst_timing->save_restore_mod_regs[11] & 0x80000000) emc0_ib_vref_dq_byte11_modded_plus = ((emc1_ranks_sub_partitions & 0xFFFF) >> 8) - dst_timing->save_restore_mod_regs[11]; uint8_t emc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) + dst_timing->save_restore_mod_regs[10]; if (dst_timing->save_restore_mod_regs[10] & 0x80000000) emc1_mrw13_op_sp0 = ((emc1_ranks_sub_partitions >> 16) & 0xFF) - dst_timing->save_restore_mod_regs[10]; uint8_t emc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) + dst_timing->save_restore_mod_regs[11]; if (dst_timing->save_restore_mod_regs[11] & 0x80000000) emc1_mrw13_op_sp1 = (emc1_ranks_sub_partitions >> 24) - dst_timing->save_restore_mod_regs[11]; dst_timing->burst_perch_regs.emc1_mrw12 = (uint8_t)emc0_ib_vref_dq_byte10_modded_plus | 0x880E0000 | (emc0_ib_vref_dq_byte11_modded_plus << 8); dst_timing->burst_perch_regs.emc0_mrw12 = emc0_ib_vref_dq_byte8_modded_plus | 0x880E0000 | (emc0_mrw12_op_sp1 << 8); if (dram_dev_num == TWO_RANK) { dst_timing->burst_perch_regs.emc0_mrw13 = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | 0x480E0000; dst_timing->burst_perch_regs.emc1_mrw13 = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | 0x480E0000; } else { dst_timing->burst_perch_regs.emc0_mrw13 = emc0_ib_vref_dq_byte9_modded_a_plus << 8 | emc0_mrw13_op_sp0 | 0xC80E0000; dst_timing->burst_perch_regs.emc1_mrw13 = (emc1_mrw13_op_sp1 << 8) | emc1_mrw13_op_sp0 | 0xC80E0000; } } } reg::Write(EMC + EMC_DBG, emc_dbg_tmp); } /* Step 25: * Program MC updown registers. */ if ((dst_timing->rate_khz > src_timing->rate_khz) && !training_enabled) { for (u32 i = 0; i < dst_timing->num_up_down; i++) { reg::Write(LaScaleRegisters[i], dst_timing->la_scale_regs_arr[i]); } /* Request a timing update. */ TimingUpdate(fbio_cfg7); } /* Step 26: * Restore ZCAL registers. */ if (dram_type == DRAM_TYPE_LPDDR4) { SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, dst_timing->burst_regs.emc_zcal_wait_cnt); reg::Write(EMC + EMC_ZCAL_INTERVAL, dst_timing->burst_regs.emc_zcal_interval); SetShadowBypass(ASSEMBLY); } if ((dram_type != DRAM_TYPE_LPDDR4) && opt_zcal_en_cc && !opt_short_zcal && opt_cc_short_zcal) { util::WaitMicroSeconds(2); SetShadowBypass(ACTIVE); if (dram_type == DRAM_TYPE_LPDDR2) { reg::Write(EMC + EMC_MRS_WAIT_CNT, dst_timing->burst_regs.emc_mrs_wait_cnt); } else if (dram_type == DRAM_TYPE_DDR4) { reg::Write(EMC + EMC_ZCAL_WAIT_CNT, dst_timing->burst_regs.emc_zcal_wait_cnt); } SetShadowBypass(ASSEMBLY); } /* Step 27: * Restore EMC_CFG, FDPD registers. */ SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_CFG, dst_timing->burst_regs.emc_cfg); SetShadowBypass(ASSEMBLY); reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, dst_timing->emc_fdpd_ctrl_cmd_no_ramp); reg::Write(EMC + EMC_SEL_DPD_CTRL, dst_timing->emc_sel_dpd_ctrl); /* Step 28: * Training recover. */ if (training_enabled && (dram_type == DRAM_TYPE_LPDDR4)) { SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_CFG, dst_timing->burst_regs.emc_cfg); reg::Write(EMC + EMC_SEL_DPD_CTRL, dst_timing->emc_sel_dpd_ctrl); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, src_timing->burst_regs.emc_zcal_wait_cnt); reg::Write(EMC + EMC_ZCAL_INTERVAL, src_timing->burst_regs.emc_zcal_interval); reg::Write(EMC + EMC_AUTO_CAL_CONFIG2, src_timing->emc_auto_cal_config2); reg::Write(EMC + EMC_AUTO_CAL_CONFIG3, src_timing->emc_auto_cal_config3); reg::Write(EMC + EMC_AUTO_CAL_CONFIG4, src_timing->emc_auto_cal_config4); reg::Write(EMC + EMC_AUTO_CAL_CONFIG5, src_timing->emc_auto_cal_config5); reg::Write(EMC + EMC_AUTO_CAL_CONFIG6, src_timing->emc_auto_cal_config6); reg::Write(EMC + EMC_AUTO_CAL_CONFIG7, src_timing->emc_auto_cal_config7); reg::Write(EMC + EMC_AUTO_CAL_CONFIG8, src_timing->emc_auto_cal_config8); SetShadowBypass(ASSEMBLY); reg::Write(EMC + EMC_TR_DVFS, dst_timing->burst_regs.emc_tr_dvfs & ~(1 << 0)); } SetShadowBypass(ACTIVE); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_COMMON, dst_timing->burst_regs.emc_pmacro_autocal_cfg_common); SetShadowBypass(ASSEMBLY); /* Step 29: * Power fix WAR. */ reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, 0xFF0000); reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_0, 0x8); reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_1, 0x8); reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, 0); /* Step 30: * Re-enable autocal. */ if (training_enabled) { emc_auto_cal_config = src_timing->emc_auto_cal_config; /* Restore FSP to account for switch back. Only needed in training. */ g_fsp_for_next_freq = !g_fsp_for_next_freq; } else { emc_auto_cal_config = dst_timing->emc_auto_cal_config; if (dst_timing->burst_regs.emc_cfg_dig_dll & 0x1) { DllEnableStall(fbio_cfg7); } } reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); } void CleanupActiveShadowCopy(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing) { const int dram_type = reg::GetValue(EMC + EMC_FBIO_CFG5, EMC_REG_BITS_MASK(FBIO_CFG5_DRAM_TYPE)); const u32 fbio_cfg7 = reg::Read(EMC + EMC_FBIO_CFG7); /* Change CFG_SWAP to ASSEMBLY_ONLY */ uint32_t emc_dbg = reg::Read(EMC + EMC_DBG); emc_dbg = ((emc_dbg & 0xF3FFFFFF) | 0x8000000); reg::Write(EMC + EMC_DBG, emc_dbg); /* Change UPDATE_AUTO_CAL_IN_UPDATE to ALWAYS */ uint32_t emc_cfg_update = reg::Read(EMC + EMC_CFG_UPDATE); emc_cfg_update = ((emc_cfg_update & 0xFFFFFFF9) | 0x04); reg::Write(EMC + EMC_CFG_UPDATE, emc_cfg_update); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Change UPDATE_AUTO_CAL_IN_UPDATE to NEVER */ emc_cfg_update = reg::Read(EMC + EMC_CFG_UPDATE); emc_cfg_update &= 0xFFFFFFF9; reg::Write(EMC + EMC_CFG_UPDATE, emc_cfg_update); /* Change CFG_SWAP to ACTIVE_ONLY */ emc_dbg = reg::Read(EMC + EMC_DBG); emc_dbg &= 0xF3FFFFFF; reg::Write(EMC + EMC_DBG, emc_dbg); /* Disable DLL and change CFG_DLL_MODE to RUN_PERIODIC */ uint32_t emc_cfg_dig_dll = reg::Read(EMC + EMC_CFG_DIG_DLL); emc_cfg_dig_dll = ((emc_cfg_dig_dll & 0xFFFFFF3E) | 0x80); reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Disable or enable DLL */ emc_cfg_dig_dll = reg::Read(EMC + EMC_CFG_DIG_DLL); if (dst_timing->burst_regs.emc_cfg_dig_dll == 0x01) { emc_cfg_dig_dll |= 0x01; } else { emc_cfg_dig_dll &= 0xFFFFFFFE; } /* Change CFG_DLL_MODE to RUN_PERIODIC */ emc_cfg_dig_dll = ((emc_cfg_dig_dll & 0xFFFFFF3F) | 0x80); reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait for DLL_LOCK to be set */ uint32_t emc_dig_dll_status = 0; do { emc_dig_dll_status = reg::Read(EMC + EMC_DIG_DLL_STATUS); } while (!(emc_dig_dll_status & (1 << 15))); /* Check if DRAM is LPDDR4 */ if (dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_RP, src_timing->burst_regs.emc_rp); reg::Write(EMC + EMC_R2P, src_timing->burst_regs.emc_r2p); reg::Write(EMC + EMC_W2P, src_timing->burst_regs.emc_w2p); reg::Write(EMC + EMC_TRPAB, src_timing->burst_regs.emc_trpab); } /* Request a timing update event */ TimingUpdate(fbio_cfg7); } void TrainFreq(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 next_clk_src) { /* Get dram dev num. */ const u32 dram_dev_num = (reg::Read(MC + MC_EMEM_ADR_CFG) & 1) + 1; /* Write RAM patterns, if first training. */ if (!g_did_first_training) { const auto * const pattern = GetEmcRamTrainingPattern(); for (u32 i = 0; i < 0x100; ++i) { reg::Write(EMC + EMC_TRAINING_PATRAM_DQ, pattern[dst_timing->training_pattern].dq[i]); reg::Write(EMC + EMC_TRAINING_PATRAM_DMI, pattern[dst_timing->training_pattern].dmi[i]); reg::Write(EMC + EMC_TRAINING_PATRAM_CTRL, 0x80000000 | i); } g_did_first_training = true; } /* Do training, if we need to. */ const u32 needed_training = dst_timing->needs_training; if (needed_training && !dst_timing->trained) { /* Determine what training to do. */ u32 training_params[8]; u32 num_params = 0; if (needed_training & (CA_TRAINING | CA_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (CA_TRAINING | CA_VREF_TRAINING | BIT_LEVEL_TRAINING)); } if (dram_dev_num == TWO_RANK) { if (needed_training & (CA_TRAINING | CA_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (CA_TRAINING | CA_VREF_TRAINING | TRAIN_SECOND_RANK | BIT_LEVEL_TRAINING)); } if (needed_training & (QUSE_TRAINING | QUSE_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (QUSE_TRAINING | QUSE_VREF_TRAINING | BIT_LEVEL_TRAINING)); training_params[num_params++] = (needed_training & (QUSE_TRAINING | BIT_LEVEL_TRAINING)); } } else { if (needed_training & (QUSE_TRAINING | QUSE_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (QUSE_TRAINING | QUSE_VREF_TRAINING | BIT_LEVEL_TRAINING)); } } if (needed_training & (WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING | BIT_LEVEL_TRAINING)); } /* Apply all training. */ for (u32 i = 0; i < num_params; ++i) { FreqChange(src_timing, dst_timing, training_params[i], next_clk_src); CleanupActiveShadowCopy(src_timing, dst_timing); } /* Set tables as trained. */ dst_timing->trained = 1; } } constexpr inline const u16 PeriodicCompensationRegisters[] = { EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3, EMC_DATA_BRLSHFT_0, EMC_DATA_BRLSHFT_1 }; void PeriodicCompensationRoutine(EmcDvfsTimingTable *timing) { if (timing->periodic_training) { const int dram_dev_num = (reg::Read(MC + MC_EMEM_ADR_CFG) & 1) + 1; const u32 fbio_cfg7 = timing->burst_regs.emc_fbio_cfg7; uint32_t emc_cfg_o = reg::Read(EMC + EMC_CFG); uint32_t emc_cfg_dig_dll_o = reg::Read(EMC + EMC_CFG_DIG_DLL); uint32_t emc_cfg_update_o = reg::Read(EMC + EMC_CFG_UPDATE); /* * 1. Power optimizations should be off. */ reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll_o & 0xFFFFFFFE); reg::Write(EMC + EMC_CFG_UPDATE, (emc_cfg_update_o & 0xFFFFF9FF) | 0x400); reg::Write(EMC + EMC_CFG, emc_cfg_o & 0x0FFFFFFF); /* Do timing update. */ TimingUpdate(fbio_cfg7); if (dram_dev_num == TWO_RANK) { WaitForUpdate(EMC_EMC_STATUS, 0x30, false, fbio_cfg7); } else { WaitForUpdate(EMC_EMC_STATUS, 0x10, false, fbio_cfg7); } WaitForUpdate(EMC_EMC_STATUS, 0x300, false, fbio_cfg7); WaitForUpdate(EMC_EMC_STATUS, 0x01, false, fbio_cfg7); /* * 2. osc kick off - this assumes training and dvfs have set * correct MR23. */ StartPeriodicCompensation(); /* * 3. Let dram capture its clock tree delays. */ util::WaitMicroSeconds(2 + ((ActualOscClocks(timing->run_clocks) * 1000) / timing->rate_khz)); /* * 4. Check delta wrt previous values (save value if margin * exceeds what is set in table). */ uint32_t del = UpdateClockTreeDelay(timing, timing, dram_dev_num, fbio_cfg7, PERIODIC_TRAINING_UPDATE); /* * 5. Apply compensation w.r.t. trained values (if clock tree * has drifted more than the set margin). */ if (timing->tree_margin < ((del * 128 * (timing->rate_khz / 1000)) / 1000000)) { for (u32 i = 0; i < util::size(PeriodicCompensationRegisters); ++i) { reg::Write(EMC + PeriodicCompensationRegisters[i], ApplyPeriodicCompensationTrimmer(timing, PeriodicCompensationRegisters[i])); } } /* Restore register values. */ reg::Write(EMC + EMC_CFG, emc_cfg_o); reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll_o); reg::Write(EMC + EMC_TIMING_CONTROL, 1); reg::Write(EMC + EMC_CFG_UPDATE, emc_cfg_update_o); } } void Dvfs(EmcDvfsTimingTable *dst_timing, EmcDvfsTimingTable *src_timing, bool train) { /* Get the old 2x clock source. */ const u32 prev_2x_clk_src = reg::GetValue(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); /* Set g_next_pll. */ g_next_pll = prev_2x_clk_src == PLLMB_UD || prev_2x_clk_src == PLLMB_OUT0; /* Reprogram pll. */ u32 next_clk_src; if (PllReprogram(dst_timing->rate_khz, dst_timing->clk_src_emc, src_timing->rate_khz, src_timing->clk_src_emc)) { if (prev_2x_clk_src == PLLMB_UD || prev_2x_clk_src == PLLMB_OUT0) { g_next_pll = 0; } else if (prev_2x_clk_src == PLLM_UD || prev_2x_clk_src == PLLM_OUT0) { g_next_pll = !g_next_pll; } next_clk_src = ProgramPllm(dst_timing->rate_khz, dst_timing->clk_src_emc, g_next_pll); } else { next_clk_src = dst_timing->clk_src_emc; const u32 next_2x_clk_src = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); if (next_2x_clk_src == PLLM_UD || next_2x_clk_src == PLLMB_UD) { if (g_next_pll) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_UD)); } } else if (next_2x_clk_src == PLLM_OUT0 || next_2x_clk_src == PLLMB_OUT0) { if (g_next_pll) { reg::SetField(next_clk_src, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_OUT0)); } } } if (train) { TrainFreq(src_timing, dst_timing, next_clk_src); if (PllReprogram(dst_timing->rate_khz, dst_timing->clk_src_emc, src_timing->rate_khz, src_timing->clk_src_emc)) { g_next_pll = !g_next_pll; } } else { FreqChange(src_timing, dst_timing, 0, next_clk_src); PeriodicCompensationRoutine(dst_timing); } } } void DoMemoryTrainingErista(int index, void *mtc_tables_buffer) { /* Get timing tables. */ auto *timing_tables = GetEmcDvfsTimingTables(index, mtc_tables_buffer); auto *timing_204 = timing_tables + 0; auto *timing_800 = timing_tables + 1; auto *timing_1600 = timing_tables + 2; /* Check timing tables. */ if (timing_204->rate_khz != 204000 || timing_1600->rate_khz != 1600000) { ShowFatalError("EmcDvfsTimingTables seem corrupted %" PRIu32 " %" PRIu32 " %" PRIu32 "?\n", timing_204->rate_khz, timing_800->rate_khz, timing_1600->rate_khz); } /* Check that we should do training. */ if (timing_204->clk_src_emc != reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC)) { /* Our clock source isn't what's expected, so presumably training has already been done? */ /* Either way, the safe bet is to skip it. */ return; } /* Train 800MHz. */ Dvfs(timing_800, timing_204, true); /* Train 1600MHz. */ Dvfs(timing_1600, timing_204, true); /* Switch to 800MHz. */ Dvfs(timing_800, timing_204, false); /* Switch to 1600MHz. */ Dvfs(timing_1600, timing_800, false); /* Wait 100ms. */ util::WaitMicroSeconds(100000); /* Do Periodic compensation */ PeriodicCompensationRoutine(timing_1600); } } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_mariko.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "../fusee_fatal.hpp" #include "../fusee_uncompress.hpp" #include "fusee_mtc.hpp" #include "fusee_mtc_timing_table_mariko.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t MC = MC_BASE; constexpr inline const uintptr_t EMC = EMC_BASE; constexpr inline const uintptr_t EMC0 = EMC0_BASE; constexpr inline const uintptr_t EMC1 = EMC1_BASE; static constinit bool g_next_pll = false; static constinit bool g_did_first_training = false; static constinit bool g_fsp_for_next_freq = false; #include "fusee_mtc_tables_mariko.inc" #include "fusee_mtc_ram_training_pattern.inc" #define DECLARE_REGISTER_HANDLER(BASE, REG, NAME) BASE + REG, constexpr inline const u32 BurstRegisters[] = { FOREACH_BURST_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 TrimRegisters[] = { FOREACH_TRIM_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 BurstMcRegisters[] = { FOREACH_BURST_MC_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 LaScaleRegisters[] = { FOREACH_LA_SCALE_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelTrimRegisters[] = { FOREACH_PER_CHANNEL_TRIM_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelBurstRegisters[] = { FOREACH_PER_CHANNEL_BURST_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelVrefRegisters[] = { FOREACH_PER_CHANNEL_VREF_REG(DECLARE_REGISTER_HANDLER) }; constexpr inline const u32 PerChannelTrainingModRegisters[] = { FOREACH_PER_CHANNEL_TRAINING_MOD_REG(DECLARE_REGISTER_HANDLER) }; using EmcDvfsTimingTable = mariko::EmcDvfsTimingTable; EmcDvfsTimingTable *GetEmcDvfsTimingTables(int index, void *mtc_tables_buffer) { /* Get the compressed table. */ const u8 *cmp_table; size_t cmp_table_size; switch (index) { #define HANDLE_CASE(N, TABLE) \ case N: \ cmp_table = TABLE; \ cmp_table_size = sizeof(TABLE); \ break; HANDLE_CASE(0x00, T210b01SdevEmcDvfsTableS4gb01) HANDLE_CASE(0x05, T210b01SdevEmcDvfsTableS4gb03) HANDLE_CASE(0x06, T210b01SdevEmcDvfsTableS8gb03) HANDLE_CASE(0x07, T210b01SdevEmcDvfsTableH4gb03) HANDLE_CASE(0x08, T210b01SdevEmcDvfsTableM4gb03) HANDLE_CASE(0x09, T210b01SdevEmcDvfsTableS4gbY01) HANDLE_CASE(0x0A, T210b01SdevEmcDvfsTableS1y4gbY01) HANDLE_CASE(0x0B, T210b01SdevEmcDvfsTableS1y8gbY01) HANDLE_CASE(0x0C, T210b01SdevEmcDvfsTableS1y4gbX03) HANDLE_CASE(0x0D, T210b01SdevEmcDvfsTableS1y8gbX03) HANDLE_CASE(0x0E, T210b01SdevEmcDvfsTableS1y4gb01) HANDLE_CASE(0x0F, T210b01SdevEmcDvfsTableM1y4gb01) HANDLE_CASE(0x10, T210b01SdevEmcDvfsTableH1y4gb01) HANDLE_CASE(0x11, T210b01SdevEmcDvfsTableS1y8gb04) HANDLE_CASE(0x12, T210b01SdevEmcDvfsTableS1z4gb01) HANDLE_CASE(0x13, T210b01SdevEmcDvfsTableH1a4gb01) HANDLE_CASE(0x14, T210b01SdevEmcDvfsTableM1a4gb01) default: ShowFatalError("Unknown EmcDvfsTimingTableIndex: %d\n", index); } /* Uncompress the table. */ EmcDvfsTimingTable *out_tables = reinterpret_cast<EmcDvfsTimingTable *>(mtc_tables_buffer); Uncompress(out_tables, 2 * sizeof(EmcDvfsTimingTable), cmp_table, cmp_table_size); return out_tables; } bool IsSamePll(u32 next_2x, u32 prev_2x) { if (next_2x == prev_2x) { return true; } else if ((next_2x == PLLM_OUT0 || next_2x == PLLM_UD) && (prev_2x == PLLM_OUT0 || prev_2x == PLLM_UD)) { return true; } else { return false; } } bool PllReprogram(u32 next_rate_khz, u32 next_clk_src, u32 prev_rate_khz, u32 prev_clk_src) { /* Get current divp value. */ u32 pll_p; switch (reg::GetValue(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLM_UD: case PLLM_OUT0: pll_p = reg::GetValue(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_MASK(PLLM_BASE_PLLM_DIVP_B01)); break; case PLLMB_UD: case PLLMB_OUT0: pll_p = reg::GetValue(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, CLK_RST_REG_BITS_MASK(PLLMB_BASE_PLLMB_DIVP_B01)); break; default: pll_p = 0; break; } /* Get clk src/divisor. */ const u32 next_2x = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); const u32 prev_2x = reg::GetField(prev_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); u32 next_div = reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR)); u32 prev_div = reg::GetField(prev_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR)); /* Update divisor, if necessary. */ if (next_2x == PLLM_UD || next_2x == PLLMB_UD) { next_div = 0; } if (prev_2x == PLLM_UD || prev_2x == PLLMB_UD) { prev_div = 0; } /* If the pll is different, reprogramming is necessary. */ if (!IsSamePll(next_2x, prev_2x)) { return true; } /* Return whether the ratios are different. */ const float next_freq = next_rate_khz * (1 + (next_div >> 1) + (0.5 * (next_div & 1))) * (pll_p + 1); const float prev_freq = prev_rate_khz * (1 + (prev_div >> 1) + (0.5 * (prev_div & 1))) * (pll_p + 1); const float ratio = prev_freq / next_freq; return ratio > 1.01 || ratio < 0.99; } u32 ProgramPllm(u32 next_rate_khz, u32 next_clk_src, u32 ret_clk_src, bool is_pllmb, EmcDvfsTimingTable *timing) { u32 ret = ret_clk_src; const uint32_t base = ((timing->pllmb_divm & 0xFF) | ((timing->pllmb_divn & 0xFF) << 8) | ((timing->pllmb_divp & 1) << 20)); if (is_pllmb) { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, base); reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE); reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLMB_MISC1, 0x10000000); if (timing->pll_en_ssc & 1) { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_SS_CFG, timing->pllmb_ss_cfg); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_SS_CTRL1, timing->pllmb_ss_ctrl1); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_SS_CTRL2, timing->pllmb_ss_ctrl2); } else { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_SS_CFG, timing->pllmb_ss_cfg & 0xBFFFFFFF); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLMB_SS_CTRL2, timing->pllmb_ss_ctrl2 & 0x0000FFFF); } reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, 0x40000000); switch (reg::GetField(ret, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLM_OUT0: reg::SetField(ret, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_OUT0)); break; case PLLM_UD: reg::SetField(ret, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_UD)); break; } while ((reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE) & 0x8000000) == 0) { /* ... */ } return ret; } else { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, base); reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE); reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC2, 0x10); if (timing->pll_en_ssc & 1) { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_SS_CFG, timing->pllm_ss_cfg); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_SS_CTRL1, timing->pllm_ss_ctrl1); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_SS_CTRL2, timing->pllm_ss_ctrl2); } else { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_SS_CFG, timing->pllm_ss_cfg & 0xBFFFFFFF); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_SS_CTRL2, timing->pllm_ss_ctrl2 & 0x0000FFFF); } reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, 0x40000000); switch (reg::GetField(ret, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLM_OUT0: reg::SetField(ret, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLM_OUT0)); break; case PLLM_UD: reg::SetField(ret, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLM_UD)); break; } while ((reg::Read(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000) == 0) { /* ... */ } return ret; } } u32 GetDllState(EmcDvfsTimingTable *timing) { return (!(timing->emc_emrs & 0x1)) ? DLL_ON : DLL_OFF; } int WaitForUpdate(u32 reg_offset, u32 mask, bool updated, u32 fbio_cfg7) { constexpr int StatusUpdateTimeout = 1000; int result = 0; if (reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH0_ENABLE)) == EMC_FBIO_CFG7_CH0_ENABLE_ENABLE) { bool success = false; for (int i = 0; i < StatusUpdateTimeout; ++i) { if (((reg::Read(EMC0 + reg_offset) & mask) != 0) == updated) { success = true; break; } util::WaitMicroSeconds(1); } result |= success ? 0 : 4; } if (reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE) { bool success = false; for (int i = 0; i < StatusUpdateTimeout; ++i) { if (((reg::Read(EMC1 + reg_offset) & mask) != 0) == updated) { success = true; break; } util::WaitMicroSeconds(1); } result |= success ? 0 : 4; } return result; } void TimingUpdate(u32 fbio_cfg7) { /* Trigger the timing update event. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); /* Wait for the update to finish. */ WaitForUpdate(EMC_EMC_STATUS, 0x800000, false, fbio_cfg7); } void CcfifoWrite(u32 addr, u32 data, u32 wait) { reg::Write(EMC + EMC_CCFIFO_DATA, data); reg::Write(EMC + EMC_CCFIFO_ADDR, (addr & 0xFFFF) | ((wait & 0x7FFF) << 16) | 0x80000000); } u32 ActualOscClocks(u32 in) { if (in < 0x40) { return in * 0x10; } else if (in < 0x80) { return 0x800; } else if (in < 0xC0) { return 0x1000; } else { return 0x2000; } } u32 DivideUpFloat(u32 a, u32 b) { const float res = a / b; const u32 floor = static_cast<u32>(res); return floor + ((static_cast<float>(floor) + 0.01 < res) ? 1 : 0); } void StartPeriodicCompensation() { reg::Write(EMC + EMC_MPC, 0x4B); reg::Read(EMC + EMC_MPC); } u32 SetShadowBypass(u32 val, u32 emc_dbg) { reg::SetField(emc_dbg, EMC_REG_BITS_VALUE(DBG_WRITE_MUX, val)); return emc_dbg; } constinit uint32_t g_periodic_timmer_compensation_intermediates[9 * 0x10] = {}; uint32_t ApplyPeriodicCompensationTrimmer(EmcDvfsTimingTable *timing, uint32_t trim_reg) { /* Initialize variables. */ uint32_t rate_mhz = timing->rate_khz / 1000; uint32_t adj[0x10] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; int tree_delta[4] = {0}; uint32_t tree_delta_taps[4] = {0}; /* Generate the intermediate array. */ #define SET_TRIM_INTERMEDIATE(_arr_, _emc_, _rank_, _byte_) \ ({ \ const uint32_t shft = timing->trim_perch_regs.emc## _emc_ ##_data_brlshft_## _rank_; \ const uint32_t base = ((shft >> (3 * _byte_)) & 7) << 6; \ const uint32_t val0 = timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank ## _rank_ ## _byte ## _byte_ ## _0; \ const uint32_t val1 = timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank ## _rank_ ## _byte ## _byte_ ## _1; \ const uint32_t val2 = timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank ## _rank_ ## _byte ## _byte_ ## _2; \ _arr_[9 * (8 * _rank_ + _byte_) + 0] = base + ((val0 >> 0) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 1] = base + ((val0 >> 8) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 2] = base + ((val0 >> 16) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 3] = base + ((val0 >> 24) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 4] = base + ((val1 >> 0) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 5] = base + ((val1 >> 8) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 6] = base + ((val1 >> 16) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 7] = base + ((val1 >> 24) & 0xFF); \ _arr_[9 * (8 * _rank_ + _byte_) + 8] = base + ((val2 >> 0) & 0xFF); \ }) { SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 0, 0); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 0, 1); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 0, 2); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 0, 3); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 0, 4); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 0, 5); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 0, 6); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 0, 7); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 1, 0); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 1, 1); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 1, 2); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 0, 1, 3); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 1, 4); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 1, 5); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 1, 6); SET_TRIM_INTERMEDIATE(g_periodic_timmer_compensation_intermediates, 1, 1, 7); } #undef SET_TRIM_INTERMEDIATE switch (trim_reg) { case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2: case EMC0_BASE + EMC_DATA_BRLSHFT_0: case EMC1_BASE + EMC_DATA_BRLSHFT_0: { tree_delta[0] = 128 * (timing->current_dram_clktree_c0d0u0 - timing->trained_dram_clktree_c0d0u0); tree_delta[1] = 128 * (timing->current_dram_clktree_c0d0u1 - timing->trained_dram_clktree_c0d0u1); tree_delta[2] = 128 * (timing->current_dram_clktree_c1d0u0 - timing->trained_dram_clktree_c1d0u0); tree_delta[3] = 128 * (timing->current_dram_clktree_c1d0u1 - timing->trained_dram_clktree_c1d0u1); tree_delta_taps[0] = (tree_delta[0] * (int)rate_mhz) / 1000000; tree_delta_taps[1] = (tree_delta[1] * (int)rate_mhz) / 1000000; tree_delta_taps[2] = (tree_delta[2] * (int)rate_mhz) / 1000000; tree_delta_taps[3] = (tree_delta[3] * (int)rate_mhz) / 1000000; for (int i = 0; i < 4; ++i) { const uint32_t sum = (tree_delta_taps[i] <= timing->tree_margin) ? 0 : tree_delta_taps[i]; for (int j = 0; j < 18; ++j) { const uint32_t v = (g_periodic_timmer_compensation_intermediates[18 * i + j] += sum); if (v < (adj[2 * i + (j < 9)] << 6)) { adj[2 * i + (j < 9)] = v >> 6; } } for (int j = 0; j < 18; ++j) { g_periodic_timmer_compensation_intermediates[18 * i + j] -= (adj[2 * i + (j < 9)] << 6); } } } break; case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2: case EMC0_BASE + EMC_DATA_BRLSHFT_1: case EMC1_BASE + EMC_DATA_BRLSHFT_1: { tree_delta[0] = 128 * (timing->current_dram_clktree_c0d1u0 - timing->trained_dram_clktree_c0d1u0); tree_delta[1] = 128 * (timing->current_dram_clktree_c0d1u1 - timing->trained_dram_clktree_c0d1u1); tree_delta[2] = 128 * (timing->current_dram_clktree_c1d1u0 - timing->trained_dram_clktree_c1d1u0); tree_delta[3] = 128 * (timing->current_dram_clktree_c1d1u1 - timing->trained_dram_clktree_c1d1u1); tree_delta_taps[0] = (tree_delta[0] * (int)rate_mhz) / 1000000; tree_delta_taps[1] = (tree_delta[1] * (int)rate_mhz) / 1000000; tree_delta_taps[2] = (tree_delta[2] * (int)rate_mhz) / 1000000; tree_delta_taps[3] = (tree_delta[3] * (int)rate_mhz) / 1000000; for (int i = 0; i < 4; ++i) { const uint32_t sum = (tree_delta_taps[i] <= timing->tree_margin) ? 0 : tree_delta_taps[i]; for (int j = 0; j < 18; ++j) { const uint32_t v = (g_periodic_timmer_compensation_intermediates[72 + 18 * i + j] += sum); if (v < (adj[8 + 2 * i + (j < 9)] << 6)) { adj[8 + 2 * i + (j < 9)] = v >> 6; } } for (int j = 0; j < 18; ++j) { g_periodic_timmer_compensation_intermediates[72 + 18 * i + j] -= (adj[8 + 2 * i + (j < 9)] << 6); } } } break; } uint32_t result = 0; switch (trim_reg) { case EMC0_BASE + EMC_DATA_BRLSHFT_0: result = ((adj[ 0] & 7) << 0) | ((adj[ 1] & 7) << 3) | ((adj[ 2] & 7) << 6) | ((adj[ 3] & 7) << 9); break; case EMC1_BASE + EMC_DATA_BRLSHFT_0: result = ((adj[ 4] & 7) << 12) | ((adj[ 5] & 7) << 15) | ((adj[ 6] & 7) << 18) | ((adj[ 7] & 7) << 21); break; case EMC0_BASE + EMC_DATA_BRLSHFT_1: result = ((adj[ 8] & 7) << 0) | ((adj[ 9] & 7) << 3) | ((adj[10] & 7) << 6) | ((adj[11] & 7) << 9); break; case EMC1_BASE + EMC_DATA_BRLSHFT_1: result = ((adj[12] & 7) << 12) | ((adj[13] & 7) << 15) | ((adj[14] & 7) << 18) | ((adj[15] & 7) << 21); break; #define ADD_TRIM_CASE(_ARR_, _RANK_, _BYTE_) \ case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK ## _RANK_ ## _BYTE ## _BYTE_ ##_0: \ result = ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 0] & 0xFF) << 0) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 1] & 0xFF) << 8) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 2] & 0xFF) << 16) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 3] & 0xFF) << 24); \ break; \ case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK ## _RANK_ ## _BYTE ## _BYTE_ ##_1: \ result = ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 4] & 0xFF) << 0) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 5] & 0xFF) << 8) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 6] & 0xFF) << 16) | ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 7] & 0xFF) << 24); \ break; \ case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK ## _RANK_ ## _BYTE ## _BYTE_ ##_2: \ result = ((_ARR_[9 * (8 * _RANK_ + _BYTE_) + 8] & 0xFF) << 0); \ break; ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 0); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 1); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 2); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 3); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 4); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 5); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 6); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 0, 7); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 0); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 1); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 2); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 3); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 4); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 5); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 6); ADD_TRIM_CASE(g_periodic_timmer_compensation_intermediates, 1, 7); #undef ADD_TRIM_CASE } return result; } u32 UpdateClockTreeDelay(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 dram_dev_num, u32 mode, int type) { uint32_t mrr_req = 0, mrr_data = 0; uint32_t temp0_0 = 0, temp0_1 = 0, temp1_0 = 0, temp1_1 = 0; int tdel = 0, tmdel = 0, adel = 0; uint32_t current_timing_rate_mhz = src_timing->rate_khz / 1000; uint32_t next_timing_rate_mhz = dst_timing->rate_khz / 1000; uint32_t fbio_cfg7 = dst_timing->emc_fbio_cfg7; const bool ch0_enable = reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH0_ENABLE)) == EMC_FBIO_CFG7_CH0_ENABLE_ENABLE; const bool ch1_enable = reg::GetField(fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE; bool dvfs_pt1 = (type == DVFS_PT1); bool training_pt1 = (type == TRAINING_PT1); bool dvfs_update = (type == DVFS_UPDATE); bool training_update = (type == TRAINING_UPDATE); bool periodic_training_update = (type == PERIODIC_TRAINING_UPDATE); /* Dev0 MSB. */ if (dvfs_pt1 || training_pt1 || periodic_training_update) { mrr_req = ((2 << 30) | (19 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, (1 << 20), true, fbio_cfg7); if (ch0_enable) { mrr_data = (reg::Read(EMC0 + EMC_MRR) & 0xFFFF); temp0_0 = ((mrr_data & 0xff) << 8); temp0_1 = (mrr_data & 0xff00); } else { temp0_0 = temp0_1 = 0; } if (ch1_enable) { mrr_data = (reg::Read(EMC1 + EMC_MRR) & 0xFFFF); temp1_0 = ((mrr_data & 0xff) << 8); temp1_1 = (mrr_data & 0xff00); } else { temp1_0 = temp1_1 = 0; } /* Dev0 LSB. */ mrr_req = ((mrr_req & ~(0xFF << 16)) | (18 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, (1 << 20), true, fbio_cfg7); if (ch0_enable) { mrr_data = (reg::Read(EMC0 + EMC_MRR) & 0xFFFF); temp0_0 |= (mrr_data & 0xff); temp0_1 |= (mrr_data & 0xff00) >> 8; } if (ch1_enable) { mrr_data = (reg::Read(EMC1 + EMC_MRR) & 0xFFFF); temp1_0 |= (mrr_data & 0xff); temp1_1 |= (mrr_data & 0xff00) >> 8; } } #define CVAL(v) ((uint32_t)((1000 * ((1000 * ActualOscClocks(src_timing->run_clocks)) / current_timing_rate_mhz)) / (2 * v))) if (ch0_enable) { if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d0u0, CVAL(temp0_0)); else if (dvfs_update) __AVERAGE_PTFV(c0d0u0); else if (training_update) __AVERAGE_WRITE_PTFV(c0d0u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d0u0, CVAL(temp0_0)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c0d0u0 - __MOVAVG_AC(dst_timing, c0d0u0)); tmdel = (tdel < 0) ? ~tdel : tdel; adel = tmdel; if (mode == 1 || ((adel * 128 * next_timing_rate_mhz) / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d0u0 = __MOVAVG_AC(dst_timing, c0d0u0); } if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d0u1, CVAL(temp0_1)); else if (dvfs_update) __AVERAGE_PTFV(c0d0u1); else if (training_update) __AVERAGE_WRITE_PTFV(c0d0u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d0u1, CVAL(temp0_1)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c0d0u1 - __MOVAVG_AC(dst_timing, c0d0u1)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d0u1 = __MOVAVG_AC(dst_timing, c0d0u1); } } else { adel = 0; } if (ch1_enable) { if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d0u0, CVAL(temp1_0)); else if (dvfs_update) __AVERAGE_PTFV(c1d0u0); else if (training_update) __AVERAGE_WRITE_PTFV(c1d0u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d0u0, CVAL(temp1_0)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c1d0u0 - __MOVAVG_AC(dst_timing, c1d0u0)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d0u0 = __MOVAVG_AC(dst_timing, c1d0u0); } if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d0u1, CVAL(temp1_1)); else if (dvfs_update) __AVERAGE_PTFV(c1d0u1); else if (training_update) __AVERAGE_WRITE_PTFV(c1d0u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d0u1, CVAL(temp1_1)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c1d0u1 - __MOVAVG_AC(dst_timing, c1d0u1)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d0u1 = __MOVAVG_AC(dst_timing, c1d0u1); } } if (dram_dev_num == TWO_RANK) { /* Dev1 MSB. */ if (dvfs_pt1 || training_pt1 || periodic_training_update) { mrr_req = ((1 << 30) | (19 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, (1 << 20), true, fbio_cfg7); if (ch0_enable) { mrr_data = (reg::Read(EMC0 + EMC_MRR) & 0xFFFF); temp0_0 = ((mrr_data & 0xff) << 8); temp0_1 = (mrr_data & 0xff00); } if (ch1_enable) { mrr_data = (reg::Read(EMC1 + EMC_MRR) & 0xFFFF); temp1_0 = ((mrr_data & 0xff) << 8); temp1_1 = (mrr_data & 0xff00); } /* Dev1 LSB. */ mrr_req = ((mrr_req & ~(0xFF << 16)) | (18 << 16)); reg::Write(EMC + EMC_MRR, mrr_req); WaitForUpdate(EMC_EMC_STATUS, (1 << 20), true, fbio_cfg7); if (ch0_enable) { mrr_data = (reg::Read(EMC0 + EMC_MRR) & 0xFFFF); temp0_0 |= ((mrr_data & 0xff) << 8); temp0_1 |= (mrr_data & 0xff00); } if (ch1_enable) { mrr_data = (reg::Read(EMC1 + EMC_MRR) & 0xFFFF); temp1_0 |= ((mrr_data & 0xff) << 8); temp1_1 |= (mrr_data & 0xff00); } } if (ch0_enable) { if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d1u0, CVAL(temp0_0)); else if (dvfs_update) __AVERAGE_PTFV(c0d1u0); else if (training_update) __AVERAGE_WRITE_PTFV(c0d1u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d1u0, CVAL(temp0_0)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c0d1u0 - __MOVAVG_AC(dst_timing, c0d1u0)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d1u0 = __MOVAVG_AC(dst_timing, c0d1u0); } if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c0d1u1, CVAL(temp0_1)); else if (dvfs_update) __AVERAGE_PTFV(c0d1u1); else if (training_update) __AVERAGE_WRITE_PTFV(c0d1u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c0d1u1, CVAL(temp0_1)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c0d1u1 - __MOVAVG_AC(dst_timing, c0d1u1)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c0d1u1 = __MOVAVG_AC(dst_timing, c0d1u1); } } if (ch1_enable) { if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d1u0, CVAL(temp1_0)); else if (dvfs_update) __AVERAGE_PTFV(c1d1u0); else if (training_update) __AVERAGE_WRITE_PTFV(c1d1u0); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d1u0, CVAL(temp1_0)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c1d1u0 - __MOVAVG_AC(dst_timing, c1d1u0)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d1u0 = __MOVAVG_AC(dst_timing, c1d1u0); } if (dvfs_pt1 || training_pt1) __INCREMENT_PTFV(c1d1u1, CVAL(temp1_1)); else if (dvfs_update) __AVERAGE_PTFV(c1d1u1); else if (training_update) __AVERAGE_WRITE_PTFV(c1d1u1); else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(c1d1u1, CVAL(temp1_1)); if (dvfs_update || training_update || periodic_training_update) { tdel = (dst_timing->current_dram_clktree_c1d1u1 - __MOVAVG_AC(dst_timing, c1d1u1)); tmdel = (tdel < 0) ? -1 * tdel : tdel; if (tmdel > adel) adel = tmdel; if (mode == 1 || (tmdel * 128 * next_timing_rate_mhz / 1000000) > dst_timing->tree_margin) dst_timing->current_dram_clktree_c1d1u1 = __MOVAVG_AC(dst_timing, c1d1u1); } } } #undef CVAL if (mode == 1) { dst_timing->trained_dram_clktree_c0d0u0 = dst_timing->current_dram_clktree_c0d0u0; dst_timing->trained_dram_clktree_c0d0u1 = dst_timing->current_dram_clktree_c0d0u1; dst_timing->trained_dram_clktree_c0d1u0 = dst_timing->current_dram_clktree_c0d1u0; dst_timing->trained_dram_clktree_c0d1u1 = dst_timing->current_dram_clktree_c0d1u1; dst_timing->trained_dram_clktree_c1d0u0 = dst_timing->current_dram_clktree_c1d0u0; dst_timing->trained_dram_clktree_c1d0u1 = dst_timing->current_dram_clktree_c1d0u1; dst_timing->trained_dram_clktree_c1d1u0 = dst_timing->current_dram_clktree_c1d1u0; dst_timing->trained_dram_clktree_c1d1u1 = dst_timing->current_dram_clktree_c1d1u1; } return adel; } u32 PeriodicCompensationHandler(int type, u32 dram_dev_num, EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing) { if (!dst_timing->periodic_training) { return 0; } uint32_t adel = 0; uint32_t samples = dst_timing->ptfv_dvfs_samples; uint32_t samples_write = dst_timing->ptfv_write_samples; uint32_t delay = 2 + (1000 * ActualOscClocks(src_timing->run_clocks) / src_timing->rate_khz); if (type == DVFS_SEQUENCE) { if (src_timing->periodic_training && (dst_timing->ptfv_config_ctrl & 1)) { /* If the previous frequency was using periodic calibration then we can reuse the previous frequencies EMA data. */ dst_timing->ptfv_dqsosc_movavg_c0d0u0 = src_timing->ptfv_dqsosc_movavg_c0d0u0 * samples; dst_timing->ptfv_dqsosc_movavg_c0d0u1 = src_timing->ptfv_dqsosc_movavg_c0d0u1 * samples; dst_timing->ptfv_dqsosc_movavg_c1d0u0 = src_timing->ptfv_dqsosc_movavg_c1d0u0 * samples; dst_timing->ptfv_dqsosc_movavg_c1d0u1 = src_timing->ptfv_dqsosc_movavg_c1d0u1 * samples; dst_timing->ptfv_dqsosc_movavg_c0d1u0 = src_timing->ptfv_dqsosc_movavg_c0d1u0 * samples; dst_timing->ptfv_dqsosc_movavg_c0d1u1 = src_timing->ptfv_dqsosc_movavg_c0d1u1 * samples; dst_timing->ptfv_dqsosc_movavg_c1d1u0 = src_timing->ptfv_dqsosc_movavg_c1d1u0 * samples; dst_timing->ptfv_dqsosc_movavg_c1d1u1 = src_timing->ptfv_dqsosc_movavg_c1d1u1 * samples; } else { /* Reset the EMA. */ dst_timing->ptfv_dqsosc_movavg_c0d0u0 = 0; dst_timing->ptfv_dqsosc_movavg_c0d0u1 = 0; dst_timing->ptfv_dqsosc_movavg_c0d1u0 = 0; dst_timing->ptfv_dqsosc_movavg_c0d1u1 = 0; dst_timing->ptfv_dqsosc_movavg_c1d0u0 = 0; dst_timing->ptfv_dqsosc_movavg_c1d0u1 = 0; dst_timing->ptfv_dqsosc_movavg_c1d1u0 = 0; dst_timing->ptfv_dqsosc_movavg_c1d1u1 = 0; for (uint32_t i = 0; i < samples; ++i) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); /* Generate next sample of data. */ adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, 0, DVFS_PT1); } } adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, 0, DVFS_UPDATE); } else if (type == WRITE_TRAINING_SEQUENCE) { /* Reset the EMA. */ dst_timing->ptfv_dqsosc_movavg_c0d0u0 = 0; dst_timing->ptfv_dqsosc_movavg_c0d0u1 = 0; dst_timing->ptfv_dqsosc_movavg_c0d1u0 = 0; dst_timing->ptfv_dqsosc_movavg_c0d1u1 = 0; dst_timing->ptfv_dqsosc_movavg_c1d0u0 = 0; dst_timing->ptfv_dqsosc_movavg_c1d0u1 = 0; dst_timing->ptfv_dqsosc_movavg_c1d1u0 = 0; dst_timing->ptfv_dqsosc_movavg_c1d1u1 = 0; for (uint32_t i = 0; i < samples_write; ++i) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); /* Generate next sample of data. */ adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, 1, TRAINING_PT1); } adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, 1, TRAINING_UPDATE); } else if (type == PERIODIC_TRAINING_SEQUENCE) { StartPeriodicCompensation(); util::WaitMicroSeconds(delay); adel = UpdateClockTreeDelay(src_timing, dst_timing, dram_dev_num, 0, PERIODIC_TRAINING_UPDATE); } return adel; } void ChangeDllSrc(EmcDvfsTimingTable *dst_timing, u32 next_clk_src) { u32 dll_setting = ((next_clk_src & 0xE00000FF) | (dst_timing->dll_clk_src & 0x1FFFFF00)) & 0xFFFFF3FF; switch (reg::GetField(next_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLMB_UD: dll_setting |= 0x400; /* PLLM_VCOB */ break; case PLLM_UD: dll_setting |= 0x000; /* PLLM_VCOA */ break; default: dll_setting |= 0x800; /* EMC_DLL_SWITCH_OUT */ break; } reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL, dll_setting); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_REG_BITS_ENUM_SEL(CLK_ENB_X_CLK_ENB_EMC_DLL, (dst_timing->clk_out_enb_x_0_clk_enb_emc_dll & 1), ENABLE, DISABLE)); reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X); } void DllPrelock(EmcDvfsTimingTable *dst_timing, EmcDvfsTimingTable *src_timing, bool training_enabled, u32 next_clk_src) { /* Update EMC_CFG_DIG_DLL */ reg::Write(EMC + EMC_CFG_DIG_DLL, (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFFFE4) | 0x00000008); /* Request a timing update event */ TimingUpdate(dst_timing->emc_fbio_cfg7); /* Update EMC_CFG_DIG_DLL */ reg::Write(EMC + EMC_CFG_DIG_DLL, (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFF824) | 0x000003C8); /* Request a timing update event */ TimingUpdate(dst_timing->emc_fbio_cfg7); /* Wait until CFG_DLL_EN is cleared. */ WaitForUpdate(EMC_CFG_DIG_DLL, (1 << 0), false, dst_timing->emc_fbio_cfg7); /* Configure PMACRO_DLL_CFG */ reg::Write(EMC + EMC_PMACRO_DLL_CFG_0, dst_timing->burst_regs.emc_pmacro_dll_cfg_0); reg::Read(EMC + EMC_PMACRO_DLL_CFG_1); reg::Write(EMC + EMC_PMACRO_DLL_CFG_1, (dst_timing->burst_regs.emc_pmacro_dll_cfg_1 & 0xFFFFDFFF) | (reg::Read(EMC + EMC_PMACRO_DLL_CFG_1) & 0x00002000)); /* Request a timing update event */ TimingUpdate(dst_timing->emc_fbio_cfg7); /* Change the dll clock source. */ ChangeDllSrc(dst_timing, next_clk_src); /* Wait 2 us. */ util::WaitMicroSeconds(2); /* Enable dll. */ reg::SetBits(EMC + EMC_CFG_DIG_DLL, 0x1); /* Request a timing update event */ TimingUpdate(dst_timing->emc_fbio_cfg7); /* Wait until CFG_DLL_EN is set. */ WaitForUpdate(EMC_CFG_DIG_DLL, (1 << 0), true, dst_timing->emc_fbio_cfg7); /* Wait for DLL_LOCK to be set */ WaitForUpdate(EMC_DIG_DLL_STATUS, (1 << 2), true, dst_timing->emc_fbio_cfg7); if (training_enabled) { /* Disable dll. */ reg::SetBits(EMC + EMC_DBG, 0x2); reg::ClearBits(EMC + EMC_CFG_DIG_DLL, 0x1); reg::ClearBits(EMC + EMC_DBG, 0x2); /* Wait until CFG_DLL_EN is cleared. */ WaitForUpdate(EMC_CFG_DIG_DLL, (1 << 0), false, dst_timing->emc_fbio_cfg7); } reg::Read(EMC + EMC_PMACRO_DIG_DLL_STATUS_0); } void DllDisable(u32 fbio_cfg7) { /* Disable dll. */ reg::ClearBits(EMC + EMC_CFG_DIG_DLL, 0x1); /* Request a timing update event */ TimingUpdate(fbio_cfg7); /* Wait until CFG_DLL_EN is cleared. */ WaitForUpdate(EMC_CFG_DIG_DLL, (1 << 0), false, fbio_cfg7); } void PllDisable(u32 dst_clk_src) { switch (reg::GetField(dst_clk_src, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC))) { case PLLM_OUT0: case PLLM_UD: reg::ClearBits(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, 0x40000000); break; case PLLMB_OUT0: case PLLMB_UD: reg::ClearBits(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, 0x40000000); break; default: reg::ClearBits(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, 0x40000000); reg::ClearBits(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, 0x40000000); break; } } void DvfsPowerRampDown(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, bool flip_backward, u32 vtt_vdda_channel) { auto *from_table = (flip_backward ? dst_timing : src_timing); auto *to_table = (flip_backward ? src_timing : dst_timing); uint32_t from_rate_khz = from_table->rate_khz; uint32_t from_period = 1000000000 / from_rate_khz; uint32_t to_rate_khz = to_table->rate_khz; uint32_t clk_div = 1000 * dst_timing->src_clock_div; uint32_t delay = util::DivideUp(clk_div, from_period); if (from_rate_khz >= 407997 || to_rate_khz <= 407996) { if (from_rate_khz >= 407997 && to_rate_khz <= 407996) { uint32_t pmacro_vttgen_ctrl_1 = reg::Read(EMC + EMC_PMACRO_VTTGEN_CTRL_1); if (dst_timing->vtt_vdda_dual_channel) { if (vtt_vdda_channel != 1) { return; } CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((to_table->vtt_vdda_ctrl_4 & 0x3F) << 10), delay); CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((to_table->vtt_vdda_ctrl_0 & 0x3F) << 10), delay * 2); } else { CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_0 & 0x3F) << 10), 0); } } } else { uint32_t pmacro_vttgen_ctrl_1 = reg::Read(EMC + EMC_PMACRO_VTTGEN_CTRL_1); if (dst_timing->vtt_vdda_dual_channel) { if (vtt_vdda_channel == 1) { CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_3 & 0x3F) << 10), delay); CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_0 & 0x3F) << 10), delay); } else if (vtt_vdda_channel == 0) { CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_1 & 0x3F) << 10), delay); CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_2 & 0x3F) << 10), delay); } } else { CcfifoWrite(EMC_PMACRO_VTTGEN_CTRL_1, (pmacro_vttgen_ctrl_1 & 0xFFFF03FF) | ((dst_timing->vtt_vdda_ctrl_0 & 0x3F) << 10), 0); } } } u32 DvfsPowerRampUp(u32 dst_clock_period, bool flip_backward, EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 training) { uint32_t misc_cfg_1 = flip_backward ? src_timing->misc_cfg_1 : dst_timing->misc_cfg_1; uint32_t emc_pmacro_cmd_pad_tx_ctrl, emc_pmacro_brick_ctrl_rfu1, emc_fbio_cfg5; if (flip_backward) { emc_pmacro_cmd_pad_tx_ctrl = src_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; emc_pmacro_brick_ctrl_rfu1 = src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; emc_fbio_cfg5 = src_timing->burst_regs.emc_fbio_cfg5; } else if (training & (CA_TRAINING | CA_VREF_TRAINING)) { emc_pmacro_cmd_pad_tx_ctrl = dst_timing->shadow_regs_ca_train.emc_pmacro_cmd_pad_tx_ctrl; emc_pmacro_brick_ctrl_rfu1 = dst_timing->shadow_regs_ca_train.emc_pmacro_brick_ctrl_rfu1; emc_fbio_cfg5 = dst_timing->shadow_regs_ca_train.emc_fbio_cfg5; } else if (training & (WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING)) { emc_pmacro_cmd_pad_tx_ctrl = dst_timing->shadow_regs_rdwr_train.emc_pmacro_cmd_pad_tx_ctrl; emc_pmacro_brick_ctrl_rfu1 = dst_timing->shadow_regs_rdwr_train.emc_pmacro_brick_ctrl_rfu1; emc_fbio_cfg5 = dst_timing->shadow_regs_rdwr_train.emc_fbio_cfg5; } else { emc_pmacro_cmd_pad_tx_ctrl = dst_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl; emc_pmacro_brick_ctrl_rfu1 = dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1; emc_fbio_cfg5 = dst_timing->burst_regs.emc_fbio_cfg5; } bool misc_flag = (misc_cfg_1 & 3) == 3; uint32_t timescale = 100000 << ((misc_cfg_1 >> 2) & 7); uint32_t delay = (timescale / dst_clock_period); if (dst_clock_period < 869 || misc_flag) { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1 & 0xFE40FE40, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1 & 0xFEEDFEED, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1 & 0xFFFFFFFF, delay + 1); CcfifoWrite(EMC_FBIO_CFG5, emc_fbio_cfg5 & 0xFFFFFEFF, delay + 10); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, emc_pmacro_cmd_pad_tx_ctrl & 0xFBFFFFFF, 5); return timescale + 10 * dst_clock_period + 3 * timescale; } else if (dst_clock_period > 1665) { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1 | 0x00000600, 0); CcfifoWrite(EMC_FBIO_CFG5, emc_fbio_cfg5 & 0xFFFFFEFF, 12); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, emc_pmacro_cmd_pad_tx_ctrl & 0xFBFFFFFF, 5); return 12 * dst_clock_period; } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1 | 0x06000600, delay + 1); CcfifoWrite(EMC_FBIO_CFG5, emc_fbio_cfg5 & 0xFFFFFEFF, delay + 10); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, emc_pmacro_cmd_pad_tx_ctrl & 0xFBFFFFFF, 5); return timescale + 10 * dst_clock_period; } } void FreqChange(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 training, u32 dst_clk_src) { /* Extract training values */ const bool train_ca = (training & CA_TRAINING); const bool train_ca_vref = (training & CA_VREF_TRAINING); //const bool train_quse = (training & QUSE_TRAINING); //const bool train_quse_vref = (training & QUSE_VREF_TRAINING); const bool train_wr = (training & WRITE_TRAINING); const bool train_wr_vref = (training & WRITE_VREF_TRAINING); const bool train_rd = (training & READ_TRAINING); const bool train_rd_vref = (training & READ_VREF_TRAINING); const bool train_second_rank = (training & TRAIN_SECOND_RANK); const bool train_bit_level = (training & BIT_LEVEL_TRAINING); /* Check if we should do training. */ const bool training_enabled = (training & (CA_TRAINING | CA_VREF_TRAINING | WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING)); uint32_t dst_emc_fbio_cfg7 = dst_timing->emc_fbio_cfg7; uint32_t dst_misc_cfg_0 = dst_timing->misc_cfg_0; uint32_t dst_misc_cfg_1 = dst_timing->misc_cfg_1; uint32_t dst_misc_cfg_2 = dst_timing->misc_cfg_2; uint32_t src_misc_cfg_0 = src_timing->misc_cfg_0; uint32_t src_misc_cfg_1 = src_timing->misc_cfg_1; uint32_t src_t_rp = src_timing->dram_timings.t_rp; uint32_t src_t_rfc = src_timing->dram_timings.t_rfc; uint32_t dst_t_pdex = dst_timing->dram_timings.t_pdex; uint32_t dst_t_fc_lpddr4 = dst_timing->dram_timings.t_fc_lpddr4; const bool ch0_enable = reg::GetField(dst_emc_fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH0_ENABLE)) == EMC_FBIO_CFG7_CH0_ENABLE_ENABLE; const bool ch1_enable = reg::GetField(dst_emc_fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE; g_fsp_for_next_freq = !g_fsp_for_next_freq; const int dram_type = reg::GetValue(EMC + EMC_FBIO_CFG5, EMC_REG_BITS_MASK(FBIO_CFG5_DRAM_TYPE)); uint32_t src_emc_zcal_wait_cnt = src_timing->burst_regs.emc_zcal_wait_cnt; bool shared_zq_resistor = (src_emc_zcal_wait_cnt >> 31) & 1; bool opt_zcal_en_cc = (dst_timing->burst_regs.emc_zcal_interval && !src_timing->burst_regs.emc_zcal_interval) || (dram_type == DRAM_TYPE_LPDDR4); uint32_t dst_t_fc_lpddr4_hz = 1000 * dst_t_fc_lpddr4; bool is_lpddr2 = (dram_type == DRAM_TYPE_LPDDR2); bool is_lpddr3 = is_lpddr2 && ((dst_timing->burst_regs.emc_fbio_cfg5 >> 25) & 1); uint32_t opt_dll_mode = (dram_type == DRAM_TYPE_DDR4) ? GetDllState(dst_timing) : DLL_OFF; int dram_dev_num = ((reg::Read(MC + MC_EMEM_ADR_CFG) & 1) + 1); uint32_t tZQCAL_lpddr4 = dst_timing->tZQCAL_lpddr4; uint32_t zqcal_before_cc_cutoff = dst_timing->zqcal_before_cc_cutoff; uint32_t opt_cc_short_zcal = dst_timing->opt_cc_short_zcal; uint32_t opt_short_zcal = dst_timing->opt_short_zcal; uint32_t opt_do_sw_qrst = dst_timing->opt_do_sw_qrst; uint32_t save_restore_clkstop_pd = dst_timing->save_restore_clkstop_pd; // uint32_t opt_E90 = dst_timing->opt_E90; uint32_t cya_allow_ref_cc = dst_timing->cya_allow_ref_cc; uint32_t ref_b4_sref_en = dst_timing->ref_b4_sref_en; uint32_t cya_issue_pc_ref = dst_timing->cya_issue_pc_ref; uint32_t src_rate_khz = src_timing->rate_khz; uint32_t dst_rate_khz = dst_timing->rate_khz; uint32_t src_clock_period = 1000000000 / src_rate_khz; uint32_t dst_clock_period = 1000000000 / dst_rate_khz; uint32_t emc_auto_cal_config = reg::Read(EMC + EMC_AUTO_CAL_CONFIG); uint32_t adj_dst_t_fc_lpddr4 = (dst_clock_period <= zqcal_before_cc_cutoff) ? dst_t_fc_lpddr4_hz : 0; uint32_t emc_dbg_o = reg::Read(EMC + EMC_DBG); uint32_t emc_pin_o = reg::Read(EMC + EMC_PIN); uint32_t emc_cfg_pipe_clk_o = reg::Read(EMC + EMC_CFG_PIPE_CLK); uint32_t emc_dbg = emc_dbg_o; uint32_t emc_cfg = dst_timing->burst_regs.emc_cfg; uint32_t emc_sel_dpd_ctrl = dst_timing->emc_sel_dpd_ctrl; uint32_t next_push, next_dq_e_ivref, next_dqs_e_ivref; /* Step 1: * Pre DVFS SW sequence. */ /* Step 1.1: Disable DLL. */ uint32_t tmp = reg::Read(EMC + EMC_CFG_DIG_DLL); tmp &= ~(1 << 0); reg::Write(EMC + EMC_CFG_DIG_DLL, tmp); /* Calculate 14000 / dst_period. */ uint32_t div_14000_by_dst_period = std::max<u32>(util::DivideUp(14000, dst_clock_period), 10); /* Request a timing update. */ TimingUpdate(dst_emc_fbio_cfg7); /* Wait for DLL to be disabled. */ WaitForUpdate(EMC_CFG_DIG_DLL, (1 << 0), false, dst_emc_fbio_cfg7); /* Step 1.2: Disable AUTOCAL. */ emc_auto_cal_config = (dst_timing->emc_auto_cal_config & 0x7FFFF9FF) | 0x600; reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); reg::Read(EMC + EMC_AUTO_CAL_CONFIG); /* Step 1.3: Disable other power features. */ emc_dbg = SetShadowBypass(ACTIVE, emc_dbg_o); reg::Write(EMC + EMC_DBG, emc_dbg); reg::Write(EMC + EMC_CFG, emc_cfg & 0x0FFFFFFF); reg::Write(EMC + EMC_SEL_DPD_CTRL, emc_sel_dpd_ctrl & 0xFFFFFEC3); reg::Write(EMC + EMC_DBG, emc_dbg_o); /* Skip this if dvfs_with_training is set. */ bool compensate_trimmer_applicable = false; uint32_t adel = 0; if (!training_enabled && dst_timing->periodic_training) { /* Wait for DRAM to get out of power down. */ WaitForUpdate(EMC_EMC_STATUS, dram_dev_num == TWO_RANK ? 0x30 : 0x10, false, dst_emc_fbio_cfg7); /* Wait for DRAM to get out of self refresh. */ WaitForUpdate(EMC_EMC_STATUS, 0x300, false, dst_emc_fbio_cfg7); if (dst_timing->periodic_training) { /* Reset all clock tree values. */ dst_timing->current_dram_clktree_c0d0u0 = dst_timing->trained_dram_clktree_c0d0u0; dst_timing->current_dram_clktree_c0d0u1 = dst_timing->trained_dram_clktree_c0d0u1; dst_timing->current_dram_clktree_c0d1u0 = dst_timing->trained_dram_clktree_c0d1u0; dst_timing->current_dram_clktree_c0d1u1 = dst_timing->trained_dram_clktree_c0d1u1; dst_timing->current_dram_clktree_c1d0u0 = dst_timing->trained_dram_clktree_c1d0u0; dst_timing->current_dram_clktree_c1d0u1 = dst_timing->trained_dram_clktree_c1d0u1; dst_timing->current_dram_clktree_c1d1u0 = dst_timing->trained_dram_clktree_c1d1u0; dst_timing->current_dram_clktree_c1d1u1 = dst_timing->trained_dram_clktree_c1d1u1; /* Do DVFS_SEQUENCE. */ adel = PeriodicCompensationHandler(DVFS_SEQUENCE, dram_dev_num, src_timing, dst_timing); /* Check if we should use compensate trimmer. */ compensate_trimmer_applicable = dst_timing->periodic_training && ((adel * 128 * (dst_rate_khz / 1000)) / 1000000) > dst_timing->tree_margin; } } reg::Write(EMC + EMC_INTSTATUS, (1 << 4)); emc_dbg = SetShadowBypass(ACTIVE, emc_dbg); reg::Write(EMC + EMC_DBG, emc_dbg); reg::Write(EMC + EMC_CFG, emc_cfg & 0x0FFFFFFF); reg::Write(EMC + EMC_SEL_DPD_CTRL, emc_sel_dpd_ctrl & 0xFFFFFEC3); reg::Write(EMC + EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o | (1 << 0)); reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, dst_timing->emc_fdpd_ctrl_cmd_no_ramp & ~(1 << 0)); /* Adjust pllm_misc1 as needed. */ if (dst_timing->pllm_misc1_0_pllm_clamp_ph90) { reg::ClearBits(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC1, 0x80000000); } /* Check if we need to turn on VREF generator. */ if (((!(src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 0))) && ((dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 0)))) || ((!(src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 10))) && ((dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl & (1 << 10))))) { uint32_t pad_tx_ctrl = dst_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; uint32_t last_pad_tx_ctrl = src_timing->burst_regs.emc_pmacro_data_pad_tx_ctrl; next_dqs_e_ivref = pad_tx_ctrl & (1 << 10); next_dq_e_ivref = pad_tx_ctrl & (1 << 0); next_push = (last_pad_tx_ctrl & ~(1 << 0) & ~(1 << 10)) | next_dq_e_ivref | next_dqs_e_ivref; reg::Write(EMC + EMC_PMACRO_DATA_PAD_TX_CTRL, next_push); reg::Write(EMC + EMC_DBG, emc_dbg_o); util::WaitMicroSeconds(1); } else { reg::Write(EMC + EMC_DBG, emc_dbg_o); } /* Check if we need to fixup xm2comppadctrl */ if ((dst_misc_cfg_1 & 0x20) == 0) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); uint32_t xm2comppadctrl = reg::Read(EMC + EMC_XM2COMPPADCTRL); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl | 0x08000000); util::WaitMicroSeconds(1); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl | 0x18000000); util::WaitMicroSeconds(1); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl | 0x38000000); util::WaitMicroSeconds(1); reg::Write(EMC + EMC_DBG, SetShadowBypass(ASSEMBLY, emc_dbg_o)); } /* Step 2: * Prelock the DLL. */ if (dst_timing->burst_regs.emc_cfg_dig_dll & (1 << 0)) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::ClearBits(EMC + EMC_PMACRO_DLL_CFG_1, 0x2000); reg::Read(EMC + EMC_PMACRO_DLL_CFG_1); reg::Write(EMC + EMC_DBG, SetShadowBypass(ASSEMBLY, emc_dbg_o)); reg::Read(EMC + EMC_DBG); DllPrelock(dst_timing, src_timing, training_enabled, dst_clk_src); } else { DllDisable(dst_emc_fbio_cfg7); } /* Step 3: * Prepare autocal for the clock change. */ /* Disable AUTOCAL. */ emc_auto_cal_config = (dst_timing->emc_auto_cal_config & 0x7FFFF9FF) | 0x600; reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_AUTO_CAL_CONFIG2, dst_timing->emc_auto_cal_config2); if (ch0_enable || ch1_enable) { reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG3, dst_timing->emc_auto_cal_config3); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG4, dst_timing->emc_auto_cal_config4); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG5, dst_timing->emc_auto_cal_config5); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG6, dst_timing->emc_auto_cal_config6); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG7, dst_timing->emc_auto_cal_config7); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG8, dst_timing->emc_auto_cal_config8); } reg::Write(EMC + EMC_DBG, emc_dbg_o); emc_auto_cal_config = (dst_timing->emc_auto_cal_config & 0x7FFFF9FE) | 0x601; reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config); /* Step 4: * Update EMC_CFG. */ reg::ClearBits(EMC + EMC_CFG, 0x10000000); reg::Write(EMC + EMC_CFG_2, dst_timing->emc_cfg_2); /* Step 5: * Prepare reference variables for ZQCAL regs. */ //print(SCREEN_LOG_LEVEL_DEBUG, "[MTC]: freq_change - step 5\n"); //mdelay(500); uint32_t emc_zcal_interval = src_timing->burst_regs.emc_zcal_interval & 0xFF000000; uint32_t dst_emc_zcal_wait_cnt = dst_timing->burst_regs.emc_zcal_wait_cnt; uint32_t zq_wait_long, zq_wait_short; if (dram_type == DRAM_TYPE_LPDDR4) { zq_wait_long = std::max<u32>(util::DivideUp(1000000, dst_clock_period), 1); zq_wait_short = std::max<u32>(util::DivideUp(30000, dst_clock_period), 8) + 1; } else if (is_lpddr2 || is_lpddr3) { zq_wait_long = std::max<u32>(util::DivideUp(360000, dst_clock_period), dst_timing->min_mrs_wait) + 4; zq_wait_short = 0; } else if (dram_type == DRAM_TYPE_DDR4) { zq_wait_long = std::max<u32>(util::DivideUp(320000, dst_clock_period), 256); zq_wait_short = 0; } else { zq_wait_long = 0; zq_wait_short = 0; } /* Step 6: * Training code. */ { uint32_t pintemp = reg::Read(EMC + EMC_PIN); if ((train_ca || train_ca_vref) && (dram_dev_num == TWO_RANK)) { reg::Write(EMC + EMC_PIN, pintemp | 0x7); } } /* Step 7: * Program FSP reference registers and send MRWs to new FSPWR. */ uint32_t mr13_flip_fspop, mr13_flip_fspwr; if (!g_fsp_for_next_freq) { mr13_flip_fspwr = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x80; mr13_flip_fspop = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x00; } else { mr13_flip_fspwr = (dst_timing->emc_mrw3 & 0xffffff3f) | 0x40; mr13_flip_fspop = (dst_timing->emc_mrw3 & 0xffffff3f) | 0xc0; } uint32_t mr13_catr_enable = mr13_flip_fspwr | 1; if (dram_dev_num == TWO_RANK) { if (train_ca || train_ca_vref) { mr13_flip_fspop = (mr13_flip_fspop & 0x3FFFFFFF) | (train_second_rank ? 0x80000000 : 0x40000000); } mr13_catr_enable = (mr13_catr_enable & 0x3FFFFFFF) | (train_second_rank ? 0x40000000 : 0x80000000); } if (dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_MRW3, mr13_flip_fspwr); reg::Write(EMC + EMC_MRW, dst_timing->emc_mrw); reg::Write(EMC + EMC_MRW2, dst_timing->emc_mrw2); } /* Step 8: * Program the shadow registers. */ /* Set burst registers. */ { uint32_t pmacro_vttgen_ctrl_1 = reg::Read(EMC + EMC_PMACRO_VTTGEN_CTRL_1); uint32_t xm2comppadctrl = reg::Read(EMC + EMC_XM2COMPPADCTRL); for (u32 i = 0; i < dst_timing->num_burst; ++i) { if (!BurstRegisters[i]) { continue; } const u32 reg_addr = BurstRegisters[i]; uint32_t wval; if (train_ca || train_ca_vref) { wval = dst_timing->shadow_regs_ca_train_arr[i]; } else if (train_wr || train_wr_vref || train_rd || train_rd_vref) { wval = dst_timing->shadow_regs_rdwr_train_arr[i]; } else { wval = dst_timing->burst_regs_arr[i]; } /* Adjust the value to write. */ switch (reg_addr) { case EMC_BASE + EMC_CFG: wval &= (dram_type == DRAM_TYPE_LPDDR4) ? 0x0FFFFFFF : 0xCFFFFFFF; break; case EMC_BASE + EMC_MRS_WAIT_CNT: if (opt_zcal_en_cc && is_lpddr2 && (opt_cc_short_zcal == 0) && (opt_short_zcal != 0)) { wval = (wval & 0xFFFFFC00) | (zq_wait_long & 0x3FF); } break; case EMC_BASE + EMC_ZCAL_WAIT_CNT: if ((opt_short_zcal != 0) && opt_zcal_en_cc && (opt_cc_short_zcal == 0) && (dram_type == DRAM_TYPE_DDR4)) { wval = (wval & 0xFFFFF800) | (zq_wait_long & 0x7FF); } break; case EMC_BASE + EMC_ZCAL_INTERVAL: if (opt_zcal_en_cc) { wval = 0; } break; case EMC_BASE + EMC_PMACRO_BRICK_CTRL_RFU1: wval &= 0xF800F800; break; case EMC_BASE + EMC_PMACRO_CMD_PAD_TX_CTRL: wval |= 0x04000000; break; case EMC_BASE + EMC_PMACRO_AUTOCAL_CFG_COMMON: wval |= 0x00010000; break; case EMC_BASE + EMC_TRAINING_CTRL: if (train_second_rank) { wval |= 0x4000; } break; case EMC_BASE + EMC_REFRESH: case EMC_BASE + EMC_TREFBW: wval >>= 0; break; case EMC_BASE + EMC_XM2COMPPADCTRL: if ((dst_misc_cfg_1 & 0x20) == 0) { wval = (wval & 0x00FFFFFF) | (xm2comppadctrl & 0xFF000000); } break; case EMC_BASE + EMC_DLL_CFG_1: wval = (wval & 0xFFFFDFFF) | (reg::Read(EMC + EMC_PMACRO_DLL_CFG_1) & 0x00002000); break; case EMC_BASE + EMC_PMACRO_VTTGEN_CTRL_1: wval = (wval & 0xFFFF03FF) | (pmacro_vttgen_ctrl_1 & 0xFC00); break; case EMC_BASE + EMC_MRW6: case EMC_BASE + EMC_MRW7: case EMC_BASE + EMC_MRW8: case EMC_BASE + EMC_MRW9: case EMC_BASE + EMC_MRW14: case EMC_BASE + EMC_MRW15: case EMC0_BASE + EMC_MRW10: case EMC0_BASE + EMC_MRW11: case EMC0_BASE + EMC_MRW12: case EMC0_BASE + EMC_MRW13: case EMC1_BASE + EMC_MRW10: case EMC1_BASE + EMC_MRW11: case EMC1_BASE + EMC_MRW12: case EMC1_BASE + EMC_MRW13: if (dram_type != DRAM_TYPE_LPDDR4) { continue; } break; } /* Write the value. */ reg::Write(reg_addr, wval); } } if (dram_type == DRAM_TYPE_LPDDR4) { /* Use the current timing when training. */ uint32_t mrw_req; if (training_enabled) mrw_req = (23 << 16) | (src_timing->run_clocks & (0xFF << 0)); else mrw_req = (23 << 16) | (dst_timing->run_clocks & (0xFF << 0)); reg::Write(EMC + EMC_MRW, mrw_req); } /* Per channel burst registers. */ if (dram_type == DRAM_TYPE_LPDDR4) { for (u32 i = 0; i < dst_timing->num_burst_per_ch; i++) { if (!PerChannelBurstRegisters[i]) { continue; } const u32 addr = PerChannelBurstRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out channels. */ if ((!ch0_enable && base == EMC0) || (!ch1_enable && base == EMC1)) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->burst_perch_regs_arr[i]); } } /* Vref regs. */ for (u32 i = 0; i < dst_timing->vref_num; i++) { if (!PerChannelVrefRegisters[i]) { continue; } const u32 addr = PerChannelVrefRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out channels. */ if ((!ch0_enable && base == EMC0) || (!ch1_enable && base == EMC1)) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->vref_perch_regs_arr[i]); } /* Training regs. */ if (training_enabled) { for (u32 i = 0; i < dst_timing->training_mod_num; i++) { if (!PerChannelTrainingModRegisters[i]) { continue; } const u32 addr = PerChannelTrainingModRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out channels. */ if ((!ch0_enable && base == EMC0) || (!ch1_enable && base == EMC1)) { continue; } /* Write the value. */ reg::Write(addr, dst_timing->training_mod_regs_arr[i]); } } /* Per channel trimmers. */ for (u32 i = 0; i < dst_timing->num_trim_per_ch; i++) { if (!PerChannelTrimRegisters[i]) { continue; } const u32 addr = PerChannelTrimRegisters[i]; const u32 base = addr & ~0xFFF; /* Filter out channels. */ if ((!ch0_enable && base == EMC0) || (!ch1_enable && base == EMC1)) { continue; } uint32_t wval = dst_timing->trim_perch_regs_arr[i]; if (compensate_trimmer_applicable) { switch (addr) { case EMC0_BASE + EMC_DATA_BRLSHFT_0: case EMC1_BASE + EMC_DATA_BRLSHFT_0: case EMC0_BASE + EMC_DATA_BRLSHFT_1: case EMC1_BASE + EMC_DATA_BRLSHFT_1: wval = ApplyPeriodicCompensationTrimmer(dst_timing, addr); break; } } /* Write the value. */ reg::Write(addr, wval); } /* Trimmers. */ for (u32 i = 0; i < dst_timing->num_trim; ++i) { if (!TrimRegisters[i]) { continue; } const u32 addr = TrimRegisters[i]; u32 wval = dst_timing->trim_regs_arr[i]; if (compensate_trimmer_applicable) { switch (addr) { case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1: case EMC_BASE + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2: wval = ApplyPeriodicCompensationTrimmer(dst_timing, addr); break; } } /* Write the value. */ reg::Write(addr, wval); } if (training_enabled) { if (train_wr && dst_timing->periodic_training) { PeriodicCompensationHandler(WRITE_TRAINING_SEQUENCE, dram_dev_num, src_timing, dst_timing); } } else { /* Write burst_mc_regs. */ for (u32 i = 0; i < dst_timing->num_mc_regs; i++) { reg::Write(BurstMcRegisters[i], dst_timing->burst_mc_regs_arr[i]); } /* Registers to be programmed on the faster clock. */ if (dst_timing->rate_khz < src_timing->rate_khz) { for (u32 i = 0; i < dst_timing->num_up_down; i++) { reg::Write(LaScaleRegisters[i], dst_timing->la_scale_regs_arr[i]); } } } if ((dst_misc_cfg_1 & 2) != 0 && (dst_misc_cfg_1 & 1) == 0) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU1, dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1); reg::Write(EMC + EMC_PMACRO_CMD_PAD_TX_CTRL, dst_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl); } reg::Write(EMC + EMC_CFG_PIPE_CLK, (1 << 0)); reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, dst_timing->emc_fdpd_ctrl_cmd_no_ramp & ~(1 << 0)); /* Step 9: * LPDDR4 section A. */ uint32_t emc_dbg_write_active = emc_dbg_o; if (dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_ZCAL_INTERVAL, emc_zcal_interval); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, (dst_emc_zcal_wait_cnt & 0xFFFFF800) | 1); reg::Write(EMC + EMC_DBG, emc_dbg_o | ((1 << 1) | (1 << 30))); reg::Write(EMC + EMC_ZCAL_INTERVAL, emc_zcal_interval); reg::Write(EMC + EMC_DBG, emc_dbg_o); if (training_enabled) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_COMMON, dst_timing->burst_regs.emc_pmacro_autocal_cfg_common | (1 << 16)); if (train_ca || train_ca_vref) { reg::Write(EMC + EMC_FBIO_CFG5, src_timing->burst_regs.emc_fbio_cfg5 | (1 << 27)); } reg::Write(EMC + EMC_DBG, emc_dbg_o); if (dst_emc_fbio_cfg7 == 0x6) { CcfifoWrite(EMC_CFG_SYNC, 1, 0); } /* Change CFG_SWAP. */ CcfifoWrite(EMC_DBG, ((emc_dbg_o & 0xF3FFFFFF) | 0x4000000), 0); } CcfifoWrite(EMC_SELF_REF, 0x101, 0); if (!(train_ca || train_ca_vref) && dst_clock_period <= zqcal_before_cc_cutoff) { CcfifoWrite(EMC_MRW3, mr13_flip_fspwr ^ 0x40, 0); CcfifoWrite(EMC_MRW6, (src_timing->burst_regs.emc_mrw6 & 0x0000C0C0) | (dst_timing->burst_regs.emc_mrw6 & 0xFFFF3F3F), 0); CcfifoWrite(EMC_MRW14, (src_timing->burst_regs.emc_mrw14 & 0x00003838) | (dst_timing->burst_regs.emc_mrw14 & 0xFFFF0707), 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_MRW7, (src_timing->burst_regs.emc_mrw7 & 0x0000C0C0) | (dst_timing->burst_regs.emc_mrw7 & 0xFFFF3F3F), 0); CcfifoWrite(EMC_MRW15, (src_timing->burst_regs.emc_mrw15 & 0x00003838) | (dst_timing->burst_regs.emc_mrw15 & 0xFFFF0707), 0); } if (opt_zcal_en_cc) { if (dram_dev_num == ONE_RANK || shared_zq_resistor) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), 0); } else { CcfifoWrite(EMC_ZQ_CAL, (1 << 0), 0); } } } if (training_enabled) { emc_dbg_write_active = (emc_dbg_o & 0xF7FFFFFF) | 0x4000000 | (1 << 30); CcfifoWrite(EMC_DBG, emc_dbg_write_active, 0); } if (train_ca || train_ca_vref) { CcfifoWrite(EMC_PMACRO_DATA_RX_TERM_MODE, src_timing->burst_regs.emc_pmacro_data_rx_term_mode & 0xFFFFFCCC, 0); if (dram_dev_num == TWO_RANK && train_second_rank) { CcfifoWrite(EMC_MRW3, mr13_flip_fspop | 0x8, (1000 * src_t_rp) / src_clock_period); CcfifoWrite(EMC_MRW3, mr13_catr_enable | 0x8, 0); } else { CcfifoWrite(EMC_MRW3, mr13_catr_enable | 0x8, (1000 * src_t_rp) / src_clock_period); } CcfifoWrite(EMC_TR_CTRL_0, (dst_timing->emc_tr_ctrl_0 & 0x3F1000) | 0x100012A, 0); CcfifoWrite(EMC_INTSTATUS, 0, 1000000 / src_clock_period); } else { CcfifoWrite(EMC_MRW3, mr13_flip_fspop | 0x8, (1000 * src_t_rp) / src_clock_period); CcfifoWrite(EMC_INTSTATUS, 0, std::max<u32>(DivideUpFloat(dst_t_fc_lpddr4_hz, src_clock_period), std::max<u32>(DivideUpFloat(14000, src_clock_period), 10))); } uint32_t t = 30 + (cya_allow_ref_cc ? ((4000 * src_t_rfc + 1000 * src_t_rp) / src_clock_period) : 0); CcfifoWrite(EMC_PIN, emc_pin_o & 0xFFFFFFF8, t); } else { CcfifoWrite(EMC_SELF_REF, 0x1, 0); } uint32_t ref_delay_mult = 1; if (ref_b4_sref_en) ++ref_delay_mult; if (cya_allow_ref_cc) ++ref_delay_mult; if (cya_issue_pc_ref) ++ref_delay_mult; uint32_t ref_delay = 20 + ref_delay_mult * (((1000 * src_t_rfc) / src_clock_period) + ((1000 * src_t_rp) / src_clock_period)); /* Step 11: * Ramp down. */ CcfifoWrite(EMC_CFG_SYNC, 1, (dram_type == DRAM_TYPE_LPDDR4) ? 0 : ref_delay); bool do_ramp_up = (dst_misc_cfg_1 & 2) == 0 || (dst_misc_cfg_1 & 1) != 0; if (!do_ramp_up) { CcfifoWrite(EMC_FBIO_CFG5, reg::Read(EMC + EMC_FBIO_CFG5) & 0xF7FFFFFF, 12); } CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active & 0xBFFFFFFF), 0); if ((dst_misc_cfg_2 & 0x10) == 0) { DvfsPowerRampDown(src_timing, dst_timing, false, 0); } CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active | 0x40000000), 0); uint32_t ramp_down_wait = 0; if (do_ramp_up) { CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, src_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl | (1 << 26), 0); CcfifoWrite(EMC_FBIO_CFG5, src_timing->burst_regs.emc_fbio_cfg5 | 0x100, 12); bool misc_flag = (dst_misc_cfg_1 & 3) == 3; uint32_t timescale = (100000 << ((dst_misc_cfg_1 >> 2) & 7)); uint32_t delay = (timescale / src_clock_period); if (src_rate_khz > 1150747 || misc_flag) { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xFEEDFEED, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xFE40FE40, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xF800F800, delay + 1); ramp_down_wait = 3 * timescale + 12 * src_clock_period; } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, src_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xF800F800, delay + 20); ramp_down_wait = timescale + 32 * src_clock_period; } if (src_rate_khz > 600240 || misc_flag) { CcfifoWrite(EMC_INTSTATUS, 0, delay + 1); ramp_down_wait += 2 * timescale; } } /* Step 12: * Trigger the clock change. */ CcfifoWrite(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); CcfifoWrite(EMC_INTSTATUS, 0, dst_timing->clkchange_delay); CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active & 0xBFFFFFFF), 0); if ((dst_misc_cfg_2 & 0x10) == 0) { DvfsPowerRampDown(src_timing, dst_timing, false, 1); } if (training_enabled) { CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active | 0x40000000), 0); } /* Step 13: * Ramp up. */ uint32_t ramp_up_wait = 0; if (do_ramp_up) { ramp_up_wait = DvfsPowerRampUp(dst_clock_period, false, src_timing, dst_timing, training); } if (ramp_up_wait < 1001000 && src_timing->ramp_wait != dst_timing->ramp_wait) { CcfifoWrite(EMC_INTSTATUS, 0, 1 + ((1001000 - ramp_up_wait) / dst_clock_period)); } if (do_ramp_up) { CcfifoWrite(EMC_DBG, emc_dbg_write_active, 0); } else { CcfifoWrite(EMC_FBIO_CFG5, reg::Read(EMC + EMC_FBIO_CFG5), 0); CcfifoWrite(EMC_DBG, emc_dbg_write_active, 12); } /* Step 14: * Bringup CKE pins. */ if (dram_type == DRAM_TYPE_LPDDR4) { uint32_t pin_val; if (train_ca || train_ca_vref) { pin_val = (dst_misc_cfg_0 & 1) ? ((emc_pin_o & 0xFFFCFFF8) | (((dst_misc_cfg_0 >> 1) & 3) << 16)) : emc_pin_o; pin_val &= 0xFFFFFFF8; if (dram_dev_num == TWO_RANK) { if (train_second_rank) { pin_val |= 5; } else { pin_val |= 6; } } } else { pin_val = (dst_misc_cfg_0 & 1) ? ((emc_pin_o & 0xFFFCFFFF) | (((dst_misc_cfg_0 >> 1) & 3) << 16)) : emc_pin_o; pin_val &= 0xFFFFFFF8; if (dram_dev_num == TWO_RANK) { pin_val |= 7; } else { pin_val |= 1; } } CcfifoWrite(EMC_PIN, pin_val, 0); } /* Step 15: * Calculate zqlatch wait time; has dependency on ramping times. */ uint32_t dst_t_pdex_hz = 1000 * dst_t_pdex; uint32_t zq_latch_dvfs_wait_time; if (dst_clock_period <= zqcal_before_cc_cutoff) { zq_latch_dvfs_wait_time = (ramp_up_wait + ramp_down_wait) / dst_clock_period; } else { zq_latch_dvfs_wait_time = util::DivideUp(dst_t_pdex_hz, dst_clock_period); } if (!(train_ca || train_ca_vref) && (dram_type == DRAM_TYPE_LPDDR4) && opt_zcal_en_cc) { int offset = (int)((tZQCAL_lpddr4 - adj_dst_t_fc_lpddr4) / dst_clock_period) - (int)zq_latch_dvfs_wait_time; int addl_wait = (int)util::DivideUp(dst_t_pdex_hz, dst_clock_period); if (dram_dev_num == TWO_RANK) { if (shared_zq_resistor) { if (dst_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), std::max<int>(0, addl_wait)); } CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), std::max<int>(0, offset + addl_wait)); CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 0), 0); if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xFFFFFFF7) | 0xC000000 | (dst_misc_cfg_2 & 8), 0); CcfifoWrite(EMC_SELF_REF, 0, 0); CcfifoWrite(EMC_REF, 0, 0); } CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), zq_wait_short + div_14000_by_dst_period + (tZQCAL_lpddr4 / dst_clock_period)); } else { if (dst_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (0 << 30) | (1 << 0), std::max<int>(0, addl_wait)); } if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xFFFFFFF7) | 0xC000000 | (dst_misc_cfg_2 & 8), std::max<int>(0, addl_wait)); CcfifoWrite(EMC_SELF_REF, 0, 0); CcfifoWrite(EMC_REF, 0, 0); } CcfifoWrite(EMC_ZQ_CAL, (0 << 30) | (1 << 1), div_14000_by_dst_period + std::max<int>(0, offset)); } } else { if (dst_clock_period > zqcal_before_cc_cutoff) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), std::max<int>(0, addl_wait)); } if (!training_enabled) { CcfifoWrite(EMC_MRW3, (mr13_flip_fspop & 0xFFFFFFF7) | 0xC000000 | (dst_misc_cfg_2 & 8), std::max<int>(0, addl_wait)); CcfifoWrite(EMC_SELF_REF, 0, 0); CcfifoWrite(EMC_REF, 0x80000000, 0); } CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), div_14000_by_dst_period + std::max<int>(0, offset)); } } /* WAR: delay for zqlatch */ CcfifoWrite(EMC_INTSTATUS, 0, 10); /* Step 16: * LPDDR4 Conditional Training Kickoff. */ if (training_enabled && dram_type == DRAM_TYPE_LPDDR4) { if (opt_do_sw_qrst) { CcfifoWrite(EMC_ISSUE_QRST, 1, 0); CcfifoWrite(EMC_ISSUE_QRST, 0, 2); } CcfifoWrite(EMC_INTSTATUS, 0, (1020000 / dst_clock_period)); { uint32_t train_cmd = 0; if (train_ca) { train_cmd |= (1 << 1); /* CA */ } if (train_ca_vref) { train_cmd |= (1 << 5); /* CA_VREF */ } if (train_wr) { train_cmd |= (1 << 3); /* WR */ } if (train_wr_vref) { train_cmd |= (1 << 6); /* WR_VREF */ } if (train_rd) { train_cmd |= (1 << 2); /* RD */ } if (train_rd_vref) { train_cmd |= (1 << 7); /* RD_VREF */ } train_cmd |= (1 << 31); /* GO */ CcfifoWrite(EMC_TRAINING_CMD, train_cmd, 0); } CcfifoWrite(EMC_SWITCH_BACK_CTRL, 1, 0); if (!(train_ca || train_ca_vref) || train_second_rank) { CcfifoWrite(EMC_MRW3, mr13_flip_fspop ^ 0xC0, 0); CcfifoWrite(EMC_INTSTATUS, 0, (1000000 / dst_clock_period)); } { uint32_t pin_val = (dst_misc_cfg_0 & 1) ? ((emc_pin_o & 0xFFFCFFFF) | (((dst_misc_cfg_0 >> 1) & 3) << 16)) : emc_pin_o; CcfifoWrite(EMC_PIN, pin_val & 0xFFFFFFF8, 0); } CcfifoWrite(EMC_CFG_SYNC, 1, 0); if ((src_misc_cfg_1 & 3) != 2) { CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active | 0x40000000), 0); CcfifoWrite(EMC_PMACRO_CMD_PAD_TX_CTRL, dst_timing->burst_regs.emc_pmacro_cmd_pad_tx_ctrl | (1 << 26), 0); CcfifoWrite(EMC_FBIO_CFG5, dst_timing->burst_regs.emc_fbio_cfg5 | 0x100, 12); bool misc_flag = (src_misc_cfg_1 & 3) == 3; uint32_t timescale = (100000 << ((src_misc_cfg_1 >> 2) & 7)); uint32_t delay = (timescale / dst_clock_period); if (dst_rate_khz > 1150747 || misc_flag) { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xFEEDFEED, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xFE40FE40, delay + 1); CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xF800F800, delay + 1); } else { CcfifoWrite(EMC_PMACRO_BRICK_CTRL_RFU1, dst_timing->burst_regs.emc_pmacro_brick_ctrl_rfu1 & 0xF800F800, delay + 20); } if (dst_rate_khz > 600240 || misc_flag) { CcfifoWrite(EMC_INTSTATUS, 0, delay + 1); } } else { CcfifoWrite(EMC_FBIO_CFG5, reg::Read(EMC + EMC_FBIO_CFG5) & 0xF7FFFFFF, 12); CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active | 0x40000000), 0); } CcfifoWrite(EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 1, 0); CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_write_active & 0xBFFFFFFF), 0); if ((dst_misc_cfg_2 & 0x10) == 0) { DvfsPowerRampDown(src_timing, dst_timing, true, 1); } if ((src_misc_cfg_1 & 3) != 2) { DvfsPowerRampUp(src_clock_period, true, src_timing, dst_timing, training); if (ramp_up_wait < 1001000 && src_timing->ramp_wait != dst_timing->ramp_wait) { CcfifoWrite(EMC_INTSTATUS, 0, 1 + ((1001000 - ramp_up_wait) / dst_clock_period)); } CcfifoWrite(EMC_DBG, emc_dbg_write_active, 0); } else { if (ramp_up_wait < 1001000 && src_timing->ramp_wait != dst_timing->ramp_wait) { CcfifoWrite(EMC_INTSTATUS, 0, 1 + ((1001000 - ramp_up_wait) / dst_clock_period)); } CcfifoWrite(EMC_FBIO_CFG5, reg::Read(EMC + EMC_FBIO_CFG5), 0); CcfifoWrite(EMC_DBG, emc_dbg_write_active, 12); } { uint32_t pin_val = (src_misc_cfg_0 & 1) ? ((emc_pin_o & 0xFFFCFFFF) | (((src_misc_cfg_0 >> 1) & 3) << 16)) : emc_pin_o; pin_val &= 0xFFFFFFF8; pin_val |= (dram_dev_num == TWO_RANK) ? 7 : 1; CcfifoWrite(EMC_PIN, pin_val, 0); } if (train_ca || train_ca_vref) { CcfifoWrite(EMC_TR_CTRL_0, 0x2A, (200000 / src_clock_period)); CcfifoWrite(EMC_TR_CTRL_0, 0x20, (1000000 / src_clock_period)); CcfifoWrite(EMC_MRW3, mr13_catr_enable & 0xFFFFFFFE, 0); CcfifoWrite(EMC_INTSTATUS, 0, (1000000 / src_clock_period)); CcfifoWrite(EMC_PMACRO_DATA_RX_TERM_MODE, src_timing->burst_regs.emc_pmacro_data_rx_term_mode, 0); } CcfifoWrite(EMC_DBG, emc_dbg_o, 0); if (opt_zcal_en_cc) { if (shared_zq_resistor) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 1), 1 + util::DivideUp(1000000, src_clock_period)); if ((!(train_ca || train_ca_vref) || train_second_rank) && dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 1), 1 + util::DivideUp(1000000, src_clock_period)); } } else { CcfifoWrite(EMC_ZQ_CAL, (dram_dev_num == ONE_RANK ? (2 << 30) : (0 << 30)) | (1 << 0), 0); CcfifoWrite(EMC_ZQ_CAL, (dram_dev_num == ONE_RANK ? (2 << 30) : (0 << 30)) | (1 << 1), 1 + util::DivideUp(1000000, src_clock_period)); } } if (!(train_ca || train_ca_vref)) { CcfifoWrite(EMC_MRW3, ((mr13_flip_fspop & 0xF3FFFFF7) | (dst_misc_cfg_2 & 8)) ^ 0x0C0000C0, 0); } CcfifoWrite(EMC_SELF_REF, 0x0, 0); } /* Step 17: * exit self refresh. */ if (dram_type != DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_SELF_REF, 0, 0); } /* Step 18: * Send MRWs to LPDDR3/DDR3. */ if (is_lpddr2) { CcfifoWrite(EMC_MRW2, dst_timing->emc_mrw2, 0); CcfifoWrite(EMC_MRW, dst_timing->emc_mrw, 0); if (is_lpddr3) { CcfifoWrite(EMC_MRW4, dst_timing->emc_mrw4, 0); } } else if (dram_type == DRAM_TYPE_DDR4) { if (opt_dll_mode) { CcfifoWrite(EMC_EMRS, dst_timing->emc_emrs & ~(1 << 26), 0); } CcfifoWrite(EMC_EMRS2, dst_timing->emc_emrs2 & ~(1 << 26), 0); CcfifoWrite(EMC_MRS, dst_timing->emc_mrs | (1 << 26), 0); } /* Step 19: * ZQCAL for LPDDR3/DDR3 */ if (opt_zcal_en_cc) { if (is_lpddr2) { uint32_t zq_op = opt_cc_short_zcal ? dst_timing->zq_op_cc_short_zcal : dst_timing->zq_op_cc_long_zcal; uint32_t zcal_wait_time_ps = opt_cc_short_zcal ? dst_timing->zcal_wait_time_ps_cc_short_zcal : dst_timing->zcal_wait_time_ps_cc_long_zcal; uint32_t zcal_wait_time_clocks = util::DivideUp(zcal_wait_time_ps, dst_clock_period); CcfifoWrite(EMC_MRS_WAIT_CNT2, (zcal_wait_time_clocks & 0x3FF) | ((zcal_wait_time_clocks & 0x7FF) << 16), 0); CcfifoWrite(EMC_MRW, (zq_op | 0x880C0000) - 0x20000, 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_MRW, zq_op | 0x480A0000, 0); } } else if (dram_type == DRAM_TYPE_DDR4) { CcfifoWrite(EMC_ZQ_CAL, (2 << 30) | (1 << 0) | (opt_cc_short_zcal ? 0 : (1 << 4)), 0); if (dram_dev_num == TWO_RANK) { CcfifoWrite(EMC_ZQ_CAL, (1 << 30) | (1 << 0) | (opt_cc_short_zcal ? 0 : (1 << 4)), 0); } } } /* Step 20: * Issue ref and optional QRST. */ if (training_enabled || dram_type != DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_REF, dram_dev_num == ONE_RANK ? 0x80000000 : 0x00000000, 0); } if (opt_do_sw_qrst) { CcfifoWrite(EMC_ISSUE_QRST, 1, 0); CcfifoWrite(EMC_ISSUE_QRST, 0, 2); } /* Step 21: * Restore ZCAL and ZCAL interval. */ if (save_restore_clkstop_pd || opt_zcal_en_cc || (training_enabled && dram_type == DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o), 0); if (opt_zcal_en_cc) { if (training_enabled) { CcfifoWrite(EMC_ZCAL_INTERVAL, (dst_misc_cfg_2 & 2) ? 0 : src_timing->burst_regs.emc_zcal_interval, 0); } else if (dram_type != DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_ZCAL_INTERVAL, (dst_misc_cfg_2 & 2) ? 0 : dst_timing->burst_regs.emc_zcal_interval, 0); } } if (save_restore_clkstop_pd || (training_enabled && dram_type == DRAM_TYPE_LPDDR4)) { CcfifoWrite(EMC_CFG, dst_timing->burst_regs.emc_cfg & ~(1 << 28), 0); } if (training_enabled && dram_type == DRAM_TYPE_LPDDR4) { CcfifoWrite(EMC_SEL_DPD_CTRL, src_timing->emc_sel_dpd_ctrl, 0); } CcfifoWrite(EMC_DBG, emc_dbg_o, 0); } /* Step 22: * Restore EMC_CFG_PIPE_CLK. */ CcfifoWrite(EMC_CFG_PIPE_CLK, emc_cfg_pipe_clk_o, 0); CcfifoWrite(EMC_INTSTATUS, 0, dst_timing->pipe_clk_delay); /* Step 23: * Do clock change. */ if (training_enabled) { uint32_t clk_source_emc; if (ch0_enable || ch1_enable) { clk_source_emc = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE, clk_source_emc); } else { clk_source_emc = 0; } ChangeDllSrc(src_timing, clk_source_emc); } { uint32_t dig_dll = (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFFFE4) | 8; if ((dst_misc_cfg_2 & 1) == 0) { dig_dll = (dig_dll & 0xFFFFFF3F) | 0x80; } reg::Write(EMC + EMC_CFG_DIG_DLL, dig_dll); reg::Read(EMC + EMC_CFG_DIG_DLL); } reg::Read(MC + MC_EMEM_ADR_CFG); reg::Read(EMC + EMC_INTSTATUS); if (ch0_enable || ch1_enable) { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, dst_clk_src); reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC); } if (WaitForUpdate(EMC_INTSTATUS, (1 << 4), true, dst_emc_fbio_cfg7)) { return; } /* Step 24: * Save training results. */ if (training_enabled) { uint32_t tmp_emem_numdev = reg::Read(MC + MC_EMEM_ADR_CFG) & 1; uint32_t emc_dbg_tmp = reg::Read(EMC + EMC_DBG); reg::Write(EMC + EMC_DBG, emc_dbg_tmp | 1); /* Set READ_MUX to ASSEMBLY. */ uint32_t tmp_dram_dev_num = 1 + tmp_emem_numdev; /* Save CA results. */ if (train_ca) { dst_timing->trim_perch_regs.emc0_cmd_brlshft_0 = reg::Read(EMC0 + EMC_CMD_BRLSHFT_0); dst_timing->trim_perch_regs.emc1_cmd_brlshft_1 = reg::Read(EMC1 + EMC_CMD_BRLSHFT_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_4 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_5 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5); if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2); } } /* Save CA_VREF results. */ if (train_ca_vref) { uint32_t emc0_training_opt_ca_vref = reg::Read(EMC0 + EMC_TRAINING_OPT_CA_VREF); uint32_t emc1_training_opt_ca_vref = reg::Read(EMC1 + EMC_TRAINING_OPT_CA_VREF); uint32_t rank_mask = tmp_dram_dev_num == TWO_RANK ? 0x480C0000 : 0xC80C0000; dst_timing->burst_perch_regs.emc0_mrw10 = (emc0_training_opt_ca_vref & 0xFFFF) | 0x880C0000; dst_timing->burst_perch_regs.emc1_mrw10 = (emc1_training_opt_ca_vref & 0xFFFF) | 0x880C0000; dst_timing->burst_perch_regs.emc0_mrw11 = (rank_mask & 0xFFFFFF00) | ((emc0_training_opt_ca_vref >> 16) & 0xFFFF); dst_timing->burst_perch_regs.emc1_mrw11 = (rank_mask & 0xFFFFFF00) | ((emc1_training_opt_ca_vref >> 16) & 0xFFFF); } /* Save RD results. */ if (train_rd) { dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank0_3 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3); if (tmp_dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_long_dqs_rank1_3 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3); } if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte4_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte5_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte6_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank0_byte7_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2); if (tmp_dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte4_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte5_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte6_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_0 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_1 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1); dst_timing->trim_regs.emc_pmacro_ib_ddll_short_dq_rank1_byte7_2 = reg::Read(EMC1 + EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2); } } /* Save RD_VREF results. */ if (train_rd_vref) { uint32_t emc_pmacro_ib_vref_dq_0 = reg::Read(EMC0 + EMC_PMACRO_IB_VREF_DQ_0); uint32_t emc_pmacro_ib_vref_dq_1 = reg::Read(EMC0 + EMC_PMACRO_IB_VREF_DQ_1); #define GET_SAVE_RESTORE_MOD_REG(n) ((dst_timing->save_restore_mod_regs[n] & 0x80000000) ? (~dst_timing->save_restore_mod_regs[n]) : (dst_timing->save_restore_mod_regs[n])) uint8_t ib_vref_dq_byte0_icr = ((emc_pmacro_ib_vref_dq_0 >> 0) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(0) & 0x7F); uint8_t ib_vref_dq_byte1_icr = ((emc_pmacro_ib_vref_dq_0 >> 8) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(1) & 0x7F); uint8_t ib_vref_dq_byte2_icr = ((emc_pmacro_ib_vref_dq_0 >> 16) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(2) & 0x7F); uint8_t ib_vref_dq_byte3_icr = ((emc_pmacro_ib_vref_dq_0 >> 24) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(3) & 0x7F); uint8_t ib_vref_dq_byte4_icr = ((emc_pmacro_ib_vref_dq_1 >> 0) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(4) & 0x7F); uint8_t ib_vref_dq_byte5_icr = ((emc_pmacro_ib_vref_dq_1 >> 8) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(5) & 0x7F); uint8_t ib_vref_dq_byte6_icr = ((emc_pmacro_ib_vref_dq_1 >> 16) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(6) & 0x7F); uint8_t ib_vref_dq_byte7_icr = ((emc_pmacro_ib_vref_dq_1 >> 24) & 0x7F) + (GET_SAVE_RESTORE_MOD_REG(7) & 0x7F); dst_timing->trim_regs.emc_pmacro_ib_vref_dq_0 = ((ib_vref_dq_byte0_icr & 0x7F) | (ib_vref_dq_byte1_icr & 0x7F) << 8) | ((ib_vref_dq_byte2_icr & 0x7F) << 16) | ((ib_vref_dq_byte3_icr & 0x7F) << 24); dst_timing->trim_regs.emc_pmacro_ib_vref_dq_1 = ((ib_vref_dq_byte4_icr & 0x7F) | (ib_vref_dq_byte5_icr & 0x7F) << 8) | ((ib_vref_dq_byte6_icr & 0x7F) << 16) | ((ib_vref_dq_byte7_icr & 0x7F) << 24); #undef GET_SAVE_RESTORE_MOD_REG } } /* Save WR results. */ if (train_wr) { dst_timing->trim_perch_regs.emc0_data_brlshft_0 = reg::Read(EMC0 + EMC_DATA_BRLSHFT_0); dst_timing->trim_perch_regs.emc1_data_brlshft_0 = reg::Read(EMC1 + EMC_DATA_BRLSHFT_0); if (tmp_dram_dev_num == TWO_RANK) { dst_timing->trim_perch_regs.emc0_data_brlshft_1 = reg::Read(EMC0 + EMC_DATA_BRLSHFT_1); dst_timing->trim_perch_regs.emc1_data_brlshft_1 = reg::Read(EMC1 + EMC_DATA_BRLSHFT_1); } dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank0_3 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3); if (tmp_dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_long_dq_rank1_3 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3); } if (train_bit_level) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte4_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte5_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte6_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank0_byte7_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2); if (tmp_dram_dev_num == TWO_RANK) { dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte0_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte1_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte2_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_0 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_1 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte3_2 = reg::Read(EMC0 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte4_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte5_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte6_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_0 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_1 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1); dst_timing->trim_regs.emc_pmacro_ob_ddll_short_dq_rank1_byte7_2 = reg::Read(EMC1 + EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2); } } /* Save WR_VREF results. */ if (train_wr_vref) { uint32_t emc0_training_opt_dq_ob_vref = reg::Read(EMC0 + EMC_TRAINING_OPT_DQ_OB_VREF); uint32_t emc1_training_opt_dq_ob_vref = reg::Read(EMC1 + EMC_TRAINING_OPT_DQ_OB_VREF); #define GET_SAVE_RESTORE_MOD_REG(n) ((dst_timing->save_restore_mod_regs[n] & 0x80000000) ? (~dst_timing->save_restore_mod_regs[n]) : (dst_timing->save_restore_mod_regs[n])) uint8_t mod_reg_8 = GET_SAVE_RESTORE_MOD_REG( 8); uint8_t mod_reg_9 = GET_SAVE_RESTORE_MOD_REG( 9); uint8_t mod_reg_10 = GET_SAVE_RESTORE_MOD_REG(10); uint8_t mod_reg_11 = GET_SAVE_RESTORE_MOD_REG(11); #undef GET_SAVE_RESTORE_MOD_REG uint32_t rank_mask = tmp_dram_dev_num == TWO_RANK ? 0x480E0000 : 0xC80E0000; uint8_t emc0_mrw12_byte0 = (mod_reg_8 + ((emc0_training_opt_dq_ob_vref >> 0) & 0xFF)); uint8_t emc0_mrw12_byte1 = (mod_reg_9 + ((emc0_training_opt_dq_ob_vref >> 8) & 0xFF)); uint8_t emc0_mrw13_byte0 = (mod_reg_8 + ((emc0_training_opt_dq_ob_vref >> 16) & 0xFF)); uint8_t emc0_mrw13_byte1 = (mod_reg_9 + ((emc0_training_opt_dq_ob_vref >> 24) & 0xFF)); uint8_t emc1_mrw12_byte0 = (mod_reg_10 + ((emc1_training_opt_dq_ob_vref >> 0) & 0xFF)); uint8_t emc1_mrw12_byte1 = (mod_reg_11 + ((emc1_training_opt_dq_ob_vref >> 8) & 0xFF)); uint8_t emc1_mrw13_byte0 = (mod_reg_10 + ((emc1_training_opt_dq_ob_vref >> 16) & 0xFF)); uint8_t emc1_mrw13_byte1 = (mod_reg_11 + ((emc1_training_opt_dq_ob_vref >> 24) & 0xFF)); dst_timing->burst_perch_regs.emc0_mrw12 = (emc0_mrw12_byte0 << 0) | (emc0_mrw12_byte1 << 8) | 0x880E0000; dst_timing->burst_perch_regs.emc1_mrw12 = (emc1_mrw12_byte0 << 0) | (emc1_mrw12_byte1 << 8) | 0x880E0000; dst_timing->burst_perch_regs.emc1_mrw13 = (emc1_mrw13_byte0 << 0) | (emc1_mrw13_byte1 << 8) | rank_mask; dst_timing->burst_perch_regs.emc0_mrw13 = (emc0_mrw13_byte0 << 0) | (emc0_mrw13_byte1 << 8) | rank_mask; } } reg::Write(EMC + EMC_DBG, emc_dbg_tmp); } /* Step 25: * Program MC updown registers. */ if (dst_timing->rate_khz > src_timing->rate_khz && !training_enabled) { for (u32 i = 0; i < dst_timing->num_up_down; i++) { reg::Write(LaScaleRegisters[i], dst_timing->la_scale_regs_arr[i]); } /* Request a timing update. */ TimingUpdate(dst_emc_fbio_cfg7); } /* Step 26: * Restore ZCAL registers. */ if (dram_type == DRAM_TYPE_LPDDR4 && !training_enabled) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, dst_timing->burst_regs.emc_zcal_wait_cnt); reg::Write(EMC + EMC_ZCAL_INTERVAL, (dst_misc_cfg_2 & 2) ? 0 : dst_timing->burst_regs.emc_zcal_interval); reg::Write(EMC + EMC_DBG, emc_dbg_o); } if (dram_type != DRAM_TYPE_LPDDR4 && opt_cc_short_zcal && opt_zcal_en_cc && !opt_short_zcal) { util::WaitMicroSeconds(2); if (is_lpddr2) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_MRS_WAIT_CNT, dst_timing->burst_regs.emc_mrs_wait_cnt); reg::Write(EMC + EMC_DBG, emc_dbg_o); } else if (dram_type == DRAM_TYPE_DDR4) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, dst_timing->burst_regs.emc_zcal_wait_cnt); reg::Write(EMC + EMC_DBG, emc_dbg_o); } } if (training_enabled) { if (!src_timing->pllm_misc1_0_pllm_clamp_ph90) { reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC1, 0x80000000); } } else { if (!dst_timing->pllm_misc1_0_pllm_clamp_ph90) { reg::SetBits(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC1, 0x80000000); } } /* Step 27: * Restore EMC_CFG, FDPD registers. */ reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_CFG, dst_timing->burst_regs.emc_cfg); reg::Write(EMC + EMC_DBG, emc_dbg_o); reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, dst_timing->emc_fdpd_ctrl_cmd_no_ramp); reg::Write(EMC + EMC_SEL_DPD_CTRL, dst_timing->emc_sel_dpd_ctrl); /* Step 28: * Training recover. */ if (training_enabled && dram_type == DRAM_TYPE_LPDDR4) { reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_CFG, dst_timing->burst_regs.emc_cfg); reg::Write(EMC + EMC_SEL_DPD_CTRL, dst_timing->emc_sel_dpd_ctrl); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, src_timing->burst_regs.emc_zcal_wait_cnt); reg::Write(EMC + EMC_ZCAL_INTERVAL, (dst_misc_cfg_2 & 2) ? 0 : dst_timing->burst_regs.emc_zcal_interval); reg::Write(EMC + EMC_AUTO_CAL_CONFIG2, dst_timing->emc_auto_cal_config2); if (ch0_enable || ch1_enable) { reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG3, dst_timing->emc_auto_cal_config3); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG4, dst_timing->emc_auto_cal_config4); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG5, dst_timing->emc_auto_cal_config5); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG6, dst_timing->emc_auto_cal_config6); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG7, dst_timing->emc_auto_cal_config7); reg::Write(EMC0 + EMC_AUTO_CAL_CONFIG8, dst_timing->emc_auto_cal_config8); } reg::Write(EMC + EMC_DBG, emc_dbg_o); reg::Write(EMC + EMC_TR_DVFS, dst_timing->burst_regs.emc_tr_dvfs & ~(1 << 0)); } /* Step 29: * Power fix WAR. */ reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_COMMON, dst_timing->burst_regs.emc_pmacro_autocal_cfg_common); reg::Write(EMC + EMC_DBG, emc_dbg_o); reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, 0xFF0000); reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_0, 0x8); reg::Write(EMC + EMC_PMACRO_TRAINING_CTRL_1, 0x8); reg::Write(EMC + EMC_PMACRO_CFG_PM_GLOBAL_0, 0); reg::Write(EMC + EMC_DBG, SetShadowBypass(ACTIVE, emc_dbg_o)); /* Fixup xm2comppadctrl */ if ((dst_misc_cfg_1 & 0x20) == 0) { uint32_t xm2comppadctrl = reg::Read(EMC + EMC_XM2COMPPADCTRL); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl & 0x1CFFFFFF); util::WaitMicroSeconds(1); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl & 0x0CFFFFFF); util::WaitMicroSeconds(1); reg::Write(EMC + EMC_XM2COMPPADCTRL, xm2comppadctrl & 0x04FFFFFF); util::WaitMicroSeconds(1); } reg::SetBits(EMC + EMC_PMACRO_DLL_CFG_1, 0x2000); reg::Read(EMC + EMC_PMACRO_DLL_CFG_1); util::WaitMicroSeconds(2); /* Select EMC DLL clock source. */ { reg::SetBits(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL, 0xC00); reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL); } reg::Write(EMC + EMC_DBG, SetShadowBypass(ASSEMBLY, emc_dbg_o)); reg::Read(EMC + EMC_DBG); /* Step 30: * Re-enable autocal. */ if (!training_enabled) { if (dst_timing->burst_regs.emc_cfg_dig_dll & 1) { uint32_t dig_dll = (reg::Read(EMC + EMC_CFG_DIG_DLL) & 0xFFFFFFE4) | 9; if ((dst_misc_cfg_2 & 1) == 0) { dig_dll = (dig_dll & 0xFFFFFF3F) | 0x80; } reg::Write(EMC + EMC_CFG_DIG_DLL, dig_dll); /* Request a timing update. */ TimingUpdate(dst_emc_fbio_cfg7); } } if (!(training_enabled && dram_type == DRAM_TYPE_LPDDR4)) { reg::Write(EMC + EMC_AUTO_CAL_CONFIG, training_enabled ? src_timing->emc_auto_cal_config : dst_timing->emc_auto_cal_config); } if (training_enabled) { g_fsp_for_next_freq = !g_fsp_for_next_freq; } if (src_timing->periodic_training) { /* Reset all clock tree values. */ src_timing->current_dram_clktree_c0d0u0 = src_timing->trained_dram_clktree_c0d0u0; src_timing->current_dram_clktree_c0d0u1 = src_timing->trained_dram_clktree_c0d0u1; src_timing->current_dram_clktree_c0d1u0 = src_timing->trained_dram_clktree_c0d1u0; src_timing->current_dram_clktree_c0d1u1 = src_timing->trained_dram_clktree_c0d1u1; src_timing->current_dram_clktree_c1d0u0 = src_timing->trained_dram_clktree_c1d0u0; src_timing->current_dram_clktree_c1d0u1 = src_timing->trained_dram_clktree_c1d0u1; src_timing->current_dram_clktree_c1d1u0 = src_timing->trained_dram_clktree_c1d1u0; src_timing->current_dram_clktree_c1d1u1 = src_timing->trained_dram_clktree_c1d1u1; } /* Disable pll. */ PllDisable(dst_clk_src); } void CleanupActiveShadowCopy(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing) { /* Change CFG_SWAP to ASSEMBLY_ONLY */ uint32_t emc_dbg = reg::Read(EMC + EMC_DBG); emc_dbg = ((emc_dbg & 0xF3FFFFFF) | 0x8000000); reg::Write(EMC + EMC_DBG, emc_dbg); /* Wait for update. */ TimingUpdate(src_timing->emc_fbio_cfg7); /* Change CFG_SWAP to ACTIVE_ONLY */ emc_dbg = reg::Read(EMC + EMC_DBG); emc_dbg &= 0xF3FFFFFF; reg::Write(EMC + EMC_DBG, emc_dbg); /* Set PMACRO_DLL_CFG_1, preserving MDDLL_SEL_CLK_SRC */ reg::Write(EMC + EMC_PMACRO_DLL_CFG_1, (reg::Read(EMC + EMC_PMACRO_DLL_CFG_1) & 0x00002000) | (src_timing->burst_regs.emc_pmacro_dll_cfg_1 & 0xFFFFDFFF)); /* Update CFG_DIG_DLL */ uint32_t emc_cfg_dig_dll = reg::Read(EMC + EMC_CFG_DIG_DLL); emc_cfg_dig_dll = (dst_timing->misc_cfg_2 & 1) ? (emc_cfg_dig_dll & 0xFFFFFFFE) : ((emc_cfg_dig_dll & 0xFFFFFF3E) | 0x80); reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Wait for update. */ TimingUpdate(src_timing->emc_fbio_cfg7); /* Disable or enable DLL */ emc_cfg_dig_dll = reg::Read(EMC + EMC_CFG_DIG_DLL); if (src_timing->burst_regs.emc_cfg_dig_dll & 1) { emc_cfg_dig_dll |= 0x01; } else { emc_cfg_dig_dll &= 0xFFFFFFFE; } if ((dst_timing->misc_cfg_2 & 1) == 0) { emc_cfg_dig_dll = ((emc_cfg_dig_dll & 0xFFFFFF3F) | 0x80); } reg::Write(EMC + EMC_CFG_DIG_DLL, emc_cfg_dig_dll); /* Wait for update. */ TimingUpdate(src_timing->emc_fbio_cfg7); /* Wait for DLL_LOCK to be set */ WaitForUpdate(EMC_DIG_DLL_STATUS, (1 << 2), true, src_timing->emc_fbio_cfg7); /* Wait for update. */ TimingUpdate(src_timing->emc_fbio_cfg7); /* Set AUTO_CAL_CONFIG. */ uint32_t emc_auto_cal_config = reg::Read(EMC + EMC_AUTO_CAL_CONFIG); emc_auto_cal_config = (dst_timing->misc_cfg_2 & 4) ? (emc_auto_cal_config & 0xDFFFF9FF) : ((emc_auto_cal_config & 0x5FFFF9FF) | 0x80000000); reg::Write(EMC + EMC_AUTO_CAL_CONFIG, emc_auto_cal_config | 0x20000000); } void TrainFreq(EmcDvfsTimingTable *src_timing, EmcDvfsTimingTable *dst_timing, u32 next_clk_src) { /* Get dram dev num. */ const u32 dram_dev_num = (reg::Read(MC + MC_EMEM_ADR_CFG) & 1) + 1; /* Write RAM patterns, if first training. */ if (!g_did_first_training) { const auto * const pattern = GetEmcRamTrainingPattern(); for (u32 i = 0; i < 0x100; ++i) { reg::Write(EMC + EMC_TRAINING_PATRAM_DQ, pattern[dst_timing->training_pattern].dq[i]); reg::Write(EMC + EMC_TRAINING_PATRAM_DMI, pattern[dst_timing->training_pattern].dmi[i]); reg::Write(EMC + EMC_TRAINING_PATRAM_CTRL, 0x80000000 | i); } g_did_first_training = true; } reg::Write(EMC + EMC_TRAINING_QUSE_CTRL_MISC, (dst_timing->burst_regs.emc_training_read_ctrl_misc & 0xFFFF0000) | 0x00001000); /* Do training, if we need to. */ const u32 needed_training = dst_timing->needs_training; if (needed_training && !dst_timing->trained) { /* Determine what training to do. */ u32 training_params[4]; u32 num_params = 0; if (needed_training & (CA_TRAINING | CA_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (CA_TRAINING | CA_VREF_TRAINING | BIT_LEVEL_TRAINING)); if (dram_dev_num == TWO_RANK) { training_params[num_params++] = (needed_training & (CA_TRAINING | CA_VREF_TRAINING | TRAIN_SECOND_RANK | BIT_LEVEL_TRAINING)); } } if (needed_training & (WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING)) { training_params[num_params++] = (needed_training & (WRITE_TRAINING | WRITE_VREF_TRAINING | READ_TRAINING | READ_VREF_TRAINING | BIT_LEVEL_TRAINING)); } /* Apply all training. */ for (u32 i = 0; i < num_params; ++i) { FreqChange(src_timing, dst_timing, training_params[i], next_clk_src); CleanupActiveShadowCopy(src_timing, dst_timing); } /* Set tables as trained. */ dst_timing->trained = 1; } } void Dvfs(EmcDvfsTimingTable *dst_timing, EmcDvfsTimingTable *src_timing, bool train) { /* Get the clock sources/rates. */ u32 clk_src_emc_from = src_timing->clk_src_emc; u32 clk_src_emc_to = dst_timing->clk_src_emc; u32 rate_from = src_timing->rate_khz; u32 rate_to = dst_timing->rate_khz; /* Get channel enables. */ const bool ch0_enable = reg::GetField(dst_timing->emc_fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH0_ENABLE)) == EMC_FBIO_CFG7_CH0_ENABLE_ENABLE; const bool ch1_enable = reg::GetField(dst_timing->emc_fbio_cfg7, EMC_REG_BITS_MASK(FBIO_CFG7_CH1_ENABLE)) == EMC_FBIO_CFG7_CH1_ENABLE_ENABLE; /* Reprogram pll. */ const u32 prev_2x_clk_src = reg::GetField(clk_src_emc_from, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); const u32 next_2x_clk_src = reg::GetField(clk_src_emc_to, CLK_RST_REG_BITS_MASK(CLK_SOURCE_EMC_EMC_2X_CLK_SRC)); if (next_2x_clk_src != PLLP_OUT0 && next_2x_clk_src != PLLP_UD) { if (ch0_enable || ch1_enable) { if (PllReprogram(rate_to, clk_src_emc_to, rate_from, clk_src_emc_from)) { if (prev_2x_clk_src == PLLMB_UD || prev_2x_clk_src == PLLMB_OUT0) { g_next_pll = 0; } else if (prev_2x_clk_src == PLLM_UD || prev_2x_clk_src == PLLM_OUT0) { g_next_pll = !g_next_pll; } clk_src_emc_to = ProgramPllm(rate_to, clk_src_emc_to, clk_src_emc_to, g_next_pll, dst_timing); } else { if (next_2x_clk_src == PLLM_UD || next_2x_clk_src == PLLMB_UD) { if (g_next_pll) { reg::SetField(clk_src_emc_to, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_UD)); } } else if (next_2x_clk_src == PLLM_OUT0 || next_2x_clk_src == PLLMB_OUT0) { if (g_next_pll) { reg::SetField(clk_src_emc_to, CLK_RST_REG_BITS_VALUE(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLMB_OUT0)); } } } } } if (train) { TrainFreq(src_timing, dst_timing, clk_src_emc_to); if (ch0_enable || ch1_enable) { if (PllReprogram(dst_timing->rate_khz, dst_timing->clk_src_emc, src_timing->rate_khz, src_timing->clk_src_emc)) { g_next_pll = !g_next_pll; } } } else { FreqChange(src_timing, dst_timing, 0, clk_src_emc_to); } } } void DoMemoryTrainingMariko(bool *out_did_training, int index, void *mtc_tables_buffer) { /* Get timing tables. */ auto *timing = GetEmcDvfsTimingTables(index, mtc_tables_buffer); auto *src_timing = timing + 0; auto *dst_timing = timing + 1; /* Check timing tables. */ if (src_timing->rate_khz != 204000 || dst_timing->rate_khz != 1600000) { ShowFatalError("EmcDvfsTimingTables seem corrupted %" PRIu32 " %" PRIu32 "?\n", src_timing->rate_khz, dst_timing->rate_khz); } /* Check that we should do training. */ if (src_timing->clk_src_emc != reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC)) { /* Our clock source isn't what's expected, so presumably training has already been done? */ /* Either way, the safe bet is to skip it. */ *out_did_training = false; return; } /* Train 1600MHz. */ Dvfs(dst_timing, src_timing, true); /* Switch to 1600MHz. */ Dvfs(dst_timing, src_timing, false); /* Set ourselves as having done training */ *out_did_training = true; } void RestoreMemoryClockRateMariko(void *mtc_tables_buffer) { /* Get timing tables. */ auto *timing_tables = reinterpret_cast<EmcDvfsTimingTable *>(mtc_tables_buffer); auto *src_timing = timing_tables + 0; auto *dst_timing = timing_tables + 1; /* Check timing tables. */ if (src_timing->rate_khz != 204000 || dst_timing->rate_khz != 1600000) { ShowFatalError("EmcDvfsTimingTables seem corrupted %" PRIu32 " %" PRIu32 "?\n", src_timing->rate_khz, dst_timing->rate_khz); } /* Switch to 204MHz */ Dvfs(src_timing, dst_timing, false); } } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_ram_training_pattern.inc ================================================ /* * Copyright (c) Atmosphre-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ struct EmcRamTrainingPattern { u32 dq[0x100]; u8 dmi[0x100]; }; constexpr const u8 EmcRamTrainingPatternData[] { 0x18, 0x18, 0x18, 0x18, 0x61, 0x61, 0x61, 0x61, 0x85, 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x14, 0x51, 0x51, 0x51, 0x51, 0x47, 0x47, 0x47, 0x47, 0x1E, 0x1E, 0x1E, 0x1E, 0x79, 0x79, 0x79, 0x79, 0xE5, 0xE5, 0xE5, 0xE5, 0x94, 0x94, 0x94, 0x94, 0x51, 0x51, 0x51, 0x51, 0x46, 0x46, 0x46, 0x46, 0x19, 0x19, 0x19, 0x19, 0x67, 0x67, 0x67, 0x67, 0x9C, 0x9C, 0x9C, 0x9C, 0x71, 0x71, 0x71, 0x71, 0xC5, 0xC5, 0xC5, 0xC5, 0x17, 0x17, 0x17, 0x17, 0x5F, 0x5F, 0x5F, 0x5F, 0x7E, 0x7E, 0x7E, 0x7E, 0xFB, 0xFB, 0xFB, 0xFB, 0xED, 0xED, 0xED, 0xED, 0xB4, 0xB4, 0xB4, 0xB4, 0xD2, 0xD2, 0xD2, 0xD2, 0x48, 0x48, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x85, 0x85, 0x85, 0x85, 0x16, 0x16, 0x16, 0x16, 0x59, 0x59, 0x59, 0x59, 0x66, 0x66, 0x66, 0x66, 0x9A, 0x9A, 0x9A, 0x9A, 0x69, 0x69, 0x69, 0x69, 0xA4, 0xA4, 0xA4, 0xA4, 0x93, 0x93, 0x93, 0x93, 0x4F, 0x4F, 0x4F, 0x4F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFC, 0xFC, 0xFC, 0xFC, 0xF3, 0xF3, 0xF3, 0xF3, 0xCD, 0xCD, 0xCD, 0xCD, 0x37, 0x37, 0x37, 0x37, 0xDC, 0xDC, 0xDC, 0xDC, 0x70, 0x70, 0x70, 0x70, 0xC3, 0xC3, 0xC3, 0xC3, 0x0F, 0x0F, 0x0F, 0x0F, 0x3E, 0x3E, 0x3E, 0x3E, 0xFA, 0xFA, 0xFA, 0xFA, 0xEB, 0xEB, 0xEB, 0xEB, 0xAC, 0xAC, 0xAC, 0xAC, 0xB3, 0xB3, 0xB3, 0xB3, 0xCC, 0xCC, 0xCC, 0xCC, 0x31, 0x31, 0x31, 0x31, 0xC5, 0xC5, 0xC5, 0xC5, 0x15, 0x15, 0x15, 0x15, 0x57, 0x57, 0x57, 0x57, 0x5F, 0x5F, 0x5F, 0x5F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFD, 0xFD, 0xFD, 0xFD, 0xF4, 0xF4, 0xF4, 0xF4, 0xD0, 0xD0, 0xD0, 0xD0, 0x42, 0x42, 0x42, 0x42, 0x08, 0x08, 0x08, 0x08, 0x23, 0x23, 0x23, 0x23, 0x8F, 0x8F, 0x8F, 0x8F, 0x3F, 0x3F, 0x3F, 0x3F, 0x18, 0x18, 0x18, 0x18, 0x61, 0x61, 0x61, 0x61, 0x85, 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x14, 0x51, 0x51, 0x51, 0x51, 0x47, 0x47, 0x47, 0x47, 0x1E, 0x1E, 0x1E, 0x1E, 0x79, 0x79, 0x79, 0x79, 0xE5, 0xE5, 0xE5, 0xE5, 0x94, 0x94, 0x94, 0x94, 0x51, 0x51, 0x51, 0x51, 0x46, 0x46, 0x46, 0x46, 0x19, 0x19, 0x19, 0x19, 0x67, 0x67, 0x67, 0x67, 0x9C, 0x9C, 0x9C, 0x9C, 0x71, 0x71, 0x71, 0x71, 0xC5, 0xC5, 0xC5, 0xC5, 0x17, 0x17, 0x17, 0x17, 0x5F, 0x5F, 0x5F, 0x5F, 0x7E, 0x7E, 0x7E, 0x7E, 0xFB, 0xFB, 0xFB, 0xFB, 0xED, 0xED, 0xED, 0xED, 0xB4, 0xB4, 0xB4, 0xB4, 0xD2, 0xD2, 0xD2, 0xD2, 0x48, 0x48, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x85, 0x85, 0x85, 0x85, 0x16, 0x16, 0x16, 0x16, 0x59, 0x59, 0x59, 0x59, 0x66, 0x66, 0x66, 0x66, 0x9A, 0x9A, 0x9A, 0x9A, 0x69, 0x69, 0x69, 0x69, 0xA4, 0xA4, 0xA4, 0xA4, 0x93, 0x93, 0x93, 0x93, 0x4F, 0x4F, 0x4F, 0x4F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFC, 0xFC, 0xFC, 0xFC, 0xF3, 0xF3, 0xF3, 0xF3, 0xCD, 0xCD, 0xCD, 0xCD, 0x37, 0x37, 0x37, 0x37, 0xDC, 0xDC, 0xDC, 0xDC, 0x70, 0x70, 0x70, 0x70, 0xC3, 0xC3, 0xC3, 0xC3, 0x0F, 0x0F, 0x0F, 0x0F, 0x3E, 0x3E, 0x3E, 0x3E, 0xFA, 0xFA, 0xFA, 0xFA, 0xEB, 0xEB, 0xEB, 0xEB, 0xAC, 0xAC, 0xAC, 0xAC, 0xB3, 0xB3, 0xB3, 0xB3, 0xCC, 0xCC, 0xCC, 0xCC, 0x31, 0x31, 0x31, 0x31, 0xC5, 0xC5, 0xC5, 0xC5, 0x15, 0x15, 0x15, 0x15, 0x57, 0x57, 0x57, 0x57, 0x5F, 0x5F, 0x5F, 0x5F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFD, 0xFD, 0xFD, 0xFD, 0xF4, 0xF4, 0xF4, 0xF4, 0xD0, 0xD0, 0xD0, 0xD0, 0x42, 0x42, 0x42, 0x42, 0x08, 0x08, 0x08, 0x08, 0x23, 0x23, 0x23, 0x23, 0x8F, 0x8F, 0x8F, 0x8F, 0x3F, 0x3F, 0x3F, 0x3F, 0x06, 0x06, 0x06, 0x06, 0x18, 0x18, 0x18, 0x18, 0x21, 0x21, 0x21, 0x21, 0x05, 0x05, 0x05, 0x05, 0x14, 0x14, 0x14, 0x14, 0x11, 0x11, 0x11, 0x11, 0x07, 0x07, 0x07, 0x07, 0x1E, 0x1E, 0x1E, 0x1E, 0x39, 0x39, 0x39, 0x39, 0x25, 0x25, 0x25, 0x25, 0x14, 0x14, 0x14, 0x14, 0x11, 0x11, 0x11, 0x11, 0x06, 0x06, 0x06, 0x06, 0x19, 0x19, 0x19, 0x19, 0x27, 0x27, 0x27, 0x27, 0x1C, 0x1C, 0x1C, 0x1C, 0x31, 0x31, 0x31, 0x31, 0x05, 0x05, 0x05, 0x05, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3B, 0x3B, 0x3B, 0x3B, 0x2D, 0x2D, 0x2D, 0x2D, 0x34, 0x34, 0x34, 0x34, 0x12, 0x12, 0x12, 0x12, 0x08, 0x08, 0x08, 0x08, 0x21, 0x21, 0x21, 0x21, 0x05, 0x05, 0x05, 0x05, 0x16, 0x16, 0x16, 0x16, 0x19, 0x19, 0x19, 0x19, 0x26, 0x26, 0x26, 0x26, 0x1A, 0x1A, 0x1A, 0x1A, 0x29, 0x29, 0x29, 0x29, 0x24, 0x24, 0x24, 0x24, 0x13, 0x13, 0x13, 0x13, 0x0F, 0x0F, 0x0F, 0x0F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3C, 0x3C, 0x3C, 0x3C, 0x33, 0x33, 0x33, 0x33, 0x0D, 0x0D, 0x0D, 0x0D, 0x37, 0x37, 0x37, 0x37, 0x1C, 0x1C, 0x1C, 0x1C, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x0F, 0x0F, 0x0F, 0x0F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3A, 0x3A, 0x3A, 0x3A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C, 0x33, 0x33, 0x33, 0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x31, 0x31, 0x31, 0x31, 0x05, 0x05, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3D, 0x3D, 0x3D, 0x3D, 0x34, 0x34, 0x34, 0x34, 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x23, 0x23, 0x23, 0x23, 0x0F, 0x0F, 0x0F, 0x0F, 0x06, 0x06, 0x06, 0x06, 0x18, 0x18, 0x18, 0x18, 0x21, 0x21, 0x21, 0x21, 0x05, 0x05, 0x05, 0x05, 0x14, 0x14, 0x14, 0x14, 0x11, 0x11, 0x11, 0x11, 0x07, 0x07, 0x07, 0x07, 0x1E, 0x1E, 0x1E, 0x1E, 0x39, 0x39, 0x39, 0x39, 0x25, 0x25, 0x25, 0x25, 0x14, 0x14, 0x14, 0x14, 0x11, 0x11, 0x11, 0x11, 0x06, 0x06, 0x06, 0x06, 0x19, 0x19, 0x19, 0x19, 0x27, 0x27, 0x27, 0x27, 0x1C, 0x1C, 0x1C, 0x1C, 0x31, 0x31, 0x31, 0x31, 0x05, 0x05, 0x05, 0x05, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3B, 0x3B, 0x3B, 0x3B, 0x2D, 0x2D, 0x2D, 0x2D, 0x34, 0x34, 0x34, 0x34, 0x12, 0x12, 0x12, 0x12, 0x08, 0x08, 0x08, 0x08, 0x21, 0x21, 0x21, 0x21, 0x05, 0x05, 0x05, 0x05, 0x16, 0x16, 0x16, 0x16, 0x19, 0x19, 0x19, 0x19, 0x26, 0x26, 0x26, 0x26, 0x1A, 0x1A, 0x1A, 0x1A, 0x29, 0x29, 0x29, 0x29, 0x24, 0x24, 0x24, 0x24, 0x13, 0x13, 0x13, 0x13, 0x0F, 0x0F, 0x0F, 0x0F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3C, 0x3C, 0x3C, 0x3C, 0x33, 0x33, 0x33, 0x33, 0x0D, 0x0D, 0x0D, 0x0D, 0x37, 0x37, 0x37, 0x37, 0x1C, 0x1C, 0x1C, 0x1C, 0x30, 0x30, 0x30, 0x30, 0x03, 0x03, 0x03, 0x03, 0x0F, 0x0F, 0x0F, 0x0F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3A, 0x3A, 0x3A, 0x3A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2C, 0x33, 0x33, 0x33, 0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x31, 0x31, 0x31, 0x31, 0x05, 0x05, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3D, 0x3D, 0x3D, 0x3D, 0x34, 0x34, 0x34, 0x34, 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x08, 0x23, 0x23, 0x23, 0x23, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03, 0x0A, 0x05, 0x0C, 0x03 }; static_assert(sizeof(EmcRamTrainingPatternData) % sizeof(EmcRamTrainingPattern) == 0); ALWAYS_INLINE const EmcRamTrainingPattern *GetEmcRamTrainingPattern() { return reinterpret_cast<const EmcRamTrainingPattern *>(EmcRamTrainingPatternData); } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_tables_erista.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ constexpr const u8 T210SdevEmcDvfsTableS6gb01[] = { #embed "../../mtc_tables/combined/T210SdevEmcDvfsTableS6gb01/table.bin" }; constexpr const u8 T210SdevEmcDvfsTableH4gb01[] = { #embed "../../mtc_tables/combined/T210SdevEmcDvfsTableH4gb01/table.bin" }; constexpr const u8 T210SdevEmcDvfsTableS4gb01[] = { #embed "../../mtc_tables/combined/T210SdevEmcDvfsTableS4gb01/table.bin" }; ================================================ FILE: fusee/program/source/mtc/fusee_mtc_tables_mariko.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ constexpr const u8 T210b01SdevEmcDvfsTableM4gb03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableM4gb03/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1z4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1z4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y8gbY01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y8gbY01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableM1a4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableM1a4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableH4gb03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableH4gb03/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y4gbX03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y4gbX03/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableM1y4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableM1y4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableH1y4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableH1y4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS4gb03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS4gb03/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS4gbY01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS4gbY01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y8gb04[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y8gb04/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableH1a4gb01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableH1a4gb01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y4gbY01[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y4gbY01/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS8gb03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS8gb03/table.bin" }; constexpr const u8 T210b01SdevEmcDvfsTableS1y8gbX03[] = { #embed "../../mtc_tables/combined/T210b01SdevEmcDvfsTableS1y8gbX03/table.bin" }; ================================================ FILE: fusee/program/source/mtc/fusee_mtc_timing_table_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> namespace ams::nxboot { #define MC_BASE (0x70019000) #define EMC_BASE (0x7001B000) #define EMC0_BASE (0x7001E000) #define EMC1_BASE (0x7001F000) enum { PLLM_OUT0 = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLM_OUT0, PLLC_OUT0 = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLC_OUT0, PLLP_OUT0 = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLP_OUT0, CLK_M = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_CLK_M, PLLM_UD = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLM_UD, PLLMB_UD = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLMB_UD, PLLMB_OUT0 = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLMB_OUT0, PLLP_UD = CLK_RST_CONTROLLER_CLK_SOURCE_EMC_EMC_2X_CLK_SRC_PLLP_UD }; enum { ONE_RANK = 1, TWO_RANK = 2, }; enum { DLL_OFF = 0, DLL_ON = 1, }; enum { AUTO_PD = 0, MAN_SR = 2, }; enum { NO_TRAINING = (0 << 0), CA_TRAINING = (1 << 0), CA_VREF_TRAINING = (1 << 1), QUSE_TRAINING = (1 << 2), QUSE_VREF_TRAINING = (1 << 3), WRITE_TRAINING = (1 << 4), WRITE_VREF_TRAINING = (1 << 5), READ_TRAINING = (1 << 6), READ_VREF_TRAINING = (1 << 7), TRAIN_SECOND_RANK = (1 << 8), BIT_LEVEL_TRAINING = (1 << 9), }; enum { DRAM_TYPE_DDR4 = EMC_FBIO_CFG5_DRAM_TYPE_DDR4, DRAM_TYPE_LPDDR4 = EMC_FBIO_CFG5_DRAM_TYPE_LPDDR4, DRAM_TYPE_LPDDR2 = EMC_FBIO_CFG5_DRAM_TYPE_LPDDR2, DRAM_TYPE_DDR2 = EMC_FBIO_CFG5_DRAM_TYPE_DDR2 }; enum { ASSEMBLY = EMC_DBG_WRITE_MUX_ASSEMBLY, ACTIVE = EMC_DBG_WRITE_MUX_ACTIVE, }; enum { DVFS_SEQUENCE = 1, WRITE_TRAINING_SEQUENCE = 2, PERIODIC_TRAINING_SEQUENCE = 3, DVFS_PT1 = 10, DVFS_UPDATE = 11, TRAINING_PT1 = 12, TRAINING_UPDATE = 13, PERIODIC_TRAINING_UPDATE = 14, }; /* * Do arithmetic in fixed point. */ #define MOVAVG_PRECISION_FACTOR 100 /* * The division portion of the average operation. */ #define __AVERAGE_PTFV(dev) \ ({ dst_timing->ptfv_dqsosc_movavg_##dev = \ dst_timing->ptfv_dqsosc_movavg_##dev / \ dst_timing->ptfv_dvfs_samples; }) /* * The division portion of the average write operation. */ #define __AVERAGE_WRITE_PTFV(dev) \ ({ dst_timing->ptfv_dqsosc_movavg_##dev = \ dst_timing->ptfv_dqsosc_movavg_##dev / \ dst_timing->ptfv_write_samples; }) /* * Convert val to fixed point and add it to the temporary average. */ #define __INCREMENT_PTFV(dev, val) \ ({ dst_timing->ptfv_dqsosc_movavg_##dev += \ ((val) * MOVAVG_PRECISION_FACTOR); }) /* * Convert a moving average back to integral form and return the value. */ #define __MOVAVG_AC(timing, dev) \ ((timing)->ptfv_dqsosc_movavg_##dev / \ MOVAVG_PRECISION_FACTOR) /* Weighted update. */ #define __WEIGHTED_UPDATE_PTFV(dev, nval) \ do { \ dst_timing->ptfv_dqsosc_movavg_##dev = \ ((nval * MOVAVG_PRECISION_FACTOR) + \ (dst_timing->ptfv_dqsosc_movavg_##dev * \ dst_timing->ptfv_movavg_weight)) / \ (dst_timing->ptfv_movavg_weight + 1); \ } while (0) /* Access a particular average. */ #define __MOVAVG(timing, dev) \ ((timing)->ptfv_dqsosc_movavg_##dev) #define FOREACH_PER_CHANNEL_BURST_REG(HANDLER) \ HANDLER(EMC0, EMC_MRW10, emc0_mrw10) \ HANDLER(EMC1, EMC_MRW10, emc1_mrw10) \ HANDLER(EMC0, EMC_MRW11, emc0_mrw11) \ HANDLER(EMC1, EMC_MRW11, emc1_mrw11) \ HANDLER(EMC0, EMC_MRW12, emc0_mrw12) \ HANDLER(EMC1, EMC_MRW12, emc1_mrw12) \ HANDLER(EMC0, EMC_MRW13, emc0_mrw13) \ HANDLER(EMC1, EMC_MRW13, emc1_mrw13) \ #define FOREACH_TRIM_REG(HANDLER) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0, emc_pmacro_ib_ddll_long_dqs_rank0_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1, emc_pmacro_ib_ddll_long_dqs_rank0_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2, emc_pmacro_ib_ddll_long_dqs_rank0_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3, emc_pmacro_ib_ddll_long_dqs_rank0_3) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0, emc_pmacro_ib_ddll_long_dqs_rank1_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1, emc_pmacro_ib_ddll_long_dqs_rank1_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2, emc_pmacro_ib_ddll_long_dqs_rank1_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3, emc_pmacro_ib_ddll_long_dqs_rank1_3) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0, emc_pmacro_ib_ddll_short_dq_rank0_byte0_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1, emc_pmacro_ib_ddll_short_dq_rank0_byte0_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2, emc_pmacro_ib_ddll_short_dq_rank0_byte0_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0, emc_pmacro_ib_ddll_short_dq_rank0_byte1_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1, emc_pmacro_ib_ddll_short_dq_rank0_byte1_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2, emc_pmacro_ib_ddll_short_dq_rank0_byte1_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0, emc_pmacro_ib_ddll_short_dq_rank0_byte2_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1, emc_pmacro_ib_ddll_short_dq_rank0_byte2_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2, emc_pmacro_ib_ddll_short_dq_rank0_byte2_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0, emc_pmacro_ib_ddll_short_dq_rank0_byte3_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1, emc_pmacro_ib_ddll_short_dq_rank0_byte3_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2, emc_pmacro_ib_ddll_short_dq_rank0_byte3_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0, emc_pmacro_ib_ddll_short_dq_rank0_byte4_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1, emc_pmacro_ib_ddll_short_dq_rank0_byte4_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2, emc_pmacro_ib_ddll_short_dq_rank0_byte4_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0, emc_pmacro_ib_ddll_short_dq_rank0_byte5_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1, emc_pmacro_ib_ddll_short_dq_rank0_byte5_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2, emc_pmacro_ib_ddll_short_dq_rank0_byte5_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0, emc_pmacro_ib_ddll_short_dq_rank0_byte6_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1, emc_pmacro_ib_ddll_short_dq_rank0_byte6_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2, emc_pmacro_ib_ddll_short_dq_rank0_byte6_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0, emc_pmacro_ib_ddll_short_dq_rank0_byte7_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1, emc_pmacro_ib_ddll_short_dq_rank0_byte7_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2, emc_pmacro_ib_ddll_short_dq_rank0_byte7_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0, emc_pmacro_ib_ddll_short_dq_rank1_byte0_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1, emc_pmacro_ib_ddll_short_dq_rank1_byte0_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2, emc_pmacro_ib_ddll_short_dq_rank1_byte0_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0, emc_pmacro_ib_ddll_short_dq_rank1_byte1_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1, emc_pmacro_ib_ddll_short_dq_rank1_byte1_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2, emc_pmacro_ib_ddll_short_dq_rank1_byte1_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0, emc_pmacro_ib_ddll_short_dq_rank1_byte2_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1, emc_pmacro_ib_ddll_short_dq_rank1_byte2_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2, emc_pmacro_ib_ddll_short_dq_rank1_byte2_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0, emc_pmacro_ib_ddll_short_dq_rank1_byte3_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1, emc_pmacro_ib_ddll_short_dq_rank1_byte3_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2, emc_pmacro_ib_ddll_short_dq_rank1_byte3_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0, emc_pmacro_ib_ddll_short_dq_rank1_byte4_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1, emc_pmacro_ib_ddll_short_dq_rank1_byte4_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2, emc_pmacro_ib_ddll_short_dq_rank1_byte4_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0, emc_pmacro_ib_ddll_short_dq_rank1_byte5_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1, emc_pmacro_ib_ddll_short_dq_rank1_byte5_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2, emc_pmacro_ib_ddll_short_dq_rank1_byte5_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0, emc_pmacro_ib_ddll_short_dq_rank1_byte6_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1, emc_pmacro_ib_ddll_short_dq_rank1_byte6_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2, emc_pmacro_ib_ddll_short_dq_rank1_byte6_2) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0, emc_pmacro_ib_ddll_short_dq_rank1_byte7_0) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1, emc_pmacro_ib_ddll_short_dq_rank1_byte7_1) \ HANDLER(EMC, EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2, emc_pmacro_ib_ddll_short_dq_rank1_byte7_2) \ HANDLER(EMC, EMC_PMACRO_IB_VREF_DQS_0, emc_pmacro_ib_vref_dqs_0) \ HANDLER(EMC, EMC_PMACRO_IB_VREF_DQS_1, emc_pmacro_ib_vref_dqs_1) \ HANDLER(EMC, EMC_PMACRO_IB_VREF_DQ_0, emc_pmacro_ib_vref_dq_0) \ HANDLER(EMC, EMC_PMACRO_IB_VREF_DQ_1, emc_pmacro_ib_vref_dq_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, emc_pmacro_ob_ddll_long_dq_rank0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, emc_pmacro_ob_ddll_long_dq_rank0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2, emc_pmacro_ob_ddll_long_dq_rank0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3, emc_pmacro_ob_ddll_long_dq_rank0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4, emc_pmacro_ob_ddll_long_dq_rank0_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5, emc_pmacro_ob_ddll_long_dq_rank0_5) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0, emc_pmacro_ob_ddll_long_dq_rank1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1, emc_pmacro_ob_ddll_long_dq_rank1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2, emc_pmacro_ob_ddll_long_dq_rank1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3, emc_pmacro_ob_ddll_long_dq_rank1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0, emc_pmacro_ob_ddll_short_dq_rank0_byte0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1, emc_pmacro_ob_ddll_short_dq_rank0_byte0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2, emc_pmacro_ob_ddll_short_dq_rank0_byte0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0, emc_pmacro_ob_ddll_short_dq_rank0_byte1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1, emc_pmacro_ob_ddll_short_dq_rank0_byte1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2, emc_pmacro_ob_ddll_short_dq_rank0_byte1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0, emc_pmacro_ob_ddll_short_dq_rank0_byte2_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1, emc_pmacro_ob_ddll_short_dq_rank0_byte2_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2, emc_pmacro_ob_ddll_short_dq_rank0_byte2_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0, emc_pmacro_ob_ddll_short_dq_rank0_byte3_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1, emc_pmacro_ob_ddll_short_dq_rank0_byte3_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2, emc_pmacro_ob_ddll_short_dq_rank0_byte3_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0, emc_pmacro_ob_ddll_short_dq_rank0_byte4_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1, emc_pmacro_ob_ddll_short_dq_rank0_byte4_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2, emc_pmacro_ob_ddll_short_dq_rank0_byte4_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0, emc_pmacro_ob_ddll_short_dq_rank0_byte5_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1, emc_pmacro_ob_ddll_short_dq_rank0_byte5_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2, emc_pmacro_ob_ddll_short_dq_rank0_byte5_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0, emc_pmacro_ob_ddll_short_dq_rank0_byte6_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1, emc_pmacro_ob_ddll_short_dq_rank0_byte6_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2, emc_pmacro_ob_ddll_short_dq_rank0_byte6_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0, emc_pmacro_ob_ddll_short_dq_rank0_byte7_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1, emc_pmacro_ob_ddll_short_dq_rank0_byte7_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2, emc_pmacro_ob_ddll_short_dq_rank0_byte7_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0, emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1, emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2, emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0, emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1, emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2, emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0, emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1, emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2, emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0, emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1, emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2, emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0, emc_pmacro_ob_ddll_short_dq_rank1_byte0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1, emc_pmacro_ob_ddll_short_dq_rank1_byte0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2, emc_pmacro_ob_ddll_short_dq_rank1_byte0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0, emc_pmacro_ob_ddll_short_dq_rank1_byte1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1, emc_pmacro_ob_ddll_short_dq_rank1_byte1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2, emc_pmacro_ob_ddll_short_dq_rank1_byte1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0, emc_pmacro_ob_ddll_short_dq_rank1_byte2_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1, emc_pmacro_ob_ddll_short_dq_rank1_byte2_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2, emc_pmacro_ob_ddll_short_dq_rank1_byte2_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0, emc_pmacro_ob_ddll_short_dq_rank1_byte3_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1, emc_pmacro_ob_ddll_short_dq_rank1_byte3_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2, emc_pmacro_ob_ddll_short_dq_rank1_byte3_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0, emc_pmacro_ob_ddll_short_dq_rank1_byte4_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1, emc_pmacro_ob_ddll_short_dq_rank1_byte4_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2, emc_pmacro_ob_ddll_short_dq_rank1_byte4_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0, emc_pmacro_ob_ddll_short_dq_rank1_byte5_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1, emc_pmacro_ob_ddll_short_dq_rank1_byte5_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2, emc_pmacro_ob_ddll_short_dq_rank1_byte5_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0, emc_pmacro_ob_ddll_short_dq_rank1_byte6_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1, emc_pmacro_ob_ddll_short_dq_rank1_byte6_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2, emc_pmacro_ob_ddll_short_dq_rank1_byte6_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0, emc_pmacro_ob_ddll_short_dq_rank1_byte7_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1, emc_pmacro_ob_ddll_short_dq_rank1_byte7_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2, emc_pmacro_ob_ddll_short_dq_rank1_byte7_2) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_0, emc_pmacro_quse_ddll_rank0_0) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_1, emc_pmacro_quse_ddll_rank0_1) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_2, emc_pmacro_quse_ddll_rank0_2) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_3, emc_pmacro_quse_ddll_rank0_3) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_0, emc_pmacro_quse_ddll_rank1_0) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_1, emc_pmacro_quse_ddll_rank1_1) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_2, emc_pmacro_quse_ddll_rank1_2) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_3, emc_pmacro_quse_ddll_rank1_3) #define FOREACH_PER_CHANNEL_TRIM_REG(HANDLER) \ HANDLER(EMC0, EMC_CMD_BRLSHFT_0, emc0_cmd_brlshft_0) \ HANDLER(EMC1, EMC_CMD_BRLSHFT_1, emc1_cmd_brlshft_1) \ HANDLER(EMC0, EMC_DATA_BRLSHFT_0, emc0_data_brlshft_0) \ HANDLER(EMC1, EMC_DATA_BRLSHFT_0, emc1_data_brlshft_0) \ HANDLER(EMC0, EMC_DATA_BRLSHFT_1, emc0_data_brlshft_1) \ HANDLER(EMC1, EMC_DATA_BRLSHFT_1, emc1_data_brlshft_1) \ HANDLER(EMC0, EMC_QUSE_BRLSHFT_0, emc0_quse_brlshft_0) \ HANDLER(EMC1, EMC_QUSE_BRLSHFT_1, emc1_quse_brlshft_1) \ HANDLER(EMC0, EMC_QUSE_BRLSHFT_2, emc0_quse_brlshft_2) \ HANDLER(EMC1, EMC_QUSE_BRLSHFT_3, emc1_quse_brlshft_3) #define FOREACH_PER_CHANNEL_VREF_REG(HANDLER) \ HANDLER(EMC0, EMC_TRAINING_OPT_DQS_IB_VREF_RANK0, emc0_training_opt_dqs_ib_vref_rank0) \ HANDLER(EMC1, EMC_TRAINING_OPT_DQS_IB_VREF_RANK0, emc1_training_opt_dqs_ib_vref_rank0) \ HANDLER(EMC0, EMC_TRAINING_OPT_DQS_IB_VREF_RANK1, emc0_training_opt_dqs_ib_vref_rank1) \ HANDLER(EMC1, EMC_TRAINING_OPT_DQS_IB_VREF_RANK1, emc1_training_opt_dqs_ib_vref_rank1) #define FOREACH_PER_CHANNEL_TRAINING_MOD_REG(HANDLER) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_IB_BYTE0, emc0_training_rw_offset_ib_byte0) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_IB_BYTE0, emc1_training_rw_offset_ib_byte0) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_IB_BYTE1, emc0_training_rw_offset_ib_byte1) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_IB_BYTE1, emc1_training_rw_offset_ib_byte1) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_IB_BYTE2, emc0_training_rw_offset_ib_byte2) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_IB_BYTE2, emc1_training_rw_offset_ib_byte2) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_IB_BYTE3, emc0_training_rw_offset_ib_byte3) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_IB_BYTE3, emc1_training_rw_offset_ib_byte3) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_IB_MISC, emc0_training_rw_offset_ib_misc) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_IB_MISC, emc1_training_rw_offset_ib_misc) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_OB_BYTE0, emc0_training_rw_offset_ob_byte0) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_OB_BYTE0, emc1_training_rw_offset_ob_byte0) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_OB_BYTE1, emc0_training_rw_offset_ob_byte1) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_OB_BYTE1, emc1_training_rw_offset_ob_byte1) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_OB_BYTE2, emc0_training_rw_offset_ob_byte2) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_OB_BYTE2, emc1_training_rw_offset_ob_byte2) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_OB_BYTE3, emc0_training_rw_offset_ob_byte3) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_OB_BYTE3, emc1_training_rw_offset_ob_byte3) \ HANDLER(EMC0, EMC_TRAINING_RW_OFFSET_OB_MISC, emc0_training_rw_offset_ob_misc) \ HANDLER(EMC1, EMC_TRAINING_RW_OFFSET_OB_MISC, emc1_training_rw_offset_ob_misc) #define FOREACH_BURST_MC_REG(HANDLER) \ HANDLER(MC, MC_EMEM_ARB_CFG, mc_emem_arb_cfg) \ HANDLER(MC, MC_EMEM_ARB_OUTSTANDING_REQ, mc_emem_arb_outstanding_req) \ HANDLER(MC, MC_EMEM_ARB_REFPB_HP_CTRL, mc_emem_arb_refpb_hp_ctrl) \ HANDLER(MC, MC_EMEM_ARB_REFPB_BANK_CTRL, mc_emem_arb_refpb_bank_ctrl) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RCD, mc_emem_arb_timing_rcd) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RP, mc_emem_arb_timing_rp) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RC, mc_emem_arb_timing_rc) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RAS, mc_emem_arb_timing_ras) \ HANDLER(MC, MC_EMEM_ARB_TIMING_FAW, mc_emem_arb_timing_faw) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RRD, mc_emem_arb_timing_rrd) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RAP2PRE, mc_emem_arb_timing_rap2pre) \ HANDLER(MC, MC_EMEM_ARB_TIMING_WAP2PRE, mc_emem_arb_timing_wap2pre) \ HANDLER(MC, MC_EMEM_ARB_TIMING_R2R, mc_emem_arb_timing_r2r) \ HANDLER(MC, MC_EMEM_ARB_TIMING_W2W, mc_emem_arb_timing_w2w) \ HANDLER(MC, MC_EMEM_ARB_TIMING_R2W, mc_emem_arb_timing_r2w) \ HANDLER(MC, MC_EMEM_ARB_TIMING_CCDMW, mc_emem_arb_timing_ccdmw) \ HANDLER(MC, MC_EMEM_ARB_TIMING_W2R, mc_emem_arb_timing_w2r) \ HANDLER(MC, MC_EMEM_ARB_TIMING_RFCPB, mc_emem_arb_timing_rfcpb) \ HANDLER(MC, MC_EMEM_ARB_DA_TURNS, mc_emem_arb_da_turns) \ HANDLER(MC, MC_EMEM_ARB_DA_COVERS, mc_emem_arb_da_covers) \ HANDLER(MC, MC_EMEM_ARB_MISC0, mc_emem_arb_misc0) \ HANDLER(MC, MC_EMEM_ARB_MISC1, mc_emem_arb_misc1) \ HANDLER(MC, MC_EMEM_ARB_MISC2, mc_emem_arb_misc2) \ HANDLER(MC, MC_EMEM_ARB_RING1_THROTTLE, mc_emem_arb_ring1_throttle) \ HANDLER(MC, MC_EMEM_ARB_DHYST_CTRL, mc_emem_arb_dhyst_ctrl) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0, mc_emem_arb_dhyst_timeout_util_0) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1, mc_emem_arb_dhyst_timeout_util_1) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2, mc_emem_arb_dhyst_timeout_util_2) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3, mc_emem_arb_dhyst_timeout_util_3) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4, mc_emem_arb_dhyst_timeout_util_4) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5, mc_emem_arb_dhyst_timeout_util_5) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6, mc_emem_arb_dhyst_timeout_util_6) \ HANDLER(MC, MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7, mc_emem_arb_dhyst_timeout_util_7) #define FOREACH_LA_SCALE_REG(HANDLER) \ HANDLER(MC, MC_MLL_MPCORER_PTSA_RATE, mc_mll_mpcorer_ptsa_rate) \ HANDLER(MC, MC_FTOP_PTSA_RATE, mc_ftop_ptsa_rate) \ HANDLER(MC, MC_PTSA_GRANT_DECREMENT, mc_ptsa_grant_decrement) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_XUSB_0, mc_latency_allowance_xusb_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_XUSB_1, mc_latency_allowance_xusb_1) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_TSEC_0, mc_latency_allowance_tsec_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_SDMMCA_0, mc_latency_allowance_sdmmca_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_SDMMCAA_0, mc_latency_allowance_sdmmcaa_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_SDMMC_0, mc_latency_allowance_sdmmc_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_SDMMCAB_0, mc_latency_allowance_sdmmcab_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_PPCS_0, mc_latency_allowance_ppcs_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_PPCS_1, mc_latency_allowance_ppcs_1) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_MPCORE_0, mc_latency_allowance_mpcore_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_HC_0, mc_latency_allowance_hc_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_HC_1, mc_latency_allowance_hc_1) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_AVPC_0, mc_latency_allowance_avpc_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_GPU_0, mc_latency_allowance_gpu_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_GPU2_0, mc_latency_allowance_gpu2_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_NVENC_0, mc_latency_allowance_nvenc_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_NVDEC_0, mc_latency_allowance_nvdec_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_VIC_0, mc_latency_allowance_vic_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_VI2_0, mc_latency_allowance_vi2_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_ISP2_0, mc_latency_allowance_isp2_0) \ HANDLER(MC, MC_LATENCY_ALLOWANCE_ISP2_1, mc_latency_allowance_isp2_1) #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE1_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE1_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE1_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE0_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE0_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0_OB_DDLL_LONG_DQ_RANK0_BYTE0_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE3_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE3_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE3_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE2_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE2_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1_OB_DDLL_LONG_DQ_RANK0_BYTE2_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE5_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE5_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE5_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE4_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE4_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2_OB_DDLL_LONG_DQ_RANK0_BYTE4_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE7_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE7_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE7_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE6_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE6_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3_OB_DDLL_LONG_DQ_RANK0_BYTE6_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE1_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE1_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE1_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE0_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE0_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0_OB_DDLL_LONG_DQ_RANK1_BYTE0_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE3_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE3_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE3_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE2_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE2_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1_OB_DDLL_LONG_DQ_RANK1_BYTE2_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE5_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE5_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE5_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE4_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE4_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2_OB_DDLL_LONG_DQ_RANK1_BYTE4_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE7_SHIFT \ 16 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE7_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE7_SHIFT #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE6_SHIFT \ 0 #define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE6_MASK \ 0x3ff << \ EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3_OB_DDLL_LONG_DQ_RANK1_BYTE6_SHIFT #define EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT 21 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT 18 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT 15 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT 12 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT 9 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT 6 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT 3 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT 0 #define EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT 21 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT 18 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT 15 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT 12 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT 9 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT 6 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT 3 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT) #define EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT 0 #define EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_MASK \ (0x7 << EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT) } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_timing_table_erista.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "fusee_mtc_timing_table_common.hpp" namespace ams::nxboot::erista { #define FOREACH_BURST_REG(HANDLER) \ HANDLER(EMC, EMC_RC, emc_rc) \ HANDLER(EMC, EMC_RFC, emc_rfc) \ HANDLER(EMC, EMC_RFCPB, emc_rfcpb) \ HANDLER(EMC, EMC_REFCTRL2, emc_refctrl2) \ HANDLER(EMC, EMC_RFC_SLR, emc_rfc_slr) \ HANDLER(EMC, EMC_RAS, emc_ras) \ HANDLER(EMC, EMC_RP, emc_rp) \ HANDLER(EMC, EMC_R2W, emc_r2w) \ HANDLER(EMC, EMC_W2R, emc_w2r) \ HANDLER(EMC, EMC_R2P, emc_r2p) \ HANDLER(EMC, EMC_W2P, emc_w2p) \ HANDLER(EMC, EMC_R2R, emc_r2r) \ HANDLER(EMC, EMC_TPPD, emc_tppd) \ HANDLER(EMC, EMC_CCDMW, emc_ccdmw) \ HANDLER(EMC, EMC_RD_RCD, emc_rd_rcd) \ HANDLER(EMC, EMC_WR_RCD, emc_wr_rcd) \ HANDLER(EMC, EMC_RRD, emc_rrd) \ HANDLER(EMC, EMC_REXT, emc_rext) \ HANDLER(EMC, EMC_WEXT, emc_wext) \ HANDLER(EMC, EMC_WDV_CHK, emc_wdv_chk) \ HANDLER(EMC, EMC_WDV, emc_wdv) \ HANDLER(EMC, EMC_WSV, emc_wsv) \ HANDLER(EMC, EMC_WEV, emc_wev) \ HANDLER(EMC, EMC_WDV_MASK, emc_wdv_mask) \ HANDLER(EMC, EMC_WS_DURATION, emc_ws_duration) \ HANDLER(EMC, EMC_WE_DURATION, emc_we_duration) \ HANDLER(EMC, EMC_QUSE, emc_quse) \ HANDLER(EMC, EMC_QUSE_WIDTH, emc_quse_width) \ HANDLER(EMC, EMC_IBDLY, emc_ibdly) \ HANDLER(EMC, EMC_OBDLY, emc_obdly) \ HANDLER(EMC, EMC_EINPUT, emc_einput) \ HANDLER(EMC, EMC_MRW6, emc_mrw6) \ HANDLER(EMC, EMC_EINPUT_DURATION, emc_einput_duration) \ HANDLER(EMC, EMC_PUTERM_EXTRA, emc_puterm_extra) \ HANDLER(EMC, EMC_PUTERM_WIDTH, emc_puterm_width) \ HANDLER(EMC, EMC_QRST, emc_qrst) \ HANDLER(EMC, EMC_QSAFE, emc_qsafe) \ HANDLER(EMC, EMC_RDV, emc_rdv) \ HANDLER(EMC, EMC_RDV_MASK, emc_rdv_mask) \ HANDLER(EMC, EMC_RDV_EARLY, emc_rdv_early) \ HANDLER(EMC, EMC_RDV_EARLY_MASK, emc_rdv_early_mask) \ HANDLER(EMC, EMC_REFRESH, emc_refresh) \ HANDLER(EMC, EMC_BURST_REFRESH_NUM, emc_burst_refresh_num) \ HANDLER(EMC, EMC_PRE_REFRESH_REQ_CNT, emc_pre_refresh_req_cnt) \ HANDLER(EMC, EMC_PDEX2WR, emc_pdex2wr) \ HANDLER(EMC, EMC_PDEX2RD, emc_pdex2rd) \ HANDLER(EMC, EMC_PCHG2PDEN, emc_pchg2pden) \ HANDLER(EMC, EMC_ACT2PDEN, emc_act2pden) \ HANDLER(EMC, EMC_AR2PDEN, emc_ar2pden) \ HANDLER(EMC, EMC_RW2PDEN, emc_rw2pden) \ HANDLER(EMC, EMC_CKE2PDEN, emc_cke2pden) \ HANDLER(EMC, EMC_PDEX2CKE, emc_pdex2cke) \ HANDLER(EMC, EMC_PDEX2MRR, emc_pdex2mrr) \ HANDLER(EMC, EMC_TXSR, emc_txsr) \ HANDLER(EMC, EMC_TXSRDLL, emc_txsrdll) \ HANDLER(EMC, EMC_TCKE, emc_tcke) \ HANDLER(EMC, EMC_TCKESR, emc_tckesr) \ HANDLER(EMC, EMC_TPD, emc_tpd) \ HANDLER(EMC, EMC_TFAW, emc_tfaw) \ HANDLER(EMC, EMC_TRPAB, emc_trpab) \ HANDLER(EMC, EMC_TCLKSTABLE, emc_tclkstable) \ HANDLER(EMC, EMC_TCLKSTOP, emc_tclkstop) \ HANDLER(EMC, EMC_MRW7, emc_mrw7) \ HANDLER(EMC, EMC_TREFBW, emc_trefbw) \ HANDLER(EMC, EMC_ODT_WRITE, emc_odt_write) \ HANDLER(EMC, EMC_FBIO_CFG5, emc_fbio_cfg5) \ HANDLER(EMC, EMC_FBIO_CFG7, emc_fbio_cfg7) \ HANDLER(EMC, EMC_CFG_DIG_DLL, emc_cfg_dig_dll) \ HANDLER(EMC, EMC_CFG_DIG_DLL_PERIOD, emc_cfg_dig_dll_period) \ HANDLER(EMC, EMC_PMACRO_IB_RXRT, emc_pmacro_ib_rxrt) \ HANDLER(EMC, EMC_CFG_PIPE_1, emc_cfg_pipe_1) \ HANDLER(EMC, EMC_CFG_PIPE_2, emc_cfg_pipe_2) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_4, emc_pmacro_quse_ddll_rank0_4) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_5, emc_pmacro_quse_ddll_rank0_5) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_4, emc_pmacro_quse_ddll_rank1_4) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_5, emc_pmacro_quse_ddll_rank1_5) \ HANDLER(EMC, EMC_MRW8, emc_mrw8) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4, emc_pmacro_ob_ddll_long_dq_rank1_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5, emc_pmacro_ob_ddll_long_dq_rank1_5) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0, emc_pmacro_ob_ddll_long_dqs_rank0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1, emc_pmacro_ob_ddll_long_dqs_rank0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2, emc_pmacro_ob_ddll_long_dqs_rank0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3, emc_pmacro_ob_ddll_long_dqs_rank0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4, emc_pmacro_ob_ddll_long_dqs_rank0_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5, emc_pmacro_ob_ddll_long_dqs_rank0_5) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0, emc_pmacro_ob_ddll_long_dqs_rank1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1, emc_pmacro_ob_ddll_long_dqs_rank1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2, emc_pmacro_ob_ddll_long_dqs_rank1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3, emc_pmacro_ob_ddll_long_dqs_rank1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4, emc_pmacro_ob_ddll_long_dqs_rank1_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5, emc_pmacro_ob_ddll_long_dqs_rank1_5) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_0, emc_pmacro_ddll_long_cmd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_1, emc_pmacro_ddll_long_cmd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_2, emc_pmacro_ddll_long_cmd_2) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_3, emc_pmacro_ddll_long_cmd_3) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_4, emc_pmacro_ddll_long_cmd_4) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_0, emc_pmacro_ddll_short_cmd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_1, emc_pmacro_ddll_short_cmd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_2, emc_pmacro_ddll_short_cmd_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3, emc_pmacro_ob_ddll_short_dq_rank0_byte0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3, emc_pmacro_ob_ddll_short_dq_rank0_byte1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3, emc_pmacro_ob_ddll_short_dq_rank0_byte2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3, emc_pmacro_ob_ddll_short_dq_rank0_byte3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3, emc_pmacro_ob_ddll_short_dq_rank0_byte4_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3, emc_pmacro_ob_ddll_short_dq_rank0_byte5_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3, emc_pmacro_ob_ddll_short_dq_rank0_byte6_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3, emc_pmacro_ob_ddll_short_dq_rank0_byte7_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3, emc_pmacro_ob_ddll_short_dq_rank1_byte0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3, emc_pmacro_ob_ddll_short_dq_rank1_byte1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3, emc_pmacro_ob_ddll_short_dq_rank1_byte2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3, emc_pmacro_ob_ddll_short_dq_rank1_byte3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3, emc_pmacro_ob_ddll_short_dq_rank1_byte4_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3, emc_pmacro_ob_ddll_short_dq_rank1_byte5_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3, emc_pmacro_ob_ddll_short_dq_rank1_byte6_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3, emc_pmacro_ob_ddll_short_dq_rank1_byte7_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3) \ HANDLER(EMC, EMC_TXDSRVTTGEN, emc_txdsrvttgen) \ HANDLER(EMC, EMC_FDPD_CTRL_DQ, emc_fdpd_ctrl_dq) \ HANDLER(EMC, EMC_FDPD_CTRL_CMD, emc_fdpd_ctrl_cmd) \ HANDLER(EMC, EMC_FBIO_SPARE, emc_fbio_spare) \ HANDLER(EMC, EMC_ZCAL_INTERVAL, emc_zcal_interval) \ HANDLER(EMC, EMC_ZCAL_WAIT_CNT, emc_zcal_wait_cnt) \ HANDLER(EMC, EMC_MRS_WAIT_CNT, emc_mrs_wait_cnt) \ HANDLER(EMC, EMC_MRS_WAIT_CNT2, emc_mrs_wait_cnt2) \ HANDLER(EMC, EMC_AUTO_CAL_CHANNEL, emc_auto_cal_channel) \ HANDLER(EMC, EMC_DLL_CFG_0, emc_dll_cfg_0) \ HANDLER(EMC, EMC_DLL_CFG_1, emc_dll_cfg_1) \ HANDLER(EMC, EMC_PMACRO_AUTOCAL_CFG_COMMON, emc_pmacro_autocal_cfg_common) \ HANDLER(EMC, EMC_PMACRO_ZCTRL, emc_pmacro_zctrl) \ HANDLER(EMC, EMC_CFG, emc_cfg) \ HANDLER(EMC, EMC_CFG_PIPE, emc_cfg_pipe) \ HANDLER(EMC, EMC_DYN_SELF_REF_CONTROL, emc_dyn_self_ref_control) \ HANDLER(EMC, EMC_QPOP, emc_qpop) \ HANDLER(EMC, EMC_DQS_BRLSHFT_0, emc_dqs_brlshft_0) \ HANDLER(EMC, EMC_DQS_BRLSHFT_1, emc_dqs_brlshft_1) \ HANDLER(EMC, EMC_CMD_BRLSHFT_2, emc_cmd_brlshft_2) \ HANDLER(EMC, EMC_CMD_BRLSHFT_3, emc_cmd_brlshft_3) \ HANDLER(EMC, EMC_PMACRO_PAD_CFG_CTRL, emc_pmacro_pad_cfg_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_PAD_RX_CTRL, emc_pmacro_data_pad_rx_ctrl) \ HANDLER(EMC, EMC_PMACRO_CMD_PAD_RX_CTRL, emc_pmacro_cmd_pad_rx_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_RX_TERM_MODE, emc_pmacro_data_rx_term_mode) \ HANDLER(EMC, EMC_PMACRO_CMD_RX_TERM_MODE, emc_pmacro_cmd_rx_term_mode) \ HANDLER(EMC, EMC_PMACRO_CMD_PAD_TX_CTRL, emc_pmacro_cmd_pad_tx_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_PAD_TX_CTRL, emc_pmacro_data_pad_tx_ctrl) \ HANDLER(EMC, EMC_PMACRO_COMMON_PAD_TX_CTRL, emc_pmacro_common_pad_tx_ctrl) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_0, emc_pmacro_vttgen_ctrl_0) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_1, emc_pmacro_vttgen_ctrl_1) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_2, emc_pmacro_vttgen_ctrl_2) \ HANDLER(EMC, EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1) \ HANDLER(EMC, EMC_PMACRO_CMD_BRICK_CTRL_FDPD, emc_pmacro_cmd_brick_ctrl_fdpd) \ HANDLER(EMC, EMC_PMACRO_BRICK_CTRL_RFU2, emc_pmacro_brick_ctrl_rfu2) \ HANDLER(EMC, EMC_PMACRO_DATA_BRICK_CTRL_FDPD, emc_pmacro_data_brick_ctrl_fdpd) \ HANDLER(EMC, EMC_PMACRO_BG_BIAS_CTRL_0, emc_pmacro_bg_bias_ctrl_0) \ HANDLER(EMC, EMC_CFG_3, emc_cfg_3) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_0, emc_pmacro_tx_pwrd_0) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_1, emc_pmacro_tx_pwrd_1) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_2, emc_pmacro_tx_pwrd_2) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_3, emc_pmacro_tx_pwrd_3) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_4, emc_pmacro_tx_pwrd_4) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_5, emc_pmacro_tx_pwrd_5) \ HANDLER(EMC, EMC_CONFIG_SAMPLE_DELAY, emc_config_sample_delay) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_0, emc_pmacro_tx_sel_clk_src_0) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_1, emc_pmacro_tx_sel_clk_src_1) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_2, emc_pmacro_tx_sel_clk_src_2) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_3, emc_pmacro_tx_sel_clk_src_3) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_4, emc_pmacro_tx_sel_clk_src_4) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_5, emc_pmacro_tx_sel_clk_src_5) \ HANDLER(EMC, EMC_PMACRO_DDLL_BYPASS, emc_pmacro_ddll_bypass) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_0, emc_pmacro_ddll_pwrd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_1, emc_pmacro_ddll_pwrd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_2, emc_pmacro_ddll_pwrd_2) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_0, emc_pmacro_cmd_ctrl_0) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_1, emc_pmacro_cmd_ctrl_1) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_2, emc_pmacro_cmd_ctrl_2) \ HANDLER(EMC, EMC_TR_TIMING_0, emc_tr_timing_0) \ HANDLER(EMC, EMC_TR_DVFS, emc_tr_dvfs) \ HANDLER(EMC, EMC_TR_CTRL_1, emc_tr_ctrl_1) \ HANDLER(EMC, EMC_TR_RDV, emc_tr_rdv) \ HANDLER(EMC, EMC_TR_QPOP, emc_tr_qpop) \ HANDLER(EMC, EMC_TR_RDV_MASK, emc_tr_rdv_mask) \ HANDLER(EMC, EMC_MRW14, emc_mrw14) \ HANDLER(EMC, EMC_TR_QSAFE, emc_tr_qsafe) \ HANDLER(EMC, EMC_TR_QRST, emc_tr_qrst) \ HANDLER(EMC, EMC_TRAINING_CTRL, emc_training_ctrl) \ HANDLER(EMC, EMC_TRAINING_SETTLE, emc_training_settle) \ HANDLER(EMC, EMC_TRAINING_VREF_SETTLE, emc_training_vref_settle) \ HANDLER(EMC, EMC_TRAINING_CA_FINE_CTRL, emc_training_ca_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_CA_CTRL_MISC, emc_training_ca_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_CA_CTRL_MISC1, emc_training_ca_ctrl_misc1) \ HANDLER(EMC, EMC_TRAINING_CA_VREF_CTRL, emc_training_ca_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_CORS_CTRL, emc_training_quse_cors_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_FINE_CTRL, emc_training_quse_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_CTRL_MISC, emc_training_quse_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_QUSE_VREF_CTRL, emc_training_quse_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_READ_FINE_CTRL, emc_training_read_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_READ_CTRL_MISC, emc_training_read_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_READ_VREF_CTRL, emc_training_read_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_WRITE_FINE_CTRL, emc_training_write_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_WRITE_CTRL_MISC, emc_training_write_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_WRITE_VREF_CTRL, emc_training_write_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_MPC, emc_training_mpc) \ HANDLER(EMC, EMC_MRW15, emc_mrw15) #define DECLARE_STRUCT_MEMBER_HANDLER(BASE, REG, NAME) uint32_t NAME; #define DECLARE_ARRAY_AND_STRUCT_MEMBERS(NAME, FOREACH_HANDLER) \ union { struct { FOREACH_HANDLER(DECLARE_STRUCT_MEMBER_HANDLER) } NAME; uint32_t NAME##_arr[sizeof(NAME) / sizeof(uint32_t)]; } struct EmcDvfsTimingTable { uint32_t rev; char dvfs_ver[60]; uint32_t rate_khz; uint32_t min_volt; uint32_t gpu_min_volt; char clock_src[32]; uint32_t clk_src_emc; uint32_t needs_training; uint32_t training_pattern; uint32_t trained; uint32_t periodic_training; uint32_t trained_dram_clktree_c0d0u0; uint32_t trained_dram_clktree_c0d0u1; uint32_t trained_dram_clktree_c0d1u0; uint32_t trained_dram_clktree_c0d1u1; uint32_t trained_dram_clktree_c1d0u0; uint32_t trained_dram_clktree_c1d0u1; uint32_t trained_dram_clktree_c1d1u0; uint32_t trained_dram_clktree_c1d1u1; uint32_t current_dram_clktree_c0d0u0; uint32_t current_dram_clktree_c0d0u1; uint32_t current_dram_clktree_c0d1u0; uint32_t current_dram_clktree_c0d1u1; uint32_t current_dram_clktree_c1d0u0; uint32_t current_dram_clktree_c1d0u1; uint32_t current_dram_clktree_c1d1u0; uint32_t current_dram_clktree_c1d1u1; uint32_t run_clocks; uint32_t tree_margin; uint32_t num_burst; uint32_t num_burst_per_ch; uint32_t num_trim; uint32_t num_trim_per_ch; uint32_t num_mc_regs; uint32_t num_up_down; uint32_t vref_num; uint32_t training_mod_num; uint32_t dram_timing_num; uint32_t ptfv_dqsosc_movavg_c0d0u0; uint32_t ptfv_dqsosc_movavg_c0d0u1; uint32_t ptfv_dqsosc_movavg_c0d1u0; uint32_t ptfv_dqsosc_movavg_c0d1u1; uint32_t ptfv_dqsosc_movavg_c1d0u0; uint32_t ptfv_dqsosc_movavg_c1d0u1; uint32_t ptfv_dqsosc_movavg_c1d1u0; uint32_t ptfv_dqsosc_movavg_c1d1u1; uint32_t ptfv_write_samples; uint32_t ptfv_dvfs_samples; uint32_t ptfv_movavg_weight; uint32_t ptfv_config_ctrl; DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_regs, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_perch_regs, FOREACH_PER_CHANNEL_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(shadow_regs_ca_train, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(shadow_regs_quse_train, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(shadow_regs_rdwr_train, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(trim_regs, FOREACH_TRIM_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(trim_perch_regs, FOREACH_PER_CHANNEL_TRIM_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(vref_perch_regs, FOREACH_PER_CHANNEL_VREF_REG); struct { uint32_t t_rp; uint32_t t_fc_lpddr4; uint32_t t_rfc; uint32_t t_pdex; uint32_t rl; } dram_timings; DECLARE_ARRAY_AND_STRUCT_MEMBERS(training_mod_regs, FOREACH_PER_CHANNEL_TRAINING_MOD_REG); uint32_t save_restore_mod_regs[12]; DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_mc_regs, FOREACH_BURST_MC_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(la_scale_regs, FOREACH_LA_SCALE_REG); uint32_t min_mrs_wait; uint32_t emc_mrw; uint32_t emc_mrw2; uint32_t emc_mrw3; uint32_t emc_mrw4; uint32_t emc_mrw9; uint32_t emc_mrs; uint32_t emc_emrs; uint32_t emc_emrs2; uint32_t emc_auto_cal_config; uint32_t emc_auto_cal_config2; uint32_t emc_auto_cal_config3; uint32_t emc_auto_cal_config4; uint32_t emc_auto_cal_config5; uint32_t emc_auto_cal_config6; uint32_t emc_auto_cal_config7; uint32_t emc_auto_cal_config8; uint32_t emc_cfg_2; uint32_t emc_sel_dpd_ctrl; uint32_t emc_fdpd_ctrl_cmd_no_ramp; uint32_t dll_clk_src; uint32_t clk_out_enb_x_0_clk_enb_emc_dll; uint32_t latency; }; #undef DECLARE_STRUCT_MEMBER_HANDLER #undef DECLARE_ARRAY_AND_STRUCT_MEMBERS static_assert(sizeof(EmcDvfsTimingTable) == 0x1340); } ================================================ FILE: fusee/program/source/mtc/fusee_mtc_timing_table_mariko.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <exosphere.hpp> #include "fusee_mtc_timing_table_common.hpp" namespace ams::nxboot::mariko { #define FOREACH_BURST_REG(HANDLER) \ HANDLER(EMC, EMC_RC, emc_rc) \ HANDLER(EMC, EMC_RFC, emc_rfc) \ HANDLER(EMC, EMC_RFCPB, emc_rfcpb) \ HANDLER(EMC, EMC_REFCTRL2, emc_refctrl2) \ HANDLER(EMC, EMC_RFC_SLR, emc_rfc_slr) \ HANDLER(EMC, EMC_RAS, emc_ras) \ HANDLER(EMC, EMC_RP, emc_rp) \ HANDLER(EMC, EMC_R2W, emc_r2w) \ HANDLER(EMC, EMC_W2R, emc_w2r) \ HANDLER(EMC, EMC_R2P, emc_r2p) \ HANDLER(EMC, EMC_W2P, emc_w2p) \ HANDLER(EMC, EMC_R2R, emc_r2r) \ HANDLER(EMC, EMC_TPPD, emc_tppd) \ HANDLER(EMC, EMC_TRTM, emc_trtm) \ HANDLER(EMC, EMC_TWTM, emc_twtm) \ HANDLER(EMC, EMC_TRATM, emc_tratm) \ HANDLER(EMC, EMC_TWATM, emc_twatm) \ HANDLER(EMC, EMC_TR2REF, emc_tr2ref) \ HANDLER(EMC, EMC_CCDMW, emc_ccdmw) \ HANDLER(EMC, EMC_RD_RCD, emc_rd_rcd) \ HANDLER(EMC, EMC_WR_RCD, emc_wr_rcd) \ HANDLER(EMC, EMC_RRD, emc_rrd) \ HANDLER(EMC, EMC_REXT, emc_rext) \ HANDLER(EMC, EMC_WEXT, emc_wext) \ HANDLER(EMC, EMC_WDV_CHK, emc_wdv_chk) \ HANDLER(EMC, EMC_WDV, emc_wdv) \ HANDLER(EMC, EMC_WSV, emc_wsv) \ HANDLER(EMC, EMC_WEV, emc_wev) \ HANDLER(EMC, EMC_WDV_MASK, emc_wdv_mask) \ HANDLER(EMC, EMC_WS_DURATION, emc_ws_duration) \ HANDLER(EMC, EMC_WE_DURATION, emc_we_duration) \ HANDLER(EMC, EMC_QUSE, emc_quse) \ HANDLER(EMC, EMC_QUSE_WIDTH, emc_quse_width) \ HANDLER(EMC, EMC_IBDLY, emc_ibdly) \ HANDLER(EMC, EMC_OBDLY, emc_obdly) \ HANDLER(EMC, EMC_EINPUT, emc_einput) \ HANDLER(EMC, EMC_MRW6, emc_mrw6) \ HANDLER(EMC, EMC_EINPUT_DURATION, emc_einput_duration) \ HANDLER(EMC, EMC_PUTERM_EXTRA, emc_puterm_extra) \ HANDLER(EMC, EMC_PUTERM_WIDTH, emc_puterm_width) \ HANDLER(EMC, EMC_QRST, emc_qrst) \ HANDLER(EMC, EMC_QSAFE, emc_qsafe) \ HANDLER(EMC, EMC_RDV, emc_rdv) \ HANDLER(EMC, EMC_RDV_MASK, emc_rdv_mask) \ HANDLER(EMC, EMC_RDV_EARLY, emc_rdv_early) \ HANDLER(EMC, EMC_RDV_EARLY_MASK, emc_rdv_early_mask) \ HANDLER(EMC, EMC_REFRESH, emc_refresh) \ HANDLER(EMC, EMC_BURST_REFRESH_NUM, emc_burst_refresh_num) \ HANDLER(EMC, EMC_PRE_REFRESH_REQ_CNT, emc_pre_refresh_req_cnt) \ HANDLER(EMC, EMC_PDEX2WR, emc_pdex2wr) \ HANDLER(EMC, EMC_PDEX2RD, emc_pdex2rd) \ HANDLER(EMC, EMC_PCHG2PDEN, emc_pchg2pden) \ HANDLER(EMC, EMC_ACT2PDEN, emc_act2pden) \ HANDLER(EMC, EMC_AR2PDEN, emc_ar2pden) \ HANDLER(EMC, EMC_RW2PDEN, emc_rw2pden) \ HANDLER(EMC, EMC_CKE2PDEN, emc_cke2pden) \ HANDLER(EMC, EMC_PDEX2CKE, emc_pdex2cke) \ HANDLER(EMC, EMC_PDEX2MRR, emc_pdex2mrr) \ HANDLER(EMC, EMC_TXSR, emc_txsr) \ HANDLER(EMC, EMC_TXSRDLL, emc_txsrdll) \ HANDLER(EMC, EMC_TCKE, emc_tcke) \ HANDLER(EMC, EMC_TCKESR, emc_tckesr) \ HANDLER(EMC, EMC_TPD, emc_tpd) \ HANDLER(EMC, EMC_TFAW, emc_tfaw) \ HANDLER(EMC, EMC_TRPAB, emc_trpab) \ HANDLER(EMC, EMC_TCLKSTABLE, emc_tclkstable) \ HANDLER(EMC, EMC_TCLKSTOP, emc_tclkstop) \ HANDLER(EMC, EMC_MRW7, emc_mrw7) \ HANDLER(EMC, EMC_TREFBW, emc_trefbw) \ HANDLER(EMC, EMC_ODT_WRITE, emc_odt_write) \ HANDLER(EMC, EMC_FBIO_CFG5, emc_fbio_cfg5) \ HANDLER(EMC, EMC_FBIO_CFG7, emc_fbio_cfg7) \ HANDLER(EMC, EMC_CFG_DIG_DLL, emc_cfg_dig_dll) \ HANDLER(EMC, EMC_CFG_DIG_DLL_PERIOD, emc_cfg_dig_dll_period) \ HANDLER(EMC, EMC_PMACRO_IB_RXRT, emc_pmacro_ib_rxrt) \ HANDLER(EMC, EMC_CFG_PIPE_1, emc_cfg_pipe_1) \ HANDLER(EMC, EMC_CFG_PIPE_2, emc_cfg_pipe_2) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_4, emc_pmacro_quse_ddll_rank0_4) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK0_5, emc_pmacro_quse_ddll_rank0_5) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_4, emc_pmacro_quse_ddll_rank1_4) \ HANDLER(EMC, EMC_PMACRO_QUSE_DDLL_RANK1_5, emc_pmacro_quse_ddll_rank1_5) \ HANDLER(EMC, EMC_MRW8, emc_mrw8) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4, emc_pmacro_ob_ddll_long_dq_rank1_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5, emc_pmacro_ob_ddll_long_dq_rank1_5) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0, emc_pmacro_ob_ddll_long_dqs_rank0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1, emc_pmacro_ob_ddll_long_dqs_rank0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2, emc_pmacro_ob_ddll_long_dqs_rank0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3, emc_pmacro_ob_ddll_long_dqs_rank0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4, emc_pmacro_ob_ddll_long_dqs_rank0_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5, emc_pmacro_ob_ddll_long_dqs_rank0_5) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0, emc_pmacro_ob_ddll_long_dqs_rank1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1, emc_pmacro_ob_ddll_long_dqs_rank1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2, emc_pmacro_ob_ddll_long_dqs_rank1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3, emc_pmacro_ob_ddll_long_dqs_rank1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4, emc_pmacro_ob_ddll_long_dqs_rank1_4) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5, emc_pmacro_ob_ddll_long_dqs_rank1_5) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_0, emc_pmacro_ddll_long_cmd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_1, emc_pmacro_ddll_long_cmd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_2, emc_pmacro_ddll_long_cmd_2) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_3, emc_pmacro_ddll_long_cmd_3) \ HANDLER(EMC, EMC_PMACRO_DDLL_LONG_CMD_4, emc_pmacro_ddll_long_cmd_4) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_0, emc_pmacro_ddll_short_cmd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_1, emc_pmacro_ddll_short_cmd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_SHORT_CMD_2, emc_pmacro_ddll_short_cmd_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3, emc_pmacro_ob_ddll_short_dq_rank0_byte0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3, emc_pmacro_ob_ddll_short_dq_rank0_byte1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3, emc_pmacro_ob_ddll_short_dq_rank0_byte2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3, emc_pmacro_ob_ddll_short_dq_rank0_byte3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3, emc_pmacro_ob_ddll_short_dq_rank0_byte4_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3, emc_pmacro_ob_ddll_short_dq_rank0_byte5_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3, emc_pmacro_ob_ddll_short_dq_rank0_byte6_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3, emc_pmacro_ob_ddll_short_dq_rank0_byte7_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3, emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3, emc_pmacro_ob_ddll_short_dq_rank1_byte0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3, emc_pmacro_ob_ddll_short_dq_rank1_byte1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3, emc_pmacro_ob_ddll_short_dq_rank1_byte2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3, emc_pmacro_ob_ddll_short_dq_rank1_byte3_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3, emc_pmacro_ob_ddll_short_dq_rank1_byte4_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3, emc_pmacro_ob_ddll_short_dq_rank1_byte5_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3, emc_pmacro_ob_ddll_short_dq_rank1_byte6_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3, emc_pmacro_ob_ddll_short_dq_rank1_byte7_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2) \ HANDLER(EMC, EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3, emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3) \ HANDLER(EMC, EMC_TXDSRVTTGEN, emc_txdsrvttgen) \ HANDLER(EMC, EMC_FDPD_CTRL_DQ, emc_fdpd_ctrl_dq) \ HANDLER(EMC, EMC_FDPD_CTRL_CMD, emc_fdpd_ctrl_cmd) \ HANDLER(EMC, EMC_FBIO_SPARE, emc_fbio_spare) \ HANDLER(EMC, EMC_ZCAL_INTERVAL, emc_zcal_interval) \ HANDLER(EMC, EMC_ZCAL_WAIT_CNT, emc_zcal_wait_cnt) \ HANDLER(EMC, EMC_MRS_WAIT_CNT, emc_mrs_wait_cnt) \ HANDLER(EMC, EMC_MRS_WAIT_CNT2, emc_mrs_wait_cnt2) \ HANDLER(EMC, EMC_AUTO_CAL_CHANNEL, emc_auto_cal_channel) \ HANDLER(EMC, EMC_PMACRO_DLL_CFG_0, emc_pmacro_dll_cfg_0) \ HANDLER(EMC, EMC_PMACRO_DLL_CFG_1, emc_pmacro_dll_cfg_1) \ HANDLER(EMC, EMC_PMACRO_DLL_CFG_2, emc_pmacro_dll_cfg_2) \ HANDLER(EMC, EMC_PMACRO_AUTOCAL_CFG_COMMON, emc_pmacro_autocal_cfg_common) \ HANDLER(EMC, EMC_PMACRO_ZCTRL, emc_pmacro_zctrl) \ HANDLER(EMC, EMC_CFG, emc_cfg) \ HANDLER(EMC, EMC_CFG_PIPE, emc_cfg_pipe) \ HANDLER(EMC, EMC_DYN_SELF_REF_CONTROL, emc_dyn_self_ref_control) \ HANDLER(EMC, EMC_QPOP, emc_qpop) \ HANDLER(EMC, EMC_DQS_BRLSHFT_0, emc_dqs_brlshft_0) \ HANDLER(EMC, EMC_DQS_BRLSHFT_1, emc_dqs_brlshft_1) \ HANDLER(EMC, EMC_CMD_BRLSHFT_2, emc_cmd_brlshft_2) \ HANDLER(EMC, EMC_CMD_BRLSHFT_3, emc_cmd_brlshft_3) \ HANDLER(EMC, EMC_PMACRO_PAD_CFG_CTRL, emc_pmacro_pad_cfg_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_PAD_RX_CTRL, emc_pmacro_data_pad_rx_ctrl) \ HANDLER(EMC, EMC_PMACRO_CMD_PAD_RX_CTRL, emc_pmacro_cmd_pad_rx_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_RX_TERM_MODE, emc_pmacro_data_rx_term_mode) \ HANDLER(EMC, EMC_PMACRO_CMD_RX_TERM_MODE, emc_pmacro_cmd_rx_term_mode) \ HANDLER(EMC, EMC_PMACRO_CMD_PAD_TX_CTRL, emc_pmacro_cmd_pad_tx_ctrl) \ HANDLER(EMC, EMC_PMACRO_DATA_PAD_TX_CTRL, emc_pmacro_data_pad_tx_ctrl) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_0, emc_pmacro_vttgen_ctrl_0) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_1, emc_pmacro_vttgen_ctrl_1) \ HANDLER(EMC, EMC_PMACRO_VTTGEN_CTRL_2, emc_pmacro_vttgen_ctrl_2) \ HANDLER(EMC, EMC_PMACRO_BRICK_CTRL_RFU1, emc_pmacro_brick_ctrl_rfu1) \ HANDLER(EMC, EMC_PMACRO_CMD_BRICK_CTRL_FDPD, emc_pmacro_cmd_brick_ctrl_fdpd) \ HANDLER(EMC, EMC_PMACRO_BRICK_CTRL_RFU2, emc_pmacro_brick_ctrl_rfu2) \ HANDLER(EMC, EMC_PMACRO_DATA_BRICK_CTRL_FDPD, emc_pmacro_data_brick_ctrl_fdpd) \ HANDLER(EMC, EMC_PMACRO_BG_BIAS_CTRL_0, emc_pmacro_bg_bias_ctrl_0) \ HANDLER(EMC, EMC_CFG_3, emc_cfg_3) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_0, emc_pmacro_tx_pwrd_0) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_1, emc_pmacro_tx_pwrd_1) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_2, emc_pmacro_tx_pwrd_2) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_3, emc_pmacro_tx_pwrd_3) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_4, emc_pmacro_tx_pwrd_4) \ HANDLER(EMC, EMC_PMACRO_TX_PWRD_5, emc_pmacro_tx_pwrd_5) \ HANDLER(EMC, EMC_CONFIG_SAMPLE_DELAY, emc_config_sample_delay) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_0, emc_pmacro_tx_sel_clk_src_0) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_1, emc_pmacro_tx_sel_clk_src_1) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_2, emc_pmacro_tx_sel_clk_src_2) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_3, emc_pmacro_tx_sel_clk_src_3) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_4, emc_pmacro_tx_sel_clk_src_4) \ HANDLER(EMC, EMC_PMACRO_TX_SEL_CLK_SRC_5, emc_pmacro_tx_sel_clk_src_5) \ HANDLER(EMC, EMC_PMACRO_DDLL_BYPASS, emc_pmacro_ddll_bypass) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_0, emc_pmacro_ddll_pwrd_0) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_1, emc_pmacro_ddll_pwrd_1) \ HANDLER(EMC, EMC_PMACRO_DDLL_PWRD_2, emc_pmacro_ddll_pwrd_2) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_0, emc_pmacro_cmd_ctrl_0) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_1, emc_pmacro_cmd_ctrl_1) \ HANDLER(EMC, EMC_PMACRO_CMD_CTRL_2, emc_pmacro_cmd_ctrl_2) \ HANDLER(EMC, EMC_PMACRO_DATA_PI_CTRL, emc_pmacro_data_pi_ctrl) \ HANDLER(EMC, EMC_PMACRO_CMD_PI_CTRL, emc_pmacro_cmd_pi_ctrl) \ HANDLER(EMC, EMC_TR_TIMING_0, emc_tr_timing_0) \ HANDLER(EMC, EMC_TR_DVFS, emc_tr_dvfs) \ HANDLER(EMC, EMC_TR_CTRL_1, emc_tr_ctrl_1) \ HANDLER(EMC, EMC_TR_RDV, emc_tr_rdv) \ HANDLER(EMC, EMC_TR_QPOP, emc_tr_qpop) \ HANDLER(EMC, EMC_TR_RDV_MASK, emc_tr_rdv_mask) \ HANDLER(EMC, EMC_MRW14, emc_mrw14) \ HANDLER(EMC, EMC_TR_QSAFE, emc_tr_qsafe) \ HANDLER(EMC, EMC_TR_QRST, emc_tr_qrst) \ HANDLER(EMC, EMC_TRAINING_CTRL, emc_training_ctrl) \ HANDLER(EMC, EMC_TRAINING_SETTLE, emc_training_settle) \ HANDLER(EMC, EMC_TRAINING_VREF_SETTLE, emc_training_vref_settle) \ HANDLER(EMC, EMC_TRAINING_CA_FINE_CTRL, emc_training_ca_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_CA_CTRL_MISC, emc_training_ca_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_CA_CTRL_MISC1, emc_training_ca_ctrl_misc1) \ HANDLER(EMC, EMC_TRAINING_CA_VREF_CTRL, emc_training_ca_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_CORS_CTRL, emc_training_quse_cors_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_FINE_CTRL, emc_training_quse_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_QUSE_CTRL_MISC, emc_training_quse_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_QUSE_VREF_CTRL, emc_training_quse_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_READ_FINE_CTRL, emc_training_read_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_READ_CTRL_MISC, emc_training_read_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_READ_VREF_CTRL, emc_training_read_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_WRITE_FINE_CTRL, emc_training_write_fine_ctrl) \ HANDLER(EMC, EMC_TRAINING_WRITE_CTRL_MISC, emc_training_write_ctrl_misc) \ HANDLER(EMC, EMC_TRAINING_WRITE_VREF_CTRL, emc_training_write_vref_ctrl) \ HANDLER(EMC, EMC_TRAINING_MPC, emc_training_mpc) \ HANDLER(EMC, EMC_MRW15, emc_mrw15) #define DECLARE_STRUCT_MEMBER_HANDLER(BASE, REG, NAME) uint32_t NAME; #define DECLARE_ARRAY_AND_STRUCT_MEMBERS(NAME, FOREACH_HANDLER) \ union { struct { FOREACH_HANDLER(DECLARE_STRUCT_MEMBER_HANDLER) } NAME; uint32_t NAME##_arr[sizeof(NAME) / sizeof(uint32_t)]; } struct EmcDvfsTimingTable { uint32_t rev; char dvfs_ver[60]; uint32_t rate_khz; uint32_t min_volt; uint32_t gpu_min_volt; char clock_src[32]; uint32_t clk_src_emc; uint32_t pll_en_ssc; uint32_t needs_training; uint32_t training_pattern; uint32_t trained; uint32_t periodic_training; uint32_t trained_dram_clktree_c0d0u0; uint32_t trained_dram_clktree_c0d0u1; uint32_t trained_dram_clktree_c0d1u0; uint32_t trained_dram_clktree_c0d1u1; uint32_t trained_dram_clktree_c1d0u0; uint32_t trained_dram_clktree_c1d0u1; uint32_t trained_dram_clktree_c1d1u0; uint32_t trained_dram_clktree_c1d1u1; uint32_t current_dram_clktree_c0d0u0; uint32_t current_dram_clktree_c0d0u1; uint32_t current_dram_clktree_c0d1u0; uint32_t current_dram_clktree_c0d1u1; uint32_t current_dram_clktree_c1d0u0; uint32_t current_dram_clktree_c1d0u1; uint32_t current_dram_clktree_c1d1u0; uint32_t current_dram_clktree_c1d1u1; uint32_t emc_fbio_cfg7; uint32_t run_clocks; uint32_t tree_margin; uint32_t num_burst; uint32_t num_burst_per_ch; uint32_t num_trim; uint32_t num_trim_per_ch; uint32_t num_mc_regs; uint32_t num_up_down; uint32_t vref_num; uint32_t training_mod_num; uint32_t dram_timing_num; uint32_t ptfv_dqsosc_movavg_c0d0u0; uint32_t ptfv_dqsosc_movavg_c0d0u1; uint32_t ptfv_dqsosc_movavg_c0d1u0; uint32_t ptfv_dqsosc_movavg_c0d1u1; uint32_t ptfv_dqsosc_movavg_c1d0u0; uint32_t ptfv_dqsosc_movavg_c1d0u1; uint32_t ptfv_dqsosc_movavg_c1d1u0; uint32_t ptfv_dqsosc_movavg_c1d1u1; uint32_t ptfv_write_samples; uint32_t ptfv_dvfs_samples; uint32_t ptfv_movavg_weight; uint32_t ptfv_config_ctrl; DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_regs, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_perch_regs, FOREACH_PER_CHANNEL_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(shadow_regs_ca_train, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(shadow_regs_rdwr_train, FOREACH_BURST_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(trim_regs, FOREACH_TRIM_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(trim_perch_regs, FOREACH_PER_CHANNEL_TRIM_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(vref_perch_regs, FOREACH_PER_CHANNEL_VREF_REG); struct { uint32_t t_rp; uint32_t t_fc_lpddr4; uint32_t t_rfc; uint32_t t_pdex; uint32_t rl; } dram_timings; uint32_t zq_op_cc_long_zcal; uint32_t zq_op_cc_short_zcal; uint32_t zcal_wait_time_ps_cc_long_zcal; uint32_t zcal_wait_time_ps_cc_short_zcal; uint32_t tZQCAL_lpddr4; uint32_t zqcal_before_cc_cutoff; uint32_t opt_cc_short_zcal; uint32_t opt_short_zcal; uint32_t opt_do_sw_qrst; uint32_t save_restore_clkstop_pd; uint32_t opt_E90; uint32_t cya_allow_ref_cc; uint32_t ref_b4_sref_en; uint32_t cya_issue_pc_ref; DECLARE_ARRAY_AND_STRUCT_MEMBERS(training_mod_regs, FOREACH_PER_CHANNEL_TRAINING_MOD_REG); uint32_t save_restore_mod_regs[12]; DECLARE_ARRAY_AND_STRUCT_MEMBERS(burst_mc_regs, FOREACH_BURST_MC_REG); DECLARE_ARRAY_AND_STRUCT_MEMBERS(la_scale_regs, FOREACH_LA_SCALE_REG); uint32_t unk_0; uint32_t vtt_vdda_ctrl_0; uint32_t src_clock_div; uint32_t vtt_vdda_dual_channel; uint32_t vtt_vdda_ctrl_1; uint32_t vtt_vdda_ctrl_2; uint32_t vtt_vdda_ctrl_3; uint32_t vtt_vdda_ctrl_4; uint32_t misc_cfg_0; uint32_t misc_cfg_1; uint32_t misc_cfg_2; uint32_t unk_1; uint32_t unk_2; uint32_t pipe_clk_delay; uint32_t clkchange_delay; uint32_t pllm_ss_cfg; uint32_t pllm_ss_ctrl1; uint32_t pllm_ss_ctrl2; uint32_t pllmb_ss_cfg; uint32_t pllmb_ss_ctrl1; uint32_t pllmb_ss_ctrl2; uint32_t pllmb_divm; uint32_t pllmb_divn; uint32_t pllmb_divp; uint32_t min_mrs_wait; uint32_t ramp_wait; uint32_t emc_mrw; uint32_t emc_mrw2; uint32_t emc_mrw3; uint32_t emc_mrw4; uint32_t emc_mrw9; uint32_t emc_mrs; uint32_t emc_emrs; uint32_t emc_emrs2; uint32_t emc_auto_cal_config; uint32_t emc_auto_cal_config2; uint32_t emc_auto_cal_config3; uint32_t emc_auto_cal_config4; uint32_t emc_auto_cal_config5; uint32_t emc_auto_cal_config6; uint32_t emc_auto_cal_config7; uint32_t emc_auto_cal_config8; uint32_t emc_cfg_2; uint32_t emc_sel_dpd_ctrl; uint32_t emc_fdpd_ctrl_cmd_no_ramp; uint32_t emc_tr_ctrl_0; uint32_t dll_clk_src; uint32_t clk_out_enb_x_0_clk_enb_emc_dll; uint32_t latency; uint32_t pllm_misc1_0_pllm_clamp_ph90; }; #undef DECLARE_STRUCT_MEMBER_HANDLER #undef DECLARE_ARRAY_AND_STRUCT_MEMBERS static_assert(sizeof(EmcDvfsTimingTable) == 0x10CC); } ================================================ FILE: fusee/program/source/sdram/fusee_sdram.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_sdram.hpp" #include "../fusee_uncompress.hpp" namespace ams::nxboot { namespace { template<fuse::SocType SocType> struct SdramParamsImpl; template<> struct SdramParamsImpl<fuse::SocType_Erista> { using Type = br::erista::BootSdramParams; }; template<> struct SdramParamsImpl<fuse::SocType_Mariko> { using Type = br::mariko::BootSdramParams; }; template<fuse::SocType SocType> using BootSdramParams = SdramParamsImpl<SocType>::Type; constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t APB = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); constexpr inline const uintptr_t EMC = EMC_ADDRESS(0); constexpr inline const uintptr_t AHB = AHB_ARBC(0); #include "fusee_sdram_params.inc" #include "fusee_sdram_params_lp0_erista.inc" #include "fusee_sdram_params_lp0_mariko.inc" void *GetSdramParams(fuse::SocType soc_type) { /* Get DRAM Id. */ const auto dram_id = fuse::GetDramId(); /* Extract to work buffer. */ void *sdram_params_work_buffer; if (soc_type == fuse::SocType_Erista) { sdram_params_work_buffer = reinterpret_cast<void *>(0x4003E000 - 2 * sizeof(BootSdramParams<fuse::SocType_Erista>)); #define HANDLE_DRAM_CASE(_DRAM_ID_, _INDEX_) \ case _DRAM_ID_: \ Uncompress(sdram_params_work_buffer, 2 * sizeof(BootSdramParams<fuse::SocType_Erista>), SdramParamsErista##_INDEX_, SdramParamsSizeErista##_INDEX_); \ if (_INDEX_ & 1) { \ sdram_params_work_buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(sdram_params_work_buffer) + sizeof(BootSdramParams<fuse::SocType_Erista>)); \ } \ break; switch (dram_id) { HANDLE_DRAM_CASE(0, 0) HANDLE_DRAM_CASE(1, 1) HANDLE_DRAM_CASE(2, 2) HANDLE_DRAM_CASE(3, 3) HANDLE_DRAM_CASE(4, 4) HANDLE_DRAM_CASE(5, 5) HANDLE_DRAM_CASE(6, 6) default: AMS_ABORT("Invalid DRAM id"); } #undef HANDLE_DRAM_CASE return static_cast<BootSdramParams<fuse::SocType_Erista> *>(sdram_params_work_buffer); } else /* if (soc_type == fuse::SocType_Mariko) */ { sdram_params_work_buffer = reinterpret_cast<void *>(0x4003E000 - 2 * sizeof(BootSdramParams<fuse::SocType_Mariko>)); #define HANDLE_DRAM_CASE(_DRAM_ID_, _INDEX_) \ case _DRAM_ID_: \ Uncompress(sdram_params_work_buffer, 2 * sizeof(BootSdramParams<fuse::SocType_Mariko>), SdramParamsMariko##_INDEX_, SdramParamsSizeMariko##_INDEX_); \ if (_INDEX_ & 1) { \ sdram_params_work_buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(sdram_params_work_buffer) + sizeof(BootSdramParams<fuse::SocType_Mariko>)); \ } \ break; switch (dram_id) { HANDLE_DRAM_CASE( 3, 12) HANDLE_DRAM_CASE( 5, 12) HANDLE_DRAM_CASE( 6, 12) HANDLE_DRAM_CASE( 8, 1) HANDLE_DRAM_CASE( 9, 2) HANDLE_DRAM_CASE(10, 3) HANDLE_DRAM_CASE(11, 4) HANDLE_DRAM_CASE(12, 1) HANDLE_DRAM_CASE(13, 2) HANDLE_DRAM_CASE(14, 3) HANDLE_DRAM_CASE(15, 4) HANDLE_DRAM_CASE(17, 6) HANDLE_DRAM_CASE(18, 7) HANDLE_DRAM_CASE(19, 6) HANDLE_DRAM_CASE(20, 10) HANDLE_DRAM_CASE(21, 10) HANDLE_DRAM_CASE(22, 10) HANDLE_DRAM_CASE(23, 7) HANDLE_DRAM_CASE(24, 6) HANDLE_DRAM_CASE(25, 11) HANDLE_DRAM_CASE(26, 11) HANDLE_DRAM_CASE(27, 11) HANDLE_DRAM_CASE(28, 7) HANDLE_DRAM_CASE(29, 0) HANDLE_DRAM_CASE(30, 0) HANDLE_DRAM_CASE(31, 0) HANDLE_DRAM_CASE(32, 5) HANDLE_DRAM_CASE(33, 5) HANDLE_DRAM_CASE(34, 5) default: AMS_ABORT("Invalid DRAM id"); } #undef HANDLE_DRAM_CASE return static_cast<BootSdramParams<fuse::SocType_Mariko> *>(sdram_params_work_buffer); } } template<fuse::SocType SocType> void SpareWrite(u32 reg, u32 value) { if (reg) { if constexpr (SocType == fuse::SocType_Erista) { reg::Write(reinterpret_cast<volatile u32 *>(reg), value); } else if constexpr (SocType == fuse::SocType_Mariko) { /* TODO: Validate the write. */ reg::Write(reinterpret_cast<volatile u32 *>(reg), value); } } } template<fuse::SocType SocType> void InitializeSdramImpl(BootSdramParams<SocType> *params) { /* Perform initial soc-specific setup. */ if constexpr (SocType == fuse::SocType_Erista) { /* Enable sel_dpd on unused pins. */ reg::Write(PMC + APBDEV_PMC_IO_DPD3_REQ, (((params->EmcPmcScratch1 & 0x3FFFFFFF) | 0x80000000) ^ 0xFFFF) & 0xC000FFFF); util::WaitMicroSeconds(params->PmcIoDpd3ReqWait); /* Disable e_dpd_vttgen. */ u32 dpd4 = (params->EmcPmcScratch2 & 0x3FFFFFFF) | 0x80000000; reg::Write(PMC + APBDEV_PMC_IO_DPD4_REQ, (dpd4 ^ 0x3FFF0000) & 0xFFFF0000); util::WaitMicroSeconds(params->PmcIoDpd4ReqWait); /* Disable e_dpd_bg. */ reg::Write(PMC + APBDEV_PMC_IO_DPD4_REQ, (dpd4 ^ 0x0000FFFF) & 0xC000FFFF); util::WaitMicroSeconds(params->PmcIoDpd4ReqWait); reg::Write(PMC + APBDEV_PMC_WEAK_BIAS, 0); util::WaitMicroSeconds(1); /* Enable memory clock. */ { /* Initialize pllm. */ { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC1, params->PllMSetupControl); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC2, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_ENUM (PLLM_BASE_PLLM_ENABLE, DISABLE), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVP, params->PllMPostDivider), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVN, params->PllMFeedbackDivider), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVM, params->PllMInputDivider)); reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_ENUM (PLLM_BASE_PLLM_ENABLE, ENABLE), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVP, params->PllMPostDivider), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVN, params->PllMFeedbackDivider), CLK_RST_REG_BITS_VALUE(PLLM_BASE_PLLM_DIVM, params->PllMInputDivider)); /* Wait 300us for stability. */ const auto stable_time = util::GetMicroSeconds() + 300; while (true) { if (reg::HasValue(CLKRST + CLK_RST_CONTROLLER_PLLM_BASE, CLK_RST_REG_BITS_ENUM(PLLM_BASE_PLLM_LOCK, LOCK))) { util::WaitMicroSeconds(10); break; } if (util::GetMicroSeconds() >= stable_time) { break; } } } /* Set CLK_SOURCE_EMC, using McEmcmArbMisc0 as MC_EMC_SAME_FREQ. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, (params->EmcClockSource & ~0x10000) | ((params->McEmemArbMisc0 >> 11) & 0x10000)); if (params->EmcClockSourceDll) { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL, params->EmcClockSourceDll); } if (params->ClearClk2Mc1) { reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE)); } /* Enable EMC/Mem. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_EMC, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_MEM, ENABLE)); /* Enable EMC DLL. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_EMC_DLL, ENABLE)); } /* Clear reset for MEM/EMC. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_EMC_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_MEM_RST, ENABLE)); /* Set pad macros. */ reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_0, params->EmcPmacroVttgenCtrl0); reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_1, params->EmcPmacroVttgenCtrl1); reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_2, params->EmcPmacroVttgenCtrl2); reg::Write(EMC + EMC_TIMING_CONTROL, 1); util::WaitMicroSeconds(1); /* Select EMC write mux. */ reg::Write(EMC + EMC_DBG, params->EmcDbg | reg::EncodeValue(EMC_REG_BITS_VALUE(DBG_WRITE_MUX, params->EmcDbgWriteMux))); /* Patch 2. */ SpareWrite<SocType>(params->EmcBctSpare2, params->EmcBctSpare3); } else if constexpr (SocType == fuse::SocType_Mariko) { /* Patch 1 */ SpareWrite<SocType>(params->EmcBctSpare0, params->EmcBctSpare1); if (params->ClkRstControllerPllmMisc2OverrideEnable) { reg::Write(CLKRST + CLK_RST_CONTROLLER_PLLM_MISC2, params->ClkRstControllerPllmMisc2Override); } /* Enable sel_dpd on unused pins. */ { u32 val = (~params->EmcPmcScratch1 & 0x00000FFF) << 18; val |= ((~params->EmcPmcScratch1 & 0x00001000) << 19) | ((~params->EmcPmcScratch1 & 0x00008000) << 15); reg::Write(PMC + APBDEV_PMC_WEAK_BIAS, val); } reg::Write(PMC + APBDEV_PMC_IO_DPD3_REQ, 0x80000000 | (~params->EmcPmcScratch1 & 0x00009FFF)); util::WaitMicroSeconds(params->PmcIoDpd3ReqWait); /* Disable e_dpd_vttgen. */ reg::Write(PMC + APBDEV_PMC_IO_DPD4_REQ, 0x80000000 | (~params->EmcPmcScratch2 & 0x3FFF0000)); util::WaitMicroSeconds(params->PmcIoDpd4ReqWait); /* Disable e_dpd_bg. */ reg::Write(PMC + APBDEV_PMC_IO_DPD4_REQ, 0x80000000 | (~params->EmcPmcScratch2 & 0x00001FFF)); util::WaitMicroSeconds(1); } /* Common phase 1. */ /* Program CMD mapping. */ reg::Write(EMC + EMC_FBIO_CFG7, params->EmcFbioCfg7); reg::Write(EMC + EMC_CMD_MAPPING_CMD0_0, params->EmcCmdMappingCmd0_0); reg::Write(EMC + EMC_CMD_MAPPING_CMD0_1, params->EmcCmdMappingCmd0_1); reg::Write(EMC + EMC_CMD_MAPPING_CMD0_2, params->EmcCmdMappingCmd0_2); reg::Write(EMC + EMC_CMD_MAPPING_CMD1_0, params->EmcCmdMappingCmd1_0); reg::Write(EMC + EMC_CMD_MAPPING_CMD1_1, params->EmcCmdMappingCmd1_1); reg::Write(EMC + EMC_CMD_MAPPING_CMD1_2, params->EmcCmdMappingCmd1_2); reg::Write(EMC + EMC_CMD_MAPPING_CMD2_0, params->EmcCmdMappingCmd2_0); reg::Write(EMC + EMC_CMD_MAPPING_CMD2_1, params->EmcCmdMappingCmd2_1); reg::Write(EMC + EMC_CMD_MAPPING_CMD2_2, params->EmcCmdMappingCmd2_2); reg::Write(EMC + EMC_CMD_MAPPING_CMD3_0, params->EmcCmdMappingCmd3_0); reg::Write(EMC + EMC_CMD_MAPPING_CMD3_1, params->EmcCmdMappingCmd3_1); reg::Write(EMC + EMC_CMD_MAPPING_CMD3_2, params->EmcCmdMappingCmd3_2); reg::Write(EMC + EMC_CMD_MAPPING_BYTE, params->EmcCmdMappingByte); /* Program brick mapping. */ reg::Write(EMC + EMC_PMACRO_BRICK_MAPPING_0, params->EmcPmacroBrickMapping0); reg::Write(EMC + EMC_PMACRO_BRICK_MAPPING_1, params->EmcPmacroBrickMapping1); reg::Write(EMC + EMC_PMACRO_BRICK_MAPPING_2, params->EmcPmacroBrickMapping2); /* Specific phase 2. */ if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU1, (params->EmcPmacroBrickCtrlRfu1 | ~0x01120112) & 0x1FFF1FFF); } else if constexpr (SocType == fuse::SocType_Mariko) { /* Set pad macros. */ reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_0, params->EmcPmacroVttgenCtrl0); reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_1, params->EmcPmacroVttgenCtrl1); reg::Write(EMC + EMC_PMACRO_VTTGEN_CTRL_2, params->EmcPmacroVttgenCtrl2); /* Set pad macro bias. */ reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, params->EmcPmacroBgBiasCtrl0); SpareWrite<SocType>(params->EmcBctSpareSecure0, params->EmcBctSpareSecure1); SpareWrite<SocType>(params->EmcBctSpareSecure2, params->EmcBctSpareSecure3); SpareWrite<SocType>(params->EmcBctSpareSecure4, params->EmcBctSpareSecure5); /* Trigger timing update. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); util::WaitMicroSeconds(params->PmcVddpSelWait + 2); /* Set clock sources. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, params->EmcClockSource); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL, params->EmcClockSourceDll); /* Select EMC write mux. */ reg::Write(EMC + EMC_DBG, params->EmcDbg | reg::EncodeValue(EMC_REG_BITS_VALUE(DBG_WRITE_MUX, params->EmcDbgWriteMux))); /* Patch 2. */ SpareWrite<SocType>(params->EmcBctSpare2, params->EmcBctSpare3); } /* Common phase 2. */ reg::Write(EMC + EMC_CONFIG_SAMPLE_DELAY, params->EmcConfigSampleDelay); reg::Write(EMC + EMC_FBIO_CFG8, params->EmcFbioCfg8); /* Program swizzle registers. */ reg::Write(EMC + EMC_SWIZZLE_RANK0_BYTE0, params->EmcSwizzleRank0Byte0); reg::Write(EMC + EMC_SWIZZLE_RANK0_BYTE1, params->EmcSwizzleRank0Byte1); reg::Write(EMC + EMC_SWIZZLE_RANK0_BYTE2, params->EmcSwizzleRank0Byte2); reg::Write(EMC + EMC_SWIZZLE_RANK0_BYTE3, params->EmcSwizzleRank0Byte3); reg::Write(EMC + EMC_SWIZZLE_RANK1_BYTE0, params->EmcSwizzleRank1Byte0); reg::Write(EMC + EMC_SWIZZLE_RANK1_BYTE1, params->EmcSwizzleRank1Byte1); reg::Write(EMC + EMC_SWIZZLE_RANK1_BYTE2, params->EmcSwizzleRank1Byte2); reg::Write(EMC + EMC_SWIZZLE_RANK1_BYTE3, params->EmcSwizzleRank1Byte3); /* Patch 3. */ SpareWrite<SocType>(params->EmcBctSpare6, params->EmcBctSpare7); /* Program pad controls. */ reg::Write(EMC + EMC_XM2COMPPADCTRL, params->EmcXm2CompPadCtrl); reg::Write(EMC + EMC_XM2COMPPADCTRL2, params->EmcXm2CompPadCtrl2); reg::Write(EMC + EMC_XM2COMPPADCTRL3, params->EmcXm2CompPadCtrl3); /* Program autocal controls with shadowed register fields. */ reg::Write(EMC + EMC_AUTO_CAL_CONFIG2, params->EmcAutoCalConfig2); reg::Write(EMC + EMC_AUTO_CAL_CONFIG3, params->EmcAutoCalConfig3); reg::Write(EMC + EMC_AUTO_CAL_CONFIG4, params->EmcAutoCalConfig4); reg::Write(EMC + EMC_AUTO_CAL_CONFIG5, params->EmcAutoCalConfig5); reg::Write(EMC + EMC_AUTO_CAL_CONFIG6, params->EmcAutoCalConfig6); reg::Write(EMC + EMC_AUTO_CAL_CONFIG7, params->EmcAutoCalConfig7); reg::Write(EMC + EMC_AUTO_CAL_CONFIG8, params->EmcAutoCalConfig8); reg::Write(EMC + EMC_PMACRO_RX_TERM, params->EmcPmacroRxTerm); reg::Write(EMC + EMC_PMACRO_DQ_TX_DRV, params->EmcPmacroDqTxDrv); reg::Write(EMC + EMC_PMACRO_CA_TX_DRV, params->EmcPmacroCaTxDrv); reg::Write(EMC + EMC_PMACRO_CMD_TX_DRV, params->EmcPmacroCmdTxDrv); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_COMMON, params->EmcPmacroAutocalCfgCommon); reg::Write(EMC + EMC_AUTO_CAL_CHANNEL, params->EmcAutoCalChannel); reg::Write(EMC + EMC_PMACRO_ZCTRL, params->EmcPmacroZctrl); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_DLL_CFG_0, params->EmcDllCfg0); reg::Write(EMC + EMC_DLL_CFG_1, params->EmcDllCfg1); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_DLL_CFG_0, params->EmcPmacroDllCfg0); reg::Write(EMC + EMC_PMACRO_DLL_CFG_1, params->EmcPmacroDllCfg1); } reg::Write(EMC + EMC_CFG_DIG_DLL_1, params->EmcCfgDigDll_1); reg::Write(EMC + EMC_DATA_BRLSHFT_0, params->EmcDataBrlshft0); reg::Write(EMC + EMC_DATA_BRLSHFT_1, params->EmcDataBrlshft1); reg::Write(EMC + EMC_DQS_BRLSHFT_0, params->EmcDqsBrlshft0); reg::Write(EMC + EMC_DQS_BRLSHFT_1, params->EmcDqsBrlshft1); reg::Write(EMC + EMC_CMD_BRLSHFT_0, params->EmcCmdBrlshft0); reg::Write(EMC + EMC_CMD_BRLSHFT_1, params->EmcCmdBrlshft1); reg::Write(EMC + EMC_CMD_BRLSHFT_2, params->EmcCmdBrlshft2); reg::Write(EMC + EMC_CMD_BRLSHFT_3, params->EmcCmdBrlshft3); reg::Write(EMC + EMC_QUSE_BRLSHFT_0, params->EmcQuseBrlshft0); reg::Write(EMC + EMC_QUSE_BRLSHFT_1, params->EmcQuseBrlshft1); reg::Write(EMC + EMC_QUSE_BRLSHFT_2, params->EmcQuseBrlshft2); reg::Write(EMC + EMC_QUSE_BRLSHFT_3, params->EmcQuseBrlshft3); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU1, (params->EmcPmacroBrickCtrlRfu1 | ~0x01BF01BF) & 0x1FFF1FFF); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU1, params->EmcPmacroBrickCtrlRfu1); } reg::Write(EMC + EMC_PMACRO_PAD_CFG_CTRL, params->EmcPmacroPadCfgCtrl); reg::Write(EMC + EMC_PMACRO_CMD_BRICK_CTRL_FDPD, params->EmcPmacroCmdBrickCtrlFdpd); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU2, params->EmcPmacroBrickCtrlRfu2 & 0xFF7FFF7F); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU2, params->EmcPmacroBrickCtrlRfu2); } reg::Write(EMC + EMC_PMACRO_DATA_BRICK_CTRL_FDPD, params->EmcPmacroDataBrickCtrlFdpd); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_BG_BIAS_CTRL_0, params->EmcPmacroBgBiasCtrl0); } reg::Write(EMC + EMC_PMACRO_DATA_PAD_RX_CTRL, params->EmcPmacroDataPadRxCtrl); reg::Write(EMC + EMC_PMACRO_CMD_PAD_RX_CTRL, params->EmcPmacroCmdPadRxCtrl); reg::Write(EMC + EMC_PMACRO_DATA_PAD_TX_CTRL, params->EmcPmacroDataPadTxCtrl); reg::Write(EMC + EMC_PMACRO_DATA_RX_TERM_MODE, params->EmcPmacroDataRxTermMode); reg::Write(EMC + EMC_PMACRO_CMD_RX_TERM_MODE, params->EmcPmacroCmdRxTermMode); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_CMD_PAD_TX_CTRL, params->EmcPmacroCmdPadTxCtrl); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_CMD_PAD_TX_CTRL, params->EmcPmacroCmdPadTxCtrl & 0xEFFFFFFF); } reg::Write(EMC + EMC_CFG_3, params->EmcCfg3); reg::Write(EMC + EMC_PMACRO_TX_PWRD_0, params->EmcPmacroTxPwrd0); reg::Write(EMC + EMC_PMACRO_TX_PWRD_1, params->EmcPmacroTxPwrd1); reg::Write(EMC + EMC_PMACRO_TX_PWRD_2, params->EmcPmacroTxPwrd2); reg::Write(EMC + EMC_PMACRO_TX_PWRD_3, params->EmcPmacroTxPwrd3); reg::Write(EMC + EMC_PMACRO_TX_PWRD_4, params->EmcPmacroTxPwrd4); reg::Write(EMC + EMC_PMACRO_TX_PWRD_5, params->EmcPmacroTxPwrd5); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_0, params->EmcPmacroTxSelClkSrc0); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_1, params->EmcPmacroTxSelClkSrc1); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_2, params->EmcPmacroTxSelClkSrc2); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_3, params->EmcPmacroTxSelClkSrc3); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_4, params->EmcPmacroTxSelClkSrc4); reg::Write(EMC + EMC_PMACRO_TX_SEL_CLK_SRC_5, params->EmcPmacroTxSelClkSrc5); if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_0, params->EmcPmacroPerbitFgcgCtrl0); reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_1, params->EmcPmacroPerbitFgcgCtrl1); reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_2, params->EmcPmacroPerbitFgcgCtrl2); reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_3, params->EmcPmacroPerbitFgcgCtrl3); reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_4, params->EmcPmacroPerbitFgcgCtrl4); reg::Write(EMC + EMC_PMACRO_PERBIT_FGCG_CTRL_5, params->EmcPmacroPerbitFgcgCtrl5); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_0, params->EmcPmacroPerbitRfuCtrl0); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_1, params->EmcPmacroPerbitRfuCtrl1); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_2, params->EmcPmacroPerbitRfuCtrl2); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_3, params->EmcPmacroPerbitRfuCtrl3); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_4, params->EmcPmacroPerbitRfuCtrl4); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU_CTRL_5, params->EmcPmacroPerbitRfuCtrl5); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_0, params->EmcPmacroPerbitRfu1Ctrl0); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_1, params->EmcPmacroPerbitRfu1Ctrl1); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_2, params->EmcPmacroPerbitRfu1Ctrl2); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_3, params->EmcPmacroPerbitRfu1Ctrl3); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_4, params->EmcPmacroPerbitRfu1Ctrl4); reg::Write(EMC + EMC_PMACRO_PERBIT_RFU1_CTRL_5, params->EmcPmacroPerbitRfu1Ctrl5); reg::Write(EMC + EMC_PMACRO_DATA_PI_CTRL, params->EmcPmacroDataPiCtrl); reg::Write(EMC + EMC_PMACRO_CMD_PI_CTRL, params->EmcPmacroCmdPiCtrl); } reg::Write(EMC + EMC_PMACRO_DDLL_BYPASS, params->EmcPmacroDdllBypass); reg::Write(EMC + EMC_PMACRO_DDLL_PWRD_0, params->EmcPmacroDdllPwrd0); reg::Write(EMC + EMC_PMACRO_DDLL_PWRD_1, params->EmcPmacroDdllPwrd1); reg::Write(EMC + EMC_PMACRO_DDLL_PWRD_2, params->EmcPmacroDdllPwrd2); reg::Write(EMC + EMC_PMACRO_CMD_CTRL_0, params->EmcPmacroCmdCtrl0); reg::Write(EMC + EMC_PMACRO_CMD_CTRL_1, params->EmcPmacroCmdCtrl1); reg::Write(EMC + EMC_PMACRO_CMD_CTRL_2, params->EmcPmacroCmdCtrl2); reg::Write(EMC + EMC_PMACRO_IB_VREF_DQ_0, params->EmcPmacroIbVrefDq_0); reg::Write(EMC + EMC_PMACRO_IB_VREF_DQ_1, params->EmcPmacroIbVrefDq_1); reg::Write(EMC + EMC_PMACRO_IB_VREF_DQS_0, params->EmcPmacroIbVrefDqs_0); reg::Write(EMC + EMC_PMACRO_IB_VREF_DQS_1, params->EmcPmacroIbVrefDqs_1); reg::Write(EMC + EMC_PMACRO_IB_RXRT, params->EmcPmacroIbRxrt); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_0, params->EmcPmacroQuseDdllRank0_0); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_1, params->EmcPmacroQuseDdllRank0_1); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_2, params->EmcPmacroQuseDdllRank0_2); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_3, params->EmcPmacroQuseDdllRank0_3); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_4, params->EmcPmacroQuseDdllRank0_4); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK0_5, params->EmcPmacroQuseDdllRank0_5); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_0, params->EmcPmacroQuseDdllRank1_0); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_1, params->EmcPmacroQuseDdllRank1_1); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_2, params->EmcPmacroQuseDdllRank1_2); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_3, params->EmcPmacroQuseDdllRank1_3); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_4, params->EmcPmacroQuseDdllRank1_4); reg::Write(EMC + EMC_PMACRO_QUSE_DDLL_RANK1_5, params->EmcPmacroQuseDdllRank1_5); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU1, params->EmcPmacroBrickCtrlRfu1); } reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, params->EmcPmacroObDdllLongDqRank0_0); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, params->EmcPmacroObDdllLongDqRank0_1); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2, params->EmcPmacroObDdllLongDqRank0_2); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3, params->EmcPmacroObDdllLongDqRank0_3); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4, params->EmcPmacroObDdllLongDqRank0_4); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5, params->EmcPmacroObDdllLongDqRank0_5); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0, params->EmcPmacroObDdllLongDqRank1_0); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1, params->EmcPmacroObDdllLongDqRank1_1); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2, params->EmcPmacroObDdllLongDqRank1_2); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3, params->EmcPmacroObDdllLongDqRank1_3); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4, params->EmcPmacroObDdllLongDqRank1_4); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5, params->EmcPmacroObDdllLongDqRank1_5); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0, params->EmcPmacroObDdllLongDqsRank0_0); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1, params->EmcPmacroObDdllLongDqsRank0_1); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2, params->EmcPmacroObDdllLongDqsRank0_2); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3, params->EmcPmacroObDdllLongDqsRank0_3); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4, params->EmcPmacroObDdllLongDqsRank0_4); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5, params->EmcPmacroObDdllLongDqsRank0_5); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0, params->EmcPmacroObDdllLongDqsRank1_0); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1, params->EmcPmacroObDdllLongDqsRank1_1); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2, params->EmcPmacroObDdllLongDqsRank1_2); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3, params->EmcPmacroObDdllLongDqsRank1_3); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4, params->EmcPmacroObDdllLongDqsRank1_4); reg::Write(EMC + EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5, params->EmcPmacroObDdllLongDqsRank1_5); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0, params->EmcPmacroIbDdllLongDqsRank0_0); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1, params->EmcPmacroIbDdllLongDqsRank0_1); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2, params->EmcPmacroIbDdllLongDqsRank0_2); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3, params->EmcPmacroIbDdllLongDqsRank0_3); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0, params->EmcPmacroIbDdllLongDqsRank1_0); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1, params->EmcPmacroIbDdllLongDqsRank1_1); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2, params->EmcPmacroIbDdllLongDqsRank1_2); reg::Write(EMC + EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3, params->EmcPmacroIbDdllLongDqsRank1_3); reg::Write(EMC + EMC_PMACRO_DDLL_LONG_CMD_0, params->EmcPmacroDdllLongCmd_0); reg::Write(EMC + EMC_PMACRO_DDLL_LONG_CMD_1, params->EmcPmacroDdllLongCmd_1); reg::Write(EMC + EMC_PMACRO_DDLL_LONG_CMD_2, params->EmcPmacroDdllLongCmd_2); reg::Write(EMC + EMC_PMACRO_DDLL_LONG_CMD_3, params->EmcPmacroDdllLongCmd_3); reg::Write(EMC + EMC_PMACRO_DDLL_LONG_CMD_4, params->EmcPmacroDdllLongCmd_4); reg::Write(EMC + EMC_PMACRO_DDLL_SHORT_CMD_0, params->EmcPmacroDdllShortCmd_0); reg::Write(EMC + EMC_PMACRO_DDLL_SHORT_CMD_1, params->EmcPmacroDdllShortCmd_1); reg::Write(EMC + EMC_PMACRO_DDLL_SHORT_CMD_2, params->EmcPmacroDdllShortCmd_2); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_COMMON_PAD_TX_CTRL, (params->EmcPmacroCommonPadTxCtrl | ~0x1) & 0xF); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_DDLL_PERIODIC_OFFSET, params->EmcPmacroDdllPeriodicOffset); } if constexpr (SocType == fuse::SocType_Erista) { SpareWrite<SocType>(params->EmcBctSpare4, params->EmcBctSpare5); } else if constexpr (SocType == fuse::SocType_Mariko) { SpareWrite<SocType>(params->EmcBctSpare4, params->EmcBctSpare5); SpareWrite<SocType>(params->EmcBctSpareSecure6, params->EmcBctSpareSecure7); SpareWrite<SocType>(params->EmcBctSpareSecure8, params->EmcBctSpareSecure9); SpareWrite<SocType>(params->EmcBctSpareSecure10, params->EmcBctSpareSecure11); } reg::Write(EMC + EMC_TIMING_CONTROL, 1); /* Initialize MC VPR settings. */ reg::Write(MC + MC_VIDEO_PROTECT_BOM, params->McVideoProtectBom); reg::Write(MC + MC_VIDEO_PROTECT_BOM_ADR_HI, params->McVideoProtectBomAdrHi); reg::Write(MC + MC_VIDEO_PROTECT_SIZE_MB, params->McVideoProtectSizeMb); reg::Write(MC + MC_VIDEO_PROTECT_VPR_OVERRIDE, params->McVideoProtectVprOverride); reg::Write(MC + MC_VIDEO_PROTECT_VPR_OVERRIDE1, params->McVideoProtectVprOverride1); reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_0, params->McVideoProtectGpuOverride0); reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_1, params->McVideoProtectGpuOverride1); /* Program SDRAM geometry parameters. */ reg::Write(MC + MC_EMEM_ADR_CFG, params->McEmemAdrCfg); reg::Write(MC + MC_EMEM_ADR_CFG_DEV0, params->McEmemAdrCfgDev0); reg::Write(MC + MC_EMEM_ADR_CFG_DEV1, params->McEmemAdrCfgDev1); reg::Write(MC + MC_EMEM_ADR_CFG_CHANNEL_MASK, params->McEmemAdrCfgChannelMask); /* Program bank swizzling. */ reg::Write(MC + MC_EMEM_ADR_CFG_BANK_MASK_0, params->McEmemAdrCfgBankMask0); reg::Write(MC + MC_EMEM_ADR_CFG_BANK_MASK_1, params->McEmemAdrCfgBankMask1); reg::Write(MC + MC_EMEM_ADR_CFG_BANK_MASK_2, params->McEmemAdrCfgBankMask2); /* Program external memory aperture (base and size). */ reg::Write(MC + MC_EMEM_CFG, params->McEmemCfg); /* Program SEC carveout (base and size). */ reg::Write(MC + MC_SEC_CARVEOUT_BOM, params->McSecCarveoutBom); reg::Write(MC + MC_SEC_CARVEOUT_ADR_HI, params->McSecCarveoutAdrHi); reg::Write(MC + MC_SEC_CARVEOUT_SIZE_MB, params->McSecCarveoutSizeMb); /* Program MTS carveout (base and size). */ reg::Write(MC + MC_MTS_CARVEOUT_BOM, params->McMtsCarveoutBom); reg::Write(MC + MC_MTS_CARVEOUT_ADR_HI, params->McMtsCarveoutAdrHi); reg::Write(MC + MC_MTS_CARVEOUT_SIZE_MB, params->McMtsCarveoutSizeMb); /* Program the memory arbiter. */ reg::Write(MC + MC_EMEM_ARB_CFG, params->McEmemArbCfg); reg::Write(MC + MC_EMEM_ARB_OUTSTANDING_REQ, params->McEmemArbOutstandingReq); reg::Write(MC + MC_EMEM_ARB_REFPB_HP_CTRL, params->McEmemArbRefpbHpCtrl); reg::Write(MC + MC_EMEM_ARB_REFPB_BANK_CTRL, params->McEmemArbRefpbBankCtrl); reg::Write(MC + MC_EMEM_ARB_TIMING_RCD, params->McEmemArbTimingRcd); reg::Write(MC + MC_EMEM_ARB_TIMING_RP, params->McEmemArbTimingRp); reg::Write(MC + MC_EMEM_ARB_TIMING_RC, params->McEmemArbTimingRc); reg::Write(MC + MC_EMEM_ARB_TIMING_RAS, params->McEmemArbTimingRas); reg::Write(MC + MC_EMEM_ARB_TIMING_FAW, params->McEmemArbTimingFaw); reg::Write(MC + MC_EMEM_ARB_TIMING_RRD, params->McEmemArbTimingRrd); reg::Write(MC + MC_EMEM_ARB_TIMING_RAP2PRE, params->McEmemArbTimingRap2Pre); reg::Write(MC + MC_EMEM_ARB_TIMING_WAP2PRE, params->McEmemArbTimingWap2Pre); reg::Write(MC + MC_EMEM_ARB_TIMING_R2R, params->McEmemArbTimingR2R); reg::Write(MC + MC_EMEM_ARB_TIMING_W2W, params->McEmemArbTimingW2W); reg::Write(MC + MC_EMEM_ARB_TIMING_CCDMW, params->McEmemArbTimingCcdmw); reg::Write(MC + MC_EMEM_ARB_TIMING_R2W, params->McEmemArbTimingR2W); reg::Write(MC + MC_EMEM_ARB_TIMING_W2R, params->McEmemArbTimingW2R); reg::Write(MC + MC_EMEM_ARB_TIMING_RFCPB, params->McEmemArbTimingRFCPB); reg::Write(MC + MC_EMEM_ARB_DA_TURNS, params->McEmemArbDaTurns); reg::Write(MC + MC_EMEM_ARB_DA_COVERS, params->McEmemArbDaCovers); reg::Write(MC + MC_EMEM_ARB_MISC0, params->McEmemArbMisc0); reg::Write(MC + MC_EMEM_ARB_MISC1, params->McEmemArbMisc1); reg::Write(MC + MC_EMEM_ARB_MISC2, params->McEmemArbMisc2); reg::Write(MC + MC_EMEM_ARB_RING1_THROTTLE, params->McEmemArbRing1Throttle); reg::Write(MC + MC_EMEM_ARB_OVERRIDE, params->McEmemArbOverride); reg::Write(MC + MC_EMEM_ARB_OVERRIDE_1, params->McEmemArbOverride1); reg::Write(MC + MC_EMEM_ARB_RSV, params->McEmemArbRsv); reg::Write(MC + MC_DA_CONFIG0, params->McDaCfg0); /* Trigger MC timing update. */ reg::Write(MC + MC_TIMING_CONTROL, 1); /* Program second-level clock enable overrides. */ reg::Write(MC + MC_CLKEN_OVERRIDE, params->McClkenOverride); /* Program statistics gathering. */ reg::Write(MC + MC_STAT_CONTROL, params->McStatControl); /* Program SDRAM geometry parameters. */ reg::Write(EMC + EMC_ADR_CFG, params->EmcAdrCfg); /* Program second-level clock enable overrides. */ reg::Write(EMC + EMC_CLKEN_OVERRIDE, params->EmcClkenOverride); /* Program EMC pad auto calibration. */ reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_0, params->EmcPmacroAutocalCfg0); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_1, params->EmcPmacroAutocalCfg1); reg::Write(EMC + EMC_PMACRO_AUTOCAL_CFG_2, params->EmcPmacroAutocalCfg2); reg::Write(EMC + EMC_AUTO_CAL_VREF_SEL_0, params->EmcAutoCalVrefSel0); reg::Write(EMC + EMC_AUTO_CAL_VREF_SEL_1, params->EmcAutoCalVrefSel1); reg::Write(EMC + EMC_AUTO_CAL_INTERVAL, params->EmcAutoCalInterval); reg::Write(EMC + EMC_AUTO_CAL_CONFIG, params->EmcAutoCalConfig); util::WaitMicroSeconds(params->EmcAutoCalWait); /* Patch 5. */ if constexpr (SocType == fuse::SocType_Erista) { SpareWrite<SocType>(params->EmcBctSpare8, params->EmcBctSpare9); } else if constexpr (SocType == fuse::SocType_Mariko) { SpareWrite<SocType>(params->EmcBctSpare8, params->EmcBctSpare9); reg::Write(EMC + EMC_AUTO_CAL_CONFIG9, params->EmcAutoCalConfig9); } /* Program EMC timing configuration. */ reg::Write(EMC + EMC_CFG_2, params->EmcCfg2); reg::Write(EMC + EMC_CFG_PIPE, params->EmcCfgPipe); reg::Write(EMC + EMC_CFG_PIPE_1, params->EmcCfgPipe1); reg::Write(EMC + EMC_CFG_PIPE_2, params->EmcCfgPipe2); reg::Write(EMC + EMC_CMDQ, params->EmcCmdQ); reg::Write(EMC + EMC_MC2EMCQ, params->EmcMc2EmcQ); reg::Write(EMC + EMC_MRS_WAIT_CNT, params->EmcMrsWaitCnt); reg::Write(EMC + EMC_MRS_WAIT_CNT2, params->EmcMrsWaitCnt2); reg::Write(EMC + EMC_FBIO_CFG5, params->EmcFbioCfg5); reg::Write(EMC + EMC_RC, params->EmcRc); reg::Write(EMC + EMC_RFC, params->EmcRfc); reg::Write(EMC + EMC_RFCPB, params->EmcRfcPb); reg::Write(EMC + EMC_REFCTRL2, params->EmcRefctrl2); reg::Write(EMC + EMC_RFC_SLR, params->EmcRfcSlr); reg::Write(EMC + EMC_RAS, params->EmcRas); reg::Write(EMC + EMC_RP, params->EmcRp); reg::Write(EMC + EMC_TPPD, params->EmcTppd); if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_TRTM, params->EmcTrtm); reg::Write(EMC + EMC_TWTM, params->EmcTwtm); reg::Write(EMC + EMC_TRATM, params->EmcTratm); reg::Write(EMC + EMC_TWATM, params->EmcTwatm); reg::Write(EMC + EMC_TR2REF, params->EmcTr2ref); } reg::Write(EMC + EMC_R2R, params->EmcR2r); reg::Write(EMC + EMC_W2W, params->EmcW2w); reg::Write(EMC + EMC_R2W, params->EmcR2w); reg::Write(EMC + EMC_W2R, params->EmcW2r); reg::Write(EMC + EMC_R2P, params->EmcR2p); reg::Write(EMC + EMC_W2P, params->EmcW2p); reg::Write(EMC + EMC_CCDMW, params->EmcCcdmw); reg::Write(EMC + EMC_RD_RCD, params->EmcRdRcd); reg::Write(EMC + EMC_WR_RCD, params->EmcWrRcd); reg::Write(EMC + EMC_RRD, params->EmcRrd); reg::Write(EMC + EMC_REXT, params->EmcRext); reg::Write(EMC + EMC_WEXT, params->EmcWext); reg::Write(EMC + EMC_WDV, params->EmcWdv); reg::Write(EMC + EMC_WDV_CHK, params->EmcWdvChk); reg::Write(EMC + EMC_WSV, params->EmcWsv); reg::Write(EMC + EMC_WEV, params->EmcWev); reg::Write(EMC + EMC_WDV_MASK, params->EmcWdvMask); reg::Write(EMC + EMC_WS_DURATION, params->EmcWsDuration); reg::Write(EMC + EMC_WE_DURATION, params->EmcWeDuration); reg::Write(EMC + EMC_QUSE, params->EmcQUse); reg::Write(EMC + EMC_QUSE_WIDTH, params->EmcQuseWidth); reg::Write(EMC + EMC_IBDLY, params->EmcIbdly); reg::Write(EMC + EMC_OBDLY, params->EmcObdly); reg::Write(EMC + EMC_EINPUT, params->EmcEInput); reg::Write(EMC + EMC_EINPUT_DURATION, params->EmcEInputDuration); reg::Write(EMC + EMC_PUTERM_EXTRA, params->EmcPutermExtra); reg::Write(EMC + EMC_PUTERM_WIDTH, params->EmcPutermWidth); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_PMACRO_COMMON_PAD_TX_CTRL, params->EmcPmacroCommonPadTxCtrl); } reg::Write(EMC + EMC_DBG, params->EmcDbg); reg::Write(EMC + EMC_QRST, params->EmcQRst); reg::Write(EMC + EMC_ISSUE_QRST, 1); reg::Write(EMC + EMC_ISSUE_QRST, 0); reg::Write(EMC + EMC_QSAFE, params->EmcQSafe); reg::Write(EMC + EMC_RDV, params->EmcRdv); reg::Write(EMC + EMC_RDV_MASK, params->EmcRdvMask); reg::Write(EMC + EMC_RDV_EARLY, params->EmcRdvEarly); reg::Write(EMC + EMC_RDV_EARLY_MASK, params->EmcRdvEarlyMask); reg::Write(EMC + EMC_QPOP, params->EmcQpop); reg::Write(EMC + EMC_REFRESH, params->EmcRefresh); reg::Write(EMC + EMC_BURST_REFRESH_NUM, params->EmcBurstRefreshNum); reg::Write(EMC + EMC_PRE_REFRESH_REQ_CNT, params->EmcPreRefreshReqCnt); reg::Write(EMC + EMC_PDEX2WR, params->EmcPdEx2Wr); reg::Write(EMC + EMC_PDEX2RD, params->EmcPdEx2Rd); reg::Write(EMC + EMC_PCHG2PDEN, params->EmcPChg2Pden); reg::Write(EMC + EMC_ACT2PDEN, params->EmcAct2Pden); reg::Write(EMC + EMC_AR2PDEN, params->EmcAr2Pden); reg::Write(EMC + EMC_RW2PDEN, params->EmcRw2Pden); reg::Write(EMC + EMC_CKE2PDEN, params->EmcCke2Pden); reg::Write(EMC + EMC_PDEX2CKE, params->EmcPdex2Cke); reg::Write(EMC + EMC_PDEX2MRR, params->EmcPdex2Mrr); reg::Write(EMC + EMC_TXSR, params->EmcTxsr); reg::Write(EMC + EMC_TXSRDLL, params->EmcTxsrDll); reg::Write(EMC + EMC_TCKE, params->EmcTcke); reg::Write(EMC + EMC_TCKESR, params->EmcTckesr); reg::Write(EMC + EMC_TPD, params->EmcTpd); reg::Write(EMC + EMC_TFAW, params->EmcTfaw); reg::Write(EMC + EMC_TRPAB, params->EmcTrpab); reg::Write(EMC + EMC_TCLKSTABLE, params->EmcTClkStable); reg::Write(EMC + EMC_TCLKSTOP, params->EmcTClkStop); reg::Write(EMC + EMC_TREFBW, params->EmcTRefBw); reg::Write(EMC + EMC_ODT_WRITE, params->EmcOdtWrite); reg::Write(EMC + EMC_CFG_DIG_DLL, params->EmcCfgDigDll); reg::Write(EMC + EMC_CFG_DIG_DLL_PERIOD, params->EmcCfgDigDllPeriod); /* Lock bit written later for CFG_ADR_EN. */ reg::Write(EMC + EMC_FBIO_SPARE, params->EmcFbioSpare & 0xFFFFFFFD); reg::Write(EMC + EMC_CFG_RSV, params->EmcCfgRsv); reg::Write(EMC + EMC_PMC_SCRATCH1, params->EmcPmcScratch1); reg::Write(EMC + EMC_PMC_SCRATCH2, params->EmcPmcScratch2); reg::Write(EMC + EMC_PMC_SCRATCH3, params->EmcPmcScratch3); reg::Write(EMC + EMC_ACPD_CONTROL, params->EmcAcpdControl); reg::Write(EMC + EMC_TXDSRVTTGEN, params->EmcTxdsrvttgen); if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_DSR_VTTGEN_CTRL_0, params->EmcPmacroDsrVttgenCtrl0); } /* Set pipe bypass enable bits before sending any DRAM commands. */ reg::Write(EMC + EMC_CFG, (params->EmcCfg * 0xE) | 0x03C00000); /* Perform bootrom patch. */ if constexpr (SocType == fuse::SocType_Erista) { if (params->BootRomPatchControl & 0x80000000) { reg::Write(APB + ((params->BootRomPatchControl & 0x3FFFFFFF) << 2), params->BootRomPatchData); reg::Write(MC + MC_TIMING_CONTROL, 1); } } else if constexpr (SocType == fuse::SocType_Mariko) { if (params->BootRomPatchControl) { SpareWrite<SocType>(params->BootRomPatchControl, params->BootRomPatchData); reg::Write(MC + MC_TIMING_CONTROL, 1); } SpareWrite<SocType>(params->EmcBctSpareSecure12, params->EmcBctSpareSecure13); SpareWrite<SocType>(params->EmcBctSpareSecure14, params->EmcBctSpareSecure15); SpareWrite<SocType>(params->EmcBctSpareSecure16, params->EmcBctSpareSecure17); } /* Release SEL_DPD_CMD. */ reg::Write(PMC + APBDEV_PMC_IO_DPD3_REQ, ((params->EmcPmcScratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000); util::WaitMicroSeconds(params->PmcIoDpd3ReqWait); if constexpr (SocType == fuse::SocType_Erista) { if (params->EmcAutoCalInterval == 0) { reg::Write(EMC + EMC_AUTO_CAL_CONFIG, params->EmcAutoCalConfig | 0x200); } reg::Write(EMC + EMC_PMACRO_BRICK_CTRL_RFU2, params->EmcPmacroBrickCtrlRfu2); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_PMACRO_CMD_PAD_TX_CTRL, params->EmcPmacroCmdPadTxCtrl); } /* ZQ CAL setup */ if (params->EmcZcalWarmColdBootEnables & 1) { if (params->MemoryType == br::BootMemoryType_Ddr3) { reg::Write(EMC + EMC_ZCAL_WAIT_CNT, params->EmcZcalWaitCnt << 3); } else if (params->MemoryType == br::BootMemoryType_LpDdr4) { reg::Write(EMC + EMC_ZCAL_WAIT_CNT, params->EmcZcalWaitCnt); reg::Write(EMC + EMC_ZCAL_MRW_CMD, params->EmcZcalMrwCmd); } } /* Trigger timing update. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); util::WaitMicroSeconds(params->EmcTimingControlWait); /* Deassert HOLD_CKE_LOW. */ if constexpr (SocType == fuse::SocType_Erista) { reg::ClearBits(PMC + APBDEV_PMC_DDR_CNTRL, ~0xFFF8007F); } else if constexpr (SocType == fuse::SocType_Mariko) { reg::ClearBits(PMC + APBDEV_PMC_DDR_CNTRL, ~0xFF78007F); } util::WaitMicroSeconds(params->PmcDdrCntrlWait); /* Set clock enable signal. */ const u32 pin_gpio_cfg = (params->EmcPinGpioEn << 16) | (params->EmcPinGpio << 12); if (params->MemoryType == br::BootMemoryType_Ddr3 || params->MemoryType == br::BootMemoryType_LpDdr4) { reg::Write(EMC + EMC_PIN, pin_gpio_cfg); reg::Read(EMC + EMC_PIN); util::WaitMicroSeconds(200 + params->EmcPinExtraWait); reg::Write(EMC + EMC_PIN, pin_gpio_cfg | 0x100); reg::Read(EMC + EMC_PIN); const u32 wait = params->MemoryType == br::BootMemoryType_Ddr3 ? 500 : 2000; util::WaitMicroSeconds(wait + params->EmcPinExtraWait); } /* Set clock enable signal. */ reg::Write(EMC + EMC_PIN, pin_gpio_cfg | 0x101); reg::Read(EMC + EMC_PIN); util::WaitMicroSeconds(params->EmcPinProgramWait); /* Send NOP */ if (params->MemoryType != br::BootMemoryType_LpDdr4) { reg::Write(EMC + EMC_NOP, (params->EmcDevSelect << 30) | 1); } /* On coldboot with LPDDR2/3, wait 200us after asserting CKE high. */ if (params->MemoryType != br::BootMemoryType_LpDdr2) { util::WaitMicroSeconds(200 + params->EmcPinExtraWait); } /* Init ZQ calibration. */ if (params->MemoryType == br::BootMemoryType_LpDdr4) { SpareWrite<SocType>(params->EmcBctSpare10, params->EmcBctSpare11); reg::Write(EMC + EMC_MRW2, params->EmcMrw2); reg::Write(EMC + EMC_MRW, params->EmcMrw1); reg::Write(EMC + EMC_MRW3, params->EmcMrw3); reg::Write(EMC + EMC_MRW4, params->EmcMrw4); reg::Write(EMC + EMC_MRW6, params->EmcMrw6); reg::Write(EMC + EMC_MRW14, params->EmcMrw14); reg::Write(EMC + EMC_MRW8, params->EmcMrw8); reg::Write(EMC + EMC_MRW12, params->EmcMrw12); reg::Write(EMC + EMC_MRW9, params->EmcMrw9); reg::Write(EMC + EMC_MRW13, params->EmcMrw13); if (params->EmcZcalWarmColdBootEnables & 1) { /* Issue ZQCAL start, device 0. */ reg::Write(EMC + EMC_ZQ_CAL, params->EmcZcalInitDev0); util::WaitMicroSeconds(params->EmcZcalInitWait); /* Issue ZQCAL latch. */ reg::Write(EMC + EMC_ZQ_CAL, params->EmcZcalInitDev0 ^ 0x3); /* Do the same for device 1. */ if ((params->EmcDevSelect & 2) == 0) { reg::Write(EMC + EMC_ZQ_CAL, params->EmcZcalInitDev1); util::WaitMicroSeconds(params->EmcZcalInitWait); reg::Write(EMC + EMC_ZQ_CAL, params->EmcZcalInitDev1 ^ 0x3); } } } /* Patches 10-12. */ if constexpr (SocType == fuse::SocType_Mariko) { SpareWrite<SocType>(params->EmcBctSpareSecure18, params->EmcBctSpareSecure19); SpareWrite<SocType>(params->EmcBctSpareSecure20, params->EmcBctSpareSecure21); SpareWrite<SocType>(params->EmcBctSpareSecure22, params->EmcBctSpareSecure23); } /* Set package and DPD pad control. */ reg::Write(PMC + APBDEV_PMC_DDR_CFG, params->PmcDdrCfg); /* Start periodic ZQ calibration. */ if (params->MemoryType == br::BootMemoryType_LpDdr2 || params->MemoryType == br::BootMemoryType_Ddr3 || params->MemoryType == br::BootMemoryType_LpDdr4) { reg::Write(EMC + EMC_ZCAL_INTERVAL, params->EmcZcalInterval); reg::Write(EMC + EMC_ZCAL_WAIT_CNT, params->EmcZcalWaitCnt); reg::Write(EMC + EMC_ZCAL_MRW_CMD, params->EmcZcalMrwCmd); } SpareWrite<SocType>(params->EmcBctSpare12, params->EmcBctSpare13); /* Trigger timing update. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); if (params->EmcExtraRefreshNum) { reg::Write(EMC + EMC_REF, (params->EmcDevSelect << 30) | (((1 << params->EmcExtraRefreshNum) - 1) << 8) | 3); } /* Enable refresh. */ reg::Write(EMC + EMC_REFCTRL, params->EmcDevSelect | 0x80000000); reg::Write(EMC + EMC_DYN_SELF_REF_CONTROL, params->EmcDynSelfRefControl); if constexpr (SocType == fuse::SocType_Erista) { reg::Write(EMC + EMC_CFG_UPDATE, params->EmcCfgUpdate); } reg::Write(EMC + EMC_CFG, params->EmcCfg); reg::Write(EMC + EMC_FDPD_CTRL_DQ, params->EmcFdpdCtrlDq); reg::Write(EMC + EMC_FDPD_CTRL_CMD, params->EmcFdpdCtrlCmd); reg::Write(EMC + EMC_SEL_DPD_CTRL, params->EmcSelDpdCtrl); /* Write addr swizzle lock bit. */ reg::Write(EMC + EMC_FBIO_SPARE, params->EmcFbioSpare | 2); /* Trigger timing update. */ reg::Write(EMC + EMC_TIMING_CONTROL, 1); if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(EMC + EMC_CFG_UPDATE, params->EmcCfgUpdate); } /* Enable EMC pipe clock gating. */ reg::Write(EMC + EMC_CFG_PIPE_CLK, params->EmcCfgPipeClk); /* Depending on freqency, enable CMD/CLK fdpd. */ reg::Write(EMC + EMC_FDPD_CTRL_CMD_NO_RAMP, params->EmcFdpdCtrlCmdNoRamp); if constexpr (SocType == fuse::SocType_Erista) { reg::ReadWrite(AHB + AHB_ARBITRATION_XBAR_CTRL, AHB_REG_BITS_VALUE(ARBITRATION_XBAR_CTRL_MEM_INIT_DONE, params->AhbArbitrationXbarCtrlMemInitDone)); } if constexpr (SocType == fuse::SocType_Mariko) { reg::Write(MC + MC_UNTRANSLATED_REGION_CHECK, params->McUntranslatedRegionCheck); } /* Lock carveouts. */ reg::Write(MC + MC_VIDEO_PROTECT_REG_CTRL, params->McVideoProtectWriteAccess); reg::Write(MC + MC_SEC_CARVEOUT_REG_CTRL, params->McSecCarveoutProtectWriteAccess); reg::Write(MC + MC_MTS_CARVEOUT_REG_CTRL, params->McMtsCarveoutRegCtrl); reg::Write(MC + MC_EMEM_CFG_ACCESS_CTRL, 1); if constexpr (SocType == fuse::SocType_Mariko) { reg::ReadWrite(AHB + AHB_ARBITRATION_XBAR_CTRL, AHB_REG_BITS_VALUE(ARBITRATION_XBAR_CTRL_MEM_INIT_DONE, params->AhbArbitrationXbarCtrlMemInitDone)); } } consteval u32 GetBitMask32(u32 range) { if (range == BITSIZEOF(u32)) { return 0xFFFFFFFF; } else { return (1u << range) - 1; } } template<fuse::SocType SocType> void SaveSdramParamsToScratch(BootSdramParams<SocType> *params) { /* Clear the carveout parameters. */ params->McGeneralizedCarveout1Cfg0 = 0; params->McGeneralizedCarveout2Cfg0 = 0; params->McGeneralizedCarveout3Cfg0 = 0; params->McGeneralizedCarveout4Cfg0 = 0; params->McGeneralizedCarveout5Cfg0 = 0; /* Patch spare write. */ { /* TODO: Clean this up? */ u32 t0 = params->EmcSwizzleRank0Byte0 << 5 >> 29 > params->EmcSwizzleRank0Byte0 << 1 >> 29; u32 t1 = (t0 & 0xFFFFFFEF) | ((params->EmcSwizzleRank1Byte0 << 5 >> 29 > params->EmcSwizzleRank1Byte0 << 1 >> 29) << 4); u32 t2 = (t1 & 0xFFFFFFFD) | ((params->EmcSwizzleRank0Byte1 << 5 >> 29 > params->EmcSwizzleRank0Byte1 << 1 >> 29) << 1); u32 t3 = (t2 & 0xFFFFFFDF) | ((params->EmcSwizzleRank1Byte1 << 5 >> 29 > params->EmcSwizzleRank1Byte1 << 1 >> 29) << 5); u32 t4 = (t3 & 0xFFFFFFFB) | ((params->EmcSwizzleRank0Byte2 << 5 >> 29 > params->EmcSwizzleRank0Byte2 << 1 >> 29) << 2); u32 t5 = (t4 & 0xFFFFFFBF) | ((params->EmcSwizzleRank1Byte2 << 5 >> 29 > params->EmcSwizzleRank1Byte2 << 1 >> 29) << 6); u32 t6 = (t5 & 0xFFFFFFF7) | ((params->EmcSwizzleRank0Byte3 << 5 >> 29 > params->EmcSwizzleRank0Byte3 << 1 >> 29) << 3); u32 t7 = (t6 & 0xFFFFFF7F) | ((params->EmcSwizzleRank1Byte3 << 5 >> 29 > params->EmcSwizzleRank1Byte3 << 1 >> 29) << 7); params->SwizzleRankByteEncode = t7; params->EmcBctSpare2 = 0x40000DD8; params->EmcBctSpare3 = params->SwizzleRankByteEncode; } /* Save parameters to scratch. */ { u32 cur_reg_offset = APBDEV_PMC_SCRATCH6; u32 cur_reg_value = reg::Read(PMC + cur_reg_offset); #define RANGE_HIGH(RANGE) (1 ? RANGE) #define RANGE_LOW(RANGE) (0 ? RANGE) static_assert(RANGE_HIGH(31:0) - RANGE_LOW(31:0) + 1 == BITSIZEOF(u32)); #define PROCESS_IMPL(PARAM, SCRATCH, SRC_RANGE, DST_RANGE, DO_READ) \ { \ constexpr u32 RegisterOffset = APBDEV_PMC_##SCRATCH; \ \ if (RegisterOffset != cur_reg_offset) { \ reg::Write(PMC + cur_reg_offset, cur_reg_value); \ cur_reg_offset = RegisterOffset; \ if constexpr (DO_READ) { \ cur_reg_value = reg::Read(PMC + RegisterOffset); \ } else { \ cur_reg_value = 0; \ } \ } \ \ constexpr u32 SrcRange = RANGE_HIGH(SRC_RANGE) - RANGE_LOW(SRC_RANGE) + 1; \ constexpr u32 DstRange = RANGE_HIGH(DST_RANGE) - RANGE_LOW(DST_RANGE) + 1; \ static_assert(SrcRange == DstRange); \ static_assert(SrcRange <= BITSIZEOF(u32)); \ \ const u32 src_value = params->PARAM; \ if constexpr (SrcRange == BITSIZEOF(u32)) { \ cur_reg_value = src_value; \ } else if constexpr (SrcRange < BITSIZEOF(u32)) { \ constexpr u32 Mask = GetBitMask32(SrcRange) << RANGE_LOW(DST_RANGE); \ \ constexpr u32 SrcLow = RANGE_LOW(SRC_RANGE); \ constexpr u32 DstLow = RANGE_LOW(DST_RANGE); \ constexpr auto Shift = (SrcLow < DstLow) ? (DstLow - SrcLow) \ : (SrcLow - DstLow); \ \ cur_reg_value &= ~Mask; \ if constexpr (SrcLow == DstLow) { \ cur_reg_value |= (src_value & Mask); \ } else if constexpr (SrcLow < DstLow) { \ cur_reg_value |= ((src_value << Shift) & Mask); \ } else { \ cur_reg_value |= ((src_value >> Shift) & Mask); \ } \ } \ } #define PROCESS_SCRATCH(PARAM, S, SRC_RANGE, DST_RANGE) PROCESS_IMPL(PARAM, SCRATCH##S, SRC_RANGE, DST_RANGE, true) #define PROCESS_SECURE_SCRATCH(PARAM, S, SRC_RANGE, DST_RANGE) PROCESS_IMPL(PARAM, SECURE_SCRATCH##S, SRC_RANGE, DST_RANGE, true) #define PROCESS_COMMON_SCRATCH(PARAM, S, SRC_RANGE, DST_RANGE) PROCESS_IMPL(PARAM, SCRATCH##S, SRC_RANGE, DST_RANGE, false) if constexpr (SocType == fuse::SocType_Erista) { FOREACH_SDRAM_SCRATCH_REGISTER_ERISTA(PROCESS_SCRATCH); FOREACH_SDRAM_SECURE_SCRATCH_REGISTER_ERISTA(PROCESS_SECURE_SCRATCH); } else /* if constexpr (SocType == fuse::SocType_Mariko) */ { FOREACH_SDRAM_SCRATCH_REGISTER_MARIKO(PROCESS_SCRATCH); FOREACH_SDRAM_SECURE_SCRATCH_REGISTER_MARIKO(PROCESS_SECURE_SCRATCH); } /* Manually process final fields. */ PROCESS_COMMON_SCRATCH(PllMInputDivider, 2, 7:0, 7:0); PROCESS_COMMON_SCRATCH(PllMFeedbackDivider, 2, 7:0, 15:8); PROCESS_COMMON_SCRATCH(PllMPostDivider, 2, 4:0, 20:16); PROCESS_COMMON_SCRATCH(PllMKVCO, 2, 0:0, 17:17); PROCESS_COMMON_SCRATCH(PllMKCP, 2, 1:0, 19:18); PROCESS_COMMON_SCRATCH(PllMSetupControl, 35, 15:0, 15:0); PROCESS_COMMON_SCRATCH(PllMInputDivider, 3, 7:0, 7:0); cur_reg_value |= 0x3E << 8; PROCESS_COMMON_SCRATCH(PllMKVCO, 3, 0:0, 21:21); PROCESS_COMMON_SCRATCH(PllMKCP, 3, 1:0, 23:22); PROCESS_COMMON_SCRATCH(PllMSetupControl, 36, 23:0, 23:0); PROCESS_COMMON_SCRATCH(PllMStableTime, 4, 9:0, 9:0); PROCESS_COMMON_SCRATCH(PllMStableTime, 4, 21:0, 31:10); /* Write the final field value. */ reg::Write(PMC + cur_reg_offset, cur_reg_value); #undef PROCESS_COMMON_SCRATCH #undef PROCESS_SECURE_SCRATCH #undef PROCESS_SCRATCH #undef PROCESS_IMPL #undef RANGE_LOW #undef RANGE_HIGH } } template<fuse::SocType SocType> void InitializeSdram(void *generic_params) { /* Get converted parameters. */ auto *sdram_params = static_cast<BootSdramParams<SocType> *>(generic_params); /* Enable VDD Memory */ pmic::EnableVddMemory(SocType); /* Set VDDP select. */ reg::Write(PMC + APBDEV_PMC_VDDP_SEL, sdram_params->PmcVddpSel); util::WaitMicroSeconds(sdram_params->PmcVddpSelWait); /* If Erista, Set DDR pad voltage. */ if constexpr (SocType == fuse::SocType_Erista) { reg::Write(PMC + APBDEV_PMC_DDR_PWR, reg::Read(PMC + APBDEV_PMC_DDR_PWR)); } /* Turn on MEM IO power. */ reg::Write(PMC + APBDEV_PMC_NO_IOPOWER, sdram_params->PmcNoIoPower); reg::Write(PMC + APBDEV_PMC_REG_SHORT, sdram_params->PmcRegShort); reg::Write(PMC + APBDEV_PMC_DDR_CNTRL, sdram_params->PmcDdrCntrl); /* Apply patch 1. */ *reinterpret_cast<volatile u32 *>(sdram_params->EmcBctSpare0) = sdram_params->EmcBctSpare1; /* Do main init. */ InitializeSdramImpl<SocType>(sdram_params); /* Save parameters to scratch. */ SaveSdramParamsToScratch<SocType>(sdram_params); } } void InitializeSdram() { /* Get soc type. */ const auto soc_type = fuse::GetSocType(); /* Get Sdram params. */ void *sdram_params = GetSdramParams(soc_type); /* Perform SoC-specific init. */ if (soc_type == fuse::SocType_Erista) { InitializeSdram<fuse::SocType_Erista>(sdram_params); } else /* if (soc_type == fuse::SocType_Mariko) */ { InitializeSdram<fuse::SocType_Mariko>(sdram_params); } /* Lock DRAM scratch. */ pmc::LockSecureRegister(pmc::SecureRegister_DramParameters); } } ================================================ FILE: fusee/program/source/sdram/fusee_sdram.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot { void InitializeSdram(); } ================================================ FILE: fusee/program/source/sdram/fusee_sdram_params.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ constexpr inline const u8 SdramParamsErista0_1[0x3CB] = { #embed "../../sdram_params/lz/sdram_params_erista_0_1.lz4" }; constexpr inline const u8 * const SdramParamsErista0 = SdramParamsErista0_1; constexpr inline const size_t SdramParamsSizeErista0 = sizeof(SdramParamsErista0_1); constexpr inline const u8 * const SdramParamsErista1 = SdramParamsErista0_1; constexpr inline const size_t SdramParamsSizeErista1 = sizeof(SdramParamsErista0_1); constexpr inline const u8 SdramParamsErista2_3[0x3C7] = { #embed "../../sdram_params/lz/sdram_params_erista_2_3.lz4" }; constexpr inline const u8 * const SdramParamsErista2 = SdramParamsErista2_3; constexpr inline const size_t SdramParamsSizeErista2 = sizeof(SdramParamsErista2_3); constexpr inline const u8 * const SdramParamsErista3 = SdramParamsErista2_3; constexpr inline const size_t SdramParamsSizeErista3 = sizeof(SdramParamsErista2_3); constexpr inline const u8 SdramParamsErista4_5[0x418] = { #embed "../../sdram_params/lz/sdram_params_erista_4_5.lz4" }; constexpr inline const u8 * const SdramParamsErista4 = SdramParamsErista4_5; constexpr inline const size_t SdramParamsSizeErista4 = sizeof(SdramParamsErista4_5); constexpr inline const u8 * const SdramParamsErista5 = SdramParamsErista4_5; constexpr inline const size_t SdramParamsSizeErista5 = sizeof(SdramParamsErista4_5); constexpr inline const u8 SdramParamsErista6_7[0x3BD] = { #embed "../../sdram_params/lz/sdram_params_erista_6_7.lz4" }; constexpr inline const u8 * const SdramParamsErista6 = SdramParamsErista6_7; constexpr inline const size_t SdramParamsSizeErista6 = sizeof(SdramParamsErista6_7); constexpr inline const u8 * const SdramParamsErista7 = SdramParamsErista6_7; constexpr inline const size_t SdramParamsSizeErista7 = sizeof(SdramParamsErista6_7); constexpr inline const u8 SdramParamsMariko0_1[0x3EE] = { #embed "../../sdram_params/lz/sdram_params_mariko_0_1.lz4" }; constexpr inline const u8 * const SdramParamsMariko0 = SdramParamsMariko0_1; constexpr inline const size_t SdramParamsSizeMariko0 = sizeof(SdramParamsMariko0_1); constexpr inline const u8 * const SdramParamsMariko1 = SdramParamsMariko0_1; constexpr inline const size_t SdramParamsSizeMariko1 = sizeof(SdramParamsMariko0_1); constexpr inline const u8 SdramParamsMariko2_3[0x449] = { #embed "../../sdram_params/lz/sdram_params_mariko_2_3.lz4" }; constexpr inline const u8 * const SdramParamsMariko2 = SdramParamsMariko2_3; constexpr inline const size_t SdramParamsSizeMariko2 = sizeof(SdramParamsMariko2_3); constexpr inline const u8 * const SdramParamsMariko3 = SdramParamsMariko2_3; constexpr inline const size_t SdramParamsSizeMariko3 = sizeof(SdramParamsMariko2_3); constexpr inline const u8 SdramParamsMariko4_5[0x3F7] = { #embed "../../sdram_params/lz/sdram_params_mariko_4_5.lz4" }; constexpr inline const u8 * const SdramParamsMariko4 = SdramParamsMariko4_5; constexpr inline const size_t SdramParamsSizeMariko4 = sizeof(SdramParamsMariko4_5); constexpr inline const u8 * const SdramParamsMariko5 = SdramParamsMariko4_5; constexpr inline const size_t SdramParamsSizeMariko5 = sizeof(SdramParamsMariko4_5); constexpr inline const u8 SdramParamsMariko6_7[0x427] = { #embed "../../sdram_params/lz/sdram_params_mariko_6_7.lz4" }; constexpr inline const u8 * const SdramParamsMariko6 = SdramParamsMariko6_7; constexpr inline const size_t SdramParamsSizeMariko6 = sizeof(SdramParamsMariko6_7); constexpr inline const u8 * const SdramParamsMariko7 = SdramParamsMariko6_7; constexpr inline const size_t SdramParamsSizeMariko7 = sizeof(SdramParamsMariko6_7); constexpr inline const u8 SdramParamsMariko8_9[0x428] = { #embed "../../sdram_params/lz/sdram_params_mariko_8_9.lz4" }; constexpr inline const u8 * const SdramParamsMariko8 = SdramParamsMariko8_9; constexpr inline const size_t SdramParamsSizeMariko8 = sizeof(SdramParamsMariko8_9); constexpr inline const u8 * const SdramParamsMariko9 = SdramParamsMariko8_9; constexpr inline const size_t SdramParamsSizeMariko9 = sizeof(SdramParamsMariko8_9); constexpr inline const u8 SdramParamsMariko10_11[0x3D2] = { #embed "../../sdram_params/lz/sdram_params_mariko_10_11.lz4" }; constexpr inline const u8 * const SdramParamsMariko10 = SdramParamsMariko10_11; constexpr inline const size_t SdramParamsSizeMariko10 = sizeof(SdramParamsMariko10_11); constexpr inline const u8 * const SdramParamsMariko11 = SdramParamsMariko10_11; constexpr inline const size_t SdramParamsSizeMariko11 = sizeof(SdramParamsMariko10_11); constexpr inline const u8 SdramParamsMariko12_13[0x3C2] = { #embed "../../sdram_params/lz/sdram_params_mariko_12_13.lz4" }; constexpr inline const u8 * const SdramParamsMariko12 = SdramParamsMariko12_13; constexpr inline const size_t SdramParamsSizeMariko12 = sizeof(SdramParamsMariko12_13); constexpr inline const u8 * const SdramParamsMariko13 = SdramParamsMariko12_13; constexpr inline const size_t SdramParamsSizeMariko13 = sizeof(SdramParamsMariko12_13); ================================================ FILE: fusee/program/source/sdram/fusee_sdram_params_lp0_erista.inc ================================================ /* * Copyright (c) Atmosphre-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define FOREACH_SDRAM_SCRATCH_REGISTER_ERISTA(HANDLER) \ /* PMC SCRATCH fields. */ \ HANDLER(EmcClockSource, 6, 7:0, 15:8) \ HANDLER(EmcClockSourceDll, 6, 7:0, 23:16) \ HANDLER(EmcClockSource, 6, 31:29, 26:24) \ HANDLER(EmcClockSourceDll, 6, 31:29, 29:27) \ HANDLER(EmcClockSourceDll, 6, 11:10, 31:30) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 9:8, 1:0) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 2:1, 3:2) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 31:30, 5:4) \ HANDLER(EmcClockSource, 7, 15:15, 6:6) \ HANDLER(EmcClockSource, 7, 26:26, 7:7) \ HANDLER(EmcClockSource, 7, 20:20, 8:8) \ HANDLER(EmcClockSource, 7, 19:19, 9:9) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 13:13, 10:10) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 12:12, 11:11) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 11:11, 12:12) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 10:10, 13:13) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 5:5, 14:14) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 4:4, 15:15) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 3:3, 16:16) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 0:0, 17:17) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 1:0, 19:18) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 4:4, 20:20) \ HANDLER(EmcOdtWrite, 7, 5:0, 26:21) \ HANDLER(EmcOdtWrite, 7, 11:8, 30:27) \ HANDLER(EmcOdtWrite, 7, 31:31, 31:31) \ HANDLER(EmcFdpdCtrlCmdNoRamp, 13, 0:0, 30:30) \ HANDLER(EmcCfgPipeClk, 13, 0:0, 31:31) \ HANDLER(McEmemArbMisc2, 14, 0:0, 30:30) \ HANDLER(McDaCfg0, 14, 0:0, 31:31) \ HANDLER(EmcQRst, 15, 6:0, 26:20) \ HANDLER(EmcQRst, 15, 20:16, 31:27) \ HANDLER(EmcPmacroCmdTxDrv, 16, 5:0, 25:20) \ HANDLER(EmcPmacroCmdTxDrv, 16, 13:8, 31:26) \ HANDLER(EmcPmacroAutocalCfg0, 17, 2:0, 22:20) \ HANDLER(EmcPmacroAutocalCfg0, 17, 10:8, 25:23) \ HANDLER(EmcPmacroAutocalCfg0, 17, 18:16, 28:26) \ HANDLER(EmcPmacroAutocalCfg0, 17, 26:24, 31:29) \ HANDLER(EmcPmacroAutocalCfg1, 18, 2:0, 22:20) \ HANDLER(EmcPmacroAutocalCfg1, 18, 10:8, 25:23) \ HANDLER(EmcPmacroAutocalCfg1, 18, 18:16, 28:26) \ HANDLER(EmcPmacroAutocalCfg1, 18, 26:24, 31:29) \ HANDLER(EmcPmacroAutocalCfg2, 19, 2:0, 22:20) \ HANDLER(EmcPmacroAutocalCfg2, 19, 10:8, 25:23) \ HANDLER(EmcPmacroAutocalCfg2, 19, 18:16, 28:26) \ HANDLER(EmcPmacroAutocalCfg2, 19, 26:24, 31:29) \ HANDLER(EmcCfgRsv, 22, 31:0, 31:0) \ HANDLER(EmcAutoCalConfig, 23, 31:0, 31:0) \ HANDLER(EmcAutoCalVrefSel0, 24, 31:0, 31:0) \ HANDLER(EmcPmacroBrickCtrlRfu1, 25, 31:0, 31:0) \ HANDLER(EmcPmacroBrickCtrlRfu2, 26, 31:0, 31:0) \ HANDLER(EmcPmcScratch1, 27, 31:0, 31:0) \ HANDLER(EmcPmcScratch2, 28, 31:0, 31:0) \ HANDLER(EmcPmcScratch3, 29, 31:0, 31:0) \ HANDLER(McEmemArbDaTurns, 30, 31:0, 31:0) \ HANDLER(EmcFbioSpare, 58, 31:24, 7:0) \ HANDLER(EmcFbioSpare, 58, 23:16, 15:8) \ HANDLER(EmcFbioSpare, 58, 15:8, 23:16) \ HANDLER(EmcFbioSpare, 58, 7:2, 29:24) \ HANDLER(EmcFbioSpare, 58, 0:0, 30:30) \ HANDLER(EmcDllCfg0, 59, 29:0, 29:0) \ HANDLER(EmcPmacroDdllBypass, 60, 11:0, 11:0) \ HANDLER(EmcPmacroDdllBypass, 60, 27:13, 26:12) \ HANDLER(EmcPmacroDdllBypass, 60, 31:29, 29:27) \ HANDLER(McEmemArbMisc0, 61, 14:0, 14:0) \ HANDLER(McEmemArbMisc0, 61, 30:16, 29:15) \ HANDLER(EmcFdpdCtrlCmd, 62, 16:0, 16:0) \ HANDLER(EmcFdpdCtrlCmd, 62, 31:20, 28:17) \ HANDLER(EmcAutoCalConfig2, 63, 27:0, 27:0) \ HANDLER(EmcBurstRefreshNum, 63, 3:0, 31:28) \ HANDLER(EmcPmacroZctrl, 64, 27:0, 27:0) \ HANDLER(EmcTppd, 64, 3:0, 31:28) \ HANDLER(EmcCfgDigDll, 65, 10:0, 10:0) \ HANDLER(EmcCfgDigDll, 65, 25:12, 24:11) \ HANDLER(EmcCfgDigDll, 65, 27:27, 25:25) \ HANDLER(EmcCfgDigDll, 65, 31:30, 27:26) \ HANDLER(EmcR2r, 65, 3:0, 31:28) \ HANDLER(EmcFdpdCtrlDq, 66, 16:0, 16:0) \ HANDLER(EmcFdpdCtrlDq, 66, 28:20, 25:17) \ HANDLER(EmcFdpdCtrlDq, 66, 31:30, 27:26) \ HANDLER(EmcW2w, 66, 3:0, 31:28) \ HANDLER(EmcPmacroTxPwrd4, 67, 13:0, 13:0) \ HANDLER(EmcPmacroTxPwrd4, 67, 29:16, 27:14) \ HANDLER(EmcPmacroCommonPadTxCtrl, 67, 3:0, 31:28) \ HANDLER(EmcPmacroTxPwrd5, 68, 13:0, 13:0) \ HANDLER(EmcPmacroTxPwrd5, 68, 29:16, 27:14) \ HANDLER(EmcPmacroDdllPwrd0, 69, 4:0, 4:0) \ HANDLER(EmcPmacroDdllPwrd0, 69, 12:6, 11:5) \ HANDLER(EmcPmacroDdllPwrd0, 69, 20:14, 18:12) \ HANDLER(EmcPmacroDdllPwrd0, 69, 28:22, 25:19) \ HANDLER(EmcPmacroDdllPwrd0, 69, 31:30, 27:26) \ HANDLER(EmcCfg, 69, 4:4, 31:31) \ HANDLER(EmcPmacroDdllPwrd1, 70, 4:0, 4:0) \ HANDLER(EmcPmacroDdllPwrd1, 70, 12:6, 11:5) \ HANDLER(EmcPmacroDdllPwrd1, 70, 20:14, 18:12) \ HANDLER(EmcPmacroDdllPwrd1, 70, 28:22, 25:19) \ HANDLER(EmcPmacroDdllPwrd1, 70, 31:30, 27:26) \ HANDLER(EmcCfg, 70, 5:5, 31:31) \ HANDLER(EmcPmacroDdllPwrd2, 71, 4:0, 4:0) \ HANDLER(EmcPmacroDdllPwrd2, 71, 12:6, 11:5) \ HANDLER(EmcPmacroDdllPwrd2, 71, 20:14, 18:12) \ HANDLER(EmcPmacroDdllPwrd2, 71, 28:22, 25:19) \ HANDLER(EmcPmacroDdllPwrd2, 71, 31:30, 27:26) \ HANDLER(EmcFbioCfg5, 71, 23:20, 31:28) \ HANDLER(EmcPmacroIbVrefDq_0, 72, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDq_0, 72, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDq_0, 72, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDq_0, 72, 30:24, 27:21) \ HANDLER(EmcFbioCfg5, 72, 15:13, 30:28) \ HANDLER(EmcCfg, 72, 6:6, 31:31) \ HANDLER(EmcPmacroIbVrefDq_1, 73, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDq_1, 73, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDq_1, 73, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDq_1, 73, 30:24, 27:21) \ HANDLER(EmcCfg2, 73, 5:3, 30:28) \ HANDLER(EmcCfg, 73, 7:7, 31:31) \ HANDLER(EmcPmacroIbVrefDqs_0, 74, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDqs_0, 74, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDqs_0, 74, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDqs_0, 74, 30:24, 27:21) \ HANDLER(EmcCfg, 74, 17:16, 29:28) \ HANDLER(EmcFbioCfg5, 74, 1:0, 31:30) \ HANDLER(EmcPmacroIbVrefDqs_1, 75, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDqs_1, 75, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDqs_1, 75, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDqs_1, 75, 30:24, 27:21) \ HANDLER(EmcFbioCfg5, 75, 3:2, 29:28) \ HANDLER(EmcCfg2, 75, 27:26, 31:30) \ HANDLER(EmcPmacroDdllShortCmd_0, 76, 6:0, 6:0) \ HANDLER(EmcPmacroDdllShortCmd_0, 76, 14:8, 13:7) \ HANDLER(EmcPmacroDdllShortCmd_0, 76, 22:16, 20:14) \ HANDLER(EmcPmacroDdllShortCmd_0, 76, 30:24, 27:21) \ HANDLER(EmcPmacroCmdPadTxCtrl, 76, 3:2, 29:28) \ HANDLER(EmcPmacroCmdPadTxCtrl, 76, 7:6, 31:30) \ HANDLER(EmcPmacroDdllShortCmd_1, 77, 6:0, 6:0) \ HANDLER(EmcPmacroDdllShortCmd_1, 77, 14:8, 13:7) \ HANDLER(EmcPmacroDdllShortCmd_1, 77, 22:16, 20:14) \ HANDLER(EmcPmacroDdllShortCmd_1, 77, 30:24, 27:21) \ HANDLER(EmcPmacroCmdPadTxCtrl, 77, 11:10, 29:28) \ HANDLER(EmcPmacroCmdPadTxCtrl, 77, 15:14, 31:30) \ HANDLER(EmcAutoCalChannel, 78, 5:0, 5:0) \ HANDLER(EmcAutoCalChannel, 78, 11:8, 9:6) \ HANDLER(EmcAutoCalChannel, 78, 27:16, 21:10) \ HANDLER(EmcAutoCalChannel, 78, 31:29, 24:22) \ HANDLER(EmcConfigSampleDelay, 78, 6:0, 31:25) \ HANDLER(EmcPmacroRxTerm, 79, 5:0, 5:0) \ HANDLER(EmcPmacroRxTerm, 79, 13:8, 11:6) \ HANDLER(EmcPmacroRxTerm, 79, 21:16, 17:12) \ HANDLER(EmcPmacroRxTerm, 79, 29:24, 23:18) \ HANDLER(EmcRc, 79, 7:0, 31:24) \ HANDLER(EmcPmacroDqTxDrv, 80, 5:0, 5:0) \ HANDLER(EmcPmacroDqTxDrv, 80, 13:8, 11:6) \ HANDLER(EmcPmacroDqTxDrv, 80, 21:16, 17:12) \ HANDLER(EmcPmacroDqTxDrv, 80, 29:24, 23:18) \ HANDLER(EmcSelDpdCtrl, 80, 5:2, 27:24) \ HANDLER(EmcSelDpdCtrl, 80, 8:8, 28:28) \ HANDLER(EmcSelDpdCtrl, 80, 18:16, 31:29) \ HANDLER(EmcPmacroCaTxDrv, 81, 5:0, 5:0) \ HANDLER(EmcPmacroCaTxDrv, 81, 13:8, 11:6) \ HANDLER(EmcPmacroCaTxDrv, 81, 21:16, 17:12) \ HANDLER(EmcPmacroCaTxDrv, 81, 29:24, 23:18) \ HANDLER(EmcObdly, 81, 5:0, 29:24) \ HANDLER(EmcObdly, 81, 29:28, 31:30) \ HANDLER(EmcZcalInterval, 82, 23:10, 13:0) \ HANDLER(EmcZcalInterval, 82, 9:0, 23:14) \ HANDLER(EmcPmacroCmdRxTermMode, 82, 1:0, 25:24) \ HANDLER(EmcPmacroCmdRxTermMode, 82, 5:4, 27:26) \ HANDLER(EmcPmacroCmdRxTermMode, 82, 9:8, 29:28) \ HANDLER(EmcPmacroCmdRxTermMode, 82, 13:12, 31:30) \ HANDLER(EmcDataBrlshft0, 83, 23:0, 23:0) \ HANDLER(EmcPmacroDataRxTermMode, 83, 1:0, 25:24) \ HANDLER(EmcPmacroDataRxTermMode, 83, 5:4, 27:26) \ HANDLER(EmcPmacroDataRxTermMode, 83, 9:8, 29:28) \ HANDLER(EmcPmacroDataRxTermMode, 83, 13:12, 31:30) \ HANDLER(EmcDataBrlshft1, 84, 23:0, 23:0) \ HANDLER(McEmemArbTimingRc, 84, 7:0, 31:24) \ HANDLER(EmcDqsBrlshft0, 85, 23:0, 23:0) \ HANDLER(McEmemArbRsv, 85, 7:0, 31:24) \ HANDLER(EmcDqsBrlshft1, 86, 23:0, 23:0) \ HANDLER(EmcCfgPipe2, 87, 11:0, 11:0) \ HANDLER(EmcCfgPipe2, 87, 27:16, 23:12) \ HANDLER(EmcCfgPipe1, 88, 11:0, 11:0) \ HANDLER(EmcCfgPipe1, 88, 27:16, 23:12) \ HANDLER(EmcPmacroCmdCtrl0, 89, 5:0, 5:0) \ HANDLER(EmcPmacroCmdCtrl0, 89, 13:8, 11:6) \ HANDLER(EmcPmacroCmdCtrl0, 89, 21:16, 17:12) \ HANDLER(EmcPmacroCmdCtrl0, 89, 29:24, 23:18) \ HANDLER(EmcPmacroCmdCtrl1, 90, 5:0, 5:0) \ HANDLER(EmcPmacroCmdCtrl1, 90, 13:8, 11:6) \ HANDLER(EmcPmacroCmdCtrl1, 90, 21:16, 17:12) \ HANDLER(EmcPmacroCmdCtrl1, 90, 29:24, 23:18) \ HANDLER(EmcRas, 90, 6:0, 30:24) \ HANDLER(EmcCfg, 90, 8:8, 31:31) \ HANDLER(EmcPmacroVttgenCtrl2, 91, 23:0, 23:0) \ HANDLER(EmcW2p, 91, 6:0, 30:24) \ HANDLER(EmcCfg, 91, 9:9, 31:31) \ HANDLER(EmcPmacroCmdPadRxCtrl, 92, 2:0, 2:0) \ HANDLER(EmcPmacroCmdPadRxCtrl, 92, 5:4, 4:3) \ HANDLER(EmcPmacroCmdPadRxCtrl, 92, 10:8, 7:5) \ HANDLER(EmcPmacroCmdPadRxCtrl, 92, 22:12, 18:8) \ HANDLER(EmcPmacroCmdPadRxCtrl, 92, 28:24, 23:19) \ HANDLER(EmcQSafe, 92, 6:0, 30:24) \ HANDLER(EmcCfg, 92, 18:18, 31:31) \ HANDLER(EmcPmacroDataPadRxCtrl, 93, 2:0, 2:0) \ HANDLER(EmcPmacroDataPadRxCtrl, 93, 5:4, 4:3) \ HANDLER(EmcPmacroDataPadRxCtrl, 93, 10:8, 7:5) \ HANDLER(EmcPmacroDataPadRxCtrl, 93, 22:12, 18:8) \ HANDLER(EmcPmacroDataPadRxCtrl, 93, 28:24, 23:19) \ HANDLER(EmcRdv, 93, 6:0, 30:24) \ HANDLER(EmcCfg, 93, 21:21, 31:31) \ HANDLER(McEmemArbDaCovers, 94, 23:0, 23:0) \ HANDLER(EmcRw2Pden, 94, 6:0, 30:24) \ HANDLER(EmcCfg, 94, 22:22, 31:31) \ HANDLER(EmcPmacroCmdCtrl2, 95, 5:0, 5:0) \ HANDLER(EmcPmacroCmdCtrl2, 95, 13:9, 10:6) \ HANDLER(EmcPmacroCmdCtrl2, 95, 21:16, 16:11) \ HANDLER(EmcPmacroCmdCtrl2, 95, 29:24, 22:17) \ HANDLER(EmcRfcPb, 95, 8:0, 31:23) \ HANDLER(EmcPmacroQuseDdllRank0_0, 96, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_0, 96, 26:16, 21:11) \ HANDLER(EmcCfgUpdate, 96, 2:0, 24:22) \ HANDLER(EmcCfgUpdate, 96, 10:8, 27:25) \ HANDLER(EmcCfgUpdate, 96, 31:28, 31:28) \ HANDLER(EmcPmacroQuseDdllRank0_1, 97, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_1, 97, 26:16, 21:11) \ HANDLER(EmcRfc, 97, 9:0, 31:22) \ HANDLER(EmcPmacroQuseDdllRank0_2, 98, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_2, 98, 26:16, 21:11) \ HANDLER(EmcTxsr, 98, 9:0, 31:22) \ HANDLER(EmcPmacroQuseDdllRank0_3, 99, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_3, 99, 26:16, 21:11) \ HANDLER(EmcMc2EmcQ, 99, 2:0, 24:22) \ HANDLER(EmcMc2EmcQ, 99, 10:8, 27:25) \ HANDLER(EmcMc2EmcQ, 99, 27:24, 31:28) \ HANDLER(EmcPmacroQuseDdllRank0_4, 100, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_4, 100, 26:16, 21:11) \ HANDLER(McEmemArbRing1Throttle, 100, 4:0, 26:22) \ HANDLER(McEmemArbRing1Throttle, 100, 20:16, 31:27) \ HANDLER(EmcPmacroQuseDdllRank0_5, 101, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_5, 101, 26:16, 21:11) \ HANDLER(EmcPmacroQuseDdllRank1_0, 102, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_0, 102, 26:16, 21:11) \ HANDLER(EmcAr2Pden, 102, 8:0, 30:22) \ HANDLER(EmcCfg, 102, 23:23, 31:31) \ HANDLER(EmcPmacroQuseDdllRank1_1, 103, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_1, 103, 26:16, 21:11) \ HANDLER(EmcRfcSlr, 103, 8:0, 30:22) \ HANDLER(EmcCfg, 103, 24:24, 31:31) \ HANDLER(EmcPmacroQuseDdllRank1_2, 104, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_2, 104, 26:16, 21:11) \ HANDLER(EmcIbdly, 104, 6:0, 28:22) \ HANDLER(EmcIbdly, 104, 29:28, 30:29) \ HANDLER(EmcCfg, 104, 25:25, 31:31) \ HANDLER(EmcPmacroQuseDdllRank1_3, 105, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_3, 105, 26:16, 21:11) \ HANDLER(McEmemArbTimingRFCPB, 105, 8:0, 30:22) \ HANDLER(EmcCfg, 105, 26:26, 31:31) \ HANDLER(EmcPmacroQuseDdllRank1_4, 106, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_4, 106, 26:16, 21:11) \ HANDLER(EmcTfaw, 106, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 106, 3:2, 30:29) \ HANDLER(EmcCfg, 106, 28:28, 31:31) \ HANDLER(EmcPmacroQuseDdllRank1_5, 107, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_5, 107, 26:16, 21:11) \ HANDLER(EmcTClkStable, 107, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 107, 7:6, 30:29) \ HANDLER(EmcCfg, 107, 29:29, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_0, 108, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_0, 108, 26:16, 21:11) \ HANDLER(EmcPdex2Mrr, 108, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 108, 11:10, 30:29) \ HANDLER(EmcCfg, 108, 30:30, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_1, 109, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_1, 109, 26:16, 21:11) \ HANDLER(EmcRdvMask, 109, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 109, 15:14, 30:29) \ HANDLER(EmcCfg, 109, 31:31, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_2, 110, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_2, 110, 26:16, 21:11) \ HANDLER(EmcRdvEarlyMask, 110, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 110, 4:4, 29:29) \ HANDLER(EmcFbioCfg5, 110, 8:8, 30:30) \ HANDLER(EmcFbioCfg5, 110, 10:10, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_3, 111, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_3, 111, 26:16, 21:11) \ HANDLER(EmcRdvEarly, 111, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 111, 12:12, 29:29) \ HANDLER(EmcFbioCfg5, 111, 25:24, 31:30) \ HANDLER(EmcPmacroObDdllLongDqRank0_4, 112, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_4, 112, 26:16, 21:11) \ HANDLER(EmcPmacroDdllShortCmd_2, 112, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 112, 28:26, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank0_5, 113, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_5, 113, 26:16, 21:11) \ HANDLER(McEmemArbTimingRp, 113, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 113, 31:30, 30:29) \ HANDLER(EmcCfg2, 113, 0:0, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_0, 114, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_0, 114, 26:16, 21:11) \ HANDLER(McEmemArbTimingRas, 114, 6:0, 28:22) \ HANDLER(EmcCfg2, 114, 2:1, 30:29) \ HANDLER(EmcCfg2, 114, 7:7, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_1, 115, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_1, 115, 26:16, 21:11) \ HANDLER(McEmemArbTimingFaw, 115, 6:0, 28:22) \ HANDLER(EmcCfg2, 115, 11:10, 30:29) \ HANDLER(EmcCfg2, 115, 14:14, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_2, 123, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_2, 123, 26:16, 21:11) \ HANDLER(McEmemArbTimingRap2Pre, 123, 6:0, 28:22) \ HANDLER(EmcCfg2, 123, 16:15, 30:29) \ HANDLER(EmcCfg2, 123, 20:20, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_3, 124, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_3, 124, 26:16, 21:11) \ HANDLER(McEmemArbTimingWap2Pre, 124, 6:0, 28:22) \ HANDLER(EmcCfg2, 124, 24:22, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank1_4, 125, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_4, 125, 26:16, 21:11) \ HANDLER(McEmemArbTimingR2W, 125, 6:0, 28:22) \ HANDLER(EmcCfg2, 125, 25:25, 29:29) \ HANDLER(EmcCfg2, 125, 29:28, 31:30) \ HANDLER(EmcPmacroObDdllLongDqRank1_5, 126, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_5, 126, 26:16, 21:11) \ HANDLER(McEmemArbTimingW2R, 126, 6:0, 28:22) \ HANDLER(EmcCfg2, 126, 31:30, 30:29) \ HANDLER(EmcCfgPipe, 126, 0:0, 31:31) \ HANDLER(EmcPmacroObDdllLongDqsRank0_0, 127, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_0, 127, 26:16, 21:11) \ HANDLER(EmcRp, 127, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 127, 4:1, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_1, 128, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_1, 128, 26:16, 21:11) \ HANDLER(EmcR2w, 128, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 128, 8:5, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_2, 129, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_2, 129, 26:16, 21:11) \ HANDLER(EmcW2r, 129, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 129, 11:9, 30:28) \ HANDLER(EmcCfgPipe, 129, 16:16, 31:31) \ HANDLER(EmcPmacroObDdllLongDqsRank0_3, 130, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_3, 130, 26:16, 21:11) \ HANDLER(EmcR2p, 130, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 130, 20:17, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_4, 131, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_4, 131, 26:16, 21:11) \ HANDLER(EmcCcdmw, 131, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 131, 24:21, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_5, 132, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_5, 132, 26:16, 21:11) \ HANDLER(EmcRdRcd, 132, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 132, 27:25, 30:28) \ HANDLER(EmcPmacroTxPwrd0, 132, 0:0, 31:31) \ HANDLER(EmcPmacroObDdllLongDqsRank1_0, 133, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_0, 133, 26:16, 21:11) \ HANDLER(EmcWrRcd, 133, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 133, 4:1, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_1, 134, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_1, 134, 26:16, 21:11) \ HANDLER(EmcWdv, 134, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 134, 8:5, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_2, 135, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_2, 135, 26:16, 21:11) \ HANDLER(EmcQUse, 135, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 135, 12:9, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_3, 136, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_3, 136, 26:16, 21:11) \ HANDLER(EmcPdEx2Wr, 136, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 136, 13:13, 28:28) \ HANDLER(EmcPmacroTxPwrd0, 136, 18:16, 31:29) \ HANDLER(EmcPmacroObDdllLongDqsRank1_4, 137, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_4, 137, 26:16, 21:11) \ HANDLER(EmcPdEx2Rd, 137, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 137, 22:19, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_5, 138, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_5, 138, 26:16, 21:11) \ HANDLER(EmcPdex2Cke, 138, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 138, 26:23, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_0, 139, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_0, 139, 26:16, 21:11) \ HANDLER(EmcPChg2Pden, 139, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd0, 139, 29:27, 30:28) \ HANDLER(EmcPmacroTxPwrd1, 139, 0:0, 31:31) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_1, 140, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_1, 140, 26:16, 21:11) \ HANDLER(EmcAct2Pden, 140, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 140, 4:1, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_2, 141, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_2, 141, 26:16, 21:11) \ HANDLER(EmcCke2Pden, 141, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 141, 8:5, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_3, 142, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_3, 142, 26:16, 21:11) \ HANDLER(EmcTcke, 142, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 142, 12:9, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_0, 143, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_0, 143, 26:16, 21:11) \ HANDLER(EmcTrpab, 143, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 143, 13:13, 28:28) \ HANDLER(EmcPmacroTxPwrd1, 143, 18:16, 31:29) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_1, 144, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_1, 144, 26:16, 21:11) \ HANDLER(EmcClkenOverride, 144, 3:1, 24:22) \ HANDLER(EmcClkenOverride, 144, 8:6, 27:25) \ HANDLER(EmcPmacroTxPwrd1, 144, 22:19, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_2, 145, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_2, 145, 26:16, 21:11) \ HANDLER(EmcEInput, 145, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 145, 26:23, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_3, 146, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_3, 146, 26:16, 21:11) \ HANDLER(EmcEInputDuration, 146, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd1, 146, 29:27, 30:28) \ HANDLER(EmcPmacroTxPwrd2, 146, 0:0, 31:31) \ HANDLER(EmcPmacroDdllLongCmd_0, 147, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_0, 147, 26:16, 21:11) \ HANDLER(EmcPutermExtra, 147, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 147, 4:1, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_1, 148, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_1, 148, 26:16, 21:11) \ HANDLER(EmcTckesr, 148, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 148, 8:5, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_2, 149, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_2, 149, 26:16, 21:11) \ HANDLER(EmcTpd, 149, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 149, 12:9, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_3, 150, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_3, 150, 26:16, 21:11) \ HANDLER(EmcWdvMask, 150, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 150, 13:13, 28:28) \ HANDLER(EmcPmacroTxPwrd2, 150, 18:16, 31:29) \ HANDLER(McEmemArbCfg, 151, 8:0, 8:0) \ HANDLER(McEmemArbCfg, 151, 20:16, 13:9) \ HANDLER(McEmemArbCfg, 151, 31:24, 21:14) \ HANDLER(EmcWdvChk, 151, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 151, 22:19, 31:28) \ HANDLER(McEmemArbMisc1, 152, 12:0, 12:0) \ HANDLER(McEmemArbMisc1, 152, 25:21, 17:13) \ HANDLER(McEmemArbMisc1, 152, 31:28, 21:18) \ HANDLER(EmcCmdBrlshft0, 152, 5:0, 27:22) \ HANDLER(EmcPmacroTxPwrd2, 152, 26:23, 31:28) \ HANDLER(EmcMrsWaitCnt2, 153, 9:0, 9:0) \ HANDLER(EmcMrsWaitCnt2, 153, 26:16, 20:10) \ HANDLER(EmcPmacroIbRxrt, 153, 10:0, 31:21) \ HANDLER(EmcMrsWaitCnt, 154, 9:0, 9:0) \ HANDLER(EmcMrsWaitCnt, 154, 26:16, 20:10) \ HANDLER(EmcPmacroDdllLongCmd_4, 154, 10:0, 31:21) \ HANDLER(EmcAutoCalInterval, 155, 20:0, 20:0) \ HANDLER(McEmemArbOutstandingReq, 155, 8:0, 29:21) \ HANDLER(McEmemArbOutstandingReq, 155, 31:30, 31:30) \ HANDLER(McEmemArbRefpbHpCtrl, 156, 6:0, 6:0) \ HANDLER(McEmemArbRefpbHpCtrl, 156, 14:8, 13:7) \ HANDLER(McEmemArbRefpbHpCtrl, 156, 22:16, 20:14) \ HANDLER(EmcCmdBrlshft1, 156, 5:0, 26:21) \ HANDLER(EmcRrd, 156, 4:0, 31:27) \ HANDLER(EmcQuseBrlshft0, 157, 19:0, 19:0) \ HANDLER(EmcFbioCfg8, 157, 27:16, 31:20) \ HANDLER(EmcQuseBrlshft1, 158, 19:0, 19:0) \ HANDLER(EmcTxsrDll, 158, 11:0, 31:20) \ HANDLER(EmcQuseBrlshft2, 159, 19:0, 19:0) \ HANDLER(EmcTxdsrvttgen, 159, 11:0, 31:20) \ HANDLER(EmcQuseBrlshft3, 160, 19:0, 19:0) \ HANDLER(EmcPmacroVttgenCtrl0, 160, 3:0, 23:20) \ HANDLER(EmcPmacroVttgenCtrl0, 160, 11:8, 27:24) \ HANDLER(EmcPmacroVttgenCtrl0, 160, 19:16, 31:28) \ HANDLER(EmcPmacroVttgenCtrl1, 161, 19:0, 19:0) \ HANDLER(EmcCmdBrlshft2, 161, 5:0, 25:20) \ HANDLER(EmcCmdBrlshft3, 161, 5:0, 31:26) \ HANDLER(EmcAutoCalConfig3, 162, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig3, 162, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig3, 162, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig3, 162, 22:20, 17:15) \ HANDLER(EmcTRefBw, 162, 13:0, 31:18) \ HANDLER(EmcAutoCalConfig4, 163, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig4, 163, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig4, 163, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig4, 163, 22:20, 17:15) \ HANDLER(EmcQpop, 163, 6:0, 24:18) \ HANDLER(EmcQpop, 163, 22:16, 31:25) \ HANDLER(EmcAutoCalConfig5, 164, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig5, 164, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig5, 164, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig5, 164, 22:20, 17:15) \ HANDLER(EmcPmacroAutocalCfgCommon, 164, 5:0, 23:18) \ HANDLER(EmcPmacroAutocalCfgCommon, 164, 13:8, 29:24) \ HANDLER(EmcPmacroAutocalCfgCommon, 164, 16:16, 30:30) \ HANDLER(EmcPmacroTxPwrd2, 164, 27:27, 31:31) \ HANDLER(EmcAutoCalConfig6, 165, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig6, 165, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig6, 165, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig6, 165, 22:20, 17:15) \ HANDLER(EmcWev, 165, 5:0, 23:18) \ HANDLER(EmcWsv, 165, 5:0, 29:24) \ HANDLER(EmcPmacroTxPwrd2, 165, 29:28, 31:30) \ HANDLER(EmcAutoCalConfig7, 166, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig7, 166, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig7, 166, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig7, 166, 22:20, 17:15) \ HANDLER(EmcCfg3, 166, 2:0, 20:18) \ HANDLER(EmcCfg3, 166, 6:4, 23:21) \ HANDLER(EmcQuseWidth, 166, 3:0, 27:24) \ HANDLER(EmcQuseWidth, 166, 29:28, 29:28) \ HANDLER(EmcPmacroTxPwrd3, 166, 1:0, 31:30) \ HANDLER(EmcAutoCalConfig8, 167, 5:0, 5:0) \ HANDLER(EmcAutoCalConfig8, 167, 13:8, 11:6) \ HANDLER(EmcAutoCalConfig8, 167, 18:16, 14:12) \ HANDLER(EmcAutoCalConfig8, 167, 22:20, 17:15) \ HANDLER(EmcPmacroBgBiasCtrl0, 167, 2:0, 20:18) \ HANDLER(EmcPmacroBgBiasCtrl0, 167, 6:4, 23:21) \ HANDLER(McEmemArbTimingRcd, 167, 5:0, 29:24) \ HANDLER(EmcPmacroTxPwrd3, 167, 3:2, 31:30) \ HANDLER(EmcXm2CompPadCtrl2, 168, 17:0, 17:0) \ HANDLER(McEmemArbTimingCcdmw, 168, 5:0, 23:18) \ HANDLER(McEmemArbOverride, 168, 27:27, 24:24) \ HANDLER(McEmemArbOverride, 168, 26:26, 25:25) \ HANDLER(McEmemArbOverride, 168, 16:16, 26:26) \ HANDLER(McEmemArbOverride, 168, 10:10, 27:27) \ HANDLER(McEmemArbOverride, 168, 4:4, 28:28) \ HANDLER(McEmemArbOverride, 168, 3:3, 29:29) \ HANDLER(EmcPmacroTxPwrd3, 168, 5:4, 31:30) \ HANDLER(EmcXm2CompPadCtrl3, 169, 17:0, 17:0) \ HANDLER(EmcRext, 169, 4:0, 22:18) \ HANDLER(EmcTClkStop, 169, 4:0, 27:23) \ HANDLER(EmcPmacroTxPwrd3, 169, 9:6, 31:28) \ HANDLER(EmcZcalWaitCnt, 170, 10:0, 10:0) \ HANDLER(EmcZcalWaitCnt, 170, 21:16, 16:11) \ HANDLER(EmcZcalWaitCnt, 170, 31:31, 17:17) \ HANDLER(EmcWext, 170, 4:0, 22:18) \ HANDLER(EmcRefctrl2, 170, 0:0, 23:23) \ HANDLER(EmcRefctrl2, 170, 26:24, 26:24) \ HANDLER(EmcRefctrl2, 170, 31:31, 27:27) \ HANDLER(EmcPmacroTxPwrd3, 170, 13:10, 31:28) \ HANDLER(EmcZcalMrwCmd, 171, 7:0, 7:0) \ HANDLER(EmcZcalMrwCmd, 171, 23:16, 15:8) \ HANDLER(EmcZcalMrwCmd, 171, 31:30, 17:16) \ HANDLER(EmcWeDuration, 171, 4:0, 22:18) \ HANDLER(EmcWsDuration, 171, 4:0, 27:23) \ HANDLER(EmcPmacroTxPwrd3, 171, 19:16, 31:28) \ HANDLER(EmcSwizzleRank0Byte0, 172, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte0, 172, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte0, 172, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte0, 172, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte0, 172, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte0, 172, 22:20, 17:15) \ HANDLER(EmcPutermWidth, 172, 31:31, 18:18) \ HANDLER(EmcPutermWidth, 172, 3:0, 22:19) \ HANDLER(McEmemArbTimingRrd, 172, 4:0, 27:23) \ HANDLER(EmcPmacroTxPwrd3, 172, 23:20, 31:28) \ HANDLER(EmcSwizzleRank0Byte1, 173, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte1, 173, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte1, 173, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte1, 173, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte1, 173, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte1, 173, 22:20, 17:15) \ HANDLER(McEmemArbTimingR2R, 173, 4:0, 22:18) \ HANDLER(McEmemArbTimingW2W, 173, 4:0, 27:23) \ HANDLER(EmcPmacroTxPwrd3, 173, 27:24, 31:28) \ HANDLER(EmcSwizzleRank0Byte2, 174, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte2, 174, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte2, 174, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte2, 174, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte2, 174, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte2, 174, 22:20, 17:15) \ HANDLER(EmcPmacroTxPwrd3, 174, 29:28, 19:18) \ HANDLER(EmcPmacroTxSelClkSrc0, 174, 11:0, 31:20) \ HANDLER(EmcSwizzleRank0Byte3, 175, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte3, 175, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte3, 175, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte3, 175, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte3, 175, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte3, 175, 22:20, 17:15) \ HANDLER(EmcPmacroTxSelClkSrc0, 175, 27:16, 29:18) \ HANDLER(EmcPmacroTxSelClkSrc1, 175, 1:0, 31:30) \ HANDLER(EmcSwizzleRank1Byte0, 176, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte0, 176, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte0, 176, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte0, 176, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte0, 176, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte0, 176, 22:20, 17:15) \ HANDLER(EmcPmacroTxSelClkSrc1, 176, 11:2, 27:18) \ HANDLER(EmcPmacroTxSelClkSrc1, 176, 19:16, 31:28) \ HANDLER(EmcSwizzleRank1Byte1, 177, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte1, 177, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte1, 177, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte1, 177, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte1, 177, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte1, 177, 22:20, 17:15) \ HANDLER(EmcPmacroTxSelClkSrc1, 177, 27:20, 25:18) \ HANDLER(EmcPmacroTxSelClkSrc3, 177, 5:0, 31:26) \ HANDLER(EmcSwizzleRank1Byte2, 178, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte2, 178, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte2, 178, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte2, 178, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte2, 178, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte2, 178, 22:20, 17:15) \ HANDLER(EmcPmacroTxSelClkSrc3, 178, 11:6, 23:18) \ HANDLER(EmcPmacroTxSelClkSrc3, 178, 23:16, 31:24) \ HANDLER(EmcSwizzleRank1Byte3, 179, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte3, 179, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte3, 179, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte3, 179, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte3, 179, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte3, 179, 22:20, 17:15) \ HANDLER(EmcPmacroTxSelClkSrc3, 179, 27:24, 21:18) \ HANDLER(EmcPmacroTxSelClkSrc2, 179, 9:0, 31:22) \ HANDLER(EmcPmacroCmdBrickCtrlFdpd, 180, 17:0, 17:0) \ HANDLER(EmcPmacroTxSelClkSrc2, 180, 11:10, 19:18) \ HANDLER(EmcPmacroTxSelClkSrc2, 180, 27:16, 31:20) \ HANDLER(EmcPmacroDataBrickCtrlFdpd, 181, 17:0, 17:0) \ HANDLER(EmcPmacroTxSelClkSrc4, 181, 11:0, 29:18) \ HANDLER(EmcPmacroTxSelClkSrc4, 181, 17:16, 31:30) \ HANDLER(EmcFbioCfg7, 182, 16:0, 16:0) \ HANDLER(McEmemArbRefpbBankCtrl, 182, 6:0, 23:17) \ HANDLER(McEmemArbRefpbBankCtrl, 182, 14:8, 30:24) \ HANDLER(McEmemArbRefpbBankCtrl, 182, 31:31, 31:31) \ HANDLER(EmcDynSelfRefControl, 183, 15:0, 15:0) \ HANDLER(EmcDynSelfRefControl, 183, 31:31, 16:16) \ HANDLER(EmcPmacroTxSelClkSrc4, 183, 27:18, 26:17) \ HANDLER(EmcPmacroTxSelClkSrc5, 183, 4:0, 31:27) \ HANDLER(EmcDllCfg1, 184, 16:0, 16:0) \ HANDLER(EmcPmacroTxSelClkSrc5, 184, 11:5, 23:17) \ HANDLER(EmcPmacroTxSelClkSrc5, 184, 23:16, 31:24) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 1:0, 1:0) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 6:5, 3:2) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 11:9, 6:4) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 13:13, 7:7) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 17:16, 9:8) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 21:20, 11:10) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 25:24, 13:12) \ HANDLER(EmcPmacroPadCfgCtrl, 185, 30:28, 16:14) \ HANDLER(EmcPmacroTxSelClkSrc5, 185, 27:24, 20:17) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 1:0, 22:21) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 5:4, 24:23) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 9:8, 26:25) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 13:12, 28:27) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 16:16, 29:29) \ HANDLER(EmcPmacroCmdPadTxCtrl, 185, 21:20, 31:30) \ HANDLER(EmcRefresh, 186, 15:0, 15:0) \ HANDLER(EmcCmdQ, 186, 4:0, 20:16) \ HANDLER(EmcCmdQ, 186, 10:8, 23:21) \ HANDLER(EmcCmdQ, 186, 14:12, 26:24) \ HANDLER(EmcCmdQ, 186, 28:24, 31:27) \ HANDLER(EmcAcpdControl, 187, 15:0, 15:0) \ HANDLER(EmcAutoCalVrefSel1, 187, 15:0, 31:16) \ HANDLER(EmcXm2CompPadCtrl, 188, 1:0, 1:0) \ HANDLER(EmcXm2CompPadCtrl, 188, 6:3, 5:2) \ HANDLER(EmcXm2CompPadCtrl, 188, 9:9, 6:6) \ HANDLER(EmcXm2CompPadCtrl, 188, 19:11, 15:7) \ HANDLER(EmcCfgDigDllPeriod, 188, 15:0, 31:16) \ HANDLER(EmcCfgDigDll_1, 189, 15:0, 15:0) \ HANDLER(EmcPreRefreshReqCnt, 189, 15:0, 31:16) \ HANDLER(EmcPmacroCmdPadTxCtrl, 190, 27:24, 19:16) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 1:0, 21:20) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 5:4, 23:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 9:8, 25:24) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 13:12, 27:26) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 16:16, 28:28) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 21:20, 30:29) \ HANDLER(EmcPmacroDataPadTxCtrl, 190, 24:24, 31:31) \ HANDLER(EmcPmacroDataPadTxCtrl, 191, 27:25, 2:0) \ HANDLER(EmcPinGpio, 8, 1:0, 31:30) \ HANDLER(EmcPinGpioEn, 9, 1:0, 31:30) \ HANDLER(EmcDevSelect, 10, 1:0, 31:30) \ HANDLER(EmcZcalWarmColdBootEnables, 11, 1:0, 31:30) \ HANDLER(EmcCfgDigDllPeriodWarmBoot, 12, 1:0, 31:30) \ HANDLER(EmcBctSpare13, 31, 31:0, 31:0) \ HANDLER(EmcBctSpare12, 32, 31:0, 31:0) \ HANDLER(EmcBctSpare7, 33, 31:0, 31:0) \ HANDLER(EmcBctSpare6, 40, 31:0, 31:0) \ HANDLER(EmcBctSpare5, 42, 31:0, 31:0) \ HANDLER(EmcBctSpare4, 44, 31:0, 31:0) \ HANDLER(EmcBctSpare3, 45, 31:0, 31:0) \ HANDLER(EmcBctSpare2, 46, 31:0, 31:0) \ HANDLER(EmcBctSpare1, 47, 31:0, 31:0) \ HANDLER(EmcBctSpare0, 48, 31:0, 31:0) \ HANDLER(EmcBctSpare9, 50, 31:0, 31:0) \ HANDLER(EmcBctSpare8, 51, 31:0, 31:0) \ HANDLER(BootRomPatchData, 56, 31:0, 31:0) \ HANDLER(BootRomPatchControl, 57, 31:0, 31:0) \ HANDLER(McClkenOverrideAllWarmBoot, 58, 0:0, 31:31) \ HANDLER(EmcClkenOverrideAllWarmBoot, 59, 0:0, 30:30) \ HANDLER(EmcMrsWarmBootEnable, 59, 0:0, 31:31) \ HANDLER(ClearClk2Mc1, 60, 0:0, 30:30) \ HANDLER(EmcWarmBootExtraModeRegWriteEnable, 60, 0:0, 31:31) \ HANDLER(ClkRstControllerPllmMisc2OverrideEnable, 61, 0:0, 30:30) \ HANDLER(EmcDbgWriteMux, 61, 0:0, 31:31) \ HANDLER(EmcExtraRefreshNum, 62, 2:0, 31:29) \ HANDLER(PmcIoDpd3ReqWait, 68, 2:0, 30:28) \ HANDLER(AhbArbitrationXbarCtrlMemInitDone, 68, 0:0, 31:31) \ HANDLER(MemoryType, 69, 2:0, 30:28) \ HANDLER(PmcIoDpd4ReqWait, 70, 2:0, 30:28) \ HANDLER(EmcTimingControlWait, 86, 7:0, 31:24) \ HANDLER(EmcZcalWarmBootWait, 87, 7:0, 31:24) \ HANDLER(WarmBootWait, 88, 7:0, 31:24) \ HANDLER(EmcPinProgramWait, 89, 7:0, 31:24) \ HANDLER(EmcAutoCalWait, 101, 9:0, 31:22) \ HANDLER(SwizzleRankByteEncode, 190, 15:0, 15:0) \ \ /* PMC SCRATCH fields for LPDDR2. */ \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 5, 23:16, 7:0) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 5, 7:0, 15:8) \ HANDLER(EmcWarmBootMrwExtra, 5, 23:16, 23:16) \ HANDLER(EmcWarmBootMrwExtra, 5, 7:0, 31:24) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 6, 31:30, 1:0) \ HANDLER(EmcWarmBootMrwExtra, 6, 31:30, 3:2) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 6, 27:26, 5:4) \ HANDLER(EmcWarmBootMrwExtra, 6, 27:26, 7:6) \ HANDLER(EmcMrw6, 8, 27:0, 27:0) \ HANDLER(EmcMrw6, 8, 31:30, 29:28) \ HANDLER(EmcMrw8, 9, 27:0, 27:0) \ HANDLER(EmcMrw8, 9, 31:30, 29:28) \ HANDLER(EmcMrw9, 10, 27:0, 27:0) \ HANDLER(EmcMrw9, 10, 31:30, 29:28) \ HANDLER(EmcMrw10, 11, 27:0, 27:0) \ HANDLER(EmcMrw10, 11, 31:30, 29:28) \ HANDLER(EmcMrw12, 12, 27:0, 27:0) \ HANDLER(EmcMrw12, 12, 31:30, 29:28) \ HANDLER(EmcMrw13, 13, 27:0, 27:0) \ HANDLER(EmcMrw13, 13, 31:30, 29:28) \ HANDLER(EmcMrw14, 14, 27:0, 27:0) \ HANDLER(EmcMrw14, 14, 31:30, 29:28) \ HANDLER(EmcMrw1, 15, 7:0, 7:0) \ HANDLER(EmcMrw1, 15, 23:16, 15:8) \ HANDLER(EmcMrw1, 15, 27:26, 17:16) \ HANDLER(EmcMrw1, 15, 31:30, 19:18) \ HANDLER(EmcWarmBootMrwExtra, 16, 7:0, 7:0) \ HANDLER(EmcWarmBootMrwExtra, 16, 23:16, 15:8) \ HANDLER(EmcWarmBootMrwExtra, 16, 27:26, 17:16) \ HANDLER(EmcWarmBootMrwExtra, 16, 31:30, 19:18) \ HANDLER(EmcMrw2, 17, 7:0, 7:0) \ HANDLER(EmcMrw2, 17, 23:16, 15:8) \ HANDLER(EmcMrw2, 17, 27:26, 17:16) \ HANDLER(EmcMrw2, 17, 31:30, 19:18) \ HANDLER(EmcMrw3, 18, 7:0, 7:0) \ HANDLER(EmcMrw3, 18, 23:16, 15:8) \ HANDLER(EmcMrw3, 18, 27:26, 17:16) \ HANDLER(EmcMrw3, 18, 31:30, 19:18) \ HANDLER(EmcMrw4, 19, 7:0, 7:0) \ HANDLER(EmcMrw4, 19, 23:16, 15:8) \ HANDLER(EmcMrw4, 19, 27:26, 17:16) \ HANDLER(EmcMrw4, 19, 31:30, 19:18) #define FOREACH_SDRAM_SECURE_SCRATCH_REGISTER_ERISTA(HANDLER) \ /* PMC SECURE_SCRATCH fields. */ \ HANDLER(EmcCmdMappingByte, 8, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping0, 9, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping1, 10, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping2, 11, 31:0, 31:0) \ HANDLER(McVideoProtectGpuOverride0, 12, 31:0, 31:0) \ HANDLER(EmcCmdMappingCmd0_0, 13, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_0, 13, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_0, 13, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_0, 13, 30:24, 27:21) \ HANDLER(McVideoProtectBomAdrHi, 13, 1:0, 29:28) \ HANDLER(McVideoProtectWriteAccess, 13, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd0_1, 14, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_1, 14, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_1, 14, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_1, 14, 30:24, 27:21) \ HANDLER(McSecCarveoutAdrHi, 14, 1:0, 29:28) \ HANDLER(McMtsCarveoutAdrHi, 14, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd1_0, 15, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_0, 15, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_0, 15, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_0, 15, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout5BomHi, 15, 1:0, 29:28) \ HANDLER(McGeneralizedCarveout3BomHi, 15, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd1_1, 16, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_1, 16, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_1, 16, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_1, 16, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout2BomHi, 16, 1:0, 29:28) \ HANDLER(McGeneralizedCarveout4BomHi, 16, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd2_0, 17, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_0, 17, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_0, 17, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_0, 17, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout1BomHi, 17, 1:0, 29:28) \ HANDLER(EmcAdrCfg, 17, 0:0, 30:30) \ HANDLER(EmcFbioSpare, 17, 1:1, 31:31) \ HANDLER(EmcCmdMappingCmd2_1, 18, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_1, 18, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_1, 18, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_1, 18, 30:24, 27:21) \ HANDLER(EmcFbioCfg8, 18, 15:15, 28:28) \ HANDLER(McEmemAdrCfg, 18, 0:0, 29:29) \ HANDLER(McSecCarveoutProtectWriteAccess, 18, 0:0, 30:30) \ HANDLER(McMtsCarveoutRegCtrl, 18, 0:0, 31:31) \ HANDLER(EmcCmdMappingCmd3_0, 19, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_0, 19, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_0, 19, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_0, 19, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout2Cfg0, 19, 6:3, 31:28) \ HANDLER(EmcCmdMappingCmd3_1, 20, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_1, 20, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_1, 20, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_1, 20, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout2Cfg0, 20, 10:7, 31:28) \ HANDLER(McGeneralizedCarveout4Cfg0, 39, 26:0, 26:0) \ HANDLER(McGeneralizedCarveout2Cfg0, 39, 17:14, 30:27) \ HANDLER(McVideoProtectVprOverride, 39, 0:0, 31:31) \ HANDLER(McGeneralizedCarveout5Cfg0, 40, 26:0, 26:0) \ HANDLER(McGeneralizedCarveout2Cfg0, 40, 21:18, 30:27) \ HANDLER(McVideoProtectVprOverride, 40, 1:1, 31:31) \ HANDLER(EmcCmdMappingCmd0_2, 41, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_2, 41, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_2, 41, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_2, 41, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 41, 6:3, 28:25) \ HANDLER(McGeneralizedCarveout2Cfg0, 41, 13:11, 31:29) \ HANDLER(EmcCmdMappingCmd1_2, 42, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_2, 42, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_2, 42, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_2, 42, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 42, 13:7, 31:25) \ HANDLER(EmcCmdMappingCmd2_2, 43, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_2, 43, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_2, 43, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_2, 43, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 43, 17:14, 28:25) \ HANDLER(McGeneralizedCarveout3Cfg0, 43, 13:11, 31:29) \ HANDLER(EmcCmdMappingCmd3_2, 44, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_2, 44, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_2, 44, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_2, 44, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 44, 21:18, 28:25) \ HANDLER(McVideoProtectVprOverride, 44, 3:2, 30:29) \ HANDLER(McVideoProtectVprOverride, 44, 6:6, 31:31) \ HANDLER(McEmemAdrCfgChannelMask, 45, 31:9, 22:0) \ HANDLER(McEmemAdrCfgDev0, 45, 2:0, 25:23) \ HANDLER(McEmemAdrCfgDev0, 45, 9:8, 27:26) \ HANDLER(McEmemAdrCfgDev0, 45, 19:16, 31:28) \ HANDLER(McEmemAdrCfgBankMask0, 46, 31:10, 21:0) \ HANDLER(McEmemAdrCfgDev1, 46, 2:0, 24:22) \ HANDLER(McEmemAdrCfgDev1, 46, 9:8, 26:25) \ HANDLER(McEmemAdrCfgDev1, 46, 19:16, 30:27) \ HANDLER(McVideoProtectVprOverride, 46, 7:7, 31:31) \ HANDLER(McEmemAdrCfgBankMask1, 47, 31:10, 21:0) \ HANDLER(McGeneralizedCarveout3Cfg0, 47, 10:3, 29:22) \ HANDLER(McVideoProtectVprOverride, 47, 9:8, 31:30) \ HANDLER(McEmemAdrCfgBankMask2, 48, 31:10, 21:0) \ HANDLER(McGeneralizedCarveout3Cfg0, 48, 21:14, 29:22) \ HANDLER(McVideoProtectVprOverride, 48, 11:11, 30:30) \ HANDLER(McVideoProtectVprOverride, 48, 14:14, 31:31) \ HANDLER(McVideoProtectGpuOverride1, 49, 15:0, 15:0) \ HANDLER(McEmemCfg, 49, 13:0, 29:16) \ HANDLER(McEmemCfg, 49, 31:31, 30:30) \ HANDLER(McVideoProtectVprOverride, 49, 15:15, 31:31) \ HANDLER(McGeneralizedCarveout3Bom, 50, 31:17, 14:0) \ HANDLER(McGeneralizedCarveout1Bom, 50, 31:17, 29:15) \ HANDLER(McVideoProtectVprOverride, 50, 18:17, 31:30) \ HANDLER(McGeneralizedCarveout4Bom, 51, 31:17, 14:0) \ HANDLER(McGeneralizedCarveout2Bom, 51, 31:17, 29:15) \ HANDLER(McVideoProtectVprOverride, 51, 20:19, 31:30) \ HANDLER(McGeneralizedCarveout5Bom, 52, 31:17, 14:0) \ HANDLER(McVideoProtectBom, 52, 31:20, 26:15) \ HANDLER(McVideoProtectVprOverride, 52, 23:21, 29:27) \ HANDLER(McVideoProtectVprOverride, 52, 26:26, 30:30) \ HANDLER(McVideoProtectVprOverride, 52, 29:29, 31:31) \ HANDLER(McVideoProtectSizeMb, 53, 11:0, 11:0) \ HANDLER(McSecCarveoutBom, 53, 31:20, 23:12) \ HANDLER(McVideoProtectVprOverride, 53, 31:30, 25:24) \ HANDLER(McVideoProtectVprOverride1, 53, 1:0, 27:26) \ HANDLER(McVideoProtectVprOverride1, 53, 7:4, 31:28) \ HANDLER(McSecCarveoutSizeMb, 54, 11:0, 11:0) \ HANDLER(McMtsCarveoutBom, 54, 31:20, 23:12) \ HANDLER(McVideoProtectVprOverride1, 54, 15:8, 31:24) \ HANDLER(McMtsCarveoutSizeMb, 55, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout4Size128kb, 55, 11:0, 23:12) \ HANDLER(McVideoProtectVprOverride1, 55, 16:16, 24:24) \ HANDLER(McGeneralizedCarveout2Cfg0, 55, 2:0, 27:25) \ HANDLER(McGeneralizedCarveout2Cfg0, 55, 25:22, 31:28) \ HANDLER(McGeneralizedCarveout3Size128kb, 56, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout2Size128kb, 56, 11:0, 23:12) \ HANDLER(McGeneralizedCarveout2Cfg0, 56, 26:26, 24:24) \ HANDLER(McGeneralizedCarveout1Cfg0, 56, 2:0, 27:25) \ HANDLER(McGeneralizedCarveout1Cfg0, 56, 25:22, 31:28) \ HANDLER(McGeneralizedCarveout1Size128kb, 57, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout5Size128kb, 57, 11:0, 23:12) \ HANDLER(McGeneralizedCarveout1Cfg0, 57, 26:26, 24:24) \ HANDLER(McGeneralizedCarveout3Cfg0, 57, 2:0, 27:25) \ HANDLER(McGeneralizedCarveout3Cfg0, 57, 25:22, 31:28) \ HANDLER(McGeneralizedCarveout3Cfg0, 58, 26:26, 0:0) \ HANDLER(McGeneralizedCarveout1Access0, 59, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access1, 60, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access2, 61, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access3, 62, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access4, 63, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access0, 64, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access1, 65, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access2, 66, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access3, 67, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access4, 68, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access0, 69, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access1, 70, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access2, 71, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access3, 72, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access4, 73, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access0, 74, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access1, 75, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access2, 76, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access3, 77, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access4, 78, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access0, 79, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access1, 80, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access2, 81, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access3, 82, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess0, 84, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess1, 85, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess2, 86, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess3, 87, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess4, 88, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess0, 89, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess1, 90, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess2, 91, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess3, 92, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess4, 93, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess0, 94, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess1, 95, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess2, 96, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess3, 97, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess4, 98, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess0, 99, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess1, 100, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess2, 101, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess3, 102, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess4, 103, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess0, 104, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess1, 105, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess2, 106, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess3, 107, 31:0, 31:0) ================================================ FILE: fusee/program/source/sdram/fusee_sdram_params_lp0_mariko.inc ================================================ /* * Copyright (c) Atmosphre-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define FOREACH_SDRAM_SCRATCH_REGISTER_MARIKO(HANDLER) \ /* PMC SCRATCH fields. */ \ HANDLER(EmcClockSource, 6, 7:0, 15:8) \ HANDLER(EmcClockSourceDll, 6, 7:0, 23:16) \ HANDLER(EmcClockSource, 6, 31:29, 26:24) \ HANDLER(EmcClockSourceDll, 6, 31:29, 29:27) \ HANDLER(EmcClockSourceDll, 6, 11:10, 31:30) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 9:8, 1:0) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 2:1, 3:2) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 31:30, 5:4) \ HANDLER(EmcClockSource, 7, 27:27, 6:6) \ HANDLER(EmcClockSource, 7, 26:26, 7:7) \ HANDLER(EmcClockSource, 7, 15:15, 8:8) \ HANDLER(EmcClockSource, 7, 25:25, 9:9) \ HANDLER(EmcClockSource, 7, 20:19, 11:10) \ HANDLER(EmcClockSource, 7, 16:16, 12:12) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 13:13, 13:13) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 12:12, 14:14) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 11:11, 15:15) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 10:10, 16:16) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 5:5, 17:17) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 4:4, 18:18) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 3:3, 19:19) \ HANDLER(ClkRstControllerPllmMisc2Override, 7, 0:0, 20:20) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 1:0, 22:21) \ HANDLER(EmcZqCalLpDdr4WarmBoot, 7, 4:4, 23:23) \ HANDLER(EmcRc, 7, 7:0, 31:24) \ HANDLER(EmcPmacroBgBiasCtrl0, 8, 13:12, 31:30) \ HANDLER(EmcFdpdCtrlCmdNoRamp, 14, 0:0, 30:30) \ HANDLER(EmcCfgPipeClk, 14, 0:0, 31:31) \ HANDLER(EmcQRst, 15, 6:0, 26:20) \ HANDLER(EmcQRst, 15, 20:16, 31:27) \ HANDLER(EmcPmacroCmdTxDrv, 16, 5:0, 25:20) \ HANDLER(EmcPmacroCmdTxDrv, 16, 13:8, 31:26) \ HANDLER(EmcFbioCfg8, 17, 27:16, 31:20) \ HANDLER(EmcTxsrDll, 18, 11:0, 31:20) \ HANDLER(EmcTxdsrvttgen, 19, 11:0, 31:20) \ HANDLER(EmcCfgRsv, 22, 31:0, 31:0) \ HANDLER(EmcAutoCalConfig, 23, 31:0, 31:0) \ HANDLER(EmcAutoCalVrefSel0, 24, 31:0, 31:0) \ HANDLER(EmcPmacroBrickCtrlRfu1, 25, 31:0, 31:0) \ HANDLER(EmcPmacroBrickCtrlRfu2, 26, 31:0, 31:0) \ HANDLER(EmcPmcScratch1, 27, 31:0, 31:0) \ HANDLER(EmcPmcScratch2, 28, 31:0, 31:0) \ HANDLER(EmcPmcScratch3, 29, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl0, 30, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl1, 31, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl2, 32, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl3, 33, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl4, 40, 31:0, 31:0) \ HANDLER(EmcPmacroPerbitRfuCtrl5, 42, 31:0, 31:0) \ HANDLER(McEmemArbDaTurns, 44, 31:0, 31:0) \ HANDLER(EmcFbioSpare, 64, 31:24, 7:0) \ HANDLER(EmcFbioSpare, 64, 23:16, 15:8) \ HANDLER(EmcFbioSpare, 64, 15:8, 23:16) \ HANDLER(EmcFbioSpare, 64, 7:2, 29:24) \ HANDLER(EmcFbioSpare, 64, 0:0, 30:30) \ HANDLER(McEmemArbMisc2, 64, 0:0, 31:31) \ HANDLER(McEmemArbMisc0, 65, 14:0, 14:0) \ HANDLER(McEmemArbMisc0, 65, 30:16, 29:15) \ HANDLER(McDaCfg0, 65, 0:0, 30:30) \ HANDLER(EmcFdpdCtrlCmd, 66, 16:0, 16:0) \ HANDLER(EmcFdpdCtrlCmd, 66, 31:20, 28:17) \ HANDLER(EmcAutoCalConfig2, 67, 27:0, 27:0) \ HANDLER(EmcBurstRefreshNum, 67, 3:0, 31:28) \ HANDLER(EmcCfgDigDll, 68, 10:0, 10:0) \ HANDLER(EmcCfgDigDll, 68, 25:12, 24:11) \ HANDLER(EmcCfgDigDll, 68, 27:27, 25:25) \ HANDLER(EmcCfgDigDll, 68, 31:30, 27:26) \ HANDLER(EmcTppd, 68, 3:0, 31:28) \ HANDLER(EmcFdpdCtrlDq, 69, 16:0, 16:0) \ HANDLER(EmcFdpdCtrlDq, 69, 28:20, 25:17) \ HANDLER(EmcFdpdCtrlDq, 69, 31:30, 27:26) \ HANDLER(EmcR2r, 69, 3:0, 31:28) \ HANDLER(EmcPmacroIbVrefDq_0, 70, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDq_0, 70, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDq_0, 70, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDq_0, 70, 30:24, 27:21) \ HANDLER(EmcW2w, 70, 3:0, 31:28) \ HANDLER(EmcPmacroIbVrefDq_1, 71, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDq_1, 71, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDq_1, 71, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDq_1, 71, 30:24, 27:21) \ HANDLER(EmcPmacroVttgenCtrl0, 71, 19:16, 31:28) \ HANDLER(EmcPmacroIbVrefDqs_0, 72, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDqs_0, 72, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDqs_0, 72, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDqs_0, 72, 30:24, 27:21) \ HANDLER(EmcPmacroIbVrefDqs_1, 73, 6:0, 6:0) \ HANDLER(EmcPmacroIbVrefDqs_1, 73, 14:8, 13:7) \ HANDLER(EmcPmacroIbVrefDqs_1, 73, 22:16, 20:14) \ HANDLER(EmcPmacroIbVrefDqs_1, 73, 30:24, 27:21) \ HANDLER(EmcPmacroDdllShortCmd_0, 74, 6:0, 6:0) \ HANDLER(EmcPmacroDdllShortCmd_0, 74, 14:8, 13:7) \ HANDLER(EmcPmacroDdllShortCmd_0, 74, 22:16, 20:14) \ HANDLER(EmcPmacroDdllShortCmd_0, 74, 30:24, 27:21) \ HANDLER(EmcPmacroDdllShortCmd_1, 75, 6:0, 6:0) \ HANDLER(EmcPmacroDdllShortCmd_1, 75, 14:8, 13:7) \ HANDLER(EmcPmacroDdllShortCmd_1, 75, 22:16, 20:14) \ HANDLER(EmcPmacroDdllShortCmd_1, 75, 30:24, 27:21) \ HANDLER(EmcPmacroDllCfg0, 76, 29:4, 25:0) \ HANDLER(EmcRp, 76, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd0, 77, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd0, 77, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd0, 77, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd0, 77, 29:28, 25:24) \ HANDLER(EmcR2w, 77, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd1, 78, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd1, 78, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd1, 78, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd1, 78, 29:28, 25:24) \ HANDLER(EmcW2r, 78, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd2, 79, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd2, 79, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd2, 79, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd2, 79, 29:28, 25:24) \ HANDLER(EmcR2p, 79, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd3, 80, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd3, 80, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd3, 80, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd3, 80, 29:28, 25:24) \ HANDLER(EmcCcdmw, 80, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd4, 81, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd4, 81, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd4, 81, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd4, 81, 29:28, 25:24) \ HANDLER(EmcRdRcd, 81, 5:0, 31:26) \ HANDLER(EmcPmacroTxPwrd5, 82, 10:0, 10:0) \ HANDLER(EmcPmacroTxPwrd5, 82, 13:12, 12:11) \ HANDLER(EmcPmacroTxPwrd5, 82, 26:16, 23:13) \ HANDLER(EmcPmacroTxPwrd5, 82, 29:28, 25:24) \ HANDLER(EmcWrRcd, 82, 5:0, 31:26) \ HANDLER(EmcAutoCalChannel, 83, 5:0, 5:0) \ HANDLER(EmcAutoCalChannel, 83, 11:8, 9:6) \ HANDLER(EmcAutoCalChannel, 83, 27:16, 21:10) \ HANDLER(EmcAutoCalChannel, 83, 31:29, 24:22) \ HANDLER(EmcConfigSampleDelay, 83, 6:0, 31:25) \ HANDLER(EmcPmacroRxTerm, 84, 5:0, 5:0) \ HANDLER(EmcPmacroRxTerm, 84, 13:8, 11:6) \ HANDLER(EmcPmacroRxTerm, 84, 21:16, 17:12) \ HANDLER(EmcPmacroRxTerm, 84, 29:24, 23:18) \ HANDLER(EmcSelDpdCtrl, 84, 5:2, 27:24) \ HANDLER(EmcSelDpdCtrl, 84, 8:8, 28:28) \ HANDLER(EmcSelDpdCtrl, 84, 18:16, 31:29) \ HANDLER(EmcPmacroDqTxDrv, 85, 5:0, 5:0) \ HANDLER(EmcPmacroDqTxDrv, 85, 13:8, 11:6) \ HANDLER(EmcPmacroDqTxDrv, 85, 21:16, 17:12) \ HANDLER(EmcPmacroDqTxDrv, 85, 29:24, 23:18) \ HANDLER(EmcObdly, 85, 5:0, 29:24) \ HANDLER(EmcObdly, 85, 29:28, 31:30) \ HANDLER(EmcPmacroCaTxDrv, 86, 5:0, 5:0) \ HANDLER(EmcPmacroCaTxDrv, 86, 13:8, 11:6) \ HANDLER(EmcPmacroCaTxDrv, 86, 21:16, 17:12) \ HANDLER(EmcPmacroCaTxDrv, 86, 29:24, 23:18) \ HANDLER(EmcPmacroVttgenCtrl1, 86, 15:10, 29:24) \ HANDLER(EmcPmacroVttgenCtrl1, 86, 21:20, 31:30) \ HANDLER(EmcPmacroZctrl, 87, 27:4, 23:0) \ HANDLER(EmcPmacroVttgenCtrl2, 87, 23:16, 31:24) \ HANDLER(EmcZcalInterval, 88, 23:10, 13:0) \ HANDLER(EmcZcalInterval, 88, 9:0, 23:14) \ HANDLER(McEmemArbTimingRc, 88, 7:0, 31:24) \ HANDLER(EmcDataBrlshft0, 89, 23:0, 23:0) \ HANDLER(McEmemArbRsv, 89, 7:0, 31:24) \ HANDLER(EmcDataBrlshft1, 90, 23:0, 23:0) \ HANDLER(EmcDqsBrlshft0, 91, 23:0, 23:0) \ HANDLER(EmcDqsBrlshft1, 92, 23:0, 23:0) \ HANDLER(EmcSwizzleRank0Byte0, 93, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte0, 93, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte0, 93, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte0, 93, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte0, 93, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte0, 93, 22:20, 17:15) \ HANDLER(EmcSwizzleRank0Byte0, 93, 26:24, 20:18) \ HANDLER(EmcSwizzleRank0Byte0, 93, 30:28, 23:21) \ HANDLER(EmcSwizzleRank0Byte1, 94, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte1, 94, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte1, 94, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte1, 94, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte1, 94, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte1, 94, 22:20, 17:15) \ HANDLER(EmcSwizzleRank0Byte1, 94, 26:24, 20:18) \ HANDLER(EmcSwizzleRank0Byte1, 94, 30:28, 23:21) \ HANDLER(EmcRas, 94, 6:0, 30:24) \ HANDLER(EmcCfg, 94, 4:4, 31:31) \ HANDLER(EmcSwizzleRank0Byte2, 95, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte2, 95, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte2, 95, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte2, 95, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte2, 95, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte2, 95, 22:20, 17:15) \ HANDLER(EmcSwizzleRank0Byte2, 95, 26:24, 20:18) \ HANDLER(EmcSwizzleRank0Byte2, 95, 30:28, 23:21) \ HANDLER(EmcW2p, 95, 6:0, 30:24) \ HANDLER(EmcCfg, 95, 5:5, 31:31) \ HANDLER(EmcSwizzleRank0Byte3, 96, 2:0, 2:0) \ HANDLER(EmcSwizzleRank0Byte3, 96, 6:4, 5:3) \ HANDLER(EmcSwizzleRank0Byte3, 96, 10:8, 8:6) \ HANDLER(EmcSwizzleRank0Byte3, 96, 14:12, 11:9) \ HANDLER(EmcSwizzleRank0Byte3, 96, 18:16, 14:12) \ HANDLER(EmcSwizzleRank0Byte3, 96, 22:20, 17:15) \ HANDLER(EmcSwizzleRank0Byte3, 96, 26:24, 20:18) \ HANDLER(EmcSwizzleRank0Byte3, 96, 30:28, 23:21) \ HANDLER(EmcQSafe, 96, 6:0, 30:24) \ HANDLER(EmcCfg, 96, 6:6, 31:31) \ HANDLER(EmcSwizzleRank1Byte0, 97, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte0, 97, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte0, 97, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte0, 97, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte0, 97, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte0, 97, 22:20, 17:15) \ HANDLER(EmcSwizzleRank1Byte0, 97, 26:24, 20:18) \ HANDLER(EmcSwizzleRank1Byte0, 97, 30:28, 23:21) \ HANDLER(EmcRdv, 97, 6:0, 30:24) \ HANDLER(EmcCfg, 97, 7:7, 31:31) \ HANDLER(EmcSwizzleRank1Byte1, 98, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte1, 98, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte1, 98, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte1, 98, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte1, 98, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte1, 98, 22:20, 17:15) \ HANDLER(EmcSwizzleRank1Byte1, 98, 26:24, 20:18) \ HANDLER(EmcSwizzleRank1Byte1, 98, 30:28, 23:21) \ HANDLER(EmcRw2Pden, 98, 6:0, 30:24) \ HANDLER(EmcCfg, 98, 8:8, 31:31) \ HANDLER(EmcSwizzleRank1Byte2, 99, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte2, 99, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte2, 99, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte2, 99, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte2, 99, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte2, 99, 22:20, 17:15) \ HANDLER(EmcSwizzleRank1Byte2, 99, 26:24, 20:18) \ HANDLER(EmcSwizzleRank1Byte2, 99, 30:28, 23:21) \ HANDLER(EmcTfaw, 99, 6:0, 30:24) \ HANDLER(EmcCfg, 99, 9:9, 31:31) \ HANDLER(EmcSwizzleRank1Byte3, 100, 2:0, 2:0) \ HANDLER(EmcSwizzleRank1Byte3, 100, 6:4, 5:3) \ HANDLER(EmcSwizzleRank1Byte3, 100, 10:8, 8:6) \ HANDLER(EmcSwizzleRank1Byte3, 100, 14:12, 11:9) \ HANDLER(EmcSwizzleRank1Byte3, 100, 18:16, 14:12) \ HANDLER(EmcSwizzleRank1Byte3, 100, 22:20, 17:15) \ HANDLER(EmcSwizzleRank1Byte3, 100, 26:24, 20:18) \ HANDLER(EmcSwizzleRank1Byte3, 100, 30:28, 23:21) \ HANDLER(EmcTClkStable, 100, 6:0, 30:24) \ HANDLER(EmcCfg, 100, 18:18, 31:31) \ HANDLER(EmcCfgPipe2, 101, 11:0, 11:0) \ HANDLER(EmcCfgPipe2, 101, 27:16, 23:12) \ HANDLER(EmcTrtm, 101, 6:0, 30:24) \ HANDLER(EmcCfg, 101, 21:21, 31:31) \ HANDLER(EmcCfgPipe1, 102, 11:0, 11:0) \ HANDLER(EmcCfgPipe1, 102, 27:16, 23:12) \ HANDLER(EmcTwtm, 102, 6:0, 30:24) \ HANDLER(EmcCfg, 102, 22:22, 31:31) \ HANDLER(EmcPmacroDdllPwrd0, 103, 4:1, 3:0) \ HANDLER(EmcPmacroDdllPwrd0, 103, 7:6, 5:4) \ HANDLER(EmcPmacroDdllPwrd0, 103, 12:9, 9:6) \ HANDLER(EmcPmacroDdllPwrd0, 103, 15:14, 11:10) \ HANDLER(EmcPmacroDdllPwrd0, 103, 20:17, 15:12) \ HANDLER(EmcPmacroDdllPwrd0, 103, 23:22, 17:16) \ HANDLER(EmcPmacroDdllPwrd0, 103, 28:25, 21:18) \ HANDLER(EmcPmacroDdllPwrd0, 103, 31:30, 23:22) \ HANDLER(EmcTratm, 103, 6:0, 30:24) \ HANDLER(EmcCfg, 103, 23:23, 31:31) \ HANDLER(EmcPmacroDdllPwrd1, 104, 4:1, 3:0) \ HANDLER(EmcPmacroDdllPwrd1, 104, 7:6, 5:4) \ HANDLER(EmcPmacroDdllPwrd1, 104, 12:9, 9:6) \ HANDLER(EmcPmacroDdllPwrd1, 104, 15:14, 11:10) \ HANDLER(EmcPmacroDdllPwrd1, 104, 20:17, 15:12) \ HANDLER(EmcPmacroDdllPwrd1, 104, 23:22, 17:16) \ HANDLER(EmcPmacroDdllPwrd1, 104, 28:25, 21:18) \ HANDLER(EmcPmacroDdllPwrd1, 104, 31:30, 23:22) \ HANDLER(EmcTwatm, 104, 6:0, 30:24) \ HANDLER(EmcCfg, 104, 24:24, 31:31) \ HANDLER(EmcPmacroDdllPwrd2, 105, 4:1, 3:0) \ HANDLER(EmcPmacroDdllPwrd2, 105, 7:6, 5:4) \ HANDLER(EmcPmacroDdllPwrd2, 105, 12:9, 9:6) \ HANDLER(EmcPmacroDdllPwrd2, 105, 15:14, 11:10) \ HANDLER(EmcPmacroDdllPwrd2, 105, 20:17, 15:12) \ HANDLER(EmcPmacroDdllPwrd2, 105, 23:22, 17:16) \ HANDLER(EmcPmacroDdllPwrd2, 105, 28:25, 21:18) \ HANDLER(EmcPmacroDdllPwrd2, 105, 31:30, 23:22) \ HANDLER(EmcTr2ref, 105, 6:0, 30:24) \ HANDLER(EmcCfg, 105, 25:25, 31:31) \ HANDLER(EmcPmacroDdllPeriodicOffset, 106, 5:0, 5:0) \ HANDLER(EmcPmacroDdllPeriodicOffset, 106, 16:8, 14:6) \ HANDLER(EmcPmacroDdllPeriodicOffset, 106, 28:20, 23:15) \ HANDLER(EmcPdex2Mrr, 106, 6:0, 30:24) \ HANDLER(EmcCfg, 106, 26:26, 31:31) \ HANDLER(McEmemArbDaCovers, 107, 23:0, 23:0) \ HANDLER(EmcClkenOverride, 107, 3:1, 26:24) \ HANDLER(EmcClkenOverride, 107, 8:6, 29:27) \ HANDLER(EmcClkenOverride, 107, 16:16, 30:30) \ HANDLER(EmcCfg, 107, 28:28, 31:31) \ HANDLER(EmcXm2CompPadCtrl, 108, 1:0, 1:0) \ HANDLER(EmcXm2CompPadCtrl, 108, 6:4, 4:2) \ HANDLER(EmcXm2CompPadCtrl, 108, 9:9, 5:5) \ HANDLER(EmcXm2CompPadCtrl, 108, 19:11, 14:6) \ HANDLER(EmcXm2CompPadCtrl, 108, 31:24, 22:15) \ HANDLER(EmcRfcPb, 108, 8:0, 31:23) \ HANDLER(EmcAutoCalConfig3, 109, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig3, 109, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig3, 109, 23:16, 21:14) \ HANDLER(EmcCfgUpdate, 109, 2:0, 24:22) \ HANDLER(EmcCfgUpdate, 109, 10:8, 27:25) \ HANDLER(EmcCfgUpdate, 109, 31:28, 31:28) \ HANDLER(EmcAutoCalConfig4, 110, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig4, 110, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig4, 110, 23:16, 21:14) \ HANDLER(EmcRfc, 110, 9:0, 31:22) \ HANDLER(EmcAutoCalConfig5, 111, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig5, 111, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig5, 111, 23:16, 21:14) \ HANDLER(EmcTxsr, 111, 9:0, 31:22) \ HANDLER(EmcAutoCalConfig6, 112, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig6, 112, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig6, 112, 23:16, 21:14) \ HANDLER(EmcMc2EmcQ, 112, 2:0, 24:22) \ HANDLER(EmcMc2EmcQ, 112, 10:8, 27:25) \ HANDLER(EmcMc2EmcQ, 112, 27:24, 31:28) \ HANDLER(EmcAutoCalConfig7, 113, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig7, 113, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig7, 113, 23:16, 21:14) \ HANDLER(McEmemArbRing1Throttle, 113, 4:0, 26:22) \ HANDLER(McEmemArbRing1Throttle, 113, 20:16, 31:27) \ HANDLER(EmcAutoCalConfig8, 114, 6:0, 6:0) \ HANDLER(EmcAutoCalConfig8, 114, 14:8, 13:7) \ HANDLER(EmcAutoCalConfig8, 114, 23:16, 21:14) \ HANDLER(EmcFbioCfg7, 115, 21:0, 21:0) \ HANDLER(EmcAr2Pden, 115, 8:0, 30:22) \ HANDLER(EmcCfg, 115, 29:29, 31:31) \ HANDLER(EmcPmacroQuseDdllRank0_0, 123, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_0, 123, 26:16, 21:11) \ HANDLER(EmcRfcSlr, 123, 8:0, 30:22) \ HANDLER(EmcCfg, 123, 30:30, 31:31) \ HANDLER(EmcPmacroQuseDdllRank0_1, 124, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_1, 124, 26:16, 21:11) \ HANDLER(EmcIbdly, 124, 6:0, 28:22) \ HANDLER(EmcIbdly, 124, 29:28, 30:29) \ HANDLER(EmcCfg, 124, 31:31, 31:31) \ HANDLER(EmcPmacroQuseDdllRank0_2, 125, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_2, 125, 26:16, 21:11) \ HANDLER(McEmemArbTimingRFCPB, 125, 8:0, 30:22) \ HANDLER(EmcFbioCfg5, 125, 4:4, 31:31) \ HANDLER(EmcPmacroQuseDdllRank0_3, 126, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_3, 126, 26:16, 21:11) \ HANDLER(EmcAutoCalConfig9, 126, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 126, 15:13, 31:29) \ HANDLER(EmcPmacroQuseDdllRank0_4, 127, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_4, 127, 26:16, 21:11) \ HANDLER(EmcRdvMask, 127, 6:0, 28:22) \ HANDLER(EmcCfg2, 127, 5:3, 31:29) \ HANDLER(EmcPmacroQuseDdllRank0_5, 128, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank0_5, 128, 26:16, 21:11) \ HANDLER(EmcRdvEarlyMask, 128, 6:0, 28:22) \ HANDLER(EmcPmacroCmdPadTxCtrl, 128, 4:2, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_0, 129, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_0, 129, 26:16, 21:11) \ HANDLER(EmcRdvEarly, 129, 6:0, 28:22) \ HANDLER(EmcPmacroCmdPadTxCtrl, 129, 9:7, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_1, 130, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_1, 130, 26:16, 21:11) \ HANDLER(EmcQuseWidth, 130, 4:0, 26:22) \ HANDLER(EmcQuseWidth, 130, 29:28, 28:27) \ HANDLER(EmcPmacroCmdPadTxCtrl, 130, 14:12, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_2, 131, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_2, 131, 26:16, 21:11) \ HANDLER(EmcPmacroDdllShortCmd_2, 131, 6:0, 28:22) \ HANDLER(EmcPmacroCmdPadTxCtrl, 131, 19:17, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_3, 132, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_3, 132, 26:16, 21:11) \ HANDLER(EmcPmacroCmdRxTermMode, 132, 1:0, 23:22) \ HANDLER(EmcPmacroCmdRxTermMode, 132, 5:4, 25:24) \ HANDLER(EmcPmacroCmdRxTermMode, 132, 9:8, 27:26) \ HANDLER(EmcPmacroCmdRxTermMode, 132, 13:13, 28:28) \ HANDLER(EmcPmacroDataPadTxCtrl, 132, 4:2, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_4, 133, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_4, 133, 26:16, 21:11) \ HANDLER(EmcPmacroDataRxTermMode, 133, 1:0, 23:22) \ HANDLER(EmcPmacroDataRxTermMode, 133, 5:4, 25:24) \ HANDLER(EmcPmacroDataRxTermMode, 133, 9:8, 27:26) \ HANDLER(EmcPmacroDataRxTermMode, 133, 13:13, 28:28) \ HANDLER(EmcPmacroDataPadTxCtrl, 133, 9:7, 31:29) \ HANDLER(EmcPmacroQuseDdllRank1_5, 134, 10:0, 10:0) \ HANDLER(EmcPmacroQuseDdllRank1_5, 134, 26:16, 21:11) \ HANDLER(McEmemArbTimingRp, 134, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 134, 14:12, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank0_0, 135, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_0, 135, 26:16, 21:11) \ HANDLER(McEmemArbTimingRas, 135, 6:0, 28:22) \ HANDLER(EmcPmacroDataPadTxCtrl, 135, 19:17, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank0_1, 136, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_1, 136, 26:16, 21:11) \ HANDLER(McEmemArbTimingFaw, 136, 6:0, 28:22) \ HANDLER(EmcCfg, 136, 17:16, 30:29) \ HANDLER(EmcFbioCfg5, 136, 8:8, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_2, 137, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_2, 137, 26:16, 21:11) \ HANDLER(McEmemArbTimingRap2Pre, 137, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 137, 1:0, 30:29) \ HANDLER(EmcFbioCfg5, 137, 10:10, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_3, 138, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_3, 138, 26:16, 21:11) \ HANDLER(McEmemArbTimingWap2Pre, 138, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 138, 3:2, 30:29) \ HANDLER(EmcFbioCfg5, 138, 12:12, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_4, 139, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_4, 139, 26:16, 21:11) \ HANDLER(McEmemArbTimingR2W, 139, 6:0, 28:22) \ HANDLER(EmcCfg2, 139, 27:26, 30:29) \ HANDLER(EmcFbioCfg5, 139, 24:24, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank0_5, 140, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank0_5, 140, 26:16, 21:11) \ HANDLER(McEmemArbTimingW2R, 140, 6:0, 28:22) \ HANDLER(EmcFbioCfg5, 140, 27:25, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank1_0, 141, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_0, 141, 26:16, 21:11) \ HANDLER(EmcWdv, 141, 5:0, 27:22) \ HANDLER(EmcFbioCfg5, 141, 23:20, 31:28) \ HANDLER(EmcPmacroObDdllLongDqRank1_1, 142, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_1, 142, 26:16, 21:11) \ HANDLER(EmcQUse, 142, 5:0, 27:22) \ HANDLER(EmcFbioCfg5, 142, 28:28, 28:28) \ HANDLER(EmcFbioCfg5, 142, 31:30, 30:29) \ HANDLER(EmcCfg2, 142, 0:0, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_2, 143, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_2, 143, 26:16, 21:11) \ HANDLER(EmcPdEx2Wr, 143, 5:0, 27:22) \ HANDLER(EmcCfg2, 143, 2:1, 29:28) \ HANDLER(EmcCfg2, 143, 7:7, 30:30) \ HANDLER(EmcCfg2, 143, 10:10, 31:31) \ HANDLER(EmcPmacroObDdllLongDqRank1_3, 144, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_3, 144, 26:16, 21:11) \ HANDLER(EmcPdEx2Rd, 144, 5:0, 27:22) \ HANDLER(EmcCfg2, 144, 11:11, 28:28) \ HANDLER(EmcCfg2, 144, 16:14, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank1_4, 145, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_4, 145, 26:16, 21:11) \ HANDLER(EmcPdex2Cke, 145, 5:0, 27:22) \ HANDLER(EmcCfg2, 145, 20:20, 28:28) \ HANDLER(EmcCfg2, 145, 24:22, 31:29) \ HANDLER(EmcPmacroObDdllLongDqRank1_5, 146, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqRank1_5, 146, 26:16, 21:11) \ HANDLER(EmcPChg2Pden, 146, 5:0, 27:22) \ HANDLER(EmcCfg2, 146, 25:25, 28:28) \ HANDLER(EmcCfg2, 146, 30:28, 31:29) \ HANDLER(EmcPmacroObDdllLongDqsRank0_0, 147, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_0, 147, 26:16, 21:11) \ HANDLER(EmcAct2Pden, 147, 5:0, 27:22) \ HANDLER(EmcCfg2, 147, 31:31, 28:28) \ HANDLER(EmcCfgPipe, 147, 2:0, 31:29) \ HANDLER(EmcPmacroObDdllLongDqsRank0_1, 148, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_1, 148, 26:16, 21:11) \ HANDLER(EmcCke2Pden, 148, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 148, 6:3, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_2, 149, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_2, 149, 26:16, 21:11) \ HANDLER(EmcTcke, 149, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 149, 10:7, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_3, 150, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_3, 150, 26:16, 21:11) \ HANDLER(EmcTrpab, 150, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 150, 11:11, 28:28) \ HANDLER(EmcCfgPipe, 150, 18:16, 31:29) \ HANDLER(EmcPmacroObDdllLongDqsRank0_4, 151, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_4, 151, 26:16, 21:11) \ HANDLER(EmcEInput, 151, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 151, 22:19, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank0_5, 152, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank0_5, 152, 26:16, 21:11) \ HANDLER(EmcEInputDuration, 152, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 152, 26:23, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_0, 153, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_0, 153, 26:16, 21:11) \ HANDLER(EmcPutermExtra, 153, 5:0, 27:22) \ HANDLER(EmcCfgPipe, 153, 27:27, 28:28) \ HANDLER(EmcPmacroTxSelClkSrc0, 153, 2:0, 31:29) \ HANDLER(EmcPmacroObDdllLongDqsRank1_1, 154, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_1, 154, 26:16, 21:11) \ HANDLER(EmcTckesr, 154, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc0, 154, 6:3, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_2, 155, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_2, 155, 26:16, 21:11) \ HANDLER(EmcTpd, 155, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc0, 155, 10:7, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_3, 156, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_3, 156, 26:16, 21:11) \ HANDLER(EmcWdvMask, 156, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc0, 156, 19:16, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_4, 157, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_4, 157, 26:16, 21:11) \ HANDLER(EmcWdvChk, 157, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc0, 157, 23:20, 31:28) \ HANDLER(EmcPmacroObDdllLongDqsRank1_5, 158, 10:0, 10:0) \ HANDLER(EmcPmacroObDdllLongDqsRank1_5, 158, 26:16, 21:11) \ HANDLER(EmcCmdBrlshft0, 158, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc0, 158, 26:24, 30:28) \ HANDLER(EmcPmacroTxSelClkSrc1, 158, 0:0, 31:31) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_0, 159, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_0, 159, 26:16, 21:11) \ HANDLER(EmcCmdBrlshft1, 159, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc1, 159, 4:1, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_1, 160, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_1, 160, 26:16, 21:11) \ HANDLER(EmcCmdBrlshft2, 160, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc1, 160, 8:5, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_2, 161, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_2, 161, 26:16, 21:11) \ HANDLER(EmcCmdBrlshft3, 161, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc1, 161, 10:9, 29:28) \ HANDLER(EmcPmacroTxSelClkSrc1, 161, 17:16, 31:30) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_3, 162, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank0_3, 162, 26:16, 21:11) \ HANDLER(EmcWev, 162, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc1, 162, 21:18, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_0, 163, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_0, 163, 26:16, 21:11) \ HANDLER(EmcWsv, 163, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc1, 163, 25:22, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_1, 164, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_1, 164, 26:16, 21:11) \ HANDLER(EmcCfg3, 164, 2:0, 24:22) \ HANDLER(EmcCfg3, 164, 6:4, 27:25) \ HANDLER(EmcPmacroTxSelClkSrc1, 164, 26:26, 28:28) \ HANDLER(EmcPmacroTxSelClkSrc3, 164, 2:0, 31:29) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_2, 165, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_2, 165, 26:16, 21:11) \ HANDLER(EmcPutermWidth, 165, 31:31, 22:22) \ HANDLER(EmcPutermWidth, 165, 4:0, 27:23) \ HANDLER(EmcPmacroTxSelClkSrc3, 165, 6:3, 31:28) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_3, 166, 10:0, 10:0) \ HANDLER(EmcPmacroIbDdllLongDqsRank1_3, 166, 26:16, 21:11) \ HANDLER(McEmemArbTimingRcd, 166, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc3, 166, 10:7, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_0, 167, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_0, 167, 26:16, 21:11) \ HANDLER(McEmemArbTimingCcdmw, 167, 5:0, 27:22) \ HANDLER(EmcPmacroTxSelClkSrc3, 167, 19:16, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_1, 168, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_1, 168, 26:16, 21:11) \ HANDLER(McEmemArbOverride, 168, 27:27, 22:22) \ HANDLER(McEmemArbOverride, 168, 26:26, 23:23) \ HANDLER(McEmemArbOverride, 168, 16:16, 24:24) \ HANDLER(McEmemArbOverride, 168, 10:10, 25:25) \ HANDLER(McEmemArbOverride, 168, 4:4, 26:26) \ HANDLER(McEmemArbOverride, 168, 3:3, 27:27) \ HANDLER(EmcPmacroTxSelClkSrc3, 168, 23:20, 31:28) \ HANDLER(EmcPmacroDdllLongCmd_2, 169, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_2, 169, 26:16, 21:11) \ HANDLER(EmcRrd, 169, 4:0, 26:22) \ HANDLER(EmcRext, 169, 4:0, 31:27) \ HANDLER(EmcPmacroDdllLongCmd_3, 170, 10:0, 10:0) \ HANDLER(EmcPmacroDdllLongCmd_3, 170, 26:16, 21:11) \ HANDLER(EmcTClkStop, 170, 4:0, 26:22) \ HANDLER(EmcWext, 170, 4:0, 31:27) \ HANDLER(EmcPmacroPerbitFgcgCtrl0, 171, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl0, 171, 26:16, 21:11) \ HANDLER(EmcRefctrl2, 171, 0:0, 22:22) \ HANDLER(EmcRefctrl2, 171, 26:24, 25:23) \ HANDLER(EmcRefctrl2, 171, 31:31, 26:26) \ HANDLER(EmcWeDuration, 171, 4:0, 31:27) \ HANDLER(EmcPmacroPerbitFgcgCtrl1, 172, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl1, 172, 26:16, 21:11) \ HANDLER(EmcWsDuration, 172, 4:0, 26:22) \ HANDLER(EmcPmacroPadCfgCtrl, 172, 0:0, 27:27) \ HANDLER(EmcPmacroPadCfgCtrl, 172, 9:9, 28:28) \ HANDLER(EmcPmacroPadCfgCtrl, 172, 13:13, 29:29) \ HANDLER(EmcPmacroPadCfgCtrl, 172, 17:16, 31:30) \ HANDLER(EmcPmacroPerbitFgcgCtrl2, 173, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl2, 173, 26:16, 21:11) \ HANDLER(McEmemArbTimingRrd, 173, 4:0, 26:22) \ HANDLER(McEmemArbTimingR2R, 173, 4:0, 31:27) \ HANDLER(EmcPmacroPerbitFgcgCtrl3, 174, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl3, 174, 26:16, 21:11) \ HANDLER(McEmemArbTimingW2W, 174, 4:0, 26:22) \ HANDLER(EmcPmacroTxSelClkSrc3, 174, 26:24, 29:27) \ HANDLER(EmcPmacroTxSelClkSrc2, 174, 1:0, 31:30) \ HANDLER(EmcPmacroPerbitFgcgCtrl4, 175, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl4, 175, 26:16, 21:11) \ HANDLER(EmcPmacroTxSelClkSrc2, 175, 10:2, 30:22) \ HANDLER(EmcPmacroTxSelClkSrc2, 175, 16:16, 31:31) \ HANDLER(EmcPmacroPerbitFgcgCtrl5, 176, 10:0, 10:0) \ HANDLER(EmcPmacroPerbitFgcgCtrl5, 176, 26:16, 21:11) \ HANDLER(EmcPmacroTxSelClkSrc2, 176, 26:17, 31:22) \ HANDLER(McEmemArbCfg, 177, 8:0, 8:0) \ HANDLER(McEmemArbCfg, 177, 20:16, 13:9) \ HANDLER(McEmemArbCfg, 177, 31:24, 21:14) \ HANDLER(EmcPmacroTxSelClkSrc4, 177, 9:0, 31:22) \ HANDLER(McEmemArbMisc1, 178, 12:0, 12:0) \ HANDLER(McEmemArbMisc1, 178, 25:21, 17:13) \ HANDLER(McEmemArbMisc1, 178, 31:28, 21:18) \ HANDLER(EmcPmacroTxSelClkSrc4, 178, 10:10, 22:22) \ HANDLER(EmcPmacroTxSelClkSrc4, 178, 24:16, 31:23) \ HANDLER(EmcMrsWaitCnt2, 179, 9:0, 9:0) \ HANDLER(EmcMrsWaitCnt2, 179, 26:16, 20:10) \ HANDLER(EmcOdtWrite, 179, 5:0, 26:21) \ HANDLER(EmcOdtWrite, 179, 11:8, 30:27) \ HANDLER(EmcOdtWrite, 179, 31:31, 31:31) \ HANDLER(EmcMrsWaitCnt, 180, 9:0, 9:0) \ HANDLER(EmcMrsWaitCnt, 180, 26:16, 20:10) \ HANDLER(EmcPmacroIbRxrt, 180, 10:0, 31:21) \ HANDLER(EmcAutoCalInterval, 181, 20:0, 20:0) \ HANDLER(EmcPmacroDdllLongCmd_4, 181, 10:0, 31:21) \ HANDLER(McEmemArbRefpbHpCtrl, 182, 6:0, 6:0) \ HANDLER(McEmemArbRefpbHpCtrl, 182, 14:8, 13:7) \ HANDLER(McEmemArbRefpbHpCtrl, 182, 22:16, 20:14) \ HANDLER(McEmemArbOutstandingReq, 182, 8:0, 29:21) \ HANDLER(McEmemArbOutstandingReq, 182, 31:30, 31:30) \ HANDLER(EmcXm2CompPadCtrl2, 183, 5:0, 5:0) \ HANDLER(EmcXm2CompPadCtrl2, 183, 17:12, 11:6) \ HANDLER(EmcXm2CompPadCtrl2, 183, 21:20, 13:12) \ HANDLER(EmcXm2CompPadCtrl2, 183, 29:24, 19:14) \ HANDLER(EmcPmacroCmdCtrl0, 183, 0:0, 20:20) \ HANDLER(EmcPmacroCmdCtrl0, 183, 5:4, 22:21) \ HANDLER(EmcPmacroCmdCtrl0, 183, 8:8, 23:23) \ HANDLER(EmcPmacroCmdCtrl0, 183, 13:12, 25:24) \ HANDLER(EmcPmacroCmdCtrl0, 183, 16:16, 26:26) \ HANDLER(EmcPmacroCmdCtrl0, 183, 21:20, 28:27) \ HANDLER(EmcPmacroCmdCtrl0, 183, 24:24, 29:29) \ HANDLER(EmcPmacroCmdCtrl0, 183, 29:28, 31:30) \ HANDLER(EmcCfgDigDll_1, 184, 19:0, 19:0) \ HANDLER(EmcPmacroCmdCtrl1, 184, 0:0, 20:20) \ HANDLER(EmcPmacroCmdCtrl1, 184, 5:4, 22:21) \ HANDLER(EmcPmacroCmdCtrl1, 184, 8:8, 23:23) \ HANDLER(EmcPmacroCmdCtrl1, 184, 13:12, 25:24) \ HANDLER(EmcPmacroCmdCtrl1, 184, 16:16, 26:26) \ HANDLER(EmcPmacroCmdCtrl1, 184, 21:20, 28:27) \ HANDLER(EmcPmacroCmdCtrl1, 184, 24:24, 29:29) \ HANDLER(EmcPmacroCmdCtrl1, 184, 29:28, 31:30) \ HANDLER(EmcQuseBrlshft0, 185, 19:0, 19:0) \ HANDLER(EmcPmacroCmdCtrl2, 185, 0:0, 20:20) \ HANDLER(EmcPmacroCmdCtrl2, 185, 5:4, 22:21) \ HANDLER(EmcPmacroCmdCtrl2, 185, 8:8, 23:23) \ HANDLER(EmcPmacroCmdCtrl2, 185, 13:12, 25:24) \ HANDLER(EmcPmacroCmdCtrl2, 185, 16:16, 26:26) \ HANDLER(EmcPmacroCmdCtrl2, 185, 21:20, 28:27) \ HANDLER(EmcPmacroCmdCtrl2, 185, 24:24, 29:29) \ HANDLER(EmcPmacroCmdCtrl2, 185, 29:28, 31:30) \ HANDLER(EmcQuseBrlshft1, 186, 19:0, 19:0) \ HANDLER(EmcPmacroDsrVttgenCtrl0, 186, 3:0, 23:20) \ HANDLER(EmcPmacroDsrVttgenCtrl0, 186, 15:8, 31:24) \ HANDLER(EmcQuseBrlshft2, 187, 19:0, 19:0) \ HANDLER(EmcPmacroPerbitRfu1Ctrl0, 187, 5:0, 25:20) \ HANDLER(EmcPmacroPerbitRfu1Ctrl0, 187, 21:16, 31:26) \ HANDLER(EmcQuseBrlshft3, 188, 19:0, 19:0) \ HANDLER(EmcPmacroPerbitRfu1Ctrl1, 188, 5:0, 25:20) \ HANDLER(EmcPmacroPerbitRfu1Ctrl1, 188, 21:16, 31:26) \ HANDLER(EmcDbg, 189, 4:0, 4:0) \ HANDLER(EmcDbg, 189, 13:9, 9:5) \ HANDLER(EmcDbg, 189, 31:24, 17:10) \ HANDLER(EmcTRefBw, 189, 13:0, 31:18) \ HANDLER(EmcZcalWaitCnt, 191, 10:0, 10:0) \ HANDLER(EmcZcalWaitCnt, 191, 21:16, 16:11) \ HANDLER(EmcZcalWaitCnt, 191, 31:31, 17:17) \ HANDLER(EmcQpop, 191, 6:0, 24:18) \ HANDLER(EmcQpop, 191, 22:16, 31:25) \ HANDLER(EmcZcalMrwCmd, 192, 7:0, 7:0) \ HANDLER(EmcZcalMrwCmd, 192, 23:16, 15:8) \ HANDLER(EmcZcalMrwCmd, 192, 31:30, 17:16) \ HANDLER(EmcPmacroAutocalCfgCommon, 192, 5:0, 23:18) \ HANDLER(EmcPmacroAutocalCfgCommon, 192, 13:8, 29:24) \ HANDLER(EmcPmacroAutocalCfgCommon, 192, 16:16, 30:30) \ HANDLER(EmcPmacroTxSelClkSrc4, 192, 25:25, 31:31) \ HANDLER(EmcPmacroDllCfg1, 193, 10:0, 10:0) \ HANDLER(EmcPmacroDllCfg1, 193, 13:12, 12:11) \ HANDLER(EmcPmacroDllCfg1, 193, 17:16, 14:13) \ HANDLER(EmcPmacroDllCfg1, 193, 21:20, 16:15) \ HANDLER(EmcPmacroDllCfg1, 193, 24:24, 17:17) \ HANDLER(EmcPmacroPerbitRfu1Ctrl2, 193, 5:0, 23:18) \ HANDLER(EmcPmacroPerbitRfu1Ctrl2, 193, 21:16, 29:24) \ HANDLER(EmcPmacroTxSelClkSrc4, 193, 26:26, 30:30) \ HANDLER(EmcPmacroTxSelClkSrc5, 193, 0:0, 31:31) \ HANDLER(EmcPmacroCmdBrickCtrlFdpd, 194, 17:0, 17:0) \ HANDLER(EmcPmacroPerbitRfu1Ctrl3, 194, 5:0, 23:18) \ HANDLER(EmcPmacroPerbitRfu1Ctrl3, 194, 21:16, 29:24) \ HANDLER(EmcPmacroTxSelClkSrc5, 194, 2:1, 31:30) \ HANDLER(EmcPmacroDataBrickCtrlFdpd, 195, 17:0, 17:0) \ HANDLER(EmcPmacroPerbitRfu1Ctrl4, 195, 5:0, 23:18) \ HANDLER(EmcPmacroPerbitRfu1Ctrl4, 195, 21:16, 29:24) \ HANDLER(EmcPmacroTxSelClkSrc5, 195, 4:3, 31:30) \ HANDLER(EmcDynSelfRefControl, 196, 15:0, 15:0) \ HANDLER(EmcDynSelfRefControl, 196, 31:31, 16:16) \ HANDLER(McEmemArbRefpbBankCtrl, 196, 6:0, 23:17) \ HANDLER(McEmemArbRefpbBankCtrl, 196, 14:8, 30:24) \ HANDLER(McEmemArbRefpbBankCtrl, 196, 31:31, 31:31) \ HANDLER(EmcPmacroCmdPadRxCtrl, 197, 1:0, 1:0) \ HANDLER(EmcPmacroCmdPadRxCtrl, 197, 5:4, 3:2) \ HANDLER(EmcPmacroCmdPadRxCtrl, 197, 12:12, 4:4) \ HANDLER(EmcPmacroCmdPadRxCtrl, 197, 19:15, 9:5) \ HANDLER(EmcPmacroCmdPadRxCtrl, 197, 27:21, 16:10) \ HANDLER(EmcPmacroPerbitRfu1Ctrl5, 197, 5:0, 22:17) \ HANDLER(EmcPmacroPerbitRfu1Ctrl5, 197, 21:16, 28:23) \ HANDLER(EmcPmacroTxSelClkSrc5, 197, 7:5, 31:29) \ HANDLER(EmcPmacroDataPadRxCtrl, 198, 1:0, 1:0) \ HANDLER(EmcPmacroDataPadRxCtrl, 198, 5:4, 3:2) \ HANDLER(EmcPmacroDataPadRxCtrl, 198, 12:12, 4:4) \ HANDLER(EmcPmacroDataPadRxCtrl, 198, 19:15, 9:5) \ HANDLER(EmcPmacroDataPadRxCtrl, 198, 27:21, 16:10) \ HANDLER(EmcPmacroTxSelClkSrc5, 198, 10:8, 19:17) \ HANDLER(EmcPmacroTxSelClkSrc5, 198, 26:16, 30:20) \ HANDLER(EmcPmacroCmdPadTxCtrl, 198, 0:0, 31:31) \ HANDLER(EmcRefresh, 199, 15:0, 15:0) \ HANDLER(EmcCmdQ, 199, 4:0, 20:16) \ HANDLER(EmcCmdQ, 199, 10:8, 23:21) \ HANDLER(EmcCmdQ, 199, 14:12, 26:24) \ HANDLER(EmcCmdQ, 199, 28:24, 31:27) \ HANDLER(EmcAcpdControl, 210, 15:0, 15:0) \ HANDLER(EmcAutoCalVrefSel1, 210, 15:0, 31:16) \ HANDLER(EmcPmacroAutocalCfg0, 211, 3:0, 3:0) \ HANDLER(EmcPmacroAutocalCfg0, 211, 11:8, 7:4) \ HANDLER(EmcPmacroAutocalCfg0, 211, 19:16, 11:8) \ HANDLER(EmcPmacroAutocalCfg0, 211, 27:24, 15:12) \ HANDLER(EmcPmacroAutocalCfg1, 211, 3:0, 19:16) \ HANDLER(EmcPmacroAutocalCfg1, 211, 11:8, 23:20) \ HANDLER(EmcPmacroAutocalCfg1, 211, 19:16, 27:24) \ HANDLER(EmcPmacroAutocalCfg1, 211, 27:24, 31:28) \ HANDLER(EmcPmacroAutocalCfg2, 212, 3:0, 3:0) \ HANDLER(EmcPmacroAutocalCfg2, 212, 11:8, 7:4) \ HANDLER(EmcPmacroAutocalCfg2, 212, 19:16, 11:8) \ HANDLER(EmcPmacroAutocalCfg2, 212, 27:24, 15:12) \ HANDLER(EmcXm2CompPadCtrl3, 212, 5:0, 21:16) \ HANDLER(EmcXm2CompPadCtrl3, 212, 17:12, 27:22) \ HANDLER(EmcXm2CompPadCtrl3, 212, 23:20, 31:28) \ HANDLER(EmcCfgDigDllPeriod, 213, 15:0, 15:0) \ HANDLER(EmcPreRefreshReqCnt, 213, 15:0, 31:16) \ HANDLER(EmcPmacroDdllBypass, 214, 0:0, 0:0) \ HANDLER(EmcPmacroDdllBypass, 214, 11:8, 4:1) \ HANDLER(EmcPmacroDdllBypass, 214, 16:13, 8:5) \ HANDLER(EmcPmacroDdllBypass, 214, 27:24, 12:9) \ HANDLER(EmcPmacroDdllBypass, 214, 31:29, 15:13) \ HANDLER(EmcPmacroDataPiCtrl, 214, 4:0, 20:16) \ HANDLER(EmcPmacroDataPiCtrl, 214, 12:8, 25:21) \ HANDLER(EmcPmacroDataPiCtrl, 214, 21:16, 31:26) \ HANDLER(EmcPmacroCmdPiCtrl, 215, 4:0, 4:0) \ HANDLER(EmcPmacroCmdPiCtrl, 215, 12:8, 9:5) \ HANDLER(EmcPmacroCmdPiCtrl, 215, 21:16, 15:10) \ HANDLER(EmcPmacroCmdPadTxCtrl, 216, 6:5, 1:0) \ HANDLER(EmcPmacroCmdPadTxCtrl, 216, 10:10, 2:2) \ HANDLER(EmcPmacroCmdPadTxCtrl, 216, 16:15, 4:3) \ HANDLER(EmcPmacroCmdPadTxCtrl, 216, 30:21, 14:5) \ HANDLER(EmcPmacroDataPadTxCtrl, 216, 0:0, 15:15) \ HANDLER(EmcPmacroDataPadTxCtrl, 216, 6:5, 17:16) \ HANDLER(EmcPmacroDataPadTxCtrl, 216, 10:10, 18:18) \ HANDLER(EmcPmacroDataPadTxCtrl, 216, 16:15, 20:19) \ HANDLER(EmcPmacroDataPadTxCtrl, 216, 30:21, 30:21) \ HANDLER(EmcPinGpio, 9, 1:0, 31:30) \ HANDLER(EmcPinGpioEn, 10, 1:0, 31:30) \ HANDLER(EmcDevSelect, 11, 1:0, 31:30) \ HANDLER(EmcZcalWarmColdBootEnables, 12, 1:0, 31:30) \ HANDLER(EmcCfgDigDllPeriodWarmBoot, 13, 1:0, 31:30) \ HANDLER(EmcBctSpare13, 45, 31:0, 31:0) \ HANDLER(EmcBctSpare12, 46, 31:0, 31:0) \ HANDLER(EmcBctSpare7, 47, 31:0, 31:0) \ HANDLER(EmcBctSpare6, 48, 31:0, 31:0) \ HANDLER(EmcBctSpare5, 50, 31:0, 31:0) \ HANDLER(EmcBctSpare4, 51, 31:0, 31:0) \ HANDLER(EmcBctSpare3, 56, 31:0, 31:0) \ HANDLER(EmcBctSpare2, 57, 31:0, 31:0) \ HANDLER(EmcBctSpare1, 58, 31:0, 31:0) \ HANDLER(EmcBctSpare0, 59, 31:0, 31:0) \ HANDLER(EmcBctSpare9, 60, 31:0, 31:0) \ HANDLER(EmcBctSpare8, 61, 31:0, 31:0) \ HANDLER(BootRomPatchData, 62, 31:0, 31:0) \ HANDLER(BootRomPatchControl, 63, 31:0, 31:0) \ HANDLER(McClkenOverrideAllWarmBoot, 65, 0:0, 31:31) \ HANDLER(EmcExtraRefreshNum, 66, 2:0, 31:29) \ HANDLER(PmcIoDpd3ReqWait, 72, 2:0, 30:28) \ HANDLER(EmcClkenOverrideAllWarmBoot, 72, 0:0, 31:31) \ HANDLER(MemoryType, 73, 2:0, 30:28) \ HANDLER(EmcMrsWarmBootEnable, 73, 0:0, 31:31) \ HANDLER(PmcIoDpd4ReqWait, 74, 2:0, 30:28) \ HANDLER(ClearClk2Mc1, 74, 0:0, 31:31) \ HANDLER(EmcWarmBootExtraModeRegWriteEnable, 75, 0:0, 28:28) \ HANDLER(ClkRstControllerPllmMisc2OverrideEnable, 75, 0:0, 29:29) \ HANDLER(EmcDbgWriteMux, 75, 0:0, 30:30) \ HANDLER(AhbArbitrationXbarCtrlMemInitDone, 75, 0:0, 31:31) \ HANDLER(EmcTimingControlWait, 90, 7:0, 31:24) \ HANDLER(EmcZcalWarmBootWait, 91, 7:0, 31:24) \ HANDLER(WarmBootWait, 92, 7:0, 31:24) \ HANDLER(EmcPinProgramWait, 93, 7:0, 31:24) \ HANDLER(EmcAutoCalWait, 114, 9:0, 31:22) \ HANDLER(SwizzleRankByteEncode, 215, 15:0, 31:16) \ \ /* PMC SCRATCH fields for LPDDR2. */ \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 5, 23:16, 7:0) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 5, 7:0, 15:8) \ HANDLER(EmcWarmBootMrwExtra, 5, 23:16, 23:16) \ HANDLER(EmcWarmBootMrwExtra, 5, 7:0, 31:24) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 6, 31:30, 1:0) \ HANDLER(EmcWarmBootMrwExtra, 6, 31:30, 3:2) \ HANDLER(EmcMrwLpddr2ZcalWarmBoot, 6, 27:26, 5:4) \ HANDLER(EmcWarmBootMrwExtra, 6, 27:26, 7:6) \ HANDLER(EmcMrw6, 8, 27:0, 27:0) \ HANDLER(EmcMrw6, 8, 31:30, 29:28) \ HANDLER(EmcMrw8, 9, 27:0, 27:0) \ HANDLER(EmcMrw8, 9, 31:30, 29:28) \ HANDLER(EmcMrw9, 10, 27:0, 27:0) \ HANDLER(EmcMrw9, 10, 31:30, 29:28) \ HANDLER(EmcMrw10, 11, 27:0, 27:0) \ HANDLER(EmcMrw10, 11, 31:30, 29:28) \ HANDLER(EmcMrw12, 12, 27:0, 27:0) \ HANDLER(EmcMrw12, 12, 31:30, 29:28) \ HANDLER(EmcMrw13, 13, 27:0, 27:0) \ HANDLER(EmcMrw13, 13, 31:30, 29:28) \ HANDLER(EmcMrw14, 14, 27:0, 27:0) \ HANDLER(EmcMrw14, 14, 31:30, 29:28) \ HANDLER(EmcMrw1, 15, 7:0, 7:0) \ HANDLER(EmcMrw1, 15, 23:16, 15:8) \ HANDLER(EmcMrw1, 15, 27:26, 17:16) \ HANDLER(EmcMrw1, 15, 31:30, 19:18) \ HANDLER(EmcWarmBootMrwExtra, 16, 7:0, 7:0) \ HANDLER(EmcWarmBootMrwExtra, 16, 23:16, 15:8) \ HANDLER(EmcWarmBootMrwExtra, 16, 27:26, 17:16) \ HANDLER(EmcWarmBootMrwExtra, 16, 31:30, 19:18) \ HANDLER(EmcMrw2, 17, 7:0, 7:0) \ HANDLER(EmcMrw2, 17, 23:16, 15:8) \ HANDLER(EmcMrw2, 17, 27:26, 17:16) \ HANDLER(EmcMrw2, 17, 31:30, 19:18) \ HANDLER(EmcMrw3, 18, 7:0, 7:0) \ HANDLER(EmcMrw3, 18, 23:16, 15:8) \ HANDLER(EmcMrw3, 18, 27:26, 17:16) \ HANDLER(EmcMrw3, 18, 31:30, 19:18) \ HANDLER(EmcMrw4, 19, 7:0, 7:0) \ HANDLER(EmcMrw4, 19, 23:16, 15:8) \ HANDLER(EmcMrw4, 19, 27:26, 17:16) \ HANDLER(EmcMrw4, 19, 31:30, 19:18) #define FOREACH_SDRAM_SECURE_SCRATCH_REGISTER_MARIKO(HANDLER) \ /* PMC SECURE_SCRATCH fields. */ \ HANDLER(EmcCmdMappingByte, 8, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping0, 9, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping1, 10, 31:0, 31:0) \ HANDLER(EmcPmacroBrickMapping2, 11, 31:0, 31:0) \ HANDLER(McVideoProtectGpuOverride0, 12, 31:0, 31:0) \ HANDLER(EmcCmdMappingCmd0_0, 13, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_0, 13, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_0, 13, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_0, 13, 30:24, 27:21) \ HANDLER(McUntranslatedRegionCheck, 13, 0:0, 28:28) \ HANDLER(McUntranslatedRegionCheck, 13, 9:8, 30:29) \ HANDLER(EmcAdrCfg, 13, 0:0, 31:31) \ HANDLER(EmcCmdMappingCmd0_1, 14, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_1, 14, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_1, 14, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_1, 14, 30:24, 27:21) \ HANDLER(McVideoProtectBomAdrHi, 14, 1:0, 29:28) \ HANDLER(McVideoProtectWriteAccess, 14, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd1_0, 15, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_0, 15, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_0, 15, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_0, 15, 30:24, 27:21) \ HANDLER(McSecCarveoutAdrHi, 15, 1:0, 29:28) \ HANDLER(McMtsCarveoutAdrHi, 15, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd1_1, 16, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_1, 16, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_1, 16, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_1, 16, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout5BomHi, 16, 1:0, 29:28) \ HANDLER(McGeneralizedCarveout3BomHi, 16, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd2_0, 17, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_0, 17, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_0, 17, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_0, 17, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout2BomHi, 17, 1:0, 29:28) \ HANDLER(McGeneralizedCarveout4BomHi, 17, 1:0, 31:30) \ HANDLER(EmcCmdMappingCmd2_1, 18, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_1, 18, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_1, 18, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_1, 18, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout1BomHi, 18, 1:0, 29:28) \ HANDLER(EmcFbioSpare, 18, 1:1, 30:30) \ HANDLER(EmcFbioCfg8, 18, 15:15, 31:31) \ HANDLER(EmcCmdMappingCmd3_0, 19, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_0, 19, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_0, 19, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_0, 19, 30:24, 27:21) \ HANDLER(McEmemAdrCfg, 19, 0:0, 28:28) \ HANDLER(McSecCarveoutProtectWriteAccess, 19, 0:0, 29:29) \ HANDLER(McMtsCarveoutRegCtrl, 19, 0:0, 30:30) \ HANDLER(McVideoProtectVprOverride, 19, 0:0, 31:31) \ HANDLER(EmcCmdMappingCmd3_1, 20, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_1, 20, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_1, 20, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_1, 20, 30:24, 27:21) \ HANDLER(McGeneralizedCarveout2Cfg0, 20, 6:3, 31:28) \ HANDLER(McGeneralizedCarveout4Cfg0, 39, 26:0, 26:0) \ HANDLER(McGeneralizedCarveout2Cfg0, 39, 10:7, 30:27) \ HANDLER(McVideoProtectVprOverride, 39, 1:1, 31:31) \ HANDLER(McGeneralizedCarveout5Cfg0, 40, 26:0, 26:0) \ HANDLER(McGeneralizedCarveout2Cfg0, 40, 17:14, 30:27) \ HANDLER(McVideoProtectVprOverride, 40, 2:2, 31:31) \ HANDLER(EmcCmdMappingCmd0_2, 41, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd0_2, 41, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd0_2, 41, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd0_2, 41, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout2Cfg0, 41, 21:18, 28:25) \ HANDLER(McGeneralizedCarveout2Cfg0, 41, 13:11, 31:29) \ HANDLER(EmcCmdMappingCmd1_2, 42, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd1_2, 42, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd1_2, 42, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd1_2, 42, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 42, 6:3, 28:25) \ HANDLER(McGeneralizedCarveout1Cfg0, 42, 13:11, 31:29) \ HANDLER(EmcCmdMappingCmd2_2, 43, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd2_2, 43, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd2_2, 43, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd2_2, 43, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 43, 10:7, 28:25) \ HANDLER(McGeneralizedCarveout3Cfg0, 43, 13:11, 31:29) \ HANDLER(EmcCmdMappingCmd3_2, 44, 6:0, 6:0) \ HANDLER(EmcCmdMappingCmd3_2, 44, 14:8, 13:7) \ HANDLER(EmcCmdMappingCmd3_2, 44, 22:16, 20:14) \ HANDLER(EmcCmdMappingCmd3_2, 44, 27:24, 24:21) \ HANDLER(McGeneralizedCarveout1Cfg0, 44, 17:14, 28:25) \ HANDLER(McVideoProtectVprOverride, 44, 3:3, 29:29) \ HANDLER(McVideoProtectVprOverride, 44, 7:6, 31:30) \ HANDLER(McEmemAdrCfgChannelMask, 45, 31:9, 22:0) \ HANDLER(McEmemAdrCfgDev0, 45, 2:0, 25:23) \ HANDLER(McEmemAdrCfgDev0, 45, 9:8, 27:26) \ HANDLER(McEmemAdrCfgDev0, 45, 19:16, 31:28) \ HANDLER(McEmemAdrCfgBankMask0, 46, 31:10, 21:0) \ HANDLER(McEmemAdrCfgDev1, 46, 2:0, 24:22) \ HANDLER(McEmemAdrCfgDev1, 46, 9:8, 26:25) \ HANDLER(McEmemAdrCfgDev1, 46, 19:16, 30:27) \ HANDLER(McVideoProtectVprOverride, 46, 8:8, 31:31) \ HANDLER(McEmemAdrCfgBankMask1, 47, 31:10, 21:0) \ HANDLER(McGeneralizedCarveout1Cfg0, 47, 21:18, 25:22) \ HANDLER(McGeneralizedCarveout3Cfg0, 47, 6:3, 29:26) \ HANDLER(McVideoProtectVprOverride, 47, 9:9, 30:30) \ HANDLER(McVideoProtectVprOverride, 47, 11:11, 31:31) \ HANDLER(McEmemAdrCfgBankMask2, 48, 31:10, 21:0) \ HANDLER(McGeneralizedCarveout3Cfg0, 48, 10:7, 25:22) \ HANDLER(McGeneralizedCarveout3Cfg0, 48, 17:14, 29:26) \ HANDLER(McVideoProtectVprOverride, 48, 15:14, 31:30) \ HANDLER(McVideoProtectGpuOverride1, 49, 15:0, 15:0) \ HANDLER(McEmemCfg, 49, 13:0, 29:16) \ HANDLER(McEmemCfg, 49, 31:31, 30:30) \ HANDLER(McVideoProtectVprOverride, 49, 17:17, 31:31) \ HANDLER(McGeneralizedCarveout3Bom, 50, 31:17, 14:0) \ HANDLER(McGeneralizedCarveout1Bom, 50, 31:17, 29:15) \ HANDLER(McVideoProtectVprOverride, 50, 19:18, 31:30) \ HANDLER(McGeneralizedCarveout4Bom, 51, 31:17, 14:0) \ HANDLER(McGeneralizedCarveout2Bom, 51, 31:17, 29:15) \ HANDLER(McVideoProtectVprOverride, 51, 21:20, 31:30) \ HANDLER(McGeneralizedCarveout5Bom, 52, 31:17, 14:0) \ HANDLER(McVideoProtectBom, 52, 31:20, 26:15) \ HANDLER(McGeneralizedCarveout3Cfg0, 52, 21:18, 30:27) \ HANDLER(McVideoProtectVprOverride, 52, 22:22, 31:31) \ HANDLER(McVideoProtectSizeMb, 53, 11:0, 11:0) \ HANDLER(McSecCarveoutBom, 53, 31:20, 23:12) \ HANDLER(McVideoProtectVprOverride, 53, 23:23, 24:24) \ HANDLER(McVideoProtectVprOverride, 53, 26:26, 25:25) \ HANDLER(McVideoProtectVprOverride, 53, 31:29, 28:26) \ HANDLER(McVideoProtectVprOverride1, 53, 1:0, 30:29) \ HANDLER(McVideoProtectVprOverride1, 53, 4:4, 31:31) \ HANDLER(McSecCarveoutSizeMb, 54, 11:0, 11:0) \ HANDLER(McMtsCarveoutBom, 54, 31:20, 23:12) \ HANDLER(McVideoProtectVprOverride1, 54, 12:5, 31:24) \ HANDLER(McMtsCarveoutSizeMb, 55, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout4Size128kb, 55, 11:0, 23:12) \ HANDLER(McVideoProtectVprOverride1, 55, 16:13, 27:24) \ HANDLER(McVideoProtectVprOverride1, 55, 26:25, 29:28) \ HANDLER(McGeneralizedCarveout2Cfg0, 55, 1:0, 31:30) \ HANDLER(McGeneralizedCarveout3Size128kb, 56, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout2Size128kb, 56, 11:0, 23:12) \ HANDLER(McGeneralizedCarveout2Cfg0, 56, 2:2, 24:24) \ HANDLER(McGeneralizedCarveout2Cfg0, 56, 26:22, 29:25) \ HANDLER(McGeneralizedCarveout1Cfg0, 56, 1:0, 31:30) \ HANDLER(McGeneralizedCarveout1Size128kb, 57, 11:0, 11:0) \ HANDLER(McGeneralizedCarveout5Size128kb, 57, 11:0, 23:12) \ HANDLER(McGeneralizedCarveout1Cfg0, 57, 2:2, 24:24) \ HANDLER(McGeneralizedCarveout1Cfg0, 57, 26:22, 29:25) \ HANDLER(McGeneralizedCarveout3Cfg0, 57, 1:0, 31:30) \ HANDLER(McGeneralizedCarveout3Cfg0, 58, 2:2, 0:0) \ HANDLER(McGeneralizedCarveout3Cfg0, 58, 26:22, 5:1) \ HANDLER(McGeneralizedCarveout1Access0, 59, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access1, 60, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access2, 61, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access3, 62, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1Access4, 63, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access0, 64, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access1, 65, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access2, 66, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access3, 67, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2Access4, 68, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access0, 69, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access1, 70, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access2, 71, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access3, 72, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3Access4, 73, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access0, 74, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access1, 75, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access2, 76, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access3, 77, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4Access4, 78, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access0, 79, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access1, 80, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access2, 81, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5Access3, 82, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess0, 84, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess1, 85, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess2, 86, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess3, 87, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout1ForceInternalAccess4, 88, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess0, 89, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess1, 90, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess2, 91, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess3, 92, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout2ForceInternalAccess4, 93, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess0, 94, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess1, 95, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess2, 96, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess3, 97, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout3ForceInternalAccess4, 98, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess0, 99, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess1, 100, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess2, 101, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess3, 102, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout4ForceInternalAccess4, 103, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess0, 104, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess1, 105, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess2, 106, 31:0, 31:0) \ HANDLER(McGeneralizedCarveout5ForceInternalAccess3, 107, 31:0, 31:0) ================================================ FILE: fusee/program/source/sein/fusee_secure_initialize.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fusee_secure_initialize.hpp" #include "../fusee_registers_di.hpp" namespace ams::nxboot { namespace { constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); constexpr inline const uintptr_t APB = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constexpr inline const uintptr_t AHB = AHB_ARBC(0); constexpr inline const uintptr_t I2S = I2S_REG(0); constexpr inline const uintptr_t DISP1 = secmon::MemoryRegionPhysicalDeviceDisp1.GetAddress(); constexpr inline const uintptr_t VIC = secmon::MemoryRegionPhysicalDeviceDsi.GetAddress() + 0x40000; constexpr inline const uintptr_t TIMER = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); constexpr inline const uintptr_t SYSCTR0 = secmon::MemoryRegionPhysicalDeviceSysCtr0.GetAddress(); void DoRcmWorkaround(const void *sbk, size_t sbk_size) { /* Set the SBK inside the security engine. */ se::SetAesKey(pkg1::AesKeySlot_SecureBoot, sbk, sbk_size); /* Lock the SBK/SSK as unreadable. */ se::LockAesKeySlot(pkg1::AesKeySlot_SecureBoot, se::KeySlotLockFlags_KeyRead); se::LockAesKeySlot(pkg1::AesKeySlot_SecureStorage, se::KeySlotLockFlags_KeyRead); /* Clear TZRAM. */ std::memset(secmon::MemoryRegionPhysicalTzram.GetPointer(), 0, secmon::MemoryRegionPhysicalTzram.GetSize()); /* Clear APBDEV_PMC_CRYPTO_OP. */ reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0); /* Clear the boot reason. */ reg::Write(PMC + APBDEV_PMC_SCRATCH200, 0); reg::Write(PMC + APBDEV_PMC_CRYPTO_OP, 0); /* Clear OBS_OVERRIDE/APB2JTAG_OVERRIDE */ reg::ReadWrite(AHB + AHB_AHB_SPARE_REG, AHB_REG_BITS_ENUM(AHB_SPARE_REG_OBS_OVERRIDE_EN, DISABLE), AHB_REG_BITS_ENUM(AHB_SPARE_REG_APB2JTAG_OVERRIDE_EN, DISABLE)); /* Clear low bits of APBDEV_PMC_SCRATCH49 */ reg::ClearBits(PMC + APBDEV_PMC_SCRATCH49, 0x3); } void DoMbistWorkaround() { /* Enable AHUB/APE clock prior to I2S accesses. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_CLK_ENB_AHUB, ENABLE)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_CLK_ENB_APE, ENABLE)); /* Configure CLK_RST_CONTROLLER_CLK_SOURCE_SOR1. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SOR1_SOR1_CLK_SEL0, MUX), CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SOR1_SOR1_CLK_SEL1, SOR1_CLOCK_SWITCH)); /* Set CSI clock source as PLLD. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLD_BASE, CLK_RST_REG_BITS_ENUM(PLLD_BASE_PLLD_ENABLE, ENABLE), CLK_RST_REG_BITS_ENUM(PLLD_BASE_CSI_CLK_SRC, PLL_D)); /* Clear APE, VIC, HOST1X, DISP1 reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_Y_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_Y_APE_RST, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_X_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_X_VIC_RST, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_DISP1_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_HOST1X_RST, ENABLE)); /* Wait two microseconds for the devices to come out of reset. */ util::WaitMicroSeconds(2); /* Set I2S_CTRL.MASTER and clear I2S_CG.SCLG_ENABLE for all I2S registers. */ reg::ReadWrite(I2S + I2S0_I2S_CTRL, I2S_REG_BITS_ENUM(I2S_CTRL_MASTER, ENABLE)); reg::ReadWrite(I2S + I2S0_I2S_CG, I2S_REG_BITS_ENUM(I2S_CG_SLCG_ENABLE, FALSE)); reg::ReadWrite(I2S + I2S1_I2S_CTRL, I2S_REG_BITS_ENUM(I2S_CTRL_MASTER, ENABLE)); reg::ReadWrite(I2S + I2S1_I2S_CG, I2S_REG_BITS_ENUM(I2S_CG_SLCG_ENABLE, FALSE)); reg::ReadWrite(I2S + I2S2_I2S_CTRL, I2S_REG_BITS_ENUM(I2S_CTRL_MASTER, ENABLE)); reg::ReadWrite(I2S + I2S2_I2S_CG, I2S_REG_BITS_ENUM(I2S_CG_SLCG_ENABLE, FALSE)); reg::ReadWrite(I2S + I2S3_I2S_CTRL, I2S_REG_BITS_ENUM(I2S_CTRL_MASTER, ENABLE)); reg::ReadWrite(I2S + I2S3_I2S_CG, I2S_REG_BITS_ENUM(I2S_CG_SLCG_ENABLE, FALSE)); reg::ReadWrite(I2S + I2S4_I2S_CTRL, I2S_REG_BITS_ENUM(I2S_CTRL_MASTER, ENABLE)); reg::ReadWrite(I2S + I2S4_I2S_CG, I2S_REG_BITS_ENUM(I2S_CG_SLCG_ENABLE, FALSE)); /* Set DC_COM_DSC_TOP_CTL.DSC_SLG_OVERRIDE */ reg::SetBits(DISP1 + DC_COM_DSC_TOP_CTL * sizeof(u32), 0x4); /* Set NV_PVIC_THI_SLCG_OVERRIDE_LOW_A */ reg::SetBits(VIC + NV_PVIC_THI_SLCG_OVERRIDE_LOW_A, 0xFFFFFFFF); /* Wait two microseconds for configuration to take. */ util::WaitMicroSeconds(2); /* Set APE, VIC, HOST1X, DISP1 reset. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_Y_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_Y_APE_RST, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_DISP1_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_L_HOST1X_RST, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_X_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_X_VIC_RST, ENABLE)); /* Set clock enable for a select few devices. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_FUSE, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_PMC, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_CACHE2, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_GPIO, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_TMR, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_L_CLK_ENB_RTC, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_CRAM2, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_IRAMD, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_IRAMC, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_IRAMB, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_IRAMA, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_U_CLK_ENB_CSITE, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_ENB_V_CLK_ENB_SE, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_V_CLK_ENB_SPDIF_DOUBLER, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_V_CLK_ENB_APB2APE, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_V_CLK_ENB_MSELECT, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_ENTROPY, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX5, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX4, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX3, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX2, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX1, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_PCIERX0, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_PLLG_REF, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_DBGAPB, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_GPU, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_MC_BBC, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_MC_CPU, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_MC_CBPA, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_MC_CAPA, ENABLE)); reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_CLK_ENB_MC_CDPA, ENABLE), CLK_RST_REG_BITS_ENUM(CLK_ENB_Y_CLK_ENB_MC_CCPA, ENABLE)); /* Clear all LVL2 clock gate overrides to zero. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, 0); reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE, 0); /* Reset CSI clock source. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLD_BASE, CLK_RST_REG_BITS_ENUM(PLLD_BASE_PLLD_BYPASS, DISABLE), CLK_RST_REG_BITS_ENUM(PLLD_BASE_PLLD_ENABLE, DISABLE), CLK_RST_REG_BITS_ENUM(PLLD_BASE_PLLD_REF_DIS, REF_ENABLE), CLK_RST_REG_BITS_ENUM(PLLD_BASE_CSI_CLK_SRC, BRICK)); /* Configure CLK_RST_CONTROLLER_CLK_SOURCE_SOR1. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SOR1_SOR1_CLK_SEL0, MUX), CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SOR1_SOR1_CLK_SEL1, SAFE_CLOCK)); /* Configure VI, HOST1X, NVENC clock sources. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_VI, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_VI_VI_CLK_SRC, PLLP_OUT0)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_HOST1X_HOST1X_CLK_SRC, PLLP_OUT0)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_NVENC, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_NVENC_NVENC_CLK_SRC, PLLP_OUT0)); } void EnableArc() { /* Enable clocks for EMC/MC, using PLLP_OUT0. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_SOURCE_EMC, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_EMC_EMC_2X_CLK_SRC, PLLP_OUT0)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_EMC, ENABLE)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_H_CLK_ENB_MEM, ENABLE)); reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_X_CLK_ENB_EMC_DLL, ENABLE)); /* Clear reset for MEM/EMC. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_RST_DEV_H_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_H_EMC_RST, ENABLE), CLK_RST_REG_BITS_ENUM(RST_DEV_H_MEM_RST, ENABLE)); /* Wait 5 microseconds for configuration to take. */ util::WaitMicroSeconds(5); /* Enable ARC_CLK_OVR_ON. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, CLK_RST_REG_BITS_ENUM(LVL2_CLK_GATE_OVRD_ARC_CLK_OVR_ON, ON)); /* Enable the ARC. */ reg::ReadWrite(MC + MC_IRAM_REG_CTRL, MC_REG_BITS_ENUM(IRAM_REG_CTRL_IRAM_CFG_WRITE_ACCESS, ENABLED)); /* Set IRAM BOM/TOP to open up access to all mmio. */ reg::Write(MC + MC_IRAM_BOM, 0x40000000); reg::Write(MC + MC_IRAM_TOM, 0x80000000); /* Read to ensure our configuration takes. */ reg::Read(MC + MC_IRAM_REG_CTRL); } void InitializeClock() { /* Set SPARE_REG0 clock divisor 2. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_SPARE_REG0, CLK_RST_REG_BITS_ENUM(SPARE_REG0_CLK_M_DIVISOR, CLK_M_DIVISOR2)); /* Set system counter frequency. */ reg::Write(SYSCTR0 + SYSCTR0_CNTFID0, 19'200'000); /* Restore TIMERUS config to 19.2 MHz. */ reg::Write(TIMER + TIMERUS_USEC_CFG, TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVIDEND, 5 - 1), TIMER_REG_BITS_VALUE(USEC_CFG_USEC_DIVISOR, 96 - 1)); /* Enable the crystal oscillator, and copy the drive strength from pmc. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_OSC_CTRL, CLK_RST_REG_BITS_ENUM (OSC_CTRL_OSC_FREQ, OSC38P4), CLK_RST_REG_BITS_ENUM (OSC_CTRL_XOE, ENABLE), CLK_RST_REG_BITS_VALUE(OSC_CTRL_XOFS, 7)); /* Set the crystal oscillator value in PMC. */ reg::ReadWrite(PMC + APBDEV_PMC_OSC_EDPD_OVER, PMC_REG_BITS_VALUE(OSC_EDPD_OVER_XOFS, 7)); /* Configure the crystal oscillator to use PMC value on warmboot. */ reg::ReadWrite(PMC + APBDEV_PMC_OSC_EDPD_OVER, PMC_REG_BITS_ENUM(OSC_EDPD_OVER_OSC_CTRL_SELECT, PMC)); /* Set HOLD_CKE_LOW_EN. */ reg::ReadWrite(PMC + APBDEV_PMC_CNTRL2, PMC_REG_BITS_ENUM(CNTRL2_HOLD_CKE_LOW_EN, ENABLE)); /* Set CFG2TMC_RAM_SVOP_PDP to 2. */ /* NOTE: Nintendo acidentally writes this to the PMC instead of the APB due to a bug. */ reg::ReadWrite(APB + APB_MISC_GP_ASDBGREG, APB_MISC_REG_BITS_VALUE(GP_ASDBGREG_CFG2TMC_RAM_SVOP_PDP, 2)); /* Set CLK_SYSTEM_RATE. */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 1), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 0)); /* Configure PLLMB_BASE. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_PLLMB_BASE, CLK_RST_REG_BITS_ENUM(PLLMB_BASE_PLLMB_ENABLE, DISABLE)); /* Configure TSC_MULT. */ constexpr u32 TscMultValue = 19'200'000 * 16 / 32768; reg::ReadWrite(PMC + APBDEV_PMC_TSC_MULT, PMC_REG_BITS_VALUE(TSC_MULT_MULT_VAL, TscMultValue)); /* Configure SCLK_BURST_POLICY */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT2), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT2), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT2), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, PLLP_OUT2)); /* Configure SUPER_SCLK_DIVIDER */ reg::Write(CLKRST + CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER, CLK_RST_REG_BITS_ENUM (SUPER_SCLK_DIVIDER_SUPER_SDIV_ENB, ENABLE), CLK_RST_REG_BITS_ENUM (SUPER_SCLK_DIVIDER_SUPER_SDIV_DIS_FROM_COP_FIQ, NOP), CLK_RST_REG_BITS_ENUM (SUPER_SCLK_DIVIDER_SUPER_SDIV_DIS_FROM_CPU_FIQ, NOP), CLK_RST_REG_BITS_ENUM (SUPER_SCLK_DIVIDER_SUPER_SDIV_DIS_FROM_COP_IRQ, NOP), CLK_RST_REG_BITS_ENUM (SUPER_SCLK_DIVIDER_SUPER_SDIV_DIS_FROM_CPU_IRQ, NOP), CLK_RST_REG_BITS_VALUE(SUPER_SCLK_DIVIDER_SUPER_SDIV_DIVIDEND, 0), CLK_RST_REG_BITS_VALUE(SUPER_SCLK_DIVIDER_SUPER_SDIV_DIVISOR, 0)); /* Set CLK_SYSTEM_RATE */ reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 2)); } void InitializePinmux(fuse::HardwareType hw_type) { /* Clear global pinmux control register */ reg::Write(APB + APB_MISC_PP_PINMUX_GLOBAL_0, 0); /* Perform initial pinmux setup. */ pinmux::SetupFirst(hw_type); /* Setup important pinmux devices. */ pinmux::SetupI2c1(); pinmux::SetupI2c5(); pinmux::SetupUartA(); pinmux::SetupVolumeButton(); pinmux::SetupHomeButton(); } } void SecureInitialize(bool enable_log) { /* Get SoC type/hardware type. */ const auto soc_type = fuse::GetSocType(); const auto hw_type = fuse::GetHardwareType(); /* If Erista, perform bootrom logic (to compensate for RCM exploit) and MBIST workaround. */ if (soc_type == fuse::SocType_Erista) { /* Potentially perform bootrom compensation. */ { u32 sbk[4]; if (fuse::GetSecureBootKey(sbk)) { DoRcmWorkaround(sbk, sizeof(sbk)); } } DoMbistWorkaround(); } /* Initialize security engine clock. */ clkrst::EnableSeClock(); /* Set fuse visibility. */ clkrst::SetFuseVisibility(true); /* Disable fuse programming. */ fuse::Lockout(); /* Initialize the security engine. */ se::Initialize(); /* Enable the arc. */ EnableArc(); /* Setup initial clocks. */ InitializeClock(); /* Setup initial pinmux. */ InitializePinmux(hw_type); /* Initialize logging. */ if (enable_log) { clkrst::EnableUartAClock(); } /* Enable various clocks. */ clkrst::EnableCldvfsClock(); clkrst::EnableI2c1Clock(); clkrst::EnableI2c5Clock(); clkrst::EnableTzramClock(); /* Ensure avp cache is enabled, since we'll be using it. */ clkrst::EnableCache2Clock(); clkrst::EnableCram2Clock(); /* Initialize I2C5. */ i2c::Initialize(i2c::Port_5); /* Configure pmic system setting. */ pmic::SetSystemSetting(soc_type); /* Enable VDD core */ pmic::EnableVddCore(soc_type); /* On hoag, enable Ldo8 */ if (hw_type == fuse::HardwareType_Hoag) { pmic::EnableLdo8(); } /* Initialize I2C1. */ i2c::Initialize(i2c::Port_1); /* Configure SCLK_BURST_POLICY. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, PLLP_OUT0)); /* Do mariko-only TZRAM configuration. */ if (soc_type == fuse::SocType_Mariko) { reg::ReadWrite(PMC + APBDEV_PMC_TZRAM_PWR_CNTRL, PMC_REG_BITS_VALUE(TZRAM_PWR_CNTRL_TZRAM_SD, 0)); reg::Write(PMC + APBDEV_PMC_TZRAM_NON_SEC_DISABLE, PMC_REG_BITS_ENUM(TZRAM_NON_SEC_DISABLE_SD_WRITE, ON), PMC_REG_BITS_ENUM(TZRAM_NON_SEC_DISABLE_SD_READ, ON)); reg::Write(PMC + APBDEV_PMC_TZRAM_SEC_DISABLE, PMC_REG_BITS_ENUM(TZRAM_SEC_DISABLE_SD_WRITE, ON), PMC_REG_BITS_ENUM(TZRAM_SEC_DISABLE_SD_READ, ON)); } /* Hold certain devices in reset. */ reg::ReadWrite(CLKRST + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_USBD_RST, ENABLE)); } } ================================================ FILE: fusee/program/source/sein/fusee_secure_initialize.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #pragma once namespace ams::nxboot { void SecureInitialize(bool enable_log); } ================================================ FILE: fusee/program/update_mtc_tables.py ================================================ #!/usr/bin/env python import sys, lz4, os from struct import unpack as up def lz4_compress(data): try: import lz4.block as block except ImportError: block = lz4.LZ4_compress return block.compress(data, 'high_compression', store_size=False) def read_file(fn): with open(fn, 'rb') as f: return f.read() def write_file(fn, data): with open(fn, 'wb') as f: f.write(data) def get_param_size(soc): return { 'erista' : 0x1340, 'mariko' : 0x10CC, }[soc] def main(argc, argv): if argc != 1: print('Usage: %s' % argv[0]) return 1 params = { 'erista' : {}, 'mariko' : {}, } compressed_params = { 'erista' : {}, 'mariko' : {}, } for board in os.listdir('mtc_tables/bin'): if board.startswith('T210b01Sdev'): soc = 'mariko' count = 3 else: assert board.startswith('T210Sdev') soc = 'erista' count = 10 assert os.listdir('mtc_tables/bin/%s' % board) == ['%d.bin' % i for i in xrange(count)] params[soc][board] = [] compressed_params[soc][board] = [] for i in xrange(count): uncompressed = read_file(os.path.join('mtc_tables/bin/%s' % board, '%d.bin' % i)) assert len(uncompressed) == get_param_size(soc) compressed = lz4_compress(uncompressed) params[soc][board].append(uncompressed) compressed_params[soc][board].append(compressed) try: os.makedirs('mtc_tables/lz/%s' % board) except: pass write_file(os.path.join('mtc_tables/lz/%s' % board, '%d.lz4' % i), compressed) try: os.makedirs('mtc_tables/combined/%s' % board) except: pass data_1600 = params[soc][board][-1] data_800 = params[soc][board][-4] if soc == 'erista' else '' data_204 = params[soc][board][0] if soc == 'mariko' else params[soc][board][3] assert up('<I', data_1600[0x40:0x44])[0] == 1600000 assert up('<I', data_204[0x40:0x44])[0] == 204000 if soc == 'erista': assert up('<I', data_800[0x40:0x44])[0] == 800000 if soc == 'mariko': data = lz4_compress(data_204 + data_1600) else: data = data_204 + data_800 + data_1600 write_file(os.path.join('mtc_tables/combined/%s' % board, 'table.bin'), data) for soc in ('erista', 'mariko'): with open('source/mtc/fusee_mtc_tables_%s.inc' % soc, 'w') as f: f.write('%s\n' % "/*") f.write('%s\n' % " * Copyright (c) Atmosph\xc3\xa8re-NX") f.write('%s\n' % " *") f.write('%s\n' % " * This program is free software; you can redistribute it and/or modify it") f.write('%s\n' % " * under the terms and conditions of the GNU General Public License,") f.write('%s\n' % " * version 2, as published by the Free Software Foundation.") f.write('%s\n' % " *") f.write('%s\n' % " * This program is distributed in the hope it will be useful, but WITHOUT") f.write('%s\n' % " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or") f.write('%s\n' % " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for") f.write('%s\n' % " * more details.") f.write('%s\n' % " *") f.write('%s\n' % " * You should have received a copy of the GNU General Public License") f.write('%s\n' % " * along with this program. If not, see <http://www.gnu.org/licenses/>.") f.write('%s\n' % " */") f.write('\n') for board in compressed_params[soc].keys(): f.write('%s\n' % ('constexpr const u8 %s[] = {' % (board))) f.write('%s\n' % (' #embed "../../mtc_tables/combined/%s/table.bin"' % (board))) f.write('};\n\n') return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv)) ================================================ FILE: fusee/program/update_sdram_params.py ================================================ #!/usr/bin/env python import sys, lz4, os from struct import unpack as up def lz4_compress(data): try: import lz4.block as block except ImportError: block = lz4.LZ4_compress return block.compress(data, 'high_compression', store_size=False) def read_file(fn): with open(fn, 'rb') as f: return f.read() def write_file(fn, data): with open(fn, 'wb') as f: f.write(data) def get_param_size(soc): return { 'erista' : 0x768, 'mariko' : 0x838, }[soc] def main(argc, argv): if argc != 1: print('Usage: %s' % argv[0]) return 1 params = { 'erista' : {}, 'mariko' : {}, } compressed_params = { 'erista' : {}, 'mariko' : {}, } for fn in os.listdir('sdram_params/bin'): assert fn.startswith('sdram_params_') and fn.endswith('.bin') (_sdram, _params, soc, _id_bin) = tuple(fn.split('_')) param_id = int(_id_bin[:-len('.bin')]) assert soc in params.keys() uncompressed = read_file(os.path.join('sdram_params/bin', fn)) assert len(uncompressed) == get_param_size(soc) params[soc][param_id] = uncompressed for soc in ('erista', 'mariko'): empty_params = '\x00' * get_param_size(soc) for param_id in xrange(0, max(params[soc].keys()) + 4, 2): param_id_l = param_id param_id_h = param_id + 1 if param_id_l in params[soc] or param_id_h in params[soc]: print soc, param_id_l, param_id_h param_l = params[soc][param_id_l] if param_id_l in params[soc] else empty_params param_h = params[soc][param_id_h] if param_id_h in params[soc] else empty_params compressed = lz4_compress(param_l + param_h) compressed_params[soc][(param_id_l, param_id_h)] = compressed write_file(os.path.join('sdram_params/lz', 'sdram_params_%s_%d_%d.lz4' % (soc, param_id_l, param_id_h)), compressed) with open('source/sdram/fusee_sdram_params.inc', 'w') as f: f.write('%s\n' % "/*") f.write('%s\n' % " * Copyright (c) Atmosph\xc3\xa8re-NX") f.write('%s\n' % " *") f.write('%s\n' % " * This program is free software; you can redistribute it and/or modify it") f.write('%s\n' % " * under the terms and conditions of the GNU General Public License,") f.write('%s\n' % " * version 2, as published by the Free Software Foundation.") f.write('%s\n' % " *") f.write('%s\n' % " * This program is distributed in the hope it will be useful, but WITHOUT") f.write('%s\n' % " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or") f.write('%s\n' % " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for") f.write('%s\n' % " * more details.") f.write('%s\n' % " *") f.write('%s\n' % " * You should have received a copy of the GNU General Public License") f.write('%s\n' % " * along with this program. If not, see <http://www.gnu.org/licenses/>.") f.write('%s\n' % " */") f.write('\n') for soc in ('Erista', 'Mariko'): for (param_id_l, param_id_h) in sorted(compressed_params[soc.lower()].keys(), key=lambda (l, h): l): compressed = compressed_params[soc.lower()][(param_id_l, param_id_h)] f.write('%s\n' % ('constexpr inline const u8 SdramParams%s%d_%d[0x%03X] = {' % (soc, param_id_l, param_id_h, len(compressed)))) f.write('%s\n' % (' #embed "../../sdram_params/lz/sdram_params_%s_%d_%d.lz4"' % (soc.lower(), param_id_l, param_id_h))) f.write('};\n\n') f.write('%s\n' % ('constexpr inline const u8 * const SdramParams%s%d = SdramParams%s%d_%d;' % (soc, param_id_l, soc, param_id_l, param_id_h))) f.write('%s\n' % ('constexpr inline const size_t SdramParamsSize%s%d = sizeof(SdramParams%s%d_%d);' % (soc, param_id_l, soc, param_id_l, param_id_h))) f.write('\n') f.write('%s\n' % ('constexpr inline const u8 * const SdramParams%s%d = SdramParams%s%d_%d;' % (soc, param_id_h, soc, param_id_l, param_id_h))) f.write('%s\n' % ('constexpr inline const size_t SdramParamsSize%s%d = sizeof(SdramParams%s%d_%d);' % (soc, param_id_h, soc, param_id_l, param_id_h))) f.write('\n') return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv)) ================================================ FILE: libraries/.gitignore ================================================ # Prerequisites *.d # Object files *.o *.ko *.obj *.elf # Linker output *.ilk *.map *.exp *.lst # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Switch Executables *.nso *.nro *.nacp *.npdm *.pfs0 *.nsp *.kip # Debug files *.dSYM/ *.su *.idb *.pdb # Kernel Module Compile Results *.mod* *.cmd .tmp_versions/ modules.order Module.symvers Mkfile.old dkms.conf # Distribution files *.tgz *.zip .**/ # NOTE: make sure to make exceptions to this pattern when needed! *.bin **/out **/build ================================================ FILE: libraries/.gitmodules ================================================ ================================================ FILE: libraries/.gitrepo ================================================ ; DO NOT EDIT (unless you know what you are doing) ; ; This subdirectory is a git "subrepo", and this file is maintained by the ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme ; [subrepo] remote = https://github.com/Atmosphere-NX/Atmosphere-libs branch = master commit = 9a8703e710760be8c88147d15414a1c581711625 parent = eb34f9789c62745d87f37e76761b14d946bac300 method = merge cmdver = 0.4.1 ================================================ FILE: libraries/LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: libraries/README.md ================================================ ![License](https://img.shields.io/badge/License-GPLv2-blue.svg) Atmosphere-libs is a collection of libraries for doing operating system development for the Nintendo Switch. Licensing ===== This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the atmosphere-libs project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects. * [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project under the Zero-Clause BSD license. Credits ===== Atmosphere-libs is currently being developed and maintained by __SciresM__.<br> In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to atmosphere-libs in some significant way: * @[devkitPro](https://github.com/devkitPro) * @[yellows8](https://github.com/yellows8) * @[qlutoo](https://github.com/plutooo) * @[hedgeberg](https://github.com/hedgeberg) * @[Nintendo](https://github.com/Nintendo) * @[NVidia](https://github.com/NVidia) * @[Kaphotics](https://github.com/kwsch) Additional credits may be found in the README.md for specific libraries. ================================================ FILE: libraries/config/arch/arm/arch.mk ================================================ ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/devkitARM/base_rules export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/arm/cpu/arm7tdmi/cpu.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_ARM7TDMI export ATMOSPHERE_SETTINGS += -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork -fstrict-volatile-bitfields export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/arm64/arch.mk ================================================ ifeq ($(strip $(ATMOSPHERE_OS_NAME)),horizon) ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/devkitA64/base_rules else include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_rules endif export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64 export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ifeq ($(strip $(ATMOSPHERE_OS_NAME)),horizon) export ATMOSPHERE_SETTINGS += -mtp=soft endif ================================================ FILE: libraries/config/arch/arm64/base_rules ================================================ include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_tools #--------------------------------------------------------------------------------- %.a: #--------------------------------------------------------------------------------- $(SILENTMSG) $(notdir $@) @rm -f $@ $(SILENTCMD)$(AR) -rc $@ $^ #--------------------------------------------------------------------------------- %.o: %.cpp $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.c $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.s @echo $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.S $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) ================================================ FILE: libraries/config/arch/arm64/base_tools ================================================ #--------------------------------------------------------------------------------- # the prefix on the compiler executables #--------------------------------------------------------------------------------- PREFIX := ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) export CC := gcc export CXX := g++ export AS := as export AR := gcc-ar export OBJCOPY := objcopy export STRIP := strip export NM := gcc-nm export RANLIB := gcc-ranlib else ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) export CC := clang export CXX := clang++ export AS := llvm-as export AR := llvm-ar export OBJCOPY := llvm-objcopy export STRIP := llvm-strip export NM := llvm-nm export RANLIB := llvm-ranlib endif ISVC=$(or $(VCBUILDHELPER_COMMAND),$(MSBUILDEXTENSIONSPATH32),$(MSBUILDEXTENSIONSPATH)) ifneq (,$(ISVC)) ERROR_FILTER := 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g' endif #--------------------------------------------------------------------------------- # allow seeing compiler command lines with make V=1 (similar to autotools' silent) #--------------------------------------------------------------------------------- ifeq ($(V),1) SILENTMSG := @true SILENTCMD := else SILENTMSG := @echo SILENTCMD := @ endif #--------------------------------------------------------------------------------- # canned command sequence for binary data #--------------------------------------------------------------------------------- define bin2o bin2s -a 8 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o endef ================================================ FILE: libraries/config/arch/arm64/cpu/cortex_a57/cpu.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_ARM_CORTEX_A57 export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mtune=cortex-a57 export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/arm64/cpu/generic_arm64/cpu.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_GENERIC_ARM64 export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mno-outline-atomics export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/armv4t/arch.mk ================================================ ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/devkitARM/base_rules export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM_V4T export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/armv8a/arch.mk ================================================ ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/devkitA64/base_rules export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM_V8A export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/x64/arch.mk ================================================ include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_rules export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_X64 export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/arch/x64/base_rules ================================================ include $(ATMOSPHERE_ARCH_MAKE_DIR)/base_tools #--------------------------------------------------------------------------------- %.a: #--------------------------------------------------------------------------------- $(SILENTMSG) $(notdir $@) @rm -f $@ $(SILENTCMD)$(AR) -rc $@ $^ #--------------------------------------------------------------------------------- %.o: %.cpp $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.c $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.s @echo $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) #--------------------------------------------------------------------------------- %.o: %.S $(SILENTMSG) $(notdir $<) $(SILENTCMD)$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) ================================================ FILE: libraries/config/arch/x64/base_tools ================================================ #--------------------------------------------------------------------------------- # the prefix on the compiler executables #--------------------------------------------------------------------------------- PREFIX := ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) export CC := gcc export CXX := g++ export AS := as export AR := gcc-ar export OBJCOPY := objcopy export STRIP := strip export NM := gcc-nm export RANLIB := gcc-ranlib else ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) export CC := clang export CXX := clang++ export AS := llvm-as export AR := llvm-ar export OBJCOPY := llvm-objcopy export STRIP := llvm-strip export NM := llvm-nm export RANLIB := llvm-ranlib endif ISVC=$(or $(VCBUILDHELPER_COMMAND),$(MSBUILDEXTENSIONSPATH32),$(MSBUILDEXTENSIONSPATH)) ifneq (,$(ISVC)) ERROR_FILTER := 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g' endif #--------------------------------------------------------------------------------- # allow seeing compiler command lines with make V=1 (similar to autotools' silent) #--------------------------------------------------------------------------------- ifeq ($(V),1) SILENTMSG := @true SILENTCMD := else SILENTMSG := @echo SILENTCMD := @ endif #--------------------------------------------------------------------------------- # canned command sequence for binary data #--------------------------------------------------------------------------------- define bin2o bin2s -a 8 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o endef ================================================ FILE: libraries/config/arch/x64/cpu/generic_x64/cpu.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_GENERIC_X64 export ATMOSPHERE_SETTINGS += -march=native -mtune=generic export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/board/generic/linux/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_GENERIC_LINUX export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) export ATMOSPHERE_CXXFLAGS += -stdlib=libc++ ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),x64) export ATMOSPHERE_SETTINGS += -target x86_64-pc-linux-gnu else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) export ATMOSPHERE_SETTINGS += -target aarch64-linux-gnu endif endif # TODO: Better way of doing this? export ATMOSPHERE_CXXFLAGS += -I/opt/libjpeg-turbo/include ================================================ FILE: libraries/config/board/generic/macos/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_GENERIC_MACOS export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) export ATMOSPHERE_CXXFLAGS += -stdlib=libc++ ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),x64) export ATMOSPHERE_SETTINGS += -target x86_64-apple-darwin else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) export ATMOSPHERE_SETTINGS += -target aarch64-apple-darwin endif endif ifeq ($(strip $(SDKROOT)),) export SDKROOT := $(shell xcrun --sdk macosx --show-sdk-path) endif # TODO: Better way of doing this? export ATMOSPHERE_CXXFLAGS += -I/opt/libjpeg-turbo/include ================================================ FILE: libraries/config/board/generic/windows/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_GENERIC_WINDOWS export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/board/nintendo/nx/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__SWITCH__ export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/board/nintendo/nx_bpmp/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_NINTENDO_NX -D__BPMP__ export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/board/qemu/virt/board.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_QEMU_VIRT -D__SWITCH__ export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/common.mk ================================================ #--------------------------------------------------------------------------------- .SUFFIXES: #--------------------------------------------------------------------------------- DIR_WILDCARD=$(foreach d,$(wildcard $(1:=/*)),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,)) export ATMOSPHERE_CONFIG_MAKE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) export ATMOSPHERE_LIBRARIES_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/.. ifeq ($(strip $(ATMOSPHERE_BOARD)),) export ATMOSPHERE_BOARD := nx-hac-001 ifeq ($(strip $(ATMOSPHERE_CPU)),) export ATMOSPHERE_CPU := arm-cortex-a57 endif endif ifeq ($(ATMOSPHERE_BUILD_NAME),) export ATMOSPHERE_BUILD_NAME := release endif ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),) ifneq ($(strip $(ATMOSPHERE_BOARD)),generic_macos) export ATMOSPHERE_COMPILER_NAME := gcc else export ATMOSPHERE_COMPILER_NAME := clang endif export ATMOSPHERE_BUILD_NAME := release endif ATMOSPHERE_BUILD_SETTINGS ?= export ATMOSPHERE_DEFINES := -DATMOSPHERE export ATMOSPHERE_SETTINGS := -fPIE -g $(ATMOSPHERE_BUILD_SETTINGS) export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \ -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \ -Wno-format-zero-length ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) export ATMOSPHERE_CFLAGS += -Wno-stringop-truncation -Wno-format-truncation else ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),clang) export ATMOSPHERE_CFLAGS += -Wno-c99-designator -Wno-gnu-alignof-expression -Wno-unused-private-field endif export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++23 -Wno-invalid-offsetof export ATMOSPHERE_ASFLAGS := ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) export ATMOSPHERE_ARCH_DIR := arm64 export ATMOSPHERE_BOARD_DIR := nintendo/nx export ATMOSPHERE_OS_DIR := horizon export ATMOSPHERE_ARCH_NAME := arm64 export ATMOSPHERE_BOARD_NAME := nintendo_nx export ATMOSPHERE_OS_NAME := horizon export ATMOSPHERE_SUB_ARCH_DIR := armv8a export ATMOSPHERE_SUB_ARCH_NAME := armv8a export ATMOSPHERE_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension export ATMOSPHERE_BOOT_CPU := arm7tdmi export ATMOSPHERE_BOOT_ARCH_NAME := arm export ATMOSPHERE_BOOT_BOARD_NAME := nintendo_nx export ATMOSPHERE_BOOT_OS_NAME := horizon export ATMOSPHERE_BOOT_SUB_ARCH_NAME := armv4t else ifeq ($(ATMOSPHERE_CPU),arm7tdmi) export ATMOSPHERE_ARCH_DIR := arm export ATMOSPHERE_BOARD_DIR := nintendo/nx_bpmp export ATMOSPHERE_OS_DIR := horizon export ATMOSPHERE_ARCH_NAME := arm export ATMOSPHERE_BOARD_NAME := nintendo_nx export ATMOSPHERE_OS_NAME := horizon export ATMOSPHERE_SUB_ARCH_DIR := armv4t export ATMOSPHERE_SUB_ARCH_NAME := armv4t export ATMOSPHERE_CPU_EXTENSIONS := endif export ATMOSPHERE_LIBDIRS := else ifeq ($(ATMOSPHERE_BOARD),qemu-virt) ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) export ATMOSPHERE_ARCH_DIR := arm64 export ATMOSPHERE_BOARD_DIR := qemu/virt export ATMOSPHERE_OS_DIR := horizon export ATMOSPHERE_ARCH_NAME := arm64 export ATMOSPHERE_BOARD_NAME := qemu_virt export ATMOSPHERE_OS_NAME := horizon export ATMOSPHERE_SUB_ARCH_DIR = armv8a export ATMOSPHERE_SUB_ARCH_NAME = armv8a export ATMOSPHERE_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension endif export ATMOSPHERE_LIBDIRS := else ifeq ($(ATMOSPHERE_BOARD),generic_windows) ifeq ($(ATMOSPHERE_CPU),generic_x64) export ATMOSPHERE_ARCH_DIR := x64 export ATMOSPHERE_BOARD_DIR := generic/windows export ATMOSPHERE_OS_DIR := windows export ATMOSPHERE_ARCH_NAME := x64 export ATMOSPHERE_BOARD_NAME := generic_windows export ATMOSPHERE_OS_NAME := windows endif else ifeq ($(ATMOSPHERE_BOARD),generic_linux) ifeq ($(ATMOSPHERE_CPU),generic_x64) export ATMOSPHERE_ARCH_DIR := x64 export ATMOSPHERE_ARCH_NAME := x64 else ifeq ($(ATMOSPHERE_CPU),generic_arm64) export ATMOSPHERE_ARCH_DIR := arm64 export ATMOSPHERE_ARCH_NAME := arm64 endif export ATMOSPHERE_BOARD_DIR := generic/linux export ATMOSPHERE_OS_DIR := linux export ATMOSPHERE_BOARD_NAME := generic_linux export ATMOSPHERE_OS_NAME := linux else ifeq ($(ATMOSPHERE_BOARD),generic_macos) ifeq ($(ATMOSPHERE_CPU),generic_x64) export ATMOSPHERE_ARCH_DIR := x64 export ATMOSPHERE_ARCH_NAME := x64 else ifeq ($(ATMOSPHERE_CPU),generic_arm64) export ATMOSPHERE_ARCH_DIR := arm64 export ATMOSPHERE_ARCH_NAME := arm64 endif export ATMOSPHERE_BOARD_DIR := generic/macos export ATMOSPHERE_OS_DIR := macos export ATMOSPHERE_BOARD_NAME := generic_macos export ATMOSPHERE_OS_NAME := macos endif ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) export ATMOSPHERE_CPU_DIR := cortex_a57 export ATMOSPHERE_CPU_NAME := arm_cortex_a57 endif ifeq ($(ATMOSPHERE_CPU),arm7tdmi) export ATMOSPHERE_CPU_DIR := arm7tdmi export ATMOSPHERE_CPU_NAME := arm7tdmi endif ifeq ($(ATMOSPHERE_CPU),generic_x64) export ATMOSPHERE_CPU_DIR := generic_x64 export ATMOSPHERE_CPU_NAME := generic_x64 endif ifeq ($(ATMOSPHERE_CPU),generic_arm64) export ATMOSPHERE_CPU_DIR := generic_arm64 export ATMOSPHERE_CPU_NAME := generic_arm64 endif export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/arch/$(ATMOSPHERE_ARCH_DIR) export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/board/$(ATMOSPHERE_BOARD_DIR) export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/os/$(ATMOSPHERE_OS_DIR) export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_ARCH_MAKE_DIR)/cpu/$(ATMOSPHERE_CPU_DIR) ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),) export ATMOSPHERE_FULL_NAME := $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)_$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_LIBRARY_DIR := lib/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BUILD_DIR := build/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_OUT_DIR := out/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) else export ATMOSPHERE_FULL_NAME := $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_LIBRARY_DIR := lib/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BUILD_DIR := build/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_OUT_DIR := out/$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) endif ifneq ($(strip $(ATMOSPHERE_BOOT_ARCH_NAME)),) ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),) export ATMOSPHERE_BOOT_FULL_NAME := $(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)_$(ATMOSPHERE_BOOT_SUB_ARCH_NAME)_$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_LIBRARY_DIR := lib/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)_$(ATMOSPHERE_BOOT_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_BUILD_DIR := build/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)_$(ATMOSPHERE_BOOT_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_OUT_DIR := out/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)_$(ATMOSPHERE_BOOT_SUB_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) else export ATMOSPHERE_BOOT_FULL_NAME := $(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)_$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_LIBRARY_DIR := lib/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_BUILD_DIR := build/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) export ATMOSPHERE_BOOT_OUT_DIR := out/$(ATMOSPHERE_BOOT_BOARD_NAME)_$(ATMOSPHERE_BOOT_ARCH_NAME)/$(ATMOSPHERE_BUILD_NAME) endif else export ATMOSPHERE_BOOT_FULL_NAME := $(ATMOSPHERE_FULL_NAME) export ATMOSPHERE_BOOT_LIBRARY_DIR := $(ATMOSPHERE_LIBRARY_DIR) export ATMOSPHERE_BOOT_BUILD_DIR := $(ATMOSPHERE_BUILD_DIR) export ATMOSPHERE_BOOT_OUT_DIR := $(ATMOSPHERE_OUT_DIR) endif ifeq ($(strip $(ATMOSPHERE_BOOT_CPU)),) export ATMOSPHERE_BOOT_CPU := $(ATMOSPHERE_CPU) endif include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk include $(ATMOSPHERE_CPU_MAKE_DIR)/cpu.mk ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),) export ATMOSPHERE_SUB_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/arch/$(ATMOSPHERE_SUB_ARCH_DIR) include $(ATMOSPHERE_SUB_ARCH_MAKE_DIR)/arch.mk endif #--------------------------------------------------------------------------------- # get atmosphere git revision information #--------------------------------------------------------------------------------- export ATMOSPHERE_GIT_BRANCH := $(shell git symbolic-ref --short HEAD) ifeq ($(strip $(shell git status --porcelain 2>/dev/null)),) export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD) else export ATMOSPHERE_GIT_REVISION := $(ATMOSPHERE_GIT_BRANCH)-$(shell git rev-parse --short HEAD)-dirty endif export ATMOSPHERE_GIT_HASH := $(shell git rev-parse --short=16 HEAD) ATMOSPHERE_DEFINES += -DATMOSPHERE_GIT_BRANCH=\"$(ATMOSPHERE_GIT_BRANCH)\" -DATMOSPHERE_GIT_REVISION=\"$(ATMOSPHERE_GIT_REVISION)\" -DATMOSPHERE_GIT_HASH="0x$(ATMOSPHERE_GIT_HASH)" #--------------------------------------------------------------------------------- # Ensure top directory is set. #--------------------------------------------------------------------------------- TOPDIR ?= $(CURDIR) #--------------------------------------------------------------------------------- # TARGET is the name of the output # SOURCES is a list of directories containing source code # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) BUILD := build DATA := data INCLUDES := include GENERAL_SOURCE_DIRS=$1 $(foreach d,$(filter-out $1/arch $1/board $1/os $1/cpu $1,$(wildcard $1/*)),$(if $(wildcard $d/.),$(filter-out $d,$(call GENERAL_SOURCE_DIRS,$d)) $d,)) SPECIFIC_SOURCE_DIRS=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),)) ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),) SPECIFIC_SOURCE_DIRS_ARCH=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/$4/.*),$1/$2/$4 $(call DIR_WILDCARD,$1/$2/$4),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),))) else SPECIFIC_SOURCE_DIRS_ARCH=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),)) endif UNFILTERED_SOURCE_DIRS=$1 $(foreach d,$(wildcard $1/*),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,)) ALL_SOURCE_DIRS=$(foreach d,$(call GENERAL_SOURCE_DIRS,$1), \ $d \ $(call SPECIFIC_SOURCE_DIRS_ARCH,$d,arch,$(ATMOSPHERE_ARCH_DIR),$(ATMOSPHERE_SUB_ARCH_DIR)) \ $(call SPECIFIC_SOURCE_DIRS,$d,board,$(ATMOSPHERE_BOARD_DIR)) \ $(call SPECIFIC_SOURCE_DIRS,$d,os,$(ATMOSPHERE_OS_DIR)) \ $(call SPECIFIC_SOURCE_DIRS,$d,cpu,$(ATMOSPHERE_ARCH_DIR)/$(ATMOSPHERE_CPU_DIR)) \ ) SOURCES ?= $(call ALL_SOURCE_DIRS,source) FIND_SPECIFIC_SOURCE_FILES= $(notdir $(wildcard $1/*.$2.$3.$4)) $(filter-out $(subst .$2.$3.,.$2.generic.,$(notdir $(wildcard $1/*.$2.$3.$4))),$(notdir $(wildcard $1/*.$2.generic.$4))) FIND_SPECIFIC_SOURCE_FILES_EX=$(foreach ext,$3,$(notdir $(wildcard $1/*.$2.$(ext).$4))) $(filter-out $(foreach ext,$3,$(subst .$2.$(ext).,.$2.generic.,$(notdir $(wildcard $1/*.$2.$(ext).$4)))),$(notdir $(wildcard $1/*.$2.generic.$4))) FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.$2)) \ $(notdir $(wildcard $(dir)/*.board.*.$2)) \ $(notdir $(wildcard $(dir)/*.os.*.$2)) \ $(notdir $(wildcard $(dir)/.cpu.*.$2)), \ $(notdir $(wildcard $(dir)/*.$2)))) \ $(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),arch,$(ATMOSPHERE_ARCH_NAME) $(ATMOSPHERE_SUB_ARCH_NAME),$2)) \ $(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),board,$(ATMOSPHERE_BOARD_NAME),$2)) \ $(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),os,$(ATMOSPHERE_OS_NAME),$2)) \ $(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),cpu,$(ATMOSPHERE_CPU_NAME) $(ATMOSPHERE_CPU_EXTENSIONS),$2)) ATMOSPHERE_GCH_IDENTIFIER := $(ATMOSPHERE_FULL_NAME) #--------------------------------------------------------------------------------- # Python. The scripts should work with Python 2 or 3, but 2 is preferred. #--------------------------------------------------------------------------------- PYTHON = $(shell command -v python >/dev/null && echo python || echo python3) #--------------------------------------------------------------------------------- # Export MAKE: # GCC's LTO driver invokes Make internally. This invocation respects both $(MAKE) # and $(MAKEFLAGS), but only if they're in the environment. By default, MAKEFLAGS # is in the environment while MAKE isn't, so GCC will always use the default # `make` command, yet it inherits MAKEFLAGS from the copy of Make the user # invoked, which might have incompatible flags. In practice this is an issue on # macOS when running e.g. `gmake -j32 -Otarget`. This behavior is arguably a bug # in GCC and/or Make, but we can work around it by exporting MAKE. #--------------------------------------------------------------------------------- export MAKE #--------------------------------------------------------------------------------- # Rules for compiling pre-compiled headers #--------------------------------------------------------------------------------- %.hpp.gch/$(ATMOSPHERE_GCH_IDENTIFIER): %.hpp %.hpp.gch @echo Precompiling $(notdir $<) for $(ATMOSPHERE_GCH_IDENTIFIER) $(SILENTCMD)$(CXX) -w -x c++-header -MMD -MP -MQ$@ -MF $(DEPSDIR)/$(notdir $*).d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) %.hpp.gch: %.hpp @[ -d $@ ] || mkdir -p $@ ================================================ FILE: libraries/config/os/horizon/os.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_HORIZON export ATMOSPHERE_SETTINGS += export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/os/linux/os.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_LINUX export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/os/macos/os.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_MACOS export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/os/windows/os.mk ================================================ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer -fno-data-sections export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += ================================================ FILE: libraries/config/templates/exosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -Os endif DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -fno-non-call-exceptions \ -Wno-array-bounds \ -Wno-stringop-overflow \ -Wno-stringop-overread CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm) ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O2 endif DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Werror -fno-non-call-exceptions \ -Wno-array-bounds \ -Wno-stringop-overflow \ -Wno-stringop-overread CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) endif export LDFLAGS = -specs=$(ATMOSPHERE_TOPDIR)/$(notdir $(ATMOSPHERE_TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-exceptions -fno-rtti -fno-use-cxa-atexit -nostdlib -nostartfiles -g $(CXXFLAGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ -Wl,--wrap,__cxa_rethrow \ -Wl,--wrap,__cxa_allocate_exception \ -Wl,--wrap,__cxa_free_exception \ -Wl,--wrap,__cxa_begin_catch \ -Wl,--wrap,__cxa_end_catch \ -Wl,--wrap,__cxa_call_unexpected \ -Wl,--wrap,__cxa_call_terminate \ -Wl,--wrap,__gxx_personality_v0 \ -Wl,--wrap,_Unwind_Resume \ -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ -Wl,--wrap,_ZSt20__throw_length_errorPKc \ -Wl,--wrap,_ZNSt11logic_errorC2EPKc export LIBS := -lexosphere -lgcc #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libexosphere ================================================ FILE: libraries/config/templates/mesosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O3 endif export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE export SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export LDFLAGS = -specs=$(ATMOSPHERE_TOPDIR)/$(notdir $(ATMOSPHERE_TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -nostdlib -nostartfiles -g $(CXXFLAGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ -Wl,--wrap,__cxa_rethrow \ -Wl,--wrap,__cxa_allocate_exception \ -Wl,--wrap,__cxa_free_exception \ -Wl,--wrap,__cxa_begin_catch \ -Wl,--wrap,__cxa_end_catch \ -Wl,--wrap,__cxa_call_unexpected \ -Wl,--wrap,__cxa_call_terminate \ -Wl,--wrap,__gxx_personality_v0 \ -Wl,--wrap,_Unwind_Resume \ -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ -Wl,--wrap,_ZSt20__throw_length_errorPKc \ -Wl,--wrap,_ZNSt11logic_errorC2EPKc export LIBS := -lmesosphere #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere ================================================ FILE: libraries/config/templates/stratosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) #--------------------------------------------------------------------------------- # pull in switch rules #--------------------------------------------------------------------------------- ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/libnx/switch_rules endif #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O2 endif export DEFINES = $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE export SETTINGS = $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -Wno-missing-field-initializers -Wno-error=unused-result export CFLAGS = $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CXXFLAGS = $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) export ASFLAGS = $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export CXXREQUIRED := -Wl,--require-defined,__libnx_initheap \ -Wl,--require-defined,__libnx_exception_handler \ -Wl,--require-defined,__libnx_alloc \ -Wl,--require-defined,__libnx_aligned_alloc \ -Wl,--require-defined,__libnx_free \ -Wl,--require-defined,__appInit \ -Wl,--require-defined,__appExit \ -Wl,--require-defined,argvSetup export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ -Wl,--wrap,__cxa_rethrow \ -Wl,--wrap,__cxa_allocate_exception \ -Wl,--wrap,__cxa_free_exception \ -Wl,--wrap,__cxa_begin_catch \ -Wl,--wrap,__cxa_end_catch \ -Wl,--wrap,__cxa_call_unexpected \ -Wl,--wrap,__cxa_call_terminate \ -Wl,--wrap,__gxx_personality_v0 \ -Wl,--wrap,_Unwind_Resume \ -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ -Wl,--wrap,_ZSt20__throw_length_errorPKc \ -Wl,--wrap,_ZNSt11logic_errorC2EPKc \ -Wl,--wrap,exit else ifeq ($(ATMOSPHERE_BOARD),generic_windows) export CXXREQUIRED := export CXXWRAPS := -Wl,--wrap,__p__acmdln -Wl,--wrap,_set_invalid_parameter_handler else export CXXREQUIRED := export CXXWRAPS := endif ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now else ifeq ($(ATMOSPHERE_OS_NAME),macos) export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-map,$(notdir $@.map) else export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $@.map) endif ifeq ($(ATMOSPHERE_COMPILER_NAME),clang) export LDFLAGS += -fuse-ld=lld endif ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export LIBS := -lstratosphere -lnx else ifeq ($(ATMOSPHERE_BOARD),generic_windows) export LIBS := -lstratosphere -lwinmm -lws2_32 -lbcrypt -static -static-libgcc -static-libstdc++ else ifeq ($(ATMOSPHERE_BOARD),generic_linux) export LIBS := -lstratosphere -pthread -lbfd else ifeq ($(ATMOSPHERE_BOARD),generic_macos) export LIBS := -lstratosphere -pthread else export LIBS := -lstratosphere endif #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export LIBDIRS = $(PORTLIBS) $(LIBNX) else export LIBDIRS = endif export AMS_LIBDIRS = $(ATMOSPHERE_LIBRARIES_DIR)/libvapours $(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere #--------------------------------------------------------------------------------- # stratosphere sysmodules may (but usually do not) have an exefs source dir #--------------------------------------------------------------------------------- export EXEFS_SRC = exefs_src ================================================ FILE: libraries/libexosphere/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libexosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libexosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, nx_bpmp, nx-hac-001, arm7tdmi,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: libraries/libexosphere/include/exosphere/actmon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::actmon { using InterruptHandler = void(*)(); void SetRegisterAddress(uintptr_t address); void HandleInterrupt(); void StartMonitoringBpmp(InterruptHandler handler); void StopMonitoringBpmp(); } ================================================ FILE: libraries/libexosphere/include/exosphere/br/br_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/br/impl/br_erista_types.hpp> #include <exosphere/br/impl/br_mariko_types.hpp> namespace ams::br { struct BootEcid { u32 ecid[4]; }; static_assert(util::is_pod<BootEcid>::value); static_assert(sizeof(BootEcid) == 0x10); } ================================================ FILE: libraries/libexosphere/include/exosphere/br/impl/br_common_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::br { enum BootMemoryType : u32 { BootMemoryType_None, BootMemoryType_LpDdr2, BootMemoryType_Ddr3, BootMemoryType_LpDdr4, }; } ================================================ FILE: libraries/libexosphere/include/exosphere/br/impl/br_erista_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/br/impl/br_common_types.hpp> namespace ams::br::erista { struct BootSdramParams { BootMemoryType MemoryType; u32 PllMInputDivider; u32 PllMFeedbackDivider; u32 PllMStableTime; u32 PllMSetupControl; u32 PllMPostDivider; u32 PllMKCP; u32 PllMKVCO; u32 EmcBctSpare0; u32 EmcBctSpare1; u32 EmcBctSpare2; u32 EmcBctSpare3; u32 EmcBctSpare4; u32 EmcBctSpare5; u32 EmcBctSpare6; u32 EmcBctSpare7; u32 EmcBctSpare8; u32 EmcBctSpare9; u32 EmcBctSpare10; u32 EmcBctSpare11; u32 EmcBctSpare12; u32 EmcBctSpare13; u32 EmcClockSource; u32 EmcClockSourceDll; u32 ClkRstControllerPllmMisc2Override; u32 ClkRstControllerPllmMisc2OverrideEnable; u32 ClearClk2Mc1; u32 EmcAutoCalInterval; u32 EmcAutoCalConfig; u32 EmcAutoCalConfig2; u32 EmcAutoCalConfig3; u32 EmcAutoCalConfig4; u32 EmcAutoCalConfig5; u32 EmcAutoCalConfig6; u32 EmcAutoCalConfig7; u32 EmcAutoCalConfig8; u32 EmcAutoCalVrefSel0; u32 EmcAutoCalVrefSel1; u32 EmcAutoCalChannel; u32 EmcPmacroAutocalCfg0; u32 EmcPmacroAutocalCfg1; u32 EmcPmacroAutocalCfg2; u32 EmcPmacroRxTerm; u32 EmcPmacroDqTxDrv; u32 EmcPmacroCaTxDrv; u32 EmcPmacroCmdTxDrv; u32 EmcPmacroAutocalCfgCommon; u32 EmcPmacroZctrl; u32 EmcAutoCalWait; u32 EmcXm2CompPadCtrl; u32 EmcXm2CompPadCtrl2; u32 EmcXm2CompPadCtrl3; u32 EmcAdrCfg; u32 EmcPinProgramWait; u32 EmcPinExtraWait; u32 EmcPinGpioEn; u32 EmcPinGpio; u32 EmcTimingControlWait; u32 EmcRc; u32 EmcRfc; u32 EmcRfcPb; u32 EmcRefctrl2; u32 EmcRfcSlr; u32 EmcRas; u32 EmcRp; u32 EmcR2r; u32 EmcW2w; u32 EmcR2w; u32 EmcW2r; u32 EmcR2p; u32 EmcW2p; u32 EmcTppd; u32 EmcCcdmw; u32 EmcRdRcd; u32 EmcWrRcd; u32 EmcRrd; u32 EmcRext; u32 EmcWext; u32 EmcWdv; u32 EmcWdvChk; u32 EmcWsv; u32 EmcWev; u32 EmcWdvMask; u32 EmcWsDuration; u32 EmcWeDuration; u32 EmcQUse; u32 EmcQuseWidth; u32 EmcIbdly; u32 EmcObdly; u32 EmcEInput; u32 EmcEInputDuration; u32 EmcPutermExtra; u32 EmcPutermWidth; u32 EmcQRst; u32 EmcQSafe; u32 EmcRdv; u32 EmcRdvMask; u32 EmcRdvEarly; u32 EmcRdvEarlyMask; u32 EmcQpop; u32 EmcRefresh; u32 EmcBurstRefreshNum; u32 EmcPreRefreshReqCnt; u32 EmcPdEx2Wr; u32 EmcPdEx2Rd; u32 EmcPChg2Pden; u32 EmcAct2Pden; u32 EmcAr2Pden; u32 EmcRw2Pden; u32 EmcCke2Pden; u32 EmcPdex2Cke; u32 EmcPdex2Mrr; u32 EmcTxsr; u32 EmcTxsrDll; u32 EmcTcke; u32 EmcTckesr; u32 EmcTpd; u32 EmcTfaw; u32 EmcTrpab; u32 EmcTClkStable; u32 EmcTClkStop; u32 EmcTRefBw; u32 EmcFbioCfg5; u32 EmcFbioCfg7; u32 EmcFbioCfg8; u32 EmcCmdMappingCmd0_0; u32 EmcCmdMappingCmd0_1; u32 EmcCmdMappingCmd0_2; u32 EmcCmdMappingCmd1_0; u32 EmcCmdMappingCmd1_1; u32 EmcCmdMappingCmd1_2; u32 EmcCmdMappingCmd2_0; u32 EmcCmdMappingCmd2_1; u32 EmcCmdMappingCmd2_2; u32 EmcCmdMappingCmd3_0; u32 EmcCmdMappingCmd3_1; u32 EmcCmdMappingCmd3_2; u32 EmcCmdMappingByte; u32 EmcFbioSpare; u32 EmcCfgRsv; u32 EmcMrs; u32 EmcEmrs; u32 EmcEmrs2; u32 EmcEmrs3; u32 EmcMrw1; u32 EmcMrw2; u32 EmcMrw3; u32 EmcMrw4; u32 EmcMrw6; u32 EmcMrw8; u32 EmcMrw9; u32 EmcMrw10; u32 EmcMrw12; u32 EmcMrw13; u32 EmcMrw14; u32 EmcMrwExtra; u32 EmcWarmBootMrwExtra; u32 EmcWarmBootExtraModeRegWriteEnable; u32 EmcExtraModeRegWriteEnable; u32 EmcMrwResetCommand; u32 EmcMrwResetNInitWait; u32 EmcMrsWaitCnt; u32 EmcMrsWaitCnt2; u32 EmcCfg; u32 EmcCfg2; u32 EmcCfgPipe; u32 EmcCfgPipeClk; u32 EmcFdpdCtrlCmdNoRamp; u32 EmcCfgUpdate; u32 EmcDbg; u32 EmcDbgWriteMux; u32 EmcCmdQ; u32 EmcMc2EmcQ; u32 EmcDynSelfRefControl; u32 AhbArbitrationXbarCtrlMemInitDone; u32 EmcCfgDigDll; u32 EmcCfgDigDll_1; u32 EmcCfgDigDllPeriod; u32 EmcDevSelect; u32 EmcSelDpdCtrl; u32 EmcFdpdCtrlDq; u32 EmcFdpdCtrlCmd; u32 EmcPmacroIbVrefDq_0; u32 EmcPmacroIbVrefDq_1; u32 EmcPmacroIbVrefDqs_0; u32 EmcPmacroIbVrefDqs_1; u32 EmcPmacroIbRxrt; u32 EmcCfgPipe1; u32 EmcCfgPipe2; u32 EmcPmacroQuseDdllRank0_0; u32 EmcPmacroQuseDdllRank0_1; u32 EmcPmacroQuseDdllRank0_2; u32 EmcPmacroQuseDdllRank0_3; u32 EmcPmacroQuseDdllRank0_4; u32 EmcPmacroQuseDdllRank0_5; u32 EmcPmacroQuseDdllRank1_0; u32 EmcPmacroQuseDdllRank1_1; u32 EmcPmacroQuseDdllRank1_2; u32 EmcPmacroQuseDdllRank1_3; u32 EmcPmacroQuseDdllRank1_4; u32 EmcPmacroQuseDdllRank1_5; u32 EmcPmacroObDdllLongDqRank0_0; u32 EmcPmacroObDdllLongDqRank0_1; u32 EmcPmacroObDdllLongDqRank0_2; u32 EmcPmacroObDdllLongDqRank0_3; u32 EmcPmacroObDdllLongDqRank0_4; u32 EmcPmacroObDdllLongDqRank0_5; u32 EmcPmacroObDdllLongDqRank1_0; u32 EmcPmacroObDdllLongDqRank1_1; u32 EmcPmacroObDdllLongDqRank1_2; u32 EmcPmacroObDdllLongDqRank1_3; u32 EmcPmacroObDdllLongDqRank1_4; u32 EmcPmacroObDdllLongDqRank1_5; u32 EmcPmacroObDdllLongDqsRank0_0; u32 EmcPmacroObDdllLongDqsRank0_1; u32 EmcPmacroObDdllLongDqsRank0_2; u32 EmcPmacroObDdllLongDqsRank0_3; u32 EmcPmacroObDdllLongDqsRank0_4; u32 EmcPmacroObDdllLongDqsRank0_5; u32 EmcPmacroObDdllLongDqsRank1_0; u32 EmcPmacroObDdllLongDqsRank1_1; u32 EmcPmacroObDdllLongDqsRank1_2; u32 EmcPmacroObDdllLongDqsRank1_3; u32 EmcPmacroObDdllLongDqsRank1_4; u32 EmcPmacroObDdllLongDqsRank1_5; u32 EmcPmacroIbDdllLongDqsRank0_0; u32 EmcPmacroIbDdllLongDqsRank0_1; u32 EmcPmacroIbDdllLongDqsRank0_2; u32 EmcPmacroIbDdllLongDqsRank0_3; u32 EmcPmacroIbDdllLongDqsRank1_0; u32 EmcPmacroIbDdllLongDqsRank1_1; u32 EmcPmacroIbDdllLongDqsRank1_2; u32 EmcPmacroIbDdllLongDqsRank1_3; u32 EmcPmacroDdllLongCmd_0; u32 EmcPmacroDdllLongCmd_1; u32 EmcPmacroDdllLongCmd_2; u32 EmcPmacroDdllLongCmd_3; u32 EmcPmacroDdllLongCmd_4; u32 EmcPmacroDdllShortCmd_0; u32 EmcPmacroDdllShortCmd_1; u32 EmcPmacroDdllShortCmd_2; u32 WarmBootWait; u32 EmcOdtWrite; u32 EmcZcalInterval; u32 EmcZcalWaitCnt; u32 EmcZcalMrwCmd; u32 EmcMrsResetDll; u32 EmcZcalInitDev0; u32 EmcZcalInitDev1; u32 EmcZcalInitWait; u32 EmcZcalWarmColdBootEnables; u32 EmcMrwLpddr2ZcalWarmBoot; u32 EmcZqCalDdr3WarmBoot; u32 EmcZqCalLpDdr4WarmBoot; u32 EmcZcalWarmBootWait; u32 EmcMrsWarmBootEnable; u32 EmcMrsResetDllWait; u32 EmcMrsExtra; u32 EmcWarmBootMrsExtra; u32 EmcEmrsDdr2DllEnable; u32 EmcMrsDdr2DllReset; u32 EmcEmrsDdr2OcdCalib; u32 EmcDdr2Wait; u32 EmcClkenOverride; u32 EmcExtraRefreshNum; u32 EmcClkenOverrideAllWarmBoot; u32 McClkenOverrideAllWarmBoot; u32 EmcCfgDigDllPeriodWarmBoot; u32 PmcVddpSel; u32 PmcVddpSelWait; u32 PmcDdrPwr; u32 PmcDdrCfg; u32 PmcIoDpd3Req; u32 PmcIoDpd3ReqWait; u32 PmcIoDpd4ReqWait; u32 PmcRegShort; u32 PmcNoIoPower; u32 PmcDdrCntrlWait; u32 PmcDdrCntrl; u32 EmcAcpdControl; u32 EmcSwizzleRank0Byte0; u32 EmcSwizzleRank0Byte1; u32 EmcSwizzleRank0Byte2; u32 EmcSwizzleRank0Byte3; u32 EmcSwizzleRank1Byte0; u32 EmcSwizzleRank1Byte1; u32 EmcSwizzleRank1Byte2; u32 EmcSwizzleRank1Byte3; u32 EmcTxdsrvttgen; u32 EmcDataBrlshft0; u32 EmcDataBrlshft1; u32 EmcDqsBrlshft0; u32 EmcDqsBrlshft1; u32 EmcCmdBrlshft0; u32 EmcCmdBrlshft1; u32 EmcCmdBrlshft2; u32 EmcCmdBrlshft3; u32 EmcQuseBrlshft0; u32 EmcQuseBrlshft1; u32 EmcQuseBrlshft2; u32 EmcQuseBrlshft3; u32 EmcDllCfg0; u32 EmcDllCfg1; u32 EmcPmcScratch1; u32 EmcPmcScratch2; u32 EmcPmcScratch3; u32 EmcPmacroPadCfgCtrl; u32 EmcPmacroVttgenCtrl0; u32 EmcPmacroVttgenCtrl1; u32 EmcPmacroVttgenCtrl2; u32 EmcPmacroBrickCtrlRfu1; u32 EmcPmacroCmdBrickCtrlFdpd; u32 EmcPmacroBrickCtrlRfu2; u32 EmcPmacroDataBrickCtrlFdpd; u32 EmcPmacroBgBiasCtrl0; u32 EmcPmacroDataPadRxCtrl; u32 EmcPmacroCmdPadRxCtrl; u32 EmcPmacroDataRxTermMode; u32 EmcPmacroCmdRxTermMode; u32 EmcPmacroDataPadTxCtrl; u32 EmcPmacroCommonPadTxCtrl; u32 EmcPmacroCmdPadTxCtrl; u32 EmcCfg3; u32 EmcPmacroTxPwrd0; u32 EmcPmacroTxPwrd1; u32 EmcPmacroTxPwrd2; u32 EmcPmacroTxPwrd3; u32 EmcPmacroTxPwrd4; u32 EmcPmacroTxPwrd5; u32 EmcConfigSampleDelay; u32 EmcPmacroBrickMapping0; u32 EmcPmacroBrickMapping1; u32 EmcPmacroBrickMapping2; u32 EmcPmacroTxSelClkSrc0; u32 EmcPmacroTxSelClkSrc1; u32 EmcPmacroTxSelClkSrc2; u32 EmcPmacroTxSelClkSrc3; u32 EmcPmacroTxSelClkSrc4; u32 EmcPmacroTxSelClkSrc5; u32 EmcPmacroDdllBypass; u32 EmcPmacroDdllPwrd0; u32 EmcPmacroDdllPwrd1; u32 EmcPmacroDdllPwrd2; u32 EmcPmacroCmdCtrl0; u32 EmcPmacroCmdCtrl1; u32 EmcPmacroCmdCtrl2; u32 McEmemAdrCfg; u32 McEmemAdrCfgDev0; u32 McEmemAdrCfgDev1; u32 McEmemAdrCfgChannelMask; u32 McEmemAdrCfgBankMask0; u32 McEmemAdrCfgBankMask1; u32 McEmemAdrCfgBankMask2; u32 McEmemCfg; u32 McEmemArbCfg; u32 McEmemArbOutstandingReq; u32 McEmemArbRefpbHpCtrl; u32 McEmemArbRefpbBankCtrl; u32 McEmemArbTimingRcd; u32 McEmemArbTimingRp; u32 McEmemArbTimingRc; u32 McEmemArbTimingRas; u32 McEmemArbTimingFaw; u32 McEmemArbTimingRrd; u32 McEmemArbTimingRap2Pre; u32 McEmemArbTimingWap2Pre; u32 McEmemArbTimingR2R; u32 McEmemArbTimingW2W; u32 McEmemArbTimingR2W; u32 McEmemArbTimingW2R; u32 McEmemArbTimingRFCPB; u32 McEmemArbDaTurns; u32 McEmemArbDaCovers; u32 McEmemArbMisc0; u32 McEmemArbMisc1; u32 McEmemArbMisc2; u32 McEmemArbRing1Throttle; u32 McEmemArbOverride; u32 McEmemArbOverride1; u32 McEmemArbRsv; u32 McDaCfg0; u32 McEmemArbTimingCcdmw; u32 McClkenOverride; u32 McStatControl; u32 McVideoProtectBom; u32 McVideoProtectBomAdrHi; u32 McVideoProtectSizeMb; u32 McVideoProtectVprOverride; u32 McVideoProtectVprOverride1; u32 McVideoProtectGpuOverride0; u32 McVideoProtectGpuOverride1; u32 McSecCarveoutBom; u32 McSecCarveoutAdrHi; u32 McSecCarveoutSizeMb; u32 McVideoProtectWriteAccess; u32 McSecCarveoutProtectWriteAccess; u32 McGeneralizedCarveout1Bom; u32 McGeneralizedCarveout1BomHi; u32 McGeneralizedCarveout1Size128kb; u32 McGeneralizedCarveout1Access0; u32 McGeneralizedCarveout1Access1; u32 McGeneralizedCarveout1Access2; u32 McGeneralizedCarveout1Access3; u32 McGeneralizedCarveout1Access4; u32 McGeneralizedCarveout1ForceInternalAccess0; u32 McGeneralizedCarveout1ForceInternalAccess1; u32 McGeneralizedCarveout1ForceInternalAccess2; u32 McGeneralizedCarveout1ForceInternalAccess3; u32 McGeneralizedCarveout1ForceInternalAccess4; u32 McGeneralizedCarveout1Cfg0; u32 McGeneralizedCarveout2Bom; u32 McGeneralizedCarveout2BomHi; u32 McGeneralizedCarveout2Size128kb; u32 McGeneralizedCarveout2Access0; u32 McGeneralizedCarveout2Access1; u32 McGeneralizedCarveout2Access2; u32 McGeneralizedCarveout2Access3; u32 McGeneralizedCarveout2Access4; u32 McGeneralizedCarveout2ForceInternalAccess0; u32 McGeneralizedCarveout2ForceInternalAccess1; u32 McGeneralizedCarveout2ForceInternalAccess2; u32 McGeneralizedCarveout2ForceInternalAccess3; u32 McGeneralizedCarveout2ForceInternalAccess4; u32 McGeneralizedCarveout2Cfg0; u32 McGeneralizedCarveout3Bom; u32 McGeneralizedCarveout3BomHi; u32 McGeneralizedCarveout3Size128kb; u32 McGeneralizedCarveout3Access0; u32 McGeneralizedCarveout3Access1; u32 McGeneralizedCarveout3Access2; u32 McGeneralizedCarveout3Access3; u32 McGeneralizedCarveout3Access4; u32 McGeneralizedCarveout3ForceInternalAccess0; u32 McGeneralizedCarveout3ForceInternalAccess1; u32 McGeneralizedCarveout3ForceInternalAccess2; u32 McGeneralizedCarveout3ForceInternalAccess3; u32 McGeneralizedCarveout3ForceInternalAccess4; u32 McGeneralizedCarveout3Cfg0; u32 McGeneralizedCarveout4Bom; u32 McGeneralizedCarveout4BomHi; u32 McGeneralizedCarveout4Size128kb; u32 McGeneralizedCarveout4Access0; u32 McGeneralizedCarveout4Access1; u32 McGeneralizedCarveout4Access2; u32 McGeneralizedCarveout4Access3; u32 McGeneralizedCarveout4Access4; u32 McGeneralizedCarveout4ForceInternalAccess0; u32 McGeneralizedCarveout4ForceInternalAccess1; u32 McGeneralizedCarveout4ForceInternalAccess2; u32 McGeneralizedCarveout4ForceInternalAccess3; u32 McGeneralizedCarveout4ForceInternalAccess4; u32 McGeneralizedCarveout4Cfg0; u32 McGeneralizedCarveout5Bom; u32 McGeneralizedCarveout5BomHi; u32 McGeneralizedCarveout5Size128kb; u32 McGeneralizedCarveout5Access0; u32 McGeneralizedCarveout5Access1; u32 McGeneralizedCarveout5Access2; u32 McGeneralizedCarveout5Access3; u32 McGeneralizedCarveout5Access4; u32 McGeneralizedCarveout5ForceInternalAccess0; u32 McGeneralizedCarveout5ForceInternalAccess1; u32 McGeneralizedCarveout5ForceInternalAccess2; u32 McGeneralizedCarveout5ForceInternalAccess3; u32 McGeneralizedCarveout5ForceInternalAccess4; u32 McGeneralizedCarveout5Cfg0; u32 EmcCaTrainingEnable; u32 SwizzleRankByteEncode; u32 BootRomPatchControl; u32 BootRomPatchData; u32 McMtsCarveoutBom; u32 McMtsCarveoutAdrHi; u32 McMtsCarveoutSizeMb; u32 McMtsCarveoutRegCtrl; }; static_assert(sizeof(BootSdramParams) == 0x768); } ================================================ FILE: libraries/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/br/impl/br_common_types.hpp> namespace ams::br::mariko { struct BootSdramParams { BootMemoryType MemoryType; u32 PllMInputDivider; u32 PllMFeedbackDivider; u32 PllMStableTime; u32 PllMSetupControl; u32 PllMPostDivider; u32 PllMKCP; u32 PllMKVCO; u32 EmcBctSpare0; u32 EmcBctSpare1; u32 EmcBctSpare2; u32 EmcBctSpare3; u32 EmcBctSpare4; u32 EmcBctSpare5; u32 EmcBctSpare6; u32 EmcBctSpare7; u32 EmcBctSpare8; u32 EmcBctSpare9; u32 EmcBctSpare10; u32 EmcBctSpare11; u32 EmcBctSpare12; u32 EmcBctSpare13; u32 EmcBctSpareSecure0; u32 EmcBctSpareSecure1; u32 EmcBctSpareSecure2; u32 EmcBctSpareSecure3; u32 EmcBctSpareSecure4; u32 EmcBctSpareSecure5; u32 EmcBctSpareSecure6; u32 EmcBctSpareSecure7; u32 EmcBctSpareSecure8; u32 EmcBctSpareSecure9; u32 EmcBctSpareSecure10; u32 EmcBctSpareSecure11; u32 EmcBctSpareSecure12; u32 EmcBctSpareSecure13; u32 EmcBctSpareSecure14; u32 EmcBctSpareSecure15; u32 EmcBctSpareSecure16; u32 EmcBctSpareSecure17; u32 EmcBctSpareSecure18; u32 EmcBctSpareSecure19; u32 EmcBctSpareSecure20; u32 EmcBctSpareSecure21; u32 EmcBctSpareSecure22; u32 EmcBctSpareSecure23; u32 EmcClockSource; u32 EmcClockSourceDll; u32 ClkRstControllerPllmMisc2Override; u32 ClkRstControllerPllmMisc2OverrideEnable; u32 ClearClk2Mc1; u32 EmcAutoCalInterval; u32 EmcAutoCalConfig; u32 EmcAutoCalConfig2; u32 EmcAutoCalConfig3; u32 EmcAutoCalConfig4; u32 EmcAutoCalConfig5; u32 EmcAutoCalConfig6; u32 EmcAutoCalConfig7; u32 EmcAutoCalConfig8; u32 EmcAutoCalConfig9; u32 EmcAutoCalVrefSel0; u32 EmcAutoCalVrefSel1; u32 EmcAutoCalChannel; u32 EmcPmacroAutocalCfg0; u32 EmcPmacroAutocalCfg1; u32 EmcPmacroAutocalCfg2; u32 EmcPmacroRxTerm; u32 EmcPmacroDqTxDrv; u32 EmcPmacroCaTxDrv; u32 EmcPmacroCmdTxDrv; u32 EmcPmacroAutocalCfgCommon; u32 EmcPmacroZctrl; u32 EmcAutoCalWait; u32 EmcXm2CompPadCtrl; u32 EmcXm2CompPadCtrl2; u32 EmcXm2CompPadCtrl3; u32 EmcAdrCfg; u32 EmcPinProgramWait; u32 EmcPinExtraWait; u32 EmcPinGpioEn; u32 EmcPinGpio; u32 EmcTimingControlWait; u32 EmcRc; u32 EmcRfc; u32 EmcRfcPb; u32 EmcRefctrl2; u32 EmcRfcSlr; u32 EmcRas; u32 EmcRp; u32 EmcR2r; u32 EmcW2w; u32 EmcR2w; u32 EmcW2r; u32 EmcR2p; u32 EmcW2p; u32 EmcTppd; u32 EmcTrtm; u32 EmcTwtm; u32 EmcTratm; u32 EmcTwatm; u32 EmcTr2ref; u32 EmcCcdmw; u32 EmcRdRcd; u32 EmcWrRcd; u32 EmcRrd; u32 EmcRext; u32 EmcWext; u32 EmcWdv; u32 EmcWdvChk; u32 EmcWsv; u32 EmcWev; u32 EmcWdvMask; u32 EmcWsDuration; u32 EmcWeDuration; u32 EmcQUse; u32 EmcQuseWidth; u32 EmcIbdly; u32 EmcObdly; u32 EmcEInput; u32 EmcEInputDuration; u32 EmcPutermExtra; u32 EmcPutermWidth; u32 EmcQRst; u32 EmcQSafe; u32 EmcRdv; u32 EmcRdvMask; u32 EmcRdvEarly; u32 EmcRdvEarlyMask; u32 EmcQpop; u32 EmcRefresh; u32 EmcBurstRefreshNum; u32 EmcPreRefreshReqCnt; u32 EmcPdEx2Wr; u32 EmcPdEx2Rd; u32 EmcPChg2Pden; u32 EmcAct2Pden; u32 EmcAr2Pden; u32 EmcRw2Pden; u32 EmcCke2Pden; u32 EmcPdex2Cke; u32 EmcPdex2Mrr; u32 EmcTxsr; u32 EmcTxsrDll; u32 EmcTcke; u32 EmcTckesr; u32 EmcTpd; u32 EmcTfaw; u32 EmcTrpab; u32 EmcTClkStable; u32 EmcTClkStop; u32 EmcTRefBw; u32 EmcFbioCfg5; u32 EmcFbioCfg7; u32 EmcFbioCfg8; u32 EmcCmdMappingCmd0_0; u32 EmcCmdMappingCmd0_1; u32 EmcCmdMappingCmd0_2; u32 EmcCmdMappingCmd1_0; u32 EmcCmdMappingCmd1_1; u32 EmcCmdMappingCmd1_2; u32 EmcCmdMappingCmd2_0; u32 EmcCmdMappingCmd2_1; u32 EmcCmdMappingCmd2_2; u32 EmcCmdMappingCmd3_0; u32 EmcCmdMappingCmd3_1; u32 EmcCmdMappingCmd3_2; u32 EmcCmdMappingByte; u32 EmcFbioSpare; u32 EmcCfgRsv; u32 EmcMrs; u32 EmcEmrs; u32 EmcEmrs2; u32 EmcEmrs3; u32 EmcMrw1; u32 EmcMrw2; u32 EmcMrw3; u32 EmcMrw4; u32 EmcMrw6; u32 EmcMrw8; u32 EmcMrw9; u32 EmcMrw10; u32 EmcMrw12; u32 EmcMrw13; u32 EmcMrw14; u32 EmcMrwExtra; u32 EmcWarmBootMrwExtra; u32 EmcWarmBootExtraModeRegWriteEnable; u32 EmcExtraModeRegWriteEnable; u32 EmcMrwResetCommand; u32 EmcMrwResetNInitWait; u32 EmcMrsWaitCnt; u32 EmcMrsWaitCnt2; u32 EmcCfg; u32 EmcCfg2; u32 EmcCfgPipe; u32 EmcCfgPipeClk; u32 EmcFdpdCtrlCmdNoRamp; u32 EmcCfgUpdate; u32 EmcDbg; u32 EmcDbgWriteMux; u32 EmcCmdQ; u32 EmcMc2EmcQ; u32 EmcDynSelfRefControl; u32 AhbArbitrationXbarCtrlMemInitDone; u32 EmcCfgDigDll; u32 EmcCfgDigDll_1; u32 EmcCfgDigDllPeriod; u32 EmcDevSelect; u32 EmcSelDpdCtrl; u32 EmcFdpdCtrlDq; u32 EmcFdpdCtrlCmd; u32 EmcPmacroIbVrefDq_0; u32 EmcPmacroIbVrefDq_1; u32 EmcPmacroIbVrefDqs_0; u32 EmcPmacroIbVrefDqs_1; u32 EmcPmacroIbRxrt; u32 EmcCfgPipe1; u32 EmcCfgPipe2; u32 EmcPmacroQuseDdllRank0_0; u32 EmcPmacroQuseDdllRank0_1; u32 EmcPmacroQuseDdllRank0_2; u32 EmcPmacroQuseDdllRank0_3; u32 EmcPmacroQuseDdllRank0_4; u32 EmcPmacroQuseDdllRank0_5; u32 EmcPmacroQuseDdllRank1_0; u32 EmcPmacroQuseDdllRank1_1; u32 EmcPmacroQuseDdllRank1_2; u32 EmcPmacroQuseDdllRank1_3; u32 EmcPmacroQuseDdllRank1_4; u32 EmcPmacroQuseDdllRank1_5; u32 EmcPmacroObDdllLongDqRank0_0; u32 EmcPmacroObDdllLongDqRank0_1; u32 EmcPmacroObDdllLongDqRank0_2; u32 EmcPmacroObDdllLongDqRank0_3; u32 EmcPmacroObDdllLongDqRank0_4; u32 EmcPmacroObDdllLongDqRank0_5; u32 EmcPmacroObDdllLongDqRank1_0; u32 EmcPmacroObDdllLongDqRank1_1; u32 EmcPmacroObDdllLongDqRank1_2; u32 EmcPmacroObDdllLongDqRank1_3; u32 EmcPmacroObDdllLongDqRank1_4; u32 EmcPmacroObDdllLongDqRank1_5; u32 EmcPmacroObDdllLongDqsRank0_0; u32 EmcPmacroObDdllLongDqsRank0_1; u32 EmcPmacroObDdllLongDqsRank0_2; u32 EmcPmacroObDdllLongDqsRank0_3; u32 EmcPmacroObDdllLongDqsRank0_4; u32 EmcPmacroObDdllLongDqsRank0_5; u32 EmcPmacroObDdllLongDqsRank1_0; u32 EmcPmacroObDdllLongDqsRank1_1; u32 EmcPmacroObDdllLongDqsRank1_2; u32 EmcPmacroObDdllLongDqsRank1_3; u32 EmcPmacroObDdllLongDqsRank1_4; u32 EmcPmacroObDdllLongDqsRank1_5; u32 EmcPmacroIbDdllLongDqsRank0_0; u32 EmcPmacroIbDdllLongDqsRank0_1; u32 EmcPmacroIbDdllLongDqsRank0_2; u32 EmcPmacroIbDdllLongDqsRank0_3; u32 EmcPmacroIbDdllLongDqsRank1_0; u32 EmcPmacroIbDdllLongDqsRank1_1; u32 EmcPmacroIbDdllLongDqsRank1_2; u32 EmcPmacroIbDdllLongDqsRank1_3; u32 EmcPmacroDdllLongCmd_0; u32 EmcPmacroDdllLongCmd_1; u32 EmcPmacroDdllLongCmd_2; u32 EmcPmacroDdllLongCmd_3; u32 EmcPmacroDdllLongCmd_4; u32 EmcPmacroDdllShortCmd_0; u32 EmcPmacroDdllShortCmd_1; u32 EmcPmacroDdllShortCmd_2; u32 EmcPmacroDdllPeriodicOffset; u32 WarmBootWait; u32 EmcOdtWrite; u32 EmcZcalInterval; u32 EmcZcalWaitCnt; u32 EmcZcalMrwCmd; u32 EmcMrsResetDll; u32 EmcZcalInitDev0; u32 EmcZcalInitDev1; u32 EmcZcalInitWait; u32 EmcZcalWarmColdBootEnables; u32 EmcMrwLpddr2ZcalWarmBoot; u32 EmcZqCalDdr3WarmBoot; u32 EmcZqCalLpDdr4WarmBoot; u32 EmcZcalWarmBootWait; u32 EmcMrsWarmBootEnable; u32 EmcMrsResetDllWait; u32 EmcMrsExtra; u32 EmcWarmBootMrsExtra; u32 EmcEmrsDdr2DllEnable; u32 EmcMrsDdr2DllReset; u32 EmcEmrsDdr2OcdCalib; u32 EmcDdr2Wait; u32 EmcClkenOverride; u32 EmcExtraRefreshNum; u32 EmcClkenOverrideAllWarmBoot; u32 McClkenOverrideAllWarmBoot; u32 EmcCfgDigDllPeriodWarmBoot; u32 PmcVddpSel; u32 PmcVddpSelWait; u32 PmcDdrCfg; u32 PmcIoDpd3Req; u32 PmcIoDpd3ReqWait; u32 PmcIoDpd4ReqWait; u32 PmcRegShort; u32 PmcNoIoPower; u32 PmcDdrCntrlWait; u32 PmcDdrCntrl; u32 EmcAcpdControl; u32 EmcSwizzleRank0Byte0; u32 EmcSwizzleRank0Byte1; u32 EmcSwizzleRank0Byte2; u32 EmcSwizzleRank0Byte3; u32 EmcSwizzleRank1Byte0; u32 EmcSwizzleRank1Byte1; u32 EmcSwizzleRank1Byte2; u32 EmcSwizzleRank1Byte3; u32 EmcTxdsrvttgen; u32 EmcDataBrlshft0; u32 EmcDataBrlshft1; u32 EmcDqsBrlshft0; u32 EmcDqsBrlshft1; u32 EmcCmdBrlshft0; u32 EmcCmdBrlshft1; u32 EmcCmdBrlshft2; u32 EmcCmdBrlshft3; u32 EmcQuseBrlshft0; u32 EmcQuseBrlshft1; u32 EmcQuseBrlshft2; u32 EmcQuseBrlshft3; u32 EmcPmacroDllCfg0; u32 EmcPmacroDllCfg1; u32 EmcPmcScratch1; u32 EmcPmcScratch2; u32 EmcPmcScratch3; u32 EmcPmacroPadCfgCtrl; u32 EmcPmacroVttgenCtrl0; u32 EmcPmacroVttgenCtrl1; u32 EmcPmacroVttgenCtrl2; u32 EmcPmacroDsrVttgenCtrl0; u32 EmcPmacroBrickCtrlRfu1; u32 EmcPmacroCmdBrickCtrlFdpd; u32 EmcPmacroBrickCtrlRfu2; u32 EmcPmacroDataBrickCtrlFdpd; u32 EmcPmacroBgBiasCtrl0; u32 EmcPmacroDataPadRxCtrl; u32 EmcPmacroCmdPadRxCtrl; u32 EmcPmacroDataRxTermMode; u32 EmcPmacroCmdRxTermMode; u32 EmcPmacroDataPadTxCtrl; u32 EmcPmacroCmdPadTxCtrl; u32 EmcCfg3; u32 EmcPmacroTxPwrd0; u32 EmcPmacroTxPwrd1; u32 EmcPmacroTxPwrd2; u32 EmcPmacroTxPwrd3; u32 EmcPmacroTxPwrd4; u32 EmcPmacroTxPwrd5; u32 EmcConfigSampleDelay; u32 EmcPmacroBrickMapping0; u32 EmcPmacroBrickMapping1; u32 EmcPmacroBrickMapping2; u32 EmcPmacroTxSelClkSrc0; u32 EmcPmacroTxSelClkSrc1; u32 EmcPmacroTxSelClkSrc2; u32 EmcPmacroTxSelClkSrc3; u32 EmcPmacroTxSelClkSrc4; u32 EmcPmacroTxSelClkSrc5; u32 EmcPmacroPerbitFgcgCtrl0; u32 EmcPmacroPerbitFgcgCtrl1; u32 EmcPmacroPerbitFgcgCtrl2; u32 EmcPmacroPerbitFgcgCtrl3; u32 EmcPmacroPerbitFgcgCtrl4; u32 EmcPmacroPerbitFgcgCtrl5; u32 EmcPmacroPerbitRfuCtrl0; u32 EmcPmacroPerbitRfuCtrl1; u32 EmcPmacroPerbitRfuCtrl2; u32 EmcPmacroPerbitRfuCtrl3; u32 EmcPmacroPerbitRfuCtrl4; u32 EmcPmacroPerbitRfuCtrl5; u32 EmcPmacroPerbitRfu1Ctrl0; u32 EmcPmacroPerbitRfu1Ctrl1; u32 EmcPmacroPerbitRfu1Ctrl2; u32 EmcPmacroPerbitRfu1Ctrl3; u32 EmcPmacroPerbitRfu1Ctrl4; u32 EmcPmacroPerbitRfu1Ctrl5; u32 EmcPmacroDataPiCtrl; u32 EmcPmacroCmdPiCtrl; u32 EmcPmacroDdllBypass; u32 EmcPmacroDdllPwrd0; u32 EmcPmacroDdllPwrd1; u32 EmcPmacroDdllPwrd2; u32 EmcPmacroCmdCtrl0; u32 EmcPmacroCmdCtrl1; u32 EmcPmacroCmdCtrl2; u32 McEmemAdrCfg; u32 McEmemAdrCfgDev0; u32 McEmemAdrCfgDev1; u32 McEmemAdrCfgChannelMask; u32 McEmemAdrCfgBankMask0; u32 McEmemAdrCfgBankMask1; u32 McEmemAdrCfgBankMask2; u32 McEmemCfg; u32 McEmemArbCfg; u32 McEmemArbOutstandingReq; u32 McEmemArbRefpbHpCtrl; u32 McEmemArbRefpbBankCtrl; u32 McEmemArbTimingRcd; u32 McEmemArbTimingRp; u32 McEmemArbTimingRc; u32 McEmemArbTimingRas; u32 McEmemArbTimingFaw; u32 McEmemArbTimingRrd; u32 McEmemArbTimingRap2Pre; u32 McEmemArbTimingWap2Pre; u32 McEmemArbTimingR2R; u32 McEmemArbTimingW2W; u32 McEmemArbTimingR2W; u32 McEmemArbTimingW2R; u32 McEmemArbTimingRFCPB; u32 McEmemArbDaTurns; u32 McEmemArbDaCovers; u32 McEmemArbMisc0; u32 McEmemArbMisc1; u32 McEmemArbMisc2; u32 McEmemArbRing1Throttle; u32 McEmemArbOverride; u32 McEmemArbOverride1; u32 McEmemArbRsv; u32 McDaCfg0; u32 McEmemArbTimingCcdmw; u32 McClkenOverride; u32 McStatControl; u32 McVideoProtectBom; u32 McVideoProtectBomAdrHi; u32 McVideoProtectSizeMb; u32 McVideoProtectVprOverride; u32 McVideoProtectVprOverride1; u32 McVideoProtectGpuOverride0; u32 McVideoProtectGpuOverride1; u32 McSecCarveoutBom; u32 McSecCarveoutAdrHi; u32 McSecCarveoutSizeMb; u32 McVideoProtectWriteAccess; u32 McSecCarveoutProtectWriteAccess; u32 McGeneralizedCarveout1Bom; u32 McGeneralizedCarveout1BomHi; u32 McGeneralizedCarveout1Size128kb; u32 McGeneralizedCarveout1Access0; u32 McGeneralizedCarveout1Access1; u32 McGeneralizedCarveout1Access2; u32 McGeneralizedCarveout1Access3; u32 McGeneralizedCarveout1Access4; u32 McGeneralizedCarveout1ForceInternalAccess0; u32 McGeneralizedCarveout1ForceInternalAccess1; u32 McGeneralizedCarveout1ForceInternalAccess2; u32 McGeneralizedCarveout1ForceInternalAccess3; u32 McGeneralizedCarveout1ForceInternalAccess4; u32 McGeneralizedCarveout1Cfg0; u32 McGeneralizedCarveout2Bom; u32 McGeneralizedCarveout2BomHi; u32 McGeneralizedCarveout2Size128kb; u32 McGeneralizedCarveout2Access0; u32 McGeneralizedCarveout2Access1; u32 McGeneralizedCarveout2Access2; u32 McGeneralizedCarveout2Access3; u32 McGeneralizedCarveout2Access4; u32 McGeneralizedCarveout2ForceInternalAccess0; u32 McGeneralizedCarveout2ForceInternalAccess1; u32 McGeneralizedCarveout2ForceInternalAccess2; u32 McGeneralizedCarveout2ForceInternalAccess3; u32 McGeneralizedCarveout2ForceInternalAccess4; u32 McGeneralizedCarveout2Cfg0; u32 McGeneralizedCarveout3Bom; u32 McGeneralizedCarveout3BomHi; u32 McGeneralizedCarveout3Size128kb; u32 McGeneralizedCarveout3Access0; u32 McGeneralizedCarveout3Access1; u32 McGeneralizedCarveout3Access2; u32 McGeneralizedCarveout3Access3; u32 McGeneralizedCarveout3Access4; u32 McGeneralizedCarveout3ForceInternalAccess0; u32 McGeneralizedCarveout3ForceInternalAccess1; u32 McGeneralizedCarveout3ForceInternalAccess2; u32 McGeneralizedCarveout3ForceInternalAccess3; u32 McGeneralizedCarveout3ForceInternalAccess4; u32 McGeneralizedCarveout3Cfg0; u32 McGeneralizedCarveout4Bom; u32 McGeneralizedCarveout4BomHi; u32 McGeneralizedCarveout4Size128kb; u32 McGeneralizedCarveout4Access0; u32 McGeneralizedCarveout4Access1; u32 McGeneralizedCarveout4Access2; u32 McGeneralizedCarveout4Access3; u32 McGeneralizedCarveout4Access4; u32 McGeneralizedCarveout4ForceInternalAccess0; u32 McGeneralizedCarveout4ForceInternalAccess1; u32 McGeneralizedCarveout4ForceInternalAccess2; u32 McGeneralizedCarveout4ForceInternalAccess3; u32 McGeneralizedCarveout4ForceInternalAccess4; u32 McGeneralizedCarveout4Cfg0; u32 McGeneralizedCarveout5Bom; u32 McGeneralizedCarveout5BomHi; u32 McGeneralizedCarveout5Size128kb; u32 McGeneralizedCarveout5Access0; u32 McGeneralizedCarveout5Access1; u32 McGeneralizedCarveout5Access2; u32 McGeneralizedCarveout5Access3; u32 McGeneralizedCarveout5Access4; u32 McGeneralizedCarveout5ForceInternalAccess0; u32 McGeneralizedCarveout5ForceInternalAccess1; u32 McGeneralizedCarveout5ForceInternalAccess2; u32 McGeneralizedCarveout5ForceInternalAccess3; u32 McGeneralizedCarveout5ForceInternalAccess4; u32 McGeneralizedCarveout5Cfg0; u32 EmcCaTrainingEnable; u32 SwizzleRankByteEncode; u32 BootRomPatchControl; u32 BootRomPatchData; u32 McMtsCarveoutBom; u32 McMtsCarveoutAdrHi; u32 McMtsCarveoutSizeMb; u32 McMtsCarveoutRegCtrl; u32 McUntranslatedRegionCheck; u32 BCT_NA; }; static_assert(sizeof(BootSdramParams) == 0x838); } ================================================ FILE: libraries/libexosphere/include/exosphere/br.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/br/br_types.hpp> ================================================ FILE: libraries/libexosphere/include/exosphere/charger.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::charger { bool IsHiZMode(); void EnterHiZMode(); void ExitHiZMode(); } ================================================ FILE: libraries/libexosphere/include/exosphere/clkrst.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::clkrst { void SetRegisterAddress(uintptr_t address); void SetFuseVisibility(bool visible); void EnableUartAClock(); void EnableUartBClock(); void EnableUartCClock(); void EnableActmonClock(); void EnableI2c1Clock(); void EnableI2c5Clock(); void EnableSeClock(); void EnableCldvfsClock(); void EnableCsiteClock(); void EnableTzramClock(); void EnableCache2Clock(); void EnableCram2Clock(); void EnableHost1xClock(); void EnableTsecClock(); void EnableSorSafeClock(); void EnableSor0Clock(); void EnableSor1Clock(); void EnableKfuseClock(); void DisableI2c1Clock(); void DisableHost1xClock(); void DisableTsecClock(); void DisableSorSafeClock(); void DisableSor0Clock(); void DisableSor1Clock(); void DisableKfuseClock(); enum BpmpClockRate { BpmpClockRate_408MHz, BpmpClockRate_544MHz, BpmpClockRate_576MHz, BpmpClockRate_589MHz, BpmpClockRate_Count, }; BpmpClockRate GetBpmpClockRate(); BpmpClockRate SetBpmpClockRate(BpmpClockRate rate); } ================================================ FILE: libraries/libexosphere/include/exosphere/common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if 1 || defined(AMS_BUILD_FOR_AUDITING) #define EXOSPHERE_BUILD_FOR_AUDITING #endif #if defined(EXOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) #define EXOSPHERE_BUILD_FOR_DEBUGGING #endif #ifdef EXOSPHERE_BUILD_FOR_DEBUGGING #define EXOSPHERE_ENABLE_ASSERTIONS #define EXOSPHERE_ENABLE_DEBUG_PRINT #endif ================================================ FILE: libraries/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ void AbortImpl(const char *expr, const char *func, const char *file, int line) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Abort Called\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); AMS_LOG("\n"); } #else AMS_UNUSED(file, line, func, expr); #endif AbortImpl(); } void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Abort Called\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); AMS_LOG(" Value: %016" PRIx64 "\n", value); AMS_LOG("\n"); { ::std::va_list vl; va_start(vl, format); AMS_VLOG(format, vl); va_end(vl); AMS_LOG("\n"); } } #else AMS_UNUSED(file, line, func, expr, format); #endif AbortImpl(); } void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Abort Called\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); AMS_LOG(" Result: 0x%08" PRIx32 "\n", result->GetValue()); AMS_LOG("\n"); { ::std::va_list vl; va_start(vl, format); AMS_VLOG(format, vl); va_end(vl); AMS_LOG("\n"); } } #else AMS_UNUSED(file, line, func, expr, result, format); #endif AbortImpl(); } void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Assertion Failure\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); AMS_LOG(" Value: %016" PRIx64 "\n", value); AMS_LOG("\n"); AMS_UNUSED(type); } #else AMS_UNUSED(type, expr, func, file, line); #endif AbortImpl(); } void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Assertion Failure\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); AMS_LOG(" Value: %016" PRIx64 "\n", value); AMS_LOG("\n"); { ::std::va_list vl; va_start(vl, format); AMS_VLOG(format, vl); va_end(vl); AMS_LOG("\n"); } AMS_UNUSED(type); } #else AMS_UNUSED(type, expr, func, file, line, format); #endif AbortImpl(); } ================================================ FILE: libraries/libexosphere/include/exosphere/flow.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::flow { void SetRegisterAddress(uintptr_t address); void ResetCpuRegisters(int core); void SetCpuCsr(int core, u32 enable_ext); void SetHaltCpuEvents(int core, bool resume_on_irq); void SetCc4Ctrl(int core, u32 value); void ClearL2FlushControl(); } ================================================ FILE: libraries/libexosphere/include/exosphere/fuse.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/br.hpp> #include <exosphere/pmic.hpp> namespace ams::fuse { enum HardwareType { HardwareType_Icosa = 0, HardwareType_Copper = 1, HardwareType_Hoag = 2, HardwareType_Iowa = 3, HardwareType_Calcio = 4, HardwareType_Aula = 5, HardwareType_Undefined = 0xF, }; enum SocType { SocType_Erista = 0, SocType_Mariko = 1, SocType_Undefined = 0xF, }; enum HardwareState { HardwareState_Development = 0, HardwareState_Production = 1, HardwareState_Undefined = 2, }; enum PatchVersion { PatchVersion_Odnx02A2 = (SocType_Erista << 12) | 0x07F, }; enum DramId { DramId_IcosaSamsung4GB = 0, DramId_IcosaHynix4GB = 1, DramId_IcosaMicron4GB = 2, DramId_IowaHynix1y4GB = 3, DramId_IcosaSamsung6GB = 4, DramId_HoagHynix1y4GB = 5, DramId_AulaHynix1y4GB = 6, DramId_Deprecated7 = 7, DramId_IowaSansung4GB = 8, DramId_IowaSamsung8GB = 9, DramId_IowaHynix4GB = 10, DramId_IowaMicron4GB = 11, DramId_HoagSamsung4GB = 12, DramId_HoagSamsung8GB = 13, DramId_HoagHynix4GB = 14, DramId_HoagMicron4GB = 15, DramId_Deprecated16 = 16, DramId_IowaSamsung1y4GBX = 17, DramId_IowaSamsung1y8GBX = 18, DramId_HoagSamsung1y4GBX = 19, DramId_IowaSamsung1z4GB = 20, DramId_HoagSamsung1z4GB = 21, DramId_AulaSamsung1z4GB = 22, DramId_HoagSamsung1y8GBX = 23, DramId_AulaSamsung1y4GBX = 24, DramId_IowaMicron1y4GB = 25, DramId_HoagMicron1y4GB = 26, DramId_AulaMicron1y4GB = 27, DramId_AulaSamsung1y8GBX = 28, DramId_IowaX1X2Samsung4GB = 29, DramId_HoagX1X2Samsung4GB = 30, DramId_AulaX1X2Samsung4GB = 31, DramId_IowaSamsung4GBY = 32, DramId_HoagSamsung4GBY = 33, DramId_AulaSamsung4GBY = 34, DramId_Count, }; enum RetailInteractiveDisplayState { RetailInteractiveDisplayState_Disabled = 0, RetailInteractiveDisplayState_Enabled = 1, }; void SetRegisterAddress(uintptr_t address); void SetWriteSecureOnly(); void Lockout(); void Activate(); void Deactivate(); void Reload(); u32 ReadWord(int address); u32 GetOdmWord(int index); DramId GetDramId(); bool GetSecureBootKey(void *dst); void GetEcid(br::BootEcid *out); HardwareType GetHardwareType(); HardwareState GetHardwareState(); u64 GetDeviceId(); PatchVersion GetPatchVersion(); RetailInteractiveDisplayState GetRetailInteractiveDisplayState(); pmic::Regulator GetRegulator(); int GetDeviceUniqueKeyGeneration(); SocType GetSocType(); int GetExpectedFuseVersion(TargetFirmware target_fw); int GetFuseVersion(); bool HasRcmVulnerabilityPatch(); bool IsOdmProductionMode(); void ConfigureFuseBypass(); } ================================================ FILE: libraries/libexosphere/include/exosphere/gic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::gic { enum InterruptMode { InterruptMode_Level = 0, InterruptMode_Edge = 1, }; constexpr inline s32 HighestPriority = 0; constexpr inline s32 InterruptCount = 224; void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address); void InitializeCommon(); void InitializeCoreUnique(); void SetPriority(int interrupt_id, int priority); void SetInterruptGroup(int interrupt_id, int group); void SetEnable(int interrupt_id, bool enable); void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask); void SetSpiMode(int interrupt_id, InterruptMode mode); void SetPending(int interrupt_id); int GetInterruptRequestId(); void SetEndOfInterrupt(int interrupt_id); } ================================================ FILE: libraries/libexosphere/include/exosphere/hw/hw_arm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::hw::arch::arm { #ifdef __BPMP__ constexpr inline size_t DataCacheLineSize = 0x20; constexpr inline size_t DataCacheSize = 32_KB; ALWAYS_INLINE void DataSynchronizationBarrier() { /* ... */ } ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() { /* ... */ } ALWAYS_INLINE void DataMemoryBarrier() { /* ... */ } ALWAYS_INLINE void InstructionSynchronizationBarrier() { /* ... */ } void InitializeDataCache(); void FinalizeDataCache(); void InvalidateEntireDataCache(); void StoreEntireDataCache(); void FlushEntireDataCache(); void InvalidateDataCacheLine(void *ptr); void StoreDataCacheLine(void *ptr); void FlushDataCacheLine(void *ptr); void InvalidateDataCache(void *ptr, size_t size); void StoreDataCache(const void *ptr, size_t size); void FlushDataCache(const void *ptr, size_t size); #else #error "Unknown ARM board for ams::hw" #endif } ================================================ FILE: libraries/libexosphere/include/exosphere/hw/hw_arm64.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/hw/hw_arm64_system_registers.hpp> #include <exosphere/hw/hw_arm64_cache.hpp> namespace ams::hw::arch::arm64 { ALWAYS_INLINE void DataSynchronizationBarrier() { __asm__ __volatile__("dsb sy" ::: "memory"); } ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() { __asm__ __volatile__("dsb ish" ::: "memory"); } ALWAYS_INLINE void DataMemoryBarrier() { __asm__ __volatile__("dmb sy" ::: "memory"); } ALWAYS_INLINE void InstructionSynchronizationBarrier() { __asm__ __volatile__("isb" ::: "memory"); } ALWAYS_INLINE void WaitForInterrupt() { __asm__ __volatile__("wfi" ::: "memory"); } ALWAYS_INLINE void WaitForEvent() { __asm__ __volatile__("wfe" ::: "memory"); } ALWAYS_INLINE void SendEvent() { __asm__ __volatile__("sev" ::: "memory"); } ALWAYS_INLINE int CountLeadingZeros(u64 v) { u64 z; __asm__ __volatile__("clz %[z], %[v]" : [z]"=r"(z) : [v]"r"(v)); return z; } ALWAYS_INLINE int CountLeadingZeros(u32 v) { u32 z; __asm__ __volatile__("clz %w[z], %w[v]" : [z]"=r"(z) : [v]"r"(v)); return z; } ALWAYS_INLINE int GetCurrentCoreId() { u64 mpidr; HW_CPU_GET_MPIDR_EL1(mpidr); return mpidr & 0xFF; } } ================================================ FILE: libraries/libexosphere/include/exosphere/hw/hw_arm64_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::hw::arch::arm64 { #if defined(ATMOSPHERE_CPU_ARM_CORTEX_A57) || defined(ATMOSPHERE_CPU_ARM_CORTEX_A53) constexpr inline size_t InstructionCacheLineSize = 0x40; constexpr inline size_t DataCacheLineSize = 0x40; constexpr inline size_t NumPerformanceCounters = 6; #else #error "Unknown CPU for cache line sizes" #endif ALWAYS_INLINE void InvalidateEntireTlb() { __asm__ __volatile__("tlbi alle3is" ::: "memory"); } ALWAYS_INLINE void InvalidateDataCacheLine(void *ptr) { __asm __volatile__("dc ivac, %[ptr]" :: [ptr]"r"(ptr) : "memory"); } ALWAYS_INLINE void FlushDataCacheLine(void *ptr) { __asm __volatile__("dc civac, %[ptr]" :: [ptr]"r"(ptr) : "memory"); } ALWAYS_INLINE void InvalidateEntireInstructionCache() { __asm__ __volatile__("ic iallu" ::: "memory"); } ALWAYS_INLINE void InvalidateTlb(uintptr_t address) { const uintptr_t page_index = address / 4_KB; __asm__ __volatile__("tlbi vae3is, %[page_index]" :: [page_index]"r"(page_index) : "memory"); } ALWAYS_INLINE void InvalidateTlbLastLevel(uintptr_t address) { const uintptr_t page_index = address / 4_KB; __asm__ __volatile__("tlbi vale3is, %[page_index]" :: [page_index]"r"(page_index) : "memory"); } void FlushDataCache(const void *ptr, size_t size); void InvalidateDataCache(const void *ptr, size_t size); } ================================================ FILE: libraries/libexosphere/include/exosphere/hw/hw_arm64_system_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::hw::arch::arm64 { #define HW_CPU_GET_SYSREG(name, value) __asm__ __volatile__("mrs %0, " #name "" : "=&r"(value) :: "memory"); #define HW_CPU_SET_SYSREG(name, value) __asm__ __volatile__("msr " #name ", %0" :: "r"(value) : "memory", "cc") #define HW_CPU_GET_SCTLR_EL3(value) HW_CPU_GET_SYSREG(sctlr_el3, value) #define HW_CPU_SET_SCTLR_EL3(value) HW_CPU_SET_SYSREG(sctlr_el3, value) #define HW_CPU_GET_SCR_EL3(value) HW_CPU_GET_SYSREG(scr_el3, value) #define HW_CPU_SET_SCR_EL3(value) HW_CPU_SET_SYSREG(scr_el3, value) #define HW_CPU_GET_CPTR_EL3(value) HW_CPU_GET_SYSREG(cptr_el3, value) #define HW_CPU_SET_CPTR_EL3(value) HW_CPU_SET_SYSREG(cptr_el3, value) #define HW_CPU_GET_TTBR0_EL3(value) HW_CPU_GET_SYSREG(ttbr0_el3, value) #define HW_CPU_SET_TTBR0_EL3(value) HW_CPU_SET_SYSREG(ttbr0_el3, value) #define HW_CPU_GET_TCR_EL3(value) HW_CPU_GET_SYSREG(tcr_el3, value) #define HW_CPU_SET_TCR_EL3(value) HW_CPU_SET_SYSREG(tcr_el3, value) #define HW_CPU_GET_MAIR_EL3(value) HW_CPU_GET_SYSREG(mair_el3, value) #define HW_CPU_SET_MAIR_EL3(value) HW_CPU_SET_SYSREG(mair_el3, value) #define HW_CPU_GET_VBAR_EL3(value) HW_CPU_GET_SYSREG(vbar_el3, value) #define HW_CPU_SET_VBAR_EL3(value) HW_CPU_SET_SYSREG(vbar_el3, value) #define HW_CPU_GET_ELR_EL3(value) HW_CPU_GET_SYSREG(elr_el3, value) #define HW_CPU_SET_ELR_EL3(value) HW_CPU_SET_SYSREG(elr_el3, value) #define HW_CPU_GET_FAR_EL3(value) HW_CPU_GET_SYSREG(far_el3, value) #define HW_CPU_SET_FAR_EL3(value) HW_CPU_SET_SYSREG(far_el3, value) #define HW_CPU_GET_ESR_EL3(value) HW_CPU_GET_SYSREG(esr_el3, value) #define HW_CPU_SET_ESR_EL3(value) HW_CPU_SET_SYSREG(esr_el3, value) #define HW_CPU_GET_CLIDR_EL1(value) HW_CPU_GET_SYSREG(clidr_el1, value) #define HW_CPU_SET_CLIDR_EL1(value) HW_CPU_SET_SYSREG(clidr_el1, value) #define HW_CPU_GET_CCSIDR_EL1(value) HW_CPU_GET_SYSREG(ccsidr_el1, value) #define HW_CPU_SET_CCSIDR_EL1(value) HW_CPU_SET_SYSREG(ccsidr_el1, value) #define HW_CPU_GET_CSSELR_EL1(value) HW_CPU_GET_SYSREG(csselr_el1, value) #define HW_CPU_SET_CSSELR_EL1(value) HW_CPU_SET_SYSREG(csselr_el1, value) #define HW_CPU_GET_CPUACTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_0, value) #define HW_CPU_SET_CPUACTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_0, value) #define HW_CPU_GET_CPUECTLR_EL1(value) HW_CPU_GET_SYSREG(s3_1_c15_c2_1, value) #define HW_CPU_SET_CPUECTLR_EL1(value) HW_CPU_SET_SYSREG(s3_1_c15_c2_1, value) #define HW_CPU_GET_DBGAUTHSTATUS_EL1(value) HW_CPU_GET_SYSREG(dbgauthstatus_el1, value) #define HW_CPU_SET_DBGAUTHSTATUS_EL1(value) HW_CPU_SET_SYSREG(dbgauthstatus_el1, value) #define HW_CPU_GET_MPIDR_EL1(value) HW_CPU_GET_SYSREG(mpidr_el1, value) #define HW_CPU_GET_OSLAR_EL1(value) HW_CPU_GET_SYSREG(oslar_el1, value) #define HW_CPU_SET_OSLAR_EL1(value) HW_CPU_SET_SYSREG(oslar_el1, value) #define HW_CPU_GET_OSDTRRX_EL1(value) HW_CPU_GET_SYSREG(osdtrrx_el1, value) #define HW_CPU_SET_OSDTRRX_EL1(value) HW_CPU_SET_SYSREG(osdtrrx_el1, value) #define HW_CPU_GET_OSDTRTX_EL1(value) HW_CPU_GET_SYSREG(osdtrtx_el1, value) #define HW_CPU_SET_OSDTRTX_EL1(value) HW_CPU_SET_SYSREG(osdtrtx_el1, value) #define HW_CPU_GET_MDSCR_EL1(value) HW_CPU_GET_SYSREG(mdscr_el1, value) #define HW_CPU_SET_MDSCR_EL1(value) HW_CPU_SET_SYSREG(mdscr_el1, value) #define HW_CPU_GET_OSECCR_EL1(value) HW_CPU_GET_SYSREG(oseccr_el1, value) #define HW_CPU_SET_OSECCR_EL1(value) HW_CPU_SET_SYSREG(oseccr_el1, value) #define HW_CPU_GET_MDCCINT_EL1(value) HW_CPU_GET_SYSREG(mdccint_el1, value) #define HW_CPU_SET_MDCCINT_EL1(value) HW_CPU_SET_SYSREG(mdccint_el1, value) #define HW_CPU_GET_DBGCLAIMCLR_EL1(value) HW_CPU_GET_SYSREG(dbgclaimclr_el1, value) #define HW_CPU_SET_DBGCLAIMCLR_EL1(value) HW_CPU_SET_SYSREG(dbgclaimclr_el1, value) #define HW_CPU_GET_FAR_EL1(value) HW_CPU_GET_SYSREG(far_el1, value) #define HW_CPU_SET_FAR_EL1(value) HW_CPU_SET_SYSREG(far_el1, value) #define HW_CPU_GET_DBGVCR32_EL2(value) HW_CPU_GET_SYSREG(dbgvcr32_el2, value) #define HW_CPU_SET_DBGVCR32_EL2(value) HW_CPU_SET_SYSREG(dbgvcr32_el2, value) #define HW_CPU_GET_SDER32_EL3(value) HW_CPU_GET_SYSREG(sder32_el3, value) #define HW_CPU_SET_SDER32_EL3(value) HW_CPU_SET_SYSREG(sder32_el3, value) #define HW_CPU_GET_MDCR_EL2(value) HW_CPU_GET_SYSREG(mdcr_el2, value) #define HW_CPU_SET_MDCR_EL2(value) HW_CPU_SET_SYSREG(mdcr_el2, value) #define HW_CPU_GET_MDCR_EL3(value) HW_CPU_GET_SYSREG(mdcr_el3, value) #define HW_CPU_SET_MDCR_EL3(value) HW_CPU_SET_SYSREG(mdcr_el3, value) #define HW_CPU_GET_SPSR_EL3(value) HW_CPU_GET_SYSREG(spsr_el3, value) #define HW_CPU_SET_SPSR_EL3(value) HW_CPU_SET_SYSREG(spsr_el3, value) #define HW_CPU_GET_DBGBVR0_EL1(value) HW_CPU_GET_SYSREG(dbgbvr0_el1, value) #define HW_CPU_SET_DBGBVR0_EL1(value) HW_CPU_SET_SYSREG(dbgbvr0_el1, value) #define HW_CPU_GET_DBGBCR0_EL1(value) HW_CPU_GET_SYSREG(dbgbcr0_el1, value) #define HW_CPU_SET_DBGBCR0_EL1(value) HW_CPU_SET_SYSREG(dbgbcr0_el1, value) #define HW_CPU_GET_DBGBVR1_EL1(value) HW_CPU_GET_SYSREG(dbgbvr1_el1, value) #define HW_CPU_SET_DBGBVR1_EL1(value) HW_CPU_SET_SYSREG(dbgbvr1_el1, value) #define HW_CPU_GET_DBGBCR1_EL1(value) HW_CPU_GET_SYSREG(dbgbcr1_el1, value) #define HW_CPU_SET_DBGBCR1_EL1(value) HW_CPU_SET_SYSREG(dbgbcr1_el1, value) #define HW_CPU_GET_DBGBVR2_EL1(value) HW_CPU_GET_SYSREG(dbgbvr2_el1, value) #define HW_CPU_SET_DBGBVR2_EL1(value) HW_CPU_SET_SYSREG(dbgbvr2_el1, value) #define HW_CPU_GET_DBGBCR2_EL1(value) HW_CPU_GET_SYSREG(dbgbcr2_el1, value) #define HW_CPU_SET_DBGBCR2_EL1(value) HW_CPU_SET_SYSREG(dbgbcr2_el1, value) #define HW_CPU_GET_DBGBVR3_EL1(value) HW_CPU_GET_SYSREG(dbgbvr3_el1, value) #define HW_CPU_SET_DBGBVR3_EL1(value) HW_CPU_SET_SYSREG(dbgbvr3_el1, value) #define HW_CPU_GET_DBGBCR3_EL1(value) HW_CPU_GET_SYSREG(dbgbcr3_el1, value) #define HW_CPU_SET_DBGBCR3_EL1(value) HW_CPU_SET_SYSREG(dbgbcr3_el1, value) #define HW_CPU_GET_DBGBVR4_EL1(value) HW_CPU_GET_SYSREG(dbgbvr4_el1, value) #define HW_CPU_SET_DBGBVR4_EL1(value) HW_CPU_SET_SYSREG(dbgbvr4_el1, value) #define HW_CPU_GET_DBGBCR4_EL1(value) HW_CPU_GET_SYSREG(dbgbcr4_el1, value) #define HW_CPU_SET_DBGBCR4_EL1(value) HW_CPU_SET_SYSREG(dbgbcr4_el1, value) #define HW_CPU_GET_DBGBVR5_EL1(value) HW_CPU_GET_SYSREG(dbgbvr5_el1, value) #define HW_CPU_SET_DBGBVR5_EL1(value) HW_CPU_SET_SYSREG(dbgbvr5_el1, value) #define HW_CPU_GET_DBGBCR5_EL1(value) HW_CPU_GET_SYSREG(dbgbcr5_el1, value) #define HW_CPU_SET_DBGBCR5_EL1(value) HW_CPU_SET_SYSREG(dbgbcr5_el1, value) #define HW_CPU_GET_DBGWVR0_EL1(value) HW_CPU_GET_SYSREG(dbgwvr0_el1, value) #define HW_CPU_SET_DBGWVR0_EL1(value) HW_CPU_SET_SYSREG(dbgwvr0_el1, value) #define HW_CPU_GET_DBGWCR0_EL1(value) HW_CPU_GET_SYSREG(dbgwcr0_el1, value) #define HW_CPU_SET_DBGWCR0_EL1(value) HW_CPU_SET_SYSREG(dbgwcr0_el1, value) #define HW_CPU_GET_DBGWVR1_EL1(value) HW_CPU_GET_SYSREG(dbgwvr1_el1, value) #define HW_CPU_SET_DBGWVR1_EL1(value) HW_CPU_SET_SYSREG(dbgwvr1_el1, value) #define HW_CPU_GET_DBGWCR1_EL1(value) HW_CPU_GET_SYSREG(dbgwcr1_el1, value) #define HW_CPU_SET_DBGWCR1_EL1(value) HW_CPU_SET_SYSREG(dbgwcr1_el1, value) #define HW_CPU_GET_DBGWVR2_EL1(value) HW_CPU_GET_SYSREG(dbgwvr2_el1, value) #define HW_CPU_SET_DBGWVR2_EL1(value) HW_CPU_SET_SYSREG(dbgwvr2_el1, value) #define HW_CPU_GET_DBGWCR2_EL1(value) HW_CPU_GET_SYSREG(dbgwcr2_el1, value) #define HW_CPU_SET_DBGWCR2_EL1(value) HW_CPU_SET_SYSREG(dbgwcr2_el1, value) #define HW_CPU_GET_DBGWVR3_EL1(value) HW_CPU_GET_SYSREG(dbgwvr3_el1, value) #define HW_CPU_SET_DBGWVR3_EL1(value) HW_CPU_SET_SYSREG(dbgwvr3_el1, value) #define HW_CPU_GET_DBGWCR3_EL1(value) HW_CPU_GET_SYSREG(dbgwcr3_el1, value) #define HW_CPU_SET_DBGWCR3_EL1(value) HW_CPU_SET_SYSREG(dbgwcr3_el1, value) #define HW_CPU_GET_CNTFRQ_EL0(value) HW_CPU_GET_SYSREG(cntfrq_el0, value) #define HW_CPU_SET_CNTFRQ_EL0(value) HW_CPU_SET_SYSREG(cntfrq_el0, value) #define HW_CPU_GET_CNTHCTL_EL2(value) HW_CPU_GET_SYSREG(cnthctl_el2, value) #define HW_CPU_SET_CNTHCTL_EL2(value) HW_CPU_SET_SYSREG(cnthctl_el2, value) #define HW_CPU_GET_ACTLR_EL2(value) HW_CPU_GET_SYSREG(actlr_el2, value) #define HW_CPU_SET_ACTLR_EL2(value) HW_CPU_SET_SYSREG(actlr_el2, value) #define HW_CPU_GET_ACTLR_EL3(value) HW_CPU_GET_SYSREG(actlr_el3, value) #define HW_CPU_SET_ACTLR_EL3(value) HW_CPU_SET_SYSREG(actlr_el3, value) #define HW_CPU_GET_HCR_EL2(value) HW_CPU_GET_SYSREG(hcr_el2, value) #define HW_CPU_SET_HCR_EL2(value) HW_CPU_SET_SYSREG(hcr_el2, value) #define HW_CPU_GET_DACR32_EL2(value) HW_CPU_GET_SYSREG(dacr32_el2, value) #define HW_CPU_SET_DACR32_EL2(value) HW_CPU_SET_SYSREG(dacr32_el2, value) #define HW_CPU_GET_SCTLR_EL2(value) HW_CPU_GET_SYSREG(sctlr_el2, value) #define HW_CPU_SET_SCTLR_EL2(value) HW_CPU_SET_SYSREG(sctlr_el2, value) #define HW_CPU_GET_SCTLR_EL1(value) HW_CPU_GET_SYSREG(sctlr_el1, value) #define HW_CPU_SET_SCTLR_EL1(value) HW_CPU_SET_SYSREG(sctlr_el1, value) /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el3 */ struct SctlrEl3 { using M = util::BitPack64::Field< 0, 1>; using A = util::BitPack64::Field< 1, 1>; using C = util::BitPack64::Field< 2, 1>; using Sa = util::BitPack64::Field< 3, 1>; using I = util::BitPack64::Field<12, 1>; using Wxn = util::BitPack64::Field<19, 1>; using Ee = util::BitPack64::Field<25, 1>; static constexpr u64 Res1 = 0x30C50830; }; /* https://static.docs.arm.com/ddi0487/fb/DDI0487F_b_armv8_arm.pdf */ struct SctlrEl2 { using M = util::BitPack64::Field< 0, 1>; using A = util::BitPack64::Field< 1, 1>; using C = util::BitPack64::Field< 2, 1>; using Sa = util::BitPack64::Field< 3, 1>; using I = util::BitPack64::Field<12, 1>; using Wxn = util::BitPack64::Field<19, 1>; using Ee = util::BitPack64::Field<25, 1>; static constexpr u64 Res1 = 0x30C50830; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/system-control-register-el1 */ struct SctlrEl1 { using M = util::BitPack64::Field< 0, 1>; using A = util::BitPack64::Field< 1, 1>; using C = util::BitPack64::Field< 2, 1>; using Sa = util::BitPack64::Field< 3, 1>; using Sa0 = util::BitPack64::Field< 4, 1>; using Cp15BEn = util::BitPack64::Field< 5, 1>; using Thee = util::BitPack64::Field< 6, 1>; using Itd = util::BitPack64::Field< 7, 1>; using Sed = util::BitPack64::Field< 8, 1>; using Uma = util::BitPack64::Field< 9, 1>; using I = util::BitPack64::Field<12, 1>; using Dze = util::BitPack64::Field<14, 1>; using Uct = util::BitPack64::Field<15, 1>; using Ntwi = util::BitPack64::Field<16, 1>; using Ntwe = util::BitPack64::Field<18, 1>; using Wxn = util::BitPack64::Field<19, 1>; using E0e = util::BitPack64::Field<24, 1>; using Ee = util::BitPack64::Field<25, 1>; using Uci = util::BitPack64::Field<26, 1>; static constexpr u64 Res1 = 0x30D00800; }; /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABGIHHJ.html */ struct ScrEl3 { using Ns = util::BitPack32::Field< 0, 1>; using Irq = util::BitPack32::Field< 1, 1>; using Fiq = util::BitPack32::Field< 2, 1>; using Ea = util::BitPack32::Field< 3, 1>; using Fw = util::BitPack32::Field< 4, 1>; using Aw = util::BitPack32::Field< 5, 1>; using Net = util::BitPack32::Field< 6, 1>; using Smd = util::BitPack32::Field< 7, 1>; using Hce = util::BitPack32::Field< 8, 1>; using Sif = util::BitPack32::Field< 9, 1>; using RwCortexA53 = util::BitPack32::Field<10, 1>; using StCortexA53 = util::BitPack32::Field<11, 1>; using Twi = util::BitPack32::Field<12, 1>; using Twe = util::BitPack32::Field<13, 1>; }; /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/CIHDEBIG.html */ struct CptrEl3 { using Tfp = util::BitPack32::Field<10, 1>; using Tta = util::BitPack32::Field<20, 1>; using Tcpac = util::BitPack32::Field<31, 1>; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/translation-control-register-el3 */ struct TcrEl3 { using T0sz = util::BitPack32::Field< 0, 6>; using Irgn0 = util::BitPack32::Field< 8, 2>; using Orgn0 = util::BitPack32::Field<10, 2>; using Sh0 = util::BitPack32::Field<12, 2>; using Tg0 = util::BitPack32::Field<14, 2>; using Ps = util::BitPack32::Field<16, 3>; using Tbi = util::BitPack32::Field<20, 1>; static constexpr u32 Res1 = 0x80800000; }; struct ClidrEl1 { using Ctype1 = util::BitPack32::Field< 0, 3>; using Ctype2 = util::BitPack32::Field< 3, 3>; using Ctype3 = util::BitPack32::Field< 6, 3>; using Louis = util::BitPack32::Field<21, 3>; using Loc = util::BitPack32::Field<24, 3>; using Louu = util::BitPack32::Field<27, 3>; }; struct CcsidrEl1 { using LineSize = util::BitPack32::Field< 0, 3>; using Associativity = util::BitPack32::Field< 3, 10>; using NumSets = util::BitPack32::Field<13, 15>; using Wa = util::BitPack32::Field<28, 1>; using Ra = util::BitPack32::Field<29, 1>; using Wb = util::BitPack32::Field<30, 1>; using Wt = util::BitPack32::Field<31, 1>; }; struct CsselrEl1 { using InD = util::BitPack32::Field<0, 1>; using Level = util::BitPack32::Field<1, 3>; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-auxiliary-control-register-el1 */ struct CpuactlrEl1CortexA57 { /* TODO: Other bits */ using NonCacheableStreamingEnhancement = util::BitPack64::Field<24, 1>; /* TODO: Other bits */ using DisableLoadPassDmb = util::BitPack64::Field<59, 1>; using ForceProcessorRcgEnablesActive = util::BitPack64::Field<63, 1>; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/cpu-extended-control-register-el1 */ struct CpuectlrEl1CortexA57 { using ProcessorDynamicRetentionControl = util::BitPack64::Field< 0, 2>; using Smpen = util::BitPack64::Field< 6, 1>; using L2LoadStoreDataPrefetchDistance = util::BitPack64::Field<32, 2>; using L2InstructionFetchPrefetchDistance = util::BitPack64::Field<35, 2>; using DisableTableWalkDescriptorAccessPrefetch = util::BitPack64::Field<38, 1>; }; /* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/dbgauthstatus_el1 */ struct DbgAuthStatusEl1 { using Nsid = util::BitPack32::Field<0, 2>; using Nsnid = util::BitPack32::Field<2, 2>; using Sid = util::BitPack32::Field<4, 2>; using Snid = util::BitPack32::Field<6, 2>; }; /* https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/cnthctl_el2 */ struct CnthctlEl2 { using El1PctEn = util::BitPack32::Field<0, 1>; using El1PcEn = util::BitPack32::Field<1, 1>; using EvntEn = util::BitPack32::Field<2, 1>; using EvntDir = util::BitPack32::Field<3, 1>; using EvntI = util::BitPack32::Field<4, 4>; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/auxiliary-control-register-el3 */ struct ActlrCortexA57 { using Cpuactlr = util::BitPack32::Field<0, 1>; using Cpuectlr = util::BitPack32::Field<1, 1>; using L2ctlr = util::BitPack32::Field<4, 1>; using L2ectlr = util::BitPack32::Field<5, 1>; using L2actlr = util::BitPack32::Field<6, 1>; }; /* https://developer.arm.com/docs/ddi0488/h/system-control/aarch64-register-descriptions/hypervisor-configuration-register-el2 */ struct HcrEl2 { using Rw = util::BitPack64::Field<31, 1>; }; struct EsrEl3 { using Iss = util::BitPack32::Field< 0, 25>; using Il = util::BitPack32::Field<25, 1>; using Ec = util::BitPack32::Field<26, 6>; }; } ================================================ FILE: libraries/libexosphere/include/exosphere/hw.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <exosphere/hw/hw_arm64.hpp> namespace ams::hw { using namespace ams::hw::arch::arm64; } #elif defined(ATMOSPHERE_ARCH_ARM) #include <exosphere/hw/hw_arm.hpp> namespace ams::hw { using namespace ams::hw::arch::arm; } #else #error "Unknown architecture for hw!" #endif ================================================ FILE: libraries/libexosphere/include/exosphere/i2c.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::i2c { enum Port { Port_1 = 0, /* TODO: Support other ports? */ Port_5 = 4, Port_Count = 5, }; void SetRegisterAddress(Port port, uintptr_t address); void Initialize(Port port); bool Query(void *dst, size_t dst_size, Port port, int address, int r); bool Send(Port port, int address, int r, const void *src, size_t src_size); inline u8 QueryByte(Port port, int address, int r) { u8 byte; Query(std::addressof(byte), sizeof(byte), port, address, r); return byte; } inline void SendByte(Port port, int address, int r, u8 byte) { Send(port, address, r, std::addressof(byte), sizeof(byte)); } } ================================================ FILE: libraries/libexosphere/include/exosphere/log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::log { #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) #define AMS_IMPL_ENABLE_LOG #endif #if defined(AMS_IMPL_ENABLE_LOG) #define AMS_LOG(...) ::ams::log::Printf(__VA_ARGS__) #define AMS_VLOG(...) ::ams::log::VPrintf(__VA_ARGS__) #define AMS_DUMP(...) ::ams::log::Dump(__VA_ARGS__) #define AMS_LOG_FLUSH() ::ams::log::Flush() #else #define AMS_LOG(...) static_cast<void>(0) #define AMS_VLOG(...) static_cast<void>(0) #define AMS_DUMP(...) static_cast<void>(0) #define AMS_LOG_FLUSH() static_cast<void>(0) #endif void Initialize(); void Initialize(uart::Port port, u32 baud_rate, u32 flags); void Finalize(); void Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void VPrintf(const char *fmt, ::std::va_list vl); void Dump(const void *src, size_t size); void SendText(const void *text, size_t size); void Flush(); } ================================================ FILE: libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::mmu::arch::arm { /* NOTE: mmu is not supported by libexosphere-on-arm. */ /* However, we want the memory layout to be parseable, so we will include some arm64 mmu definitions. */ constexpr inline u64 L1EntryShift = 30; constexpr inline u64 L2EntryShift = 21; constexpr inline u64 L3EntryShift = 12; constexpr inline u64 L1EntrySize = 1_GB; constexpr inline u64 L2EntrySize = 2_MB; constexpr inline u64 L3EntrySize = 4_KB; constexpr inline u64 PageSize = L3EntrySize; constexpr inline u64 L1EntryMask = ((static_cast<u64>(1) << (48 - L1EntryShift)) - 1) << L1EntryShift; constexpr inline u64 L2EntryMask = ((static_cast<u64>(1) << (48 - L2EntryShift)) - 1) << L2EntryShift; constexpr inline u64 L3EntryMask = ((static_cast<u64>(1) << (48 - L3EntryShift)) - 1) << L3EntryShift; constexpr inline u64 TableEntryMask = L3EntryMask; static_assert(L1EntryMask == 0x0000FFFFC0000000ul); static_assert(L2EntryMask == 0x0000FFFFFFE00000ul); static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul); } ================================================ FILE: libraries/libexosphere/include/exosphere/mmu/mmu_api.arch.arm64.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::mmu::arch::arm64 { enum PageTableTableAttribute : u64 { PageTableTableAttribute_None = (0ul << 0), PageTableTableAttribute_PrivilegedExecuteNever = (1ul << 59), PageTableTableAttribute_ExecuteNever = (1ul << 60), PageTableTableAttribute_NonSecure = (1ul << 63), PageTableTableAttributes_El3SecureCode = PageTableTableAttribute_None, PageTableTableAttributes_El3SecureData = PageTableTableAttribute_ExecuteNever, PageTableTableAttributes_El3NonSecureCode = PageTableTableAttributes_El3SecureCode | PageTableTableAttribute_NonSecure, PageTableTableAttributes_El3NonSecureData = PageTableTableAttributes_El3SecureData | PageTableTableAttribute_NonSecure, }; enum PageTableMappingAttribute : u64{ /* Security. */ PageTableMappingAttribute_NonSecure = (1ul << 5), /* El1 Access. */ PageTableMappingAttribute_El1NotAllowed = (0ul << 6), PageTableMappingAttribute_El1Allowed = (1ul << 6), /* RW Permission. */ PageTableMappingAttribute_PermissionReadWrite = (0ul << 7), PageTableMappingAttribute_PermissionReadOnly = (1ul << 7), /* Shareability. */ PageTableMappingAttribute_ShareabilityNonShareable = (0ul << 8), PageTableMappingAttribute_ShareabiltiyOuterShareable = (2ul << 8), PageTableMappingAttribute_ShareabilityInnerShareable = (3ul << 8), /* Access flag. */ PageTableMappingAttribute_AccessFlagNotAccessed = (0ul << 10), PageTableMappingAttribute_AccessFlagAccessed = (1ul << 10), /* Global. */ PageTableMappingAttribute_Global = (0ul << 11), PageTableMappingAttribute_NonGlobal = (1ul << 11), /* Contiguous */ PageTableMappingAttribute_NonContiguous = (0ul << 52), PageTableMappingAttribute_Contiguous = (1ul << 52), /* Privileged Execute Never */ PageTableMappingAttribute_PrivilegedExecuteNever = (1ul << 53), /* Execute Never */ PageTableMappingAttribute_ExecuteNever = (1ul << 54), /* Useful definitions. */ PageTableMappingAttributes_El3SecureRwCode = ( PageTableMappingAttribute_PermissionReadWrite | PageTableMappingAttribute_ShareabilityInnerShareable ), PageTableMappingAttributes_El3SecureRoCode = ( PageTableMappingAttribute_PermissionReadOnly | PageTableMappingAttribute_ShareabilityInnerShareable ), PageTableMappingAttributes_El3SecureRoData = ( PageTableMappingAttribute_PermissionReadOnly | PageTableMappingAttribute_ShareabilityInnerShareable | PageTableMappingAttribute_ExecuteNever ), PageTableMappingAttributes_El3SecureRwData = ( PageTableMappingAttribute_PermissionReadWrite | PageTableMappingAttribute_ShareabilityInnerShareable | PageTableMappingAttribute_ExecuteNever ), PageTableMappingAttributes_El3NonSecureRwCode = PageTableMappingAttributes_El3SecureRwCode | PageTableMappingAttribute_NonSecure, PageTableMappingAttributes_El3NonSecureRoCode = PageTableMappingAttributes_El3SecureRoCode | PageTableMappingAttribute_NonSecure, PageTableMappingAttributes_El3NonSecureRoData = PageTableMappingAttributes_El3SecureRoData | PageTableMappingAttribute_NonSecure, PageTableMappingAttributes_El3NonSecureRwData = PageTableMappingAttributes_El3SecureRwData | PageTableMappingAttribute_NonSecure, PageTableMappingAttributes_El3SecureDevice = PageTableMappingAttributes_El3SecureRwData, PageTableMappingAttributes_El3NonSecureDevice = PageTableMappingAttributes_El3NonSecureRwData, }; enum MemoryRegionAttribute : u64 { MemoryRegionAttribute_Device_nGnRnE = (0ul << 2), MemoryRegionAttribute_Device_nGnRE = (1ul << 2), MemoryRegionAttribute_NormalMemory = (2ul << 2), MemoryRegionAttribute_NormalMemoryNotCacheable = (3ul << 2), MemoryRegionAttribute_NormalInnerShift = 0, MemoryRegionAttribute_NormalOuterShift = 4, #define AMS_MRA_DEFINE_NORMAL_ATTR(__NAME__, __VAL__) \ MemoryRegionAttribute_NormalInner##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalInnerShift), \ MemoryRegionAttribute_NormalOuter##__NAME__ = (__VAL__ << MemoryRegionAttribute_NormalOuterShift) AMS_MRA_DEFINE_NORMAL_ATTR(NonCacheable, 4), AMS_MRA_DEFINE_NORMAL_ATTR(WriteAllocate, (1ul << 0)), AMS_MRA_DEFINE_NORMAL_ATTR(ReadAllocate, (1ul << 1)), AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughTransient, (0ul << 2)), AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackTransient, (1ul << 2)), AMS_MRA_DEFINE_NORMAL_ATTR(WriteThroughNonTransient, (2ul << 2)), AMS_MRA_DEFINE_NORMAL_ATTR(WriteBackNonTransient, (3ul << 2)), #undef AMS_MRA_DEFINE_NORMAL_ATTR MemoryRegionAttributes_Normal = ( MemoryRegionAttribute_NormalInnerReadAllocate | MemoryRegionAttribute_NormalOuterReadAllocate | MemoryRegionAttribute_NormalInnerWriteAllocate | MemoryRegionAttribute_NormalOuterWriteAllocate | MemoryRegionAttribute_NormalInnerWriteBackNonTransient | MemoryRegionAttribute_NormalOuterWriteBackNonTransient ), MemoryRegionAttributes_Device = ( MemoryRegionAttribute_Device_nGnRE ), }; constexpr inline u64 MemoryRegionAttributeWidth = 8; constexpr ALWAYS_INLINE PageTableMappingAttribute AddMappingAttributeIndex(PageTableMappingAttribute attr, int index) { return static_cast<PageTableMappingAttribute>(attr | (static_cast<typename std::underlying_type<PageTableMappingAttribute>::type>(index) << 2)); } constexpr inline u64 L1EntryShift = 30; constexpr inline u64 L2EntryShift = 21; constexpr inline u64 L3EntryShift = 12; constexpr inline u64 L1EntrySize = 1_GB; constexpr inline u64 L2EntrySize = 2_MB; constexpr inline u64 L3EntrySize = 4_KB; constexpr inline u64 PageSize = L3EntrySize; constexpr inline u64 L1EntryMask = ((1ul << (48 - L1EntryShift)) - 1) << L1EntryShift; constexpr inline u64 L2EntryMask = ((1ul << (48 - L2EntryShift)) - 1) << L2EntryShift; constexpr inline u64 L3EntryMask = ((1ul << (48 - L3EntryShift)) - 1) << L3EntryShift; constexpr inline u64 TableEntryMask = L3EntryMask; static_assert(L1EntryMask == 0x0000FFFFC0000000ul); static_assert(L2EntryMask == 0x0000FFFFFFE00000ul); static_assert(L3EntryMask == 0x0000FFFFFFFFF000ul); constexpr inline u64 TableEntryIndexMask = 0x1FF; constexpr inline u64 EntryBlock = 0x1ul; constexpr inline u64 EntryPage = 0x3ul; constexpr ALWAYS_INLINE u64 MakeTableEntry(u64 address, PageTableTableAttribute attr) { return address | static_cast<u64>(attr) | 0x3ul; } constexpr ALWAYS_INLINE u64 MakeL1BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul; } constexpr ALWAYS_INLINE u64 MakeL2BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x1ul; } constexpr ALWAYS_INLINE u64 MakeL3BlockEntry(u64 address, PageTableMappingAttribute attr) { return address | static_cast<u64>(attr) | static_cast<u64>(PageTableMappingAttribute_AccessFlagAccessed) | 0x3ul; } constexpr ALWAYS_INLINE uintptr_t GetL2Offset(uintptr_t address) { return address & ((1ul << L2EntryShift) - 1); } constexpr ALWAYS_INLINE u64 GetL1EntryIndex(uintptr_t address) { return ((address >> L1EntryShift) & TableEntryIndexMask); } constexpr ALWAYS_INLINE u64 GetL2EntryIndex(uintptr_t address) { return ((address >> L2EntryShift) & TableEntryIndexMask); } constexpr ALWAYS_INLINE u64 GetL3EntryIndex(uintptr_t address) { return ((address >> L3EntryShift) & TableEntryIndexMask); } constexpr ALWAYS_INLINE void SetTableEntryImpl(volatile u64 *table, u64 index, u64 value) { /* Write the value. */ table[index] = value; } constexpr ALWAYS_INLINE void SetTableEntry(u64 *table, u64 index, u64 value) { /* Ensure (for constexpr validation purposes) that the entry we set is clear. */ if (std::is_constant_evaluated()) { if (table[index]) { __builtin_unreachable(); } } /* Set the value. */ SetTableEntryImpl(table, index, value); } constexpr ALWAYS_INLINE void SetL1TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { SetTableEntry(table, GetL1EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); } constexpr ALWAYS_INLINE void SetL2TableEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, PageTableTableAttribute attr) { SetTableEntry(table, GetL2EntryIndex(virt_addr), MakeTableEntry(phys_addr & TableEntryMask, attr)); } constexpr ALWAYS_INLINE void SetL1BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL1EntryIndex(virt_addr); const u64 count = (size >> L1EntryShift); for (u64 i = 0; i < count; ++i) { SetTableEntry(table, start + i, MakeL1BlockEntry((phys_addr & L1EntryMask) + (i << L1EntryShift), attr)); } } constexpr ALWAYS_INLINE void SetL2BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL2EntryIndex(virt_addr); const u64 count = (size >> L2EntryShift); for (u64 i = 0; i < count; ++i) { SetTableEntry(table, start + i, MakeL2BlockEntry((phys_addr & L2EntryMask) + (i << L2EntryShift), attr)); } } constexpr ALWAYS_INLINE void SetL3BlockEntry(u64 *table, uintptr_t virt_addr, uintptr_t phys_addr, size_t size, PageTableMappingAttribute attr) { const u64 start = GetL3EntryIndex(virt_addr); const u64 count = (size >> L3EntryShift); for (u64 i = 0; i < count; ++i) { SetTableEntry(table, start + i, MakeL3BlockEntry((phys_addr & L3EntryMask) + (i << L3EntryShift), attr)); } } constexpr ALWAYS_INLINE void InvalidateL1Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL1EntryIndex(virt_addr); const u64 count = (size >> L1EntryShift); const u64 end = start + count; for (u64 i = start; i < end; ++i) { table[i] = 0; } } constexpr ALWAYS_INLINE void InvalidateL2Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL2EntryIndex(virt_addr); const u64 count = (size >> L2EntryShift); const u64 end = start + count; for (u64 i = start; i < end; ++i) { table[i] = 0; } } constexpr ALWAYS_INLINE void InvalidateL3Entries(volatile u64 *table, uintptr_t virt_addr, size_t size) { const u64 start = GetL3EntryIndex(virt_addr); const u64 count = (size >> L3EntryShift); const u64 end = start + count; for (u64 i = start; i < end; ++i) { table[i] = 0; } } } ================================================ FILE: libraries/libexosphere/include/exosphere/mmu/mmu_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <exosphere/mmu/mmu_api.arch.arm64.hpp> #elif defined(ATMOSPHERE_ARCH_ARM) #include <exosphere/mmu/mmu_api.arch.arm.hpp> #else #error "Unknown architecture for mmu!" #endif namespace ams::mmu { #if defined(ATMOSPHERE_ARCH_ARM64) using namespace ams::mmu::arch::arm64; #elif defined(ATMOSPHERE_ARCH_ARM) using namespace ams::mmu::arch::arm; #else #error "Unknown architecture for mmu!" #endif } ================================================ FILE: libraries/libexosphere/include/exosphere/mmu.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/mmu/mmu_api.hpp> ================================================ FILE: libraries/libexosphere/include/exosphere/pinmux.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/fuse.hpp> namespace ams::pinmux { void SetRegisterAddress(uintptr_t pinmux_address, uintptr_t gpio_address); void SetupFirst(fuse::HardwareType hw_type); void SetupUartA(); void SetupUartB(); void SetupUartC(); void SetupI2c1(); void SetupI2c5(); void SetupVolumeButton(); void SetupHomeButton(); } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { bool IsProduction(); bool IsProductionForVersionCheck(); bool IsProductionForPublicKey(); } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { enum MemorySize { MemorySize_4GB = 0, MemorySize_6GB = 1, MemorySize_8GB = 2, }; enum MemoryArrange { MemoryArrange_Normal = 1, MemoryArrange_AppletDev = 2, MemoryArrange_SystemDev = 3, }; enum MemoryMode { MemoryMode_SizeShift = 4, MemoryMode_SizeMask = 0x30, MemoryMode_ArrangeMask = 0x0F, MemoryMode_Auto = 0x00, MemoryMode_4GB = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), MemoryMode_4GBAppletDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)), MemoryMode_4GBSystemDev = ((MemorySize_4GB << MemoryMode_SizeShift) | (MemoryArrange_SystemDev)), MemoryMode_6GB = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), MemoryMode_6GBAppletDev = ((MemorySize_6GB << MemoryMode_SizeShift) | (MemoryArrange_AppletDev)), MemoryMode_8GB = ((MemorySize_8GB << MemoryMode_SizeShift) | (MemoryArrange_Normal)), }; constexpr ALWAYS_INLINE MemorySize GetMemorySize(MemoryMode mode) { return static_cast<MemorySize>(mode >> MemoryMode_SizeShift); } constexpr ALWAYS_INLINE MemoryArrange GetMemoryArrange(MemoryMode mode) { return static_cast<MemoryArrange>(mode & MemoryMode_ArrangeMask); } constexpr ALWAYS_INLINE MemoryMode MakeMemoryMode(MemorySize size, MemoryArrange arrange) { return static_cast<MemoryMode>((size << MemoryMode_SizeShift) | (arrange)); } struct BootConfigData { u32 version; u32 reserved_04; u32 reserved_08; u32 reserved_0C; u8 flags1[0x10]; u8 flags0[0x10]; u64 initial_tsc_value; u8 padding_38[0x200 - 0x38]; constexpr bool IsDevelopmentFunctionEnabled() const { return (this->flags1[0] & (1 << 1)) != 0; } constexpr bool IsSErrorDebugEnabled() const { return (this->flags1[0] & (1 << 2)) != 0; } constexpr u8 GetKernelFlags0() const { return this->flags0[1]; } constexpr u8 GetKernelFlags1() const { return this->flags1[0]; } constexpr MemoryMode GetMemoryMode() const { return static_cast<MemoryMode>(this->flags0[3]); } constexpr bool IsInitialTscValueValid() const { return (this->flags0[4] & (1 << 0)) != 0; } constexpr u64 GetInitialTscValue() const { return this->IsInitialTscValueValid() ? this->initial_tsc_value : 0; } }; static_assert(util::is_pod<BootConfigData>::value); static_assert(sizeof(BootConfigData) == 0x200); struct BootConfigSignedData { u32 version; u32 reserved_04; u8 flags; u8 reserved_09[0x10 - 9]; u8 ecid[0x10]; u8 flags1[0x10]; u8 flags0[0x10]; u8 padding_40[0x100 - 0x40]; constexpr bool IsPackage2EncryptionDisabled() const { return (this->flags & (1 << 0)) != 0; } constexpr bool IsPackage2SignatureVerificationDisabled() const { return (this->flags & (1 << 1)) != 0; } constexpr bool IsProgramVerificationDisabled() const { return (this->flags1[0] & (1 << 0)) != 0; } constexpr void SetPackage2SignatureVerificationDisabled(bool decrypted) { this->flags |= decrypted ? (1 << 1) : (0 << 0); } constexpr void SetPackage2EncryptionDisabled(bool decrypted) { this->flags |= decrypted ? (1 << 0) : (0 << 0); } }; static_assert(util::is_pod<BootConfigSignedData>::value); static_assert(sizeof(BootConfigSignedData) == 0x100); struct BootConfig { BootConfigData data; u8 signature[0x100]; BootConfigSignedData signed_data; }; static_assert(util::is_pod<BootConfig>::value); static_assert(sizeof(BootConfig) == 0x400); } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_bootloader_parameters.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { enum BootloaderState { BootloaderState_Start = 0, BootloaderState_LoadedBootConfig = 1, BootloaderState_InitializedDram = 2, BootloaderState_LoadedPackage2 = 3, BootloaderState_Done = 4, }; enum SecureMonitorState { SecureMonitorState_Start = 0, SecureMonitorState_Initialized = 1, }; struct BctParameters { u32 bootloader_version; u32 bootloader_start_block; u32 bootloader_start_page; u32 bootloader_attributes; }; static_assert(util::is_pod<BctParameters>::value && sizeof(BctParameters) == 0x10); struct SecureMonitorParameters { u32 bootloader_start_time; u32 bootloader_end_time; u32 secmon_start_time; u32 secmon_end_time; BctParameters bct_params; u32 deprecated_boot_reason_value; u8 deprecated_boot_reason_state; u8 reserved[0xD3]; u32 bootloader_state; u32 secmon_state; u8 reserved2[0x100]; }; static_assert(util::is_pod<SecureMonitorParameters>::value); static_assert(sizeof(SecureMonitorParameters) == 0x200); static_assert(AMS_OFFSETOF(SecureMonitorParameters, bct_params) == 0x10); static_assert(AMS_OFFSETOF(SecureMonitorParameters, bootloader_state) == 0xF8); static_assert(AMS_OFFSETOF(SecureMonitorParameters, secmon_state) == 0xFC); enum BootloaderAttribute { BootloaderAttribute_None = (0u << 0), BootloaderAttribute_RecoveryBoot = (1u << 0), BootloaderAttribute_RestrictedSmcShift = 1, BootloaderAttribute_RestrictedSmcMask = (0xFu << BootloaderAttribute_RestrictedSmcShift), }; } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_error_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { enum ErrorReason { ErrorReason_None = 0, ErrorReason_InvalidPackage2Signature = 1, ErrorReason_InvalidPackage2Meta = 2, ErrorReason_InvalidPackage2Version = 3, ErrorReason_InvalidPackage2Payload = 4, ErrorReason_UnknownSmc = 5, ErrorReason_UnknownAbort = 6, ErrorReason_InvalidCoreContext = 7, ErrorReason_InvalidSecurityEngineStickyBits = 8, ErrorReason_UnexpectedReset = 9, ErrorReason_Exception = 0x10, ErrorReason_TransitionToSafeMode = 0x20, ErrorReason_SecureInitializerReboot = 0x21, ErrorReason_SdmmcError = 0x30, ErrorReason_InvalidDramId = 0x31, ErrorReason_InvalidPackage2 = 0x32, ErrorReason_InvalidBct = 0x33, ErrorReason_InvalidGpt = 0x34, ErrorReason_FailedToTransitionToSafeMode = 0x35, ErrorReason_ActivityMonitorInterrupt = 0x36, ErrorReason_KernelPanic = 0x40, }; enum ErrorColor { ErrorColor_Black = 0x000, ErrorColor_Red = 0x00F, ErrorColor_Yellow = 0x0FF, ErrorColor_Orange = 0x07F, ErrorColor_Blue = 0xF00, ErrorColor_LightBlue = 0xFF0, ErrorColor_Pink = 0xF7F, ErrorColor_Purple = 0xF0A, }; enum ErrorInfo { ErrorInfo_ReasonMask = 0xFF, ErrorInfo_ColorShift = 20, #define MAKE_ERROR_INFO(_COLOR_, _DESC_) ((static_cast<u32>(ErrorColor_##_COLOR_) << ErrorInfo_ColorShift) | (ErrorReason_##_DESC_)) ErrorInfo_None = MAKE_ERROR_INFO(Black, None), ErrorInfo_InvalidPackage2Signature = MAKE_ERROR_INFO(Blue, InvalidPackage2Signature), ErrorInfo_InvalidPackage2Meta = MAKE_ERROR_INFO(Blue, InvalidPackage2Meta), ErrorInfo_InvalidPackage2Version = MAKE_ERROR_INFO(Blue, InvalidPackage2Version), ErrorInfo_InvalidPackage2Payload = MAKE_ERROR_INFO(Blue, InvalidPackage2Payload), ErrorInfo_UnknownSmc = MAKE_ERROR_INFO(LightBlue, UnknownSmc), ErrorInfo_UnknownAbort = MAKE_ERROR_INFO(Yellow, UnknownAbort), ErrorInfo_InvalidCoreContext = MAKE_ERROR_INFO(Pink, InvalidCoreContext), ErrorInfo_InvalidSecurityEngineStickyBits = MAKE_ERROR_INFO(Pink, InvalidSecurityEngineStickyBits), ErrorInfo_UnexpectedReset = MAKE_ERROR_INFO(Pink, UnexpectedReset), ErrorInfo_Exception = MAKE_ERROR_INFO(Orange, Exception), ErrorInfo_TransitionToSafeMode = MAKE_ERROR_INFO(Black, TransitionToSafeMode), ErrorInfo_SecureInitializerReboot = MAKE_ERROR_INFO(Black, SecureInitializerReboot), ErrorInfo_SdmmcError = MAKE_ERROR_INFO(Purple, SdmmcError), ErrorInfo_InvalidDramId = MAKE_ERROR_INFO(Purple, InvalidDramId), ErrorInfo_InvalidPackage2 = MAKE_ERROR_INFO(Purple, InvalidPackage2), ErrorInfo_InvalidBct = MAKE_ERROR_INFO(Purple, InvalidBct), ErrorInfo_InvalidGpt = MAKE_ERROR_INFO(Purple, InvalidGpt), ErrorInfo_FailedToTransitionToSafeMode = MAKE_ERROR_INFO(Purple, FailedToTransitionToSafeMode), ErrorInfo_ActivityMonitorInterrupt = MAKE_ERROR_INFO(Purple, ActivityMonitorInterrupt), #undef MAKE_ERROR_INFO }; constexpr inline ErrorReason GetErrorReason(u32 info) { return static_cast<ErrorReason>(info & ErrorInfo_ReasonMask); } constexpr inline ErrorInfo MakeKernelPanicResetInfo(u32 color) { return static_cast<ErrorInfo>((color << ErrorInfo_ColorShift) | (ErrorReason_KernelPanic)); } #define PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH (0x840) } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_key_generation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { enum KeyGeneration : int { KeyGeneration_1_0_0 = 0x00, KeyGeneration_3_0_0 = 0x01, KeyGeneration_3_0_1 = 0x02, KeyGeneration_4_0_0 = 0x03, KeyGeneration_5_0_0 = 0x04, KeyGeneration_6_0_0 = 0x05, KeyGeneration_6_2_0 = 0x06, KeyGeneration_7_0_0 = 0x07, KeyGeneration_8_1_0 = 0x08, KeyGeneration_9_0_0 = 0x09, KeyGeneration_9_1_0 = 0x0A, KeyGeneration_12_1_0 = 0x0B, KeyGeneration_13_0_0 = 0x0C, KeyGeneration_14_0_0 = 0x0D, KeyGeneration_15_0_0 = 0x0E, KeyGeneration_16_0_0 = 0x0F, KeyGeneration_17_0_0 = 0x10, KeyGeneration_18_0_0 = 0x11, KeyGeneration_19_0_0 = 0x12, KeyGeneration_20_0_0 = 0x13, KeyGeneration_21_0_0 = 0x14, KeyGeneration_Count, KeyGeneration_Current = KeyGeneration_Count - 1, KeyGeneration_Min = 0x00, KeyGeneration_Max = 0x20, }; static_assert(KeyGeneration_Count <= KeyGeneration_Max); constexpr inline const int OldMasterKeyCount = KeyGeneration_Count - 1; constexpr inline const int OldDeviceMasterKeyCount = KeyGeneration_Count - KeyGeneration_4_0_0; constexpr bool IsValidDeviceUniqueKeyGeneration(int generation) { return generation == KeyGeneration_1_0_0 || (KeyGeneration_4_0_0 <= generation && generation <= KeyGeneration_Current); } constexpr bool IsValidKeyGeneration(int generation) { return KeyGeneration_Min <= generation && generation <= KeyGeneration_Current; } } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1/pkg1_se_key_slots.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg1 { enum AesKeySlot { AesKeySlot_UserStart = 0, AesKeySlot_TzramSaveKek = 2, AesKeySlot_TzramSaveKey = 3, AesKeySlot_UserLast = 5, AesKeySlot_UserEnd = AesKeySlot_UserLast + 1, AesKeySlot_SecmonStart = 8, AesKeySlot_Temporary = 8, AesKeySlot_Smc = 9, AesKeySlot_RandomForUserWrap = 10, AesKeySlot_RandomForKeyStorageWrap = 11, AesKeySlot_DeviceMaster = 12, AesKeySlot_Master = 13, AesKeySlot_Device = 15, AesKeySlot_Count = 16, AesKeySlot_SecmonEnd = AesKeySlot_Count, /* Used only during boot. */ AesKeySlot_TsecRootDev = 11, AesKeySlot_Tsec = 12, AesKeySlot_TsecRoot = 13, AesKeySlot_SecureBoot = 14, AesKeySlot_SecureStorage = 15, AesKeySlot_DeviceMasterKeySourceKekErista = 10, AesKeySlot_MasterKek = 13, AesKeySlot_DeviceMasterKeySourceKekMariko = 14, /* Mariko only keyslots, used during boot. */ AesKeySlot_MarikoKek = 12, AesKeySlot_MarikoBek = 13, /* Bootloader keyslots, for fusee only. */ AesKeySlot_BootloaderSystem0 = 2, AesKeySlot_BootloaderSystem1 = 3, AesKeySlot_BootloaderDeviceMaster = 6, AesKeySlot_BootloaderMaster = 7, AesKeySlot_BootloaderTemporary = 8, }; enum RsaKeySlot { RsaKeySlot_Temporary = 0, RsaKeySlot_PrivateKey = 1, }; constexpr bool IsUserAesKeySlot(int slot) { return AesKeySlot_UserStart <= slot && slot < AesKeySlot_UserEnd; } } ================================================ FILE: libraries/libexosphere/include/exosphere/pkg1.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/pkg1/pkg1_bootloader_parameters.hpp> #include <exosphere/pkg1/pkg1_boot_config.hpp> #include <exosphere/pkg1/pkg1_error_types.hpp> #include <exosphere/pkg1/pkg1_key_generation.hpp> #include <exosphere/pkg1/pkg1_se_key_slots.hpp> #include <exosphere/pkg1/pkg1_api.hpp> ================================================ FILE: libraries/libexosphere/include/exosphere/pkg2.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pkg2 { constexpr inline size_t Package2SizeMax = 8_MB - 16_KB; constexpr inline size_t PayloadAlignment = 4; constexpr inline int PayloadCount = 3; constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */ constexpr inline int CurrentBootloaderVersion = 0x18; struct Package2Meta { using Magic = util::FourCC<'P','K','2','1'>; u32 package2_size; u8 key_generation; u8 header_iv_remainder[11]; u8 payload_ivs[PayloadCount][0x10]; u8 padding_40[0x10]; u8 magic[4]; u32 entrypoint; u8 padding_58[4]; u8 package2_version; u8 bootloader_version; u8 padding_5E[2]; u32 payload_sizes[PayloadCount]; u8 padding_6C[4]; u32 payload_offsets[PayloadCount]; u8 padding_7C[4]; u8 payload_hashes[PayloadCount][crypto::Sha256Generator::HashSize]; u8 padding_E0[0x20]; private: static ALWAYS_INLINE u32 ReadWord(const void *ptr, int offset) { return util::LoadLittleEndian(reinterpret_cast<const u32 *>(reinterpret_cast<uintptr_t>(ptr) + offset)); } public: ALWAYS_INLINE u8 GetKeyGeneration() const { return static_cast<u8>(std::max<s32>(0, static_cast<s32>(this->key_generation ^ this->header_iv_remainder[1] ^ this->header_iv_remainder[2]) - 1)); } ALWAYS_INLINE u32 GetSize() const { return this->package2_size ^ ReadWord(this->header_iv_remainder, 3) ^ ReadWord(this->header_iv_remainder, 7); } }; static_assert(util::is_pod<Package2Meta>::value); static_assert(sizeof(Package2Meta) == 0x100); struct Package2Header { u8 signature[0x100]; Package2Meta meta; }; static_assert(util::is_pod<Package2Header>::value); static_assert(sizeof(Package2Header) == 0x200); struct StorageLayout { u8 boot_config[16_KB]; Package2Header package2_header; u8 data[Package2SizeMax - sizeof(Package2Header)]; }; static_assert(util::is_pod<StorageLayout>::value); static_assert(sizeof(StorageLayout) == 8_MB); } ================================================ FILE: libraries/libexosphere/include/exosphere/pmc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pmc { enum SecureRegister { SecureRegister_Other = (1 << 0), SecureRegister_DramParameters = (1 << 1), SecureRegister_ResetVector = (1 << 2), SecureRegister_Carveout = (1 << 3), SecureRegister_CmacWrite = (1 << 4), SecureRegister_CmacRead = (1 << 5), SecureRegister_KeySourceWrite = (1 << 6), SecureRegister_KeySourceRead = (1 << 7), SecureRegister_Srk = (1 << 8), SecureRegister_CmacReadWrite = SecureRegister_CmacRead | SecureRegister_CmacWrite, SecureRegister_KeySourceReadWrite = SecureRegister_KeySourceRead | SecureRegister_KeySourceWrite, }; void SetRegisterAddress(uintptr_t address); void InitializeRandomScratch(); void EnableWakeEventDetection(); void ConfigureForSc7Entry(); void LockSecureRegister(SecureRegister reg); enum class LockState { Locked = 0, NotLocked = 1, PartiallyLocked = 2, }; LockState GetSecureRegisterLockState(SecureRegister reg); } ================================================ FILE: libraries/libexosphere/include/exosphere/pmic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pmic { enum Regulator { /* Erista regulators. */ Regulator_Erista_Max77621 = 0, /* Device code 0x3A000001 */ /* Mariko regulators. */ Regulator_Mariko_Max77812_A = 1, /* Device code 0x3A000002 */ Regulator_Mariko_Max77812_B = 2, /* Device code 0x3A000006 */ }; void SetEnBit(Regulator regulator); void EnableVddCpu(Regulator regulator); void DisableVddCpu(Regulator regulator); void EnableSleep(); void PowerOff(); void ShutdownSystem(bool reboot); bool IsAcOk(); bool IsPowerButtonPressed(); } ================================================ FILE: libraries/libexosphere/include/exosphere/pmic_setup.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/pmic.hpp> #include <exosphere/fuse.hpp> namespace ams::pmic { void SetSystemSetting(fuse::SocType soc_type); void EnableVddCore(fuse::SocType soc_type); void EnableLdo8(); void EnableVddMemory(fuse::SocType soc_type); } ================================================ FILE: libraries/libexosphere/include/exosphere/rtc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::rtc { void StopAlarm(); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_aes.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/se/se_common.hpp> namespace ams::se { constexpr inline int AesKeySlotCount = 16; constexpr inline size_t AesBlockSize = crypto::AesEncryptor128::BlockSize; void ClearAesKeySlot(int slot); void ClearAesKeyIv(int slot); void LockAesKeySlot(int slot, u32 flags); /* NOTE: This is Nintendo's API, but if we actually want to use SE2 we should use a different one. */ void ClearAesKeySlot2(int slot); void SetAesKey(int slot, const void *key, size_t key_size); void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size); void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size); void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size); void DecryptAes128Xts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector); void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler); void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler); void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::secmon { u8 *GetSecurityEngineEphemeralWorkBlock(); } namespace ams::se { using DoneHandler = void(*)(); enum KeySlotLockFlags { KeySlotLockFlags_None = 0, KeySlotLockFlags_KeyRead = (1u << 0), KeySlotLockFlags_KeyWrite = (1u << 1), KeySlotLockFlags_OriginalIvRead = (1u << 2), KeySlotLockFlags_OriginalIvWrite = (1u << 3), KeySlotLockFlags_UpdatedIvRead = (1u << 4), KeySlotLockFlags_UpdatedIvWrite = (1u << 5), KeySlotLockFlags_KeyUse = (1u << 6), KeySlotLockFlags_DstKeyTableOnly = (1u << 7), KeySlotLockFlags_PerKey = (1u << 8), KeySlotLockFlags_AllReadLock = (KeySlotLockFlags_KeyRead | KeySlotLockFlags_OriginalIvRead | KeySlotLockFlags_UpdatedIvRead), KeySlotLockFlags_AllLockKek = 0x1FF, KeySlotLockFlags_AllLockKey = (KeySlotLockFlags_AllLockKek & ~KeySlotLockFlags_DstKeyTableOnly), KeySlotLockFlags_EristaMask = 0x7F, KeySlotLockFlags_MarikoMask = 0xFF, }; ALWAYS_INLINE u8 *GetEphemeralWorkBlock() { return ::ams::secmon::GetSecurityEngineEphemeralWorkBlock(); } } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_hash.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::se { constexpr inline int Sha256HashSize = crypto::Sha256Generator::HashSize; union Sha256Hash { u8 bytes[Sha256HashSize / sizeof(u8) ]; u32 words[Sha256HashSize / sizeof(u32)]; }; void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_management.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::se { void SetRegisterAddress(uintptr_t address, uintptr_t address2); void Initialize(); void SetSecure(bool secure); void SetTzramSecure(); void SetPerKeySecure(); void SetContextSaveSecure(); void Lockout(); void HandleInterrupt(); void ValidateErrStatus(); void ValidateAesOperationResult(); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_oaep.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::se { size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_rng.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::se { void InitializeRandom(); void GenerateRandomBytes(void *dst, size_t size); void SetRandomKey(int slot); void GenerateSrk(); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_rsa.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/se/se_common.hpp> namespace ams::se { constexpr inline int RsaKeySlotCount = 2; constexpr inline int RsaSize = 0x100; void ClearRsaKeySlot(int slot); void LockRsaKeySlot(int slot, u32 flags); void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size); void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler); void GetRsaResult(void *dst, size_t dst_size); } ================================================ FILE: libraries/libexosphere/include/exosphere/se/se_suspend.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/se/se_aes.hpp> #include <exosphere/se/se_rsa.hpp> namespace ams::se { /* 256-bit AES keyslots are two 128-bit keys. */ constexpr inline int AesKeySlotPartCount = 2; /* RSA keys are both a modulus and an exponent. */ constexpr inline int RsaKeySlotPartCount = 2; constexpr inline size_t StickyBitContextSize = 2 * AesBlockSize; struct Context { u8 random[AesBlockSize]; u8 sticky_bits[StickyBitContextSize / AesBlockSize][AesBlockSize]; u8 aes_key[AesKeySlotCount][AesKeySlotPartCount][AesBlockSize]; u8 aes_oiv[AesKeySlotCount][AesBlockSize]; u8 aes_uiv[AesKeySlotCount][AesBlockSize]; u8 rsa_key[RsaKeySlotCount][RsaKeySlotPartCount][RsaSize / AesBlockSize][AesBlockSize]; u8 fixed_pattern[AesBlockSize]; }; static_assert(sizeof(Context) == 0x840); static_assert(util::is_pod<Context>::value); struct StickyBits { u8 se_security; u8 tzram_security; u16 crypto_security_perkey; u8 crypto_keytable_access[AesKeySlotCount]; u8 rsa_security_perkey; u8 rsa_keytable_access[RsaKeySlotCount]; }; static_assert(util::is_pod<StickyBits>::value); bool ValidateStickyBits(const StickyBits &bits); void SaveContext(Context *dst); void ConfigureAutomaticContextSave(); void SaveContextAutomatic(); void SaveTzramAutomatic(); } ================================================ FILE: libraries/libexosphere/include/exosphere/se.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/se/se_common.hpp> #include <exosphere/se/se_management.hpp> #include <exosphere/se/se_aes.hpp> #include <exosphere/se/se_hash.hpp> #include <exosphere/se/se_oaep.hpp> #include <exosphere/se/se_rsa.hpp> #include <exosphere/se/se_rng.hpp> #include <exosphere/se/se_suspend.hpp> ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/pkg1.hpp> #include <exosphere/se.hpp> #include <exosphere/secmon/secmon_monitor_context.hpp> namespace ams::secmon { struct ConfigurationContext { union { SecureMonitorConfiguration secmon_cfg; u8 _raw_exosphere_config[0x80]; }; union { EmummcConfiguration emummc_cfg; u8 _raw_emummc_config[0x120]; }; u8 sealed_device_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; u8 sealed_master_keys[pkg1::KeyGeneration_Max][se::AesBlockSize]; pkg1::BootConfig boot_config; u8 rsa_private_exponents[4][se::RsaSize]; union { u8 _misc_data[0xFC0 - sizeof(_raw_exosphere_config) - sizeof(_raw_emummc_config) - sizeof(sealed_device_keys) - sizeof(sealed_master_keys) - sizeof(boot_config) - sizeof(rsa_private_exponents)]; }; /* u8 l1_page_table[0x40]; */ }; static_assert(sizeof(ConfigurationContext) == 0xFC0); static_assert(util::is_pod<ConfigurationContext>::value); namespace impl { ALWAYS_INLINE uintptr_t GetConfigurationContextAddress() { register uintptr_t x18 asm("x18"); __asm__ __volatile__("" : [x18]"=r"(x18)); return x18; } ALWAYS_INLINE ConfigurationContext &GetConfigurationContext() { return *reinterpret_cast<ConfigurationContext *>(GetConfigurationContextAddress()); } ALWAYS_INLINE u8 *GetMasterKeyStorage(int generation) { return GetConfigurationContext().sealed_master_keys[generation]; } ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int generation) { return GetConfigurationContext().sealed_device_keys[generation]; } ALWAYS_INLINE u8 *GetRsaPrivateExponentStorage(int which) { return GetConfigurationContext().rsa_private_exponents[which]; } ALWAYS_INLINE void SetKeyGeneration(int generation) { GetConfigurationContext().secmon_cfg.key_generation = generation; } ALWAYS_INLINE void SetTargetFirmware(ams::TargetFirmware target_firmware) { GetConfigurationContext().secmon_cfg.target_firmware = target_firmware; } ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() { return std::addressof(GetConfigurationContext().boot_config); } } ALWAYS_INLINE const ConfigurationContext &GetConfigurationContext() { return *reinterpret_cast<const ConfigurationContext *>(impl::GetConfigurationContextAddress()); } ALWAYS_INLINE const SecureMonitorConfiguration &GetSecmonConfiguration() { return GetConfigurationContext().secmon_cfg; } ALWAYS_INLINE const EmummcConfiguration &GetEmummcConfiguration() { return GetConfigurationContext().emummc_cfg; } ALWAYS_INLINE const pkg1::BootConfig &GetBootConfig() { return GetConfigurationContext().boot_config; } ALWAYS_INLINE ams::TargetFirmware GetTargetFirmware() { return GetSecmonConfiguration().GetTargetFirmware(); } ALWAYS_INLINE int GetKeyGeneration() { return GetSecmonConfiguration().GetKeyGeneration(); } ALWAYS_INLINE fuse::HardwareType GetHardwareType() { return GetSecmonConfiguration().GetHardwareType(); } ALWAYS_INLINE fuse::SocType GetSocType() { return GetSecmonConfiguration().GetSocType(); } ALWAYS_INLINE fuse::HardwareState GetHardwareState() { return GetSecmonConfiguration().GetHardwareState(); } ALWAYS_INLINE u16 GetLcdVendor() { return GetSecmonConfiguration().GetLcdVendor(); } ALWAYS_INLINE uart::Port GetLogPort() { return GetSecmonConfiguration().GetLogPort(); } ALWAYS_INLINE u8 GetLogFlags() { return GetSecmonConfiguration().GetLogFlags(); } ALWAYS_INLINE u32 GetLogBaudRate() { return GetSecmonConfiguration().GetLogBaudRate(); } ALWAYS_INLINE bool IsProduction() { return GetSecmonConfiguration().IsProduction(); } } ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <exosphere/secmon/secmon_configuration_context.arch.arm64.hpp> #elif defined(ATMOSPHERE_ARCH_ARM) /* Nothing to include. */ #else #error "Unknown architecture for secmon::ConfigurationContext.hpp" #endif ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_emummc_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::secmon { enum EmummcType : u32 { EmummcType_None = 0, EmummcType_Partition = 1, EmummcType_File = 2, }; enum EmummcMmc { EmummcMmc_Nand = 0, EmummcMmc_Sd = 1, EmummcMmc_Gc = 2, }; constexpr inline size_t EmummcFilePathLengthMax = 0x80; struct EmummcFilePath { char str[EmummcFilePathLengthMax]; }; static_assert(util::is_pod<EmummcFilePath>::value); static_assert(sizeof(EmummcFilePath) == EmummcFilePathLengthMax); struct EmummcBaseConfiguration { static constexpr u32 Magic = util::FourCC<'E','F','S','0'>::Code; u32 magic; EmummcType type; u32 id; u32 fs_version; constexpr bool IsValid() const { return this->magic == Magic; } constexpr bool IsEmummcActive() const { return this->IsValid() && this->type != EmummcType_None; } }; static_assert(util::is_pod<EmummcBaseConfiguration>::value); static_assert(sizeof(EmummcBaseConfiguration) == 0x10); struct EmummcPartitionConfiguration { u64 start_sector; }; static_assert(util::is_pod<EmummcPartitionConfiguration>::value); struct EmummcFileConfiguration { EmummcFilePath path; }; static_assert(util::is_pod<EmummcFileConfiguration>::value); struct EmummcConfiguration { EmummcBaseConfiguration base_cfg; union { EmummcPartitionConfiguration partition_cfg; EmummcFileConfiguration file_cfg; }; EmummcFilePath emu_dir_path; constexpr bool IsValid() const { return this->base_cfg.IsValid(); } constexpr bool IsEmummcActive() const { return this->base_cfg.IsEmummcActive(); } }; static_assert(util::is_pod<EmummcConfiguration>::value); static_assert(sizeof(EmummcConfiguration) <= 0x200); } ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/log.hpp> #define AMS_SECMON_LOG(...) AMS_LOG(" [secmon] " __VA_ARGS__) ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/mmu.hpp> namespace ams::secmon { using Address = u64; struct MemoryRegion { private: Address m_start_address; Address m_end_address; public: consteval MemoryRegion(Address address, size_t size) : m_start_address(address), m_end_address(address + size) { if (m_end_address < m_start_address) { __builtin_unreachable(); } } constexpr Address GetStartAddress() const { return m_start_address; } constexpr Address GetAddress() const { return this->GetStartAddress(); } constexpr Address GetEndAddress() const { return m_end_address; } constexpr Address GetLastAddress() const { return m_end_address - 1; } constexpr size_t GetSize() const { return m_end_address - m_start_address; } constexpr bool Contains(Address address, size_t size) const { return m_start_address <= address && (address + size - 1) <= this->GetLastAddress(); } constexpr bool Contains(const MemoryRegion &rhs) const { return this->Contains(rhs.GetStartAddress(), rhs.GetSize()); } template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value) ALWAYS_INLINE T *GetPointer() const { return reinterpret_cast<T *>(this->GetAddress()); } template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value) ALWAYS_INLINE T *GetEndPointer() const { return reinterpret_cast<T *>(this->GetEndAddress()); } }; constexpr inline const MemoryRegion MemoryRegionVirtual = MemoryRegion(UINT64_C(0x1F0000000), 2_MB); constexpr inline const MemoryRegion MemoryRegionPhysical = MemoryRegion(UINT64_C( 0x40000000), 1_GB); constexpr inline const MemoryRegion MemoryRegionDram = MemoryRegion(UINT64_C( 0x80000000), 2_GB); constexpr inline const MemoryRegion MemoryRegionDramHigh = MemoryRegion(MemoryRegionDram.GetEndAddress(), 2_GB); constexpr inline const MemoryRegion MemoryRegionDramForMarikoProgram = MemoryRegion(UINT64_C(0xC0000000), 1_GB); constexpr inline const MemoryRegion MemoryRegionDramDcFramebuffer = MemoryRegion(UINT64_C(0xC0000000), 4_MB); static_assert(MemoryRegionDram.Contains(MemoryRegionDramForMarikoProgram)); static_assert(MemoryRegionDramForMarikoProgram.Contains(MemoryRegionDramDcFramebuffer)); constexpr inline const MemoryRegion MemoryRegionDramGpuCarveout = MemoryRegion(UINT64_C(0x80020000), UINT64_C(0x40000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramGpuCarveout)); constexpr inline const MemoryRegion MemoryRegionDramDefaultKernelCarveout = MemoryRegion(UINT64_C(0x80060000), UINT64_C(0x1FFE0000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramDefaultKernelCarveout)); constexpr inline const MemoryRegion MemoryRegionDramPackage2Payloads = MemoryRegion(MemoryRegionDram.GetAddress(), 8_MB); static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2Payloads)); constexpr inline const MemoryRegion MemoryRegionDramPackage2 = MemoryRegion(UINT64_C(0xA9800000), UINT64_C(0x07FC0000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2)); constexpr inline const MemoryRegion MemoryRegionPhysicalIram = MemoryRegion(UINT64_C(0x40000000), 0x40000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzram = MemoryRegion(UINT64_C(0x7C010000), 0x10000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMariko = MemoryRegion(UINT64_C(0x7C010000), 0x40000); static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalIram)); static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalTzram)); static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzram)); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatile(UINT64_C(0x7C010000), 0x2000); static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramVolatile)); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramNonVolatile(UINT64_C(0x7C012000), 0xE000); static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramNonVolatile)); static_assert(MemoryRegionPhysicalTzram.GetSize() == MemoryRegionPhysicalTzramNonVolatile.GetSize() + MemoryRegionPhysicalTzramVolatile.GetSize()); constexpr inline const MemoryRegion MemoryRegionVirtualL1 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize); constexpr inline const MemoryRegion MemoryRegionPhysicalL1 = MemoryRegion(util::AlignDown(MemoryRegionPhysical.GetAddress(), mmu::L1EntrySize), mmu::L1EntrySize); static_assert(MemoryRegionVirtualL1.Contains(MemoryRegionVirtual)); static_assert(MemoryRegionPhysicalL1.Contains(MemoryRegionPhysical)); constexpr inline const MemoryRegion MemoryRegionVirtualL2 = MemoryRegion(util::AlignDown(MemoryRegionVirtual.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); constexpr inline const MemoryRegion MemoryRegionPhysicalIramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalIram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2 = MemoryRegion(util::AlignDown(MemoryRegionPhysicalTzram.GetAddress(), mmu::L2EntrySize), mmu::L2EntrySize); static_assert(MemoryRegionVirtualL2.Contains(MemoryRegionVirtual)); static_assert(MemoryRegionPhysicalIramL2.Contains(MemoryRegionPhysicalIram)); static_assert(MemoryRegionPhysicalTzramL2.Contains(MemoryRegionPhysicalTzram)); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCode = MemoryRegion(UINT64_C(0x40020000), 0x20000); static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramBootCode)); constexpr inline const MemoryRegion MemoryRegionVirtualDevice = MemoryRegion(UINT64_C(0x1F0040000), UINT64_C(0x40000)); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDevice)); constexpr inline const MemoryRegion MemoryRegionVirtualDeviceEmpty = MemoryRegion(MemoryRegionVirtualDevice.GetStartAddress(), 0); #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \ HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \ HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \ HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \ HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(FuseKFuse, MemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \ HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \ HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \ HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) #define DEFINE_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \ constexpr inline const MemoryRegion MemoryRegionVirtualDevice##_NAME_ = MemoryRegion(MemoryRegionVirtualDevice##_PREV_.GetEndAddress() + 0x1000, _SIZE_); \ constexpr inline const MemoryRegion MemoryRegionPhysicalDevice##_NAME_ = MemoryRegion(_ADDRESS_, _SIZE_); \ static_assert(MemoryRegionVirtualDevice.Contains(MemoryRegionVirtualDevice##_NAME_)); \ static_assert(MemoryRegionPhysical.Contains(MemoryRegionPhysicalDevice##_NAME_)); AMS_SECMON_FOREACH_DEVICE_REGION(DEFINE_DEVICE_REGION) #undef DEFINE_DEVICE_REGION constexpr inline const MemoryRegion MemoryRegionVirtualDeviceFuses = MemoryRegion(MemoryRegionVirtualDeviceFuseKFuse.GetAddress() + 0x800, 0x400); constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceFuses = MemoryRegion(MemoryRegionPhysicalDeviceFuseKFuse.GetAddress() + 0x800, 0x400); static_assert(MemoryRegionVirtualDeviceFuseKFuse.Contains(MemoryRegionVirtualDeviceFuses)); static_assert(MemoryRegionPhysicalDeviceFuseKFuse.Contains(MemoryRegionPhysicalDeviceFuses)); constexpr inline const MemoryRegion MemoryRegionVirtualDeviceActivityMonitor = MemoryRegion(MemoryRegionVirtualDeviceSystem.GetAddress() + 0x800, 0x400); constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceActivityMonitor = MemoryRegion(MemoryRegionPhysicalDeviceSystem.GetAddress() + 0x800, 0x400); static_assert(MemoryRegionVirtualDeviceSystem.Contains(MemoryRegionVirtualDeviceActivityMonitor)); static_assert(MemoryRegionPhysicalDeviceSystem.Contains(MemoryRegionPhysicalDeviceActivityMonitor)); constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartA = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x000, 0x040); constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartB = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x040, 0x040); constexpr inline const MemoryRegion MemoryRegionVirtualDeviceUartC = MemoryRegion(MemoryRegionVirtualDeviceUart.GetAddress() + 0x200, 0x100); static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartA)); static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartB)); static_assert(MemoryRegionVirtualDeviceUart.Contains(MemoryRegionVirtualDeviceUartC)); constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartA = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x000, 0x040); constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartB = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x040, 0x040); constexpr inline const MemoryRegion MemoryRegionPhysicalDeviceUartC = MemoryRegion(MemoryRegionPhysicalDeviceUart.GetAddress() + 0x200, 0x100); static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartA)); static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartB)); static_assert(MemoryRegionPhysicalDeviceUart.Contains(MemoryRegionPhysicalDeviceUartC)); constexpr inline const MemoryRegion MemoryRegionVirtualDevicePmc = MemoryRegion(MemoryRegionVirtualDeviceRtcPmc.GetAddress() + 0x400, 0xC00); constexpr inline const MemoryRegion MemoryRegionPhysicalDevicePmc = MemoryRegion(MemoryRegionPhysicalDeviceRtcPmc.GetAddress() + 0x400, 0xC00); static_assert(MemoryRegionVirtualDeviceRtcPmc.Contains(MemoryRegionVirtualDevicePmc)); static_assert(MemoryRegionPhysicalDeviceRtcPmc.Contains(MemoryRegionPhysicalDevicePmc)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramReadOnlyAlias = MemoryRegion(UINT64_C(0x1F00A0000), MemoryRegionPhysicalTzram.GetSize()); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramReadOnlyAlias = MemoryRegion(MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize()); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramReadOnlyAlias)); static_assert(MemoryRegionPhysicalTzram.Contains(MemoryRegionPhysicalTzramReadOnlyAlias)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgram(UINT64_C(0x1F00C0000), 0xC000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramProgram)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramExceptionVectors(UINT64_C(0x1F00C0000), 0x800); static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramExceptionVectors)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgram(UINT64_C(0x1F00D0000), 0x20000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMarikoProgram(UINT64_C(0x7C020000), 0x20000); static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzramMarikoProgram)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgramFatalErrorContext(UINT64_C(0x1F00EF000), 0x1000); static_assert(MemoryRegionVirtualTzramMarikoProgram.Contains(MemoryRegionVirtualTzramMarikoProgramFatalErrorContext)); constexpr inline const MemoryRegion MemoryRegionPhysicalIramFatalErrorContext(UINT64_C(0x4003E000), 0x1000); static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramFatalErrorContext)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramMarikoProgramStack(UINT64_C(0x1F00F4000), 0x8000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramMarikoProgramStack(UINT64_C(0x7C040000), 0x8000); static_assert(MemoryRegionPhysicalTzramMariko.Contains(MemoryRegionPhysicalTzramMarikoProgramStack)); constexpr inline const MemoryRegion MemoryRegionPhysicalMarikoProgramImage(UINT64_C(0x80020000), 0x20000); static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalMarikoProgramImage)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramProgramMain(UINT64_C(0x1F00C0800), 0xB800); static_assert(MemoryRegionVirtualTzramProgram.Contains(MemoryRegionVirtualTzramProgramMain)); static_assert(MemoryRegionVirtualTzramProgram.GetSize() == MemoryRegionVirtualTzramProgramExceptionVectors.GetSize() + MemoryRegionVirtualTzramProgramMain.GetSize()); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramProgram(UINT64_C(0x7C012000), 0xC000); static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramProgram)); constexpr inline const Address PhysicalTzramProgramResetVector = MemoryRegionPhysicalTzramProgram.GetAddress() + MemoryRegionVirtualTzramProgramExceptionVectors.GetSize(); static_assert(static_cast<u32>(PhysicalTzramProgramResetVector) == PhysicalTzramProgramResetVector); constexpr uintptr_t GetPhysicalTzramProgramAddress(uintptr_t virtual_address) { return virtual_address - MemoryRegionVirtualTzramProgram.GetStartAddress() + MemoryRegionPhysicalTzramNonVolatile.GetStartAddress(); } constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Work = MemoryRegion(UINT64_C(0x1F0120000), MemoryRegionPhysicalTzram.GetSize()); constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Work = MemoryRegion( UINT64_C(0x40020000), MemoryRegionPhysicalTzram.GetSize()); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Work)); static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Work)); constexpr inline const MemoryRegion MemoryRegionVirtualIramSc7Firmware = MemoryRegion(UINT64_C(0x1F0140000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalIramSc7Firmware = MemoryRegion( UINT64_C(0x40003000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualIramSc7Firmware)); static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSc7Firmware)); constexpr inline const MemoryRegion MemoryRegionPhysicalIramSecureMonitorDebug(UINT64_C(0x40034000), 0x4000); static_assert(MemoryRegionPhysicalIram.Contains(MemoryRegionPhysicalIramSecureMonitorDebug)); constexpr inline const MemoryRegion MemoryRegionVirtualDebugCode = MemoryRegion(UINT64_C(0x1F0150000), 0x4000); constexpr inline const MemoryRegion MemoryRegionPhysicalDebugCode = MemoryRegion(UINT64_C(0x40034000), 0x4000); static_assert(MemoryRegionPhysicalIramSecureMonitorDebug.Contains(MemoryRegionPhysicalDebugCode)); constexpr inline const MemoryRegion MemoryRegionVirtualDebug = MemoryRegion(UINT64_C(0x1F0160000), 0x10000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDebug)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramBootCode = MemoryRegion(UINT64_C(0x1F01C0000), 0x2000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramBootCode = MemoryRegion( UINT64_C(0x7C010000), 0x2000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramBootCode)); static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramBootCode)); constexpr inline const MemoryRegion MemoryRegionPhysicalDramMonitorConfiguration = MemoryRegion( UINT64_C(0x8000F000), 0x1000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStore = MemoryRegion(UINT64_C(0x1F0100000), 0x10000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStore = MemoryRegion( UINT64_C(0x80010000), 0x10000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore)); static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore)); constexpr inline const MemoryRegion MemoryRegionVirtualDramDebugDataStore = MemoryRegion(UINT64_C(0x1F0110000), 0x4000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramDebugDataStore = MemoryRegion( UINT64_C(0x8000C000), 0x4000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualDramSecureDataStore)); static_assert(MemoryRegionDram.Contains(MemoryRegionPhysicalDramSecureDataStore)); constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmcMappedData = MemoryRegion(UINT64_C(0x1F0100000), 0xC000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmcMappedData = MemoryRegion(UINT64_C(0x80010000), 0xC000); constexpr inline const MemoryRegion MemoryRegionVirtualDramDcL0DevicePageTable = MemoryRegion(UINT64_C(0x1F010C000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramDcL0DevicePageTable = MemoryRegion( UINT64_C(0x8001C000), 0x1000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L0DevicePageTable = MemoryRegion(UINT64_C(0x1F010E000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L0DevicePageTable = MemoryRegion( UINT64_C(0x8001E000), 0x1000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSdmmc1L1DevicePageTable = MemoryRegion(UINT64_C(0x1F010F000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSdmmc1L1DevicePageTable = MemoryRegion( UINT64_C(0x8001F000), 0x1000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x1F0100000), 0xE000); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x1F010E000), 0x17C0); constexpr inline const MemoryRegion MemoryRegionVirtualDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x1F010F7C0), 0x0840); static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreTzram)); static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware)); static_assert(MemoryRegionVirtualDramSecureDataStore.Contains(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState)); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreTzram = MemoryRegion(UINT64_C(0x80010000), 0xE000); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware = MemoryRegion(UINT64_C(0x8001E000), 0x17C0); constexpr inline const MemoryRegion MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState = MemoryRegion(UINT64_C(0x8001F7C0), 0x0840); static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreTzram)); static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware)); static_assert(MemoryRegionPhysicalDramSecureDataStore.Contains(MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState)); constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereIramPage = MemoryRegion(UINT64_C(0x1F01F0000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereIramPage)); constexpr inline const MemoryRegion MemoryRegionVirtualAtmosphereUserPage = MemoryRegion(UINT64_C(0x1F01F2000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualAtmosphereUserPage)); constexpr inline const MemoryRegion MemoryRegionVirtualSmcUserPage = MemoryRegion(UINT64_C(0x1F01F4000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualSmcUserPage)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileData = MemoryRegion(UINT64_C(0x1F01F6000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileData = MemoryRegion( UINT64_C(0x7C010000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileData)); static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileData)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramVolatileStack = MemoryRegion(UINT64_C(0x1F01F8000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramVolatileStack = MemoryRegion( UINT64_C(0x7C011000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramVolatileStack)); static_assert(MemoryRegionPhysicalTzramVolatile.Contains(MemoryRegionPhysicalTzramVolatileStack)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramConfigurationData = MemoryRegion(UINT64_C(0x1F01FA000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramConfigurationData = MemoryRegion( UINT64_C(0x7C01E000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramConfigurationData)); static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramConfigurationData)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramL1PageTable = MemoryRegion(UINT64_C(0x1F01FCFC0), 0x40); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL1PageTable = MemoryRegion( UINT64_C(0x7C01EFC0), 0x40); static_assert(MemoryRegionPhysicalTzramConfigurationData.Contains(MemoryRegionPhysicalTzramL1PageTable)); constexpr inline const MemoryRegion MemoryRegionVirtualTzramL2L3PageTable = MemoryRegion(UINT64_C(0x1F01FE000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramL2L3PageTable = MemoryRegion( UINT64_C(0x7C01F000), 0x1000); static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramL2L3PageTable)); static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable)); constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0xC000); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeCode = MemoryRegion(UINT64_C(0x40032000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeKeys = MemoryRegion(UINT64_C(0x40033000), 0x1000); constexpr inline const MemoryRegion MemoryRegionPhysicalIramWarmbootBin = MemoryRegion(UINT64_C(0x4003E000), 0x17F0); constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400); constexpr inline const MemoryRegion MemoryRegionPhysicalIramRebootStub = MemoryRegion(UINT64_C(0x4003F000), 0x1000); } ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/fuse.hpp> #include <exosphere/uart.hpp> #include <exosphere/secmon/secmon_emummc_context.hpp> namespace ams::secmon { enum SecureMonitorConfigurationFlag : u32 { SecureMonitorConfigurationFlag_None = (0u << 0), SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel = (1u << 1), SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser = (1u << 2), SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers = (1u << 3), SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess = (1u << 4), SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5), SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6), SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7), SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel, }; struct SecureMonitorStorageConfiguration { static constexpr u32 Magic = util::FourCC<'E','X','O','0'>::Code; u32 magic; ams::TargetFirmware target_firmware; u32 flags[2]; u16 lcd_vendor; u8 log_port; u8 log_flags; u32 log_baud_rate; u32 reserved1[2]; EmummcConfiguration emummc_cfg; constexpr bool IsValid() const { return this->magic == Magic; } }; static_assert(util::is_pod<SecureMonitorStorageConfiguration>::value); static_assert(sizeof(SecureMonitorStorageConfiguration) == 0x130); struct SecureMonitorConfiguration { ams::TargetFirmware target_firmware; s32 key_generation; u8 hardware_type; u8 soc_type; u8 hardware_state; u8 log_port; u32 flags[2]; u16 lcd_vendor; u8 log_flags; u8 reserved0; u32 log_baud_rate; u32 reserved1[(0x80 - 0x1C) / sizeof(u32)]; constexpr void CopyFrom(const SecureMonitorStorageConfiguration &storage) { this->target_firmware = storage.target_firmware; this->flags[0] = storage.flags[0]; this->flags[1] = storage.flags[1]; this->lcd_vendor = storage.lcd_vendor; this->log_port = storage.log_port; this->log_flags = storage.log_flags; this->log_baud_rate = storage.log_baud_rate != 0 ? storage.log_baud_rate : 115200; } void SetFuseInfo() { this->hardware_type = fuse::GetHardwareType(); this->soc_type = fuse::GetSocType(); this->hardware_state = fuse::GetHardwareState(); } constexpr ams::TargetFirmware GetTargetFirmware() const { return this->target_firmware; } constexpr int GetKeyGeneration() const { return this->key_generation; } constexpr fuse::HardwareType GetHardwareType() const { return static_cast<fuse::HardwareType>(this->hardware_type); } constexpr fuse::SocType GetSocType() const { return static_cast<fuse::SocType>(this->soc_type); } constexpr fuse::HardwareState GetHardwareState() const { return static_cast<fuse::HardwareState>(this->hardware_state); } constexpr uart::Port GetLogPort() const { return static_cast<uart::Port>(this->log_port); } constexpr u8 GetLogFlags() const { return this->log_flags; } constexpr u16 GetLcdVendor() const { return this->lcd_vendor; } constexpr u32 GetLogBaudRate() const { return this->log_baud_rate; } constexpr bool IsProduction() const { return this->GetHardwareState() != fuse::HardwareState_Development; } constexpr bool IsDevelopmentFunctionEnabledForKernel() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel) != 0; } constexpr bool IsDevelopmentFunctionEnabledForUser() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser) != 0; } constexpr bool DisableUserModeExceptionHandlers() const { return (this->flags[0] & SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers) != 0; } constexpr bool EnableUserModePerformanceCounterAccess() const { return (this->flags[0] & SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess) != 0; } constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; } constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; } constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; } constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); } }; static_assert(util::is_pod<SecureMonitorConfiguration>::value); static_assert(sizeof(SecureMonitorConfiguration) == 0x80); constexpr inline const SecureMonitorConfiguration DefaultSecureMonitorConfiguration = { .target_firmware = ams::TargetFirmware_Current, .key_generation = {}, .hardware_type = {}, .soc_type = {}, .hardware_state = {}, .log_port = uart::Port_ReservedDebug, .flags = { SecureMonitorConfigurationFlag_Default, SecureMonitorConfigurationFlag_None }, .lcd_vendor = {}, .log_flags = {}, .reserved0 = {}, .log_baud_rate = 115200, .reserved1 = {}, }; } ================================================ FILE: libraries/libexosphere/include/exosphere/secmon/secmon_volatile_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/pkg1.hpp> #include <exosphere/pkg2.hpp> namespace ams::secmon { /* The VolatileStack page is reserved entirely for use for core 3 SMC handling. */ constexpr inline const Address Core3SmcStackAddress = MemoryRegionVirtualTzramVolatileStack.GetAddress() + MemoryRegionVirtualTzramVolatileStack.GetSize(); constexpr inline const size_t CoreExceptionStackSize = 0x80; /* Volatile keydata that we lose access to after boot. */ struct VolatileKeys { u8 boot_config_rsa_modulus[0x100]; u8 package2_dev_rsa_modulus[0x100]; u8 package2_prod_rsa_modulus[0x100]; u8 package2_aes_key[0x10]; u8 master_key_source[0x10]; u8 device_master_key_source_kek_source[0x10]; u8 mariko_dev_master_kek_source[0x10]; u8 mariko_prod_master_kek_source[0x10]; u8 dev_master_key_vectors[pkg1::OldMasterKeyCount + 1][0x10]; u8 prod_master_key_vectors[pkg1::OldMasterKeyCount + 1][0x10]; u8 device_master_key_source_sources[pkg1::OldDeviceMasterKeyCount][0x10]; u8 dev_device_master_kek_sources[pkg1::OldDeviceMasterKeyCount][0x10]; u8 prod_device_master_kek_sources[pkg1::OldDeviceMasterKeyCount][0x10]; }; static_assert(util::is_pod<VolatileKeys>::value); static_assert(sizeof(VolatileKeys) <= 0x1000); /* Nintendo uses the bottom 0x740 of this as a stack for warmboot setup, and another 0x740 for the core 0/1/2 SMC stacks. */ /* This is...wasteful. The warmboot stack is not deep. We will thus save 1K+ of nonvolatile storage by keeping the random cache in here. */ struct VolatileData { u8 se_work_block[crypto::AesEncryptor128::BlockSize]; union { u8 random_cache[0x400]; pkg2::Package2Meta pkg2_meta; }; u8 reserved_danger_zone[0x30]; /* This memory is "available", but careful consideration must be taken before declaring it used. */ u8 warmboot_stack[0x380]; u8 core012_smc_stack[0x6C0]; u8 core_exception_stacks[3][CoreExceptionStackSize]; }; static_assert(util::is_pod<VolatileData>::value); static_assert(sizeof(VolatileData) == 0x1000); ALWAYS_INLINE VolatileData &GetVolatileData() { return *MemoryRegionVirtualTzramVolatileData.GetPointer<VolatileData>(); } ALWAYS_INLINE u8 *GetRandomBytesCache() { return GetVolatileData().random_cache; } constexpr ALWAYS_INLINE size_t GetRandomBytesCacheSize() { return sizeof(VolatileData::random_cache); } ALWAYS_INLINE u8 *GetSecurityEngineEphemeralWorkBlock() { return GetVolatileData().se_work_block; } namespace boot { ALWAYS_INLINE VolatileKeys &GetVolatileKeys() { return *MemoryRegionPhysicalIramBootCodeKeys.GetPointer<VolatileKeys>(); } ALWAYS_INLINE const u8 *GetBootConfigRsaModulus() { return GetVolatileKeys().boot_config_rsa_modulus; } ALWAYS_INLINE const u8 *GetPackage2RsaModulus(bool is_prod) { auto &keys = GetVolatileKeys(); return is_prod ? keys.package2_prod_rsa_modulus : keys.package2_dev_rsa_modulus; } ALWAYS_INLINE const u8 *GetPackage2AesKey() { return GetVolatileKeys().package2_aes_key; } ALWAYS_INLINE const u8 *GetMasterKeySource() { return GetVolatileKeys().master_key_source; } ALWAYS_INLINE const u8 *GetDeviceMasterKeySourceKekSource() { return GetVolatileKeys().device_master_key_source_kek_source; } ALWAYS_INLINE const u8 *GetMarikoMasterKekSource(bool is_prod) { auto &keys = GetVolatileKeys(); return is_prod ? keys.mariko_prod_master_kek_source : keys.mariko_dev_master_kek_source; } ALWAYS_INLINE const u8 *GetMasterKeyVector(bool is_prod, size_t i) { auto &keys = GetVolatileKeys(); return is_prod ? keys.prod_master_key_vectors[i] : keys.dev_master_key_vectors[i]; } ALWAYS_INLINE const u8 *GetDeviceMasterKeySourceSource(size_t i) { return GetVolatileKeys().device_master_key_source_sources[i]; } ALWAYS_INLINE const u8 *GetDeviceMasterKekSource(bool is_prod, size_t i) { auto &keys = GetVolatileKeys(); return is_prod ? keys.prod_device_master_kek_sources[i] : keys.dev_device_master_kek_sources[i]; } ALWAYS_INLINE pkg2::Package2Meta &GetEphemeralPackage2Meta() { return GetVolatileData().pkg2_meta; } } constexpr inline const Address WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, warmboot_stack) + sizeof(VolatileData::warmboot_stack); constexpr inline const Address Core012SmcStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core012_smc_stack) + sizeof(VolatileData::core012_smc_stack); constexpr inline const Address Core0ExceptionStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core_exception_stacks) + CoreExceptionStackSize; constexpr inline const Address Core1ExceptionStackAddress = Core0ExceptionStackAddress + CoreExceptionStackSize; constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize; } ================================================ FILE: libraries/libexosphere/include/exosphere/secmon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/secmon/secmon_log.hpp> #include <exosphere/secmon/secmon_memory_layout.hpp> #include <exosphere/secmon/secmon_configuration_context.hpp> #include <exosphere/secmon/secmon_volatile_context.hpp> ================================================ FILE: libraries/libexosphere/include/exosphere/tsec.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::tsec { bool RunTsecFirmware(const void *fw, size_t fw_size); void Lock(); } ================================================ FILE: libraries/libexosphere/include/exosphere/uart.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::uart { enum Port { Port_A = 0, Port_B = 1, Port_C = 2, Port_Count = 3, Port_ReservedDebug = Port_A, Port_RightJoyCon = Port_B, Port_LeftJoyCon = Port_C, }; enum Flags { Flag_None = (0u << 0), Flag_Inverted = (1u << 0), }; void SetRegisterAddress(uintptr_t address); void Initialize(Port port, int baud_rate, u32 flags); void SendText(Port port, const void *data, size_t size); void WaitFlush(Port port); } ================================================ FILE: libraries/libexosphere/include/exosphere/util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::util { void SetRegisterAddress(uintptr_t address); void ClearMemory(void *ptr, size_t size); } ================================================ FILE: libraries/libexosphere/include/exosphere/wdt.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::wdt { void SetRegisterAddress(uintptr_t address); void Reboot(); } ================================================ FILE: libraries/libexosphere/include/exosphere.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <exosphere/common.hpp> #include <exosphere/hw.hpp> #include <exosphere/util.hpp> #include <exosphere/mmu.hpp> #include <exosphere/br.hpp> #include <exosphere/charger.hpp> #include <exosphere/gic.hpp> #include <exosphere/wdt.hpp> #include <exosphere/pkg1.hpp> #include <exosphere/pkg2.hpp> #include <exosphere/tsec.hpp> #include <exosphere/se.hpp> #include <exosphere/flow.hpp> #include <exosphere/fuse.hpp> #include <exosphere/i2c.hpp> #include <exosphere/uart.hpp> #include <exosphere/pinmux.hpp> #include <exosphere/pmic.hpp> #include <exosphere/pmic_setup.hpp> #include <exosphere/rtc.hpp> #include <exosphere/log.hpp> #include <exosphere/clkrst.hpp> #include <exosphere/actmon.hpp> #include <exosphere/pmc.hpp> #include <exosphere/secmon.hpp> ================================================ FILE: libraries/libexosphere/libexosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../config/common.mk #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- PRECOMPILED_HEADERS := ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -Os endif else ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O2 endif endif DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE -DAMS_FORCE_DISABLE_DETAILED_ASSERTIONS SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -fno-non-call-exceptions -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64) SETTINGS += -mgeneral-regs-only -ffixed-x18 else ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm) SETTINGS += -flto endif CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) LIBS := #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. #--------------------------------------------------------------------------------- .PHONY: clean all all: $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) $(GCH_DIRS) $(CPPFILES) $(CFILES) $(SFILES) @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) #--------------------------------------------------------------------------------- clean: @echo clean $(ATMOSPHERE_BUILD_NAME) ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) @rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) @for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- else GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr))))) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT) : $(OFILES) $(OFILES) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) libc.o: CFLAGS += -fno-builtin ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm) libc.o: CFLAGS += -fno-lto util_api.o: CFLAGS += -fno-lto endif #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: libraries/libexosphere/source/actmon/actmon_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "actmon_registers.hpp" namespace ams::actmon { namespace { constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceActivityMonitor.GetAddress(); constinit InterruptHandler g_interrupt_handler = nullptr; } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void HandleInterrupt() { /* Get the registers. */ const uintptr_t ACTMON = g_register_address; /* Disable the actmon interrupt. */ reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM(COP_CTRL_ENB, DISABLE)); /* Update the interrupt status. */ reg::Write(ACTMON + ACTMON_COP_INTR_STATUS, reg::Read(ACTMON + ACTMON_COP_INTR_STATUS)); /* Invoke the handler. */ if (g_interrupt_handler != nullptr) { g_interrupt_handler(); g_interrupt_handler = nullptr; } } void StartMonitoringBpmp(InterruptHandler handler) { /* Get the registers. */ const uintptr_t ACTMON = g_register_address; /* Configure the activity monitor to poll once per microsecond. */ reg::Write(ACTMON + ACTMON_GLB_PERIOD_CTRL, ACTMON_REG_BITS_ENUM (GLB_PERIOD_CTRL_SOURCE, USEC), ACTMON_REG_BITS_VALUE(GLB_PERIOD_CTRL_SAMPLE_PERIOD, 0)); /* Configure the activity monitor to generate an interrupt the first time the event occurs. */ reg::Write(ACTMON + ACTMON_COP_UPPER_WMARK, 0); /* Set the interrupt handler. */ g_interrupt_handler = handler; /* Configure the activity monitor to generate events whenever the bpmp is woken up. */ reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM (COP_CTRL_ENB, ENABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_CONSECUTIVE_ABOVE_WMARK_EN, ENABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_CONSECUTIVE_BELOW_WMARK_EN, DISABLE), ACTMON_REG_BITS_VALUE(COP_CTRL_ABOVE_WMARK_NUM, 0), ACTMON_REG_BITS_VALUE(COP_CTRL_BELOW_WMARK_NUM, 0), ACTMON_REG_BITS_ENUM (COP_CTRL_WHEN_OVERFLOW_EN, DISABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_AVG_ABOVE_WMARK_EN, DISABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_AVG_BELOW_WMARK_EN, DISABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_AT_END_EN, DISABLE), ACTMON_REG_BITS_ENUM (COP_CTRL_ENB_PERIODIC, ENABLE)); /* Read the activity monitor control register to make sure our configuration takes. */ reg::Read(ACTMON + ACTMON_COP_CTRL); } void StopMonitoringBpmp() { /* Get the registers. */ const uintptr_t ACTMON = g_register_address; /* Disable the actmon interrupt. */ reg::Write(ACTMON + ACTMON_COP_CTRL, ACTMON_REG_BITS_ENUM(COP_CTRL_ENB, DISABLE)); /* Update the interrupt status. */ reg::Write(ACTMON + ACTMON_COP_INTR_STATUS, reg::Read(ACTMON + ACTMON_COP_INTR_STATUS)); /* Clear the interrupt handler. */ g_interrupt_handler = nullptr; } } ================================================ FILE: libraries/libexosphere/source/actmon/actmon_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::actmon { #define ACTMON_GLB_PERIOD_CTRL (0x004) #define ACTMON_COP_CTRL (0x0C0) #define ACTMON_COP_UPPER_WMARK (0x0C4) #define ACTMON_COP_INTR_STATUS (0x0E4) /* Actmon source enums. */ #define ACTMON_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (ACTMON, NAME) #define ACTMON_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (ACTMON, NAME, VALUE) #define ACTMON_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (ACTMON, NAME, ENUM) #define ACTMON_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(ACTMON, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) #define DEFINE_ACTMON_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (ACTMON, NAME, __OFFSET__, __WIDTH__) #define DEFINE_ACTMON_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE) #define DEFINE_ACTMON_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) #define DEFINE_ACTMON_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) #define DEFINE_ACTMON_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (ACTMON, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) DEFINE_ACTMON_REG(GLB_PERIOD_CTRL_SAMPLE_PERIOD, 0, 8); DEFINE_ACTMON_REG_BIT_ENUM(GLB_PERIOD_CTRL_SOURCE, 8, MSEC, USEC); DEFINE_ACTMON_REG(COP_CTRL_K_VAL, 10, 3); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_ENB_PERIODIC, 18, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AT_END_EN, 19, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AVG_BELOW_WMARK_EN, 20, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_AVG_ABOVE_WMARK_EN, 21, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_WHEN_OVERFLOW_EN, 22, DISABLE, ENABLE); DEFINE_ACTMON_REG(COP_CTRL_BELOW_WMARK_NUM, 23, 3); DEFINE_ACTMON_REG(COP_CTRL_ABOVE_WMARK_NUM, 26, 3); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_CONSECUTIVE_BELOW_WMARK_EN, 29, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_CONSECUTIVE_ABOVE_WMARK_EN, 30, DISABLE, ENABLE); DEFINE_ACTMON_REG_BIT_ENUM(COP_CTRL_ENB, 31, DISABLE, ENABLE); } ================================================ FILE: libraries/libexosphere/source/charger/charger_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::charger { namespace { /* https://www.ti.com/lit/ds/symlink/bq24193.pdf */ constexpr inline int I2cAddressBq24193 = 0x6B; constexpr inline int Bq24193RegisterInputSourceControl = 0x00; /* 8.5.1.1 EN_HIZ */ enum EnHiZ : u8 { EnHiZ_Disable = (0u << 7), EnHiZ_Enable = (1u << 7), EnHiZ_Mask = (1u << 7), }; } bool IsHiZMode() { return (i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl) & EnHiZ_Mask) == EnHiZ_Enable; } void EnterHiZMode() { u8 ctrl = i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl); ctrl &= ~EnHiZ_Mask; ctrl |= EnHiZ_Enable; i2c::SendByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl, ctrl); } void ExitHiZMode() { u8 ctrl = i2c::QueryByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl); ctrl &= ~EnHiZ_Mask; ctrl |= EnHiZ_Disable; i2c::SendByte(i2c::Port_1, I2cAddressBq24193, Bq24193RegisterInputSourceControl, ctrl); } } ================================================ FILE: libraries/libexosphere/source/clkrst/clkrst_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::clkrst { namespace { constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress(); constinit BpmpClockRate g_bpmp_clock_rate = BpmpClockRate_408MHz; struct ClockParameters { uintptr_t reset_offset; uintptr_t clk_enb_offset; uintptr_t clk_src_offset; u8 index; u8 clk_src; u8 clk_div; }; void EnableClock(const ClockParameters ¶m) { /* Hold reset. */ reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1)); /* Disable clock. */ reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0)); /* Set the clock source. */ if (param.clk_src_offset != 0) { reg::Write(g_register_address + param.clk_src_offset, (param.clk_src << 29) | (param.clk_div << 0)); } /* Enable clk. */ reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 1)); /* Release reset. */ reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 0)); } void DisableClock(const ClockParameters ¶m) { /* Hold reset. */ reg::ReadWrite(g_register_address + param.reset_offset, REG_BITS_VALUE(param.index, 1, 1)); /* Disable clock. */ reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0)); } #define DEFINE_CLOCK_PARAMETERS(_VARNAME_, _REG_, _NAME_, _CLK_, _DIV_) \ constexpr inline const ClockParameters _VARNAME_ = { \ .reset_offset = CLK_RST_CONTROLLER_RST_DEVICES_##_REG_, \ .clk_enb_offset = CLK_RST_CONTROLLER_CLK_OUT_ENB_##_REG_, \ .clk_src_offset = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_, \ .index = CLK_RST_CONTROLLER_CLK_ENB_##_NAME_##_INDEX, \ .clk_src = CLK_RST_CONTROLLER_CLK_SOURCE_##_NAME_##_##_NAME_##_CLK_SRC_##_CLK_, \ .clk_div = _DIV_, \ } #define DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(_VARNAME_, _REG_, _NAME_) \ constexpr inline const ClockParameters _VARNAME_ = { \ .reset_offset = CLK_RST_CONTROLLER_RST_DEVICES_##_REG_, \ .clk_enb_offset = CLK_RST_CONTROLLER_CLK_OUT_ENB_##_REG_, \ .clk_src_offset = 0, \ .index = CLK_RST_CONTROLLER_CLK_ENB_##_NAME_##_INDEX, \ .clk_src = 0, \ .clk_div = 0, \ } DEFINE_CLOCK_PARAMETERS(UartAClock, L, UARTA, PLLP_OUT0, 0); DEFINE_CLOCK_PARAMETERS(UartBClock, L, UARTB, PLLP_OUT0, 0); DEFINE_CLOCK_PARAMETERS(UartCClock, H, UARTC, PLLP_OUT0, 0); DEFINE_CLOCK_PARAMETERS(I2c1Clock, L, I2C1, CLK_M, 0); DEFINE_CLOCK_PARAMETERS(I2c5Clock, H, I2C5, CLK_M, 0); DEFINE_CLOCK_PARAMETERS(SeClock, V, SE, PLLP_OUT0, 0); DEFINE_CLOCK_PARAMETERS(ActmonClock, V, ACTMON, CLK_M, 0); DEFINE_CLOCK_PARAMETERS(CsiteClock, U, CSITE, PLLP_OUT0, 4); DEFINE_CLOCK_PARAMETERS(Host1xClock, L, HOST1X, PLLP_OUT0, 3); DEFINE_CLOCK_PARAMETERS(TsecClock, U, TSEC, PLLP_OUT0, 2); DEFINE_CLOCK_PARAMETERS(Sor1Clock, X, SOR1, PLLP_OUT0, 2); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(CldvfsClock, W, DVFS); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(TzramClock, V, TZRAM); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(SorSafeClock, Y, SOR_SAFE); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Sor0Clock, X, SOR0); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(KfuseClock, H, KFUSE); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Cache2Clock, L, CACHE2); DEFINE_CLOCK_PARAMETERS_WITHOUT_CLKDIV(Cram2Clock, U, CRAM2); constexpr const u32 PllcDivn[] = { [BpmpClockRate_408MHz] = 0, [BpmpClockRate_544MHz] = 85, [BpmpClockRate_576MHz] = 90, [BpmpClockRate_589MHz] = 92, }; void EnablePllc(BpmpClockRate rate) { const u32 desired_divn = PllcDivn[rate]; /* Check if we're already enabled. */ const bool is_enabled = reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, ENABLE)); const bool is_good_divn = reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVN, desired_divn)); if (is_enabled && is_good_divn) { return; } /* Take PLLC out of reset. */ reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC, (reg::Read(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC) & 0xBFF0000F) | (0x80000 << 4)); reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC2, 0xF0 << 8); /* Disable pll. */ reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, DISABLE)); reg::ClearBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC1, (1u << 27)); util::WaitMicroSeconds(10); /* Set dividers. */ reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVM, 4), CLK_RST_REG_BITS_VALUE(PLLC_BASE_PLLC_DIVN, desired_divn)); /* Enable pll. */ reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, ENABLE)); while (!reg::HasValue(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_LOCK, LOCK))) { /* ... */ } /* Disable PLLC_OUT1. */ reg::Write(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_VALUE(PLLC_OUT_PLLC_OUT1_RATIO, 1)); /* Enable PLLC_OUT1. */ reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_RSTN, RESET_DISABLE), CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_CLKEN, ENABLE)); util::WaitMicroSeconds(1'000); } void DisablePllc() { /* Disable PLLC/PLLC_OUT1. */ reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_OUT, CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_RSTN, RESET_ENABLE), CLK_RST_REG_BITS_ENUM(PLLC_OUT_PLLC_OUT1_CLKEN, DISABLE)); reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_ENABLE, DISABLE)); reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_PLLC_BASE, CLK_RST_REG_BITS_ENUM(PLLC_BASE_PLLC_REF_DIS, REF_DISABLE)); reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC1, (1u << 27)); reg::SetBits(g_register_address + CLK_RST_CONTROLLER_PLLC_MISC, (1u << 30)); util::WaitMicroSeconds(10); } } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void SetFuseVisibility(bool visible) { reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_MISC_CLK_ENB, CLK_RST_REG_BITS_VALUE(MISC_CLK_ENB_CFG_ALL_VISIBLE, visible ? 1 : 0)); } void EnableUartAClock() { EnableClock(UartAClock); } void EnableUartBClock() { EnableClock(UartBClock); } void EnableUartCClock() { EnableClock(UartCClock); } void EnableActmonClock() { EnableClock(ActmonClock); } void EnableI2c1Clock() { EnableClock(I2c1Clock); } void EnableI2c5Clock() { EnableClock(I2c5Clock); } void EnableSeClock() { EnableClock(SeClock); if (fuse::GetSocType() == fuse::SocType_Mariko) { reg::ReadWrite(g_register_address + CLK_RST_CONTROLLER_CLK_SOURCE_SE, CLK_RST_REG_BITS_ENUM(CLK_SOURCE_SE_CLK_LOCK, ENABLE)); } } void EnableCldvfsClock() { EnableClock(CldvfsClock); } void EnableCsiteClock() { EnableClock(CsiteClock); } void EnableTzramClock() { EnableClock(TzramClock); } void EnableCache2Clock() { EnableClock(Cache2Clock); } void EnableCram2Clock() { EnableClock(Cram2Clock); } void EnableHost1xClock() { EnableClock(Host1xClock); } void EnableTsecClock() { EnableClock(TsecClock); } void EnableSorSafeClock() { EnableClock(SorSafeClock); } void EnableSor0Clock() { EnableClock(Sor0Clock); } void EnableSor1Clock() { EnableClock(Sor1Clock); } void EnableKfuseClock() { EnableClock(KfuseClock); } void DisableI2c1Clock() { DisableClock(I2c1Clock); } void DisableHost1xClock() { DisableClock(Host1xClock); } void DisableTsecClock() { DisableClock(TsecClock); } void DisableSorSafeClock() { DisableClock(SorSafeClock); } void DisableSor0Clock() { DisableClock(Sor0Clock); } void DisableSor1Clock() { DisableClock(Sor1Clock); } void DisableKfuseClock() { DisableClock(KfuseClock); } BpmpClockRate GetBpmpClockRate() { return g_bpmp_clock_rate; } BpmpClockRate SetBpmpClockRate(BpmpClockRate rate) { /* Get the current rate. */ const auto prev_rate = g_bpmp_clock_rate; /* Cap our rate. */ if (rate >= BpmpClockRate_Count) { rate = BpmpClockRate_589MHz; } /* Change the rate, if we need to. */ if (rate == prev_rate) { return prev_rate; } /* Configure the rate. */ if (rate != BpmpClockRate_408MHz) { /* If we were previously overclocked, restore to PLLP_OUT. */ if (prev_rate != BpmpClockRate_408MHz) { reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, PLLP_OUT0)); util::WaitMicroSeconds(1'000); } /* Configure PLLC. */ EnablePllc(rate); /* Set SCLK. */ reg::Write(g_register_address + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 3)); reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLC_OUT1), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, CLKM)); } else { /* Configure to use PLLP_OUT0. */ reg::Write(g_register_address + CLK_RST_CONTROLLER_SCLK_BURST_POLICY, CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SYS_STATE, RUN), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_FIQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_COP_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_CPU_AUTO_SWAKEUP_FROM_IRQ, NOP), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_FIQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IRQ_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE, PLLP_OUT0), CLK_RST_REG_BITS_ENUM(SCLK_BURST_POLICY_SWAKEUP_IDLE_SOURCE, CLKM)); util::WaitMicroSeconds(1'000); reg::Write(g_register_address + CLK_RST_CONTROLLER_CLK_SYSTEM_RATE, CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_HCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_AHB_RATE, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_PCLK_DIS, 0), CLK_RST_REG_BITS_VALUE(CLK_SYSTEM_RATE_APB_RATE, 2)); /* Disable PLLC. */ DisablePllc(); } /* Set the clock rate. */ g_bpmp_clock_rate = rate; /* Return the previous rate. */ return prev_rate; } } ================================================ FILE: libraries/libexosphere/source/crypto/crypto_aes_impl_security_engine.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::crypto::impl { namespace { constexpr bool IsSupportedKeySize(size_t size) { return size == 16 || size == 24 || size == 32; } } template<size_t KeySize> AesImpl<KeySize>::~AesImpl() { ClearMemory(this, sizeof(*this)); } template<size_t KeySize> void AesImpl<KeySize>::Initialize(const void *key, size_t key_size, bool is_encrypt) { static_assert(IsSupportedKeySize(KeySize)); AMS_ASSERT(key_size == sizeof(int)); AMS_UNUSED(key_size, is_encrypt); /* Set the security engine keyslot. */ m_slot = *static_cast<const int *>(key); } template<size_t KeySize> void AesImpl<KeySize>::EncryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { static_assert(IsSupportedKeySize(KeySize)); AMS_ASSERT(src_size >= BlockSize); AMS_ASSERT(dst_size >= BlockSize); if constexpr (KeySize == 16) { /* Aes 128. */ se::EncryptAes128(dst, dst_size, m_slot, src, src_size); } else if constexpr (KeySize == 24) { /* Aes 192. */ /* TODO: se::EncryptAes192(dst, dst_size, m_slot, src, src_size); */ AMS_UNUSED(dst, dst_size, src, src_size); } else if constexpr (KeySize == 32) { /* Aes 256. */ /* TODO: se::EncryptAes256(dst, dst_size, m_slot, src, src_size); */ AMS_UNUSED(dst, dst_size, src, src_size); } else { /* Invalid key size. */ static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value); } } template<size_t KeySize> void AesImpl<KeySize>::DecryptBlock(void *dst, size_t dst_size, const void *src, size_t src_size) const { static_assert(IsSupportedKeySize(KeySize)); AMS_ASSERT(src_size >= BlockSize); AMS_ASSERT(dst_size >= BlockSize); if constexpr (KeySize == 16) { /* Aes 128. */ se::DecryptAes128(dst, dst_size, m_slot, src, src_size); } else if constexpr (KeySize == 24) { /* Aes 192. */ /* TODO: se::DecryptAes192(dst, dst_size, m_slot, src, src_size); */ AMS_UNUSED(dst, dst_size, src, src_size); } else if constexpr (KeySize == 32) { /* Aes 256. */ /* TODO: se::DecryptAes256(dst, dst_size, m_slot, src, src_size); */ AMS_UNUSED(dst, dst_size, src, src_size); } else { /* Invalid key size. */ static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value); } } /* Explicitly instantiate the three supported key sizes. */ template class AesImpl<16>; template class AesImpl<24>; template class AesImpl<32>; } ================================================ FILE: libraries/libexosphere/source/flow/flow_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::flow { namespace { struct FlowControllerRegisterOffset { u16 cpu_csr; u16 halt_cpu_events; u16 cc4_core_ctrl; }; constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFlowController.GetAddress(); constexpr const FlowControllerRegisterOffset FlowControllerRegisterOffsets[] = { { FLOW_CTLR_CPU0_CSR, FLOW_CTLR_HALT_CPU0_EVENTS, FLOW_CTLR_CC4_CORE0_CTRL, }, { FLOW_CTLR_CPU1_CSR, FLOW_CTLR_HALT_CPU1_EVENTS, FLOW_CTLR_CC4_CORE1_CTRL, }, { FLOW_CTLR_CPU2_CSR, FLOW_CTLR_HALT_CPU2_EVENTS, FLOW_CTLR_CC4_CORE2_CTRL, }, { FLOW_CTLR_CPU3_CSR, FLOW_CTLR_HALT_CPU3_EVENTS, FLOW_CTLR_CC4_CORE3_CTRL, }, }; constexpr u32 GetHaltCpuEventsValue(bool resume_on_irq) { if (resume_on_irq) { return reg::Encode(FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_FLOW_MODE, WAITEVENT), FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_LIC_IRQN, ENABLE), FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_LIC_FIQN, ENABLE), FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_GIC_IRQN, ENABLE), FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_GIC_FIQN, ENABLE)); } else { return reg::Encode(FLOW_REG_BITS_ENUM(HALT_CPUN_EVENTS_FLOW_MODE, WAITEVENT)); } } } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void ResetCpuRegisters(int core) { AMS_ASSUME(core >= 0); const auto &offsets = FlowControllerRegisterOffsets[core]; reg::Write(g_register_address + offsets.cpu_csr, 0); reg::Write(g_register_address + offsets.halt_cpu_events, 0); } void SetCpuCsr(int core, u32 enable_ext) { reg::Write(g_register_address + FlowControllerRegisterOffsets[core].cpu_csr, FLOW_REG_BITS_ENUM (CPUN_CSR_INTR_FLAG, TRUE), FLOW_REG_BITS_ENUM (CPUN_CSR_EVENT_FLAG, TRUE), FLOW_REG_BITS_VALUE(CPUN_CSR_ENABLE_EXT, enable_ext), FLOW_REG_BITS_VALUE(CPUN_CSR_WAIT_WFI_BITMAP, (1u << core)), FLOW_REG_BITS_ENUM (CPUN_CSR_ENABLE, ENABLE)); } void SetHaltCpuEvents(int core, bool resume_on_irq) { reg::Write(g_register_address + FlowControllerRegisterOffsets[core].halt_cpu_events, GetHaltCpuEventsValue(resume_on_irq)); } void SetCc4Ctrl(int core, u32 value) { reg::Write(g_register_address + FlowControllerRegisterOffsets[core].cc4_core_ctrl, value); } void ClearL2FlushControl() { reg::Write(g_register_address + FLOW_CTLR_L2FLUSH_CONTROL, 0); } } ================================================ FILE: libraries/libexosphere/source/fuse/fuse_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "fuse_registers.hpp" namespace ams::fuse { namespace { static constexpr SocType SocType_CommonInternal = static_cast<SocType>(-1); static_assert(SocType_CommonInternal != SocType_Erista); static_assert(SocType_CommonInternal != SocType_Mariko); constinit SocType g_soc_type = SocType_CommonInternal; struct BypassEntry { u32 offset; u32 value; }; struct OdmWord2 { using DeviceUniqueKeyGeneration = util::BitPack32::Field<0, 5, int>; using Reserved = util::BitPack32::Field<5, 27, int>; }; struct OdmWord4 { using HardwareState1 = util::BitPack32::Field<0, 2, int>; using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>; using DramId1 = util::BitPack32::Field<HardwareType1::Next, 5, int>; using HardwareType2 = util::BitPack32::Field<DramId1::Next, 1, int>; using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>; using RetailInteractiveDisplayState = util::BitPack32::Field<HardwareState2::Next, 1, int>; using FormatVersion = util::BitPack32::Field<RetailInteractiveDisplayState::Next, 1, int>; using DramId2 = util::BitPack32::Field<FormatVersion::Next, 3, int>; using Reserved = util::BitPack32::Field<DramId2::Next, 1, int>; using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>; }; struct OdmWord28 { using Regulator = util::BitPack32::Field<0, 1, int>; using Reserved = util::BitPack32::Field<1, 31, int>; }; constexpr ALWAYS_INLINE int GetHardwareStateValue(const util::BitPack32 odm_word4) { constexpr auto HardwareState1Shift = 0; constexpr auto HardwareState2Shift = OdmWord4::HardwareState1::Count + HardwareState1Shift; return (odm_word4.Get<OdmWord4::HardwareState1>() << HardwareState1Shift) | (odm_word4.Get<OdmWord4::HardwareState2>() << HardwareState2Shift); } constexpr ALWAYS_INLINE int GetHardwareTypeValue(const util::BitPack32 odm_word4) { constexpr auto HardwareType1Shift = 0; constexpr auto HardwareType2Shift = OdmWord4::HardwareType1::Count + HardwareType1Shift; constexpr auto HardwareType3Shift = OdmWord4::HardwareType2::Count + HardwareType2Shift; return (odm_word4.Get<OdmWord4::HardwareType1>() << HardwareType1Shift) | (odm_word4.Get<OdmWord4::HardwareType2>() << HardwareType2Shift) | (odm_word4.Get<OdmWord4::HardwareType3>() << HardwareType3Shift); } constexpr ALWAYS_INLINE int GetDramIdValue(const util::BitPack32 odm_word4) { constexpr auto DramId1Shift = 0; constexpr auto DramId2Shift = OdmWord4::DramId1::Count + DramId1Shift; return (odm_word4.Get<OdmWord4::DramId1>() << DramId1Shift) | (odm_word4.Get<OdmWord4::DramId2>() << DramId2Shift); } constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFuses.GetAddress(); constinit bool g_checked_for_rcm_bug_patch = false; constinit bool g_has_rcm_bug_patch = false; ALWAYS_INLINE volatile FuseRegisterRegion *GetRegisterRegion() { return reinterpret_cast<volatile FuseRegisterRegion *>(g_register_address); } ALWAYS_INLINE volatile FuseRegisters &GetRegisters() { return GetRegisterRegion()->fuse; } ALWAYS_INLINE volatile FuseChipRegistersCommon &GetChipRegistersCommon() { return GetRegisterRegion()->chip_common; } ALWAYS_INLINE volatile FuseChipRegistersErista &GetChipRegistersErista() { return GetRegisterRegion()->chip_erista; } ALWAYS_INLINE volatile FuseChipRegistersMariko &GetChipRegistersMariko() { return GetRegisterRegion()->chip_mariko; } bool IsIdle() { return reg::HasValue(GetRegisters().FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_STATE, IDLE)); } void WaitForIdle() { while (!IsIdle()) { /* ... */ } } u32 GetOdmWordImpl(int index, fuse::SocType soc_type) { if (index < 8) { volatile auto &chip = GetChipRegistersCommon(); return chip.FUSE_RESERVED_ODM_0[index - 0]; } else if (soc_type == SocType_Mariko) { volatile auto &chip = GetChipRegistersMariko(); if (index < 22) { return chip.FUSE_RESERVED_ODM_8[index - 8]; } else if (index < 25) { return chip.FUSE_RESERVED_ODM_22[index - 22]; } else if (index < 26) { return chip.FUSE_RESERVED_ODM_25[index - 25]; } else if (index < 29) { return chip.FUSE_RESERVED_ODM_26[index - 26]; } else if (index < 30) { return chip.FUSE_RESERVED_ODM_29[index - 29]; } } AMS_ABORT("Invalid ODM fuse read"); } u32 GetCommonOdmWord(int index) { return GetOdmWordImpl(index, SocType_CommonInternal); } bool IsNewFuseFormat() { /* On mariko, this should always be true. */ if (GetSocType() != SocType_Erista) { return true; } /* Require that the format version be non-zero in odm4. */ if (util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::FormatVersion>() == 0) { return false; } /* Check that odm word 0/1 are fused with the magic values. */ constexpr u32 NewFuseFormatMagic0 = 0x8E61ECAE; constexpr u32 NewFuseFormatMagic1 = 0xF2BA3BB2; const u32 w0 = GetCommonOdmWord(0); const u32 w1 = GetCommonOdmWord(1); return w0 == NewFuseFormatMagic0 && w1 == NewFuseFormatMagic1; } constexpr u32 CompressLotCode(u32 lot0) { constexpr int Radix = 36; constexpr int Count = 5; constexpr int Width = 6; constexpr u32 Mask = (1u << Width) - 1; u32 compressed = 0; for (int i = Count - 1; i >= 0; --i) { compressed *= Radix; compressed += (lot0 >> (i * Width)) & Mask; } return compressed; } constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = { TargetFirmware_21_0_0, TargetFirmware_20_0_0, TargetFirmware_19_0_0, TargetFirmware_17_0_0, TargetFirmware_16_0_0, TargetFirmware_15_0_0, TargetFirmware_13_2_1, TargetFirmware_12_0_2, TargetFirmware_11_0_0, TargetFirmware_10_0_0, TargetFirmware_9_1_0, TargetFirmware_9_0_0, TargetFirmware_8_1_0, TargetFirmware_7_0_0, TargetFirmware_6_2_0, TargetFirmware_6_0_0, TargetFirmware_5_0_0, TargetFirmware_4_0_0, TargetFirmware_3_0_2, TargetFirmware_3_0_0, TargetFirmware_2_0_0, TargetFirmware_1_0_0, }; constexpr inline int NumFuseIncrements = util::size(FuseVersionIncrementFirmwares); constexpr const BypassEntry FuseBypassEntries[] = { /* Don't configure any fuse bypass entries. */ }; constexpr inline int NumFuseBypassEntries = util::size(FuseBypassEntries); /* Verify that the fuse version increment list is sorted. */ static_assert([] { for (size_t i = 0; i < util::size(FuseVersionIncrementFirmwares) - 1; ++i) { if (FuseVersionIncrementFirmwares[i] <= FuseVersionIncrementFirmwares[i + 1]) { return false; } } return true; }()); constexpr int GetExpectedFuseVersionImpl(TargetFirmware target_fw) { for (int i = 0; i < NumFuseIncrements; ++i) { if (target_fw >= FuseVersionIncrementFirmwares[i]) { return NumFuseIncrements - i; } } return 0; } static_assert(GetExpectedFuseVersionImpl(TargetFirmware_11_0_0) == 14); static_assert(GetExpectedFuseVersionImpl(TargetFirmware_1_0_0) == 1); static_assert(GetExpectedFuseVersionImpl(static_cast<TargetFirmware>(0)) == 0); } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void SetWriteSecureOnly() { reg::Write(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE)); } void Lockout() { reg::Write(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, ENABLE)); } u32 ReadWord(int address) { /* Require that the fuse array be idle. */ AMS_ABORT_UNLESS(IsIdle()); /* Get the registers. */ volatile auto &FUSE = GetRegisters(); /* Write the address to read. */ reg::Write(FUSE.FUSE_FUSEADDR, address); /* Set control to read. */ reg::ReadWrite(FUSE.FUSE_FUSECTRL, FUSE_REG_BITS_ENUM(FUSECTRL_CMD, READ)); /* Wait 1 us. */ util::WaitMicroSeconds(1); /* Wait for the array to be idle. */ WaitForIdle(); return reg::Read(FUSE.FUSE_FUSERDATA); } u32 GetOdmWord(int index) { return GetOdmWordImpl(index, GetSocType()); } void GetEcid(br::BootEcid *out) { /* Get the registers. */ volatile auto &chip = GetChipRegistersCommon(); /* Read the ecid components. */ const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE) & ((1u << 4) - 1); const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1); const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ; const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1) & ((1u << 28) - 1); const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1); const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1); const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1); const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED) & ((1u << 6) - 1); /* Clear the output. */ util::ClearMemory(out, sizeof(*out)); /* Copy the component bits. */ out->ecid[0] = static_cast<u32>((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved)); out->ecid[1] = static_cast<u32>((lot0 << 26) | (lot1 >> 2)); out->ecid[2] = static_cast<u32>((fab << 26) | (lot0 >> 6)); out->ecid[3] = static_cast<u32>(vendor); } u64 GetDeviceId() { /* Get the registers. */ volatile auto &chip = GetChipRegistersCommon(); /* Read the device id components. */ /* NOTE: Device ID is "basically" just an alternate encoding of Ecid. */ /* It elides lot1 (and compresses lot0), but this is fine because */ /* lot1 is fixed-value for all fused devices. */ const u64 fab = reg::Read(chip.FUSE_OPT_FAB_CODE) & ((1u << 6) - 1); const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0) /* all 32 bits */ ; const u64 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID) & ((1u << 6) - 1); const u64 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE) & ((1u << 9) - 1); const u64 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE) & ((1u << 9) - 1); /* Compress lot0 down from 32-bits to 26. */ const u64 clot0 = CompressLotCode(lot0) & ((1u << 26) - 1); return (y_coord << 0) | (x_coord << 9) | (wafer << 18) | (clot0 << 24) | (fab << 50); } DramId GetDramId() { /* Get the value. */ return static_cast<DramId>(GetDramIdValue(util::BitPack32{GetCommonOdmWord(4)})); } HardwareType GetHardwareType() { /* Read the odm word. */ const util::BitPack32 odm_word4 = { GetCommonOdmWord(4) }; /* Get the value. */ const auto value = GetHardwareTypeValue(odm_word4); switch (value) { case 0x01: return HardwareType_Icosa; case 0x02: return (true /* TODO: GetSocType() == SocType_Mariko */) ? HardwareType_Calcio : HardwareType_Copper; case 0x04: return HardwareType_Iowa; case 0x08: return HardwareType_Hoag; case 0x10: return HardwareType_Aula; default: return HardwareType_Undefined; } } HardwareState GetHardwareState() { /* Read the odm word. */ const util::BitPack32 odm_word4 = { GetCommonOdmWord(4) }; /* Get the value. */ const auto value = GetHardwareStateValue(odm_word4); switch (value) { case 3: return HardwareState_Development; case 4: return HardwareState_Production; default: return HardwareState_Undefined; } } PatchVersion GetPatchVersion() { const auto patch_version = reg::Read(GetChipRegistersCommon().FUSE_SOC_SPEEDO_1_CALIB); return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version); } RetailInteractiveDisplayState GetRetailInteractiveDisplayState() { return static_cast<RetailInteractiveDisplayState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::RetailInteractiveDisplayState>()); } pmic::Regulator GetRegulator() { if (GetSocType() == SocType_Mariko) { /* Read the odm word. */ const util::BitPack32 odm_word28 = { GetOdmWordImpl(28, SocType_Mariko) }; return static_cast<pmic::Regulator>(odm_word28.Get<OdmWord28::Regulator>() + 1); } else /* if (GetSocType() == SocType_Erista) */ { return pmic::Regulator_Erista_Max77621; } } int GetDeviceUniqueKeyGeneration() { if (IsNewFuseFormat()) { return util::BitPack32{GetCommonOdmWord(2)}.Get<OdmWord2::DeviceUniqueKeyGeneration>(); } else { return 0; } } SocType GetSocType() { if (AMS_LIKELY(g_soc_type != SocType_CommonInternal)) { return g_soc_type; } else { switch (GetHardwareType()) { case HardwareType_Icosa: case HardwareType_Copper: g_soc_type = SocType_Erista; break; case HardwareType_Iowa: case HardwareType_Hoag: case HardwareType_Calcio: case HardwareType_Aula: g_soc_type = SocType_Mariko; break; default: g_soc_type = SocType_Undefined; break; } return g_soc_type; } } int GetExpectedFuseVersion(TargetFirmware target_fw) { return GetExpectedFuseVersionImpl(target_fw); } int GetFuseVersion() { return util::PopCount(GetCommonOdmWord(7)); } bool HasRcmVulnerabilityPatch() { /* Only check for RCM bug patch once, and cache our result. */ if (!g_checked_for_rcm_bug_patch) { do { /* Mariko units are necessarily patched. */ if (fuse::GetSocType() != SocType_Erista) { g_has_rcm_bug_patch = true; break; } /* Some patched units use XUSB in RCM. */ if (reg::Read(GetChipRegistersCommon().FUSE_RESERVED_SW) & 0x80) { g_has_rcm_bug_patch = true; break; } /* Other units have a proper ipatch instead. */ u32 word_count = reg::Read(GetChipRegistersCommon().FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; u32 word_addr = 191; while (word_count && !g_has_rcm_bug_patch) { u32 word0 = ReadWord(word_addr); u32 ipatch_count = (word0 >> 16) & 0xF; for (u32 i = 0; i < ipatch_count && !g_has_rcm_bug_patch; ++i) { u32 word = ReadWord(word_addr - (i + 1)); u32 addr = (word >> 16) * 2; if (addr == 0x769a) { g_has_rcm_bug_patch = true; break; } } word_addr -= word_count; word_count = word0 >> 25; } } while (0); g_checked_for_rcm_bug_patch = true; } return g_has_rcm_bug_patch; } bool IsOdmProductionMode() { return reg::HasValue(GetChipRegistersCommon().FUSE_SECURITY_MODE, FUSE_REG_BITS_ENUM(SECURITY_MODE_SECURITY_MODE, ENABLED)); } bool GetSecureBootKey(void *dst) { /* Get the sbk from fuse data. */ bool valid = false; for (size_t i = 0; i < 4; ++i) { const u32 key_word = GetChipRegistersCommon().FUSE_PRIVATE_KEY[i]; static_cast<u32 *>(dst)[i] = key_word; valid |= key_word != 0xFFFFFFFF; } return valid; } void ConfigureFuseBypass() { /* Make the fuse registers visible. */ clkrst::SetFuseVisibility(true); /* Only perform bypass configuration if fuse programming is allowed. */ if (!reg::HasValue(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE))) { return; } /* Enable software writes to fuses. */ reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READWRITE), FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_STATUS, WRITE)); /* Enable fuse bypass. */ reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE)); /* Override fuses. */ for (const auto &entry : FuseBypassEntries) { reg::Write(g_register_address + entry.offset, entry.value); } /* Disable software writes to fuses. */ reg::ReadWrite(GetRegisters().FUSE_WRITE_ACCESS_SW, FUSE_REG_BITS_ENUM(WRITE_ACCESS_SW_CTRL, READONLY)); /* NOTE: Here, NVidia almost certainly intends to *disable* fuse bypass, but they write enable instead... */ reg::Write(GetRegisters().FUSE_FUSEBYPASS, FUSE_REG_BITS_ENUM(FUSEBYPASS_VAL, ENABLE)); /* NOTE: Here, NVidia intends to disable fuse programming. However, they fuck up -- and *clear* the disable bit. */ /* It should be noted that this is a sticky bit, and thus software clears have no effect. */ reg::ReadWrite(GetRegisters().FUSE_DISABLEREGPROGRAM, FUSE_REG_BITS_ENUM(DISABLEREGPROGRAM_VAL, DISABLE)); /* Configure FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT. */ constexpr const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); const bool key_invisible = reg::HasValue(PMC + APBDEV_PMC_SECURE_SCRATCH21, FUSE_REG_BITS_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, KEY_INVISIBLE)); reg::ReadWrite(GetRegisters().FUSE_PRIVATEKEYDISABLE, FUSE_REG_BITS_ENUM_SEL(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, key_invisible, KEY_INVISIBLE, KEY_VISIBLE)); /* Write-lock PMC_SECURE_SCRATCH21. */ reg::ReadWrite(PMC + APBDEV_PMC_SEC_DISABLE2, PMC_REG_BITS_ENUM(SEC_DISABLE2_WRITE21, ON)); } } ================================================ FILE: libraries/libexosphere/source/fuse/fuse_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::fuse { struct FuseRegisters { u32 FUSE_FUSECTRL; u32 FUSE_FUSEADDR; u32 FUSE_FUSERDATA; u32 FUSE_FUSEWDATA; u32 FUSE_FUSETIME_RD1; u32 FUSE_FUSETIME_RD2; u32 FUSE_FUSETIME_PGM1; u32 FUSE_FUSETIME_PGM2; u32 FUSE_PRIV2INTFC_START; u32 FUSE_FUSEBYPASS; u32 FUSE_PRIVATEKEYDISABLE; u32 FUSE_DISABLEREGPROGRAM; u32 FUSE_WRITE_ACCESS_SW; u32 FUSE_PWR_GOOD_SW; u32 _0x38; u32 FUSE_PRIV2RESHIFT; u32 _0x40[0x3]; u32 FUSE_FUSETIME_RD3; u32 _0x50[0xC]; u32 FUSE_PRIVATE_KEY0_NONZERO; u32 FUSE_PRIVATE_KEY1_NONZERO; u32 FUSE_PRIVATE_KEY2_NONZERO; u32 FUSE_PRIVATE_KEY3_NONZERO; u32 FUSE_PRIVATE_KEY4_NONZERO; u32 _0x94; }; static_assert(util::is_pod<FuseRegisters>::value); static_assert(sizeof(FuseRegisters) == 0x98); struct FuseChipRegistersCommon { u32 _0x98[0x1A]; u32 FUSE_PRODUCTION_MODE; u32 FUSE_JTAG_SECUREID_VALID; u32 FUSE_ODM_LOCK; u32 FUSE_OPT_OPENGL_EN; u32 FUSE_SKU_INFO; u32 FUSE_CPU_SPEEDO_0_CALIB; u32 FUSE_CPU_IDDQ_CALIB; u32 _0x11C; u32 _0x120; u32 _0x124; u32 FUSE_OPT_FT_REV; u32 FUSE_CPU_SPEEDO_1_CALIB; u32 FUSE_CPU_SPEEDO_2_CALIB; u32 FUSE_SOC_SPEEDO_0_CALIB; u32 FUSE_SOC_SPEEDO_1_CALIB; u32 FUSE_SOC_SPEEDO_2_CALIB; u32 FUSE_SOC_IDDQ_CALIB; u32 _0x144; u32 FUSE_FA; u32 FUSE_RESERVED_PRODUCTION; u32 FUSE_HDMI_LANE0_CALIB; u32 FUSE_HDMI_LANE1_CALIB; u32 FUSE_HDMI_LANE2_CALIB; u32 FUSE_HDMI_LANE3_CALIB; u32 FUSE_ENCRYPTION_RATE; u32 FUSE_PUBLIC_KEY[0x8]; u32 FUSE_TSENSOR1_CALIB; u32 FUSE_TSENSOR2_CALIB; u32 _0x18C; u32 FUSE_OPT_CP_REV; u32 FUSE_OPT_PFG; u32 FUSE_TSENSOR0_CALIB; u32 FUSE_FIRST_BOOTROM_PATCH_SIZE; u32 FUSE_SECURITY_MODE; u32 FUSE_PRIVATE_KEY[0x5]; u32 FUSE_ARM_JTAG_DIS; u32 FUSE_BOOT_DEVICE_INFO; u32 FUSE_RESERVED_SW; u32 FUSE_OPT_VP9_DISABLE; u32 FUSE_RESERVED_ODM_0[8 - 0]; u32 FUSE_OBS_DIS; u32 _0x1EC; u32 FUSE_USB_CALIB; u32 FUSE_SKU_DIRECT_CONFIG; u32 FUSE_KFUSE_PRIVKEY_CTRL; u32 FUSE_PACKAGE_INFO; u32 FUSE_OPT_VENDOR_CODE; u32 FUSE_OPT_FAB_CODE; u32 FUSE_OPT_LOT_CODE_0; u32 FUSE_OPT_LOT_CODE_1; u32 FUSE_OPT_WAFER_ID; u32 FUSE_OPT_X_COORDINATE; u32 FUSE_OPT_Y_COORDINATE; u32 FUSE_OPT_SEC_DEBUG_EN; u32 FUSE_OPT_OPS_RESERVED; u32 _0x224; u32 FUSE_GPU_IDDQ_CALIB; u32 FUSE_TSENSOR3_CALIB; u32 _0x234; u32 _0x238; u32 _0x23C; u32 _0x240; u32 _0x244; u32 FUSE_OPT_SAMPLE_TYPE; u32 FUSE_OPT_SUBREVISION; u32 FUSE_OPT_SW_RESERVED_0; u32 FUSE_OPT_SW_RESERVED_1; u32 FUSE_TSENSOR4_CALIB; u32 FUSE_TSENSOR5_CALIB; u32 FUSE_TSENSOR6_CALIB; u32 FUSE_TSENSOR7_CALIB; u32 FUSE_OPT_PRIV_SEC_EN; u32 _0x268; u32 _0x26C; u32 _0x270; u32 _0x274; u32 _0x278; u32 FUSE_FUSE2TSEC_DEBUG_DISABLE; u32 FUSE_TSENSOR_COMMON; u32 FUSE_OPT_CP_BIN; u32 FUSE_OPT_GPU_DISABLE; u32 FUSE_OPT_FT_BIN; u32 FUSE_OPT_DONE_MAP; u32 _0x294; u32 FUSE_APB2JTAG_DISABLE; u32 FUSE_ODM_INFO; u32 _0x2A0; u32 _0x2A4; u32 FUSE_ARM_CRYPT_DE_FEATURE; u32 _0x2AC; u32 _0x2B0; u32 _0x2B4; u32 _0x2B8; u32 _0x2BC; u32 FUSE_WOA_SKU_FLAG; u32 FUSE_ECO_RESERVE_1; u32 FUSE_GCPLEX_CONFIG_FUSE; u32 FUSE_PRODUCTION_MONTH; u32 FUSE_RAM_REPAIR_INDICATOR; u32 FUSE_TSENSOR9_CALIB; u32 _0x2D8; u32 FUSE_VMIN_CALIBRATION; u32 FUSE_AGING_SENSOR_CALIBRATION; u32 FUSE_DEBUG_AUTHENTICATION; u32 FUSE_SECURE_PROVISION_INDEX; u32 FUSE_SECURE_PROVISION_INFO; u32 FUSE_OPT_GPU_DISABLE_CP1; u32 FUSE_SPARE_ENDIS; u32 FUSE_ECO_RESERVE_0; u32 _0x2FC; u32 _0x300; u32 FUSE_RESERVED_CALIB0; u32 FUSE_RESERVED_CALIB1; u32 FUSE_OPT_GPU_TPC0_DISABLE; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1; u32 FUSE_OPT_CPU_DISABLE; u32 FUSE_OPT_CPU_DISABLE_CP1; u32 FUSE_TSENSOR10_CALIB; u32 FUSE_TSENSOR10_CALIB_AUX; u32 _0x324; u32 _0x328; u32 _0x32C; u32 _0x330; u32 _0x334; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2; u32 FUSE_OPT_GPU_TPC1_DISABLE; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2; u32 FUSE_OPT_CPU_DISABLE_CP2; u32 FUSE_OPT_GPU_DISABLE_CP2; u32 FUSE_USB_CALIB_EXT; u32 FUSE_RESERVED_FIELD; u32 _0x358; u32 _0x35C; u32 _0x360; u32 _0x364; u32 _0x368; u32 _0x36C; u32 _0x370; u32 _0x374; u32 _0x378; u32 FUSE_SPARE_REALIGNMENT_REG; u32 FUSE_SPARE_BIT[0x20]; }; static_assert(util::is_pod<FuseChipRegistersCommon>::value); static_assert(sizeof(FuseChipRegistersCommon) == 0x400 - 0x98); struct FuseChipRegistersErista { u32 _0x98[0x1A]; u32 FUSE_PRODUCTION_MODE; u32 FUSE_JTAG_SECUREID_VALID; u32 FUSE_ODM_LOCK; u32 FUSE_OPT_OPENGL_EN; u32 FUSE_SKU_INFO; u32 FUSE_CPU_SPEEDO_0_CALIB; u32 FUSE_CPU_IDDQ_CALIB; u32 FUSE_DAC_CRT_CALIB; u32 FUSE_DAC_HDTV_CALIB; u32 FUSE_DAC_SDTV_CALIB; u32 FUSE_OPT_FT_REV; u32 FUSE_CPU_SPEEDO_1_CALIB; u32 FUSE_CPU_SPEEDO_2_CALIB; u32 FUSE_SOC_SPEEDO_0_CALIB; u32 FUSE_SOC_SPEEDO_1_CALIB; u32 FUSE_SOC_SPEEDO_2_CALIB; u32 FUSE_SOC_IDDQ_CALIB; u32 FUSE_RESERVED_PRODUCTION_WP; u32 FUSE_FA; u32 FUSE_RESERVED_PRODUCTION; u32 FUSE_HDMI_LANE0_CALIB; u32 FUSE_HDMI_LANE1_CALIB; u32 FUSE_HDMI_LANE2_CALIB; u32 FUSE_HDMI_LANE3_CALIB; u32 FUSE_ENCRYPTION_RATE; u32 FUSE_PUBLIC_KEY[0x8]; u32 FUSE_TSENSOR1_CALIB; u32 FUSE_TSENSOR2_CALIB; u32 FUSE_VSENSOR_CALIB; u32 FUSE_OPT_CP_REV; u32 FUSE_OPT_PFG; u32 FUSE_TSENSOR0_CALIB; u32 FUSE_FIRST_BOOTROM_PATCH_SIZE; u32 FUSE_SECURITY_MODE; u32 FUSE_PRIVATE_KEY[0x5]; u32 FUSE_ARM_JTAG_DIS; u32 FUSE_BOOT_DEVICE_INFO; u32 FUSE_RESERVED_SW; u32 FUSE_OPT_VP9_DISABLE; u32 FUSE_RESERVED_ODM_0[8 - 0]; u32 FUSE_OBS_DIS; u32 FUSE_NOR_INFO; u32 FUSE_USB_CALIB; u32 FUSE_SKU_DIRECT_CONFIG; u32 FUSE_KFUSE_PRIVKEY_CTRL; u32 FUSE_PACKAGE_INFO; u32 FUSE_OPT_VENDOR_CODE; u32 FUSE_OPT_FAB_CODE; u32 FUSE_OPT_LOT_CODE_0; u32 FUSE_OPT_LOT_CODE_1; u32 FUSE_OPT_WAFER_ID; u32 FUSE_OPT_X_COORDINATE; u32 FUSE_OPT_Y_COORDINATE; u32 FUSE_OPT_SEC_DEBUG_EN; u32 FUSE_OPT_OPS_RESERVED; u32 FUSE_SATA_CALIB; u32 FUSE_GPU_IDDQ_CALIB; u32 FUSE_TSENSOR3_CALIB; u32 FUSE_SKU_BOND_OUT_L; u32 FUSE_SKU_BOND_OUT_H; u32 FUSE_SKU_BOND_OUT_U; u32 FUSE_SKU_BOND_OUT_V; u32 FUSE_SKU_BOND_OUT_W; u32 FUSE_OPT_SAMPLE_TYPE; u32 FUSE_OPT_SUBREVISION; u32 FUSE_OPT_SW_RESERVED_0; u32 FUSE_OPT_SW_RESERVED_1; u32 FUSE_TSENSOR4_CALIB; u32 FUSE_TSENSOR5_CALIB; u32 FUSE_TSENSOR6_CALIB; u32 FUSE_TSENSOR7_CALIB; u32 FUSE_OPT_PRIV_SEC_EN; u32 FUSE_PKC_DISABLE; u32 _0x26C; u32 _0x270; u32 _0x274; u32 _0x278; u32 FUSE_FUSE2TSEC_DEBUG_DISABLE; u32 FUSE_TSENSOR_COMMON; u32 FUSE_OPT_CP_BIN; u32 FUSE_OPT_GPU_DISABLE; u32 FUSE_OPT_FT_BIN; u32 FUSE_OPT_DONE_MAP; u32 _0x294; u32 FUSE_APB2JTAG_DISABLE; u32 FUSE_ODM_INFO; u32 _0x2A0; u32 _0x2A4; u32 FUSE_ARM_CRYPT_DE_FEATURE; u32 _0x2AC; u32 _0x2B0; u32 _0x2B4; u32 _0x2B8; u32 _0x2BC; u32 FUSE_WOA_SKU_FLAG; u32 FUSE_ECO_RESERVE_1; u32 FUSE_GCPLEX_CONFIG_FUSE; u32 FUSE_PRODUCTION_MONTH; u32 FUSE_RAM_REPAIR_INDICATOR; u32 FUSE_TSENSOR9_CALIB; u32 _0x2D8; u32 FUSE_VMIN_CALIBRATION; u32 FUSE_AGING_SENSOR_CALIBRATION; u32 FUSE_DEBUG_AUTHENTICATION; u32 FUSE_SECURE_PROVISION_INDEX; u32 FUSE_SECURE_PROVISION_INFO; u32 FUSE_OPT_GPU_DISABLE_CP1; u32 FUSE_SPARE_ENDIS; u32 FUSE_ECO_RESERVE_0; u32 _0x2FC; u32 _0x300; u32 FUSE_RESERVED_CALIB0; u32 FUSE_RESERVED_CALIB1; u32 FUSE_OPT_GPU_TPC0_DISABLE; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1; u32 FUSE_OPT_CPU_DISABLE; u32 FUSE_OPT_CPU_DISABLE_CP1; u32 FUSE_TSENSOR10_CALIB; u32 FUSE_TSENSOR10_CALIB_AUX; u32 FUSE_OPT_RAM_SVOP_DP; u32 FUSE_OPT_RAM_SVOP_PDP; u32 FUSE_OPT_RAM_SVOP_REG; u32 FUSE_OPT_RAM_SVOP_SP; u32 FUSE_OPT_RAM_SVOP_SMPDP; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2; u32 FUSE_OPT_GPU_TPC1_DISABLE; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2; u32 FUSE_OPT_CPU_DISABLE_CP2; u32 FUSE_OPT_GPU_DISABLE_CP2; u32 FUSE_USB_CALIB_EXT; u32 FUSE_RESERVED_FIELD; u32 FUSE_OPT_ECC_EN; u32 _0x35C; u32 _0x360; u32 _0x364; u32 _0x368; u32 _0x36C; u32 _0x370; u32 _0x374; u32 _0x378; u32 FUSE_SPARE_REALIGNMENT_REG; u32 FUSE_SPARE_BIT[0x20]; }; static_assert(util::is_pod<FuseChipRegistersErista>::value); static_assert(sizeof(FuseChipRegistersErista) == 0x400 - 0x98); struct FuseChipRegistersMariko { u32 FUSE_RESERVED_ODM_8[22 - 8]; u32 FUSE_KEK[4]; u32 FUSE_BEK[4]; u32 _0xF0[4]; u32 FUSE_PRODUCTION_MODE; u32 FUSE_JTAG_SECUREID_VALID; u32 FUSE_ODM_LOCK; u32 FUSE_OPT_OPENGL_EN; u32 FUSE_SKU_INFO; u32 FUSE_CPU_SPEEDO_0_CALIB; u32 FUSE_CPU_IDDQ_CALIB; u32 FUSE_RESERVED_ODM_22[25 - 22]; u32 FUSE_OPT_FT_REV; u32 FUSE_CPU_SPEEDO_1_CALIB; u32 FUSE_CPU_SPEEDO_2_CALIB; u32 FUSE_SOC_SPEEDO_0_CALIB; u32 FUSE_SOC_SPEEDO_1_CALIB; u32 FUSE_SOC_SPEEDO_2_CALIB; u32 FUSE_SOC_IDDQ_CALIB; u32 FUSE_RESERVED_ODM_25[26 - 25]; u32 FUSE_FA; u32 FUSE_RESERVED_PRODUCTION; u32 FUSE_HDMI_LANE0_CALIB; u32 FUSE_HDMI_LANE1_CALIB; u32 FUSE_HDMI_LANE2_CALIB; u32 FUSE_HDMI_LANE3_CALIB; u32 FUSE_ENCRYPTION_RATE; u32 FUSE_PUBLIC_KEY[0x8]; u32 FUSE_TSENSOR1_CALIB; u32 FUSE_TSENSOR2_CALIB; u32 FUSE_OPT_SECURE_SCC_DIS; u32 FUSE_OPT_CP_REV; u32 FUSE_OPT_PFG; u32 FUSE_TSENSOR0_CALIB; u32 FUSE_FIRST_BOOTROM_PATCH_SIZE; u32 FUSE_SECURITY_MODE; u32 FUSE_PRIVATE_KEY[0x5]; u32 FUSE_ARM_JTAG_DIS; u32 FUSE_BOOT_DEVICE_INFO; u32 FUSE_RESERVED_SW; u32 FUSE_OPT_VP9_DISABLE; u32 FUSE_RESERVED_ODM_0[8 - 0]; u32 FUSE_OBS_DIS; u32 _0x1EC; u32 FUSE_USB_CALIB; u32 FUSE_SKU_DIRECT_CONFIG; u32 FUSE_KFUSE_PRIVKEY_CTRL; u32 FUSE_PACKAGE_INFO; u32 FUSE_OPT_VENDOR_CODE; u32 FUSE_OPT_FAB_CODE; u32 FUSE_OPT_LOT_CODE_0; u32 FUSE_OPT_LOT_CODE_1; u32 FUSE_OPT_WAFER_ID; u32 FUSE_OPT_X_COORDINATE; u32 FUSE_OPT_Y_COORDINATE; u32 FUSE_OPT_SEC_DEBUG_EN; u32 FUSE_OPT_OPS_RESERVED; u32 _0x224; u32 FUSE_GPU_IDDQ_CALIB; u32 FUSE_TSENSOR3_CALIB; u32 FUSE_CLOCK_BONDOUT0; u32 FUSE_CLOCK_BONDOUT1; u32 FUSE_RESERVED_ODM_26[29 - 26]; u32 FUSE_OPT_SAMPLE_TYPE; u32 FUSE_OPT_SUBREVISION; u32 FUSE_OPT_SW_RESERVED_0; u32 FUSE_OPT_SW_RESERVED_1; u32 FUSE_TSENSOR4_CALIB; u32 FUSE_TSENSOR5_CALIB; u32 FUSE_TSENSOR6_CALIB; u32 FUSE_TSENSOR7_CALIB; u32 FUSE_OPT_PRIV_SEC_EN; u32 FUSE_BOOT_SECURITY_INFO; u32 _0x26C; u32 _0x270; u32 _0x274; u32 _0x278; u32 FUSE_FUSE2TSEC_DEBUG_DISABLE; u32 FUSE_TSENSOR_COMMON; u32 FUSE_OPT_CP_BIN; u32 FUSE_OPT_GPU_DISABLE; u32 FUSE_OPT_FT_BIN; u32 FUSE_OPT_DONE_MAP; u32 FUSE_RESERVED_ODM_29[30 - 29]; u32 FUSE_APB2JTAG_DISABLE; u32 FUSE_ODM_INFO; u32 _0x2A0; u32 _0x2A4; u32 FUSE_ARM_CRYPT_DE_FEATURE; u32 _0x2AC; u32 _0x2B0; u32 _0x2B4; u32 _0x2B8; u32 _0x2BC; u32 FUSE_WOA_SKU_FLAG; u32 FUSE_ECO_RESERVE_1; u32 FUSE_GCPLEX_CONFIG_FUSE; u32 FUSE_PRODUCTION_MONTH; u32 FUSE_RAM_REPAIR_INDICATOR; u32 FUSE_TSENSOR9_CALIB; u32 _0x2D8; u32 FUSE_VMIN_CALIBRATION; u32 FUSE_AGING_SENSOR_CALIBRATION; u32 FUSE_DEBUG_AUTHENTICATION; u32 FUSE_SECURE_PROVISION_INDEX; u32 FUSE_SECURE_PROVISION_INFO; u32 FUSE_OPT_GPU_DISABLE_CP1; u32 FUSE_SPARE_ENDIS; u32 FUSE_ECO_RESERVE_0; u32 _0x2FC; u32 _0x300; u32 FUSE_RESERVED_CALIB0; u32 FUSE_RESERVED_CALIB1; u32 FUSE_OPT_GPU_TPC0_DISABLE; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP1; u32 FUSE_OPT_CPU_DISABLE; u32 FUSE_OPT_CPU_DISABLE_CP1; u32 FUSE_TSENSOR10_CALIB; u32 FUSE_TSENSOR10_CALIB_AUX; u32 _0x324; u32 _0x328; u32 _0x32C; u32 _0x330; u32 _0x334; u32 FUSE_OPT_GPU_TPC0_DISABLE_CP2; u32 FUSE_OPT_GPU_TPC1_DISABLE; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP1; u32 FUSE_OPT_GPU_TPC1_DISABLE_CP2; u32 FUSE_OPT_CPU_DISABLE_CP2; u32 FUSE_OPT_GPU_DISABLE_CP2; u32 FUSE_USB_CALIB_EXT; u32 FUSE_RESERVED_FIELD; u32 _0x358; u32 _0x35C; u32 _0x360; u32 _0x364; u32 _0x368; u32 _0x36C; u32 _0x370; u32 _0x374; u32 _0x378; u32 FUSE_SPARE_REALIGNMENT_REG; u32 FUSE_SPARE_BIT[0x20]; }; static_assert(util::is_pod<FuseChipRegistersMariko>::value); static_assert(sizeof(FuseChipRegistersMariko) == 0x400 - 0x98); struct FuseRegisterRegion { FuseRegisters fuse; union { FuseChipRegistersCommon chip_common; FuseChipRegistersErista chip_erista; FuseChipRegistersMariko chip_mariko; }; }; static_assert(util::is_pod<FuseRegisterRegion>::value); static_assert(sizeof(FuseRegisterRegion) == secmon::MemoryRegionPhysicalDeviceFuses.GetSize()); #define FUSE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (FUSE, NAME) #define FUSE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (FUSE, NAME, VALUE) #define FUSE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (FUSE, NAME, ENUM) #define FUSE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(FUSE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) #define DEFINE_FUSE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (FUSE, NAME, __OFFSET__, __WIDTH__) #define DEFINE_FUSE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE) #define DEFINE_FUSE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) #define DEFINE_FUSE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) #define DEFINE_FUSE_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (FUSE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) DEFINE_FUSE_REG_TWO_BIT_ENUM(FUSECTRL_CMD, 0, IDLE, READ, WRITE, SENSE_CTRL); DEFINE_FUSE_REG(FUSECTRL_STATE, 16, 5); enum FUSE_FUSECTRL_STATE { FUSE_FUSECTRL_STATE_RESET = 0, FUSE_FUSECTRL_STATE_POST_RESET = 1, FUSE_FUSECTRL_STATE_LOAD_ROW0 = 2, FUSE_FUSECTRL_STATE_LOAD_ROW1 = 3, FUSE_FUSECTRL_STATE_IDLE = 4, FUSE_FUSECTRL_STATE_READ_SETUP = 5, FUSE_FUSECTRL_STATE_READ_STROBE = 6, FUSE_FUSECTRL_STATE_SAMPLE_FUSES = 7, FUSE_FUSECTRL_STATE_READ_HOLD = 8, FUSE_FUSECTRL_STATE_FUSE_SRC_SETUP = 9, FUSE_FUSECTRL_STATE_WRITE_SETUP = 10, FUSE_FUSECTRL_STATE_WRITE_ADDR_SETUP = 11, FUSE_FUSECTRL_STATE_WRITE_PROGRAM = 12, FUSE_FUSECTRL_STATE_WRITE_ADDR_HOLD = 13, FUSE_FUSECTRL_STATE_FUSE_SRC_HOLD = 14, FUSE_FUSECTRL_STATE_LOAD_RIR = 15, FUSE_FUSECTRL_STATE_READ_BEFORE_WRITE_SETUP = 16, FUSE_FUSECTRL_STATE_READ_DEASSERT_PD = 17, }; DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_TZ_STICKY_BIT_VAL, 4, KEY_VISIBLE, KEY_INVISIBLE); DEFINE_FUSE_REG_BIT_ENUM(PRIVATEKEYDISABLE_PRIVATEKEYDISABLE_VAL_KEY, 0, VISIBLE, INVISIBLE); DEFINE_FUSE_REG_BIT_ENUM(FUSEBYPASS_VAL, 0, DISABLE, ENABLE); DEFINE_FUSE_REG_BIT_ENUM(DISABLEREGPROGRAM_VAL, 0, DISABLE, ENABLE); DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_CTRL, 0, READWRITE, READONLY); DEFINE_FUSE_REG_BIT_ENUM(WRITE_ACCESS_SW_STATUS, 16, NOWRITE, WRITE); DEFINE_FUSE_REG_BIT_ENUM(SECURITY_MODE_SECURITY_MODE, 0, DISABLED, ENABLED); } ================================================ FILE: libraries/libexosphere/source/gic/gic_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::gic { namespace { struct GicDistributor { u32 ctlr; u32 typer; u32 iidr; u32 reserved_0x0c; u32 statusr; u32 reserved_0x14[3]; u32 impldef_0x20[8]; u32 setspi_nsr; u32 reserved_0x44; u32 clrspi_nsr; u32 reserved_0x4c; u32 setspi_sr; u32 reserved_0x54; u32 clrspi_sr; u32 reserved_0x5c[9]; u32 igroupr[32]; u32 isenabler[32]; u32 icenabler[32]; u32 ispendr[32]; u32 icpendr[32]; u32 isactiver[32]; u32 icactiver[32]; union { u8 bytes[1020]; u32 words[255]; } ipriorityr; u32 _0x7fc; union { u8 bytes[1020]; u32 words[255]; } itargetsr; u32 _0xbfc; u32 icfgr[64]; u32 igrpmodr[32]; u32 _0xd80[32]; u32 nsacr[64]; u32 sgir; u32 _0xf04[3]; u32 cpendsgir[4]; u32 spendsgir[4]; u32 reserved_0xf30[52]; static constexpr size_t SgirCpuTargetListShift = 16; enum SgirTargetListFilter : u32 { SgirTargetListFilter_CpuTargetList = (0 << 24), SgirTargetListFilter_Others = (1 << 24), SgirTargetListFilter_Self = (2 << 24), SgirTargetListFilter_Reserved = (3 << 24), }; }; static_assert(util::is_pod<GicDistributor>::value); static_assert(sizeof(GicDistributor) == 0x1000); static_assert(sizeof(GicDistributor) == secmon::MemoryRegionPhysicalDeviceGicDistributor.GetSize()); struct GicCpuInterface { u32 ctlr; u32 pmr; u32 bpr; u32 iar; u32 eoir; u32 rpr; u32 hppir; u32 abpr; u32 aiar; u32 aeoir; u32 ahppir; u32 statusr; u32 reserved_30[4]; u32 impldef_40[36]; u32 apr[4]; u32 nsapr[4]; u32 reserved_f0[3]; u32 iidr; u32 reserved_100[960]; u32 dir; u32 _0x1004[1023]; }; static_assert(util::is_pod<GicCpuInterface>::value); static_assert(sizeof(GicCpuInterface) == 0x2000); static_assert(sizeof(GicCpuInterface) == secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetSize()); constexpr inline int InterruptWords = InterruptCount / BITSIZEOF(u32); constexpr inline int SpiIndex = BITSIZEOF(u32); constinit uintptr_t g_distributor_address = secmon::MemoryRegionPhysicalDeviceGicDistributor.GetAddress(); constinit uintptr_t g_cpu_interface_address = secmon::MemoryRegionPhysicalDeviceGicCpuInterface.GetAddress(); volatile GicDistributor *GetDistributor() { return reinterpret_cast<volatile GicDistributor *>(g_distributor_address); } volatile GicCpuInterface *GetCpuInterface() { return reinterpret_cast<volatile GicCpuInterface *>(g_cpu_interface_address); } void ReadWrite(uintptr_t address, int width, int i, u32 value) { /* This code will never be invoked with a negative interrupt id. */ AMS_ASSUME(i >= 0); const int scale = BITSIZEOF(u32) / width; const int word = i / scale; const int bit = (i % scale) * width; const u32 mask = ((1u << width) - 1) << bit; const uintptr_t reg_addr = address + sizeof(u32) * word; const u32 old = reg::Read(reg_addr) & ~mask; reg::Write(reg_addr, old | ((value << bit) & mask)); } void Write(uintptr_t address, int width, int i, u32 value) { /* This code will never be invoked with a negative interrupt id. */ AMS_ASSUME(i >= 0); const int scale = BITSIZEOF(u32) / width; const int word = i / scale; const int bit = (i % scale) * width; reg::Write(address + sizeof(u32) * word, value << bit); } } void SetRegisterAddress(uintptr_t distributor_address, uintptr_t cpu_interface_address) { g_distributor_address = distributor_address; g_cpu_interface_address = cpu_interface_address; } void InitializeCommon() { /* Get the gicd registers. */ auto *gicd = GetDistributor(); /* Set IGROUPR for to be FFs. */ for (int i = SpiIndex / BITSIZEOF(u32); i < InterruptWords; ++i) { gicd->igroupr[i] = 0xFFFFFFFFu; } /* Set IPRIORITYR for spi interrupts to be 0x80. */ for (int i = SpiIndex; i < InterruptCount; ++i) { gicd->ipriorityr.bytes[i] = 0x80; } /* Enable group 0. */ gicd->ctlr = 1; } void InitializeCoreUnique() { /* Get the registers. */ auto *gicd = GetDistributor(); auto *gicc = GetCpuInterface(); /* Set IGROUPR0 to be FFs. */ gicd->igroupr[0] = 0xFFFFFFFFu; /* Set IPRIORITYR for core local interrupts to be 0x80. */ for (int i = 0; i < SpiIndex; ++i) { gicd->ipriorityr.bytes[i] = 0x80; } /* Enable group 0 as FIQs. */ gicc->ctlr = 0x1D9; /* Set PMR. */ gicc->pmr = 0x80; /* Set BPR. */ gicc->bpr = 7; } void SetPriority(int interrupt_id, int priority) { ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, ipriorityr), BITSIZEOF(u8), interrupt_id, priority); } void SetInterruptGroup(int interrupt_id, int group) { ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, igroupr), 1, interrupt_id, group); } void SetEnable(int interrupt_id, bool enable) { Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, isenabler), 1, interrupt_id, enable); } void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask) { ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, itargetsr), BITSIZEOF(u8), interrupt_id, cpu_mask); } void SetSpiMode(int interrupt_id, InterruptMode mode) { ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, icfgr), 2, interrupt_id, static_cast<u32>(mode) << 1); } void SetPending(int interrupt_id) { Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, ispendr), 1, interrupt_id, 1); } int GetInterruptRequestId() { return reg::Read(GetCpuInterface()->iar); } void SetEndOfInterrupt(int interrupt_id) { reg::Write(GetCpuInterface()->eoir, interrupt_id); } } ================================================ FILE: libraries/libexosphere/source/hw/hw_cache.arch.arm.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::hw::arch::arm { #ifdef __BPMP__ namespace { constexpr inline uintptr_t AVP_CACHE = AVP_CACHE_ADDR(0); ALWAYS_INLINE bool IsLargeBuffer(size_t size) { /* From TRM: For very large physical buffers or when the full cache needs to be cleared, */ /* software should simply loop over all lines in all ways and run the *_LINE command on each of them. */ return size >= DataCacheSize / 4; } ALWAYS_INLINE bool IsCacheEnabled() { return reg::HasValue(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, TRUE)); } void DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE op, uintptr_t addr) { /* Clear maintenance done. */ reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, AVP_CACHE_REG_BITS_ENUM(INT_CLEAR_MAINTENANCE_DONE, TRUE)); /* Write maintenance address. */ reg::Write(AVP_CACHE + AVP_CACHE_MAINT_0, addr); /* Write maintenance request. */ reg::Write(AVP_CACHE + AVP_CACHE_MAINT_2, AVP_CACHE_REG_BITS_VALUE(MAINT_2_WAY_BITMAP, 0x0), AVP_CACHE_REG_BITS_VALUE(MAINT_2_OPCODE, op)); /* Wait for maintenance to be done. */ while (!reg::HasValue(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT, AVP_CACHE_REG_BITS_ENUM(INT_RAW_EVENT_MAINTENANCE_DONE, TRUE))) { /* ... */ } /* Clear raw event. */ reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, reg::Read(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT)); } void DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE op) { /* Clear maintenance done. */ reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, AVP_CACHE_REG_BITS_ENUM(INT_CLEAR_MAINTENANCE_DONE, TRUE)); /* Write maintenance request. */ reg::Write(AVP_CACHE + AVP_CACHE_MAINT_2, AVP_CACHE_REG_BITS_VALUE(MAINT_2_WAY_BITMAP, 0xF), AVP_CACHE_REG_BITS_VALUE(MAINT_2_OPCODE, op)); /* Wait for maintenance to be done. */ while (!reg::HasValue(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT, AVP_CACHE_REG_BITS_ENUM(INT_RAW_EVENT_MAINTENANCE_DONE, TRUE))) { /* ... */ } /* Clear raw event. */ reg::Write(AVP_CACHE + AVP_CACHE_INT_CLEAR, reg::Read(AVP_CACHE + AVP_CACHE_INT_RAW_EVENT)); } } #define REQUIRE_CACHE_ENABLED() \ do { \ if (AMS_UNLIKELY(!IsCacheEnabled())) { \ return; \ } \ } while (false) \ #define REQUIRE_CACHE_DISABLED() \ do { \ if (AMS_UNLIKELY(IsCacheEnabled())) { \ return; \ } \ } while (false) \ void InitializeDataCache() { REQUIRE_CACHE_DISABLED(); /* Issue init mmu command. */ reg::Write(AVP_CACHE + AVP_CACHE_MMU_CMD, AVP_CACHE_REG_BITS_ENUM(MMU_CMD_CMD, INIT)); /* Set mmu fallback entry as RWX, uncached. */ reg::Write(AVP_CACHE + AVP_CACHE_MMU_FALLBACK_ENTRY, AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_WR_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_RD_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_EXE_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(MMU_FALLBACK_ENTRY_CACHED, DISABLE)); /* Set mmu cfg. */ reg::Write(AVP_CACHE + AVP_CACHE_MMU_CFG, AVP_CACHE_REG_BITS_ENUM(MMU_CFG_CLR_ABORT, NOP), AVP_CACHE_REG_BITS_ENUM(MMU_CFG_ABORT_MODE, STORE_LAST), AVP_CACHE_REG_BITS_ENUM(MMU_CFG_SEQ_CHECK_ALL_ENTRIES, DISABLE), AVP_CACHE_REG_BITS_ENUM(MMU_CFG_TLB_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(MMU_CFG_SEQ_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(MMU_CFG_BLOCK_MAIN_ENTRY_WR, DISABLE)); /* Initialize mmu entries. */ { /* Clear shadow copy mask. */ reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, 0); /* Add DRAM as index 0, RWX/Cached. */ { reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_MIN_ADDR, 0x80000000); reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_MAX_ADDR, util::AlignDown(0xFFFFFFFF, DataCacheLineSize)); reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_0_CFG, AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_WR_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_RD_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_EXE_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_CACHED, ENABLE)); reg::SetBits(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, (1 << 0)); } /* Add IRAM as index 1, RWX/Cached. */ { reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_MIN_ADDR, 0x40000000); reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_MAX_ADDR, util::AlignDown(0x4003FFFF, DataCacheLineSize)); reg::Write(AVP_CACHE + AVP_CACHE_MMU_SHADOW_ENTRY_1_CFG, AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_WR_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_RD_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_EXE_ENA, ENABLE), AVP_CACHE_REG_BITS_ENUM(SHADOW_ENTRY_CFG_CACHED, ENABLE)); reg::SetBits(AVP_CACHE + AVP_CACHE_MMU_SHADOW_COPY_MASK_0, (1 << 1)); } /* Issue copy shadow mmu command. */ reg::Write(AVP_CACHE + AVP_CACHE_MMU_CMD, AVP_CACHE_REG_BITS_ENUM(MMU_CMD_CMD, COPY_SHADOW)); } /* Invalidate entire cache. */ DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY); /* Enable the cache. */ reg::Write(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, TRUE), AVP_CACHE_REG_BITS_ENUM(CONFIG_FORCE_WRITE_THROUGH, TRUE), AVP_CACHE_REG_BITS_ENUM(CONFIG_MMU_TAG_MODE, PARALLEL), AVP_CACHE_REG_BITS_ENUM(CONFIG_TAG_CHECK_ABORT_ON_ERROR, TRUE)); /* Invalidate entire cache again (WAR for hardware bug). */ DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY); } void FinalizeDataCache() { REQUIRE_CACHE_ENABLED(); /* Flush entire data cache. */ FlushEntireDataCache(); /* Disable cache. */ reg::Write(AVP_CACHE + AVP_CACHE_CONFIG, AVP_CACHE_REG_BITS_ENUM(CONFIG_ENABLE_CACHE, FALSE)); } void InvalidateEntireDataCache() { REQUIRE_CACHE_ENABLED(); DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_WAY); } void StoreEntireDataCache() { REQUIRE_CACHE_ENABLED(); DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_WAY); } void FlushEntireDataCache() { REQUIRE_CACHE_ENABLED(); DoEntireCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_INVALID_WAY); } void InvalidateDataCacheLine(void *ptr) { /* NOTE: Don't check cache enabled as an optimization, as only direct caller will be InvalidateDataCache(). */ /* REQUIRE_CACHE_ENABLED(); */ DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_INVALID_PHY, reinterpret_cast<uintptr_t>(ptr)); } void StoreDataCacheLine(void *ptr) { /* NOTE: Don't check cache enabled as an optimization, as only direct caller will be FlushDataCache(). */ /* REQUIRE_CACHE_ENABLED(); */ DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_PHY, reinterpret_cast<uintptr_t>(ptr)); } void FlushDataCacheLine(void *ptr) { /* NOTE: Don't check cache enabled as an optimization, as only direct caller will be FlushDataCache(). */ /* REQUIRE_CACHE_ENABLED(); */ DoPhyCacheOperation(AVP_CACHE_MAINT_OPCODE_CLEAN_INVALID_PHY, reinterpret_cast<uintptr_t>(ptr)); } void InvalidateDataCache(void *ptr, size_t size) { REQUIRE_CACHE_ENABLED(); if (IsLargeBuffer(size)) { InvalidateEntireDataCache(); } else { const uintptr_t start = reinterpret_cast<uintptr_t>(ptr); const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { InvalidateDataCacheLine(reinterpret_cast<void *>(cur)); } } } void StoreDataCache(const void *ptr, size_t size) { REQUIRE_CACHE_ENABLED(); if (IsLargeBuffer(size)) { StoreEntireDataCache(); } else { const uintptr_t start = reinterpret_cast<uintptr_t>(ptr); const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { StoreDataCacheLine(reinterpret_cast<void *>(cur)); } } } void FlushDataCache(const void *ptr, size_t size) { REQUIRE_CACHE_ENABLED(); if (IsLargeBuffer(size)) { FlushEntireDataCache(); } else { const uintptr_t start = reinterpret_cast<uintptr_t>(ptr); const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { FlushDataCacheLine(reinterpret_cast<void *>(cur)); } } } #endif } ================================================ FILE: libraries/libexosphere/source/hw/hw_cache.arch.arm64.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::hw::arch::arm64 { void FlushDataCache(const void *ptr, size_t size) { const uintptr_t start = reinterpret_cast<uintptr_t>(ptr); const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { FlushDataCacheLine(reinterpret_cast<void *>(cur)); } } void InvalidateDataCache(const void *ptr, size_t size) { const uintptr_t start = reinterpret_cast<uintptr_t>(ptr); const uintptr_t end = util::AlignUp(start + size, hw::DataCacheLineSize); for (uintptr_t cur = start; cur < end; cur += hw::DataCacheLineSize) { InvalidateDataCacheLine(reinterpret_cast<void *>(cur)); } } } ================================================ FILE: libraries/libexosphere/source/i2c/i2c_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::i2c { namespace { constexpr inline size_t MaxTransferSize = sizeof(u32); constinit std::array<uintptr_t, Port_Count> g_register_addresses = [] { std::array<uintptr_t, Port_Count> arr = {}; arr[Port_1] = secmon::MemoryRegionPhysicalDeviceI2c1.GetAddress(); arr[Port_5] = secmon::MemoryRegionPhysicalDeviceI2c5.GetAddress(); return arr; }(); void LoadConfig(uintptr_t address) { /* Configure for TIMEOUT and MSTR config load. */ /* NOTE: Nintendo writes value 1 to reserved bit 5 here. This bit is documented as having no meaning. */ /* We will reproduce the write just in case it is undocumented. */ reg::Write(address + I2C_CONFIG_LOAD, I2C_REG_BITS_VALUE(CONFIG_LOAD_RESERVED_BIT_5, 1), I2C_REG_BITS_ENUM (CONFIG_LOAD_TIMEOUT_CONFIG_LOAD, ENABLE), I2C_REG_BITS_ENUM (CONFIG_LOAD_SLV_CONFIG_LOAD, DISABLE), I2C_REG_BITS_ENUM (CONFIG_LOAD_MSTR_CONFIG_LOAD, ENABLE)); /* Wait up to 20 microseconds for the master config to be loaded. */ for (int i = 0; i < 20; ++i) { if (reg::HasValue(address + I2C_CONFIG_LOAD, I2C_REG_BITS_ENUM(CONFIG_LOAD_MSTR_CONFIG_LOAD, DISABLE))) { return; } util::WaitMicroSeconds(1); } } void ClearBus(uintptr_t address) { /* Configure the bus clear register. */ reg::Write(address + I2C_BUS_CLEAR_CONFIG, I2C_REG_BITS_VALUE(BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD, 9), I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_STOP_COND, NO_STOP), I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_TERMINATE, IMMEDIATE), I2C_REG_BITS_ENUM (BUS_CLEAR_CONFIG_BC_ENABLE, ENABLE)); /* Load the config. */ LoadConfig(address); /* Wait up to 250us (in 25 us increments) until the bus clear is done. */ for (int i = 0; i < 10; ++i) { if (reg::HasValue(address + I2C_INTERRUPT_STATUS_REGISTER, I2C_REG_BITS_ENUM(INTERRUPT_STATUS_REGISTER_BUS_CLEAR_DONE, SET))) { break; } util::WaitMicroSeconds(25); } /* Read the bus clear status. */ reg::Read(address + I2C_BUS_CLEAR_STATUS); } void InitializePort(uintptr_t address) { /* Calculate the divisor. */ constexpr int Divisor = util::DivideUp(19200, 8 * 400); /* Set the divisor. */ reg::Write(address + I2C_CLK_DIVISOR_REGISTER, I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_STD_FAST_MODE, Divisor - 1), I2C_REG_BITS_VALUE(CLK_DIVISOR_REGISTER_HSMODE, 1)); /* Clear the bus. */ ClearBus(address); /* Clear the status. */ reg::Write(address + I2C_INTERRUPT_STATUS_REGISTER, reg::Read(address + I2C_INTERRUPT_STATUS_REGISTER)); } bool Write(uintptr_t base_address, Port port, int address, const void *src, size_t src_size, bool unused) { AMS_UNUSED(port, unused); /* Ensure we don't write too much. */ u32 data = 0; if (src_size > MaxTransferSize) { return false; } /* Copy the data to a transfer word. */ std::memcpy(std::addressof(data), src, src_size); /* Configure the to write the 7-bit address. */ reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address), I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, WRITE)); /* Configure to write the data. */ reg::Write(base_address + I2C_I2C_CMD_DATA1, data); /* Configure to write the correct amount of data. */ reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T), I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE), I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, WRITE), I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, src_size - 1)); /* Load the configuration. */ LoadConfig(base_address); /* Start the command. */ reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO)); /* Wait for the command to be done. */ while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ } /* Check if the transfer was successful. */ return reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL)); } bool Read(uintptr_t base_address, Port port, void *dst, size_t dst_size, int address, bool unused) { AMS_UNUSED(port, unused); /* Ensure we don't read too much. */ if (dst_size > MaxTransferSize) { return false; } /* Configure the to read the 7-bit address. */ reg::Write(base_address + I2C_I2C_CMD_ADDR0, I2C_REG_BITS_VALUE(I2C_CMD_ADDR0_7BIT_ADDR, address), I2C_REG_BITS_ENUM (I2C_CMD_ADDR0_7BIT_RW, READ)); /* Configure to read the correct amount of data. */ reg::Write(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM (I2C_CNFG_DEBOUNCE_CNT, DEBOUNCE_4T), I2C_REG_BITS_ENUM (I2C_CNFG_NEW_MASTER_FSM, ENABLE), I2C_REG_BITS_ENUM (I2C_CNFG_CMD1, READ), I2C_REG_BITS_VALUE(I2C_CNFG_LENGTH, dst_size - 1)); /* Load the configuration. */ LoadConfig(base_address); /* Start the command. */ reg::ReadWrite(base_address + I2C_I2C_CNFG, I2C_REG_BITS_ENUM(I2C_CNFG_SEND, GO)); /* Wait for the command to be done. */ while (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_BUSY, NOT_BUSY))) { /* ... */ } /* Check that the transfer was successful. */ if (!reg::HasValue(base_address + I2C_I2C_STATUS, I2C_REG_BITS_ENUM(I2C_STATUS_CMD1_STAT, SL1_XFER_SUCCESSFUL))) { return false; } /* Read and copy out the data. */ u32 data = reg::Read(base_address + I2C_I2C_CMD_DATA1); std::memcpy(dst, std::addressof(data), dst_size); return true; } } void SetRegisterAddress(Port port, uintptr_t address) { g_register_addresses[port] = address; } void Initialize(Port port) { InitializePort(g_register_addresses[port]); } bool Query(void *dst, size_t dst_size, Port port, int address, int r) { const uintptr_t base_address = g_register_addresses[port]; /* Select the register we want to read. */ bool success = Write(base_address, port, address, std::addressof(r), 1, false); if (success) { /* If we successfully selected, read data from the register. */ success = Read(base_address, port, dst, dst_size, address, true); } return success; } bool Send(Port port, int address, int r, const void *src, size_t src_size) { const uintptr_t base_address = g_register_addresses[port]; /* Create a transfer buffer, make sure we can use it. */ u8 buffer[MaxTransferSize]; if (src_size > sizeof(buffer) - 1) { return false; } /* Copy data into the buffer. */ buffer[0] = static_cast<u8>(r); std::memcpy(buffer + 1, src, src_size); return Write(base_address, port, address, buffer, src_size + 1, false); } } ================================================ FILE: libraries/libexosphere/source/impl/ams_impl_unexpected_default.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::impl { NORETURN void UnexpectedDefaultImpl(const char *func, const char *file, int line) { ::ams::diag::AbortImpl("", func, file, line); } } ================================================ FILE: libraries/libexosphere/source/kfuse/kfuse_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #define KFUSE_STATE (0x080) #define KFUSE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (KFUSE, NAME) #define KFUSE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (KFUSE, NAME, VALUE) #define KFUSE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (KFUSE, NAME, ENUM) #define KFUSE_REG_BITS_ENUM_KFUSEL(NAME, __COND__, TRUE_ENUM, FALKFUSE_ENUM) REG_NAMED_BITS_ENUM_KFUSEL(KFUSE, NAME, __COND__, TRUE_ENUM, FALKFUSE_ENUM) #define DEFINE_KFUSE_REG(NAME, __OFFKFUSET__, __WIDTH__) REG_DEFINE_NAMED_REG (KFUSE, NAME, __OFFKFUSET__, __WIDTH__) #define DEFINE_KFUSE_REG_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE) #define DEFINE_KFUSE_REG_TWO_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE) #define DEFINE_KFUSE_REG_THREE_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN) #define DEFINE_KFUSE_REG_FOUR_BIT_ENUM(NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (KFUSE, NAME, __OFFKFUSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, KFUSEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) DEFINE_KFUSE_REG_BIT_ENUM(STATE_DONE, 16, NOT_DONE, DONE); DEFINE_KFUSE_REG_BIT_ENUM(STATE_CRCPASS, 17, FAIL, PASS); ================================================ FILE: libraries/libexosphere/source/libc/libc.c ================================================ /* Note: copied from newlib */ #ifdef __cplusplus extern "C" { #endif #include <string.h> #include <stddef.h> #include <limits.h> /* * Copyright (C) 2004 CodeSourcery, LLC * * Permission to use, copy, modify, and distribute this file * for any purpose is hereby granted without fee, provided that * the above copyright notice and this notice appears in all * copies. * * This file is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* Handle ELF .{pre_init,init,fini}_array sections. */ #include <sys/types.h> #ifndef HAVE_INITFINI_ARRAY #define HAVE_INITFINI_ARRAY #endif #undef HAVE_INIT_FINI #ifdef HAVE_INITFINI_ARRAY /* These magic symbols are provided by the linker. */ extern void (*__preinit_array_start []) (void) __attribute__((weak)); extern void (*__preinit_array_end []) (void) __attribute__((weak)); extern void (*__init_array_start []) (void) __attribute__((weak)); extern void (*__init_array_end []) (void) __attribute__((weak)); #ifdef HAVE_INIT_FINI extern void _init (void); #endif /* Iterate over all the init routines. */ void __libc_init_array (void) { size_t count; size_t i; count = __preinit_array_end - __preinit_array_start; for (i = 0; i < count; i++) __preinit_array_start[i] (); #ifdef HAVE_INIT_FINI _init (); #endif count = __init_array_end - __init_array_start; for (i = 0; i < count; i++) __init_array_start[i] (); } #endif #ifdef HAVE_INITFINI_ARRAY extern void (*__fini_array_start []) (void) __attribute__((weak)); extern void (*__fini_array_end []) (void) __attribute__((weak)); #ifdef HAVE_INIT_FINI extern void _fini (void); #endif /* Run all the cleanup routines. */ void __libc_fini_array (void) { size_t count; size_t i; count = __fini_array_end - __fini_array_start; for (i = count; i > 0; i--) __fini_array_start[i-1] (); #ifdef HAVE_INIT_FINI _fini (); #endif } #endif /* FUNCTION <<memmove>>---move possibly overlapping memory INDEX memmove SYNOPSIS #include <string.h> void *memmove(void *<[dst]>, const void *<[src]>, size_t <[length]>); DESCRIPTION This function moves <[length]> characters from the block of memory starting at <<*<[src]>>> to the memory starting at <<*<[dst]>>>. <<memmove>> reproduces the characters correctly at <<*<[dst]>>> even if the two areas overlap. RETURNS The function returns <[dst]> as passed. PORTABILITY <<memmove>> is ANSI C. <<memmove>> requires no supporting OS subroutines. QUICKREF memmove ansi pure */ /* Nonzero if either X or Y is not aligned on a "long" boundary. */ #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) /* How many bytes are copied each iteration of the 4X unrolled loop. */ #define BIGBLOCKSIZE (sizeof (long) << 2) /* How many bytes are copied each iteration of the word copy loop. */ #define LITTLEBLOCKSIZE (sizeof (long)) /* Threshhold for punting to the byte copier. */ #undef TOO_SMALL #define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) /*SUPPRESS 20*/ void * //__inhibit_loop_to_libcall memmove (void *dst_void, const void *src_void, size_t length) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) char *dst = dst_void; const char *src = src_void; if (src < dst && dst < src + length) { /* Have to copy backwards */ src += length; dst += length; while (length--) { *--dst = *--src; } } else { while (length--) { *dst++ = *src++; } } return dst_void; #else char *dst = dst_void; const char *src = src_void; long *aligned_dst; const long *aligned_src; if (src < dst && dst < src + length) { /* Destructive overlap...have to copy backwards */ src += length; dst += length; while (length--) { *--dst = *--src; } } else { /* Use optimizing algorithm for a non-destructive copy to closely match memcpy. If the size is small or either SRC or DST is unaligned, then punt into the byte copy loop. This should be rare. */ if (!TOO_SMALL(length) && !UNALIGNED (src, dst)) { aligned_dst = (long*)dst; aligned_src = (long*)src; /* Copy 4X long words at a time if possible. */ while (length >= BIGBLOCKSIZE) { *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; length -= BIGBLOCKSIZE; } /* Copy one long word at a time if possible. */ while (length >= LITTLEBLOCKSIZE) { *aligned_dst++ = *aligned_src++; length -= LITTLEBLOCKSIZE; } /* Pick up any residual with a byte copier. */ dst = (char*)aligned_dst; src = (char*)aligned_src; } while (length--) { *dst++ = *src++; } } return dst_void; #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<memcpy>>---copy memory regions SYNOPSIS #include <string.h> void* memcpy(void *restrict <[out]>, const void *restrict <[in]>, size_t <[n]>); DESCRIPTION This function copies <[n]> bytes from the memory region pointed to by <[in]> to the memory region pointed to by <[out]>. If the regions overlap, the behavior is undefined. RETURNS <<memcpy>> returns a pointer to the first byte of the <[out]> region. PORTABILITY <<memcpy>> is ANSI C. <<memcpy>> requires no supporting OS subroutines. QUICKREF memcpy ansi pure */ void * memcpy (void * dst0, const void * __restrict src0, size_t len0) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) char *dst = (char *) dst0; char *src = (char *) src0; void *save = dst0; while (len0--) { *dst++ = *src++; } return save; #else char *dst = dst0; const char *src = src0; long *aligned_dst; const long *aligned_src; /* If the size is small, or either SRC or DST is unaligned, then punt into the byte copy loop. This should be rare. */ if (!TOO_SMALL(len0) && !UNALIGNED (src, dst)) { aligned_dst = (long*)dst; aligned_src = (long*)src; /* Copy 4X long words at a time if possible. */ while (len0 >= BIGBLOCKSIZE) { *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; *aligned_dst++ = *aligned_src++; len0 -= BIGBLOCKSIZE; } /* Copy one long word at a time if possible. */ while (len0 >= LITTLEBLOCKSIZE) { *aligned_dst++ = *aligned_src++; len0 -= LITTLEBLOCKSIZE; } /* Pick up any residual with a byte copier. */ dst = (char*)aligned_dst; src = (char*)aligned_src; } while (len0--) *dst++ = *src++; return dst0; #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<memset>>---set an area of memory INDEX memset SYNOPSIS #include <string.h> void *memset(void *<[dst]>, int <[c]>, size_t <[length]>); DESCRIPTION This function converts the argument <[c]> into an unsigned char and fills the first <[length]> characters of the array pointed to by <[dst]> to the value. RETURNS <<memset>> returns the value of <[dst]>. PORTABILITY <<memset>> is ANSI C. <<memset>> requires no supporting OS subroutines. QUICKREF memset ansi pure */ #include <string.h> #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL #define LBLOCKSIZE (sizeof(long)) #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) void * memset (void *m, int c, size_t n) { char *s = (char *) m; #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) unsigned int i; unsigned long buffer; unsigned long *aligned_addr; unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an unsigned variable. */ while (UNALIGNED (s)) { if (n--) *s++ = (char) c; else return m; } if (!TOO_SMALL (n)) { /* If we get this far, we know that n is large and s is word-aligned. */ aligned_addr = (unsigned long *) s; /* Store D into each char sized location in BUFFER so that we can set large blocks quickly. */ buffer = (d << 8) | d; buffer |= (buffer << 16); for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) buffer = (buffer << i) | buffer; /* Unroll the loop. */ while (n >= LBLOCKSIZE*4) { *aligned_addr++ = buffer; *aligned_addr++ = buffer; *aligned_addr++ = buffer; *aligned_addr++ = buffer; n -= 4*LBLOCKSIZE; } while (n >= LBLOCKSIZE) { *aligned_addr++ = buffer; n -= LBLOCKSIZE; } /* Pick up the remainder with a bytewise loop. */ s = (char*)aligned_addr; } #endif /* not PREFER_SIZE_OVER_SPEED */ while (n--) *s++ = (char) c; return m; } /* FUNCTION <<memchr>>---find character in memory INDEX memchr SYNOPSIS #include <string.h> void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>); DESCRIPTION This function searches memory starting at <<*<[src]>>> for the character <[c]>. The search only ends with the first occurrence of <[c]>, or after <[length]> characters; in particular, <<NUL>> does not terminate the search. RETURNS If the character <[c]> is found within <[length]> characters of <<*<[src]>>>, a pointer to the character is returned. If <[c]> is not found, then <<NULL>> is returned. PORTABILITY <<memchr>> is ANSI C. <<memchr>> requires no supporting OS subroutines. QUICKREF memchr ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL /* Nonzero if either X or Y is not aligned on a "long" boundary. */ #define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) /* How many bytes are loaded each iteration of the word copy loop. */ #define LBLOCKSIZE (sizeof (long)) /* Threshhold for punting to the bytewise iterator. */ #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) #if LONG_MAX == 2147483647L #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) #else #if LONG_MAX == 9223372036854775807L /* Nonzero if X (a long int) contains a NULL byte. */ #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) #else #error long int is not a 32bit or 64bit type. #endif #endif #ifndef DETECTNULL #error long int is not a 32bit or 64bit byte #endif /* DETECTCHAR returns nonzero if (long)X contains the byte used to fill (long)MASK. */ #define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK)) void * memchr (const void *src_void, int c, size_t length) { const unsigned char *src = (const unsigned char *) src_void; unsigned char d = c; #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) unsigned long *asrc; unsigned long mask; unsigned int i; while (UNALIGNED (src)) { if (!length--) return NULL; if (*src == d) return (void *) src; src++; } if (!TOO_SMALL (length)) { /* If we get this far, we know that length is large and src is word-aligned. */ /* The fast code reads the source one word at a time and only performs the bytewise search on word-sized segments if they contain the search character, which is detected by XORing the word-sized segment with a word-sized block of the search character and then detecting for the presence of NUL in the result. */ asrc = (unsigned long *) src; mask = d << 8 | d; mask = mask << 16 | mask; for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) mask = (mask << i) | mask; while (length >= LBLOCKSIZE) { if (DETECTCHAR (*asrc, mask)) break; length -= LBLOCKSIZE; asrc++; } /* If there are fewer than LBLOCKSIZE characters left, then we resort to the bytewise loop. */ src = (unsigned char *) asrc; } #endif /* not PREFER_SIZE_OVER_SPEED */ while (length--) { if (*src == d) return (void *) src; src++; } return NULL; } /* FUNCTION <<memcmp>>---compare two memory areas INDEX memcmp SYNOPSIS #include <string.h> int memcmp(const void *<[s1]>, const void *<[s2]>, size_t <[n]>); DESCRIPTION This function compares not more than <[n]> characters of the object pointed to by <[s1]> with the object pointed to by <[s2]>. RETURNS The function returns an integer greater than, equal to or less than zero according to whether the object pointed to by <[s1]> is greater than, equal to or less than the object pointed to by <[s2]>. PORTABILITY <<memcmp>> is ANSI C. <<memcmp>> requires no supporting OS subroutines. QUICKREF memcmp ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL /* Nonzero if either X or Y is not aligned on a "long" boundary. */ #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) /* How many bytes are copied each iteration of the word copy loop. */ #define LBLOCKSIZE (sizeof (long)) /* Threshhold for punting to the byte copier. */ #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) int memcmp (const void *m1, const void *m2, size_t n) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) unsigned char *s1 = (unsigned char *) m1; unsigned char *s2 = (unsigned char *) m2; while (n--) { if (*s1 != *s2) { return *s1 - *s2; } s1++; s2++; } return 0; #else unsigned char *s1 = (unsigned char *) m1; unsigned char *s2 = (unsigned char *) m2; unsigned long *a1; unsigned long *a2; /* If the size is too small, or either pointer is unaligned, then we punt to the byte compare loop. Hopefully this will not turn up in inner loops. */ if (!TOO_SMALL(n) && !UNALIGNED(s1,s2)) { /* Otherwise, load and compare the blocks of memory one word at a time. */ a1 = (unsigned long*) s1; a2 = (unsigned long*) s2; while (n >= LBLOCKSIZE) { if (*a1 != *a2) break; a1++; a2++; n -= LBLOCKSIZE; } /* check m mod LBLOCKSIZE remaining characters */ s1 = (unsigned char*)a1; s2 = (unsigned char*)a2; } while (n--) { if (*s1 != *s2) return *s1 - *s2; s1++; s2++; } return 0; #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<strchr>>---search for character in string INDEX strchr SYNOPSIS #include <string.h> char * strchr(const char *<[string]>, int <[c]>); DESCRIPTION This function finds the first occurence of <[c]> (converted to a char) in the string pointed to by <[string]> (including the terminating null character). RETURNS Returns a pointer to the located character, or a null pointer if <[c]> does not occur in <[string]>. PORTABILITY <<strchr>> is ANSI C. <<strchr>> requires no supporting OS subroutines. QUICKREF strchr ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL /* Nonzero if X is not aligned on a "long" boundary. */ #define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) /* How many bytes are loaded each iteration of the word copy loop. */ #define LBLOCKSIZE (sizeof (long)) char * strchr (const char *s1, int i) { const unsigned char *s = (const unsigned char *)s1; unsigned char c = i; #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) unsigned long mask,j; unsigned long *aligned_addr; /* Special case for finding 0. */ if (!c) { while (UNALIGNED (s)) { if (!*s) return (char *) s; s++; } /* Operate a word at a time. */ aligned_addr = (unsigned long *) s; while (!DETECTNULL (*aligned_addr)) aligned_addr++; /* Found the end of string. */ s = (const unsigned char *) aligned_addr; while (*s) s++; return (char *) s; } /* All other bytes. Align the pointer, then search a long at a time. */ while (UNALIGNED (s)) { if (!*s) return NULL; if (*s == c) return (char *) s; s++; } mask = c; for (j = 8; j < LBLOCKSIZE * 8; j <<= 1) mask = (mask << j) | mask; aligned_addr = (unsigned long *) s; while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask)) aligned_addr++; /* The block of bytes currently pointed to by aligned_addr contains either a null or the target char, or both. We catch it using the bytewise search. */ s = (unsigned char *) aligned_addr; #endif /* not PREFER_SIZE_OVER_SPEED */ while (*s && *s != c) s++; if (*s == c) return (char *)s; return NULL; } /* FUNCTION <<strcmp>>---character string compare INDEX strcmp SYNOPSIS #include <string.h> int strcmp(const char *<[a]>, const char *<[b]>); DESCRIPTION <<strcmp>> compares the string at <[a]> to the string at <[b]>. RETURNS If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, <<strcmp>> returns a number greater than zero. If the two strings match, <<strcmp>> returns zero. If <<*<[a]>>> sorts lexicographically before <<*<[b]>>>, <<strcmp>> returns a number less than zero. PORTABILITY <<strcmp>> is ANSI C. <<strcmp>> requires no supporting OS subroutines. QUICKREF strcmp ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL /* Nonzero if either X or Y is not aligned on a "long" boundary. */ #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) int strcmp (const char *s1, const char *s2) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) while (*s1 != '\0' && *s1 == *s2) { s1++; s2++; } return (*(unsigned char *) s1) - (*(unsigned char *) s2); #else unsigned long *a1; unsigned long *a2; /* If s1 or s2 are unaligned, then compare bytes. */ if (!UNALIGNED (s1, s2)) { /* If s1 and s2 are word-aligned, compare them a word at a time. */ a1 = (unsigned long*)s1; a2 = (unsigned long*)s2; while (*a1 == *a2) { /* To get here, *a1 == *a2, thus if we find a null in *a1, then the strings must be equal, so return zero. */ if (DETECTNULL (*a1)) return 0; a1++; a2++; } /* A difference was detected in last few bytes of s1, so search bytewise */ s1 = (char*)a1; s2 = (char*)a2; } while (*s1 != '\0' && *s1 == *s2) { s1++; s2++; } return (*(unsigned char *) s1) - (*(unsigned char *) s2); #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<strcpy>>---copy string INDEX strcpy SYNOPSIS #include <string.h> char *strcpy(char *<[dst]>, const char *<[src]>); DESCRIPTION <<strcpy>> copies the string pointed to by <[src]> (including the terminating null character) to the array pointed to by <[dst]>. RETURNS This function returns the initial value of <[dst]>. PORTABILITY <<strcpy>> is ANSI C. <<strcpy>> requires no supporting OS subroutines. QUICKREF strcpy ansi pure */ /*SUPPRESS 560*/ /*SUPPRESS 530*/ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL /* Nonzero if either X or Y is not aligned on a "long" boundary. */ #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) char* strcpy (char *dst0, const char *src0) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) char *s = dst0; while ((*dst0++ = *src0++)) ; return s; #else char *dst = dst0; const char *src = src0; long *aligned_dst; const long *aligned_src; /* If SRC or DEST is unaligned, then copy bytes. */ if (!UNALIGNED (src, dst)) { aligned_dst = (long*)dst; aligned_src = (long*)src; /* SRC and DEST are both "long int" aligned, try to do "long int" sized copies. */ while (!DETECTNULL(*aligned_src)) { *aligned_dst++ = *aligned_src++; } dst = (char*)aligned_dst; src = (char*)aligned_src; } while ((*dst++ = *src++)) ; return dst0; #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<strlen>>---character string length INDEX strlen SYNOPSIS #include <string.h> size_t strlen(const char *<[str]>); DESCRIPTION The <<strlen>> function works out the length of the string starting at <<*<[str]>>> by counting chararacters until it reaches a <<NULL>> character. RETURNS <<strlen>> returns the character count. PORTABILITY <<strlen>> is ANSI C. <<strlen>> requires no supporting OS subroutines. QUICKREF strlen ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL #define LBLOCKSIZE (sizeof (long)) #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) size_t strlen (const char *str) { const char *start = str; #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) unsigned long *aligned_addr; /* Align the pointer, so we can search a word at a time. */ while (UNALIGNED (str)) { if (!*str) return str - start; str++; } /* If the string is word-aligned, we can check for the presence of a null in each word-sized block. */ aligned_addr = (unsigned long *)str; while (!DETECTNULL (*aligned_addr)) aligned_addr++; /* Once a null is detected, we check each byte in that block for a precise position of the null. */ str = (char *) aligned_addr; #endif /* not PREFER_SIZE_OVER_SPEED */ while (*str) str++; return str - start; } /* FUNCTION <<strncmp>>---character string compare INDEX strncmp SYNOPSIS #include <string.h> int strncmp(const char *<[a]>, const char * <[b]>, size_t <[length]>); DESCRIPTION <<strncmp>> compares up to <[length]> characters from the string at <[a]> to the string at <[b]>. RETURNS If <<*<[a]>>> sorts lexicographically after <<*<[b]>>>, <<strncmp>> returns a number greater than zero. If the two strings are equivalent, <<strncmp>> returns zero. If <<*<[a]>>> sorts lexicographically before <<*<[b]>>>, <<strncmp>> returns a number less than zero. PORTABILITY <<strncmp>> is ANSI C. <<strncmp>> requires no supporting OS subroutines. QUICKREF strncmp ansi pure */ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) int strncmp (const char *s1, const char *s2, size_t n) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) if (n == 0) return 0; while (n-- != 0 && *s1 == *s2) { if (n == 0 || *s1 == '\0') break; s1++; s2++; } return (*(unsigned char *) s1) - (*(unsigned char *) s2); #else unsigned long *a1; unsigned long *a2; if (n == 0) return 0; /* If s1 or s2 are unaligned, then compare bytes. */ if (!UNALIGNED (s1, s2)) { /* If s1 and s2 are word-aligned, compare them a word at a time. */ a1 = (unsigned long*)s1; a2 = (unsigned long*)s2; while (n >= sizeof (long) && *a1 == *a2) { n -= sizeof (long); /* If we've run out of bytes or hit a null, return zero since we already know *a1 == *a2. */ if (n == 0 || DETECTNULL (*a1)) return 0; a1++; a2++; } /* A difference was detected in last few bytes of s1, so search bytewise */ s1 = (char*)a1; s2 = (char*)a2; } while (n-- > 0 && *s1 == *s2) { /* If we've run out of bytes or hit a null, return zero since we already know *s1 == *s2. */ if (n == 0 || *s1 == '\0') return 0; s1++; s2++; } return (*(unsigned char *) s1) - (*(unsigned char *) s2); #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<strncpy>>---counted copy string INDEX strncpy SYNOPSIS #include <string.h> char *strncpy(char *restrict <[dst]>, const char *restrict <[src]>, size_t <[length]>); DESCRIPTION <<strncpy>> copies not more than <[length]> characters from the the string pointed to by <[src]> (including the terminating null character) to the array pointed to by <[dst]>. If the string pointed to by <[src]> is shorter than <[length]> characters, null characters are appended to the destination array until a total of <[length]> characters have been written. RETURNS This function returns the initial value of <[dst]>. PORTABILITY <<strncpy>> is ANSI C. <<strncpy>> requires no supporting OS subroutines. QUICKREF strncpy ansi pure */ /*SUPPRESS 560*/ /*SUPPRESS 530*/ #undef LBLOCKSIZE #undef UNALIGNED #undef TOO_SMALL #define UNALIGNED(X, Y) \ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) #define TOO_SMALL(LEN) ((LEN) < sizeof (long)) char * strncpy (char *__restrict dst0, const char *__restrict src0, size_t count) { #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) char *dscan; const char *sscan; dscan = dst0; sscan = src0; while (count > 0) { --count; if ((*dscan++ = *sscan++) == '\0') break; } while (count-- > 0) *dscan++ = '\0'; return dst0; #else char *dst = dst0; const char *src = src0; long *aligned_dst; const long *aligned_src; /* If SRC and DEST is aligned and count large enough, then copy words. */ if (!UNALIGNED (src, dst) && !TOO_SMALL (count)) { aligned_dst = (long*)dst; aligned_src = (long*)src; /* SRC and DEST are both "long int" aligned, try to do "long int" sized copies. */ while (count >= sizeof (long int) && !DETECTNULL(*aligned_src)) { count -= sizeof (long int); *aligned_dst++ = *aligned_src++; } dst = (char*)aligned_dst; src = (char*)aligned_src; } while (count > 0) { --count; if ((*dst++ = *src++) == '\0') break; } while (count-- > 0) *dst++ = '\0'; return dst0; #endif /* not PREFER_SIZE_OVER_SPEED */ } /* FUNCTION <<strnlen>>---character string length INDEX strnlen SYNOPSIS #include <string.h> size_t strnlen(const char *<[str]>, size_t <[n]>); DESCRIPTION The <<strnlen>> function works out the length of the string starting at <<*<[str]>>> by counting chararacters until it reaches a NUL character or the maximum: <[n]> number of characters have been inspected. RETURNS <<strnlen>> returns the character count or <[n]>. PORTABILITY <<strnlen>> is a GNU extension. <<strnlen>> requires no supporting OS subroutines. */ size_t strnlen (const char *str, size_t n) { const char *start = str; while (n-- > 0 && *str) str++; return str - start; } #ifdef __cplusplus } /* extern "C" */ #endif ================================================ FILE: libraries/libexosphere/source/libc/libexo_cxx.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #ifdef __cplusplus extern "C" { #endif /* cxx implementation details to be stubbed here, as needed. */ void __cxa_pure_virtual() { AMS_ABORT("pure virtual function call"); } #ifdef __cplusplus } /* extern "C" */ #endif ================================================ FILE: libraries/libexosphere/source/log/log_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::log { namespace { constexpr inline uart::Port DefaultLogPort = uart::Port_ReservedDebug; constexpr inline u32 DefaultLogFlags = static_cast<u32>(uart::Flag_None); constexpr inline int DefaultBaudRate = 115200; constinit uart::Port g_log_port = DefaultLogPort; constinit bool g_initialized_uart = false; ALWAYS_INLINE void SetupUartClock(uart::Port port) { /* The debug port must always be set up, for compatibility with official hos. */ pinmux::SetupUartA(); clkrst::EnableUartAClock(); /* If logging to a joy-con port, configure appropriately. */ if (port == uart::Port_LeftJoyCon) { /* Logging to left joy-con (e.g. with Joyless). */ static_assert(uart::Port_LeftJoyCon == uart::Port_C); pinmux::SetupUartC(); clkrst::EnableUartCClock(); } else if (port == uart::Port_RightJoyCon) { /* Logging to right joy-con (e.g. with Joyless). */ static_assert(uart::Port_RightJoyCon == uart::Port_B); pinmux::SetupUartB(); clkrst::EnableUartBClock(); } } } void Initialize() { return Initialize(DefaultLogPort, DefaultBaudRate, DefaultLogFlags); } void Initialize(uart::Port port, u32 baud_rate, u32 flags) { /* Initialize pinmux and clock for the target uart port. */ SetupUartClock(port); /* Initialize the target uart port. */ uart::Initialize(port, baud_rate, flags); /* Note that we've initialized. */ g_log_port = port; g_initialized_uart = true; } void Finalize() { g_initialized_uart = false; } NOINLINE void VPrintf(const char *fmt, ::std::va_list vl) { /* TODO: What's a good size for the log buffer? Nintendo uses 0x100, but this seems big. */ char log_buf[0x80]; const auto len = util::TVSNPrintf(log_buf, sizeof(log_buf), fmt, vl); if (g_initialized_uart) { uart::SendText(g_log_port, log_buf, len); } } NOINLINE void Printf(const char *fmt, ...) { ::std::va_list vl; va_start(vl, fmt); VPrintf(fmt, vl); va_end(vl); } NOINLINE void Dump(const void *src, size_t size) { const u8 *src_u8 = static_cast<const u8 *>(src); for (size_t i = 0; i < size; ++i) { if ((i % 0x20) == 0x00) { Printf("%03zx| ", i); } Printf("%02x ", src_u8[i]); if ((i % 0x20) == 0x1F) { Printf("\n"); } } if ((size % 0x20) != 0) { Printf("\n"); } } void SendText(const void *text, size_t size) { if (g_initialized_uart) { uart::SendText(g_log_port, text, size); } } void Flush() { if (g_initialized_uart) { uart::WaitFlush(g_log_port); } } } ================================================ FILE: libraries/libexosphere/source/pinmux/pinmux_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::pinmux { namespace { constinit uintptr_t g_pinmux_address = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); constinit uintptr_t g_gpio_address = secmon::MemoryRegionPhysicalDeviceGpio.GetAddress(); void SetupFirstImpl(bool tx_cross_ext_con) { if (tx_cross_ext_con) { reg::Write(g_pinmux_address + PINMUX_AUX_UART2_TX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(g_pinmux_address + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); /* Configure GPIO for Uart-B/Uart-C. */ reg::ReadWrite(g_gpio_address + 0x108, REG_BITS_VALUE(0, 1, 1)); reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 1)); reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 0)); reg::ReadWrite(g_gpio_address + 0x01C, REG_BITS_VALUE(1, 1, 0)); } /* Configure PE6/PH6 */ reg::Write(g_pinmux_address + PINMUX_AUX_GPIO_PE6, PINMUX_REG_BITS_ENUM(AUX_GPIO_PE6_PM, RSVD0), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(g_pinmux_address + PINMUX_AUX_GPIO_PH6, PINMUX_REG_BITS_ENUM(AUX_GPIO_PH6_PM, RSVD0), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); /* Configure GPIO E6/H6. */ reg::ReadWrite(g_gpio_address + 0x100, REG_BITS_VALUE(6, 1, 1)); reg::ReadWrite(g_gpio_address + 0x10C, REG_BITS_VALUE(6, 1, 1)); reg::ReadWrite(g_gpio_address + 0x110, REG_BITS_VALUE(6, 1, 0)); reg::ReadWrite(g_gpio_address + 0x11C, REG_BITS_VALUE(6, 1, 0)); } } void SetRegisterAddress(uintptr_t pinmux_address, uintptr_t gpio_address) { g_pinmux_address = pinmux_address; g_gpio_address = gpio_address; } void SetupFirst(fuse::HardwareType hw_type) { switch (hw_type) { case fuse::HardwareType_Icosa: case fuse::HardwareType_Iowa: case fuse::HardwareType_Aula: SetupFirstImpl(true); break; case fuse::HardwareType_Hoag: case fuse::HardwareType_Calcio: SetupFirstImpl(false); break; case fuse::HardwareType_Copper: case fuse::HardwareType_Undefined: break; } } void SetupUartA() { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; /* Configure Uart-A. */ reg::Write(PINMUX + PINMUX_AUX_UART1_TX, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART1_RX, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_UP), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART1_RTS, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART1_CTS, PINMUX_REG_BITS_ENUM(AUX_UART1_PM, UARTA), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); } void SetupUartB() { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; /* Configure Uart-B. */ reg::Write(PINMUX + PINMUX_AUX_UART2_TX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART2_RX, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART2_RTS, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART2_CTS, PINMUX_REG_BITS_ENUM(AUX_UART2_PM, UARTB), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); /* Configure GPIO for Uart-B. */ reg::ReadWrite(g_gpio_address + 0x108, REG_BITS_VALUE(0, 4, 0)); } void SetupUartC() { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; /* Configure Uart-C. */ reg::Write(PINMUX + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART3_RX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART3_RTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART3_CTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); /* Configure GPIO for Uart-C. */ reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 1)); reg::Read(g_gpio_address + 0x118); reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 0)); reg::Read(g_gpio_address + 0x00C); } void SetupI2c1() { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; /* Configure I2c1 */ reg::Write(PINMUX + PINMUX_AUX_GEN1_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_GEN1_I2C_PM, I2C1), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_GEN1_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_GEN1_I2C_PM, I2C1), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); } void SetupI2c5() { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; /* Configure I2c5 */ reg::Write(PINMUX + PINMUX_AUX_PWR_I2C_SCL, PINMUX_REG_BITS_ENUM(AUX_PWR_I2C_PM, I2CPMU), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_PWR_I2C_SDA, PINMUX_REG_BITS_ENUM(AUX_PWR_I2C_PM, I2CPMU), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); } void SetupVolumeButton() { /* Configure VOL_UP/VOL_DOWN */ reg::ReadWrite(g_gpio_address + 0x50C, REG_BITS_VALUE(6, 1, 1)); reg::ReadWrite(g_gpio_address + 0x50C, REG_BITS_VALUE(7, 1, 1)); reg::ReadWrite(g_gpio_address + 0x51C, REG_BITS_VALUE(6, 1, 0)); reg::ReadWrite(g_gpio_address + 0x51C, REG_BITS_VALUE(7, 1, 0)); } void SetupHomeButton() { /* Configure BUTTON_HOME */ reg::ReadWrite(g_gpio_address + 0x600, REG_BITS_VALUE(1, 1, 1)); reg::ReadWrite(g_gpio_address + 0x610, REG_BITS_VALUE(1, 1, 0)); } } ================================================ FILE: libraries/libexosphere/source/pkg1/pkg1_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::pkg1 { namespace { bool IsProductionImpl() { return fuse::GetHardwareState() != fuse::HardwareState_Development; } } bool IsProduction() { return IsProductionImpl(); } bool IsProductionForVersionCheck() { return IsProductionImpl(); } bool IsProductionForPublicKey() { return IsProductionImpl(); } } ================================================ FILE: libraries/libexosphere/source/pmc/pmc_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::pmc { namespace { constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline u32 WriteMask = 0x1; constexpr inline u32 ReadMask = 0x2; enum class LockMode { Read, Write, ReadWrite, }; template<LockMode Mode> constexpr inline u32 LockMask = [] { switch (Mode) { case LockMode::Read: return ReadMask; case LockMode::Write: return WriteMask; case LockMode::ReadWrite: return ReadMask | WriteMask; default: __builtin_unreachable(); } }(); constexpr inline size_t NumSecureScratchRegisters = 120; constexpr inline size_t NumSecureDisableRegisters = 8; template<size_t SecureScratch> requires (SecureScratch < NumSecureScratchRegisters) constexpr inline std::pair<size_t, size_t> DisableRegisterIndex = [] { if constexpr (SecureScratch < 8) { return std::pair<size_t, size_t>{0, 4 + 2 * SecureScratch}; } else { constexpr size_t Relative = SecureScratch - 8; return std::pair<size_t, size_t>{1 + (Relative / 16), 2 * (Relative % 16)}; } }(); struct LockInfo { size_t scratch; LockMode mode; }; template<LockInfo Info> constexpr ALWAYS_INLINE void SetSecureScratchMask(std::array<u32, NumSecureDisableRegisters> &disables) { constexpr std::pair<size_t, size_t> Location = DisableRegisterIndex<Info.scratch>; disables[Location.first] |= LockMask<Info.mode> << Location.second; } template<LockInfo... Info> constexpr ALWAYS_INLINE void SetSecureScratchMasks(std::array<u32, NumSecureDisableRegisters> &disables) { (SetSecureScratchMask<Info>(disables), ...); } template<size_t... Ix> constexpr ALWAYS_INLINE void SetSecureScratchReadWriteMasks(std::array<u32, NumSecureDisableRegisters> &disables) { (SetSecureScratchMask<LockInfo{Ix, LockMode::ReadWrite}>(disables), ...); } template<size_t... Ix> constexpr ALWAYS_INLINE void SetSecureScratchReadMasks(std::array<u32, NumSecureDisableRegisters> &disables) { (SetSecureScratchMask<LockInfo{Ix, LockMode::Read}>(disables), ...); } template<size_t... Ix> constexpr ALWAYS_INLINE void SetSecureScratchWriteMasks(std::array<u32, NumSecureDisableRegisters> &disables) { (SetSecureScratchMask<LockInfo{Ix, LockMode::Write}>(disables), ...); } template<SecureRegister Register> constexpr ALWAYS_INLINE std::array<u32, NumSecureDisableRegisters> GetSecureScratchMasks() { std::array<u32, NumSecureDisableRegisters> disables = {}; if constexpr ((Register & SecureRegister_Other) != 0) { constexpr std::array<u32, NumSecureDisableRegisters> NonOtherDisables = GetSecureScratchMasks<static_cast<SecureRegister>(~SecureRegister_Other)>(); for (size_t i = 0; i < NumSecureDisableRegisters; i++) { disables[i] |= ~NonOtherDisables[i]; } disables[0] &= 0x007FFFF0; } if constexpr ((Register & SecureRegister_DramParameters) != 0) { SetSecureScratchReadWriteMasks< 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 104, 105, 106, 107 >(disables); } if constexpr ((Register & SecureRegister_ResetVector) != 0) { SetSecureScratchReadWriteMasks<34, 35>(disables); } if constexpr ((Register & SecureRegister_Carveout) != 0) { SetSecureScratchReadWriteMasks<16, 39, 51, 55, 74, 75, 76, 77, 78, 99, 100, 101, 102, 103>(disables); } if constexpr ((Register & SecureRegister_CmacWrite) != 0) { SetSecureScratchWriteMasks<112, 113, 114, 115>(disables); } if constexpr ((Register & SecureRegister_CmacRead) != 0) { SetSecureScratchReadMasks<112, 113, 114, 115>(disables); } if constexpr ((Register & SecureRegister_KeySourceWrite) != 0) { SetSecureScratchWriteMasks<24, 25, 26, 27>(disables); } if constexpr ((Register & SecureRegister_KeySourceRead) != 0) { SetSecureScratchReadMasks<24, 25, 26, 27>(disables); } if constexpr ((Register & SecureRegister_Srk) != 0) { SetSecureScratchReadWriteMasks<4, 5, 6, 7>(disables); } return disables; } /* Validate that the secure scratch masks produced are correct. */ #include "pmc_secure_scratch_test.inc" ALWAYS_INLINE void LockBits(uintptr_t address, u32 mask) { reg::Write(address, reg::Read(address) | mask); } template<SecureRegister Register> ALWAYS_INLINE void SetSecureScratchMasks(uintptr_t address) { constexpr auto Masks = GetSecureScratchMasks<Register>(); if constexpr (Masks[0] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE , Masks[0]); } if constexpr (Masks[1] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE2, Masks[1]); } if constexpr (Masks[2] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE3, Masks[2]); } if constexpr (Masks[3] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE4, Masks[3]); } if constexpr (Masks[4] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE5, Masks[4]); } if constexpr (Masks[5] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE6, Masks[5]); } if constexpr (Masks[6] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE7, Masks[6]); } if constexpr (Masks[7] != 0) { LockBits(address + APBDEV_PMC_SEC_DISABLE8, Masks[7]); } static_assert(Masks.size() == 8); } template<SecureRegister Register> ALWAYS_INLINE bool TestSecureScratchMasks(uintptr_t address) { constexpr auto Masks = GetSecureScratchMasks<Register>(); if constexpr (Masks[0] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE ) & Masks[0]) != Masks[0]) { return false; } } if constexpr (Masks[1] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE2) & Masks[1]) != Masks[1]) { return false; } } if constexpr (Masks[2] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE3) & Masks[2]) != Masks[2]) { return false; } } if constexpr (Masks[3] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE4) & Masks[3]) != Masks[3]) { return false; } } if constexpr (Masks[4] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE5) & Masks[4]) != Masks[4]) { return false; } } if constexpr (Masks[5] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE6) & Masks[5]) != Masks[5]) { return false; } } if constexpr (Masks[6] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE7) & Masks[6]) != Masks[6]) { return false; } } if constexpr (Masks[7] != 0) { if ((reg::Read(address + APBDEV_PMC_SEC_DISABLE8) & Masks[7]) != Masks[7]) { return false; } } static_assert(Masks.size() == 8); return true; } NOINLINE void WriteRandomValueToRegister(uintptr_t offset) { /* Create an aligned buffer. */ util::AlignedBuffer<hw::DataCacheLineSize, sizeof(u32)> buf; /* Generate random bytes into it. */ se::GenerateRandomBytes(buf, sizeof(u32)); /* Read the random value. */ const u32 random = *reinterpret_cast<const u32 *>(static_cast<u8 *>(buf)); /* Get the address. */ const uintptr_t address = g_register_address + offset; /* Write the value. */ reg::Write(address, random); /* Verify it was written. */ AMS_ABORT_UNLESS(reg::Read(address) == random); } } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void InitializeRandomScratch() { /* Write random data to the scratch that contains the SRK. */ WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH4); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH5); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH6); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH7); /* Lock the SRK scratch. */ LockSecureRegister(SecureRegister_Srk); /* Write random data to the scratch used for tzram cmac. */ WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH112); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH113); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH114); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH115); /* Write random data to the scratch used for tzram key source. */ WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH24); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH25); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH26); WriteRandomValueToRegister(APBDEV_PMC_SECURE_SCRATCH27); /* Here, Nintendo locks the SRK scratch a second time. */ /* This may just be "to be sure". */ LockSecureRegister(SecureRegister_Srk); } void EnableWakeEventDetection() { /* Get the address. */ const uintptr_t address = g_register_address; /* Wait 75us, then enable event detection, then wait another 75us. */ util::WaitMicroSeconds(75); reg::ReadWrite(address + APBDEV_PMC_CNTRL2, PMC_REG_BITS_ENUM(CNTRL2_WAKE_DET_EN, ENABLE)); util::WaitMicroSeconds(75); /* Enable all wake events. */ reg::Write(address + APBDEV_PMC_WAKE_STATUS, 0xFFFFFFFFu); reg::Write(address + APBDEV_PMC_WAKE2_STATUS, 0xFFFFFFFFu); util::WaitMicroSeconds(75); } void ConfigureForSc7Entry() { /* Get the address. */ const uintptr_t address = g_register_address; /* Configure the bootrom to perform a warmboot. */ reg::Write(address + APBDEV_PMC_SCRATCH0, 0x1); /* Enable the TSC multiplier. */ reg::ReadWrite(address + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, ENABLE)); } void LockSecureRegister(SecureRegister reg) { /* Get the address. */ const uintptr_t address = g_register_address; /* Apply each mask. */ #define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { SetSecureScratchMasks<SecureRegister_##REG>(address); } } while (0) PMC_PROCESS_REG(Other); PMC_PROCESS_REG(DramParameters); PMC_PROCESS_REG(ResetVector); PMC_PROCESS_REG(Carveout); PMC_PROCESS_REG(CmacWrite); PMC_PROCESS_REG(CmacRead); PMC_PROCESS_REG(KeySourceWrite); PMC_PROCESS_REG(KeySourceRead); PMC_PROCESS_REG(Srk); #undef PMC_PROCESS_REG } LockState GetSecureRegisterLockState(SecureRegister reg) { bool all_valid = true; bool any_valid = false; /* Get the address. */ const uintptr_t address = g_register_address; /* Test each mask. */ #define PMC_PROCESS_REG(REG) do { if ((reg & SecureRegister_##REG) != 0) { const bool test = TestSecureScratchMasks<SecureRegister_##REG>(address); all_valid &= test; any_valid |= test; } } while (0) PMC_PROCESS_REG(Other); PMC_PROCESS_REG(DramParameters); PMC_PROCESS_REG(ResetVector); PMC_PROCESS_REG(Carveout); PMC_PROCESS_REG(CmacWrite); PMC_PROCESS_REG(CmacRead); PMC_PROCESS_REG(KeySourceWrite); PMC_PROCESS_REG(KeySourceRead); PMC_PROCESS_REG(Srk); #undef PMC_PROCESS_REG if (all_valid) { return LockState::Locked; } else if (any_valid) { return LockState::PartiallyLocked; } else { return LockState::NotLocked; } } } ================================================ FILE: libraries/libexosphere/source/pmc/pmc_secure_scratch_test.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ namespace test { constexpr inline auto Other = GetSecureScratchMasks<SecureRegister_Other>(); static_assert(Other[0] == 0x00700FF0u); static_assert(Other[1] == 0xFC000000u); static_assert(Other[2] == 0x3F0FFF00u); static_assert(Other[3] == 0x00000000u); static_assert(Other[4] == 0x00000000u); static_assert(Other[5] == 0x0C000000u); static_assert(Other[6] == 0x00000000u); static_assert(Other[7] == 0xFF00FF00u); constexpr inline auto DramParameters = GetSecureScratchMasks<SecureRegister_DramParameters>(); static_assert(DramParameters[0] == 0x00000000u); static_assert(DramParameters[1] == 0x03FCFFFFu); static_assert(DramParameters[2] == 0x00000000u); static_assert(DramParameters[3] == 0x3F3FFFFFu); static_assert(DramParameters[4] == 0xFFFFFFFFu); static_assert(DramParameters[5] == 0xF3FFC00Fu); static_assert(DramParameters[6] == 0x003FFFFFu); static_assert(DramParameters[7] == 0x000000FFu); constexpr inline auto ResetVector = GetSecureScratchMasks<SecureRegister_ResetVector>(); static_assert(ResetVector[0] == 0x00000000u); static_assert(ResetVector[1] == 0x00000000u); static_assert(ResetVector[2] == 0x00F00000u); static_assert(ResetVector[3] == 0x00000000u); static_assert(ResetVector[4] == 0x00000000u); static_assert(ResetVector[5] == 0x00000000u); static_assert(ResetVector[6] == 0x00000000u); static_assert(ResetVector[7] == 0x00000000u); constexpr inline auto CmacWrite = GetSecureScratchMasks<SecureRegister_CmacWrite>(); static_assert(CmacWrite[0] == 0x00000000u); static_assert(CmacWrite[1] == 0x00000000u); static_assert(CmacWrite[2] == 0x00000000u); static_assert(CmacWrite[3] == 0x00000000u); static_assert(CmacWrite[4] == 0x00000000u); static_assert(CmacWrite[5] == 0x00000000u); static_assert(CmacWrite[6] == 0x00000000u); static_assert(CmacWrite[7] == 0x00550000u); constexpr inline auto CmacRead = GetSecureScratchMasks<SecureRegister_CmacRead>(); static_assert(CmacRead[0] == 0x00000000u); static_assert(CmacRead[1] == 0x00000000u); static_assert(CmacRead[2] == 0x00000000u); static_assert(CmacRead[3] == 0x00000000u); static_assert(CmacRead[4] == 0x00000000u); static_assert(CmacRead[5] == 0x00000000u); static_assert(CmacRead[6] == 0x00000000u); static_assert(CmacRead[7] == 0x00AA0000u); constexpr inline auto KeySourceWrite = GetSecureScratchMasks<SecureRegister_KeySourceWrite>(); static_assert(KeySourceWrite[0] == 0x00000000u); static_assert(KeySourceWrite[1] == 0x00000000u); static_assert(KeySourceWrite[2] == 0x00000055u); static_assert(KeySourceWrite[3] == 0x00000000u); static_assert(KeySourceWrite[4] == 0x00000000u); static_assert(KeySourceWrite[5] == 0x00000000u); static_assert(KeySourceWrite[6] == 0x00000000u); static_assert(KeySourceWrite[7] == 0x00000000u); constexpr inline auto KeySourceRead = GetSecureScratchMasks<SecureRegister_KeySourceRead>(); static_assert(KeySourceRead[0] == 0x00000000u); static_assert(KeySourceRead[1] == 0x00000000u); static_assert(KeySourceRead[2] == 0x000000AAu); static_assert(KeySourceRead[3] == 0x00000000u); static_assert(KeySourceRead[4] == 0x00000000u); static_assert(KeySourceRead[5] == 0x00000000u); static_assert(KeySourceRead[6] == 0x00000000u); static_assert(KeySourceRead[7] == 0x00000000u); constexpr inline auto Srk = GetSecureScratchMasks<SecureRegister_Srk>(); static_assert(Srk[0] == 0x000FF000u); static_assert(Srk[1] == 0x00000000u); static_assert(Srk[2] == 0x00000000u); static_assert(Srk[3] == 0x00000000u); static_assert(Srk[4] == 0x00000000u); static_assert(Srk[5] == 0x00000000u); static_assert(Srk[6] == 0x00000000u); static_assert(Srk[7] == 0x00000000u); } ================================================ FILE: libraries/libexosphere/source/pmic/max77620.h ================================================ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. */ #ifndef _MFD_MAX77620_H_ #define _MFD_MAX77620_H_ #define MAX77620_I2C_ADDR 0x3C /* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */ #define MAX77620_REG_CNFGGLBL1 0x00 #define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) #define MAX77620_CNFGGLBL1_MPPLD (1 << 6) #define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) #define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) #define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) #define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) #define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) #define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E #define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) #define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) #define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) #define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) #define MAX77620_REG_CNFGGLBL2 0x01 #define MAX77620_REG_CNFGGLBL3 0x02 #define MAX77620_WDTC_MASK 0x3 #define MAX77620_WDTOFFC (1 << 4) #define MAX77620_WDTSLPC (1 << 3) #define MAX77620_WDTEN (1 << 2) #define MAX77620_TWD_MASK 0x3 #define MAX77620_TWD_2s 0x0 #define MAX77620_TWD_16s 0x1 #define MAX77620_TWD_64s 0x2 #define MAX77620_TWD_128s 0x3 #define MAX77620_REG_CNFG1_32K 0x03 #define MAX77620_CNFG1_32K_OUT0_EN (1 << 2) #define MAX77620_REG_CNFGBBC 0x04 #define MAX77620_CNFGBBC_ENABLE (1 << 0) #define MAX77620_CNFGBBC_CURRENT_MASK 0x06 #define MAX77620_CNFGBBC_CURRENT_SHIFT 1 #define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18 #define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3 #define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5) #define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0 #define MAX77620_CNFGBBC_RESISTOR_SHIFT 6 #define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT) #define MAX77620_REG_IRQTOP 0x05 #define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7) #define MAX77620_IRQ_TOP_SD_MASK (1 << 6) #define MAX77620_IRQ_TOP_LDO_MASK (1 << 5) #define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4) #define MAX77620_IRQ_TOP_RTC_MASK (1 << 3) #define MAX77620_IRQ_TOP_32K_MASK (1 << 2) #define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1) #define MAX77620_REG_INTLBT 0x06 #define MAX77620_REG_IRQTOPM 0x0D #define MAX77620_IRQ_LBM_MASK (1 << 3) #define MAX77620_IRQ_TJALRM1_MASK (1 << 2) #define MAX77620_IRQ_TJALRM2_MASK (1 << 1) #define MAX77620_REG_IRQSD 0x07 #define MAX77620_REG_IRQ_LVL2_L0_7 0x08 #define MAX77620_REG_IRQ_LVL2_L8 0x09 #define MAX77620_REG_IRQ_LVL2_GPIO 0x0A #define MAX77620_REG_ONOFFIRQ 0x0B #define MAX77620_REG_NVERC 0x0C #define MAX77620_REG_INTENLBT 0x0E #define MAX77620_GLBLM_MASK (1 << 0) #define MAX77620_REG_IRQMASKSD 0x0F #define MAX77620_REG_IRQ_MSK_L0_7 0x10 #define MAX77620_REG_IRQ_MSK_L8 0x11 #define MAX77620_REG_ONOFFIRQM 0x12 #define MAX77620_REG_STATLBT 0x13 #define MAX77620_REG_STATSD 0x14 #define MAX77620_REG_ONOFFSTAT 0x15 /* SD and LDO Registers */ #define MAX77620_REG_SD0 0x16 #define MAX77620_REG_SD1 0x17 #define MAX77620_REG_SD2 0x18 #define MAX77620_REG_SD3 0x19 #define MAX77620_REG_SD4 0x1A #define MAX77620_SDX_VOLT_MASK 0xFF #define MAX77620_SD0_VOLT_MASK 0x3F #define MAX77620_SD1_VOLT_MASK 0x7F #define MAX77620_LDO_VOLT_MASK 0x3F #define MAX77620_REG_DVSSD0 0x1B #define MAX77620_REG_DVSSD1 0x1C #define MAX77620_REG_SD0_CFG 0x1D #define MAX77620_REG_SD1_CFG 0x1E #define MAX77620_REG_SD2_CFG 0x1F #define MAX77620_REG_SD3_CFG 0x20 #define MAX77620_REG_SD4_CFG 0x21 #define MAX77620_REG_SD_CFG2 0x22 #define MAX77620_REG_LDO0_CFG 0x23 #define MAX77620_REG_LDO0_CFG2 0x24 #define MAX77620_REG_LDO1_CFG 0x25 #define MAX77620_REG_LDO1_CFG2 0x26 #define MAX77620_REG_LDO2_CFG 0x27 #define MAX77620_REG_LDO2_CFG2 0x28 #define MAX77620_REG_LDO3_CFG 0x29 #define MAX77620_REG_LDO3_CFG2 0x2A #define MAX77620_REG_LDO4_CFG 0x2B #define MAX77620_REG_LDO4_CFG2 0x2C #define MAX77620_REG_LDO5_CFG 0x2D #define MAX77620_REG_LDO5_CFG2 0x2E #define MAX77620_REG_LDO6_CFG 0x2F #define MAX77620_REG_LDO6_CFG2 0x30 #define MAX77620_REG_LDO7_CFG 0x31 #define MAX77620_REG_LDO7_CFG2 0x32 #define MAX77620_REG_LDO8_CFG 0x33 #define MAX77620_REG_LDO8_CFG2 0x34 #define MAX77620_LDO_POWER_MODE_MASK 0xC0 #define MAX77620_LDO_POWER_MODE_SHIFT 6 #define MAX77620_POWER_MODE_NORMAL 3 #define MAX77620_POWER_MODE_LPM 2 #define MAX77620_POWER_MODE_GLPM 1 #define MAX77620_POWER_MODE_DISABLE 0 #define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) #define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) #define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) #define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) #define MAX77620_LDO_CFG2_SS_MASK (1 << 0) #define MAX77620_LDO_CFG2_SS_FAST (1 << 0) #define MAX77620_LDO_CFG2_SS_SLOW 0 #define MAX77620_REG_LDO_CFG3 0x35 #define MAX77620_TRACK4_MASK (1 << 5) #define MAX77620_TRACK4_SHIFT 5 #define MAX77620_LDO_SLEW_RATE_MASK 0x1 #define MAX77620_REG_GPIO0 0x36 #define MAX77620_REG_GPIO1 0x37 #define MAX77620_REG_GPIO2 0x38 #define MAX77620_REG_GPIO3 0x39 #define MAX77620_REG_GPIO4 0x3A #define MAX77620_REG_GPIO5 0x3B #define MAX77620_REG_GPIO6 0x3C #define MAX77620_REG_GPIO7 0x3D #define MAX77620_REG_PUE_GPIO 0x3E #define MAX77620_REG_PDE_GPIO 0x3F #define MAX77620_REG_AME_GPIO 0x40 #define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) #define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) #define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) #define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) #define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) #define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) #define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) #define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) #define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) #define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) #define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) #define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) #define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) #define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) #define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) #define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) #define MAX77620_REG_ONOFFCNFG1 0x41 #define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) #define MAX77620_ONOFFCNFG1_MRT_MASK 0x38 #define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3 #define MAX77620_ONOFFCNFG1_SLPEN (1 << 2) #define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1) #define MAX20024_ONOFFCNFG1_CLRSE 0x18 #define MAX77620_REG_ONOFFCNFG2 0x42 #define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7) #define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6) #define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5) #define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2) #define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0) /* FPS Registers */ #define MAX77620_REG_FPS_CFG0 0x43 #define MAX77620_REG_FPS_CFG1 0x44 #define MAX77620_REG_FPS_CFG2 0x45 #define MAX77620_REG_FPS_LDO0 0x46 #define MAX77620_REG_FPS_LDO1 0x47 #define MAX77620_REG_FPS_LDO2 0x48 #define MAX77620_REG_FPS_LDO3 0x49 #define MAX77620_REG_FPS_LDO4 0x4A #define MAX77620_REG_FPS_LDO5 0x4B #define MAX77620_REG_FPS_LDO6 0x4C #define MAX77620_REG_FPS_LDO7 0x4D #define MAX77620_REG_FPS_LDO8 0x4E #define MAX77620_REG_FPS_SD0 0x4F #define MAX77620_REG_FPS_SD1 0x50 #define MAX77620_REG_FPS_SD2 0x51 #define MAX77620_REG_FPS_SD3 0x52 #define MAX77620_REG_FPS_SD4 0x53 #define MAX77620_REG_FPS_NONE 0 #define MAX77620_FPS_SRC_MASK 0xC0 #define MAX77620_FPS_SRC_SHIFT 6 #define MAX77620_FPS_PU_PERIOD_MASK 0x38 #define MAX77620_FPS_PU_PERIOD_SHIFT 3 #define MAX77620_FPS_PD_PERIOD_MASK 0x07 #define MAX77620_FPS_PD_PERIOD_SHIFT 0 /* Minimum and maximum FPS period time (in microseconds) are * different for MAX77620 and Max20024. */ #define MAX77620_FPS_COUNT 3 #define MAX77620_FPS_PERIOD_MIN_US 40 #define MAX20024_FPS_PERIOD_MIN_US 20 #define MAX77620_FPS_PERIOD_MAX_US 2560 #define MAX20024_FPS_PERIOD_MAX_US 5120 #define MAX77620_REG_FPS_GPIO1 0x54 #define MAX77620_REG_FPS_GPIO2 0x55 #define MAX77620_REG_FPS_GPIO3 0x56 #define MAX77620_FPS_TIME_PERIOD_MASK 0x38 #define MAX77620_FPS_TIME_PERIOD_SHIFT 3 #define MAX77620_FPS_EN_SRC_MASK 0x06 #define MAX77620_FPS_EN_SRC_SHIFT 1 #define MAX77620_FPS_ENFPS_SW_MASK 0x01 #define MAX77620_FPS_ENFPS_SW 0x01 #define MAX77620_REG_FPS_RSO 0x57 #define MAX77620_REG_CID0 0x58 #define MAX77620_REG_CID1 0x59 #define MAX77620_REG_CID2 0x5A #define MAX77620_REG_CID3 0x5B #define MAX77620_REG_CID4 0x5C #define MAX77620_REG_CID5 0x5D #define MAX77620_REG_DVSSD4 0x5E #define MAX20024_REG_MAX_ADD 0x70 #define MAX77620_CID_DIDM_MASK 0xF0 #define MAX77620_CID_DIDM_SHIFT 4 /* CNCG2SD */ #define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1) #define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2) /* Device Identification Metal */ #define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF) /* Device Indentification OTP */ #define MAX77620_CID5_DIDO(n) ((n) & 0xF) /* SD CNFG1 */ #define MAX77620_SD_SR_MASK 0xC0 #define MAX77620_SD_SR_SHIFT 6 #define MAX77620_SD_POWER_MODE_MASK 0x30 #define MAX77620_SD_POWER_MODE_SHIFT 4 #define MAX77620_SD_CFG1_ADE_MASK (1 << 3) #define MAX77620_SD_CFG1_ADE_DISABLE 0 #define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3) #define MAX77620_SD_FPWM_MASK 0x04 #define MAX77620_SD_FPWM_SHIFT 2 #define MAX77620_SD_FSRADE_MASK 0x01 #define MAX77620_SD_FSRADE_SHIFT 0 #define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2) #define MAX77620_SD_CFG1_FPWM_SD_SKIP 0 #define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2) #define MAX20024_SD_CFG1_MPOK_MASK (1 << 1) #define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0) #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) #define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) #define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3) #define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4) #define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5) #define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6) #define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7) /* Interrupts */ enum { MAX77620_IRQ_TOP_GLBL, /* Low-Battery */ MAX77620_IRQ_TOP_SD, /* SD power fail */ MAX77620_IRQ_TOP_LDO, /* LDO power fail */ MAX77620_IRQ_TOP_GPIO, /* TOP GPIO internal int to MAX77620 */ MAX77620_IRQ_TOP_RTC, /* RTC */ MAX77620_IRQ_TOP_32K, /* 32kHz oscillator */ MAX77620_IRQ_TOP_ONOFF, /* ON/OFF oscillator */ MAX77620_IRQ_LBT_MBATLOW, /* Thermal alarm status, > 120C */ MAX77620_IRQ_LBT_TJALRM1, /* Thermal alarm status, > 120C */ MAX77620_IRQ_LBT_TJALRM2, /* Thermal alarm status, > 140C */ }; /* GPIOs */ enum { MAX77620_GPIO0, MAX77620_GPIO1, MAX77620_GPIO2, MAX77620_GPIO3, MAX77620_GPIO4, MAX77620_GPIO5, MAX77620_GPIO6, MAX77620_GPIO7, MAX77620_GPIO_NR, }; /* FPS Source */ enum max77620_fps_src { MAX77620_FPS_SRC_0, MAX77620_FPS_SRC_1, MAX77620_FPS_SRC_2, MAX77620_FPS_SRC_NONE, MAX77620_FPS_SRC_DEF, }; enum max77620_chip_id { MAX77620, MAX20024, }; #endif /* _MFD_MAX77620_H_ */ ================================================ FILE: libraries/libexosphere/source/pmic/max7762x.h ================================================ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _MAX7762X_H_ #define _MAX7762X_H_ /* * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init *-------+---------------+---------+--------+------------+---------+------------------ * sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) * sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) * sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) * sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | * ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) * ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | * ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | */ /* * MAX77620_AME_GPIO: control GPIO modes (bits 0 - 7 correspond to GPIO0 - GPIO7); 0 -> GPIO, 1 -> alt-mode * MAX77620_REG_GPIOx: 0x9 sets output and enable */ /*! MAX77620 partitions. */ #define REGULATOR_SD0 0 #define REGULATOR_SD1 1 #define REGULATOR_SD2 2 #define REGULATOR_SD3 3 #define REGULATOR_LDO0 4 #define REGULATOR_LDO1 5 #define REGULATOR_LDO2 6 #define REGULATOR_LDO3 7 #define REGULATOR_LDO4 8 #define REGULATOR_LDO5 9 #define REGULATOR_LDO6 10 #define REGULATOR_LDO7 11 #define REGULATOR_LDO8 12 #define REGULATOR_MAX 12 #define MAX77621_CPU_I2C_ADDR 0x1B #define MAX77621_GPU_I2C_ADDR 0x1C #define MAX77621_VOUT_REG 0 #define MAX77621_VOUT_DVC_REG 1 #define MAX77621_CONTROL1_REG 2 #define MAX77621_CONTROL2_REG 3 /* MAX77621_VOUT */ #define MAX77621_VOUT_DISABLE (0 << 7) #define MAX77621_VOUT_ENABLE (1 << 7) #define MAX77621_VOUT_MASK 0x7F #define MAX77621_VOUT_0_95V 0x37 #define MAX77621_VOUT_1_09V 0x4F /* MAX77621_VOUT_DVC_DVS */ #define MAX77621_DVS_VOUT_MASK 0x7F /* MAX77621_CONTROL1 */ #define MAX77621_SNS_ENABLE (1 << 7) #define MAX77621_FPWM_EN_M (1 << 6) #define MAX77621_NFSR_ENABLE (1 << 5) #define MAX77621_AD_ENABLE (1 << 4) #define MAX77621_BIAS_ENABLE (1 << 3) #define MAX77621_FREQSHIFT_9PER (1 << 2) #define MAX77621_RAMP_12mV_PER_US 0x0 #define MAX77621_RAMP_25mV_PER_US 0x1 #define MAX77621_RAMP_50mV_PER_US 0x2 #define MAX77621_RAMP_200mV_PER_US 0x3 #define MAX77621_RAMP_MASK 0x3 /* MAX77621_CONTROL2 */ #define MAX77621_WDTMR_ENABLE (1 << 6) #define MAX77621_DISCH_ENBABLE (1 << 5) #define MAX77621_FT_ENABLE (1 << 4) #define MAX77621_T_JUNCTION_120 (1 << 7) #define MAX77621_CKKADV_TRIP_DISABLE 0xC #define MAX77621_CKKADV_TRIP_75mV_PER_US 0x0 #define MAX77621_CKKADV_TRIP_150mV_PER_US 0x4 #define MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 #define MAX77621_INDUCTOR_MIN_30_PER 0x0 #define MAX77621_INDUCTOR_NOMINAL 0x1 #define MAX77621_INDUCTOR_PLUS_30_PER 0x2 #define MAX77621_INDUCTOR_PLUS_60_PER 0x3 #endif ================================================ FILE: libraries/libexosphere/source/pmic/pmic_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "max77620.h" #include "max7762x.h" namespace ams::pmic { namespace { constexpr inline int I2cAddressEristaMax77621 = 0x1B; constexpr inline int I2cAddressMarikoMax77812_A = 0x31; constexpr inline int I2cAddressMarikoMax77812_B = 0x33; constexpr inline int I2cAddressMax77620Pmic = 0x3C; /* https://github.com/Atmosphere-NX/Atmosphere/blob/master/emummc/source/power/max77620.h */ /* https://github.com/Atmosphere-NX/Atmosphere/blob/master/emummc/source/power/max7762x.h */ /* TODO: Find datasheet, link to it instead. */ /* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */ /* This does not contain Max77621 documentation, though. */ constexpr inline int Max77620RegisterCnfgBbc = 0x04; constexpr inline int Max77620RegisterOnOffStat = 0x15; constexpr inline int Max77620RegisterSd0 = 0x16; constexpr inline int Max77620RegisterSd1 = 0x17; constexpr inline int Max77620RegisterCnfg2Sd = 0x22; constexpr inline int Max77620RegisterCnfg1Ldo8 = 0x33; constexpr inline int Max77620RegisterGpio0 = 0x36; constexpr inline int Max77620RegisterAmeGpio = 0x40; constexpr inline int Max77620RegisterOnOffCnfg1 = 0x41; constexpr inline int Max77620RegisterCnfgFps0 = 0x43; constexpr inline int Max77620RegisterCnfgFps1 = 0x44; constexpr inline int Max77620RegisterCnfgFps2 = 0x45; constexpr inline int Max77620RegisterFpsLdo4 = 0x4A; constexpr inline int Max77620RegisterFpsLdo8 = 0x4E; constexpr inline int Max77620RegisterFpsSd0 = 0x4F; constexpr inline int Max77620RegisterFpsSd1 = 0x50; constexpr inline int Max77620RegisterFpsSd3 = 0x52; constexpr inline int Max77620RegisterFpsGpio3 = 0x56; constexpr inline int Max77621RegisterVOut = 0x00; constexpr inline int Max77621RegisterVOutDvc = 0x01; constexpr inline int Max77621RegisterControl1 = 0x02; constexpr inline int Max77621RegisterControl2 = 0x03; /* https://datasheets.maximintegrated.com/en/ds/MAX77812.pdf */ constexpr inline int Max77812RegisterEnCtrl = 0x06; constexpr inline int Max77812RegisterM4VOut = 0x26; void Max77620EnableGpio(int gpio) { u8 val; /* Clear the AE for the GPIO */ if (i2c::Query(std::addressof(val), sizeof(val), i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterAmeGpio)) { val &= ~(1 << gpio); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterAmeGpio, val); } /* Set GPIO_DRV_PUSHPULL (bit 0), GPIO_OUTPUT_VAL_HIGH (bit 3). */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterGpio0 + gpio, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH); } void SetEnBitErista() { i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE); } void EnableVddCpuErista() { /* Enable GPIO 5. */ /* TODO: What does this control? */ Max77620EnableGpio(5); /* Configure Max77621 control registers. */ i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl1, MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterControl2, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); /* Configure Max77621 VOut to 0.95v */ i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOutDvc, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); } void DisableVddCpuErista() { /* Disable Max77621 VOut. */ i2c::SendByte(i2c::Port_5, I2cAddressEristaMax77621, Max77621RegisterVOut, MAX77621_VOUT_DISABLE); } int GetI2cAddressForMarikoMax77812(Regulator regulator) { switch (regulator) { case Regulator_Mariko_Max77812_A: return I2cAddressMarikoMax77812_A; case Regulator_Mariko_Max77812_B: return I2cAddressMarikoMax77812_B; AMS_UNREACHABLE_DEFAULT_CASE(); } } void SetEnBitMariko(Regulator regulator) { /* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */ i2c::SendByte(i2c::Port_5, GetI2cAddressForMarikoMax77812(regulator), Max77812RegisterEnCtrl, 0x40); } void EnableVddCpuMariko(Regulator regulator) { const int address = GetI2cAddressForMarikoMax77812(regulator); /* Set EN_M3_LPM to enable BUCK Master 3 low power mode. */ u8 ctrl; if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) { ctrl |= 0x40; i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl); } /* Set BUCK Master 4 output voltage to 110. */ i2c::SendByte(i2c::Port_5, address, Max77812RegisterM4VOut, 110); } void DisableVddCpuMariko(Regulator regulator) { const int address = GetI2cAddressForMarikoMax77812(regulator); /* Clear EN_M3_LPM to disable BUCK Master 3 low power mode. */ u8 ctrl; if (i2c::Query(std::addressof(ctrl), sizeof(ctrl), i2c::Port_5, address, Max77812RegisterEnCtrl)) { ctrl &= ~0x40; i2c::SendByte(i2c::Port_5, address, Max77812RegisterEnCtrl, ctrl); } } u8 GetPmicOnOffStat() { return i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffStat); } void ShutdownSystemImpl(bool reboot) { /* Get value, set or clear software reset mask. */ u8 on_off_2_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2); if (reboot) { on_off_2_val |= MAX77620_ONOFFCNFG2_SFT_RST_WK; } else { on_off_2_val &= ~(MAX77620_ONOFFCNFG2_SFT_RST_WK); } i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG2, on_off_2_val); /* Get value, set software reset mask. */ u8 on_off_1_val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1); on_off_1_val |= MAX77620_ONOFFCNFG1_SFT_RST; /* NOTE: Here, userland finalizes the battery on non-Calcio. */ if (fuse::GetHardwareType() != fuse::HardwareType_Calcio) { /* ... */ } /* Actually write the value to trigger shutdown/reset. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, MAX77620_REG_ONOFFCNFG1, on_off_1_val); } void SetBackupBatteryConfig() { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgBbc, 0x40); } void SetForcePowerOffTimeConfig() { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, 0x58); } void SetFlexiblePowerSequencer() { /* Configure FPS registers. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps0, 0x38); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps1, 0x3A); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfgFps2, 0x38); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsLdo4, 0x0F); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsLdo8, 0xC7); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd0, 0x4F); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd1, 0x29); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsSd3, 0x1B); i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterFpsGpio3, 0x22); } void SetVoltage(int reg, int mv) { const u8 v = ((mv - 600) * 1000) / 12500; i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, reg, v); } } void SetEnBit(Regulator regulator) { switch (regulator) { case Regulator_Erista_Max77621: return SetEnBitErista(); case Regulator_Mariko_Max77812_A: case Regulator_Mariko_Max77812_B: return SetEnBitMariko(regulator); AMS_UNREACHABLE_DEFAULT_CASE(); } } void EnableVddCpu(Regulator regulator) { switch (regulator) { case Regulator_Erista_Max77621: return EnableVddCpuErista(); case Regulator_Mariko_Max77812_A: case Regulator_Mariko_Max77812_B: return EnableVddCpuMariko(regulator); AMS_UNREACHABLE_DEFAULT_CASE(); } } void DisableVddCpu(Regulator regulator) { switch (regulator) { case Regulator_Erista_Max77621: return DisableVddCpuErista(); case Regulator_Mariko_Max77812_A: case Regulator_Mariko_Max77812_B: return DisableVddCpuMariko(regulator); AMS_UNREACHABLE_DEFAULT_CASE(); } } void EnableSleep() { /* Get the current onoff cfg. */ u8 cnfg = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1); /* Set SlpEn. */ cnfg |= MAX77620_ONOFFCNFG1_SLPEN; /* Write the new cfg. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterOnOffCnfg1, cnfg); } void ShutdownSystem(bool reboot) { ShutdownSystemImpl(reboot); /* Allow up to 5 seconds for shutdown/reboot to take place. */ util::WaitMicroSeconds(5'000'000ul); AMS_ABORT("Shutdown failed"); } void PowerOff() { ShutdownSystemImpl(false); } bool IsAcOk() { return (GetPmicOnOffStat() & (1 << 1)) != 0; } bool IsPowerButtonPressed() { return (GetPmicOnOffStat() & (1 << 2)) != 0; } void SetSystemSetting(fuse::SocType soc_type) { SetBackupBatteryConfig(); SetForcePowerOffTimeConfig(); if (soc_type == fuse::SocType_Erista) { SetFlexiblePowerSequencer(); } } void EnableVddCore(fuse::SocType soc_type) { if (soc_type == fuse::SocType_Erista) { SetVoltage(Max77620RegisterSd0, 1125); } else /* if (soc_type == fuse::SocType_Mariko) */ { SetVoltage(Max77620RegisterSd0, 1050); } } void EnableLdo8() { i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfg1Ldo8, 0xE8); } void EnableVddMemory(fuse::SocType soc_type) { /* Disable remote sense for Sd1. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Pmic, Max77620RegisterCnfg2Sd, 0x05); /* On Erista, set Sd1 voltage. */ if (soc_type == fuse::SocType_Erista) { SetVoltage(Max77620RegisterSd1, 1100); } } } ================================================ FILE: libraries/libexosphere/source/rtc/max77620-rtc.h ================================================ /* * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _MFD_MAX77620_RTC_H_ #define _MFD_MAX77620_RTC_H_ #define MAX77620_RTC_I2C_ADDR 0x68 #define MAX77620_RTC_NR_TIME_REGS 7 #define MAX77620_RTC_CONTROLM_REG 0x02 #define MAX77620_RTC_CONTROL_REG 0x03 #define MAX77620_RTC_BIN_FORMAT (1 << 0) #define MAX77620_RTC_24H (1 << 1) #define MAX77620_RTC_UPDATE0_REG 0x04 #define MAX77620_RTC_WRITE_UPDATE (1 << 0) #define MAX77620_RTC_READ_UPDATE (1 << 4) #define MAX77620_RTC_SEC_REG 0x07 #define MAX77620_RTC_MIN_REG 0x08 #define MAX77620_RTC_HOUR_REG 0x09 #define MAX77620_RTC_HOUR_PM_MASK (1 << 6) #define MAX77620_RTC_WEEKDAY_REG 0x0A #define MAX77620_RTC_MONTH_REG 0x0B #define MAX77620_RTC_YEAR_REG 0x0C #define MAX77620_RTC_DATE_REG 0x0D #define MAX77620_ALARM1_SEC_REG 0x0E #define MAX77620_ALARM1_MIN_REG 0x0F #define MAX77620_ALARM1_HOUR_REG 0x10 #define MAX77620_ALARM1_WEEKDAY_REG 0x11 #define MAX77620_ALARM1_MONTH_REG 0x12 #define MAX77620_ALARM1_YEAR_REG 0x13 #define MAX77620_ALARM1_DATE_REG 0x14 #define MAX77620_ALARM2_SEC_REG 0x15 #define MAX77620_ALARM2_MIN_REG 0x16 #define MAX77620_ALARM2_HOUR_REG 0x17 #define MAX77620_ALARM2_WEEKDAY_REG 0x18 #define MAX77620_ALARM2_MONTH_REG 0x19 #define MAX77620_ALARM2_YEAR_REG 0x1A #define MAX77620_ALARM2_DATE_REG 0x1B #define MAX77620_RTC_ALARM_EN_MASK (1 << 7) #endif /* _MFD_MAX77620_RTC_H_ */ ================================================ FILE: libraries/libexosphere/source/rtc/rtc_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "max77620-rtc.h" namespace ams::rtc { namespace { constexpr inline int I2cAddressMax77620Rtc = 0x68; /* TODO: Find datasheet, link to it instead. */ /* NOTE: Tentatively, Max77620 "mostly" matches https://datasheets.maximintegrated.com/en/ds/MAX77863.pdf. */ constexpr inline int Max77620RtcRegisterUpdate0 = 0x04; constexpr inline int Max77620RtcRegisterAlarmStart = 0x0E; constexpr inline int Max77620RtcRegisterAlarm1Sec = 0x0E; constexpr inline int Max77620RtcRegisterAlarm1Min = 0x0F; constexpr inline int Max77620RtcRegisterAlarm1Hour = 0x10; constexpr inline int Max77620RtcRegisterAlarm1Weekday = 0x11; constexpr inline int Max77620RtcRegisterAlarm1Month = 0x12; constexpr inline int Max77620RtcRegisterAlarm1Year = 0x13; constexpr inline int Max77620RtcRegisterAlarm1Date = 0x14; constexpr inline int Max77620RtcRegisterAlarm2Sec = 0x15; constexpr inline int Max77620RtcRegisterAlarm2Min = 0x16; constexpr inline int Max77620RtcRegisterAlarm2Hour = 0x17; constexpr inline int Max77620RtcRegisterAlarm2Weekday = 0x18; constexpr inline int Max77620RtcRegisterAlarm2Month = 0x19; constexpr inline int Max77620RtcRegisterAlarm2Year = 0x1A; constexpr inline int Max77620RtcRegisterAlarm2Date = 0x1B; constexpr inline int Max77620RtcRegisterAlarmLast = 0x1B; } void StopAlarm() { /* Begin update. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_READ_UPDATE); /* Clear ALARM_EN for all alarm registers. */ for (auto reg = Max77620RtcRegisterAlarmStart; reg <= Max77620RtcRegisterAlarmLast; ++reg) { u8 val = i2c::QueryByte(i2c::Port_5, I2cAddressMax77620Rtc, reg); val &= ~MAX77620_RTC_ALARM_EN_MASK; i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, reg, val); } /* End update. */ i2c::SendByte(i2c::Port_5, I2cAddressMax77620Rtc, Max77620RtcRegisterUpdate0, MAX77620_RTC_WRITE_UPDATE); } } ================================================ FILE: libraries/libexosphere/source/se/se_aes.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { constexpr inline int AesKeySizeMax = 256 / BITSIZEOF(u8); enum AesMode { AesMode_Aes128 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY128 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY128 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, AesMode_Aes192 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY192 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY192 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, AesMode_Aes256 = ((SE_CONFIG_ENC_MODE_AESMODE_KEY256 << SE_CONFIG_ENC_MODE_OFFSET) | (SE_CONFIG_DEC_MODE_AESMODE_KEY256 << SE_CONFIG_DEC_MODE_OFFSET)) >> SE_CONFIG_DEC_MODE_OFFSET, }; enum MemoryInterface { MemoryInterface_Ahb = SE_CRYPTO_CONFIG_MEMIF_AHB, MemoryInterface_Mc = SE_CRYPTO_CONFIG_MEMIF_MCCIF, }; constexpr inline u32 AesConfigEcb = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); constexpr inline u32 AesConfigCtr = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 1), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, LINEAR_CTR), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); constexpr inline u32 AesConfigCmac = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, ENABLE)); constexpr inline u32 AesConfigCbcEncrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); constexpr inline u32 AesConfigCbcDecrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_PREV_MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); void SetConfig(volatile SecurityEngineRegisters *SE, bool encrypt, SE_CONFIG_DST dst) { reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM_SEL(CONFIG_ENC_ALG, encrypt, AES_ENC, NOP), SE_REG_BITS_ENUM_SEL(CONFIG_DEC_ALG, encrypt, NOP, AES_DEC), SE_REG_BITS_VALUE (CONFIG_DST, dst)); } void SetAesConfig(volatile SecurityEngineRegisters *SE, int slot, bool encrypt, u32 config) { const u32 encoded = reg::Encode(SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB), SE_REG_BITS_VALUE (CRYPTO_CONFIG_KEY_INDEX, slot), SE_REG_BITS_ENUM_SEL(CRYPTO_CONFIG_CORE_SEL, encrypt, ENCRYPT, DECRYPT)); reg::Write(SE->SE_CRYPTO_CONFIG, (config | encoded)); } void SetBlockCount(volatile SecurityEngineRegisters *SE, int count) { reg::Write(SE->SE_CRYPTO_LAST_BLOCK, count - 1); } void UpdateAesMode(volatile SecurityEngineRegisters *SE, AesMode mode) { reg::ReadWrite(SE->SE_CONFIG, REG_BITS_VALUE(16, 16, mode)); } void UpdateMemoryInterface(volatile SecurityEngineRegisters *SE, MemoryInterface memif) { reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_VALUE(CRYPTO_CONFIG_MEMIF, memif)); } void SetCounter(volatile SecurityEngineRegisters *SE, const void *ctr) { const u32 *ctr_32 = reinterpret_cast<const u32 *>(ctr); /* Copy the input ctr to the linear CTR registers. */ reg::Write(SE->SE_CRYPTO_LINEAR_CTR[0], util::LoadLittleEndian(ctr_32 + 0)); reg::Write(SE->SE_CRYPTO_LINEAR_CTR[1], util::LoadLittleEndian(ctr_32 + 1)); reg::Write(SE->SE_CRYPTO_LINEAR_CTR[2], util::LoadLittleEndian(ctr_32 + 2)); reg::Write(SE->SE_CRYPTO_LINEAR_CTR[3], util::LoadLittleEndian(ctr_32 + 3)); } void SetAesKeyIv(volatile SecurityEngineRegisters *SE, int slot, const void *iv, size_t iv_size) { AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); AMS_ABORT_UNLESS(iv_size <= AesBlockSize); /* Set each iv word in order. */ const u32 *iv_u32 = static_cast<const u32 *>(iv); const int num_words = iv_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { /* Select the keyslot. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); /* Set the iv word. */ SE->SE_CRYPTO_KEYTABLE_DATA = *(iv_u32++); } } void SetEncryptedAesKey(int dst_slot, int kek_slot, const void *key, size_t key_size, AesMode mode) { AMS_ABORT_UNLESS(key_size <= AesKeySizeMax); AMS_ABORT_UNLESS(0 <= dst_slot && dst_slot < AesKeySlotCount); AMS_ABORT_UNLESS(0 <= kek_slot && kek_slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Configure for single AES ECB decryption to key table. */ SetConfig(SE, false, SE_CONFIG_DST_KEYTABLE); SetAesConfig(SE, kek_slot, false, AesConfigEcb); UpdateAesMode(SE, mode); SetBlockCount(SE, 1); /* Select the destination keyslot. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, dst_slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3)); /* Ensure that the se sees the keydata we want it to. */ hw::FlushDataCache(key, key_size); hw::DataSynchronizationBarrierInnerShareable(); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, key, key_size); } void EncryptAes(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) { /* If nothing to decrypt, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(dst_size == AesBlockSize); AMS_ABORT_UNLESS(src_size == AesBlockSize); AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Configure for AES-ECB encryption to memory. */ SetConfig(SE, true, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, true, AesConfigEcb); UpdateAesMode(SE, mode); /* Execute the operation. */ ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size); } void ExpandSubkey(u8 *subkey) { /* Shift everything left one bit. */ u8 prev = 0; for (int i = AesBlockSize - 1; i >= 0; --i) { const u8 top = (subkey[i] >> 7); subkey[i] = ((subkey[i] << 1) | prev); prev = top; } /* And xor with Rb if necessary. */ if (prev != 0) { subkey[AesBlockSize - 1] ^= 0x87; } } void ExpandSubkeyLittleEndian(u8 *subkey) { /* Shift everything left one bit. */ u8 prev = 0; for (size_t i = 0; i < AesBlockSize; ++i) { const u8 top = (subkey[i] >> 7); subkey[i] = ((subkey[i] << 1) | prev); prev = top; } /* And xor with Rb if necessary. */ if (prev != 0) { subkey[0] ^= 0x87; } } void GetCmacResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) { const int num_words = dst_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { reg::Write(static_cast<u32 *>(dst) + i, reg::Read(SE->SE_HASH_RESULT[i])); } } void ComputeAesCmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, AesMode mode) { /* Validate input. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Determine mac extents. */ const int num_blocks = util::DivideUp(src_size, AesBlockSize); const size_t last_block_size = (src_size == 0) ? 0 : (src_size - ((num_blocks - 1) * AesBlockSize)); /* Create subkey. */ u8 subkey[AesBlockSize]; { /* Encrypt zeroes. */ std::memset(subkey, 0, sizeof(subkey)); EncryptAes(subkey, sizeof(subkey), slot, subkey, sizeof(subkey), mode); /* Expand. */ ExpandSubkey(subkey); /* Account for last block. */ if (last_block_size != AesBlockSize) { ExpandSubkey(subkey); } } /* Configure for AES-CMAC. */ SetConfig(SE, true, SE_CONFIG_DST_HASH_REG); SetAesConfig(SE, slot, true, AesConfigCmac); UpdateAesMode(SE, mode); /* Set the IV to zero. */ for (int i = 0; i < 4; ++i) { /* Select the keyslot. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); /* Set the iv word. */ SE->SE_CRYPTO_KEYTABLE_DATA = 0; } /* Handle blocks before the last. */ if (num_blocks > 1) { SetBlockCount(SE, num_blocks - 1); ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size); reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM(CRYPTO_CONFIG_IV_SELECT, UPDATED)); } /* Handle the last block. */ { SetBlockCount(SE, 1); /* Create the last block. */ u8 last_block[AesBlockSize]; if (last_block_size < sizeof(last_block)) { std::memset(last_block, 0, sizeof(last_block)); last_block[last_block_size] = 0x80; } std::memcpy(last_block, static_cast<const u8 *>(src) + src_size - last_block_size, last_block_size); /* Xor with the subkey. */ for (size_t i = 0; i < AesBlockSize; ++i) { last_block[i] ^= subkey[i]; } /* Ensure the SE sees correct data. */ hw::FlushDataCache(last_block, sizeof(last_block)); hw::DataSynchronizationBarrierInnerShareable(); ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, last_block, sizeof(last_block)); } /* Get the output. */ GetCmacResult(SE, dst, dst_size); } void EncryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) { /* If nothing to encrypt, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Determine extents. */ const size_t num_blocks = src_size / AesBlockSize; const size_t aligned_size = num_blocks * AesBlockSize; AMS_ABORT_UNLESS(src_size == aligned_size); /* Configure for aes-cbc encryption. */ SetConfig(SE, true, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, true, AesConfigCbcEncrypt); UpdateAesMode(SE, mode); /* Set the iv. */ SetAesKeyIv(SE, slot, iv, iv_size); /* Set the block count. */ SetBlockCount(SE, num_blocks); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size); } void DecryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) { /* If nothing to decrypt, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Determine extents. */ const size_t num_blocks = src_size / AesBlockSize; const size_t aligned_size = num_blocks * AesBlockSize; AMS_ABORT_UNLESS(src_size == aligned_size); /* Configure for aes-cbc encryption. */ SetConfig(SE, false, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, false, AesConfigCbcDecrypt); UpdateAesMode(SE, mode); /* Set the iv. */ SetAesKeyIv(SE, slot, iv, iv_size); /* Set the block count. */ SetBlockCount(SE, num_blocks); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size); } void XorWithXtsTweak(void *dst, size_t dst_size, const void *src, size_t src_size, const void *base_tweak) { /* Copy tweak. */ u8 tweak[se::AesBlockSize]; std::memcpy(tweak, base_tweak, sizeof(tweak)); /* Perform xor. */ u8 *dst_u8 = static_cast<u8 *>(dst); const u8 *src_u8 = static_cast<const u8 *>(src); const size_t num_blocks = std::min<size_t>(dst_size, src_size) / sizeof(tweak); for (size_t i = 0; i < num_blocks; ++i) { for (size_t j = 0; j < sizeof(tweak); ++j) { dst_u8[j] = src_u8[j] ^ tweak[j]; } dst_u8 += sizeof(tweak); src_u8 += sizeof(tweak); ExpandSubkeyLittleEndian(tweak); } } void DecryptAesXts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector, AesMode mode) { /* If nothing to decrypt, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(util::IsAligned(dst_size, AesBlockSize)); AMS_ABORT_UNLESS(util::IsAligned(src_size, AesBlockSize)); AMS_ABORT_UNLESS(0 <= slot_enc && slot_enc < AesKeySlotCount); AMS_ABORT_UNLESS(0 <= slot_tweak && slot_tweak < AesKeySlotCount); /* Generate tweak. */ u32 base_tweak[se::AesBlockSize / sizeof(u32)] = {}; base_tweak[util::size(base_tweak) - 1] = util::ConvertToBigEndian<u32>(static_cast<u32>(sector)); if constexpr (sizeof(sector) > sizeof(u32)) { static_assert(sizeof(sector) <= sizeof(u64)); base_tweak[util::size(base_tweak) - 2] = util::ConvertToBigEndian<u32>(static_cast<u32>(sector >> BITSIZEOF(u32))); } se::EncryptAes128(base_tweak, sizeof(base_tweak), slot_tweak, base_tweak, sizeof(base_tweak)); /* Xor all data. */ XorWithXtsTweak(dst, dst_size, src, src_size, base_tweak); /* Ensure the SE sees correct data. */ hw::FlushDataCache(dst, dst_size); /* Decrypt all data. */ { /* Get the engine. */ auto *SE = GetRegisters(); /* Determine extents. */ const size_t num_blocks = dst_size / AesBlockSize; /* Configure for AES-ECB decryption to memory. */ SetConfig(SE, false, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot_enc, false, AesConfigEcb); UpdateAesMode(SE, mode); /* Set the block count. */ SetBlockCount(SE, num_blocks); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, dst, dst_size); /* Ensure the cpu sees correct data. */ hw::InvalidateDataCache(dst, dst_size); } /* Xor all data. */ XorWithXtsTweak(dst, dst_size, dst, dst_size, base_tweak); } void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) { /* If nothing to decrypt, succeed. */ if (size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Configure for the specific operation. */ SetConfig(SE, encrypt, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, encrypt, config); UpdateMemoryInterface(SE, MemoryInterface_Mc); /* Configure the number of blocks. */ const int num_blocks = size / AesBlockSize; SetBlockCount(SE, num_blocks); /* Set the done handler. */ SetDoneHandler(SE, handler); /* Start the raw operation. */ StartOperationRaw(SE, SE_OPERATION_OP_START, out_ll_address, in_ll_address); } void ClearAesKeySlot(volatile SecurityEngineRegisters *SE, int slot) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); for (int i = 0; i < 16; ++i) { /* Select the keyslot. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, i)); /* Write the data. */ SE->SE_CRYPTO_KEYTABLE_DATA = 0; } } } void ClearAesKeySlot(int slot) { /* Clear the slot in SE1. */ ClearAesKeySlot(GetRegisters(), slot); } void ClearAesKeySlot2(int slot) { /* Clear the slot in SE2. */ ClearAesKeySlot(GetRegisters2(), slot); } void ClearAesKeyIv(int slot) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Set each iv word in order. */ for (int i = 0; i < 4; ++i) { /* Select the keyslot original iv. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); /* Set the iv word. */ SE->SE_CRYPTO_KEYTABLE_DATA = 0; /* Select the keyslot updated iv. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, UPDATED_IV), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); /* Set the iv word. */ SE->SE_CRYPTO_KEYTABLE_DATA = 0; } } void LockAesKeySlot(int slot, u32 flags) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Set non per-key flags. */ if ((flags & ~KeySlotLockFlags_PerKey) != 0) { /* KeySlotLockFlags_DstKeyTableOnly is Mariko-only. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { reg::ReadWrite(SE->SE_CRYPTO_KEYTABLE_ACCESS[slot], REG_BITS_VALUE(0, 7, ~flags), REG_BITS_VALUE(7, 1, ((flags & KeySlotLockFlags_DstKeyTableOnly) != 0) ? 1 : 0)); } else { reg::ReadWrite(SE->SE_CRYPTO_KEYTABLE_ACCESS[slot], REG_BITS_VALUE(0, 7, ~flags)); } } /* Set per-key flag. */ if ((flags & KeySlotLockFlags_PerKey) != 0) { reg::ReadWrite(SE->SE_CRYPTO_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0)); } } void SetAesKey(int slot, const void *key, size_t key_size) { /* Validate the key slot and key size. */ AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); AMS_ABORT_UNLESS(key_size <= AesKeySizeMax); /* Get the engine. */ auto *SE = GetRegisters(); /* Set each key word in order. */ const u32 *key_u32 = static_cast<const u32 *>(key); const int num_words = key_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { /* Select the keyslot. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot), SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, KEY), SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i)); /* Set the key word. */ SE->SE_CRYPTO_KEYTABLE_DATA = *(key_u32++); } } void SetEncryptedAesKey128(int dst_slot, int kek_slot, const void *key, size_t key_size) { return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes128); } void SetEncryptedAesKey256(int dst_slot, int kek_slot, const void *key, size_t key_size) { return SetEncryptedAesKey(dst_slot, kek_slot, key, key_size, AesMode_Aes256); } void EncryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { return EncryptAes(dst, dst_size, slot, src, src_size, AesMode_Aes128); } void DecryptAes128(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { /* If nothing to decrypt, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(dst_size == AesBlockSize); AMS_ABORT_UNLESS(src_size == AesBlockSize); AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Configure for AES-ECB decryption to memory. */ SetConfig(SE, false, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, false, AesConfigEcb); ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_size); } void ComputeAes128Ctr(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { /* If nothing to do, succeed. */ if (src_size == 0) { return; } /* Validate input. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Determine how many full blocks we can operate on. */ const size_t num_blocks = src_size / AesBlockSize; const size_t aligned_size = num_blocks * AesBlockSize; const size_t fractional = src_size - aligned_size; /* Here Nintendo writes 1 to SE_SPARE. It's unclear why they do this, but we will do so as well. */ SE->SE_SPARE = 0x1; /* Configure for AES-CTR encryption/decryption to memory. */ SetConfig(SE, true, SE_CONFIG_DST_MEMORY); SetAesConfig(SE, slot, true, AesConfigCtr); /* Set the counter. */ SetCounter(SE, iv); /* Process as many aligned blocks as we can. */ if (aligned_size > 0) { /* Configure the engine to process the right number of blocks. */ SetBlockCount(SE, num_blocks); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size); /* Synchronize around this point. */ hw::DataSynchronizationBarrierInnerShareable(); } /* Process a single block to output. */ if (fractional > 0 && dst_size > aligned_size) { const size_t copy_size = std::min(fractional, dst_size - aligned_size); ExecuteOperationSingleBlock(SE, static_cast<u8 *>(dst) + aligned_size, copy_size, static_cast<const u8 *>(src) + aligned_size, fractional); } } void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes128); } void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes256); } void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128); } void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256); } void DecryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128); } void DecryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) { return DecryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256); } void DecryptAes128Xts(void *dst, size_t dst_size, int slot_enc, int slot_tweak, const void *src, size_t src_size, size_t sector) { return DecryptAesXts(dst, dst_size, slot_enc, slot_tweak, src, src_size, sector, AesMode_Aes128); } void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) { /* Validate the iv. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); /* Get the registers. */ volatile auto *SE = GetRegisters(); /* Set the iv. */ SetAesKeyIv(SE, slot, iv, iv_size); /* Perform the asynchronous aes operation. */ ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcEncrypt, true, SE); } void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) { /* Validate the iv. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); /* Get the registers. */ volatile auto *SE = GetRegisters(); /* Set the iv. */ SetAesKeyIv(SE, slot, iv, iv_size); /* Perform the asynchronous aes operation. */ ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcDecrypt, false, SE); } void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) { /* Validate the iv. */ AMS_ABORT_UNLESS(iv_size == AesBlockSize); /* Get the registers. */ volatile auto *SE = GetRegisters(); /* Here Nintendo writes 1 to SE_SPARE. It's unclear why they do this, but we will do so as well. */ SE->SE_SPARE = 0x1; /* Set the counter. */ SetCounter(SE, iv); /* Perform the asynchronous aes operation. */ ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCtr, true, SE); } } ================================================ FILE: libraries/libexosphere/source/se/se_execute.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { struct LinkedListEntry { u32 zero; u32 address; u32 size; }; static_assert(util::is_pod<LinkedListEntry>::value); static_assert(sizeof(LinkedListEntry) == 0xC); uintptr_t GetPhysicalAddress(const void *ptr) { const uintptr_t virt_address = reinterpret_cast<uintptr_t>(ptr); #if defined(ATMOSPHERE_ARCH_ARM64) u64 phys_address; __asm__ __volatile__("at s1e3r, %[virt]; mrs %[phys], par_el1" : [phys]"=r"(phys_address) : [virt]"r"(virt_address) : "memory", "cc"); return (phys_address & 0x0000FFFFFFFFF000ul) | (virt_address & 0x0000000000000FFFul); #elif defined(ATMOSPHERE_ARCH_ARM) return virt_address; #else #error "Unknown architecture for Tegra Security Engine physical address translation" #endif } constexpr void SetLinkedListEntry(LinkedListEntry *entry, const void *ptr, size_t size) { /* Clear the zero field. */ entry->zero = 0; /* Set the address. */ if (ptr != nullptr) { entry->address = GetPhysicalAddress(ptr); entry->size = static_cast<u32>(size); } else { entry->address = 0; entry->size = 0; } } void StartOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op) { /* Write back the current values of the error and interrupt status. */ reg::Write(SE->SE_ERR_STATUS, reg::Read(SE->SE_ERR_STATUS)); reg::Write(SE->SE_INT_STATUS, reg::Read(SE->SE_INT_STATUS)); /* Write the operation. */ reg::Write(SE->SE_OPERATION, SE_REG_BITS_VALUE(OPERATION_OP, op)); } void EnsureOperationStarted(volatile SecurityEngineRegisters *SE) { /* Read the operation register to make sure our write takes. */ reg::Read(SE->SE_OPERATION); hw::DataSynchronizationBarrierInnerShareable(); } void WaitForOperationComplete(volatile SecurityEngineRegisters *SE) { /* Spin until the operation is done. */ while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, CLEAR))) { /* ... */ } /* Check for operation success. */ ValidateAesOperationResult(SE); } } void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size) { /* Set the linked list entries. */ LinkedListEntry src_entry; LinkedListEntry dst_entry; SetLinkedListEntry(std::addressof(src_entry), src, src_size); SetLinkedListEntry(std::addressof(dst_entry), dst, dst_size); /* Ensure the linked list entry data is seen correctly. */ hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry)); hw::FlushDataCache(std::addressof(dst_entry), sizeof(dst_entry)); hw::DataSynchronizationBarrierInnerShareable(); /* Configure the linked list addresses. */ reg::Write(SE->SE_IN_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(src_entry)))); reg::Write(SE->SE_OUT_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(dst_entry)))); /* Start the operation. */ StartOperation(SE, op); /* Wait for the operation to complete. */ WaitForOperationComplete(SE); } void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) { /* Validate sizes. */ AMS_ABORT_UNLESS(dst_size <= AesBlockSize); AMS_ABORT_UNLESS(src_size <= AesBlockSize); /* Set the block count to 1. */ reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); /* Create an aligned buffer. */ util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> aligned; std::memcpy(aligned, src, src_size); hw::FlushDataCache(aligned, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, aligned, AesBlockSize, aligned, AesBlockSize); /* Ensure that the CPU will see the correct output. */ hw::DataSynchronizationBarrierInnerShareable(); hw::FlushDataCache(aligned, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Copy the output to the destination. */ std::memcpy(dst, aligned, dst_size); } void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size) { /* Set the linked list entry. */ LinkedListEntry src_entry; SetLinkedListEntry(std::addressof(src_entry), src, src_size); /* Ensure the linked list entry data is seen correctly. */ hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry)); hw::DataSynchronizationBarrierInnerShareable(); /* Configure the linked list addresses. */ reg::Write(SE->SE_IN_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(src_entry)))); /* Start the operation. */ StartOperation(SE, SE_OPERATION_OP_START); /* Ensure the operation is started. */ EnsureOperationStarted(SE); } void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address) { /* Configure the linked list addresses. */ reg::Write(SE->SE_IN_LL_ADDR, in_ll_address); reg::Write(SE->SE_OUT_LL_ADDR, out_ll_address); /* Start the operation. */ StartOperation(SE, op); /* Ensure the operation is started. */ EnsureOperationStarted(SE); } void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE) { /* Ensure no error occurred. */ AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR))); /* Ensure the security engine is idle. */ AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))); /* Ensure there is no error status. */ AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0); } void ValidateAesOperationResult() { return ValidateAesOperationResult(GetRegisters()); } } ================================================ FILE: libraries/libexosphere/source/se/se_execute.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_registers.hpp" namespace ams::se { volatile SecurityEngineRegisters *GetRegisters(); volatile SecurityEngineRegisters *GetRegisters2(); void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size); void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size); void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size); void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address); void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler); void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE); } ================================================ FILE: libraries/libexosphere/source/se/se_hash.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { void SetMessageSize(volatile SecurityEngineRegisters *SE, size_t src_size) { /* Set the message size. */ reg::Write(SE->SE_SHA_MSG_LENGTH[0], src_size * BITSIZEOF(u8)); reg::Write(SE->SE_SHA_MSG_LENGTH[1], 0); reg::Write(SE->SE_SHA_MSG_LENGTH[2], 0); reg::Write(SE->SE_SHA_MSG_LENGTH[3], 0); /* Set the message remaining size. */ reg::Write(SE->SE_SHA_MSG_LEFT[0], src_size * BITSIZEOF(u8)); reg::Write(SE->SE_SHA_MSG_LEFT[1], 0); reg::Write(SE->SE_SHA_MSG_LEFT[2], 0); reg::Write(SE->SE_SHA_MSG_LEFT[3], 0); } void GetHashResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) { /* Copy out the words. */ const int num_words = dst_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { const u32 word = reg::Read(SE->SE_HASH_RESULT[i]); util::StoreBigEndian(static_cast<u32 *>(dst) + i, word); } } } void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size) { /* Get the engine. */ auto *SE = GetRegisters(); /* Configure the engine to perform SHA256 "encryption". */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, SHA256), SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_ENC_ALG, SHA), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DST, HASH_REG)); /* Begin a hardware hash operation. */ reg::Write(SE->SE_SHA_CONFIG, SE_REG_BITS_VALUE(SHA_CONFIG_HW_INIT_HASH, 1)); /* Set the message size. */ SetMessageSize(SE, src_size); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size); /* Get the result. */ GetHashResult(SE, dst, sizeof(*dst)); } } ================================================ FILE: libraries/libexosphere/source/se/se_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetAddress(); constinit uintptr_t g_register2_address = secmon::MemoryRegionPhysicalDeviceSecurityEngine2.GetAddress(); constinit DoneHandler g_done_handler = nullptr; void SetSecure(volatile SecurityEngineRegisters *SE, bool secure) { /* Set the security software setting. */ if (secure) { reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE)); } else { reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, NONSECURE)); } /* Read the status register to force an update. */ reg::Read(SE->SE_SE_SECURITY); } } volatile SecurityEngineRegisters *GetRegisters() { return reinterpret_cast<volatile SecurityEngineRegisters *>(g_register_address); } volatile SecurityEngineRegisters *GetRegisters2() { return reinterpret_cast<volatile SecurityEngineRegisters *>(g_register2_address); } void SetRegisterAddress(uintptr_t address, uintptr_t address2) { g_register_address = address; g_register2_address = address2; } void Initialize() { auto *SE = GetRegisters(); AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))); } void SetSecure(bool secure) { /* Set security for SE1. */ SetSecure(GetRegisters(), secure); /* If SE2 is present, set security for SE2. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { SetSecure(GetRegisters2(), secure); } } void SetTzramSecure() { auto *SE = GetRegisters(); /* Set the TZRAM setting to secure. */ SE->SE_TZRAM_SECURITY = SE_TZRAM_SETTING_SECURE; } void SetPerKeySecure() { auto *SE = GetRegisters(); /* Update PERKEY_SETTING to secure. */ reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE)); } void SetContextSaveSecure() { /* Context save lock to trustzone secure is only available on mariko. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { auto *SE = GetRegisters(); auto *SE2 = GetRegisters2(); reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, SECURE)); reg::ReadWrite(SE2->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, SECURE)); } } void Lockout() { auto *SE = GetRegisters(); /* Lock access to the AES keyslots. */ for (int i = 0; i < AesKeySlotCount; ++i) { SE->SE_CRYPTO_KEYTABLE_ACCESS[i] = 0; } /* Lock access to the RSA keyslots. */ for (int i = 0; i < RsaKeySlotCount; ++i) { SE->SE_RSA_KEYTABLE_ACCESS[i] = 0; } /* Set Per Key secure. */ SetPerKeySecure(); /* Configure SE_SECURITY. */ { reg::ReadWrite(SE->SE_SE_SECURITY, SE_REG_BITS_ENUM(SECURITY_HARD_SETTING, SECURE), SE_REG_BITS_ENUM(SECURITY_ENG_DIS, DISABLE), SE_REG_BITS_ENUM(SECURITY_PERKEY_SETTING, SECURE), SE_REG_BITS_ENUM(SECURITY_SOFT_SETTING, SECURE)); } } void HandleInterrupt() { /* Get the registers. */ auto *SE = GetRegisters(); /* Disable the SE interrupt. */ reg::Write(SE->SE_INT_ENABLE, 0); /* Execute the handler if we have one. */ if (const auto handler = g_done_handler; handler != nullptr) { g_done_handler = nullptr; handler(); } } void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler) { /* Set the done handler. */ g_done_handler = handler; /* Configure to trigger an interrupt when done. */ reg::Write(SE->SE_INT_ENABLE, SE_REG_BITS_ENUM(INT_ENABLE_SE_OP_DONE, ENABLE)); } } ================================================ FILE: libraries/libexosphere/source/se/se_oaep.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { /* NOTE: This implementation is mostly copy/pasted from crypto::impl::RsaOaepImpl. */ namespace { constexpr inline size_t HashSize = sizeof(Sha256Hash); constexpr inline u8 HeadMagic = 0x00; void ApplyMGF1(u8 *dst, size_t dst_size, const void *src, size_t src_size) { /* Check our pre-conditions. */ AMS_ABORT_UNLESS(src_size <= RsaSize - (1 + HashSize)); /* Create a buffer. */ util::AlignedBuffer<hw::DataCacheLineSize, RsaSize - (1 + HashSize) + sizeof(u32)> buf; u32 counter = 0; while (dst_size > 0) { /* Setup the current hash buffer. */ const size_t cur_size = std::min(HashSize, dst_size); std::memcpy(static_cast<u8 *>(buf), src, src_size); { u32 counter_be; util::StoreBigEndian(std::addressof(counter_be), counter++); std::memcpy(static_cast<u8 *>(buf) + src_size, std::addressof(counter_be), sizeof(counter_be)); } /* Ensure se sees correct data. */ hw::FlushDataCache(buf, src_size + sizeof(u32)); hw::DataSynchronizationBarrierInnerShareable(); /* Calculate the hash. */ Sha256Hash hash; se::CalculateSha256(std::addressof(hash), buf, src_size + sizeof(u32)); /* Mask the current output. */ const u8 *mask = hash.bytes; for (size_t i = 0; i < cur_size; ++i) { *(dst++) ^= *(mask++); } /* Advance. */ dst_size -= cur_size; } } } size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size) { /* Check our preconditions. */ AMS_ABORT_UNLESS(src_size == RsaSize); AMS_ABORT_UNLESS(label_digest_size == HashSize); /* Get a byte-readable copy of the input. */ u8 *buf = static_cast<u8 *>(src); /* Validate sanity byte. */ bool is_valid = buf[0] == HeadMagic; /* Decrypt seed and masked db. */ size_t db_len = src_size - HashSize - 1; u8 *seed = buf + 1; u8 *db = seed + HashSize; ApplyMGF1(seed, HashSize, db, db_len); ApplyMGF1(db, db_len, seed, HashSize); /* Check the label digest. */ is_valid &= crypto::IsSameBytes(label_digest, db, HashSize); /* Skip past the label digest. */ db += HashSize; db_len -= HashSize; /* Verify that DB is of the form 0000...0001 < message > */ s32 msg_ofs = 0; { int looking_for_one = 1; int invalid_db_padding = 0; int is_zero; int is_one; for (size_t i = 0; i < db_len; /* ... */) { is_zero = (db[i] == 0); is_one = (db[i] == 1); msg_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i)); looking_for_one &= ~is_one; invalid_db_padding |= (looking_for_one & ~is_zero); } is_valid &= (invalid_db_padding == 0); } /* If we're invalid, return zero size. */ const size_t valid_msg_size = db_len - msg_ofs; const size_t msg_size = std::min(dst_size, static_cast<size_t>(is_valid) * valid_msg_size); /* Copy to output. */ std::memcpy(dst, db + msg_ofs, msg_size); /* Return copied size. */ return msg_size; } } ================================================ FILE: libraries/libexosphere/source/se/se_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::se { struct SecurityEngineRegisters { u32 SE_SE_SECURITY; u32 SE_TZRAM_SECURITY; u32 SE_OPERATION; u32 SE_INT_ENABLE; u32 SE_INT_STATUS; u32 SE_CONFIG; u32 SE_IN_LL_ADDR; u32 SE_IN_CUR_BYTE_ADDR; u32 SE_IN_CUR_LL_ID; u32 SE_OUT_LL_ADDR; u32 SE_OUT_CUR_BYTE_ADDR; u32 SE_OUT_CUR_LL_ID; u32 SE_HASH_RESULT[0x10]; u32 SE_CTX_SAVE_CONFIG; u32 SE_CTX_SAVE_AUTO; u32 _0x78[0x62]; u32 SE_SHA_CONFIG; u32 SE_SHA_MSG_LENGTH[0x4]; u32 SE_SHA_MSG_LEFT[0x4]; u32 _0x224[0x17]; u32 SE_CRYPTO_SECURITY_PERKEY; u32 SE_CRYPTO_KEYTABLE_ACCESS[0x10]; u32 _0x2C4[0x10]; u32 SE_CRYPTO_CONFIG; u32 SE_CRYPTO_LINEAR_CTR[0x4]; u32 SE_CRYPTO_LAST_BLOCK; u32 SE_CRYPTO_KEYTABLE_ADDR; u32 SE_CRYPTO_KEYTABLE_DATA; u32 _0x324[0x3]; u32 SE_CRYPTO_KEYTABLE_DST; u32 _0x334[0x3]; u32 SE_RNG_CONFIG; u32 SE_RNG_SRC_CONFIG; u32 SE_RNG_RESEED_INTERVAL; u32 _0x34C[0x2D]; u32 SE_RSA_CONFIG; u32 SE_RSA_KEY_SIZE; u32 SE_RSA_EXP_SIZE; u32 SE_RSA_SECURITY_PERKEY; u32 SE_RSA_KEYTABLE_ACCESS[0x2]; u32 _0x418[0x2]; u32 SE_RSA_KEYTABLE_ADDR; u32 SE_RSA_KEYTABLE_DATA; u32 SE_RSA_OUTPUT[0x40]; u32 _0x528[0x6]; u32 SE_TZRAM_OPERATION; u32 _0x544[0xAF]; u32 SE_STATUS; u32 SE_ERR_STATUS; u32 SE_MISC; u32 SE_SPARE; u32 SE_ENTROPY_DEBUG_COUNTER; u32 _0x814; u32 _0x818; u32 _0x81C; u32 _0x820[0x5F8]; }; static_assert(util::is_pod<SecurityEngineRegisters>::value); static_assert(sizeof(SecurityEngineRegisters) == secmon::MemoryRegionPhysicalDeviceSecurityEngine.GetSize()); static_assert(AesKeySlotCount == util::size(SecurityEngineRegisters{}.SE_CRYPTO_KEYTABLE_ACCESS)); static_assert(RsaKeySlotCount == util::size(SecurityEngineRegisters{}.SE_RSA_KEYTABLE_ACCESS)); #define SE_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SE, NAME) #define SE_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SE, NAME, VALUE) #define SE_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SE, NAME, ENUM) #define SE_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SE, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) #define DEFINE_SE_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SE, NAME, __OFFSET__, __WIDTH__) #define DEFINE_SE_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE) #define DEFINE_SE_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) #define DEFINE_SE_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) #define DEFINE_SE_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (SE, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) #define DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(NAME, __OFFSET__) \ REG_DEFINE_NAMED_REG(SE, NAME, __OFFSET__, 1); \ \ enum SE_##NAME { \ SE_##NAME##_##CLEAR = 0, \ SE_##NAME##_##ACTIVE = 1, \ SE_##NAME##_##SW_CLEAR = 1, \ }; /* SE_STATUS. */ DEFINE_SE_REG_TWO_BIT_ENUM(STATUS_STATE, 0, IDLE, BUSY, WAIT_OUT, WAIT_IN); DEFINE_SE_REG_BIT_ENUM(STATUS_MEM_INTERFACE, 2, IDLE, BUSY); /* SE_SECURITY */ DEFINE_SE_REG_BIT_ENUM(SECURITY_HARD_SETTING, 0, SECURE, NONSECURE); DEFINE_SE_REG_BIT_ENUM(SECURITY_ENG_DIS, 1, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(SECURITY_PERKEY_SETTING, 2, SECURE, NONSECURE); DEFINE_SE_REG_BIT_ENUM(SECURITY_CTX_SAVE_TZ_LOCK, 4, SECURE, NONSECURE); DEFINE_SE_REG_BIT_ENUM(SECURITY_CTX_TZ_LOCK_SOFT, 5, SECURE, NONSECURE); DEFINE_SE_REG_BIT_ENUM(SECURITY_SOFT_SETTING, 16, SECURE, NONSECURE); /* SE_TZRAM_SECURITY */ DEFINE_SE_REG(TZRAM_SETTING, 0, BITSIZEOF(u32)); constexpr inline u32 SE_TZRAM_SETTING_SECURE = 0; /* SE_TZRAM_OPERATION */ DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_REQ, 0, IDLE, INITIATE); DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_MODE, 1, SAVE, RESTORE); DEFINE_SE_REG_BIT_ENUM(TZRAM_OPERATION_BUSY, 2, NO, YES); DEFINE_SE_REG(TZRAM_OPERATION_CURR_ADDR, 16, 16); /* SE_OPERATION */ DEFINE_SE_REG_THREE_BIT_ENUM(OPERATION_OP, 0, ABORT, START, RESTART_OUT, CTX_SAVE, RESTART_IN, RESERVED_5, RESERVED_6, RESERVED_7); /* SE_INT_ENABLE */ DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_LL_BUF_RD, 0, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_IN_DONE, 1, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_LL_BUF_WR, 2, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_OUT_DONE, 3, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_SE_OP_DONE, 4, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_RESEED_CNTR_EXHAUSTED, 5, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(INT_ENABLE_ERR_STAT, 16, DISABLE, ENABLE); /* SE_INT_STATUS */ DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_LL_BUF_RD, 0); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_IN_DONE, 1); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_LL_BUF_WR, 2); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_OUT_DONE, 3); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_SE_OP_DONE, 4); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_RESEED_CNTR_EXHAUSTED, 5); DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_ERR_STAT, 16); /* SE_CONFIG */ DEFINE_SE_REG(CONFIG_DEC_MODE, 16, 8); DEFINE_SE_REG(CONFIG_ENC_MODE, 24, 8); DEFINE_SE_REG_THREE_BIT_ENUM(CONFIG_DST, 2, MEMORY, HASH_REG, KEYTABLE, SRK, RSA_REG, RESERVED5, RESERVED6, RESERVED7); DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_DEC_ALG, 8, NOP, AES_DEC, RESERVED2, RESERVED3, RESERVED4, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_ENC_ALG, 12, NOP, AES_ENC, RNG, SHA, RSA, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); enum SE_CONFIG_DEC_MODE { SE_CONFIG_DEC_MODE_AESMODE_KEY128 = 0, SE_CONFIG_DEC_MODE_AESMODE_KEY192 = 1, SE_CONFIG_DEC_MODE_AESMODE_KEY256 = 2, }; enum SE_CONFIG_ENC_MODE { SE_CONFIG_ENC_MODE_AESMODE_KEY128 = 0, SE_CONFIG_ENC_MODE_AESMODE_KEY192 = 1, SE_CONFIG_ENC_MODE_AESMODE_KEY256 = 2, SE_CONFIG_ENC_MODE_SHA1 = 1, SE_CONFIG_ENC_MODE_SHA224 = 4, SE_CONFIG_ENC_MODE_SHA256 = 5, SE_CONFIG_ENC_MODE_SHA384 = 6, SE_CONFIG_ENC_MODE_SHA512 = 7, }; /* SE_CTX_SAVE_CONFIG */ DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_AES_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IVS, UPDATED_IVS); DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_L, 0, 4); DEFINE_SE_REG(CTX_SAVE_CONFIG_AES_KEY_INDEX, 8, 4); DEFINE_SE_REG(CTX_SAVE_CONFIG_RSA_WORD_QUAD, 12, 4); DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_H, 12, 4); DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_RSA_KEY_INDEX, 16, SLOT0_EXPONENT, SLOT0_MODULUS, SLOT1_EXPONENT, SLOT1_MODULUS); DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, 24, WORDS_0_3, WORDS_4_7); DEFINE_SE_REG_THREE_BIT_ENUM(CTX_SAVE_CONFIG_SRC, 29, STICKY_BITS, RSA_KEYTABLE, AES_KEYTABLE, PKA1_STICKY_BITS, MEM, RESERVED5, SRK, PKA1_KEYTABLE); /* SE_CTX_SAVE_AUTO */ DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_AUTO_ENABLE, 0, NO, YES); DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_AUTO_LOCK, 8, NO, YES); DEFINE_SE_REG(CTX_SAVE_AUTO_CURR_CNT, 16, 10); /* SE_SHA_CONFIG */ DEFINE_SE_REG(SHA_CONFIG_HW_INIT_HASH, 0, 1); /* SE_CRYPTO_KEYTABLE_ADDR */ DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, 0, 4); DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_WORD, 0, 2); DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, 0, 3); enum SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD { SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_0 = 0u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_1 = 1u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_2 = 2u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_3 = 3u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_4 = 4u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_5 = 5u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_6 = 6u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_KEY_7 = 7u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_0 = 8u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_1 = 9u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_2 = 10u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_OIV_3 = 11u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_0 = 12u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_1 = 13u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_2 = 14u, SE_CRYPTO_KEYTABLE_ADDR_KEYIV_WORD_UIV_3 = 15u, }; DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, 2, ORIGINAL_IV, UPDATED_IV); DEFINE_SE_REG_BIT_ENUM(CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, 3, KEY, IV); DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, 4, 4); /* SE_RSA_CONFIG */ DEFINE_SE_REG(RSA_CONFIG_KEY_SLOT, 24, 1); /* SE_RSA_KEYTABLE_ADDR */ DEFINE_SE_REG(RSA_KEYTABLE_ADDR_WORD_ADDR, 0, 6); DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_EXPMOD_SEL, 6, EXPONENT, MODULUS); DEFINE_SE_REG(RSA_KEYTABLE_ADDR_KEY_SLOT, 7, 1); DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_INPUT_MODE, 8, REGISTER, MEMORY); /* SE_RSA_KEYTABLE_ACCESS */ DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYREAD, 0, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUPDATE, 1, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ACCESS_KEYUSE, 2, DISABLE, ENABLE); /* SE_CRYPTO_CONFIG */ DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_HASH_ENB, 0, DISABLE, ENABLE); DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_XOR_POS, 1, BYPASS, RESERVED, TOP, BOTTOM); DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_INPUT_SEL, 3, MEMORY, RANDOM, INIT_AESOUT, LINEAR_CTR); DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_CONFIG_VCTRAM_SEL, 5, MEMORY, RESERVED, INIT_AESOUT, INIT_PREV_MEMORY); DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_IV_SELECT, 7, ORIGINAL, UPDATED); DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_CORE_SEL, 8, DECRYPT, ENCRYPT); DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_KEYSCH_BYPASS, 10, DISABLE, ENABLE); DEFINE_SE_REG(CRYPTO_CONFIG_CTR_CNTN, 11, 8); DEFINE_SE_REG(CRYPTO_CONFIG_KEY_INDEX, 24, 4); DEFINE_SE_REG_BIT_ENUM(CRYPTO_CONFIG_MEMIF, 31, AHB, MCCIF); /* SE_CRYPTO_KEYTABLE_DST */ DEFINE_SE_REG_TWO_BIT_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IV, UPDATED_IV); DEFINE_SE_REG(CRYPTO_KEYTABLE_DST_KEY_INDEX, 8, 4); /* SE_RNG_CONFIG */ DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_MODE, 0, NORMAL, FORCE_INSTANTIATION, FORCE_RESEED, RESERVED3); DEFINE_SE_REG_TWO_BIT_ENUM(RNG_CONFIG_SRC, 2, NONE, ENTROPY, LFSR, RESERVED3); /* SE_RNG_SRC_CONFIG */ DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, 0, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, 1, DISABLE, ENABLE); DEFINE_SE_REG_BIT_ENUM(RNG_SRC_CONFIG_HW_DISABLE_CYA, 2, DISABLE, ENABLE); DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_SUBSAMPLE, 4, 3); DEFINE_SE_REG(RNG_SRC_CONFIG_RO_ENTROPY_DATA_FLUSH, 8, 1); } ================================================ FILE: libraries/libexosphere/source/se/se_rng.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { constexpr inline int RngReseedInterval = 70001; void ConfigRng(volatile SecurityEngineRegisters *SE, SE_CONFIG_DST dst, SE_RNG_CONFIG_MODE mode) { /* Configure the engine to do RNG encryption. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM (CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM (CONFIG_ENC_ALG, RNG), SE_REG_BITS_ENUM (CONFIG_DEC_ALG, NOP), SE_REG_BITS_VALUE(CONFIG_DST, dst)); reg::Write(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB), SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_CORE_SEL, ENCRYPT), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, RANDOM), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); /* Configure the RNG to use Entropy as source. */ reg::Write(SE->SE_RNG_CONFIG, SE_REG_BITS_ENUM(RNG_CONFIG_SRC, ENTROPY), SE_REG_BITS_VALUE(RNG_CONFIG_MODE, mode)); } void InitializeRandom(volatile SecurityEngineRegisters *SE) { /* Lock the entropy source. */ reg::Write(SE->SE_RNG_SRC_CONFIG, SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE, ENABLE), SE_REG_BITS_ENUM(RNG_SRC_CONFIG_RO_ENTROPY_SOURCE_LOCK, ENABLE)); /* Set the reseed interval to force a reseed every 70000 blocks. */ SE->SE_RNG_RESEED_INTERVAL = RngReseedInterval; /* Initialize the DRBG. */ { u8 dummy_buf[AesBlockSize]; /* Configure the engine to force drbg instantiation by writing random to memory. */ ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_FORCE_INSTANTIATION); /* Configure to do a single RNG block operation to trigger DRBG init. */ SE->SE_CRYPTO_LAST_BLOCK = 0; /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dummy_buf, sizeof(dummy_buf), nullptr, 0); } } void GenerateSrk(volatile SecurityEngineRegisters *SE) { /* Configure the RNG to output to SRK and force a reseed. */ ConfigRng(SE, SE_CONFIG_DST_SRK, SE_RNG_CONFIG_MODE_FORCE_RESEED); /* Configure a single block operation. */ SE->SE_CRYPTO_LAST_BLOCK = 0; /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); } } void InitializeRandom() { /* Initialize random for SE1. */ InitializeRandom(GetRegisters()); /* If we have SE2, initialize random for SE2. */ /* NOTE: Nintendo's implementation of this is incorrect. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { InitializeRandom(GetRegisters2()); } } void GenerateRandomBytes(void *dst, size_t size) { /* If we're not generating any bytes, there's nothing to do. */ if (size == 0) { return; } /* Get the engine. */ auto *SE = GetRegisters(); /* Determine how many blocks to generate. */ const size_t num_blocks = size / AesBlockSize; const size_t aligned_size = num_blocks * AesBlockSize; const size_t fractional = size - aligned_size; /* Configure the RNG to generate random to memory. */ ConfigRng(SE, SE_CONFIG_DST_MEMORY, SE_RNG_CONFIG_MODE_NORMAL); /* Generate as many aligned blocks as we can. */ if (aligned_size > 0) { /* Configure the engine to generate the right number of blocks. */ SE->SE_CRYPTO_LAST_BLOCK = num_blocks - 1; /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, dst, aligned_size, nullptr, 0); } /* Generate a single block to output. */ if (fractional > 0) { ExecuteOperationSingleBlock(SE, static_cast<u8 *>(dst) + aligned_size, fractional, nullptr, 0); } } void SetRandomKey(int slot) { /* NOTE: Nintendo does not validate the destination keyslot here. */ /* Get the engine. */ auto *SE = GetRegisters(); /* Configure the RNG to output to the keytable. */ ConfigRng(SE, SE_CONFIG_DST_KEYTABLE, SE_RNG_CONFIG_MODE_NORMAL); /* Configure the keytable destination to be the low part of the key. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_0_3)); /* Configure a single block operation. */ SE->SE_CRYPTO_LAST_BLOCK = 0; /* Execute the operation to generate a random low-part of the key. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); /* Configure the keytable destination to be the high part of the key. */ reg::Write(SE->SE_CRYPTO_KEYTABLE_DST, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_DST_KEY_INDEX, slot), SE_REG_BITS_ENUM(CRYPTO_KEYTABLE_DST_WORD_QUAD, KEYS_4_7)); /* Execute the operation to generate a random high-part of the key. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, nullptr, 0); } void GenerateSrk() { /* Generate SRK for SE1. */ GenerateSrk(GetRegisters()); /* If we have SE2, generate SRK for SE2. */ /* NOTE: Nintendo's implementation of this is incorrect. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { GenerateSrk(GetRegisters2()); } } } ================================================ FILE: libraries/libexosphere/source/se/se_rsa.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { struct RsaKeyInfo { int modulus_size_val; int exponent_size_val; }; constinit RsaKeyInfo g_rsa_key_infos[RsaKeySlotCount] = {}; void ClearRsaKeySlot(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) { constexpr int NumWords = se::RsaSize / sizeof(u32); for (int i = 0; i < NumWords; ++i) { /* Select the keyslot word. */ reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i)); /* Clear the keyslot word. */ SE->SE_RSA_KEYTABLE_DATA = 0; } } void SetRsaKey(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) { const int num_words = key_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { /* Select the keyslot word. */ reg::Write(SE->SE_RSA_KEYTABLE_ADDR, SE_REG_BITS_ENUM (RSA_KEYTABLE_ADDR_INPUT_MODE, REGISTER), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_KEY_SLOT, slot), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_EXPMOD_SEL, expmod), SE_REG_BITS_VALUE(RSA_KEYTABLE_ADDR_WORD_ADDR, i)); /* Get the word. */ const u32 word = util::LoadBigEndian(static_cast<const u32 *>(key) + (num_words - 1 - i)); /* Write the keyslot word. */ SE->SE_RSA_KEYTABLE_DATA = word; } } void GetRsaResult(volatile SecurityEngineRegisters *SE, void *dst, size_t size) { /* Copy out the words. */ const int num_words = size / sizeof(u32); for (int i = 0; i < num_words; ++i) { const u32 word = reg::Read(SE->SE_RSA_OUTPUT[i]); util::StoreBigEndian(static_cast<u32 *>(dst) + num_words - 1 - i, word); } } void WaitForInputReadComplete(volatile SecurityEngineRegisters *SE) { while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_IN_DONE, CLEAR))) { /* ... */ } } } void ClearRsaKeySlot(int slot) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); /* Clear the info. */ g_rsa_key_infos[slot] = {}; /* Get the engine. */ auto *SE = GetRegisters(); /* Clear the modulus. */ ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS); /* Clear the exponent. */ ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT); } void LockRsaKeySlot(int slot, u32 flags) { /* Validate the key slot. */ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); /* Get the engine. */ auto *SE = GetRegisters(); /* Set non per-key flags. */ if ((flags & ~KeySlotLockFlags_PerKey) != 0) { /* Pack the flags into the expected format. */ u32 value = 0; value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0; value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0; value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0; reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE), SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE), SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE)); } /* Set per-key flag. */ if ((flags & KeySlotLockFlags_PerKey) != 0) { reg::ReadWrite(SE->SE_RSA_SECURITY_PERKEY, REG_BITS_VALUE(slot, 1, 0)); } } void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size) { /* Validate the key slot and sizes. */ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); AMS_ABORT_UNLESS(mod_size <= RsaSize); AMS_ABORT_UNLESS(exp_size <= RsaSize); /* Set the sizes in the info. */ auto &info = g_rsa_key_infos[slot]; info.modulus_size_val = (mod_size / 64) - 1; info.exponent_size_val = (exp_size / 4); /* Get the engine. */ auto *SE = GetRegisters(); /* Set the modulus and exponent. */ SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size); SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size); } void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { /* Validate the slot and sizes. */ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); AMS_ABORT_UNLESS(src_size <= RsaSize); AMS_ABORT_UNLESS(dst_size <= RsaSize); /* Get the engine. */ auto *SE = GetRegisters(); /* Create a work buffer. */ u8 work[RsaSize]; util::ClearMemory(work, sizeof(work)); /* Copy the input into the work buffer (reversing endianness). */ const u8 *src_u8 = static_cast<const u8 *>(src); for (size_t i = 0; i < src_size; ++i) { work[src_size - 1 - i] = src_u8[i]; } /* Flush the work buffer to ensure the SE sees correct results. */ hw::FlushDataCache(work, sizeof(work)); hw::DataSynchronizationBarrierInnerShareable(); /* Configure the engine to perform RSA encryption. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG)); /* Configure the engine to use the keyslot and correct modulus/exp sizes. */ const auto &info = g_rsa_key_infos[slot]; reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot)); reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val); reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val); /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, work, src_size); /* Copy out the result. */ GetRsaResult(SE, dst, dst_size); } void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler) { /* Validate the slot and size. */ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); AMS_ABORT_UNLESS(src_size <= RsaSize); /* Get the engine. */ auto *SE = GetRegisters(); /* Create a work buffer. */ u8 work[RsaSize]; util::ClearMemory(work, sizeof(work)); /* Copy the input into the work buffer (reversing endianness). */ const u8 *src_u8 = static_cast<const u8 *>(src); for (size_t i = 0; i < src_size; ++i) { work[src_size - 1 - i] = src_u8[i]; } /* Flush the work buffer to ensure the SE sees correct results. */ hw::FlushDataCache(work, sizeof(work)); hw::DataSynchronizationBarrierInnerShareable(); /* Configure the engine to perform RSA encryption. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG)); /* Configure the engine to use the keyslot and correct modulus/exp sizes. */ const auto &info = g_rsa_key_infos[slot]; reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot)); reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val); reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val); /* Set the done handler. */ SetDoneHandler(SE, handler); /* Trigger the input operation. */ StartInputOperation(SE, work, src_size); /* Wait for input to be read by the se. */ WaitForInputReadComplete(SE); } void GetRsaResult(void *dst, size_t dst_size) { GetRsaResult(GetRegisters(), dst, dst_size); } } ================================================ FILE: libraries/libexosphere/source/se/se_suspend.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "se_execute.hpp" namespace ams::se { namespace { constexpr inline size_t SE1ContextSaveOperationCount = 133; constexpr inline size_t SE2ContextSaveOperationCount = 646; static_assert(((SE1ContextSaveOperationCount - 2) + 1) * se::AesBlockSize == sizeof(se::Context)); constinit const u8 FixedPattern[AesBlockSize] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; bool TestRegister(volatile u32 &r, u16 v) { return (static_cast<u16>(reg::Read(r))) == v; } void ExecuteContextSaveOperation(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) { /* Save the output to a temporary buffer. */ util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> temp; AMS_ABORT_UNLESS(dst_size <= AesBlockSize); /* Ensure that the cpu and SE see consistent data. */ if (src_size > 0) { hw::FlushDataCache(src, src_size); hw::DataSynchronizationBarrierInnerShareable(); } if (dst_size > 0) { hw::FlushDataCache(temp, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); } /* Execute the operation. */ ExecuteOperation(SE, SE_OPERATION_OP_CTX_SAVE, temp, dst_size, src, src_size); /* Copy output from the operation, if any. */ if (dst_size > 0) { hw::DataSynchronizationBarrierInnerShareable(); hw::FlushDataCache(temp, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); std::memcpy(dst, temp, dst_size); } } void SaveContextBlock(volatile SecurityEngineRegisters *SE, void *dst) { /* Configure to encrypt a single block. */ reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); /* Execute the operation. */ ExecuteContextSaveOperation(SE, dst, AesBlockSize, nullptr, 0); } void ConfigureForAutomaticContextSave(volatile SecurityEngineRegisters *SE) { /* Configure the engine to do RNG encryption. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RNG), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DST, MEMORY)); reg::Write(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_ENUM (CRYPTO_CONFIG_MEMIF, AHB), SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0), SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE), SE_REG_BITS_ENUM (CRYPTO_CONFIG_CORE_SEL, ENCRYPT), SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL), SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY), SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, RANDOM), SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS), SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE)); } void WaitAutomaticContextSaveDone(volatile SecurityEngineRegisters *SE) { /* Wait for operation. */ while (!reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, ACTIVE))) { /* ... */ } /* Wait for the engine to be idle. */ while (!reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE))) { /* ... */ } /* Wait for the memory interface to be idle. */ while (!reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_MEM_INTERFACE, IDLE))) { /* ... */ } } void ValidateErrStatus(volatile SecurityEngineRegisters *SE) { /* Ensure there is no error status. */ AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0); /* Ensure no error occurred. */ AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR))); } } bool ValidateStickyBits(const StickyBits &bits) { /* Get the registers. */ auto *SE = GetRegisters(); /* Check SE_SECURITY. */ if (!TestRegister(SE->SE_SE_SECURITY, bits.se_security)) { return false; } /* Check TZRAM_SECURITY. */ if (!TestRegister(SE->SE_TZRAM_SECURITY, bits.tzram_security)) { return false; } /* Check CRYPTO_SECURITY_PERKEY. */ if (!TestRegister(SE->SE_CRYPTO_SECURITY_PERKEY, bits.crypto_security_perkey)) { return false; } /* Check CRYPTO_KEYTABLE_ACCESS. */ for (int i = 0; i < AesKeySlotCount; ++i) { if (!TestRegister(SE->SE_CRYPTO_KEYTABLE_ACCESS[i], bits.crypto_keytable_access[i])) { return false; } } /* Test RSA_SECURITY_PERKEY */ if (!TestRegister(SE->SE_RSA_SECURITY_PERKEY, bits.rsa_security_perkey)) { return false; } /* Check RSA_KEYTABLE_ACCESS. */ for (int i = 0; i < RsaKeySlotCount; ++i) { if (!TestRegister(SE->SE_RSA_KEYTABLE_ACCESS[i], bits.rsa_keytable_access[i])) { return false; } } /* All sticky bits are valid. */ return true; } void SaveContext(Context *dst) { /* Get the registers. */ auto *SE = GetRegisters(); /* Generate a random srk. */ GenerateSrk(); /* Save a randomly-generated block. */ { util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> random_block; /* Flush the region we're about to fill to ensure consistency with the SE. */ hw::FlushDataCache(random_block, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Generate random bytes. */ GenerateRandomBytes(random_block, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Flush to ensure the CPU sees consistent data for the region. */ hw::FlushDataCache(random_block, AesBlockSize); hw::DataSynchronizationBarrierInnerShareable(); /* Configure to encrypt the random block to memory. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), SE_REG_BITS_ENUM(CONFIG_ENC_ALG, AES_ENC), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DST, MEMORY)); /* Configure to context save using memory as source. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM)); /* Configure to encrypt a single block. */ reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); /* Execute the operation. */ ExecuteContextSaveOperation(SE, dst->random, AesBlockSize, random_block, AesBlockSize); } /* Save the sticky bits. */ for (size_t i = 0; i < util::size(dst->sticky_bits); ++i) { /* Configure to encrypt the sticky bits block. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, STICKY_BITS), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, i)); /* Save the block. */ SaveContextBlock(SE, dst->sticky_bits[i]); } /* Save the aes keytable. */ { for (size_t key = 0; key < util::size(dst->aes_key); ++key) { for (auto part = 0; part < AesKeySlotPartCount; ++part) { /* Configure to encrypt the part of the key. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_WORD_QUAD, part)); /* Save the block. */ SaveContextBlock(SE, dst->aes_key[key][part]); } } for (size_t key = 0; key < util::size(dst->aes_oiv); ++key) { /* Configure to encrypt the original iv. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key), SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, ORIGINAL_IVS)); /* Save the block. */ SaveContextBlock(SE, dst->aes_oiv[key]); } for (size_t key = 0; key < util::size(dst->aes_uiv); ++key) { /* Configure to encrypt the updated iv. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key), SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, UPDATED_IVS)); /* Save the block. */ SaveContextBlock(SE, dst->aes_uiv[key]); } } /* Save the rsa keytable. */ for (size_t key = 0; key < util::size(dst->rsa_key); ++key) { for (auto part = 0; part < RsaKeySlotPartCount; ++part) { /* Note that the parts are done in reverse order. */ const auto part_index = RsaKeySlotPartCount - 1 - part; /* Determine a total key index. */ const auto key_index = key * util::size(dst->rsa_key) + part_index; for (size_t block = 0; block < RsaSize / AesBlockSize; ++block) { /* Configure to encrypt the part of the key. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, RSA_KEYTABLE), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_KEY_INDEX, key_index), SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_WORD_QUAD, block)); /* Save the block. */ SaveContextBlock(SE, dst->rsa_key[key][part][block]); } } } /* Save the fixed pattern. */ { /* Configure to context save using memory as source. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM)); /* Configure to encrypt a single block. */ reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); /* Execute the operation. */ ExecuteContextSaveOperation(SE, dst->fixed_pattern, AesBlockSize, FixedPattern, AesBlockSize); } /* Save the srk. */ { /* Configure to context save using srk as source. */ reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, SRK)); /* Configure to encrypt a single block. */ reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0); /* Execute the operation. */ ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0); } /* Perform a no-op context save operation. */ { /* Configure to perform no-op. */ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_ALG, NOP), SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP)); /* Execute the operation. */ ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0); } } void ConfigureAutomaticContextSave() { /* Get registers. */ auto *SE = GetRegisters(); auto *SE2 = GetRegisters2(); /* Automatic context save is supported only on mariko. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { /* Configure SE1 to do automatic context save. */ reg::Write(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_ENUM(CTX_SAVE_AUTO_ENABLE, YES), SE_REG_BITS_ENUM(CTX_SAVE_AUTO_LOCK, YES)); /* Configure SE2 to do automatic context save. */ reg::Write(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_ENUM(CTX_SAVE_AUTO_ENABLE, YES), SE_REG_BITS_ENUM(CTX_SAVE_AUTO_LOCK, YES)); } } void SaveContextAutomatic() { /* Get registers. */ auto *SE = GetRegisters(); auto *SE2 = GetRegisters2(); /* Ensure there's no error status before or after we save context. */ ValidateErrStatus(); ON_SCOPE_EXIT { ValidateErrStatus(); }; /* Perform atomic context save. */ { /* Check that context save has not already been performed. */ AMS_ABORT_UNLESS(reg::HasValue(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, 0))); AMS_ABORT_UNLESS(reg::HasValue(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, 0))); /* Configure SE1 to do context save. */ ConfigureForAutomaticContextSave(SE); ConfigureForAutomaticContextSave(SE2); /* Start the context save operation. */ reg::Write(SE->SE_OPERATION, SE_REG_BITS_ENUM(OPERATION_OP, CTX_SAVE)); reg::Write(SE2->SE_OPERATION, SE_REG_BITS_ENUM(OPERATION_OP, CTX_SAVE)); /* Wait for the context save operation to complete. */ WaitAutomaticContextSaveDone(SE); WaitAutomaticContextSaveDone(SE2); /* Check that the correct sizes were written. */ AMS_ABORT_UNLESS(reg::HasValue(SE->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, SE1ContextSaveOperationCount))); AMS_ABORT_UNLESS(reg::HasValue(SE2->SE_CTX_SAVE_AUTO, SE_REG_BITS_VALUE(CTX_SAVE_AUTO_CURR_CNT, SE2ContextSaveOperationCount))); } } void SaveTzramAutomatic() { /* Get registers. */ auto *SE = GetRegisters(); /* Begin save-to-shadow-tzram operation. */ reg::Write(SE->SE_TZRAM_OPERATION, SE_REG_BITS_ENUM(TZRAM_OPERATION_MODE, SAVE), SE_REG_BITS_ENUM(TZRAM_OPERATION_REQ, INITIATE)); /* Wait for operation to complete. */ while (reg::HasValue(SE->SE_TZRAM_OPERATION, SE_REG_BITS_ENUM(TZRAM_OPERATION_BUSY, YES))) { /* ... */ } } void ValidateErrStatus() { /* Ensure SE has no error status. */ ValidateErrStatus(GetRegisters()); /* If on mariko, ensure SE2 has no error status. */ if (fuse::GetSocType() == fuse::SocType_Mariko) { ValidateErrStatus(GetRegisters2()); } } } ================================================ FILE: libraries/libexosphere/source/tsec/tsec_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "tsec_registers.hpp" #include "../kfuse/kfuse_registers.hpp" namespace ams::tsec { namespace { constexpr inline const uintptr_t KFUSE = 0x7000FC00; constexpr inline const uintptr_t TSEC = 0x54500000; enum TsecResult : u32 { TsecResult_Success = 0xB0B0B0B0, TsecResult_Failure = 0xD0D0D0D0, }; enum TsecMemory { TsecMemory_Imem, TsecMemory_Dmem, }; bool WaitForKfuseReady() { constexpr auto KfuseTimeout = 10 * 1000; /* 10 ms. */ const u32 end_time = util::GetMicroSeconds() + KfuseTimeout; /* Wait for STATE_DONE. */ while (!reg::HasValue(KFUSE + KFUSE_STATE, KFUSE_REG_BITS_ENUM(STATE_DONE, DONE))) { if (util::GetMicroSeconds() >= end_time) { return false; } } /* Check for STATE_CRCPASS. */ return reg::HasValue(KFUSE + KFUSE_STATE, KFUSE_REG_BITS_ENUM(STATE_CRCPASS, PASS)); } void WaitForDmaIdle() { constexpr auto DmaTimeout = 10 * 1000 * 1000; /* 10 Seconds. */ u32 cur_time = util::GetMicroSeconds(); const u32 end_time = cur_time + DmaTimeout; while (cur_time <= end_time) { if (reg::HasValue(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_BUSY, IDLE))) { return; } cur_time = util::GetMicroSeconds(); } AMS_ABORT("tsec dma timeout"); } void WaitForTsecIdle() { constexpr auto TsecTimeout = 2 * 1000 * 1000; /* 2 Seconds. */ u32 cur_time = util::GetMicroSeconds(); const u32 end_time = cur_time + TsecTimeout; while (cur_time <= end_time) { if (reg::HasValue(TSEC + TSEC_FALCON_CPUCTL, TSEC_REG_BITS_ENUM(FALCON_CPUCTL_HALTED, TRUE))) { return; } cur_time = util::GetMicroSeconds(); } AMS_ABORT("tsec timeout"); } void DoDma256(TsecMemory memory, u32 dst_offset, u32 src_offset) { reg::Write(TSEC + TSEC_FALCON_DMATRFMOFFS, TSEC_REG_BITS_VALUE(FALCON_DMATRFMOFFS_OFFSET, dst_offset)); reg::Write(TSEC + TSEC_FALCON_DMATRFFBOFFS, src_offset); if (memory == TsecMemory_Imem) { reg::Write(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_TO, IMEM), TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_SIZE, 4B)); } else { reg::Write(TSEC + TSEC_FALCON_DMATRFCMD, TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_TO, DMEM), TSEC_REG_BITS_ENUM(FALCON_DMATRFCMD_SIZE, 256B)); } WaitForDmaIdle(); } } bool RunTsecFirmware(const void *fw, size_t fw_size) { /* Enable relevant clocks. */ clkrst::EnableHost1xClock(); clkrst::EnableTsecClock(); clkrst::EnableSorSafeClock(); clkrst::EnableSor0Clock(); clkrst::EnableSor1Clock(); clkrst::EnableKfuseClock(); /* Disable clocks once we're done. */ ON_SCOPE_EXIT { clkrst::DisableHost1xClock(); clkrst::DisableTsecClock(); clkrst::DisableSorSafeClock(); clkrst::DisableSor0Clock(); clkrst::DisableSor1Clock(); clkrst::DisableKfuseClock(); }; /* Wait for kfuse to be ready. */ if (!WaitForKfuseReady()) { return false; } /* Configure falcon. */ reg::Write(TSEC + TSEC_FALCON_DMACTL, 0); reg::Write(TSEC + TSEC_FALCON_IRQMSET, 0xFFF2); reg::Write(TSEC + TSEC_FALCON_IRQDEST, 0xFFF0); reg::Write(TSEC + TSEC_FALCON_ITFEN, 0x3); /* Wait for TSEC dma to be idle. */ WaitForDmaIdle(); /* Set the base address for transfers. */ reg::Write(TSEC + TSEC_FALCON_DMATRFBASE, reinterpret_cast<uintptr_t>(fw) >> 8); /* Transfer all data to TSEC imem. */ for (size_t i = 0; i < fw_size; i += 0x100) { DoDma256(TsecMemory_Imem, i, i); } /* Write the magic value to host1x syncpoint 160. */ reg::Write(0x50003300, 0x34C2E1DA); /* Execute the firmware. */ reg::Write(TSEC + TSEC_FALCON_MAILBOX0, 0); reg::Write(TSEC + TSEC_FALCON_MAILBOX1, 0); reg::Write(TSEC + TSEC_FALCON_BOOTVEC, 0); reg::Write(TSEC + TSEC_FALCON_CPUCTL, TSEC_REG_BITS_ENUM(FALCON_CPUCTL_STARTCPU, TRUE)); /* Wait for TSEC dma to be idle. */ WaitForDmaIdle(); /* Wait for TSEC to complete. */ WaitForTsecIdle(); /* Clear magic value from host1x syncpoint 160. */ reg::Write(0x50003300, 0); /* Return whether the tsec firmware succeeded. */ return reg::Read(TSEC + TSEC_FALCON_MAILBOX1) == TsecResult_Success; } void Lock() { /* Set the tsec host1x syncpoint (160) to be secure. */ /* TODO: constexpr value. */ reg::ReadWrite(0x500038F8, REG_BITS_VALUE(0, 1, 0)); /* Clear the tsec host1x syncpoint. */ reg::Write(0x50003300, 0); } } ================================================ FILE: libraries/libexosphere/source/tsec/tsec_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #define TSEC_FALCON_IRQMSET (0x1010) #define TSEC_FALCON_IRQDEST (0x101C) #define TSEC_FALCON_MAILBOX0 (0x1040) #define TSEC_FALCON_MAILBOX1 (0x1044) #define TSEC_FALCON_ITFEN (0x1048) #define TSEC_FALCON_CPUCTL (0x1100) #define TSEC_FALCON_BOOTVEC (0x1104) #define TSEC_FALCON_DMACTL (0x110C) #define TSEC_FALCON_DMATRFBASE (0x1110) #define TSEC_FALCON_DMATRFMOFFS (0x1114) #define TSEC_FALCON_DMATRFCMD (0x1118) #define TSEC_FALCON_DMATRFFBOFFS (0x111C) #define TSEC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (TSEC, NAME) #define TSEC_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (TSEC, NAME, VALUE) #define TSEC_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (TSEC, NAME, ENUM) #define TSEC_REG_BITS_ENUM_TSECL(NAME, __COND__, TRUE_ENUM, FALTSEC_ENUM) REG_NAMED_BITS_ENUM_TSECL(TSEC, NAME, __COND__, TRUE_ENUM, FALTSEC_ENUM) #define DEFINE_TSEC_REG(NAME, __OFFTSECT__, __WIDTH__) REG_DEFINE_NAMED_REG (TSEC, NAME, __OFFTSECT__, __WIDTH__) #define DEFINE_TSEC_REG_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE) #define DEFINE_TSEC_REG_TWO_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE) #define DEFINE_TSEC_REG_THREE_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN) #define DEFINE_TSEC_REG_FOUR_BIT_ENUM(NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (TSEC, NAME, __OFFTSECT__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, TSECVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) DEFINE_TSEC_REG_BIT_ENUM(FALCON_CPUCTL_STARTCPU, 1, FALSE, TRUE); DEFINE_TSEC_REG_BIT_ENUM(FALCON_CPUCTL_HALTED, 4, FALSE, TRUE); DEFINE_TSEC_REG(FALCON_DMATRFMOFFS_OFFSET, 0, 16); DEFINE_TSEC_REG_BIT_ENUM(FALCON_DMATRFCMD_BUSY, 1, BUSY, IDLE); DEFINE_TSEC_REG_BIT_ENUM(FALCON_DMATRFCMD_TO, 4, DMEM, IMEM); DEFINE_TSEC_REG_THREE_BIT_ENUM(FALCON_DMATRFCMD_SIZE, 8, 4B, 8B, 16B, 32B, 64B, 128B, 256B, RSVD7); ================================================ FILE: libraries/libexosphere/source/uart/uart_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> #include "uart_registers.hpp" namespace ams::uart { namespace { constexpr inline const u16 UartRegisterOffsets[Port_Count] = { secmon::MemoryRegionPhysicalDeviceUartA.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), secmon::MemoryRegionPhysicalDeviceUartB.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), secmon::MemoryRegionPhysicalDeviceUartC.GetAddress() - secmon::MemoryRegionPhysicalDeviceUart.GetAddress(), }; constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceUart.GetAddress(); volatile UartRegisters *GetRegisters(Port port) { return reinterpret_cast<volatile UartRegisters *>(g_register_address + UartRegisterOffsets[port]); } void WaitSymbols(int baud, u32 num) { util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, baud)); } void WaitCycles(int baud, u32 num) { util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, 16 * baud)); } ALWAYS_INLINE void WaitFifoNotFull(volatile UartRegisters *uart) { while ((uart->lsr & UART_LSR_TX_FIFO_FULL) != 0) { /* ... */ } } ALWAYS_INLINE void WaitFifoNotEmpty(volatile UartRegisters *uart) { while ((uart->lsr & UART_LSR_RX_FIFO_EMPTY) != 0) { /* ... */ } } void WaitIdle(volatile UartRegisters *uart, u32 vendor_state) { if (vendor_state & UART_VENDOR_STATE_TX_IDLE) { while ((uart->lsr & UART_LSR_TMTY) == 0) { /* ... */ } } if (vendor_state & UART_VENDOR_STATE_RX_IDLE) { while ((uart->lsr & UART_LSR_RDR) != 0) { /* ... */ } } } constexpr inline u32 LockBit = (1 << 6); } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } void Initialize(Port port, int baud_rate, u32 flags) { /* Get the registers. */ auto *uart = GetRegisters(port); /* Parse flags. */ const bool inverted = (flags & Flag_Inverted) != 0; /* Calculate the baud rate divisor. */ constexpr u32 UartClock = 408000000; const u32 divisor = (UartClock + (baud_rate * 16) / 2) / (baud_rate * 16); /* Wait for idle state. */ WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE); /* Wait 100 us. */ util::WaitMicroSeconds(100); /* Disable interrupts. */ uart->lcr = uart->lcr & ~UART_LCR_DLAB; uart->ier = 0; uart->mcr = 0; /* Setup the uart in FIFO mode. */ uart->lcr = UART_LCR_DLAB | UART_LCR_WD_LENGTH_8; uart->dll = static_cast<u8>(divisor); uart->dlh = static_cast<u8>(divisor >> 8); uart->lcr = uart->lcr & ~UART_LCR_DLAB; reg::Read(std::addressof(uart->spr)); /* Wait three symbols. */ WaitSymbols(baud_rate, 3); /* Enable FIFO with default settings. */ uart->fcr = UART_FCR_FCR_EN_FIFO; uart->irda_csr = inverted ? UART_IRDA_CSR_INVERT_TXD : 0; reg::Read(std::addressof(uart->spr)); /* Wait three cycles. */ WaitCycles(baud_rate, 3); /* Flush the FIFO. */ WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE); uart->fcr = uart->fcr | UART_FCR_RX_CLR | UART_FCR_TX_CLR; WaitCycles(baud_rate, 32); /* Wait for idle state. */ WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); /* Wait 100 us. */ util::WaitMicroSeconds(100); } void SendText(Port port, const void *data, size_t size) { /* Get the registers. */ auto *uart = GetRegisters(port); /* Get pointer to data. */ const u8 *p = static_cast<const u8 *>(data); /* Send each byte. */ for (size_t i = 0; i < size; ++i) { WaitFifoNotFull(uart); if (p[i] == '\n') { *reinterpret_cast<volatile u8 *>(std::addressof(uart->thr)) = '\r'; WaitFifoNotFull(uart); } *reinterpret_cast<volatile u8 *>(std::addressof(uart->thr)) = p[i]; } } void WaitFlush(Port port) { /* Get the registers. */ auto *uart = GetRegisters(port); /* Wait for idle. */ WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE); } } ================================================ FILE: libraries/libexosphere/source/uart/uart_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::uart { struct UartRegisters { union { u32 thr; u32 rbr; u32 dll; }; union { u32 ier; u32 dlh; }; union { u32 iir; u32 fcr; }; u32 lcr; u32 mcr; u32 lsr; u32 msr; u32 spr; u32 irda_csr; u32 rx_fifo_cfg; u32 mie; u32 vendor_status; u32 reserved_30; u32 reserved_34; u32 reserved_38; u32 asr; }; static_assert(util::is_pod<UartRegisters>::value); static_assert(sizeof(UartRegisters) == 0x40); /* 36.3.12 UART_VENDOR_STATUS_0_0 */ enum UartVendorStatus { UART_VENDOR_STATE_TX_IDLE = 1 << 0, UART_VENDOR_STATE_RX_IDLE = 1 << 1, /* This bit is set to 1 when a read is issued to an empty FIFO and gets cleared on register read (sticky bit until read) 0 = NO_UNDERRUN 1 = UNDERRUN */ UART_VENDOR_STATE_RX_UNDERRUN = 1 << 2, /* This bit is set to 1 when write data is issued to the TX FIFO when it is already full and gets cleared on register read (sticky bit until read) 0 = NO_OVERRUN 1 = OVERRUN */ UART_VENDOR_STATE_TX_OVERRUN = 1 << 3, UART_VENDOR_STATE_RX_FIFO_COUNTER = 0b111111 << 16, /* reflects number of current entries in RX FIFO */ UART_VENDOR_STATE_TX_FIFO_COUNTER = 0b111111 << 24 /* reflects number of current entries in TX FIFO */ }; /* 36.3.6 UART_LSR_0 */ enum UartLineStatus { UART_LSR_RDR = 1 << 0, /* Receiver Data Ready */ UART_LSR_OVRF = 1 << 1, /* Receiver Overrun Error */ UART_LSR_PERR = 1 << 2, /* Parity Error */ UART_LSR_FERR = 1 << 3, /* Framing Error */ UART_LSR_BRK = 1 << 4, /* BREAK condition detected on line */ UART_LSR_THRE = 1 << 5, /* Transmit Holding Register is Empty -- OK to write data */ UART_LSR_TMTY = 1 << 6, /* Transmit Shift Register empty status */ UART_LSR_FIFOE = 1 << 7, /* Receive FIFO Error */ UART_LSR_TX_FIFO_FULL = 1 << 8, /* Transmitter FIFO full status */ UART_LSR_RX_FIFO_EMPTY = 1 << 9, /* Receiver FIFO empty status */ }; /* 36.3.4 UART_LCR_0 */ enum UartLineControl { UART_LCR_WD_LENGTH_5 = 0, /* word length 5 */ UART_LCR_WD_LENGTH_6 = 1, /* word length 6 */ UART_LCR_WD_LENGTH_7 = 2, /* word length 7 */ UART_LCR_WD_LENGTH_8 = 3, /* word length 8 */ /* STOP: 0 = Transmit 1 stop bit 1 = Transmit 2 stop bits (receiver always checks for 1 stop bit) */ UART_LCR_STOP = 1 << 2, UART_LCR_PAR = 1 << 3, /* Parity enabled */ UART_LCR_EVEN = 1 << 4, /* Even parity format. There will always be an even number of 1s in the binary representation (PAR = 1) */ UART_LCR_SET_P = 1 << 5, /* Set (force) parity to value in LCR[4] */ UART_LCR_SET_B = 1 << 6, /* Set BREAK condition -- Transmitter sends all zeroes to indicate BREAK */ UART_LCR_DLAB = 1 << 7, /* Divisor Latch Access Bit (set to allow programming of the DLH, DLM Divisors) */ }; /* 36.3.3 UART_IIR_FCR_0 */ enum UartFifoControl { UART_FCR_FCR_EN_FIFO = 1 << 0, /* Enable the transmit and receive FIFOs. This bit should be enabled */ UART_FCR_RX_CLR = 1 << 1, /* Clears the contents of the receive FIFO and resets its counter logic to 0 (the receive shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ UART_FCR_TX_CLR = 1 << 2, /* Clears the contents of the transmit FIFO and resets its counter logic to 0 (the transmit shift register is not cleared or altered). This bit returns to 0 after clearing the FIFOs */ /* DMA: 0 = DMA_MODE_0 1 = DMA_MODE_1 */ UART_FCR_DMA = 1 << 3, /* TX_TRIG 0 = FIFO_COUNT_GREATER_16 1 = FIFO_COUNT_GREATER_8 2 = FIFO_COUNT_GREATER_4 3 = FIFO_COUNT_GREATER_1 */ UART_FCR_TX_TRIG = 3 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_16 = 0 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_8 = 1 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_4 = 2 << 4, UART_FCR_TX_TRIG_FIFO_COUNT_GREATER_1 = 3 << 4, /* RX_TRIG 0 = FIFO_COUNT_GREATER_1 1 = FIFO_COUNT_GREATER_4 2 = FIFO_COUNT_GREATER_8 3 = FIFO_COUNT_GREATER_16 */ UART_FCR_RX_TRIG = 3 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_1 = 0 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_4 = 1 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_8 = 2 << 6, UART_FCR_RX_TRIG_FIFO_COUNT_GREATER_16 = 3 << 6, }; /* 36.3.2 UART_IER_DLAB_0_0 */ enum UartInterruptEnable { UART_IER_IE_RHR = 1 << 0, /* Interrupt enable for Received Data Interrupt */ UART_IER_IE_THR = 1 << 1, /* Interrupt enable for Transmitter Holding Register Empty interrupt */ UART_IER_IE_RXS = 1 << 2, /* Interrupt enable for Receiver Line Status Interrupt */ UART_IER_IE_MSI = 1 << 3, /* Interrupt enable for Modem Status Interrupt */ UART_IER_IE_RX_TIMEOUT = 1 << 4, /* Interrupt enable for RX FIFO timeout */ UART_IER_IE_EORD = 1 << 5, /* Interrupt enable for Interrupt Enable for End of Received Data */ }; /* 36.3.3 UART_IIR_FCR_0 */ enum UartInterruptIdentification { UART_IIR_IS_STA = 1 << 0, /* Interrupt Pending if ZERO */ UART_IIR_IS_PRI0 = 1 << 1, /* Encoded Interrupt ID Refer to IIR[3:0] table [36.3.3] */ UART_IIR_IS_PRI1 = 1 << 2, /* Encoded Interrupt ID Refer to IIR[3:0] table */ UART_IIR_IS_PRI2 = 1 << 3, /* Encoded Interrupt ID Refer to IIR[3:0] table */ /* FIFO Mode Status 0 = 16450 mode (no FIFO) 1 = 16550 mode (FIFO) */ UART_IIR_EN_FIFO = 3 << 6, UART_IIR_MODE_16450 = 0 << 6, UART_IIR_MODE_16550 = 1 << 6, }; /* 36.3.9 UART_IRDA_CSR_0 */ enum UartIrDAPulseCodingCSR { UART_IRDA_CSR_INVERT_RXD = 1 << 0, UART_IRDA_CSR_INVERT_TXD = 1 << 1, UART_IRDA_CSR_INVERT_CTS = 1 << 2, UART_IRDA_CSR_INVERT_RTS = 1 << 3, UART_IRDA_CSR_PWT_A_BAUD_PULSE_3_14 = 0 << 6, UART_IRDA_CSR_PWT_A_BAUD_PULSE_4_14 = 1 << 6, UART_IRDA_CSR_SIR_A = 1 << 7, }; } ================================================ FILE: libraries/libexosphere/source/util/util_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::util { namespace { constinit uintptr_t g_timer_register_address = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); ALWAYS_INLINE uintptr_t GetCurrentTimeRegisterAddress() { return g_timer_register_address + 0x10; } } void SetRegisterAddress(uintptr_t address) { g_timer_register_address = address; } u32 GetMicroSeconds() { return reg::Read(GetCurrentTimeRegisterAddress()); } void WaitMicroSeconds(int us) { const u32 start = reg::Read(GetCurrentTimeRegisterAddress()); u32 cur = start; while ((cur - start) <= static_cast<u32>(us)) { cur = reg::Read(GetCurrentTimeRegisterAddress()); } } void ClearMemory(void *ptr, size_t size) { std::memset(ptr, 0, size); } } ================================================ FILE: libraries/libexosphere/source/wdt/wdt_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <exosphere.hpp> namespace ams::wdt { namespace { volatile uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceTimer.GetAddress(); #if defined(ATMOSPHERE_ARCH_ARM64) NOINLINE void Reboot(uintptr_t registers) { __asm__ __volatile__( /* Get the current core. */ "mrs x12, mpidr_el1\n" "and x12, x12, #0xFF\n" /* Get the offsets of the registers we want to write */ "mov x10, #0x8\n" "mov x11, #0x20\n" "madd x10, x10, x12, %[registers]\n" "madd x11, x11, x12, %[registers]\n" "add x10, x10, #0x60\n" "add x11, x11, #0x100\n" /* Write the magic unlock pattern. */ "mov w9, #0xC45A\n" "str w9, [x11, #0xC]\n" /* Disable the counters. */ "mov w9, #0x2\n" "str w9, [x11, #0x8]\n" /* Start periodic timer. */ "mov w9, #0xC0000000\n" "str w9, [x10]\n" /* Set reboot source to the timer we started. */ "mov w9, #0x8015\n" "add w9, w9, w12\n" "str w9, [x11]\n" /* Enable the counters. */ "mov w9, #0x1\n" "str w9, [x11, #0x8]\n" /* Wait forever. */ "1: b 1b" : [registers]"=&r"(registers) : : "x9", "x10", "x11", "x12", "memory" ); } #elif defined(ATMOSPHERE_ARCH_ARM) NOINLINE void Reboot(uintptr_t registers) { /* Write the magic unlock pattern. */ reg::Write(registers + 0x18C, 0xC45A); /* Disable the counters. */ reg::Write(registers + 0x188, 0x2); /* Start periodic timer. */ reg::Write(registers + 0x080, 0xC0000000); /* Set reboot source to the timer we started. */ reg::Write(registers + 0x180, 0x8019); /* Enable the counters. */ reg::Write(registers + 0x188, 0x1); /* Wait forever until the reboot takes. */ AMS_INFINITE_LOOP(); } #endif } void SetRegisterAddress(uintptr_t address) { g_register_address = address; } NOINLINE void Reboot() { const uintptr_t registers = g_register_address; Reboot(registers); } } ================================================ FILE: libraries/libmesosphere/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libmesosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libmesosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, release, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4)" \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, debug, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, audit, $(strip $2), $(strip $3), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $4) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, nx-hac-001, arm-cortex-a57,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, qemu_virt_a57, qemu-virt, arm-cortex-a57,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: libraries/libmesosphere/README.md ================================================ ![License](https://img.shields.io/badge/License-GPLv2-blue.svg) libmesosphere is a work-in-progress C++ library implementing functionality for the Horizon Kernel. Licensing ===== This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the libmesosphere project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects. * [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project under the Zero-Clause BSD license. Credits ===== libmesosphere is currently being developed and maintained by __SciresM__.<br> In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to libmesosphere in some significant way: * @[devkitPro](https://github.com/devkitPro) * @[yellows8](https://github.com/yellows8) * @[qlutoo](https://github.com/plutooo) * @[hedgeberg](https://github.com/hedgeberg) * @[Nintendo](https://github.com/Nintendo) * @[NVidia](https://github.com/NVidia) * @[Kaphotics](https://github.com/kwsch) ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm/kern_generic_interrupt_controller.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern::arch::arm { struct GicDistributor { u32 ctlr; u32 typer; u32 iidr; u32 reserved_0x0c; u32 statusr; u32 reserved_0x14[3]; u32 impldef_0x20[8]; u32 setspi_nsr; u32 reserved_0x44; u32 clrspi_nsr; u32 reserved_0x4c; u32 setspi_sr; u32 reserved_0x54; u32 clrspi_sr; u32 reserved_0x5c[9]; u32 igroupr[32]; u32 isenabler[32]; u32 icenabler[32]; u32 ispendr[32]; u32 icpendr[32]; u32 isactiver[32]; u32 icactiver[32]; union { u8 bytes[1020]; u32 words[255]; } ipriorityr; u32 _0x7fc; union { u8 bytes[1020]; u32 words[255]; } itargetsr; u32 _0xbfc; u32 icfgr[64]; u32 igrpmodr[32]; u32 _0xd80[32]; u32 nsacr[64]; u32 sgir; u32 _0xf04[3]; u32 cpendsgir[4]; u32 spendsgir[4]; u32 reserved_0xf30[52]; static constexpr size_t SgirCpuTargetListShift = 16; enum SgirTargetListFilter : u32 { SgirTargetListFilter_CpuTargetList = (0 << 24), SgirTargetListFilter_Others = (1 << 24), SgirTargetListFilter_Self = (2 << 24), SgirTargetListFilter_Reserved = (3 << 24), }; }; static_assert(util::is_pod<GicDistributor>::value); static_assert(sizeof(GicDistributor) == 0x1000); struct GicCpuInterface { u32 ctlr; u32 pmr; u32 bpr; u32 iar; u32 eoir; u32 rpr; u32 hppir; u32 abpr; u32 aiar; u32 aeoir; u32 ahppir; u32 statusr; u32 reserved_30[4]; u32 impldef_40[36]; u32 apr[4]; u32 nsapr[4]; u32 reserved_f0[3]; u32 iidr; u32 reserved_100[960]; u32 dir; u32 _0x1004[1023]; }; static_assert(util::is_pod<GicCpuInterface>::value); static_assert(sizeof(GicCpuInterface) == 0x2000); struct KInterruptController { NON_COPYABLE(KInterruptController); NON_MOVEABLE(KInterruptController); public: static constexpr s32 NumSoftwareInterrupts = 16; static constexpr s32 NumLocalInterrupts = NumSoftwareInterrupts + 16; static constexpr s32 NumGlobalInterrupts = 988; static constexpr s32 NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts; static constexpr s32 NumPriorityLevels = 4; public: struct LocalState { u32 isenabler[NumLocalInterrupts / 32]; u32 ipriorityr[NumLocalInterrupts / 4]; u32 itargetsr[NumLocalInterrupts / 4]; u32 icfgr[NumLocalInterrupts / 16]; u32 spendsgir[4]; }; static_assert(sizeof(LocalState{}.spendsgir) == sizeof(GicDistributor{}.spendsgir)); struct GlobalState { u32 isenabler[NumGlobalInterrupts / 32]; u32 ipriorityr[NumGlobalInterrupts / 4]; u32 itargetsr[NumGlobalInterrupts / 4]; u32 icfgr[NumGlobalInterrupts / 16]; }; enum PriorityLevel : u8 { PriorityLevel_High = 0, PriorityLevel_Low = NumPriorityLevels - 1, PriorityLevel_Timer = 1, PriorityLevel_Scheduler = 2, }; private: static constinit inline u32 s_mask[cpu::NumCores]; private: volatile GicDistributor *m_gicd; volatile GicCpuInterface *m_gicc; public: constexpr KInterruptController() : m_gicd(nullptr), m_gicc(nullptr) { /* ... */ } void Initialize(s32 core_id); void Finalize(s32 core_id); void SaveCoreLocal(LocalState *state) const; void SaveGlobal(GlobalState *state) const; void RestoreCoreLocal(const LocalState *state) const; void RestoreGlobal(const GlobalState *state) const; public: u32 GetIrq() const { return m_gicc->iar; } static constexpr s32 ConvertRawIrq(u32 irq) { return (irq == 0x3FF) ? -1 : (irq & 0x3FF); } void Enable(s32 irq) const { m_gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32))); } void Disable(s32 irq) const { m_gicd->icenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32))); } void Clear(s32 irq) const { m_gicd->icpendr[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32))); } void SetTarget(s32 irq, s32 core_id) const { m_gicd->itargetsr.bytes[irq] = m_gicd->itargetsr.bytes[irq] | GetGicMask(core_id); } void ClearTarget(s32 irq, s32 core_id) const { m_gicd->itargetsr.bytes[irq] = m_gicd->itargetsr.bytes[irq] & ~GetGicMask(core_id); } void SetPriorityLevel(s32 irq, s32 level) const { MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low); m_gicd->ipriorityr.bytes[irq] = ToGicPriorityValue(level); } s32 GetPriorityLevel(s32 irq) const { return FromGicPriorityValue(m_gicd->ipriorityr.bytes[irq]); } void SetPriorityLevel(s32 level) const { MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low); m_gicc->pmr = ToGicPriorityValue(level); } void SetEdge(s32 irq) const { u32 cfg = m_gicd->icfgr[irq / (BITSIZEOF(u32) / 2)]; cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2)))); cfg |= (0x2 << (2 * (irq % (BITSIZEOF(u32) / 2)))); m_gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg; } void SetLevel(s32 irq) const { u32 cfg = m_gicd->icfgr[irq / (BITSIZEOF(u32) / 2)]; cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2)))); cfg |= (0x0 << (2 * (irq % (BITSIZEOF(u32) / 2)))); m_gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg; } void SendInterProcessorInterrupt(s32 irq, u64 core_mask) { MESOSPHERE_ASSERT(IsSoftware(irq)); m_gicd->sgir = GetCpuTargetListMask(irq, core_mask); } void SendInterProcessorInterrupt(s32 irq) { MESOSPHERE_ASSERT(IsSoftware(irq)); m_gicd->sgir = GicDistributor::SgirTargetListFilter_Others | irq; } void EndOfInterrupt(u32 irq) const { m_gicc->eoir = irq; } bool IsInterruptDefined(s32 irq) const { const s32 num_interrupts = std::min(32 + 32 * (m_gicd->typer & 0x1F), static_cast<u32>(NumInterrupts)); return (0 <= irq && irq < num_interrupts); } public: static constexpr ALWAYS_INLINE bool IsSoftware(s32 id) { MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts); return id < NumSoftwareInterrupts; } static constexpr ALWAYS_INLINE bool IsLocal(s32 id) { MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts); return id < NumLocalInterrupts; } static constexpr ALWAYS_INLINE bool IsGlobal(s32 id) { MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts); return NumLocalInterrupts <= id; } static constexpr size_t GetGlobalInterruptIndex(s32 id) { MESOSPHERE_ASSERT(IsGlobal(id)); return id - NumLocalInterrupts; } static constexpr size_t GetLocalInterruptIndex(s32 id) { MESOSPHERE_ASSERT(IsLocal(id)); return id; } private: static constexpr size_t PriorityShift = BITSIZEOF(u8) - util::CountTrailingZeros(NumPriorityLevels); static_assert(PriorityShift < BITSIZEOF(u8)); static_assert(util::IsPowerOfTwo(NumPriorityLevels)); static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) { return (level << PriorityShift) | ((1 << PriorityShift) - 1); } static constexpr ALWAYS_INLINE s32 FromGicPriorityValue(u8 priority) { return (priority >> PriorityShift) & (NumPriorityLevels - 1); } static constexpr ALWAYS_INLINE s32 GetCpuTargetListMask(s32 irq, u64 core_mask) { MESOSPHERE_ASSERT(IsSoftware(irq)); MESOSPHERE_ASSERT(core_mask < (1ul << cpu::NumCores)); return GicDistributor::SgirTargetListFilter_CpuTargetList | irq | (static_cast<u16>(core_mask) << GicDistributor::SgirCpuTargetListShift); } static ALWAYS_INLINE s32 GetGicMask(s32 core_id) { return s_mask[core_id]; } ALWAYS_INLINE void SetGicMask(s32 core_id) const { s_mask[core_id] = m_gicd->itargetsr.bytes[0]; } NOINLINE void SetupInterruptLines(s32 core_id) const; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm/kern_k_interrupt_controller.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_typed_address.hpp> #if 1 #include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp> #else #error "Unknown board for KInterruptController" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm/kern_k_memory_region_device_types.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* All architectures must define NumArchitectureDeviceRegions. */ constexpr inline const auto NumArchitectureDeviceRegions = 3; constexpr inline const auto KMemoryRegionType_Uart = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0); constexpr inline const auto KMemoryRegionType_InterruptCpuInterface = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_InterruptDistributor = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap); static_assert(KMemoryRegionType_Uart .GetValue() == (0x1D)); static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() == (0x2D | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_InterruptDistributor .GetValue() == (0x4D | KMemoryRegionAttr_NoUserMap)); ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_select_assembly_offsets.h> namespace ams::kern::init { struct alignas(util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)) KInitArguments { u64 cpuactlr; u64 cpuectlr; u64 sp; u64 entrypoint; u64 argument; }; static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)); static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE))); static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR); static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR); static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP); static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT); static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp> #include <mesosphere/kern_select_system_control.hpp> namespace ams::kern::arch::arm64::init { /* NOTE: Nintendo uses virtual functions, rather than a concept + template. */ template<typename T> concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) { { t.Allocate(size) } -> std::same_as<KPhysicalAddress>; { t.Free(phys_addr, size) } -> std::same_as<void>; }; class KInitialPageTable { private: KPhysicalAddress m_l1_tables[2]; u32 m_num_entries[2]; public: template<IsInitialPageAllocator PageAllocator> KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) { /* Set tables. */ m_l1_tables[0] = AllocateNewPageTable(allocator, 0); m_l1_tables[1] = AllocateNewPageTable(allocator, 0); /* Set counts. */ m_num_entries[0] = MaxPageTableEntries; m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1; } KInitialPageTable() { /* Set tables. */ m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize); m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize); /* Set counts. */ cpu::TranslationControlRegisterAccessor tcr; m_num_entries[0] = tcr.GetT0Size() / L1BlockSize; m_num_entries[1] = tcr.GetT1Size() / L1BlockSize; /* Check counts. */ MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[0] && m_num_entries[0] <= MaxPageTableEntries); MESOSPHERE_INIT_ABORT_UNLESS(0 < m_num_entries[1] && m_num_entries[1] <= MaxPageTableEntries); } constexpr ALWAYS_INLINE uintptr_t GetTtbr0L1TableAddress() const { return GetInteger(m_l1_tables[0]); } constexpr ALWAYS_INLINE uintptr_t GetTtbr1L1TableAddress() const { return GetInteger(m_l1_tables[1]); } private: constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address, u64 phys_to_virt_offset = 0) const { const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1; L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]) + phys_to_virt_offset); return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1)); } static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) { L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset); return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1)); } static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) { L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset); return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1)); } template<IsInitialPageAllocator PageAllocator> static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) { MESOSPHERE_UNUSED(phys_to_virt_offset); return allocator.Allocate(PageSize); } static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) { /* Convert to a deferenceable address, and clear. */ volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address) + phys_to_virt_offset); for (size_t i = 0; i < PageSize / sizeof(u64); ++i) { ptr[i] = 0; } } public: static consteval size_t GetMaximumOverheadSize(size_t size) { return (util::DivideUp(size, L1BlockSize) + util::DivideUp(size, L2BlockSize)) * PageSize; } private: size_t NOINLINE GetBlockCount(KVirtualAddress virt_addr, size_t size, size_t block_size) { const KVirtualAddress end_virt_addr = virt_addr + size; size_t count = 0; while (virt_addr < end_virt_addr) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); /* If an L1 block is mapped or we're empty, advance by L1BlockSize. */ if (l1_entry->IsMappedBlock() || l1_entry->IsMappedEmpty()) { MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize); virt_addr += L1BlockSize; if (l1_entry->IsMappedBlock() && block_size == L1BlockSize) { count++; } continue; } /* Non empty and non-block must be table. */ MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); /* Table, so check if we're mapped in L2. */ L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock() || l2_entry->IsMappedEmpty()) { const size_t advance_size = (l2_entry->IsMappedBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size); virt_addr += advance_size; if (l2_entry->IsMappedBlock() && block_size == advance_size) { count++; } continue; } /* Non empty and non-block must be table. */ MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* Table, so check if we're mapped in L3. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); /* L3 must be block or empty. */ MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsMappedEmpty()); const size_t advance_size = (l3_entry->IsMappedBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size); virt_addr += advance_size; if (l3_entry->IsMappedBlock() && block_size == advance_size) { count++; } } return count; } KVirtualAddress NOINLINE GetBlockByIndex(KVirtualAddress virt_addr, size_t size, size_t block_size, size_t index) { const KVirtualAddress end_virt_addr = virt_addr + size; size_t count = 0; while (virt_addr < end_virt_addr) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); /* If an L1 block is mapped or we're empty, advance by L1BlockSize. */ if (l1_entry->IsMappedBlock() || l1_entry->IsMappedEmpty()) { MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize); if (l1_entry->IsMappedBlock() && block_size == L1BlockSize) { if ((count++) == index) { return virt_addr; } } virt_addr += L1BlockSize; continue; } /* Non empty and non-block must be table. */ MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); /* Table, so check if we're mapped in L2. */ L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock() || l2_entry->IsMappedEmpty()) { const size_t advance_size = (l2_entry->IsMappedBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size); if (l2_entry->IsMappedBlock() && block_size == advance_size) { if ((count++) == index) { return virt_addr; } } virt_addr += advance_size; continue; } /* Non empty and non-block must be table. */ MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* Table, so check if we're mapped in L3. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); /* L3 must be block or empty. */ MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsMappedEmpty()); const size_t advance_size = (l3_entry->IsMappedBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size)); MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size); if (l3_entry->IsMappedBlock() && block_size == advance_size) { if ((count++) == index) { return virt_addr; } } virt_addr += advance_size; } return Null<KVirtualAddress>; } PageTableEntry *GetMappingEntry(KVirtualAddress virt_addr, size_t block_size) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); if (l1_entry->IsMappedBlock()) { MESOSPHERE_INIT_ABORT_UNLESS(block_size == L1BlockSize); return l1_entry; } MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); /* Table, so check if we're mapped in L2. */ L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock()) { const size_t real_size = (l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size); return l2_entry; } MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* Table, so check if we're mapped in L3. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); /* L3 must be block. */ MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock()); const size_t real_size = (l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize; MESOSPHERE_INIT_ABORT_UNLESS(real_size == block_size); return l3_entry; } void NOINLINE SwapBlocks(KVirtualAddress src_virt_addr, KVirtualAddress dst_virt_addr, size_t block_size, bool do_copy) { static_assert(L2ContiguousBlockSize / L2BlockSize == L3ContiguousBlockSize / L3BlockSize); const bool contig = (block_size == L2ContiguousBlockSize || block_size == L3ContiguousBlockSize); const size_t num_mappings = contig ? L2ContiguousBlockSize / L2BlockSize : 1; /* Unmap the source. */ PageTableEntry *src_entry = this->GetMappingEntry(src_virt_addr, block_size); const auto src_saved = *src_entry; for (size_t i = 0; i < num_mappings; i++) { src_entry[i] = InvalidPageTableEntry; } /* Unmap the target. */ PageTableEntry *dst_entry = this->GetMappingEntry(dst_virt_addr, block_size); const auto dst_saved = *dst_entry; for (size_t i = 0; i < num_mappings; i++) { dst_entry[i] = InvalidPageTableEntry; } /* Invalidate the entire tlb. */ cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Copy data, if we should. */ const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size)); const u64 offset_mask = negative_block_size_for_mask & ((1ul << 48) - 1); const KVirtualAddress copy_src_addr = KVirtualAddress(src_saved.GetRawAttributesUnsafeForSwap() & offset_mask); const KVirtualAddress copy_dst_addr = KVirtualAddress(dst_saved.GetRawAttributesUnsafeForSwap() & offset_mask); if (do_copy) { u8 tmp[0x100]; for (size_t ofs = 0; ofs < block_size; ofs += sizeof(tmp)) { std::memcpy(tmp, GetVoidPointer(copy_src_addr + ofs), sizeof(tmp)); std::memcpy(GetVoidPointer(copy_src_addr + ofs), GetVoidPointer(copy_dst_addr + ofs), sizeof(tmp)); std::memcpy(GetVoidPointer(copy_dst_addr + ofs), tmp, sizeof(tmp)); } cpu::DataSynchronizationBarrierInnerShareable(); } /* Swap the mappings. */ const u64 attr_preserve_mask = (block_size - 1) | 0xFFFF000000000000ul; const size_t shift_for_contig = contig ? 4 : 0; size_t advanced_size = 0; const u64 src_attr_val = src_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask; const u64 dst_attr_val = dst_saved.GetRawAttributesUnsafeForSwap() & attr_preserve_mask; for (size_t i = 0; i < num_mappings; i++) { reinterpret_cast<u64 *>(src_entry)[i] = GetInteger(copy_dst_addr + (advanced_size >> shift_for_contig)) | src_attr_val; reinterpret_cast<u64 *>(dst_entry)[i] = GetInteger(copy_src_addr + (advanced_size >> shift_for_contig)) | dst_attr_val; advanced_size += block_size; } cpu::DataSynchronizationBarrierInnerShareable(); } void NOINLINE PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, size_t block_size, bool do_copy) { const size_t block_count = this->GetBlockCount(virt_addr, size, block_size); if (block_count > 1) { for (size_t cur_block = 0; cur_block < block_count; cur_block++) { const size_t target_block = KSystemControl::Init::GenerateRandomRange(cur_block, block_count - 1); if (cur_block != target_block) { const KVirtualAddress cur_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, cur_block); const KVirtualAddress target_virt_addr = this->GetBlockByIndex(virt_addr, size, block_size, target_block); MESOSPHERE_INIT_ABORT_UNLESS(cur_virt_addr != Null<KVirtualAddress>); MESOSPHERE_INIT_ABORT_UNLESS(target_virt_addr != Null<KVirtualAddress>); this->SwapBlocks(cur_virt_addr, target_virt_addr, block_size, do_copy); } } } } public: template<IsInitialPageAllocator PageAllocator> void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator, u64 phys_to_virt_offset) { /* Ensure that addresses and sizes are page aligned. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, PageSize)); /* Iteratively map pages until the requested region is mapped. */ while (size > 0) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr, phys_to_virt_offset); /* Can we make an L1 block? */ if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) { *l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L1BlockSize; phys_addr += L1BlockSize; size -= L1BlockSize; continue; } /* If we don't already have an L2 table, we need to make a new one. */ if (!l1_entry->IsMappedTable()) { KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset); cpu::DataSynchronizationBarrierInnerShareable(); *l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever()); } L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr, phys_to_virt_offset); /* Can we make a contiguous L2 block? */ if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) { for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) { l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true); virt_addr += L2BlockSize; phys_addr += L2BlockSize; size -= L2BlockSize; } continue; } /* Can we make an L2 block? */ if (util::IsAligned(GetInteger(virt_addr), L2BlockSize) && util::IsAligned(GetInteger(phys_addr), L2BlockSize) && size >= L2BlockSize) { *l2_entry = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L2BlockSize; phys_addr += L2BlockSize; size -= L2BlockSize; continue; } /* If we don't already have an L3 table, we need to make a new one. */ if (!l2_entry->IsMappedTable()) { KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset); cpu::DataSynchronizationBarrierInnerShareable(); *l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever()); } L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr, phys_to_virt_offset); /* Can we make a contiguous L3 block? */ if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) { for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) { l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true); virt_addr += L3BlockSize; phys_addr += L3BlockSize; size -= L3BlockSize; } continue; } /* Make an L3 block. */ *l3_entry = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L3BlockSize; phys_addr += L3BlockSize; size -= L3BlockSize; } /* Ensure data consistency after our mapping is added. */ cpu::DataSynchronizationBarrierInnerShareable(); } void UnmapTtbr0Entries(u64 phys_to_virt_offset) { /* Ensure data consistency before we unmap. */ cpu::DataSynchronizationBarrierInnerShareable(); /* Define helper, as we only want to clear non-nGnRE pages. */ constexpr auto ShouldUnmap = [](const PageTableEntry *entry) ALWAYS_INLINE_LAMBDA -> bool { return entry->GetPageAttribute() != PageTableEntry::PageAttribute_Device_nGnRE; }; /* Iterate all L1 entries. */ L1PageTableEntry * const l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[0]) + phys_to_virt_offset); for (size_t l1_index = 0; l1_index < m_num_entries[0]; l1_index++) { /* Get L1 entry. */ L1PageTableEntry * const l1_entry = l1_table + l1_index; if (l1_entry->IsMappedBlock()) { /* Unmap the L1 entry, if we should. */ if (ShouldUnmap(l1_entry)) { *static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry; } } else if (l1_entry->IsMappedTable()) { /* Get the L2 table. */ L2PageTableEntry * const l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(l1_entry->GetTable()) + phys_to_virt_offset); /* Unmap all L2 entries, as relevant. */ size_t remaining_l2_entries = 0; for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) { /* Get L2 entry. */ L2PageTableEntry * const l2_entry = l2_table + l2_index; if (l2_entry->IsMappedBlock()) { const size_t num_to_clear = (l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize) / L2BlockSize; if (ShouldUnmap(l2_entry)) { for (size_t i = 0; i < num_to_clear; ++i) { static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry; } } else { remaining_l2_entries += num_to_clear; } l2_index = l2_index + num_to_clear - 1; } else if (l2_entry->IsMappedTable()) { /* Get the L3 table. */ L3PageTableEntry * const l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(l2_entry->GetTable()) + phys_to_virt_offset); /* Unmap all L3 entries, as relevant. */ size_t remaining_l3_entries = 0; for (size_t l3_index = 0; l3_index < MaxPageTableEntries; ++l3_index) { /* Get L3 entry. */ if (L3PageTableEntry * const l3_entry = l3_table + l3_index; l3_entry->IsMappedBlock()) { const size_t num_to_clear = (l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize) / L3BlockSize; if (ShouldUnmap(l3_entry)) { for (size_t i = 0; i < num_to_clear; ++i) { static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry; } } else { remaining_l3_entries += num_to_clear; } l3_index = l3_index + num_to_clear - 1; } } /* If we unmapped all L3 entries, clear the L2 entry. */ if (remaining_l3_entries == 0) { *static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry; /* Invalidate the entire tlb. */ cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); } else { remaining_l2_entries++; } } } /* If we unmapped all L2 entries, clear the L1 entry. */ if (remaining_l2_entries == 0) { *static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry; /* Invalidate the entire tlb. */ cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); } } } /* Invalidate the entire tlb. */ cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); } KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const { /* Get the L1 entry. */ const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); if (l1_entry->IsMappedBlock()) { return l1_entry->GetBlock() + (GetInteger(virt_addr) & (L1BlockSize - 1)); } MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); /* Get the L2 entry. */ const L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock()) { return l2_entry->GetBlock() + (GetInteger(virt_addr) & (L2BlockSize - 1)); } MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* Get the L3 entry. */ const L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock()); return l3_entry->GetBlock() + (GetInteger(virt_addr) & (L3BlockSize - 1)); } KPhysicalAddress GetPhysicalAddressOfRandomizedRange(KVirtualAddress virt_addr, size_t size) const { /* Define tracking variables for ourselves to use. */ KPhysicalAddress min_phys_addr = Null<KPhysicalAddress>; KPhysicalAddress max_phys_addr = Null<KPhysicalAddress>; /* Ensure the range we're querying is valid. */ const KVirtualAddress end_virt_addr = virt_addr + size; if (virt_addr > end_virt_addr) { MESOSPHERE_INIT_ABORT_UNLESS(size == 0); return min_phys_addr; } auto UpdateExtents = [&](const KPhysicalAddress block, size_t block_size) ALWAYS_INLINE_LAMBDA { /* Ensure that we are allowed to have the block here. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), block_size)); MESOSPHERE_INIT_ABORT_UNLESS(block_size <= GetInteger(end_virt_addr) - GetInteger(virt_addr)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), block_size)); MESOSPHERE_INIT_ABORT_UNLESS(size >= block_size); const KPhysicalAddress block_end = block + block_size; /* We want to update min phys addr when it's 0 or > block. */ /* This is equivalent in two's complement to (n - 1) >= block. */ if ((GetInteger(min_phys_addr) - 1) >= GetInteger(block)) { min_phys_addr = block; } /* Update max phys addr when it's 0 or < block_end. */ if (GetInteger(max_phys_addr) < GetInteger(block_end) || GetInteger(max_phys_addr) == 0) { max_phys_addr = block_end; } /* Traverse onwards. */ virt_addr += block_size; }; while (virt_addr < end_virt_addr) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); /* If an L1 block is mapped, update. */ if (l1_entry->IsMappedBlock()) { UpdateExtents(l1_entry->GetBlock(), L1BlockSize); continue; } /* Not a block, so we must have a table. */ MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock()) { UpdateExtents(l2_entry->GetBlock(), l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize); continue; } /* Not a block, so we must have a table. */ MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* We must have a mapped l3 entry to inspect. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock()); UpdateExtents(l3_entry->GetBlock(), l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize); } /* Ensure we got the right range. */ MESOSPHERE_INIT_ABORT_UNLESS(GetInteger(max_phys_addr) - GetInteger(min_phys_addr) == size); /* Write the address that we found. */ return min_phys_addr; } bool IsFree(KVirtualAddress virt_addr, size_t size) { /* Ensure that addresses and sizes are page aligned. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, PageSize)); const KVirtualAddress end_virt_addr = virt_addr + size; while (virt_addr < end_virt_addr) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); /* If an L1 block is mapped, the address isn't free. */ if (l1_entry->IsMappedBlock()) { return false; } if (!l1_entry->IsMappedTable()) { /* Not a table, so just move to check the next region. */ virt_addr = util::AlignDown(GetInteger(virt_addr) + L1BlockSize, L1BlockSize); continue; } /* Table, so check if we're mapped in L2. */ L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock()) { return false; } if (!l2_entry->IsMappedTable()) { /* Not a table, so just move to check the next region. */ virt_addr = util::AlignDown(GetInteger(virt_addr) + L2BlockSize, L2BlockSize); continue; } /* Table, so check if we're mapped in L3. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); if (l3_entry->IsMappedBlock()) { return false; } /* Not a block, so move on to check the next page. */ virt_addr = util::AlignDown(GetInteger(virt_addr) + L3BlockSize, L3BlockSize); } return true; } void Reprotect(KVirtualAddress virt_addr, size_t size, const PageTableEntry &attr_before, const PageTableEntry &attr_after) { /* Ensure that addresses and sizes are page aligned. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, PageSize)); /* Iteratively reprotect pages until the requested region is reprotected. */ while (size > 0) { L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr); /* Check if an L1 block is present. */ if (l1_entry->IsMappedBlock()) { /* Ensure that we are allowed to have an L1 block here. */ const KPhysicalAddress block = l1_entry->GetBlock(); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(size >= L1BlockSize); MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsCompatibleWithAttribute(attr_before, PageTableEntry::SoftwareReservedBit_None, false)); /* Invalidate the existing L1 block. */ *static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry; cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Create new L1 block. */ *l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L1BlockSize; size -= L1BlockSize; continue; } /* Not a block, so we must be a table. */ MESOSPHERE_INIT_ABORT_UNLESS(l1_entry->IsMappedTable()); L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr); if (l2_entry->IsMappedBlock()) { const KPhysicalAddress block = l2_entry->GetBlock(); if (l2_entry->IsContiguous()) { /* Ensure that we are allowed to have a contiguous L2 block here. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2ContiguousBlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(size >= L2ContiguousBlockSize); /* Invalidate the existing contiguous L2 block. */ for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) { /* Ensure that the entry is valid. */ MESOSPHERE_INIT_ABORT_UNLESS(l2_entry[i].IsCompatibleWithAttribute(attr_before, PageTableEntry::SoftwareReservedBit_None, true)); static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry; } cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Create a new contiguous L2 block. */ for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) { l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, block + L2BlockSize * i, attr_after, PageTableEntry::SoftwareReservedBit_None, true); } virt_addr += L2ContiguousBlockSize; size -= L2ContiguousBlockSize; } else { /* Ensure that we are allowed to have an L2 block here. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(size >= L2BlockSize); MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsCompatibleWithAttribute(attr_before, PageTableEntry::SoftwareReservedBit_None, false)); /* Invalidate the existing L2 block. */ *static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry; cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Create new L2 block. */ *l2_entry = L2PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L2BlockSize; size -= L2BlockSize; } continue; } /* Not a block, so we must be a table. */ MESOSPHERE_INIT_ABORT_UNLESS(l2_entry->IsMappedTable()); /* We must have a mapped l3 entry to reprotect. */ L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr); MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock()); const KPhysicalAddress block = l3_entry->GetBlock(); if (l3_entry->IsContiguous()) { /* Ensure that we are allowed to have a contiguous L3 block here. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3ContiguousBlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(size >= L3ContiguousBlockSize); /* Invalidate the existing contiguous L3 block. */ for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) { /* Ensure that the entry is valid. */ MESOSPHERE_INIT_ABORT_UNLESS(l3_entry[i].IsCompatibleWithAttribute(attr_before, PageTableEntry::SoftwareReservedBit_None, true)); static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry; } cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Create a new contiguous L3 block. */ for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) { l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, block + L3BlockSize * i, attr_after, PageTableEntry::SoftwareReservedBit_None, true); } virt_addr += L3ContiguousBlockSize; size -= L3ContiguousBlockSize; } else { /* Ensure that we are allowed to have an L3 block here. */ MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3BlockSize)); MESOSPHERE_INIT_ABORT_UNLESS(size >= L3BlockSize); MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsCompatibleWithAttribute(attr_before, PageTableEntry::SoftwareReservedBit_None, false)); /* Invalidate the existing L3 block. */ *static_cast<PageTableEntry *>(l3_entry) = InvalidPageTableEntry; cpu::DataSynchronizationBarrierInnerShareable(); cpu::InvalidateEntireTlb(); /* Create new L3 block. */ *l3_entry = L3PageTableEntry(PageTableEntry::BlockTag{}, block, attr_after, PageTableEntry::SoftwareReservedBit_None, false); virt_addr += L3BlockSize; size -= L3BlockSize; } } /* Ensure data consistency after we complete reprotection. */ cpu::DataSynchronizationBarrierInnerShareable(); } void PhysicallyRandomize(KVirtualAddress virt_addr, size_t size, bool do_copy) { this->PhysicallyRandomize(virt_addr, size, L1BlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L2ContiguousBlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L2BlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L3ContiguousBlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy); cpu::StoreCacheForInit(GetVoidPointer(virt_addr), size); } }; class KInitialPageAllocator final { private: static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize; struct FreeListEntry { FreeListEntry *next; size_t size; }; public: struct State { uintptr_t start_address; uintptr_t end_address; FreeListEntry *free_head; }; private: State m_state; public: constexpr ALWAYS_INLINE KInitialPageAllocator() : m_state{} { /* ... */ } ALWAYS_INLINE void Initialize(uintptr_t address) { m_state.start_address = address; m_state.end_address = address; } ALWAYS_INLINE void InitializeFromState(const State *state) { m_state = *state; } ALWAYS_INLINE void GetFinalState(State *out) { *out = m_state; m_state = {}; } private: bool CanAllocate(size_t align, size_t size) const { for (auto *cur = m_state.free_head; cur != nullptr; cur = cur->next) { const uintptr_t cur_last = reinterpret_cast<uintptr_t>(cur) + cur->size - 1; const uintptr_t alloc_last = util::AlignUp(reinterpret_cast<uintptr_t>(cur), align) + size - 1; if (alloc_last <= cur_last) { return true; } } return false; } bool TryAllocate(uintptr_t address, size_t size) { /* Try to allocate the region. */ auto **prev_next = std::addressof(m_state.free_head); for (auto *cur = m_state.free_head; cur != nullptr; prev_next = std::addressof(cur->next), cur = cur->next) { const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur); const uintptr_t cur_last = cur_start + cur->size - 1; if (cur_start <= address && address + size - 1 <= cur_last) { auto *alloc = reinterpret_cast<FreeListEntry *>(address); /* Perform fragmentation at front. */ if (cur != alloc) { prev_next = std::addressof(cur->next); *alloc = { .next = cur->next, .size = cur_start + cur->size - address, }; *cur = { .next = alloc, .size = address - cur_start, }; } /* Perform fragmentation at tail. */ if (alloc->size != size) { auto *next = reinterpret_cast<FreeListEntry *>(address + size); *next = { .next = alloc->next, .size = alloc->size - size, }; *alloc = { .next = next, .size = size, }; } *prev_next = alloc->next; return true; } } return false; } public: KPhysicalAddress Allocate(size_t align, size_t size) { /* Ensure that the free list is non-empty. */ while (!this->CanAllocate(align, size)) { this->Free(m_state.end_address, FreeUnitSize); m_state.end_address += FreeUnitSize; } /* Allocate a random address. */ const uintptr_t aligned_start = util::AlignUp(m_state.start_address, align); const uintptr_t aligned_end = util::AlignDown(m_state.end_address, align); const size_t ind_max = ((aligned_end - aligned_start) / align) - 1; while (true) { if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) { /* Clear the allocated pages. */ volatile u64 *ptr = reinterpret_cast<volatile u64 *>(random_address); for (size_t i = 0; i < size / sizeof(u64); ++i) { ptr[i] = 0; } return random_address; } } } KPhysicalAddress Allocate(size_t size) { return this->Allocate(size, size); } void Free(KPhysicalAddress phys_addr, size_t size) { auto **prev_next = std::addressof(m_state.free_head); auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr)); if (auto *cur = m_state.free_head; cur != nullptr) { const uintptr_t new_start = reinterpret_cast<uintptr_t>(new_chunk); const uintptr_t new_end = GetInteger(phys_addr) + size; while (true) { /* Attempt coalescing. */ const uintptr_t cur_start = reinterpret_cast<uintptr_t>(cur); const uintptr_t cur_end = cur_start + cur->size; if (new_start < new_end) { if (new_end < cur_start) { *new_chunk = { .next = cur, .size = size, }; break; } else if (new_end == cur_start) { *new_chunk = { .next = cur->next, .size = cur->size + size, }; break; } } else if (cur_end == new_start) { cur->size += size; return; } prev_next = std::addressof(cur->next); if (cur->next != nullptr) { cur = cur->next; } else { *new_chunk = { .next = nullptr, .size = size, }; cur->next = new_chunk; return; } } } else { *new_chunk = { .next = nullptr, .size = size, }; } *prev_next = new_chunk; } }; static_assert(IsInitialPageAllocator<KInitialPageAllocator>); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_assembly_macros.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/arch/arm64/kern_assembly_offsets.h> #define ENABLE_FPU(tmp) \ mrs tmp, cpacr_el1; \ orr tmp, tmp, #0x300000; \ msr cpacr_el1, tmp; \ isb; #define GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ add ctx, sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_THREAD_CONTEXT); \ ldp wtmp1, wtmp2, [ctx, #(THREAD_CONTEXT_FPCR_FPSR)]; \ msr fpcr, xtmp1; \ msr fpsr, xtmp2; #define RESTORE_FPU64_CALLEE_SAVE_REGISTERS(ctx) \ ldp q8, q9, [ctx, #(THREAD_CONTEXT_FPU64_Q8_Q9)]; \ ldp q10, q11, [ctx, #(THREAD_CONTEXT_FPU64_Q10_Q11)]; \ ldp q12, q13, [ctx, #(THREAD_CONTEXT_FPU64_Q12_Q13)]; \ ldp q14, q15, [ctx, #(THREAD_CONTEXT_FPU64_Q14_Q15)]; #define RESTORE_FPU64_CALLER_SAVE_REGISTERS(tmp) \ ldr tmp, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS)]; \ ldp q0, q1, [tmp, #(THREAD_FPU64_CONTEXT_Q0_Q1)]; \ ldp q2, q3, [tmp, #(THREAD_FPU64_CONTEXT_Q2_Q3)]; \ ldp q4, q5, [tmp, #(THREAD_FPU64_CONTEXT_Q4_Q5)]; \ ldp q6, q7, [tmp, #(THREAD_FPU64_CONTEXT_Q6_Q7)]; \ ldp q16, q17, [tmp, #(THREAD_FPU64_CONTEXT_Q16_Q17)]; \ ldp q18, q19, [tmp, #(THREAD_FPU64_CONTEXT_Q18_Q19)]; \ ldp q20, q21, [tmp, #(THREAD_FPU64_CONTEXT_Q20_Q21)]; \ ldp q22, q23, [tmp, #(THREAD_FPU64_CONTEXT_Q22_Q23)]; \ ldp q24, q25, [tmp, #(THREAD_FPU64_CONTEXT_Q24_Q25)]; \ ldp q26, q27, [tmp, #(THREAD_FPU64_CONTEXT_Q26_Q27)]; \ ldp q28, q29, [tmp, #(THREAD_FPU64_CONTEXT_Q28_Q29)]; \ ldp q30, q31, [tmp, #(THREAD_FPU64_CONTEXT_Q30_Q31)]; #define RESTORE_FPU64_ALL_REGISTERS(ctx, tmp) \ RESTORE_FPU64_CALLEE_SAVE_REGISTERS(ctx) \ RESTORE_FPU64_CALLER_SAVE_REGISTERS(tmp) #define RESTORE_FPU32_CALLEE_SAVE_REGISTERS(ctx) \ ldp q4, q5, [ctx, #(THREAD_CONTEXT_FPU32_Q4_Q5)]; \ ldp q6, q7, [ctx, #(THREAD_CONTEXT_FPU32_Q6_Q7)]; #define RESTORE_FPU32_CALLER_SAVE_REGISTERS(tmp) \ ldr tmp, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS)]; \ ldp q0, q1, [tmp, #(THREAD_FPU32_CONTEXT_Q0_Q1)]; \ ldp q2, q3, [tmp, #(THREAD_FPU32_CONTEXT_Q2_Q3)]; \ ldp q8, q9, [tmp, #(THREAD_FPU32_CONTEXT_Q8_Q9)]; \ ldp q10, q11, [tmp, #(THREAD_FPU32_CONTEXT_Q10_Q11)]; \ ldp q12, q13, [tmp, #(THREAD_FPU32_CONTEXT_Q12_Q13)]; \ ldp q14, q15, [tmp, #(THREAD_FPU32_CONTEXT_Q14_Q15)]; #define RESTORE_FPU32_ALL_REGISTERS(ctx, tmp) \ RESTORE_FPU32_CALLEE_SAVE_REGISTERS(ctx) \ RESTORE_FPU32_CALLER_SAVE_REGISTERS(tmp) #define ENABLE_AND_RESTORE_FPU(ctx, xtmp1, xtmp2, wtmp1, wtmp2, label_32, label_done) \ ENABLE_FPU(xtmp1) \ GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ \ ldrb wtmp1, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)]; \ tbz wtmp1, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_64_BIT), label_32##f; \ \ RESTORE_FPU64_ALL_REGISTERS(ctx, xtmp1) \ \ b label_done##f; \ \ label_32: \ RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1) \ label_done: #define ENABLE_AND_RESTORE_FPU64(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ ENABLE_FPU(xtmp1) \ GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ RESTORE_FPU64_ALL_REGISTERS(ctx, xtmp1) #define ENABLE_AND_RESTORE_FPU32(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ ENABLE_FPU(xtmp1) \ GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \ RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1) #define ERET_WITH_SPECULATION_BARRIER \ eret; \ dsb nsh; \ isb ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_assembly_offsets.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_build_config.hpp> /* TODO: Different header for this? */ #define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0 /* ams::kern::KThread, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */ #define THREAD_KERNEL_STACK_TOP 0x280 /* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */ #define THREAD_STACK_PARAMETERS_SIZE 0x140 #define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00 #define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18 #define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20 #define THREAD_STACK_PARAMETERS_DISABLE_COUNT 0x28 #define THREAD_STACK_PARAMETERS_DPC_FLAGS 0x2A #define THREAD_STACK_PARAMETERS_CURRENT_SVC_ID 0x2B #define THREAD_STACK_PARAMETERS_RESERVED_2C 0x2C #define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D #define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E #define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F #define THREAD_STACK_PARAMETERS_RESERVED_30 0x30 #define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x40 #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED (2) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_64_BIT (3) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_USERMODE_EXCEPTION_HANDLER (4) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_CACHE_MAINTENANCE_OPERATION (5) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_TLB_MAINTENANCE_OPERATION (6) #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) #define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_HARDWARE_SINGLE_STEP (7) #endif #define THREAD_EXCEPTION_FLAG_IS_CALLING_SVC (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC) #define THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER) #define THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED) #define THREAD_EXCEPTION_FLAG_IS_FPU_64_BIT (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_64_BIT) #define THREAD_EXCEPTION_FLAG_IS_IN_USERMODE_EXCEPTION_HANDLER (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_USERMODE_EXCEPTION_HANDLER) #define THREAD_EXCEPTION_FLAG_IS_IN_CACHE_MAINTENANCE_OPERATION (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_CACHE_MAINTENANCE_OPERATION) #define THREAD_EXCEPTION_FLAG_IS_IN_TLB_MAINTENANCE_OPERATION (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_TLB_MAINTENANCE_OPERATION) #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) #define THREAD_EXCEPTION_FLAG_IS_HARDWARE_SINGLE_STEP (1 << THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_HARDWARE_SINGLE_STEP) #endif /* ams::kern::arch::arm64::KThreadContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_thread_context.hpp */ #define THREAD_CONTEXT_SIZE 0x100 #define THREAD_CONTEXT_CPU_REGISTERS 0x000 #define THREAD_CONTEXT_X19 0x000 #define THREAD_CONTEXT_X20 0x008 #define THREAD_CONTEXT_X21 0x010 #define THREAD_CONTEXT_X22 0x018 #define THREAD_CONTEXT_X23 0x020 #define THREAD_CONTEXT_X24 0x028 #define THREAD_CONTEXT_X25 0x030 #define THREAD_CONTEXT_X26 0x038 #define THREAD_CONTEXT_X27 0x040 #define THREAD_CONTEXT_X28 0x048 #define THREAD_CONTEXT_X29 0x050 #define THREAD_CONTEXT_LR 0x058 #define THREAD_CONTEXT_SP 0x060 #define THREAD_CONTEXT_FPCR 0x068 #define THREAD_CONTEXT_FPSR 0x06C #define THREAD_CONTEXT_FPU_REGISTERS 0x070 #define THREAD_CONTEXT_LOCKED 0x0F0 #define THREAD_CONTEXT_X19_X20 THREAD_CONTEXT_X19 #define THREAD_CONTEXT_X21_X22 THREAD_CONTEXT_X21 #define THREAD_CONTEXT_X23_X24 THREAD_CONTEXT_X23 #define THREAD_CONTEXT_X25_X26 THREAD_CONTEXT_X25 #define THREAD_CONTEXT_X27_X28 THREAD_CONTEXT_X27 #define THREAD_CONTEXT_X29_X30 THREAD_CONTEXT_X29 #define THREAD_CONTEXT_LR_SP THREAD_CONTEXT_LR #define THREAD_CONTEXT_SP_FPCR_FPSR THREAD_CONTEXT_SP #define THREAD_CONTEXT_FPCR_FPSR THREAD_CONTEXT_FPCR #define THREAD_CONTEXT_FPU64_Q8 (THREAD_CONTEXT_FPU_REGISTERS + 0x00) #define THREAD_CONTEXT_FPU64_Q9 (THREAD_CONTEXT_FPU_REGISTERS + 0x10) #define THREAD_CONTEXT_FPU64_Q10 (THREAD_CONTEXT_FPU_REGISTERS + 0x20) #define THREAD_CONTEXT_FPU64_Q11 (THREAD_CONTEXT_FPU_REGISTERS + 0x30) #define THREAD_CONTEXT_FPU64_Q12 (THREAD_CONTEXT_FPU_REGISTERS + 0x40) #define THREAD_CONTEXT_FPU64_Q13 (THREAD_CONTEXT_FPU_REGISTERS + 0x50) #define THREAD_CONTEXT_FPU64_Q14 (THREAD_CONTEXT_FPU_REGISTERS + 0x60) #define THREAD_CONTEXT_FPU64_Q15 (THREAD_CONTEXT_FPU_REGISTERS + 0x70) #define THREAD_CONTEXT_FPU64_Q8_Q9 THREAD_CONTEXT_FPU64_Q8 #define THREAD_CONTEXT_FPU64_Q10_Q11 THREAD_CONTEXT_FPU64_Q10 #define THREAD_CONTEXT_FPU64_Q12_Q13 THREAD_CONTEXT_FPU64_Q12 #define THREAD_CONTEXT_FPU64_Q14_Q15 THREAD_CONTEXT_FPU64_Q14 #define THREAD_CONTEXT_FPU32_Q4 (THREAD_CONTEXT_FPU_REGISTERS + 0x00) #define THREAD_CONTEXT_FPU32_Q5 (THREAD_CONTEXT_FPU_REGISTERS + 0x10) #define THREAD_CONTEXT_FPU32_Q6 (THREAD_CONTEXT_FPU_REGISTERS + 0x20) #define THREAD_CONTEXT_FPU32_Q7 (THREAD_CONTEXT_FPU_REGISTERS + 0x30) #define THREAD_CONTEXT_FPU32_Q4_Q5 THREAD_CONTEXT_FPU32_Q4 #define THREAD_CONTEXT_FPU32_Q6_Q7 THREAD_CONTEXT_FPU32_Q6 #define THREAD_FPU64_CONTEXT_Q0 0x000 #define THREAD_FPU64_CONTEXT_Q1 0x010 #define THREAD_FPU64_CONTEXT_Q2 0x020 #define THREAD_FPU64_CONTEXT_Q3 0x030 #define THREAD_FPU64_CONTEXT_Q4 0x040 #define THREAD_FPU64_CONTEXT_Q5 0x050 #define THREAD_FPU64_CONTEXT_Q6 0x060 #define THREAD_FPU64_CONTEXT_Q7 0x070 #define THREAD_FPU64_CONTEXT_Q16 0x080 #define THREAD_FPU64_CONTEXT_Q17 0x090 #define THREAD_FPU64_CONTEXT_Q18 0x0A0 #define THREAD_FPU64_CONTEXT_Q19 0x0B0 #define THREAD_FPU64_CONTEXT_Q20 0x0C0 #define THREAD_FPU64_CONTEXT_Q21 0x0D0 #define THREAD_FPU64_CONTEXT_Q22 0x0E0 #define THREAD_FPU64_CONTEXT_Q23 0x0F0 #define THREAD_FPU64_CONTEXT_Q24 0x100 #define THREAD_FPU64_CONTEXT_Q25 0x110 #define THREAD_FPU64_CONTEXT_Q26 0x120 #define THREAD_FPU64_CONTEXT_Q27 0x130 #define THREAD_FPU64_CONTEXT_Q28 0x140 #define THREAD_FPU64_CONTEXT_Q29 0x150 #define THREAD_FPU64_CONTEXT_Q30 0x160 #define THREAD_FPU64_CONTEXT_Q31 0x170 #define THREAD_FPU64_CONTEXT_Q0_Q1 THREAD_FPU64_CONTEXT_Q0 #define THREAD_FPU64_CONTEXT_Q2_Q3 THREAD_FPU64_CONTEXT_Q2 #define THREAD_FPU64_CONTEXT_Q4_Q5 THREAD_FPU64_CONTEXT_Q4 #define THREAD_FPU64_CONTEXT_Q6_Q7 THREAD_FPU64_CONTEXT_Q6 #define THREAD_FPU64_CONTEXT_Q16_Q17 THREAD_FPU64_CONTEXT_Q16 #define THREAD_FPU64_CONTEXT_Q18_Q19 THREAD_FPU64_CONTEXT_Q18 #define THREAD_FPU64_CONTEXT_Q20_Q21 THREAD_FPU64_CONTEXT_Q20 #define THREAD_FPU64_CONTEXT_Q22_Q23 THREAD_FPU64_CONTEXT_Q22 #define THREAD_FPU64_CONTEXT_Q24_Q25 THREAD_FPU64_CONTEXT_Q24 #define THREAD_FPU64_CONTEXT_Q26_Q27 THREAD_FPU64_CONTEXT_Q26 #define THREAD_FPU64_CONTEXT_Q28_Q29 THREAD_FPU64_CONTEXT_Q28 #define THREAD_FPU64_CONTEXT_Q30_Q31 THREAD_FPU64_CONTEXT_Q30 #define THREAD_FPU32_CONTEXT_Q0 0x000 #define THREAD_FPU32_CONTEXT_Q1 0x010 #define THREAD_FPU32_CONTEXT_Q2 0x020 #define THREAD_FPU32_CONTEXT_Q3 0x030 #define THREAD_FPU32_CONTEXT_Q8 0x040 #define THREAD_FPU32_CONTEXT_Q9 0x050 #define THREAD_FPU32_CONTEXT_Q10 0x060 #define THREAD_FPU32_CONTEXT_Q11 0x070 #define THREAD_FPU32_CONTEXT_Q12 0x080 #define THREAD_FPU32_CONTEXT_Q13 0x090 #define THREAD_FPU32_CONTEXT_Q14 0x0A0 #define THREAD_FPU32_CONTEXT_Q15 0x0B0 #define THREAD_FPU32_CONTEXT_Q0_Q1 THREAD_FPU32_CONTEXT_Q0 #define THREAD_FPU32_CONTEXT_Q2_Q3 THREAD_FPU32_CONTEXT_Q2 #define THREAD_FPU32_CONTEXT_Q8_Q9 THREAD_FPU32_CONTEXT_Q8 #define THREAD_FPU32_CONTEXT_Q10_Q11 THREAD_FPU32_CONTEXT_Q10 #define THREAD_FPU32_CONTEXT_Q12_Q13 THREAD_FPU32_CONTEXT_Q12 #define THREAD_FPU32_CONTEXT_Q14_Q15 THREAD_FPU32_CONTEXT_Q14 /* ams::kern::arch::arm64::KExceptionContext, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_exception_context.hpp */ #define EXCEPTION_CONTEXT_SIZE 0x120 #define EXCEPTION_CONTEXT_X0 0x000 #define EXCEPTION_CONTEXT_X1 0x008 #define EXCEPTION_CONTEXT_X2 0x010 #define EXCEPTION_CONTEXT_X3 0x018 #define EXCEPTION_CONTEXT_X4 0x020 #define EXCEPTION_CONTEXT_X5 0x028 #define EXCEPTION_CONTEXT_X6 0x030 #define EXCEPTION_CONTEXT_X7 0x038 #define EXCEPTION_CONTEXT_X8 0x040 #define EXCEPTION_CONTEXT_X9 0x048 #define EXCEPTION_CONTEXT_X10 0x050 #define EXCEPTION_CONTEXT_X11 0x058 #define EXCEPTION_CONTEXT_X12 0x060 #define EXCEPTION_CONTEXT_X13 0x068 #define EXCEPTION_CONTEXT_X14 0x070 #define EXCEPTION_CONTEXT_X15 0x078 #define EXCEPTION_CONTEXT_X16 0x080 #define EXCEPTION_CONTEXT_X17 0x088 #define EXCEPTION_CONTEXT_X18 0x090 #define EXCEPTION_CONTEXT_X19 0x098 #define EXCEPTION_CONTEXT_X20 0x0A0 #define EXCEPTION_CONTEXT_X21 0x0A8 #define EXCEPTION_CONTEXT_X22 0x0B0 #define EXCEPTION_CONTEXT_X23 0x0B8 #define EXCEPTION_CONTEXT_X24 0x0C0 #define EXCEPTION_CONTEXT_X25 0x0C8 #define EXCEPTION_CONTEXT_X26 0x0D0 #define EXCEPTION_CONTEXT_X27 0x0D8 #define EXCEPTION_CONTEXT_X28 0x0E0 #define EXCEPTION_CONTEXT_X29 0x0E8 #define EXCEPTION_CONTEXT_X30 0x0F0 #define EXCEPTION_CONTEXT_SP 0x0F8 #define EXCEPTION_CONTEXT_PC 0x100 #define EXCEPTION_CONTEXT_PSR 0x108 #define EXCEPTION_CONTEXT_TPIDR 0x110 #define EXCEPTION_CONTEXT_X0_X1 EXCEPTION_CONTEXT_X0 #define EXCEPTION_CONTEXT_X2_X3 EXCEPTION_CONTEXT_X2 #define EXCEPTION_CONTEXT_X4_X5 EXCEPTION_CONTEXT_X4 #define EXCEPTION_CONTEXT_X6_X7 EXCEPTION_CONTEXT_X6 #define EXCEPTION_CONTEXT_X8_X9 EXCEPTION_CONTEXT_X8 #define EXCEPTION_CONTEXT_X10_X11 EXCEPTION_CONTEXT_X10 #define EXCEPTION_CONTEXT_X12_X13 EXCEPTION_CONTEXT_X12 #define EXCEPTION_CONTEXT_X14_X15 EXCEPTION_CONTEXT_X14 #define EXCEPTION_CONTEXT_X16_X17 EXCEPTION_CONTEXT_X16 #define EXCEPTION_CONTEXT_X18_X19 EXCEPTION_CONTEXT_X18 #define EXCEPTION_CONTEXT_X20_X21 EXCEPTION_CONTEXT_X20 #define EXCEPTION_CONTEXT_X22_X23 EXCEPTION_CONTEXT_X22 #define EXCEPTION_CONTEXT_X24_X25 EXCEPTION_CONTEXT_X24 #define EXCEPTION_CONTEXT_X26_X27 EXCEPTION_CONTEXT_X26 #define EXCEPTION_CONTEXT_X28_X29 EXCEPTION_CONTEXT_X28 #define EXCEPTION_CONTEXT_X30_SP EXCEPTION_CONTEXT_X30 #define EXCEPTION_CONTEXT_PC_PSR EXCEPTION_CONTEXT_PC #define EXCEPTION_CONTEXT_X9_X10 EXCEPTION_CONTEXT_X9 #define EXCEPTION_CONTEXT_X19_X20 EXCEPTION_CONTEXT_X19 #define EXCEPTION_CONTEXT_X21_X22 EXCEPTION_CONTEXT_X21 #define EXCEPTION_CONTEXT_X23_X24 EXCEPTION_CONTEXT_X23 #define EXCEPTION_CONTEXT_X25_X26 EXCEPTION_CONTEXT_X25 #define EXCEPTION_CONTEXT_X27_X28 EXCEPTION_CONTEXT_X27 #define EXCEPTION_CONTEXT_X29_X30 EXCEPTION_CONTEXT_X29 #define EXCEPTION_CONTEXT_SP_PC EXCEPTION_CONTEXT_SP #define EXCEPTION_CONTEXT_PSR_TPIDR EXCEPTION_CONTEXT_PSR /* ams::svc::arch::arm64::ThreadLocalRegion, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libvapours/include/vapours/svc/arch/arm64/svc_thread_local_region.hpp */ #define THREAD_LOCAL_REGION_MESSAGE_BUFFER 0x000 #define THREAD_LOCAL_REGION_DISABLE_COUNT 0x100 #define THREAD_LOCAL_REGION_INTERRUPT_FLAG 0x102 #define THREAD_LOCAL_REGION_SIZE 0x200 /* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */ #define INIT_ARGUMENTS_SIZE 0x28 #define INIT_ARGUMENTS_CPUACTLR 0x00 #define INIT_ARGUMENTS_CPUECTLR 0x08 #define INIT_ARGUMENTS_SP 0x10 #define INIT_ARGUMENTS_ENTRYPOINT 0x18 #define INIT_ARGUMENTS_ARGUMENT 0x20 /* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */ /* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */ #define KSCHEDULER_NEEDS_SCHEDULING 0x00 #define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01 #define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x18 #define KSCHEDULER_IDLE_THREAD_STACK 0x20 #define KSCHEDULER_PREVIOUS_THREAD 0x28 #define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x30 ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/arch/arm64/kern_cpu_system_registers.hpp> #include <mesosphere/kern_select_userspace_memory_access.hpp> namespace ams::kern::arch::arm64::cpu { #if defined(ATMOSPHERE_CPU_ARM_CORTEX_A57) || defined(ATMOSPHERE_CPU_ARM_CORTEX_A53) constexpr inline size_t InstructionCacheLineSize = 0x40; constexpr inline size_t DataCacheLineSize = 0x40; constexpr inline size_t NumPerformanceCounters = 6; #else #error "Unknown CPU for cache line sizes" #endif #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) constexpr inline size_t NumCores = 4; #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) constexpr inline size_t NumCores = 4; #else #error "Unknown Board for cpu::NumCores" #endif constexpr inline u32 El0Aarch64PsrMask = 0xF0000000; constexpr inline u32 El0Aarch32PsrMask = 0xFE0FFE20; /* Initialization. */ NOINLINE void InitializeInterruptThreads(s32 core_id); /* Helpers for managing memory state. */ ALWAYS_INLINE void DataSynchronizationBarrier() { __asm__ __volatile__("dsb sy" ::: "memory"); } ALWAYS_INLINE void DataSynchronizationBarrierInnerShareable() { __asm__ __volatile__("dsb ish" ::: "memory"); } ALWAYS_INLINE void DataSynchronizationBarrierInnerShareableStore() { __asm__ __volatile__("dsb ishst" ::: "memory"); } ALWAYS_INLINE void DataMemoryBarrier() { __asm__ __volatile__("dmb sy" ::: "memory"); } ALWAYS_INLINE void DataMemoryBarrierInnerShareable() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void DataMemoryBarrierInnerShareableStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); } ALWAYS_INLINE void InstructionMemoryBarrier() { __asm__ __volatile__("isb" ::: "memory"); } ALWAYS_INLINE void EnsureInstructionConsistency() { DataSynchronizationBarrierInnerShareable(); InstructionMemoryBarrier(); } ALWAYS_INLINE void EnsureInstructionConsistencyFullSystem() { DataSynchronizationBarrier(); InstructionMemoryBarrier(); } ALWAYS_INLINE void Yield() { __asm__ __volatile__("yield" ::: "memory"); } ALWAYS_INLINE void SwitchProcess(u64 ttbr, u32 proc_id) { SetTtbr0El1(ttbr); ContextIdRegisterAccessor(0).SetProcId(proc_id).Store(); InstructionMemoryBarrier(); } /* Performance counter helpers. */ ALWAYS_INLINE u64 GetCycleCounter() { return cpu::GetPmcCntrEl0(); } ALWAYS_INLINE u32 GetPerformanceCounter(s32 n) { u64 counter = 0; if (n < static_cast<s32>(NumPerformanceCounters)) { switch (n) { case 0: counter = cpu::GetPmevCntr0El0(); break; case 1: counter = cpu::GetPmevCntr1El0(); break; case 2: counter = cpu::GetPmevCntr2El0(); break; case 3: counter = cpu::GetPmevCntr3El0(); break; case 4: counter = cpu::GetPmevCntr4El0(); break; case 5: counter = cpu::GetPmevCntr5El0(); break; default: break; } } return static_cast<u32>(counter); } /* Helper for address access. */ ALWAYS_INLINE bool GetPhysicalAddressWritable(KPhysicalAddress *out, KVirtualAddress addr, bool privileged = false) { const uintptr_t va = GetInteger(addr); if (privileged) { __asm__ __volatile__("at s1e1w, %[va]" :: [va]"r"(va) : "memory"); } else { __asm__ __volatile__("at s1e0w, %[va]" :: [va]"r"(va) : "memory"); } InstructionMemoryBarrier(); u64 par = GetParEl1(); if (par & 0x1) { return false; } if (out) { *out = KPhysicalAddress((par & 0xFFFFFFFFF000ull) | (va & 0xFFFull)); } return true; } ALWAYS_INLINE bool GetPhysicalAddressReadable(KPhysicalAddress *out, KVirtualAddress addr, bool privileged = false) { const uintptr_t va = GetInteger(addr); if (privileged) { __asm__ __volatile__("at s1e1r, %[va]" :: [va]"r"(va) : "memory"); } else { __asm__ __volatile__("at s1e0r, %[va]" :: [va]"r"(va) : "memory"); } InstructionMemoryBarrier(); u64 par = GetParEl1(); if (par & 0x1) { return false; } if (out) { *out = KPhysicalAddress((par & 0xFFFFFFFFF000ull) | (va & 0xFFFull)); } return true; } ALWAYS_INLINE bool CanAccessAtomic(KProcessAddress addr, bool privileged = false) { const uintptr_t va = GetInteger(addr); if (privileged) { __asm__ __volatile__("at s1e1w, %[va]" :: [va]"r"(va) : "memory"); } else { __asm__ __volatile__("at s1e0w, %[va]" :: [va]"r"(va) : "memory"); } InstructionMemoryBarrier(); u64 par = GetParEl1(); if (par & 0x1) { return false; } return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF; } ALWAYS_INLINE void StoreDataCacheForInitArguments(const void *addr, size_t size) { const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize); for (size_t stored = 0; stored < size; stored += cpu::DataCacheLineSize) { __asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(start + stored) : "memory"); } DataSynchronizationBarrier(); } /* Synchronization helpers. */ NOINLINE void SynchronizeAllCores(); void SynchronizeCores(u64 core_mask); /* Cache management helpers. */ void StoreCacheForInit(void *addr, size_t size); void FlushEntireDataCache(); Result InvalidateDataCache(void *addr, size_t size); Result StoreDataCache(const void *addr, size_t size); Result FlushDataCache(const void *addr, size_t size); void InvalidateEntireInstructionCache(); void ClearPageToZeroImpl(void *); ALWAYS_INLINE void ClearPageToZero(void * const page) { MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(page), PageSize)); MESOSPHERE_ASSERT(page != nullptr); ClearPageToZeroImpl(page); } ALWAYS_INLINE void InvalidateTlbByAsid(u32 asid) { const u64 value = (static_cast<u64>(asid) << 48); __asm__ __volatile__("tlbi aside1is, %[value]" :: [value]"r"(value) : "memory"); EnsureInstructionConsistency(); } ALWAYS_INLINE void InvalidateTlbByAsidAndVa(u32 asid, KProcessAddress virt_addr) { const u64 value = (static_cast<u64>(asid) << 48) | ((GetInteger(virt_addr) >> 12) & 0xFFFFFFFFFFFul); __asm__ __volatile__("tlbi aside1is, %[value]" :: [value]"r"(value) : "memory"); EnsureInstructionConsistency(); } ALWAYS_INLINE void InvalidateEntireTlb() { __asm__ __volatile__("tlbi vmalle1is" ::: "memory"); EnsureInstructionConsistency(); } ALWAYS_INLINE void InvalidateEntireTlbDataOnly() { __asm__ __volatile__("tlbi vmalle1is" ::: "memory"); DataSynchronizationBarrierInnerShareable(); } ALWAYS_INLINE void InvalidateTlbByVaDataOnly(KProcessAddress virt_addr) { const u64 value = ((GetInteger(virt_addr) >> 12) & 0xFFFFFFFFFFFul); __asm__ __volatile__("tlbi vaae1is, %[value]" :: [value]"r"(value) : "memory"); DataSynchronizationBarrierInnerShareable(); } ALWAYS_INLINE uintptr_t GetCurrentThreadPointerValue() { register uintptr_t x18 asm("x18"); __asm__ __volatile__("" : [x18]"=r"(x18)); return x18; } ALWAYS_INLINE void SetCurrentThreadPointerValue(uintptr_t value) { register uintptr_t x18 asm("x18") = value; __asm__ __volatile__("":: [x18]"r"(x18)); } ALWAYS_INLINE void SetExceptionThreadStackTop(uintptr_t top) { cpu::SetCntvCvalEl0(top); } ALWAYS_INLINE void SwitchThreadLocalRegion(uintptr_t tlr) { cpu::SetTpidrRoEl0(tlr); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_cpu_system_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::kern::arch::arm64::cpu { #define MESOSPHERE_CPU_GET_SYSREG(name) \ ({ \ u64 temp_value; \ __asm__ __volatile__("mrs %0, " #name "" : "=&r"(temp_value) :: "memory"); \ temp_value; \ }) #define MESOSPHERE_CPU_SET_SYSREG(name, value) \ ({ \ __asm__ __volatile__("msr " #name ", %0" :: "r"(value) : "memory", "cc"); \ }) #define MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(name, reg_name) \ ALWAYS_INLINE void Set##name(u64 value) { MESOSPHERE_CPU_SET_SYSREG(reg_name, value); } \ ALWAYS_INLINE u64 Get##name() { return MESOSPHERE_CPU_GET_SYSREG(reg_name); } MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Ttbr0El1, ttbr0_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Ttbr1El1, ttbr1_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TcrEl1, tcr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(MairEl1, mair_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrEl1, tpidr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(VbarEl1, vbar_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(FarEl1, far_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ParEl1, par_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SctlrEl1, sctlr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CpuActlrEl1, s3_1_c15_c2_0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CpuEctlrEl1, s3_1_c15_c2_1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CsselrEl1, csselr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CcsidrEl1, ccsidr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(OslarEl1, oslar_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrEl0, tpidr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrRoEl0, tpidrro_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ElrEl1, elr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(EsrEl1, esr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpsrEl1, spsr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr0El1, afsr0_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr1El1, afsr1_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(MdscrEl1, mdscr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CpacrEl1, cpacr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ContextidrEl1, contextidr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntkCtlEl1, cntkctl_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCtlEl0, cntp_ctl_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCvalEl0, cntp_cval_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntvCvalEl0, cntv_cval_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Daif, daif) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Dfr0El1, id_aa64dfr0_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcrEl0, pmcr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcCntrEl0, pmccntr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmSelrEl0, pmselr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcCfiltrEl0, pmccfiltr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmIntEnSetEl1, pmintenset_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmCntEnSetEl0, pmcntenset_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmOvsSetEl0, pmovsset_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmIntEnClrEl1, pmintenclr_el1) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmCntEnClrEl0, pmcntenclr_el0) MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmOvsClrEl0, pmovsclr_el0) #define FOR_I_IN_0_TO_30(HANDLER, ...) \ HANDLER(0, ## __VA_ARGS__) HANDLER(1, ## __VA_ARGS__) HANDLER(2, ## __VA_ARGS__) HANDLER(3, ## __VA_ARGS__) \ HANDLER(4, ## __VA_ARGS__) HANDLER(5, ## __VA_ARGS__) HANDLER(6, ## __VA_ARGS__) HANDLER(7, ## __VA_ARGS__) \ HANDLER(8, ## __VA_ARGS__) HANDLER(9, ## __VA_ARGS__) HANDLER(10, ## __VA_ARGS__) HANDLER(11, ## __VA_ARGS__) \ HANDLER(12, ## __VA_ARGS__) HANDLER(13, ## __VA_ARGS__) HANDLER(14, ## __VA_ARGS__) HANDLER(15, ## __VA_ARGS__) \ HANDLER(16, ## __VA_ARGS__) HANDLER(17, ## __VA_ARGS__) HANDLER(18, ## __VA_ARGS__) HANDLER(19, ## __VA_ARGS__) \ HANDLER(20, ## __VA_ARGS__) HANDLER(21, ## __VA_ARGS__) HANDLER(22, ## __VA_ARGS__) HANDLER(23, ## __VA_ARGS__) \ HANDLER(24, ## __VA_ARGS__) HANDLER(25, ## __VA_ARGS__) HANDLER(26, ## __VA_ARGS__) HANDLER(27, ## __VA_ARGS__) \ HANDLER(28, ## __VA_ARGS__) HANDLER(29, ## __VA_ARGS__) HANDLER(30, ## __VA_ARGS__) #define MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS(ID, ...) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr##ID##El0, pmevcntr##ID##_el0) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevTyper##ID##El0, pmevtyper##ID##_el0) FOR_I_IN_0_TO_30(MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS) #undef MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS #undef FOR_I_IN_0_TO_30 #define FOR_I_IN_0_TO_15(HANDLER, ...) \ HANDLER(0, ## __VA_ARGS__) HANDLER(1, ## __VA_ARGS__) HANDLER(2, ## __VA_ARGS__) HANDLER(3, ## __VA_ARGS__) \ HANDLER(4, ## __VA_ARGS__) HANDLER(5, ## __VA_ARGS__) HANDLER(6, ## __VA_ARGS__) HANDLER(7, ## __VA_ARGS__) \ HANDLER(8, ## __VA_ARGS__) HANDLER(9, ## __VA_ARGS__) HANDLER(10, ## __VA_ARGS__) HANDLER(11, ## __VA_ARGS__) \ HANDLER(12, ## __VA_ARGS__) HANDLER(13, ## __VA_ARGS__) HANDLER(14, ## __VA_ARGS__) HANDLER(15, ## __VA_ARGS__) #define MESOSPHERE_CPU_DEFINE_DBG_SYSREG_ACCESSORS(ID, ...) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(DbgWcr##ID##El1, dbgwcr##ID##_el1) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(DbgWvr##ID##El1, dbgwvr##ID##_el1) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(DbgBcr##ID##El1, dbgbcr##ID##_el1) \ MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(DbgBvr##ID##El1, dbgbvr##ID##_el1) FOR_I_IN_0_TO_15(MESOSPHERE_CPU_DEFINE_DBG_SYSREG_ACCESSORS) #undef MESOSPHERE_CPU_DEFINE_DBG_SYSREG_ACCESSORS /* Base class for register accessors. */ class GenericRegisterAccessorBase { NON_COPYABLE(GenericRegisterAccessorBase); NON_MOVEABLE(GenericRegisterAccessorBase); private: u64 m_value; public: constexpr ALWAYS_INLINE GenericRegisterAccessorBase(u64 v) : m_value(v) { /* ... */ } protected: constexpr ALWAYS_INLINE u64 GetValue() const { return m_value; } constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const { return (m_value >> offset) & ((1ul << count) - 1); } constexpr ALWAYS_INLINE void SetBits(size_t offset, size_t count, u64 value) { const u64 mask = ((1ul << count) - 1) << offset; m_value &= ~mask; m_value |= (value & (mask >> offset)) << offset; } constexpr ALWAYS_INLINE void SetBitsDirect(size_t offset, size_t count, u64 value) { const u64 mask = ((1ul << count) - 1) << offset; m_value &= ~mask; m_value |= (value & mask); } constexpr ALWAYS_INLINE void SetBit(size_t offset, bool enabled) { const u64 mask = 1ul << offset; if (enabled) { m_value |= mask; } else { m_value &= ~mask; } } }; template<typename Derived> class GenericRegisterAccessor : public GenericRegisterAccessorBase { public: constexpr ALWAYS_INLINE GenericRegisterAccessor(u64 v) : GenericRegisterAccessorBase(v) { /* ... */ } protected: ALWAYS_INLINE void Store() const { static_cast<const Derived *>(this)->Store(); } }; #define MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(name) class name##RegisterAccessor : public GenericRegisterAccessor<name##RegisterAccessor> #define MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(accessor, reg_name) \ ALWAYS_INLINE accessor##RegisterAccessor() : GenericRegisterAccessor(MESOSPHERE_CPU_GET_SYSREG(reg_name)) { /* ... */ } \ constexpr ALWAYS_INLINE accessor##RegisterAccessor(u64 v) : GenericRegisterAccessor(v) { /* ... */ } \ \ ALWAYS_INLINE void Store() { const u64 v = this->GetValue(); MESOSPHERE_CPU_SET_SYSREG(reg_name, v); } /* Accessors. */ MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(MemoryAccessIndirection) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(MemoryAccessIndirection, mair_el1) }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(TranslationControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(TranslationControl, tcr_el1) constexpr ALWAYS_INLINE size_t GetT0Size() const { const size_t shift_value = this->GetBits(0, 6); return size_t(1) << (size_t(64) - shift_value); } constexpr ALWAYS_INLINE size_t GetT1Size() const { const size_t shift_value = this->GetBits(16, 6); return size_t(1) << (size_t(64) - shift_value); } constexpr ALWAYS_INLINE bool GetEpd0() const { return this->GetBits(7, 1) != 0; } constexpr ALWAYS_INLINE decltype(auto) SetEpd0(bool set) { this->SetBit(7, set); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(ArchitecturalFeatureAccessControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(ArchitecturalFeatureAccessControl, cpacr_el1) constexpr ALWAYS_INLINE decltype(auto) SetFpEnabled(bool en) { if (en) { this->SetBits(20, 2, 0x3); } else { this->SetBits(20, 2, 0x0); } return *this; } constexpr ALWAYS_INLINE bool IsFpEnabled() { return this->GetBits(20, 2) != 0; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(DebugFeature) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(DebugFeature, id_aa64dfr0_el1) constexpr ALWAYS_INLINE size_t GetNumWatchpoints() const { return this->GetBits(20, 4); } constexpr ALWAYS_INLINE size_t GetNumBreakpoints() const { return this->GetBits(12, 4); } constexpr ALWAYS_INLINE size_t GetNumContextAwareBreakpoints() const { return this->GetBits(28, 4); } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(MonitorDebugSystemControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(MonitorDebugSystemControl, mdscr_el1) constexpr ALWAYS_INLINE bool GetMde() const { return this->GetBits(15, 1) != 0; } constexpr ALWAYS_INLINE size_t GetTdcc() const { return this->GetBits(12, 1) != 0; } constexpr ALWAYS_INLINE bool GetSoftwareStep() const { return this->GetBits(0, 1) != 0; } constexpr ALWAYS_INLINE decltype(auto) SetMde(bool set) { this->SetBit(15, set); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetTdcc(bool set) { this->SetBit(12, set); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetSoftwareStep(bool set) { this->SetBit(0, set); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(MultiprocessorAffinity) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(MultiprocessorAffinity, mpidr_el1) constexpr ALWAYS_INLINE u64 GetAff0() const { return this->GetBits(0, 8); } constexpr ALWAYS_INLINE u64 GetAff1() const { return this->GetBits(8, 8); } constexpr ALWAYS_INLINE u64 GetAff2() const { return this->GetBits(16, 8); } constexpr ALWAYS_INLINE u64 GetAff3() const { return this->GetBits(32, 8); } constexpr ALWAYS_INLINE u64 GetCpuOnArgument() const { constexpr u64 Mask = 0x000000FF00FFFF00ul; return this->GetValue() & Mask; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(ThreadId) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(ThreadId, tpidr_el1) }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(OsLockAccess) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(OsLockAccess, oslar_el1) }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(ContextId) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(ContextId, contextidr_el1) constexpr ALWAYS_INLINE decltype(auto) SetProcId(u32 proc_id) { this->SetBits(0, BITSIZEOF(proc_id), proc_id); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(MainId) { public: enum class Implementer { ArmLimited = 0x41, }; enum class PrimaryPartNumber { CortexA53 = 0xD03, CortexA57 = 0xD07, }; public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(MainId, midr_el1) public: constexpr ALWAYS_INLINE Implementer GetImplementer() const { return static_cast<Implementer>(this->GetBits(24, 8)); } constexpr ALWAYS_INLINE u64 GetVariant() const { return this->GetBits(20, 4); } constexpr ALWAYS_INLINE u64 GetArchitecture() const { return this->GetBits(16, 4); } constexpr ALWAYS_INLINE PrimaryPartNumber GetPrimaryPartNumber() const { return static_cast<PrimaryPartNumber>(this->GetBits(4, 12)); } constexpr ALWAYS_INLINE u64 GetRevision() const { return this->GetBits(0, 4); } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(SystemControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(SystemControl, sctlr_el1) constexpr ALWAYS_INLINE decltype(auto) SetWxn(bool en) { this->SetBit(19, en); return *this; } constexpr ALWAYS_INLINE bool GetWxn() const { return this->GetBits(19, 1) != 0; } }; /* Accessors for timer registers. */ MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CounterTimerKernelControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CounterTimerKernelControl, cntkctl_el1) constexpr ALWAYS_INLINE decltype(auto) SetEl0PctEn(bool en) { this->SetBit(0, en); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CounterTimerPhysicalTimerControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CounterTimerPhysicalTimerControl, cntp_ctl_el0) constexpr ALWAYS_INLINE decltype(auto) SetEnable(bool en) { this->SetBit(0, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetIMask(bool en) { this->SetBit(1, en); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CounterTimerPhysicalTimerCompareValue) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CounterTimerPhysicalTimerCompareValue, cntp_cval_el0) constexpr ALWAYS_INLINE u64 GetCompareValue() { return this->GetValue(); } constexpr ALWAYS_INLINE decltype(auto) SetCompareValue(u64 value) { this->SetBits(0, BITSIZEOF(value), value); return *this; } }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CounterTimerPhysicalCountValue) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CounterTimerPhysicalCountValue, cntpct_el0) constexpr ALWAYS_INLINE u64 GetCount() { return this->GetValue(); } }; /* Accessors for cache registers. */ MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CacheLineId) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CacheLineId, clidr_el1) public: constexpr ALWAYS_INLINE int GetLevelsOfCoherency() const { return static_cast<int>(this->GetBits(24, 3)); } constexpr ALWAYS_INLINE int GetLevelsOfUnification() const { return static_cast<int>(this->GetBits(21, 3)); } /* TODO: Other bitfield accessors? */ }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(CacheSizeId) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(CacheSizeId, ccsidr_el1) public: constexpr ALWAYS_INLINE int GetNumberOfSets() const { return static_cast<int>(this->GetBits(13, 15)); } constexpr ALWAYS_INLINE int GetAssociativity() const { return static_cast<int>(this->GetBits(3, 10)); } constexpr ALWAYS_INLINE int GetLineSize() const { return static_cast<int>(this->GetBits(0, 3)); } /* TODO: Other bitfield accessors? */ }; MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(PerformanceMonitorsControl) { public: MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(PerformanceMonitorsControl, pmcr_el0) public: constexpr ALWAYS_INLINE u64 GetN() const { return this->GetBits(11, 5); } constexpr ALWAYS_INLINE decltype(auto) SetEventCounterReset(bool en) { this->SetBit(1, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetCycleCounterReset(bool en) { this->SetBit(2, en); return *this; } /* TODO: Other bitfield accessors? */ }; #undef FOR_I_IN_0_TO_15 #undef MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS #undef MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS #undef MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS #undef MESOSPHERE_CPU_GET_SYSREG #undef MESOSPHERE_CPU_SET_SYSREG } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_debug.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_debug_base.hpp> namespace ams::kern { class KThread; class KProcess; } namespace ams::kern::arch::arm64 { class KDebug final : public KAutoObjectWithSlabHeapAndContainer<KDebug, KDebugBase> { MESOSPHERE_AUTOOBJECT_TRAITS(KDebug, KSynchronizationObject); public: explicit KDebug() { /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } public: /* NOTE: These are virtual in Nintendo's kernel. */ Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags); Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags); private: Result GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags); Result SetFpuContext(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags); public: static uintptr_t GetProgramCounter(const KThread &thread); static void SetPreviousProgramCounter(); static void PrintRegister(KThread *thread = nullptr); static void PrintBacktrace(KThread *thread = nullptr); static Result BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size); static Result SetHardwareBreakPoint(ams::svc::HardwareBreakPointRegisterName name, u64 flags, u64 value); static constexpr bool IsBreakInstruction(u32 insn, u32 psr) { constexpr u32 BreakInstructionAarch64 = 0xE7FFFFFF; constexpr u32 BreakInstructionAarch32 = 0xE7FFDEFE; constexpr u32 BreakInstructionThumb32 = 0xB68E; if ((psr & 0x10) == 0) { return insn == BreakInstructionAarch64; } else { if ((psr & 0x20) == 0) { return insn == BreakInstructionAarch32; } else { return insn == BreakInstructionThumb32; } } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_exception_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern::arch::arm64 { struct KExceptionContext { u64 x[(30 - 0) + 1]; u64 sp; u64 pc; u32 psr; u32 write; u64 tpidr; u64 reserved; constexpr void GetSvcThreadContext(ams::svc::LastThreadContext *out) const { if ((this->psr & 0x10) == 0) { /* aarch64 thread. */ out->fp = this->x[29]; out->sp = this->sp; out->lr = this->x[30]; out->pc = this->pc; } else { /* aarch32 thread. */ out->fp = this->x[11]; out->sp = this->x[13]; out->lr = this->x[14]; out->pc = this->pc; } } }; static_assert(sizeof(KExceptionContext) == EXCEPTION_CONTEXT_SIZE); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8); static_assert(AMS_OFFSETOF(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9); static_assert(AMS_OFFSETOF(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10); static_assert(AMS_OFFSETOF(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11); static_assert(AMS_OFFSETOF(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12); static_assert(AMS_OFFSETOF(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13); static_assert(AMS_OFFSETOF(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14); static_assert(AMS_OFFSETOF(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15); static_assert(AMS_OFFSETOF(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16); static_assert(AMS_OFFSETOF(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17); static_assert(AMS_OFFSETOF(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18); static_assert(AMS_OFFSETOF(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19); static_assert(AMS_OFFSETOF(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20); static_assert(AMS_OFFSETOF(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21); static_assert(AMS_OFFSETOF(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22); static_assert(AMS_OFFSETOF(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23); static_assert(AMS_OFFSETOF(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24); static_assert(AMS_OFFSETOF(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25); static_assert(AMS_OFFSETOF(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26); static_assert(AMS_OFFSETOF(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27); static_assert(AMS_OFFSETOF(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28); static_assert(AMS_OFFSETOF(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29); static_assert(AMS_OFFSETOF(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30); static_assert(AMS_OFFSETOF(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP); static_assert(AMS_OFFSETOF(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC); static_assert(AMS_OFFSETOF(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR); static_assert(AMS_OFFSETOF(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_hardware_timer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_hardware_timer_base.hpp> namespace ams::kern::arch::arm64 { class KHardwareTimer : public KInterruptTask, public KHardwareTimerBase { private: s64 m_maximum_time; public: constexpr KHardwareTimer() : KInterruptTask(), KHardwareTimerBase(), m_maximum_time(std::numeric_limits<s64>::max()) { /* ... */ } public: /* Public API. */ NOINLINE void Initialize(); NOINLINE void Finalize(); static s64 GetTick() { return GetCount(); } void RegisterAbsoluteTask(KTimerTask *task, s64 task_time) { KScopedDisableDispatch dd; KScopedSpinLock lk(this->GetLock()); if (this->RegisterAbsoluteTaskImpl(task, task_time)) { if (task_time <= m_maximum_time) { SetCompareValue(task_time); EnableInterrupt(); } } } private: /* Hardware register accessors. */ static ALWAYS_INLINE void InitializeGlobalTimer() { /* Set kernel control. */ cpu::CounterTimerKernelControlRegisterAccessor(0).SetEl0PctEn(true).Store(); /* Disable the physical timer. */ cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(false).SetIMask(false).Store(); /* Set the compare value to the maximum. */ cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(std::numeric_limits<u64>::max()).Store(); /* Enable the physical timer, with interrupt masked. */ cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(true).Store(); } static ALWAYS_INLINE void EnableInterrupt() { cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(false).Store(); } static ALWAYS_INLINE void DisableInterrupt() { cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(true).SetIMask(true).Store(); } static ALWAYS_INLINE void StopTimer() { /* Set the compare value to the maximum. */ cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(std::numeric_limits<u64>::max()).Store(); /* Disable the physical timer. */ cpu::CounterTimerPhysicalTimerControlRegisterAccessor(0).SetEnable(false).SetIMask(false).Store(); } static ALWAYS_INLINE s64 GetCount() { return cpu::CounterTimerPhysicalCountValueRegisterAccessor().GetCount(); } static ALWAYS_INLINE void SetCompareValue(s64 value) { cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor(0).SetCompareValue(static_cast<u64>(value)).Store(); } public: virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); return this; } virtual void DoTask() override; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_controller.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_typed_address.hpp> #if 1 #include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp> namespace ams::kern::arch::arm64 { using ams::kern::arch::arm::GicDistributor; using ams::kern::arch::arm::GicCpuInterface; using ams::kern::arch::arm::KInterruptController; } #else #error "Unknown board for KInterruptController" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_interrupt_task.hpp> #include <mesosphere/kern_select_interrupt_controller.hpp> namespace ams::kern::arch::arm64 { class KInterruptManager { NON_COPYABLE(KInterruptManager); NON_MOVEABLE(KInterruptManager); private: struct KCoreLocalInterruptEntry { KInterruptHandler *handler; bool manually_cleared; bool needs_clear; u8 priority; constexpr KCoreLocalInterruptEntry() : handler(nullptr), manually_cleared(false), needs_clear(false), priority(KInterruptController::PriorityLevel_Low) { /* ... */ } }; struct KGlobalInterruptEntry { KInterruptHandler *handler; bool manually_cleared; bool needs_clear; constexpr KGlobalInterruptEntry() : handler(nullptr), manually_cleared(false), needs_clear(false) { /* ... */ } }; private: KCoreLocalInterruptEntry m_core_local_interrupts[cpu::NumCores][KInterruptController::NumLocalInterrupts]{}; KInterruptController m_interrupt_controller{}; KInterruptController::LocalState m_local_states[cpu::NumCores]{}; bool m_local_state_saved[cpu::NumCores]{}; mutable KSpinLock m_global_interrupt_lock{}; KGlobalInterruptEntry m_global_interrupts[KInterruptController::NumGlobalInterrupts]{}; KInterruptController::GlobalState m_global_state{}; bool m_global_state_saved{}; private: ALWAYS_INLINE KSpinLock &GetGlobalInterruptLock() const { return m_global_interrupt_lock; } ALWAYS_INLINE KGlobalInterruptEntry &GetGlobalInterruptEntry(s32 irq) { return m_global_interrupts[KInterruptController::GetGlobalInterruptIndex(irq)]; } ALWAYS_INLINE KCoreLocalInterruptEntry &GetLocalInterruptEntry(s32 irq) { return m_core_local_interrupts[GetCurrentCoreId()][KInterruptController::GetLocalInterruptIndex(irq)]; } bool OnHandleInterrupt(); public: constexpr KInterruptManager() = default; NOINLINE void Initialize(s32 core_id); NOINLINE void Finalize(s32 core_id); NOINLINE void Save(s32 core_id); NOINLINE void Restore(s32 core_id); bool IsInterruptDefined(s32 irq) const { return m_interrupt_controller.IsInterruptDefined(irq); } bool IsGlobal(s32 irq) const { return m_interrupt_controller.IsGlobal(irq); } bool IsLocal(s32 irq) const { return m_interrupt_controller.IsLocal(irq); } NOINLINE Result BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level); NOINLINE void UnbindHandler(s32 irq, s32 core); NOINLINE void ClearInterrupt(s32 irq, s32 core_id); ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq, u64 core_mask) { m_interrupt_controller.SendInterProcessorInterrupt(irq, core_mask); } ALWAYS_INLINE void SendInterProcessorInterrupt(s32 irq) { m_interrupt_controller.SendInterProcessorInterrupt(irq); } static void HandleInterrupt(bool user_mode); private: Result BindGlobal(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level); Result BindLocal(KInterruptHandler *handler, s32 irq, s32 priority, bool manual_clear); void UnbindGlobal(s32 irq); void UnbindLocal(s32 irq); void ClearGlobal(s32 irq); void ClearLocal(s32 irq); private: [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledState() { u64 intr_state; __asm__ __volatile__("mrs %[intr_state], daif\n" "ubfx %[intr_state], %[intr_state], #7, #1" : [intr_state]"=r"(intr_state) :: "memory"); return intr_state; } public: static ALWAYS_INLINE void EnableInterrupts() { __asm__ __volatile__("msr daifclr, #2" ::: "memory"); } static ALWAYS_INLINE void DisableInterrupts() { __asm__ __volatile__("msr daifset, #2" ::: "memory"); } [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndDisableInterrupts() { const auto intr_state = GetInterruptsEnabledState(); DisableInterrupts(); return intr_state; } [[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndEnableInterrupts() { const auto intr_state = GetInterruptsEnabledState(); EnableInterrupts(); return intr_state; } static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) { u64 tmp; __asm__ __volatile__("mrs %[tmp], daif\n" "bfi %[tmp], %[intr_state], #7, #1\n" "msr daif, %[tmp]" : [tmp]"=&r"(tmp) : [intr_state]"r"(intr_state) : "memory"); } static ALWAYS_INLINE bool AreInterruptsEnabled() { return GetInterruptsEnabledState() == 0; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_interrupt_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::kern::arch::arm64 { namespace interrupt_name { enum KInterruptName : s32 { /* SGIs */ KInterruptName_ThreadTerminate = 0, KInterruptName_CacheOperation = 1, KInterruptName_Scheduler = 2, KInterruptName_CoreBarrier = 3, KInterruptName_PerformanceCounter = 4, /* PPIs */ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) KInterruptName_VirtualMaintenance = 25, KInterruptName_HypervisorTimer = 26, KInterruptName_VirtualTimer = 27, KInterruptName_LegacyNFiq = 28, KInterruptName_SecurePhysicalTimer = 29, KInterruptName_NonSecurePhysicalTimer = 30, KInterruptName_LegacyNIrq = 31, #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) KInterruptName_VirtualTimer = 27, KInterruptName_SecurePhysicalTimer = 29, KInterruptName_NonSecurePhysicalTimer = 30, #endif #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) KInterruptName_MemoryController = 109, #endif }; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_memory_region_device_types.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* All architectures must define NumArchitectureDeviceRegions. */ constexpr inline const auto NumArchitectureDeviceRegions = 3; constexpr inline const auto KMemoryRegionType_Uart = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0); constexpr inline const auto KMemoryRegionType_InterruptCpuInterface = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_InterruptDistributor = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap); static_assert(KMemoryRegionType_Uart .GetValue() == (0x1D)); static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() == (0x2D | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_InterruptDistributor .GetValue() == (0x4D | KMemoryRegionAttr_NoUserMap)); ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_page_table_base.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_page_table_manager.hpp> namespace ams::kern::arch::arm64 { class KPageTable final : public KPageTableBase { NON_COPYABLE(KPageTable); NON_MOVEABLE(KPageTable); private: friend class KPageTableBase; public: using TraversalEntry = KPageTableImpl::TraversalEntry; using TraversalContext = KPageTableImpl::TraversalContext; enum BlockType { BlockType_L3Block, BlockType_L3ContiguousBlock, BlockType_L2Block, #ifdef ATMOSPHERE_BOARD_NINTENDO_NX BlockType_L2TegraSmmuBlock, #endif BlockType_L2ContiguousBlock, BlockType_L1Block, BlockType_Count, }; static_assert(L3BlockSize == PageSize); static constexpr size_t ContiguousPageSize = L3ContiguousBlockSize; #ifdef ATMOSPHERE_BOARD_NINTENDO_NX static constexpr size_t L2TegraSmmuBlockSize = 2 * L2BlockSize; #endif static constexpr size_t BlockSizes[BlockType_Count] = { [BlockType_L3Block] = L3BlockSize, [BlockType_L3ContiguousBlock] = L3ContiguousBlockSize, [BlockType_L2Block] = L2BlockSize, #ifdef ATMOSPHERE_BOARD_NINTENDO_NX [BlockType_L2TegraSmmuBlock] = L2TegraSmmuBlockSize, #endif [BlockType_L2ContiguousBlock] = L2ContiguousBlockSize, [BlockType_L1Block] = L1BlockSize, }; static constexpr BlockType GetMaxBlockType() { return BlockType_L1Block; } static constexpr size_t GetBlockSize(BlockType type) { return BlockSizes[type]; } static constexpr BlockType GetBlockType(size_t size) { switch (size) { case L3BlockSize: return BlockType_L3Block; case L3ContiguousBlockSize: return BlockType_L3ContiguousBlock; case L2BlockSize: return BlockType_L2Block; #ifdef ATMOSPHERE_BOARD_NINTENDO_NX case L2TegraSmmuBlockSize: return BlockType_L2TegraSmmuBlock; #endif case L2ContiguousBlockSize: return BlockType_L2ContiguousBlock; case L1BlockSize: return BlockType_L1Block; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } static constexpr size_t GetSmallerAlignment(size_t alignment) { MESOSPHERE_ASSERT(alignment > L3BlockSize); return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) - 1)); } static constexpr size_t GetLargerAlignment(size_t alignment) { MESOSPHERE_ASSERT(alignment < L1BlockSize); return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) + 1)); } public: /* TODO: How should this size be determined. Does the KProcess slab count need to go in a header as a define? */ static constexpr size_t NumTtbr0Entries = 81; private: static constinit inline const volatile u64 s_ttbr0_entries[NumTtbr0Entries] = {}; private: KPageTableManager *m_manager; u8 m_asid; protected: Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll); Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll); void FinalizeUpdateImpl(PageLinkedList *page_list); KPageTableManager &GetPageTableManager() const { return *m_manager; } private: constexpr PageTableEntry GetEntryTemplate(const KPageProperties properties) const { /* Check that the property is not kernel execute. */ MESOSPHERE_ABORT_UNLESS((properties.perm & KMemoryPermission_KernelExecute) == 0); /* Set basic attributes. */ PageTableEntry entry{PageTableEntry::ExtensionFlag_Valid}; entry.SetPrivilegedExecuteNever(true); entry.SetAccessFlag(PageTableEntry::AccessFlag_Accessed); entry.SetShareable(PageTableEntry::Shareable_InnerShareable); if (!this->IsKernel()) { entry.SetGlobal(false); } /* Set page attribute. */ if (properties.io) { MESOSPHERE_ABORT_UNLESS(!properties.uncached); MESOSPHERE_ABORT_UNLESS((properties.perm & KMemoryPermission_UserExecute) == 0); entry.SetPageAttribute(PageTableEntry::PageAttribute_Device_nGnRnE) .SetUserExecuteNever(true); } else if (properties.uncached) { MESOSPHERE_ABORT_UNLESS((properties.perm & KMemoryPermission_UserExecute) == 0); entry.SetPageAttribute(PageTableEntry::PageAttribute_NormalMemoryNotCacheable) .SetUserExecuteNever(true); } else { entry.SetPageAttribute(PageTableEntry::PageAttribute_NormalMemory); if ((properties.perm & KMemoryPermission_UserExecute) != 0) { /* Check that the permission is either r--/--x or r--/r-x. */ MESOSPHERE_ABORT_UNLESS((properties.perm & ~ams::svc::MemoryPermission_Read) == (KMemoryPermission_KernelRead | KMemoryPermission_UserExecute)); } else { entry.SetUserExecuteNever(true); } } /* Set AP[1] based on perm. */ switch (properties.perm & KMemoryPermission_UserReadWrite) { case KMemoryPermission_UserReadWrite: case KMemoryPermission_UserRead: entry.SetUserAccessible(true); break; case KMemoryPermission_KernelReadWrite: case KMemoryPermission_KernelRead: entry.SetUserAccessible(false); break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } /* Set AP[2] based on perm. */ switch (properties.perm & KMemoryPermission_UserReadWrite) { case KMemoryPermission_UserReadWrite: case KMemoryPermission_KernelReadWrite: entry.SetReadOnly(false); break; case KMemoryPermission_KernelRead: case KMemoryPermission_UserRead: entry.SetReadOnly(true); break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } /* Set the fault bit based on whether the page is mapped. */ entry.SetMapped((properties.perm & KMemoryPermission_NotMapped) == 0); return entry; } public: constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_asid() { /* ... */ } explicit KPageTable() { /* ... */ } static NOINLINE void Initialize(s32 core_id); static const volatile u64 &GetTtbr0Entry(size_t index) { return s_ttbr0_entries[index]; } static ALWAYS_INLINE u64 GetKernelTtbr0() { return s_ttbr0_entries[0]; } static ALWAYS_INLINE void ActivateKernel() { /* Activate, using asid 0 and process id = 0xFFFFFFFF */ cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF); } static ALWAYS_INLINE void ActivateProcess(size_t proc_idx, u32 proc_id) { cpu::SwitchProcess(s_ttbr0_entries[proc_idx + 1], proc_id); } NOINLINE void InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end); NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index); void Finalize(); static void NoteUpdatedCallback(const void *pt) { /* Note the update. */ static_cast<const KPageTable *>(pt)->NoteUpdated(); } private: Result Unmap(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool force, bool reuse_ll); Result Map(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, size_t page_size, PageLinkedList *page_list, bool reuse_ll); Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll); Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll); bool MergePages(TraversalContext *context, PageLinkedList *page_list); void MergePages(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list); Result SeparatePagesImpl(TraversalEntry *entry, TraversalContext *context, KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll); Result SeparatePages(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool reuse_ll); Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll); static ALWAYS_INLINE void PteDataMemoryBarrier() { cpu::DataMemoryBarrierInnerShareableStore(); } static ALWAYS_INLINE void ClearPageTable(KVirtualAddress table) { cpu::ClearPageToZero(GetVoidPointer(table)); } ALWAYS_INLINE void OnTableUpdated() const { cpu::InvalidateTlbByAsid(m_asid); } ALWAYS_INLINE void OnKernelTableUpdated() const { cpu::InvalidateEntireTlbDataOnly(); } ALWAYS_INLINE void OnKernelTableSinglePageUpdated(KProcessAddress virt_addr) const { cpu::InvalidateTlbByVaDataOnly(virt_addr); } void NoteUpdated() const; void NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const; KVirtualAddress AllocatePageTable(PageLinkedList *page_list, bool reuse_ll) const { KVirtualAddress table = this->GetPageTableManager().Allocate(); if (table == Null<KVirtualAddress>) { if (reuse_ll && page_list->Peek()) { table = KVirtualAddress(reinterpret_cast<uintptr_t>(page_list->Pop())); } else { return Null<KVirtualAddress>; } } MESOSPHERE_ASSERT(this->GetPageTableManager().GetRefCount(table) == 0); return table; } void FreePageTable(PageLinkedList *page_list, KVirtualAddress table) const { MESOSPHERE_ASSERT(this->GetPageTableManager().IsInPageTableHeap(table)); MESOSPHERE_ASSERT(this->GetPageTableManager().GetRefCount(table) == 0); page_list->Push(table); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_entry.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern::arch::arm64 { constexpr size_t BlocksPerContiguousBlock = 0x10; constexpr size_t BlocksPerTable = PageSize / sizeof(u64); constexpr size_t L1BlockSize = 1_GB; constexpr size_t L1ContiguousBlockSize = BlocksPerContiguousBlock * L1BlockSize; constexpr size_t L2BlockSize = 2_MB; constexpr size_t L2ContiguousBlockSize = BlocksPerContiguousBlock * L2BlockSize; constexpr size_t L3BlockSize = PageSize; constexpr size_t L3ContiguousBlockSize = BlocksPerContiguousBlock * L3BlockSize; class PageTableEntry { public: struct InvalidTag{}; struct TableTag{}; struct BlockTag{}; struct SeparateContiguousTag{}; enum Permission : u64 { Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)), Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)), Permission_KernelR = ((1ul << 53) | (1ul << 54) | (2ul << 6)), Permission_KernelRW = ((1ul << 53) | (1ul << 54) | (0ul << 6)), Permission_UserRX = ((1ul << 53) | (0ul << 54) | (3ul << 6)), Permission_UserR = ((1ul << 53) | (1ul << 54) | (3ul << 6)), Permission_UserRW = ((1ul << 53) | (1ul << 54) | (1ul << 6)), }; enum Shareable : u64 { Shareable_NonShareable = (0 << 8), Shareable_OuterShareable = (2 << 8), Shareable_InnerShareable = (3 << 8), }; /* Official attributes are: */ /* 0x00, 0x04, 0xFF, 0x44. 4-7 are unused. */ enum PageAttribute : u64 { PageAttribute_Device_nGnRnE = (0 << 2), PageAttribute_Device_nGnRE = (1 << 2), PageAttribute_NormalMemory = (2 << 2), PageAttribute_NormalMemoryNotCacheable = (3 << 2), }; enum AccessFlag : u64 { AccessFlag_NotAccessed = (0 << 10), AccessFlag_Accessed = (1 << 10), }; enum MappingFlag : u64 { MappingFlag_NotMapped = (0 << 0), MappingFlag_Mapped = (1 << 0), }; enum SoftwareReservedBit : u8 { SoftwareReservedBit_None = 0, SoftwareReservedBit_DisableMergeHead = (1u << 0), SoftwareReservedBit_DisableMergeHeadAndBody = (1u << 1), SoftwareReservedBit_DisableMergeHeadTail = (1u << 2), SoftwareReservedBit_Valid = (1u << 3), }; static constexpr ALWAYS_INLINE std::underlying_type<SoftwareReservedBit>::type EncodeSoftwareReservedBits(bool head, bool head_body, bool tail) { return (head ? SoftwareReservedBit_DisableMergeHead : SoftwareReservedBit_None) | (head_body ? SoftwareReservedBit_DisableMergeHeadAndBody : SoftwareReservedBit_None) | (tail ? SoftwareReservedBit_DisableMergeHeadTail : SoftwareReservedBit_None); } enum ExtensionFlag : u64 { ExtensionFlag_DisableMergeHead = (static_cast<u64>(SoftwareReservedBit_DisableMergeHead) << 55), ExtensionFlag_DisableMergeHeadAndBody = (static_cast<u64>(SoftwareReservedBit_DisableMergeHeadAndBody) << 55), ExtensionFlag_DisableMergeTail = (static_cast<u64>(SoftwareReservedBit_DisableMergeHeadTail) << 55), ExtensionFlag_Valid = (static_cast<u64>(SoftwareReservedBit_Valid) << 55), ExtensionFlag_ValidAndMapped = (ExtensionFlag_Valid | MappingFlag_Mapped), ExtensionFlag_TestTableMask = (ExtensionFlag_Valid | (1ul << 1)), }; enum Type : u64 { Type_None = 0x0, Type_L1Block = ExtensionFlag_Valid, Type_L1Table = 0x2, Type_L2Block = ExtensionFlag_Valid, Type_L2Table = 0x2, Type_L3Block = ExtensionFlag_TestTableMask, }; enum ContigType : u64 { ContigType_NotContiguous = (0x0ul << 52), ContigType_Contiguous = (0x1ul << 52), }; protected: u64 m_attributes; public: /* Take in a raw attribute. */ constexpr explicit ALWAYS_INLINE PageTableEntry() : m_attributes() { /* ... */ } constexpr explicit ALWAYS_INLINE PageTableEntry(u64 attr) : m_attributes(attr) { /* ... */ } constexpr explicit ALWAYS_INLINE PageTableEntry(InvalidTag) : m_attributes(0) { /* ... */ } /* Extend a previous attribute. */ constexpr explicit ALWAYS_INLINE PageTableEntry(const PageTableEntry &rhs, u64 new_attr) : m_attributes(rhs.m_attributes | new_attr) { /* ... */ } /* Construct a new attribute. */ constexpr explicit ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share, MappingFlag m) : m_attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share) | static_cast<u64>(m)) { /* ... */ } /* Construct a table. */ constexpr explicit ALWAYS_INLINE PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool is_kernel, bool pxn, size_t ref_count) : PageTableEntry(((is_kernel ? 0x3ul : 0) << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | (ref_count << 2) | 0x3) { /* ... */ } /* Construct a block. */ constexpr explicit ALWAYS_INLINE PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, u8 sw_reserved_bits, bool contig, bool page) : PageTableEntry(attr, (static_cast<u64>(sw_reserved_bits) << 55) | (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | (page ? ExtensionFlag_TestTableMask : ExtensionFlag_Valid)) { /* ... */ } constexpr explicit ALWAYS_INLINE PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, SeparateContiguousTag) : PageTableEntry(attr, GetInteger(phys_addr)) { /* ... */ } protected: constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const { return (m_attributes >> offset) & ((1ul << count) - 1); } constexpr ALWAYS_INLINE u64 SelectBits(size_t offset, size_t count) const { return m_attributes & (((1ul << count) - 1) << offset); } constexpr ALWAYS_INLINE void SetBits(size_t offset, size_t count, u64 value) { const u64 mask = ((1ul << count) - 1) << offset; m_attributes &= ~mask; m_attributes |= (value & (mask >> offset)) << offset; } constexpr ALWAYS_INLINE void SetBitsDirect(size_t offset, size_t count, u64 value) { const u64 mask = ((1ul << count) - 1) << offset; m_attributes &= ~mask; m_attributes |= (value & mask); } constexpr ALWAYS_INLINE void SetBit(size_t offset, bool enabled) { const u64 mask = 1ul << offset; if (enabled) { m_attributes |= mask; } else { m_attributes &= ~mask; } } public: constexpr ALWAYS_INLINE u8 GetSoftwareReservedBits() const { return this->GetBits(55, 3); } constexpr ALWAYS_INLINE bool IsHeadMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHead) != 0; } constexpr ALWAYS_INLINE bool IsHeadAndBodyMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHeadAndBody) != 0; } constexpr ALWAYS_INLINE bool IsTailMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHeadTail) != 0; } constexpr ALWAYS_INLINE bool IsHeadOrHeadAndBodyMergeDisabled() const { return (this->GetSoftwareReservedBits() & (SoftwareReservedBit_DisableMergeHead | SoftwareReservedBit_DisableMergeHeadAndBody)) != 0; } constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; } constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; } constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; } constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; } constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->SelectBits(10, 1)); } constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->SelectBits(8, 2)); } constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->SelectBits(2, 3)); } constexpr ALWAYS_INLINE int GetAccessFlagInteger() const { return static_cast<int>(this->GetBits(10, 1)); } constexpr ALWAYS_INLINE int GetShareableInteger() const { return static_cast<int>(this->GetBits(8, 2)); } constexpr ALWAYS_INLINE int GetPageAttributeInteger() const { return static_cast<int>(this->GetBits(2, 3)); } constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; } constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; } constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; } constexpr ALWAYS_INLINE u64 GetTestTableMask() const { return (m_attributes & ExtensionFlag_TestTableMask); } constexpr ALWAYS_INLINE bool IsBlock() const { return (m_attributes & ExtensionFlag_TestTableMask) == ExtensionFlag_Valid; } constexpr ALWAYS_INLINE bool IsPage() const { return (m_attributes & ExtensionFlag_TestTableMask) == ExtensionFlag_TestTableMask; } constexpr ALWAYS_INLINE bool IsTable() const { return (m_attributes & ExtensionFlag_TestTableMask) == 2; } constexpr ALWAYS_INLINE bool IsEmpty() const { return (m_attributes & ExtensionFlag_TestTableMask) == 0; } constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const { return this->SelectBits(12, 36); } constexpr ALWAYS_INLINE bool IsMappedBlock() const { return this->GetBits(0, 2) == 1; } constexpr ALWAYS_INLINE bool IsMappedTable() const { return this->GetBits(0, 2) == 3; } constexpr ALWAYS_INLINE bool IsMappedEmpty() const { return this->GetBits(0, 2) == 0; } constexpr ALWAYS_INLINE bool IsMapped() const { return this->GetBits(0, 1) != 0; } constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetPrivilegedExecuteNever(bool en) { this->SetBit(53, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetContiguous(bool en) { this->SetBit(52, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetGlobal(bool en) { this->SetBit(11, !en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetAccessFlag(AccessFlag f) { this->SetBitsDirect(10, 1, f); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetShareable(Shareable s) { this->SetBitsDirect(8, 2, s); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetReadOnly(bool en) { this->SetBit(7, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetUserAccessible(bool en) { this->SetBit(6, en); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetPageAttribute(PageAttribute a) { this->SetBitsDirect(2, 3, a); return *this; } constexpr ALWAYS_INLINE decltype(auto) SetMapped(bool m) { static_assert(static_cast<u64>(MappingFlag_Mapped == (1 << 0))); this->SetBit(0, m); return *this; } constexpr ALWAYS_INLINE size_t GetTableReferenceCount() const { return this->GetBits(2, 10); } constexpr ALWAYS_INLINE decltype(auto) SetTableReferenceCount(size_t num) { this->SetBits(2, 10, num); return *this; } constexpr ALWAYS_INLINE decltype(auto) OpenTableReferences(size_t num) { MESOSPHERE_ASSERT(this->GetTableReferenceCount() + num <= BlocksPerTable + 1); return this->SetTableReferenceCount(this->GetTableReferenceCount() + num); } constexpr ALWAYS_INLINE decltype(auto) CloseTableReferences(size_t num) { MESOSPHERE_ASSERT(this->GetTableReferenceCount() >= num); return this->SetTableReferenceCount(this->GetTableReferenceCount() - num); } constexpr ALWAYS_INLINE decltype(auto) SetValid() { MESOSPHERE_ASSERT((m_attributes & ExtensionFlag_Valid) == 0); m_attributes |= ExtensionFlag_Valid; return *this; } constexpr ALWAYS_INLINE u64 GetEntryTemplateForMerge() const { constexpr u64 BaseMask = (0xFFFF000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); return m_attributes & BaseMask; } constexpr ALWAYS_INLINE bool IsForMerge(u64 attr) const { constexpr u64 BaseMaskForMerge = ~static_cast<u64>(ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail); return (m_attributes & BaseMaskForMerge) == attr; } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForSeparateContiguousMask(size_t idx) { constexpr u64 BaseMask = (0xFFFF000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < BlocksPerContiguousBlock - 1) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForSeparateContiguous(size_t idx) const { return m_attributes & GetEntryTemplateForSeparateContiguousMask(idx); } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForSeparateMask(size_t idx) { constexpr u64 BaseMask = (0xFFFF000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < BlocksPerContiguousBlock) { return BaseMask | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < BlocksPerTable - 1) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForSeparate(size_t idx) const { return m_attributes & GetEntryTemplateForSeparateMask(idx); } constexpr ALWAYS_INLINE u64 GetRawAttributesUnsafe() const { return m_attributes; } constexpr ALWAYS_INLINE u64 GetRawAttributesUnsafeForSwap() const { return m_attributes; } protected: constexpr ALWAYS_INLINE u64 GetRawAttributes() const { return m_attributes; } }; static_assert(sizeof(PageTableEntry) == sizeof(u64)); constexpr inline PageTableEntry InvalidPageTableEntry = PageTableEntry(PageTableEntry::InvalidTag{}); constexpr inline size_t MaxPageTableEntries = PageSize / sizeof(PageTableEntry); class L1PageTableEntry : public PageTableEntry { public: constexpr explicit ALWAYS_INLINE L1PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ } constexpr explicit ALWAYS_INLINE L1PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool pxn) : PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3) { /* ... */ } constexpr explicit ALWAYS_INLINE L1PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool is_kernel, bool pxn) : PageTableEntry(((is_kernel ? 0x3ul : 0) << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3) { /* ... */ } constexpr explicit ALWAYS_INLINE L1PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, u8 sw_reserved_bits, bool contig) : PageTableEntry(attr, (static_cast<u64>(sw_reserved_bits) << 55) | (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1) { /* ... */ } constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const { return this->SelectBits(30, 18); } constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const { return this->SelectBits(12, 36); } constexpr ALWAYS_INLINE bool GetTable(KPhysicalAddress &out) const { if (this->IsTable()) { out = this->GetTable(); return true; } else { return false; } } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForL2BlockMask(size_t idx) { constexpr u64 BaseMask = (0xFFF0000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < L2ContiguousBlockSize / L2BlockSize) { return BaseMask | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < (L1BlockSize - L2ContiguousBlockSize) / L2BlockSize) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForL2Block(size_t idx) const { return m_attributes & GetEntryTemplateForL2BlockMask(idx); } constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, u8 sw_reserved_bits, bool contig) const { /* Check whether this has the same permission/etc as the desired attributes. */ return L1PageTableEntry(BlockTag{}, this->GetBlock(), rhs, sw_reserved_bits, contig).GetRawAttributes() == this->GetRawAttributes(); } }; class L2PageTableEntry : public PageTableEntry { public: constexpr explicit ALWAYS_INLINE L2PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ } constexpr explicit ALWAYS_INLINE L2PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool pxn) : PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3) { /* ... */ } constexpr explicit ALWAYS_INLINE L2PageTableEntry(TableTag, KPhysicalAddress phys_addr, bool is_kernel, bool pxn) : PageTableEntry(((is_kernel ? 0x3ul : 0) << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3) { /* ... */ } constexpr explicit ALWAYS_INLINE L2PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, u8 sw_reserved_bits, bool contig) : PageTableEntry(attr, (static_cast<u64>(sw_reserved_bits) << 55) | (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1) { /* ... */ } constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const { return this->SelectBits(21, 27); } constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const { return this->SelectBits(12, 36); } constexpr ALWAYS_INLINE bool GetTable(KPhysicalAddress &out) const { if (this->IsTable()) { out = this->GetTable(); return true; } else { return false; } } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForL2BlockMask(size_t idx) { constexpr u64 BaseMask = (0xFFF0000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < (L2ContiguousBlockSize / L2BlockSize) - 1) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForL2Block(size_t idx) const { return m_attributes & GetEntryTemplateForL2BlockMask(idx); } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForL3BlockMask(size_t idx) { constexpr u64 BaseMask = (0xFFF0000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < L3ContiguousBlockSize / L3BlockSize) { return BaseMask | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < (L2BlockSize - L3ContiguousBlockSize) / L3BlockSize) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForL3Block(size_t idx) const { return m_attributes & GetEntryTemplateForL3BlockMask(idx); } constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, u8 sw_reserved_bits, bool contig) const { /* Check whether this has the same permission/etc as the desired attributes. */ return L2PageTableEntry(BlockTag{}, this->GetBlock(), rhs, sw_reserved_bits, contig).GetRawAttributes() == this->GetRawAttributes(); } }; class L3PageTableEntry : public PageTableEntry { public: constexpr explicit ALWAYS_INLINE L3PageTableEntry(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ } constexpr explicit ALWAYS_INLINE L3PageTableEntry(BlockTag, KPhysicalAddress phys_addr, const PageTableEntry &attr, u8 sw_reserved_bits, bool contig) : PageTableEntry(attr, (static_cast<u64>(sw_reserved_bits) << 55) | (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x3) { /* ... */ } constexpr ALWAYS_INLINE bool IsBlock() const { return (GetRawAttributes() & ExtensionFlag_TestTableMask) == ExtensionFlag_TestTableMask; } constexpr ALWAYS_INLINE bool IsMappedBlock() const { return this->GetBits(0, 2) == 3; } constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const { return this->SelectBits(12, 36); } static constexpr ALWAYS_INLINE u64 GetEntryTemplateForL3BlockMask(size_t idx) { constexpr u64 BaseMask = (0xFFF0000000000FFFul & ~static_cast<u64>((0x1ul << 52) | ExtensionFlag_TestTableMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody | ExtensionFlag_DisableMergeTail)); if (idx == 0) { return BaseMask | ExtensionFlag_DisableMergeHead | ExtensionFlag_DisableMergeHeadAndBody; } else if (idx < (L3ContiguousBlockSize / L3BlockSize) - 1) { return BaseMask; } else { return BaseMask | ExtensionFlag_DisableMergeTail; } } constexpr ALWAYS_INLINE u64 GetEntryTemplateForL3Block(size_t idx) const { return m_attributes & GetEntryTemplateForL3BlockMask(idx); } constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, u8 sw_reserved_bits, bool contig) const { /* Check whether this has the same permission/etc as the desired attributes. */ return L3PageTableEntry(BlockTag{}, this->GetBlock(), rhs, sw_reserved_bits, contig).GetRawAttributes() == this->GetRawAttributes(); } }; constexpr inline L1PageTableEntry InvalidL1PageTableEntry = L1PageTableEntry(PageTableEntry::InvalidTag{}); constexpr inline L2PageTableEntry InvalidL2PageTableEntry = L2PageTableEntry(PageTableEntry::InvalidTag{}); constexpr inline L3PageTableEntry InvalidL3PageTableEntry = L3PageTableEntry(PageTableEntry::InvalidTag{}); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_page_table_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp> namespace ams::kern::arch::arm64 { class KPageTableImpl { NON_COPYABLE(KPageTableImpl); NON_MOVEABLE(KPageTableImpl); public: struct TraversalEntry { KPhysicalAddress phys_addr; size_t block_size; u8 sw_reserved_bits; u8 attr; constexpr bool IsHeadMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHead) != 0; } constexpr bool IsHeadAndBodyMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; } constexpr bool IsTailMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadTail) != 0; } }; enum EntryLevel : u32 { EntryLevel_L3 = 0, EntryLevel_L2 = 1, EntryLevel_L1 = 2, EntryLevel_Count = 3, }; struct TraversalContext { PageTableEntry *level_entries[EntryLevel_Count]; EntryLevel level; bool is_contiguous; }; using EntryUpdatedCallback = void (*)(const void *); private: static constexpr size_t PageBits = util::CountTrailingZeros(PageSize); static constexpr size_t NumLevels = 3; static constexpr size_t LevelBits = 9; static_assert(NumLevels > 0); template<size_t Offset, size_t Count> static constexpr ALWAYS_INLINE u64 GetBits(u64 value) { return (value >> Offset) & ((1ul << Count) - 1); } static constexpr ALWAYS_INLINE u64 GetBits(u64 value, size_t offset, size_t count) { return (value >> offset) & ((1ul << count) - 1); } template<size_t Offset, size_t Count> static constexpr ALWAYS_INLINE u64 SelectBits(u64 value) { return value & (((1ul << Count) - 1) << Offset); } static constexpr ALWAYS_INLINE u64 SelectBits(u64 value, size_t offset, size_t count) { return value & (((1ul << count) - 1) << offset); } static constexpr ALWAYS_INLINE uintptr_t GetL0Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 0), LevelBits>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL1Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 1), LevelBits>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL2Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 2), LevelBits>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL3Index(KProcessAddress addr) { return GetBits<PageBits + LevelBits * (NumLevels - 3), LevelBits>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1)>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2)>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3)>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetContiguousL1Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 1) + 4>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetContiguousL2Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 2) + 4>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetContiguousL3Offset(KProcessAddress addr) { return GetBits<0, PageBits + LevelBits * (NumLevels - 3) + 4>(GetInteger(addr)); } static constexpr ALWAYS_INLINE uintptr_t GetBlock(const PageTableEntry *pte, EntryLevel level) { return SelectBits(pte->GetRawAttributesUnsafe(), PageBits + LevelBits * level, LevelBits * (NumLevels + 1 - level)); } static constexpr ALWAYS_INLINE uintptr_t GetOffset(KProcessAddress addr, EntryLevel level) { return GetBits(GetInteger(addr), 0, PageBits + LevelBits * level); } static ALWAYS_INLINE KVirtualAddress GetPageTableVirtualAddress(KPhysicalAddress addr) { return KMemoryLayout::GetLinearVirtualAddress(addr); } public: static constexpr ALWAYS_INLINE uintptr_t GetLevelIndex(KProcessAddress addr, EntryLevel level) { return GetBits(GetInteger(addr), PageBits + LevelBits * level, LevelBits); } private: L1PageTableEntry *m_table; bool m_is_kernel; u32 m_num_entries; public: ALWAYS_INLINE KVirtualAddress GetTableEntry(KVirtualAddress table, size_t index) const { return table + index * sizeof(PageTableEntry); } ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KProcessAddress address) const { return GetPointer<L1PageTableEntry>(GetTableEntry(KVirtualAddress(m_table), GetL1Index(address) & (m_num_entries - 1))); } ALWAYS_INLINE L2PageTableEntry *GetL2EntryFromTable(KVirtualAddress table, KProcessAddress address) const { return GetPointer<L2PageTableEntry>(GetTableEntry(table, GetL2Index(address))); } ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KProcessAddress address) const { return GetL2EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address); } ALWAYS_INLINE L3PageTableEntry *GetL3EntryFromTable(KVirtualAddress table, KProcessAddress address) const { return GetPointer<L3PageTableEntry>(GetTableEntry(table, GetL3Index(address))); } ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KProcessAddress address) const { return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address); } static constexpr size_t GetBlockSize(EntryLevel level, bool contiguous = false) { return 1 << (PageBits + LevelBits * level + 4 * contiguous); } public: constexpr explicit KPageTableImpl(util::ConstantInitializeTag) : m_table(), m_is_kernel(), m_num_entries() { /* ... */ } explicit KPageTableImpl() { /* ... */ } size_t GetNumL1Entries() const { return m_num_entries; } NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end); NOINLINE void InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end); L1PageTableEntry *Finalize(); void Dump(uintptr_t start, size_t size) const; size_t CountPageTables() const; bool BeginTraversal(TraversalEntry *out_entry, TraversalContext *out_context, KProcessAddress address) const; bool ContinueTraversal(TraversalEntry *out_entry, TraversalContext *context) const; bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const; static bool MergePages(KVirtualAddress *out, TraversalContext *context, EntryUpdatedCallback on_entry_updated, const void *pt); void SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte, EntryUpdatedCallback on_entry_updated, const void *pt) const; KProcessAddress GetAddressForContext(const TraversalContext *context) const { KProcessAddress addr = m_is_kernel ? static_cast<uintptr_t>(-GetBlockSize(EntryLevel_L1)) * m_num_entries : 0; for (u32 level = context->level; level <= EntryLevel_L1; ++level) { addr += ((reinterpret_cast<uintptr_t>(context->level_entries[level]) / sizeof(PageTableEntry)) & (BlocksPerTable - 1)) << (PageBits + LevelBits * level); } return addr; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/arch/arm64/kern_k_page_table.hpp> namespace ams::kern::arch::arm64 { class KProcessPageTable { private: KPageTable m_page_table; public: void Activate(size_t process_index, u64 id) { /* Activate the page table with the specified contextidr. */ m_page_table.ActivateProcess(process_index, id); } Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit, process_index)); } void Finalize() { m_page_table.Finalize(); } ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() { return m_page_table.AcquireDeviceMapLock(); } Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm) { R_RETURN(m_page_table.SetMemoryPermission(addr, size, perm)); } Result SetProcessMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm) { R_RETURN(m_page_table.SetProcessMemoryPermission(addr, size, perm)); } Result SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr) { R_RETURN(m_page_table.SetMemoryAttribute(addr, size, mask, attr)); } Result SetHeapSize(KProcessAddress *out, size_t size) { R_RETURN(m_page_table.SetHeapSize(out, size)); } Result SetMaxHeapSize(size_t size) { R_RETURN(m_page_table.SetMaxHeapSize(size)); } Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const { R_RETURN(m_page_table.QueryInfo(out_info, out_page_info, addr)); } Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const { R_RETURN(m_page_table.QueryPhysicalAddress(out, address)); } Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(m_page_table.QueryStaticMapping(out, address, size)); } Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(m_page_table.QueryIoMapping(out, address, size)); } Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { R_RETURN(m_page_table.MapMemory(dst_address, src_address, size)); } Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { R_RETURN(m_page_table.UnmapMemory(dst_address, src_address, size)); } Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { R_RETURN(m_page_table.MapCodeMemory(dst_address, src_address, size)); } Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { R_RETURN(m_page_table.UnmapCodeMemory(dst_address, src_address, size)); } Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { R_RETURN(m_page_table.MapIo(phys_addr, size, perm)); } Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm)); } Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) { R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size, mapping)); } Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { R_RETURN(m_page_table.MapStatic(phys_addr, size, perm)); } Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm) { R_RETURN(m_page_table.MapRegion(region_type, perm)); } Result MapInsecurePhysicalMemory(KProcessAddress address, size_t size) { R_RETURN(m_page_table.MapInsecurePhysicalMemory(address, size)); } Result UnmapInsecurePhysicalMemory(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnmapInsecurePhysicalMemory(address, size)); } Result MapPageGroup(KProcessAddress addr, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPageGroup(addr, pg, state, perm)); } Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state) { R_RETURN(m_page_table.UnmapPageGroup(address, pg, state)); } Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPages(out_addr, num_pages, alignment, phys_addr, state, perm)); } Result MapPages(KProcessAddress *out_addr, size_t num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPages(out_addr, num_pages, state, perm)); } Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPages(address, num_pages, state, perm)); } Result UnmapPages(KProcessAddress addr, size_t num_pages, KMemoryState state) { R_RETURN(m_page_table.UnmapPages(addr, num_pages, state)); } Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) { R_RETURN(m_page_table.MakeAndOpenPageGroup(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr)); } Result InvalidateProcessDataCache(KProcessAddress address, size_t size) { R_RETURN(m_page_table.InvalidateProcessDataCache(address, size)); } Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) { R_RETURN(m_page_table.InvalidateCurrentProcessDataCache(address, size)); } Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) { R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size, force_debug_prod)); } Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) { R_RETURN(m_page_table.ReadDebugIoMemory(buffer, address, size, state)); } Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) { R_RETURN(m_page_table.WriteDebugMemory(address, buffer, size)); } Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state) { R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size, state)); } Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) { R_RETURN(m_page_table.LockForMapDeviceAddressSpace(out_is_io, address, size, perm, is_aligned, check_heap)); } Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) { R_RETURN(m_page_table.LockForUnmapDeviceAddressSpace(address, size, check_heap)); } Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnlockForDeviceAddressSpace(address, size)); } Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnlockForDeviceAddressSpacePartialMap(address, size)); } Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) { R_RETURN(m_page_table.OpenMemoryRangeForMapDeviceAddressSpace(out, address, size, perm, is_aligned)); } Result OpenMemoryRangeForUnmapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) { R_RETURN(m_page_table.OpenMemoryRangeForUnmapDeviceAddressSpace(out, address, size)); } Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) { R_RETURN(m_page_table.LockForIpcUserBuffer(out, address, size)); } Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnlockForIpcUserBuffer(address, size)); } Result LockForTransferMemory(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm) { R_RETURN(m_page_table.LockForTransferMemory(out, address, size, perm)); } Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup &pg) { R_RETURN(m_page_table.UnlockForTransferMemory(address, size, pg)); } Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size) { R_RETURN(m_page_table.LockForCodeMemory(out, address, size)); } Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg) { R_RETURN(m_page_table.UnlockForCodeMemory(address, size, pg)); } Result OpenMemoryRangeForProcessCacheOperation(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size) { R_RETURN(m_page_table.OpenMemoryRangeForProcessCacheOperation(out, address, size)); } Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { R_RETURN(m_page_table.CopyMemoryFromLinearToUser(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr)); } Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { R_RETURN(m_page_table.CopyMemoryFromLinearToKernel(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr)); } Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) { R_RETURN(m_page_table.CopyMemoryFromUserToLinear(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr)); } Result CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) { R_RETURN(m_page_table.CopyMemoryFromKernelToLinear(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr)); } Result CopyMemoryFromHeapToHeap(KProcessPageTable &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { R_RETURN(m_page_table.CopyMemoryFromHeapToHeap(dst_page_table.m_page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr)); } Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KProcessPageTable &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { R_RETURN(m_page_table.CopyMemoryFromHeapToHeapWithoutCheckDestination(dst_page_table.m_page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr)); } Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KProcessPageTable &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send) { R_RETURN(m_page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.m_page_table, test_perm, dst_state, send)); } Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) { R_RETURN(m_page_table.CleanupForIpcServer(address, size, dst_state)); } Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) { R_RETURN(m_page_table.CleanupForIpcClient(address, size, dst_state)); } Result MapPhysicalMemory(KProcessAddress address, size_t size) { R_RETURN(m_page_table.MapPhysicalMemory(address, size)); } Result UnmapPhysicalMemory(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnmapPhysicalMemory(address, size)); } Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) { R_RETURN(m_page_table.MapPhysicalMemoryUnsafe(address, size)); } Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) { R_RETURN(m_page_table.UnmapPhysicalMemoryUnsafe(address, size)); } Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KProcessPageTable &src_page_table, KProcessAddress src_address) { R_RETURN(m_page_table.UnmapProcessMemory(dst_address, size, src_page_table.m_page_table, src_address)); } void DumpMemoryBlocks() const { return m_page_table.DumpMemoryBlocks(); } void DumpPageTable() const { return m_page_table.DumpPageTable(); } size_t CountPageTables() const { return m_page_table.CountPageTables(); } bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { return m_page_table.GetPhysicalAddress(out, address); } bool Contains(KProcessAddress addr, size_t size) const { return m_page_table.Contains(addr, size); } bool IsInAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInAliasRegion(addr, size); } bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInUnsafeAliasRegion(addr, size); } bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); } KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); } KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); } KProcessAddress GetAliasRegionStart() const { return m_page_table.GetAliasRegionStart(); } KProcessAddress GetStackRegionStart() const { return m_page_table.GetStackRegionStart(); } KProcessAddress GetKernelMapRegionStart() const { return m_page_table.GetKernelMapRegionStart(); } KProcessAddress GetAliasCodeRegionStart() const { return m_page_table.GetAliasCodeRegionStart(); } size_t GetAddressSpaceSize() const { return m_page_table.GetAddressSpaceSize(); } size_t GetHeapRegionSize() const { return m_page_table.GetHeapRegionSize(); } size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); } size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); } size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); } size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); } size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); } size_t GetNormalMemorySize() const { return m_page_table.GetNormalMemorySize(); } size_t GetCodeSize() const { return m_page_table.GetCodeSize(); } size_t GetCodeDataSize() const { return m_page_table.GetCodeDataSize(); } size_t GetAliasCodeSize() const { return m_page_table.GetAliasCodeSize(); } size_t GetAliasCodeDataSize() const { return m_page_table.GetAliasCodeDataSize(); } u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); } KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const { return m_page_table.GetHeapPhysicalAddress(address); } KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress address) const { return m_page_table.GetHeapVirtualAddress(address); } KBlockInfoManager *GetBlockInfoManager() { return m_page_table.GetBlockInfoManager(); } KPageTableBase &GetBasePageTable() { return m_page_table; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_slab_heap_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_select_interrupt_manager.hpp> namespace ams::kern::arch::arm64 { template<typename T> concept SlabHeapNode = requires (T &t) { { t.next } -> std::convertible_to<T *>; }; ALWAYS_INLINE bool IsSlabAtomicValid() { /* Without careful consideration, slab heaps atomics are vulnerable to */ /* the ABA problem, when doing compare and swap of node pointers. */ /* We resolve this by using the ARM exclusive monitor; we bundle the */ /* load and store of the relevant values into a single exclusive monitor */ /* hold, preventing the ABA problem. */ /* However, our assembly must do both a load and a store under a single */ /* hold, at different memory addresses. Considering the case where the */ /* addresses are distinct but resolve to the same cache set (by chance), */ /* we can note that under a 1-way associative (direct-mapped) cache */ /* we would have as a guarantee that the second access would evict the */ /* cache line from the first access, invalidating our exclusive monitor */ /* hold. Thus, we require that the cache is not 1-way associative, for */ /* our implementation to be correct. */ { /* Disable interrupts. */ KScopedInterruptDisable di; /* Select L1 cache. */ cpu::SetCsselrEl1(0); cpu::InstructionMemoryBarrier(); /* Check that the L1 cache is not direct-mapped. */ return cpu::CacheSizeIdRegisterAccessor().GetAssociativity() != 0; } } template<typename T> requires SlabHeapNode<T> ALWAYS_INLINE T *AllocateFromSlabAtomic(T **head) { u32 tmp; T *node, *next; __asm__ __volatile__( "1:\n" " ldaxr %[node], [%[head]]\n" " cbz %[node], 2f\n" " ldr %[next], [%[node]]\n" " stlxr %w[tmp], %[next], [%[head]]\n" " cbnz %w[tmp], 1b\n" "2:\n" : [tmp]"=&r"(tmp), [node]"=&r"(node), [next]"=&r"(next), [head]"+&r"(head) : : "cc", "memory" ); return node; } template<typename T> requires SlabHeapNode<T> ALWAYS_INLINE void FreeToSlabAtomic(T **head, T *node) { u32 tmp; T *next; __asm__ __volatile__( "1:\n" " ldaxr %[next], [%[head]]\n" " str %[next], [%[node]]\n" " stlxr %w[tmp], %[node], [%[head]]\n" " cbnz %w[tmp], 1b\n" : [tmp]"=&r"(tmp), [node]"+&r"(node), [next]"=&r"(next), [head]"+&r"(head) : : "cc", "memory" ); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_spin_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern::arch::arm64 { class KNotAlignedSpinLock { private: u32 m_packed_tickets; public: constexpr KNotAlignedSpinLock() : m_packed_tickets(0) { /* ... */ } ALWAYS_INLINE void Lock() { u32 tmp0, tmp1, tmp2; __asm__ __volatile__( " prfm pstl1keep, %[m_packed_tickets]\n" "1:\n" " ldaxr %w[tmp0], %[m_packed_tickets]\n" " add %w[tmp2], %w[tmp0], #0x10000\n" " stxr %w[tmp1], %w[tmp2], %[m_packed_tickets]\n" " cbnz %w[tmp1], 1b\n" " \n" " and %w[tmp1], %w[tmp0], #0xFFFF\n" " cmp %w[tmp1], %w[tmp0], lsr #16\n" " b.eq 3f\n" " sevl\n" "2:\n" " wfe\n" " ldaxrh %w[tmp1], %[m_packed_tickets]\n" " cmp %w[tmp1], %w[tmp0], lsr #16\n" " b.ne 2b\n" "3:\n" : [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [m_packed_tickets]"+Q"(m_packed_tickets) : : "cc", "memory" ); } ALWAYS_INLINE void Unlock() { const u32 value = m_packed_tickets + 1; __asm__ __volatile__( " stlrh %w[value], %[m_packed_tickets]\n" : [m_packed_tickets]"+Q"(m_packed_tickets) : [value]"r"(value) : "memory" ); } }; static_assert(sizeof(KNotAlignedSpinLock) == sizeof(u32)); class KAlignedSpinLock { private: alignas(cpu::DataCacheLineSize) u16 m_current_ticket; alignas(cpu::DataCacheLineSize) u16 m_next_ticket; public: constexpr KAlignedSpinLock() : m_current_ticket(0), m_next_ticket(0) { /* ... */ } ALWAYS_INLINE void Lock() { u32 tmp0, tmp1, got_lock; __asm__ __volatile__( " prfm pstl1keep, %[m_next_ticket]\n" "1:\n" " ldxrh %w[tmp0], %[m_next_ticket]\n" " add %w[tmp1], %w[tmp0], #0x1\n" " stxrh %w[got_lock], %w[tmp1], %[m_next_ticket]\n" " cbnz %w[got_lock], 1b\n" " \n" " sevl\n" "2:\n" " wfe\n" " ldaxrh %w[tmp1], %[m_current_ticket]\n" " cmp %w[tmp1], %w[tmp0]\n" " b.ne 2b\n" : [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [got_lock]"=&r"(got_lock), [m_next_ticket]"+Q"(m_next_ticket) : [m_current_ticket]"Q"(m_current_ticket) : "cc", "memory" ); } ALWAYS_INLINE void Unlock() { const u32 value = m_current_ticket + 1; __asm__ __volatile__( " stlrh %w[value], %[m_current_ticket]\n" : [m_current_ticket]"+Q"(m_current_ticket) : [value]"r"(value) : "memory" ); } }; static_assert(sizeof(KAlignedSpinLock) == 2 * cpu::DataCacheLineSize); using KSpinLock = KNotAlignedSpinLock; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/arch/arm64/kern_k_page_table.hpp> namespace ams::kern::arch::arm64 { class KSupervisorPageTable { private: KPageTable m_page_table; public: constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize) { /* ... */ } NOINLINE void Initialize(s32 core_id); void Activate() { m_page_table.ActivateKernel(); } void ActivateForInit() { this->Activate(); /* Invalidate entire TLB. */ cpu::InvalidateEntireTlb(); } Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPages(out_addr, num_pages, alignment, phys_addr, region_start, region_num_pages, state, perm)); } Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) { R_RETURN(m_page_table.UnmapPages(address, num_pages, state)); } Result MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(m_page_table.MapPageGroup(out_addr, pg, region_start, region_num_pages, state, perm)); } Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state) { R_RETURN(m_page_table.UnmapPageGroup(address, pg, state)); } bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { return m_page_table.GetPhysicalAddress(out, address); } void DumpMemoryBlocks() const { return m_page_table.DumpMemoryBlocks(); } void DumpPageTable() const { return m_page_table.DumpPageTable(); } size_t CountPageTables() const { return m_page_table.CountPageTables(); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_thread_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern { class KThread; } namespace ams::kern::arch::arm64 { class KThreadContext { public: static constexpr size_t NumCalleeSavedRegisters = (29 - 19) + 1; static constexpr size_t NumCalleeSavedFpuRegisters = 8; static constexpr size_t NumCallerSavedFpuRegisters = 24; static constexpr size_t NumFpuRegisters = NumCalleeSavedFpuRegisters + NumCallerSavedFpuRegisters; public: union CalleeSaveRegisters { u64 registers[NumCalleeSavedRegisters]; struct { u64 x19; u64 x20; u64 x21; u64 x22; u64 x23; u64 x24; u64 x25; u64 x26; u64 x27; u64 x28; u64 x29; }; }; union CalleeSaveFpu64Registers { u128 v[NumCalleeSavedFpuRegisters]; struct { u128 q8; u128 q9; u128 q10; u128 q11; u128 q12; u128 q13; u128 q14; u128 q15; }; }; union CalleeSaveFpu32Registers { u128 v[NumCalleeSavedFpuRegisters / 2]; struct { u128 q4; u128 q5; u128 q6; u128 q7; }; }; union CalleeSaveFpuRegisters { CalleeSaveFpu64Registers fpu64; CalleeSaveFpu32Registers fpu32; }; union CallerSaveFpu64Registers { u128 v[NumCallerSavedFpuRegisters]; struct { union { u128 v0_7[NumCallerSavedFpuRegisters / 3]; struct { u128 q0; u128 q1; u128 q2; u128 q3; u128 q4; u128 q5; u128 q6; u128 q7; }; }; union { u128 v16_31[2 * NumCallerSavedFpuRegisters / 3]; struct { u128 q16; u128 q17; u128 q18; u128 q19; u128 q20; u128 q21; u128 q22; u128 q23; u128 q24; u128 q25; u128 q26; u128 q27; u128 q28; u128 q29; u128 q30; u128 q31; }; }; }; }; union CallerSaveFpu32Registers { u128 v[NumCallerSavedFpuRegisters / 2]; struct { union { u128 v0_3[(NumCallerSavedFpuRegisters / 3) / 2]; struct { u128 q0; u128 q1; u128 q2; u128 q3; }; }; union { u128 v8_15[(2 * NumCallerSavedFpuRegisters / 3) / 2]; struct { u128 q8; u128 q9; u128 q10; u128 q11; u128 q12; u128 q13; u128 q14; u128 q15; }; }; }; }; union CallerSaveFpuRegisters { CallerSaveFpu64Registers fpu64; CallerSaveFpu32Registers fpu32; }; private: CalleeSaveRegisters m_callee_saved; u64 m_lr; u64 m_sp; u32 m_fpcr; u32 m_fpsr; alignas(0x10) CalleeSaveFpuRegisters m_callee_saved_fpu; bool m_locked; private: static void RestoreFpuRegisters64(const KThreadContext &); static void RestoreFpuRegisters32(const KThreadContext &); public: constexpr explicit KThreadContext(util::ConstantInitializeTag) : m_callee_saved(), m_lr(), m_sp(), m_fpcr(), m_fpsr(), m_callee_saved_fpu(), m_locked() { /* ... */ } explicit KThreadContext() { /* ... */ } void Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main); void SetArguments(uintptr_t arg0, uintptr_t arg1); static void FpuContextSwitchHandler(KThread *thread); u32 GetFpcr() const { return m_fpcr; } u32 GetFpsr() const { return m_fpsr; } void SetFpcr(u32 v) { m_fpcr = v; } void SetFpsr(u32 v) { m_fpsr = v; } void CloneFpuStatus(); const auto &GetCalleeSaveFpuRegisters() const { return m_callee_saved_fpu; } auto &GetCalleeSaveFpuRegisters() { return m_callee_saved_fpu; } public: static void OnThreadTerminating(const KThread *thread); public: static consteval bool ValidateOffsets(); template<typename CallerSave, typename CalleeSave> requires ((std::same_as<CallerSave, CallerSaveFpu64Registers> && std::same_as<CalleeSave, CalleeSaveFpu64Registers>) || (std::same_as<CallerSave, CallerSaveFpu32Registers> && std::same_as<CalleeSave, CalleeSaveFpu32Registers>)) static void GetFpuRegisters(u128 *out, const CallerSave &caller_save, const CalleeSave &callee_save) { /* Check that the register counts are correct. */ constexpr size_t RegisterUnitCount = util::size(CalleeSave{}.v); static_assert(util::size(CalleeSave{}.v) == 1 * RegisterUnitCount); static_assert(util::size(CallerSave{}.v) == 3 * RegisterUnitCount); /* Copy the low caller-save registers. */ for (size_t i = 0; i < RegisterUnitCount; ++i) { *(out++) = caller_save.v[i]; } /* Copy the callee-save registers. */ for (size_t i = 0; i < RegisterUnitCount; ++i) { *(out++) = callee_save.v[i]; } /* Copy the remaining caller-save registers. */ for (size_t i = 0; i < 2 * RegisterUnitCount; ++i) { *(out++) = caller_save.v[RegisterUnitCount + i]; } } template<typename CallerSave, typename CalleeSave> requires ((std::same_as<CallerSave, CallerSaveFpu64Registers> && std::same_as<CalleeSave, CalleeSaveFpu64Registers>) || (std::same_as<CallerSave, CallerSaveFpu32Registers> && std::same_as<CalleeSave, CalleeSaveFpu32Registers>)) static ALWAYS_INLINE void SetFpuRegisters(CallerSave &caller_save, CalleeSave &callee_save, const u128 *v) { /* Check that the register counts are correct. */ constexpr size_t RegisterUnitCount = util::size(CalleeSave{}.v); static_assert(util::size(CalleeSave{}.v) == 1 * RegisterUnitCount); static_assert(util::size(CallerSave{}.v) == 3 * RegisterUnitCount); /* Copy the low caller-save registers. */ for (size_t i = 0; i < RegisterUnitCount; ++i) { caller_save.v[i] = *(v++); } /* Copy the callee-save registers. */ for (size_t i = 0; i < RegisterUnitCount; ++i) { callee_save.v[i] = *(v++); } /* Copy the remaining caller-save registers. */ for (size_t i = 0; i < 2 * RegisterUnitCount; ++i) { caller_save.v[RegisterUnitCount + i] = *(v++); } } }; consteval bool KThreadContext::ValidateOffsets() { static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29); static_assert(AMS_OFFSETOF(KThreadContext, m_lr) == THREAD_CONTEXT_LR); static_assert(AMS_OFFSETOF(KThreadContext, m_sp) == THREAD_CONTEXT_SP); static_assert(AMS_OFFSETOF(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR); static_assert(AMS_OFFSETOF(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu) == THREAD_CONTEXT_FPU_REGISTERS); static_assert(AMS_OFFSETOF(KThreadContext, m_locked) == THREAD_CONTEXT_LOCKED); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q8 ) == THREAD_CONTEXT_FPU64_Q8 ); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q9 ) == THREAD_CONTEXT_FPU64_Q9 ); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q10) == THREAD_CONTEXT_FPU64_Q10); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q11) == THREAD_CONTEXT_FPU64_Q11); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q12) == THREAD_CONTEXT_FPU64_Q12); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q13) == THREAD_CONTEXT_FPU64_Q13); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q14) == THREAD_CONTEXT_FPU64_Q14); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu64.q15) == THREAD_CONTEXT_FPU64_Q15); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu32.q4 ) == THREAD_CONTEXT_FPU32_Q4 ); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu32.q5 ) == THREAD_CONTEXT_FPU32_Q5 ); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu32.q6 ) == THREAD_CONTEXT_FPU32_Q6 ); static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved_fpu.fpu32.q7 ) == THREAD_CONTEXT_FPU32_Q7 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q0 ) == THREAD_FPU64_CONTEXT_Q0 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q1 ) == THREAD_FPU64_CONTEXT_Q1 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q2 ) == THREAD_FPU64_CONTEXT_Q2 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q3 ) == THREAD_FPU64_CONTEXT_Q3 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q4 ) == THREAD_FPU64_CONTEXT_Q4 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q5 ) == THREAD_FPU64_CONTEXT_Q5 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q6 ) == THREAD_FPU64_CONTEXT_Q6 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q7 ) == THREAD_FPU64_CONTEXT_Q7 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q16) == THREAD_FPU64_CONTEXT_Q16); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q17) == THREAD_FPU64_CONTEXT_Q17); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q18) == THREAD_FPU64_CONTEXT_Q18); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q19) == THREAD_FPU64_CONTEXT_Q19); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q20) == THREAD_FPU64_CONTEXT_Q20); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q21) == THREAD_FPU64_CONTEXT_Q21); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q22) == THREAD_FPU64_CONTEXT_Q22); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q23) == THREAD_FPU64_CONTEXT_Q23); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q24) == THREAD_FPU64_CONTEXT_Q24); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q25) == THREAD_FPU64_CONTEXT_Q25); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q26) == THREAD_FPU64_CONTEXT_Q26); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q27) == THREAD_FPU64_CONTEXT_Q27); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q28) == THREAD_FPU64_CONTEXT_Q28); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q29) == THREAD_FPU64_CONTEXT_Q29); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q30) == THREAD_FPU64_CONTEXT_Q30); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu64.q31) == THREAD_FPU64_CONTEXT_Q31); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q0 ) == THREAD_FPU32_CONTEXT_Q0 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q1 ) == THREAD_FPU32_CONTEXT_Q1 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q2 ) == THREAD_FPU32_CONTEXT_Q2 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q3 ) == THREAD_FPU32_CONTEXT_Q3 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q8 ) == THREAD_FPU32_CONTEXT_Q8 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q9 ) == THREAD_FPU32_CONTEXT_Q9 ); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q10) == THREAD_FPU32_CONTEXT_Q10); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q11) == THREAD_FPU32_CONTEXT_Q11); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q12) == THREAD_FPU32_CONTEXT_Q12); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q13) == THREAD_FPU32_CONTEXT_Q13); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q14) == THREAD_FPU32_CONTEXT_Q14); static_assert(AMS_OFFSETOF(KThreadContext::CallerSaveFpuRegisters, fpu32.q15) == THREAD_FPU32_CONTEXT_Q15); return true; } static_assert(KThreadContext::ValidateOffsets()); void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_secure_monitor_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern::arch::arm64::smc { template<int SmcId> void SecureMonitorCall(u64 *buf) { /* Load arguments into registers. */ register u64 x0 asm("x0") = buf[0]; register u64 x1 asm("x1") = buf[1]; register u64 x2 asm("x2") = buf[2]; register u64 x3 asm("x3") = buf[3]; register u64 x4 asm("x4") = buf[4]; register u64 x5 asm("x5") = buf[5]; register u64 x6 asm("x6") = buf[6]; register u64 x7 asm("x7") = buf[7]; /* Backup the current thread pointer. */ const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); /* Perform the call. */ __asm__ __volatile__("smc %c[smc_id]" : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) : [smc_id]"i"(SmcId) : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory" ); /* Restore the current thread pointer into X18. */ cpu::SetCurrentThreadPointerValue(current_thread_pointer_value); /* Store arguments to output. */ buf[0] = x0; buf[1] = x1; buf[2] = x2; buf[3] = x3; buf[4] = x4; buf[5] = x5; buf[6] = x6; buf[7] = x7; } enum PsciFunction { PsciFunction_CpuSuspend = 0xC4000001, PsciFunction_CpuOff = 0x84000002, PsciFunction_CpuOn = 0xC4000003, }; template<int SmcId> u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) { ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } }; SecureMonitorCall<SmcId>(args.r); return args.r[0]; } template<int SmcId> u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { return PsciCall<SmcId>(PsciFunction_CpuOn, core_id, entrypoint, arg); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/arch/arm64/kern_userspace_memory_access.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern::arch::arm64 { void UserspaceAccessFunctionAreaBegin(); class UserspaceAccess { private: class Impl { public: static bool CopyMemoryFromUser(void *dst, const void *src, size_t size); static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size); static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size); static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src); static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src); static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src); static s32 CopyStringFromUser(void *dst, const void *src, size_t size); static bool CopyMemoryToUser(void *dst, const void *src, size_t size); static bool CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size); static bool CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size); static bool CopyMemoryToUserSize32Bit(void *dst, u32 value); static s32 CopyStringToUser(void *dst, const void *src, size_t size); static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask); static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value); static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare); static bool StoreDataCache(uintptr_t start, uintptr_t end); static bool FlushDataCache(uintptr_t start, uintptr_t end); static bool InvalidateDataCache(uintptr_t start, uintptr_t end); static bool ReadIoMemory32Bit(void *dst, const void *src, size_t size); static bool ReadIoMemory16Bit(void *dst, const void *src, size_t size); static bool ReadIoMemory8Bit(void *dst, const void *src, size_t size); static bool WriteIoMemory32Bit(void *dst, const void *src, size_t size); static bool WriteIoMemory16Bit(void *dst, const void *src, size_t size); static bool WriteIoMemory8Bit(void *dst, const void *src, size_t size); }; public: static bool CopyMemoryFromUser(void *dst, const void *src, size_t size) { return Impl::CopyMemoryFromUser(dst, src, size); } static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size) { return Impl::CopyMemoryFromUserAligned32Bit(dst, src, size); } static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size) { return Impl::CopyMemoryFromUserAligned64Bit(dst, src, size); } static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src) { return Impl::CopyMemoryFromUserSize64Bit(dst, src); } static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src) { return Impl::CopyMemoryFromUserSize32Bit(dst, src); } static bool CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) { /* Check that the address is within the valid userspace range. */ if (const uintptr_t src_uptr = reinterpret_cast<uintptr_t>(src); src_uptr < ams::svc::AddressNullGuard32Size || (src_uptr + sizeof(u32) - 1) >= ams::svc::AddressMemoryRegion39Size) { return false; } return Impl::CopyMemoryFromUserSize32BitWithSupervisorAccess(dst, src); } static s32 CopyStringFromUser(void *dst, const void *src, size_t size) { return Impl::CopyStringFromUser(dst, src, size); } static bool CopyMemoryToUser(void *dst, const void *src, size_t size) { return Impl::CopyMemoryToUser(dst, src, size); } static bool CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size) { return Impl::CopyMemoryToUserAligned32Bit(dst, src, size); } static bool CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size) { return Impl::CopyMemoryToUserAligned64Bit(dst, src, size); } static bool CopyMemoryToUserSize32Bit(void *dst, u32 value) { return Impl::CopyMemoryToUserSize32Bit(dst, value); } static s32 CopyStringToUser(void *dst, const void *src, size_t size) { return Impl::CopyStringToUser(dst, src, size); } static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask) { return Impl::UpdateLockAtomic(out, address, if_zero, new_orr_mask); } static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value) { return Impl::UpdateIfEqualAtomic(out, address, compare_value, new_value); } static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare) { return Impl::DecrementIfLessThanAtomic(out, address, compare); } static bool StoreDataCache(uintptr_t start, uintptr_t end) { return Impl::StoreDataCache(start, end); } static bool FlushDataCache(uintptr_t start, uintptr_t end) { return Impl::FlushDataCache(start, end); } static bool InvalidateDataCache(uintptr_t start, uintptr_t end) { return Impl::InvalidateDataCache(start, end); } static bool ReadIoMemory32Bit(void *dst, const void *src, size_t size) { return Impl::ReadIoMemory32Bit(dst, src, size); } static bool ReadIoMemory16Bit(void *dst, const void *src, size_t size) { return Impl::ReadIoMemory16Bit(dst, src, size); } static bool ReadIoMemory8Bit(void *dst, const void *src, size_t size) { return Impl::ReadIoMemory8Bit(dst, src, size); } static bool WriteIoMemory32Bit(void *dst, const void *src, size_t size) { return Impl::WriteIoMemory32Bit(dst, src, size); } static bool WriteIoMemory16Bit(void *dst, const void *src, size_t size) { return Impl::WriteIoMemory16Bit(dst, src, size); } static bool WriteIoMemory8Bit(void *dst, const void *src, size_t size) { return Impl::WriteIoMemory8Bit(dst, src, size); } }; void UserspaceAccessFunctionAreaEnd(); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/generic/kern_k_device_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_select_page_table.hpp> namespace ams::kern::board::generic { using KDeviceVirtualAddress = u64; class KDevicePageTable { public: constexpr KDevicePageTable() { /* ... */ } Result ALWAYS_INLINE Initialize(u64 space_address, u64 space_size) { MESOSPHERE_UNUSED(space_address, space_size); R_THROW(ams::kern::svc::ResultNotImplemented()); } void ALWAYS_INLINE Finalize() { /* ... */ } Result ALWAYS_INLINE Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size) { MESOSPHERE_UNUSED(device_name, space_address, space_size); R_THROW(ams::kern::svc::ResultNotImplemented()); } Result ALWAYS_INLINE Detach(ams::svc::DeviceName device_name) { MESOSPHERE_UNUSED(device_name); R_THROW(ams::kern::svc::ResultNotImplemented()); } Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) { MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned, is_io); R_THROW(ams::kern::svc::ResultNotImplemented()); } Result ALWAYS_INLINE Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) { MESOSPHERE_UNUSED(page_table, process_address, size, device_address); R_THROW(ams::kern::svc::ResultNotImplemented()); } void ALWAYS_INLINE Unmap(KDeviceVirtualAddress device_address, size_t size) { MESOSPHERE_UNUSED(device_address, size); } public: static ALWAYS_INLINE void Initialize() { /* ... */ } static ALWAYS_INLINE void Lock() { /* ... */ } static ALWAYS_INLINE void Unlock() { /* ... */ } static ALWAYS_INLINE void Sleep() { /* ... */ } static ALWAYS_INLINE void Wakeup() { /* ... */ } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_cpu_map.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern::board::nintendo::nx::impl::cpu { /* Virtual to Physical core map. */ constexpr inline const s32 VirtualToPhysicalCoreMap[BITSIZEOF(u64)] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_select_page_table.hpp> namespace ams::kern::board::nintendo::nx { using KDeviceVirtualAddress = u64; class KDevicePageTable { private: static constexpr size_t TableCount = 4; private: KVirtualAddress m_tables[TableCount]; u8 m_table_asids[TableCount]; u64 m_attached_device; u32 m_attached_value; u32 m_detached_value; u32 m_hs_attached_value; u32 m_hs_detached_value; private: static ALWAYS_INLINE bool IsHeapVirtualAddress(KVirtualAddress addr) { const KMemoryRegion *hint = nullptr; return KMemoryLayout::IsHeapVirtualAddress(hint, addr); } static ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress addr) { const KMemoryRegion *hint = nullptr; return KMemoryLayout::IsHeapPhysicalAddress(hint, addr); } static ALWAYS_INLINE KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress addr) { return KPageTable::GetHeapVirtualAddress(addr); } static ALWAYS_INLINE KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress addr) { return KPageTable::GetHeapPhysicalAddress(addr); } static ALWAYS_INLINE KVirtualAddress GetPageTableVirtualAddress(KPhysicalAddress addr) { return KPageTable::GetPageTableVirtualAddress(addr); } static ALWAYS_INLINE KPhysicalAddress GetPageTablePhysicalAddress(KVirtualAddress addr) { return KPageTable::GetPageTablePhysicalAddress(addr); } public: constexpr KDevicePageTable() : m_tables{Null<KVirtualAddress>, Null<KVirtualAddress>, Null<KVirtualAddress>, Null<KVirtualAddress>}, m_table_asids(), m_attached_device(), m_attached_value(), m_detached_value(), m_hs_attached_value(), m_hs_detached_value() { /* ... */ } Result Initialize(u64 space_address, u64 space_size); void Finalize(); Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size); Result Detach(ams::svc::DeviceName device_name); Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io); Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address); void Unmap(KDeviceVirtualAddress device_address, size_t size) { return this->UnmapImpl(device_address, size, false); } private: Result MapDevicePage(KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm); Result MapImpl(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned); void UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force); bool IsFree(KDeviceVirtualAddress address, u64 size) const; bool Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const; public: static void Initialize(); static void Lock(); static void Unlock(); static void Sleep(); static void Wakeup(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_layout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern { constexpr inline KPhysicalAddress MainMemoryAddress = 0x80000000; constexpr inline size_t MainMemorySize = 4_GB; constexpr inline size_t MainMemorySizeMax = 8_GB; constexpr inline u32 MinimumMemoryManagerAlignmentShifts[] = { 0, 0, 0, 0 }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* All architectures must define NumBoardDeviceRegions. */ constexpr inline const auto NumBoardDeviceRegions = 6; /* UNUSED: .Derive(NumBoardDeviceRegions, 0); */ constexpr inline const auto KMemoryRegionType_MemoryController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_MemoryController1 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_MemoryController0 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_PowerManagementController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition(); constexpr inline const auto KMemoryRegionType_LegacyLpsDevices = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5); static_assert(KMemoryRegionType_MemoryController .GetValue() == (0x55 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_MemoryController1 .GetValue() == (0x65 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_MemoryController0 .GetValue() == (0x95 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5)); static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5); constexpr inline const auto NumLegacyLpsDevices = 7; constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0); constexpr inline const auto KMemoryRegionType_LegacyLpsIram = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1); constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2); constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3); constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4); constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5); constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6); static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5); static_assert(KMemoryRegionType_LegacyLpsIram .GetValue() == 0x5C5); static_assert(KMemoryRegionType_LegacyLpsFlowController .GetValue() == 0x6C5); static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr .GetValue() == 0x9C5); static_assert(KMemoryRegionType_LegacyLpsSemaphore .GetValue() == 0xAC5); static_assert(KMemoryRegionType_LegacyLpsAtomics .GetValue() == 0xCC5); static_assert(KMemoryRegionType_LegacyLpsClkRst .GetValue() == 0x11C5); ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_system_control_base.hpp> namespace ams::kern::board::nintendo::nx { class KSystemControl : public KSystemControlBase { public: /* This can be overridden as needed. */ static constexpr size_t SecureAppletMemorySize = 4_MB; public: class Init : public KSystemControlBase::Init { private: friend class KSystemControlBase::Init; private: static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg); public: /* Initialization. */ static size_t GetRealMemorySize(); static size_t GetIntendedMemorySize(); static bool ShouldIncreaseThreadResourceLimit(); static size_t GetApplicationPoolSize(); static size_t GetAppletPoolSize(); static size_t GetMinimumNonSecureSystemPoolSize(); static u8 GetDebugLogUartPort(); /* Randomness. */ static void GenerateRandom(u64 *dst, size_t count); static u64 GenerateRandomRange(u64 min, u64 max); }; public: /* Initialization. */ static NOINLINE void ConfigureKTargetSystem(); static NOINLINE void InitializePhase1(); static NOINLINE void InitializePhase2(); static NOINLINE u32 GetCreateProcessMemoryPool(); /* Randomness. */ static void GenerateRandom(u64 *dst, size_t count); static u64 GenerateRandomRange(u64 min, u64 max); static u64 GenerateRandomU64(); /* Privileged Access. */ static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); /* Power management. */ static void SleepSystem(); static NORETURN void StopSystem(void *arg = nullptr); /* User access. */ static void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args); /* Secure Memory. */ static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool); static Result AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool); static void FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/qemu/virt/kern_cpu_map.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern::board::qemu::virt::impl::cpu { /* Virtual to Physical core map. */ constexpr inline const s32 VirtualToPhysicalCoreMap[BITSIZEOF(u64)] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/qemu/virt/kern_k_memory_layout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern { constexpr inline KPhysicalAddress MainMemoryAddress = 0x40000000; constexpr inline size_t MainMemorySize = 4_GB; constexpr inline size_t MainMemorySizeMax = 8_GB; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/qemu/virt/kern_k_memory_region_device_types.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* All architectures must define NumBoardDeviceRegions. */ constexpr inline const auto NumBoardDeviceRegions = 0; /* UNUSED: .Derive(NumBoardDeviceRegions, 0); */ ================================================ FILE: libraries/libmesosphere/include/mesosphere/board/qemu/virt/kern_k_system_control.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_system_control_base.hpp> namespace ams::kern::board::qemu::virt { class KSystemControl : public KSystemControlBase { public: /* User access. */ static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_arguments_select.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_k_typed_address.hpp> #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/init/kern_k_init_arguments.hpp> #else #error "Unknown architecture for KInitArguments" #endif namespace ams::kern::init { static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments))); KInitArguments *GetInitArguments(s32 core_id); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_elf.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/init/kern_init_elf64.hpp> namespace ams::kern::init::Elf { using namespace ams::kern::init::Elf::Elf64; enum RelocationType { R_ARCHITECTURE_RELATIVE = 0x403, /* Real name R_AARCH64_RELATIVE */ }; } #else #error "Unknown Architecture" #endif namespace ams::kern::init::Elf { /* API to apply relocations or call init array. */ void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic); void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_elf64.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* From musl include/elf.h Copyright © 2005-2014 Rich Felker, et al. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include <vapours.hpp> namespace ams::kern::init::Elf::Elf64 { /* Type declarations required to perform relocations */ using Half = u16; using Word = u32; using Sword = s32; using Xword = u64; using SXword = s64; using Addr = u64; using Off = u64; class Dyn { private: SXword m_tag; union { Xword m_value; Addr m_ptr; }; public: constexpr ALWAYS_INLINE SXword GetTag() const { return m_tag; } constexpr ALWAYS_INLINE Xword GetValue() const { return m_value; } constexpr ALWAYS_INLINE Addr GetPtr() const { return m_ptr; } }; class Rel { private: Addr m_offset; Xword m_info; public: constexpr ALWAYS_INLINE Addr GetOffset() const { return m_offset; } constexpr ALWAYS_INLINE Xword GetSym() const { return m_info >> 32; } constexpr ALWAYS_INLINE Xword GetType() const { return m_info & 0xFFFFFFFF; } }; class Rela { private: Addr m_offset; Xword m_info; SXword m_addend; public: constexpr ALWAYS_INLINE Addr GetOffset() const { return m_offset; } constexpr ALWAYS_INLINE Xword GetSym() const { return m_info >> 32; } constexpr ALWAYS_INLINE Xword GetType() const { return m_info & 0xFFFFFFFF; } constexpr ALWAYS_INLINE SXword GetAddend() const { return m_addend; } }; class Relr { private: Xword m_info; public: constexpr ALWAYS_INLINE bool IsLocation() const { return (m_info & 1) == 0; } constexpr ALWAYS_INLINE Xword GetLocation() const { return m_info; } constexpr ALWAYS_INLINE Xword GetBitmap() const { return m_info >> 1; } }; enum DynamicTag { DT_NULL = 0, DT_RELA = 7, DT_RELAENT = 9, DT_REL = 17, DT_RELENT = 19, DT_RELRSZ = 35, DT_RELR = 36, DT_RELRENT = 37, DT_RELACOUNT = 0x6ffffff9, DT_RELCOUNT = 0x6ffffffa }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_layout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::kern::init { struct KernelLayout { u32 rx_offset; u32 rx_end_offset; u32 ro_offset; u32 ro_end_offset; u32 rw_offset; u32 rw_end_offset; u32 bss_offset; u32 bss_end_offset; u32 resource_offset; u32 dynamic_offset; u32 init_array_offset; u32 init_array_end_offset; u32 sysreg_offset; }; static_assert(util::is_pod<KernelLayout>::value); static_assert(sizeof(KernelLayout) == 0x34); #if defined(ATMOSPHERE_ARCH_ARM64) struct KernelSystemRegisters { u64 ttbr0_el1; u64 ttbr1_el1; u64 tcr_el1; u64 mair_el1; u64 sctlr_el1; }; #else struct KernelSystemRegisters { }; #endif } ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_page_table_select.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/init/kern_k_init_page_table.hpp> namespace ams::kern::init { using ams::kern::arch::arm64::PageTableEntry; using ams::kern::arch::arm64::init::KInitialPageTable; using ams::kern::arch::arm64::init::KInitialPageAllocator; } #else #error "Unknown architecture for KInitialPageTable" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/init/kern_init_slab_setup.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_k_slab_heap.hpp> namespace ams::kern::init { struct KSlabResourceCounts { size_t num_KProcess; size_t num_KThread; size_t num_KEvent; size_t num_KInterruptEvent; size_t num_KPort; size_t num_KSharedMemory; size_t num_KTransferMemory; size_t num_KCodeMemory; size_t num_KDeviceAddressSpace; size_t num_KSession; size_t num_KLightSession; size_t num_KObjectName; size_t num_KResourceLimit; size_t num_KDebug; size_t num_KIoPool; size_t num_KIoRegion; size_t num_KSessionRequestMappings; }; NOINLINE void InitializeSlabResourceCounts(); const KSlabResourceCounts &GetSlabResourceCounts(); size_t CalculateTotalSlabHeapSize(); NOINLINE void InitializeSlabHeaps(); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_build_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #if defined(AMS_BUILD_FOR_AUDITING) #define MESOSPHERE_BUILD_FOR_AUDITING #endif #if defined(MESOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) #define MESOSPHERE_BUILD_FOR_DEBUGGING #endif #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING #define MESOSPHERE_ENABLE_ASSERTIONS #define MESOSPHERE_ENABLE_DEBUG_PRINT #define MESOSPHERE_ENABLE_KERNEL_STACK_USAGE #endif #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) #define MESOSPHERE_NOINLINE_IF_DEBUG NOINLINE #define MESOSPHERE_ALWAYS_INLINE_IF_RELEASE NOINLINE #else #define MESOSPHERE_NOINLINE_IF_DEBUG #define MESOSPHERE_ALWAYS_INLINE_IF_RELEASE ALWAYS_INLINE #endif //#define MESOSPHERE_BUILD_FOR_TRACING //#define MESOSPHERE_ENABLE_PERFORMANCE_COUNTER #define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP #define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP /* NOTE: In 16.0.0, Nintendo deleted the creation time field for KProcess, */ /* but this may be useful for some debugging applications, and so can be. */ /* re-enabled by toggling this define. */ //#define MESOSPHERE_ENABLE_PROCESS_CREATION_TIME /* NOTE: This enables usage of KDebug handles as parameter for svc::GetInfo */ /* calls which require a process parameter. This enables a debugger to obtain */ /* address space/layout information, for example. However, it changes abi, and so */ /* this define allows toggling the extension. */ #define MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS /* NOTE: This uses currently-reserved bits inside the MapRange capability */ /* in order to support large physical addresses (40-bit instead of 36). */ /* This is toggleable in order to disable it if N ever uses those bits. */ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) //#define MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES #else #define MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/kern_build_config.hpp> #include <mesosphere/svc/kern_svc_results.hpp> #include <mesosphere/kern_select_assembly_offsets.h> namespace ams::kern { constexpr size_t PageSize = 4_KB; #ifdef ATMOSPHERE_BOARD_NINTENDO_NX ams::TargetFirmware GetTargetFirmware(); #else consteval ALWAYS_INLINE ams::TargetFirmware GetTargetFirmware() { return ams::TargetFirmware_Current; } #endif } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/svc/kern_svc_k_user_pointer.hpp> namespace ams::kern { class KDebugLog { private: static NOINLINE void VSNPrintf(char *dst, const size_t dst_size, const char *format, ::std::va_list vl); public: static NOINLINE void Initialize(); static NOINLINE void Printf(const char *format, ...) __attribute__((format(printf, 1, 2))); static NOINLINE void VPrintf(const char *format, ::std::va_list vl); static NOINLINE void LogException(const char *str); static NOINLINE Result PrintUserString(ams::kern::svc::KUserPointer<const char *> user_str, size_t len); /* Functionality for preserving across sleep. */ static NOINLINE void Save(); static NOINLINE void Restore(); }; } #ifndef MESOSPHERE_DEBUG_LOG_SELECTED #ifdef ATMOSPHERE_BOARD_NINTENDO_NX #define MESOSPHERE_DEBUG_LOG_USE_UART #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) #define MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING #else #error "Unknown board for Default Debug Log Source" #endif #define MESOSPHERE_DEBUG_LOG_SELECTED #endif #define MESOSPHERE_EXCEPTION_LOG(str) ::ams::kern::KDebugLog::LogException(str) #define MESOSPHERE_RELEASE_LOG(fmt, ...) ::ams::kern::KDebugLog::Printf((fmt), ## __VA_ARGS__) #define MESOSPHERE_RELEASE_VLOG(fmt, vl) ::ams::kern::KDebugLog::VPrintf((fmt), (vl)) #ifdef MESOSPHERE_ENABLE_DEBUG_PRINT #define MESOSPHERE_LOG(fmt, ...) MESOSPHERE_RELEASE_LOG((fmt), ## __VA_ARGS__) #define MESOSPHERE_VLOG(fmt, vl) MESOSPHERE_RELEASE_VLOG((fmt), (vl)) #else #define MESOSPHERE_LOG(fmt, ...) do { MESOSPHERE_UNUSED(fmt); MESOSPHERE_UNUSED(__VA_ARGS__); } while (0) #define MESOSPHERE_VLOG(fmt, vl) do { MESOSPHERE_UNUSED(fmt); MESOSPHERE_UNUSED(vl); } while (0) #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_initial_process_reader.hpp> namespace ams::kern { constexpr u32 InitialProcessBinaryMagic = util::FourCC<'I','N','I','1'>::Code; constexpr size_t InitialProcessBinarySizeMax = 12_MB; struct InitialProcessBinaryHeader { u32 magic; u32 size; u32 num_processes; u32 reserved; }; struct InitialProcessBinaryLayout { uintptr_t address; uintptr_t _08; uintptr_t kern_address; }; struct InitialProcessBinaryLayoutWithSize { InitialProcessBinaryLayout layout; size_t size; }; KPhysicalAddress GetInitialProcessBinaryPhysicalAddress(); size_t GetInitialProcessBinarySize(); void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size); u64 GetInitialProcessIdMin(); u64 GetInitialProcessIdMax(); size_t GetInitialProcessesSecureMemorySize(); NOINLINE size_t CopyInitialProcessBinaryToKernelMemory(); NOINLINE void CreateAndRunInitialProcesses(); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_address_arbiter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_condition_variable.hpp> namespace ams::kern { class KAddressArbiter { public: using ThreadTree = KConditionVariable::ThreadTree; private: ThreadTree m_tree; public: constexpr KAddressArbiter() = default; Result SignalToAddress(uintptr_t addr, ams::svc::SignalType type, s32 value, s32 count) { switch (type) { case ams::svc::SignalType_Signal: R_RETURN(this->Signal(addr, count)); case ams::svc::SignalType_SignalAndIncrementIfEqual: R_RETURN(this->SignalAndIncrementIfEqual(addr, value, count)); case ams::svc::SignalType_SignalAndModifyByWaitingCountIfEqual: R_RETURN(this->SignalAndModifyByWaitingCountIfEqual(addr, value, count)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s64 value, s64 timeout) { switch (type) { case ams::svc::ArbitrationType_WaitIfLessThan: R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), false, timeout)); case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan: R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), true, timeout)); case ams::svc::ArbitrationType_WaitIfEqual: R_RETURN(this->WaitIfEqual(addr, static_cast<s32>(value), timeout)); case ams::svc::ArbitrationType_WaitIfEqual64: R_RETURN(this->WaitIfEqual64(addr, value, timeout)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } private: Result Signal(uintptr_t addr, s32 count); Result SignalAndIncrementIfEqual(uintptr_t addr, s32 value, s32 count); Result SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count); Result WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout); Result WaitIfEqual(uintptr_t addr, s32 value, s64 timeout); Result WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::kern { struct KAddressSpaceInfo { public: enum Type { Type_MapSmall = 0, Type_MapLarge = 1, Type_Map39Bit = 2, Type_Heap = 3, Type_Stack = 4, Type_Alias = 5, Type_Count, }; private: size_t m_bit_width; size_t m_address; size_t m_size; Type m_type; public: static uintptr_t GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, Type type, size_t code_size); static size_t GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, Type type); static void SetAddressSpaceSize(size_t width, Type type, size_t size); constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ } constexpr size_t GetWidth() const { return m_bit_width; } constexpr size_t GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr Type GetType() const { return m_type; } constexpr void SetSize(size_t size) { m_size = size; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_affinity_mask.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern { class KAffinityMask { private: static constexpr u64 AllowedAffinityMask = (1ul << cpu::NumCores) - 1; private: u64 m_mask; private: static constexpr ALWAYS_INLINE u64 GetCoreBit(s32 core) { MESOSPHERE_ASSERT(0 <= core && core < static_cast<s32>(cpu::NumCores)); return (1ul << core); } public: constexpr ALWAYS_INLINE KAffinityMask() : m_mask(0) { MESOSPHERE_ASSERT_THIS(); } constexpr ALWAYS_INLINE u64 GetAffinityMask() const { return m_mask; } constexpr ALWAYS_INLINE void SetAffinityMask(u64 new_mask) { MESOSPHERE_ASSERT((new_mask & ~AllowedAffinityMask) == 0); m_mask = new_mask; } constexpr ALWAYS_INLINE bool GetAffinity(s32 core) const { return m_mask & GetCoreBit(core); } constexpr ALWAYS_INLINE void SetAffinity(s32 core, bool set) { MESOSPHERE_ASSERT(0 <= core && core < static_cast<s32>(cpu::NumCores)); if (set) { m_mask |= GetCoreBit(core); } else { m_mask &= ~GetCoreBit(core); } } constexpr ALWAYS_INLINE void SetAll() { m_mask = AllowedAffinityMask; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_auto_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_k_class_token.hpp> namespace ams::kern { class KProcess; #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) || defined(MESOSPHERE_BUILD_FOR_AUDITING) #define MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS) #CLASS #else #define MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS) "" #endif #define MESOSPHERE_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \ NON_COPYABLE(CLASS); \ NON_MOVEABLE(CLASS); \ private: \ friend class ::ams::kern::KClassTokenGenerator; \ static constexpr inline auto ObjectType = ::ams::kern::KClassTokenGenerator::ObjectType::CLASS; \ static constexpr inline const char * const TypeName = MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS); \ static constexpr inline ClassTokenType ClassToken() { return ::ams::kern::ClassToken<CLASS>; } \ public: \ using BaseClass = BASE_CLASS; \ static consteval ALWAYS_INLINE TypeObj GetStaticTypeObj() { \ constexpr ClassTokenType Token = ClassToken(); \ return TypeObj(TypeName, Token); \ } \ static consteval ALWAYS_INLINE const char *GetStaticTypeName() { return TypeName; } \ virtual TypeObj GetTypeObj() const { return GetStaticTypeObj(); } \ virtual const char *GetTypeName() { return GetStaticTypeName(); } \ private: class KAutoObject { public: class ReferenceCount { NON_COPYABLE(ReferenceCount); NON_MOVEABLE(ReferenceCount); private: using Storage = u32; private: util::Atomic<Storage> m_value; public: ALWAYS_INLINE explicit ReferenceCount() { /* ... */ } constexpr ALWAYS_INLINE explicit ReferenceCount(Storage v) : m_value(v) { /* ... */ } ALWAYS_INLINE void operator=(Storage v) { m_value = v; } ALWAYS_INLINE Storage GetValue() const { return m_value.Load(); } ALWAYS_INLINE bool Open() { /* Atomically increment the reference count, only if it's positive. */ u32 cur = m_value.Load<std::memory_order_relaxed>(); do { if (AMS_UNLIKELY(cur == 0)) { MESOSPHERE_AUDIT(cur != 0); return false; } MESOSPHERE_ABORT_UNLESS(cur < cur + 1); } while (AMS_UNLIKELY(!m_value.CompareExchangeWeak<std::memory_order_relaxed>(cur, cur + 1))); return true; } ALWAYS_INLINE bool Close() { /* Atomically decrement the reference count, not allowing it to decrement past zero. */ u32 cur = m_value.Load<std::memory_order_relaxed>(); do { MESOSPHERE_ABORT_UNLESS(cur > 0); } while (AMS_UNLIKELY(!m_value.CompareExchangeWeak<std::memory_order_relaxed>(cur, cur - 1))); /* Return whether the object was closed. */ return cur - 1 == 0; } }; protected: class TypeObj { private: const char *m_name; ClassTokenType m_class_token; public: constexpr explicit TypeObj(const char *n, ClassTokenType tok) : m_name(n), m_class_token(tok) { /* ... */ } constexpr ALWAYS_INLINE const char *GetName() const { return m_name; } constexpr ALWAYS_INLINE ClassTokenType GetClassToken() const { return m_class_token; } constexpr ALWAYS_INLINE bool operator==(const TypeObj &rhs) { return this->GetClassToken() == rhs.GetClassToken(); } constexpr ALWAYS_INLINE bool operator!=(const TypeObj &rhs) { return this->GetClassToken() != rhs.GetClassToken(); } constexpr ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) { return IsClassTokenDerivedFrom(this->GetClassToken(), rhs.GetClassToken()); } static constexpr ALWAYS_INLINE bool IsClassTokenDerivedFrom(ClassTokenType derived, ClassTokenType base) { return (derived | base) == derived; } }; private: MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); private: KAutoObject *m_next_closed_object; ReferenceCount m_ref_count; ClassTokenType m_class_token; public: constexpr ALWAYS_INLINE explicit KAutoObject(util::ConstantInitializeTag) : m_next_closed_object(nullptr), m_ref_count(0), m_class_token(0) { MESOSPHERE_ASSERT_THIS(); } ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); } /* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */ virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); } /* Finalize is responsible for cleaning up resource, but does not destroy the object. */ /* NOTE: This is a virtual function in official kernel, but because everything which uses it */ /* is already using CRTP for slab heap, we have devirtualized it for performance gain. */ /* virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); } */ /* NOTE: This is a virtual function which is unused-except-for-debug in Nintendo's kernel. */ /* virtual KProcess *GetOwner() const { return nullptr; } */ u32 GetReferenceCount() const { return m_ref_count.GetValue(); } ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const { return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken()); } ALWAYS_INLINE bool IsDerivedFrom(const KAutoObject &rhs) const { return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token); } template<typename Derived> ALWAYS_INLINE Derived DynamicCast() { static_assert(std::is_pointer<Derived>::value); using DerivedType = typename std::remove_pointer<Derived>::type; if (AMS_LIKELY(this->IsDerivedFrom(DerivedType::GetStaticTypeObj()))) { return static_cast<Derived>(this); } else { return nullptr; } } template<typename Derived> ALWAYS_INLINE const Derived DynamicCast() const { static_assert(std::is_pointer<Derived>::value); using DerivedType = typename std::remove_pointer<Derived>::type; if (AMS_LIKELY(this->IsDerivedFrom(DerivedType::GetStaticTypeObj()))) { return static_cast<Derived>(this); } else { return nullptr; } } MESOSPHERE_ALWAYS_INLINE_IF_RELEASE bool Open() { MESOSPHERE_ASSERT_THIS(); return m_ref_count.Open(); } MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Close() { MESOSPHERE_ASSERT_THIS(); if (m_ref_count.Close()) { this->ScheduleDestruction(); } } private: /* NOTE: This has to be defined *after* KThread is defined. */ /* Nintendo seems to handle this by defining Open/Close() in a cpp, but we'd like them to remain in headers. */ /* Implementation for this will be inside kern_k_thread.hpp, so it can be ALWAYS_INLINE. */ void ScheduleDestruction(); public: /* Getter, for KThread. */ ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; } public: template<typename Derived> requires (std::derived_from<Derived, KAutoObject>) static ALWAYS_INLINE void Create(typename std::type_identity<Derived>::type *obj) { /* Get auto object pointer. */ KAutoObject &auto_object = *static_cast<KAutoObject *>(obj); /* If we should, set our class token. */ { constexpr auto Token = Derived::GetStaticTypeObj().GetClassToken(); auto_object.m_class_token = Token; } /* Initialize reference count to 1. */ auto_object.m_ref_count = 1; } }; class KAutoObjectWithListBase : public KAutoObject { private: void *m_alignment_forcer_unused[0]; public: constexpr ALWAYS_INLINE explicit KAutoObjectWithListBase(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_alignment_forcer_unused{} { /* ... */ } ALWAYS_INLINE explicit KAutoObjectWithListBase() { /* ... */ } }; class KAutoObjectWithList : public KAutoObjectWithListBase { private: template<typename> friend class KAutoObjectWithListContainer; private: util::IntrusiveRedBlackTreeNode m_list_node; public: constexpr ALWAYS_INLINE KAutoObjectWithList(util::ConstantInitializeTag) : KAutoObjectWithListBase(util::ConstantInitialize), m_list_node(util::ConstantInitialize) { /* ... */ } ALWAYS_INLINE explicit KAutoObjectWithList() { /* ... */ } public: /* NOTE: This is virtual in Nintendo's kernel. */ u64 GetId() const; }; template<typename T> requires std::derived_from<T, KAutoObject> class KScopedAutoObject { NON_COPYABLE(KScopedAutoObject); private: template<typename U> requires std::derived_from<U, KAutoObject> friend class KScopedAutoObject; private: T *m_obj; private: constexpr ALWAYS_INLINE void Swap(KScopedAutoObject &rhs) { std::swap(m_obj, rhs.m_obj); } public: constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : m_obj(o) { if (m_obj != nullptr) { m_obj->Open(); } } ALWAYS_INLINE ~KScopedAutoObject() { if (m_obj != nullptr) { m_obj->Close(); } m_obj = nullptr; } template<typename U> requires (std::derived_from<T, U> || std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U> &&rhs) { if constexpr (std::derived_from<U, T>) { /* Upcast. */ m_obj = rhs.m_obj; rhs.m_obj = nullptr; } else { /* Downcast. */ T *derived = nullptr; if (rhs.m_obj != nullptr) { derived = rhs.m_obj->template DynamicCast<T *>(); if (derived == nullptr) { rhs.m_obj->Close(); } } m_obj = derived; rhs.m_obj = nullptr; } } constexpr ALWAYS_INLINE KScopedAutoObject<T> &operator=(KScopedAutoObject<T> &&rhs) { rhs.Swap(*this); return *this; } constexpr ALWAYS_INLINE T *operator->() { return m_obj; } constexpr ALWAYS_INLINE T &operator*() { return *m_obj; } constexpr ALWAYS_INLINE void Reset(T *o) { KScopedAutoObject(o).Swap(*this); } constexpr ALWAYS_INLINE T *GetPointerUnsafe() { return m_obj; } constexpr ALWAYS_INLINE T *ReleasePointerUnsafe() { T *ret = m_obj; m_obj = nullptr; return ret; } constexpr ALWAYS_INLINE bool IsNull() const { return m_obj == nullptr; } constexpr ALWAYS_INLINE bool IsNotNull() const { return m_obj != nullptr; } }; template<typename T> requires std::derived_from<T, KAutoObject> class KSharedAutoObject { private: T *m_object; KAutoObject::ReferenceCount m_ref_count; public: explicit KSharedAutoObject() : m_object(nullptr) { /* ... */ } void Attach(T *obj) { MESOSPHERE_ASSERT(m_object == nullptr); /* Set our object. */ m_object = obj; /* Open reference to our object. */ m_object->Open(); /* Set our reference count. */ m_ref_count = 1; } bool Open() { return m_ref_count.Open(); } void Close() { if (m_ref_count.Close()) { this->Detach(); } } ALWAYS_INLINE T *Get() const { return m_object; } private: void Detach() { /* Close our object, if we have one. */ if (T * const object = m_object; AMS_LIKELY(object != nullptr)) { /* Set our object to a debug sentinel value, which will cause a crash if accessed. */ m_object = reinterpret_cast<T *>(1); /* Close reference to our object. */ object->Close(); } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_auto_object_container.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_k_light_lock.hpp> namespace ams::kern { namespace impl { template<typename T> struct GetAutoObjectWithListComparator; class KAutoObjectWithListContainerBase { NON_COPYABLE(KAutoObjectWithListContainerBase); NON_MOVEABLE(KAutoObjectWithListContainerBase); protected: template<typename ListType> class ListAccessorImpl { NON_COPYABLE(ListAccessorImpl); NON_MOVEABLE(ListAccessorImpl); private: KScopedLightLock m_lk; ListType &m_list; public: explicit ALWAYS_INLINE ListAccessorImpl(KAutoObjectWithListContainerBase *container, ListType &list) : m_lk(container->m_lock), m_list(list) { /* ... */ } explicit ALWAYS_INLINE ListAccessorImpl(KAutoObjectWithListContainerBase &container, ListType &list) : m_lk(container.m_lock), m_list(list) { /* ... */ } ALWAYS_INLINE ~ListAccessorImpl() { /* ... */ } ALWAYS_INLINE typename ListType::iterator begin() const { return m_list.begin(); } ALWAYS_INLINE typename ListType::iterator end() const { return m_list.end(); } ALWAYS_INLINE typename ListType::iterator find(typename ListType::const_reference ref) const { return m_list.find(ref); } ALWAYS_INLINE typename ListType::iterator find_key(typename ListType::const_key_reference ref) const { return m_list.find_key(ref); } }; template<typename ListType> friend class ListAccessorImpl; private: KLightLock m_lock; protected: constexpr KAutoObjectWithListContainerBase() : m_lock() { /* ... */ } ALWAYS_INLINE void InitializeImpl() { MESOSPHERE_ASSERT_THIS(); } ALWAYS_INLINE void FinalizeImpl() { MESOSPHERE_ASSERT_THIS(); } template<typename ListType> void RegisterImpl(KAutoObjectWithList *obj, ListType &list) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); list.insert(*obj); } template<typename ListType> void UnregisterImpl(KAutoObjectWithList *obj, ListType &list) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); list.erase(list.iterator_to(*obj)); } template<typename U, typename ListType> size_t GetOwnedCountImpl(const KProcess *owner, ListType &list) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); size_t count = 0; for (const auto &obj : list) { MESOSPHERE_AUDIT(obj.template DynamicCast<const U *>() != nullptr); if (static_cast<const U &>(obj).GetOwner() == owner) { ++count; } } return count; } }; struct DummyKAutoObjectWithListComparator { static NOINLINE int Compare(KAutoObjectWithList &lhs, KAutoObjectWithList &rhs) { MESOSPHERE_UNUSED(lhs, rhs); MESOSPHERE_PANIC("DummyKAutoObjectWithListComparator invoked"); } }; } template<typename T> class KAutoObjectWithListContainer : public impl::KAutoObjectWithListContainerBase { private: using Base = impl::KAutoObjectWithListContainerBase; public: class ListAccessor; friend class ListAccessor; template<typename Comparator> using ListType = util::IntrusiveRedBlackTreeMemberTraits<&KAutoObjectWithList::m_list_node>::TreeType<Comparator>; using DummyListType = ListType<impl::DummyKAutoObjectWithListComparator>; private: DummyListType m_dummy_object_list; public: constexpr ALWAYS_INLINE KAutoObjectWithListContainer() : Base(), m_dummy_object_list() { static_assert(std::derived_from<T, KAutoObjectWithList>); } ALWAYS_INLINE void Initialize() { return this->InitializeImpl(); } ALWAYS_INLINE void Finalize() { return this->FinalizeImpl(); } void Register(T *obj); void Unregister(T *obj); private: size_t GetOwnedCountChecked(const KProcess *owner); public: template<typename U> requires (std::same_as<U, T> && requires (const U &u) { { u.GetOwner() } -> std::convertible_to<const KProcess *>; }) ALWAYS_INLINE size_t GetOwnedCount(const KProcess *owner) { return this->GetOwnedCountChecked(owner); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_auto_object_impls.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_class_token.hpp> namespace ams::kern { /* NOTE: This header is included after all other KAutoObjects. */ namespace impl { template<typename T> requires std::derived_from<T, KAutoObject> consteval bool IsAutoObjectInheritanceValidImpl() { #define CLASS_TOKEN_HANDLER(CLASSNAME) \ if constexpr (std::same_as<T, CLASSNAME>) { \ if (T::GetStaticTypeObj().GetClassToken() != ::ams::kern::ClassToken<CLASSNAME>) { \ return false; \ } \ } else { \ if (T::GetStaticTypeObj().IsDerivedFrom(CLASSNAME::GetStaticTypeObj()) != std::derived_from<T, CLASSNAME>) { \ return false; \ } \ } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return true; } consteval bool IsEveryAutoObjectInheritanceValid() { #define CLASS_TOKEN_HANDLER(CLASSNAME) if (!IsAutoObjectInheritanceValidImpl<CLASSNAME>()) { return false; } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return true; } static_assert(IsEveryAutoObjectInheritanceValid()); template<typename T> concept IsAutoObjectWithSpecializedGetId = std::derived_from<T, KAutoObjectWithList> && requires (const T &t, const KAutoObjectWithList &l) { { t.GetIdImpl() } -> std::same_as<decltype(l.GetId())>; }; template<typename T> struct AutoObjectWithListComparatorImpl { using RedBlackKeyType = u64; static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; } static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KAutoObjectWithList &v) { if constexpr (IsAutoObjectWithSpecializedGetId<T>) { return static_cast<const T &>(v).GetIdImpl(); } else { return reinterpret_cast<u64>(std::addressof(v)); } } template<typename U> requires (std::same_as<U, KAutoObjectWithList> || std::same_as<U, RedBlackKeyType>) static ALWAYS_INLINE int Compare(const U &lhs, const KAutoObjectWithList &rhs) { const u64 lid = GetRedBlackKey(lhs); const u64 rid = GetRedBlackKey(rhs); if (lid < rid) { return -1; } else if (lid > rid) { return 1; } else { return 0; } } }; template<typename T> using AutoObjectWithListComparator = AutoObjectWithListComparatorImpl<typename std::conditional<IsAutoObjectWithSpecializedGetId<T>, T, KAutoObjectWithList>::type>; template<typename T> using TrueObjectContainerListType = typename KAutoObjectWithListContainer<T>::ListType<AutoObjectWithListComparator<T>>; template<typename T> ALWAYS_INLINE TrueObjectContainerListType<T> &GetTrueObjectContainerList(typename KAutoObjectWithListContainer<T>::DummyListType &l) { static_assert(alignof(l) == alignof(impl::TrueObjectContainerListType<T>)); static_assert(sizeof(l) == sizeof(impl::TrueObjectContainerListType<T>)); return *reinterpret_cast<TrueObjectContainerListType<T> *>(std::addressof(l)); } } inline NOINLINE void KAutoObject::ScheduleDestruction() { MESOSPHERE_ASSERT_THIS(); /* Set our object to destroy. */ m_next_closed_object = GetCurrentThread().GetClosedObject(); /* Set ourselves as the thread's next object to destroy. */ GetCurrentThread().SetClosedObject(this); } template<typename T> class KAutoObjectWithListContainer<T>::ListAccessor : public impl::KAutoObjectWithListContainerBase::ListAccessorImpl<impl::TrueObjectContainerListType<T>> { NON_COPYABLE(ListAccessor); NON_MOVEABLE(ListAccessor); private: using BaseListAccessor = impl::KAutoObjectWithListContainerBase::ListAccessorImpl<impl::TrueObjectContainerListType<T>>; public: explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer *container) : BaseListAccessor(container, impl::GetTrueObjectContainerList<T>(container->m_dummy_object_list)) { /* ... */ } explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer &container) : BaseListAccessor(container, impl::GetTrueObjectContainerList<T>(container.m_dummy_object_list)) { /* ... */ } ALWAYS_INLINE ~ListAccessor() { /* ... */ } }; template<typename T> ALWAYS_INLINE void KAutoObjectWithListContainer<T>::Register(T *obj) { return this->RegisterImpl(obj, impl::GetTrueObjectContainerList<T>(m_dummy_object_list)); } template<typename T> ALWAYS_INLINE void KAutoObjectWithListContainer<T>::Unregister(T *obj) { return this->UnregisterImpl(obj, impl::GetTrueObjectContainerList<T>(m_dummy_object_list)); } template<typename T> ALWAYS_INLINE size_t KAutoObjectWithListContainer<T>::GetOwnedCountChecked(const KProcess *owner) { return this->GetOwnedCountImpl<T>(owner, impl::GetTrueObjectContainerList<T>(m_dummy_object_list)); } inline u64 KAutoObjectWithList::GetId() const { #define CLASS_TOKEN_HANDLER(CLASSNAME) \ if constexpr (impl::IsAutoObjectWithSpecializedGetId<CLASSNAME>) { \ if (const CLASSNAME * const derived = this->DynamicCast<const CLASSNAME *>(); derived != nullptr) { \ return []<typename T>(const T * const t_derived) ALWAYS_INLINE_LAMBDA -> u64 { \ static_assert(std::same_as<T, CLASSNAME>); \ if constexpr (impl::IsAutoObjectWithSpecializedGetId<CLASSNAME>) { \ return impl::AutoObjectWithListComparator<CLASSNAME>::GetRedBlackKey(*t_derived); \ } else { \ AMS_ASSUME(false); \ } \ }(derived); \ } \ } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return impl::AutoObjectWithListComparator<KAutoObjectWithList>::GetRedBlackKey(*this); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_select_page_table.hpp> #include <mesosphere/kern_svc.hpp> namespace ams::kern { class KCapabilities { private: static constexpr size_t InterruptIdCount = 0x400; struct InterruptFlagSetTag{}; using InterruptFlagSet = util::BitFlagSet<InterruptIdCount, InterruptFlagSetTag>; enum class CapabilityType : u32 { CorePriority = (1u << 3) - 1, SyscallMask = (1u << 4) - 1, MapRange = (1u << 6) - 1, MapIoPage = (1u << 7) - 1, MapRegion = (1u << 10) - 1, InterruptPair = (1u << 11) - 1, ProgramType = (1u << 13) - 1, KernelVersion = (1u << 14) - 1, HandleTable = (1u << 15) - 1, DebugFlags = (1u << 16) - 1, Invalid = 0u, Padding = ~0u, }; using RawCapabilityValue = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32), u32>; static constexpr CapabilityType GetCapabilityType(const util::BitPack32 cap) { const u32 value = cap.Get<RawCapabilityValue>(); return static_cast<CapabilityType>((~value & (value + 1)) - 1); } static constexpr u32 GetCapabilityFlag(CapabilityType type) { return static_cast<u32>(type) + 1; } template<size_t Index, size_t Count, typename T = u32> using Field = util::BitPack32::Field<Index, Count, T>; #define DEFINE_FIELD(name, prev, ...) using name = Field<prev::Next, __VA_ARGS__> template<CapabilityType Type> static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1; template<CapabilityType Type> static constexpr inline u32 CapabilityId = util::CountTrailingZeros<u32>(CapabilityFlag<Type>); struct CorePriority { using IdBits = Field<0, CapabilityId<CapabilityType::CorePriority> + 1>; DEFINE_FIELD(LowestThreadPriority, IdBits, 6); DEFINE_FIELD(HighestThreadPriority, LowestThreadPriority, 6); DEFINE_FIELD(MinimumCoreId, HighestThreadPriority, 8); DEFINE_FIELD(MaximumCoreId, MinimumCoreId, 8); }; struct SyscallMask { using IdBits = Field<0, CapabilityId<CapabilityType::SyscallMask> + 1>; DEFINE_FIELD(Mask, IdBits, 24); DEFINE_FIELD(Index, Mask, 3); }; #if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES) static constexpr u64 PhysicalMapAllowedMask = (1ul << 40) - 1; #else static constexpr u64 PhysicalMapAllowedMask = (1ul << 36) - 1; #endif struct MapRange { using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>; DEFINE_FIELD(Address, IdBits, 24); DEFINE_FIELD(ReadOnly, Address, 1, bool); }; struct MapRangeSize { using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>; DEFINE_FIELD(Pages, IdBits, 20); #if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES) DEFINE_FIELD(AddressHigh, Pages, 4); DEFINE_FIELD(Normal, AddressHigh, 1, bool); #else DEFINE_FIELD(Reserved, Pages, 4); DEFINE_FIELD(Normal, Reserved, 1, bool); #endif }; struct MapIoPage { using IdBits = Field<0, CapabilityId<CapabilityType::MapIoPage> + 1>; DEFINE_FIELD(Address, IdBits, 24); }; enum class RegionType : u32 { NoMapping = 0, KernelTraceBuffer = 1, OnMemoryBootImage = 2, DTB = 3, }; struct MapRegion { using IdBits = Field<0, CapabilityId<CapabilityType::MapRegion> + 1>; DEFINE_FIELD(Region0, IdBits, 6, RegionType); DEFINE_FIELD(ReadOnly0, Region0, 1, bool); DEFINE_FIELD(Region1, ReadOnly0, 6, RegionType); DEFINE_FIELD(ReadOnly1, Region1, 1, bool); DEFINE_FIELD(Region2, ReadOnly1, 6, RegionType); DEFINE_FIELD(ReadOnly2, Region2, 1, bool); }; static const u32 PaddingInterruptId = 0x3FF; static_assert(PaddingInterruptId < InterruptIdCount); struct InterruptPair { using IdBits = Field<0, CapabilityId<CapabilityType::InterruptPair> + 1>; DEFINE_FIELD(InterruptId0, IdBits, 10); DEFINE_FIELD(InterruptId1, InterruptId0, 10); }; struct ProgramType { using IdBits = Field<0, CapabilityId<CapabilityType::ProgramType> + 1>; DEFINE_FIELD(Type, IdBits, 3); DEFINE_FIELD(Reserved, Type, 15); }; struct KernelVersion { using IdBits = Field<0, CapabilityId<CapabilityType::KernelVersion> + 1>; DEFINE_FIELD(MinorVersion, IdBits, 4); DEFINE_FIELD(MajorVersion, MinorVersion, 13); }; struct HandleTable { using IdBits = Field<0, CapabilityId<CapabilityType::HandleTable> + 1>; DEFINE_FIELD(Size, IdBits, 10); DEFINE_FIELD(Reserved, Size, 6); }; struct DebugFlags { using IdBits = Field<0, CapabilityId<CapabilityType::DebugFlags> + 1>; DEFINE_FIELD(AllowDebug, IdBits, 1, bool); DEFINE_FIELD(ForceDebugProd, AllowDebug, 1, bool); DEFINE_FIELD(ForceDebug, ForceDebugProd, 1, bool); DEFINE_FIELD(Reserved, ForceDebug, 12); }; #undef DEFINE_FIELD static constexpr u32 InitializeOnceFlags = CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> | CapabilityFlag<CapabilityType::KernelVersion> | CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>; private: svc::SvcAccessFlagSet m_svc_access_flags; InterruptFlagSet m_irq_access_flags; u64 m_core_mask; u64 m_phys_core_mask; u64 m_priority_mask; util::BitPack32 m_debug_capabilities; s32 m_handle_table_size; util::BitPack32 m_intended_kernel_version; u32 m_program_type; private: constexpr bool SetSvcAllowed(u32 id) { if (AMS_LIKELY(id < static_cast<u32>(m_svc_access_flags.GetCount()))) { m_svc_access_flags[id] = true; return true; } else { return false; } } constexpr bool SetInterruptPermitted(u32 id) { if (AMS_LIKELY(id < static_cast<u32>(m_irq_access_flags.GetCount()))) { m_irq_access_flags[id] = true; return true; } else { return false; } } Result SetCorePriorityCapability(const util::BitPack32 cap); Result SetSyscallMaskCapability(const util::BitPack32 cap, u32 &set_svc); Result MapRange(const util::BitPack32 cap, const util::BitPack32 size_cap, KProcessPageTable *page_table); Result MapIoPage(const util::BitPack32 cap, KProcessPageTable *page_table); Result MapRegion(const util::BitPack32 cap, KProcessPageTable *page_table); Result SetInterruptPairCapability(const util::BitPack32 cap); Result SetProgramTypeCapability(const util::BitPack32 cap); Result SetKernelVersionCapability(const util::BitPack32 cap); Result SetHandleTableCapability(const util::BitPack32 cap); Result SetDebugFlagsCapability(const util::BitPack32 cap); template<typename F> static Result ProcessMapRegionCapability(const util::BitPack32 cap, F f); static Result CheckMapRegion(const util::BitPack32 cap); Result SetCapability(const util::BitPack32 cap, u32 &set_flags, u32 &set_svc, KProcessPageTable *page_table); Result SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table); Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table); public: constexpr explicit KCapabilities(util::ConstantInitializeTag) : m_svc_access_flags{}, m_irq_access_flags{}, m_core_mask{}, m_phys_core_mask{}, m_priority_mask{}, m_debug_capabilities{0}, m_handle_table_size{}, m_intended_kernel_version{}, m_program_type{} { /* ... */ } KCapabilities() { /* ... */ } Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table); Result Initialize(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table); static Result CheckCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps); constexpr u64 GetCoreMask() const { return m_core_mask; } constexpr u64 GetPhysicalCoreMask() const { return m_phys_core_mask; } constexpr u64 GetPriorityMask() const { return m_priority_mask; } constexpr s32 GetHandleTableSize() const { return m_handle_table_size; } constexpr const svc::SvcAccessFlagSet &GetSvcPermissions() const { return m_svc_access_flags; } constexpr bool IsPermittedSvc(svc::SvcId id) const { return (id < m_svc_access_flags.GetCount()) && m_svc_access_flags[id]; } constexpr bool IsPermittedInterrupt(u32 id) const { return (id < m_irq_access_flags.GetCount()) && m_irq_access_flags[id]; } constexpr bool IsPermittedDebug() const { return m_debug_capabilities.Get<DebugFlags::AllowDebug>(); } constexpr bool CanForceDebugProd() const { return m_debug_capabilities.Get<DebugFlags::ForceDebugProd>(); } constexpr bool CanForceDebug() const { return m_debug_capabilities.Get<DebugFlags::ForceDebug>(); } constexpr u32 GetIntendedKernelMajorVersion() const { return m_intended_kernel_version.Get<KernelVersion::MajorVersion>(); } constexpr u32 GetIntendedKernelMinorVersion() const { return m_intended_kernel_version.Get<KernelVersion::MinorVersion>(); } constexpr u32 GetIntendedKernelVersion() const { return ams::svc::EncodeKernelVersion(this->GetIntendedKernelMajorVersion(), this->GetIntendedKernelMinorVersion()); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_class_token.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern { class KAutoObject; class KSystemResource; #define FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(HANDLER) \ HANDLER(KAutoObject) \ \ HANDLER(KSynchronizationObject) \ HANDLER(KReadableEvent) \ \ HANDLER(KInterruptEvent) \ HANDLER(KDebug) \ HANDLER(KThread) \ HANDLER(KServerPort) \ HANDLER(KServerSession) \ HANDLER(KClientPort) \ HANDLER(KClientSession) \ HANDLER(KProcess) \ HANDLER(KResourceLimit) \ HANDLER(KLightSession) \ HANDLER(KPort) \ HANDLER(KSession) \ HANDLER(KSharedMemory) \ HANDLER(KEvent) \ HANDLER(KLightClientSession) \ HANDLER(KLightServerSession) \ HANDLER(KTransferMemory) \ HANDLER(KDeviceAddressSpace) \ HANDLER(KSessionRequest) \ HANDLER(KCodeMemory) \ HANDLER(KIoPool) \ HANDLER(KIoRegion) \ HANDLER(KSystemResource) class KClassTokenGenerator { public: using TokenBaseType = u16; public: static constexpr size_t BaseClassBits = 8; static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits; /* One bit per base class. */ static constexpr size_t NumBaseClasses = BaseClassBits; /* Final classes are permutations of three bits. */ static constexpr size_t NumFinalClasses = [] { TokenBaseType index = 0; for (size_t i = 0; i < FinalClassBits; i++) { for (size_t j = i + 1; j < FinalClassBits; j++) { for (size_t k = j + 1; k < FinalClassBits; k++) { index++; } } } return index; }(); private: template<TokenBaseType Index> static constexpr inline TokenBaseType BaseClassToken = BIT(Index); template<TokenBaseType Index> static constexpr inline TokenBaseType FinalClassToken = [] { TokenBaseType index = 0; for (size_t i = 0; i < FinalClassBits; i++) { for (size_t j = i + 1; j < FinalClassBits; j++) { for (size_t k = j + 1; k < FinalClassBits; k++) { if ((index++) == Index) { return ((1ul << i) | (1ul << j) | (1ul << k)) << BaseClassBits; } } } } __builtin_unreachable(); }(); template<typename T> static constexpr inline TokenBaseType GetClassToken() { static_assert(std::is_base_of<KAutoObject, T>::value); if constexpr (std::is_same<T, KAutoObject>::value) { static_assert(T::ObjectType == ObjectType::KAutoObject); return 0; } else if constexpr (!std::is_final<T>::value && !std::same_as<T, KSystemResource>) { static_assert(ObjectType::BaseClassesStart <= T::ObjectType && T::ObjectType < ObjectType::BaseClassesEnd); constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - static_cast<TokenBaseType>(ObjectType::BaseClassesStart); return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>(); } else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType && T::ObjectType < ObjectType::FinalClassesEnd) { constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - static_cast<TokenBaseType>(ObjectType::FinalClassesStart); return FinalClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>(); } else { static_assert(!std::is_same<T, T>::value, "GetClassToken: Invalid Type"); } }; public: enum class ObjectType { KAutoObject, BaseClassesStart, KSynchronizationObject = BaseClassesStart, KReadableEvent, BaseClassesEnd, FinalClassesStart = BaseClassesEnd, KInterruptEvent = FinalClassesStart, KDebug, KThread, KServerPort, KServerSession, KClientPort, KClientSession, KProcess, KResourceLimit, KLightSession, KPort, KSession, KSharedMemory, KEvent, KLightClientSession, KLightServerSession, KTransferMemory, KDeviceAddressSpace, KSessionRequest, KCodeMemory, KIoPool, KIoRegion, /* NOTE: What occupies these gaps? They can be inferred, but they don't make sense. */ KAlpha, KBeta, KSystemResource, FinalClassesLast, FinalClassesEnd = FinalClassesStart + NumFinalClasses, }; static_assert(ObjectType::FinalClassesLast <= ObjectType::FinalClassesEnd); template<typename T> static constexpr inline TokenBaseType ClassToken = GetClassToken<T>(); }; using ClassTokenType = KClassTokenGenerator::TokenBaseType; template<typename T> static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>; namespace impl { consteval bool IsKClassTokenGeneratorForEachMacroValid() { auto IsObjectTypeIncludedByMacro = [](KClassTokenGenerator::ObjectType object_type) -> bool { #define CLASS_TOKEN_HANDLER(CLASSNAME) if (object_type == KClassTokenGenerator::ObjectType::CLASSNAME) { return true; } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return false; }; if (!IsObjectTypeIncludedByMacro(KClassTokenGenerator::ObjectType::KAutoObject)) { return false; } for (auto base = util::ToUnderlying(KClassTokenGenerator::ObjectType::BaseClassesStart); base < util::ToUnderlying(KClassTokenGenerator::ObjectType::BaseClassesEnd); ++base) { if (!IsObjectTypeIncludedByMacro(static_cast<KClassTokenGenerator::ObjectType>(base))) { return false; } } for (auto fin = util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesStart); fin < util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesLast); ++fin) { if (const auto o = static_cast<KClassTokenGenerator::ObjectType>(fin); !IsObjectTypeIncludedByMacro(o)) { if (o != KClassTokenGenerator::ObjectType::KAlpha && o != KClassTokenGenerator::ObjectType::KBeta) { return false; } } } return true; } static_assert(IsKClassTokenGeneratorForEachMacroValid()); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_client_port.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> namespace ams::kern { class KPort; class KSession; class KClientSession; class KLightSession; class KLightClientSession; class KClientPort final : public KSynchronizationObject { MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); private: util::Atomic<s32> m_num_sessions; util::Atomic<s32> m_peak_sessions; s32 m_max_sessions; KPort *m_parent; public: constexpr explicit KClientPort(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_num_sessions(0), m_peak_sessions(0), m_max_sessions(), m_parent() { /* ... */ } explicit KClientPort() { /* ... */ } void Initialize(KPort *parent, s32 max_sessions); void OnSessionFinalized(); void OnServerClosed(); constexpr const KPort *GetParent() const { return m_parent; } ALWAYS_INLINE s32 GetNumSessions() const { return m_num_sessions.Load(); } ALWAYS_INLINE s32 GetPeakSessions() const { return m_peak_sessions.Load(); } ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; } bool IsLight() const; bool IsServerClosed() const; /* Overridden virtual functions. */ virtual void Destroy() override; virtual bool IsSignaled() const override; Result CreateSession(KClientSession **out); Result CreateLightSession(KLightClientSession **out); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_client_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> namespace ams::kern { class KSession; class KEvent; class KClientSession final : public KAutoObject { MESOSPHERE_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); private: KSession *m_parent; public: constexpr explicit KClientSession(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_parent() { /* ... */ } explicit KClientSession() { /* ... */ } void Initialize(KSession *parent) { /* Set member variables. */ m_parent = parent; } virtual void Destroy() override; constexpr KSession *GetParent() const { return m_parent; } Result SendSyncRequest(uintptr_t address, size_t size); Result SendAsyncRequest(KEvent *event, uintptr_t address, size_t size); void OnServerClosed(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_code_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KCodeMemory final : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); private: util::TypedStorage<KPageGroup> m_page_group; KProcess *m_owner; KProcessAddress m_address; KLightLock m_lock; bool m_is_initialized; bool m_is_owner_mapped; bool m_is_mapped; public: explicit KCodeMemory() : m_owner(nullptr), m_address(Null<KProcessAddress>), m_is_initialized(false), m_is_owner_mapped(false), m_is_mapped(false) { /* ... */ } Result Initialize(KProcessAddress address, size_t size); void Finalize(); Result Map(KProcessAddress address, size_t size); Result Unmap(KProcessAddress address, size_t size); Result MapToOwner(KProcessAddress address, size_t size, ams::svc::MemoryPermission perm); Result UnmapFromOwner(KProcessAddress address, size_t size); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } KProcess *GetOwner() const { return m_owner; } KProcessAddress GetSourceAddress() { return m_address; } size_t GetSize() const { return m_is_initialized ? GetReference(m_page_group).GetNumPages() * PageSize : 0; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_condition_variable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_scheduler.hpp> namespace ams::kern { class KConditionVariable { public: using ThreadTree = typename KThread::ConditionVariableThreadTreeType; private: ThreadTree m_tree; public: constexpr KConditionVariable() = default; /* Arbitration. */ static Result SignalToAddress(KProcessAddress addr); static Result WaitForAddress(ams::svc::Handle handle, KProcessAddress addr, u32 value); /* Condition variable. */ void Signal(uintptr_t cv_key, s32 count); Result Wait(KProcessAddress addr, uintptr_t key, u32 value, s64 timeout); private: void SignalImpl(KThread *thread); }; ALWAYS_INLINE void BeforeUpdatePriority(KConditionVariable::ThreadTree *tree, KThread *thread) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); tree->erase(tree->iterator_to(*thread)); } ALWAYS_INLINE void AfterUpdatePriority(KConditionVariable::ThreadTree *tree, KThread *thread) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); tree->insert(*thread); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_current_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern { class KThread; class KProcess; class KScheduler; ALWAYS_INLINE KThread *GetCurrentThreadPointer() { return reinterpret_cast<KThread *>(cpu::GetCurrentThreadPointerValue()); } ALWAYS_INLINE KThread &GetCurrentThread() { return *GetCurrentThreadPointer(); } ALWAYS_INLINE void SetCurrentThread(KThread *new_thread) { cpu::SetCurrentThreadPointerValue(reinterpret_cast<uintptr_t>(new_thread)); } ALWAYS_INLINE KProcess *GetCurrentProcessPointer(); ALWAYS_INLINE KProcess &GetCurrentProcess(); ALWAYS_INLINE s32 GetCurrentCoreId(); ALWAYS_INLINE KScheduler &GetCurrentScheduler(); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_debug_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_process.hpp> #include <mesosphere/kern_k_event_info.hpp> #include <mesosphere/kern_k_light_lock.hpp> namespace ams::kern { class KDebugBase : public KSynchronizationObject { protected: using DebugEventList = util::IntrusiveListBaseTraits<KEventInfo>::ListType; private: DebugEventList m_event_info_list; u32 m_continue_flags; KSharedAutoObject<KProcess> m_process_holder; KLightLock m_lock; KProcess::State m_old_process_state; bool m_is_attached; bool m_is_force_debug_prod; public: explicit KDebugBase() { /* ... */ } protected: bool Is64Bit() const; public: void Initialize(); void Finalize(); Result Attach(KProcess *process); Result BreakProcess(); Result TerminateProcess(); Result ContinueDebug(const u32 flags, const u64 *thread_ids, size_t num_thread_ids); Result QueryMemoryInfo(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, KProcessAddress address); Result ReadMemory(KProcessAddress buffer, KProcessAddress address, size_t size); Result WriteMemory(KProcessAddress buffer, KProcessAddress address, size_t size); Result GetThreadContext(ams::svc::ThreadContext *out, u64 thread_id, u32 context_flags); Result SetThreadContext(const ams::svc::ThreadContext &ctx, u64 thread_id, u32 context_flags); Result GetRunningThreadInfo(ams::svc::LastThreadContext *out_context, u64 *out_thread_id); Result GetDebugEventInfo(ams::svc::lp64::DebugEventInfo *out); Result GetDebugEventInfo(ams::svc::ilp32::DebugEventInfo *out); ALWAYS_INLINE bool IsAttached() const { return m_is_attached; } ALWAYS_INLINE bool IsForceDebugProd() const { return m_is_force_debug_prod; } ALWAYS_INLINE bool OpenProcess() { return m_process_holder.Open(); } ALWAYS_INLINE void CloseProcess() { return m_process_holder.Close(); } ALWAYS_INLINE KProcess *GetProcessUnsafe() const { return m_process_holder.Get(); } private: void PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params); void EnqueueDebugEventInfo(KEventInfo *info); template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>) Result GetDebugEventInfoImpl(T *out); public: virtual bool IsSignaled() const override; private: /* NOTE: This is public/virtual override in Nintendo's kernel. */ void OnFinalizeSynchronizationObject(); private: static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params); public: static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params); static void OnExitProcess(KProcess *process); static void OnTerminateProcess(KProcess *process); static void OnExitThread(KThread *thread); static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_device_address_space.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_select_device_page_table.hpp> namespace ams::kern { class KDeviceAddressSpace final : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject); private: KLightLock m_lock; KDevicePageTable m_table; u64 m_space_address; u64 m_space_size; bool m_is_initialized; public: explicit KDeviceAddressSpace() : m_is_initialized(false) { /* ... */ } Result Initialize(u64 address, u64 size); void Finalize(); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } Result Attach(ams::svc::DeviceName device_name); Result Detach(ams::svc::DeviceName device_name); Result MapByForce(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) { R_RETURN(this->Map(page_table, process_address, size, device_address, option, false)); } Result MapAligned(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) { R_RETURN(this->Map(page_table, process_address, size, device_address, option, true)); } Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address); private: Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned); public: static void Initialize(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_dpc_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern { class KDpcManager { private: static constexpr s32 DpcManagerNormalThreadPriority = 59; static constexpr s32 DpcManagerPreemptionThreadPriority = 63; static_assert(ams::svc::HighestThreadPriority <= DpcManagerNormalThreadPriority && DpcManagerNormalThreadPriority <= ams::svc::LowestThreadPriority); static_assert(ams::svc::HighestThreadPriority <= DpcManagerPreemptionThreadPriority && DpcManagerPreemptionThreadPriority <= ams::svc::LowestThreadPriority); private: static NOINLINE void Initialize(s32 core_id, s32 priority); public: static void Initialize() { const s32 core_id = GetCurrentCoreId(); if (core_id == static_cast<s32>(cpu::NumCores) - 1) { Initialize(core_id, DpcManagerPreemptionThreadPriority); } else { Initialize(core_id, DpcManagerNormalThreadPriority); } } static NOINLINE void HandleDpc(); static void Sync(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_dump_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> namespace ams::kern::KDumpObject { void DumpThread(); void DumpThread(u64 thread_id); void DumpThreadCallStack(); void DumpThreadCallStack(u64 thread_id); void DumpKernelObject(); void DumpHandle(); void DumpHandle(u64 process_id); void DumpKernelMemory(); void DumpMemory(); void DumpMemory(u64 process_id); void DumpKernelPageTable(); void DumpPageTable(); void DumpPageTable(u64 process_id); void DumpKernelCpuUtilization(); void DumpCpuUtilization(); void DumpCpuUtilization(u64 process_id); void DumpProcess(); void DumpProcess(u64 process_id); void DumpPort(); void DumpPort(u64 process_id); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_dynamic_page_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_slab_heap.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_memory_block.hpp> #include <mesosphere/kern_k_page_bitmap.hpp> #include <mesosphere/kern_select_interrupt_manager.hpp> namespace ams::kern { class KDynamicPageManager { public: class PageBuffer { private: u8 m_buffer[PageSize]; }; static_assert(sizeof(PageBuffer) == PageSize); private: KSpinLock m_lock; KPageBitmap m_page_bitmap; size_t m_used; size_t m_peak; size_t m_count; KVirtualAddress m_address; KVirtualAddress m_aligned_address; size_t m_size; public: KDynamicPageManager() : m_lock(), m_page_bitmap(), m_used(), m_peak(), m_count(), m_address(Null<KVirtualAddress>), m_aligned_address(Null<KVirtualAddress>), m_size() { /* ... */ } Result Initialize(KVirtualAddress memory, size_t size, size_t align) { /* We need to have positive size. */ R_UNLESS(size > 0, svc::ResultOutOfMemory()); /* Set addresses. */ m_address = memory; m_aligned_address = util::AlignDown(GetInteger(memory), align); /* Calculate extents. */ const size_t managed_size = m_address + size - m_aligned_address; const size_t overhead_size = util::AlignUp(KPageBitmap::CalculateManagementOverheadSize(managed_size / sizeof(PageBuffer)), sizeof(PageBuffer)); R_UNLESS(overhead_size < size, svc::ResultOutOfMemory()); /* Set tracking fields. */ m_size = util::AlignDown(size - overhead_size, sizeof(PageBuffer)); m_count = m_size / sizeof(PageBuffer); /* Clear the management region. */ u64 *management_ptr = GetPointer<u64>(m_address + size - overhead_size); std::memset(management_ptr, 0, overhead_size); /* Initialize the bitmap. */ const size_t allocatable_region_size = (GetInteger(m_address) + size - overhead_size) - GetInteger(m_aligned_address); MESOSPHERE_ABORT_UNLESS(allocatable_region_size >= sizeof(PageBuffer)); m_page_bitmap.Initialize(management_ptr, allocatable_region_size / sizeof(PageBuffer)); /* Free the pages to the bitmap. */ for (size_t i = 0; i < m_count; i++) { /* Ensure the freed page is all-zero. */ cpu::ClearPageToZero(GetPointer<PageBuffer>(m_address) + i); /* Set the bit for the free page. */ m_page_bitmap.SetBit((GetInteger(m_address) + (i * sizeof(PageBuffer)) - GetInteger(m_aligned_address)) / sizeof(PageBuffer)); } R_SUCCEED(); } constexpr KVirtualAddress GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr size_t GetUsed() const { return m_used; } constexpr size_t GetPeak() const { return m_peak; } constexpr size_t GetCount() const { return m_count; } PageBuffer *Allocate() { /* Take the lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(m_lock); /* Find a random free block. */ ssize_t soffset = m_page_bitmap.FindFreeBlock(true); if (AMS_UNLIKELY(soffset < 0)) { return nullptr; } const size_t offset = static_cast<size_t>(soffset); /* Update our tracking. */ m_page_bitmap.ClearBit(offset); m_peak = std::max(m_peak, (++m_used)); return GetPointer<PageBuffer>(m_aligned_address) + offset; } PageBuffer *Allocate(size_t count) { /* Take the lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(m_lock); /* Find a random free block. */ ssize_t soffset = m_page_bitmap.FindFreeRange(count); if (AMS_UNLIKELY(soffset < 0)) { return nullptr; } const size_t offset = static_cast<size_t>(soffset); /* Update our tracking. */ m_page_bitmap.ClearRange(offset, count); m_used += count; m_peak = std::max(m_peak, m_used); return GetPointer<PageBuffer>(m_aligned_address) + offset; } void Free(PageBuffer *pb) { /* Ensure all pages in the heap are zero. */ cpu::ClearPageToZero(pb); /* Take the lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(m_lock); /* Set the bit for the free page. */ size_t offset = (reinterpret_cast<uintptr_t>(pb) - GetInteger(m_aligned_address)) / sizeof(PageBuffer); m_page_bitmap.SetBit(offset); /* Decrement our used count. */ --m_used; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_dynamic_resource_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_dynamic_slab_heap.hpp> namespace ams::kern { template<typename T, bool ClearNode = false> class KDynamicResourceManager { NON_COPYABLE(KDynamicResourceManager); NON_MOVEABLE(KDynamicResourceManager); public: using DynamicSlabType = KDynamicSlabHeap<T, ClearNode>; private: KDynamicPageManager *m_page_allocator{}; DynamicSlabType *m_slab_heap{}; public: constexpr KDynamicResourceManager() = default; constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return m_slab_heap->GetAddress(); } constexpr ALWAYS_INLINE size_t GetSize() const { return m_slab_heap->GetSize(); } constexpr ALWAYS_INLINE size_t GetUsed() const { return m_slab_heap->GetUsed(); } constexpr ALWAYS_INLINE size_t GetPeak() const { return m_slab_heap->GetPeak(); } constexpr ALWAYS_INLINE size_t GetCount() const { return m_slab_heap->GetCount(); } ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, DynamicSlabType *slab_heap) { m_page_allocator = page_allocator; m_slab_heap = slab_heap; } T *Allocate() const { return m_slab_heap->Allocate(m_page_allocator); } ALWAYS_INLINE void Free(T *t) const { m_slab_heap->Free(t); } }; class KBlockInfoManager : public KDynamicResourceManager<KBlockInfo>{}; class KMemoryBlockSlabManager : public KDynamicResourceManager<KMemoryBlock>{}; using KBlockInfoSlabHeap = typename KBlockInfoManager::DynamicSlabType; using KMemoryBlockSlabHeap = typename KMemoryBlockSlabManager::DynamicSlabType; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_dynamic_slab_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_slab_heap.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_memory_block.hpp> #include <mesosphere/kern_k_dynamic_page_manager.hpp> namespace ams::kern { template<typename T, bool ClearNode = false> class KDynamicSlabHeap : protected impl::KSlabHeapImpl { NON_COPYABLE(KDynamicSlabHeap); NON_MOVEABLE(KDynamicSlabHeap); private: using PageBuffer = KDynamicPageManager::PageBuffer; private: util::Atomic<size_t> m_used{0}; util::Atomic<size_t> m_peak{0}; util::Atomic<size_t> m_count{0}; KVirtualAddress m_address{Null<KVirtualAddress>}; size_t m_size{}; public: constexpr KDynamicSlabHeap() = default; constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return m_address; } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } constexpr ALWAYS_INLINE size_t GetUsed() const { return m_used.Load(); } constexpr ALWAYS_INLINE size_t GetPeak() const { return m_peak.Load(); } constexpr ALWAYS_INLINE size_t GetCount() const { return m_count.Load(); } constexpr ALWAYS_INLINE bool IsInRange(KVirtualAddress addr) const { return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1; } ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, size_t num_objects) { MESOSPHERE_ASSERT(page_allocator != nullptr); /* Initialize members. */ m_address = page_allocator->GetAddress(); m_size = page_allocator->GetSize(); /* Initialize the base allocator. */ KSlabHeapImpl::Initialize(); /* Allocate until we have the correct number of objects. */ while (m_count.Load() < num_objects) { auto *allocated = reinterpret_cast<T *>(page_allocator->Allocate()); MESOSPHERE_ABORT_UNLESS(allocated != nullptr); for (size_t i = 0; i < sizeof(PageBuffer) / sizeof(T); i++) { KSlabHeapImpl::Free(allocated + i); } m_count += sizeof(PageBuffer) / sizeof(T); } } ALWAYS_INLINE T *Allocate(KDynamicPageManager *page_allocator) { T *allocated = static_cast<T *>(KSlabHeapImpl::Allocate()); /* If we successfully allocated and we should clear the node, do so. */ if constexpr (ClearNode) { if (AMS_LIKELY(allocated != nullptr)) { reinterpret_cast<KSlabHeapImpl::Node *>(allocated)->next = nullptr; } } /* If we fail to allocate, try to get a new page from our next allocator. */ if (AMS_UNLIKELY(allocated == nullptr) ) { if (page_allocator != nullptr) { allocated = reinterpret_cast<T *>(page_allocator->Allocate()); if (allocated != nullptr) { /* If we succeeded in getting a page, free the rest to our slab. */ for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) { KSlabHeapImpl::Free(allocated + i); } m_count += sizeof(PageBuffer) / sizeof(T); } } } if (AMS_LIKELY(allocated != nullptr)) { /* Construct the object. */ std::construct_at(allocated); /* Update our tracking. */ const size_t used = ++m_used; size_t peak = m_peak.Load(); while (peak < used) { if (m_peak.CompareExchangeWeak<std::memory_order_relaxed>(peak, used)) { break; } } } return allocated; } ALWAYS_INLINE void Free(T *t) { KSlabHeapImpl::Free(t); --m_used; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_readable_event.hpp> namespace ams::kern { class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList, true> { MESOSPHERE_AUTOOBJECT_TRAITS(KEvent, KAutoObject); private: KReadableEvent m_readable_event; KProcess *m_owner; bool m_initialized; bool m_readable_event_destroyed; public: constexpr explicit KEvent(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList, true>(util::ConstantInitialize), m_readable_event(util::ConstantInitialize), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ } explicit KEvent() : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ } void Initialize(); void Finalize(); bool IsInitialized() const { return m_initialized; } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); } static void PostDestroy(uintptr_t arg); KProcess *GetOwner() const { return m_owner; } KReadableEvent &GetReadableEvent() { return m_readable_event; } void Signal(); void Clear(); ALWAYS_INLINE void OnReadableEventDestroyed() { m_readable_event_destroyed = true; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_event_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KEventInfo : public KSlabAllocated<KEventInfo>, public util::IntrusiveListBaseNode<KEventInfo> { public: struct InfoCreateThread { u32 thread_id; uintptr_t tls_address; }; struct InfoExitProcess { ams::svc::ProcessExitReason reason; }; struct InfoExitThread { ams::svc::ThreadExitReason reason; }; struct InfoException { ams::svc::DebugException exception_type; s32 exception_data_count; uintptr_t exception_address; uintptr_t exception_data[std::max<size_t>(4, cpu::NumCores)]; }; struct InfoSystemCall { s64 tick; s32 id; }; public: ams::svc::DebugEvent event; u32 thread_id; u32 flags; bool is_attached; bool continue_flag; bool ignore_continue; bool close_once; union { InfoCreateThread create_thread; InfoExitProcess exit_process; InfoExitThread exit_thread; InfoException exception; InfoSystemCall system_call; } info; KThread *debug_thread; public: explicit KEventInfo() : is_attached(), continue_flag(), ignore_continue() { /* ... */ } ~KEventInfo() { /* ... */ } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_exception_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_k_exception_context.hpp> namespace ams::kern { using ams::kern::arch::arm64::KExceptionContext; } #else #error "Unknown architecture for KExceptionContext" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_handle_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_interrupt_event.hpp> namespace ams::kern { constexpr ALWAYS_INLINE util::BitPack32 GetHandleBitPack(ams::svc::Handle handle) { return util::BitPack32{handle}; } class KProcess; class KThread; class KHandleTable { NON_COPYABLE(KHandleTable); NON_MOVEABLE(KHandleTable); public: static constexpr size_t MaxTableSize = 1024; private: using HandleRawValue = util::BitPack32::Field<0, BITSIZEOF(u32), u32>; using HandleEncoded = util::BitPack32::Field<0, BITSIZEOF(ams::svc::Handle), ams::svc::Handle>; using HandleIndex = util::BitPack32::Field<0, 15, u16>; using HandleLinearId = util::BitPack32::Field<HandleIndex::Next, 15, u16>; using HandleReserved = util::BitPack32::Field<HandleLinearId::Next, 2, u32>; static constexpr u16 MinLinearId = 1; static constexpr u16 MaxLinearId = util::BitPack32{std::numeric_limits<u32>::max()}.Get<HandleLinearId>(); static constexpr ALWAYS_INLINE ams::svc::Handle EncodeHandle(u16 index, u16 linear_id) { util::BitPack32 pack = {0}; pack.Set<HandleIndex>(index); pack.Set<HandleLinearId>(linear_id); pack.Set<HandleReserved>(0); return pack.Get<HandleEncoded>(); } union EntryInfo { u16 linear_id; s16 next_free_index; constexpr ALWAYS_INLINE u16 GetLinearId() const { return linear_id; } constexpr ALWAYS_INLINE s32 GetNextFreeIndex() const { return next_free_index; } }; private: EntryInfo m_entry_infos[MaxTableSize]; KAutoObject *m_objects[MaxTableSize]; mutable KSpinLock m_lock; s32 m_free_head_index; u16 m_table_size; u16 m_max_count; u16 m_next_linear_id; u16 m_count; public: constexpr explicit KHandleTable(util::ConstantInitializeTag) : m_entry_infos(), m_objects(), m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(), m_count() { /* ... */ } explicit KHandleTable() : m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(), m_count() { MESOSPHERE_ASSERT_THIS(); } MESOSPHERE_NOINLINE_IF_DEBUG Result Initialize(s32 size) { MESOSPHERE_ASSERT_THIS(); /* Check that the table size is valid. */ R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory()); /* Lock. */ KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); /* Initialize all fields. */ m_max_count = 0; m_table_size = (size <= 0) ? MaxTableSize : size; m_next_linear_id = MinLinearId; m_count = 0; m_free_head_index = -1; /* Free all entries. */ for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { m_objects[i] = nullptr; m_entry_infos[i].next_free_index = i - 1; m_free_head_index = i; } R_SUCCEED(); } constexpr ALWAYS_INLINE size_t GetTableSize() const { return m_table_size; } constexpr ALWAYS_INLINE size_t GetCount() const { return m_count; } constexpr ALWAYS_INLINE size_t GetMaxCount() const { return m_max_count; } MESOSPHERE_NOINLINE_IF_DEBUG void Finalize(); MESOSPHERE_NOINLINE_IF_DEBUG bool Remove(ams::svc::Handle handle); template<typename T = KAutoObject> ALWAYS_INLINE KScopedAutoObject<T> GetObjectWithoutPseudoHandle(ams::svc::Handle handle) const { /* Lock and look up in table. */ KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); if constexpr (std::is_same<T, KAutoObject>::value) { return this->GetObjectImpl(handle); } else { if (auto *obj = this->GetObjectImpl(handle); AMS_LIKELY(obj != nullptr)) { return obj->DynamicCast<T*>(); } else { return nullptr; } } } template<typename T = KAutoObject> ALWAYS_INLINE KScopedAutoObject<T> GetObject(ams::svc::Handle handle) const { MESOSPHERE_ASSERT_THIS(); /* Handle pseudo-handles. */ if constexpr (std::derived_from<KProcess, T>) { if (handle == ams::svc::PseudoHandle::CurrentProcess) { auto * const cur_process = GetCurrentProcessPointer(); AMS_ASSUME(cur_process != nullptr); return cur_process; } } else if constexpr (std::derived_from<KThread, T>) { if (handle == ams::svc::PseudoHandle::CurrentThread) { auto * const cur_thread = GetCurrentThreadPointer(); AMS_ASSUME(cur_thread != nullptr); return cur_thread; } } return this->template GetObjectWithoutPseudoHandle<T>(handle); } KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(ams::svc::Handle handle) const { /* Lock and look up in table. */ KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); KAutoObject *obj = this->GetObjectImpl(handle); if (AMS_LIKELY(obj != nullptr)) { if (AMS_UNLIKELY(obj->DynamicCast<KInterruptEvent *>() != nullptr)) { return nullptr; } } return obj; } ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectForIpc(ams::svc::Handle handle, KThread *cur_thread) const { /* Handle pseudo-handles. */ AMS_ASSUME(cur_thread != nullptr); if (handle == ams::svc::PseudoHandle::CurrentProcess) { auto * const cur_process = static_cast<KAutoObject *>(static_cast<void *>(cur_thread->GetOwnerProcess())); AMS_ASSUME(cur_process != nullptr); return cur_process; } if (handle == ams::svc::PseudoHandle::CurrentThread) { return static_cast<KAutoObject *>(cur_thread); } return GetObjectForIpcWithoutPseudoHandle(handle); } ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectByIndex(ams::svc::Handle *out_handle, size_t index) const { MESOSPHERE_ASSERT_THIS(); KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); return this->GetObjectByIndexImpl(out_handle, index); } MESOSPHERE_NOINLINE_IF_DEBUG Result Reserve(ams::svc::Handle *out_handle); MESOSPHERE_NOINLINE_IF_DEBUG void Unreserve(ams::svc::Handle handle); MESOSPHERE_NOINLINE_IF_DEBUG Result Add(ams::svc::Handle *out_handle, KAutoObject *obj); MESOSPHERE_NOINLINE_IF_DEBUG void Register(ams::svc::Handle handle, KAutoObject *obj); template<typename T> ALWAYS_INLINE bool GetMultipleObjects(T **out, const ams::svc::Handle *handles, size_t num_handles) const { /* Try to convert and open all the handles. */ size_t num_opened; { /* Lock the table. */ KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); for (num_opened = 0; num_opened < num_handles; num_opened++) { /* Get the current handle. */ const auto cur_handle = handles[num_opened]; /* Get the object for the current handle. */ KAutoObject *cur_object = this->GetObjectImpl(cur_handle); if (AMS_UNLIKELY(cur_object == nullptr)) { break; } /* Cast the current object to the desired type. */ T *cur_t = cur_object->DynamicCast<T*>(); if (AMS_UNLIKELY(cur_t == nullptr)) { break; } /* Open a reference to the current object. */ cur_t->Open(); out[num_opened] = cur_t; } } /* If we converted every object, succeed. */ if (AMS_LIKELY(num_opened == num_handles)) { return true; } /* If we didn't convert entry object, close the ones we opened. */ for (size_t i = 0; i < num_opened; i++) { out[i]->Close(); } return false; } private: constexpr ALWAYS_INLINE s32 AllocateEntry() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(m_count < m_table_size); const auto index = m_free_head_index; m_free_head_index = m_entry_infos[index].GetNextFreeIndex(); m_max_count = std::max(m_max_count, ++m_count); return index; } constexpr ALWAYS_INLINE void FreeEntry(s32 index) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(m_count > 0); m_objects[index] = nullptr; m_entry_infos[index].next_free_index = m_free_head_index; m_free_head_index = index; --m_count; } constexpr ALWAYS_INLINE u16 AllocateLinearId() { const u16 id = m_next_linear_id++; if (m_next_linear_id > MaxLinearId) { m_next_linear_id = MinLinearId; } return id; } constexpr ALWAYS_INLINE bool IsValidHandle(ams::svc::Handle handle) const { MESOSPHERE_ASSERT_THIS(); /* Unpack the handle. */ const auto handle_pack = GetHandleBitPack(handle); const auto raw_value = handle_pack.Get<HandleRawValue>(); const auto index = handle_pack.Get<HandleIndex>(); const auto linear_id = handle_pack.Get<HandleLinearId>(); const auto reserved = handle_pack.Get<HandleReserved>(); MESOSPHERE_ASSERT(reserved == 0); MESOSPHERE_UNUSED(reserved); /* Validate our indexing information. */ if (AMS_UNLIKELY(raw_value == 0)) { return false; } if (AMS_UNLIKELY(linear_id == 0)) { return false; } if (AMS_UNLIKELY(index >= m_table_size)) { return false; } /* Check that there's an object, and our serial id is correct. */ if (AMS_UNLIKELY(m_objects[index] == nullptr)) { return false; } if (AMS_UNLIKELY(m_entry_infos[index].GetLinearId() != linear_id)) { return false; } return true; } constexpr MESOSPHERE_NOINLINE_IF_DEBUG KAutoObject *GetObjectImpl(ams::svc::Handle handle) const { MESOSPHERE_ASSERT_THIS(); /* Handles must not have reserved bits set. */ const auto handle_pack = GetHandleBitPack(handle); if (AMS_UNLIKELY(handle_pack.Get<HandleReserved>() != 0)) { return nullptr; } if (AMS_LIKELY(this->IsValidHandle(handle))) { return m_objects[handle_pack.Get<HandleIndex>()]; } else { return nullptr; } } constexpr ALWAYS_INLINE KAutoObject *GetObjectByIndexImpl(ams::svc::Handle *out_handle, size_t index) const { MESOSPHERE_ASSERT_THIS(); /* Index must be in bounds. */ if (AMS_UNLIKELY(index >= m_table_size)) { return nullptr; } /* Ensure entry has an object. */ if (KAutoObject *obj = m_objects[index]; obj != nullptr) { *out_handle = EncodeHandle(index, m_entry_infos[index].GetLinearId()); return obj; } else { return nullptr; } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_hardware_timer_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_timer_task.hpp> #include <mesosphere/kern_select_interrupt_manager.hpp> namespace ams::kern { class KHardwareTimerBase { private: using TimerTaskTree = util::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>; private: KSpinLock m_lock; TimerTaskTree m_task_tree; KTimerTask *m_next_task; public: constexpr ALWAYS_INLINE KHardwareTimerBase() : m_lock(), m_task_tree(), m_next_task(nullptr) { /* ... */ } private: ALWAYS_INLINE void RemoveTaskFromTree(KTimerTask *task) { /* Erase from the tree. */ auto it = m_task_tree.erase(m_task_tree.iterator_to(*task)); /* Clear the task's scheduled time. */ task->SetTime(0); /* Update our next task if relevant. */ if (m_next_task == task) { m_next_task = (it != m_task_tree.end()) ? std::addressof(*it) : nullptr; } } public: NOINLINE void CancelTask(KTimerTask *task) { KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); if (const s64 task_time = task->GetTime(); task_time > 0) { this->RemoveTaskFromTree(task); } } protected: ALWAYS_INLINE KSpinLock &GetLock() { return m_lock; } ALWAYS_INLINE s64 DoInterruptTaskImpl(s64 cur_time) { /* We want to handle all tasks, returning the next time that a task is scheduled. */ while (true) { /* Get the next task. If there isn't one, return 0. */ KTimerTask *task = m_next_task; if (task == nullptr) { return 0; } /* If the task needs to be done in the future, do it in the future and not now. */ if (const s64 task_time = task->GetTime(); task_time > cur_time) { return task_time; } /* Remove the task from the tree of tasks, and update our next task. */ this->RemoveTaskFromTree(task); /* Handle the task. */ task->OnTimer(); } } ALWAYS_INLINE bool RegisterAbsoluteTaskImpl(KTimerTask *task, s64 task_time) { MESOSPHERE_ASSERT(task_time > 0); /* Set the task's time, and insert it into our tree. */ task->SetTime(task_time); m_task_tree.insert(*task); /* Update our next task if relevant. */ if (m_next_task != nullptr && m_next_task->GetTime() <= task_time) { return false; } m_next_task = task; return true; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_initial_process_reader.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_address_space_info.hpp> #include <mesosphere/kern_select_page_table.hpp> namespace ams::kern { class KInitialProcessHeader { private: static constexpr u32 Magic = util::FourCC<'K','I','P','1'>::Code; private: u32 m_magic; u8 m_name[12]; u64 m_program_id; u32 m_version; u8 m_priority; u8 m_ideal_core_id; u8 m_1E; u8 m_flags; u32 m_rx_address; u32 m_rx_size; u32 m_rx_compressed_size; u32 m_affinity_mask; u32 m_ro_address; u32 m_ro_size; u32 m_ro_compressed_size; u32 m_stack_size; u32 m_rw_address; u32 m_rw_size; u32 m_rw_compressed_size; u32 m_4C; u32 m_bss_address; u32 m_bss_size; u32 m_pad[(0x80 - 0x58) / sizeof(u32)]; u32 m_capabilities[0x80 / sizeof(u32)]; public: constexpr bool IsValid() const { return m_magic == Magic; } constexpr void GetName(char *dst, size_t size) const { std::memset(dst, 0, size); std::memcpy(dst, m_name, std::min(sizeof(m_name), size)); } constexpr const u32 *GetCapabilities() const { return m_capabilities; } constexpr size_t GetNumCapabilities() const { return util::size(m_capabilities); } constexpr u64 GetProgramId() const { return m_program_id; } constexpr u32 GetVersion() const { return m_version; } constexpr u8 GetPriority() const { return m_priority; } constexpr u8 GetIdealCoreId() const { return m_ideal_core_id; } constexpr bool IsRxCompressed() const { return (m_flags & (1 << 0)); } constexpr bool IsRoCompressed() const { return (m_flags & (1 << 1)); } constexpr bool IsRwCompressed() const { return (m_flags & (1 << 2)); } constexpr bool Is64Bit() const { return (m_flags & (1 << 3)); } constexpr bool Is64BitAddressSpace() const { return (m_flags & (1 << 4)); } constexpr bool UsesSecureMemory() const { return (m_flags & (1 << 5)); } constexpr bool IsImmortal() const { return (m_flags & (1 << 6)); } constexpr u32 GetRxAddress() const { return m_rx_address; } constexpr u32 GetRxSize() const { return m_rx_size; } constexpr u32 GetRxCompressedSize() const { return m_rx_compressed_size; } constexpr u32 GetRoAddress() const { return m_ro_address; } constexpr u32 GetRoSize() const { return m_ro_size; } constexpr u32 GetRoCompressedSize() const { return m_ro_compressed_size; } constexpr u32 GetRwAddress() const { return m_rw_address; } constexpr u32 GetRwSize() const { return m_rw_size; } constexpr u32 GetRwCompressedSize() const { return m_rw_compressed_size; } constexpr u32 GetBssAddress() const { return m_bss_address; } constexpr u32 GetBssSize() const { return m_bss_size; } constexpr u32 GetAffinityMask() const { return m_affinity_mask; } constexpr u32 GetStackSize() const { return m_stack_size; } }; static_assert(sizeof(KInitialProcessHeader) == 0x100); class KInitialProcessReader { private: KInitialProcessHeader m_kip_header; public: constexpr KInitialProcessReader() : m_kip_header() { /* ... */ } constexpr const u32 *GetCapabilities() const { return m_kip_header.GetCapabilities(); } constexpr size_t GetNumCapabilities() const { return m_kip_header.GetNumCapabilities(); } constexpr size_t GetBinarySize() const { return m_kip_header.GetRxCompressedSize() + m_kip_header.GetRoCompressedSize() + m_kip_header.GetRwCompressedSize(); } constexpr size_t GetSize() const { if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size != 0) { return util::AlignUp(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize); } else { return util::AlignUp(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize); } } constexpr u8 GetPriority() const { return m_kip_header.GetPriority(); } constexpr u8 GetIdealCoreId() const { return m_kip_header.GetIdealCoreId(); } constexpr u32 GetAffinityMask() const { return m_kip_header.GetAffinityMask(); } constexpr u32 GetStackSize() const { return m_kip_header.GetStackSize(); } constexpr bool Is64Bit() const { return m_kip_header.Is64Bit(); } constexpr bool Is64BitAddressSpace() const { return m_kip_header.Is64BitAddressSpace(); } constexpr bool UsesSecureMemory() const { return m_kip_header.UsesSecureMemory(); } constexpr bool IsImmortal() const { return m_kip_header.IsImmortal(); } KVirtualAddress Attach(KVirtualAddress bin) { /* Copy the header. */ m_kip_header = *GetPointer<const KInitialProcessHeader>(bin); /* Check that it's valid. */ if (m_kip_header.IsValid()) { return bin + sizeof(KInitialProcessHeader); } else { return Null<KVirtualAddress>; } } Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const; void Load(const KPageGroup &pg, KVirtualAddress data) const; Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_interrupt_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_readable_event.hpp> #include <mesosphere/kern_k_interrupt_task.hpp> namespace ams::kern { class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>, public KInterruptTask { MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent); private: s32 m_interrupt_id; s32 m_core_id; bool m_is_initialized; public: constexpr explicit KInterruptEvent(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>(util::ConstantInitialize), m_interrupt_id(-1), m_core_id(-1), m_is_initialized(false) { /* ... */ } explicit KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ } Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type); void Finalize(); Result Reset(); void Clear() { MESOSPHERE_ASSERT_THIS(); /* Try to perform a reset, ignoring whether it succeeds. */ static_cast<void>(this->Reset()); } bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } constexpr s32 GetInterruptId() const { return m_interrupt_id; } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override; virtual void DoTask() override; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::kern { class KInterruptTask; class KInterruptHandler { public: virtual KInterruptTask *OnInterrupt(s32 interrupt_id) = 0; }; class KInterruptTask : public KInterruptHandler { private: KInterruptTask *m_next_task; public: constexpr ALWAYS_INLINE KInterruptTask() : m_next_task(nullptr) { /* ... */ } constexpr ALWAYS_INLINE KInterruptTask *GetNextTask() const { return m_next_task; } constexpr ALWAYS_INLINE void SetNextTask(KInterruptTask *t) { m_next_task = t; } virtual void DoTask() = 0; }; static ALWAYS_INLINE KInterruptTask *GetDummyInterruptTask() { return reinterpret_cast<KInterruptTask *>(1); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_interrupt_task_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_k_interrupt_task.hpp> namespace ams::kern { class KThread; class KInterruptTaskManager { private: class TaskQueue { private: KInterruptTask *m_head; KInterruptTask *m_tail; public: constexpr ALWAYS_INLINE TaskQueue() : m_head(nullptr), m_tail(nullptr) { /* ... */ } constexpr ALWAYS_INLINE KInterruptTask *GetHead() { return m_head; } constexpr ALWAYS_INLINE bool IsEmpty() const { return m_head == nullptr; } constexpr ALWAYS_INLINE void Clear() { m_head = nullptr; m_tail = nullptr; } void Enqueue(KInterruptTask *task); void Dequeue(); }; private: TaskQueue m_task_queue; s64 m_cpu_time; public: constexpr KInterruptTaskManager() : m_task_queue(), m_cpu_time(0) { /* ... */ } constexpr ALWAYS_INLINE s64 GetCpuTime() const { return m_cpu_time; } void EnqueueTask(KInterruptTask *task); void DoTasks(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_io_pool.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_io_region.hpp> namespace ams::kern { class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject); private: using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>; private: KLightLock m_lock; IoRegionTree m_io_region_tree; ams::svc::IoPoolType m_pool_type; bool m_is_initialized; public: static bool IsValidIoPoolType(ams::svc::IoPoolType pool_type); public: explicit KIoPool() : m_is_initialized(false) { /* ... */ } Result Initialize(ams::svc::IoPoolType pool_type); void Finalize(); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } Result AddIoRegion(KIoRegion *region); void RemoveIoRegion(KIoRegion *region); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_io_region.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KProcess; class KIoPool; class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList>, public util::IntrusiveRedBlackTreeBaseNode<KIoRegion> { MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject); private: friend class KProcess; friend class KIoPool; public: using RedBlackKeyType = KPhysicalAddress; static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; } static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); } template<typename T> requires (std::same_as<T, KIoRegion> || std::same_as<T, RedBlackKeyType>) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) { const RedBlackKeyType lval = GetRedBlackKey(lhs); const RedBlackKeyType rval = GetRedBlackKey(rhs); if (lval < rval) { return -1; } else if (lval == rval) { return 0; } else { return 1; } } private: KLightLock m_lock; KIoPool *m_pool; KPhysicalAddress m_physical_address; size_t m_size; ams::svc::MemoryMapping m_mapping; ams::svc::MemoryPermission m_permission; bool m_is_initialized; bool m_is_mapped; util::IntrusiveListNode m_process_list_node; public: explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ } Result Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm); void Finalize(); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Unmap(KProcessAddress address, size_t size); constexpr bool Overlaps(KPhysicalAddress address, size_t size) const { return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1); } constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } constexpr uintptr_t GetHint() const { /* TODO: Is this architecture specific? */ if (m_size >= 2_MB) { return GetInteger(m_physical_address) & (2_MB - 1); } else if (m_size >= 64_KB) { return GetInteger(m_physical_address) & (64_KB - 1); } else if (m_size >= 4_KB) { return GetInteger(m_physical_address) & (4_KB - 1); } else { return 0; } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_light_client_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> namespace ams::kern { class KLightSession; class KLightClientSession final : public KAutoObject { MESOSPHERE_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject); private: KLightSession *m_parent; public: explicit KLightClientSession() { /* ... */ } void Initialize(KLightSession *parent) { /* Set member variables. */ m_parent = parent; } virtual void Destroy() override; constexpr const KLightSession *GetParent() const { return m_parent; } Result SendSyncRequest(u32 *data); void OnServerClosed(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_light_condition_variable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_k_thread_queue.hpp> #include <mesosphere/kern_k_scoped_scheduler_lock_and_sleep.hpp> namespace ams::kern { class KLightConditionVariable { private: KThread::WaiterList m_wait_list; public: constexpr explicit ALWAYS_INLINE KLightConditionVariable(util::ConstantInitializeTag) : m_wait_list() { /* ... */ } explicit ALWAYS_INLINE KLightConditionVariable() { /* ... */ } public: void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true); void Broadcast(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_light_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_current_context.hpp> #include <mesosphere/kern_k_scoped_lock.hpp> namespace ams::kern { class KLightLock { private: util::Atomic<uintptr_t> m_tag; public: constexpr ALWAYS_INLINE KLightLock() : m_tag(0) { /* ... */ } void Lock() { MESOSPHERE_ASSERT_THIS(); const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()); while (true) { uintptr_t old_tag = m_tag.Load<std::memory_order_relaxed>(); while (!m_tag.CompareExchangeWeak<std::memory_order_acquire>(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1))) { /* ... */ } if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) { break; } } } ALWAYS_INLINE void Unlock() { MESOSPHERE_ASSERT_THIS(); const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()); uintptr_t expected = cur_thread; if (!m_tag.CompareExchangeStrong<std::memory_order_release>(expected, 0)) { this->UnlockSlowPath(cur_thread); } } NOINLINE bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread); NOINLINE void UnlockSlowPath(uintptr_t cur_thread); ALWAYS_INLINE bool IsLocked() const { return m_tag.Load() != 0; } ALWAYS_INLINE bool IsLockedByCurrentThread() const { return (m_tag.Load() | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()) | 0x1ul); } }; using KScopedLightLock = KScopedLock<KLightLock>; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_light_server_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_thread_queue.hpp> namespace ams::kern { class KLightSession; class KLightServerSession final : public KAutoObject, public util::IntrusiveListBaseNode<KLightServerSession> { MESOSPHERE_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject); private: KLightSession *m_parent; KThread::WaiterList m_request_list; KThread *m_current_request; u64 m_server_thread_id; KThread *m_server_thread; public: explicit KLightServerSession() : m_current_request(nullptr), m_server_thread_id(std::numeric_limits<u64>::max()), m_server_thread() { /* ... */ } void Initialize(KLightSession *parent) { /* Set member variables. */ m_parent = parent; } virtual void Destroy() override; constexpr const KLightSession *GetParent() const { return m_parent; } Result OnRequest(KThread *request_thread); Result ReplyAndReceive(u32 *data); void OnClientClosed(); private: void CleanupRequests(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_light_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_light_server_session.hpp> #include <mesosphere/kern_k_light_client_session.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KClientPort; class KProcess; class KLightSession final : public KAutoObjectWithSlabHeapAndContainer<KLightSession, KAutoObjectWithList, true> { MESOSPHERE_AUTOOBJECT_TRAITS(KLightSession, KAutoObject); private: enum class State : u8 { Invalid = 0, Normal = 1, ClientClosed = 2, ServerClosed = 3, }; public: static constexpr size_t DataSize = sizeof(u32) * 7; static constexpr u32 ReplyFlag = (1u << (BITSIZEOF(u32) - 1)); private: KLightServerSession m_server; KLightClientSession m_client; State m_state; KClientPort *m_port; uintptr_t m_name; KProcess *m_process; bool m_initialized; public: explicit KLightSession() : m_state(State::Invalid), m_process(), m_initialized() { /* ... */ } void Initialize(KClientPort *client_port, uintptr_t name); void Finalize(); bool IsInitialized() const { return m_initialized; } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_process); } static void PostDestroy(uintptr_t arg); void OnServerClosed(); void OnClientClosed(); bool IsServerClosed() const { return m_state != State::Normal; } bool IsClientClosed() const { return m_state != State::Normal; } Result OnRequest(KThread *request_thread) { R_RETURN(m_server.OnRequest(request_thread)); } KLightClientSession &GetClientSession() { return m_client; } KLightServerSession &GetServerSession() { return m_server; } const KLightClientSession &GetClientSession() const { return m_client; } const KLightServerSession &GetServerSession() const { return m_server; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_block.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { enum KMemoryState : u32 { KMemoryState_None = 0, KMemoryState_Mask = 0xFF, KMemoryState_All = ~KMemoryState_None, KMemoryState_FlagCanReprotect = (1 << 8), KMemoryState_FlagCanDebug = (1 << 9), KMemoryState_FlagCanUseIpc = (1 << 10), KMemoryState_FlagCanUseNonDeviceIpc = (1 << 11), KMemoryState_FlagCanUseNonSecureIpc = (1 << 12), KMemoryState_FlagMapped = (1 << 13), KMemoryState_FlagCode = (1 << 14), KMemoryState_FlagCanAlias = (1 << 15), KMemoryState_FlagCanCodeAlias = (1 << 16), KMemoryState_FlagCanTransfer = (1 << 17), KMemoryState_FlagCanQueryPhysical = (1 << 18), KMemoryState_FlagCanDeviceMap = (1 << 19), KMemoryState_FlagCanAlignedDeviceMap = (1 << 20), KMemoryState_FlagCanIpcUserBuffer = (1 << 21), KMemoryState_FlagReferenceCounted = (1 << 22), KMemoryState_FlagCanMapProcess = (1 << 23), KMemoryState_FlagCanChangeAttribute = (1 << 24), KMemoryState_FlagCanCodeMemory = (1 << 25), KMemoryState_FlagLinearMapped = (1 << 26), KMemoryState_FlagCanPermissionLock = (1 << 27), KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagMapped | KMemoryState_FlagCanAlias | KMemoryState_FlagCanTransfer | KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanIpcUserBuffer | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanChangeAttribute | KMemoryState_FlagLinearMapped, KMemoryState_FlagsCode = KMemoryState_FlagCanDebug | KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagMapped | KMemoryState_FlagCode | KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped, KMemoryState_FlagsMisc = KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagLinearMapped, KMemoryState_Free = ams::svc::MemoryState_Free, KMemoryState_IoMemory = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap, KMemoryState_IoRegister = ams::svc::MemoryState_Io | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap, KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagCanQueryPhysical, KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess, KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory | KMemoryState_FlagCanPermissionLock, KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory, KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped, /* KMemoryState_Alias was removed after 1.0.0. */ KMemoryState_AliasCode = ams::svc::MemoryState_AliasCode | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias, KMemoryState_AliasCodeData = ams::svc::MemoryState_AliasCodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias | KMemoryState_FlagCanCodeMemory | KMemoryState_FlagCanPermissionLock, KMemoryState_Ipc = ams::svc::MemoryState_Ipc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagLinearMapped, KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute | KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_SharedTransfered = ams::svc::MemoryState_SharedTransfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_SharedCode = ams::svc::MemoryState_SharedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_Inaccessible = ams::svc::MemoryState_Inaccessible, KMemoryState_NonSecureIpc = ams::svc::MemoryState_NonSecureIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_NonDeviceIpc = ams::svc::MemoryState_NonDeviceIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanUseNonDeviceIpc, KMemoryState_Kernel = ams::svc::MemoryState_Kernel, KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped, KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped, KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped, KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc, }; #if 1 static_assert(KMemoryState_Free == 0x00000000); static_assert(KMemoryState_IoMemory == 0x00182001); static_assert(KMemoryState_IoRegister == 0x00180001); static_assert(KMemoryState_Static == 0x00040002); static_assert(KMemoryState_Code == 0x04DC7E03); static_assert(KMemoryState_CodeData == 0x0FFEBD04); static_assert(KMemoryState_Normal == 0x077EBD05); static_assert(KMemoryState_Shared == 0x04402006); static_assert(KMemoryState_AliasCode == 0x04DD7E08); static_assert(KMemoryState_AliasCodeData == 0x0FFFBD09); static_assert(KMemoryState_Ipc == 0x045C3C0A); static_assert(KMemoryState_Stack == 0x045C3C0B); static_assert(KMemoryState_ThreadLocal == 0x0400000C); static_assert(KMemoryState_Transfered == 0x055C3C0D); static_assert(KMemoryState_SharedTransfered == 0x045C380E); static_assert(KMemoryState_SharedCode == 0x0440380F); static_assert(KMemoryState_Inaccessible == 0x00000010); static_assert(KMemoryState_NonSecureIpc == 0x045C3811); static_assert(KMemoryState_NonDeviceIpc == 0x044C2812); static_assert(KMemoryState_Kernel == 0x00000013); static_assert(KMemoryState_GeneratedCode == 0x04402214); static_assert(KMemoryState_CodeOut == 0x04402015); static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */ static_assert(KMemoryState_Insecure == 0x055C3817); #endif enum KMemoryPermission : u8 { KMemoryPermission_None = 0, KMemoryPermission_All = static_cast<u8>(~KMemoryPermission_None), KMemoryPermission_KernelShift = 3, KMemoryPermission_KernelRead = ams::svc::MemoryPermission_Read << KMemoryPermission_KernelShift, KMemoryPermission_KernelWrite = ams::svc::MemoryPermission_Write << KMemoryPermission_KernelShift, KMemoryPermission_KernelExecute = ams::svc::MemoryPermission_Execute << KMemoryPermission_KernelShift, KMemoryPermission_NotMapped = (1 << (2 * KMemoryPermission_KernelShift)), KMemoryPermission_KernelReadWrite = KMemoryPermission_KernelRead | KMemoryPermission_KernelWrite, KMemoryPermission_KernelReadExecute = KMemoryPermission_KernelRead | KMemoryPermission_KernelExecute, KMemoryPermission_UserRead = ams::svc::MemoryPermission_Read | KMemoryPermission_KernelRead, KMemoryPermission_UserWrite = ams::svc::MemoryPermission_Write | KMemoryPermission_KernelWrite, KMemoryPermission_UserExecute = ams::svc::MemoryPermission_Execute, KMemoryPermission_UserReadWrite = KMemoryPermission_UserRead | KMemoryPermission_UserWrite, KMemoryPermission_UserReadExecute = KMemoryPermission_UserRead | KMemoryPermission_UserExecute, KMemoryPermission_UserMask = ams::svc::MemoryPermission_Read | ams::svc::MemoryPermission_Write | ams::svc::MemoryPermission_Execute, KMemoryPermission_IpcLockChangeMask = KMemoryPermission_NotMapped | KMemoryPermission_UserReadWrite, }; constexpr KMemoryPermission ConvertToKMemoryPermission(ams::svc::MemoryPermission perm) { return static_cast<KMemoryPermission>((util::ToUnderlying(perm) & KMemoryPermission_UserMask) | KMemoryPermission_KernelRead | ((util::ToUnderlying(perm) & ams::svc::MemoryPermission_Write) ? KMemoryPermission_KernelWrite : KMemoryPermission_None) | (perm == ams::svc::MemoryPermission_None ? KMemoryPermission_NotMapped : KMemoryPermission_None)); } enum KMemoryAttribute : u8 { KMemoryAttribute_None = 0x00, KMemoryAttribute_All = 0xFF, KMemoryAttribute_UserMask = KMemoryAttribute_All, KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked, KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked, KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared, KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached, KMemoryAttribute_PermissionLocked = ams::svc::MemoryAttribute_PermissionLocked, KMemoryAttribute_SetMask = KMemoryAttribute_Uncached | KMemoryAttribute_PermissionLocked, }; enum KMemoryBlockDisableMergeAttribute : u8 { KMemoryBlockDisableMergeAttribute_None = 0, KMemoryBlockDisableMergeAttribute_Normal = (1u << 0), KMemoryBlockDisableMergeAttribute_DeviceLeft = (1u << 1), KMemoryBlockDisableMergeAttribute_IpcLeft = (1u << 2), KMemoryBlockDisableMergeAttribute_Locked = (1u << 3), /* ... */ KMemoryBlockDisableMergeAttribute_DeviceRight = (1u << 5), KMemoryBlockDisableMergeAttribute_AllLeft = KMemoryBlockDisableMergeAttribute_Normal | KMemoryBlockDisableMergeAttribute_DeviceLeft | KMemoryBlockDisableMergeAttribute_IpcLeft | KMemoryBlockDisableMergeAttribute_Locked, KMemoryBlockDisableMergeAttribute_AllRight = KMemoryBlockDisableMergeAttribute_DeviceRight, }; struct KMemoryInfo { uintptr_t m_address; size_t m_size; KMemoryState m_state; u16 m_device_disable_merge_left_count; u16 m_device_disable_merge_right_count; u16 m_ipc_lock_count; u16 m_device_use_count; u16 m_ipc_disable_merge_count; KMemoryPermission m_permission; KMemoryAttribute m_attribute; KMemoryPermission m_original_permission; KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; constexpr ams::svc::MemoryInfo GetSvcMemoryInfo() const { return { .base_address = m_address, .size = m_size, .state = static_cast<ams::svc::MemoryState>(m_state & KMemoryState_Mask), .attribute = static_cast<ams::svc::MemoryAttribute>(m_attribute & KMemoryAttribute_UserMask), .permission = static_cast<ams::svc::MemoryPermission>(m_permission & KMemoryPermission_UserMask), .ipc_count = m_ipc_lock_count, .device_count = m_device_use_count, .padding = {}, }; } constexpr uintptr_t GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr size_t GetNumPages() const { return this->GetSize() / PageSize; } constexpr uintptr_t GetEndAddress() const { return this->GetAddress() + this->GetSize(); } constexpr uintptr_t GetLastAddress() const { return this->GetEndAddress() - 1; } constexpr u16 GetIpcLockCount() const { return m_ipc_lock_count; } constexpr u16 GetIpcDisableMergeCount() const { return m_ipc_disable_merge_count; } constexpr KMemoryState GetState() const { return m_state; } constexpr ams::svc::MemoryState GetSvcState() const { return static_cast<ams::svc::MemoryState>(m_state & KMemoryState_Mask); } constexpr KMemoryPermission GetPermission() const { return m_permission; } constexpr KMemoryPermission GetOriginalPermission() const { return m_original_permission; } constexpr KMemoryAttribute GetAttribute() const { return m_attribute; } constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const { return m_disable_merge_attribute; } }; class KMemoryBlock : public util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> { private: KMemoryPermission m_permission; KMemoryPermission m_original_permission; KMemoryAttribute m_attribute; KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; KProcessAddress m_address; u32 m_num_pages; KMemoryState m_memory_state; u16 m_ipc_lock_count; u16 m_ipc_disable_merge_count; u16 m_device_use_count; u16 m_device_disable_merge_left_count; u16 m_device_disable_merge_right_count; public: static constexpr ALWAYS_INLINE int Compare(const KMemoryBlock &lhs, const KMemoryBlock &rhs) { if (lhs.GetAddress() < rhs.GetAddress()) { return -1; } else if (lhs.GetAddress() <= rhs.GetLastAddress()) { return 0; } else { return 1; } } public: constexpr KProcessAddress GetAddress() const { return m_address; } constexpr size_t GetNumPages() const { return m_num_pages; } constexpr size_t GetSize() const { return this->GetNumPages() * PageSize; } constexpr KProcessAddress GetEndAddress() const { return this->GetAddress() + this->GetSize(); } constexpr KProcessAddress GetLastAddress() const { return this->GetEndAddress() - 1; } constexpr KMemoryState GetState() const { return m_memory_state; } constexpr u16 GetIpcLockCount() const { return m_ipc_lock_count; } constexpr u16 GetIpcDisableMergeCount() const { return m_ipc_disable_merge_count; } constexpr u16 GetDeviceUseCount() const { return m_device_use_count; } constexpr KMemoryPermission GetPermission() const { return m_permission; } constexpr KMemoryPermission GetOriginalPermission() const { return m_original_permission; } constexpr KMemoryAttribute GetAttribute() const { return m_attribute; } constexpr KMemoryInfo GetMemoryInfo() const { return { .m_address = GetInteger(this->GetAddress()), .m_size = this->GetSize(), .m_state = m_memory_state, .m_device_disable_merge_left_count = m_device_disable_merge_left_count, .m_device_disable_merge_right_count = m_device_disable_merge_right_count, .m_ipc_lock_count = m_ipc_lock_count, .m_device_use_count = m_device_use_count, .m_ipc_disable_merge_count = m_ipc_disable_merge_count, .m_permission = m_permission, .m_attribute = m_attribute, .m_original_permission = m_original_permission, .m_disable_merge_attribute = m_disable_merge_attribute, }; } public: explicit KMemoryBlock() { /* ... */ } constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) : util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(util::ConstantInitialize), m_permission(p), m_original_permission(KMemoryPermission_None), m_attribute(attr), m_disable_merge_attribute(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), m_ipc_disable_merge_count(), m_device_use_count(0), m_device_disable_merge_left_count(), m_device_disable_merge_right_count() { /* ... */ } constexpr void Initialize(KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) { MESOSPHERE_ASSERT_THIS(); m_device_disable_merge_left_count = 0; m_device_disable_merge_right_count = 0; m_address = addr; m_num_pages = np; m_memory_state = ms; m_ipc_lock_count = 0; m_device_use_count = 0; m_permission = p; m_original_permission = KMemoryPermission_None; m_attribute = attr; m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None; } constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const { MESOSPHERE_ASSERT_THIS(); constexpr auto AttributeIgnoreMask = KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared; return m_memory_state == s && m_permission == p && (m_attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); } constexpr bool HasSameProperties(const KMemoryBlock &rhs) const { MESOSPHERE_ASSERT_THIS(); return m_memory_state == rhs.m_memory_state && m_permission == rhs.m_permission && m_original_permission == rhs.m_original_permission && m_attribute == rhs.m_attribute && m_ipc_lock_count == rhs.m_ipc_lock_count && m_device_use_count == rhs.m_device_use_count; } constexpr bool CanMergeWith(const KMemoryBlock &rhs) const { return this->HasSameProperties(rhs) && (m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute_AllRight) == 0 && (rhs.m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute_AllLeft) == 0; } constexpr bool Contains(KProcessAddress addr) const { MESOSPHERE_ASSERT_THIS(); return this->GetAddress() <= addr && addr <= this->GetEndAddress(); } constexpr void Add(const KMemoryBlock &added_block) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(added_block.GetNumPages() > 0); MESOSPHERE_ASSERT(this->GetAddress() + added_block.GetSize() - 1 < this->GetEndAddress() + added_block.GetSize() - 1); m_num_pages += added_block.GetNumPages(); m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute | added_block.m_disable_merge_attribute); m_device_disable_merge_right_count = added_block.m_device_disable_merge_right_count; } constexpr void Update(KMemoryState s, KMemoryPermission p, KMemoryAttribute a, bool set_disable_merge_attr, u8 set_mask, u8 clear_mask) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(m_original_permission == KMemoryPermission_None); MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_IpcLocked) == 0); m_memory_state = s; m_permission = p; m_attribute = static_cast<KMemoryAttribute>(a | (m_attribute & (KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared))); if (set_disable_merge_attr && set_mask != 0) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute | set_mask); } if (clear_mask != 0) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & ~clear_mask); } } constexpr void UpdateAttribute(u32 mask, u32 attr) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT((mask & KMemoryAttribute_IpcLocked) == 0); MESOSPHERE_ASSERT((mask & KMemoryAttribute_DeviceShared) == 0); m_attribute = static_cast<KMemoryAttribute>((m_attribute & ~mask) | attr); } constexpr void Split(KMemoryBlock *block, KProcessAddress addr) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this->GetAddress() < addr); MESOSPHERE_ASSERT(this->Contains(addr)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), PageSize)); block->m_address = m_address; block->m_num_pages = (addr - this->GetAddress()) / PageSize; block->m_memory_state = m_memory_state; block->m_ipc_lock_count = m_ipc_lock_count; block->m_device_use_count = m_device_use_count; block->m_permission = m_permission; block->m_original_permission = m_original_permission; block->m_attribute = m_attribute; block->m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute_AllLeft); block->m_ipc_disable_merge_count = m_ipc_disable_merge_count; block->m_device_disable_merge_left_count = m_device_disable_merge_left_count; block->m_device_disable_merge_right_count = 0; m_address = addr; m_num_pages -= block->m_num_pages; m_ipc_disable_merge_count = 0; m_device_disable_merge_left_count = 0; m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute_AllRight); } constexpr void UpdateDeviceDisableMergeStateForShareLeft(KMemoryPermission new_perm, bool left, bool right) { /* New permission/right aren't used. */ MESOSPHERE_UNUSED(new_perm, right); if (left) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute_DeviceLeft); const u16 new_device_disable_merge_left_count = ++m_device_disable_merge_left_count; MESOSPHERE_ABORT_UNLESS(new_device_disable_merge_left_count > 0); } } constexpr void UpdateDeviceDisableMergeStateForShareRight(KMemoryPermission new_perm, bool left, bool right) { /* New permission/left aren't used. */ MESOSPHERE_UNUSED(new_perm, left); if (right) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute_DeviceRight); const u16 new_device_disable_merge_right_count = ++m_device_disable_merge_right_count; MESOSPHERE_ABORT_UNLESS(new_device_disable_merge_right_count > 0); } } constexpr void UpdateDeviceDisableMergeStateForShare(KMemoryPermission new_perm, bool left, bool right) { this->UpdateDeviceDisableMergeStateForShareLeft(new_perm, left, right); this->UpdateDeviceDisableMergeStateForShareRight(new_perm, left, right); } constexpr void ShareToDevice(KMemoryPermission new_perm, bool left, bool right) { /* New permission isn't used. */ MESOSPHERE_UNUSED(new_perm); /* We must either be shared or have a zero lock count. */ MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_DeviceShared) == KMemoryAttribute_DeviceShared || m_device_use_count == 0); /* Share. */ const u16 new_count = ++m_device_use_count; MESOSPHERE_ABORT_UNLESS(new_count > 0); m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute_DeviceShared); this->UpdateDeviceDisableMergeStateForShare(new_perm, left, right); } constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(KMemoryPermission new_perm, bool left, bool right) { /* New permission/right aren't used. */ MESOSPHERE_UNUSED(new_perm, right); if (left) { if (!m_device_disable_merge_left_count) { return; } --m_device_disable_merge_left_count; } m_device_disable_merge_left_count = std::min(m_device_disable_merge_left_count, m_device_use_count); if (m_device_disable_merge_left_count == 0) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute_DeviceLeft); } } constexpr void UpdateDeviceDisableMergeStateForUnshareRight(KMemoryPermission new_perm, bool left, bool right) { /* New permission/left aren't used. */ MESOSPHERE_UNUSED(new_perm, left); if (right) { const u16 old_device_disable_merge_right_count = m_device_disable_merge_right_count--; MESOSPHERE_ASSERT(old_device_disable_merge_right_count > 0); if (old_device_disable_merge_right_count == 1) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute_DeviceRight); } } } constexpr void UpdateDeviceDisableMergeStateForUnshare(KMemoryPermission new_perm, bool left, bool right) { this->UpdateDeviceDisableMergeStateForUnshareLeft(new_perm, left, right); this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right); } constexpr void UnshareToDevice(KMemoryPermission new_perm, bool left, bool right) { /* New permission isn't used. */ MESOSPHERE_UNUSED(new_perm); /* We must be shared. */ MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_DeviceShared) == KMemoryAttribute_DeviceShared); /* Unhare. */ const u16 old_count = m_device_use_count--; MESOSPHERE_ABORT_UNLESS(old_count > 0); if (old_count == 1) { m_attribute = static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute_DeviceShared); } this->UpdateDeviceDisableMergeStateForUnshare(new_perm, left, right); } constexpr void UnshareToDeviceRight(KMemoryPermission new_perm, bool left, bool right) { /* New permission isn't used. */ MESOSPHERE_UNUSED(new_perm); /* We must be shared. */ MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_DeviceShared) == KMemoryAttribute_DeviceShared); /* Unhare. */ const u16 old_count = m_device_use_count--; MESOSPHERE_ABORT_UNLESS(old_count > 0); if (old_count == 1) { m_attribute = static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute_DeviceShared); } this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right); } constexpr void LockForIpc(KMemoryPermission new_perm, bool left, bool right) { /* We must either be locked or have a zero lock count. */ MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_IpcLocked) == KMemoryAttribute_IpcLocked || m_ipc_lock_count == 0); /* Lock. */ const u16 new_lock_count = ++m_ipc_lock_count; MESOSPHERE_ABORT_UNLESS(new_lock_count > 0); /* If this is our first lock, update our permissions. */ if (new_lock_count == 1) { MESOSPHERE_ASSERT(m_original_permission == KMemoryPermission_None); MESOSPHERE_ASSERT((m_permission | new_perm | KMemoryPermission_NotMapped) == (m_permission | KMemoryPermission_NotMapped)); MESOSPHERE_ASSERT((m_permission & KMemoryPermission_UserExecute) != KMemoryPermission_UserExecute || (new_perm == KMemoryPermission_UserRead)); m_original_permission = m_permission; m_permission = static_cast<KMemoryPermission>((new_perm & KMemoryPermission_IpcLockChangeMask) | (m_original_permission & ~KMemoryPermission_IpcLockChangeMask)); } m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute_IpcLocked); if (left) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute_IpcLeft); const u16 new_ipc_disable_merge_count = ++m_ipc_disable_merge_count; MESOSPHERE_ABORT_UNLESS(new_ipc_disable_merge_count > 0); } MESOSPHERE_UNUSED(right); } constexpr void UnlockForIpc(KMemoryPermission new_perm, bool left, bool right) { /* New permission isn't used. */ MESOSPHERE_UNUSED(new_perm); /* We must be locked. */ MESOSPHERE_ASSERT((m_attribute & KMemoryAttribute_IpcLocked) == KMemoryAttribute_IpcLocked); /* Unlock. */ const u16 old_lock_count = m_ipc_lock_count--; MESOSPHERE_ABORT_UNLESS(old_lock_count > 0); /* If this is our last unlock, update our permissions. */ if (old_lock_count == 1) { MESOSPHERE_ASSERT(m_original_permission != KMemoryPermission_None); m_permission = m_original_permission; m_original_permission = KMemoryPermission_None; m_attribute = static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute_IpcLocked); } if (left) { const u16 old_ipc_disable_merge_count = m_ipc_disable_merge_count--; MESOSPHERE_ASSERT(old_ipc_disable_merge_count > 0); if (old_ipc_disable_merge_count == 1) { m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute_IpcLeft); } } MESOSPHERE_UNUSED(right); } constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const { return m_disable_merge_attribute; } }; static_assert(std::is_trivially_destructible<KMemoryBlock>::value); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_block_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_memory_block.hpp> #include <mesosphere/kern_k_page_table_manager.hpp> namespace ams::kern { class KMemoryBlockManagerUpdateAllocator { public: static constexpr size_t MaxBlocks = 2; private: KMemoryBlock *m_blocks[MaxBlocks]; size_t m_index; KMemoryBlockSlabManager *m_slab_manager; private: ALWAYS_INLINE Result Initialize(size_t num_blocks) { /* Check num blocks. */ MESOSPHERE_ASSERT(num_blocks <= MaxBlocks); /* Set index. */ m_index = MaxBlocks - num_blocks; /* Allocate the blocks. */ for (size_t i = 0; i < num_blocks && i < MaxBlocks; ++i) { m_blocks[m_index + i] = m_slab_manager->Allocate(); R_UNLESS(m_blocks[m_index + i] != nullptr, svc::ResultOutOfResource()); } R_SUCCEED(); } public: KMemoryBlockManagerUpdateAllocator(Result *out_result, KMemoryBlockSlabManager *sm, size_t num_blocks = MaxBlocks) : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) { *out_result = this->Initialize(num_blocks); } ~KMemoryBlockManagerUpdateAllocator() { for (const auto &block : m_blocks) { if (block != nullptr) { m_slab_manager->Free(block); } } } KMemoryBlock *Allocate() { MESOSPHERE_ABORT_UNLESS(m_index < MaxBlocks); MESOSPHERE_ABORT_UNLESS(m_blocks[m_index] != nullptr); KMemoryBlock *block = nullptr; std::swap(block, m_blocks[m_index++]); return block; } void Free(KMemoryBlock *block) { MESOSPHERE_ABORT_UNLESS(m_index <= MaxBlocks); MESOSPHERE_ABORT_UNLESS(block != nullptr); if (m_index == 0) { m_slab_manager->Free(block); } else { m_blocks[--m_index] = block; } } }; class KMemoryBlockManager { public: using MemoryBlockTree = util::IntrusiveRedBlackTreeBaseTraits<KMemoryBlock>::TreeType<KMemoryBlock>; using MemoryBlockLockFunction = void (KMemoryBlock::*)(KMemoryPermission new_perm, bool left, bool right); using iterator = MemoryBlockTree::iterator; using const_iterator = MemoryBlockTree::const_iterator; private: MemoryBlockTree m_memory_block_tree; KProcessAddress m_start_address; KProcessAddress m_end_address; private: void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages); public: constexpr explicit KMemoryBlockManager(util::ConstantInitializeTag) : m_memory_block_tree(), m_start_address(Null<KProcessAddress>), m_end_address(Null<KProcessAddress>) { /* ... */ } explicit KMemoryBlockManager() { /* ... */ } iterator end() { return m_memory_block_tree.end(); } const_iterator end() const { return m_memory_block_tree.end(); } const_iterator cend() const { return m_memory_block_tree.cend(); } Result Initialize(KProcessAddress st, KProcessAddress nd, KMemoryBlockSlabManager *slab_manager); void Finalize(KMemoryBlockSlabManager *slab_manager); static bool GetRegionForFindFreeArea(KProcessAddress *out_start, KProcessAddress *out_end, KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages); KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const; void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr); void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm); void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr); void UpdateAttribute(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, u32 mask, u32 attr); iterator FindIterator(KProcessAddress address) const { return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None)); } const KMemoryBlock *FindBlock(KProcessAddress address) const { if (const_iterator it = this->FindIterator(address); it != m_memory_block_tree.end()) { return std::addressof(*it); } return nullptr; } /* Debug. */ bool CheckState() const; void DumpBlocks() const; }; class KScopedMemoryBlockManagerAuditor { private: KMemoryBlockManager *m_manager; public: explicit ALWAYS_INLINE KScopedMemoryBlockManagerAuditor(KMemoryBlockManager *m) : m_manager(m) { MESOSPHERE_AUDIT(m_manager->CheckState()); } explicit ALWAYS_INLINE KScopedMemoryBlockManagerAuditor(KMemoryBlockManager &m) : KScopedMemoryBlockManagerAuditor(std::addressof(m)) { /* ... */ } ALWAYS_INLINE ~KScopedMemoryBlockManagerAuditor() { MESOSPHERE_AUDIT(m_manager->CheckState()); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/init/kern_init_page_table_select.hpp> #include <mesosphere/kern_k_memory_region.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <mesosphere/board/nintendo/nx/kern_k_memory_layout.hpp> #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) #include <mesosphere/board/qemu/virt/kern_k_memory_layout.hpp> #else #error "Unknown board for KMemoryLayout" #endif namespace ams::kern { constexpr size_t KernelAslrAlignment = 2_MB; constexpr size_t KernelVirtualAddressSpaceWidth = size_t(1ul) << 39ul; constexpr size_t KernelPhysicalAddressSpaceWidth = size_t(1ul) << 48ul; constexpr size_t KernelVirtualAddressSpaceBase = 0ul - KernelVirtualAddressSpaceWidth; constexpr size_t KernelVirtualAddressSpaceEnd = KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); constexpr size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ul; constexpr size_t KernelVirtualAddressSpaceSize = KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; constexpr size_t KernelPhysicalAddressSpaceBase = 0ul; constexpr size_t KernelPhysicalAddressSpaceEnd = KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth; constexpr size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ul; constexpr size_t KernelPhysicalAddressSpaceSize = KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase; constexpr size_t KernelPageTableHeapSize = init::KInitialPageTable::GetMaximumOverheadSize(kern::MainMemorySizeMax); constexpr size_t KernelInitialPageHeapSize = 128_KB; constexpr size_t KernelSlabHeapDataSize = 5_MB; constexpr size_t KernelSlabHeapGapsSizeMax = 2_MB - 64_KB; constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSizeMax; /* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x800. */ constexpr size_t KernelPageBufferHeapSize = 0x3E0000; constexpr size_t KernelSlabHeapAdditionalSize = 0x148000; constexpr size_t KernelPageBufferAdditionalSize = 0x33C000; constexpr size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize + KernelPageBufferHeapSize; class KMemoryLayout { private: static constinit inline uintptr_t s_linear_phys_to_virt_diff; static constinit inline uintptr_t s_linear_virt_to_phys_diff; static constinit inline KMemoryRegionTree s_virtual_tree; static constinit inline KMemoryRegionTree s_physical_tree; static constinit inline KMemoryRegionTree s_virtual_linear_tree; static constinit inline KMemoryRegionTree s_physical_linear_tree; private: template<typename AddressType> requires IsKTypedAddress<AddressType> static ALWAYS_INLINE bool IsTypedAddress(const KMemoryRegion *®ion, AddressType address, KMemoryRegionTree &tree, KMemoryRegionType type) { /* Check if the cached region already contains the address. */ if (region != nullptr && region->Contains(GetInteger(address))) { return true; } /* Find the containing region, and update the cache. */ if (const KMemoryRegion *found = tree.Find(GetInteger(address)); found != nullptr && found->IsDerivedFrom(type)) { region = found; return true; } else { return false; } } template<typename AddressType> requires IsKTypedAddress<AddressType> static ALWAYS_INLINE bool IsTypedAddress(const KMemoryRegion *®ion, AddressType address, size_t size, KMemoryRegionTree &tree, KMemoryRegionType type) { /* Get the end of the checked region. */ const uintptr_t last_address = GetInteger(address) + size - 1; /* Walk the tree to verify the region is correct. */ const KMemoryRegion *cur = (region != nullptr && region->Contains(GetInteger(address))) ? region : tree.Find(GetInteger(address)); while (cur != nullptr && cur->IsDerivedFrom(type)) { if (last_address <= cur->GetLastAddress()) { region = cur; return true; } cur = cur->GetNext(); } return false; } template<typename AddressType> requires IsKTypedAddress<AddressType> static ALWAYS_INLINE const KMemoryRegion *Find(AddressType address, const KMemoryRegionTree &tree) { return tree.Find(GetInteger(address)); } static ALWAYS_INLINE KMemoryRegion &Dereference(KMemoryRegion *region) { MESOSPHERE_INIT_ABORT_UNLESS(region != nullptr); return *region; } static ALWAYS_INLINE const KMemoryRegion &Dereference(const KMemoryRegion *region) { MESOSPHERE_INIT_ABORT_UNLESS(region != nullptr); return *region; } static ALWAYS_INLINE KVirtualAddress GetStackTopAddress(s32 core_id, KMemoryRegionType type) { const auto ®ion = Dereference(GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id))); MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0); return region.GetEndAddress(); } public: static ALWAYS_INLINE KMemoryRegionTree &GetVirtualMemoryRegionTree() { return s_virtual_tree; } static ALWAYS_INLINE KMemoryRegionTree &GetPhysicalMemoryRegionTree() { return s_physical_tree; } static ALWAYS_INLINE KMemoryRegionTree &GetVirtualLinearMemoryRegionTree() { return s_virtual_linear_tree; } static ALWAYS_INLINE KMemoryRegionTree &GetPhysicalLinearMemoryRegionTree() { return s_physical_linear_tree; } static ALWAYS_INLINE KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress address) { return GetInteger(address) + s_linear_phys_to_virt_diff; } static ALWAYS_INLINE KPhysicalAddress GetLinearPhysicalAddress(KVirtualAddress address) { return GetInteger(address) + s_linear_virt_to_phys_diff; } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *Find(KVirtualAddress address) { return Find(address, GetVirtualMemoryRegionTree()); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *Find(KPhysicalAddress address) { return Find(address, GetPhysicalMemoryRegionTree()); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *FindLinear(KVirtualAddress address) { return Find(address, GetVirtualLinearMemoryRegionTree()); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *FindLinear(KPhysicalAddress address) { return Find(address, GetPhysicalLinearMemoryRegionTree()); } static MESOSPHERE_NOINLINE_IF_DEBUG KVirtualAddress GetMainStackTopAddress(s32 core_id) { return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack); } static MESOSPHERE_NOINLINE_IF_DEBUG KVirtualAddress GetIdleStackTopAddress(s32 core_id) { return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack); } static MESOSPHERE_NOINLINE_IF_DEBUG KVirtualAddress GetExceptionStackTopAddress(s32 core_id) { return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack); } static MESOSPHERE_NOINLINE_IF_DEBUG KVirtualAddress GetSlabRegionAddress() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab)).GetAddress(); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetDeviceRegion(KMemoryRegionType type) { return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type)); } static KPhysicalAddress GetDevicePhysicalAddress(KMemoryRegionType type) { return GetDeviceRegion(type).GetAddress(); } static KVirtualAddress GetDeviceVirtualAddress(KMemoryRegionType type) { return GetDeviceRegion(type).GetPairAddress(); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetPoolManagementRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetPageTableHeapRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetKernelStackRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetTempRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetSlabRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetKernelTraceBufferRegion() { return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelTraceBuffer)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetSecureAppletMemoryRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelSecureAppletMemory)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetVirtualLinearRegion(KVirtualAddress address) { return Dereference(FindLinear(address)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetPhysicalLinearRegion(KPhysicalAddress address) { return Dereference(FindLinear(address)); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *GetPhysicalKernelTraceBufferRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *GetPhysicalOnMemoryBootImageRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage); } static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion *GetPhysicalDTBRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsHeapPhysicalAddress(const KMemoryRegion *®ion, KPhysicalAddress address) { return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(), KMemoryRegionType_DramUserPool); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsHeapVirtualAddress(const KMemoryRegion *®ion, KVirtualAddress address) { return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(), KMemoryRegionType_VirtualDramUserPool); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsHeapPhysicalAddress(const KMemoryRegion *®ion, KPhysicalAddress address, size_t size) { return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(), KMemoryRegionType_DramUserPool); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsHeapVirtualAddress(const KMemoryRegion *®ion, KVirtualAddress address, size_t size) { return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(), KMemoryRegionType_VirtualDramUserPool); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsLinearMappedPhysicalAddress(const KMemoryRegion *®ion, KPhysicalAddress address) { return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(), static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped)); } static MESOSPHERE_NOINLINE_IF_DEBUG bool IsLinearMappedPhysicalAddress(const KMemoryRegion *®ion, KPhysicalAddress address, size_t size) { return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(), static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped)); } static std::tuple<size_t, size_t> GetTotalAndKernelMemorySizes() { size_t total_size = 0, kernel_size = 0; for (const auto ®ion : GetPhysicalMemoryRegionTree()) { if (region.IsDerivedFrom(KMemoryRegionType_Dram)) { total_size += region.GetSize(); if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) { kernel_size += region.GetSize(); } } } return std::make_tuple(total_size, kernel_size); } static void InitializeLinearMemoryAddresses(u64 phys_to_virt_diff) { /* Set static differences. */ s_linear_phys_to_virt_diff = phys_to_virt_diff; s_linear_virt_to_phys_diff = -phys_to_virt_diff; } static void InitializeLinearMemoryRegionTrees(); static size_t GetResourceRegionSizeForInit(bool use_extra_resource); static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelCodeRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelStackRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelMiscRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSlabRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetLinearRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionAttr_LinearMapped); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetLinearRegionVirtualExtents() { const auto physical = GetLinearRegionPhysicalExtents(); return KMemoryRegion(GetInteger(GetLinearVirtualAddress(physical.GetAddress())), GetInteger(GetLinearVirtualAddress(physical.GetLastAddress())), 0, KMemoryRegionType_None); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetMainMemoryPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetCarveoutRegionExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionAttr_CarveoutProtected); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelBase); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelCodeRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelCode); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSlabRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelSlab); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSecureAppletMemoryRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelSecureAppletMemory); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelPageTableHeapRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelPtHeap); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelInitPageTableRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelInitPt); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelPoolPartitionRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolPartition); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelPoolManagementRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolManagement); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSystemPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemPool); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemNonSecurePool); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelAppletPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramAppletPool); } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelApplicationPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramApplicationPool); } static MESOSPHERE_NOINLINE_IF_DEBUG bool HasKernelSystemNonSecurePoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramSystemNonSecurePool) != nullptr; } static MESOSPHERE_NOINLINE_IF_DEBUG bool HasKernelAppletPoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramAppletPool) != nullptr; } static MESOSPHERE_NOINLINE_IF_DEBUG bool HasKernelApplicationPoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramApplicationPool) != nullptr; } static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelTraceBufferRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelTraceBuffer); } }; namespace init { /* These should be generic, regardless of board. */ void SetupPoolPartitionMemoryRegions(); /* These may be implemented in a board-specific manner. */ void SetupDevicePhysicalMemoryRegions(); void SetupDramPhysicalMemoryRegions(); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #include <mesosphere/kern_k_page_heap.hpp> namespace ams::kern { class KPageGroup; class KMemoryManager { public: enum Pool { Pool_Application = 0, Pool_Applet = 1, Pool_System = 2, Pool_SystemNonSecure = 3, Pool_Count, Pool_Shift = 4, Pool_Mask = (0xF << Pool_Shift), /* Aliases. */ Pool_Unsafe = Pool_Application, Pool_Secure = Pool_System, }; enum Direction { Direction_FromFront = 0, Direction_FromBack = 1, Direction_Shift = 0, Direction_Mask = (0xF << Direction_Shift), }; static constexpr size_t MaxManagerCount = 10; private: class Impl { private: using RefCount = u16; public: static size_t CalculateManagementOverheadSize(size_t region_size); static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) { return (util::AlignUp((region_size / PageSize), BITSIZEOF(u64)) / BITSIZEOF(u64)) * sizeof(u64); } private: KPageHeap m_heap; RefCount *m_page_reference_counts; KVirtualAddress m_management_region; Pool m_pool; Impl *m_next; Impl *m_prev; public: Impl() : m_heap(), m_page_reference_counts(), m_management_region(Null<KVirtualAddress>), m_pool(), m_next(), m_prev() { /* ... */ } size_t Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p); KPhysicalAddress AllocateBlock(s32 index, bool random) { return m_heap.AllocateBlock(index, random); } KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) { return m_heap.AllocateAligned(index, num_pages, align_pages); } void Free(KPhysicalAddress addr, size_t num_pages) { m_heap.Free(addr, num_pages); } void SetInitialUsedHeapSize(size_t reserved_size) { m_heap.SetInitialUsedSize(reserved_size); } void InitializeOptimizedMemory() { std::memset(GetVoidPointer(m_management_region), 0, CalculateOptimizedProcessOverheadSize(m_heap.GetSize())); } void TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages); void TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages); bool ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, u8 fill_pattern); constexpr Pool GetPool() const { return m_pool; } constexpr size_t GetSize() const { return m_heap.GetSize(); } constexpr KPhysicalAddress GetEndAddress() const { return m_heap.GetEndAddress(); } size_t GetFreeSize() const { return m_heap.GetFreeSize(); } void DumpFreeList() const { return m_heap.DumpFreeList(); } constexpr size_t GetPageOffset(KPhysicalAddress address) const { return m_heap.GetPageOffset(address); } constexpr size_t GetPageOffsetToEnd(KPhysicalAddress address) const { return m_heap.GetPageOffsetToEnd(address); } constexpr void SetNext(Impl *n) { m_next = n; } constexpr void SetPrev(Impl *n) { m_prev = n; } constexpr Impl *GetNext() const { return m_next; } constexpr Impl *GetPrev() const { return m_prev; } void OpenFirst(KPhysicalAddress address, size_t num_pages) { size_t index = this->GetPageOffset(address); const size_t end = index + num_pages; while (index < end) { const RefCount ref_count = (++m_page_reference_counts[index]); MESOSPHERE_ABORT_UNLESS(ref_count == 1); index++; } } void Open(KPhysicalAddress address, size_t num_pages) { size_t index = this->GetPageOffset(address); const size_t end = index + num_pages; while (index < end) { const RefCount ref_count = (++m_page_reference_counts[index]); MESOSPHERE_ABORT_UNLESS(ref_count > 1); index++; } } void Close(KPhysicalAddress address, size_t num_pages) { size_t index = this->GetPageOffset(address); const size_t end = index + num_pages; size_t free_start = 0; size_t free_count = 0; while (index < end) { MESOSPHERE_ABORT_UNLESS(m_page_reference_counts[index] > 0); const RefCount ref_count = (--m_page_reference_counts[index]); /* Keep track of how many zero refcounts we see in a row, to minimize calls to free. */ if (ref_count == 0) { if (free_count > 0) { free_count++; } else { free_start = index; free_count = 1; } } else { if (free_count > 0) { this->Free(m_heap.GetAddress() + free_start * PageSize, free_count); free_count = 0; } } index++; } if (free_count > 0) { this->Free(m_heap.GetAddress() + free_start * PageSize, free_count); } } }; private: KLightLock m_pool_locks[Pool_Count]; Impl *m_pool_managers_head[Pool_Count]; Impl *m_pool_managers_tail[Pool_Count]; Impl m_managers[MaxManagerCount]; size_t m_num_managers; u64 m_optimized_process_ids[Pool_Count]; bool m_has_optimized_process[Pool_Count]; s32 m_min_heap_indexes[Pool_Count]; private: Impl &GetManager(KPhysicalAddress address) { return m_managers[KMemoryLayout::GetPhysicalLinearRegion(address).GetAttributes()]; } const Impl &GetManager(KPhysicalAddress address) const { return m_managers[KMemoryLayout::GetPhysicalLinearRegion(address).GetAttributes()]; } constexpr Impl *GetFirstManager(Pool pool, Direction dir) { return dir == Direction_FromBack ? m_pool_managers_tail[pool] : m_pool_managers_head[pool]; } constexpr Impl *GetNextManager(Impl *cur, Direction dir) { if (dir == Direction_FromBack) { return cur->GetPrev(); } else { return cur->GetNext(); } } Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index); public: KMemoryManager() : m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process(), m_min_heap_indexes() { /* ... */ } NOINLINE void Initialize(KVirtualAddress management_region, size_t management_region_size, const u32 *min_align_shifts); NOINLINE Result InitializeOptimizedMemory(u64 process_id, Pool pool); NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool); NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, size_t align_pages, u32 option); NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern); Pool GetPool(KPhysicalAddress address) const { return this->GetManager(address).GetPool(); } void Open(KPhysicalAddress address, size_t num_pages) { /* Repeatedly open references until we've done so for all pages. */ while (num_pages) { auto &manager = this->GetManager(address); const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); { KScopedLightLock lk(m_pool_locks[manager.GetPool()]); manager.Open(address, cur_pages); } num_pages -= cur_pages; address += cur_pages * PageSize; } } void OpenFirst(KPhysicalAddress address, size_t num_pages) { /* Repeatedly open references until we've done so for all pages. */ while (num_pages) { auto &manager = this->GetManager(address); const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); { KScopedLightLock lk(m_pool_locks[manager.GetPool()]); manager.OpenFirst(address, cur_pages); } num_pages -= cur_pages; address += cur_pages * PageSize; } } void Close(KPhysicalAddress address, size_t num_pages) { /* Repeatedly close references until we've done so for all pages. */ while (num_pages) { auto &manager = this->GetManager(address); const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address)); { KScopedLightLock lk(m_pool_locks[manager.GetPool()]); manager.Close(address, cur_pages); } num_pages -= cur_pages; address += cur_pages * PageSize; } } size_t GetSize() { size_t total = 0; for (size_t i = 0; i < m_num_managers; i++) { total += m_managers[i].GetSize(); } return total; } size_t GetSize(Pool pool) { constexpr Direction GetSizeDirection = Direction_FromFront; size_t total = 0; for (auto *manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr; manager = this->GetNextManager(manager, GetSizeDirection)) { total += manager->GetSize(); } return total; } size_t GetFreeSize() { size_t total = 0; for (size_t i = 0; i < m_num_managers; i++) { KScopedLightLock lk(m_pool_locks[m_managers[i].GetPool()]); total += m_managers[i].GetFreeSize(); } return total; } size_t GetFreeSize(Pool pool) { KScopedLightLock lk(m_pool_locks[pool]); constexpr Direction GetSizeDirection = Direction_FromFront; size_t total = 0; for (auto *manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr; manager = this->GetNextManager(manager, GetSizeDirection)) { total += manager->GetFreeSize(); } return total; } void DumpFreeList(Pool pool) { KScopedLightLock lk(m_pool_locks[pool]); constexpr Direction DumpDirection = Direction_FromFront; for (auto *manager = this->GetFirstManager(pool, DumpDirection); manager != nullptr; manager = this->GetNextManager(manager, DumpDirection)) { manager->DumpFreeList(); } } size_t GetMinimumAlignment(Pool pool) { return KPageHeap::GetBlockSize(m_min_heap_indexes[pool]); } public: static size_t CalculateManagementOverheadSize(size_t region_size) { return Impl::CalculateManagementOverheadSize(region_size); } static constexpr ALWAYS_INLINE u32 EncodeOption(Pool pool, Direction dir) { return (pool << Pool_Shift) | (dir << Direction_Shift); } static constexpr ALWAYS_INLINE Pool GetPool(u32 option) { return static_cast<Pool>((option & Pool_Mask) >> Pool_Shift); } static constexpr ALWAYS_INLINE Direction GetDirection(u32 option) { return static_cast<Direction>((option & Direction_Mask) >> Direction_Shift); } static constexpr ALWAYS_INLINE std::tuple<Pool, Direction> DecodeOption(u32 option) { return std::make_tuple(GetPool(option), GetDirection(option)); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_region.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_memory_region_type.hpp> namespace ams::kern { class KMemoryRegionTree; class KMemoryRegion : public util::IntrusiveRedBlackTreeBaseNode<KMemoryRegion> { NON_COPYABLE(KMemoryRegion); NON_MOVEABLE(KMemoryRegion); private: friend class KMemoryRegionTree; private: uintptr_t m_address; uintptr_t m_pair_address; uintptr_t m_last_address; u32 m_attributes; u32 m_type_id; public: static constexpr ALWAYS_INLINE int Compare(const KMemoryRegion &lhs, const KMemoryRegion &rhs) { if (lhs.GetAddress() < rhs.GetAddress()) { return -1; } else if (lhs.GetAddress() <= rhs.GetLastAddress()) { return 0; } else { return 1; } } public: constexpr ALWAYS_INLINE KMemoryRegion() : util::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>(util::ConstantInitialize), m_address(0), m_pair_address(0), m_last_address(0), m_attributes(0), m_type_id(0) { /* ... */ } ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, uintptr_t p, u32 r, u32 t) : m_address(a), m_pair_address(p), m_last_address(la), m_attributes(r), m_type_id(t) { /* ... */ } ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, u32 r, u32 t) : KMemoryRegion(a, la, std::numeric_limits<uintptr_t>::max(), r, t) { /* ... */ } private: constexpr ALWAYS_INLINE void Reset(uintptr_t a, uintptr_t la, uintptr_t p, u32 r, u32 t) { m_address = a; m_pair_address = p; m_last_address = la; m_attributes = r; m_type_id = t; } public: constexpr ALWAYS_INLINE uintptr_t GetAddress() const { return m_address; } constexpr ALWAYS_INLINE uintptr_t GetPairAddress() const { return m_pair_address; } constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const { return m_last_address; } constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const { return this->GetLastAddress() + 1; } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetEndAddress() - this->GetAddress(); } constexpr ALWAYS_INLINE u32 GetAttributes() const { return m_attributes; } constexpr ALWAYS_INLINE u32 GetType() const { return m_type_id; } constexpr ALWAYS_INLINE void SetType(u32 type) { MESOSPHERE_INIT_ABORT_UNLESS(this->CanDerive(type)); m_type_id = type; } constexpr ALWAYS_INLINE bool Contains(uintptr_t address) const { MESOSPHERE_INIT_ABORT_UNLESS(this->GetEndAddress() != 0); return this->GetAddress() <= address && address <= this->GetLastAddress(); } constexpr ALWAYS_INLINE bool IsDerivedFrom(u32 type) const { return (this->GetType() | type) == this->GetType(); } constexpr ALWAYS_INLINE bool HasTypeAttribute(KMemoryRegionAttr attr) const { return (this->GetType() | attr) == this->GetType(); } constexpr ALWAYS_INLINE bool CanDerive(u32 type) const { return (this->GetType() | type) == type; } constexpr ALWAYS_INLINE void SetPairAddress(uintptr_t a) { m_pair_address = a; } constexpr ALWAYS_INLINE void SetTypeAttribute(KMemoryRegionAttr attr) { m_type_id |= attr; } }; static_assert(std::is_trivially_destructible<KMemoryRegion>::value); class KMemoryRegionTree { public: struct DerivedRegionExtents { const KMemoryRegion *first_region; const KMemoryRegion *last_region; constexpr DerivedRegionExtents() : first_region(nullptr), last_region(nullptr) { /* ... */ } constexpr ALWAYS_INLINE uintptr_t GetAddress() const { return this->first_region->GetAddress(); } constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const { return this->last_region->GetLastAddress(); } constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const { return this->GetLastAddress() + 1; } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetEndAddress() - this->GetAddress(); } }; private: using TreeType = util::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>; public: using value_type = TreeType::value_type; using size_type = TreeType::size_type; using difference_type = TreeType::difference_type; using pointer = TreeType::pointer; using const_pointer = TreeType::const_pointer; using reference = TreeType::reference; using const_reference = TreeType::const_reference; using iterator = TreeType::iterator; using const_iterator = TreeType::const_iterator; private: TreeType m_tree; public: constexpr ALWAYS_INLINE KMemoryRegionTree() : m_tree() { /* ... */ } public: KMemoryRegion *FindModifiable(uintptr_t address) { if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) { return std::addressof(*it); } else { return nullptr; } } const KMemoryRegion *Find(uintptr_t address) const { if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) { return std::addressof(*it); } else { return nullptr; } } const KMemoryRegion *FindByType(u32 type_id) const { for (auto it = this->cbegin(); it != this->cend(); ++it) { if (it->GetType() == type_id) { return std::addressof(*it); } } return nullptr; } const KMemoryRegion *FindByTypeAndAttribute(u32 type_id, u32 attr) const { for (auto it = this->cbegin(); it != this->cend(); ++it) { if (it->GetType() == type_id && it->GetAttributes() == attr) { return std::addressof(*it); } } return nullptr; } const KMemoryRegion *FindFirstDerived(u32 type_id) const { for (auto it = this->cbegin(); it != this->cend(); it++) { if (it->IsDerivedFrom(type_id)) { return std::addressof(*it); } } return nullptr; } const KMemoryRegion *FindLastDerived(u32 type_id) const { const KMemoryRegion *region = nullptr; for (auto it = this->begin(); it != this->end(); it++) { if (it->IsDerivedFrom(type_id)) { region = std::addressof(*it); } } return region; } DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const { DerivedRegionExtents extents; MESOSPHERE_INIT_ABORT_UNLESS(extents.first_region == nullptr); MESOSPHERE_INIT_ABORT_UNLESS(extents.last_region == nullptr); for (auto it = this->cbegin(); it != this->cend(); it++) { if (it->IsDerivedFrom(type_id)) { if (extents.first_region == nullptr) { extents.first_region = std::addressof(*it); } extents.last_region = std::addressof(*it); } } MESOSPHERE_INIT_ABORT_UNLESS(extents.first_region != nullptr); MESOSPHERE_INIT_ABORT_UNLESS(extents.last_region != nullptr); return extents; } public: NOINLINE void InsertDirectly(uintptr_t address, uintptr_t last_address, u32 attr = 0, u32 type_id = 0); NOINLINE bool Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0); public: /* Iterator accessors. */ iterator begin() { return m_tree.begin(); } const_iterator begin() const { return m_tree.begin(); } iterator end() { return m_tree.end(); } const_iterator end() const { return m_tree.end(); } const_iterator cbegin() const { return this->begin(); } const_iterator cend() const { return this->end(); } iterator iterator_to(reference ref) { return m_tree.iterator_to(ref); } const_iterator iterator_to(const_reference ref) const { return m_tree.iterator_to(ref); } /* Content management. */ bool empty() const { return m_tree.empty(); } reference back() { return m_tree.back(); } const_reference back() const { return m_tree.back(); } reference front() { return m_tree.front(); } const_reference front() const { return m_tree.front(); } /* GCC over-eagerly inlines this operation. */ NOINLINE iterator insert(reference ref) { return m_tree.insert(ref); } NOINLINE iterator erase(iterator it) { return m_tree.erase(it); } iterator find(const_reference ref) const { return m_tree.find(ref); } iterator nfind(const_reference ref) const { return m_tree.nfind(ref); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_memory_region_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { enum KMemoryRegionType : u32 {}; enum KMemoryRegionAttr : typename std::underlying_type<KMemoryRegionType>::type { KMemoryRegionAttr_CarveoutProtected = 0x02000000, KMemoryRegionAttr_Uncached = 0x04000000, KMemoryRegionAttr_DidKernelMap = 0x08000000, KMemoryRegionAttr_ShouldKernelMap = 0x10000000, KMemoryRegionAttr_UserReadOnly = 0x20000000, KMemoryRegionAttr_NoUserMap = 0x40000000, KMemoryRegionAttr_LinearMapped = 0x80000000, }; namespace impl { consteval size_t BitsForDeriveSparse(size_t n) { return n + 1; } consteval size_t BitsForDeriveDense(size_t n) { AMS_ASSUME(n > 0); size_t low = 0, high = 1; for (size_t i = 0; i < n - 1; ++i) { if ((++low) == high) { ++high; low = 0; } } return high + 1; } class KMemoryRegionTypeValue { private: using ValueType = typename std::underlying_type<KMemoryRegionType>::type; private: ValueType m_value; size_t m_next_bit; bool m_finalized; bool m_sparse_only; bool m_dense_only; private: consteval KMemoryRegionTypeValue(ValueType v) : m_value(v), m_next_bit(0), m_finalized(false), m_sparse_only(false), m_dense_only(false) { /* ... */ } public: consteval KMemoryRegionTypeValue() : KMemoryRegionTypeValue(0) { /* ... */ } consteval operator KMemoryRegionType() const { return static_cast<KMemoryRegionType>(m_value); } consteval ValueType GetValue() const { return m_value; } consteval const KMemoryRegionTypeValue Finalize() { AMS_ASSUME(!m_finalized); KMemoryRegionTypeValue new_type = *this; new_type.m_finalized = true; return new_type; } consteval const KMemoryRegionTypeValue SetSparseOnly() { AMS_ASSUME(!m_finalized); AMS_ASSUME(!m_sparse_only); AMS_ASSUME(!m_dense_only); KMemoryRegionTypeValue new_type = *this; new_type.m_sparse_only = true; return new_type; } consteval const KMemoryRegionTypeValue SetDenseOnly() { AMS_ASSUME(!m_finalized); AMS_ASSUME(!m_sparse_only); AMS_ASSUME(!m_dense_only); KMemoryRegionTypeValue new_type = *this; new_type.m_dense_only = true; return new_type; } consteval KMemoryRegionTypeValue SetAttribute(KMemoryRegionAttr attr) { AMS_ASSUME(!m_finalized); KMemoryRegionTypeValue new_type = *this; new_type.m_value |= attr; return new_type; } consteval KMemoryRegionTypeValue DeriveInitial(size_t i, size_t next = BITSIZEOF(ValueType)) const { AMS_ASSUME(!m_finalized); AMS_ASSUME(!m_value); AMS_ASSUME(!m_next_bit); AMS_ASSUME(next > i); KMemoryRegionTypeValue new_type = *this; new_type.m_value = (ValueType{1} << i); new_type.m_next_bit = next; return new_type; } consteval KMemoryRegionTypeValue DeriveAttribute(KMemoryRegionAttr attr) const { AMS_ASSUME(!m_finalized); KMemoryRegionTypeValue new_type = *this; new_type.m_value |= attr; return new_type; } consteval KMemoryRegionTypeValue DeriveTransition(size_t ofs = 0, size_t adv = 1) const { AMS_ASSUME(!m_finalized); AMS_ASSUME(ofs < adv); AMS_ASSUME(m_next_bit + adv <= BITSIZEOF(ValueType)); KMemoryRegionTypeValue new_type = *this; new_type.m_value |= (ValueType{1} << (m_next_bit + ofs)); new_type.m_next_bit += adv; return new_type; } consteval KMemoryRegionTypeValue DeriveSparse(size_t ofs, size_t n, size_t i) const { AMS_ASSUME(!m_finalized); AMS_ASSUME(!m_dense_only); AMS_ASSUME(m_next_bit + ofs + n + 1 <= BITSIZEOF(ValueType)); AMS_ASSUME(i < n); KMemoryRegionTypeValue new_type = *this; new_type.m_value |= (ValueType{1} << (m_next_bit + ofs)); new_type.m_value |= (ValueType{1} << (m_next_bit + ofs + 1 + i)); new_type.m_next_bit += ofs + n + 1; return new_type; } consteval KMemoryRegionTypeValue Derive(size_t n, size_t i) const { AMS_ASSUME(!m_finalized); AMS_ASSUME(!m_sparse_only); AMS_ASSUME(m_next_bit + BitsForDeriveDense(n) <= BITSIZEOF(ValueType)); AMS_ASSUME(i < n); size_t low = 0, high = 1; for (size_t j = 0; j < i; ++j) { if ((++low) == high) { ++high; low = 0; } } AMS_ASSUME(high < BitsForDeriveDense(n)); KMemoryRegionTypeValue new_type = *this; new_type.m_value |= (ValueType{1} << (m_next_bit + low)); new_type.m_value |= (ValueType{1} << (m_next_bit + high)); new_type.m_next_bit += BitsForDeriveDense(n); return new_type; } consteval KMemoryRegionTypeValue Advance(size_t n) const { AMS_ASSUME(!m_finalized); AMS_ASSUME(m_next_bit + n <= BITSIZEOF(ValueType)); KMemoryRegionTypeValue new_type = *this; new_type.m_next_bit += n; return new_type; } constexpr ALWAYS_INLINE bool IsAncestorOf(ValueType v) const { return (m_value | v) == v; } }; } constexpr inline const auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue(); constexpr inline const auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2); constexpr inline const auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2); static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1); static_assert(KMemoryRegionType_Dram .GetValue() == 0x2); /* constexpr inline const auto KMemoryRegionType_CoreLocalRegion = KMemoryRegionType_None.DeriveInitial(2).Finalize(); */ /* static_assert(KMemoryRegionType_CoreLocalRegion.GetValue() == 0x4); */ constexpr inline const auto KMemoryRegionType_DramKernelBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 0).SetAttribute(KMemoryRegionAttr_NoUserMap).SetAttribute(KMemoryRegionAttr_CarveoutProtected); constexpr inline const auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1); constexpr inline const auto KMemoryRegionType_DramHeapBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped); static_assert(KMemoryRegionType_DramKernelBase .GetValue() == (0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16)); static_assert(KMemoryRegionType_DramHeapBase .GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped)); constexpr inline const auto KMemoryRegionType_DramKernelCode = KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0); constexpr inline const auto KMemoryRegionType_DramKernelSlab = KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1); constexpr inline const auto KMemoryRegionType_DramKernelPtHeap = KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(KMemoryRegionAttr_LinearMapped); constexpr inline const auto KMemoryRegionType_DramKernelInitPt = KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(KMemoryRegionAttr_LinearMapped); static_assert(KMemoryRegionType_DramKernelCode .GetValue() == (0xCE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramKernelSlab .GetValue() == (0x14E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() == (0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped)); static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped)); constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped); constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute(KMemoryRegionAttr_LinearMapped); static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped)); static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() == (0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped)); constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap); static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap)); constexpr inline const auto KMemoryRegionType_KernelTraceBuffer = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped).SetAttribute(KMemoryRegionAttr_UserReadOnly); constexpr inline const auto KMemoryRegionType_OnMemoryBootImage = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1); constexpr inline const auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2); static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() == (0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly)); static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156); static_assert(KMemoryRegionType_DTB.GetValue() == 0x256); constexpr inline const auto KMemoryRegionType_DramPoolPartition = KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap); static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); constexpr inline const auto KMemoryRegionType_DramPoolManagement = KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute(KMemoryRegionAttr_CarveoutProtected); /* UNUSED: .Derive(4, 1); */ /* UNUSED: .Derive(4, 2); */ constexpr inline const auto KMemoryRegionType_DramUserPool = KMemoryRegionType_DramPoolPartition.Derive(4, 3); static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == (0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected)); static_assert(KMemoryRegionType_DramUserPool .GetValue() == (0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); constexpr inline const auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0); constexpr inline const auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1); constexpr inline const auto KMemoryRegionType_DramSystemNonSecurePool = KMemoryRegionType_DramUserPool.Derive(4, 2); constexpr inline const auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected); static_assert(KMemoryRegionType_DramApplicationPool .GetValue() == (0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramAppletPool .GetValue() == (0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == (0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramSystemPool .GetValue() == (0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected)); constexpr inline const auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 4, 0); constexpr inline const auto KMemoryRegionType_VirtualDramKernelPtHeap = KMemoryRegionType_Dram.DeriveSparse(1, 4, 1); constexpr inline const auto KMemoryRegionType_VirtualDramKernelTraceBuffer = KMemoryRegionType_Dram.DeriveSparse(1, 4, 2); static_assert(KMemoryRegionType_VirtualDramHeapBase .GetValue() == 0x1A); static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A); static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A); /* UNUSED: .DeriveSparse(2, 2, 0); */ constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.Advance(2).Derive(4, 0); constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.Advance(2).Derive(4, 1); /* UNUSED: .Derive(4, 2); */ constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown = KMemoryRegionType_Dram.Advance(2).Derive(4, 3); static_assert(KMemoryRegionType_VirtualDramUnknownDebug .GetValue() == (0x32)); static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52)); static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown .GetValue() == (0x92)); constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0); constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1); constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2); /* UNUSED: .Derive(4, 3); */ static_assert(KMemoryRegionType_VirtualDramKernelInitPt .GetValue() == 0x31A); static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A); static_assert(KMemoryRegionType_VirtualDramUserPool .GetValue() == 0x61A); constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 0); constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 1); constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 2); constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 3); static_assert(KMemoryRegionType_VirtualDramApplicationPool .GetValue() == 0x361A); static_assert(KMemoryRegionType_VirtualDramAppletPool .GetValue() == 0x561A); static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A); static_assert(KMemoryRegionType_VirtualDramSystemPool .GetValue() == 0x961A); constexpr inline const auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly(); constexpr inline const auto KMemoryRegionType_BoardDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly(); static_assert(KMemoryRegionType_ArchDeviceBase .GetValue() == 0x5); static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5); #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_memory_region_device_types.inc> #elif defined(ATMOSPHERE_ARCH_ARM) #include <mesosphere/arch/arm/kern_k_memory_region_device_types.inc> #else /* Default to no architecture devices. */ constexpr inline const auto NumArchitectureDeviceRegions = 0; #endif static_assert(NumArchitectureDeviceRegions >= 0); #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc> #else /* Default to no board devices. */ constexpr inline const auto NumBoardDeviceRegions = 0; #endif static_assert(NumBoardDeviceRegions >= 0); constexpr inline const auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0); constexpr inline const auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1); constexpr inline const auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2); constexpr inline const auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3); static_assert(KMemoryRegionType_KernelCode .GetValue() == 0x19); static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29); static_assert(KMemoryRegionType_KernelMisc .GetValue() == 0x49); static_assert(KMemoryRegionType_KernelSlab .GetValue() == 0x89); constexpr inline const auto KMemoryRegionType_KernelMiscDerivedBase = KMemoryRegionType_KernelMisc.DeriveTransition(); static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149); /* UNUSED: .Derive(7, 0); */ constexpr inline const auto KMemoryRegionType_KernelMiscMainStack = KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1); constexpr inline const auto KMemoryRegionType_KernelMiscMappedDevice = KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2); constexpr inline const auto KMemoryRegionType_KernelMiscExceptionStack = KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3); constexpr inline const auto KMemoryRegionType_KernelMiscUnknownDebug = KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4); /* UNUSED: .Derive(7, 5); */ constexpr inline const auto KMemoryRegionType_KernelMiscIdleStack = KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6); static_assert(KMemoryRegionType_KernelMiscMainStack .GetValue() == 0xB49); static_assert(KMemoryRegionType_KernelMiscMappedDevice .GetValue() == 0xD49); static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349); static_assert(KMemoryRegionType_KernelMiscUnknownDebug .GetValue() == 0x1549); static_assert(KMemoryRegionType_KernelMiscIdleStack .GetValue() == 0x2349); constexpr inline const auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0); static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31); constexpr ALWAYS_INLINE KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) { if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelPtHeap; } else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelSecureAppletMemory; } else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelSecureUnknown; } else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelTraceBuffer; } else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) { return KMemoryRegionType_VirtualDramUnknownDebug; } else { return KMemoryRegionType_Dram; } } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_object_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KObjectName : public KSlabAllocated<KObjectName>, public util::IntrusiveListBaseNode<KObjectName> { public: static constexpr size_t NameLengthMax = 12; using List = util::IntrusiveListBaseTraits<KObjectName>::ListType; private: char m_name[NameLengthMax]; KAutoObject *m_object; public: static Result NewFromName(KAutoObject *obj, const char *name); static Result Delete(KAutoObject *obj, const char *name); static KScopedAutoObject<KAutoObject> Find(const char *name); template<typename Derived> static Result Delete(const char *name) { /* Find the object. */ KScopedAutoObject obj = Find(name); R_UNLESS(obj.IsNotNull(), svc::ResultNotFound()); /* Cast the object to the desired type. */ Derived *derived = obj->DynamicCast<Derived *>(); R_UNLESS(derived != nullptr, svc::ResultNotFound()); /* Check that the object is closed. */ R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState()); R_RETURN(Delete(obj.GetPointerUnsafe(), name)); } template<typename Derived> requires std::derived_from<Derived, KAutoObject> static KScopedAutoObject<Derived> Find(const char *name) { return Find(name); } private: static KScopedAutoObject<KAutoObject> FindImpl(const char *name); void Initialize(KAutoObject *obj, const char *name); bool MatchesName(const char *name) const; KAutoObject *GetObject() const { return m_object; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_bitmap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_system_control.hpp> namespace ams::kern { class KPageBitmap { public: class RandomBitGenerator { private: util::TinyMT m_rng; u32 m_entropy; u32 m_bits_available; private: void RefreshEntropy() { m_entropy = m_rng.GenerateRandomU32(); m_bits_available = BITSIZEOF(m_entropy); } bool GenerateRandomBit() { if (m_bits_available == 0) { this->RefreshEntropy(); } const bool rnd_bit = (m_entropy & 1) != 0; m_entropy >>= 1; --m_bits_available; return rnd_bit; } u64 GenerateRandomBits(u32 num_bits) { u64 result = 0; /* Iteratively add random bits to our result. */ while (num_bits > 0) { /* Ensure we have random bits to take from. */ if (m_bits_available == 0) { this->RefreshEntropy(); } /* Determine how many bits to take this round. */ const auto cur_bits = std::min(num_bits, m_bits_available); /* Generate mask for our current bits. */ const u64 mask = (static_cast<u64>(1) << cur_bits) - 1; /* Add bits to output from our entropy. */ result <<= cur_bits; result |= (m_entropy & mask); /* Remove bits from our entropy. */ m_entropy >>= cur_bits; m_bits_available -= cur_bits; /* Advance. */ num_bits -= cur_bits; } return result; } public: RandomBitGenerator() : m_entropy(), m_bits_available() { m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64())); } u64 SelectRandomBit(u64 bitmap) { u64 selected = 0; for (size_t cur_num_bits = BITSIZEOF(bitmap) / 2; cur_num_bits != 0; cur_num_bits /= 2) { const u64 high = (bitmap >> cur_num_bits); const u64 low = (bitmap & (~(UINT64_C(0xFFFFFFFFFFFFFFFF) << cur_num_bits))); /* Choose high if we have high and (don't have low or select high randomly). */ if (high && (low == 0 || this->GenerateRandomBit())) { bitmap = high; selected += cur_num_bits; } else { bitmap = low; selected += 0; } } return selected; } u64 GenerateRandom(u64 max) { /* Determine the number of bits we need. */ const u64 bits_needed = 1 + (BITSIZEOF(max) - util::CountLeadingZeros(max)); /* Generate a random value of the desired bitwidth. */ const u64 rnd = this->GenerateRandomBits(bits_needed); /* Adjust the value to be in range. */ return rnd - ((rnd / max) * max); } }; public: static constexpr size_t MaxDepth = 4; private: u64 *m_bit_storages[MaxDepth]; u64 *m_end_storages[MaxDepth]; RandomBitGenerator m_rng; size_t m_num_bits; size_t m_used_depths; public: KPageBitmap() : m_bit_storages(), m_end_storages(), m_rng(), m_num_bits(), m_used_depths() { /* ... */ } constexpr size_t GetNumBits() const { return m_num_bits; } constexpr s32 GetHighestDepthIndex() const { return static_cast<s32>(m_used_depths) - 1; } u64 *Initialize(u64 *storage, size_t size) { /* Initially, everything is un-set. */ m_num_bits = 0; /* Calculate the needed bitmap depth. */ m_used_depths = static_cast<size_t>(GetRequiredDepth(size)); MESOSPHERE_ASSERT(m_used_depths <= MaxDepth); /* Set the bitmap pointers. */ for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) { m_bit_storages[depth] = storage; size = util::AlignUp(size, BITSIZEOF(u64)) / BITSIZEOF(u64); storage += size; m_end_storages[depth] = storage; } return storage; } ssize_t FindFreeBlock(bool random) { uintptr_t offset = 0; s32 depth = 0; if (random) { do { const u64 v = m_bit_storages[depth][offset]; if (v == 0) { /* If depth is bigger than zero, then a previous level indicated a block was free. */ MESOSPHERE_ASSERT(depth == 0); return -1; } offset = offset * BITSIZEOF(u64) + m_rng.SelectRandomBit(v); ++depth; } while (depth < static_cast<s32>(m_used_depths)); } else { do { const u64 v = m_bit_storages[depth][offset]; if (v == 0) { /* If depth is bigger than zero, then a previous level indicated a block was free. */ MESOSPHERE_ASSERT(depth == 0); return -1; } offset = offset * BITSIZEOF(u64) + __builtin_ctzll(v); ++depth; } while (depth < static_cast<s32>(m_used_depths)); } return static_cast<ssize_t>(offset); } ssize_t FindFreeRange(size_t count) { /* Check that it is possible to find a range. */ const u64 * const storage_start = m_bit_storages[m_used_depths - 1]; const u64 * const storage_end = m_end_storages[m_used_depths - 1]; /* If we don't have a storage to iterate (or want more blocks than fit in a single storage), we can't find a free range. */ if (!(storage_start < storage_end && count <= BITSIZEOF(u64))) { return -1; } /* Walk the storages to select a random free range. */ const size_t options_per_storage = std::max<size_t>(BITSIZEOF(u64) / count, 1); const size_t num_entries = std::max<size_t>(storage_end - storage_start, 1); const u64 free_mask = (static_cast<u64>(1) << count) - 1; size_t num_valid_options = 0; ssize_t chosen_offset = -1; for (size_t storage_index = 0; storage_index < num_entries; ++storage_index) { u64 storage = storage_start[storage_index]; for (size_t option = 0; option < options_per_storage; ++option) { if ((storage & free_mask) == free_mask) { /* We've found a new valid option. */ ++num_valid_options; /* Select the Kth valid option with probability 1/K. This leads to an overall uniform distribution. */ if (num_valid_options == 1 || m_rng.GenerateRandom(num_valid_options) == 0) { /* This is our first option, so select it. */ chosen_offset = storage_index * BITSIZEOF(u64) + option * count; } } storage >>= count; } } /* Return the random offset we chose.*/ return chosen_offset; } void SetBit(size_t offset) { this->SetBit(this->GetHighestDepthIndex(), offset); m_num_bits++; } void ClearBit(size_t offset) { this->ClearBit(this->GetHighestDepthIndex(), offset); m_num_bits--; } bool ClearRange(size_t offset, size_t count) { s32 depth = this->GetHighestDepthIndex(); u64 *bits = m_bit_storages[depth]; size_t bit_ind = offset / BITSIZEOF(u64); if (AMS_LIKELY(count < BITSIZEOF(u64))) { const size_t shift = offset % BITSIZEOF(u64); MESOSPHERE_ASSERT(shift + count <= BITSIZEOF(u64)); /* Check that all the bits are set. */ const u64 mask = ((u64(1) << count) - 1) << shift; u64 v = bits[bit_ind]; if ((v & mask) != mask) { return false; } /* Clear the bits. */ v &= ~mask; bits[bit_ind] = v; if (v == 0) { this->ClearBit(depth - 1, bit_ind); } } else { MESOSPHERE_ASSERT(offset % BITSIZEOF(u64) == 0); MESOSPHERE_ASSERT(count % BITSIZEOF(u64) == 0); /* Check that all the bits are set. */ size_t remaining = count; size_t i = 0; do { if (bits[bit_ind + i++] != ~u64(0)) { return false; } remaining -= BITSIZEOF(u64); } while (remaining > 0); /* Clear the bits. */ remaining = count; i = 0; do { bits[bit_ind + i] = 0; this->ClearBit(depth - 1, bit_ind + i); i++; remaining -= BITSIZEOF(u64); } while (remaining > 0); } m_num_bits -= count; return true; } private: void SetBit(s32 depth, size_t offset) { while (depth >= 0) { size_t ind = offset / BITSIZEOF(u64); size_t which = offset % BITSIZEOF(u64); const u64 mask = u64(1) << which; u64 *bit = std::addressof(m_bit_storages[depth][ind]); u64 v = *bit; MESOSPHERE_ASSERT((v & mask) == 0); *bit = v | mask; if (v) { break; } offset = ind; depth--; } } void ClearBit(s32 depth, size_t offset) { while (depth >= 0) { size_t ind = offset / BITSIZEOF(u64); size_t which = offset % BITSIZEOF(u64); const u64 mask = u64(1) << which; u64 *bit = std::addressof(m_bit_storages[depth][ind]); u64 v = *bit; MESOSPHERE_ASSERT((v & mask) != 0); v &= ~mask; *bit = v; if (v) { break; } offset = ind; depth--; } } private: static constexpr s32 GetRequiredDepth(size_t region_size) { s32 depth = 0; while (true) { region_size /= BITSIZEOF(u64); depth++; if (region_size == 0) { return depth; } } } public: static constexpr size_t CalculateManagementOverheadSize(size_t region_size) { size_t overhead_bits = 0; for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) { region_size = util::AlignUp(region_size, BITSIZEOF(u64)) / BITSIZEOF(u64); overhead_bits += region_size; } return overhead_bits * sizeof(u64); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_buffer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #include <mesosphere/kern_k_dynamic_page_manager.hpp> namespace ams::kern { class KDynamicPageManager; class KPageBuffer; class KPageBufferSlabHeap : protected impl::KSlabHeapImpl { public: static constexpr size_t BufferSize = PageSize; static constinit inline size_t s_buffer_count = 0; private: size_t m_obj_size{}; public: constexpr KPageBufferSlabHeap() = default; /* See kern_init_slab_setup.cpp for definition. */ void Initialize(KDynamicPageManager &allocator); KPageBuffer *Allocate(); void Free(KPageBuffer *pb); }; class KPageBuffer { private: u8 m_buffer[KPageBufferSlabHeap::BufferSize]; public: KPageBuffer() { std::memset(m_buffer, 0, sizeof(m_buffer)); } ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() const { return KMemoryLayout::GetLinearPhysicalAddress(KVirtualAddress(this)); } static ALWAYS_INLINE KPageBuffer *FromPhysicalAddress(KPhysicalAddress phys_addr) { const KVirtualAddress virt_addr = KMemoryLayout::GetLinearVirtualAddress(phys_addr); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); return GetPointer<KPageBuffer>(virt_addr); } private: static constinit inline KPageBufferSlabHeap s_slab_heap; public: static void InitializeSlabHeap(KDynamicPageManager &allocator) { s_slab_heap.Initialize(allocator); } static KPageBuffer *Allocate() { return s_slab_heap.Allocate(); } static void Free(KPageBuffer *obj) { s_slab_heap.Free(obj); } template<size_t ExpectedSize> static ALWAYS_INLINE KPageBuffer *AllocateChecked() { /* Check that the allocation is valid. */ MESOSPHERE_ABORT_UNLESS(sizeof(KPageBuffer) == ExpectedSize); return Allocate(); } template<size_t ExpectedSize> static ALWAYS_INLINE void FreeChecked(KPageBuffer *obj) { /* Check that the free is valid. */ MESOSPHERE_ABORT_UNLESS(sizeof(KPageBuffer) == ExpectedSize); return Free(obj); } }; static_assert(sizeof(KPageBuffer) == KPageBufferSlabHeap::BufferSize); ALWAYS_INLINE KPageBuffer *KPageBufferSlabHeap::Allocate() { KPageBuffer *pb = static_cast<KPageBuffer *>(KSlabHeapImpl::Allocate()); if (AMS_LIKELY(pb != nullptr)) { std::construct_at(pb); } return pb; } ALWAYS_INLINE void KPageBufferSlabHeap::Free(KPageBuffer *pb) { KSlabHeapImpl::Free(pb); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_group.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KBlockInfoManager; class KPageGroup; class KBlockInfo { private: friend class KPageGroup; private: KBlockInfo *m_next; u32 m_page_index; u32 m_num_pages; public: KBlockInfo() : m_next(nullptr) { /* ... */ } constexpr ALWAYS_INLINE void Initialize(KPhysicalAddress addr, size_t np) { MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), PageSize)); MESOSPHERE_ASSERT(static_cast<u32>(np) == np); m_page_index = GetInteger(addr) / PageSize; m_num_pages = np; } constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_page_index * PageSize; } constexpr ALWAYS_INLINE size_t GetNumPages() const { return m_num_pages; } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetNumPages() * PageSize; } constexpr ALWAYS_INLINE KPhysicalAddress GetEndAddress() const { return (m_page_index + m_num_pages) * PageSize; } constexpr ALWAYS_INLINE KPhysicalAddress GetLastAddress() const { return this->GetEndAddress() - 1; } constexpr ALWAYS_INLINE KBlockInfo *GetNext() const { return m_next; } constexpr ALWAYS_INLINE bool IsEquivalentTo(const KBlockInfo &rhs) const { return m_page_index == rhs.m_page_index && m_num_pages == rhs.m_num_pages; } constexpr ALWAYS_INLINE bool operator==(const KBlockInfo &rhs) const { return this->IsEquivalentTo(rhs); } constexpr ALWAYS_INLINE bool operator!=(const KBlockInfo &rhs) const { return !(*this == rhs); } constexpr ALWAYS_INLINE bool IsStrictlyBefore(KPhysicalAddress addr) const { const KPhysicalAddress end = this->GetEndAddress(); if (m_page_index != 0 && end == Null<KPhysicalAddress>) { return false; } return end < addr; } constexpr ALWAYS_INLINE bool operator<(KPhysicalAddress addr) const { return this->IsStrictlyBefore(addr); } constexpr ALWAYS_INLINE bool TryConcatenate(KPhysicalAddress addr, size_t np) { if (addr != Null<KPhysicalAddress> && addr == this->GetEndAddress()) { m_num_pages += np; return true; } return false; } private: constexpr ALWAYS_INLINE void SetNext(KBlockInfo *next) { m_next = next; } }; static_assert(sizeof(KBlockInfo) <= 0x10); class KPageGroup { public: class Iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = const KBlockInfo; using difference_type = std::ptrdiff_t; using pointer = value_type *; using reference = value_type &; private: pointer m_node; public: constexpr explicit ALWAYS_INLINE Iterator(pointer n) : m_node(n) { /* ... */ } constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const { return m_node == rhs.m_node; } constexpr ALWAYS_INLINE bool operator!=(const Iterator &rhs) const { return !(*this == rhs); } constexpr ALWAYS_INLINE pointer operator->() const { return m_node; } constexpr ALWAYS_INLINE reference operator*() const { return *m_node; } constexpr ALWAYS_INLINE Iterator &operator++() { m_node = m_node->GetNext(); return *this; } constexpr ALWAYS_INLINE Iterator operator++(int) { const Iterator it{*this}; ++(*this); return it; } }; private: KBlockInfo *m_first_block; KBlockInfo *m_last_block; KBlockInfoManager *m_manager; public: explicit KPageGroup(KBlockInfoManager *m) : m_first_block(), m_last_block(), m_manager(m) { /* ... */ } ~KPageGroup() { this->Finalize(); } void CloseAndReset(); void Finalize(); ALWAYS_INLINE Iterator begin() const { return Iterator{m_first_block}; } ALWAYS_INLINE Iterator end() const { return Iterator{nullptr}; } ALWAYS_INLINE bool empty() const { return m_first_block == nullptr; } Result AddBlock(KPhysicalAddress addr, size_t num_pages); void Open() const; void OpenFirst() const; void Close() const; size_t GetNumPages() const; bool IsEquivalentTo(const KPageGroup &rhs) const; Result CopyRangeTo(KPageGroup &out, size_t offset, size_t size) const; ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const { return this->IsEquivalentTo(rhs); } ALWAYS_INLINE bool operator!=(const KPageGroup &rhs) const { return !(*this == rhs); } }; class KScopedPageGroup { private: const KPageGroup *m_pg; public: explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp, bool not_first = true) : m_pg(gp) { if (m_pg) { if (not_first) { m_pg->Open(); } else { m_pg->OpenFirst(); } } } explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp, bool not_first = true) : KScopedPageGroup(std::addressof(gp), not_first) { /* ... */ } ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } } ALWAYS_INLINE void CancelClose() { m_pg = nullptr; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_page_bitmap.hpp> namespace ams::kern { class KPageHeap { private: static constexpr inline size_t MemoryBlockPageShifts[] = { 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E }; static constexpr size_t NumMemoryBlockPageShifts = util::size(MemoryBlockPageShifts); public: static constexpr s32 GetAlignedBlockIndex(size_t num_pages, size_t align_pages) { const size_t target_pages = std::max(num_pages, align_pages); for (size_t i = 0; i < NumMemoryBlockPageShifts; i++) { if (target_pages <= (static_cast<size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) { return static_cast<s32>(i); } } return -1; } static constexpr s32 GetBlockIndex(size_t num_pages) { for (s32 i = static_cast<s32>(NumMemoryBlockPageShifts) - 1; i >= 0; i--) { if (num_pages >= (static_cast<size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) { return i; } } return -1; } static constexpr size_t GetBlockSize(size_t index) { return static_cast<size_t>(1) << MemoryBlockPageShifts[index]; } static constexpr size_t GetBlockNumPages(size_t index) { return GetBlockSize(index) / PageSize; } private: class Block { private: KPageBitmap m_bitmap; KPhysicalAddress m_heap_address; uintptr_t m_end_offset; size_t m_block_shift; size_t m_next_block_shift; public: Block() : m_bitmap(), m_heap_address(Null<KPhysicalAddress>), m_end_offset(), m_block_shift(), m_next_block_shift() { /* ... */ } constexpr size_t GetShift() const { return m_block_shift; } constexpr size_t GetNextShift() const { return m_next_block_shift; } constexpr size_t GetSize() const { return u64(1) << this->GetShift(); } constexpr size_t GetNumPages() const { return this->GetSize() / PageSize; } constexpr size_t GetNumFreeBlocks() const { return m_bitmap.GetNumBits(); } constexpr size_t GetNumFreePages() const { return this->GetNumFreeBlocks() * this->GetNumPages(); } u64 *Initialize(KPhysicalAddress addr, size_t size, size_t bs, size_t nbs, u64 *bit_storage) { /* Set shifts. */ m_block_shift = bs; m_next_block_shift = nbs; /* Align up the address. */ KPhysicalAddress end = addr + size; const size_t align = (m_next_block_shift != 0) ? (u64(1) << m_next_block_shift) : (u64(1) << m_block_shift); addr = util::AlignDown(GetInteger(addr), align); end = util::AlignUp(GetInteger(end), align); m_heap_address = addr; m_end_offset = (end - addr) / (u64(1) << m_block_shift); return m_bitmap.Initialize(bit_storage, m_end_offset); } KPhysicalAddress PushBlock(KPhysicalAddress address) { /* Set the bit for the free block. */ size_t offset = (address - m_heap_address) >> this->GetShift(); m_bitmap.SetBit(offset); /* If we have a next shift, try to clear the blocks below this one and return the new address. */ if (this->GetNextShift()) { const size_t diff = u64(1) << (this->GetNextShift() - this->GetShift()); offset = util::AlignDown(offset, diff); if (m_bitmap.ClearRange(offset, diff)) { return m_heap_address + (offset << this->GetShift()); } } /* We couldn't coalesce, or we're already as big as possible. */ return Null<KPhysicalAddress>; } KPhysicalAddress PopBlock(bool random) { /* Find a free block. */ ssize_t soffset = m_bitmap.FindFreeBlock(random); if (soffset < 0) { return Null<KPhysicalAddress>; } const size_t offset = static_cast<size_t>(soffset); /* Update our tracking and return it. */ m_bitmap.ClearBit(offset); return m_heap_address + (offset << this->GetShift()); } public: static constexpr size_t CalculateManagementOverheadSize(size_t region_size, size_t cur_block_shift, size_t next_block_shift) { const size_t cur_block_size = (u64(1) << cur_block_shift); const size_t next_block_size = (u64(1) << next_block_shift); const size_t align = (next_block_shift != 0) ? next_block_size : cur_block_size; return KPageBitmap::CalculateManagementOverheadSize((align * 2 + util::AlignUp(region_size, align)) / cur_block_size); } }; private: KPhysicalAddress m_heap_address; size_t m_heap_size; size_t m_initial_used_size; size_t m_num_blocks; Block m_blocks[NumMemoryBlockPageShifts]; KPageBitmap::RandomBitGenerator m_rng; private: void Initialize(KPhysicalAddress heap_address, size_t heap_size, KVirtualAddress management_address, size_t management_size, const size_t *block_shifts, size_t num_block_shifts); size_t GetNumFreePages() const; void FreeBlock(KPhysicalAddress block, s32 index); public: KPageHeap() : m_heap_address(Null<KPhysicalAddress>), m_heap_size(), m_initial_used_size(), m_num_blocks(), m_blocks(), m_rng() { /* ... */ } constexpr KPhysicalAddress GetAddress() const { return m_heap_address; } constexpr size_t GetSize() const { return m_heap_size; } constexpr KPhysicalAddress GetEndAddress() const { return this->GetAddress() + this->GetSize(); } constexpr size_t GetPageOffset(KPhysicalAddress block) const { return (block - this->GetAddress()) / PageSize; } constexpr size_t GetPageOffsetToEnd(KPhysicalAddress block) const { return (this->GetEndAddress() - block) / PageSize; } void Initialize(KPhysicalAddress heap_address, size_t heap_size, KVirtualAddress management_address, size_t management_size) { return this->Initialize(heap_address, heap_size, management_address, management_size, MemoryBlockPageShifts, NumMemoryBlockPageShifts); } size_t GetFreeSize() const { return this->GetNumFreePages() * PageSize; } void DumpFreeList() const; void SetInitialUsedSize(size_t reserved_size) { /* Check that the reserved size is valid. */ const size_t free_size = this->GetNumFreePages() * PageSize; MESOSPHERE_ABORT_UNLESS(m_heap_size >= free_size + reserved_size); /* Set the initial used size. */ m_initial_used_size = m_heap_size - free_size - reserved_size; } KPhysicalAddress AllocateBlock(s32 index, bool random) { if (random) { const size_t block_pages = m_blocks[index].GetNumPages(); return this->AllocateByRandom(index, block_pages, block_pages); } else { return this->AllocateByLinearSearch(index); } } KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) { /* TODO: linear search support? */ return this->AllocateByRandom(index, num_pages, align_pages); } void Free(KPhysicalAddress addr, size_t num_pages); private: KPhysicalAddress AllocateByLinearSearch(s32 index); KPhysicalAddress AllocateByRandom(s32 index, size_t num_pages, size_t align_pages); static size_t CalculateManagementOverheadSize(size_t region_size, const size_t *block_shifts, size_t num_block_shifts); public: static size_t CalculateManagementOverheadSize(size_t region_size) { return CalculateManagementOverheadSize(region_size, MemoryBlockPageShifts, NumMemoryBlockPageShifts); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_page_table_impl.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_k_page_group.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #include <mesosphere/kern_k_memory_block_manager.hpp> namespace ams::kern { enum DisableMergeAttribute : u8 { DisableMergeAttribute_None = (0u << 0), DisableMergeAttribute_DisableHead = (1u << 0), DisableMergeAttribute_DisableHeadAndBody = (1u << 1), DisableMergeAttribute_EnableHeadAndBody = (1u << 2), DisableMergeAttribute_DisableTail = (1u << 3), DisableMergeAttribute_EnableTail = (1u << 4), DisableMergeAttribute_EnableAndMergeHeadBodyTail = (1u << 5), DisableMergeAttribute_EnableHeadBodyTail = DisableMergeAttribute_EnableHeadAndBody | DisableMergeAttribute_EnableTail, DisableMergeAttribute_DisableHeadBodyTail = DisableMergeAttribute_DisableHeadAndBody | DisableMergeAttribute_DisableTail, }; struct KPageProperties { KMemoryPermission perm; bool io; bool uncached; DisableMergeAttribute disable_merge_attributes; }; static_assert(std::is_trivial<KPageProperties>::value); static_assert(sizeof(KPageProperties) == sizeof(u32)); class KResourceLimit; class KSystemResource; class KPageTableBase { NON_COPYABLE(KPageTableBase); NON_MOVEABLE(KPageTableBase); public: using TraversalEntry = KPageTableImpl::TraversalEntry; using TraversalContext = KPageTableImpl::TraversalContext; class MemoryRange { private: KPhysicalAddress m_address; size_t m_size; bool m_heap; u8 m_attr; public: constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false), m_attr(0) { /* ... */ } void Set(KPhysicalAddress address, size_t size, bool heap, u8 attr) { m_address = address; m_size = size; m_heap = heap; m_attr = attr; } constexpr KPhysicalAddress GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr bool IsHeap() const { return m_heap; } constexpr u8 GetAttribute() const { return m_attr; } void Open(); void Close(); }; protected: enum MemoryFillValue { MemoryFillValue_Zero = 0, MemoryFillValue_Stack = 'X', MemoryFillValue_Ipc = 'Y', MemoryFillValue_Heap = 'Z', }; enum RegionType { RegionType_KernelMap = 0, RegionType_Stack = 1, RegionType_Alias = 2, RegionType_Heap = 3, RegionType_Count, }; enum OperationType { OperationType_Map = 0, OperationType_MapGroup = 1, OperationType_MapFirstGroup = 2, OperationType_Unmap = 3, OperationType_ChangePermissions = 4, OperationType_ChangePermissionsAndRefresh = 5, OperationType_ChangePermissionsAndRefreshAndFlush = 6, OperationType_Separate = 7, }; static constexpr size_t MaxPhysicalMapAlignment = 1_GB; static constexpr size_t RegionAlignment = 2_MB; static_assert(RegionAlignment == KernelAslrAlignment); struct PageLinkedList { private: struct Node { Node *m_next; u8 m_buffer[PageSize - sizeof(Node *)]; }; static_assert(util::is_pod<Node>::value); private: Node *m_root; public: constexpr PageLinkedList() : m_root(nullptr) { /* ... */ } void Push(Node *n) { MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(n), PageSize)); n->m_next = m_root; m_root = n; } void Push(KVirtualAddress addr) { this->Push(GetPointer<Node>(addr)); } Node *Peek() const { return m_root; } Node *Pop() { Node * const r = m_root; m_root = r->m_next; r->m_next = nullptr; return r; } }; static_assert(std::is_trivially_destructible<PageLinkedList>::value); static constexpr u32 DefaultMemoryIgnoreAttr = KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared; static constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag as_type) { switch (static_cast<ams::svc::CreateProcessFlag>(as_type & ams::svc::CreateProcessFlag_AddressSpaceMask)) { case ams::svc::CreateProcessFlag_AddressSpace64Bit: return 39; case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated: return 36; case ams::svc::CreateProcessFlag_AddressSpace32Bit: case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias: return 32; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } private: class KScopedPageTableUpdater { private: KPageTableBase *m_pt; PageLinkedList m_ll; public: ALWAYS_INLINE explicit KScopedPageTableUpdater(KPageTableBase *pt) : m_pt(pt), m_ll() { /* ... */ } ALWAYS_INLINE explicit KScopedPageTableUpdater(KPageTableBase &pt) : KScopedPageTableUpdater(std::addressof(pt)) { /* ... */ } ALWAYS_INLINE ~KScopedPageTableUpdater() { m_pt->FinalizeUpdate(this->GetPageList()); } PageLinkedList *GetPageList() { return std::addressof(m_ll); } }; private: KProcessAddress m_address_space_start; KProcessAddress m_address_space_end; KProcessAddress m_region_starts[RegionType_Count]; KProcessAddress m_region_ends[RegionType_Count]; KProcessAddress m_current_heap_end; KProcessAddress m_alias_code_region_start; KProcessAddress m_alias_code_region_end; KProcessAddress m_code_region_start; KProcessAddress m_code_region_end; size_t m_max_heap_size; size_t m_mapped_physical_memory_size; size_t m_mapped_unsafe_physical_memory; size_t m_mapped_insecure_memory; size_t m_mapped_ipc_server_memory; size_t m_alias_region_extra_size; mutable KLightLock m_general_lock; mutable KLightLock m_map_physical_memory_lock; KLightLock m_device_map_lock; KPageTableImpl m_impl; KMemoryBlockManager m_memory_block_manager; u32 m_allocate_option; u32 m_address_space_width; bool m_is_kernel; bool m_enable_aslr; bool m_enable_device_address_space_merge; KMemoryBlockSlabManager *m_memory_block_slab_manager; KBlockInfoManager *m_block_info_manager; KResourceLimit *m_resource_limit; const KMemoryRegion *m_cached_physical_linear_region; const KMemoryRegion *m_cached_physical_heap_region; MemoryFillValue m_heap_fill_value; MemoryFillValue m_ipc_fill_value; MemoryFillValue m_stack_fill_value; public: constexpr explicit KPageTableBase(util::ConstantInitializeTag) : m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>), m_region_starts{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>}, m_region_ends{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>}, m_current_heap_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>), m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>), m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(), m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize), m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(), m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(), m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value() { /* ... */ } explicit KPageTableBase() { /* ... */ } NOINLINE void InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end); NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit); void Finalize(); constexpr bool IsKernel() const { return m_is_kernel; } constexpr bool IsAslrEnabled() const { return m_enable_aslr; } constexpr bool Contains(KProcessAddress addr) const { return m_address_space_start <= addr && addr <= m_address_space_end - 1; } constexpr bool Contains(KProcessAddress addr, size_t size) const { return m_address_space_start <= addr && addr < addr + size && addr + size - 1 <= m_address_space_end - 1; } constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const { return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1; } bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { /* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */ return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode); } ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() { return KScopedLightLock(m_device_map_lock); } KProcessAddress GetRegionAddress(ams::svc::MemoryState state) const; size_t GetRegionSize(ams::svc::MemoryState state) const; bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const; ALWAYS_INLINE KProcessAddress GetRegionAddress(KMemoryState state) const { return this->GetRegionAddress(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); } ALWAYS_INLINE size_t GetRegionSize(KMemoryState state) const { return this->GetRegionSize(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); } ALWAYS_INLINE bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->CanContain(addr, size, static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); } protected: /* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */ /* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */ /* class, and this avoids unnecessary virtual function calls. See "kern_select_page_table.hpp" */ /* for definition of these functions. */ Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll); Result Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll); void FinalizeUpdate(PageLinkedList *page_list); ALWAYS_INLINE KPageTableImpl &GetImpl() { return m_impl; } ALWAYS_INLINE const KPageTableImpl &GetImpl() const { return m_impl; } ALWAYS_INLINE bool IsLockedByCurrentThread() const { return m_general_lock.IsLockedByCurrentThread(); } ALWAYS_INLINE bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); return KMemoryLayout::IsLinearMappedPhysicalAddress(m_cached_physical_linear_region, phys_addr); } ALWAYS_INLINE bool IsLinearMappedPhysicalAddress(KPhysicalAddress phys_addr, size_t size) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); return KMemoryLayout::IsLinearMappedPhysicalAddress(m_cached_physical_linear_region, phys_addr, size); } ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr); } ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr, size_t size) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr, size); } ALWAYS_INLINE bool IsHeapPhysicalAddressForFinalize(KPhysicalAddress phys_addr) { MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread()); return KMemoryLayout::IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr); } ALWAYS_INLINE bool ContainsPages(KProcessAddress addr, size_t num_pages) const { return (m_address_space_start <= addr) && (num_pages <= (m_address_space_end - m_address_space_start) / PageSize) && (addr + num_pages * PageSize - 1 <= m_address_space_end - 1); } private: constexpr size_t GetNumGuardPages() const { return this->IsKernel() ? 1 : 4; } ALWAYS_INLINE KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const; Result CheckMemoryStateContiguous(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const; Result CheckMemoryStateContiguous(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const { R_RETURN(this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr)); } Result CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const; Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const; Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const; Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const { R_RETURN(this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr)); } Result CheckMemoryState(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const { R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr)); } bool CanReadWriteDebugMemory(KProcessAddress addr, size_t size, bool force_debug_prod); Result LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr); Result UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg); Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const; Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const; Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties &properties); Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll); void RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg); Result MakePageGroup(KPageGroup &pg, KProcessAddress addr, size_t num_pages); bool IsValidPageGroup(const KPageGroup &pg, KProcessAddress addr, size_t num_pages); Result GetContiguousMemoryRangeWithState(MemoryRange *out, KProcessAddress address, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr); NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm); Result MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryState state, KMemoryPermission perm); Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size, KMemoryState state); Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size, KMemoryState state); Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state); Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send); void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm); size_t GetSize(KMemoryState state) const; ALWAYS_INLINE bool GetPhysicalAddressLocked(KPhysicalAddress *out, KProcessAddress virt_addr) const { /* Validate pre-conditions. */ MESOSPHERE_AUDIT(this->IsLockedByCurrentThread()); return this->GetImpl().GetPhysicalAddress(out, virt_addr); } public: bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress virt_addr) const { /* Validate pre-conditions. */ MESOSPHERE_AUDIT(!this->IsLockedByCurrentThread()); /* Acquire exclusive access to the table while doing address translation. */ KScopedLightLock lk(m_general_lock); return this->GetPhysicalAddressLocked(out, virt_addr); } KBlockInfoManager *GetBlockInfoManager() const { return m_block_info_manager; } Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm); Result SetProcessMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm); Result SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr); Result SetHeapSize(KProcessAddress *out, size_t size); Result SetMaxHeapSize(size_t size); Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const; Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const; Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Static)); } Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Io)); } Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size); Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size); Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size); Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size); Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm); Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping); Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm); Result MapInsecurePhysicalMemory(KProcessAddress address, size_t size); Result UnmapInsecurePhysicalMemory(KProcessAddress address, size_t size); Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm)); } Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) { R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, this->GetRegionAddress(state), this->GetRegionSize(state) / PageSize, state, perm)); } Result MapPages(KProcessAddress *out_addr, size_t num_pages, KMemoryState state, KMemoryPermission perm) { R_RETURN(this->MapPages(out_addr, num_pages, PageSize, Null<KPhysicalAddress>, false, this->GetRegionAddress(state), this->GetRegionSize(state) / PageSize, state, perm)); } Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm); Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state); Result MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm); Result MapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm); Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state); Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr); Result InvalidateProcessDataCache(KProcessAddress address, size_t size); Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size); Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod); Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state); Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size); Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state); Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap); Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap); Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size); Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size); Result OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned); Result OpenMemoryRangeForUnmapDeviceAddressSpace(MemoryRange *out, KProcessAddress address, size_t size); Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size); Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size); Result LockForTransferMemory(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm); Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup &pg); Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size); Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg); Result OpenMemoryRangeForProcessCacheOperation(MemoryRange *out, KProcessAddress address, size_t size); Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr); Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr); Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr); Result CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr); Result CopyMemoryFromHeapToHeap(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr); Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr); Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send); Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state); Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state); Result MapPhysicalMemory(KProcessAddress address, size_t size); Result UnmapPhysicalMemory(KProcessAddress address, size_t size); Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size); Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size); Result UnmapProcessMemory(KProcessAddress dst_address, size_t size, KPageTableBase &src_pt, KProcessAddress src_address); void DumpMemoryBlocksLocked() const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); m_memory_block_manager.DumpBlocks(); } void DumpMemoryBlocks() const { KScopedLightLock lk(m_general_lock); this->DumpMemoryBlocksLocked(); } void DumpPageTable() const { KScopedLightLock lk(m_general_lock); this->GetImpl().Dump(GetInteger(m_address_space_start), m_address_space_end - m_address_space_start); } size_t CountPageTables() const { KScopedLightLock lk(m_general_lock); return this->GetImpl().CountPageTables(); } public: KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; } KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; } KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; } KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; } KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; } KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; } size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; } size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; } size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; } size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; } size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; } size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; } size_t GetAliasRegionExtraSize() const { return m_alias_region_extra_size; } size_t GetNormalMemorySize() const { /* Lock the table. */ KScopedLightLock lk(m_general_lock); return (m_current_heap_end - m_region_starts[RegionType_Heap]) + m_mapped_physical_memory_size; } size_t GetCodeSize() const; size_t GetCodeDataSize() const; size_t GetAliasCodeSize() const; size_t GetAliasCodeDataSize() const; u32 GetAllocateOption() const { return m_allocate_option; } public: static ALWAYS_INLINE KVirtualAddress GetLinearMappedVirtualAddress(KPhysicalAddress addr) { return KMemoryLayout::GetLinearVirtualAddress(addr); } static ALWAYS_INLINE KPhysicalAddress GetLinearMappedPhysicalAddress(KVirtualAddress addr) { return KMemoryLayout::GetLinearPhysicalAddress(addr); } static ALWAYS_INLINE KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress addr) { return GetLinearMappedVirtualAddress(addr); } static ALWAYS_INLINE KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress addr) { return GetLinearMappedPhysicalAddress(addr); } static ALWAYS_INLINE KVirtualAddress GetPageTableVirtualAddress(KPhysicalAddress addr) { return GetLinearMappedVirtualAddress(addr); } static ALWAYS_INLINE KPhysicalAddress GetPageTablePhysicalAddress(KVirtualAddress addr) { return GetLinearMappedPhysicalAddress(addr); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_table_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_page_table_slab_heap.hpp> #include <mesosphere/kern_k_dynamic_resource_manager.hpp> namespace ams::kern { class KPageTableManager : public KDynamicResourceManager<impl::PageTablePage, true> { public: using RefCount = KPageTableSlabHeap::RefCount; static constexpr size_t PageTableSize = KPageTableSlabHeap::PageTableSize; private: using BaseHeap = KDynamicResourceManager<impl::PageTablePage, true>; private: KPageTableSlabHeap *m_pt_heap; public: constexpr explicit KPageTableManager(util::ConstantInitializeTag) : m_pt_heap() { /* ... */ } explicit KPageTableManager() { /* ... */ } ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, KPageTableSlabHeap *pt_heap) { m_pt_heap = pt_heap; static_assert(std::derived_from<KPageTableSlabHeap, DynamicSlabType>); BaseHeap::Initialize(page_allocator, pt_heap); } KVirtualAddress Allocate() { return KVirtualAddress(BaseHeap::Allocate()); } void Free(KVirtualAddress addr) { return BaseHeap::Free(GetPointer<impl::PageTablePage>(addr)); } ALWAYS_INLINE RefCount GetRefCount(KVirtualAddress addr) const { return m_pt_heap->GetRefCount(addr); } ALWAYS_INLINE void Open(KVirtualAddress addr, int count) { return m_pt_heap->Open(addr, count); } ALWAYS_INLINE bool Close(KVirtualAddress addr, int count) { return m_pt_heap->Close(addr, count); } constexpr ALWAYS_INLINE bool IsInPageTableHeap(KVirtualAddress addr) const { return m_pt_heap->IsInRange(addr); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_page_table_slab_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_dynamic_slab_heap.hpp> namespace ams::kern { namespace impl { class PageTablePage { private: u8 m_buffer[PageSize]; public: ALWAYS_INLINE PageTablePage() { /* Do not initialize anything. */ } }; static_assert(sizeof(PageTablePage) == PageSize); } class KPageTableSlabHeap : public KDynamicSlabHeap<impl::PageTablePage, true> { public: using RefCount = u16; static constexpr size_t PageTableSize = sizeof(impl::PageTablePage); static_assert(PageTableSize == PageSize); private: using BaseHeap = KDynamicSlabHeap<impl::PageTablePage, true>; private: RefCount *m_ref_counts{}; public: static constexpr ALWAYS_INLINE size_t CalculateReferenceCountSize(size_t size) { return (size / PageSize) * sizeof(RefCount); } public: constexpr KPageTableSlabHeap() = default; private: ALWAYS_INLINE void Initialize(RefCount *rc) { m_ref_counts = rc; for (size_t i = 0; i < this->GetSize() / PageSize; i++) { m_ref_counts[i] = 0; } } constexpr ALWAYS_INLINE RefCount *GetRefCountPointer(KVirtualAddress addr) const { return m_ref_counts + ((addr - this->GetAddress()) / PageSize); } public: ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, size_t object_count, RefCount *rc) { BaseHeap::Initialize(page_allocator, object_count); this->Initialize(rc); } ALWAYS_INLINE RefCount GetRefCount(KVirtualAddress addr) const { MESOSPHERE_ASSERT(this->IsInRange(addr)); return *this->GetRefCountPointer(addr); } ALWAYS_INLINE void Open(KVirtualAddress addr, int count) { MESOSPHERE_ASSERT(this->IsInRange(addr)); *this->GetRefCountPointer(addr) += count; MESOSPHERE_ABORT_UNLESS(this->GetRefCount(addr) > 0); } ALWAYS_INLINE bool Close(KVirtualAddress addr, int count) { MESOSPHERE_ASSERT(this->IsInRange(addr)); MESOSPHERE_ABORT_UNLESS(this->GetRefCount(addr) >= count); *this->GetRefCountPointer(addr) -= count; return this->GetRefCount(addr) == 0; } constexpr ALWAYS_INLINE bool IsInPageTableHeap(KVirtualAddress addr) const { return this->IsInRange(addr); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_port.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_client_port.hpp> #include <mesosphere/kern_k_server_port.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KServerSession; class KLightServerSession; class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KPort, KAutoObject); private: enum class State : u8 { Invalid = 0, Normal = 1, ClientClosed = 2, ServerClosed = 3, }; private: KServerPort m_server; KClientPort m_client; uintptr_t m_name; State m_state; bool m_is_light; public: explicit KPort() : m_state(State::Invalid), m_is_light() { /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } void Initialize(s32 max_sessions, bool is_light, uintptr_t name); void Finalize() { /* ... */ } void OnClientClosed(); void OnServerClosed(); uintptr_t GetName() const { return m_name; } bool IsLight() const { return m_is_light; } bool IsServerClosed() const { KScopedSchedulerLock sl; return m_state == State::ServerClosed; } Result EnqueueSession(KServerSession *session); Result EnqueueSession(KLightServerSession *session); KClientPort &GetClientPort() { return m_client; } KServerPort &GetServerPort() { return m_server; } const KClientPort &GetClientPort() const { return m_client; } const KServerPort &GetServerPort() const { return m_server; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_priority_queue.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { template<typename T> concept KPriorityQueueAffinityMask = !std::is_reference<T>::value && requires (T &t) { { t.GetAffinityMask() } -> std::convertible_to<u64>; { t.SetAffinityMask(std::declval<u64>()) }; { t.GetAffinity(std::declval<int32_t>()) } -> std::same_as<bool>; { t.SetAffinity(std::declval<int32_t>(), std::declval<bool>()) }; { t.SetAll() }; }; template<typename T> concept KPriorityQueueMember = !std::is_reference<T>::value && requires (T &t) { { typename T::QueueEntry() }; { (typename T::QueueEntry()).Initialize() }; { (typename T::QueueEntry()).SetPrev(std::addressof(t)) }; { (typename T::QueueEntry()).SetNext(std::addressof(t)) }; { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>; { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>; { t.GetPriorityQueueEntry(std::declval<s32>()) } -> std::same_as<typename T::QueueEntry &>; { t.GetAffinityMask() }; { typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() } -> KPriorityQueueAffinityMask; { t.GetActiveCore() } -> std::convertible_to<s32>; { t.GetPriority() } -> std::convertible_to<s32>; }; template<typename Member, size_t _NumCores, int LowestPriority, int HighestPriority> requires KPriorityQueueMember<Member> class KPriorityQueue { public: using AffinityMaskType = typename std::remove_cv<typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>::type; static_assert(LowestPriority >= 0); static_assert(HighestPriority >= 0); static_assert(LowestPriority >= HighestPriority); static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1; static constexpr size_t NumCores = _NumCores; static constexpr ALWAYS_INLINE bool IsValidCore(s32 core) { return 0 <= core && core < static_cast<s32>(NumCores); } static constexpr ALWAYS_INLINE bool IsValidPriority(s32 priority) { return HighestPriority <= priority && priority <= LowestPriority + 1; } private: using Entry = typename Member::QueueEntry; public: class KPerCoreQueue { private: Entry m_root[NumCores]; public: constexpr ALWAYS_INLINE KPerCoreQueue() : m_root() { for (size_t i = 0; i < NumCores; i++) { m_root[i].Initialize(); } } constexpr ALWAYS_INLINE bool PushBack(s32 core, Member *member) { /* Get the entry associated with the member. */ Entry &member_entry = member->GetPriorityQueueEntry(core); /* Get the entry associated with the end of the queue. */ Member *tail = m_root[core].GetPrev(); Entry &tail_entry = (tail != nullptr) ? tail->GetPriorityQueueEntry(core) : m_root[core]; /* Link the entries. */ member_entry.SetPrev(tail); member_entry.SetNext(nullptr); tail_entry.SetNext(member); m_root[core].SetPrev(member); return (tail == nullptr); } constexpr ALWAYS_INLINE bool PushFront(s32 core, Member *member) { /* Get the entry associated with the member. */ Entry &member_entry = member->GetPriorityQueueEntry(core); /* Get the entry associated with the front of the queue. */ Member *head = m_root[core].GetNext(); Entry &head_entry = (head != nullptr) ? head->GetPriorityQueueEntry(core) : m_root[core]; /* Link the entries. */ member_entry.SetPrev(nullptr); member_entry.SetNext(head); head_entry.SetPrev(member); m_root[core].SetNext(member); return (head == nullptr); } constexpr ALWAYS_INLINE bool Remove(s32 core, Member *member) { /* Get the entry associated with the member. */ Entry &member_entry = member->GetPriorityQueueEntry(core); /* Get the entries associated with next and prev. */ Member *prev = member_entry.GetPrev(); Member *next = member_entry.GetNext(); Entry &prev_entry = (prev != nullptr) ? prev->GetPriorityQueueEntry(core) : m_root[core]; Entry &next_entry = (next != nullptr) ? next->GetPriorityQueueEntry(core) : m_root[core]; /* Unlink. */ prev_entry.SetNext(next); next_entry.SetPrev(prev); return (this->GetFront(core) == nullptr); } constexpr ALWAYS_INLINE Member *GetFront(s32 core) const { return m_root[core].GetNext(); } }; class KPriorityQueueImpl { private: KPerCoreQueue m_queues[NumPriority]; util::BitSet64<NumPriority> m_available_priorities[NumCores]; public: constexpr ALWAYS_INLINE KPriorityQueueImpl() : m_queues(), m_available_priorities() { /* ... */ } constexpr ALWAYS_INLINE void PushBack(s32 priority, s32 core, Member *member) { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { if (m_queues[priority].PushBack(core, member)) { m_available_priorities[core].SetBit(priority); } } } constexpr ALWAYS_INLINE void PushFront(s32 priority, s32 core, Member *member) { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { if (m_queues[priority].PushFront(core, member)) { m_available_priorities[core].SetBit(priority); } } } constexpr ALWAYS_INLINE void Remove(s32 priority, s32 core, Member *member) { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { if (m_queues[priority].Remove(core, member)) { m_available_priorities[core].ClearBit(priority); } } } constexpr ALWAYS_INLINE Member *GetFront(s32 core) const { MESOSPHERE_ASSERT(IsValidCore(core)); const s32 priority = m_available_priorities[core].CountLeadingZero(); if (AMS_LIKELY(priority <= LowestPriority)) { return m_queues[priority].GetFront(core); } else { return nullptr; } } constexpr ALWAYS_INLINE Member *GetFront(s32 priority, s32 core) const { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { return m_queues[priority].GetFront(core); } else { return nullptr; } } constexpr ALWAYS_INLINE Member *GetNext(s32 core, const Member *member) const { MESOSPHERE_ASSERT(IsValidCore(core)); Member *next = member->GetPriorityQueueEntry(core).GetNext(); if (next == nullptr) { const s32 priority = m_available_priorities[core].GetNextSet(member->GetPriority()); if (AMS_LIKELY(priority <= LowestPriority)) { next = m_queues[priority].GetFront(core); } } return next; } constexpr ALWAYS_INLINE void MoveToFront(s32 priority, s32 core, Member *member) { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { m_queues[priority].Remove(core, member); m_queues[priority].PushFront(core, member); } } constexpr ALWAYS_INLINE Member *MoveToBack(s32 priority, s32 core, Member *member) { MESOSPHERE_ASSERT(IsValidCore(core)); MESOSPHERE_ASSERT(IsValidPriority(priority)); if (AMS_LIKELY(priority <= LowestPriority)) { m_queues[priority].Remove(core, member); m_queues[priority].PushBack(core, member); return m_queues[priority].GetFront(core); } else { return nullptr; } } }; private: KPriorityQueueImpl m_scheduled_queue; KPriorityQueueImpl m_suggested_queue; private: static constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) { affinity &= ~(UINT64_C(1) << core); } static constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) { const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity)); ClearAffinityBit(affinity, core); return core; } constexpr ALWAYS_INLINE void PushBack(s32 priority, Member *member) { MESOSPHERE_ASSERT(IsValidPriority(priority)); /* Push onto the scheduled queue for its core, if we can. */ u64 affinity = member->GetAffinityMask().GetAffinityMask(); if (const s32 core = member->GetActiveCore(); core >= 0) { m_scheduled_queue.PushBack(priority, core, member); ClearAffinityBit(affinity, core); } /* And suggest the thread for all other cores. */ while (affinity) { m_suggested_queue.PushBack(priority, GetNextCore(affinity), member); } } constexpr ALWAYS_INLINE void PushFront(s32 priority, Member *member) { MESOSPHERE_ASSERT(IsValidPriority(priority)); /* Push onto the scheduled queue for its core, if we can. */ u64 affinity = member->GetAffinityMask().GetAffinityMask(); if (const s32 core = member->GetActiveCore(); core >= 0) { m_scheduled_queue.PushFront(priority, core, member); ClearAffinityBit(affinity, core); } /* And suggest the thread for all other cores. */ /* Note: Nintendo pushes onto the back of the suggested queue, not the front. */ while (affinity) { m_suggested_queue.PushBack(priority, GetNextCore(affinity), member); } } constexpr ALWAYS_INLINE void Remove(s32 priority, Member *member) { MESOSPHERE_ASSERT(IsValidPriority(priority)); /* Remove from the scheduled queue for its core. */ u64 affinity = member->GetAffinityMask().GetAffinityMask(); if (const s32 core = member->GetActiveCore(); core >= 0) { m_scheduled_queue.Remove(priority, core, member); ClearAffinityBit(affinity, core); } /* Remove from the suggested queue for all other cores. */ while (affinity) { m_suggested_queue.Remove(priority, GetNextCore(affinity), member); } } public: constexpr ALWAYS_INLINE KPriorityQueue() : m_scheduled_queue(), m_suggested_queue() { /* ... */ } /* Getters. */ constexpr ALWAYS_INLINE Member *GetScheduledFront(s32 core) const { return m_scheduled_queue.GetFront(core); } constexpr ALWAYS_INLINE Member *GetScheduledFront(s32 core, s32 priority) const { return m_scheduled_queue.GetFront(priority, core); } constexpr ALWAYS_INLINE Member *GetSuggestedFront(s32 core) const { return m_suggested_queue.GetFront(core); } constexpr ALWAYS_INLINE Member *GetSuggestedFront(s32 core, s32 priority) const { return m_suggested_queue.GetFront(priority, core); } constexpr ALWAYS_INLINE Member *GetScheduledNext(s32 core, const Member *member) const { return m_scheduled_queue.GetNext(core, member); } constexpr ALWAYS_INLINE Member *GetSuggestedNext(s32 core, const Member *member) const { return m_suggested_queue.GetNext(core, member); } constexpr ALWAYS_INLINE Member *GetSamePriorityNext(s32 core, const Member *member) const { return member->GetPriorityQueueEntry(core).GetNext(); } /* Mutators. */ constexpr ALWAYS_INLINE void PushBack(Member *member) { this->PushBack(member->GetPriority(), member); } constexpr ALWAYS_INLINE void Remove(Member *member) { this->Remove(member->GetPriority(), member); } constexpr ALWAYS_INLINE void MoveToScheduledFront(Member *member) { m_scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); } constexpr ALWAYS_INLINE KThread *MoveToScheduledBack(Member *member) { return m_scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), member); } /* First class fancy operations. */ constexpr ALWAYS_INLINE void ChangePriority(s32 prev_priority, bool is_running, Member *member) { MESOSPHERE_ASSERT(IsValidPriority(prev_priority)); /* Remove the member from the queues. */ const s32 new_priority = member->GetPriority(); this->Remove(prev_priority, member); /* And enqueue. If the member is running, we want to keep it running. */ if (is_running) { this->PushFront(new_priority, member); } else { this->PushBack(new_priority, member); } } constexpr ALWAYS_INLINE void ChangeAffinityMask(s32 prev_core, const AffinityMaskType &prev_affinity, Member *member) { /* Get the new information. */ const s32 priority = member->GetPriority(); const AffinityMaskType &new_affinity = member->GetAffinityMask(); const s32 new_core = member->GetActiveCore(); /* Remove the member from all queues it was in before. */ for (s32 core = 0; core < static_cast<s32>(NumCores); core++) { if (prev_affinity.GetAffinity(core)) { if (core == prev_core) { m_scheduled_queue.Remove(priority, core, member); } else { m_suggested_queue.Remove(priority, core, member); } } } /* And add the member to all queues it should be in now. */ for (s32 core = 0; core < static_cast<s32>(NumCores); core++) { if (new_affinity.GetAffinity(core)) { if (core == new_core) { m_scheduled_queue.PushBack(priority, core, member); } else { m_suggested_queue.PushBack(priority, core, member); } } } } constexpr ALWAYS_INLINE void ChangeCore(s32 prev_core, Member *member, bool to_front = false) { /* Get the new information. */ const s32 new_core = member->GetActiveCore(); const s32 priority = member->GetPriority(); /* We don't need to do anything if the core is the same. */ if (prev_core != new_core) { /* Remove from the scheduled queue for the previous core. */ if (prev_core >= 0) { m_scheduled_queue.Remove(priority, prev_core, member); } /* Remove from the suggested queue and add to the scheduled queue for the new core. */ if (new_core >= 0) { m_suggested_queue.Remove(priority, new_core, member); if (to_front) { m_scheduled_queue.PushFront(priority, new_core, member); } else { m_scheduled_queue.PushBack(priority, new_core, member); } } /* Add to the suggested queue for the previous core. */ if (prev_core >= 0) { m_suggested_queue.PushBack(priority, prev_core, member); } } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_process.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_handle_table.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_thread_local_page.hpp> #include <mesosphere/kern_k_shared_memory_info.hpp> #include <mesosphere/kern_k_io_region.hpp> #include <mesosphere/kern_k_worker_task.hpp> #include <mesosphere/kern_select_page_table.hpp> #include <mesosphere/kern_k_condition_variable.hpp> #include <mesosphere/kern_k_address_arbiter.hpp> #include <mesosphere/kern_k_capabilities.hpp> #include <mesosphere/kern_k_wait_object.hpp> #include <mesosphere/kern_k_dynamic_resource_manager.hpp> #include <mesosphere/kern_k_page_table_manager.hpp> #include <mesosphere/kern_k_system_resource.hpp> namespace ams::kern { class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { MESOSPHERE_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); public: enum State { State_Created = ams::svc::ProcessState_Created, State_CreatedAttached = ams::svc::ProcessState_CreatedAttached, State_Running = ams::svc::ProcessState_Running, State_Crashed = ams::svc::ProcessState_Crashed, State_RunningAttached = ams::svc::ProcessState_RunningAttached, State_Terminating = ams::svc::ProcessState_Terminating, State_Terminated = ams::svc::ProcessState_Terminated, State_DebugBreak = ams::svc::ProcessState_DebugBreak, }; using ThreadList = util::IntrusiveListMemberTraits<&KThread::m_process_list_node>::ListType; static constexpr size_t AslrAlignment = KernelAslrAlignment; private: using SharedMemoryInfoList = util::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType; using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_process_list_node>::ListType; using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; using TLPIterator = TLPTree::iterator; private: KProcessPageTable m_page_table; util::Atomic<size_t> m_used_kernel_memory_size; TLPTree m_fully_used_tlp_tree; TLPTree m_partially_used_tlp_tree; s32 m_ideal_core_id; void *m_attached_object; KResourceLimit *m_resource_limit; KSystemResource *m_system_resource; size_t m_memory_release_hint; State m_state; KLightLock m_state_lock; KLightLock m_list_lock; KConditionVariable m_cond_var; KAddressArbiter m_address_arbiter; u64 m_entropy[4]; bool m_is_signaled; bool m_is_initialized; bool m_is_application; bool m_is_default_application_system_resource; char m_name[13]; util::Atomic<u16> m_num_running_threads; u32 m_flags; KMemoryManager::Pool m_memory_pool; s64 m_schedule_count; KCapabilities m_capabilities; ams::svc::ProgramId m_program_id; u64 m_process_id; #if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME) s64 m_creation_time; #endif KProcessAddress m_code_address; size_t m_code_size; size_t m_main_thread_stack_size; size_t m_max_process_memory; u32 m_version; KHandleTable m_handle_table; KProcessAddress m_plr_address; void *m_plr_heap_address; KThread *m_exception_thread; ThreadList m_thread_list; SharedMemoryInfoList m_shared_memory_list; IoRegionList m_io_region_list; bool m_is_suspended; bool m_is_immortal; bool m_is_jit_debug; bool m_is_handle_table_initialized; ams::svc::DebugEvent m_jit_debug_event_type; ams::svc::DebugException m_jit_debug_exception_type; uintptr_t m_jit_debug_params[4]; u64 m_jit_debug_thread_id; KWaitObject m_wait_object; KThread *m_running_threads[cpu::NumCores]; u64 m_running_thread_idle_counts[cpu::NumCores]; u64 m_running_thread_switch_counts[cpu::NumCores]; KThread *m_pinned_threads[cpu::NumCores]; util::Atomic<s64> m_cpu_time; util::Atomic<s64> m_num_process_switches; util::Atomic<s64> m_num_thread_switches; util::Atomic<s64> m_num_fpu_switches; util::Atomic<s64> m_num_supervisor_calls; util::Atomic<s64> m_num_ipc_messages; util::Atomic<s64> m_num_ipc_replies; util::Atomic<s64> m_num_ipc_receives; private: Result Initialize(const ams::svc::CreateProcessParameter ¶ms); Result StartTermination(); void FinishTermination(); ALWAYS_INLINE void PinThread(s32 core_id, KThread *thread) { MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores)); MESOSPHERE_ASSERT(thread != nullptr); MESOSPHERE_ASSERT(m_pinned_threads[core_id] == nullptr); m_pinned_threads[core_id] = thread; } ALWAYS_INLINE void UnpinThread(s32 core_id, KThread *thread) { MESOSPHERE_UNUSED(thread); MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores)); MESOSPHERE_ASSERT(thread != nullptr); MESOSPHERE_ASSERT(m_pinned_threads[core_id] == thread); m_pinned_threads[core_id] = nullptr; } public: explicit KProcess() : m_is_initialized(false) { /* ... */ } Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal); Result Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool); void Exit(); constexpr const char *GetName() const { return m_name; } constexpr ams::svc::ProgramId GetProgramId() const { return m_program_id; } constexpr u64 GetProcessId() const { return m_process_id; } constexpr State GetState() const { return m_state; } constexpr u64 GetCoreMask() const { return m_capabilities.GetCoreMask(); } constexpr u64 GetPhysicalCoreMask() const { return m_capabilities.GetPhysicalCoreMask(); } constexpr u64 GetPriorityMask() const { return m_capabilities.GetPriorityMask(); } constexpr s32 GetIdealCoreId() const { return m_ideal_core_id; } constexpr void SetIdealCoreId(s32 core_id) { m_ideal_core_id = core_id; } constexpr bool CheckThreadPriority(s32 prio) const { return ((1ul << prio) & this->GetPriorityMask()) != 0; } constexpr u32 GetCreateProcessFlags() const { return m_flags; } constexpr bool Is64Bit() const { return m_flags & ams::svc::CreateProcessFlag_Is64Bit; } constexpr KProcessAddress GetEntryPoint() const { return m_code_address; } constexpr size_t GetMainStackSize() const { return m_main_thread_stack_size; } constexpr KMemoryManager::Pool GetMemoryPool() const { return m_memory_pool; } constexpr u64 GetRandomEntropy(size_t i) const { return m_entropy[i]; } constexpr bool IsApplication() const { return m_is_application; } constexpr bool IsDefaultApplicationSystemResource() const { return m_is_default_application_system_resource; } constexpr bool IsSuspended() const { return m_is_suspended; } constexpr void SetSuspended(bool suspended) { m_is_suspended = suspended; } Result Terminate(); constexpr bool IsTerminated() const { return m_state == State_Terminated; } constexpr bool IsAttachedToDebugger() const { return m_attached_object != nullptr; } constexpr bool IsPermittedSvc(svc::SvcId svc_id) const { return m_capabilities.IsPermittedSvc(svc_id); } constexpr bool IsPermittedInterrupt(int32_t interrupt_id) const { return m_capabilities.IsPermittedInterrupt(interrupt_id); } constexpr bool IsPermittedDebug() const { return m_capabilities.IsPermittedDebug(); } constexpr bool CanForceDebugProd() const { return m_capabilities.CanForceDebugProd(); } constexpr bool CanForceDebug() const { return m_capabilities.CanForceDebug(); } u32 GetAllocateOption() const { return m_page_table.GetAllocateOption(); } ThreadList &GetThreadList() { return m_thread_list; } const ThreadList &GetThreadList() const { return m_thread_list; } constexpr void *GetDebugObject() const { return m_attached_object; } KProcess::State SetDebugObject(void *debug_object); void ClearDebugObject(KProcess::State state); bool EnterJitDebug(ams::svc::DebugEvent event, ams::svc::DebugException exception, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0); KEventInfo *GetJitDebugInfo(); void ClearJitDebugInfo(); bool EnterUserException(); bool LeaveUserException(); bool ReleaseUserException(KThread *thread); KThread *GetPinnedThread(s32 core_id) const { MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores)); return m_pinned_threads[core_id]; } const svc::SvcAccessFlagSet &GetSvcPermissions() const { return m_capabilities.GetSvcPermissions(); } constexpr KResourceLimit *GetResourceLimit() const { return m_resource_limit; } bool ReserveResource(ams::svc::LimitableResource which, s64 value); bool ReserveResource(ams::svc::LimitableResource which, s64 value, s64 timeout); void ReleaseResource(ams::svc::LimitableResource which, s64 value); void ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint); constexpr KLightLock &GetStateLock() { return m_state_lock; } constexpr KLightLock &GetListLock() { return m_list_lock; } constexpr KProcessPageTable &GetPageTable() { return m_page_table; } constexpr const KProcessPageTable &GetPageTable() const { return m_page_table; } constexpr KHandleTable &GetHandleTable() { return m_handle_table; } constexpr const KHandleTable &GetHandleTable() const { return m_handle_table; } KWaitObject *GetWaitObjectPointer() { return std::addressof(m_wait_object); } size_t GetUsedUserPhysicalMemorySize() const; size_t GetTotalUserPhysicalMemorySize() const; size_t GetUsedNonSystemUserPhysicalMemorySize() const; size_t GetTotalNonSystemUserPhysicalMemorySize() const; Result AddSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size); void RemoveSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size); void AddIoRegion(KIoRegion *io_region); void RemoveIoRegion(KIoRegion *io_region); Result CreateThreadLocalRegion(KProcessAddress *out); void DeleteThreadLocalRegion(KProcessAddress addr); void *GetThreadLocalRegionPointer(KProcessAddress addr); constexpr KProcessAddress GetProcessLocalRegionAddress() const { return m_plr_address; } constexpr void *GetProcessLocalRegionHeapAddress() const { return m_plr_heap_address; } KThread *GetExceptionThread() const { return m_exception_thread; } void AddCpuTime(s64 diff) { m_cpu_time += diff; } s64 GetCpuTime() { return m_cpu_time.Load(); } constexpr s64 GetScheduledCount() const { return m_schedule_count; } void IncrementScheduledCount() { ++m_schedule_count; } void IncrementRunningThreadCount(); void DecrementRunningThreadCount(); size_t GetRequiredSecureMemorySizeNonDefault() const { return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0; } size_t GetRequiredSecureMemorySize() const { return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0; } size_t GetTotalSystemResourceSize() const { return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0; } size_t GetUsedSystemResourceSize() const { return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0; } void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) { m_running_threads[core] = thread; m_running_thread_idle_counts[core] = idle_count; m_running_thread_switch_counts[core] = switch_count; } void ClearRunningThread(KThread *thread) { for (size_t i = 0; i < util::size(m_running_threads); ++i) { if (m_running_threads[i] == thread) { m_running_threads[i] = nullptr; } } } const KSystemResource &GetSystemResource() const { return *m_system_resource; } const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return m_system_resource->GetMemoryBlockSlabManager(); } const KBlockInfoManager &GetBlockInfoManager() const { return m_system_resource->GetBlockInfoManager(); } const KPageTableManager &GetPageTableManager() const { return m_system_resource->GetPageTableManager(); } constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; } constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; } constexpr u64 GetRunningThreadSwitchCount(s32 core) const { return m_running_thread_switch_counts[core]; } void RegisterThread(KThread *thread); void UnregisterThread(KThread *thread); Result Run(s32 priority, size_t stack_size); Result Reset(); void SetDebugBreak() { if (m_state == State_RunningAttached) { this->ChangeState(State_DebugBreak); } } void SetAttached() { if (m_state == State_DebugBreak) { this->ChangeState(State_RunningAttached); } } Result SetActivity(ams::svc::ProcessActivity activity); void PinCurrentThread(); void UnpinCurrentThread(); void UnpinThread(KThread *thread); void SignalConditionVariable(uintptr_t cv_key, int32_t count) { return m_cond_var.Signal(cv_key, count); } Result WaitConditionVariable(KProcessAddress address, uintptr_t cv_key, u32 tag, s64 ns) { R_RETURN(m_cond_var.Wait(address, cv_key, tag, ns)); } Result SignalAddressArbiter(uintptr_t address, ams::svc::SignalType signal_type, s32 value, s32 count) { R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count)); } Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s64 value, s64 timeout) { R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout)); } Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count); static KProcess *GetProcessFromId(u64 process_id); static Result GetProcessList(s32 *out_num_processes, ams::kern::svc::KUserPointer<u64 *> out_process_ids, s32 max_out_count); static void Switch(KProcess *cur_process, KProcess *next_process) { MESOSPHERE_UNUSED(cur_process); /* Update the current page table. */ if (next_process) { next_process->GetPageTable().Activate(next_process->GetSlabIndex(), next_process->GetProcessId()); } else { Kernel::GetKernelPageTable().Activate(); } } public: /* Overridden parent functions. */ bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } void Finalize(); ALWAYS_INLINE u64 GetIdImpl() const { return this->GetProcessId(); } ALWAYS_INLINE u64 GetId() const { return this->GetIdImpl(); } virtual bool IsSignaled() const override { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); return m_is_signaled; } void DoWorkerTaskImpl(); private: void ChangeState(State new_state) { if (m_state != new_state) { m_state = new_state; m_is_signaled = true; this->NotifyAvailable(); } } ALWAYS_INLINE Result InitializeHandleTable(s32 size) { /* Try to initialize the handle table. */ R_TRY(m_handle_table.Initialize(size)); /* We succeeded, so note that we did. */ m_is_handle_table_initialized = true; R_SUCCEED(); } ALWAYS_INLINE void FinalizeHandleTable() { /* Finalize the table. */ m_handle_table.Finalize(); /* Note that the table is finalized. */ m_is_handle_table_initialized = false; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_readable_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> namespace ams::kern { class KEvent; class KReadableEvent : public KSynchronizationObject { MESOSPHERE_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject); private: bool m_is_signaled; KEvent *m_parent; public: constexpr explicit KReadableEvent(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_is_signaled(), m_parent() { MESOSPHERE_ASSERT_THIS(); } explicit KReadableEvent() { /* ... */ } void Initialize(KEvent *parent); constexpr KEvent *GetParent() const { return m_parent; } void Signal(); Result Reset(); void Clear() { MESOSPHERE_ASSERT_THIS(); /* Try to perform a reset, ignoring whether it succeeds. */ static_cast<void>(this->Reset()); } virtual bool IsSignaled() const override; virtual void Destroy() override; /* NOTE: This is a virtual function in Nintendo's kernel. */ /* virtual Result Reset(); */ }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_resource_limit.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_k_light_condition_variable.hpp> namespace ams::kern { class KResourceLimit final : public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject); private: s64 m_limit_values[ams::svc::LimitableResource_Count]; s64 m_current_values[ams::svc::LimitableResource_Count]; s64 m_current_hints[ams::svc::LimitableResource_Count]; s64 m_peak_values[ams::svc::LimitableResource_Count]; mutable KLightLock m_lock; s32 m_waiter_count; KLightConditionVariable m_cond_var; public: constexpr explicit ALWAYS_INLINE KResourceLimit(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList>(util::ConstantInitialize), m_limit_values(), m_current_values(), m_current_hints(), m_peak_values(), m_lock(), m_waiter_count(), m_cond_var(util::ConstantInitialize) { /* ... */ } explicit ALWAYS_INLINE KResourceLimit() { /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } void Initialize(); void Finalize(); s64 GetLimitValue(ams::svc::LimitableResource which) const; s64 GetCurrentValue(ams::svc::LimitableResource which) const; s64 GetPeakValue(ams::svc::LimitableResource which) const; s64 GetFreeValue(ams::svc::LimitableResource which) const; Result SetLimitValue(ams::svc::LimitableResource which, s64 value); void Add(ams::svc::LimitableResource which, s64 value); bool Reserve(ams::svc::LimitableResource which, s64 value); bool Reserve(ams::svc::LimitableResource which, s64 value, s64 timeout); void Release(ams::svc::LimitableResource which, s64 value); void Release(ams::svc::LimitableResource which, s64 value, s64 hint); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_priority_queue.hpp> #include <mesosphere/kern_k_interrupt_task_manager.hpp> #include <mesosphere/kern_k_scheduler_lock.hpp> namespace ams::kern { using KSchedulerPriorityQueue = KPriorityQueue<KThread, cpu::NumCores, ams::svc::LowestThreadPriority, ams::svc::HighestThreadPriority>; static_assert(std::is_same<KSchedulerPriorityQueue::AffinityMaskType, KAffinityMask>::value); static_assert(KSchedulerPriorityQueue::NumCores == cpu::NumCores); static_assert(KSchedulerPriorityQueue::NumPriority == BITSIZEOF(u64)); class KScopedSchedulerLock; class KScopedSchedulerLockAndSleep; class KScheduler { NON_COPYABLE(KScheduler); NON_MOVEABLE(KScheduler); public: static constexpr s32 HighestCoreMigrationAllowedPriority = 2; static_assert(ams::svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority); static_assert(ams::svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority); struct SchedulingState { util::Atomic<bool> needs_scheduling{false}; bool interrupt_task_runnable{false}; bool should_count_idle{false}; u64 idle_count{0}; u64 switch_count{0}; KThread *highest_priority_thread{nullptr}; void *idle_thread_stack{nullptr}; KThread *prev_thread{nullptr}; KInterruptTaskManager *interrupt_task_manager{nullptr}; constexpr SchedulingState() = default; }; private: friend class KScopedSchedulerLock; friend class KScopedSchedulerLockAndSleep; friend class KScopedDisableDispatch; private: SchedulingState m_state; bool m_is_active; s32 m_core_id; s64 m_last_context_switch_time; KThread *m_idle_thread; util::Atomic<KThread *> m_current_thread; public: constexpr KScheduler() : m_state(), m_is_active(false), m_core_id(0), m_last_context_switch_time(0), m_idle_thread(nullptr), m_current_thread(nullptr) { m_state.needs_scheduling = true; m_state.interrupt_task_runnable = false; m_state.should_count_idle = false; m_state.idle_count = 0; m_state.switch_count = 0; m_state.idle_thread_stack = nullptr; m_state.highest_priority_thread = nullptr; m_state.prev_thread = nullptr; m_state.interrupt_task_manager = nullptr; } NOINLINE void Initialize(KThread *idle_thread); NOINLINE void Activate(); ALWAYS_INLINE void SetInterruptTaskRunnable() { m_state.interrupt_task_runnable = true; m_state.needs_scheduling = true; } ALWAYS_INLINE void RequestScheduleOnInterrupt() { m_state.needs_scheduling = true; if (CanSchedule()) { this->ScheduleOnInterrupt(); } } ALWAYS_INLINE u64 GetIdleCount() const { return m_state.idle_count; } ALWAYS_INLINE u64 GetSwitchCount() const { return m_state.switch_count; } ALWAYS_INLINE KThread *GetIdleThread() const { return m_idle_thread; } ALWAYS_INLINE KThread *GetPreviousThread() const { return m_state.prev_thread; } ALWAYS_INLINE KThread *GetSchedulerCurrentThread() const { return m_current_thread.Load(); } ALWAYS_INLINE s64 GetLastContextSwitchTime() const { return m_last_context_switch_time; } private: /* Static private API. */ static ALWAYS_INLINE KSchedulerPriorityQueue &GetPriorityQueue() { return s_priority_queue; } static NOINLINE u64 UpdateHighestPriorityThreadsImpl(); public: /* Static public API. */ static ALWAYS_INLINE bool CanSchedule() { return GetCurrentThread().GetDisableDispatchCount() == 0; } static ALWAYS_INLINE bool IsSchedulerLockedByCurrentThread() { return s_scheduler_lock.IsLockedByCurrentThread(); } static ALWAYS_INLINE bool IsSchedulerUpdateNeeded() { return s_scheduler_update_needed; } static ALWAYS_INLINE void SetSchedulerUpdateNeeded() { s_scheduler_update_needed = true; } static ALWAYS_INLINE void ClearSchedulerUpdateNeeded() { s_scheduler_update_needed = false; } static ALWAYS_INLINE void DisableScheduling() { MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() >= 0); GetCurrentThread().DisableDispatch(); } static NOINLINE void EnableScheduling(u64 cores_needing_scheduling) { MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() >= 1); GetCurrentScheduler().RescheduleOtherCores(cores_needing_scheduling); if (GetCurrentThread().GetDisableDispatchCount() > 1) { GetCurrentThread().EnableDispatch(); } else { GetCurrentScheduler().RescheduleCurrentCore(); } } static ALWAYS_INLINE u64 UpdateHighestPriorityThreads() { if (IsSchedulerUpdateNeeded()) { return UpdateHighestPriorityThreadsImpl(); } else { return 0; } } static NOINLINE void ClearPreviousThread(KThread *thread); static NOINLINE void OnThreadStateChanged(KThread *thread, KThread::ThreadState old_state); static NOINLINE void OnThreadPriorityChanged(KThread *thread, s32 old_priority); static NOINLINE void OnThreadAffinityMaskChanged(KThread *thread, const KAffinityMask &old_affinity, s32 old_core); static NOINLINE void RotateScheduledQueue(s32 core_id, s32 priority); static NOINLINE void YieldWithoutCoreMigration(); static NOINLINE void YieldWithCoreMigration(); static NOINLINE void YieldToAnyThread(); private: /* Instanced private API. */ void ScheduleImpl(); void SwitchThread(KThread *next_thread); ALWAYS_INLINE void Schedule() { MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() == 1); MESOSPHERE_ASSERT(m_core_id == GetCurrentCoreId()); this->ScheduleImpl(); } ALWAYS_INLINE void ScheduleOnInterrupt() { GetCurrentThread().DisableDispatch(); this->Schedule(); GetCurrentThread().EnableDispatch(); } void RescheduleOtherCores(u64 cores_needing_scheduling); ALWAYS_INLINE void RescheduleCurrentCore() { MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() == 1); GetCurrentThread().EnableDispatch(); if (m_state.needs_scheduling.Load()) { /* Disable interrupts, and then check again if rescheduling is needed. */ KScopedInterruptDisable intr_disable; GetCurrentScheduler().RescheduleCurrentCoreImpl(); } } ALWAYS_INLINE void RescheduleCurrentCoreImpl() { /* Check that scheduling is needed. */ if (AMS_LIKELY(m_state.needs_scheduling.Load())) { GetCurrentThread().DisableDispatch(); this->Schedule(); GetCurrentThread().EnableDispatch(); } } NOINLINE u64 UpdateHighestPriorityThread(KThread *thread); public: using LockType = KAbstractSchedulerLock<KScheduler>; private: static bool s_scheduler_update_needed; static KSchedulerPriorityQueue s_priority_queue; static LockType s_scheduler_lock; public: static consteval bool ValidateAssemblyOffsets(); }; class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> { public: explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ } ALWAYS_INLINE ~KScopedSchedulerLock() { /* ... */ } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scheduler_impls.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_scheduler.hpp> #include <mesosphere/kern_select_interrupt_manager.hpp> namespace ams::kern { /* NOTE: This header is included after all main headers. */ consteval bool KScheduler::ValidateAssemblyOffsets() { static_assert(AMS_OFFSETOF(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING); static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_runnable) == KSCHEDULER_INTERRUPT_TASK_RUNNABLE); static_assert(AMS_OFFSETOF(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD); static_assert(AMS_OFFSETOF(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK); static_assert(AMS_OFFSETOF(KScheduler, m_state.prev_thread) == KSCHEDULER_PREVIOUS_THREAD); static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_manager) == KSCHEDULER_INTERRUPT_TASK_MANAGER); return true; } static_assert(KScheduler::ValidateAssemblyOffsets()); ALWAYS_INLINE void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) { if (const u64 core_mask = cores_needing_scheduling & ~(1ul << m_core_id); core_mask != 0) { cpu::DataSynchronizationBarrierInnerShareable(); Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_Scheduler, core_mask); } } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scheduler_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_current_context.hpp> #include <mesosphere/kern_k_scoped_lock.hpp> namespace ams::kern { class KThread; template<typename T> concept KSchedulerLockable = !std::is_reference<T>::value && requires(T) { { T::DisableScheduling() } -> std::same_as<void>; { T::EnableScheduling(std::declval<u64>()) } -> std::same_as<void>; { T::UpdateHighestPriorityThreads() } -> std::convertible_to<u64>; }; template<typename SchedulerType> requires KSchedulerLockable<SchedulerType> class KAbstractSchedulerLock { private: KAlignedSpinLock m_spin_lock; s32 m_lock_count; KThread *m_owner_thread; public: constexpr ALWAYS_INLINE KAbstractSchedulerLock() : m_spin_lock(), m_lock_count(0), m_owner_thread(nullptr) { MESOSPHERE_ASSERT_THIS(); } ALWAYS_INLINE bool IsLockedByCurrentThread() const { MESOSPHERE_ASSERT_THIS(); return m_owner_thread == GetCurrentThreadPointer(); } MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Lock() { MESOSPHERE_ASSERT_THIS(); if (this->IsLockedByCurrentThread()) { /* If we already own the lock, the lock count should be > 0. */ /* For debug, ensure this is true. */ MESOSPHERE_ASSERT(m_lock_count > 0); } else { /* Otherwise, we want to disable scheduling and acquire the spinlock. */ SchedulerType::DisableScheduling(); m_spin_lock.Lock(); /* For debug, ensure that our state is valid. */ MESOSPHERE_ASSERT(m_lock_count == 0); MESOSPHERE_ASSERT(m_owner_thread == nullptr); /* Take ownership of the lock. */ m_owner_thread = GetCurrentThreadPointer(); } /* Increment the lock count. */ m_lock_count++; } MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(m_lock_count > 0); /* Release an instance of the lock. */ if ((--m_lock_count) == 0) { /* Perform a memory barrier here. */ cpu::DataMemoryBarrierInnerShareable(); /* We're no longer going to hold the lock. Take note of what cores need scheduling. */ const u64 cores_needing_scheduling = SchedulerType::UpdateHighestPriorityThreads(); /* Note that we no longer hold the lock, and unlock the spinlock. */ m_owner_thread = nullptr; m_spin_lock.Unlock(); /* Enable scheduling, and perform a rescheduling operation. */ SchedulerType::EnableScheduling(cores_needing_scheduling); } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scoped_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { template<typename T> concept KLockable = !std::is_reference<T>::value && requires (T &t) { { t.Lock() } -> std::same_as<void>; { t.Unlock() } -> std::same_as<void>; }; template<typename T> requires KLockable<T> class KScopedLock { NON_COPYABLE(KScopedLock); NON_MOVEABLE(KScopedLock); private: T &m_lock; public: explicit ALWAYS_INLINE KScopedLock(T &l) : m_lock(l) { m_lock.Lock(); } explicit ALWAYS_INLINE KScopedLock(T *l) : KScopedLock(*l) { /* ... */ } ALWAYS_INLINE ~KScopedLock() { m_lock.Unlock(); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scoped_resource_reservation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_resource_limit.hpp> #include <mesosphere/kern_k_process.hpp> namespace ams::kern { class KScopedResourceReservation { private: KResourceLimit *m_limit; s64 m_value; ams::svc::LimitableResource m_resource; bool m_succeeded; public: ALWAYS_INLINE KScopedResourceReservation(KResourceLimit *l, ams::svc::LimitableResource r, s64 v, s64 timeout) : m_limit(l), m_value(v), m_resource(r) { if (m_limit && m_value) { m_succeeded = m_limit->Reserve(m_resource, m_value, timeout); } else { m_succeeded = true; } } ALWAYS_INLINE KScopedResourceReservation(KResourceLimit *l, ams::svc::LimitableResource r, s64 v = 1) : m_limit(l), m_value(v), m_resource(r) { if (m_limit && m_value) { m_succeeded = m_limit->Reserve(m_resource, m_value); } else { m_succeeded = true; } } ALWAYS_INLINE KScopedResourceReservation(const KProcess *p, ams::svc::LimitableResource r, s64 v, s64 t) : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) { /* ... */ } ALWAYS_INLINE KScopedResourceReservation(const KProcess *p, ams::svc::LimitableResource r, s64 v = 1) : KScopedResourceReservation(p->GetResourceLimit(), r, v) { /* ... */ } ALWAYS_INLINE ~KScopedResourceReservation() { if (m_limit && m_value && m_succeeded) { m_limit->Release(m_resource, m_value); } } ALWAYS_INLINE void Commit() { m_limit = nullptr; } ALWAYS_INLINE bool Succeeded() const { return m_succeeded; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_scoped_scheduler_lock_and_sleep.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_scheduler.hpp> #include <mesosphere/kern_select_hardware_timer.hpp> #include <mesosphere/kern_kernel.hpp> namespace ams::kern { class KScopedSchedulerLockAndSleep { private: s64 m_timeout_tick; KThread *m_thread; KHardwareTimer *m_timer; public: explicit ALWAYS_INLINE KScopedSchedulerLockAndSleep(KHardwareTimer **out_timer, KThread *t, s64 timeout) : m_timeout_tick(timeout), m_thread(t) { /* Lock the scheduler. */ KScheduler::s_scheduler_lock.Lock(); /* Set our timer only if the absolute time is positive. */ m_timer = (m_timeout_tick > 0) ? std::addressof(Kernel::GetHardwareTimer()) : nullptr; *out_timer = m_timer; } ~KScopedSchedulerLockAndSleep() { /* Register the sleep. */ if (m_timeout_tick > 0) { m_timer->RegisterAbsoluteTask(m_thread, m_timeout_tick); } /* Unlock the scheduler. */ KScheduler::s_scheduler_lock.Unlock(); } ALWAYS_INLINE void CancelSleep() { m_timeout_tick = 0; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_server_port.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KPort; class KServerSession; class KLightServerSession; class KServerPort final : public KSynchronizationObject { MESOSPHERE_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); private: using SessionList = util::IntrusiveListBaseTraits<KServerSession>::ListType; using LightSessionList = util::IntrusiveListBaseTraits<KLightServerSession>::ListType; private: SessionList m_session_list; LightSessionList m_light_session_list; KPort *m_parent; public: constexpr explicit KServerPort(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_session_list(), m_light_session_list(), m_parent() { /* ... */ } explicit KServerPort() { /* ... */ } void Initialize(KPort *parent); void EnqueueSession(KServerSession *session); void EnqueueSession(KLightServerSession *session); KServerSession *AcceptSession(); KLightServerSession *AcceptLightSession(); constexpr const KPort *GetParent() const { return m_parent; } bool IsLight() const; /* Overridden virtual functions. */ virtual void Destroy() override; virtual bool IsSignaled() const override; private: void CleanupSessions(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_session_request.hpp> #include <mesosphere/kern_k_light_lock.hpp> namespace ams::kern { class KSession; class KServerSession final : public KSynchronizationObject, public util::IntrusiveListBaseNode<KServerSession> { MESOSPHERE_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); private: using RequestList = util::IntrusiveListBaseTraits<KSessionRequest>::ListType; private: KSession *m_parent; RequestList m_request_list; KSessionRequest *m_current_request; KLightLock m_lock; public: constexpr explicit KServerSession(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_parent(), m_request_list(), m_current_request(), m_lock() { /* ... */ } explicit KServerSession() : m_current_request(nullptr), m_lock() { /* ... */ } virtual void Destroy() override; void Initialize(KSession *p) { m_parent = p; } constexpr const KSession *GetParent() const { return m_parent; } virtual bool IsSignaled() const override; Result OnRequest(KSessionRequest *request); Result ReceiveRequest(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); Result SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); void OnClientClosed(); void Dump(); private: ALWAYS_INLINE bool IsSignaledImpl() const; void CleanupRequests(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_server_session.hpp> #include <mesosphere/kern_k_client_session.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KClientPort; class KProcess; class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList, true> { MESOSPHERE_AUTOOBJECT_TRAITS(KSession, KAutoObject); private: enum class State : u8 { Invalid = 0, Normal = 1, ClientClosed = 2, ServerClosed = 3, }; private: util::Atomic<std::underlying_type<State>::type> m_atomic_state; bool m_initialized; KServerSession m_server; KClientSession m_client; KClientPort *m_port; uintptr_t m_name; KProcess *m_process; private: ALWAYS_INLINE void SetState(State state) { m_atomic_state = static_cast<u8>(state); } ALWAYS_INLINE State GetState() const { return static_cast<State>(m_atomic_state.Load()); } public: constexpr explicit KSession(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList, true>(util::ConstantInitialize), m_atomic_state(static_cast<std::underlying_type<State>::type>(State::Invalid)), m_initialized(), m_server(util::ConstantInitialize), m_client(util::ConstantInitialize), m_port(), m_name(), m_process() { /* ... */ } explicit KSession() : m_atomic_state(util::ToUnderlying(State::Invalid)), m_initialized(false), m_process(nullptr) { /* ... */ } void Initialize(KClientPort *client_port, uintptr_t name); void Finalize(); bool IsInitialized() const { return m_initialized; } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_process); } static void PostDestroy(uintptr_t arg); void OnServerClosed(); void OnClientClosed(); bool IsServerClosed() const { return this->GetState() != State::Normal; } bool IsClientClosed() const { return this->GetState() != State::Normal; } Result OnRequest(KSessionRequest *request) { R_RETURN(m_server.OnRequest(request)); } KClientSession &GetClientSession() { return m_client; } KServerSession &GetServerSession() { return m_server; } const KClientSession &GetClientSession() const { return m_client; } const KServerSession &GetServerSession() const { return m_server; } const KClientPort *GetParent() const { return m_port; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_session_request.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_event.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_process.hpp> #include <mesosphere/kern_k_memory_block.hpp> namespace ams::kern { class KSessionRequest final : public KSlabAllocated<KSessionRequest, true>, public KAutoObject, public util::IntrusiveListBaseNode<KSessionRequest> { MESOSPHERE_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject); public: class SessionMappings { private: /* At most 15 buffers of each type (4-bit descriptor counts), for 45 total. */ static constexpr size_t NumMappings = ((1ul << 4) - 1) * 3; static constexpr size_t NumStaticMappings = 8; static constexpr size_t NumDynamicMappings = NumMappings - NumStaticMappings; class Mapping { private: uintptr_t m_client_address; uintptr_t m_server_address; size_t m_size; KMemoryState m_state; public: constexpr void Set(KProcessAddress c, KProcessAddress s, size_t sz, KMemoryState st) { m_client_address = GetInteger(c); m_server_address = GetInteger(s); m_size = sz; m_state = st; } constexpr ALWAYS_INLINE KProcessAddress GetClientAddress() const { return m_client_address; } constexpr ALWAYS_INLINE KProcessAddress GetServerAddress() const { return m_server_address; } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } constexpr ALWAYS_INLINE KMemoryState GetMemoryState() const { return m_state; } }; public: class DynamicMappings : public KSlabAllocated<DynamicMappings, true> { private: Mapping m_mappings[NumDynamicMappings]; public: constexpr explicit DynamicMappings() : m_mappings() { /* ... */ } constexpr ALWAYS_INLINE Mapping &Get(size_t idx) { return m_mappings[idx]; } constexpr ALWAYS_INLINE const Mapping &Get(size_t idx) const { return m_mappings[idx]; } }; static_assert(sizeof(DynamicMappings) == sizeof(Mapping) * NumDynamicMappings); private: Mapping m_static_mappings[NumStaticMappings]; DynamicMappings *m_dynamic_mappings; u8 m_num_send; u8 m_num_recv; u8 m_num_exch; public: constexpr explicit SessionMappings(util::ConstantInitializeTag) : m_static_mappings(), m_dynamic_mappings(), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ } explicit SessionMappings() : m_dynamic_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ } void Initialize() { /* ... */ } void Finalize(); constexpr ALWAYS_INLINE size_t GetSendCount() const { return m_num_send; } constexpr ALWAYS_INLINE size_t GetReceiveCount() const { return m_num_recv; } constexpr ALWAYS_INLINE size_t GetExchangeCount() const { return m_num_exch; } Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); constexpr ALWAYS_INLINE KProcessAddress GetSendClientAddress(size_t i) const { return GetSendMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetSendServerAddress(size_t i) const { return GetSendMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE size_t GetSendSize(size_t i) const { return GetSendMapping(i).GetSize(); } constexpr ALWAYS_INLINE KMemoryState GetSendMemoryState(size_t i) const { return GetSendMapping(i).GetMemoryState(); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveClientAddress(size_t i) const { return GetReceiveMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveServerAddress(size_t i) const { return GetReceiveMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE size_t GetReceiveSize(size_t i) const { return GetReceiveMapping(i).GetSize(); } constexpr ALWAYS_INLINE KMemoryState GetReceiveMemoryState(size_t i) const { return GetReceiveMapping(i).GetMemoryState(); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeClientAddress(size_t i) const { return GetExchangeMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return GetExchangeMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return GetExchangeMapping(i).GetSize(); } constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return GetExchangeMapping(i).GetMemoryState(); } private: Result PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index); constexpr ALWAYS_INLINE const Mapping &GetSendMapping(size_t i) const { MESOSPHERE_ASSERT(i < m_num_send); const size_t index = i; if (index < NumStaticMappings) { return m_static_mappings[index]; } else { return m_dynamic_mappings->Get(index - NumStaticMappings); } } constexpr ALWAYS_INLINE const Mapping &GetReceiveMapping(size_t i) const { MESOSPHERE_ASSERT(i < m_num_recv); const size_t index = m_num_send + i; if (index < NumStaticMappings) { return m_static_mappings[index]; } else { return m_dynamic_mappings->Get(index - NumStaticMappings); } } constexpr ALWAYS_INLINE const Mapping &GetExchangeMapping(size_t i) const { MESOSPHERE_ASSERT(i < m_num_exch); const size_t index = m_num_send + m_num_recv + i; if (index < NumStaticMappings) { return m_static_mappings[index]; } else { return m_dynamic_mappings->Get(index - NumStaticMappings); } } }; private: SessionMappings m_mappings; KThread *m_thread; KProcess *m_server; KEvent *m_event; uintptr_t m_address; size_t m_size; public: constexpr explicit KSessionRequest(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_mappings(util::ConstantInitialize), m_thread(), m_server(), m_event(), m_address(), m_size() { /* ... */ } explicit KSessionRequest() : m_thread(nullptr), m_server(nullptr), m_event(nullptr) { /* ... */ } static KSessionRequest *Create() { KSessionRequest *req = KSessionRequest::Allocate(); if (AMS_LIKELY(req != nullptr)) { KAutoObject::Create<KSessionRequest>(req); } return req; } static KSessionRequest *CreateFromUnusedSlabMemory() { KSessionRequest *req = KSessionRequest::AllocateFromUnusedSlabMemory(); if (AMS_LIKELY(req != nullptr)) { KAutoObject::Create<KSessionRequest>(req); } return req; } virtual void Destroy() override { this->Finalize(); KSessionRequest::Free(this); } void Initialize(KEvent *event, uintptr_t address, size_t size) { m_mappings.Initialize(); m_thread = std::addressof(GetCurrentThread()); m_event = event; m_address = address; m_size = size; m_thread->Open(); if (m_event != nullptr) { m_event->Open(); } } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } constexpr ALWAYS_INLINE KThread *GetThread() const { return m_thread; } constexpr ALWAYS_INLINE KEvent *GetEvent() const { return m_event; } constexpr ALWAYS_INLINE uintptr_t GetAddress() const { return m_address; } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } constexpr ALWAYS_INLINE KProcess *GetServerProcess() const { return m_server; } void ALWAYS_INLINE SetServerProcess(KProcess *process) { m_server = process; m_server->Open(); } constexpr ALWAYS_INLINE void ClearThread() { m_thread = nullptr; } constexpr ALWAYS_INLINE void ClearEvent() { m_event = nullptr; } constexpr ALWAYS_INLINE size_t GetSendCount() const { return m_mappings.GetSendCount(); } constexpr ALWAYS_INLINE size_t GetReceiveCount() const { return m_mappings.GetReceiveCount(); } constexpr ALWAYS_INLINE size_t GetExchangeCount() const { return m_mappings.GetExchangeCount(); } ALWAYS_INLINE Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { R_RETURN(m_mappings.PushSend(client, server, size, state)); } ALWAYS_INLINE Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { R_RETURN(m_mappings.PushReceive(client, server, size, state)); } ALWAYS_INLINE Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { R_RETURN(m_mappings.PushExchange(client, server, size, state)); } constexpr ALWAYS_INLINE KProcessAddress GetSendClientAddress(size_t i) const { return m_mappings.GetSendClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetSendServerAddress(size_t i) const { return m_mappings.GetSendServerAddress(i); } constexpr ALWAYS_INLINE size_t GetSendSize(size_t i) const { return m_mappings.GetSendSize(i); } constexpr ALWAYS_INLINE KMemoryState GetSendMemoryState(size_t i) const { return m_mappings.GetSendMemoryState(i); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveClientAddress(size_t i) const { return m_mappings.GetReceiveClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveServerAddress(size_t i) const { return m_mappings.GetReceiveServerAddress(i); } constexpr ALWAYS_INLINE size_t GetReceiveSize(size_t i) const { return m_mappings.GetReceiveSize(i); } constexpr ALWAYS_INLINE KMemoryState GetReceiveMemoryState(size_t i) const { return m_mappings.GetReceiveMemoryState(i); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeClientAddress(size_t i) const { return m_mappings.GetExchangeClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return m_mappings.GetExchangeServerAddress(i); } constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return m_mappings.GetExchangeSize(i); } constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return m_mappings.GetExchangeMemoryState(i); } private: /* NOTE: This is public and virtual in Nintendo's kernel. */ void Finalize() { m_mappings.Finalize(); if (m_thread) { m_thread->Close(); } if (m_event) { m_event->Close(); } if (m_server) { m_server->Close(); } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_shared_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_select_page_table.hpp> namespace ams::kern { class KProcess; class KResourceLimit; class KSharedMemory final : public KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject); private: KPageGroup m_page_group; KResourceLimit *m_resource_limit; u64 m_owner_process_id; ams::svc::MemoryPermission m_owner_perm; ams::svc::MemoryPermission m_remote_perm; bool m_is_initialized; public: explicit KSharedMemory() : m_page_group(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits<u64>::max()), m_owner_perm(ams::svc::MemoryPermission_None), m_remote_perm(ams::svc::MemoryPermission_None), m_is_initialized(false) { /* ... */ } Result Initialize(KProcess *owner, size_t size, ams::svc::MemoryPermission own_perm, ams::svc::MemoryPermission rem_perm); void Finalize(); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } Result Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm); Result Unmap(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process); u64 GetOwnerProcessId() const { return m_owner_process_id; } size_t GetSize() const { return m_page_group.GetNumPages() * PageSize; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_shared_memory_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KSharedMemory; class KSharedMemoryInfo : public KSlabAllocated<KSharedMemoryInfo>, public util::IntrusiveListBaseNode<KSharedMemoryInfo> { private: KSharedMemory *m_shared_memory; size_t m_reference_count; public: explicit KSharedMemoryInfo() { /* ... */ } ~KSharedMemoryInfo() { /* ... */ } constexpr void Initialize(KSharedMemory *m) { MESOSPHERE_ASSERT_THIS(); m_shared_memory = m; m_reference_count = 0; } constexpr void Open() { ++m_reference_count; MESOSPHERE_ASSERT(m_reference_count > 0); } constexpr bool Close() { MESOSPHERE_ASSERT(m_reference_count > 0); return (--m_reference_count) == 0; } constexpr KSharedMemory *GetSharedMemory() const { return m_shared_memory; } constexpr size_t GetReferenceCount() const { return m_reference_count; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_slab_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_slab_heap_impl.hpp> namespace ams::kern { using ams::kern::arch::arm64::IsSlabAtomicValid; using ams::kern::arch::arm64::AllocateFromSlabAtomic; using ams::kern::arch::arm64::FreeToSlabAtomic; } #else #error "Unknown architecture for KSlabHeapImpl" #endif namespace ams::kern { namespace impl { class KSlabHeapImpl { NON_COPYABLE(KSlabHeapImpl); NON_MOVEABLE(KSlabHeapImpl); public: struct Node { Node *next; }; private: Node *m_head{nullptr}; public: constexpr KSlabHeapImpl() = default; void Initialize() { MESOSPHERE_ABORT_UNLESS(m_head == nullptr); MESOSPHERE_ABORT_UNLESS(IsSlabAtomicValid()); } ALWAYS_INLINE Node *GetHead() const { return m_head; } ALWAYS_INLINE void *Allocate() { return AllocateFromSlabAtomic(std::addressof(m_head)); } ALWAYS_INLINE void Free(void *obj) { return FreeToSlabAtomic(std::addressof(m_head), static_cast<Node *>(obj)); } }; } template<bool SupportDynamicExpansion> class KSlabHeapBase : protected impl::KSlabHeapImpl { NON_COPYABLE(KSlabHeapBase); NON_MOVEABLE(KSlabHeapBase); private: size_t m_obj_size{}; uintptr_t m_peak{}; uintptr_t m_start{}; uintptr_t m_end{}; private: ALWAYS_INLINE void UpdatePeakImpl(uintptr_t obj) { const util::AtomicRef<uintptr_t> peak_ref(m_peak); const uintptr_t alloc_peak = obj + this->GetObjectSize(); uintptr_t cur_peak = m_peak; do { if (alloc_peak <= cur_peak) { break; } } while (!peak_ref.CompareExchangeStrong(cur_peak, alloc_peak)); } public: constexpr KSlabHeapBase() = default; ALWAYS_INLINE bool Contains(uintptr_t address) const { return m_start <= address && address < m_end; } void Initialize(size_t obj_size, void *memory, size_t memory_size) { /* Ensure we don't initialize a slab using null memory. */ MESOSPHERE_ABORT_UNLESS(memory != nullptr); /* Set our object size. */ m_obj_size = obj_size; /* Initialize the base allocator. */ KSlabHeapImpl::Initialize(); /* Set our tracking variables. */ const size_t num_obj = (memory_size / obj_size); m_start = reinterpret_cast<uintptr_t>(memory); m_end = m_start + num_obj * obj_size; m_peak = m_start; /* Free the objects. */ u8 *cur = reinterpret_cast<u8 *>(m_end); for (size_t i = 0; i < num_obj; i++) { cur -= obj_size; KSlabHeapImpl::Free(cur); } } ALWAYS_INLINE size_t GetSlabHeapSize() const { return (m_end - m_start) / this->GetObjectSize(); } ALWAYS_INLINE size_t GetObjectSize() const { return m_obj_size; } ALWAYS_INLINE void *Allocate() { void *obj = KSlabHeapImpl::Allocate(); /* Track the allocated peak. */ #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) if (AMS_LIKELY(obj != nullptr)) { if constexpr (SupportDynamicExpansion) { if (this->Contains(reinterpret_cast<uintptr_t>(obj))) { this->UpdatePeakImpl(reinterpret_cast<uintptr_t>(obj)); } else { this->UpdatePeakImpl(reinterpret_cast<uintptr_t>(m_end) - this->GetObjectSize()); } } else { this->UpdatePeakImpl(reinterpret_cast<uintptr_t>(obj)); } } #endif return obj; } ALWAYS_INLINE void Free(void *obj) { /* Don't allow freeing an object that wasn't allocated from this heap. */ const bool contained = this->Contains(reinterpret_cast<uintptr_t>(obj)); if constexpr (SupportDynamicExpansion) { const bool is_slab = KMemoryLayout::GetSlabRegion().Contains(reinterpret_cast<uintptr_t>(obj)); MESOSPHERE_ABORT_UNLESS(contained || is_slab); } else { MESOSPHERE_ABORT_UNLESS(contained); } KSlabHeapImpl::Free(obj); } ALWAYS_INLINE size_t GetObjectIndex(const void *obj) const { if constexpr (SupportDynamicExpansion) { if (!this->Contains(reinterpret_cast<uintptr_t>(obj))) { return std::numeric_limits<size_t>::max(); } } return (reinterpret_cast<uintptr_t>(obj) - m_start) / this->GetObjectSize(); } ALWAYS_INLINE size_t GetPeakIndex() const { return this->GetObjectIndex(reinterpret_cast<const void *>(m_peak)); } ALWAYS_INLINE uintptr_t GetSlabHeapAddress() const { return m_start; } ALWAYS_INLINE size_t GetNumRemaining() const { size_t remaining = 0; /* Only calculate the number of remaining objects under debug configuration. */ #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) while (true) { auto *cur = this->GetHead(); remaining = 0; if constexpr (SupportDynamicExpansion) { const auto &slab_region = KMemoryLayout::GetSlabRegion(); while (this->Contains(reinterpret_cast<uintptr_t>(cur)) || slab_region.Contains(reinterpret_cast<uintptr_t>(cur))) { ++remaining; cur = cur->next; } } else { while (this->Contains(reinterpret_cast<uintptr_t>(cur))) { ++remaining; cur = cur->next; } } if (cur == nullptr) { break; } } #endif return remaining; } }; template<typename T, bool SupportDynamicExpansion> class KSlabHeap : public KSlabHeapBase<SupportDynamicExpansion> { private: using BaseHeap = KSlabHeapBase<SupportDynamicExpansion>; public: constexpr KSlabHeap() = default; void Initialize(void *memory, size_t memory_size) { BaseHeap::Initialize(sizeof(T), memory, memory_size); } ALWAYS_INLINE T *Allocate() { T *obj = static_cast<T *>(BaseHeap::Allocate()); if (AMS_LIKELY(obj != nullptr)) { std::construct_at(obj); } return obj; } ALWAYS_INLINE void Free(T *obj) { BaseHeap::Free(obj); } ALWAYS_INLINE size_t GetObjectIndex(const T *obj) const { return BaseHeap::GetObjectIndex(obj); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_spin_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_scoped_lock.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_spin_lock.hpp> namespace ams::kern { using ams::kern::arch::arm64::KAlignedSpinLock; using ams::kern::arch::arm64::KNotAlignedSpinLock; using ams::kern::arch::arm64::KSpinLock; } #else #error "Unknown architecture for KInterruptManager" #endif namespace ams::kern { using KScopedSpinLock = KScopedLock<KSpinLock>; using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>; using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_synchronization_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KThread; class KSynchronizationObject : public KAutoObjectWithList { MESOSPHERE_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject); public: struct ThreadListNode { ThreadListNode *next; KThread *thread; }; private: ThreadListNode *m_thread_list_head; ThreadListNode *m_thread_list_tail; protected: constexpr ALWAYS_INLINE explicit KSynchronizationObject(util::ConstantInitializeTag) : KAutoObjectWithList(util::ConstantInitialize), m_thread_list_head(), m_thread_list_tail() { MESOSPHERE_ASSERT_THIS(); } ALWAYS_INLINE explicit KSynchronizationObject() : m_thread_list_head(), m_thread_list_tail() { MESOSPHERE_ASSERT_THIS(); } /* NOTE: This is a virtual function which is overridden only by KDebugBase in Nintendo's kernel. */ /* virtual void OnFinalizeSynchronizationObject() { MESOSPHERE_ASSERT_THIS(); } */ void NotifyAvailable(Result result); ALWAYS_INLINE void NotifyAvailable() { return this->NotifyAvailable(ResultSuccess()); } public: static Result Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout); public: void Finalize(); virtual bool IsSignaled() const { AMS_INFINITE_LOOP(); } void DumpWaiters(); ALWAYS_INLINE void LinkNode(ThreadListNode *node) { /* Link the node to the list. */ if (m_thread_list_tail == nullptr) { m_thread_list_head = node; } else { m_thread_list_tail->next = node; } m_thread_list_tail = node; } ALWAYS_INLINE void UnlinkNode(ThreadListNode *node) { /* Unlink the node from the list. */ ThreadListNode *prev_ptr = reinterpret_cast<ThreadListNode *>(std::addressof(m_thread_list_head)); ThreadListNode *prev_val = nullptr; ThreadListNode *prev, *tail_prev; do { prev = prev_ptr; prev_ptr = prev_ptr->next; tail_prev = prev_val; prev_val = prev_ptr; } while (prev_ptr != node); if (m_thread_list_tail == node) { m_thread_list_tail = tail_prev; } prev->next = node->next; } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_spin_lock.hpp> namespace ams::kern { struct InitialProcessBinaryLayout; namespace init { struct KInitArguments; } } namespace ams::kern { class KResourceLimit; class KSystemControlBase { public: /* This can be overridden as needed. */ static constexpr size_t SecureAppletMemorySize = 0; protected: /* Nintendo uses std::mt19937_t for randomness. */ /* To save space (and because mt19337_t isn't secure anyway), */ /* We will use TinyMT. */ static constinit inline bool s_uninitialized_random_generator{true}; static constinit inline util::TinyMT s_random_generator{util::ConstantInitialize}; static constinit inline KSpinLock s_random_lock; public: class Init { private: static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg); public: /* Initialization. */ static size_t GetRealMemorySize(); static size_t GetIntendedMemorySize(); static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address); static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out, KPhysicalAddress kern_base_address); static bool ShouldIncreaseThreadResourceLimit(); static void TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args); static size_t GetApplicationPoolSize(); static size_t GetAppletPoolSize(); static size_t GetMinimumNonSecureSystemPoolSize(); static u8 GetDebugLogUartPort(); /* Randomness. */ static void GenerateRandom(u64 *dst, size_t count); static u64 GenerateRandomRange(u64 min, u64 max); }; protected: static NOINLINE void InitializePhase1Base(u64 seed); public: /* Initialization. */ static NOINLINE void ConfigureKTargetSystem(); static NOINLINE void InitializePhase1(); static NOINLINE void InitializePhase2(); static NOINLINE u32 GetCreateProcessMemoryPool(); /* Randomness. */ static void GenerateRandom(u64 *dst, size_t count); static u64 GenerateRandomRange(u64 min, u64 max); static u64 GenerateRandomU64(); /* Register access Access. */ static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); static u32 ReadRegisterPrivileged(ams::svc::PhysicalAddress address); static void WriteRegisterPrivileged(ams::svc::PhysicalAddress address, u32 value); /* Power management. */ static void SleepSystem(); static NORETURN void StopSystem(void *arg = nullptr); /* User access. */ #if defined(ATMOSPHERE_ARCH_ARM64) static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); #endif /* Secure Memory. */ static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool); static Result AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool); static void FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool); /* Insecure Memory. */ static KResourceLimit *GetInsecureMemoryResourceLimit(); static u32 GetInsecureMemoryPool(); protected: template<typename F> static ALWAYS_INLINE u64 GenerateUniformRange(u64 min, u64 max, F f) { /* Handle the case where the difference is too large to represent. */ if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) { return f(); } /* Iterate until we get a value in range. */ const u64 range_size = ((max + 1) - min); const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size; while (true) { if (const u64 rnd = f(); rnd < effective_max) { return min + (rnd % range_size); } } } /* User access. */ #if defined(ATMOSPHERE_ARCH_ARM64) static void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args); #endif }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_system_resource.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_k_dynamic_resource_manager.hpp> #include <mesosphere/kern_k_page_table_manager.hpp> #include <mesosphere/kern_k_resource_limit.hpp> namespace ams::kern { /* NOTE: Nintendo's implementation does not have the "is_secure_resource" field, and instead uses virtual IsSecureResource(). */ class KSystemResource : public KAutoObject { MESOSPHERE_AUTOOBJECT_TRAITS(KSystemResource, KAutoObject); private: KMemoryBlockSlabManager *m_p_memory_block_slab_manager{}; KBlockInfoManager *m_p_block_info_manager{}; KPageTableManager *m_p_page_table_manager{}; bool m_is_secure_resource{false}; public: explicit KSystemResource() : KAutoObject() { /* ... */ } constexpr explicit KSystemResource(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize) { /* ... */ } protected: ALWAYS_INLINE void SetSecureResource() { m_is_secure_resource = true; } public: virtual void Destroy() override { MESOSPHERE_PANIC("KSystemResource::Destroy() was called"); } ALWAYS_INLINE bool IsSecureResource() const { return m_is_secure_resource; } void SetManagers(KMemoryBlockSlabManager &mb, KBlockInfoManager &bi, KPageTableManager &pt) { MESOSPHERE_ASSERT(m_p_memory_block_slab_manager == nullptr); MESOSPHERE_ASSERT(m_p_block_info_manager == nullptr); MESOSPHERE_ASSERT(m_p_page_table_manager == nullptr); m_p_memory_block_slab_manager = std::addressof(mb); m_p_block_info_manager = std::addressof(bi); m_p_page_table_manager = std::addressof(pt); } const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return *m_p_memory_block_slab_manager; } const KBlockInfoManager &GetBlockInfoManager() const { return *m_p_block_info_manager; } const KPageTableManager &GetPageTableManager() const { return *m_p_page_table_manager; } KMemoryBlockSlabManager &GetMemoryBlockSlabManager() { return *m_p_memory_block_slab_manager; } KBlockInfoManager &GetBlockInfoManager() { return *m_p_block_info_manager; } KPageTableManager &GetPageTableManager() { return *m_p_page_table_manager; } KMemoryBlockSlabManager *GetMemoryBlockSlabManagerPointer() { return m_p_memory_block_slab_manager; } KBlockInfoManager *GetBlockInfoManagerPointer() { return m_p_block_info_manager; } KPageTableManager *GetPageTableManagerPointer() { return m_p_page_table_manager; } }; class KSecureSystemResource final : public KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource> { private: bool m_is_initialized; KMemoryManager::Pool m_resource_pool; KDynamicPageManager m_dynamic_page_manager; KMemoryBlockSlabManager m_memory_block_slab_manager; KBlockInfoManager m_block_info_manager; KPageTableManager m_page_table_manager; KMemoryBlockSlabHeap m_memory_block_heap; KBlockInfoSlabHeap m_block_info_heap; KPageTableSlabHeap m_page_table_heap; KResourceLimit *m_resource_limit; KVirtualAddress m_resource_address; size_t m_resource_size; public: explicit KSecureSystemResource() : m_is_initialized(false), m_resource_limit(nullptr) { /* Mark ourselves as being a secure resource. */ this->SetSecureResource(); } Result Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool); void Finalize(); bool IsInitialized() const { return m_is_initialized; } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } ALWAYS_INLINE size_t CalculateRequiredSecureMemorySize() const { if (m_resource_limit != nullptr) { return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool); } else { return 0; } } ALWAYS_INLINE size_t GetSize() const { return m_resource_size; } ALWAYS_INLINE size_t GetUsedSize() const { return m_dynamic_page_manager.GetUsed() * PageSize; } const KDynamicPageManager &GetDynamicPageManager() const { return m_dynamic_page_manager; } public: static size_t CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_target_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_system_control.hpp> namespace ams::kern { class KTargetSystem { private: friend class KSystemControlBase; friend class KSystemControl; private: struct KTargetSystemData { bool is_not_debug_mode; bool disable_debug_logging; bool disable_user_exception_handlers; bool disable_debug_memory_fill; bool disable_user_pmu_access; bool disable_kernel_debugging; bool disable_dynamic_resource_limits; }; private: static inline constinit bool s_is_uninitialized = true; static inline constinit const volatile KTargetSystemData s_data = { .is_not_debug_mode = false, .disable_debug_logging = false, .disable_user_exception_handlers = false, .disable_debug_memory_fill = false, .disable_user_pmu_access = false, .disable_kernel_debugging = false, .disable_dynamic_resource_limits = true, }; private: static ALWAYS_INLINE void SetInitialized() { s_is_uninitialized = false; } public: static ALWAYS_INLINE bool IsDebugMode() { return !(s_is_uninitialized | s_data.is_not_debug_mode); } static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return !(s_is_uninitialized | s_data.disable_debug_logging); } static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return !(s_is_uninitialized | s_data.disable_user_exception_handlers); } static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return !(s_is_uninitialized | s_data.disable_debug_memory_fill); } static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return !(s_is_uninitialized | s_data.disable_user_pmu_access); } static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return !(s_is_uninitialized | s_data.disable_kernel_debugging); } static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return !(s_is_uninitialized | s_data.disable_dynamic_resource_limits); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_svc.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_affinity_mask.hpp> #include <mesosphere/kern_k_thread_context.hpp> #include <mesosphere/kern_k_current_context.hpp> #include <mesosphere/kern_k_timer_task.hpp> #include <mesosphere/kern_k_worker_task.hpp> namespace ams::kern { class KThreadQueue; class KProcess; class KConditionVariable; class KAddressArbiter; using KThreadFunction = void (*)(uintptr_t); class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, public util::IntrusiveListBaseNode<KThread>, public KTimerTask { MESOSPHERE_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); private: friend class KProcess; friend class KConditionVariable; friend class KAddressArbiter; friend class KThreadQueue; public: static constexpr s32 MainThreadPriority = 1; static constexpr s32 IdleThreadPriority = 64; enum ThreadType : u32 { ThreadType_Main = 0, ThreadType_Kernel = 1, ThreadType_HighPriority = 2, ThreadType_User = 3, }; enum SuspendType : u32 { SuspendType_Process = 0, SuspendType_Thread = 1, SuspendType_Debug = 2, SuspendType_Backtrace = 3, SuspendType_Init = 4, SuspendType_Count, }; enum ThreadState : u16 { ThreadState_Initialized = 0, ThreadState_Waiting = 1, ThreadState_Runnable = 2, ThreadState_Terminated = 3, ThreadState_SuspendShift = 4, ThreadState_Mask = (1 << ThreadState_SuspendShift) - 1, ThreadState_ProcessSuspended = (1 << (SuspendType_Process + ThreadState_SuspendShift)), ThreadState_ThreadSuspended = (1 << (SuspendType_Thread + ThreadState_SuspendShift)), ThreadState_DebugSuspended = (1 << (SuspendType_Debug + ThreadState_SuspendShift)), ThreadState_BacktraceSuspended = (1 << (SuspendType_Backtrace + ThreadState_SuspendShift)), ThreadState_InitSuspended = (1 << (SuspendType_Init + ThreadState_SuspendShift)), ThreadState_SuspendFlagMask = ((1 << SuspendType_Count) - 1) << ThreadState_SuspendShift, }; enum DpcFlag : u32 { DpcFlag_Terminating = (1 << 0), DpcFlag_Terminated = (1 << 1), DpcFlag_PerformDestruction = (1 << 2), }; enum ExceptionFlag : u32 { ExceptionFlag_IsCallingSvc = (1 << 0), ExceptionFlag_IsInExceptionHandler = (1 << 1), ExceptionFlag_IsFpuContextRestoreNeeded = (1 << 2), ExceptionFlag_IsFpu64Bit = (1 << 3), ExceptionFlag_IsInUsermodeExceptionHandler = (1 << 4), ExceptionFlag_IsInCacheMaintenanceOperation = (1 << 5), ExceptionFlag_IsInTlbMaintenanceOperation = (1 << 6), #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) ExceptionFlag_IsHardwareSingleStep = (1 << 7), #endif }; struct StackParameters { svc::SvcAccessFlagSet svc_access_flags; KThreadContext::CallerSaveFpuRegisters *caller_save_fpu_registers; KThread *cur_thread; s16 disable_count; util::Atomic<u8> dpc_flags; u8 current_svc_id; u8 reserved_2c; util::Atomic<u8> exception_flags; bool is_pinned; u8 reserved_2f; u8 reserved_30[0x10]; KThreadContext context; }; static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10)); static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE); static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION); static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS); static_assert(AMS_OFFSETOF(StackParameters, cur_thread) == THREAD_STACK_PARAMETERS_CUR_THREAD); static_assert(AMS_OFFSETOF(StackParameters, disable_count) == THREAD_STACK_PARAMETERS_DISABLE_COUNT); static_assert(AMS_OFFSETOF(StackParameters, dpc_flags) == THREAD_STACK_PARAMETERS_DPC_FLAGS); static_assert(AMS_OFFSETOF(StackParameters, current_svc_id) == THREAD_STACK_PARAMETERS_CURRENT_SVC_ID); static_assert(AMS_OFFSETOF(StackParameters, reserved_2c) == THREAD_STACK_PARAMETERS_RESERVED_2C); static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS); static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED); static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F); static_assert(AMS_OFFSETOF(StackParameters, reserved_30) == THREAD_STACK_PARAMETERS_RESERVED_30); static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT); static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC); static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER); static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED); static_assert(ExceptionFlag_IsFpu64Bit == THREAD_EXCEPTION_FLAG_IS_FPU_64_BIT); static_assert(ExceptionFlag_IsInUsermodeExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_USERMODE_EXCEPTION_HANDLER); static_assert(ExceptionFlag_IsInCacheMaintenanceOperation == THREAD_EXCEPTION_FLAG_IS_IN_CACHE_MAINTENANCE_OPERATION); static_assert(ExceptionFlag_IsInTlbMaintenanceOperation == THREAD_EXCEPTION_FLAG_IS_IN_TLB_MAINTENANCE_OPERATION); #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) static_assert(ExceptionFlag_IsHardwareSingleStep == THREAD_EXCEPTION_FLAG_IS_HARDWARE_SINGLE_STEP); #endif struct QueueEntry { private: KThread *m_prev; KThread *m_next; public: constexpr void Initialize() { m_prev = nullptr; m_next = nullptr; } constexpr KThread *GetPrev() const { return m_prev; } constexpr KThread *GetNext() const { return m_next; } constexpr void SetPrev(KThread *t) { m_prev = t; } constexpr void SetNext(KThread *t) { m_next = t; } }; using WaiterList = util::IntrusiveListBaseTraits<KThread>::ListType; private: static constexpr size_t PriorityInheritanceCountMax = 10; union SyncObjectBuffer { KSynchronizationObject *m_sync_objects[ams::svc::ArgumentHandleCountMax]; ams::svc::Handle m_handles[ams::svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject *) / sizeof(ams::svc::Handle))]; constexpr explicit SyncObjectBuffer(util::ConstantInitializeTag) : m_sync_objects() { /* ... */ } explicit SyncObjectBuffer() { /* ... */ } }; static_assert(sizeof(SyncObjectBuffer::m_sync_objects) == sizeof(SyncObjectBuffer::m_handles)); struct ConditionVariableComparator { struct RedBlackKeyType { uintptr_t m_cv_key; s32 m_priority; constexpr ALWAYS_INLINE uintptr_t GetConditionVariableKey() const { return m_cv_key; } constexpr ALWAYS_INLINE s32 GetPriority() const { return m_priority; } }; template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) { const uintptr_t l_key = lhs.GetConditionVariableKey(); const uintptr_t r_key = rhs.GetConditionVariableKey(); if (l_key < r_key) { /* Sort first by key */ return -1; } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) { /* And then by priority. */ return -1; } else { return 1; } } }; static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>); static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>); struct LockWithPriorityInheritanceComparator { struct RedBlackKeyType { s32 m_priority; constexpr ALWAYS_INLINE s32 GetPriority() const { return m_priority; } }; template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) { if (lhs.GetPriority() < rhs.GetPriority()) { /* Sort by priority. */ return -1; } else { return 1; } } }; static_assert(ams::util::HasRedBlackKeyType<LockWithPriorityInheritanceComparator>); static_assert(std::same_as<ams::util::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>, LockWithPriorityInheritanceComparator::RedBlackKeyType>); private: util::IntrusiveListNode m_process_list_node; util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node; s32 m_priority; using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>; using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; using LockWithPriorityInheritanceThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>; using LockWithPriorityInheritanceThreadTree = ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>; public: class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, public util::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> { private: LockWithPriorityInheritanceThreadTree m_tree; KProcessAddress m_address_key; KThread *m_owner; u32 m_waiter_count; public: constexpr LockWithPriorityInheritanceInfo() : m_tree(), m_address_key(Null<KProcessAddress>), m_owner(nullptr), m_waiter_count() { /* ... */ } static LockWithPriorityInheritanceInfo *Create(KProcessAddress address_key) { /* Create a new lock info. */ auto *new_lock = LockWithPriorityInheritanceInfo::Allocate(); MESOSPHERE_ABORT_UNLESS(new_lock != nullptr); /* Set the new lock's address key. */ new_lock->m_address_key = address_key; return new_lock; } void SetOwner(KThread *new_owner) { /* Set new owner. */ m_owner = new_owner; } void AddWaiter(KThread *waiter) { /* Insert the waiter. */ m_tree.insert(*waiter); m_waiter_count++; waiter->SetWaitingLockInfo(this); } [[nodiscard]] bool RemoveWaiter(KThread *waiter) { m_tree.erase(m_tree.iterator_to(*waiter)); waiter->SetWaitingLockInfo(nullptr); return (--m_waiter_count) == 0; } KThread *GetHighestPriorityWaiter() { return std::addressof(m_tree.front()); } const KThread *GetHighestPriorityWaiter() const { return std::addressof(m_tree.front()); } LockWithPriorityInheritanceThreadTree &GetThreadTree() { return m_tree; } const LockWithPriorityInheritanceThreadTree &GetThreadTree() const { return m_tree; } constexpr KProcessAddress GetAddressKey() const { return m_address_key; } constexpr KThread *GetOwner() const { return m_owner; } constexpr u32 GetWaiterCount() const { return m_waiter_count; } }; private: using LockWithPriorityInheritanceInfoList = util::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType; ConditionVariableThreadTree *m_condvar_tree; uintptr_t m_condvar_key; alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers; u64 m_virtual_affinity_mask; KAffinityMask m_physical_affinity_mask; u64 m_thread_id; util::Atomic<s64> m_cpu_time; KProcessAddress m_address_key; KProcess *m_parent; void *m_kernel_stack_top; u32 *m_light_ipc_data; KProcessAddress m_tls_address; void *m_tls_heap_address; KLightLock m_activity_pause_lock; SyncObjectBuffer m_sync_object_buffer; s64 m_schedule_count; s64 m_last_scheduled_tick; QueueEntry m_per_core_priority_queue_entry[cpu::NumCores]; KThreadQueue *m_wait_queue; LockWithPriorityInheritanceInfoList m_held_lock_info_list; LockWithPriorityInheritanceInfo *m_waiting_lock_info; WaiterList m_pinned_waiter_list; uintptr_t m_debug_params[3]; KAutoObject *m_closed_object; u32 m_address_key_value; u32 m_suspend_request_flags; u32 m_suspend_allowed_flags; s32 m_synced_index; Result m_wait_result; Result m_debug_exception_result; s32 m_base_priority; s32 m_base_priority_on_unpin; s32 m_physical_ideal_core_id; s32 m_virtual_ideal_core_id; s32 m_num_kernel_waiters; s32 m_current_core_id; s32 m_core_id; KAffinityMask m_original_physical_affinity_mask; s32 m_original_physical_ideal_core_id; s32 m_num_core_migration_disables; ThreadState m_thread_state; util::Atomic<bool> m_termination_requested; bool m_wait_cancelled; bool m_cancellable; bool m_signaled; bool m_initialized; bool m_debug_attached; s8 m_priority_inheritance_count; bool m_resource_limit_release_hint; public: constexpr explicit KThread(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>(util::ConstantInitialize), KTimerTask(util::ConstantInitialize), m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{}, m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{}, m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize}, m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{}, m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{}, m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{}, m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{}, m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{}, m_cancellable{}, m_signaled{}, m_initialized{}, m_debug_attached{}, m_priority_inheritance_count{}, m_resource_limit_release_hint{} { /* ... */ } explicit KThread() : m_priority(-1), m_condvar_tree(nullptr), m_condvar_key(0), m_parent(nullptr), m_initialized(false) { /* ... */ } Result Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type); private: static Result InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type); public: static Result InitializeKernelThread(KThread *thread, KThreadFunction func, uintptr_t arg, s32 prio, s32 virt_core) { R_RETURN(InitializeThread(thread, func, arg, Null<KProcessAddress>, prio, virt_core, nullptr, ThreadType_Kernel)); } static Result InitializeHighPriorityThread(KThread *thread, KThreadFunction func, uintptr_t arg) { R_RETURN(InitializeThread(thread, func, arg, Null<KProcessAddress>, 0, GetCurrentCoreId(), nullptr, ThreadType_HighPriority)); } static Result InitializeUserThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner) { R_RETURN(InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, ThreadType_User)); } static void ResumeThreadsSuspendedForInit(); private: ALWAYS_INLINE StackParameters &GetStackParameters() { return *(reinterpret_cast< StackParameters *>(m_kernel_stack_top) - 1); } ALWAYS_INLINE const StackParameters &GetStackParameters() const { return *(reinterpret_cast<const StackParameters *>(m_kernel_stack_top) - 1); } public: ALWAYS_INLINE s16 GetDisableDispatchCount() const { MESOSPHERE_ASSERT_THIS(); return this->GetStackParameters().disable_count; } ALWAYS_INLINE void DisableDispatch() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() >= 0); this->GetStackParameters().disable_count++; } ALWAYS_INLINE void EnableDispatch() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() > 0); this->GetStackParameters().disable_count--; } void Pin(); void Unpin(); ALWAYS_INLINE void SaveDebugParams(uintptr_t param1, uintptr_t param2, uintptr_t param3) { m_debug_params[0] = param1; m_debug_params[1] = param2; m_debug_params[2] = param3; } ALWAYS_INLINE void RestoreDebugParams(uintptr_t *param1, uintptr_t *param2, uintptr_t *param3) { *param1 = m_debug_params[0]; *param2 = m_debug_params[1]; *param3 = m_debug_params[2]; } NOINLINE void DisableCoreMigration(); NOINLINE void EnableCoreMigration(); private: ALWAYS_INLINE void SetExceptionFlag(ExceptionFlag flag) { MESOSPHERE_ASSERT_THIS(); this->GetStackParameters().exception_flags.FetchOr<std::memory_order_relaxed>(flag); } ALWAYS_INLINE void ClearExceptionFlag(ExceptionFlag flag) { MESOSPHERE_ASSERT_THIS(); this->GetStackParameters().exception_flags.FetchAnd<std::memory_order_relaxed>(~flag); } ALWAYS_INLINE bool IsExceptionFlagSet(ExceptionFlag flag) const { MESOSPHERE_ASSERT_THIS(); return this->GetStackParameters().exception_flags.Load<std::memory_order_relaxed>() & flag; } public: /* ALWAYS_INLINE void SetCallingSvc() { return this->SetExceptionFlag(ExceptionFlag_IsCallingSvc); } */ /* ALWAYS_INLINE void ClearCallingSvc() { return this->ClearExceptionFlag(ExceptionFlag_IsCallingSvc); } */ ALWAYS_INLINE bool IsCallingSvc() const { return this->IsExceptionFlagSet(ExceptionFlag_IsCallingSvc); } ALWAYS_INLINE void SetInExceptionHandler() { return this->SetExceptionFlag(ExceptionFlag_IsInExceptionHandler); } ALWAYS_INLINE void ClearInExceptionHandler() { return this->ClearExceptionFlag(ExceptionFlag_IsInExceptionHandler); } ALWAYS_INLINE bool IsInExceptionHandler() const { return this->IsExceptionFlagSet(ExceptionFlag_IsInExceptionHandler); } /* ALWAYS_INLINE void SetFpuContextRestoreNeeded() { return this->SetExceptionFlag(ExceptionFlag_IsFpuContextRestoreNeeded); } */ /* ALWAYS_INLINE void ClearFpuContextRestoreNeeded() { return this->ClearExceptionFlag(ExceptionFlag_IsFpuContextRestoreNeeded); } */ /* ALWAYS_INLINE bool IsFpuContextRestoreNeeded() const { return this->IsExceptionFlagSet(ExceptionFlag_IsFpuContextRestoreNeeded); } */ ALWAYS_INLINE void SetFpu64Bit() { return this->SetExceptionFlag(ExceptionFlag_IsFpu64Bit); } /* ALWAYS_INLINE void ClearFpu64Bit() { return this->ClearExceptionFlag(ExceptionFlag_IsFpu64Bit); } */ /* ALWAYS_INLINE bool IsFpu64Bit() const { return this->IsExceptionFlagSet(ExceptionFlag_IsFpu64Bit); } */ ALWAYS_INLINE void SetInUsermodeExceptionHandler() { return this->SetExceptionFlag(ExceptionFlag_IsInUsermodeExceptionHandler); } ALWAYS_INLINE void ClearInUsermodeExceptionHandler() { return this->ClearExceptionFlag(ExceptionFlag_IsInUsermodeExceptionHandler); } ALWAYS_INLINE bool IsInUsermodeExceptionHandler() const { return this->IsExceptionFlagSet(ExceptionFlag_IsInUsermodeExceptionHandler); } ALWAYS_INLINE void SetInCacheMaintenanceOperation() { return this->SetExceptionFlag(ExceptionFlag_IsInCacheMaintenanceOperation); } ALWAYS_INLINE void ClearInCacheMaintenanceOperation() { return this->ClearExceptionFlag(ExceptionFlag_IsInCacheMaintenanceOperation); } ALWAYS_INLINE bool IsInCacheMaintenanceOperation() const { return this->IsExceptionFlagSet(ExceptionFlag_IsInCacheMaintenanceOperation); } ALWAYS_INLINE void SetInTlbMaintenanceOperation() { return this->SetExceptionFlag(ExceptionFlag_IsInTlbMaintenanceOperation); } ALWAYS_INLINE void ClearInTlbMaintenanceOperation() { return this->ClearExceptionFlag(ExceptionFlag_IsInTlbMaintenanceOperation); } ALWAYS_INLINE bool IsInTlbMaintenanceOperation() const { return this->IsExceptionFlagSet(ExceptionFlag_IsInTlbMaintenanceOperation); } #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) ALWAYS_INLINE void SetHardwareSingleStep() { return this->SetExceptionFlag(ExceptionFlag_IsHardwareSingleStep); } ALWAYS_INLINE void ClearHardwareSingleStep() { return this->ClearExceptionFlag(ExceptionFlag_IsHardwareSingleStep); } ALWAYS_INLINE bool IsHardwareSingleStep() const { return this->IsExceptionFlagSet(ExceptionFlag_IsHardwareSingleStep); } #endif ALWAYS_INLINE u8 GetSvcId() const { MESOSPHERE_ASSERT_THIS(); return this->GetStackParameters().current_svc_id; } ALWAYS_INLINE void RegisterDpc(DpcFlag flag) { this->GetStackParameters().dpc_flags |= flag; } ALWAYS_INLINE void ClearDpc(DpcFlag flag) { this->GetStackParameters().dpc_flags &= ~flag; } ALWAYS_INLINE u8 GetDpc() const { return this->GetStackParameters().dpc_flags.Load(); } ALWAYS_INLINE bool HasDpc() const { MESOSPHERE_ASSERT_THIS(); return this->GetDpc() != 0; } private: void SetPinnedSvcPermissions(); void SetUnpinnedSvcPermissions(); void SetUsermodeExceptionSvcPermissions(); void ClearUsermodeExceptionSvcPermissions(); private: void UpdateState(); ALWAYS_INLINE void AddHeldLock(LockWithPriorityInheritanceInfo *lock_info); ALWAYS_INLINE LockWithPriorityInheritanceInfo *FindHeldLock(KProcessAddress address_key); ALWAYS_INLINE void AddWaiterImpl(KThread *thread); ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread); ALWAYS_INLINE static void RestorePriority(KThread *thread); void StartTermination(); void FinishTermination(); void IncreaseBasePriority(s32 priority); NOINLINE void SetState(ThreadState state); public: constexpr u64 GetThreadId() const { return m_thread_id; } const KThreadContext &GetContext() const { return this->GetStackParameters().context; } KThreadContext &GetContext() { return this->GetStackParameters().context; } const auto &GetCallerSaveFpuRegisters() const { return m_caller_save_fpu_registers; } auto &GetCallerSaveFpuRegisters() { return m_caller_save_fpu_registers; } constexpr u64 GetVirtualAffinityMask() const { return m_virtual_affinity_mask; } constexpr const KAffinityMask &GetAffinityMask() const { return m_physical_affinity_mask; } Result GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask); Result SetCoreMask(int32_t ideal_core, u64 affinity_mask); void GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask); constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); } constexpr ThreadState GetRawState() const { return m_thread_state; } constexpr uintptr_t GetConditionVariableKey() const { return m_condvar_key; } constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; } constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_condvar_tree = tree; m_condvar_key = cv_key; m_address_key = address; m_address_key_value = value; } constexpr void ClearConditionVariable() { m_condvar_tree = nullptr; } constexpr bool IsWaitingForConditionVariable() const { return m_condvar_tree != nullptr; } constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_condvar_tree = tree; m_condvar_key = address; } constexpr void ClearAddressArbiter() { m_condvar_tree = nullptr; } constexpr bool IsWaitingForAddressArbiter() const { return m_condvar_tree != nullptr; } constexpr s32 GetIdealVirtualCore() const { return m_virtual_ideal_core_id; } constexpr s32 GetIdealPhysicalCore() const { return m_physical_ideal_core_id; } constexpr s32 GetActiveCore() const { return m_core_id; } constexpr void SetActiveCore(s32 core) { m_core_id = core; } constexpr ALWAYS_INLINE s32 GetCurrentCore() const { return m_current_core_id; } constexpr void SetCurrentCore(s32 core) { m_current_core_id = core; } constexpr s32 GetPriority() const { return m_priority; } constexpr void SetPriority(s32 prio) { m_priority = prio; } constexpr s32 GetBasePriority() const { return m_base_priority; } constexpr QueueEntry &GetPriorityQueueEntry(s32 core) { return m_per_core_priority_queue_entry[core]; } constexpr const QueueEntry &GetPriorityQueueEntry(s32 core) const { return m_per_core_priority_queue_entry[core]; } constexpr ConditionVariableThreadTree *GetConditionVariableTree() const { return m_condvar_tree; } constexpr s32 GetNumKernelWaiters() const { return m_num_kernel_waiters; } void AddWaiter(KThread *thread); void RemoveWaiter(KThread *thread); KThread *RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key); constexpr KProcessAddress GetAddressKey() const { return m_address_key; } constexpr u32 GetAddressKeyValue() const { return m_address_key_value; } constexpr void SetAddressKey(KProcessAddress key) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; } constexpr void SetAddressKey(KProcessAddress key, u32 val) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; m_address_key_value = val; } constexpr void SetWaitingLockInfo(LockWithPriorityInheritanceInfo *lock) { m_waiting_lock_info = lock; } constexpr LockWithPriorityInheritanceInfo *GetWaitingLockInfo() { return m_waiting_lock_info; } constexpr KThread *GetLockOwner() const { return m_waiting_lock_info != nullptr ? m_waiting_lock_info->GetOwner() : nullptr; } constexpr void ClearWaitQueue() { m_wait_queue = nullptr; } void BeginWait(KThreadQueue *queue); void NotifyAvailable(KSynchronizationObject *signaled_object, Result wait_result); void EndWait(Result wait_result); void CancelWait(Result wait_result, bool cancel_timer_task); constexpr void SetSyncedIndex(s32 index) { m_synced_index = index; } constexpr s32 GetSyncedIndex() const { return m_synced_index; } constexpr void SetWaitResult(Result wait_res) { m_wait_result = wait_res; } constexpr Result GetWaitResult() const { return m_wait_result; } constexpr void SetDebugExceptionResult(Result result) { m_debug_exception_result = result; } constexpr Result GetDebugExceptionResult() const { return m_debug_exception_result; } void WaitCancel(); bool IsWaitCancelled() const { return m_wait_cancelled; } void ClearWaitCancelled() { m_wait_cancelled = false; } void ClearCancellable() { m_cancellable = false; } void SetCancellable() { m_cancellable = true; } constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; } constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; } constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; } constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; } constexpr s64 GetYieldScheduleCount() const { return m_schedule_count; } constexpr void SetYieldScheduleCount(s64 count) { m_schedule_count = count; } constexpr KProcess *GetOwnerProcess() const { return m_parent; } constexpr bool IsUserThread() const { return m_parent != nullptr; } constexpr KProcessAddress GetThreadLocalRegionAddress() const { return m_tls_address; } constexpr void *GetThreadLocalRegionHeapAddress() const { return m_tls_heap_address; } constexpr KSynchronizationObject **GetSynchronizationObjectBuffer() { return std::addressof(m_sync_object_buffer.m_sync_objects[0]); } constexpr ams::svc::Handle *GetHandleBuffer() { return std::addressof(m_sync_object_buffer.m_handles[sizeof(m_sync_object_buffer.m_sync_objects) / (sizeof(ams::svc::Handle)) - ams::svc::ArgumentHandleCountMax]); } u16 GetUserDisableCount() const { return static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->disable_count; } void SetInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 1; } void ClearInterruptFlag() const { static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->interrupt_flag = 0; } bool IsInUserCacheMaintenanceOperation() const { return static_cast<ams::svc::ThreadLocalRegion *>(m_tls_heap_address)->cache_maintenance_flag != 0; } ALWAYS_INLINE KAutoObject *GetClosedObject() { return m_closed_object; } ALWAYS_INLINE void SetClosedObject(KAutoObject *object) { MESOSPHERE_ASSERT(object != nullptr); /* Set the object to destroy. */ m_closed_object = object; /* Schedule destruction DPC. */ if ((this->GetStackParameters().dpc_flags.Load<std::memory_order_relaxed>() & DpcFlag_PerformDestruction) == 0) { this->RegisterDpc(DpcFlag_PerformDestruction); } } ALWAYS_INLINE void DestroyClosedObjects() { /* Destroy all objects that have been closed. */ if (KAutoObject *cur = m_closed_object; cur != nullptr) { do { /* Set our closed object as the next to close. */ m_closed_object = cur->GetNextClosedObject(); /* Destroy the current object. */ cur->Destroy(); /* Advance. */ cur = m_closed_object; } while (cur != nullptr); /* Clear the pending DPC. */ this->ClearDpc(DpcFlag_PerformDestruction); } } constexpr void SetDebugAttached() { m_debug_attached = true; } constexpr bool IsAttachedToDebugger() const { return m_debug_attached; } void AddCpuTime(s32 core_id, s64 amount) { m_cpu_time += amount; /* TODO: Debug kernels track per-core tick counts. Should we? */ MESOSPHERE_UNUSED(core_id); } s64 GetCpuTime() const { return m_cpu_time.Load(); } s64 GetCpuTime(s32 core_id) const { MESOSPHERE_ABORT_UNLESS(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores)); /* TODO: Debug kernels track per-core tick counts. Should we? */ return 0; } constexpr u32 GetSuspendFlags() const { return m_suspend_allowed_flags & m_suspend_request_flags; } constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; } constexpr bool IsSuspendRequested(SuspendType type) const { return (m_suspend_request_flags & (1u << (util::ToUnderlying(ThreadState_SuspendShift) + util::ToUnderlying(type)))) != 0; } constexpr bool IsSuspendRequested() const { return m_suspend_request_flags != 0; } void RequestSuspend(SuspendType type); void Resume(SuspendType type); void TrySuspend(); void Continue(); Result SetActivity(ams::svc::ThreadActivity activity); Result GetThreadContext3(ams::svc::ThreadContext *out); void ContinueIfHasKernelWaiters() { if (this->GetNumKernelWaiters() > 0) { this->Continue(); } } void SetBasePriority(s32 priority); void SetPriorityToIdle(); Result Run(); void Exit(); Result Terminate(); ThreadState RequestTerminate(); void Sleep(s64 timeout); ALWAYS_INLINE void *GetStackTop() const { return reinterpret_cast<StackParameters *>(m_kernel_stack_top) - 1; } ALWAYS_INLINE void *GetKernelStackTop() const { return m_kernel_stack_top; } ALWAYS_INLINE bool IsTerminationRequested() const { return m_termination_requested.Load() || this->GetRawState() == ThreadState_Terminated; } size_t GetKernelStackUsage() const; void OnEnterUsermodeException(); void OnLeaveUsermodeException(); public: /* Overridden parent functions. */ ALWAYS_INLINE u64 GetIdImpl() const { return this->GetThreadId(); } ALWAYS_INLINE u64 GetId() const { return this->GetIdImpl(); } bool IsInitialized() const { return m_initialized; } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_parent) | (m_resource_limit_release_hint ? 1 : 0); } static void PostDestroy(uintptr_t arg); void Finalize(); virtual bool IsSignaled() const override; void OnTimer(); void DoWorkerTaskImpl(); public: static consteval bool IsKThreadStructurallyValid(); static KThread *GetThreadFromId(u64 thread_id); static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count); using ConditionVariableThreadTreeType = ConditionVariableThreadTree; }; static_assert(alignof(KThread) == 0x10); consteval bool KThread::IsKThreadStructurallyValid() { /* Check that the condition variable tree is valid. */ static_assert(ConditionVariableThreadTreeTraits::IsValid()); /* Check that the assembly offsets are valid. */ static_assert(AMS_OFFSETOF(KThread, m_kernel_stack_top) == THREAD_KERNEL_STACK_TOP); return true; } static_assert(KThread::IsKThreadStructurallyValid()); class KScopedDisableDispatch { public: explicit ALWAYS_INLINE KScopedDisableDispatch() { GetCurrentThread().DisableDispatch(); } NOINLINE ~KScopedDisableDispatch(); }; ALWAYS_INLINE KExceptionContext *GetExceptionContext(KThread *thread) { return reinterpret_cast<KExceptionContext *>(reinterpret_cast<uintptr_t>(thread->GetKernelStackTop()) - sizeof(KThread::StackParameters) - sizeof(KExceptionContext)); } ALWAYS_INLINE const KExceptionContext *GetExceptionContext(const KThread *thread) { return reinterpret_cast<const KExceptionContext *>(reinterpret_cast<uintptr_t>(thread->GetKernelStackTop()) - sizeof(KThread::StackParameters) - sizeof(KExceptionContext)); } ALWAYS_INLINE KProcess *GetCurrentProcessPointer() { return GetCurrentThread().GetOwnerProcess(); } ALWAYS_INLINE KProcess &GetCurrentProcess() { return *GetCurrentProcessPointer(); } ALWAYS_INLINE s32 GetCurrentCoreId() { return GetCurrentThread().GetCurrentCore(); } ALWAYS_INLINE void KTimerTask::OnTimer() { static_cast<KThread *>(this)->OnTimer(); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_thread_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_k_thread_context.hpp> namespace ams::kern { using ams::kern::arch::arm64::KThreadContext; using ams::kern::arch::arm64::GetUserContext; } #else #error "Unknown architecture for KThreadContext" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_thread_local_page.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_slab_helpers.hpp> #include <mesosphere/kern_k_page_buffer.hpp> namespace ams::kern { class KThread; class KProcess; class KThreadLocalPage : public util::IntrusiveRedBlackTreeBaseNode<KThreadLocalPage>, public KSlabAllocated<KThreadLocalPage> { public: static constexpr size_t RegionsPerPage = PageSize / ams::svc::ThreadLocalRegionSize; static_assert(RegionsPerPage > 0); private: KProcessAddress m_virt_addr; KProcess *m_owner; bool m_is_region_free[RegionsPerPage]; public: explicit KThreadLocalPage(KProcessAddress addr) : m_virt_addr(addr), m_owner(nullptr) { for (size_t i = 0; i < util::size(m_is_region_free); i++) { m_is_region_free[i] = true; } } explicit KThreadLocalPage() : KThreadLocalPage(Null<KProcessAddress>) { /* ... */ } constexpr ALWAYS_INLINE KProcessAddress GetAddress() const { return m_virt_addr; } public: using RedBlackKeyType = KProcessAddress; static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; } static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KThreadLocalPage &v) { return v.GetAddress(); } template<typename T> requires (std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThreadLocalPage &rhs) { const KProcessAddress lval = GetRedBlackKey(lhs); const KProcessAddress rval = GetRedBlackKey(rhs); if (lval < rval) { return -1; } else if (lval == rval) { return 0; } else { return 1; } } private: constexpr ALWAYS_INLINE KProcessAddress GetRegionAddress(size_t i) { return this->GetAddress() + i * ams::svc::ThreadLocalRegionSize; } constexpr ALWAYS_INLINE bool Contains(KProcessAddress addr) { return this->GetAddress() <= addr && addr < this->GetAddress() + PageSize; } constexpr ALWAYS_INLINE size_t GetRegionIndex(KProcessAddress addr) { MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), ams::svc::ThreadLocalRegionSize)); MESOSPHERE_ASSERT(this->Contains(addr)); return (addr - this->GetAddress()) / ams::svc::ThreadLocalRegionSize; } public: Result Initialize(KProcess *process); void Finalize(); KProcessAddress Reserve(); void Release(KProcessAddress addr); void *GetPointer() const; bool IsAllUsed() const { for (size_t i = 0; i < RegionsPerPage; i++) { if (m_is_region_free[i]) { return false; } } return true; } bool IsAllFree() const { for (size_t i = 0; i < RegionsPerPage; i++) { if (!m_is_region_free[i]) { return false; } } return true; } bool IsAnyUsed() const { return !this->IsAllFree(); } bool IsAnyFree() const { return !this->IsAllUsed(); } }; /* Miscellaneous sanity checking. */ static_assert(ams::svc::ThreadLocalRegionSize == THREAD_LOCAL_REGION_SIZE); static_assert(AMS_OFFSETOF(ams::svc::ThreadLocalRegion, message_buffer) == THREAD_LOCAL_REGION_MESSAGE_BUFFER); static_assert(AMS_OFFSETOF(ams::svc::ThreadLocalRegion, disable_count) == THREAD_LOCAL_REGION_DISABLE_COUNT); static_assert(AMS_OFFSETOF(ams::svc::ThreadLocalRegion, interrupt_flag) == THREAD_LOCAL_REGION_INTERRUPT_FLAG); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_thread_queue.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_select_hardware_timer.hpp> namespace ams::kern { class KThreadQueue { private: KHardwareTimer *m_hardware_timer; public: constexpr ALWAYS_INLINE KThreadQueue() : m_hardware_timer(nullptr) { /* ... */ } constexpr void SetHardwareTimer(KHardwareTimer *timer) { m_hardware_timer = timer; } virtual void NotifyAvailable(KThread *waiting_thread, KSynchronizationObject *signaled_object, Result wait_result); virtual void EndWait(KThread *waiting_thread, Result wait_result); virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task); }; class KThreadQueueWithoutEndWait : public KThreadQueue { public: constexpr ALWAYS_INLINE KThreadQueueWithoutEndWait() : KThreadQueue() { /* ... */ } virtual void EndWait(KThread *waiting_thread, Result wait_result) override final; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_timer_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { class KTimerTask : public util::IntrusiveRedBlackTreeBaseNode<KTimerTask> { private: s64 m_time; public: static constexpr ALWAYS_INLINE int Compare(const KTimerTask &lhs, const KTimerTask &rhs) { if (lhs.GetTime() < rhs.GetTime()) { return -1; } else { return 1; } } public: constexpr explicit ALWAYS_INLINE KTimerTask(util::ConstantInitializeTag) : util::IntrusiveRedBlackTreeBaseNode<KTimerTask>(util::ConstantInitialize), m_time(0) { /* ... */ } explicit ALWAYS_INLINE KTimerTask() : m_time(0) { /* ... */ } constexpr ALWAYS_INLINE void SetTime(s64 t) { m_time = t; } constexpr ALWAYS_INLINE s64 GetTime() const { return m_time; } /* NOTE: This is virtual in Nintendo's kernel. Prior to 13.0.0, KWaitObject was also a TimerTask; this is no longer the case. */ /* Since this is now KThread exclusive, we have devirtualized (see inline declaration for this inside kern_kthread.hpp). */ void OnTimer(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_trace.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_spin_lock.hpp> namespace ams::kern { #if defined(MESOSPHERE_BUILD_FOR_TRACING) constexpr inline bool IsKTraceEnabled = true; #else constexpr inline bool IsKTraceEnabled = false; #endif constexpr inline size_t KTraceBufferSize = IsKTraceEnabled ? 16_MB : 0; static_assert(IsKTraceEnabled || !IsKTraceEnabled); static_assert((IsKTraceEnabled) ^ (KTraceBufferSize == 0)); class KTrace { public: enum Type { Type_ThreadSwitch = 1, Type_SvcEntry0 = 3, Type_SvcEntry1 = 4, Type_SvcExit0 = 5, Type_SvcExit1 = 6, Type_Interrupt = 7, Type_ScheduleUpdate = 11, Type_CoreMigration = 14, }; private: static bool s_is_active; public: static void Initialize(KVirtualAddress address, size_t size); static void Start(); static void Stop(); static void PushRecord(u8 type, u64 param0 = 0, u64 param1 = 0, u64 param2 = 0, u64 param3 = 0, u64 param4 = 0, u64 param5 = 0); static ALWAYS_INLINE bool IsActive() { return s_is_active; } }; } #define MESOSPHERE_KTRACE_RESUME() \ ({ \ if constexpr (::ams::kern::IsKTraceEnabled) { \ ::ams::kern::KTrace::Start(); \ } \ }) #define MESOSPHERE_KTRACE_PAUSE() \ ({ \ if constexpr (::ams::kern::IsKTraceEnabled) { \ ::ams::kern::KTrace::Stop(); \ } \ }) #define MESOSPHERE_KTRACE_PUSH_RECORD(TYPE, ...) \ ({ \ if constexpr (::ams::kern::IsKTraceEnabled) { \ if (::ams::kern::KTrace::IsActive()) { \ ::ams::kern::KTrace::PushRecord(TYPE, ## __VA_ARGS__); \ } \ } \ }) #define MESOSPHERE_KTRACE_THREAD_SWITCH(NEXT) \ MESOSPHERE_KTRACE_PUSH_RECORD(::ams::kern::KTrace::Type_ThreadSwitch, (NEXT)->GetId()) #define MESOSPHERE_KTRACE_SVC_ENTRY(SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7) \ ({ \ if constexpr (::ams::kern::IsKTraceEnabled) { \ if (::ams::kern::KTrace::IsActive()) { \ ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcEntry0, SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4); \ ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcEntry1, PARAM5, PARAM6, PARAM7); \ } \ } \ }) #define MESOSPHERE_KTRACE_SVC_EXIT(SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7) \ ({ \ if constexpr (::ams::kern::IsKTraceEnabled) { \ if (::ams::kern::KTrace::IsActive()) { \ ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcExit0, SVC_ID, PARAM0, PARAM1, PARAM2, PARAM3, PARAM4); \ ::ams::kern::KTrace::PushRecord(::ams::kern::KTrace::Type_SvcExit1, PARAM5, PARAM6, PARAM7); \ } \ } \ }) #define MESOSPHERE_KTRACE_INTERRUPT(ID) \ MESOSPHERE_KTRACE_PUSH_RECORD(::ams::kern::KTrace::Type_Interrupt, ID) #define MESOSPHERE_KTRACE_SCHEDULE_UPDATE(CORE, PREV, NEXT) \ MESOSPHERE_KTRACE_PUSH_RECORD(::ams::kern::KTrace::Type_ScheduleUpdate, CORE, (PREV)->GetId(), (NEXT)->GetId()) #define MESOSPHERE_KTRACE_CORE_MIGRATION(THREAD_ID, PREV, NEXT, REASON) \ MESOSPHERE_KTRACE_PUSH_RECORD(::ams::kern::KTrace::Type_CoreMigration, THREAD_ID, PREV, NEXT, REASON) ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_transfer_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_slab_helpers.hpp> namespace ams::kern { class KTransferMemory final : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> { MESOSPHERE_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject); private: util::TypedStorage<KPageGroup> m_page_group; KProcess *m_owner; KProcessAddress m_address; KLightLock m_lock; ams::svc::MemoryPermission m_owner_perm; bool m_is_initialized; bool m_is_mapped; public: explicit KTransferMemory() : m_owner(nullptr), m_address(Null<KProcessAddress>), m_owner_perm(ams::svc::MemoryPermission_None), m_is_initialized(false), m_is_mapped(false) { /* ... */ } Result Initialize(KProcessAddress addr, size_t size, ams::svc::MemoryPermission own_perm); void Finalize(); bool IsInitialized() const { return m_is_initialized; } uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); } static void PostDestroy(uintptr_t arg); Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Unmap(KProcessAddress address, size_t size); KProcess *GetOwner() const { return m_owner; } KProcessAddress GetSourceAddress() { return m_address; } size_t GetSize() const { return m_is_initialized ? GetReference(m_page_group).GetNumPages() * PageSize : 0; } constexpr uintptr_t GetHint() const { /* Get memory size. */ const size_t size = this->GetSize(); /* TODO: Is this architecture specific? */ if (size >= 2_MB) { return GetInteger(m_address) & (2_MB - 1); } else if (size >= 64_KB) { return GetInteger(m_address) & (64_KB - 1); } else if (size >= 4_KB) { return GetInteger(m_address) & (4_KB - 1); } else { return 0; } } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_typed_address.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { #ifndef MESOSPHERE_DISABLE_TYPED_ADDRESSES template<bool Virtual, typename T> class KTypedAddress { private: uintptr_t m_address; public: /* Constructors. */ ALWAYS_INLINE KTypedAddress() { /* ... */ } constexpr ALWAYS_INLINE KTypedAddress(uintptr_t a) : m_address(a) { /* ... */ } template<typename U> constexpr ALWAYS_INLINE explicit KTypedAddress(U *ptr) : m_address(reinterpret_cast<uintptr_t>(ptr)) { /* ... */ } /* Copy constructor. */ constexpr ALWAYS_INLINE KTypedAddress(const KTypedAddress &rhs) = default; /* Assignment operator. */ constexpr ALWAYS_INLINE KTypedAddress &operator=(const KTypedAddress &rhs) = default; /* Arithmetic operators. */ template<typename I> constexpr ALWAYS_INLINE KTypedAddress operator+(I rhs) const { static_assert(std::is_integral<I>::value); return m_address + rhs; } template<typename I> constexpr ALWAYS_INLINE KTypedAddress operator-(I rhs) const { static_assert(std::is_integral<I>::value); return m_address - rhs; } constexpr ALWAYS_INLINE ptrdiff_t operator-(KTypedAddress rhs) const { return m_address - rhs.m_address; } template<typename I> constexpr ALWAYS_INLINE KTypedAddress operator+=(I rhs) { static_assert(std::is_integral<I>::value); m_address += rhs; return *this; } template<typename I> constexpr ALWAYS_INLINE KTypedAddress operator-=(I rhs) { static_assert(std::is_integral<I>::value); m_address -= rhs; return *this; } /* Logical operators. */ constexpr ALWAYS_INLINE uintptr_t operator&(uintptr_t mask) const { return m_address & mask; } constexpr ALWAYS_INLINE uintptr_t operator|(uintptr_t mask) const { return m_address | mask; } constexpr ALWAYS_INLINE uintptr_t operator<<(int shift) const { return m_address << shift; } constexpr ALWAYS_INLINE uintptr_t operator>>(int shift) const { return m_address >> shift; } template<typename U> constexpr ALWAYS_INLINE size_t operator/(U size) const { return m_address / size; } /* constexpr ALWAYS_INLINE uintptr_t operator%(U align) const { return m_address % align; } */ /* Comparison operators. */ constexpr ALWAYS_INLINE bool operator==(KTypedAddress rhs) const { return m_address == rhs.m_address; } constexpr ALWAYS_INLINE bool operator!=(KTypedAddress rhs) const { return m_address != rhs.m_address; } constexpr ALWAYS_INLINE bool operator<(KTypedAddress rhs) const { return m_address < rhs.m_address; } constexpr ALWAYS_INLINE bool operator<=(KTypedAddress rhs) const { return m_address <= rhs.m_address; } constexpr ALWAYS_INLINE bool operator>(KTypedAddress rhs) const { return m_address > rhs.m_address; } constexpr ALWAYS_INLINE bool operator>=(KTypedAddress rhs) const { return m_address >= rhs.m_address; } /* For convenience, also define comparison operators versus uintptr_t. */ constexpr ALWAYS_INLINE bool operator==(uintptr_t rhs) const { return m_address == rhs; } /* Allow getting the address explicitly, for use in accessors. */ constexpr ALWAYS_INLINE uintptr_t GetValue() const { return m_address; } }; struct KPhysicalAddressTag{}; struct KVirtualAddressTag{}; struct KProcessAddressTag{}; using KPhysicalAddress = KTypedAddress<false, KPhysicalAddressTag>; using KVirtualAddress = KTypedAddress<true, KVirtualAddressTag>; using KProcessAddress = KTypedAddress<true, KProcessAddressTag>; /* Define accessors. */ template<bool Virtual, typename T> constexpr ALWAYS_INLINE uintptr_t GetInteger(KTypedAddress<Virtual, T> address) { return address.GetValue(); } template<typename T, typename U> ALWAYS_INLINE T *GetPointer(KTypedAddress<true, U> address) { return reinterpret_cast<T *>(address.GetValue()); } template<typename T> ALWAYS_INLINE void *GetVoidPointer(KTypedAddress<true, T> address) { return reinterpret_cast<void *>(address.GetValue()); } #else /* Plausibly, we may not want compiler overhead from using strongly typed addresses. */ /* In this case, we should just use uintptr_t. */ using KPhysicalAddress = uintptr_t; using KVirtualAddress = uintptr_t; using KProcessAddress = uintptr_t; /* Define accessors. */ constexpr ALWAYS_INLINE uintptr_t GetInteger(uintptr_t address) { return address; } template<typename T> constexpr ALWAYS_INLINE T *GetPointer(uintptr_t address) { return reinterpret_cast<T *>(address); } template<typename T> constexpr ALWAYS_INLINE void *GetVoidPointer(uintptr_t address) { return reinterpret_cast<void *>(address); } #endif template<typename T> concept IsKTypedAddress = std::same_as<T, KPhysicalAddress> || std::same_as<T, KVirtualAddress> || std::same_as<T, KProcessAddress>; template<typename T> constexpr inline T Null = [] { if constexpr (std::is_same<T, uintptr_t>::value) { return 0; } else { static_assert(std::is_same<T, KPhysicalAddress>::value || std::is_same<T, KVirtualAddress>::value || std::is_same<T, KProcessAddress>::value); return T(0); } }(); /* Basic type validations. */ static_assert(sizeof(KPhysicalAddress) == sizeof(uintptr_t)); static_assert(sizeof(KVirtualAddress) == sizeof(uintptr_t)); static_assert(sizeof(KProcessAddress) == sizeof(uintptr_t)); static_assert(std::is_trivially_copyable<KPhysicalAddress>::value); static_assert(std::is_trivially_copyable<KVirtualAddress>::value); static_assert(std::is_trivially_copyable<KProcessAddress>::value); static_assert(std::is_trivially_copy_constructible<KPhysicalAddress>::value); static_assert(std::is_trivially_copy_constructible<KVirtualAddress>::value); static_assert(std::is_trivially_copy_constructible<KProcessAddress>::value); static_assert(std::is_trivially_move_constructible<KPhysicalAddress>::value); static_assert(std::is_trivially_move_constructible<KVirtualAddress>::value); static_assert(std::is_trivially_move_constructible<KProcessAddress>::value); static_assert(std::is_trivially_copy_assignable<KPhysicalAddress>::value); static_assert(std::is_trivially_copy_assignable<KVirtualAddress>::value); static_assert(std::is_trivially_copy_assignable<KProcessAddress>::value); static_assert(std::is_trivially_move_assignable<KPhysicalAddress>::value); static_assert(std::is_trivially_move_assignable<KVirtualAddress>::value); static_assert(std::is_trivially_move_assignable<KProcessAddress>::value); static_assert(std::is_trivially_destructible<KPhysicalAddress>::value); static_assert(std::is_trivially_destructible<KVirtualAddress>::value); static_assert(std::is_trivially_destructible<KProcessAddress>::value); static_assert(Null<uintptr_t> == 0); static_assert(Null<KPhysicalAddress> == Null<uintptr_t>); static_assert(Null<KVirtualAddress> == Null<uintptr_t>); static_assert(Null<KProcessAddress> == Null<uintptr_t>); /* Constructor/assignment validations. */ static_assert([]{ const KPhysicalAddress a(5); KPhysicalAddress b(a); return b; }() == KPhysicalAddress(5)); static_assert([]{ const KPhysicalAddress a(5); KPhysicalAddress b(10); b = a; return b; }() == KPhysicalAddress(5)); /* Arithmetic validations. */ static_assert(KPhysicalAddress(10) + 5 == KPhysicalAddress(15)); static_assert(KPhysicalAddress(10) - 5 == KPhysicalAddress(5)); static_assert([]{ KPhysicalAddress v(10); v += 5; return v; }() == KPhysicalAddress(15)); static_assert([]{ KPhysicalAddress v(10); v -= 5; return v; }() == KPhysicalAddress(5)); /* Logical validations. */ static_assert((KPhysicalAddress(0b11111111) >> 1) == 0b01111111); static_assert((KPhysicalAddress(0b10101010) >> 1) == 0b01010101); static_assert((KPhysicalAddress(0b11111111) << 1) == 0b111111110); static_assert((KPhysicalAddress(0b01010101) << 1) == 0b10101010); static_assert((KPhysicalAddress(0b11111111) & 0b01010101) == 0b01010101); static_assert((KPhysicalAddress(0b11111111) & 0b10101010) == 0b10101010); static_assert((KPhysicalAddress(0b01010101) & 0b10101010) == 0b00000000); static_assert((KPhysicalAddress(0b00000000) | 0b01010101) == 0b01010101); static_assert((KPhysicalAddress(0b11111111) | 0b01010101) == 0b11111111); static_assert((KPhysicalAddress(0b10101010) | 0b01010101) == 0b11111111); /* Comparisons. */ static_assert(KPhysicalAddress(0) == KPhysicalAddress(0)); static_assert(KPhysicalAddress(0) != KPhysicalAddress(1)); static_assert(KPhysicalAddress(0) < KPhysicalAddress(1)); static_assert(KPhysicalAddress(0) <= KPhysicalAddress(1)); static_assert(KPhysicalAddress(1) > KPhysicalAddress(0)); static_assert(KPhysicalAddress(1) >= KPhysicalAddress(0)); static_assert(!(KPhysicalAddress(0) == KPhysicalAddress(1))); static_assert(!(KPhysicalAddress(0) != KPhysicalAddress(0))); static_assert(!(KPhysicalAddress(1) < KPhysicalAddress(0))); static_assert(!(KPhysicalAddress(1) <= KPhysicalAddress(0))); static_assert(!(KPhysicalAddress(0) > KPhysicalAddress(1))); static_assert(!(KPhysicalAddress(0) >= KPhysicalAddress(1))); /* Accessors. */ static_assert(15 == GetInteger(KPhysicalAddress(15))); static_assert(0 == GetInteger(Null<KPhysicalAddress>)); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_unsafe_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_light_lock.hpp> namespace ams::kern { class KUnsafeMemory { private: mutable KLightLock m_lock; size_t m_limit_size; size_t m_current_size; public: constexpr KUnsafeMemory() : m_lock(), m_limit_size(), m_current_size() { /* ... */ } bool TryReserve(size_t size) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); /* Test for overflow. */ if (m_current_size > m_current_size + size) { return false; } /* Test for limit allowance. */ if (m_current_size + size > m_limit_size) { return false; } /* Reserve the size. */ m_current_size += size; return true; } void Release(size_t size) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); MESOSPHERE_ABORT_UNLESS(m_current_size >= size); m_current_size -= size; } size_t GetLimitSize() const { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); return m_limit_size; } size_t GetCurrentSize() const { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); return m_current_size; } Result SetLimitSize(size_t size) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); R_UNLESS(size >= m_current_size, svc::ResultLimitReached()); m_limit_size = size; R_SUCCEED(); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_unused_slab_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> namespace ams::kern { /* Utilities to allocate/free memory from the "unused" gaps between slab heaps. */ /* See KTargetSystem::IsDynamicResourceLimitsEnabled() usage for more context. */ KVirtualAddress AllocateUnusedSlabMemory(size_t size, size_t alignment); void FreeUnusedSlabMemory(KVirtualAddress address, size_t size); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_wait_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_timer_task.hpp> #include <mesosphere/kern_k_thread.hpp> namespace ams::kern { class KWaitObject { private: KThread::WaiterList m_wait_list; KThread *m_next_thread; public: constexpr KWaitObject() : m_wait_list(), m_next_thread() { /* ... */ } Result Synchronize(s64 timeout); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_worker_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { /* NOTE: We inherit KWorkerTask from KSynchronizationObject in order to devirtualize DoWorkerTask, which is exclusive to KThread/KProcess. */ /* This should be reverted, if Nintendo adds new types of worker tasks in the future. */ /* Nintendo has class KWorkerTask { ... } with identical interface but DoWorkerTask() virtual. */ class KWorkerTask : public KSynchronizationObject { private: KWorkerTask *m_next_task; public: constexpr ALWAYS_INLINE explicit KWorkerTask(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_next_task(nullptr) { /* ... */ } ALWAYS_INLINE explicit KWorkerTask() : m_next_task(nullptr) { /* ... */ } constexpr ALWAYS_INLINE KWorkerTask *GetNextTask() const { return m_next_task; } constexpr ALWAYS_INLINE void SetNextTask(KWorkerTask *task) { m_next_task = task; } void DoWorkerTask(); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_k_worker_task_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_worker_task.hpp> #include <mesosphere/kern_k_thread.hpp> namespace ams::kern { class KWorkerTaskManager { public: static constexpr s32 ExitWorkerPriority = 11; enum WorkerType { WorkerType_ExitThread, WorkerType_ExitProcess, WorkerType_Count, }; private: KWorkerTask *m_head_task; KWorkerTask *m_tail_task; KThread *m_waiting_thread; private: static void ThreadFunction(uintptr_t arg); void ThreadFunctionImpl(); KWorkerTask *GetTask(); void AddTask(KWorkerTask *task); public: constexpr KWorkerTaskManager() : m_head_task(), m_tail_task(), m_waiting_thread() { /* ... */ } NOINLINE void Initialize(s32 priority); static void AddTask(WorkerType type, KWorkerTask *task); }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_kernel.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_k_memory_layout.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_k_scheduler.hpp> #include <mesosphere/kern_k_interrupt_task_manager.hpp> #include <mesosphere/kern_select_interrupt_manager.hpp> #include <mesosphere/kern_select_hardware_timer.hpp> #include <mesosphere/kern_k_worker_task_manager.hpp> namespace ams::kern { class KThread; class KHardwareTimer; class KResourceLimit; class KInterruptManager; class KInterruptTaskManager; class KScheduler; class KMemoryManager; class KPageTableManager; class KMemoryBlockSlabManager; class KBlockInfoManager; class KUnsafeMemory; #if defined(ATMOSPHERE_ARCH_ARM64) namespace arch::arm64 { class KSupervisorPageTable; } using ams::kern::arch::arm64::KSupervisorPageTable; #else #error "Unknown architecture for KSupervisorPageTable forward declare" #endif class Kernel { public: enum class State : u8 { Invalid = 0, Initializing = 1, Initialized = 2, }; static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000; static constexpr size_t SystemMemoryBlockSlabHeapSize = 10000; static constexpr size_t BlockInfoSlabHeapSize = 4000; static constexpr size_t ReservedDynamicPageCount = 64; private: static State s_state; static KResourceLimit s_system_resource_limit; static KMemoryManager s_memory_manager; static KPageTableSlabHeap s_page_table_heap; static KMemoryBlockSlabHeap s_app_memory_block_heap; static KMemoryBlockSlabHeap s_sys_memory_block_heap; static KBlockInfoSlabHeap s_block_info_heap; static KPageTableManager s_app_page_table_manager; static KPageTableManager s_sys_page_table_manager; static KMemoryBlockSlabManager s_app_memory_block_manager; static KMemoryBlockSlabManager s_sys_memory_block_manager; static KBlockInfoManager s_app_block_info_manager; static KBlockInfoManager s_sys_block_info_manager; static KSystemResource s_app_system_resource; static KSystemResource s_sys_system_resource; static KSupervisorPageTable s_supervisor_page_table; static KUnsafeMemory s_unsafe_memory; static KWorkerTaskManager s_worker_task_managers[KWorkerTaskManager::WorkerType_Count]; static KInterruptManager s_interrupt_manager; static KScheduler s_schedulers[cpu::NumCores]; static KInterruptTaskManager s_interrupt_task_managers[cpu::NumCores]; static KHardwareTimer s_hardware_timers[cpu::NumCores]; public: static NOINLINE void InitializeCoreLocalRegion(s32 core_id); static NOINLINE void InitializeMainAndIdleThreads(s32 core_id); static NOINLINE void InitializeResourceManagers(KVirtualAddress address, size_t size); static NOINLINE void PrintLayout(); static ALWAYS_INLINE State GetState() { return s_state; } static ALWAYS_INLINE void SetState(State state) { s_state = state; } static KThread &GetMainThread(s32 core_id); static KThread &GetIdleThread(s32 core_id); static ALWAYS_INLINE KScheduler &GetScheduler() { return s_schedulers[GetCurrentCoreId()]; } static ALWAYS_INLINE KScheduler &GetScheduler(s32 core_id) { return s_schedulers[core_id]; } static ALWAYS_INLINE KInterruptTaskManager &GetInterruptTaskManager() { return s_interrupt_task_managers[GetCurrentCoreId()]; } static ALWAYS_INLINE KInterruptManager &GetInterruptManager() { return s_interrupt_manager; } static ALWAYS_INLINE KHardwareTimer &GetHardwareTimer() { return s_hardware_timers[GetCurrentCoreId()]; } static ALWAYS_INLINE KHardwareTimer &GetHardwareTimer(s32 core_id) { return s_hardware_timers[core_id]; } static ALWAYS_INLINE KResourceLimit &GetSystemResourceLimit() { return s_system_resource_limit; } static ALWAYS_INLINE KMemoryManager &GetMemoryManager() { return s_memory_manager; } static ALWAYS_INLINE KSystemResource &GetApplicationSystemResource() { return s_app_system_resource; } static ALWAYS_INLINE KSystemResource &GetSystemSystemResource() { return s_sys_system_resource; } static ALWAYS_INLINE KSupervisorPageTable &GetKernelPageTable() { return s_supervisor_page_table; } static ALWAYS_INLINE KUnsafeMemory &GetUnsafeMemory() { return s_unsafe_memory; } static ALWAYS_INLINE KWorkerTaskManager &GetWorkerTaskManager(KWorkerTaskManager::WorkerType type) { MESOSPHERE_ASSERT(type <= KWorkerTaskManager::WorkerType_Count); return s_worker_task_managers[type]; } }; ALWAYS_INLINE KScheduler &GetCurrentScheduler() { return Kernel::GetScheduler(); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_main.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> namespace ams::kern { NORETURN void HorizonKernelMain(s32 core_id); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_panic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_debug_log.hpp> namespace ams::kern { NORETURN NOINLINE void Panic(const char *file, int line, const char *format, ...) __attribute__((format(printf, 3, 4))); NORETURN NOINLINE void Panic(); } namespace ams::diag { NORETURN ALWAYS_INLINE void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { #if defined(MESOSPHERE_ENABLE_DEBUG_PRINT) ::ams::kern::Panic(file, line, "ams::diag::OnAssertionFailure: %d %s:%s", (type == AssertionType_Audit), func, expr); #else ::ams::kern::Panic(); AMS_UNUSED(type, expr, func, file, line); #endif } } #define MESOSPHERE_UNUSED(...) AMS_UNUSED(__VA_ARGS__) #ifdef MESOSPHERE_ENABLE_DEBUG_PRINT #define MESOSPHERE_PANIC(...) do { ::ams::kern::Panic(__FILE__, __LINE__, ## __VA_ARGS__); } while(0) #else #define MESOSPHERE_PANIC(...) do { MESOSPHERE_UNUSED(__VA_ARGS__); ::ams::kern::Panic(); } while(0) #endif #ifdef MESOSPHERE_ENABLE_ASSERTIONS #define MESOSPHERE_ASSERT_IMPL(expr, ...) \ ({ \ const bool __tmp_meso_assert_val = (expr); \ if (AMS_UNLIKELY(!__tmp_meso_assert_val)) { \ MESOSPHERE_PANIC(__VA_ARGS__); \ } \ }) #elif defined(MESOSPHERE_PRESERVE_ASSERTION_EXPRESSIONS) #define MESOSPHERE_ASSERT_IMPL(expr, ...) do { static_cast<void>(expr); } while (0) #else #define MESOSPHERE_ASSERT_IMPL(expr, ...) static_cast<void>(0) #endif #define MESOSPHERE_ASSERT(expr) MESOSPHERE_ASSERT_IMPL(expr, "Assertion failed: %s\n", #expr) #define MESOSPHERE_R_ASSERT(expr) MESOSPHERE_ASSERT_IMPL(R_SUCCEEDED(expr), "Result assertion failed: %s\n", #expr) #define MESOSPHERE_UNREACHABLE_DEFAULT_CASE() default: MESOSPHERE_PANIC("Unreachable default case entered") #ifdef MESOSPHERE_ENABLE_THIS_ASSERT #define MESOSPHERE_ASSERT_THIS() MESOSPHERE_ASSERT(this != nullptr) #else #define MESOSPHERE_ASSERT_THIS() #endif #ifdef MESOSPHERE_BUILD_FOR_AUDITING #define MESOSPHERE_AUDIT(expr) MESOSPHERE_ASSERT(expr) #elif defined(MESOSPHERE_PRESERVE_AUDIT_EXPRESSIONS) #define MESOSPHERE_AUDIT(expr) do { static_cast<void>(expr); } while (0) #else #define MESOSPHERE_AUDIT(expr) static_cast<void>(0) #endif #define MESOSPHERE_TODO(arg) ({ constexpr const char *__mesosphere_todo = arg; static_cast<void>(__mesosphere_todo); MESOSPHERE_PANIC("TODO (%s): %s\n", __PRETTY_FUNCTION__, __mesosphere_todo); }) #define MESOSPHERE_UNIMPLEMENTED() MESOSPHERE_PANIC("%s: Unimplemented\n", __PRETTY_FUNCTION__) #define MESOSPHERE_ABORT() MESOSPHERE_PANIC("Abort()\n"); #define MESOSPHERE_INIT_ABORT() AMS_INFINITE_LOOP() #define MESOSPHERE_ABORT_UNLESS(expr) \ ({ \ const bool _tmp_meso_assert_val = (expr); \ if (AMS_UNLIKELY(!_tmp_meso_assert_val)) { \ MESOSPHERE_PANIC("Abort(): %s", #expr); \ } \ }) #define MESOSPHERE_INIT_ABORT_UNLESS(expr) \ ({ \ const bool __tmp_meso_assert_val = (expr); \ if (AMS_UNLIKELY(!__tmp_meso_assert_val)) { \ MESOSPHERE_INIT_ABORT(); \ } \ }) #define MESOSPHERE_R_ABORT_UNLESS(expr) \ ({ \ const ::ams::Result _tmp_meso_r_abort_res = static_cast<::ams::Result>((expr)); \ if (AMS_UNLIKELY((R_FAILED(_tmp_meso_r_abort_res)))) { \ MESOSPHERE_PANIC("Result Abort(): %s 2%03d-%04d\n", #expr, _tmp_meso_r_abort_res.GetModule(), _tmp_meso_r_abort_res.GetDescription()); \ } \ }) ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_assembly_macros.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_assembly_macros.h> #else #error "Unknown architecture for CPU" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_assembly_offsets.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_assembly_offsets.h> #else #error "Unknown architecture for CPU" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_cpu.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_cpu.hpp> namespace ams::kern::cpu { using namespace ams::kern::arch::arm64::cpu; } #else #error "Unknown architecture for CPU" #endif #ifdef ATMOSPHERE_BOARD_NINTENDO_NX #include <mesosphere/board/nintendo/nx/kern_cpu_map.hpp> namespace ams::kern::cpu { using namespace ams::kern::board::nintendo::nx::impl::cpu; } #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) #include <mesosphere/board/qemu/virt/kern_cpu_map.hpp> namespace ams::kern::cpu { using namespace ams::kern::board::qemu::virt::impl::cpu; } #else #error "Unknown board for CPU Map" #endif namespace ams::kern { namespace cpu { static constexpr inline size_t NumVirtualCores = BITSIZEOF(u64); static constexpr inline u64 VirtualCoreMask = [] { u64 mask = 0; for (size_t i = 0; i < NumVirtualCores; ++i) { mask |= (UINT64_C(1) << i); } return mask; }(); static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) { u64 p_core_mask = 0; while (v_core_mask != 0) { const u64 next = util::CountTrailingZeros(v_core_mask); v_core_mask &= ~(static_cast<u64>(1) << next); p_core_mask |= (static_cast<u64>(1) << cpu::VirtualToPhysicalCoreMap[next]); } return p_core_mask; } } static_assert(cpu::NumCores <= cpu::NumVirtualCores); static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == cpu::NumVirtualCores); } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_debug.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_debug.hpp> namespace ams::kern { using ams::kern::arch::arm64::KDebug; } #else #error "Unknown architecture for KDebug" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_device_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #ifdef ATMOSPHERE_BOARD_NINTENDO_NX #include <mesosphere/board/nintendo/nx/kern_k_device_page_table.hpp> namespace ams::kern { using ams::kern::board::nintendo::nx::KDevicePageTable; } #else #include <mesosphere/board/generic/kern_k_device_page_table.hpp> namespace ams::kern { using ams::kern::board::generic::KDevicePageTable; } #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_hardware_timer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_hardware_timer.hpp> namespace ams::kern { using ams::kern::arch::arm64::KHardwareTimer; } #else #error "Unknown architecture for KHardwareTimer" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_interrupt_controller.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_interrupt_name.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_interrupt_controller.hpp> namespace ams::kern { using ams::kern::arch::arm64::KInterruptController; } #elif defined(ATMOSPHERE_ARCH_ARM) #include <mesosphere/arch/arm/kern_k_interrupt_controller.hpp> namespace ams::kern { using ams::kern::arch::arm::KInterruptController; } #else #error "Unknown architecture for KInterruptController" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_interrupt_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_select_interrupt_name.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_interrupt_manager.hpp> namespace ams::kern { using ams::kern::arch::arm64::KInterruptManager; } #else #error "Unknown architecture for KInterruptManager" #endif namespace ams::kern { /* Enable or disable interrupts for the lifetime of an object. */ class KScopedInterruptDisable { NON_COPYABLE(KScopedInterruptDisable); NON_MOVEABLE(KScopedInterruptDisable); private: u32 m_prev_intr_state; public: ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndDisableInterrupts()) { /* ... */ } ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } }; class KScopedInterruptEnable { NON_COPYABLE(KScopedInterruptEnable); NON_MOVEABLE(KScopedInterruptEnable); private: u32 m_prev_intr_state; public: ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndEnableInterrupts()) { /* ... */ } ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_interrupt_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_interrupt_name.hpp> namespace ams::kern { using namespace ams::kern::arch::arm64::interrupt_name; } #else #error "Unknown architecture for KInterruptName" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_page_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_page_table.hpp> #include <mesosphere/arch/arm64/kern_k_supervisor_page_table.hpp> #include <mesosphere/arch/arm64/kern_k_process_page_table.hpp> namespace ams::kern { using ams::kern::arch::arm64::KPageTable; using ams::kern::arch::arm64::KSupervisorPageTable; using ams::kern::arch::arm64::KProcessPageTable; } #else #error "Unknown architecture for KPageTable" #endif namespace ams::kern { /* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */ /* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */ /* class, and this avoids unnecessary virtual function calls. */ static_assert(std::derived_from<KPageTable, KPageTableBase>); ALWAYS_INLINE Result KPageTableBase::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) { R_RETURN(static_cast<KPageTable *>(this)->OperateImpl(page_list, virt_addr, num_pages, phys_addr, is_pa_valid, properties, operation, reuse_ll)); } ALWAYS_INLINE Result KPageTableBase::Operate(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) { R_RETURN(static_cast<KPageTable *>(this)->OperateImpl(page_list, virt_addr, num_pages, page_group, properties, operation, reuse_ll)); } ALWAYS_INLINE void KPageTableBase::FinalizeUpdate(PageLinkedList *page_list) { static_cast<KPageTable *>(this)->FinalizeUpdateImpl(page_list); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_page_table_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_k_page_table_impl.hpp> namespace ams::kern { using ams::kern::arch::arm64::KPageTableImpl; } #else #error "Unknown architecture for KPageTableImpl" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_system_control.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_system_control_base.hpp> #ifdef ATMOSPHERE_BOARD_NINTENDO_NX #include <mesosphere/board/nintendo/nx/kern_k_system_control.hpp> namespace ams::kern { using ams::kern::board::nintendo::nx::KSystemControl; } #elif defined(ATMOSPHERE_BOARD_QEMU_VIRT) #include <mesosphere/board/qemu/virt/kern_k_system_control.hpp> namespace ams::kern { using ams::kern::board::qemu::virt::KSystemControl; } #else #error "Unknown board for KSystemControl" #endif namespace ams::kern { ALWAYS_INLINE u32 KSystemControlBase::ReadRegisterPrivileged(ams::svc::PhysicalAddress address) { u32 v; KSystemControl::ReadWriteRegisterPrivileged(std::addressof(v), address, 0x00000000u, 0); return v; } ALWAYS_INLINE void KSystemControlBase::WriteRegisterPrivileged(ams::svc::PhysicalAddress address, u32 value) { u32 v; KSystemControl::ReadWriteRegisterPrivileged(std::addressof(v), address, 0xFFFFFFFFu, value); } } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_select_userspace_memory_access.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #ifdef ATMOSPHERE_ARCH_ARM64 #include <mesosphere/arch/arm64/kern_userspace_memory_access.hpp> namespace ams::kern { using ams::kern::arch::arm64::UserspaceAccess; } #else #error "Unknown architecture for CPU" #endif ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_slab_helpers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_k_slab_heap.hpp> #include <mesosphere/kern_k_auto_object_container.hpp> #include <mesosphere/kern_k_unused_slab_memory.hpp> namespace ams::kern { template<class Derived, bool SupportDynamicExpansion = false> class KSlabAllocated { private: static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap; public: constexpr KSlabAllocated() = default; size_t GetSlabIndex() const { return s_slab_heap.GetIndex(static_cast<const Derived *>(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); } static Derived *Allocate() { return s_slab_heap.Allocate(); } static void Free(Derived *obj) { s_slab_heap.Free(obj); } template<bool Enable = SupportDynamicExpansion, typename = typename std::enable_if<Enable>::type> static Derived *AllocateFromUnusedSlabMemory() { static_assert(Enable == SupportDynamicExpansion); Derived * const obj = GetPointer<Derived>(AllocateUnusedSlabMemory(sizeof(Derived), alignof(Derived))); if (AMS_LIKELY(obj != nullptr)) { std::construct_at(obj); } return obj; } static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); } static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; template<typename Derived, typename Base, bool SupportDynamicExpansion> requires std::derived_from<Base, KAutoObject> class KAutoObjectWithSlabHeapBase : public Base { private: template<typename, typename, bool> friend class KAutoObjectWithSlabHeap; template<typename, typename, bool> friend class KAutoObjectWithSlabHeapAndContainer; private: static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap; private: static ALWAYS_INLINE Derived *Allocate() { return s_slab_heap.Allocate(); } static ALWAYS_INLINE void Free(Derived *obj) { s_slab_heap.Free(obj); } private: static ALWAYS_INLINE bool IsInitialized(const Derived *obj) { if constexpr (requires { { obj->IsInitialized() } -> std::same_as<bool>; }) { return obj->IsInitialized(); } else { return true; } } static ALWAYS_INLINE uintptr_t GetPostDestroyArgument(const Derived *obj) { if constexpr (requires { { obj->GetPostDestroyArgument() } -> std::same_as<uintptr_t>; }) { return obj->GetPostDestroyArgument(); } else { return 0; } } public: constexpr explicit KAutoObjectWithSlabHeapBase(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeapBase() { /* ... */ } /* NOTE: IsInitialized() and GetPostDestroyArgument() are virtual functions declared in this class, */ /* in Nintendo's kernel. We fully devirtualize them, as Destroy() is the only user of them. */ /* We also devirtualize KAutoObject::Finalize(), which is only used by this function in Nintendo's kernel. */ virtual void Destroy() override final { Derived * const derived = static_cast<Derived *>(this); if (KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::IsInitialized(derived)) { Derived::PreFinalize(derived); const uintptr_t arg = KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::GetPostDestroyArgument(derived); derived->Finalize(); KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::Free(derived); Derived::PostDestroy(arg); } else { KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::Free(derived); } } size_t GetSlabIndex() const { return s_slab_heap.GetObjectIndex(static_cast<const Derived *>(this)); } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { s_slab_heap.Initialize(memory, memory_size); } static Derived *Create() { Derived *obj = Allocate(); if (AMS_LIKELY(obj != nullptr)) { KAutoObject::Create<Derived>(obj); } return obj; } template<bool Enable = SupportDynamicExpansion, typename = typename std::enable_if<Enable>::type> static Derived *CreateFromUnusedSlabMemory() { static_assert(Enable == SupportDynamicExpansion); Derived * const obj = GetPointer<Derived>(AllocateUnusedSlabMemory(sizeof(Derived), alignof(Derived))); if (AMS_LIKELY(obj != nullptr)) { std::construct_at(obj); KAutoObject::Create<Derived>(obj); } return obj; } static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); } static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); } static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); } static uintptr_t GetSlabHeapAddress() { return s_slab_heap.GetSlabHeapAddress(); } static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); } }; template<typename Derived, typename Base, bool SupportDynamicExpansion = false> class KAutoObjectWithSlabHeap : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> { public: constexpr explicit KAutoObjectWithSlabHeap(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeap() { /* ... */ } static ALWAYS_INLINE void PreFinalize(Derived *) { /* ... */ } }; template<typename Derived, typename Base, bool SupportDynamicExpansion = false> class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> { static_assert(std::derived_from<Base, KAutoObjectWithList>); private: static constinit inline KAutoObjectWithListContainer<Derived> s_container; public: class ListAccessor : public KAutoObjectWithListContainer<Derived>::ListAccessor { public: ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer<Derived>::ListAccessor(s_container) { /* ... */ } ALWAYS_INLINE ~ListAccessor() { /* ... */ } }; public: constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ } explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ } public: static void InitializeSlabHeap(void *memory, size_t memory_size) { KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::InitializeSlabHeap(memory, memory_size); s_container.Initialize(); } static void Register(Derived *obj) { return s_container.Register(obj); } static ALWAYS_INLINE void PreFinalize(Derived *obj) { s_container.Unregister(obj); } }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/kern_svc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere/svc/kern_svc_results.hpp> #include <mesosphere/svc/kern_svc_k_user_pointer.hpp> #include <mesosphere/svc/kern_svc_prototypes.hpp> ================================================ FILE: libraries/libmesosphere/include/mesosphere/svc/kern_svc_k_user_pointer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/svc/kern_svc_results.hpp> #include <mesosphere/kern_select_userspace_memory_access.hpp> namespace ams::kern::svc { namespace impl { template<typename T> concept Pointer = std::is_pointer<T>::value; template<typename T> concept NonConstPointer = Pointer<T> && !std::is_const<typename std::remove_pointer<T>::type>::value; template<typename T> concept ConstPointer = Pointer<T> && std::is_const<typename std::remove_pointer<T>::type>::value; template<typename T, size_t N> concept AlignedNPointer = Pointer<T> && alignof(typename std::remove_pointer<T>::type) >= N && util::IsAligned(sizeof(typename std::remove_pointer<T>::type), N); template<typename T> concept Aligned8Pointer = AlignedNPointer<T, sizeof(u8)>; template<typename T> concept Aligned16Pointer = AlignedNPointer<T, sizeof(u16)> && Aligned8Pointer<T>; template<typename T> concept Aligned32Pointer = AlignedNPointer<T, sizeof(u32)> && Aligned16Pointer<T>; template<typename T> concept Aligned64Pointer = AlignedNPointer<T, sizeof(u64)> && Aligned32Pointer<T>; template<typename _T> class KUserPointerImplTraits; template<typename _T> requires Aligned8Pointer<_T> class KUserPointerImplTraits<_T> { public: using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type; public: static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryFromUser(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryToUser(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } }; template<typename _T> requires Aligned32Pointer<_T> class KUserPointerImplTraits<_T> { public: using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type; public: static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } }; template<typename _T> requires Aligned64Pointer<_T> class KUserPointerImplTraits<_T> { public: using T = typename std::remove_const<typename std::remove_pointer<_T>::type>::type; public: static ALWAYS_INLINE Result CopyFromUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } static ALWAYS_INLINE Result CopyToUserspace(void *dst, const void *src, size_t size) { R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned64Bit(dst, src, size), svc::ResultInvalidPointer()); R_SUCCEED(); } }; template<typename _T> class KUserPointerImpl; template<typename _T> requires Aligned8Pointer<_T> class KUserPointerImpl<_T> : impl::KUserPointerTag { private: using Traits = KUserPointerImplTraits<_T>; protected: using CT = typename std::remove_pointer<_T>::type; using T = typename std::remove_const<CT>::type; private: CT *m_ptr; private: ALWAYS_INLINE Result CopyToImpl(void *p, size_t size) const { R_RETURN(Traits::CopyFromUserspace(p, m_ptr, size)); } ALWAYS_INLINE Result CopyFromImpl(const void *p, size_t size) const { R_RETURN(Traits::CopyToUserspace(m_ptr, p, size)); } protected: ALWAYS_INLINE Result CopyTo(T *p) const { R_RETURN(this->CopyToImpl(p, sizeof(*p))); } ALWAYS_INLINE Result CopyFrom(const T *p) const { R_RETURN(this->CopyFromImpl(p, sizeof(*p))); } ALWAYS_INLINE Result CopyArrayElementTo(T *p, size_t index) const { R_RETURN(Traits::CopyFromUserspace(p, m_ptr + index, sizeof(*p))); } ALWAYS_INLINE Result CopyArrayElementFrom(const T *p, size_t index) const { R_RETURN(Traits::CopyToUserspace(m_ptr + index, p, sizeof(*p))); } ALWAYS_INLINE Result CopyArrayTo(T *arr, size_t count) const { R_RETURN(this->CopyToImpl(arr, sizeof(*arr) * count)); } ALWAYS_INLINE Result CopyArrayFrom(const T *arr, size_t count) const { R_RETURN(this->CopyFromImpl(arr, sizeof(*arr) * count)); } constexpr ALWAYS_INLINE bool IsNull() const { return m_ptr == nullptr; } constexpr ALWAYS_INLINE CT *GetUnsafePointer() const { return m_ptr; } }; template<> class KUserPointerImpl<const char *> : impl::KUserPointerTag { private: using Traits = KUserPointerImplTraits<const char *>; protected: using CT = const char; using T = char; private: const char *m_ptr; protected: ALWAYS_INLINE Result CopyStringTo(char *dst, size_t size) const { static_assert(sizeof(char) == 1); R_UNLESS(UserspaceAccess::CopyStringFromUser(dst, m_ptr, size) > 0, svc::ResultInvalidPointer()); R_SUCCEED(); } ALWAYS_INLINE Result CopyArrayElementTo(char *dst, size_t index) const { R_RETURN(Traits::CopyFromUserspace(dst, m_ptr + index, sizeof(*dst))); } constexpr ALWAYS_INLINE bool IsNull() const { return m_ptr == nullptr; } constexpr ALWAYS_INLINE const char *GetUnsafePointer() const { return m_ptr; } }; } template<typename T> struct KUserPointer; template<typename T> requires impl::ConstPointer<T> struct KUserPointer<T> : public impl::KUserPointerImpl<T> { public: static constexpr bool IsInput = true; public: using impl::KUserPointerImpl<T>::CopyTo; using impl::KUserPointerImpl<T>::CopyArrayElementTo; using impl::KUserPointerImpl<T>::CopyArrayTo; using impl::KUserPointerImpl<T>::IsNull; using impl::KUserPointerImpl<T>::GetUnsafePointer; }; template<typename T> requires impl::NonConstPointer<T> struct KUserPointer<T> : public impl::KUserPointerImpl<T> { public: static constexpr bool IsInput = false; public: using impl::KUserPointerImpl<T>::CopyFrom; using impl::KUserPointerImpl<T>::CopyArrayElementFrom; using impl::KUserPointerImpl<T>::CopyArrayFrom; using impl::KUserPointerImpl<T>::IsNull; using impl::KUserPointerImpl<T>::GetUnsafePointer; }; template<> struct KUserPointer<const char *> : public impl::KUserPointerImpl<const char *> { public: static constexpr bool IsInput = true; public: using impl::KUserPointerImpl<const char *>::CopyStringTo; using impl::KUserPointerImpl<const char *>::CopyArrayElementTo; using impl::KUserPointerImpl<const char *>::IsNull; using impl::KUserPointerImpl<const char *>::GetUnsafePointer; }; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/svc/kern_svc_prototypes.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/svc/kern_svc_k_user_pointer.hpp> #include <mesosphere/svc/kern_svc_results.hpp> namespace ams::kern::svc { static constexpr size_t NumSupervisorCalls = AMS_KERN_NUM_SUPERVISOR_CALLS; #define AMS_KERN_SVC_DECLARE_ENUM_ID(ID, RETURN_TYPE, NAME, ...) \ SvcId_##NAME = ID, enum SvcId { AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_DECLARE_ENUM_ID, __invalid) SvcId_Count = NumSupervisorCalls, }; #undef AMS_KERN_SVC_DECLARE_ENUM_ID #define AMS_KERN_SVC_DECLARE_PROTOTYPE_64(ID, RETURN_TYPE, NAME, ...) \ NOINLINE RETURN_TYPE NAME##64(__VA_ARGS__); #define AMS_KERN_SVC_DECLARE_PROTOTYPE_64_FROM_32(ID, RETURN_TYPE, NAME, ...) \ NOINLINE RETURN_TYPE NAME##64From32(__VA_ARGS__); AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_DECLARE_PROTOTYPE_64, lp64) AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_DECLARE_PROTOTYPE_64_FROM_32, ilp32) /* TODO: Support _32 ABI */ #undef AMS_KERN_SVC_DECLARE_PROTOTYPE_64 #undef AMS_KERN_SVC_DECLARE_PROTOTYPE_64_FROM_32 struct SvcAccessFlagSetTag{}; using SvcAccessFlagSet = util::BitFlagSet<NumSupervisorCalls, SvcAccessFlagSetTag>; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/svc/kern_svc_results.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::kern::svc { /* 7 */ using ::ams::svc::ResultOutOfSessions; /* 14 */ using ::ams::svc::ResultInvalidArgument; /* 33 */ using ::ams::svc::ResultNotImplemented; /* 54 */ using ::ams::svc::ResultStopProcessingException; /* 57 */ using ::ams::svc::ResultNoSynchronizationObject; /* 59 */ using ::ams::svc::ResultTerminationRequested; /* 70 */ using ::ams::svc::ResultNoEvent; /* 101 */ using ::ams::svc::ResultInvalidSize; /* 102 */ using ::ams::svc::ResultInvalidAddress; /* 103 */ using ::ams::svc::ResultOutOfResource; /* 104 */ using ::ams::svc::ResultOutOfMemory; /* 105 */ using ::ams::svc::ResultOutOfHandles; /* 106 */ using ::ams::svc::ResultInvalidCurrentMemory; /* 108 */ using ::ams::svc::ResultInvalidNewMemoryPermission; /* 110 */ using ::ams::svc::ResultInvalidMemoryRegion; /* 112 */ using ::ams::svc::ResultInvalidPriority; /* 113 */ using ::ams::svc::ResultInvalidCoreId; /* 114 */ using ::ams::svc::ResultInvalidHandle; /* 115 */ using ::ams::svc::ResultInvalidPointer; /* 116 */ using ::ams::svc::ResultInvalidCombination; /* 117 */ using ::ams::svc::ResultTimedOut; /* 118 */ using ::ams::svc::ResultCancelled; /* 119 */ using ::ams::svc::ResultOutOfRange; /* 120 */ using ::ams::svc::ResultInvalidEnumValue; /* 121 */ using ::ams::svc::ResultNotFound; /* 122 */ using ::ams::svc::ResultBusy; /* 123 */ using ::ams::svc::ResultSessionClosed; /* 124 */ using ::ams::svc::ResultNotHandled; /* 125 */ using ::ams::svc::ResultInvalidState; /* 126 */ using ::ams::svc::ResultReservedUsed; /* 127 */ using ::ams::svc::ResultNotSupported; /* 128 */ using ::ams::svc::ResultDebug; /* 129 */ using ::ams::svc::ResultNoThread; /* 130 */ using ::ams::svc::ResultUnknownThread; /* 131 */ using ::ams::svc::ResultPortClosed; /* 132 */ using ::ams::svc::ResultLimitReached; /* 133 */ using ::ams::svc::ResultInvalidMemoryPool; /* 258 */ using ::ams::svc::ResultReceiveListBroken; /* 259 */ using ::ams::svc::ResultOutOfAddressSpace; /* 260 */ using ::ams::svc::ResultMessageTooLarge; /* 517 */ using ::ams::svc::ResultInvalidProcessId; /* 518 */ using ::ams::svc::ResultInvalidThreadId; /* 519 */ using ::ams::svc::ResultInvalidId; /* 520 */ using ::ams::svc::ResultProcessTerminated; } ================================================ FILE: libraries/libmesosphere/include/mesosphere/svc/kern_svc_tables.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <mesosphere/svc/kern_svc_prototypes.hpp> namespace ams::kern::svc { using SvcTableEntry = void (*)(); /* TODO: 32-bit ABI */ extern const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64From32; extern const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64; } ================================================ FILE: libraries/libmesosphere/include/mesosphere.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /* All kernel code should have access to libvapours. */ #include <vapours.hpp> /* First, pull in core macros (panic, etc). */ #include <mesosphere/kern_common.hpp> #include <mesosphere/kern_panic.hpp> /* Primitive types. */ #include <mesosphere/kern_k_typed_address.hpp> #include <mesosphere/kern_initial_process.hpp> #include <mesosphere/kern_k_exception_context.hpp> /* Tracing functionality. */ #include <mesosphere/kern_k_trace.hpp> /* Core pre-initialization includes. */ #include <mesosphere/kern_select_cpu.hpp> #include <mesosphere/kern_select_system_control.hpp> #include <mesosphere/kern_k_target_system.hpp> /* Initialization headers. */ #include <mesosphere/init/kern_init_elf.hpp> #include <mesosphere/init/kern_init_layout.hpp> #include <mesosphere/init/kern_init_slab_setup.hpp> #include <mesosphere/init/kern_init_page_table_select.hpp> #include <mesosphere/init/kern_init_arguments_select.hpp> #include <mesosphere/kern_k_memory_layout.hpp> /* Core functionality. */ #include <mesosphere/kern_select_interrupt_manager.hpp> #include <mesosphere/kern_k_spin_lock.hpp> #include <mesosphere/kern_k_memory_manager.hpp> #include <mesosphere/kern_k_interrupt_task_manager.hpp> #include <mesosphere/kern_k_slab_heap.hpp> #include <mesosphere/kern_k_light_lock.hpp> #include <mesosphere/kern_k_dpc_manager.hpp> #include <mesosphere/kern_kernel.hpp> #include <mesosphere/kern_k_page_table_manager.hpp> #include <mesosphere/kern_select_page_table.hpp> #include <mesosphere/kern_k_dump_object.hpp> /* Miscellaneous objects. */ #include <mesosphere/kern_k_shared_memory_info.hpp> #include <mesosphere/kern_k_event_info.hpp> /* Auto Objects. */ #include <mesosphere/kern_k_auto_object.hpp> #include <mesosphere/kern_k_synchronization_object.hpp> #include <mesosphere/kern_k_readable_event.hpp> #include <mesosphere/kern_k_handle_table.hpp> #include <mesosphere/kern_k_event.hpp> #include <mesosphere/kern_k_interrupt_event.hpp> #include <mesosphere/kern_k_light_session.hpp> #include <mesosphere/kern_k_session.hpp> #include <mesosphere/kern_k_session_request.hpp> #include <mesosphere/kern_k_port.hpp> #include <mesosphere/kern_k_shared_memory.hpp> #include <mesosphere/kern_k_transfer_memory.hpp> #include <mesosphere/kern_k_code_memory.hpp> #include <mesosphere/kern_k_device_address_space.hpp> #include <mesosphere/kern_select_debug.hpp> #include <mesosphere/kern_k_process.hpp> #include <mesosphere/kern_k_resource_limit.hpp> #include <mesosphere/kern_k_io_pool.hpp> /* More Miscellaneous objects. */ #include <mesosphere/kern_k_object_name.hpp> #include <mesosphere/kern_k_unsafe_memory.hpp> #include <mesosphere/kern_k_scoped_resource_reservation.hpp> /* Supervisor Calls. */ #include <mesosphere/kern_svc.hpp> /* Main functionality. */ #include <mesosphere/kern_main.hpp> /* Deferred includes. */ #include <mesosphere/kern_k_auto_object_impls.hpp> #include <mesosphere/kern_k_scheduler_impls.hpp> ================================================ FILE: libraries/libmesosphere/libmesosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../config/common.mk #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- PRECOMPILED_HEADERS := include/mesosphere.hpp #PRECOMPILED_HEADERS := ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O3 endif DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) SOURCES += $(foreach v,$(call ALL_SOURCE_DIRS,../libvapours/source),$(if $(findstring ../libvapours/source/sdmmc,$v),,$v)) LIBS := #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. #--------------------------------------------------------------------------------- .PHONY: clean all all: $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) $(GCH_DIRS) $(CPPFILES) $(CFILES) $(SFILES) @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) #--------------------------------------------------------------------------------- clean: @echo clean $(ATMOSPHERE_BUILD_NAME) ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) @rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) @for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- else GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr))))) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT) : $(OFILES) $(filter-out kern_svc_tables.o, $(OFILES)) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) kern_libc_generic.o: CFLAGS += -fno-builtin #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: libraries/libmesosphere/source/arch/arm/kern_generic_interrupt_controller.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm { void KInterruptController::SetupInterruptLines(s32 core_id) const { const size_t ITLines = (core_id == 0) ? 32 * ((m_gicd->typer & 0x1F) + 1) : NumLocalInterrupts; for (size_t i = 0; i < ITLines / 32; i++) { m_gicd->icenabler[i] = 0xFFFFFFFF; m_gicd->icpendr[i] = 0xFFFFFFFF; m_gicd->icactiver[i] = 0xFFFFFFFF; m_gicd->igroupr[i] = 0; } for (size_t i = 0; i < ITLines; i++) { m_gicd->ipriorityr.bytes[i] = 0xFF; m_gicd->itargetsr.bytes[i] = 0x00; } for (size_t i = 0; i < ITLines / 16; i++) { m_gicd->icfgr[i] = 0x00000000; } } void KInterruptController::Initialize(s32 core_id) { /* Setup pointers to ARM mmio. */ m_gicd = GetPointer<volatile GicDistributor >(KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_InterruptDistributor)); m_gicc = GetPointer<volatile GicCpuInterface>(KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_InterruptCpuInterface)); /* Clear CTLRs. */ m_gicc->ctlr = 0; if (core_id == 0) { m_gicd->ctlr = 0; } m_gicc->pmr = 0; m_gicc->bpr = 7; /* Setup all interrupt lines. */ SetupInterruptLines(core_id); /* Set CTLRs. */ if (core_id == 0) { m_gicd->ctlr = 1; } m_gicc->ctlr = 1; /* Set the mask for this core. */ SetGicMask(core_id); /* Set the priority level. */ SetPriorityLevel(PriorityLevel_Low); } void KInterruptController::Finalize(s32 core_id) { /* Clear CTLRs. */ if (core_id == 0) { m_gicd->ctlr = 0; } m_gicc->ctlr = 0; /* Set the priority level. */ SetPriorityLevel(PriorityLevel_High); /* Setup all interrupt lines. */ SetupInterruptLines(core_id); /* Clear pointers, if needed. */ if (core_id == 0) { m_gicd = nullptr; m_gicc = nullptr; } } void KInterruptController::SaveCoreLocal(LocalState *state) const { /* Save isenabler. */ for (size_t i = 0; i < util::size(state->isenabler); ++i) { constexpr size_t Offset = 0; state->isenabler[i] = m_gicd->isenabler[i + Offset]; m_gicd->isenabler[i + Offset] = 0xFFFFFFFF; } /* Save ipriorityr. */ for (size_t i = 0; i < util::size(state->ipriorityr); ++i) { constexpr size_t Offset = 0; state->ipriorityr[i] = m_gicd->ipriorityr.words[i + Offset]; m_gicd->ipriorityr.words[i + Offset] = 0xFFFFFFFF; } /* Save itargetsr. */ for (size_t i = 0; i < util::size(state->itargetsr); ++i) { constexpr size_t Offset = 0; state->itargetsr[i] = m_gicd->itargetsr.words[i + Offset]; } /* Save icfgr. */ for (size_t i = 0; i < util::size(state->icfgr); ++i) { constexpr size_t Offset = 0; state->icfgr[i] = m_gicd->icfgr[i + Offset]; } /* Save spendsgir. */ for (size_t i = 0; i < util::size(state->spendsgir); ++i) { state->spendsgir[i] = m_gicd->spendsgir[i]; } } void KInterruptController::SaveGlobal(GlobalState *state) const { /* Save isenabler. */ for (size_t i = 0; i < util::size(state->isenabler); ++i) { constexpr size_t Offset = util::size(LocalState{}.isenabler); state->isenabler[i] = m_gicd->isenabler[i + Offset]; m_gicd->isenabler[i + Offset] = 0xFFFFFFFF; } /* Save ipriorityr. */ for (size_t i = 0; i < util::size(state->ipriorityr); ++i) { constexpr size_t Offset = util::size(LocalState{}.ipriorityr); state->ipriorityr[i] = m_gicd->ipriorityr.words[i + Offset]; m_gicd->ipriorityr.words[i + Offset] = 0xFFFFFFFF; } /* Save itargetsr. */ for (size_t i = 0; i < util::size(state->itargetsr); ++i) { constexpr size_t Offset = util::size(LocalState{}.itargetsr); state->itargetsr[i] = m_gicd->itargetsr.words[i + Offset]; } /* Save icfgr. */ for (size_t i = 0; i < util::size(state->icfgr); ++i) { constexpr size_t Offset = util::size(LocalState{}.icfgr); state->icfgr[i] = m_gicd->icfgr[i + Offset]; } } void KInterruptController::RestoreCoreLocal(const LocalState *state) const { /* Restore ipriorityr. */ for (size_t i = 0; i < util::size(state->ipriorityr); ++i) { constexpr size_t Offset = 0; m_gicd->ipriorityr.words[i + Offset] = state->ipriorityr[i]; } /* Restore itargetsr. */ for (size_t i = 0; i < util::size(state->itargetsr); ++i) { constexpr size_t Offset = 0; m_gicd->itargetsr.words[i + Offset] = state->itargetsr[i]; } /* Restore icfgr. */ for (size_t i = 0; i < util::size(state->icfgr); ++i) { constexpr size_t Offset = 0; m_gicd->icfgr[i + Offset] = state->icfgr[i]; } /* Restore isenabler. */ for (size_t i = 0; i < util::size(state->isenabler); ++i) { constexpr size_t Offset = 0; m_gicd->icenabler[i + Offset] = 0xFFFFFFFF; m_gicd->isenabler[i + Offset] = state->isenabler[i]; } /* Restore spendsgir. */ for (size_t i = 0; i < util::size(state->spendsgir); ++i) { m_gicd->spendsgir[i] = state->spendsgir[i]; } } void KInterruptController::RestoreGlobal(const GlobalState *state) const { /* Restore ipriorityr. */ for (size_t i = 0; i < util::size(state->ipriorityr); ++i) { constexpr size_t Offset = util::size(LocalState{}.ipriorityr); m_gicd->ipriorityr.words[i + Offset] = state->ipriorityr[i]; } /* Restore itargetsr. */ for (size_t i = 0; i < util::size(state->itargetsr); ++i) { constexpr size_t Offset = util::size(LocalState{}.itargetsr); m_gicd->itargetsr.words[i + Offset] = state->itargetsr[i]; } /* Restore icfgr. */ for (size_t i = 0; i < util::size(state->icfgr); ++i) { constexpr size_t Offset = util::size(LocalState{}.icfgr); m_gicd->icfgr[i + Offset] = state->icfgr[i]; } /* Restore isenabler. */ for (size_t i = 0; i < util::size(state->isenabler); ++i) { constexpr size_t Offset = util::size(LocalState{}.isenabler); m_gicd->icenabler[i + Offset] = 0xFFFFFFFF; m_gicd->isenabler[i + Offset] = state->isenabler[i]; } } } ================================================ FILE: libraries/libmesosphere/source/arch/arm/kern_k_interrupt_controller.board.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> /* Include the common implementation. */ #include "../arm/kern_generic_interrupt_controller.inc" ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_cpu.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64::cpu { /* Declare prototype to be implemented in asm. */ void SynchronizeAllCoresImpl(s32 *sync_var, s32 num_cores); namespace { ALWAYS_INLINE void SetEventLocally() { __asm__ __volatile__("sevl" ::: "memory"); } ALWAYS_INLINE void WaitForEvent() { __asm__ __volatile__("wfe" ::: "memory"); } class KScopedCoreMigrationDisable { public: ALWAYS_INLINE KScopedCoreMigrationDisable() { GetCurrentThread().DisableCoreMigration(); } ALWAYS_INLINE ~KScopedCoreMigrationDisable() { GetCurrentThread().EnableCoreMigration(); } }; class KScopedCacheMaintenance { private: bool m_active; public: ALWAYS_INLINE KScopedCacheMaintenance() { __asm__ __volatile__("" ::: "memory"); if (m_active = !GetCurrentThread().IsInCacheMaintenanceOperation(); m_active) { GetCurrentThread().SetInCacheMaintenanceOperation(); } } ALWAYS_INLINE ~KScopedCacheMaintenance() { if (m_active) { GetCurrentThread().ClearInCacheMaintenanceOperation(); } __asm__ __volatile__("" ::: "memory"); } }; /* Nintendo registers a handler for a SGI on thread termination, but does not handle anything. */ /* This is sufficient, because post-interrupt scheduling is all they really intend to occur. */ class KThreadTerminationInterruptHandler : public KInterruptHandler { public: constexpr KThreadTerminationInterruptHandler() : KInterruptHandler() { /* ... */ } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); return nullptr; } }; class KPerformanceCounterInterruptHandler : public KInterruptHandler { private: static constinit inline KLightLock s_lock; private: u64 m_counter; s32 m_which; bool m_done; public: constexpr KPerformanceCounterInterruptHandler() : KInterruptHandler(), m_counter(), m_which(), m_done() { /* ... */ } static KLightLock &GetLock() { return s_lock; } void Setup(s32 w) { m_done = false; m_which = w; } void Wait() { while (!m_done) { cpu::Yield(); } } u64 GetCounter() const { return m_counter; } /* Nintendo misuses this per their own API, but it's functional. */ virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); if (m_which < 0) { m_counter = cpu::GetCycleCounter(); } else { m_counter = cpu::GetPerformanceCounter(m_which); } DataMemoryBarrierInnerShareable(); m_done = true; return nullptr; } }; class KCoreBarrierInterruptHandler : public KInterruptHandler { private: util::Atomic<u64> m_target_cores; KLightLock m_lock; public: constexpr KCoreBarrierInterruptHandler() : KInterruptHandler(), m_target_cores(0), m_lock() { /* ... */ } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); m_target_cores &= ~(1ul << GetCurrentCoreId()); return nullptr; } void SynchronizeCores(u64 core_mask) { /* Acquire exclusive access to ourselves. */ KScopedLightLock lk(m_lock); /* If necessary, force synchronization with other cores. */ if (const u64 other_cores_mask = core_mask & ~(1ul << GetCurrentCoreId()); other_cores_mask != 0) { /* Send an interrupt to the other cores. */ m_target_cores = other_cores_mask; cpu::DataSynchronizationBarrierInnerShareable(); Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_CoreBarrier, other_cores_mask); /* Wait for all cores to acknowledge. */ { u64 v; __asm__ __volatile__("ldaxr %[v], %[p]\n" "cbz %[v], 1f\n" "0:\n" "wfe\n" "ldaxr %[v], %[p]\n" "cbnz %[v], 0b\n" "1:\n" : [v]"=&r"(v) : [p]"Q"(*reinterpret_cast<u64 *>(std::addressof(m_target_cores))) : "memory"); } } } }; class KCacheHelperInterruptHandler : public KInterruptHandler { private: static constexpr s32 ThreadPriority = 8; public: enum class Operation { Idle, InstructionMemoryBarrier, StoreDataCache, FlushDataCache, }; private: KLightLock m_lock; KLightLock m_cv_lock; KLightConditionVariable m_cv; util::Atomic<u64> m_target_cores; volatile Operation m_operation; private: static void ThreadFunction(uintptr_t _this) { reinterpret_cast<KCacheHelperInterruptHandler *>(_this)->ThreadFunctionImpl(); } void ThreadFunctionImpl() { const u64 core_mask = (1ul << GetCurrentCoreId()); while (true) { /* Wait for a request to come in. */ { KScopedLightLock lk(m_cv_lock); while ((m_target_cores.Load() & core_mask) == 0) { m_cv.Wait(std::addressof(m_cv_lock)); } } /* Process the request. */ this->ProcessOperation(); /* Broadcast, if there's nothing pending. */ { KScopedLightLock lk(m_cv_lock); m_target_cores &= ~core_mask; if (m_target_cores.Load() == 0) { m_cv.Broadcast(); } } } } void ProcessOperation(); public: constexpr KCacheHelperInterruptHandler() : KInterruptHandler(), m_lock(), m_cv_lock(), m_cv(util::ConstantInitialize), m_target_cores(0), m_operation(Operation::Idle) { /* ... */ } void Initialize(s32 core_id) { /* Reserve a thread from the system limit. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1)); /* Create a new thread. */ KThread *new_thread = KThread::Create(); MESOSPHERE_ABORT_UNLESS(new_thread != nullptr); MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, ThreadFunction, reinterpret_cast<uintptr_t>(this), ThreadPriority, core_id)); /* Register the new thread. */ KThread::Register(new_thread); /* Run the thread. */ MESOSPHERE_R_ABORT_UNLESS(new_thread->Run()); } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); this->ProcessOperation(); m_target_cores &= ~(1ul << GetCurrentCoreId()); return nullptr; } void RequestOperation(Operation op) { KScopedLightLock lk(m_lock); /* Create core masks for us to use. */ constexpr u64 AllCoresMask = (1ul << cpu::NumCores) - 1ul; const u64 other_cores_mask = AllCoresMask & ~(1ul << GetCurrentCoreId()); if ((op == Operation::InstructionMemoryBarrier) || (Kernel::GetState() == Kernel::State::Initializing)) { /* Check that there's no on-going operation. */ MESOSPHERE_ABORT_UNLESS(m_operation == Operation::Idle); MESOSPHERE_ABORT_UNLESS(m_target_cores.Load() == 0); /* Set operation. */ m_operation = op; /* For certain operations, we want to send an interrupt. */ m_target_cores = other_cores_mask; const u64 target_mask = m_target_cores.Load(); DataSynchronizationBarrierInnerShareable(); Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_CacheOperation, target_mask); this->ProcessOperation(); while (m_target_cores.Load() != 0) { cpu::Yield(); } /* Go idle again. */ m_operation = Operation::Idle; } else { /* Lock condvar so that we can send and wait for acknowledgement of request. */ KScopedLightLock cv_lk(m_cv_lock); /* Check that there's no on-going operation. */ MESOSPHERE_ABORT_UNLESS(m_operation == Operation::Idle); MESOSPHERE_ABORT_UNLESS(m_target_cores.Load() == 0); /* Set operation. */ m_operation = op; /* Request all cores. */ m_target_cores = AllCoresMask; /* Use the condvar. */ m_cv.Broadcast(); while (m_target_cores.Load() != 0) { m_cv.Wait(std::addressof(m_cv_lock)); } /* Go idle again. */ m_operation = Operation::Idle; } } }; /* Instances of the interrupt handlers. */ constinit KThreadTerminationInterruptHandler g_thread_termination_handler; constinit KCacheHelperInterruptHandler g_cache_operation_handler; constinit KCoreBarrierInterruptHandler g_core_barrier_handler; #if defined(MESOSPHERE_ENABLE_PERFORMANCE_COUNTER) constinit KPerformanceCounterInterruptHandler g_performance_counter_handler[cpu::NumCores]; #endif /* Expose this as a global, for asm to use. */ constinit s32 g_all_core_sync_count; template<typename F> ALWAYS_INLINE void PerformCacheOperationBySetWayImpl(int level, F f) { /* Used in multiple locations. */ const u64 level_sel_value = static_cast<u64>(level << 1); /* Get the cache size id register value with interrupts disabled. */ u64 ccsidr_value; { /* Disable interrupts. */ KScopedInterruptDisable di; /* Configure the cache select register for our level. */ cpu::SetCsselrEl1(level_sel_value); /* Ensure our configuration takes before reading the cache size id register. */ cpu::InstructionMemoryBarrier(); /* Get the cache size id register. */ ccsidr_value = cpu::GetCcsidrEl1(); } /* Ensure that no memory inconsistencies occur between cache management invocations. */ cpu::DataSynchronizationBarrier(); /* Get cache size id info. */ CacheSizeIdRegisterAccessor ccsidr_el1(ccsidr_value); const int num_sets = ccsidr_el1.GetNumberOfSets(); const int num_ways = ccsidr_el1.GetAssociativity(); const int line_size = ccsidr_el1.GetLineSize(); const u64 way_shift = static_cast<u64>(__builtin_clz(num_ways)); const u64 set_shift = static_cast<u64>(line_size + 4); for (int way = 0; way <= num_ways; way++) { for (int set = 0; set <= num_sets; set++) { const u64 way_value = static_cast<u64>(way) << way_shift; const u64 set_value = static_cast<u64>(set) << set_shift; f(way_value | set_value | level_sel_value); } } } ALWAYS_INLINE void FlushDataCacheLineBySetWayImpl(const u64 sw_value) { __asm__ __volatile__("dc cisw, %[v]" :: [v]"r"(sw_value) : "memory"); } ALWAYS_INLINE void StoreDataCacheLineBySetWayImpl(const u64 sw_value) { __asm__ __volatile__("dc csw, %[v]" :: [v]"r"(sw_value) : "memory"); } void StoreDataCacheBySetWay(int level) { PerformCacheOperationBySetWayImpl(level, StoreDataCacheLineBySetWayImpl); } void FlushDataCacheBySetWay(int level) { PerformCacheOperationBySetWayImpl(level, FlushDataCacheLineBySetWayImpl); } void KCacheHelperInterruptHandler::ProcessOperation() { switch (m_operation) { case Operation::Idle: break; case Operation::InstructionMemoryBarrier: InstructionMemoryBarrier(); break; case Operation::StoreDataCache: StoreDataCacheBySetWay(0); cpu::DataSynchronizationBarrier(); break; case Operation::FlushDataCache: FlushDataCacheBySetWay(0); cpu::DataSynchronizationBarrier(); break; } } ALWAYS_INLINE Result InvalidateDataCacheRange(uintptr_t start, uintptr_t end) { MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); R_UNLESS(UserspaceAccess::InvalidateDataCache(start, end), svc::ResultInvalidCurrentMemory()); DataSynchronizationBarrier(); R_SUCCEED(); } ALWAYS_INLINE Result StoreDataCacheRange(uintptr_t start, uintptr_t end) { MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); R_UNLESS(UserspaceAccess::StoreDataCache(start, end), svc::ResultInvalidCurrentMemory()); DataSynchronizationBarrier(); R_SUCCEED(); } ALWAYS_INLINE Result FlushDataCacheRange(uintptr_t start, uintptr_t end) { MESOSPHERE_ASSERT(util::IsAligned(start, DataCacheLineSize)); MESOSPHERE_ASSERT(util::IsAligned(end, DataCacheLineSize)); R_UNLESS(UserspaceAccess::FlushDataCache(start, end), svc::ResultInvalidCurrentMemory()); DataSynchronizationBarrier(); R_SUCCEED(); } ALWAYS_INLINE void InvalidateEntireInstructionCacheLocalImpl() { __asm__ __volatile__("ic iallu" ::: "memory"); } ALWAYS_INLINE void InvalidateEntireInstructionCacheGlobalImpl() { __asm__ __volatile__("ic ialluis" ::: "memory"); } } void SynchronizeCores(u64 core_mask) { /* Request a core barrier interrupt. */ g_core_barrier_handler.SynchronizeCores(core_mask); } void StoreCacheForInit(void *addr, size_t size) { /* Store the data cache for the specified range. */ const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize); const uintptr_t end = start + size; for (uintptr_t cur = start; cur < end; cur += DataCacheLineSize) { __asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(cur) : "memory"); } /* Data synchronization barrier. */ DataSynchronizationBarrierInnerShareable(); /* Invalidate instruction cache. */ InvalidateEntireInstructionCacheLocalImpl(); /* Ensure local instruction consistency. */ EnsureInstructionConsistency(); } void FlushEntireDataCache() { KScopedCoreMigrationDisable dm; CacheLineIdRegisterAccessor clidr_el1; const int levels_of_coherency = clidr_el1.GetLevelsOfCoherency(); /* Store cache from L2 up to the level of coherence (if there's an L3 cache or greater). */ for (int level = 2; level < levels_of_coherency; ++level) { StoreDataCacheBySetWay(level - 1); } /* Flush cache from the level of coherence down to L2. */ for (int level = levels_of_coherency; level > 1; --level) { FlushDataCacheBySetWay(level - 1); } /* Data synchronization barrier for full system. */ DataSynchronizationBarrier(); } Result InvalidateDataCache(void *addr, size_t size) { /* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */ KScopedCacheMaintenance cm; const uintptr_t start = reinterpret_cast<uintptr_t>(addr); const uintptr_t end = start + size; uintptr_t aligned_start = util::AlignDown(start, DataCacheLineSize); uintptr_t aligned_end = util::AlignUp(end, DataCacheLineSize); if (aligned_start != start) { R_TRY(FlushDataCacheRange(aligned_start, aligned_start + DataCacheLineSize)); aligned_start += DataCacheLineSize; } if (aligned_start < aligned_end && (aligned_end != end)) { aligned_end -= DataCacheLineSize; R_TRY(FlushDataCacheRange(aligned_end, aligned_end + DataCacheLineSize)); } if (aligned_start < aligned_end) { R_TRY(InvalidateDataCacheRange(aligned_start, aligned_end)); } R_SUCCEED(); } Result StoreDataCache(const void *addr, size_t size) { /* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */ KScopedCacheMaintenance cm; const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize); const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize); R_RETURN(StoreDataCacheRange(start, end)); } Result FlushDataCache(const void *addr, size_t size) { /* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */ KScopedCacheMaintenance cm; const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize); const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize); R_RETURN(FlushDataCacheRange(start, end)); } void InvalidateEntireInstructionCache() { KScopedCoreMigrationDisable dm; /* Invalidate the instruction cache on all cores. */ InvalidateEntireInstructionCacheGlobalImpl(); EnsureInstructionConsistency(); /* Request the interrupt helper to perform an instruction memory barrier. */ g_cache_operation_handler.RequestOperation(KCacheHelperInterruptHandler::Operation::InstructionMemoryBarrier); } void InitializeInterruptThreads(s32 core_id) { /* Initialize the cache operation handler. */ g_cache_operation_handler.Initialize(core_id); /* Bind all handlers to the relevant interrupts. */ MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_cache_operation_handler), KInterruptName_CacheOperation, core_id, KInterruptController::PriorityLevel_High, false, false)); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_thread_termination_handler), KInterruptName_ThreadTerminate, core_id, KInterruptController::PriorityLevel_Scheduler, false, false)); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_core_barrier_handler), KInterruptName_CoreBarrier, core_id, KInterruptController::PriorityLevel_Scheduler, false, false)); /* If we should, enable user access to the performance counter registers. */ if (KTargetSystem::IsUserPmuAccessEnabled()) { SetPmUserEnrEl0(1ul); } /* If we should, enable the kernel performance counter interrupt handler. */ #if defined(MESOSPHERE_ENABLE_PERFORMANCE_COUNTER) MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_performance_counter_handler[core_id]), KInterruptName_PerformanceCounter, core_id, KInterruptController::PriorityLevel_Timer, false, false)); #endif } void SynchronizeAllCores() { SynchronizeAllCoresImpl(&g_all_core_sync_count, static_cast<s32>(cpu::NumCores)); } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_cpu_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::arch::arm64::cpu::SynchronizeAllCoresImpl(int *sync_var, int num_cores) */ .section .text._ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii, "ax", %progbits .global _ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii .type _ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii, %function _ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii: /* Loop until the sync var is less than num cores. */ sevl 1: wfe ldaxr w2, [x0] cmp w2, w1 b.gt 1b /* Increment the sync var. */ 2: ldaxr w2, [x0] add w3, w2, #1 stlxr w4, w3, [x0] cbnz w4, 2b /* Loop until the sync var matches our ticket. */ add w3, w2, w1 sevl 3: wfe ldaxr w2, [x0] cmp w2, w3 b.ne 3b /* Check if the ticket is the last. */ sub w2, w1, #1 add w2, w2, w1 cmp w3, w2 b.eq 5f /* Our ticket is not the last one. Increment. */ 4: ldaxr w2, [x0] add w3, w2, #1 stlxr w4, w3, [x0] cbnz w4, 4b ret /* Our ticket is the last one. */ 5: stlr wzr, [x0] ret /* ams::kern::arch::arm64::cpu::ClearPageToZeroImpl(void *) */ .section .text._ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, "ax", %progbits .global _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv .type _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, %function _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv: /* Efficiently clear the page using dc zva. */ dc zva, x0 add x8, x0, #0x040 dc zva, x8 add x8, x0, #0x080 dc zva, x8 add x8, x0, #0x0c0 dc zva, x8 add x8, x0, #0x100 dc zva, x8 add x8, x0, #0x140 dc zva, x8 add x8, x0, #0x180 dc zva, x8 add x8, x0, #0x1c0 dc zva, x8 add x8, x0, #0x200 dc zva, x8 add x8, x0, #0x240 dc zva, x8 add x8, x0, #0x280 dc zva, x8 add x8, x0, #0x2c0 dc zva, x8 add x8, x0, #0x300 dc zva, x8 add x8, x0, #0x340 dc zva, x8 add x8, x0, #0x380 dc zva, x8 add x8, x0, #0x3c0 dc zva, x8 add x8, x0, #0x400 dc zva, x8 add x8, x0, #0x440 dc zva, x8 add x8, x0, #0x480 dc zva, x8 add x8, x0, #0x4c0 dc zva, x8 add x8, x0, #0x500 dc zva, x8 add x8, x0, #0x540 dc zva, x8 add x8, x0, #0x580 dc zva, x8 add x8, x0, #0x5c0 dc zva, x8 add x8, x0, #0x600 dc zva, x8 add x8, x0, #0x640 dc zva, x8 add x8, x0, #0x680 dc zva, x8 add x8, x0, #0x6c0 dc zva, x8 add x8, x0, #0x700 dc zva, x8 add x8, x0, #0x740 dc zva, x8 add x8, x0, #0x780 dc zva, x8 add x8, x0, #0x7c0 dc zva, x8 add x8, x0, #0x800 dc zva, x8 add x8, x0, #0x840 dc zva, x8 add x8, x0, #0x880 dc zva, x8 add x8, x0, #0x8c0 dc zva, x8 add x8, x0, #0x900 dc zva, x8 add x8, x0, #0x940 dc zva, x8 add x8, x0, #0x980 dc zva, x8 add x8, x0, #0x9c0 dc zva, x8 add x8, x0, #0xa00 dc zva, x8 add x8, x0, #0xa40 dc zva, x8 add x8, x0, #0xa80 dc zva, x8 add x8, x0, #0xac0 dc zva, x8 add x8, x0, #0xb00 dc zva, x8 add x8, x0, #0xb40 dc zva, x8 add x8, x0, #0xb80 dc zva, x8 add x8, x0, #0xbc0 dc zva, x8 add x8, x0, #0xc00 dc zva, x8 add x8, x0, #0xc40 dc zva, x8 add x8, x0, #0xc80 dc zva, x8 add x8, x0, #0xcc0 dc zva, x8 add x8, x0, #0xd00 dc zva, x8 add x8, x0, #0xd40 dc zva, x8 add x8, x0, #0xd80 dc zva, x8 add x8, x0, #0xdc0 dc zva, x8 add x8, x0, #0xe00 dc zva, x8 add x8, x0, #0xe40 dc zva, x8 add x8, x0, #0xe80 dc zva, x8 add x8, x0, #0xec0 dc zva, x8 add x8, x0, #0xf00 dc zva, x8 add x8, x0, #0xf40 dc zva, x8 add x8, x0, #0xf80 dc zva, x8 add x8, x0, #0xfc0 dc zva, x8 ret ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { void RestoreContext(uintptr_t sp); } namespace ams::kern::arch::arm64 { namespace { enum EsrEc : u32 { EsrEc_Unknown = 0b000000, EsrEc_WaitForInterruptOrEvent = 0b000001, EsrEc_Cp15McrMrc = 0b000011, EsrEc_Cp15McrrMrrc = 0b000100, EsrEc_Cp14McrMrc = 0b000101, EsrEc_FpAccess = 0b000111, EsrEc_Cp14Mrrc = 0b001100, EsrEc_BranchTarget = 0b001101, EsrEc_IllegalExecution = 0b001110, EsrEc_Svc32 = 0b010001, EsrEc_Svc64 = 0b010101, EsrEc_SystemInstruction64 = 0b011000, EsrEc_SveZen = 0b011001, EsrEc_PointerAuthInstruction = 0b011100, EsrEc_InstructionAbortEl0 = 0b100000, EsrEc_InstructionAbortEl1 = 0b100001, EsrEc_PcAlignmentFault = 0b100010, EsrEc_DataAbortEl0 = 0b100100, EsrEc_DataAbortEl1 = 0b100101, EsrEc_SpAlignmentFault = 0b100110, EsrEc_FpException32 = 0b101000, EsrEc_FpException64 = 0b101100, EsrEc_SErrorInterrupt = 0b101111, EsrEc_BreakPointEl0 = 0b110000, EsrEc_BreakPointEl1 = 0b110001, EsrEc_SoftwareStepEl0 = 0b110010, EsrEc_SoftwareStepEl1 = 0b110011, EsrEc_WatchPointEl0 = 0b110100, EsrEc_WatchPointEl1 = 0b110101, EsrEc_BkptInstruction = 0b111000, EsrEc_BrkInstruction = 0b111100, }; u32 GetInstructionDataSupervisorMode(const KExceptionContext *context, u64 esr) { /* Check for THUMB usermode */ if ((context->psr & 0x3F) == 0x30) { u32 insn = *reinterpret_cast<u16 *>(context->pc & ~0x1); /* Check if the instruction was 32-bit. */ if ((esr >> 25) & 1) { insn = (insn << 16) | *reinterpret_cast<u16 *>((context->pc & ~0x1) + sizeof(u16)); } return insn; } else { /* Not thumb, so just get the instruction. */ return *reinterpret_cast<u32 *>(context->pc); } } u32 GetInstructionDataUserMode(const KExceptionContext *context) { /* Check for THUMB usermode */ u32 insn = 0; if ((context->psr & 0x3F) == 0x30) { u16 insn_high = 0; if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_high), reinterpret_cast<u16 *>(context->pc & ~0x1), sizeof(insn_high))) { insn = insn_high; /* Check if the instruction was a THUMB mode branch prefix. */ if (((insn >> 11) & 0b11110) == 0b11110) { u16 insn_low = 0; if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_low), reinterpret_cast<u16 *>((context->pc & ~0x1) + sizeof(u16)), sizeof(insn_low))) { insn = (static_cast<u32>(insn_high) << 16) | (static_cast<u32>(insn_low) << 0); } else { insn = 0; } } } else { insn = 0; } } else { u32 insn_value = 0; if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_value), reinterpret_cast<u32 *>(context->pc), sizeof(insn_value))) { insn = insn_value; } else if (KTargetSystem::IsDebugMode() && (context->pc & 3) == 0 && UserspaceAccess::CopyMemoryFromUserSize32BitWithSupervisorAccess(std::addressof(insn_value), reinterpret_cast<u32 *>(context->pc))) { insn = insn_value; } else { insn = 0; } } return insn; } void HandleUserException(KExceptionContext *context, u64 raw_esr, u64 raw_far, u64 afsr0, u64 afsr1, u32 data) { /* Pre-process exception registers as needed. */ u64 esr = raw_esr; u64 far = raw_far; const u64 ec = (esr >> 26) & 0x3F; if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) { /* Adjust registers if a synchronous external abort has occurred with far not valid. */ /* Mask 0x03F = Low 6 bits IFSC == 0x10: "Synchronous External abort, */ /* not on translation table walk or hardware update of translation table. */ /* Mask 0x400 = FnV = "FAR Not Valid" */ /* TODO: How would we perform this check using named register accesses? */ if ((esr & 0x43F) == 0x410) { /* Clear the faulting register on memory tagging exception. */ far = 0; } else { /* If the faulting address is a kernel address, set ISFC = 4. */ if (far >= ams::svc::AddressMemoryRegion39Size) { esr = (esr & 0xFFFFFFC0) | 4; } } } KProcess &cur_process = GetCurrentProcess(); bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled(); /* In the event that we return from this exception, we want SPSR.SS set so that we advance an instruction if single-stepping. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) context->psr |= (1ul << 21); #endif /* If we should process the user exception (and it's not a breakpoint), try to enter. */ const bool is_software_break = (ec == EsrEc_Unknown || ec == EsrEc_IllegalExecution || ec == EsrEc_BkptInstruction || ec == EsrEc_BrkInstruction); const bool is_breakpoint = (ec == EsrEc_BreakPointEl0 || ec == EsrEc_SoftwareStepEl0 || ec == EsrEc_WatchPointEl0); if ((should_process_user_exception) && !(is_software_break && cur_process.IsAttachedToDebugger() && KDebug::IsBreakInstruction(data, context->psr)) && !(is_breakpoint)) { if (cur_process.EnterUserException()) { /* Fill out the exception info. */ const bool is_aarch64 = (context->psr & 0x10) == 0; if (is_aarch64) { /* 64-bit. */ ams::svc::aarch64::ExceptionInfo *info = std::addressof(static_cast<ams::svc::aarch64::ProcessLocalRegion *>(cur_process.GetProcessLocalRegionHeapAddress())->exception_info); for (size_t i = 0; i < util::size(info->r); ++i) { info->r[i] = context->x[i]; } info->sp = context->sp; info->lr = context->x[30]; info->pc = context->pc; info->pstate = (context->psr & cpu::El0Aarch64PsrMask); info->afsr0 = afsr0; info->afsr1 = afsr1; info->esr = esr; info->far = far; } else { /* 32-bit. */ ams::svc::aarch32::ExceptionInfo *info = std::addressof(static_cast<ams::svc::aarch32::ProcessLocalRegion *>(cur_process.GetProcessLocalRegionHeapAddress())->exception_info); for (size_t i = 0; i < util::size(info->r); ++i) { info->r[i] = context->x[i]; } info->sp = context->x[13]; info->lr = context->x[14]; info->pc = context->pc; info->flags = 1; info->status_64.pstate = (context->psr & cpu::El0Aarch32PsrMask); info->status_64.afsr0 = afsr0; info->status_64.afsr1 = afsr1; info->status_64.esr = esr; info->status_64.far = far; } /* Save the debug parameters to the current thread. */ GetCurrentThread().SaveDebugParams(raw_far, raw_esr, data); /* Get the exception type. */ u32 type; switch (ec) { case EsrEc_Unknown: case EsrEc_IllegalExecution: case EsrEc_Cp15McrMrc: case EsrEc_Cp15McrrMrrc: case EsrEc_Cp14McrMrc: case EsrEc_Cp14Mrrc: case EsrEc_SystemInstruction64: case EsrEc_BkptInstruction: case EsrEc_BrkInstruction: type = ams::svc::ExceptionType_InstructionAbort; break; case EsrEc_PcAlignmentFault: type = ams::svc::ExceptionType_UnalignedInstruction; break; case EsrEc_SpAlignmentFault: type = ams::svc::ExceptionType_UnalignedData; break; case EsrEc_Svc32: case EsrEc_Svc64: type = ams::svc::ExceptionType_InvalidSystemCall; break; case EsrEc_SErrorInterrupt: type = ams::svc::ExceptionType_MemorySystemError; break; case EsrEc_InstructionAbortEl0: type = ams::svc::ExceptionType_InstructionAbort; break; case EsrEc_DataAbortEl0: /* If esr.IFSC is "Alignment Fault", return UnalignedData instead of DataAbort. */ if ((esr & 0x3F) == 0b100001) { type = ams::svc::ExceptionType_UnalignedData; } else { type = ams::svc::ExceptionType_DataAbort; } break; default: type = ams::svc::ExceptionType_DataAbort; break; } /* We want to enter at the process entrypoint, with x0 = type. */ context->pc = GetInteger(cur_process.GetEntryPoint()); context->x[0] = type; if (is_aarch64) { context->x[1] = GetInteger(cur_process.GetProcessLocalRegionAddress() + AMS_OFFSETOF(ams::svc::aarch64::ProcessLocalRegion, exception_info)); const auto *plr = GetPointer<ams::svc::aarch64::ProcessLocalRegion>(cur_process.GetProcessLocalRegionAddress()); context->sp = util::AlignDown(reinterpret_cast<uintptr_t>(plr->data) + sizeof(plr->data), 0x10); context->psr = 0; } else { context->x[1] = GetInteger(cur_process.GetProcessLocalRegionAddress() + AMS_OFFSETOF(ams::svc::aarch32::ProcessLocalRegion, exception_info)); const auto *plr = GetPointer<ams::svc::aarch32::ProcessLocalRegion>(cur_process.GetProcessLocalRegionAddress()); context->x[13] = util::AlignDown(reinterpret_cast<uintptr_t>(plr->data) + sizeof(plr->data), 0x08); context->psr = 0x10; } /* Process that we're entering a usermode exception on the current thread. */ GetCurrentThread().OnEnterUsermodeException(); return; } } /* If we should, clear the thread's state as single-step. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) if (AMS_UNLIKELY(GetCurrentThread().IsHardwareSingleStep())) { GetCurrentThread().ClearHardwareSingleStep(); cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(false).Store(); cpu::InstructionMemoryBarrier(); } #endif { /* Collect additional information based on the ec. */ uintptr_t params[3] = {}; switch (ec) { case EsrEc_Unknown: case EsrEc_IllegalExecution: case EsrEc_BkptInstruction: case EsrEc_BrkInstruction: { params[0] = ams::svc::DebugException_UndefinedInstruction; params[1] = far; params[2] = data; } break; case EsrEc_PcAlignmentFault: case EsrEc_SpAlignmentFault: { params[0] = ams::svc::DebugException_AlignmentFault; params[1] = far; } break; case EsrEc_Svc32: case EsrEc_Svc64: { params[0] = ams::svc::DebugException_UndefinedSystemCall; params[1] = far; params[2] = (esr & 0xFF); } break; case EsrEc_BreakPointEl0: case EsrEc_SoftwareStepEl0: { params[0] = ams::svc::DebugException_BreakPoint; params[1] = far; params[2] = ams::svc::BreakPointType_HardwareInstruction; } break; case EsrEc_WatchPointEl0: { params[0] = ams::svc::DebugException_BreakPoint; params[1] = far; params[2] = ams::svc::BreakPointType_HardwareData; } break; case EsrEc_SErrorInterrupt: { params[0] = ams::svc::DebugException_MemorySystemError; params[1] = far; } break; case EsrEc_InstructionAbortEl0: { params[0] = ams::svc::DebugException_InstructionAbort; params[1] = far; } break; case EsrEc_DataAbortEl0: default: { params[0] = ams::svc::DebugException_DataAbort; params[1] = far; } break; } /* Process the debug event. */ Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)); /* If we should stop processing the exception, do so. */ if (svc::ResultStopProcessingException::Includes(result)) { return; } #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) { if (ec != EsrEc_SoftwareStepEl0) { /* If the exception wasn't single-step, print details. */ MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); { /* Print the current thread's registers. */ KDebug::PrintRegister(); /* Print a backtrace. */ KDebug::PrintBacktrace(); } } else { /* If the exception was single-step and we have no debug object, we should just return. */ if (AMS_UNLIKELY(!cur_process.IsAttachedToDebugger())) { return; } } } #else { /* Print that an exception occurred. */ MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); { /* Print the current thread's registers. */ KDebug::PrintRegister(); /* Print a backtrace. */ KDebug::PrintBacktrace(); } } #endif /* If the SVC is handled, handle it. */ if (!svc::ResultNotHandled::Includes(result)) { /* If we successfully enter jit debug, stop processing the exception. */ if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) { return; } } } /* Exit the current process. */ cur_process.Exit(); } } /* NOTE: This function is called from ASM. */ void FpuContextSwitchHandler() { KThreadContext::FpuContextSwitchHandler(GetCurrentThreadPointer()); } /* NOTE: This function is called from ASM. */ void ReturnFromException(Result user_result) { /* Get the current thread. */ KThread *cur_thread = GetCurrentThreadPointer(); /* Get the current exception context. */ KExceptionContext *e_ctx = GetExceptionContext(cur_thread); /* Get the current process. */ KProcess &cur_process = GetCurrentProcess(); /* Read the exception info that userland put in tls. */ union { ams::svc::aarch64::ExceptionInfo info64; ams::svc::aarch32::ExceptionInfo info32; } info = {}; const bool is_aarch64 = (e_ctx->psr & 0x10) == 0; if (is_aarch64) { /* We're 64-bit. */ info.info64 = static_cast<const ams::svc::aarch64::ProcessLocalRegion *>(cur_process.GetProcessLocalRegionHeapAddress())->exception_info; } else { /* We're 32-bit. */ info.info32 = static_cast<const ams::svc::aarch32::ProcessLocalRegion *>(cur_process.GetProcessLocalRegionHeapAddress())->exception_info; } /* Try to leave the user exception. */ if (cur_process.LeaveUserException()) { /* Process that we're leaving a usermode exception on the current thread. */ GetCurrentThread().OnLeaveUsermodeException(); /* Copy the user context to the thread context. */ if (is_aarch64) { for (size_t i = 0; i < util::size(info.info64.r); ++i) { e_ctx->x[i] = info.info64.r[i]; } e_ctx->x[30] = info.info64.lr; e_ctx->sp = info.info64.sp; e_ctx->pc = info.info64.pc; e_ctx->psr = (info.info64.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask); } else { for (size_t i = 0; i < util::size(info.info32.r); ++i) { e_ctx->x[i] = info.info32.r[i]; } e_ctx->x[14] = info.info32.lr; e_ctx->x[13] = info.info32.sp; e_ctx->pc = info.info32.pc; e_ctx->psr = (info.info32.status_64.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask); } /* Note that PC was adjusted. */ e_ctx->write = 1; if (R_SUCCEEDED(user_result)) { /* If result handling succeeded, just restore the context. */ svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx)); } else { /* Restore the debug params for the exception. */ uintptr_t far, esr, data; GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data)); /* Pre-process exception registers as needed. */ const u64 ec = (esr >> 26) & 0x3F; if (ec == EsrEc_InstructionAbortEl0 || ec == EsrEc_DataAbortEl0) { /* Adjust registers if a synchronous external abort has occurred with far not valid. */ /* Mask 0x03F = Low 6 bits IFSC == 0x10: "Synchronous External abort, */ /* not on translation table walk or hardware update of translation table. */ /* Mask 0x400 = FnV = "FAR Not Valid" */ /* TODO: How would we perform this check using named register accesses? */ if ((esr & 0x43F) == 0x410) { /* Clear the faulting register on memory tagging exception. */ far = 0; } else { /* If the faulting address is a kernel address, set ISFC = 4. */ if (far >= ams::svc::AddressMemoryRegion39Size) { esr = (esr & 0xFFFFFFC0) | 4; } } } /* Collect additional information based on the ec. */ uintptr_t params[3] = {}; switch (ec) { case EsrEc_Unknown: case EsrEc_IllegalExecution: case EsrEc_BkptInstruction: case EsrEc_BrkInstruction: { params[0] = ams::svc::DebugException_UndefinedInstruction; params[1] = far; params[2] = data; } break; case EsrEc_PcAlignmentFault: case EsrEc_SpAlignmentFault: { params[0] = ams::svc::DebugException_AlignmentFault; params[1] = far; } break; case EsrEc_Svc32: case EsrEc_Svc64: { params[0] = ams::svc::DebugException_UndefinedSystemCall; params[1] = far; params[2] = (esr & 0xFF); } break; case EsrEc_SErrorInterrupt: { params[0] = ams::svc::DebugException_MemorySystemError; params[1] = far; } break; case EsrEc_InstructionAbortEl0: { params[0] = ams::svc::DebugException_InstructionAbort; params[1] = far; } break; case EsrEc_DataAbortEl0: default: { params[0] = ams::svc::DebugException_DataAbort; params[1] = far; } break; } /* Process the debug event. */ Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)); /* If the SVC is handled, handle it. */ if (!svc::ResultNotHandled::Includes(result)) { /* If we should stop processing the exception, restore. */ if (svc::ResultStopProcessingException::Includes(result)) { svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx)); } /* If we successfully enter jit debug, restore. */ if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) { svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx)); } } /* Otherwise, if result debug was returned, restore. */ if (svc::ResultDebug::Includes(result)) { svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx)); } } } /* Print that an exception occurred. */ MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); /* Exit the current process. */ GetCurrentProcess().Exit(); } /* NOTE: This function is called from ASM. */ void HandleException(KExceptionContext *context) { MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); /* Retrieve information about the exception. */ const bool is_user_mode = (context->psr & 0xF) == 0; const u64 esr = cpu::GetEsrEl1(); const u64 afsr0 = cpu::GetAfsr0El1(); const u64 afsr1 = cpu::GetAfsr1El1(); u64 far = 0; u32 data = 0; /* Collect far and data based on the ec. */ switch ((esr >> 26) & 0x3F) { case EsrEc_Unknown: case EsrEc_IllegalExecution: case EsrEc_BkptInstruction: case EsrEc_BrkInstruction: far = context->pc; /* NOTE: Nintendo always calls GetInstructionDataUserMode. */ if (is_user_mode) { data = GetInstructionDataUserMode(context); } else { data = GetInstructionDataSupervisorMode(context, esr); } break; case EsrEc_Svc32: if (context->psr & 0x20) { /* Thumb mode. */ context->pc -= 2; } else { /* ARM mode. */ context->pc -= 4; } far = context->pc; break; case EsrEc_Svc64: context->pc -= 4; far = context->pc; break; case EsrEc_BreakPointEl0: far = context->pc; break; default: far = cpu::GetFarEl1(); break; } /* Note that we're in an exception handler. */ GetCurrentThread().SetInExceptionHandler(); /* Verify that spsr's M is allowable (EL0t). */ { if (is_user_mode) { /* If the user disable count is set, we may need to pin the current thread. */ if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) { KScopedSchedulerLock lk; /* Pin the current thread. */ GetCurrentProcess().PinCurrentThread(); /* Set the interrupt flag for the thread. */ GetCurrentThread().SetInterruptFlag(); } /* Enable interrupts while we process the usermode exception. */ { KScopedInterruptEnable ei; /* Terminate the thread, if we should. */ if (GetCurrentThread().IsTerminationRequested()) { GetCurrentThread().Exit(); } HandleUserException(context, esr, far, afsr0, afsr1, data); } } else { const s32 core_id = GetCurrentCoreId(); MESOSPHERE_LOG("%d: Unhandled Exception in Supervisor Mode\n", core_id); if (GetCurrentProcessPointer() != nullptr) { MESOSPHERE_LOG("%d: Current Process = %s\n", core_id, GetCurrentProcess().GetName()); } for (size_t i = 0; i < 31; i++) { MESOSPHERE_LOG("%d: X[%02zu] = %016lx\n", core_id, i, context->x[i]); } MESOSPHERE_LOG("%d: PC = %016lx\n", core_id, context->pc); MESOSPHERE_LOG("%d: SP = %016lx\n", core_id, context->sp); MESOSPHERE_PANIC("Unhandled Exception in Supervisor Mode\n"); } MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); /* Handle any DPC requests. */ while (GetCurrentThread().HasDpc()) { KDpcManager::HandleDpc(); } } /* Note that we're no longer in an exception handler. */ GetCurrentThread().ClearInExceptionHandler(); } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_debug.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> /* <stratosphere/rocrt/rocrt.hpp> */ namespace ams::rocrt { constexpr inline const u32 ModuleHeaderVersion = util::FourCC<'M','O','D','0'>::Code; struct ModuleHeader { u32 signature; u32 dynamic_offset; u32 bss_start_offset; u32 bss_end_offset; u32 exception_info_start_offset; u32 exception_info_end_offset; u32 module_offset; }; struct ModuleHeaderLocation { u32 pad; u32 header_offset; }; } namespace ams::kern::arch::arm64 { namespace { constexpr inline u64 ForbiddenBreakPointFlagsMask = (((1ul << 40) - 1) << 24) | /* Reserved upper bits. */ (((1ul << 1) - 1) << 23) | /* Match VMID BreakPoint Type. */ (((1ul << 2) - 1) << 14) | /* Security State Control. */ (((1ul << 1) - 1) << 13) | /* Hyp Mode Control. */ (((1ul << 4) - 1) << 9) | /* Reserved middle bits. */ (((1ul << 2) - 1) << 3) | /* Reserved lower bits. */ (((1ul << 2) - 1) << 1); /* Privileged Mode Control. */ static_assert(ForbiddenBreakPointFlagsMask == 0xFFFFFFFFFF80FE1Eul); constexpr inline u64 ForbiddenWatchPointFlagsMask = (((1ul << 32) - 1) << 32) | /* Reserved upper bits. */ (((1ul << 4) - 1) << 20) | /* WatchPoint Type. */ (((1ul << 2) - 1) << 14) | /* Security State Control. */ (((1ul << 1) - 1) << 13) | /* Hyp Mode Control. */ (((1ul << 2) - 1) << 1); /* Privileged Access Control. */ static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul); } uintptr_t KDebug::GetProgramCounter(const KThread &thread) { return GetExceptionContext(std::addressof(thread))->pc; } void KDebug::SetPreviousProgramCounter() { /* Get the current thread. */ KThread *thread = GetCurrentThreadPointer(); MESOSPHERE_ASSERT(thread->IsCallingSvc()); /* Get the exception context. */ KExceptionContext *e_ctx = GetExceptionContext(thread); /* Set the previous pc. */ if (e_ctx->write == 0) { /* Subtract from the program counter. */ if (thread->GetOwnerProcess()->Is64Bit()) { e_ctx->pc -= sizeof(u32); } else { e_ctx->pc -= (e_ctx->psr & 0x20) ? sizeof(u16) : sizeof(u32); } /* Mark that we've set. */ e_ctx->write = 1; } } Result KDebug::GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread != GetCurrentThreadPointer()); /* Get the exception context. */ const KExceptionContext *e_ctx = GetExceptionContext(thread); /* Get whether we're 64-bit. */ const bool is_64_bit = this->Is64Bit(); /* If general registers are requested, get them. */ if ((context_flags & ams::svc::ThreadContextFlag_General) != 0) { /* We can always get X0-X7/R0-R7. */ auto register_count = 8; if (!thread->IsCallingSvc() || thread->GetSvcId() == svc::SvcId_ReturnFromException) { if (is_64_bit) { /* We're not in an SVC, so we can get X0-X29. */ register_count = 29; } else { /* We're 32-bit, so we should get R0-R12. */ register_count = 13; } } /* Get the registers. */ for (auto i = 0; i < register_count; ++i) { out->r[i] = is_64_bit ? e_ctx->x[i] : static_cast<u32>(e_ctx->x[i]); } } /* If control flags are requested, get them. */ if ((context_flags & ams::svc::ThreadContextFlag_Control) != 0) { if (is_64_bit) { out->fp = e_ctx->x[29]; out->lr = e_ctx->x[30]; out->sp = e_ctx->sp; out->pc = e_ctx->pc; out->pstate = (e_ctx->psr & cpu::El0Aarch64PsrMask); /* Adjust PC if we should. */ if (e_ctx->write == 0 && thread->IsCallingSvc()) { out->pc -= sizeof(u32); } out->tpidr = e_ctx->tpidr; } else { out->r[11] = static_cast<u32>(e_ctx->x[11]); out->r[13] = static_cast<u32>(e_ctx->x[13]); out->r[14] = static_cast<u32>(e_ctx->x[14]); out->lr = 0; out->sp = 0; out->pc = e_ctx->pc; out->pstate = (e_ctx->psr & cpu::El0Aarch32PsrMask); /* Adjust PC if we should. */ if (e_ctx->write == 0 && thread->IsCallingSvc()) { out->pc -= (e_ctx->psr & 0x20) ? sizeof(u16) : sizeof(u32); } out->tpidr = static_cast<u32>(e_ctx->tpidr); } } /* Get the FPU context. */ R_RETURN(this->GetFpuContext(out, thread, context_flags)); } Result KDebug::SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread != GetCurrentThreadPointer()); /* Get the exception context. */ KExceptionContext *e_ctx = GetExceptionContext(thread); /* If general registers are requested, set them. */ if ((context_flags & ams::svc::ThreadContextFlag_General) != 0) { if (this->Is64Bit()) { /* Set X0-X28. */ for (auto i = 0; i <= 28; ++i) { e_ctx->x[i] = ctx.r[i]; } } else { /* Set R0-R12. */ for (auto i = 0; i <= 12; ++i) { e_ctx->x[i] = static_cast<u32>(ctx.r[i]); } } } /* If control flags are requested, set them. */ if ((context_flags & ams::svc::ThreadContextFlag_Control) != 0) { /* Mark ourselve as having adjusted pc. */ e_ctx->write = 1; if (this->Is64Bit()) { e_ctx->x[29] = ctx.fp; e_ctx->x[30] = ctx.lr; e_ctx->sp = ctx.sp; e_ctx->pc = ctx.pc; e_ctx->psr = ((ctx.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask)); e_ctx->tpidr = ctx.tpidr; } else { e_ctx->x[13] = static_cast<u32>(ctx.r[13]); e_ctx->x[14] = static_cast<u32>(ctx.r[14]); e_ctx->x[30] = 0; e_ctx->sp = 0; e_ctx->pc = static_cast<u32>(ctx.pc); e_ctx->psr = ((ctx.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask)); e_ctx->tpidr = ctx.tpidr; } } /* Set the FPU context. */ R_RETURN(this->SetFpuContext(ctx, thread, context_flags)); } Result KDebug::GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread != GetCurrentThreadPointer()); /* Succeed if there's nothing to do. */ R_SUCCEED_IF((context_flags & (ams::svc::ThreadContextFlag_Fpu | ams::svc::ThreadContextFlag_FpuControl)) == 0); /* Get the thread context. */ KThreadContext *t_ctx = std::addressof(thread->GetContext()); /* Get the FPU control registers, if required. */ if ((context_flags & ams::svc::ThreadContextFlag_FpuControl) != 0) { out->fpsr = t_ctx->GetFpsr(); out->fpcr = t_ctx->GetFpcr(); } /* Get the FPU registers, if required. */ if ((context_flags & ams::svc::ThreadContextFlag_Fpu) != 0) { static_assert(util::size(ams::svc::ThreadContext{}.v) == KThreadContext::NumFpuRegisters); const auto &caller_save = thread->GetCallerSaveFpuRegisters(); const auto &callee_save = t_ctx->GetCalleeSaveFpuRegisters(); if (this->Is64Bit()) { KThreadContext::GetFpuRegisters(out->v, caller_save.fpu64, callee_save.fpu64); } else { KThreadContext::GetFpuRegisters(out->v, caller_save.fpu32, callee_save.fpu32); for (size_t i = KThreadContext::NumFpuRegisters / 2; i < KThreadContext::NumFpuRegisters; ++i) { out->v[i] = 0; } } } R_SUCCEED(); } Result KDebug::SetFpuContext(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread != GetCurrentThreadPointer()); /* Succeed if there's nothing to do. */ R_SUCCEED_IF((context_flags & (ams::svc::ThreadContextFlag_Fpu | ams::svc::ThreadContextFlag_FpuControl)) == 0); /* Get the thread context. */ KThreadContext *t_ctx = std::addressof(thread->GetContext()); /* Set the FPU control registers, if required. */ if ((context_flags & ams::svc::ThreadContextFlag_FpuControl) != 0) { t_ctx->SetFpsr(ctx.fpsr); t_ctx->SetFpcr(ctx.fpcr); } /* Set the FPU registers, if required. */ if ((context_flags & ams::svc::ThreadContextFlag_Fpu) != 0) { static_assert(util::size(ams::svc::ThreadContext{}.v) == KThreadContext::NumFpuRegisters); auto &caller_save = thread->GetCallerSaveFpuRegisters(); auto &callee_save = t_ctx->GetCalleeSaveFpuRegisters(); if (this->Is64Bit()) { KThreadContext::SetFpuRegisters(caller_save.fpu64, callee_save.fpu64, ctx.v); } else { KThreadContext::SetFpuRegisters(caller_save.fpu32, callee_save.fpu32, ctx.v); } } R_SUCCEED(); } Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) { const uintptr_t params[5] = { ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size }; R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params))); } #define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \ ({ \ cpu::SetDbgBcr##ID##El1(0); \ cpu::EnsureInstructionConsistencyFullSystem(); \ cpu::SetDbgBvr##ID##El1(VALUE); \ cpu::EnsureInstructionConsistencyFullSystem(); \ cpu::SetDbgBcr##ID##El1(FLAGS); \ cpu::EnsureInstructionConsistencyFullSystem(); \ }) #define MESOSPHERE_SET_HW_WATCH_POINT(ID, FLAGS, VALUE) \ ({ \ cpu::SetDbgWcr##ID##El1(0); \ cpu::EnsureInstructionConsistencyFullSystem(); \ cpu::SetDbgWvr##ID##El1(VALUE); \ cpu::EnsureInstructionConsistencyFullSystem(); \ cpu::SetDbgWcr##ID##El1(FLAGS); \ cpu::EnsureInstructionConsistencyFullSystem(); \ }) Result KDebug::SetHardwareBreakPoint(ams::svc::HardwareBreakPointRegisterName name, u64 flags, u64 value) { /* Get the debug feature register. */ cpu::DebugFeatureRegisterAccessor dfr0; /* Extract interesting info from the debug feature register. */ const auto num_bp = dfr0.GetNumBreakpoints(); const auto num_wp = dfr0.GetNumWatchpoints(); const auto num_ctx = dfr0.GetNumContextAwareBreakpoints(); if (ams::svc::HardwareBreakPointRegisterName_I0 <= name && name <= ams::svc::HardwareBreakPointRegisterName_I15) { /* Check that the name is a valid instruction breakpoint. */ R_UNLESS((name - ams::svc::HardwareBreakPointRegisterName_I0) <= num_bp, svc::ResultNotSupported()); /* Configure flags/value. */ if ((flags & 1) != 0) { /* We're enabling the breakpoint. Check that the flags are allowable. */ R_UNLESS((flags & ForbiddenBreakPointFlagsMask) == 0, svc::ResultInvalidCombination()); /* Require that the breakpoint be linked or match context id. */ R_UNLESS((flags & ((1ul << 21) | (1ul << 20))) != 0, svc::ResultInvalidCombination()); /* If the breakpoint matches context id, we need to get the context id. */ if ((flags & (1ul << 21)) != 0) { /* Ensure that the breakpoint is context-aware. */ R_UNLESS((name - ams::svc::HardwareBreakPointRegisterName_I0) >= (num_bp - num_ctx), svc::ResultNotSupported()); /* Check that the breakpoint does not have the mismatch bit. */ R_UNLESS((flags & (1ul << 22)) == 0, svc::ResultInvalidCombination()); /* Get the debug object from the current handle table. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(static_cast<ams::svc::Handle>(value)); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process from the debug object. */ R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); /* Close the process when we're done. */ ON_SCOPE_EXIT { debug->CloseProcess(); }; /* Get the proces. */ KProcess * const process = debug->GetProcessUnsafe(); /* Set the value to be the context id. */ value = process->GetId() & 0xFFFFFFFF; } /* Set the breakpoint as non-secure EL0-only. */ flags |= (1ul << 14) | (2ul << 1); } else { /* We're disabling the breakpoint. */ flags = 0; value = 0; } /* Set the breakpoint. */ switch (name) { case ams::svc::HardwareBreakPointRegisterName_I0: MESOSPHERE_SET_HW_BREAK_POINT( 0, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I1: MESOSPHERE_SET_HW_BREAK_POINT( 1, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I2: MESOSPHERE_SET_HW_BREAK_POINT( 2, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I3: MESOSPHERE_SET_HW_BREAK_POINT( 3, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I4: MESOSPHERE_SET_HW_BREAK_POINT( 4, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I5: MESOSPHERE_SET_HW_BREAK_POINT( 5, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I6: MESOSPHERE_SET_HW_BREAK_POINT( 6, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I7: MESOSPHERE_SET_HW_BREAK_POINT( 7, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I8: MESOSPHERE_SET_HW_BREAK_POINT( 8, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I9: MESOSPHERE_SET_HW_BREAK_POINT( 9, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I10: MESOSPHERE_SET_HW_BREAK_POINT(10, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I11: MESOSPHERE_SET_HW_BREAK_POINT(11, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I12: MESOSPHERE_SET_HW_BREAK_POINT(12, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I13: MESOSPHERE_SET_HW_BREAK_POINT(13, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I14: MESOSPHERE_SET_HW_BREAK_POINT(14, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_I15: MESOSPHERE_SET_HW_BREAK_POINT(15, flags, value); break; default: break; } } else if (ams::svc::HardwareBreakPointRegisterName_D0 <= name && name <= ams::svc::HardwareBreakPointRegisterName_D15) { /* Check that the name is a valid data breakpoint. */ R_UNLESS((name - ams::svc::HardwareBreakPointRegisterName_D0) <= num_wp, svc::ResultNotSupported()); /* Configure flags/value. */ if ((flags & 1) != 0) { /* We're enabling the watchpoint. Check that the flags are allowable. */ R_UNLESS((flags & ForbiddenWatchPointFlagsMask) == 0, svc::ResultInvalidCombination()); /* Set the breakpoint as linked non-secure EL0-only. */ flags |= (1ul << 20) | (1ul << 14) | (2ul << 1); } else { /* We're disabling the watchpoint. */ flags = 0; value = 0; } /* Set the watchpoint. */ switch (name) { case ams::svc::HardwareBreakPointRegisterName_D0: MESOSPHERE_SET_HW_WATCH_POINT( 0, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D1: MESOSPHERE_SET_HW_WATCH_POINT( 1, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D2: MESOSPHERE_SET_HW_WATCH_POINT( 2, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D3: MESOSPHERE_SET_HW_WATCH_POINT( 3, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D4: MESOSPHERE_SET_HW_WATCH_POINT( 4, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D5: MESOSPHERE_SET_HW_WATCH_POINT( 5, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D6: MESOSPHERE_SET_HW_WATCH_POINT( 6, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D7: MESOSPHERE_SET_HW_WATCH_POINT( 7, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D8: MESOSPHERE_SET_HW_WATCH_POINT( 8, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D9: MESOSPHERE_SET_HW_WATCH_POINT( 9, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D10: MESOSPHERE_SET_HW_WATCH_POINT(10, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D11: MESOSPHERE_SET_HW_WATCH_POINT(11, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D12: MESOSPHERE_SET_HW_WATCH_POINT(12, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D13: MESOSPHERE_SET_HW_WATCH_POINT(13, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D14: MESOSPHERE_SET_HW_WATCH_POINT(14, flags, value); break; case ams::svc::HardwareBreakPointRegisterName_D15: MESOSPHERE_SET_HW_WATCH_POINT(15, flags, value); break; default: break; } } else { /* Invalid name. */ R_THROW(svc::ResultInvalidEnumValue()); } R_SUCCEED(); } #undef MESOSPHERE_SET_HW_WATCH_POINT #undef MESOSPHERE_SET_HW_BREAK_POINT void KDebug::PrintRegister(KThread *thread) { #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) { /* Treat no thread as current thread. */ if (thread == nullptr) { thread = GetCurrentThreadPointer(); } /* Get the exception context. */ KExceptionContext *e_ctx = GetExceptionContext(thread); /* Get the owner process. */ if (auto *process = thread->GetOwnerProcess(); process != nullptr) { /* Lock the owner process. */ KScopedLightLock state_lk(process->GetStateLock()); KScopedLightLock list_lk(process->GetListLock()); /* Suspend all the process's threads. */ { KScopedSchedulerLock sl; auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { if (std::addressof(*it) != GetCurrentThreadPointer()) { it->RequestSuspend(KThread::SuspendType_Backtrace); } } } /* Print the registers. */ MESOSPHERE_RELEASE_LOG("Registers\n"); if ((e_ctx->psr & 0x10) == 0) { /* 64-bit thread. */ for (auto i = 0; i < 31; ++i) { MESOSPHERE_RELEASE_LOG(" X[%2d]: 0x%016lx\n", i, e_ctx->x[i]); } MESOSPHERE_RELEASE_LOG(" SP: 0x%016lx\n", e_ctx->sp); MESOSPHERE_RELEASE_LOG(" PC: 0x%016lx\n", e_ctx->pc - sizeof(u32)); MESOSPHERE_RELEASE_LOG(" PSR: 0x%08x\n", e_ctx->psr); MESOSPHERE_RELEASE_LOG(" TPIDR_EL0: 0x%016lx\n", e_ctx->tpidr); } else { /* 32-bit thread. */ for (auto i = 0; i < 13; ++i) { MESOSPHERE_RELEASE_LOG(" R[%2d]: 0x%08x\n", i, static_cast<u32>(e_ctx->x[i])); } MESOSPHERE_RELEASE_LOG(" SP: 0x%08x\n", static_cast<u32>(e_ctx->x[13])); MESOSPHERE_RELEASE_LOG(" LR: 0x%08x\n", static_cast<u32>(e_ctx->x[14])); MESOSPHERE_RELEASE_LOG(" PC: 0x%08x\n", static_cast<u32>(e_ctx->pc) - static_cast<u32>((e_ctx->psr & 0x20) ? sizeof(u16) : sizeof(u32))); MESOSPHERE_RELEASE_LOG(" PSR: 0x%08x\n", e_ctx->psr); MESOSPHERE_RELEASE_LOG(" TPIDR: 0x%08x\n", static_cast<u32>(e_ctx->tpidr)); } /* Resume the threads that we suspended. */ { KScopedSchedulerLock sl; auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { if (std::addressof(*it) != GetCurrentThreadPointer()) { it->Resume(KThread::SuspendType_Backtrace); } } } } } #else MESOSPHERE_UNUSED(thread); #endif } #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) namespace { bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) { const KMemoryRegion *cached = nullptr; return KMemoryLayout::IsHeapPhysicalAddress(cached, phys_addr); } template<typename T> bool ReadValue(T *out, KProcess *process, uintptr_t address) { KPhysicalAddress phys_addr; KMemoryInfo mem_info; ams::svc::PageInfo page_info; if (!util::IsAligned(address, sizeof(T))) { return false; } if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), address))) { return false; } if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { return false; } if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), address)) { return false; } if (!IsHeapPhysicalAddress(phys_addr)) { return false; } *out = *GetPointer<T>(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); return true; } bool GetModuleName(char *dst, size_t dst_size, KProcess *process, uintptr_t base_address) { /* Locate .rodata. */ KMemoryInfo mem_info; ams::svc::PageInfo page_info; KMemoryState mem_state = KMemoryState_None; while (true) { if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address))) { return false; } if (mem_state == KMemoryState_None) { mem_state = mem_info.GetState(); if (mem_state != KMemoryState_Code && mem_state != KMemoryState_AliasCode) { return false; } } if (mem_info.GetState() != mem_state) { return false; } if (mem_info.GetPermission() == KMemoryPermission_UserRead) { break; } base_address = mem_info.GetEndAddress(); } /* Check that first value is 0. */ u32 val; if (!ReadValue(std::addressof(val), process, base_address)) { return false; } if (val != 0) { return false; } /* Read the name length. */ if (!ReadValue(std::addressof(val), process, base_address + sizeof(u32))) { return false; } if (!(0 < val && val < dst_size)) { return false; } const size_t name_len = val; /* Read the name, one character at a time. */ for (size_t i = 0; i < name_len; ++i) { if (!ReadValue(dst + i, process, base_address + 2 * sizeof(u32) + i)) { return false; } if (!(0 < dst[i] && dst[i] <= 0x7F)) { return false; } } /* NULL-terminate. */ dst[name_len] = 0; return true; } void PrintAddress(uintptr_t address) { MESOSPHERE_RELEASE_LOG(" %p\n", reinterpret_cast<void *>(address)); } void PrintAddressWithModuleName(uintptr_t address, bool has_module_name, const char *module_name, uintptr_t base_address) { if (has_module_name) { MESOSPHERE_RELEASE_LOG(" %p [%10s + %8lx]\n", reinterpret_cast<void *>(address), module_name, address - base_address); } else { MESOSPHERE_RELEASE_LOG(" %p [%10lx + %8lx]\n", reinterpret_cast<void *>(address), base_address, address - base_address); } } void PrintAddressWithSymbol(uintptr_t address, bool has_module_name, const char *module_name, uintptr_t base_address, const char *symbol_name, uintptr_t func_address) { if (has_module_name) { MESOSPHERE_RELEASE_LOG(" %p [%10s + %8lx] (%s + %lx)\n", reinterpret_cast<void *>(address), module_name, address - base_address, symbol_name, address - func_address); } else { MESOSPHERE_RELEASE_LOG(" %p [%10lx + %8lx] (%s + %lx)\n", reinterpret_cast<void *>(address), base_address, address - base_address, symbol_name, address - func_address); } } void PrintCodeAddress(KProcess *process, uintptr_t address, bool is_lr = true) { /* Prepare to parse + print the address. */ uintptr_t test_address = is_lr ? address - sizeof(u32) : address; uintptr_t base_address = address; uintptr_t dyn_address = 0; uintptr_t sym_tab = 0; uintptr_t str_tab = 0; size_t num_sym = 0; u64 temp_64; u32 temp_32; /* Locate the start of .text. */ KMemoryInfo mem_info; ams::svc::PageInfo page_info; KMemoryState mem_state = KMemoryState_None; while (true) { if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address))) { return PrintAddress(address); } if (mem_state == KMemoryState_None) { mem_state = mem_info.GetState(); if (mem_state != KMemoryState_Code && mem_state != KMemoryState_AliasCode) { return PrintAddress(address); } } else if (mem_info.GetState() != mem_state) { return PrintAddress(address); } if (mem_info.GetPermission() != KMemoryPermission_UserReadExecute) { return PrintAddress(address); } base_address = mem_info.GetAddress(); if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), base_address - 1))) { return PrintAddress(address); } if (mem_info.GetState() != mem_state) { break; } if (mem_info.GetPermission() != KMemoryPermission_UserReadExecute) { break; } } /* Get the module name. */ char module_name[0x20]; const bool has_module_name = GetModuleName(module_name, sizeof(module_name), process, base_address); /* If the process is 32-bit, just print the module. */ if (!process->Is64Bit()) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Locate .dyn using rocrt::ModuleHeader. */ { /* Determine the ModuleHeader offset. */ u32 mod_offset; if (!ReadValue(std::addressof(mod_offset), process, base_address + sizeof(u32))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Read the signature. */ constexpr u32 SignatureFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, signature); if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + SignatureFieldOffset)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Check that the module signature is expected. */ if (temp_32 != rocrt::ModuleHeaderVersion) { /* MOD0 */ return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Determine the dynamic offset. */ constexpr u32 DynamicFieldOffset = AMS_OFFSETOF(rocrt::ModuleHeader, dynamic_offset); if (!ReadValue(std::addressof(temp_32), process, base_address + mod_offset + DynamicFieldOffset)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } dyn_address = base_address + mod_offset + temp_32; } /* Locate tables inside .dyn. */ for (size_t ofs = 0; /* ... */; ofs += 0x10) { /* Read the DynamicTag. */ if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } if (temp_64 == 0) { /* We're done parsing .dyn. */ break; } else if (temp_64 == 4) { /* We found DT_HASH */ if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Read nchain, to get the number of symbols. */ if (!ReadValue(std::addressof(temp_32), process, base_address + temp_64 + sizeof(u32))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } num_sym = temp_32; } else if (temp_64 == 5) { /* We found DT_STRTAB */ if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } str_tab = base_address + temp_64; } else if (temp_64 == 6) { /* We found DT_SYMTAB */ if (!ReadValue(std::addressof(temp_64), process, dyn_address + ofs + sizeof(u64))) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } sym_tab = base_address + temp_64; } } /* Check that we found all the tables. */ if (!(sym_tab != 0 && str_tab != 0 && num_sym != 0)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } /* Try to locate an appropriate symbol. */ for (size_t i = 0; i < num_sym; ++i) { /* Read the symbol from userspace. */ struct { u32 st_name; u8 st_info; u8 st_other; u16 st_shndx; u64 st_value; u64 st_size; } sym; { u64 x[sizeof(sym) / sizeof(u64)]; for (size_t j = 0; j < util::size(x); ++j) { if (!ReadValue(x + j, process, sym_tab + sizeof(sym) * i + sizeof(u64) * j)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } } std::memcpy(std::addressof(sym), x, sizeof(sym)); } /* Check the symbol is valid/STT_FUNC. */ if (sym.st_shndx == 0 || ((sym.st_shndx & 0xFF00) == 0xFF00)) { continue; } if ((sym.st_info & 0xF) != 2) { continue; } /* Check the address. */ const uintptr_t func_start = base_address + sym.st_value; if (func_start <= test_address && test_address < func_start + sym.st_size) { /* Read the symbol name. */ const uintptr_t sym_address = str_tab + sym.st_name; char sym_name[0x80]; sym_name[util::size(sym_name) - 1] = 0; for (size_t j = 0; j < util::size(sym_name) - 1; ++j) { if (!ReadValue(sym_name + j, process, sym_address + j)) { return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } if (sym_name[j] == 0) { break; } } /* Print the symbol. */ return PrintAddressWithSymbol(address, has_module_name, module_name, base_address, sym_name, func_start); } } /* Fall back to printing the module. */ return PrintAddressWithModuleName(address, has_module_name, module_name, base_address); } } #endif void KDebug::PrintBacktrace(KThread *thread) { #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) { /* Treat no thread as current thread. */ if (thread == nullptr) { thread = GetCurrentThreadPointer(); } /* Get the exception context. */ KExceptionContext *e_ctx = GetExceptionContext(thread); /* Get the owner process. */ if (auto *process = thread->GetOwnerProcess(); process != nullptr) { /* Lock the owner process. */ KScopedLightLock state_lk(process->GetStateLock()); KScopedLightLock list_lk(process->GetListLock()); /* Suspend all the process's threads. */ { KScopedSchedulerLock sl; auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { if (std::addressof(*it) != GetCurrentThreadPointer()) { it->RequestSuspend(KThread::SuspendType_Backtrace); } } } /* Print the backtrace. */ MESOSPHERE_RELEASE_LOG("User Backtrace\n"); if ((e_ctx->psr & 0x10) == 0) { /* 64-bit thread. */ PrintCodeAddress(process, e_ctx->pc, false); PrintCodeAddress(process, e_ctx->x[30]); /* Walk the stack frames. */ uintptr_t fp = static_cast<uintptr_t>(e_ctx->x[29]); for (auto i = 0; i < 0x20 && fp != 0 && util::IsAligned(fp, 0x10); ++i) { /* Read the next frame. */ struct { u64 fp; u64 lr; } stack_frame; { KMemoryInfo mem_info; ams::svc::PageInfo page_info; KPhysicalAddress phys_addr; if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), fp))) { break; } if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { break; } if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { break; } if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { break; } if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), fp)) { break; } if (!IsHeapPhysicalAddress(phys_addr)) { break; } u64 *frame_ptr = GetPointer<u64>(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); stack_frame.fp = frame_ptr[0]; stack_frame.lr = frame_ptr[1]; } /* Print and advance. */ PrintCodeAddress(process, stack_frame.lr); fp = stack_frame.fp; } } else { /* 32-bit thread. */ PrintCodeAddress(process, e_ctx->pc, false); PrintCodeAddress(process, e_ctx->x[14]); /* Walk the stack frames. */ uintptr_t fp = static_cast<uintptr_t>(e_ctx->x[11]); for (auto i = 0; i < 0x20 && fp != 0 && util::IsAligned(fp, 4); ++i) { /* Read the next frame. */ struct { u32 fp; u32 lr; } stack_frame; { KMemoryInfo mem_info; ams::svc::PageInfo page_info; KPhysicalAddress phys_addr; /* Read FP */ if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), fp))) { break; } if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { break; } if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { break; } if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { break; } if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), fp)) { break; } if (!IsHeapPhysicalAddress(phys_addr)) { break; } stack_frame.fp = *GetPointer<u32>(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); /* Read LR. */ uintptr_t lr_ptr = (e_ctx->x[13] <= stack_frame.fp && stack_frame.fp < e_ctx->x[13] + PageSize) ? fp + 4 : fp - 4; if (R_FAILED(process->GetPageTable().QueryInfo(std::addressof(mem_info), std::addressof(page_info), lr_ptr))) { break; } if ((mem_info.GetState() & KMemoryState_FlagReferenceCounted) == 0) { break; } if ((mem_info.GetAttribute() & KMemoryAttribute_Uncached) != 0) { break; } if ((mem_info.GetPermission() & KMemoryPermission_UserRead) != KMemoryPermission_UserRead) { break; } if (!process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), lr_ptr)) { break; } if (!IsHeapPhysicalAddress(phys_addr)) { break; } stack_frame.lr = *GetPointer<u32>(process->GetPageTable().GetHeapVirtualAddress(phys_addr)); } /* Print and advance. */ PrintCodeAddress(process, stack_frame.lr); fp = stack_frame.fp; } } /* Resume the threads that we suspended. */ { KScopedSchedulerLock sl; auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { if (std::addressof(*it) != GetCurrentThreadPointer()) { it->Resume(KThread::SuspendType_Backtrace); } } } } } #else MESOSPHERE_UNUSED(thread); #endif } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_hardware_timer.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { void KHardwareTimer::Initialize() { /* Setup the global timer for the core. */ InitializeGlobalTimer(); /* Set maximum time. */ m_maximum_time = static_cast<s64>(std::min<u64>(std::numeric_limits<s64>::max(), cpu::CounterTimerPhysicalTimerCompareValueRegisterAccessor().GetCompareValue())); /* Bind the interrupt task for this core. */ MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(this, KInterruptName_NonSecurePhysicalTimer, GetCurrentCoreId(), KInterruptController::PriorityLevel_Timer, true, true)); } void KHardwareTimer::Finalize() { /* Stop the hardware timer. */ StopTimer(); } void KHardwareTimer::DoTask() { /* Handle the interrupt. */ { KScopedSchedulerLock slk; KScopedSpinLock lk(this->GetLock()); /* Disable the timer interrupt while we handle this. */ DisableInterrupt(); if (const s64 next_time = this->DoInterruptTaskImpl(GetTick()); 0 < next_time && next_time <= m_maximum_time) { /* We have a next time, so we should set the time to interrupt and turn the interrupt on. */ SetCompareValue(next_time); EnableInterrupt(); } } /* Clear the timer interrupt. */ Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_NonSecurePhysicalTimer, GetCurrentCoreId()); } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_controller.board.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> /* Include the common implementation. */ #include "../arm/kern_generic_interrupt_controller.inc" ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_interrupt_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { void KInterruptManager::Initialize(s32 core_id) { m_interrupt_controller.Initialize(core_id); } void KInterruptManager::Finalize(s32 core_id) { m_interrupt_controller.Finalize(core_id); } void KInterruptManager::Save(s32 core_id) { /* Verify core id. */ MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* If on core 0, save the global interrupts. */ if (core_id == 0) { MESOSPHERE_ABORT_UNLESS(!m_global_state_saved); m_interrupt_controller.SaveGlobal(std::addressof(m_global_state)); m_global_state_saved = true; } /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Save all local interrupts. */ MESOSPHERE_ABORT_UNLESS(!m_local_state_saved[core_id]); m_interrupt_controller.SaveCoreLocal(std::addressof(m_local_states[core_id])); m_local_state_saved[core_id] = true; /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Finalize all cores other than core 0. */ if (core_id != 0) { this->Finalize(core_id); } /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Finalize core 0. */ if (core_id == 0) { this->Finalize(core_id); } } void KInterruptManager::Restore(s32 core_id) { /* Verify core id. */ MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Initialize core 0. */ if (core_id == 0) { this->Initialize(core_id); } /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Initialize all cores other than core 0. */ if (core_id != 0) { this->Initialize(core_id); } /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Restore all local interrupts. */ MESOSPHERE_ASSERT(m_local_state_saved[core_id]); m_interrupt_controller.RestoreCoreLocal(std::addressof(m_local_states[core_id])); m_local_state_saved[core_id] = false; /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* If on core 0, restore the global interrupts. */ if (core_id == 0) { MESOSPHERE_ASSERT(m_global_state_saved); m_interrupt_controller.RestoreGlobal(std::addressof(m_global_state)); m_global_state_saved = false; } /* Ensure all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); } bool KInterruptManager::OnHandleInterrupt() { /* Get the interrupt id. */ const u32 raw_irq = m_interrupt_controller.GetIrq(); const s32 irq = KInterruptController::ConvertRawIrq(raw_irq); /* Trace the interrupt. */ MESOSPHERE_KTRACE_INTERRUPT(irq); /* If the IRQ is spurious, we don't need to reschedule. */ if (irq < 0) { return false; } KInterruptTask *task = nullptr; if (KInterruptController::IsLocal(irq)) { /* Get local interrupt entry. */ auto &entry = GetLocalInterruptEntry(irq); if (entry.handler != nullptr) { /* Set manual clear needed if relevant. */ if (entry.manually_cleared) { m_interrupt_controller.Disable(irq); entry.needs_clear = true; } /* Set the handler. */ task = entry.handler->OnInterrupt(irq); } else { MESOSPHERE_LOG("Core%d: Unhandled local interrupt %d\n", GetCurrentCoreId(), irq); } } else if (KInterruptController::IsGlobal(irq)) { KScopedSpinLock lk(this->GetGlobalInterruptLock()); /* Get global interrupt entry. */ auto &entry = GetGlobalInterruptEntry(irq); if (entry.handler != nullptr) { /* Set manual clear needed if relevant. */ if (entry.manually_cleared) { m_interrupt_controller.Disable(irq); entry.needs_clear = true; } /* Set the handler. */ task = entry.handler->OnInterrupt(irq); } else { MESOSPHERE_LOG("Core%d: Unhandled global interrupt %d\n", GetCurrentCoreId(), irq); } } else { MESOSPHERE_LOG("Invalid interrupt %d\n", irq); } /* Acknowledge the interrupt. */ m_interrupt_controller.EndOfInterrupt(raw_irq); /* If we found no task, then we don't need to reschedule. */ if (task == nullptr) { return false; } /* If the task isn't the dummy task, we should add it to the queue. */ if (task != GetDummyInterruptTask()) { Kernel::GetInterruptTaskManager().EnqueueTask(task); } return true; } void KInterruptManager::HandleInterrupt(bool user_mode) { /* On interrupt, call OnHandleInterrupt() to determine if we need rescheduling and handle. */ const bool needs_scheduling = Kernel::GetInterruptManager().OnHandleInterrupt(); /* If we need scheduling, */ if (needs_scheduling) { if (user_mode) { /* If the interrupt occurred in the middle of a userland cache maintenance operation, ensure memory consistency before rescheduling. */ if (GetCurrentThread().IsInUserCacheMaintenanceOperation()) { cpu::DataSynchronizationBarrier(); } /* If the user disable count is set, we may need to pin the current thread. */ if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) { KScopedSchedulerLock sl; /* Pin the current thread. */ GetCurrentProcess().PinCurrentThread(); /* Set the interrupt flag for the thread. */ GetCurrentThread().SetInterruptFlag(); /* Request interrupt scheduling. */ Kernel::GetScheduler().RequestScheduleOnInterrupt(); } else { /* Request interrupt scheduling. */ Kernel::GetScheduler().RequestScheduleOnInterrupt(); } } else { /* If the interrupt occurred in the middle of a cache maintenance operation, ensure memory consistency before rescheduling. */ if (GetCurrentThread().IsInCacheMaintenanceOperation()) { cpu::DataSynchronizationBarrier(); } else if (GetCurrentThread().IsInTlbMaintenanceOperation()) { /* Otherwise, if we're in the middle of a tlb maintenance operation, ensure inner shareable memory consistency before rescheduling. */ cpu::DataSynchronizationBarrierInnerShareable(); } /* Request interrupt scheduling. */ Kernel::GetScheduler().RequestScheduleOnInterrupt(); } } /* If user mode, check if the thread needs termination. */ /* If it does, we can take advantage of this to terminate it. */ if (user_mode) { KThread *cur_thread = GetCurrentThreadPointer(); if (cur_thread->IsTerminationRequested()) { EnableInterrupts(); cur_thread->Exit(); } } } Result KInterruptManager::BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level) { MESOSPHERE_UNUSED(core_id); R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange()); if (KInterruptController::IsGlobal(irq)) { KScopedInterruptDisable di; KScopedSpinLock lk(this->GetGlobalInterruptLock()); R_RETURN(this->BindGlobal(handler, irq, core_id, priority, manual_clear, level)); } else { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); KScopedInterruptDisable di; R_RETURN(this->BindLocal(handler, irq, priority, manual_clear)); } } void KInterruptManager::UnbindHandler(s32 irq, s32 core_id) { MESOSPHERE_UNUSED(core_id); MESOSPHERE_ASSERT(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq)); if (KInterruptController::IsGlobal(irq)) { KScopedInterruptDisable di; KScopedSpinLock lk(this->GetGlobalInterruptLock()); return this->UnbindGlobal(irq); } else if (KInterruptController::IsLocal(irq)) { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); KScopedInterruptDisable di; return this->UnbindLocal(irq); } } void KInterruptManager::ClearInterrupt(s32 irq, s32 core_id) { MESOSPHERE_UNUSED(core_id); MESOSPHERE_ASSERT(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq)); if (KInterruptController::IsGlobal(irq)) { KScopedInterruptDisable di; KScopedSpinLock lk(this->GetGlobalInterruptLock()); return this->ClearGlobal(irq); } else if (KInterruptController::IsLocal(irq)) { MESOSPHERE_ASSERT(core_id == GetCurrentCoreId()); KScopedInterruptDisable di; return this->ClearLocal(irq); } } Result KInterruptManager::BindGlobal(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level) { /* Ensure the priority level is valid. */ R_UNLESS(KInterruptController::PriorityLevel_High <= priority, svc::ResultOutOfRange()); R_UNLESS(priority <= KInterruptController::PriorityLevel_Low, svc::ResultOutOfRange()); /* Ensure we aren't already bound. */ auto &entry = GetGlobalInterruptEntry(irq); R_UNLESS(entry.handler == nullptr, svc::ResultBusy()); /* Set entry fields. */ entry.needs_clear = false; entry.manually_cleared = manual_clear; entry.handler = handler; /* Configure the interrupt as level or edge. */ if (level) { m_interrupt_controller.SetLevel(irq); } else { m_interrupt_controller.SetEdge(irq); } /* Configure the interrupt. */ m_interrupt_controller.Clear(irq); m_interrupt_controller.SetTarget(irq, core_id); m_interrupt_controller.SetPriorityLevel(irq, priority); m_interrupt_controller.Enable(irq); R_SUCCEED(); } Result KInterruptManager::BindLocal(KInterruptHandler *handler, s32 irq, s32 priority, bool manual_clear) { /* Ensure the priority level is valid. */ R_UNLESS(KInterruptController::PriorityLevel_High <= priority, svc::ResultOutOfRange()); R_UNLESS(priority <= KInterruptController::PriorityLevel_Low, svc::ResultOutOfRange()); /* Ensure we aren't already bound. */ auto &entry = this->GetLocalInterruptEntry(irq); R_UNLESS(entry.handler == nullptr, svc::ResultBusy()); /* Set entry fields. */ entry.needs_clear = false; entry.manually_cleared = manual_clear; entry.handler = handler; entry.priority = static_cast<u8>(priority); /* Configure the interrupt. */ m_interrupt_controller.Clear(irq); m_interrupt_controller.SetPriorityLevel(irq, priority); m_interrupt_controller.Enable(irq); R_SUCCEED(); } void KInterruptManager::UnbindGlobal(s32 irq) { for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) { m_interrupt_controller.ClearTarget(irq, static_cast<s32>(core_id)); } m_interrupt_controller.SetPriorityLevel(irq, KInterruptController::PriorityLevel_Low); m_interrupt_controller.Disable(irq); GetGlobalInterruptEntry(irq).handler = nullptr; } void KInterruptManager::UnbindLocal(s32 irq) { m_interrupt_controller.SetPriorityLevel(irq, KInterruptController::PriorityLevel_Low); m_interrupt_controller.Disable(irq); this->GetLocalInterruptEntry(irq).handler = nullptr; } void KInterruptManager::ClearGlobal(s32 irq) { /* Get the entry. */ auto &entry = GetGlobalInterruptEntry(irq); /* If not auto-cleared, clear and enable. */ if (entry.manually_cleared && entry.needs_clear) { entry.needs_clear = false; m_interrupt_controller.Enable(irq); } } void KInterruptManager::ClearLocal(s32 irq) { /* Get the entry. */ auto &entry = this->GetLocalInterruptEntry(irq); /* If not auto-cleared, clear and enable. */ if (entry.manually_cleared && entry.needs_clear) { entry.needs_clear = false; m_interrupt_controller.Enable(irq); } } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_page_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { namespace { class AlignedMemoryBlock { private: uintptr_t m_before_start; uintptr_t m_before_end; uintptr_t m_after_start; uintptr_t m_after_end; size_t m_current_alignment; public: constexpr AlignedMemoryBlock(uintptr_t start, size_t num_pages, size_t alignment) : m_before_start(0), m_before_end(0), m_after_start(0), m_after_end(0), m_current_alignment(0) { MESOSPHERE_ASSERT(util::IsAligned(start, PageSize)); MESOSPHERE_ASSERT(num_pages > 0); /* Find an alignment that allows us to divide into at least two regions.*/ uintptr_t start_page = start / PageSize; alignment /= PageSize; while (util::AlignUp(start_page, alignment) >= util::AlignDown(start_page + num_pages, alignment)) { alignment = KPageTable::GetSmallerAlignment(alignment * PageSize) / PageSize; } m_before_start = start_page; m_before_end = util::AlignUp(start_page, alignment); m_after_start = m_before_end; m_after_end = start_page + num_pages; m_current_alignment = alignment; MESOSPHERE_ASSERT(m_current_alignment > 0); } constexpr void SetAlignment(size_t alignment) { /* We can only ever decrease the granularity. */ MESOSPHERE_ASSERT(m_current_alignment >= alignment / PageSize); m_current_alignment = alignment / PageSize; } constexpr size_t GetAlignment() const { return m_current_alignment * PageSize; } constexpr void FindBlock(uintptr_t &out, size_t &num_pages) { if ((m_after_end - m_after_start) >= m_current_alignment) { /* Select aligned memory from after block. */ const size_t available_pages = util::AlignDown(m_after_end, m_current_alignment) - m_after_start; if (num_pages == 0 || available_pages < num_pages) { num_pages = available_pages; } out = m_after_start * PageSize; m_after_start += num_pages; } else if ((m_before_end - m_before_start) >= m_current_alignment) { /* Select aligned memory from before block. */ const size_t available_pages = m_before_end - util::AlignUp(m_before_start, m_current_alignment); if (num_pages == 0 || available_pages < num_pages) { num_pages = available_pages; } m_before_end -= num_pages; out = m_before_end * PageSize; } else { /* Neither after or before can get an aligned bit of memory. */ out = 0; num_pages = 0; } } }; constexpr u64 EncodeTtbr(KPhysicalAddress table, u8 asid) { return (static_cast<u64>(asid) << 48) | (static_cast<u64>(GetInteger(table))); } } ALWAYS_INLINE void KPageTable::NoteUpdated() const { cpu::DataSynchronizationBarrierInnerShareableStore(); /* Mark ourselves as in a tlb maintenance operation. */ GetCurrentThread().SetInTlbMaintenanceOperation(); ON_SCOPE_EXIT { GetCurrentThread().ClearInTlbMaintenanceOperation(); __asm__ __volatile__("" ::: "memory"); }; if (this->IsKernel()) { this->OnKernelTableUpdated(); } else { this->OnTableUpdated(); } } ALWAYS_INLINE void KPageTable::NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const { MESOSPHERE_ASSERT(this->IsKernel()); cpu::DataSynchronizationBarrierInnerShareableStore(); /* Mark ourselves as in a tlb maintenance operation. */ GetCurrentThread().SetInTlbMaintenanceOperation(); ON_SCOPE_EXIT { GetCurrentThread().ClearInTlbMaintenanceOperation(); __asm__ __volatile__("" ::: "memory"); }; this->OnKernelTableSinglePageUpdated(virt_addr); } void KPageTable::Initialize(s32 core_id) { /* Nothing actually needed here. */ MESOSPHERE_UNUSED(core_id); } void KPageTable::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) { /* Initialize basic fields. */ m_asid = 0; m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer(); /* Initialize the base page table. */ KPageTableBase::InitializeForKernel(true, table, start, end); } Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) { /* Determine our ASID */ m_asid = process_index + 1; MESOSPHERE_ABORT_UNLESS(0 < m_asid && m_asid < util::size(s_ttbr0_entries)); /* Set our manager. */ m_manager = system_resource->GetPageTableManagerPointer(); /* Get the virtual address of our L1 table. */ const KPhysicalAddress ttbr0_phys = KPhysicalAddress(s_ttbr0_entries[m_asid] & UINT64_C(0xFFFFFFFFFFFE)); const KVirtualAddress ttbr0_virt = KMemoryLayout::GetLinearVirtualAddress(ttbr0_phys); /* Initialize our base table. */ const size_t as_width = GetAddressSpaceWidth(flags); const KProcessAddress as_start = 0; const KProcessAddress as_end = (1ul << as_width); R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(ttbr0_virt), as_start, as_end, code_address, code_size, system_resource, resource_limit)); /* Note that we've updated the table (since we created it). */ this->NoteUpdated(); R_SUCCEED(); } void KPageTable::Finalize() { /* Only process tables should be finalized. */ MESOSPHERE_ASSERT(!this->IsKernel()); /* NOTE: Here Nintendo calls an unknown OnFinalize function. */ /* this->OnFinalize(); */ /* Note that we've updated (to ensure we're synchronized). */ this->NoteUpdated(); /* NOTE: Here Nintendo calls a second unknown OnFinalize function. */ /* this->OnFinalize2(); */ /* Free all pages in the table. */ { /* Get implementation objects. */ auto &impl = this->GetImpl(); auto &mm = Kernel::GetMemoryManager(); /* Traverse, freeing all pages. */ { /* Begin the traversal. */ TraversalContext context; TraversalEntry entry; KPhysicalAddress cur_phys_addr = Null<KPhysicalAddress>; size_t cur_size = 0; u8 has_attr = 0; bool cur_valid = impl.BeginTraversal(std::addressof(entry), std::addressof(context), this->GetAddressSpaceStart()); while (true) { if (cur_valid) { /* Free the actual pages, if there are any. */ if (IsHeapPhysicalAddressForFinalize(entry.phys_addr)) { if (cur_size > 0) { /* NOTE: Nintendo really does check next_entry.attr == (cur_entry.attr != 0)...but attr is always zero as of 18.0.0, and this is "probably" for the new console or debug-only anyway, */ /* so we'll implement the weird logic verbatim even though it doesn't match the GetContiguousRange logic. */ if (entry.phys_addr == cur_phys_addr + cur_size && entry.attr == has_attr) { /* Just extend the block, since we can. */ cur_size += entry.block_size; } else { /* Close the block, and begin tracking anew. */ mm.Close(cur_phys_addr, cur_size / PageSize); cur_phys_addr = entry.phys_addr; cur_size = entry.block_size; has_attr = entry.attr != 0; } } else { cur_phys_addr = entry.phys_addr; cur_size = entry.block_size; has_attr = entry.attr != 0; } } /* Clean up the page table entries. */ bool freeing_table = false; while (true) { /* Clear the entries. */ const size_t num_to_clear = (!freeing_table && context.is_contiguous) ? BlocksPerContiguousBlock : 1; auto *pte = reinterpret_cast<PageTableEntry *>(context.is_contiguous ? util::AlignDown(reinterpret_cast<uintptr_t>(context.level_entries[context.level]), BlocksPerContiguousBlock * sizeof(PageTableEntry)) : reinterpret_cast<uintptr_t>(context.level_entries[context.level])); for (size_t i = 0; i < num_to_clear; ++i) { pte[i] = InvalidPageTableEntry; } /* Remove the entries from the previous table. */ if (context.level != KPageTableImpl::EntryLevel_L1) { context.level_entries[context.level + 1]->CloseTableReferences(num_to_clear); } /* If we cleared a table, we need to note that we updated and free the table. */ if (freeing_table) { KVirtualAddress table = KVirtualAddress(util::AlignDown(reinterpret_cast<uintptr_t>(context.level_entries[context.level - 1]), PageSize)); if (table == Null<KVirtualAddress>) { break; } ClearPageTable(table); this->GetPageTableManager().Free(table); } /* Advance; we're no longer contiguous. */ context.is_contiguous = false; context.level_entries[context.level] = pte + num_to_clear - 1; /* We may have removed the last entries in a table, in which case we can free and unmap the tables. */ if (context.level >= KPageTableImpl::EntryLevel_L1 || context.level_entries[context.level + 1]->GetTableReferenceCount() != 0) { break; } /* Advance; we will not be working with blocks any more. */ context.level = static_cast<KPageTableImpl::EntryLevel>(util::ToUnderlying(context.level) + 1); freeing_table = true; } } /* Continue the traversal. */ cur_valid = impl.ContinueTraversal(std::addressof(entry), std::addressof(context)); if (entry.block_size == 0) { break; } } /* Free any remaining pages. */ if (cur_size > 0) { mm.Close(cur_phys_addr, cur_size / PageSize); } } /* Clear the L1 table. */ { const KVirtualAddress l1_table = reinterpret_cast<uintptr_t>(impl.Finalize()); ClearPageTable(l1_table); } /* Perform inherited finalization. */ KPageTableBase::Finalize(); } } Result KPageTable::OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll) { /* Check validity of parameters. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(num_pages > 0); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages)); if (operation == OperationType_Map) { MESOSPHERE_ABORT_UNLESS(is_pa_valid); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); } else { MESOSPHERE_ABORT_UNLESS(!is_pa_valid); } if (operation == OperationType_Unmap) { R_RETURN(this->Unmap(virt_addr, num_pages, page_list, false, reuse_ll)); } else if (operation == OperationType_Separate) { R_RETURN(this->SeparatePages(virt_addr, num_pages, page_list, reuse_ll)); } else { auto entry_template = this->GetEntryTemplate(properties); switch (operation) { case OperationType_Map: /* If mapping io or uncached pages, ensure that there is no pending reschedule. */ if (properties.io || properties.uncached) { KScopedSchedulerLock sl; } R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll)); case OperationType_ChangePermissions: R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll)); case OperationType_ChangePermissionsAndRefresh: R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, false, page_list, reuse_ll)); case OperationType_ChangePermissionsAndRefreshAndFlush: R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, true, page_list, reuse_ll)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } } Result KPageTable::OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, const KPageGroup &page_group, const KPageProperties properties, OperationType operation, bool reuse_ll) { /* Check validity of parameters. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_ASSERT(num_pages > 0); MESOSPHERE_ASSERT(num_pages == page_group.GetNumPages()); /* Map the page group. */ auto entry_template = this->GetEntryTemplate(properties); switch (operation) { case OperationType_MapGroup: case OperationType_MapFirstGroup: /* If mapping io or uncached pages, ensure that there is no pending reschedule. */ if (properties.io || properties.uncached) { KScopedSchedulerLock sl; } R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirstGroup, page_list, reuse_ll)); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } Result KPageTable::Unmap(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool force, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Ensure there are no pending data writes. */ cpu::DataSynchronizationBarrier(); auto &impl = this->GetImpl(); /* If we're not forcing an unmap, separate pages immediately. */ if (!force) { R_TRY(this->SeparatePages(virt_addr, num_pages, page_list, reuse_ll)); } /* Cache initial addresses for use on cleanup. */ const KProcessAddress orig_virt_addr = virt_addr; size_t remaining_pages = num_pages; /* Ensure that any pages we track close on exit. */ KPageGroup pages_to_close(this->GetBlockInfoManager()); ON_SCOPE_EXIT { pages_to_close.CloseAndReset(); }; /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr); while (remaining_pages > 0) { /* Handle the case where we're not valid. */ if (!next_valid) { MESOSPHERE_ABORT_UNLESS(force); const size_t cur_size = std::min(next_entry.block_size - (GetInteger(virt_addr) & (next_entry.block_size - 1)), remaining_pages * PageSize); remaining_pages -= cur_size / PageSize; virt_addr += cur_size; next_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); continue; } /* Handle the case where the block is bigger than it should be. */ if (next_entry.block_size > remaining_pages * PageSize) { MESOSPHERE_ABORT_UNLESS(force); MESOSPHERE_R_ABORT_UNLESS(this->SeparatePagesImpl(std::addressof(next_entry), std::addressof(context), virt_addr, remaining_pages * PageSize, page_list, reuse_ll)); } /* Check that our state is coherent. */ MESOSPHERE_ASSERT((next_entry.block_size / PageSize) <= remaining_pages); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(next_entry.phys_addr), next_entry.block_size)); /* Unmap the block. */ bool freeing_table = false; bool need_recalculate_virt_addr = false; while (true) { /* Clear the entries. */ const size_t num_to_clear = (!freeing_table && context.is_contiguous) ? BlocksPerContiguousBlock : 1; auto *pte = reinterpret_cast<PageTableEntry *>(context.is_contiguous ? util::AlignDown(reinterpret_cast<uintptr_t>(context.level_entries[context.level]), BlocksPerContiguousBlock * sizeof(PageTableEntry)) : reinterpret_cast<uintptr_t>(context.level_entries[context.level])); for (size_t i = 0; i < num_to_clear; ++i) { pte[i] = InvalidPageTableEntry; } /* Remove the entries from the previous table. */ if (context.level != KPageTableImpl::EntryLevel_L1) { context.level_entries[context.level + 1]->CloseTableReferences(num_to_clear); } /* If we cleared a table, we need to note that we updated and free the table. */ if (freeing_table) { /* If there's no table, we also don't need to do a free. */ const KVirtualAddress table = KVirtualAddress(util::AlignDown(reinterpret_cast<uintptr_t>(context.level_entries[context.level - 1]), PageSize)); if (table == Null<KVirtualAddress>) { break; } this->NoteUpdated(); this->FreePageTable(page_list, table); need_recalculate_virt_addr = true; } /* Advance; we're no longer contiguous. */ context.is_contiguous = false; context.level_entries[context.level] = pte + num_to_clear - 1; /* We may have removed the last entries in a table, in which case we can free and unmap the tables. */ if (context.level >= KPageTableImpl::EntryLevel_L1 || context.level_entries[context.level + 1]->GetTableReferenceCount() != 0) { break; } /* Advance; we will not be working with blocks any more. */ context.level = static_cast<KPageTableImpl::EntryLevel>(util::ToUnderlying(context.level) + 1); freeing_table = true; } /* Close the blocks. */ if (!force && IsHeapPhysicalAddress(next_entry.phys_addr)) { const size_t block_num_pages = next_entry.block_size / PageSize; if (R_FAILED(pages_to_close.AddBlock(next_entry.phys_addr, block_num_pages))) { this->NoteUpdated(); Kernel::GetMemoryManager().Close(next_entry.phys_addr, block_num_pages); pages_to_close.CloseAndReset(); } } /* Advance. */ size_t freed_size = next_entry.block_size; if (need_recalculate_virt_addr) { /* We advanced more than by the block, so we need to calculate the actual advanced size. */ const size_t block_size = impl.GetBlockSize(context.level, context.is_contiguous); const KProcessAddress new_virt_addr = util::AlignDown(GetInteger(impl.GetAddressForContext(std::addressof(context))) + block_size, block_size); MESOSPHERE_ABORT_UNLESS(new_virt_addr >= virt_addr + next_entry.block_size); freed_size = std::min<size_t>(new_virt_addr - virt_addr, remaining_pages * PageSize); } /* We can just advance by the block size. */ virt_addr += freed_size; remaining_pages -= freed_size / PageSize; next_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); } /* Ensure we remain coherent. */ if (this->IsKernel() && num_pages == 1) { this->NoteSingleKernelPageUpdated(orig_virt_addr); } else { this->NoteUpdated(); } R_SUCCEED(); } Result KPageTable::Map(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, size_t page_size, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); auto &impl = this->GetImpl(); u8 sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(disable_head_merge, false, false); /* Begin traversal. */ TraversalContext context; TraversalEntry entry; bool valid = impl.BeginTraversal(std::addressof(entry), std::addressof(context), virt_addr); /* Iterate, mapping each page. */ while (num_pages > 0) { /* If we're mapping at the address, there must be nothing there. */ MESOSPHERE_ABORT_UNLESS(!valid); /* If we fail, clean up any empty tables we may have allocated. */ ON_RESULT_FAILURE { /* Remove entries for and free any tables. */ while (context.level < KPageTableImpl::EntryLevel_L1) { /* If the higher-level table has entries, we don't need to do a free. */ if (context.level_entries[context.level + 1]->GetTableReferenceCount() != 0) { break; } /* If there's no table, we also don't need to do a free. */ const KVirtualAddress table = KVirtualAddress(util::AlignDown(reinterpret_cast<uintptr_t>(context.level_entries[context.level]), PageSize)); if (table == Null<KVirtualAddress>) { break; } /* Clear the entry for the table we're removing. */ *context.level_entries[context.level + 1] = InvalidPageTableEntry; /* Remove the entry for the table one level higher. */ if (context.level + 1 < KPageTableImpl::EntryLevel_L1) { context.level_entries[context.level + 2]->CloseTableReferences(1); } /* Advance our level. */ context.level = static_cast<KPageTableImpl::EntryLevel>(util::ToUnderlying(context.level) + 1); /* Note that we performed an update and free the table. */ this->NoteUpdated(); this->FreePageTable(page_list, table); } }; /* If necessary, allocate page tables for the entry. */ size_t mapping_size = entry.block_size; while (mapping_size > page_size) { /* Allocate the table. */ const auto table = AllocatePageTable(page_list, reuse_ll); R_UNLESS(table != Null<KVirtualAddress>, svc::ResultOutOfResource()); /* Wait for pending stores to complete. */ cpu::DataSynchronizationBarrierInnerShareableStore(); /* Update the block entry to be a table entry. */ *context.level_entries[context.level] = PageTableEntry(PageTableEntry::TableTag{}, KPageTable::GetPageTablePhysicalAddress(table), this->IsKernel(), true, 0); /* Add the entry to the table containing this one. */ if (context.level != KPageTableImpl::EntryLevel_L1) { context.level_entries[context.level + 1]->OpenTableReferences(1); } /* Decrease our level. */ context.level = static_cast<KPageTableImpl::EntryLevel>(util::ToUnderlying(context.level) - 1); /* Add our new entry to the context. */ context.level_entries[context.level] = GetPointer<PageTableEntry>(table) + impl.GetLevelIndex(virt_addr, context.level); /* Update our mapping size. */ mapping_size = impl.GetBlockSize(context.level); } /* Determine how many pages we can set up on this iteration. */ const size_t block_size = impl.GetBlockSize(context.level); const size_t max_ptes = (context.level == KPageTableImpl::EntryLevel_L1 ? impl.GetNumL1Entries() : BlocksPerTable) - ((reinterpret_cast<uintptr_t>(context.level_entries[context.level]) / sizeof(PageTableEntry)) & (BlocksPerTable - 1)); const size_t max_pages = (block_size * max_ptes) / PageSize; const size_t cur_pages = std::min(max_pages, num_pages); /* Determine the new base attribute. */ const bool contig = page_size >= BlocksPerContiguousBlock * mapping_size; const size_t num_ptes = cur_pages / (block_size / PageSize); auto *pte = context.level_entries[context.level]; for (size_t i = 0; i < num_ptes; ++i) { pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, phys_addr + i * block_size, entry_template, sw_reserved_bits, contig, context.level == KPageTableImpl::EntryLevel_L3); sw_reserved_bits &= ~(PageTableEntry::SoftwareReservedBit_DisableMergeHead); } /* Add the entries to the table containing this one. */ if (context.level != KPageTableImpl::EntryLevel_L1) { context.level_entries[context.level + 1]->OpenTableReferences(num_ptes); } /* Update our context. */ context.is_contiguous = contig; context.level_entries[context.level] = pte + num_ptes - (contig ? BlocksPerContiguousBlock : 1); /* Advance our addresses. */ phys_addr += cur_pages * PageSize; virt_addr += cur_pages * PageSize; num_pages -= cur_pages; /* Continue traversal. */ valid = impl.ContinueTraversal(std::addressof(entry), std::addressof(context)); } /* We mapped, so wait for our writes to take. */ cpu::DataSynchronizationBarrierInnerShareableStore(); R_SUCCEED(); } Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Cache initial addresses for use on cleanup. */ const KProcessAddress orig_virt_addr = virt_addr; const KPhysicalAddress orig_phys_addr = phys_addr; size_t remaining_pages = num_pages; /* Map the pages, using a guard to ensure we don't leak. */ { ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(this->Unmap(orig_virt_addr, num_pages, page_list, true, true)); }; if (num_pages < ContiguousPageSize / PageSize) { R_TRY(this->Map(virt_addr, phys_addr, num_pages, entry_template, disable_head_merge && virt_addr == orig_virt_addr, L3BlockSize, page_list, reuse_ll)); remaining_pages -= num_pages; virt_addr += num_pages * PageSize; phys_addr += num_pages * PageSize; } else { /* Map the fractional part of the pages. */ size_t alignment; for (alignment = ContiguousPageSize; (virt_addr & (alignment - 1)) == (phys_addr & (alignment - 1)); alignment = GetLargerAlignment(alignment)) { /* Check if this would be our last map. */ const size_t pages_to_map = ((alignment - (virt_addr & (alignment - 1))) & (alignment - 1)) / PageSize; if (pages_to_map + (alignment / PageSize) > remaining_pages) { break; } /* Map pages, if we should. */ if (pages_to_map > 0) { R_TRY(this->Map(virt_addr, phys_addr, pages_to_map, entry_template, disable_head_merge && virt_addr == orig_virt_addr, GetSmallerAlignment(alignment), page_list, reuse_ll)); remaining_pages -= pages_to_map; virt_addr += pages_to_map * PageSize; phys_addr += pages_to_map * PageSize; } /* Don't go further than L1 block. */ if (alignment == L1BlockSize) { break; } } while (remaining_pages > 0) { /* Select the next smallest alignment. */ alignment = GetSmallerAlignment(alignment); MESOSPHERE_ASSERT((virt_addr & (alignment - 1)) == 0); MESOSPHERE_ASSERT((phys_addr & (alignment - 1)) == 0); /* Map pages, if we should. */ const size_t pages_to_map = util::AlignDown(remaining_pages, alignment / PageSize); if (pages_to_map > 0) { R_TRY(this->Map(virt_addr, phys_addr, pages_to_map, entry_template, disable_head_merge && virt_addr == orig_virt_addr, alignment, page_list, reuse_ll)); remaining_pages -= pages_to_map; virt_addr += pages_to_map * PageSize; phys_addr += pages_to_map * PageSize; } } } } /* Perform what coalescing we can. */ this->MergePages(orig_virt_addr, num_pages, page_list); /* Open references to the pages, if we should. */ if (IsHeapPhysicalAddress(orig_phys_addr)) { Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages); } R_SUCCEED(); } Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* We want to maintain a new reference to every page in the group. */ KScopedPageGroup spg(pg, not_first); /* Cache initial address for use on cleanup. */ const KProcessAddress orig_virt_addr = virt_addr; size_t mapped_pages = 0; /* Map the pages, using a guard to ensure we don't leak. */ { ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(this->Unmap(orig_virt_addr, num_pages, page_list, true, true)); }; if (num_pages < ContiguousPageSize / PageSize) { for (const auto &block : pg) { const KPhysicalAddress block_phys_addr = block.GetAddress(); const size_t cur_pages = block.GetNumPages(); R_TRY(this->Map(virt_addr, block_phys_addr, cur_pages, entry_template, disable_head_merge && virt_addr == orig_virt_addr, L3BlockSize, page_list, reuse_ll)); virt_addr += cur_pages * PageSize; mapped_pages += cur_pages; } } else { /* Create a block representing our virtual space. */ AlignedMemoryBlock virt_block(GetInteger(virt_addr), num_pages, L1BlockSize); for (const auto &block : pg) { /* Create a block representing this physical group, synchronize its alignment to our virtual block. */ const KPhysicalAddress block_phys_addr = block.GetAddress(); size_t cur_pages = block.GetNumPages(); AlignedMemoryBlock phys_block(GetInteger(block_phys_addr), cur_pages, virt_block.GetAlignment()); virt_block.SetAlignment(phys_block.GetAlignment()); while (cur_pages > 0) { /* Find a physical region for us to map at. */ uintptr_t phys_choice = 0; size_t phys_pages = 0; phys_block.FindBlock(phys_choice, phys_pages); /* If we didn't find a region, try decreasing our alignment. */ if (phys_pages == 0) { const size_t next_alignment = KPageTable::GetSmallerAlignment(phys_block.GetAlignment()); MESOSPHERE_ASSERT(next_alignment >= PageSize); phys_block.SetAlignment(next_alignment); virt_block.SetAlignment(next_alignment); continue; } /* Begin choosing virtual blocks to map at the region we chose. */ while (phys_pages > 0) { /* Find a virtual region for us to map at. */ uintptr_t virt_choice = 0; size_t virt_pages = phys_pages; virt_block.FindBlock(virt_choice, virt_pages); /* If we didn't find a region, try decreasing our alignment. */ if (virt_pages == 0) { const size_t next_alignment = KPageTable::GetSmallerAlignment(virt_block.GetAlignment()); MESOSPHERE_ASSERT(next_alignment >= PageSize); phys_block.SetAlignment(next_alignment); virt_block.SetAlignment(next_alignment); continue; } /* Map! */ R_TRY(this->Map(virt_choice, phys_choice, virt_pages, entry_template, disable_head_merge && virt_addr == orig_virt_addr, virt_block.GetAlignment(), page_list, reuse_ll)); /* Advance. */ phys_choice += virt_pages * PageSize; phys_pages -= virt_pages; cur_pages -= virt_pages; mapped_pages += virt_pages; } } } } } MESOSPHERE_ASSERT(mapped_pages == num_pages); /* Perform what coalescing we can. */ this->MergePages(orig_virt_addr, num_pages, page_list); /* We succeeded! We want to persist the reference to the pages. */ spg.CancelClose(); R_SUCCEED(); } bool KPageTable::MergePages(TraversalContext *context, PageLinkedList *page_list) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); auto &impl = this->GetImpl(); /* Iteratively merge, until we can't. */ bool merged = false; while (true) { /* Try to merge. */ KVirtualAddress freed_table = Null<KVirtualAddress>; if (!impl.MergePages(std::addressof(freed_table), context, &KPageTable::NoteUpdatedCallback, this)) { break; } /* Free the page. */ if (freed_table != Null<KVirtualAddress>) { ClearPageTable(freed_table); this->FreePageTable(page_list, freed_table); } /* We performed at least one merge. */ merged = true; } return merged; } void KPageTable::MergePages(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry entry; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(entry), std::addressof(context), virt_addr)); /* Merge start of the range. */ this->MergePages(std::addressof(context), page_list); /* If we have more than one page, do the same for the end of the range. */ if (num_pages > 1) { /* Begin traversal for end of range. */ const size_t size = num_pages * PageSize; const auto end_page = virt_addr + size; const auto last_page = end_page - PageSize; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(entry), std::addressof(context), last_page)); /* Merge. */ this->MergePages(std::addressof(context), page_list); } } Result KPageTable::SeparatePagesImpl(TraversalEntry *entry, TraversalContext *context, KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); auto &impl = this->GetImpl(); /* If at any point we fail, we want to merge. */ ON_RESULT_FAILURE { this->MergePages(context, page_list); }; /* Iterate, separating until our block size is small enough. */ while (entry->block_size > block_size) { /* If necessary, allocate a table. */ KVirtualAddress table = Null<KVirtualAddress>; if (!context->is_contiguous) { table = this->AllocatePageTable(page_list, reuse_ll); R_UNLESS(table != Null<KVirtualAddress>, svc::ResultOutOfResource()); } /* Separate. */ impl.SeparatePages(entry, context, virt_addr, GetPointer<PageTableEntry>(table), &KPageTable::NoteUpdatedCallback, this); } R_SUCCEED(); } Result KPageTable::SeparatePages(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext start_context; TraversalEntry entry; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(entry), std::addressof(start_context), virt_addr)); /* Separate pages at the start of the range. */ const size_t size = num_pages * PageSize; R_TRY(this->SeparatePagesImpl(std::addressof(entry), std::addressof(start_context), virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll)); /* If necessary, separate pages at the end of the range. */ if (num_pages > 1) { const auto end_page = virt_addr + size; const auto last_page = end_page - PageSize; /* Begin traversal. */ TraversalContext end_context; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(entry), std::addressof(end_context), last_page)); ON_RESULT_FAILURE { this->MergePages(std::addressof(start_context), page_list); }; R_TRY(this->SeparatePagesImpl(std::addressof(entry), std::addressof(end_context), last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll)); } R_SUCCEED(); } Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Ensure there are no pending data writes. */ cpu::DataSynchronizationBarrier(); /* Separate pages before we change permissions. */ R_TRY(this->SeparatePages(virt_addr, num_pages, page_list, reuse_ll)); /* ===================================================== */ /* Define a helper function which will apply our template to entries. */ enum ApplyOption : u32 { ApplyOption_None = 0, ApplyOption_FlushDataCache = (1u << 0), ApplyOption_MergeMappings = (1u << 1), }; auto ApplyEntryTemplate = [this, virt_addr, disable_merge_attr, num_pages, page_list](PageTableEntry entry_template, u32 apply_option) -> void { /* Create work variables for us to use. */ const KProcessAddress orig_virt_addr = virt_addr; const KProcessAddress end_virt_addr = orig_virt_addr + (num_pages * PageSize); KProcessAddress cur_virt_addr = virt_addr; size_t remaining_pages = num_pages; auto &impl = this->GetImpl(); /* Parse the disable merge attrs. */ const bool attr_disable_head = (disable_merge_attr & DisableMergeAttribute_DisableHead) != 0; const bool attr_disable_head_body = (disable_merge_attr & DisableMergeAttribute_DisableHeadAndBody) != 0; const bool attr_enable_head_body = (disable_merge_attr & DisableMergeAttribute_EnableHeadAndBody) != 0; const bool attr_disable_tail = (disable_merge_attr & DisableMergeAttribute_DisableTail) != 0; const bool attr_enable_tail = (disable_merge_attr & DisableMergeAttribute_EnableTail) != 0; const bool attr_enable_and_merge = (disable_merge_attr & DisableMergeAttribute_EnableAndMergeHeadBodyTail) != 0; /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), cur_virt_addr)); /* Continue changing properties until we've changed them for all pages. */ bool cleared_disable_merge_bits = false; while (remaining_pages > 0) { MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(next_entry.phys_addr), next_entry.block_size)); MESOSPHERE_ABORT_UNLESS(next_entry.block_size <= remaining_pages * PageSize); /* Determine if we're at the start. */ const bool is_start = (cur_virt_addr == orig_virt_addr); const bool is_end = ((cur_virt_addr + next_entry.block_size) == end_virt_addr); /* Determine the relevant merge attributes. */ bool disable_head_merge, disable_head_body_merge, disable_tail_merge; if (next_entry.IsHeadMergeDisabled()) { disable_head_merge = true; } else if (attr_disable_head) { disable_head_merge = is_start; } else { disable_head_merge = false; } if (is_start) { if (attr_disable_head_body) { disable_head_body_merge = true; } else if (attr_enable_head_body) { disable_head_body_merge = false; } else { disable_head_body_merge = (!attr_enable_and_merge && next_entry.IsHeadAndBodyMergeDisabled()); } } else { disable_head_body_merge = (!attr_enable_and_merge && next_entry.IsHeadAndBodyMergeDisabled()); cleared_disable_merge_bits |= (attr_enable_and_merge && next_entry.IsHeadAndBodyMergeDisabled()); } if (is_end) { if (attr_disable_tail) { disable_tail_merge = true; } else if (attr_enable_tail) { disable_tail_merge = false; } else { disable_tail_merge = (!attr_enable_and_merge && next_entry.IsTailMergeDisabled()); } } else { disable_tail_merge = (!attr_enable_and_merge && next_entry.IsTailMergeDisabled()); cleared_disable_merge_bits |= (attr_enable_and_merge && next_entry.IsTailMergeDisabled()); } /* Encode the merge disable flags into the software reserved bits. */ u8 sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(disable_head_merge, disable_head_body_merge, disable_tail_merge); /* If we should flush entries, do so. */ if ((apply_option & ApplyOption_FlushDataCache) != 0) { if (IsHeapPhysicalAddress(next_entry.phys_addr)) { MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(GetHeapVirtualAddress(next_entry.phys_addr)), next_entry.block_size)); } } /* Apply the entry template. */ { const size_t num_entries = context.is_contiguous ? BlocksPerContiguousBlock : 1; auto * const pte = context.level_entries[context.level]; const size_t block_size = impl.GetBlockSize(context.level); for (size_t i = 0; i < num_entries; ++i) { pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, next_entry.phys_addr + i * block_size, entry_template, sw_reserved_bits, context.is_contiguous, context.level == KPageTableImpl::EntryLevel_L3); sw_reserved_bits &= ~(PageTableEntry::SoftwareReservedBit_DisableMergeHead); } } /* If our option asks us to, try to merge mappings. */ bool merge = ((apply_option & ApplyOption_MergeMappings) != 0 || cleared_disable_merge_bits) && next_entry.block_size < L1BlockSize; if (merge) { const size_t larger_align = GetLargerAlignment(next_entry.block_size); if (util::IsAligned(GetInteger(cur_virt_addr) + next_entry.block_size, larger_align)) { const uintptr_t aligned_start = util::AlignDown(GetInteger(cur_virt_addr), larger_align); if (orig_virt_addr <= aligned_start && aligned_start + larger_align - 1 < GetInteger(orig_virt_addr) + (num_pages * PageSize) - 1) { merge = this->MergePages(std::addressof(context), page_list); } else { merge = false; } } else { merge = false; } } /* If we merged, correct the traversal to a sane state. */ if (merge) { /* NOTE: Begin a new traversal, now that we've merged. */ MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), cur_virt_addr)); /* The actual size needs to not take into account the portion of the block before our virtual address. */ const size_t actual_size = next_entry.block_size - (GetInteger(next_entry.phys_addr) & (next_entry.block_size - 1)); remaining_pages -= std::min(remaining_pages, actual_size / PageSize); cur_virt_addr += actual_size; } else { /* If we didn't merge, just advance. */ remaining_pages -= next_entry.block_size / PageSize; cur_virt_addr += next_entry.block_size; } /* Continue our traversal. */ if (remaining_pages == 0) { break; } MESOSPHERE_ABORT_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context))); } }; /* ===================================================== */ /* If we don't need to refresh the pages, we can just apply the mappings. */ if (!refresh_mapping) { ApplyEntryTemplate(entry_template, ApplyOption_None); this->NoteUpdated(); } else { /* We need to refresh the mappings. */ /* First, apply the changes without the mapped bit. This will cause all entries to page fault if accessed. */ { PageTableEntry unmapped_template = entry_template; unmapped_template.SetMapped(false); ApplyEntryTemplate(unmapped_template, ApplyOption_MergeMappings); this->NoteUpdated(); } /* Next, take and immediately release the scheduler lock. This will force a reschedule. */ { KScopedSchedulerLock sl; } /* Finally, apply the changes as directed, flushing the mappings before they're applied (if we should). */ ApplyEntryTemplate(entry_template, flush_mapping ? ApplyOption_FlushDataCache : ApplyOption_None); /* Wait for pending stores to complete. */ cpu::DataSynchronizationBarrierInnerShareableStore(); } /* We've succeeded, now perform what coalescing we can. */ this->MergePages(virt_addr, num_pages, page_list); R_SUCCEED(); } void KPageTable::FinalizeUpdateImpl(PageLinkedList *page_list) { while (page_list->Peek()) { KVirtualAddress page = KVirtualAddress(page_list->Pop()); MESOSPHERE_ASSERT(this->GetPageTableManager().IsInPageTableHeap(page)); MESOSPHERE_ASSERT(this->GetPageTableManager().GetRefCount(page) == 0); this->GetPageTableManager().Free(page); } } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_page_table_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { void KPageTableImpl::InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end) { m_table = static_cast<L1PageTableEntry *>(tb); m_is_kernel = true; m_num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize; /* Page table entries created by KInitialPageTable need to be iterated and modified to ensure KPageTable invariants. */ PageTableEntry *level_entries[EntryLevel_Count] = { nullptr, nullptr, m_table }; u32 level = EntryLevel_L1; while (level != EntryLevel_L1 || (level_entries[EntryLevel_L1] - static_cast<PageTableEntry *>(m_table)) < m_num_entries) { /* Get the pte; it must never have the validity-extension flag set. */ auto *pte = level_entries[level]; MESOSPHERE_ASSERT((pte->GetSoftwareReservedBits() & PageTableEntry::SoftwareReservedBit_Valid) == 0); /* While we're a table, recurse, fixing up the reference counts. */ while (level > EntryLevel_L3 && pte->IsMappedTable()) { /* Count how many references are in the table. */ auto *table = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(pte->GetTable())); size_t ref_count = 0; for (size_t i = 0; i < BlocksPerTable; ++i) { if (table[i].IsMapped()) { ++ref_count; } } /* Set the reference count for our new page, adding one additional uncloseable reference; kernel pages must never be unreferenced. */ pte->SetTableReferenceCount(ref_count + 1).SetValid(); /* Iterate downwards. */ level -= 1; level_entries[level] = table; pte = level_entries[level]; /* Check that the entry isn't unexpected. */ MESOSPHERE_ASSERT((pte->GetSoftwareReservedBits() & PageTableEntry::SoftwareReservedBit_Valid) == 0); } /* We're dealing with some block. If it's mapped, set it valid. */ if (pte->IsMapped()) { pte->SetValid(); } /* Advance. */ while (true) { /* Advance to the next entry at the current level. */ if (!util::IsAligned(reinterpret_cast<uintptr_t>(++level_entries[level]), PageSize)) { break; } /* If we're at the end of a level, advance upwards. */ level_entries[level++] = nullptr; if (level > EntryLevel_L1) { return; } } } } void KPageTableImpl::InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end) { m_table = static_cast<L1PageTableEntry *>(tb); m_is_kernel = false; m_num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize; } L1PageTableEntry *KPageTableImpl::Finalize() { return m_table; } bool KPageTableImpl::BeginTraversal(TraversalEntry *out_entry, TraversalContext *out_context, KProcessAddress address) const { /* Setup invalid defaults. */ *out_entry = {}; *out_context = {}; /* Validate that we can read the actual entry. */ const size_t l0_index = GetL0Index(address); const size_t l1_index = GetL1Index(address); if (m_is_kernel) { /* Kernel entries must be accessed via TTBR1. */ if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - m_num_entries)) { return false; } } else { /* User entries must be accessed with TTBR0. */ if ((l0_index != 0) || l1_index >= m_num_entries) { return false; } } /* Get the L1 entry, and check if it's a table. */ out_context->level_entries[EntryLevel_L1] = this->GetL1Entry(address); if (out_context->level_entries[EntryLevel_L1]->IsMappedTable()) { /* Get the L2 entry, and check if it's a table. */ out_context->level_entries[EntryLevel_L2] = this->GetL2EntryFromTable(GetPageTableVirtualAddress(out_context->level_entries[EntryLevel_L1]->GetTable()), address); if (out_context->level_entries[EntryLevel_L2]->IsMappedTable()) { /* Get the L3 entry. */ out_context->level_entries[EntryLevel_L3] = this->GetL3EntryFromTable(GetPageTableVirtualAddress(out_context->level_entries[EntryLevel_L2]->GetTable()), address); /* It's either a page or not. */ out_context->level = EntryLevel_L3; } else { /* Not a L2 table, so possibly an L2 block. */ out_context->level = EntryLevel_L2; } } else { /* Not a L1 table, so possibly an L1 block. */ out_context->level = EntryLevel_L1; } /* Determine other fields. */ const auto *pte = out_context->level_entries[out_context->level]; out_context->is_contiguous = pte->IsContiguous(); out_entry->sw_reserved_bits = pte->GetSoftwareReservedBits(); out_entry->attr = 0; out_entry->phys_addr = this->GetBlock(pte, out_context->level) + this->GetOffset(address, out_context->level); out_entry->block_size = static_cast<size_t>(1) << (PageBits + LevelBits * out_context->level + 4 * out_context->is_contiguous); return out_context->level == EntryLevel_L3 ? pte->IsPage() : pte->IsBlock(); } bool KPageTableImpl::ContinueTraversal(TraversalEntry *out_entry, TraversalContext *context) const { /* Advance entry. */ auto *cur_pte = context->level_entries[context->level]; auto *next_pte = reinterpret_cast<PageTableEntry *>(context->is_contiguous ? util::AlignDown(reinterpret_cast<uintptr_t>(cur_pte), BlocksPerContiguousBlock * sizeof(PageTableEntry)) + BlocksPerContiguousBlock * sizeof(PageTableEntry) : reinterpret_cast<uintptr_t>(cur_pte) + sizeof(PageTableEntry)); /* Set the pte. */ context->level_entries[context->level] = next_pte; /* Advance appropriately. */ while (context->level < EntryLevel_L1 && util::IsAligned(reinterpret_cast<uintptr_t>(context->level_entries[context->level]), PageSize)) { /* Advance the above table by one entry. */ context->level_entries[context->level + 1]++; context->level = static_cast<EntryLevel>(util::ToUnderlying(context->level) + 1); } /* Check if we've hit the end of the L1 table. */ if (context->level == EntryLevel_L1) { if (context->level_entries[EntryLevel_L1] - static_cast<const PageTableEntry *>(m_table) >= m_num_entries) { *context = {}; *out_entry = {}; return false; } } /* We may have advanced to a new table, and if we have we should descend. */ while (context->level > EntryLevel_L3 && context->level_entries[context->level]->IsMappedTable()) { context->level_entries[context->level - 1] = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(context->level_entries[context->level]->GetTable())); context->level = static_cast<EntryLevel>(util::ToUnderlying(context->level) - 1); } const auto *pte = context->level_entries[context->level]; context->is_contiguous = pte->IsContiguous(); out_entry->sw_reserved_bits = pte->GetSoftwareReservedBits(); out_entry->attr = 0; out_entry->phys_addr = this->GetBlock(pte, context->level); out_entry->block_size = static_cast<size_t>(1) << (PageBits + LevelBits * context->level + 4 * context->is_contiguous); return context->level == EntryLevel_L3 ? pte->IsPage() : pte->IsBlock(); } bool KPageTableImpl::GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const { /* Validate that we can read the actual entry. */ const size_t l0_index = GetL0Index(address); const size_t l1_index = GetL1Index(address); if (m_is_kernel) { /* Kernel entries must be accessed via TTBR1. */ if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - m_num_entries)) { return false; } } else { /* User entries must be accessed with TTBR0. */ if ((l0_index != 0) || l1_index >= m_num_entries) { return false; } } /* Get the L1 entry, and check if it's a table. */ const PageTableEntry *pte = this->GetL1Entry(address); EntryLevel level = EntryLevel_L1; if (pte->IsMappedTable()) { /* Get the L2 entry, and check if it's a table. */ pte = this->GetL2EntryFromTable(GetPageTableVirtualAddress(pte->GetTable()), address); level = EntryLevel_L2; if (pte->IsMappedTable()) { pte = this->GetL3EntryFromTable(GetPageTableVirtualAddress(pte->GetTable()), address); level = EntryLevel_L3; } } const bool is_block = level == EntryLevel_L3 ? pte->IsPage() : pte->IsBlock(); if (is_block) { *out = this->GetBlock(pte, level) + this->GetOffset(address, level); } else { *out = Null<KPhysicalAddress>; } return is_block; } bool KPageTableImpl::MergePages(KVirtualAddress *out, TraversalContext *context, EntryUpdatedCallback on_entry_updated, const void *pt) { /* We want to upgrade the pages by one step. */ if (context->is_contiguous) { /* We can't merge an L1 table. */ if (context->level == EntryLevel_L1) { return false; } /* We want to upgrade a contiguous mapping in a table to a block. */ PageTableEntry *pte = reinterpret_cast<PageTableEntry *>(util::AlignDown(reinterpret_cast<uintptr_t>(context->level_entries[context->level]), BlocksPerTable * sizeof(PageTableEntry))); const KPhysicalAddress phys_addr = util::AlignDown(GetBlock(pte, context->level), GetBlockSize(static_cast<EntryLevel>(context->level + 1), false)); /* First, check that all entries are valid for us to merge. */ const u64 entry_template = pte->GetEntryTemplateForMerge(); for (size_t i = 0; i < BlocksPerTable; ++i) { if (!pte[i].IsForMerge(entry_template | GetInteger(phys_addr + (i << (PageBits + LevelBits * context->level))) | PageTableEntry::ContigType_Contiguous | pte->GetTestTableMask())) { return false; } if (i > 0 && pte[i].IsHeadOrHeadAndBodyMergeDisabled()) { return false; } if (i < BlocksPerTable - 1 && pte[i].IsTailMergeDisabled()) { return false; } } /* The entries are valid for us to merge, so merge them. */ const auto *head_pte = pte; const auto *tail_pte = pte + BlocksPerTable - 1; const auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_pte->IsHeadMergeDisabled(), head_pte->IsHeadAndBodyMergeDisabled(), tail_pte->IsTailMergeDisabled()); *context->level_entries[context->level + 1] = PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), sw_reserved_bits, false, false); on_entry_updated(pt); /* Update our context. */ context->is_contiguous = false; context->level = static_cast<EntryLevel>(util::ToUnderlying(context->level) + 1); /* Set the output to the table we just freed. */ *out = KVirtualAddress(pte); } else { /* We want to upgrade a non-contiguous mapping to a contiguous mapping. */ PageTableEntry *pte = reinterpret_cast<PageTableEntry *>(util::AlignDown(reinterpret_cast<uintptr_t>(context->level_entries[context->level]), BlocksPerContiguousBlock * sizeof(PageTableEntry))); const KPhysicalAddress phys_addr = util::AlignDown(GetBlock(pte, context->level), GetBlockSize(context->level, true)); /* First, check that all entries are valid for us to merge. */ const u64 entry_template = pte->GetEntryTemplateForMerge(); for (size_t i = 0; i < BlocksPerContiguousBlock; ++i) { if (!pte[i].IsForMerge(entry_template | GetInteger(phys_addr + (i << (PageBits + LevelBits * context->level))) | pte->GetTestTableMask())) { return false; } if (i > 0 && pte[i].IsHeadOrHeadAndBodyMergeDisabled()) { return false; } if (i < BlocksPerContiguousBlock - 1 && pte[i].IsTailMergeDisabled()) { return false; } } /* The entries are valid for us to merge, so merge them. */ const auto *head_pte = pte; const auto *tail_pte = pte + BlocksPerContiguousBlock - 1; const auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_pte->IsHeadMergeDisabled(), head_pte->IsHeadAndBodyMergeDisabled(), tail_pte->IsTailMergeDisabled()); for (size_t i = 0; i < BlocksPerContiguousBlock; ++i) { pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, phys_addr + (i << (PageBits + LevelBits * context->level)), PageTableEntry(entry_template), sw_reserved_bits, true, context->level == EntryLevel_L3); } on_entry_updated(pt); /* Update our context. */ context->level_entries[context->level] = pte; context->is_contiguous = true; } return true; } void KPageTableImpl::SeparatePages(TraversalEntry *entry, TraversalContext *context, KProcessAddress address, PageTableEntry *pte, EntryUpdatedCallback on_entry_updated, const void *pt) const { /* We want to downgrade the pages by one step. */ if (context->is_contiguous) { /* We want to downgrade a contiguous mapping to a non-contiguous mapping. */ pte = reinterpret_cast<PageTableEntry *>(util::AlignDown(reinterpret_cast<uintptr_t>(context->level_entries[context->level]), BlocksPerContiguousBlock * sizeof(PageTableEntry))); auto * const first = pte; const KPhysicalAddress block = this->GetBlock(first, context->level); for (size_t i = 0; i < BlocksPerContiguousBlock; ++i) { pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, block + (i << (PageBits + LevelBits * context->level)), PageTableEntry(first->GetEntryTemplateForSeparateContiguous(i)), PageTableEntry::SeparateContiguousTag{}); } on_entry_updated(pt); context->is_contiguous = false; context->level_entries[context->level] = pte + (this->GetLevelIndex(address, context->level) & (BlocksPerContiguousBlock - 1)); } else { /* We want to downgrade a block into a table. */ auto * const first = context->level_entries[context->level]; const KPhysicalAddress block = this->GetBlock(first, context->level); for (size_t i = 0; i < BlocksPerTable; ++i) { pte[i] = PageTableEntry(PageTableEntry::BlockTag{}, block + (i << (PageBits + LevelBits * (context->level - 1))), PageTableEntry(first->GetEntryTemplateForSeparate(i)), PageTableEntry::SoftwareReservedBit_None, true, context->level - 1 == EntryLevel_L3); } context->is_contiguous = true; context->level = static_cast<EntryLevel>(util::ToUnderlying(context->level) - 1); /* Wait for pending stores to complete. */ cpu::DataSynchronizationBarrierInnerShareableStore(); /* Update the block entry to be a table entry. */ *context->level_entries[context->level + 1] = PageTableEntry(PageTableEntry::TableTag{}, KPageTable::GetPageTablePhysicalAddress(KVirtualAddress(pte)), m_is_kernel, true, BlocksPerTable); on_entry_updated(pt); context->level_entries[context->level] = pte + this->GetLevelIndex(address, context->level); } entry->sw_reserved_bits = context->level_entries[context->level]->GetSoftwareReservedBits(); entry->attr = 0; entry->phys_addr = this->GetBlock(context->level_entries[context->level], context->level) + this->GetOffset(address, context->level); entry->block_size = static_cast<size_t>(1) << (PageBits + LevelBits * context->level + 4 * context->is_contiguous); } void KPageTableImpl::Dump(uintptr_t start, size_t size) const { /* If zero size, there's nothing to dump. */ if (size == 0) { return; } /* Define extents. */ const uintptr_t end = start + size; const uintptr_t last = end - 1; /* Define tracking variables. */ bool unmapped = false; uintptr_t unmapped_start = 0; /* Walk the table. */ uintptr_t cur = start; while (cur < end) { /* Validate that we can read the actual entry. */ const size_t l0_index = GetL0Index(cur); const size_t l1_index = GetL1Index(cur); if (m_is_kernel) { /* Kernel entries must be accessed via TTBR1. */ if ((l0_index != MaxPageTableEntries - 1) || (l1_index < MaxPageTableEntries - m_num_entries)) { return; } } else { /* User entries must be accessed with TTBR0. */ if ((l0_index != 0) || l1_index >= m_num_entries) { return; } } /* Try to get from l1 table. */ const L1PageTableEntry *l1_entry = this->GetL1Entry(cur); if (l1_entry->IsBlock()) { /* Update. */ cur = util::AlignDown(cur, L1BlockSize); if (unmapped) { unmapped = false; MESOSPHERE_RELEASE_LOG("%016lx - %016lx: not mapped\n", unmapped_start, cur - 1); } /* Print. */ MESOSPHERE_RELEASE_LOG("%016lx: %016lx PA=%p SZ=1G Mapped=%d UXN=%d PXN=%d Cont=%d nG=%d AF=%d SH=%x RO=%d UA=%d NS=%d AttrIndx=%d NoMerge=%d,%d,%d\n", cur, *reinterpret_cast<const u64 *>(l1_entry), reinterpret_cast<void *>(GetInteger(l1_entry->GetBlock())), l1_entry->IsMapped(), l1_entry->IsUserExecuteNever(), l1_entry->IsPrivilegedExecuteNever(), l1_entry->IsContiguous(), !l1_entry->IsGlobal(), static_cast<int>(l1_entry->GetAccessFlagInteger()), static_cast<unsigned int>(l1_entry->GetShareableInteger()), l1_entry->IsReadOnly(), l1_entry->IsUserAccessible(), l1_entry->IsNonSecure(), static_cast<int>(l1_entry->GetPageAttributeInteger()), l1_entry->IsHeadMergeDisabled(), l1_entry->IsHeadAndBodyMergeDisabled(), l1_entry->IsTailMergeDisabled()); /* Advance. */ cur += L1BlockSize; continue; } else if (!l1_entry->IsTable()) { /* Update. */ cur = util::AlignDown(cur, L1BlockSize); if (!unmapped) { unmapped_start = cur; unmapped = true; } /* Advance. */ cur += L1BlockSize; continue; } /* Try to get from l2 table. */ const L2PageTableEntry *l2_entry = this->GetL2Entry(l1_entry, cur); if (l2_entry->IsBlock()) { /* Update. */ cur = util::AlignDown(cur, L2BlockSize); if (unmapped) { unmapped = false; MESOSPHERE_RELEASE_LOG("%016lx - %016lx: not mapped\n", unmapped_start, cur - 1); } /* Print. */ MESOSPHERE_RELEASE_LOG("%016lx: %016lx PA=%p SZ=2M Mapped=%d UXN=%d PXN=%d Cont=%d nG=%d AF=%d SH=%x RO=%d UA=%d NS=%d AttrIndx=%d NoMerge=%d,%d,%d\n", cur, *reinterpret_cast<const u64 *>(l2_entry), reinterpret_cast<void *>(GetInteger(l2_entry->GetBlock())), l2_entry->IsMapped(), l2_entry->IsUserExecuteNever(), l2_entry->IsPrivilegedExecuteNever(), l2_entry->IsContiguous(), !l2_entry->IsGlobal(), static_cast<int>(l2_entry->GetAccessFlagInteger()), static_cast<unsigned int>(l2_entry->GetShareableInteger()), l2_entry->IsReadOnly(), l2_entry->IsUserAccessible(), l2_entry->IsNonSecure(), static_cast<int>(l2_entry->GetPageAttributeInteger()), l2_entry->IsHeadMergeDisabled(), l2_entry->IsHeadAndBodyMergeDisabled(), l2_entry->IsTailMergeDisabled()); /* Advance. */ cur += L2BlockSize; continue; } else if (!l2_entry->IsTable()) { /* Update. */ cur = util::AlignDown(cur, L2BlockSize); if (!unmapped) { unmapped_start = cur; unmapped = true; } /* Advance. */ cur += L2BlockSize; continue; } /* Try to get from l3 table. */ const L3PageTableEntry *l3_entry = this->GetL3Entry(l2_entry, cur); if (l3_entry->IsBlock()) { /* Update. */ cur = util::AlignDown(cur, L3BlockSize); if (unmapped) { unmapped = false; MESOSPHERE_RELEASE_LOG("%016lx - %016lx: not mapped\n", unmapped_start, cur - 1); } /* Print. */ MESOSPHERE_RELEASE_LOG("%016lx: %016lx PA=%p SZ=4K Mapped=%d UXN=%d PXN=%d Cont=%d nG=%d AF=%d SH=%x RO=%d UA=%d NS=%d AttrIndx=%d NoMerge=%d,%d,%d\n", cur, *reinterpret_cast<const u64 *>(l3_entry), reinterpret_cast<void *>(GetInteger(l3_entry->GetBlock())), l3_entry->IsMapped(), l3_entry->IsUserExecuteNever(), l3_entry->IsPrivilegedExecuteNever(), l3_entry->IsContiguous(), !l3_entry->IsGlobal(), static_cast<int>(l3_entry->GetAccessFlagInteger()), static_cast<unsigned int>(l3_entry->GetShareableInteger()), l3_entry->IsReadOnly(), l3_entry->IsUserAccessible(), l3_entry->IsNonSecure(), static_cast<int>(l3_entry->GetPageAttributeInteger()), l3_entry->IsHeadMergeDisabled(), l3_entry->IsHeadAndBodyMergeDisabled(), l3_entry->IsTailMergeDisabled()); /* Advance. */ cur += L3BlockSize; continue; } else { /* Update. */ cur = util::AlignDown(cur, L3BlockSize); if (!unmapped) { unmapped_start = cur; unmapped = true; } /* Advance. */ cur += L3BlockSize; continue; } } /* Print the last unmapped range if necessary. */ if (unmapped) { MESOSPHERE_RELEASE_LOG("%016lx - %016lx: not mapped\n", unmapped_start, last); } } size_t KPageTableImpl::CountPageTables() const { size_t num_tables = 0; #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) { ++num_tables; for (size_t l1_index = 0; l1_index < m_num_entries; ++l1_index) { auto &l1_entry = m_table[l1_index]; if (l1_entry.IsTable()) { ++num_tables; for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) { auto *l2_entry = GetPointer<L2PageTableEntry>(GetTableEntry(KMemoryLayout::GetLinearVirtualAddress(l1_entry.GetTable()), l2_index)); if (l2_entry->IsTable()) { ++num_tables; } } } } } #endif return num_tables; } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_supervisor_page_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { void KSupervisorPageTable::Initialize(s32 core_id) { /* Verify that sctlr_el1 has the wxn bit set. */ MESOSPHERE_ABORT_UNLESS(cpu::SystemControlRegisterAccessor().GetWxn()); /* Invalidate the entire TLB. */ cpu::InvalidateEntireTlb(); /* If core 0, initialize our base page table. */ if (core_id == 0) { /* TODO: constexpr defines. */ const u64 ttbr1 = cpu::GetTtbr1El1() & 0xFFFFFFFFFFFFul; const u64 kernel_vaddr_start = 0xFFFFFF8000000000ul; const u64 kernel_vaddr_end = 0xFFFFFFFFFFE00000ul; void *table = GetVoidPointer(KPageTableBase::GetLinearMappedVirtualAddress(ttbr1)); m_page_table.InitializeForKernel(table, kernel_vaddr_start, kernel_vaddr_end); } } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_k_thread_context.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::arch::arm64 { /* These are implemented elsewhere (asm). */ void UserModeThreadStarter(); void SupervisorModeThreadStarter(); void InvokeSupervisorModeThread(uintptr_t argument, uintptr_t entrypoint) { /* Invoke the function. */ using SupervisorModeFunctionType = void (*)(uintptr_t); reinterpret_cast<SupervisorModeFunctionType>(entrypoint)(argument); /* Wait forever. */ AMS_INFINITE_LOOP(); } void OnThreadStart() { MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); /* Send KDebug event for this thread's creation. */ { KScopedInterruptEnable ei; const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) }; static_cast<void>(KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params))); } /* Handle any pending dpc. */ while (GetCurrentThread().HasDpc()) { KDpcManager::HandleDpc(); } /* Clear our status as in an exception handler */ GetCurrentThread().ClearInExceptionHandler(); } namespace { ALWAYS_INLINE bool IsFpuEnabled() { return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled(); } ALWAYS_INLINE void EnableFpu() { cpu::ArchitecturalFeatureAccessControlRegisterAccessor().SetFpEnabled(true).Store(); cpu::InstructionMemoryBarrier(); } uintptr_t SetupStackForUserModeThreadStarter(KVirtualAddress pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, const bool is_64_bit) { /* NOTE: Stack layout on entry looks like following: */ /* SP */ /* | */ /* v */ /* | KExceptionContext (size 0x120) | KThread::StackParameters (size 0x130) | */ KExceptionContext *ctx = GetPointer<KExceptionContext>(k_sp) - 1; /* Clear context. */ std::memset(ctx, 0, sizeof(*ctx)); /* Set PC and argument. */ ctx->pc = GetInteger(pc) & ~(UINT64_C(1)); ctx->x[0] = arg; /* Set PSR. */ if (is_64_bit) { ctx->psr = 0; } else { constexpr u64 PsrArmValue = 0x00; constexpr u64 PsrThumbValue = 0x20; ctx->psr = ((pc & 1) == 0 ? PsrArmValue : PsrThumbValue) | (0x10); MESOSPHERE_LOG("Creating User 32-Thread, %016lx\n", GetInteger(pc)); } /* Set CFI-value. */ if (is_64_bit) { ctx->x[18] = KSystemControl::GenerateRandomU64() | 1; } /* Set stack pointer. */ if (is_64_bit) { ctx->sp = GetInteger(u_sp); } else { ctx->x[13] = GetInteger(u_sp); } return reinterpret_cast<uintptr_t>(ctx); } uintptr_t SetupStackForSupervisorModeThreadStarter(KVirtualAddress pc, KVirtualAddress sp, uintptr_t arg) { /* NOTE: Stack layout on entry looks like following: */ /* SP */ /* | */ /* v */ /* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x140) | */ static_assert(sizeof(KThread::StackParameters) == 0x140); u64 *stack = GetPointer<u64>(sp); *(--stack) = GetInteger(pc); *(--stack) = arg; return reinterpret_cast<uintptr_t>(stack); } } void KThreadContext::Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main) { MESOSPHERE_ASSERT(k_sp != Null<KVirtualAddress>); /* Ensure that the stack pointers are aligned. */ k_sp = util::AlignDown(GetInteger(k_sp), 16); u_sp = util::AlignDown(GetInteger(u_sp), 16); /* Determine LR and SP. */ if (is_user) { /* Usermode thread. */ m_lr = reinterpret_cast<uintptr_t>(::ams::kern::arch::arm64::UserModeThreadStarter); m_sp = SetupStackForUserModeThreadStarter(u_pc, k_sp, u_sp, arg, is_64_bit); } else { /* Kernel thread. */ MESOSPHERE_ASSERT(is_64_bit); if (is_main) { /* Main thread. */ m_lr = GetInteger(u_pc); m_sp = GetInteger(k_sp); } else { /* Generic Kernel thread. */ m_lr = reinterpret_cast<uintptr_t>(::ams::kern::arch::arm64::SupervisorModeThreadStarter); m_sp = SetupStackForSupervisorModeThreadStarter(u_pc, k_sp, arg); } } /* Clear callee-saved registers. */ for (size_t i = 0; i < util::size(m_callee_saved.registers); i++) { m_callee_saved.registers[i] = 0; } /* Clear FPU state. */ m_fpcr = 0; m_fpsr = 0; for (size_t i = 0; i < util::size(m_callee_saved_fpu.fpu64.v); ++i) { m_callee_saved_fpu.fpu64.v[i] = 0; } /* Lock the context, if we're a main thread. */ m_locked = is_main; } void KThreadContext::SetArguments(uintptr_t arg0, uintptr_t arg1) { u64 *stack = reinterpret_cast<u64 *>(m_sp); stack[0] = arg0; stack[1] = arg1; } void KThreadContext::CloneFpuStatus() { u64 pcr, psr; cpu::InstructionMemoryBarrier(); KScopedInterruptDisable di; if (IsFpuEnabled()) { __asm__ __volatile__("mrs %[pcr], fpcr" : [pcr]"=r"(pcr) :: "memory"); __asm__ __volatile__("mrs %[psr], fpsr" : [psr]"=r"(psr) :: "memory"); } else { pcr = GetCurrentThread().GetContext().GetFpcr(); psr = GetCurrentThread().GetContext().GetFpsr(); } this->SetFpcr(pcr); this->SetFpsr(psr); } void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread->IsSuspended()); MESOSPHERE_ASSERT(thread->GetOwnerProcess() != nullptr); /* Get the contexts. */ const KExceptionContext *e_ctx = GetExceptionContext(thread); const KThreadContext *t_ctx = std::addressof(thread->GetContext()); if (thread->GetOwnerProcess()->Is64Bit()) { /* Set special registers. */ out->fp = e_ctx->x[29]; out->lr = e_ctx->x[30]; out->sp = e_ctx->sp; out->pc = e_ctx->pc; out->pstate = e_ctx->psr & cpu::El0Aarch64PsrMask; /* Get the thread's general purpose registers. */ if (thread->IsCallingSvc()) { for (size_t i = 19; i < 29; ++i) { out->r[i] = e_ctx->x[i]; } if (e_ctx->write == 0) { out->pc -= sizeof(u32); } } else { for (size_t i = 0; i < 29; ++i) { out->r[i] = e_ctx->x[i]; } } /* Copy tpidr. */ out->tpidr = e_ctx->tpidr; /* Copy fpu registers. */ static_assert(util::size(ams::svc::ThreadContext{}.v) == KThreadContext::NumFpuRegisters); static_assert(KThreadContext::NumCallerSavedFpuRegisters == KThreadContext::NumCalleeSavedFpuRegisters * 3); static_assert(KThreadContext::NumFpuRegisters == KThreadContext::NumCallerSavedFpuRegisters + KThreadContext::NumCalleeSavedFpuRegisters); const auto &caller_save_fpu = thread->GetCallerSaveFpuRegisters().fpu64; const auto &callee_save_fpu = t_ctx->GetCalleeSaveFpuRegisters().fpu64; if (!thread->IsCallingSvc() || thread->IsInUsermodeExceptionHandler()) { KThreadContext::GetFpuRegisters(out->v, caller_save_fpu, callee_save_fpu); } else { for (size_t i = 0; i < KThreadContext::NumCalleeSavedFpuRegisters; ++i) { out->v[(KThreadContext::NumCallerSavedFpuRegisters / 3) + i] = caller_save_fpu.v[i]; } } } else { /* Set special registers. */ out->pc = static_cast<u32>(e_ctx->pc); out->pstate = e_ctx->psr & cpu::El0Aarch32PsrMask; /* Get the thread's general purpose registers. */ for (size_t i = 0; i < 15; ++i) { out->r[i] = static_cast<u32>(e_ctx->x[i]); } /* Adjust PC, if the thread is calling svc. */ if (thread->IsCallingSvc()) { if (e_ctx->write == 0) { /* Adjust by 2 if thumb mode, 4 if arm mode. */ out->pc -= ((e_ctx->psr & 0x20) == 0) ? sizeof(u32) : sizeof(u16); } } /* Copy tpidr. */ out->tpidr = static_cast<u32>(e_ctx->tpidr); /* Copy fpu registers. */ static_assert(util::size(ams::svc::ThreadContext{}.v) == KThreadContext::NumFpuRegisters); static_assert(KThreadContext::NumCallerSavedFpuRegisters == KThreadContext::NumCalleeSavedFpuRegisters * 3); static_assert(KThreadContext::NumFpuRegisters == KThreadContext::NumCallerSavedFpuRegisters + KThreadContext::NumCalleeSavedFpuRegisters); const auto &caller_save_fpu = thread->GetCallerSaveFpuRegisters().fpu32; const auto &callee_save_fpu = t_ctx->GetCalleeSaveFpuRegisters().fpu32; if (!thread->IsCallingSvc() || thread->IsInUsermodeExceptionHandler()) { KThreadContext::GetFpuRegisters(out->v, caller_save_fpu, callee_save_fpu); } else { for (size_t i = 0; i < KThreadContext::NumCalleeSavedFpuRegisters / 2; ++i) { out->v[((KThreadContext::NumCallerSavedFpuRegisters / 3) / 2) + i] = caller_save_fpu.v[i]; } } } /* Copy fpcr/fpsr. */ out->fpcr = t_ctx->GetFpcr(); out->fpsr = t_ctx->GetFpsr(); } void KThreadContext::OnThreadTerminating(const KThread *thread) { MESOSPHERE_UNUSED(thread); /* ... */ } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_panic_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere/kern_build_config.hpp> #include <mesosphere/kern_select_assembly_offsets.h> #if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP) #define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT \ /* Save x0/x1 to stack. */ \ stp x0, x1, [sp, #-16]!; \ \ /* Get the exception context for the core. */ \ adr x0, _ZN3ams4kern26g_panic_exception_contextsE; \ mrs x1, mpidr_el1; \ and x1, x1, #0xFF; \ lsl x1, x1, #0x8; \ add x0, x0, x1; \ lsr x1, x1, #0x3; \ add x0, x0, x1; \ \ /* Save x0/x1/sp to the context. */ \ ldr x1, [sp, #(8 * 0)]; \ str x1, [x0, #(EXCEPTION_CONTEXT_X0)]; \ ldr x1, [sp, #(8 * 1)]; \ str x1, [x0, #(EXCEPTION_CONTEXT_X1)]; \ \ /* Save all other registers to the context. */ \ stp x2, x3, [x0, #(EXCEPTION_CONTEXT_X2_X3)]; \ stp x4, x5, [x0, #(EXCEPTION_CONTEXT_X4_X5)]; \ stp x6, x7, [x0, #(EXCEPTION_CONTEXT_X6_X7)]; \ stp x8, x9, [x0, #(EXCEPTION_CONTEXT_X8_X9)]; \ stp x10, x11, [x0, #(EXCEPTION_CONTEXT_X10_X11)]; \ stp x12, x13, [x0, #(EXCEPTION_CONTEXT_X12_X13)]; \ stp x14, x15, [x0, #(EXCEPTION_CONTEXT_X14_X15)]; \ stp x16, x17, [x0, #(EXCEPTION_CONTEXT_X16_X17)]; \ stp x18, x19, [x0, #(EXCEPTION_CONTEXT_X18_X19)]; \ stp x20, x21, [x0, #(EXCEPTION_CONTEXT_X20_X21)]; \ stp x22, x23, [x0, #(EXCEPTION_CONTEXT_X22_X23)]; \ stp x24, x25, [x0, #(EXCEPTION_CONTEXT_X24_X25)]; \ stp x26, x27, [x0, #(EXCEPTION_CONTEXT_X26_X27)]; \ stp x28, x29, [x0, #(EXCEPTION_CONTEXT_X28_X29)]; \ \ add x1, sp, #16; \ stp x30, x1, [x0, #(EXCEPTION_CONTEXT_X30_SP)]; \ \ /* Restore x0/x1. */ \ ldp x0, x1, [sp], #16; #else #define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT #endif /* ams::kern::Panic(const char *file, int line, const char *format, ...) */ .section .text._ZN3ams4kern5PanicEPKciS2_z, "ax", %progbits .global _ZN3ams4kern5PanicEPKciS2_z .type _ZN3ams4kern5PanicEPKciS2_z, %function _ZN3ams4kern5PanicEPKciS2_z: /* Generate the exception context. */ MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT /* Jump to the architecturally-common implementation function. */ b _ZN3ams4kern9PanicImplEPKciS2_z /* ams::kern::Panic() */ .section .text._ZN3ams4kern5PanicEv, "ax", %progbits .global _ZN3ams4kern5PanicEv .type _ZN3ams4kern5PanicEv, %function _ZN3ams4kern5PanicEv: /* Generate the exception context. */ MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT /* Jump to the architecturally-common implementation function. */ b _ZN3ams4kern9PanicImplEv ================================================ FILE: libraries/libmesosphere/source/arch/arm64/kern_userspace_memory_access_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::arch::arm64::UserspaceAccessFunctionAreaBegin() */ .section .text._ZN3ams4kern4arch5arm6432UserspaceAccessFunctionAreaBeginEv, "ax", %progbits .global _ZN3ams4kern4arch5arm6432UserspaceAccessFunctionAreaBeginEv .type _ZN3ams4kern4arch5arm6432UserspaceAccessFunctionAreaBeginEv, %function .balign 0x10 _ZN3ams4kern4arch5arm6432UserspaceAccessFunctionAreaBeginEv: /* NOTE: This is not a real function, and only exists as a label for safety. */ /* ================ All Userspace Access Functions after this line. ================ */ /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUser(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyMemoryFromUserEPvPKvm: /* Check if there's anything to copy. */ cmp x2, #0 b.eq 2f /* Keep track of the last address. */ add x3, x1, x2 1: /* We're copying memory byte-by-byte. */ ldtrb w2, [x1] strb w2, [x0], #1 add x1, x1, #1 cmp x1, x3 b.ne 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm: /* Check if there are 0x40 bytes to copy */ cmp x2, #0x3F b.ls 1f ldtr x4, [x1, #0x00] ldtr x5, [x1, #0x08] ldtr x6, [x1, #0x10] ldtr x7, [x1, #0x18] ldtr x8, [x1, #0x20] ldtr x9, [x1, #0x28] ldtr x10, [x1, #0x30] ldtr x11, [x1, #0x38] stp x4, x5, [x0, #0x00] stp x6, x7, [x0, #0x10] stp x8, x9, [x0, #0x20] stp x10, x11, [x0, #0x30] add x0, x0, #0x40 add x1, x1, #0x40 sub x2, x2, #0x40 b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned32BitEPvPKvm 1: /* We have less than 0x40 bytes to copy. */ cmp x2, #0 b.eq 2f ldtr w4, [x1] str w4, [x0], #4 add x1, x1, #4 sub x2, x2, #4 b 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm: /* Check if there are 0x40 bytes to copy */ cmp x2, #0x3F b.ls 1f ldtr x4, [x1, #0x00] ldtr x5, [x1, #0x08] ldtr x6, [x1, #0x10] ldtr x7, [x1, #0x18] ldtr x8, [x1, #0x20] ldtr x9, [x1, #0x28] ldtr x10, [x1, #0x30] ldtr x11, [x1, #0x38] stp x4, x5, [x0, #0x00] stp x6, x7, [x0, #0x10] stp x8, x9, [x0, #0x20] stp x10, x11, [x0, #0x30] add x0, x0, #0x40 add x1, x1, #0x40 sub x2, x2, #0x40 b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl30CopyMemoryFromUserAligned64BitEPvPKvm 1: /* We have less than 0x40 bytes to copy. */ cmp x2, #0 b.eq 2f ldtr x4, [x1] str x4, [x0], #8 add x1, x1, #8 sub x2, x2, #8 b 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize64BitEPvPKv: /* Just load and store a u64. */ ldtr x2, [x1] str x2, [x0] /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl27CopyMemoryFromUserSize32BitEPvPKv: /* Just load and store a u32. */ ldtr w2, [x1] str w2, [x0] /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryFromUserSize32BitWithSupervisorAccess(void *dst, const void *src) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl47CopyMemoryFromUserSize32BitWithSupervisorAccessEPvPKv: /* Just load and store a u32. */ /* NOTE: This is done with supervisor access permissions. */ ldr w2, [x1] str w2, [x0] /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyStringFromUser(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18CopyStringFromUserEPvPKvm: /* Check if there's anything to copy. */ cmp x2, #0 b.eq 3f /* Keep track of the start address and last address. */ mov x4, x1 add x3, x1, x2 1: /* We're copying memory byte-by-byte. */ ldtrb w2, [x1] strb w2, [x0], #1 add x1, x1, #1 /* If we read a null terminator, we're done. */ cmp w2, #0 b.eq 2f /* Check if we're done. */ cmp x1, x3 b.ne 1b 2: /* We're done, and we copied some amount of data from the string. */ sub x0, x1, x4 ret 3: /* We're done, and there was no string data. */ mov x0, #0 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUser(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyMemoryToUserEPvPKvm: /* Check if there's anything to copy. */ cmp x2, #0 b.eq 2f /* Keep track of the last address. */ add x3, x1, x2 1: /* We're copying memory byte-by-byte. */ ldrb w2, [x1], #1 sttrb w2, [x0] add x0, x0, #1 cmp x1, x3 b.ne 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserAligned32Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm: /* Check if there are 0x40 bytes to copy */ cmp x2, #0x3F b.ls 1f ldp x4, x5, [x1, #0x00] ldp x6, x7, [x1, #0x10] ldp x8, x9, [x1, #0x20] ldp x10, x11, [x1, #0x30] sttr x4, [x0, #0x00] sttr x5, [x0, #0x08] sttr x6, [x0, #0x10] sttr x7, [x0, #0x18] sttr x8, [x0, #0x20] sttr x9, [x0, #0x28] sttr x10, [x0, #0x30] sttr x11, [x0, #0x38] add x0, x0, #0x40 add x1, x1, #0x40 sub x2, x2, #0x40 b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned32BitEPvPKvm 1: /* We have less than 0x40 bytes to copy. */ cmp x2, #0 b.eq 2f ldr w4, [x1], #4 sttr w4, [x0] add x0, x0, #4 sub x2, x2, #4 b 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserAligned64Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm: /* Check if there are 0x40 bytes to copy */ cmp x2, #0x3F b.ls 1f ldp x4, x5, [x1, #0x00] ldp x6, x7, [x1, #0x10] ldp x8, x9, [x1, #0x20] ldp x10, x11, [x1, #0x30] sttr x4, [x0, #0x00] sttr x5, [x0, #0x08] sttr x6, [x0, #0x10] sttr x7, [x0, #0x18] sttr x8, [x0, #0x20] sttr x9, [x0, #0x28] sttr x10, [x0, #0x30] sttr x11, [x0, #0x38] add x0, x0, #0x40 add x1, x1, #0x40 sub x2, x2, #0x40 b _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl28CopyMemoryToUserAligned64BitEPvPKvm 1: /* We have less than 0x40 bytes to copy. */ cmp x2, #0 b.eq 2f ldr x4, [x1], #8 sttr x4, [x0] add x0, x0, #8 sub x2, x2, #8 b 1b 2: /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyMemoryToUserSize32Bit(void *dst, u32 value) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25CopyMemoryToUserSize32BitEPvj: /* Just store a u32. */ sttr w1, [x0] /* We're done. */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::CopyStringToUser(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16CopyStringToUserEPvPKvm: /* Check if there's anything to copy. */ cmp x2, #0 b.eq 3f /* Keep track of the start address and last address. */ mov x4, x1 add x3, x1, x2 1: /* We're copying memory byte-by-byte. */ ldrb w2, [x1], #1 sttrb w2, [x0] add x0, x0, #1 /* If we read a null terminator, we're done. */ cmp w2, #0 b.eq 2f /* Check if we're done. */ cmp x1, x3 b.ne 1b 2: /* We're done, and we copied some amount of data from the string. */ sub x0, x1, x4 ret 3: /* We're done, and there was no string data. */ mov x0, #0 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj: /* Load the value from the address. */ ldaxr w4, [x1] /* Orr in the new mask. */ orr w5, w4, w3 /* If the value is zero, use the if_zero value, otherwise use the newly orr'd value. */ cmp w4, wzr csel w5, w2, w5, eq /* Try to store. */ stlxr w6, w5, [x1] /* If we failed to store, try again. */ cbnz w6, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16UpdateLockAtomicEPjS5_jj /* We're done. */ str w4, [x0] mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii: /* Load the value from the address. */ ldaxr w4, [x1] /* Compare it to the desired one. */ cmp w4, w2 /* If equal, we want to try to write the new value. */ b.eq 1f /* Otherwise, clear our exclusive hold and finish. */ clrex b 2f 1: /* Try to store. */ stlxr w5, w3, [x1] /* If we failed to store, try again. */ cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19UpdateIfEqualAtomicEPiS5_ii 2: /* We're done. */ str w4, [x0] mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i: /* Load the value from the address. */ ldaxr w3, [x1] /* Compare it to the desired one. */ cmp w3, w2 /* If less than, we want to try to decrement. */ b.lt 1f /* Otherwise, clear our exclusive hold and finish. */ clrex b 2f 1: /* Decrement and try to store. */ sub w4, w3, #1 stlxr w5, w4, [x1] /* If we failed to store, try again. */ cbnz w5, _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl25DecrementIfLessThanAtomicEPiS5_i 2: /* We're done. */ str w3, [x0] mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::StoreDataCache(uintptr_t start, uintptr_t end) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14StoreDataCacheEmm: /* Check if we have any work to do. */ cmp x1, x0 b.eq 2f 1: /* Loop, storing each cache line. */ dc cvac, x0 add x0, x0, #0x40 cmp x1, x0 b.ne 1b 2: /* We're done! */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::FlushDataCache(uintptr_t start, uintptr_t end) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl14FlushDataCacheEmm: /* Check if we have any work to do. */ cmp x1, x0 b.eq 2f 1: /* Loop, flushing each cache line. */ dc civac, x0 add x0, x0, #0x40 cmp x1, x0 b.ne 1b 2: /* We're done! */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::InvalidateDataCache(uintptr_t start, uintptr_t end) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl19InvalidateDataCacheEmm: /* Check if we have any work to do. */ cmp x1, x0 b.eq 2f 1: /* Loop, invalidating each cache line. */ dc ivac, x0 add x0, x0, #0x40 cmp x1, x0 b.ne 1b 2: /* We're done! */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory32Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory32BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for read failure. */ adr x10, 4f 1: /* Set our return address so that on read failure we continue as though we read -1. */ mov x30, x10 /* Read the word from io. */ ldtr w9, [x5] dsb sy nop 2: /* Restore our return address. */ mov x30, x8 /* Write the value we read. */ sttr w9, [x4] /* Advance. */ add x4, x4, #4 add x5, x5, #4 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret 4: /* We failed to read a value, so continue as though we read -1. */ mov w9, #0xFFFFFFFF b 2b /* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory16Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17ReadIoMemory16BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for read failure. */ adr x10, 4f 1: /* Set our return address so that on read failure we continue as though we read -1. */ mov x30, x10 /* Read the word from io. */ ldtrh w9, [x5] dsb sy nop 2: /* Restore our return address. */ mov x30, x8 /* Write the value we read. */ sttrh w9, [x4] /* Advance. */ add x4, x4, #2 add x5, x5, #2 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret 4: /* We failed to read a value, so continue as though we read -1. */ mov w9, #0xFFFFFFFF b 2b /* ams::kern::arch::arm64::UserspaceAccess::Impl::ReadIoMemory8Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl16ReadIoMemory8BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for read failure. */ adr x10, 4f 1: /* Set our return address so that on read failure we continue as though we read -1. */ mov x30, x10 /* Read the word from io. */ ldtrb w9, [x5] dsb sy nop 2: /* Restore our return address. */ mov x30, x8 /* Write the value we read. */ sttrb w9, [x4] /* Advance. */ add x4, x4, #1 add x5, x5, #1 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret 4: /* We failed to read a value, so continue as though we read -1. */ mov w9, #0xFFFFFFFF b 2b /* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory32Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for failure. */ adr x10, 2f 1: /* Read the word from normal memory. */ ldtr w9, [x5] /* Set our return address so that on failure we continue. */ mov x30, x10 /* Write the word to io. */ sttr w9, [x5] dsb sy 2: /* Continue. */ mov x30, x8 /* Advance. */ add x4, x4, #4 add x5, x5, #4 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory16Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for failure. */ adr x10, 2f 1: /* Read the word from normal memory. */ ldtrh w9, [x5] /* Set our return address so that on failure we continue. */ mov x30, x10 /* Write the word to io. */ sttrh w9, [x5] dsb sy 2: /* Continue. */ mov x30, x8 /* Advance. */ add x4, x4, #2 add x5, x5, #2 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret /* ams::kern::arch::arm64::UserspaceAccess::Impl::WriteIoMemory8Bit(void *dst, const void *src, size_t size) */ .section .text._ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm, "ax", %progbits .global _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm .type _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm, %function .balign 0x10 _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm: /* Check if we have any work to do. */ cmp x2, #0 b.eq 3f /* Save variables in temporary registers. */ mov x4, x0 mov x5, x1 mov x6, x2 add x7, x5, x6 /* Save our return address. */ mov x8, x30 /* Prepare return address for failure. */ adr x10, 2f 1: /* Read the word from normal memory. */ ldtrb w9, [x5] /* Set our return address so that on failure we continue. */ mov x30, x10 /* Write the word to io. */ sttrb w9, [x5] dsb sy 2: /* Continue. */ mov x30, x8 /* Advance. */ add x4, x4, #1 add x5, x5, #1 cmp x5, x7 b.ne 1b 3: /* We're done! */ mov x0, #1 ret /* ================ All Userspace Access Functions before this line. ================ */ /* ams::kern::arch::arm64::UserspaceAccessFunctionAreaEnd() */ .section .text._ZN3ams4kern4arch5arm6430UserspaceAccessFunctionAreaEndEv, "ax", %progbits .global _ZN3ams4kern4arch5arm6430UserspaceAccessFunctionAreaEndEv .type _ZN3ams4kern4arch5arm6430UserspaceAccessFunctionAreaEndEv, %function .balign 0x10 _ZN3ams4kern4arch5arm6430UserspaceAccessFunctionAreaEndEv: /* NOTE: This is not a real function, and only exists as a label for safety. */ ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_address_arbiter_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::svc::CallWaitForAddress64From32() */ .section .text._ZN3ams4kern3svc26CallWaitForAddress64From32Ev, "ax", %progbits .global _ZN3ams4kern3svc26CallWaitForAddress64From32Ev .type _ZN3ams4kern3svc26CallWaitForAddress64From32Ev, %function _ZN3ams4kern3svc26CallWaitForAddress64From32Ev: /* Save LR + callee-save registers. */ str x30, [sp, #-16]! stp x6, x7, [sp, #-16]! /* Gather the arguments into correct registers. */ /* NOTE: This has to be manually implemented via asm, */ /* in order to avoid breaking ABI with pre-19.0.0. */ orr x2, x2, x5, lsl#32 orr x3, x3, x4, lsl#32 /* Invoke the svc handler. */ bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll /* Clean up registers. */ mov x1, xzr mov x2, xzr mov x3, xzr mov x4, xzr mov x5, xzr ldp x6, x7, [sp], #0x10 ldr x30, [sp], #0x10 ret /* ams::kern::svc::CallWaitForAddress64() */ .section .text._ZN3ams4kern3svc20CallWaitForAddress64Ev, "ax", %progbits .global _ZN3ams4kern3svc20CallWaitForAddress64Ev .type _ZN3ams4kern3svc20CallWaitForAddress64Ev, %function _ZN3ams4kern3svc20CallWaitForAddress64Ev: /* Save LR + FP. */ stp x29, x30, [sp, #-16]! /* Invoke the svc handler. */ bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll /* Clean up registers. */ mov x1, xzr mov x2, xzr mov x3, xzr mov x4, xzr mov x5, xzr mov x6, xzr mov x7, xzr ldp x29, x30, [sp], #0x10 ret ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_call_secure_monitor_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::svc::CallCallSecureMonitor64From32() */ .section .text._ZN3ams4kern3svc29CallCallSecureMonitor64From32Ev, "ax", %progbits .global _ZN3ams4kern3svc29CallCallSecureMonitor64From32Ev .type _ZN3ams4kern3svc29CallCallSecureMonitor64From32Ev, %function _ZN3ams4kern3svc29CallCallSecureMonitor64From32Ev: /* Secure Monitor 64-from-32 ABI is not supported. */ mov x0, xzr mov x1, xzr mov x2, xzr mov x3, xzr mov x4, xzr mov x5, xzr mov x6, xzr mov x7, xzr ret ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_exception_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere/kern_select_assembly_macros.h> /* ams::kern::svc::CallReturnFromException64(Result result) */ .section .text._ZN3ams4kern3svc25CallReturnFromException64Ev, "ax", %progbits .global _ZN3ams4kern3svc25CallReturnFromException64Ev .type _ZN3ams4kern3svc25CallReturnFromException64Ev, %function _ZN3ams4kern3svc25CallReturnFromException64Ev: /* Save registers the SVC entry handler didn't. */ stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] stp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)] stp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)] str x19, [sp, #(EXCEPTION_CONTEXT_X19)] stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)] stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)] stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)] stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] /* Call ams::kern::arch::arm64::ReturnFromException(result). */ bl _ZN3ams4kern4arch5arm6419ReturnFromExceptionENS_6ResultE 0: /* We should never reach this point. */ b 0b /* ams::kern::svc::CallReturnFromException64From32(Result result) */ .section .text._ZN3ams4kern3svc31CallReturnFromException64From32Ev, "ax", %progbits .global _ZN3ams4kern3svc31CallReturnFromException64From32Ev .type _ZN3ams4kern3svc31CallReturnFromException64From32Ev, %function _ZN3ams4kern3svc31CallReturnFromException64From32Ev: /* Save registers the SVC entry handler didn't. */ /* ... */ /* Call ams::kern::arch::arm64::ReturnFromException(result). */ bl _ZN3ams4kern4arch5arm6419ReturnFromExceptionENS_6ResultE 0: /* We should never reach this point. */ b 0b /* ams::kern::svc::RestoreContext(uintptr_t sp) */ .section .text._ZN3ams4kern3svc14RestoreContextEm, "ax", %progbits .global _ZN3ams4kern3svc14RestoreContextEm .type _ZN3ams4kern3svc14RestoreContextEm, %function _ZN3ams4kern3svc14RestoreContextEm: /* Set the stack pointer, set daif. */ mov sp, x0 msr daifset, #2 0: /* We should handle DPC. */ /* Check the dpc flags. */ ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)] cbz w8, 1f /* We have DPC to do! */ /* Save registers and call ams::kern::KDpcManager::HandleDpc(). */ sub sp, sp, #0x40 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] bl _ZN3ams4kern11KDpcManager9HandleDpcEv ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] add sp, sp, #0x40 b 0b 1: /* We're done with DPC, and should return from the svc. */ /* Get our exception flags. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* Clear in-svc, in-user-exception, and needs-fpu-restore flags. */ and w10, w9, #(~(THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED)) and w10, w10, #(~(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC)) and w10, w10, #(~(THREAD_EXCEPTION_FLAG_IS_IN_USERMODE_EXCEPTION_HANDLER)) strb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* If we don't need to restore the fpu, skip restoring it. */ tbz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED), 3f /* Enable and restore the fpu. */ ENABLE_AND_RESTORE_FPU(x10, x8, x9, w8, w9, 2, 3) /* Restore registers. */ ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)] ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)] #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Since we're returning from an exception, set SPSR.SS so that we advance an instruction if single-stepping. */ orr x10, x10, #(1 << 21) #endif msr sp_el0, x8 msr elr_el1, x9 msr spsr_el1, x10 msr tpidr_el0, x11 ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)] ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)] ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)] ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)] ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)] ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)] ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)] ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)] ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] /* Return. */ add sp, sp, #(EXCEPTION_CONTEXT_SIZE) ERET_WITH_SPECULATION_BARRIER ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { void TraceSvcEntry(const u64 *data) { MESOSPHERE_KTRACE_SVC_ENTRY(GetCurrentThread().GetSvcId(), data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } void TraceSvcExit(const u64 *data) { MESOSPHERE_KTRACE_SVC_EXIT(GetCurrentThread().GetSvcId(), data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } } ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_handlers_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere/kern_build_config.hpp> #include <mesosphere/kern_select_assembly_macros.h> /* ams::kern::arch::arm64::SvcHandler64() */ .section .text._ZN3ams4kern4arch5arm6412SvcHandler64Ev, "ax", %progbits .global _ZN3ams4kern4arch5arm6412SvcHandler64Ev .type _ZN3ams4kern4arch5arm6412SvcHandler64Ev, %function _ZN3ams4kern4arch5arm6412SvcHandler64Ev: /* Create a KExceptionContext for the exception. */ sub sp, sp, #(EXCEPTION_CONTEXT_SIZE) /* Save registers needed for ReturnFromException */ stp x9, x10, [sp, #(EXCEPTION_CONTEXT_X9_X10)] str x11, [sp, #(EXCEPTION_CONTEXT_X11)] str x18, [sp, #(EXCEPTION_CONTEXT_X18)] mrs x8, sp_el0 mrs x9, elr_el1 mrs x10, spsr_el1 mrs x11, tpidr_el0 ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)] /* Save callee-saved registers. */ stp x19, x20, [sp, #(EXCEPTION_CONTEXT_X19_X20)] stp x21, x22, [sp, #(EXCEPTION_CONTEXT_X21_X22)] stp x23, x24, [sp, #(EXCEPTION_CONTEXT_X23_X24)] stp x25, x26, [sp, #(EXCEPTION_CONTEXT_X25_X26)] stp x27, x28, [sp, #(EXCEPTION_CONTEXT_X27_X28)] /* Save miscellaneous registers. */ stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] stp x29, x30, [sp, #(EXCEPTION_CONTEXT_X29_X30)] stp x8, x9, [sp, #(EXCEPTION_CONTEXT_SP_PC)] stp x10, x11, [sp, #(EXCEPTION_CONTEXT_PSR_TPIDR)] /* Check if the SVC index is out of range. */ mrs x8, esr_el1 and x8, x8, #0xFF cmp x8, #(AMS_KERN_NUM_SUPERVISOR_CALLS) b.ge 3f /* Check the specific SVC permission bit for allowal. */ mov x9, sp add x9, x9, x8, lsr#3 ldrb w9, [x9, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)] and x10, x8, #0x7 lsr x10, x9, x10 tst x10, #1 b.eq 3f /* Check if our disable count allows us to call SVCs. */ mrs x10, tpidrro_el0 add x10, x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT) ldtrh w10, [x10] cbz w10, 1f /* It might not, so check the stack params to see if we must not allow the SVC. */ ldrb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)] cbz w10, 3f 1: /* We can call the SVC. */ adr x10, _ZN3ams4kern3svc10SvcTable64E ldr x11, [x10, x8, lsl#3] cbz x11, 3f /* Note that we're calling the SVC. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] orr w9, w9, #(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC) strb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)] /* If we should, trace the svc entry. */ #if defined(MESOSPHERE_BUILD_FOR_TRACING) sub sp, sp, #0x50 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] str x11, [sp, #(8 * 8)] mov x0, sp bl _ZN3ams4kern3svc13TraceSvcEntryEPKm ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] ldr x11, [sp, #(8 * 8)] add sp, sp, #0x50 #endif /* Invoke the SVC handler. */ msr daifclr, #2 blr x11 msr daifset, #2 2: /* We completed the SVC, and we should handle DPC. */ /* Check the dpc flags. */ ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)] cbz w8, 5f /* We have DPC to do! */ /* Save registers and call ams::kern::KDpcManager::HandleDpc(). */ sub sp, sp, #0x40 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] bl _ZN3ams4kern11KDpcManager9HandleDpcEv ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] add sp, sp, #0x40 b 2b 3: /* Invalid SVC. */ /* Setup the context to call into HandleException. */ stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X8_X9)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X10_X11)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X12_X13)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)] str x19, [sp, #(EXCEPTION_CONTEXT_X19)] stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)] stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)] stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)] stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] /* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */ mov x0, sp bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE /* If we don't need to restore the fpu, skip restoring it. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] tbz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED), 4f /* Clear the needs-fpu-restore flag. */ and w9, w9, #(~THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED) strb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* Enable and restore the fpu. */ ENABLE_AND_RESTORE_FPU64(x10, x8, x9, w8, w9) 4: /* Restore registers. */ ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)] ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)] #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Since we're returning from an SVC, make sure SPSR.SS is cleared so that if we're single-stepping we break instantly on the instruction after the SVC. */ bic x10, x10, #(1 << 21) #endif msr sp_el0, x8 msr elr_el1, x9 msr spsr_el1, x10 msr tpidr_el0, x11 ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)] ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)] ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)] ldp x16, x17, [sp, #(EXCEPTION_CONTEXT_X16_X17)] ldp x18, x19, [sp, #(EXCEPTION_CONTEXT_X18_X19)] ldp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)] ldp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)] ldp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)] ldp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)] ldp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)] /* Return. */ add sp, sp, #(EXCEPTION_CONTEXT_SIZE) ERET_WITH_SPECULATION_BARRIER 5: /* Return from SVC. */ /* If we should, trace the svc exit. */ #if defined(MESOSPHERE_BUILD_FOR_TRACING) sub sp, sp, #0x40 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] mov x0, sp bl _ZN3ams4kern3svc12TraceSvcExitEPKm ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] add sp, sp, #0x40 #endif /* Get our exception flags. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* Clear in-svc and needs-fpu-restore flags. */ and w8, w9, #(~(THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED)) and w8, w8, #(~(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC)) strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* If we don't need to restore the fpu, skip restoring it. */ tbz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED), 7f /* If we need to restore the fpu, check if we need to do a full restore. */ tbnz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_USERMODE_EXCEPTION_HANDLER), 6f /* Enable the fpu. */ ENABLE_FPU(x8) /* Get the thread context and restore fpsr/fpcr. */ GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(x10, x8, x9, w8, w9) /* Restore callee-saved registers to 64-bit fpu. */ RESTORE_FPU64_CALLEE_SAVE_REGISTERS(x10) /* Clear caller-saved registers to 64-bit fpu. */ movi v0.2d, #0 movi v1.2d, #0 movi v2.2d, #0 movi v3.2d, #0 movi v4.2d, #0 movi v5.2d, #0 movi v6.2d, #0 movi v7.2d, #0 movi v16.2d, #0 movi v17.2d, #0 movi v18.2d, #0 movi v19.2d, #0 movi v20.2d, #0 movi v21.2d, #0 movi v22.2d, #0 movi v23.2d, #0 movi v24.2d, #0 movi v25.2d, #0 movi v26.2d, #0 movi v27.2d, #0 movi v28.2d, #0 movi v29.2d, #0 movi v30.2d, #0 movi v31.2d, #0 b 7f 6: /* We need to do a full fpu restore. */ ENABLE_AND_RESTORE_FPU64(x10, x8, x9, w8, w9) 7: /* Restore registers. */ ldp x30, x8, [sp, #(EXCEPTION_CONTEXT_X30_SP)] ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)] ldr x18, [sp, #(EXCEPTION_CONTEXT_X18)] #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Since we're returning from an SVC, make sure SPSR.SS is cleared so that if we're single-stepping we break instantly on the instruction after the SVC. */ bic x10, x10, #(1 << 21) #endif msr sp_el0, x8 msr elr_el1, x9 msr spsr_el1, x10 msr tpidr_el0, x11 /* Clear registers. */ mov x8, xzr mov x9, xzr mov x10, xzr mov x11, xzr mov x12, xzr mov x13, xzr mov x14, xzr mov x15, xzr mov x16, xzr mov x17, xzr /* Return. */ add sp, sp, #(EXCEPTION_CONTEXT_SIZE) ERET_WITH_SPECULATION_BARRIER /* ams::kern::arch::arm64::SvcHandler32() */ .section .text._ZN3ams4kern4arch5arm6412SvcHandler32Ev, "ax", %progbits .global _ZN3ams4kern4arch5arm6412SvcHandler32Ev .type _ZN3ams4kern4arch5arm6412SvcHandler32Ev, %function _ZN3ams4kern4arch5arm6412SvcHandler32Ev: /* Ensure that our registers are 32-bit. */ mov w0, w0 mov w1, w1 mov w2, w2 mov w3, w3 mov w4, w4 mov w5, w5 mov w6, w6 mov w7, w7 /* Create a KExceptionContext for the exception. */ sub sp, sp, #(EXCEPTION_CONTEXT_SIZE) /* Save system registers */ mrs x17, elr_el1 mrs x20, spsr_el1 mrs x19, tpidr_el0 ldr x18, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CUR_THREAD)] stp x17, x20, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] str x19, [sp, #(EXCEPTION_CONTEXT_TPIDR)] /* Save registers. */ stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] stp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)] stp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)] stp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] stp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)] /* Check if the SVC index is out of range. */ mrs x8, esr_el1 and x8, x8, #0xFF cmp x8, #(AMS_KERN_NUM_SUPERVISOR_CALLS) b.ge 3f /* Check the specific SVC permission bit for allowal. */ mov x9, sp add x9, x9, x8, lsr#3 ldrb w9, [x9, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_SVC_PERMISSION)] and x10, x8, #0x7 lsr x10, x9, x10 tst x10, #1 b.eq 3f /* Check if our disable count allows us to call SVCs. */ mrs x10, tpidrro_el0 add x10, x10, #(THREAD_LOCAL_REGION_DISABLE_COUNT) ldtrh w10, [x10] cbz w10, 1f /* It might not, so check the stack params to see if we must not allow the SVC. */ ldrb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_IS_PINNED)] cbz w10, 3f 1: /* We can call the SVC. */ adr x10, _ZN3ams4kern3svc16SvcTable64From32E ldr x11, [x10, x8, lsl#3] cbz x11, 3f /* Note that we're calling the SVC. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] orr w9, w9, #(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC) strb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_CURRENT_SVC_ID)] /* If we should, trace the svc entry. */ #if defined(MESOSPHERE_BUILD_FOR_TRACING) sub sp, sp, #0x50 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] str x11, [sp, #(8 * 8)] mov x0, sp bl _ZN3ams4kern3svc13TraceSvcEntryEPKm ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] ldr x11, [sp, #(8 * 8)] add sp, sp, #0x50 #endif /* Invoke the SVC handler. */ msr daifclr, #2 blr x11 msr daifset, #2 2: /* We completed the SVC, and we should handle DPC. */ /* Check the dpc flags. */ ldrb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_DPC_FLAGS)] cbz w8, 5f /* We have DPC to do! */ /* Save registers and call ams::kern::KDpcManager::HandleDpc(). */ sub sp, sp, #0x20 stp w0, w1, [sp, #(4 * 0)] stp w2, w3, [sp, #(4 * 2)] stp w4, w5, [sp, #(4 * 4)] stp w6, w7, [sp, #(4 * 6)] bl _ZN3ams4kern11KDpcManager9HandleDpcEv ldp w0, w1, [sp, #(4 * 0)] ldp w2, w3, [sp, #(4 * 2)] ldp w4, w5, [sp, #(4 * 4)] ldp w6, w7, [sp, #(4 * 6)] add sp, sp, #0x20 b 2b 3: /* Invalid SVC. */ /* Setup the context to call into HandleException. */ stp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] stp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] stp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] stp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X16_X17)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X18_X19)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X20_X21)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X22_X23)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X24_X25)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X26_X27)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X28_X29)] stp xzr, xzr, [sp, #(EXCEPTION_CONTEXT_X30_SP)] /* Call ams::kern::arch::arm64::HandleException(ams::kern::arch::arm64::KExceptionContext *) */ mov x0, sp bl _ZN3ams4kern4arch5arm6415HandleExceptionEPNS2_17KExceptionContextE /* If we don't need to restore the fpu, skip restoring it. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] tbz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED), 4f /* Clear the needs-fpu-restore flag. */ and w9, w9, #(~THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED) strb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* Enable and restore the fpu. */ ENABLE_AND_RESTORE_FPU32(x10, x8, x9, w8, w9) 4: /* Restore registers. */ ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)] #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Since we're returning from an SVC, make sure SPSR.SS is cleared so that if we're single-stepping we break instantly on the instruction after the SVC. */ bic x10, x10, #(1 << 21) #endif msr elr_el1, x9 msr spsr_el1, x10 msr tpidr_el0, x11 ldp x0, x1, [sp, #(EXCEPTION_CONTEXT_X0_X1)] ldp x2, x3, [sp, #(EXCEPTION_CONTEXT_X2_X3)] ldp x4, x5, [sp, #(EXCEPTION_CONTEXT_X4_X5)] ldp x6, x7, [sp, #(EXCEPTION_CONTEXT_X6_X7)] ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)] ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)] ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] ldp x14, x15, [sp, #(EXCEPTION_CONTEXT_X14_X15)] /* Return. */ add sp, sp, #(EXCEPTION_CONTEXT_SIZE) ERET_WITH_SPECULATION_BARRIER 5: /* Return from SVC. */ /* If we should, trace the svc exit. */ #if defined(MESOSPHERE_BUILD_FOR_TRACING) sub sp, sp, #0x40 stp x0, x1, [sp, #(8 * 0)] stp x2, x3, [sp, #(8 * 2)] stp x4, x5, [sp, #(8 * 4)] stp x6, x7, [sp, #(8 * 6)] mov x0, sp bl _ZN3ams4kern3svc12TraceSvcExitEPKm ldp x0, x1, [sp, #(8 * 0)] ldp x2, x3, [sp, #(8 * 2)] ldp x4, x5, [sp, #(8 * 4)] ldp x6, x7, [sp, #(8 * 6)] add sp, sp, #0x40 #endif /* Get our exception flags. */ ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* Clear in-svc and needs-fpu-restore flags. */ and w8, w9, #(~(THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED)) and w8, w8, #(~(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC)) strb w8, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)] /* If we don't need to restore the fpu, skip restoring it. */ tbz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_FPU_CONTEXT_RESTORE_NEEDED), 7f /* If we need to restore the fpu, check if we need to do a full restore. */ tbnz w9, #(THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_USERMODE_EXCEPTION_HANDLER), 6f /* Enable the fpu. */ ENABLE_FPU(x8) /* Get the thread context and restore fpsr/fpcr. */ GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(x10, x8, x9, w8, w9) /* Restore callee-saved registers to 32-bit fpu. */ RESTORE_FPU32_CALLEE_SAVE_REGISTERS(x10) /* Clear caller-saved registers to 32-bit fpu. */ movi v0.2d, #0 movi v1.2d, #0 movi v2.2d, #0 movi v3.2d, #0 movi v8.2d, #0 movi v9.2d, #0 movi v10.2d, #0 movi v11.2d, #0 movi v12.2d, #0 movi v13.2d, #0 movi v14.2d, #0 movi v15.2d, #0 b 7f 6: /* We need to do a full fpu restore. */ ENABLE_AND_RESTORE_FPU32(x10, x8, x9, w8, w9) 7: /* Restore registers. */ ldp x9, x10, [sp, #(EXCEPTION_CONTEXT_PC_PSR)] ldr x11, [sp, #(EXCEPTION_CONTEXT_TPIDR)] #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Since we're returning from an SVC, make sure SPSR.SS is cleared so that if we're single-stepping we break instantly on the instruction after the SVC. */ bic x10, x10, #(1 << 21) #endif msr elr_el1, x9 msr spsr_el1, x10 msr tpidr_el0, x11 ldp x8, x9, [sp, #(EXCEPTION_CONTEXT_X8_X9)] ldp x10, x11, [sp, #(EXCEPTION_CONTEXT_X10_X11)] ldp x12, x13, [sp, #(EXCEPTION_CONTEXT_X12_X13)] ldp x14, xzr, [sp, #(EXCEPTION_CONTEXT_X14_X15)] /* Return. */ add sp, sp, #(EXCEPTION_CONTEXT_SIZE) ERET_WITH_SPECULATION_BARRIER ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_light_ipc_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::svc::CallSendSyncRequestLight64() */ .section .text._ZN3ams4kern3svc26CallSendSyncRequestLight64Ev, "ax", %progbits .global _ZN3ams4kern3svc26CallSendSyncRequestLight64Ev .type _ZN3ams4kern3svc26CallSendSyncRequestLight64Ev, %function _ZN3ams4kern3svc26CallSendSyncRequestLight64Ev: /* Allocate space for the light ipc data. */ sub sp, sp, #(4 * 8) /* Store the light ipc data. */ stp w1, w2, [sp, #(4 * 0)] stp w3, w4, [sp, #(4 * 2)] stp w5, w6, [sp, #(4 * 4)] str w7, [sp, #(4 * 6)] /* Invoke the svc handler. */ mov x1, sp stp x29, x30, [sp, #-16]! bl _ZN3ams4kern3svc22SendSyncRequestLight64EjPj ldp x29, x30, [sp], #16 /* Load the light ipc data. */ ldp w1, w2, [sp, #(4 * 0)] ldp w3, w4, [sp, #(4 * 2)] ldp w5, w6, [sp, #(4 * 4)] ldr w7, [sp, #(4 * 6)] /* Free the stack space for the light ipc data. */ add sp, sp, #(4 * 8) ret /* ams::kern::svc::CallSendSyncRequestLight64From32() */ .section .text._ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev, "ax", %progbits .global _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev .type _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev, %function _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev: /* Allocate space for the light ipc data. */ sub sp, sp, #(4 * 8) /* Store the light ipc data. */ stp w1, w2, [sp, #(4 * 0)] stp w3, w4, [sp, #(4 * 2)] stp w5, w6, [sp, #(4 * 4)] str w7, [sp, #(4 * 6)] /* Invoke the svc handler. */ mov x1, sp stp x29, x30, [sp, #-16]! bl _ZN3ams4kern3svc28SendSyncRequestLight64From32EjPj ldp x29, x30, [sp], #16 /* Load the light ipc data. */ ldp w1, w2, [sp, #(4 * 0)] ldp w3, w4, [sp, #(4 * 2)] ldp w5, w6, [sp, #(4 * 4)] ldr w7, [sp, #(4 * 6)] /* Free the stack space for the light ipc data. */ add sp, sp, #(4 * 8) ret /* ams::kern::svc::CallReplyAndReceiveLight64() */ .section .text._ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev, "ax", %progbits .global _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev .type _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev, %function _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev: /* Allocate space for the light ipc data. */ sub sp, sp, #(4 * 8) /* Store the light ipc data. */ stp w1, w2, [sp, #(4 * 0)] stp w3, w4, [sp, #(4 * 2)] stp w5, w6, [sp, #(4 * 4)] str w7, [sp, #(4 * 6)] /* Invoke the svc handler. */ mov x1, sp stp x29, x30, [sp, #-16]! bl _ZN3ams4kern3svc22ReplyAndReceiveLight64EjPj ldp x29, x30, [sp], #16 /* Load the light ipc data. */ ldp w1, w2, [sp, #(4 * 0)] ldp w3, w4, [sp, #(4 * 2)] ldp w5, w6, [sp, #(4 * 4)] ldr w7, [sp, #(4 * 6)] /* Free the stack space for the light ipc data. */ add sp, sp, #(4 * 8) ret /* ams::kern::svc::CallReplyAndReceiveLight64From32() */ .section .text._ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev, "ax", %progbits .global _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev .type _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev, %function _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev: /* Allocate space for the light ipc data. */ sub sp, sp, #(4 * 8) /* Store the light ipc data. */ stp w1, w2, [sp, #(4 * 0)] stp w3, w4, [sp, #(4 * 2)] stp w5, w6, [sp, #(4 * 4)] str w7, [sp, #(4 * 6)] /* Invoke the svc handler. */ mov x1, sp stp x29, x30, [sp, #-16]! bl _ZN3ams4kern3svc28ReplyAndReceiveLight64From32EjPj ldp x29, x30, [sp], #16 /* Load the light ipc data. */ ldp w1, w2, [sp, #(4 * 0)] ldp w3, w4, [sp, #(4 * 2)] ldp w5, w6, [sp, #(4 * 4)] ldr w7, [sp, #(4 * 6)] /* Free the stack space for the light ipc data. */ add sp, sp, #(4 * 8) ret ================================================ FILE: libraries/libmesosphere/source/arch/arm64/svc/kern_svc_tables.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef MESOSPHERE_USE_STUBBED_SVC_TABLES #include <mesosphere/kern_debug_log.hpp> #endif #include <mesosphere/svc/kern_svc_tables.hpp> #include <vapours/svc/svc_codegen.hpp> namespace ams::kern::svc { /* Declare special prototypes for the light ipc handlers. */ void CallSendSyncRequestLight64(); void CallSendSyncRequestLight64From32(); void CallReplyAndReceiveLight64(); void CallReplyAndReceiveLight64From32(); /* Declare special prototypes for ReturnFromException. */ void CallReturnFromException64(); void CallReturnFromException64From32(); /* Declare special prototype for (unsupported) CallCallSecureMonitor64From32. */ void CallCallSecureMonitor64From32(); /* Declare special prototypes for WaitForAddress. */ void CallWaitForAddress64(); void CallWaitForAddress64From32(); namespace { #ifndef MESOSPHERE_USE_STUBBED_SVC_TABLES #define DECLARE_SVC_STRUCT(ID, RETURN_TYPE, NAME, ...) \ class NAME { \ private: \ using Impl = ::ams::svc::codegen::KernelSvcWrapper<::ams::kern::svc::NAME##64, ::ams::kern::svc::NAME##64From32>; \ public: \ static NOINLINE void Call64() { return Impl::Call64(); } \ static NOINLINE void Call64From32() { return Impl::Call64From32(); } \ }; #else #define DECLARE_SVC_STRUCT(ID, RETURN_TYPE, NAME, ...) \ class NAME { \ public: \ static NOINLINE void Call64() { MESOSPHERE_PANIC("Stubbed Svc"#NAME"64 was called"); } \ static NOINLINE void Call64From32() { MESOSPHERE_PANIC("Stubbed Svc"#NAME"64From32 was called"); } \ }; #endif /* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */ #pragma GCC push_options #pragma GCC optimize ("-O3") #pragma GCC optimize ("omit-frame-pointer") AMS_SVC_FOREACH_KERN_DEFINITION(DECLARE_SVC_STRUCT, _) #pragma GCC pop_options constexpr const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64From32Impl = [] { std::array<SvcTableEntry, NumSupervisorCalls> table = {}; #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ if (table[ID] == nullptr) { table[ID] = NAME::Call64From32; } AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) #undef AMS_KERN_SVC_SET_TABLE_ENTRY table[svc::SvcId_SendSyncRequestLight] = CallSendSyncRequestLight64From32; table[svc::SvcId_ReplyAndReceiveLight] = CallReplyAndReceiveLight64From32; table[svc::SvcId_ReturnFromException] = CallReturnFromException64From32; table[svc::SvcId_CallSecureMonitor] = CallCallSecureMonitor64From32; table[svc::SvcId_WaitForAddress] = CallWaitForAddress64From32; return table; }(); constexpr const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64Impl = [] { std::array<SvcTableEntry, NumSupervisorCalls> table = {}; #define AMS_KERN_SVC_SET_TABLE_ENTRY(ID, RETURN_TYPE, NAME, ...) \ if (table[ID] == nullptr) { table[ID] = NAME::Call64; } AMS_SVC_FOREACH_KERN_DEFINITION(AMS_KERN_SVC_SET_TABLE_ENTRY, _) #undef AMS_KERN_SVC_SET_TABLE_ENTRY table[svc::SvcId_SendSyncRequestLight] = CallSendSyncRequestLight64; table[svc::SvcId_ReplyAndReceiveLight] = CallReplyAndReceiveLight64; table[svc::SvcId_ReturnFromException] = CallReturnFromException64; table[svc::SvcId_WaitForAddress] = CallWaitForAddress64; return table; }(); constexpr bool IsValidSvcTable(const std::array<SvcTableEntry, NumSupervisorCalls> &table) { for (size_t i = 0; i < NumSupervisorCalls; i++) { if (table[i] != nullptr) { return true; } } return false; } static_assert(IsValidSvcTable(SvcTable64Impl)); static_assert(IsValidSvcTable(SvcTable64From32Impl)); } constinit const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64 = SvcTable64Impl; constinit const std::array<SvcTableEntry, NumSupervisorCalls> SvcTable64From32 = SvcTable64From32Impl; void PatchSvcTableEntry(const SvcTableEntry *table, u32 id, SvcTableEntry entry); namespace { /* NOTE: Although the SVC tables are constants, our global constructor will run before .rodata is protected R--. */ class SvcTablePatcher { private: using SvcTable = std::array<SvcTableEntry, NumSupervisorCalls>; private: static SvcTablePatcher s_instance; private: ALWAYS_INLINE const SvcTableEntry *GetTableData(const SvcTable *table) { if (table != nullptr) { return table->data(); } else { return nullptr; } } NOINLINE void PatchTables(const SvcTableEntry *table_64, const SvcTableEntry *table_64_from_32) { /* Get the target firmware. */ const auto target_fw = kern::GetTargetFirmware(); /* 10.0.0 broke the ABI for QueryIoMapping, and renamed it to QueryMemoryMapping. */ if (target_fw < TargetFirmware_10_0_0) { if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_QueryMemoryMapping, LegacyQueryIoMapping::Call64); } if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_QueryMemoryMapping, LegacyQueryIoMapping::Call64From32); } } /* 6.0.0 broke the ABI for GetFutureThreadInfo, and renamed it to GetDebugFutureThreadInfo. */ if (target_fw < TargetFirmware_6_0_0) { static_assert(svc::SvcId_GetDebugFutureThreadInfo == svc::SvcId_LegacyGetFutureThreadInfo); if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_GetDebugFutureThreadInfo, LegacyGetFutureThreadInfo::Call64); } if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_GetDebugFutureThreadInfo, LegacyGetFutureThreadInfo::Call64From32); } } /* 3.0.0 broke the ABI for ContinueDebugEvent. */ if (target_fw < TargetFirmware_3_0_0) { if (table_64) { ::ams::kern::svc::PatchSvcTableEntry(table_64, svc::SvcId_ContinueDebugEvent, LegacyContinueDebugEvent::Call64); } if (table_64_from_32) { ::ams::kern::svc::PatchSvcTableEntry(table_64_from_32, svc::SvcId_ContinueDebugEvent, LegacyContinueDebugEvent::Call64From32); } } } public: SvcTablePatcher(const SvcTable *table_64, const SvcTable *table_64_from_32) { PatchTables(GetTableData(table_64), GetTableData(table_64_from_32)); } }; SvcTablePatcher SvcTablePatcher::s_instance(std::addressof(SvcTable64), std::addressof(SvcTable64From32)); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_atomics_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #define ATOMICS_AP0_TRIGGER 0x000 #define ATOMICS_AP0_RESULT(id) (0xc00 + id * 4) #define TRIGGER_CMD_GET 4 ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_bpmp_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> /* Message Flags */ #define BPMP_MSG_DO_ACK (1 << 0) #define BPMP_MSG_RING_DOORBELL (1 << 1) /* Messages */ #define MRQ_PING 0 #define MRQ_ENABLE_SUSPEND 17 #define MRQ_CPU_PMIC_SELECT 28 /* BPMP Power states. */ #define TEGRA_BPMP_PM_CC1 9 #define TEGRA_BPMP_PM_CC4 12 #define TEGRA_BPMP_PM_CC6 14 #define TEGRA_BPMP_PM_CC7 15 #define TEGRA_BPMP_PM_SC1 17 #define TEGRA_BPMP_PM_SC2 18 #define TEGRA_BPMP_PM_SC3 19 #define TEGRA_BPMP_PM_SC4 20 #define TEGRA_BPMP_PM_SC7 23 /* Channel states. */ #define CH_MASK(ch) (0x3u << ((ch) * 2)) #define SL_SIGL(ch) (0x0u << ((ch) * 2)) #define SL_QUED(ch) (0x1u << ((ch) * 2)) #define MA_FREE(ch) (0x2u << ((ch) * 2)) #define MA_ACKD(ch) (0x3u << ((ch) * 2)) constexpr inline int MessageSize = 0x80; constexpr inline int MessageDataSizeMax = 0x78; struct MailboxData { s32 code; s32 flags; u8 data[MessageDataSizeMax]; }; static_assert(ams::util::is_pod<MailboxData>::value); static_assert(sizeof(MailboxData) == MessageSize); struct ChannelData { MailboxData *ib; MailboxData *ob; }; ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_ictlr_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #define ICTLR_REG_BASE(irq) ((((irq) - 32) >> 5) * 0x100) #define ICTLR_FIR_SET(irq) (ICTLR_REG_BASE(irq) + 0x18) #define ICTLR_FIR_CLR(irq) (ICTLR_REG_BASE(irq) + 0x1c) #define FIR_BIT(irq) (1 << ((irq) & 0x1f)) #define INT_GIC_BASE (0) #define INT_PRI_BASE (INT_GIC_BASE + 32) #define INT_SHR_SEM_OUTBOX_IBF (INT_PRI_BASE + 6) ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) || defined(MESOSPHERE_BUILD_FOR_AUDITING) #define MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT #endif namespace ams::kern::board::nintendo::nx { namespace { /* Definitions. */ constexpr size_t PageDirectorySize = KPageTableManager::PageTableSize; constexpr size_t PageTableSize = KPageTableManager::PageTableSize; static_assert(PageDirectorySize == PageSize); constexpr size_t AsidCount = 0x80; constexpr size_t PhysicalAddressBits = 34; constexpr size_t PhysicalAddressMask = (1ul << PhysicalAddressBits) - 1ul; constexpr size_t DeviceVirtualAddressBits = 34; constexpr size_t DeviceVirtualAddressMask = (1ul << DeviceVirtualAddressBits) - 1ul; constexpr size_t DevicePageBits = 12; constexpr size_t DevicePageSize = (1ul << DevicePageBits); static_assert(DevicePageSize == PageSize); constexpr size_t DeviceLargePageBits = 22; constexpr size_t DeviceLargePageSize = (1ul << DeviceLargePageBits); static_assert(DeviceLargePageSize % DevicePageSize == 0); constexpr size_t DeviceRegionBits = 32; constexpr size_t DeviceRegionSize = (1ul << DeviceRegionBits); static_assert(DeviceRegionSize % DeviceLargePageSize == 0); constexpr size_t DeviceAsidRegisterOffsets[] = { [ams::svc::DeviceName_Afi] = MC_SMMU_AFI_ASID, [ams::svc::DeviceName_Avpc] = MC_SMMU_AVPC_ASID, [ams::svc::DeviceName_Dc] = MC_SMMU_DC_ASID, [ams::svc::DeviceName_Dcb] = MC_SMMU_DCB_ASID, [ams::svc::DeviceName_Hc] = MC_SMMU_HC_ASID, [ams::svc::DeviceName_Hda] = MC_SMMU_HDA_ASID, [ams::svc::DeviceName_Isp2] = MC_SMMU_ISP2_ASID, [ams::svc::DeviceName_MsencNvenc] = MC_SMMU_MSENC_NVENC_ASID, [ams::svc::DeviceName_Nv] = MC_SMMU_NV_ASID, [ams::svc::DeviceName_Nv2] = MC_SMMU_NV2_ASID, [ams::svc::DeviceName_Ppcs] = MC_SMMU_PPCS_ASID, [ams::svc::DeviceName_Sata] = MC_SMMU_SATA_ASID, [ams::svc::DeviceName_Vi] = MC_SMMU_VI_ASID, [ams::svc::DeviceName_Vic] = MC_SMMU_VIC_ASID, [ams::svc::DeviceName_XusbHost] = MC_SMMU_XUSB_HOST_ASID, [ams::svc::DeviceName_XusbDev] = MC_SMMU_XUSB_DEV_ASID, [ams::svc::DeviceName_Tsec] = MC_SMMU_TSEC_ASID, [ams::svc::DeviceName_Ppcs1] = MC_SMMU_PPCS1_ASID, [ams::svc::DeviceName_Dc1] = MC_SMMU_DC1_ASID, [ams::svc::DeviceName_Sdmmc1a] = MC_SMMU_SDMMC1A_ASID, [ams::svc::DeviceName_Sdmmc2a] = MC_SMMU_SDMMC2A_ASID, [ams::svc::DeviceName_Sdmmc3a] = MC_SMMU_SDMMC3A_ASID, [ams::svc::DeviceName_Sdmmc4a] = MC_SMMU_SDMMC4A_ASID, [ams::svc::DeviceName_Isp2b] = MC_SMMU_ISP2B_ASID, [ams::svc::DeviceName_Gpu] = MC_SMMU_GPU_ASID, [ams::svc::DeviceName_Gpub] = MC_SMMU_GPUB_ASID, [ams::svc::DeviceName_Ppcs2] = MC_SMMU_PPCS2_ASID, [ams::svc::DeviceName_Nvdec] = MC_SMMU_NVDEC_ASID, [ams::svc::DeviceName_Ape] = MC_SMMU_APE_ASID, [ams::svc::DeviceName_Se] = MC_SMMU_SE_ASID, [ams::svc::DeviceName_Nvjpg] = MC_SMMU_NVJPG_ASID, [ams::svc::DeviceName_Hc1] = MC_SMMU_HC1_ASID, [ams::svc::DeviceName_Se1] = MC_SMMU_SE1_ASID, [ams::svc::DeviceName_Axiap] = MC_SMMU_AXIAP_ASID, [ams::svc::DeviceName_Etr] = MC_SMMU_ETR_ASID, [ams::svc::DeviceName_Tsecb] = MC_SMMU_TSECB_ASID, [ams::svc::DeviceName_Tsec1] = MC_SMMU_TSEC1_ASID, [ams::svc::DeviceName_Tsecb1] = MC_SMMU_TSECB1_ASID, [ams::svc::DeviceName_Nvdec1] = MC_SMMU_NVDEC1_ASID, }; static_assert(util::size(DeviceAsidRegisterOffsets) == ams::svc::DeviceName_Count); constexpr bool DeviceAsidRegistersValid = [] { for (size_t i = 0; i < ams::svc::DeviceName_Count; i++) { if (DeviceAsidRegisterOffsets[i] == 0 || !util::IsAligned(DeviceAsidRegisterOffsets[i], sizeof(u32))) { return false; } } return true; }(); static_assert(DeviceAsidRegistersValid); constexpr ALWAYS_INLINE int GetDeviceAsidRegisterOffset(ams::svc::DeviceName dev) { if (dev < ams::svc::DeviceName_Count) { return DeviceAsidRegisterOffsets[dev]; } else { return -1; } } constexpr ams::svc::DeviceName HsDevices[] = { ams::svc::DeviceName_Afi, ams::svc::DeviceName_Dc, ams::svc::DeviceName_Dcb, ams::svc::DeviceName_Hda, ams::svc::DeviceName_Isp2, ams::svc::DeviceName_Sata, ams::svc::DeviceName_Vi, ams::svc::DeviceName_XusbHost, ams::svc::DeviceName_XusbDev, ams::svc::DeviceName_Tsec, ams::svc::DeviceName_Dc1, ams::svc::DeviceName_Sdmmc1a, ams::svc::DeviceName_Sdmmc2a, ams::svc::DeviceName_Sdmmc3a, ams::svc::DeviceName_Sdmmc4a, ams::svc::DeviceName_Isp2b, ams::svc::DeviceName_Gpu, ams::svc::DeviceName_Gpub, ams::svc::DeviceName_Axiap, ams::svc::DeviceName_Etr, ams::svc::DeviceName_Tsecb, ams::svc::DeviceName_Tsec1, ams::svc::DeviceName_Tsecb1, }; constexpr size_t NumHsDevices = util::size(HsDevices); constexpr u64 HsDeviceMask = [] { u64 mask = 0; for (size_t i = 0; i < NumHsDevices; i++) { mask |= 1ul << HsDevices[i]; } return mask; }(); constexpr ALWAYS_INLINE bool IsHsSupported(ams::svc::DeviceName dv) { return (HsDeviceMask & (1ul << dv)) != 0; } constexpr ALWAYS_INLINE bool IsValidPhysicalAddress(KPhysicalAddress addr) { return (static_cast<u64>(GetInteger(addr)) & ~PhysicalAddressMask) == 0; } constexpr struct { u64 start; u64 end; } SmmuSupportedRanges[] = { [ams::svc::DeviceName_Afi] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Avpc] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Dc] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Dcb] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Hc] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Hda] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Isp2] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_MsencNvenc] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Nv] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Nv2] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Ppcs] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Sata] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Vi] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Vic] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_XusbHost] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_XusbDev] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Tsec] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Ppcs1] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Dc1] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Sdmmc1a] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Sdmmc2a] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Sdmmc3a] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Sdmmc4a] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Isp2b] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Gpu] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Gpub] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Ppcs2] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Nvdec] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Ape] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Se] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Nvjpg] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Hc1] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Se1] = { 0x00000000ul, 0x0FFFFFFFFul }, [ams::svc::DeviceName_Axiap] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Etr] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Tsecb] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Tsec1] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Tsecb1] = { 0x00000000ul, 0x3FFFFFFFFul }, [ams::svc::DeviceName_Nvdec1] = { 0x00000000ul, 0x0FFFFFFFFul }, }; static_assert(util::size(SmmuSupportedRanges) == ams::svc::DeviceName_Count); constexpr bool IsAttachable(ams::svc::DeviceName device_name, u64 space_address, u64 space_size) { if (0 <= device_name && device_name < ams::svc::DeviceName_Count) { const auto &range = SmmuSupportedRanges[device_name]; return range.start <= space_address && (space_address + space_size - 1) <= range.end; } return false; } /* Types. */ class EntryBase { protected: enum Bit : u32 { Bit_Table = 28, Bit_NonSecure = 29, Bit_Writeable = 30, Bit_Readable = 31, }; private: u32 m_value; protected: constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const { return (m_value & (1u << n)); } template<Bit... Bits> constexpr ALWAYS_INLINE u32 SelectBits() const { constexpr u32 Mask = ((1u << Bits) | ...); return m_value & Mask; } constexpr ALWAYS_INLINE bool GetBit(Bit n) const { return this->SelectBit(n) != 0; } static constexpr ALWAYS_INLINE u32 EncodeBit(Bit n, bool en) { return en ? (1u << n) : 0; } static constexpr ALWAYS_INLINE u32 EncodeValue(bool r, bool w, bool ns, KPhysicalAddress addr, bool t) { return EncodeBit(Bit_Readable, r) | EncodeBit(Bit_Writeable, w) | EncodeBit(Bit_NonSecure, ns) | EncodeBit(Bit_Table, t) | static_cast<u32>(addr >> DevicePageBits); } ALWAYS_INLINE void SetValue(u32 v) { /* Prevent re-ordering around entry modifications. */ __asm__ __volatile__("" ::: "memory"); m_value = v; __asm__ __volatile__("" ::: "memory"); } public: static constexpr ALWAYS_INLINE u32 EncodePtbDataValue(KPhysicalAddress addr) { return EncodeValue(true, true, true, addr, false); } public: constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBit(Bit_NonSecure); } constexpr ALWAYS_INLINE bool IsWriteable() const { return this->GetBit(Bit_Writeable); } constexpr ALWAYS_INLINE bool IsReadable() const { return this->GetBit(Bit_Readable); } constexpr ALWAYS_INLINE bool IsValid() const { return this->SelectBits<Bit_Readable, Bit_Writeable>(); } constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBits<Bit_Readable, Bit_Writeable, Bit_NonSecure>(); } constexpr ALWAYS_INLINE KPhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; } ALWAYS_INLINE void InvalidateAttributes() { this->SetValue(m_value & ~(0xCu << 28)); } ALWAYS_INLINE void Invalidate() { this->SetValue(0); } }; class PageDirectoryEntry : public EntryBase { public: constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBit(Bit_Table); } ALWAYS_INLINE void SetTable(bool r, bool w, bool ns, KPhysicalAddress addr) { MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DevicePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, true)); } ALWAYS_INLINE void SetLargePage(bool r, bool w, bool ns, KPhysicalAddress addr) { MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DeviceLargePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, false)); } }; class PageTableEntry : public EntryBase { public: ALWAYS_INLINE void SetPage(bool r, bool w, bool ns, KPhysicalAddress addr) { MESOSPHERE_ASSERT(IsValidPhysicalAddress(addr)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), DevicePageSize)); this->SetValue(EncodeValue(r, w, ns, addr, true)); } }; class KDeviceAsidManager { private: using WordType = u32; static constexpr u8 ReservedAsids[] = { 0, 1, 2, 3 }; static constexpr size_t NumReservedAsids = util::size(ReservedAsids); static constexpr size_t BitsPerWord = BITSIZEOF(WordType); static constexpr size_t NumWords = AsidCount / BitsPerWord; static constexpr WordType FullWord = ~WordType(0u); private: WordType m_state[NumWords]; KLightLock m_lock; private: constexpr void ReserveImpl(u8 asid) { m_state[asid / BitsPerWord] |= (1u << (asid % BitsPerWord)); } constexpr void ReleaseImpl(u8 asid) { m_state[asid / BitsPerWord] &= ~(1u << (asid % BitsPerWord)); } static constexpr ALWAYS_INLINE WordType ClearLeadingZero(WordType value) { return __builtin_clzll(value) - (BITSIZEOF(unsigned long long) - BITSIZEOF(WordType)); } public: constexpr KDeviceAsidManager() : m_state(), m_lock() { for (size_t i = 0; i < NumReservedAsids; i++) { this->ReserveImpl(ReservedAsids[i]); } } Result Reserve(u8 *out, size_t num_desired) { KScopedLightLock lk(m_lock); MESOSPHERE_ASSERT(num_desired > 0); size_t num_reserved = 0; for (size_t i = 0; i < NumWords; i++) { while (m_state[i] != FullWord) { const WordType clear_bit = (m_state[i] + 1) ^ (m_state[i]); m_state[i] |= clear_bit; out[num_reserved++] = static_cast<u8>(BitsPerWord * i + BitsPerWord - 1 - ClearLeadingZero(clear_bit)); R_SUCCEED_IF(num_reserved == num_desired); } } /* We failed, so free what we reserved. */ for (size_t i = 0; i < num_reserved; i++) { this->ReleaseImpl(out[i]); } R_THROW(svc::ResultOutOfResource()); } void Release(u8 asid) { KScopedLightLock lk(m_lock); this->ReleaseImpl(asid); } }; /* Globals. */ constinit KLightLock g_lock; constinit u8 g_reserved_asid; constinit KPhysicalAddress g_memory_controller_address{Null<KPhysicalAddress>}; constinit KPhysicalAddress g_reserved_table_phys_addr{Null<KPhysicalAddress>}; constinit KDeviceAsidManager g_asid_manager; constinit u32 g_saved_page_tables[AsidCount]; constinit u32 g_saved_asid_registers[ams::svc::DeviceName_Count]; /* Memory controller access functionality. */ void WriteMcRegister(size_t offset, u32 value) { KSystemControl::WriteRegisterPrivileged(GetInteger(g_memory_controller_address) + offset, value); } u32 ReadMcRegister(size_t offset) { return KSystemControl::ReadRegisterPrivileged(GetInteger(g_memory_controller_address) + offset); } /* Memory controller interrupt functionality. */ constexpr const char * const MemoryControllerClientNames[138] = { [ 0] = "csr_ptcr (ptc)", [ 1] = "csr_display0a (dc)", [ 2] = "csr_display0ab (dcb)", [ 3] = "csr_display0b (dc)", [ 4] = "csr_display0bb (dcb)", [ 5] = "csr_display0c (dc)", [ 6] = "csr_display0cb (dcb)", [ 7] = "Unknown Client", [ 8] = "Unknown Client", [ 9] = "Unknown Client", [ 10] = "Unknown Client", [ 11] = "Unknown Client", [ 12] = "Unknown Client", [ 13] = "Unknown Client", [ 14] = "csr_afir (afi)", [ 15] = "csr_avpcarm7r (avpc)", [ 16] = "csr_displayhc (dc)", [ 17] = "csr_displayhcb (dcb)", [ 18] = "Unknown Client", [ 19] = "Unknown Client", [ 20] = "Unknown Client", [ 21] = "csr_hdar (hda)", [ 22] = "csr_host1xdmar (hc)", [ 23] = "csr_host1xr (hc)", [ 24] = "Unknown Client", [ 25] = "Unknown Client", [ 26] = "Unknown Client", [ 27] = "Unknown Client", [ 28] = "csr_nvencsrd (nvenc)", [ 29] = "csr_ppcsahbdmar (ppcs)", [ 30] = "csr_ppcsahbslvr (ppcs)", [ 31] = "csr_satar (sata)", [ 32] = "Unknown Client", [ 33] = "Unknown Client", [ 34] = "Unknown Client", [ 35] = "Unknown Client", [ 36] = "Unknown Client", [ 37] = "Unknown Client", [ 38] = "Unknown Client", [ 39] = "csr_mpcorer (cpu)", [ 40] = "Unknown Client", [ 41] = "Unknown Client", [ 42] = "Unknown Client", [ 43] = "csw_nvencswr (nvenc)", [ 44] = "Unknown Client", [ 45] = "Unknown Client", [ 46] = "Unknown Client", [ 47] = "Unknown Client", [ 48] = "Unknown Client", [ 49] = "csw_afiw (afi)", [ 50] = "csw_avpcarm7w (avpc)", [ 51] = "Unknown Client", [ 52] = "Unknown Client", [ 53] = "csw_hdaw (hda)", [ 54] = "csw_host1xw (hc)", [ 55] = "Unknown Client", [ 56] = "Unknown Client", [ 57] = "csw_mpcorew (cpu)", [ 58] = "Unknown Client", [ 59] = "csw_ppcsahbdmaw (ppcs)", [ 60] = "csw_ppcsahbslvw (ppcs)", [ 61] = "csw_sataw (sata)", [ 62] = "Unknown Client", [ 63] = "Unknown Client", [ 64] = "Unknown Client", [ 65] = "Unknown Client", [ 66] = "Unknown Client", [ 67] = "Unknown Client", [ 68] = "csr_ispra (isp2)", [ 69] = "Unknown Client", [ 70] = "csw_ispwa (isp2)", [ 71] = "csw_ispwb (isp2)", [ 72] = "Unknown Client", [ 73] = "Unknown Client", [ 74] = "csr_xusb_hostr (xusb_host)", [ 75] = "csw_xusb_hostw (xusb_host)", [ 76] = "csr_xusb_devr (xusb_dev)", [ 77] = "csw_xusb_devw (xusb_dev)", [ 78] = "csr_isprab (isp2b)", [ 79] = "Unknown Client", [ 80] = "csw_ispwab (isp2b)", [ 81] = "csw_ispwbb (isp2b)", [ 82] = "Unknown Client", [ 83] = "Unknown Client", [ 84] = "csr_tsecsrd (tsec)", [ 85] = "csw_tsecswr (tsec)", [ 86] = "csr_a9avpscr (a9avp)", [ 87] = "csw_a9avpscw (a9avp)", [ 88] = "csr_gpusrd (gpu)", [ 89] = "csw_gpuswr (gpu)", [ 90] = "csr_displayt (dc)", [ 91] = "Unknown Client", [ 92] = "Unknown Client", [ 93] = "Unknown Client", [ 94] = "Unknown Client", [ 95] = "Unknown Client", [ 96] = "csr_sdmmcra (sdmmc1a)", [ 97] = "csr_sdmmcraa (sdmmc2a)", [ 98] = "csr_sdmmcr (sdmmc3a)", [ 99] = "csr_sdmmcrab (sdmmc4a)", [100] = "csw_sdmmcwa (sdmmc1a)", [101] = "csw_sdmmcwaa (sdmmc2a)", [102] = "csw_sdmmcw (sdmmc3a)", [103] = "csw_sdmmcwab (sdmmc4a)", [104] = "Unknown Client", [105] = "Unknown Client", [106] = "Unknown Client", [107] = "Unknown Client", [108] = "csr_vicsrd (vic)", [109] = "csw_vicswr (vic)", [110] = "Unknown Client", [111] = "Unknown Client", [112] = "Unknown Client", [113] = "Unknown Client", [114] = "csw_viw (vi)", [115] = "csr_displayd (dc)", [116] = "Unknown Client", [117] = "Unknown Client", [118] = "Unknown Client", [119] = "Unknown Client", [120] = "csr_nvdecsrd (nvdec)", [121] = "csw_nvdecswr (nvdec)", [122] = "csr_aper (ape)", [123] = "csw_apew (ape)", [124] = "Unknown Client", [125] = "Unknown Client", [126] = "csr_nvjpgsrd (nvjpg)", [127] = "csw_nvjpgswr (nvjpg)", [128] = "csr_sesrd (se)", [129] = "csw_seswr (se)", [130] = "csr_axiapr (axiap)", [131] = "csw_axiapw (axiap)", [132] = "csr_etrr (etr)", [133] = "csw_etrw (etr)", [134] = "csr_tsecsrdb (tsecb)", [135] = "csw_tsecswrb (tsecb)", [136] = "csr_gpusrd2 (gpu)", [137] = "csw_gpuswr2 (gpu)", }; constexpr const char * GetMemoryControllerClientName(size_t i) { if (i < util::size(MemoryControllerClientNames)) { return MemoryControllerClientNames[i]; } return "Unknown Client"; } constexpr const char * const MemoryControllerErrorTypes[8] = { "RSVD", "Unknown", "DECERR_EMEM", "SECURITY_TRUSTZONE", "SECURITY_CARVEOUT", "Unknown", "INVALID_SMMU_PAGE", "Unknown", }; class KMemoryControllerInterruptTask : public KInterruptTask { public: constexpr KMemoryControllerInterruptTask() : KInterruptTask() { /* ... */ } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); return this; } virtual void DoTask() override { #if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT) { /* Clear the interrupt when we're done. */ ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController, GetCurrentCoreId()); }; /* Get and clear the interrupt status. */ u32 int_status, err_status, err_adr; { int_status = ReadMcRegister(MC_INTSTATUS); err_status = ReadMcRegister(MC_ERR_STATUS); err_adr = ReadMcRegister(MC_ERR_ADR); WriteMcRegister(MC_INTSTATUS, int_status); } /* Print the interrupt. */ { constexpr auto GetBits = [](u32 value, size_t ofs, size_t count) ALWAYS_INLINE_LAMBDA { return (value >> ofs) & ((1u << count) - 1); }; constexpr auto GetBit = [GetBits](u32 value, size_t ofs) ALWAYS_INLINE_LAMBDA { return (value >> ofs) & 1u; }; MESOSPHERE_RELEASE_LOG("sMMU error interrupt\n"); MESOSPHERE_RELEASE_LOG(" MC_INTSTATUS=%08x\n", int_status); MESOSPHERE_RELEASE_LOG(" DECERR_GENERALIZED_CARVEOUT=%d\n", GetBit(int_status, 17)); MESOSPHERE_RELEASE_LOG(" DECERR_MTS=%d\n", GetBit(int_status, 16)); MESOSPHERE_RELEASE_LOG(" SECERR_SEC=%d\n", GetBit(int_status, 13)); MESOSPHERE_RELEASE_LOG(" DECERR_VPR=%d\n", GetBit(int_status, 12)); MESOSPHERE_RELEASE_LOG(" INVALID_APB_ASID_UPDATE=%d\n", GetBit(int_status, 11)); MESOSPHERE_RELEASE_LOG(" INVALID_SMMU_PAGE=%d\n", GetBit(int_status, 10)); MESOSPHERE_RELEASE_LOG(" ARBITRATION_EMEM=%d\n", GetBit(int_status, 9)); MESOSPHERE_RELEASE_LOG(" SECURITY_VIOLATION=%d\n", GetBit(int_status, 8)); MESOSPHERE_RELEASE_LOG(" DECERR_EMEM=%d\n", GetBit(int_status, 6)); MESOSPHERE_RELEASE_LOG(" MC_ERRSTATUS=%08x\n", err_status); MESOSPHERE_RELEASE_LOG(" ERR_TYPE=%d (%s)\n", GetBits(err_status, 28, 3), MemoryControllerErrorTypes[GetBits(err_status, 28, 3)]); MESOSPHERE_RELEASE_LOG(" ERR_INVALID_SMMU_PAGE_READABLE=%d\n", GetBit (err_status, 27)); MESOSPHERE_RELEASE_LOG(" ERR_INVALID_SMMU_PAGE_WRITABLE=%d\n", GetBit (err_status, 26)); MESOSPHERE_RELEASE_LOG(" ERR_INVALID_SMMU_NONSECURE=%d\n", GetBit (err_status, 25)); MESOSPHERE_RELEASE_LOG(" ERR_ADR_HI=%x\n", GetBits(err_status, 20, 2)); MESOSPHERE_RELEASE_LOG(" ERR_SWAP=%d\n", GetBit (err_status, 18)); MESOSPHERE_RELEASE_LOG(" ERR_SECURITY=%d %s\n", GetBit (err_status, 17), GetBit(err_status, 17) ? "SECURE" : "NONSECURE"); MESOSPHERE_RELEASE_LOG(" ERR_RW=%d %s\n", GetBit (err_status, 16), GetBit(err_status, 16) ? "WRITE" : "READ"); MESOSPHERE_RELEASE_LOG(" ERR_ADR1=%x\n", GetBits(err_status, 12, 3)); MESOSPHERE_RELEASE_LOG(" ERR_ID=%d %s\n", GetBits(err_status, 0, 8), GetMemoryControllerClientName(GetBits(err_status, 0, 8))); MESOSPHERE_RELEASE_LOG(" MC_ERRADR=%08x\n", err_adr); MESOSPHERE_RELEASE_LOG(" ERR_ADR=%lx\n", (static_cast<u64>(GetBits(err_status, 20, 2)) << 32) | static_cast<u64>(err_adr)); MESOSPHERE_RELEASE_LOG("\n"); } } #endif } }; /* Interrupt task global. */ constinit KMemoryControllerInterruptTask g_mc_interrupt_task; /* Memory controller utilities. */ ALWAYS_INLINE void SmmuSynchronizationBarrier() { ReadMcRegister(MC_SMMU_CONFIG); } ALWAYS_INLINE void InvalidatePtc() { WriteMcRegister(MC_SMMU_PTC_FLUSH_0, 0); } ALWAYS_INLINE void InvalidatePtc(KPhysicalAddress address) { WriteMcRegister(MC_SMMU_PTC_FLUSH_1, (static_cast<u64>(GetInteger(address)) >> 32)); WriteMcRegister(MC_SMMU_PTC_FLUSH_0, (GetInteger(address) & 0xFFFFFFF0u) | 1u); } enum TlbFlushVaMatch : u32 { TlbFlushVaMatch_All = 0, TlbFlushVaMatch_Section = 2, TlbFlushVaMatch_Group = 3, }; static constexpr ALWAYS_INLINE u32 EncodeTlbFlushValue(bool match_asid, u8 asid, KDeviceVirtualAddress address, TlbFlushVaMatch match) { return ((match_asid ? 1u : 0u) << 31) | ((asid & 0x7F) << 24) | (((address & 0xFFC00000u) >> DevicePageBits)) | (match); } ALWAYS_INLINE void InvalidateTlb() { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(false, 0, 0, TlbFlushVaMatch_All)); } ALWAYS_INLINE void InvalidateTlb(u8 asid) { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, 0, TlbFlushVaMatch_All)); } ALWAYS_INLINE void InvalidateTlbSection(u8 asid, KDeviceVirtualAddress address) { return WriteMcRegister(MC_SMMU_TLB_FLUSH, EncodeTlbFlushValue(true, asid, address, TlbFlushVaMatch_Section)); } void SetTable(u8 asid, KPhysicalAddress address) { /* Write the table address. */ { KScopedLightLock lk(g_lock); WriteMcRegister(MC_SMMU_PTB_ASID, asid); WriteMcRegister(MC_SMMU_PTB_DATA, EntryBase::EncodePtbDataValue(address)); SmmuSynchronizationBarrier(); } /* Ensure consistency. */ InvalidatePtc(); InvalidateTlb(asid); SmmuSynchronizationBarrier(); } } void KDevicePageTable::Initialize() { /* Set the memory controller register address. */ g_memory_controller_address = KMemoryLayout::GetDevicePhysicalAddress(KMemoryRegionType_MemoryController); /* Allocate a page to use as a reserved/no device table. */ auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); const KVirtualAddress table_virt_addr = ptm.Allocate(); MESOSPHERE_ABORT_UNLESS(table_virt_addr != Null<KVirtualAddress>); const KPhysicalAddress table_phys_addr = GetPageTablePhysicalAddress(table_virt_addr); MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr)); ptm.Open(table_virt_addr, 1); /* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */ MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize)); g_reserved_table_phys_addr = table_phys_addr; /* Reserve an asid to correspond to no device. */ MESOSPHERE_R_ABORT_UNLESS(g_asid_manager.Reserve(std::addressof(g_reserved_asid), 1)); /* Set all asids to the reserved table. */ static_assert(AsidCount <= std::numeric_limits<u8>::max()); for (size_t i = 0; i < AsidCount; i++) { SetTable(static_cast<u8>(i), g_reserved_table_phys_addr); } /* Set all devices to the reserved asid. */ for (size_t i = 0; i < ams::svc::DeviceName_Count; i++) { u32 value = 0x80000000u; if (IsHsSupported(static_cast<ams::svc::DeviceName>(i))) { for (size_t t = 0; t < TableCount; t++) { value |= (g_reserved_asid << (BITSIZEOF(u8) * t)); } } else { value |= g_reserved_asid; } WriteMcRegister(GetDeviceAsidRegisterOffset(static_cast<ams::svc::DeviceName>(i)), value); SmmuSynchronizationBarrier(); } /* Ensure consistency. */ InvalidatePtc(); InvalidateTlb(); SmmuSynchronizationBarrier(); /* Clear int status. */ WriteMcRegister(MC_INTSTATUS, ReadMcRegister(MC_INTSTATUS)); /* If we're setting an interrupt handler, unmask all interrupts. */ #if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT) { WriteMcRegister(MC_INTMASK, 0x33D40); } #endif /* Enable the SMMU */ WriteMcRegister(MC_SMMU_CONFIG, 1); SmmuSynchronizationBarrier(); /* Install interrupt handler. */ #if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT) { MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(std::addressof(g_mc_interrupt_task), KInterruptName_MemoryController, GetCurrentCoreId(), KInterruptController::PriorityLevel_High, true, true)); } #endif } void KDevicePageTable::Lock() { g_lock.Lock(); } void KDevicePageTable::Unlock() { g_lock.Unlock(); } void KDevicePageTable::Sleep() { /* Save all page tables. */ for (size_t i = 0; i < AsidCount; ++i) { WriteMcRegister(MC_SMMU_PTB_ASID, i); SmmuSynchronizationBarrier(); g_saved_page_tables[i] = ReadMcRegister(MC_SMMU_PTB_DATA); } /* Save all asid registers. */ for (size_t i = 0; i < ams::svc::DeviceName_Count; ++i) { g_saved_asid_registers[i] = ReadMcRegister(GetDeviceAsidRegisterOffset(static_cast<ams::svc::DeviceName>(i))); } } void KDevicePageTable::Wakeup() { /* Synchronize. */ InvalidatePtc(); InvalidateTlb(); SmmuSynchronizationBarrier(); /* Disable the SMMU */ WriteMcRegister(MC_SMMU_CONFIG, 0); /* Restore the page tables. */ for (size_t i = 0; i < AsidCount; ++i) { WriteMcRegister(MC_SMMU_PTB_ASID, i); SmmuSynchronizationBarrier(); WriteMcRegister(MC_SMMU_PTB_DATA, g_saved_page_tables[i]); } SmmuSynchronizationBarrier(); /* Restore the asid registers. */ for (size_t i = 0; i < ams::svc::DeviceName_Count; ++i) { WriteMcRegister(GetDeviceAsidRegisterOffset(static_cast<ams::svc::DeviceName>(i)), g_saved_asid_registers[i]); SmmuSynchronizationBarrier(); } /* Synchronize. */ InvalidatePtc(); InvalidateTlb(); SmmuSynchronizationBarrier(); /* Enable the SMMU */ WriteMcRegister(MC_SMMU_CONFIG, 1); SmmuSynchronizationBarrier(); } /* Member functions. */ Result KDevicePageTable::Initialize(u64 space_address, u64 space_size) { /* Ensure space is valid. */ R_UNLESS(((space_address + space_size - 1) & ~DeviceVirtualAddressMask) == 0, svc::ResultInvalidMemoryRegion()); /* Determine extents. */ const size_t start_index = space_address / DeviceRegionSize; const size_t end_index = (space_address + space_size - 1) / DeviceRegionSize; /* Get the page table manager. */ auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Clear the tables. */ static_assert(TableCount == (1ul << DeviceVirtualAddressBits) / DeviceRegionSize); for (size_t i = 0; i < TableCount; ++i) { m_tables[i] = Null<KVirtualAddress>; } /* Ensure that we clean up the tables on failure. */ ON_RESULT_FAILURE { for (size_t i = start_index; i <= end_index; ++i) { if (m_tables[i] != Null<KVirtualAddress> && ptm.Close(m_tables[i], 1)) { ptm.Free(m_tables[i]); } } }; /* Allocate a table for all required indices. */ for (size_t i = start_index; i <= end_index; ++i) { const KVirtualAddress table_vaddr = ptm.Allocate(); R_UNLESS(table_vaddr != Null<KVirtualAddress>, svc::ResultOutOfMemory()); MESOSPHERE_ASSERT(IsValidPhysicalAddress(GetPageTablePhysicalAddress(table_vaddr))); ptm.Open(table_vaddr, 1); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageDirectorySize)); m_tables[i] = table_vaddr; } /* Clear asids. */ for (size_t i = 0; i < TableCount; ++i) { m_table_asids[i] = g_reserved_asid; } /* Reserve asids for the tables. */ R_TRY(g_asid_manager.Reserve(std::addressof(m_table_asids[start_index]), end_index - start_index + 1)); /* Associate tables with asids. */ for (size_t i = start_index; i <= end_index; ++i) { SetTable(m_table_asids[i], GetPageTablePhysicalAddress(m_tables[i])); } /* Set member variables. */ m_attached_device = 0; m_attached_value = (1u << 31) | m_table_asids[0]; m_detached_value = (1u << 31) | g_reserved_asid; m_hs_attached_value = (1u << 31); m_hs_detached_value = (1u << 31); for (size_t i = 0; i < TableCount; ++i) { m_hs_attached_value |= (m_table_asids[i] << (i * BITSIZEOF(u8))); m_hs_detached_value |= (g_reserved_asid << (i * BITSIZEOF(u8))); } /* We succeeded. */ R_SUCCEED(); } void KDevicePageTable::Finalize() { /* Get the page table manager. */ auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Detach from all devices. */ { KScopedLightLock lk(g_lock); for (size_t i = 0; i < ams::svc::DeviceName_Count; ++i) { const auto device_name = static_cast<ams::svc::DeviceName>(i); if ((m_attached_device & (1ul << device_name)) != 0) { WriteMcRegister(GetDeviceAsidRegisterOffset(device_name), IsHsSupported(device_name) ? m_hs_detached_value : m_detached_value); SmmuSynchronizationBarrier(); } } } /* Forcibly unmap all pages. */ this->UnmapImpl(0, (1ul << DeviceVirtualAddressBits), false); /* Release all asids. */ for (size_t i = 0; i < TableCount; ++i) { if (m_table_asids[i] != g_reserved_asid) { /* Set the table to the reserved table. */ SetTable(m_table_asids[i], g_reserved_table_phys_addr); /* Close the table. */ const KVirtualAddress table_vaddr = m_tables[i]; MESOSPHERE_ASSERT(ptm.GetRefCount(table_vaddr) == 1); MESOSPHERE_ABORT_UNLESS(ptm.Close(table_vaddr, 1)); /* Free the table. */ ptm.Free(table_vaddr); /* Release the asid. */ g_asid_manager.Release(m_table_asids[i]); } } } Result KDevicePageTable::Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size) { /* Validate the device name. */ R_UNLESS(0 <= device_name, svc::ResultNotFound()); R_UNLESS(device_name < ams::svc::DeviceName_Count, svc::ResultNotFound()); /* Check that the device isn't already attached. */ R_UNLESS((m_attached_device & (1ul << device_name)) == 0, svc::ResultBusy()); /* Validate that the space is allowed for the device. */ const size_t end_index = (space_address + space_size - 1) / DeviceRegionSize; R_UNLESS(end_index == 0 || IsHsSupported(device_name), svc::ResultInvalidCombination()); /* Validate that the device can be attached. */ R_UNLESS(IsAttachable(device_name, space_address, space_size), svc::ResultInvalidCombination()); /* Get the device asid register offset. */ const int reg_offset = GetDeviceAsidRegisterOffset(device_name); R_UNLESS(reg_offset >= 0, svc::ResultNotFound()); /* Determine the old/new values. */ const u32 old_val = IsHsSupported(device_name) ? m_hs_detached_value : m_detached_value; const u32 new_val = IsHsSupported(device_name) ? m_hs_attached_value : m_attached_value; /* Attach the device. */ { KScopedLightLock lk(g_lock); /* Validate that the device is unclaimed. */ R_UNLESS((ReadMcRegister(reg_offset) | (1u << 31)) == (old_val | (1u << 31)), svc::ResultBusy()); /* Claim the device. */ WriteMcRegister(reg_offset, new_val); SmmuSynchronizationBarrier(); /* Ensure that we claimed it successfully. */ if (ReadMcRegister(reg_offset) != new_val) { WriteMcRegister(reg_offset, old_val); SmmuSynchronizationBarrier(); R_THROW(svc::ResultNotFound()); } } /* Mark the device as attached. */ m_attached_device |= (1ul << device_name); R_SUCCEED(); } Result KDevicePageTable::Detach(ams::svc::DeviceName device_name) { /* Validate the device name. */ R_UNLESS(0 <= device_name, svc::ResultNotFound()); R_UNLESS(device_name < ams::svc::DeviceName_Count, svc::ResultNotFound()); /* Check that the device is already attached. */ R_UNLESS((m_attached_device & (1ul << device_name)) != 0, svc::ResultInvalidState()); /* Get the device asid register offset. */ const int reg_offset = GetDeviceAsidRegisterOffset(device_name); R_UNLESS(reg_offset >= 0, svc::ResultNotFound()); /* Determine the old/new values. */ const u32 old_val = IsHsSupported(device_name) ? m_hs_attached_value : m_attached_value; const u32 new_val = IsHsSupported(device_name) ? m_hs_detached_value : m_detached_value; /* When not building for debug, the old value might be unused. */ AMS_UNUSED(old_val); /* Detach the device. */ { KScopedLightLock lk(g_lock); /* Check that the device is attached. */ MESOSPHERE_ASSERT(ReadMcRegister(reg_offset) == old_val); /* Release the device. */ WriteMcRegister(reg_offset, new_val); SmmuSynchronizationBarrier(); /* Check that the device was released. */ MESOSPHERE_ASSERT((ReadMcRegister(reg_offset) | (1u << 31)) == (new_val | 1u << 31)); } /* Mark the device as detached. */ m_attached_device &= ~(1ul << device_name); R_SUCCEED(); } bool KDevicePageTable::IsFree(KDeviceVirtualAddress address, u64 size) const { MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* Walk the directory, looking for entries. */ u64 remaining = size; while (remaining > 0) { const size_t l0_index = (address / DeviceRegionSize); const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize; const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize; const PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]); if (l1 == nullptr || !l1[l1_index].IsValid()) { const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); address += DevicePageSize * map_count; remaining -= DevicePageSize * map_count; } else if (l1[l1_index].IsTable()) { const PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress())); const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); for (size_t i = 0; i < map_count; ++i) { if (l2[l2_index + i].IsValid()) { return false; } } address += DevicePageSize * map_count; remaining -= DevicePageSize * map_count; } else { /* If we have an entry, we're not free. */ return false; } } return true; } Result KDevicePageTable::MapDevicePage(KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm) { /* Ensure that the physical address is valid. */ R_UNLESS(IsValidPhysicalAddress(static_cast<u64>(GetInteger(phys_addr)) + size - 1), svc::ResultInvalidCurrentMemory()); MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* Get the memory manager and page table manager. */ KMemoryManager &mm = Kernel::GetMemoryManager(); KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Cache permissions. */ const bool read = (device_perm & ams::svc::MemoryPermission_Read) != 0; const bool write = (device_perm & ams::svc::MemoryPermission_Write) != 0; /* Walk the directory. */ u64 remaining = size; while (remaining > 0) { const size_t l0_index = (address / DeviceRegionSize); const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize; const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize; /* Get and validate l1. */ PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]); MESOSPHERE_ASSERT(l1 != nullptr); /* Setup an l1 table/entry, if needed. */ if (!l1[l1_index].IsTable()) { /* Check that an entry doesn't already exist. */ MESOSPHERE_ASSERT(!l1[l1_index].IsValid()); /* If we can make an l1 entry, do so. */ if (l2_index == 0 && util::IsAligned(GetInteger(phys_addr), DeviceLargePageSize) && remaining >= DeviceLargePageSize) { /* Set the large page. */ l1[l1_index].SetLargePage(read, write, true, phys_addr); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry))); /* Synchronize. */ InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index])))); InvalidateTlbSection(m_table_asids[l0_index], address); SmmuSynchronizationBarrier(); /* Open references to the pages. */ mm.Open(phys_addr, DeviceLargePageSize / PageSize); /* Advance. */ phys_addr += DeviceLargePageSize; address += DeviceLargePageSize; remaining -= DeviceLargePageSize; continue; } else { /* Make an l1 table. */ const KVirtualAddress table_vaddr = ptm.Allocate(); R_UNLESS(table_vaddr != Null<KVirtualAddress>, svc::ResultOutOfMemory()); MESOSPHERE_ASSERT(IsValidPhysicalAddress(GetPageTablePhysicalAddress(table_vaddr))); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(table_vaddr), PageTableSize)); /* Set the l1 table. */ l1[l1_index].SetTable(true, true, true, GetPageTablePhysicalAddress(table_vaddr)); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry))); /* Synchronize. */ InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index])))); InvalidateTlbSection(m_table_asids[l0_index], address); SmmuSynchronizationBarrier(); } } /* If we get to this point, l1 must be a table. */ MESOSPHERE_ASSERT(l1[l1_index].IsTable()); /* Map l2 entries. */ { PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress())); const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); /* Set the entries. */ for (size_t i = 0; i < map_count; ++i) { MESOSPHERE_ASSERT(!l2[l2_index + i].IsValid()); l2[l2_index + i].SetPage(read, write, true, phys_addr + DevicePageSize * i); /* Add a reference to the l2 page (from the l2 entry page). */ ptm.Open(KVirtualAddress(l2), 1); } MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry))); /* Invalidate the page table cache. */ for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) { InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l2[i])))); } /* Synchronize. */ InvalidateTlbSection(m_table_asids[l0_index], address); SmmuSynchronizationBarrier(); /* Open references to the pages. */ mm.Open(phys_addr, (map_count * DevicePageSize) / PageSize); /* Advance. */ phys_addr += map_count * DevicePageSize; address += map_count * DevicePageSize; remaining -= map_count * DevicePageSize; } } R_SUCCEED(); } Result KDevicePageTable::MapImpl(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) { /* Ensure that the region we're mapping to is free. */ R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory()); /* Ensure that if we fail, we unmap anything we mapped. */ ON_RESULT_FAILURE { this->UnmapImpl(device_address, size, false); }; /* Iterate, mapping device pages. */ KDeviceVirtualAddress cur_addr = device_address; size_t mapped_size = 0; while (mapped_size < size) { /* Map the next contiguous range. */ size_t cur_size; { /* Get the current contiguous range. */ KPageTableBase::MemoryRange contig_range; R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned)); /* Ensure we close the range when we're done. */ ON_SCOPE_EXIT { contig_range.Close(); }; /* Get the current size. */ cur_size = contig_range.GetSize(); /* Map the device page. */ R_TRY(this->MapDevicePage(contig_range.GetAddress(), cur_size, cur_addr, device_perm)); } /* Advance. */ cur_addr += cur_size; mapped_size += cur_size; } R_SUCCEED(); } void KDevicePageTable::UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force) { MESOSPHERE_UNUSED(force); MESOSPHERE_ASSERT((address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* Get the memory manager and page table manager. */ KMemoryManager &mm = Kernel::GetMemoryManager(); KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager(); /* Make a page group for the pages we're closing. */ KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); /* Walk the directory. */ u64 remaining = size; while (remaining > 0) { const size_t l0_index = (address / DeviceRegionSize); const size_t l1_index = (address % DeviceRegionSize) / DeviceLargePageSize; const size_t l2_index = (address % DeviceLargePageSize) / DevicePageSize; /* Get and validate l1. */ PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]); /* Check if there's nothing mapped at l1. */ if (l1 == nullptr || !l1[l1_index].IsValid()) { const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); /* Advance. */ address += map_count * DevicePageSize; remaining -= map_count * DevicePageSize; } else if (l1[l1_index].IsTable()) { /* Dealing with an l1 table. */ PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress())); const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining / DevicePageSize); size_t num_closed = 0; /* Invalidate the attributes of all entries. */ for (size_t i = 0; i < map_count; ++i) { if (l2[l2_index + i].IsValid()) { l2[l2_index + i].InvalidateAttributes(); ++num_closed; } } MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l2[l2_index]), map_count * sizeof(PageTableEntry))); /* Invalidate the page table cache. */ for (size_t i = util::AlignDown(l2_index, 4); i <= util::AlignDown(l2_index + map_count - 1, 4); i += 4) { InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l2[i])))); } SmmuSynchronizationBarrier(); /* Close the memory manager's references to the pages. */ { KPhysicalAddress contig_phys_addr = Null<KPhysicalAddress>; size_t contig_count = 0; for (size_t i = 0; i < map_count; ++i) { /* Get the physical address. */ const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress(); MESOSPHERE_ASSERT(phys_addr == Null<KPhysicalAddress> || IsHeapPhysicalAddress(phys_addr)); /* Fully invalidate the entry. */ l2[l2_index + i].Invalidate(); if (contig_count == 0) { /* Ensure that our address/count is valid. */ contig_phys_addr = phys_addr; contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0; } else if (phys_addr == Null<KPhysicalAddress> || phys_addr != (contig_phys_addr + (contig_count * DevicePageSize))) { /* If we're no longer contiguous, close the range we've been building. */ mm.Close(contig_phys_addr, (contig_count * DevicePageSize) / PageSize); contig_phys_addr = phys_addr; contig_count = contig_phys_addr != Null<KPhysicalAddress> ? 1 : 0; } else { ++contig_count; } } if (contig_count > 0) { mm.Close(contig_phys_addr, (contig_count * DevicePageSize) / PageSize); } } /* Close the pages. */ if (ptm.Close(KVirtualAddress(l2), num_closed)) { /* Invalidate the l1 entry. */ l1[l1_index].Invalidate(); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry))); /* Synchronize. */ InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index])))); SmmuSynchronizationBarrier(); /* Free the l2 page. */ ptm.Free(KVirtualAddress(l2)); } /* Advance. */ address += map_count * DevicePageSize; remaining -= map_count * DevicePageSize; } else { /* Dealing with an l1 entry. */ MESOSPHERE_ASSERT(l2_index == 0); /* Get the physical address. */ const KPhysicalAddress phys_addr = l1[l1_index].GetPhysicalAddress(); MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr)); /* Invalidate the entry. */ l1[l1_index].Invalidate(); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(std::addressof(l1[l1_index]), sizeof(PageDirectoryEntry))); /* Synchronize. */ InvalidatePtc(GetPageTablePhysicalAddress(KVirtualAddress(std::addressof(l1[l1_index])))); InvalidateTlbSection(m_table_asids[l0_index], address); SmmuSynchronizationBarrier(); /* Close references. */ mm.Close(phys_addr, DeviceLargePageSize / PageSize); /* Advance. */ address += DeviceLargePageSize; remaining -= DeviceLargePageSize; } } } bool KDevicePageTable::Compare(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) const { MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */ KPageTableBase::MemoryRange contig_range; if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) { return false; } /* Ensure that we close the range when we're done. */ bool range_open = true; ON_SCOPE_EXIT { if (range_open) { contig_range.Close(); } }; /* Walk the directory. */ KProcessAddress cur_process_address = process_address; size_t remaining_size = size; KPhysicalAddress cur_phys_address = contig_range.GetAddress(); size_t remaining_in_range = contig_range.GetSize(); bool first = true; u32 first_attr = 0; while (remaining_size > 0) { /* Convert the device address to a series of indices. */ const size_t l0_index = (device_address / DeviceRegionSize); const size_t l1_index = (device_address % DeviceRegionSize) / DeviceLargePageSize; const size_t l2_index = (device_address % DeviceLargePageSize) / DevicePageSize; /* Get and validate l1. */ const PageDirectoryEntry *l1 = GetPointer<PageDirectoryEntry>(m_tables[l0_index]); if (!(l1 != nullptr && l1[l1_index].IsValid())) { return false; } if (l1[l1_index].IsTable()) { /* We're acting on an l2 entry. */ const PageTableEntry *l2 = GetPointer<PageTableEntry>(GetPageTableVirtualAddress(l1[l1_index].GetPhysicalAddress())); /* Determine the number of pages to check. */ const size_t remaining_in_entry = (PageTableSize / sizeof(PageTableEntry)) - l2_index; const size_t map_count = std::min<size_t>(remaining_in_entry, remaining_size / DevicePageSize); /* Check each page. */ for (size_t i = 0; i < map_count; ++i) { /* Ensure the l2 entry is valid. */ if (!l2[l2_index + i].IsValid()) { return false; } /* Check that the attributes match the first attributes we encountered. */ const u32 cur_attr = l2[l2_index + i].GetAttributes(); if (!first && cur_attr != first_attr) { return false; } /* If there's nothing remaining in the range, refresh the range. */ if (remaining_in_range == 0) { contig_range.Close(); range_open = false; if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) { return false; } range_open = true; cur_phys_address = contig_range.GetAddress(); remaining_in_range = contig_range.GetSize(); } /* Check that the physical address is expected. */ if (l2[l2_index + i].GetPhysicalAddress() != cur_phys_address) { return false; } /* Advance. */ cur_phys_address += DevicePageSize; cur_process_address += DevicePageSize; remaining_size -= DevicePageSize; remaining_in_range -= DevicePageSize; first = false; first_attr = cur_attr; } /* Advance the device address. */ device_address += map_count * DevicePageSize; } else { /* We're acting on an l1 entry. */ if (!(l2_index == 0 && remaining_size >= DeviceLargePageSize)) { return false; } /* Check that the attributes match the first attributes we encountered. */ const u32 cur_attr = l1[l1_index].GetAttributes(); if (!first && cur_attr != first_attr) { return false; } /* If there's nothing remaining in the range, refresh the range. */ if (remaining_in_range == 0) { contig_range.Close(); range_open = false; if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), cur_process_address, remaining_size))) { return false; } range_open = true; cur_phys_address = contig_range.GetAddress(); remaining_in_range = contig_range.GetSize(); } /* Check that the physical address is expected, and there's enough in the range. */ if (remaining_in_range < DeviceLargePageSize || l1[l1_index].GetPhysicalAddress() != cur_phys_address) { return false; } /* Advance. */ cur_phys_address += DeviceLargePageSize; cur_process_address += DeviceLargePageSize; remaining_size -= DeviceLargePageSize; remaining_in_range -= DeviceLargePageSize; first = false; first_attr = cur_attr; /* Advance the device address. */ device_address += DeviceLargePageSize; } } /* The range is valid! */ return true; } Result KDevicePageTable::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) { /* Validate address/size. */ MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* IO is not supported on NX board. */ MESOSPHERE_ASSERT(!is_io); MESOSPHERE_UNUSED(is_io); /* Map the pages. */ R_RETURN(this->MapImpl(page_table, process_address, size, device_address, device_perm, is_aligned)); } Result KDevicePageTable::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) { /* Validate address/size. */ MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0); MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0); /* Ensure the page group is correct. */ R_UNLESS(this->Compare(page_table, process_address, size, device_address), svc::ResultInvalidCurrentMemory()); /* Unmap the pages. */ this->UnmapImpl(device_address, size, false); R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_io_pool.board.nintendo_nx.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ constexpr IoRegionExtents g_io_region_extents[4] = { { KPhysicalAddress(0x12000000), 224_MB }, /* PCIE_A2 */ { Null<KPhysicalAddress>, 0 }, { Null<KPhysicalAddress>, 0 }, { Null<KPhysicalAddress>, 0 }, }; constexpr bool IsValidIoPoolTypeImpl(ams::svc::IoPoolType pool_type) { return pool_type == ams::svc::IoPoolType_PcieA2; } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_k_sleep_manager.hpp" #include "kern_secure_monitor.hpp" #include "kern_lps_driver.hpp" namespace ams::kern::init { void StartOtherCore(const ams::kern::init::KInitArguments *init_args); } namespace ams::kern::board::nintendo::nx { namespace { /* Struct representing registers saved on wake/sleep. */ class SavedSystemRegisters { private: u64 elr_el1; u64 sp_el0; u64 spsr_el1; u64 daif; u64 cpacr_el1; u64 vbar_el1; u64 csselr_el1; u64 cntp_ctl_el0; u64 cntp_cval_el0; u64 cntkctl_el1; u64 tpidr_el0; u64 tpidrro_el0; u64 mdscr_el1; u64 contextidr_el1; u64 dbgwcrN_el1[16]; u64 dbgwvrN_el1[16]; u64 dbgbcrN_el1[16]; u64 dbgbvrN_el1[16]; u64 pmccfiltr_el0; u64 pmccntr_el0; u64 pmcntenset_el0; u64 pmcr_el0; u64 pmevcntrN_el0[31]; u64 pmevtyperN_el0[31]; u64 pmintenset_el1; u64 pmovsset_el0; u64 pmselr_el0; u64 pmuserenr_el0; public: void Save(); void Restore() const; }; constexpr s32 SleepManagerThreadPriority = 2; /* Globals for sleep/wake. */ constinit u64 g_sleep_target_cores; constinit KLightLock g_request_lock; constinit KLightLock g_cv_lock; constinit KLightConditionVariable g_cv{util::ConstantInitialize}; alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)]; constinit ams::kern::init::KInitArguments g_sleep_init_arguments[cpu::NumCores]; constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {}; void WaitOtherCpuPowerOff() { constexpr u64 PmcPhysicalAddress = 0x7000E400; constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9; u32 value; do { bool res = smc::ReadWriteRegister(std::addressof(value), PmcPhysicalAddress + APBDEV_PMC_PWRGATE_STATUS, 0, 0); MESOSPHERE_ASSERT(res); MESOSPHERE_UNUSED(res); } while ((value & PWRGATE_STATUS_CE123_MASK) != 0); } void SavedSystemRegisters::Save() { /* Save system registers. */ this->tpidr_el0 = cpu::GetTpidrEl0(); this->elr_el1 = cpu::GetElrEl1(); this->sp_el0 = cpu::GetSpEl0(); this->spsr_el1 = cpu::GetSpsrEl1(); this->daif = cpu::GetDaif(); this->cpacr_el1 = cpu::GetCpacrEl1(); this->vbar_el1 = cpu::GetVbarEl1(); this->csselr_el1 = cpu::GetCsselrEl1(); this->cntp_ctl_el0 = cpu::GetCntpCtlEl0(); this->cntp_cval_el0 = cpu::GetCntpCvalEl0(); this->cntkctl_el1 = cpu::GetCntkCtlEl1(); this->tpidrro_el0 = cpu::GetTpidrRoEl0(); /* Save pmu registers. */ { /* Get and clear pmcr_el0 */ this->pmcr_el0 = cpu::GetPmcrEl0(); cpu::SetPmcrEl0(0); cpu::EnsureInstructionConsistency(); /* Save other pmu registers. */ this->pmuserenr_el0 = cpu::GetPmUserEnrEl0(); this->pmselr_el0 = cpu::GetPmSelrEl0(); this->pmccfiltr_el0 = cpu::GetPmcCfiltrEl0(); this->pmcntenset_el0 = cpu::GetPmCntEnSetEl0(); this->pmintenset_el1 = cpu::GetPmIntEnSetEl1(); this->pmovsset_el0 = cpu::GetPmOvsSetEl0(); this->pmccntr_el0 = cpu::GetPmcCntrEl0(); switch (cpu::PerformanceMonitorsControlRegisterAccessor(this->pmcr_el0).GetN()) { #define HANDLE_PMU_CASE(N) \ case (N+1): \ this->pmevcntrN_el0 [ N ] = cpu::GetPmevCntr##N##El0(); \ this->pmevtyperN_el0[ N ] = cpu::GetPmevTyper##N##El0(); \ [[fallthrough]] HANDLE_PMU_CASE(30); HANDLE_PMU_CASE(29); HANDLE_PMU_CASE(28); HANDLE_PMU_CASE(27); HANDLE_PMU_CASE(26); HANDLE_PMU_CASE(25); HANDLE_PMU_CASE(24); HANDLE_PMU_CASE(23); HANDLE_PMU_CASE(22); HANDLE_PMU_CASE(21); HANDLE_PMU_CASE(20); HANDLE_PMU_CASE(19); HANDLE_PMU_CASE(18); HANDLE_PMU_CASE(17); HANDLE_PMU_CASE(16); HANDLE_PMU_CASE(15); HANDLE_PMU_CASE(14); HANDLE_PMU_CASE(13); HANDLE_PMU_CASE(12); HANDLE_PMU_CASE(11); HANDLE_PMU_CASE(10); HANDLE_PMU_CASE( 9); HANDLE_PMU_CASE( 8); HANDLE_PMU_CASE( 7); HANDLE_PMU_CASE( 6); HANDLE_PMU_CASE( 5); HANDLE_PMU_CASE( 4); HANDLE_PMU_CASE( 3); HANDLE_PMU_CASE( 2); HANDLE_PMU_CASE( 1); HANDLE_PMU_CASE( 0); #undef HANDLE_PMU_CASE case 0: default: break; } } /* Save debug registers. */ const u64 dfr0 = cpu::GetIdAa64Dfr0El1(); this->mdscr_el1 = cpu::GetMdscrEl1(); this->contextidr_el1 = cpu::GetContextidrEl1(); /* Save watchpoints. */ switch (cpu::DebugFeatureRegisterAccessor(dfr0).GetNumWatchpoints()) { #define HANDLE_DBG_CASE(N) \ case N: \ this->dbgwcrN_el1[ N ] = cpu::GetDbgWcr##N##El1(); \ this->dbgwvrN_el1[ N ] = cpu::GetDbgWvr##N##El1(); \ [[fallthrough]] HANDLE_DBG_CASE(15); HANDLE_DBG_CASE(14); HANDLE_DBG_CASE(13); HANDLE_DBG_CASE(12); HANDLE_DBG_CASE(11); HANDLE_DBG_CASE(10); HANDLE_DBG_CASE( 9); HANDLE_DBG_CASE( 8); HANDLE_DBG_CASE( 7); HANDLE_DBG_CASE( 6); HANDLE_DBG_CASE( 5); HANDLE_DBG_CASE( 4); HANDLE_DBG_CASE( 3); HANDLE_DBG_CASE( 2); #undef HANDLE_DBG_CASE case 1: this->dbgwcrN_el1[1] = cpu::GetDbgWcr1El1(); this->dbgwvrN_el1[1] = cpu::GetDbgWvr1El1(); this->dbgwcrN_el1[0] = cpu::GetDbgWcr0El1(); this->dbgwvrN_el1[0] = cpu::GetDbgWvr0El1(); [[fallthrough]]; default: break; } /* Save breakpoints. */ switch (cpu::DebugFeatureRegisterAccessor(dfr0).GetNumBreakpoints()) { #define HANDLE_DBG_CASE(N) \ case N: \ this->dbgbcrN_el1[ N ] = cpu::GetDbgBcr##N##El1(); \ this->dbgbvrN_el1[ N ] = cpu::GetDbgBvr##N##El1(); \ [[fallthrough]] HANDLE_DBG_CASE(15); HANDLE_DBG_CASE(14); HANDLE_DBG_CASE(13); HANDLE_DBG_CASE(12); HANDLE_DBG_CASE(11); HANDLE_DBG_CASE(10); HANDLE_DBG_CASE( 9); HANDLE_DBG_CASE( 8); HANDLE_DBG_CASE( 7); HANDLE_DBG_CASE( 6); HANDLE_DBG_CASE( 5); HANDLE_DBG_CASE( 4); HANDLE_DBG_CASE( 3); HANDLE_DBG_CASE( 2); #undef HANDLE_DBG_CASE case 1: this->dbgbcrN_el1[1] = cpu::GetDbgBcr1El1(); this->dbgbvrN_el1[1] = cpu::GetDbgBvr1El1(); [[fallthrough]]; default: break; } this->dbgbcrN_el1[0] = cpu::GetDbgBcr0El1(); this->dbgbvrN_el1[0] = cpu::GetDbgBvr0El1(); cpu::EnsureInstructionConsistency(); /* Clear mdscr_el1. */ cpu::SetMdscrEl1(0); cpu::EnsureInstructionConsistency(); } void SavedSystemRegisters::Restore() const { /* Restore debug registers. */ const u64 dfr0 = cpu::GetIdAa64Dfr0El1(); cpu::EnsureInstructionConsistency(); cpu::SetMdscrEl1(0); cpu::EnsureInstructionConsistency(); cpu::SetOslarEl1(0); cpu::EnsureInstructionConsistency(); /* Restore watchpoints. */ switch (cpu::DebugFeatureRegisterAccessor(dfr0).GetNumWatchpoints()) { #define HANDLE_DBG_CASE(N) \ case N: \ cpu::SetDbgWcr##N##El1(this->dbgwcrN_el1[ N ]); \ cpu::SetDbgWvr##N##El1(this->dbgwvrN_el1[ N ]); \ [[fallthrough]] HANDLE_DBG_CASE(15); HANDLE_DBG_CASE(14); HANDLE_DBG_CASE(13); HANDLE_DBG_CASE(12); HANDLE_DBG_CASE(11); HANDLE_DBG_CASE(10); HANDLE_DBG_CASE( 9); HANDLE_DBG_CASE( 8); HANDLE_DBG_CASE( 7); HANDLE_DBG_CASE( 6); HANDLE_DBG_CASE( 5); HANDLE_DBG_CASE( 4); HANDLE_DBG_CASE( 3); HANDLE_DBG_CASE( 2); #undef HANDLE_DBG_CASE case 1: cpu::SetDbgWcr1El1(this->dbgwcrN_el1[1]); cpu::SetDbgWvr1El1(this->dbgwvrN_el1[1]); cpu::SetDbgWcr0El1(this->dbgwcrN_el1[0]); cpu::SetDbgWvr0El1(this->dbgwvrN_el1[0]); [[fallthrough]]; default: break; } /* Restore breakpoints. */ switch (cpu::DebugFeatureRegisterAccessor(dfr0).GetNumBreakpoints()) { #define HANDLE_DBG_CASE(N) \ case N: \ cpu::SetDbgBcr##N##El1(this->dbgbcrN_el1[ N ]); \ cpu::SetDbgBvr##N##El1(this->dbgbvrN_el1[ N ]); \ [[fallthrough]] HANDLE_DBG_CASE(15); HANDLE_DBG_CASE(14); HANDLE_DBG_CASE(13); HANDLE_DBG_CASE(12); HANDLE_DBG_CASE(11); HANDLE_DBG_CASE(10); HANDLE_DBG_CASE( 9); HANDLE_DBG_CASE( 8); HANDLE_DBG_CASE( 7); HANDLE_DBG_CASE( 6); HANDLE_DBG_CASE( 5); HANDLE_DBG_CASE( 4); HANDLE_DBG_CASE( 3); HANDLE_DBG_CASE( 2); #undef HANDLE_DBG_CASE case 1: cpu::SetDbgBcr1El1(this->dbgbcrN_el1[1]); cpu::SetDbgBvr1El1(this->dbgbvrN_el1[1]); [[fallthrough]]; default: break; } cpu::SetDbgBcr0El1(this->dbgbcrN_el1[0]); cpu::SetDbgBvr0El1(this->dbgbvrN_el1[0]); cpu::EnsureInstructionConsistency(); cpu::SetContextidrEl1(this->contextidr_el1); cpu::EnsureInstructionConsistency(); cpu::SetMdscrEl1(this->mdscr_el1); cpu::EnsureInstructionConsistency(); /* Restore pmu registers. */ cpu::SetPmUserEnrEl0(0); cpu::PerformanceMonitorsControlRegisterAccessor(0).SetEventCounterReset(true).SetCycleCounterReset(true).Store(); cpu::EnsureInstructionConsistency(); cpu::SetPmOvsClrEl0(static_cast<u64>(static_cast<u32>(~u32()))); cpu::SetPmIntEnClrEl1(static_cast<u64>(static_cast<u32>(~u32()))); cpu::SetPmCntEnClrEl0(static_cast<u64>(static_cast<u32>(~u32()))); switch (cpu::PerformanceMonitorsControlRegisterAccessor(this->pmcr_el0).GetN()) { #define HANDLE_PMU_CASE(N) \ case (N+1): \ cpu::SetPmevCntr##N##El0 (this->pmevcntrN_el0 [ N ]); \ cpu::SetPmevTyper##N##El0(this->pmevtyperN_el0[ N ]); \ [[fallthrough]] HANDLE_PMU_CASE(30); HANDLE_PMU_CASE(29); HANDLE_PMU_CASE(28); HANDLE_PMU_CASE(27); HANDLE_PMU_CASE(26); HANDLE_PMU_CASE(25); HANDLE_PMU_CASE(24); HANDLE_PMU_CASE(23); HANDLE_PMU_CASE(22); HANDLE_PMU_CASE(21); HANDLE_PMU_CASE(20); HANDLE_PMU_CASE(19); HANDLE_PMU_CASE(18); HANDLE_PMU_CASE(17); HANDLE_PMU_CASE(16); HANDLE_PMU_CASE(15); HANDLE_PMU_CASE(14); HANDLE_PMU_CASE(13); HANDLE_PMU_CASE(12); HANDLE_PMU_CASE(11); HANDLE_PMU_CASE(10); HANDLE_PMU_CASE( 9); HANDLE_PMU_CASE( 8); HANDLE_PMU_CASE( 7); HANDLE_PMU_CASE( 6); HANDLE_PMU_CASE( 5); HANDLE_PMU_CASE( 4); HANDLE_PMU_CASE( 3); HANDLE_PMU_CASE( 2); HANDLE_PMU_CASE( 1); HANDLE_PMU_CASE( 0); #undef HANDLE_PMU_CASE case 0: default: break; } cpu::SetPmUserEnrEl0 (this->pmuserenr_el0); cpu::SetPmSelrEl0 (this->pmselr_el0); cpu::SetPmcCfiltrEl0 (this->pmccfiltr_el0); cpu::SetPmCntEnSetEl0(this->pmcntenset_el0); cpu::SetPmIntEnSetEl1(this->pmintenset_el1); cpu::SetPmOvsSetEl0 (this->pmovsset_el0); cpu::SetPmcCntrEl0 (this->pmccntr_el0); cpu::EnsureInstructionConsistency(); cpu::SetPmcrEl0(this->pmcr_el0); cpu::EnsureInstructionConsistency(); /* Restore system registers. */ cpu::SetTtbr0El1 (KPageTable::GetKernelTtbr0()); cpu::SetTpidrEl0 (this->tpidr_el0); cpu::SetElrEl1 (this->elr_el1); cpu::SetSpEl0 (this->sp_el0); cpu::SetSpsrEl1 (this->spsr_el1); cpu::SetDaif (this->daif); cpu::SetCpacrEl1 (this->cpacr_el1); cpu::SetVbarEl1 (this->vbar_el1); cpu::SetCsselrEl1 (this->csselr_el1); cpu::SetCntpCtlEl0 (this->cntp_ctl_el0); cpu::SetCntpCvalEl0(this->cntp_cval_el0); cpu::SetCntkCtlEl1 (this->cntkctl_el1); cpu::SetTpidrRoEl0 (this->tpidrro_el0); cpu::EnsureInstructionConsistency(); /* Invalidate the entire tlb. */ cpu::InvalidateEntireTlb(); } } void KSleepManager::Initialize() { /* Create a sleep manager thread for each core. */ for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) { /* Reserve a thread from the system limit. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1)); /* Create a new thread. */ KThread *new_thread = KThread::Create(); MESOSPHERE_ABORT_UNLESS(new_thread != nullptr); /* Launch the new thread. */ MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, KSleepManager::ProcessRequests, reinterpret_cast<uintptr_t>(g_sleep_buffers[core_id]), SleepManagerThreadPriority, static_cast<s32>(core_id))); /* Register the new thread. */ KThread::Register(new_thread); /* Run the thread. */ MESOSPHERE_R_ABORT_UNLESS(new_thread->Run()); } } void KSleepManager::SleepSystem() { /* Ensure device mappings are not modified during sleep. */ KDevicePageTable::Lock(); ON_SCOPE_EXIT { KDevicePageTable::Unlock(); }; /* Request that the system sleep. */ { KScopedLightLock lk(g_request_lock); /* Signal the manager to sleep on all cores. */ { KScopedLightLock lk(g_cv_lock); MESOSPHERE_ABORT_UNLESS(g_sleep_target_cores == 0); g_sleep_target_cores = (1ul << cpu::NumCores) - 1; g_cv.Broadcast(); while (g_sleep_target_cores != 0) { g_cv.Wait(std::addressof(g_cv_lock)); } } } } void KSleepManager::ProcessRequests(uintptr_t sleep_buffer) { const auto target_fw = GetTargetFirmware(); const s32 core_id = GetCurrentCoreId(); ams::kern::init::KInitArguments * const init_args = g_sleep_init_arguments + core_id; KPhysicalAddress start_core_phys_addr = Null<KPhysicalAddress>; KPhysicalAddress init_args_phys_addr = Null<KPhysicalAddress>; /* Get the physical addresses we'll need. */ { MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(start_core_phys_addr), KProcessAddress(&::ams::kern::init::StartOtherCore))); MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(init_args_phys_addr), KProcessAddress(init_args))); } const u64 target_core_mask = (1ul << core_id); const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0; /* Loop, processing sleep when requested. */ while (true) { /* Wait for a request. */ { KScopedLightLock lk(g_cv_lock); while ((g_sleep_target_cores & target_core_mask) == 0) { g_cv.Wait(std::addressof(g_cv_lock)); } } /* If on core 0, ensure the legacy lps driver is initialized. */ if (use_legacy_lps_driver && core_id == 0) { lps::Initialize(); } /* Perform Sleep/Wake sequence. */ { /* Disable interrupts. */ KScopedInterruptDisable di; /* Save the system registers for the current core. */ g_sleep_system_registers[core_id].Save(); /* Invalidate the entire tlb. */ cpu::InvalidateEntireTlb(); /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* If on core 0, put the device page tables to sleep. */ if (core_id == 0) { KDevicePageTable::Sleep(); } /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Wait 100us before continuing. */ { const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMicroSeconds(100)); while (KHardwareTimer::GetTick() < timeout) { __asm__ __volatile__("" ::: "memory"); } } /* Save the interrupt manager's state. */ Kernel::GetInterruptManager().Save(core_id); /* Setup the initial arguments. */ { /* Determine whether we're running on a cortex-a53 or a-57. */ cpu::MainIdRegisterAccessor midr_el1; const auto implementer = midr_el1.GetImplementer(); const auto primary_part = midr_el1.GetPrimaryPartNumber(); const bool needs_cpu_ctlr = (implementer == cpu::MainIdRegisterAccessor::Implementer::ArmLimited) && (primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA57 || primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA53); init_args->cpuactlr = needs_cpu_ctlr ? cpu::GetCpuActlrEl1() : 0; init_args->cpuectlr = needs_cpu_ctlr ? cpu::GetCpuEctlrEl1() : 0; init_args->sp = 0; init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry); init_args->argument = sleep_buffer; } /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Log that the core is going to sleep. */ MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, sleep_buffer); /* If we're on a core other than zero, we can just invoke the sleep handler. */ if (core_id != 0) { CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr)); } else { /* Wait for all other cores to be powered off. */ WaitOtherCpuPowerOff(); /* If we're using the legacy lps driver, enable suspend. */ if (use_legacy_lps_driver) { MESOSPHERE_R_ABORT_UNLESS(lps::EnableSuspend(true)); } /* Log that we're about to enter SC7. */ MESOSPHERE_LOG("Entering SC7\n"); /* Save the debug log state. */ KDebugLog::Save(); /* Invoke the sleep handler. */ if (!use_legacy_lps_driver) { /* When not using the legacy driver, invoke directly. */ CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr)); } else { lps::InvokeCpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr)); } /* Restore the debug log state. */ KDebugLog::Restore(); /* Log that we're about to exit SC7. */ MESOSPHERE_LOG("Exiting SC7\n"); /* Wake up the other cores. */ cpu::MultiprocessorAffinityRegisterAccessor mpidr; const auto arg = mpidr.GetCpuOnArgument(); for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) { KSystemControl::Init::TurnOnCpu(arg | i, g_sleep_init_arguments + i); } } /* Log that the core is waking from sleep. */ MESOSPHERE_LOG("Core[%d]: Woke from sleep.\n", core_id); /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Restore the interrupt manager's state. */ Kernel::GetInterruptManager().Restore(core_id); /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* If on core 0, wake up the device page tables. */ if (core_id == 0) { KDevicePageTable::Wakeup(); /* If we're using the legacy driver, resume the bpmp firmware. */ if (use_legacy_lps_driver) { lps::ResumeBpmpFirmware(); } } /* Ensure that all cores get to this point before continuing. */ cpu::SynchronizeAllCores(); /* Restore the system registers for the current core. */ g_sleep_system_registers[core_id].Restore(); } /* Signal request completed. */ { KScopedLightLock lk(g_cv_lock); g_sleep_target_cores &= ~target_core_mask; if (g_sleep_target_cores == 0) { g_cv.Broadcast(); } } } } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> namespace ams::kern::board::nintendo::nx { class KSleepManager { private: static void ResumeEntry(uintptr_t arg); static void ProcessRequests(uintptr_t buffer); public: static void Initialize(); static void SleepSystem(); public: static void CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_args); }; } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager_asm.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ #define cpuactlr_el1 s3_1_c15_c2_0 #define cpuectlr_el1 s3_1_c15_c2_1 #define LOAD_IMMEDIATE_32(reg, val) \ mov reg, #(((val) >> 0x00) & 0xFFFF); \ movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16 /* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) */ .section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, "ax", %progbits .global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm .type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, %function _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm: /* Save arguments. */ mov x16, x1 mov x17, x2 /* Enable access to FPU registers. */ mrs x1, cpacr_el1 orr x1, x1, #0x100000 msr cpacr_el1, x1 dsb sy isb /* Save callee-save registers. */ stp x18, x19, [x0], #0x10 stp x20, x21, [x0], #0x10 stp x22, x23, [x0], #0x10 stp x24, x25, [x0], #0x10 stp x26, x27, [x0], #0x10 stp x28, x29, [x0], #0x10 stp x30, xzr, [x0], #0x10 /* Save stack pointer. */ mov x1, sp str x1, [x0], #8 /* Save fpcr/fpsr. */ mrs x1, fpcr mrs x2, fpsr stp w1, w2, [x0], #8 /* Save the floating point registers. */ stp q0, q1, [x0], #0x20 stp q2, q3, [x0], #0x20 stp q4, q5, [x0], #0x20 stp q6, q7, [x0], #0x20 stp q8, q9, [x0], #0x20 stp q10, q11, [x0], #0x20 stp q12, q13, [x0], #0x20 stp q14, q15, [x0], #0x20 stp q16, q17, [x0], #0x20 stp q28, q19, [x0], #0x20 stp q20, q21, [x0], #0x20 stp q22, q23, [x0], #0x20 stp q24, q25, [x0], #0x20 stp q26, q27, [x0], #0x20 stp q28, q29, [x0], #0x20 stp q30, q31, [x0], #0x20 /* Save tpidr/cntv_cval_el0. */ mrs x1, tpidr_el1 mrs x2, cntv_cval_el0 stp x1, x2, [x0], #0x10 /* Get the current core id. */ mrs x0, mpidr_el1 and x0, x0, #0xFF /* If we're on core 0, suspend. */ cbz x0, 1f /* Otherwise, power off. */ LOAD_IMMEDIATE_32(x0, 0x84000002) smc #1 0: b 0b 1: /* Suspend. */ LOAD_IMMEDIATE_32(x0, 0xC4000001) LOAD_IMMEDIATE_32(x1, 0x0201001B) mov x2, x16 mov x3, x17 smc #1 0: b 0b /* ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry(uintptr_t arg) */ .section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, "ax", %progbits .global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm .type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm: /* Enable access to FPU registers. */ mrs x1, cpacr_el1 orr x1, x1, #0x100000 msr cpacr_el1, x1 dsb sy isb /* Restore callee-save registers. */ ldp x18, x19, [x0], #0x10 ldp x20, x21, [x0], #0x10 ldp x22, x23, [x0], #0x10 ldp x24, x25, [x0], #0x10 ldp x26, x27, [x0], #0x10 ldp x28, x29, [x0], #0x10 ldp x30, xzr, [x0], #0x10 /* Restore stack pointer. */ ldr x1, [x0], #8 mov sp, x1 /* Restore fpcr/fpsr. */ ldp w1, w2, [x0], #8 msr fpcr, x1 msr fpsr, x2 /* Restore the floating point registers. */ ldp q0, q1, [x0], #0x20 ldp q2, q3, [x0], #0x20 ldp q4, q5, [x0], #0x20 ldp q6, q7, [x0], #0x20 ldp q8, q9, [x0], #0x20 ldp q10, q11, [x0], #0x20 ldp q12, q13, [x0], #0x20 ldp q14, q15, [x0], #0x20 ldp q16, q17, [x0], #0x20 ldp q28, q19, [x0], #0x20 ldp q20, q21, [x0], #0x20 ldp q22, q23, [x0], #0x20 ldp q24, q25, [x0], #0x20 ldp q26, q27, [x0], #0x20 ldp q28, q29, [x0], #0x20 ldp q30, q31, [x0], #0x20 /* Restore tpidr/cntv_cval_el0. */ ldp x1, x2, [x0], #0x10 msr tpidr_el1, x1 msr cntv_cval_el0, x2 dsb sy isb /* Return. */ ret ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_secure_monitor.hpp" #include "kern_k_sleep_manager.hpp" namespace ams::kern::board::nintendo::nx { namespace { constexpr size_t SecureAlignment = 128_KB; constexpr size_t SecureSizeMax = util::AlignDown(512_MB - 1, SecureAlignment); /* Global variables for panic. */ constinit const volatile bool g_call_smc_on_panic = false; /* Global variables for secure memory. */ constinit KSpinLock g_secure_applet_lock; constinit bool g_secure_applet_memory_used = false; constinit KVirtualAddress g_secure_applet_memory_address = Null<KVirtualAddress>; constinit KSpinLock g_secure_region_lock; constinit bool g_secure_region_used = false; constinit KPhysicalAddress g_secure_region_phys_addr = Null<KPhysicalAddress>; constinit size_t g_secure_region_size = 0; ALWAYS_INLINE util::BitPack32 GetKernelConfigurationForInit() { u64 value = 0; smc::init::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration); return util::BitPack32{static_cast<u32>(value)}; } ALWAYS_INLINE u32 GetMemoryModeForInit() { u64 value = 0; smc::init::GetConfig(&value, 1, smc::ConfigItem::MemoryMode); return static_cast<u32>(value); } ALWAYS_INLINE smc::MemoryArrangement GetMemoryArrangeForInit() { switch(GetMemoryModeForInit() & 0x3F) { case 0x01: default: return smc::MemoryArrangement_4GB; case 0x02: return smc::MemoryArrangement_4GBForAppletDev; case 0x03: return smc::MemoryArrangement_4GBForSystemDev; case 0x11: return smc::MemoryArrangement_6GB; case 0x12: return smc::MemoryArrangement_6GBForAppletDev; case 0x21: return smc::MemoryArrangement_8GB; } } ALWAYS_INLINE u64 GenerateRandomU64ForInit() { u64 value; smc::init::GenerateRandomBytes(std::addressof(value), sizeof(value)); return value; } ALWAYS_INLINE u64 GenerateRandomU64FromSmc() { u64 value; smc::GenerateRandomBytes(std::addressof(value), sizeof(value)); return value; } ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) { u64 value; smc::GetConfig(&value, 1, which); return value; } ALWAYS_INLINE u32 GetConfigU32(smc::ConfigItem which) { return static_cast<u32>(GetConfigU64(which)); } ALWAYS_INLINE bool GetConfigBool(smc::ConfigItem which) { return GetConfigU64(which) != 0; } ALWAYS_INLINE bool CheckRegisterAllowedTable(const u8 *table, const size_t offset) { return (table[(offset / sizeof(u32)) / BITSIZEOF(u8)] & (1u << ((offset / sizeof(u32)) % BITSIZEOF(u8)))) != 0; } /* TODO: Generate this from a list of register names (see similar logic in exosphere)? */ constexpr inline const u8 McKernelRegisterWhitelist[(PageSize / sizeof(u32)) / BITSIZEOF(u8)] = { 0x9F, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x73, 0x3E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* TODO: Generate this from a list of register names (see similar logic in exosphere)? */ constexpr inline const u8 McUserRegisterWhitelist[(PageSize / sizeof(u32)) / BITSIZEOF(u8)] = { 0x00, 0x00, 0x20, 0x00, 0xF0, 0xFF, 0xF7, 0x01, 0xCD, 0xFE, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x30, 0x05, 0x06, 0xB0, 0x71, 0xC8, 0x43, 0x04, 0x80, 0xFF, 0x08, 0x80, 0x03, 0x38, 0x8E, 0x1F, 0xC8, 0xFF, 0xFF, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x30, 0xF0, 0x03, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F, 0x01, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; bool IsRegisterAccessibleToPrivileged(ams::svc::PhysicalAddress address) { /* Find the region for the address. */ const KMemoryRegion *region = KMemoryLayout::Find(KPhysicalAddress(address)); if (AMS_LIKELY(region != nullptr)) { if (AMS_LIKELY(region->IsDerivedFrom(KMemoryRegionType_MemoryController))) { /* Check the region is valid. */ MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0); /* Get the offset within the region. */ const size_t offset = address - region->GetAddress(); MESOSPHERE_ABORT_UNLESS(offset < region->GetSize()); /* Check the whitelist. */ if (AMS_LIKELY(CheckRegisterAllowedTable(McKernelRegisterWhitelist, offset))) { return true; } } } return false; } bool IsRegisterAccessibleToUser(ams::svc::PhysicalAddress address) { /* Find the region for the address. */ const KMemoryRegion *region = KMemoryLayout::Find(KPhysicalAddress(address)); if (AMS_LIKELY(region != nullptr)) { /* The PMC is always allowed. */ if (region->IsDerivedFrom(KMemoryRegionType_PowerManagementController)) { return true; } /* Memory controller is allowed if the register is whitelisted. */ if (region->IsDerivedFrom(KMemoryRegionType_MemoryController ) || region->IsDerivedFrom(KMemoryRegionType_MemoryController0) || region->IsDerivedFrom(KMemoryRegionType_MemoryController1)) { /* Check the region is valid. */ MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0); /* Get the offset within the region. */ const size_t offset = address - region->GetAddress(); MESOSPHERE_ABORT_UNLESS(offset < region->GetSize()); /* Check the whitelist. */ if (AMS_LIKELY(CheckRegisterAllowedTable(McUserRegisterWhitelist, offset))) { return true; } } } return false; } bool SetSecureRegion(KPhysicalAddress phys_addr, size_t size) { /* Ensure size is valid. */ if (size > SecureSizeMax) { return false; } /* Ensure address and size are aligned. */ if (!util::IsAligned(GetInteger(phys_addr), SecureAlignment)) { return false; } if (!util::IsAligned(size, SecureAlignment)) { return false; } /* Disable interrupts and acquire the secure region lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_secure_region_lock); /* If size is non-zero, we're allocating the secure region. Otherwise, we're freeing it. */ if (size != 0) { /* Verify that the secure region is free. */ if (g_secure_region_used) { return false; } /* Set the secure region. */ g_secure_region_used = true; g_secure_region_phys_addr = phys_addr; g_secure_region_size = size; } else { /* Verify that the secure region is in use. */ if (!g_secure_region_used) { return false; } /* Verify that the address being freed is the secure region. */ if (phys_addr != g_secure_region_phys_addr) { return false; } /* Clear the secure region. */ g_secure_region_used = false; g_secure_region_phys_addr = Null<KPhysicalAddress>; g_secure_region_size = 0; } /* Configure the carveout with the secure monitor. */ smc::ConfigureCarveout(1, GetInteger(phys_addr), size); return true; } Result AllocateSecureMemoryForApplet(KVirtualAddress *out, size_t size) { /* Verify that the size is valid. */ R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size <= KSystemControl::SecureAppletMemorySize, svc::ResultOutOfMemory()); /* Disable interrupts and acquire the secure applet lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_secure_applet_lock); /* Check that memory is reserved for secure applet use. */ MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address != Null<KVirtualAddress>); /* Verify that the secure applet memory isn't already being used. */ R_UNLESS(!g_secure_applet_memory_used, svc::ResultOutOfMemory()); /* Return the secure applet memory. */ g_secure_applet_memory_used = true; *out = g_secure_applet_memory_address; R_SUCCEED(); } void FreeSecureMemoryForApplet(KVirtualAddress address, size_t size) { /* Disable interrupts and acquire the secure applet lock. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_secure_applet_lock); /* Verify that the memory being freed is correct. */ MESOSPHERE_ABORT_UNLESS(address == g_secure_applet_memory_address); MESOSPHERE_ABORT_UNLESS(size <= KSystemControl::SecureAppletMemorySize); MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize)); MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_used); /* Release the secure applet memory. */ g_secure_applet_memory_used = false; } u32 GetVersionIdentifier() { u32 value = 0; value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 0; value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 8; value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 16; value |= static_cast<u64>('M') << 24; return value; } } /* Initialization. */ size_t KSystemControl::Init::GetRealMemorySize() { /* TODO: Move this into a header for the MC in general. */ constexpr u32 MemoryControllerConfigurationRegister = 0x70019050; u32 config_value; smc::init::ReadWriteRegister(std::addressof(config_value), MemoryControllerConfigurationRegister, 0, 0); return static_cast<size_t>(config_value & 0x3FFF) << 20; } size_t KSystemControl::Init::GetIntendedMemorySize() { switch (GetKernelConfigurationForInit().Get<smc::KernelConfiguration::MemorySize>()) { case smc::MemorySize_4GB: default: /* All invalid modes should go to 4GB. */ return 4_GB; case smc::MemorySize_6GB: return 6_GB; case smc::MemorySize_8GB: return 8_GB; } } bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() { return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>(); } size_t KSystemControl::Init::GetApplicationPoolSize() { /* Get the base pool size. */ const size_t base_pool_size = []() ALWAYS_INLINE_LAMBDA -> size_t { switch (GetMemoryArrangeForInit()) { case smc::MemoryArrangement_4GB: default: return 3285_MB; case smc::MemoryArrangement_4GBForAppletDev: return 2048_MB; case smc::MemoryArrangement_4GBForSystemDev: return 3285_MB; case smc::MemoryArrangement_6GB: return 4916_MB; case smc::MemoryArrangement_6GBForAppletDev: return 3285_MB; case smc::MemoryArrangement_8GB: return 6964_MB; } }(); /* Return (possibly) adjusted size. */ return base_pool_size; } size_t KSystemControl::Init::GetAppletPoolSize() { /* Get the base pool size. */ const size_t base_pool_size = []() ALWAYS_INLINE_LAMBDA -> size_t { switch (GetMemoryArrangeForInit()) { case smc::MemoryArrangement_4GB: default: return 507_MB; case smc::MemoryArrangement_4GBForAppletDev: return 1554_MB; case smc::MemoryArrangement_4GBForSystemDev: return 448_MB; case smc::MemoryArrangement_6GB: return 562_MB; case smc::MemoryArrangement_6GBForAppletDev: return 2193_MB; case smc::MemoryArrangement_8GB: return 562_MB; } }(); /* Return (possibly) adjusted size. */ /* NOTE: On 20.0.0+ (and even more-so 21.0.0+) the browser requires much more memory in the applet pool in order to function. */ /* Thus, we have to reduce our extra system memory size by 26 MB to compensate. */ if (kern::GetTargetFirmware() >= ams::TargetFirmware_21_0_0) { constexpr size_t ExtraSystemMemoryForAtmosphere_21_0_0 = 7_MB; return base_pool_size - ExtraSystemMemoryForAtmosphere_21_0_0 - KTraceBufferSize; } else if (kern::GetTargetFirmware() >= ams::TargetFirmware_20_0_0) { constexpr size_t ExtraSystemMemoryForAtmosphere_20_0_0 = 14_MB; return base_pool_size - ExtraSystemMemoryForAtmosphere_20_0_0 - KTraceBufferSize; } else { constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB; return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize; } } size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() { /* Verify that our minimum is at least as large as Nintendo's. */ constexpr size_t MinimumSizeWithFatal = ::ams::svc::RequiredNonSecureSystemMemorySizeWithFatal; static_assert(MinimumSizeWithFatal >= 0x2C04000); constexpr size_t MinimumSizeWithoutFatal = ::ams::svc::RequiredNonSecureSystemMemorySize; static_assert(MinimumSizeWithoutFatal >= 0x2A00000); /* Include fatal in non-seure size on 16.0.0+. */ return kern::GetTargetFirmware() >= ams::TargetFirmware_16_0_0 ? MinimumSizeWithFatal : MinimumSizeWithoutFatal; } u8 KSystemControl::Init::GetDebugLogUartPort() { /* Get the log configuration. */ u64 value = 0; smc::init::GetConfig(std::addressof(value), 1, smc::ConfigItem::ExosphereLogConfiguration); /* Extract the port. */ return static_cast<u8>((value >> 32) & 0xFF); } void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor>(core_id, entrypoint, arg)) == 0); } /* Randomness for Initialization. */ void KSystemControl::Init::GenerateRandom(u64 *dst, size_t count) { MESOSPHERE_INIT_ABORT_UNLESS(count <= 7); smc::init::GenerateRandomBytes(dst, count * sizeof(u64)); } u64 KSystemControl::Init::GenerateRandomRange(u64 min, u64 max) { return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64ForInit); } /* System Initialization. */ void KSystemControl::ConfigureKTargetSystem() { /* Configure KTargetSystem. */ volatile auto *ts = const_cast<volatile KTargetSystem::KTargetSystemData *>(std::addressof(KTargetSystem::s_data)); { /* Set whether we're in debug mode. */ { ts->is_not_debug_mode = !GetConfigBool(smc::ConfigItem::IsDebugMode); /* If we're not in debug mode, we don't want to initialize uart logging. */ ts->disable_debug_logging = ts->is_not_debug_mode; } /* Set Kernel Configuration. */ { const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; ts->disable_debug_memory_fill = !kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>(); ts->disable_user_exception_handlers = !kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>(); ts->disable_dynamic_resource_limits = kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>(); ts->disable_user_pmu_access = !kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>(); /* Configure call smc on panic. */ *const_cast<volatile bool *>(std::addressof(g_call_smc_on_panic)) = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>(); } /* Set Kernel Debugging. */ { /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ ts->disable_kernel_debugging = !GetConfigBool(smc::ConfigItem::DisableProgramVerification); } } } void KSystemControl::InitializePhase1() { /* Enable KTargetSystem. */ KTargetSystem::SetInitialized(); /* Check KTargetSystem was configured correctly. */ { /* Check IsDebugMode. */ { MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMode() == GetConfigBool(smc::ConfigItem::IsDebugMode)); MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugLoggingEnabled() == GetConfigBool(smc::ConfigItem::IsDebugMode)); } /* Check Kernel Configuration. */ { const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMemoryFillEnabled() == kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>()); MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserExceptionHandlersEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>()); MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled() == !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>()); MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserPmuAccessEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>()); MESOSPHERE_ABORT_UNLESS(g_call_smc_on_panic == kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>()); } /* Check Kernel Debugging. */ { MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsKernelDebuggingEnabled() == GetConfigBool(smc::ConfigItem::DisableProgramVerification)); } } /* Initialize random and resource limit. */ { u64 seed; smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed)); KSystemControlBase::InitializePhase1Base(seed); } /* Configure the Kernel Carveout region. */ { const auto carveout = KMemoryLayout::GetCarveoutRegionExtents(); MESOSPHERE_ABORT_UNLESS(carveout.GetEndAddress() != 0); smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize()); } } void KSystemControl::InitializePhase2() { /* Initialize the sleep manager. */ KSleepManager::Initialize(); /* Get the secure applet memory. */ const auto &secure_applet_memory = KMemoryLayout::GetSecureAppletMemoryRegion(); MESOSPHERE_INIT_ABORT_UNLESS(secure_applet_memory.GetSize() == SecureAppletMemorySize); g_secure_applet_memory_address = secure_applet_memory.GetAddress(); /* Initialize KTrace (and potentially other init). */ KSystemControlBase::InitializePhase2(); } u32 KSystemControl::GetCreateProcessMemoryPool() { return KMemoryManager::Pool_Unsafe; } /* Privileged Access. */ void KSystemControl::ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { MESOSPHERE_ABORT_UNLESS(util::IsAligned(address, sizeof(u32))); MESOSPHERE_ABORT_UNLESS(IsRegisterAccessibleToPrivileged(address)); MESOSPHERE_ABORT_UNLESS(smc::ReadWriteRegister(out, address, mask, value)); } Result KSystemControl::ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { R_UNLESS(AMS_LIKELY(util::IsAligned(address, sizeof(u32))), svc::ResultInvalidAddress()); R_UNLESS(AMS_LIKELY(IsRegisterAccessibleToUser(address)), svc::ResultInvalidAddress()); R_UNLESS(AMS_LIKELY(smc::ReadWriteRegister(out, address, mask, value)), svc::ResultInvalidAddress()); R_SUCCEED(); } /* Randomness. */ void KSystemControl::GenerateRandom(u64 *dst, size_t count) { MESOSPHERE_INIT_ABORT_UNLESS(count <= 7); smc::GenerateRandomBytes(dst, count * sizeof(u64)); } u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) { KScopedInterruptDisable intr_disable; KScopedSpinLock lk(s_random_lock); if (AMS_LIKELY(!s_uninitialized_random_generator)) { return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); }); } else { return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64FromSmc); } } u64 KSystemControl::GenerateRandomU64() { KScopedInterruptDisable intr_disable; KScopedSpinLock lk(s_random_lock); if (AMS_LIKELY(!s_uninitialized_random_generator)) { return s_random_generator.GenerateRandomU64(); } else { return GenerateRandomU64FromSmc(); } } void KSystemControl::SleepSystem() { MESOSPHERE_LOG("SleepSystem() was called\n"); KSleepManager::SleepSystem(); } void KSystemControl::StopSystem(void *arg) { if (arg != nullptr) { /* Get the address of the legacy IRAM region. */ const KVirtualAddress iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 64_KB; constexpr size_t RebootPayloadSize = 0x24000; /* NOTE: Atmosphere extension; if we received an exception context from Panic(), */ /* generate a fatal error report using it. */ const KExceptionContext *e_ctx = static_cast<const KExceptionContext *>(arg); auto *f_ctx = GetPointer<::ams::impl::FatalErrorContext>(iram_address + 0x2E000); /* Clear the fatal context. */ std::memset(f_ctx, 0xCC, sizeof(*f_ctx)); /* Set metadata. */ f_ctx->magic = ::ams::impl::FatalErrorContext::Magic; f_ctx->error_desc = ::ams::impl::FatalErrorContext::KernelPanicDesc; f_ctx->program_id = (static_cast<u64>(util::FourCC<'M', 'E', 'S', 'O'>::Code) << 0) | (static_cast<u64>(util::FourCC<'S', 'P', 'H', 'R'>::Code) << 32); /* Set identifier. */ f_ctx->report_identifier = KHardwareTimer::GetTick(); /* Set module base. */ f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress(); /* Set afsr1. */ f_ctx->afsr0 = GetVersionIdentifier(); f_ctx->afsr1 = static_cast<u32>(kern::GetTargetFirmware()); /* Set efsr/far. */ f_ctx->far = cpu::GetFarEl1(); f_ctx->esr = cpu::GetEsrEl1(); /* Copy registers. */ for (size_t i = 0; i < util::size(e_ctx->x); ++i) { f_ctx->gprs[i] = e_ctx->x[i]; } f_ctx->sp = e_ctx->sp; f_ctx->pc = cpu::GetElrEl1(); /* Dump stack trace. */ { uintptr_t fp = e_ctx->x[29]; for (f_ctx->stack_trace_size = 0; f_ctx->stack_trace_size < ::ams::impl::FatalErrorContext::MaxStackTrace && fp != 0 && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); ++(f_ctx->stack_trace_size)) { struct { uintptr_t fp; uintptr_t lr; } *stack_frame = reinterpret_cast<decltype(stack_frame)>(fp); f_ctx->stack_trace[f_ctx->stack_trace_size] = stack_frame->lr; fp = stack_frame->fp; } } /* Dump stack. */ { uintptr_t sp = e_ctx->sp; for (f_ctx->stack_dump_size = 0; f_ctx->stack_dump_size < ::ams::impl::FatalErrorContext::MaxStackDumpSize && cpu::GetPhysicalAddressWritable(nullptr, sp + f_ctx->stack_dump_size, true); f_ctx->stack_dump_size += sizeof(u64)) { *reinterpret_cast<u64 *>(f_ctx->stack_dump + f_ctx->stack_dump_size) = *reinterpret_cast<u64 *>(sp + f_ctx->stack_dump_size); } } /* Try to get a payload address. */ const KMemoryRegion *cached_region = nullptr; u64 reboot_payload_paddr = 0; if (smc::TryGetConfig(std::addressof(reboot_payload_paddr), 1, smc::ConfigItem::ExospherePayloadAddress) && KMemoryLayout::IsLinearMappedPhysicalAddress(cached_region, reboot_payload_paddr, RebootPayloadSize)) { /* If we have a payload, reboot to it. */ const KVirtualAddress reboot_payload = KMemoryLayout::GetLinearVirtualAddress(KPhysicalAddress(reboot_payload_paddr)); /* Clear IRAM. */ std::memset(GetVoidPointer(iram_address), 0xCC, RebootPayloadSize); /* Copy the payload to iram. */ for (size_t i = 0; i < RebootPayloadSize / sizeof(u32); ++i) { GetPointer<volatile u32>(iram_address)[i] = GetPointer<volatile u32>(reboot_payload)[i]; } } smc::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToFatalError); } if (g_call_smc_on_panic) { /* If we should, instruct the secure monitor to display a panic screen. */ smc::ShowError(0xF00); } AMS_INFINITE_LOOP(); } /* User access. */ void KSystemControl::CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) { /* Invoke the secure monitor. */ return smc::CallSecureMonitorFromUser(args); } /* Secure Memory. */ size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) { if (pool == KMemoryManager::Pool_Applet) { return 0; } else { return KSystemControlBase::CalculateRequiredSecureMemorySize(size, pool); } } Result KSystemControl::AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool) { /* Applet secure memory is handled separately. */ if (pool == KMemoryManager::Pool_Applet) { R_RETURN(AllocateSecureMemoryForApplet(out, size)); } /* Ensure the size is aligned. */ const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment); R_UNLESS(util::IsAligned(size, alignment), svc::ResultInvalidSize()); /* Allocate the memory. */ const size_t num_pages = size / PageSize; const KPhysicalAddress paddr = Kernel::GetMemoryManager().AllocateAndOpenContinuous(num_pages, alignment / PageSize, KMemoryManager::EncodeOption(static_cast<KMemoryManager::Pool>(pool), KMemoryManager::Direction_FromFront)); R_UNLESS(paddr != Null<KPhysicalAddress>, svc::ResultOutOfMemory()); /* Ensure we don't leak references to the memory on error. */ ON_RESULT_FAILURE { Kernel::GetMemoryManager().Close(paddr, num_pages); }; /* If the memory isn't already secure, set it as secure. */ if (pool != KMemoryManager::Pool_System) { /* Set the secure region. */ R_UNLESS(SetSecureRegion(paddr, size), svc::ResultOutOfMemory()); } /* We succeeded. */ *out = KPageTable::GetHeapVirtualAddress(paddr); R_SUCCEED(); } void KSystemControl::FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool) { /* Applet secure memory is handled separately. */ if (pool == KMemoryManager::Pool_Applet) { return FreeSecureMemoryForApplet(address, size); } /* Ensure the size is aligned. */ const size_t alignment = (pool == KMemoryManager::Pool_System ? PageSize : SecureAlignment); MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), alignment)); MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, alignment)); /* If the memory isn't secure system, reset the secure region. */ if (pool != KMemoryManager::Pool_System) { /* Check that the size being freed is the current secure region size. */ MESOSPHERE_ABORT_UNLESS(g_secure_region_size == size); /* Get the physical address. */ const KPhysicalAddress paddr = KPageTable::GetHeapPhysicalAddress(address); MESOSPHERE_ABORT_UNLESS(paddr != Null<KPhysicalAddress>); /* Check that the memory being freed is the current secure region. */ MESOSPHERE_ABORT_UNLESS(paddr == g_secure_region_phys_addr); /* Free the secure region. */ MESOSPHERE_ABORT_UNLESS(SetSecureRegion(paddr, 0)); } /* Close the secure region's pages. */ Kernel::GetMemoryManager().Close(KPageTable::GetHeapPhysicalAddress(address), size / PageSize); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_lps_driver.hpp" #include "kern_k_sleep_manager.hpp" #include "kern_bpmp_api.hpp" #include "kern_atomics_registers.hpp" #include "kern_ictlr_registers.hpp" #include "kern_sema_registers.hpp" namespace ams::kern::board::nintendo::nx::lps { namespace { constexpr inline int ChannelCount = 12; constexpr inline TimeSpan ChannelTimeout = TimeSpan::FromSeconds(1); constinit bool g_lps_init_done = false; constinit bool g_bpmp_connected = false; constinit bool g_bpmp_mail_initialized = false; constinit KSpinLock g_bpmp_mrq_lock; constinit KVirtualAddress g_evp_address = Null<KVirtualAddress>; constinit KVirtualAddress g_flow_address = Null<KVirtualAddress>; constinit KVirtualAddress g_prictlr_address = Null<KVirtualAddress>; constinit KVirtualAddress g_sema_address = Null<KVirtualAddress>; constinit KVirtualAddress g_atomics_address = Null<KVirtualAddress>; constinit KVirtualAddress g_clkrst_address = Null<KVirtualAddress>; constinit KVirtualAddress g_pmc_address = Null<KVirtualAddress>; constinit ChannelData g_channel_area[ChannelCount] = {}; constinit u32 g_csite_clk_source = 0; ALWAYS_INLINE u32 Read(KVirtualAddress address) { return *GetPointer<volatile u32>(address); } ALWAYS_INLINE void Write(KVirtualAddress address, u32 value) { *GetPointer<volatile u32>(address) = value; } void InitializeDeviceVirtualAddresses() { /* Retrieve randomized mappings. */ g_evp_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsExceptionVectors); g_flow_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsFlowController); g_prictlr_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsPrimaryICtlr); g_sema_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsSemaphore); g_atomics_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsAtomics); g_clkrst_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsClkRst); g_pmc_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_PowerManagementController); } /* NOTE: linux "do_cc4_init" */ void ConfigureCc3AndCc4() { /* Configure CC4/CC3 as enabled with time threshold as 2 microseconds. */ Write(g_flow_address + FLOW_CTLR_CC4_HVC_CONTROL, (0x2 << 3) | 0x1); /* Configure Retention with threshold 2 microseconds. */ Write(g_flow_address + FLOW_CTLR_CC4_RETENTION_CONTROL, (0x2 << 3)); /* Configure CC3/CC3 retry threshold as 2 microseconds. */ Write(g_flow_address + FLOW_CTLR_CC4_HVC_RETRY, (0x2 << 3)); /* Read the retry register to ensure writes take. */ Read(g_flow_address + FLOW_CTLR_CC4_HVC_RETRY); } constexpr bool IsValidMessageDataSize(int size) { return 0 <= size && size < MessageDataSizeMax; } /* NOTE: linux "bpmp_valid_txfer" */ constexpr bool IsTransferValid(const void *ob, int ob_size, void *ib, int ib_size) { return IsValidMessageDataSize(ob_size) && IsValidMessageDataSize(ib_size) && (ob_size == 0 || ob != nullptr) && (ib_size == 0 || ib != nullptr); } /* NOTE: linux "bpmp_ob_channel" */ int BpmpGetOutboundChannel() { return GetCurrentCoreId(); } /* NOTE: linux "bpmp_ch_sta" */ u32 BpmpGetChannelState(int channel) { cpu::DataSynchronizationBarrier(); return Read(g_sema_address + RES_SEMA_SHRD_SMP_STA) & CH_MASK(channel); } /* NOTE: linux "bpmp_master_free" */ bool BpmpIsMasterFree(int channel) { return BpmpGetChannelState(channel) == MA_FREE(channel); } /* NOTE: linux "bpmp_master_acked" */ bool BpmpIsMasterAcked(int channel) { return BpmpGetChannelState(channel) == MA_ACKD(channel); } /* NOTE: linux "bpmp_signal_slave" */ void BpmpSignalSlave(int channel) { Write(g_sema_address + RES_SEMA_SHRD_SMP_CLR, CH_MASK(channel)); cpu::DataSynchronizationBarrier(); } /* NOTE: linux "bpmp_free_master" */ void BpmpFreeMaster(int channel) { /* Transition state from ack'd to free. */ Write(g_sema_address + RES_SEMA_SHRD_SMP_CLR, ((MA_ACKD(channel)) ^ (MA_FREE(channel)))); cpu::DataSynchronizationBarrier(); } /* NOTE: linux "bpmp_ring_doorbell" */ void BpmpRingDoorbell() { Write(g_prictlr_address + ICTLR_FIR_SET(INT_SHR_SEM_OUTBOX_IBF), FIR_BIT(INT_SHR_SEM_OUTBOX_IBF)); cpu::DataSynchronizationBarrier(); } /* NOTE: linux "bpmp_wait_master_free" */ int BpmpWaitMasterFree(int channel) { /* Check if the master is already freed. */ if (BpmpIsMasterFree(channel)) { return 0; } /* Spin-poll for the master to be freed until timeout occurs. */ const auto start_tick = KHardwareTimer::GetTick(); const auto timeout = ams::svc::Tick(ChannelTimeout); do { if (BpmpIsMasterFree(channel)) { return 0; } } while ((KHardwareTimer::GetTick() - start_tick) < timeout); /* The master didn't become free. */ return -1; } /* NOTE: linux "bpmp_wait_ack" */ int BpmpWaitAck(int channel) { /* Check if the master is already ACK'd. */ if (BpmpIsMasterAcked(channel)) { return 0; } /* Spin-poll for the master to be ACK'd until timeout occurs. */ const auto start_tick = KHardwareTimer::GetTick(); const auto timeout = ams::svc::Tick(ChannelTimeout); do { if (BpmpIsMasterAcked(channel)) { return 0; } } while ((KHardwareTimer::GetTick() - start_tick) < timeout); /* The master didn't get ACK'd. */ return -1; } /* NOTE: linux "bpmp_write_ch" */ int BpmpWriteChannel(int channel, int mrq, int flags, const void *data, size_t data_size) { /* Wait to be able to master the mailbox. */ if (int res = BpmpWaitMasterFree(channel); res != 0) { return res; } /* Prepare the message. */ MailboxData *mb = g_channel_area[channel].ob; mb->code = mrq; mb->flags = flags; if (data != nullptr) { std::memcpy(mb->data, data, data_size); } /* Signal to slave that message is available. */ BpmpSignalSlave(channel); return 0; } /* NOTE: linux "__bpmp_read_ch" */ int BpmpReadChannel(int channel, void *data, size_t data_size) { /* Get the message. */ MailboxData *mb = g_channel_area[channel].ib; /* Copy any return data. */ if (data != nullptr) { std::memcpy(data, mb->data, data_size); } /* Free the channel. */ BpmpFreeMaster(channel); /* Return result. */ return mb->code; } /* NOTE: linux "tegra_bpmp_send_receive_atomic" or "tegra_bpmp_send_receive". */ int BpmpSendAndReceive(int mrq, const void *ob, int ob_size, void *ib, int ib_size) { /* Validate that the data transfer is valid. */ if (!IsTransferValid(ob, ob_size, ib, ib_size)) { return -1; } /* Validate that the bpmp is connected. */ if (!g_bpmp_connected) { return -1; } /* Disable interrupts. */ KScopedInterruptDisable di; /* Acquire exclusive access to send mrqs. */ KScopedSpinLock lk(g_bpmp_mrq_lock); /* Send the message. */ int channel = BpmpGetOutboundChannel(); if (int res = BpmpWriteChannel(channel, mrq, BPMP_MSG_DO_ACK, ob, ob_size); res != 0) { return res; } /* Send "doorbell" irq to the bpmp firmware. */ BpmpRingDoorbell(); /* Wait for the bpmp firmware to acknowledge our request. */ if (int res = BpmpWaitAck(channel); res != 0) { return res; } /* Read the data the bpmp sent back. */ return BpmpReadChannel(channel, ib, ib_size); } /* NOTE: linux "tegra_bpmp_send" */ int BpmpSend(int mrq, const void *ob, int ob_size) { /* Validate that the data transfer is valid. */ if (!IsTransferValid(ob, ob_size, nullptr, 0)) { return -1; } /* Validate that the bpmp is connected. */ if (!g_bpmp_connected) { return -1; } /* Disable interrupts. */ KScopedInterruptDisable di; /* Acquire exclusive access to send mrqs. */ KScopedSpinLock lk(g_bpmp_mrq_lock); /* Send the message. */ int channel = BpmpGetOutboundChannel(); if (int res = BpmpWriteChannel(channel, mrq, 0, ob, ob_size); res != 0) { return res; } /* Send "doorbell" irq to the bpmp firmware. */ BpmpRingDoorbell(); return 0; } /* NOTE: modified linux "tegra_bpmp_enable_suspend" */ int BpmpEnableSuspend(int mode, int flags) { /* Prepare data for bpmp. */ const s32 data[] = { mode, flags }; /* Send the data. */ return BpmpSend(MRQ_ENABLE_SUSPEND, data, sizeof(data)); } /* NOTE: linux "__bpmp_connect" */ int ConnectToBpmp() { /* Check if we've already connected. */ if (g_bpmp_connected) { return 0; } /* Verify that the resource semaphore state is set. */ if (Read(g_sema_address + RES_SEMA_SHRD_SMP_STA) == 0) { return -1; } /* Get the channels, which the bpmp firmware has configured in advance. */ { const KVirtualAddress iram_virt_addr = KMemoryLayout::GetDeviceVirtualAddress (KMemoryRegionType_LegacyLpsIram); const KPhysicalAddress iram_phys_addr = KMemoryLayout::GetDevicePhysicalAddress(KMemoryRegionType_LegacyLpsIram); for (auto i = 0; i < ChannelCount; ++i) { /* Trigger a get command for the desired channel. */ Write(g_atomics_address + ATOMICS_AP0_TRIGGER, TRIGGER_CMD_GET | (i << 16)); /* Retrieve the channel phys-addr-in-iram, and convert it to a kernel address. */ auto *ch = GetPointer<MailboxData>(iram_virt_addr + (Read(g_atomics_address + ATOMICS_AP0_RESULT(i)) - GetInteger(iram_phys_addr))); /* Verify the channel isn't null. */ /* NOTE: This is an utterly nonsense check, as this would require the bpmp firmware to specify */ /* a phys-to-virt diff as an address. On 1.0.0, which had no ASLR, this was 0x8028C000. */ /* However, Nintendo has the check, and we'll preserve it to be faithful. */ if (ch == nullptr) { return -1; } /* Set the channel in the channel area. */ g_channel_area[i].ib = ch; g_channel_area[i].ob = ch; } } /* Mark driver as connected to bpmp. */ g_bpmp_connected = true; return 0; } /* NOTE: Modified linux "bpmp_mail_init" */ int InitializeBpmpMail() { /* Check if we've already initialized. */ if (g_bpmp_mail_initialized) { return 0; } /* Mark function as having been called. */ g_bpmp_mail_initialized = true; /* Forward declare result/reply variables. */ int res, request = 0, reply = 0; /* Try to connect to the bpmp. */ if (res = ConnectToBpmp(); res != 0) { MESOSPHERE_LOG("bpmp: connect error returns %d\n", res); return res; } /* Ensure that we can successfully ping the bpmp. */ request = 1; if (res = BpmpSendAndReceive(MRQ_PING, std::addressof(request), sizeof(request), std::addressof(reply), sizeof(reply)); res != 0) { MESOSPHERE_LOG("bpmp: MRQ_PING error returns %d with reply %d\n", res, reply); return res; } /* Configure the PMIC. */ request = 1; if (res = BpmpSendAndReceive(MRQ_CPU_PMIC_SELECT, std::addressof(request), sizeof(request), std::addressof(reply), sizeof(reply)); res != 0) { MESOSPHERE_LOG("bpmp: MRQ_CPU_PMIC_SELECT for MAX77621 error returns %d with reply %d\n", res, reply); return res; } return 0; } } void Initialize() { if (!g_lps_init_done) { /* Get the addresses of the devices the driver needs. */ InitializeDeviceVirtualAddresses(); /* Configure CC3/CC4. */ ConfigureCc3AndCc4(); /* Initialize ccplex <-> bpmp mail. */ /* NOTE: Nintendo does not check that this call succeeds. */ InitializeBpmpMail(); g_lps_init_done = true; } } Result EnableSuspend(bool enable) { /* If we're not on core 0, there's nothing to do. */ R_SUCCEED_IF(GetCurrentCoreId() != 0); /* If we're not enabling suspend, there's nothing to do. */ R_SUCCEED_IF(!enable); /* Instruct BPMP to enable suspend-to-sc7. */ R_UNLESS(BpmpEnableSuspend(TEGRA_BPMP_PM_SC7, 0) == 0, svc::ResultInvalidState()); R_SUCCEED(); } void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) { /* Verify that we're allowed to perform suspension. */ MESOSPHERE_ABORT_UNLESS(g_lps_init_done); MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0); /* Save the CSITE clock source. */ g_csite_clk_source = Read(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE); /* Configure CSITE clock source as CLK_M. */ Write(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, (0x6 << 29)); /* Clear the top bit of PMC_SCRATCH4. */ Write(g_pmc_address + APBDEV_PMC_SCRATCH4, Read(g_pmc_address + APBDEV_PMC_SCRATCH4) & 0x7FFFFFFF); /* Write 1 to PMC_SCRATCH0. This will cause the bootrom to use the warmboot code-path. */ Write(g_pmc_address + APBDEV_PMC_SCRATCH0, 1); /* Read PMC_SCRATCH0 to be sure our write takes. */ Read(g_pmc_address + APBDEV_PMC_SCRATCH0); /* Invoke the sleep hander. */ KSleepManager::CpuSleepHandler(arg, entry, entry_arg); /* Disable deep power down. */ Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0); /* Restore the saved CSITE clock source. */ Write(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, g_csite_clk_source); /* Read the CSITE clock source to ensure our configuration takes. */ Read(g_clkrst_address + CLK_RST_CONTROLLER_CLK_SOURCE_CSITE); /* Configure CC3/CC4. */ ConfigureCc3AndCc4(); } void ResumeBpmpFirmware() { /* Halt the bpmp. */ Write(g_flow_address + FLOW_CTLR_HALT_COP_EVENTS, (0x2 << 29)); /* Hold the bpmp in reset. */ Write(g_clkrst_address + CLK_RST_CONTROLLER_RST_DEV_L_SET, 0x2); /* Read the saved bpmp entrypoint, and write it to the relevant exception vector. */ const u32 bpmp_entry = Read(g_pmc_address + APBDEV_PMC_SCRATCH39); Write(g_evp_address + EVP_COP_RESET_VECTOR, bpmp_entry); /* Verify that we can read back the address we wrote. */ while (Read(g_evp_address + EVP_COP_RESET_VECTOR) != bpmp_entry) { /* ... */ } /* Spin for 40 ticks, to give enough time for the bpmp to be reset. */ const auto start_tick = KHardwareTimer::GetTick(); do { __asm__ __volatile__("" ::: "memory"); } while ((KHardwareTimer::GetTick() - start_tick) < 40); /* Take the bpmp out of reset. */ Write(g_clkrst_address + CLK_RST_CONTROLLER_RST_DEV_L_CLR, 0x2); /* Resume the bpmp. */ Write(g_flow_address + FLOW_CTLR_HALT_COP_EVENTS, (0x0 << 29)); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> namespace ams::kern::board::nintendo::nx { namespace lps { void Initialize(); Result EnableSuspend(bool enable); void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg); void ResumeBpmpFirmware(); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_secure_monitor.hpp" namespace ams::kern::board::nintendo::nx::smc { namespace { enum UserFunctionId : u32 { UserFunctionId_SetConfig = 0xC3000401, UserFunctionId_GetConfigUser = 0xC3000002, UserFunctionId_GetResult = 0xC3000003, UserFunctionId_GetResultData = 0xC3000404, UserFunctionId_ModularExponentiate = 0xC3000E05, UserFunctionId_GenerateRandomBytes = 0xC3000006, UserFunctionId_GenerateAesKek = 0xC3000007, UserFunctionId_LoadAesKey = 0xC3000008, UserFunctionId_ComputeAes = 0xC3000009, UserFunctionId_GenerateSpecificAesKey = 0xC300000A, UserFunctionId_ComputeCmac = 0xC300040B, UserFunctionId_ReencryptDeviceUniqueData = 0xC300D60C, UserFunctionId_DecryptDeviceUniqueData = 0xC300100D, UserFunctionId_ModularExponentiateByStorageKey = 0xC300060F, UserFunctionId_PrepareEsDeviceUniqueKey = 0xC3000610, UserFunctionId_LoadPreparedAesKey = 0xC3000011, UserFunctionId_PrepareEsCommonTitleKey = 0xC3000012, }; enum FunctionId : u32 { FunctionId_GetConfig = 0xC3000004, FunctionId_GenerateRandomBytes = 0xC3000005, FunctionId_ShowError = 0xC3000006, FunctionId_ConfigureCarveout = 0xC3000007, FunctionId_ReadWriteRegister = 0xC3000008, /* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */ FunctionId_SetConfig = 0xC3000409, }; constexpr size_t GenerateRandomBytesSizeMax = sizeof(::ams::svc::lp64::SecureMonitorArguments) - sizeof(::ams::svc::lp64::SecureMonitorArguments{}.r[0]); /* Global lock for generate random bytes. */ constinit KSpinLock g_generate_random_lock; bool TryGetConfigImpl(u64 *out, size_t num_qwords, ConfigItem config_item) { /* Create the arguments .*/ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* If successful, copy the output. */ const bool success = static_cast<SmcResult>(args.r[0]) == SmcResult::Success; if (AMS_LIKELY(success)) { for (size_t i = 0; i < num_qwords && i < 7; i++) { out[i] = args.r[1 + i]; } } return success; } bool SetConfigImpl(ConfigItem config_item, u64 value) { /* Create the arguments .*/ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* Return whether the call was successful. */ return static_cast<SmcResult>(args.r[0]) == SmcResult::Success; } bool ReadWriteRegisterImpl(u32 *out, u64 address, u32 mask, u32 value) { /* Create the arguments .*/ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* Unconditionally write the output. */ *out = static_cast<u32>(args.r[1]); /* Return whether the call was successful. */ return static_cast<SmcResult>(args.r[0]) == SmcResult::Success; } bool GenerateRandomBytesImpl(void *dst, size_t size) { /* Create the arguments. */ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* If successful, copy the output. */ const bool success = static_cast<SmcResult>(args.r[0]) == SmcResult::Success; if (AMS_LIKELY(success)) { std::memcpy(dst, std::addressof(args.r[1]), size); } return success; } bool ConfigureCarveoutImpl(size_t which, uintptr_t address, size_t size) { /* Create the arguments .*/ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast<u64>(which), static_cast<u64>(address), static_cast<u64>(size) } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* Return whether the call was successful. */ return static_cast<SmcResult>(args.r[0]) == SmcResult::Success; } bool ShowErrorImpl(u32 color) { /* Create the arguments .*/ ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ShowError, color } }; /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r); /* Return whether the call was successful. */ return static_cast<SmcResult>(args.r[0]) == SmcResult::Success; } void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) { /* Call into the secure monitor. */ ::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_User>(args->r); } } /* SMC functionality needed for init. */ namespace init { void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { /* Ensure we successfully get the config. */ MESOSPHERE_INIT_ABORT_UNLESS(TryGetConfigImpl(out, num_qwords, config_item)); } void GenerateRandomBytes(void *dst, size_t size) { /* Check that the size is valid. */ MESOSPHERE_INIT_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax); /* Ensure we successfully generate the random bytes. */ MESOSPHERE_INIT_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size)); } void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) { /* Ensure we successfully access the register. */ MESOSPHERE_INIT_ABORT_UNLESS(ReadWriteRegisterImpl(out, address, mask, value)); } } bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Get the config. */ return TryGetConfigImpl(out, num_qwords, config_item); } void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { /* Ensure we successfully get the config. */ MESOSPHERE_ABORT_UNLESS(TryGetConfig(out, num_qwords, config_item)); } bool SetConfig(ConfigItem config_item, u64 value) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Set the config. */ return SetConfigImpl(config_item, value); } bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Access the register. */ return ReadWriteRegisterImpl(out, address, mask, value); } void ConfigureCarveout(size_t which, uintptr_t address, size_t size) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Ensure that we successfully configure the carveout. */ MESOSPHERE_ABORT_UNLESS(ConfigureCarveoutImpl(which, address, size)); } void GenerateRandomBytes(void *dst, size_t size) { /* Check that the size is valid. */ MESOSPHERE_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax); /* Disable interrupts. */ KScopedInterruptDisable di; /* Acquire the exclusive right to generate random bytes. */ KScopedSpinLock lk(g_generate_random_lock); /* Ensure we successfully generate the random bytes. */ MESOSPHERE_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size)); } void ShowError(u32 color) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Ensure we successfully show the error. */ MESOSPHERE_ABORT_UNLESS(ShowErrorImpl(color)); } void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Perform the call. */ CallSecureMonitorFromUserImpl(args); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> #include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp> namespace ams::kern::board::nintendo::nx::smc { /* Types. */ enum SmcId { SmcId_User = 0, SmcId_Supervisor = 1, }; enum MemorySize { MemorySize_4GB = 0, MemorySize_6GB = 1, MemorySize_8GB = 2, }; enum MemoryArrangement { MemoryArrangement_4GB = 0, MemoryArrangement_4GBForAppletDev = 1, MemoryArrangement_4GBForSystemDev = 2, MemoryArrangement_6GB = 3, MemoryArrangement_6GBForAppletDev = 4, MemoryArrangement_8GB = 5, }; enum class ConfigItem : u32 { /* Standard config items. */ DisableProgramVerification = 1, DramId = 2, SecurityEngineIrqNumber = 3, Version = 4, HardwareType = 5, IsRetail = 6, IsRecoveryBoot = 7, DeviceId = 8, BootReason = 9, MemoryMode = 10, IsDebugMode = 11, KernelConfiguration = 12, IsChargerHiZModeEnabled = 13, IsQuest = 14, RegulatorType = 15, DeviceUniqueKeyGeneration = 16, Package2Hash = 17, /* Extension config items for exosphere. */ ExosphereApiVersion = 65000, ExosphereNeedsReboot = 65001, ExosphereNeedsShutdown = 65002, ExosphereGitCommitHash = 65003, ExosphereHasRcmBugPatch = 65004, ExosphereBlankProdInfo = 65005, ExosphereAllowCalWrites = 65006, ExosphereEmummcType = 65007, ExospherePayloadAddress = 65008, ExosphereLogConfiguration = 65009, ExosphereForceEnableUsb30 = 65010, ExosphereSupportedHosVersion = 65011, }; enum class SmcResult { Success = 0, NotImplemented = 1, InvalidArgument = 2, InProgress = 3, NoAsyncOperation = 4, InvalidAsyncOperation = 5, NotPermitted = 6, }; struct KernelConfiguration { using DebugFillMemory = util::BitPack32::Field<0, 1, bool>; using EnableUserExceptionHandlers = util::BitPack32::Field<DebugFillMemory::Next, 1, bool>; using EnableUserPmuAccess = util::BitPack32::Field<EnableUserExceptionHandlers::Next, 1, bool>; using IncreaseThreadResourceLimit = util::BitPack32::Field<EnableUserPmuAccess::Next, 1, bool>; using DisableDynamicResourceLimits = util::BitPack32::Field<IncreaseThreadResourceLimit::Next, 1, bool>; using Reserved5 = util::BitPack32::Field<DisableDynamicResourceLimits::Next, 3, u32>; using UseSecureMonitorPanicCall = util::BitPack32::Field<Reserved5::Next, 1, bool>; using Reserved9 = util::BitPack32::Field<UseSecureMonitorPanicCall::Next, 7, u32>; using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, smc::MemorySize>; }; enum UserRebootType { UserRebootType_None = 0, UserRebootType_ToRcm = 1, UserRebootType_ToPayload = 2, UserRebootType_ToFatalError = 3, }; void GenerateRandomBytes(void *dst, size_t size); bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value); void ConfigureCarveout(size_t which, uintptr_t address, size_t size); bool SetConfig(ConfigItem config_item, u64 value); void ShowError(u32 color); void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); namespace init { void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item); void GenerateRandomBytes(void *dst, size_t size); void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value); } } ================================================ FILE: libraries/libmesosphere/source/board/nintendo/nx/kern_sema_registers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #define RES_SEMA_SHRD_SMP_STA 0x000 #define RES_SEMA_SHRD_SMP_SET 0x004 #define RES_SEMA_SHRD_SMP_CLR 0x008 ================================================ FILE: libraries/libmesosphere/source/board/qemu/virt/kern_k_system_control.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_secure_monitor.hpp" namespace ams::kern::board::qemu::virt { /* User access. */ void KSystemControl::CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) { /* Invoke the secure monitor. */ return smc::CallSecureMonitorFromUser(args); } } ================================================ FILE: libraries/libmesosphere/source/board/qemu/virt/kern_secure_monitor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_secure_monitor.hpp" namespace ams::kern::board::qemu::virt::smc { namespace { enum UserFunctionId : u32 { UserFunctionId_SetConfig = 0xC3000401, UserFunctionId_GetConfig = 0xC3000002, UserFunctionId_GetResult = 0xC3000003, UserFunctionId_GetResultData = 0xC3000404, UserFunctionId_ModularExponentiate = 0xC3000E05, UserFunctionId_GenerateRandomBytes = 0xC3000006, UserFunctionId_GenerateAesKek = 0xC3000007, UserFunctionId_LoadAesKey = 0xC3000008, UserFunctionId_ComputeAes = 0xC3000009, UserFunctionId_GenerateSpecificAesKey = 0xC300000A, UserFunctionId_ComputeCmac = 0xC300040B, UserFunctionId_ReencryptDeviceUniqueData = 0xC300D60C, UserFunctionId_DecryptDeviceUniqueData = 0xC300100D, UserFunctionId_ModularExponentiateByStorageKey = 0xC300060F, UserFunctionId_PrepareEsDeviceUniqueKey = 0xC3000610, UserFunctionId_LoadPreparedAesKey = 0xC3000011, UserFunctionId_PrepareEsCommonTitleKey = 0xC3000012, }; } void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) { MESOSPHERE_LOG("Received SMC [%p %p %p %p %p %p %p %p] from %s\n", reinterpret_cast<void *>(args->r[0]), reinterpret_cast<void *>(args->r[1]), reinterpret_cast<void *>(args->r[2]), reinterpret_cast<void *>(args->r[3]), reinterpret_cast<void *>(args->r[4]), reinterpret_cast<void *>(args->r[5]), reinterpret_cast<void *>(args->r[6]), reinterpret_cast<void *>(args->r[7]), GetCurrentProcess().GetName()); switch (args->r[0]) { case UserFunctionId_GetConfig: { switch (static_cast<ConfigItem>(args->r[1])) { case ConfigItem::ExosphereApiVersion: args->r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) | (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) | (static_cast<u64>(13) << 32) | (static_cast<u64>(GetTargetFirmware()) << 0); break; default: MESOSPHERE_PANIC("Unhandled GetConfig\n"); } args->r[0] = static_cast<u64>(SmcResult::Success); } break; default: MESOSPHERE_PANIC("Unhandled SMC [%p %p %p %p %p %p %p %p]", reinterpret_cast<void *>(args->r[0]), reinterpret_cast<void *>(args->r[1]), reinterpret_cast<void *>(args->r[2]), reinterpret_cast<void *>(args->r[3]), reinterpret_cast<void *>(args->r[4]), reinterpret_cast<void *>(args->r[5]), reinterpret_cast<void *>(args->r[6]), reinterpret_cast<void *>(args->r[7])); } } } ================================================ FILE: libraries/libmesosphere/source/board/qemu/virt/kern_secure_monitor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> namespace ams::kern::board::qemu::virt::smc { enum class ConfigItem : u32 { /* Standard config items. */ DisableProgramVerification = 1, DramId = 2, SecurityEngineIrqNumber = 3, Version = 4, HardwareType = 5, IsRetail = 6, IsRecoveryBoot = 7, DeviceId = 8, BootReason = 9, MemoryMode = 10, IsDebugMode = 11, KernelConfiguration = 12, IsChargerHiZModeEnabled = 13, IsQuest = 14, RegulatorType = 15, DeviceUniqueKeyGeneration = 16, Package2Hash = 17, /* Extension config items for exosphere. */ ExosphereApiVersion = 65000, ExosphereNeedsReboot = 65001, ExosphereNeedsShutdown = 65002, ExosphereGitCommitHash = 65003, ExosphereHasRcmBugPatch = 65004, ExosphereBlankProdInfo = 65005, ExosphereAllowCalWrites = 65006, ExosphereEmummcType = 65007, ExospherePayloadAddress = 65008, ExosphereLogConfiguration = 65009, ExosphereForceEnableUsb30 = 65010, ExosphereSupportedHosVersion = 65011, }; enum class SmcResult { Success = 0, NotImplemented = 1, InvalidArgument = 2, InProgress = 3, NoAsyncOperation = 4, InvalidAsyncOperation = 5, NotPermitted = 6, }; void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); } ================================================ FILE: libraries/libmesosphere/source/init/kern_init_elf.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::init::Elf { /* API to apply relocations or call init array. */ void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) { uintptr_t dyn_rel = 0; uintptr_t dyn_rela = 0; uintptr_t dyn_relr = 0; uintptr_t rel_count = 0; uintptr_t rela_count = 0; uintptr_t relr_sz = 0; uintptr_t rel_ent = 0; uintptr_t rela_ent = 0; uintptr_t relr_ent = 0; /* Iterate over all tags, identifying important extents. */ for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) { switch (cur_entry->GetTag()) { case DT_REL: dyn_rel = base_address + cur_entry->GetPtr(); break; case DT_RELA: dyn_rela = base_address + cur_entry->GetPtr(); break; case DT_RELR: dyn_relr = base_address + cur_entry->GetPtr(); break; case DT_RELENT: rel_ent = cur_entry->GetValue(); break; case DT_RELAENT: rela_ent = cur_entry->GetValue(); break; case DT_RELRENT: relr_ent = cur_entry->GetValue(); break; case DT_RELCOUNT: rel_count = cur_entry->GetValue(); break; case DT_RELACOUNT: rela_count = cur_entry->GetValue(); break; case DT_RELRSZ: relr_sz = cur_entry->GetValue(); break; } } /* Apply all Rel relocations */ if (rel_count > 0) { /* Check that the rel relocations are applyable. */ MESOSPHERE_INIT_ABORT_UNLESS(dyn_rel != 0); MESOSPHERE_INIT_ABORT_UNLESS(rel_ent == sizeof(Elf::Rel)); for (size_t i = 0; i < rel_count; ++i) { const auto &rel = reinterpret_cast<const Elf::Rel *>(dyn_rel)[i]; /* Only allow architecture-specific relocations. */ while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ } /* Apply the relocation. */ Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset()); *target_address += base_address; } } /* Apply all Rela relocations. */ if (rela_count > 0) { /* Check that the rela relocations are applyable. */ MESOSPHERE_INIT_ABORT_UNLESS(dyn_rela != 0); MESOSPHERE_INIT_ABORT_UNLESS(rela_ent == sizeof(Elf::Rela)); for (size_t i = 0; i < rela_count; ++i) { const auto &rela = reinterpret_cast<const Elf::Rela *>(dyn_rela)[i]; /* Only allow architecture-specific relocations. */ while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ } /* Apply the relocation. */ Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rela.GetOffset()); *target_address = base_address + rela.GetAddend(); } } /* Apply all Relr relocations. */ if (relr_sz >= sizeof(Elf::Relr)) { /* Check that the relr relocations are applyable. */ MESOSPHERE_INIT_ABORT_UNLESS(dyn_relr != 0); MESOSPHERE_INIT_ABORT_UNLESS(relr_ent == sizeof(Elf::Relr)); const size_t relr_count = relr_sz / sizeof(Elf::Relr); Elf::Addr *where = nullptr; for (size_t i = 0; i < relr_count; ++i) { const auto &relr = reinterpret_cast<const Elf::Relr *>(dyn_relr)[i]; if (relr.IsLocation()) { /* Update location. */ where = reinterpret_cast<Elf::Addr *>(base_address + relr.GetLocation()); /* Apply the relocation. */ *(where++) += base_address; } else { /* Get the bitmap. */ u64 bitmap = relr.GetBitmap(); /* Apply all relocations. */ while (bitmap != 0) { const u64 next = util::CountTrailingZeros(bitmap); bitmap &= ~(static_cast<u64>(1) << next); where[next] += base_address; } /* Advance. */ where += BITSIZEOF(bitmap) - 1; } } } } void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) { for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) { (*(void (**)())(cur_entry))(); } } } ================================================ FILE: libraries/libmesosphere/source/init/kern_init_slab_setup.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::init { /* For macro convenience. */ using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings; using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo; #define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS #define FOREACH_SLAB_TYPE(HANDLER, ...) \ HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \ HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \ HANDLER(KPort, (SLAB_COUNT(KPort)), ## __VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ## __VA_ARGS__) \ HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ## __VA_ARGS__) \ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ## __VA_ARGS__) \ HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ## __VA_ARGS__) \ HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ## __VA_ARGS__) \ HANDLER(KSession, (SLAB_COUNT(KSession)), ## __VA_ARGS__) \ HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ## __VA_ARGS__) \ HANDLER(KLightSession, (SLAB_COUNT(KLightSession)), ## __VA_ARGS__) \ HANDLER(KThreadLocalPage, (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), ## __VA_ARGS__) \ HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \ HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \ HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \ HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__) \ HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \ HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ## __VA_ARGS__) namespace { #define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME, enum KSlabType : u32 { FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count, }; #undef DEFINE_SLAB_TYPE_ENUM_MEMBER /* Constexpr counts. */ constexpr size_t SlabCountKProcess = 80; constexpr size_t SlabCountKThread = 800; constexpr size_t SlabCountKEvent = 900; constexpr size_t SlabCountKInterruptEvent = 100; constexpr size_t SlabCountKPort = 384; constexpr size_t SlabCountKSharedMemory = 80; constexpr size_t SlabCountKTransferMemory = 200; constexpr size_t SlabCountKCodeMemory = 10; constexpr size_t SlabCountKDeviceAddressSpace = 300; constexpr size_t SlabCountKSession = 1133; constexpr size_t SlabCountKLightSession = 100; constexpr size_t SlabCountKObjectName = 7; constexpr size_t SlabCountKResourceLimit = 5; constexpr size_t SlabCountKDebug = cpu::NumCores; constexpr size_t SlabCountKIoPool = 1; constexpr size_t SlabCountKIoRegion = 6; constexpr size_t SlabcountKSessionRequestMappings = 40; constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread; namespace test { constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo)); static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize); static_assert(KernelPageBufferHeapSize == 2 * PageSize + (SlabCountKProcess + SlabCountKThread + (SlabCountKProcess + SlabCountKThread) / 8) * PageSize); static_assert(KernelPageBufferAdditionalSize == (SlabCountExtraKThread + (SlabCountExtraKThread / 8)) * PageSize); } /* Global to hold our resource counts. */ constinit KSlabResourceCounts g_slab_resource_counts = { .num_KProcess = SlabCountKProcess, .num_KThread = SlabCountKThread, .num_KEvent = SlabCountKEvent, .num_KInterruptEvent = SlabCountKInterruptEvent, .num_KPort = SlabCountKPort, .num_KSharedMemory = SlabCountKSharedMemory, .num_KTransferMemory = SlabCountKTransferMemory, .num_KCodeMemory = SlabCountKCodeMemory, .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace, .num_KSession = SlabCountKSession, .num_KLightSession = SlabCountKLightSession, .num_KObjectName = SlabCountKObjectName, .num_KResourceLimit = SlabCountKResourceLimit, .num_KDebug = SlabCountKDebug, .num_KIoPool = SlabCountKIoPool, .num_KIoRegion = SlabCountKIoRegion, .num_KSessionRequestMappings = SlabcountKSessionRequestMappings, }; template<typename T> NOINLINE KVirtualAddress InitializeSlabHeap(KVirtualAddress address, size_t num_objects) { const size_t size = util::AlignUp(sizeof(T) * num_objects, alignof(void *)); KVirtualAddress start = util::AlignUp(GetInteger(address), alignof(T)); if (size > 0) { const KMemoryRegion *region = KMemoryLayout::Find(start + size - 1); MESOSPHERE_ABORT_UNLESS(region != nullptr); MESOSPHERE_ABORT_UNLESS(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); T::InitializeSlabHeap(GetVoidPointer(start), size); } return start + size; } } const KSlabResourceCounts &GetSlabResourceCounts() { return g_slab_resource_counts; } void InitializeSlabResourceCounts() { /* Note: Nintendo initializes all fields here, but we initialize all constants at compile-time. */ if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) { g_slab_resource_counts.num_KThread += SlabCountExtraKThread; } } size_t CalculateSlabHeapGapSize() { constexpr size_t KernelSlabHeapGapSize = 2_MB - 356_KB; static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax); return KernelSlabHeapGapSize; } size_t CalculateTotalSlabHeapSize() { size_t size = 0; #define ADD_SLAB_SIZE(NAME, COUNT, ...) ({ \ size += alignof(NAME); \ size += util::AlignUp(sizeof(NAME) * (COUNT), alignof(void *)); \ }); /* Add the size required for each slab. */ FOREACH_SLAB_TYPE(ADD_SLAB_SIZE) #undef ADD_SLAB_SIZE /* Add the reserved size. */ size += CalculateSlabHeapGapSize(); return size; } void InitializeSlabHeaps() { /* Get the slab region, since that's where we'll be working. */ const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion(); KVirtualAddress address = slab_region.GetAddress(); /* Clear the slab region. */ std::memset(GetVoidPointer(address), 0, slab_region.GetSize()); /* Initialize slab type array to be in sorted order. */ KSlabType slab_types[KSlabType_Count]; for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); } /* N shuffles the slab type array with the following simple algorithm. */ for (size_t i = 0; i < util::size(slab_types); i++) { const size_t rnd = KSystemControl::GenerateRandomRange(0, util::size(slab_types) - 1); std::swap(slab_types[i], slab_types[rnd]); } /* Create an array to represent the gaps between the slabs. */ const size_t total_gap_size = CalculateSlabHeapGapSize(); size_t slab_gaps[util::size(slab_types)]; for (size_t i = 0; i < util::size(slab_gaps); i++) { /* Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange is inclusive. */ /* However, Nintendo also has the off-by-one error, and it's "harmless", so we will include it ourselves. */ slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size); } /* Sort the array, so that we can treat differences between values as offsets to the starts of slabs. */ for (size_t i = 1; i < util::size(slab_gaps); i++) { for (size_t j = i; j > 0 && slab_gaps[j-1] > slab_gaps[j]; j--) { std::swap(slab_gaps[j], slab_gaps[j-1]); } } /* Track the gaps, so that we can free them to the unused slab tree. */ KVirtualAddress gap_start = address; size_t gap_size = 0; for (size_t i = 0; i < util::size(slab_types); i++) { /* Add the random gap to the address. */ const auto cur_gap = (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1]; address += cur_gap; gap_size += cur_gap; #define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \ case KSlabType_##NAME: \ if (COUNT > 0) { \ address = InitializeSlabHeap<NAME>(address, COUNT); \ } \ break; /* Initialize the slabheap. */ switch (slab_types[i]) { /* For each of the slab types, we want to initialize that heap. */ FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP) /* If we somehow get an invalid type, abort. */ MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } /* If we've hit the end of a gap, free it. */ if (gap_start + gap_size != address) { FreeUnusedSlabMemory(gap_start, gap_size); gap_start = address; gap_size = 0; } } /* Free the end of the slab region. */ FreeUnusedSlabMemory(gap_start, gap_size + (slab_region.GetEndAddress() - GetInteger(address))); } } namespace ams::kern { void KPageBufferSlabHeap::Initialize(KDynamicPageManager &allocator) { /* Get slab resource counts. */ const auto &counts = init::GetSlabResourceCounts(); /* If size is correct, account for thread local pages. */ if (BufferSize == PageSize) { s_buffer_count += counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8; } /* Set our object size. */ m_obj_size = BufferSize; /* Initialize the base allocator. */ KSlabHeapImpl::Initialize(); /* Allocate the desired page count. */ for (size_t i = 0; i < s_buffer_count; ++i) { /* Allocate an appropriate buffer. */ auto * const pb = (BufferSize <= PageSize) ? allocator.Allocate() : allocator.Allocate(BufferSize / PageSize); MESOSPHERE_ABORT_UNLESS(pb != nullptr); /* Free to our slab. */ KSlabHeapImpl::Free(pb); } } } ================================================ FILE: libraries/libmesosphere/source/kern_debug_log.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_debug_log_impl.hpp" namespace ams::kern { namespace { constinit KSpinLock g_debug_log_lock; constinit bool g_initialized_impl; /* NOTE: Nintendo's print buffer is size 0x100. */ constinit char g_print_buffer[0x400]; void PutString(const char *str) { /* Only print if the implementation is initialized. */ if (AMS_UNLIKELY(!g_initialized_impl)) { return; } #if defined(MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING) KDebugLogImpl::PutStringBySemihosting(str); #else while (*str) { /* Get a character. */ const char c = *(str++); /* Print the character. */ if (c == '\n') { KDebugLogImpl::PutChar('\r'); } KDebugLogImpl::PutChar(c); } KDebugLogImpl::Flush(); #endif } #if defined(MESOSPHERE_ENABLE_DEBUG_PRINT) Result PutUserString(ams::kern::svc::KUserPointer<const char *> user_str, size_t len) { /* Only print if the implementation is initialized. */ if (!g_initialized_impl) { R_SUCCEED(); } #if defined(MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING) /* TODO: should we do this properly? */ KDebugLogImpl::PutStringBySemihosting(user_str.GetUnsafePointer()); MESOSPHERE_UNUSED(len); #else for (size_t i = 0; i < len; ++i) { /* Get a character. */ char c; R_TRY(user_str.CopyArrayElementTo(std::addressof(c), i)); /* Print the character. */ if (c == '\n') { KDebugLogImpl::PutChar('\r'); } KDebugLogImpl::PutChar(c); } KDebugLogImpl::Flush(); #endif R_SUCCEED(); } #endif ALWAYS_INLINE void FormatU64(char * const dst, u64 value) { /* Adjust, so that we can print the value backwards. */ char *cur = dst + 2 * sizeof(value); /* Format the value in (as %016lx) */ while (cur > dst) { /* Extract the digit. */ const auto digit = value & 0xF; value >>= 4; *(--cur) = (digit <= 9) ? ('0' + digit) : ('a' + digit - 10); } } } void KDebugLog::Initialize() { if (KTargetSystem::IsDebugLoggingEnabled()) { KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); if (!g_initialized_impl) { g_initialized_impl = KDebugLogImpl::Initialize(); } } } void KDebugLog::Printf(const char *format, ...) { if (KTargetSystem::IsDebugLoggingEnabled()) { ::std::va_list vl; va_start(vl, format); VPrintf(format, vl); va_end(vl); } } void KDebugLog::VPrintf(const char *format, ::std::va_list vl) { if (KTargetSystem::IsDebugLoggingEnabled()) { KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); VSNPrintf(g_print_buffer, util::size(g_print_buffer), format, vl); PutString(g_print_buffer); } } void KDebugLog::VSNPrintf(char *dst, const size_t dst_size, const char *format, ::std::va_list vl) { ::ams::util::TVSNPrintf(dst, dst_size, format, vl); } void KDebugLog::LogException(const char *str) { if (KTargetSystem::IsDebugLoggingEnabled()) { /* Get the current program ID. */ /* NOTE: Nintendo does this after printing the string, */ /* but it seems wise to avoid holding the lock/disabling interrupts */ /* for longer than is strictly necessary. */ char suffix[18]; if (const auto *cur_process = GetCurrentProcessPointer(); AMS_LIKELY(cur_process != nullptr)) { FormatU64(suffix, cur_process->GetProgramId()); suffix[16] = '\n'; suffix[17] = '\x00'; } else { suffix[0] = '\n'; suffix[1] = '\x00'; } KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); /* Log the string. */ PutString(str); /* Log the program id (and newline) suffix. */ PutString(suffix); } } Result KDebugLog::PrintUserString(ams::kern::svc::KUserPointer<const char *> user_str, size_t len) { /* If printing is enabled, print the user string. */ #if defined(MESOSPHERE_ENABLE_DEBUG_PRINT) if (KTargetSystem::IsDebugLoggingEnabled()) { KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); R_TRY(PutUserString(user_str, len)); } #else MESOSPHERE_UNUSED(user_str, len); #endif R_SUCCEED(); } void KDebugLog::Save() { if (KTargetSystem::IsDebugLoggingEnabled()) { KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); KDebugLogImpl::Save(); } } void KDebugLog::Restore() { if (KTargetSystem::IsDebugLoggingEnabled()) { KScopedInterruptDisable di; KScopedSpinLock lk(g_debug_log_lock); KDebugLogImpl::Restore(); } } } ================================================ FILE: libraries/libmesosphere/source/kern_debug_log_impl.arch.arm64.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::kern::KDebugLogImpl::PutStringBySemihosting(const char *str) */ .section .text._ZN3ams4kern13KDebugLogImpl22PutStringBySemihostingEPKc, "ax", %progbits .global _ZN3ams4kern13KDebugLogImpl22PutStringBySemihostingEPKc .type _ZN3ams4kern13KDebugLogImpl22PutStringBySemihostingEPKc, %function .balign 0x10 _ZN3ams4kern13KDebugLogImpl22PutStringBySemihostingEPKc: mov x1, x0 mov x0, #0x4 hlt #0xF000 ret ================================================ FILE: libraries/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_debug_log_impl.hpp" namespace ams::kern { #if defined(MESOSPHERE_DEBUG_LOG_USE_UART) namespace { constexpr bool DoSaveAndRestore = false; enum UartRegister { UartRegister_THR = 0, UartRegister_IER = 1, UartRegister_FCR = 2, UartRegister_LCR = 3, UartRegister_LSR = 5, UartRegister_IRDA_CSR = 8, UartRegister_DLL = 0, UartRegister_DLH = 1, }; KVirtualAddress g_uart_address = 0; [[maybe_unused]] constinit u32 g_saved_registers[5]; ALWAYS_INLINE u32 ReadUartRegister(UartRegister which) { return GetPointer<volatile u32>(g_uart_address)[which]; } ALWAYS_INLINE void WriteUartRegister(UartRegister which, u32 value) { GetPointer<volatile u32>(g_uart_address)[which] = value; } } bool KDebugLogImpl::Initialize() { /* Get the uart memory region. */ const KMemoryRegion *uart_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_Uart); if (uart_region == nullptr) { return false; } /* Set the uart register base address. */ g_uart_address = uart_region->GetPairAddress(); if (g_uart_address == Null<KVirtualAddress>) { return false; } /* NOTE: We assume here that UART init/config has been done by the Secure Monitor. */ /* As such, we only need to disable interrupts. */ WriteUartRegister(UartRegister_IER, 0x00); return true; } void KDebugLogImpl::PutChar(char c) { while (ReadUartRegister(UartRegister_LSR) & 0x100) { /* While the FIFO is full, yield. */ cpu::Yield(); } WriteUartRegister(UartRegister_THR, c); cpu::DataSynchronizationBarrier(); } void KDebugLogImpl::Flush() { while ((ReadUartRegister(UartRegister_LSR) & 0x40) == 0) { /* Wait for the TMTY bit to be one (transmit empty). */ } } void KDebugLogImpl::Save() { if constexpr (DoSaveAndRestore) { /* Save LCR, IER, FCR. */ g_saved_registers[0] = ReadUartRegister(UartRegister_LCR); g_saved_registers[1] = ReadUartRegister(UartRegister_IER); g_saved_registers[2] = ReadUartRegister(UartRegister_FCR); /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ WriteUartRegister(UartRegister_LCR, 0x80); ReadUartRegister(UartRegister_LCR); /* Save DLL/DLH. */ g_saved_registers[3] = ReadUartRegister(UartRegister_DLL); g_saved_registers[4] = ReadUartRegister(UartRegister_DLH); /* Restore Divisor Latch Access bit. */ WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); ReadUartRegister(UartRegister_LCR); } } void KDebugLogImpl::Restore() { if constexpr (DoSaveAndRestore) { /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ WriteUartRegister(UartRegister_LCR, 0x80); ReadUartRegister(UartRegister_LCR); /* Restore DLL/DLH. */ WriteUartRegister(UartRegister_DLL, g_saved_registers[3]); WriteUartRegister(UartRegister_DLH, g_saved_registers[4]); ReadUartRegister(UartRegister_DLH); /* Restore Divisor Latch Access bit. */ WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); ReadUartRegister(UartRegister_LCR); /* Restore IER and FCR. */ WriteUartRegister(UartRegister_IER, g_saved_registers[1]); WriteUartRegister(UartRegister_FCR, g_saved_registers[2] | 2); WriteUartRegister(UartRegister_IRDA_CSR, 0x02); ReadUartRegister(UartRegister_FCR); } } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) namespace { constinit KVirtualAddress g_debug_iram_address = 0; constexpr size_t RingBufferSize = 0x5000; constinit uintptr_t g_offset = 0; constinit u8 g_saved_buffer[RingBufferSize]; } bool KDebugLogImpl::Initialize() { /* Set the base address. */ g_debug_iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x38000; std::memset(GetVoidPointer(g_debug_iram_address), 0xFF, RingBufferSize); return true; } void KDebugLogImpl::PutChar(char c) { GetPointer<char>(g_debug_iram_address)[g_offset++] = c; if (g_offset == RingBufferSize) { g_offset = 0; } } void KDebugLogImpl::Flush() { /* ... */ } void KDebugLogImpl::Save() { std::memcpy(g_saved_buffer, GetVoidPointer(g_debug_iram_address), RingBufferSize); } void KDebugLogImpl::Restore() { std::memcpy(GetVoidPointer(g_debug_iram_address), g_saved_buffer, RingBufferSize); } #else #error "Unknown Debug UART device!" #endif } ================================================ FILE: libraries/libmesosphere/source/kern_debug_log_impl.board.qemu_virt.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include "kern_debug_log_impl.hpp" namespace ams::kern { #if defined(MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING) bool KDebugLogImpl::Initialize() { return true; } void KDebugLogImpl::PutChar(char c) { /* TODO */ AMS_UNUSED(c); } void KDebugLogImpl::Flush() { /* ... */ } void KDebugLogImpl::Save() { /* ... */ } void KDebugLogImpl::Restore() { /* ... */ } #else #error "Unknown Debug device!" #endif } ================================================ FILE: libraries/libmesosphere/source/kern_debug_log_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <mesosphere.hpp> namespace ams::kern { class KDebugLogImpl { public: static NOINLINE bool Initialize(); static NOINLINE void PutStringBySemihosting(const char *s); static NOINLINE void PutChar(char c); static NOINLINE void Flush(); /* Functionality for preserving across sleep. */ static NOINLINE void Save(); static NOINLINE void Restore(); }; } ================================================ FILE: libraries/libmesosphere/source/kern_initial_process.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { struct InitialProcessInfo { KProcess *process; size_t stack_size; s32 priority; }; constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>; constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>; constinit size_t g_initial_process_binary_size = 0; constinit InitialProcessBinaryHeader g_initial_process_binary_header = {}; constinit size_t g_initial_process_secure_memory_size = 0; constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max(); constinit u64 g_initial_process_id_max = std::numeric_limits<u64>::min(); void LoadInitialProcessBinaryHeader() { if (g_initial_process_binary_header.magic != InitialProcessBinaryMagic) { /* Get the virtual address. */ MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>); const KVirtualAddress virt_addr = KMemoryLayout::GetLinearVirtualAddress(g_initial_process_binary_phys_addr); /* Copy and validate the header. */ g_initial_process_binary_header = *GetPointer<InitialProcessBinaryHeader>(virt_addr); MESOSPHERE_ABORT_UNLESS(g_initial_process_binary_header.magic == InitialProcessBinaryMagic); MESOSPHERE_ABORT_UNLESS(g_initial_process_binary_header.num_processes <= init::GetSlabResourceCounts().num_KProcess); /* Set the image address. */ g_initial_process_binary_address = virt_addr; /* Process/calculate the secure memory size. */ KVirtualAddress current = g_initial_process_binary_address + sizeof(InitialProcessBinaryHeader); const KVirtualAddress end = g_initial_process_binary_address + g_initial_process_binary_header.size; const size_t num_processes = g_initial_process_binary_header.num_processes; for (size_t i = 0; i < num_processes; ++i) { /* Validate that we can read the current KIP. */ MESOSPHERE_ABORT_UNLESS(current <= end - sizeof(KInitialProcessHeader)); /* Attach to the current KIP. */ KInitialProcessReader reader; KVirtualAddress data = reader.Attach(current); MESOSPHERE_ABORT_UNLESS(data != Null<KVirtualAddress>); /* If the process uses secure memory, account for that. */ if (reader.UsesSecureMemory()) { g_initial_process_secure_memory_size += reader.GetSize() + util::AlignUp(reader.GetStackSize(), PageSize); } /* Advance to the next KIP. */ current = data + reader.GetBinarySize(); } } } void CreateProcesses(InitialProcessInfo *infos) { /* Determine process image extents. */ KVirtualAddress current = g_initial_process_binary_address + sizeof(InitialProcessBinaryHeader); KVirtualAddress end = g_initial_process_binary_address + g_initial_process_binary_header.size; /* Decide on pools to use. */ const auto unsafe_pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool()); const auto secure_pool = (GetTargetFirmware() >= TargetFirmware_2_0_0) ? KMemoryManager::Pool_Secure : unsafe_pool; const size_t num_processes = g_initial_process_binary_header.num_processes; for (size_t i = 0; i < num_processes; ++i) { /* Validate that we can read the current KIP header. */ MESOSPHERE_ABORT_UNLESS(current <= end - sizeof(KInitialProcessHeader)); /* Attach to the current kip. */ KInitialProcessReader reader; KVirtualAddress data = reader.Attach(current); MESOSPHERE_ABORT_UNLESS(data != Null<KVirtualAddress>); /* Ensure that the remainder of our parse is page aligned. */ if (!util::IsAligned(GetInteger(data), PageSize)) { const KVirtualAddress aligned_data = util::AlignDown(GetInteger(data), PageSize); std::memmove(GetVoidPointer(aligned_data), GetVoidPointer(data), end - data); data = aligned_data; end -= (data - aligned_data); } /* If we crossed a page boundary, free the pages we're done using. */ if (KVirtualAddress aligned_current = util::AlignDown(GetInteger(current), PageSize); aligned_current != data) { const size_t freed_size = data - aligned_current; Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(aligned_current), freed_size / PageSize); Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, freed_size); } /* Parse process parameters. */ ams::svc::CreateProcessParameter params; MESOSPHERE_R_ABORT_UNLESS(reader.MakeCreateProcessParameter(std::addressof(params), true)); /* Get the binary size for the kip. */ const size_t binary_size = reader.GetBinarySize(); const size_t binary_pages = binary_size / PageSize; /* Get the pool for both the current (compressed) image, and the decompressed process. */ const auto src_pool = Kernel::GetMemoryManager().GetPool(KMemoryLayout::GetLinearPhysicalAddress(data)); const auto dst_pool = reader.UsesSecureMemory() ? secure_pool : unsafe_pool; /* Determine the process size, and how much memory isn't already reserved. */ const size_t process_size = params.code_num_pages * PageSize; const size_t unreserved_size = process_size - (src_pool == dst_pool ? util::AlignDown(binary_size, PageSize) : 0); /* Reserve however much memory we need to reserve. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, unreserved_size)); /* Create the process. */ KProcess *new_process = nullptr; { /* Make page groups to represent the data. */ KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); KPageGroup workaround_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); /* Populate the page group to represent the data. */ { /* Allocate the previously unreserved pages. */ KPageGroup unreserve_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, 1, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront))); /* Add the previously reserved pages. */ if (src_pool == dst_pool && binary_pages != 0) { MESOSPHERE_R_ABORT_UNLESS(pg.AddBlock(KMemoryLayout::GetLinearPhysicalAddress(data), binary_pages)); } /* Add the previously unreserved pages. */ for (const auto &block : unreserve_pg) { MESOSPHERE_R_ABORT_UNLESS(pg.AddBlock(block.GetAddress(), block.GetNumPages())); } } MESOSPHERE_ABORT_UNLESS(pg.GetNumPages() == static_cast<size_t>(params.code_num_pages)); /* Ensure that we do not leak pages. */ KPageGroup *process_pg = std::addressof(pg); ON_SCOPE_EXIT { process_pg->Close(); }; /* Load the process. */ reader.Load(pg, data); /* If necessary, close/release the aligned part of the data we just loaded. */ if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) { Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(data), aligned_bin_size / PageSize); Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size); } /* Create a KProcess object. */ new_process = KProcess::Create(); MESOSPHERE_ABORT_UNLESS(new_process != nullptr); /* Ensure the page group is usable for the process. */ /* If the pool is the same, we need to use the workaround page group. */ if (src_pool == dst_pool) { /* Allocate a new, usable group for the process. */ MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(workaround_pg), static_cast<size_t>(params.code_num_pages), 1, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront))); /* Copy data from the working page group to the usable one. */ auto work_it = pg.begin(); MESOSPHERE_ABORT_UNLESS(work_it != pg.end()); { auto work_address = work_it->GetAddress(); auto work_remaining = work_it->GetNumPages(); for (const auto &block : workaround_pg) { auto block_address = block.GetAddress(); auto block_remaining = block.GetNumPages(); while (block_remaining > 0) { if (work_remaining == 0) { ++work_it; work_address = work_it->GetAddress(); work_remaining = work_it->GetNumPages(); } const size_t cur_pages = std::min(block_remaining, work_remaining); const size_t cur_size = cur_pages * PageSize; std::memcpy(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_address)), GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(work_address)), cur_size); block_address += cur_size; work_address += cur_size; block_remaining -= cur_pages; work_remaining -= cur_pages; } } ++work_it; } MESOSPHERE_ABORT_UNLESS(work_it == pg.end()); /* We want to use the new page group. */ process_pg = std::addressof(workaround_pg); pg.Close(); } /* Initialize the process. */ MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal())); } /* Set the process's memory permissions. */ MESOSPHERE_R_ABORT_UNLESS(reader.SetMemoryPermissions(new_process->GetPageTable(), params)); /* Register the process. */ KProcess::Register(new_process); /* Set the ideal core id. */ new_process->SetIdealCoreId(reader.GetIdealCoreId()); /* Save the process info. */ infos[i].process = new_process; infos[i].stack_size = reader.GetStackSize(); infos[i].priority = reader.GetPriority(); /* Advance the reader. */ current = data + binary_size; } /* Release remaining memory used by the image. */ { const size_t remaining_size = util::AlignUp(GetInteger(g_initial_process_binary_address) + g_initial_process_binary_header.size, PageSize) - util::AlignDown(GetInteger(current), PageSize); const size_t remaining_pages = remaining_size / PageSize; Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(util::AlignDown(GetInteger(current), PageSize)), remaining_pages); Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, remaining_size); } } } void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size) { MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>); g_initial_process_binary_phys_addr = phys_addr; g_initial_process_binary_size = size; } KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() { MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>); return g_initial_process_binary_phys_addr; } size_t GetInitialProcessBinarySize() { MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>); return g_initial_process_binary_size; } u64 GetInitialProcessIdMin() { return g_initial_process_id_min; } u64 GetInitialProcessIdMax() { return g_initial_process_id_max; } size_t GetInitialProcessesSecureMemorySize() { LoadInitialProcessBinaryHeader(); return g_initial_process_secure_memory_size; } size_t CopyInitialProcessBinaryToKernelMemory() { LoadInitialProcessBinaryHeader(); if (g_initial_process_binary_header.num_processes > 0) { /* Ensure that we have a non-zero size. */ const size_t expected_size = g_initial_process_binary_size; MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0); /* Ensure that the size we need to reserve is as we expect it to be. */ const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize); MESOSPHERE_ABORT_UNLESS(total_size == expected_size); MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax); /* Reserve pages for the initial process binary from the system resource limit. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size)); return total_size; } else { return 0; } } void CreateAndRunInitialProcesses() { /* Allocate space for the processes. */ InitialProcessInfo *infos = static_cast<InitialProcessInfo *>(__builtin_alloca(sizeof(InitialProcessInfo) * g_initial_process_binary_header.num_processes)); /* Create the processes. */ CreateProcesses(infos); /* Determine the initial process id range. */ for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) { const auto pid = infos[i].process->GetId(); g_initial_process_id_min = std::min(g_initial_process_id_min, pid); g_initial_process_id_max = std::max(g_initial_process_id_max, pid); } /* Run the processes. */ for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) { MESOSPHERE_R_ABORT_UNLESS(infos[i].process->Run(infos[i].priority, infos[i].stack_size)); infos[i].process->Close(); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_address_arbiter.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { ALWAYS_INLINE bool ReadFromUser(s32 *out, KProcessAddress address) { return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address)); } ALWAYS_INLINE bool ReadFromUser(s64 *out, KProcessAddress address) { return UserspaceAccess::CopyMemoryFromUserSize64Bit(out, GetVoidPointer(address)); } ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) { /* NOTE: If scheduler lock is not held here, interrupt disable is required. */ /* KScopedInterruptDisable di; */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); if (!cpu::CanAccessAtomic(address)) { return false; } return UserspaceAccess::DecrementIfLessThanAtomic(out, GetPointer<s32>(address), value); } ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) { /* NOTE: If scheduler lock is not held here, interrupt disable is required. */ /* KScopedInterruptDisable di; */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); if (!cpu::CanAccessAtomic(address)) { return false; } return UserspaceAccess::UpdateIfEqualAtomic(out, GetPointer<s32>(address), value, new_value); } class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { private: KAddressArbiter::ThreadTree *m_tree; public: constexpr ThreadQueueImplForKAddressArbiter(KAddressArbiter::ThreadTree *t) : KThreadQueue(), m_tree(t) { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* If the thread is waiting on an address arbiter, remove it from the tree. */ if (waiting_thread->IsWaitingForAddressArbiter()) { m_tree->erase(m_tree->iterator_to(*waiting_thread)); waiting_thread->ClearAddressArbiter(); } /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } Result KAddressArbiter::Signal(uintptr_t addr, s32 count) { /* Perform signaling. */ s32 num_waiters = 0; { KScopedSchedulerLock sl; auto it = m_tree.nfind_key({ addr, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { /* End the thread's wait. */ KThread *target_thread = std::addressof(*it); target_thread->EndWait(ResultSuccess()); MESOSPHERE_ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->ClearAddressArbiter(); it = m_tree.erase(it); ++num_waiters; } } R_SUCCEED(); } Result KAddressArbiter::SignalAndIncrementIfEqual(uintptr_t addr, s32 value, s32 count) { /* Perform signaling. */ s32 num_waiters = 0; { KScopedSchedulerLock sl; /* Check the userspace value. */ s32 user_value; R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory()); R_UNLESS(user_value == value, svc::ResultInvalidState()); auto it = m_tree.nfind_key({ addr, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { /* End the thread's wait. */ KThread *target_thread = std::addressof(*it); target_thread->EndWait(ResultSuccess()); MESOSPHERE_ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->ClearAddressArbiter(); it = m_tree.erase(it); ++num_waiters; } } R_SUCCEED(); } Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count) { /* Perform signaling. */ s32 num_waiters = 0; { KScopedSchedulerLock sl; auto it = m_tree.nfind_key({ addr, -1 }); /* Determine the updated value. */ s32 new_value; if (count <= 0) { if ((it != m_tree.end()) && (it->GetAddressArbiterKey() == addr)) { new_value = value - 1; } else { new_value = value + 1; } } else { if ((it != m_tree.end()) && (it->GetAddressArbiterKey() == addr)) { auto tmp_it = it; s32 tmp_num_waiters = 0; while ((++tmp_it != m_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr)) { if ((++tmp_num_waiters) >= count) { break; } } if (tmp_num_waiters < count) { new_value = value - 1; } else { new_value = value; } } else { new_value = value + 1; } } /* Check the userspace value. */ s32 user_value; bool succeeded; if (value != new_value) { succeeded = UpdateIfEqual(std::addressof(user_value), addr, value, new_value); } else { succeeded = ReadFromUser(std::addressof(user_value), addr); } R_UNLESS(succeeded, svc::ResultInvalidCurrentMemory()); R_UNLESS(user_value == value, svc::ResultInvalidState()); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { /* End the thread's wait. */ KThread *target_thread = std::addressof(*it); target_thread->EndWait(ResultSuccess()); MESOSPHERE_ASSERT(target_thread->IsWaitingForAddressArbiter()); target_thread->ClearAddressArbiter(); it = m_tree.erase(it); ++num_waiters; } } R_SUCCEED(); } Result KAddressArbiter::WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout) { /* Prepare to wait. */ KThread *cur_thread = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree)); { KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); /* Check that the thread isn't terminating. */ if (cur_thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Read the value from userspace. */ s32 user_value; bool succeeded; if (decrement) { succeeded = DecrementIfLessThan(std::addressof(user_value), addr, value); } else { succeeded = ReadFromUser(std::addressof(user_value), addr); } if (!succeeded) { slp.CancelSleep(); R_THROW(svc::ResultInvalidCurrentMemory()); } /* Check that the value is less than the specified one. */ if (user_value >= value) { slp.CancelSleep(); R_THROW(svc::ResultInvalidState()); } /* Check that the timeout is non-zero. */ if (timeout == 0) { slp.CancelSleep(); R_THROW(svc::ResultTimedOut()); } /* Set the arbiter. */ cur_thread->SetAddressArbiter(std::addressof(m_tree), addr); m_tree.insert(*cur_thread); /* Wait for the thread to finish. */ wait_queue.SetHardwareTimer(timer); cur_thread->BeginWait(std::addressof(wait_queue)); } /* Get the wait result. */ R_RETURN(cur_thread->GetWaitResult()); } Result KAddressArbiter::WaitIfEqual(uintptr_t addr, s32 value, s64 timeout) { /* Prepare to wait. */ KThread *cur_thread = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree)); { KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); /* Check that the thread isn't terminating. */ if (cur_thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Read the value from userspace. */ s32 user_value; if (!ReadFromUser(std::addressof(user_value), addr)) { slp.CancelSleep(); R_THROW(svc::ResultInvalidCurrentMemory()); } /* Check that the value is equal. */ if (value != user_value) { slp.CancelSleep(); R_THROW(svc::ResultInvalidState()); } /* Check that the timeout is non-zero. */ if (timeout == 0) { slp.CancelSleep(); R_THROW(svc::ResultTimedOut()); } /* Set the arbiter. */ cur_thread->SetAddressArbiter(std::addressof(m_tree), addr); m_tree.insert(*cur_thread); /* Wait for the thread to finish. */ wait_queue.SetHardwareTimer(timer); cur_thread->BeginWait(std::addressof(wait_queue)); } /* Get the wait result. */ R_RETURN(cur_thread->GetWaitResult()); } Result KAddressArbiter::WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout) { /* Prepare to wait. */ KThread *cur_thread = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree)); { KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); /* Check that the thread isn't terminating. */ if (cur_thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Read the value from userspace. */ s64 user_value; if (!ReadFromUser(std::addressof(user_value), addr)) { slp.CancelSleep(); R_THROW(svc::ResultInvalidCurrentMemory()); } /* Check that the value is equal. */ if (value != user_value) { slp.CancelSleep(); R_THROW(svc::ResultInvalidState()); } /* Check that the timeout is non-zero. */ if (timeout == 0) { slp.CancelSleep(); R_THROW(svc::ResultTimedOut()); } /* Set the arbiter. */ cur_thread->SetAddressArbiter(std::addressof(m_tree), addr); m_tree.insert(*cur_thread); /* Wait for the thread to finish. */ wait_queue.SetHardwareTimer(timer); cur_thread->BeginWait(std::addressof(wait_queue)); } /* Get the wait result. */ R_RETURN(cur_thread->GetWaitResult()); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_address_space_info.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max(); constinit KAddressSpaceInfo AddressSpaceInfos[] = { { 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, }, { 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, }, { 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, }, { 32, Invalid, ams::svc::AddressMemoryRegionAlias32Size, KAddressSpaceInfo::Type_Alias, }, { 36, ams::svc::AddressSmallMap36Start, ams::svc::AddressSmallMap36Size, KAddressSpaceInfo::Type_MapSmall, }, { 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, }, { 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, }, { 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, }, { 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_Map39Bit, }, { 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, }, { 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, }, { 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, }, { 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, }, }; constexpr u8 FlagsToAddressSpaceWidthTable[4] = { 32, 36, 32, 39 }; constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) { /* Convert the input flags to an array index. */ const size_t idx = (flags & ams::svc::CreateProcessFlag_AddressSpaceMask) >> ams::svc::CreateProcessFlag_AddressSpaceShift; MESOSPHERE_ABORT_UNLESS(idx < sizeof(FlagsToAddressSpaceWidthTable)); /* Return the width. */ return FlagsToAddressSpaceWidthTable[idx]; } static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32Bit) == 32); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32); static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39); KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { for (auto &info : AddressSpaceInfos) { if (info.GetWidth() == width && info.GetType() == type) { return info; } } MESOSPHERE_PANIC("Could not find AddressSpaceInfo"); } } uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type, size_t code_size) { MESOSPHERE_UNUSED(code_size); return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetAddress(); } size_t KAddressSpaceInfo::GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) { /* Extract the address space from the create process flags. */ const auto as_flags = (flags & ams::svc::CreateProcessFlag_AddressSpaceMask); /* Get the address space width. */ const auto as_width = GetAddressSpaceWidth(flags); /* Get the size. */ size_t as_size = GetAddressSpaceInfo(as_width, type).GetSize(); /* If we're getting size for 32-bit without alias, adjust the sizes accordingly. */ if (as_flags == ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) { switch (type) { /* The heap space receives space that would otherwise go to the alias space. */ case KAddressSpaceInfo::Type_Heap: as_size += GetAddressSpaceInfo(as_width, KAddressSpaceInfo::Type_Alias).GetSize(); break; /* The alias space doesn't exist. */ case KAddressSpaceInfo::Type_Alias: as_size = 0; break; /* Nothing to do by default. */ default: break; } } return as_size; } void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) { GetAddressSpaceInfo(width, type).SetSize(size); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_capabilities.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KCapabilities::Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table) { /* We're initializing an initial process. */ m_svc_access_flags.Reset(); m_irq_access_flags.Reset(); m_debug_capabilities = {0}; m_handle_table_size = 0; m_intended_kernel_version = {0}; m_program_type = 0; /* Initial processes may run on all cores. */ constexpr u64 VirtMask = cpu::VirtualCoreMask; constexpr u64 PhysMask = cpu::ConvertVirtualCoreMaskToPhysical(VirtMask); m_core_mask = VirtMask; m_phys_core_mask = PhysMask; /* Initial processes may use any user priority they like. */ m_priority_mask = ~0xFul; /* Here, Nintendo sets the kernel version to the current kernel version. */ /* We will follow suit and set the version to the highest supported kernel version. */ m_intended_kernel_version.Set<KernelVersion::MajorVersion>(ams::svc::SupportedKernelMajorVersion); m_intended_kernel_version.Set<KernelVersion::MinorVersion>(ams::svc::SupportedKernelMinorVersion); /* Parse the capabilities array. */ R_RETURN(this->SetCapabilities(caps, num_caps, page_table)); } Result KCapabilities::Initialize(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table) { /* We're initializing a user process. */ m_svc_access_flags.Reset(); m_irq_access_flags.Reset(); m_debug_capabilities = {0}; m_handle_table_size = 0; m_intended_kernel_version = {0}; m_program_type = 0; /* User processes must specify what cores/priorities they can use. */ m_core_mask = 0; m_priority_mask = 0; /* Parse the user capabilities array. */ R_RETURN(this->SetCapabilities(user_caps, num_caps, page_table)); } Result KCapabilities::SetCorePriorityCapability(const util::BitPack32 cap) { /* We can't set core/priority if we've already set them. */ R_UNLESS(m_core_mask == 0, svc::ResultInvalidArgument()); R_UNLESS(m_priority_mask == 0, svc::ResultInvalidArgument()); /* Validate the core/priority. */ const auto min_core = cap.Get<CorePriority::MinimumCoreId>(); const auto max_core = cap.Get<CorePriority::MaximumCoreId>(); const auto max_prio = cap.Get<CorePriority::LowestThreadPriority>(); const auto min_prio = cap.Get<CorePriority::HighestThreadPriority>(); R_UNLESS(min_core <= max_core, svc::ResultInvalidCombination()); R_UNLESS(min_prio <= max_prio, svc::ResultInvalidCombination()); R_UNLESS(max_core < cpu::NumVirtualCores, svc::ResultInvalidCoreId()); MESOSPHERE_ASSERT(max_prio < BITSIZEOF(u64)); /* Set core mask. */ for (auto core_id = min_core; core_id <= max_core; core_id++) { m_core_mask |= (1ul << core_id); } MESOSPHERE_ASSERT((m_core_mask & cpu::VirtualCoreMask) == m_core_mask); /* Set physical core mask. */ m_phys_core_mask = cpu::ConvertVirtualCoreMaskToPhysical(m_core_mask); /* Set priority mask. */ for (auto prio = min_prio; prio <= max_prio; prio++) { m_priority_mask |= (1ul << prio); } /* We must have some core/priority we can use. */ R_UNLESS(m_core_mask != 0, svc::ResultInvalidArgument()); R_UNLESS(m_priority_mask != 0, svc::ResultInvalidArgument()); /* Processes must not have access to kernel thread priorities. */ R_UNLESS((m_priority_mask & 0xF) == 0, svc::ResultInvalidArgument()); R_SUCCEED(); } Result KCapabilities::SetSyscallMaskCapability(const util::BitPack32 cap, u32 &set_svc) { /* Validate the index. */ const auto mask = cap.Get<SyscallMask::Mask>(); const auto index = cap.Get<SyscallMask::Index>(); const u32 index_flag = (1u << index); R_UNLESS((set_svc & index_flag) == 0, svc::ResultInvalidCombination()); set_svc |= index_flag; /* Set SVCs. */ for (size_t i = 0; i < SyscallMask::Mask::Count; i++) { const u32 svc_id = SyscallMask::Mask::Count * index + i; if (mask & (1u << i)) { R_UNLESS(this->SetSvcAllowed(svc_id), svc::ResultOutOfRange()); } } R_SUCCEED(); } Result KCapabilities::MapRange(const util::BitPack32 cap, const util::BitPack32 size_cap, KProcessPageTable *page_table) { /* Get/validate address/size */ #if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES) const u64 phys_addr = static_cast<u64>(cap.Get<MapRange::Address>() | (size_cap.Get<MapRangeSize::AddressHigh>() << MapRange::Address::Count)) * PageSize; #else const u64 phys_addr = static_cast<u64>(cap.Get<MapRange::Address>()) * PageSize; /* Validate reserved bits are unused. */ R_UNLESS(size_cap.Get<MapRangeSize::Reserved>() == 0, svc::ResultOutOfRange()); #endif const size_t num_pages = size_cap.Get<MapRangeSize::Pages>(); const size_t size = num_pages * PageSize; R_UNLESS(phys_addr == GetInteger(KPhysicalAddress(phys_addr)), svc::ResultInvalidAddress()); R_UNLESS(num_pages != 0, svc::ResultInvalidSize()); R_UNLESS(phys_addr < phys_addr + size, svc::ResultInvalidAddress()); R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, svc::ResultInvalidAddress()); /* Do the mapping. */ const KMemoryPermission perm = cap.Get<MapRange::ReadOnly>() ? KMemoryPermission_UserRead : KMemoryPermission_UserReadWrite; if (size_cap.Get<MapRangeSize::Normal>()) { R_RETURN(page_table->MapStatic(phys_addr, size, perm)); } else { R_RETURN(page_table->MapIo(phys_addr, size, perm)); } } Result KCapabilities::MapIoPage(const util::BitPack32 cap, KProcessPageTable *page_table) { /* Get/validate address/size */ const u64 phys_addr = cap.Get<MapIoPage::Address>() * PageSize; const size_t num_pages = 1; const size_t size = num_pages * PageSize; R_UNLESS(phys_addr == GetInteger(KPhysicalAddress(phys_addr)), svc::ResultInvalidAddress()); R_UNLESS(num_pages != 0, svc::ResultInvalidSize()); R_UNLESS(phys_addr < phys_addr + size, svc::ResultInvalidAddress()); R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, svc::ResultInvalidAddress()); /* Do the mapping. */ R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite)); } template<typename F> ALWAYS_INLINE Result KCapabilities::ProcessMapRegionCapability(const util::BitPack32 cap, F f) { /* Define the allowed memory regions. */ constexpr const KMemoryRegionType MemoryRegions[] = { KMemoryRegionType_None, KMemoryRegionType_KernelTraceBuffer, KMemoryRegionType_OnMemoryBootImage, KMemoryRegionType_DTB, }; /* Extract regions/read only. */ const RegionType types[3] = { cap.Get<MapRegion::Region0>(), cap.Get<MapRegion::Region1>(), cap.Get<MapRegion::Region2>(), }; const bool ro[3] = { cap.Get<MapRegion::ReadOnly0>(), cap.Get<MapRegion::ReadOnly1>(), cap.Get<MapRegion::ReadOnly2>(), }; for (size_t i = 0; i < util::size(types); i++) { const auto type = types[i]; const auto perm = ro[i] ? KMemoryPermission_UserRead : KMemoryPermission_UserReadWrite; switch (type) { case RegionType::NoMapping: break; case RegionType::KernelTraceBuffer: /* NOTE: This does not match official, but is used to make pre-processing hbl capabilities in userland unnecessary. */ /* If ktrace isn't enabled, allow ktrace to succeed without mapping anything. */ if constexpr (!ams::kern::IsKTraceEnabled) { break; } case RegionType::OnMemoryBootImage: case RegionType::DTB: R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm)); break; default: R_THROW(svc::ResultNotFound()); } } R_SUCCEED(); } Result KCapabilities::MapRegion(const util::BitPack32 cap, KProcessPageTable *page_table) { /* Map each region into the process's page table. */ R_RETURN(ProcessMapRegionCapability(cap, [page_table] ALWAYS_INLINE_LAMBDA (KMemoryRegionType region_type, KMemoryPermission perm) -> Result { R_RETURN(page_table->MapRegion(region_type, perm)); })); } Result KCapabilities::CheckMapRegion(const util::BitPack32 cap) { /* Check that each region has a physical backing store. */ R_RETURN(ProcessMapRegionCapability(cap, [] ALWAYS_INLINE_LAMBDA (KMemoryRegionType region_type, KMemoryPermission perm) -> Result { MESOSPHERE_UNUSED(perm); R_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(region_type) != nullptr, svc::ResultOutOfRange()); R_SUCCEED(); })); } Result KCapabilities::SetInterruptPairCapability(const util::BitPack32 cap) { /* Extract interrupts. */ const u32 ids[2] = { cap.Get<InterruptPair::InterruptId0>(), cap.Get<InterruptPair::InterruptId1>(), }; for (size_t i = 0; i < util::size(ids); i++) { if (ids[i] != PaddingInterruptId) { R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), svc::ResultOutOfRange()); R_UNLESS(this->SetInterruptPermitted(ids[i]), svc::ResultOutOfRange()); } } R_SUCCEED(); } Result KCapabilities::SetProgramTypeCapability(const util::BitPack32 cap) { /* Validate. */ R_UNLESS(cap.Get<ProgramType::Reserved>() == 0, svc::ResultReservedUsed()); m_program_type = cap.Get<ProgramType::Type>(); R_SUCCEED(); } Result KCapabilities::SetKernelVersionCapability(const util::BitPack32 cap) { /* Ensure we haven't set our version before. */ R_UNLESS(m_intended_kernel_version.Get<KernelVersion::MajorVersion>() == 0, svc::ResultInvalidArgument()); /* Set, ensure that we set a valid version. */ m_intended_kernel_version = cap; R_UNLESS(m_intended_kernel_version.Get<KernelVersion::MajorVersion>() != 0, svc::ResultInvalidArgument()); R_SUCCEED(); } Result KCapabilities::SetHandleTableCapability(const util::BitPack32 cap) { /* Validate. */ R_UNLESS(cap.Get<HandleTable::Reserved>() == 0, svc::ResultReservedUsed()); m_handle_table_size = cap.Get<HandleTable::Size>(); R_SUCCEED(); } Result KCapabilities::SetDebugFlagsCapability(const util::BitPack32 cap) { /* Validate. */ R_UNLESS(cap.Get<DebugFlags::Reserved>() == 0, svc::ResultReservedUsed()); u32 total = 0; if (cap.Get<DebugFlags::AllowDebug>()) { ++total; } if (cap.Get<DebugFlags::ForceDebugProd>()) { ++total; } if (cap.Get<DebugFlags::ForceDebug>()) { ++total; } R_UNLESS(total <= 1, svc::ResultInvalidCombination()); m_debug_capabilities.Set<DebugFlags::AllowDebug>(cap.Get<DebugFlags::AllowDebug>()); m_debug_capabilities.Set<DebugFlags::ForceDebugProd>(cap.Get<DebugFlags::ForceDebugProd>()); m_debug_capabilities.Set<DebugFlags::ForceDebug>(cap.Get<DebugFlags::ForceDebug>()); R_SUCCEED(); } Result KCapabilities::SetCapability(const util::BitPack32 cap, u32 &set_flags, u32 &set_svc, KProcessPageTable *page_table) { /* Validate this is a capability we can act on. */ const auto type = GetCapabilityType(cap); R_UNLESS(type != CapabilityType::Invalid, svc::ResultInvalidArgument()); /* If the type is padding, we have no work to do. */ R_SUCCEED_IF(type == CapabilityType::Padding); /* Check that we haven't already processed this capability. */ const auto flag = GetCapabilityFlag(type); R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, svc::ResultInvalidCombination()); set_flags |= flag; /* Process the capability. */ switch (type) { case CapabilityType::CorePriority: R_RETURN(this->SetCorePriorityCapability(cap)); case CapabilityType::SyscallMask: R_RETURN(this->SetSyscallMaskCapability(cap, set_svc)); case CapabilityType::MapIoPage: R_RETURN(this->MapIoPage(cap, page_table)); case CapabilityType::MapRegion: R_RETURN(this->MapRegion(cap, page_table)); case CapabilityType::InterruptPair: R_RETURN(this->SetInterruptPairCapability(cap)); case CapabilityType::ProgramType: R_RETURN(this->SetProgramTypeCapability(cap)); case CapabilityType::KernelVersion: R_RETURN(this->SetKernelVersionCapability(cap)); case CapabilityType::HandleTable: R_RETURN(this->SetHandleTableCapability(cap)); case CapabilityType::DebugFlags: R_RETURN(this->SetDebugFlagsCapability(cap)); default: R_THROW(svc::ResultInvalidArgument()); } } Result KCapabilities::SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table) { u32 set_flags = 0, set_svc = 0; for (s32 i = 0; i < num_caps; i++) { const util::BitPack32 cap = { caps[i] }; if (GetCapabilityType(cap) == CapabilityType::MapRange) { /* Check that the pair cap exists. */ R_UNLESS((++i) < num_caps, svc::ResultInvalidCombination()); /* Check the pair cap is a map range cap. */ const util::BitPack32 size_cap = { caps[i] }; R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange, svc::ResultInvalidCombination()); /* Map the range. */ R_TRY(this->MapRange(cap, size_cap, page_table)); } else { R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); } } R_SUCCEED(); } Result KCapabilities::SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table) { u32 set_flags = 0, set_svc = 0; for (s32 i = 0; i < num_caps; i++) { /* Read the cap from userspace. */ u32 cap0; R_TRY(user_caps.CopyArrayElementTo(std::addressof(cap0), i)); const util::BitPack32 cap = { cap0 }; if (GetCapabilityType(cap) == CapabilityType::MapRange) { /* Check that the pair cap exists. */ R_UNLESS((++i) < num_caps, svc::ResultInvalidCombination()); /* Read the second cap from userspace. */ u32 cap1; R_TRY(user_caps.CopyArrayElementTo(std::addressof(cap1), i)); /* Check the pair cap is a map range cap. */ const util::BitPack32 size_cap = { cap1 }; R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange, svc::ResultInvalidCombination()); /* Map the range. */ R_TRY(this->MapRange(cap, size_cap, page_table)); } else { R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); } } R_SUCCEED(); } Result KCapabilities::CheckCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps) { for (s32 i = 0; i < num_caps; ++i) { /* Read the cap from userspace. */ u32 cap0; R_TRY(user_caps.CopyArrayElementTo(std::addressof(cap0), i)); /* Check the capability refers to a valid region. */ const util::BitPack32 cap = { cap0 }; if (GetCapabilityType(cap) == CapabilityType::MapRegion) { R_TRY(CheckMapRegion(cap)); } } R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_class_token.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { /* Ensure that we generate correct class tokens for all types. */ /* Ensure that the absolute token values are correct. */ static_assert(ClassToken<KAutoObject> == 0b00000000'00000000); static_assert(ClassToken<KSynchronizationObject> == 0b00000000'00000001); static_assert(ClassToken<KReadableEvent> == 0b00000000'00000011); static_assert(ClassToken<KInterruptEvent> == 0b00000111'00000011); static_assert(ClassToken<KDebug> == 0b00001011'00000001); static_assert(ClassToken<KThread> == 0b00010011'00000001); static_assert(ClassToken<KServerPort> == 0b00100011'00000001); static_assert(ClassToken<KServerSession> == 0b01000011'00000001); static_assert(ClassToken<KClientPort> == 0b10000011'00000001); static_assert(ClassToken<KClientSession> == 0b00001101'00000000); static_assert(ClassToken<KProcess> == 0b00010101'00000001); static_assert(ClassToken<KResourceLimit> == 0b00100101'00000000); static_assert(ClassToken<KLightSession> == 0b01000101'00000000); static_assert(ClassToken<KPort> == 0b10000101'00000000); static_assert(ClassToken<KSession> == 0b00011001'00000000); static_assert(ClassToken<KSharedMemory> == 0b00101001'00000000); static_assert(ClassToken<KEvent> == 0b01001001'00000000); static_assert(ClassToken<KLightClientSession> == 0b10001001'00000000); static_assert(ClassToken<KLightServerSession> == 0b00110001'00000000); static_assert(ClassToken<KTransferMemory> == 0b01010001'00000000); static_assert(ClassToken<KDeviceAddressSpace> == 0b10010001'00000000); static_assert(ClassToken<KSessionRequest> == 0b01100001'00000000); static_assert(ClassToken<KCodeMemory> == 0b10100001'00000000); static_assert(ClassToken<KIoPool> == 0b11000001'00000000); static_assert(ClassToken<KIoRegion> == 0b00001110'00000000); /* 0b00010110'00000000 */ /* 0b00100110'00000000 */ static_assert(ClassToken<KSystemResource> == 0b01000110'00000000); /* Ensure that the token hierarchy is correct. */ /* Base classes */ static_assert(ClassToken<KAutoObject> == (0b00000000)); static_assert(ClassToken<KSynchronizationObject> == (0b00000001 | ClassToken<KAutoObject>)); static_assert(ClassToken<KReadableEvent> == (0b00000010 | ClassToken<KSynchronizationObject>)); /* Final classes */ static_assert(ClassToken<KInterruptEvent> == ((0b00000111 << 8) | ClassToken<KReadableEvent>)); static_assert(ClassToken<KDebug> == ((0b00001011 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KThread> == ((0b00010011 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KServerPort> == ((0b00100011 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KServerSession> == ((0b01000011 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KClientPort> == ((0b10000011 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KClientSession> == ((0b00001101 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KProcess> == ((0b00010101 << 8) | ClassToken<KSynchronizationObject>)); static_assert(ClassToken<KResourceLimit> == ((0b00100101 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KLightSession> == ((0b01000101 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KPort> == ((0b10000101 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KSession> == ((0b00011001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KSharedMemory> == ((0b00101001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KEvent> == ((0b01001001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KLightClientSession> == ((0b10001001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KLightServerSession> == ((0b00110001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KTransferMemory> == ((0b01010001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KDeviceAddressSpace> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KSessionRequest> == ((0b01100001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KCodeMemory> == ((0b10100001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KIoPool> == ((0b11000001 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KIoRegion> == ((0b00001110 << 8) | ClassToken<KAutoObject>)); static_assert(ClassToken<KSystemResource> == ((0b01000110 << 8) | ClassToken<KAutoObject>)); /* Ensure that the token hierarchy reflects the class hierarchy. */ /* Base classes. */ static_assert(!std::is_final<KSynchronizationObject>::value && std::is_base_of<KAutoObject, KSynchronizationObject>::value); static_assert(!std::is_final<KReadableEvent>::value && std::is_base_of<KSynchronizationObject, KReadableEvent>::value); /* Final classes */ static_assert(std::is_final<KInterruptEvent>::value && std::is_base_of<KReadableEvent, KInterruptEvent>::value); static_assert(std::is_final<KDebug>::value && std::is_base_of<KSynchronizationObject, KDebug>::value); static_assert(std::is_final<KThread>::value && std::is_base_of<KSynchronizationObject, KThread>::value); static_assert(std::is_final<KServerPort>::value && std::is_base_of<KSynchronizationObject, KServerPort>::value); static_assert(std::is_final<KServerSession>::value && std::is_base_of<KSynchronizationObject, KServerSession>::value); static_assert(std::is_final<KClientPort>::value && std::is_base_of<KSynchronizationObject, KClientPort>::value); static_assert(std::is_final<KClientSession>::value && std::is_base_of<KAutoObject, KClientSession>::value); static_assert(std::is_final<KProcess>::value && std::is_base_of<KSynchronizationObject, KProcess>::value); static_assert(std::is_final<KResourceLimit>::value && std::is_base_of<KAutoObject, KResourceLimit>::value); static_assert(std::is_final<KLightSession>::value && std::is_base_of<KAutoObject, KLightSession>::value); static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value); static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value); static_assert(std::is_final<KSharedMemory>::value && std::is_base_of<KAutoObject, KSharedMemory>::value); static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value); static_assert(std::is_final<KLightClientSession>::value && std::is_base_of<KAutoObject, KLightClientSession>::value); static_assert(std::is_final<KLightServerSession>::value && std::is_base_of<KAutoObject, KLightServerSession>::value); static_assert(std::is_final<KTransferMemory>::value && std::is_base_of<KAutoObject, KTransferMemory>::value); static_assert(std::is_final<KDeviceAddressSpace>::value && std::is_base_of<KAutoObject, KDeviceAddressSpace>::value); static_assert(std::is_final<KSessionRequest>::value && std::is_base_of<KAutoObject, KSessionRequest>::value); static_assert(std::is_final<KCodeMemory>::value && std::is_base_of<KAutoObject, KCodeMemory>::value); static_assert(std::is_final<KIoPool>::value && std::is_base_of<KAutoObject, KIoPool>::value); static_assert(std::is_final<KIoRegion>::value && std::is_base_of<KAutoObject, KIoRegion>::value); static_assert(std::is_base_of<KAutoObject, KSystemResource>::value); } ================================================ FILE: libraries/libmesosphere/source/kern_k_client_port.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KClientPort::Initialize(KPort *parent, s32 max_sessions) { /* Set member variables. */ m_num_sessions = 0; m_peak_sessions = 0; m_parent = parent; m_max_sessions = max_sessions; } void KClientPort::OnSessionFinalized() { KScopedSchedulerLock sl; if (const auto prev = m_num_sessions--; prev == m_max_sessions) { this->NotifyAvailable(); } } void KClientPort::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); } bool KClientPort::IsLight() const { return this->GetParent()->IsLight(); } bool KClientPort::IsServerClosed() const { return this->GetParent()->IsServerClosed(); } void KClientPort::Destroy() { /* Note with our parent that we're closed. */ m_parent->OnClientClosed(); /* Close our reference to our parent. */ m_parent->Close(); } bool KClientPort::IsSignaled() const { MESOSPHERE_ASSERT_THIS(); return m_num_sessions.Load() < m_max_sessions; } Result KClientPort::CreateSession(KClientSession **out) { MESOSPHERE_ASSERT_THIS(); /* Declare the session we're going to allocate. */ KSession *session; /* Reserve a new session from the resource limit. */ KScopedResourceReservation session_reservation(GetCurrentProcessPointer(), ams::svc::LimitableResource_SessionCountMax); if (session_reservation.Succeeded()) { /* Allocate a session normally. */ session = KSession::Create(); } else { /* We couldn't reserve a session. Check that we support dynamically expanding the resource limit. */ R_UNLESS(GetCurrentProcess().GetResourceLimit() == std::addressof(Kernel::GetSystemResourceLimit()), svc::ResultLimitReached()); R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), svc::ResultLimitReached()); /* Try to allocate a session from unused slab memory. */ session = KSession::CreateFromUnusedSlabMemory(); R_UNLESS(session != nullptr, svc::ResultLimitReached()); ON_RESULT_FAILURE { session->Close(); }; /* We want to add two KSessionRequests to the heap, to prevent request exhaustion. */ for (size_t i = 0; i < 2; ++i) { KSessionRequest *request = KSessionRequest::CreateFromUnusedSlabMemory(); R_UNLESS(request != nullptr, svc::ResultLimitReached()); request->Close(); } /* We successfully allocated a session, so add the object we allocated to the resource limit. */ Kernel::GetSystemResourceLimit().Add(ams::svc::LimitableResource_SessionCountMax, 1); } /* Check that we successfully created a session. */ R_UNLESS(session != nullptr, svc::ResultOutOfResource()); /* Update the session counts. */ { ON_RESULT_FAILURE { session->Close(); }; /* Atomically increment the number of sessions. */ s32 new_sessions; { const auto max = m_max_sessions; auto cur_sessions = m_num_sessions.Load(); do { R_UNLESS(cur_sessions < max, svc::ResultOutOfSessions()); new_sessions = cur_sessions + 1; } while (!m_num_sessions.CompareExchangeWeak<std::memory_order_relaxed>(cur_sessions, new_sessions)); } /* Atomically update the peak session tracking. */ { auto peak = m_peak_sessions.Load(); do { if (peak >= new_sessions) { break; } } while (!m_peak_sessions.CompareExchangeWeak<std::memory_order_relaxed>(peak, new_sessions)); } } /* Initialize the session. */ session->Initialize(this, m_parent->GetName()); /* Commit the session reservation. */ session_reservation.Commit(); /* Register the session. */ KSession::Register(session); ON_RESULT_FAILURE { session->GetClientSession().Close(); session->GetServerSession().Close(); }; /* Enqueue the session with our parent. */ R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession()))); /* We succeeded, so set the output. */ *out = std::addressof(session->GetClientSession()); R_SUCCEED(); } Result KClientPort::CreateLightSession(KLightClientSession **out) { MESOSPHERE_ASSERT_THIS(); /* Declare the session we're going to allocate. */ KLightSession *session; /* Reserve a new session from the resource limit. */ KScopedResourceReservation session_reservation(GetCurrentProcessPointer(), ams::svc::LimitableResource_SessionCountMax); if (session_reservation.Succeeded()) { /* Allocate a session normally. */ session = KLightSession::Create(); } else { /* We couldn't reserve a session. Check that we support dynamically expanding the resource limit. */ R_UNLESS(GetCurrentProcess().GetResourceLimit() == std::addressof(Kernel::GetSystemResourceLimit()), svc::ResultLimitReached()); R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), svc::ResultLimitReached()); /* Try to allocate a session from unused slab memory. */ session = KLightSession::CreateFromUnusedSlabMemory(); R_UNLESS(session != nullptr, svc::ResultLimitReached()); /* We successfully allocated a session, so add the object we allocated to the resource limit. */ Kernel::GetSystemResourceLimit().Add(ams::svc::LimitableResource_SessionCountMax, 1); } /* Check that we successfully created a session. */ R_UNLESS(session != nullptr, svc::ResultOutOfResource()); /* Update the session counts. */ { ON_RESULT_FAILURE { session->Close(); }; /* Atomically increment the number of sessions. */ s32 new_sessions; { const auto max = m_max_sessions; auto cur_sessions = m_num_sessions.Load(); do { R_UNLESS(cur_sessions < max, svc::ResultOutOfSessions()); new_sessions = cur_sessions + 1; } while (!m_num_sessions.CompareExchangeWeak<std::memory_order_relaxed>(cur_sessions, new_sessions)); } /* Atomically update the peak session tracking. */ { auto peak = m_peak_sessions.Load(); do { if (peak >= new_sessions) { break; } } while (!m_peak_sessions.CompareExchangeWeak<std::memory_order_relaxed>(peak, new_sessions)); } } /* Initialize the session. */ session->Initialize(this, m_parent->GetName()); /* Commit the session reservation. */ session_reservation.Commit(); /* Register the session. */ KLightSession::Register(session); ON_RESULT_FAILURE { session->GetClientSession().Close(); session->GetServerSession().Close(); }; /* Enqueue the session with our parent. */ R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession()))); /* We succeeded, so set the output. */ *out = std::addressof(session->GetClientSession()); R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_client_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KClientSession::Destroy() { MESOSPHERE_ASSERT_THIS(); m_parent->OnClientClosed(); m_parent->Close(); } void KClientSession::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); } Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Create a session request. */ KSessionRequest *request = KSessionRequest::Create(); R_UNLESS(request != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { request->Close(); }; /* Initialize the request. */ request->Initialize(nullptr, address, size); /* Send the request. */ R_RETURN(m_parent->OnRequest(request)); } Result KClientSession::SendAsyncRequest(KEvent *event, uintptr_t address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Create a session request. */ KSessionRequest *request = KSessionRequest::Create(); R_UNLESS(request != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { request->Close(); }; /* Initialize the request. */ request->Initialize(event, address, size); /* Send the request. */ R_RETURN(m_parent->OnRequest(request)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_code_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KCodeMemory::Initialize(KProcessAddress addr, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Set members. */ m_owner = GetCurrentProcessPointer(); /* Get the owner page table. */ auto &page_table = m_owner->GetPageTable(); /* Construct the page group, guarding to make sure our state is valid on exit. */ auto pg_guard = util::ConstructAtGuarded(m_page_group, page_table.GetBlockInfoManager()); /* Lock the memory. */ R_TRY(page_table.LockForCodeMemory(GetPointer(m_page_group), addr, size)); /* Clear the memory. */ for (const auto &block : GetReference(m_page_group)) { /* Clear and store cache. */ void * const block_address = GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress())); std::memset(block_address, 0xFF, block.GetSize()); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(block_address, block.GetSize())); } /* Set remaining tracking members. */ m_owner->Open(); m_address = addr; m_is_initialized = true; m_is_owner_mapped = false; m_is_mapped = false; /* We succeeded. */ pg_guard.Cancel(); R_SUCCEED(); } void KCodeMemory::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Unlock. */ if (!m_is_mapped && !m_is_owner_mapped) { const size_t size = GetReference(m_page_group).GetNumPages() * PageSize; MESOSPHERE_R_ABORT_UNLESS(m_owner->GetPageTable().UnlockForCodeMemory(m_address, size, GetReference(m_page_group))); } /* Close the page group. */ GetReference(m_page_group).Close(); GetReference(m_page_group).Finalize(); /* Close our reference to our owner. */ m_owner->Close(); } Result KCodeMemory::Map(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Ensure we're not already mapped. */ R_UNLESS(!m_is_mapped, svc::ResultInvalidState()); /* Map the memory. */ R_TRY(GetCurrentProcess().GetPageTable().MapPageGroup(address, GetReference(m_page_group), KMemoryState_CodeOut, KMemoryPermission_UserReadWrite)); /* Mark ourselves as mapped. */ m_is_mapped = true; R_SUCCEED(); } Result KCodeMemory::Unmap(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Unmap the memory. */ R_TRY(GetCurrentProcess().GetPageTable().UnmapPageGroup(address, GetReference(m_page_group), KMemoryState_CodeOut)); /* Mark ourselves as unmapped. */ MESOSPHERE_ASSERT(m_is_mapped); m_is_mapped = false; R_SUCCEED(); } Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, ams::svc::MemoryPermission perm) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Ensure we're not already mapped. */ R_UNLESS(!m_is_owner_mapped, svc::ResultInvalidState()); /* Convert the memory permission. */ KMemoryPermission k_perm; switch (perm) { case ams::svc::MemoryPermission_Read: k_perm = KMemoryPermission_UserRead; break; case ams::svc::MemoryPermission_ReadExecute: k_perm = KMemoryPermission_UserReadExecute; break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } /* Map the memory. */ R_TRY(m_owner->GetPageTable().MapPageGroup(address, GetReference(m_page_group), KMemoryState_GeneratedCode, k_perm)); /* Mark ourselves as mapped. */ m_is_owner_mapped = true; R_SUCCEED(); } Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Unmap the memory. */ R_TRY(m_owner->GetPageTable().UnmapPageGroup(address, GetReference(m_page_group), KMemoryState_GeneratedCode)); /* Mark ourselves as unmapped. */ MESOSPHERE_ASSERT(m_is_owner_mapped); m_is_owner_mapped = false; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_condition_variable.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { ALWAYS_INLINE bool ReadFromUser(u32 *out, KProcessAddress address) { return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address)); } ALWAYS_INLINE bool WriteToUser(KProcessAddress address, u32 val) { return UserspaceAccess::CopyMemoryToUserSize32Bit(GetVoidPointer(address), val); } ALWAYS_INLINE bool UpdateLockAtomic(u32 *out, KProcessAddress address, u32 if_zero, u32 new_orr_mask) { return UserspaceAccess::UpdateLockAtomic(out, GetPointer<u32>(address), if_zero, new_orr_mask); } class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue { public: constexpr ThreadQueueImplForKConditionVariableWaitForAddress() : KThreadQueue() { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread as a waiter from its owner. */ waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue { private: KConditionVariable::ThreadTree *m_tree; public: constexpr ThreadQueueImplForKConditionVariableWaitConditionVariable(KConditionVariable::ThreadTree *t) : KThreadQueue(), m_tree(t) { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread as a waiter from its owner. */ if (KThread *owner = waiting_thread->GetLockOwner(); owner != nullptr) { owner->RemoveWaiter(waiting_thread); } /* If the thread is waiting on a condvar, remove it from the tree. */ if (waiting_thread->IsWaitingForConditionVariable()) { m_tree->erase(m_tree->iterator_to(*waiting_thread)); waiting_thread->ClearConditionVariable(); } /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } Result KConditionVariable::SignalToAddress(KProcessAddress addr) { KThread *owner_thread = GetCurrentThreadPointer(); /* Signal the address. */ { KScopedSchedulerLock sl; /* Remove waiter thread. */ bool has_waiters; KThread * const next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), addr); /* Determine the next tag. */ u32 next_value = 0; if (next_owner_thread != nullptr) { next_value = next_owner_thread->GetAddressKeyValue(); if (has_waiters) { next_value |= ams::svc::HandleWaitMask; } } /* Synchronize memory before proceeding. */ cpu::DataMemoryBarrierInnerShareable(); /* Write the value to userspace. */ Result result; if (AMS_LIKELY(WriteToUser(addr, next_value))) { result = ResultSuccess(); } else { result = svc::ResultInvalidCurrentMemory(); } /* If necessary, signal the next owner thread. */ if (next_owner_thread != nullptr) { next_owner_thread->EndWait(result); } R_RETURN(result); } } Result KConditionVariable::WaitForAddress(ams::svc::Handle handle, KProcessAddress addr, u32 value) { KThread *cur_thread = GetCurrentThreadPointer(); ThreadQueueImplForKConditionVariableWaitForAddress wait_queue; /* Wait for the address. */ KThread *owner_thread; { KScopedSchedulerLock sl; /* Check if the thread should terminate. */ R_UNLESS(!cur_thread->IsTerminationRequested(), svc::ResultTerminationRequested()); /* Read the tag from userspace. */ u32 test_tag; R_UNLESS(ReadFromUser(std::addressof(test_tag), addr), svc::ResultInvalidCurrentMemory()); /* If the tag isn't the handle (with wait mask), we're done. */ R_SUCCEED_IF(test_tag != (handle | ams::svc::HandleWaitMask)); /* Get the lock owner thread. */ owner_thread = GetCurrentProcess().GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(handle).ReleasePointerUnsafe(); R_UNLESS(owner_thread != nullptr, svc::ResultInvalidHandle()); /* Update the lock. */ cur_thread->SetAddressKey(addr, value); owner_thread->AddWaiter(cur_thread); /* Begin waiting. */ cur_thread->BeginWait(std::addressof(wait_queue)); } /* Close our reference to the owner thread, now that the wait is over. */ owner_thread->Close(); /* Get the wait result. */ R_RETURN(cur_thread->GetWaitResult()); } void KConditionVariable::SignalImpl(KThread *thread) { /* Check pre-conditions. */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Update the tag. */ KProcessAddress address = thread->GetAddressKey(); u32 own_tag = thread->GetAddressKeyValue(); u32 prev_tag; bool can_access; { /* NOTE: If scheduler lock is not held here, interrupt disable is required. */ /* KScopedInterruptDisable di; */ can_access = cpu::CanAccessAtomic(address); if (AMS_LIKELY(can_access)) { can_access = UpdateLockAtomic(std::addressof(prev_tag), address, own_tag, ams::svc::HandleWaitMask); } } if (AMS_LIKELY(can_access)) { if (prev_tag == ams::svc::InvalidHandle) { /* If nobody held the lock previously, we're all good. */ thread->EndWait(ResultSuccess()); } else { /* Get the previous owner. */ KThread *owner_thread = GetCurrentProcess().GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(static_cast<ams::svc::Handle>(prev_tag & ~ams::svc::HandleWaitMask)) .ReleasePointerUnsafe(); if (AMS_LIKELY(owner_thread != nullptr)) { /* Add the thread as a waiter on the owner. */ owner_thread->AddWaiter(thread); owner_thread->Close(); } else { /* The lock was tagged with a thread that doesn't exist. */ thread->EndWait(svc::ResultInvalidState()); } } } else { /* If the address wasn't accessible, note so. */ thread->EndWait(svc::ResultInvalidCurrentMemory()); } } void KConditionVariable::Signal(uintptr_t cv_key, s32 count) { /* Perform signaling. */ int num_waiters = 0; { KScopedSchedulerLock sl; auto it = m_tree.nfind_key({ cv_key, -1 }); while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) { KThread *target_thread = std::addressof(*it); it = m_tree.erase(it); target_thread->ClearConditionVariable(); this->SignalImpl(target_thread); ++num_waiters; } /* If we have no waiters, clear the has waiter flag. */ if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) { constexpr u32 HasNoWaiterFlag = 0; WriteToUser(cv_key, HasNoWaiterFlag); } } } Result KConditionVariable::Wait(KProcessAddress addr, uintptr_t key, u32 value, s64 timeout) { /* Prepare to wait. */ KThread *cur_thread = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(std::addressof(m_tree)); { KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); /* Check that the thread isn't terminating. */ if (cur_thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Update the value and process for the next owner. */ { /* Remove waiter thread. */ bool has_waiters; KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(has_waiters), GetInteger(addr)); /* Update for the next owner thread. */ u32 next_value = 0; if (next_owner_thread != nullptr) { /* Get the next tag value. */ next_value = next_owner_thread->GetAddressKeyValue(); if (has_waiters) { next_value |= ams::svc::HandleWaitMask; } /* Wake up the next owner. */ next_owner_thread->EndWait(ResultSuccess()); } /* Write to the cv key. */ { constexpr u32 HasWaiterFlag = 1; WriteToUser(key, HasWaiterFlag); cpu::DataMemoryBarrierInnerShareable(); } /* Write the value to userspace. */ if (!WriteToUser(addr, next_value)) { slp.CancelSleep(); R_THROW(svc::ResultInvalidCurrentMemory()); } } /* If timeout is zero, time out. */ R_UNLESS(timeout != 0, svc::ResultTimedOut()); /* Update condition variable tracking. */ cur_thread->SetConditionVariable(std::addressof(m_tree), addr, key, value); m_tree.insert(*cur_thread); /* Begin waiting. */ wait_queue.SetHardwareTimer(timer); cur_thread->BeginWait(std::addressof(wait_queue)); } /* Get the wait result. */ R_RETURN(cur_thread->GetWaitResult()); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_debug_base.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { ALWAYS_INLINE KDebugBase *GetDebugObject(KProcess *process) { return static_cast<KDebugBase *>(process->GetDebugObject()); } } void KDebugBase::Initialize() { /* Clear the continue flags. */ m_continue_flags = 0; m_is_force_debug_prod = GetCurrentProcess().CanForceDebugProd(); } bool KDebugBase::Is64Bit() const { MESOSPHERE_ASSERT(m_lock.IsLockedByCurrentThread()); MESOSPHERE_ASSERT(m_is_attached); KProcess * const process = this->GetProcessUnsafe(); MESOSPHERE_ASSERT(process != nullptr); return process->Is64Bit(); } Result KDebugBase::QueryMemoryInfo(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, KProcessAddress address) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Check that the process isn't terminated. */ R_UNLESS(!process->IsTerminated(), svc::ResultProcessTerminated()); /* Query the mapping's info. */ KMemoryInfo info; R_TRY(process->GetPageTable().QueryInfo(std::addressof(info), out_page_info, address)); /* Write output. */ *out_memory_info = info.GetSvcMemoryInfo(); R_SUCCEED(); } Result KDebugBase::ReadMemory(KProcessAddress buffer, KProcessAddress address, size_t size) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Check that the process isn't terminated. */ R_UNLESS(!process->IsTerminated(), svc::ResultProcessTerminated()); /* Get the page tables. */ KProcessPageTable &debugger_pt = GetCurrentProcess().GetPageTable(); KProcessPageTable &target_pt = process->GetPageTable(); /* Verify that the regions are in range. */ R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory()); /* Iterate over the target process's memory blocks. */ KProcessAddress cur_address = address; size_t remaining = size; while (remaining > 0) { /* Get the current memory info. */ KMemoryInfo info; ams::svc::PageInfo pi; R_TRY(target_pt.QueryInfo(std::addressof(info), std::addressof(pi), cur_address)); /* Check that the memory is accessible. */ R_UNLESS(info.GetState() != static_cast<KMemoryState>(ams::svc::MemoryState_Inaccessible), svc::ResultInvalidAddress()); /* Get the current size. */ const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address)); /* Read the memory. */ if (info.GetSvcState() != ams::svc::MemoryState_Io) { /* The memory is normal memory. */ R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size, this->IsForceDebugProd())); } else { /* Only allow IO memory to be read if not force debug prod. */ R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidCurrentMemory()); /* The memory is IO memory. */ R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size, info.GetState())); } /* Advance. */ buffer += cur_size; cur_address += cur_size; remaining -= cur_size; } R_SUCCEED(); } Result KDebugBase::WriteMemory(KProcessAddress buffer, KProcessAddress address, size_t size) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Check that the process isn't terminated. */ R_UNLESS(!process->IsTerminated(), svc::ResultProcessTerminated()); /* Get the page tables. */ KProcessPageTable &debugger_pt = GetCurrentProcess().GetPageTable(); KProcessPageTable &target_pt = process->GetPageTable(); /* Verify that the regions are in range. */ R_UNLESS(target_pt.Contains(address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(debugger_pt.Contains(buffer, size), svc::ResultInvalidCurrentMemory()); /* Iterate over the target process's memory blocks. */ KProcessAddress cur_address = address; size_t remaining = size; while (remaining > 0) { /* Get the current memory info. */ KMemoryInfo info; ams::svc::PageInfo pi; R_TRY(target_pt.QueryInfo(std::addressof(info), std::addressof(pi), cur_address)); /* Check that the memory is accessible. */ R_UNLESS(info.GetState() != static_cast<KMemoryState>(ams::svc::MemoryState_Inaccessible), svc::ResultInvalidAddress()); /* Get the current size. */ const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address)); /* Read the memory. */ if (info.GetSvcState() != ams::svc::MemoryState_Io) { /* The memory is normal memory. */ R_TRY(target_pt.WriteDebugMemory(cur_address, GetVoidPointer(buffer), cur_size)); } else { /* The memory is IO memory. */ R_TRY(target_pt.WriteDebugIoMemory(cur_address, GetVoidPointer(buffer), cur_size, info.GetState())); } /* Advance. */ buffer += cur_size; cur_address += cur_size; remaining -= cur_size; } R_SUCCEED(); } Result KDebugBase::GetRunningThreadInfo(ams::svc::LastThreadContext *out_context, u64 *out_thread_id) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Get the thread info. */ { KScopedSchedulerLock sl; /* Get the running thread. */ const s32 core_id = GetCurrentCoreId(); KThread *thread = process->GetRunningThread(core_id); /* We want to check that the thread is actually running. */ /* If it is, then the scheduler will have just switched from the thread to the current thread. */ /* This implies exactly one switch will have taken place, and the current thread will be on the current core. */ const auto &scheduler = Kernel::GetScheduler(core_id); if (!(thread != nullptr && thread->GetActiveCore() == core_id && process->GetRunningThreadSwitchCount(core_id) + 1 == scheduler.GetSwitchCount())) { /* The most recent thread switch was from a thread other than the expected one to the current one. */ /* We want to use the appropriate result to inform userland about what thread we switched from. */ if (scheduler.GetIdleCount() + 1 == scheduler.GetSwitchCount()) { /* We switched from the idle thread. */ R_THROW(svc::ResultNoThread()); } else { /* We switched from some other unknown thread. */ R_THROW(svc::ResultUnknownThread()); } } /* Get the thread's exception context. */ GetExceptionContext(thread)->GetSvcThreadContext(out_context); /* Get the thread's id. */ *out_thread_id = thread->GetId(); } R_SUCCEED(); } Result KDebugBase::Attach(KProcess *target) { /* Check that the process isn't null. */ MESOSPHERE_ASSERT(target != nullptr); /* Clear ourselves as unattached. */ m_is_attached = false; /* Attach to the process. */ { /* Lock both ourselves, the target process, and the scheduler. */ KScopedLightLock state_lk(target->GetStateLock()); KScopedLightLock list_lk(target->GetListLock()); KScopedLightLock this_lk(m_lock); KScopedSchedulerLock sl; /* Check that the process isn't already being debugged. */ R_UNLESS(!target->IsAttachedToDebugger(), svc::ResultBusy()); { /* Ensure the process is in a state that allows for debugging. */ const KProcess::State state = target->GetState(); switch (state) { case KProcess::State_Created: case KProcess::State_Running: /* Created and running processes can only be debugged if the debugger is not ForceDebugProd. */ R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidState()); break; case KProcess::State_Crashed: break; case KProcess::State_CreatedAttached: case KProcess::State_RunningAttached: case KProcess::State_DebugBreak: R_THROW(svc::ResultBusy()); case KProcess::State_Terminating: case KProcess::State_Terminated: R_THROW(svc::ResultProcessTerminated()); MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } /* Attach to the target. */ m_process_holder.Attach(target); m_is_attached = true; /* Set ourselves as the process's attached object. */ m_old_process_state = target->SetDebugObject(this); /* Send an event for our attaching to the process. */ this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess, nullptr, 0); /* Send events for attaching to each thread in the process. */ { auto end = target->GetThreadList().end(); for (auto it = target->GetThreadList().begin(); it != end; ++it) { /* Request that we suspend the thread. */ it->RequestSuspend(KThread::SuspendType_Debug); /* If the thread is in a state for us to do so, generate the event. */ if (const auto thread_state = it->GetState(); thread_state == KThread::ThreadState_Runnable || thread_state == KThread::ThreadState_Waiting) { /* Mark the thread as attached to. */ it->SetDebugAttached(); /* Send the event. */ const uintptr_t params[2] = { it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()) }; this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params)); } } } /* Send the process's jit debug info, if relevant. */ if (KEventInfo *jit_info = target->GetJitDebugInfo(); jit_info != nullptr) { this->EnqueueDebugEventInfo(jit_info); } /* Send an exception event to represent our attaching. */ const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerAttached) }; this->PushDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)); /* Signal. */ this->NotifyAvailable(); } } R_SUCCEED(); } Result KDebugBase::BreakProcess() { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const target = this->GetProcessUnsafe(); /* Lock both ourselves, the target process, and the scheduler. */ KScopedLightLock state_lk(target->GetStateLock()); KScopedLightLock list_lk(target->GetListLock()); KScopedLightLock this_lk(m_lock); KScopedSchedulerLock sl; /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Check that the process isn't terminated. */ R_UNLESS(!target->IsTerminated(), svc::ResultProcessTerminated()); /* Get the currently active threads. */ constexpr u64 ThreadIdNoThread = -1ll; constexpr u64 ThreadIdUnknownThread = -2ll; uintptr_t debug_info_params[1 + cpu::NumCores] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerBreak), }; for (size_t i = 0; i < cpu::NumCores; ++i) { /* Get the currently running thread. */ KThread *thread = target->GetRunningThread(i); /* Check that the thread's idle count is correct. */ if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) { if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) { debug_info_params[1 + i] = thread->GetId(); } else { /* We found an unknown thread. */ debug_info_params[1 + i] = ThreadIdUnknownThread; } } else { /* We didn't find a thread. */ debug_info_params[1 + i] = ThreadIdNoThread; } } /* Suspend all the threads in the process. */ { auto end = target->GetThreadList().end(); for (auto it = target->GetThreadList().begin(); it != end; ++it) { /* Request that we suspend the thread. */ it->RequestSuspend(KThread::SuspendType_Debug); } } /* Send an exception event to represent our breaking the process. */ this->PushDebugEvent(ams::svc::DebugEvent_Exception, debug_info_params, util::size(debug_info_params)); /* Signal. */ this->NotifyAvailable(); /* Set the process as breaked. */ target->SetDebugBreak(); R_SUCCEED(); } Result KDebugBase::TerminateProcess() { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), ResultSuccess()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), ResultSuccess()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const target = this->GetProcessUnsafe(); /* Terminate the process. */ /* NOTE: This result is seemingly-intentionally not checked by Nintendo. */ static_cast<void>(target->Terminate()); R_SUCCEED(); } Result KDebugBase::GetThreadContext(ams::svc::ThreadContext *out, u64 thread_id, u32 context_flags) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Get the thread from its id. */ KThread *thread = KThread::GetThreadFromId(thread_id); R_UNLESS(thread != nullptr, svc::ResultInvalidId()); ON_SCOPE_EXIT { thread->Close(); }; /* Verify that the thread is owned by our process. */ R_UNLESS(process == thread->GetOwnerProcess(), svc::ResultInvalidId()); /* Verify that the thread isn't terminated. */ R_UNLESS(thread->GetState() != KThread::ThreadState_Terminated, svc::ResultTerminationRequested()); /* Check that the thread is not the current one. */ /* NOTE: Nintendo does not check this, and thus the following loop will deadlock. */ R_UNLESS(thread != GetCurrentThreadPointer(), svc::ResultInvalidId()); /* Try to get the thread context until the thread isn't current on any core. */ while (true) { KScopedSchedulerLock sl; /* The thread needs to be requested for debug suspension. */ R_UNLESS(thread->IsSuspendRequested(KThread::SuspendType_Debug), svc::ResultInvalidState()); /* If the thread's raw state isn't runnable, check if it's current on some core. */ if (thread->GetRawState() != KThread::ThreadState_Runnable) { bool current = false; for (auto i = 0; i < static_cast<s32>(cpu::NumCores); ++i) { if (thread == Kernel::GetScheduler(i).GetSchedulerCurrentThread()) { current = true; break; } } /* If the thread is current, retry until it isn't. */ if (current) { continue; } } /* Get the thread context. */ static_assert(std::derived_from<KDebug, KDebugBase>); R_RETURN(static_cast<KDebug *>(this)->GetThreadContextImpl(out, thread, context_flags)); } } Result KDebugBase::SetThreadContext(const ams::svc::ThreadContext &ctx, u64 thread_id, u32 context_flags) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Get the thread from its id. */ KThread *thread = KThread::GetThreadFromId(thread_id); R_UNLESS(thread != nullptr, svc::ResultInvalidId()); ON_SCOPE_EXIT { thread->Close(); }; /* Verify that the thread is owned by our process. */ R_UNLESS(process == thread->GetOwnerProcess(), svc::ResultInvalidId()); /* Verify that the thread isn't terminated. */ R_UNLESS(thread->GetState() != KThread::ThreadState_Terminated, svc::ResultTerminationRequested()); /* Check that the thread is not the current one. */ /* NOTE: Nintendo does not check this, and thus the following loop will deadlock. */ R_UNLESS(thread != GetCurrentThreadPointer(), svc::ResultInvalidId()); /* Try to get the thread context until the thread isn't current on any core. */ while (true) { KScopedSchedulerLock sl; /* The thread needs to be requested for debug suspension. */ R_UNLESS(thread->IsSuspendRequested(KThread::SuspendType_Debug), svc::ResultInvalidState()); /* If the thread's raw state isn't runnable, check if it's current on some core. */ if (thread->GetRawState() != KThread::ThreadState_Runnable) { bool current = false; for (auto i = 0; i < static_cast<s32>(cpu::NumCores); ++i) { if (thread == Kernel::GetScheduler(i).GetSchedulerCurrentThread()) { current = true; break; } } /* If the thread is current, retry until it isn't. */ if (current) { continue; } } /* Update thread single-step state. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) { if ((context_flags & ams::svc::ThreadContextFlag_SetSingleStep) != 0) { /* Set single step. */ thread->SetHardwareSingleStep(); /* If no other thread flags are present, we're done. */ R_SUCCEED_IF((context_flags & ~ams::svc::ThreadContextFlag_SetSingleStep) == 0); } else if ((context_flags & ams::svc::ThreadContextFlag_ClearSingleStep) != 0) { /* Clear single step. */ thread->ClearHardwareSingleStep(); /* If no other thread flags are present, we're done. */ R_SUCCEED_IF((context_flags & ~ams::svc::ThreadContextFlag_ClearSingleStep) == 0); } } #endif /* Verify that the thread's svc state is valid. */ if (thread->IsCallingSvc()) { const u8 svc_id = thread->GetSvcId(); const bool is_valid_svc = svc_id == svc::SvcId_Break || svc_id == svc::SvcId_ReturnFromException; R_UNLESS(is_valid_svc, svc::ResultInvalidState()); } /* Set the thread context. */ static_assert(std::derived_from<KDebug, KDebugBase>); R_RETURN(static_cast<KDebug *>(this)->SetThreadContextImpl(ctx, thread, context_flags)); } } Result KDebugBase::ContinueDebug(const u32 flags, const u64 *thread_ids, size_t num_thread_ids) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const target = this->GetProcessUnsafe(); /* Lock both ourselves, the target process, and the scheduler. */ KScopedLightLock state_lk(target->GetStateLock()); KScopedLightLock list_lk(target->GetListLock()); KScopedLightLock this_lk(m_lock); KScopedSchedulerLock sl; /* Check that we're still attached now that we're locked. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Check that the process isn't terminated. */ R_UNLESS(!target->IsTerminated(), svc::ResultProcessTerminated()); /* Check that we have no pending events. */ R_UNLESS(m_event_info_list.empty(), svc::ResultBusy()); /* Clear the target's JIT debug info. */ target->ClearJitDebugInfo(); /* Set our continue flags. */ m_continue_flags = flags; /* Iterate over threads, continuing them as we should. */ bool has_debug_break_thread = false; { /* Parse our flags. */ const bool exception_handled = (m_continue_flags & ams::svc::ContinueFlag_ExceptionHandled) != 0; const bool continue_all = (m_continue_flags & ams::svc::ContinueFlag_ContinueAll) != 0; const bool continue_others = (m_continue_flags & ams::svc::ContinueFlag_ContinueOthers) != 0; /* Update each thread. */ auto end = target->GetThreadList().end(); for (auto it = target->GetThreadList().begin(); it != end; ++it) { /* Determine if we should continue the thread. */ bool should_continue; { if (continue_all) { /* Continue all threads. */ should_continue = true; } else if (continue_others) { /* Continue the thread if it doesn't match one of our target ids. */ const u64 thread_id = it->GetId(); should_continue = true; for (size_t i = 0; i < num_thread_ids; ++i) { if (thread_ids[i] == thread_id) { should_continue = false; break; } } } else { /* Continue the thread if it matches one of our target ids. */ const u64 thread_id = it->GetId(); should_continue = false; for (size_t i = 0; i < num_thread_ids; ++i) { if (thread_ids[i] == thread_id) { should_continue = true; break; } } } } /* Continue the thread if we should. */ if (should_continue) { if (exception_handled) { it->SetDebugExceptionResult(svc::ResultStopProcessingException()); } it->Resume(KThread::SuspendType_Debug); } /* If the thread has debug suspend requested, note so. */ if (it->IsSuspendRequested(KThread::SuspendType_Debug)) { has_debug_break_thread = true; } } } /* Set the process's state. */ if (has_debug_break_thread) { target->SetDebugBreak(); } else { target->SetAttached(); } R_SUCCEED(); } KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, u64 cur_thread_id, const uintptr_t *params, size_t num_params) { /* Allocate a new event. */ KEventInfo *info = KEventInfo::Allocate(); /* Populate the event info. */ if (info != nullptr) { /* Set common fields. */ info->event = event; info->thread_id = 0; info->flags = ams::svc::DebugEventFlag_Stopped; /* Set event specific fields. */ switch (event) { case ams::svc::DebugEvent_CreateProcess: { /* Check parameters. */ MESOSPHERE_ASSERT(params == nullptr); MESOSPHERE_ASSERT(num_params == 0); } break; case ams::svc::DebugEvent_CreateThread: { /* Check parameters. */ MESOSPHERE_ASSERT(params != nullptr); MESOSPHERE_ASSERT(num_params == 2); /* Set the thread id. */ info->thread_id = params[0]; /* Set the thread creation info. */ info->info.create_thread.thread_id = params[0]; info->info.create_thread.tls_address = params[1]; } break; case ams::svc::DebugEvent_ExitProcess: { /* Check parameters. */ MESOSPHERE_ASSERT(params != nullptr); MESOSPHERE_ASSERT(num_params == 1); /* Set the exit reason. */ info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(params[0]); /* Clear the thread id and flags. */ info->thread_id = 0; info->flags = 0; } break; case ams::svc::DebugEvent_ExitThread: { /* Check parameters. */ MESOSPHERE_ASSERT(params != nullptr); MESOSPHERE_ASSERT(num_params == 2); /* Set the thread id. */ info->thread_id = params[0]; /* Set the exit reason. */ info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(params[1]); } break; case ams::svc::DebugEvent_Exception: { /* Check parameters. */ MESOSPHERE_ASSERT(params != nullptr); MESOSPHERE_ASSERT(num_params >= 1); /* Set the thread id. */ info->thread_id = cur_thread_id; /* Set the exception type, and clear the count. */ info->info.exception.exception_type = static_cast<ams::svc::DebugException>(params[0]); info->info.exception.exception_data_count = 0; switch (static_cast<ams::svc::DebugException>(params[0])) { case ams::svc::DebugException_UndefinedInstruction: case ams::svc::DebugException_BreakPoint: case ams::svc::DebugException_UndefinedSystemCall: { MESOSPHERE_ASSERT(num_params >= 3); info->info.exception.exception_address = params[1]; info->info.exception.exception_data_count = 1; info->info.exception.exception_data[0] = params[2]; } break; case ams::svc::DebugException_DebuggerAttached: { info->thread_id = 0; info->info.exception.exception_address = 0; } break; case ams::svc::DebugException_UserBreak: { MESOSPHERE_ASSERT(num_params >= 2); info->info.exception.exception_address = params[1]; info->info.exception.exception_data_count = 0; for (size_t i = 2; i < num_params; ++i) { info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i]; } } break; case ams::svc::DebugException_DebuggerBreak: { info->thread_id = 0; info->info.exception.exception_address = 0; info->info.exception.exception_data_count = 0; for (size_t i = 1; i < num_params; ++i) { info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i]; } } break; case ams::svc::DebugException_MemorySystemError: { info->info.exception.exception_address = 0; } break; case ams::svc::DebugException_InstructionAbort: case ams::svc::DebugException_DataAbort: case ams::svc::DebugException_AlignmentFault: default: { MESOSPHERE_ASSERT(num_params >= 2); info->info.exception.exception_address = params[1]; } break; } } break; } } return info; } void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) { /* Create and enqueue and event. */ if (KEventInfo *new_info = CreateDebugEvent(event, GetCurrentThread().GetId(), params, num_params); new_info != nullptr) { this->EnqueueDebugEventInfo(new_info); } } void KDebugBase::EnqueueDebugEventInfo(KEventInfo *info) { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Push the event to the back of the list. */ m_event_info_list.push_back(*info); } template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>) Result KDebugBase::GetDebugEventInfoImpl(T *out) { /* Check that we're attached. */ R_UNLESS(this->IsAttached(), svc::ResultProcessTerminated()); /* Open a reference to our process. */ R_UNLESS(this->OpenProcess(), svc::ResultProcessTerminated()); /* Close our reference to our process when we're done. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Pop an event info from our queue. */ KEventInfo *info = nullptr; { KScopedSchedulerLock sl; /* Check that we have an event to dequeue. */ R_UNLESS(!m_event_info_list.empty(), svc::ResultNoEvent()); /* Pop the event from the front of the queue. */ info = std::addressof(m_event_info_list.front()); m_event_info_list.pop_front(); } MESOSPHERE_ASSERT(info != nullptr); /* Free the event info once we're done with it. */ ON_SCOPE_EXIT { KEventInfo::Free(info); }; /* Set common fields. */ out->type = info->event; out->thread_id = info->thread_id; out->flags = info->flags; /* Set event specific fields. */ switch (info->event) { case ams::svc::DebugEvent_CreateProcess: { out->info.create_process.program_id = process->GetProgramId(); out->info.create_process.process_id = process->GetId(); out->info.create_process.flags = process->GetCreateProcessFlags(); out->info.create_process.user_exception_context_address = GetInteger(process->GetProcessLocalRegionAddress()); std::memcpy(out->info.create_process.name, process->GetName(), sizeof(out->info.create_process.name)); } break; case ams::svc::DebugEvent_CreateThread: { out->info.create_thread.thread_id = info->info.create_thread.thread_id; out->info.create_thread.tls_address = info->info.create_thread.tls_address; } break; case ams::svc::DebugEvent_ExitProcess: { out->info.exit_process.reason = info->info.exit_process.reason; } break; case ams::svc::DebugEvent_ExitThread: { out->info.exit_thread.reason = info->info.exit_thread.reason; } break; case ams::svc::DebugEvent_Exception: { out->info.exception.type = info->info.exception.exception_type; out->info.exception.address = info->info.exception.exception_address; switch (info->info.exception.exception_type) { case ams::svc::DebugException_UndefinedInstruction: { MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 1); /* Only save the instruction if the caller is not force debug prod. */ if (this->IsForceDebugProd()) { out->info.exception.specific.undefined_instruction.insn = 0; } else { out->info.exception.specific.undefined_instruction.insn = info->info.exception.exception_data[0]; } } break; case ams::svc::DebugException_BreakPoint: { MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 1); out->info.exception.specific.break_point.type = static_cast<ams::svc::BreakPointType>(info->info.exception.exception_data[0]); out->info.exception.specific.break_point.address = 0; } break; case ams::svc::DebugException_UserBreak: { MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 3); out->info.exception.specific.user_break.break_reason = static_cast<ams::svc::BreakReason>(info->info.exception.exception_data[0]); out->info.exception.specific.user_break.address = info->info.exception.exception_data[1]; out->info.exception.specific.user_break.size = info->info.exception.exception_data[2]; } break; case ams::svc::DebugException_DebuggerBreak: { /* TODO: How does this work with non-4 cpu count? */ static_assert(cpu::NumCores <= 4); MESOSPHERE_ASSERT(info->info.exception.exception_data_count == cpu::NumCores); out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0]; out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1]; out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2]; out->info.exception.specific.debugger_break.active_thread_ids[3] = info->info.exception.exception_data[3]; } break; case ams::svc::DebugException_UndefinedSystemCall: { MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 1); out->info.exception.specific.undefined_system_call.id = info->info.exception.exception_data[0]; } break; default: { /* ... */ } break; } } break; } R_SUCCEED(); } Result KDebugBase::GetDebugEventInfo(ams::svc::lp64::DebugEventInfo *out) { R_RETURN(this->GetDebugEventInfoImpl(out)); } Result KDebugBase::GetDebugEventInfo(ams::svc::ilp32::DebugEventInfo *out) { R_RETURN(this->GetDebugEventInfoImpl(out)); } void KDebugBase::Finalize() { /* Perform base finalization. */ KSynchronizationObject::Finalize(); /* Perform post-synchronization finalization. */ this->OnFinalizeSynchronizationObject(); } void KDebugBase::OnFinalizeSynchronizationObject() { /* Detach from our process, if we have one. */ if (this->IsAttached() && this->OpenProcess()) { /* Close the process when we're done with it. */ ON_SCOPE_EXIT { this->CloseProcess(); }; /* Get the process pointer. */ KProcess * const process = this->GetProcessUnsafe(); /* Lock both ourselves and the target process. */ KScopedLightLock state_lk(process->GetStateLock()); KScopedLightLock list_lk(process->GetListLock()); KScopedLightLock this_lk(m_lock); /* Check that we're still attached. */ if (m_is_attached) { KScopedSchedulerLock sl; /* Detach ourselves from the process. */ process->ClearDebugObject(m_old_process_state); /* Release all threads. */ const bool resume = (process->GetState() != KProcess::State_Crashed); { auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Clear the thread's single-step state. */ it->ClearHardwareSingleStep(); #endif if (resume) { /* If the process isn't crashed, resume threads. */ it->Resume(KThread::SuspendType_Debug); } else { /* Otherwise, suspend them. */ it->RequestSuspend(KThread::SuspendType_Debug); } } } /* Note we're now unattached. */ m_is_attached = false; /* Close the initial reference opened to our process. */ this->CloseProcess(); } } /* Free any pending events. */ { KScopedSchedulerLock sl; while (!m_event_info_list.empty()) { KEventInfo *info = std::addressof(m_event_info_list.front()); m_event_info_list.pop_front(); KEventInfo::Free(info); } } } bool KDebugBase::IsSignaled() const { bool empty; { KScopedSchedulerLock sl; empty = m_event_info_list.empty(); } return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated(); } Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) { /* Get the current process. */ KProcess *process = GetCurrentProcessPointer(); /* If the event is CreateThread and we've already attached, there's nothing to do. */ if (event == ams::svc::DebugEvent_CreateThread) { R_SUCCEED_IF(GetCurrentThread().IsAttachedToDebugger()); } while (true) { /* Lock the process and the scheduler. */ KScopedLightLock state_lk(process->GetStateLock()); KScopedLightLock list_lk(process->GetListLock()); KScopedSchedulerLock sl; /* If the current thread is terminating, we can't process an event. */ R_SUCCEED_IF(GetCurrentThread().IsTerminationRequested()); /* Get the debug object. If we have none, there's nothing to process. */ KDebugBase *debug = GetDebugObject(process); R_SUCCEED_IF(debug == nullptr); /* If the event is an exception and we don't have exception events enabled, we can't handle the event. */ if (event == ams::svc::DebugEvent_Exception && (debug->m_continue_flags & ams::svc::ContinueFlag_EnableExceptionEvent) == 0) { GetCurrentThread().SetDebugExceptionResult(ResultSuccess()); R_THROW(svc::ResultNotHandled()); } /* If the current thread is suspended, retry. */ if (GetCurrentThread().IsSuspended()) { continue; } /* Suspend all the process's threads. */ { auto end = process->GetThreadList().end(); for (auto it = process->GetThreadList().begin(); it != end; ++it) { it->RequestSuspend(KThread::SuspendType_Debug); } } /* Push the event. */ debug->PushDebugEvent(event, params, num_params); debug->NotifyAvailable(); /* Set the process as breaked. */ process->SetDebugBreak(); /* If the event is an exception, set the result and clear single step. */ if (event == ams::svc::DebugEvent_Exception) { GetCurrentThread().SetDebugExceptionResult(ResultSuccess()); } /* Exit our retry loop. */ break; } /* If the event is an exception, get the exception result. */ if (event == ams::svc::DebugEvent_Exception) { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* If the thread is terminating, we can't process the exception. */ R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultStopProcessingException()); /* Get the debug object. */ if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) { /* If we have one, check the debug exception. */ R_RETURN(GetCurrentThread().GetDebugExceptionResult()); } else { /* We don't have a debug object, so stop processing the exception. */ R_THROW(svc::ResultStopProcessingException()); } } R_SUCCEED(); } Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) { if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) { R_RETURN(ProcessDebugEvent(event, params, num_params)); } R_SUCCEED(); } void KDebugBase::OnExitProcess(KProcess *process) { MESOSPHERE_ASSERT(process != nullptr); /* Check if we're attached to a debugger. */ if (process->IsAttachedToDebugger()) { /* If we are, lock the scheduler. */ KScopedSchedulerLock sl; /* Push the event. */ if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) { const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_ExitProcess) }; debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params)); debug->NotifyAvailable(); } } } void KDebugBase::OnTerminateProcess(KProcess *process) { MESOSPHERE_ASSERT(process != nullptr); /* Check if we're attached to a debugger. */ if (process->IsAttachedToDebugger()) { /* If we are, lock the scheduler. */ KScopedSchedulerLock sl; /* Push the event. */ if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) { const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_TerminateProcess) }; debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params)); debug->NotifyAvailable(); } } } void KDebugBase::OnExitThread(KThread *thread) { MESOSPHERE_ASSERT(thread != nullptr); /* Check if we're attached to a debugger. */ if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) { /* If we are, submit the event. */ const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) }; static_cast<void>(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params))); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_device_address_space.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { /* Static initializer. */ void KDeviceAddressSpace::Initialize() { /* This just forwards to the device page table manager. */ KDevicePageTable::Initialize(); } /* Member functions. */ Result KDeviceAddressSpace::Initialize(u64 address, u64 size) { MESOSPHERE_ASSERT_THIS(); /* Initialize the device page table. */ R_TRY(m_table.Initialize(address, size)); /* Set member variables. */ m_space_address = address; m_space_size = size; m_is_initialized = true; R_SUCCEED(); } void KDeviceAddressSpace::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Finalize the table. */ m_table.Finalize(); } Result KDeviceAddressSpace::Attach(ams::svc::DeviceName device_name) { /* Lock the address space. */ KScopedLightLock lk(m_lock); /* Attach. */ R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size)); } Result KDeviceAddressSpace::Detach(ams::svc::DeviceName device_name) { /* Lock the address space. */ KScopedLightLock lk(m_lock); /* Detach. */ R_RETURN(m_table.Detach(device_name)); } Result KDeviceAddressSpace::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned) { /* Check that the address falls within the space. */ R_UNLESS((m_space_address <= device_address && device_address + size - 1 <= m_space_address + m_space_size - 1), svc::ResultInvalidCurrentMemory()); /* Decode the option. */ const util::BitPack32 option_pack = { option }; const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>(); const auto flags = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Flags>(); const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>(); /* Validate the option. */ /* TODO: It is likely that this check for flags == none is only on NX board. */ R_UNLESS(flags == ams::svc::MapDeviceAddressSpaceFlag_None, svc::ResultInvalidEnumValue()); R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); /* Lock the address space. */ KScopedLightLock lk(m_lock); /* Lock the page table to prevent concurrent device mapping operations. */ KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); /* Lock the pages. */ bool is_io{}; R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned, true)); /* Ensure that if we fail, we don't keep unmapped pages locked. */ ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(page_table->UnlockForDeviceAddressSpace(process_address, size)); }; /* Check that the io status is allowable. */ if (is_io) { R_UNLESS((flags & ams::svc::MapDeviceAddressSpaceFlag_NotIoRegister) == 0, svc::ResultInvalidCombination()); } /* Map the pages. */ { /* Perform the mapping. */ R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, is_aligned, is_io)); /* Ensure that we unmap the pages if we fail to update the protections. */ /* NOTE: Nintendo does not check the result of this unmap call. */ ON_RESULT_FAILURE { m_table.Unmap(device_address, size); }; /* Update the protections in accordance with how much we mapped. */ R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size)); } /* We succeeded. */ R_SUCCEED(); } Result KDeviceAddressSpace::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address) { /* Check that the address falls within the space. */ R_UNLESS((m_space_address <= device_address && device_address + size - 1 <= m_space_address + m_space_size - 1), svc::ResultInvalidCurrentMemory()); /* Lock the address space. */ KScopedLightLock lk(m_lock); /* Lock the page table to prevent concurrent device mapping operations. */ KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); /* Lock the pages. */ R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true)); /* Unmap the pages. */ { /* If we fail to unmap, we want to do a partial unlock. */ ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size)); }; /* Perform the unmap. */ R_TRY(m_table.Unmap(page_table, process_address, size, device_address)); } /* Unlock the pages. */ MESOSPHERE_R_ABORT_UNLESS(page_table->UnlockForDeviceAddressSpace(process_address, size)); R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_dpc_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class KDpcTask { private: static constinit inline KLightLock s_req_lock; static constinit inline KLightLock s_lock; static constinit inline KLightConditionVariable s_cond_var{util::ConstantInitialize}; static constinit inline u64 s_core_mask; static constinit inline KDpcTask *s_task; private: static bool HasRequest(s32 core_id) { return (s_core_mask & (1ull << core_id)) != 0; } static void SetRequest(s32 core_id) { s_core_mask |= (1ull << core_id); } static void ClearRequest(s32 core_id) { s_core_mask &= ~(1ull << core_id); } public: virtual void DoTask() { /* ... */ } static void Request(KDpcTask *task) { KScopedLightLock rlk(s_req_lock); /* Acquire the requested task. */ MESOSPHERE_ABORT_UNLESS(s_task == nullptr); s_task = task; { KScopedLightLock lk(s_lock); MESOSPHERE_ABORT_UNLESS(s_core_mask == 0); for (auto core = 0; core < static_cast<s32>(cpu::NumCores); ++core) { SetRequest(core); } s_cond_var.Broadcast(); while (s_core_mask != 0) { s_cond_var.Wait(std::addressof(s_lock), -1ll); } } s_task = nullptr; } static void WaitForRequest() { /* Wait for a request to come in. */ const auto core_id = GetCurrentCoreId(); KScopedLightLock lk(s_lock); while (!HasRequest(core_id)) { s_cond_var.Wait(std::addressof(s_lock), -1ll); } } static bool TimedWaitForRequest(s64 timeout) { /* Wait for a request to come in. */ const auto core_id = GetCurrentCoreId(); KScopedLightLock lk(s_lock); while (!HasRequest(core_id)) { s_cond_var.Wait(std::addressof(s_lock), timeout); if (KHardwareTimer::GetTick() >= timeout) { return false; } } return true; } static void HandleRequest() { /* Perform the request. */ s_task->DoTask(); /* Clear the request. */ const auto core_id = GetCurrentCoreId(); KScopedLightLock lk(s_lock); ClearRequest(core_id); if (s_core_mask == 0) { s_cond_var.Broadcast(); } } }; /* Convenience definitions. */ constexpr s32 DpcManagerThreadPriority = 3; constexpr s64 DpcManagerTimeout = ams::svc::Tick(TimeSpan::FromMilliSeconds(10)); /* Globals. */ s64 g_preemption_priorities[cpu::NumCores]; /* Manager thread functions. */ void DpcManagerNormalThreadFunction(uintptr_t arg) { /* Input argument goes unused. */ MESOSPHERE_UNUSED(arg); /* Forever wait and service requests. */ while (true) { KDpcTask::WaitForRequest(); KDpcTask::HandleRequest(); } } void DpcManagerPreemptionThreadFunction(uintptr_t arg) { /* Input argument goes unused. */ MESOSPHERE_UNUSED(arg); /* Forever wait and service requests, rotating the scheduled queue every 10 ms. */ s64 timeout = KHardwareTimer::GetTick() + DpcManagerTimeout; while (true) { if (KDpcTask::TimedWaitForRequest(timeout)) { KDpcTask::HandleRequest(); } else { /* Rotate the scheduler queue for each core. */ KScopedSchedulerLock lk; for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) { if (const s32 priority = g_preemption_priorities[core_id]; priority > DpcManagerThreadPriority) { KScheduler::RotateScheduledQueue(static_cast<s32>(core_id), priority); } } /* Update our next timeout. */ timeout = KHardwareTimer::GetTick() + DpcManagerTimeout; } } } } void KDpcManager::Initialize(s32 core_id, s32 priority) { /* Reserve a thread from the system limit. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1)); /* Create a new thread. */ KThread *new_thread = KThread::Create(); MESOSPHERE_ABORT_UNLESS(new_thread != nullptr); /* Launch the new thread. */ g_preemption_priorities[core_id] = priority; if (core_id == cpu::NumCores - 1) { MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, DpcManagerPreemptionThreadFunction, 0, DpcManagerThreadPriority, core_id)); } else { MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(new_thread, DpcManagerNormalThreadFunction, 0, DpcManagerThreadPriority, core_id)); } /* Register the new thread. */ KThread::Register(new_thread); /* Run the thread. */ MESOSPHERE_R_ABORT_UNLESS(new_thread->Run()); } void KDpcManager::HandleDpc() { MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); MESOSPHERE_ASSERT(!KScheduler::IsSchedulerLockedByCurrentThread()); /* Get reference to the current thread. */ KThread &cur_thread = GetCurrentThread(); /* Enable interrupts, temporarily. */ KScopedInterruptEnable ei; /* If the thread is scheduled for termination, exit the thread. */ if (cur_thread.IsTerminationRequested()) { cur_thread.Exit(); __builtin_unreachable(); } /* We may also need to destroy any closed objects. */ cur_thread.DestroyClosedObjects(); } void KDpcManager::Sync() { MESOSPHERE_ASSERT(!KScheduler::IsSchedulerLockedByCurrentThread()); KDpcTask dummy_task; KDpcTask::Request(std::addressof(dummy_task)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_dump_object.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::KDumpObject { namespace { constexpr const char * const ThreadStates[] = { [KThread::ThreadState_Initialized] = "Initialized", [KThread::ThreadState_Waiting] = "Waiting", [KThread::ThreadState_Runnable] = "Runnable", [KThread::ThreadState_Terminated] = "Terminated", }; void DumpThread(KThread *thread) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); MESOSPHERE_RELEASE_LOG(" State: 0x%04x Suspend: 0x%04x Dpc: 0x%x\n", thread->GetRawState(), thread->GetSuspendFlags(), thread->GetDpc()); MESOSPHERE_RELEASE_LOG(" TLS: %p (%p)\n", GetVoidPointer(thread->GetThreadLocalRegionAddress()), thread->GetThreadLocalRegionHeapAddress()); } else { MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu Run=%d Ideal=%d (%d) Affinity=%016lx (%016lx)\n", thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize, thread->GetActiveCore(), thread->GetIdealVirtualCore(), thread->GetIdealPhysicalCore(), thread->GetVirtualAffinityMask(), thread->GetAffinityMask().GetAffinityMask()); } } void DumpThreadCallStack(KThread *thread) { if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3lu %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), process->GetId(), process->GetName(), thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); KDebug::PrintRegister(thread); KDebug::PrintBacktrace(thread); } else { MESOSPHERE_RELEASE_LOG("Thread ID=%5lu pid=%3d %-11s Pri=%2d %-11s KernelStack=%4zu/%4zu\n", thread->GetId(), -1, "(kernel)", thread->GetPriority(), ThreadStates[thread->GetState()], thread->GetKernelStackUsage(), PageSize); } } void DumpHandle(const KProcess::ListAccessor &accessor, KProcess *process) { MESOSPHERE_RELEASE_LOG("Process ID=%lu (%s)\n", process->GetId(), process->GetName()); const auto end = accessor.end(); const auto &handle_table = process->GetHandleTable(); const size_t max_handles = handle_table.GetTableSize(); for (size_t i = 0; i < max_handles; ++i) { /* Get the object + handle. */ ams::svc::Handle handle = ams::svc::InvalidHandle; KScopedAutoObject obj = handle_table.GetObjectByIndex(std::addressof(handle), i); if (obj.IsNotNull()) { if (auto *target = obj->DynamicCast<KServerSession *>(); target != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Client=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetClientSession())); target->Dump(); } else if (auto *target = obj->DynamicCast<KClientSession *>(); target != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Server=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), std::addressof(target->GetParent()->GetServerSession())); } else if (auto *target = obj->DynamicCast<KThread *>(); target != nullptr) { KProcess *target_owner = target->GetOwnerProcess(); const s32 owner_pid = target_owner != nullptr ? static_cast<s32>(target_owner->GetId()) : -1; MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d PID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast<s32>(target->GetId()), owner_pid); } else if (auto *target = obj->DynamicCast<KProcess *>(); target != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s ID=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast<s32>(target->GetId())); } else if (auto *target = obj->DynamicCast<KSharedMemory *>(); target != nullptr) { /* Find the owner. */ KProcess *target_owner = nullptr; for (auto it = accessor.begin(); it != end; ++it) { if (static_cast<KProcess *>(std::addressof(*it))->GetId() == target->GetOwnerProcessId()) { target_owner = static_cast<KProcess *>(std::addressof(*it)); break; } } MESOSPHERE_ASSERT(target_owner != nullptr); MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Size=%zu KB OwnerPID=%d (%s)\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetSize() / 1_KB, static_cast<s32>(target_owner->GetId()), target_owner->GetName()); } else if (auto *target = obj->DynamicCast<KTransferMemory *>(); target != nullptr) { KProcess *target_owner = target->GetOwner(); MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast<s32>(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); } else if (auto *target = obj->DynamicCast<KCodeMemory *>(); target != nullptr) { KProcess *target_owner = target->GetOwner(); MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s OwnerPID=%d (%s) OwnerAddress=%lx Size=%zu KB\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), static_cast<s32>(target_owner->GetId()), target_owner->GetName(), GetInteger(target->GetSourceAddress()), target->GetSize() / 1_KB); } else if (auto *target = obj->DynamicCast<KInterruptEvent *>(); target != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s irq=%d\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), target->GetInterruptId()); } else if (auto *target = obj->DynamicCast<KEvent *>(); target != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); } else if (auto *target = obj->DynamicCast<KReadableEvent *>(); target != nullptr) { if (KEvent *event = target->GetParent(); event != nullptr) { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s Parent=%p\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName(), event); } else { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); } } else { MESOSPHERE_RELEASE_LOG("Handle %08x Obj=%p Ref=%d Type=%s\n", handle, obj.GetPointerUnsafe(), obj->GetReferenceCount() - 1, obj->GetTypeName()); } if (auto *sync = obj->DynamicCast<KSynchronizationObject *>(); sync != nullptr) { sync->DumpWaiters(); } } } MESOSPHERE_RELEASE_LOG("%zu(max %zu)/%zu used.\n", handle_table.GetCount(), max_handles, handle_table.GetTableSize()); MESOSPHERE_RELEASE_LOG("\n\n"); } void DumpMemory(KProcess *process) { const auto process_id = process->GetId(); MESOSPHERE_RELEASE_LOG("Process ID=%3lu (%s)\n", process_id, process->GetName()); /* Dump the memory blocks. */ process->GetPageTable().DumpMemoryBlocks(); /* Collect information about memory totals. */ const size_t code = process->GetPageTable().GetCodeSize(); const size_t code_data = process->GetPageTable().GetCodeDataSize(); const size_t alias_code = process->GetPageTable().GetAliasCodeSize(); const size_t alias_code_data = process->GetPageTable().GetAliasCodeDataSize(); const size_t normal = process->GetPageTable().GetNormalMemorySize(); const size_t main_stack = process->GetMainStackSize(); size_t shared = 0; { KSharedMemory::ListAccessor accessor; const auto end = accessor.end(); for (auto it = accessor.begin(); it != end; ++it) { KSharedMemory *shared_mem = static_cast<KSharedMemory *>(std::addressof(*it)); if (shared_mem->GetOwnerProcessId() == process_id) { shared += shared_mem->GetSize(); } } } /* Dump the totals. */ MESOSPHERE_RELEASE_LOG("---\n"); MESOSPHERE_RELEASE_LOG("Code %8zu KB\n", code / 1_KB); MESOSPHERE_RELEASE_LOG("CodeData %8zu KB\n", code_data / 1_KB); MESOSPHERE_RELEASE_LOG("AliasCode %8zu KB\n", alias_code / 1_KB); MESOSPHERE_RELEASE_LOG("AliasCodeData %8zu KB\n", alias_code_data / 1_KB); MESOSPHERE_RELEASE_LOG("Heap %8zu KB\n", normal / 1_KB); MESOSPHERE_RELEASE_LOG("SharedMemory %8zu KB\n", shared / 1_KB); MESOSPHERE_RELEASE_LOG("InitialStack %8zu KB\n", main_stack / 1_KB); MESOSPHERE_RELEASE_LOG("---\n"); MESOSPHERE_RELEASE_LOG("TOTAL %8zu KB\n", (code + code_data + alias_code + alias_code_data + normal + main_stack + shared) / 1_KB); MESOSPHERE_RELEASE_LOG("\n\n"); } void DumpPageTable(KProcess *process) { MESOSPHERE_RELEASE_LOG("Process ID=%3lu (%s)\n", process->GetId(), process->GetName()); process->GetPageTable().DumpPageTable(); MESOSPHERE_RELEASE_LOG("\n\n"); } void DumpProcess(KProcess *process) { MESOSPHERE_RELEASE_LOG("Process ID=%3lu index=%3zu State=%d (%s)\n", process->GetId(), process->GetSlabIndex(), process->GetState(), process->GetName()); } void DumpPort(const KProcess::ListAccessor &accessor, KProcess *process) { MESOSPHERE_RELEASE_LOG("Dump Port Process ID=%lu (%s)\n", process->GetId(), process->GetName()); const auto end = accessor.end(); const auto &handle_table = process->GetHandleTable(); const size_t max_handles = handle_table.GetTableSize(); for (size_t i = 0; i < max_handles; ++i) { /* Get the object + handle. */ ams::svc::Handle handle = ams::svc::InvalidHandle; KScopedAutoObject obj = handle_table.GetObjectByIndex(std::addressof(handle), i); if (obj.IsNull()) { continue; } /* Process the object as a port. */ if (auto *server = obj->DynamicCast<KServerPort *>(); server != nullptr) { const KClientPort *client = std::addressof(server->GetParent()->GetClientPort()); const uintptr_t port_name = server->GetParent()->GetName(); /* Get the port name. */ char name[9] = {}; { /* Find the client port process. */ KProcess *client_port_process = nullptr; ON_SCOPE_EXIT { if (client_port_process != nullptr) { client_port_process->Close(); } }; { for (auto it = accessor.begin(); it != end && client_port_process == nullptr; ++it) { KProcess *cur = static_cast<KProcess *>(std::addressof(*it)); for (size_t j = 0; j < cur->GetHandleTable().GetTableSize(); ++j) { ams::svc::Handle cur_h = ams::svc::InvalidHandle; KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); if (cur_o.IsNotNull()) { if (cur_o.GetPointerUnsafe() == client) { client_port_process = cur; client_port_process->Open(); break; } } } } } /* Read the port name. */ if (client_port_process != nullptr) { if (R_FAILED(client_port_process->GetPageTable().CopyMemoryFromLinearToKernel(KProcessAddress(name), 8, port_name, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { std::memset(name, 0, sizeof(name)); } for (size_t i = 0; i < 8 && name[i] != 0; i++) { if (name[i] > 0x7F) { std::memset(name, 0, sizeof(name)); break; } } } } MESOSPHERE_RELEASE_LOG("%-9s: Handle %08x Obj=%p Cur=%3d Peak=%3d Max=%3d\n", name, handle, obj.GetPointerUnsafe(), client->GetNumSessions(), client->GetPeakSessions(), client->GetMaxSessions()); /* Identify any sessions. */ { for (auto it = accessor.begin(); it != end; ++it) { KProcess *cur = static_cast<KProcess *>(std::addressof(*it)); for (size_t j = 0; j < cur->GetHandleTable().GetTableSize(); ++j) { ams::svc::Handle cur_h = ams::svc::InvalidHandle; KScopedAutoObject cur_o = cur->GetHandleTable().GetObjectByIndex(std::addressof(cur_h), j); if (cur_o.IsNull()) { continue; } if (auto *session = cur_o->DynamicCast<KClientSession *>(); session != nullptr && session->GetParent()->GetParent() == client) { MESOSPHERE_RELEASE_LOG(" Client %p Server %p %-12s: PID=%3lu\n", session, std::addressof(session->GetParent()->GetServerSession()), cur->GetName(), cur->GetId()); } } } } } } } ALWAYS_INLINE s64 GetTickOrdered() { __asm__ __volatile__("" ::: "memory"); const s64 tick = KHardwareTimer::GetTick(); __asm__ __volatile__("" ::: "memory"); return tick; } } void DumpThread() { MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ KThread::ListAccessor accessor; const auto end = accessor.end(); /* Dump each thread. */ for (auto it = accessor.begin(); it != end; ++it) { DumpThread(static_cast<KThread *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpThread(u64 thread_id) { MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ if (KThread *thread = KThread::GetThreadFromId(thread_id); thread != nullptr) { ON_SCOPE_EXIT { thread->Close(); }; DumpThread(thread); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack() { MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Lock the list. */ KThread::ListAccessor accessor; const auto end = accessor.end(); /* Dump each thread. */ for (auto it = accessor.begin(); it != end; ++it) { DumpThreadCallStack(static_cast<KThread *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpThreadCallStack(u64 thread_id) { MESOSPHERE_RELEASE_LOG("Dump Thread\n"); { /* Find and dump the target thread. */ if (KThread *thread = KThread::GetThreadFromId(thread_id); thread != nullptr) { ON_SCOPE_EXIT { thread->Close(); }; DumpThreadCallStack(thread); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpKernelObject() { MESOSPHERE_LOG("Dump Kernel Object\n"); { /* Static slab heaps. */ { #define DUMP_KSLABOBJ(__OBJECT__) \ MESOSPHERE_RELEASE_LOG(#__OBJECT__ "\n"); \ MESOSPHERE_RELEASE_LOG(" Cur=%3zu Peak=%3zu Max=%3zu\n", __OBJECT__::GetSlabHeapSize() - __OBJECT__::GetNumRemaining(), __OBJECT__::GetPeakIndex(), __OBJECT__::GetSlabHeapSize()) DUMP_KSLABOBJ(KEvent); DUMP_KSLABOBJ(KInterruptEvent); DUMP_KSLABOBJ(KProcess); DUMP_KSLABOBJ(KThread); DUMP_KSLABOBJ(KPort); DUMP_KSLABOBJ(KSharedMemory); DUMP_KSLABOBJ(KTransferMemory); DUMP_KSLABOBJ(KDeviceAddressSpace); DUMP_KSLABOBJ(KDebug); DUMP_KSLABOBJ(KSession); DUMP_KSLABOBJ(KLightSession); DUMP_KSLABOBJ(KThreadLocalPage); DUMP_KSLABOBJ(KObjectName); DUMP_KSLABOBJ(KEventInfo); DUMP_KSLABOBJ(KSessionRequest); DUMP_KSLABOBJ(KResourceLimit); DUMP_KSLABOBJ(KIoPool); DUMP_KSLABOBJ(KIoRegion); #undef DUMP_KSLABOBJ } MESOSPHERE_RELEASE_LOG("\n"); /* Dynamic slab heaps. */ { /* Memory block slabs. */ { MESOSPHERE_RELEASE_LOG("App Memory Block\n"); auto &app = Kernel::GetApplicationSystemResource().GetMemoryBlockSlabManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", app.GetUsed(), app.GetPeak(), app.GetCount()); MESOSPHERE_RELEASE_LOG("Sys Memory Block\n"); auto &sys = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", sys.GetUsed(), sys.GetPeak(), sys.GetCount()); } /* KBlockInfo slab. */ { MESOSPHERE_RELEASE_LOG("KBlockInfo\n"); auto &manager = Kernel::GetSystemSystemResource().GetBlockInfoManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); } /* Page Table slab. */ { MESOSPHERE_RELEASE_LOG("Page Table\n"); auto &manager = Kernel::GetSystemSystemResource().GetPageTableManager(); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount()); } } MESOSPHERE_RELEASE_LOG("\n"); /* Process resources. */ { KProcess::ListAccessor accessor; size_t process_pts = 0; const auto end = accessor.end(); for (auto it = accessor.begin(); it != end; ++it) { KProcess *process = static_cast<KProcess *>(std::addressof(*it)); /* Count the number of threads. */ int threads = 0; { KThread::ListAccessor thr_accessor; const auto thr_end = thr_accessor.end(); for (auto thr_it = thr_accessor.begin(); thr_it != thr_end; ++thr_it) { KThread *thread = static_cast<KThread *>(std::addressof(*thr_it)); if (thread->GetOwnerProcess() == process) { ++threads; } } } /* Count the number of events. */ int events = 0; { KEvent::ListAccessor ev_accessor; const auto ev_end = ev_accessor.end(); for (auto ev_it = ev_accessor.begin(); ev_it != ev_end; ++ev_it) { KEvent *event = static_cast<KEvent *>(std::addressof(*ev_it)); if (event->GetOwner() == process) { ++events; } } } size_t pts = process->GetPageTable().CountPageTables(); process_pts += pts; MESOSPHERE_RELEASE_LOG("%-12s: PID=%3lu Thread %4d / Event %4d / PageTable %5zu\n", process->GetName(), process->GetId(), threads, events, pts); if (const auto &system_resource = process->GetSystemResource(); system_resource.IsSecureResource()) { const auto &secure_resource = static_cast<const KSecureSystemResource &>(system_resource); MESOSPHERE_RELEASE_LOG(" System Resource\n"); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetDynamicPageManager().GetUsed(), secure_resource.GetDynamicPageManager().GetPeak(), secure_resource.GetDynamicPageManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Memory Block\n"); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetMemoryBlockSlabManager().GetUsed(), secure_resource.GetMemoryBlockSlabManager().GetPeak(), secure_resource.GetMemoryBlockSlabManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Page Table\n"); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetPageTableManager().GetUsed(), secure_resource.GetPageTableManager().GetPeak(), secure_resource.GetPageTableManager().GetCount()); MESOSPHERE_RELEASE_LOG(" Block Info\n"); MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetBlockInfoManager().GetUsed(), secure_resource.GetBlockInfoManager().GetPeak(), secure_resource.GetBlockInfoManager().GetCount()); } } MESOSPHERE_RELEASE_LOG("Process Page Table %zu\n", process_pts); MESOSPHERE_RELEASE_LOG("Kernel Page Table %zu\n", Kernel::GetKernelPageTable().CountPageTables()); } MESOSPHERE_RELEASE_LOG("\n"); /* Resource limits. */ { auto &sys_rl = Kernel::GetSystemResourceLimit(); u64 cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_PhysicalMemoryMax); u64 lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax); MESOSPHERE_RELEASE_LOG("System ResourceLimit PhysicalMemory 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(lim >> 32), static_cast<u32>(lim)); cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax); lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_ThreadCountMax); MESOSPHERE_RELEASE_LOG("System ResourceLimit Thread %4lu / %4lu\n", cur, lim); cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_EventCountMax); lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_EventCountMax); MESOSPHERE_RELEASE_LOG("System ResourceLimit Event %4lu / %4lu\n", cur, lim); cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_TransferMemoryCountMax); lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax); MESOSPHERE_RELEASE_LOG("System ResourceLimit TransferMemory %4lu / %4lu\n", cur, lim); cur = sys_rl.GetCurrentValue(ams::svc::LimitableResource_SessionCountMax); lim = sys_rl.GetLimitValue(ams::svc::LimitableResource_SessionCountMax); MESOSPHERE_RELEASE_LOG("System ResourceLimit Session %4lu / %4lu\n", cur, lim); { KResourceLimit::ListAccessor accessor; const auto end = accessor.end(); for (auto it = accessor.begin(); it != end; ++it) { KResourceLimit *rl = static_cast<KResourceLimit *>(std::addressof(*it)); cur = rl->GetCurrentValue(ams::svc::LimitableResource_PhysicalMemoryMax); lim = rl->GetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax); MESOSPHERE_RELEASE_LOG("ResourceLimit %zu PhysicalMemory 0x%01x_%08x / 0x%01x_%08x\n", rl->GetSlabIndex(), static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(lim >> 32), static_cast<u32>(lim)); } } } MESOSPHERE_RELEASE_LOG("\n"); /* Memory Manager. */ { auto &mm = Kernel::GetMemoryManager(); u64 max = mm.GetSize(); u64 cur = max - mm.GetFreeSize(); MESOSPHERE_RELEASE_LOG("Kernel Heap Size 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(max >> 32), static_cast<u32>(max)); MESOSPHERE_RELEASE_LOG("\n"); max = mm.GetSize(KMemoryManager::Pool_Application); cur = max - mm.GetFreeSize(KMemoryManager::Pool_Application); MESOSPHERE_RELEASE_LOG("Application 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(max >> 32), static_cast<u32>(max)); mm.DumpFreeList(KMemoryManager::Pool_Application); MESOSPHERE_RELEASE_LOG("\n"); max = mm.GetSize(KMemoryManager::Pool_Applet); cur = max - mm.GetFreeSize(KMemoryManager::Pool_Applet); MESOSPHERE_RELEASE_LOG("Applet 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(max >> 32), static_cast<u32>(max)); mm.DumpFreeList(KMemoryManager::Pool_Applet); MESOSPHERE_RELEASE_LOG("\n"); max = mm.GetSize(KMemoryManager::Pool_System); cur = max - mm.GetFreeSize(KMemoryManager::Pool_System); MESOSPHERE_RELEASE_LOG("System 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(max >> 32), static_cast<u32>(max)); mm.DumpFreeList(KMemoryManager::Pool_System); MESOSPHERE_RELEASE_LOG("\n"); max = mm.GetSize(KMemoryManager::Pool_SystemNonSecure); cur = max - mm.GetFreeSize(KMemoryManager::Pool_SystemNonSecure); MESOSPHERE_RELEASE_LOG("SystemNonSecure 0x%01x_%08x / 0x%01x_%08x\n", static_cast<u32>(cur >> 32), static_cast<u32>(cur), static_cast<u32>(max >> 32), static_cast<u32>(max)); mm.DumpFreeList(KMemoryManager::Pool_SystemNonSecure); MESOSPHERE_RELEASE_LOG("\n"); } MESOSPHERE_RELEASE_LOG("\n"); } MESOSPHERE_RELEASE_LOG("\n"); } void DumpHandle() { MESOSPHERE_RELEASE_LOG("Dump Handle\n"); { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Dump each process. */ for (auto it = accessor.begin(); it != end; ++it) { DumpHandle(accessor, static_cast<KProcess *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpHandle(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump Handle\n"); { /* Find and dump the target process. */ if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; /* Lock the list. */ KProcess::ListAccessor accessor; DumpHandle(accessor, process); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpKernelMemory() { MESOSPHERE_RELEASE_LOG("Dump Kernel Memory Info\n"); { Kernel::GetKernelPageTable().DumpMemoryBlocks(); } MESOSPHERE_RELEASE_LOG("\n"); } void DumpMemory() { MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Dump each process. */ for (auto it = accessor.begin(); it != end; ++it) { DumpMemory(static_cast<KProcess *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpMemory(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump Memory Info\n"); { /* Find and dump the target process. */ if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; DumpMemory(process); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpProcess() { MESOSPHERE_RELEASE_LOG("Dump Process\n"); { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Dump each process. */ for (auto it = accessor.begin(); it != end; ++it) { DumpProcess(static_cast<KProcess *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpKernelPageTable() { MESOSPHERE_RELEASE_LOG("Dump Kernel PageTable\n"); { Kernel::GetKernelPageTable().DumpPageTable(); } MESOSPHERE_RELEASE_LOG("\n"); } void DumpPageTable() { MESOSPHERE_RELEASE_LOG("Dump Process\n"); { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Dump each process. */ for (auto it = accessor.begin(); it != end; ++it) { DumpPageTable(static_cast<KProcess *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpPageTable(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump PageTable\n"); { /* Find and dump the target process. */ if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; DumpPageTable(process); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpKernelCpuUtilization() { MESOSPHERE_RELEASE_LOG("Dump Kernel Cpu Utilization\n"); constexpr size_t MaxObjects = 64; { /* Create tracking arrays. */ KAutoObject *objects[MaxObjects]; u32 cpu_time[MaxObjects]; s64 start_tick; size_t i, n; KDpcManager::Sync(); { /* Lock the thread list. */ KThread::ListAccessor accessor; /* Begin tracking. */ start_tick = GetTickOrdered(); /* Iterate, finding kernel threads. */ const auto end = accessor.end(); i = 0; for (auto it = accessor.begin(); it != end; ++it) { KThread *thread = static_cast<KThread *>(std::addressof(*it)); if (KProcess *process = thread->GetOwnerProcess(); process == nullptr) { if (AMS_LIKELY(i < MaxObjects)) { if (AMS_LIKELY(thread->Open())) { cpu_time[i] = thread->GetCpuTime(); objects[i] = thread; ++i; } } } } /* Keep track of how many kernel threads we found. */ n = i; } /* Wait one second. */ const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromSeconds(1)); GetCurrentThread().Sleep(timeout); KDpcManager::Sync(); /* Update our metrics. */ for (i = 0; i < n; ++i) { KThread *thread = static_cast<KThread *>(objects[i]); cpu_time[i] = thread->GetCpuTime() - cpu_time[i]; } /* End tracking. */ const s64 end_tick = GetTickOrdered(); /* Log thread utilization. */ for (i = 0; i < n; ++i) { KThread *thread = static_cast<KThread *>(objects[i]); const s64 t = static_cast<u64>(cpu_time[i]) * 1000 / (end_tick - start_tick); MESOSPHERE_RELEASE_LOG("tid=%3lu (kernel) %3lu.%lu%% pri=%2d af=%lx\n", thread->GetId(), t / 10, t % 10, thread->GetPriority(), thread->GetAffinityMask().GetAffinityMask()); } /* Close all objects. */ for (i = 0; i < n; ++i) { objects[i]->Close(); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpCpuUtilization() { MESOSPHERE_RELEASE_LOG("Dump Cpu Utilization\n"); /* NOTE: Nintendo uses 0x40 as maximum here, but the KProcess slabheap has 0x50 entries. */ /* We have the stack space, so there's no reason not to allow logging all processes. */ constexpr size_t MaxObjects = 0x50; { /* Create tracking arrays. */ KAutoObject *objects[MaxObjects]; u32 cpu_time[MaxObjects]; s64 start_tick; size_t i, n; KDpcManager::Sync(); { /* Lock the process list. */ KProcess::ListAccessor accessor; /* Begin tracking. */ start_tick = GetTickOrdered(); /* Iterate, finding processes. */ const auto end = accessor.end(); i = 0; for (auto it = accessor.begin(); it != end; ++it) { KProcess *process = static_cast<KProcess *>(std::addressof(*it)); if (AMS_LIKELY(i < MaxObjects)) { if (AMS_LIKELY(process->Open())) { cpu_time[i] = process->GetCpuTime(); objects[i] = process; ++i; } } } /* Keep track of how many processes we found. */ n = i; } /* Wait one second. */ const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromSeconds(1)); GetCurrentThread().Sleep(timeout); KDpcManager::Sync(); /* Update our metrics. */ for (i = 0; i < n; ++i) { KProcess *process = static_cast<KProcess *>(objects[i]); cpu_time[i] = process->GetCpuTime() - cpu_time[i]; } /* End tracking. */ const s64 end_tick = GetTickOrdered(); /* Log process utilization. */ for (i = 0; i < n; ++i) { KProcess *process = static_cast<KProcess *>(objects[i]); const s64 t = static_cast<u64>(cpu_time[i]) * 1000 / (end_tick - start_tick); MESOSPHERE_RELEASE_LOG("pid=%3lu %-11s %3lu.%lu%%\n", process->GetId(), process->GetName(), t / 10, t % 10); } /* Close all objects. */ for (i = 0; i < n; ++i) { objects[i]->Close(); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpCpuUtilization(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump Cpu Utilization\n"); constexpr size_t MaxObjects = 64; { /* Create tracking arrays. */ KAutoObject *objects[MaxObjects]; u32 cpu_time[MaxObjects]; s64 start_tick; size_t i, n; KDpcManager::Sync(); { /* Lock the thread list. */ KThread::ListAccessor accessor; /* Begin tracking. */ start_tick = GetTickOrdered(); /* Iterate, finding process threads. */ const auto end = accessor.end(); i = 0; for (auto it = accessor.begin(); it != end; ++it) { KThread *thread = static_cast<KThread *>(std::addressof(*it)); if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->GetId() == process_id) { if (AMS_LIKELY(i < MaxObjects)) { if (AMS_LIKELY(thread->Open())) { cpu_time[i] = thread->GetCpuTime(); objects[i] = thread; ++i; } } } } /* Keep track of how many process threads we found. */ n = i; } /* Wait one second. */ const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromSeconds(1)); GetCurrentThread().Sleep(timeout); KDpcManager::Sync(); /* Update our metrics. */ for (i = 0; i < n; ++i) { KThread *thread = static_cast<KThread *>(objects[i]); cpu_time[i] = thread->GetCpuTime() - cpu_time[i]; } /* End tracking. */ const s64 end_tick = GetTickOrdered(); /* Log thread utilization. */ for (i = 0; i < n; ++i) { KThread *thread = static_cast<KThread *>(objects[i]); KProcess *process = thread->GetOwnerProcess(); const s64 t = static_cast<u64>(cpu_time[i]) * 1000 / (end_tick - start_tick); MESOSPHERE_RELEASE_LOG("tid=%3lu pid=%3lu %-11s %3lu.%lu%% pri=%2d af=%lx\n", thread->GetId(), process->GetId(), process->GetName(), t / 10, t % 10, thread->GetPriority(), thread->GetAffinityMask().GetAffinityMask()); } /* Close all objects. */ for (i = 0; i < n; ++i) { objects[i]->Close(); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpProcess(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump Process\n"); { /* Find and dump the target process. */ if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; DumpProcess(process); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpPort() { MESOSPHERE_RELEASE_LOG("Dump Port\n"); { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Dump each process. */ for (auto it = accessor.begin(); it != end; ++it) { DumpPort(accessor, static_cast<KProcess *>(std::addressof(*it))); } } MESOSPHERE_RELEASE_LOG("\n"); } void DumpPort(u64 process_id) { MESOSPHERE_RELEASE_LOG("Dump Port\n"); { /* Find and dump the target process. */ if (KProcess *process = KProcess::GetProcessFromId(process_id); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; /* Lock the list. */ KProcess::ListAccessor accessor; DumpPort(accessor, process); } } MESOSPHERE_RELEASE_LOG("\n"); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_event.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KEvent::Initialize() { MESOSPHERE_ASSERT_THIS(); /* Create our readable event. */ KAutoObject::Create<KReadableEvent>(std::addressof(m_readable_event)); /* Initialize our readable event. */ m_readable_event.Initialize(this); /* Set our owner process. */ m_owner = GetCurrentProcessPointer(); m_owner->Open(); /* Mark initialized. */ m_initialized = true; } void KEvent::Finalize() { MESOSPHERE_ASSERT_THIS(); } void KEvent::Signal() { KScopedSchedulerLock sl; if (!m_readable_event_destroyed) { m_readable_event.Signal(); } } void KEvent::Clear() { KScopedSchedulerLock sl; if (!m_readable_event_destroyed) { m_readable_event.Clear(); } } void KEvent::PostDestroy(uintptr_t arg) { /* Release the event count resource the owner process holds. */ KProcess *owner = reinterpret_cast<KProcess *>(arg); owner->ReleaseResource(ams::svc::LimitableResource_EventCountMax, 1); owner->Close(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_handle_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KHandleTable::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Get the table and clear our record of it. */ u16 saved_table_size = 0; { KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); std::swap(m_table_size, saved_table_size); } /* Close and free all entries. */ for (size_t i = 0; i < saved_table_size; i++) { if (KAutoObject *obj = m_objects[i]; obj != nullptr) { obj->Close(); } } } bool KHandleTable::Remove(ams::svc::Handle handle) { MESOSPHERE_ASSERT_THIS(); /* Don't allow removal of a pseudo-handle. */ if (AMS_UNLIKELY(ams::svc::IsPseudoHandle(handle))) { return false; } /* Handles must not have reserved bits set. */ const auto handle_pack = GetHandleBitPack(handle); if (AMS_UNLIKELY(handle_pack.Get<HandleReserved>() != 0)) { return false; } /* Find the object and free the entry. */ KAutoObject *obj = nullptr; { KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); if (AMS_LIKELY(this->IsValidHandle(handle))) { const auto index = handle_pack.Get<HandleIndex>(); obj = m_objects[index]; this->FreeEntry(index); } else { return false; } } /* Close the object. */ obj->Close(); return true; } Result KHandleTable::Add(ams::svc::Handle *out_handle, KAutoObject *obj) { MESOSPHERE_ASSERT_THIS(); KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); /* Never exceed our capacity. */ R_UNLESS(m_count < m_table_size, svc::ResultOutOfHandles()); /* Allocate entry, set output handle. */ { const auto linear_id = this->AllocateLinearId(); const auto index = this->AllocateEntry(); m_entry_infos[index].linear_id = linear_id; m_objects[index] = obj; obj->Open(); *out_handle = EncodeHandle(index, linear_id); } R_SUCCEED(); } Result KHandleTable::Reserve(ams::svc::Handle *out_handle) { MESOSPHERE_ASSERT_THIS(); KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); /* Never exceed our capacity. */ R_UNLESS(m_count < m_table_size, svc::ResultOutOfHandles()); *out_handle = EncodeHandle(this->AllocateEntry(), this->AllocateLinearId()); R_SUCCEED(); } void KHandleTable::Unreserve(ams::svc::Handle handle) { MESOSPHERE_ASSERT_THIS(); KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); /* Unpack the handle. */ const auto handle_pack = GetHandleBitPack(handle); const auto index = handle_pack.Get<HandleIndex>(); const auto linear_id = handle_pack.Get<HandleLinearId>(); const auto reserved = handle_pack.Get<HandleReserved>(); MESOSPHERE_ASSERT(reserved == 0); MESOSPHERE_ASSERT(linear_id != 0); MESOSPHERE_UNUSED(linear_id, reserved); if (AMS_LIKELY(index < m_table_size)) { /* NOTE: This code does not check the linear id. */ MESOSPHERE_ASSERT(m_objects[index] == nullptr); this->FreeEntry(index); } } void KHandleTable::Register(ams::svc::Handle handle, KAutoObject *obj) { MESOSPHERE_ASSERT_THIS(); KScopedDisableDispatch dd; KScopedSpinLock lk(m_lock); /* Unpack the handle. */ const auto handle_pack = GetHandleBitPack(handle); const auto index = handle_pack.Get<HandleIndex>(); const auto linear_id = handle_pack.Get<HandleLinearId>(); const auto reserved = handle_pack.Get<HandleReserved>(); MESOSPHERE_ASSERT(reserved == 0); MESOSPHERE_ASSERT(linear_id != 0); MESOSPHERE_UNUSED(reserved); if (AMS_LIKELY(index < m_table_size)) { /* Set the entry. */ MESOSPHERE_ASSERT(m_objects[index] == nullptr); m_entry_infos[index].linear_id = linear_id; m_objects[index] = obj; obj->Open(); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_initial_process_reader.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { struct BlzSegmentFlags { using Offset = util::BitPack16::Field<0, 12, u32>; using Size = util::BitPack16::Field<Offset::Next, 4, u32>; }; NOINLINE void BlzUncompress(void *_end) { /* Parse the footer, endian agnostic. */ static_assert(sizeof(u32) == 4); static_assert(sizeof(u16) == 2); static_assert(sizeof(u8) == 1); u8 *end = static_cast<u8 *>(_end); const u32 total_size = (end[-12] << 0) | (end[-11] << 8) | (end[-10] << 16) | (end[- 9] << 24); const u32 footer_size = (end[- 8] << 0) | (end[- 7] << 8) | (end[- 6] << 16) | (end[- 5] << 24); const u32 additional_size = (end[- 4] << 0) | (end[- 3] << 8) | (end[- 2] << 16) | (end[- 1] << 24); /* Prepare to decompress. */ u8 *cmp_start = end - total_size; u32 cmp_ofs = total_size - footer_size; u32 out_ofs = total_size + additional_size; /* Decompress. */ while (out_ofs) { u8 control = cmp_start[--cmp_ofs]; /* Each bit in the control byte is a flag indicating compressed or not compressed. */ for (size_t i = 0; i < 8 && out_ofs; ++i, control <<= 1) { if (control & 0x80) { /* NOTE: Nintendo does not check if it's possible to decompress. */ /* As such, we will leave the following as a debug assertion, and not a release assertion. */ MESOSPHERE_AUDIT(cmp_ofs >= sizeof(u16)); cmp_ofs -= sizeof(u16); /* Extract segment bounds. */ const util::BitPack16 seg_flags{static_cast<u16>((cmp_start[cmp_ofs] << 0) | (cmp_start[cmp_ofs + 1] << 8))}; const u32 seg_ofs = seg_flags.Get<BlzSegmentFlags::Offset>() + 3; const u32 seg_size = std::min(seg_flags.Get<BlzSegmentFlags::Size>() + 3, out_ofs); MESOSPHERE_AUDIT(out_ofs + seg_ofs <= total_size + additional_size); /* Copy the data. */ out_ofs -= seg_size; for (size_t j = 0; j < seg_size; j++) { cmp_start[out_ofs + j] = cmp_start[out_ofs + seg_ofs + j]; } } else { /* NOTE: Nintendo does not check if it's possible to copy. */ /* As such, we will leave the following as a debug assertion, and not a release assertion. */ MESOSPHERE_AUDIT(cmp_ofs >= sizeof(u8)); cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; } } } } NOINLINE void LoadInitialProcessSegment(const KPageGroup &pg, size_t seg_offset, size_t seg_size, size_t binary_size, KVirtualAddress data, bool compressed) { /* Save the original binary extents, for later use. */ const KPhysicalAddress binary_phys = KMemoryLayout::GetLinearPhysicalAddress(data); /* Create a page group representing the segment. */ KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()); MESOSPHERE_R_ABORT_UNLESS(pg.CopyRangeTo(segment_pg, seg_offset, util::AlignUp(seg_size, PageSize))); /* Setup the new page group's memory so that we can load the segment. */ { KVirtualAddress last_block = Null<KVirtualAddress>; KVirtualAddress last_data = Null<KVirtualAddress>; size_t last_copy_size = 0; size_t last_clear_size = 0; size_t remaining_copy_size = binary_size; for (const auto &block : segment_pg) { /* Get the current block extents. */ const auto block_addr = block.GetAddress(); const size_t block_size = block.GetSize(); if (remaining_copy_size > 0) { /* Determine if we need to copy anything. */ const size_t cur_size = std::min<size_t>(block_size, remaining_copy_size); /* NOTE: The first block may potentially overlap the binary we want to copy to. */ /* Consider e.g. the case where the overall compressed image has size 0x40000, seg_offset is 0x30000, and binary_size is > 0x20000. */ /* Suppose too that data points, say, 0x18000 into the compressed image. */ /* Suppose finally that we simply naively copy in order. */ /* The first iteration of this loop will perform an 0x10000 copy from image+0x18000 to image + 0x30000 (as there is no overlap). */ /* The second iteration will perform a copy from image+0x28000 to <allocated pages>. */ /* However, the first copy will have trashed the data in the second copy. */ /* Thus, we must copy the first block after-the-fact to avoid potentially trashing data in the overlap case. */ /* It is guaranteed by pre-condition that only the very first block can overlap with the physical binary, so we can simply memmove it at the end. */ if (last_block != Null<KVirtualAddress>) { /* This is guaranteed by pre-condition, but for ease of debugging, check for no overlap. */ MESOSPHERE_ASSERT(!util::HasOverlap(GetInteger(binary_phys), binary_size, GetInteger(block_addr), cur_size)); MESOSPHERE_UNUSED(binary_phys); /* We need to copy. */ std::memcpy(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), GetVoidPointer(data), cur_size); /* If we need to, clear past where we're copying. */ if (cur_size != block_size) { std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr + cur_size)), 0, block_size - cur_size); } /* Advance. */ remaining_copy_size -= cur_size; data += cur_size; } else { /* Save the first block, which may potentially overlap, so that we can copy it later. */ last_block = KMemoryLayout::GetLinearVirtualAddress(block_addr); last_data = data; last_copy_size = cur_size; last_clear_size = block_size - cur_size; /* Advance. */ remaining_copy_size -= cur_size; data += cur_size; } } else { /* We don't have data to copy, so we should just clear the pages. */ std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), 0, block_size); } } /* Handle a last block. */ if (last_copy_size != 0) { if (last_block != last_data) { std::memmove(GetVoidPointer(last_block), GetVoidPointer(last_data), last_copy_size); } if (last_clear_size != 0) { std::memset(GetVoidPointer(last_block + last_copy_size), 0, last_clear_size); } } } /* If compressed, uncompress the data. */ if (compressed) { /* Get the temporary region. */ const auto &temp_region = KMemoryLayout::GetTempRegion(); MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0); /* Map the process's memory into the temporary region. */ KProcessAddress temp_address = Null<KProcessAddress>; MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), segment_pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite)); ON_SCOPE_EXIT { MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, segment_pg, KMemoryState_Kernel)); }; /* Uncompress the data. */ BlzUncompress(GetVoidPointer(temp_address + binary_size)); } } } Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const { /* Get and validate addresses/sizes. */ const uintptr_t rx_address = m_kip_header.GetRxAddress(); const size_t rx_size = m_kip_header.GetRxSize(); const uintptr_t ro_address = m_kip_header.GetRoAddress(); const size_t ro_size = m_kip_header.GetRoSize(); const uintptr_t rw_address = m_kip_header.GetRwAddress(); const size_t rw_size = m_kip_header.GetRwSize(); const uintptr_t bss_address = m_kip_header.GetBssAddress(); const size_t bss_size = m_kip_header.GetBssSize(); R_UNLESS(util::IsAligned(rx_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(ro_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(rw_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(rx_address <= rx_address + util::AlignUp(rx_size, PageSize), svc::ResultInvalidAddress()); R_UNLESS(ro_address <= ro_address + util::AlignUp(ro_size, PageSize), svc::ResultInvalidAddress()); R_UNLESS(rw_address <= rw_address + util::AlignUp(rw_size, PageSize), svc::ResultInvalidAddress()); R_UNLESS(bss_address <= bss_address + util::AlignUp(bss_size, PageSize), svc::ResultInvalidAddress()); R_UNLESS(rx_address + util::AlignUp(rx_size, PageSize) <= ro_address, svc::ResultInvalidAddress()); R_UNLESS(ro_address + util::AlignUp(ro_size, PageSize) <= rw_address, svc::ResultInvalidAddress()); R_UNLESS(rw_address + rw_size <= bss_address, svc::ResultInvalidAddress()); /* Validate the address space. */ if (this->Is64BitAddressSpace()) { R_UNLESS(this->Is64Bit(), svc::ResultInvalidCombination()); } const uintptr_t start_address = rx_address; const uintptr_t end_address = bss_size > 0 ? bss_address + bss_size : rw_address + rw_size; MESOSPHERE_ABORT_UNLESS(start_address == 0); /* Default fields in parameter to zero. */ *out = {}; /* Set fields in parameter. */ out->code_address = 0; out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize; out->program_id = m_kip_header.GetProgramId(); out->version = m_kip_header.GetVersion(); out->flags = 0; out->reslimit = ams::svc::InvalidHandle; out->system_resource_num_pages = 0; /* Copy name field. */ m_kip_header.GetName(out->name, sizeof(out->name)); /* Apply other flags. */ if (this->Is64Bit()) { out->flags |= ams::svc::CreateProcessFlag_Is64Bit; } if (this->Is64BitAddressSpace()) { out->flags |= (GetTargetFirmware() >= TargetFirmware_2_0_0) ? ams::svc::CreateProcessFlag_AddressSpace64Bit : ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated; } else { out->flags |= ams::svc::CreateProcessFlag_AddressSpace32Bit; } if (enable_aslr) { out->flags |= ams::svc::CreateProcessFlag_EnableAslr; } /* All initial processes should disable device address space merge. */ out->flags |= ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge; /* Set and check code address. */ /* NOTE: Even though Nintendo passes a size to GetAddressSpaceStart at other call sites, they pass */ /* a number of pages here. Even though this is presumably only used for debug assertions, this is */ /* almost certainly a bug. */ using ASType = KAddressSpaceInfo::Type; const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall; const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type, out->code_num_pages); const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type); const uintptr_t map_end = map_start + map_size; out->code_address = map_start + start_address; MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize)); /* Apply ASLR, if needed. */ if (enable_aslr) { const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment); out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment; } R_SUCCEED(); } void KInitialProcessReader::Load(const KPageGroup &pg, KVirtualAddress data) const { /* Prepare to layout the data. */ const KVirtualAddress rx_data = data; const KVirtualAddress ro_data = rx_data + m_kip_header.GetRxCompressedSize(); const KVirtualAddress rw_data = ro_data + m_kip_header.GetRoCompressedSize(); const size_t rx_size = m_kip_header.GetRxSize(); const size_t ro_size = m_kip_header.GetRoSize(); const size_t rw_size = m_kip_header.GetRwSize(); /* If necessary, setup bss. */ if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size > 0) { /* Determine how many additional pages are needed for bss. */ const u64 rw_end = util::AlignUp<u64>(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize); const u64 bss_end = util::AlignUp<u64>(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize); if (rw_end != bss_end) { /* Find the pages corresponding to bss. */ size_t cur_offset = 0; size_t remaining_size = bss_end - rw_end; size_t bss_offset = rw_end - m_kip_header.GetRxAddress(); for (auto it = pg.begin(); it != pg.end() && remaining_size > 0; ++it) { /* Get the current size. */ const size_t cur_size = it->GetSize(); /* Determine if the offset is in range. */ const size_t rel_diff = bss_offset - cur_offset; const bool is_before = cur_offset <= bss_offset; cur_offset += cur_size; if (is_before && bss_offset < cur_offset) { /* It is, so clear the bss range. */ const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size); std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(it->GetAddress() + rel_diff)), 0, block_size); /* Advance. */ cur_offset = bss_offset + block_size; remaining_size -= block_size; bss_offset += block_size; } } } } /* Load .rwdata. */ LoadInitialProcessSegment(pg, m_kip_header.GetRwAddress() - m_kip_header.GetRxAddress(), rw_size, m_kip_header.GetRwCompressedSize(), rw_data, m_kip_header.IsRwCompressed()); /* Load .rodata. */ LoadInitialProcessSegment(pg, m_kip_header.GetRoAddress() - m_kip_header.GetRxAddress(), ro_size, m_kip_header.GetRoCompressedSize(), ro_data, m_kip_header.IsRoCompressed()); /* Load .text. */ LoadInitialProcessSegment(pg, m_kip_header.GetRxAddress() - m_kip_header.GetRxAddress(), rx_size, m_kip_header.GetRxCompressedSize(), rx_data, m_kip_header.IsRxCompressed()); } Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const { const size_t rx_size = m_kip_header.GetRxSize(); const size_t ro_size = m_kip_header.GetRoSize(); const size_t rw_size = m_kip_header.GetRwSize(); const size_t bss_size = m_kip_header.GetBssSize(); /* Set R-X pages. */ if (rx_size) { const uintptr_t start = m_kip_header.GetRxAddress() + params.code_address; R_TRY(page_table.SetProcessMemoryPermission(start, util::AlignUp(rx_size, PageSize), ams::svc::MemoryPermission_ReadExecute)); } /* Set R-- pages. */ if (ro_size) { const uintptr_t start = m_kip_header.GetRoAddress() + params.code_address; R_TRY(page_table.SetProcessMemoryPermission(start, util::AlignUp(ro_size, PageSize), ams::svc::MemoryPermission_Read)); } /* Set RW- pages. */ if (rw_size || bss_size) { const uintptr_t start = (rw_size ? m_kip_header.GetRwAddress() : m_kip_header.GetBssAddress()) + params.code_address; const uintptr_t end = (bss_size ? m_kip_header.GetBssAddress() + bss_size : m_kip_header.GetRwAddress() + rw_size) + params.code_address; R_TRY(page_table.SetProcessMemoryPermission(start, util::AlignUp(end - start, PageSize), ams::svc::MemoryPermission_ReadWrite)); } R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_interrupt_event.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KInterruptEvent::Initialize(int32_t interrupt_name, ams::svc::InterruptType type) { MESOSPHERE_ASSERT_THIS(); /* Verify the interrupt is defined and global. */ R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(interrupt_name), svc::ResultOutOfRange()); R_UNLESS(Kernel::GetInterruptManager().IsGlobal(interrupt_name), svc::ResultOutOfRange()); /* Set interrupt id. */ m_interrupt_id = interrupt_name; /* Set core id. */ m_core_id = GetCurrentCoreId(); /* Initialize readable event base. */ KReadableEvent::Initialize(nullptr); /* Bind ourselves as the handler for our interrupt id. */ R_TRY(Kernel::GetInterruptManager().BindHandler(this, m_interrupt_id, m_core_id, KInterruptController::PriorityLevel_High, true, type == ams::svc::InterruptType_Level)); /* Mark initialized. */ m_is_initialized = true; R_SUCCEED(); } void KInterruptEvent::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Unbind ourselves as the handler for our interrupt id. */ Kernel::GetInterruptManager().UnbindHandler(m_interrupt_id, m_core_id); /* Synchronize the unbind on all cores, before proceeding. */ KDpcManager::Sync(); /* Perform inherited finalization. */ KReadableEvent::Finalize(); } Result KInterruptEvent::Reset() { MESOSPHERE_ASSERT_THIS(); /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Clear the event. */ R_TRY(KReadableEvent::Reset()); /* Clear the interrupt. */ Kernel::GetInterruptManager().ClearInterrupt(m_interrupt_id, m_core_id); R_SUCCEED(); } KInterruptTask *KInterruptEvent::OnInterrupt(s32 interrupt_id) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_UNUSED(interrupt_id); return this; } void KInterruptEvent::DoTask() { MESOSPHERE_ASSERT_THIS(); /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Signal. */ this->Signal(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_interrupt_task_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KInterruptTaskManager::TaskQueue::Enqueue(KInterruptTask *task) { MESOSPHERE_ASSERT(task != m_head); MESOSPHERE_ASSERT(task != m_tail); MESOSPHERE_AUDIT(task->GetNextTask() == nullptr); /* Insert the task into the queue. */ if (m_tail != nullptr) { m_tail->SetNextTask(task); } else { m_head = task; } m_tail = task; /* Set the next task for auditing. */ #if defined (MESOSPHERE_BUILD_FOR_AUDITING) task->SetNextTask(GetDummyInterruptTask()); #endif } void KInterruptTaskManager::TaskQueue::Dequeue() { MESOSPHERE_ASSERT(m_head != nullptr); MESOSPHERE_ASSERT(m_tail != nullptr); MESOSPHERE_AUDIT(m_tail->GetNextTask() == GetDummyInterruptTask()); /* Pop the task from the front of the queue. */ KInterruptTask *old_head = m_head; if (m_head == m_tail) { m_head = nullptr; m_tail = nullptr; } else { m_head = m_head->GetNextTask(); } #if defined (MESOSPHERE_BUILD_FOR_AUDITING) old_head->SetNextTask(nullptr); #else AMS_UNUSED(old_head); #endif } void KInterruptTaskManager::EnqueueTask(KInterruptTask *task) { MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); /* Enqueue the task and signal the scheduler. */ m_task_queue.Enqueue(task); Kernel::GetScheduler().SetInterruptTaskRunnable(); } void KInterruptTaskManager::DoTasks() { /* Execute pending tasks. */ const s64 start_time = KHardwareTimer::GetTick(); for (KInterruptTask *task = m_task_queue.GetHead(); task != nullptr; task = m_task_queue.GetHead()) { /* Dequeue the task. */ m_task_queue.Dequeue(); /* Do the task with interrupts temporarily enabled. */ { KScopedInterruptEnable ei; task->DoTask(); } } const s64 end_time = KHardwareTimer::GetTick(); /* Increment the time we've spent executing. */ m_cpu_time += end_time - start_time; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_io_pool.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constinit KLightLock g_io_pool_lock; constinit bool g_pool_used[ams::svc::IoPoolType_Count]; struct IoRegionExtents { KPhysicalAddress address; size_t size; }; #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include "board/nintendo/nx/kern_k_io_pool.board.nintendo_nx.inc" #elif defined(AMS_SVC_IO_POOL_NOT_SUPPORTED) #include "kern_k_io_pool.unsupported.inc" #else #error "Unknown context for IoPoolType!" #endif constexpr bool IsValidIoRegionImpl(ams::svc::IoPoolType pool_type, KPhysicalAddress address, size_t size) { /* NOTE: It seems likely this depends on pool type, but this isn't confirmable as of now. */ MESOSPHERE_UNUSED(pool_type); /* Check if the address/size falls within any allowable extents. */ for (const auto &extents : g_io_region_extents) { if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) { return true; } } return false; } } bool KIoPool::IsValidIoPoolType(ams::svc::IoPoolType pool_type) { return IsValidIoPoolTypeImpl(pool_type); } Result KIoPool::Initialize(ams::svc::IoPoolType pool_type) { MESOSPHERE_ASSERT_THIS(); /* Register the pool type. */ { /* Lock the pool used table. */ KScopedLightLock lk(g_io_pool_lock); /* Check that the pool isn't already used. */ R_UNLESS(!g_pool_used[pool_type], svc::ResultBusy()); /* Set the pool as used. */ g_pool_used[pool_type] = true; } /* Set our fields. */ m_pool_type = pool_type; m_is_initialized = true; R_SUCCEED(); } void KIoPool::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Lock the pool used table. */ KScopedLightLock lk(g_io_pool_lock); /* Check that the pool is used. */ MESOSPHERE_ASSERT(g_pool_used[m_pool_type]); /* Set the pool as unused. */ g_pool_used[m_pool_type] = false; } Result KIoPool::AddIoRegion(KIoRegion *new_region) { MESOSPHERE_ASSERT_THIS(); /* Check that the region is allowed. */ R_UNLESS(IsValidIoRegionImpl(m_pool_type, new_region->GetAddress(), new_region->GetSize()), svc::ResultInvalidMemoryRegion()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that the desired range isn't already in our pool. */ { /* Get the lowest region with address >= the new region that's already in our tree. */ auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress()); if (lowest_after != m_io_region_tree.end()) { R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy()); } /* There is no region with address >= the new region already in our tree, but we also need to check */ /* for a region with address < the new region already in our tree. */ if (lowest_after != m_io_region_tree.begin()) { auto highest_before = --lowest_after; R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy()); } } /* Add the region to our pool. */ m_io_region_tree.insert(*new_region); R_SUCCEED(); } void KIoPool::RemoveIoRegion(KIoRegion *region) { MESOSPHERE_ASSERT_THIS(); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Remove the region from our tree. */ m_io_region_tree.erase(m_io_region_tree.iterator_to(*region)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_io_pool.unsupported.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ constexpr IoRegionExtents g_io_region_extents[4] = { { Null<KPhysicalAddress>, 0 }, { Null<KPhysicalAddress>, 0 }, { Null<KPhysicalAddress>, 0 }, { Null<KPhysicalAddress>, 0 }, }; constexpr bool IsValidIoPoolTypeImpl(ams::svc::IoPoolType pool_type) { MESOSPHERE_UNUSED(pool_type); return false; } ================================================ FILE: libraries/libmesosphere/source/kern_k_io_region.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KIoRegion::Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { MESOSPHERE_ASSERT_THIS(); /* Set fields. */ m_physical_address = phys_addr; m_size = size; m_mapping = mapping; m_permission = perm; m_pool = pool; m_is_mapped = false; /* Add ourselves to our pool. */ R_TRY(m_pool->AddIoRegion(this)); /* Open a reference to our pool. */ m_pool->Open(); /* Mark ourselves as initialized. */ m_is_initialized = true; R_SUCCEED(); } void KIoRegion::Finalize() { /* Remove ourselves from our pool. */ m_pool->RemoveIoRegion(this); /* Close our reference to our pool. */ m_pool->Close(); } Result KIoRegion::Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm) { MESOSPHERE_ASSERT_THIS(); /* Check that the desired perm is allowable. */ R_UNLESS((m_permission | map_perm) == m_permission, svc::ResultInvalidNewMemoryPermission()); /* Check that the size is correct. */ R_UNLESS(size == m_size, svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Check that we're not already mapped. */ R_UNLESS(!m_is_mapped, svc::ResultInvalidState()); /* Map ourselves. */ R_TRY(GetCurrentProcess().GetPageTable().MapIoRegion(address, m_physical_address, size, m_mapping, map_perm)); /* Add ourselves to the current process. */ GetCurrentProcess().AddIoRegion(this); /* Note that we're mapped. */ m_is_mapped = true; R_SUCCEED(); } Result KIoRegion::Unmap(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Check that the size is correct. */ R_UNLESS(size == m_size, svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Unmap ourselves. */ R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size, m_mapping)); /* Remove ourselves from the current process. */ GetCurrentProcess().RemoveIoRegion(this); /* Note that we're unmapped. */ m_is_mapped = false; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_light_client_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KLightClientSession::Destroy() { MESOSPHERE_ASSERT_THIS(); m_parent->OnClientClosed(); } void KLightClientSession::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); } Result KLightClientSession::SendSyncRequest(u32 *data) { MESOSPHERE_ASSERT_THIS(); /* Get the request thread. */ KThread *cur_thread = GetCurrentThreadPointer(); /* Set the light data. */ cur_thread->SetLightSessionData(data); /* Send the request. */ R_RETURN(m_parent->OnRequest(cur_thread)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_light_condition_variable.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { private: KThread::WaiterList *m_wait_list; bool m_allow_terminating_thread; public: constexpr ThreadQueueImplForKLightConditionVariable(KThread::WaiterList *wl, bool term) : KThreadQueue(), m_wait_list(wl), m_allow_terminating_thread(term) { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Only process waits if we're allowed to. */ if (svc::ResultTerminationRequested::Includes(wait_result) && m_allow_terminating_thread) { return; } /* Remove the thread from the waiting thread from the light condition variable. */ m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } void KLightConditionVariable::Wait(KLightLock *lock, s64 timeout, bool allow_terminating_thread) { /* Create thread queue. */ KThread *owner = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKLightConditionVariable wait_queue(std::addressof(m_wait_list), allow_terminating_thread); /* Sleep the thread. */ { KScopedSchedulerLockAndSleep lk(std::addressof(timer), owner, timeout); if (!allow_terminating_thread && owner->IsTerminationRequested()) { lk.CancelSleep(); return; } lock->Unlock(); /* Add the thread to the queue. */ m_wait_list.push_back(*owner); /* Begin waiting. */ wait_queue.SetHardwareTimer(timer); owner->BeginWait(std::addressof(wait_queue)); } /* Re-acquire the lock. */ lock->Lock(); } void KLightConditionVariable::Broadcast() { KScopedSchedulerLock lk; /* Signal all threads. */ for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it = m_wait_list.erase(it)) { it->EndWait(ResultSuccess()); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_light_lock.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class ThreadQueueImplForKLightLock final : public KThreadQueue { public: constexpr ThreadQueueImplForKLightLock() : KThreadQueue() { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Do nothing, waiting to acquire a light lock cannot be canceled. */ MESOSPHERE_UNUSED(waiting_thread, wait_result, cancel_timer_task); } }; } bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { KThread *cur_thread = reinterpret_cast<KThread *>(_cur_thread); ThreadQueueImplForKLightLock wait_queue; /* Pend the current thread waiting on the owner thread. */ { KScopedSchedulerLock sl; /* Ensure we actually have locking to do. */ if (m_tag.Load<std::memory_order_relaxed>() != _owner) { return false; } /* Add the current thread as a waiter on the owner. */ KThread *owner_thread = reinterpret_cast<KThread *>(_owner & ~1ul); cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(m_tag))); owner_thread->AddWaiter(cur_thread); /* Begin waiting to hold the lock. */ cur_thread->BeginWait(std::addressof(wait_queue)); if (owner_thread->IsSuspended()) { owner_thread->ContinueIfHasKernelWaiters(); } } return true; } void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { KThread *owner_thread = reinterpret_cast<KThread *>(_cur_thread); /* Unlock. */ { KScopedSchedulerLock sl; /* Get the next owner. */ bool has_waiters; KThread *next_owner = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag))); /* Pass the lock to the next owner. */ uintptr_t next_tag = 0; if (next_owner != nullptr) { next_tag = reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters); next_owner->EndWait(ResultSuccess()); if (next_owner->IsSuspended()) { next_owner->ContinueIfHasKernelWaiters(); } } /* We may have unsuspended in the process of acquiring the lock, so we'll re-suspend now if so. */ if (owner_thread->IsSuspended()) { owner_thread->TrySuspend(); } /* Write the new tag value. */ m_tag.Store<std::memory_order_release>(next_tag); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_light_server_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr u64 InvalidThreadId = -1ull; class ThreadQueueImplForKLightServerSessionRequest final : public KThreadQueue { private: KThread::WaiterList *m_wait_list; public: constexpr ThreadQueueImplForKLightServerSessionRequest(KThread::WaiterList *wl) : KThreadQueue(), m_wait_list(wl) { /* ... */ } virtual void EndWait(KThread *waiting_thread, Result wait_result) override { /* Remove the thread from our wait list. */ m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); /* Invoke the base end wait handler. */ KThreadQueue::EndWait(waiting_thread, wait_result); } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread from our wait list. */ m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; class ThreadQueueImplForKLightServerSessionReceive final : public KThreadQueue { private: KThread **m_server_thread; public: constexpr ThreadQueueImplForKLightServerSessionReceive(KThread **st) : KThreadQueue(), m_server_thread(st) { /* ... */ } virtual void EndWait(KThread *waiting_thread, Result wait_result) override { /* Clear the server thread. */ *m_server_thread = nullptr; /* Set the waiting thread as not cancelable. */ waiting_thread->ClearCancellable(); /* Invoke the base end wait handler. */ KThreadQueue::EndWait(waiting_thread, wait_result); } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Clear the server thread. */ *m_server_thread = nullptr; /* Set the waiting thread as not cancelable. */ waiting_thread->ClearCancellable(); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } void KLightServerSession::Destroy() { MESOSPHERE_ASSERT_THIS(); this->CleanupRequests(); m_parent->OnServerClosed(); } void KLightServerSession::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); this->CleanupRequests(); } Result KLightServerSession::OnRequest(KThread *request_thread) { MESOSPHERE_ASSERT_THIS(); ThreadQueueImplForKLightServerSessionRequest wait_queue(std::addressof(m_request_list)); /* Send the request. */ { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Check that the server isn't closed. */ R_UNLESS(!m_parent->IsServerClosed(), svc::ResultSessionClosed()); /* Check that the request thread isn't terminating. */ R_UNLESS(!request_thread->IsTerminationRequested(), svc::ResultTerminationRequested()); /* Add the request thread to our list. */ m_request_list.push_back(*request_thread); /* Begin waiting on the request. */ request_thread->BeginWait(std::addressof(wait_queue)); /* If we have a server thread, end its wait. */ if (m_server_thread != nullptr) { m_server_thread->EndWait(ResultSuccess()); } } /* NOTE: Nintendo returns GetCurrentThread().GetWaitResult() here. */ /* This is technically incorrect, although it doesn't cause problems in practice */ /* because this is only ever called with request_thread = GetCurrentThreadPointer(). */ R_RETURN(request_thread->GetWaitResult()); } Result KLightServerSession::ReplyAndReceive(u32 *data) { MESOSPHERE_ASSERT_THIS(); /* Set the server context. */ GetCurrentThread().SetLightSessionData(data); /* Reply, if we need to. */ if (data[0] & KLightSession::ReplyFlag) { KScopedSchedulerLock sl; /* Check that we're open. */ R_UNLESS(!m_parent->IsClientClosed(), svc::ResultSessionClosed()); R_UNLESS(!m_parent->IsServerClosed(), svc::ResultSessionClosed()); /* Check that we have a request to reply to. */ R_UNLESS(m_current_request != nullptr, svc::ResultInvalidState()); /* Check that the server thread id is correct. */ R_UNLESS(m_server_thread_id == GetCurrentThread().GetId(), svc::ResultInvalidState()); /* If we can reply, do so. */ if (!m_current_request->IsTerminationRequested()) { std::memcpy(m_current_request->GetLightSessionData(), GetCurrentThread().GetLightSessionData(), KLightSession::DataSize); m_current_request->EndWait(ResultSuccess()); } /* Close our current request. */ m_current_request->Close(); /* Clear our current request. */ m_current_request = nullptr; m_server_thread_id = InvalidThreadId; } /* Close any pending objects before we wait. */ GetCurrentThread().DestroyClosedObjects(); /* Create the wait queue for our receive. */ ThreadQueueImplForKLightServerSessionReceive wait_queue(std::addressof(m_server_thread)); /* Receive. */ while (true) { /* Try to receive a request. */ { KScopedSchedulerLock sl; /* Check that we aren't already receiving. */ R_UNLESS(m_server_thread == nullptr, svc::ResultInvalidState()); R_UNLESS(m_server_thread_id == InvalidThreadId, svc::ResultInvalidState()); /* Check that we're open. */ R_UNLESS(!m_parent->IsClientClosed(), svc::ResultSessionClosed()); R_UNLESS(!m_parent->IsServerClosed(), svc::ResultSessionClosed()); /* Check that we're not terminating. */ R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested()); /* If we have a request available, use it. */ if (auto head = m_request_list.begin(); head != m_request_list.end()) { /* Set our current request. */ m_current_request = std::addressof(*head); m_current_request->Open(); /* Set our server thread id. */ m_server_thread_id = GetCurrentThread().GetId(); /* Copy the client request data. */ std::memcpy(GetCurrentThread().GetLightSessionData(), m_current_request->GetLightSessionData(), KLightSession::DataSize); /* We successfully received. */ R_SUCCEED(); } /* We need to wait for a request to come in. */ /* Check if we were cancelled. */ if (GetCurrentThread().IsWaitCancelled()) { GetCurrentThread().ClearWaitCancelled(); R_THROW(svc::ResultCancelled()); } /* Mark ourselves as cancellable. */ GetCurrentThread().SetCancellable(); /* Wait for a request to come in. */ m_server_thread = GetCurrentThreadPointer(); GetCurrentThread().BeginWait(std::addressof(wait_queue)); } /* We waited to receive a request; if our wait failed, return the failing result. */ R_TRY(GetCurrentThread().GetWaitResult()); } } void KLightServerSession::CleanupRequests() { /* Cleanup all pending requests. */ { KScopedSchedulerLock sl; /* Handle the current request. */ if (m_current_request != nullptr) { /* Reply to the current request. */ if (!m_current_request->IsTerminationRequested()) { m_current_request->EndWait(svc::ResultSessionClosed()); } /* Clear our current request. */ m_current_request->Close(); m_current_request = nullptr; m_server_thread_id = InvalidThreadId; } /* Reply to all other requests. */ for (auto &thread : m_request_list) { thread.EndWait(svc::ResultSessionClosed()); } /* Wait up our server thread, if we have one. */ if (m_server_thread != nullptr) { m_server_thread->EndWait(svc::ResultSessionClosed()); } } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_light_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KLightSession::Initialize(KClientPort *client_port, uintptr_t name) { MESOSPHERE_ASSERT_THIS(); /* Increment reference count. */ /* Because reference count is one on creation, this will result */ /* in a reference count of two. Thus, when both server and client are closed */ /* this object will be destroyed. */ this->Open(); /* Create our sub sessions. */ KAutoObject::Create<KLightServerSession>(std::addressof(m_server)); KAutoObject::Create<KLightClientSession>(std::addressof(m_client)); /* Initialize our sub sessions. */ m_server.Initialize(this); m_client.Initialize(this); /* Set state and name. */ m_state = State::Normal; m_name = name; /* Set our owner process. */ m_process = GetCurrentProcessPointer(); m_process->Open(); /* Set our port. */ m_port = client_port; if (m_port != nullptr) { m_port->Open(); } /* Mark initialized. */ m_initialized = true; } void KLightSession::Finalize() { if (m_port != nullptr) { m_port->OnSessionFinalized(); m_port->Close(); } } void KLightSession::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); if (m_state == State::Normal) { m_state = State::ServerClosed; m_client.OnServerClosed(); } this->Close(); } void KLightSession::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); if (m_state == State::Normal) { m_state = State::ClientClosed; m_server.OnClientClosed(); } this->Close(); } void KLightSession::PostDestroy(uintptr_t arg) { /* Release the session count resource the owner process holds. */ KProcess *owner = reinterpret_cast<KProcess *>(arg); owner->ReleaseResource(ams::svc::LimitableResource_SessionCountMax, 1); owner->Close(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_memory_block_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = { {KMemoryState_Free , "----- Free -----"}, {KMemoryState_IoMemory , "IoMemory "}, {KMemoryState_IoRegister , "IoRegister "}, {KMemoryState_Static , "Static "}, {KMemoryState_Code , "Code "}, {KMemoryState_CodeData , "CodeData "}, {KMemoryState_Normal , "Normal "}, {KMemoryState_Shared , "Shared "}, {KMemoryState_AliasCode , "AliasCode "}, {KMemoryState_AliasCodeData , "AliasCodeData "}, {KMemoryState_Ipc , "Ipc "}, {KMemoryState_Stack , "Stack "}, {KMemoryState_ThreadLocal , "ThreadLocal "}, {KMemoryState_Transfered , "Transfered "}, {KMemoryState_SharedTransfered , "SharedTransfered"}, {KMemoryState_SharedCode , "SharedCode "}, {KMemoryState_Inaccessible , "Inaccessible "}, {KMemoryState_NonSecureIpc , "NonSecureIpc "}, {KMemoryState_NonDeviceIpc , "NonDeviceIpc "}, {KMemoryState_Kernel , "Kernel "}, {KMemoryState_GeneratedCode , "GeneratedCode "}, {KMemoryState_CodeOut , "CodeOut "}, {KMemoryState_Coverage , "Coverage "}, }; constexpr const char *GetMemoryStateName(KMemoryState state) { for (size_t i = 0; i < util::size(MemoryStateNames); i++) { if (std::get<0>(MemoryStateNames[i]) == state) { return std::get<1>(MemoryStateNames[i]); } } return "Unknown "; } constexpr const char *GetMemoryPermissionString(const KMemoryBlock &block) { if (block.GetState() == KMemoryState_Free) { return " "; } else { switch (block.GetPermission()) { case KMemoryPermission_UserReadExecute: return "r-x"; case KMemoryPermission_UserRead: return "r--"; case KMemoryPermission_UserReadWrite: return "rw-"; default: return "---"; } } } void DumpMemoryBlock(const KMemoryBlock &block) { const char *state = GetMemoryStateName(block.GetState()); const char *perm = GetMemoryPermissionString(block); const uintptr_t start = GetInteger(block.GetAddress()); const uintptr_t end = GetInteger(block.GetLastAddress()); const size_t kb = block.GetSize() / 1_KB; const char l = (block.GetAttribute() & KMemoryAttribute_Locked) ? 'L' : '-'; const char i = (block.GetAttribute() & KMemoryAttribute_IpcLocked) ? 'I' : '-'; const char d = (block.GetAttribute() & KMemoryAttribute_DeviceShared) ? 'D' : '-'; const char u = (block.GetAttribute() & KMemoryAttribute_Uncached) ? 'U' : '-'; MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, block.GetIpcLockCount(), block.GetDeviceUseCount()); } } Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, KMemoryBlockSlabManager *slab_manager) { /* Allocate a block to encapsulate the address space, insert it into the tree. */ KMemoryBlock *start_block = slab_manager->Allocate(); R_UNLESS(start_block != nullptr, svc::ResultOutOfResource()); /* Set our start and end. */ m_start_address = st; m_end_address = nd; MESOSPHERE_ASSERT(util::IsAligned(GetInteger(m_start_address), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(m_end_address), PageSize)); /* Initialize and insert the block. */ start_block->Initialize(m_start_address, (m_end_address - m_start_address) / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None); m_memory_block_tree.insert(*start_block); R_SUCCEED(); } void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager *slab_manager) { /* Erase every block until we have none left. */ auto it = m_memory_block_tree.begin(); while (it != m_memory_block_tree.end()) { KMemoryBlock *block = std::addressof(*it); it = m_memory_block_tree.erase(it); slab_manager->Free(block); } MESOSPHERE_ASSERT(m_memory_block_tree.empty()); } bool KMemoryBlockManager::GetRegionForFindFreeArea(KProcessAddress *out_start, KProcessAddress *out_end, KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) { /* Check that there's room for the pages in the specified region. */ if (num_pages + 2 * guard_pages > region_num_pages) { return false; } /* Determine the aligned start of the guarded region. */ const KProcessAddress guarded_start = region_start + guard_pages * PageSize; const KProcessAddress aligned_guarded_start = util::AlignDown(GetInteger(guarded_start), alignment); KProcessAddress aligned_guarded_start_with_offset = aligned_guarded_start + offset; if (guarded_start > aligned_guarded_start_with_offset) { if (!util::CanAddWithoutOverflow<uintptr_t>(GetInteger(aligned_guarded_start), alignment)) { return false; } aligned_guarded_start_with_offset += alignment; } /* Determine the aligned end of the guarded region. */ const KProcessAddress guarded_end = region_start + ((region_num_pages - (num_pages + guard_pages)) * PageSize); const KProcessAddress aligned_guarded_end = util::AlignDown(GetInteger(guarded_end), alignment); KProcessAddress aligned_guarded_end_with_offset = aligned_guarded_end + offset; if (aligned_guarded_end_with_offset > guarded_end) { if (aligned_guarded_end < alignment) { return false; } aligned_guarded_end_with_offset -= alignment; } /* Check that the extents are valid. */ if (aligned_guarded_end_with_offset < aligned_guarded_start_with_offset) { return false; } /* Set the output extents. */ *out_start = aligned_guarded_start_with_offset; *out_end = aligned_guarded_end_with_offset; return true; } KProcessAddress KMemoryBlockManager::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const { /* Determine the range to search in. */ KProcessAddress search_start = Null<KProcessAddress>; KProcessAddress search_end = Null<KProcessAddress>; if (this->GetRegionForFindFreeArea(std::addressof(search_start), std::addressof(search_end), region_start, region_num_pages, num_pages, alignment, offset, guard_pages)) { /* Iterate over blocks in the search space, looking for a suitable one. */ for (const_iterator it = this->FindIterator(search_start); it != m_memory_block_tree.cend(); it++) { /* If our block is past the end of our search space, we're done. */ if (search_end < it->GetAddress()) { break; } /* We only want to consider free blocks. */ if (it->GetState() != KMemoryState_Free) { continue; } /* Determine the candidate range. */ KProcessAddress candidate_start = Null<KProcessAddress>; KProcessAddress candidate_end = Null<KProcessAddress>; if (!this->GetRegionForFindFreeArea(std::addressof(candidate_start), std::addressof(candidate_end), it->GetAddress(), it->GetNumPages(), num_pages, alignment, offset, guard_pages)) { continue; } /* Try the suggested candidate (coercing into the search region if needed). */ KProcessAddress candidate = candidate_start; if (candidate < search_start) { candidate = search_start; } /* Check if the candidate is valid. */ if (candidate <= search_end && candidate <= candidate_end) { return candidate; } } } return Null<KProcessAddress>; } void KMemoryBlockManager::CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages) { /* Find the iterator now that we've updated. */ iterator it = this->FindIterator(address); if (address != m_start_address) { it--; } /* Coalesce blocks that we can. */ while (true) { iterator prev = it++; if (it == m_memory_block_tree.end()) { break; } if (prev->CanMergeWith(*it)) { KMemoryBlock *block = std::addressof(*it); m_memory_block_tree.erase(it); prev->Add(*block); allocator->Free(block); it = prev; } if (address + num_pages * PageSize < it->GetEndAddress()) { break; } } } void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr) { /* Ensure for auditing that we never end up with an invalid tree. */ KScopedMemoryBlockManagerAuditor auditor(this); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); MESOSPHERE_ASSERT((attr & (KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared)) == 0); KProcessAddress cur_address = address; size_t remaining_pages = num_pages; iterator it = this->FindIterator(address); while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; if (it->HasProperties(state, perm, attr)) { /* If we already have the right properties, just advance. */ if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; cur_address = it->GetEndAddress(); } } else { /* If we need to, create a new block before and insert it. */ if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); } /* Update block state. */ it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr); cur_address += it->GetSize(); remaining_pages -= it->GetNumPages(); } it++; } this->CoalesceForUpdate(allocator, address, num_pages); } void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr) { /* Ensure for auditing that we never end up with an invalid tree. */ KScopedMemoryBlockManagerAuditor auditor(this); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); MESOSPHERE_ASSERT((attr & (KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared)) == 0); KProcessAddress cur_address = address; size_t remaining_pages = num_pages; iterator it = this->FindIterator(address); while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; if (it->HasProperties(test_state, test_perm, test_attr) && !it->HasProperties(state, perm, attr)) { /* If we need to, create a new block before and insert it. */ if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); } /* Update block state. */ it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr); cur_address += it->GetSize(); remaining_pages -= it->GetNumPages(); } else { /* If we already have the right properties, just advance. */ if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; cur_address = it->GetEndAddress(); } } it++; } this->CoalesceForUpdate(allocator, address, num_pages); } void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm) { /* Ensure for auditing that we never end up with an invalid tree. */ KScopedMemoryBlockManagerAuditor auditor(this); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); KProcessAddress cur_address = address; size_t remaining_pages = num_pages; iterator it = this->FindIterator(address); const KProcessAddress end_address = address + (num_pages * PageSize); while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; /* If we need to, create a new block before and insert it. */ if (it->GetAddress() != cur_address) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; cur_address = it->GetAddress(); } if (it->GetSize() > remaining_size) { /* If we need to, create a new block after and insert it. */ KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); } /* Call the locked update function. */ (std::addressof(*it)->*lock_func)(perm, it->GetAddress() == address, it->GetEndAddress() == end_address); cur_address += it->GetSize(); remaining_pages -= it->GetNumPages(); it++; } this->CoalesceForUpdate(allocator, address, num_pages); } void KMemoryBlockManager::UpdateAttribute(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, u32 mask, u32 attr) { /* Ensure for auditing that we never end up with an invalid tree. */ KScopedMemoryBlockManagerAuditor auditor(this); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); KProcessAddress cur_address = address; size_t remaining_pages = num_pages; iterator it = this->FindIterator(address); while (remaining_pages > 0) { const size_t remaining_size = remaining_pages * PageSize; if ((it->GetAttribute() & mask) != attr) { /* If we need to, create a new block before and insert it. */ if (it->GetAddress() != GetInteger(cur_address)) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address); it = m_memory_block_tree.insert(*new_block); it++; cur_address = it->GetAddress(); } /* If we need to, create a new block after and insert it. */ if (it->GetSize() > remaining_size) { KMemoryBlock *new_block = allocator->Allocate(); it->Split(new_block, cur_address + remaining_size); it = m_memory_block_tree.insert(*new_block); } /* Update block state. */ it->UpdateAttribute(mask, attr); cur_address += it->GetSize(); remaining_pages -= it->GetNumPages(); } else { /* If we already have the right attributes, just advance. */ if (cur_address + remaining_size < it->GetEndAddress()) { remaining_pages = 0; cur_address += remaining_size; } else { remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize; cur_address = it->GetEndAddress(); } } it++; } this->CoalesceForUpdate(allocator, address, num_pages); } /* Debug. */ bool KMemoryBlockManager::CheckState() const { /* If we fail, we should dump blocks. */ auto dump_guard = SCOPE_GUARD { this->DumpBlocks(); }; /* Loop over every block, ensuring that we are sorted and coalesced. */ auto it = m_memory_block_tree.cbegin(); auto prev = it++; while (it != m_memory_block_tree.cend()) { /* Sequential blocks which can be merged should be merged. */ if (prev->CanMergeWith(*it)) { return false; } /* Sequential blocks should be sequential. */ if (prev->GetEndAddress() != it->GetAddress()) { return false; } /* If the block is ipc locked, it must have a count. */ if ((it->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && it->GetIpcLockCount() == 0) { return false; } /* If the block is device shared, it must have a count. */ if ((it->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && it->GetDeviceUseCount() == 0) { return false; } /* Advance the iterator. */ prev = it++; } /* Our loop will miss checking the last block, potentially, so check it. */ if (prev != m_memory_block_tree.cend()) { /* If the block is ipc locked, it must have a count. */ if ((prev->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && prev->GetIpcLockCount() == 0) { return false; } /* If the block is device shared, it must have a count. */ if ((prev->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && prev->GetDeviceUseCount() == 0) { return false; } } /* We're valid, so no need to print. */ dump_guard.Cancel(); return true; } void KMemoryBlockManager::DumpBlocks() const { /* Dump each block. */ for (const auto &block : m_memory_block_tree) { DumpMemoryBlock(block); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr size_t ReservedEarlyDramSize = 0x60000; constexpr size_t CarveoutAlignment = 0x20000; constexpr size_t CarveoutSizeMax = 512_MB - CarveoutAlignment; template<typename... T> requires (std::same_as<T, KMemoryRegionAttr> && ...) constexpr ALWAYS_INLINE KMemoryRegionType GetMemoryRegionType(KMemoryRegionType base, T... attr) { return util::FromUnderlying<KMemoryRegionType>(util::ToUnderlying(base) | (util::ToUnderlying<T>(attr) | ...)); } ALWAYS_INLINE bool SetupUartPhysicalMemoryRegion() { #if defined(MESOSPHERE_DEBUG_LOG_USE_UART) switch (KSystemControl::Init::GetDebugLogUartPort()) { case 0: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, GetMemoryRegionType(KMemoryRegionType_Uart, KMemoryRegionAttr_ShouldKernelMap)); case 1: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, GetMemoryRegionType(KMemoryRegionType_Uart, KMemoryRegionAttr_ShouldKernelMap)); case 2: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, GetMemoryRegionType(KMemoryRegionType_Uart, KMemoryRegionAttr_ShouldKernelMap)); case 3: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, GetMemoryRegionType(KMemoryRegionType_Uart, KMemoryRegionAttr_ShouldKernelMap)); default: return false; } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) return true; #else #error "Unknown Debug UART device!" #endif } ALWAYS_INLINE bool SetupPowerManagementControllerMemoryRegion() { /* For backwards compatibility, the PMC must remain mappable on < 2.0.0. */ const KMemoryRegionAttr rtc_restrict_attr = GetTargetFirmware() >= TargetFirmware_2_0_0 ? KMemoryRegionAttr_NoUserMap : static_cast<KMemoryRegionAttr>(0); const KMemoryRegionAttr pmc_restrict_attr = GetTargetFirmware() >= TargetFirmware_2_0_0 ? KMemoryRegionAttr_NoUserMap : KMemoryRegionAttr_ShouldKernelMap; return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E000, 0x400, GetMemoryRegionType(KMemoryRegionType_None, rtc_restrict_attr)) && KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7000E400, 0xC00, GetMemoryRegionType(KMemoryRegionType_PowerManagementController, pmc_restrict_attr)); } void InsertPoolPartitionRegionIntoBothTrees(size_t start, size_t size, KMemoryRegionType phys_type, KMemoryRegionType virt_type, u32 &cur_attr) { const u32 attr = cur_attr++; MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(start, size, phys_type, attr)); const KMemoryRegion *phys = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(phys_type, attr); MESOSPHERE_INIT_ABORT_UNLESS(phys != nullptr); MESOSPHERE_INIT_ABORT_UNLESS(phys->GetEndAddress() != 0); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size, virt_type, attr)); } } namespace init { void SetupDevicePhysicalMemoryRegions() { /* TODO: Give these constexpr defines somewhere? */ MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); MESOSPHERE_INIT_ABORT_UNLESS(SetupPowerManagementControllerMemoryRegion()); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, GetMemoryRegionType(KMemoryRegionType_MemoryController, KMemoryRegionAttr_NoUserMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, GetMemoryRegionType(KMemoryRegionType_MemoryController0, KMemoryRegionAttr_NoUserMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, GetMemoryRegionType(KMemoryRegionType_MemoryController1, KMemoryRegionAttr_NoUserMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, GetMemoryRegionType(KMemoryRegionType_None, KMemoryRegionAttr_NoUserMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, GetMemoryRegionType(KMemoryRegionType_InterruptDistributor, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, GetMemoryRegionType(KMemoryRegionType_InterruptCpuInterface, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, GetMemoryRegionType(KMemoryRegionType_None, KMemoryRegionAttr_NoUserMap))); /* Map IRAM unconditionally, to support debug-logging-to-iram build config. */ MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x40000000, 0x40000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsIram, KMemoryRegionAttr_ShouldKernelMap))); if (GetTargetFirmware() >= TargetFirmware_2_0_0) { /* Prevent mapping the bpmp exception vectors or the ipatch region. */ MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, GetMemoryRegionType(KMemoryRegionType_None, KMemoryRegionAttr_NoUserMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, GetMemoryRegionType(KMemoryRegionType_None, KMemoryRegionAttr_NoUserMap))); } else { /* Map devices required for legacy lps driver. */ MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsExceptionVectors, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60007000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsFlowController, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60004000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsPrimaryICtlr, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60001000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsSemaphore, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70016000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsAtomics, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60006000, 0x1000, GetMemoryRegionType(KMemoryRegionType_LegacyLpsClkRst, KMemoryRegionAttr_ShouldKernelMap))); } } void SetupDramPhysicalMemoryRegions() { const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(ams::kern::MainMemoryAddress); /* Insert blocks into the tree. */ MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); } void SetupPoolPartitionMemoryRegions() { /* Start by identifying the extents of the DRAM memory region. */ const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents(); MESOSPHERE_INIT_ABORT_UNLESS(dram_extents.GetEndAddress() != 0); /* Find the pool partitions region. */ const KMemoryRegion *pool_partitions_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(KMemoryRegionType_DramPoolPartition, 0); MESOSPHERE_INIT_ABORT_UNLESS(pool_partitions_region != nullptr); const uintptr_t pool_partitions_start = pool_partitions_region->GetAddress(); /* Determine the end of the pool region. */ const uintptr_t pool_end = pool_partitions_region->GetEndAddress(); MESOSPHERE_INIT_ABORT_UNLESS(pool_end == dram_extents.GetEndAddress()); /* Find the start of the kernel DRAM region. */ const KMemoryRegion *kernel_dram_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramKernelBase); MESOSPHERE_INIT_ABORT_UNLESS(kernel_dram_region != nullptr); const uintptr_t kernel_dram_start = kernel_dram_region->GetAddress(); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(kernel_dram_start, CarveoutAlignment)); /* Setup the pool partition layouts. */ if (GetTargetFirmware() >= TargetFirmware_5_0_0) { /* On 5.0.0+, setup modern 4-pool-partition layout. */ /* Get Application and Applet pool sizes. */ const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize(); const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize(); const size_t unsafe_system_pool_min_size = KSystemControl::Init::GetMinimumNonSecureSystemPoolSize(); /* Decide on starting addresses for our pools. */ const uintptr_t application_pool_start = pool_end - application_pool_size; const uintptr_t applet_pool_start = application_pool_start - applet_pool_size; const uintptr_t unsafe_system_pool_start = std::min(kernel_dram_start + CarveoutSizeMax, util::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment)); const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start; /* We want to arrange application pool depending on where the middle of dram is. */ const uintptr_t dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2; u32 cur_pool_attr = 0; size_t total_overhead_size = 0; if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) { InsertPoolPartitionRegionIntoBothTrees(application_pool_start, application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(application_pool_size); } else { const size_t first_application_pool_size = dram_midpoint - application_pool_start; const size_t second_application_pool_size = application_pool_start + application_pool_size - dram_midpoint; InsertPoolPartitionRegionIntoBothTrees(application_pool_start, first_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); InsertPoolPartitionRegionIntoBothTrees(dram_midpoint, second_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size); } /* Insert the applet pool. */ InsertPoolPartitionRegionIntoBothTrees(applet_pool_start, applet_pool_size, KMemoryRegionType_DramAppletPool, KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size); /* Insert the nonsecure system pool. */ InsertPoolPartitionRegionIntoBothTrees(unsafe_system_pool_start, unsafe_system_pool_size, KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size); /* Determine final total overhead size. */ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize((unsafe_system_pool_start - pool_partitions_start) - total_overhead_size); /* NOTE: Nintendo's kernel has layout [System, Management] but we have [Management, System]. This ensures the four UserPool regions are contiguous. */ /* Insert the system pool. */ const uintptr_t system_pool_start = pool_partitions_start + total_overhead_size; const size_t system_pool_size = unsafe_system_pool_start - system_pool_start; InsertPoolPartitionRegionIntoBothTrees(system_pool_start, system_pool_size, KMemoryRegionType_DramSystemPool, KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr); /* Insert the pool management region. */ const uintptr_t pool_management_start = pool_partitions_start; const size_t pool_management_size = total_overhead_size; u32 pool_management_attr = 0; InsertPoolPartitionRegionIntoBothTrees(pool_management_start, pool_management_size, KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement, pool_management_attr); } else { /* On < 5.0.0, setup a legacy 2-pool layout for backwards compatibility. */ static_assert(KMemoryManager::Pool_Count == 4); static_assert(KMemoryManager::Pool_Unsafe == KMemoryManager::Pool_Application); static_assert(KMemoryManager::Pool_Secure == KMemoryManager::Pool_System); /* Get Secure pool size. */ const size_t secure_pool_size = [](auto target_firmware) ALWAYS_INLINE_LAMBDA -> size_t { constexpr size_t LegacySecureKernelSize = 8_MB; /* KPageBuffer pages, other small kernel allocations. */ constexpr size_t LegacySecureMiscSize = 1_MB; /* Miscellaneous pages for secure process mapping. */ constexpr size_t LegacySecureHeapSize = 24_MB; /* Heap pages for secure process mapping (fs). */ constexpr size_t LegacySecureEsSize = 1_MB + 232_KB; /* Size for additional secure process (es, 4.0.0+). */ /* The baseline size for the secure region is enough to cover any allocations the kernel might make. */ size_t size = LegacySecureKernelSize; /* If on 2.0.0+, initial processes will fall within the secure region. */ if (target_firmware >= TargetFirmware_2_0_0) { /* Account for memory used directly for the processes. */ size += GetInitialProcessesSecureMemorySize(); /* Account for heap and transient memory used by the processes. */ size += LegacySecureHeapSize + LegacySecureMiscSize; } /* If on 4.0.0+, any process may use secure memory via a create process flag. */ /* In process this is used for es alone, and the secure pool's size should be */ /* increased to accommodate es's binary. */ if (target_firmware >= TargetFirmware_4_0_0) { size += LegacySecureEsSize; } return size; }(GetTargetFirmware()); /* Calculate the overhead for the secure and (defunct) applet/non-secure-system pools. */ size_t total_overhead_size = KMemoryManager::CalculateManagementOverheadSize(secure_pool_size); /* Calculate the overhead for (an amount larger than) the unsafe pool. */ const size_t approximate_total_overhead_size = total_overhead_size + KMemoryManager::CalculateManagementOverheadSize((pool_end - pool_partitions_start) - secure_pool_size - total_overhead_size) + 2 * PageSize; /* Determine the start of the unsafe region. */ const uintptr_t unsafe_memory_start = util::AlignUp(pool_partitions_start + secure_pool_size + approximate_total_overhead_size, CarveoutAlignment); /* Determine the start of the pool regions. */ const uintptr_t application_pool_start = unsafe_memory_start; /* Determine the pool sizes. */ const size_t application_pool_size = pool_end - application_pool_start; /* We want to arrange application pool depending on where the middle of dram is. */ const uintptr_t dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2; u32 cur_pool_attr = 0; if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) { InsertPoolPartitionRegionIntoBothTrees(application_pool_start, application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(application_pool_size); } else { const size_t first_application_pool_size = dram_midpoint - application_pool_start; const size_t second_application_pool_size = application_pool_start + application_pool_size - dram_midpoint; InsertPoolPartitionRegionIntoBothTrees(application_pool_start, first_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); InsertPoolPartitionRegionIntoBothTrees(dram_midpoint, second_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size); } /* Validate the true overhead size. */ MESOSPHERE_INIT_ABORT_UNLESS(total_overhead_size <= approximate_total_overhead_size); /* NOTE: Nintendo's kernel has layout [System, Management] but we have [Management, System]. This ensures the UserPool regions are contiguous. */ /* Insert the secure pool. */ const uintptr_t secure_pool_start = unsafe_memory_start - secure_pool_size; InsertPoolPartitionRegionIntoBothTrees(secure_pool_start, secure_pool_size, KMemoryRegionType_DramSystemPool, KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr); /* Insert the pool management region. */ const uintptr_t pool_management_start = pool_partitions_start; const size_t pool_management_size = secure_pool_start - pool_management_start; MESOSPHERE_INIT_ABORT_UNLESS(total_overhead_size <= pool_management_size); u32 pool_management_attr = 0; InsertPoolPartitionRegionIntoBothTrees(pool_management_start, pool_management_size, KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement, pool_management_attr); } } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_memory_layout.board.qemu_virt.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr size_t ReservedEarlyDramSize = 0x00080000; template<typename... T> requires (std::same_as<T, KMemoryRegionAttr> && ...) constexpr ALWAYS_INLINE KMemoryRegionType GetMemoryRegionType(KMemoryRegionType base, T... attr) { return util::FromUnderlying<KMemoryRegionType>(util::ToUnderlying(base) | (util::ToUnderlying<T>(attr) | ...)); } void InsertPoolPartitionRegionIntoBothTrees(size_t start, size_t size, KMemoryRegionType phys_type, KMemoryRegionType virt_type, u32 &cur_attr) { const u32 attr = cur_attr++; MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(start, size, phys_type, attr)); const KMemoryRegion *phys = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(phys_type, attr); MESOSPHERE_INIT_ABORT_UNLESS(phys != nullptr); MESOSPHERE_INIT_ABORT_UNLESS(phys->GetEndAddress() != 0); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size, virt_type, attr)); } } namespace init { void SetupDevicePhysicalMemoryRegions() { MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x08000000, 0x10000, GetMemoryRegionType(KMemoryRegionType_InterruptDistributor, KMemoryRegionAttr_ShouldKernelMap))); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x08010000, 0x10000, GetMemoryRegionType(KMemoryRegionType_InterruptCpuInterface, KMemoryRegionAttr_ShouldKernelMap))); } void SetupDramPhysicalMemoryRegions() { const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize(); const KPhysicalAddress physical_memory_base_address = KSystemControl::Init::GetKernelPhysicalBaseAddress(ams::kern::MainMemoryAddress); /* Insert blocks into the tree. */ MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram)); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(GetInteger(physical_memory_base_address), ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly)); } void SetupPoolPartitionMemoryRegions() { /* Start by identifying the extents of the DRAM memory region. */ const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents(); MESOSPHERE_INIT_ABORT_UNLESS(dram_extents.GetEndAddress() != 0); /* Find the pool partitions region. */ const KMemoryRegion *pool_partitions_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(KMemoryRegionType_DramPoolPartition, 0); MESOSPHERE_INIT_ABORT_UNLESS(pool_partitions_region != nullptr); const uintptr_t pool_partitions_start = pool_partitions_region->GetAddress(); /* Determine the end of the pool region. */ const uintptr_t pool_end = pool_partitions_region->GetEndAddress(); MESOSPHERE_INIT_ABORT_UNLESS(pool_end == dram_extents.GetEndAddress()); /* Find the start of the kernel DRAM region. */ const KMemoryRegion *kernel_dram_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramKernelBase); MESOSPHERE_INIT_ABORT_UNLESS(kernel_dram_region != nullptr); /* Setup the pool partition layouts. */ /* Get Application and Applet pool sizes. */ const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize(); const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize(); const size_t unsafe_system_pool_min_size = KSystemControl::Init::GetMinimumNonSecureSystemPoolSize(); /* Decide on starting addresses for our pools. */ const uintptr_t application_pool_start = pool_end - application_pool_size; const uintptr_t applet_pool_start = application_pool_start - applet_pool_size; const uintptr_t unsafe_system_pool_start = util::AlignDown(applet_pool_start - unsafe_system_pool_min_size, PageSize); const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start; /* We want to arrange application pool depending on where the middle of dram is. */ const uintptr_t dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2; u32 cur_pool_attr = 0; size_t total_overhead_size = 0; /* Insert the application pool. */ if (application_pool_size > 0) { if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) { InsertPoolPartitionRegionIntoBothTrees(application_pool_start, application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(application_pool_size); } else { const size_t first_application_pool_size = dram_midpoint - application_pool_start; const size_t second_application_pool_size = application_pool_start + application_pool_size - dram_midpoint; InsertPoolPartitionRegionIntoBothTrees(application_pool_start, first_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); InsertPoolPartitionRegionIntoBothTrees(dram_midpoint, second_application_pool_size, KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size); } } /* Insert the applet pool. */ if (applet_pool_size > 0) { InsertPoolPartitionRegionIntoBothTrees(applet_pool_start, applet_pool_size, KMemoryRegionType_DramAppletPool, KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size); } /* Insert the nonsecure system pool. */ if (unsafe_system_pool_size > 0) { InsertPoolPartitionRegionIntoBothTrees(unsafe_system_pool_start, unsafe_system_pool_size, KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool, cur_pool_attr); total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size); } /* Determine final total overhead size. */ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize((unsafe_system_pool_start - pool_partitions_start) - total_overhead_size); /* NOTE: Nintendo's kernel has layout [System, Management] but we have [Management, System]. This ensures the four UserPool regions are contiguous. */ /* Insert the system pool. */ const uintptr_t system_pool_start = pool_partitions_start + total_overhead_size; const size_t system_pool_size = unsafe_system_pool_start - system_pool_start; InsertPoolPartitionRegionIntoBothTrees(system_pool_start, system_pool_size, KMemoryRegionType_DramSystemPool, KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr); /* Insert the pool management region. */ const uintptr_t pool_management_start = pool_partitions_start; const size_t pool_management_size = total_overhead_size; u32 pool_management_attr = 0; InsertPoolPartitionRegionIntoBothTrees(pool_management_start, pool_management_size, KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement, pool_management_attr); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_memory_layout.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class KMemoryRegionAllocator { NON_COPYABLE(KMemoryRegionAllocator); NON_MOVEABLE(KMemoryRegionAllocator); public: static constexpr size_t MaxMemoryRegions = 200; private: KMemoryRegion m_region_heap[MaxMemoryRegions]; size_t m_num_regions; public: constexpr ALWAYS_INLINE KMemoryRegionAllocator() : m_region_heap(), m_num_regions() { /* ... */ } public: template<typename... Args> ALWAYS_INLINE KMemoryRegion *Allocate(Args&&... args) { /* Ensure we stay within the bounds of our heap. */ MESOSPHERE_INIT_ABORT_UNLESS(m_num_regions < MaxMemoryRegions); /* Create the new region. */ KMemoryRegion *region = std::addressof(m_region_heap[m_num_regions++]); std::construct_at(region, std::forward<Args>(args)...); return region; } }; constinit KMemoryRegionAllocator g_memory_region_allocator; template<typename... Args> ALWAYS_INLINE KMemoryRegion *AllocateRegion(Args&&... args) { return g_memory_region_allocator.Allocate(std::forward<Args>(args)...); } } void KMemoryRegionTree::InsertDirectly(uintptr_t address, uintptr_t last_address, u32 attr, u32 type_id) { this->insert(*AllocateRegion(address, last_address, attr, type_id)); } bool KMemoryRegionTree::Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) { /* Locate the memory region that contains the address. */ KMemoryRegion *found = this->FindModifiable(address); /* We require that the old attr is correct. */ if (found->GetAttributes() != old_attr) { return false; } /* We further require that the region can be split from the old region. */ const uintptr_t inserted_region_end = address + size; const uintptr_t inserted_region_last = inserted_region_end - 1; if (found->GetLastAddress() < inserted_region_last) { return false; } /* Further, we require that the type id is a valid transformation. */ if (!found->CanDerive(type_id)) { return false; } /* Cache information from the region before we remove it. */ const uintptr_t old_address = found->GetAddress(); const uintptr_t old_last = found->GetLastAddress(); const uintptr_t old_pair = found->GetPairAddress(); const u32 old_type = found->GetType(); /* Erase the existing region from the tree. */ this->erase(this->iterator_to(*found)); /* Insert the new region into the tree. */ if (old_address == address) { /* Reuse the old object for the new region, if we can. */ found->Reset(address, inserted_region_last, old_pair, new_attr, type_id); this->insert(*found); } else { /* If we can't re-use, adjust the old region. */ found->Reset(old_address, address - 1, old_pair, old_attr, old_type); this->insert(*found); /* Insert a new region for the split. */ const uintptr_t new_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (address - old_address) : old_pair; this->insert(*AllocateRegion(address, inserted_region_last, new_pair, new_attr, type_id)); } /* If we need to insert a region after the region, do so. */ if (old_last != inserted_region_last) { const uintptr_t after_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (inserted_region_end - old_address) : old_pair; this->insert(*AllocateRegion(inserted_region_end, old_last, after_pair, old_attr, old_type)); } return true; } void KMemoryLayout::InitializeLinearMemoryRegionTrees() { /* Initialize linear trees. */ for (auto ®ion : GetPhysicalMemoryRegionTree()) { if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) { GetPhysicalLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetLastAddress(), region.GetAttributes(), region.GetType()); } } for (auto ®ion : GetVirtualMemoryRegionTree()) { if (region.IsDerivedFrom(KMemoryRegionType_Dram)) { GetVirtualLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetLastAddress(), region.GetAttributes(), region.GetType()); } } } size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) { return KernelResourceSize + KSystemControl::SecureAppletMemorySize + (use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_memory_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) { if ((type | KMemoryRegionType_DramApplicationPool) == type) { return KMemoryManager::Pool_Application; } else if ((type | KMemoryRegionType_DramAppletPool) == type) { return KMemoryManager::Pool_Applet; } else if ((type | KMemoryRegionType_DramSystemPool) == type) { return KMemoryManager::Pool_System; } else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) { return KMemoryManager::Pool_SystemNonSecure; } else { MESOSPHERE_PANIC("InvalidMemoryRegionType for conversion to Pool"); } } } void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size, const u32 *min_align_shifts) { /* Clear the management region to zero. */ const KVirtualAddress management_region_end = management_region + management_region_size; std::memset(GetVoidPointer(management_region), 0, management_region_size); /* Reset our manager count. */ m_num_managers = 0; /* Traverse the virtual memory layout tree, initializing each manager as appropriate. */ while (m_num_managers != MaxManagerCount) { /* Locate the region that should initialize the current manager. */ KPhysicalAddress region_address = Null<KPhysicalAddress>; size_t region_size = 0; Pool region_pool = Pool_Count; for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) { /* We only care about regions that we need to create managers for. */ if (!it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) { continue; } /* We want to initialize the managers in order. */ if (it.GetAttributes() != m_num_managers) { continue; } const KPhysicalAddress cur_start = it.GetAddress(); const KPhysicalAddress cur_end = it.GetEndAddress(); /* Validate the region. */ MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>); MESOSPHERE_ASSERT(cur_start != Null<KPhysicalAddress>); MESOSPHERE_ASSERT(it.GetSize() > 0); /* Update the region's extents. */ if (region_address == Null<KPhysicalAddress>) { region_address = cur_start; region_size = it.GetSize(); region_pool = GetPoolFromMemoryRegionType(it.GetType()); } else { MESOSPHERE_ASSERT(cur_start == region_address + region_size); /* Update the size. */ region_size = cur_end - region_address; MESOSPHERE_ABORT_UNLESS(GetPoolFromMemoryRegionType(it.GetType()) == region_pool); } } /* If we didn't find a region, we're done. */ if (region_size == 0) { break; } /* Initialize a new manager for the region. */ Impl *manager = std::addressof(m_managers[m_num_managers++]); MESOSPHERE_ABORT_UNLESS(m_num_managers <= util::size(m_managers)); const size_t cur_size = manager->Initialize(region_address, region_size, management_region, management_region_end, region_pool); management_region += cur_size; MESOSPHERE_ABORT_UNLESS(management_region <= management_region_end); /* Insert the manager into the pool list. */ if (m_pool_managers_tail[region_pool] == nullptr) { m_pool_managers_head[region_pool] = manager; } else { m_pool_managers_tail[region_pool]->SetNext(manager); manager->SetPrev(m_pool_managers_tail[region_pool]); } m_pool_managers_tail[region_pool] = manager; } /* Free each region to its corresponding heap. */ size_t reserved_sizes[MaxManagerCount] = {}; const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress(); const size_t ini_size = GetInitialProcessBinarySize(); const KPhysicalAddress ini_end = ini_start + ini_size; const KPhysicalAddress ini_last = ini_end - 1; for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) { if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) { /* Get the manager for the region. */ auto &manager = m_managers[it.GetAttributes()]; const KPhysicalAddress cur_start = it.GetAddress(); const KPhysicalAddress cur_last = it.GetLastAddress(); const KPhysicalAddress cur_end = it.GetEndAddress(); if (cur_start <= ini_start && ini_last <= cur_last) { /* Free memory before the ini to the heap. */ if (cur_start != ini_start) { manager.Free(cur_start, (ini_start - cur_start) / PageSize); } /* Open/reserve the ini memory. */ manager.OpenFirst(ini_start, ini_size / PageSize); reserved_sizes[it.GetAttributes()] += ini_size; /* Free memory after the ini to the heap. */ if (ini_last != cur_last) { MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>); manager.Free(ini_end, (cur_end - ini_end) / PageSize); } } else { /* Ensure there's no partial overlap with the ini image. */ if (cur_start <= ini_last) { MESOSPHERE_ABORT_UNLESS(cur_last < ini_start); } else { /* Otherwise, check the region for general validity. */ MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>); } /* Free the memory to the heap. */ manager.Free(cur_start, it.GetSize() / PageSize); } } } /* Update the used size for all managers. */ for (size_t i = 0; i < m_num_managers; ++i) { m_managers[i].SetInitialUsedHeapSize(reserved_sizes[i]); } /* Determine the min heap size for all pools. */ for (size_t i = 0; i < Pool_Count; ++i) { /* Determine the min alignment for the pool in pages. */ const size_t min_align_pages = 1 << min_align_shifts[i]; /* Determine a heap index. */ if (const auto heap_index = KPageHeap::GetAlignedBlockIndex(min_align_pages, min_align_pages); heap_index >= 0) { m_min_heap_indexes[i] = heap_index; } } } Result KMemoryManager::InitializeOptimizedMemory(u64 process_id, Pool pool) { /* Lock the pool. */ KScopedLightLock lk(m_pool_locks[pool]); /* Check that we don't already have an optimized process. */ R_UNLESS(!m_has_optimized_process[pool], svc::ResultBusy()); /* Set the optimized process id. */ m_optimized_process_ids[pool] = process_id; m_has_optimized_process[pool] = true; /* Clear the management area for the optimized process. */ for (auto *manager = this->GetFirstManager(pool, Direction_FromFront); manager != nullptr; manager = this->GetNextManager(manager, Direction_FromFront)) { manager->InitializeOptimizedMemory(); } R_SUCCEED(); } void KMemoryManager::FinalizeOptimizedMemory(u64 process_id, Pool pool) { /* Lock the pool. */ KScopedLightLock lk(m_pool_locks[pool]); /* If the process was optimized, clear it. */ if (m_has_optimized_process[pool] && m_optimized_process_ids[pool] == process_id) { m_has_optimized_process[pool] = false; } } KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option) { /* Early return if we're allocating no pages. */ if (num_pages == 0) { return Null<KPhysicalAddress>; } /* Determine the pool and direction we're allocating from. */ const auto [pool, dir] = DecodeOption(option); /* Check that we're allocating a correctly aligned number of pages. */ const size_t min_align_pages = KPageHeap::GetBlockNumPages(m_min_heap_indexes[pool]); if (!util::IsAligned(num_pages, min_align_pages)) { return Null<KPhysicalAddress>; } /* Update our alignment. */ align_pages = std::max(align_pages, min_align_pages); /* Lock the pool that we're allocating from. */ KScopedLightLock lk(m_pool_locks[pool]); /* Choose a heap based on our page size request. */ const s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, align_pages); /* Loop, trying to iterate from each block. */ Impl *chosen_manager = nullptr; KPhysicalAddress allocated_block = Null<KPhysicalAddress>; for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr; chosen_manager = this->GetNextManager(chosen_manager, dir)) { allocated_block = chosen_manager->AllocateAligned(heap_index, num_pages, align_pages); if (allocated_block != Null<KPhysicalAddress>) { break; } } /* If we failed to allocate, quit now. */ if (allocated_block == Null<KPhysicalAddress>) { return Null<KPhysicalAddress>; } /* Maintain the optimized memory bitmap, if we should. */ if (m_has_optimized_process[pool]) { chosen_manager->TrackUnoptimizedAllocation(allocated_block, num_pages); } /* Open the first reference to the pages. */ chosen_manager->OpenFirst(allocated_block, num_pages); return allocated_block; } Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index) { /* Check that we're allocating a correctly aligned number of pages. */ const size_t min_align_pages = KPageHeap::GetBlockNumPages(m_min_heap_indexes[pool]); R_UNLESS(util::IsAligned(num_pages, min_align_pages), svc::ResultInvalidSize()); /* Adjust our min heap index to the pool minimum if needed. */ min_heap_index = std::max(min_heap_index, m_min_heap_indexes[pool]); /* Choose a heap based on our page size request. */ const s32 heap_index = KPageHeap::GetBlockIndex(num_pages); R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory()); /* Ensure that we don't leave anything un-freed. */ ON_RESULT_FAILURE { for (const auto &it : *out) { auto &manager = this->GetManager(it.GetAddress()); const size_t num_pages = std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); manager.Free(it.GetAddress(), num_pages); } out->Finalize(); }; /* Keep allocating until we've allocated all our pages. */ for (s32 index = heap_index; index >= min_heap_index && num_pages > 0; index--) { const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index); for (Impl *cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; cur_manager = this->GetNextManager(cur_manager, dir)) { while (num_pages >= pages_per_alloc) { /* Allocate a block. */ KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random); if (allocated_block == Null<KPhysicalAddress>) { break; } /* Ensure we don't leak the block if we fail. */ ON_RESULT_FAILURE { cur_manager->Free(allocated_block, pages_per_alloc); }; /* Add the block to our group. */ R_TRY(out->AddBlock(allocated_block, pages_per_alloc)); /* Maintain the optimized memory bitmap, if we should. */ if (unoptimized) { cur_manager->TrackUnoptimizedAllocation(allocated_block, pages_per_alloc); } num_pages -= pages_per_alloc; } } } /* Only succeed if we allocated as many pages as we wanted. */ R_UNLESS(num_pages == 0, svc::ResultOutOfMemory()); /* We succeeded! */ R_SUCCEED(); } Result KMemoryManager::AllocateAndOpen(KPageGroup *out, size_t num_pages, size_t align_pages, u32 option) { MESOSPHERE_ASSERT(out != nullptr); MESOSPHERE_ASSERT(out->GetNumPages() == 0); /* Early return if we're allocating no pages. */ R_SUCCEED_IF(num_pages == 0); /* Lock the pool that we're allocating from. */ const auto [pool, dir] = DecodeOption(option); KScopedLightLock lk(m_pool_locks[pool]); /* Choose a heap based on our alignment size request. */ const s32 heap_index = KPageHeap::GetAlignedBlockIndex(align_pages, align_pages); /* Allocate the page group. */ R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, m_has_optimized_process[pool], true, heap_index)); /* Open the first reference to the pages. */ for (const auto &block : *out) { KPhysicalAddress cur_address = block.GetAddress(); size_t remaining_pages = block.GetNumPages(); while (remaining_pages > 0) { /* Get the manager for the current address. */ auto &manager = this->GetManager(cur_address); /* Process part or all of the block. */ const size_t cur_pages = std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address)); manager.OpenFirst(cur_address, cur_pages); /* Advance. */ cur_address += cur_pages * PageSize; remaining_pages -= cur_pages; } } R_SUCCEED(); } Result KMemoryManager::AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern) { MESOSPHERE_ASSERT(out != nullptr); MESOSPHERE_ASSERT(out->GetNumPages() == 0); /* Decode the option. */ const auto [pool, dir] = DecodeOption(option); /* Allocate the memory. */ bool optimized; { /* Lock the pool that we're allocating from. */ KScopedLightLock lk(m_pool_locks[pool]); /* Check if we have an optimized process. */ const bool has_optimized = m_has_optimized_process[pool]; const bool is_optimized = m_optimized_process_ids[pool] == process_id; /* Always use the minimum alignment size. */ const s32 heap_index = 0; /* Allocate the page group. */ R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, has_optimized && !is_optimized, false, heap_index)); /* Set whether we should optimize. */ optimized = has_optimized && is_optimized; } /* Perform optimized memory tracking, if we should. */ if (optimized) { /* Iterate over the allocated blocks. */ for (const auto &block : *out) { /* Get the block extents. */ const KPhysicalAddress block_address = block.GetAddress(); const size_t block_pages = block.GetNumPages(); /* If it has no pages, we don't need to do anything. */ if (block_pages == 0) { continue; } /* Fill all the pages that we need to fill. */ bool any_new = false; { KPhysicalAddress cur_address = block_address; size_t remaining_pages = block_pages; while (remaining_pages > 0) { /* Get the manager for the current address. */ auto &manager = this->GetManager(cur_address); /* Process part or all of the block. */ const size_t cur_pages = std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address)); any_new = manager.ProcessOptimizedAllocation(cur_address, cur_pages, fill_pattern); /* Advance. */ cur_address += cur_pages * PageSize; remaining_pages -= cur_pages; } } /* If there are new pages, update tracking for the allocation. */ if (any_new) { /* Update tracking for the allocation. */ KPhysicalAddress cur_address = block_address; size_t remaining_pages = block_pages; while (remaining_pages > 0) { /* Get the manager for the current address. */ auto &manager = this->GetManager(cur_address); /* Lock the pool for the manager. */ KScopedLightLock lk(m_pool_locks[manager.GetPool()]); /* Track some or all of the current pages. */ const size_t cur_pages = std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address)); manager.TrackOptimizedAllocation(cur_address, cur_pages); /* Advance. */ cur_address += cur_pages * PageSize; remaining_pages -= cur_pages; } } } } else { /* Set all the allocated memory. */ for (const auto &block : *out) { std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress())), fill_pattern, block.GetSize()); } } R_SUCCEED(); } size_t KMemoryManager::Impl::Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p) { /* Calculate management sizes. */ const size_t ref_count_size = (size / PageSize) * sizeof(u16); const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(size); const size_t manager_size = util::AlignUp(optimize_map_size + ref_count_size, PageSize); const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(size); const size_t total_management_size = manager_size + page_heap_size; MESOSPHERE_ABORT_UNLESS(manager_size <= total_management_size); MESOSPHERE_ABORT_UNLESS(management + total_management_size <= management_end); MESOSPHERE_ABORT_UNLESS(util::IsAligned(total_management_size, PageSize)); /* Setup region. */ m_pool = p; m_management_region = management; m_page_reference_counts = GetPointer<RefCount>(management + optimize_map_size); MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(m_management_region), PageSize)); /* Initialize the manager's KPageHeap. */ m_heap.Initialize(address, size, management + manager_size, page_heap_size); return total_management_size; } void KMemoryManager::Impl::TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages) { /* Get the range we're tracking. */ size_t offset = this->GetPageOffset(block); const size_t last = offset + num_pages - 1; /* Track. */ u64 *optimize_map = GetPointer<u64>(m_management_region); while (offset <= last) { /* Mark the page as not being optimized-allocated. */ optimize_map[offset / BITSIZEOF(u64)] &= ~(u64(1) << (offset % BITSIZEOF(u64))); offset++; } } void KMemoryManager::Impl::TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages) { /* Get the range we're tracking. */ size_t offset = this->GetPageOffset(block); const size_t last = offset + num_pages - 1; /* Track. */ u64 *optimize_map = GetPointer<u64>(m_management_region); while (offset <= last) { /* Mark the page as being optimized-allocated. */ optimize_map[offset / BITSIZEOF(u64)] |= (u64(1) << (offset % BITSIZEOF(u64))); offset++; } } bool KMemoryManager::Impl::ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, u8 fill_pattern) { /* We want to return whether any pages were newly allocated. */ bool any_new = false; /* Get the range we're processing. */ size_t offset = this->GetPageOffset(block); const size_t last = offset + num_pages - 1; /* Process. */ u64 *optimize_map = GetPointer<u64>(m_management_region); while (offset <= last) { /* Check if the page has been optimized-allocated before. */ if ((optimize_map[offset / BITSIZEOF(u64)] & (u64(1) << (offset % BITSIZEOF(u64)))) == 0) { /* If not, it's new. */ any_new = true; /* Fill the page. */ std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(m_heap.GetAddress()) + offset * PageSize), fill_pattern, PageSize); } offset++; } /* Return the number of pages we processed. */ return any_new; } size_t KMemoryManager::Impl::CalculateManagementOverheadSize(size_t region_size) { const size_t ref_count_size = (region_size / PageSize) * sizeof(u16); const size_t optimize_map_size = (util::AlignUp((region_size / PageSize), BITSIZEOF(u64)) / BITSIZEOF(u64)) * sizeof(u64); const size_t manager_meta_size = util::AlignUp(optimize_map_size + ref_count_size, PageSize); const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size); return manager_meta_size + page_heap_size; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_object_name.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constinit KLightLock g_object_list_lock; constinit KObjectName::List g_object_list; } void KObjectName::Initialize(KAutoObject *obj, const char *name) { /* Set member variables. */ m_object = obj; std::strncpy(m_name, name, sizeof(m_name)); m_name[sizeof(m_name) - 1] = '\x00'; /* Open a reference to the object we hold. */ m_object->Open(); } bool KObjectName::MatchesName(const char *name) const { return std::strncmp(m_name, name, sizeof(m_name)) == 0; } Result KObjectName::NewFromName(KAutoObject *obj, const char *name) { /* Create a new object name. */ KObjectName *new_name = KObjectName::Allocate(); R_UNLESS(new_name != nullptr, svc::ResultOutOfResource()); /* Initialize the new name. */ new_name->Initialize(obj, name); /* Check if there's an existing name. */ { /* Ensure we have exclusive access to the global list. */ KScopedLightLock lk(g_object_list_lock); /* If the object doesn't exist, put it into the list. */ KScopedAutoObject existing_object = FindImpl(name); if (existing_object.IsNull()) { g_object_list.push_back(*new_name); R_SUCCEED(); } } /* The object already exists, which is an error condition. Perform cleanup. */ obj->Close(); KObjectName::Free(new_name); R_THROW(svc::ResultInvalidState()); } Result KObjectName::Delete(KAutoObject *obj, const char *compare_name) { /* Ensure we have exclusive access to the global list. */ KScopedLightLock lk(g_object_list_lock); /* Find a matching entry in the list, and delete it. */ for (auto &name : g_object_list) { if (name.MatchesName(compare_name) && obj == name.GetObject()) { /* We found a match, clean up its resources. */ obj->Close(); g_object_list.erase(g_object_list.iterator_to(name)); KObjectName::Free(std::addressof(name)); R_SUCCEED(); } } /* We didn't find the object in the list. */ R_THROW(svc::ResultNotFound()); } KScopedAutoObject<KAutoObject> KObjectName::Find(const char *name) { /* Ensure we have exclusive access to the global list. */ KScopedLightLock lk(g_object_list_lock); return FindImpl(name); } KScopedAutoObject<KAutoObject> KObjectName::FindImpl(const char *compare_name) { /* Try to find a matching object in the global list. */ for (const auto &name : g_object_list) { if (name.MatchesName(compare_name)) { return name.GetObject(); } } /* There's no matching entry in the list. */ return nullptr; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_page_group.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KPageGroup::Finalize() { KBlockInfo *cur = m_first_block; while (cur != nullptr) { KBlockInfo *next = cur->GetNext(); m_manager->Free(cur); cur = next; } m_first_block = nullptr; m_last_block = nullptr; } void KPageGroup::CloseAndReset() { auto &mm = Kernel::GetMemoryManager(); KBlockInfo *cur = m_first_block; while (cur != nullptr) { KBlockInfo *next = cur->GetNext(); mm.Close(cur->GetAddress(), cur->GetNumPages()); m_manager->Free(cur); cur = next; } m_first_block = nullptr; m_last_block = nullptr; } size_t KPageGroup::GetNumPages() const { size_t num_pages = 0; for (const auto &it : *this) { num_pages += it.GetNumPages(); } return num_pages; } Result KPageGroup::AddBlock(KPhysicalAddress addr, size_t num_pages) { /* Succeed immediately if we're adding no pages. */ R_SUCCEED_IF(num_pages == 0); /* Check for overflow. */ MESOSPHERE_ASSERT(addr < addr + num_pages * PageSize); /* Try to just append to the last block. */ if (m_last_block != nullptr) { R_SUCCEED_IF(m_last_block->TryConcatenate(addr, num_pages)); } /* Allocate a new block. */ KBlockInfo *new_block = m_manager->Allocate(); R_UNLESS(new_block != nullptr, svc::ResultOutOfResource()); /* Initialize the block. */ new_block->Initialize(addr, num_pages); /* Add the block to our list. */ if (m_last_block != nullptr) { m_last_block->SetNext(new_block); } else { m_first_block = new_block; } m_last_block = new_block; R_SUCCEED(); } Result KPageGroup::CopyRangeTo(KPageGroup &out, size_t range_offset, size_t range_size) const { /* Get the previous last block for the group. */ KBlockInfo * const out_last = out.m_last_block; const auto out_last_addr = out_last != nullptr ? out_last->GetAddress() : Null<KPhysicalAddress>; const auto out_last_np = out_last != nullptr ? out_last->GetNumPages() : 0; /* Ensure we cleanup the group on failure. */ ON_RESULT_FAILURE { KBlockInfo *cur = out_last != nullptr ? out_last->GetNext() : out.m_first_block; while (cur != nullptr) { KBlockInfo *next = cur->GetNext(); out.m_manager->Free(cur); cur = next; } if (out_last != nullptr) { out_last->Initialize(out_last_addr, out_last_np); out_last->SetNext(nullptr); } else { out.m_first_block = nullptr; } out.m_last_block = out_last; }; /* Find the pages within the requested range. */ size_t cur_offset = 0, remaining_size = range_size; for (auto it = this->begin(); it != this->end() && remaining_size > 0; ++it) { /* Get the current size. */ const size_t cur_size = it->GetSize(); /* Determine if the offset is in range. */ const size_t rel_diff = range_offset - cur_offset; const bool is_before = cur_offset <= range_offset; cur_offset += cur_size; if (is_before && range_offset < cur_offset) { /* It is, so add the block. */ const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size); R_TRY(out.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize)); /* Advance. */ cur_offset = range_offset + block_size; remaining_size -= block_size; range_offset += block_size; } } /* Check that we successfully copied the range. */ MESOSPHERE_ABORT_UNLESS(remaining_size == 0); R_SUCCEED(); } void KPageGroup::Open() const { auto &mm = Kernel::GetMemoryManager(); for (const auto &it : *this) { mm.Open(it.GetAddress(), it.GetNumPages()); } } void KPageGroup::OpenFirst() const { auto &mm = Kernel::GetMemoryManager(); for (const auto &it : *this) { mm.OpenFirst(it.GetAddress(), it.GetNumPages()); } } void KPageGroup::Close() const { auto &mm = Kernel::GetMemoryManager(); for (const auto &it : *this) { mm.Close(it.GetAddress(), it.GetNumPages()); } } bool KPageGroup::IsEquivalentTo(const KPageGroup &rhs) const { auto lit = this->begin(); auto rit = rhs.begin(); auto lend = this->end(); auto rend = rhs.end(); while (lit != lend && rit != rend) { if (*lit != *rit) { return false; } ++lit; ++rit; } return lit == lend && rit == rend; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_page_heap.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KPageHeap::Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management_address, size_t management_size, const size_t *block_shifts, size_t num_block_shifts) { /* Check our assumptions. */ MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(size, PageSize)); MESOSPHERE_ASSERT(0 < num_block_shifts && num_block_shifts <= NumMemoryBlockPageShifts); const KVirtualAddress management_end = management_address + management_size; /* Set our members. */ m_heap_address = address; m_heap_size = size; m_num_blocks = num_block_shifts; /* Setup bitmaps. */ u64 *cur_bitmap_storage = GetPointer<u64>(management_address); for (size_t i = 0; i < num_block_shifts; i++) { const size_t cur_block_shift = block_shifts[i]; const size_t next_block_shift = (i != num_block_shifts - 1) ? block_shifts[i + 1] : 0; cur_bitmap_storage = m_blocks[i].Initialize(m_heap_address, m_heap_size, cur_block_shift, next_block_shift, cur_bitmap_storage); } /* Ensure we didn't overextend our bounds. */ MESOSPHERE_ABORT_UNLESS(KVirtualAddress(cur_bitmap_storage) <= management_end); } size_t KPageHeap::GetNumFreePages() const { size_t num_free = 0; for (size_t i = 0; i < m_num_blocks; i++) { num_free += m_blocks[i].GetNumFreePages(); } return num_free; } KPhysicalAddress KPageHeap::AllocateByLinearSearch(s32 index) { const size_t needed_size = m_blocks[index].GetSize(); for (s32 i = index; i < static_cast<s32>(m_num_blocks); i++) { if (const KPhysicalAddress addr = m_blocks[i].PopBlock(false); addr != Null<KPhysicalAddress>) { if (const size_t allocated_size = m_blocks[i].GetSize(); allocated_size > needed_size) { this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize); } return addr; } } return Null<KPhysicalAddress>; } KPhysicalAddress KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) { /* Get the size and required alignment. */ const size_t needed_size = num_pages * PageSize; const size_t align_size = align_pages * PageSize; /* Determine meta-alignment of our desired alignment size. */ const size_t align_shift = util::CountTrailingZeros(align_size); /* Decide on a block to allocate from. */ constexpr size_t MinimumPossibleAlignmentsForRandomAllocation = 4; { /* By default, we'll want to look at all blocks larger than our current one. */ s32 max_blocks = static_cast<s32>(m_num_blocks); /* Determine the maximum block we should try to allocate from. */ size_t possible_alignments = 0; for (s32 i = index; i < max_blocks; ++i) { /* Add the possible alignments from blocks at the current size. */ possible_alignments += (1 + ((m_blocks[i].GetSize() - needed_size) >> align_shift)) * m_blocks[i].GetNumFreeBlocks(); /* If there are enough possible alignments, we don't need to look at larger blocks. */ if (possible_alignments >= MinimumPossibleAlignmentsForRandomAllocation) { max_blocks = i + 1; break; } } /* If we have any possible alignments which require a larger block, we need to pick one. */ if (possible_alignments > 0 && index + 1 < max_blocks) { /* Select a random alignment from the possibilities. */ const size_t rnd = m_rng.GenerateRandom(possible_alignments); /* Determine which block corresponds to the random alignment we chose. */ possible_alignments = 0; for (s32 i = index; i < max_blocks; ++i) { /* Add the possible alignments from blocks at the current size. */ possible_alignments += (1 + ((m_blocks[i].GetSize() - needed_size) >> align_shift)) * m_blocks[i].GetNumFreeBlocks(); /* If the current block gets us to our random choice, use the current block. */ if (rnd < possible_alignments) { index = i; break; } } } } /* Pop a block from the index we selected. */ if (KPhysicalAddress addr = m_blocks[index].PopBlock(true); addr != Null<KPhysicalAddress>) { /* Determine how much size we have left over. */ if (const size_t leftover_size = m_blocks[index].GetSize() - needed_size; leftover_size > 0) { /* Determine how many valid alignments we can have. */ const size_t possible_alignments = 1 + (leftover_size >> align_shift); /* Select a random valid alignment. */ const size_t random_offset = m_rng.GenerateRandom(possible_alignments) << align_shift; /* Free memory before the random offset. */ if (random_offset != 0) { this->Free(addr, random_offset / PageSize); } /* Advance our block by the random offset. */ addr += random_offset; /* Free memory after our allocated block. */ if (random_offset != leftover_size) { this->Free(addr + needed_size, (leftover_size - random_offset) / PageSize); } } /* Return the block we allocated. */ return addr; } return Null<KPhysicalAddress>; } void KPageHeap::FreeBlock(KPhysicalAddress block, s32 index) { do { block = m_blocks[index++].PushBlock(block); } while (block != Null<KPhysicalAddress>); } void KPageHeap::Free(KPhysicalAddress addr, size_t num_pages) { /* Freeing no pages is a no-op. */ if (num_pages == 0) { return; } /* Find the largest block size that we can free, and free as many as possible. */ s32 big_index = static_cast<s32>(m_num_blocks) - 1; const KPhysicalAddress start = addr; const KPhysicalAddress end = addr + num_pages * PageSize; KPhysicalAddress before_start = start; KPhysicalAddress before_end = start; KPhysicalAddress after_start = end; KPhysicalAddress after_end = end; while (big_index >= 0) { const size_t block_size = m_blocks[big_index].GetSize(); const KPhysicalAddress big_start = util::AlignUp(GetInteger(start), block_size); const KPhysicalAddress big_end = util::AlignDown(GetInteger(end), block_size); if (big_start < big_end) { /* Free as many big blocks as we can. */ for (auto block = big_start; block < big_end; block += block_size) { this->FreeBlock(block, big_index); } before_end = big_start; after_start = big_end; break; } big_index--; } MESOSPHERE_ASSERT(big_index >= 0); /* Free space before the big blocks. */ for (s32 i = big_index - 1; i >= 0; i--) { const size_t block_size = m_blocks[i].GetSize(); while (before_start + block_size <= before_end) { before_end -= block_size; this->FreeBlock(before_end, i); } } /* Free space after the big blocks. */ for (s32 i = big_index - 1; i >= 0; i--) { const size_t block_size = m_blocks[i].GetSize(); while (after_start + block_size <= after_end) { this->FreeBlock(after_start, i); after_start += block_size; } } } size_t KPageHeap::CalculateManagementOverheadSize(size_t region_size, const size_t *block_shifts, size_t num_block_shifts) { size_t overhead_size = 0; for (size_t i = 0; i < num_block_shifts; i++) { const size_t cur_block_shift = block_shifts[i]; const size_t next_block_shift = (i != num_block_shifts - 1) ? block_shifts[i + 1] : 0; overhead_size += KPageHeap::Block::CalculateManagementOverheadSize(region_size, cur_block_shift, next_block_shift); } return util::AlignUp(overhead_size, PageSize); } void KPageHeap::DumpFreeList() const { MESOSPHERE_RELEASE_LOG("KPageHeap::DumpFreeList %p\n", this); for (size_t i = 0; i < m_num_blocks; ++i) { const size_t block_size = m_blocks[i].GetSize(); const char *suffix; size_t size; if (block_size >= 1_GB) { suffix = "GiB"; size = block_size / 1_GB; } else if (block_size >= 1_MB) { suffix = "MiB"; size = block_size / 1_MB; } else if (block_size >= 1_KB) { suffix = "KiB"; size = block_size / 1_KB; } else { suffix = "B"; size = block_size; } MESOSPHERE_RELEASE_LOG(" %4zu %s block x %zu\n", size, suffix, m_blocks[i].GetNumFreeBlocks()); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_page_table_base.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #include <mesosphere/kern_select_page_table.hpp> namespace ams::kern { namespace { class KScopedLightLockPair { NON_COPYABLE(KScopedLightLockPair); NON_MOVEABLE(KScopedLightLockPair); private: KLightLock *m_lower; KLightLock *m_upper; public: ALWAYS_INLINE KScopedLightLockPair(KLightLock &lhs, KLightLock &rhs) { /* Ensure our locks are in a consistent order. */ if (std::addressof(lhs) <= std::addressof(rhs)) { m_lower = std::addressof(lhs); m_upper = std::addressof(rhs); } else { m_lower = std::addressof(rhs); m_upper = std::addressof(lhs); } /* Acquire both locks. */ m_lower->Lock(); if (m_lower != m_upper) { m_upper->Lock(); } } ~KScopedLightLockPair() { /* Unlock the upper lock. */ if (m_upper != nullptr && m_upper != m_lower) { m_upper->Unlock(); } /* Unlock the lower lock. */ if (m_lower != nullptr) { m_lower->Unlock(); } } public: /* Utility. */ ALWAYS_INLINE void TryUnlockHalf(KLightLock &lock) { /* Only allow unlocking if the lock is half the pair. */ if (m_lower != m_upper) { /* We want to be sure the lock is one we own. */ if (m_lower == std::addressof(lock)) { lock.Unlock(); m_lower = nullptr; } else if (m_upper == std::addressof(lock)) { lock.Unlock(); m_upper = nullptr; } } } }; } void KPageTableBase::MemoryRange::Open() { /* If the range contains heap pages, open them. */ if (this->IsHeap()) { Kernel::GetMemoryManager().Open(this->GetAddress(), this->GetSize() / PageSize); } } void KPageTableBase::MemoryRange::Close() { /* If the range contains heap pages, close them. */ if (this->IsHeap()) { Kernel::GetMemoryManager().Close(this->GetAddress(), this->GetSize() / PageSize); } } void KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) { /* Initialize our members. */ m_address_space_width = (is_64_bit) ? BITSIZEOF(u64) : BITSIZEOF(u32); m_address_space_start = KProcessAddress(GetInteger(start)); m_address_space_end = KProcessAddress(GetInteger(end)); m_is_kernel = true; m_enable_aslr = true; m_enable_device_address_space_merge = false; for (auto i = 0; i < RegionType_Count; ++i) { m_region_starts[i] = 0; m_region_ends[i] = 0; } m_current_heap_end = 0; m_alias_code_region_start = 0; m_alias_code_region_end = 0; m_code_region_start = 0; m_code_region_end = 0; m_max_heap_size = 0; m_mapped_physical_memory_size = 0; m_mapped_unsafe_physical_memory = 0; m_mapped_insecure_memory = 0; m_mapped_ipc_server_memory = 0; m_alias_region_extra_size = 0; m_memory_block_slab_manager = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManagerPointer(); m_block_info_manager = Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer(); m_resource_limit = std::addressof(Kernel::GetSystemResourceLimit()); m_allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront); m_heap_fill_value = MemoryFillValue_Zero; m_ipc_fill_value = MemoryFillValue_Zero; m_stack_fill_value = MemoryFillValue_Zero; m_cached_physical_linear_region = nullptr; m_cached_physical_heap_region = nullptr; /* Initialize our implementation. */ m_impl.InitializeForKernel(table, start, end); /* Initialize our memory block manager. */ MESOSPHERE_R_ABORT_UNLESS(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager)); } Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) { /* Validate the region. */ MESOSPHERE_ABORT_UNLESS(start <= code_address); MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size); MESOSPHERE_ABORT_UNLESS(code_address + code_size - 1 <= end - 1); /* Define helpers. */ auto GetSpaceStart = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA { return KAddressSpaceInfo::GetAddressSpaceStart(flags, type, code_size); }; auto GetSpaceSize = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA { return KAddressSpaceInfo::GetAddressSpaceSize(flags, type); }; /* Default to zero alias region extra size. */ m_alias_region_extra_size = 0; /* Set our width and heap/alias sizes. */ m_address_space_width = GetAddressSpaceWidth(flags); size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias); size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap); /* Set code regions and determine remaining sizes. */ KProcessAddress process_code_start; KProcessAddress process_code_end; size_t stack_region_size; size_t kernel_map_region_size; KProcessAddress before_process_code_start, after_process_code_start; size_t before_process_code_size, after_process_code_size; if (m_address_space_width == 39) { stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack); kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit); m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit); m_alias_code_region_start = m_code_region_start; m_alias_code_region_end = m_code_region_end; process_code_start = util::AlignDown(GetInteger(code_address), RegionAlignment); process_code_end = util::AlignUp(GetInteger(code_address) + code_size, RegionAlignment); before_process_code_start = m_code_region_start; before_process_code_size = process_code_start - before_process_code_start; after_process_code_start = process_code_end; after_process_code_size = m_code_region_end - process_code_end; /* If we have a 39-bit address space and should, enable extra size to the alias region. */ if (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) { /* Extra size is 1/8th of the address space. */ m_alias_region_extra_size = (static_cast<size_t>(1) << m_address_space_width) / 8; alias_region_size += m_alias_region_extra_size; } } else { stack_region_size = 0; kernel_map_region_size = 0; m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapSmall); m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapSmall); m_alias_code_region_start = m_code_region_start; m_alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge) + GetSpaceSize(KAddressSpaceInfo::Type_MapLarge); m_region_starts[RegionType_Stack] = m_code_region_start; m_region_ends[RegionType_Stack] = m_code_region_end; m_region_starts[RegionType_KernelMap] = m_code_region_start; m_region_ends[RegionType_KernelMap] = m_code_region_end; process_code_start = m_code_region_start; process_code_end = m_code_region_end; before_process_code_start = m_code_region_start; before_process_code_size = 0; after_process_code_start = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge); after_process_code_size = GetSpaceSize(KAddressSpaceInfo::Type_MapLarge); } /* Set other basic fields. */ m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0; m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0; m_address_space_start = start; m_address_space_end = end; m_is_kernel = false; m_memory_block_slab_manager = system_resource->GetMemoryBlockSlabManagerPointer(); m_block_info_manager = system_resource->GetBlockInfoManagerPointer(); m_resource_limit = resource_limit; /* Set up our undetermined regions. */ { /* Declare helper structure for layout process. */ struct RegionLayoutInfo { size_t size; RegionType type; s32 alloc_index; /* 0 for before process code, 1 for after process code */ }; /* Create region layout info array, and add regions to it. */ RegionLayoutInfo region_layouts[RegionType_Count] = {}; size_t num_regions = 0; if (kernel_map_region_size > 0) { region_layouts[num_regions++] = { .size = kernel_map_region_size, .type = RegionType_KernelMap, .alloc_index = 0, }; } if (stack_region_size > 0) { region_layouts[num_regions++] = { .size = stack_region_size, .type = RegionType_Stack, .alloc_index = 0, }; } region_layouts[num_regions++] = { .size = alias_region_size, .type = RegionType_Alias, .alloc_index = 0, }; region_layouts[num_regions++] = { .size = heap_region_size, .type = RegionType_Heap, .alloc_index = 0, }; /* Selection-sort the regions by size largest-to-smallest. */ for (size_t i = 0; i < num_regions - 1; ++i) { for (size_t j = i + 1; j < num_regions; ++j) { if (region_layouts[i].size < region_layouts[j].size) { std::swap(region_layouts[i], region_layouts[j]); } } } /* Layout the regions. */ constexpr auto AllocIndexCount = 2; KProcessAddress alloc_starts[AllocIndexCount] = { before_process_code_start, after_process_code_start }; size_t alloc_sizes[AllocIndexCount] = { before_process_code_size, after_process_code_size }; size_t alloc_counts[AllocIndexCount] = {}; for (size_t i = 0; i < num_regions; ++i) { /* Get reference to the current region. */ auto &cur_region = region_layouts[i]; /* Determine where the current region should go. */ cur_region.alloc_index = alloc_sizes[1] >= alloc_sizes[0] ? 1 : 0; ++alloc_counts[cur_region.alloc_index]; /* Check that the current region can fit. */ R_UNLESS(alloc_sizes[cur_region.alloc_index] >= cur_region.size, svc::ResultOutOfMemory()); /* Update our remaining size tracking. */ alloc_sizes[cur_region.alloc_index] -= cur_region.size; } /* Selection sort the regions to coalesce them by alloc index. */ for (size_t i = 0; i < num_regions - 1; ++i) { for (size_t j = i + 1; j < num_regions; ++j) { if (region_layouts[i].alloc_index > region_layouts[j].alloc_index) { std::swap(region_layouts[i], region_layouts[j]); } } } /* Layout the regions for each alloc index. */ for (auto cur_alloc_index = 0; cur_alloc_index < AllocIndexCount; ++cur_alloc_index) { /* If there are no regions to place, continue. */ const size_t cur_alloc_count = alloc_counts[cur_alloc_index]; if (cur_alloc_count == 0) { continue; } /* Determine the starting region index for the current alloc index. */ size_t cur_region_index = 0; for (size_t i = 0; i < num_regions; ++i) { if (region_layouts[i].alloc_index == cur_alloc_index) { cur_region_index = i; break; } } /* If aslr is enabled, randomize the current region order. Otherwise, sort by type. */ if (m_enable_aslr) { for (size_t i = 0; i < cur_alloc_count - 1; ++i) { std::swap(region_layouts[cur_region_index + i], region_layouts[cur_region_index + KSystemControl::GenerateRandomRange(i, cur_alloc_count - 1)]); } } else { for (size_t i = 0; i < cur_alloc_count - 1; ++i) { for (size_t j = i + 1; j < cur_alloc_count; ++j) { if (region_layouts[cur_region_index + i].type > region_layouts[cur_region_index + j].type) { std::swap(region_layouts[cur_region_index + i], region_layouts[cur_region_index + j]); } } } } /* Determine aslr offsets for the current space. */ size_t aslr_offsets[RegionType_Count] = {}; if (m_enable_aslr) { /* Generate the aslr offsets. */ for (size_t i = 0; i < cur_alloc_count; ++i) { aslr_offsets[i] = KSystemControl::GenerateRandomRange(0, alloc_sizes[cur_alloc_index] / RegionAlignment) * RegionAlignment; } /* Sort the aslr offsets. */ for (size_t i = 0; i < cur_alloc_count - 1; ++i) { for (size_t j = i + 1; j < cur_alloc_count; ++j) { if (aslr_offsets[i] > aslr_offsets[j]) { std::swap(aslr_offsets[i], aslr_offsets[j]); } } } } /* Calculate final region positions. */ KProcessAddress prev_region_end = alloc_starts[cur_alloc_index]; size_t prev_aslr_offset = 0; for (size_t i = 0; i < cur_alloc_count; ++i) { /* Get the current region. */ auto &cur_region = region_layouts[cur_region_index + i]; /* Set the current region start/end. */ m_region_starts[cur_region.type] = (aslr_offsets[i] - prev_aslr_offset) + GetInteger(prev_region_end); m_region_ends[cur_region.type] = m_region_starts[cur_region.type] + cur_region.size; /* Update tracking variables. */ prev_region_end = m_region_ends[cur_region.type]; prev_aslr_offset = aslr_offsets[i]; } } /* Declare helpers to check that regions are inside our address space. */ const KProcessAddress process_code_last = process_code_end - 1; auto IsInAddressSpace = [&](KProcessAddress addr) ALWAYS_INLINE_LAMBDA { return m_address_space_start <= addr && addr <= m_address_space_end; }; /* Ensure that the KernelMap region is valid. */ for (size_t k = 0; k < num_regions; ++k) { if (const auto &kmap_region = region_layouts[k]; kmap_region.type == RegionType_KernelMap) { /* If there's no kmap region, we have nothing to check. */ if (kmap_region.size == 0) { break; } /* Check that the kmap region is within our address space. */ MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_KernelMap])); MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_KernelMap])); /* Check for overlap with process code. */ const KProcessAddress kmap_start = m_region_starts[RegionType_KernelMap]; const KProcessAddress kmap_last = m_region_ends[RegionType_KernelMap] - 1; MESOSPHERE_ABORT_UNLESS(kernel_map_region_size == 0 || kmap_last < process_code_start || process_code_last < kmap_start); /* Check for overlap with stack. */ for (size_t s = 0; s < num_regions; ++s) { if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) { if (stack_region.size != 0) { const KProcessAddress stack_start = m_region_starts[RegionType_Stack]; const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1; MESOSPHERE_ABORT_UNLESS((kernel_map_region_size == 0 && stack_region_size == 0) || kmap_last < stack_start || stack_last < kmap_start); } break; } } /* Check for overlap with alias. */ for (size_t a = 0; a < num_regions; ++a) { if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { if (alias_region.size != 0) { const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; MESOSPHERE_ABORT_UNLESS(kmap_last < alias_start || alias_last < kmap_start); } break; } } /* Check for overlap with heap. */ for (size_t h = 0; h < num_regions; ++h) { if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { if (heap_region.size != 0) { const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; MESOSPHERE_ABORT_UNLESS(kmap_last < heap_start || heap_last < kmap_start); } break; } } } } /* Check that the Stack region is valid. */ for (size_t s = 0; s < num_regions; ++s) { if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) { /* If there's no stack region, we have nothing to check. */ if (stack_region.size == 0) { break; } /* Check that the stack region is within our address space. */ MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Stack])); MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Stack])); /* Check for overlap with process code. */ const KProcessAddress stack_start = m_region_starts[RegionType_Stack]; const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1; MESOSPHERE_ABORT_UNLESS(stack_region_size == 0 || stack_last < process_code_start || process_code_last < stack_start); /* Check for overlap with alias. */ for (size_t a = 0; a < num_regions; ++a) { if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { if (alias_region.size != 0) { const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; MESOSPHERE_ABORT_UNLESS(stack_last < alias_start || alias_last < stack_start); } break; } } /* Check for overlap with heap. */ for (size_t h = 0; h < num_regions; ++h) { if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { if (heap_region.size != 0) { const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; MESOSPHERE_ABORT_UNLESS(stack_last < heap_start || heap_last < stack_start); } break; } } } } /* Check that the Alias region is valid. */ for (size_t a = 0; a < num_regions; ++a) { if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) { /* If there's no alias region, we have nothing to check. */ if (alias_region.size == 0) { break; } /* Check that the alias region is within our address space. */ MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Alias])); MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Alias])); /* Check for overlap with process code. */ const KProcessAddress alias_start = m_region_starts[RegionType_Alias]; const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1; MESOSPHERE_ABORT_UNLESS(alias_last < process_code_start || process_code_last < alias_start); /* Check for overlap with heap. */ for (size_t h = 0; h < num_regions; ++h) { if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { if (heap_region.size != 0) { const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; MESOSPHERE_ABORT_UNLESS(alias_last < heap_start || heap_last < alias_start); } break; } } } } /* Check that the Heap region is valid. */ for (size_t h = 0; h < num_regions; ++h) { if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) { /* If there's no heap region, we have nothing to check. */ if (heap_region.size == 0) { break; } /* Check that the heap region is within our address space. */ MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Heap])); MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Heap])); /* Check for overlap with process code. */ const KProcessAddress heap_start = m_region_starts[RegionType_Heap]; const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1; MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start); } } } /* Set heap and fill members. */ m_current_heap_end = m_region_starts[RegionType_Heap]; m_max_heap_size = 0; m_mapped_physical_memory_size = 0; m_mapped_unsafe_physical_memory = 0; m_mapped_insecure_memory = 0; m_mapped_ipc_server_memory = 0; const bool fill_memory = KTargetSystem::IsDebugMemoryFillEnabled(); m_heap_fill_value = fill_memory ? MemoryFillValue_Heap : MemoryFillValue_Zero; m_ipc_fill_value = fill_memory ? MemoryFillValue_Ipc : MemoryFillValue_Zero; m_stack_fill_value = fill_memory ? MemoryFillValue_Stack : MemoryFillValue_Zero; /* Set allocation option. */ m_allocate_option = KMemoryManager::EncodeOption(pool, from_back ? KMemoryManager::Direction_FromBack : KMemoryManager::Direction_FromFront); /* Initialize our implementation. */ m_impl.InitializeForProcess(table, GetInteger(start), GetInteger(end)); /* Initialize our memory block manager. */ R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager)); } void KPageTableBase::Finalize() { /* Finalize memory blocks. */ m_memory_block_manager.Finalize(m_memory_block_slab_manager); /* Free any unsafe mapped memory. */ if (m_mapped_unsafe_physical_memory) { Kernel::GetUnsafeMemory().Release(m_mapped_unsafe_physical_memory); } /* Release any insecure mapped memory. */ if (m_mapped_insecure_memory) { if (auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(); insecure_resource_limit != nullptr) { insecure_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, m_mapped_insecure_memory); } } /* Release any ipc server memory. */ if (m_mapped_ipc_server_memory) { m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, m_mapped_ipc_server_memory); } /* Invalidate the entire instruction cache. */ cpu::InvalidateEntireInstructionCache(); } KProcessAddress KPageTableBase::GetRegionAddress(ams::svc::MemoryState state) const { switch (state) { case ams::svc::MemoryState_Free: case ams::svc::MemoryState_Kernel: return m_address_space_start; case ams::svc::MemoryState_Normal: return m_region_starts[RegionType_Heap]; case ams::svc::MemoryState_Ipc: case ams::svc::MemoryState_NonSecureIpc: case ams::svc::MemoryState_NonDeviceIpc: return m_region_starts[RegionType_Alias]; case ams::svc::MemoryState_Stack: return m_region_starts[RegionType_Stack]; case ams::svc::MemoryState_Static: case ams::svc::MemoryState_ThreadLocal: return m_region_starts[RegionType_KernelMap]; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Shared: case ams::svc::MemoryState_AliasCode: case ams::svc::MemoryState_AliasCodeData: case ams::svc::MemoryState_Transfered: case ams::svc::MemoryState_SharedTransfered: case ams::svc::MemoryState_SharedCode: case ams::svc::MemoryState_GeneratedCode: case ams::svc::MemoryState_CodeOut: case ams::svc::MemoryState_Coverage: case ams::svc::MemoryState_Insecure: return m_alias_code_region_start; case ams::svc::MemoryState_Code: case ams::svc::MemoryState_CodeData: return m_code_region_start; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } size_t KPageTableBase::GetRegionSize(ams::svc::MemoryState state) const { switch (state) { case ams::svc::MemoryState_Free: case ams::svc::MemoryState_Kernel: return m_address_space_end - m_address_space_start; case ams::svc::MemoryState_Normal: return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; case ams::svc::MemoryState_Ipc: case ams::svc::MemoryState_NonSecureIpc: case ams::svc::MemoryState_NonDeviceIpc: return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; case ams::svc::MemoryState_Stack: return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; case ams::svc::MemoryState_Static: case ams::svc::MemoryState_ThreadLocal: return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Shared: case ams::svc::MemoryState_AliasCode: case ams::svc::MemoryState_AliasCodeData: case ams::svc::MemoryState_Transfered: case ams::svc::MemoryState_SharedTransfered: case ams::svc::MemoryState_SharedCode: case ams::svc::MemoryState_GeneratedCode: case ams::svc::MemoryState_CodeOut: case ams::svc::MemoryState_Coverage: case ams::svc::MemoryState_Insecure: return m_alias_code_region_end - m_alias_code_region_start; case ams::svc::MemoryState_Code: case ams::svc::MemoryState_CodeData: return m_code_region_end - m_code_region_start; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { const KProcessAddress end = addr + size; const KProcessAddress last = end - 1; const KProcessAddress region_start = this->GetRegionAddress(state); const size_t region_size = this->GetRegionSize(state); const bool is_in_region = region_start <= addr && addr < end && last <= region_start + region_size - 1; const bool is_in_heap = !(end <= m_region_starts[RegionType_Heap] || m_region_ends[RegionType_Heap] <= addr || m_region_starts[RegionType_Heap] == m_region_ends[RegionType_Heap]); const bool is_in_alias = !(end <= m_region_starts[RegionType_Alias] || m_region_ends[RegionType_Alias] <= addr || m_region_starts[RegionType_Alias] == m_region_ends[RegionType_Alias]); switch (state) { case ams::svc::MemoryState_Free: case ams::svc::MemoryState_Kernel: return is_in_region; case ams::svc::MemoryState_Io: case ams::svc::MemoryState_Static: case ams::svc::MemoryState_Code: case ams::svc::MemoryState_CodeData: case ams::svc::MemoryState_Shared: case ams::svc::MemoryState_AliasCode: case ams::svc::MemoryState_AliasCodeData: case ams::svc::MemoryState_Stack: case ams::svc::MemoryState_ThreadLocal: case ams::svc::MemoryState_Transfered: case ams::svc::MemoryState_SharedTransfered: case ams::svc::MemoryState_SharedCode: case ams::svc::MemoryState_GeneratedCode: case ams::svc::MemoryState_CodeOut: case ams::svc::MemoryState_Coverage: case ams::svc::MemoryState_Insecure: return is_in_region && !is_in_heap && !is_in_alias; case ams::svc::MemoryState_Normal: MESOSPHERE_ASSERT(is_in_heap); return is_in_region && !is_in_alias; case ams::svc::MemoryState_Ipc: case ams::svc::MemoryState_NonSecureIpc: case ams::svc::MemoryState_NonDeviceIpc: MESOSPHERE_ASSERT(is_in_alias); return is_in_region && !is_in_heap; default: return false; } } Result KPageTableBase::CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const { /* Validate the states match expectation. */ R_UNLESS((it->GetState() & state_mask) == state, svc::ResultInvalidCurrentMemory()); R_UNLESS((it->GetPermission() & perm_mask) == perm, svc::ResultInvalidCurrentMemory()); R_UNLESS((it->GetAttribute() & attr_mask) == attr, svc::ResultInvalidCurrentMemory()); R_SUCCEED(); } Result KPageTableBase::CheckMemoryStateContiguous(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Get information about the first block. */ const KProcessAddress last_addr = addr + size - 1; KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr); /* If the start address isn't aligned, we need a block. */ const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) ? 1 : 0; while (true) { /* Validate against the provided masks. */ R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr)); /* Break once we're done. */ if (last_addr <= it->GetLastAddress()) { break; } /* Advance our iterator. */ it++; MESOSPHERE_ASSERT(it != m_memory_block_manager.cend()); } /* If the end address isn't aligned, we need a block. */ const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != it->GetEndAddress()) ? 1 : 0; if (out_blocks_needed != nullptr) { *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; } R_SUCCEED(); } Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Validate all blocks in the range have correct state. */ const KMemoryState first_state = it->GetState(); const KMemoryPermission first_perm = it->GetPermission(); const KMemoryAttribute first_attr = it->GetAttribute(); while (true) { /* Validate the current block. */ R_UNLESS(it->GetState() == first_state, svc::ResultInvalidCurrentMemory()); R_UNLESS(it->GetPermission() == first_perm, svc::ResultInvalidCurrentMemory()); R_UNLESS((it->GetAttribute() | ignore_attr) == (first_attr | ignore_attr), svc::ResultInvalidCurrentMemory()); /* Validate against the provided masks. */ R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr)); /* Break once we're done. */ if (last_addr <= it->GetLastAddress()) { break; } /* Advance our iterator. */ it++; MESOSPHERE_ASSERT(it != m_memory_block_manager.cend()); } /* Write output state. */ if (out_state != nullptr) { *out_state = first_state; } if (out_perm != nullptr) { *out_perm = first_perm; } if (out_attr != nullptr) { *out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr); } /* If the end address isn't aligned, we need a block. */ if (out_blocks_needed != nullptr) { const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != it->GetEndAddress()) ? 1 : 0; *out_blocks_needed = blocks_for_end_align; } R_SUCCEED(); } Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Check memory state. */ const KProcessAddress last_addr = addr + size - 1; KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr); R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr)); /* If the start address isn't aligned, we need a block. */ if (out_blocks_needed != nullptr && util::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) { ++(*out_blocks_needed); } R_SUCCEED(); } Result KPageTableBase::LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr) { /* Validate basic preconditions. */ MESOSPHERE_ASSERT((lock_attr & attr) == 0); MESOSPHERE_ASSERT((lock_attr & (KMemoryAttribute_IpcLocked | KMemoryAttribute_DeviceShared)) == 0); /* Validate the lock request. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(addr, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check that the output page group is empty, if it exists. */ if (out_pg) { MESOSPHERE_ASSERT(out_pg->GetNumPages() == 0); } /* Check the state. */ KMemoryState old_state; KMemoryPermission old_perm; KMemoryAttribute old_attr; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr)); /* Get the physical address, if we're supposed to. */ if (out_paddr != nullptr) { MESOSPHERE_ABORT_UNLESS(this->GetPhysicalAddressLocked(out_paddr, addr)); } /* Make the page group, if we're supposed to. */ if (out_pg != nullptr) { R_TRY(this->MakePageGroup(*out_pg, addr, num_pages)); } /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Decide on new perm and attr. */ new_perm = (new_perm != KMemoryPermission_None) ? new_perm : old_perm; KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr | lock_attr); /* Update permission, if we need to. */ if (new_perm != old_perm) { /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); const KPageProperties properties = { new_perm, false, (old_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_DisableHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); } /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm, new_attr, KMemoryBlockDisableMergeAttribute_Locked, KMemoryBlockDisableMergeAttribute_None); /* If we have an output group, open. */ if (out_pg) { out_pg->Open(); } R_SUCCEED(); } Result KPageTableBase::UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg) { /* Validate basic preconditions. */ MESOSPHERE_ASSERT((attr_mask & lock_attr) == lock_attr); MESOSPHERE_ASSERT((attr & lock_attr) == lock_attr); /* Validate the unlock request. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(addr, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the state. */ KMemoryState old_state; KMemoryPermission old_perm; KMemoryAttribute old_attr; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr)); /* Check the page group. */ if (pg != nullptr) { R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), svc::ResultInvalidMemoryRegion()); } /* Decide on new perm and attr. */ new_perm = (new_perm != KMemoryPermission_None) ? new_perm : old_perm; KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Update permission, if we need to. */ if (new_perm != old_perm) { /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); const KPageProperties properties = { new_perm, false, (old_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_EnableAndMergeHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); } /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm, new_attr, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Locked); R_SUCCEED(); } Result KPageTableBase::QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(out_info != nullptr); MESOSPHERE_ASSERT(out_page != nullptr); const KMemoryBlock *block = m_memory_block_manager.FindBlock(address); R_UNLESS(block != nullptr, svc::ResultInvalidCurrentMemory()); *out_info = block->GetMemoryInfo(); out_page->flags = 0; R_SUCCEED(); } Result KPageTableBase::QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const { MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(out != nullptr); const KProcessAddress region_start = this->GetRegionAddress(state); const size_t region_size = this->GetRegionSize(state); /* Check that the address/size are potentially valid. */ R_UNLESS((address < address + size), svc::ResultNotFound()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 }; bool cur_valid = false; TraversalEntry next_entry; bool next_valid; size_t tot_size = 0; next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), region_start); next_entry.block_size = (next_entry.block_size - (GetInteger(region_start) & (next_entry.block_size - 1))); /* Iterate, looking for entry. */ while (true) { if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) { cur_entry.block_size += next_entry.block_size; } else { if (cur_valid && cur_entry.phys_addr <= address && address + size <= cur_entry.phys_addr + cur_entry.block_size) { /* Check if this region is valid. */ const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr); if (R_SUCCEEDED(this->CheckMemoryState(mapped_address, size, KMemoryState_Mask, static_cast<KMemoryState>(util::ToUnderlying(state)), KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { /* It is! */ *out = mapped_address; R_SUCCEED(); } } /* Update tracking variables. */ tot_size += cur_entry.block_size; cur_entry = next_entry; cur_valid = next_valid; } if (cur_entry.block_size + tot_size >= region_size) { break; } next_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); } /* Check the last entry. */ R_UNLESS(cur_valid, svc::ResultNotFound()); R_UNLESS(cur_entry.phys_addr <= address, svc::ResultNotFound()); R_UNLESS(address + size <= cur_entry.phys_addr + cur_entry.block_size, svc::ResultNotFound()); /* Check if the last region is valid. */ const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr); R_TRY_CATCH(this->CheckMemoryState(mapped_address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)) { R_CONVERT_ALL(svc::ResultNotFound()); } R_END_TRY_CATCH; /* We found the region. */ *out = mapped_address; R_SUCCEED(); } Result KPageTableBase::MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate that the source address's state is valid. */ KMemoryState src_state; size_t num_src_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Validate that the dst address's state is valid. */ size_t num_dst_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator for the source. */ Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); /* Create an update allocator for the destination. */ Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); /* Map the memory. */ { /* Determine the number of pages being operated on. */ const size_t num_pages = size / PageSize; /* Create page groups for the memory being unmapped. */ KPageGroup pg(m_block_info_manager); /* Create the page group representing the source. */ R_TRY(this->MakePageGroup(pg, src_address, num_pages)); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Reprotect the source as kernel-read/not mapped. */ const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(KMemoryPermission_KernelRead | KMemoryPermission_NotMapped); const KMemoryAttribute new_src_attr = KMemoryAttribute_Locked; const KPageProperties src_properties = { new_src_perm, false, false, DisableMergeAttribute_DisableHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, src_properties, OperationType_ChangePermissions, false)); /* Ensure that we unprotect the source pages on failure. */ ON_RESULT_FAILURE { const KPageProperties unprotect_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_EnableHeadBodyTail }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, unprotect_properties, OperationType_ChangePermissions, true)); }; /* Map the alias pages. */ const KPageProperties dst_map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties, false)); /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, new_src_perm, new_src_attr, KMemoryBlockDisableMergeAttribute_Locked, KMemoryBlockDisableMergeAttribute_None); m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_Stack, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); } R_SUCCEED(); } Result KPageTableBase::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate that the source address's state is valid. */ KMemoryState src_state; size_t num_src_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_NotMapped | KMemoryPermission_KernelRead, KMemoryAttribute_All, KMemoryAttribute_Locked)); /* Validate that the dst address's state is valid. */ KMemoryPermission dst_perm; size_t num_dst_allocator_blocks; R_TRY(this->CheckMemoryState(nullptr, std::addressof(dst_perm), nullptr, std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Stack, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator for the source. */ Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); /* Create an update allocator for the destination. */ Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); /* Unmap the memory. */ { /* Determine the number of pages being operated on. */ const size_t num_pages = size / PageSize; /* Create page groups for the memory being unmapped. */ KPageGroup pg(m_block_info_manager); /* Create the page group representing the destination. */ R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); /* Ensure the page group is the valid for the source. */ R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), svc::ResultInvalidMemoryRegion()); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the aliased copy of the pages. */ const KPageProperties dst_unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, dst_unmap_properties, OperationType_Unmap, false)); /* Ensure that we re-map the aliased pages on failure. */ ON_RESULT_FAILURE { this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg); }; /* Try to set the permissions for the source pages back to what they should be. */ const KPageProperties src_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_EnableAndMergeHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, src_properties, OperationType_ChangePermissions, false)); /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Locked); m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); } R_SUCCEED(); } Result KPageTableBase::MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { /* Validate the mapping request. */ R_UNLESS(this->CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Verify that the source memory is normal heap. */ KMemoryState src_state; KMemoryPermission src_perm; size_t num_src_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(src_state), std::addressof(src_perm), nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Verify that the destination memory is unmapped. */ size_t num_dst_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator for the source. */ Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); /* Create an update allocator for the destination. */ Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); /* Map the code memory. */ { /* Determine the number of pages being operated on. */ const size_t num_pages = size / PageSize; /* Create page groups for the memory being unmapped. */ KPageGroup pg(m_block_info_manager); /* Create the page group representing the source. */ R_TRY(this->MakePageGroup(pg, src_address, num_pages)); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Reprotect the source as kernel-read/not mapped. */ const KMemoryPermission new_perm = static_cast<KMemoryPermission>(KMemoryPermission_KernelRead | KMemoryPermission_NotMapped); const KPageProperties src_properties = { new_perm, false, false, DisableMergeAttribute_DisableHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, src_properties, OperationType_ChangePermissions, false)); /* Ensure that we unprotect the source pages on failure. */ ON_RESULT_FAILURE { const KPageProperties unprotect_properties = { src_perm, false, false, DisableMergeAttribute_EnableHeadBodyTail }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, unprotect_properties, OperationType_ChangePermissions, true)); }; /* Map the alias pages. */ const KPageProperties dst_properties = { new_perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false)); /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, new_perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Locked, KMemoryBlockDisableMergeAttribute_None); m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_AliasCode, new_perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); } R_SUCCEED(); } Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) { /* Validate the mapping request. */ R_UNLESS(this->CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidMemoryRegion()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Verify that the source memory is locked normal heap. */ size_t num_src_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked)); /* Verify that the destination memory is aliasable code. */ size_t num_dst_allocator_blocks; R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_FlagCanCodeAlias, KMemoryState_FlagCanCodeAlias, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All & ~KMemoryAttribute_PermissionLocked, KMemoryAttribute_None)); /* Determine whether any pages being unmapped are code. */ bool any_code_pages = false; { KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(dst_address); while (true) { /* Check if the memory has code flag. */ if ((it->GetState() & KMemoryState_FlagCode) != 0) { any_code_pages = true; break; } /* Check if we're done. */ if (dst_address + size - 1 <= it->GetLastAddress()) { break; } /* Advance. */ ++it; } } /* Ensure that we maintain the instruction cache. */ bool reprotected_pages = false; ON_SCOPE_EXIT { if (reprotected_pages && any_code_pages) { cpu::InvalidateEntireInstructionCache(); } }; /* Unmap. */ { /* Determine the number of pages being operated on. */ const size_t num_pages = size / PageSize; /* Create page groups for the memory being unmapped. */ KPageGroup pg(m_block_info_manager); /* Create the page group representing the destination. */ R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); /* Verify that the page group contains the same pages as the source. */ R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), svc::ResultInvalidMemoryRegion()); /* Create an update allocator for the source. */ Result src_allocator_result; KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result), m_memory_block_slab_manager, num_src_allocator_blocks); R_TRY(src_allocator_result); /* Create an update allocator for the destination. */ Result dst_allocator_result; KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result), m_memory_block_slab_manager, num_dst_allocator_blocks); R_TRY(dst_allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the aliased copy of the pages. */ const KPageProperties dst_unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, dst_unmap_properties, OperationType_Unmap, false)); /* Ensure that we re-map the aliased pages on failure. */ ON_RESULT_FAILURE { this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg); }; /* Try to set the permissions for the source pages back to what they should be. */ const KPageProperties src_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_EnableAndMergeHeadBodyTail }; R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, src_properties, OperationType_ChangePermissions, false)); /* Apply the memory block updates. */ m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Locked); /* Note that we reprotected pages. */ reprotected_pages = true; } R_SUCCEED(); } Result KPageTableBase::MapInsecurePhysicalMemory(KProcessAddress address, size_t size) { /* Get the insecure memory resource limit and pool. */ auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(); const auto insecure_pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetInsecureMemoryPool()); /* Reserve the insecure memory. */ /* NOTE: ResultOutOfMemory is returned here instead of the usual LimitReached. */ KScopedResourceReservation memory_reservation(insecure_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultOutOfMemory()); /* Allocate pages for the insecure memory. */ KPageGroup pg(m_block_info_manager); R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), size / PageSize, 1, KMemoryManager::EncodeOption(insecure_pool, KMemoryManager::Direction_FromFront))); /* Close the opened pages when we're done with them. */ /* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */ ON_SCOPE_EXIT { pg.Close(); }; /* Clear all the newly allocated pages. */ for (const auto &it : pg) { std::memset(GetVoidPointer(GetHeapVirtualAddress(it.GetAddress())), m_heap_fill_value, it.GetSize()); } /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate that the address's state is valid. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Map the pages. */ const size_t num_pages = size / PageSize; const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, pg, map_properties, OperationType_MapGroup, false)); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Insecure, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* Update our mapped insecure size. */ m_mapped_insecure_memory += size; /* Commit the memory reservation. */ memory_reservation.Commit(); /* We succeeded. */ R_SUCCEED(); } Result KPageTableBase::UnmapInsecurePhysicalMemory(KProcessAddress address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Insecure, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the memory. */ const size_t num_pages = size / PageSize; const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); /* Update our mapped insecure size. */ m_mapped_insecure_memory -= size; /* Release the insecure memory from the insecure limit. */ if (auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(); insecure_resource_limit != nullptr) { insecure_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size); } R_SUCCEED(); } KProcessAddress KPageTableBase::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const { KProcessAddress address = Null<KProcessAddress>; KProcessAddress search_start = Null<KProcessAddress>; KProcessAddress search_end = Null<KProcessAddress>; if (m_memory_block_manager.GetRegionForFindFreeArea(std::addressof(search_start), std::addressof(search_end), region_start, region_num_pages, num_pages, alignment, offset, guard_pages)) { if (this->IsAslrEnabled()) { /* Try to directly find a free area up to 8 times. */ for (size_t i = 0; i < 8; i++) { const size_t random_offset = KSystemControl::GenerateRandomRange(0, (search_end - search_start) / alignment) * alignment; const KProcessAddress candidate = search_start + random_offset; KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(candidate); MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end()); if (it->GetState() != KMemoryState_Free) { continue; } if (!(it->GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; } if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= it->GetLastAddress())) { continue; } address = candidate; break; } /* Fall back to finding the first free area with a random offset. */ if (address == Null<KProcessAddress>) { /* NOTE: Nintendo does not account for guard pages here. */ /* This may theoretically cause an offset to be chosen that cannot be mapped. */ /* We will account for guard pages. */ const size_t offset_blocks = KSystemControl::GenerateRandomRange(0, (search_end - search_start) / alignment); const auto region_end = region_start + region_num_pages * PageSize; address = m_memory_block_manager.FindFreeArea(search_start + offset_blocks * alignment, (region_end - (search_start + offset_blocks * alignment)) / PageSize, num_pages, alignment, offset, guard_pages); } } /* Find the first free area. */ if (address == Null<KProcessAddress>) { address = m_memory_block_manager.FindFreeArea(region_start, region_num_pages, num_pages, alignment, offset, guard_pages); } } return address; } size_t KPageTableBase::GetSize(KMemoryState state) const { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Iterate, counting blocks with the desired state. */ size_t total_size = 0; for (KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(m_address_space_start); it != m_memory_block_manager.end(); ++it) { if (it->GetState() == state) { total_size += it->GetSize(); } } return total_size; } size_t KPageTableBase::GetCodeSize() const { return this->GetSize(KMemoryState_Code); } size_t KPageTableBase::GetCodeDataSize() const { return this->GetSize(KMemoryState_CodeData); } size_t KPageTableBase::GetAliasCodeSize() const { return this->GetSize(KMemoryState_AliasCode); } size_t KPageTableBase::GetAliasCodeDataSize() const { return this->GetSize(KMemoryState_AliasCodeData); } Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties &properties) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Create a page group to hold the pages we allocate. */ KPageGroup pg(m_block_info_manager); /* Allocate the pages. */ R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, 1, m_allocate_option)); /* Ensure that the page group is closed when we're done working with it. */ ON_SCOPE_EXIT { pg.Close(); }; /* Clear all pages. */ for (const auto &it : pg) { std::memset(GetVoidPointer(GetHeapVirtualAddress(it.GetAddress())), m_heap_fill_value, it.GetSize()); } /* Map the pages. */ R_RETURN(this->Operate(page_list, address, num_pages, pg, properties, OperationType_MapGroup, false)); } Result KPageTableBase::MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Note the current address, so that we can iterate. */ const KProcessAddress start_address = address; KProcessAddress cur_address = address; /* Ensure that we clean up on failure. */ ON_RESULT_FAILURE { MESOSPHERE_ABORT_UNLESS(!reuse_ll); if (cur_address != start_address) { const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(page_list, start_address, (cur_address - start_address) / PageSize, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true)); } }; /* Iterate, mapping all pages in the group. */ for (const auto &block : pg) { /* Map and advance. */ const KPageProperties cur_properties = (cur_address == start_address) ? properties : KPageProperties{ properties.perm, properties.io, properties.uncached, DisableMergeAttribute_None }; R_TRY(this->Operate(page_list, cur_address, block.GetNumPages(), block.GetAddress(), true, cur_properties, OperationType_Map, reuse_ll)); cur_address += block.GetSize(); } /* We succeeded! */ R_SUCCEED(); } void KPageTableBase::RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Note the current address, so that we can iterate. */ const KProcessAddress start_address = address; const KProcessAddress last_address = start_address + size - 1; const KProcessAddress end_address = last_address + 1; /* Iterate over the memory. */ auto pg_it = pg.begin(); MESOSPHERE_ABORT_UNLESS(pg_it != pg.end()); KPhysicalAddress pg_phys_addr = pg_it->GetAddress(); size_t pg_pages = pg_it->GetNumPages(); auto it = m_memory_block_manager.FindIterator(start_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* Determine the range to map. */ KProcessAddress map_address = std::max(GetInteger(it->GetAddress()), GetInteger(start_address)); const KProcessAddress map_end_address = std::min(GetInteger(it->GetEndAddress()), GetInteger(end_address)); MESOSPHERE_ABORT_UNLESS(map_end_address != map_address); /* Determine if we should disable head merge. */ const bool disable_head_merge = it->GetAddress() >= GetInteger(start_address) && (it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Normal) != 0; const KPageProperties map_properties = { it->GetPermission(), false, false, disable_head_merge ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; /* While we have pages to map, map them. */ size_t map_pages = (map_end_address - map_address) / PageSize; while (map_pages > 0) { /* Check if we're at the end of the physical block. */ if (pg_pages == 0) { /* Ensure there are more pages to map. */ MESOSPHERE_ABORT_UNLESS(pg_it != pg.end()); /* Advance our physical block. */ ++pg_it; pg_phys_addr = pg_it->GetAddress(); pg_pages = pg_it->GetNumPages(); } /* Map whatever we can. */ const size_t cur_pages = std::min(pg_pages, map_pages); MESOSPHERE_R_ABORT_UNLESS(this->Operate(page_list, map_address, map_pages, pg_phys_addr, true, map_properties, OperationType_Map, true)); /* Advance. */ map_address += cur_pages * PageSize; map_pages -= cur_pages; pg_phys_addr += cur_pages * PageSize; pg_pages -= cur_pages; } /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ ++it; } /* Check that we re-mapped precisely the page group. */ MESOSPHERE_ABORT_UNLESS((++pg_it) == pg.end()); } Result KPageTableBase::MakePageGroup(KPageGroup &pg, KProcessAddress addr, size_t num_pages) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); const size_t size = num_pages * PageSize; /* We're making a new group, not adding to an existing one. */ R_UNLESS(pg.empty(), svc::ResultInvalidCurrentMemory()); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; R_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), addr), svc::ResultInvalidCurrentMemory()); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; /* Iterate, adding to group as we go. */ while (tot_size < size) { R_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)), svc::ResultInvalidCurrentMemory()); if (next_entry.phys_addr != (cur_addr + cur_size)) { const size_t cur_pages = cur_size / PageSize; R_UNLESS(IsHeapPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); R_TRY(pg.AddBlock(cur_addr, cur_pages)); cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we add the right amount for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* add the last block. */ const size_t cur_pages = cur_size / PageSize; R_UNLESS(IsHeapPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); R_TRY(pg.AddBlock(cur_addr, cur_pages)); R_SUCCEED(); } bool KPageTableBase::IsValidPageGroup(const KPageGroup &pg, KProcessAddress addr, size_t num_pages) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); const size_t size = num_pages * PageSize; /* Empty groups are necessarily invalid. */ if (pg.empty()) { return false; } auto &impl = this->GetImpl(); /* We're going to validate that the group we'd expect is the group we see. */ auto cur_it = pg.begin(); KPhysicalAddress cur_block_address = cur_it->GetAddress(); size_t cur_block_pages = cur_it->GetNumPages(); auto UpdateCurrentIterator = [&]() ALWAYS_INLINE_LAMBDA { if (cur_block_pages == 0) { if ((++cur_it) == pg.end()) { return false; } cur_block_address = cur_it->GetAddress(); cur_block_pages = cur_it->GetNumPages(); } return true; }; /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; if (!impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), addr)) { return false; } /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; /* Iterate, comparing expected to actual. */ while (tot_size < size) { if (!impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context))) { return false; } if (next_entry.phys_addr != (cur_addr + cur_size)) { const size_t cur_pages = cur_size / PageSize; if (!IsHeapPhysicalAddress(cur_addr)) { return false; } if (!UpdateCurrentIterator()) { return false; } if (cur_block_address != cur_addr || cur_block_pages < cur_pages) { return false; } cur_block_address += cur_size; cur_block_pages -= cur_pages; cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we compare the right amount for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } if (!IsHeapPhysicalAddress(cur_addr)) { return false; } if (!UpdateCurrentIterator()) { return false; } return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize); } Result KPageTableBase::GetContiguousMemoryRangeWithState(MemoryRange *out, KProcessAddress address, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); auto &impl = this->GetImpl(); /* Begin a traversal. */ TraversalContext context; TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 }; R_UNLESS(impl.BeginTraversal(std::addressof(cur_entry), std::addressof(context), address), svc::ResultInvalidCurrentMemory()); /* Traverse until we have enough size or we aren't contiguous any more. */ const KPhysicalAddress phys_address = cur_entry.phys_addr; const u8 entry_attr = cur_entry.attr; size_t contig_size; for (contig_size = cur_entry.block_size - (GetInteger(phys_address) & (cur_entry.block_size - 1)); contig_size < size; contig_size += cur_entry.block_size) { if (!impl.ContinueTraversal(std::addressof(cur_entry), std::addressof(context))) { break; } if (cur_entry.phys_addr != phys_address + contig_size) { break; } if (cur_entry.attr != entry_attr) { break; } } /* Take the minimum size for our region. */ size = std::min(size, contig_size); /* Check that the memory is contiguous (modulo the reference count bit). */ const u32 test_state_mask = state_mask | KMemoryState_FlagReferenceCounted; const bool is_heap = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr)); if (!is_heap) { R_TRY(this->CheckMemoryStateContiguous(address, size, test_state_mask, state, perm_mask, perm, attr_mask, attr)); } /* The memory is contiguous, so set the output range. */ out->Set(phys_address, size, is_heap, attr); R_SUCCEED(); } Result KPageTableBase::SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission svc_perm) { const size_t num_pages = size / PageSize; /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Verify we can change the memory permission. */ KMemoryState old_state; KMemoryPermission old_perm; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), addr, size, KMemoryState_FlagCanReprotect, KMemoryState_FlagCanReprotect, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Determine new perm. */ const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); R_SUCCEED_IF(old_perm == new_perm); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform mapping operation. */ const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, new_perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None); R_SUCCEED(); } Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission svc_perm) { const size_t num_pages = size / PageSize; /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Verify we can change the memory permission. */ KMemoryState old_state; KMemoryPermission old_perm; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), addr, size, KMemoryState_FlagCode, KMemoryState_FlagCode, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Make a new page group for the region. */ KPageGroup pg(m_block_info_manager); /* Determine new perm/state. */ const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); KMemoryState new_state = old_state; const bool is_w = (new_perm & KMemoryPermission_UserWrite) == KMemoryPermission_UserWrite; const bool is_x = (new_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute; const bool was_x = (old_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute; MESOSPHERE_ASSERT(!(is_w && is_x)); if (is_w) { switch (old_state) { case KMemoryState_Code: new_state = KMemoryState_CodeData; break; case KMemoryState_AliasCode: new_state = KMemoryState_AliasCodeData; break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } /* Create a page group, if we're setting execute permissions. */ if (is_x) { R_TRY(this->MakePageGroup(pg, GetInteger(addr), num_pages)); } /* Succeed if there's nothing to do. */ R_SUCCEED_IF(old_perm == new_perm && old_state == new_state); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* If we're creating an executable mapping, take and immediately release the scheduler lock. This will force a reschedule. */ if (is_x) { KScopedSchedulerLock sl; } /* Ensure cache coherency, if we're setting pages as executable. */ if (is_x) { for (const auto &block : pg) { MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetHeapVirtualAddress(block.GetAddress())), block.GetSize())); } cpu::InvalidateEntireInstructionCache(); } /* Perform mapping operation. */ const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None }; const auto operation = was_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, new_state, new_perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None); /* Ensure cache coherency, if we're setting pages as executable. */ if (was_x) { cpu::InvalidateEntireInstructionCache(); } R_SUCCEED(); } Result KPageTableBase::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr) { const size_t num_pages = size / PageSize; MESOSPHERE_ASSERT((mask | KMemoryAttribute_SetMask) == KMemoryAttribute_SetMask); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Verify we can change the memory attribute. */ KMemoryState old_state; KMemoryPermission old_perm; KMemoryAttribute old_attr; size_t num_allocator_blocks; constexpr u32 AttributeTestMask = ~(KMemoryAttribute_SetMask | KMemoryAttribute_DeviceShared); const u32 state_test_mask = ((mask & KMemoryAttribute_Uncached) ? static_cast<u32>(KMemoryState_FlagCanChangeAttribute) : 0) | ((mask & KMemoryAttribute_PermissionLocked) ? static_cast<u32>(KMemoryState_FlagCanPermissionLock) : 0); R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), addr, size, state_test_mask, state_test_mask, KMemoryPermission_None, KMemoryPermission_None, AttributeTestMask, KMemoryAttribute_None, ~AttributeTestMask)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* If we need to, perform a change attribute operation. */ if ((mask & KMemoryAttribute_Uncached) != 0) { /* Determine the new attribute. */ const KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(((old_attr & ~mask) | (attr & mask))); /* Perform operation. */ const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefreshAndFlush, false)); } /* Update the blocks. */ m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages, mask, attr); R_SUCCEED(); } Result KPageTableBase::SetHeapSize(KProcessAddress *out, size_t size) { /* Lock the physical memory mutex. */ KScopedLightLock map_phys_mem_lk(m_map_physical_memory_lock); /* Try to perform a reduction in heap, instead of an extension. */ KProcessAddress cur_address; size_t allocation_size; { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate that setting heap size is possible at all. */ R_UNLESS(!m_is_kernel, svc::ResultOutOfMemory()); R_UNLESS(size <= static_cast<size_t>(m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]), svc::ResultOutOfMemory()); R_UNLESS(size <= m_max_heap_size, svc::ResultOutOfMemory()); if (size < static_cast<size_t>(m_current_heap_end - m_region_starts[RegionType_Heap])) { /* The size being requested is less than the current size, so we need to free the end of the heap. */ /* Validate memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), m_region_starts[RegionType_Heap] + size, (m_current_heap_end - m_region_starts[RegionType_Heap]) - size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the end of the heap. */ const size_t num_pages = ((m_current_heap_end - m_region_starts[RegionType_Heap]) - size) / PageSize; const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), m_region_starts[RegionType_Heap] + size, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Release the memory from the resource limit. */ m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, num_pages * PageSize); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), m_region_starts[RegionType_Heap] + size, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, size == 0 ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None); /* Update the current heap end. */ m_current_heap_end = m_region_starts[RegionType_Heap] + size; /* Set the output. */ *out = m_region_starts[RegionType_Heap]; R_SUCCEED(); } else if (size == static_cast<size_t>(m_current_heap_end - m_region_starts[RegionType_Heap])) { /* The size requested is exactly the current size. */ *out = m_region_starts[RegionType_Heap]; R_SUCCEED(); } else { /* We have to allocate memory. Determine how much to allocate and where while the table is locked. */ cur_address = m_current_heap_end; allocation_size = size - (m_current_heap_end - m_region_starts[RegionType_Heap]); } } /* Reserve memory for the heap extension. */ KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, allocation_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Allocate pages for the heap extension. */ KPageGroup pg(m_block_info_manager); R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), allocation_size / PageSize, 1, m_allocate_option)); /* Close the opened pages when we're done with them. */ /* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */ ON_SCOPE_EXIT { pg.Close(); }; /* Clear all the newly allocated pages. */ for (const auto &it : pg) { std::memset(GetVoidPointer(GetHeapVirtualAddress(it.GetAddress())), m_heap_fill_value, it.GetSize()); } /* Map the pages. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Ensure that the heap hasn't changed since we began executing. */ MESOSPHERE_ABORT_UNLESS(cur_address == m_current_heap_end); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), m_current_heap_end, allocation_size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Map the pages. */ const size_t num_pages = allocation_size / PageSize; const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, (m_current_heap_end == m_region_starts[RegionType_Heap]) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), m_current_heap_end, num_pages, pg, map_properties, OperationType_MapGroup, false)); /* We succeeded, so commit our memory reservation. */ memory_reservation.Commit(); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), m_current_heap_end, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, m_region_starts[RegionType_Heap] == m_current_heap_end ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None); /* Update the current heap end. */ m_current_heap_end = m_region_starts[RegionType_Heap] + size; /* Set the output. */ *out = m_region_starts[RegionType_Heap]; R_SUCCEED(); } } Result KPageTableBase::SetMaxHeapSize(size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Only process page tables are allowed to set heap size. */ MESOSPHERE_ASSERT(!this->IsKernel()); m_max_heap_size = size; R_SUCCEED(); } Result KPageTableBase::QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const { /* If the address is invalid, create a fake block. */ if (!this->Contains(addr, 1)) { *out_info = { .m_address = GetInteger(m_address_space_end), .m_size = 0 - GetInteger(m_address_space_end), .m_state = static_cast<KMemoryState>(ams::svc::MemoryState_Inaccessible), .m_device_disable_merge_left_count = 0, .m_device_disable_merge_right_count = 0, .m_ipc_lock_count = 0, .m_device_use_count = 0, .m_ipc_disable_merge_count = 0, .m_permission = KMemoryPermission_None, .m_attribute = KMemoryAttribute_None, .m_original_permission = KMemoryPermission_None, .m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None, }; out_page_info->flags = 0; R_SUCCEED(); } /* Otherwise, lock the table and query. */ KScopedLightLock lk(m_general_lock); R_RETURN(this->QueryInfoImpl(out_info, out_page_info, addr)); } Result KPageTableBase::QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Align the address down to page size. */ address = util::AlignDown(GetInteger(address), PageSize); /* Verify that we can query the address. */ KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address); R_UNLESS(it != m_memory_block_manager.end(), svc::ResultInvalidCurrentMemory()); /* Check the memory state. */ R_TRY(this->CheckMemoryState(it, KMemoryState_FlagCanQueryPhysical, KMemoryState_FlagCanQueryPhysical, KMemoryPermission_UserReadExecute, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); /* Prepare to traverse. */ KPhysicalAddress phys_addr; size_t phys_size; KProcessAddress virt_addr = it->GetAddress(); KProcessAddress end_addr = it->GetEndAddress(); /* Perform traversal. */ { /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = m_impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr); R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory()); /* Set tracking variables. */ phys_addr = next_entry.phys_addr; phys_size = next_entry.block_size - (GetInteger(phys_addr) & (next_entry.block_size - 1)); /* Iterate. */ while (true) { /* Continue the traversal. */ traverse_valid = m_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); if (!traverse_valid) { break; } if (next_entry.phys_addr != (phys_addr + phys_size)) { /* Check if we're done. */ if (virt_addr <= address && address <= virt_addr + phys_size - 1) { break; } /* Advance. */ phys_addr = next_entry.phys_addr; virt_addr += next_entry.block_size; phys_size = next_entry.block_size - (GetInteger(phys_addr) & (next_entry.block_size - 1)); } else { phys_size += next_entry.block_size; } /* Check if we're done. */ if (end_addr < virt_addr + phys_size) { break; } } MESOSPHERE_ASSERT(virt_addr <= address && address <= virt_addr + phys_size - 1); /* Ensure we use the right size. */ if (end_addr < virt_addr + phys_size) { phys_size = end_addr - virt_addr; } } /* Set the output. */ out->physical_address = GetInteger(phys_addr); out->virtual_address = GetInteger(virt_addr); out->size = phys_size; R_SUCCEED(); } Result KPageTableBase::MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryState state, KMemoryPermission perm) { /* Check pre-conditions. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(size, PageSize)); MESOSPHERE_ASSERT(size > 0); R_UNLESS(phys_addr < phys_addr + size, svc::ResultInvalidAddress()); const size_t num_pages = size / PageSize; const KPhysicalAddress last = phys_addr + size - 1; /* Get region extents. */ const KProcessAddress region_start = m_region_starts[RegionType_KernelMap]; const size_t region_size = m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; const size_t region_num_pages = region_size / PageSize; MESOSPHERE_ASSERT(this->CanContain(region_start, region_size, state)); /* Locate the memory region. */ const KMemoryRegion *region = KMemoryLayout::Find(phys_addr); R_UNLESS(region != nullptr, svc::ResultInvalidAddress()); MESOSPHERE_ASSERT(region->Contains(GetInteger(phys_addr))); /* Ensure that the region is mappable. */ const bool is_rw = perm == KMemoryPermission_UserReadWrite; while (true) { /* Check that the region exists. */ R_UNLESS(region != nullptr, svc::ResultInvalidAddress()); /* Check the region attributes. */ R_UNLESS(!region->IsDerivedFrom(KMemoryRegionType_Dram), svc::ResultInvalidAddress()); R_UNLESS(!region->HasTypeAttribute(KMemoryRegionAttr_UserReadOnly) || !is_rw, svc::ResultInvalidAddress()); R_UNLESS(!region->HasTypeAttribute(KMemoryRegionAttr_NoUserMap), svc::ResultInvalidAddress()); /* Check if we're done. */ if (GetInteger(last) <= region->GetLastAddress()) { break; } /* Advance. */ region = region->GetNext(); }; /* Select an address to map at. */ KProcessAddress addr = Null<KProcessAddress>; for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) { const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type)); const KPhysicalAddress aligned_phys = util::AlignUp(GetInteger(phys_addr), alignment) + alignment - 1; if (aligned_phys <= phys_addr) { continue; } const KPhysicalAddress last_aligned_paddr = util::AlignDown(GetInteger(last) + 1, alignment) - 1; if (!(last_aligned_paddr <= last && aligned_phys <= last_aligned_paddr)) { continue; } addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0, this->GetNumGuardPages()); if (addr != Null<KProcessAddress>) { break; } } R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory()); /* Check that we can map IO here. */ MESOSPHERE_ASSERT(this->CanContain(addr, size, state)); MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Perform mapping operation. */ const KPageProperties properties = { perm, state == KMemoryState_IoRegister, false, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(page_list, addr, num_pages, phys_addr, true, properties, OperationType_Map, false)); /* Set the output address. */ *out = addr; R_SUCCEED(); } Result KPageTableBase::MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Map the io memory. */ KProcessAddress addr; R_TRY(this->MapIoImpl(std::addressof(addr), updater.GetPageList(), phys_addr, size, KMemoryState_IoRegister, perm)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, size / PageSize, KMemoryState_IoRegister, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ R_SUCCEED(); } Result KPageTableBase::MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission svc_perm) { const size_t num_pages = size / PageSize; /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_None, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform mapping operation. */ const KMemoryPermission perm = ConvertToKMemoryPermission(svc_perm); const KPageProperties properties = { perm, mapping == ams::svc::MemoryMapping_IoRegister, mapping == ams::svc::MemoryMapping_Uncached, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false)); /* Update the blocks. */ const auto state = mapping == ams::svc::MemoryMapping_Memory ? KMemoryState_IoMemory : KMemoryState_IoRegister; m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, state, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ R_SUCCEED(); } Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) { const size_t num_pages = size / PageSize; /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate the memory state. */ KMemoryState old_state; KMemoryPermission old_perm; KMemoryAttribute old_attr; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, mapping == ams::svc::MemoryMapping_Memory ? KMemoryState_IoMemory : KMemoryState_IoRegister, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked)); /* Validate that the region being unmapped corresponds to the physical range described. */ { /* Get the impl. */ auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; MESOSPHERE_ABORT_UNLESS(impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), dst_address)); /* Check that the physical region matches. */ R_UNLESS(next_entry.phys_addr == phys_addr, svc::ResultInvalidMemoryRegion()); /* Iterate. */ for (size_t checked_size = next_entry.block_size - (GetInteger(phys_addr) & (next_entry.block_size - 1)); checked_size < size; checked_size += next_entry.block_size) { /* Continue the traversal. */ MESOSPHERE_ABORT_UNLESS(impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context))); /* Check that the physical region matches. */ R_UNLESS(next_entry.phys_addr == phys_addr + checked_size, svc::ResultInvalidMemoryRegion()); } } /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* If the region being unmapped is Memory, synchronize. */ if (mapping == ams::svc::MemoryMapping_Memory) { /* Change the region to be uncached. */ const KPageProperties properties = { old_perm, false, true, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefresh, false)); /* Temporarily unlock ourselves, so that other operations can occur while we flush the region. */ m_general_lock.Unlock(); ON_SCOPE_EXIT { m_general_lock.Lock(); }; /* Flush the region. */ MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(dst_address), size)); } /* Perform the unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); R_SUCCEED(); } Result KPageTableBase::MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(size, PageSize)); MESOSPHERE_ASSERT(size > 0); R_UNLESS(phys_addr < phys_addr + size, svc::ResultInvalidAddress()); const size_t num_pages = size / PageSize; const KPhysicalAddress last = phys_addr + size - 1; /* Get region extents. */ const KProcessAddress region_start = this->GetRegionAddress(KMemoryState_Static); const size_t region_size = this->GetRegionSize(KMemoryState_Static); const size_t region_num_pages = region_size / PageSize; /* Locate the memory region. */ const KMemoryRegion *region = KMemoryLayout::Find(phys_addr); R_UNLESS(region != nullptr, svc::ResultInvalidAddress()); MESOSPHERE_ASSERT(region->Contains(GetInteger(phys_addr))); R_UNLESS(GetInteger(last) <= region->GetLastAddress(), svc::ResultInvalidAddress()); /* Check the region attributes. */ const bool is_rw = perm == KMemoryPermission_UserReadWrite; R_UNLESS( region->IsDerivedFrom(KMemoryRegionType_Dram), svc::ResultInvalidAddress()); R_UNLESS(!region->HasTypeAttribute(KMemoryRegionAttr_NoUserMap), svc::ResultInvalidAddress()); R_UNLESS(!region->HasTypeAttribute(KMemoryRegionAttr_UserReadOnly) || !is_rw, svc::ResultInvalidAddress()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Select an address to map at. */ KProcessAddress addr = Null<KProcessAddress>; for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) { const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type)); const KPhysicalAddress aligned_phys = util::AlignUp(GetInteger(phys_addr), alignment) + alignment - 1; if (aligned_phys <= phys_addr) { continue; } const KPhysicalAddress last_aligned_paddr = util::AlignDown(GetInteger(last) + 1, alignment) - 1; if (!(last_aligned_paddr <= last && aligned_phys <= last_aligned_paddr)) { continue; } addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0, this->GetNumGuardPages()); if (addr != Null<KProcessAddress>) { break; } } R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory()); /* Check that we can map static here. */ MESOSPHERE_ASSERT(this->CanContain(addr, size, KMemoryState_Static)); MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform mapping operation. */ const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties, OperationType_Map, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, KMemoryState_Static, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ R_SUCCEED(); } Result KPageTableBase::MapRegion(KMemoryRegionType region_type, KMemoryPermission perm) { /* Get the memory region. */ const KMemoryRegion *region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(region_type); R_UNLESS(region != nullptr, svc::ResultOutOfRange()); /* Check that the region is valid. */ MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0); /* Map the region. */ R_TRY_CATCH(this->MapStatic(region->GetAddress(), region->GetSize(), perm)) { R_CONVERT(svc::ResultInvalidAddress, svc::ResultOutOfRange()) } R_END_TRY_CATCH; R_SUCCEED(); } Result KPageTableBase::MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { MESOSPHERE_ASSERT(util::IsAligned(alignment, PageSize) && alignment >= PageSize); /* Ensure this is a valid map request. */ R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state), svc::ResultInvalidCurrentMemory()); R_UNLESS(num_pages < region_num_pages, svc::ResultOutOfMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Find a random address to map at. */ KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0, this->GetNumGuardPages()); R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory()); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), alignment)); MESOSPHERE_ASSERT(this->CanContain(addr, num_pages * PageSize, state)); MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform mapping operation. */ const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead }; if (is_pa_valid) { R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties, OperationType_Map, false)); } else { R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, properties)); } /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ *out_addr = addr; R_SUCCEED(); } Result KPageTableBase::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm) { /* Check that the map is in range. */ const size_t size = num_pages * PageSize; R_UNLESS(this->CanContain(address, size, state), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Map the pages. */ const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, properties)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); R_SUCCEED(); } Result KPageTableBase::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) { /* Check that the unmap is in range. */ const size_t size = num_pages * PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform the unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); R_SUCCEED(); } Result KPageTableBase::MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread()); /* Ensure this is a valid map request. */ const size_t num_pages = pg.GetNumPages(); R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state), svc::ResultInvalidCurrentMemory()); R_UNLESS(num_pages < region_num_pages, svc::ResultOutOfMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Find a random address to map at. */ KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize, 0, this->GetNumGuardPages()); R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory()); MESOSPHERE_ASSERT(this->CanContain(addr, num_pages * PageSize, state)); MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform mapping operation. */ const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ *out_addr = addr; R_SUCCEED(); } Result KPageTableBase::MapPageGroup(KProcessAddress addr, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm) { MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread()); /* Ensure this is a valid map request. */ const size_t num_pages = pg.GetNumPages(); const size_t size = num_pages * PageSize; R_UNLESS(this->CanContain(addr, size, state), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check if state allows us to map. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Ensure cache coherency, if we're mapping executable pages. */ if ((perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute) { cpu::InvalidateEntireInstructionCache(); } /* Perform mapping operation. */ const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* We successfully mapped the pages. */ R_SUCCEED(); } Result KPageTableBase::UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state) { MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread()); /* Ensure this is a valid unmap request. */ const size_t num_pages = pg.GetNumPages(); const size_t size = num_pages * PageSize; R_UNLESS(this->CanContain(address, size, state), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check if state allows us to unmap. */ KMemoryPermission old_perm; size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(nullptr, std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Check that the page group is valid. */ R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), svc::ResultInvalidCurrentMemory()); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Perform unmapping operation. */ const KPageProperties properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_Unmap, false)); /* Ensure cache coherency, if we're mapping executable pages. */ if ((old_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute) { cpu::InvalidateEntireInstructionCache(); } /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); R_SUCCEED(); } Result KPageTableBase::MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) { /* Ensure that the page group isn't null. */ MESOSPHERE_ASSERT(out != nullptr); /* Make sure that the region we're mapping is valid for the table. */ const size_t size = num_pages * PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check if state allows us to create the group. */ R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr)); /* Create a new page group for the region. */ R_TRY(this->MakePageGroup(*out, address, num_pages)); /* Open a new reference to the pages in the group. */ out->Open(); R_SUCCEED(); } Result KPageTableBase::InvalidateProcessDataCache(KProcessAddress address, size_t size) { /* Check that the region is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_Uncached, KMemoryAttribute_None)); /* Get the impl. */ auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), address); R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory()); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory()); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Check that the pages are linearly mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Invalidate the block. */ if (cur_size > 0) { MESOSPHERE_R_ABORT_UNLESS(cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size)); } /* Advance. */ cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Check that the last block is linearly mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Invalidate the last block. */ if (cur_size > 0) { MESOSPHERE_R_ABORT_UNLESS(cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size)); } R_SUCCEED(); } Result KPageTableBase::InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) { /* Check pre-condition: this is being called on the current process. */ MESOSPHERE_ASSERT(this == std::addressof(GetCurrentProcess().GetPageTable().GetBasePageTable())); /* Check that the region is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_Uncached, KMemoryAttribute_None)); /* Invalidate the data cache. */ R_RETURN(cpu::InvalidateDataCache(GetVoidPointer(address), size)); } bool KPageTableBase::CanReadWriteDebugMemory(KProcessAddress address, size_t size, bool force_debug_prod) { /* Check pre-conditions. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* If the memory is debuggable and user-readable, we can perform the access. */ if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) { return true; } /* If we're in debug mode, and the process isn't force debug prod, check if the memory is debuggable and kernel-readable and user-executable. */ if (KTargetSystem::IsDebugMode() && !force_debug_prod) { if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryAttribute_None, KMemoryAttribute_None))) { return true; } } /* If neither of the above checks passed, we can't access the memory. */ return false; } Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) { /* Lightly validate the region is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Require that the memory either be user-readable-and-mapped or debug-accessible. */ const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); if (!can_read) { R_UNLESS(this->CanReadWriteDebugMemory(address, size, force_debug_prod), svc::ResultInvalidCurrentMemory()); } /* Get the impl. */ auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), address); R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory()); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy as much aligned data as we can. */ if (cur_size >= sizeof(u32)) { const size_t copy_size = util::AlignDown(cur_size, sizeof(u32)); const void * copy_src = GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)); MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(copy_src, copy_size)); R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(buffer, copy_src, copy_size), svc::ResultInvalidPointer()); buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + copy_size); cur_addr += copy_size; cur_size -= copy_size; } /* Copy remaining data. */ if (cur_size > 0) { const void * copy_src = GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)); MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(copy_src, cur_size)); R_UNLESS(UserspaceAccess::CopyMemoryToUser(buffer, copy_src, cur_size), svc::ResultInvalidPointer()); } R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + cur_size); cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); R_SUCCEED(); } Result KPageTableBase::WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) { /* Lightly validate the region is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Require that the memory either be user-writable-and-mapped or debug-accessible. */ const bool can_write = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None)); if (!can_write) { R_UNLESS(this->CanReadWriteDebugMemory(address, size, false), svc::ResultInvalidCurrentMemory()); } /* Get the impl. */ auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), address); R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory()); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy as much aligned data as we can. */ if (cur_size >= sizeof(u32)) { const size_t copy_size = util::AlignDown(cur_size, sizeof(u32)); R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), buffer, copy_size), svc::ResultInvalidCurrentMemory()); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), copy_size)); buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + copy_size); cur_addr += copy_size; cur_size -= copy_size; } /* Copy remaining data. */ if (cur_size > 0) { R_UNLESS(UserspaceAccess::CopyMemoryFromUser(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), buffer, cur_size), svc::ResultInvalidCurrentMemory()); MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size)); } R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(buffer) + cur_size); cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); /* Invalidate the entire instruction cache, as this svc allows modifying executable pages. */ cpu::InvalidateEntireInstructionCache(); R_SUCCEED(); } Result KPageTableBase::ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size, KMemoryState state) { /* Check pre-conditions. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Determine the mapping extents. */ const KPhysicalAddress map_start = util::AlignDown(GetInteger(phys_addr), PageSize); const KPhysicalAddress map_end = util::AlignUp(GetInteger(phys_addr) + size, PageSize); const size_t map_size = map_end - map_start; /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Temporarily map the io memory. */ KProcessAddress io_addr; R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, state, KMemoryPermission_UserRead)); /* Ensure we unmap the io memory when we're done with it. */ ON_SCOPE_EXIT { const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true)); }; /* Read the memory. */ const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); switch ((GetInteger(read_addr) | size) & 3) { case 0: { R_UNLESS(UserspaceAccess::ReadIoMemory32Bit(buffer, GetVoidPointer(read_addr), size), svc::ResultInvalidPointer()); } break; case 2: { R_UNLESS(UserspaceAccess::ReadIoMemory16Bit(buffer, GetVoidPointer(read_addr), size), svc::ResultInvalidPointer()); } break; default: { R_UNLESS(UserspaceAccess::ReadIoMemory8Bit(buffer, GetVoidPointer(read_addr), size), svc::ResultInvalidPointer()); } break; } R_SUCCEED(); } Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size, KMemoryState state) { /* Check pre-conditions. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); /* Determine the mapping extents. */ const KPhysicalAddress map_start = util::AlignDown(GetInteger(phys_addr), PageSize); const KPhysicalAddress map_end = util::AlignUp(GetInteger(phys_addr) + size, PageSize); const size_t map_size = map_end - map_start; /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Temporarily map the io memory. */ KProcessAddress io_addr; R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, state, KMemoryPermission_UserReadWrite)); /* Ensure we unmap the io memory when we're done with it. */ ON_SCOPE_EXIT { const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true)); }; /* Read the memory. */ const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); switch ((GetInteger(write_addr) | size) & 3) { case 0: { R_UNLESS(UserspaceAccess::WriteIoMemory32Bit(GetVoidPointer(write_addr), buffer, size), svc::ResultInvalidPointer()); } break; case 2: { R_UNLESS(UserspaceAccess::WriteIoMemory16Bit(GetVoidPointer(write_addr), buffer, size), svc::ResultInvalidPointer()); } break; default: { R_UNLESS(UserspaceAccess::WriteIoMemory8Bit(GetVoidPointer(write_addr), buffer, size), svc::ResultInvalidPointer()); } break; } R_SUCCEED(); } Result KPageTableBase::ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* We need to lock both this table, and the current process's table, so set up some aliases. */ KPageTableBase &src_page_table = *this; KPageTableBase &dst_page_table = GetCurrentProcess().GetPageTable().GetBasePageTable(); /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* Check that the desired range is readable io memory. */ R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)); /* Read the memory. */ u8 *dst = static_cast<u8 *>(buffer); const KProcessAddress last_address = address + size - 1; while (address <= last_address) { /* Get the current physical address. */ KPhysicalAddress phys_addr; MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address)); /* Determine the current read size. */ const size_t cur_size = std::min<size_t>(last_address - address + 1, PageSize - (GetInteger(address) & (PageSize - 1))); /* Read. */ R_TRY(dst_page_table.ReadIoMemoryImpl(dst, phys_addr, cur_size, state)); /* Advance. */ address += cur_size; dst += cur_size; } R_SUCCEED(); } Result KPageTableBase::WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* We need to lock both this table, and the current process's table, so set up some aliases. */ KPageTableBase &src_page_table = *this; KPageTableBase &dst_page_table = GetCurrentProcess().GetPageTable().GetBasePageTable(); /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* Check that the desired range is writable io memory. */ R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, state, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None)); /* Read the memory. */ const u8 *src = static_cast<const u8 *>(buffer); const KProcessAddress last_address = address + size - 1; while (address <= last_address) { /* Get the current physical address. */ KPhysicalAddress phys_addr; MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address)); /* Determine the current read size. */ const size_t cur_size = std::min<size_t>(last_address - address + 1, PageSize - (GetInteger(address) & (PageSize - 1))); /* Read. */ R_TRY(dst_page_table.WriteIoMemoryImpl(phys_addr, src, cur_size, state)); /* Advance. */ address += cur_size; src += cur_size; } R_SUCCEED(); } Result KPageTableBase::LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); size_t num_allocator_blocks; KMemoryState old_state; R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Update the memory blocks. */ m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None); /* Set whether the locked memory was io. */ *out_is_io = static_cast<ams::svc::MemoryState>(old_state & KMemoryState_Mask) == ams::svc::MemoryState_Io; R_SUCCEED(); } Result KPageTableBase::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ const u32 test_state = KMemoryState_FlagCanDeviceMap | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None); size_t num_allocator_blocks; R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_allocator_blocks), address, size, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Update the memory blocks. */ const KMemoryBlockManager::MemoryBlockLockFunction lock_func = m_enable_device_address_space_merge ? &KMemoryBlock::UpdateDeviceDisableMergeStateForShare : &KMemoryBlock::UpdateDeviceDisableMergeStateForShareRight; m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, lock_func, KMemoryPermission_None); R_SUCCEED(); } Result KPageTableBase::UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_allocator_blocks), address, size, KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Update the memory blocks. */ m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::UnshareToDevice, KMemoryPermission_None); R_SUCCEED(); } Result KPageTableBase::UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size) { /* Lightly validate the range before doing anything else. */ const size_t num_pages = size / PageSize; R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check memory state. */ size_t allocator_num_blocks = 0; R_TRY(this->CheckMemoryStateContiguous(std::addressof(allocator_num_blocks), address, size, KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared)); /* Create an update allocator for the region. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, allocator_num_blocks); R_TRY(allocator_result); /* Update the memory blocks. */ m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, m_enable_device_address_space_merge ? &KMemoryBlock::UpdateDeviceDisableMergeStateForUnshare : &KMemoryBlock::UpdateDeviceDisableMergeStateForUnshareRight, KMemoryPermission_None); R_SUCCEED(); } Result KPageTableBase::OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::MemoryRange *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Get the range. */ const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap); R_TRY(this->GetContiguousMemoryRangeWithState(out, address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None)); /* We got the range, so open it. */ out->Open(); R_SUCCEED(); } Result KPageTableBase::OpenMemoryRangeForUnmapDeviceAddressSpace(MemoryRange *out, KProcessAddress address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Get the range. */ R_TRY(this->GetContiguousMemoryRangeWithState(out, address, size, KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared)); /* We got the range, so open it. */ out->Open(); R_SUCCEED(); } Result KPageTableBase::LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) { R_RETURN(this->LockMemoryAndOpen(nullptr, out, address, size, KMemoryState_FlagCanIpcUserBuffer, KMemoryState_FlagCanIpcUserBuffer, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None, static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite), KMemoryAttribute_Locked)); } Result KPageTableBase::UnlockForIpcUserBuffer(KProcessAddress address, size_t size) { R_RETURN(this->UnlockMemory(address, size, KMemoryState_FlagCanIpcUserBuffer, KMemoryState_FlagCanIpcUserBuffer, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked, KMemoryPermission_UserReadWrite, KMemoryAttribute_Locked, nullptr)); } Result KPageTableBase::LockForTransferMemory(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm) { R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState_FlagCanTransfer, KMemoryState_FlagCanTransfer, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None, perm, KMemoryAttribute_Locked)); } Result KPageTableBase::UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup &pg) { R_RETURN(this->UnlockMemory(address, size, KMemoryState_FlagCanTransfer, KMemoryState_FlagCanTransfer, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked, KMemoryPermission_UserReadWrite, KMemoryAttribute_Locked, std::addressof(pg))); } Result KPageTableBase::LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size) { R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState_FlagCanCodeMemory, KMemoryState_FlagCanCodeMemory, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None, static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite), KMemoryAttribute_Locked)); } Result KPageTableBase::UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg) { R_RETURN(this->UnlockMemory(address, size, KMemoryState_FlagCanCodeMemory, KMemoryState_FlagCanCodeMemory, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked, KMemoryPermission_UserReadWrite, KMemoryAttribute_Locked, std::addressof(pg))); } Result KPageTableBase::OpenMemoryRangeForProcessCacheOperation(MemoryRange *out, KProcessAddress address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Get the range. */ R_TRY(this->GetContiguousMemoryRangeWithState(out, address, size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_Uncached, KMemoryAttribute_None)); /* We got the range, so open it. */ out->Open(); R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(src_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check memory state. */ R_TRY(this->CheckMemoryStateContiguous(src_addr, size, src_state_mask, src_state, src_test_perm, src_test_perm, src_attr_mask | KMemoryAttribute_Uncached, src_attr)); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), src_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy as much aligned data as we can. */ if (cur_size >= sizeof(u32)) { const size_t copy_size = util::AlignDown(cur_size, sizeof(u32)); R_UNLESS(UserspaceAccess::CopyMemoryToUserAligned32Bit(GetVoidPointer(dst_addr), GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), copy_size), svc::ResultInvalidCurrentMemory()); dst_addr += copy_size; cur_addr += copy_size; cur_size -= copy_size; } /* Copy remaining data. */ if (cur_size > 0) { R_UNLESS(UserspaceAccess::CopyMemoryToUser(GetVoidPointer(dst_addr), GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size), svc::ResultInvalidCurrentMemory()); } R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ dst_addr += cur_size; cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); } R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(src_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check memory state. */ R_TRY(this->CheckMemoryStateContiguous(src_addr, size, src_state_mask, src_state, src_test_perm, src_test_perm, src_attr_mask | KMemoryAttribute_Uncached, src_attr)); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), src_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy the data. */ std::memcpy(GetVoidPointer(dst_addr), GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size); R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ dst_addr += cur_size; cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); } R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(dst_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check memory state. */ R_TRY(this->CheckMemoryStateContiguous(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_test_perm, dst_attr_mask | KMemoryAttribute_Uncached, dst_attr)); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), dst_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy as much aligned data as we can. */ if (cur_size >= sizeof(u32)) { const size_t copy_size = util::AlignDown(cur_size, sizeof(u32)); R_UNLESS(UserspaceAccess::CopyMemoryFromUserAligned32Bit(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), GetVoidPointer(src_addr), copy_size), svc::ResultInvalidCurrentMemory()); src_addr += copy_size; cur_addr += copy_size; cur_size -= copy_size; } /* Copy remaining data. */ if (cur_size > 0) { R_UNLESS(UserspaceAccess::CopyMemoryFromUser(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), GetVoidPointer(src_addr), cur_size), svc::ResultInvalidCurrentMemory()); } R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ src_addr += cur_size; cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); } R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) { /* Lightly validate the range before doing anything else. */ R_UNLESS(this->Contains(dst_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check memory state. */ R_TRY(this->CheckMemoryStateContiguous(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_test_perm, dst_attr_mask | KMemoryAttribute_Uncached, dst_attr)); auto &impl = this->GetImpl(); /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), dst_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_addr = next_entry.phys_addr; size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1)); size_t tot_size = cur_size; auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result { /* Ensure the address is linear mapped. */ R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory()); /* Copy the data. */ std::memcpy(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), GetVoidPointer(src_addr), cur_size); R_SUCCEED(); }; /* Iterate. */ while (tot_size < size) { /* Continue the traversal. */ traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); if (next_entry.phys_addr != (cur_addr + cur_size)) { /* Perform copy. */ R_TRY(PerformCopy()); /* Advance. */ src_addr += cur_size; cur_addr = next_entry.phys_addr; cur_size = next_entry.block_size; } else { cur_size += next_entry.block_size; } tot_size += next_entry.block_size; } /* Ensure we use the right size for the last block. */ if (tot_size > size) { cur_size -= (tot_size - size); } /* Perform copy for the last block. */ R_TRY(PerformCopy()); } R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromHeapToHeap(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { /* For convenience, alias this. */ KPageTableBase &src_page_table = *this; /* Lightly validate the ranges before doing anything else. */ R_UNLESS(src_page_table.Contains(src_addr, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_page_table.Contains(dst_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* Check memory state. */ R_TRY(src_page_table.CheckMemoryStateContiguous(src_addr, size, src_state_mask, src_state, src_test_perm, src_test_perm, src_attr_mask | KMemoryAttribute_Uncached, src_attr)); R_TRY(dst_page_table.CheckMemoryStateContiguous(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_test_perm, dst_attr_mask | KMemoryAttribute_Uncached, dst_attr)); /* Get implementations. */ auto &src_impl = src_page_table.GetImpl(); auto &dst_impl = dst_page_table.GetImpl(); /* Prepare for traversal. */ TraversalContext src_context; TraversalContext dst_context; TraversalEntry src_next_entry; TraversalEntry dst_next_entry; bool traverse_valid; /* Begin traversal. */ traverse_valid = src_impl.BeginTraversal(std::addressof(src_next_entry), std::addressof(src_context), src_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); traverse_valid = dst_impl.BeginTraversal(std::addressof(dst_next_entry), std::addressof(dst_context), dst_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_src_block_addr = src_next_entry.phys_addr; KPhysicalAddress cur_dst_block_addr = dst_next_entry.phys_addr; size_t cur_src_size = src_next_entry.block_size - (GetInteger(cur_src_block_addr) & (src_next_entry.block_size - 1)); size_t cur_dst_size = dst_next_entry.block_size - (GetInteger(cur_dst_block_addr) & (dst_next_entry.block_size - 1)); /* Adjust the initial block sizes. */ src_next_entry.block_size = cur_src_size; dst_next_entry.block_size = cur_dst_size; /* Before we get any crazier, succeed if there's nothing to do. */ R_SUCCEED_IF(size == 0); /* We're going to manage dual traversal via an offset against the total size. */ KPhysicalAddress cur_src_addr = cur_src_block_addr; KPhysicalAddress cur_dst_addr = cur_dst_block_addr; size_t cur_min_size = std::min<size_t>(cur_src_size, cur_dst_size); /* Iterate. */ size_t ofs = 0; while (ofs < size) { /* Determine how much we can copy this iteration. */ const size_t cur_copy_size = std::min<size_t>(cur_min_size, size - ofs); /* If we need to advance the traversals, do so. */ bool updated_src = false, updated_dst = false, skip_copy = false; if (ofs + cur_copy_size != size) { if (cur_src_addr + cur_min_size == cur_src_block_addr + cur_src_size) { /* Continue the src traversal. */ traverse_valid = src_impl.ContinueTraversal(std::addressof(src_next_entry), std::addressof(src_context)); MESOSPHERE_ASSERT(traverse_valid); /* Update source. */ updated_src = cur_src_addr + cur_min_size != GetInteger(src_next_entry.phys_addr); } if (cur_dst_addr + cur_min_size == dst_next_entry.phys_addr + dst_next_entry.block_size) { /* Continue the dst traversal. */ traverse_valid = dst_impl.ContinueTraversal(std::addressof(dst_next_entry), std::addressof(dst_context)); MESOSPHERE_ASSERT(traverse_valid); /* Update destination. */ updated_dst = cur_dst_addr + cur_min_size != GetInteger(dst_next_entry.phys_addr); } /* If we didn't update either of source/destination, skip the copy this iteration. */ if (!updated_src && !updated_dst) { skip_copy = true; /* Update the source block address. */ cur_src_block_addr = src_next_entry.phys_addr; } } /* Do the copy, unless we're skipping it. */ if (!skip_copy) { /* We need both ends of the copy to be heap blocks. */ R_UNLESS(IsHeapPhysicalAddress(cur_src_addr), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsHeapPhysicalAddress(cur_dst_addr), svc::ResultInvalidCurrentMemory()); /* Copy the data. */ std::memcpy(GetVoidPointer(GetHeapVirtualAddress(cur_dst_addr)), GetVoidPointer(GetHeapVirtualAddress(cur_src_addr)), cur_copy_size); /* Update. */ cur_src_block_addr = src_next_entry.phys_addr; cur_src_addr = updated_src ? cur_src_block_addr : cur_src_addr + cur_copy_size; cur_dst_block_addr = dst_next_entry.phys_addr; cur_dst_addr = updated_dst ? cur_dst_block_addr : cur_dst_addr + cur_copy_size; /* Advance offset. */ ofs += cur_copy_size; } /* Update min size. */ cur_src_size = src_next_entry.block_size; cur_dst_size = dst_next_entry.block_size; cur_min_size = std::min<size_t>(cur_src_block_addr - cur_src_addr + cur_src_size, cur_dst_block_addr - cur_dst_addr + cur_dst_size); } } R_SUCCEED(); } Result KPageTableBase::CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) { /* For convenience, alias this. */ KPageTableBase &src_page_table = *this; /* Lightly validate the ranges before doing anything else. */ R_UNLESS(src_page_table.Contains(src_addr, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_page_table.Contains(dst_addr, size), svc::ResultInvalidCurrentMemory()); /* Copy the memory. */ { /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* Check memory state for source. */ R_TRY(src_page_table.CheckMemoryStateContiguous(src_addr, size, src_state_mask, src_state, src_test_perm, src_test_perm, src_attr_mask | KMemoryAttribute_Uncached, src_attr)); /* Destination state is intentionally unchecked. */ MESOSPHERE_UNUSED(dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr); /* Get implementations. */ auto &src_impl = src_page_table.GetImpl(); auto &dst_impl = dst_page_table.GetImpl(); /* Prepare for traversal. */ TraversalContext src_context; TraversalContext dst_context; TraversalEntry src_next_entry; TraversalEntry dst_next_entry; bool traverse_valid; /* Begin traversal. */ traverse_valid = src_impl.BeginTraversal(std::addressof(src_next_entry), std::addressof(src_context), src_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); traverse_valid = dst_impl.BeginTraversal(std::addressof(dst_next_entry), std::addressof(dst_context), dst_addr); MESOSPHERE_ABORT_UNLESS(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_src_block_addr = src_next_entry.phys_addr; KPhysicalAddress cur_dst_block_addr = dst_next_entry.phys_addr; size_t cur_src_size = src_next_entry.block_size - (GetInteger(cur_src_block_addr) & (src_next_entry.block_size - 1)); size_t cur_dst_size = dst_next_entry.block_size - (GetInteger(cur_dst_block_addr) & (dst_next_entry.block_size - 1)); /* Adjust the initial block sizes. */ src_next_entry.block_size = cur_src_size; dst_next_entry.block_size = cur_dst_size; /* Before we get any crazier, succeed if there's nothing to do. */ R_SUCCEED_IF(size == 0); /* We're going to manage dual traversal via an offset against the total size. */ KPhysicalAddress cur_src_addr = cur_src_block_addr; KPhysicalAddress cur_dst_addr = cur_dst_block_addr; size_t cur_min_size = std::min<size_t>(cur_src_size, cur_dst_size); /* Iterate. */ size_t ofs = 0; while (ofs < size) { /* Determine how much we can copy this iteration. */ const size_t cur_copy_size = std::min<size_t>(cur_min_size, size - ofs); /* If we need to advance the traversals, do so. */ bool updated_src = false, updated_dst = false, skip_copy = false; if (ofs + cur_copy_size != size) { if (cur_src_addr + cur_min_size == cur_src_block_addr + cur_src_size) { /* Continue the src traversal. */ traverse_valid = src_impl.ContinueTraversal(std::addressof(src_next_entry), std::addressof(src_context)); MESOSPHERE_ASSERT(traverse_valid); /* Update source. */ updated_src = cur_src_addr + cur_min_size != GetInteger(src_next_entry.phys_addr); } if (cur_dst_addr + cur_min_size == dst_next_entry.phys_addr + dst_next_entry.block_size) { /* Continue the dst traversal. */ traverse_valid = dst_impl.ContinueTraversal(std::addressof(dst_next_entry), std::addressof(dst_context)); MESOSPHERE_ASSERT(traverse_valid); /* Update destination. */ updated_dst = cur_dst_addr + cur_min_size != GetInteger(dst_next_entry.phys_addr); } /* If we didn't update either of source/destination, skip the copy this iteration. */ if (!updated_src && !updated_dst) { skip_copy = true; /* Update the source block address. */ cur_src_block_addr = src_next_entry.phys_addr; } } /* Do the copy, unless we're skipping it. */ if (!skip_copy) { /* We need both ends of the copy to be heap blocks. */ R_UNLESS(IsHeapPhysicalAddress(cur_src_addr), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsHeapPhysicalAddress(cur_dst_addr), svc::ResultInvalidCurrentMemory()); /* Copy the data. */ std::memcpy(GetVoidPointer(GetHeapVirtualAddress(cur_dst_addr)), GetVoidPointer(GetHeapVirtualAddress(cur_src_addr)), cur_copy_size); /* Update. */ cur_src_block_addr = src_next_entry.phys_addr; cur_src_addr = updated_src ? cur_src_block_addr : cur_src_addr + cur_copy_size; cur_dst_block_addr = dst_next_entry.phys_addr; cur_dst_addr = updated_dst ? cur_dst_block_addr : cur_dst_addr + cur_copy_size; /* Advance offset. */ ofs += cur_copy_size; } /* Update min size. */ cur_src_size = src_next_entry.block_size; cur_dst_size = dst_next_entry.block_size; cur_min_size = std::min<size_t>(cur_src_block_addr - cur_src_addr + cur_src_size, cur_dst_block_addr - cur_dst_addr + cur_dst_size); } } R_SUCCEED(); } #pragma GCC push_options #pragma GCC optimize ("-O3") Result KPageTableBase::SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state) { /* Validate pre-conditions. */ MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(test_perm == KMemoryPermission_UserReadWrite || test_perm == KMemoryPermission_UserRead); /* Check that the address is in range. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Get the source permission. */ const auto src_perm = static_cast<KMemoryPermission>((test_perm == KMemoryPermission_UserReadWrite) ? (KMemoryPermission_KernelReadWrite | KMemoryPermission_NotMapped) : KMemoryPermission_UserRead); /* Get aligned extents. */ const KProcessAddress aligned_src_start = util::AlignDown(GetInteger(address), PageSize); const KProcessAddress aligned_src_end = util::AlignUp(GetInteger(address) + size, PageSize); const KProcessAddress mapping_src_start = util::AlignUp(GetInteger(address), PageSize); const KProcessAddress mapping_src_end = util::AlignDown(GetInteger(address) + size, PageSize); const auto aligned_src_last = GetInteger(aligned_src_end) - 1; const auto mapping_src_last = GetInteger(mapping_src_end) - 1; /* Get the test state and attribute mask. */ u32 test_state; u32 test_attr_mask; switch (dst_state) { case KMemoryState_Ipc: test_state = KMemoryState_FlagCanUseIpc; test_attr_mask = KMemoryAttribute_All & (~(KMemoryAttribute_PermissionLocked | KMemoryAttribute_IpcLocked)); break; case KMemoryState_NonSecureIpc: test_state = KMemoryState_FlagCanUseNonSecureIpc; test_attr_mask = KMemoryAttribute_All & (~(KMemoryAttribute_PermissionLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_IpcLocked)); break; case KMemoryState_NonDeviceIpc: test_state = KMemoryState_FlagCanUseNonDeviceIpc; test_attr_mask = KMemoryAttribute_All & (~(KMemoryAttribute_PermissionLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_IpcLocked)); break; default: R_THROW(svc::ResultInvalidCombination()); } /* Ensure that on failure, we roll back appropriately. */ size_t mapped_size = 0; ON_RESULT_FAILURE { if (mapped_size > 0) { this->CleanupForIpcClientOnServerSetupFailure(page_list, mapping_src_start, mapped_size, src_perm); } }; size_t blocks_needed = 0; /* Iterate, mapping as needed. */ KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(aligned_src_start); while (true) { /* Validate the current block. */ R_TRY(this->CheckMemoryState(it, test_state, test_state, test_perm, test_perm, test_attr_mask, KMemoryAttribute_None)); if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < GetInteger(it->GetEndAddress()) && GetInteger(it->GetAddress()) < GetInteger(mapping_src_end)) { const auto cur_start = it->GetAddress() >= GetInteger(mapping_src_start) ? GetInteger(it->GetAddress()) : GetInteger(mapping_src_start); const auto cur_end = mapping_src_last >= GetInteger(it->GetLastAddress()) ? GetInteger(it->GetEndAddress()) : GetInteger(mapping_src_end); const size_t cur_size = cur_end - cur_start; if (GetInteger(it->GetAddress()) < GetInteger(mapping_src_start)) { ++blocks_needed; } if (mapping_src_last < GetInteger(it->GetLastAddress())) { ++blocks_needed; } /* Set the permissions on the block, if we need to. */ if ((it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) { const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= GetInteger(it->GetAddress())) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None; const DisableMergeAttribute tail_attr = (cur_end == GetInteger(mapping_src_end)) ? DisableMergeAttribute_DisableTail : DisableMergeAttribute_None; const KPageProperties properties = { src_perm, false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) }; R_TRY(this->Operate(page_list, cur_start, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); } /* Note that we mapped this part. */ mapped_size += cur_size; } /* If the block is at the end, we're done. */ if (aligned_src_last <= GetInteger(it->GetLastAddress())) { break; } /* Advance. */ ++it; MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end()); } if (out_blocks_needed != nullptr) { MESOSPHERE_ASSERT(blocks_needed <= KMemoryBlockManagerUpdateAllocator::MaxBlocks); *out_blocks_needed = blocks_needed; } R_SUCCEED(); } Result KPageTableBase::SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(src_page_table.IsLockedByCurrentThread()); /* Check that we can theoretically map. */ const KProcessAddress region_start = m_region_starts[RegionType_Alias]; const size_t region_size = m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; R_UNLESS(size < region_size, svc::ResultOutOfAddressSpace()); /* Get aligned source extents. */ const KProcessAddress src_start = src_addr; const KProcessAddress src_end = src_addr + size; const KProcessAddress aligned_src_start = util::AlignDown(GetInteger(src_start), PageSize); const KProcessAddress aligned_src_end = util::AlignUp(GetInteger(src_start) + size, PageSize); const KProcessAddress mapping_src_start = util::AlignUp(GetInteger(src_start), PageSize); const KProcessAddress mapping_src_end = util::AlignDown(GetInteger(src_start) + size, PageSize); const size_t aligned_src_size = aligned_src_end - aligned_src_start; const size_t mapping_src_size = (mapping_src_start < mapping_src_end) ? (mapping_src_end - mapping_src_start) : 0; /* Select a random address to map at. */ KProcessAddress dst_addr = Null<KProcessAddress>; for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) { const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type)); const size_t offset = GetInteger(aligned_src_start) & (alignment - 1); dst_addr = this->FindFreeArea(region_start, region_size / PageSize, aligned_src_size / PageSize, alignment, offset, this->GetNumGuardPages()); if (dst_addr != Null<KProcessAddress>) { break; } } R_UNLESS(dst_addr != Null<KProcessAddress>, svc::ResultOutOfAddressSpace()); /* Check that we can perform the operation we're about to perform. */ MESOSPHERE_ASSERT(this->CanContain(dst_addr, aligned_src_size, dst_state)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Reserve space for any partial pages we allocate. */ const size_t unmapped_size = aligned_src_size - mapping_src_size; KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, unmapped_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Ensure that we manage page references correctly. */ KPhysicalAddress start_partial_page = Null<KPhysicalAddress>; KPhysicalAddress end_partial_page = Null<KPhysicalAddress>; KProcessAddress cur_mapped_addr = dst_addr; /* If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll free on scope exit. */ ON_SCOPE_EXIT { if (start_partial_page != Null<KPhysicalAddress>) { Kernel::GetMemoryManager().Close(start_partial_page, 1); } if (end_partial_page != Null<KPhysicalAddress>) { Kernel::GetMemoryManager().Close(end_partial_page, 1); } }; ON_RESULT_FAILURE { if (cur_mapped_addr != dst_addr) { const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_addr, (cur_mapped_addr - dst_addr) / PageSize, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true)); } }; /* Allocate the start page as needed. */ if (aligned_src_start < mapping_src_start) { start_partial_page = Kernel::GetMemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); R_UNLESS(start_partial_page != Null<KPhysicalAddress>, svc::ResultOutOfMemory()); } /* Allocate the end page as needed. */ if (mapping_src_end < aligned_src_end && (aligned_src_start < mapping_src_end || aligned_src_start == mapping_src_start)) { end_partial_page = Kernel::GetMemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); R_UNLESS(end_partial_page != Null<KPhysicalAddress>, svc::ResultOutOfMemory()); } /* Get the implementation. */ auto &src_impl = src_page_table.GetImpl(); /* Get the fill value for partial pages. */ const auto fill_val = m_ipc_fill_value; /* Begin traversal. */ TraversalContext context; TraversalEntry next_entry; bool traverse_valid = src_impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), aligned_src_start); MESOSPHERE_ASSERT(traverse_valid); MESOSPHERE_UNUSED(traverse_valid); /* Prepare tracking variables. */ KPhysicalAddress cur_block_addr = next_entry.phys_addr; size_t cur_block_size = next_entry.block_size - (GetInteger(cur_block_addr) & (next_entry.block_size - 1)); size_t tot_block_size = cur_block_size; /* Map the start page, if we have one. */ if (start_partial_page != Null<KPhysicalAddress>) { /* Ensure the page holds correct data. */ const KVirtualAddress start_partial_virt = GetHeapVirtualAddress(start_partial_page); if (send) { const size_t partial_offset = src_start - aligned_src_start; size_t copy_size, clear_size; if (src_end < mapping_src_start) { copy_size = size; clear_size = mapping_src_start - src_end; } else { copy_size = mapping_src_start - src_start; clear_size = 0; } std::memset(GetVoidPointer(start_partial_virt), fill_val, partial_offset); std::memcpy(GetVoidPointer(start_partial_virt + partial_offset), GetVoidPointer(GetHeapVirtualAddress(cur_block_addr) + partial_offset), copy_size); if (clear_size > 0) { std::memset(GetVoidPointer(start_partial_virt + partial_offset + copy_size), fill_val, clear_size); } } else { std::memset(GetVoidPointer(start_partial_virt), fill_val, PageSize); } /* Map the page. */ const KPageProperties start_map_properties = { test_perm, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(updater.GetPageList(), cur_mapped_addr, 1, start_partial_page, true, start_map_properties, OperationType_Map, false)); /* Update tracking extents. */ cur_mapped_addr += PageSize; cur_block_addr += PageSize; cur_block_size -= PageSize; /* If the block's size was one page, we may need to continue traversal. */ if (cur_block_size == 0 && aligned_src_size > PageSize) { traverse_valid = src_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); cur_block_addr = next_entry.phys_addr; cur_block_size = next_entry.block_size; tot_block_size += next_entry.block_size; } } /* Map the remaining pages. */ while (aligned_src_start + tot_block_size < mapping_src_end) { /* Continue the traversal. */ traverse_valid = src_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); /* Process the block. */ if (next_entry.phys_addr != cur_block_addr + cur_block_size) { /* Map the block we've been processing so far. */ const KPageProperties map_properties = { test_perm, false, false, (cur_mapped_addr == dst_addr) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), cur_mapped_addr, cur_block_size / PageSize, cur_block_addr, true, map_properties, OperationType_Map, false)); /* Update tracking extents. */ cur_mapped_addr += cur_block_size; cur_block_addr = next_entry.phys_addr; cur_block_size = next_entry.block_size; } else { cur_block_size += next_entry.block_size; } tot_block_size += next_entry.block_size; } /* Handle the last direct-mapped page. */ if (const KProcessAddress mapped_block_end = aligned_src_start + tot_block_size - cur_block_size; mapped_block_end < mapping_src_end) { const size_t last_block_size = mapping_src_end - mapped_block_end; /* Map the last block. */ const KPageProperties map_properties = { test_perm, false, false, (cur_mapped_addr == dst_addr) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), cur_mapped_addr, last_block_size / PageSize, cur_block_addr, true, map_properties, OperationType_Map, false)); /* Update tracking extents. */ cur_mapped_addr += last_block_size; cur_block_addr += last_block_size; if (mapped_block_end + cur_block_size < aligned_src_end && cur_block_size == last_block_size) { traverse_valid = src_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); MESOSPHERE_ASSERT(traverse_valid); cur_block_addr = next_entry.phys_addr; } } /* Map the end page, if we have one. */ if (end_partial_page != Null<KPhysicalAddress>) { /* Ensure the page holds correct data. */ const KVirtualAddress end_partial_virt = GetHeapVirtualAddress(end_partial_page); if (send) { const size_t copy_size = src_end - mapping_src_end; std::memcpy(GetVoidPointer(end_partial_virt), GetVoidPointer(GetHeapVirtualAddress(cur_block_addr)), copy_size); std::memset(GetVoidPointer(end_partial_virt + copy_size), fill_val, PageSize - copy_size); } else { std::memset(GetVoidPointer(end_partial_virt), fill_val, PageSize); } /* Map the page. */ const KPageProperties map_properties = { test_perm, false, false, (cur_mapped_addr == dst_addr) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), cur_mapped_addr, 1, end_partial_page, true, map_properties, OperationType_Map, false)); } /* Update memory blocks to reflect our changes */ m_memory_block_manager.Update(std::addressof(allocator), dst_addr, aligned_src_size / PageSize, dst_state, test_perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* Set the output address. */ *out_addr = dst_addr + (src_start - aligned_src_start); /* We succeeded. */ memory_reservation.Commit(); R_SUCCEED(); } Result KPageTableBase::SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send) { /* For convenience, alias this. */ KPageTableBase &dst_page_table = *this; /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(std::addressof(src_page_table)); /* Perform client setup. */ size_t num_allocator_blocks; R_TRY(src_page_table.SetupForIpcClient(updater.GetPageList(), std::addressof(num_allocator_blocks), src_addr, size, test_perm, dst_state)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), src_page_table.m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* Get the mapped extents. */ const KProcessAddress src_map_start = util::AlignUp(GetInteger(src_addr), PageSize); const KProcessAddress src_map_end = util::AlignDown(GetInteger(src_addr) + size, PageSize); const size_t src_map_size = src_map_end - src_map_start; /* Ensure that we clean up appropriately if we fail after this. */ const auto src_perm = static_cast<KMemoryPermission>((test_perm == KMemoryPermission_UserReadWrite) ? (KMemoryPermission_KernelReadWrite | KMemoryPermission_NotMapped) : KMemoryPermission_UserRead); ON_RESULT_FAILURE { if (src_map_end > src_map_start) { src_page_table.CleanupForIpcClientOnServerSetupFailure(updater.GetPageList(), src_map_start, src_map_size, src_perm); } }; /* Perform server setup. */ R_TRY(dst_page_table.SetupForIpcServer(out_dst_addr, size, src_addr, test_perm, dst_state, src_page_table, send)); /* If anything was mapped, ipc-lock the pages. */ if (src_map_start < src_map_end) { /* Get the source permission. */ src_page_table.m_memory_block_manager.UpdateLock(std::addressof(allocator), src_map_start, (src_map_end - src_map_start) / PageSize, &KMemoryBlock::LockForIpc, src_perm); } R_SUCCEED(); } Result KPageTableBase::CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) { /* Validate the address. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, dst_state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Get aligned extents. */ const KProcessAddress aligned_start = util::AlignDown(GetInteger(address), PageSize); const KProcessAddress aligned_end = util::AlignUp(GetInteger(address) + size, PageSize); const size_t aligned_size = aligned_end - aligned_start; const size_t aligned_num_pages = aligned_size / PageSize; /* Unmap the pages. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), aligned_start, aligned_num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Update memory blocks. */ m_memory_block_manager.Update(std::addressof(allocator), aligned_start, aligned_num_pages, KMemoryState_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); /* Release from the resource limit as relevant. */ const KProcessAddress mapping_start = util::AlignUp(GetInteger(address), PageSize); const KProcessAddress mapping_end = util::AlignDown(GetInteger(address) + size, PageSize); const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0; m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_size - mapping_size); R_SUCCEED(); } Result KPageTableBase::CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) { /* Validate the address. */ R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Get aligned source extents. */ const KProcessAddress mapping_start = util::AlignUp(GetInteger(address), PageSize); const KProcessAddress mapping_end = util::AlignDown(GetInteger(address) + size, PageSize); const KProcessAddress mapping_last = mapping_end - 1; const size_t mapping_size = (mapping_start < mapping_end) ? (mapping_end - mapping_start) : 0; /* If nothing was mapped, we're actually done immediately. */ R_SUCCEED_IF(mapping_size == 0); /* Get the test state and attribute mask. */ u32 test_state; u32 test_attr_mask; switch (dst_state) { case KMemoryState_Ipc: test_state = KMemoryState_FlagCanUseIpc; test_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked; break; case KMemoryState_NonSecureIpc: test_state = KMemoryState_FlagCanUseNonSecureIpc; test_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_Locked; break; case KMemoryState_NonDeviceIpc: test_state = KMemoryState_FlagCanUseNonDeviceIpc; test_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_Locked; break; default: R_THROW(svc::ResultInvalidCombination()); } /* Lock the table. */ /* NOTE: Nintendo does this *after* creating the updater below, but this does not follow convention elsewhere in KPageTableBase. */ KScopedLightLock lk(m_general_lock); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Ensure that on failure, we roll back appropriately. */ size_t mapped_size = 0; ON_RESULT_FAILURE { if (mapped_size > 0) { /* Determine where the mapping ends. */ const auto mapped_end = GetInteger(mapping_start) + mapped_size; const auto mapped_last = mapped_end - 1; /* Get current and next iterators. */ KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start); KMemoryBlockManager::const_iterator next_it = cur_it; ++next_it; /* Create tracking variables. */ KProcessAddress cur_address = cur_it->GetAddress(); size_t cur_size = cur_it->GetSize(); bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission(); bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1; bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; while ((GetInteger(cur_address) + cur_size - 1) < mapped_last) { /* Check that we have a next block. */ MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end()); /* Check if we can consolidate the next block's permission set with the current one. */ const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission(); const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1; if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) { /* We can consolidate the reprotection for the current and next block into a single call. */ cur_size += next_it->GetSize(); } else { /* We have to operate on the current block. */ if ((cur_needs_set_perm || first) && !cur_perm_eq) { const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true)); } /* Advance. */ cur_address = next_it->GetAddress(); cur_size = next_it->GetSize(); first = false; } /* Advance. */ cur_perm_eq = next_perm_eq; cur_needs_set_perm = next_needs_set_perm; cur_it = next_it++; } /* Process the last block. */ if ((first || cur_needs_set_perm) && !cur_perm_eq) { const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true)); } } }; /* Iterate, reprotecting as needed. */ { /* Get current and next iterators. */ KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start); KMemoryBlockManager::const_iterator next_it = cur_it; ++next_it; /* Validate the current block. */ MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(cur_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); /* Create tracking variables. */ KProcessAddress cur_address = cur_it->GetAddress(); size_t cur_size = cur_it->GetSize(); bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission(); bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1; bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0; while ((cur_address + cur_size - 1) < mapping_last) { /* Check that we have a next block. */ MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end()); /* Validate the next block. */ MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(next_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked)); /* Check if we can consolidate the next block's permission set with the current one. */ const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission(); const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1; if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) { /* We can consolidate the reprotection for the current and next block into a single call. */ cur_size += next_it->GetSize(); } else { /* We have to operate on the current block. */ if ((cur_needs_set_perm || first) && !cur_perm_eq) { const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); } /* Mark that we mapped the block. */ mapped_size += cur_size; /* Advance. */ cur_address = next_it->GetAddress(); cur_size = next_it->GetSize(); first = false; } /* Advance. */ cur_perm_eq = next_perm_eq; cur_needs_set_perm = next_needs_set_perm; cur_it = next_it++; } /* Process the last block. */ const auto lock_count = cur_it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); if ((first || cur_needs_set_perm || (lock_count == 1)) && !cur_perm_eq) { const DisableMergeAttribute head_body_attr = first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None; const DisableMergeAttribute tail_attr = lock_count == 1 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None; const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) }; R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false)); } } /* Create an update allocator. */ /* NOTE: Guaranteed zero blocks needed here. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, 0); R_TRY(allocator_result); /* Unlock the pages. */ m_memory_block_manager.UpdateLock(std::addressof(allocator), mapping_start, mapping_size / PageSize, &KMemoryBlock::UnlockForIpc, KMemoryPermission_None); R_SUCCEED(); } void KPageTableBase::CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm) { MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(size, PageSize)); /* Get the mapped extents. */ const KProcessAddress src_map_start = address; const KProcessAddress src_map_end = address + size; const KProcessAddress src_map_last = src_map_end - 1; /* This function is only invoked when there's something to do. */ MESOSPHERE_ASSERT(src_map_end > src_map_start); /* Iterate over blocks, fixing permissions. */ KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address); while (true) { const auto cur_start = it->GetAddress() >= GetInteger(src_map_start) ? it->GetAddress() : GetInteger(src_map_start); const auto cur_end = src_map_last <= it->GetLastAddress() ? src_map_end : it->GetEndAddress(); /* If we can, fix the protections on the block. */ if ((it->GetIpcLockCount() == 0 && (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) || (it->GetIpcLockCount() != 0 && (it->GetOriginalPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm)) { /* Check if we actually need to fix the protections on the block. */ if (cur_end == src_map_end || it->GetAddress() <= GetInteger(src_map_start) || (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) { const bool start_nc = (it->GetAddress() == GetInteger(src_map_start)) ? ((it->GetDisableMergeAttribute() & (KMemoryBlockDisableMergeAttribute_Locked | KMemoryBlockDisableMergeAttribute_IpcLeft)) == 0) : it->GetAddress() <= GetInteger(src_map_start); const DisableMergeAttribute head_body_attr = start_nc ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None; DisableMergeAttribute tail_attr; if (cur_end == src_map_end && it->GetEndAddress() == src_map_end) { auto next_it = it; ++next_it; const auto lock_count = it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0); tail_attr = lock_count == 0 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None; } else { tail_attr = DisableMergeAttribute_None; } const KPageProperties properties = { it->GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) }; MESOSPHERE_R_ABORT_UNLESS(this->Operate(page_list, cur_start, (cur_end - cur_start) / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true)); } } /* If we're past the end of the region, we're done. */ if (src_map_last <= it->GetLastAddress()) { break; } /* Advance. */ ++it; MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end()); } } #pragma GCC pop_options Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { /* Lock the physical memory lock. */ KScopedLightLock phys_lk(m_map_physical_memory_lock); /* Calculate the last address for convenience. */ const KProcessAddress last_address = address + size - 1; /* Define iteration variables. */ KProcessAddress cur_address; size_t mapped_size; /* The entire mapping process can be retried. */ while (true) { /* Check if the memory is already mapped. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Iterate over the memory. */ cur_address = address; mapped_size = 0; auto it = m_memory_block_manager.FindIterator(cur_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { if (it->GetState() != KMemoryState_Free) { mapped_size += (last_address + 1 - cur_address); } break; } /* Track the memory if it's mapped. */ if (it->GetState() != KMemoryState_Free) { mapped_size += it->GetEndAddress() - cur_address; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } /* If the size mapped is the size requested, we've nothing to do. */ R_SUCCEED_IF(size == mapped_size); } /* Allocate and map the memory. */ { /* Reserve the memory from the process resource limit. */ KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, size - mapped_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Allocate pages for the new memory. */ KPageGroup pg(m_block_info_manager); R_TRY(Kernel::GetMemoryManager().AllocateForProcess(std::addressof(pg), (size - mapped_size) / PageSize, m_allocate_option, GetCurrentProcess().GetId(), m_heap_fill_value)); /* If we fail in the next bit (or retry), we need to cleanup the pages. */ auto pg_guard = SCOPE_GUARD { pg.OpenFirst(); pg.Close(); }; /* Map the memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); size_t num_allocator_blocks = 0; /* Verify that nobody has mapped memory since we first checked. */ { /* Iterate over the memory. */ size_t checked_mapped_size = 0; cur_address = address; auto it = m_memory_block_manager.FindIterator(cur_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); const bool is_free = it->GetState() == KMemoryState_Free; if (is_free) { if (it->GetAddress() < GetInteger(address)) { ++num_allocator_blocks; } if (last_address < it->GetLastAddress()) { ++num_allocator_blocks; } } /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { if (!is_free) { checked_mapped_size += (last_address + 1 - cur_address); } break; } /* Track the memory if it's mapped. */ if (!is_free) { checked_mapped_size += it->GetEndAddress() - cur_address; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } /* If the size now isn't what it was before, somebody mapped or unmapped concurrently. */ /* If this happened, retry. */ if (mapped_size != checked_mapped_size) { continue; } } /* Create an update allocator. */ MESOSPHERE_ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks); Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Prepare to iterate over the memory. */ auto pg_it = pg.begin(); KPhysicalAddress pg_phys_addr = pg_it->GetAddress(); size_t pg_pages = pg_it->GetNumPages(); /* Reset the current tracking address, and make sure we clean up on failure. */ pg_guard.Cancel(); cur_address = address; ON_RESULT_FAILURE { if (cur_address > address) { const KProcessAddress last_unmap_address = cur_address - 1; /* Iterate, unmapping the pages. */ cur_address = address; auto it = m_memory_block_manager.FindIterator(cur_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* If the memory state is free, we mapped it and need to unmap it. */ if (it->GetState() == KMemoryState_Free) { /* Determine the range to unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_unmap_address + 1 - cur_address) / PageSize; /* Unmap. */ MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true)); } /* Check if we're done. */ if (last_unmap_address <= it->GetLastAddress()) { break; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } } /* Release any remaining unmapped memory. */ Kernel::GetMemoryManager().OpenFirst(pg_phys_addr, pg_pages); Kernel::GetMemoryManager().Close(pg_phys_addr, pg_pages); for (++pg_it; pg_it != pg.end(); ++pg_it) { Kernel::GetMemoryManager().OpenFirst(pg_it->GetAddress(), pg_it->GetNumPages()); Kernel::GetMemoryManager().Close(pg_it->GetAddress(), pg_it->GetNumPages()); } }; auto it = m_memory_block_manager.FindIterator(cur_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* If it's unmapped, we need to map it. */ if (it->GetState() == KMemoryState_Free) { /* Determine the range to map. */ const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, cur_address == this->GetAliasRegionStart() ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None }; size_t map_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize; /* While we have pages to map, map them. */ { /* Create a page group for the current mapping range. */ KPageGroup cur_pg(m_block_info_manager); { ON_RESULT_FAILURE { cur_pg.OpenFirst(); cur_pg.Close(); }; size_t remain_pages = map_pages; while (remain_pages > 0) { /* Check if we're at the end of the physical block. */ if (pg_pages == 0) { /* Ensure there are more pages to map. */ MESOSPHERE_ASSERT(pg_it != pg.end()); /* Advance our physical block. */ ++pg_it; pg_phys_addr = pg_it->GetAddress(); pg_pages = pg_it->GetNumPages(); } /* Add whatever we can to the current block. */ const size_t cur_pages = std::min(pg_pages, remain_pages); R_TRY(cur_pg.AddBlock(pg_phys_addr + ((pg_pages - cur_pages) * PageSize), cur_pages)); /* Advance. */ remain_pages -= cur_pages; pg_pages -= cur_pages; } } /* Map the pages. */ R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, cur_pg, map_properties, OperationType_MapFirstGroup, false)); } } /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } /* We succeeded, so commit the memory reservation. */ memory_reservation.Commit(); /* Increase our tracked mapped size. */ m_mapped_physical_memory_size += (size - mapped_size); /* Update the relevant memory blocks. */ m_memory_block_manager.UpdateIfMatch(std::addressof(allocator), address, size / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, address == this->GetAliasRegionStart() ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None); R_SUCCEED(); } } } } Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size) { /* Lock the physical memory lock. */ KScopedLightLock phys_lk(m_map_physical_memory_lock); /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Calculate the last address for convenience. */ const KProcessAddress last_address = address + size - 1; /* Define iteration variables. */ KProcessAddress map_start_address = Null<KProcessAddress>; KProcessAddress map_last_address = Null<KProcessAddress>; KProcessAddress cur_address; size_t mapped_size; size_t num_allocator_blocks = 0; /* Check if the memory is mapped. */ { /* Iterate over the memory. */ cur_address = address; mapped_size = 0; auto it = m_memory_block_manager.FindIterator(cur_address); while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* Verify the memory's state. */ const bool is_normal = it->GetState() == KMemoryState_Normal && it->GetAttribute() == 0; const bool is_free = it->GetState() == KMemoryState_Free; R_UNLESS(is_normal || is_free, svc::ResultInvalidCurrentMemory()); if (is_normal) { R_UNLESS(it->GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory()); if (map_start_address == Null<KProcessAddress>) { map_start_address = cur_address; } map_last_address = (last_address >= it->GetLastAddress()) ? it->GetLastAddress() : last_address; if (it->GetAddress() < GetInteger(address)) { ++num_allocator_blocks; } if (last_address < it->GetLastAddress()) { ++num_allocator_blocks; } mapped_size += (map_last_address + 1 - cur_address); } /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } /* If there's nothing mapped, we've nothing to do. */ R_SUCCEED_IF(mapped_size == 0); } /* Create an update allocator. */ MESOSPHERE_ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks); Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Separate the mapping. */ const KPageProperties sep_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), map_start_address, (map_last_address + 1 - map_start_address) / PageSize, Null<KPhysicalAddress>, false, sep_properties, OperationType_Separate, false)); /* Reset the current tracking address, and make sure we clean up on failure. */ cur_address = address; /* Iterate over the memory, unmapping as we go. */ auto it = m_memory_block_manager.FindIterator(cur_address); const auto clear_merge_attr = (it->GetState() == KMemoryState_Normal && it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address) ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None; while (true) { /* Check that the iterator is valid. */ MESOSPHERE_ASSERT(it != m_memory_block_manager.end()); /* If the memory state is normal, we need to unmap it. */ if (it->GetState() == KMemoryState_Normal) { /* Determine the range to unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize; /* Unmap. */ MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); } /* Check if we're done. */ if (last_address <= it->GetLastAddress()) { break; } /* Advance. */ cur_address = it->GetEndAddress(); ++it; } /* Release the memory resource. */ m_mapped_physical_memory_size -= mapped_size; m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, mapped_size); /* Update memory blocks. */ m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, clear_merge_attr); /* We succeeded. */ R_SUCCEED(); } Result KPageTableBase::MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) { /* Try to reserve the unsafe memory. */ R_UNLESS(Kernel::GetUnsafeMemory().TryReserve(size), svc::ResultLimitReached()); /* Ensure we release our reservation on failure. */ ON_RESULT_FAILURE { Kernel::GetUnsafeMemory().Release(size); }; /* Create a page group for the new memory. */ KPageGroup pg(m_block_info_manager); /* Allocate the new memory. */ const size_t num_pages = size / PageSize; R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, 1, KMemoryManager::EncodeOption(KMemoryManager::Pool_Unsafe, KMemoryManager::Direction_FromFront))); /* Close the page group when we're done with it. */ ON_SCOPE_EXIT { pg.Close(); }; /* Clear the new memory. */ for (const auto &block : pg) { std::memset(GetVoidPointer(GetHeapVirtualAddress(block.GetAddress())), m_heap_fill_value, block.GetSize()); } /* Map the new memory. */ { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Map the pages. */ const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_DisableHead }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, pg, map_properties, OperationType_MapGroup, false)); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None); /* Update our mapped unsafe size. */ m_mapped_unsafe_physical_memory += size; /* We succeeded. */ R_SUCCEED(); } } Result KPageTableBase::UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) { /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Check whether we can unmap this much unsafe physical memory. */ R_UNLESS(size <= m_mapped_unsafe_physical_memory, svc::ResultInvalidCurrentMemory()); /* Check the memory state. */ size_t num_allocator_blocks; R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the memory. */ const size_t num_pages = size / PageSize; const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); /* Release the unsafe memory from the limit. */ Kernel::GetUnsafeMemory().Release(size); /* Update our mapped unsafe size. */ m_mapped_unsafe_physical_memory -= size; R_SUCCEED(); } Result KPageTableBase::UnmapProcessMemory(KProcessAddress dst_address, size_t size, KPageTableBase &src_page_table, KProcessAddress src_address) { /* We need to lock both this table, and the current process's table, so set up an alias. */ KPageTableBase &dst_page_table = *this; /* Acquire the table locks. */ KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); /* Check that the memory is mapped in the destination process. */ size_t num_allocator_blocks; R_TRY(dst_page_table.CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_SharedCode, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None)); /* Check that the memory is mapped in the source process. */ R_TRY(src_page_table.CheckMemoryState(src_address, size, KMemoryState_FlagCanMapProcess, KMemoryState_FlagCanMapProcess, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Validate that the memory ranges are compatible. */ { /* Define a helper type. */ struct ContiguousRangeInfo { public: KPageTableBase &m_pt; TraversalContext m_context; TraversalEntry m_entry; KPhysicalAddress m_phys_addr; size_t m_cur_size; size_t m_remaining_size; public: ContiguousRangeInfo(KPageTableBase &pt, KProcessAddress address, size_t size) : m_pt(pt), m_remaining_size(size) { /* Begin a traversal. */ MESOSPHERE_ABORT_UNLESS(m_pt.GetImpl().BeginTraversal(std::addressof(m_entry), std::addressof(m_context), address)); /* Setup tracking fields. */ m_phys_addr = m_entry.phys_addr; m_cur_size = std::min<size_t>(m_remaining_size, m_entry.block_size - (GetInteger(m_phys_addr) & (m_entry.block_size - 1))); /* Consume the whole contiguous block. */ this->DetermineContiguousBlockExtents(); } void ContinueTraversal() { /* Update our remaining size. */ m_remaining_size = m_remaining_size - m_cur_size; /* Update our tracking fields. */ if (m_remaining_size > 0) { m_phys_addr = m_entry.phys_addr; m_cur_size = std::min<size_t>(m_remaining_size, m_entry.block_size); /* Consume the whole contiguous block. */ this->DetermineContiguousBlockExtents(); } } private: void DetermineContiguousBlockExtents() { /* Continue traversing until we're not contiguous, or we have enough. */ while (m_cur_size < m_remaining_size) { MESOSPHERE_ABORT_UNLESS(m_pt.GetImpl().ContinueTraversal(std::addressof(m_entry), std::addressof(m_context))); /* If we're not contiguous, we're done. */ if (m_entry.phys_addr != m_phys_addr + m_cur_size) { break; } /* Update our current size. */ m_cur_size = std::min(m_remaining_size, m_cur_size + m_entry.block_size); } } }; /* Create ranges for both tables. */ ContiguousRangeInfo src_range(src_page_table, src_address, size); ContiguousRangeInfo dst_range(dst_page_table, dst_address, size); /* Validate the ranges. */ while (src_range.m_remaining_size > 0 && dst_range.m_remaining_size > 0) { R_UNLESS(src_range.m_phys_addr == dst_range.m_phys_addr, svc::ResultInvalidMemoryRegion()); R_UNLESS(src_range.m_cur_size == dst_range.m_cur_size, svc::ResultInvalidMemoryRegion()); src_range.ContinueTraversal(); dst_range.ContinueTraversal(); } } /* We no longer need to hold our lock on the source page table. */ lk.TryUnlockHalf(src_page_table.m_general_lock); /* Create an update allocator. */ Result allocator_result; KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); /* Unmap the memory. */ const size_t num_pages = size / PageSize; const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false)); /* Apply the memory block update. */ m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal); R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_port.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KPort::Initialize(s32 max_sessions, bool is_light, uintptr_t name) { /* Open a new reference count to the initialized port. */ this->Open(); /* Create and initialize our server/client pair. */ KAutoObject::Create<KServerPort>(std::addressof(m_server)); KAutoObject::Create<KClientPort>(std::addressof(m_client)); m_server.Initialize(this); m_client.Initialize(this, max_sessions); /* Set our member variables. */ m_is_light = is_light; m_name = name; m_state = State::Normal; } void KPort::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; if (m_state == State::Normal) { m_state = State::ClientClosed; } } void KPort::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; if (m_state == State::Normal) { m_state = State::ServerClosed; } } Result KPort::EnqueueSession(KServerSession *session) { KScopedSchedulerLock sl; R_UNLESS(m_state == State::Normal, svc::ResultPortClosed()); m_server.EnqueueSession(session); R_SUCCEED(); } Result KPort::EnqueueSession(KLightServerSession *session) { KScopedSchedulerLock sl; R_UNLESS(m_state == State::Normal, svc::ResultPortClosed()); m_server.EnqueueSession(session); R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_process.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr u64 InitialProcessIdMin = 1; constexpr u64 InitialProcessIdMax = 0x50; constexpr u64 ProcessIdMin = InitialProcessIdMax + 1; constexpr u64 ProcessIdMax = std::numeric_limits<u64>::max(); constinit util::Atomic<u64> g_initial_process_id = InitialProcessIdMin; constinit util::Atomic<u64> g_process_id = ProcessIdMin; Result TerminateChildren(KProcess *process, const KThread *thread_to_not_terminate) { /* Request that all children threads terminate. */ { KScopedLightLock proc_lk(process->GetListLock()); KScopedSchedulerLock sl; if (thread_to_not_terminate != nullptr && process->GetPinnedThread(GetCurrentCoreId()) == thread_to_not_terminate) { /* NOTE: Here Nintendo unpins the current thread instead of the thread_to_not_terminate. */ /* This is valid because the only caller which uses non-nullptr as argument uses GetCurrentThreadPointer(), */ /* but it's still notable because it seems incorrect at first glance. */ process->UnpinCurrentThread(); } auto &thread_list = process->GetThreadList(); for (auto it = thread_list.begin(); it != thread_list.end(); ++it) { if (KThread *thread = std::addressof(*it); thread != thread_to_not_terminate) { if (thread->GetState() != KThread::ThreadState_Terminated) { thread->RequestTerminate(); } } } } /* Wait for all children threads to terminate. */ while (true) { /* Get the next child. */ KThread *cur_child = nullptr; { KScopedLightLock proc_lk(process->GetListLock()); auto &thread_list = process->GetThreadList(); for (auto it = thread_list.begin(); it != thread_list.end(); ++it) { if (KThread *thread = std::addressof(*it); thread != thread_to_not_terminate) { if (thread->GetState() != KThread::ThreadState_Terminated) { if (AMS_LIKELY(thread->Open())) { cur_child = thread; break; } } } } } /* If we didn't find any non-terminated children, we're done. */ if (cur_child == nullptr) { break; } /* Terminate and close the thread. */ ON_SCOPE_EXIT { cur_child->Close(); }; if (const Result terminate_result = cur_child->Terminate(); svc::ResultTerminationRequested::Includes(terminate_result)) { R_THROW(terminate_result); } } R_SUCCEED(); } class ThreadQueueImplForKProcessEnterUserException final : public KThreadQueue { private: KThread **m_exception_thread; public: constexpr ThreadQueueImplForKProcessEnterUserException(KThread **t) : KThreadQueue(), m_exception_thread(t) { /* ... */ } virtual void EndWait(KThread *waiting_thread, Result wait_result) override { /* Set the exception thread. */ *m_exception_thread = waiting_thread; /* Invoke the base end wait handler. */ KThreadQueue::EndWait(waiting_thread, wait_result); } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread as a waiter on its mutex owner. */ waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } void KProcess::Finalize() { /* Delete the process local region. */ this->DeleteThreadLocalRegion(m_plr_address); /* Get the used memory size. */ const size_t used_memory_size = this->GetUsedNonSystemUserPhysicalMemorySize(); /* Finalize the page table. */ m_page_table.Finalize(); /* Finish using our system resource. */ { if (m_system_resource->IsSecureResource()) { /* Finalize optimized memory. If memory wasn't optimized, this is a no-op. */ Kernel::GetMemoryManager().FinalizeOptimizedMemory(this->GetId(), m_memory_pool); } m_system_resource->Close(); } /* Free all shared memory infos. */ { auto it = m_shared_memory_list.begin(); while (it != m_shared_memory_list.end()) { KSharedMemoryInfo *info = std::addressof(*it); KSharedMemory *shmem = info->GetSharedMemory(); while (!info->Close()) { shmem->Close(); } shmem->Close(); it = m_shared_memory_list.erase(it); KSharedMemoryInfo::Free(info); } } /* Close all references to our io regions. */ { auto it = m_io_region_list.begin(); while (it != m_io_region_list.end()) { KIoRegion *io_region = std::addressof(*it); it = m_io_region_list.erase(it); io_region->Close(); } } /* Our thread local page list must be empty at this point. */ MESOSPHERE_ABORT_UNLESS(m_partially_used_tlp_tree.empty()); MESOSPHERE_ABORT_UNLESS(m_fully_used_tlp_tree.empty()); /* Release memory to the resource limit. */ if (m_resource_limit != nullptr) { MESOSPHERE_ABORT_UNLESS(used_memory_size >= m_memory_release_hint); m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, used_memory_size, used_memory_size - m_memory_release_hint); m_resource_limit->Close(); } /* Log that we finalized for debug. */ MESOSPHERE_LOG("KProcess::Finalize() pid=%ld name=%-12s\n", m_process_id, m_name); /* Perform inherited finalization. */ KSynchronizationObject::Finalize(); } Result KProcess::Initialize(const ams::svc::CreateProcessParameter ¶ms) { /* Validate that the intended kernel version is high enough for us to support. */ R_UNLESS(m_capabilities.GetIntendedKernelVersion() >= ams::svc::RequiredKernelVersion, svc::ResultInvalidCombination()); /* Validate that the intended kernel version isn't too high for us to support. */ R_UNLESS(m_capabilities.GetIntendedKernelVersion() <= ams::svc::SupportedKernelVersion, svc::ResultInvalidCombination()); /* Create and clear the process local region. */ R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address))); m_plr_heap_address = this->GetThreadLocalRegionPointer(m_plr_address); std::memset(m_plr_heap_address, 0, ams::svc::ThreadLocalRegionSize); /* Copy in the name from parameters. */ static_assert(sizeof(params.name) < sizeof(m_name)); std::memcpy(m_name, params.name, sizeof(params.name)); m_name[sizeof(params.name)] = 0; /* Set misc fields. */ m_state = State_Created; m_main_thread_stack_size = 0; m_used_kernel_memory_size = 0; m_ideal_core_id = 0; m_flags = params.flags; m_version = params.version; m_program_id = params.program_id; m_code_address = params.code_address; m_code_size = params.code_num_pages * PageSize; m_is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication); m_is_jit_debug = false; #if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME) m_creation_time = KHardwareTimer::GetTick(); #endif /* Set thread fields. */ for (size_t i = 0; i < cpu::NumCores; i++) { m_running_threads[i] = nullptr; m_pinned_threads[i] = nullptr; m_running_thread_idle_counts[i] = 0; m_running_thread_switch_counts[i] = 0; } /* Set max memory. */ m_max_process_memory = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(m_flags), KAddressSpaceInfo::Type_Heap); /* Generate random entropy. */ KSystemControl::GenerateRandom(m_entropy, util::size(m_entropy)); /* Clear remaining fields. */ m_num_running_threads = 0; m_num_process_switches = 0; m_num_thread_switches = 0; m_num_fpu_switches = 0; m_num_supervisor_calls = 0; m_num_ipc_messages = 0; m_is_signaled = false; m_attached_object = nullptr; m_exception_thread = nullptr; m_is_suspended = false; m_memory_release_hint = 0; m_schedule_count = 0; m_is_handle_table_initialized = false; /* We're initialized! */ m_is_initialized = true; R_SUCCEED(); } Result KProcess::Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(res_limit != nullptr); MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast<size_t>(params.code_num_pages)); /* Set members. */ m_memory_pool = pool; m_resource_limit = res_limit; m_is_default_application_system_resource = false; m_is_immortal = immortal; /* Setup our system resource. */ if (const size_t system_resource_num_pages = params.system_resource_num_pages; system_resource_num_pages != 0) { /* Create a secure system resource. */ KSecureSystemResource *secure_resource = KSecureSystemResource::Create(); R_UNLESS(secure_resource != nullptr, svc::ResultOutOfResource()); ON_RESULT_FAILURE { secure_resource->Close(); }; /* Initialize the secure resource. */ R_TRY(secure_resource->Initialize(system_resource_num_pages * PageSize, m_resource_limit, m_memory_pool)); /* Set our system resource. */ m_system_resource = secure_resource; } else { /* Use the system-wide system resource. */ const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication); m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource()); m_is_default_application_system_resource = is_app; /* Open reference to the system resource. */ m_system_resource->Open(); } /* Ensure we clean up our secure resource, if we fail. */ ON_RESULT_FAILURE { m_system_resource->Close(); }; /* Setup page table. */ { const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0; R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit, this->GetSlabIndex())); } ON_RESULT_FAILURE_2 { m_page_table.Finalize(); }; /* Ensure we can insert the code region. */ R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, KMemoryState_Code), svc::ResultInvalidMemoryRegion()); /* Map the code region. */ R_TRY(m_page_table.MapPageGroup(params.code_address, pg, KMemoryState_Code, KMemoryPermission_KernelRead)); /* Initialize capabilities. */ R_TRY(m_capabilities.Initialize(caps, num_caps, std::addressof(m_page_table))); /* Initialize the process id. */ m_process_id = g_initial_process_id++; MESOSPHERE_ABORT_UNLESS(InitialProcessIdMin <= m_process_id); MESOSPHERE_ABORT_UNLESS(m_process_id <= InitialProcessIdMax); /* Initialize the rest of the process. */ R_TRY(this->Initialize(params)); /* Open a reference to the resource limit. */ m_resource_limit->Open(); /* We succeeded! */ R_SUCCEED(); } Result KProcess::Initialize(const ams::svc::CreateProcessParameter ¶ms, svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(res_limit != nullptr); /* Set pool and resource limit. */ m_memory_pool = pool; m_resource_limit = res_limit; m_is_default_application_system_resource = false; m_is_immortal = false; /* Get the memory sizes. */ const size_t code_num_pages = params.code_num_pages; const size_t system_resource_num_pages = params.system_resource_num_pages; const size_t code_size = code_num_pages * PageSize; const size_t system_resource_size = system_resource_num_pages * PageSize; /* Reserve memory for our code resource. */ KScopedResourceReservation memory_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, code_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Setup our system resource. */ if (system_resource_num_pages != 0) { /* Create a secure system resource. */ KSecureSystemResource *secure_resource = KSecureSystemResource::Create(); R_UNLESS(secure_resource != nullptr, svc::ResultOutOfResource()); ON_RESULT_FAILURE { secure_resource->Close(); }; /* Initialize the secure resource. */ R_TRY(secure_resource->Initialize(system_resource_size, m_resource_limit, m_memory_pool)); /* Set our system resource. */ m_system_resource = secure_resource; } else { /* Use the system-wide system resource. */ const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication); m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource()); m_is_default_application_system_resource = is_app; /* Open reference to the system resource. */ m_system_resource->Open(); } /* Ensure we clean up our secure resource, if we fail. */ ON_RESULT_FAILURE { m_system_resource->Close(); }; /* Setup page table. */ { const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0; R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit, this->GetSlabIndex())); } ON_RESULT_FAILURE_2 { m_page_table.Finalize(); }; /* Ensure we can insert the code region. */ R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState_Code), svc::ResultInvalidMemoryRegion()); /* Map the code region. */ R_TRY(m_page_table.MapPages(params.code_address, code_num_pages, KMemoryState_Code, static_cast<KMemoryPermission>(KMemoryPermission_KernelRead | KMemoryPermission_NotMapped))); /* Initialize capabilities. */ R_TRY(m_capabilities.Initialize(user_caps, num_caps, std::addressof(m_page_table))); /* Initialize the process id. */ m_process_id = g_process_id++; MESOSPHERE_ABORT_UNLESS(ProcessIdMin <= m_process_id); MESOSPHERE_ABORT_UNLESS(m_process_id <= ProcessIdMax); /* If we should optimize memory allocations, do so. */ if (m_system_resource->IsSecureResource() && (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0) { R_TRY(Kernel::GetMemoryManager().InitializeOptimizedMemory(m_process_id, pool)); } /* Initialize the rest of the process. */ R_TRY(this->Initialize(params)); /* Open a reference to the resource limit. */ m_resource_limit->Open(); /* We succeeded, so commit our memory reservation. */ memory_reservation.Commit(); R_SUCCEED(); } void KProcess::DoWorkerTaskImpl() { /* Terminate child threads. */ MESOSPHERE_R_ABORT_UNLESS(TerminateChildren(this, nullptr)); /* Finalize the handle table, if we're not immortal. */ if (!m_is_immortal && m_is_handle_table_initialized) { this->FinalizeHandleTable(); } /* Call the debug callback. */ KDebug::OnExitProcess(this); /* Finish termination. */ this->FinishTermination(); } Result KProcess::StartTermination() { /* Finalize the handle table when we're done, if the process isn't immortal. */ ON_RESULT_SUCCESS { if (!m_is_immortal) { this->FinalizeHandleTable(); } }; /* Terminate child threads other than the current one. */ R_RETURN(TerminateChildren(this, GetCurrentThreadPointer())); } void KProcess::FinishTermination() { /* Only allow termination to occur if the process isn't immortal. */ if (!m_is_immortal) { /* Release resource limit hint. */ if (m_resource_limit != nullptr) { m_memory_release_hint = this->GetUsedNonSystemUserPhysicalMemorySize(); m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, 0, m_memory_release_hint); } /* Change state. */ { KScopedSchedulerLock sl; this->ChangeState(State_Terminated); } /* Close. */ this->Close(); } } void KProcess::Exit() { MESOSPHERE_ASSERT_THIS(); /* Determine whether we need to start terminating. */ bool needs_terminate = false; { KScopedLightLock lk(m_state_lock); KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_state != State_Created); MESOSPHERE_ASSERT(m_state != State_CreatedAttached); MESOSPHERE_ASSERT(m_state != State_Crashed); MESOSPHERE_ASSERT(m_state != State_Terminated); if (m_state == State_Running || m_state == State_RunningAttached || m_state == State_DebugBreak) { this->ChangeState(State_Terminating); needs_terminate = true; } } /* If we need to start termination, do so. */ if (needs_terminate) { static_cast<void>(this->StartTermination()); /* Note for debug that we're exiting the process. */ MESOSPHERE_LOG("KProcess::Exit() pid=%ld name=%-12s\n", m_process_id, m_name); /* Register the process as a work task. */ KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitProcess, this); } /* Exit the current thread. */ GetCurrentThread().Exit(); MESOSPHERE_PANIC("Thread survived call to exit"); } Result KProcess::Terminate() { MESOSPHERE_ASSERT_THIS(); /* Determine whether we need to start terminating */ bool needs_terminate = false; { KScopedLightLock lk(m_state_lock); /* Check whether we're allowed to terminate. */ R_UNLESS(m_state != State_Created, svc::ResultInvalidState()); R_UNLESS(m_state != State_CreatedAttached, svc::ResultInvalidState()); KScopedSchedulerLock sl; if (m_state == State_Running || m_state == State_RunningAttached || m_state == State_Crashed || m_state == State_DebugBreak) { this->ChangeState(State_Terminating); needs_terminate = true; } } /* If we need to terminate, do so. */ if (needs_terminate) { /* If we fail to terminate, register as a worker task. */ ON_RESULT_FAILURE { /* Note for debug that we're terminating the process. */ MESOSPHERE_LOG("KProcess::Terminate() FAIL pid=%ld name=%-12s\n", m_process_id, m_name); /* Register the process as a work task. */ KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitProcess, this); }; /* Start termination. */ R_TRY(this->StartTermination()); /* Note for debug that we're terminating the process. */ MESOSPHERE_LOG("KProcess::Terminate() OK pid=%ld name=%-12s\n", m_process_id, m_name); /* Call the debug callback. */ KDebug::OnTerminateProcess(this); /* Finish termination. */ this->FinishTermination(); } R_SUCCEED(); } Result KProcess::AddSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size) { /* Lock ourselves, to prevent concurrent access. */ KScopedLightLock lk(m_state_lock); /* Address and size parameters aren't used. */ MESOSPHERE_UNUSED(address, size); /* Try to find an existing info for the memory. */ KSharedMemoryInfo *info = nullptr; for (auto it = m_shared_memory_list.begin(); it != m_shared_memory_list.end(); ++it) { if (it->GetSharedMemory() == shmem) { info = std::addressof(*it); break; } } /* If we didn't find an info, create one. */ if (info == nullptr) { /* Allocate a new info. */ info = KSharedMemoryInfo::Allocate(); R_UNLESS(info != nullptr, svc::ResultOutOfResource()); /* Initialize the info and add it to our list. */ info->Initialize(shmem); m_shared_memory_list.push_back(*info); } /* Open a reference to the shared memory and its info. */ shmem->Open(); info->Open(); R_SUCCEED(); } void KProcess::RemoveSharedMemory(KSharedMemory *shmem, KProcessAddress address, size_t size) { /* Lock ourselves, to prevent concurrent access. */ KScopedLightLock lk(m_state_lock); /* Address and size parameters aren't used. */ MESOSPHERE_UNUSED(address, size); /* Find an existing info for the memory. */ KSharedMemoryInfo *info = nullptr; auto it = m_shared_memory_list.begin(); for (/* ... */; it != m_shared_memory_list.end(); ++it) { if (it->GetSharedMemory() == shmem) { info = std::addressof(*it); break; } } MESOSPHERE_ABORT_UNLESS(info != nullptr); /* Close a reference to the info and its memory. */ if (info->Close()) { m_shared_memory_list.erase(it); KSharedMemoryInfo::Free(info); } shmem->Close(); } void KProcess::AddIoRegion(KIoRegion *io_region) { /* Lock ourselves, to prevent concurrent access. */ KScopedLightLock lk(m_state_lock); /* Open a reference to the region. */ io_region->Open(); /* Add the region to our list. */ m_io_region_list.push_back(*io_region); } void KProcess::RemoveIoRegion(KIoRegion *io_region) { /* Remove the region from our list. */ { /* Lock ourselves, to prevent concurrent access. */ KScopedLightLock lk(m_state_lock); /* Remove the region from our list. */ m_io_region_list.erase(m_io_region_list.iterator_to(*io_region)); } /* Close our reference to the io region. */ io_region->Close(); } Result KProcess::CreateThreadLocalRegion(KProcessAddress *out) { KThreadLocalPage *tlp = nullptr; KProcessAddress tlr = Null<KProcessAddress>; /* See if we can get a region from a partially used TLP. */ { KScopedSchedulerLock sl; if (auto it = m_partially_used_tlp_tree.begin(); it != m_partially_used_tlp_tree.end()) { tlr = it->Reserve(); MESOSPHERE_ABORT_UNLESS(tlr != Null<KProcessAddress>); if (it->IsAllUsed()) { tlp = std::addressof(*it); m_partially_used_tlp_tree.erase(it); m_fully_used_tlp_tree.insert(*tlp); } *out = tlr; R_SUCCEED(); } } /* Allocate a new page. */ tlp = KThreadLocalPage::Allocate(); R_UNLESS(tlp != nullptr, svc::ResultOutOfMemory()); ON_RESULT_FAILURE { KThreadLocalPage::Free(tlp); }; /* Initialize the new page. */ R_TRY(tlp->Initialize(this)); /* Reserve a TLR. */ tlr = tlp->Reserve(); MESOSPHERE_ABORT_UNLESS(tlr != Null<KProcessAddress>); /* Insert into our tree. */ { KScopedSchedulerLock sl; if (tlp->IsAllUsed()) { m_fully_used_tlp_tree.insert(*tlp); } else { m_partially_used_tlp_tree.insert(*tlp); } } /* We succeeded! */ *out = tlr; R_SUCCEED(); } void KProcess::DeleteThreadLocalRegion(KProcessAddress addr) { KThreadLocalPage *page_to_free = nullptr; /* Release the region. */ { KScopedSchedulerLock sl; /* Try to find the page in the partially used list. */ auto it = m_partially_used_tlp_tree.find_key(util::AlignDown(GetInteger(addr), PageSize)); if (it == m_partially_used_tlp_tree.end()) { /* If we don't find it, it has to be in the fully used list. */ it = m_fully_used_tlp_tree.find_key(util::AlignDown(GetInteger(addr), PageSize)); MESOSPHERE_ABORT_UNLESS(it != m_fully_used_tlp_tree.end()); /* Release the region. */ it->Release(addr); /* Move the page out of the fully used list. */ KThreadLocalPage *tlp = std::addressof(*it); m_fully_used_tlp_tree.erase(it); if (tlp->IsAllFree()) { page_to_free = tlp; } else { m_partially_used_tlp_tree.insert(*tlp); } } else { /* Release the region. */ it->Release(addr); /* Handle the all-free case. */ KThreadLocalPage *tlp = std::addressof(*it); if (tlp->IsAllFree()) { m_partially_used_tlp_tree.erase(it); page_to_free = tlp; } } } /* If we should free the page it was in, do so. */ if (page_to_free != nullptr) { page_to_free->Finalize(); KThreadLocalPage::Free(page_to_free); } } void *KProcess::GetThreadLocalRegionPointer(KProcessAddress addr) { KThreadLocalPage *tlp = nullptr; { KScopedSchedulerLock sl; if (auto it = m_partially_used_tlp_tree.find_key(util::AlignDown(GetInteger(addr), PageSize)); it != m_partially_used_tlp_tree.end()) { tlp = std::addressof(*it); } else if (auto it = m_fully_used_tlp_tree.find_key(util::AlignDown(GetInteger(addr), PageSize)); it != m_fully_used_tlp_tree.end()) { tlp = std::addressof(*it); } else { return nullptr; } } return static_cast<u8 *>(tlp->GetPointer()) + (GetInteger(addr) & (PageSize - 1)); } bool KProcess::ReserveResource(ams::svc::LimitableResource which, s64 value) { if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { return rl->Reserve(which, value); } else { return true; } } bool KProcess::ReserveResource(ams::svc::LimitableResource which, s64 value, s64 timeout) { if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { return rl->Reserve(which, value, timeout); } else { return true; } } void KProcess::ReleaseResource(ams::svc::LimitableResource which, s64 value) { if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { rl->Release(which, value); } } void KProcess::ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint) { if (KResourceLimit *rl = this->GetResourceLimit(); rl != nullptr) { rl->Release(which, value, hint); } } void KProcess::IncrementRunningThreadCount() { MESOSPHERE_ASSERT(m_num_running_threads.Load() >= 0); ++m_num_running_threads; } void KProcess::DecrementRunningThreadCount() { MESOSPHERE_ASSERT(m_num_running_threads.Load() > 0); if (const auto prev = m_num_running_threads--; prev == 1) { static_cast<void>(this->Terminate()); } } bool KProcess::EnterUserException() { /* Get the current thread. */ KThread *cur_thread = GetCurrentThreadPointer(); MESOSPHERE_ASSERT(this == cur_thread->GetOwnerProcess()); /* Check that we haven't already claimed the exception thread. */ if (m_exception_thread == cur_thread) { return false; } /* Create the wait queue we'll be using. */ ThreadQueueImplForKProcessEnterUserException wait_queue(std::addressof(m_exception_thread)); /* Claim the exception thread. */ { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Check that we're not terminating. */ if (cur_thread->IsTerminationRequested()) { return false; } /* If we don't have an exception thread, we can just claim it directly. */ if (m_exception_thread == nullptr) { m_exception_thread = cur_thread; KScheduler::SetSchedulerUpdateNeeded(); return true; } /* Otherwise, we need to wait until we don't have an exception thread. */ /* Add the current thread as a waiter on the current exception thread. */ cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); m_exception_thread->AddWaiter(cur_thread); /* Wait to claim the exception thread. */ cur_thread->BeginWait(std::addressof(wait_queue)); } /* If our wait didn't end due to thread termination, we succeeded. */ return !svc::ResultTerminationRequested::Includes(cur_thread->GetWaitResult()); } bool KProcess::LeaveUserException() { return this->ReleaseUserException(GetCurrentThreadPointer()); } bool KProcess::ReleaseUserException(KThread *thread) { KScopedSchedulerLock sl; if (m_exception_thread == thread) { m_exception_thread = nullptr; /* Remove waiter thread. */ bool has_waiters; if (KThread *next = thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); next != nullptr) { next->EndWait(ResultSuccess()); } KScheduler::SetSchedulerUpdateNeeded(); return true; } else { return false; } } void KProcess::RegisterThread(KThread *thread) { KScopedLightLock lk(m_list_lock); m_thread_list.push_back(*thread); } void KProcess::UnregisterThread(KThread *thread) { KScopedLightLock lk(m_list_lock); m_thread_list.erase(m_thread_list.iterator_to(*thread)); } size_t KProcess::GetUsedUserPhysicalMemorySize() const { const size_t norm_size = m_page_table.GetNormalMemorySize(); const size_t other_size = m_code_size + m_main_thread_stack_size; const size_t sec_size = this->GetRequiredSecureMemorySizeNonDefault(); return norm_size + other_size + sec_size; } size_t KProcess::GetTotalUserPhysicalMemorySize() const { /* Get the amount of free and used size. */ const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax); const size_t max_size = m_max_process_memory; /* Determine used size. */ /* NOTE: This does *not* check this->IsDefaultApplicationSystemResource(), unlike GetUsedUserPhysicalMemorySize(). */ const size_t norm_size = m_page_table.GetNormalMemorySize(); const size_t other_size = m_code_size + m_main_thread_stack_size; const size_t sec_size = this->GetRequiredSecureMemorySize(); const size_t used_size = norm_size + other_size + sec_size; /* NOTE: These function calls will recalculate, introducing a race...it is unclear why Nintendo does it this way. */ if (used_size + free_size > max_size) { return max_size; } else { return free_size + this->GetUsedUserPhysicalMemorySize(); } } size_t KProcess::GetUsedNonSystemUserPhysicalMemorySize() const { const size_t norm_size = m_page_table.GetNormalMemorySize(); const size_t other_size = m_code_size + m_main_thread_stack_size; return norm_size + other_size; } size_t KProcess::GetTotalNonSystemUserPhysicalMemorySize() const { /* Get the amount of free and used size. */ const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax); const size_t max_size = m_max_process_memory; /* Determine used size. */ /* NOTE: This does *not* check this->IsDefaultApplicationSystemResource(), unlike GetUsedUserPhysicalMemorySize(). */ const size_t norm_size = m_page_table.GetNormalMemorySize(); const size_t other_size = m_code_size + m_main_thread_stack_size; const size_t sec_size = this->GetRequiredSecureMemorySize(); const size_t used_size = norm_size + other_size + sec_size; /* NOTE: These function calls will recalculate, introducing a race...it is unclear why Nintendo does it this way. */ if (used_size + free_size > max_size) { return max_size - this->GetRequiredSecureMemorySizeNonDefault(); } else { return free_size + this->GetUsedNonSystemUserPhysicalMemorySize(); } } Result KProcess::Run(s32 priority, size_t stack_size) { MESOSPHERE_ASSERT_THIS(); /* Lock ourselves, to prevent concurrent access. */ KScopedLightLock lk(m_state_lock); /* Validate that we're in a state where we can initialize. */ const auto state = m_state; R_UNLESS(state == State_Created || state == State_CreatedAttached, svc::ResultInvalidState()); /* Place a tentative reservation of a thread for this process. */ KScopedResourceReservation thread_reservation(this, ams::svc::LimitableResource_ThreadCountMax); R_UNLESS(thread_reservation.Succeeded(), svc::ResultLimitReached()); /* Ensure that we haven't already allocated stack. */ MESOSPHERE_ABORT_UNLESS(m_main_thread_stack_size == 0); /* Ensure that we're allocating a valid stack. */ R_UNLESS(stack_size + m_code_size <= m_max_process_memory, svc::ResultOutOfMemory()); R_UNLESS(stack_size + m_code_size >= m_code_size, svc::ResultOutOfMemory()); /* Place a tentative reservation of memory for our new stack. */ KScopedResourceReservation mem_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, stack_size); R_UNLESS(mem_reservation.Succeeded(), svc::ResultLimitReached()); /* Allocate and map our stack. */ KProcessAddress stack_top = Null<KProcessAddress>; if (stack_size) { KProcessAddress stack_bottom; R_TRY(m_page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize, KMemoryState_Stack, KMemoryPermission_UserReadWrite)); stack_top = stack_bottom + stack_size; m_main_thread_stack_size = stack_size; } /* Ensure our stack is safe to clean up on exit. */ ON_RESULT_FAILURE { if (m_main_thread_stack_size) { MESOSPHERE_R_ABORT_UNLESS(m_page_table.UnmapPages(stack_top - m_main_thread_stack_size, m_main_thread_stack_size / PageSize, KMemoryState_Stack)); m_main_thread_stack_size = 0; } }; /* Set our maximum heap size. */ R_TRY(m_page_table.SetMaxHeapSize(m_max_process_memory - (m_main_thread_stack_size + m_code_size))); /* Initialize our handle table. */ R_TRY(this->InitializeHandleTable(m_capabilities.GetHandleTableSize())); ON_RESULT_FAILURE_2 { this->FinalizeHandleTable(); }; /* Create a new thread for the process. */ KThread *main_thread = KThread::Create(); R_UNLESS(main_thread != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { main_thread->Close(); }; /* Initialize the thread. */ R_TRY(KThread::InitializeUserThread(main_thread, reinterpret_cast<KThreadFunction>(GetVoidPointer(this->GetEntryPoint())), 0, stack_top, priority, m_ideal_core_id, this)); /* Register the thread, and commit our reservation. */ KThread::Register(main_thread); thread_reservation.Commit(); /* Add the thread to our handle table. */ ams::svc::Handle thread_handle; R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread)); /* Set the thread arguments. */ main_thread->GetContext().SetArguments(0, thread_handle); /* Update our state. */ this->ChangeState((state == State_Created) ? State_Running : State_RunningAttached); ON_RESULT_FAILURE_2 { this->ChangeState(state); }; /* Run our thread. */ R_TRY(main_thread->Run()); /* Open a reference to represent that we're running. */ this->Open(); /* We succeeded! Commit our memory reservation. */ mem_reservation.Commit(); /* Note for debug that we're running a new process. */ MESOSPHERE_LOG("KProcess::Run() pid=%ld name=%-12s thread=%ld affinity=0x%lx ideal_core=%d active_core=%d\n", m_process_id, m_name, main_thread->GetId(), main_thread->GetVirtualAffinityMask(), main_thread->GetIdealVirtualCore(), main_thread->GetActiveCore()); R_SUCCEED(); } Result KProcess::Reset() { MESOSPHERE_ASSERT_THIS(); /* Lock the process and the scheduler. */ KScopedLightLock lk(m_state_lock); KScopedSchedulerLock sl; /* Validate that we're in a state that we can reset. */ R_UNLESS(m_state != State_Terminated, svc::ResultInvalidState()); R_UNLESS(m_is_signaled, svc::ResultInvalidState()); /* Clear signaled. */ m_is_signaled = false; R_SUCCEED(); } Result KProcess::SetActivity(ams::svc::ProcessActivity activity) { /* Lock ourselves and the scheduler. */ KScopedLightLock lk(m_state_lock); KScopedLightLock list_lk(m_list_lock); KScopedSchedulerLock sl; /* Validate our state. */ R_UNLESS(m_state != State_Terminating, svc::ResultInvalidState()); R_UNLESS(m_state != State_Terminated, svc::ResultInvalidState()); /* Either pause or resume. */ if (activity == ams::svc::ProcessActivity_Paused) { /* Verify that we're not suspended. */ R_UNLESS(!m_is_suspended, svc::ResultInvalidState()); /* Suspend all threads. */ auto end = this->GetThreadList().end(); for (auto it = this->GetThreadList().begin(); it != end; ++it) { it->RequestSuspend(KThread::SuspendType_Process); } /* Set ourselves as suspended. */ this->SetSuspended(true); } else { MESOSPHERE_ASSERT(activity == ams::svc::ProcessActivity_Runnable); /* Verify that we're suspended. */ R_UNLESS(m_is_suspended, svc::ResultInvalidState()); /* Resume all threads. */ auto end = this->GetThreadList().end(); for (auto it = this->GetThreadList().begin(); it != end; ++it) { it->Resume(KThread::SuspendType_Process); } /* Set ourselves as resumed. */ this->SetSuspended(false); } R_SUCCEED(); } void KProcess::PinCurrentThread() { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Get the current thread. */ const s32 core_id = GetCurrentCoreId(); KThread *cur_thread = GetCurrentThreadPointer(); /* If the thread isn't terminated, pin it. */ if (!cur_thread->IsTerminationRequested()) { /* Pin it. */ this->PinThread(core_id, cur_thread); cur_thread->Pin(); /* An update is needed. */ KScheduler::SetSchedulerUpdateNeeded(); } } void KProcess::UnpinCurrentThread() { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Get the current thread. */ const s32 core_id = GetCurrentCoreId(); KThread *cur_thread = GetCurrentThreadPointer(); /* Unpin it. */ cur_thread->Unpin(); this->UnpinThread(core_id, cur_thread); /* An update is needed. */ KScheduler::SetSchedulerUpdateNeeded(); } void KProcess::UnpinThread(KThread *thread) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Get the thread's core id. */ const auto core_id = thread->GetActiveCore(); /* Unpin it. */ this->UnpinThread(core_id, thread); thread->Unpin(); /* An update is needed. */ KScheduler::SetSchedulerUpdateNeeded(); } Result KProcess::GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count) { /* Lock the list. */ KScopedLightLock lk(m_list_lock); /* Iterate over the list. */ s32 count = 0; auto end = this->GetThreadList().end(); for (auto it = this->GetThreadList().begin(); it != end; ++it) { /* If we're within array bounds, write the id. */ if (count < max_out_count) { /* Get the thread id. */ KThread *thread = std::addressof(*it); const u64 id = thread->GetId(); /* Copy the id to userland. */ R_TRY(out_thread_ids.CopyArrayElementFrom(std::addressof(id), count)); } /* Increment the count. */ ++count; } /* We successfully iterated the list. */ *out_num_threads = count; R_SUCCEED(); } KProcess::State KProcess::SetDebugObject(void *debug_object) { /* Attaching should only happen to non-null objects while the scheduler is locked. */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(debug_object != nullptr); /* Cache our state to return it to the debug object. */ const auto old_state = m_state; /* Set the object. */ m_attached_object = debug_object; /* Check that our state is valid for attach. */ MESOSPHERE_ASSERT(m_state == State_Created || m_state == State_Running || m_state == State_Crashed); /* Update our state. */ if (m_state != State_DebugBreak) { if (m_state == State_Created) { this->ChangeState(State_CreatedAttached); } else { this->ChangeState(State_DebugBreak); } } return old_state; } void KProcess::ClearDebugObject(KProcess::State old_state) { /* Detaching from process should only happen while the scheduler is locked. */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Clear the attached object. */ m_attached_object = nullptr; /* Validate that the process is in an attached state. */ MESOSPHERE_ASSERT(m_state == State_CreatedAttached || m_state == State_RunningAttached || m_state == State_DebugBreak || m_state == State_Terminating || m_state == State_Terminated); /* Change the state appropriately. */ if (m_state == State_CreatedAttached) { this->ChangeState(State_Created); } else if (m_state == State_RunningAttached || m_state == State_DebugBreak) { /* Disallow transition back to created from running. */ if (old_state == State_Created) { old_state = State_Running; } this->ChangeState(old_state); } } bool KProcess::EnterJitDebug(ams::svc::DebugEvent event, ams::svc::DebugException exception, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) { /* Check that we're the current process. */ MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this == GetCurrentProcessPointer()); /* If we aren't allowed to enter jit debug, don't. */ if ((m_flags & ams::svc::CreateProcessFlag_EnableDebug) == 0) { return false; } /* We're the current process, so we should be some kind of running. */ MESOSPHERE_ASSERT(m_state != State_Created); MESOSPHERE_ASSERT(m_state != State_CreatedAttached); MESOSPHERE_ASSERT(m_state != State_Terminated); /* Try to enter JIT debug. */ while (true) { /* Lock ourselves and the scheduler. */ KScopedLightLock lk(m_state_lock); KScopedLightLock list_lk(m_list_lock); KScopedSchedulerLock sl; /* If we're attached to a debugger, we're necessarily in debug. */ if (this->IsAttachedToDebugger()) { return true; } /* If the current thread is terminating, we can't enter debug. */ if (GetCurrentThread().IsTerminationRequested()) { return false; } /* We're not attached to debugger, so check that. */ MESOSPHERE_ASSERT(m_state != State_RunningAttached); MESOSPHERE_ASSERT(m_state != State_DebugBreak); /* If we're terminating, we can't enter debug. */ if (m_state != State_Running && m_state != State_Crashed) { MESOSPHERE_ASSERT(m_state == State_Terminating); return false; } /* If the current thread is suspended, retry. */ if (GetCurrentThread().IsSuspended()) { continue; } /* Suspend all our threads. */ { auto end = this->GetThreadList().end(); for (auto it = this->GetThreadList().begin(); it != end; ++it) { it->RequestSuspend(KThread::SuspendType_Debug); } } /* Change our state to crashed. */ this->ChangeState(State_Crashed); /* Enter jit debug. */ m_is_jit_debug = true; m_jit_debug_event_type = event; m_jit_debug_exception_type = exception; m_jit_debug_params[0] = param1; m_jit_debug_params[1] = param2; m_jit_debug_params[2] = param3; m_jit_debug_params[3] = param4; m_jit_debug_thread_id = GetCurrentThread().GetId(); /* Exit our retry loop. */ break; } /* Check if our state indicates we're in jit debug. */ { KScopedSchedulerLock sl; if (m_state == State_Running || m_state == State_RunningAttached || m_state == State_Crashed || m_state == State_DebugBreak) { return true; } } return false; } KEventInfo *KProcess::GetJitDebugInfo() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); if (m_is_jit_debug) { const uintptr_t params[5] = { m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3] }; return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_thread_id, params, util::size(params)); } else { return nullptr; } } void KProcess::ClearJitDebugInfo() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); m_is_jit_debug = false; } KProcess *KProcess::GetProcessFromId(u64 process_id) { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Iterate over the list. */ for (auto it = accessor.begin(); it != end; ++it) { /* Get the process. */ KProcess *process = static_cast<KProcess *>(std::addressof(*it)); if (process->GetId() == process_id) { if (AMS_LIKELY(process->Open())) { return process; } } } /* We failed to find the process. */ return nullptr; } Result KProcess::GetProcessList(s32 *out_num_processes, ams::kern::svc::KUserPointer<u64 *> out_process_ids, s32 max_out_count) { /* Lock the list. */ KProcess::ListAccessor accessor; const auto end = accessor.end(); /* Iterate over the list. */ s32 count = 0; for (auto it = accessor.begin(); it != end; ++it) { /* If we're within array bounds, write the id. */ if (count < max_out_count) { /* Get the process id. */ KProcess *process = static_cast<KProcess *>(std::addressof(*it)); const u64 id = process->GetId(); /* Copy the id to userland. */ R_TRY(out_process_ids.CopyArrayElementFrom(std::addressof(id), count)); } /* Increment the count. */ ++count; } /* We successfully iterated the list. */ *out_num_processes = count; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_readable_event.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KReadableEvent::Initialize(KEvent *parent) { MESOSPHERE_ASSERT_THIS(); m_is_signaled = false; m_parent = parent; if (m_parent != nullptr) { m_parent->Open(); } } bool KReadableEvent::IsSignaled() const { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); return m_is_signaled; } void KReadableEvent::Destroy() { MESOSPHERE_ASSERT_THIS(); if (m_parent) { { KScopedSchedulerLock sl; m_parent->OnReadableEventDestroyed(); } m_parent->Close(); } } void KReadableEvent::Signal() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock lk; if (!m_is_signaled) { m_is_signaled = true; this->NotifyAvailable(); } } Result KReadableEvent::Reset() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock lk; R_UNLESS(m_is_signaled, svc::ResultInvalidState()); m_is_signaled = false; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_resource_limit.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr s64 DefaultTimeout = ams::svc::Tick(TimeSpan::FromSeconds(10)); } void KResourceLimit::Initialize() { m_waiter_count = 0; std::memset(m_limit_values, 0, sizeof(m_limit_values)); std::memset(m_current_values, 0, sizeof(m_current_values)); std::memset(m_current_hints, 0, sizeof(m_current_hints)); std::memset(m_peak_values, 0, sizeof(m_peak_values)); } void KResourceLimit::Finalize() { /* ... */ } s64 KResourceLimit::GetLimitValue(ams::svc::LimitableResource which) const { MESOSPHERE_ASSERT_THIS(); s64 value; { KScopedLightLock lk(m_lock); value = m_limit_values[which]; MESOSPHERE_ASSERT(value >= 0); MESOSPHERE_ASSERT(m_current_values[which] <= m_peak_values[which]); MESOSPHERE_ASSERT(m_peak_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); } return value; } s64 KResourceLimit::GetCurrentValue(ams::svc::LimitableResource which) const { MESOSPHERE_ASSERT_THIS(); s64 value; { KScopedLightLock lk(m_lock); value = m_current_values[which]; MESOSPHERE_ASSERT(value >= 0); MESOSPHERE_ASSERT(m_current_values[which] <= m_peak_values[which]); MESOSPHERE_ASSERT(m_peak_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); } return value; } s64 KResourceLimit::GetPeakValue(ams::svc::LimitableResource which) const { MESOSPHERE_ASSERT_THIS(); s64 value; { KScopedLightLock lk(m_lock); value = m_peak_values[which]; MESOSPHERE_ASSERT(value >= 0); MESOSPHERE_ASSERT(m_current_values[which] <= m_peak_values[which]); MESOSPHERE_ASSERT(m_peak_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); } return value; } s64 KResourceLimit::GetFreeValue(ams::svc::LimitableResource which) const { MESOSPHERE_ASSERT_THIS(); s64 value; { KScopedLightLock lk(m_lock); MESOSPHERE_ASSERT(m_current_values[which] >= 0); MESOSPHERE_ASSERT(m_current_values[which] <= m_peak_values[which]); MESOSPHERE_ASSERT(m_peak_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); value = m_limit_values[which] - m_current_values[which]; } return value; } Result KResourceLimit::SetLimitValue(ams::svc::LimitableResource which, s64 value) { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); R_UNLESS(m_current_values[which] <= value, svc::ResultInvalidState()); m_limit_values[which] = value; m_peak_values[which] = m_current_values[which]; R_SUCCEED(); } void KResourceLimit::Add(ams::svc::LimitableResource which, s64 value) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KTargetSystem::IsDynamicResourceLimitsEnabled()); KScopedLightLock lk(m_lock); /* Check that this is a true increase. */ MESOSPHERE_ABORT_UNLESS(value > 0); /* Check that we can perform an increase. */ MESOSPHERE_ABORT_UNLESS(m_current_values[which] <= m_peak_values[which]); MESOSPHERE_ABORT_UNLESS(m_peak_values[which] <= m_limit_values[which]); MESOSPHERE_ABORT_UNLESS(m_current_hints[which] <= m_current_values[which]); /* Check that the increase doesn't cause an overflow. */ const auto increased_limit = m_limit_values[which] + value; const auto increased_current = m_current_values[which] + value; const auto increased_hint = m_current_hints[which] + value; MESOSPHERE_ABORT_UNLESS(m_limit_values[which] < increased_limit); MESOSPHERE_ABORT_UNLESS(m_current_values[which] < increased_current); MESOSPHERE_ABORT_UNLESS(m_current_hints[which] < increased_hint); /* Add the value. */ m_limit_values[which] = increased_limit; m_current_values[which] = increased_current; m_current_hints[which] = increased_hint; /* Update our peak. */ m_peak_values[which] = std::max(m_peak_values[which], increased_current); } bool KResourceLimit::Reserve(ams::svc::LimitableResource which, s64 value) { return this->Reserve(which, value, KHardwareTimer::GetTick() + DefaultTimeout); } bool KResourceLimit::Reserve(ams::svc::LimitableResource which, s64 value, s64 timeout) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(value >= 0); KScopedLightLock lk(m_lock); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); if (m_current_hints[which] >= m_limit_values[which]) { return false; } /* Loop until we reserve or run out of time. */ while (true) { MESOSPHERE_ASSERT(m_current_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); /* If we would overflow, don't allow to succeed. */ if (m_current_values[which] + value <= m_current_values[which]) { break; } if (m_current_values[which] + value <= m_limit_values[which]) { m_current_values[which] += value; m_current_hints[which] += value; m_peak_values[which] = std::max(m_peak_values[which], m_current_values[which]); return true; } if (m_current_hints[which] + value <= m_limit_values[which] && (timeout < 0 || KHardwareTimer::GetTick() < timeout)) { m_waiter_count++; m_cond_var.Wait(std::addressof(m_lock), timeout, false); m_waiter_count--; if (GetCurrentThread().IsTerminationRequested()) { return false; } } else { break; } } return false; } void KResourceLimit::Release(ams::svc::LimitableResource which, s64 value) { this->Release(which, value, value); } void KResourceLimit::Release(ams::svc::LimitableResource which, s64 value, s64 hint) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(value >= 0); MESOSPHERE_ASSERT(hint >= 0); KScopedLightLock lk(m_lock); MESOSPHERE_ASSERT(m_current_values[which] <= m_limit_values[which]); MESOSPHERE_ASSERT(m_current_hints[which] <= m_current_values[which]); MESOSPHERE_ASSERT(value <= m_current_values[which]); MESOSPHERE_ASSERT(hint <= m_current_hints[which]); m_current_values[which] -= value; m_current_hints[which] -= hint; if (m_waiter_count != 0) { m_cond_var.Broadcast(); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_scheduler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #pragma GCC push_options #pragma GCC optimize ("-O3") namespace ams::kern { bool KScheduler::s_scheduler_update_needed; KScheduler::LockType KScheduler::s_scheduler_lock; KSchedulerPriorityQueue KScheduler::s_priority_queue; namespace { class KSchedulerInterruptHandler : public KInterruptHandler { public: constexpr KSchedulerInterruptHandler() : KInterruptHandler() { /* ... */ } virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { MESOSPHERE_UNUSED(interrupt_id); return GetDummyInterruptTask(); } }; ALWAYS_INLINE void IncrementScheduledCount(KThread *thread) { if (KProcess *parent = thread->GetOwnerProcess(); parent != nullptr) { parent->IncrementScheduledCount(); } } KSchedulerInterruptHandler g_scheduler_interrupt_handler; ALWAYS_INLINE auto *GetSchedulerInterruptHandler() { return std::addressof(g_scheduler_interrupt_handler); } } void KScheduler::Initialize(KThread *idle_thread) { /* Set core ID/idle thread/interrupt task manager. */ m_core_id = GetCurrentCoreId(); m_idle_thread = idle_thread; m_state.idle_thread_stack = m_idle_thread->GetStackTop(); m_state.interrupt_task_manager = std::addressof(Kernel::GetInterruptTaskManager()); /* Insert the main thread into the priority queue. */ { KScopedSchedulerLock lk; GetPriorityQueue().PushBack(GetCurrentThreadPointer()); SetSchedulerUpdateNeeded(); } /* Bind interrupt handler. */ MESOSPHERE_R_ABORT_UNLESS(Kernel::GetInterruptManager().BindHandler(GetSchedulerInterruptHandler(), KInterruptName_Scheduler, m_core_id, KInterruptController::PriorityLevel_Scheduler, false, false)); /* Set the current thread. */ m_current_thread = GetCurrentThreadPointer(); } void KScheduler::Activate() { MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() == 1); m_state.should_count_idle = KTargetSystem::IsDebugMode(); m_is_active = true; RescheduleCurrentCore(); } u64 KScheduler::UpdateHighestPriorityThread(KThread *highest_thread) { if (KThread *prev_highest_thread = m_state.highest_priority_thread; AMS_LIKELY(prev_highest_thread != highest_thread)) { if (AMS_LIKELY(prev_highest_thread != nullptr)) { IncrementScheduledCount(prev_highest_thread); prev_highest_thread->SetLastScheduledTick(KHardwareTimer::GetTick()); } if (m_state.should_count_idle) { if (AMS_LIKELY(highest_thread != nullptr)) { if (KProcess *process = highest_thread->GetOwnerProcess(); process != nullptr) { /* Set running thread (and increment switch count). */ process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count, ++m_state.switch_count); } } else { /* Set idle count and switch count to switch count + 1. */ m_state.idle_count = ++m_state.switch_count; } } MESOSPHERE_KTRACE_SCHEDULE_UPDATE(m_core_id, (prev_highest_thread != nullptr ? prev_highest_thread : m_idle_thread), (highest_thread != nullptr ? highest_thread : m_idle_thread)); m_state.highest_priority_thread = highest_thread; m_state.needs_scheduling = true; return (1ul << m_core_id); } else { return 0; } } u64 KScheduler::UpdateHighestPriorityThreadsImpl() { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); /* Clear that we need to update. */ ClearSchedulerUpdateNeeded(); u64 cores_needing_scheduling = 0, idle_cores = 0; KThread *top_threads[cpu::NumCores]; auto &priority_queue = GetPriorityQueue(); /* We want to go over all cores, finding the highest priority thread and determining if scheduling is needed for that core. */ for (size_t core_id = 0; core_id < cpu::NumCores; core_id++) { KThread *top_thread = priority_queue.GetScheduledFront(core_id); if (top_thread != nullptr) { /* We need to check if the thread's process has a pinned thread. */ if (KProcess *parent = top_thread->GetOwnerProcess(); parent != nullptr) { /* Check that there's a pinned thread other than the current top thread. */ if (KThread *pinned = parent->GetPinnedThread(core_id); pinned != nullptr && pinned != top_thread) { /* We need to prefer threads with kernel waiters to the pinned thread. */ if (top_thread->GetNumKernelWaiters() == 0 && top_thread != parent->GetExceptionThread()) { /* If the pinned thread is runnable, use it. */ if (pinned->GetRawState() == KThread::ThreadState_Runnable) { top_thread = pinned; } else { top_thread = nullptr; } } } } } else { idle_cores |= (1ul << core_id); } top_threads[core_id] = top_thread; cores_needing_scheduling |= Kernel::GetScheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]); } /* Idle cores are bad. We're going to try to migrate threads to each idle core in turn. */ while (idle_cores != 0) { s32 core_id = __builtin_ctzll(idle_cores); if (KThread *suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { s32 migration_candidates[cpu::NumCores]; size_t num_candidates = 0; /* While we have a suggested thread, try to migrate it! */ while (suggested != nullptr) { /* Check if the suggested thread is the top thread on its core. */ const s32 suggested_core = suggested->GetActiveCore(); if (KThread *top_thread = (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; top_thread != suggested) { /* Make sure we're not dealing with threads too high priority for migration. */ if (top_thread != nullptr && top_thread->GetPriority() < HighestCoreMigrationAllowedPriority) { break; } /* The suggested thread isn't bound to its core, so we can migrate it! */ suggested->SetActiveCore(core_id); priority_queue.ChangeCore(suggested_core, suggested); MESOSPHERE_KTRACE_CORE_MIGRATION(suggested->GetId(), suggested_core, core_id, 1); top_threads[core_id] = suggested; cores_needing_scheduling |= Kernel::GetScheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]); break; } /* Note this core as a candidate for migration. */ MESOSPHERE_ASSERT(num_candidates < cpu::NumCores); migration_candidates[num_candidates++] = suggested_core; suggested = priority_queue.GetSuggestedNext(core_id, suggested); } /* If suggested is nullptr, we failed to migrate a specific thread. So let's try all our candidate cores' top threads. */ if (suggested == nullptr) { for (size_t i = 0; i < num_candidates; i++) { /* Check if there's some other thread that can run on the candidate core. */ const s32 candidate_core = migration_candidates[i]; suggested = top_threads[candidate_core]; if (KThread *next_on_candidate_core = priority_queue.GetScheduledNext(candidate_core, suggested); next_on_candidate_core != nullptr) { /* The candidate core can run some other thread! We'll migrate its current top thread to us. */ top_threads[candidate_core] = next_on_candidate_core; cores_needing_scheduling |= Kernel::GetScheduler(candidate_core).UpdateHighestPriorityThread(top_threads[candidate_core]); /* Perform the migration. */ suggested->SetActiveCore(core_id); priority_queue.ChangeCore(candidate_core, suggested); MESOSPHERE_KTRACE_CORE_MIGRATION(suggested->GetId(), candidate_core, core_id, 2); top_threads[core_id] = suggested; cores_needing_scheduling |= Kernel::GetScheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]); break; } } } } idle_cores &= ~(1ul << core_id); } return cores_needing_scheduling; } void KScheduler::SwitchThread(KThread *next_thread) { KProcess * const cur_process = GetCurrentProcessPointer(); KThread * const cur_thread = GetCurrentThreadPointer(); /* We never want to schedule a null thread, so use the idle thread if we don't have a next. */ if (next_thread == nullptr) { next_thread = m_idle_thread; } if (next_thread->GetCurrentCore() != m_core_id) { next_thread->SetCurrentCore(m_core_id); } /* If we're not actually switching thread, there's nothing to do. */ if (next_thread == cur_thread) { return; } /* Next thread is now known not to be nullptr, and must not be dispatchable. */ MESOSPHERE_ASSERT(next_thread->GetDisableDispatchCount() == 1); /* Update the CPU time tracking variables. */ const s64 prev_tick = m_last_context_switch_time; const s64 cur_tick = KHardwareTimer::GetTick(); const s64 tick_diff = cur_tick - prev_tick; cur_thread->AddCpuTime(m_core_id, tick_diff); if (cur_process != nullptr) { cur_process->AddCpuTime(tick_diff); } m_last_context_switch_time = cur_tick; /* Update our previous thread. */ if (cur_process != nullptr) { /* NOTE: Combining this into AMS_LIKELY(!... && ...) triggers an internal compiler error: Segmentation fault in GCC 9.2.0. */ if (AMS_LIKELY(!cur_thread->IsTerminationRequested()) && AMS_LIKELY(cur_thread->GetActiveCore() == m_core_id)) { m_state.prev_thread = cur_thread; } else { m_state.prev_thread = nullptr; } } MESOSPHERE_KTRACE_THREAD_SWITCH(next_thread); #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) /* Ensure the single-step bit in mdscr reflects the correct single-step state for the new thread. */ /* NOTE: Per ARM docs, changing the single-step bit requires a "context synchronization event" to */ /* be sure that our new configuration takes. However, there are three types of synchronization event: */ /* Taking an exception, returning from an exception, and ISB. The single-step bit change only matters */ /* in EL0...which implies a return-from-exception has occurred since we set the bit. Thus, forcing */ /* an ISB is unnecessary, and we can modify the register safely and be confident it will affect the next */ /* userland instruction executed. */ cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(next_thread->IsHardwareSingleStep()).Store(); #endif /* Switch the current process, if we're switching processes. */ if (KProcess *next_process = next_thread->GetOwnerProcess(); next_process != cur_process) { KProcess::Switch(cur_process, next_process); } /* Set the new thread. */ SetCurrentThread(next_thread); m_current_thread = next_thread; /* Set the new Thread Local region. */ const auto tls_address = GetInteger(next_thread->GetThreadLocalRegionAddress()); cpu::SwitchThreadLocalRegion(tls_address); /* Update the thread's cpu time differential in TLS, if relevant. */ if (tls_address != 0) { static_cast<ams::svc::ThreadLocalRegion *>(next_thread->GetThreadLocalRegionHeapAddress())->thread_cpu_time = next_thread->GetCpuTime() - cur_tick; } } void KScheduler::ClearPreviousThread(KThread *thread) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); for (size_t i = 0; i < cpu::NumCores; ++i) { /* Get an atomic reference to the core scheduler's previous thread. */ const util::AtomicRef<KThread *> prev_thread(Kernel::GetScheduler(static_cast<s32>(i)).m_state.prev_thread); /* Atomically clear the previous thread if it's our target. */ KThread *compare = thread; prev_thread.CompareExchangeStrong(compare, nullptr); } } void KScheduler::OnThreadStateChanged(KThread *thread, KThread::ThreadState old_state) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); /* Check if the state has changed, because if it hasn't there's nothing to do. */ const KThread::ThreadState cur_state = thread->GetRawState(); if (cur_state == old_state) { return; } /* Update the priority queues. */ if (old_state == KThread::ThreadState_Runnable) { /* If we were previously runnable, then we're not runnable now, and we should remove. */ GetPriorityQueue().Remove(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(); } else if (cur_state == KThread::ThreadState_Runnable) { /* If we're now runnable, then we weren't previously, and we should add. */ GetPriorityQueue().PushBack(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(); } } void KScheduler::OnThreadPriorityChanged(KThread *thread, s32 old_priority) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); /* If the thread is runnable, we want to change its priority in the queue. */ if (thread->GetRawState() == KThread::ThreadState_Runnable) { GetPriorityQueue().ChangePriority(old_priority, thread == GetCurrentThreadPointer(), thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(); } } void KScheduler::OnThreadAffinityMaskChanged(KThread *thread, const KAffinityMask &old_affinity, s32 old_core) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); /* If the thread is runnable, we want to change its affinity in the queue. */ if (thread->GetRawState() == KThread::ThreadState_Runnable) { GetPriorityQueue().ChangeAffinityMask(old_core, old_affinity, thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(); } } void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); /* Get a reference to the priority queue. */ auto &priority_queue = GetPriorityQueue(); /* Rotate the front of the queue to the end. */ KThread *top_thread = priority_queue.GetScheduledFront(core_id, priority); KThread *next_thread = nullptr; if (top_thread != nullptr) { next_thread = priority_queue.MoveToScheduledBack(top_thread); if (next_thread != top_thread) { IncrementScheduledCount(top_thread); IncrementScheduledCount(next_thread); } } /* While we have a suggested thread, try to migrate it! */ { KThread *suggested = priority_queue.GetSuggestedFront(core_id, priority); while (suggested != nullptr) { /* Check if the suggested thread is the top thread on its core. */ const s32 suggested_core = suggested->GetActiveCore(); if (KThread *top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { /* If the next thread is a new thread that has been waiting longer than our suggestion, we prefer it to our suggestion. */ if (top_thread != next_thread && next_thread != nullptr && next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick()) { suggested = nullptr; break; } /* If we're allowed to do a migration, do one. */ /* NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the suggestion to the front of the queue. */ if (top_on_suggested_core == nullptr || top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { suggested->SetActiveCore(core_id); priority_queue.ChangeCore(suggested_core, suggested, true); IncrementScheduledCount(suggested); break; } } /* Get the next suggestion. */ suggested = priority_queue.GetSamePriorityNext(core_id, suggested); } } /* Now that we might have migrated a thread with the same priority, check if we can do better. */ { KThread *best_thread = priority_queue.GetScheduledFront(core_id); if (best_thread == GetCurrentThreadPointer()) { best_thread = priority_queue.GetScheduledNext(core_id, best_thread); } /* If the best thread we can choose has a priority the same or worse than ours, try to migrate a higher priority thread. */ if (best_thread != nullptr && best_thread->GetPriority() >= priority) { KThread *suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { /* If the suggestion's priority is the same as ours, don't bother. */ if (suggested->GetPriority() >= best_thread->GetPriority()) { break; } /* Check if the suggested thread is the top thread on its core. */ const s32 suggested_core = suggested->GetActiveCore(); if (KThread *top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { /* If we're allowed to do a migration, do one. */ /* NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the suggestion to the front of the queue. */ if (top_on_suggested_core == nullptr || top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { suggested->SetActiveCore(core_id); priority_queue.ChangeCore(suggested_core, suggested, true); IncrementScheduledCount(suggested); break; } } /* Get the next suggestion. */ suggested = priority_queue.GetSuggestedNext(core_id, suggested); } } } /* After a rotation, we need a scheduler update. */ SetSchedulerUpdateNeeded(); } void KScheduler::YieldWithoutCoreMigration() { /* Validate preconditions. */ MESOSPHERE_ASSERT(CanSchedule()); MESOSPHERE_ASSERT(GetCurrentProcessPointer() != nullptr); /* Get the current thread and process. */ KThread &cur_thread = GetCurrentThread(); KProcess &cur_process = GetCurrentProcess(); /* If the thread's yield count matches, there's nothing for us to do. */ if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { return; } /* Get a reference to the priority queue. */ auto &priority_queue = GetPriorityQueue(); /* Perform the yield. */ { KScopedSchedulerLock sl; const auto cur_state = cur_thread.GetRawState(); if (cur_state == KThread::ThreadState_Runnable) { /* Put the current thread at the back of the queue. */ KThread *next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); IncrementScheduledCount(std::addressof(cur_thread)); /* If the next thread is different, we have an update to perform. */ if (next_thread != std::addressof(cur_thread)) { SetSchedulerUpdateNeeded(); } else { /* Otherwise, set the thread's yield count so that we won't waste work until the process is scheduled again. */ cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); } } } } void KScheduler::YieldWithCoreMigration() { /* Validate preconditions. */ MESOSPHERE_ASSERT(CanSchedule()); MESOSPHERE_ASSERT(GetCurrentProcessPointer() != nullptr); /* Get the current thread and process. */ KThread &cur_thread = GetCurrentThread(); KProcess &cur_process = GetCurrentProcess(); /* If the thread's yield count matches, there's nothing for us to do. */ if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { return; } /* Get a reference to the priority queue. */ auto &priority_queue = GetPriorityQueue(); /* Perform the yield. */ { KScopedSchedulerLock sl; const auto cur_state = cur_thread.GetRawState(); if (cur_state == KThread::ThreadState_Runnable) { /* Get the current active core. */ const s32 core_id = cur_thread.GetActiveCore(); /* Put the current thread at the back of the queue. */ KThread *next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); IncrementScheduledCount(std::addressof(cur_thread)); /* While we have a suggested thread, try to migrate it! */ bool recheck = false; KThread *suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { /* Check if the suggested thread is the thread running on its core. */ const s32 suggested_core = suggested->GetActiveCore(); if (KThread *running_on_suggested_core = (suggested_core >= 0) ? Kernel::GetScheduler(suggested_core).m_state.highest_priority_thread : nullptr; running_on_suggested_core != suggested) { /* If the current thread's priority is higher than our suggestion's we prefer the next thread to the suggestion. */ /* We also prefer the next thread when the current thread's priority is equal to the suggestions, but the next thread has been waiting longer. */ if ((suggested->GetPriority() > cur_thread.GetPriority()) || (suggested->GetPriority() == cur_thread.GetPriority() && next_thread != std::addressof(cur_thread) && next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick())) { suggested = nullptr; break; } /* If we're allowed to do a migration, do one. */ /* NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the suggestion to the front of the queue. */ if (running_on_suggested_core == nullptr || running_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { suggested->SetActiveCore(core_id); priority_queue.ChangeCore(suggested_core, suggested, true); MESOSPHERE_KTRACE_CORE_MIGRATION(suggested->GetId(), suggested_core, core_id, 3); IncrementScheduledCount(suggested); break; } else { /* We couldn't perform a migration, but we should check again on a future yield. */ recheck = true; } } /* Get the next suggestion. */ suggested = priority_queue.GetSuggestedNext(core_id, suggested); } /* If we still have a suggestion or the next thread is different, we have an update to perform. */ if (suggested != nullptr || next_thread != std::addressof(cur_thread)) { SetSchedulerUpdateNeeded(); } else if (!recheck) { /* Otherwise if we don't need to re-check, set the thread's yield count so that we won't waste work until the process is scheduled again. */ cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); } } } } void KScheduler::YieldToAnyThread() { /* Validate preconditions. */ MESOSPHERE_ASSERT(CanSchedule()); MESOSPHERE_ASSERT(GetCurrentProcessPointer() != nullptr); /* Get the current thread and process. */ KThread &cur_thread = GetCurrentThread(); KProcess &cur_process = GetCurrentProcess(); /* If the thread's yield count matches, there's nothing for us to do. */ if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { return; } /* Get a reference to the priority queue. */ auto &priority_queue = GetPriorityQueue(); /* Perform the yield. */ { KScopedSchedulerLock sl; const auto cur_state = cur_thread.GetRawState(); if (cur_state == KThread::ThreadState_Runnable) { /* Get the current active core. */ const s32 core_id = cur_thread.GetActiveCore(); /* Migrate the current thread to core -1. */ cur_thread.SetActiveCore(-1); priority_queue.ChangeCore(core_id, std::addressof(cur_thread)); MESOSPHERE_KTRACE_CORE_MIGRATION(cur_thread.GetId(), core_id, -1, 4); IncrementScheduledCount(std::addressof(cur_thread)); /* If there's nothing scheduled, we can try to perform a migration. */ if (priority_queue.GetScheduledFront(core_id) == nullptr) { /* While we have a suggested thread, try to migrate it! */ KThread *suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { /* Check if the suggested thread is the top thread on its core. */ const s32 suggested_core = suggested->GetActiveCore(); if (KThread *top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { /* If we're allowed to do a migration, do one. */ if (top_on_suggested_core == nullptr || top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { suggested->SetActiveCore(core_id); priority_queue.ChangeCore(suggested_core, suggested); MESOSPHERE_KTRACE_CORE_MIGRATION(suggested->GetId(), suggested_core, core_id, 5); IncrementScheduledCount(suggested); } /* Regardless of whether we migrated, we had a candidate, so we're done. */ break; } /* Get the next suggestion. */ suggested = priority_queue.GetSuggestedNext(core_id, suggested); } /* If the suggestion is different from the current thread, we need to perform an update. */ if (suggested != std::addressof(cur_thread)) { SetSchedulerUpdateNeeded(); } else { /* Otherwise, set the thread's yield count so that we won't waste work until the process is scheduled again. */ cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount()); } } else { /* Otherwise, we have an update to perform. */ SetSchedulerUpdateNeeded(); } } } } } #pragma GCC pop_options ================================================ FILE: libraries/libmesosphere/source/kern_k_scoped_disable_dispatch.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { KScopedDisableDispatch::~KScopedDisableDispatch() { if (GetCurrentThread().GetDisableDispatchCount() <= 1) { Kernel::GetScheduler().RescheduleCurrentCore(); } else { GetCurrentThread().EnableDispatch(); } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_server_port.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KServerPort::Initialize(KPort *parent) { /* Set member variables. */ m_parent = parent; } bool KServerPort::IsLight() const { return this->GetParent()->IsLight(); } void KServerPort::CleanupSessions() { /* Ensure our preconditions are met. */ if (this->IsLight()) { MESOSPHERE_ASSERT(m_session_list.empty()); } else { MESOSPHERE_ASSERT(m_light_session_list.empty()); } /* Cleanup the session list. */ while (true) { /* Get the last session in the list. */ KServerSession *session = nullptr; { KScopedSchedulerLock sl; if (!m_session_list.empty()) { session = std::addressof(m_session_list.front()); m_session_list.pop_front(); } } /* Close the session. */ if (session != nullptr) { session->Close(); } else { break; } } /* Cleanup the light session list. */ while (true) { /* Get the last session in the list. */ KLightServerSession *session = nullptr; { KScopedSchedulerLock sl; if (!m_light_session_list.empty()) { session = std::addressof(m_light_session_list.front()); m_light_session_list.pop_front(); } } /* Close the session. */ if (session != nullptr) { session->Close(); } else { break; } } } void KServerPort::Destroy() { /* Note with our parent that we're closed. */ m_parent->OnServerClosed(); /* Perform necessary cleanup of our session lists. */ this->CleanupSessions(); /* Close our reference to our parent. */ m_parent->Close(); } bool KServerPort::IsSignaled() const { MESOSPHERE_ASSERT_THIS(); if (this->IsLight()) { return !m_light_session_list.empty(); } else { return !m_session_list.empty(); } } void KServerPort::EnqueueSession(KServerSession *session) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(!this->IsLight()); KScopedSchedulerLock sl; /* Add the session to our queue. */ m_session_list.push_back(*session); if (m_session_list.size() == 1) { this->NotifyAvailable(); } } void KServerPort::EnqueueSession(KLightServerSession *session) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this->IsLight()); KScopedSchedulerLock sl; /* Add the session to our queue. */ m_light_session_list.push_back(*session); if (m_light_session_list.size() == 1) { this->NotifyAvailable(); } } KServerSession *KServerPort::AcceptSession() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(!this->IsLight()); KScopedSchedulerLock sl; /* Return the first session in the list. */ if (m_session_list.empty()) { return nullptr; } KServerSession *session = std::addressof(m_session_list.front()); m_session_list.pop_front(); return session; } KLightServerSession *KServerPort::AcceptLightSession() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this->IsLight()); KScopedSchedulerLock sl; /* Return the first session in the list. */ if (m_light_session_list.empty()) { return nullptr; } KLightServerSession *session = std::addressof(m_light_session_list.front()); m_light_session_list.pop_front(); return session; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_server_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #pragma GCC push_options #pragma GCC optimize ("-O3") namespace ams::kern { namespace ipc { using MessageBuffer = ams::svc::ipc::MessageBuffer; } namespace { constexpr inline size_t PointerTransferBufferAlignment = 0x10; class ThreadQueueImplForKServerSessionRequest final : public KThreadQueue { /* ... */ }; class ReceiveList { private: u32 m_data[ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountMax * ipc::MessageBuffer::ReceiveListEntry::GetDataSize() / sizeof(u32)]; s32 m_recv_list_count; uintptr_t m_msg_buffer_end; uintptr_t m_msg_buffer_space_end; public: static constexpr ALWAYS_INLINE int GetEntryCount(const ipc::MessageBuffer::MessageHeader &header) { const auto count = header.GetReceiveListCount(); switch (count) { case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_None: return 0; case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer: return 0; case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToSingleBuffer: return 1; default: return count - ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset; } } public: ReceiveList(const u32 *dst_msg, uintptr_t dst_address, const KProcessPageTable &dst_page_table, const ipc::MessageBuffer::MessageHeader &dst_header, const ipc::MessageBuffer::SpecialHeader &dst_special_header, size_t msg_size, size_t out_offset, s32 dst_recv_list_idx, bool is_tls) { m_recv_list_count = dst_header.GetReceiveListCount(); m_msg_buffer_end = dst_address + sizeof(u32) * out_offset; m_msg_buffer_space_end = dst_address + msg_size; /* NOTE: Nintendo calculates the receive list index here using the special header. */ /* We pre-calculate it in the caller, and pass it as a parameter. */ MESOSPHERE_UNUSED(dst_special_header); const u32 *recv_list = dst_msg + dst_recv_list_idx; const auto entry_count = GetEntryCount(dst_header); if (is_tls) { __builtin_memcpy(m_data, recv_list, entry_count * ipc::MessageBuffer::ReceiveListEntry::GetDataSize()); } else { uintptr_t page_addr = util::AlignDown(dst_address, PageSize); uintptr_t cur_addr = dst_address + dst_recv_list_idx * sizeof(u32); for (size_t i = 0; i < entry_count * ipc::MessageBuffer::ReceiveListEntry::GetDataSize() / sizeof(u32); ++i) { if (page_addr != util::AlignDown(cur_addr, PageSize)) { KPhysicalAddress phys_addr; dst_page_table.GetPhysicalAddress(std::addressof(phys_addr), KProcessAddress(cur_addr)); recv_list = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(phys_addr)); page_addr = util::AlignDown(cur_addr, PageSize); } m_data[i] = *(recv_list++); cur_addr += sizeof(u32); } } } constexpr ALWAYS_INLINE bool IsIndex() const { return m_recv_list_count > ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset; } constexpr ALWAYS_INLINE bool IsToMessageBuffer() const { return m_recv_list_count == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer; } void GetBuffer(uintptr_t &out, size_t size, int &key) const { switch (m_recv_list_count) { case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_None: { out = 0; } break; case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer: { const uintptr_t buf = util::AlignUp(m_msg_buffer_end + key, PointerTransferBufferAlignment); if ((buf < buf + size) && (buf + size <= m_msg_buffer_space_end)) { out = buf; key = buf + size - m_msg_buffer_end; } else { out = 0; } } break; case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToSingleBuffer: { const ipc::MessageBuffer::ReceiveListEntry entry(m_data[0], m_data[1]); const uintptr_t buf = util::AlignUp(entry.GetAddress() + key, PointerTransferBufferAlignment); const uintptr_t entry_addr = entry.GetAddress(); const size_t entry_size = entry.GetSize(); if ((buf < buf + size) && (entry_addr < entry_addr + entry_size) && (buf + size <= entry_addr + entry_size)) { out = buf; key = buf + size - entry_addr; } else { out = 0; } } break; default: { if (key < m_recv_list_count - ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset) { const ipc::MessageBuffer::ReceiveListEntry entry(m_data[2 * key + 0], m_data[2 * key + 1]); const uintptr_t entry_addr = entry.GetAddress(); const size_t entry_size = entry.GetSize(); if ((entry_addr < entry_addr + entry_size) && (entry_size >= size)) { out = entry_addr; } } else { out = 0; } } break; } } }; template<bool MoveHandleAllowed> ALWAYS_INLINE Result ProcessMessageSpecialData(int &offset, KProcess &dst_process, KProcess &src_process, KThread &src_thread, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, const ipc::MessageBuffer::SpecialHeader &src_special_header) { /* Copy the special header to the destination. */ offset = dst_msg.Set(src_special_header); /* Copy the process ID. */ if (src_special_header.GetHasProcessId()) { /* NOTE: Atmosphere extends the official kernel here to enable the mitm api. */ /* If building the kernel without this support, just set the following to false. */ constexpr bool EnableProcessIdPassthroughForAtmosphere = true; if constexpr (EnableProcessIdPassthroughForAtmosphere) { constexpr u64 PassthroughProcessIdMask = UINT64_C(0xFFFF000000000000); constexpr u64 PassthroughProcessIdValue = UINT64_C(0xFFFE000000000000); static_assert((PassthroughProcessIdMask & PassthroughProcessIdValue) == PassthroughProcessIdValue); const u64 src_process_id_value = src_msg.GetProcessId(offset); const bool is_passthrough = (src_process_id_value & PassthroughProcessIdMask) == PassthroughProcessIdValue; offset = dst_msg.SetProcessId(offset, is_passthrough ? (src_process_id_value & ~PassthroughProcessIdMask) : src_process.GetId()); } else { offset = dst_msg.SetProcessId(offset, src_process.GetId()); } } /* Prepare to process handles. */ auto &dst_handle_table = dst_process.GetHandleTable(); auto &src_handle_table = src_process.GetHandleTable(); Result result = ResultSuccess(); /* Process copy handles. */ for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) { /* Get the handles. */ const ams::svc::Handle src_handle = src_msg.GetHandle(offset); ams::svc::Handle dst_handle = ams::svc::InvalidHandle; /* If we're in a success state, try to move the handle to the new table. */ if (R_SUCCEEDED(result) && src_handle != ams::svc::InvalidHandle) { KScopedAutoObject obj = src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread)); if (obj.IsNotNull()) { Result add_result = dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe()); if (R_FAILED(add_result)) { result = add_result; dst_handle = ams::svc::InvalidHandle; } } else { result = svc::ResultInvalidHandle(); } } /* Set the handle. */ offset = dst_msg.SetHandle(offset, dst_handle); } /* Process move handles. */ if constexpr (MoveHandleAllowed) { for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) { /* Get the handles. */ const ams::svc::Handle src_handle = src_msg.GetHandle(offset); ams::svc::Handle dst_handle = ams::svc::InvalidHandle; /* Whether or not we've succeeded, we need to remove the handles from the source table. */ if (src_handle != ams::svc::InvalidHandle) { if (R_SUCCEEDED(result)) { KScopedAutoObject obj = src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle); if (obj.IsNotNull()) { Result add_result = dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe()); src_handle_table.Remove(src_handle); if (R_FAILED(add_result)) { result = add_result; dst_handle = ams::svc::InvalidHandle; } } else { result = svc::ResultInvalidHandle(); } } else { src_handle_table.Remove(src_handle); } } /* Set the handle. */ offset = dst_msg.SetHandle(offset, dst_handle); } } R_RETURN(result); } ALWAYS_INLINE Result ProcessReceiveMessagePointerDescriptors(int &offset, int &pointer_key, KProcessPageTable &dst_page_table, KProcessPageTable &src_page_table, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, const ReceiveList &dst_recv_list, bool dst_user) { /* Get the offset at the start of processing. */ const int cur_offset = offset; /* Get the pointer desc. */ ipc::MessageBuffer::PointerDescriptor src_desc(src_msg, cur_offset); offset += ipc::MessageBuffer::PointerDescriptor::GetDataSize() / sizeof(u32); /* Extract address/size. */ const uintptr_t src_pointer = src_desc.GetAddress(); const size_t recv_size = src_desc.GetSize(); uintptr_t recv_pointer = 0; /* Process the buffer, if it has a size. */ if (recv_size > 0) { /* If using indexing, set index. */ if (dst_recv_list.IsIndex()) { pointer_key = src_desc.GetIndex(); } /* Get the buffer. */ dst_recv_list.GetBuffer(recv_pointer, recv_size, pointer_key); R_UNLESS(recv_pointer != 0, svc::ResultOutOfResource()); /* Perform the pointer data copy. */ if (dst_user) { R_TRY(src_page_table.CopyMemoryFromHeapToHeapWithoutCheckDestination(dst_page_table, recv_pointer, recv_size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite), KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked, src_pointer, KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped, KMemoryPermission_UserRead, KMemoryAttribute_Uncached, KMemoryAttribute_None)); } else { R_TRY(src_page_table.CopyMemoryFromLinearToUser(recv_pointer, recv_size, src_pointer, KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped, KMemoryPermission_UserRead, KMemoryAttribute_Uncached, KMemoryAttribute_None)); } } /* Set the output descriptor. */ dst_msg.Set(cur_offset, ipc::MessageBuffer::PointerDescriptor(reinterpret_cast<void *>(recv_pointer), recv_size, src_desc.GetIndex())); R_SUCCEED(); } constexpr ALWAYS_INLINE Result GetMapAliasMemoryState(KMemoryState &out, ipc::MessageBuffer::MapAliasDescriptor::Attribute attr) { switch (attr) { case ipc::MessageBuffer::MapAliasDescriptor::Attribute_Ipc: out = KMemoryState_Ipc; break; case ipc::MessageBuffer::MapAliasDescriptor::Attribute_NonSecureIpc: out = KMemoryState_NonSecureIpc; break; case ipc::MessageBuffer::MapAliasDescriptor::Attribute_NonDeviceIpc: out = KMemoryState_NonDeviceIpc; break; default: R_THROW(svc::ResultInvalidCombination()); } R_SUCCEED(); } constexpr ALWAYS_INLINE Result GetMapAliasTestStateAndAttributeMask(u32 &out_state, u32 &out_attr_mask, KMemoryState state) { switch (state) { case KMemoryState_Ipc: out_state = KMemoryState_FlagCanUseIpc; out_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked; break; case KMemoryState_NonSecureIpc: out_state = KMemoryState_FlagCanUseNonSecureIpc; out_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_Locked; break; case KMemoryState_NonDeviceIpc: out_state = KMemoryState_FlagCanUseNonDeviceIpc; out_attr_mask = KMemoryAttribute_Uncached | KMemoryAttribute_Locked; break; default: R_THROW(svc::ResultInvalidCombination()); } R_SUCCEED(); } ALWAYS_INLINE void CleanupSpecialData(KProcess &dst_process, u32 *dst_msg_ptr, size_t dst_buffer_size) { /* Parse the message. */ const ipc::MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); const ipc::MessageBuffer::MessageHeader dst_header(dst_msg); const ipc::MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header); /* Check that the size is big enough. */ if (ipc::MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) { return; } /* Set the special header. */ int offset = dst_msg.Set(dst_special_header); /* Clear the process id, if needed. */ if (dst_special_header.GetHasProcessId()) { offset = dst_msg.SetProcessId(offset, 0); } /* Clear handles, as relevant. */ auto &dst_handle_table = dst_process.GetHandleTable(); for (auto i = 0; i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount()); ++i) { const ams::svc::Handle handle = dst_msg.GetHandle(offset); if (handle != ams::svc::InvalidHandle) { dst_handle_table.Remove(handle); } offset = dst_msg.SetHandle(offset, ams::svc::InvalidHandle); } } ALWAYS_INLINE Result CleanupServerHandles(uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr) { /* Server is assumed to be current thread. */ const KThread &thread = GetCurrentThread(); /* Get the linear message pointer. */ u32 *msg_ptr; if (message) { msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(message_paddr)); } else { msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(thread.GetThreadLocalRegionHeapAddress())->message_buffer; buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer); message = GetInteger(thread.GetThreadLocalRegionAddress()); } /* Parse the message. */ const ipc::MessageBuffer msg(msg_ptr, buffer_size); const ipc::MessageBuffer::MessageHeader header(msg); const ipc::MessageBuffer::SpecialHeader special_header(msg, header); /* Check that the size is big enough. */ R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(header, special_header) <= buffer_size, svc::ResultInvalidCombination()); /* If there's a special header, there may be move handles we need to close. */ if (header.GetHasSpecialHeader()) { /* Determine the offset to the start of handles. */ auto offset = msg.GetSpecialDataIndex(header, special_header); if (special_header.GetHasProcessId()) { offset += sizeof(u64) / sizeof(u32); } if (auto copy_count = special_header.GetCopyHandleCount(); copy_count > 0) { offset += (sizeof(ams::svc::Handle) * copy_count) / sizeof(u32); } /* Get the handle table. */ auto &handle_table = thread.GetOwnerProcess()->GetHandleTable(); /* Close the handles. */ for (auto i = 0; i < special_header.GetMoveHandleCount(); ++i) { handle_table.Remove(msg.GetHandle(offset)); offset += sizeof(ams::svc::Handle) / sizeof(u32); } } R_SUCCEED(); } ALWAYS_INLINE Result CleanupServerMap(KSessionRequest *request, KProcess *server_process) { /* If there's no server process, there's nothing to clean up. */ R_SUCCEED_IF(server_process == nullptr); /* Get the page table. */ auto &server_page_table = server_process->GetPageTable(); /* Cleanup Send mappings. */ for (size_t i = 0; i < request->GetSendCount(); ++i) { R_TRY(server_page_table.CleanupForIpcServer(request->GetSendServerAddress(i), request->GetSendSize(i), request->GetSendMemoryState(i))); } /* Cleanup Receive mappings. */ for (size_t i = 0; i < request->GetReceiveCount(); ++i) { R_TRY(server_page_table.CleanupForIpcServer(request->GetReceiveServerAddress(i), request->GetReceiveSize(i), request->GetReceiveMemoryState(i))); } /* Cleanup Exchange mappings. */ for (size_t i = 0; i < request->GetExchangeCount(); ++i) { R_TRY(server_page_table.CleanupForIpcServer(request->GetExchangeServerAddress(i), request->GetExchangeSize(i), request->GetExchangeMemoryState(i))); } R_SUCCEED(); } ALWAYS_INLINE Result CleanupClientMap(KSessionRequest *request, KProcessPageTable *client_page_table) { /* If there's no client page table, there's nothing to clean up. */ R_SUCCEED_IF(client_page_table == nullptr); /* Cleanup Send mappings. */ for (size_t i = 0; i < request->GetSendCount(); ++i) { R_TRY(client_page_table->CleanupForIpcClient(request->GetSendClientAddress(i), request->GetSendSize(i), request->GetSendMemoryState(i))); } /* Cleanup Receive mappings. */ for (size_t i = 0; i < request->GetReceiveCount(); ++i) { R_TRY(client_page_table->CleanupForIpcClient(request->GetReceiveClientAddress(i), request->GetReceiveSize(i), request->GetReceiveMemoryState(i))); } /* Cleanup Exchange mappings. */ for (size_t i = 0; i < request->GetExchangeCount(); ++i) { R_TRY(client_page_table->CleanupForIpcClient(request->GetExchangeClientAddress(i), request->GetExchangeSize(i), request->GetExchangeMemoryState(i))); } R_SUCCEED(); } ALWAYS_INLINE Result CleanupMap(KSessionRequest *request, KProcess *server_process, KProcessPageTable *client_page_table) { /* Cleanup the server map. */ R_TRY(CleanupServerMap(request, server_process)); /* Cleanup the client map. */ R_TRY(CleanupClientMap(request, client_page_table)); R_SUCCEED(); } ALWAYS_INLINE Result ProcessReceiveMessageMapAliasDescriptors(int &offset, KProcessPageTable &dst_page_table, KProcessPageTable &src_page_table, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, KSessionRequest *request, KMemoryPermission perm, bool send) { /* Get the offset at the start of processing. */ const int cur_offset = offset; /* Get the map alias descriptor. */ ipc::MessageBuffer::MapAliasDescriptor src_desc(src_msg, cur_offset); offset += ipc::MessageBuffer::MapAliasDescriptor::GetDataSize() / sizeof(u32); /* Extract address/size. */ const KProcessAddress src_address = src_desc.GetAddress(); const size_t size = src_desc.GetSize(); KProcessAddress dst_address = 0; /* Determine the result memory state. */ KMemoryState dst_state; R_TRY(GetMapAliasMemoryState(dst_state, src_desc.GetAttribute())); /* Process the buffer, if it has a size. */ if (size > 0) { /* Set up the source pages for ipc. */ R_TRY(dst_page_table.SetupForIpc(std::addressof(dst_address), size, src_address, src_page_table, perm, dst_state, send)); /* Ensure that we clean up on failure. */ ON_RESULT_FAILURE { static_cast<void>(dst_page_table.CleanupForIpcServer(dst_address, size, dst_state)); static_cast<void>(src_page_table.CleanupForIpcClient(src_address, size, dst_state)); }; /* Push the appropriate mapping. */ if (perm == KMemoryPermission_UserRead) { R_TRY(request->PushSend(src_address, dst_address, size, dst_state)); } else if (send) { R_TRY(request->PushExchange(src_address, dst_address, size, dst_state)); } else { R_TRY(request->PushReceive(src_address, dst_address, size, dst_state)); } } /* Set the output descriptor. */ dst_msg.Set(cur_offset, ipc::MessageBuffer::MapAliasDescriptor(GetVoidPointer(dst_address), size, src_desc.GetAttribute())); R_SUCCEED(); } ALWAYS_INLINE Result ReceiveMessage(bool &recv_list_broken, uintptr_t dst_message_buffer, size_t dst_buffer_size, KPhysicalAddress dst_message_paddr, KThread &src_thread, uintptr_t src_message_buffer, size_t src_buffer_size, KServerSession *session, KSessionRequest *request) { /* Prepare variables for receive. */ const KThread &dst_thread = GetCurrentThread(); KProcess &dst_process = *(dst_thread.GetOwnerProcess()); KProcess &src_process = *(src_thread.GetOwnerProcess()); auto &dst_page_table = dst_process.GetPageTable(); auto &src_page_table = src_process.GetPageTable(); /* NOTE: Session is used only for debugging, and so may go unused. */ MESOSPHERE_UNUSED(session); /* The receive list is initially not broken. */ recv_list_broken = false; /* Set the server process for the request. */ request->SetServerProcess(std::addressof(dst_process)); /* Determine the message buffers. */ u32 *dst_msg_ptr, *src_msg_ptr; bool dst_user, src_user; if (dst_message_buffer) { dst_msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(dst_message_paddr)); dst_user = true; } else { dst_msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(dst_thread.GetThreadLocalRegionHeapAddress())->message_buffer; dst_buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer); dst_message_buffer = GetInteger(dst_thread.GetThreadLocalRegionAddress()); dst_user = false; } if (src_message_buffer) { /* NOTE: Nintendo does not check the result of this GetPhysicalAddress call. */ KPhysicalAddress src_message_paddr; src_page_table.GetPhysicalAddress(std::addressof(src_message_paddr), src_message_buffer); src_msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(src_message_paddr)); src_user = true; } else { src_msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(src_thread.GetThreadLocalRegionHeapAddress())->message_buffer; src_buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer); src_message_buffer = GetInteger(src_thread.GetThreadLocalRegionAddress()); src_user = false; } /* Parse the headers. */ const ipc::MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); const ipc::MessageBuffer src_msg(src_msg_ptr, src_buffer_size); const ipc::MessageBuffer::MessageHeader dst_header(dst_msg); const ipc::MessageBuffer::MessageHeader src_header(src_msg); const ipc::MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header); const ipc::MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); /* Get the end of the source message. */ const size_t src_end_offset = ipc::MessageBuffer::GetRawDataIndex(src_header, src_special_header) + src_header.GetRawCount(); /* Ensure that the headers fit. */ R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) <= dst_buffer_size, svc::ResultInvalidCombination()); R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(src_header, src_special_header) <= src_buffer_size, svc::ResultInvalidCombination()); /* Ensure the receive list offset is after the end of raw data. */ if (dst_header.GetReceiveListOffset()) { R_UNLESS(dst_header.GetReceiveListOffset() >= ipc::MessageBuffer::GetRawDataIndex(dst_header, dst_special_header) + dst_header.GetRawCount(), svc::ResultInvalidCombination()); } /* Ensure that the destination buffer is big enough to receive the source. */ R_UNLESS(dst_buffer_size >= src_end_offset * sizeof(u32), svc::ResultMessageTooLarge()); /* Get the receive list. */ const s32 dst_recv_list_idx = ipc::MessageBuffer::GetReceiveListIndex(dst_header, dst_special_header); ReceiveList dst_recv_list(dst_msg_ptr, dst_message_buffer, dst_page_table, dst_header, dst_special_header, dst_buffer_size, src_end_offset, dst_recv_list_idx, !dst_user); /* Ensure that the source special header isn't invalid. */ const bool src_has_special_header = src_header.GetHasSpecialHeader(); if (src_has_special_header) { /* Sending move handles from client -> server is not allowed. */ R_UNLESS(src_special_header.GetMoveHandleCount() == 0, svc::ResultInvalidCombination()); } /* Prepare for further processing. */ int pointer_key = 0; int offset = dst_msg.Set(src_header); /* Set up a guard to make sure that we end up in a clean state on error. */ ON_RESULT_FAILURE { /* Cleanup mappings. */ static_cast<void>(CleanupMap(request, std::addressof(dst_process), std::addressof(src_page_table))); /* Cleanup special data. */ if (src_header.GetHasSpecialHeader()) { CleanupSpecialData(dst_process, dst_msg_ptr, dst_buffer_size); } /* Cleanup the header if the receive list isn't broken. */ if (!recv_list_broken) { dst_msg.Set(dst_header); if (dst_header.GetHasSpecialHeader()) { dst_msg.Set(dst_special_header); } } }; /* Process any special data. */ if (src_header.GetHasSpecialHeader()) { /* After we process, make sure we track whether the receive list is broken. */ ON_SCOPE_EXIT { if (offset > dst_recv_list_idx) { recv_list_broken = true; } }; /* Process special data. */ R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, dst_msg, src_msg, src_special_header)); } /* Process any pointer buffers. */ for (auto i = 0; i < src_header.GetPointerCount(); ++i) { /* After we process, make sure we track whether the receive list is broken. */ ON_SCOPE_EXIT { if (offset > dst_recv_list_idx) { recv_list_broken = true; } }; R_TRY(ProcessReceiveMessagePointerDescriptors(offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, dst_user && dst_header.GetReceiveListCount() == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer)); } /* Process any map alias buffers. */ for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { /* After we process, make sure we track whether the receive list is broken. */ ON_SCOPE_EXIT { if (offset > dst_recv_list_idx) { recv_list_broken = true; } }; /* We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. */ const KMemoryPermission perm = (i >= src_header.GetSendCount()) ? KMemoryPermission_UserReadWrite : KMemoryPermission_UserRead; /* Buffer is send if it is send or exch. */ const bool send = (i < src_header.GetSendCount()) || (i >= src_header.GetSendCount() + src_header.GetReceiveCount()); R_TRY(ProcessReceiveMessageMapAliasDescriptors(offset, dst_page_table, src_page_table, dst_msg, src_msg, request, perm, send)); } /* Process any raw data. */ if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { /* After we process, make sure we track whether the receive list is broken. */ ON_SCOPE_EXIT { if (offset + raw_count > dst_recv_list_idx) { recv_list_broken = true; } }; /* Get the offset and size. */ const size_t offset_words = offset * sizeof(u32); const size_t raw_size = raw_count * sizeof(u32); /* Fast case is TLS -> TLS, do raw memcpy if we can. */ if (!dst_user && !src_user) { std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); } else if (dst_user) { /* Determine how much fast size we can copy. */ const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize); const size_t fast_size = max_fast_size - offset_words; /* Determine source state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */ const auto src_state = src_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped; /* Determine the source permission. User buffer should be unmapped + read, TLS should be user readable. */ const KMemoryPermission src_perm = static_cast<KMemoryPermission>(src_user ? (KMemoryPermission_NotMapped | KMemoryPermission_KernelRead) : KMemoryPermission_UserRead); /* Perform the fast part of the copy. */ R_TRY(src_page_table.CopyMemoryFromLinearToKernel(reinterpret_cast<uintptr_t>(dst_msg_ptr) + offset_words, fast_size, src_message_buffer + offset_words, src_state, src_state, src_perm, KMemoryAttribute_Uncached, KMemoryAttribute_None)); /* If the fast part of the copy didn't get everything, perform the slow part of the copy. */ if (fast_size < raw_size) { R_TRY(src_page_table.CopyMemoryFromHeapToHeap(dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite), KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked, src_message_buffer + max_fast_size, src_state, src_state, src_perm, KMemoryAttribute_Uncached, KMemoryAttribute_None)); } } else /* if (src_user) */ { /* The source is a user buffer, so it should be unmapped + readable. */ constexpr KMemoryPermission SourcePermission = static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelRead); /* Copy the memory. */ R_TRY(src_page_table.CopyMemoryFromLinearToUser(dst_message_buffer + offset_words, raw_size, src_message_buffer + offset_words, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, SourcePermission, KMemoryAttribute_Uncached, KMemoryAttribute_None)); } } /* We succeeded! */ R_SUCCEED(); } ALWAYS_INLINE Result ProcessSendMessageReceiveMapping(KProcessPageTable &dst_page_table, KProcessAddress client_address, KProcessAddress server_address, size_t size, KMemoryState src_state) { /* If the size is zero, there's nothing to process. */ R_SUCCEED_IF(size == 0); /* Get the memory state and attribute mask to test. */ u32 test_state; u32 test_attr_mask; R_TRY(GetMapAliasTestStateAndAttributeMask(test_state, test_attr_mask, src_state)); /* Determine buffer extents. */ KProcessAddress aligned_dst_start = util::AlignDown(GetInteger(client_address), PageSize); KProcessAddress aligned_dst_end = util::AlignUp(GetInteger(client_address) + size, PageSize); KProcessAddress mapping_dst_start = util::AlignUp(GetInteger(client_address), PageSize); KProcessAddress mapping_dst_end = util::AlignDown(GetInteger(client_address) + size, PageSize); KProcessAddress mapping_src_end = util::AlignDown(GetInteger(server_address) + size, PageSize); /* If the start of the buffer is unaligned, handle that. */ if (aligned_dst_start != mapping_dst_start) { MESOSPHERE_ASSERT(client_address < mapping_dst_start); const size_t copy_size = std::min<size_t>(size, mapping_dst_start - client_address); R_TRY(dst_page_table.CopyMemoryFromUserToLinear(client_address, copy_size, test_state, test_state, KMemoryPermission_UserReadWrite, test_attr_mask, KMemoryAttribute_None, server_address)); } /* If the end of the buffer is unaligned, handle that. */ if (mapping_dst_end < aligned_dst_end && (aligned_dst_start == mapping_dst_start || aligned_dst_start < mapping_dst_end)) { const size_t copy_size = client_address + size - mapping_dst_end; R_TRY(dst_page_table.CopyMemoryFromUserToLinear(mapping_dst_end, copy_size, test_state, test_state, KMemoryPermission_UserReadWrite, test_attr_mask, KMemoryAttribute_None, mapping_src_end)); } R_SUCCEED(); } ALWAYS_INLINE Result ProcessSendMessagePointerDescriptors(int &offset, int &pointer_key, KProcessPageTable &dst_page_table, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, const ReceiveList &dst_recv_list, bool dst_user) { /* Get the offset at the start of processing. */ const int cur_offset = offset; /* Get the pointer desc. */ ipc::MessageBuffer::PointerDescriptor src_desc(src_msg, cur_offset); offset += ipc::MessageBuffer::PointerDescriptor::GetDataSize() / sizeof(u32); /* Extract address/size. */ const uintptr_t src_pointer = src_desc.GetAddress(); const size_t recv_size = src_desc.GetSize(); uintptr_t recv_pointer = 0; /* Process the buffer, if it has a size. */ if (recv_size > 0) { /* If using indexing, set index. */ if (dst_recv_list.IsIndex()) { pointer_key = src_desc.GetIndex(); } /* Get the buffer. */ dst_recv_list.GetBuffer(recv_pointer, recv_size, pointer_key); R_UNLESS(recv_pointer != 0, svc::ResultOutOfResource()); /* Perform the pointer data copy. */ const bool dst_heap = dst_user && dst_recv_list.IsToMessageBuffer(); const auto dst_state = dst_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped; const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_heap ? (KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite) : KMemoryPermission_UserReadWrite); R_TRY(dst_page_table.CopyMemoryFromUserToLinear(recv_pointer, recv_size, dst_state, dst_state, dst_perm, KMemoryAttribute_Uncached, KMemoryAttribute_None, src_pointer)); } /* Set the output descriptor. */ dst_msg.Set(cur_offset, ipc::MessageBuffer::PointerDescriptor(reinterpret_cast<void *>(recv_pointer), recv_size, src_desc.GetIndex())); R_SUCCEED(); } ALWAYS_INLINE Result SendMessage(uintptr_t src_message_buffer, size_t src_buffer_size, KPhysicalAddress src_message_paddr, KThread &dst_thread, uintptr_t dst_message_buffer, size_t dst_buffer_size, KServerSession *session, KSessionRequest *request) { /* Prepare variables for send. */ KThread &src_thread = GetCurrentThread(); KProcess &dst_process = *(dst_thread.GetOwnerProcess()); KProcess &src_process = *(src_thread.GetOwnerProcess()); auto &dst_page_table = dst_process.GetPageTable(); auto &src_page_table = src_process.GetPageTable(); /* NOTE: Session is used only for debugging, and so may go unused. */ MESOSPHERE_UNUSED(session); /* NOTE: Source page table is not used, and so may go unused. */ MESOSPHERE_UNUSED(src_page_table); /* Determine the message buffers. */ u32 *dst_msg_ptr, *src_msg_ptr; bool dst_user, src_user; if (dst_message_buffer) { /* NOTE: Nintendo does not check the result of this GetPhysicalAddress call. */ KPhysicalAddress dst_message_paddr; dst_page_table.GetPhysicalAddress(std::addressof(dst_message_paddr), dst_message_buffer); dst_msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(dst_message_paddr)); dst_user = true; } else { dst_msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(dst_thread.GetThreadLocalRegionHeapAddress())->message_buffer; dst_buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer); dst_message_buffer = GetInteger(dst_thread.GetThreadLocalRegionAddress()); dst_user = false; } if (src_message_buffer) { src_msg_ptr = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(src_message_paddr)); src_user = true; } else { src_msg_ptr = static_cast<ams::svc::ThreadLocalRegion *>(src_thread.GetThreadLocalRegionHeapAddress())->message_buffer; src_buffer_size = sizeof(ams::svc::ThreadLocalRegion{}.message_buffer); src_message_buffer = GetInteger(src_thread.GetThreadLocalRegionAddress()); src_user = false; } /* Parse the headers. */ const ipc::MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size); const ipc::MessageBuffer src_msg(src_msg_ptr, src_buffer_size); const ipc::MessageBuffer::MessageHeader dst_header(dst_msg); const ipc::MessageBuffer::MessageHeader src_header(src_msg); const ipc::MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header); const ipc::MessageBuffer::SpecialHeader src_special_header(src_msg, src_header); /* Get the end of the source message. */ const size_t src_end_offset = ipc::MessageBuffer::GetRawDataIndex(src_header, src_special_header) + src_header.GetRawCount(); /* Declare variables for processing. */ int offset = 0; int pointer_key = 0; bool processed_special_data = false; /* Send the message. */ { /* Make sure that we end up in a clean state on error. */ ON_RESULT_FAILURE { /* Cleanup special data. */ if (processed_special_data) { if (src_header.GetHasSpecialHeader()) { CleanupSpecialData(dst_process, dst_msg_ptr, dst_buffer_size); } } else { static_cast<void>(CleanupServerHandles(src_user ? src_message_buffer : 0, src_buffer_size, src_message_paddr)); } /* Cleanup mappings. */ static_cast<void>(CleanupMap(request, std::addressof(src_process), std::addressof(dst_page_table))); }; /* Ensure that the headers fit. */ R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(src_header, src_special_header) <= src_buffer_size, svc::ResultInvalidCombination()); R_UNLESS(ipc::MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) <= dst_buffer_size, svc::ResultInvalidCombination()); /* Ensure the receive list offset is after the end of raw data. */ if (dst_header.GetReceiveListOffset()) { R_UNLESS(dst_header.GetReceiveListOffset() >= ipc::MessageBuffer::GetRawDataIndex(dst_header, dst_special_header) + dst_header.GetRawCount(), svc::ResultInvalidCombination()); } /* Ensure that the destination buffer is big enough to receive the source. */ R_UNLESS(dst_buffer_size >= src_end_offset * sizeof(u32), svc::ResultMessageTooLarge()); /* Replies must have no buffers. */ R_UNLESS(src_header.GetSendCount() == 0, svc::ResultInvalidCombination()); R_UNLESS(src_header.GetReceiveCount() == 0, svc::ResultInvalidCombination()); R_UNLESS(src_header.GetExchangeCount() == 0, svc::ResultInvalidCombination()); /* Get the receive list. */ const s32 dst_recv_list_idx = ipc::MessageBuffer::GetReceiveListIndex(dst_header, dst_special_header); ReceiveList dst_recv_list(dst_msg_ptr, dst_message_buffer, dst_page_table, dst_header, dst_special_header, dst_buffer_size, src_end_offset, dst_recv_list_idx, !dst_user); /* Handle any receive buffers. */ for (size_t i = 0; i < request->GetReceiveCount(); ++i) { R_TRY(ProcessSendMessageReceiveMapping(dst_page_table, request->GetReceiveClientAddress(i), request->GetReceiveServerAddress(i), request->GetReceiveSize(i), request->GetReceiveMemoryState(i))); } /* Handle any exchange buffers. */ for (size_t i = 0; i < request->GetExchangeCount(); ++i) { R_TRY(ProcessSendMessageReceiveMapping(dst_page_table, request->GetExchangeClientAddress(i), request->GetExchangeServerAddress(i), request->GetExchangeSize(i), request->GetExchangeMemoryState(i))); } /* Set the header. */ offset = dst_msg.Set(src_header); /* Process any special data. */ MESOSPHERE_ASSERT(GetCurrentThreadPointer() == std::addressof(src_thread)); processed_special_data = true; if (src_header.GetHasSpecialHeader()) { R_TRY(ProcessMessageSpecialData<true>(offset, dst_process, src_process, src_thread, dst_msg, src_msg, src_special_header)); } /* Process any pointer buffers. */ for (auto i = 0; i < src_header.GetPointerCount(); ++i) { R_TRY(ProcessSendMessagePointerDescriptors(offset, pointer_key, dst_page_table, dst_msg, src_msg, dst_recv_list, dst_user && dst_header.GetReceiveListCount() == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer)); } /* Clear any map alias buffers. */ for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { offset = dst_msg.Set(offset, ipc::MessageBuffer::MapAliasDescriptor()); } /* Process any raw data. */ if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { /* Get the offset and size. */ const size_t offset_words = offset * sizeof(u32); const size_t raw_size = raw_count * sizeof(u32); /* Fast case is TLS -> TLS, do raw memcpy if we can. */ if (!dst_user && !src_user) { std::memcpy(dst_msg_ptr + offset, src_msg_ptr + offset, raw_size); } else if (src_user) { /* Determine how much fast size we can copy. */ const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize); const size_t fast_size = max_fast_size - offset_words; /* Determine dst state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */ const auto dst_state = dst_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped; /* Determine the dst permission. User buffer should be unmapped + read, TLS should be user readable. */ const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_user ? (KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite) : KMemoryPermission_UserReadWrite); /* Perform the fast part of the copy. */ R_TRY(dst_page_table.CopyMemoryFromKernelToLinear(dst_message_buffer + offset_words, fast_size, dst_state, dst_state, dst_perm, KMemoryAttribute_Uncached, KMemoryAttribute_None, reinterpret_cast<uintptr_t>(src_msg_ptr) + offset_words)); /* If the fast part of the copy didn't get everything, perform the slow part of the copy. */ if (fast_size < raw_size) { R_TRY(dst_page_table.CopyMemoryFromHeapToHeap(dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size, dst_state, dst_state, dst_perm, KMemoryAttribute_Uncached, KMemoryAttribute_None, src_message_buffer + max_fast_size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelRead), KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked)); } } else /* if (dst_user) */ { /* The destination is a user buffer, so it should be unmapped + readable. */ constexpr KMemoryPermission DestinationPermission = static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite); /* Copy the memory. */ R_TRY(dst_page_table.CopyMemoryFromUserToLinear(dst_message_buffer + offset_words, raw_size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, DestinationPermission, KMemoryAttribute_Uncached, KMemoryAttribute_None, src_message_buffer + offset_words)); } } } /* Perform (and validate) any remaining cleanup. */ R_RETURN(CleanupMap(request, std::addressof(src_process), std::addressof(dst_page_table))); } ALWAYS_INLINE void ReplyAsyncError(KProcess *to_process, uintptr_t to_msg_buf, size_t to_msg_buf_size, Result result) { /* Convert the buffer to a physical address. */ KPhysicalAddress phys_addr; to_process->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), KProcessAddress(to_msg_buf)); /* Convert the physical address to a linear pointer. */ u32 *to_msg = GetPointer<u32>(KPageTable::GetHeapVirtualAddress(phys_addr)); /* Set the error. */ ipc::MessageBuffer msg(to_msg, to_msg_buf_size); msg.SetAsyncResult(result); } } void KServerSession::Destroy() { MESOSPHERE_ASSERT_THIS(); m_parent->OnServerClosed(); this->CleanupRequests(); m_parent->Close(); } Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size, KPhysicalAddress server_message_paddr) { MESOSPHERE_ASSERT_THIS(); /* Lock the session. */ KScopedLightLock lk(m_lock); /* Get the request and client thread. */ KSessionRequest *request; KThread *client_thread; { KScopedSchedulerLock sl; /* Ensure that we can service the request. */ R_UNLESS(!m_parent->IsClientClosed(), svc::ResultSessionClosed()); /* Ensure we aren't already servicing a request. */ R_UNLESS(m_current_request == nullptr, svc::ResultNotFound()); /* Ensure we have a request to service. */ R_UNLESS(!m_request_list.empty(), svc::ResultNotFound()); /* Pop the first request from the list. */ request = std::addressof(m_request_list.front()); m_request_list.pop_front(); /* Get the thread for the request. */ client_thread = request->GetThread(); R_UNLESS(client_thread != nullptr, svc::ResultSessionClosed()); /* Open the client thread. */ client_thread->Open(); } ON_SCOPE_EXIT { client_thread->Close(); }; /* Set the request as our current. */ m_current_request = request; /* Get the client address. */ uintptr_t client_message = request->GetAddress(); size_t client_buffer_size = request->GetSize(); bool recv_list_broken = false; /* Receive the message. */ Result result = ReceiveMessage(recv_list_broken, server_message, server_buffer_size, server_message_paddr, *client_thread, client_message, client_buffer_size, this, request); /* Handle cleanup on receive failure. */ if (R_FAILED(result)) { /* Cache the result to return it to the client. */ const Result result_for_client = result; /* Clear the current request. */ { KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_current_request == request); m_current_request = nullptr; if (!m_request_list.empty()) { this->NotifyAvailable(); } } /* Reply to the client. */ { /* After we reply, close our reference to the request. */ ON_SCOPE_EXIT { request->Close(); }; /* Get the event to check whether the request is async. */ if (KEvent *event = request->GetEvent(); event != nullptr) { /* The client sent an async request. */ KProcess *client = client_thread->GetOwnerProcess(); auto &client_pt = client->GetPageTable(); /* Send the async result. */ if (R_FAILED(result_for_client)) { ReplyAsyncError(client, client_message, client_buffer_size, result_for_client); } /* Unlock the client buffer. */ /* NOTE: Nintendo does not check the result of this. */ static_cast<void>(client_pt.UnlockForIpcUserBuffer(client_message, client_buffer_size)); /* Signal the event. */ event->Signal(); } else { /* End the client thread's wait. */ KScopedSchedulerLock sl; if (!client_thread->IsTerminationRequested()) { client_thread->EndWait(result_for_client); } } } /* Set the server result. */ if (recv_list_broken) { result = svc::ResultReceiveListBroken(); } else { result = svc::ResultNotFound(); } } R_RETURN(result); } Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buffer_size, KPhysicalAddress server_message_paddr) { MESOSPHERE_ASSERT_THIS(); /* Lock the session. */ KScopedLightLock lk(m_lock); /* Get the request. */ KSessionRequest *request; { KScopedSchedulerLock sl; /* Get the current request. */ request = m_current_request; R_UNLESS(request != nullptr, svc::ResultInvalidState()); /* Clear the current request, since we're processing it. */ m_current_request = nullptr; if (!m_request_list.empty()) { this->NotifyAvailable(); } } /* Close reference to the request once we're done processing it. */ ON_SCOPE_EXIT { request->Close(); }; /* Extract relevant information from the request. */ const uintptr_t client_message = request->GetAddress(); const size_t client_buffer_size = request->GetSize(); KThread *client_thread = request->GetThread(); KEvent *event = request->GetEvent(); /* Check whether we're closed. */ const bool closed = (client_thread == nullptr || m_parent->IsClientClosed()); Result result; if (!closed) { /* If we're not closed, send the reply. */ result = SendMessage(server_message, server_buffer_size, server_message_paddr, *client_thread, client_message, client_buffer_size, this, request); } else { /* Otherwise, we'll need to do some cleanup. */ KProcess *server_process = request->GetServerProcess(); KProcess *client_process = (client_thread != nullptr) ? client_thread->GetOwnerProcess() : nullptr; KProcessPageTable *client_page_table = (client_process != nullptr) ? std::addressof(client_process->GetPageTable()) : nullptr; /* Cleanup server handles. */ result = CleanupServerHandles(server_message, server_buffer_size, server_message_paddr); /* Cleanup mappings. */ Result cleanup_map_result = CleanupMap(request, server_process, client_page_table); /* If we successfully cleaned up handles, use the map cleanup result as our result. */ if (R_SUCCEEDED(result)) { result = cleanup_map_result; } } /* Select a result for the client. */ Result client_result = result; if (closed && R_SUCCEEDED(result)) { result = svc::ResultSessionClosed(); client_result = svc::ResultSessionClosed(); } else { result = ResultSuccess(); } /* If there's a client thread, update it. */ if (client_thread != nullptr) { if (event != nullptr) { /* Get the client process/page table. */ KProcess *client_process = client_thread->GetOwnerProcess(); KProcessPageTable *client_page_table = std::addressof(client_process->GetPageTable()); /* If we need to, reply with an async error. */ if (R_FAILED(client_result)) { ReplyAsyncError(client_process, client_message, client_buffer_size, client_result); } /* Unlock the client buffer. */ /* NOTE: Nintendo does not check the result of this. */ static_cast<void>(client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size)); /* Signal the event. */ event->Signal(); } else { /* End the client thread's wait. */ KScopedSchedulerLock sl; if (!client_thread->IsTerminationRequested()) { client_thread->EndWait(client_result); } } } R_RETURN(result); } Result KServerSession::OnRequest(KSessionRequest *request) { MESOSPHERE_ASSERT_THIS(); /* Create the wait queue. */ ThreadQueueImplForKServerSessionRequest wait_queue; /* Handle the request. */ { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Ensure that we can handle new requests. */ R_UNLESS(!m_parent->IsServerClosed(), svc::ResultSessionClosed()); /* Check that we're not terminating. */ R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested()); /* Get whether we're empty. */ const bool was_empty = m_request_list.empty(); /* Add the request to the list. */ request->Open(); m_request_list.push_back(*request); /* If we were empty, signal. */ if (was_empty) { this->NotifyAvailable(); } /* If we have a request, this is asynchronous, and we don't need to wait. */ R_SUCCEED_IF(request->GetEvent() != nullptr); /* This is a synchronous request, so we should wait for our request to complete. */ GetCurrentThread().BeginWait(std::addressof(wait_queue)); } R_RETURN(GetCurrentThread().GetWaitResult()); } bool KServerSession::IsSignaledImpl() const { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* If the client is closed, we're always signaled. */ if (m_parent->IsClientClosed()) { return true; } /* Otherwise, we're signaled if we have a request and aren't handling one. */ return !m_request_list.empty() && m_current_request == nullptr; } bool KServerSession::IsSignaled() const { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); return this->IsSignaledImpl(); } void KServerSession::CleanupRequests() { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); /* Clean up any pending requests. */ while (true) { /* Get the next request. */ KSessionRequest *request = nullptr; { KScopedSchedulerLock sl; if (m_current_request) { /* Choose the current request if we have one. */ request = m_current_request; m_current_request = nullptr; } else if (!m_request_list.empty()) { /* Pop the request from the front of the list. */ request = std::addressof(m_request_list.front()); m_request_list.pop_front(); } } /* If there's no request, we're done. */ if (request == nullptr) { break; } /* Close a reference to the request once it's cleaned up. */ ON_SCOPE_EXIT { request->Close(); }; /* Extract relevant information from the request. */ const uintptr_t client_message = request->GetAddress(); const size_t client_buffer_size = request->GetSize(); KThread *client_thread = request->GetThread(); KEvent *event = request->GetEvent(); KProcess *server_process = request->GetServerProcess(); KProcess *client_process = (client_thread != nullptr) ? client_thread->GetOwnerProcess() : nullptr; KProcessPageTable *client_page_table = (client_process != nullptr) ? std::addressof(client_process->GetPageTable()) : nullptr; /* Cleanup the mappings. */ Result result = CleanupMap(request, server_process, client_page_table); /* If there's a client thread, update it. */ if (client_thread != nullptr) { if (event != nullptr) { /* We need to reply async. */ ReplyAsyncError(client_process, client_message, client_buffer_size, (R_SUCCEEDED(result) ? svc::ResultSessionClosed() : result)); /* Unlock the client buffer. */ /* NOTE: Nintendo does not check the result of this. */ static_cast<void>(client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size)); /* Signal the event. */ event->Signal(); } else { /* End the client thread's wait. */ KScopedSchedulerLock sl; if (!client_thread->IsTerminationRequested()) { client_thread->EndWait(R_SUCCEEDED(result) ? svc::ResultSessionClosed() : result); } } } } } void KServerSession::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); /* Handle any pending requests. */ KSessionRequest *prev_request = nullptr; while (true) { /* Declare variables for processing the request. */ KSessionRequest *request = nullptr; KEvent *event = nullptr; KThread *thread = nullptr; bool cur_request = false; bool terminate = false; /* Get the next request. */ { KScopedSchedulerLock sl; if (m_current_request != nullptr && m_current_request != prev_request) { /* Set the request, open a reference as we process it. */ request = m_current_request; request->Open(); cur_request = true; /* Get thread and event for the request. */ thread = request->GetThread(); event = request->GetEvent(); /* If the thread is terminating, handle that. */ if (thread->IsTerminationRequested()) { request->ClearThread(); request->ClearEvent(); terminate = true; } prev_request = request; } else if (!m_request_list.empty()) { /* Pop the request from the front of the list. */ request = std::addressof(m_request_list.front()); m_request_list.pop_front(); /* Get thread and event for the request. */ thread = request->GetThread(); event = request->GetEvent(); } } /* If there are no requests, we're done. */ if (request == nullptr) { break; } /* All requests must have threads. */ MESOSPHERE_ASSERT(thread != nullptr); /* Ensure that we close the request when done. */ ON_SCOPE_EXIT { request->Close(); }; /* If we're terminating, close a reference to the thread and event. */ if (terminate) { thread->Close(); if (event != nullptr) { event->Close(); } } /* If we need to, reply. */ if (event != nullptr && !cur_request) { /* There must be no mappings. */ MESOSPHERE_ASSERT(request->GetSendCount() == 0); MESOSPHERE_ASSERT(request->GetReceiveCount() == 0); MESOSPHERE_ASSERT(request->GetExchangeCount() == 0); /* Get the process and page table. */ KProcess *client_process = thread->GetOwnerProcess(); auto &client_pt = client_process->GetPageTable(); /* Reply to the request. */ ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(), svc::ResultSessionClosed()); /* Unlock the buffer. */ /* NOTE: Nintendo does not check the result of this. */ static_cast<void>(client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize())); /* Signal the event. */ event->Signal(); } } /* Notify. */ this->NotifyAvailable(svc::ResultSessionClosed()); } void KServerSession::Dump() { MESOSPHERE_ASSERT_THIS(); KScopedLightLock lk(m_lock); { KScopedSchedulerLock sl; MESOSPHERE_RELEASE_LOG("Dump Session %p\n", this); /* Dump current request. */ bool has_request = false; if (m_current_request != nullptr) { KThread *thread = m_current_request->GetThread(); const s32 thread_id = thread != nullptr ? static_cast<s32>(thread->GetId()) : -1; MESOSPHERE_RELEASE_LOG(" CurrentReq %p Thread=%p ID=%d\n", m_current_request, thread, thread_id); has_request = true; } /* Dump all rqeuests in list. */ for (auto it = m_request_list.begin(); it != m_request_list.end(); ++it) { KThread *thread = it->GetThread(); const s32 thread_id = thread != nullptr ? static_cast<s32>(thread->GetId()) : -1; MESOSPHERE_RELEASE_LOG(" Req %p Thread=%p ID=%d\n", m_current_request, thread, thread_id); has_request = true; } /* If we didn't have any requests, print so. */ if (!has_request) { MESOSPHERE_RELEASE_LOG(" None\n"); } } } } #pragma GCC pop_options ================================================ FILE: libraries/libmesosphere/source/kern_k_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KSession::Initialize(KClientPort *client_port, uintptr_t name) { MESOSPHERE_ASSERT_THIS(); /* Increment reference count. */ /* Because reference count is one on creation, this will result */ /* in a reference count of two. Thus, when both server and client are closed */ /* this object will be destroyed. */ this->Open(); /* Create our sub sessions. */ KAutoObject::Create<KServerSession>(std::addressof(m_server)); KAutoObject::Create<KClientSession>(std::addressof(m_client)); /* Initialize our sub sessions. */ m_server.Initialize(this); m_client.Initialize(this); /* Set state and name. */ this->SetState(State::Normal); m_name = name; /* Set our owner process. */ m_process = GetCurrentProcessPointer(); m_process->Open(); /* Set our port. */ m_port = client_port; if (m_port != nullptr) { m_port->Open(); } /* Mark initialized. */ m_initialized = true; } void KSession::Finalize() { if (m_port != nullptr) { m_port->OnSessionFinalized(); m_port->Close(); } } void KSession::OnServerClosed() { MESOSPHERE_ASSERT_THIS(); if (this->GetState() == State::Normal) { this->SetState(State::ServerClosed); m_client.OnServerClosed(); } } void KSession::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); if (this->GetState() == State::Normal) { this->SetState(State::ClientClosed); m_server.OnClientClosed(); } } void KSession::PostDestroy(uintptr_t arg) { /* Release the session count resource the owner process holds. */ KProcess *owner = reinterpret_cast<KProcess *>(arg); owner->ReleaseResource(ams::svc::LimitableResource_SessionCountMax, 1); owner->Close(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_session_request.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KSessionRequest::SessionMappings::PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index) { /* At most 15 buffers of each type (4-bit descriptor counts). */ MESOSPHERE_ASSERT(index < NumMappings); /* Get the mapping. */ Mapping *mapping; if (index < NumStaticMappings) { mapping = std::addressof(m_static_mappings[index]); } else { /* Allocate dynamic mappings as necessary. */ if (m_dynamic_mappings == nullptr) { m_dynamic_mappings = DynamicMappings::Allocate(); R_UNLESS(m_dynamic_mappings != nullptr, svc::ResultOutOfMemory()); } mapping = std::addressof(m_dynamic_mappings->Get(index - NumStaticMappings)); } /* Set the mapping. */ mapping->Set(client, server, size, state); R_SUCCEED(); } Result KSessionRequest::SessionMappings::PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { MESOSPHERE_ASSERT(m_num_recv == 0); MESOSPHERE_ASSERT(m_num_exch == 0); R_RETURN(this->PushMap(client, server, size, state, m_num_send++)); } Result KSessionRequest::SessionMappings::PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { MESOSPHERE_ASSERT(m_num_exch == 0); R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv++)); } Result KSessionRequest::SessionMappings::PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++)); } void KSessionRequest::SessionMappings::Finalize() { if (m_dynamic_mappings) { DynamicMappings::Free(m_dynamic_mappings); m_dynamic_mappings = nullptr; } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_shared_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KSharedMemory::Initialize(KProcess *owner, size_t size, ams::svc::MemoryPermission own_perm, ams::svc::MemoryPermission rem_perm) { MESOSPHERE_ASSERT_THIS(); /* Set members. */ m_owner_process_id = owner->GetId(); m_owner_perm = own_perm; m_remote_perm = rem_perm; /* Get the number of pages. */ const size_t num_pages = util::DivideUp(size, PageSize); MESOSPHERE_ASSERT(num_pages > 0); /* Get the resource limit. */ KResourceLimit *reslimit = owner->GetResourceLimit(); /* Reserve memory for ourselves. */ KScopedResourceReservation memory_reservation(reslimit, ams::svc::LimitableResource_PhysicalMemoryMax, size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Allocate the memory. */ R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(m_page_group), num_pages, 1, owner->GetAllocateOption())); /* Commit our reservation. */ memory_reservation.Commit(); /* Set our resource limit. */ m_resource_limit = reslimit; m_resource_limit->Open(); /* Mark initialized. */ m_is_initialized = true; /* Clear all pages in the memory. */ for (const auto &block : m_page_group) { std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block.GetAddress())), 0, block.GetSize()); } R_SUCCEED(); } void KSharedMemory::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Get the number of pages. */ const size_t num_pages = m_page_group.GetNumPages(); const size_t size = num_pages * PageSize; /* Close and finalize the page group. */ m_page_group.Close(); m_page_group.Finalize(); /* Release the memory reservation. */ m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size); m_resource_limit->Close(); } Result KSharedMemory::Map(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process, ams::svc::MemoryPermission map_perm) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Validate the permission. */ const ams::svc::MemoryPermission test_perm = (process->GetId() == m_owner_process_id) ? m_owner_perm : m_remote_perm; if (test_perm == ams::svc::MemoryPermission_DontCare) { MESOSPHERE_ASSERT(map_perm == ams::svc::MemoryPermission_Read || map_perm == ams::svc::MemoryPermission_ReadWrite); } else { R_UNLESS(map_perm == test_perm, svc::ResultInvalidNewMemoryPermission()); } /* Map the memory. */ R_RETURN(table->MapPageGroup(address, m_page_group, KMemoryState_Shared, ConvertToKMemoryPermission(map_perm))); } Result KSharedMemory::Unmap(KProcessPageTable *table, KProcessAddress address, size_t size, KProcess *process) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_UNUSED(process); /* Validate the size. */ R_UNLESS(m_page_group.GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Unmap the memory. */ R_RETURN(table->UnmapPageGroup(address, m_page_group, KMemoryState_Shared)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_synchronization_object.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { private: using ThreadListNode = KSynchronizationObject::ThreadListNode; private: KSynchronizationObject **m_objects; ThreadListNode *m_nodes; s32 m_count; public: constexpr ThreadQueueImplForKSynchronizationObjectWait(KSynchronizationObject **o, ThreadListNode *n, s32 c) : m_objects(o), m_nodes(n), m_count(c) { /* ... */ } virtual void NotifyAvailable(KThread *waiting_thread, KSynchronizationObject *signaled_object, Result wait_result) override { /* Determine the sync index, and unlink all nodes. */ s32 sync_index = -1; for (auto i = 0; i < m_count; ++i) { /* Check if this is the signaled object. */ if (m_objects[i] == signaled_object && sync_index == -1) { sync_index = i; } /* Unlink the current node from the current object. */ m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); } /* Set the waiting thread's sync index. */ waiting_thread->SetSyncedIndex(sync_index); /* Set the waiting thread as not cancellable. */ waiting_thread->ClearCancellable(); /* Invoke the base end wait handler. */ KThreadQueue::EndWait(waiting_thread, wait_result); } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove all nodes from our list. */ for (auto i = 0; i < m_count; ++i) { m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); } /* Set the waiting thread as not cancellable. */ waiting_thread->ClearCancellable(); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } void KSynchronizationObject::Finalize() { MESOSPHERE_ASSERT_THIS(); /* If auditing, ensure that the object has no waiters. */ #if defined(MESOSPHERE_BUILD_FOR_AUDITING) { KScopedSchedulerLock sl; for (auto *cur_node = m_thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { KThread *thread = cur_node->thread; MESOSPHERE_LOG("KSynchronizationObject::Finalize(%p) with %p (id=%ld) waiting.\n", this, thread, thread->GetId()); } } #endif /* NOTE: In Nintendo's kernel, the following is virtual and called here. */ /* this->OnFinalizeSynchronizationObject(); */ } Result KSynchronizationObject::Wait(s32 *out_index, KSynchronizationObject **objects, const s32 num_objects, s64 timeout) { /* Allocate space on stack for thread nodes. */ ThreadListNode *thread_nodes = static_cast<ThreadListNode *>(__builtin_alloca(sizeof(ThreadListNode) * num_objects)); /* Prepare for wait. */ KThread *thread = GetCurrentThreadPointer(); KHardwareTimer *timer; ThreadQueueImplForKSynchronizationObjectWait wait_queue(objects, thread_nodes, num_objects); { /* Setup the scheduling lock and sleep. */ KScopedSchedulerLockAndSleep slp(std::addressof(timer), thread, timeout); /* Check if the thread should terminate. */ if (thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Check if any of the objects are already signaled. */ for (auto i = 0; i < num_objects; ++i) { MESOSPHERE_ASSERT(objects[i] != nullptr); if (objects[i]->IsSignaled()) { *out_index = i; slp.CancelSleep(); R_SUCCEED(); } } /* Check if the timeout is zero. */ if (timeout == 0) { slp.CancelSleep(); R_THROW(svc::ResultTimedOut()); } /* Check if waiting was canceled. */ if (thread->IsWaitCancelled()) { slp.CancelSleep(); thread->ClearWaitCancelled(); R_THROW(svc::ResultCancelled()); } /* Add the waiters. */ for (auto i = 0; i < num_objects; ++i) { thread_nodes[i].thread = thread; thread_nodes[i].next = nullptr; objects[i]->LinkNode(std::addressof(thread_nodes[i])); } /* Mark the thread as cancellable. */ thread->SetCancellable(); /* Clear the thread's synced index. */ thread->SetSyncedIndex(-1); /* Wait for an object to be signaled. */ wait_queue.SetHardwareTimer(timer); thread->BeginWait(std::addressof(wait_queue)); } /* Set the output index. */ *out_index = thread->GetSyncedIndex(); /* Get the wait result. */ R_RETURN(thread->GetWaitResult()); } void KSynchronizationObject::NotifyAvailable(Result result) { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; /* If we're not signaled, we've nothing to notify. */ if (!this->IsSignaled()) { return; } /* Iterate over each thread. */ for (auto *cur_node = m_thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { cur_node->thread->NotifyAvailable(this, result); } } void KSynchronizationObject::DumpWaiters() { MESOSPHERE_ASSERT_THIS(); /* If debugging, dump the list of waiters. */ #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) { KScopedSchedulerLock sl; MESOSPHERE_RELEASE_LOG("Threads waiting on %p:\n", this); for (auto *cur_node = m_thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { KThread *thread = cur_node->thread; if (KProcess *process = thread->GetOwnerProcess(); process != nullptr) { MESOSPHERE_RELEASE_LOG(" %p tid=%ld pid=%ld (%s)\n", thread, thread->GetId(), process->GetId(), process->GetName()); } else { MESOSPHERE_RELEASE_LOG(" %p tid=%ld (Kernel)\n", thread, thread->GetId()); } } /* If we didn't have any waiters, print so. */ if (m_thread_list_head == nullptr) { MESOSPHERE_RELEASE_LOG(" None\n"); } } #endif } } ================================================ FILE: libraries/libmesosphere/source/kern_k_system_control_base.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #if defined(ATMOSPHERE_ARCH_ARM64) #include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp> #endif namespace ams::kern { namespace init { /* TODO: Is this function name architecture specific? */ void StartOtherCore(const ams::kern::init::KInitArguments *init_args); } /* Initialization. */ size_t KSystemControlBase::Init::GetRealMemorySize() { return ams::kern::MainMemorySize; } size_t KSystemControlBase::Init::GetIntendedMemorySize() { return ams::kern::MainMemorySize; } KPhysicalAddress KSystemControlBase::Init::GetKernelPhysicalBaseAddress(KPhysicalAddress base_address) { const size_t real_dram_size = KSystemControl::Init::GetRealMemorySize(); const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize(); if (intended_dram_size * 2 <= real_dram_size) { return base_address; } else { return base_address + ((real_dram_size - intended_dram_size) / 2); } } void KSystemControlBase::Init::GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out, KPhysicalAddress kern_base_address) { *out = { .address = GetInteger(KSystemControl::Init::GetKernelPhysicalBaseAddress(ams::kern::MainMemoryAddress)) + KSystemControl::Init::GetIntendedMemorySize() - InitialProcessBinarySizeMax, ._08 = 0, .kern_address = GetInteger(kern_base_address), }; } bool KSystemControlBase::Init::ShouldIncreaseThreadResourceLimit() { return true; } size_t KSystemControlBase::Init::GetApplicationPoolSize() { return 0; } size_t KSystemControlBase::Init::GetAppletPoolSize() { return 0; } size_t KSystemControlBase::Init::GetMinimumNonSecureSystemPoolSize() { return 0; } u8 KSystemControlBase::Init::GetDebugLogUartPort() { return 0; } void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { #if defined(ATMOSPHERE_ARCH_ARM64) MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0>(core_id, entrypoint, arg)) == 0); #else AMS_INFINITE_LOOP(); #endif } void KSystemControlBase::Init::TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args) { /* Get entrypoint. */ KPhysicalAddress entrypoint = Null<KPhysicalAddress>; while (!cpu::GetPhysicalAddressReadable(std::addressof(entrypoint), reinterpret_cast<uintptr_t>(::ams::kern::init::StartOtherCore), true)) { /* ... */ } /* Get arguments. */ KPhysicalAddress args_addr = Null<KPhysicalAddress>; while (!cpu::GetPhysicalAddressReadable(std::addressof(args_addr), reinterpret_cast<uintptr_t>(args), true)) { /* ... */ } /* Ensure cache is correct for the initial arguments. */ cpu::StoreDataCacheForInitArguments(args, sizeof(*args)); /* Turn on the cpu. */ KSystemControl::Init::CpuOnImpl(core_id, GetInteger(entrypoint), GetInteger(args_addr)); } /* Randomness for Initialization. */ void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) { if (AMS_UNLIKELY(s_uninitialized_random_generator)) { const u64 seed = KHardwareTimer::GetTick(); s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32)); s_uninitialized_random_generator = false; } for (size_t i = 0; i < count; ++i) { dst[i] = s_random_generator.GenerateRandomU64(); } } u64 KSystemControlBase::Init::GenerateRandomRange(u64 min, u64 max) { if (AMS_UNLIKELY(s_uninitialized_random_generator)) { const u64 seed = KHardwareTimer::GetTick(); s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32)); s_uninitialized_random_generator = false; } return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); }); } /* System Initialization. */ void KSystemControlBase::ConfigureKTargetSystem() { /* By default, use the default config set in the KTargetSystem header. */ } void KSystemControlBase::InitializePhase1() { /* Enable KTargetSystem. */ { KTargetSystem::SetInitialized(); } /* Initialize random and resource limit. */ KSystemControlBase::InitializePhase1Base(KHardwareTimer::GetTick()); } void KSystemControlBase::InitializePhase1Base(u64 seed) { /* Initialize the rng, if we somehow haven't already. */ if (AMS_UNLIKELY(s_uninitialized_random_generator)) { s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32)); s_uninitialized_random_generator = false; } /* Initialize debug logging. */ KDebugLog::Initialize(); /* System ResourceLimit initialization. */ { /* Construct the resource limit object. */ KResourceLimit &sys_res_limit = Kernel::GetSystemResourceLimit(); KAutoObject::Create<KResourceLimit>(std::addressof(sys_res_limit)); sys_res_limit.Initialize(); /* Set the initial limits. */ const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes(); /* Update 39-bit address space infos. */ { /* Heap should be equal to the total memory size, minimum 8 GB, maximum 32 GB. */ /* Alias should be equal to 8 * heap size, maximum 128 GB. */ const size_t heap_size = std::max(std::min(util::AlignUp(total_memory_size, 1_GB), 32_GB), 8_GB); const size_t alias_size = std::min(heap_size * 8, 128_GB); /* Set the address space sizes. */ KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap, heap_size); KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size); } const auto &slab_counts = init::GetSlabResourceCounts(); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size)); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread)); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_EventCountMax, slab_counts.num_KEvent)); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax, slab_counts.num_KTransferMemory)); MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_SessionCountMax, slab_counts.num_KSession)); /* Reserve system memory. */ MESOSPHERE_ABORT_UNLESS(sys_res_limit.Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, kernel_memory_size)); } } void KSystemControlBase::InitializePhase2() { /* Initialize KTrace. */ if constexpr (IsKTraceEnabled) { const auto &ktrace = KMemoryLayout::GetKernelTraceBufferRegion(); KTrace::Initialize(ktrace.GetAddress(), ktrace.GetSize()); } } u32 KSystemControlBase::GetCreateProcessMemoryPool() { return KMemoryManager::Pool_System; } /* Privileged Access. */ void KSystemControlBase::ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { /* TODO */ MESOSPHERE_UNUSED(out, address, mask, value); MESOSPHERE_UNIMPLEMENTED(); } Result KSystemControlBase::ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { MESOSPHERE_UNUSED(out, address, mask, value); R_THROW(svc::ResultNotImplemented()); } /* Randomness. */ void KSystemControlBase::GenerateRandom(u64 *dst, size_t count) { KScopedInterruptDisable intr_disable; KScopedSpinLock lk(s_random_lock); for (size_t i = 0; i < count; ++i) { dst[i] = s_random_generator.GenerateRandomU64(); } } u64 KSystemControlBase::GenerateRandomRange(u64 min, u64 max) { KScopedInterruptDisable intr_disable; KScopedSpinLock lk(s_random_lock); return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); }); } u64 KSystemControlBase::GenerateRandomU64() { KScopedInterruptDisable intr_disable; KScopedSpinLock lk(s_random_lock); return s_random_generator.GenerateRandomU64(); } void KSystemControlBase::SleepSystem() { MESOSPHERE_LOG("SleepSystem() was called\n"); } void KSystemControlBase::StopSystem(void *) { MESOSPHERE_LOG("KSystemControlBase::StopSystem\n"); AMS_INFINITE_LOOP(); } /* User access. */ #if defined(ATMOSPHERE_ARCH_ARM64) void KSystemControlBase::CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) { /* Get the function id for the current call. */ u64 function_id = args->r[0]; /* We'll need to map in pages if arguments are pointers. Prepare page groups to do so. */ auto &page_table = GetCurrentProcess().GetPageTable(); auto *bim = page_table.GetBlockInfoManager(); constexpr size_t MaxMappedRegisters = 7; std::array<KPageGroup, MaxMappedRegisters> page_groups = { KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), }; for (size_t i = 0; i < MaxMappedRegisters; i++) { const size_t reg_id = i + 1; if (function_id & (1ul << (8 + reg_id))) { /* Create and open a new page group for the address. */ KVirtualAddress virt_addr = args->r[reg_id]; if (R_SUCCEEDED(page_table.MakeAndOpenPageGroup(std::addressof(page_groups[i]), util::AlignDown(GetInteger(virt_addr), PageSize), 1, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None))) { /* Translate the virtual address to a physical address. */ const auto it = page_groups[i].begin(); MESOSPHERE_ASSERT(it != page_groups[i].end()); MESOSPHERE_ASSERT(it->GetNumPages() == 1); args->r[reg_id] = GetInteger(it->GetAddress()) | (GetInteger(virt_addr) & (PageSize - 1)); } else { /* If we couldn't map, we should clear the address. */ args->r[reg_id] = 0; } } } /* Invoke the secure monitor. */ KSystemControl::CallSecureMonitorFromUserImpl(args); /* Make sure that we close any pages that we opened. */ for (size_t i = 0; i < MaxMappedRegisters; i++) { page_groups[i].Close(); } } void KSystemControlBase::CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) { /* By default, we don't actually support secure monitor, so just set args to a failure code. */ args->r[0] = 1; } #endif /* Secure Memory. */ size_t KSystemControlBase::CalculateRequiredSecureMemorySize(size_t size, u32 pool) { MESOSPHERE_UNUSED(pool); return size; } Result KSystemControlBase::AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool) { /* Ensure the size is aligned. */ constexpr size_t Alignment = PageSize; R_UNLESS(util::IsAligned(size, Alignment), svc::ResultInvalidSize()); /* Allocate the memory. */ const size_t num_pages = size / PageSize; const KPhysicalAddress paddr = Kernel::GetMemoryManager().AllocateAndOpenContinuous(num_pages, Alignment / PageSize, KMemoryManager::EncodeOption(static_cast<KMemoryManager::Pool>(pool), KMemoryManager::Direction_FromFront)); R_UNLESS(paddr != Null<KPhysicalAddress>, svc::ResultOutOfMemory()); *out = KPageTable::GetHeapVirtualAddress(paddr); R_SUCCEED(); } void KSystemControlBase::FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool) { /* Ensure the size is aligned. */ constexpr size_t Alignment = PageSize; MESOSPHERE_UNUSED(pool); MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), Alignment)); MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, Alignment)); /* Close the secure region's pages. */ Kernel::GetMemoryManager().Close(KPageTable::GetHeapPhysicalAddress(address), size / PageSize); } /* Insecure Memory. */ KResourceLimit *KSystemControlBase::GetInsecureMemoryResourceLimit() { return std::addressof(Kernel::GetSystemResourceLimit()); } u32 KSystemControlBase::GetInsecureMemoryPool() { return KMemoryManager::Pool_SystemNonSecure; } } ================================================ FILE: libraries/libmesosphere/source/kern_k_system_resource.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KSecureSystemResource::Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool) { /* Set members. */ m_resource_limit = resource_limit; m_resource_size = size; m_resource_pool = pool; /* Determine required size for our secure resource. */ const size_t secure_size = this->CalculateRequiredSecureMemorySize(); /* Reserve memory for our secure resource. */ KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, secure_size); R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached()); /* Allocate secure memory. */ R_TRY(KSystemControl::AllocateSecureMemory(std::addressof(m_resource_address), m_resource_size, m_resource_pool)); MESOSPHERE_ASSERT(m_resource_address != Null<KVirtualAddress>); /* Ensure we clean up the secure memory, if we fail past this point. */ ON_RESULT_FAILURE { KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool); }; /* Check that our allocation is bigger than the reference counts needed for it. */ const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(m_resource_size), PageSize); R_UNLESS(m_resource_size > rc_size, svc::ResultOutOfMemory()); /* Initialize slab heaps. */ R_TRY(m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size, PageSize)); m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer<KPageTableManager::RefCount>(m_resource_address)); m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0); /* Initialize managers. */ m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_page_table_heap)); m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_memory_block_heap)); m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_block_info_heap)); /* Set our managers. */ this->SetManagers(m_memory_block_slab_manager, m_block_info_manager, m_page_table_manager); /* Commit the memory reservation. */ memory_reservation.Commit(); /* Open reference to our resource limit. */ if (m_resource_limit != nullptr) { m_resource_limit->Open(); } /* Set ourselves as initialized. */ m_is_initialized = true; R_SUCCEED(); } void KSecureSystemResource::Finalize() { /* Check that we have no outstanding allocations. */ MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0); MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0); MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0); /* Free our secure memory. */ KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool); /* Clean up our resource usage. */ if (m_resource_limit != nullptr) { /* Release the memory reservation. */ m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, this->CalculateRequiredSecureMemorySize()); /* Close reference to our resource limit. */ m_resource_limit->Close(); } } size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool) { return KSystemControl::CalculateRequiredSecureMemorySize(size, pool); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_thread.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { constexpr inline s32 TerminatingThreadPriority = ams::svc::SystemThreadPriorityHighest - 1; constinit util::Atomic<u64> g_thread_id = 0; constexpr ALWAYS_INLINE bool IsKernelAddressKey(KProcessAddress key) { const uintptr_t key_uptr = GetInteger(key); return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast && (key_uptr & 1) == 0; } void InitializeKernelStack(uintptr_t stack_top) { #if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE) const uintptr_t stack_bottom = stack_top - PageSize; std::memset(reinterpret_cast<void *>(stack_bottom), 0xCC, PageSize - sizeof(KThread::StackParameters)); #else MESOSPHERE_UNUSED(stack_top); #endif } void CleanupKernelStack(uintptr_t stack_top) { const uintptr_t stack_bottom = stack_top - PageSize; KPhysicalAddress stack_paddr = Null<KPhysicalAddress>; MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(stack_paddr), stack_bottom)); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPages(stack_bottom, 1, KMemoryState_Kernel)); /* Free the stack page. */ KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(stack_paddr)); } class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { /* ... */ }; class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { private: KThread::WaiterList *m_wait_list; public: constexpr ThreadQueueImplForKThreadSetProperty(KThread::WaiterList *wl) : m_wait_list(wl) { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread from the wait list. */ m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } ALWAYS_INLINE void KThread::SetPinnedSvcPermissions() { /* Get our stack parameters. */ auto &sp = this->GetStackParameters(); /* Get our parent's svc permissions. */ MESOSPHERE_ASSERT(m_parent != nullptr); const auto &svc_permissions = m_parent->GetSvcPermissions(); /* Get whether we have access to return from exception. */ const bool return_from_exception = sp.svc_access_flags[svc::SvcId_ReturnFromException]; /* Clear all permissions. */ sp.svc_access_flags.Reset(); /* Set SynchronizePreemptionState if allowed. */ if (svc_permissions[svc::SvcId_SynchronizePreemptionState]) { sp.svc_access_flags[svc::SvcId_SynchronizePreemptionState] = true; } /* If we previously had ReturnFromException, potentially grant it and GetInfo. */ if (return_from_exception) { /* Set ReturnFromException (guaranteed allowed, if we're here). */ sp.svc_access_flags[svc::SvcId_ReturnFromException] = true; /* Set GetInfo if allowed. */ if (svc_permissions[svc::SvcId_GetInfo]) { sp.svc_access_flags[svc::SvcId_GetInfo] = true; } } } ALWAYS_INLINE void KThread::SetUnpinnedSvcPermissions() { /* Get our stack parameters. */ auto &sp = this->GetStackParameters(); /* Get our parent's svc permissions. */ MESOSPHERE_ASSERT(m_parent != nullptr); const auto &svc_permissions = m_parent->GetSvcPermissions(); /* Get whether we have access to return from exception. */ const bool return_from_exception = sp.svc_access_flags[svc::SvcId_ReturnFromException]; /* Copy permissions. */ sp.svc_access_flags = svc_permissions; /* Clear specific SVCs based on our state. */ sp.svc_access_flags[svc::SvcId_SynchronizePreemptionState] = false; if (!return_from_exception) { sp.svc_access_flags[svc::SvcId_ReturnFromException] = false; } } ALWAYS_INLINE void KThread::SetUsermodeExceptionSvcPermissions() { /* Get our stack parameters. */ auto &sp = this->GetStackParameters(); /* Get our parent's svc permissions. */ MESOSPHERE_ASSERT(m_parent != nullptr); const auto &svc_permissions = m_parent->GetSvcPermissions(); /* Set ReturnFromException if allowed. */ if (svc_permissions[svc::SvcId_ReturnFromException]) { sp.svc_access_flags[svc::SvcId_ReturnFromException] = true; } /* Set GetInfo if allowed. */ if (svc_permissions[svc::SvcId_GetInfo]) { sp.svc_access_flags[svc::SvcId_GetInfo] = true; } } ALWAYS_INLINE void KThread::ClearUsermodeExceptionSvcPermissions() { /* Get our stack parameters. */ auto &sp = this->GetStackParameters(); /* Clear ReturnFromException. */ sp.svc_access_flags[svc::SvcId_ReturnFromException] = false; /* If pinned, clear GetInfo. */ if (sp.is_pinned) { sp.svc_access_flags[svc::SvcId_GetInfo] = false; } } Result KThread::Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type) { /* Assert parameters are valid. */ MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(kern_stack_top != nullptr); MESOSPHERE_ASSERT((type == ThreadType_Main) || (ams::svc::HighestThreadPriority <= prio && prio <= ams::svc::LowestThreadPriority)); MESOSPHERE_ASSERT((owner != nullptr) || (type != ThreadType_User)); MESOSPHERE_ASSERT(0 <= virt_core && virt_core < static_cast<s32>(BITSIZEOF(u64))); /* Convert the virtual core to a physical core. */ const s32 phys_core = cpu::VirtualToPhysicalCoreMap[virt_core]; MESOSPHERE_ASSERT(0 <= phys_core && phys_core < static_cast<s32>(cpu::NumCores)); /* First, clear the TLS address. */ m_tls_address = Null<KProcessAddress>; const uintptr_t kern_stack_top_address = reinterpret_cast<uintptr_t>(kern_stack_top); MESOSPHERE_UNUSED(kern_stack_top_address); /* Next, assert things based on the type. */ switch (type) { case ThreadType_Main: { MESOSPHERE_ASSERT(arg == 0); } [[fallthrough]]; case ThreadType_HighPriority: if (type != ThreadType_Main) { MESOSPHERE_ASSERT(phys_core == GetCurrentCoreId()); } [[fallthrough]]; case ThreadType_Kernel: { MESOSPHERE_ASSERT(user_stack_top == 0); MESOSPHERE_ASSERT(util::IsAligned(kern_stack_top_address, PageSize)); } [[fallthrough]]; case ThreadType_User: { MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetCoreMask() | (1ul << virt_core)) == owner->GetCoreMask())); MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetPriorityMask() | (1ul << prio)) == owner->GetPriorityMask())); } break; default: MESOSPHERE_PANIC("KThread::Initialize: Unknown ThreadType %u", static_cast<u32>(type)); break; } /* Set the ideal core ID and affinity mask. */ m_virtual_ideal_core_id = virt_core; m_physical_ideal_core_id = phys_core; m_virtual_affinity_mask = (static_cast<u64>(1) << virt_core); m_physical_affinity_mask.SetAffinity(phys_core, true); /* Set the thread state. */ m_thread_state = (type == ThreadType_Main) ? ThreadState_Runnable : ThreadState_Initialized; /* Set TLS address and TLS heap address. */ /* NOTE: Nintendo wrote TLS address above already, but official code really does write tls address twice. */ m_tls_address = 0; m_tls_heap_address = 0; /* Set parent and condvar tree. */ m_parent = nullptr; m_condvar_tree = nullptr; m_condvar_key = 0; /* Set sync booleans. */ m_signaled = false; m_termination_requested = false; m_wait_cancelled = false; m_cancellable = false; /* Set core ID and wait result. */ m_core_id = phys_core; m_wait_result = svc::ResultNoSynchronizationObject(); /* Set the stack top. */ m_kernel_stack_top = kern_stack_top; /* Set priorities. */ m_priority = prio; m_base_priority = prio; /* Initialize wait queue/sync index. */ m_synced_index = -1; m_wait_queue = nullptr; /* Set suspend flags. */ m_suspend_request_flags = 0; m_suspend_allowed_flags = ThreadState_SuspendFlagMask; /* We're neither debug attached, nor are we nesting our priority inheritance. */ m_debug_attached = false; m_priority_inheritance_count = 0; /* We haven't been scheduled, and we have done no light IPC. */ m_schedule_count = -1; m_last_scheduled_tick = 0; m_light_ipc_data = nullptr; /* We're not waiting for a lock, and we haven't disabled migration. */ m_waiting_lock_info = nullptr; m_num_core_migration_disables = 0; /* We have no waiters, and no closed objects. */ m_num_kernel_waiters = 0; m_closed_object = nullptr; /* Set our current core id. */ m_current_core_id = phys_core; /* We haven't released our resource limit hint, and we've spent no time on the cpu. */ m_resource_limit_release_hint = false; m_cpu_time = 0; /* Setup our kernel stack. */ if (type != ThreadType_Main) { InitializeKernelStack(reinterpret_cast<uintptr_t>(kern_stack_top)); } /* Clear our stack parameters. */ std::memset(static_cast<void *>(std::addressof(this->GetStackParameters())), 0, sizeof(StackParameters)); /* Setup the TLS, if needed. */ if (type == ThreadType_User) { R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address))); m_tls_heap_address = owner->GetThreadLocalRegionPointer(m_tls_address); std::memset(m_tls_heap_address, 0, ams::svc::ThreadLocalRegionSize); } /* Set parent, if relevant. */ if (owner != nullptr) { m_parent = owner; m_parent->Open(); } /* Initialize thread context. */ constexpr bool IsDefault64Bit = sizeof(uintptr_t) == sizeof(u64); const bool is_64_bit = m_parent ? m_parent->Is64Bit() : IsDefault64Bit; const bool is_user = (type == ThreadType_User); const bool is_main = (type == ThreadType_Main); this->GetContext().Initialize(reinterpret_cast<uintptr_t>(func), reinterpret_cast<uintptr_t>(this->GetStackTop()), GetInteger(user_stack_top), arg, is_user, is_64_bit, is_main); /* Setup the stack parameters. */ StackParameters &sp = this->GetStackParameters(); if (m_parent != nullptr) { this->SetUnpinnedSvcPermissions(); this->ClearUsermodeExceptionSvcPermissions(); } sp.caller_save_fpu_registers = std::addressof(m_caller_save_fpu_registers); sp.cur_thread = this; sp.disable_count = 1; this->SetInExceptionHandler(); if (m_parent != nullptr && is_64_bit) { this->SetFpu64Bit(); } /* Set thread ID. */ m_thread_id = g_thread_id++; /* We initialized! */ m_initialized = true; /* Register ourselves with our parent process. */ if (m_parent != nullptr) { m_parent->RegisterThread(this); if (m_parent->IsSuspended()) { this->RequestSuspend(SuspendType_Process); } } R_SUCCEED(); } Result KThread::InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type) { /* Get stack region for the thread. */ const auto &stack_region = KMemoryLayout::GetKernelStackRegion(); MESOSPHERE_ABORT_UNLESS(stack_region.GetEndAddress() != 0); /* Allocate a page to use as the thread. */ KPageBuffer *page = KPageBuffer::AllocateChecked<PageSize>(); R_UNLESS(page != nullptr, svc::ResultOutOfResource()); /* Map the stack page. */ KProcessAddress stack_top = Null<KProcessAddress>; { /* If we fail to map, avoid leaking the page. */ ON_RESULT_FAILURE { KPageBuffer::Free(page); }; /* Perform the mapping. */ KProcessAddress stack_bottom = Null<KProcessAddress>; R_TRY(Kernel::GetKernelPageTable().MapPages(std::addressof(stack_bottom), 1, PageSize, page->GetPhysicalAddress(), stack_region.GetAddress(), stack_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite)); /* Calculate top of the stack. */ stack_top = stack_bottom + PageSize; } /* If we fail, cleanup the stack we mapped. */ ON_RESULT_FAILURE { CleanupKernelStack(GetInteger(stack_top)); }; /* Initialize the thread. */ R_RETURN(thread->Initialize(func, arg, GetVoidPointer(stack_top), user_stack_top, prio, core, owner, type)); } void KThread::PostDestroy(uintptr_t arg) { KProcess *owner = reinterpret_cast<KProcess *>(arg & ~1ul); const bool resource_limit_release_hint = (arg & 1); const s64 hint_value = (resource_limit_release_hint ? 0 : 1); if (owner != nullptr) { owner->ReleaseResource(ams::svc::LimitableResource_ThreadCountMax, 1, hint_value); owner->Close(); } else { Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_ThreadCountMax, 1, hint_value); } } void KThread::ResumeThreadsSuspendedForInit() { KThread::ListAccessor list_accessor; { KScopedSchedulerLock sl; for (auto &thread : list_accessor) { static_cast<KThread &>(thread).Resume(SuspendType_Init); } } } void KThread::Finalize() { MESOSPHERE_ASSERT_THIS(); /* If the thread has an owner process, unregister it. */ if (m_parent != nullptr) { m_parent->UnregisterThread(this); } /* If the thread has a local region, delete it. */ if (m_tls_address != Null<KProcessAddress>) { m_parent->DeleteThreadLocalRegion(m_tls_address); } /* Release any waiters. */ { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); KScopedSchedulerLock sl; /* Check that we have no kernel waiters. */ MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters == 0); auto it = m_held_lock_info_list.begin(); while (it != m_held_lock_info_list.end()) { /* Get the lock info. */ auto * const lock_info = std::addressof(*it); /* The lock shouldn't have a kernel waiter. */ MESOSPHERE_ASSERT(!IsKernelAddressKey(lock_info->GetAddressKey())); /* Remove all waiters. */ while (lock_info->GetWaiterCount() != 0) { /* Get the front waiter. */ KThread * const waiter = lock_info->GetHighestPriorityWaiter(); /* Remove it from the lock. */ if (lock_info->RemoveWaiter(waiter)) { MESOSPHERE_ASSERT(lock_info->GetWaiterCount() == 0); } /* Cancel the thread's wait. */ waiter->CancelWait(svc::ResultInvalidState(), true); } /* Remove the held lock from our list. */ it = m_held_lock_info_list.erase(it); /* Free the lock info. */ LockWithPriorityInheritanceInfo::Free(lock_info); } } /* Cleanup the kernel stack. */ if (m_kernel_stack_top != nullptr) { CleanupKernelStack(reinterpret_cast<uintptr_t>(m_kernel_stack_top)); } /* Perform inherited finalization. */ KSynchronizationObject::Finalize(); } bool KThread::IsSignaled() const { return m_signaled; } void KThread::OnTimer() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* If we're waiting, cancel the wait. */ if (this->GetState() == ThreadState_Waiting) { m_wait_queue->CancelWait(this, svc::ResultTimedOut(), false); } } void KThread::StartTermination() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Release user exception and unpin, if relevant. */ if (m_parent != nullptr) { m_parent->ReleaseUserException(this); if (m_parent->GetPinnedThread(GetCurrentCoreId()) == this) { m_parent->UnpinCurrentThread(); } } /* Set state to terminated. */ this->SetState(KThread::ThreadState_Terminated); /* Clear the thread's status as running in parent. */ if (m_parent != nullptr) { m_parent->ClearRunningThread(this); } /* Call the on thread termination handler. */ KThreadContext::OnThreadTerminating(this); /* Clear previous thread in KScheduler. */ KScheduler::ClearPreviousThread(this); /* Register terminated dpc flag. */ this->RegisterDpc(DpcFlag_Terminated); } void KThread::FinishTermination() { MESOSPHERE_ASSERT_THIS(); /* Ensure that the thread is not executing on any core. */ if (m_parent != nullptr) { /* Wait for the thread to not be current on any core. */ for (size_t i = 0; i < cpu::NumCores; ++i) { KThread *core_thread; do { core_thread = Kernel::GetScheduler(i).GetSchedulerCurrentThread(); } while (core_thread == this); } /* Ensure that all cores are synchronized at this point. */ cpu::SynchronizeCores(m_parent->GetPhysicalCoreMask()); } /* Acquire the scheduler lock. */ KScopedSchedulerLock sl; /* Signal. */ m_signaled = true; KSynchronizationObject::NotifyAvailable(); /* Close the thread. */ this->Close(); } void KThread::DoWorkerTaskImpl() { /* Finish the termination that was begun by Exit(). */ this->FinishTermination(); } void KThread::OnEnterUsermodeException() { this->SetUsermodeExceptionSvcPermissions(); this->SetInUsermodeExceptionHandler(); } void KThread::OnLeaveUsermodeException() { this->ClearUsermodeExceptionSvcPermissions(); /* NOTE: InUsermodeExceptionHandler will be cleared by RestoreContext. */ } void KThread::Pin() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Set ourselves as pinned. */ this->GetStackParameters().is_pinned = true; /* Disable core migration. */ MESOSPHERE_ASSERT(m_num_core_migration_disables == 0); { ++m_num_core_migration_disables; /* Save our ideal state to restore when we're unpinned. */ m_original_physical_ideal_core_id = m_physical_ideal_core_id; m_original_physical_affinity_mask = m_physical_affinity_mask; /* Bind ourselves to this core. */ const s32 active_core = this->GetActiveCore(); const s32 current_core = GetCurrentCoreId(); this->SetActiveCore(current_core); m_physical_ideal_core_id = current_core; m_physical_affinity_mask.SetAffinityMask(1ul << current_core); if (active_core != current_core || m_physical_affinity_mask.GetAffinityMask() != m_original_physical_affinity_mask.GetAffinityMask()) { KScheduler::OnThreadAffinityMaskChanged(this, m_original_physical_affinity_mask, active_core); } /* Set base priority-on-unpin. */ const s32 old_base_priority = m_base_priority; m_base_priority_on_unpin = old_base_priority; /* Set base priority to higher than any possible process priority. */ m_base_priority = std::min<s32>(old_base_priority, __builtin_ctzll(this->GetOwnerProcess()->GetPriorityMask()) - 1); RestorePriority(this); } /* Disallow performing thread suspension. */ { /* Update our allow flags. */ m_suspend_allowed_flags &= ~(1 << (util::ToUnderlying(SuspendType_Thread) + util::ToUnderlying(ThreadState_SuspendShift))); /* Update our state. */ this->UpdateState(); } /* Update our SVC access permissions. */ this->SetPinnedSvcPermissions(); } void KThread::Unpin() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Set ourselves as unpinned. */ this->GetStackParameters().is_pinned = false; /* Enable core migration. */ MESOSPHERE_ASSERT(m_num_core_migration_disables == 1); { --m_num_core_migration_disables; /* Restore our original state. */ const KAffinityMask old_mask = m_physical_affinity_mask; m_physical_ideal_core_id = m_original_physical_ideal_core_id; m_physical_affinity_mask = m_original_physical_affinity_mask; if (m_physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { const s32 active_core = this->GetActiveCore(); if (!m_physical_affinity_mask.GetAffinity(active_core)) { if (m_physical_ideal_core_id >= 0) { this->SetActiveCore(m_physical_ideal_core_id); } else { this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(m_physical_affinity_mask.GetAffinityMask())); } } KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); } m_base_priority = m_base_priority_on_unpin; RestorePriority(this); } /* Allow performing thread suspension (if termination hasn't been requested). */ if (!this->IsTerminationRequested()) { /* Update our allow flags. */ m_suspend_allowed_flags |= (1 << (util::ToUnderlying(SuspendType_Thread) + util::ToUnderlying(ThreadState_SuspendShift))); /* Update our state. */ this->UpdateState(); /* Update our SVC access permissions. */ MESOSPHERE_ASSERT(m_parent != nullptr); this->SetUnpinnedSvcPermissions(); } /* Resume any threads that began waiting on us while we were pinned. */ for (auto it = m_pinned_waiter_list.begin(); it != m_pinned_waiter_list.end(); it = m_pinned_waiter_list.erase(it)) { it->EndWait(ResultSuccess()); } } void KThread::DisableCoreMigration() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_num_core_migration_disables >= 0); if ((m_num_core_migration_disables++) == 0) { /* Save our ideal state to restore when we can migrate again. */ m_original_physical_ideal_core_id = m_physical_ideal_core_id; m_original_physical_affinity_mask = m_physical_affinity_mask; /* Bind ourselves to this core. */ const s32 active_core = this->GetActiveCore(); m_physical_ideal_core_id = active_core; m_physical_affinity_mask.SetAffinityMask(1ul << active_core); if (m_physical_affinity_mask.GetAffinityMask() != m_original_physical_affinity_mask.GetAffinityMask()) { KScheduler::OnThreadAffinityMaskChanged(this, m_original_physical_affinity_mask, active_core); } } } void KThread::EnableCoreMigration() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_num_core_migration_disables > 0); if ((--m_num_core_migration_disables) == 0) { const KAffinityMask old_mask = m_physical_affinity_mask; /* Restore our ideals. */ m_physical_ideal_core_id = m_original_physical_ideal_core_id; m_physical_affinity_mask = m_original_physical_affinity_mask; if (m_physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { const s32 active_core = this->GetActiveCore(); if (!m_physical_affinity_mask.GetAffinity(active_core)) { if (m_physical_ideal_core_id >= 0) { this->SetActiveCore(m_physical_ideal_core_id); } else { this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(m_physical_affinity_mask.GetAffinityMask())); } } KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); } } } Result KThread::GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask) { MESOSPHERE_ASSERT_THIS(); { KScopedSchedulerLock sl; /* Get the virtual mask. */ *out_ideal_core = m_virtual_ideal_core_id; *out_affinity_mask = m_virtual_affinity_mask; } R_SUCCEED(); } void KThread::GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask) { MESOSPHERE_ASSERT_THIS(); { KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_num_core_migration_disables >= 0); /* Select between core mask and original core mask. */ if (m_num_core_migration_disables == 0) { *out_ideal_core = m_physical_ideal_core_id; *out_affinity_mask = m_physical_affinity_mask.GetAffinityMask(); } else { *out_ideal_core = m_original_physical_ideal_core_id; *out_affinity_mask = m_original_physical_affinity_mask.GetAffinityMask(); } } } Result KThread::SetCoreMask(int32_t core_id, u64 v_affinity_mask) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(m_parent != nullptr); MESOSPHERE_ASSERT(v_affinity_mask != 0); KScopedLightLock lk(m_activity_pause_lock); /* Set the core mask. */ u64 p_affinity_mask = 0; { KScopedSchedulerLock sl; MESOSPHERE_ASSERT(m_num_core_migration_disables >= 0); /* If we're updating, set our ideal virtual core. */ if (core_id != ams::svc::IdealCoreNoUpdate) { m_virtual_ideal_core_id = core_id; } else { /* Preserve our ideal core id. */ core_id = m_virtual_ideal_core_id; R_UNLESS(((1ul << core_id) & v_affinity_mask) != 0, svc::ResultInvalidCombination()); } /* Set our affinity mask. */ m_virtual_affinity_mask = v_affinity_mask; /* Translate the virtual core to a physical core. */ if (core_id >= 0) { core_id = cpu::VirtualToPhysicalCoreMap[core_id]; } /* Translate the virtual affinity mask to a physical one. */ p_affinity_mask = cpu::ConvertVirtualCoreMaskToPhysical(v_affinity_mask); /* If we haven't disabled migration, perform an affinity change. */ if (m_num_core_migration_disables == 0) { const KAffinityMask old_mask = m_physical_affinity_mask; /* Set our new ideals. */ m_physical_ideal_core_id = core_id; m_physical_affinity_mask.SetAffinityMask(p_affinity_mask); if (m_physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { const s32 active_core = this->GetActiveCore(); if (active_core >= 0 && !m_physical_affinity_mask.GetAffinity(active_core)) { const s32 new_core = m_physical_ideal_core_id >= 0 ? m_physical_ideal_core_id : BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(m_physical_affinity_mask.GetAffinityMask()); this->SetActiveCore(new_core); } KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); } } else { /* Otherwise, we edit the original affinity for restoration later. */ m_original_physical_ideal_core_id = core_id; m_original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); } } /* Update the pinned waiter list. */ ThreadQueueImplForKThreadSetProperty wait_queue(std::addressof(m_pinned_waiter_list)); { bool retry_update; do { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Don't do any further management if our termination has been requested. */ R_SUCCEED_IF(this->IsTerminationRequested()); /* By default, we won't need to retry. */ retry_update = false; /* Check if the thread is currently running. */ bool thread_is_current = false; s32 thread_core; for (thread_core = 0; thread_core < static_cast<s32>(cpu::NumCores); ++thread_core) { if (Kernel::GetScheduler(thread_core).GetSchedulerCurrentThread() == this) { thread_is_current = true; break; } } /* If the thread is currently running, check whether it's no longer allowed under the new mask. */ if (thread_is_current && ((1ul << thread_core) & p_affinity_mask) == 0) { /* If the thread is pinned, we want to wait until it's not pinned. */ if (this->GetStackParameters().is_pinned) { /* Verify that the current thread isn't terminating. */ R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested()); /* Wait until the thread isn't pinned any more. */ m_pinned_waiter_list.push_back(GetCurrentThread()); GetCurrentThread().BeginWait(std::addressof(wait_queue)); } else { /* If the thread isn't pinned, release the scheduler lock and retry until it's not current. */ retry_update = true; } } } while (retry_update); } R_SUCCEED(); } void KThread::SetBasePriority(s32 priority) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority); KScopedSchedulerLock sl; /* Determine the priority value to use. */ const s32 target_priority = m_termination_requested.Load() && priority >= TerminatingThreadPriority ? TerminatingThreadPriority : priority; /* Change our base priority. */ if (this->GetStackParameters().is_pinned) { m_base_priority_on_unpin = target_priority; } else { m_base_priority = target_priority; } /* Perform a priority restoration. */ RestorePriority(this); } void KThread::IncreaseBasePriority(s32 priority) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(!this->GetStackParameters().is_pinned); /* Set our base priority. */ if (m_base_priority > priority) { m_base_priority = priority; /* Perform a priority restoration. */ RestorePriority(this); } } void KThread::SetPriorityToIdle() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; /* Change both our priorities to the idle thread priority. */ const s32 old_priority = m_priority; m_priority = IdleThreadPriority; m_base_priority = IdleThreadPriority; KScheduler::OnThreadPriorityChanged(this, old_priority); } void KThread::RequestSuspend(SuspendType type) { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock lk; /* Note the request in our flags. */ m_suspend_request_flags |= (1u << (util::ToUnderlying(ThreadState_SuspendShift) + util::ToUnderlying(type))); /* Try to perform the suspend. */ this->TrySuspend(); } void KThread::Resume(SuspendType type) { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; /* Clear the request in our flags. */ m_suspend_request_flags &= ~(1u << (util::ToUnderlying(ThreadState_SuspendShift) + util::ToUnderlying(type))); /* Update our state. */ this->UpdateState(); } void KThread::WaitCancel() { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; /* Check if we're waiting and cancellable. */ if (this->GetState() == ThreadState_Waiting && m_cancellable) { m_wait_cancelled = false; m_wait_queue->CancelWait(this, svc::ResultCancelled(), true); } else { /* Otherwise, note that we cancelled a wait. */ m_wait_cancelled = true; } } void KThread::TrySuspend() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(this->IsSuspendRequested()); /* Ensure that we have no waiters. */ if (this->GetNumKernelWaiters() > 0) { return; } MESOSPHERE_ABORT_UNLESS(this->GetNumKernelWaiters() == 0); /* Perform the suspend. */ this->UpdateState(); } void KThread::UpdateState() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Set our suspend flags in state. */ const auto old_state = m_thread_state; const auto new_state = static_cast<ThreadState>(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); m_thread_state = new_state; /* Note the state change in scheduler. */ if (new_state != old_state) { KScheduler::OnThreadStateChanged(this, old_state); } } void KThread::Continue() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Clear our suspend flags in state. */ const auto old_state = m_thread_state; m_thread_state = static_cast<ThreadState>(old_state & ThreadState_Mask); /* Note the state change in scheduler. */ KScheduler::OnThreadStateChanged(this, old_state); } size_t KThread::GetKernelStackUsage() const { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(m_kernel_stack_top != nullptr); #if defined(MESOSPHERE_ENABLE_KERNEL_STACK_USAGE) const u8 *stack = static_cast<const u8 *>(m_kernel_stack_top) - PageSize; size_t i; for (i = 0; i < PageSize; ++i) { if (stack[i] != 0xCC) { break; } } return PageSize - i; #else return 0; #endif } Result KThread::SetActivity(ams::svc::ThreadActivity activity) { /* Lock ourselves. */ KScopedLightLock lk(m_activity_pause_lock); /* Set the activity. */ { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Verify our state. */ const auto cur_state = this->GetState(); R_UNLESS((cur_state == ThreadState_Waiting || cur_state == ThreadState_Runnable), svc::ResultInvalidState()); /* Either pause or resume. */ if (activity == ams::svc::ThreadActivity_Paused) { /* Verify that we're not suspended. */ R_UNLESS(!this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState()); /* Suspend. */ this->RequestSuspend(SuspendType_Thread); } else { MESOSPHERE_ASSERT(activity == ams::svc::ThreadActivity_Runnable); /* Verify that we're suspended. */ R_UNLESS(this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState()); /* Resume. */ this->Resume(SuspendType_Thread); } } /* If the thread is now paused, update the pinned waiter list. */ if (activity == ams::svc::ThreadActivity_Paused) { ThreadQueueImplForKThreadSetProperty wait_queue(std::addressof(m_pinned_waiter_list)); bool thread_is_current; do { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Don't do any further management if our termination has been requested. */ R_SUCCEED_IF(this->IsTerminationRequested()); /* By default, treat the thread as not current. */ thread_is_current = false; /* Check whether the thread is pinned. */ if (this->GetStackParameters().is_pinned) { /* Verify that the current thread isn't terminating. */ R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested()); /* Wait until the thread isn't pinned any more. */ m_pinned_waiter_list.push_back(GetCurrentThread()); GetCurrentThread().BeginWait(std::addressof(wait_queue)); } else { /* Check if the thread is currently running. */ /* If it is, we'll need to retry. */ for (auto i = 0; i < static_cast<s32>(cpu::NumCores); ++i) { if (Kernel::GetScheduler(i).GetSchedulerCurrentThread() == this) { thread_is_current = true; break; } } } } while (thread_is_current); } R_SUCCEED(); } Result KThread::GetThreadContext3(ams::svc::ThreadContext *out) { /* Lock ourselves. */ KScopedLightLock lk(m_activity_pause_lock); /* Get the context. */ { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* Verify that we're suspended. */ R_UNLESS(this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState()); /* If we're not terminating, get the thread's user context. */ if (!this->IsTerminationRequested()) { GetUserContext(out, this); } } R_SUCCEED(); } void KThread::AddHeldLock(LockWithPriorityInheritanceInfo *lock_info) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Set ourselves as the lock's owner. */ lock_info->SetOwner(this); /* Add the lock to our held list. */ m_held_lock_info_list.push_front(*lock_info); } KThread::LockWithPriorityInheritanceInfo *KThread::FindHeldLock(KProcessAddress address_key) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Try to find an existing held lock. */ for (auto &held_lock : m_held_lock_info_list) { if (held_lock.GetAddressKey() == address_key) { return std::addressof(held_lock); } } return nullptr; } void KThread::AddWaiterImpl(KThread *thread) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(thread->GetConditionVariableTree() == nullptr); /* Get the thread's address key. */ const auto address_key = thread->GetAddressKey(); /* Keep track of how many kernel waiters we have. */ if (IsKernelAddressKey(address_key)) { MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters++) >= 0); KScheduler::SetSchedulerUpdateNeeded(); } /* Get the relevant lock info. */ auto *lock_info = this->FindHeldLock(address_key); if (lock_info == nullptr) { /* Create a new lock for the address key. */ lock_info = LockWithPriorityInheritanceInfo::Create(address_key); /* Add the new lock to our list. */ this->AddHeldLock(lock_info); } /* Add the thread as waiter to the lock info. */ lock_info->AddWaiter(thread); } void KThread::RemoveWaiterImpl(KThread *thread) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Keep track of how many kernel waiters we have. */ if (IsKernelAddressKey(thread->GetAddressKey())) { MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters--) > 0); KScheduler::SetSchedulerUpdateNeeded(); } /* Get the info for the lock the thread is waiting on. */ auto *lock_info = thread->GetWaitingLockInfo(); MESOSPHERE_ASSERT(lock_info->GetOwner() == this); /* Remove the waiter. */ if (lock_info->RemoveWaiter(thread)) { m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info)); LockWithPriorityInheritanceInfo::Free(lock_info); } } void KThread::RestorePriority(KThread *thread) { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); while (thread != nullptr) { /* We want to inherit priority where possible. */ s32 new_priority = thread->GetBasePriority(); for (const auto &held_lock : thread->m_held_lock_info_list) { new_priority = std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority()); } /* If the priority we would inherit is not different from ours, don't do anything. */ if (new_priority == thread->GetPriority()) { return; } /* Get the owner of whatever lock this thread is waiting on. */ KThread * const lock_owner = thread->GetLockOwner(); /* If the thread is waiting on some lock, remove it as a waiter to prevent violating red black tree invariants. */ if (lock_owner != nullptr) { lock_owner->RemoveWaiterImpl(thread); } /* Ensure we don't violate condition variable red black tree invariants. */ if (auto *cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { BeforeUpdatePriority(cv_tree, thread); } /* Change the priority. */ const s32 old_priority = thread->GetPriority(); thread->SetPriority(new_priority); /* Restore the condition variable, if relevant. */ if (auto *cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { AfterUpdatePriority(cv_tree, thread); } /* If we removed the thread from some lock's waiting list, add it back. */ if (lock_owner != nullptr) { lock_owner->AddWaiterImpl(thread); } /* Update the scheduler. */ KScheduler::OnThreadPriorityChanged(thread, old_priority); /* Continue inheriting priority. */ thread = lock_owner; } } void KThread::AddWaiter(KThread *thread) { MESOSPHERE_ASSERT_THIS(); this->AddWaiterImpl(thread); /* If the thread has a higher priority than us, we should inherit. */ if (thread->GetPriority() < this->GetPriority()) { RestorePriority(this); } } void KThread::RemoveWaiter(KThread *thread) { MESOSPHERE_ASSERT_THIS(); this->RemoveWaiterImpl(thread); /* If our priority is the same as the thread's (and we've inherited), we may need to restore to lower priority. */ if (this->GetPriority() == thread->GetPriority() && this->GetPriority() < this->GetBasePriority()) { RestorePriority(this); } } KThread *KThread::RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); /* Get the relevant lock info. */ auto *lock_info = this->FindHeldLock(key); if (lock_info == nullptr) { *out_has_waiters = false; return nullptr; } /* Remove the lock info from our held list. */ m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info)); /* Keep track of how many kernel waiters we have. */ if (IsKernelAddressKey(lock_info->GetAddressKey())) { m_num_kernel_waiters -= lock_info->GetWaiterCount(); MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters >= 0); KScheduler::SetSchedulerUpdateNeeded(); } MESOSPHERE_ASSERT(lock_info->GetWaiterCount() > 0); /* Remove the highest priority waiter from the lock to be the next owner. */ KThread *next_lock_owner = lock_info->GetHighestPriorityWaiter(); if (lock_info->RemoveWaiter(next_lock_owner)) { /* The new owner was the only waiter. */ *out_has_waiters = false; /* Free the lock info, since it has no waiters. */ LockWithPriorityInheritanceInfo::Free(lock_info); } else { /* There are additional waiters on the lock. */ *out_has_waiters = true; /* Add the lock to the new owner's held list. */ next_lock_owner->AddHeldLock(lock_info); /* Keep track of any kernel waiters for the new owner. */ if (IsKernelAddressKey(lock_info->GetAddressKey())) { next_lock_owner->m_num_kernel_waiters += lock_info->GetWaiterCount(); MESOSPHERE_ABORT_UNLESS(next_lock_owner->m_num_kernel_waiters > 0); /* NOTE: No need to set scheduler update needed, because we will have already done so when removing earlier. */ } } /* If our priority is the same as the next owner's (and we've inherited), we may need to restore to lower priority. */ if (this->GetPriority() == next_lock_owner->GetPriority() && this->GetPriority() < this->GetBasePriority()) { RestorePriority(this); /* NOTE: No need to restore priority on the next lock owner, because it was already the highest priority waiter on the lock. */ } /* Return the next lock owner. */ return next_lock_owner; } Result KThread::Run() { MESOSPHERE_ASSERT_THIS(); /* If the kernel hasn't finished initializing, then we should suspend. */ if (Kernel::GetState() != Kernel::State::Initialized) { this->RequestSuspend(SuspendType_Init); } while (true) { KScopedSchedulerLock lk; /* If either this thread or the current thread are requesting termination, note it. */ R_UNLESS(!this->IsTerminationRequested(), svc::ResultTerminationRequested()); R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested()); /* Ensure our thread state is correct. */ R_UNLESS(this->GetState() == ThreadState_Initialized, svc::ResultInvalidState()); /* If the current thread has been asked to suspend, suspend it and retry. */ if (GetCurrentThread().IsSuspended()) { GetCurrentThread().UpdateState(); continue; } /* If we're not a kernel thread and we've been asked to suspend, suspend ourselves. */ if (KProcess *parent = this->GetOwnerProcess(); parent != nullptr) { if (this->IsSuspended()) { this->UpdateState(); } parent->IncrementRunningThreadCount(); } /* Open a reference, now that we're running. */ this->Open(); /* Set our state and finish. */ this->SetState(KThread::ThreadState_Runnable); R_SUCCEED(); } } void KThread::Exit() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); /* Call the debug callback. */ KDebug::OnExitThread(this); /* Release the thread resource hint, running thread count from parent. */ if (m_parent != nullptr) { m_parent->ReleaseResource(ams::svc::LimitableResource_ThreadCountMax, 0, 1); m_resource_limit_release_hint = true; m_parent->DecrementRunningThreadCount(); } /* Destroy any dependent objects. */ this->DestroyClosedObjects(); /* Perform termination. */ { KScopedSchedulerLock sl; /* Disallow all suspension. */ m_suspend_allowed_flags = 0; this->UpdateState(); /* Start termination. */ this->StartTermination(); /* Register the thread as a work task. */ KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitThread, this); } MESOSPHERE_PANIC("KThread::Exit() would return"); } Result KThread::Terminate() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this != GetCurrentThreadPointer()); /* Request the thread terminate if it hasn't already. */ if (const auto new_state = this->RequestTerminate(); new_state != ThreadState_Terminated) { /* If the thread isn't terminated, wait for it to terminate. */ s32 index; KSynchronizationObject *objects[] = { this }; R_TRY(KSynchronizationObject::Wait(std::addressof(index), objects, 1, ams::svc::WaitInfinite)); } R_SUCCEED(); } KThread::ThreadState KThread::RequestTerminate() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this != GetCurrentThreadPointer()); KScopedSchedulerLock sl; /* Determine if this is the first termination request. */ const bool first_request = [&]() ALWAYS_INLINE_LAMBDA -> bool { /* Perform an atomic compare-and-swap from false to true. */ bool expected = false; return m_termination_requested.CompareExchangeStrong(expected, true); }(); /* If this is the first request, start termination procedure. */ if (first_request) { /* If the thread is in initialized state, just change state to terminated. */ if (this->GetState() == ThreadState_Initialized) { m_thread_state = ThreadState_Terminated; return ThreadState_Terminated; } /* Register the terminating dpc. */ this->RegisterDpc(DpcFlag_Terminating); /* If the thread is pinned, unpin it. */ if (this->GetStackParameters().is_pinned) { this->GetOwnerProcess()->UnpinThread(this); } /* If the thread is suspended, continue it. */ if (this->IsSuspended()) { m_suspend_allowed_flags = 0; this->UpdateState(); } /* Change the thread's priority to be higher than any system thread's. */ this->IncreaseBasePriority(TerminatingThreadPriority); /* If the thread is runnable, send a termination interrupt to other cores. */ if (this->GetState() == ThreadState_Runnable) { if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask() & ~(1ul << GetCurrentCoreId()); core_mask != 0) { cpu::DataSynchronizationBarrierInnerShareable(); Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_ThreadTerminate, core_mask); } } /* Wake up the thread. */ if (this->GetState() == ThreadState_Waiting) { m_wait_queue->CancelWait(this, svc::ResultTerminationRequested(), true); } } return this->GetState(); } void KThread::Sleep(s64 timeout) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(!KScheduler::IsSchedulerLockedByCurrentThread()); MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); MESOSPHERE_ASSERT(timeout > 0); ThreadQueueImplForKThreadSleep wait_queue; KHardwareTimer *timer; { /* Setup the scheduling lock and sleep. */ KScopedSchedulerLockAndSleep slp(std::addressof(timer), this, timeout); /* Check if the thread should terminate. */ if (this->IsTerminationRequested()) { slp.CancelSleep(); return; } /* Wait for the sleep to end. */ wait_queue.SetHardwareTimer(timer); this->BeginWait(std::addressof(wait_queue)); } } void KThread::BeginWait(KThreadQueue *queue) { /* Set our state as waiting. */ this->SetState(ThreadState_Waiting); /* Set our wait queue. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdangling-pointer" m_wait_queue = queue; #pragma GCC diagnostic pop } void KThread::NotifyAvailable(KSynchronizationObject *signaled_object, Result wait_result) { MESOSPHERE_ASSERT_THIS(); /* Lock the scheduler. */ KScopedSchedulerLock sl; /* If we're waiting, notify our queue that we're available. */ if (this->GetState() == ThreadState_Waiting) { m_wait_queue->NotifyAvailable(this, signaled_object, wait_result); } } void KThread::EndWait(Result wait_result) { MESOSPHERE_ASSERT_THIS(); /* Lock the scheduler. */ KScopedSchedulerLock sl; /* If we're waiting, notify our queue that we're available. */ if (this->GetState() == ThreadState_Waiting) { m_wait_queue->EndWait(this, wait_result); } } void KThread::CancelWait(Result wait_result, bool cancel_timer_task) { MESOSPHERE_ASSERT_THIS(); /* Lock the scheduler. */ KScopedSchedulerLock sl; /* If we're waiting, notify our queue that we're available. */ if (this->GetState() == ThreadState_Waiting) { m_wait_queue->CancelWait(this, wait_result, cancel_timer_task); } } void KThread::SetState(ThreadState state) { MESOSPHERE_ASSERT_THIS(); KScopedSchedulerLock sl; const ThreadState old_state = m_thread_state; m_thread_state = static_cast<ThreadState>((old_state & ~ThreadState_Mask) | (state & ThreadState_Mask)); if (m_thread_state != old_state) { KScheduler::OnThreadStateChanged(this, old_state); } } KThread *KThread::GetThreadFromId(u64 thread_id) { /* Lock the list. */ KThread::ListAccessor accessor; const auto end = accessor.end(); /* Find the object with the right id. */ if (const auto it = accessor.find_key(thread_id); it != end) { /* Try to open the thread. */ if (KThread *thread = static_cast<KThread *>(std::addressof(*it)); AMS_LIKELY(thread->Open())) { MESOSPHERE_ASSERT(thread->GetId() == thread_id); return thread; } } /* We failed to find or couldn't open the thread. */ return nullptr; } Result KThread::GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count) { /* Lock the list. */ KThread::ListAccessor accessor; const auto end = accessor.end(); /* Iterate over the list. */ s32 count = 0; for (auto it = accessor.begin(); it != end; ++it) { /* If we're within array bounds, write the id. */ if (count < max_out_count) { /* Get the thread id. */ KThread *thread = static_cast<KThread *>(std::addressof(*it)); const u64 id = thread->GetId(); /* Copy the id to userland. */ R_TRY(out_thread_ids.CopyArrayElementFrom(std::addressof(id), count)); } /* Increment the count. */ ++count; } /* We successfully iterated the list. */ *out_num_threads = count; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_thread_local_page.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KThreadLocalPage::Initialize(KProcess *process) { MESOSPHERE_ASSERT_THIS(); /* Set that this process owns us. */ m_owner = process; /* Allocate a new page. */ KPageBuffer *page_buf = KPageBuffer::AllocateChecked<PageSize>(); R_UNLESS(page_buf != nullptr, svc::ResultOutOfMemory()); ON_RESULT_FAILURE { KPageBuffer::Free(page_buf); }; /* Map the address in. */ R_RETURN(m_owner->GetPageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, page_buf->GetPhysicalAddress(), KMemoryState_ThreadLocal, KMemoryPermission_UserReadWrite)); } void KThreadLocalPage::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Get the physical address of the page. */ KPhysicalAddress phys_addr = Null<KPhysicalAddress>; MESOSPHERE_ABORT_UNLESS(m_owner->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), this->GetAddress())); /* Unmap the page. */ MESOSPHERE_R_ABORT_UNLESS(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState_ThreadLocal)); /* Free the page. */ KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(phys_addr)); } KProcessAddress KThreadLocalPage::Reserve() { MESOSPHERE_ASSERT_THIS(); for (size_t i = 0; i < util::size(m_is_region_free); i++) { if (m_is_region_free[i]) { m_is_region_free[i] = false; return this->GetRegionAddress(i); } } return Null<KProcessAddress>; } void KThreadLocalPage::Release(KProcessAddress addr) { MESOSPHERE_ASSERT_THIS(); m_is_region_free[this->GetRegionIndex(addr)] = true; } void *KThreadLocalPage::GetPointer() const { MESOSPHERE_ASSERT_THIS(); KPhysicalAddress phys_addr; MESOSPHERE_ABORT_UNLESS(m_owner->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), this->GetAddress())); return static_cast<void *>(KPageBuffer::FromPhysicalAddress(phys_addr)); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_thread_queue.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { void KThreadQueue::NotifyAvailable(KThread *waiting_thread, KSynchronizationObject *signaled_object, Result wait_result) { MESOSPHERE_UNUSED(waiting_thread, signaled_object, wait_result); MESOSPHERE_PANIC("KThreadQueue::NotifyAvailable\n"); } void KThreadQueue::EndWait(KThread *waiting_thread, Result wait_result) { /* Set the thread's wait result. */ waiting_thread->SetWaitResult(wait_result); /* Set the thread as runnable. */ waiting_thread->SetState(KThread::ThreadState_Runnable); /* Clear the thread's wait queue. */ waiting_thread->ClearWaitQueue(); /* Cancel the thread task. */ if (m_hardware_timer != nullptr) { m_hardware_timer->CancelTask(waiting_thread); } } void KThreadQueue::CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) { /* Set the thread's wait result. */ waiting_thread->SetWaitResult(wait_result); /* Set the thread as runnable. */ waiting_thread->SetState(KThread::ThreadState_Runnable); /* Clear the thread's wait queue. */ waiting_thread->ClearWaitQueue(); /* Cancel the thread task. */ if (cancel_timer_task && m_hardware_timer != nullptr) { m_hardware_timer->CancelTask(waiting_thread); } } void KThreadQueueWithoutEndWait::EndWait(KThread *waiting_thread, Result wait_result) { MESOSPHERE_UNUSED(waiting_thread, wait_result); MESOSPHERE_PANIC("KThreadQueueWithoutEndWait::EndWait\n"); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_trace.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { /* Static initializations. */ constinit bool KTrace::s_is_active = false; namespace { constinit KSpinLock g_ktrace_lock; constinit KVirtualAddress g_ktrace_buffer_address = Null<KVirtualAddress>; constinit size_t g_ktrace_buffer_size = 0; constinit u64 g_type_filter = 0; struct KTraceHeader { u32 magic; u32 offset; u32 index; u32 count; static constexpr u32 Magic = util::FourCC<'K','T','R','0'>::Code; }; static_assert(util::is_pod<KTraceHeader>::value); struct KTraceRecord { u8 core_id; u8 type; u16 process_id; u32 thread_id; u64 tick; u64 data[6]; }; static_assert(util::is_pod<KTraceRecord>::value); static_assert(sizeof(KTraceRecord) == 0x40); ALWAYS_INLINE bool IsTypeFiltered(u8 type) { return (g_type_filter & (UINT64_C(1) << (type & (BITSIZEOF(u64) - 1)))) != 0; } } void KTrace::Initialize(KVirtualAddress address, size_t size) { /* Only perform tracing when on development hardware. */ if (KTargetSystem::IsDebugMode()) { const size_t offset = util::AlignUp(sizeof(KTraceHeader), sizeof(KTraceRecord)); if (offset < size) { /* Clear the trace buffer. */ std::memset(GetVoidPointer(address), 0, size); /* Initialize the KTrace header. */ KTraceHeader *header = GetPointer<KTraceHeader>(address); header->magic = KTraceHeader::Magic; header->offset = offset; header->index = 0; header->count = (size - offset) / sizeof(KTraceRecord); /* Set the global data. */ g_ktrace_buffer_address = address; g_ktrace_buffer_size = size; /* Set the filters to defaults. */ g_type_filter = ~(UINT64_C(0)); } } } void KTrace::Start() { if (g_ktrace_buffer_address != Null<KVirtualAddress>) { /* Get exclusive access to the trace buffer. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_ktrace_lock); /* Reset the header. */ KTraceHeader *header = GetPointer<KTraceHeader>(g_ktrace_buffer_address); header->index = 0; /* Reset the records. */ KTraceRecord *records = GetPointer<KTraceRecord>(g_ktrace_buffer_address + header->offset); std::memset(records, 0, sizeof(*records) * header->count); /* Note that we're active. */ s_is_active = true; } } void KTrace::Stop() { if (g_ktrace_buffer_address != Null<KVirtualAddress>) { /* Get exclusive access to the trace buffer. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_ktrace_lock); /* Note that we're paused. */ s_is_active = false; } } void KTrace::PushRecord(u8 type, u64 param0, u64 param1, u64 param2, u64 param3, u64 param4, u64 param5) { /* Get exclusive access to the trace buffer. */ KScopedInterruptDisable di; KScopedSpinLock lk(g_ktrace_lock); /* Check whether we should push the record to the trace buffer. */ if (s_is_active && IsTypeFiltered(type)) { /* Get the current thread and process. */ KThread &cur_thread = GetCurrentThread(); KProcess *cur_process = GetCurrentProcessPointer(); /* Get the current record index from the header. */ KTraceHeader *header = GetPointer<KTraceHeader>(g_ktrace_buffer_address); u32 index = header->index; /* Get the current record. */ KTraceRecord *record = GetPointer<KTraceRecord>(g_ktrace_buffer_address + header->offset + index * sizeof(KTraceRecord)); /* Set the record's data. */ *record = { .core_id = static_cast<u8>(GetCurrentCoreId()), .type = type, .process_id = static_cast<u16>(cur_process != nullptr ? cur_process->GetId() : ~0), .thread_id = static_cast<u32>(cur_thread.GetId()), .tick = static_cast<u64>(KHardwareTimer::GetTick()), .data = { param0, param1, param2, param3, param4, param5 }, }; /* Advance the current index. */ if ((++index) >= header->count) { index = 0; } /* Set the next index. */ header->index = index; } } } ================================================ FILE: libraries/libmesosphere/source/kern_k_transfer_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { Result KTransferMemory::Initialize(KProcessAddress addr, size_t size, ams::svc::MemoryPermission own_perm) { MESOSPHERE_ASSERT_THIS(); /* Set members. */ m_owner = GetCurrentProcessPointer(); /* Get the owner page table. */ auto &page_table = m_owner->GetPageTable(); /* Construct the page group, guarding to make sure our state is valid on exit. */ auto pg_guard = util::ConstructAtGuarded(m_page_group, page_table.GetBlockInfoManager()); /* Lock the memory. */ R_TRY(page_table.LockForTransferMemory(GetPointer(m_page_group), addr, size, ConvertToKMemoryPermission(own_perm))); /* Set remaining tracking members. */ m_owner->Open(); m_owner_perm = own_perm; m_address = addr; m_is_initialized = true; m_is_mapped = false; /* We succeeded. */ pg_guard.Cancel(); R_SUCCEED(); } void KTransferMemory::Finalize() { MESOSPHERE_ASSERT_THIS(); /* Unlock. */ if (!m_is_mapped) { const size_t size = GetReference(m_page_group).GetNumPages() * PageSize; MESOSPHERE_R_ABORT_UNLESS(m_owner->GetPageTable().UnlockForTransferMemory(m_address, size, GetReference(m_page_group))); } /* Close the page group. */ GetReference(m_page_group).Close(); GetReference(m_page_group).Finalize(); } void KTransferMemory::PostDestroy(uintptr_t arg) { KProcess *owner = reinterpret_cast<KProcess *>(arg); owner->ReleaseResource(ams::svc::LimitableResource_TransferMemoryCountMax, 1); owner->Close(); } Result KTransferMemory::Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Validate the permission. */ R_UNLESS(m_owner_perm == map_perm, svc::ResultInvalidState()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Ensure we're not already mapped. */ R_UNLESS(!m_is_mapped, svc::ResultInvalidState()); /* Map the memory. */ const KMemoryState state = (m_owner_perm == ams::svc::MemoryPermission_None) ? KMemoryState_Transfered : KMemoryState_SharedTransfered; R_TRY(GetCurrentProcess().GetPageTable().MapPageGroup(address, GetReference(m_page_group), state, KMemoryPermission_UserReadWrite)); /* Mark ourselves as mapped. */ m_is_mapped = true; R_SUCCEED(); } Result KTransferMemory::Unmap(KProcessAddress address, size_t size) { MESOSPHERE_ASSERT_THIS(); /* Validate the size. */ R_UNLESS(GetReference(m_page_group).GetNumPages() == util::DivideUp(size, PageSize), svc::ResultInvalidSize()); /* Lock ourselves. */ KScopedLightLock lk(m_lock); /* Unmap the memory. */ const KMemoryState state = (m_owner_perm == ams::svc::MemoryPermission_None) ? KMemoryState_Transfered : KMemoryState_SharedTransfered; R_TRY(GetCurrentProcess().GetPageTable().UnmapPageGroup(address, GetReference(m_page_group), state)); /* Mark ourselves as unmapped. */ MESOSPHERE_ASSERT(m_is_mapped); m_is_mapped = false; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_unused_slab_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class KUnusedSlabMemory : public util::IntrusiveRedBlackTreeBaseNode<KUnusedSlabMemory> { NON_COPYABLE(KUnusedSlabMemory); NON_MOVEABLE(KUnusedSlabMemory); private: size_t m_size; public: struct RedBlackKeyType { size_t m_size; constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } }; template<typename T> requires (std::same_as<T, KUnusedSlabMemory> || std::same_as<T, RedBlackKeyType>) static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KUnusedSlabMemory &rhs) { if (lhs.GetSize() < rhs.GetSize()) { return -1; } else { return 1; } } public: KUnusedSlabMemory(size_t size) : m_size(size) { /* ... */ } constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return reinterpret_cast<uintptr_t>(this); } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } }; static_assert(std::is_trivially_destructible<KUnusedSlabMemory>::value); using KUnusedSlabMemoryTree = util::IntrusiveRedBlackTreeBaseTraits<KUnusedSlabMemory>::TreeType<KUnusedSlabMemory>; constinit KLightLock g_unused_slab_memory_lock; constinit KUnusedSlabMemoryTree g_unused_slab_memory_tree; } KVirtualAddress AllocateUnusedSlabMemory(size_t size, size_t alignment) { /* Acquire exclusive access to the memory tree. */ KScopedLightLock lk(g_unused_slab_memory_lock); /* Adjust size and alignment. */ size = std::max(size, sizeof(KUnusedSlabMemory)); alignment = std::max(alignment, alignof(KUnusedSlabMemory)); /* Find the smallest block which fits our allocation. */ KUnusedSlabMemory *best_fit = std::addressof(*g_unused_slab_memory_tree.nfind_key({ size - 1 })); /* Ensure that the chunk is valid. */ size_t prefix_waste; KVirtualAddress alloc_start; KVirtualAddress alloc_last; KVirtualAddress alloc_end; KVirtualAddress chunk_last; KVirtualAddress chunk_end; while (true) { /* Check that we still have a chunk satisfying our size requirement. */ if (AMS_UNLIKELY(best_fit == nullptr)) { return Null<KVirtualAddress>; } /* Determine where the actual allocation would start. */ alloc_start = util::AlignUp(GetInteger(best_fit->GetAddress()), alignment); if (AMS_LIKELY(alloc_start >= best_fit->GetAddress())) { prefix_waste = alloc_start - best_fit->GetAddress(); alloc_end = alloc_start + size; alloc_last = alloc_end - 1; /* Check that the allocation remains in bounds. */ if (alloc_start <= alloc_last) { chunk_end = best_fit->GetAddress() + best_fit->GetSize(); chunk_last = chunk_end - 1; if (AMS_LIKELY(alloc_last <= chunk_last)) { break; } } } /* Check the next smallest block. */ best_fit = best_fit->GetNext(); } /* Remove the chunk we selected from the tree. */ g_unused_slab_memory_tree.erase(g_unused_slab_memory_tree.iterator_to(*best_fit)); std::destroy_at(best_fit); /* If there's enough prefix waste due to alignment for a new chunk, insert it into the tree. */ if (prefix_waste >= sizeof(KUnusedSlabMemory)) { std::construct_at(best_fit, prefix_waste); g_unused_slab_memory_tree.insert(*best_fit); } /* If there's enough suffix waste after the allocation for a new chunk, insert it into the tree. */ if (alloc_last < alloc_end + sizeof(KUnusedSlabMemory) - 1 && alloc_end + sizeof(KUnusedSlabMemory) - 1 <= chunk_last) { KUnusedSlabMemory *suffix_chunk = GetPointer<KUnusedSlabMemory>(alloc_end); std::construct_at(suffix_chunk, chunk_end - alloc_end); g_unused_slab_memory_tree.insert(*suffix_chunk); } /* Return the allocated memory. */ return alloc_start; } void FreeUnusedSlabMemory(KVirtualAddress address, size_t size) { /* NOTE: This is called only during initialization, so we don't need exclusive access. */ /* Nintendo doesn't acquire the lock here, either. */ /* Check that there's anything at all for us to free. */ if (AMS_UNLIKELY(size == 0)) { return; } /* Determine the start of the block. */ const KVirtualAddress block_start = util::AlignUp(GetInteger(address), alignof(KUnusedSlabMemory)); /* Check that there's space for a KUnusedSlabMemory to exist. */ if (AMS_UNLIKELY(std::numeric_limits<uintptr_t>::max() - sizeof(KUnusedSlabMemory) < GetInteger(block_start))) { return; } /* Determine the end of the block region. */ const KVirtualAddress block_end = util::AlignDown(GetInteger(address) + size, alignof(KUnusedSlabMemory)); /* Check that the block remains within bounds. */ if (AMS_UNLIKELY(block_start + sizeof(KUnusedSlabMemory) - 1 > block_end - 1)){ return; } /* Create the block. */ KUnusedSlabMemory *block = GetPointer<KUnusedSlabMemory>(block_start); std::construct_at(block, GetInteger(block_end) - GetInteger(block_start)); /* Insert the block into the tree. */ g_unused_slab_memory_tree.insert(*block); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_wait_object.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class ThreadQueueImplForKWaitObjectSynchronize final : public KThreadQueueWithoutEndWait { private: KThread::WaiterList *m_wait_list; KThread **m_thread; public: constexpr ThreadQueueImplForKWaitObjectSynchronize(KThread::WaiterList *wl, KThread **t) : KThreadQueueWithoutEndWait(), m_wait_list(wl), m_thread(t) { /* ... */ } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { /* Remove the thread from the wait list. */ m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); /* If the result was a timeout and the thread is our wait object thread, cancel recursively. */ if (svc::ResultTimedOut::Includes(wait_result) && waiting_thread == *m_thread) { for (auto &thread : *m_wait_list) { thread.CancelWait(svc::ResultTimedOut(), false); } } /* If the thread is our wait object thread, clear it. */ if (*m_thread == waiting_thread) { *m_thread = nullptr; } /* Invoke the base cancel wait handler. */ KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); } }; } Result KWaitObject::Synchronize(s64 timeout) { /* Perform the wait. */ KHardwareTimer *timer; KThread *cur_thread = GetCurrentThreadPointer(); ThreadQueueImplForKWaitObjectSynchronize wait_queue(std::addressof(m_wait_list), std::addressof(m_next_thread)); { KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout); /* Check that the thread isn't terminating. */ if (cur_thread->IsTerminationRequested()) { slp.CancelSleep(); R_THROW(svc::ResultTerminationRequested()); } /* Handle the case where timeout is non-negative/infinite. */ if (timeout >= 0) { /* Check if we're already waiting. */ if (m_next_thread != nullptr) { slp.CancelSleep(); R_THROW(svc::ResultBusy()); } /* If timeout is zero, handle the special case by canceling all waiting threads. */ if (timeout == 0) { for (auto &thread : m_wait_list) { thread.CancelWait(svc::ResultTimedOut(), false); } slp.CancelSleep(); R_SUCCEED(); } } /* If the timeout isn't infinite, register it as our next timeout. */ if (timeout > 0) { wait_queue.SetHardwareTimer(timer); m_next_thread = cur_thread; } /* Add the current thread to our wait list. */ m_wait_list.push_back(*cur_thread); /* Wait until the timeout occurs. */ cur_thread->BeginWait(std::addressof(wait_queue)); } R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/kern_k_worker_task_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { class ThreadQueueImplForKWorkerTaskManager final : public KThreadQueue { private: KThread **m_waiting_thread; public: constexpr ThreadQueueImplForKWorkerTaskManager(KThread **t) : KThreadQueue(), m_waiting_thread(t) { /* ... */ } virtual void EndWait(KThread *waiting_thread, Result wait_result) override { /* Clear our waiting thread. */ *m_waiting_thread = nullptr; /* Invoke the base end wait handler. */ KThreadQueue::EndWait(waiting_thread, wait_result); } virtual void CancelWait(KThread *waiting_thread, Result wait_result, bool cancel_timer_task) override { MESOSPHERE_UNUSED(waiting_thread, wait_result, cancel_timer_task); MESOSPHERE_PANIC("ThreadQueueImplForKWorkerTaskManager::CancelWait\n"); } }; } void KWorkerTask::DoWorkerTask() { if (auto * const thread = this->DynamicCast<KThread *>(); thread != nullptr) { return thread->DoWorkerTaskImpl(); } else { auto * const process = this->DynamicCast<KProcess *>(); MESOSPHERE_ABORT_UNLESS(process != nullptr); return process->DoWorkerTaskImpl(); } } void KWorkerTaskManager::Initialize(s32 priority) { /* Reserve a thread from the system limit. */ MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_ThreadCountMax, 1)); /* Create a new thread. */ KThread *thread = KThread::Create(); MESOSPHERE_ABORT_UNLESS(thread != nullptr); /* Launch the new thread. */ MESOSPHERE_R_ABORT_UNLESS(KThread::InitializeKernelThread(thread, ThreadFunction, reinterpret_cast<uintptr_t>(this), priority, cpu::NumCores - 1)); /* Register the new thread. */ KThread::Register(thread); /* Run the thread. */ MESOSPHERE_R_ABORT_UNLESS(thread->Run()); } void KWorkerTaskManager::AddTask(WorkerType type, KWorkerTask *task) { MESOSPHERE_ASSERT(type <= WorkerType_Count); Kernel::GetWorkerTaskManager(type).AddTask(task); } void KWorkerTaskManager::ThreadFunction(uintptr_t arg) { reinterpret_cast<KWorkerTaskManager *>(arg)->ThreadFunctionImpl(); } void KWorkerTaskManager::ThreadFunctionImpl() { /* Create wait queue. */ ThreadQueueImplForKWorkerTaskManager wait_queue(std::addressof(m_waiting_thread)); while (true) { KWorkerTask *task; /* Get a worker task. */ { KScopedSchedulerLock sl; task = this->GetTask(); if (task == nullptr) { /* Wait to have a task. */ m_waiting_thread = GetCurrentThreadPointer(); GetCurrentThread().BeginWait(std::addressof(wait_queue)); continue; } } /* Do the task. */ task->DoWorkerTask(); /* Destroy any objects we may need to close. */ GetCurrentThread().DestroyClosedObjects(); } } KWorkerTask *KWorkerTaskManager::GetTask() { MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); KWorkerTask *next = m_head_task; if (next != nullptr) { /* Advance the list. */ if (m_head_task == m_tail_task) { m_head_task = nullptr; m_tail_task = nullptr; } else { m_head_task = m_head_task->GetNextTask(); } /* Clear the next task's next. */ next->SetNextTask(nullptr); } return next; } void KWorkerTaskManager::AddTask(KWorkerTask *task) { KScopedSchedulerLock sl; MESOSPHERE_ASSERT(task->GetNextTask() == nullptr); /* Insert the task. */ if (m_tail_task) { m_tail_task->SetNextTask(task); m_tail_task = task; } else { m_head_task = task; m_tail_task = task; /* Make ourselves active if we need to. */ if (m_waiting_thread != nullptr) { m_waiting_thread->EndWait(ResultSuccess()); } } } } ================================================ FILE: libraries/libmesosphere/source/kern_kernel.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { KDynamicPageManager g_resource_manager_page_manager; template<typename T> ALWAYS_INLINE void PrintMemoryRegion(const char *prefix, const T &extents) { static_assert(std::is_same<decltype(extents.GetAddress()), uintptr_t>::value); static_assert(std::is_same<decltype(extents.GetLastAddress()), uintptr_t>::value); if constexpr (std::is_same<uintptr_t, unsigned int>::value) { MESOSPHERE_LOG("%-24s0x%08x - 0x%08x\n", prefix, extents.GetAddress(), extents.GetLastAddress()); } else if constexpr (std::is_same<uintptr_t, unsigned long>::value) { MESOSPHERE_LOG("%-24s0x%016lx - 0x%016lx\n", prefix, extents.GetAddress(), extents.GetLastAddress()); } else if constexpr (std::is_same<uintptr_t, unsigned long long>::value) { MESOSPHERE_LOG("%-24s0x%016llx - 0x%016llx\n", prefix, extents.GetAddress(), extents.GetLastAddress()); } else { static_assert(!std::is_same<T, T>::value, "Unknown uintptr_t width!"); } } } void Kernel::InitializeCoreLocalRegion(s32 core_id) { /* The core local region no longer exists, so just clear the current thread. */ AMS_UNUSED(core_id); SetCurrentThread(nullptr); } void Kernel::InitializeMainAndIdleThreads(s32 core_id) { /* This function wants to setup the main thread and the idle thread. */ KThread *main_thread = std::addressof(Kernel::GetMainThread(core_id)); void *main_thread_stack = GetVoidPointer(KMemoryLayout::GetMainStackTopAddress(core_id)); KThread *idle_thread = std::addressof(Kernel::GetIdleThread(core_id)); void *idle_thread_stack = GetVoidPointer(KMemoryLayout::GetIdleStackTopAddress(core_id)); KAutoObject::Create<KThread>(main_thread); KAutoObject::Create<KThread>(idle_thread); MESOSPHERE_R_ABORT_UNLESS(main_thread->Initialize(nullptr, 0, main_thread_stack, 0, KThread::MainThreadPriority, core_id, nullptr, KThread::ThreadType_Main)); MESOSPHERE_R_ABORT_UNLESS(idle_thread->Initialize(nullptr, 0, idle_thread_stack, 0, KThread::IdleThreadPriority, core_id, nullptr, KThread::ThreadType_Main)); /* Set the current thread to be the main thread, and we have no processes running yet. */ SetCurrentThread(main_thread); /* Initialize the interrupt manager, hardware timer, and scheduler */ GetInterruptManager().Initialize(core_id); GetHardwareTimer().Initialize(); GetScheduler().Initialize(idle_thread); } void Kernel::InitializeResourceManagers(KVirtualAddress address, size_t size) { /* Ensure that the buffer is suitable for our use. */ MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(address), PageSize)); MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize)); /* Ensure that we have space for our reference counts. */ const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(size), PageSize); MESOSPHERE_ABORT_UNLESS(rc_size < size); size -= rc_size; /* Determine dynamic page managers. */ KDynamicPageManager * const app_dynamic_page_manager = nullptr; KDynamicPageManager * const sys_dynamic_page_manager = KTargetSystem::IsDynamicResourceLimitsEnabled() ? std::addressof(g_resource_manager_page_manager) : nullptr; /* Initialize the resource managers' shared page manager. */ MESOSPHERE_R_ABORT_UNLESS(g_resource_manager_page_manager.Initialize(address, size, std::max<size_t>(PageSize, KPageBufferSlabHeap::BufferSize))); /* Initialize the KPageBuffer slab heap. */ KPageBuffer::InitializeSlabHeap(g_resource_manager_page_manager); /* Initialize the block info heap. */ s_block_info_heap.Initialize(std::addressof(g_resource_manager_page_manager), BlockInfoSlabHeapSize); /* Initialize the system slab managers. */ s_sys_block_info_manager.Initialize(sys_dynamic_page_manager, std::addressof(s_block_info_heap)); s_sys_memory_block_heap.Initialize(std::addressof(g_resource_manager_page_manager), SystemMemoryBlockSlabHeapSize); s_sys_memory_block_manager.Initialize(sys_dynamic_page_manager, std::addressof(s_sys_memory_block_heap)); /* Initialize the application slab managers. */ s_app_block_info_manager.Initialize(app_dynamic_page_manager, std::addressof(s_block_info_heap)); s_app_memory_block_heap.Initialize(std::addressof(g_resource_manager_page_manager), ApplicationMemoryBlockSlabHeapSize); s_app_memory_block_manager.Initialize(app_dynamic_page_manager, std::addressof(s_app_memory_block_heap)); /* Reserve all but a fixed number of remaining pages for the page table heap. */ const size_t num_pt_pages = g_resource_manager_page_manager.GetCount() - g_resource_manager_page_manager.GetUsed() - ReservedDynamicPageCount; s_page_table_heap.Initialize(std::addressof(g_resource_manager_page_manager), num_pt_pages, GetPointer<KPageTableManager::RefCount>(address + size)); /* Create and initialize the system system resource. */ s_sys_page_table_manager.Initialize(sys_dynamic_page_manager, std::addressof(s_page_table_heap)); KAutoObject::Create<KSystemResource>(std::addressof(s_sys_system_resource)); s_sys_system_resource.SetManagers(s_sys_memory_block_manager, s_sys_block_info_manager, s_sys_page_table_manager); /* Create and initialize the application system resource. */ s_app_page_table_manager.Initialize(app_dynamic_page_manager, std::addressof(s_page_table_heap)); KAutoObject::Create<KSystemResource>(std::addressof(s_app_system_resource)); s_app_system_resource.SetManagers(s_app_memory_block_manager, s_app_block_info_manager, s_app_page_table_manager); /* Check that we have the correct number of dynamic pages available. */ MESOSPHERE_ABORT_UNLESS(g_resource_manager_page_manager.GetCount() - g_resource_manager_page_manager.GetUsed() == ReservedDynamicPageCount); } void Kernel::PrintLayout() { const auto target_fw = kern::GetTargetFirmware(); /* Print out the kernel version. */ MESOSPHERE_LOG("Horizon Kernel (Mesosphere)\n"); MESOSPHERE_LOG("Built: %s %s\n", __DATE__, __TIME__); MESOSPHERE_LOG("Atmosphere version: %d.%d.%d-%s\n", ATMOSPHERE_RELEASE_VERSION, ATMOSPHERE_GIT_REVISION); MESOSPHERE_LOG("Target Firmware: %d.%d.%d\n", (target_fw >> 24) & 0xFF, (target_fw >> 16) & 0xFF, (target_fw >> 8) & 0xFF); MESOSPHERE_LOG("Supported OS version: %d.%d.%d\n", ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR, ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR, ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO); MESOSPHERE_LOG("\n"); /* Print relative memory usage. */ const auto [total, kernel] = KMemoryLayout::GetTotalAndKernelMemorySizes(); MESOSPHERE_LOG("Kernel Memory Usage: %zu/%zu MB\n", util::AlignUp(kernel, 1_MB) / 1_MB, util::AlignUp(total, 1_MB) / 1_MB); MESOSPHERE_LOG("\n"); /* Print out important memory layout regions. */ MESOSPHERE_LOG("Virtual Memory Layout\n"); PrintMemoryRegion(" KernelRegion", KMemoryLayout::GetKernelRegionExtents()); PrintMemoryRegion(" Code", KMemoryLayout::GetKernelCodeRegionExtents()); PrintMemoryRegion(" Stack", KMemoryLayout::GetKernelStackRegionExtents()); PrintMemoryRegion(" Misc", KMemoryLayout::GetKernelMiscRegionExtents()); PrintMemoryRegion(" Slab", KMemoryLayout::GetKernelSlabRegionExtents()); PrintMemoryRegion(" LinearRegion", KMemoryLayout::GetLinearRegionVirtualExtents()); MESOSPHERE_LOG("\n"); MESOSPHERE_LOG("Physical Memory Layout\n"); PrintMemoryRegion(" LinearRegion", KMemoryLayout::GetLinearRegionPhysicalExtents()); PrintMemoryRegion(" CarveoutRegion", KMemoryLayout::GetCarveoutRegionExtents()); MESOSPHERE_LOG("\n"); PrintMemoryRegion(" KernelRegion", KMemoryLayout::GetKernelRegionPhysicalExtents()); PrintMemoryRegion(" Code", KMemoryLayout::GetKernelCodeRegionPhysicalExtents()); PrintMemoryRegion(" Slab", KMemoryLayout::GetKernelSlabRegionPhysicalExtents()); if constexpr (KSystemControl::SecureAppletMemorySize > 0) { PrintMemoryRegion(" SecureApplet", KMemoryLayout::GetKernelSecureAppletMemoryRegionPhysicalExtents()); } PrintMemoryRegion(" PageTableHeap", KMemoryLayout::GetKernelPageTableHeapRegionPhysicalExtents()); PrintMemoryRegion(" InitPageTable", KMemoryLayout::GetKernelInitPageTableRegionPhysicalExtents()); if constexpr (IsKTraceEnabled) { MESOSPHERE_LOG(" DebugRegion\n"); PrintMemoryRegion(" Trace Buffer", KMemoryLayout::GetKernelTraceBufferRegionPhysicalExtents()); } PrintMemoryRegion(" MemoryPoolRegion", KMemoryLayout::GetKernelPoolPartitionRegionPhysicalExtents()); if (GetTargetFirmware() >= TargetFirmware_5_0_0) { PrintMemoryRegion(" Management", KMemoryLayout::GetKernelPoolManagementRegionPhysicalExtents()); PrintMemoryRegion(" System", KMemoryLayout::GetKernelSystemPoolRegionPhysicalExtents()); if (KMemoryLayout::HasKernelSystemNonSecurePoolRegion()) { PrintMemoryRegion(" SystemUnsafe", KMemoryLayout::GetKernelSystemNonSecurePoolRegionPhysicalExtents()); } if (KMemoryLayout::HasKernelAppletPoolRegion()) { PrintMemoryRegion(" Applet", KMemoryLayout::GetKernelAppletPoolRegionPhysicalExtents()); } if (KMemoryLayout::HasKernelApplicationPoolRegion()) { PrintMemoryRegion(" Application", KMemoryLayout::GetKernelApplicationPoolRegionPhysicalExtents()); } } else { PrintMemoryRegion(" Management", KMemoryLayout::GetKernelPoolManagementRegionPhysicalExtents()); PrintMemoryRegion(" Secure", KMemoryLayout::GetKernelSystemPoolRegionPhysicalExtents()); PrintMemoryRegion(" Unsafe", KMemoryLayout::GetKernelApplicationPoolRegionPhysicalExtents()); } MESOSPHERE_LOG("\n"); } } ================================================ FILE: libraries/libmesosphere/source/kern_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern { namespace { template<typename F> ALWAYS_INLINE void DoOnEachCoreInOrder(s32 core_id, F f) { cpu::SynchronizeAllCores(); for (size_t i = 0; i < cpu::NumCores; i++) { if (static_cast<s32>(i) == core_id) { f(); } cpu::SynchronizeAllCores(); } } } NORETURN void HorizonKernelMain(s32 core_id) { /* Setup the Core Local Region, and note that we're initializing. */ Kernel::InitializeCoreLocalRegion(core_id); Kernel::SetState(Kernel::State::Initializing); /* Ensure that all cores get to this point before proceeding. */ cpu::SynchronizeAllCores(); /* Initialize the main and idle thread for each core. */ DoOnEachCoreInOrder(core_id, [=]() ALWAYS_INLINE_LAMBDA { Kernel::InitializeMainAndIdleThreads(core_id); }); if (core_id == 0) { /* Initialize the carveout and the system resource limit. */ KSystemControl::InitializePhase1(); /* Synchronize all cores before proceeding, to ensure access to the global rng is consistent. */ cpu::SynchronizeAllCores(); /* Initialize the memory manager and the KPageBuffer slabheap. */ { const auto &management_region = KMemoryLayout::GetPoolManagementRegion(); MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0); static_assert(util::size(MinimumMemoryManagerAlignmentShifts) == KMemoryManager::Pool_Count); Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize(), MinimumMemoryManagerAlignmentShifts); } /* Copy the Initial Process Binary to safe memory. */ CopyInitialProcessBinaryToKernelMemory(); /* Print out information about the kernel. */ Kernel::PrintLayout(); /* Initialize the KObject Slab Heaps. */ init::InitializeSlabHeaps(); /* Initialize the Dynamic Slab Heaps. */ { const auto &pt_heap_region = KMemoryLayout::GetPageTableHeapRegion(); MESOSPHERE_ABORT_UNLESS(pt_heap_region.GetEndAddress() != 0); Kernel::InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize()); } } else { /* Synchronize all cores before proceeding, to ensure access to the global rng is consistent. */ cpu::SynchronizeAllCores(); } /* Initialize the supervisor page table for each core. */ DoOnEachCoreInOrder(core_id, [=]() ALWAYS_INLINE_LAMBDA { KPageTable::Initialize(core_id); Kernel::GetKernelPageTable().Initialize(core_id); }); /* Activate the supervisor page table for each core. */ DoOnEachCoreInOrder(core_id, [=]() ALWAYS_INLINE_LAMBDA { Kernel::GetKernelPageTable().ActivateForInit(); }); /* NOTE: Kernel calls on each core a nullsub here on retail kernel. */ /* Register the main/idle threads and initialize the interrupt task manager. */ DoOnEachCoreInOrder(core_id, [=]() ALWAYS_INLINE_LAMBDA { KThread::Register(std::addressof(Kernel::GetMainThread(core_id))); KThread::Register(std::addressof(Kernel::GetIdleThread(core_id))); }); /* Activate the scheduler and enable interrupts. */ DoOnEachCoreInOrder(core_id, [=]() ALWAYS_INLINE_LAMBDA { Kernel::GetScheduler().Activate(); KInterruptManager::EnableInterrupts(); }); /* Initialize cpu interrupt threads. */ cpu::InitializeInterruptThreads(core_id); /* Initialize the DPC manager. */ KDpcManager::Initialize(); cpu::SynchronizeAllCores(); /* Perform more core-0 specific initialization. */ if (core_id == 0) { /* Initialize the exit worker managers, so that threads and processes may exit cleanly. */ Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_ExitThread).Initialize(KWorkerTaskManager::ExitWorkerPriority); Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_ExitProcess).Initialize(KWorkerTaskManager::ExitWorkerPriority); /* Setup so that we may sleep later, and reserve memory for secure applets. */ KSystemControl::InitializePhase2(); /* Initialize the SMMU. */ KDeviceAddressSpace::Initialize(); /* Load the initial processes. */ CreateAndRunInitialProcesses(); /* We're done initializing! */ Kernel::SetState(Kernel::State::Initialized); /* Resume all threads suspended while we initialized. */ KThread::ResumeThreadsSuspendedForInit(); /* Validate that all reserved dram blocks are valid. */ for (const auto ®ion : KMemoryLayout::GetPhysicalMemoryRegionTree()) { if (region.IsDerivedFrom(KMemoryRegionType_DramReservedBase)) { MESOSPHERE_ABORT_UNLESS(region.GetEndAddress() != 0); } } } cpu::SynchronizeAllCores(); /* Set the current thread priority to idle. */ GetCurrentThread().SetPriorityToIdle(); /* Exit the main thread. */ { auto &main_thread = Kernel::GetMainThread(core_id); main_thread.Open(); main_thread.Exit(); } /* Main() is done, and we should never get to this point. */ MESOSPHERE_PANIC("Main Thread continued after exit."); AMS_INFINITE_LOOP(); } } ================================================ FILE: libraries/libmesosphere/source/kern_panic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> extern "C" void _start(); namespace ams::result::impl { NORETURN void OnResultAssertion(Result result) { MESOSPHERE_PANIC("OnResultAssertion(2%03d-%04d)", result.GetModule(), result.GetDescription()); } } namespace ams::kern { /* NOTE: This is not exposed via a header, but is referenced via assembly. */ /* NOTE: Nintendo does not save register contents on panic; we use this */ /* to generate an atmosphere fatal report on panic. */ constinit KExceptionContext g_panic_exception_contexts[cpu::NumCores]; namespace { constexpr std::array<s32, cpu::NumCores> NegativeArray = [] { std::array<s32, cpu::NumCores> arr = {}; for (size_t i = 0; i < arr.size(); i++) { arr[i] = -1; } return arr; }(); constinit util::Atomic<s32> g_next_ticket = 0; constinit util::Atomic<s32> g_current_ticket = 0; constinit std::array<s32, cpu::NumCores> g_core_tickets = NegativeArray; s32 GetCoreTicket() { const s32 core_id = GetCurrentCoreId(); if (g_core_tickets[core_id] == -1) { g_core_tickets[core_id] = 2 * (g_next_ticket++); } return g_core_tickets[core_id]; } void WaitCoreTicket() { const s32 expected = GetCoreTicket(); const s32 desired = expected + 1; s32 compare = g_current_ticket.Load<std::memory_order_relaxed>(); do { if (compare == desired) { break; } compare = expected; } while (!g_current_ticket.CompareExchangeWeak(compare, desired)); } void ReleaseCoreTicket() { const s32 expected = GetCoreTicket() + 1; const s32 desired = expected + 1; s32 compare = expected; g_current_ticket.CompareExchangeStrong(compare, desired); } ALWAYS_INLINE KExceptionContext *GetPanicExceptionContext(int core_id) { #if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP) return std::addressof(g_panic_exception_contexts[core_id]); #else return nullptr; #endif } [[gnu::unused]] void PrintCurrentState() { /* Wait for it to be our turn to print. */ WaitCoreTicket(); /* Get the current exception context. */ const s32 core_id = GetCurrentCoreId(); const auto *core_ctx = GetPanicExceptionContext(core_id); /* Print the state. */ MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id); /* Print kernel state. */ #ifdef ATMOSPHERE_ARCH_ARM64 MESOSPHERE_RELEASE_LOG("Kernel Registers:\n"); for (size_t i = 0; i < 31; i++) { MESOSPHERE_RELEASE_LOG(" X[%02zu] = %016lx\n", i, core_ctx->x[i]); } MESOSPHERE_RELEASE_LOG(" SP = %016lx\n", core_ctx->sp); /* Print kernel backtrace. */ MESOSPHERE_RELEASE_LOG("Kernel Backtrace:\n"); uintptr_t fp = core_ctx != nullptr ? core_ctx->x[29] : reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) { struct { uintptr_t fp; uintptr_t lr; } *stack_frame = reinterpret_cast<decltype(stack_frame)>(fp); MESOSPHERE_RELEASE_LOG(" [%02zx]: %p\n", i, reinterpret_cast<void *>(stack_frame->lr)); fp = stack_frame->fp; } #endif /* Print registers and user backtrace. */ KDebug::PrintRegister(); KDebug::PrintBacktrace(); MESOSPHERE_RELEASE_LOG("\n"); /* Allow the next core to print. */ ReleaseCoreTicket(); } NORETURN void StopSystem() { #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING /* Print the current core. */ PrintCurrentState(); #endif KSystemControl::StopSystem(GetPanicExceptionContext(GetCurrentCoreId())); } } NORETURN WEAK_SYMBOL void PanicImpl(const char *file, int line, const char *format, ...) { #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING /* Wait for it to be our turn to print. */ WaitCoreTicket(); ::std::va_list vl; va_start(vl, format); MESOSPHERE_RELEASE_LOG("Core[%d]: Kernel Panic at %s:%d\n", GetCurrentCoreId(), file, line); if (KProcess *cur_process = GetCurrentProcessPointer(); cur_process != nullptr) { MESOSPHERE_RELEASE_LOG("Core[%d]: Current Process: %s\n", GetCurrentCoreId(), cur_process->GetName()); } MESOSPHERE_RELEASE_VLOG(format, vl); MESOSPHERE_RELEASE_LOG("\n"); va_end(vl); #else MESOSPHERE_UNUSED(file, line, format); #endif StopSystem(); } NORETURN WEAK_SYMBOL void PanicImpl() { StopSystem(); } } ================================================ FILE: libraries/libmesosphere/source/libc/kern_cxx.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #ifdef __cplusplus extern "C" { #endif /* cxx implementation details to be stubbed here, as needed. */ void __cxa_pure_virtual() { MESOSPHERE_PANIC("pure virtual function call"); } #ifdef __cplusplus } /* extern "C" */ #endif ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_activity.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidThreadActivity(ams::svc::ThreadActivity thread_activity) { switch (thread_activity) { case ams::svc::ThreadActivity_Runnable: case ams::svc::ThreadActivity_Paused: return true; default: return false; } } constexpr bool IsValidProcessActivity(ams::svc::ProcessActivity process_activity) { switch (process_activity) { case ams::svc::ProcessActivity_Runnable: case ams::svc::ProcessActivity_Paused: return true; default: return false; } } Result SetThreadActivity(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { /* Validate the activity. */ R_UNLESS(IsValidThreadActivity(thread_activity), svc::ResultInvalidEnumValue()); /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Check that the activity is being set on a non-current thread for the current process. */ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(), svc::ResultBusy()); /* Set the activity. */ R_TRY(thread->SetActivity(thread_activity)); R_SUCCEED(); } Result SetProcessActivity(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { /* Validate the activity. */ R_UNLESS(IsValidProcessActivity(process_activity), svc::ResultInvalidEnumValue()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Check that the activity isn't being set on the current process. */ R_UNLESS(process.GetPointerUnsafe() != GetCurrentProcessPointer(), svc::ResultBusy()); /* Set the activity. */ R_TRY(process->SetActivity(process_activity)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result SetThreadActivity64(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { R_RETURN(SetThreadActivity(thread_handle, thread_activity)); } Result SetProcessActivity64(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { R_RETURN(SetProcessActivity(process_handle, process_activity)); } /* ============================= 64From32 ABI ============================= */ Result SetThreadActivity64From32(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { R_RETURN(SetThreadActivity(thread_handle, thread_activity)); } Result SetProcessActivity64From32(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { R_RETURN(SetProcessActivity(process_handle, process_activity)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_address_arbiter.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsKernelAddress(uintptr_t address) { return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; } constexpr bool IsValidSignalType(ams::svc::SignalType type) { switch (type) { case ams::svc::SignalType_Signal: case ams::svc::SignalType_SignalAndIncrementIfEqual: case ams::svc::SignalType_SignalAndModifyByWaitingCountIfEqual: return true; default: return false; } } constexpr bool IsValidArbitrationType(ams::svc::ArbitrationType type) { switch (type) { case ams::svc::ArbitrationType_WaitIfLessThan: case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan: case ams::svc::ArbitrationType_WaitIfEqual: case ams::svc::ArbitrationType_WaitIfEqual64: return true; default: return false; } } Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { /* Validate input. */ R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) { R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress()); } else { R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); } R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue()); /* Convert timeout from nanoseconds to ticks. */ s64 timeout; if (timeout_ns > 0) { const ams::svc::Tick offset_tick(TimeSpan::FromNanoSeconds(timeout_ns)); if (AMS_LIKELY(offset_tick > 0)) { timeout = KHardwareTimer::GetTick() + offset_tick + 2; if (AMS_UNLIKELY(timeout <= 0)) { timeout = std::numeric_limits<s64>::max(); } } else { timeout = std::numeric_limits<s64>::max(); } } else { timeout = timeout_ns; } R_RETURN(GetCurrentProcess().WaitAddressArbiter(address, arb_type, value, timeout)); } Result SignalToAddress(uintptr_t address, ams::svc::SignalType signal_type, int32_t value, int32_t count) { /* Validate input. */ R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); R_UNLESS(IsValidSignalType(signal_type), svc::ResultInvalidEnumValue()); R_RETURN(GetCurrentProcess().SignalAddressArbiter(address, signal_type, value, count)); } } /* ============================= 64 ABI ============================= */ Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns)); } Result SignalToAddress64(ams::svc::Address address, ams::svc::SignalType signal_type, int32_t value, int32_t count) { R_RETURN(SignalToAddress(address, signal_type, value, count)); } /* ============================= 64From32 ABI ============================= */ Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns)); } Result SignalToAddress64From32(ams::svc::Address address, ams::svc::SignalType signal_type, int32_t value, int32_t count) { R_RETURN(SignalToAddress(address, signal_type, value, count)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_address_translation.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out_info, uintptr_t address) { /* NOTE: In 10.0.0, Nintendo stubbed this SVC. Should we do so? */ /* R_UNLESS(GetTargetFirmware() < TargetFirmware_10_0_0, svc::ResultInvalidCurrentMemory()); */ /* Get reference to page table. */ auto &pt = GetCurrentProcess().GetPageTable(); /* Check that the address is valid. */ R_UNLESS(pt.Contains(address, 1), svc::ResultInvalidCurrentMemory()); /* Query the physical mapping. */ R_TRY(pt.QueryPhysicalAddress(out_info, address)); R_SUCCEED(); } Result QueryMemoryMapping(uintptr_t *out_address, size_t *out_size, uint64_t phys_addr, size_t size) { /* Declare variables we'll populate. */ KProcessAddress found_address = Null<KProcessAddress>; size_t found_size = 0; /* Get reference to page table. */ auto &pt = GetCurrentProcess().GetPageTable(); /* Check whether the address is aligned. */ const bool aligned = util::IsAligned(phys_addr, PageSize); auto QueryMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result { /* The size must be non-zero. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); /* The request must not overflow. */ R_UNLESS((phys_addr < phys_addr + size), svc::ResultNotFound()); /* Query the mapping. */ R_TRY_CATCH(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size)) { R_CATCH(svc::ResultNotFound) { /* If we failed to find an io mapping, check if the address is a static mapping. */ R_TRY(pt.QueryStaticMapping(std::addressof(found_address), phys_addr, size)); } } R_END_TRY_CATCH; /* Use the size as the found size. */ found_size = size; R_SUCCEED(); }; if (aligned) { /* Query the input. */ R_TRY(QueryMappingFromPageTable(phys_addr, size)); } else { if (kern::GetTargetFirmware() < TargetFirmware_8_0_0 && phys_addr >= PageSize) { /* Query the aligned-down page. */ const size_t offset = phys_addr & (PageSize - 1); R_TRY(QueryMappingFromPageTable(phys_addr - offset, size + offset)); /* Adjust the output address. */ found_address += offset; } else { /* Newer kernel only allows unaligned addresses when they're special enum members. */ R_UNLESS(phys_addr < PageSize, svc::ResultNotFound()); /* Try to find the memory region. */ const KMemoryRegion * const region = [] ALWAYS_INLINE_LAMBDA (ams::svc::MemoryRegionType type) -> const KMemoryRegion * { switch (type) { case ams::svc::MemoryRegionType_KernelTraceBuffer: return KMemoryLayout::GetPhysicalKernelTraceBufferRegion(); case ams::svc::MemoryRegionType_OnMemoryBootImage: return KMemoryLayout::GetPhysicalOnMemoryBootImageRegion(); case ams::svc::MemoryRegionType_DTB: return KMemoryLayout::GetPhysicalDTBRegion(); default: return nullptr; } }(static_cast<ams::svc::MemoryRegionType>(phys_addr)); /* Ensure that we found the region. */ R_UNLESS(region != nullptr, svc::ResultNotFound()); /* Chcek that the region is valid. */ MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0); R_TRY(pt.QueryStaticMapping(std::addressof(found_address), region->GetAddress(), region->GetSize())); found_size = region->GetSize(); } } /* We succeeded. */ MESOSPHERE_ASSERT(found_address != Null<KProcessAddress>); MESOSPHERE_ASSERT(found_size != 0); if (out_address != nullptr) { *out_address = GetInteger(found_address); } if (out_size != nullptr) { *out_size = found_size; } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result QueryPhysicalAddress64(ams::svc::lp64::PhysicalMemoryInfo *out_info, ams::svc::Address address) { R_RETURN(QueryPhysicalAddress(out_info, address)); } Result QueryMemoryMapping64(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); static_assert(sizeof(*out_size) == sizeof(size_t)); R_RETURN(QueryMemoryMapping(reinterpret_cast<uintptr_t *>(out_address), reinterpret_cast<size_t *>(out_size), physical_address, size)); } Result LegacyQueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); R_RETURN(QueryMemoryMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size)); } /* ============================= 64From32 ABI ============================= */ Result QueryPhysicalAddress64From32(ams::svc::ilp32::PhysicalMemoryInfo *out_info, ams::svc::Address address) { ams::svc::PhysicalMemoryInfo info = {}; R_TRY(QueryPhysicalAddress(std::addressof(info), address)); *out_info = { .physical_address = info.physical_address, .virtual_address = static_cast<u32>(info.virtual_address), .size = static_cast<u32>(info.size), }; R_SUCCEED(); } Result QueryMemoryMapping64From32(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); static_assert(sizeof(*out_size) == sizeof(size_t)); R_RETURN(QueryMemoryMapping(reinterpret_cast<uintptr_t *>(out_address), reinterpret_cast<size_t *>(out_size), physical_address, size)); } Result LegacyQueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); R_RETURN(QueryMemoryMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_cache.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { class CacheOperation { public: virtual void Operate(void *address, size_t size) const = 0; }; Result DoProcessCacheOperation(const CacheOperation &operation, KProcessPageTable &page_table, uintptr_t address, size_t size) { /* Determine aligned extents. */ const uintptr_t aligned_start = util::AlignDown(address, PageSize); const uintptr_t aligned_end = util::AlignUp(address + size, PageSize); /* Iterate over and operate on contiguous ranges. */ uintptr_t cur_address = aligned_start; size_t remaining = size; while (remaining > 0) { /* Get a contiguous range to operate on. */ KPageTableBase::MemoryRange contig_range; R_TRY(page_table.OpenMemoryRangeForProcessCacheOperation(std::addressof(contig_range), cur_address, aligned_end - cur_address)); /* Close the range when we're done operating on it. */ ON_SCOPE_EXIT { contig_range.Close(); }; /* Adjust to remain within range. */ KVirtualAddress operate_address = KMemoryLayout::GetLinearVirtualAddress(contig_range.GetAddress()); size_t operate_size = contig_range.GetSize(); if (cur_address < address) { operate_address += (address - cur_address); operate_size -= (address - cur_address); } if (operate_size > remaining) { operate_size = remaining; } /* Operate. */ operation.Operate(GetVoidPointer(operate_address), operate_size); /* Advance. */ cur_address += contig_range.GetSize(); remaining -= operate_size; } MESOSPHERE_ASSERT(remaining == 0); R_SUCCEED(); } void FlushEntireDataCache() { /* Flushing cache takes up to 1ms, so determine our minimum end tick. */ const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMilliSeconds(1)); /* Flush the entire data cache. */ cpu::FlushEntireDataCache(); /* Wait for 1ms to have passed. */ while (KHardwareTimer::GetTick() < timeout) { cpu::Yield(); } } Result FlushDataCache(uintptr_t address, size_t size) { /* Succeed if there's nothing to do. */ R_SUCCEED_IF(size == 0); /* Validate that the region is within range. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Flush the cache. */ R_TRY(cpu::FlushDataCache(reinterpret_cast<void *>(address), size)); R_SUCCEED(); } Result InvalidateProcessDataCache(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { /* Validate address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Invalidate the cache. */ if (process.GetPointerUnsafe() == GetCurrentProcessPointer()) { R_TRY(process->GetPageTable().InvalidateCurrentProcessDataCache(address, size)); } else { R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size)); } R_SUCCEED(); } Result StoreProcessDataCache(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { /* Validate address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Verify the region is within range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Perform the operation. */ if (process.GetPointerUnsafe() == GetCurrentProcessPointer()) { R_RETURN(cpu::StoreDataCache(reinterpret_cast<void *>(address), size)); } else { class StoreCacheOperation : public CacheOperation { public: virtual void Operate(void *address, size_t size) const override { MESOSPHERE_R_ABORT_UNLESS(cpu::StoreDataCache(address, size)); } } operation; R_RETURN(DoProcessCacheOperation(operation, page_table, address, size)); } } Result FlushProcessDataCache(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { /* Validate address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Verify the region is within range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Perform the operation. */ if (process.GetPointerUnsafe() == GetCurrentProcessPointer()) { R_RETURN(cpu::FlushDataCache(reinterpret_cast<void *>(address), size)); } else { class FlushCacheOperation : public CacheOperation { public: virtual void Operate(void *address, size_t size) const override { MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(address, size)); } } operation; R_RETURN(DoProcessCacheOperation(operation, page_table, address, size)); } } } /* ============================= 64 ABI ============================= */ void FlushEntireDataCache64() { return FlushEntireDataCache(); } Result FlushDataCache64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(FlushDataCache(address, size)); } Result InvalidateProcessDataCache64(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(InvalidateProcessDataCache(process_handle, address, size)); } Result StoreProcessDataCache64(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(StoreProcessDataCache(process_handle, address, size)); } Result FlushProcessDataCache64(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(FlushProcessDataCache(process_handle, address, size)); } /* ============================= 64From32 ABI ============================= */ void FlushEntireDataCache64From32() { return FlushEntireDataCache(); } Result FlushDataCache64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(FlushDataCache(address, size)); } Result InvalidateProcessDataCache64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(InvalidateProcessDataCache(process_handle, address, size)); } Result StoreProcessDataCache64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(StoreProcessDataCache(process_handle, address, size)); } Result FlushProcessDataCache64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(FlushProcessDataCache(process_handle, address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_code_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidMapCodeMemoryPermission(ams::svc::MemoryPermission perm) { return perm == ams::svc::MemoryPermission_ReadWrite; } constexpr bool IsValidMapToOwnerCodeMemoryPermission(ams::svc::MemoryPermission perm) { return perm == ams::svc::MemoryPermission_Read || perm == ams::svc::MemoryPermission_ReadExecute; } constexpr bool IsValidUnmapCodeMemoryPermission(ams::svc::MemoryPermission perm) { return perm == ams::svc::MemoryPermission_None; } constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(ams::svc::MemoryPermission perm) { return perm == ams::svc::MemoryPermission_None; } Result CreateCodeMemory(ams::svc::Handle *out, uintptr_t address, size_t size) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Create the code memory. */ KCodeMemory *code_mem = KCodeMemory::Create(); R_UNLESS(code_mem != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { code_mem->Close(); }; /* Verify that the region is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Initialize the code memory. */ R_TRY(code_mem->Initialize(address, size)); /* Register the code memory. */ KCodeMemory::Register(code_mem); /* Add the code memory to the handle table. */ R_TRY(GetCurrentProcess().GetHandleTable().Add(out, code_mem)); R_SUCCEED(); } Result ControlCodeMemory(ams::svc::Handle code_memory_handle, ams::svc::CodeMemoryOperation operation, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { /* Validate the address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the code memory from its handle. */ KScopedAutoObject code_mem = GetCurrentProcess().GetHandleTable().GetObject<KCodeMemory>(code_memory_handle); R_UNLESS(code_mem.IsNotNull(), svc::ResultInvalidHandle()); /* NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process. */ /* This enables homebrew usage of these SVCs for JIT. */ /* R_UNLESS(code_mem->GetOwner() != GetCurrentProcessPointer(), svc::ResultInvalidHandle()); */ /* Perform the operation. */ switch (operation) { case ams::svc::CodeMemoryOperation_Map: { /* Check that the region is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_CodeOut), svc::ResultInvalidMemoryRegion()); /* Check the memory permission. */ R_UNLESS(IsValidMapCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Map the memory. */ R_TRY(code_mem->Map(address, size)); } break; case ams::svc::CodeMemoryOperation_Unmap: { /* Check that the region is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_CodeOut), svc::ResultInvalidMemoryRegion()); /* Check the memory permission. */ R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Unmap the memory. */ R_TRY(code_mem->Unmap(address, size)); } break; case ams::svc::CodeMemoryOperation_MapToOwner: { /* Check that the region is in range. */ R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion()); /* Check the memory permission. */ R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Map the memory to its owner. */ R_TRY(code_mem->MapToOwner(address, size, perm)); } break; case ams::svc::CodeMemoryOperation_UnmapFromOwner: { /* Check that the region is in range. */ R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion()); /* Check the memory permission. */ R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Unmap the memory from its owner. */ R_TRY(code_mem->UnmapFromOwner(address, size)); } break; default: R_THROW(svc::ResultInvalidEnumValue()); } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result CreateCodeMemory64(ams::svc::Handle *out_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(CreateCodeMemory(out_handle, address, size)); } Result ControlCodeMemory64(ams::svc::Handle code_memory_handle, ams::svc::CodeMemoryOperation operation, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { R_RETURN(ControlCodeMemory(code_memory_handle, operation, address, size, perm)); } /* ============================= 64From32 ABI ============================= */ Result CreateCodeMemory64From32(ams::svc::Handle *out_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(CreateCodeMemory(out_handle, address, size)); } Result ControlCodeMemory64From32(ams::svc::Handle code_memory_handle, ams::svc::CodeMemoryOperation operation, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { R_RETURN(ControlCodeMemory(code_memory_handle, operation, address, size, perm)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_condition_variable.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsKernelAddress(uintptr_t address) { return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; } Result WaitProcessWideKeyAtomic(uintptr_t address, uintptr_t cv_key, uint32_t tag, int64_t timeout_ns) { /* Validate input. */ R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress()); /* Convert timeout from nanoseconds to ticks. */ s64 timeout; if (timeout_ns > 0) { const ams::svc::Tick offset_tick(TimeSpan::FromNanoSeconds(timeout_ns)); if (AMS_LIKELY(offset_tick > 0)) { timeout = KHardwareTimer::GetTick() + offset_tick + 2; if (AMS_UNLIKELY(timeout <= 0)) { timeout = std::numeric_limits<s64>::max(); } } else { timeout = std::numeric_limits<s64>::max(); } } else { timeout = timeout_ns; } /* Wait on the condition variable. */ R_RETURN(GetCurrentProcess().WaitConditionVariable(address, util::AlignDown(cv_key, sizeof(u32)), tag, timeout)); } void SignalProcessWideKey(uintptr_t cv_key, int32_t count) { /* Signal the condition variable. */ return GetCurrentProcess().SignalConditionVariable(util::AlignDown(cv_key, sizeof(u32)), count); } } /* ============================= 64 ABI ============================= */ Result WaitProcessWideKeyAtomic64(ams::svc::Address address, ams::svc::Address cv_key, uint32_t tag, int64_t timeout_ns) { R_RETURN(WaitProcessWideKeyAtomic(address, cv_key, tag, timeout_ns)); } void SignalProcessWideKey64(ams::svc::Address cv_key, int32_t count) { return SignalProcessWideKey(cv_key, count); } /* ============================= 64From32 ABI ============================= */ Result WaitProcessWideKeyAtomic64From32(ams::svc::Address address, ams::svc::Address cv_key, uint32_t tag, int64_t timeout_ns) { R_RETURN(WaitProcessWideKeyAtomic(address, cv_key, tag, timeout_ns)); } void SignalProcessWideKey64From32(ams::svc::Address cv_key, int32_t count) { return SignalProcessWideKey(cv_key, count); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_debug.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr inline int32_t MaximumDebuggableThreadCount = 0x60; Result DebugActiveProcess(ams::svc::Handle *out_handle, uint64_t process_id) { /* Check that the SVC can be used. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Get the process from its id. */ KProcess *process = KProcess::GetProcessFromId(process_id); R_UNLESS(process != nullptr, svc::ResultInvalidProcessId()); /* Close the reference we opened to the process on scope exit. */ ON_SCOPE_EXIT { process->Close(); }; /* Check that the debugging is allowed. */ const bool allowable = process->IsPermittedDebug() || GetCurrentProcess().CanForceDebug() || GetCurrentProcess().CanForceDebugProd(); R_UNLESS(allowable, svc::ResultInvalidState()); /* Disallow debugging one's own processs, to prevent softlocks. */ R_UNLESS(process != GetCurrentProcessPointer(), svc::ResultInvalidState()); /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Create a new debug object. */ KDebug *debug = KDebug::Create(); R_UNLESS(debug != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { debug->Close(); }; /* Initialize the debug object. */ debug->Initialize(); /* Register the debug object. */ KDebug::Register(debug); /* Try to attach to the target process. */ R_TRY(debug->Attach(process)); /* Add the new debug object to the handle table. */ R_TRY(handle_table.Add(out_handle, debug)); R_SUCCEED(); } Result BreakDebugProcess(ams::svc::Handle debug_handle) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Break the process. */ R_TRY(debug->BreakProcess()); R_SUCCEED(); } Result TerminateDebugProcess(ams::svc::Handle debug_handle) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Terminate the process. */ R_TRY(debug->TerminateProcess()); R_SUCCEED(); } template<typename EventInfoType> Result GetDebugEvent(KUserPointer<EventInfoType *> out_info, ams::svc::Handle debug_handle) { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Create and clear a new event info. */ EventInfoType info; std::memset(std::addressof(info), 0, sizeof(info)); /* Get the next info from the debug object. */ R_TRY(debug->GetDebugEventInfo(std::addressof(info))); /* Copy the info out to the user. */ R_TRY(out_info.CopyFrom(std::addressof(info))); R_SUCCEED(); } Result ContinueDebugEventImpl(ams::svc::Handle debug_handle, uint32_t flags, const uint64_t *thread_ids, int32_t num_thread_ids) { /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Continue the event. */ R_TRY(debug->ContinueDebug(flags, thread_ids, num_thread_ids)); R_SUCCEED(); } Result ContinueDebugEvent(ams::svc::Handle debug_handle, uint32_t flags, KUserPointer<const uint64_t *> user_thread_ids, int32_t num_thread_ids) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Verify that the flags are valid. */ R_UNLESS((flags | ams::svc::ContinueFlag_AllMask) == ams::svc::ContinueFlag_AllMask, svc::ResultInvalidEnumValue()); /* Verify that continue all and continue others flags are exclusive. */ constexpr u32 AllAndOthersMask = ams::svc::ContinueFlag_ContinueAll | ams::svc::ContinueFlag_ContinueOthers; R_UNLESS((flags & AllAndOthersMask) != AllAndOthersMask, svc::ResultInvalidEnumValue()); /* Verify that the number of thread ids is valid. */ R_UNLESS((0 <= num_thread_ids && num_thread_ids <= MaximumDebuggableThreadCount), svc::ResultOutOfRange()); /* Copy the threads from userspace. */ uint64_t thread_ids[MaximumDebuggableThreadCount]; if (num_thread_ids > 0) { R_TRY(user_thread_ids.CopyArrayTo(thread_ids, num_thread_ids)); } /* Continue the event. */ R_TRY(ContinueDebugEventImpl(debug_handle, flags, thread_ids, num_thread_ids)); R_SUCCEED(); } Result LegacyContinueDebugEvent(ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Verify that the flags are valid. */ R_UNLESS((flags | ams::svc::ContinueFlag_AllMask) == ams::svc::ContinueFlag_AllMask, svc::ResultInvalidEnumValue()); /* Verify that continue all and continue others flags are exclusive. */ constexpr u32 AllAndOthersMask = ams::svc::ContinueFlag_ContinueAll | ams::svc::ContinueFlag_ContinueOthers; R_UNLESS((flags & AllAndOthersMask) != AllAndOthersMask, svc::ResultInvalidEnumValue()); /* Continue the event. */ R_TRY(ContinueDebugEventImpl(debug_handle, flags, std::addressof(thread_id), 1)); R_SUCCEED(); } Result GetDebugThreadContext(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Validate the context flags. */ R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Get the thread context. */ ams::svc::ThreadContext context = {}; R_TRY(debug->GetThreadContext(std::addressof(context), thread_id, context_flags)); /* Copy the context to userspace. */ R_TRY(out_context.CopyFrom(std::addressof(context))); R_SUCCEED(); } Result SetDebugThreadContext(ams::svc::Handle debug_handle, uint64_t thread_id, KUserPointer<const ams::svc::ThreadContext *> user_context, uint32_t context_flags) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Validate the context flags. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) { /* Check that the flags are a subset of the allowable. */ constexpr u32 AllFlagsMask = ams::svc::ThreadContextFlag_All | ams::svc::ThreadContextFlag_SetSingleStep | ams::svc::ThreadContextFlag_ClearSingleStep; R_UNLESS((context_flags | AllFlagsMask) == AllFlagsMask, svc::ResultInvalidEnumValue()); /* Check that thread isn't both setting and clearing single step. */ const bool set_ss = (context_flags & ams::svc::ThreadContextFlag_SetSingleStep) != 0; const bool clear_ss = (context_flags & ams::svc::ThreadContextFlag_ClearSingleStep) != 0; R_UNLESS(!(set_ss && clear_ss), svc::ResultInvalidEnumValue()); } #else { /* Check that the flags are a subset of the allowable. */ R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue()); } #endif /* Copy the thread context from userspace. */ ams::svc::ThreadContext context; R_TRY(user_context.CopyTo(std::addressof(context))); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Set the thread context. */ R_TRY(debug->SetThreadContext(context, thread_id, context_flags)); R_SUCCEED(); } Result QueryDebugProcessMemory(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uintptr_t address) { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Query the mapping's info. */ R_TRY(debug->QueryMemoryInfo(out_memory_info, out_page_info, address)); R_SUCCEED(); } template<typename T> Result QueryDebugProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uint64_t address) { /* Get an ams::svc::MemoryInfo for the region. */ ams::svc::MemoryInfo info = {}; R_TRY(QueryDebugProcessMemory(std::addressof(info), out_page_info, debug_handle, address)); /* Copy the info to userspace. */ if constexpr (std::same_as<T, ams::svc::MemoryInfo>) { R_TRY(out_memory_info.CopyFrom(std::addressof(info))); } else { /* Convert the info. */ T converted_info = {}; static_assert(std::same_as<decltype(T{}.base_address), decltype(ams::svc::MemoryInfo{}.base_address)>); static_assert(std::same_as<decltype(T{}.size), decltype(ams::svc::MemoryInfo{}.size)>); converted_info.base_address = info.base_address; converted_info.size = info.size; converted_info.state = info.state; converted_info.attribute = info.attribute; converted_info.permission = info.permission; converted_info.ipc_count = info.ipc_count; converted_info.device_count = info.device_count; /* Copy it. */ R_TRY(out_memory_info.CopyFrom(std::addressof(converted_info))); } R_SUCCEED(); } Result ReadDebugProcessMemory(uintptr_t buffer, ams::svc::Handle debug_handle, uintptr_t address, size_t size) { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Validate address / size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((buffer < buffer + size), svc::ResultInvalidCurrentMemory()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Read the memory. */ R_TRY(debug->ReadMemory(buffer, address, size)); R_SUCCEED(); } Result WriteDebugProcessMemory(ams::svc::Handle debug_handle, uintptr_t buffer, uintptr_t address, size_t size) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Validate address / size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((buffer < buffer + size), svc::ResultInvalidCurrentMemory()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Write the memory. */ R_TRY(debug->WriteMemory(buffer, address, size)); R_SUCCEED(); } Result SetHardwareBreakPoint(ams::svc::HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Set the breakpoint. */ R_TRY(KDebug::SetHardwareBreakPoint(name, flags, value)); R_SUCCEED(); } Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { /* Only allow invoking the svc on development hardware or if force debug prod. */ R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Get the thread from its id. */ KThread *thread = KThread::GetThreadFromId(thread_id); R_UNLESS(thread != nullptr, svc::ResultInvalidThreadId()); ON_SCOPE_EXIT { thread->Close(); }; /* Get the process from the debug object. */ R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); /* Close the process when we're done. */ ON_SCOPE_EXIT { debug->CloseProcess(); }; /* Get the proces. */ KProcess * const process = debug->GetProcessUnsafe(); /* Verify that the process is the thread's parent. */ R_UNLESS(process == thread->GetOwnerProcess(), svc::ResultInvalidThreadId()); /* Get the parameter. */ switch (param) { case ams::svc::DebugThreadParam_Priority: { /* Get the priority. */ *out_32 = thread->GetPriority(); } break; case ams::svc::DebugThreadParam_State: { /* Get the thread state and suspend status. */ KThread::ThreadState state; bool suspended_user; bool suspended_debug; { KScopedSchedulerLock sl; state = thread->GetState(); suspended_user = thread->IsSuspendRequested(KThread::SuspendType_Thread); suspended_debug = thread->IsSuspendRequested(KThread::SuspendType_Debug); } /* Set the suspend flags. */ *out_32 = 0; if (suspended_user) { *out_32 |= ams::svc::ThreadSuspend_User; } if (suspended_debug) { *out_32 |= ams::svc::ThreadSuspend_Debug; } /* Set the state. */ switch (state) { case KThread::ThreadState_Initialized: { *out_64 = ams::svc::ThreadState_Initializing; } break; case KThread::ThreadState_Waiting: { *out_64 = ams::svc::ThreadState_Waiting; } break; case KThread::ThreadState_Runnable: { *out_64 = ams::svc::ThreadState_Running; } break; case KThread::ThreadState_Terminated: { *out_64 = ams::svc::ThreadState_Terminated; } break; default: R_THROW(svc::ResultInvalidState()); } } break; case ams::svc::DebugThreadParam_IdealCore: { /* Get the ideal core. */ s32 core_id; u64 affinity_mask; thread->GetPhysicalCoreMask(std::addressof(core_id), std::addressof(affinity_mask)); *out_32 = core_id; } break; case ams::svc::DebugThreadParam_CurrentCore: { /* Get the current core. */ *out_32 = thread->GetActiveCore(); } break; case ams::svc::DebugThreadParam_AffinityMask: { /* Get the affinity mask. */ s32 core_id; u64 affinity_mask; thread->GetPhysicalCoreMask(std::addressof(core_id), std::addressof(affinity_mask)); *out_32 = affinity_mask; } break; default: R_THROW(ams::svc::ResultInvalidEnumValue()); } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result DebugActiveProcess64(ams::svc::Handle *out_handle, uint64_t process_id) { R_RETURN(DebugActiveProcess(out_handle, process_id)); } Result BreakDebugProcess64(ams::svc::Handle debug_handle) { R_RETURN(BreakDebugProcess(debug_handle)); } Result TerminateDebugProcess64(ams::svc::Handle debug_handle) { R_RETURN(TerminateDebugProcess(debug_handle)); } Result GetDebugEvent64(KUserPointer<ams::svc::lp64::DebugEventInfo *> out_info, ams::svc::Handle debug_handle) { R_RETURN(GetDebugEvent(out_info, debug_handle)); } Result ContinueDebugEvent64(ams::svc::Handle debug_handle, uint32_t flags, KUserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) { R_RETURN(ContinueDebugEvent(debug_handle, flags, thread_ids, num_thread_ids)); } Result LegacyContinueDebugEvent64(ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { R_RETURN(LegacyContinueDebugEvent(debug_handle, flags, thread_id)); } Result GetDebugThreadContext64(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { R_RETURN(GetDebugThreadContext(out_context, debug_handle, thread_id, context_flags)); } Result SetDebugThreadContext64(ams::svc::Handle debug_handle, uint64_t thread_id, KUserPointer<const ams::svc::ThreadContext *> context, uint32_t context_flags) { R_RETURN(SetDebugThreadContext(debug_handle, thread_id, context, context_flags)); } Result QueryDebugProcessMemory64(KUserPointer<ams::svc::lp64::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, ams::svc::Address address) { R_RETURN(QueryDebugProcessMemory(out_memory_info, out_page_info, debug_handle, address)); } Result ReadDebugProcessMemory64(ams::svc::Address buffer, ams::svc::Handle debug_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(ReadDebugProcessMemory(buffer, debug_handle, address, size)); } Result WriteDebugProcessMemory64(ams::svc::Handle debug_handle, ams::svc::Address buffer, ams::svc::Address address, ams::svc::Size size) { R_RETURN(WriteDebugProcessMemory(debug_handle, buffer, address, size)); } Result SetHardwareBreakPoint64(ams::svc::HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value) { R_RETURN(SetHardwareBreakPoint(name, flags, value)); } Result GetDebugThreadParam64(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { R_RETURN(GetDebugThreadParam(out_64, out_32, debug_handle, thread_id, param)); } /* ============================= 64From32 ABI ============================= */ Result DebugActiveProcess64From32(ams::svc::Handle *out_handle, uint64_t process_id) { R_RETURN(DebugActiveProcess(out_handle, process_id)); } Result BreakDebugProcess64From32(ams::svc::Handle debug_handle) { R_RETURN(BreakDebugProcess(debug_handle)); } Result TerminateDebugProcess64From32(ams::svc::Handle debug_handle) { R_RETURN(TerminateDebugProcess(debug_handle)); } Result GetDebugEvent64From32(KUserPointer<ams::svc::ilp32::DebugEventInfo *> out_info, ams::svc::Handle debug_handle) { R_RETURN(GetDebugEvent(out_info, debug_handle)); } Result ContinueDebugEvent64From32(ams::svc::Handle debug_handle, uint32_t flags, KUserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) { R_RETURN(ContinueDebugEvent(debug_handle, flags, thread_ids, num_thread_ids)); } Result LegacyContinueDebugEvent64From32(ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { R_RETURN(LegacyContinueDebugEvent(debug_handle, flags, thread_id)); } Result GetDebugThreadContext64From32(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { R_RETURN(GetDebugThreadContext(out_context, debug_handle, thread_id, context_flags)); } Result SetDebugThreadContext64From32(ams::svc::Handle debug_handle, uint64_t thread_id, KUserPointer<const ams::svc::ThreadContext *> context, uint32_t context_flags) { R_RETURN(SetDebugThreadContext(debug_handle, thread_id, context, context_flags)); } Result QueryDebugProcessMemory64From32(KUserPointer<ams::svc::ilp32::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, ams::svc::Address address) { R_RETURN(QueryDebugProcessMemory(out_memory_info, out_page_info, debug_handle, address)); } Result ReadDebugProcessMemory64From32(ams::svc::Address buffer, ams::svc::Handle debug_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(ReadDebugProcessMemory(buffer, debug_handle, address, size)); } Result WriteDebugProcessMemory64From32(ams::svc::Handle debug_handle, ams::svc::Address buffer, ams::svc::Address address, ams::svc::Size size) { R_RETURN(WriteDebugProcessMemory(debug_handle, buffer, address, size)); } Result SetHardwareBreakPoint64From32(ams::svc::HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value) { R_RETURN(SetHardwareBreakPoint(name, flags, value)); } Result GetDebugThreadParam64From32(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) { R_RETURN(GetDebugThreadParam(out_64, out_32, debug_handle, thread_id, param)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_debug_string.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result OutputDebugString(KUserPointer<const char *> debug_str, size_t len) { /* Succeed immediately if there's nothing to output. */ R_SUCCEED_IF(len == 0); /* Ensure that the data being output is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(debug_str.GetUnsafePointer()), len), svc::ResultInvalidCurrentMemory()); /* Output the string. */ R_RETURN(KDebugLog::PrintUserString(debug_str, len)); } } /* ============================= 64 ABI ============================= */ Result OutputDebugString64(KUserPointer<const char *> debug_str, ams::svc::Size len) { R_RETURN(OutputDebugString(debug_str, len)); } /* ============================= 64From32 ABI ============================= */ Result OutputDebugString64From32(KUserPointer<const char *> debug_str, ams::svc::Size len) { R_RETURN(OutputDebugString(debug_str, len)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_device_address_space.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr inline u64 DeviceAddressSpaceAlignMask = (1ul << 22) - 1; constexpr bool IsProcessAndDeviceAligned(uint64_t process_address, uint64_t device_address) { return (process_address & DeviceAddressSpaceAlignMask) == (device_address & DeviceAddressSpaceAlignMask); } Result CreateDeviceAddressSpace(ams::svc::Handle *out, uint64_t das_address, uint64_t das_size) { /* Validate input. */ R_UNLESS(util::IsAligned(das_address, PageSize), svc::ResultInvalidMemoryRegion()); R_UNLESS(util::IsAligned(das_size, PageSize), svc::ResultInvalidMemoryRegion()); R_UNLESS(das_size > 0, svc::ResultInvalidMemoryRegion()); R_UNLESS((das_address < das_address + das_size), svc::ResultInvalidMemoryRegion()); /* Create the device address space. */ KDeviceAddressSpace *das = KDeviceAddressSpace::Create(); R_UNLESS(das != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { das->Close(); }; /* Initialize the device address space. */ R_TRY(das->Initialize(das_address, das_size)); /* Register the device address space. */ KDeviceAddressSpace::Register(das); /* Add to the handle table. */ R_TRY(GetCurrentProcess().GetHandleTable().Add(out, das)); R_SUCCEED(); } Result AttachDeviceAddressSpace(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle); R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle()); /* Attach. */ R_RETURN(das->Attach(device_name)); } Result DetachDeviceAddressSpace(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle); R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle()); /* Detach. */ R_RETURN(das->Detach(device_name)); } constexpr bool IsValidDeviceMemoryPermission(ams::svc::MemoryPermission device_perm) { switch (device_perm) { case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_Write: case ams::svc::MemoryPermission_ReadWrite: return true; default: return false; } } Result MapDeviceAddressSpaceByForce(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) { /* Decode the option. */ const util::BitPack32 option_pack = { option }; const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>(); const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>(); /* Validate input. */ R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion()); R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission()); R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle); R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the process address is within range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory()); /* Map. */ R_RETURN(das->MapByForce(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option)); } Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) { /* Decode the option. */ const util::BitPack32 option_pack = { option }; const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>(); const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>(); /* Validate input. */ R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(IsProcessAndDeviceAligned(process_address, device_address), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion()); R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory()); R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission()); R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue()); /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle); R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the process address is within range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory()); /* Map. */ R_RETURN(das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option)); } Result UnmapDeviceAddressSpace(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address) { /* Validate input. */ R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion()); R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory()); /* Get the device address space. */ KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle); R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the process address is within range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory()); R_RETURN(das->Unmap(std::addressof(page_table), KProcessAddress(process_address), size, device_address)); } } /* ============================= 64 ABI ============================= */ Result CreateDeviceAddressSpace64(ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) { R_RETURN(CreateDeviceAddressSpace(out_handle, das_address, das_size)); } Result AttachDeviceAddressSpace64(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { R_RETURN(AttachDeviceAddressSpace(device_name, das_handle)); } Result DetachDeviceAddressSpace64(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { R_RETURN(DetachDeviceAddressSpace(device_name, das_handle)); } Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } Result UnmapDeviceAddressSpace64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) { R_RETURN(UnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address)); } /* ============================= 64From32 ABI ============================= */ Result CreateDeviceAddressSpace64From32(ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) { R_RETURN(CreateDeviceAddressSpace(out_handle, das_address, das_size)); } Result AttachDeviceAddressSpace64From32(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { R_RETURN(AttachDeviceAddressSpace(device_name, das_handle)); } Result DetachDeviceAddressSpace64From32(ams::svc::DeviceName device_name, ams::svc::Handle das_handle) { R_RETURN(DetachDeviceAddressSpace(device_name, das_handle)); } Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } Result UnmapDeviceAddressSpace64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) { R_RETURN(UnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_event.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result SignalEvent(ams::svc::Handle event_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Get the writable event. */ KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); R_UNLESS(event.IsNotNull(), svc::ResultInvalidHandle()); event->Signal(); R_SUCCEED(); } Result ClearEvent(ams::svc::Handle event_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Try to clear the writable event. */ { KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle); if (event.IsNotNull()) { event->Clear(); R_SUCCEED(); } } /* Try to clear the readable event. */ { KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle); if (readable_event.IsNotNull()) { if (auto * const interrupt_event = readable_event->DynamicCast<KInterruptEvent *>(); interrupt_event != nullptr) { interrupt_event->Clear(); } else { readable_event->Clear(); } R_SUCCEED(); } } R_THROW(svc::ResultInvalidHandle()); } Result CreateEvent(ams::svc::Handle *out_write, ams::svc::Handle *out_read) { /* Get the current process and handle table. */ auto &process = GetCurrentProcess(); auto &handle_table = process.GetHandleTable(); /* Declare the event we're going to allocate. */ KEvent *event; /* Reserve a new event from the process resource limit. */ KScopedResourceReservation event_reservation(std::addressof(process), ams::svc::LimitableResource_EventCountMax); if (event_reservation.Succeeded()) { /* Allocate an event normally. */ event = KEvent::Create(); } else { /* We couldn't reserve an event. Check that we support dynamically expanding the resource limit. */ R_UNLESS(process.GetResourceLimit() == std::addressof(Kernel::GetSystemResourceLimit()), svc::ResultLimitReached()); R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), svc::ResultLimitReached()); /* Try to allocate an event from unused slab memory. */ event = KEvent::CreateFromUnusedSlabMemory(); R_UNLESS(event != nullptr, svc::ResultLimitReached()); /* We successfully allocated an event, so add the object we allocated to the resource limit. */ Kernel::GetSystemResourceLimit().Add(ams::svc::LimitableResource_EventCountMax, 1); } /* Check that we successfully created an event. */ R_UNLESS(event != nullptr, svc::ResultOutOfResource()); /* Initialize the event. */ event->Initialize(); /* Commit the event reservation. */ event_reservation.Commit(); /* Ensure that we clean up the event (and its only references are handle table) on function end. */ ON_SCOPE_EXIT { event->GetReadableEvent().Close(); event->Close(); }; /* Register the event. */ KEvent::Register(event); /* Add the event to the handle table. */ R_TRY(handle_table.Add(out_write, event)); /* Ensure that we maintaing a clean handle state on exit. */ ON_RESULT_FAILURE { handle_table.Remove(*out_write); }; /* Add the readable event to the handle table. */ R_RETURN(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); } } /* ============================= 64 ABI ============================= */ Result SignalEvent64(ams::svc::Handle event_handle) { R_RETURN(SignalEvent(event_handle)); } Result ClearEvent64(ams::svc::Handle event_handle) { R_RETURN(ClearEvent(event_handle)); } Result CreateEvent64(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { R_RETURN(CreateEvent(out_write_handle, out_read_handle)); } /* ============================= 64From32 ABI ============================= */ Result SignalEvent64From32(ams::svc::Handle event_handle) { R_RETURN(SignalEvent(event_handle)); } Result ClearEvent64From32(ams::svc::Handle event_handle) { R_RETURN(ClearEvent(event_handle)); } Result CreateEvent64From32(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { R_RETURN(CreateEvent(out_write_handle, out_read_handle)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_exception.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) void PrintBreak(ams::svc::BreakReason break_reason) { /* Print that break was called. */ MESOSPHERE_RELEASE_LOG("%s: svc::Break(%d) was called, pid=%ld, tid=%ld\n", GetCurrentProcess().GetName(), static_cast<s32>(break_reason), GetCurrentProcess().GetId(), GetCurrentThread().GetId()); /* Print the current thread's registers. */ KDebug::PrintRegister(); /* Print a backtrace. */ KDebug::PrintBacktrace(); } #endif void Break(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) { /* Determine whether the break is only a notification. */ const bool is_notification = (break_reason & ams::svc::BreakReason_NotificationOnlyFlag) != 0; /* If the break isn't a notification, print it. */ if (!is_notification) { #if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) PrintBreak(break_reason); #endif } /* If the current process is attached to debugger, try to notify it. */ if (GetCurrentProcess().IsAttachedToDebugger()) { if (R_SUCCEEDED(KDebug::BreakIfAttached(break_reason, address, size))) { /* If we attached, set the pc to the instruction before the current one and return. */ KDebug::SetPreviousProgramCounter(); return; } } /* If the break is only a notification, we're done. */ if (is_notification) { return; } /* Print that break was called. */ MESOSPHERE_EXCEPTION_LOG("Break() called. "); /* Try to enter JIT debug state. */ if (GetCurrentProcess().EnterJitDebug(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, KDebug::GetProgramCounter(GetCurrentThread()), break_reason, address, size)) { /* We entered JIT debug, so set the pc to the instruction before the current one and return. */ KDebug::SetPreviousProgramCounter(); return; } /* Exit the current process. */ GetCurrentProcess().Exit(); } } /* ============================= 64 ABI ============================= */ void Break64(ams::svc::BreakReason break_reason, ams::svc::Address arg, ams::svc::Size size) { return Break(break_reason, arg, size); } /* ============================= 64From32 ABI ============================= */ void Break64From32(ams::svc::BreakReason break_reason, ams::svc::Address arg, ams::svc::Size size) { return Break(break_reason, arg, size); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_info.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result GetInitialProcessIdRange(u64 *out, ams::svc::InitialProcessIdRangeInfo info) { switch (info) { case ams::svc::InitialProcessIdRangeInfo_Minimum: MESOSPHERE_ABORT_UNLESS(GetInitialProcessIdMin() <= GetInitialProcessIdMax()); *out = GetInitialProcessIdMin(); break; case ams::svc::InitialProcessIdRangeInfo_Maximum: MESOSPHERE_ABORT_UNLESS(GetInitialProcessIdMin() <= GetInitialProcessIdMax()); *out = GetInitialProcessIdMax(); break; default: R_THROW(svc::ResultInvalidCombination()); } R_SUCCEED(); } Result GetInfoImpl(u64 *out, ams::svc::InfoType info_type, KProcess *process) { switch (info_type) { case ams::svc::InfoType_CoreMask: *out = process->GetCoreMask(); break; case ams::svc::InfoType_PriorityMask: *out = process->GetPriorityMask(); break; case ams::svc::InfoType_AliasRegionAddress: *out = GetInteger(process->GetPageTable().GetAliasRegionStart()); break; case ams::svc::InfoType_AliasRegionSize: *out = process->GetPageTable().GetAliasRegionSize(); break; case ams::svc::InfoType_HeapRegionAddress: *out = GetInteger(process->GetPageTable().GetHeapRegionStart()); break; case ams::svc::InfoType_HeapRegionSize: *out = process->GetPageTable().GetHeapRegionSize(); break; case ams::svc::InfoType_TotalMemorySize: *out = process->GetTotalUserPhysicalMemorySize(); break; case ams::svc::InfoType_UsedMemorySize: *out = process->GetUsedUserPhysicalMemorySize(); break; case ams::svc::InfoType_AslrRegionAddress: *out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart()); break; case ams::svc::InfoType_AslrRegionSize: *out = process->GetPageTable().GetAliasCodeRegionSize(); break; case ams::svc::InfoType_StackRegionAddress: *out = GetInteger(process->GetPageTable().GetStackRegionStart()); break; case ams::svc::InfoType_StackRegionSize: *out = process->GetPageTable().GetStackRegionSize(); break; case ams::svc::InfoType_SystemResourceSizeTotal: *out = process->GetTotalSystemResourceSize(); break; case ams::svc::InfoType_SystemResourceSizeUsed: *out = process->GetUsedSystemResourceSize(); break; case ams::svc::InfoType_ProgramId: *out = process->GetProgramId(); break; case ams::svc::InfoType_UserExceptionContextAddress: *out = GetInteger(process->GetProcessLocalRegionAddress()); break; case ams::svc::InfoType_TotalNonSystemMemorySize: *out = process->GetTotalNonSystemUserPhysicalMemorySize(); break; case ams::svc::InfoType_UsedNonSystemMemorySize: *out = process->GetUsedNonSystemUserPhysicalMemorySize(); break; case ams::svc::InfoType_IsApplication: *out = process->IsApplication(); break; case ams::svc::InfoType_FreeThreadCount: if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) { const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax); const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax); *out = limit_value - current_value; } else { *out = 0; } break; case ams::svc::InfoType_AliasRegionExtraSize: *out = process->GetPageTable().GetAliasRegionExtraSize(); break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } R_SUCCEED(); } Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) { switch (info_type) { case ams::svc::InfoType_CoreMask: case ams::svc::InfoType_PriorityMask: case ams::svc::InfoType_AliasRegionAddress: case ams::svc::InfoType_AliasRegionSize: case ams::svc::InfoType_HeapRegionAddress: case ams::svc::InfoType_HeapRegionSize: case ams::svc::InfoType_TotalMemorySize: case ams::svc::InfoType_UsedMemorySize: case ams::svc::InfoType_AslrRegionAddress: case ams::svc::InfoType_AslrRegionSize: case ams::svc::InfoType_StackRegionAddress: case ams::svc::InfoType_StackRegionSize: case ams::svc::InfoType_SystemResourceSizeTotal: case ams::svc::InfoType_SystemResourceSizeUsed: case ams::svc::InfoType_ProgramId: case ams::svc::InfoType_UserExceptionContextAddress: case ams::svc::InfoType_TotalNonSystemMemorySize: case ams::svc::InfoType_UsedNonSystemMemorySize: case ams::svc::InfoType_IsApplication: case ams::svc::InfoType_FreeThreadCount: case ams::svc::InfoType_AliasRegionExtraSize: { /* These info types don't support non-zero subtypes. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle); #if defined(MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS) /* If we the process is valid, use it. */ if (process.IsNotNull()) { R_RETURN(GetInfoImpl(out, info_type, process.GetPointerUnsafe())); } /* Otherwise, as a mesosphere extension check if we were passed a usable KDebug. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process from the debug object. */ /* TODO: ResultInvalidHandle()? */ R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); /* Close the process when we're done. */ ON_SCOPE_EXIT { debug->CloseProcess(); }; /* Return the info. */ R_RETURN(GetInfoImpl(out, info_type, debug->GetProcessUnsafe())); #else /* Verify that the process is valid. */ R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Return the relevant info. */ R_RETURN(GetInfoImpl(out, info_type, process.GetPointerUnsafe())); #endif } break; case ams::svc::InfoType_DebuggerAttached: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get whether debugger is attached. */ *out = GetCurrentProcess().GetDebugObject() != nullptr; } break; case ams::svc::InfoType_ResourceLimit: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get the handle table and resource limit. */ KHandleTable &handle_table = GetCurrentProcess().GetHandleTable(); KResourceLimit *resource_limit = GetCurrentProcess().GetResourceLimit(); if (resource_limit != nullptr) { /* Get a new handle for the resource limit. */ ams::svc::Handle tmp; R_TRY(handle_table.Add(std::addressof(tmp), resource_limit)); /* Set the output. */ *out = tmp; } else { /* Set the output. */ *out = ams::svc::InvalidHandle; } } break; case ams::svc::InfoType_IdleTickCount: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Disable dispatch while we get the tick count. */ KScopedDisableDispatch dd; /* Verify the requested core is valid. */ const bool core_valid = (info_subtype == static_cast<u64>(-1ul)) || (info_subtype == static_cast<u64>(GetCurrentCoreId())); R_UNLESS(core_valid, svc::ResultInvalidCombination()); /* Get the idle tick count. */ *out = Kernel::GetScheduler().GetIdleThread()->GetCpuTime() - Kernel::GetInterruptTaskManager().GetCpuTime(); } break; case ams::svc::InfoType_RandomEntropy: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the requested entropy is valid. */ R_UNLESS(info_subtype < 4, svc::ResultInvalidCombination()); /* Get the entropy. */ *out = GetCurrentProcess().GetRandomEntropy(info_subtype); } break; case ams::svc::InfoType_InitialProcessIdRange: { /* NOTE: This info type was added in 4.0.0, and removed in 5.0.0. */ R_UNLESS(GetTargetFirmware() < TargetFirmware_5_0_0, svc::ResultInvalidEnumValue()); /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Get the process id range. */ R_TRY(GetInitialProcessIdRange(out, static_cast<ams::svc::InitialProcessIdRangeInfo>(info_subtype))); } break; case ams::svc::InfoType_ThreadTickCount: { /* Verify the requested core is valid. */ const bool core_valid = (info_subtype == static_cast<u64>(-1ul)) || (info_subtype < cpu::NumVirtualCores); R_UNLESS(core_valid, svc::ResultInvalidCombination()); /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Disable dispatch while we get the tick count. */ KScopedDisableDispatch dd; /* Determine the tick count. */ s64 tick_count; if (info_subtype == static_cast<u64>(-1ul)) { tick_count = thread->GetCpuTime(); if (GetCurrentThreadPointer() == thread.GetPointerUnsafe()) { const s64 cur_tick = KHardwareTimer::GetTick(); const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); tick_count += (cur_tick - prev_switch); } } else { const s32 phys_core = cpu::VirtualToPhysicalCoreMap[info_subtype]; MESOSPHERE_ABORT_UNLESS(phys_core < static_cast<s32>(cpu::NumCores)); tick_count = thread->GetCpuTime(phys_core); if (GetCurrentThreadPointer() == thread.GetPointerUnsafe() && phys_core == GetCurrentCoreId()) { const s64 cur_tick = KHardwareTimer::GetTick(); const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); tick_count += (cur_tick - prev_switch); } } /* Set the output. */ *out = tick_count; } break; case ams::svc::InfoType_IsSvcPermitted: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == svc::SvcId_SynchronizePreemptionState, svc::ResultInvalidCombination()); /* Get whether the svc is permitted. */ *out = GetCurrentProcess().IsPermittedSvc(static_cast<svc::SvcId>(info_subtype)); } break; case ams::svc::InfoType_IoRegionHint: { /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get the io region from its handle. */ KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(handle); R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle()); /* Get the io region's address hint. */ *out = io_region->GetHint(); } break; case ams::svc::InfoType_TransferMemoryHint: { /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get the transfer memory from its handle. */ KScopedAutoObject transfer_memory = GetCurrentProcess().GetHandleTable().GetObject<KTransferMemory>(handle); R_UNLESS(transfer_memory.IsNotNull(), svc::ResultInvalidHandle()); /* Get the transfer memory's address hint. */ *out = transfer_memory->GetHint(); } break; case ams::svc::InfoType_MesosphereMeta: { /* Verify the handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); switch (static_cast<ams::svc::MesosphereMetaInfo>(info_subtype)) { case ams::svc::MesosphereMetaInfo_KernelVersion: { /* Return the supported kernel version. */ *out = ams::svc::SupportedKernelVersion; } break; case ams::svc::MesosphereMetaInfo_IsKTraceEnabled: { /* Return whether the kernel supports tracing. */ constexpr u64 KTraceValue = ams::kern::IsKTraceEnabled ? 1 : 0; *out = KTraceValue; } break; case ams::svc::MesosphereMetaInfo_IsSingleStepEnabled: { /* Return whether the kernel supports hardware single step. */ #if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP) *out = 1; #else *out = 0; #endif } break; default: R_THROW(svc::ResultInvalidCombination()); } } break; case ams::svc::InfoType_MesosphereCurrentProcess: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the sub-type is valid. */ R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination()); /* Get the handle table. */ KHandleTable &handle_table = GetCurrentProcess().GetHandleTable(); /* Get a new handle for the current process. */ ams::svc::Handle tmp; R_TRY(handle_table.Add(std::addressof(tmp), GetCurrentProcessPointer())); /* Set the output. */ *out = tmp; } break; default: { /* For debug, log the invalid info call. */ MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype); } R_THROW(svc::ResultInvalidEnumValue()); } R_SUCCEED(); } constexpr bool IsValidMemoryPool(u64 pool) { switch (static_cast<KMemoryManager::Pool>(pool)) { case KMemoryManager::Pool_Application: case KMemoryManager::Pool_Applet: case KMemoryManager::Pool_System: case KMemoryManager::Pool_SystemNonSecure: return true; default: return false; } } Result GetSystemInfo(u64 *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, u64 info_subtype) { switch (info_type) { case ams::svc::SystemInfoType_TotalPhysicalMemorySize: case ams::svc::SystemInfoType_UsedPhysicalMemorySize: { /* Verify the input handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Verify the sub-type is valid. */ R_UNLESS(IsValidMemoryPool(info_subtype), svc::ResultInvalidCombination()); /* Convert to pool. */ const auto pool = static_cast<KMemoryManager::Pool>(info_subtype); /* Get the memory size. */ auto &mm = Kernel::GetMemoryManager(); switch (info_type) { case ams::svc::SystemInfoType_TotalPhysicalMemorySize: *out = mm.GetSize(pool); break; case ams::svc::SystemInfoType_UsedPhysicalMemorySize: *out = mm.GetSize(pool) - mm.GetFreeSize(pool); break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } break; case ams::svc::SystemInfoType_InitialProcessIdRange: { /* Verify the handle is invalid. */ R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Get the process id range. */ R_TRY(GetInitialProcessIdRange(out, static_cast<ams::svc::InitialProcessIdRangeInfo>(info_subtype))); } break; default: R_THROW(svc::ResultInvalidEnumValue()); } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result GetInfo64(uint64_t *out, ams::svc::InfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(GetInfo(out, info_type, handle, info_subtype)); } Result GetSystemInfo64(uint64_t *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(GetSystemInfo(out, info_type, handle, info_subtype)); } /* ============================= 64From32 ABI ============================= */ Result GetInfo64From32(uint64_t *out, ams::svc::InfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(GetInfo(out, info_type, handle, info_subtype)); } Result GetSystemInfo64From32(uint64_t *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(GetSystemInfo(out, info_type, handle, info_subtype)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_insecure_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result MapInsecurePhysicalMemory(uintptr_t address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the mapping is in range. */ auto &pt = GetCurrentProcess().GetPageTable(); R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Insecure), svc::ResultInvalidMemoryRegion()); /* Map the insecure memory. */ R_RETURN(pt.MapInsecurePhysicalMemory(address, size)); } Result UnmapInsecurePhysicalMemory(uintptr_t address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the mapping is in range. */ auto &pt = GetCurrentProcess().GetPageTable(); R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Insecure), svc::ResultInvalidMemoryRegion()); /* Map the insecure memory. */ R_RETURN(pt.UnmapInsecurePhysicalMemory(address, size)); } } /* ============================= 64 ABI ============================= */ Result MapInsecurePhysicalMemory64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapInsecurePhysicalMemory(address, size)); } Result UnmapInsecurePhysicalMemory64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapInsecurePhysicalMemory(address, size)); } /* ============================= 64From32 ABI ============================= */ Result MapInsecurePhysicalMemory64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapInsecurePhysicalMemory(address, size)); } Result UnmapInsecurePhysicalMemory64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapInsecurePhysicalMemory(address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_interrupt_event.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidInterruptType(ams::svc::InterruptType type) { switch (type) { case ams::svc::InterruptType_Edge: case ams::svc::InterruptType_Level: return true; default: return false; } } Result CreateInterruptEvent(ams::svc::Handle *out, int32_t interrupt_id, ams::svc::InterruptType type) { /* Validate the type. */ R_UNLESS(IsValidInterruptType(type), svc::ResultInvalidEnumValue()); /* Check whether the interrupt is allowed. */ auto &process = GetCurrentProcess(); R_UNLESS(process.IsPermittedInterrupt(interrupt_id), svc::ResultNotFound()); /* Get the current handle table. */ auto &handle_table = process.GetHandleTable(); /* Create the interrupt event. */ KInterruptEvent *event = KInterruptEvent::Create(); R_UNLESS(event != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { event->Close(); }; /* Initialize the event. */ R_TRY(event->Initialize(interrupt_id, type)); /* Register the event. */ KInterruptEvent::Register(event); /* Add the event to the handle table. */ R_TRY(handle_table.Add(out, event)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result CreateInterruptEvent64(ams::svc::Handle *out_read_handle, int32_t interrupt_id, ams::svc::InterruptType interrupt_type) { R_RETURN(CreateInterruptEvent(out_read_handle, interrupt_id, interrupt_type)); } /* ============================= 64From32 ABI ============================= */ Result CreateInterruptEvent64From32(ams::svc::Handle *out_read_handle, int32_t interrupt_id, ams::svc::InterruptType interrupt_type) { R_RETURN(CreateInterruptEvent(out_read_handle, interrupt_id, interrupt_type)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_io_pool.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { #if defined(AMS_SVC_IO_POOL_NOT_SUPPORTED) constexpr bool IsIoPoolApiSupported = false; #else constexpr bool IsIoPoolApiSupported = true; #endif [[maybe_unused]] constexpr bool IsValidIoRegionMapping(ams::svc::MemoryMapping mapping) { switch (mapping) { case ams::svc::MemoryMapping_IoRegister: case ams::svc::MemoryMapping_Uncached: case ams::svc::MemoryMapping_Memory: return true; default: return false; } } [[maybe_unused]] constexpr bool IsValidIoRegionPermission(ams::svc::MemoryPermission perm) { switch (perm) { case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_ReadWrite: return true; default: return false; } } Result CreateIoPool(ams::svc::Handle *out, ams::svc::IoPoolType pool_type) { if constexpr (IsIoPoolApiSupported) { /* Validate that we're allowed to create a pool for the given type. */ R_UNLESS(KIoPool::IsValidIoPoolType(pool_type), svc::ResultNotFound()); /* Create the io pool. */ KIoPool *io_pool = KIoPool::Create(); R_UNLESS(io_pool != nullptr, svc::ResultOutOfResource()); /* Ensure the only reference is in the handle table when we're done. */ ON_SCOPE_EXIT { io_pool->Close(); }; /* Initialize the io pool. */ R_TRY(io_pool->Initialize(pool_type)); /* Register the io pool. */ KIoPool::Register(io_pool); /* Add the io pool to the handle table. */ R_TRY(GetCurrentProcess().GetHandleTable().Add(out, io_pool)); R_SUCCEED(); } else { MESOSPHERE_UNUSED(out, pool_type); R_THROW(svc::ResultNotImplemented()); } } Result CreateIoRegion(ams::svc::Handle *out, ams::svc::Handle io_pool_handle, uint64_t phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { if constexpr (IsIoPoolApiSupported) { /* Validate the address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(phys_addr, PageSize), svc::ResultInvalidAddress()); R_UNLESS((phys_addr < phys_addr + size), svc::ResultInvalidMemoryRegion()); /* Validate the mapping/permissions. */ R_UNLESS(IsValidIoRegionMapping(mapping), svc::ResultInvalidEnumValue()); R_UNLESS(IsValidIoRegionPermission(perm), svc::ResultInvalidEnumValue()); /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Get the io pool. */ KScopedAutoObject io_pool = handle_table.GetObject<KIoPool>(io_pool_handle); R_UNLESS(io_pool.IsNotNull(), svc::ResultInvalidHandle()); /* Create the io region. */ KIoRegion *io_region = KIoRegion::Create(); R_UNLESS(io_region != nullptr, svc::ResultOutOfResource()); /* Ensure the only reference is in the handle table when we're done. */ ON_SCOPE_EXIT { io_region->Close(); }; /* Initialize the io region. */ R_TRY(io_region->Initialize(io_pool.GetPointerUnsafe(), phys_addr, size, mapping, perm)); /* Register the io region. */ KIoRegion::Register(io_region); /* Add the io region to the handle table. */ R_TRY(handle_table.Add(out, io_region)); R_SUCCEED(); } else { MESOSPHERE_UNUSED(out, io_pool_handle, phys_addr, size, mapping, perm); R_THROW(svc::ResultNotImplemented()); } } Result MapIoRegion(ams::svc::Handle io_region_handle, uintptr_t address, size_t size, ams::svc::MemoryPermission map_perm) { if constexpr (IsIoPoolApiSupported) { /* Validate the address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the mapping is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, ams::svc::MemoryState_Io), svc::ResultInvalidMemoryRegion()); /* Validate the map permission. */ R_UNLESS(IsValidIoRegionPermission(map_perm), svc::ResultInvalidNewMemoryPermission()); /* Get the io region. */ KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle); R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle()); /* Map the io region. */ R_TRY(io_region->Map(address, size, map_perm)); /* We succeeded. */ R_SUCCEED(); } else { MESOSPHERE_UNUSED(io_region_handle, address, size, map_perm); R_THROW(svc::ResultNotImplemented()); } } Result UnmapIoRegion(ams::svc::Handle io_region_handle, uintptr_t address, size_t size) { if constexpr (IsIoPoolApiSupported) { /* Validate the address/size. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the mapping is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, ams::svc::MemoryState_Io), svc::ResultInvalidMemoryRegion()); /* Get the io region. */ KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle); R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle()); /* Unmap the io region. */ R_TRY(io_region->Unmap(address, size)); /* We succeeded. */ R_SUCCEED(); } else { MESOSPHERE_UNUSED(io_region_handle, address, size); R_THROW(svc::ResultNotImplemented()); } } } /* ============================= 64 ABI ============================= */ Result CreateIoPool64(ams::svc::Handle *out_handle, ams::svc::IoPoolType pool_type) { R_RETURN(CreateIoPool(out_handle, pool_type)); } Result CreateIoRegion64(ams::svc::Handle *out_handle, ams::svc::Handle io_pool, ams::svc::PhysicalAddress physical_address, ams::svc::Size size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { R_RETURN(CreateIoRegion(out_handle, io_pool, physical_address, size, mapping, perm)); } Result MapIoRegion64(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { R_RETURN(MapIoRegion(io_region, address, size, perm)); } Result UnmapIoRegion64(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapIoRegion(io_region, address, size)); } /* ============================= 64From32 ABI ============================= */ Result CreateIoPool64From32(ams::svc::Handle *out_handle, ams::svc::IoPoolType pool_type) { R_RETURN(CreateIoPool(out_handle, pool_type)); } Result CreateIoRegion64From32(ams::svc::Handle *out_handle, ams::svc::Handle io_pool, ams::svc::PhysicalAddress physical_address, ams::svc::Size size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm) { R_RETURN(CreateIoRegion(out_handle, io_pool, physical_address, size, mapping, perm)); } Result MapIoRegion64From32(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { R_RETURN(MapIoRegion(io_region, address, size, perm)); } Result UnmapIoRegion64From32(ams::svc::Handle io_region, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapIoRegion(io_region, address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_ipc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> #pragma GCC push_options #pragma GCC optimize ("-O3") namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { ALWAYS_INLINE Result SendSyncRequestImpl(uintptr_t message, size_t buffer_size, ams::svc::Handle session_handle) { /* Get the client session. */ KScopedAutoObject session = GetCurrentProcess().GetHandleTable().GetObject<KClientSession>(session_handle); R_UNLESS(session.IsNotNull(), svc::ResultInvalidHandle()); /* Get the parent, and persist a reference to it until we're done. */ KScopedAutoObject parent = session->GetParent(); MESOSPHERE_ASSERT(parent.IsNotNull()); /* Send the request. */ R_RETURN(session->SendSyncRequest(message, buffer_size)); } ALWAYS_INLINE Result ReplyAndReceiveImpl(int32_t *out_index, uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr, KSynchronizationObject **objs, int32_t num_objects, ams::svc::Handle reply_target, int64_t timeout_ns) { /* Reply to the target, if one is specified. */ if (reply_target != ams::svc::InvalidHandle) { KScopedAutoObject session = GetCurrentProcess().GetHandleTable().GetObject<KServerSession>(reply_target); R_UNLESS(session.IsNotNull(), svc::ResultInvalidHandle()); /* If we fail to reply, we want to set the output index to -1. */ ON_RESULT_FAILURE { *out_index = -1; }; /* Send the reply. */ R_TRY(session->SendReply(message, buffer_size, message_paddr)); } /* Receive a message. */ { /* Convert the timeout from nanoseconds to ticks. */ /* NOTE: Nintendo does not use this conversion logic in WaitSynchronization... */ s64 timeout; if (timeout_ns > 0) { const ams::svc::Tick offset_tick(TimeSpan::FromNanoSeconds(timeout_ns)); if (AMS_LIKELY(offset_tick > 0)) { timeout = KHardwareTimer::GetTick() + offset_tick + 2; if (AMS_UNLIKELY(timeout <= 0)) { timeout = std::numeric_limits<s64>::max(); } } else { timeout = std::numeric_limits<s64>::max(); } } else { timeout = timeout_ns; } /* Wait for a message. */ while (true) { /* Close any pending objects before we wait. */ GetCurrentThread().DestroyClosedObjects(); /* Wait for an object. */ s32 index; Result result = KSynchronizationObject::Wait(std::addressof(index), objs, num_objects, timeout); if (svc::ResultTimedOut::Includes(result)) { R_THROW(result); } /* Receive the request. */ if (R_SUCCEEDED(result)) { KServerSession *session = objs[index]->DynamicCast<KServerSession *>(); if (session != nullptr) { result = session->ReceiveRequest(message, buffer_size, message_paddr); if (svc::ResultNotFound::Includes(result)) { continue; } } } *out_index = index; R_RETURN(result); } } } ALWAYS_INLINE Result ReplyAndReceiveImpl(int32_t *out_index, uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr, KUserPointer<const ams::svc::Handle *> user_handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { /* Ensure number of handles is valid. */ R_UNLESS(0 <= num_handles && num_handles <= ams::svc::ArgumentHandleCountMax, svc::ResultOutOfRange()); /* Get the synchronization context. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); KSynchronizationObject **objs = GetCurrentThread().GetSynchronizationObjectBuffer(); ams::svc::Handle *handles = GetCurrentThread().GetHandleBuffer(); /* Copy user handles. */ if (num_handles > 0) { /* Ensure that we can try to get the handles. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); /* Get the handles. */ R_TRY(user_handles.CopyArrayTo(handles, num_handles)); /* Convert the handles to objects. */ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles), svc::ResultInvalidHandle()); } /* Ensure handles are closed when we're done. */ ON_SCOPE_EXIT { for (auto i = 0; i < num_handles; ++i) { objs[i]->Close(); } }; R_RETURN(ReplyAndReceiveImpl(out_index, message, buffer_size, message_paddr, objs, num_handles, reply_target, timeout_ns)); } ALWAYS_INLINE Result SendSyncRequest(ams::svc::Handle session_handle) { R_RETURN(SendSyncRequestImpl(0, 0, session_handle)); } ALWAYS_INLINE Result SendSyncRequestWithUserBuffer(uintptr_t message, size_t buffer_size, ams::svc::Handle session_handle) { /* Validate that the message buffer is page aligned and does not overflow. */ R_UNLESS(util::IsAligned(message, PageSize), svc::ResultInvalidAddress()); R_UNLESS(buffer_size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(buffer_size, PageSize), svc::ResultInvalidSize()); R_UNLESS(message < message + buffer_size, svc::ResultInvalidCurrentMemory()); /* Get the process page table. */ auto &page_table = GetCurrentProcess().GetPageTable(); /* Lock the message buffer. */ R_TRY(page_table.LockForIpcUserBuffer(nullptr, message, buffer_size)); { /* If we fail to send the message, unlock the message buffer. */ ON_RESULT_FAILURE { static_cast<void>(page_table.UnlockForIpcUserBuffer(message, buffer_size)); }; /* Send the request. */ MESOSPHERE_ASSERT(message != 0); R_TRY(SendSyncRequestImpl(message, buffer_size, session_handle)); } /* We successfully processed, so try to unlock the message buffer. */ R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); } ALWAYS_INLINE Result SendAsyncRequestWithUserBufferImpl(ams::svc::Handle *out_event_handle, uintptr_t message, size_t buffer_size, ams::svc::Handle session_handle) { /* Get the process and handle table. */ auto &process = GetCurrentProcess(); auto &handle_table = process.GetHandleTable(); /* Reserve a new event from the process resource limit. */ KScopedResourceReservation event_reservation(std::addressof(process), ams::svc::LimitableResource_EventCountMax); R_UNLESS(event_reservation.Succeeded(), svc::ResultLimitReached()); /* Get the client session. */ KScopedAutoObject session = GetCurrentProcess().GetHandleTable().GetObject<KClientSession>(session_handle); R_UNLESS(session.IsNotNull(), svc::ResultInvalidHandle()); /* Get the parent, and persist a reference to it until we're done. */ KScopedAutoObject parent = session->GetParent(); MESOSPHERE_ASSERT(parent.IsNotNull()); /* Create a new event. */ KEvent *event = KEvent::Create(); R_UNLESS(event != nullptr, svc::ResultOutOfResource()); /* Initialize the event. */ event->Initialize(); /* Commit our reservation. */ event_reservation.Commit(); /* At end of scope, kill the standing event references. */ ON_SCOPE_EXIT { event->GetReadableEvent().Close(); event->Close(); }; /* Register the event. */ KEvent::Register(event); /* Add the readable event to the handle table. */ R_TRY(handle_table.Add(out_event_handle, std::addressof(event->GetReadableEvent()))); /* Ensure that if we fail to send the request, we close the readable handle. */ ON_RESULT_FAILURE { handle_table.Remove(*out_event_handle); }; /* Send the async request. */ R_RETURN(session->SendAsyncRequest(event, message, buffer_size)); } ALWAYS_INLINE Result SendAsyncRequestWithUserBuffer(ams::svc::Handle *out_event_handle, uintptr_t message, size_t buffer_size, ams::svc::Handle session_handle) { /* Validate that the message buffer is page aligned and does not overflow. */ R_UNLESS(util::IsAligned(message, PageSize), svc::ResultInvalidAddress()); R_UNLESS(buffer_size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(buffer_size, PageSize), svc::ResultInvalidSize()); R_UNLESS(message < message + buffer_size, svc::ResultInvalidCurrentMemory()); /* Get the process page table. */ auto &page_table = GetCurrentProcess().GetPageTable(); /* Lock the message buffer. */ R_TRY(page_table.LockForIpcUserBuffer(nullptr, message, buffer_size)); /* Ensure that if we fail and aren't terminating that we unlock the user buffer. */ ON_RESULT_FAILURE_BESIDES(svc::ResultTerminationRequested) { static_cast<void>(page_table.UnlockForIpcUserBuffer(message, buffer_size)); }; /* Send the request. */ MESOSPHERE_ASSERT(message != 0); R_RETURN(SendAsyncRequestWithUserBufferImpl(out_event_handle, message, buffer_size, session_handle)); } ALWAYS_INLINE Result ReplyAndReceive(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(ReplyAndReceiveImpl(out_index, 0, 0, Null<KPhysicalAddress>, handles, num_handles, reply_target, timeout_ns)); } ALWAYS_INLINE Result ReplyAndReceiveWithUserBuffer(int32_t *out_index, uintptr_t message, size_t buffer_size, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { /* Validate that the message buffer is page aligned and does not overflow. */ R_UNLESS(util::IsAligned(message, PageSize), svc::ResultInvalidAddress()); R_UNLESS(buffer_size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(buffer_size, PageSize), svc::ResultInvalidSize()); R_UNLESS(message < message + buffer_size, svc::ResultInvalidCurrentMemory()); /* Get the process page table. */ auto &page_table = GetCurrentProcess().GetPageTable(); /* Lock the message buffer, getting its physical address. */ KPhysicalAddress message_paddr; R_TRY(page_table.LockForIpcUserBuffer(std::addressof(message_paddr), message, buffer_size)); { /* If we fail to send the message, unlock the message buffer. */ ON_RESULT_FAILURE { static_cast<void>(page_table.UnlockForIpcUserBuffer(message, buffer_size)); }; /* Reply/Receive the request. */ MESOSPHERE_ASSERT(message != 0); R_TRY(ReplyAndReceiveImpl(out_index, message, buffer_size, message_paddr, handles, num_handles, reply_target, timeout_ns)); } /* We successfully processed, so try to unlock the message buffer. */ R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); } } /* ============================= 64 ABI ============================= */ Result SendSyncRequest64(ams::svc::Handle session_handle) { R_RETURN(SendSyncRequest(session_handle)); } Result SendSyncRequestWithUserBuffer64(ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, ams::svc::Handle session_handle) { R_RETURN(SendSyncRequestWithUserBuffer(message_buffer, message_buffer_size, session_handle)); } Result SendAsyncRequestWithUserBuffer64(ams::svc::Handle *out_event_handle, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, ams::svc::Handle session_handle) { R_RETURN(SendAsyncRequestWithUserBuffer(out_event_handle, message_buffer, message_buffer_size, session_handle)); } Result ReplyAndReceive64(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(ReplyAndReceive(out_index, handles, num_handles, reply_target, timeout_ns)); } Result ReplyAndReceiveWithUserBuffer64(int32_t *out_index, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(ReplyAndReceiveWithUserBuffer(out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns)); } /* ============================= 64From32 ABI ============================= */ Result SendSyncRequest64From32(ams::svc::Handle session_handle) { R_RETURN(SendSyncRequest(session_handle)); } Result SendSyncRequestWithUserBuffer64From32(ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, ams::svc::Handle session_handle) { R_RETURN(SendSyncRequestWithUserBuffer(message_buffer, message_buffer_size, session_handle)); } Result SendAsyncRequestWithUserBuffer64From32(ams::svc::Handle *out_event_handle, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, ams::svc::Handle session_handle) { R_RETURN(SendAsyncRequestWithUserBuffer(out_event_handle, message_buffer, message_buffer_size, session_handle)); } Result ReplyAndReceive64From32(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(ReplyAndReceive(out_index, handles, num_handles, reply_target, timeout_ns)); } Result ReplyAndReceiveWithUserBuffer64From32(int32_t *out_index, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(ReplyAndReceiveWithUserBuffer(out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns)); } } #pragma GCC pop_options ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_kernel_debug.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { void KernelDebug(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { MESOSPHERE_UNUSED(kern_debug_type, arg0, arg1, arg2); #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING { switch (kern_debug_type) { case ams::svc::KernelDebugType_Thread: if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpThread(); } else { KDumpObject::DumpThread(arg0); } break; case ams::svc::KernelDebugType_ThreadCallStack: if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpThreadCallStack(); } else { KDumpObject::DumpThreadCallStack(arg0); } break; case ams::svc::KernelDebugType_KernelObject: KDumpObject::DumpKernelObject(); break; case ams::svc::KernelDebugType_Handle: if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpHandle(); } else { KDumpObject::DumpHandle(arg0); } break; case ams::svc::KernelDebugType_Memory: if (arg0 == static_cast<u64>(-2)) { KDumpObject::DumpKernelMemory(); } else if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpMemory(); } else { KDumpObject::DumpMemory(arg0); } break; case ams::svc::KernelDebugType_PageTable: if (arg0 == static_cast<u64>(-2)) { KDumpObject::DumpKernelPageTable(); } else if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpPageTable(); } else { KDumpObject::DumpPageTable(arg0); } break; case ams::svc::KernelDebugType_CpuUtilization: { const auto old_prio = GetCurrentThread().GetBasePriority(); GetCurrentThread().SetBasePriority(3); if (arg0 == static_cast<u64>(-2)) { KDumpObject::DumpKernelCpuUtilization(); } else if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpCpuUtilization(); } else { KDumpObject::DumpCpuUtilization(arg0); } GetCurrentThread().SetBasePriority(old_prio); } break; case ams::svc::KernelDebugType_Process: if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpProcess(); } else { KDumpObject::DumpProcess(arg0); } break; case ams::svc::KernelDebugType_SuspendProcess: if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Paused))) { MESOSPHERE_RELEASE_LOG("Suspend Process ID=%3lu\n", process->GetId()); } } break; case ams::svc::KernelDebugType_ResumeProcess: if (KProcess *process = KProcess::GetProcessFromId(arg0); process != nullptr) { ON_SCOPE_EXIT { process->Close(); }; if (R_SUCCEEDED(process->SetActivity(ams::svc::ProcessActivity_Runnable))) { MESOSPHERE_RELEASE_LOG("Resume Process ID=%3lu\n", process->GetId()); } } break; case ams::svc::KernelDebugType_Port: if (arg0 == static_cast<u64>(-1)) { KDumpObject::DumpPort(); } else { KDumpObject::DumpPort(arg0); } break; default: break; } } #endif } void ChangeKernelTraceState(ams::svc::KernelTraceState kern_trace_state) { #ifdef MESOSPHERE_BUILD_FOR_DEBUGGING { switch (kern_trace_state) { case ams::svc::KernelTraceState_Enabled: { MESOSPHERE_KTRACE_RESUME(); } break; case ams::svc::KernelTraceState_Disabled: { MESOSPHERE_KTRACE_PAUSE(); } break; default: break; } } #else { MESOSPHERE_UNUSED(kern_trace_state); } #endif } } /* ============================= 64 ABI ============================= */ void KernelDebug64(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return KernelDebug(kern_debug_type, arg0, arg1, arg2); } void ChangeKernelTraceState64(ams::svc::KernelTraceState kern_trace_state) { return ChangeKernelTraceState(kern_trace_state); } /* ============================= 64From32 ABI ============================= */ void KernelDebug64From32(ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return KernelDebug(kern_debug_type, arg0, arg1, arg2); } void ChangeKernelTraceState64From32(ams::svc::KernelTraceState kern_trace_state) { return ChangeKernelTraceState(kern_trace_state); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_light_ipc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { ALWAYS_INLINE Result SendSyncRequestLight(ams::svc::Handle session_handle, u32 *args) { /* Get the light client session from its handle. */ KScopedAutoObject session = GetCurrentProcess().GetHandleTable().GetObject<KLightClientSession>(session_handle); R_UNLESS(session.IsNotNull(), svc::ResultInvalidHandle()); /* Send the request. */ R_TRY(session->SendSyncRequest(args)); R_SUCCEED(); } ALWAYS_INLINE Result ReplyAndReceiveLight(ams::svc::Handle session_handle, u32 *args) { /* Get the light server session from its handle. */ KScopedAutoObject session = GetCurrentProcess().GetHandleTable().GetObject<KLightServerSession>(session_handle); R_UNLESS(session.IsNotNull(), svc::ResultInvalidHandle()); /* Handle the request. */ R_TRY(session->ReplyAndReceive(args)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result SendSyncRequestLight64(ams::svc::Handle session_handle, u32 *args) { R_RETURN(SendSyncRequestLight(session_handle, args)); } Result ReplyAndReceiveLight64(ams::svc::Handle session_handle, u32 *args) { R_RETURN(ReplyAndReceiveLight(session_handle, args)); } /* ============================= 64From32 ABI ============================= */ Result SendSyncRequestLight64From32(ams::svc::Handle session_handle, u32 *args) { R_RETURN(SendSyncRequestLight(session_handle, args)); } Result ReplyAndReceiveLight64From32(ams::svc::Handle session_handle, u32 *args) { R_RETURN(ReplyAndReceiveLight(session_handle, args)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_lock.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsKernelAddress(uintptr_t address) { return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; } Result ArbitrateLock(ams::svc::Handle thread_handle, uintptr_t address, uint32_t tag) { /* Validate the input address. */ R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress()); R_RETURN(KConditionVariable::WaitForAddress(thread_handle, address, tag)); } Result ArbitrateUnlock(uintptr_t address) { /* Validate the input address. */ R_UNLESS(!IsKernelAddress(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(util::IsAligned(address, sizeof(u32)), svc::ResultInvalidAddress()); R_RETURN(KConditionVariable::SignalToAddress(address)); } } /* ============================= 64 ABI ============================= */ Result ArbitrateLock64(ams::svc::Handle thread_handle, ams::svc::Address address, uint32_t tag) { R_RETURN(ArbitrateLock(thread_handle, address, tag)); } Result ArbitrateUnlock64(ams::svc::Address address) { R_RETURN(ArbitrateUnlock(address)); } /* ============================= 64From32 ABI ============================= */ Result ArbitrateLock64From32(ams::svc::Handle thread_handle, ams::svc::Address address, uint32_t tag) { R_RETURN(ArbitrateLock(thread_handle, address, tag)); } Result ArbitrateUnlock64From32(ams::svc::Address address) { R_RETURN(ArbitrateUnlock(address)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidSetMemoryPermission(ams::svc::MemoryPermission perm) { switch (perm) { case ams::svc::MemoryPermission_None: case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_ReadWrite: return true; default: return false; } } Result SetMemoryPermission(uintptr_t address, size_t size, ams::svc::MemoryPermission perm) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Validate the permission. */ R_UNLESS(IsValidSetMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Validate that the region is in range for the current process. */ auto &page_table = GetCurrentProcess().GetPageTable(); R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Set the memory attribute. */ R_RETURN(page_table.SetMemoryPermission(address, size, perm)); } Result SetMemoryAttribute(uintptr_t address, size_t size, uint32_t mask, uint32_t attr) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Validate the attribute and mask. */ constexpr u32 SupportedMask = ams::svc::MemoryAttribute_Uncached | ams::svc::MemoryAttribute_PermissionLocked; R_UNLESS((mask | attr) == mask, svc::ResultInvalidCombination()); R_UNLESS((mask | attr | SupportedMask) == SupportedMask, svc::ResultInvalidCombination()); /* Check that permission locked is either being set or not masked. */ R_UNLESS((mask & ams::svc::MemoryAttribute_PermissionLocked) == (attr & ams::svc::MemoryAttribute_PermissionLocked), svc::ResultInvalidCombination()); /* Validate that the region is in range for the current process. */ auto &page_table = GetCurrentProcess().GetPageTable(); R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Set the memory attribute. */ R_RETURN(page_table.SetMemoryAttribute(address, size, mask, attr)); } Result MapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) { /* Validate that addresses are page aligned. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); /* Validate that size is positive and page aligned. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); /* Ensure that neither mapping overflows. */ R_UNLESS(src_address < src_address + size, svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_address < dst_address + size, svc::ResultInvalidCurrentMemory()); /* Get the page table we're operating on. */ auto &page_table = GetCurrentProcess().GetPageTable(); /* Ensure that the memory we're mapping is in range. */ R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_Stack), svc::ResultInvalidMemoryRegion()); /* Map the memory. */ R_RETURN(page_table.MapMemory(dst_address, src_address, size)); } Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) { /* Validate that addresses are page aligned. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); /* Validate that size is positive and page aligned. */ R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); /* Ensure that neither mapping overflows. */ R_UNLESS(src_address < src_address + size, svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_address < dst_address + size, svc::ResultInvalidCurrentMemory()); /* Get the page table we're operating on. */ auto &page_table = GetCurrentProcess().GetPageTable(); /* Ensure that the memory we're unmapping is in range. */ R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_Stack), svc::ResultInvalidMemoryRegion()); /* Unmap the memory. */ R_RETURN(page_table.UnmapMemory(dst_address, src_address, size)); } } /* ============================= 64 ABI ============================= */ Result SetMemoryPermission64(ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { R_RETURN(SetMemoryPermission(address, size, perm)); } Result SetMemoryAttribute64(ams::svc::Address address, ams::svc::Size size, uint32_t mask, uint32_t attr) { R_RETURN(SetMemoryAttribute(address, size, mask, attr)); } Result MapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { R_RETURN(MapMemory(dst_address, src_address, size)); } Result UnmapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { R_RETURN(UnmapMemory(dst_address, src_address, size)); } /* ============================= 64From32 ABI ============================= */ Result SetMemoryPermission64From32(ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission perm) { R_RETURN(SetMemoryPermission(address, size, perm)); } Result SetMemoryAttribute64From32(ams::svc::Address address, ams::svc::Size size, uint32_t mask, uint32_t attr) { R_RETURN(SetMemoryAttribute(address, size, mask, attr)); } Result MapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { R_RETURN(MapMemory(dst_address, src_address, size)); } Result UnmapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) { R_RETURN(UnmapMemory(dst_address, src_address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_physical_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result SetHeapSize(uintptr_t *out_address, size_t size) { /* Validate size. */ R_UNLESS(util::IsAligned(size, ams::svc::HeapSizeAlignment), svc::ResultInvalidSize()); R_UNLESS(size < ams::kern::MainMemorySizeMax, svc::ResultInvalidSize()); /* Set the heap size. */ KProcessAddress address = Null<KProcessAddress>; R_TRY(GetCurrentProcess().GetPageTable().SetHeapSize(std::addressof(address), size)); /* Set the output. */ *out_address = GetInteger(address); R_SUCCEED(); } Result SetUnsafeLimit(size_t limit) { /* Ensure the size is aligned. */ R_UNLESS(util::IsAligned(limit, PageSize), svc::ResultInvalidSize()); /* Ensure that the size is not bigger than we can accommodate. */ R_UNLESS(limit <= Kernel::GetMemoryManager().GetSize(KMemoryManager::Pool_Unsafe), svc::ResultOutOfRange()); /* Set the size. */ R_RETURN(Kernel::GetUnsafeMemory().SetLimitSize(limit)); } Result MapPhysicalMemory(uintptr_t address, size_t size) { /* Validate address / size. */ const size_t min_alignment = Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool()); R_UNLESS(util::IsAligned(address, min_alignment), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, min_alignment), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion()); /* Verify that the process has system resource. */ auto &process = GetCurrentProcess(); R_UNLESS(process.GetTotalSystemResourceSize() > 0, svc::ResultInvalidState()); /* Verify that the region is in range. */ auto &page_table = process.GetPageTable(); R_UNLESS(page_table.IsInAliasRegion(address, size), svc::ResultInvalidMemoryRegion()); /* Map the memory. */ R_TRY(page_table.MapPhysicalMemory(address, size)); R_SUCCEED(); } Result UnmapPhysicalMemory(uintptr_t address, size_t size) { /* Validate address / size. */ const size_t min_alignment = Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool()); R_UNLESS(util::IsAligned(address, min_alignment), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, min_alignment), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidMemoryRegion()); /* Verify that the process has system resource. */ auto &process = GetCurrentProcess(); R_UNLESS(process.GetTotalSystemResourceSize() > 0, svc::ResultInvalidState()); /* Verify that the region is in range. */ auto &page_table = process.GetPageTable(); R_UNLESS(page_table.IsInAliasRegion(address, size), svc::ResultInvalidMemoryRegion()); /* Unmap the memory. */ R_TRY(page_table.UnmapPhysicalMemory(address, size)); R_SUCCEED(); } Result MapPhysicalMemoryUnsafe(uintptr_t address, size_t size) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the region is in range. */ auto &process = GetCurrentProcess(); auto &page_table = process.GetPageTable(); R_UNLESS(page_table.IsInUnsafeAliasRegion(address, size), svc::ResultInvalidMemoryRegion()); /* Verify that the process isn't already using the unsafe pool. */ R_UNLESS(process.GetMemoryPool() != KMemoryManager::Pool_Unsafe, svc::ResultInvalidMemoryPool()); /* Map the memory. */ R_TRY(page_table.MapPhysicalMemoryUnsafe(address, size)); R_SUCCEED(); } Result UnmapPhysicalMemoryUnsafe(uintptr_t address, size_t size) { /* Validate address / size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Verify that the region is in range. */ auto &process = GetCurrentProcess(); auto &page_table = process.GetPageTable(); R_UNLESS(page_table.IsInUnsafeAliasRegion(address, size), svc::ResultInvalidMemoryRegion()); /* Unmap the memory. */ R_TRY(page_table.UnmapPhysicalMemoryUnsafe(address, size)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result SetHeapSize64(ams::svc::Address *out_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); R_RETURN(SetHeapSize(reinterpret_cast<uintptr_t *>(out_address), size)); } Result MapPhysicalMemory64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapPhysicalMemory(address, size)); } Result UnmapPhysicalMemory64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapPhysicalMemory(address, size)); } Result MapPhysicalMemoryUnsafe64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapPhysicalMemoryUnsafe(address, size)); } Result UnmapPhysicalMemoryUnsafe64(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapPhysicalMemoryUnsafe(address, size)); } Result SetUnsafeLimit64(ams::svc::Size limit) { R_RETURN(SetUnsafeLimit(limit)); } /* ============================= 64From32 ABI ============================= */ Result SetHeapSize64From32(ams::svc::Address *out_address, ams::svc::Size size) { static_assert(sizeof(*out_address) == sizeof(uintptr_t)); R_RETURN(SetHeapSize(reinterpret_cast<uintptr_t *>(out_address), size)); } Result MapPhysicalMemory64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapPhysicalMemory(address, size)); } Result UnmapPhysicalMemory64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapPhysicalMemory(address, size)); } Result MapPhysicalMemoryUnsafe64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(MapPhysicalMemoryUnsafe(address, size)); } Result UnmapPhysicalMemoryUnsafe64From32(ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapPhysicalMemoryUnsafe(address, size)); } Result SetUnsafeLimit64From32(ams::svc::Size limit) { R_RETURN(SetUnsafeLimit(limit)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_port.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result ManageNamedPort(ams::svc::Handle *out_server_handle, KUserPointer<const char *> user_name, s32 max_sessions) { /* Copy the provided name from user memory to kernel memory. */ char name[KObjectName::NameLengthMax] = {}; R_TRY(user_name.CopyStringTo(name, sizeof(name))); /* Validate that sessions and name are valid. */ R_UNLESS(max_sessions >= 0, svc::ResultOutOfRange()); R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange()); if (max_sessions > 0) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Create a new port. */ KPort *port = KPort::Create(); R_UNLESS(port != nullptr, svc::ResultOutOfResource()); /* Initialize the new port. */ port->Initialize(max_sessions, false, 0); /* Register the port. */ KPort::Register(port); /* Ensure that our only reference to the port is in the handle table when we're done. */ ON_SCOPE_EXIT { port->GetClientPort().Close(); port->GetServerPort().Close(); }; /* Register the handle in the table. */ R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); ON_RESULT_FAILURE { handle_table.Remove(*out_server_handle); }; /* Create a new object name. */ R_TRY(KObjectName::NewFromName(std::addressof(port->GetClientPort()), name)); } else /* if (max_sessions == 0) */ { /* Ensure that this else case is correct. */ MESOSPHERE_AUDIT(max_sessions == 0); /* If we're closing, there's no server handle. */ *out_server_handle = ams::svc::InvalidHandle; /* Delete the object. */ R_TRY(KObjectName::Delete<KClientPort>(name)); } R_SUCCEED(); } Result CreatePort(ams::svc::Handle *out_server, ams::svc::Handle *out_client, int32_t max_sessions, bool is_light, uintptr_t name) { /* Ensure max sessions is valid. */ R_UNLESS(max_sessions > 0, svc::ResultOutOfRange()); /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Create a new port. */ KPort *port = KPort::Create(); R_UNLESS(port != nullptr, svc::ResultOutOfResource()); /* Initialize the port. */ port->Initialize(max_sessions, is_light, name); /* Ensure that we clean up the port (and its only references are handle table) on function end. */ ON_SCOPE_EXIT { port->GetServerPort().Close(); port->GetClientPort().Close(); }; /* Register the port. */ KPort::Register(port); /* Add the client to the handle table. */ R_TRY(handle_table.Add(out_client, std::addressof(port->GetClientPort()))); /* Ensure that we maintain a clean handle state on exit. */ ON_RESULT_FAILURE { handle_table.Remove(*out_client); }; /* Add the server to the handle table. */ R_RETURN(handle_table.Add(out_server, std::addressof(port->GetServerPort()))); } Result ConnectToNamedPort(ams::svc::Handle *out, KUserPointer<const char *> user_name) { /* Copy the provided name from user memory to kernel memory. */ char name[KObjectName::NameLengthMax] = {}; R_TRY(user_name.CopyStringTo(name, sizeof(name))); /* Validate that name is valid. */ R_UNLESS(name[sizeof(name) - 1] == '\x00', svc::ResultOutOfRange()); /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Find the client port. */ auto port = KObjectName::Find<KClientPort>(name); R_UNLESS(port.IsNotNull(), svc::ResultNotFound()); /* Reserve a handle for the port. */ /* NOTE: Nintendo really does write directly to the output handle here. */ R_TRY(handle_table.Reserve(out)); ON_RESULT_FAILURE { handle_table.Unreserve(*out); }; /* Create a session. */ KClientSession *session; R_TRY(port->CreateSession(std::addressof(session))); /* Register the session in the table, close the extra reference. */ handle_table.Register(*out, session); session->Close(); /* We succeeded. */ R_SUCCEED(); } Result ConnectToPort(ams::svc::Handle *out, ams::svc::Handle port) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Get the client port. */ KScopedAutoObject client_port = handle_table.GetObject<KClientPort>(port); R_UNLESS(client_port.IsNotNull(), svc::ResultInvalidHandle()); /* Reserve a handle for the port. */ /* NOTE: Nintendo really does write directly to the output handle here. */ R_TRY(handle_table.Reserve(out)); ON_RESULT_FAILURE { handle_table.Unreserve(*out); }; /* Create the session. */ KAutoObject *session; if (client_port->IsLight()) { R_TRY(client_port->CreateLightSession(reinterpret_cast<KLightClientSession **>(std::addressof(session)))); } else { R_TRY(client_port->CreateSession(reinterpret_cast<KClientSession **>(std::addressof(session)))); } /* Register the session. */ handle_table.Register(*out, session); session->Close(); /* We succeeded. */ R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result ConnectToNamedPort64(ams::svc::Handle *out_handle, KUserPointer<const char *> name) { R_RETURN(ConnectToNamedPort(out_handle, name)); } Result CreatePort64(ams::svc::Handle *out_server_handle, ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ams::svc::Address name) { R_RETURN(CreatePort(out_server_handle, out_client_handle, max_sessions, is_light, name)); } Result ManageNamedPort64(ams::svc::Handle *out_server_handle, KUserPointer<const char *> name, int32_t max_sessions) { R_RETURN(ManageNamedPort(out_server_handle, name, max_sessions)); } Result ConnectToPort64(ams::svc::Handle *out_handle, ams::svc::Handle port) { R_RETURN(ConnectToPort(out_handle, port)); } /* ============================= 64From32 ABI ============================= */ Result ConnectToNamedPort64From32(ams::svc::Handle *out_handle, KUserPointer<const char *> name) { R_RETURN(ConnectToNamedPort(out_handle, name)); } Result CreatePort64From32(ams::svc::Handle *out_server_handle, ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ams::svc::Address name) { R_RETURN(CreatePort(out_server_handle, out_client_handle, max_sessions, is_light, name)); } Result ManageNamedPort64From32(ams::svc::Handle *out_server_handle, KUserPointer<const char *> name, int32_t max_sessions) { R_RETURN(ManageNamedPort(out_server_handle, name, max_sessions)); } Result ConnectToPort64From32(ams::svc::Handle *out_handle, ams::svc::Handle port) { R_RETURN(ConnectToPort(out_handle, port)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_power_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { void SleepSystem() { return KSystemControl::SleepSystem(); } } /* ============================= 64 ABI ============================= */ void SleepSystem64() { return SleepSystem(); } /* ============================= 64From32 ABI ============================= */ void SleepSystem64From32() { return SleepSystem(); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_process.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidVirtualCoreId(int32_t core_id) { return (0 <= core_id && core_id < static_cast<int32_t>(cpu::NumVirtualCores)); } void ExitProcess() { GetCurrentProcess().Exit(); MESOSPHERE_PANIC("Process survived call to exit"); } Result GetProcessId(u64 *out_process_id, ams::svc::Handle handle) { /* Get the object from the handle table. */ KScopedAutoObject obj = GetCurrentProcess().GetHandleTable().GetObject<KAutoObject>(handle); R_UNLESS(obj.IsNotNull(), svc::ResultInvalidHandle()); /* Get the process from the object. */ if (KProcess *process = obj->DynamicCast<KProcess *>(); process != nullptr) { /* The object is a process, so we can use it directly. */ /* Make sure the target process exists. */ R_UNLESS(process != nullptr, svc::ResultInvalidHandle()); /* Get the process id. */ *out_process_id = process->GetId(); } else if (KThread *t = obj->DynamicCast<KThread *>(); t != nullptr) { /* The object is a thread, so we want to use its parent. */ KProcess *process = t->GetOwnerProcess(); /* Make sure the target process exists. */ R_UNLESS(process != nullptr, svc::ResultInvalidHandle()); /* Get the process id. */ *out_process_id = process->GetId(); } else if (KDebug *d = obj->DynamicCast<KDebug *>(); d != nullptr) { /* The object is a debug, so we want to use the process it's attached to. */ /* Make sure the target process exists. */ R_UNLESS(d->IsAttached(), svc::ResultInvalidHandle()); R_UNLESS(d->OpenProcess(), svc::ResultInvalidHandle()); ON_SCOPE_EXIT { d->CloseProcess(); }; /* Get the process id. */ *out_process_id = d->GetProcessUnsafe()->GetProcessId(); } else { R_THROW(svc::ResultInvalidHandle()); } R_SUCCEED(); } Result GetProcessList(int32_t *out_num_processes, KUserPointer<uint64_t *> out_process_ids, int32_t max_out_count) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Validate that the out count is valid. */ R_UNLESS((0 <= max_out_count && max_out_count <= static_cast<int32_t>(std::numeric_limits<int32_t>::max() / sizeof(u64))), svc::ResultOutOfRange()); /* Validate that the pointer is in range. */ if (max_out_count > 0) { R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_process_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); } /* Get the process list. */ R_RETURN(KProcess::GetProcessList(out_num_processes, out_process_ids, max_out_count)); } Result CreateProcess(ams::svc::Handle *out, const ams::svc::CreateProcessParameter ¶ms, KUserPointer<const uint32_t *> user_caps, int32_t num_caps) { /* Validate the capabilities pointer. */ R_UNLESS(num_caps >= 0, svc::ResultInvalidPointer()); if (num_caps > 0) { /* Check for overflow. */ R_UNLESS(((num_caps * sizeof(u32)) / sizeof(u32)) == static_cast<size_t>(num_caps), svc::ResultInvalidPointer()); /* Validate that the pointer is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_caps.GetUnsafePointer()), num_caps * sizeof(u32)), svc::ResultInvalidPointer()); } /* Validate that the parameter flags are valid. */ R_UNLESS((params.flags & ~ams::svc::CreateProcessFlag_All) == 0, svc::ResultInvalidEnumValue()); /* Validate that 64-bit process is okay. */ const bool is_64_bit = (params.flags & ams::svc::CreateProcessFlag_Is64Bit) != 0; if constexpr (sizeof(void *) < sizeof(u64)) { R_UNLESS(!is_64_bit, svc::ResultInvalidCombination()); } /* Decide on an address space map region. */ uintptr_t map_start, map_end; size_t map_size; const size_t code_size = params.code_num_pages * PageSize; switch (params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) { case ams::svc::CreateProcessFlag_AddressSpace32Bit: case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias: { map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall, code_size); map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall); map_end = map_start + map_size; } break; case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated: { /* 64-bit address space requires 64-bit process. */ R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall, code_size); map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall); map_end = map_start + map_size; } break; case ams::svc::CreateProcessFlag_AddressSpace64Bit: { /* 64-bit address space requires 64-bit process. */ R_UNLESS(is_64_bit, svc::ResultInvalidCombination()); map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit, code_size); map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit); map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Heap); } break; default: R_THROW(svc::ResultInvalidEnumValue()); } /* Validate the pool partition. */ if (GetTargetFirmware() >= TargetFirmware_5_0_0) { switch (params.flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { case ams::svc::CreateProcessFlag_PoolPartitionApplication: case ams::svc::CreateProcessFlag_PoolPartitionApplet: case ams::svc::CreateProcessFlag_PoolPartitionSystem: case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: break; default: R_THROW(svc::ResultInvalidEnumValue()); } } /* Check that the code address is aligned. */ R_UNLESS(util::IsAligned(params.code_address, KProcess::AslrAlignment), svc::ResultInvalidAddress()); /* Check that the number of code pages is >= 0. */ R_UNLESS(params.code_num_pages >= 0, svc::ResultInvalidSize()); /* Check that the number of extra resource pages is >= 0. */ R_UNLESS(params.system_resource_num_pages >= 0, svc::ResultInvalidSize()); /* Validate that the alias region extra size is allowed, if enabled. */ if (params.flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) { /* Check that we have a 64-bit address space. */ R_UNLESS((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace64Bit, svc::ResultInvalidState()); /* Check that the system resource page count is non-zero. */ R_UNLESS(params.system_resource_num_pages > 0, svc::ResultInvalidState()); /* Check that debug mode is enabled. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultInvalidState()); } /* Convert to sizes. */ const size_t code_num_pages = params.code_num_pages; const size_t system_resource_num_pages = params.system_resource_num_pages; const size_t total_pages = code_num_pages + system_resource_num_pages; const size_t system_resource_size = system_resource_num_pages * PageSize; const size_t total_size = code_size + system_resource_size; /* Check for overflow. */ R_UNLESS((code_size / PageSize) == code_num_pages, svc::ResultInvalidSize()); R_UNLESS((system_resource_size / PageSize) == system_resource_num_pages, svc::ResultInvalidSize()); R_UNLESS((code_num_pages + system_resource_num_pages) >= code_num_pages, svc::ResultOutOfMemory()); R_UNLESS((total_size / PageSize) == total_pages, svc::ResultInvalidSize()); /* Check that the number of pages is valid. */ R_UNLESS(code_num_pages < (map_size / PageSize), svc::ResultInvalidMemoryRegion()); /* Validate that the code falls within the map reigon. */ R_UNLESS(map_start <= params.code_address, svc::ResultInvalidMemoryRegion()); R_UNLESS(params.code_address < params.code_address + code_size, svc::ResultInvalidMemoryRegion()); R_UNLESS(params.code_address + code_size - 1 <= map_end - 1, svc::ResultInvalidMemoryRegion()); /* Check that the number of pages is valid for the kernel address space. */ R_UNLESS(code_num_pages < (kern::MainMemorySizeMax / PageSize), svc::ResultOutOfMemory()); R_UNLESS(system_resource_num_pages < (kern::MainMemorySizeMax / PageSize), svc::ResultOutOfMemory()); R_UNLESS(total_pages < (kern::MainMemorySizeMax / PageSize), svc::ResultOutOfMemory()); /* Check that optimized memory allocation is used only for applications. */ const bool optimize_allocs = (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0; const bool is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0; R_UNLESS(!optimize_allocs || is_application, svc::ResultBusy()); /* Check that the user-provided capabilities are accessible and refer to valid regions. */ R_TRY(KCapabilities::CheckCapabilities(user_caps, num_caps)); /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Create the new process. */ KProcess *process = KProcess::Create(); R_UNLESS(process != nullptr, svc::ResultOutOfResource()); /* Ensure that the only reference to the process is in the handle table when we're done. */ ON_SCOPE_EXIT { process->Close(); }; /* Get the resource limit from the handle. */ KScopedAutoObject resource_limit = handle_table.GetObject<KResourceLimit>(params.reslimit); R_UNLESS(resource_limit.IsNotNull() || params.reslimit == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* Decide on a resource limit for the process. */ KResourceLimit *process_resource_limit = resource_limit.IsNotNull() ? resource_limit.GetPointerUnsafe() : std::addressof(Kernel::GetSystemResourceLimit()); /* Get the pool for the process. */ const auto pool = [](u32 flags) ALWAYS_INLINE_LAMBDA -> KMemoryManager::Pool { if (GetTargetFirmware() >= TargetFirmware_5_0_0) { switch (flags & ams::svc::CreateProcessFlag_PoolPartitionMask) { case ams::svc::CreateProcessFlag_PoolPartitionApplication: return KMemoryManager::Pool_Application; case ams::svc::CreateProcessFlag_PoolPartitionApplet: return KMemoryManager::Pool_Applet; case ams::svc::CreateProcessFlag_PoolPartitionSystem: return KMemoryManager::Pool_System; case ams::svc::CreateProcessFlag_PoolPartitionSystemNonSecure: default: return KMemoryManager::Pool_SystemNonSecure; } } else if (GetTargetFirmware() >= TargetFirmware_4_0_0) { if ((flags & ams::svc::CreateProcessFlag_DeprecatedUseSecureMemory) != 0) { return KMemoryManager::Pool_Secure; } else { return static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool()); } } else { return static_cast<KMemoryManager::Pool>(KSystemControl::GetCreateProcessMemoryPool()); } }(params.flags); /* Initialize the process. */ R_TRY(process->Initialize(params, user_caps, num_caps, process_resource_limit, pool)); /* Register the process. */ KProcess::Register(process); /* Add the process to the handle table. */ R_TRY(handle_table.Add(out, process)); R_SUCCEED(); } template<typename T> Result CreateProcess(ams::svc::Handle *out, KUserPointer<const T *> user_parameters, KUserPointer<const uint32_t *> user_caps, int32_t num_caps) { /* Read the parameters from user space. */ T params; R_TRY(user_parameters.CopyTo(std::addressof(params))); /* Invoke the implementation. */ if constexpr (std::same_as<T, ams::svc::CreateProcessParameter>) { R_RETURN(CreateProcess(out, params, user_caps, num_caps)); } else { /* Convert the parameters. */ ams::svc::CreateProcessParameter converted_params; static_assert(sizeof(T{}.name) == sizeof(ams::svc::CreateProcessParameter{}.name)); std::memcpy(converted_params.name, params.name, sizeof(converted_params.name)); converted_params.version = params.version; converted_params.program_id = params.program_id; converted_params.code_address = params.code_address; converted_params.code_num_pages = params.code_num_pages; converted_params.flags = params.flags; converted_params.reslimit = params.reslimit; converted_params.system_resource_num_pages = params.system_resource_num_pages; /* Invoke. */ R_RETURN(CreateProcess(out, converted_params, user_caps, num_caps)); } } Result StartProcess(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { /* Validate stack size. */ const uint64_t aligned_stack_size = util::AlignUp(main_thread_stack_size, Kernel::GetMemoryManager().GetMinimumAlignment(GetCurrentProcess().GetMemoryPool())); R_UNLESS(aligned_stack_size >= main_thread_stack_size, svc::ResultOutOfMemory()); R_UNLESS(aligned_stack_size == static_cast<size_t>(aligned_stack_size), svc::ResultOutOfMemory()); /* Get the target process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate the core id. */ R_UNLESS(IsValidVirtualCoreId(core_id), svc::ResultInvalidCoreId()); R_UNLESS(((1ul << core_id) & process->GetCoreMask()) != 0, svc::ResultInvalidCoreId()); /* Validate the priority. */ R_UNLESS(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority, svc::ResultInvalidPriority()); R_UNLESS(process->CheckThreadPriority(priority), svc::ResultInvalidPriority()); /* Set the process's ideal processor. */ process->SetIdealCoreId(core_id); /* Run the process. */ R_RETURN(process->Run(priority, static_cast<size_t>(aligned_stack_size))); } Result TerminateProcess(ams::svc::Handle process_handle) { /* Get the target process. */ KProcess *process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle).ReleasePointerUnsafe(); R_UNLESS(process != nullptr, svc::ResultInvalidHandle()); if (process != GetCurrentProcessPointer()) { /* We're terminating another process. Close our reference after terminating the process. */ ON_SCOPE_EXIT { process->Close(); }; /* Terminate the process. */ R_TRY(process->Terminate()); } else { /* We're terminating ourselves. Close our reference immediately. */ process->Close(); /* Exit. */ ExitProcess(); } R_SUCCEED(); } Result GetProcessInfo(int64_t *out, ams::svc::Handle process_handle, ams::svc::ProcessInfoType info_type) { /* Get the target process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Get the info. */ switch (info_type) { case ams::svc::ProcessInfoType_ProcessState: { /* Get the process's state. */ KProcess::State state; { KScopedLightLock proc_lk(process->GetStateLock()); KScopedSchedulerLock sl; state = process->GetState(); } /* Convert to svc state. */ switch (state) { case KProcess::State_Created: *out = ams::svc::ProcessState_Created; break; case KProcess::State_CreatedAttached: *out = ams::svc::ProcessState_CreatedAttached; break; case KProcess::State_Running: *out = ams::svc::ProcessState_Running; break; case KProcess::State_Crashed: *out = ams::svc::ProcessState_Crashed; break; case KProcess::State_RunningAttached: *out = ams::svc::ProcessState_RunningAttached; break; case KProcess::State_Terminating: *out = ams::svc::ProcessState_Terminating; break; case KProcess::State_Terminated: *out = ams::svc::ProcessState_Terminated; break; case KProcess::State_DebugBreak: *out = ams::svc::ProcessState_DebugBreak; break; MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); } } break; default: R_THROW(svc::ResultInvalidEnumValue()); } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ void ExitProcess64() { return ExitProcess(); } Result GetProcessId64(uint64_t *out_process_id, ams::svc::Handle process_handle) { R_RETURN(GetProcessId(out_process_id, process_handle)); } Result GetProcessList64(int32_t *out_num_processes, KUserPointer<uint64_t *> out_process_ids, int32_t max_out_count) { R_RETURN(GetProcessList(out_num_processes, out_process_ids, max_out_count)); } Result CreateProcess64(ams::svc::Handle *out_handle, KUserPointer<const ams::svc::lp64::CreateProcessParameter *> parameters, KUserPointer<const uint32_t *> caps, int32_t num_caps) { R_RETURN(CreateProcess(out_handle, parameters, caps, num_caps)); } Result StartProcess64(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { R_RETURN(StartProcess(process_handle, priority, core_id, main_thread_stack_size)); } Result TerminateProcess64(ams::svc::Handle process_handle) { R_RETURN(TerminateProcess(process_handle)); } Result GetProcessInfo64(int64_t *out_info, ams::svc::Handle process_handle, ams::svc::ProcessInfoType info_type) { R_RETURN(GetProcessInfo(out_info, process_handle, info_type)); } /* ============================= 64From32 ABI ============================= */ void ExitProcess64From32() { return ExitProcess(); } Result GetProcessId64From32(uint64_t *out_process_id, ams::svc::Handle process_handle) { R_RETURN(GetProcessId(out_process_id, process_handle)); } Result GetProcessList64From32(int32_t *out_num_processes, KUserPointer<uint64_t *> out_process_ids, int32_t max_out_count) { R_RETURN(GetProcessList(out_num_processes, out_process_ids, max_out_count)); } Result CreateProcess64From32(ams::svc::Handle *out_handle, KUserPointer<const ams::svc::ilp32::CreateProcessParameter *> parameters, KUserPointer<const uint32_t *> caps, int32_t num_caps) { R_RETURN(CreateProcess(out_handle, parameters, caps, num_caps)); } Result StartProcess64From32(ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { R_RETURN(StartProcess(process_handle, priority, core_id, main_thread_stack_size)); } Result TerminateProcess64From32(ams::svc::Handle process_handle) { R_RETURN(TerminateProcess(process_handle)); } Result GetProcessInfo64From32(int64_t *out_info, ams::svc::Handle process_handle, ams::svc::ProcessInfoType info_type) { R_RETURN(GetProcessInfo(out_info, process_handle, info_type)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_process_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidProcessMemoryPermission(ams::svc::MemoryPermission perm) { switch (perm) { case ams::svc::MemoryPermission_None: case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_ReadWrite: case ams::svc::MemoryPermission_ReadExecute: case ams::svc::MemoryPermission_Execute: return true; default: return false; } } Result SetProcessMemoryPermission(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Validate the memory permission. */ R_UNLESS(IsValidProcessMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the address is in range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Set the memory permission. */ R_RETURN(page_table.SetProcessMemoryPermission(address, size, perm)); } Result MapProcessMemory(uintptr_t dst_address, ams::svc::Handle process_handle, uint64_t src_address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(src_address == static_cast<uintptr_t>(src_address), svc::ResultInvalidCurrentMemory()); /* Get the processes. */ KProcess *dst_process = GetCurrentProcessPointer(); KScopedAutoObject src_process = dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); R_UNLESS(src_process.IsNotNull(), svc::ResultInvalidHandle()); /* Get the page tables. */ auto &dst_pt = dst_process->GetPageTable(); auto &src_pt = src_process->GetPageTable(); /* Validate that the mapping is in range. */ R_UNLESS(src_pt.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState_SharedCode), svc::ResultInvalidMemoryRegion()); /* Create a new page group. */ KPageGroup pg(dst_pt.GetBlockInfoManager()); /* Make the page group. */ R_TRY(src_pt.MakeAndOpenPageGroup(std::addressof(pg), src_address, size / PageSize, KMemoryState_FlagCanMapProcess, KMemoryState_FlagCanMapProcess, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None)); /* Close the page group when we're done. */ ON_SCOPE_EXIT { pg.Close(); }; /* Map the group. */ R_TRY(dst_pt.MapPageGroup(dst_address, pg, KMemoryState_SharedCode, KMemoryPermission_UserReadWrite)); R_SUCCEED(); } Result UnmapProcessMemory(uintptr_t dst_address, ams::svc::Handle process_handle, uint64_t src_address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(src_address == static_cast<uintptr_t>(src_address), svc::ResultInvalidCurrentMemory()); /* Get the processes. */ KProcess *dst_process = GetCurrentProcessPointer(); KScopedAutoObject src_process = dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); R_UNLESS(src_process.IsNotNull(), svc::ResultInvalidHandle()); /* Get the page tables. */ auto &dst_pt = dst_process->GetPageTable(); auto &src_pt = src_process->GetPageTable(); /* Validate that the mapping is in range. */ R_UNLESS(src_pt.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState_SharedCode), svc::ResultInvalidMemoryRegion()); /* Unmap the memory. */ R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address)); R_SUCCEED(); } Result MapProcessCodeMemory(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(src_address == static_cast<uintptr_t>(src_address), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_address == static_cast<uintptr_t>(dst_address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the mapping is in range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory()); /* Map the memory. */ R_TRY(page_table.MapCodeMemory(dst_address, src_address, size)); R_SUCCEED(); } Result UnmapProcessCodeMemory(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((dst_address < dst_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS((src_address < src_address + size), svc::ResultInvalidCurrentMemory()); R_UNLESS(src_address == static_cast<uintptr_t>(src_address), svc::ResultInvalidCurrentMemory()); R_UNLESS(dst_address == static_cast<uintptr_t>(dst_address), svc::ResultInvalidCurrentMemory()); R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory()); /* Get the process from its handle. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Validate that the mapping is in range. */ auto &page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory()); R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_AliasCode), svc::ResultInvalidCurrentMemory()); /* Unmap the memory. */ R_TRY(page_table.UnmapCodeMemory(dst_address, src_address, size)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result SetProcessMemoryPermission64(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { R_RETURN(SetProcessMemoryPermission(process_handle, address, size, perm)); } Result MapProcessMemory64(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { R_RETURN(MapProcessMemory(dst_address, process_handle, src_address, size)); } Result UnmapProcessMemory64(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { R_RETURN(UnmapProcessMemory(dst_address, process_handle, src_address, size)); } Result MapProcessCodeMemory64(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(MapProcessCodeMemory(process_handle, dst_address, src_address, size)); } Result UnmapProcessCodeMemory64(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(UnmapProcessCodeMemory(process_handle, dst_address, src_address, size)); } /* ============================= 64From32 ABI ============================= */ Result SetProcessMemoryPermission64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) { R_RETURN(SetProcessMemoryPermission(process_handle, address, size, perm)); } Result MapProcessMemory64From32(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { R_RETURN(MapProcessMemory(dst_address, process_handle, src_address, size)); } Result UnmapProcessMemory64From32(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) { R_RETURN(UnmapProcessMemory(dst_address, process_handle, src_address, size)); } Result MapProcessCodeMemory64From32(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(MapProcessCodeMemory(process_handle, dst_address, src_address, size)); } Result UnmapProcessCodeMemory64From32(ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(UnmapProcessCodeMemory(process_handle, dst_address, src_address, size)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_processor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { int32_t GetCurrentProcessorNumber() { /* Setup variables to track affinity information. */ s32 current_phys_core; u64 v_affinity_mask = 0; /* Forever try to get the affinity. */ while (true) { /* Update affinity information if we've run out. */ while (v_affinity_mask == 0) { current_phys_core = GetCurrentCoreId(); v_affinity_mask = GetCurrentThread().GetVirtualAffinityMask(); if ((v_affinity_mask & (1ul << current_phys_core)) != 0) { return current_phys_core; } } /* Check the next virtual bit. */ do { const s32 next_virt_core = static_cast<s32>(__builtin_ctzll(v_affinity_mask)); if (current_phys_core == cpu::VirtualToPhysicalCoreMap[next_virt_core]) { return next_virt_core; } v_affinity_mask &= ~(1ul << next_virt_core); } while (v_affinity_mask != 0); } } } /* ============================= 64 ABI ============================= */ int32_t GetCurrentProcessorNumber64() { return GetCurrentProcessorNumber(); } /* ============================= 64From32 ABI ============================= */ int32_t GetCurrentProcessorNumber64From32() { return GetCurrentProcessorNumber(); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_query_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result QueryProcessMemory(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uintptr_t address) { /* Get the process. */ KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle); R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); /* Query the mapping's info. */ KMemoryInfo info; R_TRY(process->GetPageTable().QueryInfo(std::addressof(info), out_page_info, address)); /* Write output. */ *out_memory_info = info.GetSvcMemoryInfo(); R_SUCCEED(); } template<typename T> Result QueryProcessMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) { /* Get an ams::svc::MemoryInfo for the region. */ ams::svc::MemoryInfo info = {}; R_TRY(QueryProcessMemory(std::addressof(info), out_page_info, process_handle, address)); /* Copy the info to userspace. */ if constexpr (std::same_as<T, ams::svc::MemoryInfo>) { R_TRY(out_memory_info.CopyFrom(std::addressof(info))); } else { /* Convert the info. */ T converted_info = {}; static_assert(std::same_as<decltype(T{}.base_address), decltype(ams::svc::MemoryInfo{}.base_address)>); static_assert(std::same_as<decltype(T{}.size), decltype(ams::svc::MemoryInfo{}.size)>); converted_info.base_address = info.base_address; converted_info.size = info.size; converted_info.state = info.state; converted_info.attribute = info.attribute; converted_info.permission = info.permission; converted_info.ipc_count = info.ipc_count; converted_info.device_count = info.device_count; /* Copy it. */ R_TRY(out_memory_info.CopyFrom(std::addressof(converted_info))); } R_SUCCEED(); } template<typename T> Result QueryMemory(KUserPointer<T *> out_memory_info, ams::svc::PageInfo *out_page_info, uintptr_t address) { /* Query memory is just QueryProcessMemory on the current process. */ R_RETURN(QueryProcessMemory(out_memory_info, out_page_info, ams::svc::PseudoHandle::CurrentProcess, address)); } } /* ============================= 64 ABI ============================= */ Result QueryMemory64(KUserPointer<ams::svc::lp64::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Address address) { R_RETURN(QueryMemory(out_memory_info, out_page_info, address)); } Result QueryProcessMemory64(KUserPointer<ams::svc::lp64::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) { R_RETURN(QueryProcessMemory(out_memory_info, out_page_info, process_handle, address)); } /* ============================= 64From32 ABI ============================= */ Result QueryMemory64From32(KUserPointer<ams::svc::ilp32::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Address address) { R_RETURN(QueryMemory(out_memory_info, out_page_info, address)); } Result QueryProcessMemory64From32(KUserPointer<ams::svc::ilp32::MemoryInfo *> out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle process_handle, uint64_t address) { R_RETURN(QueryProcessMemory(out_memory_info, out_page_info, process_handle, address)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_register.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result ReadWriteRegister(uint32_t *out, ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) { /* Clear the output unconditionally. */ *out = 0; /* Read/write the register. */ R_RETURN(KSystemControl::ReadWriteRegister(out, address, mask, value)); } } /* ============================= 64 ABI ============================= */ Result ReadWriteRegister64(uint32_t *out_value, ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) { R_RETURN(ReadWriteRegister(out_value, address, mask, value)); } /* ============================= 64From32 ABI ============================= */ Result ReadWriteRegister64From32(uint32_t *out_value, ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) { R_RETURN(ReadWriteRegister(out_value, address, mask, value)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_resource_limit.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidLimitableResource(ams::svc::LimitableResource which) { return which < ams::svc::LimitableResource_Count; } Result GetResourceLimitLimitValue(int64_t *out_limit_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { /* Validate the resource. */ R_UNLESS(IsValidLimitableResource(which), svc::ResultInvalidEnumValue()); /* Get the resource limit. */ KScopedAutoObject resource_limit = GetCurrentProcess().GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle()); /* Get the limit value. */ *out_limit_value = resource_limit->GetLimitValue(which); R_SUCCEED(); } Result GetResourceLimitCurrentValue(int64_t *out_current_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { /* Validate the resource. */ R_UNLESS(IsValidLimitableResource(which), svc::ResultInvalidEnumValue()); /* Get the resource limit. */ KScopedAutoObject resource_limit = GetCurrentProcess().GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle()); /* Get the current value. */ *out_current_value = resource_limit->GetCurrentValue(which); R_SUCCEED(); } Result GetResourceLimitPeakValue(int64_t *out_peak_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { /* Validate the resource. */ R_UNLESS(IsValidLimitableResource(which), svc::ResultInvalidEnumValue()); /* Get the resource limit. */ KScopedAutoObject resource_limit = GetCurrentProcess().GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle()); /* Get the peak value. */ *out_peak_value = resource_limit->GetPeakValue(which); R_SUCCEED(); } Result CreateResourceLimit(ams::svc::Handle *out_handle) { /* Create a new resource limit. */ KResourceLimit *resource_limit = KResourceLimit::Create(); R_UNLESS(resource_limit != nullptr, svc::ResultOutOfResource()); /* Ensure we don't leak a reference to the limit. */ ON_SCOPE_EXIT { resource_limit->Close(); }; /* Initialize the resource limit. */ resource_limit->Initialize(); /* Register the limit. */ KResourceLimit::Register(resource_limit); /* Add the limit to the handle table. */ R_TRY(GetCurrentProcess().GetHandleTable().Add(out_handle, resource_limit)); R_SUCCEED(); } Result SetResourceLimitLimitValue(ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which, int64_t limit_value) { /* Validate the resource. */ R_UNLESS(IsValidLimitableResource(which), svc::ResultInvalidEnumValue()); /* Get the resource limit. */ KScopedAutoObject resource_limit = GetCurrentProcess().GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle); R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle()); /* Set the limit value. */ R_TRY(resource_limit->SetLimitValue(which, limit_value)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result GetResourceLimitLimitValue64(int64_t *out_limit_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitLimitValue(out_limit_value, resource_limit_handle, which)); } Result GetResourceLimitCurrentValue64(int64_t *out_current_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitCurrentValue(out_current_value, resource_limit_handle, which)); } Result GetResourceLimitPeakValue64(int64_t *out_peak_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitPeakValue(out_peak_value, resource_limit_handle, which)); } Result CreateResourceLimit64(ams::svc::Handle *out_handle) { R_RETURN(CreateResourceLimit(out_handle)); } Result SetResourceLimitLimitValue64(ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which, int64_t limit_value) { R_RETURN(SetResourceLimitLimitValue(resource_limit_handle, which, limit_value)); } /* ============================= 64From32 ABI ============================= */ Result GetResourceLimitLimitValue64From32(int64_t *out_limit_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitLimitValue(out_limit_value, resource_limit_handle, which)); } Result GetResourceLimitCurrentValue64From32(int64_t *out_current_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitCurrentValue(out_current_value, resource_limit_handle, which)); } Result GetResourceLimitPeakValue64From32(int64_t *out_peak_value, ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which) { R_RETURN(GetResourceLimitPeakValue(out_peak_value, resource_limit_handle, which)); } Result CreateResourceLimit64From32(ams::svc::Handle *out_handle) { R_RETURN(CreateResourceLimit(out_handle)); } Result SetResourceLimitLimitValue64From32(ams::svc::Handle resource_limit_handle, ams::svc::LimitableResource which, int64_t limit_value) { R_RETURN(SetResourceLimitLimitValue(resource_limit_handle, which, limit_value)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_secure_monitor_call.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { } /* ============================= 64 ABI ============================= */ void CallSecureMonitor64(ams::svc::lp64::SecureMonitorArguments *args) { KSystemControl::CallSecureMonitorFromUser(args); } /* ============================= 64From32 ABI ============================= */ /* CallSecureMonitor64From32 is not supported. */ } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_session.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { template<typename T> Result CreateSession(ams::svc::Handle *out_server, ams::svc::Handle *out_client, uintptr_t name) { /* Get the current process and handle table. */ auto &process = GetCurrentProcess(); auto &handle_table = process.GetHandleTable(); /* Declare the session we're going to allocate. */ T *session; /* Reserve a new session from the process resource limit. */ KScopedResourceReservation session_reservation(std::addressof(process), ams::svc::LimitableResource_SessionCountMax); if (session_reservation.Succeeded()) { /* Allocate a session normally. */ session = T::Create(); } else { /* We couldn't reserve a session. Check that we support dynamically expanding the resource limit. */ R_UNLESS(process.GetResourceLimit() == std::addressof(Kernel::GetSystemResourceLimit()), svc::ResultLimitReached()); R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), svc::ResultLimitReached()); /* Try to allocate a session from unused slab memory. */ session = T::CreateFromUnusedSlabMemory(); R_UNLESS(session != nullptr, svc::ResultLimitReached()); ON_RESULT_FAILURE { session->Close(); }; /* If we're creating a KSession, we want to add two KSessionRequests to the heap, to prevent request exhaustion. */ /* NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's no reason to not do this statically. */ if constexpr (std::same_as<T, KSession>) { for (size_t i = 0; i < 2; ++i) { KSessionRequest *request = KSessionRequest::CreateFromUnusedSlabMemory(); R_UNLESS(request != nullptr, svc::ResultLimitReached()); request->Close(); } } /* We successfully allocated a session, so add the object we allocated to the resource limit. */ Kernel::GetSystemResourceLimit().Add(ams::svc::LimitableResource_SessionCountMax, 1); } /* Check that we successfully created a session. */ R_UNLESS(session != nullptr, svc::ResultOutOfResource()); /* Initialize the session. */ session->Initialize(nullptr, name); /* Commit the session reservation. */ session_reservation.Commit(); /* Ensure that we clean up the session (and its only references are handle table) on function end. */ ON_SCOPE_EXIT { session->GetClientSession().Close(); session->GetServerSession().Close(); }; /* Register the session. */ T::Register(session); /* Add the server session to the handle table. */ R_TRY(handle_table.Add(out_server, std::addressof(session->GetServerSession()))); /* Ensure that we maintaing a clean handle state on exit. */ ON_RESULT_FAILURE { handle_table.Remove(*out_server); }; /* Add the client session to the handle table. */ R_RETURN(handle_table.Add(out_client, std::addressof(session->GetClientSession()))); } Result CreateSession(ams::svc::Handle *out_server, ams::svc::Handle *out_client, bool is_light, uintptr_t name) { if (is_light) { R_RETURN(CreateSession<KLightSession>(out_server, out_client, name)); } else { R_RETURN(CreateSession<KSession>(out_server, out_client, name)); } } Result AcceptSession(ams::svc::Handle *out, ams::svc::Handle port_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Get the server port. */ KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle); R_UNLESS(port.IsNotNull(), svc::ResultInvalidHandle()); /* Reserve an entry for the new session. */ R_TRY(handle_table.Reserve(out)); ON_RESULT_FAILURE { handle_table.Unreserve(*out); }; /* Accept the session. */ KAutoObject *session; if (port->IsLight()) { session = port->AcceptLightSession(); } else { session = port->AcceptSession(); } /* Ensure we accepted successfully. */ R_UNLESS(session != nullptr, svc::ResultNotFound()); /* Register the session. */ handle_table.Register(*out, session); session->Close(); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result CreateSession64(ams::svc::Handle *out_server_session_handle, ams::svc::Handle *out_client_session_handle, bool is_light, ams::svc::Address name) { R_RETURN(CreateSession(out_server_session_handle, out_client_session_handle, is_light, name)); } Result AcceptSession64(ams::svc::Handle *out_handle, ams::svc::Handle port) { R_RETURN(AcceptSession(out_handle, port)); } /* ============================= 64From32 ABI ============================= */ Result CreateSession64From32(ams::svc::Handle *out_server_session_handle, ams::svc::Handle *out_client_session_handle, bool is_light, ams::svc::Address name) { R_RETURN(CreateSession(out_server_session_handle, out_client_session_handle, is_light, name)); } Result AcceptSession64From32(ams::svc::Handle *out_handle, ams::svc::Handle port) { R_RETURN(AcceptSession(out_handle, port)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_shared_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidSharedMemoryPermission(ams::svc::MemoryPermission perm) { switch (perm) { case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_ReadWrite: return true; default: return false; } } constexpr bool IsValidRemoteSharedMemoryPermission(ams::svc::MemoryPermission perm) { return IsValidSharedMemoryPermission(perm) || perm == ams::svc::MemoryPermission_DontCare; } Result MapSharedMemory(ams::svc::Handle shmem_handle, uintptr_t address, size_t size, ams::svc::MemoryPermission map_perm) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Validate the permission. */ R_UNLESS(IsValidSharedMemoryPermission(map_perm), svc::ResultInvalidNewMemoryPermission()); /* Get the current process. */ auto &process = GetCurrentProcess(); auto &page_table = process.GetPageTable(); /* Get the shared memory. */ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); R_UNLESS(shmem.IsNotNull(), svc::ResultInvalidHandle()); /* Verify that the mapping is in range. */ R_UNLESS(page_table.CanContain(address, size, KMemoryState_Shared), svc::ResultInvalidMemoryRegion()); /* Add the shared memory to the process. */ R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size)); /* Ensure that we clean up the shared memory if we fail to map it. */ ON_RESULT_FAILURE { process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); }; /* Map the shared memory. */ R_RETURN(shmem->Map(std::addressof(page_table), address, size, std::addressof(process), map_perm)); } Result UnmapSharedMemory(ams::svc::Handle shmem_handle, uintptr_t address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Get the current process. */ auto &process = GetCurrentProcess(); auto &page_table = process.GetPageTable(); /* Get the shared memory. */ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); R_UNLESS(shmem.IsNotNull(), svc::ResultInvalidHandle()); /* Verify that the mapping is in range. */ R_UNLESS(page_table.CanContain(address, size, KMemoryState_Shared), svc::ResultInvalidMemoryRegion()); /* Unmap the shared memory. */ R_TRY(shmem->Unmap(std::addressof(page_table), address, size, std::addressof(process))); /* Remove the shared memory from the process. */ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); R_SUCCEED(); } Result CreateSharedMemory(ams::svc::Handle *out, size_t size, ams::svc::MemoryPermission owner_perm, ams::svc::MemoryPermission remote_perm) { /* Validate the size. */ R_UNLESS(0 < size && size < kern::MainMemorySizeMax, svc::ResultInvalidSize()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); /* Validate the permissions. */ R_UNLESS(IsValidSharedMemoryPermission(owner_perm), svc::ResultInvalidNewMemoryPermission()); R_UNLESS(IsValidRemoteSharedMemoryPermission(remote_perm), svc::ResultInvalidNewMemoryPermission()); /* Create the shared memory. */ KSharedMemory *shmem = KSharedMemory::Create(); R_UNLESS(shmem != nullptr, svc::ResultOutOfResource()); /* Ensure the only reference is in the handle table when we're done. */ ON_SCOPE_EXIT { shmem->Close(); }; /* Initialize the shared memory. */ R_TRY(shmem->Initialize(GetCurrentProcessPointer(), size, owner_perm, remote_perm)); /* Register the shared memory. */ KSharedMemory::Register(shmem); /* Add the shared memory to the handle table. */ R_TRY(GetCurrentProcess().GetHandleTable().Add(out, shmem)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result MapSharedMemory64(ams::svc::Handle shmem_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission map_perm) { R_RETURN(MapSharedMemory(shmem_handle, address, size, map_perm)); } Result UnmapSharedMemory64(ams::svc::Handle shmem_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapSharedMemory(shmem_handle, address, size)); } Result CreateSharedMemory64(ams::svc::Handle *out_handle, ams::svc::Size size, ams::svc::MemoryPermission owner_perm, ams::svc::MemoryPermission remote_perm) { R_RETURN(CreateSharedMemory(out_handle, size, owner_perm, remote_perm)); } /* ============================= 64From32 ABI ============================= */ Result MapSharedMemory64From32(ams::svc::Handle shmem_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission map_perm) { R_RETURN(MapSharedMemory(shmem_handle, address, size, map_perm)); } Result UnmapSharedMemory64From32(ams::svc::Handle shmem_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapSharedMemory(shmem_handle, address, size)); } Result CreateSharedMemory64From32(ams::svc::Handle *out_handle, ams::svc::Size size, ams::svc::MemoryPermission owner_perm, ams::svc::MemoryPermission remote_perm) { R_RETURN(CreateSharedMemory(out_handle, size, owner_perm, remote_perm)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result CloseHandle(ams::svc::Handle handle) { /* Remove the handle. */ R_UNLESS(GetCurrentProcess().GetHandleTable().Remove(handle), svc::ResultInvalidHandle()); R_SUCCEED(); } Result ResetSignal(ams::svc::Handle handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Try to reset as readable event. */ { KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle); if (readable_event.IsNotNull()) { if (auto * const interrupt_event = readable_event->DynamicCast<KInterruptEvent *>(); interrupt_event != nullptr) { R_RETURN(interrupt_event->Reset()); } else { R_RETURN(readable_event->Reset()); } } } /* Try to reset as process. */ { KScopedAutoObject process = handle_table.GetObject<KProcess>(handle); if (process.IsNotNull()) { R_RETURN(process->Reset()); } } R_THROW(svc::ResultInvalidHandle()); } Result WaitSynchronizationImpl(int32_t *out_index, KSynchronizationObject **objs, int32_t num_handles, int64_t timeout_ns) { /* Convert the timeout from nanoseconds to ticks. */ s64 timeout; if (timeout_ns > 0) { u64 ticks = KHardwareTimer::GetTick(); ticks += ams::svc::Tick(TimeSpan::FromNanoSeconds(timeout_ns)); ticks += 2; timeout = ticks; } else { timeout = timeout_ns; } R_RETURN(KSynchronizationObject::Wait(out_index, objs, num_handles, timeout)); } Result WaitSynchronization(int32_t *out_index, KUserPointer<const ams::svc::Handle *> user_handles, int32_t num_handles, int64_t timeout_ns) { /* Ensure number of handles is valid. */ R_UNLESS(0 <= num_handles && num_handles <= ams::svc::ArgumentHandleCountMax, svc::ResultOutOfRange()); /* Get the synchronization context. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); KSynchronizationObject **objs = GetCurrentThread().GetSynchronizationObjectBuffer(); ams::svc::Handle *handles = GetCurrentThread().GetHandleBuffer(); /* Copy user handles. */ if (num_handles > 0) { /* Ensure that we can try to get the handles. */ R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); /* Get the handles. */ R_TRY(user_handles.CopyArrayTo(handles, num_handles)); /* Convert the handles to objects. */ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles), svc::ResultInvalidHandle()); } /* Ensure handles are closed when we're done. */ ON_SCOPE_EXIT { for (auto i = 0; i < num_handles; ++i) { objs[i]->Close(); } }; /* Wait on the objects. */ R_TRY_CATCH(WaitSynchronizationImpl(out_index, objs, num_handles, timeout_ns)) { R_CONVERT(svc::ResultSessionClosed, ResultSuccess()) } R_END_TRY_CATCH; R_SUCCEED(); } Result CancelSynchronization(ams::svc::Handle handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Cancel the thread's wait. */ thread->WaitCancel(); R_SUCCEED(); } void SynchronizePreemptionState() { /* Lock the scheduler. */ KScopedSchedulerLock sl; /* If the current thread is pinned, unpin it. */ KProcess *cur_process = GetCurrentProcessPointer(); if (cur_process->GetPinnedThread(GetCurrentCoreId()) == GetCurrentThreadPointer()) { /* Clear the current thread's interrupt flag. */ GetCurrentThread().ClearInterruptFlag(); /* Unpin the current thread. */ cur_process->UnpinCurrentThread(); } } } /* ============================= 64 ABI ============================= */ Result CloseHandle64(ams::svc::Handle handle) { R_RETURN(CloseHandle(handle)); } Result ResetSignal64(ams::svc::Handle handle) { R_RETURN(ResetSignal(handle)); } Result WaitSynchronization64(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) { R_RETURN(WaitSynchronization(out_index, handles, num_handles, timeout_ns)); } Result CancelSynchronization64(ams::svc::Handle handle) { R_RETURN(CancelSynchronization(handle)); } void SynchronizePreemptionState64() { return SynchronizePreemptionState(); } /* ============================= 64From32 ABI ============================= */ Result CloseHandle64From32(ams::svc::Handle handle) { R_RETURN(CloseHandle(handle)); } Result ResetSignal64From32(ams::svc::Handle handle) { R_RETURN(ResetSignal(handle)); } Result WaitSynchronization64From32(int32_t *out_index, KUserPointer<const ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) { R_RETURN(WaitSynchronization(out_index, handles, num_handles, timeout_ns)); } Result CancelSynchronization64From32(ams::svc::Handle handle) { R_RETURN(CancelSynchronization(handle)); } void SynchronizePreemptionState64From32() { return SynchronizePreemptionState(); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_thread.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidVirtualCoreId(int32_t core_id) { return (0 <= core_id && core_id < static_cast<int32_t>(cpu::NumVirtualCores)); } Result CreateThread(ams::svc::Handle *out, ams::svc::ThreadFunc f, uintptr_t arg, uintptr_t stack_bottom, int32_t priority, int32_t core_id) { /* Adjust core id, if it's the default magic. */ KProcess &process = GetCurrentProcess(); if (core_id == ams::svc::IdealCoreUseProcessValue) { core_id = process.GetIdealCoreId(); } /* Validate arguments. */ R_UNLESS(IsValidVirtualCoreId(core_id), svc::ResultInvalidCoreId()); R_UNLESS(((1ul << core_id) & process.GetCoreMask()) != 0, svc::ResultInvalidCoreId()); R_UNLESS(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority, svc::ResultInvalidPriority()); R_UNLESS(process.CheckThreadPriority(priority), svc::ResultInvalidPriority()); /* Reserve a new thread from the process resource limit (waiting up to 100ms). */ KScopedResourceReservation thread_reservation(std::addressof(process), ams::svc::LimitableResource_ThreadCountMax, 1, KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMilliSeconds(100))); R_UNLESS(thread_reservation.Succeeded(), svc::ResultLimitReached()); /* Create the thread. */ KThread *thread = KThread::Create(); R_UNLESS(thread != nullptr, svc::ResultOutOfResource()); ON_SCOPE_EXIT { thread->Close(); }; /* Initialize the thread. */ { KScopedLightLock lk(process.GetStateLock()); R_TRY(KThread::InitializeUserThread(thread, reinterpret_cast<KThreadFunction>(static_cast<uintptr_t>(f)), arg, stack_bottom, priority, core_id, std::addressof(process))); } /* Commit the thread reservation. */ thread_reservation.Commit(); /* Clone the current fpu status to the new thread. */ thread->GetContext().CloneFpuStatus(); /* Register the new thread. */ KThread::Register(thread); /* Add the thread to the handle table. */ R_TRY(process.GetHandleTable().Add(out, thread)); R_SUCCEED(); } Result StartThread(ams::svc::Handle thread_handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Try to start the thread. */ R_RETURN(thread->Run()); } void ExitThread() { GetCurrentThread().Exit(); MESOSPHERE_PANIC("Thread survived call to exit"); } void SleepThread(int64_t ns) { /* When the input tick is positive, sleep. */ if (AMS_LIKELY(ns > 0)) { /* Convert the timeout from nanoseconds to ticks. */ /* NOTE: Nintendo does not use this conversion logic in WaitSynchronization... */ s64 timeout; const ams::svc::Tick offset_tick(TimeSpan::FromNanoSeconds(ns)); if (AMS_LIKELY(offset_tick > 0)) { timeout = KHardwareTimer::GetTick() + offset_tick + 2; if (AMS_UNLIKELY(timeout <= 0)) { timeout = std::numeric_limits<s64>::max(); } } else { timeout = std::numeric_limits<s64>::max(); } /* Sleep. */ /* NOTE: Nintendo does not check the result of this sleep. */ GetCurrentThread().Sleep(timeout); } else if (ns == ams::svc::YieldType_WithoutCoreMigration) { KScheduler::YieldWithoutCoreMigration(); } else if (ns == ams::svc::YieldType_WithCoreMigration) { KScheduler::YieldWithCoreMigration(); } else if (ns == ams::svc::YieldType_ToAnyThread) { KScheduler::YieldToAnyThread(); } else { /* Nintendo does nothing at all if an otherwise invalid value is passed. */ } } Result GetThreadPriority(int32_t *out_priority, ams::svc::Handle thread_handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Get the thread's priority. */ *out_priority = thread->GetPriority(); R_SUCCEED(); } Result SetThreadPriority(ams::svc::Handle thread_handle, int32_t priority) { /* Get the current process. */ KProcess &process = GetCurrentProcess(); /* Get the thread from its handle. */ KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Validate the thread is owned by the current process. */ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); /* Validate the priority. */ R_UNLESS(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority, svc::ResultInvalidPriority()); R_UNLESS(process.CheckThreadPriority(priority), svc::ResultInvalidPriority()); /* Set the thread priority. */ thread->SetBasePriority(priority); R_SUCCEED(); } Result GetThreadCoreMask(int32_t *out_core_id, uint64_t *out_affinity_mask, ams::svc::Handle thread_handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Get the core mask. */ R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); R_SUCCEED(); } Result SetThreadCoreMask(ams::svc::Handle thread_handle, int32_t core_id, uint64_t affinity_mask) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Validate the thread is owned by the current process. */ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); /* Determine the core id/affinity mask. */ if (core_id == ams::svc::IdealCoreUseProcessValue) { core_id = GetCurrentProcess().GetIdealCoreId(); affinity_mask = (1ul << core_id); } else { /* Validate the affinity mask. */ const u64 process_core_mask = GetCurrentProcess().GetCoreMask(); R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, svc::ResultInvalidCoreId()); R_UNLESS(affinity_mask != 0, svc::ResultInvalidCombination()); /* Validate the core id. */ if (IsValidVirtualCoreId(core_id)) { R_UNLESS(((1ul << core_id) & affinity_mask) != 0, svc::ResultInvalidCombination()); } else { R_UNLESS(core_id == ams::svc::IdealCoreNoUpdate || core_id == ams::svc::IdealCoreDontCare, svc::ResultInvalidCoreId()); } } /* Set the core mask. */ R_TRY(thread->SetCoreMask(core_id, affinity_mask)); R_SUCCEED(); } Result GetThreadId(uint64_t *out_thread_id, ams::svc::Handle thread_handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Get the thread's id. */ *out_thread_id = thread->GetId(); R_SUCCEED(); } Result GetThreadContext3(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle thread_handle) { /* Get the thread from its handle. */ KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Require the handle be to a non-current thread in the current process. */ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(), svc::ResultBusy()); /* Get the thread context. */ ams::svc::ThreadContext context = {}; R_TRY(thread->GetThreadContext3(std::addressof(context))); /* Copy the thread context to user space. */ R_TRY(out_context.CopyFrom(std::addressof(context))); R_SUCCEED(); } Result GetThreadList(int32_t *out_num_threads, KUserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented()); /* Validate that the out count is valid. */ R_UNLESS((0 <= max_out_count && max_out_count <= static_cast<int32_t>(std::numeric_limits<int32_t>::max() / sizeof(u64))), svc::ResultOutOfRange()); /* Validate that the pointer is in range. */ if (max_out_count > 0) { R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory()); } /* Get the handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); /* Try to get as a debug object. */ KScopedAutoObject debug = handle_table.GetObject<KDebug>(debug_handle); if (debug.IsNotNull()) { /* Check that the debug object has a process. */ R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated()); R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated()); ON_SCOPE_EXIT { debug->CloseProcess(); }; /* Get the thread list. */ R_TRY(debug->GetProcessUnsafe()->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); } else { /* Only allow getting as a process (or global) if the caller does not have ForceDebugProd. */ R_UNLESS(!GetCurrentProcess().CanForceDebugProd(), svc::ResultInvalidHandle()); /* Try to get as a process. */ KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle<KProcess>(debug_handle); if (process.IsNotNull()) { /* Get the thread list. */ R_TRY(process->GetThreadList(out_num_threads, out_thread_ids, max_out_count)); } else { /* If the object is not a process, the caller may want the global thread list. */ R_UNLESS(debug_handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle()); /* If passed invalid handle, we should return the global thread list. */ R_TRY(KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count)); } } R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result CreateThread64(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) { R_RETURN(CreateThread(out_handle, func, arg, stack_bottom, priority, core_id)); } Result StartThread64(ams::svc::Handle thread_handle) { R_RETURN(StartThread(thread_handle)); } void ExitThread64() { return ExitThread(); } void SleepThread64(int64_t ns) { return SleepThread(ns); } Result GetThreadPriority64(int32_t *out_priority, ams::svc::Handle thread_handle) { R_RETURN(GetThreadPriority(out_priority, thread_handle)); } Result SetThreadPriority64(ams::svc::Handle thread_handle, int32_t priority) { R_RETURN(SetThreadPriority(thread_handle, priority)); } Result GetThreadCoreMask64(int32_t *out_core_id, uint64_t *out_affinity_mask, ams::svc::Handle thread_handle) { R_RETURN(GetThreadCoreMask(out_core_id, out_affinity_mask, thread_handle)); } Result SetThreadCoreMask64(ams::svc::Handle thread_handle, int32_t core_id, uint64_t affinity_mask) { R_RETURN(SetThreadCoreMask(thread_handle, core_id, affinity_mask)); } Result GetThreadId64(uint64_t *out_thread_id, ams::svc::Handle thread_handle) { R_RETURN(GetThreadId(out_thread_id, thread_handle)); } Result GetThreadContext364(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle thread_handle) { R_RETURN(GetThreadContext3(out_context, thread_handle)); } Result GetThreadList64(int32_t *out_num_threads, KUserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { R_RETURN(GetThreadList(out_num_threads, out_thread_ids, max_out_count, debug_handle)); } /* ============================= 64From32 ABI ============================= */ Result CreateThread64From32(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) { R_RETURN(CreateThread(out_handle, func, arg, stack_bottom, priority, core_id)); } Result StartThread64From32(ams::svc::Handle thread_handle) { R_RETURN(StartThread(thread_handle)); } void ExitThread64From32() { return ExitThread(); } void SleepThread64From32(int64_t ns) { return SleepThread(ns); } Result GetThreadPriority64From32(int32_t *out_priority, ams::svc::Handle thread_handle) { R_RETURN(GetThreadPriority(out_priority, thread_handle)); } Result SetThreadPriority64From32(ams::svc::Handle thread_handle, int32_t priority) { R_RETURN(SetThreadPriority(thread_handle, priority)); } Result GetThreadCoreMask64From32(int32_t *out_core_id, uint64_t *out_affinity_mask, ams::svc::Handle thread_handle) { R_RETURN(GetThreadCoreMask(out_core_id, out_affinity_mask, thread_handle)); } Result SetThreadCoreMask64From32(ams::svc::Handle thread_handle, int32_t core_id, uint64_t affinity_mask) { R_RETURN(SetThreadCoreMask(thread_handle, core_id, affinity_mask)); } Result GetThreadId64From32(uint64_t *out_thread_id, ams::svc::Handle thread_handle) { R_RETURN(GetThreadId(out_thread_id, thread_handle)); } Result GetThreadContext364From32(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle thread_handle) { R_RETURN(GetThreadContext3(out_context, thread_handle)); } Result GetThreadList64From32(int32_t *out_num_threads, KUserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) { R_RETURN(GetThreadList(out_num_threads, out_thread_ids, max_out_count, debug_handle)); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_thread_profiler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { Result GetLastThreadInfoImpl(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags) { /* Disable interrupts. */ KScopedInterruptDisable di; /* Get the previous thread. */ KThread *prev_thread = Kernel::GetScheduler().GetPreviousThread(); R_UNLESS(prev_thread != nullptr, svc::ResultNoThread()); /* Verify the last thread was owned by the current process. */ R_UNLESS(prev_thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultUnknownThread()); /* Clear the output flags. */ *out_flags = 0; /* Get the thread's exception context. */ GetExceptionContext(prev_thread)->GetSvcThreadContext(out_context); /* Get the tls address. */ *out_tls_address = GetInteger(prev_thread->GetThreadLocalRegionAddress()); /* Set the syscall flag if appropriate. */ if (prev_thread->IsCallingSvc()) { *out_flags |= ams::svc::LastThreadInfoFlag_ThreadInSystemCall; } R_SUCCEED(); } Result SynchronizeCurrentProcessToFutureTime(int64_t ns) { /* Get the wait object. */ KWaitObject *wait_object = GetCurrentProcess().GetWaitObjectPointer(); /* Convert the timeout from nanoseconds to ticks. */ s64 timeout; if (ns > 0) { u64 ticks = KHardwareTimer::GetTick(); ticks += ams::svc::Tick(TimeSpan::FromNanoSeconds(ns)); ticks += 2; timeout = ticks; } else { timeout = ns; } /* Synchronize to the desired time. */ R_TRY(wait_object->Synchronize(timeout)); R_SUCCEED(); } Result GetDebugFutureThreadInfo(ams::svc::LastThreadContext *out_context, uint64_t *out_thread_id, ams::svc::Handle debug_handle, int64_t ns) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); /* Get the debug object. */ KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle); R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle()); /* Synchronize the current process to the desired time. */ R_TRY(SynchronizeCurrentProcessToFutureTime(ns)); /* Get the running thread info. */ R_TRY(debug->GetRunningThreadInfo(out_context, out_thread_id)); R_SUCCEED(); } Result LegacyGetFutureThreadInfo(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags, int64_t ns) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); /* Synchronize the current process to the desired time. */ R_TRY(SynchronizeCurrentProcessToFutureTime(ns)); /* Get the thread info. */ R_TRY(GetLastThreadInfoImpl(out_context, out_tls_address, out_flags)); R_SUCCEED(); } Result GetLastThreadInfo(ams::svc::LastThreadContext *out_context, uintptr_t *out_tls_address, uint32_t *out_flags) { /* Only allow invoking the svc on development hardware. */ R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNoThread()); /* Get the thread info. */ R_TRY(GetLastThreadInfoImpl(out_context, out_tls_address, out_flags)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result GetDebugFutureThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, uint64_t *out_thread_id, ams::svc::Handle debug_handle, int64_t ns) { R_RETURN(GetDebugFutureThreadInfo(out_context, out_thread_id, debug_handle, ns)); } Result LegacyGetFutureThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags, int64_t ns) { R_RETURN(LegacyGetFutureThreadInfo(out_context, reinterpret_cast<uintptr_t *>(out_tls_address), out_flags, ns)); } Result GetLastThreadInfo64(ams::svc::lp64::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); R_RETURN(GetLastThreadInfo(out_context, reinterpret_cast<uintptr_t *>(out_tls_address), out_flags)); } /* ============================= 64From32 ABI ============================= */ Result GetDebugFutureThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, uint64_t *out_thread_id, ams::svc::Handle debug_handle, int64_t ns) { ams::svc::LastThreadContext context = {}; R_TRY(GetDebugFutureThreadInfo(std::addressof(context), out_thread_id, debug_handle, ns)); *out_context = { .fp = static_cast<u32>(context.fp), .sp = static_cast<u32>(context.sp), .lr = static_cast<u32>(context.lr), .pc = static_cast<u32>(context.pc), }; R_SUCCEED(); } Result LegacyGetFutureThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags, int64_t ns) { static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); ams::svc::LastThreadContext context = {}; R_TRY(LegacyGetFutureThreadInfo(std::addressof(context), reinterpret_cast<uintptr_t *>(out_tls_address), out_flags, ns)); *out_context = { .fp = static_cast<u32>(context.fp), .sp = static_cast<u32>(context.sp), .lr = static_cast<u32>(context.lr), .pc = static_cast<u32>(context.pc), }; R_SUCCEED(); } Result GetLastThreadInfo64From32(ams::svc::ilp32::LastThreadContext *out_context, ams::svc::Address *out_tls_address, uint32_t *out_flags) { static_assert(sizeof(*out_tls_address) == sizeof(uintptr_t)); ams::svc::LastThreadContext context = {}; R_TRY(GetLastThreadInfo(std::addressof(context), reinterpret_cast<uintptr_t *>(out_tls_address), out_flags)); *out_context = { .fp = static_cast<u32>(context.fp), .sp = static_cast<u32>(context.sp), .lr = static_cast<u32>(context.lr), .pc = static_cast<u32>(context.pc), }; R_SUCCEED(); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_tick.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { int64_t GetSystemTick() { return KHardwareTimer::GetTick(); } } /* ============================= 64 ABI ============================= */ int64_t GetSystemTick64() { return GetSystemTick(); } /* ============================= 64From32 ABI ============================= */ int64_t GetSystemTick64From32() { return GetSystemTick(); } } ================================================ FILE: libraries/libmesosphere/source/svc/kern_svc_transfer_memory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <mesosphere.hpp> namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { constexpr bool IsValidTransferMemoryPermission(ams::svc::MemoryPermission perm) { switch (perm) { case ams::svc::MemoryPermission_None: case ams::svc::MemoryPermission_Read: case ams::svc::MemoryPermission_ReadWrite: return true; default: return false; } } Result MapTransferMemory(ams::svc::Handle trmem_handle, uintptr_t address, size_t size, ams::svc::MemoryPermission map_perm) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Validate the permission. */ R_UNLESS(IsValidTransferMemoryPermission(map_perm), svc::ResultInvalidState()); /* Get the transfer memory. */ KScopedAutoObject trmem = GetCurrentProcess().GetHandleTable().GetObject<KTransferMemory>(trmem_handle); R_UNLESS(trmem.IsNotNull(), svc::ResultInvalidHandle()); /* Verify that the mapping is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Transfered), svc::ResultInvalidMemoryRegion()); /* Map the transfer memory. */ R_TRY(trmem->Map(address, size, map_perm)); /* We succeeded. */ R_SUCCEED(); } Result UnmapTransferMemory(ams::svc::Handle trmem_handle, uintptr_t address, size_t size) { /* Validate the address/size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Get the transfer memory. */ KScopedAutoObject trmem = GetCurrentProcess().GetHandleTable().GetObject<KTransferMemory>(trmem_handle); R_UNLESS(trmem.IsNotNull(), svc::ResultInvalidHandle()); /* Verify that the mapping is in range. */ R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Transfered), svc::ResultInvalidMemoryRegion()); /* Unmap the transfer memory. */ R_TRY(trmem->Unmap(address, size)); R_SUCCEED(); } Result CreateTransferMemory(ams::svc::Handle *out, uintptr_t address, size_t size, ams::svc::MemoryPermission map_perm) { /* Validate the size. */ R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress()); R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize()); R_UNLESS(size > 0, svc::ResultInvalidSize()); R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory()); /* Validate the permissions. */ R_UNLESS(IsValidTransferMemoryPermission(map_perm), svc::ResultInvalidNewMemoryPermission()); /* Get the current process and handle table. */ auto &process = GetCurrentProcess(); auto &handle_table = process.GetHandleTable(); /* Reserve a new transfer memory from the process resource limit. */ KScopedResourceReservation trmem_reservation(std::addressof(process), ams::svc::LimitableResource_TransferMemoryCountMax); R_UNLESS(trmem_reservation.Succeeded(), svc::ResultLimitReached()); /* Create the transfer memory. */ KTransferMemory *trmem = KTransferMemory::Create(); R_UNLESS(trmem != nullptr, svc::ResultOutOfResource()); /* Ensure the only reference is in the handle table when we're done. */ ON_SCOPE_EXIT { trmem->Close(); }; /* Ensure that the region is in range. */ R_UNLESS(process.GetPageTable().Contains(address, size), svc::ResultInvalidCurrentMemory()); /* Initialize the transfer memory. */ R_TRY(trmem->Initialize(address, size, map_perm)); /* Commit the reservation. */ trmem_reservation.Commit(); /* Register the transfer memory. */ KTransferMemory::Register(trmem); /* Add the transfer memory to the handle table. */ R_TRY(handle_table.Add(out, trmem)); R_SUCCEED(); } } /* ============================= 64 ABI ============================= */ Result MapTransferMemory64(ams::svc::Handle trmem_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission owner_perm) { R_RETURN(MapTransferMemory(trmem_handle, address, size, owner_perm)); } Result UnmapTransferMemory64(ams::svc::Handle trmem_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapTransferMemory(trmem_handle, address, size)); } Result CreateTransferMemory64(ams::svc::Handle *out_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission map_perm) { R_RETURN(CreateTransferMemory(out_handle, address, size, map_perm)); } /* ============================= 64From32 ABI ============================= */ Result MapTransferMemory64From32(ams::svc::Handle trmem_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission owner_perm) { R_RETURN(MapTransferMemory(trmem_handle, address, size, owner_perm)); } Result UnmapTransferMemory64From32(ams::svc::Handle trmem_handle, ams::svc::Address address, ams::svc::Size size) { R_RETURN(UnmapTransferMemory(trmem_handle, address, size)); } Result CreateTransferMemory64From32(ams::svc::Handle *out_handle, ams::svc::Address address, ams::svc::Size size, ams::svc::MemoryPermission map_perm) { R_RETURN(CreateTransferMemory(out_handle, address, size, map_perm)); } } ================================================ FILE: libraries/libstratosphere/Makefile ================================================ ATMOSPHERE_BUILD_CONFIGS := all: nx_release THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) define ATMOSPHERE_ADD_TARGET ATMOSPHERE_BUILD_CONFIGS += $(strip $1) $(strip $1): @echo "Building $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libstratosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) clean-$(strip $1): @echo "Cleaning $(strip $1)" @$$(MAKE) -f $(CURRENT_DIRECTORY)/libstratosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5) endef define ATMOSPHERE_ADD_TARGETS $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_release, $(strip $2)release, $(strip $3), $(strip $4), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $5)" $(strip $6) \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_debug, $(strip $2)debug, $(strip $3), $(strip $4), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_DEBUGGING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 $(strip $6) \ )) $(eval $(call ATMOSPHERE_ADD_TARGET, $(strip $1)_audit, $(strip $2)audit, $(strip $3), $(strip $4), \ ATMOSPHERE_BUILD_SETTINGS="$(strip $5) -DAMS_BUILD_FOR_AUDITING" ATMOSPHERE_BUILD_FOR_DEBUGGING=1 ATMOSPHERE_BUILD_FOR_AUDITING=1 $(strip $6) \ )) endef $(eval $(call ATMOSPHERE_ADD_TARGETS, nx, , nx-hac-001, arm-cortex-a57,,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, win_x64, , generic_windows, generic_x64,,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64, , generic_linux, generic_x64,,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, linux_x64_clang, clang_, generic_linux, generic_x64,, ATMOSPHERE_COMPILER_NAME="clang")) $(eval $(call ATMOSPHERE_ADD_TARGETS, linux_arm64_clang, clang_, generic_linux, generic_arm64,, ATMOSPHERE_COMPILER_NAME="clang")) $(eval $(call ATMOSPHERE_ADD_TARGETS, macos_x64, , generic_macos, generic_x64,,)) $(eval $(call ATMOSPHERE_ADD_TARGETS, macos_arm64, , generic_macos, generic_arm64,,)) clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config)) .PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS), $(config) clean-$(config)) ================================================ FILE: libraries/libstratosphere/README.md ================================================ ![License](https://img.shields.io/badge/License-GPLv2-blue.svg) libstratosphere is a work-in-progress C++ library for development of system modules for the Nintendo Switch. It is built around extending [libnx](https://github.com/switchbrew/libnx). It also provides bindings for custom extensions to Horizon OS implemented by [Atmosphère](https://github.com/Atmosphere-NX). Licensing ===== This software is licensed under the terms of the GPLv2, with exemptions for specific projects noted below. You can find a copy of the license in the [LICENSE file](LICENSE). Exemptions: * The [yuzu Nintendo Switch emulator](https://github.com/yuzu-emu/yuzu) and the [Ryujinx Team and Contributors](https://github.com/orgs/Ryujinx) are exempt from GPLv2 licensing. They are permitted, each at their individual discretion, to instead license any source code authored for the libstratosphere project as either GPLv2 or later or the [MIT license](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/licensing_exemptions/MIT_LICENSE). In doing so, they may alter, supplement, or entirely remove the copyright notice for each file they choose to relicense. Neither the Atmosphère project nor its individual contributors shall assert their moral rights against any of the aforementioned projects. * [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project under the Zero-Clause BSD license. Credits ===== libstratosphere is currently being developed and maintained by __SciresM__.<br> In addition to those credited in [Atmosphère's credits](https://github.com/Atmosphere-NX/Atmosphere/blob/master/README.md#Credits), we would like to thank for contributing to libstratosphere in some significant way: * __hthh__ * __fincs__ * __lioncash__ * __misson20000__ * __neobrain__ * __yellows8__ * @[Nintendo](https://github.com/Nintendo) ================================================ FILE: libraries/libstratosphere/discard-ehframe.ld ================================================ SECTIONS { /* Discard .eh_frame section */ /DISCARD/ : { *(.group .comment .note .interp) EXCLUDE_FILE(*crtbegin.o) *(.eh_frame_hdr .eh_frame) } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams/ams_emummc_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ams/ams_types.hpp> namespace ams::emummc { /* Get whether emummc is active. */ bool IsActive(); /* Get the active emummc id. */ u32 GetActiveId(); /* Get Nintendo redirection path. */ const char *GetNintendoDirPath(); /* Get Emummc folderpath, NULL if not file-based. */ const char *GetFilePath(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams/ams_environment.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ams/ams_types.hpp> namespace ams { /* Will be called by libstratosphere on crash. */ #if defined(ATMOSPHERE_OS_HORIZON) void CrashHandler(ThreadExceptionDump *ctx); #endif /* API for boot sysmodule. */ void InitializeForBoot(); void SetInitialRebootPayload(const void *src, size_t src_size); void *Malloc(size_t size); void Free(void *ptr); void *MallocForRapidJson(size_t size); void *ReallocForRapidJson(void *ptr, size_t size); void FreeForRapidJson(void *ptr); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams/ams_exosphere_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ams/ams_types.hpp> namespace ams::exosphere { ApiInfo GetApiInfo(); #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) void ForceRebootToRcm(); void ForceRebootToIramPayload(); void ForceRebootToFatalError(); void ForceRebootByPmic(); void ForceShutdown(); bool IsRcmBugPatched(); bool ShouldBlankProdInfo(); bool ShouldAllowWritesToProdInfo(); u64 GetDeviceId(); void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size); void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size); #endif } namespace ams { /* Version checking utility. */ inline void CheckApiVersion() { const u32 runtime_version = exosphere::GetApiInfo().GetVersion(); const u32 build_version = exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION); if (runtime_version < build_version) { R_ABORT_UNLESS(exosphere::ResultVersionMismatch()); } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams/ams_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> #include <stratosphere/hos.hpp> namespace ams::exosphere { using TargetFirmware = ams::TargetFirmware; constexpr ALWAYS_INLINE u32 GetVersion(u32 major, u32 minor, u32 micro) { return (major << 16) | (minor << 8) | (micro); } struct ApiInfo { using TargetFirmwareVersion = util::BitPack64::Field<0, 32, TargetFirmware>; using MasterKeyRevision = util::BitPack64::Field<TargetFirmwareVersion::Next, 8, u32>; using MicroVersion = util::BitPack64::Field<MasterKeyRevision::Next, 8, u32>; using MinorVersion = util::BitPack64::Field<MicroVersion::Next, 8, u32>; using MajorVersion = util::BitPack64::Field<MinorVersion::Next, 8, u32>; util::BitPack64 value; constexpr ALWAYS_INLINE u32 GetVersion() const { return ::ams::exosphere::GetVersion(this->GetMajorVersion(), this->GetMinorVersion(), this->GetMicroVersion()); } constexpr ALWAYS_INLINE u32 GetMajorVersion() const { return this->value.Get<MajorVersion>(); } constexpr ALWAYS_INLINE u32 GetMinorVersion() const { return this->value.Get<MinorVersion>(); } constexpr ALWAYS_INLINE u32 GetMicroVersion() const { return this->value.Get<MicroVersion>(); } constexpr ALWAYS_INLINE TargetFirmware GetTargetFirmware() const { return this->value.Get<TargetFirmwareVersion>(); } constexpr ALWAYS_INLINE u32 GetMasterKeyRevision() const { return this->value.Get<MasterKeyRevision>(); } }; } namespace ams { struct FatalErrorContext : ::ams::impl::FatalErrorContext, sf::LargeData, sf::PrefersMapAliasTransferMode {}; static_assert(sizeof(FatalErrorContext) == sizeof(::ams::impl::FatalErrorContext)); #ifdef ATMOSPHERE_GIT_BRANCH NX_CONSTEXPR const char *GetGitBranch() { return ATMOSPHERE_GIT_BRANCH; } #endif #ifdef ATMOSPHERE_GIT_REVISION NX_CONSTEXPR const char *GetGitRevision() { return ATMOSPHERE_GIT_REVISION; } #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::impl { struct SystemThreadDefinition { s32 priority; const char *name; }; #define AMS_DEFINE_SYSTEM_THREAD(__AMS_THREAD_PRIORITY__, __AMS_MODULE__, __AMS_THREAD_NAME__) \ constexpr inline const ::ams::impl::SystemThreadDefinition SystemThreadDefinition_##__AMS_MODULE__##_##__AMS_THREAD_NAME__ = { __AMS_THREAD_PRIORITY__, "ams." # __AMS_MODULE__ "." #__AMS_THREAD_NAME__ } /* sm. */ AMS_DEFINE_SYSTEM_THREAD(-1, sm, Main); AMS_DEFINE_SYSTEM_THREAD(-1, sm, DispatcherThread); /* spl. */ AMS_DEFINE_SYSTEM_THREAD(-1, spl, Main); /* Loader. */ AMS_DEFINE_SYSTEM_THREAD(21, ldr, Main); /* Process Manager. */ AMS_DEFINE_SYSTEM_THREAD(21, pm, Main); AMS_DEFINE_SYSTEM_THREAD(21, pm, ProcessTrack); /* NCM. */ AMS_DEFINE_SYSTEM_THREAD(21, ncm, MainWaitThreads); AMS_DEFINE_SYSTEM_THREAD(21, ncm, ContentManagerServerIpcSession); AMS_DEFINE_SYSTEM_THREAD(21, ncm, LocationResolverServerIpcSession); /* FS. */ AMS_DEFINE_SYSTEM_THREAD(11, sdmmc, DeviceDetector); AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool); AMS_DEFINE_SYSTEM_THREAD(17, fs, Main); AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess); AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess); AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess); AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess); AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader); /* Boot. */ AMS_DEFINE_SYSTEM_THREAD(-1, boot, Main); /* Mitm. */ AMS_DEFINE_SYSTEM_THREAD(-7, mitm, InitializeThread); AMS_DEFINE_SYSTEM_THREAD(-1, mitm_sf, QueryServerProcessThread); AMS_DEFINE_SYSTEM_THREAD(16, mitm_fs, RomFileSystemInitializeThread); AMS_DEFINE_SYSTEM_THREAD(16, mitm_fs, RomFileSystemFinalizeThread); AMS_DEFINE_SYSTEM_THREAD(21, mitm, DebugThrowThread); AMS_DEFINE_SYSTEM_THREAD(21, mitm_sysupdater, IpcServer); AMS_DEFINE_SYSTEM_THREAD(21, mitm_sysupdater, AsyncPrepareSdCardUpdateTask); /* boot2. */ AMS_DEFINE_SYSTEM_THREAD(20, boot2, Main); /* LogManager. */ AMS_DEFINE_SYSTEM_THREAD(10, LogManager, MainThread); AMS_DEFINE_SYSTEM_THREAD(10, lm, IpcServer); AMS_DEFINE_SYSTEM_THREAD(10, lm, Flush); AMS_DEFINE_SYSTEM_THREAD(10, lm, HtcsConnection); /* dmnt. */ AMS_DEFINE_SYSTEM_THREAD(-3, dmnt, MultiCoreEventManager); AMS_DEFINE_SYSTEM_THREAD(-1, dmnt, CheatDebugEvents); AMS_DEFINE_SYSTEM_THREAD(-1, dmnt, MultiCoreBP); AMS_DEFINE_SYSTEM_THREAD(11, dmnt, Main); AMS_DEFINE_SYSTEM_THREAD(11, dmnt, Ipc); AMS_DEFINE_SYSTEM_THREAD(11, dmnt, CheatDetect); AMS_DEFINE_SYSTEM_THREAD(20, dmnt, CheatVirtualMachine); /* fatal */ AMS_DEFINE_SYSTEM_THREAD(-13, fatal, Main); AMS_DEFINE_SYSTEM_THREAD(-13, fatalsrv, FatalTaskThread); AMS_DEFINE_SYSTEM_THREAD( 9, fatalsrv, IpcDispatcher); /* creport. */ AMS_DEFINE_SYSTEM_THREAD(16, creport, Main); /* ro. */ AMS_DEFINE_SYSTEM_THREAD(21, ro, Main); /* gpio. */ AMS_DEFINE_SYSTEM_THREAD(-12, gpio, InterruptHandler); /* bpc. */ AMS_DEFINE_SYSTEM_THREAD(4, bpc, IpcServer); /* powctl. */ AMS_DEFINE_SYSTEM_THREAD(9, powctl, InterruptHandler); /* hid. */ AMS_DEFINE_SYSTEM_THREAD(-10, hid, IpcServer); /* ns.*/ AMS_DEFINE_SYSTEM_THREAD(21, ns, ApplicationManagerIpcSession); AMS_DEFINE_SYSTEM_THREAD(21, nssrv, AsyncPrepareCardUpdateTask); /* settings. */ AMS_DEFINE_SYSTEM_THREAD(21, settings, Main); AMS_DEFINE_SYSTEM_THREAD(21, settings, IpcServer); AMS_DEFINE_SYSTEM_THREAD(21, settings, LazyWriter); /* erpt. */ AMS_DEFINE_SYSTEM_THREAD(21, erpt, Main); AMS_DEFINE_SYSTEM_THREAD(21, erpt, IpcServer); /* socket. */ AMS_DEFINE_SYSTEM_THREAD(29, socket, ResolverIpcServer); /* jpegdec. */ AMS_DEFINE_SYSTEM_THREAD(21, jpegdec, Main); /* pgl. */ AMS_DEFINE_SYSTEM_THREAD(21, pgl, Main); AMS_DEFINE_SYSTEM_THREAD(21, pgl, ProcessControlTask); /* htc. */ AMS_DEFINE_SYSTEM_THREAD(10, htc, Main); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcIpc); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcsIpc); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcsMonitor); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcfsIpc); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcfsMonitor); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowDiscovery); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowTcpServer); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowUsbIndication); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowListen); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowObserver); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowSend); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtclowReceive); AMS_DEFINE_SYSTEM_THREAD(10, htc, Htcmisc); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcmiscReceive); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcmiscSend); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcObserver); AMS_DEFINE_SYSTEM_THREAD(10, tma, BridgePcieDriver); /* cs/scs. */ AMS_DEFINE_SYSTEM_THREAD(20, cs, Main); AMS_DEFINE_SYSTEM_THREAD(20, cs, HidctlService); AMS_DEFINE_SYSTEM_THREAD(20, cs, HidctlLegacyServer); AMS_DEFINE_SYSTEM_THREAD(20, cs, AudioServer); AMS_DEFINE_SYSTEM_THREAD(10, cs, GrcVideoSender); AMS_DEFINE_SYSTEM_THREAD(10, cs, GrcVideoReader); AMS_DEFINE_SYSTEM_THREAD(10, cs, GrcAudioSender); AMS_DEFINE_SYSTEM_THREAD(10, cs, GrcAudioReader); AMS_DEFINE_SYSTEM_THREAD(21, scs, ShellServer); AMS_DEFINE_SYSTEM_THREAD(21, scs, ShellEventHandler); /* DevServer/TioServer. */ AMS_DEFINE_SYSTEM_THREAD(21, TioServer, Main); AMS_DEFINE_SYSTEM_THREAD(21, TioServer, FileServerHtcsServer); AMS_DEFINE_SYSTEM_THREAD(21, TioServer, SdCardObserver); AMS_DEFINE_SYSTEM_THREAD(16, memlet, Main); /* ServiceProfile */ AMS_DEFINE_SYSTEM_THREAD(-1, sprofile, IpcServer); #undef AMS_DEFINE_SYSTEM_THREAD } #define AMS_GET_SYSTEM_THREAD_PRIORITY(__AMS_MODULE__, __AMS_THREAD_NAME__) ( ::ams::impl::SystemThreadDefinition_##__AMS_MODULE__##_##__AMS_THREAD_NAME__ ).priority #define AMS_GET_SYSTEM_THREAD_NAME(__AMS_MODULE__, __AMS_THREAD_NAME__) ( ::ams::impl::SystemThreadDefinition_##__AMS_MODULE__##_##__AMS_THREAD_NAME__ ).name ================================================ FILE: libraries/libstratosphere/include/stratosphere/ams.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ams/ams_types.hpp> #include <stratosphere/ams/ams_exosphere_api.hpp> #include <stratosphere/ams/ams_emummc_api.hpp> #include <stratosphere/ams/ams_environment.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/boot2/boot2_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::boot2 { /* Boot2 API. */ /* Normally invoked by PM. */ void LaunchPreSdCardBootProgramsAndBoot2(); /* Normally invoked by boot2. */ void LaunchPostSdCardBootPrograms(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/boot2.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/boot2/boot2_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/cal/cal_battery_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::cal { Result GetBatteryVersion(u8 *out); Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cal.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/cal/cal_battery_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_control_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/vi/vi_layer_stack.hpp> namespace ams::capsrv { constexpr inline s32 DefaultCaptureTimeoutMilliSeconds = 100; Result InitializeScreenShotControl(); void FinalizeScreenShotControl(); Result OpenRawScreenShotReadStreamForDevelop(size_t *out_data_size, s32 *out_width, s32 *out_height, vi::LayerStack layer_stack, TimeSpan timeout); Result ReadRawScreenShotReadStreamForDevelop(size_t *out_read_size, void *dst, size_t dst_size, std::ptrdiff_t offset); void CloseRawScreenShotReadStreamForDevelop(); Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::capsrv { enum ScreenShotDecoderFlag : u64 { ScreenShotDecoderFlag_None = (0 << 0), ScreenShotDecoderFlag_EnableFancyUpsampling = (1 << 0), ScreenShotDecoderFlag_EnableBlockSmoothing = (1 << 1), }; using ScreenShotJpegDecoderFlagType = typename std::underlying_type<ScreenShotDecoderFlag>::type; struct ScreenShotDecodeOption { ScreenShotJpegDecoderFlagType flags; u8 reserved[0x20 - sizeof(ScreenShotJpegDecoderFlagType)]; static constexpr ScreenShotDecodeOption GetDefaultOption() { return ScreenShotDecodeOption{}; } constexpr bool HasJpegDecoderFlag(ScreenShotJpegDecoderFlagType flag) const { return (this->flags & flag) != 0; } }; static_assert(sizeof(ScreenShotDecodeOption) == 0x20); static_assert(util::is_pod<ScreenShotDecodeOption>::value); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(ScreenShotDecodeOption) == sizeof(::CapsScreenShotDecodeOption)); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/capsrv/server/capsrv_server_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::capsrv::server { constexpr inline int ScreenShotWidth = 1280; constexpr inline int ScreenShotHeight = 720; constexpr inline int MovieWidth = 1280; constexpr inline int MovieHeight = 720; constexpr inline size_t SoftwareJpegDecoderWorkMemorySize = 16_KB; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/capsrv/server/capsrv_server_decoder_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::capsrv::server { Result InitializeForDecoderServer(); void FinalizeForDecoderServer(); void DecoderControlServerThreadFunction(void *); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/capsrv.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/capsrv/capsrv_screen_shot_decode_option.hpp> #include <stratosphere/capsrv/server/capsrv_server_config.hpp> #include <stratosphere/capsrv/server/capsrv_server_decoder_api.hpp> #include <stratosphere/capsrv/capsrv_screen_shot_control_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/cfg/cfg_types.hpp> #include <stratosphere/cfg/cfg_locale_types.hpp> #include <stratosphere/sm/sm_types.hpp> namespace ams::cfg { /* SD card configuration. */ bool IsSdCardRequiredServicesReady(); void WaitSdCardRequiredServicesReady(); bool IsSdCardInitialized(); void WaitSdCardInitialized(); /* Override key utilities. */ OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id); /* Locale utilities. */ OverrideLocale GetOverrideLocale(ncm::ProgramId program_id); /* Flag utilities. */ bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag); bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag); bool HasGlobalFlag(const char *flag); Result DeleteGlobalFlag(const char *flag); /* HBL Configuration utilities. */ bool HasHblFlag(const char *flag); const char *GetHblPath(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cfg/cfg_locale_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/cfg/cfg_types.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::cfg { struct OverrideLocale { settings::LanguageCode language_code; settings::RegionCode region_code; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cfg/cfg_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::cfg { namespace impl { enum OverrideStatusFlag : u64 { OverrideStatusFlag_Hbl = (1u << 0), OverrideStatusFlag_ProgramSpecific = (1u << 1), OverrideStatusFlag_CheatEnabled = (1u << 2), OverrideStatusFlag_AddressSpaceShift = 3, OverrideStatusFlag_AddressSpaceMask = ((1u << 2) - 1) << OverrideStatusFlag_AddressSpaceShift, #if defined(ATMOSPHERE_OS_HORIZON) OverrideStatusFlag_AddressSpace32Bit = (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64BitDeprecated = (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace32BitWithoutAlias = (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, OverrideStatusFlag_AddressSpace64Bit = (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift) << OverrideStatusFlag_AddressSpaceShift, #endif }; } struct OverrideStatus { u64 keys_held; u64 flags; constexpr inline u64 GetKeysHeld() const { return this->keys_held; } #define DEFINE_FLAG_ACCESSORS(flag) \ constexpr inline bool Is##flag() const { return this->flags & impl::OverrideStatusFlag_##flag; } \ constexpr inline void Set##flag() { this->flags |= impl::OverrideStatusFlag_##flag; } \ constexpr inline void Clear##flag() { this->flags &= ~u64(impl::OverrideStatusFlag_##flag); } DEFINE_FLAG_ACCESSORS(Hbl) DEFINE_FLAG_ACCESSORS(ProgramSpecific) DEFINE_FLAG_ACCESSORS(CheatEnabled) #undef DEFINE_FLAG_ACCESSORS constexpr inline u64 GetOverrideAddressSpaceFlags() const { return this->flags & impl::OverrideStatusFlag_AddressSpaceMask; } constexpr inline bool HasOverrideAddressSpace() const { return this->IsHbl() && this->GetOverrideAddressSpaceFlags() != 0; } }; static_assert(sizeof(OverrideStatus) == 0x10, "sizeof(OverrideStatus)"); static_assert(util::is_pod<OverrideStatus>::value, "util::is_pod<OverrideStatus>::value"); constexpr inline bool operator==(const OverrideStatus &lhs, const OverrideStatus &rhs) { if (std::is_constant_evaluated()) { return lhs.keys_held == rhs.keys_held && lhs.flags == rhs.flags; } else { return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(lhs)) == 0; } } constexpr inline bool operator!=(const OverrideStatus &lhs, const OverrideStatus &rhs) { return !(lhs == rhs); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cfg.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/cfg/cfg_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/clkrst/clkrst_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/clkrst/clkrst_types.hpp> namespace ams::clkrst { void Initialize(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/clkrst/clkrst_session_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/clkrst/clkrst_types.hpp> namespace ams::clkrst { struct ClkRstSession { void *_session; }; Result OpenSession(ClkRstSession *out, DeviceCode device_code); void CloseSession(ClkRstSession *session); void SetResetAsserted(ClkRstSession *session); void SetResetDeasserted(ClkRstSession *session); void SetClockRate(ClkRstSession *session, u32 hz); void SetClockDisabled(ClkRstSession *session); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/clkrst/clkrst_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::clkrst { /* ... */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/clkrst.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/clkrst/clkrst_types.hpp> #include <stratosphere/clkrst/clkrst_api.hpp> #include <stratosphere/clkrst/clkrst_session_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs/cs_audio_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::cs { void InitializeAudioServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs/cs_command_processor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/scs/scs_command_processor.hpp> #include <stratosphere/vi/vi_layer_stack.hpp> namespace ams::cs { using CommandHeader = scs::CommandHeader; using ResponseHeader = scs::ResponseHeader; class CommandProcessor : public scs::CommandProcessor { public: virtual bool ProcessCommand(const CommandHeader &header, const u8 *body, s32 socket) override; private: void TakeScreenShot(const CommandHeader &header, s32 socket, vi::LayerStack layer_stack); private: static void SendFirmwareVersion(s32 socket, const CommandHeader &header); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs/cs_hid_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::cs { void InitializeHidServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs/cs_remote_video_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::cs { void InitializeRemoteVideoServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs/cs_target_io_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::cs { void InitializeTargetIoServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/cs.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/cs/cs_audio_server.hpp> #include <stratosphere/cs/cs_hid_server.hpp> #include <stratosphere/cs/cs_remote_video_server.hpp> #include <stratosphere/cs/cs_target_io_server.hpp> #include <stratosphere/cs/cs_command_processor.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_device_address_space_common.hpp> #include <stratosphere/dd/dd_device_address_space_types.hpp> #include <stratosphere/dd/dd_device_address_space_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_types.hpp> #include <stratosphere/dd/dd_device_address_space_common.hpp> #include <stratosphere/dd/dd_device_address_space_types.hpp> namespace ams::dd { Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 address, u64 size); Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 size); void DestroyDeviceAddressSpace(DeviceAddressSpaceType *das); void AttachDeviceAddressSpaceHandle(DeviceAddressSpaceType *das, DeviceAddressSpaceHandle handle, bool managed); DeviceAddressSpaceHandle GetDeviceAddressSpaceHandle(DeviceAddressSpaceType *das); Result MapDeviceAddressSpaceAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm); Result MapDeviceAddressSpaceNotAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm); void UnmapDeviceAddressSpace(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address); Result AttachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name); void DetachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_types.hpp> namespace ams::dd { #if defined(ATMOSPHERE_OS_HORIZON) using DeviceName = ::ams::svc::DeviceName; using enum ::ams::svc::DeviceName; #else enum DeviceName { }; #endif constexpr inline u64 DeviceAddressSpaceMemoryRegionAlignment = 4_KB; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_device_address_space_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_types.hpp> namespace ams::dd { using DeviceVirtualAddress = u64; using DeviceAddressSpaceHandle = os::NativeHandle; struct DeviceAddressSpaceType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; DeviceAddressSpaceHandle device_handle; u8 state; bool is_handle_managed; }; static_assert(std::is_trivial<DeviceAddressSpaceType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_io_mappings.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::dd { /* Convenience Helper. */ inline uintptr_t GetIoMapping(dd::PhysicalAddress phys_addr, size_t size) { const uintptr_t io_mapping = dd::QueryIoMapping(phys_addr, size); AMS_ABORT_UNLESS(io_mapping); return io_mapping; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_process_handle.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_types.hpp> namespace ams::dd { ProcessHandle GetCurrentProcessHandle(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd/dd_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::dd { using ProcessHandle = os::NativeHandle; using MemoryPermission = os::MemoryPermission; using enum os::MemoryPermission; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dd.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/dd/dd_types.hpp> #include <stratosphere/dd/dd_device_address_space.hpp> #include <stratosphere/dd/dd_io_mappings.hpp> #include <stratosphere/dd/dd_process_handle.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_device_code_entry.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ddsf { class IDevice; class DeviceCodeEntry { NON_COPYABLE(DeviceCodeEntry); NON_MOVEABLE(DeviceCodeEntry); private: ams::DeviceCode m_device_code = ams::InvalidDeviceCode; IDevice *m_device = nullptr; public: constexpr DeviceCodeEntry(ams::DeviceCode dc, IDevice *dev) : m_device_code(dc), m_device(dev) { AMS_ASSERT(dev != nullptr); } constexpr ams::DeviceCode GetDeviceCode() const { return m_device_code; } constexpr IDevice &GetDevice() { return *m_device; } constexpr const IDevice &GetDevice() const { return *m_device; } }; class DeviceCodeEntryHolder { NON_COPYABLE(DeviceCodeEntryHolder); NON_MOVEABLE(DeviceCodeEntryHolder); private: util::IntrusiveListNode m_list_node; util::TypedStorage<DeviceCodeEntry> m_entry_storage; bool m_is_constructed; public: using ListTraits = util::IntrusiveListMemberTraits<&DeviceCodeEntryHolder::m_list_node>; using List = typename ListTraits::ListType; friend class util::IntrusiveList<DeviceCodeEntryHolder, util::IntrusiveListMemberTraits<&DeviceCodeEntryHolder::m_list_node>>; public: DeviceCodeEntryHolder() : m_list_node(), m_entry_storage(), m_is_constructed(false) { /* ... */ } ~DeviceCodeEntryHolder() { if (this->IsConstructed()) { this->Destroy(); } } void AddTo(List &list) { list.push_back(*this); } void RemoveFrom(List list) { list.erase(list.iterator_to(*this)); } bool IsLinkedToList() const { return m_list_node.IsLinked(); } DeviceCodeEntry &Construct(DeviceCode dc, IDevice *dev) { AMS_ASSERT(!this->IsConstructed()); DeviceCodeEntry *entry = util::ConstructAt(m_entry_storage, dc, dev); m_is_constructed = true; return *entry; } bool IsConstructed() const { return m_is_constructed; } void Destroy() { AMS_ASSERT(this->IsConstructed()); util::DestroyAt(m_entry_storage); m_is_constructed = false; } DeviceCodeEntry &Get() { AMS_ASSERT(this->IsConstructed()); return GetReference(m_entry_storage); } const DeviceCodeEntry &Get() const { AMS_ASSERT(this->IsConstructed()); return GetReference(m_entry_storage); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_device_code_entry_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/impl/ddsf_for_each.hpp> #include <stratosphere/ddsf/ddsf_device_code_entry.hpp> namespace ams::ddsf { class IDevice; class DeviceCodeEntryManager { private: ams::MemoryResource *m_memory_resource; ddsf::DeviceCodeEntryHolder::List m_entry_list; mutable os::SdkMutex m_entry_list_lock; private: void DestroyAllEntries() { auto it = m_entry_list.begin(); while (it != m_entry_list.end()) { ddsf::DeviceCodeEntryHolder *entry = std::addressof(*it); it = m_entry_list.erase(it); AMS_ASSERT(entry->IsConstructed()); if (entry->IsConstructed()) { entry->Destroy(); } m_memory_resource->Deallocate(entry, sizeof(*entry)); } } public: DeviceCodeEntryManager(ams::MemoryResource *mr) : m_memory_resource(mr), m_entry_list(), m_entry_list_lock() { /* ... */ } ~DeviceCodeEntryManager() { this->DestroyAllEntries(); } void Reset() { std::scoped_lock lk(m_entry_list_lock); this->DestroyAllEntries(); } Result Add(DeviceCode device_code, IDevice *device); bool Remove(DeviceCode device_code); Result FindDeviceCodeEntry(DeviceCodeEntry **out, DeviceCode device_code); Result FindDeviceCodeEntry(const DeviceCodeEntry **out, DeviceCode device_code) const; Result FindDevice(IDevice **out, DeviceCode device_code); Result FindDevice(const IDevice **out, DeviceCode device_code) const; template<typename F> int ForEachEntry(F f) { return impl::ForEach(m_entry_list_lock, m_entry_list, [&](DeviceCodeEntryHolder &holder) -> bool { AMS_ASSERT(holder.IsConstructed()); return f(holder.Get()); }); } template<typename F> int ForEachEntry(F f) const { return impl::ForEach(m_entry_list_lock, m_entry_list, [&](const DeviceCodeEntryHolder &holder) -> bool { AMS_ASSERT(holder.IsConstructed()); return f(holder.Get()); }); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_event_handler_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/ddsf/ddsf_i_event_handler.hpp> namespace ams::ddsf { class EventHandlerManager; class EventHandlerManager { NON_COPYABLE(EventHandlerManager); NON_MOVEABLE(EventHandlerManager); private: struct LoopControlCommandParameters; private: bool m_is_initialized; bool m_is_looping; os::SdkConditionVariable m_is_looping_cv; os::MultiWaitType m_multi_wait; os::ThreadType *m_loop_thread; os::Event m_loop_control_event; os::MultiWaitHolderType m_loop_control_event_holder; LoopControlCommandParameters *m_loop_control_command_params; os::LightEvent m_loop_control_command_done_event; os::SdkMutex m_loop_control_lock; private: void ProcessControlCommand(LoopControlCommandParameters *params); void ProcessControlCommandImpl(LoopControlCommandParameters *params); public: EventHandlerManager() : m_is_initialized(false), m_is_looping(false), m_is_looping_cv(), m_multi_wait(), m_loop_thread(), m_loop_control_event(os::EventClearMode_AutoClear), m_loop_control_event_holder(), m_loop_control_command_params(), m_loop_control_command_done_event(os::EventClearMode_AutoClear), m_loop_control_lock() { this->Initialize(); } ~EventHandlerManager() { if (m_is_looping) { AMS_ASSERT(!this->IsRunningOnLoopThread()); this->RequestStop(); } if (m_is_initialized) { this->Finalize(); } } bool IsRunningOnLoopThread() const { return m_loop_thread == os::GetCurrentThread(); } bool IsLooping() const { return m_is_looping; } void Initialize(); void Finalize(); void RegisterHandler(IEventHandler *handler); void UnregisterHandler(IEventHandler *handler); void WaitLoopEnter(); void WaitLoopExit(); void RequestStop(); void LoopAuto(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/impl/ddsf_type_tag.hpp> namespace ams::ddsf { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) #define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \ static_assert(std::convertible_to<__CLASS__ *, __BASE__ *>); \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{#__CLASS__, __BASE__::s_ams_ddsf_castable_type_tag}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } #else #define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \ static_assert(std::convertible_to<__CLASS__ *, __BASE__ *>); \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{__BASE__::s_ams_ddsf_castable_type_tag}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } #endif class ICastable { private: constexpr virtual const impl::TypeTag &GetTypeTag() const = 0; template<typename T> constexpr ALWAYS_INLINE void AssertCastableTo() const { AMS_ASSERT(this->IsCastableTo<T>()); } public: template<typename T> constexpr bool IsCastableTo() const { return this->GetTypeTag().DerivesFrom(T::s_ams_ddsf_castable_type_tag); } template<typename T> constexpr T &SafeCastTo() { this->AssertCastableTo<T>(); return static_cast<T &>(*this); } template<typename T> constexpr const T &SafeCastTo() const { this->AssertCastableTo<T>(); return static_cast<const T &>(*this); } template<typename T> constexpr T *SafeCastToPointer() { this->AssertCastableTo<T>(); return static_cast<T *>(this); } template<typename T> constexpr const T *SafeCastToPointer() const { this->AssertCastableTo<T>(); return static_cast<const T *>(this); } #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) constexpr const char *GetClassName() const { return this->GetTypeTag().GetClassName(); } #endif }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_device.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_sdk_mutex.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/impl/ddsf_for_each.hpp> #include <stratosphere/ddsf/ddsf_i_castable.hpp> #include <stratosphere/ddsf/ddsf_i_session.hpp> namespace ams::ddsf { class IDriver; class IDevice : public ICastable { friend Result OpenSession(IDevice *device, ISession *session, AccessMode mode); friend void CloseSession(ISession *session); friend class IDriver; public: AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDevice); private: util::IntrusiveListNode m_list_node; IDriver *m_driver; ISession::List m_session_list; mutable os::SdkMutex m_session_list_lock; bool m_is_exclusive_write; public: using ListTraits = util::IntrusiveListMemberTraits<&IDevice::m_list_node>; using List = typename ListTraits::ListType; friend class util::IntrusiveList<IDevice, util::IntrusiveListMemberTraits<&IDevice::m_list_node>>; private: Result AttachSession(ISession *session) { AMS_ASSERT(session != nullptr); std::scoped_lock lk(m_session_list_lock); /* Check if we're allowed to attach the session. */ if (m_is_exclusive_write && session->CheckExclusiveWrite()) { for (const auto &attached : m_session_list) { R_UNLESS(!attached.CheckAccess(AccessMode_Write), ddsf::ResultAccessModeDenied()); } } /* Attach the session. */ m_session_list.push_back(*session); R_SUCCEED(); } void DetachSession(ISession *session) { AMS_ASSERT(session != nullptr); std::scoped_lock lk(m_session_list_lock); m_session_list.erase(m_session_list.iterator_to(*session)); } void AttachDriver(IDriver *drv) { AMS_ASSERT(drv != nullptr); AMS_ASSERT(!this->IsDriverAttached()); m_driver = drv; AMS_ASSERT(this->IsDriverAttached()); } void DetachDriver() { AMS_ASSERT(this->IsDriverAttached()); m_driver = nullptr; AMS_ASSERT(!this->IsDriverAttached()); } public: IDevice(bool exclusive_write) : m_list_node(), m_driver(nullptr), m_session_list(), m_session_list_lock(), m_is_exclusive_write(exclusive_write) { m_session_list.clear(); } protected: virtual ~IDevice() { m_session_list.clear(); } public: void AddTo(List &list) { list.push_back(*this); } void RemoveFrom(List list) { list.erase(list.iterator_to(*this)); } bool IsLinkedToList() const { return m_list_node.IsLinked(); } IDriver &GetDriver() { AMS_ASSERT(this->IsDriverAttached()); return *m_driver; } const IDriver &GetDriver() const { AMS_ASSERT(this->IsDriverAttached()); return *m_driver; } bool IsDriverAttached() const { return m_driver != nullptr; } template<typename F> Result ForEachSession(F f, bool return_on_fail) { R_RETURN(impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail)); } template<typename F> Result ForEachSession(F f, bool return_on_fail) const { R_RETURN(impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail)); } template<typename F> int ForEachSession(F f) { return impl::ForEach(m_session_list_lock, m_session_list, f); } template<typename F> int ForEachSession(F f) const { return impl::ForEach(m_session_list_lock, m_session_list, f); } bool HasAnyOpenSession() const { return !m_session_list.empty(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_sdk_mutex.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/impl/ddsf_for_each.hpp> #include <stratosphere/ddsf/ddsf_i_castable.hpp> #include <stratosphere/ddsf/ddsf_i_device.hpp> namespace ams::ddsf { class IDriver : public ICastable { public: AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDriver); private: util::IntrusiveListNode m_list_node; IDevice::List m_device_list; mutable os::SdkMutex m_device_list_lock; public: using ListTraits = util::IntrusiveListMemberTraits<&IDriver::m_list_node>; using List = typename ListTraits::ListType; friend class util::IntrusiveList<IDriver, util::IntrusiveListMemberTraits<&IDriver::m_list_node>>; private: public: IDriver() : m_list_node(), m_device_list(), m_device_list_lock() { m_device_list.clear(); } protected: virtual ~IDriver() { m_device_list.clear(); } public: void AddTo(List &list) { list.push_back(*this); } void RemoveFrom(List list) { list.erase(list.iterator_to(*this)); } bool IsLinkedToList() const { return m_list_node.IsLinked(); } bool HasAnyDevice() const { return !m_device_list.empty(); } void RegisterDevice(IDevice *dev) { AMS_ASSERT(dev != nullptr); std::scoped_lock lk(m_device_list_lock); dev->AttachDriver(this); m_device_list.push_back(*dev); } void UnregisterDevice(IDevice *dev) { AMS_ASSERT(dev != nullptr); std::scoped_lock lk(m_device_list_lock); m_device_list.erase(m_device_list.iterator_to(*dev)); dev->DetachDriver(); } template<typename F> Result ForEachDevice(F f, bool return_on_fail) { R_RETURN(impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail)); } template<typename F> Result ForEachDevice(F f, bool return_on_fail) const { R_RETURN(impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail)); } template<typename F> int ForEachDevice(F f) { return impl::ForEach(m_device_list_lock, m_device_list, f); } template<typename F> int ForEachDevice(F f) const { return impl::ForEach(m_device_list_lock, m_device_list, f); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::ddsf { class EventHandlerManager; class IEventHandler { NON_COPYABLE(IEventHandler); NON_MOVEABLE(IEventHandler); friend class EventHandlerManager; private: os::MultiWaitHolderType m_holder; uintptr_t m_user_data; bool m_is_initialized; bool m_is_registered; private: void Link(os::MultiWaitType *multi_wait) { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(!this->IsRegistered()); AMS_ASSERT(multi_wait != nullptr); os::LinkMultiWaitHolder(multi_wait, std::addressof(m_holder)); } void Unlink() { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(this->IsRegistered()); os::UnlinkMultiWaitHolder(std::addressof(m_holder)); } static IEventHandler &ToEventHandler(os::MultiWaitHolderType *holder) { AMS_ASSERT(holder != nullptr); auto &event_handler = *reinterpret_cast<IEventHandler *>(os::GetMultiWaitHolderUserData(holder)); AMS_ASSERT(event_handler.IsInitialized()); return event_handler; } public: IEventHandler() : m_holder(), m_user_data(0), m_is_initialized(false), m_is_registered(false) { /* ... */ } virtual ~IEventHandler() { if (this->IsRegistered()) { this->Unlink(); } if (this->IsInitialized()) { this->Finalize(); } } bool IsInitialized() const { return m_is_initialized; } bool IsRegistered() const { return m_is_registered; } uintptr_t GetUserData() const { return m_user_data; } void SetUserData(uintptr_t d) { m_user_data = d; } template<typename T> void Initialize(T *object) { AMS_ASSERT(object != nullptr); AMS_ASSERT(!this->IsInitialized()); os::InitializeMultiWaitHolder(std::addressof(m_holder), object); os::SetMultiWaitHolderUserData(std::addressof(m_holder), reinterpret_cast<uintptr_t>(this)); m_is_initialized = true; m_is_registered = false; } void Finalize() { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(!this->IsRegistered()); os::FinalizeMultiWaitHolder(std::addressof(m_holder)); m_is_initialized = false; m_is_registered = false; } protected: virtual void HandleEvent() = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/impl/ddsf_for_each.hpp> #include <stratosphere/ddsf/ddsf_i_castable.hpp> namespace ams::ddsf { class ISession; class IDevice; Result OpenSession(IDevice *device, ISession *session, AccessMode access_mode); void CloseSession(ISession *session); class ISession : public ICastable { friend Result OpenSession(IDevice *device, ISession *session, AccessMode mode); friend void CloseSession(ISession *session); public: AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDevice); private: util::IntrusiveListNode m_list_node; IDevice *m_device; AccessMode m_access_mode; public: using ListTraits = util::IntrusiveListMemberTraits<&ISession::m_list_node>; using List = typename ListTraits::ListType; friend class util::IntrusiveList<ISession, util::IntrusiveListMemberTraits<&ISession::m_list_node>>; private: void AttachDevice(IDevice *dev, AccessMode mode) { AMS_ASSERT(dev != nullptr); AMS_ASSERT(!this->IsOpen()); m_device = dev; m_access_mode = mode; AMS_ASSERT(this->IsOpen()); } void DetachDevice() { /* AMS_ASSERT(this->IsOpen()); */ m_device = nullptr; m_access_mode = AccessMode_None; AMS_ASSERT(!this->IsOpen()); } public: ISession() : m_list_node(), m_device(nullptr), m_access_mode() { /* ... */ } protected: virtual ~ISession() { this->DetachDevice(); AMS_ASSERT(!this->IsOpen()); } public: void AddTo(List &list) { list.push_back(*this); } void RemoveFrom(List list) { list.erase(list.iterator_to(*this)); } bool IsLinkedToList() const { return m_list_node.IsLinked(); } IDevice &GetDevice() { AMS_ASSERT(this->IsOpen()); return *m_device; } const IDevice &GetDevice() const { AMS_ASSERT(this->IsOpen()); return *m_device; } bool IsOpen() const { return m_device != nullptr; } bool CheckAccess(AccessMode mode) const { AMS_ASSERT(this->IsOpen()); return ((~m_access_mode) & mode) == 0; } bool CheckExclusiveWrite() const { return this->CheckAccess(AccessMode_Write) && !this->CheckAccess(AccessMode_Shared); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_device_code_entry.hpp> namespace ams::ddsf { void SetMemoryResource(ams::MemoryResource *mr); ams::MemoryResource *GetMemoryResource(); static constexpr size_t DeviceCodeEntryHolderSize = sizeof(DeviceCodeEntryHolder); void SetDeviceCodeEntryHolderMemoryResource(ams::MemoryResource *mr); ams::MemoryResource *GetDeviceCodeEntryHolderMemoryResource(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/ddsf_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ddsf { enum AccessMode { AccessMode_None = (0u << 0), AccessMode_Read = (1u << 0), AccessMode_Write = (1u << 1), AccessMode_Shared = (1u << 2), AccessMode_ReadWrite = AccessMode_Read | AccessMode_Write, AccessMode_WriteShared = AccessMode_Write | AccessMode_Shared, AccessMode_ReadWriteShared = AccessMode_Read | AccessMode_WriteShared, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_for_each.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ddsf::impl { template<typename Lock, typename List, typename F> inline Result ForEach(Lock &lock, List &list, F f, bool return_on_fail) { std::scoped_lock lk(lock); Result result = ResultSuccess(); for (auto && it : list) { if (const auto cur_result = f(std::addressof(it)); R_FAILED(cur_result)) { if (return_on_fail) { R_RETURN(cur_result); } else if (R_SUCCEEDED(result)) { result = cur_result; } } } R_RETURN(result); } template<typename List, typename F, typename Lock> inline int ForEach(Lock &lock, List &list, F f) { std::scoped_lock lk(lock); int success_count = 0; for (auto && it : list) { if (!f(it)) { return success_count; } ++success_count; } return success_count; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf/impl/ddsf_type_tag.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> namespace ams::ddsf::impl { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) #define AMS_DDSF_CASTABLE_ROOT_TRAITS(__CLASS__) \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{#__CLASS__}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } #else #define AMS_DDSF_CASTABLE_ROOT_TRAITS(__CLASS__) \ public: \ static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{}; \ constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; } #endif class TypeTag { private: const char * const m_class_name; const TypeTag * const m_base; public: #if !(defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)) constexpr TypeTag() : m_class_name(nullptr), m_base(nullptr) { /* ... */} constexpr TypeTag(const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_ASSERT(this != m_base); } } constexpr TypeTag(const char *c) : m_class_name(nullptr), m_base(nullptr) { AMS_UNUSED(c); } constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(nullptr), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_UNUSED(c); AMS_ASSERT(this != m_base); } } #else constexpr TypeTag(const char *c) : m_class_name(c), m_base(nullptr) { /* ... */ } constexpr TypeTag(const char *c, const TypeTag &b) : m_class_name(c), m_base(std::addressof(b)) { if (!std::is_constant_evaluated()) { AMS_ASSERT(this != m_base); } } #endif constexpr const char * GetClassName() const { return m_class_name; } constexpr bool Is(const TypeTag &rhs) const { return this == std::addressof(rhs); } constexpr bool DerivesFrom(const TypeTag &rhs) const { const TypeTag * cur = this; while (cur != nullptr) { if (cur == std::addressof(rhs)) { return true; } cur = cur->m_base; } return false; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ddsf.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/ddsf/ddsf_i_castable.hpp> #include <stratosphere/ddsf/ddsf_i_session.hpp> #include <stratosphere/ddsf/ddsf_i_device.hpp> #include <stratosphere/ddsf/ddsf_i_driver.hpp> #include <stratosphere/ddsf/ddsf_device_code_entry.hpp> #include <stratosphere/ddsf/ddsf_device_code_entry_manager.hpp> #include <stratosphere/ddsf/ddsf_i_event_handler.hpp> #include <stratosphere/ddsf/ddsf_event_handler_manager.hpp> #include <stratosphere/ddsf/ddsf_memory_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/diag_log_types.hpp> namespace ams::diag { using AbortObserver = void (*)(const AbortInfo &); struct AbortObserverHolder { AbortObserver observer; AbortObserverHolder *next; bool is_registered; }; void InitializeAbortObserverHolder(AbortObserverHolder *holder, AbortObserver observer); void RegisterAbortObserver(AbortObserverHolder *holder); void UnregisterAbortObserver(AbortObserverHolder *holder); void EnableDefaultAbortObserver(bool en); struct SdkAbortInfo { AbortInfo abort_info; Result result; const ::ams::os::UserExceptionInfo *exc_info; }; using SdkAbortObserver = void (*)(const SdkAbortInfo &); struct SdkAbortObserverHolder { SdkAbortObserver observer; SdkAbortObserverHolder *next; bool is_registered; }; void InitializeSdkAbortObserverHolder(SdkAbortObserverHolder *holder, SdkAbortObserver observer); void RegisterSdkAbortObserver(SdkAbortObserverHolder *holder); void UnregisterSdkAbortObserver(SdkAbortObserverHolder *holder); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/diag_log_types.hpp> namespace ams::diag { enum AssertionFailureOperation { AssertionFailureOperation_Abort, AssertionFailureOperation_Continue, }; using AssertionFailureHandler = AssertionFailureOperation (*)(const AssertionInfo &info); void SetAssertionFailureHandler(AssertionFailureHandler handler); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp> #elif defined(ATMOSPHERE_OS_LINUX) #include <stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp> #elif defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp> #else #error "Unknown OS for diag::Backtrace" #endif namespace ams::diag { size_t GetBacktrace(uintptr_t *out, size_t out_size); #if defined(ATMOSPHERE_OS_HORIZON) size_t GetBacktace(uintptr_t *out, size_t out_size, uintptr_t fp, uintptr_t sp, uintptr_t pc); #endif class Backtrace { private: impl::Backtrace m_impl; public: NOINLINE Backtrace() { m_impl.Initialize(); m_impl.Step(); } #if defined(ATMOSPHERE_OS_HORIZON) Backtrace(uintptr_t fp, uintptr_t sp, uintptr_t pc) { m_impl.Initialize(fp, sp, pc); } #endif bool Step() { return m_impl.Step(); } uintptr_t GetStackPointer() const { return m_impl.GetStackPointer(); } uintptr_t GetReturnAddress() const { return m_impl.GetReturnAddress(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/impl/diag_impl_structured_log.hpp> #if defined(AMS_IMPL_ENABLE_LOG) #define AMS_LOG(...) AMS_IMPL_STRUCTURED_LOG_IMPL("", ::ams::diag::LogSeverity_Info, 0, __VA_ARGS__) #define AMS_VLOG(_FMT_, _VL_) AMS_IMPL_STRUCTURED_VLOG_IMPL("", ::ams::diag::LogSeverity_Info, 0, _FMT_, _VL_) #define AMS_PUT(_MSG_, _ML_) AMS_IMPL_STRUCTURED_PUT_IMPL("", ::ams::diag::LogSeverity_Info, 0, _MSG_, _ML_) #define AMS_STRUCTURED_LOG(_MOD_, _SEV_, _VER_, ...) AMS_IMPL_STRUCTURED_LOG_IMPL(_MOD_, _SEV_, _VER_, __VA_ARGS__) #define AMS_STRUCTURED_VLOG(_MOD_, _SEV_, _VER_, _FMT_, _VL_) AMS_IMPL_STRUCTURED_VLOG_IMPL(_MOD_, _SEV_, _VER_, _FMT_, _VL_) #define AMS_STRUCTURED_PUT(_MOD_, _SEV_, _VER_, _MSG_, _ML_) AMS_IMPL_STRUCTURED_PUT_IMPL(_MOD_, _SEV_, _VER_, _MSG_, _ML_) #else #define AMS_LOG(...) do { /* ... */ } while (false) #define AMS_VLOG(_FMT_, _VL_) do { /* ... */ } while (false) #define AMS_PUT(_MSG_, _ML_) do { /* ... */ } while (false) #define AMS_STRUCTURED_LOG(_MOD_, _SEV_, _VER_, ...) do { /* ... */ } while (false) #define AMS_STRUCTURED_VLOG(_MOD_, _SEV_, _VER_, _FMT_, _VL_) do { /* ... */ } while (false) #define AMS_STRUCTURED_PUT(_MOD_, _SEV_, _VER_, _MSG_, _ML_) do { /* ... */ } while (false) #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_log_observer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/diag_log_types.hpp> namespace ams::diag { using LogObserver = void (*)(const LogMetaData &meta, const LogBody &body, void *arg); struct LogObserverHolder { LogObserver log_observer; LogObserverHolder *next; bool is_registered; void *arg; }; constexpr inline void InitializeLogObserverHolder(LogObserverHolder *holder, LogObserver observer, void *arg) { holder->log_observer = observer; holder->next = nullptr; holder->is_registered = false; holder->arg = arg; } void RegisterLogObserver(LogObserverHolder *holder); void UnregisterLogObserver(LogObserverHolder *holder); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_log_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag { enum LogSeverity { LogSeverity_Trace = 0, LogSeverity_Info = 1, LogSeverity_Warn = 2, LogSeverity_Error = 3, LogSeverity_Fatal = 4, }; struct SourceInfo { int line_number; const char *file_name; const char *function_name; }; struct LogMetaData { SourceInfo source_info; const char *module_name; LogSeverity severity; int verbosity; bool use_default_locale_charset; void *additional_data; size_t additional_data_size; }; struct LogBody { const char *message; size_t message_size; bool is_head; bool is_tail; }; struct LogMessage { const char *fmt; std::va_list *vl; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_sdk_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/impl/diag_impl_structured_log.hpp> #if defined(AMS_IMPL_ENABLE_SDK_LOG) #define AMS_SDK_LOG(...) AMS_IMPL_STRUCTURED_LOG_IMPL("$", ::ams::diag::LogSeverity_Info, 0, __VA_ARGS__) #define AMS_SDK_VLOG(_FMT_, _VL_) AMS_IMPL_STRUCTURED_VLOG_IMPL("$", ::ams::diag::LogSeverity_Info, 0, _FMT_, _VL_) #define AMS_SDK_PUT(_MSG_, _ML_) AMS_IMPL_STRUCTURED_PUT_IMPL("$", ::ams::diag::LogSeverity_Info, 0, _MSG_, _ML_) #else #define AMS_SDK_LOG(...) do { /* ... */ } while (false) #define AMS_SDK_VLOG(_FMT_, _VL_) do { /* ... */ } while (false) #define AMS_SDK_PUT(_MSG_, _ML_) do { /* ... */ } while (false) #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/diag_symbol.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag { uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address); size_t GetSymbolSize(uintptr_t address); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag::impl { class Backtrace { private: static constexpr size_t MemoryInfoBufferSize = 5; public: struct StackInfo { uintptr_t stack_top; uintptr_t stack_bottom; }; private: s64 m_memory_info_buffer[MemoryInfoBufferSize]{}; StackInfo *m_current_stack_info = nullptr; StackInfo m_exception_stack_info{}; StackInfo m_normal_stack_info{}; uintptr_t m_fp = 0; uintptr_t m_prev_fp = 0; uintptr_t m_lr = 0; public: Backtrace() = default; void Initialize(); void Initialize(uintptr_t fp, uintptr_t sp, uintptr_t pc); bool Step(); uintptr_t GetStackPointer() const; uintptr_t GetReturnAddress() const; private: void SetStackInfo(uintptr_t fp, uintptr_t sp); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag::impl { class Backtrace { private: static constexpr size_t BacktraceEntryCountMax = 0x80; private: void *m_backtrace_addresses[BacktraceEntryCountMax]; size_t m_index = 0; size_t m_size = 0; public: Backtrace() = default; void Initialize(); bool Step(); uintptr_t GetStackPointer() const; uintptr_t GetReturnAddress() const; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag::impl { class Backtrace { private: static constexpr size_t BacktraceEntryCountMax = 0x80; private: void *m_backtrace_addresses[BacktraceEntryCountMax]; size_t m_index = 0; size_t m_size = 0; public: Backtrace() = default; void Initialize(); bool Step(); uintptr_t GetStackPointer() const; uintptr_t GetReturnAddress() const; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag::impl { class Backtrace { private: static constexpr size_t BacktraceEntryCountMax = 0x80; private: void *m_backtrace_addresses[BacktraceEntryCountMax]; size_t m_index = 0; size_t m_size = 0; public: Backtrace() = default; void Initialize(); bool Step(); uintptr_t GetStackPointer() const; uintptr_t GetReturnAddress() const; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_impl_build_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) #define AMS_IMPL_ENABLE_SDK_LOG #else //#define AMS_IMPL_ENABLE_SDK_LOG #endif #if defined(AMS_ENABLE_LOG) #define AMS_IMPL_ENABLE_LOG #if defined(AMS_DISABLE_LOG) #error "Incoherent log configuration" #endif #elif defined(AMS_DISABLE_LOG) #elif defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) #define AMS_IMPL_ENABLE_LOG #else //#define AMS_IMPL_ENABLE_LOG #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_impl_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/diag_log_types.hpp> namespace ams::diag::impl { void LogImpl(const LogMetaData &meta, const char *fmt, ...) __attribute__((format(printf, 2, 3))); void VLogImpl(const LogMetaData &meta, const char *fmt, std::va_list vl); void PutImpl(const LogMetaData &meta, const char *msg, size_t msg_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_impl_structured_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/impl/diag_impl_build_config.hpp> #include <stratosphere/diag/impl/diag_impl_log.hpp> #if defined(AMS_IMPL_ENABLE_LOG) || defined(AMS_IMPL_ENABLE_SDK_LOG) #define AMS_IMPL_LOG_META_DATA(_MOD_, _SEV_, _VER_) \ (::ams::diag::LogMetaData { \ { __LINE__, __FILE__, AMS_CURRENT_FUNCTION_NAME }, \ _MOD_, \ _SEV_, \ _VER_, \ false, \ nullptr, \ 0, \ }) #define AMS_IMPL_STRUCTURED_LOG_IMPL(_MOD_, _SEV_, _VER_, ...) ::ams::diag::impl::LogImpl(AMS_IMPL_LOG_META_DATA(_MOD_, _SEV_, _VER_), __VA_ARGS__) #define AMS_IMPL_STRUCTURED_VLOG_IMPL(_MOD_, _SEV_, _VER_, _FMT_, _VL_) ::ams::diag::impl::VLogImpl(AMS_IMPL_LOG_META_DATA(_MOD_, _SEV_, _VER_), _FMT_, _VL_) #define AMS_IMPL_STRUCTURED_PUT_IMPL(_MOD_, _SEV_, _VER_, _MSG_, _ML_) ::ams::diag::impl::PutImpl(AMS_IMPL_LOG_META_DATA(_MOD_, _SEV_, _VER_), _MSG_, _ML_) #else #define AMS_IMPL_STRUCTURED_LOG_IMPL(_MOD_, _SEV_, _VER_, ...) do { /* ... */ } while (false) #define AMS_IMPL_STRUCTURED_VLOG_IMPL(_MOD_, _SEV_, _VER_, _FMT_, _VL_) do { /* ... */ } while (false) #define AMS_IMPL_STRUCTURED_PUT_IMPL(_MOD_, _SEV_, _VER_, _MSG_, _ML_) do { /* ... */ } while (false) #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_impl_structured_sdk_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/diag/impl/diag_impl_build_config.hpp> #include <stratosphere/diag/impl/diag_impl_structured_log.hpp> #if defined(AMS_IMPL_ENABLE_SDK_LOG) #define AMS_IMPL_STRUCTURED_SDK_LOG(_MOD_, _SEV_, _VER_, ...) AMS_IMPL_STRUCTURED_LOG_IMPL("$" #_MOD_ , ::ams::diag::LogSeverity_##_SEV_, _VER_, __VA_ARGS__) #define AMS_IMPL_STRUCTURED_SDK_VLOG(_MOD_, _SEV_, _VER_, _FMT_, _VL_) AMS_IMPL_STRUCTURED_VLOG_IMPL("$" #_MOD_ , ::ams::diag::LogSeverity_##_SEV_, _VER_, _FMT_, _VL_) #define AMS_IMPL_STRUCTURED_SDK_PUT(_MOD_, _SEV_, _VER_, _MSG_, _ML_) AMS_IMPL_STRUCTURED_PUT_IMPL("$" #_MOD_ , ::ams::diag::LogSeverity_##_SEV_, _VER_, _MSG_, _ML_) #else #define AMS_IMPL_STRUCTURED_SDK_LOG(_MOD_, _SEV_, _VER_, ...) do { /* ... */ } while (false) #define AMS_IMPL_STRUCTURED_SDK_VLOG(_MOD_, _SEV_, _VER_, _FMT_, _VL_) do { /* ... */ } while (false) #define AMS_IMPL_STRUCTURED_SDK_PUT(_MOD_, _SEV_, _VER_, _MSG_, _ML_) do { /* ... */ } while (false) #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag/impl/diag_utf8_util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::diag::impl { int GetValidSizeAsUtf8String(const char *str, size_t len); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/diag.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/diag/diag_log_types.hpp> #include <stratosphere/diag/diag_log_observer.hpp> #include <stratosphere/diag/impl/diag_impl_log.hpp> #include <stratosphere/diag/diag_log.hpp> #include <stratosphere/diag/diag_sdk_log.hpp> #include <stratosphere/diag/diag_abort_observer.hpp> #include <stratosphere/diag/diag_assertion_failure_handler.hpp> #include <stratosphere/diag/impl/diag_utf8_util.hpp> #include <stratosphere/diag/diag_backtrace.hpp> #include <stratosphere/diag/diag_symbol.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/dmnt/dmnt_cheat_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::dmnt::cheat { struct CheatProcessMetadata { struct MemoryRegionExtents { u64 base; u64 size; }; os::ProcessId process_id; ncm::ProgramId program_id; MemoryRegionExtents main_nso_extents; MemoryRegionExtents heap_extents; MemoryRegionExtents alias_extents; MemoryRegionExtents aslr_extents; u8 main_nso_module_id[0x20]; }; static_assert(util::is_pod<CheatProcessMetadata>::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!"); struct CheatDefinition : sf::LargeData, sf::PrefersMapAliasTransferMode { char readable_name[0x40]; uint32_t num_opcodes; uint32_t opcodes[0x100]; }; struct CheatEntry : sf::LargeData, sf::PrefersMapAliasTransferMode { bool enabled; uint32_t cheat_id; CheatDefinition definition; }; static_assert(util::is_pod<CheatDefinition>::value, "CheatDefinition"); static_assert(util::is_pod<CheatEntry>::value, "CheatEntry"); struct FrozenAddressValue { u64 value; u8 width; }; struct FrozenAddressEntry { u64 address; FrozenAddressValue value; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/dmnt.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/dmnt/dmnt_cheat_types.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/erpt_ids.autogen.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> /* NOTE: This file is auto-generated. */ /* Do not make edits to this file by hand. */ #define AMS_ERPT_FOREACH_FIELD_TYPE(HANDLER) \ HANDLER(FieldType_NumericU64, 0 ) \ HANDLER(FieldType_NumericU32, 1 ) \ HANDLER(FieldType_NumericI64, 2 ) \ HANDLER(FieldType_NumericI32, 3 ) \ HANDLER(FieldType_String, 4 ) \ HANDLER(FieldType_U8Array, 5 ) \ HANDLER(FieldType_U32Array, 6 ) \ HANDLER(FieldType_U64Array, 7 ) \ HANDLER(FieldType_I32Array, 8 ) \ HANDLER(FieldType_I64Array, 9 ) \ HANDLER(FieldType_Bool, 10) \ HANDLER(FieldType_NumericU16, 11) \ HANDLER(FieldType_NumericU8, 12) \ HANDLER(FieldType_NumericI16, 13) \ HANDLER(FieldType_NumericI8, 14) \ HANDLER(FieldType_I8Array, 15) #define AMS_ERPT_FOREACH_CATEGORY(HANDLER) \ HANDLER(Test, 0 ) \ HANDLER(ErrorInfo, 1 ) \ HANDLER(ConnectionStatusInfo, 2 ) \ HANDLER(NetworkInfo, 3 ) \ HANDLER(NXMacAddressInfo, 4 ) \ HANDLER(StealthNetworkInfo, 5 ) \ HANDLER(LimitHighCapacityInfo, 6 ) \ HANDLER(NATTypeInfo, 7 ) \ HANDLER(WirelessAPMacAddressInfo, 8 ) \ HANDLER(GlobalIPAddressInfo, 9 ) \ HANDLER(EnableWirelessInterfaceInfo, 10 ) \ HANDLER(EnableWifiInfo, 11 ) \ HANDLER(EnableBluetoothInfo, 12 ) \ HANDLER(EnableNFCInfo, 13 ) \ HANDLER(NintendoZoneSSIDListVersionInfo, 14 ) \ HANDLER(LANAdapterMacAddressInfo, 15 ) \ HANDLER(ApplicationInfo, 16 ) \ HANDLER(OccurrenceInfo, 17 ) \ HANDLER(ProductModelInfo, 18 ) \ HANDLER(CurrentLanguageInfo, 19 ) \ HANDLER(UseNetworkTimeProtocolInfo, 20 ) \ HANDLER(TimeZoneInfo, 21 ) \ HANDLER(ControllerFirmwareInfo, 22 ) \ HANDLER(VideoOutputInfo, 23 ) \ HANDLER(NANDFreeSpaceInfo, 24 ) \ HANDLER(SDCardFreeSpaceInfo, 25 ) \ HANDLER(ScreenBrightnessInfo, 26 ) \ HANDLER(AudioFormatInfo, 27 ) \ HANDLER(MuteOnHeadsetUnpluggedInfo, 28 ) \ HANDLER(NumUserRegisteredInfo, 29 ) \ HANDLER(DataDeletionInfo, 30 ) \ HANDLER(ControllerVibrationInfo, 31 ) \ HANDLER(LockScreenInfo, 32 ) \ HANDLER(InternalBatteryLotNumberInfo, 33 ) \ HANDLER(LeftControllerSerialNumberInfo, 34 ) \ HANDLER(RightControllerSerialNumberInfo, 35 ) \ HANDLER(NotificationInfo, 36 ) \ HANDLER(TVInfo, 37 ) \ HANDLER(SleepInfo, 38 ) \ HANDLER(ConnectionInfo, 39 ) \ HANDLER(NetworkErrorInfo, 40 ) \ HANDLER(FileAccessPathInfo, 41 ) \ HANDLER(GameCardCIDInfo, 42 ) \ HANDLER(NANDCIDInfoDeprecated, 43 ) \ HANDLER(MicroSDCIDInfoDeprecated, 44 ) \ HANDLER(NANDSpeedModeInfo, 45 ) \ HANDLER(MicroSDSpeedModeInfo, 46 ) \ HANDLER(GameCardSpeedModeInfo, 47 ) \ HANDLER(UserAccountInternalIDInfo, 48 ) \ HANDLER(NetworkServiceAccountInternalIDInfo, 49 ) \ HANDLER(NintendoAccountInternalIDInfo, 50 ) \ HANDLER(USB3AvailableInfo, 51 ) \ HANDLER(CallStackInfo, 52 ) \ HANDLER(SystemStartupLogInfo, 53 ) \ HANDLER(RegionSettingInfo, 54 ) \ HANDLER(NintendoZoneConnectedInfo, 55 ) \ HANDLER(ForceSleepInfo, 56 ) \ HANDLER(ChargerInfo, 57 ) \ HANDLER(RadioStrengthInfo, 58 ) \ HANDLER(ErrorInfoAuto, 59 ) \ HANDLER(AccessPointInfo, 60 ) \ HANDLER(ErrorInfoDefaults, 61 ) \ HANDLER(SystemPowerStateInfo, 62 ) \ HANDLER(PerformanceInfo, 63 ) \ HANDLER(ThrottlingInfo, 64 ) \ HANDLER(GameCardErrorInfo, 65 ) \ HANDLER(EdidInfo, 66 ) \ HANDLER(ThermalInfo, 67 ) \ HANDLER(CradleFirmwareInfo, 68 ) \ HANDLER(RunningApplicationInfo, 69 ) \ HANDLER(RunningAppletInfo, 70 ) \ HANDLER(FocusedAppletHistoryInfo, 71 ) \ HANDLER(CompositorInfo, 72 ) \ HANDLER(BatteryChargeInfo, 73 ) \ HANDLER(NANDExtendedCsdDeprecated, 74 ) \ HANDLER(NANDPatrolInfo, 75 ) \ HANDLER(NANDErrorInfo, 76 ) \ HANDLER(NANDDriverLog, 77 ) \ HANDLER(SdCardSizeSpec, 78 ) \ HANDLER(SdCardErrorInfo, 79 ) \ HANDLER(SdCardDriverLog , 80 ) \ HANDLER(FsProxyErrorInfo, 81 ) \ HANDLER(SystemAppletSceneInfo, 82 ) \ HANDLER(VideoInfo, 83 ) \ HANDLER(GpuErrorInfo, 84 ) \ HANDLER(PowerClockInfo, 85 ) \ HANDLER(AdspErrorInfo, 86 ) \ HANDLER(NvDispDeviceInfo, 87 ) \ HANDLER(NvDispDcWindowInfo, 88 ) \ HANDLER(NvDispDpModeInfo, 89 ) \ HANDLER(NvDispDpLinkSpec, 90 ) \ HANDLER(NvDispDpLinkStatus, 91 ) \ HANDLER(NvDispDpHdcpInfo, 92 ) \ HANDLER(NvDispDpAuxCecInfo, 93 ) \ HANDLER(NvDispDcInfo, 94 ) \ HANDLER(NvDispDsiInfo, 95 ) \ HANDLER(NvDispErrIDInfo, 96 ) \ HANDLER(SdCardMountInfo, 97 ) \ HANDLER(RetailInteractiveDisplayInfo, 98 ) \ HANDLER(CompositorStateInfo, 99 ) \ HANDLER(CompositorLayerInfo, 100 ) \ HANDLER(CompositorDisplayInfo, 101 ) \ HANDLER(CompositorHWCInfo, 102 ) \ HANDLER(MonitorCapability, 103 ) \ HANDLER(ErrorReportSharePermissionInfo, 104 ) \ HANDLER(MultimediaInfo, 105 ) \ HANDLER(ConnectedControllerInfo, 106 ) \ HANDLER(FsMemoryInfo, 107 ) \ HANDLER(UserClockContextInfo, 108 ) \ HANDLER(NetworkClockContextInfo, 109 ) \ HANDLER(AcpGeneralSettingsInfo, 110 ) \ HANDLER(AcpPlayLogSettingsInfo, 111 ) \ HANDLER(AcpAocSettingsInfo, 112 ) \ HANDLER(AcpBcatSettingsInfo, 113 ) \ HANDLER(AcpStorageSettingsInfo, 114 ) \ HANDLER(AcpRatingSettingsInfo, 115 ) \ HANDLER(MonitorSettings, 116 ) \ HANDLER(RebootlessSystemUpdateVersionInfo, 117 ) \ HANDLER(NifmConnectionTestInfo, 118 ) \ HANDLER(PcieLoggedStateInfo, 119 ) \ HANDLER(NetworkSecurityCertificateInfo, 120 ) \ HANDLER(AcpNeighborDetectionInfo, 121 ) \ HANDLER(GpuCrashInfo, 122 ) \ HANDLER(UsbStateInfo, 123 ) \ HANDLER(NvHostErrInfo, 124 ) \ HANDLER(RunningUlaInfo, 125 ) \ HANDLER(InternalPanelInfo, 126 ) \ HANDLER(ResourceLimitInfo, 127 ) \ HANDLER(ResourceLimitPeakInfoDeprecated, 128 ) \ HANDLER(TouchScreenInfo, 129 ) \ HANDLER(AcpUserAccountSettingsInfo, 130 ) \ HANDLER(AudioDeviceInfo, 131 ) \ HANDLER(AbnormalWakeInfo, 132 ) \ HANDLER(ServiceProfileInfo, 133 ) \ HANDLER(BluetoothAudioInfoDeprecated, 134 ) \ HANDLER(BluetoothPairingCountInfo, 135 ) \ HANDLER(FsProxyErrorInfo2, 136 ) \ HANDLER(BuiltInWirelessOUIInfo, 137 ) \ HANDLER(WirelessAPOUIInfo, 138 ) \ HANDLER(EthernetAdapterOUIInfo, 139 ) \ HANDLER(NANDTypeInfoDeprecated, 140 ) \ HANDLER(MicroSDTypeInfo, 141 ) \ HANDLER(AttachmentFileInfo, 142 ) \ HANDLER(WlanInfo, 143 ) \ HANDLER(HalfAwakeStateInfo, 144 ) \ HANDLER(PctlSettingInfo, 145 ) \ HANDLER(GameCardLogInfo, 146 ) \ HANDLER(WlanIoctlErrorInfo, 147 ) \ HANDLER(SdCardActivationInfo, 148 ) \ HANDLER(GameCardDetailedErrorInfo, 149 ) \ HANDLER(NetworkInfo2, 150 ) \ HANDLER(SystemSettingInfo, 151 ) \ HANDLER(MigrationStateInfo, 152 ) \ HANDLER(WinVdInfo, 153 ) \ HANDLER(PscTransitionStateInfo, 154 ) \ HANDLER(FsProxyErrorInfo3, 155 ) \ HANDLER(BluetoothErrorInfo, 156 ) \ HANDLER(TestNx, 1000) \ HANDLER(NANDTypeInfo, 1001) \ HANDLER(NANDExtendedCsd, 1002) \ HANDLER(BluetoothAudioInfo, 1003) #define AMS_ERPT_FOREACH_FIELD(HANDLER) \ HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(TestU32, 1, Test, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(TestI64, 2, Test, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(TestI32, 3, Test, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(TestString, 4, Test, FieldType_String, FieldFlag_None ) \ HANDLER(TestU8Array, 5, Test, FieldType_U8Array, FieldFlag_None ) \ HANDLER(TestU32Array, 6, Test, FieldType_U32Array, FieldFlag_None ) \ HANDLER(TestU64Array, 7, Test, FieldType_U64Array, FieldFlag_None ) \ HANDLER(TestI32Array, 8, Test, FieldType_I32Array, FieldFlag_None ) \ HANDLER(TestI64Array, 9, Test, FieldType_I64Array, FieldFlag_None ) \ HANDLER(ErrorCode, 10, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ErrorDescription, 11, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(OccurrenceTimestamp, 12, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ReportIdentifier, 13, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ HANDLER(ConnectionStatus, 14, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AccessPointSSID, 15, AccessPointInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AccessPointSecurityType, 16, AccessPointInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RadioStrength, 17, RadioStrengthInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NXMacAddress, 18, NXMacAddressInfo, FieldType_String, FieldFlag_None ) \ HANDLER(IPAddressAcquisitionMethod, 19, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CurrentIPAddress, 20, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SubnetMask, 21, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GatewayIPAddress, 22, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(DNSType, 23, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PriorityDNSIPAddress, 24, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AlternateDNSIPAddress, 25, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(UseProxyFlag, 26, NetworkInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ProxyIPAddress, 27, NetworkInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ProxyPort, 28, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ProxyAutoAuthenticateFlag, 29, NetworkInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(MTU, 30, NetworkInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ConnectAutomaticallyFlag, 31, NetworkInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(UseStealthNetworkFlag, 32, StealthNetworkInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LimitHighCapacityFlag, 33, LimitHighCapacityInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NATType, 34, NATTypeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(WirelessAPMacAddress, 35, WirelessAPMacAddressInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GlobalIPAddress, 36, GlobalIPAddressInfo, FieldType_String, FieldFlag_None ) \ HANDLER(EnableWirelessInterfaceFlag, 37, EnableWirelessInterfaceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(EnableWifiFlag, 38, EnableWifiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(EnableBluetoothFlag, 39, EnableBluetoothInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(EnableNFCFlag, 40, EnableNFCInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NintendoZoneSSIDListVersion, 41, NintendoZoneSSIDListVersionInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LANAdapterMacAddress, 42, LANAdapterMacAddressInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ApplicationID, 43, ApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ApplicationTitle, 44, ApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ApplicationVersion, 45, ApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ApplicationStorageLocation, 46, ApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(DownloadContentType, 47, OccurrenceInfo, FieldType_String, FieldFlag_None ) \ HANDLER(InstallContentType, 48, OccurrenceInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ConsoleStartingUpFlag, 49, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(SystemStartingUpFlag, 50, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ConsoleFirstInitFlag, 51, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(HomeMenuScreenDisplayedFlag, 52, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(DataManagementScreenDisplayedFlag, 53, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ConnectionTestingFlag, 54, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ApplicationRunningFlag, 55, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(DataCorruptionDetectedFlag, 56, OccurrenceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ProductModel, 57, ProductModelInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CurrentLanguage, 58, CurrentLanguageInfo, FieldType_String, FieldFlag_None ) \ HANDLER(UseNetworkTimeProtocolFlag, 59, UseNetworkTimeProtocolInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TimeZone, 60, TimeZoneInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ControllerFirmware, 61, ControllerFirmwareInfo, FieldType_String, FieldFlag_None ) \ HANDLER(VideoOutputSetting, 62, VideoOutputInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NANDFreeSpace, 63, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SDCardFreeSpace, 64, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SerialNumber, 65, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ HANDLER(OsVersion, 66, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ HANDLER(ScreenBrightnessAutoAdjustFlag, 67, ScreenBrightnessInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(HdmiAudioOutputMode, 68, AudioFormatInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SpeakerAudioOutputMode, 69, AudioFormatInfo, FieldType_String, FieldFlag_None ) \ HANDLER(HeadphoneAudioOutputMode, 70, AudioFormatInfo, FieldType_String, FieldFlag_None ) \ HANDLER(MuteOnHeadsetUnpluggedFlag, 71, MuteOnHeadsetUnpluggedInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NumUserRegistered, 72, NumUserRegisteredInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(StorageAutoOrganizeFlag, 73, DataDeletionInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ControllerVibrationVolume, 74, ControllerVibrationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LockScreenFlag, 75, LockScreenInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(InternalBatteryLotNumber, 76, InternalBatteryLotNumberInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LeftControllerSerialNumber, 77, LeftControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RightControllerSerialNumber, 78, RightControllerSerialNumberInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NotifyInGameDownloadCompletionFlag, 79, NotificationInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NotificationSoundFlag, 80, NotificationInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TVResolutionSetting, 81, TVInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RGBRangeSetting, 82, TVInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ReduceScreenBurnFlag, 83, TVInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TVAllowsCecFlag, 84, TVInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(HandheldModeTimeToScreenSleep, 85, SleepInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ConsoleModeTimeToScreenSleep, 86, SleepInfo, FieldType_String, FieldFlag_None ) \ HANDLER(StopAutoSleepDuringContentPlayFlag, 87, SleepInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LastConnectionTestDownloadSpeed, 88, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(LastConnectionTestUploadSpeed, 89, ConnectionInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DEPRECATED_ServerFQDN, 90, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(HTTPRequestContents, 91, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(HTTPRequestResponseContents, 92, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(EdgeServerIPAddress, 93, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CDNContentPath, 94, NetworkErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(FileAccessPath, 95, FileAccessPathInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardCID, 96, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NANDCIDDeprecated, 97, NANDCIDInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ HANDLER(MicroSDCIDDeprecated, 98, MicroSDCIDInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NANDSpeedMode, 99, NANDSpeedModeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(MicroSDSpeedMode, 100, MicroSDSpeedModeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardSpeedMode, 101, GameCardSpeedModeInfo, FieldType_String, FieldFlag_None ) \ HANDLER(UserAccountInternalID, 102, UserAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NetworkServiceAccountInternalID, 103, NetworkServiceAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NintendoAccountInternalID, 104, NintendoAccountInternalIDInfo, FieldType_String, FieldFlag_None ) \ HANDLER(USB3AvailableFlag, 105, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(CallStack, 106, CallStackInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SystemStartupLog, 107, SystemStartupLogInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RegionSetting, 108, RegionSettingInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NintendoZoneConnectedFlag, 109, NintendoZoneConnectedInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ForcedSleepHighTemperatureReading, 110, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ForcedSleepFanSpeedReading, 111, ForceSleepInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ForcedSleepHWInfo, 112, ForceSleepInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AbnormalPowerStateInfo, 113, ChargerInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ScreenBrightnessLevel, 114, ScreenBrightnessInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ProgramId, 115, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AbortFlag, 116, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ReportVisibilityFlag, 117, ErrorInfoAuto, FieldType_Bool, FieldFlag_None ) \ HANDLER(FatalFlag, 118, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(OccurrenceTimestampNet, 119, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ResultBacktrace, 120, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(GeneralRegisterAarch32, 121, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(StackBacktrace32, 122, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(ExceptionInfoAarch32, 123, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(GeneralRegisterAarch64, 124, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(ExceptionInfoAarch64, 125, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(StackBacktrace64, 126, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(RegisterSetFlag32, 127, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(RegisterSetFlag64, 128, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(ProgramMappedAddr32, 129, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ProgramMappedAddr64, 130, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AbortType, 131, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PrivateOsVersion, 132, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ HANDLER(CurrentSystemPowerState, 133, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PreviousSystemPowerState, 134, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DestinationSystemPowerState, 135, SystemPowerStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PscTransitionCurrentState, 136, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PscTransitionPreviousState, 137, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PscInitializedList, 138, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(PscCurrentPmStateList, 139, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PscNextPmStateList, 140, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PerformanceMode, 141, PerformanceInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PerformanceConfiguration, 142, PerformanceInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(Throttled, 143, ThrottlingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ThrottlingDuration, 144, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ThrottlingTimestamp, 145, ThrottlingInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GameCardCrcErrorCount, 146, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardAsicCrcErrorCount, 147, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardRefreshCount, 148, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardReadRetryCount, 149, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(EdidBlock, 150, EdidInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EdidExtensionBlock, 151, EdidInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(CreateProcessFailureFlag, 152, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TemperaturePcb, 153, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(TemperatureSoc, 154, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(CurrentFanDuty, 155, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(LastDvfsThresholdTrippedDeprecated, 156, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(CradlePdcHFwVersion, 157, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CradlePdcAFwVersion, 158, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CradleMcuFwVersion, 159, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CradleDp2HdmiFwVersion, 160, CradleFirmwareInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(RunningApplicationId, 161, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningApplicationTitle, 162, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningApplicationVersion, 163, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningApplicationStorageLocation, 164, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningAppletList, 165, RunningAppletInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(FocusedAppletHistory, 166, FocusedAppletHistoryInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(CompositorState, 167, CompositorStateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CompositorLayerState, 168, CompositorLayerInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CompositorDisplayState, 169, CompositorDisplayInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CompositorHWCState, 170, CompositorHWCInfo, FieldType_String, FieldFlag_None ) \ HANDLER(InputCurrentLimit, 171, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BoostModeCurrentLimitDeprecated, 172, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FastChargeCurrentLimit, 173, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ChargeVoltageLimit, 174, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ChargeConfigurationDeprecated, 175, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(HizModeDeprecated, 176, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ChargeEnabled, 177, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PowerSupplyPathDeprecated, 178, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BatteryTemperature, 179, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BatteryChargePercent, 180, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BatteryChargeVoltage, 181, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(BatteryAge, 182, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PowerRole, 183, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PowerSupplyType, 184, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PowerSupplyVoltage, 185, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PowerSupplyCurrent, 186, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ControllerPowerSupplyAcquiredDeprecated, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(OtgRequestedDeprecated, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NANDPreEolInfoDeprecated, 190, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDDeviceLifeTimeEstTypADeprecated, 191, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDDeviceLifeTimeEstTypBDeprecated, 192, NANDExtendedCsdDeprecated, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDPatrolCount, 193, NANDPatrolInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumActivationFailures, 194, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumActivationErrorCorrections, 195, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumReadWriteFailures, 196, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumReadWriteErrorCorrections, 197, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDErrorLog, 198, NANDDriverLog, FieldType_String, FieldFlag_None ) \ HANDLER(SdCardUserAreaSize, 199, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SdCardProtectedAreaSize, 200, SdCardSizeSpec, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SdCardNumActivationFailures, 201, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SdCardNumActivationErrorCorrections, 202, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SdCardNumReadWriteFailures, 203, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SdCardNumReadWriteErrorCorrections, 204, SdCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SdCardErrorLog, 205, SdCardDriverLog , FieldType_String, FieldFlag_None ) \ HANDLER(EncryptionKey, 206, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EncryptedExceptionInfo, 207, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardTimeoutRetryErrorCount, 208, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsRemountForDataCorruptCount, 209, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsRemountForDataCorruptRetryOutCount, 210, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardInsertionCount, 211, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardRemovalCount, 212, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardAsicInitializeCount, 213, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(TestU16, 214, Test, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(TestU8, 215, Test, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(TestI16, 216, Test, FieldType_NumericI16, FieldFlag_None ) \ HANDLER(TestI8, 217, Test, FieldType_NumericI8, FieldFlag_None ) \ HANDLER(SystemAppletScene, 218, SystemAppletSceneInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(CodecType, 219, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DecodeBuffers, 220, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FrameWidth, 221, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FrameHeight, 222, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ColorPrimaries, 223, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(TransferCharacteristics, 224, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(MatrixCoefficients, 225, VideoInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(DisplayWidth, 226, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(DisplayHeight, 227, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(DARWidth, 228, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(DARHeight, 229, VideoInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ColorFormat, 230, VideoInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(ColorSpace, 231, VideoInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SurfaceLayout, 232, VideoInfo, FieldType_String, FieldFlag_None ) \ HANDLER(BitStream, 233, VideoInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(VideoDecState, 234, VideoInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GpuErrorChannelId, 235, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorAruId, 236, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(GpuErrorType, 237, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorFaultInfo, 238, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorWriteAccess, 239, GpuErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(GpuErrorFaultAddress, 240, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(GpuErrorFaultUnit, 241, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorFaultType, 242, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorHwContextPointer, 243, GpuErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(GpuErrorContextStatus, 244, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaIntr, 245, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaErrorType, 246, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaHeaderShadow, 247, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaHeader, 248, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaGpShadow0, 249, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuErrorPbdmaGpShadow1, 250, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AccessPointChannel, 251, AccessPointInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(ThreadName, 252, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AdspExceptionRegistersDeprecated, 253, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionSpsrDeprecated, 254, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionProgramCounter, 255, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionLinkRegister, 256, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionStackPointer, 257, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionArmModeRegistersDeprecated, 258, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionStackAddressDeprecated, 259, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionStackDumpDeprecated, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionReasonDeprecated, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(OscillatorClockDeprecated, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CpuDvfsTableClocksDeprecated, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(CpuDvfsTableVoltagesDeprecated, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(GpuDvfsTableClocksDeprecated, 265, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(GpuDvfsTableVoltagesDeprecated, 266, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(EmcDvfsTableClocksDeprecated, 267, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(EmcDvfsTableVoltagesDeprecated, 268, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(ModuleClockFrequencies, 269, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(ModuleClockEnableFlagsDeprecated, 270, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModulePowerEnableFlagsDeprecated, 271, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModuleResetAssertFlags, 272, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModuleMinimumVoltageClockRates, 273, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PowerDomainEnableFlagsDeprecated, 274, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(PowerDomainVoltagesDeprecated, 275, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(AccessPointRssi, 276, RadioStrengthInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FuseInfoDeprecated, 277, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(VideoLog, 278, VideoInfo, FieldType_String, FieldFlag_None ) \ HANDLER(GameCardDeviceId, 279, GameCardCIDInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardAsicReinitializeCount, 280, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(GameCardAsicReinitializeFailureCount, 281, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(GameCardAsicReinitializeFailureDetail, 282, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(GameCardRefreshSuccessCount, 283, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(GameCardAwakenCount, 284, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardAwakenFailureCount, 285, GameCardErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(GameCardReadCountFromInsert, 286, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardReadCountFromAwaken, 287, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLastReadErrorPageAddress, 288, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLastReadErrorPageCount, 289, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AppletManagerContextTrace, 290, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(NvDispIsRegistered, 291, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispIsSuspend, 292, NvDispDeviceInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDC0SurfaceNum, 293, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(NvDispDC1SurfaceNum, 294, NvDispDeviceInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(NvDispWindowSrcRectX, 295, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowSrcRectY, 296, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowSrcRectWidth, 297, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowSrcRectHeight, 298, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowDstRectX, 299, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowDstRectY, 300, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowDstRectWidth, 301, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowDstRectHeight, 302, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowIndex, 303, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowBlendOperation, 304, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowAlphaOperation, 305, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowDepth, 306, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowAlpha, 307, NvDispDcWindowInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispWindowHFilter, 308, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispWindowVFilter, 309, NvDispDcWindowInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispWindowOptions, 310, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispWindowSyncPointId, 311, NvDispDcWindowInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPSorPower, 312, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPClkType, 313, NvDispDpModeInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDPEnable, 314, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPState, 315, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPEdid, 316, NvDispDpModeInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NvDispDPEdidSize, 317, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPEdidExtSize, 318, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPFakeMode, 319, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPModeNumber, 320, NvDispDpModeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPPlugInOut, 321, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPAuxIntHandler, 322, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPForceMaxLinkBW, 323, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPIsConnected, 324, NvDispDpModeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkValid, 325, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkMaxBW, 326, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDPLinkMaxLaneCount, 327, NvDispDpLinkSpec, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDPLinkDownSpread, 328, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkSupportEnhancedFraming, 329, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkBpp, 330, NvDispDpLinkSpec, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkScaramberCap, 331, NvDispDpLinkSpec, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkBW, 332, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDPLinkLaneCount, 333, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDPLinkEnhancedFraming, 334, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkScrambleEnable, 335, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkActivePolarity, 336, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkActiveCount, 337, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkTUSize, 338, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkActiveFrac, 339, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkWatermark, 340, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkHBlank, 341, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkVBlank, 342, NvDispDpLinkStatus, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDPLinkOnlyEnhancedFraming, 343, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkOnlyEdpCap, 344, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkSupportFastLT, 345, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkLTDataValid, 346, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkTsp3Support, 347, NvDispDpLinkStatus, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDPLinkAuxInterval, 348, NvDispDpLinkStatus, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispHdcpCreated, 349, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispHdcpUserRequest, 350, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispHdcpPlugged, 351, NvDispDpHdcpInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispHdcpState, 352, NvDispDpHdcpInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispHdcpFailCount, 353, NvDispDpHdcpInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispHdcpHdcp22, 354, NvDispDpHdcpInfo, FieldType_NumericI8, FieldFlag_None ) \ HANDLER(NvDispHdcpMaxRetry, 355, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispHdcpHpd, 356, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispHdcpRepeater, 357, NvDispDpHdcpInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispCecRxBuf, 358, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NvDispCecRxLength, 359, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispCecTxBuf, 360, NvDispDpAuxCecInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NvDispCecTxLength, 361, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispCecTxRet, 362, NvDispDpAuxCecInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispCecState, 363, NvDispDpAuxCecInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispCecTxInfo, 364, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispCecRxInfo, 365, NvDispDpAuxCecInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDCIndex, 366, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCInitialize, 367, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDCClock, 368, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDCFrequency, 369, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCFailed, 370, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDCModeWidth, 371, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispDCModeHeight, 372, NvDispDcInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(NvDispDCModeBpp, 373, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCPanelFrequency, 374, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCWinDirty, 375, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCWinEnable, 376, NvDispDcInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDCVrr, 377, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDCPanelInitialize, 378, NvDispDcInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDsiDataFormat, 379, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiVideoMode, 380, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiRefreshRate, 381, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiLpCmdModeFrequency, 382, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiHsCmdModeFrequency, 383, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiPanelResetTimeout, 384, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiPhyFrequency, 385, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiFrequency, 386, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDsiInstance, 387, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDcDsiHostCtrlEnable, 388, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiInit, 389, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiEnable, 390, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiHsMode, 391, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiVendorId, 392, NvDispDsiInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NvDispDcDsiLcdVendorNum, 393, NvDispDsiInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NvDispDcDsiHsClockControl, 394, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDcDsiEnableHsClockInLpMode, 395, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiTeFrameUpdate, 396, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispDcDsiGangedType, 397, NvDispDsiInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispDcDsiHbpInPktSeq, 398, NvDispDsiInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NvDispErrID, 399, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispErrData0, 400, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvDispErrData1, 401, NvDispErrIDInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SdCardMountStatus, 402, SdCardMountInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SdCardMountUnexpectedResult, 403, SdCardMountInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NANDTotalSize, 404, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SdCardTotalSize, 405, SDCardFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(ElapsedTimeSinceInitialLaunch, 406, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ElapsedTimeSincePowerOn, 407, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ElapsedTimeSinceLastAwake, 408, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(OccurrenceTick, 409, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(RetailInteractiveDisplayFlag, 410, RetailInteractiveDisplayInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(FatFsError, 411, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsExtraError, 412, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsErrorDrive, 413, FsProxyErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsErrorName, 414, FsProxyErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(MonitorManufactureCode, 415, MonitorCapability, FieldType_String, FieldFlag_None ) \ HANDLER(MonitorProductCode, 416, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(MonitorSerialNumber, 417, MonitorCapability, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(MonitorManufactureYear, 418, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PhysicalAddress, 419, MonitorCapability, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(Is4k60Hz, 420, MonitorCapability, FieldType_Bool, FieldFlag_None ) \ HANDLER(Is4k30Hz, 421, MonitorCapability, FieldType_Bool, FieldFlag_None ) \ HANDLER(Is1080P60Hz, 422, MonitorCapability, FieldType_Bool, FieldFlag_None ) \ HANDLER(Is720P60Hz, 423, MonitorCapability, FieldType_Bool, FieldFlag_None ) \ HANDLER(PcmChannelMax, 424, MonitorCapability, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(CrashReportHash, 425, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ErrorReportSharePermission, 426, ErrorReportSharePermissionInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(VideoCodecTypeEnum, 427, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(VideoBitRate, 428, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(VideoFrameRate, 429, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(VideoWidth, 430, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(VideoHeight, 431, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(AudioCodecTypeEnum, 432, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(AudioSampleRate, 433, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(AudioChannelCount, 434, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(AudioBitRate, 435, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaContainerType, 436, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaProfileType, 437, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaLevelType, 438, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaCacheSizeEnum, 439, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaErrorStatusEnum, 440, MultimediaInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(MultimediaErrorLog, 441, MultimediaInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ServerFqdn, 442, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ServerIpAddress, 443, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(TestStringEncrypt, 444, Test, FieldType_String, FieldFlag_Encrypt) \ HANDLER(TestU8ArrayEncrypt, 445, Test, FieldType_U8Array, FieldFlag_Encrypt) \ HANDLER(TestU32ArrayEncrypt, 446, Test, FieldType_U32Array, FieldFlag_Encrypt) \ HANDLER(TestU64ArrayEncrypt, 447, Test, FieldType_U64Array, FieldFlag_Encrypt) \ HANDLER(TestI32ArrayEncrypt, 448, Test, FieldType_I32Array, FieldFlag_Encrypt) \ HANDLER(TestI64ArrayEncrypt, 449, Test, FieldType_I64Array, FieldFlag_Encrypt) \ HANDLER(CipherKey, 450, ErrorInfoAuto, FieldType_U8Array, FieldFlag_None ) \ HANDLER(FileSystemPath, 451, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \ HANDLER(WebMediaPlayerOpenUrl, 452, ErrorInfo, FieldType_String, FieldFlag_Encrypt) \ HANDLER(WebMediaPlayerLastSocketErrors, 453, ErrorInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(UnknownControllerCount, 454, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AttachedControllerCount, 455, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothControllerCount, 456, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(UsbControllerCount, 457, ConnectedControllerInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(ControllerTypeList, 458, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ControllerInterfaceList, 459, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ControllerStyleList, 460, ConnectedControllerInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(FsPooledBufferPeakFreeSize, 461, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferRetriedCount, 462, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferReduceAllocationCount, 463, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsBufferManagerPeakFreeSize, 464, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsBufferManagerRetriedCount, 465, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsExpHeapPeakFreeSize, 466, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsBufferPoolPeakFreeSize, 467, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPatrolReadAllocateBufferSuccessCount, 468, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPatrolReadAllocateBufferFailureCount, 469, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SteadyClockInternalOffset, 470, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SteadyClockCurrentTimePointValue, 471, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(UserClockContextOffset, 472, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(UserClockContextTimeStampValue, 473, UserClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(NetworkClockContextOffset, 474, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(NetworkClockContextTimeStampValue, 475, NetworkClockContextInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemAbortFlag, 476, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ApplicationAbortFlag, 477, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NifmErrorCode, 478, ConnectionStatusInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LcsApplicationId, 479, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LcsContentMetaKeyIdList, 480, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(LcsContentMetaKeyVersionList, 481, ErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(LcsContentMetaKeyTypeList, 482, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(LcsContentMetaKeyInstallTypeList, 483, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(LcsSenderFlag, 484, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LcsApplicationRequestFlag, 485, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LcsHasExFatDriverFlag, 486, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LcsIpAddress, 487, ErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AcpStartupUserAccount, 488, AcpUserAccountSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpAocRegistrationType, 489, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpAttributeFlag, 490, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AcpSupportedLanguageFlag, 491, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AcpParentalControlFlag, 492, AcpGeneralSettingsInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AcpScreenShot, 493, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpVideoCapture, 494, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpDataLossConfirmation, 495, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpPlayLogPolicy, 496, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpPresenceGroupId, 497, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AcpRatingAge, 498, AcpRatingSettingsInfo, FieldType_I8Array, FieldFlag_None ) \ HANDLER(AcpAocBaseId, 499, AcpAocSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AcpSaveDataOwnerId, 500, AcpStorageSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AcpUserAccountSaveDataSize, 501, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpUserAccountSaveDataJournalSize, 502, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpDeviceSaveDataSize, 503, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpDeviceSaveDataJournalSize, 504, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpBcatDeliveryCacheStorageSize, 505, AcpBcatSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpApplicationErrorCodeCategory, 506, AcpGeneralSettingsInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AcpLocalCommunicationId, 507, AcpGeneralSettingsInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(AcpLogoType, 508, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpLogoHandling, 509, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpRuntimeAocInstall, 510, AcpAocSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpCrashReport, 511, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpHdcp, 512, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpSeedForPseudoDeviceId, 513, AcpGeneralSettingsInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AcpBcatPassphrase, 514, AcpBcatSettingsInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AcpUserAccountSaveDataSizeMax, 515, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpUserAccountSaveDataJournalSizeMax, 516, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpDeviceSaveDataSizeMax, 517, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpDeviceSaveDataJournalSizeMax, 518, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpTemporaryStorageSize, 519, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpCacheStorageSize, 520, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpCacheStorageJournalSize, 521, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpCacheStorageDataAndJournalSizeMax, 522, AcpStorageSettingsInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpCacheStorageIndexMax, 523, AcpStorageSettingsInfo, FieldType_NumericI16, FieldFlag_None ) \ HANDLER(AcpPlayLogQueryableApplicationId, 524, AcpPlayLogSettingsInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(AcpPlayLogQueryCapability, 525, AcpPlayLogSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AcpRepairFlag, 526, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(RunningApplicationPatchStorageLocation, 527, RunningApplicationInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningApplicationVersionNumber, 528, RunningApplicationInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsRecoveredByInvalidateCacheCount, 529, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsSaveDataIndexCount, 530, FsProxyErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsBufferManagerPeakTotalAllocatableSize, 531, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(MonitorCurrentWidth, 532, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(MonitorCurrentHeight, 533, MonitorSettings, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(MonitorCurrentRefreshRate, 534, MonitorSettings, FieldType_String, FieldFlag_None ) \ HANDLER(RebootlessSystemUpdateVersion, 535, RebootlessSystemUpdateVersionInfo, FieldType_String, FieldFlag_None ) \ HANDLER(EncryptedExceptionInfo1, 536, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EncryptedExceptionInfo2, 537, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EncryptedExceptionInfo3, 538, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EncryptedDyingMessage, 539, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(DramIdDeprecated, 540, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NifmConnectionTestRedirectUrl, 541, NifmConnectionTestInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AcpRequiredNetworkServiceLicenseOnLaunchFlag, 542, AcpUserAccountSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PciePort0Flags, 543, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort0Speed, 544, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PciePort0ResetTimeInUs, 545, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort0IrqCount, 546, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort0Statistics, 547, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PciePort1Flags, 548, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort1Speed, 549, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PciePort1ResetTimeInUs, 550, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort1IrqCount, 551, PcieLoggedStateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PciePort1Statistics, 552, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PcieFunction0VendorId, 553, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(PcieFunction0DeviceId, 554, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(PcieFunction0PmState, 555, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PcieFunction0IsAcquired, 556, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PcieFunction1VendorId, 557, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(PcieFunction1DeviceId, 558, PcieLoggedStateInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(PcieFunction1PmState, 559, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PcieFunction1IsAcquired, 560, PcieLoggedStateInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PcieGlobalRootComplexStatistics, 561, PcieLoggedStateInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(PciePllResistorCalibrationValue, 562, PcieLoggedStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(CertificateRequestedHostName, 563, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CertificateCommonName, 564, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CertificateSANCount, 565, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CertificateSANs, 566, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(FsBufferPoolMaxAllocateSize, 567, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(CertificateIssuerName, 568, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ApplicationAliveTime, 569, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ApplicationInFocusTime, 570, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ApplicationOutOfFocusTime, 571, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(ApplicationBackgroundFocusTime, 572, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(AcpUserAccountSwitchLock, 573, AcpUserAccountSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(USB3HostAvailableFlag, 574, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(USB3DeviceAvailableFlag, 575, USB3AvailableInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(AcpNeighborDetectionClientConfigurationSendDataId, 576, AcpNeighborDetectionInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AcpNeighborDetectionClientConfigurationReceivableDataIds, 577, AcpNeighborDetectionInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(AcpStartupUserAccountOptionFlag, 578, AcpUserAccountSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(ServerErrorCode, 579, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AppletManagerMetaLogTrace, 580, ErrorInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(ServerCertificateSerialNumber, 581, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ServerCertificatePublicKeyAlgorithm, 582, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ServerCertificateSignatureAlgorithm, 583, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(ServerCertificateNotBefore, 584, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(ServerCertificateNotAfter, 585, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(CertificateAlgorithmInfoBits, 586, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(TlsConnectionPeerIpAddress, 587, NetworkSecurityCertificateInfo, FieldType_String, FieldFlag_None ) \ HANDLER(TlsConnectionLastHandshakeState, 588, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(TlsConnectionInfoBits, 589, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SslStateBits, 590, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SslProcessInfoBits, 591, NetworkSecurityCertificateInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SslProcessHeapSize, 592, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(SslBaseErrorCode, 593, NetworkSecurityCertificateInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(GpuCrashDumpSize, 594, GpuCrashInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GpuCrashDump, 595, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(RunningApplicationProgramIndex, 596, RunningApplicationInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(UsbTopology, 597, UsbStateInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(AkamaiReferenceId, 598, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NvHostErrID, 599, NvHostErrInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NvHostErrDataArrayU32, 600, NvHostErrInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(HasSyslogFlag, 601, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(AcpRuntimeParameterDelivery, 602, AcpGeneralSettingsInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PlatformRegion, 603, RegionSettingInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningUlaApplicationId, 604, RunningUlaInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningUlaAppletId, 605, RunningUlaInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(RunningUlaVersion, 606, RunningUlaInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(RunningUlaApplicationStorageLocation, 607, RunningUlaInfo, FieldType_String, FieldFlag_None ) \ HANDLER(RunningUlaPatchStorageLocation, 608, RunningUlaInfo, FieldType_String, FieldFlag_None ) \ HANDLER(NANDTotalSizeOfSystem, 609, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(NANDFreeSpaceOfSystem, 610, NANDFreeSpaceInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AccessPointSSIDAsHex, 611, AccessPointInfo, FieldType_String, FieldFlag_None ) \ HANDLER(PanelVendorId, 612, InternalPanelInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PanelRevisionId, 613, InternalPanelInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PanelModelId, 614, InternalPanelInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(ErrorContext, 615, ErrorInfoAuto, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ErrorContextSize, 616, ErrorInfoAuto, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(ErrorContextTotalSize, 617, ErrorInfoAuto, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(SystemPhysicalMemoryLimit, 618, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemThreadCountLimit, 619, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemEventCountLimit, 620, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemTransferMemoryCountLimit, 621, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemSessionCountLimit, 622, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemPhysicalMemoryPeak, 623, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemThreadCountPeak, 624, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemEventCountPeak, 625, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemTransferMemoryCountPeak, 626, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(SystemSessionCountPeak, 627, ResourceLimitInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GpuCrashHash, 628, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(TouchScreenPanelGpioValue, 629, TouchScreenInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BrowserCertificateHostName, 630, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(BrowserCertificateCommonName, 631, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(BrowserCertificateOrganizationalUnitName, 632, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(FsPooledBufferFailedIdealAllocationCountOnAsyncAccess, 633, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(AudioOutputTarget, 634, AudioDeviceInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AudioOutputChannelCount, 635, AudioDeviceInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AppletTotalActiveTime, 636, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(WakeCount, 637, AbnormalWakeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(PredominantWakeReason, 638, AbnormalWakeInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(EdidExtensionBlock2, 639, EdidInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(EdidExtensionBlock3, 640, EdidInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(LumenRequestId, 641, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(LlnwLlid, 642, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(SupportingLimitedApplicationLicenses, 643, RunningApplicationInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(RuntimeLimitedApplicationLicenseUpgrade, 644, RunningApplicationInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(ServiceProfileRevisionKey, 645, ServiceProfileInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(BluetoothAudioConnectionCountDeprecated, 646, BluetoothAudioInfoDeprecated, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothHidPairingInfoCountDeprecated, 647, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothAudioPairingInfoCountDeprecated, 648, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothLePairingInfoCountDeprecated, 649, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatFsBisSystemFilePeakOpenCount, 650, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisSystemDirectoryPeakOpenCount, 651, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisUserFilePeakOpenCount, 652, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisUserDirectoryPeakOpenCount, 653, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsSdCardFilePeakOpenCount, 654, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsSdCardDirectoryPeakOpenCount, 655, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(SslAlertInfo, 656, NetworkSecurityCertificateInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(SslVersionInfo, 657, NetworkSecurityCertificateInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(FatFsBisSystemUniqueFileEntryPeakOpenCount, 658, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisSystemUniqueDirectoryEntryPeakOpenCount, 659, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisUserUniqueFileEntryPeakOpenCount, 660, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsBisUserUniqueDirectoryEntryPeakOpenCount, 661, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsSdCardUniqueFileEntryPeakOpenCount, 662, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(FatFsSdCardUniqueDirectoryEntryPeakOpenCount, 663, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(ServerErrorIsRetryable, 664, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(FsDeepRetryStartCount, 665, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsUnrecoverableByGameCardAccessFailedCount, 666, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(BuiltInWirelessOUI, 667, BuiltInWirelessOUIInfo, FieldType_String, FieldFlag_None ) \ HANDLER(WirelessAPOUI, 668, WirelessAPOUIInfo, FieldType_String, FieldFlag_None ) \ HANDLER(EthernetAdapterOUI, 669, EthernetAdapterOUIInfo, FieldType_String, FieldFlag_None ) \ HANDLER(FatFsBisSystemFatSafeControlResult, 670, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatFsBisSystemFatErrorNumber, 671, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsBisSystemFatSafeErrorNumber, 672, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsBisUserFatSafeControlResult, 673, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatFsBisUserFatErrorNumber, 674, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FatFsBisUserFatSafeErrorNumber, 675, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(GpuCrashDump2, 676, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(NANDTypeDeprecated, 677, NANDTypeInfoDeprecated, FieldType_U8Array, FieldFlag_None ) \ HANDLER(MicroSDType, 678, MicroSDTypeInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardLastDeactivateReasonResult, 679, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLastDeactivateReason, 680, GameCardErrorInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(InvalidErrorCode, 681, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(AppletId, 682, ApplicationInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(PrevReportIdentifier, 683, ErrorInfoAuto, FieldType_String, FieldFlag_None ) \ HANDLER(SyslogStartupTimeBase, 684, ErrorInfoAuto, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(NxdmpIsAttached, 685, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ScreenshotIsAttached, 686, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(SyslogIsAttached, 687, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(SaveSyslogResult, 688, AttachmentFileInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(EncryptionKeyGeneration, 689, ErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FsBufferManagerNonBlockingRetriedCount, 690, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FsPooledBufferNonBlockingRetriedCount, 691, FsMemoryInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(LastConnectionTestDownloadSpeed64, 692, ConnectionInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(LastConnectionTestUploadSpeed64, 693, ConnectionInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(EncryptionKeyV1, 694, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GpuCrashDumpAttachmentId, 695, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GpuCrashDumpIsAttached, 696, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(CallerIdentifier, 697, ErrorInfo, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(WlanMainState, 698, WlanInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(WlanSubState, 699, WlanInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(AdspSyslogIsAttached, 702, AttachmentFileInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(LastHalfAwakeTime, 703, HalfAwakeStateInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(LastHalfAwakeTimeAfterBackgroundTaskDone, 704, HalfAwakeStateInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(LastHalfAwakeTimeAfterStateUnlocked, 705, HalfAwakeStateInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(LastHalfAwakePowerStateMessage, 706, HalfAwakeStateInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FastlyRequestId, 707, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(CloudflareCfRay, 708, ErrorInfo, FieldType_String, FieldFlag_None ) \ HANDLER(WlanCommandEventHistory, 709, WlanInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(FsSaveDataAttributeCheckFailureCount, 710, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PctlIsRestrictionEnabled, 711, PctlSettingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PctlIsPairingActive, 712, PctlSettingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PctlSafetyLevel, 713, PctlSettingInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PctlRatingAge, 714, PctlSettingInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PctlRatingOrganization, 715, PctlSettingInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(PctlIsSnsPostRestricted, 716, PctlSettingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PctlIsFreeCommunicationRestrictedByDefault, 717, PctlSettingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PctlIsStereoVisionRestricted, 718, PctlSettingInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PctlRestrictedFreeCommunicationApplicationIdList, 719, PctlSettingInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(PctlExemptApplicationIdList, 720, PctlSettingInfo, FieldType_U64Array, FieldFlag_None ) \ HANDLER(GameCardLogEncryptionKeyIndex, 721, GameCardLogInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLogEncryptedKey, 722, GameCardLogInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardAsicHandlerLogLength, 723, GameCardLogInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardWorkerLogLength, 724, GameCardLogInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardAsicHandlerLogTimeStamp, 725, GameCardLogInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GameCardWorkerLogTimeStamp, 726, GameCardLogInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GameCardEncryptedAsicHandlerLog, 727, GameCardLogInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardEncryptedWorkerLog, 728, GameCardLogInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(WlanIoctlErrno, 729, ErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(FsSaveDataCertificateVerificationFailureCount, 730, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(SdCardActivationMilliSeconds, 731, SdCardActivationInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardLastAwakenFailureResult, 732, GameCardDetailedErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardInsertedTimestamp, 733, GameCardDetailedErrorInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GameCardPreviousInsertedTimestamp, 734, GameCardDetailedErrorInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(WlanChipResetTriggered, 735, WlanInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(NANDNumReadFailures, 736, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumReadRecoveries, 737, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumWriteFailures, 738, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDNumWriteRecoveries, 739, NANDErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(WlanCommandEventHistoryV2, 740, WlanInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(WlanChipResetReason, 741, ErrorInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(WlanAssertDumpData, 742, ErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ApplicationErrorFlag, 743, ApplicationInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(FsOrphanedSaveDataTotalSize, 744, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FsOrphanedSaveDataCount, 745, FsProxyErrorInfo2, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(MigrationType, 746, MigrationStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(MigrationResumeCount, 747, MigrationStateInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(MigrationStateData, 748, MigrationStateInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(WinVdPcEnvironment, 749, WinVdInfo, FieldType_String, FieldFlag_None ) \ HANDLER(PscBlockingPmModuleList, 750, PscTransitionStateInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(CrashReportFlag, 751, ErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TouchScreenPanelVendor, 752, TouchScreenInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(GameCardReportMiscFlags, 753, GameCardDetailedErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(GameCardRemovedTimestamp, 754, GameCardDetailedErrorInfo, FieldType_NumericI64, FieldFlag_None ) \ HANDLER(GameCardPackageId, 755, GameCardDetailedErrorInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(GameCardInserted, 756, GameCardDetailedErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(ErptStartupCount, 757, ErrorInfoAuto, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardTotalNumberOfLogicalClusters, 758, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardBytePerLogicalSector, 759, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardLogicalSectorPerCluster, 760, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardFormatType, 761, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatSdCardNumberOfFat, 762, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(FatSdCardSectorPerFat, 763, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardNumberOfReservedSectors, 764, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardFirstDataSector, 765, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(FatSdCardTotalNumberOfSectors, 766, FsProxyErrorInfo3, FieldType_NumericU64, FieldFlag_None ) \ HANDLER(FatSdCardCheckFlags, 767, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(BluetoothHaltedReason, 768, ErrorInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothHaltedCurrentPmState, 769, ErrorInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothHaltedRequestedPmState, 770, ErrorInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothHaltedBtpApiFailedId, 771, ErrorInfo, FieldType_NumericU16, FieldFlag_None ) \ HANDLER(RomFsRecoveredAesFailedCount, 772, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DriverRecoveredAesFailedCount, 773, FsProxyErrorInfo3, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(BluetoothIsHalted, 774, BluetoothErrorInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \ HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(HizMode, 1003, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(PowerSupplyPath, 1004, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ControllerPowerSupplyAcquired, 1005, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(OtgRequested, 1006, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \ HANDLER(AdspExceptionRegisters, 1007, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionSpsr, 1008, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionArmModeRegisters, 1009, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionStackAddress, 1010, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(AdspExceptionStackDump, 1011, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(AdspExceptionReason, 1012, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(CpuDvfsTableClocks, 1013, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(CpuDvfsTableVoltages, 1014, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(GpuDvfsTableClocks, 1015, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(GpuDvfsTableVoltages, 1016, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(EmcDvfsTableClocks, 1017, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(EmcDvfsTableVoltages, 1018, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(PowerDomainEnableFlags, 1019, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(PowerDomainVoltages, 1020, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \ HANDLER(FuseInfo, 1021, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \ HANDLER(NANDType, 1022, NANDTypeInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(BluetoothHidPairingInfoCount, 1023, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothAudioPairingInfoCount, 1024, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(BluetoothLePairingInfoCount, 1025, BluetoothPairingCountInfo, FieldType_NumericU8, FieldFlag_None ) \ HANDLER(NANDPreEolInfo, 1026, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDDeviceLifeTimeEstTypA, 1027, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(NANDDeviceLifeTimeEstTypB, 1028, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(OscillatorClock, 1029, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(DramId, 1030, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \ HANDLER(LastDvfsThresholdTripped, 1031, ThermalInfo, FieldType_NumericI32, FieldFlag_None ) \ HANDLER(ModuleClockEnableFlags, 1032, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(ModulePowerEnableFlags, 1033, PowerClockInfo, FieldType_U8Array, FieldFlag_None ) \ HANDLER(BluetoothAudioConnectionCount, 1034, BluetoothAudioInfo, FieldType_NumericU8, FieldFlag_None ) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/erpt_multiple_category_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/erpt/erpt_types.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::erpt { constexpr inline u32 CategoriesPerMultipleCategoryContext = 0x10; constexpr inline u32 FieldsPerMultipleCategoryContext = CategoriesPerMultipleCategoryContext * 4; struct MultipleCategoryContextEntry : public sf::LargeData, public sf::PrefersMapAliasTransferMode { u32 version; u32 category_count; CategoryId categories[CategoriesPerMultipleCategoryContext]; u32 field_counts[CategoriesPerMultipleCategoryContext]; u32 array_buf_counts[CategoriesPerMultipleCategoryContext]; FieldEntry fields[FieldsPerMultipleCategoryContext]; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/erpt_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/time/time_posix_time.hpp> #include <stratosphere/erpt/erpt_ids.autogen.hpp> namespace ams::erpt { #define GENERATE_ENUM(NAME, ID, ...) NAME = ID, enum FieldType { AMS_ERPT_FOREACH_FIELD_TYPE(GENERATE_ENUM) FieldType_Count, }; #undef GENERATE_ENUM #define GENERATE_ENUM(NAME, ID, ...) CategoryId_##NAME = ID, enum CategoryId { AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM) }; #undef GENERATE_ENUM #define GENERATE_ENUM(NAME, ID, ...) FieldId_##NAME = ID, enum FieldId { AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM) }; #undef GENERATE_ENUM constexpr inline u32 ArrayBufferSizeDefault = 0x100; constexpr inline u32 ArrayBufferSizeMax = 96_KB; constexpr inline u32 ArrayFieldSizeMax = 16_KB - 1; enum ReportType { ReportType_Start = 0, ReportType_Visible = ReportType_Start, ReportType_Invisible = 1, ReportType_End = 2, ReportType_Count = ReportType_End, ReportType_Any = ReportType_Count, }; constexpr inline u32 ReportCountMax = 50; constexpr inline u32 AttachmentsPerReportMax = 5; constexpr inline u32 AttachmentCountMax = ReportCountMax * AttachmentsPerReportMax; constexpr inline u32 ReportMetaDataSize = 0x20; struct ReportMetaData { u8 user_data[ReportMetaDataSize]; }; constexpr inline u32 ReportIdSize = 20; struct ReportId { union { u8 id[ReportIdSize]; util::Uuid uuid; #pragma pack(push, 1) struct { u32 time_low; u16 time_mid; u16 time_high_and_version; u8 clock_high; u8 clock_low; u64 node; } uuid_data; #pragma pack(pop) }; }; static_assert(sizeof(ReportId) == ReportIdSize); inline bool operator==(const ReportId &lhs, const ReportId &rhs) { return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0; } inline bool operator!=(const ReportId &lhs, const ReportId &rhs) { return !(lhs == rhs); } struct ReportFlag { using Transmitted = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<0>; using HasAttachment = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>::Flag<1>; }; using ReportFlagSet = util::BitFlagSet<BITSIZEOF(u32), ReportFlag>; static_assert(util::is_pod<ReportFlagSet>::value); static_assert(sizeof(ReportFlagSet) == sizeof(u32)); struct CreateReportOptionFlag { using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>; }; using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>; static_assert(util::is_pod<CreateReportOptionFlagSet>::value); static_assert(sizeof(CreateReportOptionFlagSet) == sizeof(u32)); struct ReportInfo { ReportType type; ReportId id; ReportMetaData meta_data; ReportFlagSet flags; time::PosixTime timestamp_user; time::PosixTime timestamp_network; s64 report_size; u64 reserved[3]; }; struct ReportList { u32 report_count; ReportInfo reports[ReportCountMax]; }; constexpr inline u32 AttachmentIdSize = 20; struct AttachmentId { union { u8 id[AttachmentIdSize]; util::Uuid uuid; }; }; static_assert(sizeof(AttachmentId) == AttachmentIdSize); inline bool operator==(const AttachmentId &lhs, const AttachmentId &rhs) { return std::memcmp(lhs.id, rhs.id, sizeof(lhs.uuid)) == 0; } inline bool operator!=(const AttachmentId &lhs, const AttachmentId &rhs) { return !(lhs == rhs); } struct AttachmentFlag { using HasOwner = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>::Flag<1>; }; using AttachmentFlagSet = util::BitFlagSet<BITSIZEOF(u32), AttachmentFlag>; static_assert(util::is_pod<AttachmentFlagSet>::value); static_assert(sizeof(AttachmentFlagSet) == sizeof(u32)); constexpr inline u32 AttachmentNameSizeMax = 0x20; struct AttachmentInfo { ReportId owner_report_id; AttachmentId attachment_id; AttachmentFlagSet flags; s64 attachment_size; char attachment_name[AttachmentNameSizeMax]; }; struct AttachmentList { u32 attachment_count; AttachmentInfo attachments[AttachmentsPerReportMax]; }; constexpr inline u32 AttachmentSizeMax = 512_KB; struct FieldEntry { FieldId id; FieldType type; union { u64 value_u64; u32 value_u32; u16 value_u16; u8 value_u8; s64 value_i64; s32 value_i32; s16 value_i16; s8 value_i8; bool value_bool; struct { u32 start_idx; u32 size; } value_array; }; }; struct CategoryEntry { CategoryId category; u32 field_count; u32 array_buffer_count; }; constexpr inline u32 FieldsPerContext = 20; struct ContextEntry { u32 version; u32 field_count; CategoryId category; FieldEntry fields[FieldsPerContext]; u8 *array_buffer; u32 array_free_count; u32 array_buffer_size; }; struct StorageUsageStatistics { util::Uuid journal_uuid; u32 used_storage_size; s64 max_report_size; u32 report_count[ReportType_Count]; u32 transmitted_count[ReportType_Count]; u32 untransmitted_count[ReportType_Count]; }; /* https://github.com/msgpack/msgpack/blob/master/spec.md#overview */ enum class ValueTypeTag { FixMap = 0x80, FixArray = 0x90, FixStr = 0xA0, False = 0xC2, True = 0xC3, Bin8 = 0xC4, Bin16 = 0xC5, U8 = 0xCC, U16 = 0xCD, U32 = 0xCE, U64 = 0xCF, I8 = 0xD0, I16 = 0xD1, I32 = 0xD2, I64 = 0xD3, Str8 = 0xD9, Str16 = 0xDA, Array16 = 0xDC, Map16 = 0xDE, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_attachment.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/erpt/erpt_types.hpp> #define AMS_ERPT_I_ATTACHMENT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Open, (const erpt::AttachmentId &attachment_id), (attachment_id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Read, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer), (out_count, out_buffer)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetFlags, (erpt::AttachmentFlagSet flags), (flags)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetFlags, (ams::sf::Out<erpt::AttachmentFlagSet> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, Close, (), ()) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetSize, (ams::sf::Out<s64> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IAttachment, AMS_ERPT_I_ATTACHMENT_INTERFACE_INFO, 0x10FC4A69) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/erpt/erpt_types.hpp> #include <stratosphere/erpt/erpt_multiple_category_context.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp> #define AMS_ERPT_I_CONTEXT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SubmitContext, (const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer), (ctx_buffer, str_buffer)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreateReportV0, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer), (report_type, ctx_buffer, str_buffer, meta_buffer)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetInitialLaunchSettingsCompletionTime, (const time::SteadyClockTimePoint &time_point), (time_point), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 3, Result, ClearInitialLaunchSettingsCompletionTime, (), (), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, UpdatePowerOnTime, (), (), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, UpdateAwakeTime, (), (), hos::Version_3_0_0, hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, CreateReportWithAdditionalContext, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags, const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer), (report_type, ctx_buffer, str_buffer, meta_buffer, result, flags, category_entries, field_entries, array_buffer), hos::Version_21_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleCategoryContext, (const erpt::MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer), (ctx_entry, str_buffer), hos::Version_5_0_0, hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleContext, (const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer), (category_entries, field_entries, array_buffer), hos::Version_21_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, UpdateApplicationLaunchTime, (), (), hos::Version_6_0_0, hos::Version_20_5_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, RegisterRunningApplicationInfo, (ncm::ApplicationId app_id, ncm::ProgramId program_id), (app_id, program_id), hos::Version_21_0_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, ClearApplicationLaunchTime, (), (), hos::Version_6_0_0, hos::Version_20_5_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, UnregisterRunningApplicationInfo, (), (), hos::Version_21_0_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out<erpt::AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), (out, attachment_name, attachment_data), hos::Version_8_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer), hos::Version_8_0_0, hos::Version_10_2_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated2, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer, result), hos::Version_11_0_0, hos::Version_16_1_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachments, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer, result, flags), hos::Version_17_0_0) \ AMS_SF_METHOD_INFO(C, H, 11, Result, CreateReportV1, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result), (report_type, ctx_buffer, str_buffer, meta_buffer, result), hos::Version_11_0_0) \ AMS_SF_METHOD_INFO(C, H, 12, Result, CreateReport, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags), (report_type, ctx_buffer, str_buffer, meta_buffer, result, flags), hos::Version_17_0_0) \ AMS_SF_METHOD_INFO(C, H, 13, Result, SubmitAttachmentWithLz4Compression, (ams::sf::Out<erpt::AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), (out, attachment_name, attachment_data), hos::Version_20_0_0) \ AMS_SF_METHOD_INFO(C, H, 14, Result, CreateReportWithSpecifiedReprotId, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags, const erpt::ReportId &report_id), (report_type, ctx_buffer, str_buffer, meta_buffer, attachment_ids_buffer, result, flags, report_id), hos::Version_20_0_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, RegisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 21, Result, UnregisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 22, Result, UpdateAppletSuspendedDuration, (ncm::ProgramId program_id, TimeSpanType duration), (program_id, duration), hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 30, Result, InvalidateForcedShutdownDetection, (), (), hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 40, Result, WaitForReportCreation, (), (), hos::Version_21_0_0) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO, 0xDD41DD03) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/erpt/erpt_types.hpp> #define AMS_ERPT_I_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetReportList, (const ams::sf::OutBuffer &out_list, erpt::ReportType type_filter), (out_list, type_filter)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetEvent, (ams::sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, CleanupReports, (), (), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 3, Result, DeleteReport, (const erpt::ReportId &report_id), (report_id), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetStorageUsageStatistics, (ams::sf::Out<erpt::StorageUsageStatistics> out), (out), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetAttachmentListDeprecated, (const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_buf, report_id), hos::Version_8_0_0, hos::Version_19_0_1) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetAttachmentList, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const erpt::ReportId &report_id), (out_count, out_buf, report_id), hos::Version_20_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, GetReportSizeMax, (ams::sf::Out<u32> out), (out), hos::Version_20_0_0) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IManager, AMS_ERPT_I_MANAGER_INTERFACE_INFO, 0x5CFCC43F) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_report.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/erpt/erpt_types.hpp> #define AMS_ERPT_I_REPORT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Open, (const erpt::ReportId &report_id), (report_id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Read, (ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer), (out_count, out_buffer)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetFlags, (erpt::ReportFlagSet flags), (flags)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetFlags, (ams::sf::Out<erpt::ReportFlagSet> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, Close, (), ()) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetSize, (ams::sf::Out<s64> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IReport, AMS_ERPT_I_REPORT_INTERFACE_INFO, 0xE4CD5A61) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/sf/erpt_sf_i_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/erpt/erpt_types.hpp> #include <stratosphere/erpt/sf/erpt_sf_i_report.hpp> #include <stratosphere/erpt/sf/erpt_sf_i_manager.hpp> #include <stratosphere/erpt/sf/erpt_sf_i_attachment.hpp> #define AMS_ERPT_I_SESSION_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenReport, (ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IReport>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, OpenManager, (ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IManager>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, OpenAttachment, (ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IAttachment>> out), (out), hos::Version_8_0_0) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, ISession, AMS_ERPT_I_SESSION_INTERFACE_INFO, 0x00395188) ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/srv/erpt_srv_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::erpt::srv { Result Initialize(u8 *mem, size_t mem_size); Result InitializeAndStartService(); Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len); Result SetProductModel(const char *model, u32 model_len); Result SetRegionSetting(const char *region, u32 region_len); /* Atmosphere extension. */ Result SetRedirectNewReportsToSdCard(bool redirect); Result SetEnabledAutomaticReportCleanup(bool redirect); void Wait(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt/srv/erpt_srv_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/erpt/erpt_ids.autogen.hpp> namespace ams::erpt::srv { constexpr inline const char ReportOnSdStoragePath[] = "ersd"; constexpr inline const char ReportOnSdStorageRootDirectoryPath[] = "ersd:/"; constexpr inline const char ReportStoragePath[] = "save"; constexpr inline const char JournalFileName[] = "save:/journal"; constexpr inline const char ForcedShutdownContextFileName[] = "save:/forced-shutdown"; constexpr size_t ReportFileNameLength = 64; constexpr size_t AttachmentFileNameLength = 64; constexpr size_t MaxFieldStringSize = 64; struct ReportFileName { char name[ReportFileNameLength]; }; struct AttachmentFileName { char name[AttachmentFileNameLength]; }; enum FieldFlag : u8 { FieldFlag_None = 0, FieldFlag_Encrypt = 1, }; #define STRINGIZE_HANDLER(NAME, ...) #NAME, constexpr inline const char * const FieldString[] = { AMS_ERPT_FOREACH_FIELD(STRINGIZE_HANDLER) }; constexpr inline const char * const CategoryString[] = { AMS_ERPT_FOREACH_CATEGORY(STRINGIZE_HANDLER) }; constexpr inline const char * const TypeString[] = { AMS_ERPT_FOREACH_FIELD_TYPE(STRINGIZE_HANDLER) }; #undef STRINGIZE_HANDLER #define GET_FIELD_CATEGORY(FIELD, ID, CATEGORY, TYPE, FLAG) CategoryId_##CATEGORY, constexpr inline const CategoryId FieldIndexToCategoryMap[] = { AMS_ERPT_FOREACH_FIELD(GET_FIELD_CATEGORY) }; #undef GET_FIELD_CATEGORY #define GET_FIELD_TYPE(FIELD, ID, CATEGORY, TYPE, FLAG) TYPE, constexpr inline const FieldType FieldIndexToTypeMap[] = { AMS_ERPT_FOREACH_FIELD(GET_FIELD_TYPE) }; #undef GET_FIELD_TYPE #define GET_FIELD_FLAG(FIELD, ID, CATEGORY, TYPE, FLAG) FLAG, constexpr inline const FieldFlag FieldIndexToFlagMap[] = { AMS_ERPT_FOREACH_FIELD(GET_FIELD_FLAG) }; #undef GET_FIELD_FLAG #define GET_FIELD_ID(FIELD, ...) FieldId_##FIELD, constexpr inline const FieldId FieldIndexToFieldIdMap[] = { AMS_ERPT_FOREACH_FIELD(GET_FIELD_ID) }; #undef GET_FIELD_ID #define GET_CATEGORY_ID(CATEGORY, ...) CategoryId_##CATEGORY, constexpr inline const CategoryId CategoryIndexToCategoryIdMap[] = { AMS_ERPT_FOREACH_CATEGORY(GET_CATEGORY_ID) }; #undef GET_CATEGORY_ID constexpr util::optional<size_t> FindFieldIndex(FieldId id) { if (std::is_constant_evaluated()) { for (size_t i = 0; i < util::size(FieldIndexToFieldIdMap); ++i) { if (FieldIndexToFieldIdMap[i] == id) { return i; } } return util::nullopt; } else { if (const auto it = std::lower_bound(std::begin(FieldIndexToFieldIdMap), std::end(FieldIndexToFieldIdMap), id); it != std::end(FieldIndexToFieldIdMap) && *it == id) { return std::distance(FieldIndexToFieldIdMap, it); } else { return util::nullopt; } } } constexpr util::optional<size_t> FindCategoryIndex(CategoryId id) { if (std::is_constant_evaluated()) { for (size_t i = 0; i < util::size(CategoryIndexToCategoryIdMap); ++i) { if (CategoryIndexToCategoryIdMap[i] == id) { return i; } } return util::nullopt; } else { if (const auto it = std::lower_bound(std::begin(CategoryIndexToCategoryIdMap), std::end(CategoryIndexToCategoryIdMap), id); it != std::end(CategoryIndexToCategoryIdMap) && *it == id) { return std::distance(CategoryIndexToCategoryIdMap, it); } else { return util::nullopt; } } } constexpr inline bool IsValidCategory(CategoryId id) { return FindCategoryIndex(id).has_value(); } constexpr inline CategoryId ConvertFieldToCategory(FieldId id) { const auto index = FindFieldIndex(id); AMS_ASSERT(index.has_value()); return FieldIndexToCategoryMap[index.value()]; } constexpr inline FieldType ConvertFieldToType(FieldId id) { const auto index = FindFieldIndex(id); AMS_ASSERT(index.has_value()); return FieldIndexToTypeMap[index.value()]; } constexpr inline FieldFlag ConvertFieldToFlag(FieldId id) { const auto index = FindFieldIndex(id); AMS_ASSERT(index.has_value()); return FieldIndexToFlagMap[index.value()]; } constexpr inline ReportFlagSet MakeNoReportFlags() { return util::MakeBitFlagSet<32, ReportFlag>(); } constexpr inline CreateReportOptionFlagSet MakeNoCreateReportOptionFlags() { return util::MakeBitFlagSet<32, CreateReportOptionFlag>(); } constexpr inline AttachmentFlagSet MakeNoAttachmentFlags() { return util::MakeBitFlagSet<32, AttachmentFlag>(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/erpt.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/erpt/erpt_ids.autogen.hpp> #include <stratosphere/erpt/erpt_types.hpp> #include <stratosphere/erpt/erpt_multiple_category_context.hpp> #include <stratosphere/erpt/sf/erpt_sf_i_context.hpp> #include <stratosphere/erpt/sf/erpt_sf_i_session.hpp> #include <stratosphere/erpt/srv/erpt_srv_types.hpp> #include <stratosphere/erpt/srv/erpt_srv_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/err/err_error_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::err { enum class ErrorContextType : u8 { None = 0, Http = 1, FileSystem = 2, WebMediaPlayer = 3, LocalContentShare = 4, }; struct PaddingErrorContext { u8 padding[0x200 - 8]; }; struct ErrorContext : public sf::LargeData, public sf::PrefersMapAliasTransferMode { ErrorContextType type; u8 reserved[7]; union { PaddingErrorContext padding; }; }; static_assert(sizeof(ErrorContext) == 0x200); static_assert(util::is_pod<ErrorContext>::value); struct ContextDescriptor { int value; constexpr ALWAYS_INLINE bool operator==(const ContextDescriptor &rhs) const { return this->value == rhs.value; } constexpr ALWAYS_INLINE bool operator!=(const ContextDescriptor &rhs) const { return this->value != rhs.value; } constexpr ALWAYS_INLINE bool operator< (const ContextDescriptor &rhs) const { return this->value < rhs.value; } constexpr ALWAYS_INLINE bool operator<=(const ContextDescriptor &rhs) const { return this->value <= rhs.value; } constexpr ALWAYS_INLINE bool operator> (const ContextDescriptor &rhs) const { return this->value > rhs.value; } constexpr ALWAYS_INLINE bool operator>=(const ContextDescriptor &rhs) const { return this->value >= rhs.value; } }; constexpr inline const ContextDescriptor InvalidContextDescriptor{ -1 }; namespace impl { constexpr inline const ContextDescriptor ContextDescriptorMin{ 0x001 }; constexpr inline const ContextDescriptor ContextDescriptorMax{ 0x1FF }; } constexpr Result MakeResultWithContextDescriptor(Result result, ContextDescriptor descriptor) { /* Check pre-conditions. */ AMS_ASSERT(R_FAILED(result)); AMS_ASSERT(descriptor != InvalidContextDescriptor); AMS_ASSERT(impl::ContextDescriptorMin <= descriptor && descriptor <= impl::ContextDescriptorMax); return result::impl::ResultInternalAccessor::MergeReserved(result, descriptor.value | 0x200); } constexpr ContextDescriptor GetContextDescriptorFromResult(Result result) { /* Check pre-conditions. */ AMS_ASSERT(R_FAILED(result)); /* Get reserved bits. */ const auto reserved = result::impl::ResultInternalAccessor::GetReserved(result); if ((reserved & 0x200) != 0x200) { return InvalidContextDescriptor; } /* Check the descriptor value. */ const ContextDescriptor descriptor{static_cast<decltype(ContextDescriptor{}.value)>(reserved & ~0x200)}; if (!(impl::ContextDescriptorMin <= descriptor && descriptor <= impl::ContextDescriptorMax)) { return InvalidContextDescriptor; } return descriptor; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/err/err_system_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/err/err_types.hpp> namespace ams::err { ErrorCode ConvertResultToErrorCode(const Result &result); void GetErrorCodeString(char *dst, size_t dst_size, ErrorCode error_code); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/err/err_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::err { using ErrorCodeCategory = u32; using ErrorCodeNumber = u32; struct ErrorCode { static constexpr auto StringLengthMax = 15; ErrorCodeCategory category; ErrorCodeNumber number; constexpr ALWAYS_INLINE bool IsValid() const { return this->category > 0; } }; constexpr inline ErrorCode InvalidErrorCode = { .category = 0, .number = 0, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/err.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/err/err_types.hpp> #include <stratosphere/err/err_error_context.hpp> #include <stratosphere/err/err_system_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fat/fat_file_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fat { constexpr inline size_t FatErrorNameMaxLength = 0x10; struct FatError { int error; int extra_error; int drive_id; char name[FatErrorNameMaxLength]; u8 reserved[4]; }; static_assert(sizeof(FatError) == 0x20); static_assert(util::is_pod<FatError>::value); struct FatReportInfo1 { u16 open_file_peak_count; u16 open_directory_peak_count; }; static_assert(sizeof(FatReportInfo1) == 4); static_assert(util::is_pod<FatReportInfo1>::value); struct FatReportInfo2 { u16 open_unique_file_entry_peak_count; u16 open_unique_directory_entry_peak_count; }; static_assert(sizeof(FatReportInfo2) == 4); static_assert(util::is_pod<FatReportInfo2>::value); struct FatSafeInfo { u32 result; u32 error_number; u32 safe_error_number; }; static_assert(sizeof(FatSafeInfo) == 12); static_assert(util::is_pod<FatSafeInfo>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fat.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fat/fat_file_system.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fatal/fatal_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::fatal { enum FatalPolicy : u32 { FatalPolicy_ErrorReportAndErrorScreen = 0, FatalPolicy_ErrorReport = 1, FatalPolicy_ErrorScreen = 2, }; #if defined(ATMOSPHERE_ARCH_ARM64) namespace aarch64 { enum RegisterName { RegisterName_X0 = 0, RegisterName_X1 = 1, RegisterName_X2 = 2, RegisterName_X3 = 3, RegisterName_X4 = 4, RegisterName_X5 = 5, RegisterName_X6 = 6, RegisterName_X7 = 7, RegisterName_X8 = 8, RegisterName_X9 = 9, RegisterName_X10 = 10, RegisterName_X11 = 11, RegisterName_X12 = 12, RegisterName_X13 = 13, RegisterName_X14 = 14, RegisterName_X15 = 15, RegisterName_X16 = 16, RegisterName_X17 = 17, RegisterName_X18 = 18, RegisterName_X19 = 19, RegisterName_X20 = 20, RegisterName_X21 = 21, RegisterName_X22 = 22, RegisterName_X23 = 23, RegisterName_X24 = 24, RegisterName_X25 = 25, RegisterName_X26 = 26, RegisterName_X27 = 27, RegisterName_X28 = 28, RegisterName_FP = 29, RegisterName_LR = 30, RegisterName_SP = 31, RegisterName_PC = 32, RegisterName_GeneralPurposeCount, RegisterName_PState = 33, RegisterName_Afsr0 = 34, RegisterName_Afsr1 = 35, RegisterName_Esr = 36, RegisterName_Far = 37, RegisterName_Count, }; struct CpuContext { using RegisterType = u64; static constexpr size_t MaxStackTraceDepth = 0x20; static constexpr const char *RegisterNameStrings[RegisterName_Count] = { "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15", "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23", "X24", "X25", "X26", "X27", "X28", "FP", "LR", "SP", "PC", "PState", "Afsr0", "Afsr1", "Esr", "Far", }; /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { struct { union { RegisterType x[RegisterName_GeneralPurposeCount]; struct { RegisterType _x[RegisterName_FP]; RegisterType fp; RegisterType lr; RegisterType sp; RegisterType pc; }; }; RegisterType pstate; RegisterType afsr0; RegisterType afsr1; RegisterType esr; RegisterType far; }; RegisterType registers[RegisterName_Count]; }; /* Misc. */ RegisterType stack_trace[MaxStackTraceDepth]; RegisterType base_address; RegisterType register_set_flags; u32 stack_trace_size; void ClearState() { std::memset(this, 0, sizeof(*this)); } void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { /* Right now, we mux program ID in through afsr when creport. */ /* TODO: Better way to do this? */ this->afsr0 = static_cast<RegisterType>(program_id.value); } ncm::ProgramId GetProgramIdForAtmosphere() const { return ncm::ProgramId{this->afsr0}; } void SetRegisterValue(RegisterName name, RegisterType value) { this->registers[name] = value; this->register_set_flags |= (RegisterType(1) << name); } bool HasRegisterValue(RegisterName name) const { return this->register_set_flags & (RegisterType(1) << name); } void SetBaseAddress(RegisterType base_addr) { this->base_address = base_addr; } }; } #endif #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) namespace aarch32 { enum RegisterName { RegisterName_R0 = 0, RegisterName_R1 = 1, RegisterName_R2 = 2, RegisterName_R3 = 3, RegisterName_R4 = 4, RegisterName_R5 = 5, RegisterName_R6 = 6, RegisterName_R7 = 7, RegisterName_R8 = 8, RegisterName_R9 = 9, RegisterName_R10 = 10, RegisterName_FP = 11, RegisterName_IP = 12, RegisterName_LR = 13, RegisterName_SP = 14, RegisterName_PC = 15, RegisterName_GeneralPurposeCount, RegisterName_PState = 16, RegisterName_Afsr0 = 17, RegisterName_Afsr1 = 18, RegisterName_Esr = 29, RegisterName_Far = 20, RegisterName_Count, }; struct CpuContext { using RegisterType = u32; static constexpr size_t MaxStackTraceDepth = 0x20; static constexpr const char *RegisterNameStrings[RegisterName_Count] = { "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "FP", "IP", "LR", "SP", "PC", "PState", "Afsr0", "Afsr1", "Esr", "Far", }; /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { struct { union { RegisterType r[RegisterName_GeneralPurposeCount]; struct { RegisterType _x[RegisterName_FP]; RegisterType fp; RegisterType ip; RegisterType lr; RegisterType sp; RegisterType pc; }; }; RegisterType pstate; RegisterType afsr0; RegisterType afsr1; RegisterType esr; RegisterType far; }; RegisterType registers[RegisterName_Count]; }; /* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */ RegisterType stack_trace[MaxStackTraceDepth]; u32 stack_trace_size; RegisterType base_address; RegisterType register_set_flags; void ClearState() { std::memset(this, 0, sizeof(*this)); } void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { /* Right now, we mux program ID in through afsr when creport. */ /* TODO: Better way to do this? */ this->afsr0 = static_cast<RegisterType>(static_cast<u64>(program_id.value) >> 0); this->afsr1 = static_cast<RegisterType>(static_cast<u64>(program_id.value) >> 32); } ncm::ProgramId GetProgramIdForAtmosphere() const { return ncm::ProgramId{(static_cast<u64>(this->afsr1) << 32ul) | (static_cast<u64>(this->afsr0) << 0ul)}; } void SetRegisterValue(RegisterName name, RegisterType value) { this->registers[name] = value; this->register_set_flags |= (RegisterType(1) << name); } bool HasRegisterValue(RegisterName name) const { return this->register_set_flags & (RegisterType(1) << name); } void SetBaseAddress(RegisterType base_addr) { this->base_address = base_addr; } }; } #endif #if defined(ATMOSPHERE_ARCH_X64) namespace x64 { enum RegisterName { /* TODO */ RegisterName_Count, }; struct CpuContext { using RegisterType = u64; static constexpr size_t MaxStackTraceDepth = 0x20; static constexpr const char *RegisterNameStrings[RegisterName_Count] = { /* TODO */ }; /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { // struct { // /* TODO */ // }; RegisterType registers[RegisterName_Count]; }; /* Misc. */ RegisterType stack_trace[MaxStackTraceDepth]; RegisterType base_address; RegisterType register_set_flags; u32 stack_trace_size; void ClearState() { std::memset(this, 0, sizeof(*this)); } void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { AMS_UNUSED(program_id); AMS_ABORT("TODO"); } ncm::ProgramId GetProgramIdForAtmosphere() const { AMS_ABORT("TODO"); } void SetRegisterValue(RegisterName name, RegisterType value) { this->registers[name] = value; this->register_set_flags |= (RegisterType(1) << name); } bool HasRegisterValue(RegisterName name) const { return this->register_set_flags & (RegisterType(1) << name); } void SetBaseAddress(RegisterType base_addr) { this->base_address = base_addr; } }; } #endif #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) namespace x86 { enum RegisterName { /* TODO */ RegisterName_Count, }; struct CpuContext { using RegisterType = u32; static constexpr size_t MaxStackTraceDepth = 0x20; static constexpr const char *RegisterNameStrings[RegisterName_Count] = { /* TODO */ }; /* Registers, exception context. N left names for these fields in fatal .rodata. */ union { // struct { // /* TODO */ // }; RegisterType registers[RegisterName_Count]; }; /* Misc. Yes, stack_trace_size is really laid out differently than aarch64... */ RegisterType stack_trace[MaxStackTraceDepth]; u32 stack_trace_size; RegisterType base_address; RegisterType register_set_flags; void ClearState() { std::memset(this, 0, sizeof(*this)); } void SetProgramIdForAtmosphere(ncm::ProgramId program_id) { AMS_UNUSED(program_id); AMS_ABORT("TODO"); } ncm::ProgramId GetProgramIdForAtmosphere() const { AMS_ABORT("TODO"); } void SetRegisterValue(RegisterName name, RegisterType value) { this->registers[name] = value; this->register_set_flags |= (RegisterType(1) << name); } bool HasRegisterValue(RegisterName name) const { return this->register_set_flags & (RegisterType(1) << name); } void SetBaseAddress(RegisterType base_addr) { this->base_address = base_addr; } }; } #endif struct CpuContext : sf::LargeData, sf::PrefersMapAliasTransferMode { enum Architecture { #if defined(ATMOSPHERE_ARCH_ARM64) Architecture_Aarch64, #endif #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) Architecture_Aarch32, #endif #if defined(ATMOSPHERE_X64) Architecture_X64, #endif #if defined(ATMOSPHERE_X64) || defined(ATMOSPHERE_ARCH_X86) Architecture_X86, #endif }; union { #if defined(ATMOSPHERE_ARCH_ARM64) aarch64::CpuContext aarch64_ctx; #endif #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) aarch32::CpuContext aarch32_ctx; #endif #if defined(ATMOSPHERE_X64) aarch64::CpuContext x64_ctx; #endif #if defined(ATMOSPHERE_X64) || defined(ATMOSPHERE_ARCH_X86) aarch64::CpuContext x86_ctx; #endif u8 raw_storage[0x248]; }; Architecture architecture; u32 type; void ClearState() { std::memset(this, 0, sizeof(*this)); } }; #if defined(ATMOSPHERE_ARCH_ARM64) static_assert(util::is_pod<aarch64::CpuContext>::value && sizeof(aarch64::CpuContext) == 0x248, "aarch64::CpuContext definition!"); #endif #if defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) static_assert(util::is_pod<aarch32::CpuContext>::value && sizeof(aarch32::CpuContext) == 0xE0, "aarch32::CpuContext definition!"); #endif static_assert(util::is_pod<CpuContext>::value && sizeof(CpuContext) == 0x250, "CpuContext definition!"); struct HashedTraceContext { u8 data[0x20]; u32 data_count; }; static_assert(util::is_pod<HashedTraceContext>::value); static_assert(sizeof(HashedTraceContext) == 0x24); static_assert(alignof(HashedTraceContext) == 0x4); namespace srv { struct ThrowContext { Result result; FatalPolicy policy; ncm::ProgramId program_id; ncm::ProgramId throw_program_id; char proc_name[0xD]; bool is_creport; CpuContext cpu_ctx; HashedTraceContext hashed_trace_ctx; bool generate_error_report; os::Event *erpt_event; os::Event *battery_event; size_t stack_dump_size; u64 stack_dump_base; u8 stack_dump[0x100]; u64 tls_address; u8 tls_dump[0x100]; ThrowContext(os::Event *erpt, os::Event *bat) : result(ResultSuccess()), policy(), program_id(), throw_program_id(), proc_name(), is_creport(), cpu_ctx(), hashed_trace_ctx(), generate_error_report(), erpt_event(erpt), battery_event(bat), stack_dump_size(), stack_dump_base(), stack_dump(), tls_address(), tls_dump() { /* ... */ } }; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_private_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fatal/fatal_types.hpp> #include <stratosphere/sf.hpp> #define AMS_FATAL_I_PRIVATE_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetFatalEvent, (sf::OutCopyHandle out_h), (out_h)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, GetFatalContext, (sf::Out<Result> out_error, sf::Out<ncm::ProgramId> out_program_id, sf::Out<fatal::FatalPolicy> out_policy, sf::Out<fatal::CpuContext> out_ctx), (out_error, out_program_id, out_policy, out_ctx)) AMS_SF_DEFINE_INTERFACE(ams::fatal::impl, IPrivateService, AMS_FATAL_I_PRIVATE_SERVICE_INTERFACE_INFO, 0x6C3C9791) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fatal/impl/fatal_i_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fatal/fatal_types.hpp> #include <stratosphere/sf.hpp> #define AMS_FATAL_I_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ThrowFatal, (Result error, const sf::ClientProcessId &client_pid), (error, client_pid)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, ThrowFatalWithPolicy, (Result error, const sf::ClientProcessId &client_pid, fatal::FatalPolicy policy), (error, client_pid, policy)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, ThrowFatalWithCpuContext, (Result error, const sf::ClientProcessId &client_pid, fatal::FatalPolicy policy, const fatal::CpuContext &cpu_ctx), (error, client_pid, policy, cpu_ctx)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, ThrowFatalWithHashedTraceContext, (Result error, const sf::ClientProcessId &client_pid, ncm::ProgramId program_id, const fatal::HashedTraceContext &htc), (error, client_pid, program_id, htc)) AMS_SF_DEFINE_INTERFACE(ams::fatal::impl, IService, AMS_FATAL_I_SERVICE_INTERFACE_INFO, 0x91328766) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fatal.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fatal/fatal_types.hpp> #include <stratosphere/fatal/impl/fatal_i_service.hpp> #include <stratosphere/fatal/impl/fatal_i_private_service.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/common/fs_dbm_rom_types.hpp> #include <stratosphere/fs/common/fs_dbm_rom_path_tool.hpp> #include <stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 14.3.0.0 */ class HierarchicalRomFileTable { public: using Position = u32; using StorageSizeType = u32; struct FindPosition { Position next_dir; Position next_file; }; static_assert(util::is_pod<FindPosition>::value); using FileInfo = RomFileInfo; static constexpr RomFileId PositionToFileId(Position pos) { return static_cast<RomFileId>(pos); } static constexpr Position FileIdToPosition(RomFileId id) { return static_cast<Position>(id); } private: static constexpr inline Position InvalidPosition = ~Position(); static constexpr inline Position RootPosition = 0; static constexpr inline size_t ReservedDirectoryCount = 1; static constexpr RomDirectoryId PositionToDirectoryId(Position pos) { return static_cast<RomDirectoryId>(pos); } static constexpr Position DirectoryIdToPosition(RomDirectoryId id) { return static_cast<Position>(id); } static_assert(std::is_same<RomDirectoryId, RomFileId>::value); struct RomDirectoryEntry { Position next; Position dir; Position file; }; static_assert(util::is_pod<RomDirectoryEntry>::value); struct RomFileEntry { Position next; FileInfo info; }; static_assert(util::is_pod<RomFileEntry>::value); static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; template<typename ImplKeyType, typename ClientKeyType, typename ValueType> class EntryMapTable : public KeyValueRomStorageTemplate<ImplKeyType, ValueType, MaxKeyLength> { public: using ImplKey = ImplKeyType; using ClientKey = ClientKeyType; using Value = ValueType; using Position = HierarchicalRomFileTable::Position; using Base = KeyValueRomStorageTemplate<ImplKeyType, ValueType, MaxKeyLength>; public: Result Add(Position *out, const ClientKeyType &key, const Value &value) { R_RETURN(Base::AddInternal(out, key.key, key.Hash(), key.name.begin(), key.name.length(), value)); } Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) { R_RETURN(Base::GetInternal(out_pos, out_val, key.key, key.Hash(), key.name.begin(), key.name.length())); } Result GetByPosition(ImplKey *out_key, Value *out_val, Position pos) { R_RETURN(Base::GetByPosition(out_key, out_val, pos)); } Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) { R_RETURN(Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos)); } Result SetByPosition(Position pos, const Value &value) { R_RETURN(Base::SetByPosition(pos, value)); } }; struct RomEntryKey { Position parent; bool IsEqual(const RomEntryKey &rhs, const void *aux_lhs, size_t aux_lhs_size, const void *aux_rhs, size_t aux_rhs_size) const { if (this->parent != rhs.parent) { return false; } if (aux_lhs_size != aux_rhs_size) { return false; } return RomPathTool::IsEqualPath(reinterpret_cast<const RomPathChar *>(aux_lhs), reinterpret_cast<const RomPathChar *>(aux_rhs), aux_lhs_size / sizeof(RomPathChar)); } }; static_assert(util::is_pod<RomEntryKey>::value); struct EntryKey { RomEntryKey key; RomPathTool::RomEntryName name; constexpr u32 Hash() const { u32 hash = this->key.parent ^ 123456789; const RomPathChar * cur = this->name.begin(); const RomPathChar * const end = this->name.end(); while (cur < end) { const u32 c = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(cur++))); hash = ((hash >> 5) | (hash << 27)) ^ c; } return hash; } }; using DirectoryEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomDirectoryEntry>; using FileEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomFileEntry>; private: DirectoryEntryMapTable m_dir_table; FileEntryMapTable m_file_table; public: static s64 QueryDirectoryEntryBucketStorageSize(StorageSizeType count); static s64 QueryDirectoryEntrySize(StorageSizeType aux_size); static s64 QueryFileEntryBucketStorageSize(StorageSizeType count); static s64 QueryFileEntrySize(StorageSizeType aux_size); static Result Format(SubStorage dir_bucket, SubStorage file_bucket); public: HierarchicalRomFileTable(); Result Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry); void Finalize(); Result CreateRootDirectory(); Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path); Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info); Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path); Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path); Result OpenFile(FileInfo *out, const RomPathChar *path); Result OpenFile(FileInfo *out, RomFileId id); Result FindOpen(FindPosition *out, const RomPathChar *path); Result FindOpen(FindPosition *out, RomDirectoryId id); Result FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length); Result FindNextFile(RomPathChar *out, FindPosition *find, size_t length); Result QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size); private: Result GetParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path); Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path); Result FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path); Result FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path); Result FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path); Result CheckSameEntryExists(const EntryKey &key, Result if_exists); Result GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key); Result GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id); Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key); Result GetFileEntry(RomFileEntry *out_entry, RomFileId id); Result OpenFile(FileInfo *out, const EntryKey &key); Result FindOpen(FindPosition *out, const EntryKey &key); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/common/fs_dbm_rom_types.hpp> #include <stratosphere/fs/fs_substorage.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 14.3.0.0 */ template<typename KeyType, typename ValueType, size_t MaxAuxiliarySize> class KeyValueRomStorageTemplate { public: using Key = KeyType; using Value = ValueType; using Position = u32; using BucketIndex = s64; using StorageSizeType = u32; struct FindIndex { BucketIndex ind; Position pos; }; static_assert(util::is_pod<FindIndex>::value); private: static constexpr inline Position InvalidPosition = ~Position(); struct Element { Key key; Value value; Position next; StorageSizeType size; }; static_assert(util::is_pod<Element>::value); private: s64 m_bucket_count; SubStorage m_bucket_storage; SubStorage m_kv_storage; s64 m_total_entry_size; u32 m_entry_count; public: static constexpr s64 QueryBucketStorageSize(s64 num) { return num * sizeof(Position); } static constexpr s64 QueryBucketCount(StorageSizeType size) { return size / sizeof(Position); } static constexpr size_t QueryEntrySize(StorageSizeType aux_size) { return util::AlignUp<size_t>(sizeof(Element) + aux_size, alignof(Element)); } static Result Format(SubStorage bucket, StorageSizeType count) { const Position pos = InvalidPosition; for (auto i = 0u; i < count; i++) { R_TRY(bucket.Write(i * sizeof(pos), std::addressof(pos), sizeof(pos))); } R_SUCCEED(); } public: constexpr KeyValueRomStorageTemplate() : m_bucket_count(), m_bucket_storage(), m_kv_storage(), m_total_entry_size(), m_entry_count() { /* ... */ } Result Initialize(const SubStorage &bucket, s64 count, const SubStorage &kv) { AMS_ASSERT(count > 0); m_bucket_storage = bucket; m_bucket_count = count; m_kv_storage = kv; R_SUCCEED(); } void Finalize() { m_bucket_storage = SubStorage(); m_bucket_count = 0; m_kv_storage = SubStorage(); } s64 GetTotalEntrySize() const { return m_total_entry_size; } protected: Result AddInternal(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) { AMS_ASSERT(out != nullptr); AMS_ASSERT(aux != nullptr || aux_size == 0); AMS_ASSERT(m_bucket_count > 0); { Position pos, prev_pos; Element elem; const Result find_res = this->FindInternal(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size); R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists()); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res); } Position pos; R_TRY(this->AllocateEntry(std::addressof(pos), static_cast<StorageSizeType>(aux_size))); Position next_pos; R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key)); const Element elem = { key, value, next_pos, static_cast<StorageSizeType>(aux_size) }; R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size)); *out = pos; m_entry_count++; R_SUCCEED(); } Result GetInternal(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_val != nullptr); AMS_ASSERT(aux != nullptr); Position pos, prev_pos; Element elem; R_TRY(this->FindInternal(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size)); *out_pos = pos; *out_val = elem.value; R_SUCCEED(); } Result GetByPosition(Key *out_key, Value *out_val, Position pos) { AMS_ASSERT(out_key != nullptr); AMS_ASSERT(out_val != nullptr); Element elem; R_TRY(this->ReadKeyValue(std::addressof(elem), pos)); *out_key = elem.key; *out_val = elem.value; R_SUCCEED(); } Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) { AMS_ASSERT(out_key != nullptr); AMS_ASSERT(out_val != nullptr); AMS_ASSERT(out_aux != nullptr); AMS_ASSERT(out_aux_size != nullptr); Element elem; R_TRY(this->ReadKeyValue(std::addressof(elem), out_aux, out_aux_size, pos)); *out_key = elem.key; *out_val = elem.value; R_SUCCEED(); } Result SetByPosition(Position pos, const Value &value) { Element elem; R_TRY(this->ReadKeyValue(std::addressof(elem), pos)); elem.value = value; R_RETURN(this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0)); } private: BucketIndex HashToBucket(u32 hash_key) const { return hash_key % m_bucket_count; } Result FindInternal(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_prev != nullptr); AMS_ASSERT(out_elem != nullptr); AMS_ASSERT(aux != nullptr || aux_size == 0); AMS_ASSERT(m_bucket_count > 0); *out_pos = 0; *out_prev = 0; const BucketIndex ind = HashToBucket(hash_key); Position cur; R_TRY(this->ReadBucket(std::addressof(cur), ind)); s64 kv_size; R_TRY(m_kv_storage.GetSize(std::addressof(kv_size))); AMS_ASSERT(cur == InvalidPosition || cur < kv_size); R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound()); auto buf = ::ams::fs::impl::MakeUnique<u8[]>(MaxAuxiliarySize); R_UNLESS(buf != nullptr, fs::ResultAllocationMemoryFailedMakeUnique()); while (true) { size_t cur_aux_size; R_TRY(this->ReadKeyValue(out_elem, buf.get(), std::addressof(cur_aux_size), cur)); if (key.IsEqual(out_elem->key, aux, aux_size, buf.get(), cur_aux_size)) { *out_pos = cur; R_SUCCEED(); } *out_prev = cur; cur = out_elem->next; R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound()); } } Result AllocateEntry(Position *out, StorageSizeType aux_size) { AMS_ASSERT(out != nullptr); s64 kv_size; R_TRY(m_kv_storage.GetSize(std::addressof(kv_size))); const size_t end_pos = m_total_entry_size + sizeof(Element) + static_cast<size_t>(aux_size); R_UNLESS(end_pos <= static_cast<size_t>(kv_size), fs::ResultDbmKeyFull()); *out = static_cast<Position>(m_total_entry_size); m_total_entry_size = util::AlignUp<s64>(static_cast<s64>(end_pos), alignof(Position)); R_SUCCEED(); } Result LinkEntry(Position *out, Position pos, u32 hash_key) { AMS_ASSERT(out != nullptr); const BucketIndex ind = HashToBucket(hash_key); Position next; R_TRY(this->ReadBucket(std::addressof(next), ind)); s64 kv_size; R_TRY(m_kv_storage.GetSize(std::addressof(kv_size))); AMS_ASSERT(next == InvalidPosition || next < kv_size); R_TRY(this->WriteBucket(pos, ind)); *out = next; R_SUCCEED(); } Result ReadBucket(Position *out, BucketIndex ind) { AMS_ASSERT(out != nullptr); AMS_ASSERT(ind < m_bucket_count); const s64 offset = ind * sizeof(Position); R_RETURN(m_bucket_storage.Read(offset, out, sizeof(*out))); } Result WriteBucket(Position pos, BucketIndex ind) { AMS_ASSERT(ind < m_bucket_count); const s64 offset = ind * sizeof(Position); R_RETURN(m_bucket_storage.Write(offset, std::addressof(pos), sizeof(pos))); } Result ReadKeyValue(Element *out, Position pos) { AMS_ASSERT(out != nullptr); s64 kv_size; R_TRY(m_kv_storage.GetSize(std::addressof(kv_size))); AMS_ASSERT(pos < kv_size); R_RETURN(m_kv_storage.Read(pos, out, sizeof(*out))); } Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) { AMS_ASSERT(out != nullptr); AMS_ASSERT(out_aux != nullptr); AMS_ASSERT(out_aux_size != nullptr); R_TRY(this->ReadKeyValue(out, pos)); *out_aux_size = out->size; if (out->size > 0) { R_TRY(m_kv_storage.Read(pos + sizeof(*out), out_aux, out->size)); } R_SUCCEED(); } Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size) { AMS_ASSERT(elem != nullptr); AMS_ASSERT(aux != nullptr); s64 kv_size; R_TRY(m_kv_storage.GetSize(std::addressof(kv_size))); AMS_ASSERT(pos < kv_size); R_TRY(m_kv_storage.Write(pos, elem, sizeof(*elem))); if (aux != nullptr && aux_size > 0) { R_TRY(m_kv_storage.Write(pos + sizeof(*elem), aux, aux_size)); } R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/common/fs_dbm_rom_types.hpp> namespace ams::fs::RomPathTool { /* ACCURATE_TO_VERSION: 14.3.0.0 */ constexpr inline u32 MaxPathLength = 0x300; constexpr ALWAYS_INLINE bool IsSeparator(RomPathChar c) { return c == RomStringTraits::DirectorySeparator; } constexpr ALWAYS_INLINE bool IsNullTerminator(RomPathChar c) { return c == RomStringTraits::NullTerminator; } constexpr ALWAYS_INLINE bool IsDot(RomPathChar c) { return c == RomStringTraits::Dot; } class RomEntryName { private: const RomPathChar *m_path; size_t m_length; public: constexpr RomEntryName() : m_path(nullptr), m_length(0) { /* ... */ } constexpr void Initialize(const RomPathChar *p, size_t len) { m_path = p; m_length = len; } constexpr bool IsCurrentDirectory() const { return m_length == 1 && IsDot(m_path[0]); } constexpr bool IsParentDirectory() const { return m_length == 2 && IsDot(m_path[0]) && IsDot(m_path[1]); } constexpr bool IsRootDirectory() const { return m_length == 0; } constexpr const RomPathChar *begin() const { return m_path; } constexpr const RomPathChar *end() const { return m_path + m_length; } constexpr size_t length() const { return m_length; } }; constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) { AMS_ASSERT(p != nullptr); return length == 1 && IsDot(p[0]); } constexpr inline bool IsCurrentDirectory(const RomPathChar *p) { AMS_ASSERT(p != nullptr); return IsDot(p[0]) && IsNullTerminator(p[1]); } constexpr inline bool IsParentDirectory(const RomPathChar *p) { AMS_ASSERT(p != nullptr); return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]); } constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) { AMS_ASSERT(p != nullptr); return length == 2 && IsDot(p[0]) && IsDot(p[1]); } constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) { AMS_ASSERT(lhs != nullptr); AMS_ASSERT(rhs != nullptr); return std::strncmp(lhs, rhs, length) == 0; } Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p); class PathParser { private: const RomPathChar *m_prev_path_start; const RomPathChar *m_prev_path_end; const RomPathChar *m_next_path; bool m_finished; public: constexpr PathParser() : m_prev_path_start(), m_prev_path_end(), m_next_path(), m_finished() { /* ... */ } Result Initialize(const RomPathChar *path); void Finalize(); bool IsParseFinished() const; bool IsDirectoryPath() const; Result GetAsDirectoryName(RomEntryName *out) const; Result GetAsFileName(RomEntryName *out) const; Result GetNextDirectoryName(RomEntryName *out); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 14.3.0.0 */ using RomPathChar = char; using RomFileId = u32; using RomDirectoryId = u32; struct RomFileSystemInformation { s64 size; s64 directory_bucket_offset; s64 directory_bucket_size; s64 directory_entry_offset; s64 directory_entry_size; s64 file_bucket_offset; s64 file_bucket_size; s64 file_entry_offset; s64 file_entry_size; s64 body_offset; }; static_assert(util::is_pod<RomFileSystemInformation>::value); static_assert(sizeof(RomFileSystemInformation) == 0x50); struct RomFileInfo { Int64 offset; Int64 size; }; static_assert(util::is_pod<RomFileInfo>::value); namespace RomStringTraits { constexpr inline char DirectorySeparator = '/'; constexpr inline char NullTerminator = '\x00'; constexpr inline char Dot = '.'; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_directory_path_parser.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_path.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class DirectoryPathParser { NON_COPYABLE(DirectoryPathParser); NON_MOVEABLE(DirectoryPathParser); private: char *m_buffer; char m_replaced_char; s32 m_position; fs::Path m_current_path; public: DirectoryPathParser() : m_buffer(nullptr), m_replaced_char(StringTraits::NullTerminator), m_position(0), m_current_path() { /* ... */ } const fs::Path &GetCurrentPath() const { return m_current_path; } Result Initialize(fs::Path *path) { /* Declare a default buffer, in case the path has no write buffer. */ static constinit char EmptyBuffer[1] = ""; /* Get a usable buffer. */ char *buf = path->GetWriteBufferLength() > 0 ? path->GetWriteBuffer() : EmptyBuffer; /* Get the windows skip length. */ const auto windows_skip_len = fs::GetWindowsSkipLength(buf); /* Set our buffer. */ m_buffer = buf + windows_skip_len; /* Set up our initial state. */ if (windows_skip_len) { R_TRY(m_current_path.InitializeWithNormalization(buf, windows_skip_len + 1)); } else { if (char * const first = this->ReadNextImpl(); first != nullptr) { R_TRY(m_current_path.InitializeWithNormalization(first)); } } R_SUCCEED(); } Result ReadNext(bool *out_finished) { /* Default to not finished. */ *out_finished = false; /* Get the next child component. */ if (auto * const child = this->ReadNextImpl(); child != nullptr) { /* Append the child component to our current path. */ R_TRY(m_current_path.AppendChild(child)); } else { /* We have no child component, so we're finished. */ *out_finished = true; } R_SUCCEED(); } private: char *ReadNextImpl() { /* Check that we have characters to read. */ if (m_position < 0 || m_buffer[0] == StringTraits::NullTerminator) { return nullptr; } /* If we have a replaced character, restore it. */ if (m_replaced_char != StringTraits::NullTerminator) { m_buffer[m_position] = m_replaced_char; if (m_replaced_char == StringTraits::DirectorySeparator) { ++m_position; } } /* If we're at the start of a root-relative path, begin by returning the root. */ if (m_position == 0 && m_buffer[0] == StringTraits::DirectorySeparator) { m_replaced_char = m_buffer[1]; m_buffer[1] = StringTraits::NullTerminator; m_position = 1; return m_buffer; } /* Otherwise, find the end of the next path component. */ s32 i; for (i = m_position; m_buffer[i] != StringTraits::DirectorySeparator; ++i) { if (m_buffer[i] == StringTraits::NullTerminator) { char * const ret = (i != m_position) ? m_buffer + m_position : nullptr; m_position = -1; return ret; } } /* Sanity check that we're not ending on a separator. */ AMS_ASSERT(m_buffer[i + 1] != StringTraits::NullTerminator); char * const ret = m_buffer + m_position; m_replaced_char = StringTraits::DirectorySeparator; m_buffer[i] = 0; m_position = i; return ret; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/common/fs_file_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class FileStorage : public IStorage, public impl::Newable { NON_COPYABLE(FileStorage); NON_MOVEABLE(FileStorage); private: static constexpr s64 InvalidSize = -1; private: std::unique_ptr<fsa::IFile> m_unique_file; std::shared_ptr<fsa::IFile> m_shared_file; fsa::IFile *m_base_file; s64 m_size; public: FileStorage(fsa::IFile *f) : m_unique_file(f), m_size(InvalidSize) { m_base_file = m_unique_file.get(); } FileStorage(std::unique_ptr<fsa::IFile> f) : m_unique_file(std::move(f)), m_size(InvalidSize) { m_base_file = m_unique_file.get(); } FileStorage(std::shared_ptr<fsa::IFile> f) : m_shared_file(f), m_size(InvalidSize) { m_base_file = m_shared_file.get(); } virtual ~FileStorage() { /* ... */ } private: Result UpdateSize(); protected: constexpr FileStorage() : m_unique_file(), m_shared_file(), m_base_file(nullptr), m_size(InvalidSize) { /* ... */ } void SetFile(fs::fsa::IFile *file) { AMS_ASSERT(file != nullptr); AMS_ASSERT(m_base_file == nullptr); m_base_file = file; } void SetFile(std::unique_ptr<fs::fsa::IFile> &&file) { AMS_ASSERT(file != nullptr); AMS_ASSERT(m_base_file == nullptr); AMS_ASSERT(m_unique_file == nullptr); m_unique_file = std::move(file); m_base_file = m_unique_file.get(); } public: virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; virtual Result GetSize(s64 *out_size) override; virtual Result SetSize(s64 size) override; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; /* ACCURATE_TO_VERSION: Unknown */ class FileStorageBasedFileSystem : public FileStorage { NON_COPYABLE(FileStorageBasedFileSystem); NON_MOVEABLE(FileStorageBasedFileSystem); private: std::shared_ptr<fs::fsa::IFileSystem> m_base_file_system; public: constexpr FileStorageBasedFileSystem() : FileStorage(), m_base_file_system(nullptr) { /* ... */ } Result Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode); }; class FileHandleStorage : public IStorage, public impl::Newable { private: static constexpr s64 InvalidSize = -1; private: FileHandle m_handle; bool m_close_file; s64 m_size; os::SdkMutex m_mutex; public: constexpr explicit FileHandleStorage(FileHandle handle, bool close_file) : m_handle(handle), m_close_file(close_file), m_size(InvalidSize), m_mutex() { /* ... */ } constexpr explicit FileHandleStorage(FileHandle handle) : FileHandleStorage(handle, false) { /* ... */ } virtual ~FileHandleStorage() override { if (m_close_file) { CloseFile(m_handle); } } protected: Result UpdateSize(); public: virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; virtual Result GetSize(s64 *out_size) override; virtual Result SetSize(s64 size) override; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_access_log.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum AccessLogMode : u32 { AccessLogMode_None = 0, AccessLogMode_Log = 1, AccessLogMode_SdCard = 2, }; Result GetGlobalAccessLogMode(u32 *out); Result SetGlobalAccessLogMode(u32 mode); void SetLocalAccessLog(bool enabled); void SetLocalSystemAccessLogForDebug(bool enabled); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ void InitializeForSystem(); void InitializeWithMultiSessionForSystem(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_application.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ Result MountApplicationPackage(const char *name, const char *common_path); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_bis.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_istorage.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum class BisPartitionId { /* Boot0 */ BootPartition1Root = 0, /* Boot1 */ BootPartition2Root = 10, /* Non-Boot */ UserDataRoot = 20, BootConfigAndPackage2Part1 = 21, BootConfigAndPackage2Part2 = 22, BootConfigAndPackage2Part3 = 23, BootConfigAndPackage2Part4 = 24, BootConfigAndPackage2Part5 = 25, BootConfigAndPackage2Part6 = 26, CalibrationBinary = 27, CalibrationFile = 28, SafeMode = 29, User = 30, System = 31, SystemProperEncryption = 32, SystemProperPartition = 33, SignedSystemPartitionOnSafeMode = 34, DeviceTreeBlob = 35, System0 = 36, }; const char *GetBisMountName(BisPartitionId id); Result MountBis(BisPartitionId id, const char *root_path); Result MountBis(const char *name, BisPartitionId id); void SetBisRootForHost(BisPartitionId id, const char *root_path); Result OpenBisPartition(std::unique_ptr<fs::IStorage> *out, BisPartitionId id); Result InvalidateBisCache(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_code.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/fs_code_verification_data.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 16.2.0.0 */ Result MountCode(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id); Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id, bool is_hbl, bool is_specific); Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_code_verification_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 13.4.0.0 */ struct CodeVerificationData : public ams::sf::LargeData { u8 signature[crypto::Rsa2048PssSha256Verifier::SignatureSize]; u8 target_hash[crypto::Rsa2048PssSha256Verifier::HashSize]; bool has_data; u8 reserved[3]; }; static_assert(sizeof(CodeVerificationData) == crypto::Rsa2048PssSha256Verifier::SignatureSize + crypto::Rsa2048PssSha256Verifier::HashSize + 4); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/sf.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ struct Int64 { u32 low; u32 high; constexpr ALWAYS_INLINE void Set(s64 v) { this->low = static_cast<u32>((v & static_cast<u64>(0x00000000FFFFFFFFul)) >> 0); this->high = static_cast<u32>((v & static_cast<u64>(0xFFFFFFFF00000000ul)) >> 32); } constexpr ALWAYS_INLINE s64 Get() const { return (static_cast<s64>(this->high) << 32) | (static_cast<s64>(this->low)); } constexpr ALWAYS_INLINE Int64 &operator=(s64 v) { this->Set(v); return *this; } constexpr ALWAYS_INLINE operator s64() const { return this->Get(); } }; static_assert(util::is_pod<Int64>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_content.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum ContentType { ContentType_Meta = 0, ContentType_Control = 1, ContentType_Manual = 2, ContentType_Logo = 3, ContentType_Data = 4, }; Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ContentType content_type); Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId id, ContentType content_type); Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::DataId id, ContentType content_type); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_content_attributes.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum ContentAttributes : u8 { ContentAttributes_None = 0x0, ContentAttributes_All = 0xF, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_content_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_content_storage_id.hpp> namespace ams::fs { constexpr inline const char * const ContentStorageDirectoryName = "Contents"; const char *GetContentStorageMountName(ContentStorageId id); Result MountContentStorage(ContentStorageId id); Result MountContentStorage(const char *name, ContentStorageId id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_content_storage_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 16.2.0.0 */ enum class ContentStorageId : u32 { System = 0, User = 1, SdCard = 2, System0 = 3, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { enum class AbortSpecifier { Default, Abort, Return, }; using ResultHandler = AbortSpecifier (*)(Result); class FsContext { private: ResultHandler m_handler; public: constexpr explicit FsContext(ResultHandler h) : m_handler(h) { /* ... */ } constexpr void SetHandler(ResultHandler h) { m_handler = h; } constexpr AbortSpecifier HandleResult(Result result) const { return m_handler(result); } }; void SetDefaultFsContextResultHandler(const ResultHandler handler); const FsContext *GetCurrentThreadFsContext(); void SetCurrentThreadFsContext(const FsContext *context); class ScopedFsContext { private: const FsContext * const m_prev_context; public: ALWAYS_INLINE ScopedFsContext(const FsContext &ctx) : m_prev_context(GetCurrentThreadFsContext()) { SetCurrentThreadFsContext(std::addressof(ctx)); } ALWAYS_INLINE ~ScopedFsContext() { SetCurrentThreadFsContext(m_prev_context); } }; class ScopedAutoAbortDisabler { private: const FsContext * const m_prev_context; public: ScopedAutoAbortDisabler(); ALWAYS_INLINE ~ScopedAutoAbortDisabler() { SetCurrentThreadFsContext(m_prev_context); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_device_save_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_save_data_types.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ Result MountDeviceSaveData(const char *name); Result MountDeviceSaveData(const char *name, const ncm::ApplicationId application_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_directory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline size_t EntryNameLengthMax = 0x300; struct DirectoryEntry { char name[EntryNameLengthMax + 1]; char pad[3]; s8 type; u8 pad2[3]; s64 file_size; }; struct DirectoryHandle { void *handle; }; Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries); Result GetDirectoryEntryCount(s64 *out, DirectoryHandle handle); void CloseDirectory(DirectoryHandle handle); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_error_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fat/fat_file_system.hpp> namespace ams::fs { struct StorageErrorInfo { u32 num_activation_failures; u32 num_activation_error_corrections; u32 num_read_write_failures; u32 num_read_write_error_corrections; }; static_assert(sizeof(StorageErrorInfo) == 0x10); static_assert(util::is_pod<StorageErrorInfo>::value); struct FileSystemProxyErrorInfo { u32 rom_fs_remount_for_data_corruption_count; u32 rom_fs_unrecoverable_data_corruption_by_remount_count; fat::FatError fat_fs_error; u32 rom_fs_recovered_by_invalidate_cache_count; u32 save_data_index_count; fat::FatReportInfo1 bis_system_fat_report_info_1; fat::FatReportInfo1 bis_user_fat_report_info_1; fat::FatReportInfo1 sd_card_fat_report_info_1; fat::FatReportInfo2 bis_system_fat_report_info_2; fat::FatReportInfo2 bis_user_fat_report_info_2; fat::FatReportInfo2 sd_card_fat_report_info_2; u32 rom_fs_deep_retry_start_count; u32 rom_fs_unrecoverable_by_game_card_access_failed_count; fat::FatSafeInfo bis_system_fat_safe_info; fat::FatSafeInfo bis_user_fat_safe_info; u8 reserved[0x18]; }; static_assert(sizeof(FileSystemProxyErrorInfo) == 0x80); static_assert(util::is_pod<FileSystemProxyErrorInfo>::value); Result GetAndClearMmcErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size); Result GetAndClearSdCardErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size); Result GetAndClearFileSystemProxyErrorInfo(FileSystemProxyErrorInfo *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_file.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { struct ReadOption { u32 _value; static const ReadOption None; }; enum ReadOptionFlag : u32 { ReadOptionFlag_None = (0 << 0), }; inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None}; inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32)); enum WriteOptionFlag : u32 { WriteOptionFlag_None = (0 << 0), WriteOptionFlag_Flush = (1 << 0), }; struct WriteOption { u32 _value; constexpr inline bool HasFlushFlag() const { return _value & WriteOptionFlag_Flush; } static const WriteOption None; static const WriteOption Flush; }; inline constexpr const WriteOption WriteOption::None = {WriteOptionFlag_None}; inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush}; inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) { return !(lhs == rhs); } static_assert(util::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32)); struct FileHandle { void *handle; }; Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option); Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size); Result GetFileSize(s64 *out, FileHandle handle); Result FlushFile(FileHandle handle); Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option); Result SetFileSize(FileHandle handle, s64 size); int GetFileOpenMode(FileHandle handle); void CloseFile(FileHandle handle); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { namespace fsa { class IFileSystem; } enum OpenMode { OpenMode_Read = (1 << 0), OpenMode_Write = (1 << 1), OpenMode_AllowAppend = (1 << 2), OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write), OpenMode_All = (OpenMode_ReadWrite | OpenMode_AllowAppend), }; enum OpenDirectoryMode { OpenDirectoryMode_Directory = (1 << 0), OpenDirectoryMode_File = (1 << 1), OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File), /* TODO: Separate enum, like N? */ OpenDirectoryMode_NotRequireFileSize = (1 << 31), }; enum DirectoryEntryType { DirectoryEntryType_Directory = 0, DirectoryEntryType_File = 1, }; enum CreateOption { CreateOption_None = (0 << 0), CreateOption_BigFile = (1 << 0), }; struct FileHandle; struct DirectoryHandle; Result CreateFile(const char *path, s64 size); Result CreateFile(const char* path, s64 size, int option); Result DeleteFile(const char *path); Result CreateDirectory(const char *path); Result DeleteDirectory(const char *path); Result DeleteDirectoryRecursively(const char *path); Result RenameFile(const char *old_path, const char *new_path); Result RenameDirectory(const char *old_path, const char *new_path); Result GetEntryType(DirectoryEntryType *out, const char *path); Result OpenFile(FileHandle *out_file, const char *path, int mode); Result OpenDirectory(DirectoryHandle *out_dir, const char *path, int mode); Result CleanDirectoryRecursively(const char *path); Result GetFreeSpaceSize(s64 *out, const char *path); Result GetTotalSpaceSize(s64 *out, const char *path); Result SetConcatenationFileAttribute(const char *path); Result OpenFile(FileHandle *out, std::unique_ptr<fsa::IFile> &&file, int mode); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_for_debug.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/time/time_posix_time.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ struct FileTimeStamp { time::PosixTime create; time::PosixTime modify; time::PosixTime access; bool is_local_time; char pad[7]; }; static_assert(util::is_pod<FileTimeStamp>::value && sizeof(FileTimeStamp) == 0x20); struct FileTimeStampRaw { s64 create; s64 modify; s64 access; bool is_local_time; char pad[7]; }; static_assert(util::is_pod<FileTimeStampRaw>::value && sizeof(FileTimeStampRaw) == 0x20); static_assert(__builtin_offsetof(FileTimeStampRaw, create) == __builtin_offsetof(FileTimeStampRaw, create)); static_assert(__builtin_offsetof(FileTimeStampRaw, modify) == __builtin_offsetof(FileTimeStampRaw, modify)); static_assert(__builtin_offsetof(FileTimeStampRaw, access) == __builtin_offsetof(FileTimeStampRaw, access)); static_assert(__builtin_offsetof(FileTimeStampRaw, is_local_time) == __builtin_offsetof(FileTimeStampRaw, is_local_time)); static_assert(__builtin_offsetof(FileTimeStampRaw, pad) == __builtin_offsetof(FileTimeStampRaw, pad)); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); #endif namespace impl { Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path); } Result GetFileTimeStamp(FileTimeStamp *out, const char *path); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_filesystem_for_debug.hpp> namespace ams::fs { /* Common utilities. */ Result EnsureDirectory(const char *path); Result EnsureParentDirectory(const char *path); Result HasFile(bool *out, const char *path); Result HasDirectory(bool *out, const char *path); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_game_card.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline size_t GameCardCidSize = 0x10; constexpr inline size_t GameCardDeviceIdSize = 0x10; enum class GameCardPartition { Update = 0, Normal = 1, Secure = 2, Logo = 3, }; enum class GameCardPartitionRaw { NormalReadable, SecureReadable, RootWriteable, }; enum GameCardAttribute : u8 { GameCardAttribute_AutoBootFlag = (1 << 0), GameCardAttribute_HistoryEraseFlag = (1 << 1), GameCardAttribute_RepairToolFlag = (1 << 2), GameCardAttribute_DifferentRegionCupToTerraDeviceFlag = (1 << 3), GameCardAttribute_DifferentRegionCupToGlobalDeviceFlag = (1 << 4), GameCardAttribute_HasCa10CertificateFlag = (1 << 7), }; enum class GameCardCompatibilityType : u8 { Normal = 0, Terra = 1, }; struct GameCardErrorReportInfo { u16 game_card_crc_error_num; u16 reserved1; u16 asic_crc_error_num; u16 reserved2; u16 refresh_num; u16 reserved3; u16 retry_limit_out_num; u16 timeout_retry_num; u16 asic_reinitialize_failure_detail; u16 insertion_count; u16 removal_count; u16 asic_reinitialize_num; u32 initialize_count; u16 asic_reinitialize_failure_num; u16 awaken_failure_num; u16 reserved4; u16 refresh_succeeded_count; u32 last_read_error_page_address; u32 last_read_error_page_count; u32 awaken_count; u32 read_count_from_insert; u32 read_count_from_awaken; u8 reserved5[8]; }; static_assert(util::is_pod<GameCardErrorReportInfo>::value); static_assert(sizeof(GameCardErrorReportInfo) == 0x40); using GameCardHandle = u32; Result GetGameCardHandle(GameCardHandle *out); Result MountGameCardPartition(const char *name, GameCardHandle handle, GameCardPartition partition); Result GetGameCardCid(void *dst, size_t size); Result GetGameCardDeviceId(void *dst, size_t size); Result GetGameCardErrorReportInfo(GameCardErrorReportInfo *out); bool IsGameCardInserted(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_host.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/fs_code_verification_data.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum MountHostOptionFlag : u32 { MountHostOptionFlag_None = (0 << 0), MountHostOptionFlag_PseudoCaseSensitive = (1 << 0), }; struct MountHostOption { u32 _value; constexpr inline bool HasPseudoCaseSensitiveFlag() const { return _value & MountHostOptionFlag_PseudoCaseSensitive; } static const MountHostOption None; static const MountHostOption PseudoCaseSensitive; }; inline constexpr const MountHostOption MountHostOption::None = {MountHostOptionFlag_None}; inline constexpr const MountHostOption MountHostOption::PseudoCaseSensitive = {MountHostOptionFlag_PseudoCaseSensitive}; inline constexpr bool operator==(const MountHostOption &lhs, const MountHostOption &rhs) { return lhs._value == rhs._value; } inline constexpr bool operator!=(const MountHostOption &lhs, const MountHostOption &rhs) { return !(lhs == rhs); } Result MountHost(const char *name, const char *root_path); Result MountHost(const char *name, const char *root_path, const MountHostOption &option); Result MountHostRoot(); Result MountHostRoot(const MountHostOption &option); void UnmountHostRoot(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_i_buffer_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { class IBufferManager { public: class BufferAttribute { private: s32 m_level; public: constexpr BufferAttribute() : m_level(0) { /* ... */ } constexpr explicit BufferAttribute(s32 l) : m_level(l) { /* ... */ } constexpr s32 GetLevel() const { return m_level; } }; using CacheHandle = u64; static constexpr s32 BufferLevelMin = 0; using MemoryRange = std::pair<uintptr_t, size_t>; static constexpr ALWAYS_INLINE MemoryRange MakeMemoryRange(uintptr_t address, size_t size) { return MemoryRange(address, size); } public: virtual ~IBufferManager() { /* ... */ } ALWAYS_INLINE const MemoryRange AllocateBuffer(size_t size, const BufferAttribute &attr) { return this->DoAllocateBuffer(size, attr); } ALWAYS_INLINE const MemoryRange AllocateBuffer(size_t size) { return this->DoAllocateBuffer(size, BufferAttribute()); } ALWAYS_INLINE void DeallocateBuffer(uintptr_t address, size_t size) { return this->DoDeallocateBuffer(address, size); } ALWAYS_INLINE void DeallocateBuffer(const MemoryRange &memory_range) { return this->DoDeallocateBuffer(memory_range.first, memory_range.second); } ALWAYS_INLINE CacheHandle RegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) { return this->DoRegisterCache(address, size, attr); } ALWAYS_INLINE CacheHandle RegisterCache(const MemoryRange &memory_range, const BufferAttribute &attr) { return this->DoRegisterCache(memory_range.first, memory_range.second, attr); } ALWAYS_INLINE const std::pair<uintptr_t, size_t> AcquireCache(CacheHandle handle) { return this->DoAcquireCache(handle); } ALWAYS_INLINE size_t GetTotalSize() const { return this->DoGetTotalSize(); } ALWAYS_INLINE size_t GetFreeSize() const { return this->DoGetFreeSize(); } ALWAYS_INLINE size_t GetTotalAllocatableSize() const { return this->DoGetTotalAllocatableSize(); } ALWAYS_INLINE size_t GetFreeSizePeak() const { return this->DoGetFreeSizePeak(); } ALWAYS_INLINE size_t GetTotalAllocatableSizePeak() const { return this->DoGetTotalAllocatableSizePeak(); } ALWAYS_INLINE size_t GetRetriedCount() const { return this->DoGetRetriedCount(); } ALWAYS_INLINE void ClearPeak() { return this->DoClearPeak(); } protected: virtual const MemoryRange DoAllocateBuffer(size_t size, const BufferAttribute &attr) = 0; virtual void DoDeallocateBuffer(uintptr_t address, size_t size) = 0; virtual CacheHandle DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) = 0; virtual const MemoryRange DoAcquireCache(CacheHandle handle) = 0; virtual size_t DoGetTotalSize() const = 0; virtual size_t DoGetFreeSize() const = 0; virtual size_t DoGetTotalAllocatableSize() const = 0; virtual size_t DoGetFreeSizePeak() const = 0; virtual size_t DoGetTotalAllocatableSizePeak() const = 0; virtual size_t DoGetRetriedCount() const = 0; virtual void DoClearPeak() = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_i_event_notifier.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class IEventNotifier { public: virtual ~IEventNotifier() { /* ... */ } Result BindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) { AMS_ASSERT(out != nullptr); R_RETURN(this->DoBindEvent(out, clear_mode)); } private: virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_image_directory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum class ImageDirectoryId { Nand = 0, SdCard = 1, }; Result MountImageDirectory(const char *name, ImageDirectoryId id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_operate_range.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IStorage { public: virtual ~IStorage() { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) = 0; virtual Result Write(s64 offset, const void *buffer, size_t size) = 0; virtual Result Flush() = 0; virtual Result SetSize(s64 size) = 0; virtual Result GetSize(s64 *out) = 0; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0; virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) { R_RETURN(this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0)); } public: static inline Result CheckAccessRange(s64 offset, s64 size, s64 total_size) { R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); R_UNLESS(offset + size <= total_size, fs::ResultOutOfRange()); R_SUCCEED(); } static ALWAYS_INLINE Result CheckAccessRange(s64 offset, size_t size, s64 total_size) { R_RETURN(CheckAccessRange(offset, static_cast<s64>(size), total_size)); } static inline Result CheckOffsetAndSize(s64 offset, s64 size) { R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); R_SUCCEED(); } static ALWAYS_INLINE Result CheckOffsetAndSize(s64 offset, size_t size) { R_RETURN(CheckOffsetAndSize(offset, static_cast<s64>(size))); } static inline Result CheckOffsetAndSizeWithResult(s64 offset, s64 size, Result fail_result) { R_TRY_CATCH(CheckOffsetAndSize(offset, size)) { R_CONVERT_ALL(fail_result); } R_END_TRY_CATCH; R_SUCCEED(); } static ALWAYS_INLINE Result CheckOffsetAndSizeWithResult(s64 offset, size_t size, Result fail_result) { R_RETURN(CheckOffsetAndSizeWithResult(offset, static_cast<s64>(size), fail_result)); } }; class ReadOnlyStorageAdapter : public IStorage { private: std::shared_ptr<IStorage> m_shared_storage; std::unique_ptr<IStorage> m_unique_storage; IStorage *m_storage; public: explicit ReadOnlyStorageAdapter(IStorage *s) : m_unique_storage(s) { m_storage = m_unique_storage.get(); } explicit ReadOnlyStorageAdapter(std::shared_ptr<IStorage> s) : m_shared_storage(s) { m_storage = m_shared_storage.get(); } explicit ReadOnlyStorageAdapter(std::unique_ptr<IStorage> s) : m_unique_storage(std::move(s)) { m_storage = m_unique_storage.get(); } virtual ~ReadOnlyStorageAdapter() { /* ... */ } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(m_storage->Read(offset, buffer, size)); } virtual Result Flush() override { R_RETURN(m_storage->Flush()); } virtual Result GetSize(s64 *out) override { R_RETURN(m_storage->GetSize(out)); } virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { R_RETURN(m_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* TODO: Better result? Is it possible to get a more specific one? */ AMS_UNUSED(offset, buffer, size); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result SetSize(s64 size) override { /* TODO: Better result? Is it possible to get a more specific one? */ AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedOperation()); } }; template<typename T> concept PointerToStorage = ::ams::util::RawOrSmartPointerTo<T, ::ams::fs::IStorage>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_memory_management.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ using AllocateFunction = void *(*)(size_t); using DeallocateFunction = void (*)(void *, size_t); void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator); namespace impl { class Newable; void *Allocate(size_t size); void Deallocate(void *ptr, size_t size); void LockAllocatorMutex(); void UnlockAllocatorMutex(); void *AllocateUnsafe(size_t size); void DeallocateUnsafe(void *ptr, size_t size); class AllocatorImpl { public: static ALWAYS_INLINE void *Allocate(size_t size) { return ::ams::fs::impl::Allocate(size); } static ALWAYS_INLINE void *AllocateUnsafe(size_t size) { return ::ams::fs::impl::AllocateUnsafe(size); } static ALWAYS_INLINE void Deallocate(void *ptr, size_t size) { return ::ams::fs::impl::Deallocate(ptr, size); } static ALWAYS_INLINE void DeallocateUnsafe(void *ptr, size_t size) { return ::ams::fs::impl::DeallocateUnsafe(ptr, size); } static ALWAYS_INLINE void LockAllocatorMutex() { return ::ams::fs::impl::LockAllocatorMutex(); } static ALWAYS_INLINE void UnlockAllocatorMutex() { return ::ams::fs::impl::UnlockAllocatorMutex(); } }; template<typename T, typename Impl, bool AllocateWhileLocked> class AllocatorTemplate : public std::allocator<T> { public: template<typename U> struct rebind { using other = AllocatorTemplate<U, Impl, AllocateWhileLocked>; }; private: bool m_allocation_failed; private: static ALWAYS_INLINE T *AllocateImpl(::std::size_t n) { if constexpr (AllocateWhileLocked) { auto * const p = Impl::AllocateUnsafe(sizeof(T) * n); Impl::UnlockAllocatorMutex(); return static_cast<T *>(p); } else { return static_cast<T *>(Impl::Allocate(sizeof(T) * n)); } } public: AllocatorTemplate() : m_allocation_failed(false) { /* ... */ } template<typename U> AllocatorTemplate(const AllocatorTemplate<U, Impl, AllocateWhileLocked> &rhs) : m_allocation_failed(rhs.IsAllocationFailed()) { /* ... */ } bool IsAllocationFailed() const { return m_allocation_failed; } [[nodiscard]] T *allocate(::std::size_t n) { auto * const p = AllocateImpl(n); if (AMS_UNLIKELY(p == nullptr) && n) { m_allocation_failed = true; } return p; } void deallocate(T *p, ::std::size_t n) { Impl::Deallocate(p, sizeof(T) * n); } }; template<typename T, typename Impl> using AllocatorTemplateForAllocateShared = AllocatorTemplate<T, Impl, true>; template<typename T, template<typename, typename> class AllocatorTemplateT, typename Impl, typename... Args> std::shared_ptr<T> AllocateSharedImpl(Args &&... args) { /* Try to allocate. */ { /* Acquire exclusive access to the allocator. */ Impl::LockAllocatorMutex(); /* Check that we can allocate memory (using overestimate of 0x80 + sizeof(T)). */ if (auto * const p = Impl::AllocateUnsafe(0x80 + sizeof(T)); AMS_LIKELY(p != nullptr)) { /* Free the memory we allocated. */ Impl::DeallocateUnsafe(p, 0x80 + sizeof(T)); /* Get allocator type. */ using AllocatorType = AllocatorTemplateT<T, Impl>; /* Allocate the shared pointer. */ return std::allocate_shared<T>(AllocatorType{}, std::forward<Args>(args)...); } else { /* We can't allocate. */ Impl::UnlockAllocatorMutex(); } } /* We failed. */ return nullptr; } class Deleter { private: size_t m_size; public: Deleter() : m_size() { /* ... */ } explicit Deleter(size_t sz) : m_size(sz) { /* ... */ } void operator()(void *ptr) const { ::ams::fs::impl::Deallocate(ptr, m_size); } }; template<typename T> auto MakeUnique() { /* Check that we're not using MakeUnique unnecessarily. */ static_assert(!std::derived_from<T, ::ams::fs::impl::Newable>); return std::unique_ptr<T, Deleter>(static_cast<T *>(::ams::fs::impl::Allocate(sizeof(T))), Deleter(sizeof(T))); } template<typename ArrayT> auto MakeUnique(size_t size) { using T = typename std::remove_extent<ArrayT>::type; static_assert(util::is_pod<ArrayT>::value); static_assert(std::is_array<ArrayT>::value); /* Check that we're not using MakeUnique unnecessarily. */ static_assert(!std::derived_from<T, ::ams::fs::impl::Newable>); using ReturnType = std::unique_ptr<ArrayT, Deleter>; const size_t alloc_size = sizeof(T) * size; return ReturnType(static_cast<T *>(::ams::fs::impl::Allocate(alloc_size)), Deleter(alloc_size)); } } template<typename T, typename... Args> std::shared_ptr<T> AllocateShared(Args &&... args) { return ::ams::fs::impl::AllocateSharedImpl<T, ::ams::fs::impl::AllocatorTemplateForAllocateShared, ::ams::fs::impl::AllocatorImpl>(std::forward<Args>(args)...); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_memory_report_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { struct MemoryReportInfo { u64 pooled_buffer_peak_free_size; u64 pooled_buffer_retried_count; u64 pooled_buffer_reduce_allocation_count; u64 buffer_manager_peak_free_size; u64 buffer_manager_retried_count; u64 exp_heap_peak_free_size; u64 buffer_pool_peak_free_size; u64 patrol_read_allocate_buffer_success_count; u64 patrol_read_allocate_buffer_failure_count; u64 buffer_manager_peak_total_allocatable_size; u64 buffer_pool_max_allocate_size; u64 pooled_buffer_failed_ideal_allocation_count_on_async_access; u8 reserved[0x20]; }; static_assert(sizeof(MemoryReportInfo) == 0x80); static_assert(util::is_pod<MemoryReportInfo>::value); Result GetAndClearMemoryReportInfo(MemoryReportInfo *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_query_range.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class MemoryStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { private: u8 * const m_buf; const s64 m_size; public: MemoryStorage(void *b, s64 sz) : m_buf(static_cast<u8 *>(b)), m_size(sz) { /* .. */ } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Succeed immediately on zero-sized read. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); /* Copy from memory. */ std::memcpy(buffer, m_buf + offset, size); R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* Succeed immediately on zero-sized write. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); /* Copy to memory. */ std::memcpy(m_buf + offset, buffer, size); R_SUCCEED(); } virtual Result Flush() override { R_SUCCEED(); } virtual Result GetSize(s64 *out) override { *out = m_size; R_SUCCEED(); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForMemoryStorage()); } virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { AMS_UNUSED(offset, size, src, src_size); switch (op_id) { case OperationId::Invalidate: R_SUCCEED(); case OperationId::QueryRange: R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); reinterpret_cast<QueryRangeInfo *>(dst)->Clear(); R_SUCCEED(); default: R_THROW(fs::ResultUnsupportedOperateRangeForMemoryStorage()); } } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_mmc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { constexpr inline size_t MmcCidSize = 0x10; constexpr inline size_t MmcExtendedCsdSize = 0x200; constexpr inline int MmcExtendedCsdOffsetReEolInfo = 267; constexpr inline int MmcExtendedCsdOffsetDeviceLifeTimeEstTypA = 268; constexpr inline int MmcExtendedCsdOffsetDeviceLifeTimeEstTypB = 269; enum MmcSpeedMode { MmcSpeedMode_Identification = 0, MmcSpeedMode_LegacySpeed = 1, MmcSpeedMode_HighSpeed = 2, MmcSpeedMode_Hs200 = 3, MmcSpeedMode_Hs400 = 4, MmcSpeedMode_Unknown = 5, }; enum class MmcPartition { UserData = 0, BootPartition1 = 1, BootPartition2 = 2, }; Result GetMmcCid(void *dst, size_t size); inline void ClearMmcCidSerialNumber(u8 *cid) { /* Clear the serial number from the cid. */ std::memset(cid + 1, 0, 4); } Result GetMmcSpeedMode(MmcSpeedMode *out); Result GetMmcPatrolCount(u32 *out); Result GetMmcExtendedCsd(void *dst, size_t size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_mount.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline size_t MountNameLengthMax = 15; Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src); void Unmount(const char *mount_name); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_operate_range.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum class OperationId : s64 { FillZero = 0, DestroySignature = 1, Invalidate = 2, QueryRange = 3, QueryUnpreparedRange = 4, QueryLazyLoadCompletionRate = 5, SetLazyLoadPriority = 6, ReadLazyLoadFileForciblyForDebug = 10001, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_memory_management.hpp> #include <stratosphere/fs/impl/fs_common_mount_name.hpp> #include <stratosphere/fs/fs_path_utility.hpp> namespace ams::fs { class DirectoryPathParser; /* ACCURATE_TO_VERSION: 13.4.0.0 */ /* NOTE: Intentional inaccuracy in custom WriteBuffer class, to save 0x10 bytes (0x28 -> 0x18) over Nintendo's implementation. */ class Path { NON_COPYABLE(Path); NON_MOVEABLE(Path); private: static constexpr const char *EmptyPath = ""; static constexpr size_t WriteBufferAlignmentLength = 8; private: friend class DirectoryPathParser; public: class WriteBuffer { NON_COPYABLE(WriteBuffer); private: char *m_buffer; size_t m_length_and_is_normalized; public: constexpr WriteBuffer() : m_buffer(nullptr), m_length_and_is_normalized(0) { /* ... */ } constexpr ~WriteBuffer() { if (m_buffer != nullptr) { ::ams::fs::impl::Deallocate(m_buffer, this->GetLength()); this->ResetBuffer(); } } constexpr WriteBuffer(WriteBuffer &&rhs) : m_buffer(rhs.m_buffer), m_length_and_is_normalized(rhs.m_length_and_is_normalized) { rhs.ResetBuffer(); } constexpr WriteBuffer &operator=(WriteBuffer &&rhs) { if (m_buffer != nullptr) { ::ams::fs::impl::Deallocate(m_buffer, this->GetLength()); } m_buffer = rhs.m_buffer; m_length_and_is_normalized = rhs.m_length_and_is_normalized; rhs.ResetBuffer(); return *this; } std::unique_ptr<char[], ::ams::fs::impl::Deleter> ReleaseBuffer() { auto released = std::unique_ptr<char[], ::ams::fs::impl::Deleter>(m_buffer, ::ams::fs::impl::Deleter(this->GetLength())); this->ResetBuffer(); return released; } constexpr ALWAYS_INLINE void ResetBuffer() { m_buffer = nullptr; this->SetLength(0); } constexpr ALWAYS_INLINE char *Get() const { return m_buffer; } constexpr ALWAYS_INLINE size_t GetLength() const { return m_length_and_is_normalized >> 1; } constexpr ALWAYS_INLINE bool IsNormalized() const { return static_cast<bool>(m_length_and_is_normalized & 1); } constexpr ALWAYS_INLINE void SetNormalized() { m_length_and_is_normalized |= static_cast<size_t>(1); } constexpr ALWAYS_INLINE void SetNotNormalized() { m_length_and_is_normalized &= ~static_cast<size_t>(1); } private: constexpr ALWAYS_INLINE WriteBuffer(char *buffer, size_t length) : m_buffer(buffer), m_length_and_is_normalized(0) { this->SetLength(length); } public: static WriteBuffer Make(size_t length) { if (void *alloc = ::ams::fs::impl::Allocate(length); alloc != nullptr) { return WriteBuffer(static_cast<char *>(alloc), length); } else { return WriteBuffer(); } } private: constexpr ALWAYS_INLINE void SetLength(size_t size) { m_length_and_is_normalized = (m_length_and_is_normalized & 1) | (size << 1); } }; private: const char *m_str; WriteBuffer m_write_buffer; public: constexpr Path() : m_str(EmptyPath), m_write_buffer() { /* ... */ } constexpr Path(const char *s, util::ConstantInitializeTag) : m_str(s), m_write_buffer() { m_write_buffer.SetNormalized(); } constexpr ~Path() { /* ... */ } std::unique_ptr<char[], ::ams::fs::impl::Deleter> ReleaseBuffer() { /* Check pre-conditions. */ AMS_ASSERT(m_write_buffer.Get() != nullptr); /* Reset. */ m_str = EmptyPath; /* Release our write buffer. */ return m_write_buffer.ReleaseBuffer(); } constexpr Result SetShallowBuffer(const char *buffer) { /* Check pre-conditions. */ AMS_ASSERT(m_write_buffer.GetLength() == 0); /* Check the buffer is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Set buffer. */ this->SetReadOnlyBuffer(buffer); /* Note that we're normalized. */ this->SetNormalized(); R_SUCCEED(); } constexpr const char *GetString() const { /* Check pre-conditions. */ AMS_ASSERT(this->IsNormalized()); return m_str; } constexpr size_t GetLength() const { if (std::is_constant_evaluated()) { return util::Strlen(this->GetString()); } else { return std::strlen(this->GetString()); } } constexpr bool IsEmpty() const { return *m_str == '\x00'; } constexpr bool IsMatchHead(const char *p, size_t len) const { return util::Strncmp(this->GetString(), p, len) == 0; } Result Initialize(const Path &rhs) { /* Check the other path is normalized. */ const bool normalized = rhs.IsNormalized(); R_UNLESS(normalized, fs::ResultNotNormalized()); /* Allocate buffer for our path. */ const auto len = rhs.GetLength(); R_TRY(this->Preallocate(len + 1)); /* Copy the path. */ const size_t copied = util::Strlcpy<char>(m_write_buffer.Get(), rhs.GetString(), len + 1); R_UNLESS(copied == len, fs::ResultUnexpectedInPathA()); /* Set normalized. */ this->SetNormalized(); R_SUCCEED(); } Result Initialize(const char *path, size_t len) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Initialize. */ R_TRY(this->InitializeImpl(path, len)); /* Set not normalized. */ this->SetNotNormalized(); R_SUCCEED(); } Result Initialize(const char *path) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->Initialize(path, std::strlen(path))); } Result InitializeWithFormat(const char *fmt, ...) __attribute__((format (printf, 2, 3))) { /* Check the format string is valid. */ R_UNLESS(fmt != nullptr, fs::ResultNullptrArgument()); /* Create the va_list for formatting. */ std::va_list vl; va_start(vl, fmt); /* Determine how big the string will be. */ char dummy; const auto len = util::VSNPrintf(std::addressof(dummy), 0, fmt, vl); /* Allocate buffer for our path. */ R_TRY(this->Preallocate(len + 1)); /* Format our path into our new buffer. */ const auto real_len = util::VSNPrintf(m_write_buffer.Get(), m_write_buffer.GetLength(), fmt, vl); AMS_ASSERT(real_len == len); AMS_UNUSED(real_len); /* Finish the va_list. */ va_end(vl); /* Set not normalized. */ this->SetNotNormalized(); R_SUCCEED(); } Result InitializeWithReplaceBackslash(const char *path) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Initialize. */ R_TRY(this->InitializeImpl(path, std::strlen(path))); /* Replace slashes as desired. */ if (const auto write_buffer_length = m_write_buffer.GetLength(); write_buffer_length > 1) { fs::Replace(m_write_buffer.Get(), write_buffer_length - 1, '\\', '/'); } /* Set not normalized. */ this->SetNotNormalized(); R_SUCCEED(); } Result InitializeWithReplaceForwardSlashes(const char *path) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Initialize. */ R_TRY(this->InitializeImpl(path, std::strlen(path))); /* Replace slashes as desired. */ if (m_write_buffer.GetLength() > 1) { if (auto *p = m_write_buffer.Get(); p[0] == '/' && p[1] == '/') { p[0] = '\\'; p[1] = '\\'; } } /* Set not normalized. */ this->SetNotNormalized(); R_SUCCEED(); } Result InitializeWithReplaceUnc(const char *path) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Initialize. */ R_TRY(this->InitializeImpl(path, std::strlen(path))); /* Set not normalized. */ this->SetNotNormalized(); /* Replace unc as desired. */ if (m_str[0]) { auto *p = m_write_buffer.Get(); /* Replace :/// -> \\ as needed. */ if (auto *sep = std::strstr(p, ":///"); sep != nullptr) { sep[0] = '\\'; sep[1] = '\\'; } /* Edit path prefix. */ if (!util::Strncmp(p, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER "/", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN + 1)) { static_assert((AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER)[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] == '/'); p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] = '\\'; p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 0] = '\\'; } if (p[0] == '/' && p[1] == '/') { p[0] = '\\'; p[1] = '\\'; } } R_SUCCEED(); } Result InitializeWithNormalization(const char *path, size_t size) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Initialize. */ R_TRY(this->InitializeImpl(path, size)); /* Set not normalized. */ this->SetNotNormalized(); /* Perform normalization. */ fs::PathFlags path_flags; if (fs::IsPathRelative(m_str)) { path_flags.AllowRelativePath(); } else if (fs::IsWindowsPath(m_str, true)) { path_flags.AllowWindowsPath(); } else { /* NOTE: In this case, Nintendo checks is normalized, then sets is normalized, then returns success. */ /* This seems like a bug. */ size_t dummy; bool normalized; R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str)); this->SetNormalized(); R_SUCCEED(); } /* Normalize. */ R_TRY(this->Normalize(path_flags)); this->SetNormalized(); R_SUCCEED(); } Result InitializeWithNormalization(const char *path) { /* Check the path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->InitializeWithNormalization(path, std::strlen(path))); } Result InitializeAsEmpty() { /* Clear our buffer. */ this->ClearBuffer(); /* Set normalized. */ this->SetNormalized(); R_SUCCEED(); } Result AppendChild(const char *child) { /* Check the path is valid. */ R_UNLESS(child != nullptr, fs::ResultNullptrArgument()); /* Basic checks. If we hvea a path and the child is empty, we have nothing to do. */ const char *c = child; if (m_str[0]) { /* Skip an early separator. */ if (*c == '/') { ++c; } R_SUCCEED_IF(*c == '\x00'); } /* If we don't have a string, we can just initialize. */ auto cur_len = std::strlen(m_str); if (cur_len == 0) { R_RETURN(this->Initialize(child)); } /* Remove a trailing separator. */ if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') { --cur_len; } /* Get the child path's length. */ auto child_len = std::strlen(c); /* Reset our write buffer. */ WriteBuffer old_write_buffer; if (m_write_buffer.Get() != nullptr) { old_write_buffer = std::move(m_write_buffer); this->ClearBuffer(); } /* Pre-allocate the new buffer. */ R_TRY(this->Preallocate(cur_len + 1 + child_len + 1)); /* Get our write buffer. */ auto *dst = m_write_buffer.Get(); if (old_write_buffer.Get() != nullptr && cur_len > 0) { util::Strlcpy<char>(dst, old_write_buffer.Get(), cur_len + 1); } /* Add separator. */ dst[cur_len] = '/'; /* Copy the child path. */ const size_t copied = util::Strlcpy<char>(dst + cur_len + 1, c, child_len + 1); R_UNLESS(copied == child_len, fs::ResultUnexpectedInPathA()); R_SUCCEED(); } Result AppendChild(const Path &rhs) { R_RETURN(this->AppendChild(rhs.GetString())); } Result Combine(const Path &parent, const Path &child) { /* Get the lengths. */ const auto p_len = parent.GetLength(); const auto c_len = child.GetLength(); /* Allocate our buffer. */ R_TRY(this->Preallocate(p_len + c_len + 1)); /* Initialize as parent. */ R_TRY(this->Initialize(parent)); /* If we're empty, we can just initialize as child. */ if (this->IsEmpty()) { R_TRY(this->Initialize(child)); } else { /* Otherwise, we should append the child. */ R_TRY(this->AppendChild(child)); } R_SUCCEED(); } Result RemoveChild() { /* If we don't have a write-buffer, ensure that we have one. */ if (m_write_buffer.Get() == nullptr) { if (const auto len = std::strlen(m_str); len > 0) { R_TRY(this->Preallocate(len)); util::Strlcpy<char>(m_write_buffer.Get(), m_str, len + 1); } } /* Check that it's possible for us to remove a child. */ auto *p = m_write_buffer.Get(); s32 len = std::strlen(p); R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), fs::ResultNotImplemented()); /* Handle a trailing separator. */ if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) { --len; } /* Remove the child path segment. */ while ((--len) >= 0 && p[len]) { if (p[len] == '/' || p[len] == '\\') { if (len > 0) { p[len] = 0; } else { p[1] = 0; len = 1; } break; } } /* Check that length remains > 0. */ R_UNLESS(len > 0, fs::ResultNotImplemented()); R_SUCCEED(); } Result Normalize(const PathFlags &flags) { /* If we're already normalized, nothing to do. */ R_SUCCEED_IF(this->IsNormalized()); /* Check if we're normalized. */ bool normalized; size_t dummy; R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str, flags)); /* If we're not normalized, normalize. */ if (!normalized) { /* Determine necessary buffer length. */ auto len = m_write_buffer.GetLength(); if (flags.IsRelativePathAllowed() && fs::IsPathRelative(m_str)) { len += 2; } if (flags.IsWindowsPathAllowed() && fs::IsWindowsPath(m_str, true)) { len += 1; } /* Allocate a new buffer. */ const size_t size = util::AlignUp(len, WriteBufferAlignmentLength); auto buf = WriteBuffer::Make(size); R_UNLESS(buf.Get() != nullptr, fs::ResultAllocationMemoryFailedMakeUnique()); /* Normalize into it. */ R_TRY(PathFormatter::Normalize(buf.Get(), size, m_write_buffer.Get(), m_write_buffer.GetLength(), flags)); /* Set the normalized buffer as our buffer. */ this->SetModifiableBuffer(std::move(buf)); } /* Set normalized. */ this->SetNormalized(); R_SUCCEED(); } private: void ClearBuffer() { m_write_buffer.ResetBuffer(); m_str = EmptyPath; } void SetModifiableBuffer(WriteBuffer &&buffer) { /* Check pre-conditions. */ AMS_ASSERT(buffer.Get() != nullptr); AMS_ASSERT(buffer.GetLength() > 0); AMS_ASSERT(util::IsAligned(buffer.GetLength(), WriteBufferAlignmentLength)); /* Get whether we're normalized. */ if (m_write_buffer.IsNormalized()) { buffer.SetNormalized(); } else { buffer.SetNotNormalized(); } /* Set write buffer. */ m_write_buffer = std::move(buffer); m_str = m_write_buffer.Get(); } constexpr void SetReadOnlyBuffer(const char *buffer) { m_str = buffer; m_write_buffer.ResetBuffer(); } Result Preallocate(size_t length) { /* Allocate additional space, if needed. */ if (length > m_write_buffer.GetLength()) { /* Allocate buffer. */ const size_t size = util::AlignUp(length, WriteBufferAlignmentLength); auto buf = WriteBuffer::Make(size); R_UNLESS(buf.Get() != nullptr, fs::ResultAllocationMemoryFailedMakeUnique()); /* Set write buffer. */ this->SetModifiableBuffer(std::move(buf)); } R_SUCCEED(); } Result InitializeImpl(const char *path, size_t size) { if (size > 0 && path[0]) { /* Pre allocate a buffer for the path. */ R_TRY(this->Preallocate(size + 1)); /* Copy the path. */ const size_t copied = util::Strlcpy<char>(m_write_buffer.Get(), path, size + 1); R_UNLESS(copied >= size, fs::ResultUnexpectedInPathA()); } else { /* We can just clear the buffer. */ this->ClearBuffer(); } R_SUCCEED(); } constexpr char *GetWriteBuffer() { AMS_ASSERT(m_write_buffer.Get() != nullptr); return m_write_buffer.Get(); } constexpr ALWAYS_INLINE size_t GetWriteBufferLength() const { return m_write_buffer.GetLength(); } constexpr ALWAYS_INLINE bool IsNormalized() const { return m_write_buffer.IsNormalized(); } constexpr ALWAYS_INLINE void SetNormalized() { m_write_buffer.SetNormalized(); } constexpr ALWAYS_INLINE void SetNotNormalized() { m_write_buffer.SetNotNormalized(); } public: ALWAYS_INLINE bool operator==(const fs::Path &rhs) const { return std::strcmp(this->GetString(), rhs.GetString()) == 0; } ALWAYS_INLINE bool operator!=(const fs::Path &rhs) const { return !(*this == rhs); } ALWAYS_INLINE bool operator==(const char *p) const { return std::strcmp(this->GetString(), p) == 0; } ALWAYS_INLINE bool operator!=(const char *p) const { return !(*this == p); } }; consteval fs::Path MakeConstantPath(const char *s) { return fs::Path(s, util::ConstantInitializeTag{}); } inline Result SetUpFixedPath(fs::Path *out, const char *s) { /* Verify the path is normalized. */ bool normalized; size_t dummy; R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s)); R_UNLESS(normalized, fs::ResultInvalidPathFormat()); /* Set the fixed path. */ R_RETURN(out->SetShallowBuffer(s)); } inline Result SetUpFixedPathSingleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e) { /* Print the path into the buffer. */ const size_t len = util::TSNPrintf(buf, buf_size, "/%s", e); R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); /* Set up the path. */ R_RETURN(SetUpFixedPath(out, buf)); } inline Result SetUpFixedPathDoubleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e, const char *e2) { /* Print the path into the buffer. */ const size_t len = util::TSNPrintf(buf, buf_size, "/%s/%s", e, e2); R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); /* Set up the path. */ R_RETURN(SetUpFixedPath(out, buf)); } inline Result SetUpFixedPathSaveId(fs::Path *out, char *buf, size_t buf_size, u64 id) { /* Print the path into the buffer. */ const size_t len = util::TSNPrintf(buf, buf_size, "/%016" PRIx64 "", id); R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); /* Set up the path. */ R_RETURN(SetUpFixedPath(out, buf)); } inline Result SetUpFixedPathSaveMetaName(fs::Path *out, char *buf, size_t buf_size, u32 type) { /* Print the path into the buffer. */ const size_t len = util::TSNPrintf(buf, buf_size, "/%08" PRIx32 ".meta", type); R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); /* Set up the path. */ R_RETURN(SetUpFixedPath(out, buf)); } inline Result SetUpFixedPathSaveMetaDir(fs::Path *out, char *buf, size_t buf_size, u64 id) { /* Print the path into the buffer. */ const size_t len = util::TSNPrintf(buf, buf_size, "/saveMeta/%016" PRIx64 "", id); R_UNLESS(len < buf_size, fs::ResultInvalidArgument()); /* Set up the path. */ R_RETURN(SetUpFixedPath(out, buf)); } constexpr inline bool IsWindowsDriveRootPath(const fs::Path &path) { const char * const str = path.GetString(); return fs::IsWindowsDrive(str) && (str[2] == StringTraits::DirectorySeparator || str[2] == StringTraits::AlternateDirectorySeparator) && str[3] == StringTraits::NullTerminator; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_path_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_path.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 13.4.0.0 */ namespace StringTraits { constexpr inline char DirectorySeparator = '/'; constexpr inline char DriveSeparator = ':'; constexpr inline char Dot = '.'; constexpr inline char NullTerminator = '\x00'; constexpr inline char AlternateDirectorySeparator = '\\'; constexpr inline const char InvalidCharacters[6] = { ':', '*', '?', '<', '>', '|' }; constexpr inline const char InvalidCharactersForHostName[6] = { ':', '*', '<', '>', '|', '$' }; constexpr inline const char InvalidCharactersForMountName[5] = { '*', '?', '<', '>', '|' }; namespace impl { template<const char *InvalidCharacterSet, size_t NumInvalidCharacters> consteval u64 MakeInvalidCharacterMask(size_t n) { u64 mask = 0; for (size_t i = 0; i < NumInvalidCharacters; ++i) { if ((static_cast<u64>(InvalidCharacterSet[i]) >> 6) == n) { mask |= static_cast<u64>(1) << (static_cast<u64>(InvalidCharacterSet[i]) & 0x3F); } } return mask; } template<const char *InvalidCharacterSet, size_t NumInvalidCharacters> constexpr ALWAYS_INLINE bool IsInvalidCharacterImpl(char c) { constexpr u64 Masks[4] = { MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(0), MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(1), MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(2), MakeInvalidCharacterMask<InvalidCharacterSet, NumInvalidCharacters>(3) }; return (Masks[static_cast<u64>(c) >> 6] & (static_cast<u64>(1) << (static_cast<u64>(c) & 0x3F))) != 0; } } constexpr ALWAYS_INLINE bool IsInvalidCharacter(char c) { return impl::IsInvalidCharacterImpl<InvalidCharacters, util::size(InvalidCharacters)>(c); } constexpr ALWAYS_INLINE bool IsInvalidCharacterForHostName(char c) { return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName, util::size(InvalidCharactersForHostName)>(c); } constexpr ALWAYS_INLINE bool IsInvalidCharacterForMountName(char c) { return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName, util::size(InvalidCharactersForMountName)>(c); } } constexpr inline size_t WindowsDriveLength = 2; constexpr inline size_t UncPathPrefixLength = 2; constexpr inline size_t DosDevicePathPrefixLength = 4; class PathFlags { private: static constexpr u32 WindowsPathFlag = (1 << 0); static constexpr u32 RelativePathFlag = (1 << 1); static constexpr u32 EmptyPathFlag = (1 << 2); static constexpr u32 MountNameFlag = (1 << 3); static constexpr u32 BackslashFlag = (1 << 4); static constexpr u32 AllCharactersFlag = (1 << 5); private: u32 m_value; public: constexpr ALWAYS_INLINE PathFlags() : m_value(0) { /* ... */ } #define DECLARE_PATH_FLAG_HANDLER(__WHICH__) \ constexpr ALWAYS_INLINE bool Is ## __WHICH__ ##Allowed() const { return (m_value & __WHICH__ ## Flag) != 0; } \ constexpr ALWAYS_INLINE void Allow ## __WHICH__ () { m_value |= __WHICH__ ## Flag; } DECLARE_PATH_FLAG_HANDLER(WindowsPath) DECLARE_PATH_FLAG_HANDLER(RelativePath) DECLARE_PATH_FLAG_HANDLER(EmptyPath) DECLARE_PATH_FLAG_HANDLER(MountName) DECLARE_PATH_FLAG_HANDLER(Backslash) DECLARE_PATH_FLAG_HANDLER(AllCharacters) #undef DECLARE_PATH_FLAG_HANDLER }; template<typename T> requires (std::same_as<T, char> || std::same_as<T, wchar_t>) constexpr inline bool IsDosDevicePath(const T *path) { AMS_ASSERT(path != nullptr); using namespace StringTraits; return path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator && (path[2] == Dot || path[2] == '?') && (path[3] == DirectorySeparator || path[3] == AlternateDirectorySeparator); } template<typename T> requires (std::same_as<T, char> || std::same_as<T, wchar_t>) constexpr inline bool IsUncPath(const T *path, bool allow_forward_slash = true, bool allow_back_slash = true) { AMS_ASSERT(path != nullptr); using namespace StringTraits; return (allow_forward_slash && path[0] == DirectorySeparator && path[1] == DirectorySeparator) || (allow_back_slash && path[0] == AlternateDirectorySeparator && path[1] == AlternateDirectorySeparator); } constexpr inline bool IsWindowsDrive(const char *path) { AMS_ASSERT(path != nullptr); return (('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && path[1] == StringTraits::DriveSeparator; } constexpr inline bool IsWindowsPath(const char *path, bool allow_forward_slash_unc) { return IsWindowsDrive(path) || IsDosDevicePath(path) || IsUncPath(path, allow_forward_slash_unc, true); } constexpr inline int GetWindowsSkipLength(const char *path) { if (IsDosDevicePath(path)) { return DosDevicePathPrefixLength; } else if (IsWindowsDrive(path)) { return WindowsDriveLength; } else if (IsUncPath(path)) { return UncPathPrefixLength; } else { return 0; } } constexpr inline bool IsPathAbsolute(const char *path) { return IsWindowsPath(path, false) || path[0] == StringTraits::DirectorySeparator; } constexpr inline bool IsPathRelative(const char *path) { return path[0] && !IsPathAbsolute(path); } constexpr inline bool IsCurrentDirectory(const char *path) { return path[0] == StringTraits::Dot && (path[1] == StringTraits::NullTerminator || path[1] == StringTraits::DirectorySeparator); } constexpr inline bool IsParentDirectory(const char *path) { return path[0] == StringTraits::Dot && path[1] == StringTraits::Dot && (path[2] == StringTraits::NullTerminator || path[2] == StringTraits::DirectorySeparator); } constexpr inline bool IsPathStartWithCurrentDirectory(const char *path) { return IsCurrentDirectory(path) || IsParentDirectory(path); } constexpr inline bool IsSubPath(const char *lhs, const char *rhs) { /* Check pre-conditions. */ AMS_ASSERT(lhs != nullptr); AMS_ASSERT(rhs != nullptr); /* Import StringTraits names for current scope. */ using namespace StringTraits; /* Special case certain paths. */ if (IsUncPath(lhs) && !IsUncPath(rhs)) { return false; } if (!IsUncPath(lhs) && IsUncPath(rhs)) { return false; } if (lhs[0] == DirectorySeparator && lhs[1] == NullTerminator && rhs[0] == DirectorySeparator && rhs[1] != NullTerminator) { return true; } if (rhs[0] == DirectorySeparator && rhs[1] == NullTerminator && lhs[0] == DirectorySeparator && lhs[1] != NullTerminator) { return true; } /* Check subpath. */ for (size_t i = 0; /* ... */; ++i) { if (lhs[i] == NullTerminator) { return rhs[i] == DirectorySeparator; } else if (rhs[i] == NullTerminator) { return lhs[i] == DirectorySeparator; } else if (lhs[i] != rhs[i]) { return false; } } } /* Path utilities. */ constexpr inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) { AMS_ASSERT(dst != nullptr); for (char *cur = dst; cur < dst + dst_size && *cur; ++cur) { if (*cur == old_char) { *cur = new_char; } } } constexpr inline Result CheckUtf8(const char *s) { /* Check pre-conditions. */ AMS_ASSERT(s != nullptr); /* Iterate, checking for utf8-validity. */ while (*s) { char utf8_buf[4] = {}; const auto pick_res = util::PickOutCharacterFromUtf8String(utf8_buf, std::addressof(s)); R_UNLESS(pick_res == util::CharacterEncodingResult_Success, fs::ResultInvalidPathFormat()); u32 dummy; const auto cvt_res = util::ConvertCharacterUtf8ToUtf32(std::addressof(dummy), utf8_buf); R_UNLESS(cvt_res == util::CharacterEncodingResult_Success, fs::ResultInvalidPathFormat()); } R_SUCCEED(); } /* Path formatting. */ class PathNormalizer { private: enum class PathState { Start, Normal, FirstSeparator, Separator, CurrentDir, ParentDir, }; private: static constexpr void ReplaceParentDirectoryPath(char *dst, const char *src) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Start with a dir-separator. */ dst[0] = DirectorySeparator; auto i = 1; while (src[i] != NullTerminator) { if ((src[i - 1] == DirectorySeparator || src[i - 1] == AlternateDirectorySeparator) && src[i + 0] == Dot && src[i + 1] == Dot && (src[i + 2] == DirectorySeparator || src[i + 2] == AlternateDirectorySeparator)) { dst[i - 1] = DirectorySeparator; dst[i + 0] = Dot; dst[i + 1] = Dot; dst[i + 2] = DirectorySeparator; i += 3; } else { if (src[i - 1] == AlternateDirectorySeparator && src[i + 0] == Dot && src[i + 1] == Dot && src[i + 2] == NullTerminator) { dst[i - 1] = DirectorySeparator; dst[i + 0] = Dot; dst[i + 1] = Dot; i += 2; break; } dst[i] = src[i]; ++i; } } dst[i] = StringTraits::NullTerminator; } public: static constexpr bool IsParentDirectoryPathReplacementNeeded(const char *path) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; if (path[0] != DirectorySeparator && path[0] != AlternateDirectorySeparator) { return false; } /* Check to find a parent reference using alternate separators. */ if (path[0] != NullTerminator && path[1] != NullTerminator && path[2] != NullTerminator) { size_t i; for (i = 0; path[i + 3] != NullTerminator; ++path) { if (path[i + 1] != Dot || path[i + 2] != Dot) { continue; } const char c0 = path[i + 0]; const char c3 = path[i + 3]; if (c0 == AlternateDirectorySeparator && (c3 == DirectorySeparator || c3 == AlternateDirectorySeparator || c3 == NullTerminator)) { return true; } if (c3 == AlternateDirectorySeparator && (c0 == DirectorySeparator || c0 == AlternateDirectorySeparator)) { return true; } } if (path[i + 0] == AlternateDirectorySeparator && path[i + 1] == Dot && path[i + 2] == Dot /* && path[i + 3] == NullTerminator */) { return true; } } return false; } static constexpr Result IsNormalized(bool *out, size_t *out_len, const char *path, bool allow_all_characters = false) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Parse the path. */ auto state = PathState::Start; size_t len = 0; while (path[len] != NullTerminator) { /* Get the current character. */ const char c = path[len++]; /* Check the current character is valid. */ if (!allow_all_characters && state != PathState::Start) { R_UNLESS(!IsInvalidCharacter(c), fs::ResultInvalidCharacter()); } /* Process depending on current state. */ switch (state) { /* Import the PathState enums for convenience. */ using enum PathState; case Start: R_UNLESS(c == DirectorySeparator, fs::ResultInvalidPathFormat()); state = FirstSeparator; break; case Normal: if (c == DirectorySeparator) { state = Separator; } break; case FirstSeparator: case Separator: if (c == DirectorySeparator) { *out = false; R_SUCCEED(); } if (c == Dot) { state = CurrentDir; } else { state = Normal; } break; case CurrentDir: if (c == DirectorySeparator) { *out = false; R_SUCCEED(); } if (c == Dot) { state = ParentDir; } else { state = Normal; } break; case ParentDir: if (c == DirectorySeparator) { *out = false; R_SUCCEED(); } state = Normal; break; AMS_UNREACHABLE_DEFAULT_CASE(); } } /* Check the final state. */ switch (state) { /* Import the PathState enums for convenience. */ using enum PathState; case Start: R_THROW(fs::ResultInvalidPathFormat()); case Normal: case FirstSeparator: *out = true; break; case Separator: case CurrentDir: case ParentDir: *out = false; break; AMS_UNREACHABLE_DEFAULT_CASE(); } /* Set the output length. */ *out_len = len; R_SUCCEED(); } static constexpr Result Normalize(char *dst, size_t *out_len, const char *path, size_t max_out_size, bool is_windows_path, bool is_drive_relative_path, bool allow_all_characters = false) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Prepare to iterate. */ const char *cur_path = path; size_t total_len = 0; /* If path begins with a separator, check that we're not drive relative. */ if (cur_path[0] != DirectorySeparator) { R_UNLESS(is_drive_relative_path, fs::ResultInvalidPathFormat()); dst[total_len++] = DirectorySeparator; } /* We're going to need to do path replacement, potentially. */ char *replacement_path = nullptr; size_t replacement_path_size = 0; ON_SCOPE_EXIT { if (replacement_path != nullptr) { if (std::is_constant_evaluated()) { delete[] replacement_path; } else { ::ams::fs::impl::Deallocate(replacement_path, replacement_path_size); } } }; /* Perform path replacement, if necessary. */ if (IsParentDirectoryPathReplacementNeeded(cur_path)) { if (std::is_constant_evaluated()) { replacement_path_size = fs::EntryNameLengthMax + 1; replacement_path = new char[replacement_path_size]; } else { replacement_path_size = fs::EntryNameLengthMax + 1; replacement_path = static_cast<char *>(::ams::fs::impl::Allocate(replacement_path_size)); } ReplaceParentDirectoryPath(replacement_path, cur_path); cur_path = replacement_path; } /* Iterate, normalizing path components. */ bool skip_next_sep = false; size_t i = 0; while (cur_path[i] != NullTerminator) { /* Process a directory separator, if we run into one. */ if (cur_path[i] == DirectorySeparator) { /* Swallow separators. */ do { ++i; } while (cur_path[i] == DirectorySeparator); /* Check if we hit end of string. */ if (cur_path[i] == NullTerminator) { break; } /* If we aren't skipping the separator, write it, checking that we remain in bounds. */ if (!skip_next_sep) { if (total_len + 1 == max_out_size) { dst[total_len] = NullTerminator; *out_len = total_len; R_THROW(fs::ResultTooLongPath()); } dst[total_len++] = DirectorySeparator; } /* Don't skip the next separator. */ skip_next_sep = false; } /* Get the length of the current directory component. */ size_t dir_len = 0; while (cur_path[i + dir_len] != DirectorySeparator && cur_path[i + dir_len] != NullTerminator) { /* Check for validity. */ if (!allow_all_characters) { R_UNLESS(!IsInvalidCharacter(cur_path[i + dir_len]), fs::ResultInvalidCharacter()); } ++dir_len; } /* Handle the current dir component. */ if (IsCurrentDirectory(cur_path + i)) { skip_next_sep = true; } else if (IsParentDirectory(cur_path + i)) { /* We should have just written a separator. */ AMS_ASSERT(dst[total_len - 1] == DirectorySeparator); /* We should have started with a separator, for non-windows paths. */ if (!is_windows_path) { AMS_ASSERT(dst[0] == DirectorySeparator); } /* Remove the previous component. */ if (total_len == 1) { R_UNLESS(is_windows_path, fs::ResultDirectoryUnobtainable()); --total_len; } else { total_len -= 2; do { if (dst[total_len] == DirectorySeparator) { break; } } while ((--total_len) != 0); } /* We should be pointing to a directory separator, for non-windows paths. */ if (!is_windows_path) { AMS_ASSERT(dst[total_len] == DirectorySeparator); } /* We should remain in bounds. */ AMS_ASSERT(total_len < max_out_size); } else { /* Copy, possibly truncating. */ if (total_len + dir_len + 1 > max_out_size) { const size_t copy_len = max_out_size - (total_len + 1); for (size_t j = 0; j < copy_len; ++j) { dst[total_len++] = cur_path[i + j]; } dst[total_len] = NullTerminator; *out_len = total_len; R_THROW(fs::ResultTooLongPath()); } for (size_t j = 0; j < dir_len; ++j) { dst[total_len++] = cur_path[i + j]; } } /* Advance past the current directory component. */ i += dir_len; } if (skip_next_sep) { --total_len; } if (total_len == 0 && max_out_size != 0) { total_len = 1; dst[0] = DirectorySeparator; } /* NOTE: Probable nintendo bug, as max_out_size must be at least total_len + 1 for the null terminator. */ R_UNLESS(max_out_size >= total_len - 1, fs::ResultTooLongPath()); dst[total_len] = NullTerminator; /* Check that the result path is normalized. */ bool is_normalized; size_t dummy; R_TRY(IsNormalized(std::addressof(is_normalized), std::addressof(dummy), dst, allow_all_characters)); /* Assert that the result path is normalized. */ AMS_ASSERT(is_normalized); /* Set the output length. */ *out_len = total_len; R_SUCCEED(); } }; class PathFormatter { private: static constexpr ALWAYS_INLINE Result CheckSharedName(const char *name, size_t len) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; if (len == 1) { R_UNLESS(name[0] != Dot, fs::ResultInvalidPathFormat()); } else if (len == 2) { R_UNLESS(name[0] != Dot || name[1] != Dot, fs::ResultInvalidPathFormat()); } for (size_t i = 0; i < len; ++i) { R_UNLESS(!IsInvalidCharacter(name[i]), fs::ResultInvalidCharacter()); } R_SUCCEED(); } static constexpr ALWAYS_INLINE Result CheckHostName(const char *name, size_t len) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; if (len == 2) { R_UNLESS(name[0] != Dot || name[1] != Dot, fs::ResultInvalidPathFormat()); } for (size_t i = 0; i < len; ++i) { R_UNLESS(!IsInvalidCharacterForHostName(name[i]), fs::ResultInvalidCharacter()); } R_SUCCEED(); } static constexpr Result CheckInvalidBackslash(bool *out_contains_backslash, const char *path, bool allow_backslash) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Default to no backslashes, so we can just write if we see one. */ *out_contains_backslash = false; while (*path != NullTerminator) { if (*(path++) == AlternateDirectorySeparator) { *out_contains_backslash = true; R_UNLESS(allow_backslash, fs::ResultInvalidCharacter()); } } R_SUCCEED(); } public: static constexpr ALWAYS_INLINE Result CheckPathFormat(const char *path, const PathFlags &flags) { bool normalized; size_t len; R_RETURN(IsNormalized(std::addressof(normalized), std::addressof(len), path, flags)); } static constexpr ALWAYS_INLINE Result SkipMountName(const char **out, size_t *out_len, const char *path) { R_RETURN(ParseMountName(out, out_len, nullptr, 0, path)); } static constexpr Result ParseMountName(const char **out, size_t *out_len, char *out_mount_name, size_t out_mount_name_buffer_size, const char *path) { /* Check pre-conditions. */ AMS_ASSERT(path != nullptr); AMS_ASSERT(out_len != nullptr); AMS_ASSERT(out != nullptr); AMS_ASSERT((out_mount_name == nullptr) == (out_mount_name_buffer_size == 0)); /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Determine max mount length. */ const auto max_mount_len = out_mount_name_buffer_size == 0 ? MountNameLengthMax + 1 : std::min(MountNameLengthMax + 1, out_mount_name_buffer_size); /* Parse the path until we see a drive separator. */ size_t mount_len = 0; for (/* ... */; mount_len < max_mount_len && path[mount_len]; ++mount_len) { const char c = path[mount_len]; /* If we see a drive separator, advance, then we're done with the pre-drive separator part of the mount. */ if (c == DriveSeparator) { ++mount_len; break; } /* If we see a directory separator, we're not in a mount name. */ if (c == DirectorySeparator || c == AlternateDirectorySeparator) { *out = path; *out_len = 0; R_SUCCEED(); } } /* Check to be sure we're actually looking at a mount name. */ if (mount_len <= 2 || path[mount_len - 1] != DriveSeparator) { *out = path; *out_len = 0; R_SUCCEED(); } /* Check that all characters in the mount name are allowable. */ for (size_t i = 0; i < mount_len; ++i) { R_UNLESS(!IsInvalidCharacterForMountName(path[i]), fs::ResultInvalidCharacter()); } /* Copy out the mount name. */ if (out_mount_name_buffer_size > 0) { R_UNLESS(mount_len < out_mount_name_buffer_size, fs::ResultTooLongPath()); for (size_t i = 0; i < mount_len; ++i) { out_mount_name[i] = path[i]; } out_mount_name[mount_len] = NullTerminator; } /* Set the output. */ *out = path + mount_len; *out_len = mount_len; R_SUCCEED(); } static constexpr ALWAYS_INLINE Result SkipRelativeDotPath(const char **out, size_t *out_len, const char *path) { R_RETURN(ParseRelativeDotPath(out, out_len, nullptr, 0, path)); } static constexpr Result ParseRelativeDotPath(const char **out, size_t *out_len, char *out_relative, size_t out_relative_buffer_size, const char *path) { /* Check pre-conditions. */ AMS_ASSERT(path != nullptr); AMS_ASSERT(out_len != nullptr); AMS_ASSERT(out != nullptr); AMS_ASSERT((out_relative == nullptr) == (out_relative_buffer_size == 0)); /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Initialize the output buffer, if we have one. */ if (out_relative_buffer_size > 0) { out_relative[0] = NullTerminator; } /* Check if the path is relative. */ if (path[0] == Dot && (path[1] == NullTerminator || path[1] == DirectorySeparator || path[1] == AlternateDirectorySeparator)) { if (out_relative_buffer_size > 0) { R_UNLESS(out_relative_buffer_size >= 2, fs::ResultTooLongPath()); out_relative[0] = Dot; out_relative[1] = NullTerminator; } *out = path + 1; *out_len = 1; R_SUCCEED(); } /* Ensure the path isn't a parent directory. */ R_UNLESS(!(path[0] == Dot && path[1] == Dot), fs::ResultDirectoryUnobtainable()); /* There was no relative dot path. */ *out = path; *out_len = 0; R_SUCCEED(); } static constexpr Result SkipWindowsPath(const char **out, size_t *out_len, bool *out_normalized, const char *path, bool has_mount_name) { /* We're normalized if and only if the parsing doesn't throw ResultNotNormalized(). */ *out_normalized = true; R_TRY_CATCH(ParseWindowsPath(out, out_len, nullptr, 0, path, has_mount_name)) { R_CATCH(fs::ResultNotNormalized) { *out_normalized = false; } } R_END_TRY_CATCH; ON_RESULT_INCLUDED(fs::ResultNotNormalized) { *out_normalized = false; }; R_SUCCEED(); } static constexpr Result ParseWindowsPath(const char **out, size_t *out_len, char *out_win, size_t out_win_buffer_size, const char *path, bool has_mount_name) { /* Check pre-conditions. */ AMS_ASSERT(path != nullptr); AMS_ASSERT(out_len != nullptr); AMS_ASSERT(out != nullptr); AMS_ASSERT((out_win == nullptr) == (out_win_buffer_size == 0)); /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Initialize the output buffer, if we have one. */ if (out_win_buffer_size > 0) { out_win[0] = NullTerminator; } /* Handle path start. */ const char *cur_path = path; if (has_mount_name && path[0] == DirectorySeparator) { if (path[1] == AlternateDirectorySeparator && path[2] == AlternateDirectorySeparator) { R_UNLESS(out_win_buffer_size > 0, fs::ResultNotNormalized()); ++cur_path; } else if (IsWindowsDrive(path + 1)) { R_UNLESS(out_win_buffer_size > 0, fs::ResultNotNormalized()); ++cur_path; } } /* Handle windows drive. */ if (IsWindowsDrive(cur_path)) { /* Parse up to separator. */ size_t win_path_len = WindowsDriveLength; for (/* ... */; cur_path[win_path_len] != NullTerminator; ++win_path_len) { R_UNLESS(!IsInvalidCharacter(cur_path[win_path_len]), fs::ResultInvalidCharacter()); if (cur_path[win_path_len] == DirectorySeparator || cur_path[win_path_len] == AlternateDirectorySeparator) { break; } } /* Ensure that we're normalized, if we're required to be. */ if (out_win_buffer_size == 0) { for (size_t i = 0; i < win_path_len; ++i) { R_UNLESS(cur_path[i] != AlternateDirectorySeparator, fs::ResultNotNormalized()); } } else { /* Ensure we can copy into the normalized buffer. */ R_UNLESS(win_path_len < out_win_buffer_size, fs::ResultTooLongPath()); for (size_t i = 0; i < win_path_len; ++i) { out_win[i] = cur_path[i]; } out_win[win_path_len] = NullTerminator; fs::Replace(out_win, win_path_len, AlternateDirectorySeparator, DirectorySeparator); } *out = cur_path + win_path_len; *out_len = win_path_len; R_SUCCEED(); } /* Handle DOS device. */ if (IsDosDevicePath(cur_path)) { size_t dos_prefix_len = DosDevicePathPrefixLength; if (IsWindowsDrive(cur_path + dos_prefix_len)) { dos_prefix_len += WindowsDriveLength; } else { --dos_prefix_len; } if (out_win_buffer_size > 0) { /* Ensure we can copy into the normalized buffer. */ R_UNLESS(dos_prefix_len < out_win_buffer_size, fs::ResultTooLongPath()); for (size_t i = 0; i < dos_prefix_len; ++i) { out_win[i] = cur_path[i]; } out_win[dos_prefix_len] = NullTerminator; fs::Replace(out_win, dos_prefix_len, DirectorySeparator, AlternateDirectorySeparator); } *out = cur_path + dos_prefix_len; *out_len = dos_prefix_len; R_SUCCEED(); } /* Handle UNC path. */ if (IsUncPath(cur_path, false, true)) { const char *final_path = cur_path; R_UNLESS(cur_path[UncPathPrefixLength] != DirectorySeparator, fs::ResultInvalidPathFormat()); R_UNLESS(cur_path[UncPathPrefixLength] != AlternateDirectorySeparator, fs::ResultInvalidPathFormat()); size_t cur_component_offset = 0; size_t pos = UncPathPrefixLength; for (/* ... */; cur_path[pos] != NullTerminator; ++pos) { if (cur_path[pos] == DirectorySeparator || cur_path[pos] == AlternateDirectorySeparator) { if (cur_component_offset != 0) { R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset)); final_path = cur_path + pos; break; } R_UNLESS(cur_path[pos + 1] != DirectorySeparator, fs::ResultInvalidPathFormat()); R_UNLESS(cur_path[pos + 1] != AlternateDirectorySeparator, fs::ResultInvalidPathFormat()); R_TRY(CheckHostName(cur_path + 2, pos - 2)); cur_component_offset = pos + 1; } } R_UNLESS(cur_component_offset != pos, fs::ResultInvalidPathFormat()); if (cur_component_offset != 0 && final_path == cur_path) { R_TRY(CheckSharedName(cur_path + cur_component_offset, pos - cur_component_offset)); final_path = cur_path + pos; } size_t unc_prefix_len = final_path - cur_path; /* Ensure that we're normalized, if we're required to be. */ if (out_win_buffer_size == 0) { for (size_t i = 0; i < unc_prefix_len; ++i) { R_UNLESS(cur_path[i] != DirectorySeparator, fs::ResultNotNormalized()); } } else { /* Ensure we can copy into the normalized buffer. */ R_UNLESS(unc_prefix_len < out_win_buffer_size, fs::ResultTooLongPath()); for (size_t i = 0; i < unc_prefix_len; ++i) { out_win[i] = cur_path[i]; } out_win[unc_prefix_len] = NullTerminator; fs::Replace(out_win, unc_prefix_len, DirectorySeparator, AlternateDirectorySeparator); } *out = cur_path + unc_prefix_len; *out_len = unc_prefix_len; R_SUCCEED(); } /* There's no windows path to parse. */ *out = path; *out_len = 0; R_SUCCEED(); } static constexpr Result IsNormalized(bool *out, size_t *out_len, const char *path, const PathFlags &flags = {}) { /* Ensure nothing is null. */ R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_UNLESS(out_len != nullptr, fs::ResultNullptrArgument()); R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Verify that the path is valid utf-8. */ R_TRY(fs::CheckUtf8(path)); /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Handle the case where the path is empty. */ if (path[0] == NullTerminator) { R_UNLESS(flags.IsEmptyPathAllowed(), fs::ResultInvalidPathFormat()); *out = true; *out_len = 0; R_SUCCEED(); } /* All normalized paths start with a directory separator...unless they're windows paths, relative paths, or have mount names. */ if (path[0] != DirectorySeparator) { R_UNLESS(flags.IsWindowsPathAllowed() || flags.IsRelativePathAllowed() || flags.IsMountNameAllowed(), fs::ResultInvalidPathFormat()); } /* Check that the path is allowed to be a windows path, if it is. */ if (fs::IsWindowsPath(path, false)) { R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); } /* Skip past the mount name, if one is present. */ size_t total_len = 0; size_t mount_name_len = 0; R_TRY(SkipMountName(std::addressof(path), std::addressof(mount_name_len), path)); /* If we had a mount name, check that that was allowed. */ if (mount_name_len > 0) { R_UNLESS(flags.IsMountNameAllowed(), fs::ResultInvalidPathFormat()); total_len += mount_name_len; } /* Check that the path starts as a normalized path should. */ if (path[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(path) && !IsWindowsPath(path, false)) { R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); R_UNLESS(!IsInvalidCharacter(path[0]), fs::ResultInvalidPathFormat()); *out = false; R_SUCCEED(); } /* Process relative path. */ size_t relative_len = 0; R_TRY(SkipRelativeDotPath(std::addressof(path), std::addressof(relative_len), path)); /* If we have a relative path, check that was allowed. */ if (relative_len > 0) { R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); total_len += relative_len; if (path[0] == NullTerminator) { *out = true; *out_len = total_len; R_SUCCEED(); } } /* Process windows path. */ size_t windows_len = 0; bool normalized_win = false; R_TRY(SkipWindowsPath(std::addressof(path), std::addressof(windows_len), std::addressof(normalized_win), path, mount_name_len > 0)); /* If the windows path wasn't normalized, we're not normalized. */ if (!normalized_win) { R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); *out = false; R_SUCCEED(); } /* If we had a windows path, check that was allowed. */ if (windows_len > 0) { R_UNLESS(flags.IsWindowsPathAllowed(), fs::ResultInvalidPathFormat()); total_len += windows_len; /* We can't have both a relative path and a windows path. */ R_UNLESS(relative_len == 0, fs::ResultInvalidPathFormat()); /* A path ending in a windows path isn't normalized. */ if (path[0] == NullTerminator) { *out = false; R_SUCCEED(); } /* Check that there are no windows directory separators in the path. */ for (size_t i = 0; path[i] != NullTerminator; ++i) { if (path[i] == AlternateDirectorySeparator) { *out = false; R_SUCCEED(); } } } /* Check that parent directory replacement is not needed if backslashes are allowed. */ if (flags.IsBackslashAllowed() && PathNormalizer::IsParentDirectoryPathReplacementNeeded(path)) { *out = false; R_SUCCEED(); } /* Check that the backslash state is valid. */ bool is_backslash_contained = false; R_TRY(CheckInvalidBackslash(std::addressof(is_backslash_contained), path, flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); /* Check that backslashes are contained only if allowed. */ if (is_backslash_contained && !flags.IsBackslashAllowed()) { *out = false; R_SUCCEED(); } /* Check that the final result path is normalized. */ size_t normal_len = 0; R_TRY(PathNormalizer::IsNormalized(out, std::addressof(normal_len), path, flags.IsAllCharactersAllowed())); /* Add the normal length. */ total_len += normal_len; /* Set the output length. */ *out_len = total_len; R_SUCCEED(); } static constexpr Result Normalize(char *dst, size_t dst_size, const char *path, size_t path_len, const PathFlags &flags) { /* Use StringTraits names for remainder of scope. */ using namespace StringTraits; /* Prepare to iterate. */ const char *src = path; size_t cur_pos = 0; bool is_windows_path = false; /* Check if the path is empty. */ if (src[0] == NullTerminator) { if (dst_size != 0) { dst[0] = NullTerminator; } R_UNLESS(flags.IsEmptyPathAllowed(), fs::ResultInvalidPathFormat()); R_SUCCEED(); } /* Handle a mount name. */ size_t mount_name_len = 0; if (flags.IsMountNameAllowed()) { R_TRY(ParseMountName(std::addressof(src), std::addressof(mount_name_len), dst + cur_pos, dst_size - cur_pos, src)); cur_pos += mount_name_len; } /* Handle a drive-relative prefix. */ bool is_drive_relative = false; if (src[0] != DirectorySeparator && !IsPathStartWithCurrentDirectory(src) && !IsWindowsPath(src, false)) { R_UNLESS(flags.IsRelativePathAllowed(), fs::ResultInvalidPathFormat()); R_UNLESS(!IsInvalidCharacter(src[0]), fs::ResultInvalidPathFormat()); dst[cur_pos++] = Dot; is_drive_relative = true; } size_t relative_len = 0; if (flags.IsRelativePathAllowed()) { R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); R_TRY(ParseRelativeDotPath(std::addressof(src), std::addressof(relative_len), dst + cur_pos, dst_size - cur_pos, src)); cur_pos += relative_len; if (src[0] == NullTerminator) { R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); dst[cur_pos] = NullTerminator; R_SUCCEED(); } } /* Handle a windows path. */ if (flags.IsWindowsPathAllowed()) { const char * const orig = src; R_UNLESS(cur_pos < dst_size, fs::ResultTooLongPath()); size_t windows_len = 0; R_TRY(ParseWindowsPath(std::addressof(src), std::addressof(windows_len), dst + cur_pos, dst_size - cur_pos, src, mount_name_len != 0)); cur_pos += windows_len; if (src[0] == NullTerminator) { /* NOTE: Bug in original code here repeated, should be checking cur_pos + 2. */ R_UNLESS(cur_pos + 1 < dst_size, fs::ResultTooLongPath()); dst[cur_pos + 0] = DirectorySeparator; dst[cur_pos + 1] = NullTerminator; R_SUCCEED(); } if ((src - orig) > 0) { is_windows_path = true; } } /* Check for invalid backslash. */ bool backslash_contained = false; R_TRY(CheckInvalidBackslash(std::addressof(backslash_contained), src, flags.IsWindowsPathAllowed() || flags.IsBackslashAllowed())); /* Handle backslash replacement as necessary. */ if (backslash_contained && flags.IsWindowsPathAllowed()) { /* Create a temporary buffer holding a slash-replaced version of the path. */ /* NOTE: Nintendo unnecessarily allocates and replaces here a fully copy of the path, despite having skipped some of it already. */ const size_t replaced_src_len = path_len - (src - path); char *replaced_src = nullptr; ON_SCOPE_EXIT { if (replaced_src != nullptr) { if (std::is_constant_evaluated()) { delete[] replaced_src; } else { ::ams::fs::impl::Deallocate(replaced_src, replaced_src_len); } } }; if (std::is_constant_evaluated()) { replaced_src = new char[replaced_src_len]; } else { replaced_src = static_cast<char *>(::ams::fs::impl::Allocate(replaced_src_len)); } util::Strlcpy<char>(replaced_src, src, replaced_src_len); fs::Replace(replaced_src, replaced_src_len, AlternateDirectorySeparator, DirectorySeparator); size_t dummy; R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), replaced_src, dst_size - cur_pos, is_windows_path, is_drive_relative, flags.IsAllCharactersAllowed())); } else { /* We can just do normalization. */ size_t dummy; R_TRY(PathNormalizer::Normalize(dst + cur_pos, std::addressof(dummy), src, dst_size - cur_pos, is_windows_path, is_drive_relative, flags.IsAllCharactersAllowed())); } R_SUCCEED(); } }; inline Result ConvertToFspPath(fssrv::sf::FspPath *out, const char *src) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(src != nullptr); /* Copy the path. */ const size_t len = util::Strlcpy<char>(out->str, src, sizeof(out->str)); R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); /* Skip mount name. */ const char *path_split_mount_name; size_t skip_len; R_TRY(PathFormatter::SkipMountName(std::addressof(path_split_mount_name), std::addressof(skip_len), src)); /* Perform further validation. */ if (fs::IsWindowsPath(path_split_mount_name, true)) { if ((skip_len == 0 || !util::Strncmp<char>(src, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1)) && fs::IsUncPath(out->str + skip_len, true, false)) { out->str[skip_len + 0] = '\\'; out->str[skip_len + 1] = '\\'; } } else { fs::Replace(out->str, sizeof(out->str) - 1, '\\', '/'); } R_SUCCEED(); } Result FormatToFspPath(fssrv::sf::FspPath *out, const char *fmt, ...) __attribute__((format(printf, 2, 3))); inline Result FormatToFspPath(fssrv::sf::FspPath *out, const char *fmt, ...) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(fmt != nullptr); /* Format the path. */ std::va_list vl; va_start(vl, fmt); const size_t len = util::VSNPrintf(out->str, sizeof(out->str), fmt, vl); va_end(vl); R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); /* Skip mount name. */ const char *path_split_mount_name; size_t skip_len; R_TRY(PathFormatter::SkipMountName(std::addressof(path_split_mount_name), std::addressof(skip_len), out->str)); /* Perform further validation. */ if (fs::IsWindowsPath(path_split_mount_name, true)) { if ((skip_len == 0 || !util::Strncmp<char>(out->str, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1)) && fs::IsUncPath(out->str + skip_len, true, false)) { out->str[skip_len + 0] = '\\'; out->str[skip_len + 1] = '\\'; } } else { fs::Replace(out->str, sizeof(out->str) - 1, '\\', '/'); } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_priority.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum Priority { Priority_Realtime = 0, Priority_Normal = 1, Priority_Low = 2, }; enum PriorityRaw { PriorityRaw_Realtime = 0, PriorityRaw_Normal = 1, PriorityRaw_Low = 2, PriorityRaw_Background = 3, }; Priority GetPriorityOnCurrentThread(); Priority GetPriority(os::ThreadType *thread); PriorityRaw GetPriorityRawOnCurrentThread(); PriorityRaw GetPriorityRaw(os::ThreadType *thread); void SetPriorityOnCurrentThread(Priority prio); void SetPriority(os::ThreadType *thread, Priority prio); void SetPriorityRawOnCurrentThread(PriorityRaw prio); void SetPriorityRaw(os::ThreadType *thread, PriorityRaw prio); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_program_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_content_attributes.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: 17.5.0.0 */ Result GetProgramId(ncm::ProgramId *out, const char *path, fs::ContentAttributes attr); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ struct ProgramIndexMapInfo { ncm::ProgramId program_id; ncm::ProgramId base_program_id; u8 program_index; u8 pad[0xF]; }; static_assert(util::is_pod<ProgramIndexMapInfo>::value); static_assert(sizeof(ProgramIndexMapInfo) == 0x20); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_query_range.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_file.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ struct QueryRangeInfo { s32 aes_ctr_key_type; s32 speed_emulation_type; u8 reserved[0x38]; void Clear() { this->aes_ctr_key_type = 0; this->speed_emulation_type = 0; std::memset(this->reserved, 0, sizeof(this->reserved)); } void Merge(const QueryRangeInfo &rhs) { this->aes_ctr_key_type |= rhs.aes_ctr_key_type; this->speed_emulation_type |= rhs.speed_emulation_type; } }; static_assert(util::is_pod<QueryRangeInfo>::value); static_assert(sizeof(QueryRangeInfo) == 0x40); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo)); #endif using FileQueryRangeInfo = QueryRangeInfo; using StorageQueryRangeInfo = QueryRangeInfo; Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size); enum class AesCtrKeyTypeFlag : s32 { InternalKeyForSoftwareAes = (1 << 0), InternalKeyForHardwareAes = (1 << 1), ExternalKeyForHardwareAes = (1 << 2), }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_read_only_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ namespace { class ReadOnlyFile : public fsa::IFile, public impl::Newable { NON_COPYABLE(ReadOnlyFile); NON_MOVEABLE(ReadOnlyFile); private: std::unique_ptr<fsa::IFile> m_base_file; public: explicit ReadOnlyFile(std::unique_ptr<fsa::IFile> &&f) : m_base_file(std::move(f)) { AMS_ASSERT(m_base_file != nullptr); } virtual ~ReadOnlyFile() { /* ... */ } private: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { R_RETURN(m_base_file->Read(out, offset, buffer, size, option)); } virtual Result DoGetSize(s64 *out) override final { R_RETURN(m_base_file->GetSize(out)); } virtual Result DoFlush() override final { R_SUCCEED(); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { bool need_append; R_TRY(this->DryWrite(std::addressof(need_append), offset, size, option, fs::OpenMode_Read)); AMS_ASSERT(!need_append); AMS_UNUSED(buffer); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFile()); } virtual Result DoSetSize(s64 size) override final { R_TRY(this->DrySetSize(size, fs::OpenMode_Read)); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFile()); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { switch (op_id) { case OperationId::Invalidate: case OperationId::QueryRange: R_RETURN(m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); default: R_THROW(fs::ResultUnsupportedOperateRangeForReadOnlyFile()); } } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { return m_base_file->GetDomainObjectId(); } }; } template<typename T> class ReadOnlyFileSystemTemplate : public fsa::IFileSystem, public impl::Newable { NON_COPYABLE(ReadOnlyFileSystemTemplate); NON_MOVEABLE(ReadOnlyFileSystemTemplate); private: T m_base_fs; public: explicit ReadOnlyFileSystemTemplate(T &&fs) : m_base_fs(std::move(fs)) { /* ... */ } virtual ~ReadOnlyFileSystemTemplate() { /* ... */ } private: virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); std::unique_ptr<fsa::IFile> base_file; R_TRY(m_base_fs->OpenFile(std::addressof(base_file), path, mode)); auto read_only_file = std::make_unique<ReadOnlyFile>(std::move(base_file)); R_UNLESS(read_only_file != nullptr, fs::ResultAllocationMemoryFailedInReadOnlyFileSystemA()); *out_file = std::move(read_only_file); R_SUCCEED(); } virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { R_RETURN(m_base_fs->OpenDirectory(out_dir, path, mode)); } virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetEntryType(out, path)); } virtual Result DoCommit() override final { R_SUCCEED(); } virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { AMS_UNUSED(path, size, flags); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoDeleteFile(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoCreateDirectory(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoDeleteDirectory(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForReadOnlyFileSystem()); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetFreeSpaceSize(out, path)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); R_THROW(fs::ResultUnsupportedGetTotalSpaceSizeForReadOnlyFileSystem()); } virtual Result DoCommitProvisionally(s64 counter) override final { AMS_UNUSED(counter); R_THROW(fs::ResultUnsupportedCommitProvisionallyForReadOnlyFileSystem()); } }; using ReadOnlyFileSystem = ReadOnlyFileSystemTemplate<std::unique_ptr<::ams::fs::fsa::IFileSystem>>; using ReadOnlyFileSystemShared = ReadOnlyFileSystemTemplate<std::shared_ptr<::ams::fs::fsa::IFileSystem>>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/fs_query_range.hpp> namespace ams::fs { #if defined(ATMOSPHERE_OS_HORIZON) class RemoteFile : public fsa::IFile, public impl::Newable { NON_COPYABLE(RemoteFile); NON_MOVEABLE(RemoteFile); private: ::FsFile m_base_file; public: RemoteFile(const ::FsFile &f) : m_base_file(f) { /* ... */ } virtual ~RemoteFile() { fsFileClose(std::addressof(m_base_file)); } public: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { R_RETURN(fsFileRead(std::addressof(m_base_file), offset, buffer, size, option._value, out)); } virtual Result DoGetSize(s64 *out) override final { R_RETURN(fsFileGetSize(std::addressof(m_base_file), out)); } virtual Result DoFlush() override final { R_RETURN(fsFileFlush(std::addressof(m_base_file))); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { R_RETURN(fsFileWrite(std::addressof(m_base_file), offset, buffer, size, option._value)); } virtual Result DoSetSize(s64 size) override final { R_RETURN(fsFileSetSize(std::addressof(m_base_file), size)); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { AMS_UNUSED(src, src_size); R_UNLESS(op_id == OperationId::QueryRange, fs::ResultUnsupportedOperateRangeForFileServiceObjectAdapter()); R_UNLESS(dst_size == sizeof(FileQueryRangeInfo), fs::ResultInvalidSize()); R_RETURN(fsFileOperateRange(std::addressof(m_base_file), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(dst))); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { return sf::cmif::DomainObjectId{serviceGetObjectId(const_cast<::Service *>(std::addressof(m_base_file.s)))}; } }; class RemoteDirectory : public fsa::IDirectory, public impl::Newable { NON_COPYABLE(RemoteDirectory); NON_MOVEABLE(RemoteDirectory); private: ::FsDir m_base_dir; public: RemoteDirectory(const ::FsDir &d) : m_base_dir(d) { /* ... */ } virtual ~RemoteDirectory() { fsDirClose(std::addressof(m_base_dir)); } public: virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { static_assert(sizeof(*out_entries) == sizeof(::FsDirectoryEntry)); R_RETURN(fsDirRead(std::addressof(m_base_dir), out_count, max_entries, reinterpret_cast<::FsDirectoryEntry *>(out_entries))); } virtual Result DoGetEntryCount(s64 *out) override final { R_RETURN(fsDirGetEntryCount(std::addressof(m_base_dir), out)); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { return sf::cmif::DomainObjectId{serviceGetObjectId(const_cast<::Service *>(std::addressof(m_base_dir.s)))}; } }; class RemoteFileSystem : public fsa::IFileSystem, public impl::Newable { NON_COPYABLE(RemoteFileSystem); NON_MOVEABLE(RemoteFileSystem); private: ::FsFileSystem m_base_fs; public: RemoteFileSystem(const ::FsFileSystem &fs) : m_base_fs(fs) { /* ... */ } virtual ~RemoteFileSystem() { fsFsClose(std::addressof(m_base_fs)); } private: Result GetPathForServiceObject(fssrv::sf::Path *out_path, const fs::Path &path) { /* Copy, ensuring length is in bounds. */ const size_t len = util::Strlcpy<char>(out_path->str, path.GetString(), sizeof(out_path->str)); R_UNLESS(len < sizeof(out_path->str), fs::ResultTooLongPath()); /* Replace directory separators. */ /* TODO: Is this still necessary? We originally had it to not break things on low firmware. */ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) fs::Replace(out_path->str, sizeof(out_path->str) - 1, '\\', '/'); #endif R_SUCCEED(); } public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsCreateFile(std::addressof(m_base_fs), sf_path.str, size, flags)); } virtual Result DoDeleteFile(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsDeleteFile(std::addressof(m_base_fs), sf_path.str)); } virtual Result DoCreateDirectory(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsCreateDirectory(std::addressof(m_base_fs), sf_path.str)); } virtual Result DoDeleteDirectory(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsDeleteDirectory(std::addressof(m_base_fs), sf_path.str)); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsDeleteDirectoryRecursively(std::addressof(m_base_fs), sf_path.str)); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); R_TRY(GetPathForServiceObject(std::addressof(new_sf_path), new_path)); R_RETURN(fsFsRenameFile(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str)); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { fssrv::sf::Path old_sf_path; fssrv::sf::Path new_sf_path; R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path)); R_TRY(GetPathForServiceObject(std::addressof(new_sf_path), new_path)); R_RETURN(fsFsRenameDirectory(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str)); } virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType)); R_RETURN(fsFsGetEntryType(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsDirEntryType *>(out))); } virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); FsFile f; R_TRY(fsFsOpenFile(std::addressof(m_base_fs), sf_path.str, mode, std::addressof(f))); auto file = std::make_unique<RemoteFile>(f); R_UNLESS(file != nullptr, fs::ResultAllocationMemoryFailedNew()); *out_file = std::move(file); R_SUCCEED(); } virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); FsDir d; R_TRY(fsFsOpenDirectory(std::addressof(m_base_fs), sf_path.str, mode, std::addressof(d))); auto dir = std::make_unique<RemoteDirectory>(d); R_UNLESS(dir != nullptr, fs::ResultAllocationMemoryFailedNew()); *out_dir = std::move(dir); R_SUCCEED(); } virtual Result DoCommit() override final { R_RETURN(fsFsCommit(std::addressof(m_base_fs))); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsGetFreeSpace(std::addressof(m_base_fs), sf_path.str, out)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsGetTotalSpace(std::addressof(m_base_fs), sf_path.str, out)); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsCleanDirectoryRecursively(std::addressof(m_base_fs), sf_path.str)); } virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); R_RETURN(fsFsGetFileTimeStampRaw(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsTimeStampRaw *>(out))); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const fs::Path &path) override final { fssrv::sf::Path sf_path; R_TRY(GetPathForServiceObject(std::addressof(sf_path), path)); R_RETURN(fsFsQueryEntry(std::addressof(m_base_fs), dst, dst_size, src, src_size, sf_path.str, static_cast<FsFileSystemQueryId>(query))); } }; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fs { #if defined(ATMOSPHERE_OS_HORIZON) class RemoteStorage : public IStorage, public impl::Newable { NON_COPYABLE(RemoteStorage); NON_MOVEABLE(RemoteStorage); private: ::FsStorage m_base_storage; public: RemoteStorage(::FsStorage &s) : m_base_storage(s) { /* ... */} virtual ~RemoteStorage() { fsStorageClose(std::addressof(m_base_storage)); } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(fsStorageRead(std::addressof(m_base_storage), offset, buffer, size)); }; virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_RETURN(fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size)); }; virtual Result Flush() override { R_RETURN(fsStorageFlush(std::addressof(m_base_storage))); }; virtual Result GetSize(s64 *out_size) override { R_RETURN(fsStorageGetSize(std::addressof(m_base_storage), out_size)); }; virtual Result SetSize(s64 size) override { R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), size)); }; virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { /* TODO: How to deal with this? */ AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size); R_THROW(fs::ResultUnsupportedOperation()); }; }; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_result_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ void SetEnabledAutoAbort(bool enabled); void SetResultHandledByApplication(bool application); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_rights_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_content_attributes.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ union RightsId { u8 data[0x10]; u64 data64[2]; }; static_assert(sizeof(RightsId) == 0x10); static_assert(util::is_pod<RightsId>::value); inline bool operator==(const RightsId &lhs, const RightsId &rhs) { return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) == 0; } inline bool operator!=(const RightsId &lhs, const RightsId &rhs) { return !(lhs == rhs); } inline bool operator<(const RightsId &lhs, const RightsId &rhs) { return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(RightsId)) < 0; } constexpr inline RightsId InvalidRightsId = {}; /* Rights ID API */ Result GetRightsId(RightsId *out, const char *path, fs::ContentAttributes attr); Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path, fs::ContentAttributes attr); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class RomFsFileSystem : public fsa::IFileSystem, public impl::Newable { NON_COPYABLE(RomFsFileSystem); public: using RomFileTable = HierarchicalRomFileTable; private: RomFileTable m_rom_file_table; IStorage *m_base_storage; std::unique_ptr<IStorage> m_unique_storage; std::unique_ptr<IStorage> m_dir_bucket_storage; std::unique_ptr<IStorage> m_dir_entry_storage; std::unique_ptr<IStorage> m_file_bucket_storage; std::unique_ptr<IStorage> m_file_entry_storage; s64 m_entry_size; private: Result GetFileInfo(RomFileTable::FileInfo *out, const char *path); public: static Result GetRequiredWorkingMemorySize(size_t *out, IStorage *storage); public: RomFsFileSystem(); virtual ~RomFsFileSystem() override; Result Initialize(IStorage *base, void *work, size_t work_size, bool use_cache); Result Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache); IStorage *GetBaseStorage(); RomFileTable *GetRomFileTable(); Result GetFileBaseOffset(s64 *out, const char *path); public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; virtual Result DoDeleteFile(const fs::Path &path) override; virtual Result DoCreateDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; virtual Result DoRollback() override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_save_data_management.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_save_data_types.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ Result DeleteSaveData(SaveDataId id); Result DeleteSaveData(SaveDataSpaceId space_id, SaveDataId id); Result GetSaveDataFlags(u32 *out, SaveDataId id); Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id); Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags); Result GetSaveDataAvailableSize(s64 *out, SaveDataId id); Result GetSaveDataJournalSize(s64 *out, SaveDataId id); Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_save_data_transaction.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_save_data_types.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ Result CommitSaveData(const char *path); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_save_data_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ using SaveDataId = u64; using SystemSaveDataId = u64; using SystemBcatSaveDataId = SystemSaveDataId; enum class SaveDataSpaceId : u8 { System = 0, User = 1, SdSystem = 2, Temporary = 3, SdUser = 4, ProperSystem = 100, SafeMode = 101, }; enum class SaveDataType : u8 { System = 0, Account = 1, Bcat = 2, Device = 3, Temporary = 4, Cache = 5, SystemBcat = 6, }; enum class SaveDataRank : u8 { Primary = 0, Secondary = 1, }; struct UserId { u64 data[2]; }; static_assert(util::is_pod<UserId>::value); constexpr inline bool operator<(const UserId &lhs, const UserId &rhs) { if (lhs.data[0] < rhs.data[0]) { return true; } else if (lhs.data[0] == rhs.data[0] && lhs.data[1] < rhs.data[1]) { return true; } else { return false; } } constexpr inline bool operator==(const UserId &lhs, const UserId &rhs) { return lhs.data[0] == rhs.data[0] && lhs.data[1] == rhs.data[1]; } constexpr inline bool operator!=(const UserId &lhs, const UserId &rhs) { return !(lhs == rhs); } constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0; constexpr inline UserId InvalidUserId = {}; enum SaveDataFlags : u32 { SaveDataFlags_None = (0 << 0), SaveDataFlags_KeepAfterResettingSystemSaveData = (1 << 0), SaveDataFlags_KeepAfterRefurbishment = (1 << 1), SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2), SaveDataFlags_NeedsSecureDelete = (1 << 3), }; enum class SaveDataMetaType : u8 { None = 0, Thumbnail = 1, ExtensionContext = 2, }; struct SaveDataMetaInfo { u32 size; SaveDataMetaType type; u8 reserved[0xB]; }; static_assert(util::is_pod<SaveDataMetaInfo>::value); static_assert(sizeof(SaveDataMetaInfo) == 0x10); struct SaveDataCreationInfo { s64 size; s64 journal_size; s64 block_size; u64 owner_id; u32 flags; SaveDataSpaceId space_id; bool pseudo; u8 reserved[0x1A]; }; static_assert(util::is_pod<SaveDataCreationInfo>::value); static_assert(sizeof(SaveDataCreationInfo) == 0x40); struct SaveDataAttribute { ncm::ProgramId program_id; UserId user_id; SystemSaveDataId system_save_data_id; SaveDataType type; SaveDataRank rank; u16 index; u8 reserved[0x1C]; static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id, u16 index, SaveDataRank rank) { return { .program_id = program_id, .user_id = user_id, .system_save_data_id = system_save_data_id, .type = type, .rank = rank, .index = index, }; } static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id, u16 index) { return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary); } static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id) { return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary); } }; static_assert(sizeof(SaveDataAttribute) == 0x40); static_assert(std::is_trivially_destructible<SaveDataAttribute>::value); constexpr inline bool operator<(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) { return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) < std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank); } constexpr inline bool operator==(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) { return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank, lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.type, rhs.rank, rhs.index); } constexpr inline bool operator!=(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) { return !(lhs == rhs); } constexpr inline size_t DefaultSaveDataBlockSize = 16_KB; struct SaveDataExtraData { SaveDataAttribute attr; u64 owner_id; s64 timestamp; u32 flags; u8 pad[4]; s64 available_size; s64 journal_size; s64 commit_id; u8 unused[0x190]; }; static_assert(sizeof(SaveDataExtraData) == 0x200); static_assert(util::is_pod<SaveDataExtraData>::value); struct HashSalt { static constexpr size_t Size = 32; u8 value[Size]; }; static_assert(util::is_pod<HashSalt>::value); static_assert(sizeof(HashSalt) == HashSalt::Size); using SaveDataHashSalt = util::optional<HashSalt>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class IEventNotifier; constexpr inline size_t SdCardCidSize = 0x10; enum SdCardSpeedMode { SdCardSpeedMode_Identification = 0, SdCardSpeedMode_DefaultSpeed = 1, SdCardSpeedMode_HighSpeed = 2, SdCardSpeedMode_Sdr12 = 3, SdCardSpeedMode_Sdr25 = 4, SdCardSpeedMode_Sdr50 = 5, SdCardSpeedMode_Sdr104 = 6, SdCardSpeedMode_Ddr50 = 7, SdCardSpeedMode_Unknown = 8, }; struct EncryptionSeed { char value[0x10]; }; static_assert(util::is_pod<EncryptionSeed>::value); static_assert(sizeof(EncryptionSeed) == 0x10); Result GetSdCardCid(void *dst, size_t size); inline void ClearSdCardCidSerialNumber(u8 *cid) { /* Clear the serial number from the cid. */ std::memset(cid + 2, 0, 4); } Result GetSdCardUserAreaSize(s64 *out); Result GetSdCardProtectedAreaSize(s64 *out); Result GetSdCardSpeedMode(SdCardSpeedMode *out); Result MountSdCard(const char *name); Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name); Result OpenSdCardDetectionEventNotifier(std::unique_ptr<IEventNotifier> *out); bool IsSdCardInserted(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_signed_system_partition.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ bool IsSignedSystemPartitionOnSdCardValid(const char *system_root_path); bool IsSignedSystemPartitionOnSdCardValidDeprecated(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_speed_emulation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum class SpeedEmulationMode { None = 0, Faster = 1, Slower = 2, Random = 3, }; /* TODO */ /* Result SetSpeedEmulationMode(SpeedEmulationMode mode); */ /* Result GetSpeedEmulationMode(SpeedEmulationMode *out); */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_storage_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ enum StorageType : s32 { StorageType_SaveData = 0, StorageType_RomFs = 1, StorageType_Authoring = 2, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fs_istorage.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ class SubStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { private: std::shared_ptr<IStorage> m_shared_base_storage; fs::IStorage *m_base_storage; s64 m_offset; s64 m_size; bool m_resizable; private: constexpr bool IsValid() const { return m_base_storage != nullptr; } public: SubStorage() : m_shared_base_storage(), m_base_storage(nullptr), m_offset(0), m_size(0), m_resizable(false) { /* ... */ } SubStorage(const SubStorage &rhs) : m_shared_base_storage(rhs.m_shared_base_storage), m_base_storage(rhs.m_base_storage), m_offset(rhs.m_offset), m_size(rhs.m_size), m_resizable(rhs.m_resizable) { /* ... */} SubStorage &operator=(const SubStorage &rhs) { if (this != std::addressof(rhs)) { m_shared_base_storage = rhs.m_shared_base_storage; m_base_storage = rhs.m_base_storage; m_offset = rhs.m_offset; m_size = rhs.m_size; m_resizable = rhs.m_resizable; } return *this; } SubStorage(IStorage *storage, s64 o, s64 sz) : m_shared_base_storage(), m_base_storage(storage), m_offset(o), m_size(sz), m_resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(m_offset >= 0); AMS_ABORT_UNLESS(m_size >= 0); } SubStorage(std::shared_ptr<IStorage> storage, s64 o, s64 sz) : m_shared_base_storage(storage), m_base_storage(storage.get()), m_offset(o), m_size(sz), m_resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(m_offset >= 0); AMS_ABORT_UNLESS(m_size >= 0); } SubStorage(SubStorage *sub, s64 o, s64 sz) : m_shared_base_storage(sub->m_shared_base_storage), m_base_storage(sub->m_base_storage), m_offset(o + sub->m_offset), m_size(sz), m_resizable(false) { AMS_ABORT_UNLESS(this->IsValid()); AMS_ABORT_UNLESS(m_offset >= 0); AMS_ABORT_UNLESS(m_size >= 0); AMS_ABORT_UNLESS(sub->m_size >= o + sz); } ALWAYS_INLINE ::ams::fs::IStorage *operator->() { return this; } public: void SetResizable(bool rsz) { m_resizable = rsz; } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Ensure we're initialized. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and read. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(m_base_storage->Read(m_offset + offset, buffer, size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override{ /* Ensure we're initialized. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and write. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(m_base_storage->Write(m_offset + offset, buffer, size)); } virtual Result Flush() override { R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); R_RETURN(m_base_storage->Flush()); } virtual Result SetSize(s64 size) override { /* Ensure we're initialized and validate arguments. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); R_UNLESS(m_resizable, fs::ResultUnsupportedSetSizeForNotResizableSubStorage()); R_TRY(IStorage::CheckOffsetAndSize(m_offset, size)); /* Ensure that we're allowed to set size. */ s64 cur_size; R_TRY(m_base_storage->GetSize(std::addressof(cur_size))); R_UNLESS(cur_size == m_offset + m_size, fs::ResultUnsupportedSetSizeForResizableSubStorage()); /* Set the size. */ R_TRY(m_base_storage->SetSize(m_offset + size)); m_size = size; R_SUCCEED(); } virtual Result GetSize(s64 *out) override { /* Ensure we're initialized. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); *out = m_size; R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { /* Ensure we're initialized. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); /* If we're not invalidating, sanity check arguments. */ if (op_id != fs::OperationId::Invalidate) { /* Succeed immediately on zero-sized operation other than invalidate. */ R_SUCCEED_IF(size == 0); /* Check access extents. */ R_TRY(IStorage::CheckOffsetAndSize(offset, size)); } /* Perform the operation. */ R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, m_offset + offset, size, src, src_size)); } using IStorage::OperateRange; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_system_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ Result QueryMountSystemDataCacheSize(size_t *out, ncm::SystemDataId data_id); Result MountSystemData(const char *name, ncm::SystemDataId data_id); Result MountSystemData(const char *name, ncm::SystemDataId data_id, void *cache_buffer, size_t cache_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fs_system_save_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_save_data_types.hpp> namespace ams::fs { /* ACCURATE_TO_VERSION: Unknown */ void DisableAutoSaveDataCreation(); Result CreateSystemSaveData(SystemSaveDataId save_id, s64 size, s64 journal_size, u32 flags); Result CreateSystemSaveData(SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags); Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags); Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, s64 size, s64 journal_size, u32 flags); Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags); Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags); Result MountSystemSaveData(const char *name, SystemSaveDataId id); Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id); Result MountSystemSaveData(const char *name, SystemSaveDataId id, UserId user_id); Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id); Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fsa/fs_idirectory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_directory.hpp> namespace ams::fs::fsa { /* ACCURATE_TO_VERSION: Unknown */ class IDirectory { public: virtual ~IDirectory() { /* ... */ } Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { R_UNLESS(out_count != nullptr, fs::ResultNullptrArgument()); if (max_entries == 0) { *out_count = 0; R_SUCCEED(); } R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument()); R_UNLESS(max_entries > 0, fs::ResultInvalidArgument()); R_RETURN(this->DoRead(out_count, out_entries, max_entries)); } Result GetEntryCount(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->DoGetEntryCount(out)); } public: /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0; protected: /* ...? */ private: virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) = 0; virtual Result DoGetEntryCount(s64 *out) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifile.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_operate_range.hpp> namespace ams::fs::fsa { class IFile { public: virtual ~IFile() { /* ... */ } Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { /* Check that we have an output pointer. */ R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); /* If we have nothing to read, just succeed. */ if (size == 0) { *out = 0; R_SUCCEED(); } /* Check that the read is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_UNLESS(offset >= 0, fs::ResultOutOfRange()); R_UNLESS(util::IsIntValueRepresentable<s64>(size), fs::ResultOutOfRange()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); /* Do the read. */ R_RETURN(this->DoRead(out, offset, buffer, size, option)); } ALWAYS_INLINE Result Read(size_t *out, s64 offset, void *buffer, size_t size) { R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None)); } Result GetSize(s64 *out) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->DoGetSize(out)); } Result Flush() { R_RETURN(this->DoFlush()); } Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { /* Handle the zero-size case. */ if (size == 0) { if (option.HasFlushFlag()) { R_TRY(this->Flush()); } R_SUCCEED(); } /* Check the write is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); R_UNLESS(offset >= 0, fs::ResultOutOfRange()); R_UNLESS(util::IsIntValueRepresentable<s64>(size), fs::ResultOutOfRange()); R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange()); R_RETURN(this->DoWrite(offset, buffer, size, option)); } Result SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultOutOfRange()); R_RETURN(this->DoSetSize(size)); } Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) { R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0)); } public: /* TODO: This is a hack to allow the mitm API to work. Find a better way? */ virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0; protected: Result DryRead(size_t *out, s64 offset, size_t size, const fs::ReadOption &option, OpenMode open_mode) { AMS_UNUSED(option); /* Check that we can read. */ R_UNLESS((open_mode & OpenMode_Read) != 0, fs::ResultReadNotPermitted()); /* Get the file size, and validate our offset. */ s64 file_size = 0; R_TRY(this->DoGetSize(std::addressof(file_size))); R_UNLESS(offset <= file_size, fs::ResultOutOfRange()); *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size))); R_SUCCEED(); } Result DrySetSize(s64 size, fs::OpenMode open_mode) { AMS_UNUSED(size); /* Check that we can write. */ R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted()); R_SUCCEED(); } Result DryWrite(bool *out_append, s64 offset, size_t size, const fs::WriteOption &option, fs::OpenMode open_mode) { AMS_UNUSED(option); /* Check that we can write. */ R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted()); /* Get the file size. */ s64 file_size = 0; R_TRY(this->DoGetSize(&file_size)); /* Determine if we need to append. */ *out_append = false; if (file_size < offset + static_cast<s64>(size)) { R_UNLESS((open_mode & OpenMode_AllowAppend) != 0, fs::ResultFileExtensionWithoutOpenModeAllowAppend()); *out_append = true; } R_SUCCEED(); } private: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0; virtual Result DoGetSize(s64 *out) = 0; virtual Result DoFlush() = 0; virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) = 0; virtual Result DoSetSize(s64 size) = 0; virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fsa/fs_ifilesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_filesystem_for_debug.hpp> #include <stratosphere/fs/fs_path.hpp> namespace ams::fs::fsa { /* ACCURATE_TO_VERSION: Unknown */ class IFile; class IDirectory; enum class QueryId { SetConcatenationFileAttribute = 0, UpdateMac = 1, IsSignedSystemPartitionOnSdCardValid = 2, QueryUnpreparedFileInformation = 3, }; class IFileSystem { public: virtual ~IFileSystem() { /* ... */ } Result CreateFile(const fs::Path &path, s64 size, int option) { R_UNLESS(size >= 0, fs::ResultOutOfRange()); R_RETURN(this->DoCreateFile(path, size, option)); } Result CreateFile(const fs::Path &path, s64 size) { R_RETURN(this->CreateFile(path, size, fs::CreateOption_None)); } Result DeleteFile(const fs::Path &path) { R_RETURN(this->DoDeleteFile(path)); } Result CreateDirectory(const fs::Path &path) { R_RETURN(this->DoCreateDirectory(path)); } Result DeleteDirectory(const fs::Path &path) { R_RETURN(this->DoDeleteDirectory(path)); } Result DeleteDirectoryRecursively(const fs::Path &path) { R_RETURN(this->DoDeleteDirectoryRecursively(path)); } Result RenameFile(const fs::Path &old_path, const fs::Path &new_path) { R_RETURN(this->DoRenameFile(old_path, new_path)); } Result RenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { R_RETURN(this->DoRenameDirectory(old_path, new_path)); } Result GetEntryType(DirectoryEntryType *out, const fs::Path &path) { R_RETURN(this->DoGetEntryType(out, path)); } Result OpenFile(std::unique_ptr<IFile> *out_file, const fs::Path &path, OpenMode mode) { R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidOpenMode()); R_RETURN(this->DoOpenFile(out_file, path, mode)); } Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) { R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument()); R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidOpenMode()); R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidOpenMode()); R_RETURN(this->DoOpenDirectory(out_dir, path, mode)); } Result Commit() { R_RETURN(this->DoCommit()); } Result GetFreeSpaceSize(s64 *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->DoGetFreeSpaceSize(out, path)); } Result GetTotalSpaceSize(s64 *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->DoGetTotalSpaceSize(out, path)); } Result CleanDirectoryRecursively(const fs::Path &path) { R_RETURN(this->DoCleanDirectoryRecursively(path)); } Result GetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) { R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_RETURN(this->DoGetFileTimeStampRaw(out, path)); } Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const fs::Path &path) { R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path)); } /* These aren't accessible as commands. */ Result CommitProvisionally(s64 counter) { R_RETURN(this->DoCommitProvisionally(counter)); } Result Rollback() { R_RETURN(this->DoRollback()); } Result Flush() { R_RETURN(this->DoFlush()); } protected: /* ...? */ private: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) = 0; virtual Result DoDeleteFile(const fs::Path &path) = 0; virtual Result DoCreateDirectory(const fs::Path &path) = 0; virtual Result DoDeleteDirectory(const fs::Path &path) = 0; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) = 0; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) = 0; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) = 0; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) = 0; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) = 0; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) = 0; virtual Result DoCommit() = 0; virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); R_THROW(fs::ResultNotImplemented()); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); R_THROW(fs::ResultNotImplemented()); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) = 0; virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) { AMS_UNUSED(out, path); R_THROW(fs::ResultNotImplemented()); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) { AMS_UNUSED(dst, dst_size, src, src_size, query, path); R_THROW(fs::ResultNotImplemented()); } /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) { AMS_UNUSED(counter); R_THROW(fs::ResultNotImplemented()); } virtual Result DoRollback() { R_THROW(fs::ResultNotImplemented()); } virtual Result DoFlush() { R_THROW(fs::ResultNotImplemented()); } }; template<typename T> concept PointerToFileSystem = ::ams::util::RawOrSmartPointerTo<T, ::ams::fs::fsa::IFileSystem>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/fsa/fs_registrar.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs::fsa { /* ACCURATE_TO_VERSION: Unknown */ class ICommonMountNameGenerator { public: virtual ~ICommonMountNameGenerator() { /* ... */ } virtual Result GenerateCommonMountName(char *name, size_t name_size) = 0; }; class IFileSystem; Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs); Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator); Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator, bool use_data_cache, bool use_path_cache, bool multi_commit_supported); void Unregister(const char *name); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_access_log_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_access_log.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_priority.hpp> #include <stratosphere/os/os_tick.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ enum AccessLogTarget : u32 { AccessLogTarget_None = (0 << 0), AccessLogTarget_Application = (1 << 0), AccessLogTarget_System = (1 << 1), }; struct IdentifyAccessLogHandle { void *handle; public: static constexpr IdentifyAccessLogHandle MakeHandle(void *h) { return IdentifyAccessLogHandle{h}; } }; bool IsEnabledAccessLog(u32 target); bool IsEnabledAccessLog(); bool IsEnabledHandleAccessLog(fs::FileHandle handle); bool IsEnabledHandleAccessLog(fs::DirectoryHandle handle); bool IsEnabledHandleAccessLog(fs::impl::IdentifyAccessLogHandle handle); bool IsEnabledHandleAccessLog(const void *handle); bool IsEnabledFileSystemAccessorAccessLog(const char *mount_name); void EnableFileSystemAccessorAccessLog(const char *mount_name); using AccessLogPrinterCallback = int (*)(char *buffer, size_t buffer_size); void RegisterStartAccessLogPrinterCallback(AccessLogPrinterCallback callback); void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::impl::IdentifyAccessLogHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLog(Result result, fs::Priority priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 7, 8))); void OutputAccessLog(Result result, fs::PriorityRaw priority_raw, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 7, 8))); void OutputAccessLogToOnlySdCard(const char *fmt, ...) __attribute__((format (printf, 1, 2))); void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) __attribute__((format (printf, 6, 7))); class IdString { private: char m_buffer[0x20]; private: const char *ToValueString(int id); public: template<typename T> const char *ToString(T id); }; template<typename T> requires (requires { T{}; }) inline T DereferenceOutValue(T *out_value, Result result) { if (R_SUCCEEDED(result) && out_value != nullptr) { return *out_value; } else { return T{}; } } static_assert(sizeof(size_t) == sizeof(u64)); } /* Access log result name. */ #define AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME __tmp_ams_fs_access_log_result /* Access log utils. */ #define AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__VALUE__) ::ams::fs::impl::DereferenceOutValue(__VALUE__, AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME) /* Access log components. */ #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE ", read_size: %" PRIuZ "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE ", read_size: %" PRIuZ "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %" PRIuZ "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT ", name: \"%s\"" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT ", entry_count: %" PRId64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT ", entry_buffer_count: %" PRId64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE ", open_mode: 0x%" PRIX32 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH ", path: \"%s\"" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE ", path: \"%s\", size: %" PRId64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE ", path: \"%s\", open_mode: 0x%" PRIX32 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME ", path: \"%s\", new_path: \"%s\"" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE ", entry_type: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE ", content_type: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION ", mount_host_option: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH ", root_path: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID ", applicationid: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID ", bispartitionid: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID ", contentstorageid: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID ", systemdataid: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID ", dataid: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE ", gamecard_handle: 0x%" PRIX32 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION ", gamecard_partition: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID ", imagedirectoryid: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID ", programid: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID ", savedataid: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID ", savedataspaceid: %s" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID ", save_data_owner_id: 0x%" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID ", userid: 0x%016" PRIx64 "%016" PRIx64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS ", save_data_flags: 0x%08" PRIX32 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE ", save_data_journal_size: %" PRId64 "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE ", save_data_size: %" PRId64 "" /* Access log formats. */ #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE "" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_FILE(__OUT_READ_SIZE__, __OFFSET__, __SIZE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE, __OFFSET__, __SIZE__, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_READ_SIZE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_FLUSH_OPTION AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION ", write_option: Flush" #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE(__OPTION__) ((__OPTION__).HasFlushFlag() ? AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_FLUSH_OPTION : AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE_WITH_NO_OPTION) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_FILE_SIZE(__OUT_SIZE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_SIZE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_DIRECTORY(__OUT_ENTRY_COUNT__, __ENTRY_BUFFER_COUNT__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT, __ENTRY_BUFFER_COUNT__, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_ENTRY_COUNT__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_DIRECTORY_ENTRY_COUNT(__OUT_ENTRY_COUNT__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_ENTRY_COUNT__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_ENTRY_TYPE(__OUT_ENTRY_TYPE__, __PATH__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE, __PATH__, ::ams::fs::impl::IdString().ToString(AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_ENTRY_TYPE__)) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(__OUT_SIZE__, __NAME__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, __NAME__, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_SIZE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(__NAME__, __PATH__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), (__PATH__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(__NAME__, __ID__, __PATH__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__), (__PATH__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(__NAME__, __PATH__, __ID__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID, (__NAME__), (__PATH__), (__ID__).value #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(__NAME__, __PATH__, __TYPE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), ::ams::fs::impl::IdString().ToString(__TYPE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PROGRAM_ID(__NAME__, __ID__, __TYPE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__ID__), ::ams::fs::impl::IdString().ToString(__TYPE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(__NAME__, __PATH__, __ID__, __TYPE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(__NAME__, __PATH__, __ID__, __TYPE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(__NAME__, __ID__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(__NAME__, __ID__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID, (__NAME__), (__ID__).value #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(__NAME__, __GCHANDLE__, __PARTITION__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION, (__NAME__), __GCHANDLE__, ::ams::fs::impl::IdString().ToString(__PARTITION__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT() \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(__OPTION__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME), ::ams::fs::impl::IdString().ToString(__OPTION__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(__NAME__, __ROOT_PATH__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH, (__NAME__), (__ROOT_PATH__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(__NAME__, __ROOT_PATH__, __OPTION__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (__NAME__), (__ROOT_PATH__), ::ams::fs::impl::IdString().ToString(__OPTION__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(__NAME__, __ID__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(__NAME__, __ID__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID, (__NAME__), (__ID__).value #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(__NAME__, __SPACE__, __SAVE__, __USER__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \ (__NAME__), ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1] #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__, __OWNER__, __SIZE__, __JOURNAL_SIZE__, __FLAGS__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS, \ ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1], (__OWNER__), (__SIZE__), (__JOURNAL_SIZE__), (__FLAGS__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(__SPACE__, __SAVE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, \ ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \ ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1] #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(__SPACE__, __SAVE__, __SIZE__, __JOURNAL_SIZE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE, \ ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__SIZE__), (__JOURNAL_SIZE__) #define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(__ID__, __SIZE__) \ AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE, (__ID__).value, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__SIZE__) /* Access log invocation lambdas. */ #define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \ [&](const char *__fs_func_name_) -> Result { \ if (!(__ENABLED__)) { \ R_RETURN(__EXPR__); \ } else { \ const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ } \ }(__NAME__) #define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \ [&](const char *__fs_func_name_) -> Result { \ if (!(__ENABLED__)) { \ R_RETURN(__EXPR__); \ } else { \ const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __PRIORITY__, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ } \ }(__NAME__) #define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \ [&](const char *__fs_func_name_) -> Result { \ if (!(__ENABLED__)) { \ R_RETURN(__RESULT__); \ } else { \ const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__RESULT__); \ ::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __START__, __END__, __fs_func_name_, __HANDLE__, __VA_ARGS__); \ R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ } \ }(__NAME__) #define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \ [&](const char *__fs_func_name_) -> Result { \ if (!(__ENABLED__)) { \ R_RETURN(__EXPR__); \ } else { \ const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \ const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \ const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \ ::ams::fs::impl::OutputAccessLogUnlessResultSuccess(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, nullptr, __VA_ARGS__); \ R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \ } \ }(__NAME__) /* Access log api. */ #define AMS_FS_IMPL_ACCESS_LOG(__EXPR__, __HANDLE__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_SYSTEM(__EXPR__, __HANDLE__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System) && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(__EXPR__, __HANDLE__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT(__RESULT__, __START__, __END__, __HANDLE__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL((__RESULT__), __START__, __END__, __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(__EXPR__, ...) \ AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) /* FS Accessor logging. */ #define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL(__NAME__, __ENABLED__) \ do { \ if (static_cast<bool>(__ENABLED__)) { \ ::ams::fs::impl::EnableFileSystemAccessorAccessLog((__NAME__)); \ } \ } while (false) #define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(__NAME__) \ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application)) // DEBUG #define AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG /* System access log api. */ #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG) #define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) \ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System)) #else #define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) (__EXPR__) #define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) static_cast<void>(0) #endif /* Specific utilities. */ #define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(__EXPR__, __HANDLE__, __FILESYSTEM__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(__EXPR__, __HANDLE__, __FILESYSTEM__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), __NAME__, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_MOUNT(__EXPR__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(__EXPR__, __NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) #define AMS_FS_IMPL_ACCESS_LOG_UNMOUNT(__EXPR__, __MOUNT_NAME__, ...) \ AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledFileSystemAccessorAccessLog(__MOUNT_NAME__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_common_mount_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ /* Delimiting of mount names. */ constexpr inline const char ReservedMountNamePrefixCharacter = '@'; #define AMS_FS_IMPL_MOUNT_NAME_DELIMITER ":/" #define AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN 2 constexpr inline const char * const MountNameDelimiter = AMS_FS_IMPL_MOUNT_NAME_DELIMITER; /* Filesystem names. */ #define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME "@Host" #define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN 5 constexpr inline const char * const HostRootFileSystemMountName = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME; constexpr inline const char * const SdCardFileSystemMountName = "@Sdcard"; constexpr inline const char * const GameCardFileSystemMountName = "@Gc"; constexpr inline size_t GameCardFileSystemMountNameSuffixLength = 1; constexpr inline const char * const GameCardFileSystemMountNameUpdateSuffix = "U"; constexpr inline const char * const GameCardFileSystemMountNameNormalSuffix = "N"; constexpr inline const char * const GameCardFileSystemMountNameSecureSuffix = "S"; /* Built-in storage names. */ constexpr inline const char * const BisCalibrationFilePartitionMountName = "@CalibFile"; constexpr inline const char * const BisSafeModePartitionMountName = "@Safe"; constexpr inline const char * const BisUserPartitionMountName = "@User"; constexpr inline const char * const BisSystemPartitionMountName = "@System"; /* Content storage names. */ constexpr inline const char * const ContentStorageSystemMountName = "@SystemContent"; constexpr inline const char * const ContentStorageUserMountName = "@UserContent"; constexpr inline const char * const ContentStorageSdCardMountName = "@SdCardContent"; /* Registered update partition. */ constexpr inline const char * const RegisteredUpdatePartitionMountName = "@RegUpdate"; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ Result QueryMountDataCacheSize(size_t *out, ncm::DataId data_id, ncm::StorageId storage_id); Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id); Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size); Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_filesystem_proxy_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ enum FileSystemProxyType { FileSystemProxyType_Code = 0, FileSystemProxyType_Rom = 1, FileSystemProxyType_Logo = 2, FileSystemProxyType_Control = 3, FileSystemProxyType_Manual = 4, FileSystemProxyType_Meta = 5, FileSystemProxyType_Data = 6, FileSystemProxyType_Package = 7, FileSystemProxyType_UpdatePartition = 8, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_fs_inline_context_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/sf/sf_fs_inline_context.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline u8 TlsIoPriorityMask = 0x7; constexpr inline u8 TlsIoRecursiveCallMask = 0x8; struct TlsIoValueForInheritance { u8 _tls_value; }; inline void SetCurrentRequestRecursive() { os::ThreadType * const cur_thread = os::GetCurrentThread(); sf::SetFsInlineContext(cur_thread, TlsIoRecursiveCallMask | sf::GetFsInlineContext(cur_thread)); } inline bool IsCurrentRequestRecursive() { return (sf::GetFsInlineContext(os::GetCurrentThread()) & TlsIoRecursiveCallMask) != 0; } inline TlsIoValueForInheritance GetTlsIoValueForInheritance() { return TlsIoValueForInheritance { sf::GetFsInlineContext(os::GetCurrentThread()) }; } inline void SetTlsIoValueForInheritance(TlsIoValueForInheritance tls_io) { sf::SetFsInlineContext(os::GetCurrentThread(), tls_io._tls_value); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_hash_generator_factory_selector.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ fssystem::IHash256GeneratorFactorySelector *GetNcaHashGeneratorFactorySelector(); fssystem::IHash256GeneratorFactorySelector *GetSaveDataHashGeneratorFactorySelector(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_newable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_memory_management.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ class Newable { public: static ALWAYS_INLINE void *operator new(size_t size) noexcept { return ::ams::fs::impl::Allocate(size); } static ALWAYS_INLINE void *operator new(size_t size, Newable *placement) noexcept { AMS_UNUSED(size); return placement; } static ALWAYS_INLINE void *operator new[](size_t size) noexcept { return ::ams::fs::impl::Allocate(size); } static ALWAYS_INLINE void operator delete(void *ptr, size_t size) noexcept { return ::ams::fs::impl::Deallocate(ptr, size); } static ALWAYS_INLINE void operator delete[](void *ptr, size_t size) noexcept { return ::ams::fs::impl::Deallocate(ptr, size); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_priority_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_priority.hpp> #include <stratosphere/fs/impl/fs_fs_inline_context_utils.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ enum TlsIoPriority : u8 { TlsIoPriority_Normal = 0, TlsIoPriority_Realtime = 1, TlsIoPriority_Low = 2, TlsIoPriority_Background = 3, }; #if defined(ATMOSPHERE_OS_HORIZON) /* Ensure that TlsIo priority matches libnx priority. */ static_assert(TlsIoPriority_Normal == static_cast<TlsIoPriority>(::FsPriority_Normal)); static_assert(TlsIoPriority_Realtime == static_cast<TlsIoPriority>(::FsPriority_Realtime)); static_assert(TlsIoPriority_Low == static_cast<TlsIoPriority>(::FsPriority_Low)); static_assert(TlsIoPriority_Background == static_cast<TlsIoPriority>(::FsPriority_Background)); #endif constexpr inline Result ConvertFsPriorityToTlsIoPriority(u8 *out, PriorityRaw priority) { AMS_ASSERT(out != nullptr); switch (priority) { case PriorityRaw_Normal: *out = TlsIoPriority_Normal; break; case PriorityRaw_Realtime: *out = TlsIoPriority_Realtime; break; case PriorityRaw_Low: *out = TlsIoPriority_Low; break; case PriorityRaw_Background: *out = TlsIoPriority_Background; break; default: R_THROW(fs::ResultInvalidArgument()); } R_SUCCEED(); } constexpr inline Result ConvertTlsIoPriorityToFsPriority(PriorityRaw *out, u8 tls_io) { AMS_ASSERT(out != nullptr); switch (static_cast<TlsIoPriority>(tls_io)) { case TlsIoPriority_Normal: *out = PriorityRaw_Normal; break; case TlsIoPriority_Realtime: *out = PriorityRaw_Realtime; break; case TlsIoPriority_Low: *out = PriorityRaw_Low; break; case TlsIoPriority_Background: *out = PriorityRaw_Background; break; default: R_THROW(fs::ResultInvalidArgument()); } R_SUCCEED(); } inline u8 GetTlsIoPriority(os::ThreadType *thread) { return sf::GetFsInlineContext(thread) & TlsIoPriorityMask; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_result_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fs::impl { /* ACCURATE_TO_VERSION: Unknown */ bool IsAbortNeeded(Result result); void LogErrorMessage(Result result, const char *function); } #define AMS_FS_R_CHECK_ABORT_IMPL(__RESULT__, __FORCE__) \ ({ \ if (::ams::fs::impl::IsAbortNeeded(__RESULT__) || (__FORCE__)) { \ ::ams::fs::impl::LogErrorMessage(__RESULT__, AMS_CURRENT_FUNCTION_NAME); \ R_ABORT_UNLESS(__RESULT__); \ } \ }) #define AMS_FS_R_TRY(__RESULT__) \ ({ \ const ::ams::Result __tmp_fs_result = (__RESULT__); \ AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \ R_TRY(__tmp_fs_result); \ }) #define AMS_FS_R_ABORT_UNLESS(__RESULT__) \ ({ \ const ::ams::Result __tmp_fs_result = (__RESULT__); \ AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, true); \ }) #define AMS_FS_ABORT_UNLESS_WITH_RESULT(__EXPR__, __RESULT__) \ ({ \ if (!(__EXPR__)) { \ AMS_FS_R_ABORT_UNLESS((__RESULT__)); \ } \ }) #define AMS_FS_R_THROW(__RESULT__) \ ({ \ const ::ams::Result __tmp_fs_result = (__RESULT__); \ AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \ R_THROW(__tmp_fs_result); \ }) #define AMS_FS_R_UNLESS(__EXPR__, __RESULT__) \ ({ \ if (!(__EXPR__)) { \ AMS_FS_R_THROW((__RESULT__)); \ } \ }) #define AMS_FS_R_TRY_CATCH(__EXPR__) R_TRY_CATCH(__EXPR__) #define AMS_FS_R_CATCH(...) R_CATCH(__VA_ARGS__) #define AMS_FS_R_END_TRY_CATCH \ else if (R_FAILED(R_CURRENT_RESULT)) { \ AMS_FS_R_THROW(R_CURRENT_RESULT); \ } \ } \ }) #define AMS_FS_R_END_TRY_CATCH_WITH_ABORT_UNLESS \ else { \ AMS_FS_R_ABORT_UNLESS(R_CURRENT_RESULT); \ } \ } \ }) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_service_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sm/sm_types.hpp> namespace ams::fs::impl { constexpr inline const sm::ServiceName FileSystemProxyServiceName = sm::ServiceName::Encode("fsp-srv"); constexpr inline const sm::ServiceName ProgramRegistryServiceName = sm::ServiceName::Encode("fsp-pr"); constexpr inline const sm::ServiceName FileSystemProxyForLoaderServiceName = sm::ServiceName::Encode("fsp-ldr"); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs/impl/fs_storage_service_object_adapter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fs::impl { template<typename StorageInterface> class StorageServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::IStorage { NON_COPYABLE(StorageServiceObjectAdapter); NON_MOVEABLE(StorageServiceObjectAdapter); private: sf::SharedPointer<StorageInterface> m_x; public: explicit StorageServiceObjectAdapter(sf::SharedPointer<StorageInterface> &&o) : m_x(o) { /* ... */} virtual ~StorageServiceObjectAdapter() { /* ... */ } public: virtual Result Read(s64 offset, void *buffer, size_t size) override final { R_RETURN(m_x->Read(offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size))); } virtual Result GetSize(s64 *out) override final { R_RETURN(m_x->GetSize(out)); } virtual Result Flush() override final { R_RETURN(m_x->Flush()); } virtual Result Write(s64 offset, const void *buffer, size_t size) override final { R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size))); } virtual Result SetSize(s64 size) override final { R_RETURN(m_x->SetSize(size)); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { AMS_UNUSED(src, src_size); switch (op_id) { case OperationId::Invalidate: { fs::QueryRangeInfo dummy_range_info; R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast<s32>(op_id), offset, size)); } case OperationId::QueryRange: { R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); R_RETURN(m_x->OperateRange(reinterpret_cast<fs::QueryRangeInfo *>(dst), static_cast<s32>(op_id), offset, size)); } default: { R_THROW(fs::ResultUnsupportedOperateRangeForStorageServiceObjectAdapter()); } } } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fs.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_result_utils.hpp> #include <stratosphere/fs/fs_context.hpp> #include <stratosphere/fs/fs_result_config.hpp> #include <stratosphere/fs/fs_storage_type.hpp> #include <stratosphere/fs/fs_priority.hpp> #include <stratosphere/fs/impl/fs_priority_utils.hpp> #include <stratosphere/fs/fs_access_log.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_filesystem_proxy_type.hpp> #include <stratosphere/fs/fsa/fs_registrar.hpp> #include <stratosphere/fs/fs_remote_filesystem.hpp> #include <stratosphere/fs/fs_read_only_filesystem.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_i_event_notifier.hpp> #include <stratosphere/fs/fs_substorage.hpp> #include <stratosphere/fs/fs_memory_storage.hpp> #include <stratosphere/fs/fs_remote_storage.hpp> #include <stratosphere/fs/common/fs_file_storage.hpp> #include <stratosphere/fs/fs_query_range.hpp> #include <stratosphere/fs/fs_speed_emulation.hpp> #include <stratosphere/fs/impl/fs_common_mount_name.hpp> #include <stratosphere/fs/fs_mount.hpp> #include <stratosphere/fs/fs_path_utility.hpp> #include <stratosphere/fs/fs_path.hpp> #include <stratosphere/fs/common/fs_directory_path_parser.hpp> #include <stratosphere/fs/fs_filesystem_utils.hpp> #include <stratosphere/fs/fs_romfs_filesystem.hpp> #include <stratosphere/fs/impl/fs_data.hpp> #include <stratosphere/fs/fs_application.hpp> #include <stratosphere/fs/fs_bis.hpp> #include <stratosphere/fs/fs_code.hpp> #include <stratosphere/fs/fs_content.hpp> #include <stratosphere/fs/fs_content_storage.hpp> #include <stratosphere/fs/fs_error_info.hpp> #include <stratosphere/fs/fs_game_card.hpp> #include <stratosphere/fs/fs_host.hpp> #include <stratosphere/fs/fs_image_directory.hpp> #include <stratosphere/fs/fs_mmc.hpp> #include <stratosphere/fs/fs_save_data_types.hpp> #include <stratosphere/fs/fs_save_data_management.hpp> #include <stratosphere/fs/fs_save_data_transaction.hpp> #include <stratosphere/fs/fs_device_save_data.hpp> #include <stratosphere/fs/fs_system_save_data.hpp> #include <stratosphere/fs/fs_sd_card.hpp> #include <stratosphere/fs/fs_signed_system_partition.hpp> #include <stratosphere/fs/fs_system_data.hpp> #include <stratosphere/fs/fs_program_index_map_info.hpp> #include <stratosphere/fs/fs_program_id.hpp> #include <stratosphere/fs/impl/fs_access_log_impl.hpp> #include <stratosphere/fs/impl/fs_hash_generator_factory_selector.hpp> #include <stratosphere/fs/impl/fs_storage_service_object_adapter.hpp> #include <stratosphere/fs/fs_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_local_file_system_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> namespace ams::fssrv::fscreator { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class LocalFileSystemCreator final : public ILocalFileSystemCreator { NON_COPYABLE(LocalFileSystemCreator); NON_MOVEABLE(LocalFileSystemCreator); private: bool m_is_development; public: explicit LocalFileSystemCreator(bool dev) : m_is_development(dev) { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_partition_file_system_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> namespace ams::fssrv::fscreator { /* ACCURATE_TO_VERSION: Unknown */ class PartitionFileSystemCreator : public IPartitionFileSystemCreator { NON_COPYABLE(PartitionFileSystemCreator); NON_MOVEABLE(PartitionFileSystemCreator); public: PartitionFileSystemCreator() { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_rom_file_system_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> namespace ams::fssrv::fscreator { /* ACCURATE_TO_VERSION: Unknown */ class RomFileSystemCreator : public IRomFileSystemCreator { NON_COPYABLE(RomFileSystemCreator); NON_MOVEABLE(RomFileSystemCreator); private: MemoryResource *m_allocator; public: explicit RomFileSystemCreator(MemoryResource *mr) : m_allocator(mr) { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> #include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp> namespace ams::fssystem { struct NcaCryptoConfiguration; struct NcaCompressionConfiguration; } namespace ams::fssrv::fscreator { class StorageOnNcaCreator : public IStorageOnNcaCreator { NON_COPYABLE(StorageOnNcaCreator); NON_MOVEABLE(StorageOnNcaCreator); private: MemoryResource *m_allocator; const fssystem::NcaCryptoConfiguration &m_nca_crypto_cfg; const fssystem::NcaCompressionConfiguration &m_nca_compression_cfg; fs::IBufferManager * const m_buffer_manager; fssystem::IHash256GeneratorFactorySelector * const m_hash_generator_factory_selector; public: explicit StorageOnNcaCreator(MemoryResource *mr, const fssystem::NcaCryptoConfiguration &cfg, const fssystem::NcaCompressionConfiguration &c_cfg, fs::IBufferManager *bm, fssystem::IHash256GeneratorFactorySelector *hgfs) : m_allocator(mr), m_nca_crypto_cfg(cfg), m_nca_compression_cfg(c_cfg), m_buffer_manager(bm), m_hash_generator_factory_selector(hgfs) { /* ... */ } virtual Result Create(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index) override; virtual Result CreateWithPatch(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index) override; virtual Result CreateNcaReader(std::shared_ptr<fssystem::NcaReader> *out, std::shared_ptr<fs::IStorage> storage) override; #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) Result CreateWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index); Result CreateWithPatchWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index); Result CreateByRawStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader); #endif }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_subdirectory_file_system_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> namespace ams::fssrv::fscreator { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class SubDirectoryFileSystemCreator final : public ISubDirectoryFileSystemCreator { NON_COPYABLE(SubDirectoryFileSystemCreator); NON_MOVEABLE(SubDirectoryFileSystemCreator); public: explicit SubDirectoryFileSystemCreator() { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::fsa::IFileSystem> base_fs, const fs::Path &path) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssrv::fscreator { struct FileSystemCreatorInterfaces; } namespace ams::fssrv { class BaseStorageServiceImpl; class BaseFileSystemServiceImpl; class NcaFileSystemServiceImpl; class SaveDataFileSystemServiceImpl; class AccessFailureManagementServiceImpl; class TimeServiceImpl; class StatusReportServiceImpl; class ProgramRegistryServiceImpl; class AccessLogServiceImpl; class DebugConfigurationServiceImpl; /* ACCURATE_TO_VERSION: Unknown */ struct FileSystemProxyConfiguration { fscreator::FileSystemCreatorInterfaces *m_fs_creator_interfaces; BaseStorageServiceImpl *m_base_storage_service_impl; BaseFileSystemServiceImpl *m_base_file_system_service_impl; NcaFileSystemServiceImpl *m_nca_file_system_service_impl; SaveDataFileSystemServiceImpl *m_save_data_file_system_service_impl; AccessFailureManagementServiceImpl *m_access_failure_management_service_impl; TimeServiceImpl *m_time_service_impl; StatusReportServiceImpl *m_status_report_service_impl; ProgramRegistryServiceImpl *m_program_registry_service_impl; AccessLogServiceImpl *m_access_log_service_impl; DebugConfigurationServiceImpl *m_debug_configuration_service_impl; }; struct InternalProgramIdRangeForSpeedEmulation { u64 program_id_value_min; u64 program_id_value_max; }; } namespace ams::fssrv { void InitializeForFileSystemProxy(const FileSystemProxyConfiguration &config); void InitializeFileSystemProxyServer(int threads); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_program_registry.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy_for_loader.hpp> namespace ams::fssrv { namespace impl { class FileSystemProxyCoreImpl; } class NcaFileSystemService; class SaveDataFileSystemService; /* ACCURATE_TO_VERSION: Unknown */ class FileSystemProxyImpl { NON_COPYABLE(FileSystemProxyImpl); NON_MOVEABLE(FileSystemProxyImpl); private: impl::FileSystemProxyCoreImpl *m_impl; std::shared_ptr<NcaFileSystemService> m_nca_service; std::shared_ptr<SaveDataFileSystemService> m_save_data_service; u64 m_process_id; public: FileSystemProxyImpl(); ~FileSystemProxyImpl(); /* TODO */ public: /* fsp-srv */ Result OpenFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 type); Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid); Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out); Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type); Result OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type); Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id); Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type); Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id); Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id); Result InvalidateBisCache(); Result OpenHostFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path); Result OpenSdCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out); Result FormatSdCardFileSystem(); Result DeleteSaveDataFileSystem(u64 save_data_id); Result CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info); Result CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info); Result RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids); Result DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id); Result FormatSdCardDryRun(); Result IsExFatSupported(ams::sf::Out<bool> out); Result DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute); Result OpenGameCardStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 handle, u32 partition); Result OpenGameCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 handle, u32 partition); Result ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size); Result DeleteCacheStorage(u16 index); Result GetCacheStorageSize(ams::sf::Out<s64> out_size, ams::sf::Out<s64> out_journal_size, u16 index); Result CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt); Result OpenHostFileSystemWithOption(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 option); Result OpenSaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute); Result OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute); Result OpenReadOnlySaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute); Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id); Result ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id); Result WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer); /* ... */ Result OpenImageDirectoryFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id); /* ... */ Result OpenContentStorageFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id); /* ... */ Result OpenDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out); Result OpenDataStorageByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::ProgramId program_id); Result OpenDataStorageByDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id); Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out); Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index); Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index); Result OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type); Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type); Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out); Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out); Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out); Result OpenSystemDataUpdateEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out); Result NotifySystemDataUpdateEvent(); /* ... */ Result SetCurrentPosixTime(s64 posix_time); /* ... */ Result GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id); Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key); Result UnregisterAllExternalKey(); Result GetProgramId(ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr); Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path); Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path); Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr); Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference); Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id); Result VerifySaveDataFileSystemBySaveDataSpaceId(); Result CorruptSaveDataFileSystemBySaveDataSpaceId(); Result QuerySaveDataInternalStorageTotalSize(); Result GetSaveDataCommitId(); Result UnregisterExternalKey(const fs::RightsId &rights_id); Result SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed); Result SetSdCardAccessibility(bool accessible); Result IsSdCardAccessible(ams::sf::Out<bool> out); Result IsSignedSystemPartitionOnSdCardValid(ams::sf::Out<bool> out); Result OpenAccessFailureDetectionEventNotifier(); /* ... */ Result GetAndClearErrorInfo(ams::sf::Out<fs::FileSystemProxyErrorInfo> out); Result RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count); Result SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path); Result SetSaveDataSize(s64 size, s64 journal_size); Result SetSaveDataRootPath(const fssrv::sf::FspPath &path); Result DisableAutoSaveDataCreation(); Result SetGlobalAccessLogMode(u32 mode); Result GetGlobalAccessLogMode(ams::sf::Out<u32> out); Result OutputAccessLogToSdCard(const ams::sf::InBuffer &buf); Result RegisterUpdatePartition(); Result OpenRegisteredUpdatePartition(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out); Result GetAndClearMemoryReportInfo(ams::sf::Out<fs::MemoryReportInfo> out); /* ... */ Result GetProgramIndexForAccessLog(ams::sf::Out<u32> out_idx, ams::sf::Out<u32> out_count); Result GetFsStackUsage(ams::sf::Out<u32> out, u32 type); Result UnsetSaveDataRootPath(); Result OutputMultiProgramTagAccessLog(); Result FlushAccessLogOnSdCard(); Result OutputApplicationInfoAccessLog(); Result RegisterDebugConfiguration(u32 key, s64 value); Result UnregisterDebugConfiguration(u32 key); Result OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf); Result CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset); /* ... */ public: /* fsp-ldr */ Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id); Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id); Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id); Result OpenCodeFileSystemDeprecated4(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id); Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id); Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id); }; static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>); static_assert(sf::IsIFileSystemProxyForLoader<FileSystemProxyImpl>); /* ACCURATE_TO_VERSION: Unknown */ class InvalidFileSystemProxyImplForLoader { public: Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) { AMS_UNUSED(out_fs, path, program_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) { AMS_UNUSED(out_fs, out_verif, path, program_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { AMS_UNUSED(out_fs, out_verif, path, attr, program_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result OpenCodeFileSystemDeprecated4(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { AMS_UNUSED(out_fs, out_verif, path, attr, program_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { AMS_UNUSED(out_fs, out_verif, attr, program_id, storage_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) { AMS_UNUSED(out, process_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { AMS_UNUSED(client_pid); R_THROW(fs::ResultPortAcceptableCountLimited()); } }; static_assert(sf::IsIFileSystemProxyForLoader<FileSystemProxyImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_file_system_proxy_server_session_resource_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssrv { enum class FileSystemProxyServerSessionType : s32 { Any = 0, Realtime = 1, Background = 2, Other = 3, }; constexpr inline auto FileSystemProxyServerActiveSessionCount = 5; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_i_file_system_creator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fs { class IStorage; enum class BisPartitionId; class Path; namespace fsa { class IFileSystem; } } namespace ams::fssystem { class NcaReader; class NcaFsHeaderReader; class IAsynchronousAccessSplitter; namespace save { /* TODO */ } } namespace ams::fssrv::fscreator { /* ACCURATE_TO_VERSION: Unknown */ class IRomFileSystemCreator { public: virtual ~IRomFileSystemCreator() { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) = 0; }; /* ACCURATE_TO_VERSION: Unknown */ class IPartitionFileSystemCreator { public: virtual ~IPartitionFileSystemCreator() { /* ... */ } virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) = 0; }; /* ACCURATE_TO_VERSION: Unknown */ class IStorageOnNcaCreator { public: virtual ~IStorageOnNcaCreator() { /* ... */ } virtual Result Create(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index) = 0; virtual Result CreateWithPatch(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index) = 0; virtual Result CreateNcaReader(std::shared_ptr<fssystem::NcaReader> *out, std::shared_ptr<fs::IStorage> storage) = 0; }; /* ACCURATE_TO_VERSION: Unknown */ class ILocalFileSystemCreator { public: virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) = 0; public: Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, const fs::Path &path, bool case_sensitive) { R_RETURN(this->Create(out, path, case_sensitive, false, ResultSuccess())); } }; /* ACCURATE_TO_VERSION: Unknown */ class ISubDirectoryFileSystemCreator { public: virtual Result Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::fsa::IFileSystem> base_fs, const fs::Path &path) = 0; }; /* ACCURATE_TO_VERSION: Unknown */ struct FileSystemCreatorInterfaces { ILocalFileSystemCreator *local_fs_creator; ISubDirectoryFileSystemCreator *subdir_fs_creator; /* TODO: These don't exist any more, and should be refactored out. */ IRomFileSystemCreator *rom_fs_creator; IPartitionFileSystemCreator *partition_fs_creator; IStorageOnNcaCreator *storage_on_nca_creator; /* TODO: More creators. */ }; static_assert(util::is_pod<FileSystemCreatorInterfaces>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_interface_adapters.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp> #include <stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_exp_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/lmem/lmem_exp_heap.hpp> namespace ams::fssrv { /* ACCURATE_TO_VERSION: Unknown */ class MemoryResourceFromExpHeap : public ams::MemoryResource { private: lmem::HeapHandle m_heap_handle; public: constexpr explicit MemoryResourceFromExpHeap(lmem::HeapHandle handle) : m_heap_handle(handle) { /* ... */ } protected: virtual void *AllocateImpl(size_t size, size_t align) override { return lmem::AllocateFromExpHeap(m_heap_handle, size, static_cast<s32>(align)); } virtual void DeallocateImpl(void *p, size_t size, size_t align) override { AMS_UNUSED(size, align); return lmem::FreeToExpHeap(m_heap_handle, p); } virtual bool IsEqualImpl(const MemoryResource &rhs) const override { AMS_UNUSED(rhs); return false; } }; /* ACCURATE_TO_VERSION: Unknown */ class PeakCheckableMemoryResourceFromExpHeap : public ams::MemoryResource { private: lmem::HeapHandle m_heap_handle; os::SdkMutex m_mutex; size_t m_peak_free_size; size_t m_current_free_size; public: constexpr explicit PeakCheckableMemoryResourceFromExpHeap(size_t heap_size) : m_heap_handle(nullptr), m_mutex(), m_peak_free_size(heap_size), m_current_free_size(heap_size) { /* ... */ } void SetHeapHandle(lmem::HeapHandle handle) { m_heap_handle = handle; } size_t GetPeakFreeSize() const { return m_peak_free_size; } size_t GetCurrentFreeSize() const { return m_current_free_size; } void ClearPeak() { m_peak_free_size = m_current_free_size; } std::scoped_lock<os::SdkMutex> GetScopedLock() { return std::scoped_lock(m_mutex); } void OnAllocate(void *p, size_t size); void OnDeallocate(void *p, size_t size); protected: virtual void *AllocateImpl(size_t size, size_t align) override; virtual void DeallocateImpl(void *p, size_t size, size_t align) override; virtual bool IsEqualImpl(const MemoryResource &rhs) const override { AMS_UNUSED(rhs); return false; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::mem { class StandardAllocator; } namespace ams::fssrv { /* ACCURATE_TO_VERSION: Unknown */ class MemoryResourceFromStandardAllocator : public ams::MemoryResource { private: mem::StandardAllocator *m_allocator; os::SdkMutex m_mutex; size_t m_peak_free_size; size_t m_current_free_size; size_t m_peak_allocated_size; public: explicit MemoryResourceFromStandardAllocator(mem::StandardAllocator *allocator); constexpr virtual ~MemoryResourceFromStandardAllocator() = default; public: size_t GetPeakFreeSize() const { return m_peak_free_size; } size_t GetCurrentFreeSize() const { return m_current_free_size; } size_t GetPeakAllocatedSize() const { return m_peak_allocated_size; } void ClearPeak(); protected: virtual void *AllocateImpl(size_t size, size_t align) override; virtual void DeallocateImpl(void *p, size_t size, size_t align) override; virtual bool IsEqualImpl(const MemoryResource &rhs) const override { AMS_UNUSED(rhs); return false; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_nca_crypto_configuration.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> namespace ams::fssrv { const ::ams::fssystem::NcaCryptoConfiguration *GetDefaultNcaCryptoConfiguration(bool prod); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_nca_file_system_service_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_pimpl.hpp> #include <stratosphere/fssrv/fssrv_file_system_proxy_api.hpp> namespace ams::fssrv { class BaseFileSystemServiceImpl; class ProgramRegistryServiceImpl; class AccessFailureManagementServiceImpl; namespace fscreator { class LocalFileSystemCreator; class TargetManagerFileSystemCreator; class PartitionFileSystemCreator; class IRomFileSystemCreator; class StorageOnNcaCreator; class SubDirectoryFileSystemCreator; class EncryptedFileSystemCreator; class INspRootFileSystemCreator; } namespace impl { class UpdatePartitionPath; class ExternalKeyManager; class LocationResolverSet; class SystemDataUpdateEventManager; } /* ACCURATE_TO_VERSION: Unknown */ class NcaFileSystemServiceImpl { public: struct Configuration { BaseFileSystemServiceImpl *base_fs_service; fscreator::LocalFileSystemCreator *local_fs_creator; fscreator::TargetManagerFileSystemCreator *tm_fs_creator; fscreator::PartitionFileSystemCreator *partition_fs_creator; fscreator::IRomFileSystemCreator *rom_fs_creator; fscreator::StorageOnNcaCreator *storage_on_nca_creator; fscreator::SubDirectoryFileSystemCreator *subdir_fs_creator; fscreator::EncryptedFileSystemCreator *encrypted_fs_creator; fscreator::INspRootFileSystemCreator *nsp_root_fs_creator; ProgramRegistryServiceImpl *program_registry_service; AccessFailureManagementServiceImpl *access_failure_management_service; InternalProgramIdRangeForSpeedEmulation program_id_range_for_speed_emulation; }; private: struct MountInfo { bool is_game_card; u32 gc_handle; bool is_host_fs; bool can_mount_nca; }; private: Configuration m_config; fssystem::Pimpl<impl::UpdatePartitionPath, 0x350> m_update_partition_path; fssystem::Pimpl<impl::ExternalKeyManager, 0x50> m_external_key_manager; fssystem::Pimpl<impl::UpdatePartitionPath, 0xA8> m_location_resolver_set; fssystem::Pimpl<impl::SystemDataUpdateEventManager, 0x48> m_system_data_update_event_manager; fs::EncryptionSeed m_encryption_seed; int m_romfs_remount_for_data_corruption_count; int m_romfs_unrecoverable_data_corruption_by_remount_count; int m_romfs_recovered_by_invalidate_cache_count; os::SdkMutex m_romfs_count_mutex; public: NcaFileSystemServiceImpl(const Configuration &cfg) : m_config(cfg) { /* ... */ } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_program_registry.hpp> namespace ams::fssrv { class ProgramRegistryServiceImpl; namespace impl { class ProgramInfo; } /* ACCURATE_TO_VERSION: Unknown */ class ProgramRegistryImpl { NON_COPYABLE(ProgramRegistryImpl); NON_MOVEABLE(ProgramRegistryImpl); private: u64 m_process_id; public: ProgramRegistryImpl(); ~ProgramRegistryImpl(); public: static void Initialize(ProgramRegistryServiceImpl *service); public: Result RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const ams::sf::InBuffer &data, s64 data_size, const ams::sf::InBuffer &desc, s64 desc_size); Result UnregisterProgram(u64 process_id); Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid); Result SetEnabledProgramVerification(bool en); }; static_assert(sf::IsIProgramRegistry<ProgramRegistryImpl>); /* ACCURATE_TO_VERSION: Unknown */ class InvalidProgramRegistryImpl { public: Result RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const ams::sf::InBuffer &data, s64 data_size, const ams::sf::InBuffer &desc, s64 desc_size) { AMS_UNUSED(process_id, program_id, storage_id, data, data_size, desc, desc_size); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result UnregisterProgram(u64 process_id) { AMS_UNUSED(process_id); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { AMS_UNUSED(client_pid); R_THROW(fs::ResultPortAcceptableCountLimited()); } Result SetEnabledProgramVerification(bool en) { AMS_UNUSED(en); R_THROW(fs::ResultPortAcceptableCountLimited()); } }; static_assert(sf::IsIProgramRegistry<InvalidProgramRegistryImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_pimpl.hpp> namespace ams::fssrv { namespace impl { class ProgramInfo; class ProgramRegistryManager; class ProgramIndexMapInfoManager; } /* ACCURATE_TO_VERSION: Unknown */ class ProgramRegistryServiceImpl { public: struct Configuration { /* ... */ }; private: Configuration m_config; fssystem::Pimpl<impl::ProgramRegistryManager, 0x40> m_registry_manager; fssystem::Pimpl<impl::ProgramIndexMapInfoManager, 0x50> m_index_map_info_manager; public: ProgramRegistryServiceImpl(const Configuration &cfg) : m_config(cfg) { /* ... */ } Result RegisterProgramInfo(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size); Result UnregisterProgramInfo(u64 process_id); Result ResetProgramIndexMapInfo(const fs::ProgramIndexMapInfo *infos, int count); Result GetProgramInfo(std::shared_ptr<impl::ProgramInfo> *out, u64 process_id); Result GetProgramInfoByProgramId(std::shared_ptr<impl::ProgramInfo> *out, u64 program_id); size_t GetProgramIndexMapInfoCount(); util::optional<fs::ProgramIndexMapInfo> GetProgramIndexMapInfo(const ncm::ProgramId &program_id); ncm::ProgramId GetProgramIdByIndex(const ncm::ProgramId &program_id, u8 index); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/impl/fssrv_access_control.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssrv/impl/fssrv_access_control_bits.hpp> namespace ams::fssrv { bool IsDebugFlagEnabled(); void SetDebugFlagEnabled(bool en); } namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ struct Accessibility { u8 value; constexpr bool CanRead() const { return value & (1 << 0); } constexpr bool CanWrite() const { return value & (1 << 1); } static constexpr Accessibility MakeAccessibility(bool read, bool write) { return { static_cast<u8>(read * (1 << 0) + write * (1 << 1)) }; } }; static_assert(std::is_trivial<Accessibility>::value); class ContentOwnerInfo : public util::IntrusiveListBaseNode<ContentOwnerInfo>, public ::ams::fs::impl::Newable { private: u64 m_id; public: ContentOwnerInfo(u64 id) : m_id(id) { /* ... */ } u64 GetId() const { return m_id; } }; class SaveDataOwnerInfo : public util::IntrusiveListBaseNode<SaveDataOwnerInfo>, public ::ams::fs::impl::Newable { private: u64 m_id; Accessibility m_accessibility; public: SaveDataOwnerInfo(u64 id, Accessibility access) : m_id(id), m_accessibility(access) { /* ... */ } u64 GetId() const { return m_id; } Accessibility GetAccessibility() const { return m_accessibility; } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class AccessControl { public: enum class AccessibilityType : u32 { MountLogo, MountContentMeta, MountContentControl, MountContentManual, MountContentData, MountApplicationPackage, MountSaveDataStorage, MountContentStorage, MountImageAndVideoStorage, MountCloudBackupWorkStorage, MountCustomStorage, MountBisCalibrationFile, MountBisSafeMode, MountBisUser, MountBisSystem, MountBisSystemProperEncryption, MountBisSystemProperPartition, MountSdCard, MountGameCard, MountDeviceSaveData, MountSystemSaveData, MountOthersSaveData, MountOthersSystemSaveData, OpenBisPartitionBootPartition1Root, OpenBisPartitionBootPartition2Root, OpenBisPartitionUserDataRoot, OpenBisPartitionBootConfigAndPackage2Part1, OpenBisPartitionBootConfigAndPackage2Part2, OpenBisPartitionBootConfigAndPackage2Part3, OpenBisPartitionBootConfigAndPackage2Part4, OpenBisPartitionBootConfigAndPackage2Part5, OpenBisPartitionBootConfigAndPackage2Part6, OpenBisPartitionCalibrationBinary, OpenBisPartitionCalibrationFile, OpenBisPartitionSafeMode, OpenBisPartitionUser, OpenBisPartitionSystem, OpenBisPartitionSystemProperEncryption, OpenBisPartitionSystemProperPartition, OpenSdCardStorage, OpenGameCardStorage, MountSystemDataPrivate, MountHost, MountRegisteredUpdatePartition, MountSaveDataInternalStorage, MountTemporaryDirectory, MountAllBaseFileSystem, NotMount, Count, }; enum class OperationType : u32 { InvalidateBisCache, EraseMmc, GetGameCardDeviceCertificate, GetGameCardIdSet, FinalizeGameCardDriver, GetGameCardAsicInfo, CreateSaveData, DeleteSaveData, CreateSystemSaveData, CreateOthersSystemSaveData, DeleteSystemSaveData, OpenSaveDataInfoReader, OpenSaveDataInfoReaderForSystem, OpenSaveDataInfoReaderForInternal, OpenSaveDataMetaFile, SetCurrentPosixTime, ReadSaveDataFileSystemExtraData, SetGlobalAccessLogMode, SetSpeedEmulationMode, Debug, FillBis, CorruptSaveData, CorruptSystemSaveData, VerifySaveData, DebugSaveData, FormatSdCard, GetRightsId, RegisterExternalKey, SetEncryptionSeed, WriteSaveDataFileSystemExtraDataTimeStamp, WriteSaveDataFileSystemExtraDataFlags, WriteSaveDataFileSystemExtraDataCommitId, WriteSaveDataFileSystemExtraDataAll, ExtendSaveData, ExtendSystemSaveData, ExtendOthersSystemSaveData, RegisterUpdatePartition, OpenSaveDataTransferManager, OpenSaveDataTransferManagerVersion2, OpenSaveDataTransferManagerForSaveDataRepair, OpenSaveDataTransferManagerForSaveDataRepairTool, OpenSaveDataTransferProhibiter, OpenSaveDataMover, OpenBisWiper, ListAccessibleSaveDataOwnerId, ControlMmcPatrol, OverrideSaveDataTransferTokenSignVerificationKey, OpenSdCardDetectionEventNotifier, OpenGameCardDetectionEventNotifier, OpenSystemDataUpdateEventNotifier, NotifySystemDataUpdateEvent, OpenAccessFailureDetectionEventNotifier, GetAccessFailureDetectionEvent, IsAccessFailureDetected, ResolveAccessFailure, AbandonAccessFailure, QuerySaveDataInternalStorageTotalSize, GetSaveDataCommitId, SetSdCardAccessibility, SimulateDevice, CreateSaveDataWithHashSalt, RegisterProgramIndexMapInfo, ChallengeCardExistence, CreateOwnSaveData, DeleteOwnSaveData, ReadOwnSaveDataFileSystemExtraData, ExtendOwnSaveData, OpenOwnSaveDataTransferProhibiter, FindOwnSaveDataWithFilter, OpenSaveDataTransferManagerForRepair, SetDebugConfiguration, OpenDataStorageByPath, Count, }; AMS_PRAGMA_BEGIN_PACK(4) struct AccessControlDataHeader { u8 version; u8 reserved[3]; u64 flag_bits; u32 content_owner_infos_offset; u32 content_owner_infos_size; u32 save_data_owner_infos_offset; u32 save_data_owner_infos_size; }; struct AccessControlDescriptor { u8 version; u8 content_owner_id_count; u8 save_data_owner_id_count; u8 reserved; u64 flag_bits; u64 content_owner_id_min; u64 content_owner_id_max; u64 save_data_owner_id_min; u64 save_data_owner_id_max; /* ... */ }; AMS_PRAGMA_END_PACK() static_assert(util::is_pod<AccessControlDataHeader>::value); static_assert(util::is_pod<AccessControlDescriptor>::value); static constexpr u64 AllFlagBitsMask = ~static_cast<u64>(0); static constexpr u64 DebugFlagDisableMask = AllFlagBitsMask & ~util::ToUnderlying(AccessControlBits::Bits::Debug); private: using ContentOwnerInfoList = util::IntrusiveListBaseTraits<ContentOwnerInfo>::ListType; using SaveDataOwnerInfoList = util::IntrusiveListBaseTraits<SaveDataOwnerInfo>::ListType; private: util::optional<AccessControlBits> m_flag_bits; ContentOwnerInfoList m_content_owner_infos; SaveDataOwnerInfoList m_save_data_owner_infos; public: AccessControl(const void *data, s64 data_size, const void *desc, s64 desc_size); AccessControl(const void *data, s64 data_size, const void *desc, s64 desc_size, u64 flag_mask); ~AccessControl(); public: bool HasContentOwnerId(u64 owner_id) const; Accessibility GetAccessibilitySaveDataOwnedBy(u64 owner_id) const; void ListContentOwnerId(s32 *out_count, u64 *out_owner_ids, s32 offset, s32 count) const; void ListSaveDataOwnedId(s32 *out_count, ncm::ApplicationId *out_owner_ids, s32 offset, s32 count) const; Accessibility GetAccessibilityFor(AccessibilityType type) const; bool CanCall(OperationType type) const; public: u64 GetRawFlagBits() const { return m_flag_bits.value().GetValue(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/impl/fssrv_access_control_bits.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssrv/impl/fssrv_access_control_bits.hpp> namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_FOR_EACH_ACCESS_CONTROL_CAPABILITY(HANDLER, _NS_) \ HANDLER(CanAbandonAccessFailure, _NS_::AccessFailureResolution) \ HANDLER(CanChallengeCardExistence, _NS_::GameCard) \ HANDLER(CanControlMmcPatrol, _NS_::None) \ HANDLER(CanCorruptSaveData, _NS_::Debug, _NS_::CorruptSaveData) \ HANDLER(CanCorruptSystemSaveData, _NS_::CorruptSaveData, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanCreateOthersSystemSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanCreateOwnSaveData, _NS_::CreateOwnSaveData) \ HANDLER(CanCreateSaveData, _NS_::CreateSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanCreateSaveDataWithHashSalt, _NS_::None) \ HANDLER(CanCreateSystemSaveData, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ HANDLER(CanDebugSaveData, _NS_::Debug, _NS_::SaveDataForDebug) \ HANDLER(CanDeleteOwnSaveData, _NS_::CreateOwnSaveData) \ HANDLER(CanDeleteSaveData, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanDeleteSystemSaveData, _NS_::SystemSaveDataManagement, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ HANDLER(CanEraseMmc, _NS_::BisAllRaw) \ HANDLER(CanExtendOthersSystemSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanExtendOwnSaveData, _NS_::CreateOwnSaveData) \ HANDLER(CanExtendSaveData, _NS_::CreateSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanExtendSystemSaveData, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ HANDLER(CanFillBis, _NS_::Debug, _NS_::FillBis) \ HANDLER(CanFinalizeGameCardDriver, _NS_::GameCardPrivate) \ HANDLER(CanFindOwnSaveDataWithFilter, _NS_::CreateOwnSaveData) \ HANDLER(CanFormatSdCard, _NS_::FormatSdCard) \ HANDLER(CanGetAccessFailureDetectionEvent, _NS_::AccessFailureResolution) \ HANDLER(CanGetGameCardAsicInfo, _NS_::GameCardPrivate) \ HANDLER(CanGetGameCardDeviceCertificate, _NS_::GameCard) \ HANDLER(CanGetGameCardIdSet, _NS_::GameCard) \ HANDLER(CanGetRightsId, _NS_::GetRightsId) \ HANDLER(CanGetSaveDataCommitId, _NS_::SaveDataTransferVersion2, _NS_::SaveDataBackUp) \ HANDLER(CanInvalidateBisCache, _NS_::BisAllRaw) \ HANDLER(CanIsAccessFailureDetected, _NS_::AccessFailureResolution) \ HANDLER(CanListAccessibleSaveDataOwnerId, _NS_::SaveDataTransferVersion2, _NS_::SaveDataTransfer, _NS_::CreateSaveData) \ HANDLER(CanMountAllBaseFileSystemRead, _NS_::None) \ HANDLER(CanMountAllBaseFileSystemWrite, _NS_::None) \ HANDLER(CanMountApplicationPackageRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountBisCalibrationFileRead, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanMountBisCalibrationFileWrite, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanMountBisSafeModeRead, _NS_::BisAllRaw) \ HANDLER(CanMountBisSafeModeWrite, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemProperEncryptionRead, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemProperEncryptionWrite, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemProperPartitionRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemProperPartitionWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountBisSystemWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountBisUserRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountBisUserWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ HANDLER(CanMountCloudBackupWorkStorageRead, _NS_::SaveDataTransferVersion2) \ HANDLER(CanMountCloudBackupWorkStorageWrite, _NS_::SaveDataTransferVersion2) \ HANDLER(CanMountContentControlRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountContentDataRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountContentManualRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountContentMetaRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountContentStorageRead, _NS_::ContentManager) \ HANDLER(CanMountContentStorageWrite, _NS_::ContentManager) \ HANDLER(CanMountCustomStorage0Read, _NS_::None) \ HANDLER(CanMountCustomStorage0Write, _NS_::None) \ HANDLER(CanMountDeviceSaveDataRead, _NS_::DeviceSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanMountDeviceSaveDataWrite, _NS_::DeviceSaveData, _NS_::SaveDataBackUp) \ HANDLER(CanMountGameCardRead, _NS_::GameCard) \ HANDLER(CanMountHostRead, _NS_::Debug, _NS_::Host) \ HANDLER(CanMountHostWrite, _NS_::Debug, _NS_::Host) \ HANDLER(CanMountImageAndVideoStorageRead, _NS_::ImageManager) \ HANDLER(CanMountImageAndVideoStorageWrite, _NS_::ImageManager) \ HANDLER(CanMountLogoRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ HANDLER(CanMountOthersSaveDataRead, _NS_::SaveDataBackUp) \ HANDLER(CanMountOthersSaveDataWrite, _NS_::SaveDataBackUp) \ HANDLER(CanMountOthersSystemSaveDataRead, _NS_::SaveDataBackUp) \ HANDLER(CanMountOthersSystemSaveDataWrite, _NS_::SaveDataBackUp) \ HANDLER(CanMountRegisteredUpdatePartitionRead, _NS_::SystemUpdate) \ HANDLER(CanMountSaveDataStorageRead, _NS_::None) \ HANDLER(CanMountSaveDataStorageWrite, _NS_::None) \ HANDLER(CanMountSdCardRead, _NS_::Debug, _NS_::SdCard) \ HANDLER(CanMountSdCardWrite, _NS_::Debug, _NS_::SdCard) \ HANDLER(CanMountSystemDataPrivateRead, _NS_::SystemData, _NS_::SystemSaveData) \ HANDLER(CanMountSystemSaveDataRead, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ HANDLER(CanMountSystemSaveDataWrite, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ HANDLER(CanMountTemporaryDirectoryRead, _NS_::Debug) \ HANDLER(CanMountTemporaryDirectoryWrite, _NS_::Debug) \ HANDLER(CanNotifySystemDataUpdateEvent, _NS_::SystemUpdate) \ HANDLER(CanOpenAccessFailureDetectionEventNotifier, _NS_::AccessFailureResolution) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part1Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part1Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part2Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part2Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part3Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part3Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part4Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part4Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part5Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part5Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part6Read, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part6Write, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootPartition1RootRead, _NS_::SystemUpdate, _NS_::BisAllRaw, _NS_::BootModeControl) \ HANDLER(CanOpenBisPartitionBootPartition1RootWrite, _NS_::SystemUpdate, _NS_::BisAllRaw, _NS_::BootModeControl) \ HANDLER(CanOpenBisPartitionBootPartition2RootRead, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionBootPartition2RootWrite, _NS_::SystemUpdate, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionCalibrationBinaryRead, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanOpenBisPartitionCalibrationBinaryWrite, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanOpenBisPartitionCalibrationFileRead, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanOpenBisPartitionCalibrationFileWrite, _NS_::BisAllRaw, _NS_::Calibration) \ HANDLER(CanOpenBisPartitionSafeModeRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSafeModeWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemProperEncryptionRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemProperEncryptionWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemProperPartitionRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemProperPartitionWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionSystemWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionUserDataRootRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionUserDataRootWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionUserRead, _NS_::BisAllRaw) \ HANDLER(CanOpenBisPartitionUserWrite, _NS_::BisAllRaw) \ HANDLER(CanOpenBisWiper, _NS_::ContentManager) \ HANDLER(CanOpenDataStorageByPath, _NS_::None) \ HANDLER(CanOpenGameCardDetectionEventNotifier, _NS_::DeviceDetection, _NS_::GameCardRaw, _NS_::GameCard) \ HANDLER(CanOpenGameCardStorageRead, _NS_::GameCardRaw) \ HANDLER(CanOpenGameCardStorageWrite, _NS_::GameCardRaw) \ HANDLER(CanOpenOwnSaveDataTransferProhibiter, _NS_::CreateOwnSaveData) \ HANDLER(CanOpenSaveDataInfoReader, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanOpenSaveDataInfoReaderForInternal, _NS_::SaveDataManagement) \ HANDLER(CanOpenSaveDataInfoReaderForSystem, _NS_::SystemSaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanOpenSaveDataInternalStorageRead, _NS_::None) \ HANDLER(CanOpenSaveDataInternalStorageWrite, _NS_::None) \ HANDLER(CanOpenSaveDataMetaFile, _NS_::SaveDataMeta) \ HANDLER(CanOpenSaveDataMover, _NS_::MoveCacheStorage) \ HANDLER(CanOpenSaveDataTransferManager, _NS_::SaveDataTransfer) \ HANDLER(CanOpenSaveDataTransferManagerForRepair, _NS_::SaveDataBackUp) \ HANDLER(CanOpenSaveDataTransferManagerForSaveDataRepair, _NS_::SaveDataTransferVersion2) \ HANDLER(CanOpenSaveDataTransferManagerForSaveDataRepairTool, _NS_::None) \ HANDLER(CanOpenSaveDataTransferManagerVersion2, _NS_::SaveDataTransferVersion2) \ HANDLER(CanOpenSaveDataTransferProhibiter, _NS_::SaveDataTransferVersion2, _NS_::CreateSaveData) \ HANDLER(CanOpenSdCardDetectionEventNotifier, _NS_::DeviceDetection, _NS_::SdCard) \ HANDLER(CanOpenSdCardStorageRead, _NS_::Debug, _NS_::SdCard) \ HANDLER(CanOpenSdCardStorageWrite, _NS_::Debug, _NS_::SdCard) \ HANDLER(CanOpenSystemDataUpdateEventNotifier, _NS_::SystemData, _NS_::SystemSaveData) \ HANDLER(CanOverrideSaveDataTransferTokenSignVerificationKey, _NS_::None) \ HANDLER(CanQuerySaveDataInternalStorageTotalSize, _NS_::SaveDataTransfer) \ HANDLER(CanReadOwnSaveDataFileSystemExtraData, _NS_::CreateOwnSaveData) \ HANDLER(CanReadSaveDataFileSystemExtraData, _NS_::SystemSaveDataManagement, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanRegisterExternalKey, _NS_::RegisterExternalKey) \ HANDLER(CanRegisterProgramIndexMapInfo, _NS_::RegisterProgramIndexMapInfo) \ HANDLER(CanRegisterUpdatePartition, _NS_::RegisterUpdatePartition) \ HANDLER(CanResolveAccessFailure, _NS_::AccessFailureResolution) \ HANDLER(CanSetCurrentPosixTime, _NS_::SetTime) \ HANDLER(CanSetDebugConfiguration, _NS_::None) \ HANDLER(CanSetEncryptionSeed, _NS_::ContentManager) \ HANDLER(CanSetGlobalAccessLogMode, _NS_::SettingsControl) \ HANDLER(CanSetSdCardAccessibility, _NS_::SdCard) \ HANDLER(CanSetSpeedEmulationMode, _NS_::SettingsControl) \ HANDLER(CanSimulateDevice, _NS_::Debug) \ HANDLER(CanVerifySaveData, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanWriteSaveDataFileSystemExtraDataAll, _NS_::None) \ HANDLER(CanWriteSaveDataFileSystemExtraDataCommitId, _NS_::SaveDataBackUp) \ HANDLER(CanWriteSaveDataFileSystemExtraDataFlags, _NS_::SaveDataTransferVersion2, _NS_::SystemSaveDataManagement, _NS_::SaveDataBackUp) \ HANDLER(CanWriteSaveDataFileSystemExtraDataTimeStamp, _NS_::SaveDataBackUp) /* ACCURATE_TO_VERSION: 13.4.0.0 */ class AccessControlBits { public: enum class Bits : u64 { None = 0, ApplicationInfo = UINT64_C(1) << 0, BootModeControl = UINT64_C(1) << 1, Calibration = UINT64_C(1) << 2, SystemSaveData = UINT64_C(1) << 3, GameCard = UINT64_C(1) << 4, SaveDataBackUp = UINT64_C(1) << 5, SaveDataManagement = UINT64_C(1) << 6, BisAllRaw = UINT64_C(1) << 7, GameCardRaw = UINT64_C(1) << 8, GameCardPrivate = UINT64_C(1) << 9, SetTime = UINT64_C(1) << 10, ContentManager = UINT64_C(1) << 11, ImageManager = UINT64_C(1) << 12, CreateSaveData = UINT64_C(1) << 13, SystemSaveDataManagement = UINT64_C(1) << 14, BisFileSystem = UINT64_C(1) << 15, SystemUpdate = UINT64_C(1) << 16, SaveDataMeta = UINT64_C(1) << 17, DeviceSaveData = UINT64_C(1) << 18, SettingsControl = UINT64_C(1) << 19, SystemData = UINT64_C(1) << 20, SdCard = UINT64_C(1) << 21, Host = UINT64_C(1) << 22, FillBis = UINT64_C(1) << 23, CorruptSaveData = UINT64_C(1) << 24, SaveDataForDebug = UINT64_C(1) << 25, FormatSdCard = UINT64_C(1) << 26, GetRightsId = UINT64_C(1) << 27, RegisterExternalKey = UINT64_C(1) << 28, RegisterUpdatePartition = UINT64_C(1) << 29, SaveDataTransfer = UINT64_C(1) << 30, DeviceDetection = UINT64_C(1) << 31, AccessFailureResolution = UINT64_C(1) << 32, SaveDataTransferVersion2 = UINT64_C(1) << 33, RegisterProgramIndexMapInfo = UINT64_C(1) << 34, CreateOwnSaveData = UINT64_C(1) << 35, MoveCacheStorage = UINT64_C(1) << 36, Debug = UINT64_C(1) << 62, FullPermission = UINT64_C(1) << 63 }; private: static constexpr u64 CombineBits(Bits b) { return util::ToUnderlying(b); } template<typename... Args> static constexpr u64 CombineBits(Bits b, Args... args) { return CombineBits(b) | CombineBits(args...); } private: const u64 m_value; public: constexpr AccessControlBits(u64 v) : m_value(v) { /* ... */ } constexpr u64 GetValue() const { return m_value; } #define DEFINE_ACCESS_GETTER(name, ...) \ constexpr bool name() const { constexpr u64 Mask = CombineBits(Bits::FullPermission, ## __VA_ARGS__); return (m_value & Mask); } AMS_FSSRV_FOR_EACH_ACCESS_CONTROL_CAPABILITY(DEFINE_ACCESS_GETTER, Bits) #undef DEFINE_ACCESS_GETTER }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/impl/fssrv_external_key_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/fs_rights_id.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/spl/spl_types.hpp> namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ExternalKeyEntry : public util::IntrusiveListBaseNode<ExternalKeyEntry>, public ::ams::fs::impl::Newable { private: fs::RightsId m_rights_id; spl::AccessKey m_access_key; public: ExternalKeyEntry(const fs::RightsId &rights_id, const spl::AccessKey &access_key) : m_rights_id(rights_id), m_access_key(access_key) { /* ... */ } bool Contains(const fs::RightsId &rights_id) const { return crypto::IsSameBytes(std::addressof(m_rights_id), std::addressof(rights_id), sizeof(m_rights_id)); } bool Contains(const void *key, size_t key_size) const { AMS_ASSERT(key_size == sizeof(spl::AccessKey)); AMS_UNUSED(key_size); return crypto::IsSameBytes(std::addressof(m_access_key), key, sizeof(m_access_key)); } void CopyAccessKey(spl::AccessKey *out) const { AMS_ASSERT(out != nullptr); std::memcpy(out, std::addressof(m_access_key), sizeof(m_access_key)); } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ExternalKeyManager { NON_COPYABLE(ExternalKeyManager); NON_MOVEABLE(ExternalKeyManager); private: using ExternalKeyList = util::IntrusiveListBaseTraits<ExternalKeyEntry>::ListType; private: ExternalKeyList m_key_list; os::SdkMutex m_mutex; public: constexpr ExternalKeyManager() : m_key_list(), m_mutex() { /* ... */ } Result Register(const fs::RightsId &rights_id, const spl::AccessKey &access_key) { /* Acquire exclusive access to the key list */ std::scoped_lock lk(m_mutex); /* Try to find an existing entry. */ spl::AccessKey existing; if (R_SUCCEEDED(this->FindCore(std::addressof(existing), rights_id))) { /* Check the key matches what was previously registered. */ R_UNLESS(crypto::IsSameBytes(std::addressof(existing), std::addressof(access_key), sizeof(access_key)), fs::ResultNcaExternalKeyInconsistent()); } else { /* Make a new entry. */ auto *entry = new ExternalKeyEntry(rights_id, access_key); R_UNLESS(entry != nullptr, fs::ResultAllocationMemoryFailed()); /* Add the entry to our list. */ m_key_list.push_back(*entry); } R_SUCCEED(); } Result Unregister(const fs::RightsId &rights_id) { /* Acquire exclusive access to the key list */ std::scoped_lock lk(m_mutex); /* Find a matching entry. */ for (auto it = m_key_list.begin(); it != m_key_list.end(); ++it) { if (it->Contains(rights_id)) { auto *entry = std::addressof(*it); m_key_list.erase(it); delete entry; break; } } /* Always succeed. */ R_SUCCEED(); } Result UnregisterAll() { /* Acquire exclusive access to the key list */ std::scoped_lock lk(m_mutex); /* Remove all entries until our list is empty. */ while (!m_key_list.empty()) { auto *entry = std::addressof(*m_key_list.begin()); m_key_list.erase(m_key_list.iterator_to(*entry)); delete entry; } R_SUCCEED(); } bool IsAvailableAccessKey(const void *key, size_t key_size) { /* Acquire exclusive access to the key list */ std::scoped_lock lk(m_mutex); /* Check if any entry contains the key. */ for (const auto &entry : m_key_list) { if (entry.Contains(key, key_size)) { return true; } } return false; } Result Find(spl::AccessKey *out, const fs::RightsId &rights_id) { /* Acquire exclusive access to the key list */ std::scoped_lock lk(m_mutex); /* Try to find an entry with the desired rights id. */ R_RETURN(this->FindCore(out, rights_id)); } private: Result FindCore(spl::AccessKey *out, const fs::RightsId &rights_id) { for (const auto &entry : m_key_list) { if (entry.Contains(rights_id)) { entry.CopyAccessKey(out); R_SUCCEED(); } } R_THROW(fs::ResultNcaExternalKeyUnregistered()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/impl/fssrv_file_system_proxy_service_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_program_registry.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy_for_loader.hpp> #include <stratosphere/fssrv/fssrv_file_system_proxy_impl.hpp> namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ ams::sf::EmplacedRef<fssrv::sf::IFileSystemProxy, fssrv::FileSystemProxyImpl> GetFileSystemProxyServiceObject(); ams::sf::SharedPointer<fssrv::sf::IProgramRegistry> GetProgramRegistryServiceObject(); ams::sf::SharedPointer<fssrv::sf::IProgramRegistry> GetInvalidProgramRegistryServiceObject(); ams::sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(); ams::sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetInvalidFileSystemProxyForLoaderServiceObject(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/impl/fssrv_impl_program_index_map_info_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fs_program_index_map_info.hpp> #include <stratosphere/fssystem/fssystem_pimpl.hpp> namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ struct ProgramIndexMapInfoEntry : public ::ams::util::IntrusiveListBaseNode<ProgramIndexMapInfoEntry>, public ::ams::fs::impl::Newable { ncm::ProgramId program_id; ncm::ProgramId base_program_id; u8 program_index; }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ProgramIndexMapInfoManager { NON_COPYABLE(ProgramIndexMapInfoManager); NON_MOVEABLE(ProgramIndexMapInfoManager); private: using ProgramIndexMapInfoList = util::IntrusiveListBaseTraits<ProgramIndexMapInfoEntry>::ListType; private: ProgramIndexMapInfoList m_list; mutable os::SdkMutex m_mutex; public: constexpr ProgramIndexMapInfoManager() : m_list(), m_mutex() { /* ... */ } void Clear() { /* Acquire exclusive access to the map. */ std::scoped_lock lk(m_mutex); /* Actually clear. */ this->ClearImpl(); } size_t GetProgramCount() const { /* Acquire exclusive access to the map. */ std::scoped_lock lk(m_mutex); /* Get the size. */ return m_list.size(); } util::optional<fs::ProgramIndexMapInfo> Get(const ncm::ProgramId &program_id) const { /* Acquire exclusive access to the map. */ std::scoped_lock lk(m_mutex); /* Get the entry from the map. */ return this->GetImpl([&] (const ProgramIndexMapInfoEntry &entry) { return entry.program_id == program_id; }); } ncm::ProgramId GetProgramId(const ncm::ProgramId &program_id, u8 program_index) const { /* Acquire exclusive access to the map. */ std::scoped_lock lk(m_mutex); /* Get the program info for the desired program id. */ const auto base_info = this->GetImpl([&] (const ProgramIndexMapInfoEntry &entry) { return entry.program_id == program_id; }); /* Check that an entry exists for the program id. */ if (!base_info.has_value()) { return ncm::InvalidProgramId; } /* Get a program info which matches the same base program with the desired index. */ const auto target_info = this->GetImpl([&] (const ProgramIndexMapInfoEntry &entry) { return entry.base_program_id == base_info->base_program_id && entry.program_index == program_index; }); /* Return the desired program id. */ if (target_info.has_value()) { return target_info->program_id; } else { return ncm::InvalidProgramId; } } Result Reset(const fs::ProgramIndexMapInfo *infos, int count) { /* Acquire exclusive access to the map. */ std::scoped_lock lk(m_mutex); /* Clear the map, and ensure we remain clear if we fail after this point. */ this->ClearImpl(); ON_RESULT_FAILURE { this->ClearImpl(); }; /* Add each info to the list. */ for (int i = 0; i < count; ++i) { /* Allocate new entry. */ auto *entry = new ProgramIndexMapInfoEntry; R_UNLESS(entry != nullptr, fs::ResultAllocationMemoryFailedNew()); /* Copy over the info. */ entry->program_id = infos[i].program_id; entry->base_program_id = infos[i].base_program_id; entry->program_index = infos[i].program_index; /* Add to the list. */ m_list.push_back(*entry); } /* We successfully imported the map. */ R_SUCCEED(); } private: void ClearImpl() { /* Delete all entries. */ while (!m_list.empty()) { /* Get the first entry. */ ProgramIndexMapInfoEntry *front = std::addressof(*m_list.begin()); /* Erase it from the list. */ m_list.erase(m_list.iterator_to(*front)); /* Delete the entry. */ delete front; } } template<typename F> util::optional<fs::ProgramIndexMapInfo> GetImpl(F f) const { /* Try to find an entry matching the predicate. */ util::optional<fs::ProgramIndexMapInfo> match = util::nullopt; for (const auto &entry : m_list) { /* If the predicate matches, we want to return the relevant info. */ if (f(entry)) { match.emplace(); match->program_id = entry.program_id; match->base_program_id = entry.base_program_id; match->program_index = entry.program_index; break; } } return match; } }; } AMS_FSSYSTEM_ENABLE_PIMPL(::ams::fssrv::impl::ProgramIndexMapInfoManager) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_query_range.hpp> #include <stratosphere/fssystem/fssystem_utility.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_path.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifile.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_idirectory.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp> namespace ams::fs::fsa { class IFile; class IDirectory; class IFileSystem; } namespace ams::fssrv::impl { class FileSystemInterfaceAdapter; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class FileInterfaceAdapter { NON_COPYABLE(FileInterfaceAdapter); NON_MOVEABLE(FileInterfaceAdapter); private: ams::sf::SharedPointer<FileSystemInterfaceAdapter> m_parent_filesystem; std::unique_ptr<fs::fsa::IFile> m_base_file; bool m_allow_all_operations; public: FileInterfaceAdapter(std::unique_ptr<fs::fsa::IFile> &&file, FileSystemInterfaceAdapter *parent, bool allow_all); private: void InvalidateCache(); public: /* Command API. */ Result Read(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option); Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option); Result Flush(); Result SetSize(s64 size); Result GetSize(ams::sf::Out<s64> out); Result OperateRange(ams::sf::Out<fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size); Result OperateRangeWithBuffer(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size); }; static_assert(fssrv::sf::IsIFile<FileInterfaceAdapter>); /* ACCURATE_TO_VERSION: 13.4.0.0 */ class DirectoryInterfaceAdapter { NON_COPYABLE(DirectoryInterfaceAdapter); NON_MOVEABLE(DirectoryInterfaceAdapter); private: ams::sf::SharedPointer<FileSystemInterfaceAdapter> m_parent_filesystem; std::unique_ptr<fs::fsa::IDirectory> m_base_dir; bool m_allow_all_operations; public: DirectoryInterfaceAdapter(std::unique_ptr<fs::fsa::IDirectory> &&dir, FileSystemInterfaceAdapter *parent, bool allow_all); public: /* Command API */ Result Read(ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries); Result GetEntryCount(ams::sf::Out<s64> out); }; static_assert(fssrv::sf::IsIDirectory<DirectoryInterfaceAdapter>); /* ACCURATE_TO_VERSION: 13.4.0.0 */ class FileSystemInterfaceAdapter : public ams::sf::ISharedObject { NON_COPYABLE(FileSystemInterfaceAdapter); NON_MOVEABLE(FileSystemInterfaceAdapter); private: std::shared_ptr<fs::fsa::IFileSystem> m_base_fs; fs::PathFlags m_path_flags; bool m_allow_all_operations; bool m_is_mitm_interface; public: FileSystemInterfaceAdapter(std::shared_ptr<fs::fsa::IFileSystem> &&fs, const fs::PathFlags &flags, bool allow_all, bool is_mitm_interface = false) : m_base_fs(std::move(fs)), m_path_flags(flags), m_allow_all_operations(allow_all), m_is_mitm_interface(is_mitm_interface) { /* ... */ } FileSystemInterfaceAdapter(std::shared_ptr<fs::fsa::IFileSystem> &&fs, bool allow_all, bool is_mitm_interface = false) : m_base_fs(std::move(fs)), m_path_flags(), m_allow_all_operations(allow_all), m_is_mitm_interface(is_mitm_interface) { /* ... */ } private: Result SetUpPath(fs::Path *out, const fssrv::sf::Path &sf_path); public: /* Command API. */ Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option); Result DeleteFile(const fssrv::sf::Path &path); Result CreateDirectory(const fssrv::sf::Path &path); Result DeleteDirectory(const fssrv::sf::Path &path); Result DeleteDirectoryRecursively(const fssrv::sf::Path &path); Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path); Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path); Result GetEntryType(ams::sf::Out<u32> out, const fssrv::sf::Path &path); Result OpenFile(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFile>> out, const fssrv::sf::Path &path, u32 mode); Result OpenDirectory(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDirectory>> out, const fssrv::sf::Path &path, u32 mode); Result Commit(); Result GetFreeSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path); Result GetTotalSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path); Result CleanDirectoryRecursively(const fssrv::sf::Path &path); Result GetFileTimeStampRaw(ams::sf::Out<fs::FileTimeStampRaw> out, const fssrv::sf::Path &path); Result QueryEntry(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path); }; #if defined(ATMOSPHERE_OS_HORIZON) class RemoteFile { NON_COPYABLE(RemoteFile); NON_MOVEABLE(RemoteFile); private: ::FsFile m_base_file; public: RemoteFile(::FsFile &s) : m_base_file(s) { /* ... */} virtual ~RemoteFile() { fsFileClose(std::addressof(m_base_file)); } public: Result Read(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option) { R_RETURN(fsFileRead(std::addressof(m_base_file), offset, buffer.GetPointer(), size, option._value, reinterpret_cast<u64 *>(out.GetPointer()))); } Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option) { R_RETURN(fsFileWrite(std::addressof(m_base_file), offset, buffer.GetPointer(), size, option._value)); } Result Flush(){ R_RETURN(fsFileFlush(std::addressof(m_base_file))); } Result SetSize(s64 size) { R_RETURN(fsFileSetSize(std::addressof(m_base_file), size)); } Result GetSize(ams::sf::Out<s64> out) { R_RETURN(fsFileGetSize(std::addressof(m_base_file), out.GetPointer())); } Result OperateRange(ams::sf::Out<fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) { static_assert(sizeof(::FsRangeInfo) == sizeof(fs::FileQueryRangeInfo)); R_RETURN(fsFileOperateRange(std::addressof(m_base_file), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer()))); } Result OperateRangeWithBuffer(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size) { AMS_UNUSED(out_buf, in_buf, op_id, offset, size); AMS_ABORT("TODO"); } }; static_assert(fssrv::sf::IsIFile<RemoteFile>); class RemoteDirectory { NON_COPYABLE(RemoteDirectory); NON_MOVEABLE(RemoteDirectory); private: ::FsDir m_base_dir; public: RemoteDirectory(::FsDir &s) : m_base_dir(s) { /* ... */} virtual ~RemoteDirectory() { fsDirClose(std::addressof(m_base_dir)); } public: Result Read(ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries) { static_assert(sizeof(::FsDirectoryEntry) == sizeof(fs::DirectoryEntry)); R_RETURN(fsDirRead(std::addressof(m_base_dir), out.GetPointer(), out_entries.GetSize() / sizeof(fs::DirectoryEntry), reinterpret_cast<::FsDirectoryEntry *>(out_entries.GetPointer()))); } Result GetEntryCount(ams::sf::Out<s64> out) { R_RETURN(fsDirGetEntryCount(std::addressof(m_base_dir), out.GetPointer())); } }; static_assert(fssrv::sf::IsIDirectory<RemoteDirectory>); class RemoteFileSystem { NON_COPYABLE(RemoteFileSystem); NON_MOVEABLE(RemoteFileSystem); private: ::FsFileSystem m_base_fs; public: RemoteFileSystem(::FsFileSystem &s) : m_base_fs(s) { /* ... */} virtual ~RemoteFileSystem() { fsFsClose(std::addressof(m_base_fs)); } public: /* Command API. */ Result CreateFile(const fssrv::sf::Path &path, s64 size, s32 option) { R_RETURN(fsFsCreateFile(std::addressof(m_base_fs), path.str, size, option)); } Result DeleteFile(const fssrv::sf::Path &path) { R_RETURN(fsFsDeleteFile(std::addressof(m_base_fs), path.str)); } Result CreateDirectory(const fssrv::sf::Path &path) { R_RETURN(fsFsCreateDirectory(std::addressof(m_base_fs), path.str)); } Result DeleteDirectory(const fssrv::sf::Path &path) { R_RETURN(fsFsDeleteDirectory(std::addressof(m_base_fs), path.str)); } Result DeleteDirectoryRecursively(const fssrv::sf::Path &path) { R_RETURN(fsFsDeleteDirectoryRecursively(std::addressof(m_base_fs), path.str)); } Result RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { R_RETURN(fsFsRenameFile(std::addressof(m_base_fs), old_path.str, new_path.str)); } Result RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { R_RETURN(fsFsRenameDirectory(std::addressof(m_base_fs), old_path.str, new_path.str)); } Result GetEntryType(ams::sf::Out<u32> out, const fssrv::sf::Path &path) { static_assert(sizeof(::FsDirEntryType) == sizeof(u32)); R_RETURN(fsFsGetEntryType(std::addressof(m_base_fs), path.str, reinterpret_cast<::FsDirEntryType *>(out.GetPointer()))); } Result Commit() { R_RETURN(fsFsCommit(std::addressof(m_base_fs))); } Result GetFreeSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path) { R_RETURN(fsFsGetFreeSpace(std::addressof(m_base_fs), path.str, out.GetPointer())); } Result GetTotalSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path) { R_RETURN(fsFsGetTotalSpace(std::addressof(m_base_fs), path.str, out.GetPointer())); } Result CleanDirectoryRecursively(const fssrv::sf::Path &path) { R_RETURN(fsFsCleanDirectoryRecursively(std::addressof(m_base_fs), path.str)); } Result GetFileTimeStampRaw(ams::sf::Out<fs::FileTimeStampRaw> out, const fssrv::sf::Path &path) { static_assert(sizeof(fs::FileTimeStampRaw) == sizeof(::FsTimeStampRaw)); R_RETURN(fsFsGetFileTimeStampRaw(std::addressof(m_base_fs), path.str, reinterpret_cast<::FsTimeStampRaw *>(out.GetPointer()))); } Result QueryEntry(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path) { R_RETURN(fsFsQueryEntry(std::addressof(m_base_fs), out_buf.GetPointer(), out_buf.GetSize(), in_buf.GetPointer(), in_buf.GetSize(), path.str, static_cast<FsFileSystemQueryId>(query_id))); } Result OpenFile(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFile>> out, const fssrv::sf::Path &path, u32 mode); Result OpenDirectory(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDirectory>> out, const fssrv::sf::Path &path, u32 mode); }; static_assert(fssrv::sf::IsIFileSystem<RemoteFileSystem>); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_query_range.hpp> #include <stratosphere/fssystem/fssystem_utility.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_istorage.hpp> namespace ams::fs { class IStorage; } namespace ams::fssrv::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class StorageInterfaceAdapter { NON_COPYABLE(StorageInterfaceAdapter); private: std::shared_ptr<fs::IStorage> m_base_storage; public: explicit StorageInterfaceAdapter(std::shared_ptr<fs::IStorage> &&storage) : m_base_storage(std::move(storage)) { /* ... */ } public: /* Command API. */ Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size); Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size); Result Flush(); Result SetSize(s64 size); Result GetSize(ams::sf::Out<s64> out); Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size); }; static_assert(fssrv::sf::IsIStorage<StorageInterfaceAdapter>); #if defined(ATMOSPHERE_OS_HORIZON) class RemoteStorage { NON_COPYABLE(RemoteStorage); NON_MOVEABLE(RemoteStorage); private: ::FsStorage m_base_storage; public: RemoteStorage(::FsStorage &s) : m_base_storage(s) { /* ... */} virtual ~RemoteStorage() { fsStorageClose(std::addressof(m_base_storage)); } public: Result Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) { R_RETURN(fsStorageRead(std::addressof(m_base_storage), offset, buffer.GetPointer(), size)); } Result Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { R_RETURN(fsStorageWrite(std::addressof(m_base_storage), offset, buffer.GetPointer(), size)); } Result Flush(){ R_RETURN(fsStorageFlush(std::addressof(m_base_storage))); } Result SetSize(s64 size) { R_RETURN(fsStorageSetSize(std::addressof(m_base_storage), size)); } Result GetSize(ams::sf::Out<s64> out) { R_RETURN(fsStorageGetSize(std::addressof(m_base_storage), out.GetPointer())); } Result OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) { static_assert(sizeof(::FsRangeInfo) == sizeof(fs::StorageQueryRangeInfo)); R_RETURN(fsStorageOperateRange(std::addressof(m_base_storage), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(out.GetPointer()))); } }; static_assert(fssrv::sf::IsIStorage<RemoteStorage>); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_device_operator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_error_info.hpp> #include <stratosphere/fs/fs_game_card.hpp> /* TODO */ /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_DEVICE_OPERATOR_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, IsSdCardInserted, (ams::sf::Out<bool> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetSdCardSpeedMode, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetSdCardCid, (ams::sf::OutBuffer out, s64 size), (out, size)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetSdCardUserAreaSize, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetSdCardProtectedAreaSize, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetAndClearSdCardErrorInfo, (ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size), (out_sei, out_size, out_buf, size)) \ AMS_SF_METHOD_INFO(C, H, 100, Result, GetMmcCid, (ams::sf::OutBuffer out, s64 size), (out, size)) \ AMS_SF_METHOD_INFO(C, H, 101, Result, GetMmcSpeedMode, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 112, Result, GetMmcPatrolCount, (ams::sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 113, Result, GetAndClearMmcErrorInfo, (ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size), (out_sei, out_size, out_buf, size)) \ AMS_SF_METHOD_INFO(C, H, 114, Result, GetMmcExtendedCsd, (ams::sf::OutBuffer out, s64 size), (out, size)) \ AMS_SF_METHOD_INFO(C, H, 200, Result, IsGameCardInserted, (ams::sf::Out<bool> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 202, Result, GetGameCardHandle, (ams::sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 208, Result, GetGameCardIdSet, (ams::sf::OutBuffer out, s64 size), (out, size)) \ AMS_SF_METHOD_INFO(C, H, 217, Result, GetGameCardErrorReportInfo, (ams::sf::Out<fs::GameCardErrorReportInfo> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 218, Result, GetGameCardDeviceId, (ams::sf::OutBuffer out, s64 size), (out, size)) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IDeviceOperator, AMS_FSSRV_I_DEVICE_OPERATOR_INTERFACE_INFO, 0x1484E21C) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_EVENT_NOTIFIER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetEventHandle, (ams::sf::OutCopyHandle out), (out)) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IEventNotifier, AMS_FSSRV_I_EVENT_NOTIFIER_INTERFACE_INFO, 0xA7E3A62C) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_istorage.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_device_operator.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp> #include <stratosphere/fs/fs_error_info.hpp> #include <stratosphere/fs/fs_memory_report_info.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_FILE_SYSTEM_PROXY_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_Min, hos::Version_1_0_0) \ AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type), (out, program_id, type), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithIdObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type), (out, path, attr, program_id, type), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id), (out, path, id)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (), ()) \ AMS_SF_METHOD_INFO(C, H, 17, Result, OpenHostFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 18, Result, OpenSdCardFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 19, Result, FormatSdCardFileSystem, (), (), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 21, Result, DeleteSaveDataFileSystem, (u64 save_data_id), (save_data_id)) \ AMS_SF_METHOD_INFO(C, H, 22, Result, CreateSaveDataFileSystem, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info), (attribute, creation_info, meta_info)) \ AMS_SF_METHOD_INFO(C, H, 23, Result, CreateSaveDataFileSystemBySystemSaveDataId, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info), (attribute, creation_info)) \ AMS_SF_METHOD_INFO(C, H, 24, Result, RegisterSaveDataFileSystemAtomicDeletion, (const ams::sf::InBuffer &save_data_ids), (save_data_ids)) \ AMS_SF_METHOD_INFO(C, H, 25, Result, DeleteSaveDataFileSystemBySaveDataSpaceId, (u8 indexer_space_id, u64 save_data_id), (indexer_space_id, save_data_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 26, Result, FormatSdCardDryRun, (), (), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 27, Result, IsExFatSupported, (ams::sf::Out<bool> out), (out), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 28, Result, DeleteSaveDataFileSystemBySaveDataAttribute, (u8 space_id, const fs::SaveDataAttribute &attribute), (space_id, attribute), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 30, Result, OpenGameCardStorage, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 handle, u32 partition), (out, handle, partition)) \ AMS_SF_METHOD_INFO(C, H, 31, Result, OpenGameCardFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 handle, u32 partition), (out, handle, partition)) \ AMS_SF_METHOD_INFO(C, H, 32, Result, ExtendSaveDataFileSystem, (u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size), (space_id, save_data_id, available_size, journal_size), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 33, Result, DeleteCacheStorage, (u16 index), (index), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 34, Result, GetCacheStorageSize, (ams::sf::Out<s64> out_size, ams::sf::Out<s64> out_journal_size, u16 index), (out_size, out_journal_size, index), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 35, Result, CreateSaveDataFileSystemWithHashSalt, (const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt), (attribute, creation_info, meta_info, salt), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 36, Result, OpenHostFileSystemWithOption, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 option), (out, path, option), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 51, Result, OpenSaveDataFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ AMS_SF_METHOD_INFO(C, H, 52, Result, OpenSaveDataFileSystemBySystemSaveDataId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute)) \ AMS_SF_METHOD_INFO(C, H, 53, Result, OpenReadOnlySaveDataFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute), (out, space_id, attribute), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 57, Result, ReadSaveDataFileSystemExtraDataBySaveDataSpaceId, (const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id), (buffer, space_id, save_data_id), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 58, Result, ReadSaveDataFileSystemExtraData, (const ams::sf::OutBuffer &buffer, u64 save_data_id), (buffer, save_data_id)) \ AMS_SF_METHOD_INFO(C, H, 59, Result, WriteSaveDataFileSystemExtraData, (u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer), (save_data_id, space_id, buffer), hos::Version_2_0_0) \ /* AMS_SF_METHOD_INFO(C, H, 60, Result, OpenSaveDataInfoReader, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 61, Result, OpenSaveDataInfoReaderBySaveDataSpaceId, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 62, Result, OpenSaveDataInfoReaderOnlyCacheStorage, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 64, Result, OpenSaveDataInternalStorageFileSystem, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 65, Result, UpdateSaveDataMacForDebug, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 66, Result, WriteSaveDataFileSystemExtraDataWithMask, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 67, Result, FindSaveDataWithFilter, (), (), hos::Version_6_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 68, Result, OpenSaveDataInfoReaderWithFilter, (), (), hos::Version_6_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 69, Result, ReadSaveDataFileSystemExtraDataBySaveDataAttribute, (), (), hos::Version_8_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 70, Result, WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (), (), hos::Version_8_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 71, Result, ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, (), (), hos::Version_10_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 80, Result, OpenSaveDataMetaFile, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 81, Result, OpenSaveDataTransferManager, (), (), hos::Version_4_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 82, Result, OpenSaveDataTransferManagerVersion2, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 83, Result, OpenSaveDataTransferProhibiter, (), (), hos::Version_6_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 84, Result, ListAccessibleSaveDataOwnerId, (), (), hos::Version_6_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 85, Result, OpenSaveDataTransferManagerForSaveDataRepair, (), (), hos::Version_9_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 86, Result, OpenSaveDataMover, (), (), hos::Version_10_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 87, Result, OpenSaveDataTransferManagerForRepair, (), (), hos::Version_11_0_0) */ \ AMS_SF_METHOD_INFO(C, H, 100, Result, OpenImageDirectoryFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id), (out, id)) \ /* AMS_SF_METHOD_INFO(C, H, 101, Result, OpenBaseFileSystem, (), (), hos::Version_11_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 102, Result, FormatBaseFileSystem, (), (), hos::Version_12_0_0) */ \ AMS_SF_METHOD_INFO(C, H, 110, Result, OpenContentStorageFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id), (out, id)) \ /* AMS_SF_METHOD_INFO(C, H, 120, Result, OpenCloudBackupWorkStorageFileSystem, (), (), hos::Version_6_0_0, hos::Version_9_2_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 130, Result, OpenCustomStorageFileSystem, (), (), hos::Version_7_0_0) */ \ AMS_SF_METHOD_INFO(C, H, 200, Result, OpenDataStorageByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 201, Result, OpenDataStorageByProgramId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 202, Result, OpenDataStorageByDataId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id), (out, data_id, storage_id)) \ AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index), (out, index), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index), (out, index), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPathObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type), (out, path, attr, type), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 510, Result, OpenSystemDataUpdateEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 511, Result, NotifySystemDataUpdateEvent, (), (), hos::Version_5_0_0) \ /* AMS_SF_METHOD_INFO(C, H, 520, Result, SimulateDeviceDetectionEvent, (), (), hos::Version_6_0_0) */ \ AMS_SF_METHOD_INFO(C, H, 600, Result, SetCurrentPosixTime, (s64 posix_time), (posix_time), hos::Version_Min, hos::Version_3_0_2) \ /* AMS_SF_METHOD_INFO(C, H, 601, Result, QuerySaveDataTotalSize, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 602, Result, VerifySaveDataFileSystem, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 603, Result, CorruptSaveDataFileSystem, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 604, Result, CreatePaddingFile, (), ()) */ \ /* AMS_SF_METHOD_INFO(C, H, 605, Result, DeleteAllPaddingFiles, (), ()) */ \ AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id), (out, program_id, storage_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (const fs::RightsId &rights_id, const spl::AccessKey &access_key), (rights_id, access_key), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (), (), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPathObsolete, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr), (out, out_key_generation, path, attr), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (s64 posix_time, s32 time_difference), (posix_time, time_difference), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (ams::sf::Out<s64> out, u8 space_id), (out, space_id), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 614, Result, CorruptSaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 615, Result, QuerySaveDataInternalStorageTotalSize, (), (), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 616, Result, GetSaveDataCommitId, (), (), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 617, Result, UnregisterExternalKey, (const fs::RightsId &rights_id), (rights_id), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 618, Result, GetProgramId, (ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr), (out, path, attr), hos::Version_17_0_0) \ AMS_SF_METHOD_INFO(C, H, 620, Result, SetSdCardEncryptionSeed, (const fs::EncryptionSeed &seed), (seed), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 630, Result, SetSdCardAccessibility, (bool accessible), (accessible), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 631, Result, IsSdCardAccessible, (ams::sf::Out<bool> out), (out), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 640, Result, IsSignedSystemPartitionOnSdCardValid, (ams::sf::Out<bool> out), (out), hos::Version_4_0_0, hos::Version_7_0_1) \ AMS_SF_METHOD_INFO(C, H, 700, Result, OpenAccessFailureDetectionEventNotifier, (), (), hos::Version_5_0_0) \ /* AMS_SF_METHOD_INFO(C, H, 701, Result, GetAccessFailureDetectionEvent, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 702, Result, IsAccessFailureDetected, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 710, Result, ResolveAccessFailure, (), (), hos::Version_5_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 720, Result, AbandonAccessFailure, (), (), hos::Version_5_0_0) */ \ AMS_SF_METHOD_INFO(C, H, 800, Result, GetAndClearErrorInfo, (ams::sf::Out<fs::FileSystemProxyErrorInfo> out), (out), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 810, Result, RegisterProgramIndexMapInfo, (const ams::sf::InBuffer &buffer, s32 count), (buffer, count), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 1000, Result, SetBisRootForHost, (u32 id, const fssrv::sf::FspPath &path), (id, path), hos::Version_Min, hos::Version_9_2_0) \ AMS_SF_METHOD_INFO(C, H, 1001, Result, SetSaveDataSize, (s64 size, s64 journal_size), (size, journal_size)) \ AMS_SF_METHOD_INFO(C, H, 1002, Result, SetSaveDataRootPath, (const fssrv::sf::FspPath &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 1003, Result, DisableAutoSaveDataCreation, (), ()) \ AMS_SF_METHOD_INFO(C, H, 1004, Result, SetGlobalAccessLogMode, (u32 mode), (mode)) \ AMS_SF_METHOD_INFO(C, H, 1005, Result, GetGlobalAccessLogMode, (ams::sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1006, Result, OutputAccessLogToSdCard, (const ams::sf::InBuffer &buf), (buf)) \ AMS_SF_METHOD_INFO(C, H, 1007, Result, RegisterUpdatePartition, (), (), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 1008, Result, OpenRegisteredUpdatePartition, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 1009, Result, GetAndClearMemoryReportInfo, (ams::sf::Out<fs::MemoryReportInfo> out), (out), hos::Version_4_0_0) \ /* AMS_SF_METHOD_INFO(C, H, 1010, Result, SetDataStorageRedirectTarget, (), (), hos::Version_5_1_0, hos::Version_6_2_0) */ \ AMS_SF_METHOD_INFO(C, H, 1011, Result, GetProgramIndexForAccessLog, (ams::sf::Out<u32> out_idx, ams::sf::Out<u32> out_count), (out_idx, out_count), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 1012, Result, GetFsStackUsage, (ams::sf::Out<u32> out, u32 type), (out, type), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 1013, Result, UnsetSaveDataRootPath, (), (), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 1014, Result, OutputMultiProgramTagAccessLog, (), (), hos::Version_10_0_0, hos::Version_10_2_0) \ AMS_SF_METHOD_INFO(C, H, 1016, Result, FlushAccessLogOnSdCard, (), (), hos::Version_11_0_0) \ AMS_SF_METHOD_INFO(C, H, 1017, Result, OutputApplicationInfoAccessLog, (), (), hos::Version_11_0_0) \ AMS_SF_METHOD_INFO(C, H, 1018, Result, RegisterDebugConfiguration, (u32 key, s64 value), (key, value), hos::Version_13_0_0) \ AMS_SF_METHOD_INFO(C, H, 1019, Result, UnregisterDebugConfiguration, (u32 key), (key), hos::Version_13_0_0) \ AMS_SF_METHOD_INFO(C, H, 1100, Result, OverrideSaveDataTransferTokenSignVerificationKey, (const ams::sf::InBuffer &buf), (buf), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 1110, Result, CorruptSaveDataFileSystemByOffset, (u8 space_id, u64 save_data_id, s64 offset), (space_id, save_data_id, offset), hos::Version_6_0_0) \ /* AMS_SF_METHOD_INFO(C, H, 1200, Result, OpenMultiCommitManager, (), (), hos::Version_6_0_0) */ \ /* AMS_SF_METHOD_INFO(C, H, 1300, Result, OpenBisWiper, (), (), hos::Version_10_0_0) */ AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxy, AMS_FSSRV_I_FILE_SYSTEM_PROXY_INTERFACE_INFO, 0x7DF34ED2) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_file_system_proxy_for_loader.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp> #include <stratosphere/fs/fs_code_verification_data.hpp> #include <stratosphere/fs/fs_content_attributes.hpp> /* ACCURATE_TO_VERSION: 17.5.0.0 */ #define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated2, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated3, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_16_0_0, hos::Version_16_1_0) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated4, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_17_0_0, hos::Version_19_0_1) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id), (out_fs, out_verif, attr, program_id, storage_id), hos::Version_20_0_0) \ AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxyForLoader, AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO, 0xDC92EE15) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_program_registry.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_code.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_PROGRAM_REGISTRY_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, RegisterProgram, (u64 process_id, u64 program_id, u8 storage_id, const ams::sf::InBuffer &data, s64 data_size, const ams::sf::InBuffer &desc, s64 desc_size), (process_id, program_id, storage_id, data, data_size, desc, desc_size)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, UnregisterProgram, (u64 process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \ AMS_SF_METHOD_INFO(C, H, 256, Result, SetEnabledProgramVerification, (bool en), (en)) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IProgramRegistry, AMS_FSSRV_I_PROGRAM_REGISTRY_INTERFACE_INFO, 0xDA73738C) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_idirectory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_directory.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_DIRECTORY_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Read, (ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries), (out, out_entries)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetEntryCount, (ams::sf::Out<s64> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IDirectory, AMS_FSSRV_I_DIRECTORY_INTERFACE_INFO, 0xB4953DB6) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_ifile.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_query_range.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_FILE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Read, (ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, ams::fs::ReadOption option), (out, offset, buffer, size, option)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Write, (s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, ams::fs::WriteOption option), (offset, buffer, size, option)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Flush, (), ()) \ AMS_SF_METHOD_INFO(C, H, 3, Result, SetSize, (s64 size), (size)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetSize, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, OperateRange, (ams::sf::Out<ams::fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size), (out, op_id, offset, size), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, OperateRangeWithBuffer, (const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size), (out_buf, in_buf, op_id, offset, size), hos::Version_12_0_0) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFile, AMS_FSSRV_I_FILE_INTERFACE_INFO, 0xF3716DA1) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_filesystem_for_debug.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_path.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifile.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_idirectory.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_FILESYSTEM_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, CreateFile, (const ams::fssrv::sf::Path &path, s64 size, s32 option), (path, size, option)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, DeleteFile, (const ams::fssrv::sf::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, CreateDirectory, (const ams::fssrv::sf::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, DeleteDirectory, (const ams::fssrv::sf::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, DeleteDirectoryRecursively, (const ams::fssrv::sf::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, RenameFile, (const ams::fssrv::sf::Path &old_path, const ams::fssrv::sf::Path &new_path), (old_path, new_path)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, RenameDirectory, (const ams::fssrv::sf::Path &old_path, const ams::fssrv::sf::Path &new_path), (old_path, new_path)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetEntryType, (ams::sf::Out<u32> out, const ams::fssrv::sf::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFile, (ams::sf::Out<ams::sf::SharedPointer<ams::fssrv::sf::IFile>> out, const ams::fssrv::sf::Path &path, u32 mode), (out, path, mode)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDirectory, (ams::sf::Out<ams::sf::SharedPointer<ams::fssrv::sf::IDirectory>> out, const ams::fssrv::sf::Path &path, u32 mode), (out, path, mode)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, Commit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetFreeSpaceSize, (ams::sf::Out<s64> out, const ams::fssrv::sf::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetTotalSpaceSize, (ams::sf::Out<s64> out, const ams::fssrv::sf::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, CleanDirectoryRecursively, (const ams::fssrv::sf::Path &path), (path), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 14, Result, GetFileTimeStampRaw, (ams::sf::Out<ams::fs::FileTimeStampRaw> out, const ams::fssrv::sf::Path &path), (out, path), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 15, Result, QueryEntry, (const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 query_id, const ams::fssrv::sf::Path &path), (out_buf, in_buf, query_id, path), hos::Version_4_0_0) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystem, AMS_FSSRV_I_FILESYSTEM_INTERFACE_INFO, 0xD4EA59E7) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_istorage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_query_range.hpp> /* ACCURATE_TO_VERSION: 13.4.0.0 */ #define AMS_FSSRV_I_STORAGE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Read, (s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Write, (s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size), (offset, buffer, size)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Flush, (), ()) \ AMS_SF_METHOD_INFO(C, H, 3, Result, SetSize, (s64 size), (size)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetSize, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, OperateRange, (ams::sf::Out<ams::fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size), (out, op_id, offset, size), hos::Version_4_0_0) AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IStorage, AMS_FSSRV_I_STORAGE_INTERFACE_INFO, 0xC4D2CAEB) ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_path.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::fssrv::sf { /* ACCURATE_TO_VERSION: 13.4.0.0 */ struct Path : public ams::sf::LargeData { char str[fs::EntryNameLengthMax + 1]; static constexpr Path Encode(const char *p) { Path path = {}; for (size_t i = 0; i < sizeof(path) - 1; i++) { path.str[i] = p[i]; if (p[i] == '\x00') { break; } } return path; } static constexpr size_t GetPathLength(const Path &path) { size_t len = 0; for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) { len++; } return len; } }; static_assert(util::is_pod<Path>::value); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(Path) == FS_MAX_PATH); #endif using FspPath = Path; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssrv.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssrv/sf/fssrv_sf_path.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_ifile.hpp> #include <stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp> #include <stratosphere/fssrv/impl/fssrv_impl_program_index_map_info_manager.hpp> #include <stratosphere/fssrv/impl/fssrv_access_control.hpp> #include <stratosphere/fssrv/fssrv_nca_crypto_configuration.hpp> #include <stratosphere/fssrv/fssrv_memory_resource_from_standard_allocator.hpp> #include <stratosphere/fssrv/fssrv_memory_resource_from_exp_heap.hpp> #include <stratosphere/fssrv/fssrv_i_file_system_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_partition_file_system_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_rom_file_system_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_local_file_system_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_subdirectory_file_system_creator.hpp> #include <stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp> #include <stratosphere/fssrv/fssrv_file_system_proxy_server_session_resource_manager.hpp> #include <stratosphere/fssrv/impl/fssrv_file_system_proxy_service_object.hpp> #include <stratosphere/fssrv/fssrv_file_system_proxy_api.hpp> #include <stratosphere/fssrv/fssrv_program_registry_impl.hpp> #include <stratosphere/fssrv/fssrv_program_registry_service.hpp> #include <stratosphere/fssrv/fssrv_nca_file_system_service_impl.hpp> #include <stratosphere/fssrv/impl/fssrv_external_key_manager.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_buffer_manager_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> namespace ams::fssystem::buffers { namespace impl { constexpr inline auto RetryWait = TimeSpan::FromMilliSeconds(10); } /* ACCURATE_TO_VERSION: Unknown */ template<typename F, typename OnFailure> Result DoContinuouslyUntilBufferIsAllocated(F f, OnFailure on_failure, const char *function_name) { constexpr auto BufferAllocationRetryLogCountMax = 10; constexpr auto BufferAllocationRetryLogInterval = 100; for (auto count = 1; true; count++) { R_TRY_CATCH(f()) { R_CATCH(fs::ResultBufferAllocationFailed) { if ((1 <= count && count <= BufferAllocationRetryLogCountMax) || ((count % BufferAllocationRetryLogInterval) == 0)) { /* TODO: Log */ AMS_UNUSED(function_name); } R_TRY(on_failure()); os::SleepThread(impl::RetryWait); continue; } } R_END_TRY_CATCH; R_SUCCEED(); } } template<typename F> Result DoContinuouslyUntilBufferIsAllocated(F f, const char *function_name) { R_TRY(DoContinuouslyUntilBufferIsAllocated(f, []() ALWAYS_INLINE_LAMBDA { R_SUCCEED(); }, function_name)); R_SUCCEED(); } /* ACCURATE_TO_VERSION: Unknown */ class BufferManagerContext { private: bool m_needs_blocking; public: constexpr BufferManagerContext() : m_needs_blocking(false) { /* ... */ } public: bool IsNeedBlocking() const { return m_needs_blocking; } void SetNeedBlocking(bool need) { m_needs_blocking = need; } }; void RegisterBufferManagerContext(const BufferManagerContext *context); BufferManagerContext *GetBufferManagerContext(); void EnableBlockingBufferManagerAllocation(); /* ACCURATE_TO_VERSION: Unknown */ class ScopedBufferManagerContextRegistration { private: BufferManagerContext m_cur_context; const BufferManagerContext *m_old_context; public: ALWAYS_INLINE explicit ScopedBufferManagerContextRegistration() { m_old_context = GetBufferManagerContext(); if (m_old_context != nullptr) { m_cur_context = *m_old_context; } RegisterBufferManagerContext(std::addressof(m_cur_context)); } ALWAYS_INLINE ~ScopedBufferManagerContextRegistration() { RegisterBufferManagerContext(m_old_context); } }; /* ACCURATE_TO_VERSION: Unknown */ template<typename IsValidBufferFunction> Result AllocateBufferUsingBufferManagerContext(fs::IBufferManager::MemoryRange *out, fs::IBufferManager *buffer_manager, size_t size, const fs::IBufferManager::BufferAttribute attribute, IsValidBufferFunction is_valid_buffer, const char *func_name) { AMS_ASSERT(out != nullptr); AMS_ASSERT(buffer_manager != nullptr); AMS_ASSERT(func_name != nullptr); /* Clear the output. */ *out = fs::IBufferManager::MakeMemoryRange(0, 0); /* Get the context. */ auto context = GetBufferManagerContext(); auto AllocateBufferImpl = [=]() -> Result { auto buffer = buffer_manager->AllocateBuffer(size, attribute); if (!is_valid_buffer(buffer)) { if (buffer.first != 0) { buffer_manager->DeallocateBuffer(buffer.first, buffer.second); } R_THROW(fs::ResultBufferAllocationFailed()); } *out = buffer; R_SUCCEED(); }; if (context == nullptr || !context->IsNeedBlocking()) { /* If there's no context (or we don't need to block), just allocate the buffer. */ R_TRY(AllocateBufferImpl()); } else { /* Otherwise, try to allocate repeatedly. */ R_TRY(DoContinuouslyUntilBufferIsAllocated(AllocateBufferImpl, func_name)); } AMS_ASSERT(out->first != 0); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buddy_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class FileSystemBuddyHeap { NON_COPYABLE(FileSystemBuddyHeap); NON_MOVEABLE(FileSystemBuddyHeap); public: static constexpr size_t BufferAlignment = sizeof(void *); static constexpr size_t BlockSizeMin = 2 * sizeof(void *); static constexpr s32 OrderUpperLimit = BITSIZEOF(s32) - 1; private: class PageList; struct PageEntry { PageEntry *next; }; static_assert(util::is_pod<PageEntry>::value); static_assert(sizeof(PageEntry) <= BlockSizeMin); class PageList : public ::ams::fs::impl::Newable { NON_COPYABLE(PageList); NON_MOVEABLE(PageList); private: PageEntry *m_first_page_entry; PageEntry *m_last_page_entry; s32 m_entry_count; public: constexpr PageList() : m_first_page_entry(), m_last_page_entry(), m_entry_count() { /* ... */ } constexpr bool IsEmpty() const { return m_entry_count == 0; } constexpr s32 GetSize() const { return m_entry_count; } constexpr const PageEntry *GetFront() const { return m_first_page_entry; } public: PageEntry *PopFront(); void PushBack(PageEntry *page_entry); bool Remove(PageEntry *page_entry); }; private: size_t m_block_size; s32 m_order_max; uintptr_t m_heap_start; size_t m_heap_size; PageList *m_free_lists; size_t m_total_free_size; PageList *m_external_free_lists; std::unique_ptr<PageList[]> m_internal_free_lists; public: static constexpr s32 GetBlockCountFromOrder(s32 order) { AMS_ASSERT(0 <= order); AMS_ASSERT(order < OrderUpperLimit); return (1 << order); } static constexpr size_t QueryWorkBufferSize(s32 order_max) { AMS_ASSERT(0 < order_max && order_max < OrderUpperLimit); return util::AlignUp(sizeof(PageList) * (order_max + 1) + alignof(PageList), alignof(u64)); } static constexpr s32 QueryOrderMax(size_t size, size_t block_size) { AMS_ASSERT(size >= block_size); AMS_ASSERT(block_size >= BlockSizeMin); AMS_ASSERT(util::IsPowerOfTwo(block_size)); const auto block_count = static_cast<s32>(util::AlignUp(size, block_size) / block_size); for (auto order = 1; true; order++) { if (block_count <= GetBlockCountFromOrder(order)) { return order; } } } public: constexpr FileSystemBuddyHeap() : m_block_size(), m_order_max(), m_heap_start(), m_heap_size(), m_free_lists(), m_total_free_size(), m_external_free_lists(), m_internal_free_lists() { /* ... */ } Result Initialize(uintptr_t address, size_t size, size_t block_size, s32 order_max); Result Initialize(uintptr_t address, size_t size, size_t block_size) { R_RETURN(this->Initialize(address, size, block_size, QueryOrderMax(size, block_size))); } Result Initialize(uintptr_t address, size_t size, size_t block_size, s32 order_max, void *work, size_t work_size) { AMS_ASSERT(work_size >= QueryWorkBufferSize(order_max)); AMS_UNUSED(work_size); const auto aligned_work = util::AlignUp(reinterpret_cast<uintptr_t>(work), alignof(PageList)); m_external_free_lists = reinterpret_cast<PageList *>(aligned_work); R_RETURN(this->Initialize(address, size, block_size, order_max)); } Result Initialize(uintptr_t address, size_t size, size_t block_size, void *work, size_t work_size) { R_RETURN(this->Initialize(address, size, block_size, QueryOrderMax(size, block_size), work, work_size)); } void Finalize(); void *AllocateByOrder(s32 order); void Free(void *ptr, s32 order); size_t GetTotalFreeSize() const; size_t GetAllocatableSizeMax() const; void Dump() const; s32 GetOrderFromBytes(size_t size) const { AMS_ASSERT(m_free_lists != nullptr); return this->GetOrderFromBlockCount(this->GetBlockCountFromSize(size)); } size_t GetBytesFromOrder(s32 order) const { AMS_ASSERT(m_free_lists != nullptr); AMS_ASSERT(0 <= order); AMS_ASSERT(order <= this->GetOrderMax()); return (this->GetBlockSize() << order); } s32 GetOrderMax() const { AMS_ASSERT(m_free_lists != nullptr); return m_order_max; } size_t GetBlockSize() const { AMS_ASSERT(m_free_lists != nullptr); return m_block_size; } s32 GetPageBlockCountMax() const { AMS_ASSERT(m_free_lists != nullptr); return 1 << this->GetOrderMax(); } size_t GetPageSizeMax() const { AMS_ASSERT(m_free_lists != nullptr); return this->GetPageBlockCountMax() * this->GetBlockSize(); } private: void DivideBuddies(PageEntry *page_entry, s32 required_order, s32 chosen_order); void JoinBuddies(PageEntry *page_entry, s32 order); PageEntry *GetBuddy(PageEntry *page_entry, s32 order); PageEntry *GetFreePageEntry(s32 order); s32 GetOrderFromBlockCount(s32 block_count) const; s32 GetBlockCountFromSize(size_t size) const { const size_t bsize = this->GetBlockSize(); return static_cast<s32>(util::AlignUp(size, bsize) / bsize); } uintptr_t GetAddressFromPageEntry(const PageEntry &page_entry) const { const uintptr_t address = reinterpret_cast<uintptr_t>(std::addressof(page_entry)); AMS_ASSERT(m_heap_start <= address); AMS_ASSERT(address < m_heap_start + m_heap_size); AMS_ASSERT(util::IsAligned(address - m_heap_start, this->GetBlockSize())); return address; } PageEntry *GetPageEntryFromAddress(uintptr_t address) const { AMS_ASSERT(m_heap_start <= address); AMS_ASSERT(address < m_heap_start + m_heap_size); return reinterpret_cast<PageEntry *>(m_heap_start + util::AlignDown(address - m_heap_start, this->GetBlockSize())); } s32 GetIndexFromPageEntry(const PageEntry &page_entry) const { const uintptr_t address = reinterpret_cast<uintptr_t>(std::addressof(page_entry)); AMS_ASSERT(m_heap_start <= address); AMS_ASSERT(address < m_heap_start + m_heap_size); AMS_ASSERT(util::IsAligned(address - m_heap_start, this->GetBlockSize())); return static_cast<s32>((address - m_heap_start) / this->GetBlockSize()); } bool IsAlignedToOrder(const PageEntry *page_entry, s32 order) const { return util::IsAligned(GetIndexFromPageEntry(*page_entry), GetBlockCountFromOrder(order)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lmem.hpp> #include <stratosphere/fs/fs_memory_management.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> #include <stratosphere/fssystem/buffers/fssystem_file_system_buddy_heap.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class FileSystemBufferManager : public fs::IBufferManager { NON_COPYABLE(FileSystemBufferManager); NON_MOVEABLE(FileSystemBufferManager); public: using BuddyHeap = FileSystemBuddyHeap; private: class CacheHandleTable { NON_COPYABLE(CacheHandleTable); NON_MOVEABLE(CacheHandleTable); private: class Entry { private: CacheHandle m_handle; uintptr_t m_address; size_t m_size; BufferAttribute m_attr; public: constexpr void Initialize(CacheHandle h, uintptr_t a, size_t sz, BufferAttribute t) { m_handle = h; m_address = a; m_size = sz; m_attr = t; } constexpr CacheHandle GetHandle() const { return m_handle; } constexpr uintptr_t GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr BufferAttribute GetBufferAttribute() const { return m_attr; } }; class AttrInfo : public util::IntrusiveListBaseNode<AttrInfo>, public ::ams::fs::impl::Newable { NON_COPYABLE(AttrInfo); NON_MOVEABLE(AttrInfo); private: s32 m_level; s32 m_cache_count; size_t m_cache_size; public: constexpr AttrInfo(s32 l, s32 cc, size_t cs) : m_level(l), m_cache_count(cc), m_cache_size(cs) { /* ... */ } constexpr s32 GetLevel() const { return m_level; } constexpr s32 GetCacheCount() const { return m_cache_count; } constexpr void IncrementCacheCount() { ++m_cache_count; } constexpr void DecrementCacheCount() { --m_cache_count; } constexpr size_t GetCacheSize() const { return m_cache_size; } constexpr void AddCacheSize(size_t diff) { m_cache_size += diff; } constexpr void SubtractCacheSize(size_t diff) { AMS_ASSERT(m_cache_size >= diff); m_cache_size -= diff; } using Newable::operator new; using Newable::operator delete; static ALWAYS_INLINE void *operator new(size_t, void *p) noexcept { return p; } static ALWAYS_INLINE void operator delete(void *, size_t, void*) noexcept { /* ... */ } }; using AttrListTraits = util::IntrusiveListBaseTraits<AttrInfo>; using AttrList = typename AttrListTraits::ListType; private: std::unique_ptr<char[], ::ams::fs::impl::Deleter> m_internal_entry_buffer; char *m_external_entry_buffer; size_t m_entry_buffer_size; Entry *m_entries; s32 m_entry_count; s32 m_entry_count_max; AttrList m_attr_list; char *m_external_attr_info_buffer; s32 m_external_attr_info_count; s32 m_cache_count_min; size_t m_cache_size_min; size_t m_total_cache_size; CacheHandle m_current_handle; public: static constexpr size_t QueryWorkBufferSize(s32 max_cache_count) { AMS_ASSERT(max_cache_count > 0); const auto entry_size = sizeof(Entry) * max_cache_count; const auto attr_list_size = sizeof(AttrInfo) * 0x100; return util::AlignUp(entry_size + attr_list_size + alignof(Entry) + alignof(AttrInfo), 8); } public: CacheHandleTable() : m_internal_entry_buffer(), m_external_entry_buffer(), m_entry_buffer_size(), m_entries(), m_entry_count(), m_entry_count_max(), m_attr_list(), m_external_attr_info_buffer(), m_external_attr_info_count(), m_cache_count_min(), m_cache_size_min(), m_total_cache_size(), m_current_handle() { /* ... */ } ~CacheHandleTable() { this->Finalize(); } Result Initialize(s32 max_cache_count); Result Initialize(s32 max_cache_count, void *work, size_t work_size) { const auto aligned_entry_buf = util::AlignUp(reinterpret_cast<uintptr_t>(work), alignof(Entry)); m_external_entry_buffer = reinterpret_cast<char *>(aligned_entry_buf); m_entry_buffer_size = sizeof(Entry) * max_cache_count; const auto aligned_attr_info_buf = util::AlignUp(reinterpret_cast<uintptr_t>(m_external_entry_buffer + m_entry_buffer_size), alignof(AttrInfo)); const auto work_end = reinterpret_cast<uintptr_t>(work) + work_size; m_external_attr_info_buffer = reinterpret_cast<char *>(aligned_attr_info_buf); m_external_attr_info_count = static_cast<s32>((work_end - aligned_attr_info_buf) / sizeof(AttrInfo)); R_SUCCEED(); } void Finalize(); bool Register(CacheHandle *out, uintptr_t address, size_t size, const BufferAttribute &attr); bool Unregister(uintptr_t *out_address, size_t *out_size, CacheHandle handle); bool UnregisterOldest(uintptr_t *out_address, size_t *out_size, const BufferAttribute &attr, size_t required_size = 0); CacheHandle PublishCacheHandle(); size_t GetTotalCacheSize() const; private: void UnregisterCore(uintptr_t *out_address, size_t *out_size, Entry *entry); Entry *AcquireEntry(uintptr_t address, size_t size, const BufferAttribute &attr); void ReleaseEntry(Entry *entry); AttrInfo *FindAttrInfo(const BufferAttribute &attr); s32 GetCacheCountMin(const BufferAttribute &attr) { AMS_UNUSED(attr); return m_cache_count_min; } size_t GetCacheSizeMin(const BufferAttribute &attr) { AMS_UNUSED(attr); return m_cache_size_min; } }; private: BuddyHeap m_buddy_heap; CacheHandleTable m_cache_handle_table; size_t m_total_size; size_t m_peak_free_size; size_t m_peak_total_allocatable_size; size_t m_retried_count; mutable os::SdkMutex m_mutex; public: static constexpr size_t QueryWorkBufferSize(s32 max_cache_count, s32 max_order) { const auto buddy_size = FileSystemBuddyHeap::QueryWorkBufferSize(max_order); const auto table_size = CacheHandleTable::QueryWorkBufferSize(max_cache_count); return buddy_size + table_size; } public: FileSystemBufferManager() : m_total_size(), m_peak_free_size(), m_peak_total_allocatable_size(), m_retried_count(), m_mutex() { /* ... */ } virtual ~FileSystemBufferManager() { /* ... */ } Result Initialize(s32 max_cache_count, uintptr_t address, size_t buffer_size, size_t block_size) { AMS_ASSERT(buffer_size > 0); R_TRY(m_cache_handle_table.Initialize(max_cache_count)); R_TRY(m_buddy_heap.Initialize(address, buffer_size, block_size)); m_total_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = m_total_size; m_peak_total_allocatable_size = m_total_size; R_SUCCEED(); } Result Initialize(s32 max_cache_count, uintptr_t address, size_t buffer_size, size_t block_size, s32 max_order) { AMS_ASSERT(buffer_size > 0); R_TRY(m_cache_handle_table.Initialize(max_cache_count)); R_TRY(m_buddy_heap.Initialize(address, buffer_size, block_size, max_order)); m_total_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = m_total_size; m_peak_total_allocatable_size = m_total_size; R_SUCCEED(); } Result Initialize(s32 max_cache_count, uintptr_t address, size_t buffer_size, size_t block_size, void *work, size_t work_size) { const auto table_size = CacheHandleTable::QueryWorkBufferSize(max_cache_count); const auto buddy_size = work_size - table_size; AMS_ASSERT(work_size > table_size); const auto table_buffer = static_cast<char *>(work); const auto buddy_buffer = table_buffer + table_size; R_TRY(m_cache_handle_table.Initialize(max_cache_count, table_buffer, table_size)); R_TRY(m_buddy_heap.Initialize(address, buffer_size, block_size, buddy_buffer, buddy_size)); m_total_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = m_total_size; m_peak_total_allocatable_size = m_total_size; R_SUCCEED(); } Result Initialize(s32 max_cache_count, uintptr_t address, size_t buffer_size, size_t block_size, s32 max_order, void *work, size_t work_size) { const auto table_size = CacheHandleTable::QueryWorkBufferSize(max_cache_count); const auto buddy_size = work_size - table_size; AMS_ASSERT(work_size > table_size); const auto table_buffer = static_cast<char *>(work); const auto buddy_buffer = table_buffer + table_size; R_TRY(m_cache_handle_table.Initialize(max_cache_count, table_buffer, table_size)); R_TRY(m_buddy_heap.Initialize(address, buffer_size, block_size, max_order, buddy_buffer, buddy_size)); m_total_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = m_total_size; m_peak_total_allocatable_size = m_total_size; R_SUCCEED(); } void Finalize() { m_buddy_heap.Finalize(); m_cache_handle_table.Finalize(); } private: virtual const fs::IBufferManager::MemoryRange DoAllocateBuffer(size_t size, const BufferAttribute &attr) override; virtual void DoDeallocateBuffer(uintptr_t address, size_t size) override; virtual CacheHandle DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) override; virtual const fs::IBufferManager::MemoryRange DoAcquireCache(CacheHandle handle) override; virtual size_t DoGetTotalSize() const override; virtual size_t DoGetFreeSize() const override; virtual size_t DoGetTotalAllocatableSize() const override; virtual size_t DoGetFreeSizePeak() const override; virtual size_t DoGetTotalAllocatableSizePeak() const override; virtual size_t DoGetRetriedCount() const override; virtual void DoClearPeak() override; private: const fs::IBufferManager::MemoryRange AllocateBufferImpl(size_t size, const BufferAttribute &attr); void DeallocateBufferImpl(uintptr_t address, size_t size); CacheHandle RegisterCacheImpl(uintptr_t address, size_t size, const BufferAttribute &attr); const fs::IBufferManager::MemoryRange AcquireCacheImpl(CacheHandle handle); size_t GetFreeSizeImpl() const; size_t GetTotalAllocatableSizeImpl() const; size_t GetFreeSizePeakImpl() const; size_t GetTotalAllocatableSizePeakImpl() const; size_t GetRetriedCountImpl() const; void ClearPeakImpl(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_aes_ctr_counter_extended_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_aes_ctr_storage.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class AesCtrCounterExtendedStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AesCtrCounterExtendedStorage); NON_MOVEABLE(AesCtrCounterExtendedStorage); public: static constexpr size_t BlockSize = crypto::Aes128CtrEncryptor::BlockSize; static constexpr size_t KeySize = crypto::Aes128CtrEncryptor::KeySize; static constexpr size_t IvSize = crypto::Aes128CtrEncryptor::IvSize; static constexpr size_t NodeSize = 16_KB; using IAllocator = BucketTree::IAllocator; using DecryptFunction = void(*)(void *dst, size_t dst_size, u8 index, u8 gen, const void *enc_key, size_t enc_key_size, const void *iv, size_t iv_size, const void *src, size_t src_size); class IDecryptor { public: virtual ~IDecryptor() { /* ... */ } virtual void Decrypt(void *buf, size_t buf_size, const void *enc_key, size_t enc_key_size, void *iv, size_t iv_size) = 0; virtual bool HasExternalDecryptionKey() const = 0; }; struct Entry { enum class Encryption : u8 { Encrypted = 0, NotEncrypted = 1, }; u8 offset[sizeof(s64)]; Encryption encryption_value; u8 reserved[3]; s32 generation; void SetOffset(s64 value) { std::memcpy(this->offset, std::addressof(value), sizeof(s64)); } s64 GetOffset() const { s64 value; std::memcpy(std::addressof(value), this->offset, sizeof(s64)); return value; } }; static_assert(sizeof(Entry) == 0x10); static_assert(alignof(Entry) == 4); static_assert(util::is_pod<Entry>::value); public: static constexpr s64 QueryHeaderStorageSize() { return BucketTree::QueryHeaderStorageSize(); } static constexpr s64 QueryNodeStorageSize(s32 entry_count) { return BucketTree::QueryNodeStorageSize(NodeSize, sizeof(Entry), entry_count); } static constexpr s64 QueryEntryStorageSize(s32 entry_count) { return BucketTree::QueryEntryStorageSize(NodeSize, sizeof(Entry), entry_count); } static Result CreateExternalDecryptor(std::unique_ptr<IDecryptor> *out, DecryptFunction func, s32 key_index, s32 key_generation); static Result CreateSoftwareDecryptor(std::unique_ptr<IDecryptor> *out); private: BucketTree m_table; fs::SubStorage m_data_storage; u8 m_key[KeySize]; u32 m_secure_value; s64 m_counter_offset; std::unique_ptr<IDecryptor> m_decryptor; public: AesCtrCounterExtendedStorage() : m_table(), m_data_storage(), m_secure_value(), m_counter_offset(), m_decryptor() { /* ... */ } virtual ~AesCtrCounterExtendedStorage() { this->Finalize(); } Result Initialize(IAllocator *allocator, const void *key, size_t key_size, u32 secure_value, s64 counter_offset, fs::SubStorage data_storage, fs::SubStorage node_storage, fs::SubStorage entry_storage, s32 entry_count, std::unique_ptr<IDecryptor> &&decryptor); void Finalize(); bool IsInitialized() const { return m_table.IsInitialized(); } virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); BucketTree::Offsets offsets; R_TRY(m_table.GetOffsets(std::addressof(offsets))); *out = offsets.end_offset; R_SUCCEED(); } virtual Result Flush() override { R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { AMS_UNUSED(offset, buffer, size); R_THROW(fs::ResultUnsupportedWriteForAesCtrCounterExtendedStorage()); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForAesCtrCounterExtendedStorage()); } Result GetEntryList(Entry *out_entries, s32 *out_entry_count, s32 entry_count, s64 offset, s64 size); private: Result Initialize(IAllocator *allocator, const void *key, size_t key_size, u32 secure_value, fs::SubStorage data_storage, fs::SubStorage table_storage); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_aes_ctr_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ template<fs::PointerToStorage BasePointer> class AesCtrStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AesCtrStorage); NON_MOVEABLE(AesCtrStorage); public: static constexpr size_t BlockSize = crypto::Aes128CtrEncryptor::BlockSize; static constexpr size_t KeySize = crypto::Aes128CtrEncryptor::KeySize; static constexpr size_t IvSize = crypto::Aes128CtrEncryptor::IvSize; private: BasePointer m_base_storage; char m_key[KeySize]; char m_iv[IvSize]; public: static void MakeIv(void *dst, size_t dst_size, u64 upper, s64 offset); public: AesCtrStorage(BasePointer base, const void *key, size_t key_size, const void *iv, size_t iv_size); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; virtual Result SetSize(s64 size) override; virtual Result GetSize(s64 *out) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; using AesCtrStorageByPointer = AesCtrStorage<fs::IStorage *>; using AesCtrStorageBySharedPointer = AesCtrStorage<std::shared_ptr<fs::IStorage>>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_aes_ctr_storage_external.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ class AesCtrStorageExternal : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AesCtrStorageExternal); NON_MOVEABLE(AesCtrStorageExternal); public: static constexpr size_t BlockSize = crypto::Aes128CtrEncryptor::BlockSize; static constexpr size_t KeySize = crypto::Aes128CtrEncryptor::KeySize; static constexpr size_t IvSize = crypto::Aes128CtrEncryptor::IvSize; private: std::shared_ptr<fs::IStorage> m_base_storage; u8 m_iv[IvSize]; DecryptAesCtrFunction m_decrypt_function; s32 m_key_index; s32 m_key_generation; u8 m_encrypted_key[KeySize]; public: AesCtrStorageExternal(std::shared_ptr<fs::IStorage> bs, const void *enc_key, size_t enc_key_size, const void *iv, size_t iv_size, DecryptAesCtrFunction df, s32 kidx, s32 kgen); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; virtual Result GetSize(s64 *out) override; virtual Result Flush() override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result SetSize(s64 size) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_aes_xts_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/os.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ template<fs::PointerToStorage BasePointer> class AesXtsStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AesXtsStorage); NON_MOVEABLE(AesXtsStorage); public: static constexpr size_t AesBlockSize = crypto::Aes128XtsEncryptor::BlockSize; static constexpr size_t KeySize = crypto::Aes128XtsEncryptor::KeySize; static constexpr size_t IvSize = crypto::Aes128XtsEncryptor::IvSize; private: BasePointer m_base_storage; char m_key[2][KeySize]; char m_iv[IvSize]; const size_t m_block_size; os::SdkMutex m_mutex; public: static void MakeAesXtsIv(void *dst, size_t dst_size, s64 offset, size_t block_size); public: AesXtsStorage(BasePointer base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result Flush() override; virtual Result SetSize(s64 size) override; virtual Result GetSize(s64 *out) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; using AesXtsStorageByPointer = AesXtsStorage<fs::IStorage *>; using AesXtsStorageBySharedPointer = AesXtsStorage<std::shared_ptr<fs::IStorage>>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_aes_xts_storage_external.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ template<fs::PointerToStorage BasePointer> class AesXtsStorageExternal : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AesXtsStorageExternal); NON_MOVEABLE(AesXtsStorageExternal); public: static constexpr size_t AesBlockSize = crypto::Aes128XtsEncryptor::BlockSize; static constexpr size_t KeySize = crypto::Aes128XtsEncryptor::KeySize; static constexpr size_t IvSize = crypto::Aes128XtsEncryptor::IvSize; private: BasePointer m_base_storage; char m_key[2][KeySize]; char m_iv[IvSize]; const size_t m_block_size; CryptAesXtsFunction m_encrypt_function; CryptAesXtsFunction m_decrypt_function; public: AesXtsStorageExternal(BasePointer bs, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size, CryptAesXtsFunction ef, CryptAesXtsFunction df); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; virtual Result GetSize(s64 *out) override; virtual Result Flush() override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result SetSize(s64 size) override; }; using AesXtsStorageExternalByPointer = AesXtsStorageExternal<fs::IStorage *>; using AesXtsStorageExternalBySharedPointer = AesXtsStorageExternal<std::shared_ptr<fs::IStorage>>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssystem/fssystem_alignment_matching_storage_impl.hpp> #include <stratosphere/fssystem/fssystem_pooled_buffer.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ template<size_t _DataAlign, size_t _BufferAlign> class AlignmentMatchingStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AlignmentMatchingStorage); NON_MOVEABLE(AlignmentMatchingStorage); public: static constexpr size_t DataAlign = _DataAlign; static constexpr size_t BufferAlign = _BufferAlign; static constexpr size_t DataAlignMax = 0x200; static_assert(DataAlign <= DataAlignMax); static_assert(util::IsPowerOfTwo(DataAlign)); static_assert(util::IsPowerOfTwo(BufferAlign)); private: std::shared_ptr<fs::IStorage> m_shared_base_storage; fs::IStorage * const m_base_storage; s64 m_base_storage_size; bool m_is_base_storage_size_dirty; public: explicit AlignmentMatchingStorage(fs::IStorage *bs) : m_base_storage(bs), m_is_base_storage_size_dirty(true) { /* ... */ } explicit AlignmentMatchingStorage(std::shared_ptr<fs::IStorage> bs) : m_shared_base_storage(std::move(bs)), m_base_storage(m_shared_base_storage.get()), m_is_base_storage_size_dirty(true) { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Allocate a work buffer on stack. */ __attribute__((aligned(DataAlignMax))) char work_buf[DataAlign]; static_assert(util::IsAligned(alignof(work_buf), BufferAlign)); /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); R_RETURN(AlignmentMatchingStorageImpl::Read(m_base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast<char *>(buffer), size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* Allocate a work buffer on stack. */ __attribute__((aligned(DataAlignMax))) char work_buf[DataAlign]; static_assert(util::IsAligned(alignof(work_buf), BufferAlign)); /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); R_RETURN(AlignmentMatchingStorageImpl::Write(m_base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast<const char *>(buffer), size)); } virtual Result Flush() override { R_RETURN(m_base_storage->Flush()); } virtual Result SetSize(s64 size) override { ON_SCOPE_EXIT { m_is_base_storage_size_dirty = true; }; R_RETURN(m_base_storage->SetSize(util::AlignUp(size, DataAlign))); } virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); if (m_is_base_storage_size_dirty) { s64 size; R_TRY(m_base_storage->GetSize(std::addressof(size))); m_base_storage_size = size; m_is_base_storage_size_dirty = false; } *out = m_base_storage_size; R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { if (op_id == fs::OperationId::Invalidate) { R_RETURN(m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size)); } else { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); const auto aligned_offset = util::AlignDown(offset, DataAlign); const auto aligned_offset_end = util::AlignUp(offset + valid_size, DataAlign); const auto aligned_size = aligned_offset_end - aligned_offset; R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size)); } } }; /* ACCURATE_TO_VERSION: Unknown */ template<fs::PointerToStorage BasePointer, size_t _BufferAlign> class AlignmentMatchingStoragePooledBuffer : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AlignmentMatchingStoragePooledBuffer); NON_MOVEABLE(AlignmentMatchingStoragePooledBuffer); public: static constexpr size_t BufferAlign = _BufferAlign; static_assert(util::IsPowerOfTwo(BufferAlign)); private: BasePointer m_base_storage; s64 m_base_storage_size; size_t m_data_align; bool m_is_base_storage_size_dirty; public: explicit AlignmentMatchingStoragePooledBuffer(BasePointer bs, size_t da) : m_base_storage(std::move(bs)), m_data_align(da), m_is_base_storage_size_dirty(true) { AMS_ASSERT(util::IsPowerOfTwo(da)); } virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); R_RETURN(AlignmentMatchingStorageImpl::Read(m_base_storage, pooled_buffer.GetBuffer(), pooled_buffer.GetSize(), m_data_align, BufferAlign, offset, static_cast<char *>(buffer), size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); R_RETURN(AlignmentMatchingStorageImpl::Write(m_base_storage, pooled_buffer.GetBuffer(), pooled_buffer.GetSize(), m_data_align, BufferAlign, offset, static_cast<const char *>(buffer), size)); } virtual Result Flush() override { R_RETURN(m_base_storage->Flush()); } virtual Result SetSize(s64 size) override { ON_SCOPE_EXIT { m_is_base_storage_size_dirty = true; }; R_RETURN(m_base_storage->SetSize(util::AlignUp(size, m_data_align))); } virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); if (m_is_base_storage_size_dirty) { s64 size; R_TRY(m_base_storage->GetSize(std::addressof(size))); m_base_storage_size = size; m_is_base_storage_size_dirty = false; } *out = m_base_storage_size; R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { if (op_id == fs::OperationId::Invalidate) { R_RETURN(m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size)); } else { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); const auto aligned_offset = util::AlignDown(offset, m_data_align); const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align); const auto aligned_size = aligned_offset_end - aligned_offset; R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size)); } } }; /* ACCURATE_TO_VERSION: Unknown */ template<size_t _BufferAlign> class AlignmentMatchingStorageInBulkRead : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(AlignmentMatchingStorageInBulkRead); NON_MOVEABLE(AlignmentMatchingStorageInBulkRead); public: static constexpr size_t BufferAlign = _BufferAlign; static_assert(util::IsPowerOfTwo(BufferAlign)); private: std::shared_ptr<fs::IStorage> m_shared_base_storage; fs::IStorage * const m_base_storage; s64 m_base_storage_size; size_t m_data_align; public: explicit AlignmentMatchingStorageInBulkRead(fs::IStorage *bs, size_t da) : m_shared_base_storage(), m_base_storage(bs), m_base_storage_size(-1), m_data_align(da) { AMS_ASSERT(util::IsPowerOfTwo(m_data_align)); } explicit AlignmentMatchingStorageInBulkRead(std::shared_ptr<fs::IStorage> bs, size_t da) : m_shared_base_storage(bs), m_base_storage(m_shared_base_storage.get()), m_base_storage_size(-1), m_data_align(da) { AMS_ASSERT(util::IsPowerOfTwo(da)); } virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer(m_data_align, m_data_align); R_RETURN(AlignmentMatchingStorageImpl::Write(m_base_storage, pooled_buffer.GetBuffer(), pooled_buffer.GetSize(), m_data_align, BufferAlign, offset, static_cast<const char *>(buffer), size)); } virtual Result Flush() override { R_RETURN(m_base_storage->Flush()); } virtual Result SetSize(s64 size) override { ON_SCOPE_EXIT { m_base_storage_size = -1; }; R_RETURN(m_base_storage->SetSize(util::AlignUp(size, m_data_align))); } virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); if (m_base_storage_size < 0) { s64 size; R_TRY(m_base_storage->GetSize(std::addressof(size))); m_base_storage_size = size; } *out = m_base_storage_size; R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { if (op_id == fs::OperationId::Invalidate) { R_RETURN(m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size)); } else { /* Succeed if zero size. */ R_SUCCEED_IF(size == 0); /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); const auto aligned_offset = util::AlignDown(offset, m_data_align); const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align); const auto aligned_size = aligned_offset_end - aligned_offset; R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size)); } } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class AlignmentMatchingStorageImpl { public: static Result Read(fs::IStorage *base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, char *buffer, size_t size); static Result Write(fs::IStorage *base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, const char *buffer, size_t size); static Result Read(std::shared_ptr<fs::IStorage> &base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, char *buffer, size_t size) { R_RETURN(Read(base_storage.get(), work_buf, work_buf_size, data_alignment, buffer_alignment, offset, buffer, size)); } static Result Write(std::shared_ptr<fs::IStorage> &base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, const char *buffer, size_t size) { R_RETURN(Write(base_storage.get(), work_buf, work_buf_size, data_alignment, buffer_alignment, offset, buffer, size)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_allocator_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> /* Forward declare ams::fs allocate shared. */ namespace ams::fs::impl { template<typename T, template<typename, typename> class AllocatorTemplateT, typename Impl, typename... Args> std::shared_ptr<T> AllocateSharedImpl(Args &&... args); } namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ using AllocateFunction = void *(*)(size_t size); using DeallocateFunction = void (*)(void *ptr, size_t size); void InitializeAllocator(AllocateFunction allocate_func, DeallocateFunction deallocate_func); void InitializeAllocatorForSystem(AllocateFunction allocate_func, DeallocateFunction deallocate_func); void *Allocate(size_t size); void Deallocate(void *ptr, size_t size); namespace impl { template<bool ForSystem> class AllocatorFunctionSet { public: static void *Allocate(size_t size); static void *AllocateUnsafe(size_t size); static void Deallocate(void *ptr, size_t size); static void DeallocateUnsafe(void *ptr, size_t size); static void LockAllocatorMutex(); static void UnlockAllocatorMutex(); }; using AllocatorFunctionSetForNormal = AllocatorFunctionSet<false>; using AllocatorFunctionSetForSystem = AllocatorFunctionSet<true>; template<typename T, typename Impl, bool RequireNonNull, bool AllocateWhileLocked> class AllocatorTemplate : public std::allocator<T> { public: template<typename U> struct rebind { using other = AllocatorTemplate<U, Impl, RequireNonNull, AllocateWhileLocked>; }; private: static ALWAYS_INLINE T *AllocateImpl(::std::size_t n) { if constexpr (AllocateWhileLocked) { auto * const p = Impl::AllocateUnsafe(sizeof(T) * n); Impl::UnlockAllocatorMutex(); return static_cast<T *>(p); } else { return static_cast<T *>(Impl::Allocate(sizeof(T) * n)); } } public: AllocatorTemplate() { /* ... */ } template<typename U> AllocatorTemplate(const AllocatorTemplate<U, Impl, RequireNonNull, AllocateWhileLocked> &) { /* ... */ } [[nodiscard]] T *allocate(::std::size_t n) { auto * const p = AllocateImpl(n); if constexpr (RequireNonNull) { AMS_ABORT_UNLESS(p != nullptr); } return p; } void deallocate(T *p, ::std::size_t n) { Impl::Deallocate(p, sizeof(T) * n); } }; template<typename T, typename Impl> using AllocatorTemplateForAllocateShared = AllocatorTemplate<T, Impl, true, true>; } template<typename T, typename... Args> std::shared_ptr<T> AllocateShared(Args &&... args) { return ::ams::fs::impl::AllocateSharedImpl<T, impl::AllocatorTemplateForAllocateShared, impl::AllocatorFunctionSetForNormal>(std::forward<Args>(args)...); } template<typename TImpl, typename ErrorResult, typename TIntf, typename... Args> Result AllocateSharedForSystem(std::shared_ptr<TIntf> *out, Args &&... args) { /* Allocate the object. */ auto p = ::ams::fs::impl::AllocateSharedImpl<TImpl, impl::AllocatorTemplateForAllocateShared, impl::AllocatorFunctionSetForSystem>(std::forward<Args>(args)...); /* Check that allocation succeeded. */ R_UNLESS(p != nullptr, ErrorResult()); /* Return the allocated object. */ *out = std::move(p); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_asynchronous_access.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class IAsynchronousAccessSplitter { public: static IAsynchronousAccessSplitter *GetDefaultAsynchronousAccessSplitter(); public: constexpr IAsynchronousAccessSplitter() = default; constexpr virtual ~IAsynchronousAccessSplitter() { /* ... */ } public: Result QueryNextOffset(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size); public: virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) = 0; virtual Result QueryInvocationCount(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size) { AMS_UNUSED(out, start_offset, end_offset, access_size, alignment_size); AMS_ABORT("TODO"); } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class DefaultAsynchronousAccessSplitter final : public IAsynchronousAccessSplitter { public: constexpr DefaultAsynchronousAccessSplitter() = default; public: virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) override { /* Align the access. */ *out = util::AlignDown(offset + access_size, alignment_size); R_SUCCEED(); } virtual Result QueryInvocationCount(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size) override { /* Determine aligned access count. */ *out = util::DivideUp(end_offset - util::AlignDown(start_offset, alignment_size), access_size); R_SUCCEED(); } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ inline IAsynchronousAccessSplitter *IAsynchronousAccessSplitter::GetDefaultAsynchronousAccessSplitter() { static constinit DefaultAsynchronousAccessSplitter s_default_access_splitter; return std::addressof(s_default_access_splitter); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bitmap_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ constexpr inline s32 CountLeadingZeros(u32 val) { return util::CountLeadingZeros(val); } constexpr inline s32 CountLeadingOnes(u32 val) { return CountLeadingZeros(~val); } inline u32 ReadU32(const u8 *buf, size_t index) { u32 val; std::memcpy(std::addressof(val), buf + index, sizeof(u32)); return val; } inline void WriteU32(u8 *buf, size_t index, u32 val) { std::memcpy(buf + index, std::addressof(val), sizeof(u32)); } constexpr inline bool IsPowerOfTwo(s32 val) { return util::IsPowerOfTwo(val); } constexpr inline u32 ILog2(u32 val) { AMS_ASSERT(val > 0); return (BITSIZEOF(u32) - 1 - util::CountLeadingZeros<u32>(val)); } constexpr inline u32 CeilingPowerOfTwo(u32 val) { if (val == 0) { return 1; } return util::CeilingPowerOfTwo<u32>(val); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_block_cache_buffered_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_storage_type.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_memory_management.hpp> #include <stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp> #include <stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp> namespace ams::fssystem { constexpr inline size_t IntegrityMinLayerCount = 2; constexpr inline size_t IntegrityMaxLayerCount = 7; constexpr inline size_t IntegrityLayerCountSave = 5; constexpr inline size_t IntegrityLayerCountSaveDataMeta = 4; struct FileSystemBufferManagerSet { fs::IBufferManager *buffers[IntegrityMaxLayerCount]; }; static_assert(util::is_pod<FileSystemBufferManagerSet>::value); /* ACCURATE_TO_VERSION: 13.4.0.0 */ class BlockCacheBufferedStorage : public ::ams::fs::IStorage { NON_COPYABLE(BlockCacheBufferedStorage); NON_MOVEABLE(BlockCacheBufferedStorage); public: static constexpr size_t DefaultMaxCacheEntryCount = 24; private: using MemoryRange = fs::IBufferManager::MemoryRange; struct AccessRange { s64 offset; size_t size; s64 GetEndOffset() const { return this->offset + this->size; } bool IsIncluded(s64 ofs) const { return this->offset <= ofs && ofs < this->GetEndOffset(); } }; static_assert(util::is_pod<AccessRange>::value); struct CacheEntry { AccessRange range; bool is_valid; bool is_write_back; bool is_cached; bool is_flushing; u16 lru_counter; fs::IBufferManager::CacheHandle handle; uintptr_t memory_address; size_t memory_size; void Invalidate() { this->is_write_back = false; this->is_flushing = false; } bool IsAllocated() const { return this->is_valid && (this->is_write_back ? this->memory_address != 0 : this->handle != 0); } bool IsWriteBack() const { return this->is_write_back; } }; static_assert(util::is_pod<CacheEntry>::value); using BlockCacheManager = ::ams::fssystem::impl::BlockCacheManager<CacheEntry, fs::IBufferManager>; using CacheIndex = BlockCacheManager::CacheIndex; enum Flag : s32 { Flag_KeepBurstMode = (1 << 8), Flag_RealData = (1 << 10), }; private: os::SdkRecursiveMutex *m_mutex; IStorage *m_data_storage; Result m_last_result; s64 m_data_size; size_t m_verification_block_size; size_t m_verification_block_shift; s32 m_flags; s32 m_buffer_level; BlockCacheManager m_block_cache_manager; bool m_is_writable; public: BlockCacheBufferedStorage(); virtual ~BlockCacheBufferedStorage() override; Result Initialize(fs::IBufferManager *bm, os::SdkRecursiveMutex *mtx, IStorage *data, s64 data_size, size_t verif_block_size, s32 max_cache_entries, bool is_real_data, s8 buffer_level, bool is_keep_burst_mode, bool is_writable); void Finalize(); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result SetSize(s64) override { R_THROW(fs::ResultUnsupportedSetSizeForBlockCacheBufferedStorage()); } virtual Result GetSize(s64 *out) override; virtual Result Flush() override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; using IStorage::OperateRange; Result Commit(); Result OnRollback(); bool IsEnabledKeepBurstMode() const { return (m_flags & Flag_KeepBurstMode) != 0; } bool IsRealDataCache() const { return (m_flags & Flag_RealData) != 0; } void SetKeepBurstMode(bool en) { if (en) { m_flags |= Flag_KeepBurstMode; } else { m_flags &= ~Flag_KeepBurstMode; } } void SetRealDataCache(bool en) { if (en) { m_flags |= Flag_RealData; } else { m_flags &= ~Flag_RealData; } } private: Result FillZeroImpl(s64 offset, s64 size); Result DestroySignatureImpl(s64 offset, s64 size); Result InvalidateImpl(); Result QueryRangeImpl(void *dst, size_t dst_size, s64 offset, s64 size); Result GetAssociateBuffer(MemoryRange *out_range, CacheEntry *out_entry, s64 offset, size_t ideal_size, bool is_allocate_for_write); Result StoreOrDestroyBuffer(CacheIndex *out, const MemoryRange &range, CacheEntry *entry); Result StoreOrDestroyBuffer(const MemoryRange &range, CacheEntry *entry) { AMS_ASSERT(entry != nullptr); CacheIndex dummy; R_RETURN(this->StoreOrDestroyBuffer(std::addressof(dummy), range, entry)); } Result FlushCacheEntry(CacheIndex index, bool invalidate); Result FlushRangeCacheEntries(s64 offset, s64 size, bool invalidate); Result FlushAllCacheEntries(); Result InvalidateAllCacheEntries(); Result ControlDirtiness(); Result UpdateLastResult(Result result); Result ReadHeadCache(MemoryRange *out_range, CacheEntry *out_entry, bool *out_cache_needed, s64 *offset, s64 *aligned_offset, s64 aligned_offset_end, char **buffer, size_t *size); Result ReadTailCache(MemoryRange *out_range, CacheEntry *out_entry, bool *out_cache_needed, s64 offset, s64 aligned_offset, s64 *aligned_offset_end, char *buffer, size_t *size); Result BulkRead(s64 offset, void *buffer, size_t size, MemoryRange *range_head, MemoryRange *range_tail, CacheEntry *entry_head, CacheEntry *entry_tail, bool head_cache_needed, bool tail_cache_needed); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_substorage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class BucketTree { NON_COPYABLE(BucketTree); NON_MOVEABLE(BucketTree); public: static constexpr u32 Magic = util::FourCC<'B','K','T','R'>::Code; static constexpr u32 Version = 1; static constexpr size_t NodeSizeMin = 1_KB; static constexpr size_t NodeSizeMax = 512_KB; public: class Visitor; struct Header { u32 magic; u32 version; s32 entry_count; s32 reserved; void Format(s32 entry_count); Result Verify() const; }; static_assert(util::is_pod<Header>::value); static_assert(sizeof(Header) == 0x10); struct NodeHeader { s32 index; s32 count; s64 offset; Result Verify(s32 node_index, size_t node_size, size_t entry_size) const; }; static_assert(util::is_pod<NodeHeader>::value); static_assert(sizeof(NodeHeader) == 0x10); struct Offsets { s64 start_offset; s64 end_offset; constexpr bool IsInclude(s64 offset) const { return this->start_offset <= offset && offset < this->end_offset; } constexpr bool IsInclude(s64 offset, s64 size) const { return size > 0 && this->start_offset <= offset && size <= (this->end_offset - offset); } }; static_assert(util::is_pod<Offsets>::value); static_assert(sizeof(Offsets) == 0x10); struct OffsetCache { Offsets offsets; os::SdkMutex mutex; bool is_initialized; constexpr OffsetCache() : offsets{ -1, -1 }, mutex(), is_initialized(false) { /* ... */ } }; class ContinuousReadingInfo { private: size_t m_read_size; s32 m_skip_count; bool m_done; public: constexpr ContinuousReadingInfo() : m_read_size(), m_skip_count(), m_done() { /* ... */ } constexpr void Reset() { m_read_size = 0; m_skip_count = 0; m_done = false; } constexpr void SetSkipCount(s32 count) { AMS_ASSERT(count >= 0); m_skip_count = count; } constexpr s32 GetSkipCount() const { return m_skip_count; } constexpr bool CheckNeedScan() { return (--m_skip_count) <= 0; } constexpr void Done() { m_read_size = 0; m_done = true; } constexpr bool IsDone() const { return m_done; } constexpr void SetReadSize(size_t size) { m_read_size = size; } constexpr size_t GetReadSize() const { return m_read_size; } constexpr bool CanDo() const { return m_read_size > 0; } }; using IAllocator = MemoryResource; private: class NodeBuffer { NON_COPYABLE(NodeBuffer); private: IAllocator *m_allocator; void *m_header; public: NodeBuffer() : m_allocator(), m_header() { /* ... */ } ~NodeBuffer() { AMS_ASSERT(m_header == nullptr); } NodeBuffer(NodeBuffer &&rhs) : m_allocator(rhs.m_allocator), m_header(rhs.m_header) { rhs.m_allocator = nullptr; rhs.m_header = nullptr; } NodeBuffer &operator=(NodeBuffer &&rhs) { if (this != std::addressof(rhs)) { AMS_ASSERT(m_header == nullptr); m_allocator = rhs.m_allocator; m_header = rhs.m_header; rhs.m_allocator = nullptr; rhs.m_header = nullptr; } return *this; } bool Allocate(IAllocator *allocator, size_t node_size) { AMS_ASSERT(m_header == nullptr); m_allocator = allocator; m_header = allocator->Allocate(node_size, sizeof(s64)); AMS_ASSERT(util::IsAligned(m_header, sizeof(s64))); return m_header != nullptr; } void Free(size_t node_size) { if (m_header) { m_allocator->Deallocate(m_header, node_size); m_header = nullptr; } m_allocator = nullptr; } void FillZero(size_t node_size) const { if (m_header) { std::memset(m_header, 0, node_size); } } NodeHeader *Get() const { return reinterpret_cast<NodeHeader *>(m_header); } NodeHeader *operator->() const { return this->Get(); } template<typename T> T *Get() const { static_assert(util::is_pod<T>::value); static_assert(sizeof(T) == sizeof(NodeHeader)); return reinterpret_cast<T *>(m_header); } IAllocator *GetAllocator() const { return m_allocator; } }; private: static constexpr s32 GetEntryCount(size_t node_size, size_t entry_size) { return static_cast<s32>((node_size - sizeof(NodeHeader)) / entry_size); } static constexpr s32 GetOffsetCount(size_t node_size) { return static_cast<s32>((node_size - sizeof(NodeHeader)) / sizeof(s64)); } static constexpr s32 GetEntrySetCount(size_t node_size, size_t entry_size, s32 entry_count) { const s32 entry_count_per_node = GetEntryCount(node_size, entry_size); return util::DivideUp(entry_count, entry_count_per_node); } static constexpr s32 GetNodeL2Count(size_t node_size, size_t entry_size, s32 entry_count) { const s32 offset_count_per_node = GetOffsetCount(node_size); const s32 entry_set_count = GetEntrySetCount(node_size, entry_size, entry_count); if (entry_set_count <= offset_count_per_node) { return 0; } const s32 node_l2_count = util::DivideUp(entry_set_count, offset_count_per_node); AMS_ABORT_UNLESS(node_l2_count <= offset_count_per_node); return util::DivideUp(entry_set_count - (offset_count_per_node - (node_l2_count - 1)), offset_count_per_node); } public: static constexpr s64 QueryHeaderStorageSize() { return sizeof(Header); } static constexpr s64 QueryNodeStorageSize(size_t node_size, size_t entry_size, s32 entry_count) { AMS_ASSERT(entry_size >= sizeof(s64)); AMS_ASSERT(node_size >= entry_size + sizeof(NodeHeader)); AMS_ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); AMS_ASSERT(util::IsPowerOfTwo(node_size)); AMS_ASSERT(entry_count >= 0); if (entry_count <= 0) { return 0; } return (1 + GetNodeL2Count(node_size, entry_size, entry_count)) * static_cast<s64>(node_size); } static constexpr s64 QueryEntryStorageSize(size_t node_size, size_t entry_size, s32 entry_count) { AMS_ASSERT(entry_size >= sizeof(s64)); AMS_ASSERT(node_size >= entry_size + sizeof(NodeHeader)); AMS_ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); AMS_ASSERT(util::IsPowerOfTwo(node_size)); AMS_ASSERT(entry_count >= 0); if (entry_count <= 0) { return 0; } return GetEntrySetCount(node_size, entry_size, entry_count) * static_cast<s64>(node_size); } private: mutable fs::SubStorage m_node_storage; mutable fs::SubStorage m_entry_storage; NodeBuffer m_node_l1; size_t m_node_size; size_t m_entry_size; s32 m_entry_count; s32 m_offset_count; s32 m_entry_set_count; OffsetCache m_offset_cache; public: BucketTree() : m_node_storage(), m_entry_storage(), m_node_l1(), m_node_size(), m_entry_size(), m_entry_count(), m_offset_count(), m_entry_set_count(), m_offset_cache() { /* ... */ } ~BucketTree() { this->Finalize(); } Result Initialize(IAllocator *allocator, fs::SubStorage node_storage, fs::SubStorage entry_storage, size_t node_size, size_t entry_size, s32 entry_count); void Initialize(size_t node_size, s64 end_offset); void Finalize(); bool IsInitialized() const { return m_node_size > 0; } bool IsEmpty() const { return m_entry_size == 0; } Result Find(Visitor *visitor, s64 virtual_address); Result InvalidateCache(); s32 GetEntryCount() const { return m_entry_count; } IAllocator *GetAllocator() const { return m_node_l1.GetAllocator(); } Result GetOffsets(Offsets *out) { /* Ensure we have an offset cache. */ R_TRY(this->EnsureOffsetCache()); /* Set the output. */ *out = m_offset_cache.offsets; R_SUCCEED(); } private: template<typename EntryType> struct ContinuousReadingParam { s64 offset; size_t size; NodeHeader entry_set; s32 entry_index; Offsets offsets; EntryType entry; }; private: template<typename EntryType> Result ScanContinuousReading(ContinuousReadingInfo *out_info, const ContinuousReadingParam<EntryType> ¶m) const; bool IsExistL2() const { return m_offset_count < m_entry_set_count; } bool IsExistOffsetL2OnL1() const { return this->IsExistL2() && m_node_l1->count < m_offset_count; } s64 GetEntrySetIndex(s32 node_index, s32 offset_index) const { return (m_offset_count - m_node_l1->count) + (m_offset_count * node_index) + offset_index; } Result EnsureOffsetCache(); }; /* ACCURATE_TO_VERSION: Unknown */ class BucketTree::Visitor { NON_COPYABLE(Visitor); NON_MOVEABLE(Visitor); private: friend class BucketTree; union EntrySetHeader { NodeHeader header; struct Info { s32 index; s32 count; s64 end; s64 start; } info; static_assert(util::is_pod<Info>::value); }; static_assert(util::is_pod<EntrySetHeader>::value); private: const BucketTree *m_tree; BucketTree::Offsets m_offsets; void *m_entry; s32 m_entry_index; s32 m_entry_set_count; EntrySetHeader m_entry_set; public: constexpr Visitor() : m_tree(), m_entry(), m_entry_index(-1), m_entry_set_count(), m_entry_set{} { /* ... */ } ~Visitor() { if (m_entry != nullptr) { m_tree->GetAllocator()->Deallocate(m_entry, m_tree->m_entry_size); m_tree = nullptr; m_entry = nullptr; } } bool IsValid() const { return m_entry_index >= 0; } bool CanMoveNext() const { return this->IsValid() && (m_entry_index + 1 < m_entry_set.info.count || m_entry_set.info.index + 1 < m_entry_set_count); } bool CanMovePrevious() const { return this->IsValid() && (m_entry_index > 0 || m_entry_set.info.index > 0); } Result MoveNext(); Result MovePrevious(); template<typename EntryType> Result ScanContinuousReading(ContinuousReadingInfo *out_info, s64 offset, size_t size) const; const void *Get() const { AMS_ASSERT(this->IsValid()); return m_entry; } template<typename T> const T *Get() const { AMS_ASSERT(this->IsValid()); return reinterpret_cast<const T *>(m_entry); } const BucketTree *GetTree() const { return m_tree; } private: Result Initialize(const BucketTree *tree, const BucketTree::Offsets &offsets); Result Find(s64 virtual_address); Result FindEntrySet(s32 *out_index, s64 virtual_address, s32 node_index); Result FindEntrySetWithBuffer(s32 *out_index, s64 virtual_address, s32 node_index, char *buffer); Result FindEntrySetWithoutBuffer(s32 *out_index, s64 virtual_address, s32 node_index); Result FindEntry(s64 virtual_address, s32 entry_set_index); Result FindEntryWithBuffer(s64 virtual_address, s32 entry_set_index, char *buffer); Result FindEntryWithoutBuffer(s64 virtual_address, s32 entry_set_index); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree_template_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_pooled_buffer.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree_utils.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ template<typename EntryType> Result BucketTree::ScanContinuousReading(ContinuousReadingInfo *out_info, const ContinuousReadingParam<EntryType> ¶m) const { static_assert(util::is_pod<ContinuousReadingParam<EntryType>>::value); /* Validate our preconditions. */ AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(out_info != nullptr); AMS_ASSERT(m_entry_size == sizeof(EntryType)); /* Reset the output. */ out_info->Reset(); /* If there's nothing to read, we're done. */ R_SUCCEED_IF(param.size == 0); /* If we're reading a fragment, we're done. */ R_SUCCEED_IF(param.entry.IsFragment()); /* Validate the first entry. */ auto entry = param.entry; auto cur_offset = param.offset; R_UNLESS(entry.GetVirtualOffset() <= cur_offset, fs::ResultOutOfRange()); /* Create a pooled buffer for our scan. */ PooledBuffer pool(m_node_size, 1); char *buffer = nullptr; s64 entry_storage_size; R_TRY(m_entry_storage.GetSize(std::addressof(entry_storage_size))); /* Read the node. */ if (m_node_size <= pool.GetSize()) { buffer = pool.GetBuffer(); const auto ofs = param.entry_set.index * static_cast<s64>(m_node_size); R_UNLESS(m_node_size + ofs <= static_cast<size_t>(entry_storage_size), fs::ResultInvalidBucketTreeNodeEntryCount()); R_TRY(m_entry_storage.Read(ofs, buffer, m_node_size)); } /* Calculate extents. */ const auto end_offset = cur_offset + static_cast<s64>(param.size); s64 phys_offset = entry.GetPhysicalOffset(); /* Start merge tracking. */ s64 merge_size = 0; s64 readable_size = 0; bool merged = false; /* Iterate. */ auto entry_index = param.entry_index; for (const auto entry_count = param.entry_set.count; entry_index < entry_count; ++entry_index) { /* If we're past the end, we're done. */ if (end_offset <= cur_offset) { break; } /* Validate the entry offset. */ const auto entry_offset = entry.GetVirtualOffset(); R_UNLESS(entry_offset <= cur_offset, fs::ResultInvalidIndirectEntryOffset()); /* Get the next entry. */ EntryType next_entry = {}; s64 next_entry_offset; if (entry_index + 1 < entry_count) { if (buffer != nullptr) { const auto ofs = impl::GetBucketTreeEntryOffset(0, m_entry_size, entry_index + 1); std::memcpy(std::addressof(next_entry), buffer + ofs, m_entry_size); } else { const auto ofs = impl::GetBucketTreeEntryOffset(param.entry_set.index, m_node_size, m_entry_size, entry_index + 1); R_TRY(m_entry_storage.Read(ofs, std::addressof(next_entry), m_entry_size)); } next_entry_offset = next_entry.GetVirtualOffset(); R_UNLESS(param.offsets.IsInclude(next_entry_offset), fs::ResultInvalidIndirectEntryOffset()); } else { next_entry_offset = param.entry_set.offset; } /* Validate the next entry offset. */ R_UNLESS(cur_offset < next_entry_offset, fs::ResultInvalidIndirectEntryOffset()); /* Determine the much data there is. */ const auto data_size = next_entry_offset - cur_offset; AMS_ASSERT(data_size > 0); /* Determine how much data we should read. */ const auto remaining_size = end_offset - cur_offset; const size_t read_size = static_cast<size_t>(std::min(data_size, remaining_size)); AMS_ASSERT(read_size <= param.size); /* Update our merge tracking. */ if (entry.IsFragment()) { /* If we can't merge, stop looping. */ if (EntryType::FragmentSizeMax <= read_size || remaining_size <= data_size) { break; } /* Otherwise, add the current size to the merge size. */ merge_size += read_size; } else { /* If we can't merge, stop looping. */ if (phys_offset != entry.GetPhysicalOffset()) { break; } /* Add the size to the readable amount. */ readable_size += merge_size + read_size; AMS_ASSERT(readable_size <= static_cast<s64>(param.size)); /* Update whether we've merged. */ merged |= merge_size > 0; merge_size = 0; } /* Advance. */ cur_offset += read_size; AMS_ASSERT(cur_offset <= end_offset); phys_offset += next_entry_offset - entry_offset; entry = next_entry; } /* If we merged, set our readable size. */ if (merged) { out_info->SetReadSize(static_cast<size_t>(readable_size)); } out_info->SetSkipCount(entry_index - param.entry_index); R_SUCCEED(); } template<typename EntryType> Result BucketTree::Visitor::ScanContinuousReading(ContinuousReadingInfo *out_info, s64 offset, size_t size) const { static_assert(util::is_pod<EntryType>::value); AMS_ASSERT(this->IsValid()); /* Create our parameters. */ ContinuousReadingParam<EntryType> param = { offset, size, m_entry_set.header, m_entry_index }; std::memcpy(std::addressof(param.offsets), std::addressof(m_offsets), sizeof(BucketTree::Offsets)); std::memcpy(std::addressof(param.entry), m_entry, sizeof(EntryType)); /* Scan. */ R_RETURN(m_tree->ScanContinuousReading<EntryType>(out_info, param)); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_bucket_tree_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> namespace ams::fssystem::impl { /* ACCURATE_TO_VERSION: Unknown */ class SafeValue { public: static ALWAYS_INLINE s64 GetInt64(const void *ptr) { s64 value; std::memcpy(std::addressof(value), ptr, sizeof(s64)); return value; } static ALWAYS_INLINE s64 GetInt64(const s64 *ptr) { return GetInt64(static_cast<const void *>(ptr)); } static ALWAYS_INLINE s64 GetInt64(const s64 &v) { return GetInt64(std::addressof(v)); } static ALWAYS_INLINE void SetInt64(void *dst, const void *src) { std::memcpy(dst, src, sizeof(s64)); } static ALWAYS_INLINE void SetInt64(void *dst, const s64 *src) { return SetInt64(dst, static_cast<const void *>(src)); } static ALWAYS_INLINE void SetInt64(void *dst, const s64 &v) { return SetInt64(dst, std::addressof(v)); } }; /* ACCURATE_TO_VERSION: Unknown */ template<typename IteratorType> struct BucketTreeNode { using Header = BucketTree::NodeHeader; Header header; s32 GetCount() const { return this->header.count; } void *GetArray() { return std::addressof(this->header) + 1; } template<typename T> T *GetArray() { return reinterpret_cast<T *>(this->GetArray()); } const void *GetArray() const { return std::addressof(this->header) + 1; } template<typename T> const T *GetArray() const { return reinterpret_cast<const T *>(this->GetArray()); } s64 GetBeginOffset() const { return *this->GetArray<s64>(); } s64 GetEndOffset() const { return this->header.offset; } IteratorType GetBegin() { return IteratorType(this->GetArray<s64>()); } IteratorType GetEnd() { return IteratorType(this->GetArray<s64>()) + this->header.count; } IteratorType GetBegin() const { return IteratorType(this->GetArray<s64>()); } IteratorType GetEnd() const { return IteratorType(this->GetArray<s64>()) + this->header.count; } IteratorType GetBegin(size_t entry_size) { return IteratorType(this->GetArray(), entry_size); } IteratorType GetEnd(size_t entry_size) { return IteratorType(this->GetArray(), entry_size) + this->header.count; } IteratorType GetBegin(size_t entry_size) const { return IteratorType(this->GetArray(), entry_size); } IteratorType GetEnd(size_t entry_size) const { return IteratorType(this->GetArray(), entry_size) + this->header.count; } }; constexpr inline s64 GetBucketTreeEntryOffset(s64 entry_set_offset, size_t entry_size, s32 entry_index) { return entry_set_offset + sizeof(BucketTree::NodeHeader) + entry_index * static_cast<s64>(entry_size); } constexpr inline s64 GetBucketTreeEntryOffset(s32 entry_set_index, size_t node_size, size_t entry_size, s32 entry_index) { return GetBucketTreeEntryOffset(entry_set_index * static_cast<s64>(node_size), entry_size, entry_index); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_buffered_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_substorage.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class BufferedStorage : public ::ams::fs::IStorage { NON_COPYABLE(BufferedStorage); NON_MOVEABLE(BufferedStorage); private: class Cache; class UniqueCache; class SharedCache; private: fs::SubStorage m_base_storage; fs::IBufferManager *m_buffer_manager; size_t m_block_size; s64 m_base_storage_size; std::unique_ptr<Cache[]> m_caches; s32 m_cache_count; Cache *m_next_acquire_cache; Cache *m_next_fetch_cache; os::SdkMutex m_mutex; bool m_bulk_read_enabled; public: BufferedStorage(); virtual ~BufferedStorage(); Result Initialize(fs::SubStorage base_storage, fs::IBufferManager *buffer_manager, size_t block_size, s32 buffer_count); void Finalize(); bool IsInitialized() const { return m_caches != nullptr; } virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result GetSize(s64 *out) override; virtual Result SetSize(s64 size) override; virtual Result Flush() override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; using IStorage::OperateRange; void InvalidateCaches(); fs::IBufferManager *GetBufferManager() const { return m_buffer_manager; } void EnableBulkRead() { m_bulk_read_enabled = true; } private: Result PrepareAllocation(); Result ControlDirtiness(); Result ReadCore(s64 offset, void *buffer, size_t size); bool ReadHeadCache(s64 *offset, void *buffer, size_t *size, s64 *buffer_offset); bool ReadTailCache(s64 offset, void *buffer, size_t *size, s64 buffer_offset); Result BulkRead(s64 offset, void *buffer, size_t size, bool head_cache_needed, bool tail_cache_needed); Result WriteCore(s64 offset, const void *buffer, size_t size); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compressed_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_asynchronous_access.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> #include <stratosphere/fssystem/fssystem_compression_common.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> #include <stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class CompressedStorage : public ::ams::fs::IStorage, public ::ams::fssystem::IAsynchronousAccessSplitter, public ::ams::fs::impl::Newable { NON_COPYABLE(CompressedStorage); NON_MOVEABLE(CompressedStorage); public: static constexpr size_t NodeSize = 16_KB; using IAllocator = BucketTree::IAllocator; struct Entry { s64 virt_offset; s64 phys_offset; CompressionType compression_type; s32 phys_size; s64 GetPhysicalSize() const { return this->phys_size; } }; static_assert(util::is_pod<Entry>::value); static_assert(sizeof(Entry) == 0x18); public: static constexpr s64 QueryNodeStorageSize(s32 entry_count) { return BucketTree::QueryNodeStorageSize(NodeSize, sizeof(Entry), entry_count); } static constexpr s64 QueryEntryStorageSize(s32 entry_count) { return BucketTree::QueryEntryStorageSize(NodeSize, sizeof(Entry), entry_count); } private: class CompressedStorageCore { NON_COPYABLE(CompressedStorageCore); NON_MOVEABLE(CompressedStorageCore); private: size_t m_block_size_max; size_t m_continuous_reading_size_max; BucketTree m_table; fs::SubStorage m_data_storage; GetDecompressorFunction m_get_decompressor_function; public: CompressedStorageCore() : m_table(), m_data_storage() { /* ... */ } ~CompressedStorageCore() { this->Finalize(); } public: Result Initialize(MemoryResource *bktr_allocator, fs::SubStorage data_storage, fs::SubStorage node_storage, fs::SubStorage entry_storage, s32 bktr_entry_count, size_t block_size_max, size_t continuous_reading_size_max, GetDecompressorFunction get_decompressor) { /* Check pre-conditions. */ AMS_ASSERT(bktr_allocator != nullptr); AMS_ASSERT(0 < block_size_max); AMS_ASSERT(block_size_max <= continuous_reading_size_max); AMS_ASSERT(get_decompressor != nullptr); /* Initialize our entry table. */ R_TRY(m_table.Initialize(bktr_allocator, node_storage, entry_storage, NodeSize, sizeof(Entry), bktr_entry_count)); /* Set our other fields. */ m_block_size_max = block_size_max; m_continuous_reading_size_max = continuous_reading_size_max; m_data_storage = data_storage; m_get_decompressor_function = get_decompressor; R_SUCCEED(); } void Finalize() { if (this->IsInitialized()) { m_table.Finalize(); m_data_storage = fs::SubStorage(); } } fs::IStorage *GetDataStorage() { return std::addressof(m_data_storage); } Result GetDataStorageSize(s64 *out) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); /* Get size. */ R_RETURN(m_data_storage.GetSize(out)); } BucketTree &GetEntryTable() { return m_table; } Result GetEntryList(Entry *out_entries, s32 *out_read_count, s32 max_entry_count, s64 offset, s64 size) { /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(size >= 0); AMS_ASSERT(this->IsInitialized()); /* Check that we can output the count. */ R_UNLESS(out_read_count != nullptr, fs::ResultNullptrArgument()); /* Check that we have anything to read at all. */ R_SUCCEED_IF(size == 0); /* Check that either we have a buffer, or this is to determine how many we need. */ if (max_entry_count != 0) { R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument()); } /* Get the table offsets. */ BucketTree::Offsets table_offsets; R_TRY(m_table.GetOffsets(std::addressof(table_offsets))); /* Validate arguments. */ R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange()); /* Find the offset in our tree. */ BucketTree::Visitor visitor; R_TRY(m_table.Find(std::addressof(visitor), offset)); { const auto entry_offset = visitor.Get<Entry>()->virt_offset; R_UNLESS(0 <= entry_offset && table_offsets.IsInclude(entry_offset), fs::ResultUnexpectedInCompressedStorageA()); } /* Get the entries. */ const auto end_offset = offset + size; s32 read_count = 0; while (visitor.Get<Entry>()->virt_offset < end_offset) { /* If we should be setting the output, do so. */ if (max_entry_count != 0) { /* Ensure we only read as many entries as we can. */ if (read_count >= max_entry_count) { break; } /* Set the current output entry. */ out_entries[read_count] = *visitor.Get<Entry>(); } /* Increase the read count. */ ++read_count; /* If we're at the end, we're done. */ if (!visitor.CanMoveNext()) { break; } /* Move to the next entry. */ R_TRY(visitor.MoveNext()); } /* Set the output read count. */ *out_read_count = read_count; R_SUCCEED(); } Result GetSize(s64 *out) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); /* Get our table offsets. */ BucketTree::Offsets offsets; R_TRY(m_table.GetOffsets(std::addressof(offsets))); /* Set the output. */ *out = offsets.end_offset; R_SUCCEED(); } Result Invalidate() { /* Invalidate our entry table. */ R_TRY(m_table.InvalidateCache()); /* Invalidate our data storage. */ R_TRY(m_data_storage.OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max())); R_SUCCEED(); } Result OperatePerEntry(s64 offset, s64 size, auto f) { /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(size >= 0); AMS_ASSERT(this->IsInitialized()); /* Succeed if there's nothing to operate on. */ R_SUCCEED_IF(size == 0); /* Get the table offsets. */ BucketTree::Offsets table_offsets; R_TRY(m_table.GetOffsets(std::addressof(table_offsets))); /* Validate arguments. */ R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange()); /* Find the offset in our tree. */ BucketTree::Visitor visitor; R_TRY(m_table.Find(std::addressof(visitor), offset)); { const auto entry_offset = visitor.Get<Entry>()->virt_offset; R_UNLESS(0 <= entry_offset && table_offsets.IsInclude(entry_offset), fs::ResultUnexpectedInCompressedStorageA()); } /* Prepare to operate in chunks. */ auto cur_offset = offset; const auto end_offset = offset + static_cast<s64>(size); while (cur_offset < end_offset) { /* Get the current entry. */ const auto cur_entry = *visitor.Get<Entry>(); /* Get and validate the entry's offset. */ const auto cur_entry_offset = cur_entry.virt_offset; R_UNLESS(cur_entry_offset <= cur_offset, fs::ResultUnexpectedInCompressedStorageA()); /* Get and validate the next entry offset. */ s64 next_entry_offset; if (visitor.CanMoveNext()) { R_TRY(visitor.MoveNext()); next_entry_offset = visitor.Get<Entry>()->virt_offset; R_UNLESS(table_offsets.IsInclude(next_entry_offset), fs::ResultUnexpectedInCompressedStorageA()); } else { next_entry_offset = table_offsets.end_offset; } R_UNLESS(cur_offset < next_entry_offset, fs::ResultUnexpectedInCompressedStorageA()); /* Get the offset of the entry in the data we read. */ const auto data_offset = cur_offset - cur_entry_offset; const auto data_size = (next_entry_offset - cur_entry_offset); AMS_ASSERT(data_size > 0); /* Determine how much is left. */ const auto remaining_size = end_offset - cur_offset; const auto cur_size = std::min<s64>(remaining_size, data_size - data_offset); AMS_ASSERT(cur_size <= size); /* Get the data storage size. */ s64 storage_size = 0; R_TRY(m_data_storage.GetSize(std::addressof(storage_size))); /* Check that our read remains naively physically in bounds. */ R_UNLESS(0 <= cur_entry.phys_offset && cur_entry.phys_offset <= storage_size, fs::ResultUnexpectedInCompressedStorageC()); /* If we have any compression, verify that we remain physically in bounds. */ if (cur_entry.compression_type != CompressionType_None) { R_UNLESS(cur_entry.phys_offset + cur_entry.GetPhysicalSize() <= storage_size, fs::ResultUnexpectedInCompressedStorageC()); } /* Check that block alignment requirements are met. */ if (CompressionTypeUtility::IsBlockAlignmentRequired(cur_entry.compression_type)) { R_UNLESS(util::IsAligned(cur_entry.phys_offset, CompressionBlockAlignment), fs::ResultUnexpectedInCompressedStorageA()); } /* Invoke the operator. */ bool is_continuous = true; R_TRY(f(std::addressof(is_continuous), cur_entry, data_size, data_offset, cur_size)); /* If not continuous, we're done. */ if (!is_continuous) { break; } /* Advance. */ cur_offset += cur_size; } R_SUCCEED(); } Result OperateRange(s64 offset, s64 size, auto f) { /* Get the table offsets. */ BucketTree::Offsets table_offsets; R_TRY(m_table.GetOffsets(std::addressof(table_offsets))); /* Validate arguments. */ R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange()); /* If our table is empty, we have nothing to operate on. */ R_SUCCEED_IF(m_table.IsEmpty()); /* Operate on the range. */ s64 required_access_physical_offset = 0; s64 required_access_physical_size = 0; R_TRY(this->OperatePerEntry(offset, size, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 read_size) -> Result { AMS_UNUSED(virtual_data_size); /* Determine the physical extents. */ s64 physical_offset, physical_size; if (CompressionTypeUtility::IsRandomAccessible(entry.compression_type)) { physical_offset = entry.phys_offset + data_offset; physical_size = read_size; } else { physical_offset = entry.phys_offset; physical_size = entry.GetPhysicalSize(); } /* If we have a pending data storage operation, perform it if we have to. */ const s64 required_access_physical_end = required_access_physical_offset + required_access_physical_size; if (required_access_physical_size > 0) { /* Check that we can can coalesce this operation with the previous one; if we can't, we need to perform it. */ if (!(required_access_physical_end <= physical_offset && physical_offset <= util::AlignUp(required_access_physical_end, CompressionBlockAlignment))) { R_TRY(f(required_access_physical_offset, required_access_physical_size)); required_access_physical_size = 0; } } /* If we need to access the data storage, update our storage access parameters. */ if (CompressionTypeUtility::IsDataStorageAccessRequired(entry.compression_type)) { /* Update the required access parameters. */ if (required_access_physical_size > 0) { required_access_physical_size += physical_size + (physical_offset - required_access_physical_end); } else { required_access_physical_offset = physical_offset; required_access_physical_size = physical_size; } } else { /* Verify that we're allowed to be operating on the non-data-storage-access type. */ R_UNLESS(entry.compression_type == CompressionType_Zeros, fs::ResultUnexpectedInCompressedStorageB()); } /* We're always continuous. */ *out_continuous = true; R_SUCCEED(); })); /* If we have a pending operation, perform it. */ if (required_access_physical_size > 0) { R_TRY(f(required_access_physical_offset, required_access_physical_size)); } R_SUCCEED(); } Result QueryAppropriateOffsetForAsynchronousAccess(s64 *out, s64 offset, s64 access_size, s64 alignment_size) { /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(this->IsInitialized()); /* Check that we can write to the output. */ R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); /* Get the table offsets. */ BucketTree::Offsets table_offsets; R_TRY(m_table.GetOffsets(std::addressof(table_offsets))); /* Validate arguments. */ R_UNLESS(table_offsets.IsInclude(offset, 1), fs::ResultOutOfRange()); /* Operate on the range. */ s64 required_access_physical_offset = 0; s64 required_access_physical_size = 0; s64 required_access_physical_end = 0; s64 appropriate_virtual_offset = offset; R_TRY(this->OperatePerEntry(offset, table_offsets.end_offset - offset, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 read_size) -> Result { AMS_UNUSED(virtual_data_size); /* Determine the physical extents. */ s64 physical_offset, physical_size; if (CompressionTypeUtility::IsRandomAccessible(entry.compression_type)) { physical_offset = entry.phys_offset + data_offset; physical_size = read_size; } else { physical_offset = entry.phys_offset; physical_size = entry.GetPhysicalSize(); } /* If we don't need to access the data storage, update our storage access parameters simply. */ if (!CompressionTypeUtility::IsDataStorageAccessRequired(entry.compression_type)) { /* Verify that we're allowed to be operating on the non-data-storage-access type. */ R_UNLESS(entry.compression_type == CompressionType_Zeros, fs::ResultUnexpectedInCompressedStorageB()); /* No access is required, so we can advance the offset freely. */ appropriate_virtual_offset += read_size; /* A read to zeros is always continuous. */ *out_continuous = true; R_SUCCEED(); } /* Update the required access parameters. */ if (required_access_physical_size > 0) { /* Check that we can can coalesce this operation with the previous one; if we can't, we need to account for the gap. */ if ((required_access_physical_end <= physical_offset && physical_offset <= util::AlignUp(required_access_physical_end, CompressionBlockAlignment))) { const s64 gap_size = physical_offset - required_access_physical_end; if (required_access_physical_size + gap_size > access_size) { *out_continuous = false; R_SUCCEED(); } required_access_physical_size += gap_size; } } else { required_access_physical_offset = physical_offset; } /* If we're within the access bounds, we want to continue on. */ if (physical_size + required_access_physical_size <= access_size) { required_access_physical_size += physical_size; required_access_physical_end = physical_offset + physical_size; appropriate_virtual_offset += read_size; *out_continuous = true; R_SUCCEED(); } /* We're no longer within the access bounds, so we won't be continuous. */ *out_continuous = false; /* Ensure we account for block alignment. */ if (CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type)) { if (appropriate_virtual_offset == offset) { appropriate_virtual_offset += read_size; access_size = std::max<s64>(access_size, read_size); } } else { /* Get the default splitter. */ auto * const default_splitter = fssystem::IAsynchronousAccessSplitter::GetDefaultAsynchronousAccessSplitter(); /* Query for an appropriate offset. */ s64 appropriate_physical_offset = 0; R_TRY(default_splitter->QueryAppropriateOffset(std::addressof(appropriate_physical_offset), physical_offset, access_size - required_access_physical_size, alignment_size)); /* Use it, if we should. */ if (const auto gap_size = appropriate_physical_offset - physical_offset; gap_size > 0) { appropriate_virtual_offset += gap_size; required_access_physical_size += gap_size; } } R_SUCCEED(); })); /* Check that the offset is actually appropriate. */ AMS_ASSERT(offset <= appropriate_virtual_offset && appropriate_virtual_offset <= table_offsets.end_offset); AMS_ASSERT(0 <= required_access_physical_size && required_access_physical_size <= access_size); /* Set the output. */ *out = appropriate_virtual_offset; R_SUCCEED(); } Result QueryRange(void *dst, size_t dst_size, s64 offset, s64 size) { /* Check arguments. */ R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidArgument()); /* If we have nothing to query, succeed immediately. */ R_SUCCEED_IF(size <= 0); /* Operate on the range. */ fs::QueryRangeInfo full_info; full_info.Clear(); R_TRY(this->OperateRange(offset, size, [&](s64 offset, s64 size) -> Result { /* Operate on our data storage. */ fs::QueryRangeInfo cur_info; R_TRY(m_data_storage.OperateRange(std::addressof(cur_info), sizeof(cur_info), fs::OperationId::QueryRange, offset, size, nullptr, 0)); /* Merge the info. */ full_info.Merge(cur_info); R_SUCCEED(); })); R_SUCCEED(); } public: using ReadImplFunction = util::IFunction<Result(void *, size_t)>; using ReadFunction = util::IFunction<Result(size_t, const ReadImplFunction &)>; public: Result Read(s64 offset, s64 size, const ReadFunction &read_func) { /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(this->IsInitialized()); /* Succeed immediately, if we have nothing to read. */ R_SUCCEED_IF(size == 0); /* Declare read lambda. */ constexpr int EntriesCountMax = 0x80; struct Entries { CompressionType compression_type; u32 gap_from_prev; u32 physical_size; u32 virtual_size; }; Entries entries[EntriesCountMax]; s32 entry_count = 0; Entry prev_entry = { .virt_offset = -1, }; bool will_allocate_pooled_buffer = false; s64 required_access_physical_offset = 0; s64 required_access_physical_size = 0; auto PerformRequiredRead = [&]() -> Result { /* If there are no entries, we have nothing to do. */ R_SUCCEED_IF(entry_count == 0); /* Get the remaining size in a convenient form. */ const size_t total_required_size = static_cast<size_t>(required_access_physical_size); /* Perform the read based on whether we need to allocate a buffer. */ if (will_allocate_pooled_buffer) { /* Allocate a pooled buffer. */ fssystem::PooledBuffer pooled_buffer; if (pooled_buffer.GetAllocatableSizeMax() >= total_required_size) { pooled_buffer.Allocate(total_required_size, m_block_size_max); } else { pooled_buffer.AllocateParticularlyLarge(std::min<size_t>(total_required_size, PooledBuffer::GetAllocatableParticularlyLargeSizeMax()), m_block_size_max); } /* Read each of the entries. */ for (s32 entry_idx = 0; entry_idx < entry_count; ++entry_idx) { /* Determine the current read size. */ bool will_use_pooled_buffer = false; const size_t cur_read_size = [&] () ALWAYS_INLINE_LAMBDA -> size_t { if (const size_t target_entry_size = static_cast<size_t>(entries[entry_idx].physical_size) + static_cast<size_t>(entries[entry_idx].gap_from_prev); target_entry_size <= pooled_buffer.GetSize()) { /* We'll be using the pooled buffer. */ will_use_pooled_buffer = true; /* Determine how much we can read. */ const size_t max_size = std::min<size_t>(required_access_physical_size, pooled_buffer.GetSize()); size_t read_size = 0; for (auto n = entry_idx; n < entry_count; ++n) { const size_t cur_entry_size = static_cast<size_t>(entries[n].physical_size) + static_cast<size_t>(entries[n].gap_from_prev); if (read_size + cur_entry_size > max_size) { break; } read_size += cur_entry_size; } return read_size; } else { /* If we don't fit, we must be uncompressed. */ AMS_ASSERT(entries[entry_idx].compression_type == CompressionType_None); /* We can perform the whole of an uncompressed read directly. */ return entries[entry_idx].virtual_size; } }(); /* Perform the read based on whether or not we'll use the pooled buffer. */ if (will_use_pooled_buffer) { /* Read the compressed data into the pooled buffer. */ auto * const buffer = pooled_buffer.GetBuffer(); R_TRY(m_data_storage.Read(required_access_physical_offset, buffer, cur_read_size)); /* Temporarily increase our thread priority, while we decompress the data. */ ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative); /* Decompress the data. */ size_t buffer_offset; for (buffer_offset = 0; entry_idx < entry_count && ((static_cast<size_t>(entries[entry_idx].physical_size) + static_cast<size_t>(entries[entry_idx].gap_from_prev)) == 0 || buffer_offset < cur_read_size); buffer_offset += entries[entry_idx++].physical_size) { /* Advance by the relevant gap. */ buffer_offset += entries[entry_idx].gap_from_prev; const auto compression_type = entries[entry_idx].compression_type; switch (compression_type) { case CompressionType_None: { /* Check that we can remain within bounds. */ AMS_ASSERT(buffer_offset + entries[entry_idx].virtual_size <= cur_read_size); /* Perform no decompression. */ R_TRY(read_func(entries[entry_idx].virtual_size, util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check that the size is valid. */ AMS_ASSERT(dst_size == entries[entry_idx].virtual_size); AMS_UNUSED(dst_size); /* We have no compression, so just copy the data out. */ std::memcpy(dst, buffer + buffer_offset, entries[entry_idx].virtual_size); R_SUCCEED(); }))); } break; case CompressionType_Zeros: { /* Check that we can remain within bounds. */ AMS_ASSERT(buffer_offset <= cur_read_size); /* Zero the memory. */ R_TRY(read_func(entries[entry_idx].virtual_size, util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check that the size is valid. */ AMS_ASSERT(dst_size == entries[entry_idx].virtual_size); AMS_UNUSED(dst_size); /* The data is zeroes, so zero the buffer. */ std::memset(dst, 0, entries[entry_idx].virtual_size); R_SUCCEED(); }))); } break; default: { /* Check that we can remain within bounds. */ AMS_ASSERT(buffer_offset + entries[entry_idx].physical_size <= cur_read_size); /* Get the decompressor. */ const auto decompressor = this->GetDecompressor(compression_type); R_UNLESS(decompressor != nullptr, fs::ResultUnexpectedInCompressedStorageB()); /* Decompress the data. */ R_TRY(read_func(entries[entry_idx].virtual_size, util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check that the size is valid. */ AMS_ASSERT(dst_size == entries[entry_idx].virtual_size); AMS_UNUSED(dst_size); /* Perform the decompression. */ R_RETURN(decompressor(dst, entries[entry_idx].virtual_size, buffer + buffer_offset, entries[entry_idx].physical_size)); }))); } break; } } /* Check that we processed the correct amount of data. */ AMS_ASSERT(buffer_offset == cur_read_size); } else { /* Account for the gap from the previous entry. */ required_access_physical_offset += entries[entry_idx].gap_from_prev; required_access_physical_size -= entries[entry_idx].gap_from_prev; /* We don't need the buffer (as the data is uncompressed), so just execute the read. */ R_TRY(read_func(cur_read_size, util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check that the size is valid. */ AMS_ASSERT(dst_size == cur_read_size); AMS_UNUSED(dst_size); /* Perform the read. */ R_RETURN(m_data_storage.Read(required_access_physical_offset, dst, cur_read_size)); }))); } /* Advance on. */ required_access_physical_offset += cur_read_size; required_access_physical_size -= cur_read_size; } /* Verify that we have nothing remaining to read. */ AMS_ASSERT(required_access_physical_size == 0); R_SUCCEED(); } else { /* We don't need a buffer, so just execute the read. */ R_TRY(read_func(total_required_size, util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check that the size is valid. */ AMS_ASSERT(dst_size == total_required_size); AMS_UNUSED(dst_size); /* Perform the read. */ R_RETURN(m_data_storage.Read(required_access_physical_offset, dst, total_required_size)); }))); } R_SUCCEED(); }; R_TRY(this->OperatePerEntry(offset, size, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 read_size) -> Result { /* Determine the physical extents. */ s64 physical_offset, physical_size; if (CompressionTypeUtility::IsRandomAccessible(entry.compression_type)) { physical_offset = entry.phys_offset + data_offset; physical_size = read_size; } else { physical_offset = entry.phys_offset; physical_size = entry.GetPhysicalSize(); } /* If we have a pending data storage operation, perform it if we have to. */ const s64 required_access_physical_end = required_access_physical_offset + required_access_physical_size; if (required_access_physical_size > 0) { const bool required_by_gap = !(required_access_physical_end <= physical_offset && physical_offset <= util::AlignUp(required_access_physical_end, CompressionBlockAlignment)); const bool required_by_continuous_size = ((physical_size + physical_offset) - required_access_physical_end) + required_access_physical_size > static_cast<s64>(m_continuous_reading_size_max); const bool required_by_entry_count = entry_count == EntriesCountMax; if (required_by_gap || required_by_continuous_size || required_by_entry_count) { /* Check that our planned access is sane. */ AMS_ASSERT(!will_allocate_pooled_buffer || required_access_physical_size <= static_cast<s64>(m_continuous_reading_size_max)); /* Perform the required read. */ R_TRY(PerformRequiredRead()); /* Reset our requirements. */ prev_entry.virt_offset = -1; required_access_physical_size = 0; entry_count = 0; will_allocate_pooled_buffer = false; } } /* Sanity check that we're within bounds on entries. */ AMS_ASSERT(entry_count < EntriesCountMax); /* Determine if a buffer allocation is needed. */ if (entry.compression_type != CompressionType_None || (prev_entry.virt_offset >= 0 && entry.virt_offset - prev_entry.virt_offset != entry.phys_offset - prev_entry.phys_offset)) { will_allocate_pooled_buffer = true; } /* If we need to access the data storage, update our required access parameters. */ if (CompressionTypeUtility::IsDataStorageAccessRequired(entry.compression_type)) { /* If the data is compressed, ensure the access is sane. */ if (entry.compression_type != CompressionType_None) { R_UNLESS(data_offset == 0, fs::ResultInvalidOffset()); R_UNLESS(virtual_data_size == read_size, fs::ResultInvalidSize()); R_UNLESS(entry.GetPhysicalSize() <= static_cast<s64>(m_block_size_max), fs::ResultUnexpectedInCompressedStorageD()); } /* Update the required access parameters. */ s64 gap_from_prev; if (required_access_physical_size > 0) { gap_from_prev = physical_offset - required_access_physical_end; } else { gap_from_prev = 0; required_access_physical_offset = physical_offset; } required_access_physical_size += physical_size + gap_from_prev; /* Create an entry to access the data storage. */ entries[entry_count++] = { .compression_type = entry.compression_type, .gap_from_prev = static_cast<u32>(gap_from_prev), .physical_size = static_cast<u32>(physical_size), .virtual_size = static_cast<u32>(read_size), }; } else { /* Verify that we're allowed to be operating on the non-data-storage-access type. */ R_UNLESS(entry.compression_type == CompressionType_Zeros, fs::ResultUnexpectedInCompressedStorageB()); /* If we have entries, create a fake entry for the zero region. */ if (entry_count != 0) { /* We need to have a physical size. */ R_UNLESS(entry.GetPhysicalSize() != 0, fs::ResultUnexpectedInCompressedStorageD()); /* Create a fake entry. */ entries[entry_count++] = { .compression_type = CompressionType_Zeros, .gap_from_prev = 0, .physical_size = 0, .virtual_size = static_cast<u32>(read_size), }; } else { /* We have no entries, so we can just perform the read. */ R_TRY(read_func(static_cast<size_t>(read_size), util::MakeIFunction([&] (void *dst, size_t dst_size) -> Result { /* Check the space we should zero is correct. */ AMS_ASSERT(dst_size == static_cast<size_t>(read_size)); AMS_UNUSED(dst_size); /* Zero the memory. */ std::memset(dst, 0, read_size); R_SUCCEED(); }))); } } /* Set the previous entry. */ prev_entry = entry; /* We're continuous. */ *out_continuous = true; R_SUCCEED(); })); /* If we still have a pending access, perform it. */ if (required_access_physical_size != 0) { R_TRY(PerformRequiredRead()); } R_SUCCEED(); } private: DecompressorFunction GetDecompressor(CompressionType type) const { /* Check that we can get a decompressor for the type. */ if (CompressionTypeUtility::IsUnknownType(type)) { return nullptr; } /* Get the decompressor. */ return m_get_decompressor_function(type); } bool IsInitialized() const { return m_table.IsInitialized(); } }; class CacheManager { NON_COPYABLE(CacheManager); NON_MOVEABLE(CacheManager); private: struct Range { s64 offset; size_t size; s64 GetEndOffset() const { return this->offset + this->size; } bool IsIncluded(s64 ofs) const { return this->offset <= ofs && ofs < this->GetEndOffset(); } }; static_assert(util::is_pod<Range>::value); struct CacheEntry { Range range; fs::IBufferManager::CacheHandle handle; uintptr_t memory_address; u32 memory_size; bool is_valid; bool is_cached; u16 lru_counter; void Invalidate() { /* ... */ } bool IsAllocated() const { return this->is_valid && this->handle != 0; } bool IsIncluded(s64 offset) const { return this->is_valid && this->range.IsIncluded(offset); } bool IsWriteBack() const { return false; } }; static_assert(util::is_pod<CacheEntry>::value); struct AccessRange { s64 virtual_offset; s64 virtual_size; u32 physical_size; bool is_block_alignment_required; s64 GetEndVirtualOffset() const { return this->virtual_offset + this->virtual_size; } }; static_assert(util::is_pod<AccessRange>::value); using BlockCacheManager = ::ams::fssystem::impl::BlockCacheManager<CacheEntry, fs::IBufferManager>; using CacheIndex = BlockCacheManager::CacheIndex; private: size_t m_cache_size_unk_0; size_t m_cache_size_unk_1; os::SdkMutex m_mutex; BlockCacheManager m_block_cache_manager; s64 m_storage_size = 0; public: CacheManager() = default; ~CacheManager() { this->Finalize(); } public: Result Initialize(fs::IBufferManager *cache_allocator, s64 storage_size, size_t cache_size_0, size_t cache_size_1, size_t max_cache_entries) { /* Initialize our block cache manager. */ R_TRY(m_block_cache_manager.Initialize(cache_allocator, max_cache_entries)); /* Set our fields. */ m_cache_size_unk_0 = cache_size_0; m_cache_size_unk_1 = cache_size_1; m_storage_size = storage_size; R_SUCCEED(); } void Finalize() { /* If necessary, invalidate anything we have cached. */ if (m_block_cache_manager.IsInitialized()) { this->Invalidate(); } /* Finalize our block cache manager. */ m_block_cache_manager.Finalize(); } void Invalidate() { /* Acquire exclusive access to our manager. */ std::scoped_lock lk(m_mutex); /* Invalidate all entries. */ return m_block_cache_manager.Invalidate(); } Result Read(CompressedStorageCore &core, s64 offset, void *buffer, size_t size) { /* If we have nothing to read, succeed. */ R_SUCCEED_IF(size == 0); /* Check that we have a buffer to read into. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Check that the read is in bounds. */ R_UNLESS(offset <= m_storage_size, fs::ResultInvalidOffset()); /* Determine how much we can read. */ const size_t read_size = std::min<size_t>(size, m_storage_size - offset); /* Create head/tail ranges. */ AccessRange head_range = {}; AccessRange tail_range = {}; bool is_tail_set = false; /* Operate to determine the head range. */ R_TRY(core.OperatePerEntry(offset, 1, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 data_read_size) -> Result { AMS_UNUSED(data_offset, data_read_size); /* Set the head range. */ head_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, .physical_size = static_cast<u32>(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; /* If required, set the tail range. */ if (static_cast<s64>(offset + read_size) <= entry.virt_offset + virtual_data_size) { tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, .physical_size = static_cast<u32>(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; is_tail_set = true; } /* We only want to determine the head range, so we're not continuous. */ *out_continuous = false; R_SUCCEED(); })); /* If necessary, determine the tail range. */ if (!is_tail_set) { R_TRY(core.OperatePerEntry(offset + read_size - 1, 1, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 data_read_size) -> Result { AMS_UNUSED(data_offset, data_read_size); /* Set the tail range. */ tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, .physical_size = static_cast<u32>(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; /* We only want to determine the tail range, so we're not continuous. */ *out_continuous = false; R_SUCCEED(); })); } /* Begin performing the accesses. */ s64 cur_offset = offset; size_t cur_size = read_size; char *cur_dst = static_cast<char *>(buffer); /* If we can use the head/tail cache, do so. */ if (m_block_cache_manager.GetCount() > 0) { /* Read the head cache. */ R_TRY(this->ReadHeadCache(core, cur_offset, cur_dst, cur_size, head_range, tail_range)); /* If we're now done, succeed. */ R_SUCCEED_IF(cur_size == 0); /* Read the tail cache. */ R_TRY(this->ReadTailCache(core, cur_offset, cur_dst, cur_size, head_range, tail_range)); /* If we're now done, succeed. */ R_SUCCEED_IF(cur_size == 0); } /* Determine our alignment. */ const bool head_unaligned = head_range.is_block_alignment_required && (cur_offset != head_range.virtual_offset || static_cast<s64>(cur_size) < head_range.virtual_size); const bool tail_unaligned = [&] () ALWAYS_INLINE_LAMBDA -> bool { if (tail_range.is_block_alignment_required) { if (static_cast<s64>(cur_size + cur_offset) == tail_range.GetEndVirtualOffset()) { return false; } else if (!head_unaligned) { return true; } else { return head_range.GetEndVirtualOffset() < static_cast<s64>(cur_size + cur_offset); } } else { return false; } }(); /* Determine start/end offsets. */ const s64 start_offset = head_range.is_block_alignment_required ? head_range.virtual_offset : cur_offset; const s64 end_offset = tail_range.is_block_alignment_required ? tail_range.GetEndVirtualOffset() : cur_offset + cur_size; /* Perform the read. */ bool is_burst_reading = false; R_TRY(core.Read(start_offset, end_offset - start_offset, util::MakeIFunction([&] (size_t size_buffer_required, const CompressedStorageCore::ReadImplFunction &read_impl) -> Result { /* Determine whether we're burst reading. */ const AccessRange *unaligned_range = nullptr; if (!is_burst_reading) { /* Check whether we're using head, tail, or none as unaligned. */ if (head_unaligned && head_range.virtual_offset <= cur_offset && cur_offset < head_range.GetEndVirtualOffset()) { unaligned_range = std::addressof(head_range); } else if (tail_unaligned && tail_range.virtual_offset <= cur_offset && cur_offset < tail_range.GetEndVirtualOffset()) { unaligned_range = std::addressof(tail_range); } else { is_burst_reading = true; } } AMS_ASSERT((is_burst_reading ^ (unaligned_range != nullptr))); /* Perform reading by burst, or not. */ if (is_burst_reading) { /* Check that the access is valid for burst reading. */ AMS_ASSERT(size_buffer_required <= cur_size); /* Perform the read. */ R_TRY(read_impl(cur_dst, size_buffer_required)); /* Advance. */ cur_dst += size_buffer_required; cur_offset += size_buffer_required; cur_size -= size_buffer_required; /* Determine whether we're going to continue burst reading. */ const s64 offset_aligned = tail_unaligned ? tail_range.virtual_offset : end_offset; AMS_ASSERT(cur_offset <= offset_aligned); if (offset_aligned <= cur_offset) { is_burst_reading = false; } } else { /* We're not burst reading, so we have some unaligned range. */ AMS_ASSERT(unaligned_range != nullptr); /* Check that the size is correct. */ AMS_ASSERT(size_buffer_required == static_cast<size_t>(unaligned_range->virtual_size)); /* Get a pooled buffer for our read. */ fssystem::PooledBuffer pooled_buffer; pooled_buffer.Allocate(size_buffer_required, size_buffer_required); /* Perform read. */ R_TRY(read_impl(pooled_buffer.GetBuffer(), size_buffer_required)); /* Copy the data we read to the destination. */ const size_t skip_size = cur_offset - unaligned_range->virtual_offset; const size_t copy_size = std::min<size_t>(cur_size, unaligned_range->GetEndVirtualOffset() - cur_offset); std::memcpy(cur_dst, pooled_buffer.GetBuffer() + skip_size, copy_size); /* Advance. */ cur_dst += copy_size; cur_offset += copy_size; cur_size -= copy_size; /* If we should, cache what we read. */ if (m_block_cache_manager.GetCount() > 0 && unaligned_range->physical_size > m_cache_size_unk_1) { CacheEntry entry; for (s64 ofs = unaligned_range->virtual_offset; ofs < unaligned_range->GetEndVirtualOffset(); ofs += entry.range.size) { /* Find or allocate buffer. */ fs::IBufferManager::MemoryRange memory_range; R_TRY(this->FindOrAllocateBuffer(std::addressof(memory_range), std::addressof(entry), ofs, unaligned_range->GetEndVirtualOffset() - ofs)); /* If not cached, cache the data. */ if (!entry.is_cached) { std::memcpy(reinterpret_cast<void *>(memory_range.first), pooled_buffer.GetBuffer() + (ofs - unaligned_range->virtual_offset), entry.range.size); entry.is_cached = true; } /* Store the associated buffer. */ this->StoreAssociateBuffer(memory_range, entry); } } } R_SUCCEED(); }))); R_SUCCEED(); } private: Result FindBuffer(fs::IBufferManager::MemoryRange *out, CacheEntry *out_entry, s64 offset) { /* Check pre-conditions. */ AMS_ASSERT(m_block_cache_manager.IsInitialized()); AMS_ASSERT(out != nullptr); AMS_ASSERT(out_entry != nullptr); /* Acquire exclusive access to our entries. */ std::scoped_lock lk(m_mutex); /* Find the buffer. */ R_RETURN(this->FindBufferImpl(out, out_entry, offset)); } Result FindBufferImpl(fs::IBufferManager::MemoryRange *out, CacheEntry *out_entry, s64 offset) { /* Check pre-conditions. */ AMS_ASSERT(m_mutex.IsLockedByCurrentThread()); /* Get our block cache count */ const auto count = m_block_cache_manager.GetCount(); /* Try to find the buffer. */ CacheIndex index; for (index = 0; index < count; ++index) { if (const auto &buffer = m_block_cache_manager[index]; buffer.IsAllocated() && buffer.IsIncluded(offset)) { break; } } /* Set the output. */ if (index != count) { /* Acquire the entry. */ m_block_cache_manager.AcquireCacheEntry(out_entry, out, index); if (out->first == 0) { *out = {}; *out_entry = {}; } } else { *out = {}; *out_entry = {}; } R_SUCCEED(); } Result FindOrAllocateBuffer(fs::IBufferManager::MemoryRange *out, CacheEntry *out_entry, s64 offset, size_t max_range_size) { /* Check pre-conditions. */ AMS_ASSERT(m_block_cache_manager.IsInitialized()); AMS_ASSERT(out != nullptr); AMS_ASSERT(out_entry != nullptr); /* Acquire exclusive access to our block cache manager. */ std::scoped_lock lk(m_mutex); /* Try to find the buffer. */ R_TRY(this->FindBufferImpl(out, out_entry, offset)); /* Determine the range size. */ const size_t range_size = std::min<size_t>(max_range_size, m_cache_size_unk_0); /* If necessary, allocate. */ if (out->first == 0) { R_TRY(fssystem::buffers::AllocateBufferUsingBufferManagerContext(out, m_block_cache_manager.GetAllocator(), range_size, fs::IBufferManager::BufferAttribute(0x20), [] (const fs::IBufferManager::MemoryRange &buffer) -> bool { return buffer.first != 0; }, AMS_CURRENT_FUNCTION_NAME)); /* Set the entry for the allocated buffer. */ out_entry->is_valid = out->first != 0; out_entry->is_cached = false; out_entry->handle = 0; out_entry->memory_address = 0; out_entry->memory_size = 0; out_entry->range.offset = offset; out_entry->range.size = range_size; out_entry->lru_counter = 0; } /* Check that the result is valid. */ AMS_ASSERT(out_entry->range.size <= out->second); R_SUCCEED(); } Result ReadHeadCache(CompressedStorageCore &core, s64 &offset, char *&buffer, size_t &size, AccessRange &head_range, const AccessRange &tail_range) { /* Check pre-conditions. */ AMS_ASSERT(buffer != nullptr); /* Read until we're done with the head cache */ while (head_range.virtual_size > 0 && head_range.virtual_offset < tail_range.GetEndVirtualOffset()) { /* Cache the access extents. */ s64 access_offset = offset; char *access_buf = buffer; size_t access_size = size; /* Determine the current access extents. */ s64 cur_offset = head_range.virtual_offset + util::AlignDown<s64>(access_offset - head_range.virtual_offset, m_cache_size_unk_0); while (cur_offset < head_range.GetEndVirtualOffset() && cur_offset < static_cast<s64>(offset + size)) { /* Find the relevant entry. */ fs::IBufferManager::MemoryRange memory_range = {}; CacheEntry entry = {}; R_TRY(this->FindBuffer(std::addressof(memory_range), std::addressof(entry), cur_offset)); /* If the entry isn't cached, we're done. */ R_SUCCEED_IF(!entry.is_cached); /* Otherwise, copy the cacheed data. */ const size_t copy_size = std::min<size_t>(access_size, entry.range.GetEndOffset() - access_offset); std::memcpy(access_buf, reinterpret_cast<const void *>(memory_range.first + access_offset - entry.range.offset), copy_size); /* Advance. */ access_buf += copy_size; access_offset += copy_size; access_size -= copy_size; cur_offset += entry.range.size; /* Store the associated buffer. */ this->StoreAssociateBuffer(memory_range, entry); } /* Update the output extents. */ buffer = access_buf; offset = access_offset; size = access_size; /* Determine the new head range. */ AccessRange new_head_range = { .virtual_offset = head_range.GetEndVirtualOffset(), .virtual_size = 0, .physical_size = 0, .is_block_alignment_required = true, }; if (head_range.GetEndVirtualOffset() == tail_range.virtual_offset) { /* We can use the tail range directly. */ new_head_range.virtual_size = tail_range.virtual_size; new_head_range.physical_size = tail_range.physical_size; new_head_range.is_block_alignment_required = tail_range.is_block_alignment_required; } else if (head_range.GetEndVirtualOffset() < tail_range.GetEndVirtualOffset()) { /* We need to find the new head range. */ R_TRY(core.OperatePerEntry(new_head_range.virtual_offset, 1, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 data_read_size) -> Result { AMS_UNUSED(data_offset, data_read_size); /* If we can, use the current entry. */ if (entry.virt_offset < tail_range.GetEndVirtualOffset()) { new_head_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, .physical_size = static_cast<u32>(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; } /* We only want to determine the new head range, so we're not continuous. */ *out_continuous = false; R_SUCCEED(); })); } /* Update the head range. */ head_range = new_head_range; } R_SUCCEED(); } Result ReadTailCache(CompressedStorageCore &core, s64 offset, char *buffer, size_t &size, const AccessRange &head_range, AccessRange &tail_range) { /* Check pre-conditions. */ AMS_ASSERT(buffer != nullptr); /* Read until we're done with the tail cache */ while (tail_range.virtual_offset >= offset) { /* Loop reading, while we can. */ const s64 dst_end_offset = offset + size; s64 cur_offset = tail_range.virtual_offset; while (cur_offset < dst_end_offset) { /* Find the relevant entry. */ fs::IBufferManager::MemoryRange memory_range = {}; CacheEntry entry = {}; R_TRY(this->FindBuffer(std::addressof(memory_range), std::addressof(entry), cur_offset)); /* If the entry isn't cached, we're done. */ R_SUCCEED_IF(!entry.is_cached); /* Sanity check our current access. */ AMS_ASSERT(offset <= entry.range.offset); /* Copy the cacheed data. */ const s64 cur_end_offset = std::min<s64>(dst_end_offset, entry.range.GetEndOffset()); std::memcpy(buffer + entry.range.offset - offset, reinterpret_cast<const void *>(memory_range.first), cur_end_offset - entry.range.offset); /* Advance. */ cur_offset += entry.range.size; /* Store the associated buffer. */ this->StoreAssociateBuffer(memory_range, entry); } /* Update the output extents. */ size -= std::min<s64>(dst_end_offset, tail_range.GetEndVirtualOffset()) - tail_range.virtual_offset; /* Update the tail range. */ bool new_tail_found = false; if (tail_range.virtual_offset - 1 >= 0) { /* We need to find the new tail range. */ R_TRY(core.OperatePerEntry(tail_range.virtual_offset - 1, 1, [&] (bool *out_continuous, const Entry &entry, s64 virtual_data_size, s64 data_offset, s64 data_read_size) -> Result { AMS_UNUSED(data_offset, data_read_size); /* If we can, use the current entry. */ if (head_range.virtual_offset != entry.virt_offset) { tail_range = { .virtual_offset = entry.virt_offset, .virtual_size = virtual_data_size, .physical_size = static_cast<u32>(entry.phys_size), .is_block_alignment_required = CompressionTypeUtility::IsBlockAlignmentRequired(entry.compression_type), }; new_tail_found = true; } /* We only want to determine the new head range, so we're not continuous. */ *out_continuous = false; R_SUCCEED(); })); } /* If we didn't find a new tail, write a default (and we're done). */ if (!new_tail_found) { tail_range = { .virtual_offset = tail_range.virtual_offset, .virtual_size = 0, .physical_size = 0, .is_block_alignment_required = true, }; break; } } R_SUCCEED(); } void StoreAssociateBuffer(const fs::IBufferManager::MemoryRange &memory_range, const CacheEntry &entry) { /* Check pre-conditions. */ AMS_ASSERT(m_block_cache_manager.GetCount() > 0); /* Acquire exclusive access to our manager. */ std::scoped_lock lk(m_mutex); /* Get empty cache index. */ CacheIndex empty_index, lru_index; m_block_cache_manager.GetEmptyCacheEntryIndex(std::addressof(empty_index), std::addressof(lru_index)); /* If nothing is empty, invalidate the least recently used entry. */ if (empty_index == BlockCacheManager::InvalidCacheIndex) { m_block_cache_manager.InvalidateCacheEntry(lru_index); empty_index = lru_index; } /* Set the entry. */ m_block_cache_manager.SetCacheEntry(empty_index, entry, memory_range); } }; private: CompressedStorageCore m_core; CacheManager m_cache_manager; public: CompressedStorage() = default; virtual ~CompressedStorage() { this->Finalize(); } Result Initialize(MemoryResource *bktr_allocator, fs::IBufferManager *cache_allocator, fs::SubStorage data_storage, fs::SubStorage node_storage, fs::SubStorage entry_storage, s32 bktr_entry_count, size_t block_size_max, size_t continuous_reading_size_max, GetDecompressorFunction get_decompressor, size_t cache_size_0, size_t cache_size_1, s32 max_cache_entries) { /* Initialize our core. */ R_TRY(m_core.Initialize(bktr_allocator, data_storage, node_storage, entry_storage, bktr_entry_count, block_size_max, continuous_reading_size_max, get_decompressor)); /* Get our core size. */ s64 core_size = 0; R_TRY(m_core.GetSize(std::addressof(core_size))); /* Initialize our cache manager. */ R_TRY(m_cache_manager.Initialize(cache_allocator, core_size, cache_size_0, cache_size_1, max_cache_entries)); R_SUCCEED(); } void Finalize() { m_cache_manager.Finalize(); m_core.Finalize(); } fs::IStorage *GetDataStorage() { return m_core.GetDataStorage(); } Result GetDataStorageSize(s64 *out) { R_RETURN(m_core.GetDataStorageSize(out)); } Result GetEntryList(Entry *out_entries, s32 *out_read_count, s32 max_entry_count, s64 offset, s64 size) { R_RETURN(m_core.GetEntryList(out_entries, out_read_count, max_entry_count, offset, size)); } fssystem::BucketTree &GetEntryTable() { return m_core.GetEntryTable(); } public: virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) override { R_RETURN(m_core.QueryAppropriateOffsetForAsynchronousAccess(out, offset, access_size, alignment_size)); } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(m_cache_manager.Read(m_core, offset, buffer, size)); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { AMS_UNUSED(src, src_size); /* Check pre-conditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(size >= 0); /* Perform the operation. */ switch (op_id) { case fs::OperationId::Invalidate: m_cache_manager.Invalidate(); R_TRY(m_core.Invalidate()); break; case fs::OperationId::QueryRange: R_TRY(m_core.QueryRange(dst, dst_size, offset, size)); break; default: R_THROW(fs::ResultUnsupportedOperateRangeForCompressedStorage()); } R_SUCCEED(); } virtual Result GetSize(s64 *out) override { R_RETURN(m_core.GetSize(out)); } virtual Result Flush() override { R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { AMS_UNUSED(offset, buffer, size); R_THROW(fs::ResultUnsupportedWriteForCompressedStorage()); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); /* NOTE: Is Nintendo returning the wrong result here? */ R_THROW(fs::ResultUnsupportedSetSizeForIndirectStorage()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compression_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ enum CompressionType : u8 { CompressionType_None = 0, CompressionType_Zeros = 1, CompressionType_2 = 2, CompressionType_Lz4 = 3, CompressionType_Unknown = 4, }; using DecompressorFunction = Result (*)(void *, size_t, const void *, size_t); using GetDecompressorFunction = DecompressorFunction (*)(CompressionType); constexpr s64 CompressionBlockAlignment = 0x10; namespace CompressionTypeUtility { constexpr bool IsBlockAlignmentRequired(CompressionType type) { return type != CompressionType_None && type != CompressionType_Zeros; } constexpr bool IsDataStorageAccessRequired(CompressionType type) { return type != CompressionType_Zeros; } constexpr bool IsRandomAccessible(CompressionType type) { return type == CompressionType_None; } constexpr bool IsUnknownType(CompressionType type) { return type >= CompressionType_Unknown; } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_compression_configuration.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> namespace ams::fssystem { const ::ams::fssystem::NcaCompressionConfiguration *GetNcaCompressionConfiguration(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_crypto_configuration.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> #include <stratosphere/ncm/ncm_content_meta_platform.hpp> namespace ams::fssystem { const ::ams::fssystem::NcaCryptoConfiguration *GetNcaCryptoConfiguration(bool prod); void SetUpKekAccessKeys(bool prod); void InvalidateHardwareAesKey(); bool IsValidSignatureKeyGeneration(ncm::ContentMetaPlatform platform, size_t key_generation); const u8 *GetAcidSignatureKeyModulus(ncm::ContentMetaPlatform platform, bool prod, size_t key_generation, bool unk_unused); size_t GetAcidSignatureKeyModulusSize(ncm::ContentMetaPlatform platform, bool unk_unused); const u8 *GetAcidSignatureKeyPublicExponent(); constexpr inline size_t AcidSignatureKeyPublicExponentSize = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { class DirectoryRedirectionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(DirectoryRedirectionFileSystem); private: std::unique_ptr<fs::fsa::IFileSystem> m_base_fs; fs::Path m_before_dir; fs::Path m_after_dir; public: DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs) : m_base_fs(std::move(fs)), m_before_dir(), m_after_dir() { /* ... */ } Result InitializeWithFixedPath(const char *before, const char *after) { R_TRY(fs::SetUpFixedPath(std::addressof(m_before_dir), before)); R_TRY(fs::SetUpFixedPath(std::addressof(m_after_dir), after)); R_SUCCEED(); } private: Result ResolveFullPath(fs::Path *out, const fs::Path &path) { if (path.IsMatchHead(m_before_dir.GetString(), m_before_dir.GetLength())) { R_TRY(out->Initialize(m_after_dir)); R_TRY(out->AppendChild(path.GetString() + m_before_dir.GetLength())); } else { R_TRY(out->Initialize(path)); } R_SUCCEED(); } public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CreateFile(full_path, size, option)); } virtual Result DoDeleteFile(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteFile(full_path)); } virtual Result DoCreateDirectory(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CreateDirectory(full_path)); } virtual Result DoDeleteDirectory(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteDirectory(full_path)); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path)); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { fs::Path old_full_path; fs::Path new_full_path; R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path)); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { fs::Path old_full_path; fs::Path new_full_path; R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path)); } virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetEntryType(out, full_path)); } virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode)); } virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode)); } virtual Result DoCommit() override { R_RETURN(m_base_fs->Commit()); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path)); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path)); } virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_path)); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path)); } /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override { R_RETURN(m_base_fs->CommitProvisionally(counter)); } virtual Result DoRollback() override { R_RETURN(m_base_fs->Rollback()); } virtual Result DoFlush() override { R_RETURN(m_base_fs->Flush()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class DirectorySaveDataFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(DirectorySaveDataFileSystem); private: std::unique_ptr<fs::fsa::IFileSystem> m_unique_fs; fs::fsa::IFileSystem * const m_base_fs; os::SdkMutex m_accessor_mutex = {}; s32 m_open_writable_files = 0; bool m_is_journaling_supported = false; bool m_is_multi_commit_supported = false; bool m_is_journaling_enabled = false; /* Extension member to ensure proper savedata locking. */ std::unique_ptr<fs::fsa::IFile> m_lock_file = nullptr; public: DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs) : m_unique_fs(std::move(fs)), m_base_fs(m_unique_fs.get()) { /* ... */ } DirectorySaveDataFileSystem(fs::fsa::IFileSystem *fs) : m_unique_fs(), m_base_fs(fs) { /* ... */ } Result Initialize(bool journaling_supported, bool multi_commit_enabled, bool journaling_enabled); private: Result SynchronizeDirectory(const fs::Path &dst, const fs::Path &src); Result ResolvePath(fs::Path *out, const fs::Path &path); Result AcquireLockFile(); public: void DecrementWriteOpenFileCount(); public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override; virtual Result DoDeleteFile(const fs::Path &path) override; virtual Result DoCreateDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; virtual Result DoRollback() override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_external_code.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> namespace ams::fssystem { fs::fsa::IFileSystem *GetExternalCodeFileSystem(ncm::ProgramId program_id); Result CreateExternalCode(os::NativeHandle *out, ncm::ProgramId program_id); void DestroyExternalCode(ncm::ProgramId program_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_file_system_proxy_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssrv::fscreator { struct FileSystemCreatorInterfaces; } namespace ams::fssystem { /* TODO: This is kind of really a fs process function/tied into fs main. */ /* This should be re-examined when FS is reimplemented. */ void InitializeForFileSystemProxy(); void InitializeForAtmosphereMitm(); const ::ams::fssrv::fscreator::FileSystemCreatorInterfaces *GetFileSystemCreatorInterfaces(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_forwarding_file_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/fs_query_range.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ForwardingFile final : public ::ams::fs::fsa::IFile, public ::ams::fs::impl::Newable { NON_COPYABLE(ForwardingFile); NON_MOVEABLE(ForwardingFile); private: std::unique_ptr<fs::fsa::IFile> m_base_file; public: ForwardingFile(std::unique_ptr<fs::fsa::IFile> f) : m_base_file(std::move(f)) { /* ... */ } virtual ~ForwardingFile() { /* ... */ } public: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { R_RETURN(m_base_file->Read(out, offset, buffer, size, option)); } virtual Result DoGetSize(s64 *out) override final { R_RETURN(m_base_file->GetSize(out)); } virtual Result DoFlush() override final { R_RETURN(m_base_file->Flush()); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { R_RETURN(m_base_file->Write(offset, buffer, size, option)); } virtual Result DoSetSize(s64 size) override final { R_RETURN(m_base_file->SetSize(size)); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { R_RETURN(m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { return m_base_file->GetDomainObjectId(); } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ForwardingDirectory final : public ::ams::fs::fsa::IDirectory, public ::ams::fs::impl::Newable { NON_COPYABLE(ForwardingDirectory); NON_MOVEABLE(ForwardingDirectory); private: std::unique_ptr<fs::fsa::IDirectory> m_base_dir; public: ForwardingDirectory(std::unique_ptr<fs::fsa::IDirectory> d) : m_base_dir(std::move(d)) { /* ... */ } virtual ~ForwardingDirectory() { /* ... */ } public: virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override final { R_RETURN(m_base_dir->Read(out_count, out_entries, max_entries)); } virtual Result DoGetEntryCount(s64 *out) override final { R_RETURN(m_base_dir->GetEntryCount(out)); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { return m_base_dir->GetDomainObjectId(); } }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ForwardingFileSystem final : public ::ams::fs::fsa::IFileSystem, public ::ams::fs::impl::Newable { NON_COPYABLE(ForwardingFileSystem); NON_MOVEABLE(ForwardingFileSystem); private: std::shared_ptr<fs::fsa::IFileSystem> m_base_fs; public: ForwardingFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs) : m_base_fs(std::move(fs)) { /* ... */ } virtual ~ForwardingFileSystem() { /* ... */ } public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { R_RETURN(m_base_fs->CreateFile(path, size, flags)); } virtual Result DoDeleteFile(const fs::Path &path) override final { R_RETURN(m_base_fs->DeleteFile(path)); } virtual Result DoCreateDirectory(const fs::Path &path) override final { R_RETURN(m_base_fs->CreateDirectory(path)); } virtual Result DoDeleteDirectory(const fs::Path &path) override final { R_RETURN(m_base_fs->DeleteDirectory(path)); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { R_RETURN(m_base_fs->DeleteDirectoryRecursively(path)); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { R_RETURN(m_base_fs->RenameFile(old_path, new_path)); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { R_RETURN(m_base_fs->RenameDirectory(old_path, new_path)); } virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetEntryType(out, path)); } virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override final { R_RETURN(m_base_fs->OpenFile(out_file, path, mode)); } virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override final { R_RETURN(m_base_fs->OpenDirectory(out_dir, path, mode)); } virtual Result DoCommit() override final { R_RETURN(m_base_fs->Commit()); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetFreeSpaceSize(out, path)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetTotalSpaceSize(out, path)); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { R_RETURN(m_base_fs->CleanDirectoryRecursively(path)); } virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override final { R_RETURN(m_base_fs->GetFileTimeStampRaw(out, path)); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override final { R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, path)); } virtual Result DoCommitProvisionally(s64 counter) override final { R_RETURN(m_base_fs->CommitProvisionally(counter)); } virtual Result DoRollback() override final { R_RETURN(m_base_fs->Rollback()); } virtual Result DoFlush() override final { R_RETURN(m_base_fs->Flush()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_hierarchical_integrity_verification_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_substorage.hpp> #include <stratosphere/fs/fs_storage_type.hpp> #include <stratosphere/fssystem/fssystem_integrity_verification_storage.hpp> #include <stratosphere/fssystem/fssystem_block_cache_buffered_storage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ struct HierarchicalIntegrityVerificationLevelInformation { fs::Int64 offset; fs::Int64 size; s32 block_order; u8 reserved[4]; }; static_assert(util::is_pod<HierarchicalIntegrityVerificationLevelInformation>::value); static_assert(sizeof(HierarchicalIntegrityVerificationLevelInformation) == 0x18); static_assert(alignof(HierarchicalIntegrityVerificationLevelInformation) == 0x4); struct HierarchicalIntegrityVerificationInformation { u32 max_layers; HierarchicalIntegrityVerificationLevelInformation info[IntegrityMaxLayerCount - 1]; fs::HashSalt seed; s64 GetLayeredHashSize() const { return this->info[this->max_layers - 2].offset; } s64 GetDataOffset() const { return this->info[this->max_layers - 2].offset; } s64 GetDataSize() const { return this->info[this->max_layers - 2].size; } }; static_assert(util::is_pod<HierarchicalIntegrityVerificationInformation>::value); struct HierarchicalIntegrityVerificationMetaInformation { u32 magic; u32 version; u32 master_hash_size; HierarchicalIntegrityVerificationInformation level_hash_info; /* TODO: Format */ }; static_assert(util::is_pod<HierarchicalIntegrityVerificationMetaInformation>::value); struct HierarchicalIntegrityVerificationSizeSet { s64 control_size; s64 master_hash_size; s64 layered_hash_sizes[IntegrityMaxLayerCount - 2]; }; static_assert(util::is_pod<HierarchicalIntegrityVerificationSizeSet>::value); class HierarchicalIntegrityVerificationStorageControlArea { NON_COPYABLE(HierarchicalIntegrityVerificationStorageControlArea); NON_MOVEABLE(HierarchicalIntegrityVerificationStorageControlArea); public: static constexpr size_t HashSize = crypto::Sha256Generator::HashSize; struct InputParam { size_t level_block_size[IntegrityMaxLayerCount - 1]; }; static_assert(util::is_pod<InputParam>::value); private: fs::SubStorage m_storage; HierarchicalIntegrityVerificationMetaInformation m_meta; public: static Result QuerySize(HierarchicalIntegrityVerificationSizeSet *out, const InputParam &input_param, s32 layer_count, s64 data_size); /* TODO Format */ static Result Expand(fs::SubStorage meta_storage, const HierarchicalIntegrityVerificationMetaInformation &meta); public: HierarchicalIntegrityVerificationStorageControlArea() { /* ... */ } Result Initialize(fs::SubStorage meta_storage); void Finalize(); u32 GetMasterHashSize() const { return m_meta.master_hash_size; } void GetLevelHashInfo(HierarchicalIntegrityVerificationInformation *out) { AMS_ASSERT(out != nullptr); *out = m_meta.level_hash_info; } }; class HierarchicalIntegrityVerificationStorage : public ::ams::fs::IStorage { NON_COPYABLE(HierarchicalIntegrityVerificationStorage); NON_MOVEABLE(HierarchicalIntegrityVerificationStorage); private: friend struct HierarchicalIntegrityVerificationMetaInformation; protected: static constexpr s64 HashSize = crypto::Sha256Generator::HashSize; static constexpr size_t MaxLayers = IntegrityMaxLayerCount; public: using GenerateRandomFunction = void (*)(void *dst, size_t size); class HierarchicalStorageInformation { public: enum { MasterStorage = 0, Layer1Storage = 1, Layer2Storage = 2, Layer3Storage = 3, Layer4Storage = 4, Layer5Storage = 5, DataStorage = 6, }; private: fs::SubStorage m_storages[DataStorage + 1]; public: void SetMasterHashStorage(fs::SubStorage s) { m_storages[MasterStorage] = s; } void SetLayer1HashStorage(fs::SubStorage s) { m_storages[Layer1Storage] = s; } void SetLayer2HashStorage(fs::SubStorage s) { m_storages[Layer2Storage] = s; } void SetLayer3HashStorage(fs::SubStorage s) { m_storages[Layer3Storage] = s; } void SetLayer4HashStorage(fs::SubStorage s) { m_storages[Layer4Storage] = s; } void SetLayer5HashStorage(fs::SubStorage s) { m_storages[Layer5Storage] = s; } void SetDataStorage(fs::SubStorage s) { m_storages[DataStorage] = s; } fs::SubStorage &operator[](s32 index) { AMS_ASSERT(MasterStorage <= index && index <= DataStorage); return m_storages[index]; } }; private: static GenerateRandomFunction s_generate_random; static void SetGenerateRandomFunction(GenerateRandomFunction func) { s_generate_random = func; } private: FileSystemBufferManagerSet *m_buffers; os::SdkRecursiveMutex *m_mutex; IntegrityVerificationStorage m_verify_storages[MaxLayers - 1]; BlockCacheBufferedStorage m_buffer_storages[MaxLayers - 1]; os::Semaphore *m_read_semaphore; os::Semaphore *m_write_semaphore; s64 m_data_size; s32 m_max_layers; public: HierarchicalIntegrityVerificationStorage() : m_buffers(nullptr), m_mutex(nullptr), m_data_size(-1) { /* ... */ } virtual ~HierarchicalIntegrityVerificationStorage() override { this->Finalize(); } Result Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, IHash256GeneratorFactory *hgf, bool hash_salt_enabled, os::SdkRecursiveMutex *mtx, os::Semaphore *read_sema, os::Semaphore *write_sema, int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level, bool is_writable, bool allow_cleared_blocks); Result Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, IHash256GeneratorFactory *hgf, bool hash_salt_enabled, os::SdkRecursiveMutex *mtx, int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level, bool is_writable, bool allow_cleared_blocks) { R_RETURN(this->Initialize(info, storage, bufs, hgf, hash_salt_enabled, mtx, nullptr, nullptr, max_data_cache_entries, max_hash_cache_entries, buffer_level, is_writable, allow_cleared_blocks)); } void Finalize(); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForHierarchicalIntegrityVerificationStorage()); } virtual Result GetSize(s64 *out) override; virtual Result Flush() override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; using IStorage::OperateRange; Result Commit(); Result OnRollback(); bool IsInitialized() const { return m_data_size >= 0; } FileSystemBufferManagerSet *GetBuffers() { return m_buffers; } void GetParameters(HierarchicalIntegrityVerificationStorageControlArea::InputParam *out) const { AMS_ASSERT(out != nullptr); for (auto level = 0; level <= m_max_layers - 2; ++level) { out->level_block_size[level] = static_cast<size_t>(m_verify_storages[level].GetBlockSize()); } } s64 GetL1HashVerificationBlockSize() const { return m_verify_storages[m_max_layers - 2].GetBlockSize(); } fs::SubStorage GetL1HashStorage() { return fs::SubStorage(std::addressof(m_buffer_storages[m_max_layers - 3]), 0, util::DivideUp(m_data_size, this->GetL1HashVerificationBlockSize())); } public: static constexpr s8 GetDefaultDataCacheBufferLevel(u32 max_layers) { return 16 + max_layers - 2; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_i_hash_256_generator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem { enum HashAlgorithmType : u8 { HashAlgorithmType_Sha2 = 0, HashAlgorithmType_Sha3 = 1, }; /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IHash256Generator { public: static constexpr size_t HashSize = 256 / BITSIZEOF(u8); public: constexpr IHash256Generator() = default; virtual constexpr ~IHash256Generator() { /* ... */ } public: void Initialize() { return this->DoInitialize(); } void Update(const void *data, size_t size) { /* Check pre-conditions. */ AMS_ASSERT(data != nullptr); return this->DoUpdate(data, size); } void GetHash(void *dst, size_t dst_size) { /* Check pre-conditions. */ AMS_ASSERT(dst_size == HashSize); return this->DoGetHash(dst, dst_size); } protected: virtual void DoInitialize() = 0; virtual void DoUpdate(const void *data, size_t size) = 0; virtual void DoGetHash(void *dst, size_t dst_size) = 0; }; /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IHash256GeneratorFactory { public: constexpr IHash256GeneratorFactory() = default; virtual constexpr ~IHash256GeneratorFactory() { /* ... */ } Result Create(std::unique_ptr<IHash256Generator> *out) { return this->DoCreate(out); } void GenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) { /* Check pre-conditions. */ AMS_ASSERT(dst != nullptr); AMS_ASSERT(src != nullptr); AMS_ASSERT(dst_size == IHash256Generator::HashSize); return this->DoGenerateHash(dst, dst_size, src, src_size); } protected: virtual Result DoCreate(std::unique_ptr<IHash256Generator> *out) = 0; virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) = 0; }; /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IHash256GeneratorFactorySelector { public: constexpr IHash256GeneratorFactorySelector() = default; virtual constexpr ~IHash256GeneratorFactorySelector() { /* ... */ } IHash256GeneratorFactory *GetFactory(HashAlgorithmType alg) { return this->DoGetFactory(alg); } protected: virtual IHash256GeneratorFactory *DoGetFactory(HashAlgorithmType alg) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_indirect_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class IndirectStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(IndirectStorage); NON_MOVEABLE(IndirectStorage); public: static constexpr s32 StorageCount = 2; static constexpr size_t NodeSize = 16_KB; using IAllocator = MemoryResource; struct Entry { u8 virt_offset[sizeof(s64)]; u8 phys_offset[sizeof(s64)]; s32 storage_index; void SetVirtualOffset(const s64 &ofs) { std::memcpy(this->virt_offset, std::addressof(ofs), sizeof(s64)); } s64 GetVirtualOffset() const { s64 offset; std::memcpy(std::addressof(offset), this->virt_offset, sizeof(s64)); return offset; } void SetPhysicalOffset(const s64 &ofs) { std::memcpy(this->phys_offset, std::addressof(ofs), sizeof(s64)); } s64 GetPhysicalOffset() const { s64 offset; std::memcpy(std::addressof(offset), this->phys_offset, sizeof(s64)); return offset; } }; static_assert(util::is_pod<Entry>::value); static_assert(sizeof(Entry) == 0x14); struct EntryData { s64 virt_offset; s64 phys_offset; s32 storage_index; void Set(const Entry &entry) { this->virt_offset = entry.GetVirtualOffset(); this->phys_offset = entry.GetPhysicalOffset(); this->storage_index = entry.storage_index; } }; static_assert(util::is_pod<EntryData>::value); private: struct ContinuousReadingEntry { static constexpr size_t FragmentSizeMax = 4_KB; IndirectStorage::Entry entry; s64 GetVirtualOffset() const { return this->entry.GetVirtualOffset(); } s64 GetPhysicalOffset() const { return this->entry.GetPhysicalOffset(); } bool IsFragment() const { return this->entry.storage_index != 0; } }; static_assert(util::is_pod<ContinuousReadingEntry>::value); public: static constexpr s64 QueryHeaderStorageSize() { return BucketTree::QueryHeaderStorageSize(); } static constexpr s64 QueryNodeStorageSize(s32 entry_count) { return BucketTree::QueryNodeStorageSize(NodeSize, sizeof(Entry), entry_count); } static constexpr s64 QueryEntryStorageSize(s32 entry_count) { return BucketTree::QueryEntryStorageSize(NodeSize, sizeof(Entry), entry_count); } private: BucketTree m_table; fs::SubStorage m_data_storage[StorageCount]; public: IndirectStorage() : m_table(), m_data_storage() { /* ... */ } virtual ~IndirectStorage() { this->Finalize(); } Result Initialize(IAllocator *allocator, fs::SubStorage table_storage); void Finalize(); bool IsInitialized() const { return m_table.IsInitialized(); } Result Initialize(IAllocator *allocator, fs::SubStorage node_storage, fs::SubStorage entry_storage, s32 entry_count) { R_RETURN(m_table.Initialize(allocator, node_storage, entry_storage, NodeSize, sizeof(Entry), entry_count)); } void SetStorage(s32 idx, fs::SubStorage storage) { AMS_ASSERT(0 <= idx && idx < StorageCount); m_data_storage[idx] = storage; } template<typename T> void SetStorage(s32 idx, T storage, s64 offset, s64 size) { AMS_ASSERT(0 <= idx && idx < StorageCount); m_data_storage[idx] = fs::SubStorage(storage, offset, size); } Result GetEntryList(Entry *out_entries, s32 *out_entry_count, s32 entry_count, s64 offset, s64 size); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); BucketTree::Offsets offsets; R_TRY(m_table.GetOffsets(std::addressof(offsets))); *out = offsets.end_offset; R_SUCCEED(); } virtual Result Flush() override { R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { AMS_UNUSED(offset, buffer, size); R_THROW(fs::ResultUnsupportedWriteForIndirectStorage()); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForIndirectStorage()); } protected: BucketTree &GetEntryTable() { return m_table; } fs::SubStorage &GetDataStorage(s32 index) { AMS_ASSERT(0 <= index && index < StorageCount); return m_data_storage[index]; } template<bool ContinuousCheck, bool RangeCheck, typename F> Result OperatePerEntry(s64 offset, s64 size, F func); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_indirect_storage_template_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_indirect_storage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ template<bool ContinuousCheck, bool RangeCheck, typename F> Result IndirectStorage::OperatePerEntry(s64 offset, s64 size, F func) { /* Validate preconditions. */ AMS_ASSERT(offset >= 0); AMS_ASSERT(size >= 0); AMS_ASSERT(this->IsInitialized()); /* Succeed if there's nothing to operate on. */ R_SUCCEED_IF(size == 0); /* Get the table offsets. */ BucketTree::Offsets table_offsets; R_TRY(m_table.GetOffsets(std::addressof(table_offsets))); /* Validate arguments. */ R_UNLESS(table_offsets.IsInclude(offset, size), fs::ResultOutOfRange()); /* Find the offset in our tree. */ BucketTree::Visitor visitor; R_TRY(m_table.Find(std::addressof(visitor), offset)); { const auto entry_offset = visitor.Get<Entry>()->GetVirtualOffset(); R_UNLESS(0 <= entry_offset && table_offsets.IsInclude(entry_offset), fs::ResultInvalidIndirectEntryOffset()); } /* Prepare to operate in chunks. */ auto cur_offset = offset; const auto end_offset = offset + static_cast<s64>(size); BucketTree::ContinuousReadingInfo cr_info; while (cur_offset < end_offset) { /* Get the current entry. */ const auto cur_entry = *visitor.Get<Entry>(); /* Get and validate the entry's offset. */ const auto cur_entry_offset = cur_entry.GetVirtualOffset(); R_UNLESS(cur_entry_offset <= cur_offset, fs::ResultInvalidIndirectEntryOffset()); /* Validate the storage index. */ R_UNLESS(0 <= cur_entry.storage_index && cur_entry.storage_index < StorageCount, fs::ResultInvalidIndirectEntryStorageIndex()); /* If we need to check the continuous info, do so. */ if constexpr (ContinuousCheck) { /* Scan, if we need to. */ if (cr_info.CheckNeedScan()) { R_TRY(visitor.ScanContinuousReading<ContinuousReadingEntry>(std::addressof(cr_info), cur_offset, static_cast<size_t>(end_offset - cur_offset))); } /* Process a base storage entry. */ if (cr_info.CanDo()) { /* Ensure that we can process. */ R_UNLESS(cur_entry.storage_index == 0, fs::ResultInvalidIndirectEntryStorageIndex()); /* Ensure that we remain within range. */ const auto data_offset = cur_offset - cur_entry_offset; const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset(); const auto cur_size = static_cast<s64>(cr_info.GetReadSize()); /* If we should, verify the range. */ if constexpr (RangeCheck) { /* Get the current data storage's size. */ s64 cur_data_storage_size; R_TRY(m_data_storage[0].GetSize(std::addressof(cur_data_storage_size))); R_UNLESS(0 <= cur_entry_phys_offset && cur_entry_phys_offset <= cur_data_storage_size, fs::ResultInvalidIndirectEntryOffset()); R_UNLESS(cur_entry_phys_offset + data_offset + cur_size <= cur_data_storage_size, fs::ResultInvalidIndirectStorageSize()); } /* Operate. */ R_TRY(func(std::addressof(m_data_storage[0]), cur_entry_phys_offset + data_offset, cur_offset, cur_size)); /* Mark as done. */ cr_info.Done(); } } /* Get and validate the next entry offset. */ s64 next_entry_offset; if (visitor.CanMoveNext()) { R_TRY(visitor.MoveNext()); next_entry_offset = visitor.Get<Entry>()->GetVirtualOffset(); R_UNLESS(table_offsets.IsInclude(next_entry_offset), fs::ResultInvalidIndirectEntryOffset()); } else { next_entry_offset = table_offsets.end_offset; } R_UNLESS(cur_offset < next_entry_offset, fs::ResultInvalidIndirectEntryOffset()); /* Get the offset of the entry in the data we read. */ const auto data_offset = cur_offset - cur_entry_offset; const auto data_size = (next_entry_offset - cur_entry_offset); AMS_ASSERT(data_size > 0); /* Determine how much is left. */ const auto remaining_size = end_offset - cur_offset; const auto cur_size = std::min<s64>(remaining_size, data_size - data_offset); AMS_ASSERT(cur_size <= size); /* Operate, if we need to. */ bool needs_operate; if constexpr (!ContinuousCheck) { needs_operate = true; } else { needs_operate = !cr_info.IsDone() || cur_entry.storage_index != 0; } if (needs_operate) { const auto cur_entry_phys_offset = cur_entry.GetPhysicalOffset(); if constexpr (RangeCheck) { /* Get the current data storage's size. */ s64 cur_data_storage_size; R_TRY(m_data_storage[cur_entry.storage_index].GetSize(std::addressof(cur_data_storage_size))); /* Ensure that we remain within range. */ R_UNLESS(0 <= cur_entry_phys_offset && cur_entry_phys_offset <= cur_data_storage_size, fs::ResultIndirectStorageCorrupted()); R_UNLESS(cur_entry_phys_offset + data_offset + cur_size <= cur_data_storage_size, fs::ResultIndirectStorageCorrupted()); } R_TRY(func(std::addressof(m_data_storage[cur_entry.storage_index]), cur_entry_phys_offset + data_offset, cur_offset, cur_size)); } cur_offset += cur_size; } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_integrity_romfs_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_memory_storage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fssystem/fssystem_nca_header.hpp> #include <stratosphere/fssystem/fssystem_hierarchical_integrity_verification_storage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline size_t IntegrityLayerCountRomFs = 7; constexpr inline size_t IntegrityHashLayerBlockSize = 16_KB; class IntegrityRomFsStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { private: HierarchicalIntegrityVerificationStorage m_integrity_storage; FileSystemBufferManagerSet m_buffers; os::SdkRecursiveMutex m_mutex; Hash m_master_hash; std::unique_ptr<fs::MemoryStorage> m_master_hash_storage; public: IntegrityRomFsStorage() : m_mutex() { /* ... */ } virtual ~IntegrityRomFsStorage() override { this->Finalize(); } Result Initialize(HierarchicalIntegrityVerificationInformation level_hash_info, Hash master_hash, HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation storage_info, fs::IBufferManager *bm, int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level, IHash256GeneratorFactory *hgf); void Finalize(); virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(m_integrity_storage.Read(offset, buffer, size)); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_RETURN(m_integrity_storage.Write(offset, buffer, size)); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForIntegrityRomFsStorage()); } virtual Result GetSize(s64 *out) override { R_RETURN(m_integrity_storage.GetSize(out)); } virtual Result Flush() override { R_RETURN(m_integrity_storage.Flush()); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { R_RETURN(m_integrity_storage.OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } Result Commit() { R_RETURN(m_integrity_storage.Commit()); } FileSystemBufferManagerSet *GetBuffers() { return m_integrity_storage.GetBuffers(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_integrity_verification_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/fs_substorage.hpp> #include <stratosphere/fs/fs_storage_type.hpp> #include <stratosphere/fssystem/fssystem_block_cache_buffered_storage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IntegrityVerificationStorage : public ::ams::fs::IStorage { NON_COPYABLE(IntegrityVerificationStorage); NON_MOVEABLE(IntegrityVerificationStorage); public: static constexpr s64 HashSize = crypto::Sha256Generator::HashSize; struct BlockHash { u8 hash[HashSize]; }; static_assert(util::is_pod<BlockHash>::value); private: fs::SubStorage m_hash_storage; fs::SubStorage m_data_storage; s64 m_verification_block_size; s64 m_verification_block_order; s64 m_upper_layer_verification_block_size; s64 m_upper_layer_verification_block_order; fs::IBufferManager *m_buffer_manager; util::optional<fs::HashSalt> m_salt; bool m_is_real_data; fssystem::IHash256GeneratorFactory *m_hash_generator_factory; bool m_is_writable; bool m_allow_cleared_blocks; public: IntegrityVerificationStorage() : m_verification_block_size(0), m_verification_block_order(0), m_upper_layer_verification_block_size(0), m_upper_layer_verification_block_order(0), m_buffer_manager(nullptr), m_salt(util::nullopt) { /* ... */ } virtual ~IntegrityVerificationStorage() override { this->Finalize(); } void Initialize(fs::SubStorage hs, fs::SubStorage ds, s64 verif_block_size, s64 upper_layer_verif_block_size, fs::IBufferManager *bm, fssystem::IHash256GeneratorFactory *hgf, const util::optional<fs::HashSalt> &salt, bool is_real_data, bool is_writable, bool allow_cleared_blocks); void Finalize(); virtual Result Read(s64 offset, void *buffer, size_t size) override; virtual Result Write(s64 offset, const void *buffer, size_t size) override; virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForIntegrityVerificationStorage()); } virtual Result GetSize(s64 *out) override; virtual Result Flush() override; virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; using IStorage::OperateRange; void CalcBlockHash(BlockHash *out, const void *buffer, std::unique_ptr<fssystem::IHash256Generator> &generator) const { return this->CalcBlockHash(out, buffer, static_cast<size_t>(m_verification_block_size), generator); } s64 GetBlockSize() const { return m_verification_block_size; } private: Result ReadBlockSignature(void *dst, size_t dst_size, s64 offset, size_t size); Result WriteBlockSignature(const void *src, size_t src_size, s64 offset, size_t size); Result VerifyHash(const void *buf, BlockHash *hash, std::unique_ptr<fssystem::IHash256Generator> &generator); void CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size, std::unique_ptr<fssystem::IHash256Generator> &generator) const; Result IsCleared(bool *is_cleared, const BlockHash &hash); private: static void SetValidationBit(BlockHash *hash) { AMS_ASSERT(hash != nullptr); hash->hash[HashSize - 1] |= 0x80; } static bool IsValidationBit(const BlockHash *hash) { AMS_ASSERT(hash != nullptr); return (hash->hash[HashSize - 1] & 0x80) != 0; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_local_file_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/fs_memory_management.hpp> #include <stratosphere/fs/fs_path.hpp> namespace ams::fssystem { /* TODO: Put this in its own header? */ enum PathCaseSensitiveMode { PathCaseSensitiveMode_CaseInsensitive = 0, PathCaseSensitiveMode_CaseSensitive = 1, }; /* ACCURATE_TO_VERSION: 13.4.0.0 */ class LocalFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(LocalFileSystem); NON_MOVEABLE(LocalFileSystem); private: #if defined(ATMOSPHERE_OS_WINDOWS) using NativeCharacterType = wchar_t; #else using NativeCharacterType = char; #endif using NativePathBuffer = std::unique_ptr<NativeCharacterType[], ::ams::fs::impl::Deleter>; private: fs::Path m_root_path; fssystem::PathCaseSensitiveMode m_case_sensitive_mode; NativePathBuffer m_native_path_buffer; int m_native_path_length; bool m_use_posix_time; public: LocalFileSystem(bool posix_time = true) : m_root_path(), m_native_path_buffer(), m_native_path_length(0), m_use_posix_time(posix_time) { /* ... */ } Result Initialize(const fs::Path &root_path, fssystem::PathCaseSensitiveMode case_sensitive_mode); Result GetCaseSensitivePath(int *out_size, char *dst, size_t dst_size, const char *path, const char *work_path); private: Result CheckPathCaseSensitively(const NativeCharacterType *path, const NativeCharacterType *root_path, NativeCharacterType *cs_buf, size_t cs_size, bool check_case_sensitivity); Result ResolveFullPath(NativePathBuffer *out, const fs::Path &path, int max_len, int min_len, bool check_case_sensitivity); public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; virtual Result DoDeleteFile(const fs::Path &path) override; virtual Result DoCreateDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override; virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; virtual Result DoRollback() override; public: Result DoGetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const fs::Path &path); Result DeleteDirectoryRecursivelyInternal(const NativeCharacterType *path, bool delete_top); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fssystem/fssystem_compression_common.hpp> #include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp> #include <stratosphere/fssystem/fssystem_asynchronous_access.hpp> #include <stratosphere/fssystem/fssystem_nca_header.hpp> #include <stratosphere/fs/fs_i_buffer_manager.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ class CompressedStorage; class AesCtrCounterExtendedStorage; class IndirectStorage; class SparseStorage; struct NcaCryptoConfiguration; using KeyGenerationFunction = void (*)(void *dst_key, size_t dst_key_size, const void *src_key, size_t src_key_size, s32 key_type); using DecryptAesCtrFunction = void (*)(void *dst, size_t dst_size, u8 key_index, u8 key_generation, const void *src_key, size_t src_key_size, const void *iv, size_t iv_size, const void *src, size_t src_size); using CryptAesXtsFunction = Result (*)(void *dst, size_t dst_size, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, const void *src, size_t src_size); using VerifySign1Function = bool (*)(const void *sig, size_t sig_size, const void *data, size_t data_size, u8 generation); struct NcaCryptoConfiguration { static constexpr size_t Rsa2048KeyModulusSize = crypto::Rsa2048PssSha256Verifier::ModulusSize; static constexpr size_t Rsa2048KeyPublicExponentSize = crypto::Rsa2048PssSha256Verifier::MaximumExponentSize; static constexpr size_t Rsa2048KeyPrivateExponentSize = Rsa2048KeyModulusSize; static constexpr size_t Aes128KeySize = crypto::AesEncryptor128::KeySize; static constexpr size_t Header1SignatureKeyGenerationMax = 1; static constexpr s32 KeyAreaEncryptionKeyIndexCount = 3; static constexpr s32 HeaderEncryptionKeyCount = 2; static constexpr u8 KeyAreaEncryptionKeyIndexZeroKey = 0xFF; static constexpr size_t KeyGenerationMax = 32; const u8 *header_1_sign_key_moduli[Header1SignatureKeyGenerationMax + 1]; u8 header_1_sign_key_public_exponent[Rsa2048KeyPublicExponentSize]; u8 key_area_encryption_key_source[KeyAreaEncryptionKeyIndexCount][Aes128KeySize]; u8 header_encryption_key_source[Aes128KeySize]; u8 header_encrypted_encryption_keys[HeaderEncryptionKeyCount][Aes128KeySize]; KeyGenerationFunction generate_key; CryptAesXtsFunction decrypt_aes_xts_external; CryptAesXtsFunction encrypt_aes_xts_external; DecryptAesCtrFunction decrypt_aes_ctr; DecryptAesCtrFunction decrypt_aes_ctr_external; VerifySign1Function verify_sign1; bool is_plaintext_header_available; bool is_available_sw_key; #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) bool is_unsigned_header_available_for_host_tool; #endif }; static_assert(util::is_pod<NcaCryptoConfiguration>::value); struct NcaCompressionConfiguration { GetDecompressorFunction get_decompressor; }; static_assert(util::is_pod<NcaCompressionConfiguration>::value); constexpr inline s32 KeyAreaEncryptionKeyCount = NcaCryptoConfiguration::KeyAreaEncryptionKeyIndexCount * NcaCryptoConfiguration::KeyGenerationMax; enum class KeyType : s32 { ZeroKey = -2, InvalidKey = -1, NcaHeaderKey1 = KeyAreaEncryptionKeyCount + 0, NcaHeaderKey2 = KeyAreaEncryptionKeyCount + 1, NcaExternalKey = KeyAreaEncryptionKeyCount + 2, SaveDataDeviceUniqueMac = KeyAreaEncryptionKeyCount + 3, SaveDataSeedUniqueMac = KeyAreaEncryptionKeyCount + 4, SaveDataTransferMac = KeyAreaEncryptionKeyCount + 5, }; constexpr inline bool IsInvalidKeyTypeValue(s32 key_type) { return key_type < 0; } constexpr inline s32 GetKeyTypeValue(u8 key_index, u8 key_generation) { if (key_index == NcaCryptoConfiguration::KeyAreaEncryptionKeyIndexZeroKey) { return util::ToUnderlying(KeyType::ZeroKey); } if (key_index >= NcaCryptoConfiguration::KeyAreaEncryptionKeyIndexCount) { return util::ToUnderlying(KeyType::InvalidKey); } return NcaCryptoConfiguration::KeyAreaEncryptionKeyIndexCount * key_generation + key_index; } class NcaReader : public ::ams::fs::impl::Newable { NON_COPYABLE(NcaReader); NON_MOVEABLE(NcaReader); private: NcaHeader m_header; u8 m_decryption_keys[NcaHeader::DecryptionKey_Count][NcaCryptoConfiguration::Aes128KeySize]; std::shared_ptr<fs::IStorage> m_body_storage; std::unique_ptr<fs::IStorage> m_header_storage; u8 m_external_decryption_key[NcaCryptoConfiguration::Aes128KeySize]; DecryptAesCtrFunction m_decrypt_aes_ctr; DecryptAesCtrFunction m_decrypt_aes_ctr_external; bool m_is_software_aes_prioritized; bool m_is_available_sw_key; NcaHeader::EncryptionType m_header_encryption_type; bool m_is_header_sign1_signature_valid; GetDecompressorFunction m_get_decompressor; IHash256GeneratorFactorySelector *m_hash_generator_factory_selector; public: NcaReader(); ~NcaReader(); Result Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg, const NcaCompressionConfiguration &compression_cfg, IHash256GeneratorFactorySelector *hgf_selector); std::shared_ptr<fs::IStorage> GetSharedBodyStorage(); u32 GetMagic() const; NcaHeader::DistributionType GetDistributionType() const; NcaHeader::ContentType GetContentType() const; u8 GetHeaderSign1KeyGeneration() const; u8 GetKeyGeneration() const; u8 GetKeyIndex() const; u64 GetContentSize() const; u64 GetProgramId() const; u32 GetContentIndex() const; u32 GetSdkAddonVersion() const; void GetRightsId(u8 *dst, size_t dst_size) const; bool HasFsInfo(s32 index) const; s32 GetFsCount() const; const Hash &GetFsHeaderHash(s32 index) const; void GetFsHeaderHash(Hash *dst, s32 index) const; void GetFsInfo(NcaHeader::FsInfo *dst, s32 index) const; u64 GetFsOffset(s32 index) const; u64 GetFsEndOffset(s32 index) const; u64 GetFsSize(s32 index) const; void GetEncryptedKey(void *dst, size_t size) const; const void *GetDecryptionKey(s32 index) const; bool HasValidInternalKey() const; bool HasInternalDecryptionKeyForAesHw() const; bool IsSoftwareAesPrioritized() const; void PrioritizeSoftwareAes(); bool IsAvailableSwKey() const; bool HasExternalDecryptionKey() const; const void *GetExternalDecryptionKey() const; void SetExternalDecryptionKey(const void *src, size_t size); void GetRawData(void *dst, size_t dst_size) const; DecryptAesCtrFunction GetExternalDecryptAesCtrFunction() const; DecryptAesCtrFunction GetExternalDecryptAesCtrFunctionForExternalKey() const; NcaHeader::EncryptionType GetEncryptionType() const; Result ReadHeader(NcaFsHeader *dst, s32 index) const; GetDecompressorFunction GetDecompressor() const; IHash256GeneratorFactorySelector *GetHashGeneratorFactorySelector() const; bool GetHeaderSign1Valid() const; void GetHeaderSign2(void *dst, size_t size) const; void GetHeaderSign2TargetHash(void *dst, size_t size) const; }; class NcaFsHeaderReader : public ::ams::fs::impl::Newable { NON_COPYABLE(NcaFsHeaderReader); NON_MOVEABLE(NcaFsHeaderReader); private: NcaFsHeader m_data; s32 m_fs_index; public: NcaFsHeaderReader() : m_fs_index(-1) { std::memset(std::addressof(m_data), 0, sizeof(m_data)); } Result Initialize(const NcaReader &reader, s32 index); bool IsInitialized() const { return m_fs_index >= 0; } // NcaFsHeader &GetData() { return m_data; } // const NcaFsHeader &GetData() const { return m_data; } void GetRawData(void *dst, size_t dst_size) const; NcaFsHeader::HashData &GetHashData(); const NcaFsHeader::HashData &GetHashData() const; u16 GetVersion() const; s32 GetFsIndex() const; NcaFsHeader::FsType GetFsType() const; NcaFsHeader::HashType GetHashType() const; NcaFsHeader::EncryptionType GetEncryptionType() const; NcaPatchInfo &GetPatchInfo(); const NcaPatchInfo &GetPatchInfo() const; const NcaAesCtrUpperIv GetAesCtrUpperIv() const; bool IsSkipLayerHashEncryption() const; Result GetHashTargetOffset(s64 *out) const; bool ExistsSparseLayer() const; NcaSparseInfo &GetSparseInfo(); const NcaSparseInfo &GetSparseInfo() const; bool ExistsCompressionLayer() const; NcaCompressionInfo &GetCompressionInfo(); const NcaCompressionInfo &GetCompressionInfo() const; bool ExistsPatchMetaHashLayer() const; NcaMetaDataHashDataInfo &GetPatchMetaDataHashDataInfo(); const NcaMetaDataHashDataInfo &GetPatchMetaDataHashDataInfo() const; NcaFsHeader::MetaDataHashType GetPatchMetaHashType() const; bool ExistsSparseMetaHashLayer() const; NcaMetaDataHashDataInfo &GetSparseMetaDataHashDataInfo(); const NcaMetaDataHashDataInfo &GetSparseMetaDataHashDataInfo() const; NcaFsHeader::MetaDataHashType GetSparseMetaHashType() const; }; class NcaFileSystemDriver : public ::ams::fs::impl::Newable { NON_COPYABLE(NcaFileSystemDriver); NON_MOVEABLE(NcaFileSystemDriver); #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) private: #else public: #endif struct StorageContext { bool open_raw_storage; std::shared_ptr<fs::IStorage> body_substorage; std::shared_ptr<fssystem::SparseStorage> current_sparse_storage; std::shared_ptr<fs::IStorage> sparse_storage_meta_storage; std::shared_ptr<fssystem::SparseStorage> original_sparse_storage; void *external_current_sparse_storage; /* TODO: Add real type? */ void *external_original_sparse_storage; /* TODO: Add real type? */ std::shared_ptr<fs::IStorage> aes_ctr_ex_storage_meta_storage; std::shared_ptr<fs::IStorage> aes_ctr_ex_storage_data_storage; std::shared_ptr<fssystem::AesCtrCounterExtendedStorage> aes_ctr_ex_storage; std::shared_ptr<fs::IStorage> indirect_storage_meta_storage; std::shared_ptr<fssystem::IndirectStorage> indirect_storage; std::shared_ptr<fs::IStorage> fs_data_storage; std::shared_ptr<fs::IStorage> compressed_storage_meta_storage; std::shared_ptr<fssystem::CompressedStorage> compressed_storage; std::shared_ptr<fs::IStorage> patch_layer_info_storage; std::shared_ptr<fs::IStorage> sparse_layer_info_storage; /* For tools. */ std::shared_ptr<fs::IStorage> external_original_storage; }; private: enum AlignmentStorageRequirement { /* TODO */ AlignmentStorageRequirement_CacheBlockSize = 0, AlignmentStorageRequirement_None = 1, }; private: std::shared_ptr<NcaReader> m_original_reader; std::shared_ptr<NcaReader> m_reader; MemoryResource * const m_allocator; fs::IBufferManager * const m_buffer_manager; fssystem::IHash256GeneratorFactorySelector * const m_hash_generator_factory_selector; public: static Result SetupFsHeaderReader(NcaFsHeaderReader *out, const NcaReader &reader, s32 fs_index); public: NcaFileSystemDriver(std::shared_ptr<NcaReader> reader, MemoryResource *allocator, fs::IBufferManager *buffer_manager, IHash256GeneratorFactorySelector *hgf_selector) : m_original_reader(), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager), m_hash_generator_factory_selector(hgf_selector) { AMS_ASSERT(m_reader != nullptr); AMS_ASSERT(m_hash_generator_factory_selector != nullptr); } NcaFileSystemDriver(std::shared_ptr<NcaReader> original_reader, std::shared_ptr<NcaReader> reader, MemoryResource *allocator, fs::IBufferManager *buffer_manager, IHash256GeneratorFactorySelector *hgf_selector) : m_original_reader(original_reader), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager), m_hash_generator_factory_selector(hgf_selector) { AMS_ASSERT(m_reader != nullptr); AMS_ASSERT(m_hash_generator_factory_selector != nullptr); } Result OpenStorageWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<IAsynchronousAccessSplitter> *out_splitter, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx); Result OpenStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<IAsynchronousAccessSplitter> *out_splitter, NcaFsHeaderReader *out_header_reader, s32 fs_index) { /* Create a storage context. */ StorageContext ctx{}; /* Open the storage. */ R_RETURN(OpenStorageWithContext(out, out_splitter, out_header_reader, fs_index, std::addressof(ctx))); } #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) private: #else public: #endif Result CreateStorageByRawStorage(std::shared_ptr<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, StorageContext *ctx); private: Result OpenStorageImpl(std::shared_ptr<fs::IStorage> *out, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx); Result OpenIndirectableStorageAsOriginal(std::shared_ptr<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, StorageContext *ctx); Result CreateBodySubStorage(std::shared_ptr<fs::IStorage> *out, s64 offset, s64 size); Result CreateAesCtrStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, AlignmentStorageRequirement alignment_storage_requirement); Result CreateAesXtsStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset); Result CreateSparseStorageMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info); Result CreateSparseStorageCore(std::shared_ptr<fssystem::SparseStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 base_size, std::shared_ptr<fs::IStorage> meta_storage, const NcaSparseInfo &sparse_info, bool external_info); Result CreateSparseStorage(std::shared_ptr<fs::IStorage> *out, s64 *out_fs_data_offset, std::shared_ptr<fssystem::SparseStorage> *out_sparse_storage, std::shared_ptr<fs::IStorage> *out_meta_storage, s32 index, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info); Result CreateSparseStorageMetaStorageWithVerification(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> *out_verification, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info, const NcaMetaDataHashDataInfo &meta_data_hash_data_info, IHash256GeneratorFactory *hgf); Result CreateSparseStorageWithVerification(std::shared_ptr<fs::IStorage> *out, s64 *out_fs_data_offset, std::shared_ptr<fssystem::SparseStorage> *out_sparse_storage, std::shared_ptr<fs::IStorage> *out_meta_storage, std::shared_ptr<fs::IStorage> *out_verification, s32 index, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info, const NcaMetaDataHashDataInfo &meta_data_hash_data_info, NcaFsHeader::MetaDataHashType meta_data_hash_type); Result CreateAesCtrExStorageMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, NcaFsHeader::EncryptionType encryption_type, const NcaAesCtrUpperIv &upper_iv, const NcaPatchInfo &patch_info); Result CreateAesCtrExStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::AesCtrCounterExtendedStorage> *out_ext, std::shared_ptr<fs::IStorage> base_storage, std::shared_ptr<fs::IStorage> meta_storage, s64 counter_offset, const NcaAesCtrUpperIv &upper_iv, const NcaPatchInfo &patch_info); Result CreateIndirectStorageMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaPatchInfo &patch_info); Result CreateIndirectStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IndirectStorage> *out_ind, std::shared_ptr<fs::IStorage> base_storage, std::shared_ptr<fs::IStorage> original_data_storage, std::shared_ptr<fs::IStorage> meta_storage, const NcaPatchInfo &patch_info); Result CreatePatchMetaStorage(std::shared_ptr<fs::IStorage> *out_aes_ctr_ex_meta, std::shared_ptr<fs::IStorage> *out_indirect_meta, std::shared_ptr<fs::IStorage> *out_verification, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, const NcaPatchInfo &patch_info, const NcaMetaDataHashDataInfo &meta_data_hash_data_info, IHash256GeneratorFactory *hgf); Result CreateSha256Storage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &sha256_data, IHash256GeneratorFactory *hgf); Result CreateIntegrityVerificationStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info, IHash256GeneratorFactory *hgf); Result CreateIntegrityVerificationStorageForMeta(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> *out_verification, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaMetaDataHashDataInfo &meta_data_hash_data_info, IHash256GeneratorFactory *hgf); Result CreateIntegrityVerificationStorageImpl(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info, s64 layer_info_offset, int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level, IHash256GeneratorFactory *hgf); Result CreateRegionSwitchStorage(std::shared_ptr<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> inside_storage, std::shared_ptr<fs::IStorage> outside_storage); Result CreateCompressedStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::CompressedStorage> *out_cmp, std::shared_ptr<fs::IStorage> *out_meta, std::shared_ptr<fs::IStorage> base_storage, const NcaCompressionInfo &compression_info); public: Result CreateCompressedStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::CompressedStorage> *out_cmp, std::shared_ptr<fs::IStorage> *out_meta, std::shared_ptr<fs::IStorage> base_storage, const NcaCompressionInfo &compression_info, GetDecompressorFunction get_decompressor, MemoryResource *allocator, fs::IBufferManager *buffer_manager); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_header.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ struct Hash { static constexpr size_t Size = IHash256Generator::HashSize; u8 value[Size]; }; static_assert(sizeof(Hash) == Hash::Size); static_assert(util::is_pod<Hash>::value); using NcaDigest = Hash; struct NcaHeader { enum class ContentType : u8 { Program = 0, Meta = 1, Control = 2, Manual = 3, Data = 4, PublicData = 5, Start = Program, End = PublicData, }; enum class DistributionType : u8 { Download = 0, GameCard = 1, Start = Download, End = GameCard, }; enum class EncryptionType : u8 { Auto = 0, None = 1, }; enum DecryptionKey { DecryptionKey_AesXts = 0, DecryptionKey_AesXts1 = DecryptionKey_AesXts, DecryptionKey_AesXts2 = 1, DecryptionKey_AesCtr = 2, DecryptionKey_AesCtrEx = 3, DecryptionKey_AesCtrHw = 4, DecryptionKey_Count, }; struct FsInfo { u32 start_sector; u32 end_sector; u32 hash_sectors; u32 reserved; }; static_assert(sizeof(FsInfo) == 0x10); static_assert(util::is_pod<FsInfo>::value); static constexpr u32 Magic0 = util::FourCC<'N','C','A','0'>::Code; static constexpr u32 Magic1 = util::FourCC<'N','C','A','1'>::Code; static constexpr u32 Magic2 = util::FourCC<'N','C','A','2'>::Code; static constexpr u32 Magic3 = util::FourCC<'N','C','A','3'>::Code; static constexpr u32 Magic = Magic3; static constexpr size_t Size = 1_KB; static constexpr s32 FsCountMax = 4; static constexpr size_t HeaderSignCount = 2; static constexpr size_t HeaderSignSize = 0x100; static constexpr size_t EncryptedKeyAreaSize = 0x100; static constexpr size_t SectorSize = 0x200; static constexpr size_t SectorShift = 9; static constexpr size_t RightsIdSize = 0x10; static constexpr size_t XtsBlockSize = 0x200; static constexpr size_t CtrBlockSize = 0x10; static_assert(SectorSize == (1 << SectorShift)); /* Data members. */ u8 header_sign_1[HeaderSignSize]; u8 header_sign_2[HeaderSignSize]; u32 magic; DistributionType distribution_type; ContentType content_type; u8 key_generation; u8 key_index; u64 content_size; u64 program_id; u32 content_index; u32 sdk_addon_version; u8 key_generation_2; u8 header1_signature_key_generation; u8 reserved_222[2]; u32 reserved_224[3]; u8 rights_id[RightsIdSize]; FsInfo fs_info[FsCountMax]; Hash fs_header_hash[FsCountMax]; u8 encrypted_key_area[EncryptedKeyAreaSize]; static constexpr u64 SectorToByte(u32 sector) { return static_cast<u64>(sector) << SectorShift; } static constexpr u32 ByteToSector(u64 byte) { return static_cast<u32>(byte >> SectorShift); } u8 GetProperKeyGeneration() const; }; static_assert(sizeof(NcaHeader) == NcaHeader::Size); static_assert(util::is_pod<NcaHeader>::value); struct NcaBucketInfo { static constexpr size_t HeaderSize = 0x10; fs::Int64 offset; fs::Int64 size; u8 header[HeaderSize]; }; static_assert(util::is_pod<NcaBucketInfo>::value); struct NcaPatchInfo { static constexpr size_t Size = 0x40; static constexpr size_t Offset = 0x100; fs::Int64 indirect_offset; fs::Int64 indirect_size; u8 indirect_header[NcaBucketInfo::HeaderSize]; fs::Int64 aes_ctr_ex_offset; fs::Int64 aes_ctr_ex_size; u8 aes_ctr_ex_header[NcaBucketInfo::HeaderSize]; bool HasIndirectTable() const; bool HasAesCtrExTable() const; }; static_assert(util::is_pod<NcaPatchInfo>::value); union NcaAesCtrUpperIv { u64 value; struct { u32 generation; u32 secure_value; } part; }; static_assert(util::is_pod<NcaAesCtrUpperIv>::value); struct NcaSparseInfo { NcaBucketInfo bucket; fs::Int64 physical_offset; u16 generation; u8 reserved[6]; s64 GetPhysicalSize() const { return this->bucket.offset + this->bucket.size; } u32 GetGeneration() const { return static_cast<u32>(this->generation) << 16; } const NcaAesCtrUpperIv MakeAesCtrUpperIv(NcaAesCtrUpperIv upper_iv) const { NcaAesCtrUpperIv sparse_upper_iv = upper_iv; sparse_upper_iv.part.generation = this->GetGeneration(); return sparse_upper_iv; } }; static_assert(util::is_pod<NcaSparseInfo>::value); struct NcaCompressionInfo { NcaBucketInfo bucket; u8 reserved[8]; }; static_assert(util::is_pod<NcaCompressionInfo>::value); struct NcaMetaDataHashDataInfo { fs::Int64 offset; fs::Int64 size; Hash hash; }; static_assert(util::is_pod<NcaMetaDataHashDataInfo>::value); struct NcaFsHeader { static constexpr size_t Size = 0x200; static constexpr size_t HashDataOffset = 0x8; struct Region { fs::Int64 offset; fs::Int64 size; }; static_assert(util::is_pod<Region>::value); enum class FsType : u8 { RomFs = 0, PartitionFs = 1, }; enum class EncryptionType : u8 { Auto = 0, None = 1, AesXts = 2, AesCtr = 3, AesCtrEx = 4, AesCtrSkipLayerHash = 5, AesCtrExSkipLayerHash = 6, }; enum class HashType : u8 { Auto = 0, None = 1, HierarchicalSha256Hash = 2, HierarchicalIntegrityHash = 3, AutoSha3 = 4, HierarchicalSha3256Hash = 5, HierarchicalIntegritySha3Hash = 6, }; enum class MetaDataHashType : u8 { None = 0, HierarchicalIntegrity = 1, }; union HashData { struct HierarchicalSha256Data { static constexpr size_t HashLayerCountMax = 5; static const size_t MasterHashOffset; Hash fs_data_master_hash; s32 hash_block_size; s32 hash_layer_count; Region hash_layer_region[HashLayerCountMax]; } hierarchical_sha256_data; static_assert(util::is_pod<HierarchicalSha256Data>::value); struct IntegrityMetaInfo { static const size_t MasterHashOffset; u32 magic; u32 version; u32 master_hash_size; struct LevelHashInfo { u32 max_layers; struct HierarchicalIntegrityVerificationLevelInformation { static constexpr size_t IntegrityMaxLayerCount = 7; fs::Int64 offset; fs::Int64 size; s32 block_order; u8 reserved[4]; } info[HierarchicalIntegrityVerificationLevelInformation::IntegrityMaxLayerCount - 1]; struct SignatureSalt { static constexpr size_t Size = 0x20; u8 value[Size]; } seed; } level_hash_info; Hash master_hash; } integrity_meta_info; static_assert(util::is_pod<IntegrityMetaInfo>::value); u8 padding[NcaPatchInfo::Offset - HashDataOffset]; }; u16 version; FsType fs_type; HashType hash_type; EncryptionType encryption_type; MetaDataHashType meta_data_hash_type; u8 reserved[2]; HashData hash_data; NcaPatchInfo patch_info; NcaAesCtrUpperIv aes_ctr_upper_iv; NcaSparseInfo sparse_info; NcaCompressionInfo compression_info; NcaMetaDataHashDataInfo meta_data_hash_data_info; u8 pad[0x30]; bool IsSkipLayerHashEncryption() const { return this->encryption_type == EncryptionType::AesCtrSkipLayerHash || this->encryption_type == EncryptionType::AesCtrExSkipLayerHash; } Result GetHashTargetOffset(s64 *out) const { switch (this->hash_type) { case HashType::HierarchicalIntegrityHash: case HashType::HierarchicalIntegritySha3Hash: *out = this->hash_data.integrity_meta_info.level_hash_info.info[this->hash_data.integrity_meta_info.level_hash_info.max_layers - 2].offset; R_SUCCEED(); case HashType::HierarchicalSha256Hash: case HashType::HierarchicalSha3256Hash: *out = this->hash_data.hierarchical_sha256_data.hash_layer_region[this->hash_data.hierarchical_sha256_data.hash_layer_count - 1].offset; R_SUCCEED(); default: R_THROW(fs::ResultInvalidNcaFsHeader()); } } }; static_assert(sizeof(NcaFsHeader) == NcaFsHeader::Size); static_assert(util::is_pod<NcaFsHeader>::value); static_assert(AMS_OFFSETOF(NcaFsHeader, patch_info) == NcaPatchInfo::Offset); inline constexpr const size_t NcaFsHeader::HashData::HierarchicalSha256Data::MasterHashOffset = AMS_OFFSETOF(NcaFsHeader, hash_data.hierarchical_sha256_data.fs_data_master_hash); inline constexpr const size_t NcaFsHeader::HashData::IntegrityMetaInfo::MasterHashOffset = AMS_OFFSETOF(NcaFsHeader, hash_data.integrity_meta_info.master_hash); struct NcaMetaDataHashData { s64 layer_info_offset; NcaFsHeader::HashData::IntegrityMetaInfo integrity_meta_info; }; static_assert(sizeof(NcaMetaDataHashData) == sizeof(NcaFsHeader::HashData::IntegrityMetaInfo) + sizeof(s64)); static_assert(util::is_pod<NcaMetaDataHashData>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ template<typename MetaType> class PartitionFileSystemCore : public fs::impl::Newable, public fs::fsa::IFileSystem { NON_COPYABLE(PartitionFileSystemCore); NON_MOVEABLE(PartitionFileSystemCore); private: class PartitionFile; class PartitionDirectory; private: fs::IStorage *m_base_storage; MetaType *m_meta_data; bool m_initialized; size_t m_meta_data_size; std::unique_ptr<MetaType> m_unique_meta_data; std::shared_ptr<fs::IStorage> m_shared_storage; private: Result Initialize(fs::IStorage *base_storage, MemoryResource *allocator); public: PartitionFileSystemCore(); virtual ~PartitionFileSystemCore() override; Result Initialize(std::unique_ptr<MetaType> &&meta_data, std::shared_ptr<fs::IStorage> base_storage); Result Initialize(MetaType *meta_data, std::shared_ptr<fs::IStorage> base_storage); Result Initialize(fs::IStorage *base_storage); Result Initialize(std::shared_ptr<fs::IStorage> base_storage); Result Initialize(std::shared_ptr<fs::IStorage> base_storage, MemoryResource *allocator); Result GetFileBaseOffset(s64 *out_offset, const char *path); virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override; virtual Result DoDeleteFile(const fs::Path &path) override; virtual Result DoCreateDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; }; using PartitionFileSystem = PartitionFileSystemCore<PartitionFileSystemMeta>; using Sha256PartitionFileSystem = PartitionFileSystemCore<Sha256PartitionFileSystemMeta>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_partition_file_system_meta.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ namespace impl { struct PartitionFileSystemFormat { #pragma pack(push, 1) struct PartitionEntry { u64 offset; u64 size; u32 name_offset; u32 reserved; }; static_assert(util::is_pod<PartitionEntry>::value); #pragma pack(pop) static constexpr const char VersionSignature[] = { 'P', 'F', 'S', '0' }; static constexpr size_t EntryNameLengthMax = ::ams::fs::EntryNameLengthMax; static constexpr size_t FileDataAlignmentSize = 0x20; using ResultSignatureVerificationFailed = fs::ResultPartitionSignatureVerificationFailed; }; struct Sha256PartitionFileSystemFormat { static constexpr size_t HashSize = ::ams::crypto::Sha256Generator::HashSize; #pragma pack(push, 1) struct PartitionEntry { u64 offset; u64 size; u32 name_offset; u32 hash_target_size; u64 hash_target_offset; char hash[HashSize]; }; static_assert(util::is_pod<PartitionEntry>::value); #pragma pack(pop) static constexpr const char VersionSignature[] = { 'H', 'F', 'S', '0' }; static constexpr size_t EntryNameLengthMax = ::ams::fs::EntryNameLengthMax; static constexpr size_t FileDataAlignmentSize = 0x200; using ResultSignatureVerificationFailed = fs::ResultSha256PartitionSignatureVerificationFailed; }; } template<typename Format> class PartitionFileSystemMetaCore : public fs::impl::Newable { public: static constexpr size_t EntryNameLengthMax = Format::EntryNameLengthMax; static constexpr size_t FileDataAlignmentSize = Format::FileDataAlignmentSize; /* Forward declare header. */ struct PartitionFileSystemHeader; using PartitionEntry = typename Format::PartitionEntry; protected: bool m_initialized; PartitionFileSystemHeader *m_header; PartitionEntry *m_entries; char *m_name_table; size_t m_meta_data_size; MemoryResource *m_allocator; char *m_buffer; public: PartitionFileSystemMetaCore() : m_initialized(false), m_allocator(nullptr), m_buffer(nullptr) { /* ... */ } ~PartitionFileSystemMetaCore(); Result Initialize(fs::IStorage *storage, MemoryResource *allocator); Result Initialize(fs::IStorage *storage, void *header, size_t header_size); const PartitionEntry *GetEntry(s32 index) const; s32 GetEntryCount() const; s32 GetEntryIndex(const char *name) const; const char *GetEntryName(s32 index) const; size_t GetHeaderSize() const; size_t GetMetaDataSize() const; public: static Result QueryMetaDataSize(size_t *out_size, fs::IStorage *storage); protected: void DeallocateBuffer(); }; using PartitionFileSystemMeta = PartitionFileSystemMetaCore<impl::PartitionFileSystemFormat>; class Sha256PartitionFileSystemMeta : public PartitionFileSystemMetaCore<impl::Sha256PartitionFileSystemFormat> { public: using PartitionFileSystemMetaCore<impl::Sha256PartitionFileSystemFormat>::Initialize; Result Initialize(fs::IStorage *base_storage, MemoryResource *allocator, const void *hash, size_t hash_size, util::optional<u8> suffix = util::nullopt); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pimpl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ namespace impl { template<typename T, size_t Size> struct PimplHelper { static void Construct(void *); static void Destroy(void *); }; } template<typename T, size_t Size> class Pimpl { private: #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) static constexpr size_t ExtraSizeToEnsureCompatibility = 0; #elif defined(ATMOSPHERE_OS_MACOS) static constexpr size_t ExtraSizeToEnsureCompatibility = 0x20; #endif static constexpr size_t StorageSize = Size + ExtraSizeToEnsureCompatibility; private: alignas(0x10) u8 m_storage[StorageSize]; public: ALWAYS_INLINE Pimpl() { impl::PimplHelper<T, StorageSize>::Construct(m_storage); } ALWAYS_INLINE ~Pimpl() { impl::PimplHelper<T, StorageSize>::Destroy(m_storage); } ALWAYS_INLINE T *Get() { return reinterpret_cast<T *>(m_storage + 0); } ALWAYS_INLINE T *operator->() { return reinterpret_cast<T *>(m_storage + 0); } }; #define AMS_FSSYSTEM_ENABLE_PIMPL(_CLASSNAME_) \ namespace ams::fssystem::impl { \ \ template<size_t Size> \ struct PimplHelper<_CLASSNAME_, Size> { \ static ALWAYS_INLINE void Construct(void *p) { \ static_assert(sizeof(_CLASSNAME_) <= Size); \ static_assert(alignof(_CLASSNAME_) <= 0x10); \ \ std::construct_at(static_cast<_CLASSNAME_ *>(p)); \ } \ \ static ALWAYS_INLINE void Destroy(void *p) { \ std::destroy_at(static_cast<_CLASSNAME_ *>(p)); \ } \ }; \ \ } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_pooled_buffer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ constexpr inline size_t BufferPoolAlignment = 4_KB; constexpr inline size_t BufferPoolWorkSize = 320; class PooledBuffer { NON_COPYABLE(PooledBuffer); private: char *m_buffer; size_t m_size; private: static size_t GetAllocatableSizeMaxCore(bool large); public: static size_t GetAllocatableSizeMax() { return GetAllocatableSizeMaxCore(false); } static size_t GetAllocatableParticularlyLargeSizeMax() { return GetAllocatableSizeMaxCore(true); } private: void Swap(PooledBuffer &rhs) { std::swap(m_buffer, rhs.m_buffer); std::swap(m_size, rhs.m_size); } public: /* Constructor/Destructor. */ constexpr PooledBuffer() : m_buffer(), m_size() { /* ... */ } PooledBuffer(size_t ideal_size, size_t required_size) : m_buffer(), m_size() { this->Allocate(ideal_size, required_size); } ~PooledBuffer() { this->Deallocate(); } /* Move and assignment. */ explicit PooledBuffer(PooledBuffer &&rhs) : m_buffer(rhs.m_buffer), m_size(rhs.m_size) { rhs.m_buffer = nullptr; rhs.m_size = 0; } PooledBuffer &operator=(PooledBuffer &&rhs) { PooledBuffer(std::move(rhs)).Swap(*this); return *this; } /* Allocation API. */ void Allocate(size_t ideal_size, size_t required_size) { return this->AllocateCore(ideal_size, required_size, false); } void AllocateParticularlyLarge(size_t ideal_size, size_t required_size) { return this->AllocateCore(ideal_size, required_size, true); } void Shrink(size_t ideal_size); void Deallocate() { /* Shrink the buffer to empty. */ this->Shrink(0); AMS_ASSERT(m_buffer == nullptr); } char *GetBuffer() const { AMS_ASSERT(m_buffer != nullptr); return m_buffer; } size_t GetSize() const { AMS_ASSERT(m_buffer != nullptr); return m_size; } private: void AllocateCore(size_t ideal_size, size_t required_size, bool large); }; Result InitializeBufferPool(char *buffer, size_t size); Result InitializeBufferPool(char *buffer, size_t size, char *work, size_t work_size); bool IsPooledBuffer(const void *buffer); size_t GetPooledBufferRetriedCount(); size_t GetPooledBufferReduceAllocationCount(); size_t GetPooledBufferFreeSizePeak(); void ClearPooledBufferPeak(); void RegisterAdditionalDeviceAddress(uintptr_t address, size_t size); void UnregisterAdditionalDeviceAddress(uintptr_t address); bool IsAdditionalDeviceAddress(const void *ptr); inline bool IsDeviceAddress(const void *buffer) { return IsPooledBuffer(buffer) || IsAdditionalDeviceAddress(buffer); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> #include <stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp> #include <stratosphere/fs/fs_istorage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class RomFsFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(RomFsFileSystem); public: using RomFileTable = fs::HierarchicalRomFileTable; private: RomFileTable m_rom_file_table; fs::IStorage *m_base_storage; std::shared_ptr<fs::IStorage> m_shared_storage; std::unique_ptr<fs::IStorage> m_dir_bucket_storage; std::unique_ptr<fs::IStorage> m_dir_entry_storage; std::unique_ptr<fs::IStorage> m_file_bucket_storage; std::unique_ptr<fs::IStorage> m_file_entry_storage; s64 m_entry_size; private: Result GetFileInfo(RomFileTable::FileInfo *out, const char *path); Result GetFileInfo(RomFileTable::FileInfo *out, const fs::Path &path) { R_RETURN(this->GetFileInfo(out, path.GetString())); } Result CheckPathFormat(const fs::Path &path) const { R_RETURN(fs::PathFormatter::CheckPathFormat(path.GetString(), fs::PathFlags{})); } public: static Result GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage); public: RomFsFileSystem(); virtual ~RomFsFileSystem() override; Result Initialize(fs::IStorage *base, void *work, size_t work_size, bool use_cache); Result Initialize(std::shared_ptr<fs::IStorage> base, void *work, size_t work_size, bool use_cache); fs::IStorage *GetBaseStorage(); RomFileTable *GetRomFileTable(); Result GetFileBaseOffset(s64 *out, const fs::Path &path); public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override; virtual Result DoDeleteFile(const fs::Path &path) override; virtual Result DoCreateDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectory(const fs::Path &path) override; virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override; virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override; virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override; virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override; virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override; virtual Result DoCommit() override; virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override; virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override; /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_service_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_priority.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class ServiceContext { private: struct DeferredProcessContextForDeviceError { u64 process_id; bool is_process_deferred; bool is_invoke_deferral_requested; }; struct DeferredProcessContextForPriority { int session_type; bool is_process_deferred; bool is_acquired; }; private: fs::PriorityRaw m_priority; DeferredProcessContextForDeviceError m_deferred_process_context_for_device_error; DeferredProcessContextForPriority m_deferred_process_context_for_priority; int m_storage_flag; void *m_request_hook_context; bool m_enable_count_failed_ideal_pooled_buffer_allocations; public: ServiceContext() : m_priority(fs::PriorityRaw_Normal), m_storage_flag(0), m_request_hook_context(nullptr), m_enable_count_failed_ideal_pooled_buffer_allocations(false) { /* ... */ } }; void RegisterServiceContext(ServiceContext *context); void UnregisterServiceContext(); ServiceContext *GetServiceContext(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sha_hash_generator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ namespace impl { template<typename Traits> class ShaHashGenerator final : public ::ams::fssystem::IHash256Generator, public ::ams::fs::impl::Newable { static_assert(Traits::Generator::HashSize == IHash256Generator::HashSize); NON_COPYABLE(ShaHashGenerator); NON_MOVEABLE(ShaHashGenerator); private: using Generator = typename Traits::Generator; private: Generator m_generator; public: ShaHashGenerator() = default; protected: virtual void DoInitialize() override { m_generator.Initialize(); } virtual void DoUpdate(const void *data, size_t size) override { m_generator.Update(data, size); } virtual void DoGetHash(void *dst, size_t dst_size) override { m_generator.GetHash(dst, dst_size); } }; template<typename Traits> class ShaHashGeneratorFactory final : public IHash256GeneratorFactory, public ::ams::fs::impl::Newable { static_assert(Traits::Generator::HashSize == IHash256Generator::HashSize); NON_COPYABLE(ShaHashGeneratorFactory); NON_MOVEABLE(ShaHashGeneratorFactory); public: constexpr ShaHashGeneratorFactory() = default; protected: virtual Result DoCreate(std::unique_ptr<IHash256Generator> *out) override { auto generator = std::unique_ptr<IHash256Generator>(new ShaHashGenerator<Traits>()); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedNew()); *out = std::move(generator); R_SUCCEED(); } virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) override { Traits::Generate(dst, dst_size, src, src_size); } }; struct Sha256Traits { using Generator = crypto::Sha256Generator; static ALWAYS_INLINE void Generate(void *dst, size_t dst_size, const void *src, size_t src_size) { return crypto::GenerateSha256(dst, dst_size, src, src_size); } }; struct Sha3256Traits { using Generator = crypto::Sha3256Generator; static ALWAYS_INLINE void Generate(void *dst, size_t dst_size, const void *src, size_t src_size) { return crypto::GenerateSha3256(dst, dst_size, src, src_size); } }; } using Sha256HashGenerator = impl::ShaHashGenerator<impl::Sha256Traits>; using Sha256HashGeneratorFactory = impl::ShaHashGeneratorFactory<impl::Sha256Traits>; using Sha3256HashGenerator = impl::ShaHashGenerator<impl::Sha3256Traits>; using Sha3256HashGeneratorFactory = impl::ShaHashGeneratorFactory<impl::Sha3256Traits>; class ShaHashGeneratorFactorySelector final : public IHash256GeneratorFactorySelector, public ::ams::fs::impl::Newable { NON_COPYABLE(ShaHashGeneratorFactorySelector); NON_MOVEABLE(ShaHashGeneratorFactorySelector); private: Sha256HashGeneratorFactory m_sha256_factory; Sha3256HashGeneratorFactory m_sha3_256_factory; public: constexpr ShaHashGeneratorFactorySelector() = default; protected: virtual IHash256GeneratorFactory *DoGetFactory(HashAlgorithmType alg) override { switch (alg) { case HashAlgorithmType_Sha2: return std::addressof(m_sha256_factory); case HashAlgorithmType_Sha3: return std::addressof(m_sha3_256_factory); AMS_UNREACHABLE_DEFAULT_CASE(); } } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_sparse_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fssystem/fssystem_indirect_storage.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class SparseStorage : public IndirectStorage { NON_COPYABLE(SparseStorage); NON_MOVEABLE(SparseStorage); private: class ZeroStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { public: ZeroStorage() { /* ... */ } virtual ~ZeroStorage() { /* ... */ } public: virtual Result Read(s64 offset, void *buffer, size_t size) override { AMS_ASSERT(offset >= 0); AMS_ASSERT(buffer != nullptr || size == 0); AMS_UNUSED(offset); if (size > 0) { std::memset(buffer, 0, size); } R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { AMS_UNUSED(dst, dst_size, op_id, offset, size, src, src_size); R_SUCCEED(); } virtual Result GetSize(s64 *out) override { AMS_ASSERT(out != nullptr); *out = std::numeric_limits<s64>::max(); R_SUCCEED(); } virtual Result Flush() override { R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { AMS_UNUSED(offset, buffer, size); R_THROW(fs::ResultUnsupportedWriteForZeroStorage()); } virtual Result SetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedSetSizeForZeroStorage()); } }; private: ZeroStorage m_zero_storage; public: SparseStorage() : IndirectStorage(), m_zero_storage() { /* ... */ } virtual ~SparseStorage() { /* ... */ } using IndirectStorage::Initialize; void Initialize(s64 end_offset) { this->GetEntryTable().Initialize(NodeSize, end_offset); this->SetZeroStorage(); } void SetDataStorage(fs::SubStorage storage) { AMS_ASSERT(this->IsInitialized()); this->SetStorage(0, storage); this->SetZeroStorage(); } template<typename T> void SetDataStorage(T storage, s64 offset, s64 size) { AMS_ASSERT(this->IsInitialized()); this->SetStorage(0, storage, offset, size); this->SetZeroStorage(); } virtual Result Read(s64 offset, void *buffer, size_t size) override; private: void SetZeroStorage() { return this->SetStorage(1, std::addressof(m_zero_storage), 0, std::numeric_limits<s64>::max()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_speed_emulation_configuration.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_speed_emulation.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class SpeedEmulationConfiguration { public: static void SetSpeedEmulationMode(::ams::fs::SpeedEmulationMode mode); static ::ams::fs::SpeedEmulationMode GetSpeedEmulationMode(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fsa/fs_ifile.hpp> #include <stratosphere/fs/fsa/fs_idirectory.hpp> #include <stratosphere/fs/fsa/fs_ifilesystem.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ class SubDirectoryFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(SubDirectoryFileSystem); private: std::shared_ptr<fs::fsa::IFileSystem> m_shared_fs; fs::fsa::IFileSystem * const m_base_fs; fs::Path m_root_path; public: SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs) : m_shared_fs(std::move(fs)), m_base_fs(m_shared_fs.get()), m_root_path() { /* ... */ } SubDirectoryFileSystem(fs::fsa::IFileSystem *fs) : m_shared_fs(), m_base_fs(fs), m_root_path() { /* ... */ } Result Initialize(const fs::Path &path) { R_RETURN(m_root_path.Initialize(path)); } private: Result ResolveFullPath(fs::Path *out, const fs::Path &path) { R_RETURN(out->Combine(m_root_path, path)); } public: virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CreateFile(full_path, size, option)); } virtual Result DoDeleteFile(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteFile(full_path)); } virtual Result DoCreateDirectory(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CreateDirectory(full_path)); } virtual Result DoDeleteDirectory(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteDirectory(full_path)); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path)); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { fs::Path old_full_path; fs::Path new_full_path; R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path)); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { fs::Path old_full_path; fs::Path new_full_path; R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path)); R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path)); R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path)); } virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetEntryType(out, full_path)); } virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode)); } virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode)); } virtual Result DoCommit() override { R_RETURN(m_base_fs->Commit()); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path)); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path)); } virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_path)); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { fs::Path full_path; R_TRY(this->ResolveFullPath(std::addressof(full_path), path)); R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path)); } /* These aren't accessible as commands. */ virtual Result DoCommitProvisionally(s64 counter) override { R_RETURN(m_base_fs->CommitProvisionally(counter)); } virtual Result DoRollback() override { R_RETURN(m_base_fs->Rollback()); } virtual Result DoFlush() override { R_RETURN(m_base_fs->Flush()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_switch_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_istorage.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 14.3.0.0 */ template<typename F> class SwitchStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(SwitchStorage); NON_MOVEABLE(SwitchStorage); private: std::shared_ptr<fs::IStorage> m_true_storage; std::shared_ptr<fs::IStorage> m_false_storage; F m_truth_function; private: ALWAYS_INLINE std::shared_ptr<fs::IStorage> &SelectStorage() { return m_truth_function() ? m_true_storage : m_false_storage; } public: SwitchStorage(std::shared_ptr<fs::IStorage> t, std::shared_ptr<fs::IStorage> f, F func) : m_true_storage(std::move(t)), m_false_storage(std::move(f)), m_truth_function(func) { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { R_RETURN(this->SelectStorage()->Read(offset, buffer, size)); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { switch (op_id) { case fs::OperationId::Invalidate: { R_TRY(m_true_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); R_TRY(m_false_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); R_SUCCEED(); } case fs::OperationId::QueryRange: { R_TRY(this->SelectStorage()->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); R_SUCCEED(); } default: R_THROW(fs::ResultUnsupportedOperateRangeForSwitchStorage()); } } virtual Result GetSize(s64 *out) override { R_RETURN(this->SelectStorage()->GetSize(out)); } virtual Result Flush() override { R_RETURN(this->SelectStorage()->Flush()); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { R_RETURN(this->SelectStorage()->Write(offset, buffer, size)); } virtual Result SetSize(s64 size) override { R_RETURN(this->SelectStorage()->SetSize(size)); } }; class RegionSwitchStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable { NON_COPYABLE(RegionSwitchStorage); NON_MOVEABLE(RegionSwitchStorage); public: struct Region { s64 offset; s64 size; }; private: std::shared_ptr<fs::IStorage> m_inside_region_storage; std::shared_ptr<fs::IStorage> m_outside_region_storage; Region m_region; public: RegionSwitchStorage(std::shared_ptr<fs::IStorage> &&i, std::shared_ptr<fs::IStorage> &&o, Region r) : m_inside_region_storage(std::move(i)), m_outside_region_storage(std::move(o)), m_region(r) { /* ... */ } virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Process until we're done. */ size_t processed = 0; while (processed < size) { /* Process on the appropriate storage. */ s64 cur_size = 0; if (this->CheckRegions(std::addressof(cur_size), offset + processed, size - processed)) { R_TRY(m_inside_region_storage->Read(offset + processed, static_cast<u8 *>(buffer) + processed, cur_size)); } else { R_TRY(m_outside_region_storage->Read(offset + processed, static_cast<u8 *>(buffer) + processed, cur_size)); } /* Advance. */ processed += cur_size; } R_SUCCEED(); } virtual Result Write(s64 offset, const void *buffer, size_t size) override { /* Process until we're done. */ size_t processed = 0; while (processed < size) { /* Process on the appropriate storage. */ s64 cur_size = 0; if (this->CheckRegions(std::addressof(cur_size), offset + processed, size - processed)) { R_TRY(m_inside_region_storage->Write(offset + processed, static_cast<const u8 *>(buffer) + processed, cur_size)); } else { R_TRY(m_outside_region_storage->Write(offset + processed, static_cast<const u8 *>(buffer) + processed, cur_size)); } /* Advance. */ processed += cur_size; } R_SUCCEED(); } virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { switch (op_id) { case fs::OperationId::Invalidate: { R_TRY(m_inside_region_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); R_TRY(m_outside_region_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); R_SUCCEED(); } case fs::OperationId::QueryRange: { /* Create a new info. */ fs::QueryRangeInfo merged_info; merged_info.Clear(); /* Process until we're done. */ s64 processed = 0; while (processed < size) { /* Process on the appropriate storage. */ s64 cur_size = 0; fs::QueryRangeInfo cur_info; if (this->CheckRegions(std::addressof(cur_size), offset + processed, size - processed)) { R_TRY(m_inside_region_storage->OperateRange(std::addressof(cur_info), sizeof(cur_info), op_id, offset + processed, cur_size, src, src_size)); } else { R_TRY(m_outside_region_storage->OperateRange(std::addressof(cur_info), sizeof(cur_info), op_id, offset + processed, cur_size, src, src_size)); } /* Merge the current info. */ merged_info.Merge(cur_info); /* Advance. */ processed += cur_size; } /* Write the merged info. */ *reinterpret_cast<fs::QueryRangeInfo *>(dst) = merged_info; R_SUCCEED(); } default: R_THROW(fs::ResultUnsupportedOperateRangeForRegionSwitchStorage()); } } virtual Result GetSize(s64 *out) override { R_RETURN(m_inside_region_storage->GetSize(out)); } virtual Result Flush() override { /* Flush both storages. */ R_TRY(m_inside_region_storage->Flush()); R_TRY(m_outside_region_storage->Flush()); R_SUCCEED(); } virtual Result SetSize(s64 size) override { /* Set size for both storages. */ R_TRY(m_inside_region_storage->SetSize(size)); R_TRY(m_outside_region_storage->SetSize(size)); R_SUCCEED(); } private: bool CheckRegions(s64 *out_current_size, s64 offset, s64 size) const { /* Check if our region contains the access. */ if (m_region.offset <= offset) { if (offset < m_region.offset + m_region.size) { if (m_region.offset + m_region.size <= offset + size) { *out_current_size = m_region.offset + m_region.size - offset; } else { *out_current_size = size; } return true; } else { *out_current_size = size; return false; } } else { if (m_region.offset <= offset + size) { *out_current_size = m_region.offset - offset; } else { *out_current_size = size; } return false; } } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_thread_priority_changer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: Unknown */ class ScopedThreadPriorityChanger { public: enum class Mode { Absolute, Relative, }; private: os::ThreadType *m_thread; s32 m_priority; public: ALWAYS_INLINE explicit ScopedThreadPriorityChanger(s32 priority, Mode mode) : m_thread(os::GetCurrentThread()), m_priority(0) { const auto result_priority = std::min((mode == Mode::Relative) ? os::GetThreadPriority(m_thread) + priority : priority, os::LowestSystemThreadPriority); m_priority = os::ChangeThreadPriority(m_thread, result_priority); } ALWAYS_INLINE ~ScopedThreadPriorityChanger() { os::ChangeThreadPriority(m_thread, m_priority); } }; class ScopedThreadPriorityChangerByAccessPriority { public: enum class AccessMode { Read, Write, }; private: static s32 GetThreadPriorityByAccessPriority(AccessMode mode); private: ScopedThreadPriorityChanger m_scoped_changer; public: ALWAYS_INLINE explicit ScopedThreadPriorityChangerByAccessPriority(AccessMode mode) : m_scoped_changer(GetThreadPriorityByAccessPriority(mode), ScopedThreadPriorityChanger::Mode::Absolute) { /* ... */ } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_path.hpp> namespace ams::fssystem { /* ACCURATE_TO_VERSION: 13.4.0.0 */ namespace impl { template<typename F> concept IterateDirectoryHandler = requires (F f, const fs::Path &path, const fs::DirectoryEntry &entry) { { f(path, entry) } -> std::convertible_to<::ams::Result>; }; /* Iteration. */ template<IterateDirectoryHandler OnEnterDir, IterateDirectoryHandler OnExitDir, IterateDirectoryHandler OnFile> Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, fs::Path &work_path, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { /* Open the directory. */ std::unique_ptr<fs::fsa::IDirectory> dir; R_TRY(fs->OpenDirectory(std::addressof(dir), work_path, fs::OpenDirectoryMode_All)); /* Read and handle entries. */ while (true) { /* Read a single entry. */ s64 read_count = 0; R_TRY(dir->Read(std::addressof(read_count), dir_ent, 1)); /* If we're out of entries, we're done. */ if (read_count == 0) { break; } /* Append child path. */ R_TRY(work_path.AppendChild(dir_ent->name)); { if (dir_ent->type == fs::DirectoryEntryType_Directory) { /* Enter directory. */ R_TRY(on_enter_dir(work_path, *dir_ent)); /* Recurse. */ R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, dir_ent, on_enter_dir, on_exit_dir, on_file)); /* Exit directory. */ R_TRY(on_exit_dir(work_path, *dir_ent)); } else { /* Call file handler. */ R_TRY(on_file(work_path, *dir_ent)); } } R_TRY(work_path.RemoveChild()); } R_SUCCEED(); } /* TODO: Cleanup. */ } /* Iteration API */ template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile> Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &root_path, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { /* Create work path from the root path. */ fs::Path work_path; R_TRY(work_path.Initialize(root_path)); R_RETURN(impl::IterateDirectoryRecursivelyImpl(fs, work_path, dir_ent_buf, on_enter_dir, on_exit_dir, on_file)); } template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile> Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { fs::DirectoryEntry dir_entry = {}; R_RETURN(IterateDirectoryRecursively(fs, root_path, std::addressof(dir_entry), on_enter_dir, on_exit_dir, on_file)); } template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile> Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) { R_RETURN(IterateDirectoryRecursively(fs, fs::MakeConstantPath("/"), on_enter_dir, on_exit_dir, on_file)); } /* TODO: Cleanup API */ /* Copy API. */ Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size); ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size) { R_RETURN(CopyFile(fs, fs, dst_path, src_path, work_buf, work_buf_size)); } Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size); ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) { R_RETURN(CopyDirectoryRecursively(fs, fs, dst_path, src_path, entry, work_buf, work_buf_size)); } /* Locking utilities. */ class SemaphoreAdaptor : public os::Semaphore { public: SemaphoreAdaptor(int c, int mc) : os::Semaphore(c, mc) { /* ... */ } bool TryLock(int *out_acquired, int count) { AMS_ASSERT(count > 0); for (auto i = 0; i < count; ++i) { if (!this->TryAcquire()) { *out_acquired = i; return false; } } *out_acquired = count; return true; } void Unlock(int count) { if (count > 0) { this->Release(count); } } bool try_lock() { return this->TryAcquire(); } void unlock() { this->Release(); } }; Result TryAcquireCountSemaphore(util::unique_lock<SemaphoreAdaptor> *out, SemaphoreAdaptor *adaptor); class IUniqueLock { NON_COPYABLE(IUniqueLock); NON_MOVEABLE(IUniqueLock); public: virtual ~IUniqueLock() { /* ... */ } }; template<typename T> class UniqueLockWithPin final : public IUniqueLock, public ::ams::fs::impl::Newable { private: util::unique_lock<SemaphoreAdaptor> m_lock; T m_pinned_object; public: UniqueLockWithPin(util::unique_lock<SemaphoreAdaptor> lock, T obj) : m_lock(std::move(lock)), m_pinned_object(std::move(obj)) { /* ... */ } virtual ~UniqueLockWithPin() override { m_lock = {}; } }; template<typename T> class MultiLockWithPin final : public IUniqueLock, public ::ams::fs::impl::Newable { private: T m_pinned_object; SemaphoreAdaptor *m_semaphore_adaptor; int m_lock_count; public: MultiLockWithPin(T obj, SemaphoreAdaptor *adaptor) : m_pinned_object(std::move(obj)), m_semaphore_adaptor(adaptor), m_lock_count(0) { /* ... */ } virtual ~MultiLockWithPin() override { if (m_lock_count > 0) { m_semaphore_adaptor->Unlock(m_lock_count); } } Result Lock(int count) { AMS_ASSERT(m_lock_count == 0); R_UNLESS(m_semaphore_adaptor->TryLock(std::addressof(m_lock_count), count), fs::ResultOpenCountLimit()); R_SUCCEED(); } }; template<typename T> Result MakeUniqueLockWithPin(std::unique_ptr<IUniqueLock> *out, SemaphoreAdaptor *adaptor, T obj) { /* Create the semaphore unique lock. */ util::unique_lock<SemaphoreAdaptor> sema_lock; R_TRY(TryAcquireCountSemaphore(std::addressof(sema_lock), adaptor)); /* Create the output unique lock. */ auto result_lock = std::unique_ptr<UniqueLockWithPin<T>>(new UniqueLockWithPin<T>(std::move(sema_lock), std::move(obj))); R_UNLESS(result_lock != nullptr, fs::ResultAllocationMemoryFailedNew()); /* Set the output. */ *out = std::move(result_lock); R_SUCCEED(); } template<typename T> Result MakeUniqueLockWithPin(std::unique_ptr<IUniqueLock> *out, SemaphoreAdaptor *adaptor, int count, T obj) { /* Create the output unique lock. */ auto result_lock = std::unique_ptr<MultiLockWithPin<T>>(new MultiLockWithPin<T>(std::move(obj), adaptor)); R_UNLESS(result_lock != nullptr, fs::ResultAllocationMemoryFailedNew()); /* Acquire the output lock. */ R_TRY(result_lock->Lock(count)); /* Set the output. */ *out = std::move(result_lock); R_SUCCEED(); } /* Other utility. */ Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path); Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path); Result EnsureDirectory(fs::fsa::IFileSystem *fs, const fs::Path &path); template<s64 RetryMilliSeconds = 100, s32 MaxTryCount = 10> ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) { /* Retry sleeping between retries. */ constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds); Result result = f(); for (int i = 0; i < MaxTryCount && fs::ResultTargetLocked::Includes(result); ++i) { os::SleepThread(RetryWaitTime); result = f(); } R_RETURN(result); } ALWAYS_INLINE Result RetryToAvoidTargetLocked(auto f) { R_RETURN((RetryFinitelyForTargetLocked<2, 25>(f))); } void AddCounter(void *counter, size_t counter_size, u64 value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/impl/fssystem_block_cache_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/impl/fs_newable.hpp> namespace ams::fssystem::impl { /* ACCURATE_TO_VERSION: 13.4.0.0 */ template<typename CacheEntryType, typename AllocatorType> class BlockCacheManager { NON_COPYABLE(BlockCacheManager); NON_MOVEABLE(BlockCacheManager); public: using MemoryRange = typename AllocatorType::MemoryRange; using CacheIndex = s32; using BufferAttribute = typename AllocatorType::BufferAttribute; static constexpr CacheIndex InvalidCacheIndex = -1; using CacheEntry = CacheEntryType; static_assert(util::is_pod<CacheEntry>::value); private: AllocatorType *m_allocator = nullptr; std::unique_ptr<CacheEntry[], ::ams::fs::impl::Deleter> m_entries{}; s32 m_max_cache_entry_count = 0; public: constexpr BlockCacheManager() = default; public: Result Initialize(AllocatorType *allocator, s32 max_entries) { /* Check pre-conditions. */ AMS_ASSERT(m_allocator == nullptr); AMS_ASSERT(m_entries == nullptr); AMS_ASSERT(allocator != nullptr); /* Setup our entries buffer, if necessary. */ if (max_entries > 0) { /* Create the entries. */ m_entries = fs::impl::MakeUnique<CacheEntry[]>(static_cast<size_t>(max_entries)); R_UNLESS(m_entries != nullptr, fs::ResultAllocationMemoryFailedMakeUnique()); /* Clear the entries. */ std::memset(m_entries.get(), 0, sizeof(CacheEntry) * max_entries); } /* Set fields. */ m_allocator = allocator; m_max_cache_entry_count = max_entries; R_SUCCEED(); } void Finalize() { /* Reset all fields. */ m_entries.reset(nullptr); m_allocator = nullptr; m_max_cache_entry_count = 0; } bool IsInitialized() const { return m_allocator != nullptr; } AllocatorType *GetAllocator() { return m_allocator; } s32 GetCount() const { return m_max_cache_entry_count; } void AcquireCacheEntry(CacheEntry *out_entry, MemoryRange *out_range, CacheIndex index) { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(index < this->GetCount()); /* Get the entry. */ auto &entry = m_entries[index]; /* Set the out range. */ if (entry.IsWriteBack()) { *out_range = AllocatorType::MakeMemoryRange(entry.memory_address, entry.memory_size); } else { *out_range = m_allocator->AcquireCache(entry.handle); } /* Set the out entry. */ *out_entry = entry; /* Sanity check. */ AMS_ASSERT(out_entry->is_valid); AMS_ASSERT(out_entry->is_cached); /* Clear our local entry. */ entry.is_valid = false; entry.handle = 0; entry.memory_address = 0; entry.memory_size = 0; entry.lru_counter = 0; /* Update the out entry. */ out_entry->is_valid = true; out_entry->handle = 0; out_entry->memory_address = 0; out_entry->memory_size = 0; out_entry->lru_counter = 0; } bool ExistsRedundantCacheEntry(const CacheEntry &entry) const { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); /* Iterate over all entries, checking if any contain our extents. */ for (auto i = 0; i < this->GetCount(); ++i) { if (const auto &cur_entry = m_entries[i]; cur_entry.IsAllocated()) { if (cur_entry.range.offset < entry.range.GetEndOffset() && entry.range.offset < cur_entry.range.GetEndOffset()) { return true; } } } return false; } void GetEmptyCacheEntryIndex(CacheIndex *out_empty, CacheIndex *out_lru) { /* Find empty and lru indices. */ CacheIndex empty = InvalidCacheIndex, lru = InvalidCacheIndex; for (auto i = 0; i < this->GetCount(); ++i) { if (auto &entry = m_entries[i]; entry.is_valid) { /* Get/Update the lru counter. */ if (entry.lru_counter != std::numeric_limits<decltype(entry.lru_counter)>::max()) { ++entry.lru_counter; } /* Update the lru index. */ if (lru == InvalidCacheIndex || m_entries[lru].lru_counter < entry.lru_counter) { lru = i; } } else { /* The entry is invalid, so we can update the empty index. */ if (empty == InvalidCacheIndex) { empty = i; } } } /* Set the output. */ *out_empty = empty; *out_lru = lru; } void Invalidate() { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); /* Invalidate all entries. */ for (auto i = 0; i < this->GetCount(); ++i) { if (m_entries[i].is_valid) { this->InvalidateCacheEntry(i); } } } void InvalidateCacheEntry(CacheIndex index) { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(index < this->GetCount()); /* Get the entry. */ auto &entry = m_entries[index]; AMS_ASSERT(entry.is_valid); /* If necessary, perform write-back. */ if (entry.IsWriteBack()) { AMS_ASSERT(entry.memory_address != 0 && entry.handle == 0); m_allocator->DeallocateBuffer(AllocatorType::MakeMemoryRange(entry.memory_address, entry.memory_size)); } else { AMS_ASSERT(entry.memory_address == 0 && entry.handle != 0); if (const auto memory_range = m_allocator->AcquireCache(entry.handle); memory_range.first) { m_allocator->DeallocateBuffer(memory_range); } } /* Set entry as invalid. */ entry.is_valid = false; entry.Invalidate(); } void RegisterCacheEntry(CacheIndex index, const MemoryRange &memory_range, const BufferAttribute &attribute) { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); /* Register the entry. */ if (auto &entry = m_entries[index]; entry.IsWriteBack()) { entry.handle = 0; entry.memory_address = memory_range.first; entry.memory_size = memory_range.second; } else { entry.handle = m_allocator->RegisterCache(memory_range, attribute); entry.memory_address = 0; entry.memory_size = 0; } } void ReleaseCacheEntry(CacheEntry *entry, const MemoryRange &memory_range) { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); /* Release the entry. */ m_allocator->DeallocateBuffer(memory_range); entry->is_valid = false; entry->is_cached = false; } void ReleaseCacheEntry(CacheIndex index, const MemoryRange &memory_range) { return this->ReleaseCacheEntry(std::addressof(m_entries[index]), memory_range); } bool SetCacheEntry(CacheIndex index, const CacheEntry &entry, const MemoryRange &memory_range, const BufferAttribute &attr) { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(0 <= index && index < this->GetCount()); /* Write the entry. */ m_entries[index] = entry; /* Sanity check. */ AMS_ASSERT(entry.is_valid); AMS_ASSERT(entry.is_cached); AMS_ASSERT(entry.handle == 0); AMS_ASSERT(entry.memory_address == 0); /* Register or release. */ if (this->ExistsRedundantCacheEntry(entry)) { this->ReleaseCacheEntry(index, memory_range); return false; } else { this->RegisterCacheEntry(index, memory_range, attr); return true; } } bool SetCacheEntry(CacheIndex index, const CacheEntry &entry, const MemoryRange &memory_range) { const BufferAttribute attr{}; return this->SetCacheEntry(index, entry, memory_range, attr); } void SetFlushing(CacheIndex index, bool en) { if constexpr (requires { m_entries[index].is_flushing; }) { m_entries[index].is_flushing = en; } } void SetWriteBack(CacheIndex index, bool en) { if constexpr (requires { m_entries[index].is_write_back; }) { m_entries[index].is_write_back = en; } } const CacheEntry &operator[](CacheIndex index) const { /* Check pre-conditions. */ AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(0 <= index && index < this->GetCount()); return m_entries[index]; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_i_save_file.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem::save { /* TODO */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem/save/fssystem_i_save_file_system_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::fssystem::save { /* TODO */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/fssystem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fssystem/fssystem_allocator_utility.hpp> #include <stratosphere/fssystem/fssystem_utility.hpp> #include <stratosphere/fssystem/fssystem_bitmap_utils.hpp> #include <stratosphere/fssystem/fssystem_speed_emulation_configuration.hpp> #include <stratosphere/fssystem/fssystem_external_code.hpp> #include <stratosphere/fssystem/fssystem_forwarding_file_system.hpp> #include <stratosphere/fssystem/fssystem_partition_file_system.hpp> #include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp> #include <stratosphere/fssystem/fssystem_thread_priority_changer.hpp> #include <stratosphere/fssystem/fssystem_aes_ctr_storage.hpp> #include <stratosphere/fssystem/fssystem_aes_xts_storage.hpp> #include <stratosphere/fssystem/fssystem_subdirectory_filesystem.hpp> #include <stratosphere/fssystem/fssystem_directory_redirection_filesystem.hpp> #include <stratosphere/fssystem/fssystem_directory_savedata_filesystem.hpp> #include <stratosphere/fssystem/fssystem_romfs_file_system.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree.hpp> #include <stratosphere/fssystem/fssystem_bucket_tree_template_impl.hpp> #include <stratosphere/fssystem/fssystem_indirect_storage.hpp> #include <stratosphere/fssystem/fssystem_indirect_storage_template_impl.hpp> #include <stratosphere/fssystem/fssystem_sparse_storage.hpp> #include <stratosphere/fssystem/fssystem_nca_header.hpp> #include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp> #include <stratosphere/fssystem/fssystem_crypto_configuration.hpp> #include <stratosphere/fssystem/fssystem_compression_configuration.hpp> #include <stratosphere/fssystem/fssystem_aes_ctr_counter_extended_storage.hpp> #include <stratosphere/fssystem/fssystem_aes_ctr_storage_external.hpp> #include <stratosphere/fssystem/fssystem_aes_xts_storage_external.hpp> #include <stratosphere/fssystem/fssystem_switch_storage.hpp> #include <stratosphere/fssystem/buffers/fssystem_buffer_manager_utils.hpp> #include <stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp> #include <stratosphere/fssystem/fssystem_pooled_buffer.hpp> #include <stratosphere/fssystem/fssystem_service_context.hpp> #include <stratosphere/fssystem/fssystem_alignment_matching_storage_impl.hpp> #include <stratosphere/fssystem/fssystem_alignment_matching_storage.hpp> #include <stratosphere/fssystem/fssystem_compressed_storage.hpp> #include <stratosphere/fssystem/fssystem_buffered_storage.hpp> #include <stratosphere/fssystem/fssystem_hierarchical_integrity_verification_storage.hpp> #include <stratosphere/fssystem/fssystem_integrity_romfs_storage.hpp> #include <stratosphere/fssystem/fssystem_sha_hash_generator.hpp> #include <stratosphere/fssystem/fssystem_local_file_system.hpp> #include <stratosphere/fssystem/fssystem_file_system_proxy_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/gc/gc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gc/impl/gc_types.hpp> namespace ams::gc { struct GameCardIdSet { gc::impl::CardId1 id1; gc::impl::CardId2 id2; gc::impl::CardId3 id3; }; static_assert(util::is_pod<GameCardIdSet>::value); static_assert(sizeof(GameCardIdSet) == 0xC); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gc/impl/gc_embedded_data_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gc/impl/gc_gc_crypto.hpp> namespace ams::gc::impl { class EmbeddedDataHolder { NON_COPYABLE(EmbeddedDataHolder); NON_MOVEABLE(EmbeddedDataHolder); friend class GcCrypto; private: struct ConcatenatedGcLibraryEmbeddedKeys { u8 enc_hmac_key_for_cv[GcCrypto::GcHmacKeyLength]; u8 enc_hmac_key_for_key_and_iv[GcCrypto::GcHmacKeyLength]; u8 enc_cv_constant_value[GcCrypto::GcCvConstLength]; u8 enc_rsa_oaep_label_hash[GcCrypto::GcSha256HashLength]; }; static_assert(util::is_pod<ConcatenatedGcLibraryEmbeddedKeys>::value); static_assert(sizeof(ConcatenatedGcLibraryEmbeddedKeys) == 0x70); private: static bool s_is_dev; static const void *s_ca_public_exponent; static const void *s_ca1_modulus; static const void *s_ca9_modulus; static const void *s_ca10_modulus; static const void *s_ca10_certificate_modulus; static const void *s_card_header_key; private: static constinit inline u8 s_titlekey_keks[GcCrypto::GcTitleKeyKekIndexMax][GcCrypto::GcAesKeyLength] = {}; public: static Result SetLibraryEmbeddedKeys(bool is_dev = GcCrypto::CheckDevelopmentSpl()); static void SetLibraryTitleKeyKek(size_t kek_index, const void *kek, size_t kek_size) { AMS_ASSERT(kek_index < GcCrypto::GcTitleKeyKekIndexMax); AMS_ASSERT(kek_size == GcCrypto::GcAesKeyLength); AMS_UNUSED(kek_size); std::memcpy(s_titlekey_keks[kek_index], kek, sizeof(s_titlekey_keks[kek_index])); } private: static Result DecryptoEmbeddedKeys(ConcatenatedGcLibraryEmbeddedKeys *out, size_t out_size, bool is_dev = GcCrypto::CheckDevelopmentSpl()); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gc/impl/gc_gc_crypto.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gc/impl/gc_types.hpp> namespace ams::gc::impl { class GcCrypto { NON_COPYABLE(GcCrypto); NON_MOVEABLE(GcCrypto); public: static constexpr size_t GcRsaKeyLength = crypto::Rsa2048PssSha256Verifier::ModulusSize; static constexpr size_t GcRsaPublicExponentLength = 3; static constexpr size_t GcAesKeyLength = crypto::AesEncryptor128::KeySize; static constexpr size_t GcAesCbcIvLength = crypto::Aes128CbcEncryptor::IvSize; static constexpr size_t GcHmacKeyLength = 0x20; static constexpr size_t GcCvConstLength = 0x10; static constexpr size_t GcTitleKeyKekIndexMax = 0x10; static constexpr size_t GcSha256HashLength = crypto::Sha256Generator::HashSize; public: static bool CheckDevelopmentSpl(); static Result DecryptAesKeySpl(void *dst, size_t dst_size, const void *src, size_t src_size, s32 generation, u32 option); static Result VerifyCardHeader(const void *header_buffer, size_t header_size, const void *modulus, size_t modulus_size); static Result EncryptCardHeader(void *header, size_t header_size); static Result DecryptCardHeader(void *header, size_t header_size); static Result VerifyT1CardCertificate(const void *cert_buffer, size_t cert_size); static Result VerifyCa10Certificate(const void *cert_buffer, size_t cert_size); static Result DecryptCardInitialData(void *dst, size_t dst_size, const void *initial_data, size_t data_size, size_t kek_index); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gc/impl/gc_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::gc::impl { struct CardInitialDataPayload { u8 package_id[8]; u8 reserved_8[8]; u8 auth_data[0x10]; u8 auth_mac[0x10]; u8 auth_nonce[0xC]; }; static_assert(util::is_pod<CardInitialDataPayload>::value); static_assert(sizeof(CardInitialDataPayload) == 0x3C); struct CardInitialData { CardInitialDataPayload payload; u8 padding[0x200 - sizeof(CardInitialDataPayload)]; }; static_assert(util::is_pod<CardInitialData>::value); static_assert(sizeof(CardInitialData) == 0x200); enum FwVersion : u8 { FwVersion_ForDev = 0, FwVersion_1_0_0 = 1, FwVersion_4_0_0 = 2, FwVersion_9_0_0 = 3, FwVersion_11_0_0 = 4, FwVersion_12_0_0 = 5, }; enum KekIndex : u8 { KekIndex_Version0 = 0, KekIndex_VersionForDev = 1, }; struct CardHeaderKeyIndex { using KekIndex = util::BitPack8::Field<0, 4, gc::impl::KekIndex>; using TitleKeyDecIndex = util::BitPack8::Field<KekIndex::Next, 4, u8>; static_assert(TitleKeyDecIndex::Next == BITSIZEOF(u8)); }; struct CardHeaderEncryptedData { u32 fw_version[2]; u32 acc_ctrl_1; u32 wait_1_time_read; u32 wait_2_time_read; u32 wait_1_time_write; u32 wait_2_time_write; u32 fw_mode; u32 cup_version; u8 compatibility_type; u8 reserved_25; u8 reserved_26; u8 reserved_27; u8 upp_hash[8]; u64 cup_id; u8 reserved_38[0x38]; }; static_assert(util::is_pod<CardHeaderEncryptedData>::value); static_assert(sizeof(CardHeaderEncryptedData) == 0x70); enum MakerCodeForCardId1 : u8 { MakerCodeForCardId1_MegaChips = 0xC2, MakerCodeForCardId1_Lapis = 0xAE, }; enum MemoryCapacity : u8 { MemoryCapacity_1GB = 0xFA, MemoryCapacity_2GB = 0xF8, MemoryCapacity_4GB = 0xF0, MemoryCapacity_8GB = 0xE0, MemoryCapacity_16GB = 0xE1, MemoryCapacity_32GB = 0xE2, }; enum MemoryType : u8 { MemoryType_T1RomFast = 0x01, MemoryType_T2RomFast = 0x02, MemoryType_T1NandFast = 0x09, MemoryType_T2NandFast = 0x0A, MemoryType_T1RomLate = 0x21, MemoryType_T2RomLate = 0x22, MemoryType_T1NandLate = 0x29, MemoryType_T2NandLate = 0x2A, }; enum CardSecurityNumber : u8 { CardSecurityNumber_0 = 0x00, CardSecurityNumber_1 = 0x01, CardSecurityNumber_2 = 0x02, CardSecurityNumber_3 = 0x03, CardSecurityNumber_4 = 0x04, }; enum CardType : u8 { CardType_Rom = 0x00, CardType_Writable_Dev_T1 = 0x01, CardType_Writable_Prod_T1 = 0x02, CardType_Writable_Dev_T2 = 0x03, CardType_Writable_Prod_T2 = 0x04, }; enum AccessControl1ClockRate : u32 { AccessControl1ClockRate_25MHz = 0x00A10011, AccessControl1ClockRate_50MHz = 0x00A10010, }; enum SelSec : u8 { SelSec_T1 = 1, SelSec_T2 = 2, }; struct CardId1 { MakerCodeForCardId1 maker_code; MemoryCapacity memory_capacity; u8 reserved; MemoryType memory_type; }; struct CardId2 { CardSecurityNumber card_security_number; CardType card_type; u8 reserved[2]; }; struct CardId3 { u8 reserved[4]; }; struct CardHeader { static constexpr u32 Magic = util::FourCC<'H','E','A','D'>::Code; u32 magic; u32 rom_area_start_page; u32 backup_area_start_page; util::BitPack8 key_index; u8 rom_size; u8 version; u8 flags; u8 package_id[8]; u32 valid_data_end_page; u8 reserved_11C[4]; u8 iv[crypto::Aes128CbcDecryptor::IvSize]; u64 partition_fs_header_address; u64 partition_fs_header_size; u8 partition_fs_header_hash[crypto::Sha256Generator::HashSize]; u8 initial_data_hash[crypto::Sha256Generator::HashSize]; u32 sel_sec; u32 sel_t1_key; u32 sel_key; u32 lim_area_page; union { u8 raw_encrypted_data[sizeof(CardHeaderEncryptedData)]; CardHeaderEncryptedData encrypted_data; }; }; static_assert(util::is_pod<CardHeader>::value); static_assert(sizeof(CardHeader) == 0x100); struct CardHeaderWithSignature { u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize]; CardHeader data; }; static_assert(util::is_pod<CardHeaderWithSignature>::value); static_assert(sizeof(CardHeaderWithSignature) == 0x200); static constexpr size_t CardDeviceIdLength = 0x10; struct T1CardCertificate { static constexpr u32 Magic = util::FourCC<'C','E','R','T'>::Code; u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize]; u32 magic; u32 version; u8 kek_index; u8 flags[7]; u8 t1_card_device_id[CardDeviceIdLength]; u8 iv[crypto::Aes128CtrEncryptor::IvSize]; u8 hw_key[crypto::Aes128CtrEncryptor::KeySize]; u8 reserved[0xC0]; u8 padding[0x200]; }; static_assert(util::is_pod<T1CardCertificate>::value); static_assert(sizeof(T1CardCertificate) == 0x400); struct Ca10Certificate { u8 signature[crypto::Rsa2048Pkcs1Sha256Verifier::SignatureSize]; u8 unk_100[0x30]; u8 modulus[crypto::Rsa2048Pkcs1Sha256Verifier::ModulusSize]; u8 unk_230[0x1D0]; }; static_assert(util::is_pod<Ca10Certificate>::value); static_assert(sizeof(Ca10Certificate) == 0x400); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/gc/impl/gc_types.hpp> #include <stratosphere/gc/impl/gc_gc_crypto.hpp> #include <stratosphere/gc/impl/gc_embedded_data_holder.hpp> #include <stratosphere/gc/gc.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/board/nintendo/nx/gpio_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/driver/gpio_i_gpio_driver.hpp> namespace ams::gpio::driver::board::nintendo::nx { void Initialize(bool enable_interrupt_handlers); void SetInitialGpioConfig(); void SetInitialWakePinConfig(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_driver_client_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/driver/gpio_i_gpio_driver.hpp> namespace ams::gpio::driver { void Initialize(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_driver_service_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/driver/gpio_i_gpio_driver.hpp> namespace ams::gpio::driver { void RegisterDriver(IGpioDriver *driver); void UnregisterDriver(IGpioDriver *driver); Result RegisterDeviceCode(DeviceCode device_code, Pad *pad); bool UnregisterDeviceCode(DeviceCode device_code); void RegisterInterruptHandler(ddsf::IEventHandler *handler); void UnregisterInterruptHandler(ddsf::IEventHandler *handler); void SetInitialGpioConfig(); void SetInitialWakePinConfig(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_i_gpio_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/ddsf.hpp> namespace ams::gpio::driver { class Pad; class IGpioDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(IGpioDriver); NON_MOVEABLE(IGpioDriver); AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::IGpioDriver, ::ams::ddsf::IDriver); public: IGpioDriver() : IDriver() { /* ... */ } virtual ~IGpioDriver() { /* ... */ } virtual void InitializeDriver() = 0; virtual void FinalizeDriver() = 0; virtual Result InitializePad(Pad *pad) = 0; virtual void FinalizePad(Pad *pad) = 0; virtual Result GetDirection(Direction *out, Pad *pad) const = 0; virtual Result SetDirection(Pad *pad, Direction direction) = 0; virtual Result GetValue(GpioValue *out, Pad *pad) const = 0; virtual Result SetValue(Pad *pad, GpioValue value) = 0; virtual Result GetInterruptMode(InterruptMode *out, Pad *pad) const = 0; virtual Result SetInterruptMode(Pad *pad, InterruptMode mode) = 0; virtual Result SetInterruptEnabled(Pad *pad, bool en) = 0; virtual Result GetInterruptStatus(InterruptStatus *out, Pad *pad) = 0; virtual Result ClearInterruptStatus(Pad *pad) = 0; virtual os::SdkMutex &GetInterruptControlMutex(const Pad &pad) const = 0; virtual Result GetDebounceEnabled(bool *out, Pad *pad) const = 0; virtual Result SetDebounceEnabled(Pad *pad, bool en) = 0; virtual Result GetDebounceTime(s32 *out_ms, Pad *pad) const = 0; virtual Result SetDebounceTime(Pad *pad, s32 ms) = 0; virtual Result GetUnknown22(u32 *out) = 0; virtual void Unknown23() = 0; virtual Result SetValueForSleepState(Pad *pad, GpioValue value) = 0; virtual Result IsWakeEventActive(bool *out, Pad *pad) const = 0; virtual Result SetWakeEventActiveFlagSetForDebug(Pad *pad, bool en) = 0; virtual Result SetWakePinDebugMode(WakePinDebugMode mode) = 0; virtual Result Suspend() = 0; virtual Result SuspendLow() = 0; virtual Result Resume() = 0; virtual Result ResumeLow() = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/ddsf.hpp> namespace ams::gpio::driver { class Pad : public ::ams::ddsf::IDevice { NON_COPYABLE(Pad); NON_MOVEABLE(Pad); AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::Pad, ::ams::ddsf::IDevice); private: int m_pad_number; bool m_is_interrupt_enabled; public: explicit Pad(int pad) : IDevice(true), m_pad_number(pad), m_is_interrupt_enabled(false) { /* ... */ } Pad() : Pad(0) { /* ... */ } virtual ~Pad() { /* ... */ } int GetPadNumber() const { return m_pad_number; } void SetPadNumber(int p) { m_pad_number = p; } bool IsInterruptEnabled() const { return m_is_interrupt_enabled; } void SetInterruptEnabled(bool en) { m_is_interrupt_enabled = en; } bool IsInterruptRequiredForDriver() const { return this->IsInterruptEnabled() && this->IsAnySessionBoundToInterrupt(); } bool IsAnySessionBoundToInterrupt() const; void SignalInterruptBoundEvent(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> namespace ams::gpio::driver { namespace impl { constexpr inline size_t GpioPadSessionSize = 0x60; constexpr inline size_t GpioPadSessionAlign = 8; struct alignas(GpioPadSessionAlign) GpioPadSessionImplPadded; } struct GpioPadSession { util::TypedStorage<impl::GpioPadSessionImplPadded, impl::GpioPadSessionSize, impl::GpioPadSessionAlign> _impl; }; Result OpenSession(GpioPadSession *out, DeviceCode device_code, ddsf::AccessMode access_mode); void CloseSession(GpioPadSession *session); Result SetDirection(GpioPadSession *session, gpio::Direction direction); Result GetDirection(gpio::Direction *out, GpioPadSession *session); Result SetValue(GpioPadSession *session, gpio::GpioValue value); Result GetValue(gpio::GpioValue *out, GpioPadSession *session); /* TODO */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_select_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/driver/gpio_i_gpio_driver.hpp> #include <stratosphere/gpio/driver/gpio_driver_service_api.hpp> #include <stratosphere/gpio/driver/gpio_driver_client_api.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/gpio/driver/board/nintendo/nx/gpio_driver_api.hpp> namespace ams::gpio::driver::board { using namespace ams::gpio::driver::board::nintendo::nx; } #else // TODO: #error "Unknown board for ams::gpio::driver::" #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_event_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::gpio::driver::impl { class EventHolder { NON_COPYABLE(EventHolder); NON_MOVEABLE(EventHolder); private: os::SystemEventType *m_event; public: constexpr EventHolder() : m_event(nullptr) { /* ... */ } void AttachEvent(os::SystemEventType *event) { m_event = event; } os::SystemEventType *DetachEvent() { auto ev = m_event; m_event = nullptr; return ev; } os::SystemEventType *GetSystemEvent() { return m_event; } bool IsBound() const { return m_event != nullptr; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_pad_session_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/driver/gpio_pad_accessor.hpp> #include <stratosphere/gpio/driver/impl/gpio_event_holder.hpp> #include <stratosphere/ddsf.hpp> namespace ams::gpio::driver { class Pad; } namespace ams::gpio::driver::impl { class PadSessionImpl : public ::ams::ddsf::ISession { NON_COPYABLE(PadSessionImpl); NON_MOVEABLE(PadSessionImpl); AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::impl::PadSessionImpl, ::ams::ddsf::ISession); private: EventHolder m_event_holder; private: Result UpdateDriverInterruptEnabled(); public: PadSessionImpl() : m_event_holder() { /* ... */ } ~PadSessionImpl() { this->Close(); } bool IsInterruptBound() const { return m_event_holder.IsBound(); } Result Open(Pad *pad, ddsf::AccessMode access_mode); void Close(); Result BindInterrupt(os::SystemEventType *event); void UnbindInterrupt(); Result GetInterruptEnabled(bool *out) const; Result SetInterruptEnabled(bool en); void SignalInterruptBoundEvent(); }; static_assert( sizeof(PadSessionImpl) <= GpioPadSessionSize); static_assert(alignof(PadSessionImpl) <= GpioPadSessionAlign); struct alignas(GpioPadSessionAlign) GpioPadSessionImplPadded { PadSessionImpl _impl; u8 _padding[GpioPadSessionSize - sizeof(PadSessionImpl)]; }; static_assert( sizeof(GpioPadSessionImplPadded) == GpioPadSessionSize); static_assert(alignof(GpioPadSessionImplPadded) == GpioPadSessionAlign); ALWAYS_INLINE PadSessionImpl &GetPadSessionImpl(GpioPadSession &session) { return GetReference(session._impl)._impl; } ALWAYS_INLINE const PadSessionImpl &GetPadSessionImpl(const GpioPadSession &session) { return GetReference(session._impl)._impl; } ALWAYS_INLINE PadSessionImpl &GetOpenPadSessionImpl(GpioPadSession &session) { auto &ref = GetReference(session._impl)._impl; AMS_ASSERT(ref.IsOpen()); return ref; } ALWAYS_INLINE const PadSessionImpl &GetOpenPadSessionImpl(const GpioPadSession &session) { const auto &ref = GetReference(session._impl)._impl; AMS_ASSERT(ref.IsOpen()); return ref; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/sf/gpio_sf_i_manager.hpp> namespace ams::gpio { void Initialize(); void Finalize(); void InitializeWith(ams::sf::SharedPointer<gpio::sf::IManager> sp); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/gpio_select_pad_name.hpp> #include <stratosphere/gpio/driver/gpio_pad.hpp> namespace ams::gpio { struct GpioPadSession { void *_session; os::SystemEventType *_event; }; Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code); void CloseSession(GpioPadSession *session); Direction GetDirection(GpioPadSession *session); void SetDirection(GpioPadSession *session, Direction direction); GpioValue GetValue(GpioPadSession *session); void SetValue(GpioPadSession *session, GpioValue value); InterruptMode GetInterruptMode(GpioPadSession *session); void SetInterruptMode(GpioPadSession *session, InterruptMode mode); bool GetInterruptEnable(GpioPadSession *session); void SetInterruptEnable(GpioPadSession *session, bool en); InterruptStatus GetInterruptStatus(GpioPadSession *session); void ClearInterruptStatus(GpioPadSession *session); int GetDebounceTime(GpioPadSession *session); void SetDebounceTime(GpioPadSession *session, int ms); bool GetDebounceEnabled(GpioPadSession *session); void SetDebounceEnabled(GpioPadSession *session, bool en); Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session); void UnbindInterrupt(GpioPadSession *session); Result IsWakeEventActive(bool *out_is_active, ams::DeviceCode device_code); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> namespace ams::gpio { enum GpioPadName : u32 { GpioPadName_CodecLdoEnTemp = 1, GpioPadName_PowSdEn = 2, GpioPadName_BtRst = 3, GpioPadName_RamCode3 = 4, GpioPadName_GameCardReset = 5, GpioPadName_CodecAlert = 6, GpioPadName_PowGc = 7, GpioPadName_DebugControllerDet = 8, GpioPadName_BattChgStatus = 9, GpioPadName_BattChgEnableN = 10, GpioPadName_FanTach = 11, GpioPadName_ExtconDetS = 12, GpioPadName_Vdd50AEn = 13, GpioPadName_SdevCoaxSel1 = 14, GpioPadName_GameCardCd = 15, GpioPadName_ProdType0 = 16, GpioPadName_ProdType1 = 17, GpioPadName_ProdType2 = 18, GpioPadName_ProdType3 = 19, GpioPadName_TempAlert = 20, GpioPadName_CodecHpDetIrq = 21, GpioPadName_MotionInt = 22, GpioPadName_TpIrq = 23, GpioPadName_ButtonSleep2 = 24, GpioPadName_ButtonVolUp = 25, GpioPadName_ButtonVolDn = 26, GpioPadName_BattMgicIrq = 27, GpioPadName_RecoveryKey = 28, GpioPadName_PowLcdBlEn = 29, GpioPadName_LcdReset = 30, GpioPadName_PdVconnEn = 31, GpioPadName_PdRstN = 32, GpioPadName_Bq24190Irq = 33, GpioPadName_SdevCoaxSel0 = 34, GpioPadName_SdWp = 35, GpioPadName_TpReset = 36, GpioPadName_BtGpio2 = 37, GpioPadName_BtGpio3 = 38, GpioPadName_BtGpio4 = 39, GpioPadName_CradleIrq = 40, GpioPadName_PowVcpuInt = 41, GpioPadName_Max77621GpuInt = 42, GpioPadName_ExtconChgU = 43, GpioPadName_ExtconChgS = 44, GpioPadName_WifiRfDisable = 45, GpioPadName_WifiReset = 46, GpioPadName_ApWakeBt = 47, GpioPadName_BtWakeAp = 48, GpioPadName_BtGpio5 = 49, GpioPadName_PowLcdVddPEn = 50, GpioPadName_PowLcdVddNEn = 51, GpioPadName_ExtconDetU = 52, GpioPadName_RamCode2 = 53, GpioPadName_Vdd50BEn = 54, GpioPadName_WifiWakeHost = 55, GpioPadName_SdCd = 56, GpioPadName_OtgFet1ForSdev = 57, GpioPadName_OtgFet2ForSdev = 58, GpioPadName_ExtConWakeU = 59, GpioPadName_ExtConWakeS = 60, GpioPadName_PmuIrq = 61, GpioPadName_ExtUart2Cts = 62, GpioPadName_ExtUart3Cts = 63, GpioPadName_5VStepDownEn = 64, GpioPadName_UsbSwitchB2Oc = 65, GpioPadName_5VStepDownPg = 66, GpioPadName_UsbSwitchAEn = 67, GpioPadName_UsbSwitchAFlag = 68, GpioPadName_UsbSwitchB3Oc = 69, GpioPadName_UsbSwitchB3En = 70, GpioPadName_UsbSwitchB2En = 71, GpioPadName_Hdmi5VEn = 72, GpioPadName_UsbSwitchB1En = 73, GpioPadName_HdmiPdTrEn = 74, GpioPadName_FanEn = 75, GpioPadName_UsbSwitchB1Oc = 76, GpioPadName_PwmFan = 77, GpioPadName_HdmiHpd = 78, GpioPadName_Max77812Irq = 79, GpioPadName_Debug0 = 80, GpioPadName_Debug1 = 81, GpioPadName_Debug2 = 82, GpioPadName_Debug3 = 83, GpioPadName_NfcIrq = 84, GpioPadName_NfcRst = 85, GpioPadName_McuIrq = 86, GpioPadName_McuBoot = 87, GpioPadName_McuRst = 88, GpioPadName_Vdd5V3En = 89, GpioPadName_McuPor = 90, GpioPadName_LcdGpio1 = 91, GpioPadName_NfcEn = 92, }; constexpr inline const DeviceCode DeviceCode_CodecLdoEnTemp = 0x33000002; constexpr inline const DeviceCode DeviceCode_PowSdEn = 0x3C000001; constexpr inline const DeviceCode DeviceCode_BtRst = 0x37000002; constexpr inline const DeviceCode DeviceCode_RamCode3 = 0xC9000402; constexpr inline const DeviceCode DeviceCode_GameCardReset = 0x3C000402; constexpr inline const DeviceCode DeviceCode_CodecAlert = 0x33000003; constexpr inline const DeviceCode DeviceCode_PowGc = 0x3C000401; constexpr inline const DeviceCode DeviceCode_DebugControllerDet = 0x350000CA; constexpr inline const DeviceCode DeviceCode_BattChgStatus = 0x39000407; constexpr inline const DeviceCode DeviceCode_BattChgEnableN = 0x39000003; constexpr inline const DeviceCode DeviceCode_FanTach = 0x3D000002; constexpr inline const DeviceCode DeviceCode_ExtconDetS = 0x3500040B; constexpr inline const DeviceCode DeviceCode_Vdd50AEn = 0x39000401; constexpr inline const DeviceCode DeviceCode_SdevCoaxSel1 = 0xCA000406; constexpr inline const DeviceCode DeviceCode_GameCardCd = 0x3C000403; constexpr inline const DeviceCode DeviceCode_ProdType0 = 0xC900040B; constexpr inline const DeviceCode DeviceCode_ProdType1 = 0xC900040C; constexpr inline const DeviceCode DeviceCode_ProdType2 = 0xC900040D; constexpr inline const DeviceCode DeviceCode_ProdType3 = 0xC900040E; constexpr inline const DeviceCode DeviceCode_TempAlert = 0x3E000002; constexpr inline const DeviceCode DeviceCode_CodecHpDetIrq = 0x33000004; constexpr inline const DeviceCode DeviceCode_MotionInt = 0x35000041; constexpr inline const DeviceCode DeviceCode_TpIrq = 0x35000036; constexpr inline const DeviceCode DeviceCode_ButtonSleep2 = 0x35000001; constexpr inline const DeviceCode DeviceCode_ButtonVolUp = 0x35000002; constexpr inline const DeviceCode DeviceCode_ButtonVolDn = 0x35000003; constexpr inline const DeviceCode DeviceCode_BattMgicIrq = 0x39000034; constexpr inline const DeviceCode DeviceCode_RecoveryKey = 0x35000004; constexpr inline const DeviceCode DeviceCode_PowLcdBlEn = 0x3400003E; constexpr inline const DeviceCode DeviceCode_LcdReset = 0x34000033; constexpr inline const DeviceCode DeviceCode_PdVconnEn = 0x040000CC; constexpr inline const DeviceCode DeviceCode_PdRstN = 0x040000CA; constexpr inline const DeviceCode DeviceCode_Bq24190Irq = 0x39000002; constexpr inline const DeviceCode DeviceCode_SdevCoaxSel0 = 0xCA000405; constexpr inline const DeviceCode DeviceCode_SdWp = 0x3C000003; constexpr inline const DeviceCode DeviceCode_TpReset = 0x35000035; constexpr inline const DeviceCode DeviceCode_BtGpio2 = 0x37000401; constexpr inline const DeviceCode DeviceCode_BtGpio3 = 0x37000402; constexpr inline const DeviceCode DeviceCode_BtGpio4 = 0x37000403; constexpr inline const DeviceCode DeviceCode_CradleIrq = 0x040000CB; constexpr inline const DeviceCode DeviceCode_PowVcpuInt = 0x3E000003; constexpr inline const DeviceCode DeviceCode_Max77621GpuInt = 0x3E000004; constexpr inline const DeviceCode DeviceCode_ExtconChgU = 0x35000402; constexpr inline const DeviceCode DeviceCode_ExtconChgS = 0x3500040C; constexpr inline const DeviceCode DeviceCode_WifiRfDisable = 0x38000003; constexpr inline const DeviceCode DeviceCode_WifiReset = 0x38000002; constexpr inline const DeviceCode DeviceCode_ApWakeBt = 0x37000003; constexpr inline const DeviceCode DeviceCode_BtWakeAp = 0x37000004; constexpr inline const DeviceCode DeviceCode_BtGpio5 = 0x37000404; constexpr inline const DeviceCode DeviceCode_PowLcdVddPEn = 0x34000034; constexpr inline const DeviceCode DeviceCode_PowLcdVddNEn = 0x34000035; constexpr inline const DeviceCode DeviceCode_ExtconDetU = 0x35000401; constexpr inline const DeviceCode DeviceCode_RamCode2 = 0xC9000401; constexpr inline const DeviceCode DeviceCode_Vdd50BEn = 0x39000402; constexpr inline const DeviceCode DeviceCode_WifiWakeHost = 0x38000004; constexpr inline const DeviceCode DeviceCode_SdCd = 0x3C000002; constexpr inline const DeviceCode DeviceCode_OtgFet1ForSdev = 0x39000404; constexpr inline const DeviceCode DeviceCode_OtgFet2ForSdev = 0x39000405; constexpr inline const DeviceCode DeviceCode_ExtConWakeU = 0x35000403; constexpr inline const DeviceCode DeviceCode_ExtConWakeS = 0x3500040D; constexpr inline const DeviceCode DeviceCode_PmuIrq = 0x39000406; constexpr inline const DeviceCode DeviceCode_ExtUart2Cts = 0x35000404; constexpr inline const DeviceCode DeviceCode_ExtUart3Cts = 0x3500040E; constexpr inline const DeviceCode DeviceCode_5VStepDownEn = 0x39000408; constexpr inline const DeviceCode DeviceCode_UsbSwitchB2Oc = 0x04000401; constexpr inline const DeviceCode DeviceCode_5VStepDownPg = 0x39000409; constexpr inline const DeviceCode DeviceCode_UsbSwitchAEn = 0x04000402; constexpr inline const DeviceCode DeviceCode_UsbSwitchAFlag = 0x04000403; constexpr inline const DeviceCode DeviceCode_UsbSwitchB3Oc = 0x04000404; constexpr inline const DeviceCode DeviceCode_UsbSwitchB3En = 0x04000405; constexpr inline const DeviceCode DeviceCode_UsbSwitchB2En = 0x04000406; constexpr inline const DeviceCode DeviceCode_Hdmi5VEn = 0x34000004; constexpr inline const DeviceCode DeviceCode_UsbSwitchB1En = 0x04000407; constexpr inline const DeviceCode DeviceCode_HdmiPdTrEn = 0x34000005; constexpr inline const DeviceCode DeviceCode_FanEn = 0x3D000003; constexpr inline const DeviceCode DeviceCode_UsbSwitchB1Oc = 0x04000408; constexpr inline const DeviceCode DeviceCode_PwmFan = 0x3D000001; constexpr inline const DeviceCode DeviceCode_HdmiHpd = 0x34000006; constexpr inline const DeviceCode DeviceCode_Max77812Irq = 0x3E000003; constexpr inline const DeviceCode DeviceCode_Debug0 = 0xCA000001; constexpr inline const DeviceCode DeviceCode_Debug1 = 0xCA000002; constexpr inline const DeviceCode DeviceCode_Debug2 = 0xCA000003; constexpr inline const DeviceCode DeviceCode_Debug3 = 0xCA000004; constexpr inline const DeviceCode DeviceCode_NfcIrq = 0x36000004; constexpr inline const DeviceCode DeviceCode_NfcRst = 0x36000003; constexpr inline const DeviceCode DeviceCode_McuIrq = 0x35000415; constexpr inline const DeviceCode DeviceCode_McuBoot = 0x35000416; constexpr inline const DeviceCode DeviceCode_McuRst = 0x35000417; constexpr inline const DeviceCode DeviceCode_Vdd5V3En = 0x39000403; constexpr inline const DeviceCode DeviceCode_McuPor = 0x35000418; constexpr inline const DeviceCode DeviceCode_LcdGpio1 = 0x35000005; constexpr inline const DeviceCode DeviceCode_NfcEn = 0x36000002; constexpr inline const DeviceCode DeviceCode_ExtUart2Rts = 0x35000406; constexpr inline const DeviceCode DeviceCode_ExtUart3Rts = 0x35000410; constexpr inline const DeviceCode DeviceCode_GpioPortC7 = 0x3500041B; constexpr inline const DeviceCode DeviceCode_GpioPortD0 = 0x3500041C; constexpr inline const DeviceCode DeviceCode_GpioPortC5 = 0x3500041D; constexpr inline const DeviceCode DeviceCode_GpioPortC6 = 0x3500041E; constexpr inline const DeviceCode DeviceCode_GpioPortY7 = 0x35000065; constexpr inline const DeviceCode DeviceCode_GpioPortF1 = 0x04000409; constexpr inline const DeviceCode DeviceCode_GpioPortH0 = 0x34000401; constexpr inline const DeviceCode DeviceCode_GpioPortI6 = 0x37000405; constexpr inline GpioPadName ConvertToGpioPadName(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_CodecLdoEnTemp .GetInternalValue(): return GpioPadName_CodecLdoEnTemp; case DeviceCode_PowSdEn .GetInternalValue(): return GpioPadName_PowSdEn; case DeviceCode_BtRst .GetInternalValue(): return GpioPadName_BtRst; case DeviceCode_RamCode3 .GetInternalValue(): return GpioPadName_RamCode3; case DeviceCode_GameCardReset .GetInternalValue(): return GpioPadName_GameCardReset; case DeviceCode_CodecAlert .GetInternalValue(): return GpioPadName_CodecAlert; case DeviceCode_PowGc .GetInternalValue(): return GpioPadName_PowGc; case DeviceCode_DebugControllerDet.GetInternalValue(): return GpioPadName_DebugControllerDet; case DeviceCode_BattChgStatus .GetInternalValue(): return GpioPadName_BattChgStatus; case DeviceCode_BattChgEnableN .GetInternalValue(): return GpioPadName_BattChgEnableN; case DeviceCode_FanTach .GetInternalValue(): return GpioPadName_FanTach; case DeviceCode_ExtconDetS .GetInternalValue(): return GpioPadName_ExtconDetS; case DeviceCode_Vdd50AEn .GetInternalValue(): return GpioPadName_Vdd50AEn; case DeviceCode_SdevCoaxSel1 .GetInternalValue(): return GpioPadName_SdevCoaxSel1; case DeviceCode_GameCardCd .GetInternalValue(): return GpioPadName_GameCardCd; case DeviceCode_ProdType0 .GetInternalValue(): return GpioPadName_ProdType0; case DeviceCode_ProdType1 .GetInternalValue(): return GpioPadName_ProdType1; case DeviceCode_ProdType2 .GetInternalValue(): return GpioPadName_ProdType2; case DeviceCode_ProdType3 .GetInternalValue(): return GpioPadName_ProdType3; case DeviceCode_TempAlert .GetInternalValue(): return GpioPadName_TempAlert; case DeviceCode_CodecHpDetIrq .GetInternalValue(): return GpioPadName_CodecHpDetIrq; case DeviceCode_MotionInt .GetInternalValue(): return GpioPadName_MotionInt; case DeviceCode_TpIrq .GetInternalValue(): return GpioPadName_TpIrq; case DeviceCode_ButtonSleep2 .GetInternalValue(): return GpioPadName_ButtonSleep2; case DeviceCode_ButtonVolUp .GetInternalValue(): return GpioPadName_ButtonVolUp; case DeviceCode_ButtonVolDn .GetInternalValue(): return GpioPadName_ButtonVolDn; case DeviceCode_BattMgicIrq .GetInternalValue(): return GpioPadName_BattMgicIrq; case DeviceCode_RecoveryKey .GetInternalValue(): return GpioPadName_RecoveryKey; case DeviceCode_PowLcdBlEn .GetInternalValue(): return GpioPadName_PowLcdBlEn; case DeviceCode_LcdReset .GetInternalValue(): return GpioPadName_LcdReset; case DeviceCode_PdVconnEn .GetInternalValue(): return GpioPadName_PdVconnEn; case DeviceCode_PdRstN .GetInternalValue(): return GpioPadName_PdRstN; case DeviceCode_Bq24190Irq .GetInternalValue(): return GpioPadName_Bq24190Irq; case DeviceCode_SdevCoaxSel0 .GetInternalValue(): return GpioPadName_SdevCoaxSel0; case DeviceCode_SdWp .GetInternalValue(): return GpioPadName_SdWp; case DeviceCode_TpReset .GetInternalValue(): return GpioPadName_TpReset; case DeviceCode_BtGpio2 .GetInternalValue(): return GpioPadName_BtGpio2; case DeviceCode_BtGpio3 .GetInternalValue(): return GpioPadName_BtGpio3; case DeviceCode_BtGpio4 .GetInternalValue(): return GpioPadName_BtGpio4; case DeviceCode_CradleIrq .GetInternalValue(): return GpioPadName_CradleIrq; /* case DeviceCode_PowVcpuInt .GetInternalValue(): return GpioPadName_PowVcpuInt; */ case DeviceCode_Max77621GpuInt .GetInternalValue(): return GpioPadName_Max77621GpuInt; case DeviceCode_ExtconChgU .GetInternalValue(): return GpioPadName_ExtconChgU; case DeviceCode_ExtconChgS .GetInternalValue(): return GpioPadName_ExtconChgS; case DeviceCode_WifiRfDisable .GetInternalValue(): return GpioPadName_WifiRfDisable; case DeviceCode_WifiReset .GetInternalValue(): return GpioPadName_WifiReset; case DeviceCode_ApWakeBt .GetInternalValue(): return GpioPadName_ApWakeBt; case DeviceCode_BtWakeAp .GetInternalValue(): return GpioPadName_BtWakeAp; case DeviceCode_BtGpio5 .GetInternalValue(): return GpioPadName_BtGpio5; case DeviceCode_PowLcdVddPEn .GetInternalValue(): return GpioPadName_PowLcdVddPEn; case DeviceCode_PowLcdVddNEn .GetInternalValue(): return GpioPadName_PowLcdVddNEn; case DeviceCode_ExtconDetU .GetInternalValue(): return GpioPadName_ExtconDetU; case DeviceCode_RamCode2 .GetInternalValue(): return GpioPadName_RamCode2; case DeviceCode_Vdd50BEn .GetInternalValue(): return GpioPadName_Vdd50BEn; case DeviceCode_WifiWakeHost .GetInternalValue(): return GpioPadName_WifiWakeHost; case DeviceCode_SdCd .GetInternalValue(): return GpioPadName_SdCd; case DeviceCode_OtgFet1ForSdev .GetInternalValue(): return GpioPadName_OtgFet1ForSdev; case DeviceCode_OtgFet2ForSdev .GetInternalValue(): return GpioPadName_OtgFet2ForSdev; case DeviceCode_ExtConWakeU .GetInternalValue(): return GpioPadName_ExtConWakeU; case DeviceCode_ExtConWakeS .GetInternalValue(): return GpioPadName_ExtConWakeS; case DeviceCode_PmuIrq .GetInternalValue(): return GpioPadName_PmuIrq; case DeviceCode_ExtUart2Cts .GetInternalValue(): return GpioPadName_ExtUart2Cts; case DeviceCode_ExtUart3Cts .GetInternalValue(): return GpioPadName_ExtUart3Cts; case DeviceCode_5VStepDownEn .GetInternalValue(): return GpioPadName_5VStepDownEn; case DeviceCode_UsbSwitchB2Oc .GetInternalValue(): return GpioPadName_UsbSwitchB2Oc; case DeviceCode_5VStepDownPg .GetInternalValue(): return GpioPadName_5VStepDownPg; case DeviceCode_UsbSwitchAEn .GetInternalValue(): return GpioPadName_UsbSwitchAEn; case DeviceCode_UsbSwitchAFlag .GetInternalValue(): return GpioPadName_UsbSwitchAFlag; case DeviceCode_UsbSwitchB3Oc .GetInternalValue(): return GpioPadName_UsbSwitchB3Oc; case DeviceCode_UsbSwitchB3En .GetInternalValue(): return GpioPadName_UsbSwitchB3En; case DeviceCode_UsbSwitchB2En .GetInternalValue(): return GpioPadName_UsbSwitchB2En; case DeviceCode_Hdmi5VEn .GetInternalValue(): return GpioPadName_Hdmi5VEn; case DeviceCode_UsbSwitchB1En .GetInternalValue(): return GpioPadName_UsbSwitchB1En; case DeviceCode_HdmiPdTrEn .GetInternalValue(): return GpioPadName_HdmiPdTrEn; case DeviceCode_FanEn .GetInternalValue(): return GpioPadName_FanEn; case DeviceCode_UsbSwitchB1Oc .GetInternalValue(): return GpioPadName_UsbSwitchB1Oc; case DeviceCode_PwmFan .GetInternalValue(): return GpioPadName_PwmFan; case DeviceCode_HdmiHpd .GetInternalValue(): return GpioPadName_HdmiHpd; case DeviceCode_Max77812Irq .GetInternalValue(): return GpioPadName_Max77812Irq; case DeviceCode_Debug0 .GetInternalValue(): return GpioPadName_Debug0; case DeviceCode_Debug1 .GetInternalValue(): return GpioPadName_Debug1; case DeviceCode_Debug2 .GetInternalValue(): return GpioPadName_Debug2; case DeviceCode_Debug3 .GetInternalValue(): return GpioPadName_Debug3; case DeviceCode_NfcIrq .GetInternalValue(): return GpioPadName_NfcIrq; case DeviceCode_NfcRst .GetInternalValue(): return GpioPadName_NfcRst; case DeviceCode_McuIrq .GetInternalValue(): return GpioPadName_McuIrq; case DeviceCode_McuBoot .GetInternalValue(): return GpioPadName_McuBoot; case DeviceCode_McuRst .GetInternalValue(): return GpioPadName_McuRst; case DeviceCode_Vdd5V3En .GetInternalValue(): return GpioPadName_Vdd5V3En; case DeviceCode_McuPor .GetInternalValue(): return GpioPadName_McuPor; case DeviceCode_LcdGpio1 .GetInternalValue(): return GpioPadName_LcdGpio1; case DeviceCode_NfcEn .GetInternalValue(): return GpioPadName_NfcEn; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline DeviceCode ConvertToDeviceCode(GpioPadName gpn) { switch (gpn) { case GpioPadName_CodecLdoEnTemp: return DeviceCode_CodecLdoEnTemp; case GpioPadName_PowSdEn: return DeviceCode_PowSdEn; case GpioPadName_BtRst: return DeviceCode_BtRst; case GpioPadName_RamCode3: return DeviceCode_RamCode3; case GpioPadName_GameCardReset: return DeviceCode_GameCardReset; case GpioPadName_CodecAlert: return DeviceCode_CodecAlert; case GpioPadName_PowGc: return DeviceCode_PowGc; case GpioPadName_DebugControllerDet: return DeviceCode_DebugControllerDet; case GpioPadName_BattChgStatus: return DeviceCode_BattChgStatus; case GpioPadName_BattChgEnableN: return DeviceCode_BattChgEnableN; case GpioPadName_FanTach: return DeviceCode_FanTach; case GpioPadName_ExtconDetS: return DeviceCode_ExtconDetS; case GpioPadName_Vdd50AEn: return DeviceCode_Vdd50AEn; case GpioPadName_SdevCoaxSel1: return DeviceCode_SdevCoaxSel1; case GpioPadName_GameCardCd: return DeviceCode_GameCardCd; case GpioPadName_ProdType0: return DeviceCode_ProdType0; case GpioPadName_ProdType1: return DeviceCode_ProdType1; case GpioPadName_ProdType2: return DeviceCode_ProdType2; case GpioPadName_ProdType3: return DeviceCode_ProdType3; case GpioPadName_TempAlert: return DeviceCode_TempAlert; case GpioPadName_CodecHpDetIrq: return DeviceCode_CodecHpDetIrq; case GpioPadName_MotionInt: return DeviceCode_MotionInt; case GpioPadName_TpIrq: return DeviceCode_TpIrq; case GpioPadName_ButtonSleep2: return DeviceCode_ButtonSleep2; case GpioPadName_ButtonVolUp: return DeviceCode_ButtonVolUp; case GpioPadName_ButtonVolDn: return DeviceCode_ButtonVolDn; case GpioPadName_BattMgicIrq: return DeviceCode_BattMgicIrq; case GpioPadName_RecoveryKey: return DeviceCode_RecoveryKey; case GpioPadName_PowLcdBlEn: return DeviceCode_PowLcdBlEn; case GpioPadName_LcdReset: return DeviceCode_LcdReset; case GpioPadName_PdVconnEn: return DeviceCode_PdVconnEn; case GpioPadName_PdRstN: return DeviceCode_PdRstN; case GpioPadName_Bq24190Irq: return DeviceCode_Bq24190Irq; case GpioPadName_SdevCoaxSel0: return DeviceCode_SdevCoaxSel0; case GpioPadName_SdWp: return DeviceCode_SdWp; case GpioPadName_TpReset: return DeviceCode_TpReset; case GpioPadName_BtGpio2: return DeviceCode_BtGpio2; case GpioPadName_BtGpio3: return DeviceCode_BtGpio3; case GpioPadName_BtGpio4: return DeviceCode_BtGpio4; case GpioPadName_CradleIrq: return DeviceCode_CradleIrq; case GpioPadName_PowVcpuInt: return DeviceCode_PowVcpuInt; case GpioPadName_Max77621GpuInt: return DeviceCode_Max77621GpuInt; case GpioPadName_ExtconChgU: return DeviceCode_ExtconChgU; case GpioPadName_ExtconChgS: return DeviceCode_ExtconChgS; case GpioPadName_WifiRfDisable: return DeviceCode_WifiRfDisable; case GpioPadName_WifiReset: return DeviceCode_WifiReset; case GpioPadName_ApWakeBt: return DeviceCode_ApWakeBt; case GpioPadName_BtWakeAp: return DeviceCode_BtWakeAp; case GpioPadName_BtGpio5: return DeviceCode_BtGpio5; case GpioPadName_PowLcdVddPEn: return DeviceCode_PowLcdVddPEn; case GpioPadName_PowLcdVddNEn: return DeviceCode_PowLcdVddNEn; case GpioPadName_ExtconDetU: return DeviceCode_ExtconDetU; case GpioPadName_RamCode2: return DeviceCode_RamCode2; case GpioPadName_Vdd50BEn: return DeviceCode_Vdd50BEn; case GpioPadName_WifiWakeHost: return DeviceCode_WifiWakeHost; case GpioPadName_SdCd: return DeviceCode_SdCd; case GpioPadName_OtgFet1ForSdev: return DeviceCode_OtgFet1ForSdev; case GpioPadName_OtgFet2ForSdev: return DeviceCode_OtgFet2ForSdev; case GpioPadName_ExtConWakeU: return DeviceCode_ExtConWakeU; case GpioPadName_ExtConWakeS: return DeviceCode_ExtConWakeS; case GpioPadName_PmuIrq: return DeviceCode_PmuIrq; case GpioPadName_ExtUart2Cts: return DeviceCode_ExtUart2Cts; case GpioPadName_ExtUart3Cts: return DeviceCode_ExtUart3Cts; case GpioPadName_5VStepDownEn: return DeviceCode_5VStepDownEn; case GpioPadName_UsbSwitchB2Oc: return DeviceCode_UsbSwitchB2Oc; case GpioPadName_5VStepDownPg: return DeviceCode_5VStepDownPg; case GpioPadName_UsbSwitchAEn: return DeviceCode_UsbSwitchAEn; case GpioPadName_UsbSwitchAFlag: return DeviceCode_UsbSwitchAFlag; case GpioPadName_UsbSwitchB3Oc: return DeviceCode_UsbSwitchB3Oc; case GpioPadName_UsbSwitchB3En: return DeviceCode_UsbSwitchB3En; case GpioPadName_UsbSwitchB2En: return DeviceCode_UsbSwitchB2En; case GpioPadName_Hdmi5VEn: return DeviceCode_Hdmi5VEn; case GpioPadName_UsbSwitchB1En: return DeviceCode_UsbSwitchB1En; case GpioPadName_HdmiPdTrEn: return DeviceCode_HdmiPdTrEn; case GpioPadName_FanEn: return DeviceCode_FanEn; case GpioPadName_UsbSwitchB1Oc: return DeviceCode_UsbSwitchB1Oc; case GpioPadName_PwmFan: return DeviceCode_PwmFan; case GpioPadName_HdmiHpd: return DeviceCode_HdmiHpd; case GpioPadName_Max77812Irq: return DeviceCode_Max77812Irq; case GpioPadName_Debug0: return DeviceCode_Debug0; case GpioPadName_Debug1: return DeviceCode_Debug1; case GpioPadName_Debug2: return DeviceCode_Debug2; case GpioPadName_Debug3: return DeviceCode_Debug3; case GpioPadName_NfcIrq: return DeviceCode_NfcIrq; case GpioPadName_NfcRst: return DeviceCode_NfcRst; case GpioPadName_McuIrq: return DeviceCode_McuIrq; case GpioPadName_McuBoot: return DeviceCode_McuBoot; case GpioPadName_McuRst: return DeviceCode_McuRst; case GpioPadName_Vdd5V3En: return DeviceCode_Vdd5V3En; case GpioPadName_McuPor: return DeviceCode_McuPor; case GpioPadName_LcdGpio1: return DeviceCode_LcdGpio1; case GpioPadName_NfcEn: return DeviceCode_NfcEn; AMS_UNREACHABLE_DEFAULT_CASE(); } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> namespace ams::gpio { enum GpioPadName : u32 { GpioPadName_EnableSdCardPower = 2, }; constexpr inline const DeviceCode DeviceCode_EnableSdCardPower = 0x3C000001; constexpr inline GpioPadName ConvertToGpioPadName(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_EnableSdCardPower.GetInternalValue(): return GpioPadName_EnableSdCardPower; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline DeviceCode ConvertToDeviceCode(GpioPadName gpn) { switch (gpn) { case GpioPadName_EnableSdCardPower: return DeviceCode_EnableSdCardPower; AMS_UNREACHABLE_DEFAULT_CASE(); } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp> #else #include <stratosphere/gpio/gpio_pad_name.generic.hpp> #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::gpio { enum InterruptMode : u32 { InterruptMode_LowLevel = 0, InterruptMode_HighLevel = 1, InterruptMode_RisingEdge = 2, InterruptMode_FallingEdge = 3, InterruptMode_AnyEdge = 4, }; enum Direction : u32 { Direction_Input = 0, Direction_Output = 1, }; enum GpioValue : u32 { GpioValue_Low = 0, GpioValue_High = 1, }; enum InterruptStatus : u32 { InterruptStatus_Inactive = 0, InterruptStatus_Active = 1, }; enum WakePinDebugMode { WakePinDebugMode_AutoImmediateWake = 1, WakePinDebugMode_NoWake = 2, }; using WakeBitFlag = util::BitFlagSet<128>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/sf/gpio_sf_i_manager.hpp> namespace ams::gpio::server { ams::sf::SharedPointer<gpio::sf::IManager> GetServiceObject(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/gpio_select_pad_name.hpp> #include <stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp> #define AMS_GPIO_I_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenSessionForDev, (ams::sf::Out<ams::sf::SharedPointer<gpio::sf::IPadSession>> out, s32 pad_descriptor), (out, pad_descriptor) ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, OpenSession, (ams::sf::Out<ams::sf::SharedPointer<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name), (out, pad_name) ) \ AMS_SF_METHOD_INFO(C, H, 2, Result, OpenSessionForTest, (ams::sf::Out<ams::sf::SharedPointer<gpio::sf::IPadSession>> out, gpio::GpioPadName pad_name), (out, pad_name) ) \ AMS_SF_METHOD_INFO(C, H, 3, Result, IsWakeEventActive, (ams::sf::Out<bool> out, gpio::GpioPadName pad_name), (out, pad_name), hos::Version_Min, hos::Version_6_2_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetWakeEventActiveFlagSet, (ams::sf::Out<gpio::WakeBitFlag> out), (out), hos::Version_Min, hos::Version_6_2_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, SetWakeEventActiveFlagSetForDebug, (gpio::GpioPadName pad_name, bool is_enabled), (pad_name, is_enabled), hos::Version_Min, hos::Version_6_2_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, SetWakePinDebugMode, (s32 mode), (mode) ) \ AMS_SF_METHOD_INFO(C, H, 7, Result, OpenSession2, (ams::sf::Out<ams::sf::SharedPointer<gpio::sf::IPadSession>> out, DeviceCode device_code, ddsf::AccessMode access_mode), (out, device_code, access_mode), hos::Version_5_0_0 ) \ AMS_SF_METHOD_INFO(C, H, 8, Result, IsWakeEventActive2, (ams::sf::Out<bool> out, DeviceCode device_code), (out, device_code), hos::Version_5_0_0 ) \ AMS_SF_METHOD_INFO(C, H, 9, Result, SetWakeEventActiveFlagSetForDebug2, (DeviceCode device_code, bool is_enabled), (device_code, is_enabled), hos::Version_5_0_0 ) \ AMS_SF_METHOD_INFO(C, H, 10, Result, SetRetryValues, (u32 arg0, u32 arg1), (arg0, arg1), hos::Version_6_0_0 ) AMS_SF_DEFINE_INTERFACE(ams::gpio::sf, IManager, AMS_GPIO_I_MANAGER_INTERFACE_INFO, 0xD219501E) ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/gpio/gpio_types.hpp> #define AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetDirection, (gpio::Direction direction), (direction) ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetDirection, (ams::sf::Out<gpio::Direction> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetInterruptMode, (gpio::InterruptMode mode), (mode) ) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetInterruptMode, (ams::sf::Out<gpio::InterruptMode> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 4, Result, SetInterruptEnable, (bool enable), (enable) ) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetInterruptEnable, (ams::sf::Out<bool> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetInterruptStatus, (ams::sf::Out<gpio::InterruptStatus> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 7, Result, ClearInterruptStatus, (), () ) \ AMS_SF_METHOD_INFO(C, H, 8, Result, SetValue, (gpio::GpioValue value), (value) ) \ AMS_SF_METHOD_INFO(C, H, 9, Result, GetValue, (ams::sf::Out<gpio::GpioValue> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 10, Result, BindInterrupt, (ams::sf::OutCopyHandle out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 11, Result, UnbindInterrupt, (), () ) \ AMS_SF_METHOD_INFO(C, H, 12, Result, SetDebounceEnabled, (bool enable), (enable) ) \ AMS_SF_METHOD_INFO(C, H, 13, Result, GetDebounceEnabled, (ams::sf::Out<bool> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 14, Result, SetDebounceTime, (s32 ms), (ms) ) \ AMS_SF_METHOD_INFO(C, H, 15, Result, GetDebounceTime, (ams::sf::Out<s32> out), (out) ) \ AMS_SF_METHOD_INFO(C, H, 16, Result, SetValueForSleepState, (gpio::GpioValue value), (value), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 16, Result, GetValueForSleepState, (ams::sf::Out<gpio::GpioValue> out), (out), hos::Version_6_0_0) AMS_SF_DEFINE_INTERFACE(ams::gpio::sf, IPadSession, AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO, 0x7448A8A7) ================================================ FILE: libraries/libstratosphere/include/stratosphere/gpio.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/gpio/gpio_types.hpp> #include <stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp> #include <stratosphere/gpio/sf/gpio_sf_i_manager.hpp> #include <stratosphere/gpio/gpio_api.hpp> #include <stratosphere/gpio/gpio_pad_api.hpp> #include <stratosphere/gpio/driver/gpio_select_driver_api.hpp> #include <stratosphere/gpio/driver/gpio_pad_accessor.hpp> #include <stratosphere/gpio/driver/impl/gpio_pad_session_impl.hpp> #include <stratosphere/gpio/server/gpio_server_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/hid/hid_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::hid { /* Key API. */ Result GetKeysHeld(u64 *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/hid.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/hid/hid_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/hos/hos_stratosphere_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/hos/hos_types.hpp> namespace ams::hos { void InitializeForStratosphere(); void InitializeForStratosphereDebug(hos::Version debug_version); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/hos/hos_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::hos { enum Version : u32 { Version_Min = ::ams::TargetFirmware_Min, Version_1_0_0 = ::ams::TargetFirmware_1_0_0, Version_2_0_0 = ::ams::TargetFirmware_2_0_0, Version_2_1_0 = ::ams::TargetFirmware_2_1_0, Version_2_2_0 = ::ams::TargetFirmware_2_2_0, Version_2_3_0 = ::ams::TargetFirmware_2_3_0, Version_3_0_0 = ::ams::TargetFirmware_3_0_0, Version_3_0_1 = ::ams::TargetFirmware_3_0_1, Version_3_0_2 = ::ams::TargetFirmware_3_0_2, Version_4_0_0 = ::ams::TargetFirmware_4_0_0, Version_4_0_1 = ::ams::TargetFirmware_4_0_1, Version_4_1_0 = ::ams::TargetFirmware_4_1_0, Version_5_0_0 = ::ams::TargetFirmware_5_0_0, Version_5_0_1 = ::ams::TargetFirmware_5_0_1, Version_5_0_2 = ::ams::TargetFirmware_5_0_2, Version_5_1_0 = ::ams::TargetFirmware_5_1_0, Version_6_0_0 = ::ams::TargetFirmware_6_0_0, Version_6_0_1 = ::ams::TargetFirmware_6_0_1, Version_6_1_0 = ::ams::TargetFirmware_6_1_0, Version_6_2_0 = ::ams::TargetFirmware_6_2_0, Version_7_0_0 = ::ams::TargetFirmware_7_0_0, Version_7_0_1 = ::ams::TargetFirmware_7_0_1, Version_8_0_0 = ::ams::TargetFirmware_8_0_0, Version_8_0_1 = ::ams::TargetFirmware_8_0_1, Version_8_1_0 = ::ams::TargetFirmware_8_1_0, Version_8_1_1 = ::ams::TargetFirmware_8_1_1, Version_9_0_0 = ::ams::TargetFirmware_9_0_0, Version_9_0_1 = ::ams::TargetFirmware_9_0_1, Version_9_1_0 = ::ams::TargetFirmware_9_1_0, Version_9_2_0 = ::ams::TargetFirmware_9_2_0, Version_10_0_0 = ::ams::TargetFirmware_10_0_0, Version_10_0_1 = ::ams::TargetFirmware_10_0_1, Version_10_0_2 = ::ams::TargetFirmware_10_0_2, Version_10_0_3 = ::ams::TargetFirmware_10_0_3, Version_10_0_4 = ::ams::TargetFirmware_10_0_4, Version_10_1_0 = ::ams::TargetFirmware_10_1_0, Version_10_2_0 = ::ams::TargetFirmware_10_2_0, Version_11_0_0 = ::ams::TargetFirmware_11_0_0, Version_11_0_1 = ::ams::TargetFirmware_11_0_1, Version_12_0_0 = ::ams::TargetFirmware_12_0_0, Version_12_0_1 = ::ams::TargetFirmware_12_0_1, Version_12_0_2 = ::ams::TargetFirmware_12_0_2, Version_12_0_3 = ::ams::TargetFirmware_12_0_3, Version_12_1_0 = ::ams::TargetFirmware_12_1_0, Version_13_0_0 = ::ams::TargetFirmware_13_0_0, Version_13_1_0 = ::ams::TargetFirmware_13_1_0, Version_13_2_0 = ::ams::TargetFirmware_13_2_0, Version_13_2_1 = ::ams::TargetFirmware_13_2_1, Version_14_0_0 = ::ams::TargetFirmware_14_0_0, Version_14_1_0 = ::ams::TargetFirmware_14_1_0, Version_14_1_1 = ::ams::TargetFirmware_14_1_1, Version_14_1_2 = ::ams::TargetFirmware_14_1_2, Version_15_0_0 = ::ams::TargetFirmware_15_0_0, Version_15_0_1 = ::ams::TargetFirmware_15_0_1, Version_16_0_0 = ::ams::TargetFirmware_16_0_0, Version_16_0_1 = ::ams::TargetFirmware_16_0_1, Version_16_0_2 = ::ams::TargetFirmware_16_0_2, Version_16_0_3 = ::ams::TargetFirmware_16_0_3, Version_16_1_0 = ::ams::TargetFirmware_16_1_0, Version_17_0_0 = ::ams::TargetFirmware_17_0_0, Version_17_0_1 = ::ams::TargetFirmware_17_0_1, Version_18_0_0 = ::ams::TargetFirmware_18_0_0, Version_18_0_1 = ::ams::TargetFirmware_18_0_1, Version_18_1_0 = ::ams::TargetFirmware_18_1_0, Version_19_0_0 = ::ams::TargetFirmware_19_0_0, Version_19_0_1 = ::ams::TargetFirmware_19_0_1, Version_20_0_0 = ::ams::TargetFirmware_20_0_0, Version_20_0_1 = ::ams::TargetFirmware_20_0_1, Version_20_1_0 = ::ams::TargetFirmware_20_1_0, Version_20_1_1 = ::ams::TargetFirmware_20_1_1, Version_20_1_5 = ::ams::TargetFirmware_20_1_5, Version_20_2_0 = ::ams::TargetFirmware_20_2_0, Version_20_3_0 = ::ams::TargetFirmware_20_3_0, Version_20_4_0 = ::ams::TargetFirmware_20_4_0, Version_20_5_0 = ::ams::TargetFirmware_20_5_0, Version_21_0_0 = ::ams::TargetFirmware_21_0_0, Version_21_0_1 = ::ams::TargetFirmware_21_0_1, Version_21_1_0 = ::ams::TargetFirmware_21_1_0, Version_21_2_0 = ::ams::TargetFirmware_21_2_0, Version_Current = ::ams::TargetFirmware_Current, Version_Max = ::ams::TargetFirmware_Max, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/hos/hos_version_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/hos/hos_types.hpp> namespace ams::hos { ::ams::hos::Version GetVersion(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/hos.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/hos/hos_types.hpp> #include <stratosphere/hos/hos_version_api.hpp> #include <stratosphere/hos/hos_stratosphere_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/server/htc_htcmisc_channel_ids.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_channel_types.hpp> namespace ams::htc::server { constexpr inline htclow::ChannelId HtcmiscClientChannelId = 1; constexpr inline htclow::ChannelId HtcmiscServerChannelId = 2; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/server/htc_htcmisc_hipc_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htclow { class HtclowManager; } namespace ams::htc::server { void InitializeHtcmiscServer(htclow::HtclowManager *htclow_manager); void FinalizeHtcmiscServer(); void LoopHtcmiscServer(); void RequestStopHtcmiscServer(); class HtcmiscImpl; HtcmiscImpl *GetHtcmiscImpl(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/tenv/htc_tenv.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htc::tenv { void Initialize(AllocateFunction allocate, DeallocateFunction deallocate); Result RegisterDefinitionFilePath(os::ProcessId process_id, const char *path, size_t size); void UnregisterDefinitionFilePath(os::ProcessId process_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/tenv/htc_tenv_i_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/htc/tenv/htc_tenv_types.hpp> #define AMS_HTC_TENV_I_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetVariable, (sf::Out<s64> out_size, const sf::OutBuffer &out_buffer, const htc::tenv::VariableName &name), (out_size, out_buffer, name)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetVariableLength, (sf::Out<s64> out_size,const htc::tenv::VariableName &name), (out_size, name)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, WaitUntilVariableAvailable, (s64 timeout_ms), (timeout_ms)) AMS_SF_DEFINE_INTERFACE(ams::htc::tenv, IService, AMS_HTC_TENV_I_SERVICE_INTERFACE_INFO, 0x041F65C5) ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/tenv/htc_tenv_i_service_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/htc/tenv/htc_tenv_i_service.hpp> #define AMS_HTC_TENV_I_SERVICE_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetServiceInterface, (sf::Out<sf::SharedPointer<htc::tenv::IService>> out, const sf::ClientProcessId &process_id), (out, process_id)) AMS_SF_DEFINE_INTERFACE(ams::htc::tenv, IServiceManager, AMS_HTC_TENV_I_SERVICE_MANAGER_INTERFACE_INFO, 0x38649D88) ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/tenv/htc_tenv_service_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/htc/tenv/htc_tenv_i_service_manager.hpp> namespace ams::htc::tenv { constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("htc:tenv"); class ServiceManager { public: Result GetServiceInterface(sf::Out<sf::SharedPointer<htc::tenv::IService>> out, const sf::ClientProcessId &process_id); }; static_assert(htc::tenv::IsIServiceManager<ServiceManager>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc/tenv/htc_tenv_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htc::tenv { struct VariableName { char str[0x40]; }; constexpr inline auto PathLengthMax = 0x300; struct alignas(4) Path { char str[PathLengthMax]; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/htc/server/htc_htcmisc_hipc_server.hpp> #include <stratosphere/htc/server/htc_htcmisc_channel_ids.hpp> #include <stratosphere/htc/tenv/htc_tenv_types.hpp> #include <stratosphere/htc/tenv/htc_tenv.hpp> #include <stratosphere/htc/tenv/htc_tenv_service_manager.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcfs/htcfs_hipc_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htclow { class HtclowManager; } namespace ams::htcfs { void Initialize(htclow::HtclowManager *htclow_manager); void RegisterHipcServer(); void LoopHipcServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcfs.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/htcfs/htcfs_hipc_server.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow/htclow_channel_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_module_types.hpp> namespace ams::htclow { using ChannelId = u16; struct ChannelType { bool _is_initialized; ModuleId _module_id; ChannelId _channel_id; }; enum ChannelState { ChannelState_Connectable = 0, ChannelState_Unconnectable = 1, ChannelState_Connected = 2, ChannelState_Disconnected = 3, }; struct ChannelConfig { bool flow_control_enabled; bool handshake_enabled; u64 initial_counter_max_data; size_t max_packet_size; }; constexpr bool IsStateTransitionAllowed(ChannelState from, ChannelState to) { switch (from) { case ChannelState_Connectable: return to == ChannelState_Unconnectable || to == ChannelState_Connected || to == ChannelState_Disconnected; case ChannelState_Unconnectable: return to == ChannelState_Connectable || to == ChannelState_Disconnected; case ChannelState_Connected: return to == ChannelState_Disconnected; case ChannelState_Disconnected: return to == ChannelState_Disconnected; AMS_UNREACHABLE_DEFAULT_CASE(); } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow/htclow_manager_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_types.hpp> namespace ams::htclow { class HtclowManager; namespace HtclowManagerHolder { void AddReference(); void Release(); HtclowManager *GetHtclowManager(); void SetDefaultDriver(htclow::impl::DriverType driver_type); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow/htclow_module_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_module_types.hpp> namespace ams::htclow { enum class ModuleId : u8 { Unknown = 0, Htcfs = 1, Htcmisc = 3, Htcs = 4, }; struct ModuleType { bool _is_initialized; ModuleId _id; }; constexpr void InitializeModule(ModuleType *out, ModuleId id) { *out = { ._is_initialized = true, ._id = id, }; } constexpr void FinalizeModule(ModuleType *out) { *out = { ._is_initialized = false, ._id = ModuleId::Unknown, }; } class Module final { private: ModuleType m_impl; public: constexpr explicit Module(ModuleId id) : m_impl() { InitializeModule(std::addressof(m_impl), id); } constexpr ~Module() { FinalizeModule(std::addressof(m_impl)); } ModuleType *GetBase() { return std::addressof(m_impl); } const ModuleType *GetBase() const { return std::addressof(m_impl); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow/htclow_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htclow { namespace impl { enum class DriverType { Unknown = 0, Debug = 1, Socket = 2, Usb = 3, HostBridge = 4, PlainChannel = 5, }; } constexpr inline s16 ProtocolVersion = 5; enum ReceiveOption { ReceiveOption_NonBlocking = 0, ReceiveOption_ReceiveAnyData = 1, ReceiveOption_ReceiveAllData = 2, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow/impl/htclow_internal_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_channel_types.hpp> namespace ams::htclow::impl { struct ChannelInternalType { ChannelId channel_id; s8 reserved; ModuleId module_id; }; static_assert(sizeof(ChannelInternalType) == 4); constexpr ALWAYS_INLINE ChannelInternalType ConvertChannelType(ChannelType channel) { return { .channel_id = channel._channel_id, .reserved = 0, .module_id = channel._module_id, }; } constexpr ALWAYS_INLINE bool operator==(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return lhs.module_id == rhs.module_id && lhs.reserved == rhs.reserved && lhs.channel_id == rhs.channel_id; } constexpr ALWAYS_INLINE bool operator!=(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return !(lhs == rhs); } constexpr ALWAYS_INLINE bool operator<(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return std::tie(lhs.module_id, lhs.reserved, lhs.channel_id) < std::tie(rhs.module_id, rhs.reserved, rhs.channel_id); } constexpr ALWAYS_INLINE bool operator>(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return rhs < lhs; } constexpr ALWAYS_INLINE bool operator<=(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return !(lhs > rhs); } constexpr ALWAYS_INLINE bool operator>=(const ChannelInternalType &lhs, const ChannelInternalType &rhs) { return !(lhs < rhs); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htclow.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/htclow/htclow_types.hpp> #include <stratosphere/htclow/impl/htclow_internal_types.hpp> #include <stratosphere/htclow/htclow_manager_holder.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/htcs_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htcs/htcs_types.hpp> namespace ams::htcs { bool IsInitialized(); size_t GetWorkingMemorySize(int max_socket_count); void Initialize(AllocateFunction allocate, DeallocateFunction deallocate, int num_sessions = SessionCountMax); void Initialize(void *buffer, size_t buffer_size); void InitializeForDisableDisconnectionEmulation(AllocateFunction allocate, DeallocateFunction deallocate, int num_sessions = SessionCountMax); void InitializeForDisableDisconnectionEmulation(void *buffer, size_t buffer_size); void InitializeForSystem(void *buffer, size_t buffer_size, int num_sessions); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/htcs_socket.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htcs/htcs_types.hpp> namespace ams::htcs { const HtcsPeerName GetPeerNameAny(); const HtcsPeerName GetDefaultHostName(); s32 GetLastError(); s32 Socket(); s32 Close(s32 desc); s32 Connect(s32 desc, const SockAddrHtcs *address); s32 Bind(s32 desc, const SockAddrHtcs *address); s32 Listen(s32 desc, s32 backlog_count); s32 Accept(s32 desc, SockAddrHtcs *address); s32 Shutdown(s32 desc, s32 how); s32 Fcntl(s32 desc, s32 command, s32 value); s32 Select(s32 count, FdSet *read, FdSet *write, FdSet *exception, TimeVal *timeout); ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, s32 flags); ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags); void FdSetZero(FdSet *set); void FdSetSet(s32 fd, FdSet *set); void FdSetClr(s32 fd, FdSet *set); bool FdSetIsSet(s32 fd, const FdSet *set); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/htcs_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htcs { using ssize_t = intptr_t; using AddressFamilyType = u16; constexpr inline int PeerNameBufferLength = 32; constexpr inline int PortNameBufferLength = 32; constexpr inline int SessionCountMax = 0x10; constexpr inline int SocketCountMax = 40; constexpr inline int FdSetSize = SocketCountMax; struct HtcsPeerName { char name[PeerNameBufferLength]; }; struct HtcsPortName { char name[PortNameBufferLength]; }; struct SockAddrHtcs { AddressFamilyType family; HtcsPeerName peer_name; HtcsPortName port_name; }; struct TimeVal { s64 tv_sec; s64 tv_usec; }; struct FdSet { int fds[FdSetSize]; }; enum SocketError { HTCS_ENONE = 0, HTCS_EACCES = 2, HTCS_EADDRINUSE = 3, HTCS_EADDRNOTAVAIL = 4, HTCS_EAGAIN = 6, HTCS_EALREADY = 7, HTCS_EBADF = 8, HTCS_EBUSY = 10, HTCS_ECONNABORTED = 13, HTCS_ECONNREFUSED = 14, HTCS_ECONNRESET = 15, HTCS_EDESTADDRREQ = 17, HTCS_EFAULT = 21, HTCS_EINPROGRESS = 26, HTCS_EINTR = 27, HTCS_EINVAL = 28, HTCS_EIO = 29, HTCS_EISCONN = 30, HTCS_EMFILE = 33, HTCS_EMSGSIZE = 35, HTCS_ENETDOWN = 38, HTCS_ENETRESET = 39, HTCS_ENOBUFS = 42, HTCS_ENOMEM = 49, HTCS_ENOTCONN = 56, HTCS_ETIMEDOUT = 76, HTCS_EUNKNOWN = 79, HTCS_EWOULDBLOCK = HTCS_EAGAIN, }; enum MessageFlag { HTCS_MSG_PEEK = 1, HTCS_MSG_WAITALL = 2, }; enum ShutdownType { HTCS_SHUT_RD = 0, HTCS_SHUT_WR = 1, HTCS_SHUT_RDWR = 2, }; enum FcntlOperation { HTCS_F_GETFL = 3, HTCS_F_SETFL = 4, }; enum FcntlFlag { HTCS_O_NONBLOCK = 4, }; enum AddressFamily { HTCS_AF_HTCS = 0, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/impl/htcs_channel_ids.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htclow/htclow_channel_types.hpp> namespace ams::htcs::impl { constexpr inline htclow::ChannelId HtcsClientChannelId = 0; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/impl/htcs_manager_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htcs/htcs_types.hpp> namespace ams::htcs::impl { class HtcsManager; namespace HtcsManagerHolder { void AddReference(); void Release(); HtcsManager *GetHtcsManager(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs/server/htcs_hipc_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::htcs::server { void Initialize(); void RegisterHipcServer(); void LoopHipcServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/htcs.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/htcs/htcs_types.hpp> #include <stratosphere/htcs/htcs_api.hpp> #include <stratosphere/htcs/htcs_socket.hpp> #include <stratosphere/htcs/impl/htcs_manager_holder.hpp> #include <stratosphere/htcs/impl/htcs_channel_ids.hpp> #include <stratosphere/htcs/server/htcs_hipc_server.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/board/nintendo/nx/i2c_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c::driver::board::nintendo::nx { void Initialize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_bus_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c::driver { namespace impl { constexpr inline size_t I2cSessionSize = 0x60; constexpr inline size_t I2cSessionAlign = 8; struct alignas(I2cSessionAlign) I2cSessionImplPadded; } struct I2cSession { util::TypedStorage<impl::I2cSessionImplPadded, impl::I2cSessionSize, impl::I2cSessionAlign> _impl; }; Result OpenSession(I2cSession *out, DeviceCode device_code); void CloseSession(I2cSession &session); Result Send(I2cSession &session, const void *src, size_t src_size, TransactionOption option); Result Receive(void *dst, size_t dst_size, I2cSession &session, TransactionOption option); Result ExecuteCommandList(void *dst, size_t dst_size, I2cSession &session, const void *src, size_t src_size); Result SetRetryPolicy(I2cSession &session, int max_retry_count, int retry_interval_us); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_driver_client_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c::driver { void Initialize(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_driver_service_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/driver/i2c_i2c_device_property.hpp> #include <stratosphere/i2c/driver/i2c_i_i2c_driver.hpp> namespace ams::i2c::driver { void RegisterDriver(II2cDriver *driver); void UnregisterDriver(II2cDriver *driver); Result RegisterDeviceCode(DeviceCode device_code, I2cDeviceProperty *device); bool UnregisterDeviceCode(DeviceCode device_code); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i2c_device_property.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/ddsf.hpp> namespace ams::i2c::driver { class I2cDeviceProperty : public ::ams::ddsf::IDevice { NON_COPYABLE(I2cDeviceProperty); NON_MOVEABLE(I2cDeviceProperty); AMS_DDSF_CASTABLE_TRAITS(ams::i2c::driver::I2cDeviceProperty, ::ams::ddsf::IDevice); private: u16 m_address; AddressingMode m_addressing_mode; util::IntrusiveListNode m_device_property_list_node; public: using DevicePropertyListTraits = util::IntrusiveListMemberTraits<&I2cDeviceProperty::m_device_property_list_node>; using DevicePropertyList = typename DevicePropertyListTraits::ListType; friend class util::IntrusiveList<I2cDeviceProperty, util::IntrusiveListMemberTraits<&I2cDeviceProperty::m_device_property_list_node>>; public: I2cDeviceProperty() : IDevice(false), m_address(0), m_addressing_mode(AddressingMode_SevenBit), m_device_property_list_node() { /* ... */ } I2cDeviceProperty(u16 addr, AddressingMode m) : IDevice(false), m_address(addr), m_addressing_mode(m), m_device_property_list_node() { /* ... */ } virtual ~I2cDeviceProperty() { /* ... */ } u16 GetAddress() const { return m_address; } AddressingMode GetAddressingMode() const { return m_addressing_mode; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_i_i2c_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/ddsf.hpp> namespace ams::i2c::driver { class I2cDeviceProperty; class II2cDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(II2cDriver); NON_MOVEABLE(II2cDriver); AMS_DDSF_CASTABLE_TRAITS(ams::i2c::driver::II2cDriver, ::ams::ddsf::IDriver); public: II2cDriver() : IDriver() { /* ... */ } virtual ~II2cDriver() { /* ... */ } virtual void InitializeDriver() = 0; virtual void FinalizeDriver() = 0; virtual Result InitializeDevice(I2cDeviceProperty *device) = 0; virtual void FinalizeDevice(I2cDeviceProperty *device) = 0; virtual Result Send(I2cDeviceProperty *device, const void *src, size_t src_size, TransactionOption option) = 0; virtual Result Receive(void *dst, size_t dst_size, I2cDeviceProperty *device, TransactionOption option) = 0; virtual os::SdkMutex &GetTransactionOrderMutex() = 0; virtual void SuspendBus() = 0; virtual void SuspendPowerBus() = 0; virtual void ResumeBus() = 0; virtual void ResumePowerBus() = 0; virtual const DeviceCode &GetDeviceCode() const = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/i2c_select_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/driver/i2c_i_i2c_driver.hpp> #include <stratosphere/i2c/driver/i2c_i2c_device_property.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/i2c/driver/board/nintendo/nx/i2c_driver_api.hpp> namespace ams::i2c::driver::board { using namespace ams::i2c::driver::board::nintendo::nx; } #else // TODO: #error "Unknown board for ams::i2c::driver::" #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/driver/impl/i2c_i2c_session_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/driver/i2c_bus_api.hpp> #include <stratosphere/ddsf.hpp> namespace ams::i2c::driver { class I2cDeviceProperty; } namespace ams::i2c::driver::impl { class I2cSessionImpl : public ::ams::ddsf::ISession { NON_COPYABLE(I2cSessionImpl); NON_MOVEABLE(I2cSessionImpl); AMS_DDSF_CASTABLE_TRAITS(ams::i2c::driver::impl::I2cSessionImpl, ::ams::ddsf::ISession); private: enum class Command { Send = 0, Receive = 1, }; private: TimeSpan m_retry_interval; int m_max_retry_count; private: Result SendHandler(const u8 **cur_cmd, u8 **cur_dst); Result ReceiveHandler(const u8 **cur_cmd, u8 **cur_dst); Result ExtensionHandler(const u8 **cur_cmd, u8 **cur_dst); Result ExecuteTransactionWithRetry(void *dst, Command command, const void *src, size_t size, TransactionOption option); public: I2cSessionImpl(int mr, TimeSpan rt) : m_retry_interval(rt), m_max_retry_count(mr) { /* ... */ } ~I2cSessionImpl() { this->Close(); } Result Open(I2cDeviceProperty *device, ddsf::AccessMode access_mode); void Close(); Result Send(const void *src, size_t src_size, TransactionOption option); Result Receive(void *dst, size_t dst_size, TransactionOption option); Result ExecuteCommandList(void *dst, size_t dst_size, const void *src, size_t src_size); Result SetRetryPolicy(int mr, int interval_us); }; static_assert( sizeof(I2cSessionImpl) <= I2cSessionSize); static_assert(alignof(I2cSessionImpl) <= I2cSessionAlign); struct alignas(I2cSessionAlign) I2cSessionImplPadded { I2cSessionImpl _impl; u8 _padding[I2cSessionSize - sizeof(I2cSessionImpl)]; }; static_assert( sizeof(I2cSessionImplPadded) == I2cSessionSize); static_assert(alignof(I2cSessionImplPadded) == I2cSessionAlign); ALWAYS_INLINE I2cSessionImpl &GetI2cSessionImpl(I2cSession &session) { return GetReference(session._impl)._impl; } ALWAYS_INLINE const I2cSessionImpl &GetI2cSessionImpl(const I2cSession &session) { return GetReference(session._impl)._impl; } ALWAYS_INLINE I2cSessionImpl &GetOpenI2cSessionImpl(I2cSession &session) { auto &ref = GetReference(session._impl)._impl; AMS_ASSERT(ref.IsOpen()); return ref; } ALWAYS_INLINE const I2cSessionImpl &GetOpenI2cSessionImpl(const I2cSession &session) { const auto &ref = GetReference(session._impl)._impl; AMS_ASSERT(ref.IsOpen()); return ref; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/sf/i2c_sf_i_manager.hpp> namespace ams::i2c { void InitializeWith(ams::sf::SharedPointer<i2c::sf::IManager> sp, ams::sf::SharedPointer<i2c::sf::IManager> sp_pcv); void InitializeEmpty(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_bus_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c { struct I2cSession { void *_session; }; Result OpenSession(I2cSession *out, DeviceCode device_code); void CloseSession(I2cSession &session); Result Send(const I2cSession &session, const void *src, size_t src_size, TransactionOption option); Result Receive(void *dst, size_t dst_size, const I2cSession &session, TransactionOption option); Result ExecuteCommandList(void *dst, size_t dst_size, const I2cSession &session, const void *src, size_t src_size); void SetRetryPolicy(const I2cSession &session, int max_retry_count, int retry_interval_us); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_command_list_formatter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c { constexpr inline size_t CommandListLengthMax = 0x100; constexpr inline size_t CommandListReceiveCommandSize = 2; constexpr inline size_t CommandListSendCommandSize = 2; constexpr inline size_t CommandListSleepCommandSize = 2; class CommandListFormatter { NON_COPYABLE(CommandListFormatter); NON_MOVEABLE(CommandListFormatter); private: size_t m_current_index; size_t m_command_list_length; void *m_command_list; private: Result IsEnqueueAble(size_t sz) const; public: CommandListFormatter(void *p, size_t sz) : m_current_index(0), m_command_list_length(sz), m_command_list(p) { AMS_ABORT_UNLESS(m_command_list_length <= CommandListLengthMax); } ~CommandListFormatter() { m_command_list = nullptr; } size_t GetCurrentLength() const { return m_current_index; } const void *GetListHead() const { return m_command_list; } Result EnqueueReceiveCommand(i2c::TransactionOption option, size_t size); Result EnqueueSendCommand(i2c::TransactionOption option, const void *src, size_t size); Result EnqueueSleepCommand(int us); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_device_name.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c { enum I2cBus { I2cBus_I2c1 = 0, I2cBus_I2c2 = 1, I2cBus_I2c3 = 2, I2cBus_I2c4 = 3, I2cBus_I2c5 = 4, I2cBus_I2c6 = 5, }; constexpr inline const DeviceCode DeviceCode_I2c1 = 0x02000001; constexpr inline const DeviceCode DeviceCode_I2c2 = 0x02000002; constexpr inline const DeviceCode DeviceCode_I2c3 = 0x02000003; constexpr inline const DeviceCode DeviceCode_I2c4 = 0x02000004; constexpr inline const DeviceCode DeviceCode_I2c5 = 0x02000005; constexpr inline const DeviceCode DeviceCode_I2c6 = 0x02000006; constexpr inline DeviceCode ConvertToDeviceCode(I2cBus bus) { switch (bus) { case I2cBus_I2c1: return DeviceCode_I2c1; case I2cBus_I2c2: return DeviceCode_I2c2; case I2cBus_I2c3: return DeviceCode_I2c3; case I2cBus_I2c4: return DeviceCode_I2c4; case I2cBus_I2c5: return DeviceCode_I2c5; case I2cBus_I2c6: return DeviceCode_I2c6; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline DeviceCode ConvertToI2cBus(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_I2c1.GetInternalValue(): return I2cBus_I2c1; case DeviceCode_I2c2.GetInternalValue(): return I2cBus_I2c2; case DeviceCode_I2c3.GetInternalValue(): return I2cBus_I2c3; case DeviceCode_I2c4.GetInternalValue(): return I2cBus_I2c4; case DeviceCode_I2c5.GetInternalValue(): return I2cBus_I2c5; case DeviceCode_I2c6.GetInternalValue(): return I2cBus_I2c6; AMS_UNREACHABLE_DEFAULT_CASE(); } } enum I2cDevice : u32 { I2cDevice_ClassicController = 0, I2cDevice_Ftm3bd56 = 1, I2cDevice_Tmp451 = 2, I2cDevice_Nct72 = 3, I2cDevice_Alc5639 = 4, I2cDevice_Max77620Rtc = 5, I2cDevice_Max77620Pmic = 6, I2cDevice_Max77621Cpu = 7, I2cDevice_Max77621Gpu = 8, I2cDevice_Bq24193 = 9, I2cDevice_Max17050 = 10, I2cDevice_Bm92t30mwv = 11, I2cDevice_Ina226Vdd15v0Hb = 12, I2cDevice_Ina226VsysCpuDs = 13, I2cDevice_Ina226VddCpuAp = 13, I2cDevice_Ina226VsysGpuDs = 14, I2cDevice_Ina226VddGpuAp = 14, I2cDevice_Ina226VsysDdrDs = 15, I2cDevice_Ina226VddDdr1V1Pmic = 15, I2cDevice_Ina226VsysAp = 16, I2cDevice_Ina226VsysBlDs = 17, I2cDevice_Bh1730 = 18, I2cDevice_Ina226VsysCore = 19, I2cDevice_Ina226VddCoreAp = 19, I2cDevice_Ina226Soc1V8 = 20, I2cDevice_Ina226VddSoc1V8 = 20, I2cDevice_Ina226Lpddr1V8 = 21, I2cDevice_Ina226Vdd1V8 = 21, I2cDevice_Ina226Reg1V32 = 22, I2cDevice_Ina226Vdd3V3Sys = 23, I2cDevice_HdmiDdc = 24, I2cDevice_HdmiScdc = 25, I2cDevice_HdmiHdcp = 26, I2cDevice_Fan53528 = 27, I2cDevice_Max77812_3 = 28, I2cDevice_Max77812_2 = 29, I2cDevice_Ina226VddDdr0V6 = 30, I2cDevice_HoagNfcIc = 31, /* TODO */ I2cDevice_PmicUnknownAula_4_18 = 32, /* TODO */ }; /* TODO: Better place for this? */ constexpr inline const DeviceCode DeviceCode_ClassicController = 0x350000C9; constexpr inline const DeviceCode DeviceCode_Ftm3bd56 = 0x35000033; constexpr inline const DeviceCode DeviceCode_Tmp451 = 0x3E000001; constexpr inline const DeviceCode DeviceCode_Nct72 = 0x3E000001; constexpr inline const DeviceCode DeviceCode_Alc5639 = 0x33000001; constexpr inline const DeviceCode DeviceCode_Max77620Rtc = 0x3B000001; constexpr inline const DeviceCode DeviceCode_Max77620Pmic = 0x3A000001; constexpr inline const DeviceCode DeviceCode_Max77621Cpu = 0x3A000003; constexpr inline const DeviceCode DeviceCode_Max77621Gpu = 0x3A000004; constexpr inline const DeviceCode DeviceCode_Bq24193 = 0x39000001; constexpr inline const DeviceCode DeviceCode_Max17050 = 0x39000033; constexpr inline const DeviceCode DeviceCode_Bm92t30mwv = 0x040000C9; constexpr inline const DeviceCode DeviceCode_Ina226Vdd15v0Hb = 0x3F000401; constexpr inline const DeviceCode DeviceCode_Ina226VsysCpuDs = 0x3F000001; constexpr inline const DeviceCode DeviceCode_Ina226VddCpuAp = 0x3F000001; constexpr inline const DeviceCode DeviceCode_Ina226VsysGpuDs = 0x3F000002; constexpr inline const DeviceCode DeviceCode_Ina226VddGpuAp = 0x3F000002; constexpr inline const DeviceCode DeviceCode_Ina226VsysDdrDs = 0x3F000003; constexpr inline const DeviceCode DeviceCode_Ina226VddDdr1V1Pmi = 0x3F000003; constexpr inline const DeviceCode DeviceCode_Ina226VsysAp = 0x3F000402; constexpr inline const DeviceCode DeviceCode_Ina226VsysBlDs = 0x3F000403; constexpr inline const DeviceCode DeviceCode_Bh1730 = 0x35000047; constexpr inline const DeviceCode DeviceCode_Ina226VsysCore = 0x3F000404; constexpr inline const DeviceCode DeviceCode_Ina226VddCoreAp = 0x3F000404; constexpr inline const DeviceCode DeviceCode_Ina226Soc1V8 = 0x3F000405; constexpr inline const DeviceCode DeviceCode_Ina226VddSoc1V8 = 0x3F000405; constexpr inline const DeviceCode DeviceCode_Ina226Lpddr1V8 = 0x3F000406; constexpr inline const DeviceCode DeviceCode_Ina226Vdd1V8 = 0x3F000406; constexpr inline const DeviceCode DeviceCode_Ina226Reg1V32 = 0x3F000407; constexpr inline const DeviceCode DeviceCode_Ina226Vdd3V3Sys = 0x3F000408; constexpr inline const DeviceCode DeviceCode_HdmiDdc = 0x34000001; constexpr inline const DeviceCode DeviceCode_HdmiScdc = 0x34000002; constexpr inline const DeviceCode DeviceCode_HdmiHdcp = 0x34000003; constexpr inline const DeviceCode DeviceCode_Fan53528 = 0x3A000005; constexpr inline const DeviceCode DeviceCode_Max77812_3 = 0x3A000002; constexpr inline const DeviceCode DeviceCode_Max77812_2 = 0x3A000006; constexpr inline const DeviceCode DeviceCode_Ina226VddDdr0V6 = 0x3F000409; constexpr inline const DeviceCode DeviceCode_HoagNfcIc = 0x36000001; constexpr inline const DeviceCode DeviceCode_PmicUnknownAula_4_18 = 0x3A000007; constexpr inline DeviceCode ConvertToDeviceCode(I2cDevice dv) { switch (dv) { case I2cDevice_ClassicController: return DeviceCode_ClassicController; case I2cDevice_Ftm3bd56: return DeviceCode_Ftm3bd56; case I2cDevice_Tmp451: return DeviceCode_Tmp451; case I2cDevice_Nct72: return DeviceCode_Nct72; case I2cDevice_Alc5639: return DeviceCode_Alc5639; case I2cDevice_Max77620Rtc: return DeviceCode_Max77620Rtc; case I2cDevice_Max77620Pmic: return DeviceCode_Max77620Pmic; case I2cDevice_Max77621Cpu: return DeviceCode_Max77621Cpu; case I2cDevice_Max77621Gpu: return DeviceCode_Max77621Gpu; case I2cDevice_Bq24193: return DeviceCode_Bq24193; case I2cDevice_Max17050: return DeviceCode_Max17050; case I2cDevice_Bm92t30mwv: return DeviceCode_Bm92t30mwv; case I2cDevice_Ina226Vdd15v0Hb: return DeviceCode_Ina226Vdd15v0Hb; case I2cDevice_Ina226VsysCpuDs: return DeviceCode_Ina226VsysCpuDs; case I2cDevice_Ina226VsysGpuDs: return DeviceCode_Ina226VsysGpuDs; case I2cDevice_Ina226VsysDdrDs: return DeviceCode_Ina226VsysDdrDs; case I2cDevice_Ina226VsysAp: return DeviceCode_Ina226VsysAp; case I2cDevice_Ina226VsysBlDs: return DeviceCode_Ina226VsysBlDs; case I2cDevice_Bh1730: return DeviceCode_Bh1730; case I2cDevice_Ina226VsysCore: return DeviceCode_Ina226VsysCore; case I2cDevice_Ina226Soc1V8: return DeviceCode_Ina226Soc1V8; case I2cDevice_Ina226Lpddr1V8: return DeviceCode_Ina226Lpddr1V8; case I2cDevice_Ina226Reg1V32: return DeviceCode_Ina226Reg1V32; case I2cDevice_Ina226Vdd3V3Sys: return DeviceCode_Ina226Vdd3V3Sys; case I2cDevice_HdmiDdc: return DeviceCode_HdmiDdc; case I2cDevice_HdmiScdc: return DeviceCode_HdmiScdc; case I2cDevice_HdmiHdcp: return DeviceCode_HdmiHdcp; case I2cDevice_Fan53528: return DeviceCode_Fan53528; case I2cDevice_Max77812_3: return DeviceCode_Max77812_3; case I2cDevice_Max77812_2: return DeviceCode_Max77812_2; case I2cDevice_Ina226VddDdr0V6: return DeviceCode_Ina226VddDdr0V6; case I2cDevice_HoagNfcIc: return DeviceCode_HoagNfcIc; case I2cDevice_PmicUnknownAula_4_18: return DeviceCode_PmicUnknownAula_4_18; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline I2cDevice ConvertToI2cDevice(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_ClassicController .GetInternalValue(): return I2cDevice_ClassicController; case DeviceCode_Ftm3bd56 .GetInternalValue(): return I2cDevice_Ftm3bd56; case DeviceCode_Tmp451 .GetInternalValue(): return I2cDevice_Tmp451; /* case DeviceCode_Nct72 .GetInternalValue(): return I2cDevice_Nct72; */ case DeviceCode_Alc5639 .GetInternalValue(): return I2cDevice_Alc5639; case DeviceCode_Max77620Rtc .GetInternalValue(): return I2cDevice_Max77620Rtc; case DeviceCode_Max77620Pmic .GetInternalValue(): return I2cDevice_Max77620Pmic; case DeviceCode_Max77621Cpu .GetInternalValue(): return I2cDevice_Max77621Cpu; case DeviceCode_Max77621Gpu .GetInternalValue(): return I2cDevice_Max77621Gpu; case DeviceCode_Bq24193 .GetInternalValue(): return I2cDevice_Bq24193; case DeviceCode_Max17050 .GetInternalValue(): return I2cDevice_Max17050; case DeviceCode_Bm92t30mwv .GetInternalValue(): return I2cDevice_Bm92t30mwv; case DeviceCode_Ina226Vdd15v0Hb .GetInternalValue(): return I2cDevice_Ina226Vdd15v0Hb; case DeviceCode_Ina226VsysCpuDs .GetInternalValue(): return I2cDevice_Ina226VsysCpuDs; case DeviceCode_Ina226VsysGpuDs .GetInternalValue(): return I2cDevice_Ina226VsysGpuDs; case DeviceCode_Ina226VsysDdrDs .GetInternalValue(): return I2cDevice_Ina226VsysDdrDs; case DeviceCode_Ina226VsysAp .GetInternalValue(): return I2cDevice_Ina226VsysAp; case DeviceCode_Ina226VsysBlDs .GetInternalValue(): return I2cDevice_Ina226VsysBlDs; case DeviceCode_Bh1730 .GetInternalValue(): return I2cDevice_Bh1730; case DeviceCode_Ina226VsysCore .GetInternalValue(): return I2cDevice_Ina226VsysCore; case DeviceCode_Ina226Soc1V8 .GetInternalValue(): return I2cDevice_Ina226Soc1V8; case DeviceCode_Ina226Lpddr1V8 .GetInternalValue(): return I2cDevice_Ina226Lpddr1V8; case DeviceCode_Ina226Reg1V32 .GetInternalValue(): return I2cDevice_Ina226Reg1V32; case DeviceCode_Ina226Vdd3V3Sys .GetInternalValue(): return I2cDevice_Ina226Vdd3V3Sys; case DeviceCode_HdmiDdc .GetInternalValue(): return I2cDevice_HdmiDdc; case DeviceCode_HdmiScdc .GetInternalValue(): return I2cDevice_HdmiScdc; case DeviceCode_HdmiHdcp .GetInternalValue(): return I2cDevice_HdmiHdcp; case DeviceCode_Fan53528 .GetInternalValue(): return I2cDevice_Fan53528; case DeviceCode_Max77812_3 .GetInternalValue(): return I2cDevice_Max77812_3; case DeviceCode_Max77812_2 .GetInternalValue(): return I2cDevice_Max77812_2; case DeviceCode_Ina226VddDdr0V6 .GetInternalValue(): return I2cDevice_Ina226VddDdr0V6; case DeviceCode_HoagNfcIc .GetInternalValue(): return I2cDevice_HoagNfcIc; case DeviceCode_PmicUnknownAula_4_18.GetInternalValue(): return I2cDevice_PmicUnknownAula_4_18; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr bool IsPowerBusDeviceCode(DeviceCode device_code) { switch (device_code.GetInternalValue()) { case DeviceCode_Max77620Pmic.GetInternalValue(): case DeviceCode_Max77812_3 .GetInternalValue(): case DeviceCode_Max77621Cpu .GetInternalValue(): case DeviceCode_Max77621Gpu .GetInternalValue(): case DeviceCode_Fan53528 .GetInternalValue(): case DeviceCode_Max77812_2 .GetInternalValue(): case DeviceCode_Max77620Rtc .GetInternalValue(): return true; default: return false; } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_device_name.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> namespace ams::i2c { enum I2cBus { I2cBus_I2c1 = 0, }; constexpr inline const DeviceCode DeviceCode_I2c1 = 0x02000001; constexpr inline DeviceCode ConvertToDeviceCode(I2cBus bus) { switch (bus) { case I2cBus_I2c1: return DeviceCode_I2c1; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline DeviceCode ConvertToI2cBus(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_I2c1.GetInternalValue(): return I2cBus_I2c1; AMS_UNREACHABLE_DEFAULT_CASE(); } } enum I2cDevice : u32 { I2cDevice_ClassicController = 0, }; /* TODO: Better place for this? */ constexpr inline const DeviceCode DeviceCode_ClassicController = 0x350000C9; constexpr inline DeviceCode ConvertToDeviceCode(I2cDevice dv) { switch (dv) { case I2cDevice_ClassicController: return DeviceCode_ClassicController; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline I2cDevice ConvertToI2cDevice(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_ClassicController.GetInternalValue(): return I2cDevice_ClassicController; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr bool IsPowerBusDeviceCode(DeviceCode device_code) { switch (device_code.GetInternalValue()) { default: return false; } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_register_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/i2c_command_list_formatter.hpp> #include <stratosphere/i2c/i2c_bus_api.hpp> namespace ams::i2c { template<typename RegType> requires std::unsigned_integral<RegType> Result ReadSingleRegister(const I2cSession &session, u8 address, RegType *out) { /* Check pre-conditions. */ AMS_ABORT_UNLESS(out != nullptr); constexpr i2c::TransactionOption StartOption = i2c::TransactionOption_StartCondition; constexpr i2c::TransactionOption StopOption = static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition); u8 cmd_list[CommandListLengthMax]; i2c::CommandListFormatter formatter(cmd_list, sizeof(cmd_list)); R_TRY(formatter.EnqueueSendCommand(StartOption, std::addressof(address), sizeof(address))); R_TRY(formatter.EnqueueReceiveCommand(StopOption, sizeof(*out))); R_TRY(i2c::ExecuteCommandList(out, sizeof(*out), session, cmd_list, formatter.GetCurrentLength())); R_SUCCEED(); } template<typename RegType> requires std::unsigned_integral<RegType> Result WriteSingleRegister(const I2cSession &session, u8 address, RegType value) { /* Prepare buffer. */ u8 buf[sizeof(address) + sizeof(value)]; std::memcpy(buf + 0, std::addressof(address), sizeof(address)); std::memcpy(buf + sizeof(address), std::addressof(value), sizeof(value)); constexpr i2c::TransactionOption StopOption = static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition); R_TRY(i2c::Send(session, buf, sizeof(buf), StopOption)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_select_device_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/i2c/i2c_device_name.board.nintendo_nx.hpp> #else #include <stratosphere/i2c/i2c_device_name.generic.hpp> #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/i2c_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::i2c { enum TransactionOption : u32 { TransactionOption_StartCondition = (1u << 0), TransactionOption_StopCondition = (1u << 1), TransactionOption_MaxBits = (1u << 30), }; enum AddressingMode : u32 { AddressingMode_SevenBit = 0, }; enum SpeedMode : u32 { SpeedMode_Standard = 100000, SpeedMode_Fast = 400000, SpeedMode_FastPlus = 1000000, SpeedMode_HighSpeed = 3400000, }; using I2cCommand = u8; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/server/i2c_server_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/sf/i2c_sf_i_manager.hpp> namespace ams::i2c::server { ams::sf::SharedPointer<i2c::sf::IManager> GetServiceObject(); ams::sf::SharedPointer<i2c::sf::IManager> GetServiceObjectPowerBus(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/sf/i2c_sf_i_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/i2c/i2c_select_device_name.hpp> #include <stratosphere/i2c/sf/i2c_sf_i_session.hpp> #define AMS_I2C_I_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenSessionForDev, (ams::sf::Out<ams::sf::SharedPointer<i2c::sf::ISession>> out, s32 bus_idx, u16 slave_address, i2c::AddressingMode addressing_mode, i2c::SpeedMode speed_mode), (out, bus_idx, slave_address, addressing_mode, speed_mode) ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, OpenSession, (ams::sf::Out<ams::sf::SharedPointer<i2c::sf::ISession>> out, i2c::I2cDevice device), (out, device) ) \ AMS_SF_METHOD_INFO(C, H, 2, Result, HasDevice, (ams::sf::Out<bool> out, i2c::I2cDevice device), (out, device), hos::Version_Min, hos::Version_5_1_0) \ AMS_SF_METHOD_INFO(C, H, 3, Result, HasDeviceForDev, (ams::sf::Out<bool> out, i2c::I2cDevice device), (out, device), hos::Version_Min, hos::Version_5_1_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, OpenSession2, (ams::sf::Out<ams::sf::SharedPointer<i2c::sf::ISession>> out, DeviceCode device_code), (out, device_code), hos::Version_6_0_0 ) AMS_SF_DEFINE_INTERFACE(ams::i2c::sf, IManager, AMS_I2C_I_MANAGER_INTERFACE_INFO, 0xE4C9D8F0) ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c/sf/i2c_sf_i_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c/i2c_types.hpp> #define AMS_I2C_I_SESSION_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SendOld, (const ams::sf::InBuffer &in_data, i2c::TransactionOption option), (in_data, option), hos::Version_Min, hos::Version_5_1_0) \ AMS_SF_METHOD_INFO(C, H, 1, Result, ReceiveOld, (const ams::sf::OutBuffer &out_data, i2c::TransactionOption option), (out_data, option), hos::Version_Min, hos::Version_5_1_0) \ AMS_SF_METHOD_INFO(C, H, 2, Result, ExecuteCommandListOld, (const ams::sf::OutBuffer &rcv_buf, const ams::sf::InPointerArray<i2c::I2cCommand> &command_list), (rcv_buf, command_list), hos::Version_Min, hos::Version_5_1_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, Send, (const ams::sf::InAutoSelectBuffer &in_data, i2c::TransactionOption option), (in_data, option) ) \ AMS_SF_METHOD_INFO(C, H, 11, Result, Receive, (const ams::sf::OutAutoSelectBuffer &out_data, i2c::TransactionOption option), (out_data, option) ) \ AMS_SF_METHOD_INFO(C, H, 12, Result, ExecuteCommandList, (const ams::sf::OutAutoSelectBuffer &rcv_buf, const ams::sf::InPointerArray<i2c::I2cCommand> &command_list), (rcv_buf, command_list) ) \ AMS_SF_METHOD_INFO(C, H, 13, Result, SetRetryPolicy, (s32 max_retry_count, s32 retry_interval_us), (max_retry_count, retry_interval_us), hos::Version_6_0_0 ) AMS_SF_DEFINE_INTERFACE(ams::i2c::sf, ISession, AMS_I2C_I_SESSION_INTERFACE_INFO, 0x40154EFE) ================================================ FILE: libraries/libstratosphere/include/stratosphere/i2c.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/i2c/i2c_types.hpp> #include <stratosphere/i2c/i2c_select_device_name.hpp> #include <stratosphere/i2c/i2c_command_list_formatter.hpp> #include <stratosphere/i2c/sf/i2c_sf_i_session.hpp> #include <stratosphere/i2c/sf/i2c_sf_i_manager.hpp> #include <stratosphere/i2c/server/i2c_server_api.hpp> #include <stratosphere/i2c/driver/i2c_select_driver_api.hpp> #include <stratosphere/i2c/driver/i2c_driver_service_api.hpp> #include <stratosphere/i2c/driver/i2c_driver_client_api.hpp> #include <stratosphere/i2c/driver/i2c_bus_api.hpp> #include <stratosphere/i2c/driver/impl/i2c_i2c_session_impl.hpp> #include <stratosphere/i2c/i2c_api.hpp> #include <stratosphere/i2c/i2c_bus_api.hpp> #include <stratosphere/i2c/i2c_register_accessor.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/init/init_malloc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::mem { class StandardAllocator; } namespace ams::init { void InitializeAllocator(void *address, size_t size, bool cache_enabled); void InitializeAllocator(void *address, size_t size); mem::StandardAllocator *GetAllocator(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/init.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/init/init_malloc.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_archive.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/kvdb/kvdb_auto_buffer.hpp> namespace ams::kvdb { /* Functionality for parsing/generating a key value archive. */ class ArchiveReader { private: AutoBuffer &m_buffer; size_t m_offset; public: ArchiveReader(AutoBuffer &b) : m_buffer(b), m_offset(0) { /* ... */ } private: Result Peek(void *dst, size_t size); Result Read(void *dst, size_t size); public: Result ReadEntryCount(size_t *out); Result GetEntrySize(size_t *out_key_size, size_t *out_value_size); Result ReadEntry(void *out_key, size_t key_size, void *out_value, size_t value_size); }; class ArchiveWriter { private: AutoBuffer &m_buffer; size_t m_offset; public: ArchiveWriter(AutoBuffer &b) : m_buffer(b), m_offset(0) { /* ... */ } private: Result Write(const void *src, size_t size); public: void WriteHeader(size_t entry_count); void WriteEntry(const void *key, size_t key_size, const void *value, size_t value_size); }; class ArchiveSizeHelper { private: size_t m_size; public: ArchiveSizeHelper(); void AddEntry(size_t key_size, size_t value_size); size_t GetSize() const { return m_size; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_auto_buffer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::kvdb { class AutoBuffer { NON_COPYABLE(AutoBuffer); private: u8 *m_buffer; size_t m_size; public: AutoBuffer() : m_buffer(nullptr), m_size(0) { /* ... */ } ~AutoBuffer() { this->Reset(); } AutoBuffer(AutoBuffer &&rhs) { m_buffer = rhs.m_buffer; m_size = rhs.m_size; rhs.m_buffer = nullptr; rhs.m_size = 0; } AutoBuffer &operator=(AutoBuffer &&rhs) { AutoBuffer(std::move(rhs)).Swap(*this); return *this; } void Swap(AutoBuffer &rhs) { std::swap(m_buffer, rhs.m_buffer); std::swap(m_size, rhs.m_size); } void Reset() { if (m_buffer != nullptr) { delete[] m_buffer; m_buffer = nullptr; m_size = 0; } } u8 *Get() const { return m_buffer; } size_t GetSize() const { return m_size; } Result Initialize(size_t size) { /* Check that we're not already initialized. */ AMS_ABORT_UNLESS(m_buffer == nullptr); /* Allocate a buffer. */ m_buffer = new (std::nothrow) u8[size]; R_UNLESS(m_buffer != nullptr, kvdb::ResultAllocationFailed()); m_size = size; R_SUCCEED(); } Result Initialize(const void *buf, size_t size) { /* Create a new buffer of the right size. */ R_TRY(this->Initialize(size)); /* Copy the input data in. */ std::memcpy(m_buffer, buf, size); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_bounded_string.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::kvdb { /* Represents a string with a backing buffer of N bytes. */ template<size_t N> class BoundedString { static_assert(N > 0, "BoundedString requires non-zero backing buffer!"); private: char m_buffer[N]; public: /* Constructors. */ constexpr BoundedString() { m_buffer[0] = 0; } explicit constexpr BoundedString(const char *s) { AMS_ABORT_UNLESS(static_cast<size_t>(util::Strnlen(s, N)) < N); util::Strlcpy(m_buffer, s, N); } /* Static constructors. */ static constexpr BoundedString<N> Make(const char *s) { return BoundedString<N>(s); } static BoundedString<N> MakeFormat(const char *format, ...) __attribute__((format (printf, 1, 2))) { BoundedString<N> string; std::va_list vl; va_start(vl, format); AMS_ABORT_UNLESS(static_cast<size_t>(util::VSNPrintf(string.m_buffer, N, format, vl)) < N); va_end(vl); return string; } /* Getters. */ constexpr size_t GetLength() const { return util::Strnlen(m_buffer, N); } constexpr const char *Get() const { return m_buffer; } constexpr operator const char *() const { return m_buffer; } /* Assignment. */ constexpr BoundedString<N> &Assign(const char *s) { AMS_ABORT_UNLESS(static_cast<size_t>(util::Strnlen(s, N)) < N); util::Strlcpy(m_buffer, s, N); return *this; } BoundedString<N> &AssignFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) { std::va_list vl; va_start(vl, format); AMS_ABORT_UNLESS(static_cast<size_t>(util::VSNPrintf(m_buffer, N, format, vl)) < N); va_end(vl); return *this; } /* Append to existing. */ BoundedString<N> &Append(const char *s) { const size_t length = GetLength(); AMS_ABORT_UNLESS(length + static_cast<size_t>(util::Strnlen(s, N)) < N); std::strncat(m_buffer, s, N - length - 1); return *this; } BoundedString<N> &Append(char c) { const size_t length = GetLength(); AMS_ABORT_UNLESS(length + 1 < N); m_buffer[length] = c; m_buffer[length + 1] = 0; return *this; } BoundedString<N> &AppendFormat(const char *format, ...) __attribute__((format (printf, 2, 3))) { const size_t length = GetLength(); std::va_list vl; va_start(vl, format); AMS_ABORT_UNLESS(static_cast<size_t>(util::VSNPrintf(m_buffer + length, N - length, format, vl)) < static_cast<size_t>(N - length)); va_end(vl); return *this; } /* Substring utilities. */ void GetSubString(char *dst, size_t dst_size, size_t offset, size_t length) const { /* Make sure output buffer can hold the substring. */ AMS_ABORT_UNLESS(offset + length <= GetLength()); AMS_ABORT_UNLESS(dst_size > length); /* Copy substring to dst. */ std::strncpy(dst, m_buffer + offset, length); dst[length] = 0; } BoundedString<N> MakeSubString(size_t offset, size_t length) const { BoundedString<N> string; GetSubString(string.m_buffer, N, offset, length); return string; } /* Comparison. */ constexpr bool Equals(const char *s, size_t offset = 0) const { if (std::is_constant_evaluated()) { return util::Strncmp(m_buffer + offset, s, N - offset) == 0; } else { return std::strncmp(m_buffer + offset, s, N - offset) == 0; } } constexpr bool operator==(const BoundedString<N> &rhs) const { return this->Equals(rhs.m_buffer); } constexpr bool operator!=(const BoundedString<N> &rhs) const { return !(*this == rhs); } constexpr bool EqualsPostfix(const char *s) const { const size_t suffix_length = util::Strnlen(s, N); const size_t length = GetLength(); return suffix_length <= length && this->Equals(s, length - suffix_length); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/kvdb/kvdb_bounded_string.hpp> #include <stratosphere/kvdb/kvdb_file_key_value_store.hpp> namespace ams::kvdb { namespace impl { template<class Key, size_t Capacity> class LruList { private: /* Subtypes. */ struct LruHeader { u32 entry_count; }; public: static constexpr size_t BufferSize = sizeof(Key) * Capacity; static constexpr size_t FileSize = sizeof(LruHeader) + BufferSize; using Path = FileKeyValueStore::Path; private: Path m_file_path; Key *m_keys; LruHeader m_header; public: static Result CreateNewList(const char *path) { /* Create new lru_list.dat. */ R_TRY(fs::CreateFile(path, FileSize)); /* Open the file. */ fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write)); ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Write new header with zero entries to the file. */ LruHeader new_header = { .entry_count = 0, }; R_TRY(fs::WriteFile(file, 0, std::addressof(new_header), sizeof(new_header), fs::WriteOption::Flush)); R_SUCCEED(); } private: void RemoveIndex(size_t i) { AMS_ABORT_UNLESS(i < this->GetCount()); std::memmove(m_keys + i, m_keys + i + 1, sizeof(*m_keys) * (this->GetCount() - (i + 1))); this->DecrementCount(); } void IncrementCount() { m_header.entry_count++; } void DecrementCount() { m_header.entry_count--; } public: LruList() : m_keys(nullptr), m_header() { /* ... */ } Result Initialize(const char *path, void *buf, size_t size) { /* Only initialize once, and ensure we have sufficient memory. */ AMS_ABORT_UNLESS(m_keys == nullptr); AMS_ABORT_UNLESS(size >= BufferSize); /* Setup member variables. */ m_keys = static_cast<Key *>(buf); m_file_path.Assign(path); std::memset(m_keys, 0, BufferSize); /* Open file. */ fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), m_file_path, fs::OpenMode_Read)); ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Read header. */ R_TRY(fs::ReadFile(file, 0, std::addressof(m_header), sizeof(m_header))); /* Read entries. */ R_TRY(fs::ReadFile(file, sizeof(m_header), m_keys, BufferSize)); R_SUCCEED(); } Result Save() { /* Open file. */ fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), m_file_path, fs::OpenMode_Read)); ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Write header. */ R_TRY(fs::WriteFile(file, 0, std::addressof(m_header), sizeof(m_header), fs::WriteOption::None)); /* Write entries. */ R_TRY(fs::WriteFile(file, sizeof(m_header), m_keys, BufferSize, fs::WriteOption::None)); /* Flush. */ R_TRY(fs::FlushFile(file)); R_SUCCEED(); } size_t GetCount() const { return m_header.entry_count; } bool IsEmpty() const { return this->GetCount() == 0; } bool IsFull() const { return this->GetCount() >= Capacity; } Key Get(size_t i) const { AMS_ABORT_UNLESS(i < this->GetCount()); return m_keys[i]; } Key Peek() const { AMS_ABORT_UNLESS(!this->IsEmpty()); return this->Get(0); } void Push(const Key &key) { AMS_ABORT_UNLESS(!this->IsFull()); m_keys[this->GetCount()] = key; this->IncrementCount(); } Key Pop() { AMS_ABORT_UNLESS(!this->IsEmpty()); this->RemoveIndex(0); } bool Remove(const Key &key) { const size_t count = this->GetCount(); /* Iterate over the list, removing the last entry that matches the key. */ for (size_t i = 0; i < count; i++) { if (m_keys[count - 1 - i] == key) { this->RemoveIndex(count - 1 - i); return true; } } return false; } bool Contains(const Key &key) const { const size_t count = this->GetCount(); /* Iterate over the list, checking to see if we have the key. */ for (size_t i = 0; i < count; i++) { if (m_keys[count - 1 - i] == key) { return true; } } return false; } bool Update(const Key &key) { if (this->Remove(key)) { this->Push(key); return true; } return false; } }; } template<class Key, size_t Capacity> class FileKeyValueCache { static_assert(util::is_pod<Key>::value, "FileKeyValueCache Key must be pod!"); static_assert(sizeof(Key) <= FileKeyValueStore::MaxKeySize, "FileKeyValueCache Key is too big!"); public: using LeastRecentlyUsedList = impl::LruList<Key, Capacity>; /* Note: Nintendo code in NS uses Path = BoundedString<0x180> here. */ /* It's unclear why, since they use 0x300 everywhere else. */ /* We'll just use 0x300, since it shouldn't make a difference, */ /* as FileKeyValueStore paths are limited to 0x100 anyway. */ using Path = typename LeastRecentlyUsedList::Path; private: FileKeyValueStore m_kvs; LeastRecentlyUsedList m_lru_list; private: static constexpr Path GetLeastRecentlyUsedListPath(const char *dir) { return Path::MakeFormat("%s/%s", dir, "lru_list.dat"); } static constexpr Path GetFileKeyValueStorePath(const char *dir) { return Path::MakeFormat("%s/%s", dir, "kvs"); } static Result Exists(bool *out, const char *path, fs::DirectoryEntryType type) { /* Set out to false initially. */ *out = false; /* Try to get the entry type. */ fs::DirectoryEntryType entry_type; R_TRY_CATCH(fs::GetEntryType(std::addressof(entry_type), path)) { /* If the path doesn't exist, nothing has gone wrong. */ R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); } R_END_TRY_CATCH; /* Check that the entry type is correct. */ R_UNLESS(entry_type == type, kvdb::ResultInvalidFilesystemState()); /* The entry exists and is the correct type. */ *out = true; R_SUCCEED(); } static Result DirectoryExists(bool *out, const char *path) { R_RETURN(Exists(out, path, fs::DirectoryEntryType_Directory)); } static Result FileExists(bool *out, const char *path) { R_RETURN(Exists(out, path, fs::DirectoryEntryType_File)); } public: static Result CreateNewCache(const char *dir) { /* Make a new key value store filesystem, and a new lru_list.dat. */ R_TRY(LeastRecentlyUsedList::CreateNewList(GetLeastRecentlyUsedListPath(dir))); R_TRY(fs::CreateDirectory(dir)); R_SUCCEED(); } static Result ValidateExistingCache(const char *dir) { /* Check for existence. */ bool has_lru = false, has_kvs = false; R_TRY(FileExists(std::addressof(has_lru), GetLeastRecentlyUsedListPath(dir))); R_TRY(DirectoryExists(std::addressof(has_kvs), GetFileKeyValueStorePath(dir))); /* If neither exists, CreateNewCache was never called. */ R_UNLESS(has_lru || has_kvs, kvdb::ResultNotCreated()); /* If one exists but not the other, we have an invalid state. */ R_UNLESS(has_lru && has_kvs, kvdb::ResultInvalidFilesystemState()); R_SUCCEED(); } private: void RemoveOldestKey() { const Key &oldest_key = m_lru_list.Peek(); m_lru_list.Pop(); m_kvs.Remove(oldest_key); } public: Result Initialize(const char *dir, void *buf, size_t size) { /* Initialize list. */ R_TRY(m_lru_list.Initialize(GetLeastRecentlyUsedListPath(dir), buf, size)); /* Initialize kvs. */ /* NOTE: Despite creating the kvs folder and returning an error if it does not exist, */ /* Nintendo does not use the kvs folder, and instead uses the passed dir. */ /* This causes lru_list.dat to be in the same directory as the store's .val files */ /* instead of in the same directory as a folder containing the store's .val files. */ /* This is probably a Nintendo bug, but because system saves contain data in the wrong */ /* layout it can't really be fixed without breaking existing devices... */ R_TRY(m_kvs.Initialize(dir)); R_SUCCEED(); } size_t GetCount() const { return m_lru_list.GetCount(); } size_t GetCapacity() const { return Capacity; } Key GetKey(size_t i) const { return m_lru_list.Get(i); } bool Contains(const Key &key) const { return m_lru_list.Contains(key); } Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { /* Note that we accessed the key. */ m_lru_list.Update(key); R_RETURN(m_kvs.Get(out_size, out_value, max_out_size, key)); } template<typename Value> Result Get(Value *out_value, const Key &key) { /* Note that we accessed the key. */ m_lru_list.Update(key); R_RETURN(m_kvs.Get(out_value, key)); } Result GetSize(size_t *out_size, const Key &key) { R_RETURN(m_kvs.GetSize(out_size, key)); } Result Set(const Key &key, const void *value, size_t value_size) { if (m_lru_list.Update(key)) { /* If an entry for the key exists, delete the existing value file. */ m_kvs.Remove(key); } else { /* If the list is full, we need to remove the oldest key. */ if (m_lru_list.IsFull()) { this->RemoveOldestKey(); } /* Add the key to the list. */ m_lru_list.Push(key); } /* Loop, trying to save the new value to disk. */ while (true) { /* Try to set the key. */ R_TRY_CATCH(m_kvs.Set(key, value, value_size)) { R_CATCH(fs::ResultNotEnoughFreeSpace) { /* If our entry is the only thing in the Lru list, remove it. */ if (m_lru_list.GetCount() == 1) { m_lru_list.Pop(); R_TRY(m_lru_list.Save()); R_THROW(fs::ResultNotEnoughFreeSpace()); } /* Otherwise, remove the oldest element from the cache and try again. */ this->RemoveOldestKey(); continue; } } R_END_TRY_CATCH; /* If we got here, we succeeded. */ break; } /* Save the list. */ R_TRY(m_lru_list.Save()); R_SUCCEED(); } template<typename Value> Result Set(const Key &key, const Value &value) { R_RETURN(this->Set(key, &value, sizeof(Value))); } Result Remove(const Key &key) { /* Remove the key. */ m_lru_list.Remove(key); R_TRY(m_kvs.Remove(key)); R_TRY(m_lru_list.Save()); R_SUCCEED(); } Result RemoveAll() { /* TODO: Nintendo doesn't check errors here. Should we? */ while (!m_lru_list.IsEmpty()) { this->RemoveOldestKey(); } R_TRY(m_lru_list.Save()); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_file_key_value_store.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/kvdb/kvdb_bounded_string.hpp> namespace ams::kvdb { class FileKeyValueStore { NON_COPYABLE(FileKeyValueStore); NON_MOVEABLE(FileKeyValueStore); public: static constexpr size_t MaxFileLength = 0xFF; static constexpr char FileExtension[5] = ".val"; static constexpr size_t FileExtensionLength = sizeof(FileExtension) - 1; static constexpr size_t MaxKeySize = (MaxFileLength - FileExtensionLength) / 2; using Path = kvdb::BoundedString<fs::EntryNameLengthMax>; using FileName = kvdb::BoundedString<MaxFileLength>; private: /* Subtypes. */ struct Entry { u8 key[MaxKeySize]; void *value; size_t key_size; size_t value_size; }; static_assert(util::is_pod<Entry>::value, "FileKeyValueStore::Entry definition!"); class Cache { private: u8 *m_backing_buffer = nullptr; size_t m_backing_buffer_size = 0; size_t m_backing_buffer_free_offset = 0; Entry *m_entries = nullptr; size_t m_count = 0; size_t m_capacity = 0; private: void *Allocate(size_t size); bool HasEntries() const { return m_entries != nullptr && m_capacity != 0; } public: Result Initialize(void *buffer, size_t buffer_size, size_t capacity); void Invalidate(); util::optional<size_t> TryGet(void *out_value, size_t max_out_size, const void *key, size_t key_size); util::optional<size_t> TryGetSize(const void *key, size_t key_size); void Set(const void *key, size_t key_size, const void *value, size_t value_size); bool Contains(const void *key, size_t key_size); }; private: os::SdkMutex m_lock; Path m_dir_path; Cache m_cache; private: Path GetPath(const void *key, size_t key_size); Result GetKey(size_t *out_size, void *out_key, size_t max_out_size, const FileName &file_name); public: FileKeyValueStore() : m_lock() { /* ... */ } /* Basic accessors. */ Result Initialize(const char *dir); Result InitializeWithCache(const char *dir, void *cache_buffer, size_t cache_buffer_size, size_t cache_capacity); Result Get(size_t *out_size, void *out_value, size_t max_out_size, const void *key, size_t key_size); Result GetSize(size_t *out_size, const void *key, size_t key_size); Result Set(const void *key, size_t key_size, const void *value, size_t value_size); Result Remove(const void *key, size_t key_size); /* Niceties. */ template<typename Key> Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { static_assert(util::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!"); R_RETURN(this->Get(out_size, out_value, max_out_size, std::addressof(key), sizeof(Key))); } template<typename Key, typename Value> Result Get(Value *out_value, const Key &key) { static_assert(util::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!"); size_t size = 0; R_TRY(this->Get(std::addressof(size), out_value, sizeof(Value), key)); AMS_ABORT_UNLESS(size >= sizeof(Value)); R_SUCCEED(); } template<typename Key> Result GetSize(size_t *out_size, const Key &key) { R_RETURN(this->GetSize(out_size, std::addressof(key), sizeof(Key))); } template<typename Key> Result Set(const Key &key, const void *value, size_t value_size) { static_assert(util::is_pod<Key>::value && sizeof(Key) <= MaxKeySize, "Invalid FileKeyValueStore Key!"); R_RETURN(this->Set(std::addressof(key), sizeof(Key), value, value_size)); } template<typename Key, typename Value> Result Set(const Key &key, const Value &value) { static_assert(util::is_pod<Value>::value && !std::is_pointer<Value>::value, "Invalid FileKeyValueStore Value!"); R_RETURN(this->Set(key, std::addressof(value), sizeof(Value))); } template<typename Key> Result Remove(const Key &key) { R_RETURN(this->Remove(std::addressof(key), sizeof(Key))); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb/kvdb_memory_key_value_store.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_file.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/fs/fs_filesystem.hpp> #include <stratosphere/kvdb/kvdb_auto_buffer.hpp> #include <stratosphere/kvdb/kvdb_archive.hpp> #include <stratosphere/kvdb/kvdb_bounded_string.hpp> namespace ams::kvdb { template<class Key> class MemoryKeyValueStore { static_assert(util::is_pod<Key>::value, "KeyValueStore Keys must be pod!"); NON_COPYABLE(MemoryKeyValueStore); NON_MOVEABLE(MemoryKeyValueStore); public: /* Subtypes. */ class Entry { private: Key m_key; void *m_value; size_t m_value_size; public: constexpr Entry(const Key &k, void *v, size_t s) : m_key(k), m_value(v), m_value_size(s) { /* ... */ } const Key &GetKey() const { return m_key; } template<typename Value = void> Value *GetValuePointer() { /* Size check. Note: Nintendo does not size check. */ if constexpr (!std::is_same<Value, void>::value) { AMS_ABORT_UNLESS(sizeof(Value) <= m_value_size); /* Ensure we only get pod. */ static_assert(util::is_pod<Value>::value, "KeyValueStore Values must be pod"); } return reinterpret_cast<Value *>(m_value); } template<typename Value = void> const Value *GetValuePointer() const { /* Size check. Note: Nintendo does not size check. */ if constexpr (!std::is_same<Value, void>::value) { AMS_ABORT_UNLESS(sizeof(Value) <= m_value_size); /* Ensure we only get pod. */ static_assert(util::is_pod<Value>::value, "KeyValueStore Values must be pod"); } return reinterpret_cast<Value *>(m_value); } template<typename Value> Value &GetValue() { return *(this->GetValuePointer<Value>()); } template<typename Value> const Value &GetValue() const { return *(this->GetValuePointer<Value>()); } size_t GetValueSize() const { return m_value_size; } constexpr inline bool operator<(const Key &rhs) const { return m_key < rhs; } constexpr inline bool operator==(const Key &rhs) const { return m_key == rhs; } }; class Index { private: size_t m_count; size_t m_capacity; Entry *m_entries; MemoryResource *m_memory_resource; public: Index() : m_count(0), m_capacity(0), m_entries(nullptr), m_memory_resource(nullptr) { /* ... */ } ~Index() { if (m_entries != nullptr) { this->ResetEntries(); m_memory_resource->Deallocate(m_entries, sizeof(Entry) * m_capacity); m_entries = nullptr; } } size_t GetCount() const { return m_count; } size_t GetCapacity() const { return m_capacity; } void ResetEntries() { for (size_t i = 0; i < m_count; i++) { m_memory_resource->Deallocate(m_entries[i].GetValuePointer(), m_entries[i].GetValueSize()); } m_count = 0; } Result Initialize(size_t capacity, MemoryResource *mr) { m_entries = reinterpret_cast<Entry *>(mr->Allocate(sizeof(Entry) * capacity)); R_UNLESS(m_entries != nullptr, kvdb::ResultAllocationFailed()); m_capacity = capacity; m_memory_resource = mr; R_SUCCEED(); } Result Set(const Key &key, const void *value, size_t value_size) { /* Find entry for key. */ Entry *it = this->lower_bound(key); if (it != this->end() && it->GetKey() == key) { /* Entry already exists. Free old value. */ m_memory_resource->Deallocate(it->GetValuePointer(), it->GetValueSize()); } else { /* We need to add a new entry. Check we have room, move future keys forward. */ R_UNLESS(m_count < m_capacity, kvdb::ResultOutOfKeyResource()); std::memmove(it + 1, it, sizeof(*it) * (this->end() - it)); m_count++; } /* Allocate new value. */ void *new_value = m_memory_resource->Allocate(value_size); R_UNLESS(new_value != nullptr, kvdb::ResultAllocationFailed()); std::memcpy(new_value, value, value_size); /* Save the new Entry in the map. */ *it = Entry(key, new_value, value_size); R_SUCCEED(); } Result AddUnsafe(const Key &key, void *value, size_t value_size) { R_UNLESS(m_count < m_capacity, kvdb::ResultOutOfKeyResource()); m_entries[m_count++] = Entry(key, value, value_size); R_SUCCEED(); } Result Remove(const Key &key) { /* Find entry for key. */ Entry *it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); /* Free the value, move entries back. */ m_memory_resource->Deallocate(it->GetValuePointer(), it->GetValueSize()); std::memmove(it, it + 1, sizeof(*it) * (this->end() - (it + 1))); m_count--; R_SUCCEED(); } Entry *begin() { return this->GetBegin(); } const Entry *begin() const { return this->GetBegin(); } Entry *end() { return this->GetEnd(); } const Entry *end() const { return this->GetEnd(); } const Entry *cbegin() const { return this->begin(); } const Entry *cend() const { return this->end(); } Entry *lower_bound(const Key &key) { return this->GetLowerBound(key); } const Entry *lower_bound(const Key &key) const { return this->GetLowerBound(key); } Entry *find(const Key &key) { return this->Find(key); } const Entry *find(const Key &key) const { return this->Find(key); } private: Entry *GetBegin() { return m_entries; } const Entry *GetBegin() const { return m_entries; } Entry *GetEnd() { return this->GetBegin() + m_count; } const Entry *GetEnd() const { return this->GetBegin() + m_count; } Entry *GetLowerBound(const Key &key) { return std::lower_bound(this->GetBegin(), this->GetEnd(), key); } const Entry *GetLowerBound(const Key &key) const { return std::lower_bound(this->GetBegin(), this->GetEnd(), key); } Entry *Find(const Key &key) { auto it = this->GetLowerBound(key); auto end = this->GetEnd(); if (it != end && it->GetKey() == key) { return it; } return end; } const Entry *Find(const Key &key) const { auto it = this->GetLowerBound(key); auto end = this->GetEnd(); if (it != end && it->GetKey() == key) { return it; } return end; } }; private: using Path = kvdb::BoundedString<fs::EntryNameLengthMax>; private: Index m_index; Path m_path; Path m_temp_path; MemoryResource *m_memory_resource; public: MemoryKeyValueStore() { /* ... */ } Result Initialize(const char *dir, size_t capacity, MemoryResource *mr) { /* Ensure that the passed path is a directory. */ fs::DirectoryEntryType entry_type; R_TRY(fs::GetEntryType(std::addressof(entry_type), dir)); R_UNLESS(entry_type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound()); /* Set paths. */ m_path.AssignFormat("%s%s", dir, "/imkvdb.arc"); m_temp_path.AssignFormat("%s%s", dir, "/imkvdb.tmp"); /* Initialize our index. */ R_TRY(m_index.Initialize(capacity, mr)); m_memory_resource = mr; R_SUCCEED(); } Result InitializeForReadOnlyArchiveFile(const char *path, size_t capacity, MemoryResource *mr) { /* Ensure that the passed path is a directory. */ fs::DirectoryEntryType entry_type; R_TRY(fs::GetEntryType(std::addressof(entry_type), path)); R_UNLESS(entry_type == fs::DirectoryEntryType_File, fs::ResultPathNotFound()); /* Set paths. */ m_path.Assign(path); m_temp_path.Assign(""); /* Initialize our index. */ R_TRY(m_index.Initialize(capacity, mr)); m_memory_resource = mr; R_SUCCEED(); } Result Initialize(size_t capacity, MemoryResource *mr) { /* This initializes without an archive file. */ /* A store initialized this way cannot have its contents loaded from or flushed to disk. */ m_path.Assign(""); m_temp_path.Assign(""); /* Initialize our index. */ R_TRY(m_index.Initialize(capacity, mr)); m_memory_resource = mr; R_SUCCEED(); } size_t GetCount() const { return m_index.GetCount(); } size_t GetCapacity() const { return m_index.GetCapacity(); } Result Load() { /* Reset any existing entries. */ m_index.ResetEntries(); /* Try to read the archive -- note, path not found is a success condition. */ /* This is because no archive file = no entries, so we're in the right state. */ AutoBuffer buffer; R_TRY_CATCH(this->ReadArchiveFile(std::addressof(buffer))) { R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); } R_END_TRY_CATCH; /* Parse entries from the buffer. */ { ArchiveReader reader(buffer); size_t entry_count = 0; R_TRY(reader.ReadEntryCount(std::addressof(entry_count))); for (size_t i = 0; i < entry_count; i++) { /* Get size of key/value. */ size_t key_size = 0, value_size = 0; R_TRY(reader.GetEntrySize(std::addressof(key_size), std::addressof(value_size))); /* Allocate memory for value. */ void *new_value = m_memory_resource->Allocate(value_size); R_UNLESS(new_value != nullptr, kvdb::ResultAllocationFailed()); /* If we fail before adding to the index, deallocate our value. */ ON_RESULT_FAILURE { m_memory_resource->Deallocate(new_value, value_size); }; /* Read key and value. */ Key key; R_TRY(reader.ReadEntry(std::addressof(key), sizeof(key), new_value, value_size)); R_TRY(m_index.AddUnsafe(key, new_value, value_size)); } } R_SUCCEED(); } Result Save(bool destructive = false) { /* Create a buffer to hold the archive. */ AutoBuffer buffer; R_TRY(buffer.Initialize(this->GetArchiveSize())); /* Write the archive to the buffer. */ { ArchiveWriter writer(buffer); writer.WriteHeader(this->GetCount()); for (const auto &it : m_index) { const auto &key = it.GetKey(); writer.WriteEntry(std::addressof(key), sizeof(Key), it.GetValuePointer(), it.GetValueSize()); } } /* Save the buffer to disk. */ R_RETURN(this->Commit(buffer, destructive)); } Result Set(const Key &key, const void *value, size_t value_size) { R_RETURN(m_index.Set(key, value, value_size)); } template<typename Value> Result Set(const Key &key, const Value &value) { /* Only allow setting pod. */ static_assert(util::is_pod<Value>::value, "KeyValueStore Values must be pod"); R_RETURN(this->Set(key, std::addressof(value), sizeof(Value))); } template<typename Value> Result Set(const Key &key, const Value *value) { /* Only allow setting pod. */ static_assert(util::is_pod<Value>::value, "KeyValueStore Values must be pod"); R_RETURN(this->Set(key, value, sizeof(Value))); } Result Get(size_t *out_size, void *out_value, size_t max_out_size, const Key &key) { /* Find entry. */ auto it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); size_t size = std::min(max_out_size, it->GetValueSize()); std::memcpy(out_value, it->GetValuePointer(), size); *out_size = size; R_SUCCEED(); } template<typename Value = void> Result GetValuePointer(Value **out_value, const Key &key) { /* Find entry. */ auto it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); *out_value = it->template GetValuePointer<Value>(); R_SUCCEED(); } template<typename Value = void> Result GetValuePointer(const Value **out_value, const Key &key) const { /* Find entry. */ auto it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); *out_value = it->template GetValuePointer<Value>(); R_SUCCEED(); } template<typename Value> Result GetValue(Value *out_value, const Key &key) const { /* Find entry. */ auto it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); *out_value = it->template GetValue<Value>(); R_SUCCEED(); } Result GetValueSize(size_t *out_size, const Key &key) const { /* Find entry. */ auto it = this->find(key); R_UNLESS(it != this->end(), kvdb::ResultKeyNotFound()); *out_size = it->GetValueSize(); R_SUCCEED(); } Result Remove(const Key &key) { R_RETURN(m_index.Remove(key)); } Entry *begin() { return m_index.begin(); } const Entry *begin() const { return m_index.begin(); } Entry *end() { return m_index.end(); } const Entry *end() const { return m_index.end(); } const Entry *cbegin() const { return m_index.cbegin(); } const Entry *cend() const { return m_index.cend(); } Entry *lower_bound(const Key &key) { return m_index.lower_bound(key); } const Entry *lower_bound(const Key &key) const { return m_index.lower_bound(key); } Entry *find(const Key &key) { return m_index.find(key); } const Entry *find(const Key &key) const { return m_index.find(key); } private: Result SaveArchiveToFile(const char *path, const void *buf, size_t size) { /* Try to delete the archive, but allow deletion failure. */ fs::DeleteFile(path); /* Create new archive. */ R_TRY(fs::CreateFile(path, size)); /* Write data to the archive. */ { fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write)); ON_SCOPE_EXIT { fs::CloseFile(file); }; R_TRY(fs::WriteFile(file, 0, buf, size, fs::WriteOption::Flush)); } R_SUCCEED(); } Result Commit(const AutoBuffer &buffer, bool destructive) { if (destructive) { /* Delete and save to the real archive. */ R_TRY(SaveArchiveToFile(m_path.Get(), buffer.Get(), buffer.GetSize())); } else { /* Delete and save to a temporary archive. */ R_TRY(SaveArchiveToFile(m_temp_path.Get(), buffer.Get(), buffer.GetSize())); /* Try to delete the saved archive, but allow deletion failure. */ fs::DeleteFile(m_path.Get()); /* Rename the path. */ R_TRY(fs::RenameFile(m_temp_path.Get(), m_path.Get())); } R_SUCCEED(); } size_t GetArchiveSize() const { ArchiveSizeHelper size_helper; for (const auto &it : m_index) { size_helper.AddEntry(sizeof(Key), it.GetValueSize()); } return size_helper.GetSize(); } Result ReadArchiveFile(AutoBuffer *dst) const { /* Open the file. */ fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), m_path, fs::OpenMode_Read)); ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Get the archive file size. */ s64 archive_size; R_TRY(fs::GetFileSize(std::addressof(archive_size), file)); /* Make a new buffer, read the file. */ R_TRY(dst->Initialize(static_cast<size_t>(archive_size))); R_TRY(fs::ReadFile(file, 0, dst->Get(), dst->GetSize())); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/kvdb.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/kvdb/kvdb_auto_buffer.hpp> #include <stratosphere/kvdb/kvdb_bounded_string.hpp> #include <stratosphere/kvdb/kvdb_archive.hpp> #include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp> #include <stratosphere/kvdb/kvdb_file_key_value_store.hpp> #include <stratosphere/kvdb/kvdb_file_key_value_cache.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/impl/ldr_debug_monitor_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ldr/ldr_types.hpp> #include <stratosphere/sf.hpp> #define AMS_LDR_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgument, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, FlushArguments, (), ()) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetProcessModuleInfo, (sf::Out<u32> count, const sf::OutPointerArray<ldr::ModuleInfo> &out, os::ProcessId process_id), (count, out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 65000, void, AtmosphereHasLaunchedBootProgram, (sf::Out<bool> out, ncm::ProgramId program_id), (out, program_id)) AMS_SF_DEFINE_INTERFACE(ams::ldr::impl, IDebugMonitorInterface, AMS_LDR_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO, 0xEE195D22) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/impl/ldr_process_manager_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ldr/ldr_types.hpp> #include <stratosphere/sf.hpp> #define AMS_LDR_I_PROCESS_MANAGER_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, CreateProcess, (sf::OutMoveHandle proc_h, ldr::PinId id, u32 flags, sf::CopyHandle &&reslimit_h, const ldr::ProgramAttributes &attrs), (proc_h, id, flags, std::move(reslimit_h), attrs)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetProgramInfo, (sf::Out<ldr::ProgramInfo> out_program_info, const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs), (out_program_info, loc, attrs)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, PinProgram, (sf::Out<ldr::PinId> out_id, const ncm::ProgramLocation &loc), (out_id, loc)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, UnpinProgram, (ldr::PinId id), (id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, SetEnabledProgramVerification, (bool enabled), (enabled), hos::Version_10_0_0) \ AMS_SF_METHOD_INFO(C, H, 65000, void, AtmosphereHasLaunchedBootProgram, (sf::Out<bool> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 65001, Result, AtmosphereGetProgramInfo, (sf::Out<ldr::ProgramInfo> out_program_info, sf::Out<cfg::OverrideStatus> out_status, const ncm::ProgramLocation &loc, const ldr::ProgramAttributes &attrs), (out_program_info, out_status, loc, attrs)) \ AMS_SF_METHOD_INFO(C, H, 65002, Result, AtmospherePinProgram, (sf::Out<ldr::PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status), (out_id, loc, override_status)) AMS_SF_DEFINE_INTERFACE(ams::ldr::impl, IProcessManagerInterface, AMS_LDR_I_PROCESS_MANAGER_INTERFACE_INTERFACE_INFO, 0x01518B8E) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/impl/ldr_shell_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ldr/ldr_types.hpp> #include <stratosphere/sf.hpp> #define AMS_LDR_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgumentDeprecated, (ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size), (program_id, args, args_size), hos::Version_Min, hos::Version_10_2_0) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetProgramArgument, (ncm::ProgramId program_id, const sf::InPointerBuffer &args), (program_id, args), hos::Version_11_0_0 ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, FlushArguments, (), ()) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereRegisterExternalCode, (sf::OutMoveHandle out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 65001, void, AtmosphereUnregisterExternalCode, (ncm::ProgramId program_id), (program_id)) AMS_SF_DEFINE_INTERFACE(ams::ldr::impl, IShellInterface, AMS_LDR_I_SHELL_INTERFACE_INTERFACE_INFO, 0x3EE5B554) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/ldr_pm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ldr/ldr_types.hpp> namespace ams::ldr::pm { /* Process Manager API. */ Result CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle reslimit, ldr::ProgramAttributes attrs); Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc, ldr::ProgramAttributes attrs); Result PinProgram(PinId *out, const ncm::ProgramLocation &loc); Result UnpinProgram(PinId pin_id); Result SetEnabledProgramVerification(bool enabled); Result HasLaunchedBootProgram(bool *out, ncm::ProgramId program_id); /* Atmosphere extension API. */ Result AtmosphereGetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, ldr::ProgramAttributes attrs); Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/ldr_shell_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/ldr/ldr_types.hpp> namespace ams::ldr { /* Shell API. */ Result InitializeForShell(); Result FinalizeForShell(); Result SetProgramArgument(ncm::ProgramId program_id, const void *arg, size_t size); Result FlushArguments(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr/ldr_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/ncm/ncm_program_location.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> #include <stratosphere/ncm/ncm_content_meta_platform.hpp> #include <stratosphere/fs/fs_content_attributes.hpp> namespace ams::ldr { /* General types. */ struct ProgramInfo : public sf::LargeData { u8 main_thread_priority; u8 default_cpu_id; u16 flags; u32 main_thread_stack_size; ncm::ProgramId program_id; u32 acid_sac_size; u32 aci_sac_size; u32 acid_fac_size; u32 aci_fah_size; u8 unused_20[0x10]; u8 ac_buffer[0x3E0]; }; static_assert(util::is_pod<ProgramInfo>::value && sizeof(ProgramInfo) == 0x410, "ProgramInfo definition!"); enum ProgramInfoFlag { ProgramInfoFlag_SystemModule = (0 << 0), ProgramInfoFlag_Application = (1 << 0), ProgramInfoFlag_Applet = (2 << 0), ProgramInfoFlag_InvalidType = (3 << 0), ProgramInfoFlag_ApplicationTypeMask = (3 << 0), ProgramInfoFlag_AllowDebug = (1 << 2), }; enum CreateProcessFlag { CreateProcessFlag_EnableDebug = (1 << 0), CreateProcessFlag_DisableAslr = (1 << 1), }; struct ProgramArguments { u32 allocated_size; u32 arguments_size; u8 reserved[0x18]; u8 arguments[]; }; static_assert(sizeof(ProgramArguments) == 0x20, "ProgramArguments definition!"); struct PinId { u64 value; }; inline bool operator==(const PinId &lhs, const PinId &rhs) { return lhs.value == rhs.value; } inline bool operator!=(const PinId &lhs, const PinId &rhs) { return lhs.value != rhs.value; } static_assert(sizeof(PinId) == sizeof(u64) && util::is_pod<PinId>::value, "PinId definition!"); struct ModuleInfo { u8 module_id[0x20]; u64 address; u64 size; }; static_assert(sizeof(ModuleInfo) == 0x30); /* NSO types. */ struct NsoHeader { static constexpr u32 Magic = util::FourCC<'N','S','O','0'>::Code; enum Segment : size_t { Segment_Text = 0, Segment_Ro = 1, Segment_Rw = 2, Segment_Count, }; enum Flag : u32 { Flag_CompressedText = (1 << 0), Flag_CompressedRo = (1 << 1), Flag_CompressedRw = (1 << 2), Flag_CheckHashText = (1 << 3), Flag_CheckHashRo = (1 << 4), Flag_CheckHashRw = (1 << 5), Flag_PreventCodeReads = (1 << 6), }; struct SegmentInfo { u32 file_offset; u32 dst_offset; u32 size; u32 reserved; }; u32 magic; u32 version; u32 reserved_08; u32 flags; union { struct { u32 text_file_offset; u32 text_dst_offset; u32 text_size; u32 unk_file_offset; u32 ro_file_offset; u32 ro_dst_offset; u32 ro_size; u32 unk_size; u32 rw_file_offset; u32 rw_dst_offset; u32 rw_size; u32 bss_size; }; SegmentInfo segments[Segment_Count]; }; u8 module_id[sizeof(ModuleInfo::module_id)]; union { u32 compressed_sizes[Segment_Count]; struct { u32 text_compressed_size; u32 ro_compressed_size; u32 rw_compressed_size; }; }; u8 reserved_6C[0x34]; union { u8 segment_hashes[Segment_Count][crypto::Sha256Generator::HashSize]; struct { u8 text_hash[crypto::Sha256Generator::HashSize]; u8 ro_hash[crypto::Sha256Generator::HashSize]; u8 rw_hash[crypto::Sha256Generator::HashSize]; }; }; }; static_assert(sizeof(NsoHeader) == 0x100 && util::is_pod<NsoHeader>::value, "NsoHeader definition!"); /* NPDM types. */ struct Aci { static constexpr u32 Magic = util::FourCC<'A','C','I','0'>::Code; u32 magic; u8 reserved_04[0xC]; ncm::ProgramId program_id; u8 reserved_18[0x8]; u32 fah_offset; u32 fah_size; u32 sac_offset; u32 sac_size; u32 kac_offset; u32 kac_size; u8 reserved_38[0x8]; }; static_assert(sizeof(Aci) == 0x40 && util::is_pod<Aci>::value, "Aci definition!"); struct Acid { static constexpr u32 Magic = util::FourCC<'A','C','I','D'>::Code; enum AcidFlag { AcidFlag_Production = (1 << 0), AcidFlag_UnqualifiedApproval = (1 << 1), AcidFlag_DeprecatedUseSecureMemory = (1 << 2), AcidFlag_PoolPartitionShift = 2, AcidFlag_PoolPartitionMask = (0xF << AcidFlag_PoolPartitionShift), AcidFlag_LoadBrowserCoreDll = (1 << 7), }; enum PoolPartition { PoolPartition_Application = 0, PoolPartition_Applet = 1, PoolPartition_System = 2, PoolPartition_SystemNonSecure = 3, }; #if defined(ATMOSPHERE_OS_HORIZON) static_assert(PoolPartition_Application == (svc::CreateProcessFlag_PoolPartitionApplication >> svc::CreateProcessFlag_PoolPartitionShift)); static_assert(PoolPartition_Applet == (svc::CreateProcessFlag_PoolPartitionApplet >> svc::CreateProcessFlag_PoolPartitionShift)); static_assert(PoolPartition_System == (svc::CreateProcessFlag_PoolPartitionSystem >> svc::CreateProcessFlag_PoolPartitionShift)); static_assert(PoolPartition_SystemNonSecure == (svc::CreateProcessFlag_PoolPartitionSystemNonSecure >> svc::CreateProcessFlag_PoolPartitionShift)); #endif u8 signature[0x100]; u8 modulus[0x100]; u32 magic; u32 size; u8 version; u8 unknown_209; u8 reserved_20A[2]; u32 flags; ncm::ProgramId program_id_min; ncm::ProgramId program_id_max; u32 fac_offset; u32 fac_size; u32 sac_offset; u32 sac_size; u32 kac_offset; u32 kac_size; u8 reserved_238[0x8]; }; static_assert(sizeof(Acid) == 0x240 && util::is_pod<Acid>::value, "Acid definition!"); struct Npdm { static constexpr u32 Magic = util::FourCC<'M','E','T','A'>::Code; enum MetaFlag { MetaFlag_Is64Bit = (1 << 0), MetaFlag_AddressSpaceTypeShift = 1, MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift), MetaFlag_OptimizeMemoryAllocation = (1 << 4), MetaFlag_DisableDeviceAddressSpaceMerge = (1 << 5), MetaFlag_EnableAliasRegionExtraSize = (1 << 6), MetaFlag_PreventCodeReads = (1 << 7), }; enum AddressSpaceType { AddressSpaceType_32Bit = 0, AddressSpaceType_64BitDeprecated = 1, AddressSpaceType_32BitWithoutAlias = 2, AddressSpaceType_64Bit = 3, }; #if defined(ATMOSPHERE_OS_HORIZON) static_assert(AddressSpaceType_32Bit == (svc::CreateProcessFlag_AddressSpace32Bit >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_64BitDeprecated == (svc::CreateProcessFlag_AddressSpace64BitDeprecated >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_32BitWithoutAlias == (svc::CreateProcessFlag_AddressSpace32BitWithoutAlias >> svc::CreateProcessFlag_AddressSpaceShift)); static_assert(AddressSpaceType_64Bit == (svc::CreateProcessFlag_AddressSpace64Bit >> svc::CreateProcessFlag_AddressSpaceShift)); #endif u32 magic; u32 signature_key_generation; u8 reserved_08[4]; u8 flags; u8 reserved_0D; u8 main_thread_priority; u8 default_cpu_id; u8 reserved_10[4]; u32 system_resource_size; u32 version; u32 main_thread_stack_size; char program_name[0x10]; char product_code[0x10]; u8 reserved_40[0x30]; u32 aci_offset; u32 aci_size; u32 acid_offset; u32 acid_size; }; static_assert(sizeof(Npdm) == 0x80 && util::is_pod<Npdm>::value, "Npdm definition!"); struct ProgramAttributes { ncm::ContentMetaPlatform platform; fs::ContentAttributes content_attributes; }; static_assert(sizeof(ProgramAttributes) == 2 && util::is_pod<ProgramAttributes>::value, "ProgramAttributes definition!"); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ldr.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ldr/ldr_types.hpp> #include <stratosphere/ldr/ldr_shell_api.hpp> #include <stratosphere/ldr/ldr_pm_api.hpp> #include <stratosphere/ldr/impl/ldr_process_manager_interface.hpp> #include <stratosphere/ldr/impl/ldr_debug_monitor_interface.hpp> #include <stratosphere/ldr/impl/ldr_shell_interface.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/lm/lm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::lm { void Initialize(); void Finalize(); void SetDestination(u32 destination); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lm/lm_log_getter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::lm { void StartLogging(); void StopLogging(); void GetLog(char *dst, size_t size, s64 *out_write_size, u32 *out_drop_count); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lm/lm_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::lm { enum LogDestination { LogDestination_TargetManager = (1 << 0), LogDestination_Uart = (1 << 1), LogDestination_UartIfSleep = (1 << 2), LogDestination_All = 0xFFFF, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lm/lm_types.hpp> #include <stratosphere/lm/lm_api.hpp> #include <stratosphere/lm/lm_log_getter.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/lmem/impl/lmem_impl_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> namespace ams::lmem::impl { /* NOTE: Nintendo does not use util::IntrusiveListNode. */ /* They seem to manually manage linked list pointers. */ /* This is pretty gross, so we're going to use util::IntrusiveListNode. */ struct ExpHeapMemoryBlockHead { u16 magic; u32 attributes; size_t block_size; util::IntrusiveListNode list_node; }; static_assert(std::is_trivially_destructible<ExpHeapMemoryBlockHead>::value); using ExpHeapMemoryBlockList = typename util::IntrusiveListMemberTraits<&ExpHeapMemoryBlockHead::list_node>::ListType; struct ExpHeapHead { ExpHeapMemoryBlockList free_list; ExpHeapMemoryBlockList used_list; u16 group_id; u16 mode; bool use_alignment_margins; char pad[3]; }; static_assert(sizeof(ExpHeapHead) == 0x28); static_assert(std::is_trivially_destructible<ExpHeapHead>::value); struct FrameHeapHead { void *next_block_head; void *next_block_tail; }; static_assert(sizeof(FrameHeapHead) == 0x10); static_assert(std::is_trivially_destructible<FrameHeapHead>::value); struct UnitHead { UnitHead *next; }; struct UnitHeapList { UnitHead *head; }; struct UnitHeapHead { UnitHeapList free_list; size_t unit_size; s32 alignment; s32 num_units; }; static_assert(sizeof(UnitHeapHead) == 0x18); static_assert(std::is_trivially_destructible<UnitHeapHead>::value); union ImplementationHeapHead { ExpHeapHead exp_heap_head; FrameHeapHead frame_heap_head; UnitHeapHead unit_heap_head; }; struct HeapHead { u32 magic; util::IntrusiveListNode list_node; using ChildListTraits = util::IntrusiveListMemberTraits<&HeapHead::list_node>; using ChildList = ChildListTraits::ListType; ChildList child_list; void *heap_start; void *heap_end; os::SdkMutexType mutex; u8 option; ImplementationHeapHead impl_head; }; static_assert(std::is_trivially_destructible<HeapHead>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lmem/lmem_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lmem/impl/lmem_impl_common.hpp> namespace ams::lmem { enum CreateOption { CreateOption_None = (0), CreateOption_ZeroClear = (1 << 0), CreateOption_DebugFill = (1 << 1), CreateOption_ThreadSafe = (1 << 2), }; enum FillType { FillType_Unallocated, FillType_Allocated, FillType_Freed, FillType_Count, }; namespace impl { struct HeapHead; } using HeapHandle = impl::HeapHead *; using HeapCommonHead = impl::HeapHead; struct MemoryRange { uintptr_t address; size_t size; }; constexpr inline s32 DefaultAlignment = 0x8; /* Common API. */ u32 GetDebugFillValue(FillType fill_type); void SetDebugFillValue(FillType fill_type, u32 value); size_t GetTotalSize(HeapHandle handle); void *GetStartAddress(HeapHandle handle); bool ContainsAddress(HeapHandle handle, const void *address); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lmem/lmem_exp_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lmem/lmem_common.hpp> namespace ams::lmem { enum AllocationMode { AllocationMode_FirstFit, AllocationMode_BestFit, }; enum AllocationDirection { AllocationDirection_Front, AllocationDirection_Back, }; using HeapVisitor = void (*)(void *block, HeapHandle handle, uintptr_t user_data); HeapHandle CreateExpHeap(void *address, size_t size, u32 option); void DestroyExpHeap(HeapHandle handle); MemoryRange AdjustExpHeap(HeapHandle handle); void *AllocateFromExpHeap(HeapHandle handle, size_t size); void *AllocateFromExpHeap(HeapHandle handle, size_t size, s32 alignment); void FreeToExpHeap(HeapHandle handle, void *block); size_t ResizeExpHeapMemoryBlock(HeapHandle handle, void *block, size_t size); size_t GetExpHeapTotalFreeSize(HeapHandle handle); size_t GetExpHeapAllocatableSize(HeapHandle handle, s32 alignment); AllocationMode GetExpHeapAllocationMode(HeapHandle handle); AllocationMode SetExpHeapAllocationMode(HeapHandle handle, AllocationMode new_mode); bool GetExpHeapUseMarginsOfAlignment(HeapHandle handle); bool SetExpHeapUseMarginsOfAlignment(HeapHandle handle, bool use_margins); u16 GetExpHeapGroupId(HeapHandle handle); u16 SetExpHeapGroupId(HeapHandle handle, u16 group_id); size_t GetExpHeapMemoryBlockSize(const void *memory_block); u16 GetExpHeapMemoryBlockGroupId(const void *memory_block); AllocationDirection GetExpHeapMemoryBlockAllocationDirection(const void *memory_block); void VisitExpHeapAllocatedBlocks(HeapHandle handle, HeapVisitor visitor, uintptr_t user_data); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lmem/lmem_unit_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lmem/lmem_common.hpp> namespace ams::lmem { enum InfoPlacement { InfoPlacement_Head, InfoPlacement_Tail, }; HeapHandle CreateUnitHeap(void *address, size_t size, size_t unit_size, u32 option); HeapHandle CreateUnitHeap(void *address, size_t size, size_t unit_size, u32 option, s32 alignment, InfoPlacement info_placement); HeapHandle CreateUnitHeap(void *address, size_t size, size_t unit_size, u32 option, s32 alignment, HeapCommonHead *heap_head); void DestroyUnitHeap(HeapHandle handle); void InvalidateUnitHeap(HeapHandle handle); void ExtendUnitHeap(HeapHandle handle, size_t size); void *AllocateFromUnitHeap(HeapHandle handle); void FreeToUnitHeap(HeapHandle handle, void *block); size_t GetUnitHeapUnitSize(HeapHandle handle); s32 GetUnitHeapAlignment(HeapHandle handle); size_t GetUnitHeapFreeCount(HeapHandle handle); size_t GetUnitHeapUsedCount(HeapHandle handle); size_t GetUnitHeapRequiredSize(size_t unit_size, size_t unit_count, s32 alignment, bool internal_metadata); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lmem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lmem/lmem_common.hpp> #include <stratosphere/lmem/lmem_exp_heap.hpp> #include <stratosphere/lmem/lmem_unit_heap.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_add_on_content_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_i_add_on_content_location_resolver.hpp> namespace ams::lr { class AddOnContentLocationResolver { NON_COPYABLE(AddOnContentLocationResolver); private: sf::SharedPointer<IAddOnContentLocationResolver> m_interface; public: AddOnContentLocationResolver() : m_interface(nullptr) { /* ... */ } explicit AddOnContentLocationResolver(sf::SharedPointer<IAddOnContentLocationResolver> intf) : m_interface(intf) { /* ... */ } AddOnContentLocationResolver(AddOnContentLocationResolver &&rhs) { m_interface = std::move(rhs.m_interface); } AddOnContentLocationResolver &operator=(AddOnContentLocationResolver &&rhs) { AddOnContentLocationResolver(std::move(rhs)).Swap(*this); return *this; } void Swap(AddOnContentLocationResolver &rhs) { std::swap(m_interface, rhs.m_interface); } public: /* Actual commands. */ Result ResolveAddOnContentPath(Path *out, ncm::DataId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveAddOnContentPath(out, id)); } Result RegisterAddOnContentStorage(ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_RETURN(m_interface->RegisterAddOnContentStorage(id, application_id, storage_id)); } else { R_RETURN(m_interface->RegisterAddOnContentStorageDeprecated(id, storage_id)); } } Result UnregisterAllAddOnContentPath() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->UnregisterAllAddOnContentPath()); } Result RefreshApplicationAddOnContent(const ncm::ApplicationId *ids, size_t num_ids) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->RefreshApplicationAddOnContent(sf::InArray<ncm::ApplicationId>(ids, num_ids))); } Result UnregisterApplicationAddOnContent(ncm::ApplicationId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->UnregisterApplicationAddOnContent(id)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_location_resolver.hpp> #include <stratosphere/lr/lr_add_on_content_location_resolver.hpp> #include <stratosphere/lr/lr_registered_location_resolver.hpp> namespace ams::lr { /* Management. */ void Initialize(); void Finalize(); /* Service API. */ Result OpenLocationResolver(LocationResolver *out, ncm::StorageId storage_id); Result OpenRegisteredLocationResolver(RegisteredLocationResolver *out); Result OpenAddOnContentLocationResolver(AddOnContentLocationResolver *out); Result RefreshLocationResolver(ncm::StorageId storage_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_i_add_on_content_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #define AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveAddOnContentPath, (sf::Out<lr::Path> out, ncm::DataId id), (out, id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorageDeprecated, (ncm::DataId id, ncm::StorageId storage_id), (id, storage_id), hos::Version_2_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterAddOnContentStorage, (ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id), (id, application_id, storage_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 2, Result, UnregisterAllAddOnContentPath, (), (), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 3, Result, RefreshApplicationAddOnContent, (const sf::InArray<ncm::ApplicationId> &ids), (ids), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, UnregisterApplicationAddOnContent, (ncm::ApplicationId id), (id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetRegisteredAddOnContentPaths, (sf::Out<lr::PathByMapAlias> out, sf::Out<lr::PathByMapAlias> out2, ncm::DataId id), (out, out2, id), hos::Version_15_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, RegisterAddOnContentPath, (ncm::DataId id, ncm::ApplicationId application_id, const lr::PathByMapAlias &path), (id, application_id, path), hos::Version_15_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, RegisterAddOnContentPaths, (ncm::DataId id, ncm::ApplicationId application_id, const lr::PathByMapAlias &path, const lr::PathByMapAlias &path2), (id, application_id, path, path2), hos::Version_15_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, IAddOnContentLocationResolver, AMS_LR_I_ADD_ON_CONTENT_LOCATION_RESOLVER_INTERFACE_INFO, 0x77617E39) ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #define AMS_LR_I_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveProgramPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RedirectProgramPath, (const lr::Path &path, ncm::ProgramId id), (path, id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, ResolveApplicationControlPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, ResolveApplicationHtmlDocumentPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, ResolveDataPath, (sf::Out<lr::Path> out, ncm::DataId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, RedirectApplicationControlPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_1_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 5, Result, RedirectApplicationControlPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, RedirectApplicationHtmlDocumentPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_1_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 6, Result, RedirectApplicationHtmlDocumentPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, ResolveApplicationLegalInformationPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, RedirectApplicationLegalInformationPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_1_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 8, Result, RedirectApplicationLegalInformationPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, Refresh, (), ()) \ AMS_SF_METHOD_INFO(C, H, 10, Result, RedirectApplicationProgramPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_5_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 10, Result, RedirectApplicationProgramPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 11, Result, ClearApplicationRedirectionDeprecated, (), (), hos::Version_5_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 11, Result, ClearApplicationRedirection, (const sf::InArray<ncm::ProgramId> &excluding_ids), (excluding_ids), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 12, Result, EraseProgramRedirection, (ncm::ProgramId id), (id), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 13, Result, EraseApplicationControlRedirection, (ncm::ProgramId id), (id), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 14, Result, EraseApplicationHtmlDocumentRedirection, (ncm::ProgramId id), (id), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 15, Result, EraseApplicationLegalInformationRedirection, (ncm::ProgramId id), (id), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 16, Result, ResolveProgramPathForDebug, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 17, Result, RedirectProgramPathForDebug, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 18, Result, RedirectApplicationProgramPathForDebugDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_7_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 18, Result, RedirectApplicationProgramPathForDebug, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 19, Result, EraseProgramRedirectionForDebug, (ncm::ProgramId id), (id), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, Disable, (), (), hos::Version_15_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, ILocationResolver, AMS_LR_I_LOCATION_RESOLVER_INTERFACE_INFO, 0xB36C8B0E) ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_i_location_resolver_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_i_location_resolver.hpp> #include <stratosphere/lr/lr_i_add_on_content_location_resolver.hpp> #include <stratosphere/lr/lr_i_registered_location_resolver.hpp> #define AMS_LR_I_LOCATION_RESOLVER_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenLocationResolver, (sf::Out<ams::sf::SharedPointer<lr::ILocationResolver>> out, ncm::StorageId storage_id), (out, storage_id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, OpenRegisteredLocationResolver, (sf::Out<ams::sf::SharedPointer<lr::IRegisteredLocationResolver>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, RefreshLocationResolver, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, OpenAddOnContentLocationResolver, (sf::Out<ams::sf::SharedPointer<lr::IAddOnContentLocationResolver>> out), (out), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, SetEnabled, (const ams::sf::InMapAliasArray<ncm::StorageId> &storages), (storages), hos::Version_15_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, ILocationResolverManager, AMS_LR_I_LOCATION_RESOLVER_MANAGER_INTERFACE_INFO, 0xB2950191) ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_i_registered_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #define AMS_LR_I_REGISTERED_LOCATION_RESOLVER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ResolveProgramPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterProgramPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_1_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterProgramPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 2, Result, UnregisterProgramPath, (ncm::ProgramId id), (id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, RedirectProgramPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_1_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 3, Result, RedirectProgramPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, ResolveHtmlDocumentPath, (sf::Out<lr::Path> out, ncm::ProgramId id), (out, id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, RegisterHtmlDocumentPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_2_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 5, Result, RegisterHtmlDocumentPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, UnregisterHtmlDocumentPath, (ncm::ProgramId id), (id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, RedirectHtmlDocumentPathDeprecated, (const lr::Path &path, ncm::ProgramId id), (path, id), hos::Version_2_0_0, hos::Version_8_1_1) \ AMS_SF_METHOD_INFO(C, H, 7, Result, RedirectHtmlDocumentPath, (const lr::Path &path, ncm::ProgramId id, ncm::ProgramId owner_id), (path, id, owner_id), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, Refresh, (), (), hos::Version_7_0_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, RefreshExcluding, (const sf::InArray<ncm::ProgramId> &ids), (ids), hos::Version_9_0_0) AMS_SF_DEFINE_INTERFACE(ams::lr, IRegisteredLocationResolver, AMS_LR_I_REGISTERED_LOCATION_RESOLVER_INTERFACE_INFO, 0x35346AC9) ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_i_location_resolver.hpp> namespace ams::lr { class LocationResolver { NON_COPYABLE(LocationResolver); private: sf::SharedPointer<ILocationResolver> m_interface; public: LocationResolver() : m_interface(nullptr) { /* ... */ } explicit LocationResolver(sf::SharedPointer<ILocationResolver> intf) : m_interface(intf) { /* ... */ } LocationResolver(LocationResolver &&rhs) { m_interface = std::move(rhs.m_interface); } LocationResolver &operator=(LocationResolver &&rhs) { LocationResolver(std::move(rhs)).swap(*this); return *this; } void swap(LocationResolver &rhs) { std::swap(m_interface, rhs.m_interface); } public: Result ResolveProgramPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveProgramPath(out, id)); } void RedirectProgramPath(const Path &path, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_ABORT_UNLESS(m_interface->RedirectProgramPath(path, id)); } Result ResolveApplicationControlPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveApplicationControlPath(out, id)); } Result ResolveApplicationHtmlDocumentPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveApplicationHtmlDocumentPath(out, id)); } Result ResolveDataPath(Path *out, ncm::DataId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveDataPath(out, id)); } void RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectApplicationControlPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectApplicationControlPathDeprecated(path, id)); } } void RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectApplicationHtmlDocumentPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectApplicationHtmlDocumentPathDeprecated(path, id)); } } Result ResolveApplicationLegalInformationPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveApplicationLegalInformationPath(out, id)); } void RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectApplicationLegalInformationPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectApplicationLegalInformationPathDeprecated(path, id)); } } Result Refresh() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Refresh()); } void RedirectApplicationProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectApplicationProgramPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectApplicationProgramPathDeprecated(path, id)); } } Result ClearApplicationRedirection() { AMS_ASSERT(m_interface != nullptr); AMS_ASSERT(hos::GetVersion() < hos::Version_9_0_0); R_RETURN(this->ClearApplicationRedirection(nullptr, 0)); } Result ClearApplicationRedirection(const ncm::ProgramId *excluding_ids, size_t num_ids) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_RETURN(m_interface->ClearApplicationRedirection(sf::InArray<ncm::ProgramId>(excluding_ids, num_ids))); } else { R_RETURN(m_interface->ClearApplicationRedirectionDeprecated()); } } Result EraseProgramRedirection(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseProgramRedirection(id)); } Result EraseApplicationControlRedirection(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseApplicationControlRedirection(id)); } Result EraseApplicationHtmlDocumentRedirection(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseApplicationHtmlDocumentRedirection(id)); } Result EraseApplicationLegalInformationRedirection(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseApplicationLegalInformationRedirection(id)); } Result ResolveProgramPathForDebug(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveProgramPathForDebug(out, id)); } void RedirectProgramPathForDebug(const Path &path, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_ABORT_UNLESS(m_interface->RedirectProgramPathForDebug(path, id)); } void RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectApplicationProgramPathForDebug(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectApplicationProgramPathForDebugDeprecated(path, id)); } } Result EraseProgramRedirectionForDebug(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->EraseProgramRedirectionForDebug(id)); } Result Disable() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Disable()); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_location_resolver_manager_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_i_location_resolver_manager.hpp> #include <stratosphere/ncm/ncm_bounded_map.hpp> namespace ams::lr { class LocationResolverManagerImpl { private: static constexpr size_t ResolverCountMax = 5; private: /* Resolver storage. */ ncm::BoundedMap<ncm::StorageId, sf::SharedPointer<ILocationResolver>, ResolverCountMax> m_location_resolvers{}; ncm::BoundedMap<ncm::StorageId, bool, ResolverCountMax> m_location_resolvers_enabled{}; bool m_default_enabled = true; sf::SharedPointer<IRegisteredLocationResolver> m_registered_location_resolver = nullptr; sf::SharedPointer<IAddOnContentLocationResolver> m_add_on_content_location_resolver = nullptr; os::SdkMutex m_mutex{}; public: /* Actual commands. */ Result OpenLocationResolver(sf::Out<sf::SharedPointer<ILocationResolver>> out, ncm::StorageId storage_id); Result OpenRegisteredLocationResolver(sf::Out<sf::SharedPointer<IRegisteredLocationResolver>> out); Result RefreshLocationResolver(ncm::StorageId storage_id); Result OpenAddOnContentLocationResolver(sf::Out<sf::SharedPointer<IAddOnContentLocationResolver>> out); Result SetEnabled(const sf::InMapAliasArray<ncm::StorageId> &storages); }; static_assert(IsILocationResolverManager<LocationResolverManagerImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_registered_location_resolver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_i_registered_location_resolver.hpp> namespace ams::lr { class RegisteredLocationResolver { NON_COPYABLE(RegisteredLocationResolver); private: sf::SharedPointer<IRegisteredLocationResolver> m_interface; public: RegisteredLocationResolver() : m_interface(nullptr) { /* ... */ } explicit RegisteredLocationResolver(sf::SharedPointer<IRegisteredLocationResolver> intf) : m_interface(intf) { /* ... */ } RegisteredLocationResolver(RegisteredLocationResolver &&rhs) { m_interface = std::move(rhs.m_interface); } RegisteredLocationResolver &operator=(RegisteredLocationResolver &&rhs) { RegisteredLocationResolver(std::move(rhs)).Swap(*this); return *this; } void Swap(RegisteredLocationResolver &rhs) { std::swap(m_interface, rhs.m_interface); } public: /* Actual commands. */ Result ResolveProgramPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveProgramPath(out, id)); } Result RegisterProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_RETURN(m_interface->RegisterProgramPath(path, id, owner_id)); } else { R_RETURN(m_interface->RegisterProgramPathDeprecated(path, id)); } } Result UnregisterProgramPath(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->UnregisterProgramPath(id)); } void RedirectProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectProgramPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectProgramPathDeprecated(path, id)); } } Result ResolveHtmlDocumentPath(Path *out, ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ResolveHtmlDocumentPath(out, id)); } Result RegisterHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_RETURN(m_interface->RegisterHtmlDocumentPath(path, id, owner_id)); } else { R_RETURN(m_interface->RegisterHtmlDocumentPathDeprecated(path, id)); } } Result UnregisterHtmlDocumentPath(ncm::ProgramId id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->UnregisterHtmlDocumentPath(id)); } void RedirectHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) { AMS_ASSERT(m_interface != nullptr); if (hos::GetVersion() >= hos::Version_9_0_0) { R_ABORT_UNLESS(m_interface->RedirectHtmlDocumentPath(path, id, owner_id)); } else { R_ABORT_UNLESS(m_interface->RedirectHtmlDocumentPathDeprecated(path, id)); } } Result Refresh() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Refresh()); } Result RefreshExcluding(const ncm::ProgramId *excluding_ids, size_t num_ids) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->RefreshExcluding(sf::InArray<ncm::ProgramId>(excluding_ids, num_ids))); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr/lr_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::lr { struct alignas(4) Path : ams::sf::LargeData { char str[fs::EntryNameLengthMax]; static constexpr Path Encode(const char *p) { Path path = {}; /* Copy C string to path, terminating when a null byte is found. */ for (size_t i = 0; i < sizeof(path) - 1; i++) { path.str[i] = p[i]; if (p[i] == '\x00') { break; } } return path; } constexpr inline size_t GetLength() const { /* Determine length from the first null byte occurence. */ size_t len = 0; for (size_t i = 0; i < sizeof(this->str) - 1 && this->str[i] != '\x00'; i++) { len++; } return len; } constexpr inline bool IsValid() const { /* Determine validity by presence of a terminating null byte. */ for (size_t i = 0; i < sizeof(this->str); i++) { if (this->str[i] == '\x00') { return true; } } return false; } }; static_assert(util::is_pod<Path>::value && sizeof(Path) == fs::EntryNameLengthMax); struct PathByMapAlias : public Path, ams::sf::PrefersMapAliasTransferMode{}; static_assert(util::is_pod<PathByMapAlias>::value); static_assert(sizeof(PathByMapAlias) == sizeof(Path)); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/lr.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/lr/lr_types.hpp> #include <stratosphere/lr/lr_api.hpp> #include <stratosphere/lr/lr_location_resolver_manager_impl.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_cached_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/mem/impl/mem_impl_common.hpp> namespace ams::mem::impl::heap { class TlsHeapCache; class CachedHeap final { NON_COPYABLE(CachedHeap); private: TlsHeapCache *m_tls_heap_cache; public: constexpr CachedHeap() : m_tls_heap_cache() { /* ... */ } ~CachedHeap() { this->Finalize(); } ALWAYS_INLINE CachedHeap(CachedHeap &&rhs) : m_tls_heap_cache(rhs.m_tls_heap_cache) { rhs.m_tls_heap_cache = nullptr; } ALWAYS_INLINE CachedHeap &operator=(CachedHeap &&rhs) { this->Reset(); m_tls_heap_cache = rhs.m_tls_heap_cache; rhs.m_tls_heap_cache = nullptr; return *this; } void *Allocate(size_t n); void *Allocate(size_t n, size_t align); size_t GetAllocationSize(const void *ptr); errno_t Free(void *p); errno_t FreeWithSize(void *p, size_t size); errno_t Reallocate(void *ptr, size_t size, void **p); errno_t Shrink(void *ptr, size_t size); void ReleaseAllCache(); void Finalize(); bool CheckCache(); errno_t QueryV(int query, std::va_list vl); errno_t Query(int query, ...); void Reset() { this->Finalize(); } void Reset(TlsHeapCache *thc); TlsHeapCache *Release(); constexpr explicit ALWAYS_INLINE operator bool() const { return m_tls_heap_cache != nullptr; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/mem/impl/mem_impl_common.hpp> #include <stratosphere/mem/impl/mem_impl_declarations.hpp> namespace ams::mem::impl::heap { class CachedHeap; class TlsHeapCentral; using HeapWalkCallback = int (*)(void *ptr, size_t size, void *user_data); class CentralHeap final { NON_COPYABLE(CentralHeap); NON_MOVEABLE(CentralHeap); public: static constexpr size_t PageSize = 4_KB; static constexpr size_t MinimumAlignment = alignof(u64); using DestructorHandler = void (*)(void *start, void *end); private: TlsHeapCentral *m_tls_heap_central; bool m_use_virtual_memory; u32 m_option; u8 *m_start; u8 *m_end; public: constexpr CentralHeap() : m_tls_heap_central(), m_use_virtual_memory(), m_option(), m_start(), m_end() { /* ... */ } ~CentralHeap() { this->Finalize(); } errno_t Initialize(void *start, size_t size, u32 option); void Finalize(); ALWAYS_INLINE void *Allocate(size_t n) { return this->Allocate(n, MinimumAlignment); } void *Allocate(size_t n, size_t align); size_t GetAllocationSize(const void *ptr); errno_t Free(void *p); errno_t FreeWithSize(void *p, size_t size); errno_t Reallocate(void *ptr, size_t size, void **p); errno_t Shrink(void *ptr, size_t size); bool MakeCache(CachedHeap *cached_heap); errno_t WalkAllocatedPointers(HeapWalkCallback callback, void *user_data); errno_t QueryV(int query, std::va_list vl); errno_t Query(int query, ...); }; static_assert(sizeof(CentralHeap) <= sizeof(::ams::mem::impl::InternalCentralHeapStorage)); static_assert(alignof(CentralHeap) <= alignof(void *)); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/impl/mem_impl_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <errno.h> namespace ams::mem::impl { constexpr inline size_t MaxSize = static_cast<size_t>(std::numeric_limits<s64>::max()); using errno_t = int; enum DumpMode { DumpMode_Basic = (0 << 0), DumpMode_Spans = (1 << 0), DumpMode_Pointers = (1 << 1), DumpMode_Pages = (1 << 2), DumpMode_All = (DumpMode_Pages | DumpMode_Pointers | DumpMode_Spans | DumpMode_Basic), }; enum AllocQuery { AllocQuery_Dump = 0, AllocQuery_PageSize = 1, AllocQuery_AllocatedSize = 2, AllocQuery_FreeSize = 3, AllocQuery_SystemSize = 4, AllocQuery_MaxAllocatableSize = 5, AllocQuery_IsClean = 6, AllocQuery_HeapHash = 7, AllocQuery_UnifyFreeList = 8, AllocQuery_SetColor = 9, AllocQuery_GetColor = 10, AllocQuery_SetName = 11, AllocQuery_GetName = 12, /* AllocQuery_Thirteen = 13, */ AllocQuery_CheckCache = 14, AllocQuery_ClearCache = 15, AllocQuery_FinalizeCache = 16, AllocQuery_FreeSizeMapped = 17, AllocQuery_MaxAllocatableSizeMapped = 18, AllocQuery_DumpJson = 19, }; enum HeapOption { HeapOption_UseEnvironment = (1 << 0), HeapOption_DisableCache = (1 << 2), }; struct HeapHash { size_t alloc_count; size_t alloc_size; size_t hash; }; static_assert(util::is_pod<HeapHash>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/impl/mem_impl_declarations.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::mem::impl { namespace heap { class CentralHeap; } using InternalCentralHeapStorage = ::ams::util::TypedStorage<::ams::mem::impl::heap::CentralHeap, sizeof(void *) * 6, alignof(void *)>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/impl/mem_impl_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/mem/impl/mem_impl_common.hpp> #include <stratosphere/mem/impl/heap/mem_impl_heap_cached_heap.hpp> #include <stratosphere/mem/impl/heap/mem_impl_heap_central_heap.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem/mem_standard_allocator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/mem/impl/mem_impl_declarations.hpp> namespace ams::mem { class StandardAllocator { NON_COPYABLE(StandardAllocator); NON_MOVEABLE(StandardAllocator); public: using WalkCallback = int (*)(void *ptr, size_t size, void *user_data); struct AllocatorHash { size_t allocated_count; size_t allocated_size; size_t hash; }; private: bool m_initialized; bool m_enable_thread_cache; uintptr_t m_unused; os::TlsSlot m_tls_slot; impl::InternalCentralHeapStorage m_central_heap_storage; public: StandardAllocator(); StandardAllocator(void *mem, size_t size); StandardAllocator(void *mem, size_t size, bool enable_cache); ~StandardAllocator() { if (m_initialized) { this->Finalize(); } } void Initialize(void *mem, size_t size); void Initialize(void *mem, size_t size, bool enable_cache); void Finalize(); void *Allocate(size_t size); void *Allocate(size_t size, size_t alignment); void Free(void *ptr); void *Reallocate(void *ptr, size_t new_size); size_t Shrink(void *ptr, size_t new_size); void ClearThreadCache() const; void CleanUpManagementArea() const; size_t GetSizeOf(const void *ptr) const; size_t GetTotalFreeSize() const; size_t GetAllocatableSize() const; void WalkAllocatedBlocks(WalkCallback callback, void *user_data) const; void Dump() const; AllocatorHash Hash() const; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mem.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/mem/mem_standard_allocator.hpp> #include <stratosphere/mem/impl/mem_impl_heap.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/mitm/impl/mitm_pm_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> #include <stratosphere/cfg/cfg_types.hpp> #include <stratosphere/sf.hpp> #define AMS_MITM_PM_IMPL_I_PM_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, PrepareLaunchProgram, (sf::Out<u64> out_boost_size, ncm::ProgramId program_id, const cfg::OverrideStatus &override_status, bool is_application), (out_boost_size, program_id, override_status, is_application)) AMS_SF_DEFINE_INTERFACE(ams::mitm::pm::impl, IPmInterface, AMS_MITM_PM_IMPL_I_PM_INTERFACE_INFO, 0xEA88789C) ================================================ FILE: libraries/libstratosphere/include/stratosphere/mitm/mitm_pm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> namespace ams::mitm::pm { /* PM API. */ void Initialize(); void Finalize(); Result PrepareLaunchProgram(u64 *out, ncm::ProgramId program_id, const cfg::OverrideStatus &status, bool is_application); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/mitm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/mitm/impl/mitm_pm_interface.hpp> #include <stratosphere/mitm/mitm_pm_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_meta_database.hpp> #include <stratosphere/ncm/ncm_content_storage.hpp> #include <stratosphere/ncm/ncm_i_content_manager.hpp> #include <stratosphere/fs/fs_content_storage_id.hpp> namespace ams::ncm { /* Management. */ void Initialize(); void Finalize(); void InitializeWithObject(sf::SharedPointer<IContentManager> manager_object); /* Service API. */ Result CreateContentStorage(StorageId storage_id); Result CreateContentMetaDatabase(StorageId storage_id); Result VerifyContentStorage(StorageId storage_id); Result VerifyContentMetaDatabase(StorageId storage_id); Result OpenContentStorage(ContentStorage *out, StorageId storage_id); Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id); Result CleanupContentMetaDatabase(StorageId storage_id); Result ActivateContentStorage(StorageId storage_id); Result InactivateContentStorage(StorageId storage_id); Result ActivateContentMetaDatabase(StorageId storage_id); Result InactivateContentMetaDatabase(StorageId storage_id); Result InvalidateRightsIdCache(); Result ActivateFsContentStorage(fs::ContentStorageId fs_content_storage_id); /* Deprecated API. */ Result CloseContentStorageForcibly(StorageId storage_id); Result CloseContentMetaDatabaseForcibly(StorageId storage_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_auto_buffer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { class AutoBuffer { NON_COPYABLE(AutoBuffer); private: u8 *m_buffer; size_t m_size; public: AutoBuffer() : m_buffer(nullptr), m_size(0) { /* ... */ } ~AutoBuffer() { this->Reset(); } AutoBuffer(AutoBuffer &&rhs) { m_buffer = rhs.m_buffer; m_size = rhs.m_size; rhs.m_buffer = nullptr; rhs.m_size = 0; } AutoBuffer &operator=(AutoBuffer &&rhs) { AutoBuffer(std::move(rhs)).Swap(*this); return *this; } void Swap(AutoBuffer &rhs) { std::swap(m_buffer, rhs.m_buffer); std::swap(m_size, rhs.m_size); } void Reset() { if (m_buffer != nullptr) { delete[] m_buffer; m_buffer = nullptr; m_size = 0; } } u8 *Get() const { return m_buffer; } size_t GetSize() const { return m_size; } Result Initialize(size_t size) { /* Check that we're not already initialized. */ AMS_ABORT_UNLESS(m_buffer == nullptr); /* Allocate a buffer. */ m_buffer = new (std::nothrow) u8[size]; R_UNLESS(m_buffer != nullptr, ncm::ResultAllocationFailed()); m_size = size; R_SUCCEED(); } Result Initialize(const void *buf, size_t size) { /* Create a new buffer of the right size. */ R_TRY(this->Initialize(size)); /* Copy the input data in. */ std::memcpy(m_buffer, buf, size); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_bounded_map.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { template<class Key, class Value, size_t N> using BoundedMap = util::BoundedMap<Key, Value, N>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct ContentId { util::Uuid uuid; bool operator==(const ContentId &other) const { return this->uuid == other.uuid; } bool operator!=(const ContentId &other) const { return this->uuid != other.uuid; } bool operator==(const util::Uuid &other) const { return this->uuid == other; } bool operator!=(const util::Uuid &other) const { return this->uuid != other; } }; static_assert(alignof(ContentId) == 1); constexpr inline ContentId InvalidContentId = { util::InvalidUuid }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_id_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_rights_id.hpp> #include <stratosphere/ncm/ncm_content_id.hpp> #include <stratosphere/ncm/ncm_content_info_data.hpp> namespace ams::ncm { constexpr inline size_t ContentIdStringLength = 2 * sizeof(ContentId); constexpr inline size_t RightsIdStringLength = 2 * sizeof(fs::RightsId); constexpr inline size_t TicketFileStringLength = RightsIdStringLength + 4; constexpr inline size_t CertFileStringLength = RightsIdStringLength + 5; struct ContentIdString { char data[ContentIdStringLength + 1]; }; ContentIdString GetContentIdString(ContentId id); void GetStringFromContentId(char *dst, size_t dst_size, ContentId id); void GetStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id); void GetTicketFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id); void GetCertificateFileStringFromRightsId(char *dst, size_t dst_size, fs::RightsId id); util::optional<ContentId> GetContentIdFromString(const char *str, size_t len); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_content_attributes.hpp> #include <stratosphere/ncm/ncm_content_id.hpp> #include <stratosphere/ncm/ncm_content_type.hpp> namespace ams::ncm { struct ContentInfo { static constexpr fs::ContentAttributes DefaultContentAttributes = fs::ContentAttributes_None; ContentId content_id; u32 size_low; u8 size_high; u8 content_attributes; ContentType content_type; u8 id_offset; constexpr const ContentId &GetId() const { return this->content_id; } constexpr u64 GetSize() const { return (static_cast<u64>(this->size_high) << 32) | static_cast<u64>(this->size_low); } constexpr fs::ContentAttributes GetContentAttributes() const { return static_cast<fs::ContentAttributes>(this->content_attributes & 0xF); } constexpr ContentType GetType() const { return this->content_type; } constexpr u8 GetIdOffset() const { return this->id_offset; } static constexpr ContentInfo Make(ContentId id, u64 size, fs::ContentAttributes attr, ContentType type, u8 id_ofs = 0) { const u32 size_low = size & 0xFFFFFFFFu; const u8 size_high = static_cast<u8>(size >> 32); return { .content_id = id, .size_low = size_low, .size_high = size_high, .content_attributes = attr, .content_type = type, .id_offset = id_ofs, }; } }; static_assert(sizeof(util::is_pod<ContentInfo>::value)); static_assert(sizeof(ContentInfo) == 0x18); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_info_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_info.hpp> #include <stratosphere/ncm/ncm_content_storage.hpp> #include <stratosphere/ncm/ncm_storage_id.hpp> #include <stratosphere/ncm/ncm_content_meta_key.hpp> namespace ams::ncm { struct Digest { u8 data[crypto::Sha256Generator::HashSize]; }; enum class InstallState : u8 { NotPrepared, Prepared, Installed, AlreadyExists, }; struct PackagedContentInfo { Digest digest; ContentInfo info; constexpr const ContentId &GetId() const { return this->info.GetId(); } constexpr fs::ContentAttributes GetContentAttributes() const { return this->info.GetContentAttributes(); } constexpr ContentType GetType() const { return this->info.GetType(); } constexpr u8 GetIdOffset() const { return this->info.GetIdOffset(); } }; struct InstallContentInfo { Digest digest; crypto::Sha256Context context; u8 buffered_data[crypto::Sha256Generator::BlockSize]; u64 buffered_data_size; ContentInfo info; PlaceHolderId placeholder_id; ContentMetaType meta_type; InstallState install_state; bool verify_digest; StorageId storage_id; bool is_temporary; bool is_sha256_calculated; s64 written; constexpr const ContentId &GetId() const { return this->info.GetId(); } constexpr u64 GetSize() const { return this->info.GetSize(); } constexpr fs::ContentAttributes GetContentAttributes() const { return this->info.GetContentAttributes(); } constexpr ContentType GetType() const { return this->info.GetType(); } constexpr u8 GetIdOffset() const { return this->info.GetIdOffset(); } constexpr const PlaceHolderId &GetPlaceHolderId() const { return this->placeholder_id; } constexpr ContentMetaType GetContentMetaType() const { return this->meta_type; } constexpr InstallState GetInstallState() const { return this->install_state; } constexpr StorageId GetStorageId() const { return this->storage_id; } constexpr s64 GetSizeWritten() const { return this->written; } static constexpr InstallContentInfo Make(const ContentInfo &info, ContentMetaType meta_type) { return { .info = info, .meta_type = meta_type, }; } static constexpr InstallContentInfo Make(const PackagedContentInfo &info, ContentMetaType meta_type) { return { .digest = info.digest, .info = info.info, .meta_type = meta_type, .verify_digest = true, }; } }; static_assert(sizeof(InstallContentInfo) == 0xC8); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_info_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_content_meta_key.hpp> namespace ams::ncm { constexpr inline s64 MaxClusterSize = 256_KB; s64 CalculateRequiredSize(s64 file_size, s64 cluster_size = MaxClusterSize); s64 CalculateRequiredSizeForExtension(s64 file_size, s64 cluster_size = MaxClusterSize); class ContentMetaDatabase; Result EstimateRequiredSize(s64 *out_size, const ContentMetaKey &key, ContentMetaDatabase *db); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_management_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_meta.hpp> #include <stratosphere/ncm/ncm_content_meta_database.hpp> #include <stratosphere/ncm/ncm_content_storage.hpp> namespace ams::ncm { class ContentMetaDatabaseBuilder { private: ContentMetaDatabase *m_db; private: Result BuildFromPackageContentMeta(void *buf, size_t size, const ContentInfo &meta_info); public: explicit ContentMetaDatabaseBuilder(ContentMetaDatabase *d) : m_db(d) { /* ... */ } Result BuildFromStorage(ContentStorage *storage); Result BuildFromPackage(const char *package_root_path); Result Cleanup(); }; Result ListApplicationPackage(s32 *out_count, ApplicationId *out_ids, s32 max_out_ids, const char *package_root_path); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_manager_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct ContentManagerConfig { bool build_system_database; bool import_database_from_system_on_sd; bool enable_integrated_system_content; bool HasAnyConfig() const { return this->ShouldBuildDatabase() || this->import_database_from_system_on_sd || this->enable_integrated_system_content; } bool ShouldBuildDatabase() const { return hos::GetVersion() < hos::Version_4_0_0 || this->build_system_database; } bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const { return this->import_database_from_system_on_sd; } bool IsIntegratedSystemContentEnabled() const { return this->enable_integrated_system_content; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_manager_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/fs/fs_mount.hpp> #include <stratosphere/fs/fs_bis.hpp> #include <stratosphere/fs/fs_content_storage.hpp> #include <stratosphere/fs/fs_system_save_data.hpp> #include <stratosphere/ncm/ncm_i_content_manager.hpp> #include <stratosphere/ncm/ncm_content_manager_config.hpp> #include <stratosphere/ncm/ncm_content_meta_database.hpp> #include <stratosphere/ncm/ncm_bounded_map.hpp> #include <stratosphere/ncm/ncm_rights_id_cache.hpp> #include <stratosphere/ncm/ncm_content_management_utils.hpp> #include <stratosphere/ncm/ncm_content_meta_utils.hpp> #include <stratosphere/ncm/ncm_registered_host_content.hpp> #include <stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp> #include <stratosphere/ncm/ncm_integrated_content_storage_impl.hpp> #include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp> namespace ams::ncm { class ContentMetaMemoryResource : public MemoryResource { private: mem::StandardAllocator m_allocator; size_t m_peak_total_alloc_size; size_t m_peak_alloc_size; public: explicit ContentMetaMemoryResource(void *heap, size_t heap_size) : m_allocator(heap, heap_size), m_peak_total_alloc_size(0), m_peak_alloc_size(0) { /* ... */ } mem::StandardAllocator *GetAllocator() { return std::addressof(m_allocator); } size_t GetPeakTotalAllocationSize() const { return m_peak_total_alloc_size; } size_t GetPeakAllocationSize() const { return m_peak_alloc_size; } private: virtual void *AllocateImpl(size_t size, size_t alignment) override { void *mem = m_allocator.Allocate(size, alignment); m_peak_total_alloc_size = std::max(m_allocator.Hash().allocated_size, m_peak_total_alloc_size); m_peak_alloc_size = std::max(size, m_peak_alloc_size); return mem; } virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override { AMS_UNUSED(size, alignment); return m_allocator.Free(buffer); } virtual bool IsEqualImpl(const MemoryResource &resource) const override { return this == std::addressof(resource); } }; struct SystemSaveDataInfo { u64 id; u64 size; u64 journal_size; u32 flags; fs::SaveDataSpaceId space_id; }; static_assert(util::is_pod<SystemSaveDataInfo>::value); struct IntegratedContentStorageImpl; class ContentManagerImpl { private: constexpr static size_t MaxContentStorageRoots = 8; constexpr static size_t MaxIntegratedContentStorageRoots = 8; constexpr static size_t MaxContentMetaDatabaseRoots = 8; constexpr static size_t MaxIntegratedContentMetaDatabaseRoots = 8; constexpr static size_t MaxConfigs = 8; constexpr static size_t MaxIntegratedConfigs = 8; private: struct ContentStorageConfig { fs::ContentStorageId content_storage_id; bool skip_verify_and_create; bool skip_activate; }; struct IntegratedContentStorageConfig { ncm::StorageId storage_id; fs::ContentStorageId content_storage_ids[MaxContentStorageRoots]; int num_content_storage_ids; bool is_integrated; }; private: struct ContentStorageRoot { NON_COPYABLE(ContentStorageRoot); NON_MOVEABLE(ContentStorageRoot); char mount_name[fs::MountNameLengthMax + 1]; char path[128]; StorageId storage_id; util::optional<ContentStorageConfig> config; sf::SharedPointer<IContentStorage> content_storage; ContentStorageRoot() : mount_name(), path(), storage_id(), config(util::nullopt), content_storage() { /* ... */ } }; struct IntegratedContentStorageRoot { NON_COPYABLE(IntegratedContentStorageRoot); NON_MOVEABLE(IntegratedContentStorageRoot); const IntegratedContentStorageConfig *m_config; ContentStorageRoot *m_roots; int m_num_roots; sf::EmplacedRef<IContentStorage, IntegratedContentStorageImpl> m_integrated_content_storage; IntegratedContentStorageRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_storage() { /* ... */ } Result Create(); Result Verify(); Result Open(sf::Out<sf::SharedPointer<IContentStorage>> out, RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content); Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content); Result Inactivate(RegisteredHostContent ®istered_host_content); Result Activate(ContentStorageRoot &root, RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content); Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content, fs::ContentStorageId content_storage_id); ContentStorageRoot *GetRoot(fs::ContentStorageId storage_id) { for (auto i = 0; i < m_num_roots; ++i) { if (auto &root = m_roots[i]; root.config.has_value() && root.config->content_storage_id == storage_id) { return std::addressof(root); } } return nullptr; } }; struct ContentMetaDatabaseRoot { NON_COPYABLE(ContentMetaDatabaseRoot); NON_MOVEABLE(ContentMetaDatabaseRoot); char mount_name[fs::MountNameLengthMax + 1]; char path[128]; StorageId storage_id; util::optional<ContentStorageConfig> storage_config; util::optional<SystemSaveDataInfo> save_data_info; util::optional<kvdb::MemoryKeyValueStore<ContentMetaKey>> kvs; sf::SharedPointer<IContentMetaDatabase> content_meta_database; ContentMetaMemoryResource *memory_resource; u32 max_content_metas; ContentMetaDatabaseRoot() : mount_name(), path(), storage_id(), storage_config(util::nullopt), save_data_info(util::nullopt), kvs(util::nullopt), content_meta_database(), memory_resource(), max_content_metas() { /* ... */ } }; struct IntegratedContentMetaDatabaseRoot { NON_COPYABLE(IntegratedContentMetaDatabaseRoot); NON_MOVEABLE(IntegratedContentMetaDatabaseRoot); const IntegratedContentStorageConfig *m_config; ContentMetaDatabaseRoot *m_roots; int m_num_roots; sf::EmplacedRef<IContentMetaDatabase, IntegratedContentMetaDatabaseImpl> m_integrated_content_meta_database; IntegratedContentMetaDatabaseRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_meta_database() { /* ... */ } Result Create(); Result Verify(); Result Open(sf::Out<sf::SharedPointer<IContentMetaDatabase>> out); Result Cleanup(); Result Activate(); Result Inactivate(); Result Activate(ContentMetaDatabaseRoot &root); Result Activate(fs::ContentStorageId content_storage_id); ContentMetaDatabaseRoot *GetRoot(fs::ContentStorageId storage_id) { for (auto i = 0; i < m_num_roots; ++i) { if (auto &root = m_roots[i]; root.storage_config.has_value() && root.storage_config->content_storage_id == storage_id) { return std::addressof(root); } } return nullptr; } }; private: os::SdkRecursiveMutex m_mutex{}; bool m_initialized{false}; IntegratedContentStorageRoot m_integrated_content_storage_roots[MaxIntegratedContentStorageRoots]{}; ContentStorageRoot m_content_storage_roots[MaxContentStorageRoots]{}; IntegratedContentMetaDatabaseRoot m_integrated_content_meta_database_roots[MaxIntegratedContentMetaDatabaseRoots]{}; ContentMetaDatabaseRoot m_content_meta_database_roots[MaxContentMetaDatabaseRoots]{}; IntegratedContentStorageConfig m_integrated_configs[MaxIntegratedConfigs]{}; ContentStorageConfig m_configs[MaxConfigs]{}; u32 m_num_integrated_content_storage_entries{0}; u32 m_num_content_storage_entries{0}; u32 m_num_integrated_content_meta_entries{0}; u32 m_num_content_meta_entries{0}; u32 m_num_integrated_configs{0}; u32 m_num_configs{0}; RightsIdCache m_rights_id_cache{}; RegisteredHostContent m_registered_host_content{}; public: ContentManagerImpl() = default; ~ContentManagerImpl(); public: Result Initialize(const ContentManagerConfig &config); private: Result Initialize(const ContentManagerConfig &manager_config, const IntegratedContentStorageConfig *integrated_configs, size_t num_integrated_configs, const ContentStorageConfig *configs, size_t num_configs, const ncm::StorageId *activated_storages, size_t num_activated_storages); Result InitializeStorageBuiltInSystem(const ContentManagerConfig &manager_config); Result InitializeStorage(ncm::StorageId storage_id); const ContentStorageConfig &GetContentStorageConfig(fs::ContentStorageId content_storage_id) { for (size_t i = 0; i < m_num_configs; ++i) { if (m_configs[i].content_storage_id == content_storage_id) { return m_configs[i]; } } /* NOTE: Nintendo accesses out of bounds memory here. Should we explicitly abort? This is guaranteed by data to never happen. */ AMS_ASSUME(false); } private: /* Helpers. */ Result GetIntegratedContentStorageConfig(IntegratedContentStorageConfig **out, fs::ContentStorageId content_storage_id); Result GetIntegratedContentStorageRoot(IntegratedContentStorageRoot **out, StorageId id); Result GetIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot **out, StorageId id); Result InitializeContentStorageRoot(ContentStorageRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> config); Result InitializeContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> storage_config); Result InitializeIntegratedContentStorageRoot(IntegratedContentStorageRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count); Result InitializeIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count); Result BuildContentMetaDatabase(StorageId storage_id); Result BuildContentMetaDatabaseImpl(StorageId storage_id); Result ImportContentMetaDatabase(StorageId storage_id, bool from_signed_partition); Result ImportContentMetaDatabaseImpl(ContentMetaDatabaseRoot *root, const char *import_mount_name); private: /* Helpers for unofficial functionality. */ bool IsNeedRebuildSystemContentMetaDatabase(); public: /* Actual commands. */ Result CreateContentStorage(StorageId storage_id); Result CreateContentMetaDatabase(StorageId storage_id); Result VerifyContentStorage(StorageId storage_id); Result VerifyContentMetaDatabase(StorageId storage_id); Result OpenContentStorage(sf::Out<sf::SharedPointer<IContentStorage>> out, StorageId storage_id); Result OpenContentMetaDatabase(sf::Out<sf::SharedPointer<IContentMetaDatabase>> out, StorageId storage_id); Result CloseContentStorageForcibly(StorageId storage_id); Result CloseContentMetaDatabaseForcibly(StorageId storage_id); Result CleanupContentMetaDatabase(StorageId storage_id); Result ActivateContentStorage(StorageId storage_id); Result InactivateContentStorage(StorageId storage_id); Result ActivateContentMetaDatabase(StorageId storage_id); Result InactivateContentMetaDatabase(StorageId storage_id); Result InvalidateRightsIdCache(); Result GetMemoryReport(sf::Out<MemoryReport> out); Result ActivateFsContentStorage(fs::ContentStorageId fs_content_storage_id); }; static_assert(IsIContentManager<ContentManagerImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_meta_id.hpp> #include <stratosphere/ncm/ncm_content_meta_key.hpp> #include <stratosphere/ncm/ncm_content_meta_platform.hpp> #include <stratosphere/ncm/ncm_content_info.hpp> #include <stratosphere/ncm/ncm_content_info_data.hpp> #include <stratosphere/ncm/ncm_firmware_variation.hpp> #include <stratosphere/ncm/ncm_storage_id.hpp> namespace ams::ncm { enum ContentMetaAttribute : u8 { ContentMetaAttribute_None = (0 << 0), ContentMetaAttribute_IncludesExFatDriver = (1 << 0), ContentMetaAttribute_Rebootless = (1 << 1), ContentMetaAttribute_Compacted = (1 << 2), }; struct ContentMetaInfo { u64 id; u32 version; ContentMetaType type; u8 attributes; u8 padding[2]; static constexpr ContentMetaInfo Make(u64 id, u32 version, ContentMetaType type, u8 attributes) { return { .id = id, .version = version, .type = type, .attributes = attributes, }; } constexpr ContentMetaKey ToKey() const { return ContentMetaKey::Make(this->id, this->version, this->type); } }; static_assert(sizeof(ContentMetaInfo) == 0x10); struct ContentMetaHeader { u16 extended_header_size; u16 content_count; u16 content_meta_count; u8 attributes; ContentMetaPlatform platform; }; static_assert(sizeof(ContentMetaHeader) == 0x8); struct PackagedContentMetaHeader { u64 id; u32 version; ContentMetaType type; ContentMetaPlatform platform; u16 extended_header_size; u16 content_count; u16 content_meta_count; u8 attributes; u8 storage_id; ContentInstallType install_type; bool committed; u32 required_download_system_version; u8 reserved_1C[4]; }; static_assert(sizeof(PackagedContentMetaHeader) == 0x20); static_assert(AMS_OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C); using InstallContentMetaHeader = PackagedContentMetaHeader; struct ApplicationMetaExtendedHeader { PatchId patch_id; u32 required_system_version; u32 required_application_version; }; struct PatchMetaExtendedHeader { ApplicationId application_id; u32 required_system_version; u32 extended_data_size; u8 reserved[0x8]; }; struct AddOnContentMetaExtendedHeader { ApplicationId application_id; u32 required_application_version; u8 content_accessibilities; u8 padding[3]; DataPatchId data_patch_id; }; struct LegacyAddOnContentMetaExtendedHeader { ApplicationId application_id; u32 required_application_version; u32 padding; }; struct DeltaMetaExtendedHeader { ApplicationId application_id; u32 extended_data_size; u32 padding; }; struct SystemUpdateMetaExtendedHeader { u32 extended_data_size; }; template<typename ContentMetaHeaderType, typename ContentInfoType> class ContentMetaAccessor { public: using HeaderType = ContentMetaHeaderType; using InfoType = ContentInfoType; private: void *m_data; const size_t m_size; bool m_is_header_valid; private: static size_t GetExtendedHeaderSize(ContentMetaType type) { switch (type) { case ContentMetaType::Application: return sizeof(ApplicationMetaExtendedHeader); case ContentMetaType::Patch: return sizeof(PatchMetaExtendedHeader); case ContentMetaType::AddOnContent: return sizeof(AddOnContentMetaExtendedHeader); case ContentMetaType::Delta: return sizeof(DeltaMetaExtendedHeader); default: return 0; } } protected: constexpr ContentMetaAccessor(const void *d, size_t sz) : m_data(const_cast<void *>(d)), m_size(sz), m_is_header_valid(true) { /* ... */ } constexpr ContentMetaAccessor(void *d, size_t sz) : m_data(d), m_size(sz), m_is_header_valid(false) { /* ... */ } template<class NewHeaderType, class NewInfoType> static constexpr size_t CalculateSizeImpl(size_t ext_header_size, size_t content_count, size_t content_meta_count, size_t extended_data_size, bool has_digest) { return sizeof(NewHeaderType) + ext_header_size + content_count * sizeof(NewInfoType) + content_meta_count * sizeof(ContentMetaInfo) + extended_data_size + (has_digest ? sizeof(Digest) : 0); } static constexpr size_t CalculateSize(ContentMetaType type, size_t content_count, size_t content_meta_count, size_t extended_data_size, bool has_digest = false) { return CalculateSizeImpl<ContentMetaHeaderType, ContentInfoType>(GetExtendedHeaderSize(type), content_count, content_meta_count, extended_data_size, has_digest); } uintptr_t GetExtendedHeaderAddress() const { return reinterpret_cast<uintptr_t>(m_data) + sizeof(HeaderType); } uintptr_t GetContentInfoStartAddress() const { return this->GetExtendedHeaderAddress() + this->GetExtendedHeaderSize(); } uintptr_t GetContentInfoAddress(size_t i) const { return this->GetContentInfoStartAddress() + i * sizeof(InfoType); } uintptr_t GetContentMetaInfoStartAddress() const { return this->GetContentInfoAddress(this->GetContentCount()); } uintptr_t GetContentMetaInfoAddress(size_t i) const { return this->GetContentMetaInfoStartAddress() + i * sizeof(ContentMetaInfo); } uintptr_t GetExtendedDataAddress() const { return this->GetContentMetaInfoAddress(this->GetContentMetaCount()); } uintptr_t GetDigestAddress() const { return this->GetExtendedDataAddress() + this->GetExtendedDataSize(); } InfoType *GetWritableContentInfo(size_t i) const { AMS_ABORT_UNLESS(i < this->GetContentCount()); return reinterpret_cast<InfoType *>(this->GetContentInfoAddress(i)); } InfoType *GetWritableContentInfo(ContentType type) const { InfoType *found = nullptr; for (size_t i = 0; i < this->GetContentCount(); i++) { /* We want to find the info with the lowest id offset and the correct type. */ InfoType *info = this->GetWritableContentInfo(i); if (info->GetType() == type && (found == nullptr || info->GetIdOffset() < found->GetIdOffset())) { found = info; } } return found; } InfoType *GetWritableContentInfo(ContentType type, u8 id_ofs) const { for (size_t i = 0; i < this->GetContentCount(); i++) { /* We want to find the info with the correct id offset and the correct type. */ if (InfoType *info = this->GetWritableContentInfo(i); info->GetType() == type && info->GetIdOffset() == id_ofs) { return info; } } return nullptr; } s64 CalculateContentRequiredSize() const { s64 required_size = 0; for (size_t i = 0; i < this->GetContentCount(); i++) { required_size += CalculateRequiredSize(this->GetContentInfo(i)->info.GetSize()); } return required_size; } void SetStorageId(StorageId storage_id) { this->GetWritableHeader()->storage_id = static_cast<u8>(storage_id); } public: const void *GetData() const { return m_data; } size_t GetSize() const { return m_size; } HeaderType *GetWritableHeader() const { AMS_ABORT_UNLESS(m_is_header_valid); return reinterpret_cast<HeaderType *>(m_data); } const HeaderType *GetHeader() const { AMS_ABORT_UNLESS(m_is_header_valid); return static_cast<const HeaderType *>(m_data); } ContentMetaKey GetKey() const { auto header = this->GetHeader(); return ContentMetaKey::Make(header->id, header->version, header->type, header->install_type); } size_t GetExtendedHeaderSize() const { return this->GetHeader()->extended_header_size; } template<typename ExtendedHeaderType> const ExtendedHeaderType *GetExtendedHeader() const { return reinterpret_cast<const ExtendedHeaderType *>(this->GetExtendedHeaderAddress()); } size_t GetContentCount() const { return this->GetHeader()->content_count; } const InfoType *GetContentInfo(size_t i) const { AMS_ABORT_UNLESS(i < this->GetContentCount()); return this->GetWritableContentInfo(i); } const InfoType *GetContentInfo(ContentType type) const { return this->GetWritableContentInfo(type); } const InfoType *GetContentInfo(ContentType type, u8 id_ofs) const { return this->GetWritableContentInfo(type, id_ofs); } size_t GetContentMetaCount() const { return this->GetHeader()->content_meta_count; } const ContentMetaInfo *GetContentMetaInfo(size_t i) const { AMS_ABORT_UNLESS(i < this->GetContentMetaCount()); return reinterpret_cast<const ContentMetaInfo *>(this->GetContentMetaInfoAddress(i)); } size_t GetExtendedDataSize() const { switch (this->GetHeader()->type) { case ContentMetaType::Patch: return this->GetExtendedHeader<PatchMetaExtendedHeader>()->extended_data_size; case ContentMetaType::Delta: return this->GetExtendedHeader<DeltaMetaExtendedHeader>()->extended_data_size; case ContentMetaType::SystemUpdate: return this->GetExtendedHeaderSize() == 0 ? 0 : this->GetExtendedHeader<SystemUpdateMetaExtendedHeader>()->extended_data_size; default: return 0; } } const void *GetExtendedData() const { return reinterpret_cast<const void *>(this->GetExtendedDataAddress()); } const Digest *GetDigest() const { return reinterpret_cast<Digest *>(this->GetDigestAddress()); } bool HasContent(const ContentId &id) const { for (size_t i = 0; i < this->GetContentCount(); i++) { if (id == this->GetContentInfo(i)->GetId()) { return true; } } return false; } StorageId GetStorageId() const { return static_cast<StorageId>(this->GetHeader()->storage_id); } util::optional<ApplicationId> GetApplicationId(const ContentMetaKey &key) const { switch (key.type) { case ContentMetaType::Application: return ApplicationId{ key.id }; case ContentMetaType::Patch: return this->GetExtendedHeader<PatchMetaExtendedHeader>()->application_id; case ContentMetaType::AddOnContent: return this->GetExtendedHeader<AddOnContentMetaExtendedHeader>()->application_id; case ContentMetaType::Delta: return this->GetExtendedHeader<DeltaMetaExtendedHeader>()->application_id; default: return util::nullopt; } } util::optional<ApplicationId> GetApplicationId() const { return this->GetApplicationId(this->GetKey()); } }; class ContentMetaReader : public ContentMetaAccessor<ContentMetaHeader, ContentInfo> { public: constexpr ContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ } using ContentMetaAccessor::CalculateSize; }; class PackagedContentMetaReader : public ContentMetaAccessor<PackagedContentMetaHeader, PackagedContentInfo> { public: constexpr PackagedContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ } size_t CalculateConvertInstallContentMetaSize() const; void ConvertToInstallContentMeta(void *dst, size_t size, const InstallContentInfo &meta); size_t CalculateConvertContentMetaSize() const; void ConvertToContentMeta(void *dst, size_t size, const ContentInfo &meta); size_t CalculateConvertFragmentOnlyInstallContentMetaSize(s32 fragment_count) const { return CalculateSizeImpl<InstallContentMetaHeader, InstallContentInfo>(this->GetExtendedHeaderSize(), fragment_count + 1, 0, 0, false); } Result CalculateConvertFragmentOnlyInstallContentMetaSize(size_t *out_size, u32 source_version) const; Result ConvertToFragmentOnlyInstallContentMeta(void *dst, size_t size, const InstallContentInfo &content_info, u32 source_version); size_t CountDeltaFragments() const; static constexpr size_t CalculateSize(ContentMetaType type, size_t content_count, size_t content_meta_count, size_t extended_data_size) { return ContentMetaAccessor::CalculateSize(type, content_count, content_meta_count, extended_data_size, true); } size_t GetExtendedDataOffset() const { return this->GetExtendedDataAddress() - reinterpret_cast<uintptr_t>(this->GetData()); } }; class InstallContentMetaReader : public ContentMetaAccessor<InstallContentMetaHeader, InstallContentInfo> { public: constexpr InstallContentMetaReader(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ } using ContentMetaAccessor::CalculateSize; using ContentMetaAccessor::CalculateContentRequiredSize; using ContentMetaAccessor::GetStorageId; size_t CalculateConvertSize() const; void ConvertToContentMeta(void *dst, size_t size) const; }; class InstallContentMetaWriter : public ContentMetaAccessor<InstallContentMetaHeader, InstallContentInfo> { public: InstallContentMetaWriter(const void *data, size_t size) : ContentMetaAccessor(data, size) { /* ... */ } using ContentMetaAccessor::CalculateSize; using ContentMetaAccessor::CalculateContentRequiredSize; using ContentMetaAccessor::GetWritableContentInfo; using ContentMetaAccessor::SetStorageId; }; class PatchMetaExtendedDataAccessor; struct PatchDeltaHeader; class AutoBuffer; class MetaConverter { public: static Result CountContentExceptForMeta(s32 *out, PatchMetaExtendedDataAccessor *accessor, const PatchDeltaHeader &header, s32 delta_index); static Result FindDeltaIndex(s32 *out, PatchMetaExtendedDataAccessor *accessor, u32 source_version, u32 destination_version); static Result GetFragmentOnlyInstallContentMeta(AutoBuffer *out, const InstallContentInfo &content_info, const PackagedContentMetaReader &reader, PatchMetaExtendedDataAccessor *accessor, u32 source_version); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_i_content_meta_database.hpp> namespace ams::ncm { class ContentMetaDatabase { NON_COPYABLE(ContentMetaDatabase); public: struct ListCount { s32 written; s32 total; }; private: sf::SharedPointer<IContentMetaDatabase> m_interface; public: ContentMetaDatabase() : m_interface(nullptr) { /* ... */ } explicit ContentMetaDatabase(sf::SharedPointer<IContentMetaDatabase> intf) : m_interface(intf) { /* ... */ } ContentMetaDatabase(ContentMetaDatabase &&rhs) { m_interface = std::move(rhs.m_interface); } ContentMetaDatabase &operator=(ContentMetaDatabase &&rhs) { ContentMetaDatabase(std::move(rhs)).swap(*this); return *this; } void swap(ContentMetaDatabase &rhs) { std::swap(m_interface, rhs.m_interface); } public: Result Set(const ContentMetaKey &key, const void *buf, size_t size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Set(key, sf::InBuffer(buf, size))); } Result Get(size_t *out_size, void *dst, size_t dst_size, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); u64 size; R_TRY(m_interface->Get(std::addressof(size), key, sf::OutBuffer(dst, dst_size))); *out_size = size; R_SUCCEED(); } #define AMS_NCM_DEFINE_GETTERS(Kind, IdType) \ Result Get##Kind(ContentId *out, IdType##Id id, u32 version) { \ R_RETURN(m_interface->GetContentIdByType(out, ContentMetaKey::MakeUnknownType(id.value, version), ContentType::Kind)); \ } \ \ Result Get##Kind(ContentInfo *out, IdType##Id id, u32 version) { \ R_RETURN(m_interface->GetContentInfoByType(out, ContentMetaKey::MakeUnknownType(id.value, version), ContentType::Kind)); \ } \ \ Result GetLatest##Kind(ContentId *out, IdType##Id id) { \ ContentMetaKey latest_key; \ R_TRY(m_interface->GetLatestContentMetaKey(std::addressof(latest_key), id.value)); \ R_RETURN(m_interface->GetContentIdByType(out, latest_key, ContentType::Kind)); \ } \ \ Result GetLatest##Kind(ContentInfo *out, IdType##Id id) { \ ContentMetaKey latest_key; \ R_TRY(m_interface->GetLatestContentMetaKey(std::addressof(latest_key), id.value)); \ R_RETURN(m_interface->GetContentInfoByType(out, latest_key, ContentType::Kind)); \ } AMS_NCM_DEFINE_GETTERS(Program, Program) AMS_NCM_DEFINE_GETTERS(Data, Data) AMS_NCM_DEFINE_GETTERS(Control, Application) AMS_NCM_DEFINE_GETTERS(HtmlDocument, Application) AMS_NCM_DEFINE_GETTERS(LegalInformation, Application) #undef AMS_NCM_DEFINE_GETTERS Result Remove(const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Remove(key)); } Result Remove(SystemProgramId id, u32 version) { R_RETURN(this->Remove(ContentMetaKey::Make(id, version))); } Result Remove(SystemDataId id, u32 version) { R_RETURN(this->Remove(ContentMetaKey::Make(id, version))); } Result Remove(ApplicationId id, u32 version) { R_RETURN(this->Remove(ContentMetaKey::Make(id, version))); } Result GetContentIdByType(ContentId *out_content_id, const ContentMetaKey &key, ContentType type) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentIdByType(out_content_id, key, type)); } Result GetContentIdByTypeAndIdOffset(ContentId *out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentIdByTypeAndIdOffset(out_content_id, key, type, id_offset)); } ListCount ListApplication(ApplicationContentMetaKey *dst, size_t dst_size) { ListCount lc = {}; R_ABORT_UNLESS(m_interface->ListApplication(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray<ApplicationContentMetaKey>(dst, dst_size), ContentMetaType::Unknown)); return lc; } ListCount ListContentMeta(ContentMetaKey *dst, size_t dst_size, ContentMetaType type = ContentMetaType::Unknown, ApplicationId app_id = InvalidApplicationId, u64 min = std::numeric_limits<u64>::min(), u64 max = std::numeric_limits<u64>::max(), ContentInstallType install_type = ContentInstallType::Full) { ListCount lc = {}; R_ABORT_UNLESS(m_interface->List(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray<ContentMetaKey>(dst, dst_size), type, app_id, min, max, install_type)); return lc; } Result GetLatest(ContentMetaKey *out_key, u64 id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetLatestContentMetaKey(out_key, id)); } Result ListContentInfo(s32 *out_count, ContentInfo *dst, size_t dst_size, const ContentMetaKey &key, s32 offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ListContentInfo(out_count, sf::OutArray<ContentInfo>(dst, dst_size), key, offset)); } Result ListContentMetaInfo(s32 *out_count, ContentMetaInfo *dst, size_t dst_size, const ContentMetaKey &key, s32 offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ListContentMetaInfo(out_count, sf::OutArray<ContentMetaInfo>(dst, dst_size), key, offset)); } Result Has(bool *out, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Has(out, key)); } Result HasAll(bool *out, const ContentMetaKey *keys, size_t num_keys) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->HasAll(out, sf::InArray<ContentMetaKey>(keys, num_keys))); } Result HasContent(bool *out, const ContentMetaKey &key, const ContentId &content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->HasContent(out, key, content_id)); } Result GetSize(size_t *out_size, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); u64 size; R_TRY(m_interface->GetSize(std::addressof(size), key)); *out_size = size; R_SUCCEED(); } Result GetRequiredSystemVersion(u32 *out_version, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetRequiredSystemVersion(out_version, key)); } Result GetPatchId(PatchId *out_patch_id, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); static_assert(sizeof(*out_patch_id) == sizeof(u64)); R_RETURN(m_interface->GetPatchContentMetaId(reinterpret_cast<u64 *>(out_patch_id), key)); } Result GetDataPatchId(DataPatchId *out_patch_id, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); static_assert(sizeof(*out_patch_id) == sizeof(u64)); R_RETURN(m_interface->GetPatchContentMetaId(reinterpret_cast<u64 *>(out_patch_id), key)); } Result DisableForcibly() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->DisableForcibly()); } Result LookupOrphanContent(bool *out_orphaned, ContentId *content_list, size_t count) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->LookupOrphanContent(sf::OutArray<bool>(out_orphaned, count), sf::InArray<ContentId>(content_list, count))); } Result Commit() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Commit()); } Result GetAttributes(u8 *out_attributes, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetAttributes(out_attributes, key)); } Result GetRequiredApplicationVersion(u32 *out_version, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetRequiredApplicationVersion(out_version, key)); } Result GetContentAccessibilities(u8 *out_accessibilities, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentAccessibilities(out_accessibilities, key)); } Result GetContentInfoByType(ContentInfo *out_content_info, const ContentMetaKey &key, ContentType type) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentInfoByType(out_content_info, key, type)); } Result GetContentInfoByTypeAndIdOffset(ContentInfo *out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentInfoByTypeAndIdOffset(out_content_info, key, type, id_offset)); } Result GetPlatform(ContentMetaPlatform *out, const ContentMetaKey &key) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetPlatform(out, key)); } Result HasAttributes(u8 *out, u8 attr_mask) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->HasAttributes(out, attr_mask)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_extended_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_info.hpp> #include <stratosphere/ncm/ncm_content_meta_id.hpp> #include <stratosphere/ncm/ncm_content_meta.hpp> #include <stratosphere/ncm/ncm_firmware_variation.hpp> #include <stratosphere/ncm/ncm_mapped_memory.hpp> namespace ams::ncm { enum class UpdateType : u8 { ApplyAsDelta = 0, Overwrite = 1, Create = 2, }; struct FragmentIndicator { u16 content_info_index; u16 fragment_index; }; struct FragmentSet { ContentId source_content_id; ContentId destination_content_id; u32 source_size_low; u16 source_size_high; u16 destination_size_high; u32 destination_size_low; u16 fragment_count; ContentType target_content_type; UpdateType update_type; u8 reserved[4]; constexpr s64 GetSourceSize() const { return (static_cast<s64>(this->source_size_high) << 32) + this->source_size_low; } constexpr s64 GetDestinationSize() const { return (static_cast<s64>(this->destination_size_high) << 32) + this->destination_size_low; } constexpr void SetSourceSize(s64 size) { this->source_size_low = size & 0xFFFFFFFFll; this->source_size_high = static_cast<u16>(size >> 32); } constexpr void SetDestinationSize(s64 size) { this->destination_size_low = size & 0xFFFFFFFFll; this->destination_size_high = static_cast<u16>(size >> 32); } }; struct SystemUpdateMetaExtendedDataHeader { u32 version; u32 firmware_variation_count; }; struct DeltaMetaExtendedDataHeader { PatchId source_id; PatchId destination_id; u32 source_version; u32 destination_version; u16 fragment_set_count; u8 reserved[6]; }; struct PatchMetaExtendedDataHeader { u32 history_count; u32 delta_history_count; u32 delta_count; u32 fragment_set_count; u32 history_content_total_count; u32 delta_content_total_count; u8 reserved[4]; }; struct PatchHistoryHeader { ContentMetaKey key; Digest digest; u16 content_count; u8 reserved[2]; }; struct PatchDeltaHistory { PatchId source_id; PatchId destination_id; u32 source_version; u32 destination_version; u64 download_size; u8 reserved[4]; }; struct PatchDeltaHeader { DeltaMetaExtendedDataHeader delta; u16 content_count; u8 reserved[4]; }; template<typename MemberTypePointer, typename DataTypePointer> class PatchMetaExtendedDataReaderWriterBase { private: MemberTypePointer m_data; const size_t m_size; public: PatchMetaExtendedDataReaderWriterBase(MemberTypePointer d, size_t sz) : m_data(d), m_size(sz) { /* ... */ } protected: s32 CountFragmentSet(s32 delta_index) const { auto delta_header = this->GetPatchDeltaHeader(0); s32 count = 0; for (s32 i = 0; i < delta_index; i++) { count += delta_header[i].delta.fragment_set_count; } return count; } s32 CountHistoryContent(s32 history_index) const { auto history_header = this->GetPatchHistoryHeader(0); s32 count = 0; for (s32 i = 0; i < history_index; i++) { count += history_header[i].content_count; } return count; } s32 CountDeltaContent(s32 delta_index) const { auto delta_header = this->GetPatchDeltaHeader(0); s32 count = 0; for (s32 i = 0; i < delta_index; i++) { count += delta_header[i].content_count; } return count; } s32 CountFragment(s32 index) const { auto fragment_set = this->GetFragmentSet(0, 0); s32 count = 0; for (s32 i = 0; i < index; i++) { count += fragment_set[i].fragment_count; } return count; } DataTypePointer GetHeaderAddress() const { return reinterpret_cast<DataTypePointer>(m_data); } DataTypePointer GetPatchHistoryHeaderAddress(s32 index) const { auto header = this->GetHeader(); AMS_ABORT_UNLESS(static_cast<u16>(index) < header->history_count); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * index; } DataTypePointer GetPatchDeltaHistoryAddress(s32 index) const { auto header = this->GetHeader(); AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_history_count); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * index; } DataTypePointer GetPatchDeltaHeaderAddress(s32 index) const { auto header = this->GetHeader(); AMS_ABORT_UNLESS(static_cast<u16>(index) < header->delta_count); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * header->delta_history_count + sizeof(PatchDeltaHeader) * index; } DataTypePointer GetFragmentSetAddress(s32 delta_index, s32 fragment_set_index) const { auto header = this->GetHeader(); AMS_ABORT_UNLESS(static_cast<u16>(delta_index) < header->delta_count); auto delta_header = this->GetPatchDeltaHeader(delta_index); AMS_ABORT_UNLESS(static_cast<u16>(fragment_set_index) < delta_header->delta.fragment_set_count); auto previous_fragment_set_count = this->CountFragmentSet(delta_index); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * header->delta_history_count + sizeof(PatchDeltaHeader) * header->delta_count + sizeof(FragmentSet) * (previous_fragment_set_count + fragment_set_index); } DataTypePointer GetPatchHistoryContentInfoAddress(s32 history_index, s32 content_index) const { auto header = this->GetHeader(); auto history_header = this->GetPatchHistoryHeader(history_index); AMS_ABORT_UNLESS(static_cast<u16>(content_index) < history_header->content_count); auto prev_history_count = this->CountHistoryContent(history_index); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * header->delta_history_count + sizeof(PatchDeltaHeader) * header->delta_count + sizeof(FragmentSet) * header->fragment_set_count + sizeof(ContentInfo) * (prev_history_count + content_index); } DataTypePointer GetPatchDeltaPackagedContentInfoAddress(s32 delta_index, s32 content_index) const { auto header = this->GetHeader(); auto delta_header = this->GetPatchDeltaHeader(delta_index); AMS_ABORT_UNLESS(static_cast<u16>(content_index) < delta_header->content_count); auto content_count = this->CountDeltaContent(delta_index); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * header->delta_history_count + sizeof(PatchDeltaHeader) * header->delta_count + sizeof(FragmentSet) * header->fragment_set_count + sizeof(ContentInfo) * header->history_content_total_count + sizeof(PackagedContentInfo) * (content_count + content_index); } DataTypePointer GetFragmentIndicatorAddress(s32 delta_index, s32 fragment_set_index, s32 index) const { auto header = this->GetHeader(); auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index); AMS_ABORT_UNLESS(static_cast<u16>(index) < fragment_set->fragment_count); auto fragment_set_count = this->CountFragmentSet(delta_index); auto fragment_count = this->CountFragment(fragment_set_count + fragment_set_index); return this->GetHeaderAddress() + sizeof(PatchMetaExtendedDataHeader) + sizeof(PatchHistoryHeader) * header->history_count + sizeof(PatchDeltaHistory) * header->delta_history_count + sizeof(PatchDeltaHeader) * header->delta_count + sizeof(FragmentSet) * header->fragment_set_count + sizeof(ContentInfo) * header->history_content_total_count + sizeof(PackagedContentInfo) * header->delta_content_total_count + sizeof(FragmentIndicator) * (fragment_count + index); } public: const PatchMetaExtendedDataHeader *GetHeader() const { return reinterpret_cast<const PatchMetaExtendedDataHeader *>(this->GetHeaderAddress()); } const PatchHistoryHeader *GetPatchHistoryHeader(s32 index) const { return reinterpret_cast<const PatchHistoryHeader *>(this->GetPatchHistoryHeaderAddress(index)); } const PatchDeltaHistory *GetPatchDeltaHistory(s32 index) const { return reinterpret_cast<const PatchDeltaHistory *>(this->GetPatchDeltaHistoryAddress(index)); } const ContentInfo *GetPatchHistoryContentInfo(s32 history_index, s32 content_index) const { return reinterpret_cast<const ContentInfo *>(this->GetPatchHistoryContentInfoAddress(history_index, content_index)); } const PatchDeltaHeader *GetPatchDeltaHeader(s32 index) const { return reinterpret_cast<const PatchDeltaHeader *>(this->GetPatchDeltaHeaderAddress(index)); } const PackagedContentInfo *GetPatchDeltaPackagedContentInfo(s32 delta_index, s32 content_index) const { return reinterpret_cast<const PackagedContentInfo *>(this->GetPatchDeltaPackagedContentInfoAddress(delta_index, content_index)); } const FragmentSet *GetFragmentSet(s32 delta_index, s32 fragment_set_index) const { return reinterpret_cast<const FragmentSet *>(this->GetFragmentSetAddress(delta_index, fragment_set_index)); } const FragmentIndicator *GetFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 index) const { return reinterpret_cast<const FragmentIndicator *>(this->GetFragmentIndicatorAddress(delta_index, fragment_set_index, index)); } const FragmentIndicator *FindFragmentIndicator(s32 delta_index, s32 fragment_set_index, s32 fragment_index) const { auto fragment_set = this->GetFragmentSet(delta_index, fragment_set_index); auto fragment = this->GetFragmentIndicator(delta_index, fragment_set_index, 0); for (s32 i = 0; i < fragment_set->fragment_count; i++) { if (fragment[i].fragment_index == fragment_index) { return std::addressof(fragment[i]); } } return nullptr; } }; class PatchMetaExtendedDataReader : public PatchMetaExtendedDataReaderWriterBase<const void *, const u8 *> { public: PatchMetaExtendedDataReader(const void *data, size_t size) : PatchMetaExtendedDataReaderWriterBase(data, size) { /* ... */ } }; class SystemUpdateMetaExtendedDataReaderWriterBase { private: void *m_data; const size_t m_size; bool m_is_header_valid; protected: constexpr SystemUpdateMetaExtendedDataReaderWriterBase(const void *d, size_t sz) : m_data(const_cast<void *>(d)), m_size(sz), m_is_header_valid(true) { /* ... */ } constexpr SystemUpdateMetaExtendedDataReaderWriterBase(void *d, size_t sz) : m_data(d), m_size(sz), m_is_header_valid(false) { /* ... */ } uintptr_t GetHeaderAddress() const { return reinterpret_cast<uintptr_t>(m_data); } uintptr_t GetFirmwareVariationIdStartAddress() const { return this->GetHeaderAddress() + sizeof(SystemUpdateMetaExtendedDataHeader); } uintptr_t GetFirmwareVariationIdAddress(size_t i) const { return this->GetFirmwareVariationIdStartAddress() + i * sizeof(FirmwareVariationId); } uintptr_t GetFirmwareVariationInfoStartAddress() const { return this->GetFirmwareVariationIdAddress(this->GetFirmwareVariationCount()); } uintptr_t GetFirmwareVariationInfoAddress(size_t i) const { return this->GetFirmwareVariationInfoStartAddress() + i * sizeof(FirmwareVariationInfo); } uintptr_t GetContentMetaInfoStartAddress() const { return this->GetFirmwareVariationInfoAddress(this->GetFirmwareVariationCount()); } uintptr_t GetContentMetaInfoAddress(size_t i) const { return this->GetContentMetaInfoStartAddress() + i * sizeof(ContentMetaInfo); } public: const SystemUpdateMetaExtendedDataHeader *GetHeader() const { AMS_ABORT_UNLESS(m_is_header_valid); return reinterpret_cast<const SystemUpdateMetaExtendedDataHeader *>(this->GetHeaderAddress()); } size_t GetFirmwareVariationCount() const { return this->GetHeader()->firmware_variation_count; } const FirmwareVariationId *GetFirmwareVariationId(size_t i) const { AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount()); return reinterpret_cast<FirmwareVariationId *>(this->GetFirmwareVariationIdAddress(i)); } const FirmwareVariationInfo *GetFirmwareVariationInfo(size_t i) const { AMS_ABORT_UNLESS(i < this->GetFirmwareVariationCount()); return reinterpret_cast<FirmwareVariationInfo *>(this->GetFirmwareVariationInfoAddress(i)); } void GetContentMetaInfoList(Span<const ContentMetaInfo> *out_list, size_t i) const { size_t preceding_content_meta_count = 0; /* Count the number of preceding content metas. */ for (size_t j = 0; j < i; j++) { preceding_content_meta_count += this->GetFirmwareVariationInfo(j)->content_meta_count; } /* Output the list. */ *out_list = Span<const ContentMetaInfo>(reinterpret_cast<const ContentMetaInfo *>(this->GetContentMetaInfoAddress(preceding_content_meta_count)), this->GetFirmwareVariationInfo(i)->content_meta_count); } }; class SystemUpdateMetaExtendedDataReader : public SystemUpdateMetaExtendedDataReaderWriterBase { public: constexpr SystemUpdateMetaExtendedDataReader(const void *data, size_t size) : SystemUpdateMetaExtendedDataReaderWriterBase(data, size) { /* ... */ } }; template<typename T> class ReadableStructPin; class AccessorBase { public: template<typename T> class PinBase { private: AccessorBase *m_accessor; u64 m_pin_id; T *m_data; size_t m_size; public: PinBase() : m_accessor(nullptr), m_data(nullptr), m_size(0) { /* ... */ } PinBase(const PinBase &) = delete; PinBase &operator=(const PinBase &) = delete; PinBase(PinBase &&rhs) : m_accessor(rhs.m_accessor), m_pin_id(rhs.m_pin_id), m_data(rhs.m_data), m_size(rhs.m_size) { rhs.m_accessor = nullptr; } PinBase &operator=(PinBase &&rhs) { m_accessor = rhs.m_accessor; m_pin_id = rhs.m_pin_id; m_data = rhs.m_data; m_size = rhs.m_size; rhs.m_accessor = nullptr; return *this; } virtual ~PinBase() { this->Reset(); } public: void Reset() { if (m_accessor != nullptr) { static_cast<void>(m_accessor->ReleasePin(m_pin_id)); m_accessor = nullptr; } } void Reset(AccessorBase *accessor, u64 pin_id, void *data, size_t size) { AMS_ASSERT(data != nullptr || size == 0); this->Reset(); m_accessor = accessor; m_pin_id = pin_id; m_data = reinterpret_cast<T *>(data); m_size = size; } T *GetData() const { return m_data; } size_t GetDataSize() const { return m_size; } }; private: IMapper *m_mapper; public: AccessorBase(IMapper *mapper) : m_mapper(mapper) { /* ... */ } template<typename T> Result AcquireReadableStructPin(ReadableStructPin<T> *out, size_t offset) { /* Acquire mapped memory for the pin. */ MappedMemory memory = {}; R_TRY(m_mapper->GetMappedMemory(std::addressof(memory), offset, sizeof(T))); /* Mark the memory as in use. */ R_RETURN(m_mapper->MarkUsing(memory.id)); /* Setup the pin. */ out->Reset(this, memory.id, memory.GetBuffer(offset, sizeof(T)), sizeof(T)); R_SUCCEED(); } Result ReleasePin(u64 id) { R_RETURN(m_mapper->UnmarkUsing(id)); } template<typename T> Result ReadStruct(T *out, size_t offset) { /* Acquire mapped memory for the pin. */ MappedMemory memory = {}; R_TRY(m_mapper->GetMappedMemory(std::addressof(memory), offset, sizeof(T))); /* Mark the memory as in use. */ R_RETURN(m_mapper->MarkUsing(memory.id)); ON_SCOPE_EXIT { static_cast<void>(this->ReleasePin(memory.id)); }; /* Copy out the struct. */ *out = *reinterpret_cast<const T *>(memory.GetBuffer(offset, sizeof(T))); R_SUCCEED(); } }; template<typename T> class ReadableStructPin final : public AccessorBase::PinBase<const u8> { public: using PinBase::PinBase; using PinBase::operator=; const T *Get() const { return reinterpret_cast<const T *>(this->GetData()); } size_t GetSize() const { return this->GetDataSize(); } const T &operator*() const { return *this->Get(); } const T *operator->() const { return this->Get(); } }; class PatchMetaExtendedDataAccessor : public AccessorBase { private: struct CachedCount { s32 index; s32 count; }; private: util::optional<CachedCount> m_cached_history_content_count = util::nullopt; util::optional<CachedCount> m_cached_delta_content_count = util::nullopt; util::optional<CachedCount> m_cached_fragment_set_count = util::nullopt; util::optional<CachedCount> m_cached_fragment_indicator_count = util::nullopt; util::optional<PatchMetaExtendedDataHeader> m_header = util::nullopt; public: using AccessorBase::AccessorBase; public: Result GetHeader(ReadableStructPin<PatchMetaExtendedDataHeader> *out) { R_RETURN(this->AcquireReadableStructPin(out, 0)); } Result GetHeader(PatchMetaExtendedDataHeader *out) { R_RETURN(this->template ReadStruct<PatchMetaExtendedDataHeader>(out, 0)); } Result GetHistoryHeader(ReadableStructPin<PatchHistoryHeader> *out, s32 index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= index && static_cast<u32>(index) < m_header->history_count, ncm::ResultInvalidOffset()); /* Get the header. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * index; R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetPatchDeltaHistory(ReadableStructPin<PatchDeltaHistory> *out, s32 index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= index && static_cast<u32>(index) < m_header->delta_history_count, ncm::ResultInvalidOffset()); /* Get the history. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * index; R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetPatchDeltaHeader(ReadableStructPin<PatchDeltaHeader> *out, s32 index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= index && static_cast<u32>(index) < m_header->delta_count, ncm::ResultInvalidOffset()); /* Get the header. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * index; R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetFragmentSet(ReadableStructPin<FragmentSet> *out, s32 delta_index, s32 fragment_set_index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= delta_index && static_cast<u32>(delta_index) < m_header->delta_count, ncm::ResultInvalidOffset()); /* Get the previous fragment set count. */ s32 previous_fragment_set_count = 0; R_TRY(this->CountFragmentSet(std::addressof(previous_fragment_set_count), delta_index)); /* Get the set. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * (previous_fragment_set_count + fragment_set_index); R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetFragmentSetDirectly(ReadableStructPin<FragmentSet> *out, s32 fragment_set_direct_index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= fragment_set_direct_index && static_cast<u32>(fragment_set_direct_index) < m_header->fragment_set_count, ncm::ResultInvalidOffset()); /* Get the set. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * (fragment_set_direct_index); R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetPatchHistoryContentInfo(ReadableStructPin<ContentInfo> *out, s32 history_index, s32 content_index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= history_index && static_cast<u32>(history_index) < m_header->history_count, ncm::ResultInvalidOffset()); /* Determine the true history content index. */ s32 prev_history_count = 0; R_TRY(this->CountHistoryContentInfo(std::addressof(prev_history_count), history_index)); /* Adjust and check the content index. */ content_index += prev_history_count; R_UNLESS(0 <= content_index && static_cast<u32>(content_index) < m_header->history_content_total_count, ncm::ResultInvalidOffset()); /* Get the info. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * m_header->fragment_set_count + sizeof(ContentInfo) * content_index; R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetPatchDeltaContentInfo(ReadableStructPin<PackagedContentInfo> *out, s32 delta_index, s32 content_index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= delta_index && static_cast<u32>(delta_index) < m_header->delta_count, ncm::ResultInvalidOffset()); /* Determine the true delta content index. */ s32 prev_delta_count = 0; R_TRY(this->CountDeltaContentInfo(std::addressof(prev_delta_count), delta_index)); /* Adjust and check the content index. */ content_index += prev_delta_count; R_UNLESS(0 <= content_index && static_cast<u32>(content_index) < m_header->delta_content_total_count, ncm::ResultInvalidOffset()); /* Get the info. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * m_header->fragment_set_count + sizeof(ContentInfo) * m_header->history_content_total_count + sizeof(PackagedContentInfo) * content_index; R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result GetFragmentIndicator(ReadableStructPin<FragmentIndicator> *out, s32 delta_index, s32 fragment_set_index, s32 index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= delta_index && static_cast<u32>(delta_index) < m_header->delta_count, ncm::ResultInvalidOffset()); /* Get the previous fragment set count. */ s32 previous_fragment_set_count = 0; R_TRY(this->CountFragmentSet(std::addressof(previous_fragment_set_count), delta_index)); /* Get the previous fragment indicator count. */ s32 previous_fragment_count = 0; R_TRY(this->CountFragmentIndicator(std::addressof(previous_fragment_count), previous_fragment_count + fragment_set_index)); /* Get the info. */ const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * m_header->fragment_set_count + sizeof(ContentInfo) * m_header->history_content_total_count + sizeof(PackagedContentInfo) * m_header->delta_content_total_count + sizeof(FragmentIndicator) * (previous_fragment_count + index); R_RETURN(this->AcquireReadableStructPin(out, offset)); } Result FindFragmentIndicator(ReadableStructPin<FragmentIndicator> *out, s32 delta_index, s32 fragment_set_index, s32 fragment_index) { /* Ensure we have our header. */ R_TRY(this->EnsureHeader()); /* Check that the index is valid. */ R_UNLESS(0 <= delta_index && static_cast<u32>(delta_index) < m_header->delta_count, ncm::ResultInvalidOffset()); /* Get the fragment count. */ s32 fragment_count = 0; { ReadableStructPin<FragmentSet> set; R_TRY(this->GetFragmentSet(std::addressof(set), delta_index, fragment_set_index)); fragment_count = set->fragment_count; } /* Get the previous fragment set count. */ s32 previous_fragment_set_count = 0; R_TRY(this->CountFragmentSet(std::addressof(previous_fragment_set_count), delta_index)); /* Get the previous fragment indicator count. */ s32 previous_fragment_count = 0; R_TRY(this->CountFragmentIndicator(std::addressof(previous_fragment_count), previous_fragment_count + fragment_set_index)); /* Look for a correct indicator. */ for (auto i = 0; i < fragment_count; ++i) { /* Get the current info. */ ReadableStructPin<FragmentIndicator> indicator; const size_t offset = sizeof(PatchHistoryHeader) + sizeof(PatchHistoryHeader) * m_header->history_count + sizeof(PatchDeltaHistory) * m_header->delta_history_count + sizeof(PatchDeltaHeader) * m_header->delta_count + sizeof(FragmentSet) * m_header->fragment_set_count + sizeof(ContentInfo) * m_header->history_content_total_count + sizeof(PackagedContentInfo) * m_header->delta_content_total_count + sizeof(FragmentIndicator) * (previous_fragment_count + i); R_TRY(this->AcquireReadableStructPin(std::addressof(indicator), offset)); /* If it matches, return it. */ if (indicator->fragment_index == fragment_index) { *out = std::move(indicator); R_SUCCEED(); } } /* We didn't find an indicator. */ R_THROW(ncm::ResultFragmentIndicatorNotFound()); } Result GetHistoryHeader(PatchHistoryHeader *out, s32 index) { /* Get the pin. */ ReadableStructPin<PatchHistoryHeader> pin; R_TRY(this->GetHistoryHeader(std::addressof(pin), index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetPatchDeltaHistory(PatchDeltaHistory *out, s32 index) { /* Get the pin. */ ReadableStructPin<PatchDeltaHistory> pin; R_TRY(this->GetPatchDeltaHistory(std::addressof(pin), index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetPatchDeltaHeader(PatchDeltaHeader *out, s32 index) { /* Get the pin. */ ReadableStructPin<PatchDeltaHeader> pin; R_TRY(this->GetPatchDeltaHeader(std::addressof(pin), index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetFragmentSet(FragmentSet *out, s32 delta_index, s32 fragment_set_index) { /* Get the pin. */ ReadableStructPin<FragmentSet> pin; R_TRY(this->GetFragmentSet(std::addressof(pin), delta_index, fragment_set_index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetPatchHistoryContentInfo(ContentInfo *out, s32 history_index, s32 content_index) { /* Get the header. */ ReadableStructPin<ContentInfo> pin; R_TRY(this->GetPatchHistoryContentInfo(std::addressof(pin), history_index, content_index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetPatchDeltaContentInfo(PackagedContentInfo *out, s32 delta_index, s32 content_index) { /* Get the header. */ ReadableStructPin<PackagedContentInfo> pin; R_TRY(this->GetPatchDeltaContentInfo(std::addressof(pin), delta_index, content_index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result GetFragmentIndicator(FragmentIndicator *out, s32 delta_index, s32 fragment_set_index, s32 index) { /* Get the header. */ ReadableStructPin<FragmentIndicator> pin; R_TRY(this->GetFragmentIndicator(std::addressof(pin), delta_index, fragment_set_index, index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result FindFragmentIndicator(FragmentIndicator *out, s32 delta_index, s32 fragment_set_index, s32 fragment_index) { /* Get the header. */ ReadableStructPin<FragmentIndicator> pin; R_TRY(this->FindFragmentIndicator(std::addressof(pin), delta_index, fragment_set_index, fragment_index)); /* Copy it out. */ *out = *pin; R_SUCCEED(); } Result CountHistoryContentInfo(s32 *out, s32 index) { R_RETURN(this->CountImpl(out, index, m_cached_history_content_count, [&](s32 *out, s32 i) -> Result { /* Get the history header. */ ReadableStructPin<ncm::PatchHistoryHeader> header; R_TRY(this->GetHistoryHeader(std::addressof(header), i)); /* Set the content count. */ *out = header->content_count; R_SUCCEED(); })); } Result CountDeltaContentInfo(s32 *out, s32 index) { R_RETURN(this->CountImpl(out, index, m_cached_delta_content_count, [&](s32 *out, s32 i) -> Result { /* Get the history header. */ ReadableStructPin<ncm::PatchDeltaHeader> header; R_TRY(this->GetPatchDeltaHeader(std::addressof(header), i)); /* Set the content count. */ *out = header->content_count; R_SUCCEED(); })); } Result CountFragmentSet(s32 *out, s32 index) { R_RETURN(this->CountImpl(out, index, m_cached_fragment_set_count, [&](s32 *out, s32 i) -> Result { /* Get the history header. */ ReadableStructPin<ncm::PatchDeltaHeader> header; R_TRY(this->GetPatchDeltaHeader(std::addressof(header), i)); /* Set the fragment set count. */ *out = header->delta.fragment_set_count; R_SUCCEED(); })); } Result CountFragmentIndicator(s32 *out, s32 index) { R_RETURN(this->CountImpl(out, index, m_cached_fragment_indicator_count, [&](s32 *out, s32 i) -> Result { /* Get the history header. */ ReadableStructPin<ncm::FragmentSet> set; R_TRY(this->GetFragmentSetDirectly(std::addressof(set), i)); /* Set the indicator count. */ *out = set->fragment_count; R_SUCCEED(); })); } private: Result CountImpl(s32 *out, s32 index, util::optional<CachedCount> &cache, auto get_count_impl) const { /* Ensure the value is cached. */ if (!(cache.has_value() && cache->index == index)) { /* Determine the count. */ CachedCount calc = { .index = index, .count = 0 }; for (auto i = 0; i < index; ++i) { s32 cur_count = 0; R_TRY(get_count_impl(std::addressof(cur_count), i)); calc.count += cur_count; } /* Cache the count. */ cache = calc; } /* Set the output count. */ *out = cache->count; R_SUCCEED(); } private: Result EnsureHeader() { /* If we have our header, we're good. */ R_SUCCEED_IF(m_header.has_value()); /* Get our header. */ PatchMetaExtendedDataHeader header{}; R_TRY(this->GetHeader(std::addressof(header))); /* Set our header. */ m_header.emplace(header); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_data_id.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> namespace ams::ncm { struct ApplicationId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const ApplicationId &) const = default; constexpr inline bool operator!=(const ApplicationId &) const = default; static const ApplicationId Start; static const ApplicationId End; }; constexpr inline const ApplicationId InvalidApplicationId = {}; inline constexpr const ApplicationId ApplicationId::Start = { 0x0100000000010000ul }; inline constexpr const ApplicationId ApplicationId::End = { 0x01FFFFFFFFFFFFFFul }; inline constexpr bool IsApplicationId(const ProgramId &program_id) { return ApplicationId::Start <= program_id && program_id <= ApplicationId::End; } inline constexpr bool IsApplicationId(const ApplicationId &) { return true; } struct ApplicationGroupId { u64 value; }; struct PatchId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const PatchId &) const = default; constexpr inline bool operator!=(const PatchId &) const = default; }; struct PatchGroupId { u64 value; }; struct AddOnContentId { u64 value; constexpr operator DataId() const { return { this->value }; } constexpr inline bool operator==(const AddOnContentId &) const = default; constexpr inline bool operator!=(const AddOnContentId &) const = default; }; struct DeltaId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const DeltaId &) const = default; constexpr inline bool operator!=(const DeltaId &) const = default; }; struct DataPatchId { u64 value; constexpr operator DataId() const { return { this->value }; } constexpr inline bool operator==(const DataPatchId &) const = default; constexpr inline bool operator!=(const DataPatchId &) const = default; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_key.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_content_meta_id.hpp> #include <stratosphere/ncm/ncm_content_meta_type.hpp> #include <stratosphere/ncm/ncm_system_content_meta_id.hpp> namespace ams::ncm { enum class ContentInstallType : u8 { Full = 0, FragmentOnly = 1, Unknown = 7, }; struct ContentMetaKey { u64 id; u32 version; ContentMetaType type; ContentInstallType install_type; u8 padding[2]; bool operator<(const ContentMetaKey &rhs) const { return std::tie(this->id, this->version, this->type, this->install_type) < std::tie(rhs.id, rhs.version, rhs.type, rhs.install_type); } constexpr bool operator==(const ContentMetaKey &rhs) const { return std::tie(this->id, this->version, this->type, this->install_type) == std::tie(rhs.id, rhs.version, rhs.type, rhs.install_type); } constexpr bool operator!=(const ContentMetaKey &rhs) const { return !(*this == rhs); } static constexpr ContentMetaKey MakeUnknownType(u64 id, u32 version) { return { .id = id, .version = version, .type = ContentMetaType::Unknown }; } static constexpr ContentMetaKey Make(u64 id, u32 version, ContentMetaType type) { return { .id = id, .version = version, .type = type }; } static constexpr ContentMetaKey Make(u64 id, u32 version, ContentMetaType type, ContentInstallType install_type) { return { .id = id, .version = version, .type = type, .install_type = install_type }; } static constexpr ContentMetaKey Make(SystemProgramId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::SystemProgram }; } static constexpr ContentMetaKey Make(SystemDataId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::SystemData }; } static constexpr ContentMetaKey Make(SystemUpdateId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::SystemUpdate }; } static constexpr ContentMetaKey Make(ApplicationId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::Application }; } static constexpr ContentMetaKey Make(PatchId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::Patch }; } static constexpr ContentMetaKey Make(PatchId id, u32 version, ContentInstallType install_type) { return { .id = id.value, .version = version, .type = ContentMetaType::Patch, .install_type = install_type }; } static constexpr ContentMetaKey Make(DeltaId id, u32 version) { return { .id = id.value, .version = version, .type = ContentMetaType::Delta }; } }; static_assert(sizeof(ContentMetaKey) == 0x10); struct ApplicationContentMetaKey { ContentMetaKey key; ncm::ApplicationId application_id; }; static_assert(sizeof(ApplicationContentMetaKey) == 0x18); struct StorageContentMetaKey { ContentMetaKey key; StorageId storage_id; u8 reserved[7]; constexpr bool operator==(StorageContentMetaKey &rhs) const { return this->key == rhs.key && this->storage_id == rhs.storage_id; } constexpr bool operator<(StorageContentMetaKey &rhs) const { return this->key == rhs.key ? this->storage_id < rhs.storage_id : this->key < rhs.key; } }; static_assert(sizeof(StorageContentMetaKey) == 0x18); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_platform.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { enum class ContentMetaPlatform : u8 { Nx = 0x0, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { enum class ContentMetaType : u8 { Unknown = 0x0, SystemProgram = 0x1, SystemData = 0x2, SystemUpdate = 0x3, BootImagePackage = 0x4, BootImagePackageSafe = 0x5, Application = 0x80, Patch = 0x81, AddOnContent = 0x82, Delta = 0x83, DataPatch = 0x84, }; const char *GetContentMetaTypeString(ContentMetaType type); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_auto_buffer.hpp> #include <stratosphere/ncm/ncm_storage_id.hpp> #include <stratosphere/ncm/ncm_content_storage.hpp> #include <stratosphere/ncm/ncm_content_meta_key.hpp> #include <stratosphere/ncm/ncm_content_meta_database.hpp> #include <stratosphere/ncm/ncm_firmware_variation.hpp> namespace ams::ncm { using MountContentMetaFunction = Result (*)(const char *mount_name, const char *path, fs::ContentAttributes attr); bool IsContentMetaFileName(const char *name); Result ReadContentMetaPathAlongWithExtendedDataAndDigest(AutoBuffer *out, const char *path, fs::ContentAttributes attr); Result ReadContentMetaPathAlongWithExtendedDataAndDigestSuppressingFsAbort(AutoBuffer *out, const char *path, fs::ContentAttributes attr); Result ReadContentMetaPathWithoutExtendedDataOrDigest(AutoBuffer *out, const char *path, fs::ContentAttributes attr); Result ReadContentMetaPathWithoutExtendedDataOrDigestSuppressingFsAbort(AutoBuffer *out, const char *path, fs::ContentAttributes attr); using ReadContentMetaPathFunction = Result (*)(AutoBuffer *out, const char *path, fs::ContentAttributes attr); Result TryReadContentMetaPath(fs::ContentAttributes *out_attr, AutoBuffer *out, const char *path, ReadContentMetaPathFunction func); Result TryReadContentMetaPath(AutoBuffer *out, const char *path, ReadContentMetaPathFunction func); Result ReadVariationContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const Path &path, fs::ContentAttributes attr, FirmwareVariationId firmware_variation_id); void SetMountContentMetaFunction(MountContentMetaFunction func); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_i_content_storage.hpp> namespace ams::ncm { class ContentStorage { NON_COPYABLE(ContentStorage); private: sf::SharedPointer<IContentStorage> m_interface; public: ContentStorage() : m_interface(nullptr) { /* ... */ } explicit ContentStorage(sf::SharedPointer<IContentStorage> intf) : m_interface(intf) { /* ... */ } ContentStorage(ContentStorage &&rhs) { m_interface = std::move(rhs.m_interface); } ContentStorage &operator=(ContentStorage &&rhs) { ContentStorage(std::move(rhs)).swap(*this); return *this; } void swap(ContentStorage &rhs) { std::swap(m_interface, rhs.m_interface); } public: PlaceHolderId GeneratePlaceHolderId() { AMS_ASSERT(m_interface != nullptr); PlaceHolderId id; R_ABORT_UNLESS(m_interface->GeneratePlaceHolderId(std::addressof(id))); return id; } Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->CreatePlaceHolder(placeholder_id, content_id, size)); } Result DeletePlaceHolder(PlaceHolderId placeholder_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->DeletePlaceHolder(placeholder_id)); } Result HasPlaceHolder(bool *out, PlaceHolderId placeholder_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->HasPlaceHolder(out, placeholder_id)); } Result WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const void *buf, size_t size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->WritePlaceHolder(placeholder_id, offset, sf::InBuffer(buf, size))); } Result Register(PlaceHolderId placeholder_id, ContentId content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Register(placeholder_id, content_id)); } Result Delete(ContentId content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Delete(content_id)); } Result Has(bool *out, ContentId content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->Has(out, content_id)); } void GetPath(Path *out, ContentId content_id) { AMS_ASSERT(m_interface != nullptr); R_ABORT_UNLESS(m_interface->GetPath(out, content_id)); } void GetPlaceHolderPath(Path *out, PlaceHolderId placeholder_id) { AMS_ASSERT(m_interface != nullptr); R_ABORT_UNLESS(m_interface->GetPlaceHolderPath(out, placeholder_id)); } Result CleanupAllPlaceHolder() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->CleanupAllPlaceHolder()); } Result ListPlaceHolder(s32 *out_count, PlaceHolderId *out_list, size_t out_list_size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ListPlaceHolder(out_count, sf::OutArray<PlaceHolderId>(out_list, out_list_size))); } Result GetContentCount(s32 *out_count) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetContentCount(out_count)); } Result ListContentId(s32 *out_count, ContentId *out_list, size_t out_list_size, s32 offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ListContentId(out_count, sf::OutArray<ContentId>(out_list, out_list_size), offset)); } Result GetSize(s64 *out_size, ContentId content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetSizeFromContentId(out_size, content_id)); } Result GetSize(s64 *out_size, PlaceHolderId placeholder_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetSizeFromPlaceHolderId(out_size, placeholder_id)); } Result DisableForcibly() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->DisableForcibly()); } Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->RevertToPlaceHolder(placeholder_id, old_content_id, new_content_id)); } Result SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->SetPlaceHolderSize(placeholder_id, size)); } Result ReadContentIdFile(void *dst, size_t size, ContentId content_id, s64 offset) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->ReadContentIdFile(sf::OutBuffer(dst, size), content_id, offset)); } Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr) { AMS_ASSERT(m_interface != nullptr); const auto vers = hos::GetVersion(); if (vers >= hos::Version_16_0_0) { R_RETURN(m_interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id, attr)); } else if (vers >= hos::Version_3_0_0) { R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdDeprecated2(out_rights_id, placeholder_id)); } else { AMS_ABORT_UNLESS(vers >= hos::Version_2_0_0); *out_rights_id = {}; R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdDeprecated(std::addressof(out_rights_id->id), placeholder_id)); } } Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id, fs::ContentAttributes attr) { AMS_ASSERT(m_interface != nullptr); const auto vers = hos::GetVersion(); if (vers >= hos::Version_16_0_0) { R_RETURN(m_interface->GetRightsIdFromContentId(out_rights_id, content_id, attr)); } else if (vers >= hos::Version_3_0_0) { R_RETURN(m_interface->GetRightsIdFromContentIdDeprecated2(out_rights_id, content_id)); } else { AMS_ABORT_UNLESS(vers >= hos::Version_2_0_0); *out_rights_id = {}; R_RETURN(m_interface->GetRightsIdFromContentIdDeprecated(std::addressof(out_rights_id->id), content_id)); } } Result WriteContentForDebug(ContentId content_id, s64 offset, const void *buf, size_t size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->WriteContentForDebug(content_id, offset, sf::InBuffer(buf, size))); } Result GetFreeSpaceSize(s64 *out_size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetFreeSpaceSize(out_size)); } Result GetTotalSpaceSize(s64 *out_size) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetTotalSpaceSize(out_size)); } Result FlushPlaceHolder() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->FlushPlaceHolder()); } Result RepairInvalidFileAttribute() { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->RepairInvalidFileAttribute()); } Result GetRightsIdFromPlaceHolderIdWithCache(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) { AMS_ASSERT(m_interface != nullptr); const auto vers = hos::GetVersion(); if (vers >= hos::Version_16_0_0) { R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id, attr)); } else { R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdWithCacheDeprecated(out_rights_id, cache_content_id, placeholder_id)); } } Result GetProgramId(ncm::ProgramId *out, ContentId content_id, fs::ContentAttributes attr) { AMS_ASSERT(m_interface != nullptr); R_RETURN(m_interface->GetProgramId(out, content_id, attr)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_content_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { enum class ContentType : u8 { Meta = 0, Program = 1, Data = 2, Control = 3, HtmlDocument = 4, LegalInformation = 5, DeltaFragment = 6, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_data_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct DataId { u64 value; static const DataId Invalid; constexpr inline auto operator<=>(const DataId &) const = default; }; inline constexpr const DataId DataId::Invalid = {}; inline constexpr const DataId InvalidDataId = DataId::Invalid; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_firmware_variation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct FirmwareVariationInfo { bool refer_to_base; u8 _0x1[3]; u32 content_meta_count; u8 reserved[0x18]; }; struct FirmwareVariationId { u32 value; }; constexpr inline bool operator==(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) { return lhs.value == rhs.value; } constexpr inline bool operator!=(const FirmwareVariationId &lhs, const FirmwareVariationId &rhs) { return lhs.value != rhs.value; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_i_content_storage.hpp> #include <stratosphere/ncm/ncm_i_content_meta_database.hpp> #include <stratosphere/ncm/ncm_memory_report.hpp> #include <stratosphere/fs/fs_content_storage_id.hpp> #define AMS_NCM_I_CONTENT_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, CreateContentStorage, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, VerifyContentStorage, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, VerifyContentMetaDatabase, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, OpenContentStorage, (sf::Out<sf::SharedPointer<ncm::IContentStorage>> out, ncm::StorageId storage_id), (out, storage_id)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, OpenContentMetaDatabase, (sf::Out<sf::SharedPointer<ncm::IContentMetaDatabase>> out, ncm::StorageId storage_id), (out, storage_id)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, CloseContentStorageForcibly, (ncm::StorageId storage_id), (storage_id), hos::Version_1_0_0, hos::Version_1_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, CloseContentMetaDatabaseForcibly, (ncm::StorageId storage_id), (storage_id), hos::Version_1_0_0, hos::Version_1_0_0) \ AMS_SF_METHOD_INFO(C, H, 8, Result, CleanupContentMetaDatabase, (ncm::StorageId storage_id), (storage_id)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, ActivateContentStorage, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, InactivateContentStorage, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 11, Result, ActivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 12, Result, InactivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateRightsIdCache, (), (), hos::Version_9_0_0) \ AMS_SF_METHOD_INFO(C, H, 14, Result, GetMemoryReport, (sf::Out<ncm::MemoryReport> out), (out), hos::Version_10_0_0) \ AMS_SF_METHOD_INFO(C, H, 15, Result, ActivateFsContentStorage, (fs::ContentStorageId fs_storage_id), (fs_storage_id)) /* Technically min 16.0.0, but used. */ AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentManager, AMS_NCM_I_CONTENT_MANAGER_INTERFACE_INFO, 0xFDB4FFE1); ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf.hpp> #include <stratosphere/ncm/ncm_content_meta.hpp> #define AMS_NCM_I_CONTENT_META_DATABASE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Set, (const ncm::ContentMetaKey &key, const sf::InBuffer &value), (key, value)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Get, (sf::Out<u64> out_size, const ncm::ContentMetaKey &key, const sf::OutBuffer &out_value), (out_size, key, out_value)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Remove, (const ncm::ContentMetaKey &key), (key)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetContentIdByType, (sf::Out<ncm::ContentId> out_content_id, const ncm::ContentMetaKey &key, ncm::ContentType type), (out_content_id, key, type)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, ListContentInfo, (sf::Out<s32> out_entries_written, const sf::OutArray<ncm::ContentInfo> &out_info, const ncm::ContentMetaKey &key, s32 offset), (out_entries_written, out_info, key, offset)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, List, (sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ncm::ContentMetaKey> &out_info, ncm::ContentMetaType meta_type, ncm::ApplicationId application_id, u64 min, u64 max, ncm::ContentInstallType install_type), (out_entries_total, out_entries_written, out_info, meta_type, application_id, min, max, install_type)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetLatestContentMetaKey, (sf::Out<ncm::ContentMetaKey> out_key, u64 id), (out_key, id)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, ListApplication, (sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ncm::ApplicationContentMetaKey> &out_keys, ncm::ContentMetaType meta_type), (out_entries_total, out_entries_written, out_keys, meta_type)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, Has, (sf::Out<bool> out, const ncm::ContentMetaKey &key), (out, key)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, HasAll, (sf::Out<bool> out, const sf::InArray<ncm::ContentMetaKey> &keys), (out, keys)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, GetSize, (sf::Out<u64> out_size, const ncm::ContentMetaKey &key), (out_size, key)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetRequiredSystemVersion, (sf::Out<u32> out_version, const ncm::ContentMetaKey &key), (out_version, key)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetPatchContentMetaId, (sf::Out<u64> out_patch_id, const ncm::ContentMetaKey &key), (out_patch_id, key)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, DisableForcibly, (), ()) \ AMS_SF_METHOD_INFO(C, H, 14, Result, LookupOrphanContent, (const sf::OutArray<bool> &out_orphaned, const sf::InArray<ncm::ContentId> &content_ids), (out_orphaned, content_ids)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, Commit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 16, Result, HasContent, (sf::Out<bool> out, const ncm::ContentMetaKey &key, const ncm::ContentId &content_id), (out, key, content_id)) \ AMS_SF_METHOD_INFO(C, H, 17, Result, ListContentMetaInfo, (sf::Out<s32> out_entries_written, const sf::OutArray<ncm::ContentMetaInfo> &out_meta_info, const ncm::ContentMetaKey &key, s32 offset), (out_entries_written, out_meta_info, key, offset)) \ AMS_SF_METHOD_INFO(C, H, 18, Result, GetAttributes, (sf::Out<u8> out_attributes, const ncm::ContentMetaKey &key), (out_attributes, key)) \ AMS_SF_METHOD_INFO(C, H, 19, Result, GetRequiredApplicationVersion, (sf::Out<u32> out_version, const ncm::ContentMetaKey &key), (out_version, key), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, GetContentIdByTypeAndIdOffset, (sf::Out<ncm::ContentId> out_content_id, const ncm::ContentMetaKey &key, ncm::ContentType type, u8 id_offset), (out_content_id, key, type, id_offset), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 21, Result, GetCount, (sf::Out<u32> out_count), (out_count), hos::Version_10_0_0) \ AMS_SF_METHOD_INFO(C, H, 22, Result, GetOwnerApplicationId, (sf::Out<ncm::ApplicationId> out_id, const ncm::ContentMetaKey &key), (out_id, key), hos::Version_10_0_0) \ AMS_SF_METHOD_INFO(C, H, 23, Result, GetContentAccessibilities, (sf::Out<u8> out_accessibilities, const ncm::ContentMetaKey &key), (out_accessibilities, key), hos::Version_15_0_0) \ AMS_SF_METHOD_INFO(C, H, 24, Result, GetContentInfoByType, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type), (out_content_info, key, type), hos::Version_15_0_0) \ AMS_SF_METHOD_INFO(C, H, 25, Result, GetContentInfoByTypeAndIdOffset, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type, u8 id_offset), (out_content_info, key, type, id_offset), hos::Version_15_0_0) \ AMS_SF_METHOD_INFO(C, H, 26, Result, GetPlatform, (sf::Out<ncm::ContentMetaPlatform> out, const ncm::ContentMetaKey &key), (out, key), hos::Version_17_0_0) \ AMS_SF_METHOD_INFO(C, H, 27, Result, HasAttributes, (sf::Out<u8> out, u8 attr_mask), (out, attr_mask), hos::Version_20_0_0) AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentMetaDatabase, AMS_NCM_I_CONTENT_META_DATABASE_INTERFACE_INFO, 0x58021FEC) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf.hpp> #include <stratosphere/ncm/ncm_content_id.hpp> #include <stratosphere/ncm/ncm_placeholder_id.hpp> #include <stratosphere/ncm/ncm_path.hpp> #include <stratosphere/ncm/ncm_rights_id.hpp> #define AMS_NCM_I_CONTENT_STORAGE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GeneratePlaceHolderId, (sf::Out<ncm::PlaceHolderId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreatePlaceHolder_AtmosphereAlignmentFix, (ncm::ContentId content_id, ncm::PlaceHolderId placeholder_id, s64 size), (content_id, placeholder_id, size), hos::Version_Min, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreatePlaceHolder, (ncm::PlaceHolderId placeholder_id, ncm::ContentId content_id, s64 size), (placeholder_id, content_id, size), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 2, Result, DeletePlaceHolder, (ncm::PlaceHolderId placeholder_id), (placeholder_id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, HasPlaceHolder, (sf::Out<bool> out, ncm::PlaceHolderId placeholder_id), (out, placeholder_id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, WritePlaceHolder, (ncm::PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data), (placeholder_id, offset, data)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, Register_AtmosphereAlignmentFix, (ncm::ContentId content_id, ncm::PlaceHolderId placeholder_id), (content_id, placeholder_id), hos::Version_Min, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 5, Result, Register, (ncm::PlaceHolderId placeholder_id, ncm::ContentId content_id), (placeholder_id, content_id), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, Delete, (ncm::ContentId content_id), (content_id)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, Has, (sf::Out<bool> out, ncm::ContentId content_id), (out, content_id)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, GetPath, (sf::Out<ncm::Path> out, ncm::ContentId content_id), (out, content_id)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, GetPlaceHolderPath, (sf::Out<ncm::Path> out, ncm::PlaceHolderId placeholder_id), (out, placeholder_id)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CleanupAllPlaceHolder, (), ()) \ AMS_SF_METHOD_INFO(C, H, 11, Result, ListPlaceHolder, (sf::Out<s32> out_count, const sf::OutArray<ncm::PlaceHolderId> &out_buf), (out_count, out_buf)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetContentCount, (sf::Out<s32> out_count), (out_count)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, ListContentId, (sf::Out<s32> out_count, const sf::OutArray<ncm::ContentId> &out_buf, s32 start_offset), (out_count, out_buf, start_offset)) \ AMS_SF_METHOD_INFO(C, H, 14, Result, GetSizeFromContentId, (sf::Out<s64> out_size, ncm::ContentId content_id), (out_size, content_id)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, DisableForcibly, (), ()) \ AMS_SF_METHOD_INFO(C, H, 16, Result, RevertToPlaceHolder_AtmosphereAlignmentFix, (ncm::ContentId old_content_id, ncm::ContentId new_content_id, ncm::PlaceHolderId placeholder_id), (old_content_id, new_content_id, placeholder_id), hos::Version_2_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 16, Result, RevertToPlaceHolder, (ncm::PlaceHolderId placeholder_id, ncm::ContentId old_content_id, ncm::ContentId new_content_id), (placeholder_id, old_content_id, new_content_id), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 17, Result, SetPlaceHolderSize, (ncm::PlaceHolderId placeholder_id, s64 size), (placeholder_id, size), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 18, Result, ReadContentIdFile, (const sf::OutBuffer &buf, ncm::ContentId content_id, s64 offset), (buf, content_id, offset), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 19, Result, GetRightsIdFromPlaceHolderIdDeprecated, (sf::Out<ams::fs::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id), (out_rights_id, placeholder_id), hos::Version_2_0_0, hos::Version_2_3_0) \ AMS_SF_METHOD_INFO(C, H, 19, Result, GetRightsIdFromPlaceHolderIdDeprecated2, (sf::Out<ncm::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id), (out_rights_id, placeholder_id), hos::Version_3_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 19, Result, GetRightsIdFromPlaceHolderId, (sf::Out<ncm::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id, fs::ContentAttributes attr), (out_rights_id, placeholder_id, attr), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, GetRightsIdFromContentIdDeprecated, (sf::Out<ams::fs::RightsId> out_rights_id, ncm::ContentId content_id), (out_rights_id, content_id), hos::Version_2_0_0, hos::Version_2_3_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, GetRightsIdFromContentIdDeprecated2, (sf::Out<ncm::RightsId> out_rights_id, ncm::ContentId content_id), (out_rights_id, content_id), hos::Version_3_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 20, Result, GetRightsIdFromContentId, (sf::Out<ncm::RightsId> out_rights_id, ncm::ContentId content_id, fs::ContentAttributes attr), (out_rights_id, content_id, attr), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 21, Result, WriteContentForDebug, (ncm::ContentId content_id, s64 offset, const sf::InBuffer &data), (content_id, offset, data), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 22, Result, GetFreeSpaceSize, (sf::Out<s64> out_size), (out_size), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 23, Result, GetTotalSpaceSize, (sf::Out<s64> out_size), (out_size), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 24, Result, FlushPlaceHolder, (), (), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 25, Result, GetSizeFromPlaceHolderId, (sf::Out<s64> out, ncm::PlaceHolderId placeholder_id), (out, placeholder_id), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 26, Result, RepairInvalidFileAttribute, (), (), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCacheDeprecated, (sf::Out<ncm::RightsId> out_rights_id, ncm::ContentId cache_content_id, ncm::PlaceHolderId placeholder_id), (out_rights_id, cache_content_id, placeholder_id), hos::Version_8_0_0, hos::Version_15_0_1) \ AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCache, (sf::Out<ncm::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id, ncm::ContentId cache_content_id, fs::ContentAttributes attr), (out_rights_id, placeholder_id, cache_content_id, attr), hos::Version_16_0_0) \ AMS_SF_METHOD_INFO(C, H, 28, Result, RegisterPath, (const ncm::ContentId &content_id, const ncm::Path &path), (content_id, path), hos::Version_13_0_0) \ AMS_SF_METHOD_INFO(C, H, 29, Result, ClearRegisteredPath, (), (), hos::Version_13_0_0) \ AMS_SF_METHOD_INFO(C, H, 30, Result, GetProgramId, (sf::Out<ncm::ProgramId> out, ncm::ContentId content_id, fs::ContentAttributes attr), (out, content_id, attr), hos::Version_17_0_0) AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentStorage, AMS_NCM_I_CONTENT_STORAGE_INTERFACE_INFO, 0xFEAE3DD1) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_ids.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_data_id.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> #include <stratosphere/ncm/ncm_content_meta_id.hpp> #include <stratosphere/ncm/ncm_system_content_meta_id.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_install_progress.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::ncm { enum class InstallProgressState : u8 { NotPrepared = 0, DataPrepared = 1, Prepared = 2, Downloaded = 3, Committed = 4, Fatal = 5, }; struct InstallProgress { InstallProgressState state; u8 pad[3]; util::TypedStorage<Result> last_result; s64 installed_size; s64 total_size; Result GetLastResult() const { return util::GetReference(last_result); } void SetLastResult(Result result) { *util::GetPointer(last_result) = result; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_install_task_data.hpp> #include <stratosphere/ncm/ncm_install_task_occupied_size.hpp> namespace ams::ncm { enum class ListContentMetaKeyFilter : u8 { All = 0, Committed = 1, NotCommitted = 2, }; enum InstallConfig { InstallConfig_None = (0 << 0), InstallConfig_SystemUpdate = (1 << 2), InstallConfig_RequiresExFatDriver = (1 << 3), InstallConfig_IgnoreTicket = (1 << 4), }; struct InstallThroughput { s64 installed; TimeSpan elapsed_time; }; struct InstallContentMetaInfo { ContentId content_id; s64 content_size; ContentMetaKey key; bool verify_digest; bool has_key; Digest digest; static constexpr InstallContentMetaInfo MakeVerifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky, const Digest &d) { return { .content_id = cid, .content_size = sz, .key = ky, .verify_digest = true, .has_key = true, .digest = d, }; } static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz, const ContentMetaKey &ky) { return { .content_id = cid, .content_size = sz, .key = ky, .verify_digest = false, .has_key = true, }; } static constexpr InstallContentMetaInfo MakeUnverifiable(const ContentId &cid, s64 sz) { return { .content_id = cid, .content_size = sz, .verify_digest = false, .has_key = false, }; } }; static_assert(sizeof(InstallContentMetaInfo) == 0x50); class InstallTaskBase { NON_COPYABLE(InstallTaskBase); NON_MOVEABLE(InstallTaskBase); private: crypto::Sha256Generator m_sha256_generator{}; StorageId m_install_storage{}; InstallTaskDataBase *m_data{}; InstallProgress m_progress{}; os::SdkMutex m_progress_mutex{}; u32 m_config{}; os::SdkMutex m_cancel_mutex{}; bool m_cancel_requested{}; InstallThroughput m_throughput{}; TimeSpan m_throughput_start_time{}; os::SdkMutex m_throughput_mutex{}; FirmwareVariationId m_firmware_variation_id{}; private: ALWAYS_INLINE Result SetLastResultOnFailure(Result result) { if (R_FAILED(result)) { this->SetLastResult(result); } R_RETURN(result); } public: InstallTaskBase() : m_data(), m_progress(), m_progress_mutex(), m_cancel_mutex(), m_cancel_requested(), m_throughput_mutex() { /* ... */ } virtual ~InstallTaskBase() { /* ... */ }; public: virtual void Cancel(); virtual void ResetCancel(); Result Prepare(); Result GetPreparedPlaceHolderPath(Path *out_path, u64 id, ContentMetaType meta_type, ContentType type); Result CalculateRequiredSize(s64 *out_size); Result Cleanup(); Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter); Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset) { R_RETURN(this->ListContentMetaKey(out_keys_written, out_keys, out_keys_count, offset, ListContentMetaKeyFilter::All)); } Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset); Result Execute(); Result PrepareAndExecute(); Result Commit(const StorageContentMetaKey *keys, s32 num_keys); Result Commit() { R_RETURN(this->Commit(nullptr, 0)); } virtual InstallProgress GetProgress(); void ResetLastResult(); Result IncludesExFatDriver(bool *out); InstallThroughput GetThroughput(); Result CalculateContentsSize(s64 *out_size, const ContentMetaKey &key, StorageId storage_id); Result ListOccupiedSize(s32 *out_written, InstallTaskOccupiedSize *out_list, s32 out_list_size, s32 offset); Result FindMaxRequiredApplicationVersion(u32 *out); Result FindMaxRequiredSystemVersion(u32 *out); protected: Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config); Result PrepareContentMeta(const InstallContentMetaInfo &meta_info, util::optional<ContentMetaKey> key, util::optional<u32> source_version); Result PrepareContentMeta(ContentId content_id, s64 size, ContentMetaType meta_type, AutoBuffer *buffer); Result WritePlaceHolderBuffer(InstallContentInfo *content_info, const void *data, size_t data_size); void PrepareAgain(); Result CountInstallContentMetaData(s32 *out_count); Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index); Result DeleteInstallContentMetaData(const ContentMetaKey *keys, s32 num_keys); virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) = 0; virtual Result PrepareDependency(); Result PrepareSystemUpdateDependency(); virtual Result PrepareContentMetaIfLatest(const ContentMetaKey &key); /* NOTE: This is not virtual in Nintendo's code. We do so to facilitate downgrades. */ u32 GetConfig() const { return m_config; } Result WriteContentMetaToPlaceHolder(InstallContentInfo *out_install_content_info, ContentStorage *storage, const InstallContentMetaInfo &meta_info, util::optional<bool> is_temporary); StorageId GetInstallStorage() const { return m_install_storage; } virtual Result OnPrepareComplete() { R_SUCCEED(); } Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out); Result CanContinue(); private: bool IsCancelRequested(); Result PrepareImpl(); Result ExecuteImpl(); Result CommitImpl(const StorageContentMetaKey *keys, s32 num_keys); Result CleanupOne(const InstallContentMeta &content_meta); Result VerifyAllNotCommitted(const StorageContentMetaKey *keys, s32 num_keys); virtual Result PrepareInstallContentMetaData() = 0; virtual Result GetLatestVersion(util::optional<u32> *out_version, u64 id) { AMS_UNUSED(out_version, id); R_THROW(ncm::ResultContentMetaNotFound()); } virtual Result OnExecuteComplete() { R_SUCCEED(); } Result WritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info); virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) = 0; bool IsNecessaryInstallTicket(const fs::RightsId &rights_id); virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) = 0; Result IsNewerThanInstalled(bool *out, const ContentMetaKey &key); Result PreparePlaceHolder(); void SetProgressState(InstallProgressState state); void IncrementProgress(s64 size); void SetTotalSize(s64 size); void SetLastResult(Result last_result); void CleanupProgress(); void ResetThroughputMeasurement(); void StartThroughputMeasurement(); void UpdateThroughputMeasurement(s64 throughput); Result GetInstallContentMetaDataFromPath(AutoBuffer *out, const Path &path, const InstallContentInfo &content_info, util::optional<u32> source_version); InstallContentInfo MakeInstallContentInfoFrom(const InstallContentMetaInfo &info, const PlaceHolderId &placeholder_id, util::optional<bool> is_temporary); Result ReadContentMetaInfoList(s32 *out_count, std::unique_ptr<ContentMetaInfo[]> *out_meta_infos, const ContentMetaKey &key, fs::ContentAttributes attr); Result ListRightsIdsByInstallContentMeta(s32 *out_count, Span<RightsId> out_span, const InstallContentMeta &content_meta, s32 offset); public: virtual Result CheckInstallable() { R_SUCCEED(); } void SetFirmwareVariationId(FirmwareVariationId id) { m_firmware_variation_id = id; } Result ListRightsIds(s32 *out_count, Span<RightsId> out_span, const ContentMetaKey &key, s32 offset); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_data.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_meta.hpp> #include <stratosphere/ncm/ncm_install_progress.hpp> #include <stratosphere/ncm/ncm_system_update_task_apply_info.hpp> namespace ams::ncm { struct InstallContentMeta { std::unique_ptr<char[]> data; size_t size; InstallContentMetaReader GetReader() const { return InstallContentMetaReader(this->data.get(), this->size); } InstallContentMetaWriter GetWriter() const { return InstallContentMetaWriter(this->data.get(), this->size); } }; class InstallTaskDataBase { public: Result Get(InstallContentMeta *out, s32 index); Result Update(const InstallContentMeta &content_meta, s32 index); Result Has(bool *out, u64 id); public: virtual Result GetProgress(InstallProgress *out_progress) = 0; virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) = 0; virtual Result SetState(InstallProgressState state) = 0; virtual Result SetLastResult(Result result) = 0; virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) = 0; virtual Result Push(const void *data, size_t data_size) = 0; virtual Result Count(s32 *out) = 0; virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) = 0; virtual Result Cleanup() = 0; private: virtual Result GetSize(size_t *out_size, s32 index) = 0; virtual Result Get(s32 index, void *out, size_t out_size) = 0; virtual Result Update(s32 index, const void *data, size_t data_size) = 0; }; class MemoryInstallTaskData : public InstallTaskDataBase { private: struct DataHolder : public InstallContentMeta, public util::IntrusiveListBaseNode<DataHolder>{}; using DataList = util::IntrusiveListBaseTraits<DataHolder>::ListType; private: DataList m_data_list; InstallProgressState m_state; Result m_last_result; SystemUpdateTaskApplyInfo m_system_update_task_apply_info; public: MemoryInstallTaskData() : m_data_list(), m_state(InstallProgressState::NotPrepared), m_last_result(ResultSuccess()), m_system_update_task_apply_info() { /* ... */ }; ~MemoryInstallTaskData() { this->Cleanup(); } public: virtual Result GetProgress(InstallProgress *out_progress) override; virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) override; virtual Result SetState(InstallProgressState state) override; virtual Result SetLastResult(Result result) override; virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) override; virtual Result Push(const void *data, size_t data_size) override; virtual Result Count(s32 *out) override; virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override; virtual Result Cleanup() override; private: virtual Result GetSize(size_t *out_size, s32 index) override; virtual Result Get(s32 index, void *out, size_t out_size) override; virtual Result Update(s32 index, const void *data, size_t data_size) override; }; class FileInstallTaskData : public InstallTaskDataBase { private: struct Header { u32 max_entries; u32 count; s64 last_data_offset; Result last_result; InstallProgressState progress_state; SystemUpdateTaskApplyInfo system_update_task_apply_info; }; static_assert(sizeof(Header) == 0x18); struct EntryInfo { s64 offset; s64 size; }; static_assert(sizeof(EntryInfo) == 0x10); private: Header m_header{}; char m_path[64]{}; private: static constexpr Header MakeInitialHeader(s32 max_entries) { return { .max_entries = static_cast<u32>(max_entries), .count = 0, .last_data_offset = GetEntryInfoOffset(max_entries), .last_result = ResultSuccess(), .progress_state = InstallProgressState::NotPrepared, .system_update_task_apply_info = SystemUpdateTaskApplyInfo::Unknown, }; } static constexpr s64 GetEntryInfoOffset(s32 index) { return index * sizeof(EntryInfo) + sizeof(Header); } public: static Result Create(const char *path, s32 max_entries); Result Initialize(const char *path); public: virtual Result GetProgress(InstallProgress *out_progress) override; virtual Result GetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo *out_info) override; virtual Result SetState(InstallProgressState state) override; virtual Result SetLastResult(Result result) override; virtual Result SetSystemUpdateTaskApplyInfo(SystemUpdateTaskApplyInfo info) override; virtual Result Push(const void *data, size_t data_size) override; virtual Result Count(s32 *out) override; virtual Result Delete(const ContentMetaKey *keys, s32 num_keys) override; virtual Result Cleanup() override; private: virtual Result GetSize(size_t *out_size, s32 index) override; virtual Result Get(s32 index, void *out, size_t out_size) override; virtual Result Update(s32 index, const void *data, size_t data_size) override; Result GetEntryInfo(EntryInfo *out_entry_info, s32 index); Result Write(const void *data, size_t size, s64 offset); Result Read(void *out, size_t out_size, s64 offset); Result WriteHeader(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_install_task_occupied_size.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_meta_key.hpp> namespace ams::ncm { struct InstallTaskOccupiedSize { ContentMetaKey key; s64 size; StorageId storage_id; u8 reserved[7]; }; static_assert(sizeof(InstallTaskOccupiedSize) == 0x20); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <stratosphere/ncm/ncm_i_content_meta_database.hpp> #include <stratosphere/ncm/ncm_integrated_list.hpp> namespace ams::ncm { class IntegratedContentMetaDatabaseImpl { NON_COPYABLE(IntegratedContentMetaDatabaseImpl); NON_MOVEABLE(IntegratedContentMetaDatabaseImpl); private: using ListType = ncm::IntegratedList<ncm::IContentMetaDatabase, 2>; using DataType = ListType::ListData; private: os::SdkRecursiveMutex m_mutex; ListType m_list; bool m_disabled; public: IntegratedContentMetaDatabaseImpl() : m_mutex(), m_list(), m_disabled(false) { /* ... */ } void Add(sf::SharedPointer<ncm::IContentMetaDatabase> p, u8 id) { DataType data = {std::move(p), id}; m_list.Add(data); } private: /* Helpers. */ Result EnsureEnabled() const { R_UNLESS(!m_disabled, ncm::ResultInvalidContentMetaDatabase()); R_SUCCEED(); } public: /* Actual commands. */ Result Set(const ContentMetaKey &key, const sf::InBuffer &value); Result Get(sf::Out<u64> out_size, const ContentMetaKey &key, const sf::OutBuffer &out_value); Result Remove(const ContentMetaKey &key); Result GetContentIdByType(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type); Result ListContentInfo(sf::Out<s32> out_entries_written, const sf::OutArray<ContentInfo> &out_info, const ContentMetaKey &key, s32 offset); Result List(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaKey> &out_info, ContentMetaType meta_type, ApplicationId application_id, u64 min, u64 max, ContentInstallType install_type); Result GetLatestContentMetaKey(sf::Out<ContentMetaKey> out_key, u64 id); Result ListApplication(sf::Out<s32> out_entries_total, sf::Out<s32> out_entries_written, const sf::OutArray<ApplicationContentMetaKey> &out_keys, ContentMetaType meta_type); Result Has(sf::Out<bool> out, const ContentMetaKey &key); Result HasAll(sf::Out<bool> out, const sf::InArray<ContentMetaKey> &keys); Result GetSize(sf::Out<u64> out_size, const ContentMetaKey &key); Result GetRequiredSystemVersion(sf::Out<u32> out_version, const ContentMetaKey &key); Result GetPatchContentMetaId(sf::Out<u64> out_patch_id, const ContentMetaKey &key); Result DisableForcibly(); Result LookupOrphanContent(const sf::OutArray<bool> &out_orphaned, const sf::InArray<ContentId> &content_ids); Result Commit(); Result HasContent(sf::Out<bool> out, const ContentMetaKey &key, const ContentId &content_id); Result ListContentMetaInfo(sf::Out<s32> out_entries_written, const sf::OutArray<ContentMetaInfo> &out_meta_info, const ContentMetaKey &key, s32 offset); Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key); Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key); Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset); Result GetCount(sf::Out<u32> out_count); Result GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key); Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key); Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type); Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset); Result GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key); Result HasAttributes(sf::Out<u8> out, u8 attr_mask); }; static_assert(ncm::IsIContentMetaDatabase<IntegratedContentMetaDatabaseImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_content_storage_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <stratosphere/ncm/ncm_i_content_storage.hpp> #include <stratosphere/ncm/ncm_integrated_list.hpp> namespace ams::ncm { class IntegratedContentStorageImpl { NON_COPYABLE(IntegratedContentStorageImpl); NON_MOVEABLE(IntegratedContentStorageImpl); private: using ListType = ncm::IntegratedList<ncm::IContentStorage, 2>; using DataType = ListType::ListData; private: os::SdkRecursiveMutex m_mutex; ListType m_list; bool m_disabled; public: IntegratedContentStorageImpl() : m_mutex(), m_list(), m_disabled(false) { /* ... */ } void Add(sf::SharedPointer<ncm::IContentStorage> p, u8 id) { DataType data = {std::move(p), id}; m_list.Add(data); } private: /* Helpers. */ Result EnsureEnabled() const { R_UNLESS(!m_disabled, ncm::ResultInvalidContentStorage()); R_SUCCEED(); } public: /* Actual commands. */ Result GeneratePlaceHolderId(sf::Out<PlaceHolderId> out); Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, s64 size); Result DeletePlaceHolder(PlaceHolderId placeholder_id); Result HasPlaceHolder(sf::Out<bool> out, PlaceHolderId placeholder_id); Result WritePlaceHolder(PlaceHolderId placeholder_id, s64 offset, const sf::InBuffer &data); Result Register(PlaceHolderId placeholder_id, ContentId content_id); Result Delete(ContentId content_id); Result Has(sf::Out<bool> out, ContentId content_id); Result GetPath(sf::Out<Path> out, ContentId content_id); Result GetPlaceHolderPath(sf::Out<Path> out, PlaceHolderId placeholder_id); Result CleanupAllPlaceHolder(); Result ListPlaceHolder(sf::Out<s32> out_count, const sf::OutArray<PlaceHolderId> &out_buf); Result GetContentCount(sf::Out<s32> out_count); Result ListContentId(sf::Out<s32> out_count, const sf::OutArray<ContentId> &out_buf, s32 start_offset); Result GetSizeFromContentId(sf::Out<s64> out_size, ContentId content_id); Result DisableForcibly(); Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id); Result SetPlaceHolderSize(PlaceHolderId placeholder_id, s64 size); Result ReadContentIdFile(const sf::OutBuffer &buf, ContentId content_id, s64 offset); Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, PlaceHolderId placeholder_id); Result GetRightsIdFromPlaceHolderIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id); Result GetRightsIdFromPlaceHolderId(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, fs::ContentAttributes attr); Result GetRightsIdFromContentIdDeprecated(sf::Out<ams::fs::RightsId> out_rights_id, ContentId content_id); Result GetRightsIdFromContentIdDeprecated2(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id); Result GetRightsIdFromContentId(sf::Out<ncm::RightsId> out_rights_id, ContentId content_id, fs::ContentAttributes attr); Result WriteContentForDebug(ContentId content_id, s64 offset, const sf::InBuffer &data); Result GetFreeSpaceSize(sf::Out<s64> out_size); Result GetTotalSpaceSize(sf::Out<s64> out_size); Result FlushPlaceHolder(); Result GetSizeFromPlaceHolderId(sf::Out<s64> out, PlaceHolderId placeholder_id); Result RepairInvalidFileAttribute(); Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr); Result RegisterPath(const ContentId &content_id, const Path &path); Result ClearRegisteredPath(); Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr); /* 16.0.0 Alignment change hacks. */ Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); } Result Register_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id) { R_RETURN(this->Register(placeholder_id, content_id)); } Result RevertToPlaceHolder_AtmosphereAlignmentFix(ncm::ContentId old_content_id, ncm::ContentId new_content_id, ncm::PlaceHolderId placeholder_id) { R_RETURN(this->RevertToPlaceHolder(placeholder_id, old_content_id, new_content_id)); } Result GetRightsIdFromPlaceHolderIdWithCacheDeprecated(sf::Out<ncm::RightsId> out_rights_id, ContentId cache_content_id, PlaceHolderId placeholder_id) { R_RETURN(this->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id, fs::ContentAttributes_None)); } }; static_assert(ncm::IsIContentStorage<IntegratedContentStorageImpl>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_integrated_list.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_shared_object.hpp> namespace ams::ncm { template<typename T, size_t N> class IntegratedList { static_assert(N <= std::numeric_limits<u8>::max()); public: struct ListData { sf::SharedPointer<T> interface; u8 id; }; private: size_t m_count; sf::SharedPointer<T> m_interfaces[N]; u8 m_ids[N]; public: IntegratedList() : m_count(0), m_interfaces(), m_ids() { /* ... */ } void Add(ListData &data) { /* Find place to insert into the list. */ const size_t pos = std::distance(std::begin(m_ids), std::lower_bound(std::begin(m_ids), std::end(m_ids), data.id)); /* If we need to, move stuff to make space. */ if (m_ids[pos] > data.id) { AMS_ABORT_UNLESS(m_count < N); for (size_t i = m_count; i > pos; --i) { m_ids[i] = std::move(m_ids[i - 1]); m_interfaces[i] = std::move(m_interfaces[i - 1]); } /* If we're inserting somewhere in the middle, increment count. */ m_count++; } else if (m_ids[pos] < data.id) { /* If we're inserting at the end, increment count. */ AMS_ABORT_UNLESS(m_count < N); m_count++; } /* Set at position. */ m_interfaces[pos] = data.interface; m_ids[pos] = data.id; } ListData Get(size_t idx) { AMS_ABORT_UNLESS(idx < m_count); return { m_interfaces[idx], m_ids[idx] }; } Result TryEach(auto callback) { Result result = ResultSuccess(); for (size_t i = 0; i < m_count; ++i) { result = callback(this->Get(i)); if (R_SUCCEEDED(result)) { break; } } R_RETURN(result); } Result ForAll(auto callback) { for (size_t i = 0; i < m_count; ++i) { R_TRY(callback(this->Get(i))); } R_SUCCEED(); } size_t GetCount() const { return m_count; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_make_path.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_content_id.hpp> #include <stratosphere/ncm/ncm_placeholder_id.hpp> #include <stratosphere/ncm/ncm_path_string.hpp> namespace ams::ncm { using MakeContentPathFunction = void (*)(PathString *out, ContentId content_id, const char *root_path); using MakePlaceHolderPathFunction = void (*)(PathString *out, PlaceHolderId placeholder_id,const char *root_path); void MakeFlatContentFilePath(PathString *out, ContentId content_id, const char *root_path); void MakeSha256HierarchicalContentFilePath_ForFat4KCluster(PathString *out, ContentId content_id, const char *root_path); void MakeSha256HierarchicalContentFilePath_ForFat16KCluster(PathString *out, ContentId content_id, const char *root_path); void MakeSha256HierarchicalContentFilePath_ForFat32KCluster(PathString *out, ContentId content_id, const char *root_path); size_t GetHierarchicalContentDirectoryDepth(MakeContentPathFunction func); void MakeFlatPlaceHolderFilePath(PathString *out, PlaceHolderId placeholder_id, const char *root_path); void MakeSha256HierarchicalPlaceHolderFilePath_ForFat16KCluster(PathString *out, PlaceHolderId placeholder_id, const char *root_pathroot); size_t GetHierarchicalPlaceHolderDirectoryDepth(MakePlaceHolderPathFunction func); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_mapped_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::ncm { struct MappedMemory { u64 id; size_t offset; u8 *buffer; size_t buffer_size; bool IsIncluded(size_t o, size_t sz) const { return this->offset <= o && sz <= this->buffer_size && (o + sz) <= (this->offset + this->buffer_size); } u8 *GetBuffer(size_t o, size_t sz) const { AMS_ASSERT(this->buffer != nullptr); AMS_ASSERT(this->IsIncluded(o, sz)); AMS_UNUSED(sz); return this->buffer + (o - this->offset); } }; static_assert(util::is_pod<MappedMemory>::value); class IMapper { public: virtual ~IMapper() { /* ... */ } public: virtual Result GetMappedMemory(MappedMemory *out, size_t offset, size_t size) = 0; virtual Result MarkUsing(u64 id) = 0; virtual Result UnmarkUsing(u64 id) = 0; virtual Result MarkDirty(u64 id) = 0; protected: virtual Result MapImpl(MappedMemory *out, Span<u8> data, size_t offset, size_t size) = 0; virtual Result UnmapImpl(MappedMemory *mem) = 0; virtual bool IsAccessibleSizeUpdatable() = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_max_count.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { constexpr inline s32 SystemMaxContentMetaCount = 0x800; constexpr inline s32 GameCardMaxContentMetaCount = 0x800; constexpr inline s32 HostMaxContentMetaCount = 0x800; constexpr inline s32 UserMaxContentMetaCount = 0x2000; constexpr inline s32 SdCardMaxContentMetaCount = 0x2000; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_memory_report.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/lmem/lmem_common.hpp> namespace ams::ncm { struct MemoryResourceState { size_t peak_total_alloc_size; size_t peak_alloc_size; size_t allocatable_size; size_t total_free_size; }; static_assert(sizeof(MemoryResourceState) == 0x20); struct MemoryReport { MemoryResourceState system_content_meta_resource_state; MemoryResourceState sd_and_user_content_meta_resource_state; MemoryResourceState gamecard_content_meta_resource_state; MemoryResourceState heap_resource_state; }; static_assert(sizeof(MemoryReport) == 0x80); class HeapState { private: os::SdkMutex m_mutex; lmem::HeapHandle m_heap_handle; size_t m_total_alloc_size; size_t m_peak_total_alloc_size; size_t m_peak_alloc_size; public: constexpr HeapState() : m_mutex(), m_heap_handle(nullptr), m_total_alloc_size(0), m_peak_total_alloc_size(0), m_peak_alloc_size(0) { /* ... */ } void Initialize(lmem::HeapHandle heap_handle); void Allocate(size_t size); void Free(size_t size); void GetMemoryResourceState(MemoryResourceState *out); }; HeapState &GetHeapState(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_package_install_task_base.hpp> namespace ams::ncm { class PackageInstallTask : public PackageInstallTaskBase { private: MemoryInstallTaskData m_data{}; public: Result Initialize(const char *package_root, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket); protected: bool IsContentMetaContentName(const char *name); virtual Result PrepareInstallContentMetaData() override; private: virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out_info, const ContentMetaKey &key) override; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_package_install_task_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/kvdb/kvdb_bounded_string.hpp> #include <stratosphere/ncm/ncm_install_task_base.hpp> namespace ams::ncm { class PackageInstallTaskBase : public InstallTaskBase { private: using PackagePath = kvdb::BoundedString<256>; private: PackagePath m_package_root; void *m_buffer{}; size_t m_buffer_size{}; public: PackageInstallTaskBase() : m_package_root() { /* ... */ } Result Initialize(const char *package_root_path, void *buffer, size_t buffer_size, StorageId storage_id, InstallTaskDataBase *data, u32 config); protected: const char *GetPackageRootPath() { return m_package_root.Get(); } private: virtual Result OnWritePlaceHolder(const ContentMetaKey &key, InstallContentInfo *content_info) override; virtual Result InstallTicket(const fs::RightsId &rights_id, ContentMetaType meta_type) override; void CreateContentMetaPath(PackagePath *out_path, ContentId content_id); void CreateContentPath(PackagePath *out_path, ContentId content_id); void CreateTicketPath(PackagePath *out_path, fs::RightsId id); void CreateCertificatePath(PackagePath *out_path, fs::RightsId id); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_package_system_downgrade_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_package_system_update_task.hpp> namespace ams::ncm { class PackageSystemDowngradeTask : public PackageSystemUpdateTask { public: Result Commit(); protected: virtual Result PrepareContentMetaIfLatest(const ContentMetaKey &key) override; private: Result PreCommit(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_package_system_update_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_package_install_task_base.hpp> namespace ams::ncm { class PackageSystemUpdateTask : public PackageInstallTaskBase { private: using PackagePath = kvdb::BoundedString<0x100>; private: PackagePath m_context_path{}; FileInstallTaskData m_data{}; ContentMetaDatabase m_package_db{}; bool m_gamecard_content_meta_database_active{}; public: ~PackageSystemUpdateTask(); void Inactivate(); Result Initialize(const char *package_root, const char *context_path, void *buffer, size_t buffer_size, bool requires_exfat_driver, FirmwareVariationId firmware_variation_id); util::optional<ContentMetaKey> GetSystemUpdateMetaKey(); protected: virtual Result PrepareInstallContentMetaData() override; virtual Result GetInstallContentMetaInfo(InstallContentMetaInfo *out, const ContentMetaKey &key) override; InstallTaskDataBase &GetInstallData() { return m_data; } /* Atmosphere extension. */ private: virtual Result PrepareDependency() override; Result GetContentInfoOfContentMeta(ContentInfo *out, const ContentMetaKey &key); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::ncm { struct alignas(4) Path : ams::sf::LargeData { char str[fs::EntryNameLengthMax]; static constexpr Path Encode(const char *p) { Path path = {}; /* Copy C string to path, terminating when a null byte is found. */ for (size_t i = 0; i < sizeof(path) - 1; i++) { path.str[i] = p[i]; if (p[i] == '\x00') { break; } } return path; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_path_string.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/kvdb/kvdb_bounded_string.hpp> namespace ams::ncm { using PathString = kvdb::BoundedString<fs::EntryNameLengthMax>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_placeholder_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct PlaceHolderId { util::Uuid uuid; bool operator==(const PlaceHolderId &other) const { return this->uuid == other.uuid; } bool operator!=(const PlaceHolderId &other) const { return this->uuid != other.uuid; } bool operator==(const util::Uuid &other) const { return this->uuid == other; } bool operator!=(const util::Uuid &other) const { return this->uuid != other; } }; static_assert(alignof(PlaceHolderId) == 1); constexpr inline PlaceHolderId InvalidPlaceHolderId = { util::InvalidUuid }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_program_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { struct ProgramId { u64 value; #if defined(ATMOSPHERE_OS_HORIZON) inline explicit operator svc::ProgramId() const { static_assert(sizeof(value) == sizeof(svc::ProgramId)); return { this->value }; } #endif constexpr inline auto operator<=>(const ProgramId &) const = default; }; inline constexpr const ProgramId InvalidProgramId = {}; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_program_location.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_program_id.hpp> #include <stratosphere/ncm/ncm_storage_id.hpp> namespace ams::ncm { struct ProgramLocation { ProgramId program_id; u8 storage_id; static constexpr ProgramLocation Make(ProgramId program_id, StorageId storage_id) { return { .program_id = program_id, .storage_id = static_cast<u8>(storage_id), }; } }; static_assert(sizeof(ProgramLocation) == 0x10 && util::is_pod<ProgramLocation>::value); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(ProgramLocation) == sizeof(::NcmProgramLocation) && alignof(ProgramLocation) == alignof(::NcmProgramLocation), "ProgramLocation Libnx Compatibility"); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_registered_host_content.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_content_id.hpp> #include <stratosphere/ncm/ncm_path.hpp> namespace ams::ncm { class RegisteredHostContent { NON_COPYABLE(RegisteredHostContent); NON_MOVEABLE(RegisteredHostContent); private: class RegisteredPath; private: using RegisteredPathList = ams::util::IntrusiveListBaseTraits<RegisteredPath>::ListType; private: os::SdkMutex m_mutex; RegisteredPathList m_path_list; public: RegisteredHostContent() : m_mutex(), m_path_list() { /* ... */ } ~RegisteredHostContent(); Result RegisterPath(const ncm::ContentId &content_id, const ncm::Path &path); Result GetPath(Path *out, const ncm::ContentId &content_id); void ClearPaths(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_rights_id.hpp> namespace ams::ncm { struct RightsId { fs::RightsId id; u8 key_generation; u8 reserved[7]; }; static_assert(sizeof(RightsId) == 0x18); static_assert(util::is_pod<RightsId>::value); inline bool operator==(const RightsId &lhs, const RightsId &rhs) { return std::tie(lhs.id, lhs.key_generation) == std::tie(rhs.id, rhs.key_generation); } inline bool operator!=(const RightsId &lhs, const RightsId &rhs) { return !(lhs == rhs); } inline bool operator<(const RightsId &lhs, const RightsId &rhs) { return std::tie(lhs.id, lhs.key_generation) < std::tie(rhs.id, rhs.key_generation); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_rights_id_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_rights_id.hpp> #include <stratosphere/ncm/ncm_content_id.hpp> namespace ams::ncm { class RightsIdCache { NON_COPYABLE(RightsIdCache); NON_MOVEABLE(RightsIdCache); private: static constexpr size_t MaxEntries = 0x80; private: struct Entry { public: util::Uuid uuid; ncm::RightsId rights_id; u64 last_accessed; }; private: Entry m_entries[MaxEntries]; u64 m_counter; os::SdkMutex m_mutex; public: RightsIdCache() : m_entries(), m_counter(2), m_mutex() { this->Invalidate(); } void Invalidate() { m_counter = 2; for (size_t i = 0; i < MaxEntries; i++) { m_entries[i].last_accessed = 1; } } void Store(ContentId content_id, ncm::RightsId rights_id) { std::scoped_lock lk(m_mutex); Entry *eviction_candidate = std::addressof(m_entries[0]); /* Find a suitable existing entry to store our new one at. */ for (size_t i = 1; i < MaxEntries; i++) { Entry *entry = std::addressof(m_entries[i]); /* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */ if (content_id == entry->uuid || (content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) { eviction_candidate = entry; } } /* Update the cache. */ eviction_candidate->uuid = content_id.uuid; eviction_candidate->rights_id = rights_id; eviction_candidate->last_accessed = m_counter++; } bool Find(ncm::RightsId *out_rights_id, ContentId content_id) { std::scoped_lock lk(m_mutex); /* Attempt to locate the content id in the cache. */ for (size_t i = 0; i < MaxEntries; i++) { Entry *entry = std::addressof(m_entries[i]); if (entry->last_accessed != 1 && content_id == entry->uuid) { entry->last_accessed = m_counter; m_counter++; *out_rights_id = entry->rights_id; return true; } } return false; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_storage_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { enum class StorageId : u8 { None = 0, Host = 1, GameCard = 2, BuiltInSystem = 3, BuiltInUser = 4, SdCard = 5, Any = 6, /* Aliases. */ Card = GameCard, BuildInSystem = BuiltInSystem, BuildInUser = BuiltInUser, }; constexpr inline bool IsUniqueStorage(StorageId id) { return id != StorageId::None && id != StorageId::Any; } constexpr inline bool IsInstallableStorage(StorageId id) { return id == StorageId::BuiltInSystem || id == StorageId::BuiltInUser || id == StorageId::SdCard || id == StorageId::Any; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_storage_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_storage_id.hpp> #include <stratosphere/ncm/ncm_content_meta_id.hpp> namespace ams::ncm { class StorageList { public: static constexpr s32 MaxCount = 10; private: StorageId m_ids[MaxCount]; s32 m_count; public: constexpr StorageList() : m_ids(), m_count() { /* ... */ } void Push(StorageId storage_id) { AMS_ABORT_UNLESS(m_count < MaxCount); for (s32 i = 0; i < MaxCount; i++) { if (m_ids[i] == storage_id) { return; } } m_ids[m_count++] = storage_id; } s32 Count() const { return m_count; } StorageId operator[](s32 i) const { AMS_ABORT_UNLESS(i < m_count); return m_ids[i]; } }; constexpr StorageList GetStorageList(StorageId storage_id) { StorageList list; switch (storage_id) { case StorageId::BuiltInSystem: case StorageId::BuiltInUser: case StorageId::SdCard: list.Push(storage_id); break; case StorageId::Any: list.Push(StorageId::SdCard); list.Push(StorageId::BuiltInUser); break; AMS_UNREACHABLE_DEFAULT_CASE(); } return list; } Result SelectDownloadableStorage(StorageId *out_storage_id, StorageId storage_id, s64 required_size); Result SelectPatchStorage(StorageId *out_storage_id, StorageId storage_id, PatchId patch_id); const char *GetStorageIdString(StorageId storage_id); const char *GetStorageIdStringForPlayReport(StorageId storage_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_submission_package_install_task.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/fs/common/fs_file_storage.hpp> #include <stratosphere/ncm/ncm_package_install_task.hpp> namespace ams::ncm { class SubmissionPackageInstallTask : public PackageInstallTask { private: class Impl; private: std::unique_ptr<Impl> m_impl; public: SubmissionPackageInstallTask(); virtual ~SubmissionPackageInstallTask() override; Result Initialize(fs::FileHandle handle, StorageId storage_id, void *buffer, size_t buffer_size, bool ignore_ticket = false); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_system_content_meta_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_data_id.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> namespace ams::ncm { struct SystemProgramId { u64 value; constexpr operator ProgramId() const { return { this->value }; } static const SystemProgramId Start; static const SystemProgramId Fs; static const SystemProgramId Loader; static const SystemProgramId Ncm; static const SystemProgramId Pm; static const SystemProgramId Sm; static const SystemProgramId Boot; static const SystemProgramId Usb; static const SystemProgramId Tma; static const SystemProgramId Boot2; static const SystemProgramId Settings; static const SystemProgramId Bus; static const SystemProgramId Bluetooth; static const SystemProgramId Bcat; static const SystemProgramId Dmnt; static const SystemProgramId Friends; static const SystemProgramId Nifm; static const SystemProgramId Ptm; static const SystemProgramId Shell; static const SystemProgramId BsdSockets; static const SystemProgramId Hid; static const SystemProgramId Audio; static const SystemProgramId LogManager; static const SystemProgramId Wlan; static const SystemProgramId Cs; static const SystemProgramId Ldn; static const SystemProgramId NvServices; static const SystemProgramId Pcv; static const SystemProgramId Ppc; static const SystemProgramId NvnFlinger; static const SystemProgramId Pcie; static const SystemProgramId Account; static const SystemProgramId Ns; static const SystemProgramId Nfc; static const SystemProgramId Psc; static const SystemProgramId CapSrv; static const SystemProgramId Am; static const SystemProgramId Ssl; static const SystemProgramId Nim; static const SystemProgramId Cec; static const SystemProgramId Tspm; static const SystemProgramId Spl; static const SystemProgramId Lbl; static const SystemProgramId Btm; static const SystemProgramId Erpt; static const SystemProgramId Time; static const SystemProgramId Vi; static const SystemProgramId Pctl; static const SystemProgramId Npns; static const SystemProgramId Eupld; static const SystemProgramId Arp; static const SystemProgramId Glue; static const SystemProgramId Eclct; static const SystemProgramId Es; static const SystemProgramId Fatal; static const SystemProgramId Grc; static const SystemProgramId Creport; static const SystemProgramId Ro; static const SystemProgramId Profiler; static const SystemProgramId Sdb; static const SystemProgramId Migration; static const SystemProgramId Jit; static const SystemProgramId JpegDec; static const SystemProgramId SafeMode; static const SystemProgramId Olsc; static const SystemProgramId Dt; static const SystemProgramId Nd; static const SystemProgramId Ngct; static const SystemProgramId Pgl; static const SystemProgramId Omm; static const SystemProgramId Eth; static const SystemProgramId Ngc; static const SystemProgramId End; static const SystemProgramId BrowserCoreDll; static const SystemProgramId Manu; static const SystemProgramId Htc; static const SystemProgramId DmntGen2; static const SystemProgramId DevServer; }; struct AtmosphereProgramId { u64 value; constexpr operator SystemProgramId() const { return { this->value }; } constexpr operator ProgramId() const { return static_cast<SystemProgramId>(*this); } static const AtmosphereProgramId Mitm; static const AtmosphereProgramId AtmosphereLogManager; static const AtmosphereProgramId AtmosphereMemlet; }; inline constexpr const AtmosphereProgramId AtmosphereProgramId::Mitm = { 0x010041544D530000ul }; inline constexpr const AtmosphereProgramId AtmosphereProgramId::AtmosphereLogManager = { 0x0100000000000420ul }; inline constexpr const AtmosphereProgramId AtmosphereProgramId::AtmosphereMemlet = { 0x0100000000000421ul }; inline constexpr bool IsAtmosphereProgramId(const ProgramId &program_id) { return program_id == AtmosphereProgramId::Mitm || program_id == AtmosphereProgramId::AtmosphereLogManager || program_id == AtmosphereProgramId::AtmosphereMemlet; } inline constexpr bool IsSystemProgramId(const AtmosphereProgramId &) { return true; } inline constexpr const SystemProgramId SystemProgramId::Start = { 0x0100000000000000ul }; inline constexpr const SystemProgramId SystemProgramId::Fs = { 0x0100000000000000ul }; inline constexpr const SystemProgramId SystemProgramId::Loader = { 0x0100000000000001ul }; inline constexpr const SystemProgramId SystemProgramId::Ncm = { 0x0100000000000002ul }; inline constexpr const SystemProgramId SystemProgramId::Pm = { 0x0100000000000003ul }; inline constexpr const SystemProgramId SystemProgramId::Sm = { 0x0100000000000004ul }; inline constexpr const SystemProgramId SystemProgramId::Boot = { 0x0100000000000005ul }; inline constexpr const SystemProgramId SystemProgramId::Usb = { 0x0100000000000006ul }; inline constexpr const SystemProgramId SystemProgramId::Tma = { 0x0100000000000007ul }; inline constexpr const SystemProgramId SystemProgramId::Boot2 = { 0x0100000000000008ul }; inline constexpr const SystemProgramId SystemProgramId::Settings = { 0x0100000000000009ul }; inline constexpr const SystemProgramId SystemProgramId::Bus = { 0x010000000000000Aul }; inline constexpr const SystemProgramId SystemProgramId::Bluetooth = { 0x010000000000000Bul }; inline constexpr const SystemProgramId SystemProgramId::Bcat = { 0x010000000000000Cul }; inline constexpr const SystemProgramId SystemProgramId::Dmnt = { 0x010000000000000Dul }; inline constexpr const SystemProgramId SystemProgramId::Friends = { 0x010000000000000Eul }; inline constexpr const SystemProgramId SystemProgramId::Nifm = { 0x010000000000000Ful }; inline constexpr const SystemProgramId SystemProgramId::Ptm = { 0x0100000000000010ul }; inline constexpr const SystemProgramId SystemProgramId::Shell = { 0x0100000000000011ul }; inline constexpr const SystemProgramId SystemProgramId::BsdSockets = { 0x0100000000000012ul }; inline constexpr const SystemProgramId SystemProgramId::Hid = { 0x0100000000000013ul }; inline constexpr const SystemProgramId SystemProgramId::Audio = { 0x0100000000000014ul }; inline constexpr const SystemProgramId SystemProgramId::LogManager = { 0x0100000000000015ul }; inline constexpr const SystemProgramId SystemProgramId::Wlan = { 0x0100000000000016ul }; inline constexpr const SystemProgramId SystemProgramId::Cs = { 0x0100000000000017ul }; inline constexpr const SystemProgramId SystemProgramId::Ldn = { 0x0100000000000018ul }; inline constexpr const SystemProgramId SystemProgramId::NvServices = { 0x0100000000000019ul }; inline constexpr const SystemProgramId SystemProgramId::Pcv = { 0x010000000000001Aul }; inline constexpr const SystemProgramId SystemProgramId::Ppc = { 0x010000000000001Bul }; inline constexpr const SystemProgramId SystemProgramId::NvnFlinger = { 0x010000000000001Cul }; inline constexpr const SystemProgramId SystemProgramId::Pcie = { 0x010000000000001Dul }; inline constexpr const SystemProgramId SystemProgramId::Account = { 0x010000000000001Eul }; inline constexpr const SystemProgramId SystemProgramId::Ns = { 0x010000000000001Ful }; inline constexpr const SystemProgramId SystemProgramId::Nfc = { 0x0100000000000020ul }; inline constexpr const SystemProgramId SystemProgramId::Psc = { 0x0100000000000021ul }; inline constexpr const SystemProgramId SystemProgramId::CapSrv = { 0x0100000000000022ul }; inline constexpr const SystemProgramId SystemProgramId::Am = { 0x0100000000000023ul }; inline constexpr const SystemProgramId SystemProgramId::Ssl = { 0x0100000000000024ul }; inline constexpr const SystemProgramId SystemProgramId::Nim = { 0x0100000000000025ul }; inline constexpr const SystemProgramId SystemProgramId::Cec = { 0x0100000000000026ul }; inline constexpr const SystemProgramId SystemProgramId::Tspm = { 0x0100000000000027ul }; inline constexpr const SystemProgramId SystemProgramId::Spl = { 0x0100000000000028ul }; inline constexpr const SystemProgramId SystemProgramId::Lbl = { 0x0100000000000029ul }; inline constexpr const SystemProgramId SystemProgramId::Btm = { 0x010000000000002Aul }; inline constexpr const SystemProgramId SystemProgramId::Erpt = { 0x010000000000002Bul }; inline constexpr const SystemProgramId SystemProgramId::Time = { 0x010000000000002Cul }; inline constexpr const SystemProgramId SystemProgramId::Vi = { 0x010000000000002Dul }; inline constexpr const SystemProgramId SystemProgramId::Pctl = { 0x010000000000002Eul }; inline constexpr const SystemProgramId SystemProgramId::Npns = { 0x010000000000002Ful }; inline constexpr const SystemProgramId SystemProgramId::Eupld = { 0x0100000000000030ul }; inline constexpr const SystemProgramId SystemProgramId::Arp = { 0x0100000000000031ul }; inline constexpr const SystemProgramId SystemProgramId::Glue = { 0x0100000000000031ul }; inline constexpr const SystemProgramId SystemProgramId::Eclct = { 0x0100000000000032ul }; inline constexpr const SystemProgramId SystemProgramId::Es = { 0x0100000000000033ul }; inline constexpr const SystemProgramId SystemProgramId::Fatal = { 0x0100000000000034ul }; inline constexpr const SystemProgramId SystemProgramId::Grc = { 0x0100000000000035ul }; inline constexpr const SystemProgramId SystemProgramId::Creport = { 0x0100000000000036ul }; inline constexpr const SystemProgramId SystemProgramId::Ro = { 0x0100000000000037ul }; inline constexpr const SystemProgramId SystemProgramId::Profiler = { 0x0100000000000038ul }; inline constexpr const SystemProgramId SystemProgramId::Sdb = { 0x0100000000000039ul }; inline constexpr const SystemProgramId SystemProgramId::Migration = { 0x010000000000003Aul }; inline constexpr const SystemProgramId SystemProgramId::Jit = { 0x010000000000003Bul }; inline constexpr const SystemProgramId SystemProgramId::JpegDec = { 0x010000000000003Cul }; inline constexpr const SystemProgramId SystemProgramId::SafeMode = { 0x010000000000003Dul }; inline constexpr const SystemProgramId SystemProgramId::Olsc = { 0x010000000000003Eul }; inline constexpr const SystemProgramId SystemProgramId::Dt = { 0x010000000000003Ful }; inline constexpr const SystemProgramId SystemProgramId::Nd = { 0x0100000000000040ul }; inline constexpr const SystemProgramId SystemProgramId::Ngct = { 0x0100000000000041ul }; inline constexpr const SystemProgramId SystemProgramId::Pgl = { 0x0100000000000042ul }; inline constexpr const SystemProgramId SystemProgramId::Omm = { 0x0100000000000045ul }; inline constexpr const SystemProgramId SystemProgramId::Eth = { 0x0100000000000046ul }; inline constexpr const SystemProgramId SystemProgramId::Ngc = { 0x0100000000000050ul }; inline constexpr const SystemProgramId SystemProgramId::End = { 0x01000000000007FFul }; inline constexpr const SystemProgramId SystemProgramId::BrowserCoreDll = { 0x010000000000085Dul }; inline constexpr const SystemProgramId SystemProgramId::Manu = { 0x010000000000B14Aul }; inline constexpr const SystemProgramId SystemProgramId::Htc = { 0x010000000000B240ul }; inline constexpr const SystemProgramId SystemProgramId::DmntGen2 = { 0x010000000000D609ul }; inline constexpr const SystemProgramId SystemProgramId::DevServer = { 0x010000000000D623ul }; inline constexpr bool IsSystemProgramId(const ProgramId &program_id) { return (SystemProgramId::Start <= program_id && program_id <= SystemProgramId::End) || IsAtmosphereProgramId(program_id); } inline constexpr bool IsSystemProgramId(const SystemProgramId &) { return true; } struct SystemDataId { u64 value; constexpr operator DataId() const { return { this->value }; } constexpr inline bool operator==(const SystemDataId &) const = default; constexpr inline bool operator!=(const SystemDataId &) const = default; static const SystemDataId Start; static const SystemDataId CertStore; static const SystemDataId ErrorMessage; static const SystemDataId MiiModel; static const SystemDataId BrowserDll; static const SystemDataId Help; static const SystemDataId SharedFont; static const SystemDataId NgWord; static const SystemDataId SsidList; static const SystemDataId Dictionary; static const SystemDataId SystemVersion; static const SystemDataId AvatarImage; static const SystemDataId LocalNews; static const SystemDataId Eula; static const SystemDataId UrlBlackList; static const SystemDataId TimeZoneBinar; static const SystemDataId CertStoreCruiser; static const SystemDataId FontNintendoExtension; static const SystemDataId FontStandard; static const SystemDataId FontKorean; static const SystemDataId FontChineseTraditional; static const SystemDataId FontChineseSimple; static const SystemDataId FontBfcpx; static const SystemDataId SystemUpdate; static const SystemDataId FirmwareDebugSettings; static const SystemDataId BootImagePackage; static const SystemDataId BootImagePackageSafe; static const SystemDataId BootImagePackageExFat; static const SystemDataId BootImagePackageExFatSafe; static const SystemDataId FatalMessage; static const SystemDataId ControllerIcon; static const SystemDataId PlatformConfigIcosa; static const SystemDataId PlatformConfigCopper; static const SystemDataId PlatformConfigHoag; static const SystemDataId ControllerFirmware; static const SystemDataId NgWord2; static const SystemDataId PlatformConfigIcosaMariko; static const SystemDataId ApplicationBlackList; static const SystemDataId RebootlessSystemUpdateVersion; static const SystemDataId ContentActionTable; static const SystemDataId PlatformConfigCalcio; static const SystemDataId PlatformConfigAula; static const SystemDataId End; }; inline constexpr const SystemDataId SystemDataId::Start = { 0x0100000000000800ul }; inline constexpr const SystemDataId SystemDataId::CertStore = { 0x0100000000000800ul }; inline constexpr const SystemDataId SystemDataId::ErrorMessage = { 0x0100000000000801ul }; inline constexpr const SystemDataId SystemDataId::MiiModel = { 0x0100000000000802ul }; inline constexpr const SystemDataId SystemDataId::BrowserDll = { 0x0100000000000803ul }; inline constexpr const SystemDataId SystemDataId::Help = { 0x0100000000000804ul }; inline constexpr const SystemDataId SystemDataId::SharedFont = { 0x0100000000000805ul }; inline constexpr const SystemDataId SystemDataId::NgWord = { 0x0100000000000806ul }; inline constexpr const SystemDataId SystemDataId::SsidList = { 0x0100000000000807ul }; inline constexpr const SystemDataId SystemDataId::Dictionary = { 0x0100000000000808ul }; inline constexpr const SystemDataId SystemDataId::SystemVersion = { 0x0100000000000809ul }; inline constexpr const SystemDataId SystemDataId::AvatarImage = { 0x010000000000080Aul }; inline constexpr const SystemDataId SystemDataId::LocalNews = { 0x010000000000080Bul }; inline constexpr const SystemDataId SystemDataId::Eula = { 0x010000000000080Cul }; inline constexpr const SystemDataId SystemDataId::UrlBlackList = { 0x010000000000080Dul }; inline constexpr const SystemDataId SystemDataId::TimeZoneBinar = { 0x010000000000080Eul }; inline constexpr const SystemDataId SystemDataId::CertStoreCruiser = { 0x010000000000080Ful }; inline constexpr const SystemDataId SystemDataId::FontNintendoExtension = { 0x0100000000000810ul }; inline constexpr const SystemDataId SystemDataId::FontStandard = { 0x0100000000000811ul }; inline constexpr const SystemDataId SystemDataId::FontKorean = { 0x0100000000000812ul }; inline constexpr const SystemDataId SystemDataId::FontChineseTraditional = { 0x0100000000000813ul }; inline constexpr const SystemDataId SystemDataId::FontChineseSimple = { 0x0100000000000814ul }; inline constexpr const SystemDataId SystemDataId::FontBfcpx = { 0x0100000000000815ul }; inline constexpr const SystemDataId SystemDataId::SystemUpdate = { 0x0100000000000816ul }; inline constexpr const SystemDataId SystemDataId::FirmwareDebugSettings = { 0x0100000000000818ul }; inline constexpr const SystemDataId SystemDataId::BootImagePackage = { 0x0100000000000819ul }; inline constexpr const SystemDataId SystemDataId::BootImagePackageSafe = { 0x010000000000081Aul }; inline constexpr const SystemDataId SystemDataId::BootImagePackageExFat = { 0x010000000000081Bul }; inline constexpr const SystemDataId SystemDataId::BootImagePackageExFatSafe = { 0x010000000000081Cul }; inline constexpr const SystemDataId SystemDataId::FatalMessage = { 0x010000000000081Dul }; inline constexpr const SystemDataId SystemDataId::ControllerIcon = { 0x010000000000081Eul }; inline constexpr const SystemDataId SystemDataId::PlatformConfigIcosa = { 0x010000000000081Ful }; inline constexpr const SystemDataId SystemDataId::PlatformConfigCopper = { 0x0100000000000820ul }; inline constexpr const SystemDataId SystemDataId::PlatformConfigHoag = { 0x0100000000000821ul }; inline constexpr const SystemDataId SystemDataId::ControllerFirmware = { 0x0100000000000822ul }; inline constexpr const SystemDataId SystemDataId::NgWord2 = { 0x0100000000000823ul }; inline constexpr const SystemDataId SystemDataId::PlatformConfigIcosaMariko = { 0x0100000000000824ul }; inline constexpr const SystemDataId SystemDataId::ApplicationBlackList = { 0x0100000000000825ul }; inline constexpr const SystemDataId SystemDataId::RebootlessSystemUpdateVersion = { 0x0100000000000826ul }; inline constexpr const SystemDataId SystemDataId::ContentActionTable = { 0x0100000000000827ul }; inline constexpr const SystemDataId SystemDataId::PlatformConfigCalcio = { 0x0100000000000829ul }; inline constexpr const SystemDataId SystemDataId::PlatformConfigAula = { 0x0100000000000831ul }; inline constexpr const SystemDataId SystemDataId::End = { 0x0100000000000FFFul }; inline constexpr bool IsSystemDataId(const DataId &data_id) { return SystemDataId::Start <= data_id && data_id <= SystemDataId::End; } inline constexpr bool IsSystemDataId(const SystemDataId &) { return true; } struct SystemUpdateId { u64 value; constexpr operator DataId() const { return { this->value }; } constexpr inline bool operator==(const SystemUpdateId &) const = default; constexpr inline bool operator!=(const SystemUpdateId &) const = default; }; struct SystemAppletId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const SystemAppletId &) const = default; constexpr inline bool operator!=(const SystemAppletId &) const = default; static const SystemAppletId Start; static const SystemAppletId Qlaunch; static const SystemAppletId Auth; static const SystemAppletId Cabinet; static const SystemAppletId Controller; static const SystemAppletId DataErase; static const SystemAppletId Error; static const SystemAppletId NetConnect; static const SystemAppletId PlayerSelect; static const SystemAppletId Swkbd; static const SystemAppletId MiiEdit; static const SystemAppletId Web; static const SystemAppletId Shop; static const SystemAppletId OverlayDisp; static const SystemAppletId PhotoViewer; static const SystemAppletId Set; static const SystemAppletId OfflineWeb; static const SystemAppletId LoginShare; static const SystemAppletId WifiWebAuth; static const SystemAppletId Starter; static const SystemAppletId MyPage; static const SystemAppletId PlayReport; static const SystemAppletId MaintenanceMenu; static const SystemAppletId Gift; static const SystemAppletId DummyShop; static const SystemAppletId UserMigration; static const SystemAppletId Encounter; static const SystemAppletId Story; static const SystemAppletId End; }; inline constexpr const SystemAppletId SystemAppletId::Start = { 0x0100000000001000ul }; inline constexpr const SystemAppletId SystemAppletId::Qlaunch = { 0x0100000000001000ul }; inline constexpr const SystemAppletId SystemAppletId::Auth = { 0x0100000000001001ul }; inline constexpr const SystemAppletId SystemAppletId::Cabinet = { 0x0100000000001002ul }; inline constexpr const SystemAppletId SystemAppletId::Controller = { 0x0100000000001003ul }; inline constexpr const SystemAppletId SystemAppletId::DataErase = { 0x0100000000001004ul }; inline constexpr const SystemAppletId SystemAppletId::Error = { 0x0100000000001005ul }; inline constexpr const SystemAppletId SystemAppletId::NetConnect = { 0x0100000000001006ul }; inline constexpr const SystemAppletId SystemAppletId::PlayerSelect = { 0x0100000000001007ul }; inline constexpr const SystemAppletId SystemAppletId::Swkbd = { 0x0100000000001008ul }; inline constexpr const SystemAppletId SystemAppletId::MiiEdit = { 0x0100000000001009ul }; inline constexpr const SystemAppletId SystemAppletId::Web = { 0x010000000000100Aul }; inline constexpr const SystemAppletId SystemAppletId::Shop = { 0x010000000000100Bul }; inline constexpr const SystemAppletId SystemAppletId::OverlayDisp = { 0x010000000000100Cul }; inline constexpr const SystemAppletId SystemAppletId::PhotoViewer = { 0x010000000000100Dul }; inline constexpr const SystemAppletId SystemAppletId::Set = { 0x010000000000100Eul }; inline constexpr const SystemAppletId SystemAppletId::OfflineWeb = { 0x010000000000100Ful }; inline constexpr const SystemAppletId SystemAppletId::LoginShare = { 0x0100000000001010ul }; inline constexpr const SystemAppletId SystemAppletId::WifiWebAuth = { 0x0100000000001011ul }; inline constexpr const SystemAppletId SystemAppletId::Starter = { 0x0100000000001012ul }; inline constexpr const SystemAppletId SystemAppletId::MyPage = { 0x0100000000001013ul }; inline constexpr const SystemAppletId SystemAppletId::PlayReport = { 0x0100000000001014ul }; inline constexpr const SystemAppletId SystemAppletId::MaintenanceMenu = { 0x0100000000001015ul }; inline constexpr const SystemAppletId SystemAppletId::Gift = { 0x010000000000101Aul }; inline constexpr const SystemAppletId SystemAppletId::DummyShop = { 0x010000000000101Bul }; inline constexpr const SystemAppletId SystemAppletId::UserMigration = { 0x010000000000101Cul }; inline constexpr const SystemAppletId SystemAppletId::Encounter = { 0x010000000000101Dul }; inline constexpr const SystemAppletId SystemAppletId::Story = { 0x0100000000001020ul }; inline constexpr const SystemAppletId SystemAppletId::End = { 0x0100000000001FFFul }; inline constexpr bool IsSystemAppletId(const ProgramId &program_id) { return SystemAppletId::Start <= program_id && program_id <= SystemAppletId::End; } inline constexpr bool IsSystemAppletId(const SystemAppletId &) { return true; } struct SystemDebugAppletId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const SystemDebugAppletId &) const = default; constexpr inline bool operator!=(const SystemDebugAppletId &) const = default; static const SystemDebugAppletId Start; static const SystemDebugAppletId SnapShotDumper; static const SystemDebugAppletId End; }; inline constexpr const SystemDebugAppletId SystemDebugAppletId::Start = { 0x0100000000002000ul }; inline constexpr const SystemDebugAppletId SystemDebugAppletId::SnapShotDumper = { 0x0100000000002071ul }; inline constexpr const SystemDebugAppletId SystemDebugAppletId::End = { 0x0100000000002FFFul }; inline constexpr bool IsSystemDebugAppletId(const ProgramId &program_id) { return SystemDebugAppletId::Start <= program_id && program_id <= SystemDebugAppletId::End; } inline constexpr bool IsSystemDebugAppletId(const SystemDebugAppletId &) { return true; } struct LibraryAppletId { u64 value; constexpr operator SystemAppletId() const { return { this->value }; } constexpr operator ProgramId() const { return static_cast<SystemAppletId>(*this); } constexpr inline bool operator==(const LibraryAppletId &) const = default; constexpr inline bool operator!=(const LibraryAppletId &) const = default; static const LibraryAppletId Auth; static const LibraryAppletId Controller; static const LibraryAppletId Error; static const LibraryAppletId PlayerSelect; static const LibraryAppletId Swkbd; static const LibraryAppletId Web; static const LibraryAppletId Shop; static const LibraryAppletId PhotoViewer; static const LibraryAppletId OfflineWeb; static const LibraryAppletId LoginShare; static const LibraryAppletId WifiWebAuth; static const LibraryAppletId MyPage; }; inline constexpr const LibraryAppletId LibraryAppletId::Auth = { SystemAppletId::Auth.value }; inline constexpr const LibraryAppletId LibraryAppletId::Controller = { SystemAppletId::Controller.value }; inline constexpr const LibraryAppletId LibraryAppletId::Error = { SystemAppletId::Error.value }; inline constexpr const LibraryAppletId LibraryAppletId::PlayerSelect = { SystemAppletId::PlayerSelect.value }; inline constexpr const LibraryAppletId LibraryAppletId::Swkbd = { SystemAppletId::Swkbd.value }; inline constexpr const LibraryAppletId LibraryAppletId::Web = { SystemAppletId::Web.value }; inline constexpr const LibraryAppletId LibraryAppletId::Shop = { SystemAppletId::Shop.value }; inline constexpr const LibraryAppletId LibraryAppletId::PhotoViewer = { SystemAppletId::PhotoViewer.value }; inline constexpr const LibraryAppletId LibraryAppletId::OfflineWeb = { SystemAppletId::OfflineWeb.value }; inline constexpr const LibraryAppletId LibraryAppletId::LoginShare = { SystemAppletId::LoginShare.value }; inline constexpr const LibraryAppletId LibraryAppletId::WifiWebAuth = { SystemAppletId::WifiWebAuth.value }; inline constexpr const LibraryAppletId LibraryAppletId::MyPage = { SystemAppletId::MyPage.value }; inline constexpr bool IsLibraryAppletId(const ProgramId &id) { return id == LibraryAppletId::Auth || id == LibraryAppletId::Controller || id == LibraryAppletId::Error || id == LibraryAppletId::PlayerSelect || id == LibraryAppletId::Swkbd || id == LibraryAppletId::Web || id == LibraryAppletId::Shop || id == LibraryAppletId::PhotoViewer || id == LibraryAppletId::OfflineWeb || id == LibraryAppletId::LoginShare || id == LibraryAppletId::WifiWebAuth || id == LibraryAppletId::MyPage; } inline constexpr bool IsLibraryAppletId(const LibraryAppletId &) { return true; } struct WebAppletId { u64 value; constexpr operator LibraryAppletId() const { return { this->value }; } constexpr operator SystemAppletId() const { return static_cast<LibraryAppletId>(*this); } constexpr operator ProgramId() const { return static_cast<SystemAppletId>(*this); } constexpr inline bool operator==(const WebAppletId &) const = default; constexpr inline bool operator!=(const WebAppletId &) const = default; static const WebAppletId Web; static const WebAppletId Shop; static const WebAppletId OfflineWeb; static const WebAppletId LoginShare; static const WebAppletId WifiWebAuth; }; inline constexpr const WebAppletId WebAppletId::Web = { LibraryAppletId::Web.value }; inline constexpr const WebAppletId WebAppletId::Shop = { LibraryAppletId::Shop.value }; inline constexpr const WebAppletId WebAppletId::OfflineWeb = { LibraryAppletId::OfflineWeb.value }; inline constexpr const WebAppletId WebAppletId::LoginShare = { LibraryAppletId::LoginShare.value }; inline constexpr const WebAppletId WebAppletId::WifiWebAuth = { LibraryAppletId::WifiWebAuth.value }; inline constexpr bool IsWebAppletId(const ProgramId &id) { return id == WebAppletId::Web || id == WebAppletId::Shop || id == WebAppletId::OfflineWeb || id == WebAppletId::LoginShare || id == WebAppletId::WifiWebAuth; } inline constexpr bool IsWebAppletId(const WebAppletId &) { return true; } struct SystemApplicationId { u64 value; constexpr operator ProgramId() const { return { this->value }; } constexpr inline bool operator==(const SystemApplicationId &) const = default; constexpr inline bool operator!=(const SystemApplicationId &) const = default; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm/ncm_system_update_task_apply_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ncm { enum class SystemUpdateTaskApplyInfo : u8 { Unknown = 0, RequireReboot = 1, RequireNoReboot = 2, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ncm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/ncm/ncm_max_count.hpp> #include <stratosphere/ncm/ncm_program_location.hpp> #include <stratosphere/ncm/ncm_auto_buffer.hpp> #include <stratosphere/ncm/ncm_make_path.hpp> #include <stratosphere/ncm/ncm_content_id_utils.hpp> #include <stratosphere/ncm/ncm_content_info_utils.hpp> #include <stratosphere/ncm/ncm_content_meta.hpp> #include <stratosphere/ncm/ncm_content_meta_extended_data.hpp> #include <stratosphere/ncm/ncm_content_meta_database.hpp> #include <stratosphere/ncm/ncm_content_storage.hpp> #include <stratosphere/ncm/ncm_content_manager_impl.hpp> #include <stratosphere/ncm/ncm_content_meta_utils.hpp> #include <stratosphere/ncm/ncm_firmware_variation.hpp> #include <stratosphere/ncm/ncm_install_task_base.hpp> #include <stratosphere/ncm/ncm_install_task_data.hpp> #include <stratosphere/ncm/ncm_install_task_occupied_size.hpp> #include <stratosphere/ncm/ncm_memory_report.hpp> #include <stratosphere/ncm/ncm_package_install_task_base.hpp> #include <stratosphere/ncm/ncm_package_install_task.hpp> #include <stratosphere/ncm/ncm_package_system_downgrade_task.hpp> #include <stratosphere/ncm/ncm_package_system_update_task.hpp> #include <stratosphere/ncm/ncm_registered_host_content.hpp> #include <stratosphere/ncm/ncm_submission_package_install_task.hpp> #include <stratosphere/ncm/ncm_storage_utils.hpp> #include <stratosphere/ncm/ncm_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/nim/nim_network_install_manager_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/nim/nim_system_update_task_id.hpp> namespace ams::nim { /* Management. */ void InitializeForNetworkInstallManager(); void FinalizeForNetworkInstallManager(); /* Service API. */ Result DestroySystemUpdateTask(const SystemUpdateTaskId &id); s32 ListSystemUpdateTask(SystemUpdateTaskId *out_list, size_t out_list_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/nim/nim_system_update_task_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/nim/nim_task_id_common.hpp> namespace ams::nim { AMS_NIM_DEFINE_TASK_ID(SystemUpdateTaskId, 8); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/nim/nim_task_id_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/nim/nim_task_id_common.hpp> namespace ams::nim { #define AMS_NIM_DEFINE_TASK_ID(ID, ALIGN) \ struct alignas(ALIGN) ID { \ util::Uuid uuid; \ \ ALWAYS_INLINE bool IsValid() const { \ return this->uuid != util::InvalidUuid; \ } \ }; \ \ static_assert(alignof(ID) == ALIGN); \ \ ALWAYS_INLINE bool operator==(const ID &lhs, const ID &rhs) { \ return lhs.uuid == rhs.uuid; \ } \ \ ALWAYS_INLINE bool operator!=(const ID &lhs, const ID &rhs) { \ return lhs.uuid != rhs.uuid; \ } \ \ constexpr inline ID Invalid##ID = { util::InvalidUuid } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/nim.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/nim/nim_network_install_manager_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ns/impl/ns_i_async.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/err/err_error_context.hpp> #include <stratosphere/sf.hpp> #define AMS_NS_I_ASYNC_RESULT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Get, (), ()) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Cancel, (), ()) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetErrorContext, (::ams::sf::Out<::ams::err::ErrorContext> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::ns::impl, IAsyncResult, AMS_NS_I_ASYNC_RESULT_INTERFACE_INFO, 0x66E1ADBD) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ns.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ns/impl/ns_i_async.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/nsd/impl/device/nsd_device.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/nsd/nsd_types.hpp> namespace ams::nsd::impl::device { const EnvironmentIdentifier &GetEnvironmentIdentifierFromSettings(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/nsd/nsd_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::nsd { struct EnvironmentIdentifier { static constexpr size_t Size = 8; char value[Size]; constexpr friend bool operator==(const EnvironmentIdentifier &lhs, const EnvironmentIdentifier &rhs) { return util::Strncmp(lhs.value, rhs.value, Size) == 0; } constexpr friend bool operator!=(const EnvironmentIdentifier &lhs, const EnvironmentIdentifier &rhs) { return !(lhs == rhs); } }; constexpr inline const EnvironmentIdentifier EnvironmentIdentifierOfProductDevice = {"lp1"}; constexpr inline const EnvironmentIdentifier EnvironmentIdentifierOfNotProductDevice = {"dd1"}; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/nsd.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/nsd/nsd_types.hpp> #include <stratosphere/nsd/impl/device/nsd_device.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp> #else #error "Unknown OS for ams::os::impl::InternalBusyMutexImpl" #endif namespace ams::os::impl { class InternalBusyMutex { private: InternalBusyMutexImpl m_impl; public: constexpr InternalBusyMutex() : m_impl() { /* ... */ } ALWAYS_INLINE void Initialize() { m_impl.Initialize(); } ALWAYS_INLINE void Finalize() { m_impl.Finalize(); } ALWAYS_INLINE bool IsLocked() const { return m_impl.IsLocked(); } ALWAYS_INLINE void Lock() { return m_impl.Lock(); } ALWAYS_INLINE bool TryLock() { return m_impl.TryLock(); } ALWAYS_INLINE void Unlock() { return m_impl.Unlock(); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; using InternalBusyMutexStorage = util::TypedStorage<InternalBusyMutex>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { class InternalBusyMutexImpl { private: std::atomic<bool> m_value{false}; u8 m_padding[3]{}; public: constexpr InternalBusyMutexImpl() = default; ALWAYS_INLINE void Initialize() { m_value.store(false, std::memory_order_relaxed); } ALWAYS_INLINE void Finalize() { /* ... */ } ALWAYS_INLINE bool IsLocked() const { return m_value.load(std::memory_order_acquire); } ALWAYS_INLINE bool TryLock() { bool expected = false; return m_value.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_acquire); } ALWAYS_INLINE void Lock() { while (!this->TryLock()) { #if defined(ATMOSPHERE_ARCH_X64) || defined(ATMOSPHERE_ARCH_X86) _mm_pause(); #elif defined(ATMOSPHERE_ARCH_ARM64) || defined(ATMOSPHERE_ARCH_ARM) __asm__ __volatile__("yield" ::: "memory"); #else #error "InternalBusyMutex requires yield intrinsics" #endif } } ALWAYS_INLINE void Unlock() { m_value.store(false, std::memory_order_release); } }; static_assert(sizeof(InternalBusyMutexImpl) == sizeof(u32)); #define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0 } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { class InternalBusyMutexImpl { private: u32 m_value; public: constexpr InternalBusyMutexImpl() : m_value(0) { /* ... */ } constexpr void Initialize() { m_value = 0; } constexpr void Finalize() { /* ... */ } constexpr bool IsLocked() const { return m_value != 0; } void Lock(); bool TryLock(); void Unlock(); }; #define AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES 0 } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> #if defined(AMS_OS_IMPL_USE_PTHREADS) #include <stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp> #elif defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp> #else #error "Unknown OS for ams::os::impl::InternalConditionVariableImpl" #endif namespace ams::os::impl { class InternalConditionVariable { private: InternalConditionVariableImpl m_impl; public: constexpr InternalConditionVariable() : m_impl() { /* ... */ } void Initialize() { m_impl.Initialize(); } void Finalize() { m_impl.Finalize(); } void Signal() { m_impl.Signal(); } void Broadcast() { m_impl.Broadcast(); } void Wait(InternalCriticalSection *cs) { m_impl.Wait(cs); } ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper) { return m_impl.TimedWait(cs, timeout_helper); } }; using InternalConditionVariableStorage = util::TypedStorage<InternalConditionVariable>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os::impl { class TimeoutHelper; class InternalConditionVariableImpl { private: u32 m_value; public: constexpr InternalConditionVariableImpl() : m_value(0) { /* ... */ } constexpr void Initialize() { m_value = 0; } constexpr void Finalize() { /* ... */ } void Signal(); void Broadcast(); void Wait(InternalCriticalSection *cs); ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); }; using InternalConditionVariableStorageTypeForConstantInitialize = u32; #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER {0} } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.os.windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os::impl { class TimeoutHelper; struct WindowsConditionVariable; using WindowsConditionVariableStorage = util::TypedStorage<WindowsConditionVariable, sizeof(void *), alignof(void *)>; #if defined(ATMOSPHERE_ARCH_X64) #define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0, 0 #elif defined(ATMOSPHERE_ARCH_X86) #define AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES 0 #else #error "Unknown architecture for WindowsConditionVariable initializer" #endif class InternalConditionVariableImpl { private: u32 m_value; public: union { s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)]; WindowsConditionVariableStorage m_windows_cv_storage; }; constexpr InternalConditionVariableImpl() : _arr{AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ } constexpr ~InternalConditionVariableImpl() { if (!std::is_constant_evaluated()) { this->Finalize(); } } void Initialize(); void Finalize(); void Signal(); void Broadcast(); void Wait(InternalCriticalSection *cs); ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); }; struct InternalConditionVariableStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsConditionVariableStorage) / sizeof(s32)]; }; #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CONDITION_VARIABLE_CONSTANT_INITIALIZE_ARRAY_VALUES } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_condition_variable_impl.pthread.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os::impl { class TimeoutHelper; class InternalConditionVariableImpl { private: pthread_cond_t m_pthread_cond = PTHREAD_COND_INITIALIZER; public: constexpr InternalConditionVariableImpl() = default; constexpr ~InternalConditionVariableImpl() { if (!std::is_constant_evaluated()) { this->Finalize(); } } void Initialize(); void Finalize(); void Signal(); void Broadcast(); void Wait(InternalCriticalSection *cs); ConditionVariableStatus TimedWait(InternalCriticalSection *cs, const TimeoutHelper &timeout_helper); }; using InternalConditionVariableStorageTypeForConstantInitialize = pthread_cond_t; #define AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = PTHREAD_COND_INITIALIZER } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(AMS_OS_IMPL_USE_PTHREADS) #include <stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp> #elif defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp> #else #error "Unknown OS for ams::os::impl::InternalCriticalSectionImpl" #endif namespace ams::os::impl { class InternalCriticalSection { private: InternalCriticalSectionImpl m_impl; public: constexpr InternalCriticalSection() : m_impl() { /* ... */ } void Initialize() { m_impl.Initialize(); } void Finalize() { m_impl.Finalize(); } void Enter() { return m_impl.Enter(); } bool TryEnter() { return m_impl.TryEnter(); } void Leave() { return m_impl.Leave(); } #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) bool IsLockedByCurrentThread() const { return m_impl.IsLockedByCurrentThread(); } #endif ALWAYS_INLINE void Lock() { return this->Enter(); } ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } ALWAYS_INLINE void Unlock() { return this->Leave(); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } InternalCriticalSectionImpl *Get() { return std::addressof(m_impl); } const InternalCriticalSectionImpl *Get() const { return std::addressof(m_impl); } }; using InternalCriticalSectionStorage = util::TypedStorage<InternalCriticalSection>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { #if defined(ATMOSPHERE_OS_HORIZON) class ReaderWriterLockHorizonImpl; #endif class InternalConditionVariableImpl; class InternalCriticalSectionImpl { private: #if defined(ATMOSPHERE_OS_HORIZON) friend class ReaderWriterLockHorizonImpl; #endif friend class InternalConditionVariableImpl; private: u32 m_thread_handle; public: constexpr InternalCriticalSectionImpl() : m_thread_handle(svc::InvalidHandle) { /* ... */ } constexpr void Initialize() { m_thread_handle = svc::InvalidHandle; } constexpr void Finalize() { /* ... */ } void Enter(); bool TryEnter(); void Leave(); bool IsLockedByCurrentThread() const; ALWAYS_INLINE void Lock() { return this->Enter(); } ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } ALWAYS_INLINE void Unlock() { return this->Leave(); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; using InternalCriticalSectionStorageTypeForConstantInitialize = u32; #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER {0} #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.os.windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { class InternalConditionVariableImpl; struct WindowsCriticalSection; using WindowsCriticalSectionStorage = util::TypedStorage<WindowsCriticalSection, 8 + 4 * sizeof(void *), alignof(void *)>; #if defined(ATMOSPHERE_ARCH_X64) #define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, -1, 0, 0, 0, 0, 0, 0, 0 #elif defined(ATMOSPHERE_ARCH_X86) #define AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES -1, -1, 0, 0, 0, 0 #else #error "Unknown architecture for WindowsCriticalSection initializer" #endif class InternalCriticalSectionImpl { private: friend class InternalConditionVariableImpl; private: union { s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)]; WindowsCriticalSectionStorage m_windows_critical_section_storage; }; public: constexpr InternalCriticalSectionImpl() : _arr{AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES} { /* ... */ } constexpr ~InternalCriticalSectionImpl() { if (!std::is_constant_evaluated()) { this->Finalize(); } } void Initialize(); void Finalize(); void Enter(); bool TryEnter(); void Leave(); bool IsLockedByCurrentThread() const; ALWAYS_INLINE void Lock() { return this->Enter(); } ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } ALWAYS_INLINE void Unlock() { return this->Leave(); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; struct InternalCriticalSectionStorageTypeForConstantInitialize { s32 _arr[sizeof(WindowsCriticalSectionStorage) / sizeof(s32)]; }; #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER { AMS_OS_WINDOWS_CRITICAL_SECTION_CONSTANT_INITIALIZE_ARRAY_VALUES } #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_critical_section_impl.pthread.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_types.hpp> namespace ams::os::impl { class InternalConditionVariableImpl; /* NOTE: macOS (and possibly other targets) do not provide adaptive mutex. */ #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) #define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP #else #define AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #endif #if defined(ATMOSPHERE_OS_LINUX) #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD #else //#define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD #endif class InternalCriticalSectionImpl { private: friend class InternalConditionVariableImpl; private: pthread_mutex_t m_pthread_mutex = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER; public: constexpr InternalCriticalSectionImpl() = default; constexpr ~InternalCriticalSectionImpl() { if (!std::is_constant_evaluated()) { this->Finalize(); } } void Initialize(); void Finalize(); void Enter(); bool TryEnter(); void Leave(); #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) bool IsLockedByCurrentThread() const; #endif ALWAYS_INLINE void Lock() { return this->Enter(); } ALWAYS_INLINE bool TryLock() { return this->TryEnter(); } ALWAYS_INLINE void Unlock() { return this->Leave(); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; using InternalCriticalSectionStorageTypeForConstantInitialize = pthread_mutex_t; #define AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER ._storage_for_constant_initialize = AMS_OS_IMPL_PTHREAD_MUTEX_INITIALIZER } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_internal_light_event_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp> #else #error "Unknown OS for ams::os::impl::InternalLightEventImpl" #endif namespace ams::os::impl { class InternalLightEvent { private: InternalLightEventImpl m_impl; public: explicit InternalLightEvent(bool signaled) : m_impl(signaled) { /* ... */ } ALWAYS_INLINE void SignalWithAutoClear() { return m_impl.SignalWithAutoClear(); } ALWAYS_INLINE void SignalWithManualClear() { return m_impl.SignalWithManualClear(); } ALWAYS_INLINE void Clear() { return m_impl.Clear(); } ALWAYS_INLINE void WaitWithAutoClear() { return m_impl.WaitWithAutoClear(); } ALWAYS_INLINE void WaitWithManualClear() { return m_impl.WaitWithManualClear(); } ALWAYS_INLINE bool TryWaitWithAutoClear() { return m_impl.TryWaitWithAutoClear(); } ALWAYS_INLINE bool TryWaitWithManualClear() { return m_impl.TryWaitWithManualClear(); } ALWAYS_INLINE bool TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper) { return m_impl.TimedWaitWithAutoClear(timeout_helper); } ALWAYS_INLINE bool TimedWaitWithManualClear(const TimeoutHelper &timeout_helper) { return m_impl.TimedWaitWithManualClear(timeout_helper); } }; using InternalLightEventStorage = util::TypedStorage<InternalLightEvent>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event_impl.os.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os::impl { class TimeoutHelper; class InternalLightEventImpl { private: u16 m_counter_low; u8 m_counter_high; std::atomic<u8> m_signal_state; InternalCriticalSection m_cs; InternalConditionVariable m_cv; public: explicit InternalLightEventImpl(bool signaled) { this->Initialize(signaled); } ~InternalLightEventImpl() { this->Finalize(); } void Initialize(bool signaled); void Finalize(); void SignalWithAutoClear(); void SignalWithManualClear(); void Clear(); void WaitWithAutoClear(); void WaitWithManualClear(); bool TryWaitWithAutoClear(); bool TryWaitWithManualClear(); bool TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper); bool TimedWaitWithManualClear(const TimeoutHelper &timeout_helper); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_light_event_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { class TimeoutHelper; class InternalLightEventImpl { private: std::atomic<s32> m_state; u32 m_padding; public: explicit InternalLightEventImpl(bool signaled) { this->Initialize(signaled); } ~InternalLightEventImpl() { this->Finalize(); } void Initialize(bool signaled); void Finalize(); void SignalWithAutoClear(); void SignalWithManualClear(); void Clear(); void WaitWithAutoClear(); void WaitWithManualClear(); bool TryWaitWithAutoClear(); bool TryWaitWithManualClear(); bool TimedWaitWithAutoClear(const TimeoutHelper &timeout_helper); bool TimedWaitWithManualClear(const TimeoutHelper &timeout_helper); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp> #elif defined(ATMOSPHERE_OS_LINUX) #include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp> #elif defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp> #else #error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexImpl" #endif namespace ams::os::impl { class InternalReaderWriterBusyMutex { private: InternalReaderWriterBusyMutexImpl m_impl; public: constexpr InternalReaderWriterBusyMutex() : m_impl() { /* ... */ } ALWAYS_INLINE void AcquireReadLock() { return m_impl.AcquireReadLock(); } ALWAYS_INLINE void ReleaseReadLock() { return m_impl.ReleaseReadLock(); } ALWAYS_INLINE void AcquireWriteLock() { return m_impl.AcquireWriteLock(); } ALWAYS_INLINE void ReleaseWriteLock() { return m_impl.ReleaseWriteLock(); } }; using InternalReaderWriterBusyMutexStorage = util::TypedStorage<InternalReaderWriterBusyMutex>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp> namespace ams::os::impl { class InternalReaderWriterBusyMutexImpl { private: u32 m_value; public: constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { /* ... */ } constexpr void Initialize() { m_value = 0; } void AcquireReadLock(); void ReleaseReadLock(); void AcquireWriteLock(); void ReleaseWriteLock(); }; #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp> namespace ams::os::impl { /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ class InternalReaderWriterBusyMutexImpl { private: u32 m_value; public: constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } } constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } } void AcquireReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } void ReleaseReadLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } void AcquireWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } void ReleaseWriteLock() { AMS_ABORT("TODO: Linux InternalReaderWriterBusyMutexImpl"); } }; #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp> namespace ams::os::impl { /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ class InternalReaderWriterBusyMutexImpl { private: u32 m_value; public: constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } } constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } } void AcquireReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } void ReleaseReadLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } void AcquireWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } void ReleaseWriteLock() { AMS_ABORT("TODO: macOS InternalReaderWriterBusyMutexImpl"); } }; #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp> namespace ams::os::impl { /* NOTE: The current implementation is based on load/linked store conditional, we should figure out how to do this on x64. */ /* We could also consider using https://docs.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks */ class InternalReaderWriterBusyMutexImpl { private: u32 m_value; public: constexpr InternalReaderWriterBusyMutexImpl() : m_value(0) { if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } } constexpr void Initialize() { m_value = 0; if (!std::is_constant_evaluated()) { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } } void AcquireReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } void ReleaseReadLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } void AcquireWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } void ReleaseWriteLock() { AMS_ABORT("TODO: Windows InternalReaderWriterBusyMutexImpl"); } }; #define AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER {0} } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_internal_rw_busy_mutex_value.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) class InternalReaderWriterBusyMutexValue { public: static constexpr inline u8 WriterCountMax = std::numeric_limits<u8>::max(); static constexpr ALWAYS_INLINE u16 GetReaderCount(u32 v) { return static_cast<u16>(v >> 0); } static constexpr ALWAYS_INLINE u8 GetWriterCurrent(u32 v) { return static_cast<u8>(v >> 16); } static constexpr ALWAYS_INLINE u8 GetWriterNext(u32 v) { return static_cast<u8>(v >> 24); } static constexpr ALWAYS_INLINE u32 IncrementWriterNext(u32 v) { return v + (1u << 24); } static constexpr ALWAYS_INLINE bool IsWriteLocked(u32 v) { return GetWriterCurrent(v) != GetWriterNext(v); } static ALWAYS_INLINE u8 *GetWriterCurrentPointer(u32 *p) { if constexpr (util::IsLittleEndian()) { return reinterpret_cast<u8 *>(reinterpret_cast<uintptr_t>(p)) + 2; } else { return reinterpret_cast<u8 *>(reinterpret_cast<uintptr_t>(p)) + 1; } } }; #else #error "Unknown OS for ams::os::impl::InternalReaderWriterBusyMutexValue" #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_memory_fence_api.os.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_ARCH_X64) #include <xmmintrin.h> #include <emmintrin.h> #endif namespace ams::os::impl { #if defined(ATMOSPHERE_ARCH_X64) ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("" ::: "memory"); _mm_sfence(); } ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("" ::: "memory"); _mm_lfence(); } ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("" ::: "memory"); _mm_mfence(); } ALWAYS_INLINE void FenceMemoryAnyAny() {__asm__ __volatile__("" ::: "memory"); _mm_mfence(); } #elif defined(ATMOSPHERE_ARCH_ARM64) ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); } ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } #else #error "Unknown architecture for os::impl::FenceMemory* (Generic)" #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/impl/os_memory_fence_api.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os::impl { #if defined(ATMOSPHERE_ARCH_ARM64) ALWAYS_INLINE void FenceMemoryStoreStore() { __asm__ __volatile__("dmb ishst" ::: "memory"); } ALWAYS_INLINE void FenceMemoryStoreLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryStoreAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadStore() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadLoad() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryLoadAny() { __asm__ __volatile__("dmb ishld" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyStore() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyLoad() { __asm__ __volatile__("dmb ish" ::: "memory"); } ALWAYS_INLINE void FenceMemoryAnyAny() { __asm__ __volatile__("dmb ish" ::: "memory"); } #else #error "Unknown architecture for os::impl::FenceMemory* (Horizon)" #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_argument.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { int GetHostArgc(); char **GetHostArgv(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_barrier.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_barrier_types.hpp> #include <stratosphere/os/os_barrier_api.hpp> namespace ams::os { class Barrier { NON_COPYABLE(Barrier); NON_MOVEABLE(Barrier); private: BarrierType m_barrier; public: explicit Barrier(int num_threads) { InitializeBarrier(std::addressof(m_barrier), num_threads); } ~Barrier() { FinalizeBarrier(std::addressof(m_barrier)); } void Await() { return AwaitBarrier(std::addressof(m_barrier)); } operator BarrierType &() { return m_barrier; } operator const BarrierType &() const { return m_barrier; } BarrierType *GetBase() { return std::addressof(m_barrier); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_barrier_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct BarrierType; void InitializeBarrier(BarrierType *barrier, int num_threads); void FinalizeBarrier(BarrierType *barrier); void AwaitBarrier(BarrierType *barrier); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_barrier_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { struct BarrierType { u16 max_threads; u16 waiting_threads; u32 base_counter_lower; u32 base_counter_upper; impl::InternalCriticalSectionStorage cs_barrier; impl::InternalConditionVariableStorage cv_gathered; }; static_assert(std::is_trivial<BarrierType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_busy_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_busy_mutex_types.hpp> #include <stratosphere/os/os_busy_mutex_api.hpp> namespace ams::os { class BusyMutex { NON_COPYABLE(BusyMutex); NON_MOVEABLE(BusyMutex); private: BusyMutexType m_mutex; public: constexpr explicit BusyMutex() : m_mutex{::ams::os::BusyMutexType::State_Initialized, nullptr, {{AMS_OS_INTERNAL_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZE_ARRAY_VALUES}}} { /* ... */ } ~BusyMutex() { FinalizeBusyMutex(std::addressof(m_mutex)); } void lock() { return LockBusyMutex(std::addressof(m_mutex)); } void unlock() { return UnlockBusyMutex(std::addressof(m_mutex)); } bool try_lock() { return TryLockBusyMutex(std::addressof(m_mutex)); } ALWAYS_INLINE void Lock() { return this->lock(); } ALWAYS_INLINE void Unlock() { return this->unlock(); } ALWAYS_INLINE bool TryLock() { return this->try_lock(); } operator BusyMutexType &() { return m_mutex; } operator const BusyMutexType &() const { return m_mutex; } BusyMutexType *GetBase() { return std::addressof(m_mutex); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_busy_mutex_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct BusyMutexType; void InitializeBusyMutex(BusyMutexType *mutex); void FinalizeBusyMutex(BusyMutexType *mutex); void LockBusyMutex(BusyMutexType *mutex); bool TryLockBusyMutex(BusyMutexType *mutex); void UnlockBusyMutex(BusyMutexType *mutex); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_busy_mutex_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_busy_mutex.hpp> namespace ams::os { struct ThreadType; struct BusyMutexType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; u8 state; ThreadType *owner_thread; union { s32 _arr[sizeof(impl::InternalBusyMutexStorage) / sizeof(s32)]; impl::InternalBusyMutexStorage _storage; }; }; static_assert(std::is_trivial<BusyMutexType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_cache.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { void FlushDataCache(const void *addr, size_t size); void FlushEntireDataCache(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_common_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { #if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #define AMS_OS_IMPL_USE_PTHREADS #elif defined(ATMOSPHERE_OS_WINDOWS) //#define AMS_OS_IMPL_USE_PTHREADS #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_common_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_config.hpp> #if defined(AMS_OS_IMPL_USE_PTHREADS) #include <pthread.h> #endif namespace ams::os { enum class TriBool { False = 0, True = 1, Undefined = 2, }; enum class MessageQueueWaitKind { ForNotEmpty, ForNotFull, }; struct ProcessId { u64 value; inline constexpr explicit operator u64() const { return this->value; } /* Invalid Process ID. */ static const ProcessId Invalid; }; inline constexpr const ProcessId ProcessId::Invalid = {static_cast<u64>(-1ull)}; inline constexpr const ProcessId InvalidProcessId = ProcessId::Invalid; inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value == rhs.value; } inline constexpr bool operator!=(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value != rhs.value; } inline constexpr bool operator<(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value < rhs.value; } inline constexpr bool operator<=(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value <= rhs.value; } inline constexpr bool operator>(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value > rhs.value; } inline constexpr bool operator>=(const ProcessId &lhs, const ProcessId &rhs) { return lhs.value >= rhs.value; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_condition_variable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_mutex_types.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> #include <stratosphere/os/os_condition_variable_types.hpp> #include <stratosphere/os/os_condition_variable_api.hpp> namespace ams::os { class ConditionVariable { NON_COPYABLE(ConditionVariable); NON_MOVEABLE(ConditionVariable); private: ConditionVariableType m_cv; public: constexpr ConditionVariable() : m_cv{::ams::os::ConditionVariableType::State_Initialized, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } ~ConditionVariable() { FinalizeConditionVariable(std::addressof(m_cv)); } void Signal() { SignalConditionVariable(std::addressof(m_cv)); } void Broadcast() { BroadcastConditionVariable(std::addressof(m_cv)); } void Wait(ams::os::MutexType &mutex) { WaitConditionVariable(std::addressof(m_cv), std::addressof(mutex)); } ConditionVariableStatus TimedWait(ams::os::MutexType &mutex, TimeSpan timeout) { return TimedWaitConditionVariable(std::addressof(m_cv), std::addressof(mutex), timeout); } operator ConditionVariableType &() { return m_cv; } operator const ConditionVariableType &() const { return m_cv; } ConditionVariableType *GetBase() { return std::addressof(m_cv); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_condition_variable_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_condition_variable_common.hpp> namespace ams::os { struct MutexType; struct ConditionVariableType; void InitializeConditionVariable(ConditionVariableType *cv); void FinalizeConditionVariable(ConditionVariableType *cv); void SignalConditionVariable(ConditionVariableType *cv); void BroadcastConditionVariable(ConditionVariableType *cv); void WaitConditionVariable(ConditionVariableType *cv, MutexType *m); ConditionVariableStatus TimedWaitConditionVariable(ConditionVariableType *cv, MutexType *m, TimeSpan timeout); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_condition_variable_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { enum class ConditionVariableStatus { TimedOut = 0, Success = 1, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_condition_variable_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { struct ConditionVariableType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; u8 state; union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial<ConditionVariableType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_debug.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_debug_types.hpp> #include <stratosphere/os/os_debug_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_debug_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_debug_types.hpp> #include <stratosphere/os/os_tick.hpp> namespace ams::os { void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size); void QueryMemoryInfo(MemoryInfo *out); Tick GetIdleTickCount(); int GetFreeThreadCount(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_debug_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct MemoryInfo { u64 total_available_memory_size; size_t total_used_memory_size; size_t total_memory_heap_size; size_t allocated_memory_heap_size; size_t program_size; size_t total_thread_stack_size; int thread_count; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/os_event_types.hpp> #include <stratosphere/os/os_event_api.hpp> namespace ams::os { class Event { NON_COPYABLE(Event); NON_MOVEABLE(Event); private: EventType m_event; public: explicit Event(EventClearMode clear_mode) { InitializeEvent(std::addressof(m_event), false, clear_mode); } ~Event() { FinalizeEvent(std::addressof(m_event)); } void Wait() { return WaitEvent(std::addressof(m_event)); } bool TryWait() { return TryWaitEvent(std::addressof(m_event)); } bool TimedWait(TimeSpan timeout) { return TimedWaitEvent(std::addressof(m_event), timeout); } void Signal() { return SignalEvent(std::addressof(m_event)); } void Clear() { return ClearEvent(std::addressof(m_event)); } operator EventType &() { return m_event; } operator const EventType &() const { return m_event; } EventType *GetBase() { return std::addressof(m_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_event_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> namespace ams::os { struct EventType; struct MultiWaitHolderType; void InitializeEvent(EventType *event, bool signaled, EventClearMode clear_mode); void FinalizeEvent(EventType *event); void SignalEvent(EventType *event); void WaitEvent(EventType *event); bool TryWaitEvent(EventType *event); bool TimedWaitEvent(EventType *event, TimeSpan timeout); void ClearEvent(EventType *event); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, EventType *event); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_event_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { enum EventClearMode { EventClearMode_ManualClear = 0, EventClearMode_AutoClear = 1, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_event_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; } struct EventType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> multi_wait_object_list_storage; bool signaled; bool initially_signaled; u8 clear_mode; u8 state; u32 broadcast_counter_low; u32 broadcast_counter_high; impl::InternalCriticalSectionStorage cs_event; impl::InternalConditionVariableStorage cv_signaled; }; static_assert(std::is_trivial<EventType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_insecure_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { Result AllocateInsecureMemory(uintptr_t *out_address, size_t size); void FreeInsecureMemory(uintptr_t address, size_t size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_interrupt_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/os_interrupt_event_common.hpp> #include <stratosphere/os/os_interrupt_event_types.hpp> #include <stratosphere/os/os_interrupt_event_api.hpp> namespace ams::os { class InterruptEvent { NON_COPYABLE(InterruptEvent); NON_MOVEABLE(InterruptEvent); private: InterruptEventType m_event; public: explicit InterruptEvent(InterruptName name, EventClearMode clear_mode) { InitializeInterruptEvent(std::addressof(m_event), name, clear_mode); } ~InterruptEvent() { FinalizeInterruptEvent(std::addressof(m_event)); } void Wait() { return WaitInterruptEvent(std::addressof(m_event)); } bool TryWait() { return TryWaitInterruptEvent(std::addressof(m_event)); } bool TimedWait(TimeSpan timeout) { return TimedWaitInterruptEvent(std::addressof(m_event), timeout); } void Clear() { return ClearInterruptEvent(std::addressof(m_event)); } operator InterruptEventType &() { return m_event; } operator const InterruptEventType &() const { return m_event; } InterruptEventType *GetBase() { return std::addressof(m_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_interrupt_event_common.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct InterruptEventType; struct MultiWaitHolderType; void InitializeInterruptEvent(InterruptEventType *event, InterruptName name, EventClearMode clear_mode); void FinalizeInterruptEvent(InterruptEventType *event); void WaitInterruptEvent(InterruptEventType *event); bool TryWaitInterruptEvent(InterruptEventType *event); bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout); void ClearInterruptEvent(InterruptEventType *event); NativeHandle GetInterruptEventHandle(const InterruptEventType *event); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { #if defined(ATMOSPHERE_OS_HORIZON) using InterruptName = s32; #elif defined(ATMOSPHERE_OS_WINDOWS) using InterruptName = const char *; #elif defined(ATMOSPHERE_OS_LINUX) using InterruptName = const char *; #elif defined(ATMOSPHERE_OS_MACOS) using InterruptName = const char *; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; class InterruptEventImpl; } struct InterruptEventType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> multi_wait_object_list_storage; u8 clear_mode; u8 state; util::TypedStorage<impl::InterruptEventImpl, sizeof(NativeHandle) * 2, alignof(NativeHandle)> impl; }; static_assert(std::is_trivial<InterruptEventType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_io_region.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_io_region_types.hpp> #include <stratosphere/os/os_io_region_api.hpp> namespace ams::os { class IoRegion { NON_COPYABLE(IoRegion); NON_MOVEABLE(IoRegion); private: IoRegionType m_io_region; public: constexpr IoRegion() : m_io_region{ .state = IoRegionType::State_NotInitialized } { /* ... */ } IoRegion(NativeHandle io_pool_handle, uintptr_t address, size_t size, MemoryMapping mapping, MemoryPermission permission) { R_ABORT_UNLESS(CreateIoRegion(std::addressof(m_io_region), io_pool_handle, address, size, mapping, permission)); } IoRegion(size_t size, NativeHandle handle, bool managed) { this->AttachHandle(size, handle, managed); } ~IoRegion() { if (m_io_region.state == IoRegionType::State_NotInitialized) { return; } if (m_io_region.state == IoRegionType::State_Mapped) { this->Unmap(); } DestroyIoRegion(std::addressof(m_io_region)); } void AttachHandle(size_t size, NativeHandle handle, bool managed) { AttachIoRegionHandle(std::addressof(m_io_region), size, handle, managed); } NativeHandle GetHandle() const { return GetIoRegionHandle(std::addressof(m_io_region)); } Result Map(void **out, MemoryPermission perm) { R_RETURN(MapIoRegion(out, std::addressof(m_io_region), perm)); } void Unmap() { UnmapIoRegion(std::addressof(m_io_region)); } operator IoRegionType &() { return m_io_region; } operator const IoRegionType &() const { return m_io_region; } IoRegionType *GetBase() { return std::addressof(m_io_region); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_io_region_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_memory_permission.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct IoRegionType; Result CreateIoRegion(IoRegionType *io_region, NativeHandle io_pool_handle, uintptr_t address, size_t size, MemoryMapping mapping, MemoryPermission permission); void AttachIoRegionHandle(IoRegionType *io_region, size_t size, NativeHandle handle, bool managed); os::NativeHandle DetachIoRegionHandle(IoRegionType *io_region); void DestroyIoRegion(IoRegionType *io_region); NativeHandle GetIoRegionHandle(const IoRegionType *io_region); Result MapIoRegion(void **out, IoRegionType *io_region, MemoryPermission perm); void UnmapIoRegion(IoRegionType *io_region); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_io_region_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct IoRegionType { enum State { State_NotInitialized = 0, State_Initialized = 1, State_Mapped = 2, State_Detached = 3, }; NativeHandle handle; u8 state; size_t size; void *mapped_address; bool handle_managed; mutable impl::InternalCriticalSectionStorage cs_io_region; }; static_assert(std::is_trivial<IoRegionType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/os_light_event_types.hpp> #include <stratosphere/os/os_light_event_api.hpp> namespace ams::os { class LightEvent { NON_COPYABLE(LightEvent); NON_MOVEABLE(LightEvent); private: LightEventType m_event; public: explicit LightEvent(EventClearMode clear_mode) { InitializeLightEvent(std::addressof(m_event), false, clear_mode); } ~LightEvent() { FinalizeLightEvent(std::addressof(m_event)); } void Wait() { return WaitLightEvent(std::addressof(m_event)); } bool TryWait() { return TryWaitLightEvent(std::addressof(m_event)); } bool TimedWait(TimeSpan timeout) { return TimedWaitLightEvent(std::addressof(m_event), timeout); } void Signal() { return SignalLightEvent(std::addressof(m_event)); } void Clear() { return ClearLightEvent(std::addressof(m_event)); } operator LightEventType &() { return m_event; } operator const LightEventType &() const { return m_event; } LightEventType *GetBase() { return std::addressof(m_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_event_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> namespace ams::os { struct LightEventType; void InitializeLightEvent(LightEventType *event, bool signaled, EventClearMode clear_mode); void FinalizeLightEvent(LightEventType *event); void SignalLightEvent(LightEventType *event); void WaitLightEvent(LightEventType *event); bool TryWaitLightEvent(LightEventType *event); bool TimedWaitLightEvent(LightEventType *event, TimeSpan timeout); void ClearLightEvent(LightEventType *event); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_event_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_light_event.hpp> namespace ams::os { struct LightEventType { bool is_auto_clear; bool is_initialized; impl::InternalLightEventStorage storage; }; static_assert(std::is_trivial<LightEventType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_message_queue.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_light_message_queue_types.hpp> #include <stratosphere/os/os_light_message_queue_api.hpp> namespace ams::os { class LightMessageQueue { NON_COPYABLE(LightMessageQueue); NON_MOVEABLE(LightMessageQueue); private: LightMessageQueueType m_mq; public: explicit LightMessageQueue(uintptr_t *buf, size_t count) { InitializeLightMessageQueue(std::addressof(m_mq), buf, count); } ~LightMessageQueue() { FinalizeLightMessageQueue(std::addressof(m_mq)); } /* Sending (FIFO functionality) */ void Send(uintptr_t data) { return SendLightMessageQueue(std::addressof(m_mq), data); } bool TrySend(uintptr_t data) { return TrySendLightMessageQueue(std::addressof(m_mq), data); } bool TimedSend(uintptr_t data, TimeSpan timeout) { return TimedSendLightMessageQueue(std::addressof(m_mq), data, timeout); } /* Jamming (LIFO functionality) */ void Jam(uintptr_t data) { return JamLightMessageQueue(std::addressof(m_mq), data); } bool TryJam(uintptr_t data) { return TryJamLightMessageQueue(std::addressof(m_mq), data); } bool TimedJam(uintptr_t data, TimeSpan timeout) { return TimedJamLightMessageQueue(std::addressof(m_mq), data, timeout); } /* Receive functionality */ void Receive(uintptr_t *out) { return ReceiveLightMessageQueue(out, std::addressof(m_mq)); } bool TryReceive(uintptr_t *out) { return TryReceiveLightMessageQueue(out, std::addressof(m_mq)); } bool TimedReceive(uintptr_t *out, TimeSpan timeout) { return TimedReceiveLightMessageQueue(out, std::addressof(m_mq), timeout); } /* Peek functionality */ void Peek(uintptr_t *out) const { return PeekLightMessageQueue(out, std::addressof(m_mq)); } bool TryPeek(uintptr_t *out) const { return TryPeekLightMessageQueue(out, std::addressof(m_mq)); } bool TimedPeek(uintptr_t *out, TimeSpan timeout) const { return TimedPeekLightMessageQueue(out, std::addressof(m_mq), timeout); } operator LightMessageQueueType &() { return m_mq; } operator const LightMessageQueueType &() const { return m_mq; } LightMessageQueueType *GetBase() { return std::addressof(m_mq); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_message_queue_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct LightMessageQueueType; void InitializeLightMessageQueue(LightMessageQueueType *mq, uintptr_t *buffer, size_t count); void FinalizeLightMessageQueue(LightMessageQueueType *mq); /* Sending (FIFO functionality) */ void SendLightMessageQueue(LightMessageQueueType *mq, uintptr_t data); bool TrySendLightMessageQueue(LightMessageQueueType *mq, uintptr_t data); bool TimedSendLightMessageQueue(LightMessageQueueType *mq, uintptr_t data, TimeSpan timeout); /* Jamming (LIFO functionality) */ void JamLightMessageQueue(LightMessageQueueType *mq, uintptr_t data); bool TryJamLightMessageQueue(LightMessageQueueType *mq, uintptr_t data); bool TimedJamLightMessageQueue(LightMessageQueueType *mq, uintptr_t data, TimeSpan timeout); /* Receive functionality */ void ReceiveLightMessageQueue(uintptr_t *out, LightMessageQueueType *mq); bool TryReceiveLightMessageQueue(uintptr_t *out, LightMessageQueueType *mq); bool TimedReceiveLightMessageQueue(uintptr_t *out, LightMessageQueueType *mq, TimeSpan timeout); /* Peek functionality */ void PeekLightMessageQueue(uintptr_t *out, const LightMessageQueueType *mq); bool TryPeekLightMessageQueue(uintptr_t *out, const LightMessageQueueType *mq); bool TimedPeekLightMessageQueue(uintptr_t *out, const LightMessageQueueType *mq, TimeSpan timeout); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_message_queue_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_busy_mutex.hpp> #include <stratosphere/os/impl/os_internal_light_event.hpp> namespace ams::os { namespace impl { using LightMessageQueueMutex = InternalBusyMutex; using LightMessageQueueMutexStorage = InternalBusyMutexStorage; } struct LightMessageQueueType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; uintptr_t *buffer; s32 capacity; s32 count; s32 offset; u8 state; mutable impl::LightMessageQueueMutexStorage mutex_queue; mutable impl::InternalLightEventStorage ev_not_full; mutable impl::InternalLightEventStorage ev_not_empty; }; static_assert(std::is_trivial<LightMessageQueueType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_semaphore.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_light_semaphore_types.hpp> #include <stratosphere/os/os_light_semaphore_api.hpp> namespace ams::os { class LightSemaphore { NON_COPYABLE(LightSemaphore); NON_MOVEABLE(LightSemaphore); private: LightSemaphoreType m_sema; public: explicit LightSemaphore(s32 count, s32 max_count) { InitializeLightSemaphore(std::addressof(m_sema), count, max_count); } ~LightSemaphore() { FinalizeLightSemaphore(std::addressof(m_sema)); } void Acquire() { return os::AcquireLightSemaphore(std::addressof(m_sema)); } bool TryAcquire() { return os::TryAcquireLightSemaphore(std::addressof(m_sema)); } bool TimedAcquire(TimeSpan timeout) { return os::TimedAcquireLightSemaphore(std::addressof(m_sema), timeout); } void Release() { return os::ReleaseLightSemaphore(std::addressof(m_sema)); } void Release(s32 count) { return os::ReleaseLightSemaphore(std::addressof(m_sema), count); } s32 GetCurrentCount() const { return os::GetCurrentLightSemaphoreCount(std::addressof(m_sema)); } operator LightSemaphoreType &() { return m_sema; } operator const LightSemaphoreType &() const { return m_sema; } LightSemaphoreType *GetBase() { return std::addressof(m_sema); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_semaphore_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct LightSemaphoreType; void InitializeLightSemaphore(LightSemaphoreType *sema, s32 count, s32 max_count); void FinalizeLightSemaphore(LightSemaphoreType *sema); void AcquireLightSemaphore(LightSemaphoreType *sema); bool TryAcquireLightSemaphore(LightSemaphoreType *sema); bool TimedAcquireLightSemaphore(LightSemaphoreType *sema, TimeSpan timeout); void ReleaseLightSemaphore(LightSemaphoreType *sema); void ReleaseLightSemaphore(LightSemaphoreType *sema, s32 count); s32 GetCurrentLightSemaphoreCount(const LightSemaphoreType *sema); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_light_semaphore_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_busy_mutex.hpp> #include <stratosphere/os/impl/os_internal_light_event.hpp> namespace ams::os { namespace impl { using LightSemaphoreMutex = InternalBusyMutex; using LightSemaphoreMutexStorage = InternalBusyMutexStorage; } struct LightSemaphoreType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; u8 state; s32 count; s32 max_count; mutable impl::LightSemaphoreMutexStorage mutex; impl::InternalLightEventStorage ev_not_zero; }; static_assert(std::is_trivial<LightSemaphoreType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_attribute.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { enum MemoryAttribute { MemoryAttribute_Normal, MemoryAttribute_Uncached, }; void SetMemoryAttribute(uintptr_t address, size_t size, MemoryAttribute attr); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { using AddressSpaceGenerateRandomFunction = u64 (*)(u64); enum MemoryPermission { MemoryPermission_None = (0 << 0), MemoryPermission_ReadOnly = (1 << 0), MemoryPermission_WriteOnly = (1 << 1), MemoryPermission_ExecuteOnly = (1 << 2), MemoryPermission_ReadWrite = MemoryPermission_ReadOnly | MemoryPermission_WriteOnly, MemoryPermission_ReadExecute = MemoryPermission_ReadOnly | MemoryPermission_ExecuteOnly, }; #if defined(ATMOSPHERE_OS_HORIZON) using MemoryMapping = svc::MemoryMapping; using enum svc::MemoryMapping; #else enum MemoryMapping : u32 { MemoryMapping_IoRegister = 0, MemoryMapping_Uncached = 1, MemoryMapping_Memory = 2, }; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_fence.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_memory_fence_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_fence_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/os/impl/os_memory_fence_api.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/os/impl/os_memory_fence_api.os.generic.hpp> #else #error "Unknown os for os::MemoryFence*" #endif namespace ams::os { ALWAYS_INLINE void FenceMemoryStoreStore() { return impl::FenceMemoryStoreStore(); } ALWAYS_INLINE void FenceMemoryStoreLoad() { return impl::FenceMemoryStoreLoad(); } ALWAYS_INLINE void FenceMemoryStoreAny() { return impl::FenceMemoryStoreAny(); } ALWAYS_INLINE void FenceMemoryLoadStore() { return impl::FenceMemoryLoadStore(); } ALWAYS_INLINE void FenceMemoryLoadLoad() { return impl::FenceMemoryLoadLoad(); } ALWAYS_INLINE void FenceMemoryLoadAny() { return impl::FenceMemoryLoadAny(); } ALWAYS_INLINE void FenceMemoryAnyStore() { return impl::FenceMemoryLoadStore(); } ALWAYS_INLINE void FenceMemoryAnyLoad() { return impl::FenceMemoryLoadLoad(); } ALWAYS_INLINE void FenceMemoryAnyAny() { return impl::FenceMemoryLoadAny(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_heap.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_memory_heap_common.hpp> #include <stratosphere/os/os_memory_heap_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_heap_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_heap_common.hpp> namespace ams::os { Result SetMemoryHeapSize(size_t size); uintptr_t GetMemoryHeapAddress(); size_t GetMemoryHeapSize(); Result AllocateMemoryBlock(uintptr_t *out_address, size_t size); void FreeMemoryBlock(uintptr_t address, size_t size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_heap_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { constexpr inline size_t MemoryHeapUnitSize = 2_MB; constexpr inline size_t MemoryBlockUnitSize = 2_MB; constexpr inline size_t MemoryPageSize = 4_KB; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_memory_permission.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { void SetMemoryPermission(uintptr_t address, size_t size, MemoryPermission perm); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_message_queue.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_message_queue_common.hpp> #include <stratosphere/os/os_message_queue_types.hpp> #include <stratosphere/os/os_message_queue_api.hpp> namespace ams::os { class MessageQueue { NON_COPYABLE(MessageQueue); NON_MOVEABLE(MessageQueue); private: MessageQueueType m_mq; public: explicit MessageQueue(uintptr_t *buf, size_t count) { InitializeMessageQueue(std::addressof(m_mq), buf, count); } ~MessageQueue() { FinalizeMessageQueue(std::addressof(m_mq)); } /* Sending (FIFO functionality) */ void Send(uintptr_t data) { return SendMessageQueue(std::addressof(m_mq), data); } bool TrySend(uintptr_t data) { return TrySendMessageQueue(std::addressof(m_mq), data); } bool TimedSend(uintptr_t data, TimeSpan timeout) { return TimedSendMessageQueue(std::addressof(m_mq), data, timeout); } /* Jamming (LIFO functionality) */ void Jam(uintptr_t data) { return JamMessageQueue(std::addressof(m_mq), data); } bool TryJam(uintptr_t data) { return TryJamMessageQueue(std::addressof(m_mq), data); } bool TimedJam(uintptr_t data, TimeSpan timeout) { return TimedJamMessageQueue(std::addressof(m_mq), data, timeout); } /* Receive functionality */ void Receive(uintptr_t *out) { return ReceiveMessageQueue(out, std::addressof(m_mq)); } bool TryReceive(uintptr_t *out) { return TryReceiveMessageQueue(out, std::addressof(m_mq)); } bool TimedReceive(uintptr_t *out, TimeSpan timeout) { return TimedReceiveMessageQueue(out, std::addressof(m_mq), timeout); } /* Peek functionality */ void Peek(uintptr_t *out) const { return PeekMessageQueue(out, std::addressof(m_mq)); } bool TryPeek(uintptr_t *out) const { return TryPeekMessageQueue(out, std::addressof(m_mq)); } bool TimedPeek(uintptr_t *out, TimeSpan timeout) const { return TimedPeekMessageQueue(out, std::addressof(m_mq), timeout); } operator MessageQueueType &() { return m_mq; } operator const MessageQueueType &() const { return m_mq; } MessageQueueType *GetBase() { return std::addressof(m_mq); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_message_queue_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_message_queue_common.hpp> namespace ams::os { struct MessageQueueType; struct MultiWaitHolderType; void InitializeMessageQueue(MessageQueueType *mq, uintptr_t *buffer, size_t count); void FinalizeMessageQueue(MessageQueueType *mq); /* Sending (FIFO functionality) */ void SendMessageQueue(MessageQueueType *mq, uintptr_t data); bool TrySendMessageQueue(MessageQueueType *mq, uintptr_t data); bool TimedSendMessageQueue(MessageQueueType *mq, uintptr_t data, TimeSpan timeout); /* Jamming (LIFO functionality) */ void JamMessageQueue(MessageQueueType *mq, uintptr_t data); bool TryJamMessageQueue(MessageQueueType *mq, uintptr_t data); bool TimedJamMessageQueue(MessageQueueType *mq, uintptr_t data, TimeSpan timeout); /* Receive functionality */ void ReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq); bool TryReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq); bool TimedReceiveMessageQueue(uintptr_t *out, MessageQueueType *mq, TimeSpan timeout); /* Peek functionality */ void PeekMessageQueue(uintptr_t *out, const MessageQueueType *mq); bool TryPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq); bool TimedPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq, TimeSpan timeout); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, MessageQueueType *event, MessageQueueWaitType wait_type); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_message_queue_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { enum class MessageQueueWaitType { ForNotFull = 1, ForNotEmpty = 2, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_message_queue_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; } struct MessageQueueType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty; uintptr_t *buffer; s32 capacity; s32 count; s32 offset; u8 state; mutable impl::InternalCriticalSectionStorage cs_queue; mutable impl::InternalConditionVariableStorage cv_not_full; mutable impl::InternalConditionVariableStorage cv_not_empty; }; static_assert(std::is_trivial<MessageQueueType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_multiple_wait.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_multiple_wait_types.hpp> #include <stratosphere/os/os_multiple_wait_api.hpp> #include <stratosphere/os/os_multiple_wait_utils.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_message_queue_common.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct MultiWaitHolderType; struct MultiWaitType; void InitializeMultiWait(MultiWaitType *multi_wait); void FinalizeMultiWait(MultiWaitType *multi_wait); MultiWaitHolderType *WaitAny(MultiWaitType *multi_wait); MultiWaitHolderType *TryWaitAny(MultiWaitType *multi_wait); MultiWaitHolderType *TimedWaitAny(MultiWaitType *multi_wait, TimeSpan timeout); void FinalizeMultiWaitHolder(MultiWaitHolderType *holder); void LinkMultiWaitHolder(MultiWaitType *multi_wait, MultiWaitHolderType *holder); void UnlinkMultiWaitHolder(MultiWaitHolderType *holder); void UnlinkAllMultiWaitHolder(MultiWaitType *multi_wait); void MoveAllMultiWaitHolder(MultiWaitType *dst, MultiWaitType *src); void SetMultiWaitHolderUserData(MultiWaitHolderType *holder, uintptr_t user_data); uintptr_t GetMultiWaitHolderUserData(const MultiWaitHolderType *holder); void InitializeMultiWaitHolder(MultiWaitHolderType *holder, NativeHandle handle); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os { namespace impl { class MultiWaitImpl; struct MultiWaitHolderImpl; } struct MultiWaitType { enum State { State_NotInitialized, State_Initialized, }; u8 state; bool is_waiting; util::TypedStorage<impl::MultiWaitImpl, util::AlignUp(sizeof(util::IntrusiveListNode) + sizeof(impl::InternalCriticalSection) + 2 * sizeof(void *) + sizeof(NativeHandle), alignof(void *)), alignof(void *)> impl_storage; }; static_assert(std::is_trivial<MultiWaitType>::value); struct MultiWaitHolderType { util::TypedStorage<impl::MultiWaitHolderImpl, 2 * sizeof(util::IntrusiveListNode) + 3 * sizeof(void *), alignof(void *)> impl_storage; uintptr_t user_data; }; static_assert(std::is_trivial<MultiWaitHolderType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_message_queue_common.hpp> #include <stratosphere/os/os_multiple_wait_api.hpp> #include <stratosphere/os/os_multiple_wait_types.hpp> namespace ams::os { namespace impl { class AutoMultiWaitHolder { private: MultiWaitHolderType m_holder; public: template<typename T> ALWAYS_INLINE explicit AutoMultiWaitHolder(MultiWaitType *multi_wait, T &&arg) { InitializeMultiWaitHolder(std::addressof(m_holder), std::forward<T>(arg)); LinkMultiWaitHolder(multi_wait, std::addressof(m_holder)); } ALWAYS_INLINE ~AutoMultiWaitHolder() { UnlinkMultiWaitHolder(std::addressof(m_holder)); FinalizeMultiWaitHolder(std::addressof(m_holder)); } ALWAYS_INLINE std::pair<MultiWaitHolderType *, int> ConvertResult(const std::pair<MultiWaitHolderType *, int> result, int index) { if (result.first == std::addressof(m_holder)) { return std::make_pair(static_cast<MultiWaitHolderType *>(nullptr), index); } else { return result; } } }; template<typename F> inline std::pair<MultiWaitHolderType *, int> WaitAnyImpl(F &&func, MultiWaitType *multi_wait, int) { return std::pair<MultiWaitHolderType *, int>(func(multi_wait), -1); } template<typename F, typename T, typename... Args> inline std::pair<MultiWaitHolderType *, int> WaitAnyImpl(F &&func, MultiWaitType *multi_wait, int index, T &&x, Args &&... args) { AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x)); return holder.ConvertResult(WaitAnyImpl(std::forward<F>(func), multi_wait, index + 1, std::forward<Args>(args)...), index); } template<typename F, typename... Args> inline std::pair<MultiWaitHolderType *, int> WaitAnyImpl(F &&func, MultiWaitType *multi_wait, Args &&... args) { return WaitAnyImpl(std::forward<F>(func), multi_wait, 0, std::forward<Args>(args)...); } class TempMultiWait { private: MultiWaitType m_multi_wait; public: ALWAYS_INLINE TempMultiWait() { os::InitializeMultiWait(std::addressof(m_multi_wait)); } ALWAYS_INLINE ~TempMultiWait() { os::FinalizeMultiWait(std::addressof(m_multi_wait)); } MultiWaitType *Get() { return std::addressof(m_multi_wait); } }; template<typename F, typename... Args> inline std::pair<MultiWaitHolderType *, int> WaitAnyImpl(F &&func, Args &&... args) { TempMultiWait temp_multi_wait; return WaitAnyImpl(std::forward<F>(func), temp_multi_wait.Get(), 0, std::forward<Args>(args)...); } using WaitAnyFunction = MultiWaitHolderType * (*)(MultiWaitType *); class NotBoolButInt { private: int m_value; public: constexpr ALWAYS_INLINE NotBoolButInt(int v) : m_value(v) { /* ... */ } constexpr ALWAYS_INLINE operator int() const { return m_value; } explicit operator bool() const = delete; }; } template<typename... Args> requires (sizeof...(Args) > 0) inline std::pair<MultiWaitHolderType *, int> WaitAny(MultiWaitType *multi_wait, Args &&... args) { return impl::WaitAnyImpl(static_cast<impl::WaitAnyFunction>(&::ams::os::WaitAny), multi_wait, std::forward<Args>(args)...); } template<typename... Args> requires (sizeof...(Args) > 0) inline int WaitAny(Args &&... args) { return impl::WaitAnyImpl(static_cast<impl::WaitAnyFunction>(&::ams::os::WaitAny), std::forward<Args>(args)...).second; } template<typename... Args> requires (sizeof...(Args) > 0) inline std::pair<MultiWaitHolderType *, int> TryWaitAny(MultiWaitType *multi_wait, Args &&... args) { return impl::WaitAnyImpl(static_cast<impl::WaitAnyFunction>(&::ams::os::TryWaitAny), multi_wait, std::forward<Args>(args)...); } template<typename... Args> requires (sizeof...(Args) > 0) inline impl::NotBoolButInt TryWaitAny(Args &&... args) { return impl::WaitAnyImpl(static_cast<impl::WaitAnyFunction>(&::ams::os::TryWaitAny), std::forward<Args>(args)...).second; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_mutex_common.hpp> #include <stratosphere/os/os_mutex_types.hpp> #include <stratosphere/os/os_mutex_api.hpp> namespace ams::os { class Mutex { NON_COPYABLE(Mutex); NON_MOVEABLE(Mutex); private: MutexType m_mutex; public: constexpr explicit Mutex(bool recursive) : m_mutex{::ams::os::MutexType::State_Initialized, recursive, 0, 0, nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER } } { /* ... */ } ~Mutex() { FinalizeMutex(std::addressof(m_mutex)); } void lock() { return LockMutex(std::addressof(m_mutex)); } void unlock() { return UnlockMutex(std::addressof(m_mutex)); } bool try_lock() { return TryLockMutex(std::addressof(m_mutex)); } bool IsLockedByCurrentThread() const { return IsMutexLockedByCurrentThread(std::addressof(m_mutex)); } ALWAYS_INLINE void Lock() { return this->lock(); } ALWAYS_INLINE void Unlock() { return this->unlock(); } ALWAYS_INLINE bool TryLock() { return this->try_lock(); } operator MutexType &() { return m_mutex; } operator const MutexType &() const { return m_mutex; } MutexType *GetBase() { return std::addressof(m_mutex); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_mutex_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_mutex_common.hpp> namespace ams::os { struct MutexType; void InitializeMutex(MutexType *mutex, bool recursive, int lock_level); void FinalizeMutex(MutexType *mutex); void LockMutex(MutexType *mutex); bool TryLockMutex(MutexType *mutex); void UnlockMutex(MutexType *mutex); bool IsMutexLockedByCurrentThread(const MutexType *mutex); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_mutex_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { constexpr inline s32 MutexLockLevelMin = 1; constexpr inline s32 MutexLockLevelMax = BITSIZEOF(s32) - 1; constexpr inline s32 MutexLockLevelInitial = 0; constexpr inline s32 MutexRecursiveLockCountMax = (1 << BITSIZEOF(u16)) - 1; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_mutex_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os { struct ThreadType; struct MutexType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; u8 state; bool is_recursive; s32 lock_level; s32 nest_count; ThreadType *owner_thread; union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial<MutexType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_native_handle.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_native_handle_types.hpp> #include <stratosphere/os/os_native_handle_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_native_handle_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_native_handle_types.hpp> namespace ams::os { void CloseNativeHandle(NativeHandle handle); NativeHandle GetCurrentProcessHandle(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_native_handle_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { #if defined(ATMOSPHERE_OS_HORIZON) using NativeHandle = svc::Handle; static_assert(std::unsigned_integral<NativeHandle>); constexpr inline NativeHandle InvalidNativeHandle = svc::InvalidHandle; #elif defined(ATMOSPHERE_OS_WINDOWS) using NativeHandle = void *; constexpr inline NativeHandle InvalidNativeHandle = nullptr; #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) using NativeHandle = s32; constexpr inline NativeHandle InvalidNativeHandle = -1; #else #error "Unknown OS for os::NativeHandle" #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_process_code_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { struct ProcessMemoryRegion { u64 address; u64 size; }; Result MapProcessCodeMemory(u64 *out, NativeHandle handle, const ProcessMemoryRegion *regions, size_t num_regions, AddressSpaceGenerateRandomFunction generate_random); Result UnmapProcessCodeMemory(NativeHandle handle, u64 process_code_address, const ProcessMemoryRegion *regions, size_t num_regions); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_process_handle_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/ncm/ncm_program_id.hpp> namespace ams::os { Result GetProcessId(os::ProcessId *out, NativeHandle handle); ALWAYS_INLINE ProcessId GetProcessId(NativeHandle handle) { ProcessId process_id; R_ABORT_UNLESS(GetProcessId(std::addressof(process_id), handle)); return process_id; } ALWAYS_INLINE ProcessId GetCurrentProcessId() { return GetProcessId(GetCurrentProcessHandle()); } Result GetProgramId(ncm::ProgramId *out, NativeHandle handle); ALWAYS_INLINE ncm::ProgramId GetProgramId(NativeHandle handle) { ncm::ProgramId program_id; R_ABORT_UNLESS(GetProgramId(std::addressof(program_id), handle)); return program_id; } ALWAYS_INLINE ncm::ProgramId GetCurrentProgramId() { return GetProgramId(GetCurrentProcessHandle()); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_process_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { Result MapProcessMemory(void **out, NativeHandle handle, u64 process_address, size_t process_size, AddressSpaceGenerateRandomFunction generate_random); void UnmapProcessMemory(void *mapped_memory, NativeHandle handle, u64 process_address, size_t process_size); Result SetProcessMemoryPermission(NativeHandle handle, u64 process_address, u64 process_size, MemoryPermission perm); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_random.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> namespace ams::os { void GenerateRandomBytes(void *dst, size_t size); /* Convenience API. */ u32 GenerateRandomU32(u32 max = std::numeric_limits<u32>::max()); u64 GenerateRandomU64(u64 max = std::numeric_limits<u64>::max()); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_rw_busy_mutex_types.hpp> #include <stratosphere/os/os_rw_busy_mutex_api.hpp> namespace ams::os { class ReaderWriterBusyMutex { NON_COPYABLE(ReaderWriterBusyMutex); NON_MOVEABLE(ReaderWriterBusyMutex); private: ReaderWriterBusyMutexType m_rw_mutex; public: constexpr explicit ReaderWriterBusyMutex() : m_rw_mutex{ { AMS_OS_INTERNAL_READER_WRITER_BUSY_MUTEX_IMPL_CONSTANT_INITIALIZER } } { /* ... */ } void AcquireReadLock() { return os::AcquireReadLockBusyMutex(std::addressof(m_rw_mutex)); } void ReleaseReadLock() { return os::ReleaseReadLockBusyMutex(std::addressof(m_rw_mutex)); } void AcquireWriteLock() { return os::AcquireWriteLockBusyMutex(std::addressof(m_rw_mutex)); } void ReleaseWriteLock() { return os::ReleaseWriteLockBusyMutex(std::addressof(m_rw_mutex)); } void lock_shared() { return this->AcquireReadLock(); } void unlock_shared() { return this->ReleaseReadLock(); } void lock() { return this->AcquireWriteLock(); } void unlock() { return this->ReleaseWriteLock(); } operator ReaderWriterBusyMutexType &() { return m_rw_mutex; } operator const ReaderWriterBusyMutexType &() const { return m_rw_mutex; } ReaderWriterBusyMutexType *GetBase() { return std::addressof(m_rw_mutex); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct ReaderWriterBusyMutexType; void InitalizeReaderWriterLockBusyMutex(ReaderWriterBusyMutexType *rw_mutex); void AcquireReadLockBusyMutex(ReaderWriterBusyMutexType *rw_mutex); void ReleaseReadLockBusyMutex(ReaderWriterBusyMutexType *rw_mutex); void AcquireWriteLockBusyMutex(ReaderWriterBusyMutexType *rw_mutex); void ReleaseWriteLockBusyMutex(ReaderWriterBusyMutexType *rw_mutex); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_busy_mutex_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_rw_busy_mutex.hpp> namespace ams::os { struct ReaderWriterBusyMutexType { union { s32 _arr[sizeof(impl::InternalReaderWriterBusyMutexStorage) / sizeof(s32)]; impl::InternalReaderWriterBusyMutexStorage _storage; }; }; static_assert(std::is_trivial<ReaderWriterBusyMutexType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_lock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_rw_lock_common.hpp> #include <stratosphere/os/os_rw_lock_types.hpp> #include <stratosphere/os/os_rw_lock_api.hpp> namespace ams::os { class ReaderWriterLock { NON_COPYABLE(ReaderWriterLock); NON_MOVEABLE(ReaderWriterLock); private: ReaderWriterLockType m_rw_lock; public: constexpr explicit ReaderWriterLock() : m_rw_lock {{ { MakeConstantInitializedLockCount(), 0 } }, 0, ::ams::os::ReaderWriterLockType::State_Initialized, nullptr, 0, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}, {AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER} } { /* ... */ } constexpr ~ReaderWriterLock() { if (!std::is_constant_evaluated()) { os::FinalizeReaderWriterLock(std::addressof(m_rw_lock)); } } void AcquireReadLock() { return os::AcquireReadLock(std::addressof(m_rw_lock)); } bool TryAcquireReadLock() { return os::TryAcquireReadLock(std::addressof(m_rw_lock)); } void ReleaseReadLock() { return os::ReleaseReadLock(std::addressof(m_rw_lock)); } void AcquireWriteLock() { return os::AcquireWriteLock(std::addressof(m_rw_lock)); } bool TryAcquireWriteLock() { return os::TryAcquireWriteLock(std::addressof(m_rw_lock)); } void ReleaseWriteLock() { return os::ReleaseWriteLock(std::addressof(m_rw_lock)); } bool IsReadLockHeld() const { return os::IsReadLockHeld(std::addressof(m_rw_lock)); } bool IsWriteLockHeldByCurrentThread() const { return os::IsWriteLockHeldByCurrentThread(std::addressof(m_rw_lock)); } bool IsLockOwner() const { return os::IsReaderWriterLockOwnerThread(std::addressof(m_rw_lock)); } void lock_shared() { return this->AcquireReadLock(); } bool try_lock_shared() { return this->TryAcquireReadLock(); } void unlock_shared() { return this->ReleaseReadLock(); } void lock() { return this->AcquireWriteLock(); } bool try_lock() { return this->TryAcquireWriteLock(); } void unlock() { return this->ReleaseWriteLock(); } operator ReaderWriterLockType &() { return m_rw_lock; } operator const ReaderWriterLockType &() const { return m_rw_lock; } ReaderWriterLockType *GetBase() { return std::addressof(m_rw_lock); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_lock_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_rw_lock_common.hpp> namespace ams::os { struct ReaderWriterLockType; void InitializeReaderWriterLock(ReaderWriterLockType *rw_lock); void FinalizeReaderWriterLock(ReaderWriterLockType *rw_lock); void AcquireReadLock(ReaderWriterLockType *rw_lock); bool TryAcquireReadLock(ReaderWriterLockType *rw_lock); void ReleaseReadLock(ReaderWriterLockType *rw_lock); void AcquireWriteLock(ReaderWriterLockType *rw_lock); bool TryAcquireWriteLock(ReaderWriterLockType *rw_lock); void ReleaseWriteLock(ReaderWriterLockType *rw_lock); bool IsReadLockHeld(const ReaderWriterLockType *rw_lock); bool IsWriteLockHeldByCurrentThread(const ReaderWriterLockType *rw_lock); bool IsReaderWriterLockOwnerThread(const ReaderWriterLockType *rw_lock); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_lock_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { constexpr inline s32 ReaderWriterLockCountMax = (1 << (BITSIZEOF(u16) - 1)) - 1; constexpr inline s32 ReaderWriterLockWaiterCountMax = (1 << BITSIZEOF(u8)) - 1; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_rw_lock_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { struct ThreadType; struct ReaderWriterLockType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; struct LockCount { union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage cs_storage; impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; util::BitPack32 counter; }; static_assert(util::is_pod<LockCount>::value); static_assert(std::is_trivial<LockCount>::value); union { struct { LockCount c; u32 write_lock_count; } aligned; struct { u32 write_lock_count; LockCount c; } not_aligned; } lock_count; u32 reserved_1; u8 state; ThreadType *owner_thread; u32 reserved_2; union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; } cv_read_lock; union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; } cv_write_lock; }; static_assert(std::is_trivial<ReaderWriterLockType>::value); #if defined(ATMOSPHERE_OS_HORIZON) consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() { return {}; } #elif defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) /* If windows/linux, require that the lock counter have guaranteed alignment, so that we may constant-initialize. */ static_assert(alignof(ReaderWriterLockType) == sizeof(u64)); consteval ReaderWriterLockType::LockCount MakeConstantInitializedLockCount() { return ReaderWriterLockType::LockCount { { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, {}, }; } #else #error "Unknown OS for constant initialized RW-lock LockCount" #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_condition_variable.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_sdk_mutex.hpp> #include <stratosphere/os/os_sdk_recursive_mutex.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { struct SdkConditionVariableType { union { s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)]; impl::InternalConditionVariableStorage _storage; impl::InternalConditionVariableStorageTypeForConstantInitialize _storage_for_constant_initialize; }; ALWAYS_INLINE void Initialize() { GetReference(this->_storage).Initialize(); } void Wait(SdkMutexType &mutex); bool TimedWait(SdkMutexType &mutex, TimeSpan timeout); void Wait(SdkRecursiveMutexType &mutex); bool TimedWait(SdkRecursiveMutexType &mutex, TimeSpan timeout); ALWAYS_INLINE void Signal() { GetReference(this->_storage).Signal(); } ALWAYS_INLINE void Broadcast() { GetReference(this->_storage).Broadcast(); } }; static_assert(std::is_trivial<SdkConditionVariableType>::value); class SdkConditionVariable { private: SdkConditionVariableType m_cv; public: constexpr SdkConditionVariable() : m_cv{{AMS_OS_INTERNAL_CONDITION_VARIABLE_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } ALWAYS_INLINE void Wait(SdkMutex &m) { return m_cv.Wait(m.m_mutex); } ALWAYS_INLINE bool TimedWait(SdkMutex &m, TimeSpan timeout) { return m_cv.TimedWait(m.m_mutex, timeout); } ALWAYS_INLINE void Wait(SdkRecursiveMutex &m) { return m_cv.Wait(m.m_mutex); } ALWAYS_INLINE bool TimedWait(SdkRecursiveMutex &m, TimeSpan timeout) { return m_cv.TimedWait(m.m_mutex, timeout); } ALWAYS_INLINE void Signal() { return m_cv.Signal(); } ALWAYS_INLINE void Broadcast() { return m_cv.Broadcast(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os { class SdkConditionVariable; struct ThreadType; struct SdkMutexType { #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) os::ThreadType *owner_thread; #endif union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; }; static_assert(std::is_trivial<SdkMutexType>::value); void InitializeSdkMutex(SdkMutexType *mutex); void LockSdkMutex(SdkMutexType *mutex); bool TryLockSdkMutex(SdkMutexType *mutex); void UnlockSdkMutex(SdkMutexType *mutex); bool IsSdkMutexLockedByCurrentThread(const SdkMutexType *mutex); class SdkMutex { private: friend class SdkConditionVariable; private: SdkMutexType m_mutex; public: #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) constexpr SdkMutex() : m_mutex{{AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } #else constexpr SdkMutex() : m_mutex{nullptr, {AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER}} { /* ... */ } #endif ALWAYS_INLINE void Lock() { return os::LockSdkMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool TryLock() { return os::TryLockSdkMutex(std::addressof(m_mutex)); } ALWAYS_INLINE void Unlock() { return os::UnlockSdkMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool IsLockedByCurrentThread() const { return os::IsSdkMutexLockedByCurrentThread(std::addressof(m_mutex)); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_recursive_mutex.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> namespace ams::os { class SdkConditionVariable; struct SdkRecursiveMutexType { #if !defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) os::ThreadType *owner_thread; #endif union { s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; impl::InternalCriticalSectionStorage _storage; impl::InternalCriticalSectionStorageTypeForConstantInitialize _storage_for_constant_initialize; }; u32 recursive_count; }; static_assert(std::is_trivial<SdkRecursiveMutexType>::value); void InitializeSdkRecursiveMutex(SdkRecursiveMutexType *rmutex); void LockSdkRecursiveMutex(SdkRecursiveMutexType *rmutex); bool TryLockSdkRecursiveMutex(SdkRecursiveMutexType *rmutex); void UnlockSdkRecursiveMutex(SdkRecursiveMutexType *rmutex); bool IsSdkRecursiveMutexLockedByCurrentThread(const SdkRecursiveMutexType *rmutex); class SdkRecursiveMutex { private: friend class SdkConditionVariable; private: SdkRecursiveMutexType m_mutex; public: #if defined(AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CAN_CHECK_LOCKED_BY_CURRENT_THREAD) constexpr SdkRecursiveMutex() : m_mutex{ { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ } #else constexpr SdkRecursiveMutex() : m_mutex{ nullptr, { AMS_OS_INTERNAL_CRITICAL_SECTION_IMPL_CONSTANT_INITIALIZER }, 0 } { /* ... */ } #endif ALWAYS_INLINE void Lock() { return os::LockSdkRecursiveMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool TryLock() { return os::TryLockSdkRecursiveMutex(std::addressof(m_mutex)); } ALWAYS_INLINE void Unlock() { return os::UnlockSdkRecursiveMutex(std::addressof(m_mutex)); } ALWAYS_INLINE bool IsLockedByCurrentThread() const { return os::IsSdkRecursiveMutexLockedByCurrentThread(std::addressof(m_mutex)); } ALWAYS_INLINE void lock() { return this->Lock(); } ALWAYS_INLINE bool try_lock() { return this->TryLock(); } ALWAYS_INLINE void unlock() { return this->Unlock(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_reply_and_receive.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct MultiWaitHolderType; struct MultiWaitType; Result SdkReplyAndReceive(os::MultiWaitHolderType **out, NativeHandle reply_target, MultiWaitType *multi_wait); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_thread_types.hpp> #include <stratosphere/os/os_sdk_thread_types.hpp> #include <stratosphere/os/os_thread_local_storage_common.hpp> namespace ams::os { ALWAYS_INLINE SdkInternalTlsType *GetSdkInternalTlsArray(ThreadType *thread = os::GetCurrentThread()) { #if defined(ATMOSPHERE_OS_HORIZON) return std::addressof(thread->sdk_internal_tls); #else return reinterpret_cast<SdkInternalTlsType *>(std::addressof(thread->tls_value_array[TlsSlotCountMax])); #endif } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_sdk_thread_info_types.hpp> #include <stratosphere/os/os_sdk_thread_info_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_sdk_thread_info_types.hpp> #include <stratosphere/os/os_thread_types.hpp> namespace ams::os { void GetThreadStackInfo(uintptr_t *out_stack_top, size_t *out_stack_size, const ThreadType *thread); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> namespace ams::os { enum SdkLastThreadInfoFlag : u32 { SdkLastThreadInfoFlag_ThreadInSystemCall = (1u << 0), }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_local_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_thread_local_storage.hpp> #include <stratosphere/os/os_sdk_thread_local_storage_api.hpp> namespace ams::os { class SdkThreadLocalStorage { NON_COPYABLE(SdkThreadLocalStorage); NON_MOVEABLE(SdkThreadLocalStorage); private: TlsSlot m_tls_slot; public: SdkThreadLocalStorage() { R_ABORT_UNLESS(os::SdkAllocateTlsSlot(std::addressof(m_tls_slot), nullptr)); } explicit SdkThreadLocalStorage(TlsDestructor destructor) { R_ABORT_UNLESS(os::SdkAllocateTlsSlot(std::addressof(m_tls_slot), destructor)); } ~SdkThreadLocalStorage() { os::FreeTlsSlot(m_tls_slot); } uintptr_t GetValue() const { return os::GetTlsValue(m_tls_slot); } void SetValue(uintptr_t value) { return os::SetTlsValue(m_tls_slot, value); } TlsSlot GetTlsSlot() const { return m_tls_slot; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_local_storage_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> #include <stratosphere/os/os_thread_local_storage_common.hpp> namespace ams::os { Result SdkAllocateTlsSlot(TlsSlot *out, TlsDestructor destructor); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_thread_local_storage_common.hpp> namespace ams::os { struct SdkInternalTlsType { uintptr_t sf_inline_context; }; static_assert(util::is_pod<SdkInternalTlsType>::value); static_assert((sizeof(SdkInternalTlsType) % sizeof(uintptr_t)) == 0); constexpr inline size_t SdkInternalTlsCount = sizeof(SdkInternalTlsType) / sizeof(uintptr_t); static_assert(SdkInternalTlsCount <= SdkTlsSlotCountMax); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_semaphore.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_semaphore_types.hpp> #include <stratosphere/os/os_semaphore_api.hpp> namespace ams::os { class Semaphore { NON_COPYABLE(Semaphore); NON_MOVEABLE(Semaphore); private: SemaphoreType m_sema; public: explicit Semaphore(s32 count, s32 max_count) { InitializeSemaphore(std::addressof(m_sema), count, max_count); } ~Semaphore() { FinalizeSemaphore(std::addressof(m_sema)); } void Acquire() { return os::AcquireSemaphore(std::addressof(m_sema)); } bool TryAcquire() { return os::TryAcquireSemaphore(std::addressof(m_sema)); } bool TimedAcquire(TimeSpan timeout) { return os::TimedAcquireSemaphore(std::addressof(m_sema), timeout); } void Release() { return os::ReleaseSemaphore(std::addressof(m_sema)); } void Release(s32 count) { return os::ReleaseSemaphore(std::addressof(m_sema), count); } s32 GetCurrentCount() const { return os::GetCurrentSemaphoreCount(std::addressof(m_sema)); } operator SemaphoreType &() { return m_sema; } operator const SemaphoreType &() const { return m_sema; } SemaphoreType *GetBase() { return std::addressof(m_sema); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_semaphore_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { struct SemaphoreType; struct MultiWaitHolderType; void InitializeSemaphore(SemaphoreType *sema, s32 count, s32 max_count); void FinalizeSemaphore(SemaphoreType *sema); void AcquireSemaphore(SemaphoreType *sema); bool TryAcquireSemaphore(SemaphoreType *sema); bool TimedAcquireSemaphore(SemaphoreType *sema, TimeSpan timeout); void ReleaseSemaphore(SemaphoreType *sema); void ReleaseSemaphore(SemaphoreType *sema, s32 count); s32 GetCurrentSemaphoreCount(const SemaphoreType *sema); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SemaphoreType *sema); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_semaphore_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; } struct SemaphoreType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist; u8 state; s32 count; s32 max_count; impl::InternalCriticalSectionStorage cs_sema; impl::InternalConditionVariableStorage cv_not_zero; }; static_assert(std::is_trivial<SemaphoreType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_shared_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_shared_memory_types.hpp> #include <stratosphere/os/os_shared_memory_api.hpp> namespace ams::os { class SharedMemory { NON_COPYABLE(SharedMemory); NON_MOVEABLE(SharedMemory); private: SharedMemoryType m_shared_memory; public: constexpr SharedMemory() : m_shared_memory{ .state = SharedMemoryType::State_NotInitialized } { /* ... */ } SharedMemory(size_t size, MemoryPermission my_perm, MemoryPermission other_perm) { R_ABORT_UNLESS(CreateSharedMemory(std::addressof(m_shared_memory), size, my_perm, other_perm)); } SharedMemory(size_t size, NativeHandle handle, bool managed) { this->Attach(size, handle, managed); } ~SharedMemory() { if (m_shared_memory.state == SharedMemoryType::State_NotInitialized) { return; } DestroySharedMemory(std::addressof(m_shared_memory)); } void Attach(size_t size, NativeHandle handle, bool managed) { return AttachSharedMemory(std::addressof(m_shared_memory), size, handle, managed); } void *Map(MemoryPermission perm) { return MapSharedMemory(std::addressof(m_shared_memory), perm); } void Unmap() { return UnmapSharedMemory(std::addressof(m_shared_memory)); } void *GetMappedAddress() const { return GetSharedMemoryAddress(std::addressof(m_shared_memory)); } size_t GetSize() const { return GetSharedMemorySize(std::addressof(m_shared_memory)); } NativeHandle GetHandle() const { return GetSharedMemoryHandle(std::addressof(m_shared_memory)); } operator SharedMemoryType &() { return m_shared_memory; } operator const SharedMemoryType &() const { return m_shared_memory; } SharedMemoryType *GetBase() { return std::addressof(m_shared_memory); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_shared_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_memory_permission.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct SharedMemoryType; Result CreateSharedMemory(SharedMemoryType *shared_memory, size_t size, MemoryPermission my_perm, MemoryPermission other_perm); void AttachSharedMemory(SharedMemoryType *shared_memory, size_t size, NativeHandle handle, bool managed); void DestroySharedMemory(SharedMemoryType *shared_memory); void *MapSharedMemory(SharedMemoryType *shared_memory, MemoryPermission perm); void UnmapSharedMemory(SharedMemoryType *shared_memory); void *GetSharedMemoryAddress(const SharedMemoryType *shared_memory); size_t GetSharedMemorySize(const SharedMemoryType *shared_memory); NativeHandle GetSharedMemoryHandle(const SharedMemoryType *shared_memory); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_shared_memory_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct SharedMemoryType { enum State { State_NotInitialized = 0, State_Initialized = 1, State_Mapped = 2, }; u8 state; bool handle_managed; bool allocated; void *address; size_t size; NativeHandle handle; mutable impl::InternalCriticalSectionStorage cs_shared_memory; }; static_assert(std::is_trivial<SharedMemoryType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_system_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/os_system_event_types.hpp> #include <stratosphere/os/os_system_event_api.hpp> namespace ams::os { class SystemEvent { NON_COPYABLE(SystemEvent); NON_MOVEABLE(SystemEvent); private: SystemEventType m_system_event; public: SystemEvent() { m_system_event.state = SystemEventType::State_NotInitialized; } explicit SystemEvent(EventClearMode clear_mode, bool inter_process) { R_ABORT_UNLESS(CreateSystemEvent(std::addressof(m_system_event), clear_mode, inter_process)); } explicit SystemEvent(NativeHandle read_handle, bool manage_read_handle, NativeHandle write_handle, bool manage_write_handle, EventClearMode clear_mode) { AttachSystemEvent(std::addressof(m_system_event), read_handle, manage_read_handle, write_handle, manage_write_handle, clear_mode); } ~SystemEvent() { if (m_system_event.state == SystemEventType::State_NotInitialized) { return; } DestroySystemEvent(std::addressof(m_system_event)); } void Attach(NativeHandle read_handle, bool manage_read_handle, NativeHandle write_handle, bool manage_write_handle, EventClearMode clear_mode) { AMS_ABORT_UNLESS(m_system_event.state == SystemEventType::State_NotInitialized); return AttachSystemEvent(std::addressof(m_system_event), read_handle, manage_read_handle, write_handle, manage_write_handle, clear_mode); } void AttachReadableHandle(NativeHandle read_handle, bool manage_read_handle, EventClearMode clear_mode) { AMS_ABORT_UNLESS(m_system_event.state == SystemEventType::State_NotInitialized); return AttachReadableHandleToSystemEvent(std::addressof(m_system_event), read_handle, manage_read_handle, clear_mode); } void AttachWritableHandle(NativeHandle write_handle, bool manage_write_handle, EventClearMode clear_mode) { AMS_ABORT_UNLESS(m_system_event.state == SystemEventType::State_NotInitialized); return AttachWritableHandleToSystemEvent(std::addressof(m_system_event), write_handle, manage_write_handle, clear_mode); } NativeHandle DetachReadableHandle() { return DetachReadableHandleOfSystemEvent(std::addressof(m_system_event)); } NativeHandle DetachWritableHandle() { return DetachWritableHandleOfSystemEvent(std::addressof(m_system_event)); } void Wait() { return WaitSystemEvent(std::addressof(m_system_event)); } bool TryWait() { return TryWaitSystemEvent(std::addressof(m_system_event)); } bool TimedWait(TimeSpan timeout) { return TimedWaitSystemEvent(std::addressof(m_system_event), timeout); } void Signal() { return SignalSystemEvent(std::addressof(m_system_event)); } void Clear() { return ClearSystemEvent(std::addressof(m_system_event)); } NativeHandle GetReadableHandle() const { return GetReadableHandleOfSystemEvent(std::addressof(m_system_event)); } NativeHandle GetWritableHandle() const { return GetWritableHandleOfSystemEvent(std::addressof(m_system_event)); } operator SystemEventType &() { return m_system_event; } operator const SystemEventType &() const { return m_system_event; } SystemEventType *GetBase() { return std::addressof(m_system_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_system_event_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct SystemEventType; struct MultiWaitHolderType; Result CreateSystemEvent(SystemEventType *event, EventClearMode clear_mode, bool inter_process); void DestroySystemEvent(SystemEventType *event); void AttachSystemEvent(SystemEventType *event, NativeHandle read_handle, bool read_handle_managed, NativeHandle write_handle, bool write_handle_managed, EventClearMode clear_mode); void AttachReadableHandleToSystemEvent(SystemEventType *event, NativeHandle read_handle, bool manage_read_handle, EventClearMode clear_mode); void AttachWritableHandleToSystemEvent(SystemEventType *event, NativeHandle write_handle, bool manage_write_handle, EventClearMode clear_mode); NativeHandle DetachReadableHandleOfSystemEvent(SystemEventType *event); NativeHandle DetachWritableHandleOfSystemEvent(SystemEventType *event); NativeHandle GetReadableHandleOfSystemEvent(const SystemEventType *event); NativeHandle GetWritableHandleOfSystemEvent(const SystemEventType *event); void SignalSystemEvent(SystemEventType *event); void WaitSystemEvent(SystemEventType *event); bool TryWaitSystemEvent(SystemEventType *event); bool TimedWaitSystemEvent(SystemEventType *event, TimeSpan timeout); void ClearSystemEvent(SystemEventType *event); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SystemEventType *event); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_system_event_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_types.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { namespace impl { struct InterProcessEventType { enum State { State_NotInitialized = 0, State_Initialized = 1, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> multi_wait_object_list_storage; bool auto_clear; u8 state; bool is_readable_handle_managed; bool is_writable_handle_managed; NativeHandle readable_handle; NativeHandle writable_handle; }; static_assert(std::is_trivial<InterProcessEventType>::value); } struct SystemEventType { enum State { State_NotInitialized = 0, State_InitializedAsEvent = 1, State_InitializedAsInterProcessEvent = 2, }; union { EventType event; impl::InterProcessEventType inter_process_event; }; u8 state; }; static_assert(std::is_trivial<SystemEventType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_thread_common.hpp> #include <stratosphere/os/os_thread_types.hpp> #include <stratosphere/os/os_thread_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_thread_common.hpp> namespace ams::os { struct ThreadType; struct MultiWaitHolderType; Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority, s32 ideal_core); Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority); void DestroyThread(ThreadType *thread); void StartThread(ThreadType *thread); ThreadType *GetCurrentThread(); void WaitThread(ThreadType *thread); bool TryWaitThread(ThreadType *thread); void YieldThread(); void SleepThread(TimeSpan time); s32 SuspendThread(ThreadType *thread); s32 ResumeThread(ThreadType *thread); s32 GetThreadSuspendCount(const ThreadType *thread); /* TODO: void GetThreadContext(ThreadContextInfo *out_context, const ThreadType *thread); */ s32 ChangeThreadPriority(ThreadType *thread, s32 priority); s32 GetThreadPriority(const ThreadType *thread); s32 GetThreadCurrentPriority(const ThreadType *thread); void SetThreadName(ThreadType *thread, const char *name); void SetThreadNamePointer(ThreadType *thread, const char *name); const char *GetThreadNamePointer(const ThreadType *thread); s32 GetCurrentProcessorNumber(); s32 GetCurrentCoreNumber(); void SetThreadCoreMask(ThreadType *thread, s32 ideal_core, u64 affinity_mask); void GetThreadCoreMask(s32 *out_ideal_core, u64 *out_affinity_mask, const ThreadType *thread); u64 GetThreadAvailableCoreMask(); ThreadId GetThreadId(const ThreadType *thread); void InitializeMultiWaitHolder(MultiWaitHolderType *holder, ThreadType *thread); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { constexpr inline s32 ThreadSuspendCountMax = 127; constexpr inline s32 ThreadNameLengthMax = 0x20; constexpr inline s32 ThreadPriorityRangeSize = 32; constexpr inline s32 HighestThreadPriority = 0; constexpr inline s32 DefaultThreadPriority = ThreadPriorityRangeSize / 2; constexpr inline s32 LowestThreadPriority = ThreadPriorityRangeSize - 1; constexpr inline s32 InvalidThreadPriority = 127; constexpr inline s32 LowestSystemThreadPriority = 35; constexpr inline s32 HighestSystemThreadPriority = -12; constexpr inline size_t StackGuardAlignment = 4_KB; constexpr inline size_t ThreadStackAlignment = 4_KB; using ThreadFunction = void (*)(void *); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_thread_local_storage_common.hpp> #include <stratosphere/os/os_thread_local_storage_api.hpp> namespace ams::os { class ThreadLocalStorage { NON_COPYABLE(ThreadLocalStorage); NON_MOVEABLE(ThreadLocalStorage); private: TlsSlot m_tls_slot; public: ThreadLocalStorage() { R_ABORT_UNLESS(os::AllocateTlsSlot(std::addressof(m_tls_slot), nullptr)); } explicit ThreadLocalStorage(TlsDestructor destructor) { R_ABORT_UNLESS(os::AllocateTlsSlot(std::addressof(m_tls_slot), destructor)); } ~ThreadLocalStorage() { os::FreeTlsSlot(m_tls_slot); } uintptr_t GetValue() const { return os::GetTlsValue(m_tls_slot); } void SetValue(uintptr_t value) { return os::SetTlsValue(m_tls_slot, value); } TlsSlot GetTlsSlot() const { return m_tls_slot; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> #include <stratosphere/os/os_thread_local_storage_common.hpp> namespace ams::os { Result AllocateTlsSlot(TlsSlot *out, TlsDestructor destructor); void FreeTlsSlot(TlsSlot slot); uintptr_t GetTlsValue(TlsSlot slot); void SetTlsValue(TlsSlot slot, uintptr_t value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_local_storage_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { struct TlsSlot { u32 _value; }; using TlsDestructor = void (*)(uintptr_t arg); constexpr inline size_t TlsSlotCountMax = 16; constexpr inline size_t SdkTlsSlotCountMax = 16; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_thread_common.hpp> #include <stratosphere/os/os_thread_local_storage_common.hpp> #include <stratosphere/os/os_thread_local_storage_api.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> #include <stratosphere/os/os_sdk_thread_types.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; } #if !defined(AMS_OS_IMPL_USE_PTHREADS) using ThreadId = u64; #else /* TODO: decide whether using pthread_id_np_t or not more thoroughly. */ #if defined(ATMOSPHERE_OS_MACOS) #define AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID #endif #if defined(AMS_OS_IMPL_USE_PTHREADID_NP_FOR_THREAD_ID) using ThreadId = u64; #else static_assert(sizeof(pthread_t) <= sizeof(u64)); using ThreadId = pthread_t; #endif #endif struct ThreadType { static constexpr u16 Magic = 0xF5A5; enum State { State_NotInitialized = 0, State_Initialized = 1, State_DestroyedBeforeStarted = 2, State_Started = 3, State_Terminated = 4, }; util::TypedStorage<util::IntrusiveListNode> all_threads_node; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist; uintptr_t reserved[4]; u8 state; bool stack_is_aliased; bool auto_registered; u8 suspend_count; u16 magic; s16 base_priority; u16 version; char name_buffer[ThreadNameLengthMax]; const char *name_pointer; ThreadId thread_id; void *original_stack; void *stack; size_t stack_size; ThreadFunction function; void *initial_fiber; void *current_fiber; void *argument; mutable impl::InternalCriticalSectionStorage cs_thread; mutable impl::InternalConditionVariableStorage cv_thread; /* The following members are arch/os specific. */ #if defined(AMS_OS_IMPL_USE_PTHREADS) mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax]; mutable impl::InternalCriticalSectionStorage cs_pthread_exit; mutable impl::InternalConditionVariableStorage cv_pthread_exit; bool exited_pthread; pthread_t pthread; u64 affinity_mask; int ideal_core; #elif defined(ATMOSPHERE_OS_HORIZON) /* NOTE: Here, Nintendo stores the TLS array. This is handled by libnx in our case. */ /* However, we need to access certain values in other threads' TLS (Nintendo uses a hardcoded layout for SDK tls members...) */ /* These members are tls slot holders in sdk code, but just normal thread type members under our scheme. */ SdkInternalTlsType sdk_internal_tls; using ThreadImpl = ::Thread; ThreadImpl *thread_impl; ThreadImpl thread_impl_storage; #elif defined(ATMOSPHERE_OS_WINDOWS) mutable uintptr_t tls_value_array[TlsSlotCountMax + SdkTlsSlotCountMax]; NativeHandle native_handle; int ideal_core; u64 affinity_mask; #endif }; static_assert(std::is_trivial<ThreadType>::value); constexpr inline s32 IdealCoreDontCare = -1; constexpr inline s32 IdealCoreUseDefault = -2; constexpr inline s32 IdealCoreNoUpdate = -3; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_tick.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> namespace ams::os { class Tick; /* Tick API. */ Tick GetSystemTick(); Tick GetSystemTickOrdered(); s64 GetSystemTickFrequency(); TimeSpan ConvertToTimeSpan(Tick tick); Tick ConvertToTick(TimeSpan ts); class Tick { private: s64 m_tick; public: constexpr explicit Tick(s64 t = 0) : m_tick(t) { /* ... */ } Tick(TimeSpan ts) : m_tick(ConvertToTick(ts).GetInt64Value()) { /* ... */ } public: constexpr s64 GetInt64Value() const { return m_tick; } TimeSpan ToTimeSpan() const { return ConvertToTimeSpan(*this); } /* Tick arithmetic. */ constexpr Tick &operator+=(Tick rhs) { m_tick += rhs.m_tick; return *this; } constexpr Tick &operator-=(Tick rhs) { m_tick -= rhs.m_tick; return *this; } constexpr Tick operator+(Tick rhs) const { Tick r(*this); return r += rhs; } constexpr Tick operator-(Tick rhs) const { Tick r(*this); return r -= rhs; } constexpr bool operator==(const Tick &rhs) const { return m_tick == rhs.m_tick; } constexpr bool operator!=(const Tick &rhs) const { return !(*this == rhs); } constexpr bool operator<(const Tick &rhs) const { return m_tick < rhs.m_tick; } constexpr bool operator>=(const Tick &rhs) const { return !(*this < rhs); } constexpr bool operator>(const Tick &rhs) const { return m_tick > rhs.m_tick; } constexpr bool operator<=(const Tick &rhs) const { return !(*this > rhs); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_timer_event.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_timer_event_types.hpp> #include <stratosphere/os/os_timer_event_api.hpp> namespace ams::os { class TimerEvent { NON_COPYABLE(TimerEvent); NON_MOVEABLE(TimerEvent); private: TimerEventType m_event; public: explicit TimerEvent(EventClearMode clear_mode) { InitializeTimerEvent(std::addressof(m_event), clear_mode); } ~TimerEvent() { FinalizeTimerEvent(std::addressof(m_event)); } void StartOneShot(TimeSpan first_time) { return StartOneShotTimerEvent(std::addressof(m_event), first_time); } void StartPeriodic(TimeSpan first_time, TimeSpan interval) { return StartPeriodicTimerEvent(std::addressof(m_event), first_time, interval); } void Stop() { return StopTimerEvent(std::addressof(m_event)); } void Wait() { return WaitTimerEvent(std::addressof(m_event)); } bool TryWait() { return TryWaitTimerEvent(std::addressof(m_event)); } void Signal() { return SignalTimerEvent(std::addressof(m_event)); } void Clear() { return ClearTimerEvent(std::addressof(m_event)); } operator TimerEventType &() { return m_event; } operator const TimerEventType &() const { return m_event; } TimerEventType *GetBase() { return std::addressof(m_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_timer_event_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> namespace ams::os { struct TimerEventType; struct MultiWaitHolderType; void InitializeTimerEvent(TimerEventType *event, EventClearMode clear_mode); void FinalizeTimerEvent(TimerEventType *event); void StartOneShotTimerEvent(TimerEventType *event, TimeSpan first_time); void StartPeriodicTimerEvent(TimerEventType *event, TimeSpan first_time, TimeSpan interval); void StopTimerEvent(TimerEventType *event); void WaitTimerEvent(TimerEventType *event); bool TryWaitTimerEvent(TimerEventType *event); void SignalTimerEvent(TimerEventType *event); void ClearTimerEvent(TimerEventType *event); void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, TimerEventType *event); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_timer_event_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_event_common.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/impl/os_internal_condition_variable.hpp> namespace ams::os { namespace impl { class MultiWaitObjectList; } struct TimerEventType { using TimeSpanStorage = util::TypedStorage<TimeSpan>; enum State { State_NotInitialized = 0, State_Initialized = 1, }; enum TimerState { TimerState_Stop = 0, TimerState_OneShot = 1, TimerState_Periodic = 2, }; util::TypedStorage<impl::MultiWaitObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> multi_wait_object_list_storage; u8 state; u8 clear_mode; bool signaled; u8 timer_state; u32 broadcast_counter_low; u32 broadcast_counter_high; TimeSpanStorage next_time_to_wakeup; TimeSpanStorage first; TimeSpanStorage interval; impl::InternalCriticalSectionStorage cs_timer_event; impl::InternalConditionVariableStorage cv_signaled; }; static_assert(std::is_trivial<TimerEventType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_transfer_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_transfer_memory_types.hpp> #include <stratosphere/os/os_transfer_memory_api.hpp> namespace ams::os { class TransferMemory { NON_COPYABLE(TransferMemory); NON_MOVEABLE(TransferMemory); private: TransferMemoryType m_tmem; public: constexpr TransferMemory() : m_tmem{ .state = TransferMemoryType::State_NotInitialized } { /* ... */ } TransferMemory(void *address, size_t size, MemoryPermission perm) { R_ABORT_UNLESS(CreateTransferMemory(std::addressof(m_tmem), address, size, perm)); } TransferMemory(size_t size, NativeHandle handle, bool managed) { this->Attach(size, handle, managed); } ~TransferMemory() { if (m_tmem.state == TransferMemoryType::State_NotInitialized) { return; } DestroyTransferMemory(std::addressof(m_tmem)); } void Attach(size_t size, NativeHandle handle, bool managed) { AttachTransferMemory(std::addressof(m_tmem), size, handle, managed); } NativeHandle Detach() { return DetachTransferMemory(std::addressof(m_tmem)); } Result Map(void **out, MemoryPermission owner_perm) { R_RETURN(MapTransferMemory(out, std::addressof(m_tmem), owner_perm)); } void Unmap() { UnmapTransferMemory(std::addressof(m_tmem)); } operator TransferMemoryType &() { return m_tmem; } operator const TransferMemoryType &() const { return m_tmem; } TransferMemoryType *GetBase() { return std::addressof(m_tmem); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_transfer_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_memory_permission.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct TransferMemoryType; Result CreateTransferMemory(TransferMemoryType *tmem, void *address, size_t size, MemoryPermission perm); void AttachTransferMemory(TransferMemoryType *tmem, size_t size, NativeHandle handle, bool managed); NativeHandle DetachTransferMemory(TransferMemoryType *tmem); void DestroyTransferMemory(TransferMemoryType *tmem); Result MapTransferMemory(void **out, TransferMemoryType *tmem, MemoryPermission owner_perm); void UnmapTransferMemory(TransferMemoryType *tmem); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_transfer_memory_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/impl/os_internal_critical_section.hpp> #include <stratosphere/os/os_native_handle.hpp> namespace ams::os { struct TransferMemoryType { enum State { State_NotInitialized = 0, State_Created = 1, State_Mapped = 2, State_Detached = 3, }; u8 state; bool handle_managed; bool allocated; void *address; size_t size; NativeHandle handle; mutable impl::InternalCriticalSectionStorage cs_transfer_memory; }; static_assert(std::is_trivial<TransferMemoryType>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_unsafe_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_memory_common.hpp> namespace ams::os { Result AllocateUnsafeMemory(uintptr_t *out_address, size_t size); Result FreeUnsafeMemory(uintptr_t address, size_t size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_virtual_address_memory_common.hpp> #include <stratosphere/os/os_virtual_address_memory_types.hpp> #include <stratosphere/os/os_virtual_address_memory_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_virtual_address_memory_common.hpp> #include <stratosphere/os/os_virtual_address_memory_types.hpp> namespace ams::os { void InitializeVirtualAddressMemory(); Result AllocateAddressRegion(uintptr_t *out, size_t size); Result AllocateMemory(uintptr_t *out, size_t size); Result AllocateMemoryPages(uintptr_t address, size_t size); Result FreeAddressRegion(uintptr_t address); Result FreeMemoryPages(uintptr_t address, size_t size); VirtualAddressMemoryResourceUsage GetVirtualAddressMemoryResourceUsage(); bool IsVirtualAddressMemoryEnabled(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::os { constexpr inline size_t AddressRegionAlignment = 64_KB; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os/os_virtual_address_memory_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_virtual_address_memory_common.hpp> namespace ams::os { struct VirtualAddressMemoryResourceUsage { size_t assigned_size; size_t used_size; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/os.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> #include <stratosphere/os/os_tick.hpp> #include <stratosphere/os/os_memory_common.hpp> #include <stratosphere/os/os_memory_fence.hpp> #include <stratosphere/os/os_memory_permission.hpp> #include <stratosphere/os/os_memory_attribute.hpp> #include <stratosphere/os/os_memory_heap.hpp> #include <stratosphere/os/os_virtual_address_memory.hpp> #include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/os/os_process_handle_api.hpp> #include <stratosphere/os/os_process_memory_api.hpp> #include <stratosphere/os/os_process_code_memory_api.hpp> #include <stratosphere/os/os_insecure_memory_api.hpp> #include <stratosphere/os/os_unsafe_memory_api.hpp> #include <stratosphere/os/os_random.hpp> #include <stratosphere/os/os_mutex.hpp> #include <stratosphere/os/os_condition_variable.hpp> #include <stratosphere/os/os_sdk_mutex.hpp> #include <stratosphere/os/os_sdk_recursive_mutex.hpp> #include <stratosphere/os/os_sdk_condition_variable.hpp> #include <stratosphere/os/os_busy_mutex.hpp> #include <stratosphere/os/os_rw_busy_mutex.hpp> #include <stratosphere/os/os_rw_lock.hpp> #include <stratosphere/os/os_shared_memory.hpp> #include <stratosphere/os/os_transfer_memory.hpp> #include <stratosphere/os/os_semaphore.hpp> #include <stratosphere/os/os_event.hpp> #include <stratosphere/os/os_system_event.hpp> #include <stratosphere/os/os_interrupt_event.hpp> #include <stratosphere/os/os_timer_event.hpp> #include <stratosphere/os/os_thread_local_storage.hpp> #include <stratosphere/os/os_sdk_thread_local_storage.hpp> #include <stratosphere/os/os_sdk_reply_and_receive.hpp> #include <stratosphere/os/os_thread.hpp> #include <stratosphere/os/os_sdk_thread_api.hpp> #include <stratosphere/os/os_sdk_thread_info.hpp> #include <stratosphere/os/os_message_queue.hpp> #include <stratosphere/os/os_light_event.hpp> #include <stratosphere/os/os_light_message_queue.hpp> #include <stratosphere/os/os_light_semaphore.hpp> #include <stratosphere/os/os_barrier.hpp> #include <stratosphere/os/os_io_region.hpp> #include <stratosphere/os/os_multiple_wait.hpp> #include <stratosphere/os/os_argument.hpp> #include <stratosphere/os/os_cache.hpp> #include <stratosphere/os/os_debug.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/osdbg/osdbg_thread_types.hpp> #include <stratosphere/osdbg/osdbg_thread_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/osdbg/osdbg_thread_api_impl.hpp> namespace ams::osdbg { struct ThreadInfo; Result InitializeThreadInfo(ThreadInfo *thread_info, os::NativeHandle debug_handle, const osdbg::DebugInfoCreateProcess *create_process, const osdbg::DebugInfoCreateThread *create_thread); Result UpdateThreadInfo(ThreadInfo *thread_info); Result GetThreadName(char *dst, const ThreadInfo *thread_info); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_api_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/osdbg/osdbg_thread_types.hpp> namespace ams::osdbg { constexpr inline s32 GetThreadPriority(const ThreadInfo *thread_info) { return thread_info->_base_priority; } constexpr inline s32 GetThreadCurrentPriority(const ThreadInfo *thread_info) { return thread_info->_current_priority; } constexpr inline size_t GetThreadStackSize(const ThreadInfo *thread_info) { return thread_info->_stack_size; } constexpr inline uintptr_t GetThreadStackAddress(const ThreadInfo *thread_info) { return thread_info->_stack; } constexpr inline uintptr_t GetThreadFunction(const ThreadInfo *thread_info) { return thread_info->_function; } constexpr inline uintptr_t GetThreadFunctionArgument(const ThreadInfo *thread_info) { return thread_info->_argument; } constexpr inline uintptr_t GetThreadNamePointer(const ThreadInfo *thread_info) { return thread_info->_name_pointer; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/osdbg/osdbg_thread_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::osdbg { namespace impl { union ThreadTypeCommon; } #if defined(ATMOSPHERE_OS_HORIZON) using DebugInfoCreateProcess = svc::DebugInfoCreateProcess; using DebugInfoCreateThread = svc::DebugInfoCreateThread; #else struct DebugInfoCreateProcess{}; struct DebugInfoCreateThread{}; #endif enum ThreadTypeType : u8 { ThreadTypeType_Unknown = 0, ThreadTypeType_Nintendo, ThreadTypeType_Stratosphere, #if defined(ATMOSPHERE_OS_HORIZON) ThreadTypeType_Libnx, #endif }; struct ThreadInfo { s32 _base_priority; s32 _current_priority; size_t _stack_size; uintptr_t _stack; uintptr_t _argument; uintptr_t _function; uintptr_t _name_pointer; impl::ThreadTypeCommon *_thread_type; os::NativeHandle _debug_handle; ThreadTypeType _thread_type_type; #if defined(ATMOSPHERE_OS_HORIZON) osdbg::DebugInfoCreateProcess _debug_info_create_process; osdbg::DebugInfoCreateThread _debug_info_create_thread; #endif }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/osdbg.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/osdbg/osdbg_thread.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/patcher/patcher_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ro/ro_types.hpp> namespace ams::patcher { /* Helper for applying to code binaries. */ void LocateAndApplyIpsPatchesToModule(const char *mount_name, const char *patch_dir, size_t protected_size, size_t offset, const ro::ModuleId *module_id, u8 *mapped_module, size_t mapped_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/patcher.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/patcher/patcher_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/pcv/pcv_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pcv/pcv_types.hpp> namespace ams::pcv { void Initialize(); void Finalize(); Result SetClockEnabled(Module module, bool en); Result SetClockRate(Module module, ClockHz hz); Result SetReset(Module module, bool en); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pcv/pcv_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pcv { using ClockHz = u32; using MicroVolt = s32; using MilliC = s32; /* TODO: Device codes? */ enum Module { Module_Cpu = 0, Module_Gpu = 1, Module_I2s1 = 2, Module_I2s2 = 3, Module_I2s3 = 4, Module_Pwm = 5, Module_I2c1 = 6, Module_I2c2 = 7, Module_I2c3 = 8, Module_I2c4 = 9, Module_I2c5 = 10, Module_I2c6 = 11, Module_Spi1 = 12, Module_Spi2 = 13, Module_Spi3 = 14, Module_Spi4 = 15, Module_Disp1 = 16, Module_Disp2 = 17, Module_Isp = 18, Module_Vi = 19, Module_Sdmmc1 = 20, Module_Sdmmc2 = 21, Module_Sdmmc3 = 22, Module_Sdmmc4 = 23, Module_Owr = 24, Module_Csite = 25, Module_Tsec = 26, Module_Mselect = 27, Module_Hda2codec2x = 28, Module_Actmon = 29, Module_I2cSlow = 30, Module_Sor1 = 31, Module_Sata = 32, Module_Hda = 33, Module_XusbCoreHostSrc = 34, Module_XusbFalconSrc = 35, Module_XusbFsSrc = 36, Module_XusbCoreDevSrc = 37, Module_XusbSsSrc = 38, Module_UartA = 39, Module_UartB = 40, Module_UartC = 41, Module_UartD = 42, Module_Host1x = 43, Module_Entropy = 44, Module_SocTherm = 45, Module_Vic = 46, Module_Nvenc = 47, Module_Nvjpg = 48, Module_Nvdec = 49, Module_Qspi = 50, Module_ViI2c = 51, Module_Tsecb = 52, Module_Ape = 53, Module_AudioDsp = 54, Module_AudioUart = 55, Module_Emc = 56, Module_Plle = 57, Module_PlleHwSeq = 58, Module_Dsi = 59, Module_Maud = 60, Module_Dpaux1 = 61, Module_MipiCal = 62, Module_UartFstMipiCal = 63, Module_Osc = 64, Module_SysBus = 65, Module_SorSafe = 66, Module_XusbSs = 67, Module_XusbHost = 68, Module_XusbDevice = 69, Module_Extperiph1 = 70, Module_Ahub = 71, Module_Hda2hdmicodec = 72, Module_Gpuaux = 73, Module_UsbD = 74, Module_Usb2 = 75, Module_Pcie = 76, Module_Afi = 77, Module_PciExClk = 78, Module_PExUsbPhy = 79, Module_XUsbPadCtl = 80, Module_Apbdma = 81, Module_Usb2TrkClk = 82, Module_XUsbIoPll = 83, Module_XUsbIoPllHwSeq = 84, Module_Cec = 85, Module_Extperiph2 = 86, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pcv.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pcv/pcv_types.hpp> #include <stratosphere/pcv/pcv_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/pgl_event_observer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/sf/pgl_sf_i_event_observer.hpp> #include <stratosphere/pgl/tipc/pgl_tipc_i_event_observer.hpp> namespace ams::pgl { namespace impl { class EventObserverInterface { NON_COPYABLE(EventObserverInterface); NON_MOVEABLE(EventObserverInterface); public: constexpr EventObserverInterface() = default; virtual ~EventObserverInterface() { /* ... */ } virtual Result GetSystemEvent(os::SystemEventType *out) = 0; virtual Result GetProcessEventInfo(pm::ProcessEventInfo *out) = 0; }; class EventObserverByCmif final : public EventObserverInterface { NON_COPYABLE(EventObserverByCmif); NON_MOVEABLE(EventObserverByCmif); private: ams::sf::SharedPointer<pgl::sf::IEventObserver> m_cmif_interface; public: explicit EventObserverByCmif(ams::sf::SharedPointer<pgl::sf::IEventObserver> intf) : m_cmif_interface(intf) { /* ... */ } public: virtual Result GetSystemEvent(os::SystemEventType *out) override { ams::sf::NativeHandle handle; R_TRY(m_cmif_interface->GetProcessEventHandle(std::addressof(handle))); os::AttachReadableHandleToSystemEvent(out, handle.GetOsHandle(), handle.IsManaged(), os::EventClearMode_AutoClear); handle.Detach(); R_SUCCEED(); } virtual Result GetProcessEventInfo(pm::ProcessEventInfo *out) override { R_RETURN(m_cmif_interface->GetProcessEventInfo(out)); } }; template<typename T> requires tipc::IsIEventObserver<T> class EventObserverByTipc final : public EventObserverInterface { NON_COPYABLE(EventObserverByTipc); NON_MOVEABLE(EventObserverByTipc); private: T m_tipc_interface; public: template<typename... Args> explicit EventObserverByTipc(Args &&... args) : m_tipc_interface(std::forward<Args>(args)...) { /* ... */ } public: virtual Result GetSystemEvent(os::SystemEventType *out) override { os::NativeHandle handle; R_TRY(m_tipc_interface.GetProcessEventHandle(std::addressof(handle))); os::AttachReadableHandleToSystemEvent(out, handle, true, os::EventClearMode_AutoClear); R_SUCCEED(); } virtual Result GetProcessEventInfo(pm::ProcessEventInfo *out) override { R_RETURN(m_tipc_interface.GetProcessEventInfo(ams::tipc::Out<pm::ProcessEventInfo>(out))); } }; } class EventObserver { NON_COPYABLE(EventObserver); private: struct Deleter { void operator()(impl::EventObserverInterface *); }; public: using UniquePtr = std::unique_ptr<impl::EventObserverInterface, Deleter>; private: UniquePtr m_impl; public: EventObserver() { /* ... */ } explicit EventObserver(UniquePtr impl) : m_impl(std::move(impl)) { /* ... */ } EventObserver(EventObserver &&rhs) { m_impl = std::move(rhs.m_impl); } EventObserver &operator=(EventObserver &&rhs) { EventObserver(std::move(rhs)).Swap(*this); return *this; } void Swap(EventObserver &rhs) { std::swap(m_impl, rhs.m_impl); } public: Result GetSystemEvent(os::SystemEventType *out) { R_RETURN(m_impl->GetSystemEvent(out)); } Result GetProcessEventInfo(pm::ProcessEventInfo *out) { R_RETURN(m_impl->GetProcessEventInfo(out)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/pgl_shell_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/pgl_event_observer.hpp> namespace ams::pgl { Result Initialize(); void Finalize(); Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 process_flags, u8 pgl_flags); Result TerminateProcess(os::ProcessId process_id); Result LaunchProgramFromHost(os::ProcessId *out, const char *content_path, u32 process_flags); Result GetHostContentMetaInfo(pgl::ContentMetaInfo *out, const char *content_path); Result GetApplicationProcessId(os::ProcessId *out); Result BoostSystemMemoryResourceLimit(u64 size); Result IsProcessTracked(bool *out, os::ProcessId process_id); Result EnableApplicationCrashReport(bool enabled); Result IsApplicationCrashReportEnabled(bool *out); Result EnableApplicationAllThreadDumpOnCrash(bool enabled); Result TriggerApplicationSnapShotDumper(const char *arg, SnapShotDumpType dump_type); Result GetEventObserver(pgl::EventObserver *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/pgl_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/ncm.hpp> namespace ams::pgl { enum LaunchFlags : u8 { LaunchFlags_None = 0, LaunchFlags_EnableDetailedCrashReport = (1 << 0), LaunchFlags_EnableCrashReportScreenShotForProduction = (1 << 1), LaunchFlags_EnableCrashReportScreenShotForDevelop = (1 << 2), }; enum class SnapShotDumpType : u32 { None = 0, Auto = 1, Full = 2, }; /* TODO: Is this really nn::ncm::Content<Something>Info? */ struct ContentMetaInfo { u64 id; u32 version; ncm::ContentType content_type; u8 id_offset; u8 reserved_0E[2]; static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) { return { .id = id, .version = version, .content_type = content_type, .id_offset = id_offset, }; } }; static_assert(sizeof(ContentMetaInfo) == 0x10 && util::is_pod<ContentMetaInfo>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/sf/pgl_sf_i_event_observer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/pgl/pgl_types.hpp> #define AMS_PGL_SF_I_EVENT_OBSERVER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetProcessEventHandle, (ams::sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetProcessEventInfo, (ams::sf::Out<pm::ProcessEventInfo> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::pgl::sf, IEventObserver, AMS_PGL_SF_I_EVENT_OBSERVER_INTERFACE_INFO, 0x00000000); ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/sf/pgl_sf_i_shell_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/sf/pgl_sf_i_event_observer.hpp> #define AMS_PGL_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (ams::sf::Out<os::ProcessId> out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags), (out, loc, pm_flags, pgl_flags)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, LaunchProgramFromHost, (ams::sf::Out<os::ProcessId> out, const ams::sf::InBuffer &content_path, u32 pm_flags), (out, content_path, pm_flags)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetHostContentMetaInfo, (ams::sf::Out<pgl::ContentMetaInfo> out, const ams::sf::InBuffer &content_path), (out, content_path)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetApplicationProcessId, (ams::sf::Out<os::ProcessId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, BoostSystemMemoryResourceLimit, (u64 size), (size)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, IsProcessTracked, (ams::sf::Out<bool> out, os::ProcessId process_id), (out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, EnableApplicationCrashReport, (bool enabled), (enabled)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, IsApplicationCrashReportEnabled, (ams::sf::Out<bool> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, EnableApplicationAllThreadDumpOnCrash, (bool enabled), (enabled)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetProcessId, (ams::sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, TriggerApplicationSnapShotDumper, (pgl::SnapShotDumpType dump_type, const ams::sf::InBuffer &arg), (dump_type, arg)) \ AMS_SF_METHOD_INFO(C, H, 20, Result, GetShellEventObserver, (ams::sf::Out<ams::sf::SharedPointer<pgl::sf::IEventObserver>> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 21, Result, Command21NotImplemented, (ams::sf::Out<u64> out, u32 in, const ams::sf::InBuffer &buf1, const ams::sf::InBuffer &buf2), (out, in, buf1, buf2), hos::Version_11_0_0) AMS_SF_DEFINE_INTERFACE(ams::pgl::sf, IShellInterface, AMS_PGL_I_SHELL_INTERFACE_INTERFACE_INFO, 0x00000000); ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/srv/pgl_srv_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/srv/pgl_srv_shell_interface.hpp> namespace ams::pgl::srv { void InitializeHeap(); void *Allocate(size_t size); void Deallocate(void *p, size_t size); void StartServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/srv/pgl_srv_shell_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/sf/pgl_sf_i_shell_interface.hpp> #include <stratosphere/pgl/tipc/pgl_tipc_i_shell_interface.hpp> namespace ams::pgl::srv { class ShellInterfaceCommon { NON_COPYABLE(ShellInterfaceCommon); NON_MOVEABLE(ShellInterfaceCommon); public: constexpr ShellInterfaceCommon() = default; public: Result LaunchProgramImpl(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags); Result TerminateProcessImpl(os::ProcessId process_id); Result LaunchProgramFromHostImpl(os::ProcessId *out, const void *content_path, size_t content_path_size, u32 pm_flags); Result GetHostContentMetaInfoImpl(pgl::ContentMetaInfo *out, const void *content_path, size_t content_path_size); Result GetApplicationProcessIdImpl(os::ProcessId *out); Result BoostSystemMemoryResourceLimitImpl(u64 size); Result IsProcessTrackedImpl(bool *out, os::ProcessId process_id); Result EnableApplicationCrashReportImpl(bool enabled); Result IsApplicationCrashReportEnabledImpl(bool *out); Result EnableApplicationAllThreadDumpOnCrashImpl(bool enabled); Result GetProcessId(os::ProcessId *out, ncm::ProgramId program_id); Result TriggerApplicationSnapShotDumperImpl(SnapShotDumpType dump_type, const void *arg, size_t arg_size); }; class ShellInterfaceCmif : public ShellInterfaceCommon { NON_COPYABLE(ShellInterfaceCmif); NON_MOVEABLE(ShellInterfaceCmif); private: using Allocator = ams::sf::ExpHeapAllocator; using ObjectFactory = ams::sf::ObjectFactory<ams::sf::ExpHeapAllocator::Policy>; private: Allocator *m_allocator; public: constexpr ShellInterfaceCmif(Allocator *a) : ShellInterfaceCommon(), m_allocator(a) { /* ... */ } public: /* Interface commands. */ Result LaunchProgram(ams::sf::Out<os::ProcessId> out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags); Result TerminateProcess(os::ProcessId process_id); Result LaunchProgramFromHost(ams::sf::Out<os::ProcessId> out, const ams::sf::InBuffer &content_path, u32 pm_flags); Result GetHostContentMetaInfo(ams::sf::Out<pgl::ContentMetaInfo> out, const ams::sf::InBuffer &content_path); Result GetApplicationProcessId(ams::sf::Out<os::ProcessId> out); Result BoostSystemMemoryResourceLimit(u64 size); Result IsProcessTracked(ams::sf::Out<bool> out, os::ProcessId process_id); Result EnableApplicationCrashReport(bool enabled); Result IsApplicationCrashReportEnabled(ams::sf::Out<bool> out); Result EnableApplicationAllThreadDumpOnCrash(bool enabled); Result GetProcessId(ams::sf::Out<os::ProcessId> out, ncm::ProgramId program_id); Result TriggerApplicationSnapShotDumper(SnapShotDumpType dump_type, const ams::sf::InBuffer &arg); Result GetShellEventObserver(ams::sf::Out<ams::sf::SharedPointer<pgl::sf::IEventObserver>> out); Result Command21NotImplemented(ams::sf::Out<u64> out, u32 in, const ams::sf::InBuffer &buf1, const ams::sf::InBuffer &buf2); }; static_assert(pgl::sf::IsIShellInterface<ShellInterfaceCmif>); class ShellInterfaceTipc : public ShellInterfaceCommon { NON_COPYABLE(ShellInterfaceTipc); NON_MOVEABLE(ShellInterfaceTipc); public: constexpr ShellInterfaceTipc() : ShellInterfaceCommon() { /* ... */ } public: /* Interface commands. */ Result LaunchProgram(ams::tipc::Out<os::ProcessId> out, const ncm::ProgramLocation loc, u32 pm_flags, u8 pgl_flags); Result TerminateProcess(os::ProcessId process_id); Result LaunchProgramFromHost(ams::tipc::Out<os::ProcessId> out, const ams::tipc::InBuffer content_path, u32 pm_flags); Result GetHostContentMetaInfo(ams::tipc::Out<pgl::ContentMetaInfo> out, const ams::tipc::InBuffer content_path); Result GetApplicationProcessId(ams::tipc::Out<os::ProcessId> out); Result BoostSystemMemoryResourceLimit(u64 size); Result IsProcessTracked(ams::tipc::Out<bool> out, os::ProcessId process_id); Result EnableApplicationCrashReport(bool enabled); Result IsApplicationCrashReportEnabled(ams::tipc::Out<bool> out); Result EnableApplicationAllThreadDumpOnCrash(bool enabled); Result GetProcessId(ams::tipc::Out<os::ProcessId> out, ncm::ProgramId program_id); Result GetShellEventObserver(ams::tipc::OutMoveHandle out); }; static_assert(pgl::tipc::IsIShellInterface<ShellInterfaceTipc>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/tipc/pgl_tipc_i_event_observer.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/tipc.hpp> #include <stratosphere/pgl/pgl_types.hpp> #define AMS_PGL_TIPC_I_EVENT_OBSERVER_INTERFACE_INFO(C, H) \ AMS_TIPC_METHOD_INFO(C, H, 0, Result, GetProcessEventHandle, (ams::tipc::OutCopyHandle out), (out)) \ AMS_TIPC_METHOD_INFO(C, H, 1, Result, GetProcessEventInfo, (ams::tipc::Out<pm::ProcessEventInfo> out), (out)) AMS_TIPC_DEFINE_INTERFACE(ams::pgl::tipc, IEventObserver, AMS_PGL_TIPC_I_EVENT_OBSERVER_INTERFACE_INFO); ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl/tipc/pgl_tipc_i_shell_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/tipc.hpp> #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/tipc/pgl_tipc_i_event_observer.hpp> #define AMS_PGL_TIPC_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_TIPC_METHOD_INFO(C, H, 0, Result, LaunchProgram, (ams::tipc::Out<os::ProcessId> out, const ncm::ProgramLocation loc, u32 pm_flags, u8 pgl_flags), (out, loc, pm_flags, pgl_flags)) \ AMS_TIPC_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ AMS_TIPC_METHOD_INFO(C, H, 2, Result, LaunchProgramFromHost, (ams::tipc::Out<os::ProcessId> out, const ams::tipc::InBuffer content_path, u32 pm_flags), (out, content_path, pm_flags)) \ AMS_TIPC_METHOD_INFO(C, H, 4, Result, GetHostContentMetaInfo, (ams::tipc::Out<pgl::ContentMetaInfo> out, const ams::tipc::InBuffer content_path), (out, content_path)) \ AMS_TIPC_METHOD_INFO(C, H, 5, Result, GetApplicationProcessId, (ams::tipc::Out<os::ProcessId> out), (out)) \ AMS_TIPC_METHOD_INFO(C, H, 6, Result, BoostSystemMemoryResourceLimit, (u64 size), (size)) \ AMS_TIPC_METHOD_INFO(C, H, 7, Result, IsProcessTracked, (ams::tipc::Out<bool> out, os::ProcessId process_id), (out, process_id)) \ AMS_TIPC_METHOD_INFO(C, H, 8, Result, EnableApplicationCrashReport, (bool enabled), (enabled)) \ AMS_TIPC_METHOD_INFO(C, H, 9, Result, IsApplicationCrashReportEnabled, (ams::tipc::Out<bool> out), (out)) \ AMS_TIPC_METHOD_INFO(C, H, 10, Result, EnableApplicationAllThreadDumpOnCrash, (bool enabled), (enabled)) \ AMS_TIPC_METHOD_INFO(C, H, 20, Result, GetShellEventObserver, (ams::tipc::OutMoveHandle out), (out)) AMS_TIPC_DEFINE_INTERFACE(ams::pgl::tipc, IShellInterface, AMS_PGL_TIPC_I_SHELL_INTERFACE_INTERFACE_INFO); ================================================ FILE: libraries/libstratosphere/include/stratosphere/pgl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pgl/pgl_types.hpp> #include <stratosphere/pgl/pgl_event_observer.hpp> #include <stratosphere/pgl/pgl_shell_api.hpp> #include <stratosphere/pgl/pgl_shell_api.hpp> #include <stratosphere/pgl/srv/pgl_srv_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/pinmux/driver/pinmux_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pinmux::driver { void Initialize(); void Finalize(); void SetInitialConfig(); void SetInitialDrivePadConfig(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pinmux/pinmux_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pinmux { /* ... */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pinmux.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pinmux/pinmux_api.hpp> #include <stratosphere/pinmux/driver/pinmux_driver_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/impl/pm_boot_mode_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/sf.hpp> #define AMS_PM_I_BOOT_MODE_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, void, GetBootMode, (sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, void, SetMaintenanceBoot, (), ()) \ AMS_SF_METHOD_INFO(C, H, 2, void, GetUnknown, (sf::Out<u32> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, SetUnknown, (u32 val), (val)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IBootModeInterface, AMS_PM_I_BOOT_MODE_INTERFACE_INTERFACE_INFO, 0x96D01649) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/impl/pm_debug_monitor_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/sf.hpp> #define AMS_PM_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetExceptionProcessIdList, (sf::Out<u32> out_count, const sf::OutArray<os::ProcessId> &out_process_ids), (out_count, out_process_ids)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, StartProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetProcessId, (sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, HookToCreateProcess, (sf::OutCopyHandle out_hook, ncm::ProgramId program_id), (out_hook, program_id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetApplicationProcessId, (sf::Out<os::ProcessId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, HookToCreateApplicationProcess, (sf::OutCopyHandle out_hook), (out_hook)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, ClearHook, (u32 which), (which), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetProgramId, (sf::Out<ncm::ProgramId> out, os::ProcessId process_id), (out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereGetProcessInfo, (sf::OutCopyHandle out_process_handle, sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status, os::ProcessId process_id), (out_process_handle, out_loc, out_status, process_id)) \ AMS_SF_METHOD_INFO(C, H, 65001, Result, AtmosphereGetCurrentLimitInfo, (sf::Out<s64> out_cur_val, sf::Out<s64> out_lim_val, u32 group, u32 resource), (out_cur_val, out_lim_val, group, resource)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IDebugMonitorInterface, AMS_PM_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO, 0x9391F0EE) #define AMS_PM_I_DEPRECATED_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetModuleIdList, (sf::Out<u32> out_count, const sf::OutBuffer &out_buf, u64 unused), (out_count, out_buf, unused)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetExceptionProcessIdList, (sf::Out<u32> out_count, const sf::OutArray<os::ProcessId> &out_process_ids), (out_count, out_process_ids)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, StartProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetProcessId, (sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, HookToCreateProcess, (sf::OutCopyHandle out_hook, ncm::ProgramId program_id), (out_hook, program_id)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetApplicationProcessId, (sf::Out<os::ProcessId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, HookToCreateApplicationProcess, (sf::OutCopyHandle out_hook), (out_hook)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetProgramId, (sf::Out<ncm::ProgramId> out, os::ProcessId process_id), (out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereGetProcessInfo, (sf::OutCopyHandle out_process_handle, sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status, os::ProcessId process_id), (out_process_handle, out_loc, out_status, process_id)) \ AMS_SF_METHOD_INFO(C, H, 65001, Result, AtmosphereGetCurrentLimitInfo, (sf::Out<s64> out_cur_val, sf::Out<s64> out_lim_val, u32 group, u32 resource), (out_cur_val, out_lim_val, group, resource)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IDeprecatedDebugMonitorInterface, AMS_PM_I_DEPRECATED_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO, 0x9391F0EE) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/impl/pm_information_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/sf.hpp> #define AMS_PM_I_INFORMATION_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetProgramId, (sf::Out<ncm::ProgramId> out, os::ProcessId process_id), (out, process_id)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetAppletResourceLimitCurrentValue, (sf::Out<pm::ResourceLimitValue> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetAppletResourceLimitPeakValue, (sf::Out<pm::ResourceLimitValue> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereGetProcessId, (sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 65001, Result, AtmosphereHasLaunchedBootProgram, (sf::Out<bool> out, ncm::ProgramId program_id), (out, program_id)) \ AMS_SF_METHOD_INFO(C, H, 65002, Result, AtmosphereGetProcessInfo, (sf::Out<ncm::ProgramLocation> out_loc, sf::Out<cfg::OverrideStatus> out_status, os::ProcessId process_id), (out_loc, out_status, process_id)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IInformationInterface, AMS_PM_I_INFORMATION_INTERFACE_INTERFACE_INFO, 0xF205AA1F) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/impl/pm_shell_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/sf.hpp> #define AMS_PM_I_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out<os::ProcessId> out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out<pm::ProcessEventInfo> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, void, NotifyBootFinished, (), ()) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetApplicationProcessIdForShell, (sf::Out<os::ProcessId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, BoostApplicationThreadResourceLimit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 9, void, GetBootFinishedEventHandle, (sf::OutCopyHandle out), (out), hos::Version_8_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, BoostSystemThreadResourceLimit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetProcessId, (sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IShellInterface, AMS_PM_I_SHELL_INTERFACE_INTERFACE_INFO, 0x387D60C0) #define AMS_PM_I_DEPRECATED_SHELL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, LaunchProgram, (sf::Out<os::ProcessId> out_process_id, const ncm::ProgramLocation &loc, u32 flags), (out_process_id, loc, flags)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, TerminateProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, TerminateProgram, (ncm::ProgramId program_id), (program_id)) \ AMS_SF_METHOD_INFO(C, H, 3, void, GetProcessEventHandle, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, void, GetProcessEventInfo, (sf::Out<pm::ProcessEventInfo> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, CleanupProcess, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, ClearExceptionOccurred, (os::ProcessId process_id), (process_id)) \ AMS_SF_METHOD_INFO(C, H, 7, void, NotifyBootFinished, (), ()) \ AMS_SF_METHOD_INFO(C, H, 8, Result, GetApplicationProcessIdForShell, (sf::Out<os::ProcessId> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, BoostSystemMemoryResourceLimit, (u64 boost_size), (boost_size), hos::Version_4_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, BoostSystemThreadResourceLimit, (), ()) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetProcessId, (sf::Out<os::ProcessId> out, ncm::ProgramId program_id), (out, program_id)) AMS_SF_DEFINE_INTERFACE(ams::pm::impl, IDeprecatedShellInterface, AMS_PM_I_DEPRECATED_SHELL_INTERFACE_INTERFACE_INFO, 0x387D60C0) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/pm_boot_mode_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pm/pm_types.hpp> namespace ams::pm::bm { /* Boot Mode API. */ BootMode GetBootMode(); void SetMaintenanceBoot(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/pm_dmnt_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ldr.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/ncm/ncm_program_location.hpp> namespace ams::pm::dmnt { /* Debug Monitor API. */ Result StartProcess(os::ProcessId process_id); Result GetProgramId(ncm::ProgramId *out_program_id, os::ProcessId process_id); Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id); Result GetApplicationProcessId(os::ProcessId *out_process_id); Result HookToCreateApplicationProcess(os::NativeHandle *out_handle); Result HookToCreateProcess(os::NativeHandle *out_handle, const ncm::ProgramId program_id); Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id); #if defined(ATMOSPHERE_OS_HORIZON) Result AtmosphereGetCurrentLimitInfo(u64 *out_current_value, u64 *out_limit_value, ResourceLimitGroup group, svc::LimitableResource resource); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/pm_info_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/ncm/ncm_program_location.hpp> #include <stratosphere/cfg/cfg_types.hpp> namespace ams::pm::info { /* Information API. */ Result GetProgramId(ncm::ProgramId *out_program_id, os::ProcessId process_id); Result GetProcessId(os::ProcessId *out_process_id, ncm::ProgramId program_id); Result HasLaunchedBootProgram(bool *out, ncm::ProgramId program_id); Result GetAppletResourceLimitCurrentValue(pm::ResourceLimitValue *out); Result GetAppletResourceLimitPeakValue(pm::ResourceLimitValue *out); Result GetProcessInfo(ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id); /* Information convenience API. */ bool HasLaunchedBootProgram(ncm::ProgramId program_id); Result IsHblProcessId(bool *out, os::ProcessId process_id); Result IsHblProgramId(bool *out, ncm::ProgramId program_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ldr.hpp> #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/ncm/ncm_program_location.hpp> namespace ams::pm::shell { /* Shell API. */ Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 launch_flags); Result TerminateProcess(os::ProcessId process_id); Result GetProcessEventEvent(os::SystemEvent *out); Result GetProcessEventInfo(ProcessEventInfo *out); Result GetApplicationProcessIdForShell(os::ProcessId *out); Result BoostSystemMemoryResourceLimit(u64 size); Result BoostApplicationThreadResourceLimit(); Result BoostSystemThreadResourceLimit(); Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_common_types.hpp> namespace ams::pm { enum class BootMode { Normal = 0, Maintenance = 1, SafeMode = 2, }; enum ResourceLimitGroup { ResourceLimitGroup_System = 0, ResourceLimitGroup_Application = 1, ResourceLimitGroup_Applet = 2, ResourceLimitGroup_Count, }; enum LaunchFlags : u32 { LaunchFlags_None = 0, LaunchFlags_SignalOnExit = (1 << 0), LaunchFlags_SignalOnStart = (1 << 1), LaunchFlags_SignalOnException = (1 << 2), LaunchFlags_SignalOnDebugEvent = (1 << 3), LaunchFlags_StartSuspended = (1 << 4), LaunchFlags_DisableAslr = (1 << 5), }; enum LaunchFlagsDeprecated : u32 { LaunchFlagsDeprecated_None = 0, LaunchFlagsDeprecated_SignalOnExit = (1 << 0), LaunchFlagsDeprecated_StartSuspended = (1 << 1), LaunchFlagsDeprecated_SignalOnException = (1 << 2), LaunchFlagsDeprecated_DisableAslr = (1 << 3), LaunchFlagsDeprecated_SignalOnDebugEvent = (1 << 4), LaunchFlagsDeprecated_SignalOnStart = (1 << 5), }; struct ResourceLimitValue { u64 physical_memory; u32 thread_count; u32 event_count; u32 transfer_memory_count; u32 session_count; }; constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1; enum class ProcessEvent : u32 { None = 0, Exited = 1, Started = 2, Exception = 3, DebugRunning = 4, DebugBreak = 5, }; enum class ProcessEventDeprecated : u32 { None = 0, Exception = 1, Exited = 2, DebugRunning = 3, DebugBreak = 4, Started = 5, }; inline u32 GetProcessEventValue(ProcessEvent event) { if (hos::GetVersion() >= hos::Version_5_0_0) { return static_cast<u32>(event); } switch (event) { case ProcessEvent::None: return static_cast<u32>(ProcessEventDeprecated::None); case ProcessEvent::Exited: return static_cast<u32>(ProcessEventDeprecated::Exited); case ProcessEvent::Started: return static_cast<u32>(ProcessEventDeprecated::Started); case ProcessEvent::Exception: return static_cast<u32>(ProcessEventDeprecated::Exception); case ProcessEvent::DebugRunning: return static_cast<u32>(ProcessEventDeprecated::DebugRunning); case ProcessEvent::DebugBreak: return static_cast<u32>(ProcessEventDeprecated::DebugBreak); AMS_UNREACHABLE_DEFAULT_CASE(); } } struct ProcessEventInfo { u32 event; os::ProcessId process_id; inline ProcessEvent GetProcessEvent() const { if (hos::GetVersion() >= hos::Version_5_0_0) { return static_cast<ProcessEvent>(this->event); } switch (static_cast<ProcessEventDeprecated>(event)) { case ProcessEventDeprecated::None: return ProcessEvent::None; case ProcessEventDeprecated::Exited: return ProcessEvent::Exited; case ProcessEventDeprecated::Started: return ProcessEvent::Started; case ProcessEventDeprecated::Exception: return ProcessEvent::Exception; case ProcessEventDeprecated::DebugRunning: return ProcessEvent::DebugRunning; case ProcessEventDeprecated::DebugBreak: return ProcessEvent::DebugBreak; AMS_UNREACHABLE_DEFAULT_CASE(); } } }; static_assert(sizeof(ProcessEventInfo) == 0x10 && util::is_pod<ProcessEventInfo>::value, "ProcessEventInfo definition!"); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pm/pm_types.hpp> #include <stratosphere/pm/pm_boot_mode_api.hpp> #include <stratosphere/pm/pm_info_api.hpp> #include <stratosphere/pm/pm_shell_api.hpp> #include <stratosphere/pm/pm_dmnt_api.hpp> #include <stratosphere/pm/impl/pm_boot_mode_interface.hpp> #include <stratosphere/pm/impl/pm_debug_monitor_interface.hpp> #include <stratosphere/pm/impl/pm_information_interface.hpp> #include <stratosphere/pm/impl/pm_shell_interface.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> #include <stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp> namespace ams::powctl::driver::impl { #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) class ChargeArbiter { private: const ChargeParametersRule *m_rules; size_t m_num_rules; int m_charge_voltage_limit; BatteryTemperatureLevel m_temperature_level; int m_avg_v_cell; float m_voltage_fuel_gauge_percentage; bool m_has_battery_done_current; int m_battery_done_current; PowerState m_power_state; const ChargeParametersRule *m_selected_rule; bool m_check_battery_done_current; private: static constexpr bool IsInRange(int value, int min, int max) { if (!(min <= value)) { return false; } if (max == std::numeric_limits<int>::max()) { return value <= max; } else { return value < max; } } static constexpr bool IsInRangeFloat(float value, float min, float max) { if (!(min <= value)) { return false; } if (max == std::numeric_limits<float>::max()) { return value <= max; } else { return value < max; } } bool IsAcceptablePowerState(const PowerState *acceptable, size_t num_acceptable) const { for (size_t i = 0; i < num_acceptable; ++i) { if (m_power_state == acceptable[i]) { return true; } } return false; } public: ChargeArbiter(const ChargeParametersRule *r, size_t nr, int cvl) : m_rules(r), m_num_rules(nr), m_charge_voltage_limit(cvl), m_temperature_level(BatteryTemperatureLevel::Medium), m_avg_v_cell(4080), m_voltage_fuel_gauge_percentage(25.0), m_has_battery_done_current(false), m_battery_done_current(0), m_power_state(PowerState::FullAwake), m_selected_rule(nullptr), m_check_battery_done_current(false) { this->UpdateSelectedRule(); } void SetBatteryTemperatureLevel(BatteryTemperatureLevel btl) { m_temperature_level = btl; this->UpdateSelectedRule(); } void SetBatteryAverageVCell(int avg) { m_avg_v_cell = avg; this->UpdateSelectedRule(); } void SetBatteryVoltageFuelGaugePercentage(float pct) { m_voltage_fuel_gauge_percentage = pct; this->UpdateSelectedRule(); } void SetBatteryDoneCurrent(int current) { m_battery_done_current = current; m_has_battery_done_current = true; this->UpdateSelectedRule(); } void SetPowerState(PowerState ps) { m_power_state = ps; this->UpdateSelectedRule(); } int GetChargeVoltageLimit() const { return m_charge_voltage_limit; } bool IsBatteryDoneCurrentAcceptable(int current) const { const auto *rule = this->GetSelectedRule(); AMS_ASSERT(rule != nullptr); return IsInRange(current, rule->min_battery_done_current, rule->max_battery_done_current); } const ChargeParametersRule *GetSelectedRule() const { return m_selected_rule; } void UpdateSelectedRule() { /* Try to find an entry that fits our current requirements. */ const ChargeParametersRule *best_rule = nullptr; for (size_t i = 0; i < m_num_rules; ++i) { /* Get the current rule. */ const ChargeParametersRule &cur_rule = m_rules[i]; /* Check the temperature level. */ if (m_temperature_level != cur_rule.temperature_level) { continue; } /* Check that average voltage is in range. */ if (!IsInRange(m_avg_v_cell, cur_rule.min_avg_v_cell, cur_rule.max_avg_v_cell)) { continue; } /* Check that voltage fuel gauge percentage is in range. */ if (!IsInRangeFloat(m_voltage_fuel_gauge_percentage, cur_rule.min_voltage_fuel_gauge_percentage, cur_rule.max_voltage_fuel_gauge_percentage)) { continue; } /* Check if our power state is acceptable. */ if (!this->IsAcceptablePowerState(cur_rule.acceptable_power_states, cur_rule.num_acceptable_power_states)) { continue; } /* The limit is probably acceptable. */ if (m_selected_rule != std::addressof(cur_rule)) { /* We're selecting a new rule. Check if our need to deal with battery current is acceptable. */ if (cur_rule.check_battery_current && m_check_battery_done_current) { continue; } /* Determine whether we should check battery done current. */ bool check_battery_done_current; if (m_selected_rule != nullptr && m_selected_rule->check_battery_current) { if (m_selected_rule->temperature_level == m_temperature_level && IsInRange(m_avg_v_cell, m_selected_rule->min_avg_v_cell, m_selected_rule->max_avg_v_cell) && IsInRangeFloat(m_voltage_fuel_gauge_percentage, m_selected_rule->min_voltage_fuel_gauge_percentage, m_selected_rule->max_voltage_fuel_gauge_percentage)) { check_battery_done_current = m_has_battery_done_current && !IsInRange(m_battery_done_current, m_selected_rule->min_battery_done_current, m_selected_rule->max_battery_done_current); } else { check_battery_done_current = true; } } else { check_battery_done_current = false; } /* Set whether we need to check the battery done current. */ m_has_battery_done_current = false; m_check_battery_done_current |= check_battery_done_current; } else { /* We're selecting the currently selected rule. Make sure the battery done current is acceptable if we have one. */ if (m_has_battery_done_current && !IsInRange(m_battery_done_current, cur_rule.min_battery_done_current, cur_rule.max_battery_done_current)) { continue; } } /* Select the current rule. */ best_rule = std::addressof(cur_rule); break; } /* Update our selected rule. */ m_selected_rule = best_rule; } }; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl::driver::impl { struct ChargeParametersRule { BatteryTemperatureLevel temperature_level; int min_avg_v_cell; int max_avg_v_cell; int min_battery_done_current; int max_battery_done_current; float min_unknown_14; float max_unknown_18; float min_voltage_fuel_gauge_percentage; float max_voltage_fuel_gauge_percentage; const PowerState *acceptable_power_states; size_t num_acceptable_power_states; bool check_battery_current; bool reinitialize_charger; int charge_voltage_limit; int fast_charge_current_limit; int battery_compensation; int voltage_clamp; }; struct UnknownParameterX { int _00; int _04; double _08; double _10; }; struct ChargeParameters { int temp_min; int temp_low; int temp_high; int temp_max; int low_voltage_fast_charge_current_limit; int default_charge_voltage_limit; const UnknownParameterX *unknown_x_table; size_t x_table_size; double _28; double _30; const ChargeParametersRule *rules; size_t num_rules; }; const ChargeParameters &GetChargeParameters(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_charger_parameters.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl::driver::impl { struct ChargeParametersRule { /* ... */ }; struct UnknownParameterX { /* ... */ }; struct ChargeParameters { /* ... */ }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.hpp> #else #include <stratosphere/powctl/driver/impl/powctl_charger_parameters.generic.hpp> #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/driver/powctl_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl { void Initialize(bool enable_interrupt_handlers); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl::impl { constexpr inline const double MinRawDefaultPercentage = 3.0; constexpr inline const double MaxRawDefaultPercentage = 99.0; constexpr inline const double MinRawThresholdPercentage = 11.0; constexpr inline const int MinDisplayPercentage = 1; constexpr inline const int MaxDisplayPercentage = 100; constexpr inline void CalculateMarginatedRawPercentage(double *out_marginated_min, double *out_marginated_max, double min, double max) { /* Ensure minimum is in correct range. */ min = std::max(std::min(min, MinRawThresholdPercentage), MinRawDefaultPercentage); /* Calculate the marginated values. */ constexpr const double MinMarginPercentage = 0.93359375; constexpr const double MaxMarginPercentage = -0.83593750; const auto margin_factor = (max - min) / (MaxRawDefaultPercentage - MinRawDefaultPercentage); *out_marginated_min = min + MinMarginPercentage * margin_factor; *out_marginated_max = max + MaxMarginPercentage * margin_factor; } constexpr inline int GetDisplayPercentage(double raw_percentage, double min, double max) { /* Calculate the display percentage. */ constexpr const double BaseDisplayPercentage = 2.0; const auto display_percentage = BaseDisplayPercentage + ((static_cast<double>(MaxDisplayPercentage - BaseDisplayPercentage) * (raw_percentage - min)) / (max - min)); /* Clamp the display percentage within bounds. */ return std::max(std::min(static_cast<int>(display_percentage), MaxDisplayPercentage), MinDisplayPercentage); } constexpr inline int ConvertBatteryChargePercentage(double raw_percentage, double min, double max) { /* Marginate the min/max. */ double marginated_min = 0.0, marginated_max = 0.0; CalculateMarginatedRawPercentage(std::addressof(marginated_min), std::addressof(marginated_max), min, max); /* Convert to display percentage. */ return GetDisplayPercentage(raw_percentage, marginated_min, marginated_max); } constexpr inline int ConvertBatteryChargePercentage(double raw_percentage) { return ConvertBatteryChargePercentage(raw_percentage, MinRawDefaultPercentage, MaxRawDefaultPercentage); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_battery_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> #include <stratosphere/powctl/powctl_session_api.hpp> namespace ams::powctl { /* Battery API. */ Result GetBatteryChargePercentage(float *out_percent, Session &session); Result GetBatteryVoltageFuelGaugePercentage(float *out_percent, Session &session); Result GetBatteryFullCapacity(int *out_mah, Session &session); Result GetBatteryRemainingCapacity(int *out_mah, Session &session); Result SetBatteryChargePercentageMinimumAlertThreshold(Session &session, float percentage); Result SetBatteryChargePercentageMaximumAlertThreshold(Session &session, float percentage); Result SetBatteryVoltageFuelGaugePercentageMinimumAlertThreshold(Session &session, float percentage); Result SetBatteryVoltageFuelGaugePercentageMaximumAlertThreshold(Session &session, float percentage); Result SetBatteryFullChargeThreshold(Session &session, float percentage); Result GetBatteryAverageCurrent(int *out_ma, Session &session); Result GetBatteryCurrent(int *out_ma, Session &session); Result GetBatteryInternalState(void *dst, size_t *out_size, Session &session, size_t dst_size); Result SetBatteryInternalState(Session &session, const void *src, size_t src_size); Result GetBatteryNeedToRestoreParameters(bool *out, Session &session); Result SetBatteryNeedToRestoreParameters(Session &session, bool en); Result IsBatteryI2cShutdownEnabled(bool *out, Session &session); Result SetBatteryI2cShutdownEnabled(Session &session, bool en); Result IsBatteryPresent(bool *out, Session &session); Result GetBatteryCycles(int *out, Session &session); Result SetBatteryCycles(Session &session, int cycles); Result GetBatteryAge(float *out_percent, Session &session); Result GetBatteryTemperature(float *out_c, Session &session); Result GetBatteryMaximumTemperature(float *out_c, Session &session); Result SetBatteryTemperatureMinimumAlertThreshold(Session &session, float c); Result SetBatteryTemperatureMaximumAlertThreshold(Session &session, float c); Result GetBatteryVCell(int *out_mv, Session &session); Result GetBatteryAverageVCell(int *out_mv, Session &session); Result GetBatteryAverageVCellTime(TimeSpan *out, Session &session); Result GetBatteryOpenCircuitVoltage(int *out_mv, Session &session); Result SetBatteryVoltageMinimumAlertThreshold(Session &session, int mv); Result SetBatteryVoltageMaximumAlertThreshold(Session &session, int mv); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_charger_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> #include <stratosphere/powctl/powctl_session_api.hpp> namespace ams::powctl { /* Charger API. */ Result GetChargerChargeCurrentState(ChargeCurrentState *out, Session &session); Result SetChargerChargeCurrentState(Session &session, ChargeCurrentState state); Result GetChargerFastChargeCurrentLimit(int *out_ma, Session &session); Result SetChargerFastChargeCurrentLimit(Session &session, int ma); Result GetChargerChargeVoltageLimit(int *out_mv, Session &session); Result SetChargerChargeVoltageLimit(Session &session, int mv); Result SetChargerChargerConfiguration(Session &session, ChargerConfiguration cfg); Result IsChargerHiZEnabled(bool *out, Session &session); Result SetChargerHiZEnabled(Session &session, bool en); Result GetChargerInputCurrentLimit(int *out_ma, Session &session); Result SetChargerInputCurrentLimit(Session &session, int ma); Result SetChargerInputVoltageLimit(Session &session, int mv); Result SetChargerBoostModeCurrentLimit(Session &session, int ma); Result GetChargerChargerStatus(ChargerStatus *out, Session &session); Result IsChargerWatchdogTimerEnabled(bool *out, Session &session); Result SetChargerWatchdogTimerEnabled(Session &session, bool en); Result SetChargerWatchdogTimerTimeout(Session &session, TimeSpan timeout); Result ResetChargerWatchdogTimer(Session &session); Result GetChargerBatteryCompensation(int *out_mo, Session &session); Result SetChargerBatteryCompensation(Session &session, int mo); Result GetChargerVoltageClamp(int *out_mv, Session &session); Result SetChargerVoltageClamp(Session &session, int mv); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/i2c.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl { /* Fuel Gauge. */ constexpr inline const DeviceCode DeviceCode_Max17050 = i2c::DeviceCode_Max17050; /* Charger. */ constexpr inline const DeviceCode DeviceCode_Bq24193 = i2c::DeviceCode_Bq24193; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_select_devices.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/powctl/powctl_devices.board.nintendo_nx.hpp> #else /* Error? */ #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_session_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/powctl/powctl_types.hpp> namespace ams::powctl { namespace impl { class SessionImpl : public ::ams::ddsf::ISession { NON_COPYABLE(SessionImpl); NON_MOVEABLE(SessionImpl); AMS_DDSF_CASTABLE_TRAITS(ams::powctl::impl::SessionImpl, ::ams::ddsf::ISession); public: SessionImpl() : ISession() { /* ... */ } ~SessionImpl() { ddsf::CloseSession(this); } }; } struct Session { bool has_session; util::TypedStorage<impl::SessionImpl> impl_storage; struct ConstantInitializeTag{}; constexpr Session(ConstantInitializeTag) : has_session(false), impl_storage() { /* ... */ } Session() : has_session(false) { /* ... */ } }; Result OpenSession(Session *out, DeviceCode device_code, ddsf::AccessMode access_mode); void CloseSession(Session &session); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl/powctl_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::powctl { /* Charger types. */ enum ChargerStatus { ChargerStatus_Charging = 1, ChargerStatus_NotCharging = 3, ChargerStatus_ChargeTerminationDone = 4, }; enum ChargerConfiguration { ChargerConfiguration_ChargeDisable = 1, ChargerConfiguration_ChargeBattery = 2, ChargerConfiguration_Otg = 3, }; enum ChargeCurrentState { ChargeCurrentState_Unknown = 0x0, ChargeCurrentState_NotCharging = 0x1, ChargeCurrentState_ChargingForce20Percent = 0x2, ChargeCurrentState_Charging = 0x3, }; enum class BatteryTemperatureLevel { TooLow = 0, Low = 1, Medium = 2, High = 3, TooHigh = 4, }; enum class PowerState { FullAwake = 0, MinimumAwake = 1, SleepCharge = 2, SleepDischarge = 3, ShutdownChargeMain = 4, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/powctl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/powctl/powctl_types.hpp> #include <stratosphere/powctl/powctl_select_devices.hpp> #include <stratosphere/powctl/powctl_session_api.hpp> #include <stratosphere/powctl/powctl_battery_api.hpp> #include <stratosphere/powctl/powctl_charger_api.hpp> #include <stratosphere/powctl/impl/powctl_battery_charge_percentage.hpp> #include <stratosphere/powctl/driver/powctl_driver_api.hpp> #include <stratosphere/powctl/driver/impl/powctl_select_charger_parameters.hpp> #include <stratosphere/powctl/driver/impl/powctl_charge_arbiter.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/psc/psc_pm_module.os.horizon.hpp> #else #include <stratosphere/psc/psc_pm_module.os.generic.hpp> #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.os.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/psc/psc_types.hpp> #include <stratosphere/psc/psc_pm_module_id.hpp> #include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp> namespace ams::psc { class PmModule { NON_COPYABLE(PmModule); NON_MOVEABLE(PmModule); private: os::SystemEvent m_system_event; bool m_initialized; PmModuleId m_module_id; uintptr_t m_reserved; PmState m_state; PmFlagSet m_flags; public: PmModule() : m_initialized(false), m_module_id(PmModuleId_Reserved0), m_reserved(0), m_state(PmState_FullAwake), m_flags() { /* ... */ } ~PmModule() { if (m_initialized) { R_ABORT_UNLESS(this->Finalize()); } } Result Initialize(const PmModuleId mid, const PmModuleId *dependencies, u32 dependency_count, os::EventClearMode clear_mode) { /* TODO: Should we do in-process dependency resolution? */ AMS_UNUSED(dependencies, dependency_count); /* Check that we're not already initialized. */ R_UNLESS(!m_initialized, psc::ResultAlreadyInitialized()); /* Create our event. */ R_ABORT_UNLESS(os::CreateSystemEvent(m_system_event.GetBase(), clear_mode, false)); /* Set our state. */ m_module_id = mid; m_initialized = true; R_SUCCEED(); } Result Finalize() { /* Check that we're initialized. */ R_UNLESS(m_initialized, psc::ResultNotInitialized()); /* Destroy our system event. */ os::DestroySystemEvent(m_system_event.GetBase()); /* Mark not initialized. */ m_initialized = false; R_SUCCEED(); } constexpr PmModuleId GetId() const { return m_module_id; } Result GetRequest(PmState *out_state, PmFlagSet *out_flags) { /* Check that we're initialized. */ R_UNLESS(m_initialized, psc::ResultNotInitialized()); /* Set output. */ *out_state = m_state; *out_flags = m_flags; R_SUCCEED(); } Result Acknowledge(PmState state, Result res) { /* Check that we're initialized. */ R_UNLESS(m_initialized, psc::ResultNotInitialized()); /* Check the transition was successful. */ R_ABORT_UNLESS(res); AMS_UNUSED(state); R_SUCCEED(); } os::SystemEvent *GetEventPointer() { return std::addressof(m_system_event); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/psc_pm_module.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/psc/psc_types.hpp> #include <stratosphere/psc/psc_pm_module_id.hpp> #include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp> namespace ams::psc { class PmModule { NON_COPYABLE(PmModule); NON_MOVEABLE(PmModule); private: ams::sf::SharedPointer<psc::sf::IPmModule> m_intf; os::SystemEvent m_system_event; bool m_initialized; PmModuleId m_module_id; uintptr_t m_reserved; public: PmModule(); ~PmModule(); Result Initialize(const PmModuleId mid, const PmModuleId *dependencies, u32 dependency_count, os::EventClearMode clear_mode); Result Finalize(); constexpr PmModuleId GetId() const { return m_module_id; } Result GetRequest(PmState *out_state, PmFlagSet *out_flags); Result Acknowledge(PmState state, Result res); os::SystemEvent *GetEventPointer(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/psc_pm_module_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::psc { enum PmModuleId : u32 { PmModuleId_Reserved0 = 0, PmModuleId_Usb = 4, PmModuleId_Ethernet = 5, PmModuleId_Fgm = 6, PmModuleId_PcvClock = 7, PmModuleId_PcvVoltage = 8, PmModuleId_Gpio = 9, PmModuleId_Pinmux = 10, PmModuleId_Uart = 11, PmModuleId_I2c = 12, PmModuleId_I2cPcv = 13, PmModuleId_Spi = 14, PmModuleId_Pwm = 15, PmModuleId_Psm = 16, PmModuleId_Tc = 17, PmModuleId_Omm = 18, PmModuleId_Pcie = 19, PmModuleId_Lbl = 20, PmModuleId_Display = 21, PmModuleId_Hid = 24, PmModuleId_WlanSockets = 25, PmModuleId_Fs = 27, PmModuleId_Audio = 28, PmModuleId_TmaHostIo = 30, PmModuleId_Bluetooth = 31, PmModuleId_Bpc = 32, PmModuleId_Fan = 33, PmModuleId_Pcm = 34, PmModuleId_Nfc = 35, PmModuleId_Apm = 36, PmModuleId_Btm = 37, PmModuleId_Nifm = 38, PmModuleId_GpioLow = 39, PmModuleId_Npns = 40, PmModuleId_Lm = 41, PmModuleId_Bcat = 42, PmModuleId_Time = 43, PmModuleId_Pctl = 44, PmModuleId_Erpt = 45, PmModuleId_Eupld = 46, PmModuleId_Friends = 47, PmModuleId_Bgtc = 48, PmModuleId_Account = 49, PmModuleId_Sasbus = 50, PmModuleId_Ntc = 51, PmModuleId_Idle = 52, PmModuleId_Tcap = 53, PmModuleId_PsmLow = 54, PmModuleId_Ndd = 55, PmModuleId_Olsc = 56, PmModuleId_Ns = 61, PmModuleId_Nvservices = 101, PmModuleId_Spsm = 127, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/psc_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::psc { enum PmState { PmState_FullAwake = 0, PmState_MinimumAwake = 1, PmState_SleepReady = 2, PmState_EssentialServicesSleepReady = 3, PmState_EssentialServicesAwake = 4, PmState_ShutdownReady = 5, PmState_Unknown = 6, }; constexpr inline u32 MaximumDependencyLevels = 20; struct PmFlag { }; using PmFlagSet = util::BitFlagSet<BITSIZEOF(u32), PmFlag>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/sf/psc_sf_i_pm_module.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/psc/psc_types.hpp> #include <stratosphere/psc/psc_pm_module_id.hpp> #define AMS_PSC_I_PM_MODULE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Initialize, (ams::sf::OutCopyHandle out, psc::PmModuleId module_id, const ams::sf::InBuffer &child_list), (out, module_id, child_list)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetRequest, (ams::sf::Out<psc::PmState> out_state, ams::sf::Out<psc::PmFlagSet> out_flags), (out_state, out_flags)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Acknowledge, (), ()) \ AMS_SF_METHOD_INFO(C, H, 3, Result, Finalize, (), ()) \ AMS_SF_METHOD_INFO(C, H, 4, Result, AcknowledgeEx, (psc::PmState state), (state), hos::Version_5_1_0) AMS_SF_DEFINE_INTERFACE(ams::psc::sf, IPmModule, AMS_PSC_I_PM_MODULE_INTERFACE_INFO, 0x4275F38F) ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc/sf/psc_sf_i_pm_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp> #define AMS_PSC_I_PM_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Initialize, (ams::sf::Out<ams::sf::SharedPointer<psc::sf::IPmModule>> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::psc::sf, IPmService, AMS_PSC_I_PM_SERVICE_INTERFACE_INFO, 0xEABE6F26) ================================================ FILE: libraries/libstratosphere/include/stratosphere/psc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/psc/psc_types.hpp> #include <stratosphere/psc/psc_pm_module_id.hpp> #include <stratosphere/psc/sf/psc_sf_i_pm_module.hpp> #include <stratosphere/psc/sf/psc_sf_i_pm_service.hpp> #include <stratosphere/psc/psc_pm_module.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/board/nintendo/nx/pwm_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm::driver::board::nintendo::nx { void Initialize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_channel_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm::driver { namespace impl { constexpr inline size_t ChannelSessionSize = 0x60; constexpr inline size_t ChannelSessionAlign = 8; struct alignas(ChannelSessionAlign) ChannelSessionImplPadded; } struct ChannelSession { util::TypedStorage<impl::ChannelSessionImplPadded, impl::ChannelSessionSize, impl::ChannelSessionAlign> _impl; }; Result OpenSession(ChannelSession *out, DeviceCode device_code); void CloseSession(ChannelSession &session); void SetPeriod(ChannelSession &session, TimeSpan period); TimeSpan GetPeriod(ChannelSession &session); void SetDuty(ChannelSession &session, int duty); int GetDuty(ChannelSession &session); void SetEnabled(ChannelSession &session, bool en); bool GetEnabled(ChannelSession &session); void SetScale(ChannelSession &session, double scale); double GetScale(ChannelSession &session); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_driver_client_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm::driver { void Initialize(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_driver_service_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/driver/pwm_i_pwm_device.hpp> #include <stratosphere/pwm/driver/pwm_i_pwm_driver.hpp> namespace ams::pwm::driver { void RegisterDriver(IPwmDriver *driver); void UnregisterDriver(IPwmDriver *driver); Result RegisterDeviceCode(DeviceCode device_code, IPwmDevice *device); bool UnregisterDeviceCode(DeviceCode device_code); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_device.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/ddsf.hpp> namespace ams::pwm::driver { class IPwmDevice : public ::ams::ddsf::IDevice { NON_COPYABLE(IPwmDevice); NON_MOVEABLE(IPwmDevice); AMS_DDSF_CASTABLE_TRAITS(ams::pwm::driver::IPwmDevice, ::ams::ddsf::IDevice); private: int m_channel_index; public: IPwmDevice(int id) : IDevice(false), m_channel_index(id) { /* ... */ } virtual ~IPwmDevice() { /* ... */ } constexpr int GetChannelIndex() const { return m_channel_index; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_i_pwm_driver.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/driver/pwm_i_pwm_device.hpp> #include <stratosphere/ddsf.hpp> namespace ams::pwm::driver { class IPwmDriver : public ::ams::ddsf::IDriver { NON_COPYABLE(IPwmDriver); NON_MOVEABLE(IPwmDriver); AMS_DDSF_CASTABLE_TRAITS(ams::pwm::driver::IPwmDriver, ::ams::ddsf::IDriver); public: IPwmDriver() : IDriver() { /* ... */ } virtual ~IPwmDriver() { /* ... */ } virtual void InitializeDriver() = 0; virtual void FinalizeDriver() = 0; virtual Result InitializeDevice(IPwmDevice *device) = 0; virtual void FinalizeDevice(IPwmDevice *device) = 0; virtual Result SetPeriod(IPwmDevice *device, TimeSpan period) = 0; virtual Result GetPeriod(TimeSpan *out, IPwmDevice *device) = 0; /* TODO: Nintendo removed these in 14.0.0. Should we? */ virtual Result SetDuty(IPwmDevice *device, int duty) = 0; virtual Result GetDuty(int *out, IPwmDevice *device) = 0; virtual Result SetScale(IPwmDevice *device, double scale) = 0; virtual Result GetScale(double *out, IPwmDevice *device) = 0; virtual Result SetEnabled(IPwmDevice *device, bool en) = 0; virtual Result GetEnabled(bool *out, IPwmDevice *device) = 0; virtual Result Suspend() = 0; virtual void Resume() = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/driver/pwm_select_driver_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/driver/pwm_i_pwm_driver.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/pwm/driver/board/nintendo/nx/pwm_driver_api.hpp> namespace ams::pwm::driver::board { using namespace ams::pwm::driver::board::nintendo::nx; } #else // TODO: #error "Unknown board for ams::pwm::driver::" #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/sf/pwm_sf_i_manager.hpp> namespace ams::pwm { void InitializeWith(ams::sf::SharedPointer<pwm::sf::IManager> sp); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm { struct ChannelSession { void *_session; }; Result OpenSession(ChannelSession *out, DeviceCode device_code); void CloseSession(ChannelSession &session); void SetPeriod(ChannelSession &session, TimeSpan period); TimeSpan GetPeriod(ChannelSession &session); void SetDuty(ChannelSession &session, int duty); int GetDuty(ChannelSession &session); void SetEnabled(ChannelSession &session, bool en); bool GetEnabled(ChannelSession &session); void SetScale(ChannelSession &session, double scale); double GetScale(ChannelSession &session); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_name.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm { enum ChannelName { ChannelName_Invalid = 0, ChannelName_CpuFan = 1, ChannelName_LcdBacklight = 2, ChannelName_BlinkLed = 3, }; constexpr inline const DeviceCode DeviceCode_CpuFan = 0x3D000001; constexpr inline const DeviceCode DeviceCode_LcdBacklight = 0x3400003D; constexpr inline const DeviceCode DeviceCode_BlinkLed = 0x35000065; constexpr inline DeviceCode ConvertToDeviceCode(ChannelName cn) { switch (cn) { case ChannelName_CpuFan: return DeviceCode_CpuFan; case ChannelName_LcdBacklight: return DeviceCode_LcdBacklight; case ChannelName_BlinkLed: return DeviceCode_BlinkLed; AMS_UNREACHABLE_DEFAULT_CASE(); } } constexpr inline ChannelName ConvertToChannelName(DeviceCode dc) { switch (dc.GetInternalValue()) { case DeviceCode_CpuFan .GetInternalValue(): return ChannelName_CpuFan; case DeviceCode_LcdBacklight.GetInternalValue(): return ChannelName_LcdBacklight; case DeviceCode_BlinkLed .GetInternalValue(): return ChannelName_BlinkLed; AMS_UNREACHABLE_DEFAULT_CASE(); } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_channel_name.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> namespace ams::pwm { enum ChannelName { ChannelName_Invalid = 0, }; constexpr inline DeviceCode ConvertToDeviceCode(ChannelName cn) { switch (cn) { AMS_UNREACHABLE_DEFAULT_CASE(); } return InvalidDeviceCode; } constexpr inline ChannelName ConvertToChannelName(DeviceCode dc) { switch (dc.GetInternalValue()) { AMS_UNREACHABLE_DEFAULT_CASE(); } return ChannelName_Invalid; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_select_channel_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/pwm/pwm_channel_name.board.nintendo_nx.hpp> #else #include <stratosphere/pwm/pwm_channel_name.generic.hpp> #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/pwm_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::pwm { /* ... */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/server/pwm_server_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/sf/pwm_sf_i_manager.hpp> namespace ams::pwm::server { ams::sf::SharedPointer<pwm::sf::IManager> GetServiceObject(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/sf/pwm_sf_i_channel_session.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/pwm/pwm_types.hpp> #define AMS_PWM_I_CHANNEL_SESSION_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SetPeriod, (TimeSpanType period), (period)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetPeriod, (ams::sf::Out<TimeSpanType> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetDuty, (int duty), (duty), hos::Version_Min, hos::Version_13_2_1) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetDuty, (ams::sf::Out<int> out), (out), hos::Version_Min, hos::Version_13_2_1) \ AMS_SF_METHOD_INFO(C, H, 4, Result, SetEnabled, (bool enabled), (enabled)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetEnabled, (ams::sf::Out<bool> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, SetScale, (double scale), (scale), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetScale, (ams::sf::Out<double> out), (out), hos::Version_6_0_0) AMS_SF_DEFINE_INTERFACE(ams::pwm::sf, IChannelSession, AMS_PWM_I_CHANNEL_SESSION_INTERFACE_INFO, 0xAC0A18F9) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm/sf/pwm_sf_i_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ddsf/ddsf_types.hpp> #include <stratosphere/pwm/pwm_select_channel_name.hpp> #include <stratosphere/pwm/sf/pwm_sf_i_channel_session.hpp> #define AMS_PWM_I_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenSessionForDev, (ams::sf::Out<ams::sf::SharedPointer<pwm::sf::IChannelSession>> out, int channel), (out, channel) ) \ AMS_SF_METHOD_INFO(C, H, 1, Result, OpenSession, (ams::sf::Out<ams::sf::SharedPointer<pwm::sf::IChannelSession>> out, pwm::ChannelName channel_name), (out, channel_name) ) \ AMS_SF_METHOD_INFO(C, H, 2, Result, OpenSession2, (ams::sf::Out<ams::sf::SharedPointer<pwm::sf::IChannelSession>> out, DeviceCode device_code), (out, device_code), hos::Version_6_0_0) AMS_SF_DEFINE_INTERFACE(ams::pwm::sf, IManager, AMS_PWM_I_MANAGER_INTERFACE_INFO, 0xBC382479) ================================================ FILE: libraries/libstratosphere/include/stratosphere/pwm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/pwm/pwm_types.hpp> #include <stratosphere/pwm/pwm_select_channel_name.hpp> #include <stratosphere/pwm/sf/pwm_sf_i_channel_session.hpp> #include <stratosphere/pwm/sf/pwm_sf_i_manager.hpp> #include <stratosphere/pwm/server/pwm_server_api.hpp> #include <stratosphere/pwm/driver/pwm_select_driver_api.hpp> #include <stratosphere/pwm/driver/pwm_driver_service_api.hpp> #include <stratosphere/pwm/driver/pwm_driver_client_api.hpp> #include <stratosphere/pwm/driver/pwm_channel_api.hpp> #include <stratosphere/pwm/pwm_api.hpp> #include <stratosphere/pwm/pwm_channel_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/allocators.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Allocator /*! \class rapidjson::Allocator \brief Concept for allocating, resizing and freeing memory block. Note that Malloc() and Realloc() are non-static but Free() is static. So if an allocator need to support Free(), it needs to put its pointer in the header of memory block. \code concept Allocator { static const bool kNeedFree; //!< Whether this allocator needs to call Free(). // Allocate a memory block. // \param size of the memory block in bytes. // \returns pointer to the memory block. void* Malloc(size_t size); // Resize a memory block. // \param originalPtr The pointer to current memory block. Null pointer is permitted. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) // \param newSize the new size in bytes. void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // Free a memory block. // \param pointer to the memory block. Null pointer is permitted. static void Free(void *ptr); }; \endcode */ /*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY \ingroup RAPIDJSON_CONFIG \brief User-defined kDefaultChunkCapacity definition. User can define this as any \c size that is a power of 2. */ #ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY #define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) #endif /////////////////////////////////////////////////////////////////////////////// // CrtAllocator //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. \note implements Allocator concept */ class CrtAllocator { public: static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. return RAPIDJSON_MALLOC(size); else return NULL; // standardize to returning NULL. } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; if (newSize == 0) { RAPIDJSON_FREE(originalPtr); return NULL; } return RAPIDJSON_REALLOC(originalPtr, newSize); } static void Free(void *ptr) { RAPIDJSON_FREE(ptr); } }; /////////////////////////////////////////////////////////////////////////////// // MemoryPoolAllocator //! Default memory allocator used by the parser and DOM. /*! This allocator allocate memory blocks from pre-allocated memory chunks. It does not free memory blocks. And Realloc() only allocate new memory. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. User may also supply a buffer as the first chunk. If the user-buffer is full then additional chunks are allocated by BaseAllocator. The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \note implements Allocator concept */ template <typename BaseAllocator = CrtAllocator> class MemoryPoolAllocator { public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { } //! Constructor with user-supplied buffer. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. The user buffer will not be deallocated when this allocator is destructed. \param buffer User supplied buffer. \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer); chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->size = 0; chunkHead_->next = 0; } //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ ~MemoryPoolAllocator() { Clear(); RAPIDJSON_DELETE(ownBaseAllocator_); } //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { while (chunkHead_ && chunkHead_ != userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } if (chunkHead_ && chunkHead_ == userBuffer_) chunkHead_->size = 0; // Clear user buffer } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ size_t Capacity() const { size_t capacity = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) capacity += c->capacity; return capacity; } //! Computes the memory blocks allocated. /*! \return total used bytes. */ size_t Size() const { size_t size = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size += c->size; return size; } //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { if (!size) return NULL; size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) return NULL; void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; chunkHead_->size += size; return buffer; } //! Resizes a memory block (concept Allocator) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { if (originalPtr == 0) return Malloc(newSize); if (newSize == 0) return NULL; originalSize = RAPIDJSON_ALIGN(originalSize); newSize = RAPIDJSON_ALIGN(newSize); // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast<size_t>(newSize - originalSize); if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; return originalPtr; } } // Realloc process: allocate and copy memory, do not free original buffer. if (void* newBuffer = Malloc(newSize)) { if (originalSize) std::memcpy(newBuffer, originalPtr, originalSize); return newBuffer; } else return NULL; } //! Frees a memory block (concept Allocator) static void Free(void *ptr) { (void)ptr; } // Do nothing private: //! Copy constructor is not permitted. MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; //! Copy assignment operator is not permitted. MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. \return true if success. */ bool AddChunk(size_t capacity) { if (!baseAllocator_) ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { chunk->capacity = capacity; chunk->size = 0; chunk->next = chunkHead_; chunkHead_ = chunk; return true; } else return false; } static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. */ struct ChunkHeader { size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t size; //!< Current size of allocated memory in bytes. ChunkHeader *next; //!< Next chunk in the linked list. }; ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. void *userBuffer_; //!< User supplied buffer. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ENCODINGS_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/cursorstreamwrapper.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ #include "stream.h" #if defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN //! Cursor stream wrapper for counting line and column number if error exists. /*! \tparam InputStream Any stream that implements Stream Concept */ template <typename InputStream, typename Encoding = UTF8<> > class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> { public: typedef typename Encoding::Ch Ch; CursorStreamWrapper(InputStream& is): GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {} // counting line and column number Ch Take() { Ch ch = this->is_.Take(); if(ch == '\n') { line_ ++; col_ = 0; } else { col_ ++; } return ch; } //! Get the error line number, if error exists. size_t GetLine() const { return line_; } //! Get the error column number, if error exists. size_t GetColumn() const { return col_; } private: size_t line_; //!< Current Line size_t col_; //!< Current Column }; #if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_POP #endif #if defined(__GNUC__) RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/document.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ /*! \file document.h */ #include "reader.h" #include "internal/meta.h" #include "internal/strfunc.h" #include "memorystream.h" #include "encodedstream.h" #include <new> // placement new #include <limits> #ifdef __cpp_lib_three_way_comparison #include <compare> #endif RAPIDJSON_DIAG_PUSH #ifdef __clang__ RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(c++98-compat) #elif defined(_MSC_VER) RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif #ifdef __GNUC__ RAPIDJSON_DIAG_OFF(effc++) #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include <iterator> // std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include <utility> // std::move #endif RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. template <typename Encoding, typename Allocator> class GenericValue; template <typename Encoding, typename Allocator, typename StackAllocator> class GenericDocument; /*! \def RAPIDJSON_DEFAULT_ALLOCATOR \ingroup RAPIDJSON_CONFIG \brief Allows to choose default allocator. User can define this to use CrtAllocator or MemoryPoolAllocator. */ #ifndef RAPIDJSON_DEFAULT_ALLOCATOR #define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator> #endif /*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR \ingroup RAPIDJSON_CONFIG \brief Allows to choose default stack allocator for Document. User can define this to use CrtAllocator or MemoryPoolAllocator. */ #ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR #define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator #endif /*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY \ingroup RAPIDJSON_CONFIG \brief User defined kDefaultObjectCapacity value. User can define this as any natural number. */ #ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY // number of objects that rapidjson::Value allocates memory for by default #define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 #endif /*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY \ingroup RAPIDJSON_CONFIG \brief User defined kDefaultArrayCapacity value. User can define this as any natural number. */ #ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY // number of array elements that rapidjson::Value allocates memory for by default #define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 #endif //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. https://code.google.com/p/rapidjson/issues/detail?id=64 */ template <typename Encoding, typename Allocator> class GenericMember { public: GenericValue<Encoding, Allocator> name; //!< name of member (must be a string) GenericValue<Encoding, Allocator> value; //!< value of member. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT : name(std::move(rhs.name)), value(std::move(rhs.value)) { } //! Move assignment in C++11 GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { return *this = static_cast<GenericMember&>(rhs); } #endif //! Assignment with move semantics. /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. */ GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { if (RAPIDJSON_LIKELY(this != &rhs)) { name = rhs.name; value = rhs.value; } return *this; } // swap() for std::sort() and other potential use in STL. friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { a.name.Swap(b.name); a.value.Swap(b.value); } private: //! Copy constructor is not permitted. GenericMember(const GenericMember& rhs); }; /////////////////////////////////////////////////////////////////////////////// // GenericMemberIterator #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! \tparam Const Is this a constant iterator? \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. This class implements a Random Access Iterator for GenericMember elements of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. \note This iterator implementation is mainly intended to avoid implicit conversions from iterator values to \c NULL, e.g. from GenericValue::FindMember. \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a pointer-based implementation, if your platform doesn't provide the C++ <iterator> header. \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template <bool Const, typename Encoding, typename Allocator> class GenericMemberIterator { friend class GenericValue<Encoding,Allocator>; template <bool, typename, typename> friend class GenericMemberIterator; typedef GenericMember<Encoding,Allocator> PlainType; typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; public: //! Iterator type itself typedef GenericMemberIterator Iterator; //! Constant iterator type typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator; //! Non-constant iterator type typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator; /** \name std::iterator_traits support */ //@{ typedef ValueType value_type; typedef ValueType * pointer; typedef ValueType & reference; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; //@} //! Pointer to (const) GenericMember typedef pointer Pointer; //! Reference to (const) GenericMember typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. \note All operations, except for comparisons, are undefined on such values. */ GenericMemberIterator() : ptr_() {} //! Iterator conversions to more const /*! \param it (Non-const) iterator to copy from Allows the creation of an iterator from another GenericMemberIterator that is "less const". Especially, creating a non-constant iterator from a constant iterator are disabled: \li const -> non-const (not ok) \li const -> const (ok) \li non-const -> const (ok) \li non-const -> non-const (ok) \note If the \c Const template parameter is already \c false, this constructor effectively defines a regular copy-constructor. Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } //! @name stepping //@{ Iterator& operator++(){ ++ptr_; return *this; } Iterator& operator--(){ --ptr_; return *this; } Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } //@} //! @name increment/decrement //@{ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } //@} //! @name relations //@{ template <bool Const_> bool operator==(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ == that.ptr_; } template <bool Const_> bool operator!=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ != that.ptr_; } template <bool Const_> bool operator<=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <= that.ptr_; } template <bool Const_> bool operator>=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ >= that.ptr_; } template <bool Const_> bool operator< (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ < that.ptr_; } template <bool Const_> bool operator> (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ > that.ptr_; } #ifdef __cpp_lib_three_way_comparison template <bool Const_> std::strong_ordering operator<=>(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <=> that.ptr_; } #endif //@} //! @name dereference //@{ Reference operator*() const { return *ptr_; } Pointer operator->() const { return ptr_; } Reference operator[](DifferenceType n) const { return ptr_[n]; } //@} //! Distance DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } private: //! Internal constructor from plain pointer explicit GenericMemberIterator(Pointer p) : ptr_(p) {} Pointer ptr_; //!< raw pointer }; #else // RAPIDJSON_NOMEMBERITERATORCLASS // class-based member iterator implementation disabled, use plain pointers template <bool Const, typename Encoding, typename Allocator> class GenericMemberIterator; //! non-const GenericMemberIterator template <typename Encoding, typename Allocator> class GenericMemberIterator<false,Encoding,Allocator> { public: //! use plain pointer as iterator type typedef GenericMember<Encoding,Allocator>* Iterator; }; //! const GenericMemberIterator template <typename Encoding, typename Allocator> class GenericMemberIterator<true,Encoding,Allocator> { public: //! use plain const pointer as iterator type typedef const GenericMember<Encoding,Allocator>* Iterator; }; #endif // RAPIDJSON_NOMEMBERITERATORCLASS /////////////////////////////////////////////////////////////////////////////// // GenericStringRef //! Reference to a constant string (not taking a copy) /*! \tparam CharType character type of the string This helper class is used to automatically infer constant string references for string literals, especially from \c const \b (!) character arrays. The main use is for creating JSON string values without copying the source string via an \ref Allocator. This requires that the referenced string pointers have a sufficient lifetime, which exceeds the lifetime of the associated GenericValue. \b Example \code Value v("foo"); // ok, no need to copy & calculate length const char foo[] = "foo"; v.SetString(foo); // ok const char* bar = foo; // Value x(bar); // not ok, can't rely on bar's lifetime Value x(StringRef(bar)); // lifetime explicitly guaranteed by user Value y(StringRef(bar, 3)); // ok, explicitly pass length \endcode \see StringRef, GenericValue::SetString */ template<typename CharType> struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array #ifndef __clang__ // -Wdocumentation /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than \ref StringRef(const CharType*) by inferring the string \ref length from the array length, and also supports strings containing null characters. \tparam N length of the string, automatically inferred \param str Constant character array, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note Constant complexity. \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif template<SizeType N> GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer #ifndef __clang__ // -Wdocumentation /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. \see StringRef(const CharType*) \param str Constant character pointer, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif explicit GenericStringRef(const CharType* str) : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ #endif GenericStringRef(const CharType* str, SizeType len) : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } const Ch* const s; //!< plain CharType pointer const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: SizeType NotNullStrLen(const CharType* str) { RAPIDJSON_ASSERT(str != 0); return internal::StrLen(str); } /// Empty string - used when passing in a NULL pointer static const Ch emptyString[]; //! Disallow construction from non-const array template<SizeType N> GenericStringRef(CharType (&str)[N]) /* = delete */; //! Copy assignment operator not permitted - immutable type GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; template<typename CharType> const CharType GenericStringRef<CharType>::emptyString[] = { CharType() }; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType Character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ template<typename CharType> inline GenericStringRef<CharType> StringRef(const CharType* str) { return GenericStringRef<CharType>(str); } //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. This version has better performance with supplied length, and also supports string containing null characters. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param length The length of source string. \return GenericStringRef string reference object \relatesalso GenericStringRef */ template<typename CharType> inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) { return GenericStringRef<CharType>(str, SizeType(length)); } #if RAPIDJSON_HAS_STDSTRING //! Mark a string object as constant string /*! Mark a string object (e.g. \c std::string) as a "string literal". This function can be used to avoid copying a string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ template<typename CharType> inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) { return GenericStringRef<CharType>(str.data(), SizeType(str.size())); } #endif /////////////////////////////////////////////////////////////////////////////// // GenericValue type traits namespace internal { template <typename T, typename Encoding = void, typename Allocator = void> struct IsGenericValueImpl : FalseType {}; // select candidates according to nested encoding and allocator types template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type> : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {}; // helper to match arbitrary GenericValue instantiations, including derived classes template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {}; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // TypeHelper namespace internal { template <typename ValueType, typename T> struct TypeHelper {}; template<typename ValueType> struct TypeHelper<ValueType, bool> { static bool Is(const ValueType& v) { return v.IsBool(); } static bool Get(const ValueType& v) { return v.GetBool(); } static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } }; template<typename ValueType> struct TypeHelper<ValueType, int> { static bool Is(const ValueType& v) { return v.IsInt(); } static int Get(const ValueType& v) { return v.GetInt(); } static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } }; template<typename ValueType> struct TypeHelper<ValueType, unsigned> { static bool Is(const ValueType& v) { return v.IsUint(); } static unsigned Get(const ValueType& v) { return v.GetUint(); } static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; #ifdef _MSC_VER RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); template<typename ValueType> struct TypeHelper<ValueType, long> { static bool Is(const ValueType& v) { return v.IsInt(); } static long Get(const ValueType& v) { return v.GetInt(); } static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } }; RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); template<typename ValueType> struct TypeHelper<ValueType, unsigned long> { static bool Is(const ValueType& v) { return v.IsUint(); } static unsigned long Get(const ValueType& v) { return v.GetUint(); } static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; #endif template<typename ValueType> struct TypeHelper<ValueType, int64_t> { static bool Is(const ValueType& v) { return v.IsInt64(); } static int64_t Get(const ValueType& v) { return v.GetInt64(); } static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } }; template<typename ValueType> struct TypeHelper<ValueType, uint64_t> { static bool Is(const ValueType& v) { return v.IsUint64(); } static uint64_t Get(const ValueType& v) { return v.GetUint64(); } static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } }; template<typename ValueType> struct TypeHelper<ValueType, double> { static bool Is(const ValueType& v) { return v.IsDouble(); } static double Get(const ValueType& v) { return v.GetDouble(); } static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } }; template<typename ValueType> struct TypeHelper<ValueType, float> { static bool Is(const ValueType& v) { return v.IsFloat(); } static float Get(const ValueType& v) { return v.GetFloat(); } static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } }; template<typename ValueType> struct TypeHelper<ValueType, const typename ValueType::Ch*> { typedef const typename ValueType::Ch* StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return v.GetString(); } static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #if RAPIDJSON_HAS_STDSTRING template<typename ValueType> struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > { typedef std::basic_string<typename ValueType::Ch> StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #endif template<typename ValueType> struct TypeHelper<ValueType, typename ValueType::Array> { typedef typename ValueType::Array ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(ValueType& v) { return v.GetArray(); } static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } }; template<typename ValueType> struct TypeHelper<ValueType, typename ValueType::ConstArray> { typedef typename ValueType::ConstArray ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(const ValueType& v) { return v.GetArray(); } }; template<typename ValueType> struct TypeHelper<ValueType, typename ValueType::Object> { typedef typename ValueType::Object ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template<typename ValueType> struct TypeHelper<ValueType, typename ValueType::ConstObject> { typedef typename ValueType::ConstObject ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(const ValueType& v) { return v.GetObject(); } }; } // namespace internal // Forward declarations template <bool, typename> class GenericArray; template <bool, typename> class GenericObject; /////////////////////////////////////////////////////////////////////////////// // GenericValue //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! A JSON value can be one of 7 types. This class is a variant type supporting these types. Use the Value if UTF8 and default allocator \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR > class GenericValue { public: //! Name-value pair in an object. typedef GenericMember<Encoding, Allocator> Member; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object. typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself. typedef GenericArray<false, ValueType> Array; typedef GenericArray<true, ValueType> ConstArray; typedef GenericObject<false, ValueType> Object; typedef GenericObject<true, ValueType> ConstObject; //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { rhs.data_.f.flags = kNullFlag; // give up contents } #endif private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Moving from a GenericDocument is not permitted. template <typename StackAllocator> GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs); //! Move assignment from a GenericDocument is not permitted. template <typename StackAllocator> GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs); #endif public: //! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \param type Type of the value. \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { static const uint16_t defaultFlags[] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. if (type == kStringType) data_.ss.SetLength(0); } //! Explicit copy constructor (with allocator) /*! Creates a copy of a Value by using the given Allocator \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ template <typename SourceAllocator> GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) { switch (rhs.GetType()) { case kObjectType: { SizeType count = rhs.data_.o.size; Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member))); const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer(); for (SizeType i = 0; i < count; i++) { new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); } data_.f.flags = kObjectFlag; data_.o.size = data_.o.capacity = count; SetMembersPointer(lm); } break; case kArrayType: { SizeType count = rhs.data_.a.size; GenericValue* le = reinterpret_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue))); const GenericValue<Encoding,SourceAllocator>* re = rhs.GetElementsPointer(); for (SizeType i = 0; i < count; i++) new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); data_.f.flags = kArrayFlag; data_.a.size = data_.a.capacity = count; SetElementsPointer(le); } break; case kStringType: if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast<const Data*>(&rhs.data_); } else SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); break; default: data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast<const Data*>(&rhs.data_); break; } } //! Constructor for boolean value. /*! \param b Boolean value \note This constructor is limited to \em real boolean values and rejects implicitly converted types like arbitrary pointers. Use an explicit cast to \c bool, if you want to construct a boolean JSON value in such cases. */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template <typename T> explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472 #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif : data_() { // safe-guard against failing SFINAE RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value)); data_.f.flags = b ? kTrueFlag : kFalseFlag; } //! Constructor for int value. explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i; data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; } //! Constructor for unsigned value. explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u; data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); } //! Constructor for int64_t value. explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i64; data_.f.flags = kNumberInt64Flag; if (i64 >= 0) { data_.f.flags |= kNumberUint64Flag; if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for uint64_t value. explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u64; data_.f.flags = kNumberUint64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) data_.f.flags |= kInt64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } //! Constructor for float value. explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } //! Constructor for constant string (i.e. do not make a copy of string) explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #endif //! Constructor for Array. /*! \param a An array obtained by \c GetArray(). \note \c Array is always pass-by-value. \note the source array is moved into this value and the sourec array becomes empty. */ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { a.value_.data_ = Data(); a.value_.data_.f.flags = kArrayFlag; } //! Constructor for Object. /*! \param o An object obtained by \c GetObject(). \note \c Object is always pass-by-value. \note the source object is moved into this value and the sourec object becomes empty. */ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { o.value_.data_ = Data(); o.value_.data_.f.flags = kObjectFlag; } //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); Allocator::Free(e); } break; case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); Allocator::Free(GetMembersPointer()); break; case kCopyStringFlag: Allocator::Free(const_cast<Ch*>(GetStringPointer())); break; default: break; // Do nothing for other types. } } } //@} //!@name Assignment operators //@{ //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { if (RAPIDJSON_LIKELY(this != &rhs)) { this->~GenericValue(); RawAssign(rhs); } return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { return *this = rhs.Move(); } #endif //! Assignment of constant string reference (no copy) /*! \param str Constant string reference to be assigned \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. \see GenericStringRef, operator=(T) */ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { GenericValue s(str); return *this = s; } //! Assignment with primitive types. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value The value to be assigned. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref SetString(const Ch*, Allocator&) (for copying) or \ref StringRef() (to explicitly mark the pointer as constant) instead. All other pointer types would implicitly convert to \c bool, use \ref SetBool() instead. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; } //! Deep-copy assignment from Value /*! Assigns a \b copy of the Value to the current Value object \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template <typename SourceAllocator> GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) { RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs)); this->~GenericValue(); new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } //! Exchange the contents of this value with those of other. /*! \param other Another value. \note Constant complexity. */ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { GenericValue temp; temp.RawAssign(*this); RawAssign(other); other.RawAssign(temp); return *this; } //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.value, b.value); // ... } \endcode \see Swap() */ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@} //!@name Equal-to and not-equal-to operators //@{ //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). */ template <typename SourceAllocator> bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const { typedef GenericValue<Encoding, SourceAllocator> RhsType; if (GetType() != rhs.GetType()) return false; switch (GetType()) { case kObjectType: // Warning: O(n^2) inner-loop if (data_.o.size != rhs.data_.o.size) return false; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) return false; } return true; case kArrayType: if (data_.a.size != rhs.data_.a.size) return false; for (SizeType i = 0; i < data_.a.size; i++) if ((*this)[i] != rhs[i]) return false; return true; case kStringType: return StringEqual(rhs); case kNumberType: if (IsDouble() || rhs.IsDouble()) { double a = GetDouble(); // May convert from integer to double. double b = rhs.GetDouble(); // Ditto return a >= b && a <= b; // Prevent -Wfloat-equal } else return data_.n.u64 == rhs.data_.n.u64; default: return true; } } //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } #if RAPIDJSON_HAS_STDSTRING //! Equal-to operator with string object /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); } #endif //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } //! Not-equal-to operator /*! \return !(*this == rhs) */ template <typename SourceAllocator> bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); } //! Not-equal-to operator with const C-string pointer bool operator!=(const Ch* rhs) const { return !(*this == rhs); } //! Not-equal-to operator with arbitrary types /*! \return !(*this == rhs) */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } //! Not-Equal-to operator with arbitrary types (symmetric version) /*! \return !(rhs == lhs) */ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type //@{ Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); } bool IsNull() const { return data_.f.flags == kNullFlag; } bool IsFalse() const { return data_.f.flags == kFalseFlag; } bool IsTrue() const { return data_.f.flags == kTrueFlag; } bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } bool IsObject() const { return data_.f.flags == kObjectFlag; } bool IsArray() const { return data_.f.flags == kArrayFlag; } bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } // Checks whether a number can be losslessly converted to a double. bool IsLosslessDouble() const { if (!IsNumber()) return false; if (IsUint64()) { uint64_t u = GetUint64(); volatile double d = static_cast<double>(u); return (d >= 0.0) && (d < static_cast<double>((std::numeric_limits<uint64_t>::max)())) && (u == static_cast<uint64_t>(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast<double>(i); return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)())) && (d < static_cast<double>((std::numeric_limits<int64_t>::max)())) && (i == static_cast<int64_t>(d)); } return true; // double, int, uint are always lossless } // Checks whether a number is a float (possible lossy). bool IsFloat() const { if ((data_.f.flags & kDoubleFlag) == 0) return false; double d = GetDouble(); return d >= -3.4028234e38 && d <= 3.4028234e38; } // Checks whether a number can be losslessly converted to a float. bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); if (a < static_cast<double>(-(std::numeric_limits<float>::max)()) || a > static_cast<double>((std::numeric_limits<float>::max)())) return false; double b = static_cast<double>(static_cast<float>(a)); return a >= b && a <= b; // Prevent -Wfloat-equal } //@} //!@name Null //@{ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } //@} //!@name Bool //@{ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } //@} //!@name Object //@{ //! Set this value as an empty object. /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } //! Get the capacity of object. SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. Since 0.2, if the name is not correct, it will assert. If user is unsure whether a member exists, user should use HasMember() first. A better approach is to use FindMember(). \note Linear time complexity. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) { GenericValue n(StringRef(name)); return (*this)[n]; } template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam SourceAllocator Allocator of the \c name value \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). And it can also handle strings with embedded null characters. \note Linear time complexity. */ template <typename SourceAllocator> GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) { MemberIterator member = FindMember(name); if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note // This will generate -Wexit-time-destructors in clang // static GenericValue NullValue; // return NullValue; // Use static buffer and placement-new to prevent destruction static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); } } template <typename SourceAllocator> const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; } #if RAPIDJSON_HAS_STDSTRING //! Get a value from an object associated with name (string object). GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; } const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif //! Const member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } //! Request the object to have enough capacity to store members. /*! \param newCapacity The capacity that the object at least need to have. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note Linear time complexity. */ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsObject()); if (newCapacity > data_.o.capacity) { SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); data_.o.capacity = newCapacity; } return *this; } //! Check whether a member exists in the object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } #if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); } #endif //! Check whether a member exists in the object with GenericValue name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ template <typename SourceAllocator> bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); } //! Find member by name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ MemberIterator FindMember(const Ch* name) { GenericValue n(StringRef(name)); return FindMember(n); } ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); } //! Find member by name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); MemberIterator member = MemberBegin(); for ( ; member != MemberEnd(); ++member) if (name.StringEqual(member->name)) break; return member; } template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); } #if RAPIDJSON_HAS_STDSTRING //! Find member by string object name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). */ MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); } ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); } #endif //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c name and \c value will be transferred to this object on success. \pre IsObject() && name.IsString() \post name.IsNull() && value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; if (o.size >= o.capacity) MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); o.size++; return *this; } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Add a string object as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } #endif //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A string value as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) AddMember(GenericValue& name, T value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Add a member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c value will be transferred to this object on success. \pre IsObject() \post value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A constant string reference as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Remove all members in the object. /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. \note Linear time complexity. */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); data_.o.size = 0; } //! Remove a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Linear time complexity. */ bool RemoveMember(const Ch* name) { GenericValue n(StringRef(name)); return RemoveMember(n); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif template <typename SourceAllocator> bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { RemoveMember(m); return true; } else return false; } //! Remove a member in object by iterator. /*! \param m member iterator (obtained by FindMember() or MemberBegin()). \return the new iterator after removal. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Constant time complexity. */ MemberIterator RemoveMember(MemberIterator m) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) *m = *last; // Move the last one to this place else m->~Member(); // Only one left, just destroy --data_.o.size; return m; } //! Remove a member from an object by iterator. /*! \param pos iterator to the member to remove \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() \return Iterator following the removed element. If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. \note This function preserves the relative order of the remaining object members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator pos) { return EraseMember(pos, pos +1); } //! Remove members in the range [first, last) from an object. /*! \param first iterator to the first member to remove \param last iterator following the last member to remove \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() \return Iterator following the last removed element. \note This function preserves the relative order of the remaining object members. \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member)); data_.o.size -= static_cast<SizeType>(last - first); return pos; } //! Erase a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note Linear time complexity. */ bool EraseMember(const Ch* name) { GenericValue n(StringRef(name)); return EraseMember(n); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); } #endif template <typename SourceAllocator> bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { EraseMember(m); return true; } else return false; } Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} //!@name Array //@{ //! Set this value as an empty array. /*! \post IsArray == true */ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } //! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. \note Linear time complexity. */ void Clear() { RAPIDJSON_ASSERT(IsArray()); GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); data_.a.size = 0; } //! Get an element from array by index. /*! \pre IsArray() == true \param index Zero-based index of element. \see operator[](T*) */ GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); return GetElementsPointer()[index]; } const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; } //! Element iterator /*! \pre IsArray() == true */ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); } //! Constant \em past-the-end element iterator /*! \pre IsArray() == true */ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); } //! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note Linear time complexity. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); data_.a.capacity = newCapacity; } return *this; } //! Append a GenericValue at the end of the array. /*! \param value Value to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \post value.IsNull() == true \return The value itself for fluent API. \note The ownership of \c value will be transferred to this array on success. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); GetElementsPointer()[data_.a.size++].RawAssign(value); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { return PushBack(value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Append a constant string reference at the end of the array. /*! \param value Constant string reference to be appended. \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. \see GenericStringRef */ GenericValue& PushBack(StringRefType value, Allocator& allocator) { return (*this).template PushBack<StringRefType>(value, allocator); } //! Append a primitive value at the end of the array. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value Value of primitive type T to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref PushBack(GenericValue&, Allocator&) or \ref PushBack(StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized constant time complexity. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); } //! Remove the last element in the array. /*! \note Constant time complexity. */ GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); GetElementsPointer()[--data_.a.size].~GenericValue(); return *this; } //! Remove an element of array by iterator. /*! \param pos iterator to the element to remove \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1); } //! Remove elements in the range [first, last) of the array. /*! \param first iterator to the first element to remove \param last iterator following the last element to remove \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() \return Iterator following the last removed element. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(data_.a.size > 0); RAPIDJSON_ASSERT(GetElementsPointer() != 0); RAPIDJSON_ASSERT(first >= Begin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue)); data_.a.size -= static_cast<SizeType>(last - first); return pos; } Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } //@} //!@name Number //@{ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } //! Get the value as double type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. */ double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision) RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision) } //! Get the value as float type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. */ float GetFloat() const { return static_cast<float>(GetDouble()); } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; } //@} //!@name String //@{ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string pointer. \param length The length of source string, excluding the trailing null terminator. \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == length \see SetString(StringRefType) */ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } //! Set this value as a string without copying source string. /*! \param s source string reference \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == s.length */ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } //! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string. \param length The length of source string, excluding the trailing null terminator. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string reference \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} //!@name Array //@{ //! Templated version for checking whether this value is type T. /*! \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch> */ template <typename T> bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); } template <typename T> T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); } template <typename T> T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); } template<typename T> ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); } template<typename T> ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); } //@} //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. It can also be used to deep clone this value via GenericDocument, which is also a Handler. \tparam Handler type of handler. \param handler An object implementing concept Handler. */ template <typename Handler> bool Accept(Handler& handler) const { switch(GetType()) { case kNullType: return handler.Null(); case kFalseType: return handler.Bool(false); case kTrueType: return handler.Bool(true); case kObjectType: if (RAPIDJSON_UNLIKELY(!handler.StartObject())) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) return false; if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) return false; } return handler.EndObject(data_.o.size); case kArrayType: if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; for (const GenericValue* v = Begin(); v != End(); ++v) if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); case kStringType: return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsDouble()) return handler.Double(data_.n.d); else if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); else return handler.Uint64(data_.n.u64); } } private: template <typename, typename> friend class GenericValue; template <typename, typename, typename> friend class GenericDocument; enum { kBoolFlag = 0x0008, kNumberFlag = 0x0010, kIntFlag = 0x0020, kUintFlag = 0x0040, kInt64Flag = 0x0080, kUint64Flag = 0x0100, kDoubleFlag = 0x0200, kStringFlag = 0x0400, kCopyFlag = 0x0800, kInlineStrFlag = 0x1000, // Initial flags of different types. kNullFlag = kNullType, // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types. kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag), kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag), kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag), kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag), kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag), kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag), kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag), kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag), kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag), kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag), kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag), kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0x07 }; static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer #elif RAPIDJSON_64BIT char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes #else char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes #endif uint16_t flags; }; struct String { SizeType length; SizeType hashcode; //!< reserved const Ch* str; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars // (excluding the terminating zero) and store a value to determine the length of the contained // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). struct ShortString { enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; inline static bool Usable(SizeType len) { return (MaxSize >= len); } inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); } inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; }i; struct U { unsigned u; char padding2[4]; }u; #else struct I { char padding[4]; int i; }i; struct U { char padding2[4]; unsigned u; }u; #endif int64_t i64; uint64_t u64; double d; }; // 8 bytes struct ObjectData { SizeType size; SizeType capacity; Member* members; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode struct ArrayData { SizeType size; SizeType capacity; GenericValue* elements; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; ShortString ss; Number n; ObjectData o; ArrayData a; Flag f; }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; if (count) { GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue)); } else SetElementsPointer(0); data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member))); SetMembersPointer(m); std::memcpy(static_cast<void*>(m), members, count * sizeof(Member)); } else SetMembersPointer(0); data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { data_.f.flags = kConstStringFlag; SetStringPointer(s); data_.s.length = s.length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(StringRefType s, Allocator& allocator) { Ch* str = 0; if (ShortString::Usable(s.length)) { data_.f.flags = kShortStringFlag; data_.ss.SetLength(s.length); str = data_.ss.str; } else { data_.f.flags = kCopyStringFlag; data_.s.length = s.length; str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch))); SetStringPointer(str); } std::memcpy(str, s, s.length * sizeof(Ch)); str[s.length] = '\0'; } //! Assignment without calling destructor void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; // data_.f.flags = rhs.data_.f.flags; rhs.data_.f.flags = kNullFlag; } template <typename SourceAllocator> bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const { RAPIDJSON_ASSERT(IsString()); RAPIDJSON_ASSERT(rhs.IsString()); const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); if(len1 != len2) { return false; } const Ch* const str1 = GetString(); const Ch* const str2 = rhs.GetString(); if(str1 == str2) { return true; } // fast path for constant string return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); } Data data_; }; //! GenericValue with UTF8 encoding typedef GenericValue<UTF8<> > Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument //! A document for parsing JSON text as DOM. /*! \note implements Handler concept \tparam Encoding Encoding for both parsing and string storage. \tparam Allocator Allocator for allocating memory for the DOM \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR, typename StackAllocator = RAPIDJSON_DEFAULT_STACK_ALLOCATOR > class GenericDocument : public GenericValue<Encoding, Allocator> { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. \param type Mandatory type of object to create. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } //! Constructor /*! Creates an empty document which type is Null. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(std::move(rhs.stack_)), parseResult_(rhs.parseResult_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); } #endif ~GenericDocument() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT { // The cast to ValueType is necessary here, because otherwise it would // attempt to call GenericValue's templated assignment operator. ValueType::operator=(std::forward<ValueType>(rhs)); // Calling the destructor here would prematurely call stack_'s destructor Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = std::move(rhs.stack_); parseResult_ = rhs.parseResult_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); return *this; } #endif //! Exchange the contents of this document with those of another. /*! \param rhs Another document. \note Constant complexity. \see GenericValue::Swap */ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { ValueType::Swap(rhs); stack_.Swap(rhs.stack_); internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(parseResult_, rhs.parseResult_); return *this; } // Allow Swap with ValueType. // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. using ValueType::Swap; //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.doc, b.doc); // ... } \endcode \see Swap() */ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Populate this document by a generator which produces SAX events. /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype. \param g Generator functor which sends SAX events to the parameter. \return The document itself for fluent API. */ template <typename Generator> GenericDocument& Populate(Generator& g) { ClearStackOnExit scope(*this); if (g(*this)) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document } return *this; } //!@name Parse from stream //!@{ //! Parse JSON text from an input stream (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam SourceEncoding Encoding of input stream \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template <unsigned parseFlags, typename SourceEncoding, typename InputStream> GenericDocument& ParseStream(InputStream& is) { GenericReader<SourceEncoding, Encoding, StackAllocator> reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse<parseFlags>(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document } return *this; } //! Parse JSON text from an input stream /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template <unsigned parseFlags, typename InputStream> GenericDocument& ParseStream(InputStream& is) { return ParseStream<parseFlags, Encoding, InputStream>(is); } //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template <typename InputStream> GenericDocument& ParseStream(InputStream& is) { return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is); } //!@} //!@name Parse in-place from mutable string //!@{ //! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ template <unsigned parseFlags> GenericDocument& ParseInsitu(Ch* str) { GenericInsituStringStream<Encoding> s(str); return ParseStream<parseFlags | kParseInsituFlag>(s); } //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) /*! \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ GenericDocument& ParseInsitu(Ch* str) { return ParseInsitu<kParseDefaultFlags>(str); } //!@} //!@name Parse from read-only string //!@{ //! Parse JSON text from a read-only string (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \tparam SourceEncoding Transcoding from input Encoding \param str Read-only zero-terminated string to be parsed. */ template <unsigned parseFlags, typename SourceEncoding> GenericDocument& Parse(const typename SourceEncoding::Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream<SourceEncoding> s(str); return ParseStream<parseFlags, SourceEncoding>(s); } //! Parse JSON text from a read-only string /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. */ template <unsigned parseFlags> GenericDocument& Parse(const Ch* str) { return Parse<parseFlags, Encoding>(str); } //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) /*! \param str Read-only zero-terminated string to be parsed. */ GenericDocument& Parse(const Ch* str) { return Parse<kParseDefaultFlags>(str); } template <unsigned parseFlags, typename SourceEncoding> GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream<SourceEncoding, MemoryStream> is(ms); ParseStream<parseFlags, SourceEncoding>(is); return *this; } template <unsigned parseFlags> GenericDocument& Parse(const Ch* str, size_t length) { return Parse<parseFlags, Encoding>(str, length); } GenericDocument& Parse(const Ch* str, size_t length) { return Parse<kParseDefaultFlags>(str, length); } #if RAPIDJSON_HAS_STDSTRING template <unsigned parseFlags, typename SourceEncoding> GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) { // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) return Parse<parseFlags, SourceEncoding>(str.c_str()); } template <unsigned parseFlags> GenericDocument& Parse(const std::basic_string<Ch>& str) { return Parse<parseFlags, Encoding>(str.c_str()); } GenericDocument& Parse(const std::basic_string<Ch>& str) { return Parse<kParseDefaultFlags>(str); } #endif // RAPIDJSON_HAS_STDSTRING //!@} //!@name Handling parse errors //!@{ //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseError() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation /*! \return \ref ParseResult of the last parse operation \code Document doc; ParseResult ok = doc.Parse(json); if (!ok) printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); \endcode */ #endif operator ParseResult() const { return parseResult_; } //!@} //! Get the allocator of this document. Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} ~ClearStackOnExit() { d_.ClearStack(); } private: ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); GenericDocument& d_; }; // callers of the following private Handler functions // template <typename,typename,typename> friend class GenericReader; // for parsing template <typename, typename> friend class GenericValue; // for deep copying public: // Implementation of Handler bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; } bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; } bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; } bool RawNumber(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator()); else new (stack_.template Push<ValueType>()) ValueType(str, length); return true; } bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator()); else new (stack_.template Push<ValueType>()) ValueType(str, length); return true; } bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; } bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount); stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator()); return true; } bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; } bool EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop<ValueType>(elementCount); stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator()); return true; } private: //! Prohibit copying GenericDocument(const GenericDocument&); //! Prohibit assignment GenericDocument& operator=(const GenericDocument&); void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) (stack_.template Pop<ValueType>(1))->~ValueType(); else stack_.Clear(); stack_.ShrinkToFit(); } void Destroy() { RAPIDJSON_DELETE(ownAllocator_); } static const size_t kDefaultStackCapacity = 1024; Allocator* allocator_; Allocator* ownAllocator_; internal::Stack<StackAllocator> stack_; ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding typedef GenericDocument<UTF8<> > Document; //! Helper class for accessing Value of array type. /*! Instance of this helper class is obtained by \c GenericValue::GetArray(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template <bool Const, typename ValueT> class GenericArray { public: typedef GenericArray<true, ValueT> ConstArray; typedef GenericArray<false, ValueT> Array; typedef ValueT PlainType; typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; typedef ValueType* ValueIterator; // This may be const or non-const iterator typedef const ValueT* ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; template <typename, typename> friend class GenericValue; GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} operator ValueType&() const { return value_; } SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } bool Empty() const { return value_.Empty(); } void Clear() const { value_.Clear(); } ValueType& operator[](SizeType index) const { return value_[index]; } ValueIterator Begin() const { return value_.Begin(); } ValueIterator End() const { return value_.End(); } GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } GenericArray PopBack() const { value_.PopBack(); return *this; } ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR ValueIterator begin() const { return value_.Begin(); } ValueIterator end() const { return value_.End(); } #endif private: GenericArray(); GenericArray(ValueType& value) : value_(value) {} ValueType& value_; }; //! Helper class for accessing Value of object type. /*! Instance of this helper class is obtained by \c GenericValue::GetObject(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template <bool Const, typename ValueT> class GenericObject { public: typedef GenericObject<true, ValueT> ConstObject; typedef GenericObject<false, ValueT> Object; typedef ValueT PlainType; typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; typedef typename ValueType::EncodingType EncodingType; typedef typename ValueType::Ch Ch; template <typename, typename> friend class GenericValue; GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} operator ValueType&() const { return value_; } SizeType MemberCount() const { return value_.MemberCount(); } SizeType MemberCapacity() const { return value_.MemberCapacity(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template <typename T> ValueType& operator[](T* name) const { return value_[name]; } template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; } #if RAPIDJSON_HAS_STDSTRING ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; } #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); } #endif template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); } MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); } #if RAPIDJSON_HAS_STDSTRING MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); } #endif GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } void RemoveAllMembers() { value_.RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); } #endif template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); } MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); } #endif template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR MemberIterator begin() const { return value_.MemberBegin(); } MemberIterator end() const { return value_.MemberEnd(); } #endif private: GenericObject(); GenericObject(ValueType& value) : value_(value) {} ValueType& value_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_DOCUMENT_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/encodedstream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ #include "stream.h" #include "memorystream.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam InputByteStream Type of input byte stream. For example, FileReadStream. */ template <typename Encoding, typename InputByteStream> class EncodedInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedInputStream(InputByteStream& is) : is_(is) { current_ = Encoding::TakeBOM(is_); } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); InputByteStream& is_; Ch current_; }; //! Specialized for UTF8 MemoryStream. template <> class EncodedInputStream<UTF8<>, MemoryStream> { public: typedef UTF8<>::Ch Ch; EncodedInputStream(MemoryStream& is) : is_(is) { if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take(); if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take(); if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take(); } Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) {} void Flush() {} Ch* PutBegin() { return 0; } size_t PutEnd(Ch*) { return 0; } MemoryStream& is_; private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); }; //! Output byte stream wrapper with statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. */ template <typename Encoding, typename OutputByteStream> class EncodedOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { if (putBOM) Encoding::PutBOM(os_); } void Put(Ch c) { Encoding::Put(os_, c); } void Flush() { os_.Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedOutputStream(const EncodedOutputStream&); EncodedOutputStream& operator=(const EncodedOutputStream&); OutputByteStream& os_; }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x //! Input stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for reading. \tparam InputByteStream type of input byte stream to be wrapped. */ template <typename CharType, typename InputByteStream> class AutoUTFInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param is input stream to be wrapped. \param type UTF encoding type if it is not detected from the stream. */ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; current_ = takeFunc_(*is_); } UTFType GetType() const { return type_; } bool HasBOM() const { return hasBOM_; } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } size_t Tell() const { return is_->Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFInputStream(const AutoUTFInputStream&); AutoUTFInputStream& operator=(const AutoUTFInputStream&); // Detect encoding type with BOM or RFC 4627 void DetectType() { // BOM (Byte Order Mark): // 00 00 FE FF UTF-32BE // FF FE 00 00 UTF-32LE // FE FF UTF-16BE // FF FE UTF-16LE // EF BB BF UTF-8 const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4()); if (!c) return; unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); hasBOM_ = false; if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } // RFC 4627: Section 3 // "Since the first two characters of a JSON text will always be ASCII // characters [RFC0020], it is possible to determine whether an octet // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking // at the pattern of nulls in the first four octets." // 00 00 00 xx UTF-32BE // 00 xx 00 xx UTF-16BE // xx 00 00 00 UTF-32LE // xx 00 xx 00 UTF-16LE // xx xx xx xx UTF-8 if (!hasBOM_) { int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; case 0x01: type_ = kUTF32LE; break; case 0x05: type_ = kUTF16LE; break; case 0x0F: type_ = kUTF8; break; default: break; // Use type defined by user. } } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); } typedef Ch (*TakeFunc)(InputByteStream& is); InputByteStream* is_; UTFType type_; Ch current_; TakeFunc takeFunc_; bool hasBOM_; }; //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. \tparam OutputByteStream type of output byte stream to be wrapped. */ template <typename CharType, typename OutputByteStream> class AutoUTFOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param os output stream to be wrapped. \param type UTF encoding type. \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; if (putBOM) PutBOM(); } UTFType GetType() const { return type_; } void Put(Ch c) { putFunc_(*os_, c); } void Flush() { os_->Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFOutputStream(const AutoUTFOutputStream&); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); void PutBOM() { typedef void (*PutBOMFunc)(OutputByteStream&); static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; f[type_](*os_); } typedef void (*PutFunc)(OutputByteStream&, Ch); OutputByteStream* os_; UTFType type_; PutFunc putFunc_; }; #undef RAPIDJSON_ENCODINGS_FUNC RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/encodings.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_ #include "rapidjson.h" #if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code #elif defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(overflow) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Encoding /*! \class rapidjson::Encoding \brief Concept for encoding of Unicode characters. \code concept Encoding { typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. enum { supportUnicode = 1 }; // or 0 if not supporting unicode //! \brief Encode a Unicode codepoint to an output stream. //! \param os Output stream. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. template<typename OutputStream> static void Encode(OutputStream& os, unsigned codepoint); //! \brief Decode a Unicode codepoint from an input stream. //! \param is Input stream. //! \param codepoint Output of the unicode codepoint. //! \return true if a valid codepoint can be decoded from the stream. template <typename InputStream> static bool Decode(InputStream& is, unsigned* codepoint); //! \brief Validate one Unicode codepoint from an encoded stream. //! \param is Input stream to obtain codepoint. //! \param os Output for copying one codepoint. //! \return true if it is valid. //! \note This function just validating and copying the codepoint without actually decode it. template <typename InputStream, typename OutputStream> static bool Validate(InputStream& is, OutputStream& os); // The following functions are deal with byte streams. //! Take a character from input byte stream, skip BOM if exist. template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is); //! Take a character from input byte stream. template <typename InputByteStream> static Ch Take(InputByteStream& is); //! Put BOM to output byte stream. template <typename OutputByteStream> static void PutBOM(OutputByteStream& os); //! Put a character to output byte stream. template <typename OutputByteStream> static void Put(OutputByteStream& os, Ch c); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // UTF8 //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 http://tools.ietf.org/html/rfc3629 \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. \note implements Encoding concept */ template<typename CharType = char> struct UTF8 { typedef CharType Ch; enum { supportUnicode = 1 }; template<typename OutputStream> static void Encode(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) os.Put(static_cast<Ch>(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F))); os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); } } template<typename OutputStream> static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F))); } } template <typename InputStream> static bool Decode(InputStream& is, unsigned* codepoint) { #define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu) #define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = static_cast<unsigned char>(c); return true; } unsigned char type = GetRange(static_cast<unsigned char>(c)); if (type >= 32) { *codepoint = 0; } else { *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c); } bool result = true; switch (type) { case 2: RAPIDJSON_TAIL(); return result; case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } #undef RAPIDJSON_COPY #undef RAPIDJSON_TRANS #undef RAPIDJSON_TAIL } template <typename InputStream, typename OutputStream> static bool Validate(InputStream& is, OutputStream& os) { #define RAPIDJSON_COPY() os.Put(c = is.Take()) #define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) Ch c; RAPIDJSON_COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast<unsigned char>(c))) { case 2: RAPIDJSON_TAIL(); return result; case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } #undef RAPIDJSON_COPY #undef RAPIDJSON_TRANS #undef RAPIDJSON_TAIL } static unsigned char GetRange(unsigned char c) { // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. static const unsigned char type[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, }; return type[c]; } template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); typename InputByteStream::Ch c = Take(is); if (static_cast<unsigned char>(c) != 0xEFu) return c; c = is.Take(); if (static_cast<unsigned char>(c) != 0xBBu) return c; c = is.Take(); if (static_cast<unsigned char>(c) != 0xBFu) return c; c = is.Take(); return c; } template <typename InputByteStream> static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast<Ch>(is.Take()); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu)); } template <typename OutputByteStream> static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(c)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF16 //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 http://tools.ietf.org/html/rfc2781 \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness. */ template<typename CharType = wchar_t> struct UTF16 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); enum { supportUnicode = 1 }; template<typename OutputStream> static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair os.Put(static_cast<typename OutputStream::Ch>(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00)); } } template<typename OutputStream> static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00)); } } template <typename InputStream> static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { *codepoint = static_cast<unsigned>(c); return true; } else if (c <= 0xDBFF) { *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10; c = is.Take(); *codepoint |= (static_cast<unsigned>(c) & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } return false; } template <typename InputStream, typename OutputStream> static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); typename InputStream::Ch c; os.Put(static_cast<typename OutputStream::Ch>(c = is.Take())); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { os.Put(c = is.Take()); return c >= 0xDC00 && c <= 0xDFFF; } return false; } }; //! UTF-16 little endian encoding. template<typename CharType = wchar_t> struct UTF16LE : UTF16<CharType> { template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c; } template <typename InputByteStream> static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast<uint8_t>(is.Take()); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; return static_cast<CharType>(c); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); } template <typename OutputByteStream> static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu)); } }; //! UTF-16 big endian encoding. template<typename CharType = wchar_t> struct UTF16BE : UTF16<CharType> { template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c; } template <typename InputByteStream> static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())); return static_cast<CharType>(c); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); } template <typename OutputByteStream> static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF32 //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness. */ template<typename CharType = unsigned> struct UTF32 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); enum { supportUnicode = 1 }; template<typename OutputStream> static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(codepoint); } template<typename OutputStream> static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, codepoint); } template <typename InputStream> static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c = is.Take(); *codepoint = c; return c <= 0x10FFFF; } template <typename InputStream, typename OutputStream> static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c; os.Put(c = is.Take()); return c <= 0x10FFFF; } }; //! UTF-32 little endian enocoding. template<typename CharType = unsigned> struct UTF32LE : UTF32<CharType> { template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; } template <typename InputByteStream> static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast<uint8_t>(is.Take()); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24; return static_cast<CharType>(c); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); } template <typename OutputByteStream> static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu)); } }; //! UTF-32 big endian encoding. template<typename CharType = unsigned> struct UTF32BE : UTF32<CharType> { template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; } template <typename InputByteStream> static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())); return static_cast<CharType>(c); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu)); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu)); } template <typename OutputByteStream> static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu)); os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // ASCII //! ASCII encoding. /*! http://en.wikipedia.org/wiki/ASCII \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. \note implements Encoding concept */ template<typename CharType = char> struct ASCII { typedef CharType Ch; enum { supportUnicode = 0 }; template<typename OutputStream> static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); os.Put(static_cast<Ch>(codepoint & 0xFF)); } template<typename OutputStream> static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); } template <typename InputStream> static bool Decode(InputStream& is, unsigned* codepoint) { uint8_t c = static_cast<uint8_t>(is.Take()); *codepoint = c; return c <= 0X7F; } template <typename InputStream, typename OutputStream> static bool Validate(InputStream& is, OutputStream& os) { uint8_t c = static_cast<uint8_t>(is.Take()); os.Put(static_cast<typename OutputStream::Ch>(c)); return c <= 0x7F; } template <typename InputByteStream> static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); uint8_t c = static_cast<uint8_t>(Take(is)); return static_cast<Ch>(c); } template <typename InputByteStream> static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast<Ch>(is.Take()); } template <typename OutputByteStream> static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); (void)os; } template <typename OutputByteStream> static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast<typename OutputByteStream::Ch>(c)); } }; /////////////////////////////////////////////////////////////////////////////// // AutoUTF //! Runtime-specified UTF encoding type of a stream. enum UTFType { kUTF8 = 0, //!< UTF-8. kUTF16LE = 1, //!< UTF-16 little endian. kUTF16BE = 2, //!< UTF-16 big endian. kUTF32LE = 3, //!< UTF-32 little endian. kUTF32BE = 4 //!< UTF-32 big endian. }; //! Dynamically select encoding according to stream's runtime-specified UTF encoding type. /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). */ template<typename CharType> struct AutoUTF { typedef CharType Ch; enum { supportUnicode = 1 }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x template<typename OutputStream> static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template<typename OutputStream> static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template <typename InputStream> static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template <typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); } #undef RAPIDJSON_ENCODINGS_FUNC }; /////////////////////////////////////////////////////////////////////////////// // Transcoder //! Encoding conversion. template<typename SourceEncoding, typename TargetEncoding> struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::Encode(os, codepoint); return true; } template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::EncodeUnsafe(os, codepoint); return true; } //! Validate one Unicode codepoint from an encoded stream. template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; // Forward declaration. template<typename Stream> inline void PutUnsafe(Stream& stream, typename Stream::Ch c); //! Specialization of Transcoder with same source and target encoding. template<typename Encoding> struct Transcoder<Encoding, Encoding> { template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ENCODINGS_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/error/en.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_EN_H_ #define RAPIDJSON_ERROR_EN_H_ #include "error.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(covered-switch-default) #endif RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. /*! \ingroup RAPIDJSON_ERRORS \param parseErrorCode Error code obtained in parsing. \return the error message. \note User can make a copy of this function for localization. Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { switch (parseErrorCode) { case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } //! Maps error code of validation into error message. /*! \ingroup RAPIDJSON_ERRORS \param validateErrorCode Error code obtained from validator. \return the error message. \note User can make a copy of this function for localization. Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { switch (validateErrorCode) { case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_EN_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/error/error.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ERROR_ERROR_H_ #define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_CHARTYPE //! Character type of error messages. /*! \ingroup RAPIDJSON_ERRORS The default character type is \c char. On Windows, user can define this macro as \c TCHAR for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_CHARTYPE #define RAPIDJSON_ERROR_CHARTYPE char #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_STRING #define RAPIDJSON_ERROR_STRING(x) x #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseErrorCode //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { kParseErrorNone = 0, //!< No error. kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorValueInvalid, //!< Invalid value. kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorTermination, //!< Parsing was terminated. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. }; //! Result of parsing (wraps ParseErrorCode) /*! \ingroup RAPIDJSON_ERRORS \code Document doc; ParseResult ok = doc.Parse("[42]"); if (!ok) { fprintf(stderr, "JSON parse error: %s (%u)", GetParseError_En(ok.Code()), ok.Offset()); exit(EXIT_FAILURE); } \endcode \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { //!! Unspecified boolean type typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } bool operator!=(const ParseResult& that) const { return !(*this == that); } bool operator!=(ParseErrorCode code) const { return !(*this == code); } friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: ParseErrorCode code_; size_t offset_; }; //! Function pointer type of GetParseError(). /*! \ingroup RAPIDJSON_ERRORS This is the prototype for \c GetParseError_X(), where \c X is a locale. User can dynamically change locale in runtime, e.g.: \code GetParseErrorFunc GetParseError = GetParseError_En; // or whatever const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); /////////////////////////////////////////////////////////////////////////////// // ValidateErrorCode //! Error codes when validating. /*! \ingroup RAPIDJSON_ERRORS \see GenericSchemaValidator */ enum ValidateErrorCode { kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. kValidateErrorNone = 0, //!< No error. kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. kValidateErrorMinimum, //!< Number is less than the 'minimum' value. kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. kValidateErrorRequired, //!< Object is missing one or more members required by the schema. kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. kValidateErrorPatternProperties, //!< See other errors. kValidateErrorDependencies, //!< Object has missing property or schema dependencies. kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values kValidateErrorType, //!< Property has a type that is not allowed by the schema.. kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. }; //! Function pointer type of GetValidateError(). /*! \ingroup RAPIDJSON_ERRORS This is the prototype for \c GetValidateError_X(), where \c X is a locale. User can dynamically change locale in runtime, e.g.: \code GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode()); \endcode */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_ERROR_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/filereadstream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ #include "stream.h" #include <cstdio> #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). /*! \note implements Stream concept */ class FileReadStream { public: typedef char Ch; //!< Character type (byte). //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } Ch Peek() const { return *current_; } Ch Take() { Ch c = *current_; Read(); return c; } size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: void Read() { if (current_ < bufferLast_) ++current_; else if (!eof_) { count_ += readCount_; readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; if (readCount_ < bufferSize_) { buffer_[readCount_] = '\0'; ++bufferLast_; eof_ = true; } } } std::FILE* fp_; Ch *buffer_; size_t bufferSize_; Ch *bufferLast_; Ch *current_; size_t readCount_; size_t count_; //!< Number of characters read bool eof_; }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/filewritestream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ #include "stream.h" #include <cstdio> #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for output using fwrite(). /*! \note implements Stream concept */ class FileWriteStream { public: typedef char Ch; //!< Character type. Only support char. FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { RAPIDJSON_ASSERT(fp_ != 0); } void Put(char c) { if (current_ >= bufferEnd_) Flush(); *current_++ = c; } void PutN(char c, size_t n) { size_t avail = static_cast<size_t>(bufferEnd_ - current_); while (n > avail) { std::memset(current_, c, avail); current_ += avail; Flush(); n -= avail; avail = static_cast<size_t>(bufferEnd_ - current_); } if (n > 0) { std::memset(current_, c, n); current_ += n; } } void Flush() { if (current_ != buffer_) { size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); if (result < static_cast<size_t>(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors } current_ = buffer_; } } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: // Prohibit copy constructor & assignment operator. FileWriteStream(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&); std::FILE* fp_; char *buffer_; char *bufferEnd_; char *current_; }; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(FileWriteStream& stream, char c, size_t n) { stream.PutN(c, n); } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/fwd.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_FWD_H_ #define RAPIDJSON_FWD_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN // encodings.h template<typename CharType> struct UTF8; template<typename CharType> struct UTF16; template<typename CharType> struct UTF16BE; template<typename CharType> struct UTF16LE; template<typename CharType> struct UTF32; template<typename CharType> struct UTF32BE; template<typename CharType> struct UTF32LE; template<typename CharType> struct ASCII; template<typename CharType> struct AutoUTF; template<typename SourceEncoding, typename TargetEncoding> struct Transcoder; // allocators.h class CrtAllocator; template <typename BaseAllocator> class MemoryPoolAllocator; // stream.h template <typename Encoding> struct GenericStringStream; typedef GenericStringStream<UTF8<char> > StringStream; template <typename Encoding> struct GenericInsituStringStream; typedef GenericInsituStringStream<UTF8<char> > InsituStringStream; // stringbuffer.h template <typename Encoding, typename Allocator> class GenericStringBuffer; typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer; // filereadstream.h class FileReadStream; // filewritestream.h class FileWriteStream; // memorybuffer.h template <typename Allocator> struct GenericMemoryBuffer; typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer; // memorystream.h struct MemoryStream; // reader.h template<typename Encoding, typename Derived> struct BaseReaderHandler; template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator> class GenericReader; typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader; // writer.h template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags> class Writer; // prettywriter.h template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags> class PrettyWriter; // document.h template <typename Encoding, typename Allocator> class GenericMember; template <bool Const, typename Encoding, typename Allocator> class GenericMemberIterator; template<typename CharType> struct GenericStringRef; template <typename Encoding, typename Allocator> class GenericValue; typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value; template <typename Encoding, typename Allocator, typename StackAllocator> class GenericDocument; typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document; // pointer.h template <typename ValueType, typename Allocator> class GenericPointer; typedef GenericPointer<Value, CrtAllocator> Pointer; // schema.h template <typename SchemaDocumentType> class IGenericRemoteSchemaDocumentProvider; template <typename ValueT, typename Allocator> class GenericSchemaDocument; typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument; typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider; template < typename SchemaDocumentType, typename OutputHandler, typename StateAllocator> class GenericSchemaValidator; typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSONFWD_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/biginteger.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_BIGINTEGER_H_ #define RAPIDJSON_BIGINTEGER_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include <intrin.h> // for _umul128 #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { class BigInteger { public: typedef uint64_t Type; BigInteger(const BigInteger& rhs) : count_(rhs.count_) { std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; } BigInteger(const char* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 while (length >= kMaxDigitPerIteration) { AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); length -= kMaxDigitPerIteration; i += kMaxDigitPerIteration; } if (length > 0) AppendDecimal64(decimals + i, decimals + i + length); } BigInteger& operator=(const BigInteger &rhs) { if (this != &rhs) { count_ = rhs.count_; std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } return *this; } BigInteger& operator=(uint64_t u) { digits_[0] = u; count_ = 1; return *this; } BigInteger& operator+=(uint64_t u) { Type backup = digits_[0]; digits_[0] += u; for (size_t i = 0; i < count_ - 1; i++) { if (digits_[i] >= backup) return *this; // no carry backup = digits_[i + 1]; digits_[i + 1] += 1; } // Last carry if (digits_[count_ - 1] < backup) PushBack(1); return *this; } BigInteger& operator*=(uint64_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { uint64_t hi; digits_[i] = MulAdd64(digits_[i], u, k, &hi); k = hi; } if (k > 0) PushBack(k); return *this; } BigInteger& operator*=(uint32_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { const uint64_t c = digits_[i] >> 32; const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t uc = u * c; const uint64_t ud = u * d; const uint64_t p0 = ud + k; const uint64_t p1 = uc + (p0 >> 32); digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); k = p1 >> 32; } if (k > 0) PushBack(k); return *this; } BigInteger& operator<<=(size_t shift) { if (IsZero() || shift == 0) return *this; size_t offset = shift / kTypeBit; size_t interShift = shift % kTypeBit; RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); count_ += offset; } else { digits_[count_] = 0; for (size_t i = count_; i > 0; i--) digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); digits_[offset] = digits_[0] << interShift; count_ += offset; if (digits_[count_]) count_++; } std::memset(digits_, 0, offset * sizeof(Type)); return *this; } bool operator==(const BigInteger& rhs) const { return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; } bool operator==(const Type rhs) const { return count_ == 1 && digits_[0] == rhs; } BigInteger& MultiplyPow5(unsigned exp) { static const uint32_t kPow5[12] = { 5, 5 * 5, 5 * 5 * 5, 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 }; if (exp == 0) return *this; for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13 if (exp > 0) *this *= kPow5[exp - 1]; return *this; } // Compute absolute difference of this and rhs. // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } else { a = this; b = &rhs; ret = false; } Type borrow = 0; for (size_t i = 0; i < a->count_; i++) { Type d = a->digits_[i] - borrow; if (i < b->count_) d -= b->digits_[i]; borrow = (d > a->digits_[i]) ? 1 : 0; out->digits_[i] = d; if (d != 0) out->count_ = i + 1; } return ret; } int Compare(const BigInteger& rhs) const { if (count_ != rhs.count_) return count_ < rhs.count_ ? -1 : 1; for (size_t i = count_; i-- > 0;) if (digits_[i] != rhs.digits_[i]) return digits_[i] < rhs.digits_[i] ? -1 : 1; return 0; } size_t GetCount() const { return count_; } Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: void AppendDecimal64(const char* begin, const char* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; else { unsigned exp = static_cast<unsigned>(end - begin); (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u } } void PushBack(Type digit) { RAPIDJSON_ASSERT(count_ < kCapacity); digits_[count_++] = digit; } static uint64_t ParseUint64(const char* begin, const char* end) { uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); r = r * 10u + static_cast<unsigned>(*p - '0'); } return r; } // Assume a * b + k < 2^128 static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t low = _umul128(a, b, outHigh) + k; if (low < k) (*outHigh)++; return low; #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b); p += k; *outHigh = static_cast<uint64_t>(p >> 64); return static_cast<uint64_t>(p); #else const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; x1 += (x0 >> 32); // can't give carry x1 += x2; if (x1 < x2) x3 += (static_cast<uint64_t>(1) << 32); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t hi = x3 + (x1 >> 32); lo += k; if (lo < k) hi++; *outHigh = hi; return lo; #endif } static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kTypeBit = sizeof(Type) * 8; Type digits_[kCapacity]; size_t count_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_BIGINTEGER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/clzll.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_CLZLL_H_ #define RAPIDJSON_CLZLL_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && !defined(UNDER_CE) #include <intrin.h> #if defined(_WIN64) #pragma intrinsic(_BitScanReverse64) #else #pragma intrinsic(_BitScanReverse) #endif #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline uint32_t clzll(uint64_t x) { // Passing 0 to __builtin_clzll is UB in GCC and results in an // infinite loop in the software implementation. RAPIDJSON_ASSERT(x != 0); #if defined(_MSC_VER) && !defined(UNDER_CE) unsigned long r = 0; #if defined(_WIN64) _BitScanReverse64(&r, x); #else // Scan the high 32 bits. if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return 63 - (r + 32); // Scan the low 32 bits. _BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF)); #endif // _WIN64 return 63 - r; #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) // __builtin_clzll wrapper return static_cast<uint32_t>(__builtin_clzll(x)); #else // naive version uint32_t r = 0; while (!(x & (static_cast<uint64_t>(1) << 63))) { x <<= 1; ++r; } return r; #endif // _MSC_VER } #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_CLZLL_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/diyfp.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" #include "clzll.h" #include <limits> #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include <intrin.h> #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif struct DiyFp { DiyFp() : f(), e() {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} explicit DiyFp(double d) { union { double d; uint64_t u64; } u = { d }; int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize); uint64_t significand = (u.u64 & kDpSignificandMask); if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; } else { f = significand; e = kDpMinExponent + 1; } } DiyFp operator-(const DiyFp& rhs) const { return DiyFp(f - rhs.f, e); } DiyFp operator*(const DiyFp& rhs) const { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t h; uint64_t l = _umul128(f, rhs.f, &h); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f); uint64_t h = static_cast<uint64_t>(p >> 64); uint64_t l = static_cast<uint64_t>(p); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #else const uint64_t M32 = 0xFFFFFFFF; const uint64_t a = f >> 32; const uint64_t b = f & M32; const uint64_t c = rhs.f >> 32; const uint64_t d = rhs.f & M32; const uint64_t ac = a * c; const uint64_t bc = b * c; const uint64_t ad = a * d; const uint64_t bd = b * d; uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); tmp += 1U << 31; /// mult_round return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); #endif } DiyFp Normalize() const { int s = static_cast<int>(clzll(f)); return DiyFp(f << s, e - s); } DiyFp NormalizeBoundary() const { DiyFp res = *this; while (!(res.f & (kDpHiddenBit << 1))) { res.f <<= 1; res.e--; } res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); return res; } void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); mi.f <<= mi.e - pl.e; mi.e = pl.e; *plus = pl; *minus = mi; } double ToDouble() const { union { double d; uint64_t u64; }u; RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); if (e < kDpDenormalExponent) { // Underflow. return 0.0; } if (e >= kDpMaxExponent) { // Overflow. return std::numeric_limits<double>::infinity(); } const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast<uint64_t>(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; } static const int kDiySignificandSize = 64; static const int kDpSignificandSize = 52; static const int kDpExponentBias = 0x3FF + kDpSignificandSize; static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias; static const int kDpDenormalExponent = -kDpExponentBias + 1; static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); uint64_t f; int e; }; inline DiyFp GetCachedPowerByIndex(size_t index) { // 10^-348, 10^-340, ..., 10^340 static const uint64_t kCachedPowers_F[] = { RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) }; static const int16_t kCachedPowers_E[] = { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; RAPIDJSON_ASSERT(index < 87); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast<int>(dk); if (dk - k > 0.0) k++; unsigned index = static_cast<unsigned>((k >> 3) + 1); *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table return GetCachedPowerByIndex(index); } inline DiyFp GetCachedPower10(int exp, int *outExp) { RAPIDJSON_ASSERT(exp >= -348); unsigned index = static_cast<unsigned>(exp + 348) / 8u; *outExp = -348 + static_cast<int>(index) * 8; return GetCachedPowerByIndex(index); } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef __clang__ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_OFF(padded) #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIYFP_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/dtoa.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" #include "ieee754.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 #endif inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer wp_w - rest > rest + ten_kappa - wp_w)) { buffer[len - 1]--; rest += ten_kappa; } } inline int CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; if (n < 1000) return 3; if (n < 10000) return 4; if (n < 100000) return 5; if (n < 1000000) return 6; if (n < 10000000) return 7; if (n < 100000000) return 8; // Will not reach 10 digits in DigitGen() //if (n < 1000000000) return 9; //return 10; return 9; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { uint32_t d = 0; switch (kappa) { case 9: d = p1 / 100000000; p1 %= 100000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break; case 6: d = p1 / 100000; p1 %= 100000; break; case 5: d = p1 / 10000; p1 %= 10000; break; case 4: d = p1 / 1000; p1 %= 1000; break; case 3: d = p1 / 100; p1 %= 100; break; case 2: d = p1 / 10; p1 %= 10; break; case 1: d = p1; p1 = 0; break; default:; } if (d || *len) buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); kappa--; uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); return; } } // kappa = 0 for (;;) { p2 *= 10; delta *= 10; char d = static_cast<char>(p2 >> -one.e); if (d || *len) buffer[(*len)++] = static_cast<char>('0' + d); p2 &= one.f - 1; kappa--; if (p2 < delta) { *K += kappa; int index = -kappa; GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); return; } } } inline void Grisu2(double value, char* buffer, int* length, int* K) { const DiyFp v(value); DiyFp w_m, w_p; v.NormalizedBoundaries(&w_m, &w_p); const DiyFp c_mk = GetCachedPower(w_p.e, K); const DiyFp W = v.Normalize() * c_mk; DiyFp Wp = w_p * c_mk; DiyFp Wm = w_m * c_mk; Wm.f++; Wp.f--; DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); } inline char* WriteExponent(int K, char* buffer) { if (K < 0) { *buffer++ = '-'; K = -K; } if (K >= 100) { *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); K %= 100; const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else if (K >= 10) { const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else *buffer++ = static_cast<char>('0' + static_cast<char>(K)); return buffer; } inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { const int kk = length + k; // 10^(kk-1) <= v < 10^kk if (0 <= k && kk <= 21) { // 1234e7 -> 12340000000 for (int i = length; i < kk; i++) buffer[i] = '0'; buffer[kk] = '.'; buffer[kk + 1] = '0'; return &buffer[kk + 2]; } else if (0 < kk && kk <= 21) { // 1234e-2 -> 12.34 std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); buffer[kk] = '.'; if (0 > k + maxDecimalPlaces) { // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[kk + 2]; // Reserve one zero } else return &buffer[length + 1]; } else if (-6 < kk && kk <= 0) { // 1234e-6 -> 0.001234 const int offset = 2 - kk; std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); buffer[0] = '0'; buffer[1] = '.'; for (int i = 2; i < offset; i++) buffer[i] = '0'; if (length - kk > maxDecimalPlaces) { // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = maxDecimalPlaces + 1; i > 2; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[3]; // Reserve one zero } else return &buffer[length + offset]; } else if (kk < -maxDecimalPlaces) { // Truncate to zero buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else if (length == 1) { // 1e30 buffer[1] = 'e'; return WriteExponent(kk - 1, &buffer[2]); } else { // 1234e30 -> 1.234e33 std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); buffer[1] = '.'; buffer[length + 1] = 'e'; return WriteExponent(kk - 1, &buffer[0 + length + 2]); } } inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); Double d(value); if (d.IsZero()) { if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else { if (value < 0) { *buffer++ = '-'; value = -value; } int length, K; Grisu2(value, buffer, &length, &K); return Prettify(buffer, length, K, maxDecimalPlaces); } } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DTOA_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/ieee754.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_IEEE754_ #define RAPIDJSON_IEEE754_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { class Double { public: Double() {} Double(double d) : d_(d) {} Double(uint64_t u) : u_(u) {} double Value() const { return d_; } uint64_t Uint64Value() const { return u_; } double NextPositiveDouble() const { RAPIDJSON_ASSERT(!Sign()); return Double(u_ + 1).Value(); } bool Sign() const { return (u_ & kSignMask) != 0; } uint64_t Significand() const { return u_ & kSignificandMask; } int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else return order + 1074; } private: static const int kSignificandSize = 52; static const int kExponentBias = 0x3FF; static const int kDenormalExponent = 1 - kExponentBias; static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); union { double d_; uint64_t u_; }; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_IEEE754_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/itoa.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline const char* GetDigitsLut() { static const char cDigitsLut[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; return cDigitsLut; } inline char* u32toa(uint32_t value, char* buffer) { RAPIDJSON_ASSERT(buffer != 0); const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else if (value < 100000000) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } else { // value = aabbbbcccc in decimal const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else *buffer++ = static_cast<char>('0' + static_cast<char>(a)); const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } return buffer; } inline char* i32toa(int32_t value, char* buffer) { RAPIDJSON_ASSERT(buffer != 0); uint32_t u = static_cast<uint32_t>(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u32toa(u, buffer); } inline char* u64toa(uint64_t value, char* buffer) { RAPIDJSON_ASSERT(buffer != 0); const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen10 = kTen8 * 100; const uint64_t kTen11 = kTen8 * 1000; const uint64_t kTen12 = kTen8 * 10000; const uint64_t kTen13 = kTen8 * 100000; const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; if (value < kTen8) { uint32_t v = static_cast<uint32_t>(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (v >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } } else if (value < kTen16) { const uint32_t v0 = static_cast<uint32_t>(value / kTen8); const uint32_t v1 = static_cast<uint32_t>(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; if (value >= kTen15) *buffer++ = cDigitsLut[d1]; if (value >= kTen14) *buffer++ = cDigitsLut[d1 + 1]; if (value >= kTen13) *buffer++ = cDigitsLut[d2]; if (value >= kTen12) *buffer++ = cDigitsLut[d2 + 1]; if (value >= kTen11) *buffer++ = cDigitsLut[d3]; if (value >= kTen10) *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } else { const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844 value %= kTen16; if (a < 10) *buffer++ = static_cast<char>('0' + static_cast<char>(a)); else if (a < 100) { const uint32_t i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else if (a < 1000) { *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100)); const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else { const uint32_t i = (a / 100) << 1; const uint32_t j = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } const uint32_t v0 = static_cast<uint32_t>(value / kTen8); const uint32_t v1 = static_cast<uint32_t>(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } return buffer; } inline char* i64toa(int64_t value, char* buffer) { RAPIDJSON_ASSERT(buffer != 0); uint64_t u = static_cast<uint64_t>(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u64toa(u, buffer); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ITOA_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/meta.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ #include "../rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif #if RAPIDJSON_HAS_CXX11_TYPETRAITS #include <type_traits> #endif //@cond RAPIDJSON_INTERNAL RAPIDJSON_NAMESPACE_BEGIN namespace internal { // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching template <typename T> struct Void { typedef void Type; }; /////////////////////////////////////////////////////////////////////////////// // BoolType, TrueType, FalseType // template <bool Cond> struct BoolType { static const bool Value = Cond; typedef BoolType Type; }; typedef BoolType<true> TrueType; typedef BoolType<false> FalseType; /////////////////////////////////////////////////////////////////////////////// // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; }; template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; }; template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {}; template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {}; template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {}; template <> struct AndExprCond<true, true> : TrueType {}; template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {}; template <> struct OrExprCond<false, false> : FalseType {}; template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {}; template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {}; template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {}; template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {}; /////////////////////////////////////////////////////////////////////////////// // AddConst, MaybeAddConst, RemoveConst template <typename T> struct AddConst { typedef const T Type; }; template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; template <typename T> struct RemoveConst { typedef T Type; }; template <typename T> struct RemoveConst<const T> { typedef T Type; }; /////////////////////////////////////////////////////////////////////////////// // IsSame, IsConst, IsMoreConst, IsPointer // template <typename T, typename U> struct IsSame : FalseType {}; template <typename T> struct IsSame<T, T> : TrueType {}; template <typename T> struct IsConst : FalseType {}; template <typename T> struct IsConst<const T> : TrueType {}; template <typename CT, typename T> struct IsMoreConst : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>, BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {}; template <typename T> struct IsPointer : FalseType {}; template <typename T> struct IsPointer<T*> : TrueType {}; /////////////////////////////////////////////////////////////////////////////// // IsBaseOf // #if RAPIDJSON_HAS_CXX11_TYPETRAITS template <typename B, typename D> struct IsBaseOf : BoolType< ::std::is_base_of<B,D>::value> {}; #else // simplified version adopted from Boost template<typename B, typename D> struct IsBaseOfImpl { RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); typedef char (&Yes)[1]; typedef char (&No) [2]; template <typename T> static Yes Check(const D*, T); static No Check(const B*, int); struct Host { operator const B*() const; operator const D*(); }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; }; template <typename B, typename D> struct IsBaseOf : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {}; #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS ////////////////////////////////////////////////////////////////////////// // EnableIf / DisableIf // template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; }; template <typename T> struct EnableIfCond<false, T> { /* empty */ }; template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; }; template <typename T> struct DisableIfCond<true, T> { /* empty */ }; template <typename Condition, typename T = void> struct EnableIf : EnableIfCond<Condition::Value, T> {}; template <typename Condition, typename T = void> struct DisableIf : DisableIfCond<Condition::Value, T> {}; // SFINAE helpers struct SfinaeTag {}; template <typename T> struct RemoveSfinaeTag; template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL #define RAPIDJSON_DISABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ <RAPIDJSON_REMOVEFPTR_(cond), \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ <RAPIDJSON_REMOVEFPTR_(cond), \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type } // namespace internal RAPIDJSON_NAMESPACE_END //@endcond #if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_META_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/pow10.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. \param n non-negative exponent. Must <= 308. \return 10.0^n */ inline double Pow10(int n) { static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }; RAPIDJSON_ASSERT(n >= 0 && n <= 308); return e[n]; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_POW10_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/regex.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_REGEX_H_ #define RAPIDJSON_INTERNAL_REGEX_H_ #include "../allocators.h" #include "../stream.h" #include "stack.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifndef RAPIDJSON_REGEX_VERBOSE #define RAPIDJSON_REGEX_VERBOSE 0 #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // DecodedStream template <typename SourceStream, typename Encoding> class DecodedStream { public: DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } unsigned Peek() { return codepoint_; } unsigned Take() { unsigned c = codepoint_; if (c) // No further decoding when '\0' Decode(); return c; } private: void Decode() { if (!Encoding::Decode(ss_, &codepoint_)) codepoint_ = 0; } SourceStream& ss_; unsigned codepoint_; }; /////////////////////////////////////////////////////////////////////////////// // GenericRegex static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidRange = ~SizeType(0); template <typename Encoding, typename Allocator> class GenericRegexSearch; //! Regular expression engine with subset of ECMAscript grammar. /*! Supported regular expression syntax: - \c ab Concatenation - \c a|b Alternation - \c a? Zero or one - \c a* Zero or more - \c a+ One or more - \c a{3} Exactly 3 times - \c a{3,} At least 3 times - \c a{3,5} 3 to 5 times - \c (ab) Grouping - \c ^a At the beginning - \c a$ At the end - \c . Any character - \c [abc] Character classes - \c [a-c] Character class range - \c [a-z0-9_] Character class combination - \c [^abc] Negated character classes - \c [^a-c] Negated character class range - \c [\b] Backspace (U+0008) - \c \\| \\\\ ... Escape characters - \c \\f Form feed (U+000C) - \c \\n Line feed (U+000A) - \c \\r Carriage return (U+000D) - \c \\t Tab (U+0009) - \c \\v Vertical tab (U+000B) \note This is a Thompson NFA engine, implemented with reference to Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", https://swtch.com/~rsc/regexp/regexp1.html */ template <typename Encoding, typename Allocator = CrtAllocator> class GenericRegex { public: typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; template <typename, typename> friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), anchorBegin_(), anchorEnd_() { GenericStringStream<Encoding> ss(source); DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss); Parse(ds); } ~GenericRegex() { RAPIDJSON_DELETE(ownAllocator_); } bool IsValid() const { return root_ != kRegexInvalidState; } private: enum Operator { kZeroOrOne, kZeroOrMore, kOneOrMore, kConcatenation, kAlternation, kLeftParenthesis }; static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' static const unsigned kRangeCharacterClass = 0xFFFFFFFE; static const unsigned kRangeNegationFlag = 0x80000000; struct Range { unsigned start; // unsigned end; SizeType next; }; struct State { SizeType out; //!< Equals to kInvalid for matching state SizeType out1; //!< Equals to non-kInvalid for split SizeType rangeStart; unsigned codepoint; }; struct Frag { Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} SizeType start; SizeType out; //!< link-list of all output states SizeType minIndex; }; State& GetState(SizeType index) { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom<State>()[index]; } const State& GetState(SizeType index) const { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom<State>()[index]; } Range& GetRange(SizeType index) { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom<Range>()[index]; } const Range& GetRange(SizeType index) const { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom<Range>()[index]; } template <typename InputStream> void Parse(DecodedStream<InputStream, Encoding>& ds) { Stack<Allocator> operandStack(allocator_, 256); // Frag Stack<Allocator> operatorStack(allocator_, 256); // Operator Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) *atomCountStack.template Push<unsigned>() = 0; unsigned codepoint; while (ds.Peek() != 0) { switch (codepoint = ds.Take()) { case '^': anchorBegin_ = true; break; case '$': anchorEnd_ = true; break; case '|': while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation) if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) return; *operatorStack.template Push<Operator>() = kAlternation; *atomCountStack.template Top<unsigned>() = 0; break; case '(': *operatorStack.template Push<Operator>() = kLeftParenthesis; *atomCountStack.template Push<unsigned>() = 0; break; case ')': while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis) if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) return; if (operatorStack.Empty()) return; operatorStack.template Pop<Operator>(1); atomCountStack.template Pop<unsigned>(1); ImplicitConcatenation(atomCountStack, operatorStack); break; case '?': if (!Eval(operandStack, kZeroOrOne)) return; break; case '*': if (!Eval(operandStack, kZeroOrMore)) return; break; case '+': if (!Eval(operandStack, kOneOrMore)) return; break; case '{': { unsigned n, m; if (!ParseUnsigned(ds, &n)) return; if (ds.Peek() == ',') { ds.Take(); if (ds.Peek() == '}') m = kInfinityQuantifier; else if (!ParseUnsigned(ds, &m) || m < n) return; } else m = n; if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') return; ds.Take(); } break; case '.': PushOperand(operandStack, kAnyCharacterClass); ImplicitConcatenation(atomCountStack, operatorStack); break; case '[': { SizeType range; if (!ParseRange(ds, &range)) return; SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); GetState(s).rangeStart = range; *operandStack.template Push<Frag>() = Frag(s, s, s); } ImplicitConcatenation(atomCountStack, operatorStack); break; case '\\': // Escape character if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default RAPIDJSON_DELIBERATE_FALLTHROUGH; default: // Pattern character PushOperand(operandStack, codepoint); ImplicitConcatenation(atomCountStack, operatorStack); } } while (!operatorStack.Empty()) if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1))) return; // Link the operand to matching state. if (operandStack.GetSize() == sizeof(Frag)) { Frag* e = operandStack.template Pop<Frag>(1); Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); root_ = e->start; #if RAPIDJSON_REGEX_VERBOSE printf("root: %d\n", root_); for (SizeType i = 0; i < stateCount_ ; i++) { State& s = GetState(i); printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); } printf("\n"); #endif } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { State* s = states_.template Push<State>(); s->out = out; s->out1 = out1; s->codepoint = codepoint; s->rangeStart = kRegexInvalidRange; return stateCount_++; } void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) { SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); *operandStack.template Push<Frag>() = Frag(s, s, s); } void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) { if (*atomCountStack.template Top<unsigned>()) *operatorStack.template Push<Operator>() = kConcatenation; (*atomCountStack.template Top<unsigned>())++; } SizeType Append(SizeType l1, SizeType l2) { SizeType old = l1; while (GetState(l1).out != kRegexInvalidState) l1 = GetState(l1).out; GetState(l1).out = l2; return old; } void Patch(SizeType l, SizeType s) { for (SizeType next; l != kRegexInvalidState; l = next) { next = GetState(l).out; GetState(l).out = s; } } bool Eval(Stack<Allocator>& operandStack, Operator op) { switch (op) { case kConcatenation: RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); { Frag e2 = *operandStack.template Pop<Frag>(1); Frag e1 = *operandStack.template Pop<Frag>(1); Patch(e1.out, e2.start); *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); } return true; case kAlternation: if (operandStack.GetSize() >= sizeof(Frag) * 2) { Frag e2 = *operandStack.template Pop<Frag>(1); Frag e1 = *operandStack.template Pop<Frag>(1); SizeType s = NewState(e1.start, e2.start, 0); *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); return true; } return false; case kZeroOrOne: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop<Frag>(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex); return true; } return false; case kZeroOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop<Frag>(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex); return true; } return false; case kOneOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop<Frag>(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex); return true; } return false; default: // syntax error (e.g. unclosed kLeftParenthesis) return false; } } bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) { RAPIDJSON_ASSERT(n <= m); RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); if (n == 0) { if (m == 0) // a{0} not support return false; else if (m == kInfinityQuantifier) Eval(operandStack, kZeroOrMore); // a{0,} -> a* else { Eval(operandStack, kZeroOrOne); // a{0,5} -> a? for (unsigned i = 0; i < m - 1; i++) CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? for (unsigned i = 0; i < m - 1; i++) Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? } return true; } for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a CloneTopOperand(operandStack); if (m == kInfinityQuantifier) Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ else if (m > n) { CloneTopOperand(operandStack); // a{3,5} -> a a a a Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? for (unsigned i = n; i < m - 1; i++) CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? for (unsigned i = n; i < m; i++) Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? } for (unsigned i = 0; i < n - 1; i++) Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? return true; } static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } void CloneTopOperand(Stack<Allocator>& operandStack) { const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) State* s = states_.template Push<State>(count); memcpy(s, &GetState(src.minIndex), count * sizeof(State)); for (SizeType j = 0; j < count; j++) { if (s[j].out != kRegexInvalidState) s[j].out += count; if (s[j].out1 != kRegexInvalidState) s[j].out1 += count; } *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count); stateCount_ += count; } template <typename InputStream> bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; while (ds.Peek() >= '0' && ds.Peek() <= '9') { if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 return false; // overflow r = r * 10 + (ds.Take() - '0'); } *u = r; return true; } template <typename InputStream> bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; SizeType start = kRegexInvalidRange; SizeType current = kRegexInvalidRange; unsigned codepoint; while ((codepoint = ds.Take()) != 0) { if (isBegin) { isBegin = false; if (codepoint == '^') { negate = true; continue; } } switch (codepoint) { case ']': if (start == kRegexInvalidRange) return false; // Error: nothing inside [] if (step == 2) { // Add trailing '-' SizeType r = NewRange('-'); RAPIDJSON_ASSERT(current != kRegexInvalidRange); GetRange(current).next = r; } if (negate) GetRange(start).start |= kRangeNegationFlag; *range = start; return true; case '\\': if (ds.Peek() == 'b') { ds.Take(); codepoint = 0x0008; // Escape backspace character } else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default RAPIDJSON_DELIBERATE_FALLTHROUGH; default: switch (step) { case 1: if (codepoint == '-') { step++; break; } // fall through to step 0 for other characters RAPIDJSON_DELIBERATE_FALLTHROUGH; case 0: { SizeType r = NewRange(codepoint); if (current != kRegexInvalidRange) GetRange(current).next = r; if (start == kRegexInvalidRange) start = r; current = r; } step = 1; break; default: RAPIDJSON_ASSERT(step == 2); GetRange(current).end = codepoint; step = 0; } } } return false; } SizeType NewRange(unsigned codepoint) { Range* r = ranges_.template Push<Range>(); r->start = r->end = codepoint; r->next = kRegexInvalidRange; return rangeCount_++; } template <typename InputStream> bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': case '$': case '|': case '(': case ')': case '?': case '*': case '+': case '.': case '[': case ']': case '{': case '}': case '\\': *escapedCodepoint = codepoint; return true; case 'f': *escapedCodepoint = 0x000C; return true; case 'n': *escapedCodepoint = 0x000A; return true; case 'r': *escapedCodepoint = 0x000D; return true; case 't': *escapedCodepoint = 0x0009; return true; case 'v': *escapedCodepoint = 0x000B; return true; default: return false; // Unsupported escape character } } Allocator* ownAllocator_; Allocator* allocator_; Stack<Allocator> states_; Stack<Allocator> ranges_; SizeType root_; SizeType stateCount_; SizeType rangeCount_; static const unsigned kInfinityQuantifier = ~0u; // For SearchWithAnchoring() bool anchorBegin_; bool anchorEnd_; }; template <typename RegexType, typename Allocator = CrtAllocator> class GenericRegexSearch { public: typedef typename RegexType::EncodingType Encoding; typedef typename Encoding::Ch Ch; GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : regex_(regex), allocator_(allocator), ownAllocator_(0), state0_(allocator, 0), state1_(allocator, 0), stateSet_() { RAPIDJSON_ASSERT(regex_.IsValid()); if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize())); state0_.template Reserve<SizeType>(regex_.stateCount_); state1_.template Reserve<SizeType>(regex_.stateCount_); } ~GenericRegexSearch() { Allocator::Free(stateSet_); RAPIDJSON_DELETE(ownAllocator_); } template <typename InputStream> bool Match(InputStream& is) { return SearchWithAnchoring(is, true, true); } bool Match(const Ch* s) { GenericStringStream<Encoding> is(s); return Match(is); } template <typename InputStream> bool Search(InputStream& is) { return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); } bool Search(const Ch* s) { GenericStringStream<Encoding> is(s); return Search(is); } private: typedef typename RegexType::State State; typedef typename RegexType::Range Range; template <typename InputStream> bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { DecodedStream<InputStream, Encoding> ds(is); state0_.Clear(); Stack<Allocator> *current = &state0_, *next = &state1_; const size_t stateSetSize = GetStateSetSize(); std::memset(stateSet_, 0, stateSetSize); bool matched = AddState(*current, regex_.root_); unsigned codepoint; while (!current->Empty() && (codepoint = ds.Take()) != 0) { std::memset(stateSet_, 0, stateSetSize); next->Clear(); matched = false; for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) { const State& sr = regex_.GetState(*s); if (sr.codepoint == codepoint || sr.codepoint == RegexType::kAnyCharacterClass || (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) { matched = AddState(*next, sr.out) || matched; if (!anchorEnd && matched) return true; } if (!anchorBegin) AddState(*next, regex_.root_); } internal::Swap(current, next); } return matched; } size_t GetStateSetSize() const { return (regex_.stateCount_ + 31) / 32 * 4; } // Return whether the added states is a match state bool AddState(Stack<Allocator>& l, SizeType index) { RAPIDJSON_ASSERT(index != kRegexInvalidState); const State& s = regex_.GetState(index); if (s.out1 != kRegexInvalidState) { // Split bool matched = AddState(l, s.out); return AddState(l, s.out1) || matched; } else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { stateSet_[index >> 5] |= (1u << (index & 31)); *l.template PushUnsafe<SizeType>() = index; } return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. } bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; while (rangeIndex != kRegexInvalidRange) { const Range& r = regex_.GetRange(rangeIndex); if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) return yes; rangeIndex = r.next; } return !yes; } const RegexType& regex_; Allocator* allocator_; Allocator* ownAllocator_; Stack<Allocator> state0_; Stack<Allocator> state1_; uint32_t* stateSet_; }; typedef GenericRegex<UTF8<> > Regex; typedef GenericRegexSearch<Regex> RegexSearch; } // namespace internal RAPIDJSON_NAMESPACE_END #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_REGEX_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/stack.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ #include "../allocators.h" #include "swap.h" #include <cstddef> #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // Stack //! A type-unsafe stack for storing different types of data. /*! \tparam Allocator Allocator for allocating stack memory. */ template <typename Allocator> class Stack { public: // Optimization note: Do not allocate memory for stack_ in constructor. // Do it lazily when first Push() -> Expand() -> Resize(). Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack(Stack&& rhs) : allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(rhs.stack_), stackTop_(rhs.stackTop_), stackEnd_(rhs.stackEnd_), initialCapacity_(rhs.initialCapacity_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } #endif ~Stack() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack& operator=(Stack&& rhs) { if (&rhs != this) { Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = rhs.stack_; stackTop_ = rhs.stackTop_; stackEnd_ = rhs.stackEnd_; initialCapacity_ = rhs.initialCapacity_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } return *this; } #endif void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(stack_, rhs.stack_); internal::Swap(stackTop_, rhs.stackTop_); internal::Swap(stackEnd_, rhs.stackEnd_); internal::Swap(initialCapacity_, rhs.initialCapacity_); } void Clear() { stackTop_ = stack_; } void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) stack_ = 0; stackTop_ = 0; stackEnd_ = 0; } else Resize(GetSize()); } // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template<typename T> RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_))) Expand<T>(count); } template<typename T> RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { Reserve<T>(count); return PushUnsafe<T>(count); } template<typename T> RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_ASSERT(stackTop_); RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_)); T* ret = reinterpret_cast<T*>(stackTop_); stackTop_ += sizeof(T) * count; return ret; } template<typename T> T* Pop(size_t count) { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stackTop_ -= count * sizeof(T); return reinterpret_cast<T*>(stackTop_); } template<typename T> T* Top() { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast<T*>(stackTop_ - sizeof(T)); } template<typename T> const T* Top() const { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast<T*>(stackTop_ - sizeof(T)); } template<typename T> T* End() { return reinterpret_cast<T*>(stackTop_); } template<typename T> const T* End() const { return reinterpret_cast<T*>(stackTop_); } template<typename T> T* Bottom() { return reinterpret_cast<T*>(stack_); } template<typename T> const T* Bottom() const { return reinterpret_cast<T*>(stack_); } bool HasAllocator() const { return allocator_ != 0; } Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } private: template<typename T> void Expand(size_t count) { // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. size_t newCapacity; if (stack_ == 0) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); newCapacity += (newCapacity + 1) / 2; } size_t newSize = GetSize() + sizeof(T) * count; if (newCapacity < newSize) newCapacity = newSize; Resize(newCapacity); } void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } void Destroy() { Allocator::Free(stack_); RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack } // Prohibit copy constructor & assignment operator. Stack(const Stack&); Stack& operator=(const Stack&); Allocator* allocator_; Allocator* ownAllocator_; char *stack_; char *stackTop_; char *stackEnd_; size_t initialCapacity_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STACK_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/strfunc.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" #include <cwchar> RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom strlen() which works on different character types. /*! \tparam Ch Character type (e.g. char, wchar_t, short) \param s Null-terminated input string. \return Number of characters in the string. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template <typename Ch> inline SizeType StrLen(const Ch* s) { RAPIDJSON_ASSERT(s != 0); const Ch* p = s; while (*p) ++p; return SizeType(p - s); } template <> inline SizeType StrLen(const char* s) { return SizeType(std::strlen(s)); } template <> inline SizeType StrLen(const wchar_t* s) { return SizeType(std::wcslen(s)); } //! Returns number of code points in a encoded string. template<typename Encoding> bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { RAPIDJSON_ASSERT(s != 0); RAPIDJSON_ASSERT(outCount != 0); GenericStringStream<Encoding> is(s); const typename Encoding::Ch* end = s + length; SizeType count = 0; while (is.src_ < end) { unsigned codepoint; if (!Encoding::Decode(is, &codepoint)) return false; count++; } *outCount = count; return true; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/strtod.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_ #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" #include "pow10.h" #include <climits> #include <limits> RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline double FastPath(double significand, int exp) { if (exp < -308) return 0.0; else if (exp >= 0) return significand * internal::Pow10(exp); else return significand / internal::Pow10(-exp); } inline double StrtodNormalPrecision(double d, int p) { if (p < -308) { // Prevent expSum < -308, making Pow10(p) = 0 d = FastPath(d, -308); d = FastPath(d, p + 308); } else d = FastPath(d, p); return d; } template <typename T> inline T Min3(T a, T b, T c) { T m = a; if (m > b) m = b; if (m > c) m = c; return m; } inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { const Double db(b); const uint64_t bInt = db.IntegerSignificand(); const int bExp = db.IntegerExponent(); const int hExp = bExp - 1; int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; // Adjust for decimal exponent if (dExp >= 0) { dS_Exp2 += dExp; dS_Exp5 += dExp; } else { bS_Exp2 -= dExp; bS_Exp5 -= dExp; hS_Exp2 -= dExp; hS_Exp5 -= dExp; } // Adjust for binary exponent if (bExp >= 0) bS_Exp2 += bExp; else { dS_Exp2 -= bExp; hS_Exp2 -= bExp; } // Adjust for half ulp exponent if (hExp >= 0) hS_Exp2 += hExp; else { dS_Exp2 -= hExp; bS_Exp2 -= hExp; } // Remove common power of two factor from all three scaled values int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); dS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2; BigInteger dS = d; dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2); BigInteger bS(bInt); bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2); BigInteger hS(1); hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2); BigInteger delta(0); dS.Difference(bS, &delta); return delta.Compare(hS); } inline bool StrtodFast(double d, int p, double* result) { // Use fast path for string-to-double conversion if possible // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ if (p > 22 && p < 22 + 16) { // Fast Path Cases In Disguise d *= internal::Pow10(p - 22); p = 22; } if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 *result = FastPath(d, p); return true; } else return false; } // Compute an approximation and see if it is within 1/2 ULP inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) { uint64_t significand = 0; int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 for (; i < dLen; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); } if (i < dLen && decimals[i] >= '5') // Rounding significand++; int remaining = dLen - i; const int kUlpShift = 3; const int kUlp = 1 << kUlpShift; int64_t error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); v = v.Normalize(); error <<= -v.e; dExp += remaining; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 }; int adjustment = dExp - actualExp; RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); v = v * kPow10[adjustment - 1]; if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit error += kUlp / 2; } v = v * cachedPower; error += kUlp + (error == 0 ? 0 : 1); const int oldExp = v.e; v = v.Normalize(); error <<= oldExp - v.e; const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); int precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { int scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; error = (error >> scaleExp) + 1 + kUlp; precisionSize -= scaleExp; } DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if (precisionBits >= halfWay + static_cast<unsigned>(error)) { rounded.f++; if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) rounded.f >>= 1; rounded.e++; } } *result = rounded.ToDouble(); return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); } inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) { RAPIDJSON_ASSERT(dLen >= 0); const BigInteger dInt(decimals, static_cast<unsigned>(dLen)); Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) return a.Value(); // within half ULP else if (cmp == 0) { // Round towards even if (a.Significand() & 1) return a.NextPositiveDouble(); else return a.Value(); } else // adjustment return a.NextPositiveDouble(); } inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); double result = 0.0; if (StrtodFast(d, p, &result)) return result; RAPIDJSON_ASSERT(length <= INT_MAX); int dLen = static_cast<int>(length); RAPIDJSON_ASSERT(length >= decimalPosition); RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); int dExpAdjust = static_cast<int>(length - decimalPosition); RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); int dExp = exp - dExpAdjust; // Make sure length+dExp does not overflow RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); // Trim leading zeros while (dLen > 0 && *decimals == '0') { dLen--; decimals++; } // Trim trailing zeros while (dLen > 0 && decimals[dLen - 1] == '0') { dLen--; dExp++; } if (dLen == 0) { // Buffer only contains zeros. return 0.0; } // Trim right-most digits const int kMaxDecimalDigit = 767 + 1; if (dLen > kMaxDecimalDigit) { dExp += dLen - kMaxDecimalDigit; dLen = kMaxDecimalDigit; } // If too small, underflow to zero. // Any x <= 10^-324 is interpreted as zero. if (dLen + dExp <= -324) return 0.0; // If too large, overflow to infinity. // Any x >= 10^309 is interpreted as +infinity. if (dLen + dExp > 309) return std::numeric_limits<double>::infinity(); if (StrtodDiyFp(decimals, dLen, dExp, &result)) return result; // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison return StrtodBigInteger(result, decimals, dLen, dExp); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STRTOD_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/internal/swap.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_INTERNAL_SWAP_H_ #define RAPIDJSON_INTERNAL_SWAP_H_ #include "../rapidjson.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom swap() to avoid dependency on C++ <algorithm> header /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. \note This has the same semantics as std::swap(). */ template <typename T> inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { T tmp = a; a = b; b = tmp; } } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_SWAP_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/istreamwrapper.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ #define RAPIDJSON_ISTREAMWRAPPER_H_ #include "stream.h" #include <iosfwd> #include <ios> #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::istringstream - \c std::stringstream - \c std::wistringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wifstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_istream. */ template <typename StreamType> class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; //! Constructor. /*! \param stream stream opened for read. */ BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { Read(); } //! Constructor. /*! \param stream stream opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } Ch Peek() const { return *current_; } Ch Take() { Ch c = *current_; Read(); return c; } size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: BasicIStreamWrapper(); BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); void Read() { if (current_ < bufferLast_) ++current_; else if (!eof_) { count_ += readCount_; readCount_ = bufferSize_; bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) { readCount_ = static_cast<size_t>(stream_.gcount()); *(bufferLast_ = buffer_ + readCount_) = '\0'; eof_ = true; } } } StreamType &stream_; Ch peekBuffer_[4], *buffer_; size_t bufferSize_; Ch *bufferLast_; Ch *current_; size_t readCount_; size_t count_; //!< Number of characters read bool eof_; }; typedef BasicIStreamWrapper<std::istream> IStreamWrapper; typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper; #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ISTREAMWRAPPER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/memorybuffer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ #include "stream.h" #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output byte stream. /*! This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. Differences between MemoryBuffer and StringBuffer: 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template <typename Allocator = CrtAllocator> struct GenericMemoryBuffer { typedef char Ch; // byte GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} void Put(Ch c) { *stack_.template Push<Ch>() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { stack_.ShrinkToFit(); } Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } void Pop(size_t count) { stack_.template Pop<Ch>(count); } const Ch* GetBuffer() const { return stack_.template Bottom<Ch>(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack<Allocator> stack_; }; typedef GenericMemoryBuffer<> MemoryBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_MEMORYBUFFER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/memorystream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ #include "stream.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. /*! This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. Differences between MemoryStream and StringStream: 1. StringStream has encoding but MemoryStream is a byte stream. 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). \note implements Stream concept */ struct MemoryStream { typedef char Ch; // byte MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } size_t Tell() const { return static_cast<size_t>(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return Tell() + 4 <= size_ ? src_ : 0; } const Ch* src_; //!< Current read position. const Ch* begin_; //!< Original head of the string. const Ch* end_; //!< End of stream. size_t size_; //!< Size of the stream. }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_MEMORYBUFFER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/msinttypes/inttypes.h ================================================ // ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // miloyip: VC supports inttypes.h since VC2013 #if _MSC_VER >= 1800 #include <inttypes.h> #else // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_VER >= 1800 #endif // _MSC_INTTYPES_H_ ] ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/msinttypes/stdint.h ================================================ // ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the product nor the names of its contributors may // be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif // miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. #if _MSC_VER >= 1600 // [ #include <stdint.h> #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 #undef INT8_C #undef INT16_C #undef INT32_C #undef INT64_C #undef UINT8_C #undef UINT16_C #undef UINT32_C #undef UINT64_C // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>. // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #else // ] _MSC_VER >= 1700 [ #include <limits.h> // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}' // or compiler would give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #if defined(__cplusplus) && !defined(_M_ARM) extern "C" { #endif # include <wchar.h> #if defined(__cplusplus) && !defined(_M_ARM) } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>. // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_VER >= 1600 ] #endif // _MSC_STDINT_H_ ] ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/ostreamwrapper.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ #define RAPIDJSON_OSTREAMWRAPPER_H_ #include "stream.h" #include <iosfwd> #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::ostringstream - \c std::stringstream - \c std::wpstringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wofstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_ostream. */ template <typename StreamType> class BasicOStreamWrapper { public: typedef typename StreamType::char_type Ch; BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} void Put(Ch c) { stream_.put(c); } void Flush() { stream_.flush(); } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: BasicOStreamWrapper(const BasicOStreamWrapper&); BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); StreamType& stream_; }; typedef BasicOStreamWrapper<std::ostream> OStreamWrapper; typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper; #ifdef __clang__ RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_OSTREAMWRAPPER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/pointer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_POINTER_H_ #define RAPIDJSON_POINTER_H_ #include "document.h" #include "internal/itoa.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode */ enum PointerParseErrorCode { kPointerParseErrorNone = 0, //!< The parse is successful kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' kPointerParseErrorInvalidEscape, //!< Invalid escape kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment }; /////////////////////////////////////////////////////////////////////////////// // GenericPointer //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. /*! This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" (https://tools.ietf.org/html/rfc6901). A JSON pointer is for identifying a specific value in a JSON document (GenericDocument). It can simplify coding of DOM tree manipulation, because it can access multiple-level depth of DOM tree with single API call. After it parses a string representation (e.g. "/foo/0" or URI fragment representation (e.g. "#/foo/0") into its internal representation (tokens), it can be used to resolve a specific value in multiple documents, or sub-tree of documents. Contrary to GenericValue, Pointer can be copy constructed and copy assigned. Apart from assignment, a Pointer cannot be modified after construction. Although Pointer is very convenient, please aware that constructing Pointer involves parsing and dynamic memory allocation. A special constructor with user- supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> > \tparam Allocator The allocator type for allocating memory for internal representation. \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ template <typename ValueType, typename Allocator = CrtAllocator> class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. They are resolved according to the actual value type (object or array). For token that are not numbers, or the numeric value is out of bound (greater than limits of SizeType), they are only treated as string form (i.e. the token's index will be equal to kPointerInvalidIndex). This struct is public so that user can create a Pointer without parsing and allocation, using a special constructor. */ struct Token { const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. SizeType length; //!< Length of the name. SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. }; //!@name Constructors and destructor. //@{ //! Default constructor. GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Constructor that parses a string or URI fragment representation. /*! \param source A null-terminated, string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. */ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, internal::StrLen(source)); } #if RAPIDJSON_HAS_STDSTRING //! Constructor that parses a string or URI fragment representation. /*! \param source A string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source.c_str(), source.size()); } #endif //! Constructor that parses a string or URI fragment representation, with length of the source string. /*! \param source A string or URI fragment representation of JSON pointer. \param length Length of source. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Slightly faster than the overload without length. */ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, length); } //! Constructor with user-supplied tokens. /*! This constructor let user supplies const array of tokens. This prevents the parsing process and eliminates allocation. This is preferred for memory constrained environments. \param tokens An constant array of tokens representing the JSON pointer. \param tokenCount Number of tokens. \b Example \code #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } #define INDEX(i) { #i, sizeof(#i) - 1, i } static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); // Equivalent to static const Pointer p("/foo/123"); #undef NAME #undef INDEX \endcode */ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } //! Copy constructor. GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } //! Destructor. ~GenericPointer() { if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. Allocator::Free(tokens_); RAPIDJSON_DELETE(ownAllocator_); } //! Assignment operator. GenericPointer& operator=(const GenericPointer& rhs) { if (this != &rhs) { // Do not delete ownAllcator if (nameBuffer_) Allocator::Free(tokens_); tokenCount_ = rhs.tokenCount_; parseErrorOffset_ = rhs.parseErrorOffset_; parseErrorCode_ = rhs.parseErrorCode_; if (rhs.nameBuffer_) CopyFromRaw(rhs); // Normally parsed tokens. else { tokens_ = rhs.tokens_; // User supplied const tokens. nameBuffer_ = 0; } } return *this; } //! Swap the content of this pointer with an other. /*! \param other The pointer to swap with. \note Constant complexity. */ GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { internal::Swap(allocator_, other.allocator_); internal::Swap(ownAllocator_, other.ownAllocator_); internal::Swap(nameBuffer_, other.nameBuffer_); internal::Swap(tokens_, other.tokens_); internal::Swap(tokenCount_, other.tokenCount_); internal::Swap(parseErrorOffset_, other.parseErrorOffset_); internal::Swap(parseErrorCode_, other.parseErrorCode_); return *this; } //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.pointer, b.pointer); // ... } \endcode \see Swap() */ friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //@} //!@name Append token //@{ //! Append a token and return a new Pointer /*! \param token Token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Token& token, Allocator* allocator = 0) const { GenericPointer r; r.allocator_ = allocator; Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); r.tokens_[tokenCount_].name = p; r.tokens_[tokenCount_].length = token.length; r.tokens_[tokenCount_].index = token.index; return r; } //! Append a name token with length, and return a new Pointer /*! \param name Name to be appended. \param length Length of name. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { Token token = { name, length, kPointerInvalidIndex }; return Append(token, allocator); } //! Append a name token without length, and return a new Pointer /*! \param name Name (const Ch*) to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Append a name token, and return a new Pointer /*! \param name Name to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const { return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator); } #endif //! Append a index token, and return a new Pointer /*! \param index Index to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); SizeType length = static_cast<SizeType>(end - buffer); buffer[length] = '\0'; if (sizeof(Ch) == 1) { Token token = { reinterpret_cast<Ch*>(buffer), length, index }; return Append(token, allocator); } else { Ch name[21]; for (size_t i = 0; i <= length; i++) name[i] = static_cast<Ch>(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } } //! Append a token by value, and return a new Pointer /*! \param token token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { if (token.IsString()) return Append(token.GetString(), token.GetStringLength(), allocator); else { RAPIDJSON_ASSERT(token.IsUint64()); RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); return Append(static_cast<SizeType>(token.GetUint64()), allocator); } } //!@name Handling Parse Error //@{ //! Check whether this is a valid pointer. bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } //! Get the parsing error offset in code unit. size_t GetParseErrorOffset() const { return parseErrorOffset_; } //! Get the parsing error code. PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } //@} //! Get the allocator of this pointer. Allocator& GetAllocator() { return *allocator_; } //!@name Tokens //@{ //! Get the token array (const version only). const Token* GetTokens() const { return tokens_; } //! Get the number of tokens. size_t GetTokenCount() const { return tokenCount_; } //@} //!@name Equality/inequality operators //@{ //! Equality operator. /*! \note When any pointers are invalid, always returns false. */ bool operator==(const GenericPointer& rhs) const { if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) return false; for (size_t i = 0; i < tokenCount_; i++) { if (tokens_[i].index != rhs.tokens_[i].index || tokens_[i].length != rhs.tokens_[i].length || (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) { return false; } } return true; } //! Inequality operator. /*! \note When any pointers are invalid, always returns true. */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } //! Less than operator. /*! \note Invalid pointers are always greater than valid ones. */ bool operator<(const GenericPointer& rhs) const { if (!IsValid()) return false; if (!rhs.IsValid()) return true; if (tokenCount_ != rhs.tokenCount_) return tokenCount_ < rhs.tokenCount_; for (size_t i = 0; i < tokenCount_; i++) { if (tokens_[i].index != rhs.tokens_[i].index) return tokens_[i].index < rhs.tokens_[i].index; if (tokens_[i].length != rhs.tokens_[i].length) return tokens_[i].length < rhs.tokens_[i].length; if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) return cmp < 0; } return false; } //@} //!@name Stringify //@{ //! Stringify the pointer into string representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template<typename OutputStream> bool Stringify(OutputStream& os) const { return Stringify<false, OutputStream>(os); } //! Stringify the pointer into URI fragment representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template<typename OutputStream> bool StringifyUriFragment(OutputStream& os) const { return Stringify<true, OutputStream>(os); } //@} //!@name Create value //@{ //! Create a value in a subtree. /*! If the value is not exist, it creates all parent values and a JSON Null value. So it always succeed and return the newly created or existing value. Remind that it may change types of parents according to tokens, so it potentially removes previously stored values. For example, if a document was an array, and "/foo" is used to create a value, then the document will be changed to an object, and all existing array elements are lost. \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created (a JSON Null value), or already exists value. */ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { v->PushBack(ValueType().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } else { if (t->index == kPointerInvalidIndex) { // must be object name if (!v->IsObject()) v->SetObject(); // Change to Object } else { // object name or array index if (!v->IsArray() && !v->IsObject()) v->SetArray(); // Change to Array } if (v->IsArray()) { if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) v->PushBack(ValueType().Move(), allocator); exist = false; } v = &((*v)[t->index]); } else { typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length))); if (m == v->MemberEnd()) { v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); m = v->MemberEnd(); v = &(--m)->value; // Assumes AddMember() appends at the end exist = false; } else v = &m->value; } } } if (alreadyExist) *alreadyExist = exist; return *v; } //! Creates a value in a document. /*! \param document A document to be resolved. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ template <typename stackAllocator> ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const { return Create(document, document.GetAllocator(), alreadyExist); } //@} //!@name Query value //@{ //! Query a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. \return Pointer to the value if it can be resolved. Otherwise null. \note There are only 3 situations when a value cannot be resolved: 1. A value in the path is not an array nor object. 2. An object value does not contain the token. 3. A token is out of range of an array value. Use unresolvedTokenIndex to retrieve the token index. */ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length))); if (m == v->MemberEnd()) break; v = &m->value; } continue; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) break; v = &((*v)[t->index]); continue; default: break; } // Error: unresolved token if (unresolvedTokenIndex) *unresolvedTokenIndex = static_cast<size_t>(t - tokens_); return 0; } return v; } //! Query a const value in a const subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { return Get(const_cast<ValueType&>(root), unresolvedTokenIndex); } //@} //!@name Query a value with default //@{ //! Query a value in a subtree with default value. /*! Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. So that this function always succeed. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param defaultValue Default value to be cloned if the value was not exists. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif //! Query a value in a subtree with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); } //! Query a value in a document with default value. template <typename stackAllocator> ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //! Query a value in a document with default null-terminated string. template <typename stackAllocator> ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template <typename stackAllocator> ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #endif //! Query a value in a document with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template <typename T, typename stackAllocator> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //@} //!@name Set a value //@{ //! Set a value in a subtree, with move semantics. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be set. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = value; } //! Set a value in a subtree, with copy semantics. ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).CopyFrom(value, allocator); } //! Set a null-terminated string in a subtree. ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Set a std::basic_string in a subtree. ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #endif //! Set a primitive value in a subtree. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value).Move(); } //! Set a value in a document, with move semantics. template <typename stackAllocator> ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const { return Create(document) = value; } //! Set a value in a document, with copy semantics. template <typename stackAllocator> ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const { return Create(document).CopyFrom(value, document.GetAllocator()); } //! Set a null-terminated string in a document. template <typename stackAllocator> ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Sets a std::basic_string in a document. template <typename stackAllocator> ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #endif //! Set a primitive value in a document. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template <typename T, typename stackAllocator> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const { return Create(document) = value; } //@} //!@name Swap a value //@{ //! Swap a value with a value in a subtree. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be swapped. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).Swap(value); } //! Swap a value with a value in a document. template <typename stackAllocator> ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const { return Create(document).Swap(value); } //@} //! Erase a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Whether the resolved value is found and erased. \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. */ bool Erase(ValueType& root) const { RAPIDJSON_ASSERT(IsValid()); if (tokenCount_ == 0) // Cannot erase the root return false; ValueType* v = &root; const Token* last = tokens_ + (tokenCount_ - 1); for (const Token *t = tokens_; t != last; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length))); if (m == v->MemberEnd()) return false; v = &m->value; } break; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) return false; v = &((*v)[t->index]); break; default: return false; } } switch (v->GetType()) { case kObjectType: return v->EraseMember(GenericStringRef<Ch>(last->name, last->length)); case kArrayType: if (last->index == kPointerInvalidIndex || last->index >= v->Size()) return false; v->Erase(v->Begin() + last->index); return true; default: return false; } } private: //! Clone the content from rhs to this. /*! \param rhs Source pointer. \param extraToken Extra tokens to be allocated. \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. \return Start of non-occupied name buffer, for storing extra names. */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) nameBufferSize += t->length; tokenCount_ = rhs.tokenCount_ + extraToken; tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); if (rhs.tokenCount_ > 0) { std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); } if (nameBufferSize > 0) { std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); } // Adjust pointers to name buffer std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) t->name += diff; return nameBuffer_ + nameBufferSize; } //! Check whether a character should be percent-encoded. /*! According to RFC 3986 2.3 Unreserved Characters. \param c The character (code unit) to be tested. */ bool NeedPercentEncode(Ch c) const { return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); } //! Parse a JSON String or its URI fragment representation into tokens. #ifndef __clang__ // -Wdocumentation /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ #endif void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); RAPIDJSON_ASSERT(tokens_ == 0); // Create own allocator if user did not supply. if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; for (const Ch* s = source; s != source + length; s++) if (*s == '/') tokenCount_++; Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); size_t i = 0; // Detect if it is a URI fragment bool uriFragment = false; if (source[i] == '#') { uriFragment = true; i++; } if (i != length && source[i] != '/') { parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; goto error; } while (i < length) { RAPIDJSON_ASSERT(source[i] == '/'); i++; // consumes '/' token->name = name; bool isNumber = true; while (i < length && source[i] != '/') { Ch c = source[i]; if (uriFragment) { // Decoding percent-encoding for URI fragment if (c == '%') { PercentDecodeStream is(&source[i], source + length); GenericInsituStringStream<EncodingType> os(name); Ch* begin = os.PutBegin(); if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) { parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; goto error; } size_t len = os.PutEnd(begin); i += is.Tell() - 1; if (len == 1) c = *name; else { name += len; isNumber = false; i++; continue; } } else if (NeedPercentEncode(c)) { parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; goto error; } } i++; // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { c = source[i]; if (c == '0') c = '~'; else if (c == '1') c = '/'; else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } i++; } else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } } // First check for index: all of characters are digit if (c < '0' || c > '9') isNumber = false; *name++ = c; } token->length = static_cast<SizeType>(name - token->name); if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator // Second check for index: more than one digit cannot have leading zero if (isNumber && token->length > 1 && token->name[0] == '0') isNumber = false; // String to SizeType conversion SizeType n = 0; if (isNumber) { for (size_t j = 0; j < token->length; j++) { SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0'); if (m < n) { // overflow detection isNumber = false; break; } n = m; } } token->index = isNumber ? n : kPointerInvalidIndex; token++; } RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer parseErrorCode_ = kPointerParseErrorNone; return; error: Allocator::Free(tokens_); nameBuffer_ = 0; tokens_ = 0; tokenCount_ = 0; parseErrorOffset_ = i; return; } //! Stringify to string or URI fragment representation. /*! \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. \tparam OutputStream type of output stream. \param os The output stream. */ template<bool uriFragment, typename OutputStream> bool Stringify(OutputStream& os) const { RAPIDJSON_ASSERT(IsValid()); if (uriFragment) os.Put('#'); for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { os.Put('/'); for (size_t j = 0; j < t->length; j++) { Ch c = t->name[j]; if (c == '~') { os.Put('~'); os.Put('0'); } else if (c == '/') { os.Put('~'); os.Put('1'); } else if (uriFragment && NeedPercentEncode(c)) { // Transcode to UTF8 sequence GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]); PercentEncodeStream<OutputStream> target(os); if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target)) return false; j += source.Tell() - 1; } else os.Put(c); } } return true; } //! A helper stream for decoding a percent-encoded sequence into code unit. /*! This stream decodes %XY triplet into code unit (0-255). If it encounters invalid characters, it sets output code unit as 0 and mark invalid, and to be checked by IsValid(). */ class PercentDecodeStream { public: typedef typename ValueType::Ch Ch; //! Constructor /*! \param source Start of the stream \param end Past-the-end of the stream. */ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} Ch Take() { if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet valid_ = false; return 0; } src_++; Ch c = 0; for (int j = 0; j < 2; j++) { c = static_cast<Ch>(c << 4); Ch h = *src_; if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0'); else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10); else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10); else { valid_ = false; return 0; } src_++; } return c; } size_t Tell() const { return static_cast<size_t>(src_ - head_); } bool IsValid() const { return valid_; } private: const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. const Ch* end_; //!< Past-the-end position. bool valid_; //!< Whether the parsing is valid. }; //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. template <typename OutputStream> class PercentEncodeStream { public: PercentEncodeStream(OutputStream& os) : os_(os) {} void Put(char c) { // UTF-8 must be byte unsigned char u = static_cast<unsigned char>(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4])); os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15])); } private: OutputStream& os_; }; Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. Allocator* ownAllocator_; //!< Allocator owned by this Pointer. Ch* nameBuffer_; //!< A buffer containing all names in tokens. Token* tokens_; //!< A list of tokens. size_t tokenCount_; //!< Number of tokens in tokens_. size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. PointerParseErrorCode parseErrorCode_; //!< Parsing error code. }; //! GenericPointer for Value (UTF-8, default allocator). typedef GenericPointer<Value> Pointer; //!@name Helper functions for GenericPointer //@{ ////////////////////////////////////////////////////////////////////////////// template <typename T> typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) { return pointer.Create(root, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a); } // No allocator parameter template <typename DocumentType> typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) { return pointer.Create(document); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document); } ////////////////////////////////////////////////////////////////////////////// template <typename T> typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template <typename T> const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template <typename T, typename CharType, size_t N> typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); } template <typename T, typename CharType, size_t N> const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); } ////////////////////////////////////////////////////////////////////////////// template <typename T> typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template <typename T> typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template <typename T> typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #endif template <typename T, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template <typename T, typename CharType, size_t N> typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); } #endif template <typename T, typename CharType, size_t N, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); } // No allocator parameter template <typename DocumentType> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template <typename DocumentType> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template <typename DocumentType> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #endif template <typename DocumentType, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); } #endif template <typename DocumentType, typename CharType, size_t N, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); } ////////////////////////////////////////////////////////////////////////////// template <typename T> typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template <typename T> typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template <typename T> typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template <typename T> typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #endif template <typename T, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template <typename T, typename CharType, size_t N> typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); } #endif template <typename T, typename CharType, size_t N, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); } // No allocator parameter template <typename DocumentType> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template <typename DocumentType> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template <typename DocumentType> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) { return pointer.Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template <typename DocumentType> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) { return pointer.Set(document, value); } #endif template <typename DocumentType, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) { return pointer.Set(document, value); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); } #endif template <typename DocumentType, typename CharType, size_t N, typename T2> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); } ////////////////////////////////////////////////////////////////////////////// template <typename T> typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Swap(root, value, a); } template <typename T, typename CharType, size_t N> typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a); } template <typename DocumentType> typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) { return pointer.Swap(document, value); } template <typename DocumentType, typename CharType, size_t N> typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value); } ////////////////////////////////////////////////////////////////////////////// template <typename T> bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) { return pointer.Erase(root); } template <typename T, typename CharType, size_t N> bool EraseValueByPointer(T& root, const CharType(&source)[N]) { return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root); } //@} RAPIDJSON_NAMESPACE_END #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_POINTER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/prettywriter.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. /*! \see PrettyWriter::SetFormatOptions */ enum PrettyFormatOptions { kFormatDefault = 0, //!< Default pretty formatting. kFormatSingleLineArray = 1 //!< Format arrays on a single line. }; //! Writer with indentation and spacing. /*! \tparam OutputStream Type of output os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> { public: typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base; typedef typename Base::Ch Ch; //! Constructor /*! \param os Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS PrettyWriter(PrettyWriter&& rhs) : Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} #endif //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } //! Set pretty writer formatting options. /*! \param options Formatting options. */ PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { formatOptions_ = options; return *this; } /*! @name Implementation of Handler \see Handler */ //@{ bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); return Base::EndValue(Base::WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string<Ch>& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); return Base::WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string<Ch>& str) { return Key(str.data(), SizeType(str.size())); } #endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::EndValue(Base::WriteEndObject()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::Flush(); return true; } bool StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true); return Base::WriteStartArray(); } bool EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray); bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::EndValue(Base::WriteEndArray()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::Flush(); return true; } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. */ bool RawValue(const Ch* json, size_t length, Type type) { RAPIDJSON_ASSERT(json != 0); PrettyPrefix(type); return Base::EndValue(Base::WriteRawValue(json, length)); } protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>(); if (level->inArray) { if (level->valueCount > 0) { Base::os_->Put(','); // add comma if it is not the first element in array if (formatOptions_ & kFormatSingleLineArray) Base::os_->Put(' '); } if (!(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::os_->Put(','); Base::os_->Put('\n'); } else { Base::os_->Put(':'); Base::os_->Put(' '); } } else Base::os_->Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. Base::hasRoot_ = true; } } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count); } Ch indentChar_; unsigned indentCharCount_; PrettyFormatOptions formatOptions_; private: // Prohibit copy constructor & assignment operator. PrettyWriter(const PrettyWriter&); PrettyWriter& operator=(const PrettyWriter&); }; RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/rapidjson.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ /*!\file rapidjson.h \brief common definitions and configuration \see RAPIDJSON_CONFIG */ /*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration \brief Configuration macros for library features Some RapidJSON features are configurable to adapt the library to a wide variety of platforms, environments and usage scenarios. Most of the features can be configured in terms of overridden or predefined preprocessor macros at compile-time. Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. \note These macros should be given on the compiler command-line (where applicable) to avoid inconsistent values when compiling different translation units of a single application. */ #include <cstdlib> // malloc(), realloc(), free(), size_t #include <cstring> // memset(), memcpy(), memmove(), memcmp() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_VERSION_STRING // // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. // //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x // token concatenation #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN2(X, Y) X##Y //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Major version of RapidJSON in integer. */ /*! \def RAPIDJSON_MINOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Minor version of RapidJSON in integer. */ /*! \def RAPIDJSON_PATCH_VERSION \ingroup RAPIDJSON_CONFIG \brief Patch version of RapidJSON in integer. */ /*! \def RAPIDJSON_VERSION_STRING \ingroup RAPIDJSON_CONFIG \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format. */ #define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 1 #define RAPIDJSON_PATCH_VERSION 0 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NAMESPACE_(BEGIN|END) /*! \def RAPIDJSON_NAMESPACE \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace In order to avoid symbol clashes and/or "One Definition Rule" errors between multiple inclusions of (different versions of) RapidJSON in a single binary, users can customize the name of the main RapidJSON namespace. In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref RAPIDJSON_NAMESPACE_END need to be defined as well: \code // in some .cpp file #define RAPIDJSON_NAMESPACE my::rapidjson #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { #define RAPIDJSON_NAMESPACE_END } } #include "rapidjson/..." \endcode \see rapidjson */ /*! \def RAPIDJSON_NAMESPACE_BEGIN \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (opening expression) \see RAPIDJSON_NAMESPACE */ /*! \def RAPIDJSON_NAMESPACE_END \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (closing expression) \see RAPIDJSON_NAMESPACE */ #ifndef RAPIDJSON_NAMESPACE #define RAPIDJSON_NAMESPACE rapidjson #endif #ifndef RAPIDJSON_NAMESPACE_BEGIN #define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { #endif #ifndef RAPIDJSON_NAMESPACE_END #define RAPIDJSON_NAMESPACE_END } #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_HAS_STDSTRING #ifndef RAPIDJSON_HAS_STDSTRING #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation #else #define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default #endif /*! \def RAPIDJSON_HAS_STDSTRING \ingroup RAPIDJSON_CONFIG \brief Enable RapidJSON support for \c std::string By defining this preprocessor symbol to \c 1, several convenience functions for using \ref rapidjson::GenericValue with \c std::string are enabled, especially for construction and comparison. \hideinitializer */ #endif // !defined(RAPIDJSON_HAS_STDSTRING) #if RAPIDJSON_HAS_STDSTRING #include <string> #endif // RAPIDJSON_HAS_STDSTRING /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE /*! \def RAPIDJSON_NO_INT64DEFINE \ingroup RAPIDJSON_CONFIG \brief Use external 64-bit integer types. RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types to be available at global scope. If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to prevent RapidJSON from defining its own types. */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else // Other compilers should have this. #include <stdint.h> #include <inttypes.h> #endif //!@endcond #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_INT64DEFINE #endif #endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE #endif //!@endcond #endif // RAPIDJSON_FORCEINLINE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! \def RAPIDJSON_ENDIAN \ingroup RAPIDJSON_CONFIG GCC 4.6 provided macro for detecting endianness of the target machine. But other compilers may not have this. User can define RAPIDJSON_ENDIAN to either \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. Default detection implemented with reference to \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp */ #ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro # ifdef __BYTE_ORDER__ # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) # include <endian.h> # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN // Detect with architecture macros # elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else # error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_64BIT //! Whether using 64-bit architecture #ifndef RAPIDJSON_64BIT #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) #define RAPIDJSON_64BIT 1 #else #define RAPIDJSON_64BIT 0 #endif #endif // RAPIDJSON_64BIT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ALIGN //! Data alignment of the machine. /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align Some machines require strict data alignment. The default is 8 bytes. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN #define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u)) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_UINT64_C2 //! Construct a 64-bit literal by a pair of 32-bit integer. /*! 64-bit literal with or without ULL suffix is prone to compiler warnings. UINT64_C() is C macro which cause compilation problems. Use this macro to define 64-bit constants by a pair of 32-bit integer. */ #ifndef RAPIDJSON_UINT64_C2 #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32)) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_48BITPOINTER_OPTIMIZATION //! Use only lower 48-bit address for some pointers. /*! \ingroup RAPIDJSON_CONFIG This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. The higher 16-bit can be used for storing other data. \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. */ #ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 #else #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 #endif #endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION #if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 #if RAPIDJSON_64BIT != 1 #error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 #endif #define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x)))) #define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) #else #define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) #define RAPIDJSON_GETPOINTER(type, p) (p) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel or ARM compatible processors. To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. #define RAPIDJSON_SSE42 \endcode // Enable ARM Neon optimization. #define RAPIDJSON_NEON \endcode \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_SIZETYPEDEFINE #ifndef RAPIDJSON_NO_SIZETYPEDEFINE /*! \def RAPIDJSON_NO_SIZETYPEDEFINE \ingroup RAPIDJSON_CONFIG \brief User-provided \c SizeType definition. In order to avoid using 32-bit size types for indexing strings and arrays, define this preprocessor symbol and provide the type rapidjson::SizeType before including RapidJSON: \code #define RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { typedef ::std::size_t SizeType; } #include "rapidjson/..." \endcode \see rapidjson::SizeType */ #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_SIZETYPEDEFINE #endif RAPIDJSON_NAMESPACE_BEGIN //! Size type (for string lengths, array sizes, etc.) /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, instead of using \c size_t. Users may override the SizeType by defining \ref RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; RAPIDJSON_NAMESPACE_END #endif // always import std::size_t to rapidjson namespace RAPIDJSON_NAMESPACE_BEGIN using std::size_t; RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ASSERT //! Assertion. /*! \ingroup RAPIDJSON_CONFIG By default, rapidjson uses C \c assert() for internal assertions. User can override it by defining RAPIDJSON_ASSERT(x) macro. \note Parsing errors are handled and can be customized by the \ref RAPIDJSON_ERRORS APIs. */ #ifndef RAPIDJSON_ASSERT #include <cassert> #define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT // Prefer C++11 static_assert, if available #ifndef RAPIDJSON_STATIC_ASSERT #if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) #define RAPIDJSON_STATIC_ASSERT(x) \ static_assert(x, RAPIDJSON_STRINGIFY(x)) #endif // C++11 #endif // RAPIDJSON_STATIC_ASSERT // Adopt C++03 implementation from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #endif RAPIDJSON_NAMESPACE_BEGIN template <bool x> struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; template <size_t x> struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif #ifndef __clang__ //!@endcond #endif /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time \param x compile-time condition \hideinitializer */ #define RAPIDJSON_STATIC_ASSERT(x) \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif // RAPIDJSON_STATIC_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY //! Compiler branching hint for expression with high probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression likely to be true. */ #ifndef RAPIDJSON_LIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) #else #define RAPIDJSON_LIKELY(x) (x) #endif #endif //! Compiler branching hint for expression with low probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression unlikely to be true. */ #ifndef RAPIDJSON_UNLIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define RAPIDJSON_UNLIKELY(x) (x) #endif #endif /////////////////////////////////////////////////////////////////////////////// // Helpers //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) // adopted from Boost #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) #if defined(__has_builtin) #define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) #else #define RAPIDJSON_HAS_BUILTIN(x) 0 #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF #if defined(__GNUC__) #define RAPIDJSON_GNUC \ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) #endif #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_OFF(x) \ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) // push/pop support in Clang and GCC>=4.6 #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else // GCC >= 4.2, < 4.6 #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif #elif defined(_MSC_VER) // pragma (MSVC specific) #define RAPIDJSON_PRAGMA(x) __pragma(x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else #define RAPIDJSON_DIAG_OFF(x) /* ignored */ #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif // RAPIDJSON_DIAG_* /////////////////////////////////////////////////////////////////////////////// // C++11 features #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) || \ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1900) || \ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else #define RAPIDJSON_NOEXCEPT /* noexcept */ #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS #if (defined(_MSC_VER) && _MSC_VER >= 1700) #define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 #else #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif #endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1700) || \ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 #endif #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR /////////////////////////////////////////////////////////////////////////////// // C++17 features #if defined(__has_cpp_attribute) # if __has_cpp_attribute(fallthrough) # define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] # else # define RAPIDJSON_DELIBERATE_FALLTHROUGH # endif #else # define RAPIDJSON_DELIBERATE_FALLTHROUGH #endif //!@endcond //! Assertion (in non-throwing contexts). /*! \ingroup RAPIDJSON_CONFIG Some functions provide a \c noexcept guarantee, if the compiler supports it. In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to throw an exception. This macro adds a separate customization point for such cases. Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is supported, and to \ref RAPIDJSON_ASSERT otherwise. */ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NOEXCEPT_ASSERT #ifndef RAPIDJSON_NOEXCEPT_ASSERT #ifdef RAPIDJSON_ASSERT_THROWS #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT_ASSERT(x) #else #include <cassert> #define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT #else #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) #endif // RAPIDJSON_ASSERT_THROWS #endif // RAPIDJSON_NOEXCEPT_ASSERT /////////////////////////////////////////////////////////////////////////////// // malloc/realloc/free #ifndef RAPIDJSON_MALLOC ///! customization point for global \c malloc #define RAPIDJSON_MALLOC(size) std::malloc(size) #endif #ifndef RAPIDJSON_REALLOC ///! customization point for global \c realloc #define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) #endif #ifndef RAPIDJSON_FREE ///! customization point for global \c free #define RAPIDJSON_FREE(ptr) std::free(ptr) #endif /////////////////////////////////////////////////////////////////////////////// // new/delete #ifndef RAPIDJSON_NEW ///! customization point for global \c new #define RAPIDJSON_NEW(TypeName) new TypeName #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete #define RAPIDJSON_DELETE(x) delete x #endif /////////////////////////////////////////////////////////////////////////////// // Type /*! \namespace rapidjson \brief main RapidJSON namespace \see RAPIDJSON_NAMESPACE */ RAPIDJSON_NAMESPACE_BEGIN //! Type of JSON value enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/reader.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ /*! \file reader.h */ #include "allocators.h" #include "stream.h" #include "encodedstream.h" #include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" #include <limits> #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include <intrin.h> #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include <nmmintrin.h> #elif defined(RAPIDJSON_SSE2) #include <emmintrin.h> #elif defined(RAPIDJSON_NEON) #include <arm_neon.h> #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(old-style-cast) RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_NOTHING /* deliberately empty */ #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) //!@endcond /*! \def RAPIDJSON_PARSE_ERROR_NORETURN \ingroup RAPIDJSON_ERRORS \brief Macro to indicate a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) This macros can be used as a customization point for the internal error handling mechanism of RapidJSON. A common usage model is to throw an exception instead of requiring the caller to explicitly check the \ref rapidjson::GenericReader::Parse's return value: \code #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ throw ParseException(parseErrorCode, #parseErrorCode, offset) #include <stdexcept> // std::runtime_error #include "rapidjson/error/error.h" // rapidjson::ParseResult struct ParseException : std::runtime_error, rapidjson::ParseResult { ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) : std::runtime_error(msg), ParseResult(code, offset) {} }; #include "rapidjson/reader.h" \endcode \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse */ #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ SetParseError(parseErrorCode, offset); \ RAPIDJSON_MULTILINEMACRO_END #endif /*! \def RAPIDJSON_PARSE_ERROR \ingroup RAPIDJSON_ERRORS \brief (Internal) macro to indicate and handle a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. \see RAPIDJSON_PARSE_ERROR_NORETURN \hideinitializer */ #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ RAPIDJSON_MULTILINEMACRO_END #endif #include "error/error.h" // ParseErrorCode, ParseResult RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag /*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. User can define this as any \c ParseFlag combinations. */ #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS #define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream */ enum ParseFlag { kParseNoFlags = 0, //!< No flags are set. kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// // Handler /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { typename Ch; bool Null(); bool Bool(bool b); bool Int(int i); bool Uint(unsigned i); bool Int64(int64_t i); bool Uint64(uint64_t i); bool Double(double d); /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType memberCount); bool StartArray(); bool EndArray(SizeType elementCount); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // BaseReaderHandler //! Default implementation of Handler. /*! This can be used as base class of any reader handler. \note implements Handler concept */ template<typename Encoding = UTF8<>, typename Derived = void> struct BaseReaderHandler { typedef typename Encoding::Ch Ch; typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override; bool Default() { return true; } bool Null() { return static_cast<Override&>(*this).Default(); } bool Bool(bool) { return static_cast<Override&>(*this).Default(); } bool Int(int) { return static_cast<Override&>(*this).Default(); } bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); } bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); } bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); } bool Double(double) { return static_cast<Override&>(*this).Default(); } /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); } bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); } bool StartObject() { return static_cast<Override&>(*this).Default(); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); } bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); } bool StartArray() { return static_cast<Override&>(*this).Default(); } bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); } }; /////////////////////////////////////////////////////////////////////////////// // StreamLocalCopy namespace internal { template<typename Stream, int = StreamTraits<Stream>::copyOptimization> class StreamLocalCopy; //! Do copy optimization. template<typename Stream> class StreamLocalCopy<Stream, 1> { public: StreamLocalCopy(Stream& original) : s(original), original_(original) {} ~StreamLocalCopy() { original_ = s; } Stream s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; Stream& original_; }; //! Keep reference. template<typename Stream> class StreamLocalCopy<Stream, 0> { public: StreamLocalCopy(Stream& original) : s(original) {} Stream& s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // SkipWhitespace //! Skip the JSON white spaces in a stream. /*! \param is A input stream for skipping white spaces. \note This function has SSE2/SSE4.2 specialization. */ template<typename InputStream> void SkipWhitespace(InputStream& is) { internal::StreamLocalCopy<InputStream> copy(is); InputStream& s(copy.s); typename InputStream::Ch c; while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') s.Take(); } inline const char* SkipWhitespace(const char* p, const char* end) { while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; return p; } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); if (r != 16) // some of characters is non-whitespace return p + r; } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The middle of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p)); const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); if (r != 16) // some of characters is non-whitespace return p + r; } return SkipWhitespace(p, end); } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } return SkipWhitespace(p, end); } #elif defined(RAPIDJSON_NEON) //! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; const uint8x16_t w0 = vmovq_n_u8(' '); const uint8x16_t w1 = vmovq_n_u8('\n'); const uint8x16_t w2 = vmovq_n_u8('\r'); const uint8x16_t w3 = vmovq_n_u8('\t'); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, w0); x = vorrq_u8(x, vceqq_u8(s, w1)); x = vorrq_u8(x, vceqq_u8(s, w2)); x = vorrq_u8(x, vceqq_u8(s, w3)); x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; const uint8x16_t w0 = vmovq_n_u8(' '); const uint8x16_t w1 = vmovq_n_u8('\n'); const uint8x16_t w2 = vmovq_n_u8('\r'); const uint8x16_t w3 = vmovq_n_u8('\t'); for (; p <= end - 16; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, w0); x = vorrq_u8(x, vceqq_u8(s, w1)); x = vorrq_u8(x, vceqq_u8(s, w2)); x = vorrq_u8(x, vceqq_u8(s, w3)); x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } return SkipWhitespace(p, end); } #endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& is) { is.src_ = SkipWhitespace_SIMD(is.src_); } template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) { is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); } #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. /*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. It needs to allocate a stack for storing a single decoded string during non-destructive parsing. For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. */ template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator> class GenericReader { public: typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type //! Constructor. /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template <unsigned parseFlags, typename InputStream, typename Handler> ParseResult Parse(InputStream& is, Handler& handler) { if (parseFlags & kParseIterativeFlag) return IterativeParse<parseFlags>(is, handler); parseResult_.Clear(); ClearStackOnExit scope(*this); SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { ParseValue<parseFlags>(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } } } return parseResult_; } //! Parse JSON text (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template <typename InputStream, typename Handler> ParseResult Parse(InputStream& is, Handler& handler) { return Parse<kParseDefaultFlags>(is, handler); } //! Initialize JSON text token-by-token parsing /*! */ void IterativeParseInit() { parseResult_.Clear(); state_ = IterativeParsingStartState; } //! Parse one token from JSON text /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template <unsigned parseFlags, typename InputStream, typename Handler> bool IterativeParseNext(InputStream& is, Handler& handler) { while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { SkipWhitespaceAndComments<parseFlags>(is); Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state_, t); IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler); // If we've finished or hit an error... if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { // Report errors. if (d == IterativeParsingErrorState) { HandleError(state_, is); return false; } // Transition to the finish state. RAPIDJSON_ASSERT(d == IterativeParsingFinishState); state_ = d; // If StopWhenDone is not set... if (!(parseFlags & kParseStopWhenDoneFlag)) { // ... and extra non-whitespace data is found... SkipWhitespaceAndComments<parseFlags>(is); if (is.Peek() != '\0') { // ... this is considered an error. HandleError(state_, is); return false; } } // Success! We are done! return true; } // Transition to the new state. state_ = d; // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. if (!IsIterativeParsingDelimiterState(n)) return true; } // We reached the end of file. stack_.Clear(); if (state_ != IterativeParsingFinishState) { HandleError(state_, is); return false; } return true; } //! Check if token-by-token parsing JSON text is complete /*! \return Whether the JSON has been fully decoded. */ RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { return IsIterativeParsingCompleteState(state_); } //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } protected: void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } private: // Prohibit copy constructor & assignment operator. GenericReader(const GenericReader&); GenericReader& operator=(const GenericReader&); void ClearStack() { stack_.Clear(); } // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericReader& r) : r_(r) {} ~ClearStackOnExit() { r_.ClearStack(); } private: GenericReader& r_; ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); }; template<unsigned parseFlags, typename InputStream> void SkipWhitespaceAndComments(InputStream& is) { SkipWhitespace(is); if (parseFlags & kParseCommentsFlag) { while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { if (Consume(is, '*')) { while (true) { if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); else if (Consume(is, '*')) { if (Consume(is, '/')) break; } else is.Take(); } } else if (RAPIDJSON_LIKELY(Consume(is, '/'))) while (is.Peek() != '\0' && is.Take() != '\n') {} else RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); SkipWhitespace(is); } } } // Parse object: { string : value, ... } template<unsigned parseFlags, typename InputStream, typename Handler> void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, '}')) { if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString<parseFlags>(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue<parseFlags>(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; switch (is.Peek()) { case ',': is.Take(); SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case '}': is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy } if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == '}') { if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } // Parse array: [ value, ... ] template<unsigned parseFlags, typename InputStream, typename Handler> void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' if (RAPIDJSON_UNLIKELY(!handler.StartArray())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType elementCount = 0;;) { ParseValue<parseFlags>(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ',')) { SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; } else if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } else RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == ']') { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } template<unsigned parseFlags, typename InputStream, typename Handler> void ParseNull(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { if (RAPIDJSON_UNLIKELY(!handler.Null())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template<unsigned parseFlags, typename InputStream, typename Handler> void ParseTrue(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template<unsigned parseFlags, typename InputStream, typename Handler> void ParseFalse(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template<typename InputStream> RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { if (RAPIDJSON_LIKELY(is.Peek() == expect)) { is.Take(); return true; } else return false; } // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). template<typename InputStream> unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = is.Peek(); codepoint <<= 4; codepoint += static_cast<unsigned>(c); if (c >= '0' && c <= '9') codepoint -= '0'; else if (c >= 'A' && c <= 'F') codepoint -= 'A' - 10; else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } is.Take(); } return codepoint; } template <typename CharType> class StackStream { public: typedef CharType Ch; StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {} RAPIDJSON_FORCEINLINE void Put(Ch c) { *stack_.template Push<Ch>() = c; ++length_; } RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push<Ch>(count); } size_t Length() const { return length_; } Ch* Pop() { return stack_.template Pop<Ch>(length_); } private: StackStream(const StackStream&); StackStream& operator=(const StackStream&); internal::Stack<StackAllocator>& stack_; SizeType length_; }; // Parse string and generate String event. Different code paths for kParseInsituFlag. template<unsigned parseFlags, typename InputStream, typename Handler> void ParseString(InputStream& is, Handler& handler, bool isKey = false) { internal::StreamLocalCopy<InputStream> copy(is); InputStream& s(copy.s); RAPIDJSON_ASSERT(s.Peek() == '\"'); s.Take(); // Skip '\"' bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { StackStream<typename TargetEncoding::Ch> stackStream(stack_); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SizeType length = static_cast<SizeType>(stackStream.Length()) - 1; const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } if (RAPIDJSON_UNLIKELY(!success)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse string to an output is // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream> RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 //!@endcond for (;;) { // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. if (!(parseFlags & kParseValidateEncodingFlag)) ScanCopyUnescapedString(is, os); Ch c = is.Peek(); if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset is.Take(); Ch e = is.Peek(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) { is.Take(); os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)])); } else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe is.Take(); os.Put('\''); } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { // high surrogate, check if followed by valid low surrogate if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) { // Handle UTF-16 surrogate pair if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); unsigned codepoint2 = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } // single low surrogate else { RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); } } TEncoding::Encode(os, codepoint); } else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); } else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? !Transcoder<SEncoding, TEncoding>::Validate(is, os) : !Transcoder<SEncoding, TEncoding>::Transcode(is, os)))) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); } } } template<typename InputStream, typename OutputStream> static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { // Do nothing for generic version } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) // StringStream -> StackStream<char> static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = p; return; } else os.Put(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast<SizeType>(__builtin_ffs(r) - 1); #endif if (length != 0) { char* q = reinterpret_cast<char*>(os.Push(length)); for (size_t i = 0; i < length; i++) q[i] = p[i]; p += length; } break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); } is.src_ = p; } // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); return; } char* p = is.src_; char *q = is.dst_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; } else *q++ = *p++; // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); for (;; p += 16, q += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast<size_t>(__builtin_ffs(r) - 1); #endif for (const char* pend = p + length; p != pend; ) *q++ = *p++; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); } is.src_ = p; is.dst_ = q; } // When read/write pointers are the same for insitu stream, just skip unescaped characters static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { RAPIDJSON_ASSERT(is.src_ == is.dst_); char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); for (; p != nextAligned; p++) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast<size_t>(__builtin_ffs(r) - 1); #endif p += length; break; } } is.src_ = is.dst_ = p; } #elif defined(RAPIDJSON_NEON) // StringStream -> StackStream<char> static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = p; return; } else os.Put(*p++); // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped if (length != 0) { char* q = reinterpret_cast<char*>(os.Push(length)); for (size_t i = 0; i < length; i++) q[i] = p[i]; p += length; } break; } vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s); } is.src_ = p; } // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); return; } char* p = is.src_; char *q = is.dst_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; } else *q++ = *p++; // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16, q += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped for (const char* pend = p + length; p != pend; ) { *q++ = *p++; } break; } vst1q_u8(reinterpret_cast<uint8_t *>(q), s); } is.src_ = p; is.dst_ = q; } // When read/write pointers are the same for insitu stream, just skip unescaped characters static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { RAPIDJSON_ASSERT(is.src_ == is.dst_); char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); for (; p != nextAligned; p++) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); p += 8 + (lz >> 3); break; } } else { uint32_t lz = internal::clzll(low); p += lz >> 3; break; } } is.src_ = is.dst_ = p; } #endif // RAPIDJSON_NEON template<typename InputStream, bool backup, bool pushOnTake> class NumberStream; template<typename InputStream> class NumberStream<InputStream, false, false> { public: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } const char* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); InputStream& is; }; template<typename InputStream> class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> { typedef NumberStream<InputStream, false, false> Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} RAPIDJSON_FORCEINLINE Ch TakePush() { stackStream.Put(static_cast<char>(Base::is.Peek())); return Base::is.Take(); } RAPIDJSON_FORCEINLINE void Push(char c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } const char* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: StackStream<char> stackStream; }; template<typename InputStream> class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> { typedef NumberStream<InputStream, true, false> Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template<unsigned parseFlags, typename InputStream, typename Handler> void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy<InputStream> copy(is); NumberStream<InputStream, ((parseFlags & kParseNumbersAsStringsFlag) != 0) ? ((parseFlags & kParseInsituFlag) == 0) : ((parseFlags & kParseFullPrecisionFlag) != 0), (parseFlags & kParseNumbersAsStringsFlag) != 0 && (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s); size_t startOffset = s.Tell(); double d = 0.0; bool useNanOrInf = false; // Parse minus bool minus = Consume(s, '-'); // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { i = 0; s.TakePush(); } else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast<unsigned>(s.TakePush() - '0'); if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); significandDigit++; } } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { if (Consume(s, 'N')) { if (Consume(s, 'a') && Consume(s, 'N')) { d = std::numeric_limits<double>::quiet_NaN(); useNanOrInf = true; } } else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { if (Consume(s, 'n') && Consume(s, 'f')) { d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity()); useNanOrInf = true; if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } } } if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; if (use64bit) { if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { d = static_cast<double>(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { d = static_cast<double>(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); significandDigit++; } } // Force double for big integer if (useDouble) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { d = d * 10 + (s.TakePush() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; size_t decimalPosition; if (Consume(s, '.')) { decimalPosition = s.Length(); if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { #if RAPIDJSON_64BIT // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); --expFrac; if (i64 != 0) significandDigit++; } } d = static_cast<double>(i64); #else // Use double to store significand in 32-bit architecture d = static_cast<double>(use64bit ? i64 : i); #endif useDouble = true; } while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else s.TakePush(); } } else decimalPosition = s.Length(); // decimal position at the end of integer. // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (Consume(s, 'e') || Consume(s, 'E')) { if (!useDouble) { d = static_cast<double>(use64bit ? i64 : i); useDouble = true; } bool expMinus = false; if (Consume(s, '+')) ; else if (Consume(s, '-')) expMinus = true; if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast<int>(s.Take() - '0'); if (expMinus) { // (exp + expFrac) must not underflow int => we're detecting when -exp gets // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into // underflow territory): // // -(exp * 10 + 9) + expFrac >= INT_MIN // <=> exp <= (expFrac - INT_MIN - 9) / 10 RAPIDJSON_ASSERT(expFrac <= 0); int maxExp = (expFrac + 2147483639) / 10; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast<int>(s.Take() - '0'); if (RAPIDJSON_UNLIKELY(exp > maxExp)) { while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast<int>(s.Take() - '0'); if (RAPIDJSON_UNLIKELY(exp > maxExp)) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } } } else RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); if (expMinus) exp = -exp; } // Finish parsing, call event according to the type of number. bool cont = true; if (parseFlags & kParseNumbersAsStringsFlag) { if (parseFlags & kParseInsituFlag) { s.Pop(); // Pop stack no matter if it will be used or not. typename InputStream::Ch* head = is.PutBegin(); const size_t length = s.Tell() - startOffset; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); // unable to insert the \0 character here, it will erase the comma after this number const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head); cont = handler.RawNumber(str, SizeType(length), false); } else { SizeType numCharsToCopy = static_cast<SizeType>(s.Length()); StringStream srcStream(s.Pop()); StackStream<typename TargetEncoding::Ch> dstStream(stack_); while (numCharsToCopy--) { Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1; cont = handler.RawNumber(str, SizeType(length), true); } } else { size_t length = s.Length(); const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; if (parseFlags & kParseFullPrecisionFlag) d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); else d = internal::StrtodNormalPrecision(d, p); // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal if (d > (std::numeric_limits<double>::max)()) { // Overflow // TODO: internal::StrtodX should report overflow (or underflow) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } cont = handler.Double(minus ? -d : d); } else if (useNanOrInf) { cont = handler.Double(d); } else { if (use64bit) { if (minus) cont = handler.Int64(static_cast<int64_t>(~i64 + 1)); else cont = handler.Uint64(i64); } else { if (minus) cont = handler.Int(static_cast<int32_t>(~i + 1)); else cont = handler.Uint(i); } } } if (RAPIDJSON_UNLIKELY(!cont)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); } // Parse any JSON value template<unsigned parseFlags, typename InputStream, typename Handler> void ParseValue(InputStream& is, Handler& handler) { switch (is.Peek()) { case 'n': ParseNull <parseFlags>(is, handler); break; case 't': ParseTrue <parseFlags>(is, handler); break; case 'f': ParseFalse <parseFlags>(is, handler); break; case '"': ParseString<parseFlags>(is, handler); break; case '{': ParseObject<parseFlags>(is, handler); break; case '[': ParseArray <parseFlags>(is, handler); break; default : ParseNumber<parseFlags>(is, handler); break; } } // Iterative Parsing // States enum IterativeParsingState { IterativeParsingFinishState = 0, // sink states at top IterativeParsingErrorState, // sink states at top IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, IterativeParsingMemberValueState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, IterativeParsingArrayFinishState, // Single value state IterativeParsingValueState, // Delimiter states (at bottom) IterativeParsingElementDelimiterState, IterativeParsingMemberDelimiterState, IterativeParsingKeyValueDelimiterState, cIterativeParsingStateCount }; // Tokens enum Token { LeftBracketToken = 0, RightBracketToken, LeftCurlyBracketToken, RightCurlyBracketToken, CommaToken, ColonToken, StringToken, FalseToken, TrueToken, NullToken, NumberToken, kTokenCount }; RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken #define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N // Maps from ASCII to Token static const unsigned char tokenMap[256] = { N16, // 00~0F N16, // 10~1F N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F N16, // 40~4F N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF }; #undef N #undef N16 //!@endcond if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]); else return NumberToken; } RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { // Finish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Error(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Start { IterativeParsingArrayInitialState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingValueState, // String IterativeParsingValueState, // False IterativeParsingValueState, // True IterativeParsingValueState, // Null IterativeParsingValueState // Number }, // ObjectInitial { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberKey { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingKeyValueDelimiterState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberValue { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingMemberDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ArrayInitial { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // Element { IterativeParsingErrorState, // Left bracket IterativeParsingArrayFinishState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingElementDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ArrayFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Single Value (sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // MemberDelimiter { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // KeyValueDelimiter { IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberValueState, // String IterativeParsingMemberValueState, // False IterativeParsingMemberValueState, // True IterativeParsingMemberValueState, // Null IterativeParsingMemberValueState // Number }, }; // End of G return static_cast<IterativeParsingState>(G[state][token]); } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // May return a new state on state pop. template <unsigned parseFlags, typename InputStream, typename Handler> RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { (void)token; switch (dst) { case IterativeParsingErrorState: return dst; case IterativeParsingObjectInitialState: case IterativeParsingArrayInitialState: { // Push the state(Element or MemeberValue) if we are nested in another array or value of member. // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. IterativeParsingState n = src; if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) n = IterativeParsingElementState; else if (src == IterativeParsingKeyValueDelimiterState) n = IterativeParsingMemberValueState; // Push current state. *stack_.template Push<SizeType>(1) = n; // Initialize and push the member/element count. *stack_.template Push<SizeType>(1) = 0; // Call handler bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return dst; } } case IterativeParsingMemberKeyState: ParseString<parseFlags>(is, handler, true); if (HasParseError()) return IterativeParsingErrorState; else return dst; case IterativeParsingKeyValueDelimiterState: RAPIDJSON_ASSERT(token == ColonToken); is.Take(); return dst; case IterativeParsingMemberValueState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue<parseFlags>(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingElementState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue<parseFlags>(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingMemberDelimiterState: case IterativeParsingElementDelimiterState: is.Take(); // Update member/element count. *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1; return dst; case IterativeParsingObjectFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); return IterativeParsingErrorState; } // Get member count. SizeType c = *stack_.template Pop<SizeType>(1); // If the object is not empty, count the last member. if (src == IterativeParsingMemberValueState) ++c; // Restore the state. IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndObject(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } case IterativeParsingArrayFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); return IterativeParsingErrorState; } // Get element count. SizeType c = *stack_.template Pop<SizeType>(1); // If the array is not empty, count the last element. if (src == IterativeParsingElementState) ++c; // Restore the state. IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndArray(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } default: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. // The IterativeParsingStartState is not enumerated in this switch-case. // It is impossible for that case. And it can be caught by following assertion. // The IterativeParsingFinishState is not enumerated in this switch-case either. // It is a "derivative" state which cannot triggered from Predict() directly. // Therefore it cannot happen here. And it can be caught by following assertion. RAPIDJSON_ASSERT(dst == IterativeParsingValueState); // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue<parseFlags>(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return IterativeParsingFinishState; } } template <typename InputStream> void HandleError(IterativeParsingState src, InputStream& is) { if (HasParseError()) { // Error flag has been set. return; } switch (src) { case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingKeyValueDelimiterState: case IterativeParsingArrayInitialState: case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; } } RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { return s >= IterativeParsingElementDelimiterState; } RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { return s <= IterativeParsingErrorState; } template <unsigned parseFlags, typename InputStream, typename Handler> ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler); if (d == IterativeParsingErrorState) { HandleError(state, is); break; } state = d; // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. typedef GenericReader<UTF8<>, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_READER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/schema.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available-> // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License-> You may obtain a copy of the License at // // http://opensource->org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied-> See the License for the // specific language governing permissions and limitations under the License-> #ifndef RAPIDJSON_SCHEMA_H_ #define RAPIDJSON_SCHEMA_H_ #include "document.h" #include "pointer.h" #include "stringbuffer.h" #include "error/en.h" #include <cmath> // abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX #include "internal/regex.h" #elif RAPIDJSON_SCHEMA_USE_STDREGEX #include <regex> #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX #define RAPIDJSON_SCHEMA_HAS_REGEX 1 #else #define RAPIDJSON_SCHEMA_HAS_REGEX 0 #endif #ifndef RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_VERBOSE 0 #endif #if RAPIDJSON_SCHEMA_VERBOSE #include "stringbuffer.h" #endif RAPIDJSON_DIAG_PUSH #if defined(__GNUC__) RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_OFF(weak-vtables) RAPIDJSON_DIAG_OFF(exit-time-destructors) RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) RAPIDJSON_DIAG_OFF(variadic-macros) #elif defined(_MSC_VER) RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Verbose Utilities #if RAPIDJSON_SCHEMA_VERBOSE namespace internal { inline void PrintInvalidKeyword(const char* keyword) { printf("Fail keyword: %s\n", keyword); } inline void PrintInvalidKeyword(const wchar_t* keyword) { wprintf(L"Fail keyword: %ls\n", keyword); } inline void PrintInvalidDocument(const char* document) { printf("Fail document: %s\n\n", document); } inline void PrintInvalidDocument(const wchar_t* document) { wprintf(L"Fail document: %ls\n\n", document); } inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); } inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); } } // namespace internal #endif // RAPIDJSON_SCHEMA_VERBOSE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_INVALID_KEYWORD_RETURN #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) #else #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) #endif #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ RAPIDJSON_MULTILINEMACRO_BEGIN\ context.invalidCode = code;\ context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\ return false;\ RAPIDJSON_MULTILINEMACRO_END /////////////////////////////////////////////////////////////////////////////// // ValidateFlag /*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kValidateDefaultFlags definition. User can define this as any \c ValidateFlag combinations. */ #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags #endif //! Combination of validate flags /*! \see */ enum ValidateFlag { kValidateNoFlags = 0, //!< No flags are set. kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error. kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// // Forward declarations template <typename ValueType, typename Allocator> class GenericSchemaDocument; namespace internal { template <typename SchemaDocumentType> class Schema; /////////////////////////////////////////////////////////////////////////////// // ISchemaValidator class ISchemaValidator { public: virtual ~ISchemaValidator() {} virtual bool IsValid() const = 0; virtual void SetValidateFlags(unsigned flags) = 0; virtual unsigned GetValidateFlags() const = 0; }; /////////////////////////////////////////////////////////////////////////////// // ISchemaStateFactory template <typename SchemaType> class ISchemaStateFactory { public: virtual ~ISchemaStateFactory() {} virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0; virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; virtual void* CreateHasher() = 0; virtual uint64_t GetHashCode(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0; virtual void* MallocState(size_t size) = 0; virtual void FreeState(void* p) = 0; }; /////////////////////////////////////////////////////////////////////////////// // IValidationErrorHandler template <typename SchemaType> class IValidationErrorHandler { public: typedef typename SchemaType::Ch Ch; typedef typename SchemaType::SValue SValue; virtual ~IValidationErrorHandler() {} virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; virtual void NotMultipleOf(double actual, const SValue& expected) = 0; virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; virtual void DisallowedItem(SizeType index) = 0; virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; virtual void StartMissingProperties() = 0; virtual void AddMissingProperty(const SValue& name) = 0; virtual bool EndMissingProperties() = 0; virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; virtual void StartDependencyErrors() = 0; virtual void StartMissingDependentProperties() = 0; virtual void AddMissingDependentProperty(const SValue& targetName) = 0; virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; virtual bool EndDependencyErrors() = 0; virtual void DisallowedValue(const ValidateErrorCode code) = 0; virtual void StartDisallowedType() = 0; virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0; virtual void Disallowed() = 0; }; /////////////////////////////////////////////////////////////////////////////// // Hasher // For comparison of compound value template<typename Encoding, typename Allocator> class Hasher { public: typedef typename Encoding::Ch Ch; Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} bool Null() { return WriteType(kNullType); } bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); } bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); } bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); } bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); } bool Double(double d) { Number n; if (d < 0) n.u.i = static_cast<int64_t>(d); else n.u.u = static_cast<uint64_t>(d); n.d = d; return WriteNumber(n); } bool RawNumber(const Ch* str, SizeType len, bool) { WriteBuffer(kNumberType, str, len * sizeof(Ch)); return true; } bool String(const Ch* str, SizeType len, bool) { WriteBuffer(kStringType, str, len * sizeof(Ch)); return true; } bool StartObject() { return true; } bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } bool EndObject(SizeType memberCount) { uint64_t h = Hash(0, kObjectType); uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2); for (SizeType i = 0; i < memberCount; i++) h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive *stack_.template Push<uint64_t>() = h; return true; } bool StartArray() { return true; } bool EndArray(SizeType elementCount) { uint64_t h = Hash(0, kArrayType); uint64_t* e = stack_.template Pop<uint64_t>(elementCount); for (SizeType i = 0; i < elementCount; i++) h = Hash(h, e[i]); // Use hash to achieve element order sensitive *stack_.template Push<uint64_t>() = h; return true; } bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } uint64_t GetHashCode() const { RAPIDJSON_ASSERT(IsValid()); return *stack_.template Top<uint64_t>(); } private: static const size_t kDefaultSize = 256; struct Number { union U { uint64_t u; int64_t i; }u; double d; }; bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } bool WriteBuffer(Type type, const void* data, size_t len) { // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); const unsigned char* d = static_cast<const unsigned char*>(data); for (size_t i = 0; i < len; i++) h = Hash(h, d[i]); *stack_.template Push<uint64_t>() = h; return true; } static uint64_t Hash(uint64_t h, uint64_t d) { static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); h ^= d; h *= kPrime; return h; } Stack<Allocator> stack_; }; /////////////////////////////////////////////////////////////////////////////// // SchemaValidationContext template <typename SchemaDocumentType> struct SchemaValidationContext { typedef Schema<SchemaDocumentType> SchemaType; typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType; typedef IValidationErrorHandler<SchemaType> ErrorHandlerType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; enum PatternValidatorType { kPatternValidatorOnly, kPatternValidatorWithProperty, kPatternValidatorWithAdditionalProperty }; SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : factory(f), error_handler(eh), schema(s), valueSchema(), invalidKeyword(), invalidCode(), hasher(), arrayElementHashCodes(), validators(), validatorCount(), patternPropertiesValidators(), patternPropertiesValidatorCount(), patternPropertiesSchemas(), patternPropertiesSchemaCount(), valuePatternValidatorType(kPatternValidatorOnly), propertyExist(), inArray(false), valueUniqueness(false), arrayUniqueness(false) { } ~SchemaValidationContext() { if (hasher) factory.DestroryHasher(hasher); if (validators) { for (SizeType i = 0; i < validatorCount; i++) factory.DestroySchemaValidator(validators[i]); factory.FreeState(validators); } if (patternPropertiesValidators) { for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) factory.DestroySchemaValidator(patternPropertiesValidators[i]); factory.FreeState(patternPropertiesValidators); } if (patternPropertiesSchemas) factory.FreeState(patternPropertiesSchemas); if (propertyExist) factory.FreeState(propertyExist); } SchemaValidatorFactoryType& factory; ErrorHandlerType& error_handler; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; ValidateErrorCode invalidCode; void* hasher; // Only validator access void* arrayElementHashCodes; // Only validator access this ISchemaValidator** validators; SizeType validatorCount; ISchemaValidator** patternPropertiesValidators; SizeType patternPropertiesValidatorCount; const SchemaType** patternPropertiesSchemas; SizeType patternPropertiesSchemaCount; PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; SizeType arrayElementIndex; bool* propertyExist; bool inArray; bool valueUniqueness; bool arrayUniqueness; }; /////////////////////////////////////////////////////////////////////////////// // Schema template <typename SchemaDocumentType> class Schema { public: typedef typename SchemaDocumentType::ValueType ValueType; typedef typename SchemaDocumentType::AllocatorType AllocatorType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef SchemaValidationContext<SchemaDocumentType> Context; typedef Schema<SchemaDocumentType> SchemaType; typedef GenericValue<EncodingType, AllocatorType> SValue; typedef IValidationErrorHandler<Schema> ErrorHandler; friend class GenericSchemaDocument<ValueType, AllocatorType>; Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), uri_(schemaDocument->GetURI(), *allocator), pointer_(p, allocator), typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), notValidatorIndex_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), patternPropertyCount_(), propertyCount_(), minProperties_(), maxProperties_(SizeType(~0)), additionalProperties_(true), hasDependencies_(), hasRequired_(), hasSchemaDependencies_(), additionalItemsSchema_(), itemsList_(), itemsTuple_(), itemsTupleCount_(), minItems_(), maxItems_(SizeType(~0)), additionalItems_(true), uniqueItems_(false), pattern_(), minLength_(0), maxLength_(~SizeType(0)), exclusiveMinimum_(false), exclusiveMaximum_(false), defaultValueLength_(0) { typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; if (!value.IsObject()) return; if (const ValueType* v = GetMember(value, GetTypeString())) { type_ = 0; if (v->IsString()) AddType(*v); else if (v->IsArray()) for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) AddType(*itr); } if (const ValueType* v = GetMember(value, GetEnumString())) { if (v->IsArray() && v->Size() > 0) { enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType; char buffer[256u + 24]; MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); enum_[enumCount_++] = h.GetHashCode(); } } } if (schemaDocument) { AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); } if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); notValidatorIndex_ = validatorCount_; validatorCount_++; } // Object const ValueType* properties = GetMember(value, GetPropertiesString()); const ValueType* required = GetMember(value, GetRequiredString()); const ValueType* dependencies = GetMember(value, GetDependenciesString()); { // Gather properties from properties/required/dependencies SValue allProperties(kArrayType); if (properties && properties->IsObject()) for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) AddUniqueElement(allProperties, itr->name); if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) AddUniqueElement(allProperties, *itr); if (dependencies && dependencies->IsObject()) for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { AddUniqueElement(allProperties, itr->name); if (itr->value.IsArray()) for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) if (i->IsString()) AddUniqueElement(allProperties, *i); } if (allProperties.Size() > 0) { propertyCount_ = allProperties.Size(); properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_)); for (SizeType i = 0; i < propertyCount_; i++) { new (&properties_[i]) Property(); properties_[i].name = allProperties[i]; properties_[i].schema = typeless_; } } } if (properties && properties->IsObject()) { PointerType q = p.Append(GetPropertiesString(), allocator_); for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); } } if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { PointerType q = p.Append(GetPatternPropertiesString(), allocator_); patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); patternPropertyCount_ = 0; for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { new (&patternProperties_[patternPropertyCount_]) PatternProperty(); patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); patternPropertyCount_++; } } if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) { SizeType index; if (FindPropertyIndex(*itr, &index)) { properties_[index].required = true; hasRequired_ = true; } } if (dependencies && dependencies->IsObject()) { PointerType q = p.Append(GetDependenciesString(), allocator_); hasDependencies_ = true; for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { SizeType sourceIndex; if (FindPropertyIndex(itr->name, &sourceIndex)) { if (itr->value.IsArray()) { properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_)); std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { SizeType targetIndex; if (FindPropertyIndex(*targetItr, &targetIndex)) properties_[sourceIndex].dependencies[targetIndex] = true; } } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } } } } if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); // Array if (const ValueType* v = GetMember(value, GetItemsString())) { PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation schemaDocument->CreateSchema(&itemsList_, q, *v, document); else if (v->IsArray()) { // Tuple validation itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size())); SizeType index = 0; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); } } AssignIfExist(minItems_, value, GetMinItemsString()); AssignIfExist(maxItems_, value, GetMaxItemsString()); if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); // String AssignIfExist(minLength_, value, GetMinLengthString()); AssignIfExist(maxLength_, value, GetMaxLengthString()); if (const ValueType* v = GetMember(value, GetPatternString())) pattern_ = CreatePattern(*v); // Number if (const ValueType* v = GetMember(value, GetMinimumString())) if (v->IsNumber()) minimum_.CopyFrom(*v, *allocator_); if (const ValueType* v = GetMember(value, GetMaximumString())) if (v->IsNumber()) maximum_.CopyFrom(*v, *allocator_); AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); if (const ValueType* v = GetMember(value, GetMultipleOfString())) if (v->IsNumber() && v->GetDouble() > 0.0) multipleOf_.CopyFrom(*v, *allocator_); // Default if (const ValueType* v = GetMember(value, GetDefaultValueString())) if (v->IsString()) defaultValueLength_ = v->GetStringLength(); } ~Schema() { AllocatorType::Free(enum_); if (properties_) { for (SizeType i = 0; i < propertyCount_; i++) properties_[i].~Property(); AllocatorType::Free(properties_); } if (patternProperties_) { for (SizeType i = 0; i < patternPropertyCount_; i++) patternProperties_[i].~PatternProperty(); AllocatorType::Free(patternProperties_); } AllocatorType::Free(itemsTuple_); #if RAPIDJSON_SCHEMA_HAS_REGEX if (pattern_) { pattern_->~RegexType(); AllocatorType::Free(pattern_); } #endif } const SValue& GetURI() const { return uri_; } const PointerType& GetPointer() const { return pointer_; } bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; if (itemsList_) context.valueSchema = itemsList_; else if (itemsTuple_) { if (context.arrayElementIndex < itemsTupleCount_) context.valueSchema = itemsTuple_[context.arrayElementIndex]; else if (additionalItemsSchema_) context.valueSchema = additionalItemsSchema_; else if (additionalItems_) context.valueSchema = typeless_; else { context.error_handler.DisallowedItem(context.arrayElementIndex); // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error context.valueSchema = typeless_; // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set context.arrayElementIndex++; RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems); } } else context.valueSchema = typeless_; context.arrayElementIndex++; } return true; } RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) otherValid = context.patternPropertiesValidators[--count]->IsValid(); bool patternValid = true; for (SizeType i = 0; i < count; i++) if (!context.patternPropertiesValidators[i]->IsValid()) { patternValid = false; break; } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { if (!patternValid) { context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); } } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { if (!patternValid || !otherValid) { context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); } } else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties); } } // For enums only check if we have a hasher if (enum_ && context.hasher) { const uint64_t h = context.factory.GetHashCode(context.hasher); for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; context.error_handler.DisallowedValue(kValidateErrorEnum); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum); foundEnum:; } if (allOf_.schemas) for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) if (!context.validators[i]->IsValid()) { context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); } if (anyOf_.schemas) { for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) if (context.validators[i]->IsValid()) goto foundAny; context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); foundAny:; } if (oneOf_.schemas) { bool oneValid = false; for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { if (oneValid) { context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); } else oneValid = true; } if (!oneValid) { context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); } } if (not_ && context.validators[notValidatorIndex_]->IsValid()) { context.error_handler.Disallowed(); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); } return true; } bool Null(Context& context) const { if (!(type_ & (1 << kNullSchemaType))) { DisallowedType(context, GetNullString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } return CreateParallelValidator(context); } bool Bool(Context& context, bool) const { if (!(type_ & (1 << kBooleanSchemaType))) { DisallowedType(context, GetBooleanString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } return CreateParallelValidator(context); } bool Int(Context& context, int i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint(Context& context, unsigned u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Int64(Context& context, int64_t i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint64(Context& context, uint64_t u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Double(Context& context, double d) const { if (!(type_ & (1 << kNumberSchemaType))) { DisallowedType(context, GetNumberString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) return false; if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) return false; if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) return false; return CreateParallelValidator(context); } bool String(Context& context, const Ch* str, SizeType length, bool) const { if (!(type_ & (1 << kStringSchemaType))) { DisallowedType(context, GetStringString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) { if (count < minLength_) { context.error_handler.TooShort(str, length, minLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength); } if (count > maxLength_) { context.error_handler.TooLong(str, length, maxLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength); } } } if (pattern_ && !IsPatternMatch(pattern_, str, length)) { context.error_handler.DoesNotMatch(str, length); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern); } return CreateParallelValidator(context); } bool StartObject(Context& context) const { if (!(type_ & (1 << kObjectSchemaType))) { DisallowedType(context, GetObjectString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_)); std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); } if (patternProperties_) { // pre-allocate schema array SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count)); context.patternPropertiesSchemaCount = 0; std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); } return CreateParallelValidator(context); } bool Key(Context& context, const Ch* str, SizeType len, bool) const { if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; context.valueSchema = typeless_; } } SizeType index = 0; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; } else context.valueSchema = properties_[index].schema; if (context.propertyExist) context.propertyExist[index] = true; return true; } if (additionalPropertiesSchema_) { if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; } else context.valueSchema = additionalPropertiesSchema_; return true; } else if (additionalProperties_) { context.valueSchema = typeless_; return true; } if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error context.valueSchema = typeless_; context.error_handler.DisallowedProperty(str, len); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties); } return true; } bool EndObject(Context& context, SizeType memberCount) const { if (hasRequired_) { context.error_handler.StartMissingProperties(); for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].required && !context.propertyExist[index]) if (properties_[index].schema->defaultValueLength_ == 0 ) context.error_handler.AddMissingProperty(properties_[index].name); if (context.error_handler.EndMissingProperties()) RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired); } if (memberCount < minProperties_) { context.error_handler.TooFewProperties(memberCount, minProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties); } if (memberCount > maxProperties_) { context.error_handler.TooManyProperties(memberCount, maxProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties); } if (hasDependencies_) { context.error_handler.StartDependencyErrors(); for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { const Property& source = properties_[sourceIndex]; if (context.propertyExist[sourceIndex]) { if (source.dependencies) { context.error_handler.StartMissingDependentProperties(); for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); context.error_handler.EndMissingDependentProperties(source.name); } else if (source.dependenciesSchema) { ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; if (!dependenciesValidator->IsValid()) context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); } } } if (context.error_handler.EndDependencyErrors()) RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies); } return true; } bool StartArray(Context& context) const { context.arrayElementIndex = 0; context.inArray = true; // Ensure we note that we are in an array if (!(type_ & (1 << kArraySchemaType))) { DisallowedType(context, GetArrayString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } return CreateParallelValidator(context); } bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; if (elementCount < minItems_) { context.error_handler.TooFewItems(elementCount, minItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems); } if (elementCount > maxItems_) { context.error_handler.TooManyItems(elementCount, maxItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems); } return true; } static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) { switch (validateErrorCode) { case kValidateErrorMultipleOf: return GetMultipleOfString(); case kValidateErrorMaximum: return GetMaximumString(); case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same case kValidateErrorMinimum: return GetMinimumString(); case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same case kValidateErrorMaxLength: return GetMaxLengthString(); case kValidateErrorMinLength: return GetMinLengthString(); case kValidateErrorPattern: return GetPatternString(); case kValidateErrorMaxItems: return GetMaxItemsString(); case kValidateErrorMinItems: return GetMinItemsString(); case kValidateErrorUniqueItems: return GetUniqueItemsString(); case kValidateErrorAdditionalItems: return GetAdditionalItemsString(); case kValidateErrorMaxProperties: return GetMaxPropertiesString(); case kValidateErrorMinProperties: return GetMinPropertiesString(); case kValidateErrorRequired: return GetRequiredString(); case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString(); case kValidateErrorPatternProperties: return GetPatternPropertiesString(); case kValidateErrorDependencies: return GetDependenciesString(); case kValidateErrorEnum: return GetEnumString(); case kValidateErrorType: return GetTypeString(); case kValidateErrorOneOf: return GetOneOfString(); case kValidateErrorOneOfMatch: return GetOneOfString(); // Same case kValidateErrorAllOf: return GetAllOfString(); case kValidateErrorAnyOf: return GetAnyOfString(); case kValidateErrorNot: return GetNotString(); default: return GetNullString(); } } // Generate functions for string literal according to Ch #define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\ return v;\ } RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') RAPIDJSON_STRING_(Not, 'n', 'o', 't') RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') #undef RAPIDJSON_STRING_ private: enum SchemaValueType { kNullSchemaType, kBooleanSchemaType, kObjectSchemaType, kArraySchemaType, kStringSchemaType, kNumberSchemaType, kIntegerSchemaType, kTotalSchemaType }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex<Ch> RegexType; #else typedef char RegexType; #endif struct SchemaArray { SchemaArray() : schemas(), count() {} ~SchemaArray() { AllocatorType::Free(schemas); } const SchemaType** schemas; SizeType begin; // begin index of context.validators SizeType count; }; template <typename V1, typename V2> void AddUniqueElement(V1& a, const V2& v) { for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) if (*itr == v) return; V1 c(v, *allocator_); a.PushBack(c, *allocator_); } static const ValueType* GetMember(const ValueType& value, const ValueType& name) { typename ValueType::ConstMemberIterator itr = value.FindMember(name); return itr != value.MemberEnd() ? &(itr->value) : 0; } static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsBool()) out = v->GetBool(); } static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) out = static_cast<SizeType>(v->GetUint64()); } void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { if (const ValueType* v = GetMember(value, name)) { if (v->IsArray() && v->Size() > 0) { PointerType q = p.Append(name, allocator_); out.count = v->Size(); out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*))); memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); out.begin = validatorCount_; validatorCount_ += out.count; } } } #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX template <typename ValueType> RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); r = 0; } return r; } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { GenericRegexSearch<RegexType> rs(*pattern); return rs.Search(str); } #elif RAPIDJSON_SCHEMA_USE_STDREGEX template <typename ValueType> RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType))); try { return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); } catch (const std::regex_error&) { AllocatorType::Free(r); } } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { std::match_results<const Ch*> r; return std::regex_search(str, str + length, r, *pattern); } #else template <typename ValueType> RegexType* CreatePattern(const ValueType&) { return 0; } static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } #endif // RAPIDJSON_SCHEMA_USE_STDREGEX void AddType(const ValueType& type) { if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); } bool CreateParallelValidator(Context& context) const { if (enum_ || context.arrayUniqueness) context.hasher = context.factory.CreateHasher(); if (validatorCount_) { RAPIDJSON_ASSERT(context.validators == 0); context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); context.validatorCount = validatorCount_; // Always return after first failure for these sub-validators if (allOf_.schemas) CreateSchemaValidators(context, allOf_, false); if (anyOf_.schemas) CreateSchemaValidators(context, anyOf_, false); if (oneOf_.schemas) CreateSchemaValidators(context, oneOf_, false); if (not_) context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false); if (hasSchemaDependencies_) { for (SizeType i = 0; i < propertyCount_; i++) if (properties_[i].dependenciesSchema) context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false); } } return true; } void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const { for (SizeType i = 0; i < schemas.count; i++) context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors); } // O(n) bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { SizeType len = name.GetStringLength(); const Ch* str = name.GetString(); for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].name.GetStringLength() == len && (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) { *outIndex = index; return true; } return false; } bool CheckInt(Context& context, int64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { DisallowedType(context, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); } } else if (minimum_.IsUint64()) { context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64() } else if (!CheckDoubleMinimum(context, static_cast<double>(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); } } else if (maximum_.IsUint64()) { } /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() else if (!CheckDoubleMaximum(context, static_cast<double>(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); } } else if (!CheckDoubleMultipleOf(context, static_cast<double>(i))) return false; } return true; } bool CheckUint(Context& context, uint64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { DisallowedType(context, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType); } if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); } } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() else if (!CheckDoubleMinimum(context, static_cast<double>(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); } } else if (maximum_.IsInt64()) { context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_ } else if (!CheckDoubleMaximum(context, static_cast<double>(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (i % multipleOf_.GetUint64() != 0) { context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); } } else if (!CheckDoubleMultipleOf(context, static_cast<double>(i))) return false; } return true; } bool CheckDoubleMinimum(Context& context, double d) const { if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); } return true; } bool CheckDoubleMaximum(Context& context, double d) const { if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); } return true; } bool CheckDoubleMultipleOf(Context& context, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); double q = std::floor(a / b); double r = a - q * b; if (r > 0.0) { context.error_handler.NotMultipleOf(d, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf); } return true; } void DisallowedType(Context& context, const ValueType& actualType) const { ErrorHandler& eh = context.error_handler; eh.StartDisallowedType(); if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); eh.EndDisallowedType(actualType); } struct Property { Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} ~Property() { AllocatorType::Free(dependencies); } SValue name; const SchemaType* schema; const SchemaType* dependenciesSchema; SizeType dependenciesValidatorIndex; bool* dependencies; bool required; }; struct PatternProperty { PatternProperty() : schema(), pattern() {} ~PatternProperty() { if (pattern) { pattern->~RegexType(); AllocatorType::Free(pattern); } } const SchemaType* schema; RegexType* pattern; }; AllocatorType* allocator_; SValue uri_; PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; SchemaArray allOf_; SchemaArray anyOf_; SchemaArray oneOf_; const SchemaType* not_; unsigned type_; // bitmask of kSchemaType SizeType validatorCount_; SizeType notValidatorIndex_; Property* properties_; const SchemaType* additionalPropertiesSchema_; PatternProperty* patternProperties_; SizeType patternPropertyCount_; SizeType propertyCount_; SizeType minProperties_; SizeType maxProperties_; bool additionalProperties_; bool hasDependencies_; bool hasRequired_; bool hasSchemaDependencies_; const SchemaType* additionalItemsSchema_; const SchemaType* itemsList_; const SchemaType** itemsTuple_; SizeType itemsTupleCount_; SizeType minItems_; SizeType maxItems_; bool additionalItems_; bool uniqueItems_; RegexType* pattern_; SizeType minLength_; SizeType maxLength_; SValue minimum_; SValue maximum_; SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; SizeType defaultValueLength_; }; template<typename Stack, typename Ch> struct TokenHelper { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { *documentStack.template Push<Ch>() = '/'; char buffer[21]; size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); for (size_t i = 0; i < length; i++) *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]); } }; // Partial specialized version for char to prevent buffer copying. template <typename Stack> struct TokenHelper<Stack, char> { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { if (sizeof(SizeType) == 4) { char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint *buffer++ = '/'; const char* end = internal::u32toa(index, buffer); documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer))); } else { char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64 *buffer++ = '/'; const char* end = internal::u64toa(index, buffer); documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer))); } } }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // IGenericRemoteSchemaDocumentProvider template <typename SchemaDocumentType> class IGenericRemoteSchemaDocumentProvider { public: typedef typename SchemaDocumentType::Ch Ch; virtual ~IGenericRemoteSchemaDocumentProvider() {} virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; }; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaDocument //! JSON schema document. /*! A JSON schema document is a compiled version of a JSON schema. It is basically a tree of internal::Schema. \note This is an immutable class (i.e. its instance cannot be modified after construction). \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. \tparam Allocator Allocator type for allocating memory of this document. */ template <typename ValueT, typename Allocator = CrtAllocator> class GenericSchemaDocument { public: typedef ValueT ValueType; typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType; typedef Allocator AllocatorType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef internal::Schema<GenericSchemaDocument> SchemaType; typedef GenericPointer<ValueType, Allocator> PointerType; typedef GenericValue<EncodingType, Allocator> URIType; friend class internal::Schema<GenericSchemaDocument>; template <typename, typename, typename> friend class GenericSchemaValidator; //! Constructor. /*! Compile a JSON document into schema document. \param document A JSON document as source. \param uri The base URI of this schema document for purposes of violation reporting. \param uriLength Length of \c name, in code points. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. */ explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), root_(), typeless_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); Ch noUri[1] = {0}; uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType))); new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. CreateSchemaRecursive(&root_, PointerType(), document, document); // Resolve $ref while (!schemaRef_.Empty()) { SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1); if (const SchemaType* s = GetSchema(refEntry->target)) { if (refEntry->schema) *refEntry->schema = s; // Create entry in map if not exist if (!GetSchema(refEntry->source)) { new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_); } } else if (refEntry->schema) *refEntry->schema = typeless_; refEntry->~SchemaRefEntry(); } RAPIDJSON_ASSERT(root_ != 0); schemaRef_.ShrinkToFit(); // Deallocate all memory for ref } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : remoteProvider_(rhs.remoteProvider_), allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), root_(rhs.root_), typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), schemaRef_(std::move(rhs.schemaRef_)), uri_(std::move(rhs.uri_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.typeless_ = 0; } #endif //! Destructor ~GenericSchemaDocument() { while (!schemaMap_.Empty()) schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry(); if (typeless_) { typeless_->~SchemaType(); Allocator::Free(typeless_); } RAPIDJSON_DELETE(ownAllocator_); } const URIType& GetURI() const { return uri_; } //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } private: //! Prohibit copying GenericSchemaDocument(const GenericSchemaDocument&); //! Prohibit assignment GenericSchemaDocument& operator=(const GenericSchemaDocument&); struct SchemaRefEntry { SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} PointerType source; PointerType target; const SchemaType** schema; }; struct SchemaEntry { SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} ~SchemaEntry() { if (owned) { schema->~SchemaType(); Allocator::Free(schema); } } PointerType pointer; SchemaType* schema; bool owned; }; void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { if (schema) *schema = typeless_; if (v.GetType() == kObjectType) { const SchemaType* s = GetSchema(pointer); if (!s) CreateSchema(schema, pointer, v, document); for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); } void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { RAPIDJSON_ASSERT(pointer.IsValid()); if (v.IsObject()) { if (!HandleRefSchema(pointer, schema, v, document)) { SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_); if (schema) *schema = s; } } } bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; static const ValueType kRefValue(kRefString, 4); typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); if (itr == v.MemberEnd()) return false; if (itr->value.IsString()) { SizeType len = itr->value.GetStringLength(); if (len > 0) { const Ch* s = itr->value.GetString(); SizeType i = 0; while (i < len && s[i] != '#') // Find the first # i++; if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { if (schema) *schema = sc; new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_); return true; } } } } } else if (s[i] == '#') { // Local reference, defer resolution PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const ValueType* nv = pointer.Get(document)) if (HandleRefSchema(source, schema, *nv, document)) return true; new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_); return true; } } } } return false; } const SchemaType* GetSchema(const PointerType& pointer) const { for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target) if (pointer == target->pointer) return target->schema; return 0; } PointerType GetPointer(const SchemaType* schema) const { for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target) if (schema == target->schema) return target->pointer; return PointerType(); } const SchemaType* GetTypeless() const { return typeless_; } static const size_t kInitialSchemaMapSize = 64; static const size_t kInitialSchemaRefSize = 64; IRemoteSchemaDocumentProviderType* remoteProvider_; Allocator *allocator_; Allocator *ownAllocator_; const SchemaType* root_; //!< Root schema. SchemaType* typeless_; internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref URIType uri_; }; //! GenericSchemaDocument using Value type. typedef GenericSchemaDocument<Value> SchemaDocument; //! IGenericRemoteSchemaDocumentProvider using SchemaDocument. typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaValidator //! JSON Schema Validator. /*! A SAX style JSON schema validator. It uses a \c GenericSchemaDocument to validate SAX events. It delegates the incoming SAX events to an output handler. The default output handler does nothing. It can be reused multiple times by calling \c Reset(). \tparam SchemaDocumentType Type of schema document. \tparam OutputHandler Type of output handler. Default handler does nothing. \tparam StateAllocator Allocator for storing the internal validation states. */ template < typename SchemaDocumentType, typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>, typename StateAllocator = CrtAllocator> class GenericSchemaValidator : public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, public internal::ISchemaValidator, public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> { public: typedef typename SchemaDocumentType::SchemaType SchemaType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename SchemaType::EncodingType EncodingType; typedef typename SchemaType::SValue SValue; typedef typename EncodingType::Ch Ch; typedef GenericStringRef<Ch> StringRefType; typedef GenericValue<EncodingType, StateAllocator> ValueType; //! Constructor without output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), error_(kObjectType), currentError_(), missingDependents_(), valid_(true), flags_(kValidateDefaultFlags) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Constructor with output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, OutputHandler& outputHandler, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(&outputHandler), error_(kObjectType), currentError_(), missingDependents_(), valid_(true), flags_(kValidateDefaultFlags) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Destructor. ~GenericSchemaValidator() { Reset(); RAPIDJSON_DELETE(ownStateAllocator_); } //! Reset the internal states. void Reset() { while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); ResetError(); } //! Reset the error state. void ResetError() { error_.SetObject(); currentError_.SetNull(); missingDependents_.SetNull(); valid_ = true; } //! Implementation of ISchemaValidator void SetValidateFlags(unsigned flags) { flags_ = flags; } virtual unsigned GetValidateFlags() const { return flags_; } //! Checks whether the current state is valid. // Implementation of ISchemaValidator virtual bool IsValid() const { if (!valid_) return false; if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false; return true; } //! Gets the error object. ValueType& GetError() { return error_; } const ValueType& GetError() const { return error_; } //! Gets the JSON pointer pointed to the invalid schema. // If reporting all errors, the stack will be empty. PointerType GetInvalidSchemaPointer() const { return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); } //! Gets the keyword of invalid schema. // If reporting all errors, the stack will be empty, so return "errors". const Ch* GetInvalidSchemaKeyword() const { if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword; if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString(); return 0; } //! Gets the error code of invalid schema. // If reporting all errors, the stack will be empty, so return kValidateErrors. ValidateErrorCode GetInvalidSchemaCode() const { if (!schemaStack_.Empty()) return CurrentContext().invalidCode; if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors; return kValidateErrorNone; } //! Gets the JSON pointer pointed to the invalid value. // If reporting all errors, the stack will be empty. PointerType GetInvalidDocumentPointer() const { if (documentStack_.Empty()) { return PointerType(); } else { return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch)); } } void NotMultipleOf(int64_t actual, const SValue& expected) { AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); } void NotMultipleOf(uint64_t actual, const SValue& expected) { AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); } void NotMultipleOf(double actual, const SValue& expected) { AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected); } void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMaximumString : 0); } void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMaximumString : 0); } void AboveMaximum(double actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMaximumString : 0); } void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMinimumString : 0); } void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMinimumString : 0); } void BelowMinimum(double actual, const SValue& expected, bool exclusive) { AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected, exclusive ? &SchemaType::GetExclusiveMinimumString : 0); } void TooLong(const Ch* str, SizeType length, SizeType expected) { AddNumberError(kValidateErrorMaxLength, ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); } void TooShort(const Ch* str, SizeType length, SizeType expected) { AddNumberError(kValidateErrorMinLength, ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); } void DoesNotMatch(const Ch* str, SizeType length) { currentError_.SetObject(); currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); AddCurrentError(kValidateErrorPattern); } void DisallowedItem(SizeType index) { currentError_.SetObject(); currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); AddCurrentError(kValidateErrorAdditionalItems, true); } void TooFewItems(SizeType actualCount, SizeType expectedCount) { AddNumberError(kValidateErrorMinItems, ValueType(actualCount).Move(), SValue(expectedCount).Move()); } void TooManyItems(SizeType actualCount, SizeType expectedCount) { AddNumberError(kValidateErrorMaxItems, ValueType(actualCount).Move(), SValue(expectedCount).Move()); } void DuplicateItems(SizeType index1, SizeType index2) { ValueType duplicates(kArrayType); duplicates.PushBack(index1, GetStateAllocator()); duplicates.PushBack(index2, GetStateAllocator()); currentError_.SetObject(); currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); AddCurrentError(kValidateErrorUniqueItems, true); } void TooManyProperties(SizeType actualCount, SizeType expectedCount) { AddNumberError(kValidateErrorMaxProperties, ValueType(actualCount).Move(), SValue(expectedCount).Move()); } void TooFewProperties(SizeType actualCount, SizeType expectedCount) { AddNumberError(kValidateErrorMinProperties, ValueType(actualCount).Move(), SValue(expectedCount).Move()); } void StartMissingProperties() { currentError_.SetArray(); } void AddMissingProperty(const SValue& name) { currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); } bool EndMissingProperties() { if (currentError_.Empty()) return false; ValueType error(kObjectType); error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); currentError_ = error; AddCurrentError(kValidateErrorRequired); return true; } void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { for (SizeType i = 0; i < count; ++i) MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError()); } void DisallowedProperty(const Ch* name, SizeType length) { currentError_.SetObject(); currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); AddCurrentError(kValidateErrorAdditionalProperties, true); } void StartDependencyErrors() { currentError_.SetObject(); } void StartMissingDependentProperties() { missingDependents_.SetArray(); } void AddMissingDependentProperty(const SValue& targetName) { missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); } void EndMissingDependentProperties(const SValue& sourceName) { if (!missingDependents_.Empty()) { // Create equivalent 'required' error ValueType error(kObjectType); ValidateErrorCode code = kValidateErrorRequired; error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator()); AddErrorCode(error, code); AddErrorInstanceLocation(error, false); // When appending to a pointer ensure its allocator is used PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator()); AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator())); ValueType wrapper(kObjectType); wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator()); currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator()); } } void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator()); } bool EndDependencyErrors() { if (currentError_.ObjectEmpty()) return false; ValueType error(kObjectType); error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); currentError_ = error; AddCurrentError(kValidateErrorDependencies); return true; } void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) { currentError_.SetObject(); AddCurrentError(code); } void StartDisallowedType() { currentError_.SetArray(); } void AddExpectedType(const typename SchemaType::ValueType& expectedType) { currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); } void EndDisallowedType(const typename SchemaType::ValueType& actualType) { ValueType error(kObjectType); error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); currentError_ = error; AddCurrentError(kValidateErrorType); } void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf AddErrorArray(kValidateErrorAllOf, subvalidators, count); //for (SizeType i = 0; i < count; ++i) { // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError()); //} } void NoneOf(ISchemaValidator** subvalidators, SizeType count) { AddErrorArray(kValidateErrorAnyOf, subvalidators, count); } void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) { AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count); } void Disallowed() { currentError_.SetObject(); AddCurrentError(kValidateErrorNot); } #define RAPIDJSON_STRING_(name, ...) \ static const StringRefType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \ return v;\ } RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e') RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e') RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') #undef RAPIDJSON_STRING_ #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ RAPIDJSON_MULTILINEMACRO_BEGIN\ *documentStack_.template Push<Ch>() = '\0';\ documentStack_.template Pop<Ch>(1);\ internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\ RAPIDJSON_MULTILINEMACRO_END #else #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() #endif #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ return valid_ = false;\ } #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\ if (context->hasher)\ static_cast<HasherType*>(context->hasher)->method arg2;\ if (context->validators)\ for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\ if (context->patternPropertiesValidators)\ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\ } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ return valid_; #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } bool RawNumber(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); return valid_ = !outputHandler_ || outputHandler_->StartObject(); } bool Key(const Ch* str, SizeType len, bool copy) { if (!valid_) return false; AppendToken(str, len); if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } bool EndObject(SizeType memberCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); return valid_ = !outputHandler_ || outputHandler_->StartArray(); } bool EndArray(SizeType elementCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ // Implementation of ISchemaStateFactory<SchemaType> virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) { ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(), #if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, #endif &GetStateAllocator()); sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag); return sv; } virtual void DestroySchemaValidator(ISchemaValidator* validator) { GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator); v->~GenericSchemaValidator(); StateAllocator::Free(v); } virtual void* CreateHasher() { return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); } virtual uint64_t GetHashCode(void* hasher) { return static_cast<HasherType*>(hasher)->GetHashCode(); } virtual void DestroryHasher(void* hasher) { HasherType* h = static_cast<HasherType*>(hasher); h->~HasherType(); StateAllocator::Free(h); } virtual void* MallocState(size_t size) { return GetStateAllocator().Malloc(size); } virtual void FreeState(void* p) { StateAllocator::Free(p); } private: typedef typename SchemaType::Context Context; typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray; typedef internal::Hasher<EncodingType, StateAllocator> HasherType; GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, const char* basePath, size_t basePathSize, #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(root), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), error_(kObjectType), currentError_(), missingDependents_(), valid_(true), flags_(kValidateDefaultFlags) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) #endif { if (basePath && basePathSize) memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize); } StateAllocator& GetStateAllocator() { if (!stateAllocator_) stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); return *stateAllocator_; } bool GetContinueOnErrors() const { return flags_ & kValidateContinueOnErrorFlag; } bool BeginValue() { if (schemaStack_.Empty()) PushSchema(root_); else { if (CurrentContext().inArray) internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors()) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; const SchemaType** sa = CurrentContext().patternPropertiesSchemas; typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; bool valueUniqueness = CurrentContext().valueUniqueness; RAPIDJSON_ASSERT(CurrentContext().valueSchema); PushSchema(*CurrentContext().valueSchema); if (count > 0) { CurrentContext().objectPatternValidatorType = patternValidatorType; ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count)); for (SizeType i = 0; i < count; i++) va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError } CurrentContext().arrayUniqueness = valueUniqueness; } return true; } bool EndValue() { if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors()) return false; #if RAPIDJSON_SCHEMA_VERBOSE GenericStringBuffer<EncodingType> sb; schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); *documentStack_.template Push<Ch>() = '\0'; documentStack_.template Pop<Ch>(1); internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>()); #endif void* hasher = CurrentContext().hasher; uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0; PopSchema(); if (!schemaStack_.Empty()) { Context& context = CurrentContext(); // Only check uniqueness if there is a hasher if (hasher && context.valueUniqueness) { HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes); if (!a) CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) if (itr->GetUint64() == h) { DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size()); // Cleanup before returning if continuing if (GetContinueOnErrors()) { a->PushBack(h, GetStateAllocator()); while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/'); } RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems); } a->PushBack(h, GetStateAllocator()); } } // Remove the last token of document pointer while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/') ; return true; } void AppendToken(const Ch* str, SizeType len) { documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters *documentStack_.template PushUnsafe<Ch>() = '/'; for (SizeType i = 0; i < len; i++) { if (str[i] == '~') { *documentStack_.template PushUnsafe<Ch>() = '~'; *documentStack_.template PushUnsafe<Ch>() = '0'; } else if (str[i] == '/') { *documentStack_.template PushUnsafe<Ch>() = '~'; *documentStack_.template PushUnsafe<Ch>() = '1'; } else *documentStack_.template PushUnsafe<Ch>() = str[i]; } } RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); } RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop<Context>(1); if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) { a->~HashCodeArray(); StateAllocator::Free(a); } c->~Context(); } void AddErrorInstanceLocation(ValueType& result, bool parent) { GenericStringBuffer<EncodingType> sb; PointerType instancePointer = GetInvalidDocumentPointer(); ((parent && instancePointer.GetTokenCount() > 0) ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) : instancePointer).StringifyUriFragment(sb); ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator()); result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); } void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) { GenericStringBuffer<EncodingType> sb; SizeType len = CurrentSchema().GetURI().GetStringLength(); if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch)); if (schema.GetTokenCount()) schema.StringifyUriFragment(sb); else GetInvalidSchemaPointer().StringifyUriFragment(sb); ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator()); result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); } void AddErrorCode(ValueType& result, const ValidateErrorCode code) { result.AddMember(GetErrorCodeString(), code, GetStateAllocator()); } void AddError(ValueType& keyword, ValueType& error) { typename ValueType::MemberIterator member = error_.FindMember(keyword); if (member == error_.MemberEnd()) error_.AddMember(keyword, error, GetStateAllocator()); else { if (member->value.IsObject()) { ValueType errors(kArrayType); errors.PushBack(member->value, GetStateAllocator()); member->value = errors; } member->value.PushBack(error, GetStateAllocator()); } } void AddCurrentError(const ValidateErrorCode code, bool parent = false) { AddErrorCode(currentError_, code); AddErrorInstanceLocation(currentError_, parent); AddErrorSchemaLocation(currentError_); AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_); } void MergeError(ValueType& other) { for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { AddError(it->name, it->value); } } void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected, const typename SchemaType::ValueType& (*exclusive)() = 0) { currentError_.SetObject(); currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); if (exclusive) currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); AddCurrentError(code); } void AddErrorArray(const ValidateErrorCode code, ISchemaValidator** subvalidators, SizeType count) { ValueType errors(kArrayType); for (SizeType i = 0; i < count; ++i) errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator()); currentError_.SetObject(); currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); AddCurrentError(code); } const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; } Context& CurrentContext() { return *schemaStack_.template Top<Context>(); } const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); } static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; const SchemaType& root_; StateAllocator* stateAllocator_; StateAllocator* ownStateAllocator_; internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch) OutputHandler* outputHandler_; ValueType error_; ValueType currentError_; ValueType missingDependents_; bool valid_; unsigned flags_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; #endif }; typedef GenericSchemaValidator<SchemaDocument> SchemaValidator; /////////////////////////////////////////////////////////////////////////////// // SchemaValidatingReader //! A helper class for parsing with validation. /*! This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam SourceEncoding Encoding of the input stream. \tparam SchemaDocumentType Type of schema document. \tparam StackAllocator Allocator type for stack. */ template < unsigned parseFlags, typename InputStream, typename SourceEncoding, typename SchemaDocumentType = SchemaDocument, typename StackAllocator = CrtAllocator> class SchemaValidatingReader { public: typedef typename SchemaDocumentType::PointerType PointerType; typedef typename InputStream::Ch Ch; typedef GenericValue<SourceEncoding, StackAllocator> ValueType; //! Constructor /*! \param is Input stream. \param sd Schema document. */ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {} template <typename Handler> bool operator()(Handler& handler) { GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader; GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler); parseResult_ = reader.template Parse<parseFlags>(is_, validator); isValid_ = validator.IsValid(); if (isValid_) { invalidSchemaPointer_ = PointerType(); invalidSchemaKeyword_ = 0; invalidDocumentPointer_ = PointerType(); error_.SetObject(); } else { invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); invalidSchemaCode_ = validator.GetInvalidSchemaCode(); invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); error_.CopyFrom(validator.GetError(), allocator_); } return parseResult_; } const ParseResult& GetParseResult() const { return parseResult_; } bool IsValid() const { return isValid_; } const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } const ValueType& GetError() const { return error_; } ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; } private: InputStream& is_; const SchemaDocumentType& sd_; ParseResult parseResult_; PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; ValidateErrorCode invalidSchemaCode_; StackAllocator allocator_; ValueType error_; bool isValid_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_SCHEMA_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/stream.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" #ifndef RAPIDJSON_STREAM_H_ #define RAPIDJSON_STREAM_H_ #include "encodings.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Stream /*! \class rapidjson::Stream \brief Concept for reading and writing characters. For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). For write-only stream, only need to implement Put() and Flush(). \code concept Stream { typename Ch; //!< Character type of the stream. //! Read the current character from stream without moving the read cursor. Ch Peek() const; //! Read the current character from stream and moving the read cursor to next character. Ch Take(); //! Get the current read cursor. //! \return Number of characters read from start. size_t Tell(); //! Begin writing operation at the current read pointer. //! \return The begin writer pointer. Ch* PutBegin(); //! Write a character. void Put(Ch c); //! Flush the buffer. void Flush(); //! End the writing operation. //! \param begin The begin write pointer returned by PutBegin(). //! \return Number of characters written. size_t PutEnd(Ch* begin); } \endcode */ //! Provides additional information for stream. /*! By using traits pattern, this type provides a default configuration for stream. For custom stream, this type can be specialized for other configuration. See TEST(Reader, CustomStringStream) in readertest.cpp for example. */ template<typename Stream> struct StreamTraits { //! Whether to make local copy of stream for optimization during parsing. /*! By default, for safety, streams do not use local copy optimization. Stream that can be copied fast should specialize this, like StreamTraits<StringStream>. */ enum { copyOptimization = 0 }; }; //! Reserve n characters for writing to a stream. template<typename Stream> inline void PutReserve(Stream& stream, size_t count) { (void)stream; (void)count; } //! Write character to a stream, presuming buffer is reserved. template<typename Stream> inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { stream.Put(c); } //! Put N copies of a character to a stream. template<typename Stream, typename Ch> inline void PutN(Stream& stream, Ch c, size_t n) { PutReserve(stream, n); for (size_t i = 0; i < n; i++) PutUnsafe(stream, c); } /////////////////////////////////////////////////////////////////////////////// // GenericStreamWrapper //! A Stream Wrapper /*! \tThis string stream is a wrapper for any stream by just forwarding any \treceived message to the origin stream. \note implements Stream concept */ #if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif template <typename InputStream, typename Encoding = UTF8<> > class GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; GenericStreamWrapper(InputStream& is): is_(is) {} Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() { return is_.Tell(); } Ch* PutBegin() { return is_.PutBegin(); } void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } // wrapper for MemoryStream const Ch* Peek4() const { return is_.Peek4(); } // wrapper for AutoUTFInputStream UTFType GetType() const { return is_.GetType(); } bool HasBOM() const { return is_.HasBOM(); } protected: InputStream& is_; }; #if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_POP #endif /////////////////////////////////////////////////////////////////////////////// // StringStream //! Read-only string stream. /*! \note implements Stream concept */ template <typename Encoding> struct GenericStringStream { typedef typename Encoding::Ch Ch; GenericStringStream(const Ch *src) : src_(src), head_(src) {} Ch Peek() const { return *src_; } Ch Take() { return *src_++; } size_t Tell() const { return static_cast<size_t>(src_ - head_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. }; template <typename Encoding> struct StreamTraits<GenericStringStream<Encoding> > { enum { copyOptimization = 1 }; }; //! String stream with UTF8 encoding. typedef GenericStringStream<UTF8<> > StringStream; /////////////////////////////////////////////////////////////////////////////// // InsituStringStream //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. \note implements Stream concept */ template <typename Encoding> struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } Ch Take() { return *src_++; } size_t Tell() { return static_cast<size_t>(src_ - head_); } // Write void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } Ch* PutBegin() { return dst_ = src_; } size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); } void Flush() {} Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Pop(size_t count) { dst_ -= count; } Ch* src_; Ch* dst_; Ch* head_; }; template <typename Encoding> struct StreamTraits<GenericInsituStringStream<Encoding> > { enum { copyOptimization = 1 }; }; //! Insitu string stream with UTF8 encoding. typedef GenericInsituStringStream<UTF8<> > InsituStringStream; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STREAM_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/stringbuffer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ #include "stream.h" #include "internal/stack.h" #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include <utility> // std::move #endif #include "internal/stack.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. /*! \tparam Encoding Encoding of the stream. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template <typename Encoding, typename Allocator = CrtAllocator> class GenericStringBuffer { public: typedef typename Encoding::Ch Ch; GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { if (&rhs != this) stack_ = std::move(rhs.stack_); return *this; } #endif void Put(Ch c) { *stack_.template Push<Ch>() = c; } void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { // Push and pop a null terminator. This is safe. *stack_.template Push<Ch>() = '\0'; stack_.ShrinkToFit(); stack_.template Pop<Ch>(1); } void Reserve(size_t count) { stack_.template Reserve<Ch>(count); } Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); } void Pop(size_t count) { stack_.template Pop<Ch>(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. *stack_.template Push<Ch>() = '\0'; stack_.template Pop<Ch>(1); return stack_.template Bottom<Ch>(); } //! Get the size of string in bytes in the string buffer. size_t GetSize() const { return stack_.GetSize(); } //! Get the length of string in Ch in the string buffer. size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } static const size_t kDefaultCapacity = 256; mutable internal::Stack<Allocator> stack_; private: // Prohibit copy constructor & assignment operator. GenericStringBuffer(const GenericStringBuffer&); GenericStringBuffer& operator=(const GenericStringBuffer&); }; //! String buffer with UTF8 encoding typedef GenericStringBuffer<UTF8<> > StringBuffer; template<typename Encoding, typename Allocator> inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) { stream.Reserve(count); } template<typename Encoding, typename Allocator> inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) { stream.PutUnsafe(c); } //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) { std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STRINGBUFFER_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson/writer.h ================================================ // Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ #include "stream.h" #include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" #include "internal/itoa.h" #include "stringbuffer.h" #include <new> // placement new #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include <intrin.h> #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include <nmmintrin.h> #elif defined(RAPIDJSON_SSE2) #include <emmintrin.h> #elif defined(RAPIDJSON_NEON) #include <arm_neon.h> #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(c++98-compat) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // WriteFlag /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kWriteDefaultFlags definition. User can define this as any \c WriteFlag combinations. */ #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags #endif //! Combination of writeFlags enum WriteFlag { kWriteNoFlags = 0, //!< No flags are set. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS }; //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output os. User may programmatically calls the functions of a writer to generate JSON text. On the other side, a writer can also be passed to objects that generates events, for example Reader::Parse() and Document::Accept(). \tparam OutputStream Type of output stream. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class Writer { public: typedef typename SourceEncoding::Ch Ch; static const int kDefaultMaxDecimalPlaces = 324; //! Constructor /*! \param os Output stream. \param stackAllocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Writer(Writer&& rhs) : os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { rhs.os_ = 0; } #endif //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, in order to make a Writer object reusable for output multiple JSONs. \param os New output stream. \code Writer<OutputStream> writer(os1); writer.StartObject(); // ... writer.EndObject(); writer.Reset(os2); writer.StartObject(); // ... writer.EndObject(); \endcode */ void Reset(OutputStream& os) { os_ = &os; hasRoot_ = false; level_stack_.Clear(); } //! Checks whether the output is a complete JSON. /*! A complete JSON has a complete root object or array. */ bool IsComplete() const { return hasRoot_ && level_stack_.Empty(); } int GetMaxDecimalPlaces() const { return maxDecimalPlaces_; } //! Sets the maximum number of decimal places for double output. /*! This setting truncates the output with specified number of decimal places. For example, \code writer.SetMaxDecimalPlaces(3); writer.StartArray(); writer.Double(0.12345); // "0.123" writer.Double(0.0001); // "0.0" writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) writer.EndArray(); \endcode The default setting does not truncate any decimal places. You can restore to this setting by calling \code writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); \endcode */ void SetMaxDecimalPlaces(int maxDecimalPlaces) { maxDecimalPlaces_ = maxDecimalPlaces; } /*!@name Implementation of Handler \see Handler */ //@{ bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } //! Writes the given \c double value to the stream /*! \param d The value to be written. \return Whether it is succeed. */ bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kNumberType); return EndValue(WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); return EndValue(WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string<Ch>& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { Prefix(kObjectType); new (level_stack_.template Push<Level>()) Level(false); return WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string<Ch>& str) { return Key(str.data(), SizeType(str.size())); } #endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop<Level>(1); return EndValue(WriteEndObject()); } bool StartArray() { Prefix(kArrayType); new (level_stack_.template Push<Level>()) Level(true); return WriteStartArray(); } bool EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray); level_stack_.template Pop<Level>(1); return EndValue(WriteEndArray()); } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. */ bool RawValue(const Ch* json, size_t length, Type type) { RAPIDJSON_ASSERT(json != 0); Prefix(type); return EndValue(WriteRawValue(json, length)); } //! Flush the output stream. /*! Allows the user to flush the output stream immediately. */ void Flush() { os_->Flush(); } static const size_t kDefaultLevelDepth = 32; protected: //! Information for each nested level struct Level { Level(bool inArray_) : valueCount(0), inArray(inArray_) {} size_t valueCount; //!< number of values in this level bool inArray; //!< true if in array, otherwise in object }; bool WriteNull() { PutReserve(*os_, 4); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; } bool WriteBool(bool b) { if (b) { PutReserve(*os_, 4); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); } else { PutReserve(*os_, 5); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); } return true; } bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); PutReserve(*os_, static_cast<size_t>(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); PutReserve(*os_, static_cast<size_t>(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); PutReserve(*os_, static_cast<size_t>(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast<size_t>(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); return true; } bool WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { if (!(writeFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char buffer[25]; char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); PutReserve(*os_, static_cast<size_t>(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 Z16, Z16, // 30~4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 }; if (TargetEncoding::supportUnicode) PutReserve(*os_, 2 + length * 6); // "\uxxxx..." else PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." PutUnsafe(*os_, '\"'); GenericStringStream<SourceEncoding> is(str); while (ScanWriteUnescapedString(is, length)) { const Ch c = is.Peek(); if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) { // Unicode escaping unsigned codepoint; if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); PutUnsafe(*os_, hexDigits[(lead ) & 15]); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) { is.Take(); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)])); if (escape[static_cast<unsigned char>(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); } } else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) return false; } PutUnsafe(*os_, '\"'); return true; } bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) { return RAPIDJSON_LIKELY(is.Tell() < length); } bool WriteStartObject() { os_->Put('{'); return true; } bool WriteEndObject() { os_->Put('}'); return true; } bool WriteStartArray() { os_->Put('['); return true; } bool WriteEndArray() { os_->Put(']'); return true; } bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); GenericStringStream<SourceEncoding> is(json); while (RAPIDJSON_LIKELY(is.Tell() < length)) { RAPIDJSON_ASSERT(is.Peek() != '\0'); if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) return false; } return true; } void Prefix(Type type) { (void)type; if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root Level* level = level_stack_.template Top<Level>(); if (level->valueCount > 0) { if (level->inArray) os_->Put(','); // add comma if it is not the first element in array else // in object os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. hasRoot_ = true; } } // Flush the value if it is the top level one. bool EndValue(bool ret) { if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text Flush(); return ret; } OutputStream* os_; internal::Stack<StackAllocator> level_stack_; int maxDecimalPlaces_; bool hasRoot_; private: // Prohibit copy constructor & assignment operator. Writer(const Writer&); Writer& operator=(const Writer&); }; // Full specialization for StringStream to prevent memory copying template<> inline bool Writer<StringBuffer>::WriteInt(int i) { char *buffer = os_->Push(11); const char* end = internal::i32toa(i, buffer); os_->Pop(static_cast<size_t>(11 - (end - buffer))); return true; } template<> inline bool Writer<StringBuffer>::WriteUint(unsigned u) { char *buffer = os_->Push(10); const char* end = internal::u32toa(u, buffer); os_->Pop(static_cast<size_t>(10 - (end - buffer))); return true; } template<> inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { char *buffer = os_->Push(21); const char* end = internal::i64toa(i64, buffer); os_->Pop(static_cast<size_t>(21 - (end - buffer))); return true; } template<> inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { char *buffer = os_->Push(20); const char* end = internal::u64toa(u, buffer); os_->Pop(static_cast<size_t>(20 - (end - buffer))); return true; } template<> inline bool Writer<StringBuffer>::WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); os_->Pop(static_cast<size_t>(25 - (end - buffer))); return true; } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) template<> inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) return RAPIDJSON_LIKELY(is.Tell() < length); if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; const char* end = is.head_ + length; const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); if (nextAligned > end) return true; while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); for (; p != endAligned; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType len; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); len = offset; #else len = static_cast<SizeType>(__builtin_ffs(r) - 1); #endif char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); for (size_t i = 0; i < len; i++) q[i] = p[i]; p += len; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); } is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } #elif defined(RAPIDJSON_NEON) template<> inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) return RAPIDJSON_LIKELY(is.Tell() < length); if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; const char* end = is.head_ + length; const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15)); if (nextAligned > end) return true; while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (; p != endAligned; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType len = 0; bool escaped = false; if (low == 0) { if (high != 0) { uint32_t lz = internal::clzll(high); len = 8 + (lz >> 3); escaped = true; } } else { uint32_t lz = internal::clzll(low); len = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); for (size_t i = 0; i < len; i++) q[i] = p[i]; p += len; break; } vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s); } is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } #endif // RAPIDJSON_NEON RAPIDJSON_NAMESPACE_END #if defined(_MSC_VER) || defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ ================================================ FILE: libraries/libstratosphere/include/stratosphere/rapidjson.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ams/ams_environment.hpp> #define RAPIDJSON_NAMESPACE ams::rapidjson #define RAPIDJSON_ASSERT(x) AMS_ABORT_UNLESS(x) #define RAPIDJSON_MALLOC(size) ams::MallocForRapidJson(size) #define RAPIDJSON_REALLOC(ptr, size) ams::ReallocForRapidJson(ptr, size) #define RAPIDJSON_FREE(ptr) ams::FreeForRapidJson(ptr) #include <stratosphere/rapidjson/rapidjson.h> #include <stratosphere/rapidjson/encodings.h> #include <stratosphere/rapidjson/reader.h> ================================================ FILE: libraries/libstratosphere/include/stratosphere/regulator/regulator_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/regulator/regulator_types.hpp> namespace ams::regulator { void Initialize(); void Finalize(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/regulator/regulator_session_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/regulator/regulator_types.hpp> namespace ams::regulator { struct RegulatorSession { void *_session; }; Result OpenSession(RegulatorSession *out, DeviceCode device_code); void CloseSession(RegulatorSession *session); bool GetVoltageEnabled(RegulatorSession *session); Result SetVoltageEnabled(RegulatorSession *session, bool enabled); Result SetVoltageValue(RegulatorSession *session, u32 micro_volts); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/regulator/regulator_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::regulator { /* ... */ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/regulator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/regulator/regulator_types.hpp> #include <stratosphere/regulator/regulator_api.hpp> #include <stratosphere/regulator/regulator_session_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/ro/impl/ro_debug_monitor_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ro/ro_types.hpp> #include <stratosphere/ldr/ldr_types.hpp> #include <stratosphere/sf.hpp> #define AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetProcessModuleInfo, (sf::Out<u32> out_count, const sf::OutArray<ldr::ModuleInfo> &out_infos, os::ProcessId process_id), (out_count, out_infos, process_id)) AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IDebugMonitorInterface, AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO, 0xBBA11B0A) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ro/impl/ro_ro_exception_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::ro::impl { struct ExceptionInfo { uintptr_t module_address; size_t module_size; uintptr_t info_offset; size_t info_size; }; bool GetExceptionInfo(ExceptionInfo *out, uintptr_t pc); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ro/impl/ro_ro_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ro/ro_types.hpp> #include <stratosphere/sf.hpp> #define AMS_RO_I_RO_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, MapManualLoadModuleMemory, (sf::Out<u64> out_load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size), (out_load_address, client_pid, nro_address, nro_size, bss_address, bss_size)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, UnmapManualLoadModuleMemory, (const sf::ClientProcessId &client_pid, u64 nro_address), (client_pid, nro_address)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size), (client_pid, nrr_address, nrr_size)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address), (client_pid, nrr_address)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h), (client_pid, std::move(process_h))) \ AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterProcessModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h), (client_pid, nrr_address, nrr_size, std::move(process_h)), hos::Version_7_0_0) AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IRoInterface, AMS_RO_I_RO_INTERFACE_INTERFACE_INFO, 0xA52C55A9) ================================================ FILE: libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::ro { enum NrrKind : u8 { NrrKind_User = 0, NrrKind_JitPlugin = 1, NrrKind_Count, }; static constexpr size_t ModuleIdSize = 0x20; struct ModuleId { u8 data[ModuleIdSize]; }; static_assert(sizeof(ModuleId) == ModuleIdSize); struct NrrCertification { static constexpr size_t RsaKeySize = 0x100; static constexpr size_t SignedSize = 0x120; u64 program_id_mask; u64 program_id_pattern; u8 reserved_10[0x10]; u8 modulus[RsaKeySize]; u8 signature[RsaKeySize]; }; static_assert(sizeof(NrrCertification) == NrrCertification::RsaKeySize + NrrCertification::SignedSize); class NrrHeader { public: static constexpr u32 Magic = util::FourCC<'N','R','R','0'>::Code; private: u32 m_magic; u32 m_key_generation; u8 m_reserved_08[0x08]; NrrCertification m_certification; u8 m_signature[0x100]; ncm::ProgramId m_program_id; u32 m_size; u8 m_nrr_kind; /* 7.0.0+ */ u8 m_reserved_33D[3]; u32 m_hashes_offset; u32 m_num_hashes; u8 m_reserved_348[8]; public: bool IsMagicValid() const { return m_magic == Magic; } bool IsProgramIdValid() const { return (m_program_id.value & m_certification.program_id_mask) == m_certification.program_id_pattern; } NrrKind GetNrrKind() const { const NrrKind kind = static_cast<NrrKind>(m_nrr_kind); AMS_ABORT_UNLESS(kind < NrrKind_Count); return kind; } ncm::ProgramId GetProgramId() const { return m_program_id; } u32 GetSize() const { return m_size; } u32 GetNumHashes() const { return m_num_hashes; } size_t GetHashesOffset() const { return m_hashes_offset; } uintptr_t GetHashes() const { return reinterpret_cast<uintptr_t>(this) + this->GetHashesOffset(); } u32 GetKeyGeneration() const { return m_key_generation; } const u8 *GetCertificationSignature() const { return m_certification.signature; } const u8 *GetCertificationSignedArea() const { return reinterpret_cast<const u8 *>(std::addressof(m_certification)); } const u8 *GetCertificationModulus() const { return m_certification.modulus; } const u8 *GetSignature() const { return m_signature; } const u8 *GetSignedArea() const { return reinterpret_cast<const u8 *>(std::addressof(m_program_id)); } size_t GetSignedAreaSize() const { return m_size - GetSignedAreaOffset(); } static constexpr size_t GetSignedAreaOffset(); }; static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader definition!"); constexpr size_t NrrHeader::GetSignedAreaOffset() { return AMS_OFFSETOF(NrrHeader, m_program_id); } class NroHeader { public: static constexpr u32 Magic = util::FourCC<'N','R','O','0'>::Code; static constexpr u32 FlagAlignedHeader = 1; private: u32 m_entrypoint_insn; u32 m_mod_offset; u8 m_reserved_08[0x8]; u32 m_magic; u8 m_version; u32 m_size; u32 m_flags; u32 m_text_offset; u32 m_text_size; u32 m_ro_offset; u32 m_ro_size; u32 m_rw_offset; u32 m_rw_size; u32 m_bss_size; u8 m_reserved_3C[0x4]; ModuleId m_module_id; u8 m_reserved_60[0x20]; public: bool IsMagicValid() const { return m_magic == Magic; } u32 GetVersion() const { return m_version; } u32 GetSize() const { return m_size; } u32 GetFlags() const { return m_flags; } bool IsAlignedHeader() const { return m_flags & FlagAlignedHeader; } u32 GetTextOffset() const { return m_text_offset; } u32 GetTextSize() const { return m_text_size; } u32 GetRoOffset() const { return m_ro_offset; } u32 GetRoSize() const { return m_ro_size; } u32 GetRwOffset() const { return m_rw_offset; } u32 GetRwSize() const { return m_rw_size; } u32 GetBssSize() const { return m_bss_size; } const ModuleId *GetModuleId() const { return std::addressof(m_module_id); } }; static_assert(sizeof(NroHeader) == 0x80, "NroHeader definition!"); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/ro.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/ro/ro_types.hpp> #include <stratosphere/ro/impl/ro_ro_interface.hpp> #include <stratosphere/ro/impl/ro_debug_monitor_interface.hpp> #include <stratosphere/ro/impl/ro_ro_exception_info.hpp> #include <stratosphere/rocrt/rocrt.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/rocrt/rocrt.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::rocrt { constexpr inline const u32 ModuleHeaderVersion = util::FourCC<'M','O','D','0'>::Code; struct ModuleHeader { u32 signature; u32 dynamic_offset; u32 bss_start_offset; u32 bss_end_offset; u32 exception_info_start_offset; u32 exception_info_end_offset; u32 module_offset; }; struct ModuleHeaderLocation { u32 pad; u32 header_offset; }; constexpr inline u32 CheckModuleHeaderSignature(const ModuleHeader *header) { if (header->signature == ModuleHeaderVersion) { return header->signature; } else { return 0; } } inline ModuleHeader *GetModuleHeader(const ModuleHeaderLocation *loc) { return reinterpret_cast<ModuleHeader *>(reinterpret_cast<uintptr_t>(loc) + loc->header_offset); } inline uintptr_t GetDynamicOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast<uintptr_t>(loc) + loc->header_offset + header->dynamic_offset; } inline uintptr_t GetBssStartAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast<uintptr_t>(loc) + loc->header_offset + header->bss_start_offset; } inline uintptr_t GetBssEndAddress(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast<uintptr_t>(loc) + loc->header_offset + header->bss_end_offset; } inline uintptr_t GetModuleOffset(const ModuleHeader *header, const ModuleHeaderLocation *loc) { return reinterpret_cast<uintptr_t>(loc) + loc->header_offset + header->module_offset; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs/scs_command_processor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::scs { struct alignas(alignof(u32)) CommandHeader { u64 id __attribute__((packed)); u32 command; u32 body_size; }; static_assert(sizeof(CommandHeader) == 0x10); static_assert(alignof(CommandHeader) == alignof(u32)); struct alignas(alignof(u32)) ResponseHeader { u64 id __attribute__((packed)); u32 response; u32 body_size; }; static_assert(sizeof(ResponseHeader) == 0x10); static_assert(alignof(ResponseHeader) == alignof(u32)); class CommandProcessor { protected: enum Command { Command_None = 0, Command_LaunchProgramFromHost = 1, Command_TerminateProcesses = 2, Command_GetFirmwareVersion = 3, Command_Reboot = 4, Command_SetSafeMode = 5, Command_RegisterTenvDefinitionFilePath = 6, Command_TerminateApplication = 7, Command_Shutdown = 8, Command_SubscribeProcessEvent = 9, Command_GetTitleName = 10, Command_ControlVirtualTemperature = 11, Command_LaunchInstalledApplication = 12, Command_LaunchGameCardApplication = 13, Command_LaunchInstalledSystemProcess = 14, Command_TakeScreenShot = 15, Command_TakeForegroundScreenShot = 16, Command_SimulateGameCardDetection = 17, Command_SimulateSdCardDetection = 18, Command_DumpRunningApplication = 19, }; enum Response { Response_None = 0, Response_Success = 1, Response_Error = 2, Response_ProgramExited = 3, Response_FirmwareVersion = 4, Response_JitDebug = 5, Response_ProgramLaunched = 6, Response_TitleName = 7, Response_ScreenShot = 8, }; public: constexpr CommandProcessor() = default; void Initialize(); public: virtual bool ProcessCommand(const CommandHeader &header, const u8 *body, s32 socket); protected: static std::scoped_lock<os::SdkMutex> MakeSendGuardBlock(); static void Send(s32 socket, const void *data, size_t size); static void SendSuccess(s32 socket, const CommandHeader &header); static void SendErrorResult(s32 socket, const CommandHeader &header, Result result); private: static void SendErrorResult(s32 socket, u64 id, Result result); static void SendExited(s32 socket, u64 id, u64 process_id); static void SendJitDebug(s32 socket, u64 id); static void SendLaunched(s32 socket, u64 id, u64 process_id); static void OnProcessStart(u64 id, s32 socket, os::ProcessId process_id); static void OnProcessExit(u64 id, s32 socket, os::ProcessId process_id); static void OnProcessJitDebug(u64 id, s32 socket, os::ProcessId process_id); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs/scs_server_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> namespace ams::scs { enum Port { Port_HtcTenv, Port_Count, }; constexpr inline int SessionCount[Port_Count] = { 6, }; constexpr inline auto MaxSessions = [] { auto total = 0; for (const auto sessions : SessionCount) { total += sessions; } return total; }(); struct ServerOptions { static constexpr size_t PointerBufferSize = 0; static constexpr size_t MaxDomains = 6; static constexpr size_t MaxDomainObjects = 16; static constexpr bool CanDeferInvokeRequest = false; static constexpr bool CanManageMitmServers = false; }; class ServerManager final : public sf::hipc::ServerManager<Port_Count, ServerOptions, MaxSessions> { /* ... */ }; ServerManager *GetServerManager(); void StartServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs/scs_shell.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_ids.hpp> namespace ams::scs { using ProcessEventHandler = void(*)(u64 id, s32 socket, os::ProcessId process_id); void InitializeShell(); void RegisterCommonProcessEventHandler(ProcessEventHandler on_start, ProcessEventHandler on_exit, ProcessEventHandler on_jit_debug); Result RegisterSocket(s32 socket, u64 id); void UnregisterSocket(s32 socket); Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, const void *args, size_t args_size, u32 process_flags); inline Result LaunchProgram(os::ProcessId *out, ncm::ProgramId program_id, const void *args, size_t args_size, u32 process_flags) { R_RETURN(LaunchProgram(out, ncm::ProgramLocation::Make(program_id, ncm::StorageId::BuiltInSystem), args, args_size, process_flags)); } Result SubscribeProcessEvent(s32 socket, bool is_register, u64 id); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs/scs_shell_server.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/htcs.hpp> #include <stratosphere/scs/scs_command_processor.hpp> namespace ams::scs { class ShellServer { private: htcs::HtcsPortName m_port_name; os::ThreadType m_thread; u8 m_buffer[64_KB]; CommandProcessor *m_command_processor; private: static void ThreadEntry(void *arg) { reinterpret_cast<ShellServer *>(arg)->DoShellServer(); } void DoShellServer(); public: constexpr ShellServer() = default; public: void Initialize(const char *port_name, void *stack, size_t stack_size, CommandProcessor *command_processor); void Start(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs/scs_tenv.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::scs { void InitializeTenvServiceManager(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/scs.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/scs/scs_command_processor.hpp> #include <stratosphere/scs/scs_shell_server.hpp> #include <stratosphere/scs/scs_shell.hpp> #include <stratosphere/scs/scs_tenv.hpp> #include <stratosphere/scs/scs_server_manager.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/factory/settings_configuration_id.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::settings::factory { struct ConfigurationId1 { char str[30]; }; static_assert(sizeof(ConfigurationId1) == 30); static_assert(util::is_pod<ConfigurationId1>::value); void GetConfigurationId1(ConfigurationId1 *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/factory/settings_device_certificate.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::settings::factory { struct EccP256DeviceCertificate { u8 data[0x180]; }; static_assert(sizeof(EccP256DeviceCertificate) == 0x180); static_assert(util::is_pod<EccP256DeviceCertificate>::value); struct EccB233DeviceCertificate { u8 data[0x180]; }; static_assert(sizeof(EccB233DeviceCertificate) == 0x180); static_assert(util::is_pod<EccB233DeviceCertificate>::value); struct Rsa2048DeviceCertificate { u8 data[0x240]; }; static_assert(sizeof(Rsa2048DeviceCertificate) == 0x240); static_assert(util::is_pod<Rsa2048DeviceCertificate>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/factory/settings_serial_number.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::settings::factory { struct SerialNumber { char str[0x18]; }; static_assert(sizeof(SerialNumber) == 0x18); static_assert(util::is_pod<SerialNumber>::value); Result GetSerialNumber(SerialNumber *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_fwdbg_types.hpp> namespace ams::settings::fwdbg { bool IsDebugModeEnabled(); size_t GetSettingsItemValueSize(const char *name, const char *key); size_t GetSettingsItemValue(void *dst, size_t dst_size, const char *name, const char *key); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/settings_fwdbg_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::settings::fwdbg { } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/settings_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::settings { constexpr size_t SettingsNameLengthMax = 0x40; constexpr size_t SettingsItemKeyLengthMax = 0x40; struct SettingsName : public sf::LargeData { char value[util::AlignUp(SettingsNameLengthMax + 1, alignof(u64))]; }; static_assert(util::is_pod<SettingsName>::value && sizeof(SettingsName) > SettingsNameLengthMax); struct SettingsItemKey : public sf::LargeData { char value[util::AlignUp(SettingsItemKeyLengthMax + 1, alignof(u64))]; }; static_assert(util::is_pod<SettingsItemKey>::value && sizeof(SettingsItemKey) > SettingsItemKeyLengthMax); enum Language { Language_Japanese, Language_AmericanEnglish, Language_French, Language_German, Language_Italian, Language_Spanish, Language_Chinese, Language_Korean, Language_Dutch, Language_Portuguese, Language_Russian, Language_Taiwanese, Language_BritishEnglish, Language_CanadianFrench, Language_LatinAmericanSpanish, /* 4.0.0+ */ Language_SimplifiedChinese, Language_TraditionalChinese, /* 10.1.0+ */ Language_PortugueseBr, Language_Count, }; struct LanguageCode { static constexpr size_t MaxLength = 8; char name[MaxLength]; static constexpr LanguageCode Encode(util::string_view name) { LanguageCode out{}; for (size_t i = 0; i < MaxLength && i < name.size(); i++) { out.name[i] = name[i]; } return out; } template<Language Lang> static constexpr inline LanguageCode EncodeLanguage() { if constexpr (false) { /* ... */ } #define AMS_MATCH_LANGUAGE(lang, enc) else if constexpr (Lang == Language_##lang) { return LanguageCode::Encode(enc); } AMS_MATCH_LANGUAGE(Japanese, "ja") AMS_MATCH_LANGUAGE(AmericanEnglish, "en-US") AMS_MATCH_LANGUAGE(French, "fr") AMS_MATCH_LANGUAGE(German, "de") AMS_MATCH_LANGUAGE(Italian, "it") AMS_MATCH_LANGUAGE(Spanish, "es") AMS_MATCH_LANGUAGE(Chinese, "zh-CN") AMS_MATCH_LANGUAGE(Korean, "ko") AMS_MATCH_LANGUAGE(Dutch, "nl") AMS_MATCH_LANGUAGE(Portuguese, "pt") AMS_MATCH_LANGUAGE(Russian, "ru") AMS_MATCH_LANGUAGE(Taiwanese, "zh-TW") AMS_MATCH_LANGUAGE(BritishEnglish, "en-GB") AMS_MATCH_LANGUAGE(CanadianFrench, "fr-CA") AMS_MATCH_LANGUAGE(LatinAmericanSpanish, "es-419") /* 4.0.0+ */ AMS_MATCH_LANGUAGE(SimplifiedChinese, "zh-Hans") AMS_MATCH_LANGUAGE(TraditionalChinese, "zh-Hant") /* 10.1.0+ */ AMS_MATCH_LANGUAGE(PortugueseBr, "pt-BR") #undef AMS_MATCH_LANGUAGE else { static_assert(Lang != Language_Japanese); } } static constexpr inline LanguageCode Encode(const Language language) { constexpr LanguageCode EncodedLanguages[Language_Count] = { EncodeLanguage<Language_Japanese>(), EncodeLanguage<Language_AmericanEnglish>(), EncodeLanguage<Language_French>(), EncodeLanguage<Language_German>(), EncodeLanguage<Language_Italian>(), EncodeLanguage<Language_Spanish>(), EncodeLanguage<Language_Chinese>(), EncodeLanguage<Language_Korean>(), EncodeLanguage<Language_Dutch>(), EncodeLanguage<Language_Portuguese>(), EncodeLanguage<Language_Russian>(), EncodeLanguage<Language_Taiwanese>(), EncodeLanguage<Language_BritishEnglish>(), EncodeLanguage<Language_CanadianFrench>(), EncodeLanguage<Language_LatinAmericanSpanish>(), /* 4.0.0+ */ EncodeLanguage<Language_SimplifiedChinese>(), EncodeLanguage<Language_TraditionalChinese>(), /* 10.1.0+ */ EncodeLanguage<Language_PortugueseBr>(), }; return EncodedLanguages[language]; } }; constexpr inline bool operator==(const LanguageCode &lhs, const LanguageCode &rhs) { return util::Strncmp<char>(lhs.name, rhs.name, sizeof(lhs)) == 0; } constexpr inline bool operator!=(const LanguageCode &lhs, const LanguageCode &rhs) { return !(lhs == rhs); } constexpr inline bool operator==(const LanguageCode &lhs, const Language &rhs) { return lhs == LanguageCode::Encode(rhs); } constexpr inline bool operator!=(const LanguageCode &lhs, const Language &rhs) { return !(lhs == rhs); } constexpr inline bool operator==(const Language &lhs, const LanguageCode &rhs) { return rhs == lhs; } constexpr inline bool operator!=(const Language &lhs, const LanguageCode &rhs) { return !(lhs == rhs); } namespace impl { template<size_t ...Is> constexpr inline bool IsValidLanguageCode(const LanguageCode &lc, std::index_sequence<Is...>) { return ((lc == LanguageCode::Encode(static_cast<Language>(Is))) || ...); } } constexpr inline bool IsValidLanguageCodeDeprecated(const LanguageCode &lc) { return impl::IsValidLanguageCode(lc, std::make_index_sequence<Language_Count - 3>{}); } constexpr inline bool IsValidLanguageCodeDeprecated2(const LanguageCode &lc) { return impl::IsValidLanguageCode(lc, std::make_index_sequence<Language_Count - 1>{}); } constexpr inline bool IsValidLanguageCode(const LanguageCode &lc) { return impl::IsValidLanguageCode(lc, std::make_index_sequence<Language_Count>{}); } static_assert(util::is_pod<LanguageCode>::value); static_assert(sizeof(LanguageCode) == sizeof(u64)); /* Not an official type, but convenient. */ enum RegionCode : s32 { RegionCode_Japan, RegionCode_America, RegionCode_Europe, RegionCode_Australia, RegionCode_China, RegionCode_Korea, RegionCode_Taiwan, RegionCode_Count, }; constexpr inline bool IsValidRegionCode(const RegionCode rc) { return 0 <= rc && rc < RegionCode_Count; } /* This needs to be defined separately from libnx's so that it can inherit from sf::LargeData. */ struct FirmwareVersion : public sf::LargeData { u8 major; u8 minor; u8 micro; u8 padding1; u8 revision_major; u8 revision_minor; u8 padding2; u8 padding3; char platform[0x20]; char version_hash[0x40]; char display_version[0x18]; char display_title[0x80]; constexpr inline u32 GetVersion() const { return (static_cast<u32>(major) << 16) | (static_cast<u32>(minor) << 8) | (static_cast<u32>(micro) << 0); } }; static_assert(util::is_pod<FirmwareVersion>::value); static_assert(sizeof(FirmwareVersion) == 0x100); #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(FirmwareVersion) == sizeof(::SetSysFirmwareVersion)); #endif constexpr inline bool operator==(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetVersion() == rhs.GetVersion(); } constexpr inline bool operator!=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return !(lhs == rhs); } constexpr inline bool operator<(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetVersion() < rhs.GetVersion(); } constexpr inline bool operator>=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return !(lhs < rhs); } constexpr inline bool operator<=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetVersion() <= rhs.GetVersion(); } constexpr inline bool operator>(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return !(lhs <= rhs); } struct BluetoothDevicesSettings : public sf::LargeData { u8 address[0x6]; char name[0x20]; u8 class_of_device[0x3]; u8 link_key[0x10]; u8 link_key_present; u16 version; u32 trusted_services; u16 vid; u16 pid; u8 sub_class; u8 attribute_mask; u16 descriptor_length; u8 descriptor[0x80]; u8 key_type; u8 device_type; u16 brr_size; u8 brr[0x9]; u8 reserved0; char name2[0xF9]; u8 reserved1[0x31]; }; #if defined(ATMOSPHERE_OS_HORIZON) static_assert(sizeof(BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings)); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_error_report.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { enum ErrorReportSharePermission { ErrorReportSharePermission_NotConfirmed = 0, ErrorReportSharePermission_Granted = 1, ErrorReportSharePermission_Denied = 2, }; ErrorReportSharePermission GetErrorReportSharePermission(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_firmware_version.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { struct alignas(4) FirmwareVersion { u8 major; u8 minor; u8 micro; u8 padding1; u8 revision_major; u8 revision_minor; u8 padding2; u8 padding3; char platform[0x20]; char revision[0x40]; char display_version[0x18]; char display_name[0x80]; constexpr int GetComparableVersion() const { return (static_cast<int>(major) << 16) | (static_cast<int>(minor) << 8) | (static_cast<int>(micro) << 0); } constexpr friend bool operator==(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() == rhs.GetComparableVersion(); } constexpr friend bool operator!=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() != rhs.GetComparableVersion(); } constexpr friend bool operator<=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() <= rhs.GetComparableVersion(); } constexpr friend bool operator>=(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() >= rhs.GetComparableVersion(); } constexpr friend bool operator<(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() < rhs.GetComparableVersion(); } constexpr friend bool operator>(const FirmwareVersion &lhs, const FirmwareVersion &rhs) { return lhs.GetComparableVersion() > rhs.GetComparableVersion(); } }; void GetFirmwareVersion(FirmwareVersion *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_platform_region.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { enum PlatformRegion { PlatformRegion_Invalid = 0, PlatformRegion_Global = 1, PlatformRegion_China = 2, }; PlatformRegion GetPlatformRegion(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_product_model.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { enum ProductModel { ProductModel_Invalid = 0, ProductModel_Nx = 1, }; ProductModel GetProductModel(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_region.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { enum RegionCode { RegionCode_Japan = 0, RegionCode_Usa = 1, RegionCode_Europe = 2, RegionCode_Australia = 3, RegionCode_HongKongTaiwanKorea = 4, RegionCode_China = 5, }; void GetRegionCode(RegionCode *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings/system/settings_serial_number.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/settings/settings_types.hpp> namespace ams::settings::system { struct SerialNumber { char str[0x18]; }; void GetSerialNumber(SerialNumber *out); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/settings.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/settings/settings_types.hpp> #include <stratosphere/settings/settings_fwdbg_types.hpp> #include <stratosphere/settings/settings_fwdbg_api.hpp> #include <stratosphere/settings/factory/settings_serial_number.hpp> #include <stratosphere/settings/factory/settings_configuration_id.hpp> #include <stratosphere/settings/factory/settings_device_certificate.hpp> #include <stratosphere/settings/system/settings_error_report.hpp> #include <stratosphere/settings/system/settings_firmware_version.hpp> #include <stratosphere/settings/system/settings_platform_region.hpp> #include <stratosphere/settings/system/settings_product_model.hpp> #include <stratosphere/settings/system/settings_region.hpp> #include <stratosphere/settings/system/settings_serial_number.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp> namespace ams::sf::cmif { struct DomainObjectId { u32 value; constexpr void SetValue(u32 new_value) { this->value = new_value; } }; static_assert(std::is_trivial<DomainObjectId>::value && sizeof(DomainObjectId) == sizeof(u32), "DomainObjectId"); inline constexpr bool operator==(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value == rhs.value; } inline constexpr bool operator!=(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value != rhs.value; } inline constexpr bool operator<(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value < rhs.value; } inline constexpr bool operator<=(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value <= rhs.value; } inline constexpr bool operator>(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value > rhs.value; } inline constexpr bool operator>=(const DomainObjectId &lhs, const DomainObjectId &rhs) { return lhs.value >= rhs.value; } constexpr inline const DomainObjectId InvalidDomainObjectId = { .value = 0 }; class ServerDomainBase { public: virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) = 0; virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) = 0; virtual void UnreserveIds(const DomainObjectId *ids, size_t count) = 0; virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) = 0; virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) = 0; virtual ServiceObjectHolder GetObject(DomainObjectId id) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/cmif/sf_cmif_domain_api.hpp> #include <stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp> #include <stratosphere/sf/impl/sf_service_object_impl.hpp> namespace ams::sf::cmif { class ServerDomainManager { NON_COPYABLE(ServerDomainManager); NON_MOVEABLE(ServerDomainManager); private: class Domain; struct Entry { NON_COPYABLE(Entry); NON_MOVEABLE(Entry); util::IntrusiveListNode free_list_node; util::IntrusiveListNode domain_list_node; Domain *owner; ServiceObjectHolder object; explicit Entry() : owner(nullptr) { /* ... */ } }; class Domain final : public DomainServiceObject, private sf::impl::ServiceObjectImplBase2 { NON_COPYABLE(Domain); NON_MOVEABLE(Domain); private: using EntryList = typename util::IntrusiveListMemberTraits<&Entry::domain_list_node>::ListType; private: ServerDomainManager *m_manager; EntryList m_entries; public: explicit Domain(ServerDomainManager *m) : m_manager(m) { /* ... */ } ~Domain(); void DisposeImpl(); virtual void AddReference() override { ServiceObjectImplBase2::AddReferenceImpl(); } virtual void Release() override { if (ServiceObjectImplBase2::ReleaseImpl()) { this->DisposeImpl(); } } virtual ServerDomainBase *GetServerDomain() override final { return static_cast<ServerDomainBase *>(this); } virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final; virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) override final; virtual void UnreserveIds(const DomainObjectId *ids, size_t count) override final; virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) override final; virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) override final; virtual ServiceObjectHolder GetObject(DomainObjectId id) override final; }; public: using DomainEntryStorage = util::TypedStorage<Entry>; using DomainStorage = util::TypedStorage<Domain>; private: class EntryManager { private: using EntryList = typename util::IntrusiveListMemberTraits<&Entry::free_list_node>::ListType; private: os::SdkMutex m_lock; EntryList m_free_list; Entry *m_entries; size_t m_num_entries; public: EntryManager(DomainEntryStorage *entry_storage, size_t entry_count); ~EntryManager(); Entry *AllocateEntry(); void FreeEntry(Entry *); void AllocateSpecificEntries(const DomainObjectId *ids, size_t count); inline DomainObjectId GetId(Entry *e) { const size_t index = e - m_entries; AMS_ABORT_UNLESS(index < m_num_entries); return DomainObjectId{ u32(index + 1) }; } inline Entry *GetEntry(DomainObjectId id) { if (id == InvalidDomainObjectId) { return nullptr; } const size_t index = id.value - 1; if (!(index < m_num_entries)) { return nullptr; } return m_entries + index; } }; private: os::SdkMutex m_entry_owner_lock; EntryManager m_entry_manager; private: virtual void *AllocateDomain() = 0; virtual void FreeDomain(void *) = 0; protected: ServerDomainManager(DomainEntryStorage *entry_storage, size_t entry_count) : m_entry_owner_lock(), m_entry_manager(entry_storage, entry_count) { /* ... */ } inline DomainServiceObject *AllocateDomainServiceObject() { void *storage = this->AllocateDomain(); if (storage == nullptr) { return nullptr; } return std::construct_at(static_cast<Domain *>(storage), this); } public: static void DestroyDomainServiceObject(DomainServiceObject *obj) { static_cast<Domain *>(obj)->DisposeImpl(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_mitm_config.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp> #include <stratosphere/sf/cmif/sf_cmif_domain_api.hpp> #include <stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp> namespace ams::sf::cmif { class DomainServiceObjectDispatchTable : public impl::ServiceDispatchTableBase { private: Result ProcessMessageImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const; Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, ServerDomainBase *domain, const cmif::PointerAndSize &in_raw_data) const; public: Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; }; class DomainServiceObjectProcessor : public ServerMessageProcessor { private: ServerMessageProcessor *m_impl_processor; ServerDomainBase *m_domain; DomainObjectId *m_in_object_ids; DomainObjectId *m_out_object_ids; size_t m_num_in_objects; ServerMessageRuntimeMetadata m_impl_metadata; public: DomainServiceObjectProcessor(ServerDomainBase *d, DomainObjectId *in_obj_ids, size_t num_in_objs) : m_domain(d), m_in_object_ids(in_obj_ids), m_num_in_objects(num_in_objs) { AMS_ABORT_UNLESS(m_domain != nullptr); AMS_ABORT_UNLESS(m_in_object_ids != nullptr); m_impl_processor = nullptr; m_out_object_ids = nullptr; m_impl_metadata = {}; } constexpr size_t GetInObjectCount() const { return m_num_in_objects; } constexpr size_t GetOutObjectCount() const { return m_impl_metadata.GetOutObjectCount(); } constexpr size_t GetImplOutHeadersSize() const { return m_impl_metadata.GetOutHeadersSize(); } constexpr size_t GetImplOutDataTotalSize() const { return m_impl_metadata.GetUnalignedOutDataSize() + m_impl_metadata.GetOutHeadersSize(); } public: /* Used to enabled templated message processors. */ virtual void SetImplementationProcessor(ServerMessageProcessor *impl) override final { if (m_impl_processor == nullptr) { m_impl_processor = impl; } else { m_impl_processor->SetImplementationProcessor(impl); } m_impl_metadata = m_impl_processor->GetRuntimeMetadata(); } virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final { const auto runtime_metadata = m_impl_processor->GetRuntimeMetadata(); return ServerMessageRuntimeMetadata { .in_data_size = static_cast<u16>(runtime_metadata.GetInDataSize() + runtime_metadata.GetInObjectCount() * sizeof(DomainObjectId)), .unaligned_out_data_size = static_cast<u16>(runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutObjectCount() * sizeof(DomainObjectId)), .in_headers_size = static_cast<u8>(runtime_metadata.GetInHeadersSize() + sizeof(CmifDomainInHeader)), .out_headers_size = static_cast<u8>(runtime_metadata.GetOutHeadersSize() + sizeof(CmifDomainOutHeader)), .in_object_count = 0, .out_object_count = 0, }; } virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const override final; virtual Result GetInObjects(ServiceObjectHolder *in_objects) const override final; virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final; virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) override final; virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) override final; }; class DomainServiceObject : public IServiceObject, public ServerDomainBase { friend class DomainServiceObjectDispatchTable; public: static constexpr inline DomainServiceObjectDispatchTable s_CmifServiceDispatchTable{}; private: virtual ServerDomainBase *GetServerDomain() = 0; }; class MitmDomainServiceObject : public DomainServiceObject{}; static_assert(sizeof(DomainServiceObject) == sizeof(MitmDomainServiceObject)); template<> struct ServiceDispatchTraits<DomainServiceObject> { static_assert(std::is_base_of<sf::IServiceObject, DomainServiceObject>::value, "DomainServiceObject must derive from sf::IServiceObject"); #if AMS_SF_MITM_SUPPORTED static_assert(!std::is_base_of<sf::IMitmServiceObject, DomainServiceObject>::value, "DomainServiceObject must not derive from sf::IMitmServiceObject"); #endif using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); using DispatchTableType = DomainServiceObjectDispatchTable; static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessage<DispatchTableType>; static constexpr inline ServiceDispatchMeta Meta{std::addressof(DomainServiceObject::s_CmifServiceDispatchTable), ProcessHandlerImpl}; }; template<> struct ServiceDispatchTraits<MitmDomainServiceObject> { static_assert(std::is_base_of<DomainServiceObject, MitmDomainServiceObject>::value, "MitmDomainServiceObject must derive from DomainServiceObject"); using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); using DispatchTableType = DomainServiceObjectDispatchTable; static constexpr ProcessHandlerType ProcessHandlerImpl = &impl::ServiceDispatchTableBase::ProcessMessageForMitm<DispatchTableType>; static constexpr inline ServiceDispatchMeta Meta{std::addressof(DomainServiceObject::s_CmifServiceDispatchTable), ProcessHandlerImpl}; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_inline_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> namespace ams::sf::cmif { using InlineContext = u32; InlineContext GetInlineContext(); InlineContext SetInlineContext(InlineContext ctx); class ScopedInlineContextChanger { private: InlineContext m_prev_ctx; public: ALWAYS_INLINE explicit ScopedInlineContextChanger(InlineContext new_ctx) : m_prev_ctx(SetInlineContext(new_ctx)) { /* ... */ } ~ScopedInlineContextChanger() { SetInlineContext(m_prev_ctx); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> namespace ams::sf::cmif { class PointerAndSize { private: uintptr_t m_pointer; size_t m_size; public: constexpr PointerAndSize() : m_pointer(0), m_size(0) { /* ... */ } constexpr PointerAndSize(uintptr_t ptr, size_t sz) : m_pointer(ptr), m_size(sz) { /* ... */ } PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } void *GetPointer() const { return reinterpret_cast<void *>(m_pointer); } constexpr uintptr_t GetAddress() const { return m_pointer; } constexpr size_t GetSize() const { return m_size; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> namespace ams::sf::cmif { /* Forward declare ServiceDispatchContext, ServiceObjectHolder. */ struct ServiceDispatchContext; class ServiceObjectHolder; struct DomainObjectId; /* This is needed for non-templated domain message processing. */ struct ServerMessageRuntimeMetadata { u16 in_data_size; u16 unaligned_out_data_size; u8 in_headers_size; u8 out_headers_size; u8 in_object_count; u8 out_object_count; constexpr size_t GetInDataSize() const { return static_cast<size_t>(this->in_data_size); } constexpr size_t GetOutDataSize() const { return static_cast<size_t>(util::AlignUp(this->unaligned_out_data_size, sizeof(u32))); } constexpr size_t GetUnalignedOutDataSize() const { return static_cast<size_t>(this->unaligned_out_data_size); } constexpr size_t GetInHeadersSize() const { return static_cast<size_t>(this->in_headers_size); } constexpr size_t GetOutHeadersSize() const { return static_cast<size_t>(this->out_headers_size); } constexpr size_t GetInObjectCount() const { return static_cast<size_t>(this->in_object_count); } constexpr size_t GetOutObjectCount() const { return static_cast<size_t>(this->out_object_count); } constexpr size_t GetUnfixedOutPointerSizeOffset() const { return this->GetInDataSize() + this->GetInHeadersSize() + 0x10 /* padding. */; } }; static_assert(util::is_pod<ServerMessageRuntimeMetadata>::value, "util::is_pod<ServerMessageRuntimeMetadata>::value"); static_assert(sizeof(ServerMessageRuntimeMetadata) == sizeof(u64), "sizeof(ServerMessageRuntimeMetadata)"); class ServerMessageProcessor { public: /* Used to enabled templated message processors. */ virtual void SetImplementationProcessor(ServerMessageProcessor *impl) = 0; virtual const ServerMessageRuntimeMetadata GetRuntimeMetadata() const = 0; virtual Result PrepareForProcess(const ServiceDispatchContext &ctx, const ServerMessageRuntimeMetadata runtime_metadata) const = 0; virtual Result GetInObjects(ServiceObjectHolder *in_objects) const = 0; virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0; virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, PointerAndSize &out_raw_data, const ServerMessageRuntimeMetadata runtime_metadata) = 0; virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, ServiceObjectHolder *out_objects, DomainObjectId *ids) = 0; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_mitm_config.hpp> #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> #include <stratosphere/sf/cmif/sf_cmif_server_message_processor.hpp> namespace ams::sf::hipc { class ServerSessionManager; class ServerSession; } namespace ams::sf::cmif { class ServerMessageProcessor; struct HandlesToClose { os::NativeHandle handles[8]; size_t num_handles; }; struct ServiceDispatchContext { sf::IServiceObject *srv_obj; hipc::ServerSessionManager *manager; hipc::ServerSession *session; ServerMessageProcessor *processor; HandlesToClose *handles_to_close; const PointerAndSize pointer_buffer; const PointerAndSize in_message_buffer; const PointerAndSize out_message_buffer; const HipcParsedRequest request; }; struct ServiceCommandMeta { hos::Version hosver_low; hos::Version hosver_high; u32 cmd_id; Result (*handler)(CmifOutHeader **out_header_ptr, ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data); constexpr inline bool MatchesVersion(hos::Version hosver) const { const bool min_valid = this->hosver_low == hos::Version_Min; const bool max_valid = this->hosver_high == hos::Version_Max; return (min_valid || this->hosver_low <= hosver) && (max_valid || hosver <= this->hosver_high); } constexpr inline bool Matches(u32 cmd_id, hos::Version hosver) const { return this->cmd_id == cmd_id && this->MatchesVersion(hosver); } constexpr inline decltype(handler) GetHandler() const { return this->handler; } constexpr inline bool operator>(const ServiceCommandMeta &rhs) const { if (this->cmd_id > rhs.cmd_id) { return true; } else if (this->cmd_id == rhs.cmd_id && this->hosver_low > rhs.hosver_low) { return true; } else if (this->cmd_id == rhs.cmd_id && this->hosver_low == rhs.hosver_low && this->hosver_high == rhs.hosver_high){ return true; } else { return false; } } }; static_assert(util::is_pod<ServiceCommandMeta>::value && sizeof(ServiceCommandMeta) == 0x18, "sizeof(ServiceCommandMeta)"); namespace impl { class ServiceDispatchTableBase { protected: Result ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const; Result ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count, u32 interface_id_for_debug) const; public: /* CRTP. */ template<typename T> Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { static_assert(std::is_base_of<ServiceDispatchTableBase, T>::value, "ServiceDispatchTableBase::Process<T>"); R_RETURN(static_cast<const T *>(this)->ProcessMessage(ctx, in_raw_data)); } template<typename T> Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { static_assert(std::is_base_of<ServiceDispatchTableBase, T>::value, "ServiceDispatchTableBase::ProcessForMitm<T>"); R_RETURN(static_cast<const T *>(this)->ProcessMessageForMitm(ctx, in_raw_data)); } }; template<u32 InterfaceIdForDebug, size_t N> class ServiceDispatchTableImpl : public ServiceDispatchTableBase { public: static constexpr size_t NumEntries = N; private: const std::array<ServiceCommandMeta, N> m_entries; public: explicit constexpr ServiceDispatchTableImpl(const std::array<ServiceCommandMeta, N> &e) : m_entries{e} { /* ... */ } Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { R_RETURN(this->ProcessMessageImpl(ctx, in_raw_data, m_entries.data(), m_entries.size(), InterfaceIdForDebug)); } Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const { R_RETURN(this->ProcessMessageForMitmImpl(ctx, in_raw_data, m_entries.data(), m_entries.size(), InterfaceIdForDebug)); } constexpr const std::array<ServiceCommandMeta, N> &GetEntries() const { return m_entries; } }; } template<u32 InterfaceIdForDebug, size_t N> class ServiceDispatchTable : public impl::ServiceDispatchTableImpl<InterfaceIdForDebug, N> { public: explicit constexpr ServiceDispatchTable(const std::array<ServiceCommandMeta, N> &e) : impl::ServiceDispatchTableImpl<InterfaceIdForDebug, N>(e) { /* ... */ } }; struct ServiceDispatchMeta { const impl::ServiceDispatchTableBase *DispatchTable; Result (impl::ServiceDispatchTableBase::*ProcessHandler)(ServiceDispatchContext &, const cmif::PointerAndSize &) const; uintptr_t GetServiceId() const { return reinterpret_cast<uintptr_t>(this->DispatchTable); } }; template<typename T> requires sf::IsServiceObject<T> struct ServiceDispatchTraits { using ProcessHandlerType = decltype(ServiceDispatchMeta::ProcessHandler); static constexpr inline auto DispatchTable = T::template s_CmifServiceDispatchTable<T>; using DispatchTableType = decltype(DispatchTable); static constexpr ProcessHandlerType ProcessHandlerImpl = sf::IsMitmServiceObject<T> ? (&impl::ServiceDispatchTableBase::ProcessMessageForMitm<DispatchTableType>) : (&impl::ServiceDispatchTableBase::ProcessMessage<DispatchTableType>); static constexpr inline ServiceDispatchMeta Meta{std::addressof(DispatchTable), ProcessHandlerImpl}; }; template<> struct ServiceDispatchTraits<sf::IServiceObject> { static constexpr inline auto DispatchTable = ServiceDispatchTable<0, 0>(std::array<ServiceCommandMeta, 0>{}); }; #if AMS_SF_MITM_SUPPORTED template<> struct ServiceDispatchTraits<sf::IMitmServiceObject> { static constexpr inline auto DispatchTable = ServiceDispatchTable<0, 0>(std::array<ServiceCommandMeta, 0>{}); }; #endif template<typename T> constexpr ALWAYS_INLINE const ServiceDispatchMeta *GetServiceDispatchMeta() { return std::addressof(ServiceDispatchTraits<T>::Meta); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp> namespace ams::sf::cmif { class ServiceObjectHolder { private: SharedPointer<IServiceObject> m_srv; const ServiceDispatchMeta *m_dispatch_meta; private: /* Copy constructor. */ ServiceObjectHolder(const ServiceObjectHolder &o) : m_srv(o.m_srv), m_dispatch_meta(o.m_dispatch_meta) { /* ... */ } ServiceObjectHolder &operator=(const ServiceObjectHolder &o) = delete; public: /* Default constructor, null all members. */ ServiceObjectHolder() : m_srv(nullptr, false), m_dispatch_meta(nullptr) { /* ... */ } ~ServiceObjectHolder() { m_dispatch_meta = nullptr; } /* Ensure correct type id at runtime through template constructor. */ template<typename ServiceImpl> constexpr explicit ServiceObjectHolder(SharedPointer<ServiceImpl> &&s) : m_srv(std::move(s)), m_dispatch_meta(GetServiceDispatchMeta<ServiceImpl>()) { /* ... */ } /* Move constructor, assignment operator. */ ServiceObjectHolder(ServiceObjectHolder &&o) : m_srv(std::move(o.m_srv)), m_dispatch_meta(std::move(o.m_dispatch_meta)) { o.m_dispatch_meta = nullptr; } ServiceObjectHolder &operator=(ServiceObjectHolder &&o) { ServiceObjectHolder tmp(std::move(o)); tmp.swap(*this); return *this; } /* State management. */ void swap(ServiceObjectHolder &o) { m_srv.swap(o.m_srv); std::swap(m_dispatch_meta, o.m_dispatch_meta); } void Reset() { m_srv = nullptr; m_dispatch_meta = nullptr; } ServiceObjectHolder Clone() const { return ServiceObjectHolder(*this); } /* Boolean operators. */ explicit constexpr operator bool() const { return m_srv != nullptr; } constexpr bool operator!() const { return m_srv == nullptr; } /* Getters. */ constexpr uintptr_t GetServiceId() const { if (m_dispatch_meta) { return m_dispatch_meta->GetServiceId(); } return 0; } template<typename Interface> constexpr inline bool IsServiceObjectValid() const { return this->GetServiceId() == GetServiceDispatchMeta<Interface>()->GetServiceId(); } template<typename Interface> inline Interface *GetServiceObject() const { if (this->GetServiceId() == GetServiceDispatchMeta<Interface>()->GetServiceId()) { return static_cast<Interface *>(m_srv.Get()); } return nullptr; } inline sf::IServiceObject *GetServiceObjectUnsafe() const { return static_cast<sf::IServiceObject *>(m_srv.Get()); } /* Processing. */ Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> namespace ams::sf::hipc { void *GetMessageBufferOnTls(); constexpr size_t TlsMessageBufferSize = 0x100; #if defined(ATMOSPHERE_OS_HORIZON) ALWAYS_INLINE void *GetMessageBufferOnTls() { return svc::GetThreadLocalRegion()->message_buffer; } #endif enum class ReceiveResult { Success, Closed, NeedsRetry, }; void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *holder, os::NativeHandle port); void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *holder, os::NativeHandle request); Result Receive(ReceiveResult *out_recv_result, os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer); Result Receive(bool *out_closed, os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer); Result Reply(os::NativeHandle session_handle, const cmif::PointerAndSize &message_buffer); Result CreateSession(os::NativeHandle *out_server_handle, os::NativeHandle *out_client_handle); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp> #include <stratosphere/sf/cmif/sf_cmif_domain_manager.hpp> namespace ams::sf::hipc { class ServerDomainSessionManager : public ServerSessionManager, private cmif::ServerDomainManager { protected: using cmif::ServerDomainManager::DomainEntryStorage; using cmif::ServerDomainManager::DomainStorage; protected: virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message) override final; public: ServerDomainSessionManager(DomainEntryStorage *entry_storage, size_t entry_count) : ServerDomainManager(entry_storage, entry_count) { /* ... */ } inline cmif::DomainServiceObject *AllocateDomainServiceObject() { return cmif::ServerDomainManager::AllocateDomainServiceObject(); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_mitm_config.hpp> #include <stratosphere/sf/hipc/sf_hipc_server_domain_session_manager.hpp> #include <stratosphere/sm.hpp> namespace ams::sf::hipc { struct DefaultServerManagerOptions { static constexpr size_t PointerBufferSize = 0; static constexpr size_t MaxDomains = 0; static constexpr size_t MaxDomainObjects = 0; static constexpr bool CanDeferInvokeRequest = false; static constexpr bool CanManageMitmServers = false; }; static constexpr size_t ServerSessionCountMax = 0x40; static_assert(ServerSessionCountMax == 0x40, "ServerSessionCountMax isn't 0x40 somehow, this assert is a reminder that this will break lots of things"); template<size_t, typename, size_t> class ServerManager; class ServerManagerBase : public ServerDomainSessionManager { NON_COPYABLE(ServerManagerBase); NON_MOVEABLE(ServerManagerBase); public: #if AMS_SF_MITM_SUPPORTED using MitmQueryFunction = bool (*)(const sm::MitmProcessInfo &); #endif private: enum class UserDataTag : uintptr_t { Server = 1, Session = 2, #if AMS_SF_MITM_SUPPORTED MitmServer = 3, #endif }; protected: using ServerDomainSessionManager::DomainEntryStorage; using ServerDomainSessionManager::DomainStorage; protected: class Server : public os::MultiWaitHolderType { friend class ServerManagerBase; template<size_t, typename, size_t> friend class ServerManager; NON_COPYABLE(Server); NON_MOVEABLE(Server); private: cmif::ServiceObjectHolder m_static_object; os::NativeHandle m_port_handle; sm::ServiceName m_service_name; int m_index; bool m_service_managed; #if AMS_SF_MITM_SUPPORTED bool m_is_mitm_server; #endif public: #if AMS_SF_MITM_SUPPORTED void AcknowledgeMitmSession(std::shared_ptr<::Service> *out_fsrv, sm::MitmProcessInfo *out_client_info) { /* Check mitm server. */ AMS_ABORT_UNLESS(m_is_mitm_server); /* Create forward service. */ *out_fsrv = ServerSession::CreateForwardService(); /* Get client info. */ R_ABORT_UNLESS(sm::mitm::AcknowledgeSession(out_fsrv->get(), out_client_info, m_service_name)); } #endif }; protected: static constinit inline bool g_is_any_deferred_supported = false; #if AMS_SF_MITM_SUPPORTED static constinit inline bool g_is_any_mitm_supported = false; #endif private: /* Multiple wait management. */ os::MultiWaitType m_multi_wait; os::Event m_request_stop_event; os::MultiWaitHolderType m_request_stop_event_holder; os::Event m_notify_event; os::MultiWaitHolderType m_notify_event_holder; os::SdkMutex m_selection_mutex; os::SdkMutex m_deferred_list_mutex; os::MultiWaitType m_deferred_list; /* Boolean values. */ const bool m_is_defer_supported; const bool m_is_mitm_supported; private: virtual void RegisterServerSessionToWait(ServerSession *session) override final; void LinkToDeferredList(os::MultiWaitHolderType *holder); void LinkDeferred(); bool WaitAndProcessImpl(); Result ProcessForServer(os::MultiWaitHolderType *holder); Result ProcessForSession(os::MultiWaitHolderType *holder); #if AMS_SF_MITM_SUPPORTED Result ProcessForMitmServer(os::MultiWaitHolderType *holder); #endif void RegisterServerImpl(Server *server, os::NativeHandle port_handle, bool is_mitm_server) { server->m_port_handle = port_handle; hipc::AttachMultiWaitHolderForAccept(server, port_handle); #if AMS_SF_MITM_SUPPORTED server->m_is_mitm_server = is_mitm_server; if (is_mitm_server) { /* Mitm server. */ AMS_ABORT_UNLESS(this->CanManageMitmServers()); os::SetMultiWaitHolderUserData(server, static_cast<uintptr_t>(UserDataTag::MitmServer)); } else { /* Non-mitm server. */ os::SetMultiWaitHolderUserData(server, static_cast<uintptr_t>(UserDataTag::Server)); } #else AMS_UNUSED(is_mitm_server); os::SetMultiWaitHolderUserData(server, static_cast<uintptr_t>(UserDataTag::Server)); #endif os::LinkMultiWaitHolder(std::addressof(m_multi_wait), server); } void RegisterServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, os::NativeHandle port_handle, bool is_mitm_server) { /* Allocate server memory. */ auto *server = this->AllocateServer(); AMS_ABORT_UNLESS(server != nullptr); server->m_service_managed = false; if (static_holder) { server->m_static_object = std::move(static_holder); } else { server->m_index = index; } this->RegisterServerImpl(server, port_handle, is_mitm_server); } Result RegisterServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, sm::ServiceName service_name, size_t max_sessions) { /* Register service. */ os::NativeHandle port_handle; R_TRY(sm::RegisterService(&port_handle, service_name, max_sessions, false)); /* Allocate server memory. */ auto *server = this->AllocateServer(); AMS_ABORT_UNLESS(server != nullptr); server->m_service_managed = true; server->m_service_name = service_name; if (static_holder) { server->m_static_object = std::move(static_holder); } else { server->m_index = index; } this->RegisterServerImpl(server, port_handle, false); R_SUCCEED(); } #if AMS_SF_MITM_SUPPORTED Result InstallMitmServerImpl(os::NativeHandle *out_port_handle, sm::ServiceName service_name, MitmQueryFunction query_func); #endif protected: virtual Server *AllocateServer() = 0; virtual void DestroyServer(Server *server) = 0; virtual Result OnNeedsToAccept(int port_index, Server *server) { AMS_UNUSED(port_index, server); AMS_ABORT("OnNeedsToAccept must be overridden when using indexed ports"); } template<typename Interface> Result AcceptImpl(Server *server, SharedPointer<Interface> p) { R_RETURN(ServerSessionManager::AcceptSession(server->m_port_handle, std::move(p))); } #if AMS_SF_MITM_SUPPORTED template<typename Interface> Result AcceptMitmImpl(Server *server, SharedPointer<Interface> p, std::shared_ptr<::Service> forward_service) { AMS_ABORT_UNLESS(this->CanManageMitmServers()); R_RETURN(ServerSessionManager::AcceptMitmSession(server->m_port_handle, std::move(p), std::move(forward_service))); } template<typename Interface> Result RegisterMitmServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, sm::ServiceName service_name) { /* Install mitm service. */ os::NativeHandle port_handle; R_TRY(this->InstallMitmServerImpl(&port_handle, service_name, &Interface::ShouldMitm)); /* Allocate server memory. */ auto *server = this->AllocateServer(); AMS_ABORT_UNLESS(server != nullptr); server->m_service_managed = true; server->m_service_name = service_name; if (static_holder) { server->m_static_object = std::move(static_holder); } else { server->m_index = index; } this->RegisterServerImpl(server, port_handle, true); R_SUCCEED(); } #endif public: ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count, bool defer_supported, bool mitm_supported) : ServerDomainSessionManager(entry_storage, entry_count), m_request_stop_event(os::EventClearMode_ManualClear), m_notify_event(os::EventClearMode_ManualClear), m_selection_mutex(), m_deferred_list_mutex(), m_is_defer_supported(defer_supported), m_is_mitm_supported(mitm_supported) { /* Link multi-wait holders. */ os::InitializeMultiWait(std::addressof(m_multi_wait)); os::InitializeMultiWaitHolder(std::addressof(m_request_stop_event_holder), m_request_stop_event.GetBase()); os::LinkMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_request_stop_event_holder)); os::InitializeMultiWaitHolder(std::addressof(m_notify_event_holder), m_notify_event.GetBase()); os::LinkMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_notify_event_holder)); os::InitializeMultiWait(std::addressof(m_deferred_list)); } virtual ~ServerManagerBase() = default; static ALWAYS_INLINE bool CanAnyDeferInvokeRequest() { return g_is_any_deferred_supported; } ALWAYS_INLINE bool CanDeferInvokeRequest() const { return CanAnyDeferInvokeRequest() && m_is_defer_supported; } #if AMS_SF_MITM_SUPPORTED static ALWAYS_INLINE bool CanAnyManageMitmServers() { return g_is_any_mitm_supported; } ALWAYS_INLINE bool CanManageMitmServers() const { return CanAnyManageMitmServers() && m_is_mitm_supported; } #else static consteval bool CanAnyManageMitmServers() { return false; } static consteval bool CanManageMitmServers() { return false; } #endif template<typename Interface> void RegisterObjectForServer(SharedPointer<Interface> static_object, os::NativeHandle port_handle) { this->RegisterServerImpl(0, cmif::ServiceObjectHolder(std::move(static_object)), port_handle, false); } template<typename Interface> Result RegisterObjectForServer(SharedPointer<Interface> static_object, sm::ServiceName service_name, size_t max_sessions) { R_RETURN(this->RegisterServerImpl(0, cmif::ServiceObjectHolder(std::move(static_object)), service_name, max_sessions)); } void RegisterServer(int port_index, os::NativeHandle port_handle) { this->RegisterServerImpl(port_index, cmif::ServiceObjectHolder(), port_handle, false); } Result RegisterServer(int port_index, sm::ServiceName service_name, size_t max_sessions) { R_RETURN(this->RegisterServerImpl(port_index, cmif::ServiceObjectHolder(), service_name, max_sessions)); } /* Processing. */ os::MultiWaitHolderType *WaitSignaled(); void ResumeProcessing(); void RequestStopProcessing(); void AddUserMultiWaitHolder(os::MultiWaitHolderType *holder); Result Process(os::MultiWaitHolderType *holder); void WaitAndProcess(); void LoopProcess(); }; template<size_t MaxServers, typename ManagerOptions = DefaultServerManagerOptions, size_t MaxSessions = ServerSessionCountMax - MaxServers> class ServerManager : public ServerManagerBase { NON_COPYABLE(ServerManager); NON_MOVEABLE(ServerManager); static_assert(MaxServers <= ServerSessionCountMax, "MaxServers can never be larger than ServerSessionCountMax (0x40)."); static_assert(MaxSessions <= ServerSessionCountMax, "MaxSessions can never be larger than ServerSessionCountMax (0x40)."); static_assert(MaxServers + MaxSessions <= ServerSessionCountMax, "MaxServers + MaxSessions can never be larger than ServerSessionCountMax (0x40)."); private: static constexpr inline bool DomainCountsValid = [] { if constexpr (ManagerOptions::MaxDomains > 0) { return ManagerOptions::MaxDomainObjects > 0; } else { return ManagerOptions::MaxDomainObjects == 0; } }(); static_assert(DomainCountsValid, "Invalid Domain Counts"); #if !(AMS_SF_MITM_SUPPORTED) static_assert(!ManagerOptions::CanManageMitmServers); #endif protected: using ServerManagerBase::DomainEntryStorage; using ServerManagerBase::DomainStorage; private: /* Resource storage. */ os::SdkMutex m_resource_mutex; util::TypedStorage<Server> m_server_storages[MaxServers]; bool m_server_allocated[MaxServers]; util::TypedStorage<ServerSession> m_session_storages[MaxSessions]; bool m_session_allocated[MaxSessions]; u8 m_pointer_buffer_storage[0x10 + (MaxSessions * ManagerOptions::PointerBufferSize)]; #if AMS_SF_MITM_SUPPORTED u8 m_saved_message_storage[0x10 + (MaxSessions * ((ManagerOptions::CanDeferInvokeRequest || ManagerOptions::CanManageMitmServers) ? hipc::TlsMessageBufferSize : 0))]; #else u8 m_saved_message_storage[0x10 + (MaxSessions * ((ManagerOptions::CanDeferInvokeRequest) ? hipc::TlsMessageBufferSize : 0))]; #endif uintptr_t m_pointer_buffers_start; uintptr_t m_saved_messages_start; /* Domain resources. */ DomainStorage m_domain_storages[ManagerOptions::MaxDomains]; bool m_domain_allocated[ManagerOptions::MaxDomains]; DomainEntryStorage m_domain_entry_storages[ManagerOptions::MaxDomainObjects]; private: constexpr inline size_t GetServerIndex(const Server *server) const { const size_t i = server - GetPointer(m_server_storages[0]); AMS_ABORT_UNLESS(i < MaxServers); return i; } constexpr inline size_t GetSessionIndex(const ServerSession *session) const { const size_t i = session - GetPointer(m_session_storages[0]); AMS_ABORT_UNLESS(i < MaxSessions); return i; } constexpr inline cmif::PointerAndSize GetObjectBySessionIndex(const ServerSession *session, uintptr_t start, size_t size) const { return cmif::PointerAndSize(start + this->GetSessionIndex(session) * size, size); } protected: virtual ServerSession *AllocateSession() override final { if constexpr (MaxSessions > 0) { std::scoped_lock lk(m_resource_mutex); for (size_t i = 0; i < MaxSessions; i++) { if (!m_session_allocated[i]) { m_session_allocated[i] = true; return GetPointer(m_session_storages[i]); } } } return nullptr; } virtual void FreeSession(ServerSession *session) override final { std::scoped_lock lk(m_resource_mutex); const size_t index = this->GetSessionIndex(session); AMS_ABORT_UNLESS(m_session_allocated[index]); m_session_allocated[index] = false; } virtual Server *AllocateServer() override final { if constexpr (MaxServers > 0) { std::scoped_lock lk(m_resource_mutex); for (size_t i = 0; i < MaxServers; i++) { if (!m_server_allocated[i]) { m_server_allocated[i] = true; return GetPointer(m_server_storages[i]); } } } return nullptr; } virtual void DestroyServer(Server *server) override final { std::scoped_lock lk(m_resource_mutex); const size_t index = this->GetServerIndex(server); AMS_ABORT_UNLESS(m_server_allocated[index]); { os::UnlinkMultiWaitHolder(server); os::FinalizeMultiWaitHolder(server); if (server->m_service_managed) { #if AMS_SF_MITM_SUPPORTED if constexpr (ManagerOptions::CanManageMitmServers) { if (server->m_is_mitm_server) { R_ABORT_UNLESS(sm::mitm::UninstallMitm(server->m_service_name)); } else { R_ABORT_UNLESS(sm::UnregisterService(server->m_service_name)); } } else { R_ABORT_UNLESS(sm::UnregisterService(server->m_service_name)); } #else R_ABORT_UNLESS(sm::UnregisterService(server->m_service_name)); #endif os::CloseNativeHandle(server->m_port_handle); } } m_server_allocated[index] = false; } virtual void *AllocateDomain() override final { std::scoped_lock lk(m_resource_mutex); for (size_t i = 0; i < ManagerOptions::MaxDomains; i++) { if (!m_domain_allocated[i]) { m_domain_allocated[i] = true; return GetPointer(m_domain_storages[i]); } } return nullptr; } virtual void FreeDomain(void *domain) override final { std::scoped_lock lk(m_resource_mutex); DomainStorage *ptr = static_cast<DomainStorage *>(domain); const size_t index = ptr - m_domain_storages; AMS_ABORT_UNLESS(index < ManagerOptions::MaxDomains); AMS_ABORT_UNLESS(m_domain_allocated[index]); m_domain_allocated[index] = false; } virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const override final { if constexpr (ManagerOptions::PointerBufferSize > 0) { return this->GetObjectBySessionIndex(session, m_pointer_buffers_start, ManagerOptions::PointerBufferSize); } else { return cmif::PointerAndSize(); } } virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const override final { if constexpr (ManagerOptions::CanDeferInvokeRequest || ManagerOptions::CanManageMitmServers) { return this->GetObjectBySessionIndex(session, m_saved_messages_start, hipc::TlsMessageBufferSize); } else { return cmif::PointerAndSize(); } } public: ServerManager() : ServerManagerBase(m_domain_entry_storages, ManagerOptions::MaxDomainObjects, ManagerOptions::CanDeferInvokeRequest, ManagerOptions::CanManageMitmServers), m_resource_mutex() { /* Clear storages. */ #define SF_SM_MEMCLEAR(obj) if constexpr (sizeof(obj) > 0) { std::memset(obj, 0, sizeof(obj)); } SF_SM_MEMCLEAR(m_server_storages); SF_SM_MEMCLEAR(m_server_allocated); SF_SM_MEMCLEAR(m_session_storages); SF_SM_MEMCLEAR(m_session_allocated); SF_SM_MEMCLEAR(m_pointer_buffer_storage); SF_SM_MEMCLEAR(m_saved_message_storage); SF_SM_MEMCLEAR(m_domain_allocated); #undef SF_SM_MEMCLEAR /* Set resource starts. */ m_pointer_buffers_start = util::AlignUp(reinterpret_cast<uintptr_t>(m_pointer_buffer_storage), 0x10); m_saved_messages_start = util::AlignUp(reinterpret_cast<uintptr_t>(m_saved_message_storage), 0x10); /* Update globals. */ if constexpr (ManagerOptions::CanDeferInvokeRequest) { ServerManagerBase::g_is_any_deferred_supported = true; } #if AMS_SF_MITM_SUPPORTED if constexpr (ManagerOptions::CanManageMitmServers) { ServerManagerBase::g_is_any_mitm_supported = true; } #endif } ~ServerManager() { /* Close all sessions. */ if constexpr (MaxSessions > 0) { for (size_t i = 0; i < MaxSessions; i++) { if (m_session_allocated[i]) { this->CloseSessionImpl(GetPointer(m_session_storages[i])); } } } /* Close all servers. */ if constexpr (MaxServers > 0) { for (size_t i = 0; i < MaxServers; i++) { if (m_server_allocated[i]) { this->DestroyServer(GetPointer(m_server_storages[i])); } } } } public: #if AMS_SF_MITM_SUPPORTED template<typename Interface, bool Enable = ManagerOptions::CanManageMitmServers, typename = typename std::enable_if<Enable>::type> Result RegisterMitmServer(int port_index, sm::ServiceName service_name) { AMS_ABORT_UNLESS(this->CanManageMitmServers()); R_RETURN(this->template RegisterMitmServerImpl<Interface>(port_index, cmif::ServiceObjectHolder(), service_name)); } #endif }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_mitm_config.hpp> #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp> #include <stratosphere/sf/hipc/sf_hipc_api.hpp> namespace ams::sf::cmif { struct ServiceDispatchContext; } namespace ams::sf::hipc { class ServerSessionManager; class ServerManagerBase; namespace impl { class HipcManagerImpl; } class ServerSession : public os::MultiWaitHolderType { friend class ServerSessionManager; friend class ServerManagerBase; friend class impl::HipcManagerImpl; NON_COPYABLE(ServerSession); NON_MOVEABLE(ServerSession); private: cmif::ServiceObjectHolder m_srv_obj_holder; cmif::PointerAndSize m_pointer_buffer; cmif::PointerAndSize m_saved_message; #if AMS_SF_MITM_SUPPORTED util::TypedStorage<std::shared_ptr<::Service>> m_forward_service; #endif os::NativeHandle m_session_handle; bool m_is_closed; bool m_has_received; const bool m_has_forward_service; public: ServerSession(os::NativeHandle h, cmif::ServiceObjectHolder &&obj) : m_srv_obj_holder(std::move(obj)), m_session_handle(h), m_has_forward_service(false) { hipc::AttachMultiWaitHolderForReply(this, h); m_is_closed = false; m_has_received = false; #if AMS_SF_MITM_SUPPORTED AMS_ABORT_UNLESS(!this->IsMitmSession()); #endif } ~ServerSession() { #if AMS_SF_MITM_SUPPORTED if (m_has_forward_service) { util::DestroyAt(m_forward_service); } #endif } #if AMS_SF_MITM_SUPPORTED ServerSession(os::NativeHandle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : m_srv_obj_holder(std::move(obj)), m_session_handle(h), m_has_forward_service(true) { hipc::AttachMultiWaitHolderForReply(this, h); m_is_closed = false; m_has_received = false; util::ConstructAt(m_forward_service, std::move(fsrv)); AMS_ABORT_UNLESS(util::GetReference(m_forward_service) != nullptr); } ALWAYS_INLINE bool IsMitmSession() const { return m_has_forward_service; } Result ForwardRequest(const cmif::ServiceDispatchContext &ctx) const; static inline void ForwardServiceDeleter(Service *srv) { serviceClose(srv); delete srv; } static inline std::shared_ptr<::Service> CreateForwardService() { return std::shared_ptr<::Service>(new ::Service(), ForwardServiceDeleter); } #endif }; class ServerSessionManager { private: template<typename Constructor> Result CreateSessionImpl(ServerSession **out, const Constructor &ctor) { /* Allocate session. */ ServerSession *session_memory = this->AllocateSession(); R_UNLESS(session_memory != nullptr, sf::hipc::ResultOutOfSessionMemory()); ON_RESULT_FAILURE { this->DestroySession(session_memory); }; /* Register session. */ R_TRY(ctor(session_memory)); /* Save new session to output. */ *out = session_memory; R_SUCCEED(); } void DestroySession(ServerSession *session); Result ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); virtual void RegisterServerSessionToWait(ServerSession *session) = 0; protected: Result DispatchRequest(cmif::ServiceObjectHolder &&obj, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); protected: virtual ServerSession *AllocateSession() = 0; virtual void FreeSession(ServerSession *session) = 0; virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const = 0; virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const = 0; Result ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message); void CloseSessionImpl(ServerSession *session); Result RegisterSessionImpl(ServerSession *session_memory, os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj); Result AcceptSessionImpl(ServerSession *session_memory, os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj); #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); Result AcceptMitmSessionImpl(ServerSession *session_memory, os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); #endif Result ReceiveRequest(ServerSession *session, const cmif::PointerAndSize &message) { R_RETURN(this->ReceiveRequestImpl(session, message)); } Result RegisterSession(ServerSession **out, os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj) { auto ctor = [&](ServerSession *session_memory) -> Result { R_RETURN(this->RegisterSessionImpl(session_memory, session_handle, std::forward<cmif::ServiceObjectHolder>(obj))); }; R_RETURN(this->CreateSessionImpl(out, ctor)); } Result AcceptSession(ServerSession **out, os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj) { auto ctor = [&](ServerSession *session_memory) -> Result { R_RETURN(this->AcceptSessionImpl(session_memory, port_handle, std::forward<cmif::ServiceObjectHolder>(obj))); }; R_RETURN(this->CreateSessionImpl(out, ctor)); } #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSession(ServerSession **out, os::NativeHandle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { auto ctor = [&](ServerSession *session_memory) -> Result { R_RETURN(this->RegisterMitmSessionImpl(session_memory, mitm_session_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv))); }; R_RETURN(this->CreateSessionImpl(out, ctor)); } Result AcceptMitmSession(ServerSession **out, os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) { auto ctor = [&](ServerSession *session_memory) -> Result { R_RETURN(this->AcceptMitmSessionImpl(session_memory, mitm_port_handle, std::forward<cmif::ServiceObjectHolder>(obj), std::forward<std::shared_ptr<::Service>>(fsrv))); }; R_RETURN(this->CreateSessionImpl(out, ctor)); } #endif public: Result RegisterSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj); Result AcceptSession(os::NativeHandle port_handle, cmif::ServiceObjectHolder &&obj); #if AMS_SF_MITM_SUPPORTED Result RegisterMitmSession(os::NativeHandle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); Result AcceptMitmSession(os::NativeHandle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv); #endif template<typename Interface> Result AcceptSession(os::NativeHandle port_handle, SharedPointer<Interface> obj) { R_RETURN(this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj)))); } #if AMS_SF_MITM_SUPPORTED template<typename Interface> Result AcceptMitmSession(os::NativeHandle mitm_port_handle, SharedPointer<Interface> obj, std::shared_ptr<::Service> &&fsrv) { R_RETURN(this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward<std::shared_ptr<::Service>>(fsrv))); } #endif Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message); virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) { /* This is unused. */ AMS_UNUSED(tag); return this; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_autogen_impl_macros.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/impl/sf_impl_autogen_interface_macros.hpp> #include <stratosphere/sf/impl/sf_impl_template_base.hpp> namespace ams::sf::impl { #define AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ virtual RETURN AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGS override { \ return ImplGetter::GetImplPointer(static_cast<ImplHolder *>(this))->NAME ARGNAMES; \ } #define AMS_SF_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO, INTF_ID) \ namespace NAMESPACE { \ \ AMS_SF_DEFINE_INTERFACE_IMPL(BASE, INTERFACE, CMD_MACRO, INTF_ID) \ \ } \ \ namespace ams::sf::impl { \ \ template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \ class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public Base, public ImplHolder { \ public: \ template<typename... Args> \ constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward<Args>(args)...) { } \ private: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD) \ }; \ \ } #define AMS_SF_DEFINE_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO, INTF_ID) \ AMS_SF_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, ::ams::sf::IServiceObject, CMD_MACRO, INTF_ID) #define AMS_SF_DEFINE_MITM_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO, INTF_ID) \ AMS_SF_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, ::ams::sf::IMitmServiceObject, CMD_MACRO, INTF_ID) #define AMS_SF_DEFINE_INTERFACE_WITH_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO, INTF_ID) \ namespace NAMESPACE { \ \ AMS_SF_DEFINE_INTERFACE_IMPL(BASE, INTERFACE, CMD_MACRO, INTF_ID) \ \ } \ \ namespace ams::sf::impl { \ \ template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \ class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public ImplTemplateBaseT<BASE, Base, ImplHolder, ImplGetter, Root> { \ private: \ using BaseImplTemplateBase = ImplTemplateBaseT<BASE, Base, ImplHolder, ImplGetter, Root>; \ public: \ template<typename... Args> \ constexpr explicit ImplTemplateBaseT(Args &&...args) : BaseImplTemplateBase(std::forward<Args>(args)...) { } \ private: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD) \ }; \ \ } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_autogen_interface_macros.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sf::impl { struct SyncFunctionTraits { public: template<typename R, typename C, typename... A> static std::tuple<A...> GetArgsImpl(R(C::*)(A...)); }; template<auto F> using SyncFunctionArgsType = decltype(SyncFunctionTraits::GetArgsImpl(F)); template<typename T> struct TypeTag{}; template<size_t First, size_t... Ix> static constexpr inline size_t ParameterCount = sizeof...(Ix); #define AMS_SF_IMPL_SYNC_FUNCTION_NAME(FUNCNAME) \ _ams_sf_sync_##FUNCNAME #define AMS_SF_IMPL_DEFINE_INTERFACE_SYNC_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ virtual RETURN AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGS = 0; #define AMS_SF_IMPL_EXTRACT_INTERFACE_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ using NAME##ArgumentsType = ::ams::sf::impl::SyncFunctionArgsType<&CLASSNAME::AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME)>; #define AMS_SF_IMPL_DEFINE_INTERFACE_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ ALWAYS_INLINE RETURN NAME ARGS { \ return this->AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGNAMES; \ } #define AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ template<typename Interface, typename A> struct NAME##ServiceCommandMetaHolder; \ \ template<typename Interface, typename ...Arguments> \ requires std::same_as<std::tuple<Arguments...>, NAME##ArgumentsType> \ struct NAME##ServiceCommandMetaHolder<Interface, std::tuple<Arguments...>> { \ static constexpr auto Value = ::ams::sf::impl::MakeServiceCommandMeta<VERSION_MIN, VERSION_MAX, CMD_ID, &Interface::AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME), RETURN, Interface, Arguments...>(); \ }; #define AMS_SF_IMPL_GET_NULL_FOR_PARAMETER_COUNT(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ , 0 #define AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ NAME##ServiceCommandMetaHolder<Interface, NAME##ArgumentsType>::Value, template<typename...> struct Print; #define AMS_SF_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO, INTF_ID) \ class CLASSNAME : public BASECLASS { \ public: \ static constexpr u32 InterfaceIdForDebug = INTF_ID; \ private: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_SYNC_METHOD) \ public: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_EXTRACT_INTERFACE_SYNC_METHOD_ARGUMENTS) \ public: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_METHOD) \ private: \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER) \ public: \ template<typename Interface> \ static constexpr inline ::ams::sf::cmif::ServiceDispatchTable s_CmifServiceDispatchTable { \ [] { \ constexpr size_t CurSize = ::ams::sf::impl::ParameterCount<0 CMD_MACRO(CLASSNAME, AMS_SF_IMPL_GET_NULL_FOR_PARAMETER_COUNT) >; \ std::array<::ams::sf::cmif::ServiceCommandMeta, CurSize> cur_entries { CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY) }; \ \ constexpr const auto &BaseEntries = ::ams::sf::cmif::ServiceDispatchTraits<BASECLASS>::DispatchTable.GetEntries(); \ constexpr size_t BaseSize = BaseEntries.size(); \ \ constexpr size_t CombinedSize = BaseSize + CurSize; \ \ std::array<size_t, CombinedSize> map{}; \ for (size_t i = 0; i < CombinedSize; ++i) { map[i] = i; } \ \ for (size_t i = 1; i < CombinedSize; ++i) { \ size_t j = i; \ while (j > 0) { \ const auto li = map[j]; \ const auto ri = map[j - 1]; \ \ const auto &lhs = (li < BaseSize) ? BaseEntries[li] : cur_entries[li - BaseSize]; \ const auto &rhs = (ri < BaseSize) ? BaseEntries[ri] : cur_entries[ri - BaseSize]; \ \ if (!(rhs > lhs)) { \ break; \ } \ \ std::swap(map[j], map[j - 1]); \ \ --j; \ } \ } \ \ std::array<::ams::sf::cmif::ServiceCommandMeta, CombinedSize> combined_entries{}; \ for (size_t i = 0; i < CombinedSize; ++i) { \ if (map[i] < BaseSize) { \ combined_entries[i] = BaseEntries[map[i]]; \ } else { \ combined_entries[i] = cur_entries[map[i] - BaseSize]; \ } \ } \ \ return ::ams::sf::cmif::ServiceDispatchTable<Interface::InterfaceIdForDebug, CombinedSize> { combined_entries }; \ }() \ }; \ }; #define AMS_SF_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ template<typename T, typename... Args> \ concept Is##CLASSNAME##__##NAME##Impl = requires (T &t, Args &&... args) { \ { t.NAME(std::forward<Args>(args)...) } -> std::same_as<RETURN>; \ }; \ \ template<typename T, typename A> \ struct Is##CLASSNAME##__##NAME##Holder : std::false_type{}; \ \ template<typename T, typename... Args> requires std::same_as<std::tuple<Args...>, CLASSNAME::NAME##ArgumentsType> \ struct Is##CLASSNAME##__##NAME##Holder<T, std::tuple<Args...>> : std::bool_constant<Is##CLASSNAME##__##NAME##Impl<T, Args...>>{}; \ \ template<typename T> \ static constexpr inline bool Is##CLASSNAME##__##NAME = Is##CLASSNAME##__##NAME##Holder<T, CLASSNAME::NAME##ArgumentsType>::value; #define AMS_SF_IMPL_CHECK_CONCEPT_HELPER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ Is##CLASSNAME##__##NAME<T> && #define AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \ CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_CONCEPT_HELPERS) \ \ template<typename T> \ concept Is##CLASSNAME = CMD_MACRO(CLASSNAME, AMS_SF_IMPL_CHECK_CONCEPT_HELPER) true; #define AMS_SF_DEFINE_INTERFACE_IMPL(BASECLASS, CLASSNAME, CMD_MACRO, INTF_ID) \ AMS_SF_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO, INTF_ID) \ AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \ static_assert(Is##CLASSNAME<CLASSNAME>); #define AMS_SF_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, hos::Version_Min, hos::Version_Max) #define AMS_SF_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, hos::Version_Max) #define AMS_SF_METHOD_INFO_9(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) #define AMS_SF_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, FUNC, ...) FUNC #define AMS_SF_METHOD_INFO(...) \ AMS_SF_METHOD_INFO_X(, ## __VA_ARGS__, AMS_SF_METHOD_INFO_9(__VA_ARGS__), AMS_SF_METHOD_INFO_8(__VA_ARGS__), AMS_SF_METHOD_INFO_7(__VA_ARGS__)) } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/sf_out.hpp> #include <stratosphere/sf/sf_buffers.hpp> #include <stratosphere/sf/sf_native_handle.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_dispatch.hpp> #include <stratosphere/sf/cmif/sf_cmif_service_object_holder.hpp> #include <stratosphere/sf/cmif/sf_cmif_domain_api.hpp> #include <stratosphere/sf/hipc/sf_hipc_api.hpp> #include <stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp> /* Serialization classes. */ namespace ams::sf { namespace impl { struct ProcessIdHolder { os::ProcessId process_id; constexpr explicit operator os::ProcessId() const { return this->process_id; } constexpr os::ProcessId GetValue() const { return this->process_id; } constexpr void SetValue(const os::ProcessId &p) { this->process_id = p; } }; } struct ClientProcessId : public impl::ProcessIdHolder {}; static_assert(std::is_trivial<ClientProcessId>::value && sizeof(ClientProcessId) == sizeof(os::ProcessId), "ClientProcessId"); struct ClientAppletResourceUserId : public impl::ProcessIdHolder {}; static_assert(std::is_trivial<ClientAppletResourceUserId >::value && sizeof(ClientAppletResourceUserId ) == sizeof(os::ProcessId), "ClientAppletResourceUserId"); namespace impl { constexpr inline Result MarshalProcessId(ClientProcessId &client, const os::ProcessId &client_process_id) { client.SetValue(client_process_id); R_SUCCEED(); } constexpr inline Result MarshalProcessId(ClientAppletResourceUserId &client, const os::ProcessId &client_process_id) { if (client.GetValue() != client_process_id && client.GetValue() != os::ProcessId{}) { R_THROW(sf::ResultPreconditionViolation()); } R_SUCCEED(); } } namespace impl { struct OutObjectTag{}; template<size_t, size_t> class InOutObjectHolder; } template<typename ServiceImpl> requires std::derived_from<ServiceImpl, IServiceObject> class Out<SharedPointer<ServiceImpl>> : public impl::OutObjectTag { template<typename> friend class Out; public: using Interface = ServiceImpl; private: impl::SharedPointerBase *m_out; cmif::DomainObjectId *m_object_id; private: Out(impl::SharedPointerBase *p, cmif::DomainObjectId *o = nullptr) : m_out(p), m_object_id(o) { /* ... */ } public: Out(const Out &rhs) : m_out(rhs.m_out), m_object_id(rhs.m_object_id) { /* ... */ } Out(SharedPointer<ServiceImpl> *out, cmif::DomainObjectId *o = nullptr) : m_out(std::addressof(out->m_base)), m_object_id(o) { /* .... */ } template<typename U> requires std::derived_from<U, ServiceImpl> Out(Out<SharedPointer<U>> out) : m_out(out.m_out), m_object_id(out.m_object_id) { /* ... */ } template<typename U> requires std::derived_from<U, ServiceImpl> Out(SharedPointer<U> *out, cmif::DomainObjectId *o = nullptr) : m_out(std::addressof(out->m_base)), m_object_id(o) { /* .... */ } void SetValue(SharedPointer<ServiceImpl> s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) { *m_out = std::move(s.m_base); if (new_object_id != cmif::InvalidDomainObjectId) { AMS_ABORT_UNLESS(m_object_id != nullptr); *m_object_id = new_object_id; } } template<typename U> requires std::derived_from<U, ServiceImpl> void SetValue(SharedPointer<U> s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) { *m_out = std::move(s.m_base); if (new_object_id != cmif::InvalidDomainObjectId) { AMS_ABORT_UNLESS(m_object_id != nullptr); *m_object_id = new_object_id; } } class DerefProxy { template<typename> friend class Out; private: Out &m_target; private: explicit DerefProxy(Out &t) : m_target(t) { /* ... */ } public: DerefProxy &operator=(SharedPointer<ServiceImpl> p) { m_target.SetValue(std::move(p)); return *this; } template<typename U> requires std::derived_from<U, ServiceImpl> DerefProxy &operator=(SharedPointer<U> p) { m_target.SetValue(std::move(p)); return *this; } }; DerefProxy operator *() { return DerefProxy(*this); } template<typename U> Out<SharedPointer<U>> DownCast() { return Out<SharedPointer<U>>(m_out, m_object_id); } }; } #if defined(ATMOSPHERE_OS_HORIZON) namespace ams::sf::impl { /* Machinery for filtering type lists. */ template<class, class> struct TupleCat; template<class... First, class... Second> struct TupleCat<std::tuple<First...>, std::tuple<Second...>> { using type = std::tuple<First..., Second...>; }; template<template <typename> typename Cond> struct TupleFilter { private: template<typename, typename> struct ImplType; template<typename Res> struct ImplType<Res, std::tuple<>> { using type = Res; }; template<typename Res, typename T, typename... Ts> struct ImplType<Res, std::tuple<T, Ts...>> { using type = typename std::conditional<Cond<T>::value, typename ImplType<typename TupleCat<Res, std::tuple<T>>::type, std::tuple<Ts...>>::type, typename ImplType<Res, std::tuple<Ts...>>::type >::type; }; public: template<typename T> using FilteredType = typename ImplType<std::tuple<>, T>::type; }; enum class ArgumentType { InData, OutData, Buffer, InHandle, OutHandle, InObject, OutObject, }; template<typename T> struct IsInObject : public std::false_type{}; template<typename T> struct IsInObject<sf::SharedPointer<T>> : public std::true_type { static_assert(std::is_base_of<sf::IServiceObject, T>::value, "Invalid IsInObject<sf::SharedPointer<T>>"); }; template<typename T> constexpr inline ArgumentType GetArgumentType = [] { static_assert(!std::same_as<T, sf::NativeHandle>); static_assert(!std::same_as<T, sf::Out<sf::NativeHandle>>); if constexpr (sf::IsBuffer<T>) { return ArgumentType::Buffer; } else if constexpr (IsInObject<T>::value) { return ArgumentType::InObject; } else if constexpr (std::is_base_of<sf::impl::OutObjectTag, T>::value) { return ArgumentType::OutObject; } else if constexpr (std::same_as<T, sf::CopyHandle> || std::same_as<T, sf::MoveHandle>) { return ArgumentType::InHandle; } else if constexpr (std::same_as<T, sf::OutCopyHandle> || std::same_as<T, sf::OutMoveHandle>) { return ArgumentType::OutHandle; } else if constexpr (std::is_base_of<sf::impl::OutBaseTag, T>::value) { return ArgumentType::OutData; } else if constexpr (std::is_trivial<T>::value && !std::is_pointer<T>::value) { return ArgumentType::InData; } else if constexpr (std::is_same<T, ::ams::Result>::value) { return ArgumentType::InData; } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } }(); template<typename T, ArgumentType ArgT> struct ArgumentTypeFilter : public std::bool_constant<GetArgumentType<T> == ArgT>{}; template<typename T, typename U> struct TypeEqualityFilter : public std::bool_constant<std::is_same<T, U>::value>{}; /* Argument type filters. */ template<typename T> using InDataFilter = ArgumentTypeFilter<T, ArgumentType::InData>; template<typename T> using OutDataFilter = ArgumentTypeFilter<T, ArgumentType::OutData>; template<typename T> using BufferFilter = ArgumentTypeFilter<T, ArgumentType::Buffer>; template<typename T> using InHandleFilter = ArgumentTypeFilter<T, ArgumentType::InHandle>; template<typename T> using OutHandleFilter = ArgumentTypeFilter<T, ArgumentType::OutHandle>; template<typename T> using InObjectFilter = ArgumentTypeFilter<T, ArgumentType::InObject>; template<typename T> using OutObjectFilter = ArgumentTypeFilter<T, ArgumentType::OutObject>; template<typename T> struct ProcessIdHolderFilter : public std::bool_constant<std::is_base_of<sf::impl::ProcessIdHolder, T>::value>{}; /* Handle kind filters. */ template<typename T> using InMoveHandleFilter = TypeEqualityFilter<T, sf::MoveHandle>; template<typename T> using InCopyHandleFilter = TypeEqualityFilter<T, sf::CopyHandle>; template<typename T> using OutMoveHandleFilter = TypeEqualityFilter<T, sf::Out<sf::MoveHandle>>; template<typename T> using OutCopyHandleFilter = TypeEqualityFilter<T, sf::Out<sf::CopyHandle>>; template<typename> struct BufferAttributeArrayGetter; template<typename ...Ts> struct BufferAttributeArrayGetter<std::tuple<Ts...>> { static constexpr std::array<u32, sizeof...(Ts)> value = { BufferAttributes<Ts>..., }; }; template<> struct BufferAttributeArrayGetter<std::tuple<>> { static constexpr std::array<u32, 0> value{}; }; template<auto Predicate> struct BufferAttributeCounter { template<size_t Size> static constexpr size_t GetCount(const std::array<u32, Size> &attributes_array) { size_t count = 0; for (size_t i = 0; i < Size; i++) { if (Predicate(attributes_array[i])) { count++; } } return count; } }; NX_CONSTEXPR size_t InHipcMapAliasBufferPredicate(const u32 attribute) { if ((attribute & SfBufferAttr_In) && !(attribute & SfBufferAttr_Out)) { return (attribute & SfBufferAttr_HipcMapAlias) || (attribute & SfBufferAttr_HipcAutoSelect); } else { return false; } } NX_CONSTEXPR size_t OutHipcMapAliasBufferPredicate(const u32 attribute) { if (!(attribute & SfBufferAttr_In) && (attribute & SfBufferAttr_Out)) { return (attribute & SfBufferAttr_HipcMapAlias) || (attribute & SfBufferAttr_HipcAutoSelect); } else { return false; } } NX_CONSTEXPR size_t InHipcPointerBufferPredicate(const u32 attribute) { if ((attribute & SfBufferAttr_In) && !(attribute & SfBufferAttr_Out)) { return (attribute & SfBufferAttr_HipcPointer) || (attribute & SfBufferAttr_HipcAutoSelect); } else { return false; } } NX_CONSTEXPR size_t OutHipcPointerBufferPredicate(const u32 attribute) { if (!(attribute & SfBufferAttr_In) && (attribute & SfBufferAttr_Out)) { return (attribute & SfBufferAttr_HipcPointer) || (attribute & SfBufferAttr_HipcAutoSelect); } else { return false; } } NX_CONSTEXPR size_t FixedSizeOutHipcPointerBufferPredicate(const u32 attribute) { return OutHipcPointerBufferPredicate(attribute) && (attribute & SfBufferAttr_FixedSize); } template<typename> struct RawDataOffsetCalculator; template<typename... Ts> struct RawDataOffsetCalculator<std::tuple<Ts...>> { private: template<typename T> struct LayoutHelper { static_assert(GetArgumentType<T> == ArgumentType::InData, "LayoutHelper InData"); static constexpr size_t Alignment = alignof(T); static constexpr size_t Size = sizeof(T); }; template<typename T> struct LayoutHelper<Out<T>> { static_assert(GetArgumentType<T> == ArgumentType::InData, "LayoutHelper OutData"); static constexpr size_t Alignment = alignof(T); static constexpr size_t Size = sizeof(T); }; static constexpr void StableSort(std::array<size_t, sizeof...(Ts)> &map, const std::array<size_t, sizeof...(Ts)> &values) { /* Use insertion sort, which is stable and optimal for small numbers of parameters. */ for (size_t i = 1; i < sizeof...(Ts); i++) { for (size_t j = i; j > 0 && values[map[j-1]] > values[map[j]]; j--) { std::swap(map[j], map[j-1]); } } } public: static constexpr std::array<size_t, sizeof...(Ts)+1> Offsets = [] { std::array<size_t, sizeof...(Ts)+1> offsets{}; offsets[0] = 0; if constexpr (sizeof...(Ts) > 0) { /* Get size, alignment for each type. */ const std::array<size_t, sizeof...(Ts)> sizes = { LayoutHelper<Ts>::Size... }; const std::array<size_t, sizeof...(Ts)> aligns = { LayoutHelper<Ts>::Alignment... }; /* We want to sort...by alignment. */ std::array<size_t, sizeof...(Ts)> map = {}; for (size_t i = 0; i < sizeof...(Ts); i++) { map[i] = i; } StableSort(map, aligns); /* Iterate over sorted sizes. */ size_t cur_offset = 0; for (size_t i : map) { cur_offset = util::AlignUp(cur_offset, aligns[i]); offsets[i] = cur_offset; cur_offset += sizes[i]; } offsets[sizeof...(Ts)] = cur_offset; } return offsets; }(); }; struct ArgumentSerializationInfo { /* Type used to select from below fields. */ ArgumentType arg_type; /* Raw data indexing. */ size_t in_raw_data_index; size_t out_raw_data_index; /* Buffer indexing. */ size_t buffer_index; size_t send_map_alias_index; size_t recv_map_alias_index; size_t send_pointer_index; size_t recv_pointer_index; size_t unfixed_recv_pointer_index; size_t fixed_size; /* Handle indexing. */ size_t in_move_handle_index; size_t in_copy_handle_index; size_t out_move_handle_index; size_t out_copy_handle_index; /* Object indexing. */ size_t in_object_index; size_t out_object_index; }; template<typename T> using DecayForCommandMetaArguments = typename std::conditional<(sf::IsLargeData<typename std::decay<T>::type> && !std::is_base_of<impl::OutBaseTag, typename std::decay<T>::type>::value), T, typename std::conditional<(std::same_as<T, sf::MoveHandle &&> || std::same_as<T, sf::CopyHandle &&>), typename std::decay<T>::type &, typename std::decay<T>::type>::type>::type; template<typename... Arguments> struct CommandMetaInfo { public: using ArgsTypeForInvoke = std::tuple<DecayForCommandMetaArguments<Arguments>...>; using ArgsType = std::tuple<typename std::decay<Arguments>::type...>; using InDatas = TupleFilter<InDataFilter>::FilteredType<ArgsType>; using OutDatas = TupleFilter<OutDataFilter>::FilteredType<ArgsType>; using Buffers = TupleFilter<BufferFilter>::FilteredType<ArgsType>; using InHandles = TupleFilter<InHandleFilter>::FilteredType<ArgsType>; using OutHandles = TupleFilter<OutHandleFilter>::FilteredType<ArgsType>; using InObjects = TupleFilter<InObjectFilter>::FilteredType<ArgsType>; using OutObjects = TupleFilter<OutObjectFilter>::FilteredType<ArgsType>; /* Not kept separate from InDatas when processing, for reasons. */ using InProcessIdHolders = TupleFilter<ProcessIdHolderFilter>::FilteredType<InDatas>; /* TODO: Support OutProcessIdHolders? */ static constexpr size_t NumInDatas = std::tuple_size<InDatas>::value; static constexpr size_t NumOutDatas = std::tuple_size<OutDatas>::value; static constexpr size_t NumBuffers = std::tuple_size<Buffers>::value; static constexpr size_t NumInHandles = std::tuple_size<InHandles>::value; static constexpr size_t NumOutHandles = std::tuple_size<OutHandles>::value; static constexpr size_t NumInObjects = std::tuple_size<InObjects>::value; static constexpr size_t NumOutObjects = std::tuple_size<OutObjects>::value; static constexpr size_t NumInProcessIdHolders = std::tuple_size<InProcessIdHolders>::value; static constexpr bool HasInProcessIdHolder = NumInProcessIdHolders >= 1; template<typename T> static constexpr bool IsInProcessIdHolder = GetArgumentType<T> == ArgumentType::InData && std::is_base_of<sf::impl::ProcessIdHolder, T>::value; template<size_t I> static constexpr bool IsInProcessIdHolderIndex = I < std::tuple_size<ArgsType>::value && IsInProcessIdHolder<typename std::tuple_element<I, ArgsType>::type>; static_assert(NumBuffers <= 8, "Methods must take in <= 8 Buffers"); static_assert(NumInHandles <= 8, "Methods must take in <= 8 Handles"); static_assert(NumOutHandles + NumOutObjects <= 8, "Methods must output <= 8 Handles"); /* Buffer marshalling. */ static constexpr std::array<u32, NumBuffers> BufferAttributes = BufferAttributeArrayGetter<Buffers>::value; static constexpr size_t NumInHipcMapAliasBuffers = BufferAttributeCounter<InHipcMapAliasBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumOutHipcMapAliasBuffers = BufferAttributeCounter<OutHipcMapAliasBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumInHipcPointerBuffers = BufferAttributeCounter<InHipcPointerBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumOutHipcPointerBuffers = BufferAttributeCounter<OutHipcPointerBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumFixedSizeOutHipcPointerBuffers = BufferAttributeCounter<FixedSizeOutHipcPointerBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumUnfixedSizeOutHipcPointerBuffers = NumOutHipcPointerBuffers - NumFixedSizeOutHipcPointerBuffers; /* In/Out data marshalling. */ static constexpr std::array<size_t, NumInDatas+1> InDataOffsets = RawDataOffsetCalculator<InDatas>::Offsets; static constexpr size_t InDataSize = util::AlignUp(InDataOffsets[NumInDatas], alignof(u16)); static constexpr std::array<size_t, NumOutDatas+1> OutDataOffsets = RawDataOffsetCalculator<OutDatas>::Offsets; static constexpr size_t UnalignedOutDataSize = OutDataOffsets[NumOutDatas]; static constexpr size_t OutDataSize = util::AlignUp(OutDataOffsets[NumOutDatas], alignof(u32)); static constexpr size_t OutDataAlign = [] { if constexpr (std::tuple_size<OutDatas>::value) { return alignof(typename std::tuple_element<0, OutDatas>::type); } return static_cast<size_t>(0); }(); /* Handle marshalling. */ static constexpr size_t NumInMoveHandles = std::tuple_size<TupleFilter<InMoveHandleFilter>::FilteredType<InHandles>>::value; static constexpr size_t NumInCopyHandles = std::tuple_size<TupleFilter<InCopyHandleFilter>::FilteredType<InHandles>>::value; static constexpr size_t NumOutMoveHandles = std::tuple_size<TupleFilter<OutMoveHandleFilter>::FilteredType<OutHandles>>::value; static constexpr size_t NumOutCopyHandles = std::tuple_size<TupleFilter<OutCopyHandleFilter>::FilteredType<OutHandles>>::value; static_assert(NumInMoveHandles + NumInCopyHandles == NumInHandles, "NumInMoveHandles + NumInCopyHandles == NumInHandles"); static_assert(NumOutMoveHandles + NumOutCopyHandles == NumOutHandles, "NumOutMoveHandles + NumOutCopyHandles == NumOutHandles"); /* Used by server message processor at runtime. */ static constexpr inline const cmif::ServerMessageRuntimeMetadata RuntimeMetadata = cmif::ServerMessageRuntimeMetadata{ .in_data_size = InDataSize, .unaligned_out_data_size = UnalignedOutDataSize, .in_headers_size = sizeof(CmifInHeader), .out_headers_size = sizeof(CmifOutHeader), .in_object_count = NumInObjects, .out_object_count = NumOutObjects, }; /* Construction of argument serialization structs. */ private: template<typename> struct ArgumentSerializationInfoConstructor; template<typename ...Ts> struct ArgumentSerializationInfoConstructor<std::tuple<Ts...>> { template<typename T> static constexpr ArgumentSerializationInfo ProcessUpdate(ArgumentSerializationInfo ¤t_info) { /* Save a copy of the current state to return. */ ArgumentSerializationInfo returned_info = current_info; /* Clear previous iteration's fixed size. */ returned_info.fixed_size = 0; current_info.fixed_size = 0; constexpr auto arg_type = GetArgumentType<T>; returned_info.arg_type = arg_type; if constexpr (arg_type == ArgumentType::InData) { /* New rawdata, so increment index. */ current_info.in_raw_data_index++; } else if constexpr (arg_type == ArgumentType::OutData) { /* New rawdata, so increment index. */ current_info.out_raw_data_index++; } else if constexpr (arg_type == ArgumentType::InHandle) { /* New InHandle, increment the appropriate index. */ if constexpr (std::is_same<T, sf::MoveHandle>::value) { current_info.in_move_handle_index++; } else if constexpr (std::is_same<T, sf::CopyHandle>::value) { current_info.in_copy_handle_index++; } else { static_assert(!std::is_same<T, T>::value, "Invalid InHandle kind"); } } else if constexpr (arg_type == ArgumentType::OutHandle) { /* New OutHandle, increment the appropriate index. */ if constexpr (std::is_same<T, sf::Out<sf::MoveHandle>>::value) { current_info.out_move_handle_index++; } else if constexpr (std::is_same<T, sf::Out<sf::CopyHandle>>::value) { current_info.out_copy_handle_index++; } else { static_assert(!std::is_same<T, T>::value, "Invalid OutHandle kind"); } } else if constexpr (arg_type == ArgumentType::InObject) { /* New InObject, increment the appropriate index. */ current_info.in_object_index++; } else if constexpr (arg_type == ArgumentType::OutObject) { /* New OutObject, increment the appropriate index. */ current_info.out_object_index++; } else if constexpr (arg_type == ArgumentType::Buffer) { /* New Buffer, increment the appropriate index. */ const auto attributes = BufferAttributes[current_info.buffer_index]; current_info.buffer_index++; if (attributes & SfBufferAttr_HipcMapAlias) { if (attributes & SfBufferAttr_In) { current_info.send_map_alias_index++; } else if (attributes & SfBufferAttr_Out) { current_info.recv_map_alias_index++; } } else if (attributes & SfBufferAttr_HipcPointer) { if (attributes & SfBufferAttr_In) { current_info.send_pointer_index++; } else if (attributes & SfBufferAttr_Out) { current_info.recv_pointer_index++; if (!(attributes & SfBufferAttr_FixedSize)) { current_info.unfixed_recv_pointer_index++; } else { returned_info.fixed_size = LargeDataSize<T>; } } } else if (attributes & SfBufferAttr_HipcAutoSelect) { if (attributes & SfBufferAttr_In) { current_info.send_map_alias_index++; current_info.send_pointer_index++; } else if (attributes & SfBufferAttr_Out) { current_info.recv_map_alias_index++; current_info.recv_pointer_index++; if (!(attributes & SfBufferAttr_FixedSize)) { current_info.unfixed_recv_pointer_index++; } else { returned_info.fixed_size = LargeDataSize<T>; } } } } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } return returned_info; } static constexpr std::array<ArgumentSerializationInfo, sizeof...(Ts)> ArgumentSerializationInfos = [] { ArgumentSerializationInfo current_info = {}; return std::array<ArgumentSerializationInfo, sizeof...(Ts)>{ ProcessUpdate<Ts>(current_info)... }; }(); }; public: static constexpr std::array<ArgumentSerializationInfo, std::tuple_size<ArgsType>::value> ArgumentSerializationInfos = ArgumentSerializationInfoConstructor<ArgsType>::ArgumentSerializationInfos; }; template<size_t _Size, size_t _Align> class OutRawHolder { public: static constexpr size_t Size = _Size; static constexpr size_t Align = _Align ? _Align : alignof(u8); private: alignas(Align) u8 m_data[Size]; public: constexpr OutRawHolder() : m_data() { /* ... */ } template<size_t Offset, size_t TypeSize> constexpr inline uintptr_t GetAddress() const { static_assert(Offset <= Size, "Offset <= Size"); static_assert(TypeSize <= Size, "TypeSize <= Size"); static_assert(Offset + TypeSize <= Size, "Offset + TypeSize <= Size"); return reinterpret_cast<uintptr_t>(std::addressof(m_data[Offset])); } constexpr inline void CopyTo(void *dst) const { if constexpr (Size > 0) { std::memcpy(dst, m_data, Size); } } }; template<size_t _NumMove, size_t _NumCopy> class InHandleHolder { public: static constexpr size_t NumMove = _NumMove; static constexpr size_t NumCopy = _NumCopy; private: MoveHandle m_move_handles[NumMove]; CopyHandle m_copy_handles[NumCopy]; public: constexpr InHandleHolder() : m_move_handles(), m_copy_handles() { /* ... */ } template<size_t Index> constexpr inline MoveHandle &SetMoveHandle(os::NativeHandle os_handle) { static_assert(Index < NumMove); m_move_handles[Index] = sf::NativeHandle(os_handle, true); return m_move_handles[Index]; } template<size_t Index> constexpr inline CopyHandle &SetCopyHandle(os::NativeHandle os_handle) { static_assert(Index < NumCopy); m_copy_handles[Index] = sf::NativeHandle(os_handle, true); return m_copy_handles[Index]; } }; template<size_t _NumMove, size_t _NumCopy> class OutHandleHolder { public: static constexpr size_t NumMove = _NumMove; static constexpr size_t NumCopy = _NumCopy; private: NativeHandle m_move_handles[NumMove]; NativeHandle m_copy_handles[NumCopy]; public: constexpr OutHandleHolder() : m_move_handles(), m_copy_handles() { /* ... */ } template<size_t Index> constexpr inline NativeHandle *GetMoveHandlePointer() { static_assert(Index < NumMove, "Index < NumMove"); return m_move_handles + Index; } template<size_t Index> constexpr inline NativeHandle *GetCopyHandlePointer() { static_assert(Index < NumCopy, "Index < NumCopy"); return m_copy_handles + Index; } constexpr inline void CopyTo(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, const size_t num_out_object_handles) { ctx.handles_to_close->num_handles = 0; #define _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { const auto handle = m_copy_handles[n].GetOsHandle(); response.copy_handles[n] = handle; if (m_copy_handles[n].IsManaged()) { ctx.handles_to_close->handles[ctx.handles_to_close->num_handles++] = handle; } m_copy_handles[n].Detach(); } } while (0) _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(2); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(3); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(4); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(5); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(6); _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(7); #undef _SF_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE #define _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(n) do { if constexpr (NumMove > n) { response.move_handles[n + num_out_object_handles] = m_move_handles[n].GetOsHandle(); m_move_handles[n].Detach(); } } while (0) _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(0); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(1); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(2); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(3); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(4); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(5); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(6); _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(7); #undef _SF_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE } }; template<size_t NumInObjects, size_t NumOutObjects> class InOutObjectHolder { private: std::array<cmif::ServiceObjectHolder, NumInObjects> m_in_object_holders; std::array<cmif::ServiceObjectHolder, NumOutObjects> m_out_object_holders; std::array<util::TypedStorage<SharedPointer<sf::IServiceObject>>, NumOutObjects> m_out_shared_pointers; std::array<cmif::DomainObjectId, NumOutObjects> m_out_object_ids; public: constexpr InOutObjectHolder() : m_in_object_holders(), m_out_object_holders() { #define _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(n) if constexpr (NumOutObjects > n) { m_out_object_ids[n] = cmif::InvalidDomainObjectId; } _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(0) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(1) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(2) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(3) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(4) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(5) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(6) _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID(7) #undef _SF_IN_OUT_HOLDER_INITIALIZE_OBJECT_ID } Result GetInObjects(const sf::cmif::ServerMessageProcessor *processor) { if constexpr (NumInObjects > 0) { R_TRY(processor->GetInObjects(m_in_object_holders.data())); } R_SUCCEED(); } template<typename ServiceImplTuple> constexpr inline Result ValidateInObjects() const { static_assert(std::tuple_size<ServiceImplTuple>::value == NumInObjects); #define _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(n) do { \ if constexpr (NumInObjects > n) { \ using SharedPointerType = typename std::tuple_element<n, ServiceImplTuple>::type; \ using ServiceImplType = typename SharedPointerType::Interface; \ R_UNLESS((m_in_object_holders[n].template IsServiceObjectValid<ServiceImplType>()), sf::cmif::ResultInvalidInObject()); \ } \ } while (0) _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(0); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(1); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(2); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(3); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(4); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(5); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(6); _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(7); #undef _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT R_SUCCEED(); } template<size_t Index, typename Interface> SharedPointer<Interface> *GetOutObjectSharedPointer() { static_assert(sizeof(SharedPointer<Interface>) == sizeof(SharedPointer<sf::IServiceObject>)); return static_cast<SharedPointer<Interface> *>(static_cast<void *>(GetPointer(m_out_shared_pointers[Index]))); } template<size_t Index, typename Interface> Out<SharedPointer<Interface>> GetOutObject() { auto sp = std::construct_at(GetOutObjectSharedPointer<Index, Interface>()); return Out<SharedPointer<Interface>>(sp, std::addressof(m_out_object_ids[Index])); } template<size_t Index, typename Interface> void SetOutObject() { m_out_object_holders[Index] = cmif::ServiceObjectHolder(std::move(*GetOutObjectSharedPointer<Index, Interface>())); } constexpr void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response) { if constexpr (NumOutObjects > 0) { ctx.processor->SetOutObjects(ctx, response, m_out_object_holders.data(), m_out_object_ids.data()); } } }; class HipcCommandProcessorCommon : public sf::cmif::ServerMessageProcessor { public: virtual void SetImplementationProcessor(sf::cmif::ServerMessageProcessor *) override final { /* ... */ } virtual void PrepareForErrorReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const cmif::ServerMessageRuntimeMetadata runtime_metadata) override final { const size_t raw_size = runtime_metadata.GetOutHeadersSize(); const auto response = hipcMakeRequestInline(ctx.out_message_buffer.GetPointer(), .type = CmifCommandType_Invalid, /* Really response */ .num_data_words = static_cast<u32>((util::AlignUp(raw_size, 0x4) + 0x10 /* padding */) / sizeof(u32)), ); out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), raw_size); } virtual Result GetInObjects(cmif::ServiceObjectHolder *in_objects) const override final { /* By default, InObjects aren't supported. */ AMS_UNUSED(in_objects); R_THROW(sf::ResultNotSupported()); } }; template<typename CommandMeta> struct HipcCommandProcessor : public HipcCommandProcessorCommon { public: virtual const cmif::ServerMessageRuntimeMetadata GetRuntimeMetadata() const override final { return CommandMeta::RuntimeMetadata; } virtual Result PrepareForProcess(const cmif::ServiceDispatchContext &ctx, const cmif::ServerMessageRuntimeMetadata runtime_metadata) const override final { const auto &meta = ctx.request.meta; bool is_request_valid = true; is_request_valid &= meta.send_pid == CommandMeta::HasInProcessIdHolder; is_request_valid &= meta.num_send_statics == CommandMeta::NumInHipcPointerBuffers; /* is_request_valid &= meta.num_recv_statics == CommandMeta::NumOutHipcPointerBuffers; */ is_request_valid &= meta.num_send_buffers == CommandMeta::NumInHipcMapAliasBuffers; is_request_valid &= meta.num_recv_buffers == CommandMeta::NumOutHipcMapAliasBuffers; is_request_valid &= meta.num_exch_buffers == 0; /* Exchange buffers aren't supported. */ is_request_valid &= meta.num_copy_handles == CommandMeta::NumInCopyHandles; is_request_valid &= meta.num_move_handles == CommandMeta::NumInMoveHandles; const size_t meta_raw_size = meta.num_data_words * sizeof(u32); const size_t command_raw_size = util::AlignUp(runtime_metadata.GetUnfixedOutPointerSizeOffset() + (CommandMeta::NumUnfixedSizeOutHipcPointerBuffers * sizeof(u16)), alignof(u32)); is_request_valid &= meta_raw_size >= command_raw_size; R_UNLESS(is_request_valid, sf::hipc::ResultInvalidCmifRequest()); R_SUCCEED(); } virtual HipcRequest PrepareForReply(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &out_raw_data, const cmif::ServerMessageRuntimeMetadata runtime_metadata) override final { const size_t raw_size = runtime_metadata.GetOutDataSize() + runtime_metadata.GetOutHeadersSize(); const auto response = hipcMakeRequestInline(ctx.out_message_buffer.GetPointer(), .type = CmifCommandType_Invalid, /* Really response */ .num_send_statics = CommandMeta::NumOutHipcPointerBuffers, .num_data_words = static_cast<u32>((util::AlignUp(raw_size, 0x4) + 0x10 /* padding */) / sizeof(u32)), .num_copy_handles = CommandMeta::NumOutCopyHandles, .num_move_handles = static_cast<u32>(CommandMeta::NumOutMoveHandles + runtime_metadata.GetOutObjectCount()), ); out_raw_data = cmif::PointerAndSize(util::AlignUp(reinterpret_cast<uintptr_t>(response.data_words), 0x10), raw_size); return response; } virtual void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response, cmif::ServiceObjectHolder *out_objects, cmif::DomainObjectId *ids) override final { AMS_UNUSED(ids); #define _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(n) do { if constexpr (CommandMeta::NumOutObjects > n) { SetOutObjectImpl<n>(response, ctx.manager, std::move(out_objects[n])); } } while (0) _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(0); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(1); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(2); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(3); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(4); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(5); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(6); _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL(7); #undef _SF_IMPL_PROCESSOR_SET_OUT_OBJECT_IMPL } /* Useful defines. */ using ArgsTypeForInvoke = typename CommandMeta::ArgsTypeForInvoke; using ArgsType = typename CommandMeta::ArgsType; using BufferArrayType = std::array<cmif::PointerAndSize, CommandMeta::NumBuffers>; using OutRawHolderType = OutRawHolder<CommandMeta::OutDataSize, CommandMeta::OutDataAlign>; using InHandleHolderType = InHandleHolder<CommandMeta::NumInMoveHandles, CommandMeta::NumInCopyHandles>; using OutHandleHolderType = OutHandleHolder<CommandMeta::NumOutMoveHandles, CommandMeta::NumOutCopyHandles>; using InOutObjectHolderType = InOutObjectHolder<CommandMeta::NumInObjects, CommandMeta::NumOutObjects>; /* Buffer processing. */ private: template<size_t Index> NX_CONSTEXPR void SetOutObjectImpl(const HipcRequest &response, hipc::ServerSessionManager *manager, cmif::ServiceObjectHolder &&object) { /* If no object, write os::InvalidNativeHandle. This is what official software does. */ if (!object) { response.move_handles[Index] = os::InvalidNativeHandle; return; } os::NativeHandle server_handle, client_handle; R_ABORT_UNLESS(sf::hipc::CreateSession(std::addressof(server_handle), std::addressof(client_handle))); R_ABORT_UNLESS(manager->RegisterSession(server_handle, std::move(object))); response.move_handles[Index] = client_handle; } template<u32 Attributes> NX_CONSTEXPR bool IsMapTransferModeValid(u32 mode) { static_assert(!((Attributes & SfBufferAttr_HipcMapTransferAllowsNonSecure) && (Attributes & SfBufferAttr_HipcMapTransferAllowsNonDevice)), "Invalid Attributes"); if constexpr (Attributes & SfBufferAttr_HipcMapTransferAllowsNonSecure) { return mode == HipcBufferMode_NonSecure; } else if constexpr (Attributes & SfBufferAttr_HipcMapTransferAllowsNonDevice) { return mode == HipcBufferMode_NonDevice; } else { return mode == HipcBufferMode_Normal; } } template<size_t BufferIndex> static constexpr inline size_t GetIndexFromBufferIndex = [] { for (size_t i = 0; i < CommandMeta::ArgumentSerializationInfos.size(); i++) { const auto Info = CommandMeta::ArgumentSerializationInfos[i]; if (Info.arg_type == ArgumentType::Buffer && Info.buffer_index == BufferIndex) { return i; } } return std::numeric_limits<size_t>::max(); }(); template<size_t BufferIndex, size_t Index = GetIndexFromBufferIndex<BufferIndex>> NX_CONSTEXPR void ProcessBufferImpl(const cmif::ServiceDispatchContext &ctx, cmif::PointerAndSize &buffer, bool &is_buffer_map_alias, bool &map_alias_buffers_valid, size_t &pointer_buffer_head, size_t &pointer_buffer_tail, const cmif::ServerMessageRuntimeMetadata runtime_metadata) { static_assert(Index != std::numeric_limits<size_t>::max(), "Invalid Index From Buffer Index"); constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; constexpr auto Attributes = CommandMeta::BufferAttributes[BufferIndex]; static_assert(BufferIndex == Info.buffer_index && Info.arg_type == ArgumentType::Buffer, "BufferIndex == Info.buffer_index && Info.arg_type == ArgumentType::Buffer"); if constexpr (Attributes & SfBufferAttr_HipcMapAlias) { is_buffer_map_alias = true; if constexpr (Attributes & SfBufferAttr_In) { const HipcBufferDescriptor *desc = std::addressof(ctx.request.data.send_buffers[Info.send_map_alias_index]); buffer = cmif::PointerAndSize(hipcGetBufferAddress(desc), hipcGetBufferSize(desc)); if (!IsMapTransferModeValid<Attributes>(static_cast<u32>(desc->mode))) { map_alias_buffers_valid = false; } } else if constexpr (Attributes & SfBufferAttr_Out) { const HipcBufferDescriptor *desc = std::addressof(ctx.request.data.recv_buffers[Info.recv_map_alias_index]); buffer = cmif::PointerAndSize(hipcGetBufferAddress(desc), hipcGetBufferSize(desc)); if (!IsMapTransferModeValid<Attributes>(static_cast<u32>(desc->mode))) { map_alias_buffers_valid = false; } } else { static_assert(Attributes != Attributes, "Invalid Buffer Attributes"); } } else if constexpr (Attributes & SfBufferAttr_HipcPointer) { is_buffer_map_alias = false; if constexpr (Attributes & SfBufferAttr_In) { const HipcStaticDescriptor *desc = std::addressof(ctx.request.data.send_statics[Info.send_pointer_index]); buffer = cmif::PointerAndSize(hipcGetStaticAddress(desc), hipcGetStaticSize(desc)); const size_t size = buffer.GetSize(); if (size) { pointer_buffer_tail = std::max(pointer_buffer_tail, buffer.GetAddress() + size); } } else if constexpr (Attributes & SfBufferAttr_Out) { if constexpr (Attributes & SfBufferAttr_FixedSize) { constexpr size_t size = Info.fixed_size; static_assert(size > 0, "FixedSize object must have non-zero size!"); pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10); buffer = cmif::PointerAndSize(pointer_buffer_head, size); } else { const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + runtime_metadata.GetUnfixedOutPointerSizeOffset()); const size_t size = static_cast<size_t>(recv_pointer_sizes[Info.unfixed_recv_pointer_index]); pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10); buffer = cmif::PointerAndSize(pointer_buffer_head, size); } } else { static_assert(Attributes != Attributes, "Invalid Buffer Attributes"); } } else if constexpr (Attributes & SfBufferAttr_HipcAutoSelect) { if constexpr (Attributes & SfBufferAttr_In) { const HipcBufferDescriptor *map_desc = std::addressof(ctx.request.data.send_buffers[Info.send_map_alias_index]); const HipcStaticDescriptor *ptr_desc = std::addressof(ctx.request.data.send_statics[Info.send_pointer_index]); is_buffer_map_alias = hipcGetBufferAddress(map_desc) != 0; if (is_buffer_map_alias) { buffer = cmif::PointerAndSize(hipcGetBufferAddress(map_desc), hipcGetBufferSize(map_desc)); if (!IsMapTransferModeValid<Attributes>(static_cast<u32>(map_desc->mode))) { map_alias_buffers_valid = false; } } else { buffer = cmif::PointerAndSize(hipcGetStaticAddress(ptr_desc), hipcGetStaticSize(ptr_desc)); const size_t size = buffer.GetSize(); if (size) { pointer_buffer_tail = std::max(pointer_buffer_tail, buffer.GetAddress() + size); } } } else if constexpr (Attributes & SfBufferAttr_Out) { const HipcBufferDescriptor *map_desc = std::addressof(ctx.request.data.recv_buffers[Info.recv_map_alias_index]); is_buffer_map_alias = hipcGetBufferAddress(map_desc) != 0; if (is_buffer_map_alias) { buffer = cmif::PointerAndSize(hipcGetBufferAddress(map_desc), hipcGetBufferSize(map_desc)); if (!IsMapTransferModeValid<Attributes>(static_cast<u32>(map_desc->mode))) { map_alias_buffers_valid = false; } } else { if constexpr (Attributes & SfBufferAttr_FixedSize) { constexpr size_t size = Info.fixed_size; static_assert(size > 0, "FixedSize object must have non-zero size!"); pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10); buffer = cmif::PointerAndSize(pointer_buffer_head, size); } else { const u16 *recv_pointer_sizes = reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(ctx.request.data.data_words) + runtime_metadata.GetUnfixedOutPointerSizeOffset()); const size_t size = static_cast<size_t>(recv_pointer_sizes[Info.unfixed_recv_pointer_index]); pointer_buffer_head = util::AlignDown(pointer_buffer_head - size, 0x10); buffer = cmif::PointerAndSize(pointer_buffer_head, size); } } } else { static_assert(Attributes != Attributes, "Invalid Buffer Attributes"); } } else { static_assert(Attributes != Attributes, "Invalid Buffer Attributes"); } } template<size_t BufferIndex, size_t Index = GetIndexFromBufferIndex<BufferIndex>> NX_CONSTEXPR void SetOutBufferImpl(const HipcRequest &response, const cmif::PointerAndSize &buffer, const bool is_buffer_map_alias) { static_assert(Index != std::numeric_limits<size_t>::max(), "Invalid Index From Buffer Index"); constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; constexpr auto Attributes = CommandMeta::BufferAttributes[BufferIndex]; static_assert(BufferIndex == Info.buffer_index && Info.arg_type == ArgumentType::Buffer, "BufferIndex == Info.buffer_index && Info.arg_type == ArgumentType::Buffer"); if constexpr (Attributes & SfBufferAttr_Out) { if constexpr (Attributes & SfBufferAttr_HipcPointer) { response.send_statics[Info.recv_pointer_index] = hipcMakeSendStatic(buffer.GetPointer(), buffer.GetSize(), Info.recv_pointer_index); } else if constexpr (Attributes & SfBufferAttr_HipcAutoSelect) { if (!is_buffer_map_alias) { response.send_statics[Info.recv_pointer_index] = hipcMakeSendStatic(buffer.GetPointer(), buffer.GetSize(), Info.recv_pointer_index); } else { response.send_statics[Info.recv_pointer_index] = hipcMakeSendStatic(nullptr, 0, Info.recv_pointer_index); } } } } public: NX_CONSTEXPR Result ProcessBuffers(const cmif::ServiceDispatchContext &ctx, BufferArrayType &buffers, std::array<bool, CommandMeta::NumBuffers> &is_buffer_map_alias, const cmif::ServerMessageRuntimeMetadata runtime_metadata) { bool map_alias_buffers_valid = true; size_t pointer_buffer_tail = ctx.pointer_buffer.GetAddress(); size_t pointer_buffer_head = pointer_buffer_tail + ctx.pointer_buffer.GetSize(); #define _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(n) do { if constexpr (CommandMeta::NumBuffers > n) { ProcessBufferImpl<n>(ctx, buffers[n], is_buffer_map_alias[n], map_alias_buffers_valid, pointer_buffer_head, pointer_buffer_tail, runtime_metadata); } } while (0) _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(0); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(1); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(2); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(3); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(4); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(5); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(6); _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL(7); #undef _SF_IMPL_PROCESSOR_PROCESS_BUFFER_IMPL R_UNLESS(map_alias_buffers_valid, sf::hipc::ResultInvalidCmifRequest()); if constexpr (CommandMeta::NumOutHipcPointerBuffers > 0) { R_UNLESS(pointer_buffer_tail <= pointer_buffer_head, sf::hipc::ResultPointerBufferTooSmall()); } R_SUCCEED(); } NX_CONSTEXPR void SetOutBuffers(const HipcRequest &response, const BufferArrayType &buffers, const std::array<bool, CommandMeta::NumBuffers> &is_buffer_map_alias) { #define _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(n) do { if constexpr (CommandMeta::NumBuffers > n) { SetOutBufferImpl<n>(response, buffers[n], is_buffer_map_alias[n]); } } while (0) _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(0); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(1); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(2); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(3); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(4); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(5); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(6); _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL(7); #undef _SF_IMPL_PROCESSOR_SET_OUT_BUFFER_IMPL } /* Argument deserialization. */ private: template<size_t Index, typename T = typename std::tuple_element<Index, ArgsType>::type> NX_CONSTEXPR typename std::tuple_element<Index, ArgsTypeForInvoke>::type DeserializeArgumentImpl(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const OutRawHolderType &out_raw_holder, const BufferArrayType &buffers, InHandleHolderType &in_handles_holder, OutHandleHolderType &out_handles_holder, InOutObjectHolderType &in_out_objects_holder) { constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; if constexpr (Info.arg_type == ArgumentType::InData) { /* New in rawdata. */ constexpr size_t Offset = CommandMeta::InDataOffsets[Info.in_raw_data_index]; if constexpr (!std::is_same<T, bool>::value) { return *reinterpret_cast<const T *>(in_raw_data.GetAddress() + Offset); } else { /* Special case bools. */ return *reinterpret_cast<const u8 *>(in_raw_data.GetAddress() + Offset) & 1; } } else if constexpr (Info.arg_type == ArgumentType::OutData) { /* New out rawdata. */ constexpr size_t Offset = CommandMeta::OutDataOffsets[Info.out_raw_data_index]; return T(out_raw_holder.template GetAddress<Offset, T::TypeSize>()); } else if constexpr (Info.arg_type == ArgumentType::InHandle) { /* New InHandle. */ using InvokeType = typename std::tuple_element<Index, ArgsTypeForInvoke>::type; if constexpr (std::is_same<T, sf::MoveHandle>::value) { static_assert(std::same_as<InvokeType, sf::MoveHandle &>); return in_handles_holder.template SetMoveHandle<Info.in_move_handle_index>(ctx.request.data.move_handles[Info.in_move_handle_index]); } else if constexpr (std::is_same<T, sf::CopyHandle>::value) { static_assert(std::same_as<InvokeType, sf::CopyHandle &>); return in_handles_holder.template SetCopyHandle<Info.in_copy_handle_index>(ctx.request.data.copy_handles[Info.in_copy_handle_index]); } else { static_assert(!std::is_same<T, T>::value, "Invalid InHandle kind"); } } else if constexpr (Info.arg_type == ArgumentType::OutHandle) { /* New OutHandle. */ if constexpr (std::is_same<T, sf::OutMoveHandle>::value) { return T(out_handles_holder.template GetMoveHandlePointer<Info.out_move_handle_index>()); } else if constexpr (std::is_same<T, sf::OutCopyHandle>::value) { return T(out_handles_holder.template GetCopyHandlePointer<Info.out_copy_handle_index>()); } else { static_assert(!std::is_same<T, T>::value, "Invalid OutHandle kind"); } } else if constexpr (Info.arg_type == ArgumentType::InObject) { /* New InObject. */ return in_out_objects_holder.template GetInObject<Info.in_object_index, typename T::Interface>(); } else if constexpr (Info.arg_type == ArgumentType::OutObject) { /* New OutObject. */ return in_out_objects_holder.template GetOutObject<Info.out_object_index, typename T::Interface>(); } else if constexpr (Info.arg_type == ArgumentType::Buffer) { /* Buffers were already processed earlier. */ if constexpr (sf::IsLargeData<T>) { /* Fake buffer. This is either InData or OutData, but serializing over buffers. */ constexpr auto Attributes = CommandMeta::BufferAttributes[Info.buffer_index]; if constexpr (Attributes & SfBufferAttr_In) { /* TODO: AMS_ABORT_UNLESS()? N does not bother. */ using InvokeType = typename std::tuple_element<Index, ArgsTypeForInvoke>::type; static_assert(std::same_as<InvokeType, const T &>); return *reinterpret_cast<const T *>(buffers[Info.buffer_index].GetAddress()); } else if constexpr (Attributes & SfBufferAttr_Out) { return T(buffers[Info.buffer_index]); } else { static_assert(!std::is_same<T, T>::value, "Invalid BufferAttributes for LargeData type."); } } else { /* Actual buffer! */ return T(buffers[Info.buffer_index]); } } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } } template<size_t... Is> NX_CONSTEXPR ArgsTypeForInvoke DeserializeArgumentsImpl(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const OutRawHolderType &out_raw_holder, const BufferArrayType &buffers, InHandleHolderType &in_handles_holder, OutHandleHolderType &out_handles_holder, InOutObjectHolderType &in_out_objects_holder, std::index_sequence<Is...>) { return ArgsTypeForInvoke { DeserializeArgumentImpl<Is>(ctx, in_raw_data, out_raw_holder, buffers, in_handles_holder, out_handles_holder, in_out_objects_holder)..., }; } public: NX_CONSTEXPR ArgsTypeForInvoke DeserializeArguments(const cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const OutRawHolderType &out_raw_holder, const BufferArrayType &buffers, InHandleHolderType &in_handles_holder, OutHandleHolderType &out_handles_holder, InOutObjectHolderType &in_out_objects_holder) { return DeserializeArgumentsImpl(ctx, in_raw_data, out_raw_holder, buffers, in_handles_holder, out_handles_holder, in_out_objects_holder, std::make_index_sequence<std::tuple_size<ArgsTypeForInvoke>::value>{}); } }; inline Result GetCmifOutHeaderPointer(CmifOutHeader **out_header_ptr, cmif::PointerAndSize &out_raw_data) { CmifOutHeader *header = static_cast<CmifOutHeader *>(out_raw_data.GetPointer()); R_UNLESS(out_raw_data.GetSize() >= sizeof(*header), sf::cmif::ResultInvalidHeaderSize()); out_raw_data = cmif::PointerAndSize(out_raw_data.GetAddress() + sizeof(*header), out_raw_data.GetSize() - sizeof(*header)); *out_header_ptr = header; R_SUCCEED(); } template<typename CommandMeta, typename... Arguments> constexpr Result InvokeServiceCommandImplCommon(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, Result (*invoke_impl)(sf::IServiceObject *, Arguments &&...)) { using ImplProcessorType = HipcCommandProcessor<CommandMeta>; using BufferArrayType = std::array<cmif::PointerAndSize, CommandMeta::NumBuffers>; using InHandleHolderType = InHandleHolder<CommandMeta::NumInMoveHandles, CommandMeta::NumInCopyHandles>; using OutHandleHolderType = OutHandleHolder<CommandMeta::NumOutMoveHandles, CommandMeta::NumOutCopyHandles>; using OutRawHolderType = OutRawHolder<CommandMeta::OutDataSize, CommandMeta::OutDataAlign>; using InOutObjectHolderType = InOutObjectHolder<CommandMeta::NumInObjects, CommandMeta::NumOutObjects>; /* Create a processor for us to work with. */ ImplProcessorType impl_processor; if (ctx.processor == nullptr) { /* In the non-domain case, this is our only processor. */ ctx.processor = std::addressof(impl_processor); } else { /* In the domain case, we already have a processor, so we should give it a pointer to our template implementation. */ ctx.processor->SetImplementationProcessor(std::addressof(impl_processor)); } /* Validate the metadata has the expected counts. */ const auto runtime_metadata = ctx.processor->GetRuntimeMetadata(); R_TRY(ctx.processor->PrepareForProcess(ctx, runtime_metadata)); /* Storage for output. */ BufferArrayType buffers; std::array<bool, CommandMeta::NumBuffers> is_buffer_map_alias = {}; OutRawHolderType out_raw_holder; OutHandleHolderType out_handles_holder; InOutObjectHolderType in_out_objects_holder; /* Process buffers. */ R_TRY(ImplProcessorType::ProcessBuffers(ctx, buffers, is_buffer_map_alias, runtime_metadata)); /* Process input/output objects. */ R_TRY(in_out_objects_holder.GetInObjects(ctx.processor)); R_TRY((in_out_objects_holder.template ValidateInObjects<typename CommandMeta::InObjects>())); /* Decoding/Invocation. */ { Result command_result; { InHandleHolderType in_handles_holder; typename CommandMeta::ArgsTypeForInvoke args_tuple = ImplProcessorType::DeserializeArguments(ctx, in_raw_data, out_raw_holder, buffers, in_handles_holder, out_handles_holder, in_out_objects_holder); /* Handle in process ID holder if relevant. */ if constexpr (CommandMeta::HasInProcessIdHolder) { /* TODO: More precise value than 32? */ static_assert(std::tuple_size<typename CommandMeta::ArgsTypeForInvoke>::value <= 32, "Commands must have <= 32 arguments"); const os::ProcessId process_id{ctx.request.pid}; #define _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(n) do { \ using ArgsTypeForInvoke = typename CommandMeta::ArgsTypeForInvoke; \ if constexpr (n < std::tuple_size<ArgsTypeForInvoke>::value) { \ if constexpr (CommandMeta::template IsInProcessIdHolderIndex<n>) { \ R_TRY(MarshalProcessId(std::get<n>(args_tuple), process_id)); \ } \ } \ } while (0) _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x00); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x01); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x02); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x03); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x04); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x05); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x06); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x07); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x08); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x09); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0a); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0b); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0c); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0d); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0e); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x0f); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x10); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x11); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x12); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x13); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x14); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x15); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x16); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x17); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x18); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x19); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1a); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1b); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1c); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1d); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1e); _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID(0x1f); #undef _SF_IMPL_PROCESSOR_MARSHAL_PROCESS_ID } using TrueArgumentsTuple = std::tuple<Arguments...>; sf::IServiceObject * const this_ptr = ctx.srv_obj; command_result = [this_ptr, invoke_impl, &args_tuple]<size_t ...Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { R_RETURN(invoke_impl(this_ptr, std::forward<typename std::tuple_element<Ix, TrueArgumentsTuple>::type>(std::get<Ix>(args_tuple))...)); }(std::make_index_sequence<std::tuple_size<typename CommandMeta::ArgsTypeForInvoke>::value>()); } if (R_FAILED(command_result)) { cmif::PointerAndSize out_raw_data; ctx.processor->PrepareForErrorReply(ctx, out_raw_data, runtime_metadata); R_TRY(GetCmifOutHeaderPointer(out_header_ptr, out_raw_data)); R_RETURN(command_result); } } /* Encode. */ cmif::PointerAndSize out_raw_data; const auto response = ctx.processor->PrepareForReply(ctx, out_raw_data, runtime_metadata); R_TRY(GetCmifOutHeaderPointer(out_header_ptr, out_raw_data)); /* Copy raw data output struct. */ R_UNLESS(out_raw_data.GetSize() >= OutRawHolderType::Size, sf::cmif::ResultInvalidOutRawSize()); out_raw_holder.CopyTo(out_raw_data.GetPointer()); /* Set output recvlist buffers. */ ImplProcessorType::SetOutBuffers(response, buffers, is_buffer_map_alias); /* Set out handles. */ out_handles_holder.CopyTo(ctx, response, runtime_metadata.GetOutObjectCount()); /* Set output objects. */ #define _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(n) do { \ if constexpr (n < CommandMeta::NumOutObjects) { \ in_out_objects_holder.template SetOutObject<n, typename std::tuple_element_t<n, typename CommandMeta::OutObjects>::Interface>(); \ } \ } while (0) _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(0); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(1); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(2); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(3); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(4); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(5); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(6); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(7); _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(8); #undef _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT in_out_objects_holder.SetOutObjects(ctx, response); R_SUCCEED(); } template<auto ServiceCommandImpl, typename Return, typename ClassType, typename... Arguments> constexpr Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { using CommandMeta = CommandMetaInfo<Arguments...>; static_assert(std::is_base_of<sf::IServiceObject, ClassType>::value, "InvokeServiceCommandImpl: Service Commands must be ServiceObject member functions"); constexpr bool ReturnsResult = std::is_same<Return, Result>::value; constexpr bool ReturnsVoid = std::is_same<Return, void>::value; static_assert(ReturnsResult || ReturnsVoid, "Service Commands must return Result or void."); R_RETURN((InvokeServiceCommandImplCommon<CommandMeta, Arguments...>(out_header_ptr, ctx, in_raw_data, +[](sf::IServiceObject *srv_obj, Arguments &&... args) -> Result { if constexpr (ReturnsResult) { R_RETURN((static_cast<ClassType *>(srv_obj)->*ServiceCommandImpl)(std::forward<Arguments>(args)...)); } else { (static_cast<ClassType *>(srv_obj)->*ServiceCommandImpl)(std::forward<Arguments>(args)...); R_SUCCEED(); } }))); } } #elif defined(ATMOSPHERE_OS_WINDOWS) namespace ams::sf::impl { template<auto ServiceCommandImpl, typename Return, typename ClassType, typename... Arguments> inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ AMS_UNUSED(out_header_ptr, ctx, in_raw_data); AMS_ABORT("HIPC serialization not currently supported on Windows."); } } #elif defined(ATMOSPHERE_OS_LINUX) namespace ams::sf::impl { template<auto ServiceCommandImpl, typename Return, typename ClassType, typename... Arguments> inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ AMS_UNUSED(out_header_ptr, ctx, in_raw_data); AMS_ABORT("HIPC serialization not currently supported on Linux."); } } #elif defined(ATMOSPHERE_OS_MACOS) namespace ams::sf::impl { template<auto ServiceCommandImpl, typename Return, typename ClassType, typename... Arguments> inline Result InvokeServiceCommandImpl(CmifOutHeader **out_header_ptr, cmif::ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ AMS_UNUSED(out_header_ptr, ctx, in_raw_data); AMS_ABORT("HIPC serialization not currently supported on macOS."); } } #else #error "Unknown OS for sf Command serialization." #endif namespace ams::sf::impl { template<hos::Version Low, hos::Version High, u32 CommandId, auto CommandImpl, typename Return, typename ClassType, typename... Arguments> consteval inline cmif::ServiceCommandMeta MakeServiceCommandMeta() { return { .hosver_low = Low, .hosver_high = High, .cmd_id = static_cast<u32>(CommandId), .handler = ::ams::sf::impl::InvokeServiceCommandImpl<CommandImpl, Return, ClassType, Arguments...>, }; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_template_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sf::impl { template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter, typename Root> class ImplTemplateBaseT; template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter> class ImplTemplateBase : public ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface> { private: using BaseImpl = ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface>; public: using BaseImpl::BaseImpl; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/impl/sf_service_object_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sf::impl { class ServiceObjectImplBase2 { private: std::atomic<u32> m_ref_count; protected: constexpr ServiceObjectImplBase2() : m_ref_count(1) { /* ... */ } void AddReferenceImpl() { const auto prev = m_ref_count.fetch_add(1); AMS_ABORT_UNLESS(prev < std::numeric_limits<u32>::max()); } bool ReleaseImpl() { const auto prev = m_ref_count.fetch_sub(1); AMS_ABORT_UNLESS(prev != 0); return prev == 1; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_allocation_policies.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sf { namespace impl { struct StatelessDummyAllocator; } template<typename A> class StatelessAllocationPolicy { public: static constexpr bool HasStatefulAllocator = false; using Allocator = impl::StatelessDummyAllocator; template<typename> using StatelessAllocator = A; template<typename> static void *AllocateAligned(size_t size, size_t align) { AMS_UNUSED(align); return A().Allocate(size); } template<typename> static void DeallocateAligned(void *ptr, size_t size, size_t align) { AMS_UNUSED(align); A().Deallocate(ptr, size); } }; template<template<typename> typename A> class StatelessTypedAllocationPolicy { public: static constexpr bool HasStatefulAllocator = false; using Allocator = impl::StatelessDummyAllocator; template<typename T> using StatelessAllocator = A<T>; template<typename T> static void *AllocateAligned(size_t size, size_t align) { AMS_UNUSED(align); return StatelessAllocator<T>().Allocate(size); } template<typename T> static void DeallocateAligned(void *ptr, size_t size, size_t align) { AMS_UNUSED(align); StatelessAllocator<T>().Deallocate(ptr, size); } }; template<typename A> class StatefulAllocationPolicy { public: static constexpr bool HasStatefulAllocator = true; using Allocator = A; static void *AllocateAligned(Allocator *allocator, size_t size, size_t align) { AMS_UNUSED(align); return allocator->Allocate(size); } static void DeallocateAligned(Allocator *allocator, void *ptr, size_t size, size_t align) { AMS_UNUSED(align); allocator->Deallocate(ptr, size); } }; template<typename T> concept IsStatefulPolicy = T::HasStatefulAllocator; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_buffer_tags.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once namespace ams::sf { /* Helper structs for serialization of buffers. */ struct LargeData{}; struct PrefersMapAliasTransferMode{}; struct PrefersPointerTransferMode{}; struct PrefersAutoSelectTransferMode{}; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_buffers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_out.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::sf { enum class BufferTransferMode { MapAlias, Pointer, AutoSelect, }; namespace impl { /* Buffer utilities. */ struct BufferBaseTag{}; template<BufferTransferMode TransferMode> constexpr inline u32 BufferTransferModeAttributes = [] { if constexpr (TransferMode == BufferTransferMode::MapAlias) { return SfBufferAttr_HipcMapAlias; } else if constexpr (TransferMode == BufferTransferMode::Pointer) { return SfBufferAttr_HipcPointer; } else if constexpr(TransferMode == BufferTransferMode::AutoSelect) { return SfBufferAttr_HipcAutoSelect; } else { static_assert(false, "Invalid BufferTransferMode"); } }(); } template<typename T> constexpr inline bool IsLargeData = std::is_base_of<sf::LargeData, T>::value; template<typename T> constexpr inline bool IsLargeData<Out<T>> = IsLargeData<T>; template<typename T> constexpr inline size_t LargeDataSize = sizeof(T); template<typename T> constexpr inline size_t LargeDataSize<Out<T>> = sizeof(T); template<typename T> constexpr inline BufferTransferMode PreferredTransferMode = [] { constexpr bool prefers_map_alias = std::is_base_of<PrefersMapAliasTransferMode, T>::value; constexpr bool prefers_pointer = std::is_base_of<PrefersPointerTransferMode, T>::value; constexpr bool prefers_auto_select = std::is_base_of<PrefersAutoSelectTransferMode, T>::value; if constexpr (prefers_map_alias) { static_assert(!prefers_pointer && !prefers_auto_select, "Type T must only prefer one transfer mode."); return BufferTransferMode::MapAlias; } else if constexpr (prefers_pointer) { static_assert(!prefers_map_alias && !prefers_auto_select, "Type T must only prefer one transfer mode."); return BufferTransferMode::Pointer; } else if constexpr (prefers_auto_select) { static_assert(!prefers_map_alias && !prefers_pointer, "Type T must only prefer one transfer mode."); return BufferTransferMode::AutoSelect; } else if constexpr (IsLargeData<T>) { return BufferTransferMode::Pointer; } else { return BufferTransferMode::MapAlias; } }(); template<typename T> constexpr inline BufferTransferMode PreferredTransferMode<Out<T>> = PreferredTransferMode<T>; namespace impl { class BufferBase : public BufferBaseTag { public: static constexpr u32 AdditionalAttributes = 0; private: const cmif::PointerAndSize m_pas; protected: constexpr uintptr_t GetAddressImpl() const { return m_pas.GetAddress(); } template<typename Entry> constexpr inline size_t GetSizeImpl() const { return m_pas.GetSize() / sizeof(Entry); } public: constexpr BufferBase() : m_pas() { /* ... */ } constexpr BufferBase(const cmif::PointerAndSize &pas) : m_pas(pas) { /* ... */ } constexpr BufferBase(uintptr_t ptr, size_t sz) : m_pas(ptr, sz) { /* ... */ } }; class InBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_In; public: constexpr InBufferBase() : BaseType() { /* ... */ } constexpr InBufferBase(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } }; class OutBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_Out; public: constexpr OutBufferBase() : BaseType() { /* ... */ } constexpr OutBufferBase(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } }; template<BufferTransferMode TMode, u32 ExtraAttributes = 0> class InBufferImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr InBufferImpl() : BaseType() { /* ... */ } constexpr InBufferImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } constexpr const u8 *GetPointer() const { return reinterpret_cast<const u8 *>(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl<u8>(); } }; template<BufferTransferMode TMode, u32 ExtraAttributes = 0> class OutBufferImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr OutBufferImpl() : BaseType() { /* ... */ } constexpr OutBufferImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } constexpr u8 *GetPointer() const { return reinterpret_cast<u8 *>(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl<u8>(); } }; template<typename T, BufferTransferMode TMode = PreferredTransferMode<T>> struct InArrayImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr InArrayImpl() : BaseType() { /* ... */ } constexpr InArrayImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr const T *GetPointer() const { return reinterpret_cast<const T *>(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl<T>(); } constexpr const T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit operator Span<const T>() const { return {this->GetPointer(), this->GetSize()}; } constexpr Span<const T> ToSpan() const { return {this->GetPointer(), this->GetSize()}; } }; template<typename T, BufferTransferMode TMode = PreferredTransferMode<T>> struct OutArrayImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr BufferTransferMode TransferMode = TMode; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr OutArrayImpl() : BaseType() { /* ... */ } constexpr OutArrayImpl(const cmif::PointerAndSize &pas) : BaseType(pas) { /* ... */ } OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ } constexpr T *GetPointer() const { return reinterpret_cast<T *>(this->GetAddressImpl()); } constexpr size_t GetSize() const { return this->GetSizeImpl<T>(); } constexpr T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit operator Span<T>() const { return {this->GetPointer(), this->GetSize()}; } constexpr Span<T> ToSpan() const { return {this->GetPointer(), this->GetSize()}; } }; } /* Buffer Types. */ using InBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias>; using InMapAliasBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias>; using InPointerBuffer = typename impl::InBufferImpl<BufferTransferMode::Pointer>; using InAutoSelectBuffer = typename impl::InBufferImpl<BufferTransferMode::AutoSelect>; using InNonSecureBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonSecure>; using InNonDeviceBuffer = typename impl::InBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonDevice>; using InNonSecureAutoSelectBuffer = typename impl::InBufferImpl<BufferTransferMode::AutoSelect, SfBufferAttr_HipcMapTransferAllowsNonSecure>; using OutBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias>; using OutMapAliasBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias>; using OutPointerBuffer = typename impl::OutBufferImpl<BufferTransferMode::Pointer>; using OutAutoSelectBuffer = typename impl::OutBufferImpl<BufferTransferMode::AutoSelect>; using OutNonSecureBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonSecure>; using OutNonDeviceBuffer = typename impl::OutBufferImpl<BufferTransferMode::MapAlias, SfBufferAttr_HipcMapTransferAllowsNonDevice>; using OutNonSecureAutoSelectBuffer = typename impl::OutBufferImpl<BufferTransferMode::AutoSelect, SfBufferAttr_HipcMapTransferAllowsNonSecure>; template<typename T> using InArray = typename impl::InArrayImpl<T>; template<typename T> using InMapAliasArray = typename impl::InArrayImpl<T, BufferTransferMode::MapAlias>; template<typename T> using InPointerArray = typename impl::InArrayImpl<T, BufferTransferMode::Pointer>; template<typename T> using InAutoSelectArray = typename impl::InArrayImpl<T, BufferTransferMode::AutoSelect>; template<typename T> using OutArray = typename impl::OutArrayImpl<T>; template<typename T> using OutMapAliasArray = typename impl::OutArrayImpl<T, BufferTransferMode::MapAlias>; template<typename T> using OutPointerArray = typename impl::OutArrayImpl<T, BufferTransferMode::Pointer>; template<typename T> using OutAutoSelectArray = typename impl::OutArrayImpl<T, BufferTransferMode::AutoSelect>; /* Attribute serialization structs. */ template<typename T> constexpr inline bool IsBuffer = [] { const bool is_buffer = std::is_base_of<impl::BufferBaseTag, T>::value; const bool is_large_data = IsLargeData<T>; static_assert(!(is_buffer && is_large_data), "Invalid sf::IsBuffer state"); return is_buffer || is_large_data; }(); template<typename T> constexpr inline u32 BufferAttributes = [] { static_assert(IsBuffer<T>, "BufferAttributes requires IsBuffer"); if constexpr (std::is_base_of<impl::BufferBaseTag, T>::value) { return impl::BufferTransferModeAttributes<T::TransferMode> | T::AdditionalAttributes; } else if constexpr (IsLargeData<T>) { u32 attr = SfBufferAttr_FixedSize | impl::BufferTransferModeAttributes<PreferredTransferMode<T>>; if constexpr (std::is_base_of<impl::OutBaseTag, T>::value) { attr |= SfBufferAttr_Out; } else { attr |= SfBufferAttr_In; } return attr; } else { static_assert(!std::is_same<T, T>::value, "Invalid BufferAttributes<T>"); } }(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ams.hpp> #include <stratosphere/os.hpp> #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/sf/sf_types.hpp> #include <stratosphere/sf/sf_mitm_config.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_default_allocation_policy.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> namespace ams::sf { namespace impl { void *DefaultAllocateImpl(size_t size, size_t align, size_t offset); void DefaultDeallocateImpl(void *ptr, size_t size, size_t align, size_t offset); template<typename T> class DefaultAllocationPolicyAllocator { private: struct Holder { MemoryResource *allocator; alignas(alignof(T)) std::byte storage[sizeof(T)]; }; public: void *Allocate(size_t size) { AMS_ASSERT(size == sizeof(T)); AMS_UNUSED(size); return DefaultAllocateImpl(sizeof(Holder), alignof(Holder), AMS_OFFSETOF(Holder, storage)); } void Deallocate(void *ptr, size_t size) { AMS_ASSERT(size == sizeof(T)); AMS_UNUSED(size); return DefaultDeallocateImpl(ptr, sizeof(Holder), alignof(Holder), AMS_OFFSETOF(Holder, storage)); } }; } using DefaultAllocationPolicy = StatelessTypedAllocationPolicy<impl::DefaultAllocationPolicyAllocator>; MemoryResource *GetGlobalDefaultMemoryResource(); MemoryResource *GetCurrentEffectiveMemoryResource(); MemoryResource *GetCurrentMemoryResource(); MemoryResource *GetNewDeleteMemoryResource(); MemoryResource *SetGlobalDefaultMemoryResource(MemoryResource *mr); MemoryResource *SetCurrentMemoryResource(MemoryResource *mr); class ScopedCurrentMemoryResourceSetter { NON_COPYABLE(ScopedCurrentMemoryResourceSetter); NON_MOVEABLE(ScopedCurrentMemoryResourceSetter); private: MemoryResource *m_prev; public: explicit ScopedCurrentMemoryResourceSetter(MemoryResource *mr); ~ScopedCurrentMemoryResourceSetter(); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_exp_heap_allocator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> namespace ams::sf { struct ExpHeapAllocator { using Policy = StatefulAllocationPolicy<ExpHeapAllocator>; lmem::HeapHandle _handle; os::SdkMutexType _mutex; void Attach(lmem::HeapHandle h) { this->_handle = h; os::InitializeSdkMutex(std::addressof(this->_mutex)); } void Detach() { this->_handle = {}; } void *Allocate(size_t size) { os::LockSdkMutex(std::addressof(this->_mutex)); auto ptr = lmem::AllocateFromExpHeap(this->_handle, size); os::UnlockSdkMutex(std::addressof(this->_mutex)); return ptr; } void Deallocate(void *ptr, size_t size) { AMS_UNUSED(size); os::LockSdkMutex(std::addressof(this->_mutex)); lmem::FreeToExpHeap(this->_handle, ptr); os::UnlockSdkMutex(std::addressof(this->_mutex)); } }; static_assert(util::is_pod<ExpHeapAllocator>::value); template<size_t Size, typename Tag = void> struct ExpHeapStaticAllocator { using Policy = StatelessAllocationPolicy<ExpHeapStaticAllocator<Size, Tag>>; struct Globals { ExpHeapAllocator allocator; alignas(0x10) std::byte buffer[Size == 0 ? 1 : Size]; }; static constinit inline Globals _globals = {}; static void Initialize(int option) { _globals.allocator.Attach(lmem::CreateExpHeap(std::addressof(_globals.buffer), Size, option)); } static void Initialize(lmem::HeapHandle handle) { _globals.allocator.Attach(handle); } static void *Allocate(size_t size) { return _globals.allocator.Allocate(size); } static void Deallocate(void *ptr, size_t size) { return _globals.allocator.Deallocate(ptr, size); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_fs_inline_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> namespace ams::os { struct ThreadType; } namespace ams::sf { u8 GetFsInlineContext(os::ThreadType *thread); u8 SetFsInlineContext(os::ThreadType *thread, u8 ctx); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_lmem_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/lmem.hpp> namespace ams::sf { class ExpHeapMemoryResource : public MemoryResource { private: lmem::HeapHandle m_handle; public: constexpr ExpHeapMemoryResource() : m_handle() { /* ... */ } constexpr explicit ExpHeapMemoryResource(lmem::HeapHandle h) : m_handle(h) { /* ... */ } void Attach(lmem::HeapHandle h) { AMS_ABORT_UNLESS(m_handle == lmem::HeapHandle()); m_handle = h; } lmem::HeapHandle GetHandle() const { return m_handle; } private: virtual void *AllocateImpl(size_t size, size_t alignment) override { return lmem::AllocateFromExpHeap(m_handle, size, static_cast<int>(alignment)); } virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override { AMS_UNUSED(size, alignment); return lmem::FreeToExpHeap(m_handle, buffer); } virtual bool IsEqualImpl(const MemoryResource &resource) const override { return this == std::addressof(resource); } }; class UnitHeapMemoryResource : public MemoryResource { private: lmem::HeapHandle m_handle; public: constexpr UnitHeapMemoryResource() : m_handle() { /* ... */ } constexpr explicit UnitHeapMemoryResource(lmem::HeapHandle h) : m_handle(h) { /* ... */ } void Attach(lmem::HeapHandle h) { AMS_ABORT_UNLESS(m_handle == lmem::HeapHandle()); m_handle = h; } lmem::HeapHandle GetHandle() const { return m_handle; } private: virtual void *AllocateImpl(size_t size, size_t alignment) override { AMS_ASSERT(size <= lmem::GetUnitHeapUnitSize(m_handle)); AMS_ASSERT(alignment <= static_cast<size_t>(lmem::GetUnitHeapAlignment(m_handle))); AMS_UNUSED(size, alignment); return lmem::AllocateFromUnitHeap(m_handle); } virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override { AMS_UNUSED(size, alignment); return lmem::FreeToUnitHeap(m_handle, buffer); } virtual bool IsEqualImpl(const MemoryResource &resource) const override { return this == std::addressof(resource); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_mem_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/mem.hpp> namespace ams::sf { class StandardAllocatorMemoryResource : public MemoryResource { private: mem::StandardAllocator *m_standard_allocator; public: explicit StandardAllocatorMemoryResource(mem::StandardAllocator *sa) : m_standard_allocator(sa) { /* ... */ } mem::StandardAllocator *GetAllocator() const { return m_standard_allocator; } private: virtual void *AllocateImpl(size_t size, size_t alignment) override { return m_standard_allocator->Allocate(size, alignment); } virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) override { AMS_UNUSED(size, alignment); return m_standard_allocator->Free(buffer); } virtual bool IsEqualImpl(const MemoryResource &resource) const override { return this == std::addressof(resource); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_memory_resource.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> namespace ams::sf { struct MemoryResourceAllocationPolicy { static constexpr bool HasStatefulAllocator = true; using Allocator = MemoryResource; static void *AllocateAligned(MemoryResource *mr, size_t size, size_t align) { return mr->allocate(size, align); } static void DeallocateAligned(MemoryResource *mr, void *ptr, size_t size, size_t align) { return mr->deallocate(ptr, size, align); } }; template<typename T> struct MemoryResourceStaticAllocator { static constinit inline MemoryResource *g_memory_resource = nullptr; static constexpr void Initialize(MemoryResource *mr) { g_memory_resource = mr; } struct Policy { static constexpr bool HasStatefulAllocator = false; using Allocator = MemoryResource; template<typename> using StatelessAllocator = Allocator; template<typename> static void *AllocateAligned(size_t size, size_t align) { return g_memory_resource->allocate(size, align); } template<typename> static void DeallocateAligned(void *ptr, size_t size, size_t align) { g_memory_resource->deallocate(ptr, size, align); } }; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_mitm_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #if defined(ATMOSPHERE_OS_HORIZON) #define AMS_SF_MITM_SUPPORTED 1 #else #define AMS_SF_MITM_SUPPORTED 0 #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_mitm_dispatch.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_mitm_config.hpp> #if AMS_SF_MITM_SUPPORTED #include <switch.h> #ifdef __cplusplus extern "C" { #endif typedef struct { Handle target_session; u32 context; SfBufferAttrs buffer_attrs; SfBuffer buffers[8]; bool in_send_pid; u32 in_num_objects; const Service* in_objects[8]; u32 in_num_handles; Handle in_handles[8]; u32 out_num_objects; Service* out_objects; SfOutHandleAttrs out_handle_attrs; Handle* out_handles; u64 override_pid; } SfMitmDispatchParams; NX_INLINE Result serviceMitmDispatchImpl( Service* s, u32 request_id, const void* in_data, u32 in_data_size, void* out_data, u32 out_data_size, SfMitmDispatchParams disp ) { // Make a copy of the service struct, so that the compiler can assume that it won't be modified by function calls. Service srv = *s; void* in = serviceMakeRequest(&srv, request_id, disp.context, in_data_size, disp.in_send_pid, disp.buffer_attrs, disp.buffers, disp.in_num_objects, disp.in_objects, disp.in_num_handles, disp.in_handles); if (in_data_size) __builtin_memcpy(in, in_data, in_data_size); if (disp.in_send_pid && disp.override_pid) { const u64 pid = (disp.override_pid & 0x0000FFFFFFFFFFFFul) | 0xFFFE000000000000ul; __builtin_memcpy((u8 *)armGetTls() + 0xC, &pid, sizeof(pid)); } Result rc = svcSendSyncRequest(disp.target_session == INVALID_HANDLE ? s->session : disp.target_session); if (R_SUCCEEDED(rc)) { void* out = NULL; rc = serviceParseResponse(&srv, out_data_size, &out, disp.out_num_objects, disp.out_objects, disp.out_handle_attrs, disp.out_handles); if (R_SUCCEEDED(rc) && out_data && out_data_size) __builtin_memcpy(out_data, out, out_data_size); } return rc; } #define serviceMitmDispatch(_s,_rid,...) \ serviceMitmDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfMitmDispatchParams){ __VA_ARGS__ }) #define serviceMitmDispatchIn(_s,_rid,_in,...) \ serviceMitmDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfMitmDispatchParams){ __VA_ARGS__ }) #define serviceMitmDispatchOut(_s,_rid,_out,...) \ serviceMitmDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfMitmDispatchParams){ __VA_ARGS__ }) #define serviceMitmDispatchInOut(_s,_rid,_in,_out,...) \ serviceMitmDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfMitmDispatchParams){ __VA_ARGS__ }) #ifdef __cplusplus } #endif #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_native_handle.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os/os_native_handle.hpp> #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_out.hpp> namespace ams::sf { class NativeHandle { protected: NON_COPYABLE(NativeHandle); private: os::NativeHandle m_handle; bool m_managed; public: constexpr NativeHandle() : m_handle(os::InvalidNativeHandle), m_managed(false) { /* ... */ } constexpr NativeHandle(os::NativeHandle handle, bool managed) : m_handle(handle), m_managed(managed) { /* ... */ } constexpr NativeHandle(NativeHandle &&rhs) : m_handle(rhs.m_handle), m_managed(rhs.m_managed) { rhs.m_managed = false; rhs.m_handle = os::InvalidNativeHandle; } constexpr NativeHandle &operator=(NativeHandle &&rhs) { NativeHandle(std::move(rhs)).swap(*this); return *this; } constexpr ~NativeHandle() { if (m_managed) { os::CloseNativeHandle(m_handle); } } constexpr void Detach() { m_managed = false; m_handle = os::InvalidNativeHandle; } constexpr void Swap(NativeHandle &rhs) { std::swap(m_handle, rhs.m_handle); std::swap(m_managed, rhs.m_managed); } constexpr ALWAYS_INLINE void swap(NativeHandle &rhs) { return Swap(rhs); } constexpr NativeHandle GetShared() const { return NativeHandle(m_handle, false); } constexpr os::NativeHandle GetOsHandle() const { return m_handle; } constexpr bool IsManaged() const { return m_managed; } constexpr void Reset() { NativeHandle().swap(*this); } }; class CopyHandle : public NativeHandle { public: using NativeHandle::NativeHandle; using NativeHandle::operator=; }; class MoveHandle : public NativeHandle { public: using NativeHandle::NativeHandle; using NativeHandle::operator=; }; constexpr ALWAYS_INLINE void swap(NativeHandle &lhs, NativeHandle &rhs) { lhs.swap(rhs); } template<> class Out<CopyHandle> { private: NativeHandle *m_ptr; public: Out(NativeHandle *p) : m_ptr(p) { /* ... */ } void SetValue(NativeHandle v) const { *m_ptr = std::move(v); } ALWAYS_INLINE void SetValue(os::NativeHandle os_handle, bool managed) const { return this->SetValue(NativeHandle(os_handle, managed)); } NativeHandle &operator*() const { return *m_ptr; } }; template<> class Out<MoveHandle> { private: NativeHandle *m_ptr; public: Out(NativeHandle *p) : m_ptr(p) { /* ... */ } void SetValue(NativeHandle v) const { *m_ptr = std::move(v); } ALWAYS_INLINE void SetValue(os::NativeHandle os_handle, bool managed) const { return this->SetValue(NativeHandle(os_handle, managed)); } NativeHandle &operator*() const { return *m_ptr; } }; using OutCopyHandle = Out<CopyHandle>; using OutMoveHandle = Out<MoveHandle>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_object_factory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/impl/sf_impl_template_base.hpp> #include <stratosphere/sf/sf_object_impl_factory.hpp> #include <stratosphere/sf/sf_memory_resource.hpp> #include <stratosphere/sf/sf_default_allocation_policy.hpp> namespace ams::sf { namespace impl { template<typename> struct IsSmartPointer : public std::false_type{}; template<typename T> struct IsSmartPointer<SharedPointer<T>> : public std::true_type{}; template<typename T> struct IsSmartPointer<std::shared_ptr<T>> : public std::true_type{}; template<typename T, typename D> struct IsSmartPointer<std::unique_ptr<T, D>> : public std::true_type{}; template<typename Impl> struct UnmanagedEmplaceImplHolderBaseGetter { using Type = Impl; }; template<typename Impl> requires (std::is_abstract<Impl>::value) struct UnmanagedEmplaceImplHolderBaseGetter<Impl> { class Impl2 : public Impl { public: using Impl::Impl; private: constexpr virtual void AddReference() override { /* ... */ } constexpr virtual void Release() override { /* ... */ } }; using Type = Impl2; }; template<typename Impl> class UnmanagedEmplacedImplHolder { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: using Impl2 = typename UnmanagedEmplaceImplHolderBaseGetter<Impl>::Type; static_assert(!std::is_abstract<Impl2>::value); private: Impl2 m_impl; private: template<typename... Args> constexpr explicit UnmanagedEmplacedImplHolder(Args &&... args) : m_impl(std::forward<Args>(args)...) { /* ... */ } public: static constexpr Impl *GetImplPointer(UnmanagedEmplacedImplHolder *holder) { return std::addressof(holder->m_impl); } }; template<typename Impl> class EmplacedImplHolder : private Impl { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: template<typename... Args> constexpr explicit EmplacedImplHolder(Args &&... args) : Impl(std::forward<Args>(args)...) { /* ... */ } public: static constexpr Impl *GetImplPointer(EmplacedImplHolder *holder) { return holder; } template<typename Interface> static constexpr Impl *GetEmplacedImplPointerImpl(const SharedPointer<Interface> &sp) { using Base = impl::ImplTemplateBase<Interface, Interface, EmplacedImplHolder, EmplacedImplHolder>; return static_cast<Base *>(sp.Get()); } }; template<typename Impl> requires (IsSmartPointer<Impl>::value) class EmplacedImplHolder<Impl> : private Impl { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: template<typename... Args> constexpr explicit EmplacedImplHolder(Args &&... args) : Impl(std::forward<Args>(args)...) { /* ... */ } public: static constexpr auto *GetImplPointer(EmplacedImplHolder *holder) { return static_cast<Impl *>(holder)->operator ->(); } template<typename Interface> static constexpr Impl *GetEmplacedImplPointerImpl(const SharedPointer<Interface> &sp) { using Base = impl::ImplTemplateBase<Interface, Interface, EmplacedImplHolder, EmplacedImplHolder>; return static_cast<Base *>(sp.Get()); } }; template<typename T> using SmartPointerHolder = EmplacedImplHolder<T>; template<typename T> class ManagedPointerHolder { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: T *m_p; private: constexpr explicit ManagedPointerHolder(T *p) : m_p(p) { /* ... */ } constexpr ~ManagedPointerHolder() { m_p->Release(); } static constexpr T *GetImplPointer(ManagedPointerHolder *holder) { return holder->m_p; } }; template<typename T> class UnmanagedPointerHolder { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: T *m_p; private: constexpr explicit UnmanagedPointerHolder(T *p) : m_p(p) { /* ... */ } static constexpr T *GetImplPointer(UnmanagedPointerHolder *holder) { return holder->m_p; } }; } template<typename Interface, typename Impl> class UnmanagedServiceObject final : public impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedEmplacedImplHolder<Impl>, impl::UnmanagedEmplacedImplHolder<Impl>> { private: using ImplBase = impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedEmplacedImplHolder<Impl>, impl::UnmanagedEmplacedImplHolder<Impl>>; public: using ImplBase::ImplBase; constexpr virtual void AddReference() override { /* ... */ } constexpr virtual void Release() override { /* ... */ } constexpr Impl &GetImpl() { return *impl::UnmanagedEmplacedImplHolder<Impl>::GetImplPointer(this); } constexpr SharedPointer<Interface> GetShared() { return SharedPointer<Interface>(this, false); } }; template<typename Interface, typename T> class UnmanagedServiceObjectByPointer final : public impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedPointerHolder<T>, impl::UnmanagedPointerHolder<T>> { private: using ImplBase = impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedPointerHolder<T>, impl::UnmanagedPointerHolder<T>>; public: constexpr explicit UnmanagedServiceObjectByPointer(T *ptr) : ImplBase(ptr) { /* ... */ } constexpr virtual void AddReference() override { /* ... */ } constexpr virtual void Release() override { /* ... */ } constexpr SharedPointer<Interface> GetShared() { return SharedPointer<Interface>(this, false); } }; template<typename Policy> class ObjectFactory; template<typename Interface, typename Impl> class EmplacedRef : public SharedPointer<Interface> { template<typename> friend class ObjectFactory; private: constexpr explicit EmplacedRef(Interface *ptr, bool incref) : SharedPointer<Interface>(ptr, incref) { /* ... */ } public: constexpr EmplacedRef() { /* ... */ } constexpr Impl &GetImpl() const { return *impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(*this); } }; template<typename Policy> requires (!IsStatefulPolicy<Policy>) class ObjectFactory<Policy> { private: template<typename Interface, typename Holder, typename T> static constexpr SharedPointer<Interface> CreateSharedForPointer(T t) { using Base = impl::ImplTemplateBase<Interface, Interface, Holder, Holder>; return SharedPointer<Interface>(ObjectImplFactory<Base, Policy>::Create(std::forward<T>(t)), false); } public: template<typename Interface, typename Impl, typename... Args> static constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Args &&... args) { using Base = impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>>; return EmplacedRef<Interface, Impl>(ObjectImplFactory<Base, Policy>::Create(std::forward<Args>(args)...), false); } template<typename T, typename... Args> static constexpr SharedPointer<T> CreateUserSharedObject(Args &&... args) { return SharedPointer<T>(ObjectImplFactory<T, Policy>::Create(std::forward<Args>(args)...), false); } template<typename Impl, typename Interface> static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) { return impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(sp); } template<typename Interface, typename Smart> static constexpr SharedPointer<Interface> CreateShared(Smart &&sp) { return CreateSharedForPointer<Interface, impl::SmartPointerHolder<typename std::decay<decltype(sp)>::type>>(std::forward<Smart>(sp)); } template<typename Interface, typename T> static constexpr SharedPointer<Interface> CreateShared(T *p) { return CreateSharedForPointer<Interface, impl::ManagedPointerHolder<T>>(p); } template<typename Interface, typename T> static constexpr SharedPointer<Interface> CreateSharedWithoutManagement(T *p) { return CreateSharedForPointer<Interface, impl::UnmanagedPointerHolder<T>>(p); } }; template<typename Policy> requires (IsStatefulPolicy<Policy>) class ObjectFactory<Policy> { public: using Allocator = typename Policy::Allocator; private: template<typename Interface, typename Holder, typename T> static constexpr SharedPointer<Interface> CreateSharedForPointer(Allocator *a, T t) { using Base = impl::ImplTemplateBase<Interface, Interface, Holder, Holder>; return SharedPointer<Interface>(ObjectImplFactory<Base, Policy>::Create(a, std::forward<T>(t)), false); } public: template<typename Interface, typename Impl, typename... Args> static constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Allocator *a, Args &&... args) { using Base = impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>>; return EmplacedRef<Interface, Impl>(ObjectImplFactory<Base, Policy>::Create(a, std::forward<Args>(args)...), false); } template<typename T, typename... Args> static constexpr SharedPointer<T> CreateUserSharedObject(Allocator *a, Args &&... args) { return SharedPointer<T>(ObjectImplFactory<T, Policy>::Create(a, std::forward<Args>(args)...), false); } template<typename Impl, typename Interface> static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) { return impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(sp); } template<typename Interface, typename Smart> static constexpr SharedPointer<Interface> CreateShared(Allocator *a, Smart &&sp) { return CreateSharedForPointer<Interface, impl::SmartPointerHolder<typename std::decay<decltype(sp)>::type>>(a, std::forward<Smart>(sp)); } template<typename Interface, typename T> static constexpr SharedPointer<Interface> CreateShared(Allocator *a, T *p) { return CreateSharedForPointer<Interface, impl::ManagedPointerHolder<T>>(a, p); } template<typename Interface, typename T> static constexpr SharedPointer<Interface> CreateSharedWithoutManagement(Allocator *a, T *p) { return CreateSharedForPointer<Interface, impl::UnmanagedPointerHolder<T>>(a, p); } }; template<typename Policy> class StatefulObjectFactory { public: using Allocator = typename Policy::Allocator; private: using StaticObjectFactory = ObjectFactory<Policy>; private: Allocator *m_allocator; public: constexpr explicit StatefulObjectFactory(Allocator *a) : m_allocator(a) { /* ... */ } template<typename Interface, typename Impl, typename... Args> constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Args &&... args) { return StaticObjectFactory::template CreateSharedEmplaced<Interface, Impl>(m_allocator, std::forward<Args>(args)...); } template<typename Impl, typename Interface> static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) { return StaticObjectFactory::template GetEmplacedImplPointer<Impl, Interface>(sp); } template<typename Interface, typename Smart> constexpr SharedPointer<Interface> CreateShared(Allocator *a, Smart &&sp) { AMS_UNUSED(a); return StaticObjectFactory::template CreateShared<Interface>(m_allocator, std::forward<Smart>(sp)); } template<typename Interface, typename T> constexpr SharedPointer<Interface> CreateShared(Allocator *a, T *p) { AMS_UNUSED(a); return StaticObjectFactory::template CreateShared<Interface>(m_allocator, p); } template<typename Interface, typename T> constexpr SharedPointer<Interface> CreateSharedWithoutManagement(Allocator *a, T *p) { AMS_UNUSED(a); return StaticObjectFactory::template CreateSharedWithoutManagement<Interface>(m_allocator, p); } }; using DefaultObjectFactory = ObjectFactory<DefaultAllocationPolicy>; using MemoryResourceObjectFactory = ObjectFactory<MemoryResourceAllocationPolicy>; template<typename Interface, typename Impl, typename... Args> inline EmplacedRef<Interface, Impl> CreateSharedObjectEmplaced(Args &&... args) { return DefaultObjectFactory::CreateSharedEmplaced<Interface, Impl>(std::forward<Args>(args)...); } template<typename Interface, typename Impl, typename... Args> inline EmplacedRef<Interface, Impl> CreateSharedObjectEmplaced(MemoryResource *mr, Args &&... args) { return MemoryResourceObjectFactory::CreateSharedEmplaced<Interface, Impl>(mr, std::forward<Args>(args)...); } template<typename Interface, typename Smart> inline SharedPointer<Interface> CreateSharedObject(Smart &&sp) { return DefaultObjectFactory::CreateShared<Interface, Smart>(std::forward<Smart>(sp)); } template<typename Interface, typename Smart> inline SharedPointer<Interface> CreateSharedObject(MemoryResource *mr, Smart &&sp) { return MemoryResourceObjectFactory::CreateShared<Interface, Smart>(mr, std::forward<Smart>(sp)); } template<typename Interface, typename T> inline SharedPointer<Interface> CreateSharedObject(T *ptr) { return DefaultObjectFactory::CreateShared<Interface, T>(std::move(ptr)); } template<typename Interface, typename T> inline SharedPointer<Interface> CreateSharedObjectWithoutManagement(T *ptr) { return DefaultObjectFactory::CreateSharedWithoutManagement<Interface, T>(std::move(ptr)); } template<typename Interface, typename T> inline SharedPointer<Interface> CreateSharedObjectWithoutManagement(MemoryResource *mr, T *ptr) { return DefaultObjectFactory::CreateSharedWithoutManagement<Interface, T>(mr, std::move(ptr)); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_object_impl_factory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> #include <stratosphere/sf/impl/sf_service_object_impl.hpp> namespace ams::sf { namespace impl { struct StatelessDummyAllocator{}; template<typename Base, typename Policy> class ObjectImplFactoryWithStatelessAllocator { public: class Object; using Allocator = StatelessDummyAllocator; using StatelessAllocator = typename Policy::template StatelessAllocator<Object>; class Object final : private ::ams::sf::impl::ServiceObjectImplBase2, public Base { NON_COPYABLE(Object); NON_MOVEABLE(Object); friend class ObjectImplFactoryWithStatelessAllocator; private: template<typename... Args> explicit Object(Args &&... args) : Base(std::forward<Args>(args)...) { /* ... */ } static void *operator new(size_t size) { return Policy::template AllocateAligned<Object>(size, alignof(Object)); } static void operator delete(void *ptr, size_t size) { return Policy::template DeallocateAligned<Object>(ptr, size, alignof(Object)); } static void *operator new(size_t size, Allocator *); static void operator delete(void *ptr, Allocator *); void DisposeImpl() { delete this; } public: void AddReference() { ServiceObjectImplBase2::AddReferenceImpl(); } void Release() { if (ServiceObjectImplBase2::ReleaseImpl()) { this->DisposeImpl(); } } Allocator *GetAllocator() const { return nullptr; } }; template<typename... Args> static Object *Create(Args &&... args) { return new Object(std::forward<Args>(args)...); } template<typename... Args> static Object *Create(Allocator *, Args &&... args) { return new Object(std::forward<Args>(args)...); } }; template<typename Base, typename Policy> class ObjectImplFactoryWithStatefulAllocator { public: using Allocator = typename Policy::Allocator; class Object final : private ::ams::sf::impl::ServiceObjectImplBase2, public Base { NON_COPYABLE(Object); NON_MOVEABLE(Object); friend class ObjectImplFactoryWithStatefulAllocator; private: Allocator *m_allocator; private: template<typename... Args> explicit Object(Args &&... args) : Base(std::forward<Args>(args)...) { /* ... */ } static void *operator new(size_t size); static void operator delete(void *ptr, size_t size) { AMS_UNUSED(ptr, size); } static void *operator new(size_t size, Allocator *a) { return Policy::AllocateAligned(a, size, alignof(Object)); } static void operator delete(void *ptr, Allocator *a) { return Policy::DeallocateAligned(a, ptr, sizeof(Object), alignof(Object)); } void DisposeImpl() { Allocator *a = this->GetAllocator(); std::destroy_at(this); operator delete(this, a); } public: void AddReference() { ServiceObjectImplBase2::AddReferenceImpl(); } void Release() { if (ServiceObjectImplBase2::ReleaseImpl()) { this->DisposeImpl(); } } Allocator *GetAllocator() const { return m_allocator; } }; template<typename... Args> static Object *Create(Allocator *a, Args &&... args) { auto *ptr = new (a) Object(std::forward<Args>(args)...); if (ptr != nullptr) { ptr->m_allocator = a; } return ptr; } }; } template<typename Base, typename Policy> class ObjectImplFactory; template<typename Base, typename Policy> requires (!IsStatefulPolicy<Policy>) class ObjectImplFactory<Base, Policy> : public impl::ObjectImplFactoryWithStatelessAllocator<Base, Policy>{}; template<typename Base, typename Policy> requires (IsStatefulPolicy<Policy>) class ObjectImplFactory<Base, Policy> : public impl::ObjectImplFactoryWithStatefulAllocator<Base, Policy>{}; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_out.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp> namespace ams::sf { namespace impl { struct OutBaseTag{}; } template<typename> struct IsOutForceEnabled : public std::false_type{}; template<> struct IsOutForceEnabled<::ams::Result> : public std::true_type{}; template<typename T> concept OutEnabled = (std::is_trivial<T>::value || IsOutForceEnabled<T>::value) && !std::is_pointer<T>::value; template<typename T> class Out : public impl::OutBaseTag { static_assert(OutEnabled<T>); public: static constexpr size_t TypeSize = sizeof(T); private: T *m_ptr; public: constexpr Out(uintptr_t p) : m_ptr(reinterpret_cast<T *>(p)) { /* ... */ } constexpr Out(T *p) : m_ptr(p) { /* ... */ } constexpr Out(const cmif::PointerAndSize &pas) : m_ptr(reinterpret_cast<T *>(pas.GetAddress())) { /* TODO: Is AMS_ABORT_UNLESS(pas.GetSize() >= sizeof(T)); necessary? */ } template<typename U> requires (std::integral<T> && std::is_enum<U>::value && std::same_as<typename std::underlying_type<U>::type, T>) constexpr Out(U *p) : m_ptr(reinterpret_cast<T *>(p)) { static_assert(sizeof(U) == sizeof(T)); static_assert(alignof(U) == alignof(T)); } void SetValue(const T& value) const { *m_ptr = value; } const T &GetValue() const { return *m_ptr; } T *GetPointer() const { return m_ptr; } /* Convenience operators. */ T &operator*() const { return *m_ptr; } T *operator->() const { return m_ptr; } }; template<typename T> class Out<T *> { static_assert(!std::is_same<T, T>::value, "Invalid sf::Out<T> (Raw Pointer)"); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_out.hpp> #include <stratosphere/sf/sf_shared_object.hpp> namespace ams::sf { class IServiceObject : public ISharedObject { public: virtual ~IServiceObject() { /* ... */ } }; template<typename T> concept IsServiceObject = std::derived_from<T, IServiceObject>; #if AMS_SF_MITM_SUPPORTED class IMitmServiceObject : public IServiceObject { public: virtual ~IMitmServiceObject() { /* ... */ } }; class MitmServiceImplBase { protected: std::shared_ptr<::Service> m_forward_service; sm::MitmProcessInfo m_client_info; public: MitmServiceImplBase(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : m_forward_service(std::move(s)), m_client_info(c) { /* ... */ } }; template<typename T> concept IsMitmServiceObject = IsServiceObject<T> && std::derived_from<T, IMitmServiceObject>; template<typename T> concept IsMitmServiceImpl = requires (std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) { { T(std::forward<std::shared_ptr<::Service>>(s), c) }; { T::ShouldMitm(c) } -> std::same_as<bool>; }; #else template<typename T> concept IsMitmServiceObject = false; #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_shared_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_mitm_config.hpp> #include <stratosphere/sf/sf_out.hpp> namespace ams::sf { class ISharedObject { NON_COPYABLE(ISharedObject); NON_MOVEABLE(ISharedObject); protected: constexpr ISharedObject() { /* ... */ } ~ISharedObject() { /* ... */ } public: constexpr virtual void AddReference() = 0; constexpr virtual void Release() = 0; }; namespace impl { class SharedPointerBase { private: ISharedObject *m_ptr; private: constexpr void AddReferenceImpl() const { if (m_ptr != nullptr) { m_ptr->AddReference(); } } constexpr void ReleaseImpl() const { if (m_ptr != nullptr) { m_ptr->Release(); } } public: constexpr SharedPointerBase() : m_ptr(nullptr) { /* ... */ } constexpr SharedPointerBase(ISharedObject *ptr, bool incref) : m_ptr(ptr) { if (incref) { this->AddReferenceImpl(); } } constexpr ~SharedPointerBase() { this->ReleaseImpl(); } constexpr SharedPointerBase(const SharedPointerBase &rhs) : m_ptr(rhs.m_ptr) { this->AddReferenceImpl(); } constexpr SharedPointerBase(SharedPointerBase &&rhs) : m_ptr(rhs.m_ptr) { rhs.m_ptr = nullptr; } constexpr SharedPointerBase &operator=(const SharedPointerBase &rhs) { SharedPointerBase tmp(rhs); tmp.swap(*this); return *this; } constexpr SharedPointerBase &operator=(SharedPointerBase &&rhs) { SharedPointerBase tmp(std::move(rhs)); tmp.swap(*this); return *this; } constexpr void swap(SharedPointerBase &rhs) { std::swap(m_ptr, rhs.m_ptr); } constexpr ISharedObject *Detach() { ISharedObject *ret = m_ptr; m_ptr = nullptr; return ret; } constexpr ISharedObject *Get() const { return m_ptr; } }; } template<typename I> class SharedPointer { template<typename> friend class ::ams::sf::SharedPointer; template<typename> friend class ::ams::sf::Out; public: using Interface = I; private: impl::SharedPointerBase m_base; public: constexpr SharedPointer() : m_base() { /* ... */ } constexpr SharedPointer(std::nullptr_t) : m_base() { /* ... */ } constexpr SharedPointer(Interface *ptr, bool incref) : m_base(static_cast<ISharedObject *>(ptr), incref) { /* ... */ } constexpr SharedPointer(const SharedPointer &rhs) : m_base(rhs.m_base) { /* ... */ } constexpr SharedPointer(SharedPointer &&rhs) : m_base(std::move(rhs.m_base)) { /* ... */ } template<typename U> requires std::derived_from<U, Interface> constexpr SharedPointer(const SharedPointer<U> &rhs) : m_base(rhs.m_base) { /* ... */ } template<typename U> requires std::derived_from<U, Interface> constexpr SharedPointer(SharedPointer<U> &&rhs) : m_base(std::move(rhs.m_base)) { /* ... */ } constexpr SharedPointer &operator=(std::nullptr_t) { SharedPointer().swap(*this); return *this; } constexpr SharedPointer &operator=(const SharedPointer &rhs) { SharedPointer tmp(rhs); tmp.swap(*this); return *this; } constexpr SharedPointer &operator=(SharedPointer &&rhs) { SharedPointer tmp(std::move(rhs)); tmp.swap(*this); return *this; } template<typename U> requires std::derived_from<U, Interface> constexpr SharedPointer &operator=(const SharedPointer<U> &rhs) { SharedPointer tmp(rhs); tmp.swap(*this); return *this; } template<typename U> requires std::derived_from<U, Interface> constexpr SharedPointer &operator=(SharedPointer<U> &&rhs) { SharedPointer tmp(std::move(rhs)); tmp.swap(*this); return *this; } constexpr void swap(SharedPointer &rhs) { m_base.swap(rhs.m_base); } constexpr Interface *Detach() { return static_cast<Interface *>(m_base.Detach()); } constexpr void Reset() { *this = nullptr; } constexpr Interface *Get() const { return static_cast<Interface *>(m_base.Get()); } constexpr Interface *operator->() const { AMS_ASSERT(this->Get() != nullptr); return this->Get(); } constexpr bool operator!() const { return this->Get() == nullptr; } constexpr bool operator==(std::nullptr_t) const { return this->Get() == nullptr; } constexpr bool operator!=(std::nullptr_t) const { return this->Get() != nullptr; } }; template<typename Interface> constexpr void Swap(SharedPointer<Interface> &lhs, SharedPointer<Interface> &rhs) { lhs.swap(rhs); } constexpr inline void ReleaseSharedObject(ISharedObject *ptr) { ptr->Release(); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_standard_allocation_policy.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_default_allocation_policy.hpp> namespace ams::sf { using StandardAllocationPolicy = DefaultAllocationPolicy; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_std_allocation_policy.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> namespace ams::sf { template<template<typename> class StdAllocator> class StdAllocationPolicy { public: static constexpr bool HasStatefulAllocator = false; using Allocator = impl::StatelessDummyAllocator; template<typename T> struct StatelessAllocator { static void *Allocate(size_t size) { return StdAllocator<T>().allocate(size / sizeof(T)); } static void Deallocate(void *ptr, size_t size) { StdAllocator<T>().deallocate(static_cast<T *>(ptr), size / sizeof(T)); } }; template<typename T> static void *AllocateAligned(size_t size, size_t align) { AMS_UNUSED(align); return StdAllocator<T>().allocate(size / sizeof(T)); } template<typename T> static void DeallocateAligned(void *ptr, size_t size, size_t align) { AMS_UNUSED(align); StdAllocator<T>().deallocate(static_cast<T *>(ptr), size / sizeof(T)); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf/sf_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #ifdef __cplusplus extern "C" { #endif #if defined(ATMOSPHERE_COMPILER_CLANG) #define AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR ALWAYS_INLINE #else #define AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR constexpr ALWAYS_INLINE #endif #define HIPC_AUTO_RECV_STATIC UINT8_MAX #define HIPC_RESPONSE_NO_PID UINT32_MAX typedef struct HipcMetadata { u32 type; u32 num_send_statics; u32 num_send_buffers; u32 num_recv_buffers; u32 num_exch_buffers; u32 num_data_words; u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC u32 send_pid; u32 num_copy_handles; u32 num_move_handles; } HipcMetadata; typedef struct HipcHeader { u32 type : 16; u32 num_send_statics : 4; u32 num_send_buffers : 4; u32 num_recv_buffers : 4; u32 num_exch_buffers : 4; u32 num_data_words : 10; u32 recv_static_mode : 4; u32 padding : 6; u32 recv_list_offset : 11; // Unused. u32 has_special_header : 1; } HipcHeader; typedef struct HipcSpecialHeader { u32 send_pid : 1; u32 num_copy_handles : 4; u32 num_move_handles : 4; u32 padding : 23; } HipcSpecialHeader; typedef struct HipcStaticDescriptor { u32 index : 6; u32 address_high : 6; u32 address_mid : 4; u32 size : 16; u32 address_low; } HipcStaticDescriptor; typedef struct HipcBufferDescriptor { u32 size_low; u32 address_low; u32 mode : 2; u32 address_high : 22; u32 size_high : 4; u32 address_mid : 4; } HipcBufferDescriptor; typedef struct HipcRecvListEntry { u32 address_low; u32 address_high : 16; u32 size : 16; } HipcRecvListEntry; typedef struct HipcRequest { HipcStaticDescriptor* send_statics; HipcBufferDescriptor* send_buffers; HipcBufferDescriptor* recv_buffers; HipcBufferDescriptor* exch_buffers; u32* data_words; HipcRecvListEntry* recv_list; u32* copy_handles; u32* move_handles; } HipcRequest; typedef struct HipcParsedRequest { HipcMetadata meta; HipcRequest data; u64 pid; } HipcParsedRequest; typedef struct HipcResponse { u64 pid; u32 num_statics; u32 num_data_words; u32 num_copy_handles; u32 num_move_handles; HipcStaticDescriptor* statics; u32* data_words; u32* copy_handles; u32* move_handles; } HipcResponse; typedef enum HipcBufferMode { HipcBufferMode_Normal = 0, HipcBufferMode_NonSecure = 1, HipcBufferMode_Invalid = 2, HipcBufferMode_NonDevice = 3, } HipcBufferMode; AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index) { return (HipcStaticDescriptor){ .index = index, .address_high = (u32)((uintptr_t)buffer >> 36), .address_mid = (u32)((uintptr_t)buffer >> 32), .size = (u32)size, .address_low = (u32)(uintptr_t)buffer, }; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode) { return (HipcBufferDescriptor){ .size_low = (u32)size, .address_low = (u32)(uintptr_t)buffer, .mode = mode, .address_high = (u32)((uintptr_t)buffer >> 36), .size_high = (u32)(size >> 32), .address_mid = (u32)((uintptr_t)buffer >> 32), }; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size) { return (HipcRecvListEntry){ .address_low = (u32)((uintptr_t)buffer), .address_high = (u32)((uintptr_t)buffer >> 32), .size = (u32)size, }; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc) { return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36)); } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc) { return desc->size; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc) { return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36)); } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc) { return desc->size_low | ((size_t)desc->size_high << 32); } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base) { // Copy handles u32* copy_handles = NULL; if (meta.num_copy_handles) { copy_handles = (u32*)base; base = copy_handles + meta.num_copy_handles; } // Move handles u32* move_handles = NULL; if (meta.num_move_handles) { move_handles = (u32*)base; base = move_handles + meta.num_move_handles; } // Send statics HipcStaticDescriptor* send_statics = NULL; if (meta.num_send_statics) { send_statics = (HipcStaticDescriptor*)base; base = send_statics + meta.num_send_statics; } // Send buffers HipcBufferDescriptor* send_buffers = NULL; if (meta.num_send_buffers) { send_buffers = (HipcBufferDescriptor*)base; base = send_buffers + meta.num_send_buffers; } // Recv buffers HipcBufferDescriptor* recv_buffers = NULL; if (meta.num_recv_buffers) { recv_buffers = (HipcBufferDescriptor*)base; base = recv_buffers + meta.num_recv_buffers; } // Exch buffers HipcBufferDescriptor* exch_buffers = NULL; if (meta.num_exch_buffers) { exch_buffers = (HipcBufferDescriptor*)base; base = exch_buffers + meta.num_exch_buffers; } // Data words u32* data_words = NULL; if (meta.num_data_words) { data_words = (u32*)base; base = data_words + meta.num_data_words; } // Recv list HipcRecvListEntry* recv_list = NULL; if (meta.num_recv_statics) recv_list = (HipcRecvListEntry*)base; return (HipcRequest){ .send_statics = send_statics, .send_buffers = send_buffers, .recv_buffers = recv_buffers, .exch_buffers = exch_buffers, .data_words = data_words, .recv_list = recv_list, .copy_handles = copy_handles, .move_handles = move_handles, }; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta) { // Write message header bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles; HipcHeader* hdr = (HipcHeader*)base; base = hdr+1; *hdr = (HipcHeader){ .type = meta.type, .num_send_statics = meta.num_send_statics, .num_send_buffers = meta.num_send_buffers, .num_recv_buffers = meta.num_recv_buffers, .num_exch_buffers = meta.num_exch_buffers, .num_data_words = meta.num_data_words, .recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u, .padding = 0, .recv_list_offset = 0, .has_special_header = has_special_header, }; // Write special header if (has_special_header) { HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base; base = sphdr+1; *sphdr = (HipcSpecialHeader){ .send_pid = meta.send_pid, .num_copy_handles = meta.num_copy_handles, .num_move_handles = meta.num_move_handles, }; if (meta.send_pid) base = (u8*)base + sizeof(u64); } // Calculate layout return hipcCalcRequestLayout(meta, base); } #define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ }) AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base) { // Parse message header HipcHeader hdr = {}; __builtin_memcpy(&hdr, base, sizeof(hdr)); base = (u8*)base + sizeof(hdr); u32 num_recv_statics = 0; u64 pid = 0; // Parse recv static mode if (hdr.recv_static_mode) { if (hdr.recv_static_mode == 2u) num_recv_statics = HIPC_AUTO_RECV_STATIC; else if (hdr.recv_static_mode > 2u) num_recv_statics = hdr.recv_static_mode - 2u; } // Parse special header HipcSpecialHeader sphdr = {}; if (hdr.has_special_header) { __builtin_memcpy(&sphdr, base, sizeof(sphdr)); base = (u8*)base + sizeof(sphdr); // Read PID descriptor if (sphdr.send_pid) { pid = *(u64*)base; base = (u8*)base + sizeof(u64); } } const HipcMetadata meta = { .type = hdr.type, .num_send_statics = hdr.num_send_statics, .num_send_buffers = hdr.num_send_buffers, .num_recv_buffers = hdr.num_recv_buffers, .num_exch_buffers = hdr.num_exch_buffers, .num_data_words = hdr.num_data_words, .num_recv_statics = num_recv_statics, .send_pid = sphdr.send_pid, .num_copy_handles = sphdr.num_copy_handles, .num_move_handles = sphdr.num_move_handles, }; return (HipcParsedRequest){ .meta = meta, .data = hipcCalcRequestLayout(meta, base), .pid = pid, }; } AMS_SF_HIPC_PARSE_IMPL_CONSTEXPR HipcResponse hipcParseResponse(void* base) { // Parse header HipcHeader hdr = {}; __builtin_memcpy(&hdr, base, sizeof(hdr)); base = (u8*)base + sizeof(hdr); // Initialize response HipcResponse response = {}; response.num_statics = hdr.num_send_statics; response.num_data_words = hdr.num_data_words; response.pid = HIPC_RESPONSE_NO_PID; // Parse special header if (hdr.has_special_header) { HipcSpecialHeader sphdr = {}; __builtin_memcpy(&sphdr, base, sizeof(sphdr)); base = (u8*)base + sizeof(sphdr); // Update response response.num_copy_handles = sphdr.num_copy_handles; response.num_move_handles = sphdr.num_move_handles; // Parse PID descriptor if (sphdr.send_pid) { response.pid = *(u64*)base; base = (u8*)base + sizeof(u64); } } // Copy handles response.copy_handles = (u32*)base; base = response.copy_handles + response.num_copy_handles; // Move handles response.move_handles = (u32*)base; base = response.move_handles + response.num_move_handles; // Send statics response.statics = (HipcStaticDescriptor*)base; base = response.statics + response.num_statics; // Data words response.data_words = (u32*)base; return response; } typedef enum CmifCommandType { CmifCommandType_Invalid = 0, CmifCommandType_LegacyRequest = 1, CmifCommandType_Close = 2, CmifCommandType_LegacyControl = 3, CmifCommandType_Request = 4, CmifCommandType_Control = 5, CmifCommandType_RequestWithContext = 6, CmifCommandType_ControlWithContext = 7, } CmifCommandType; typedef enum CmifDomainRequestType { CmifDomainRequestType_Invalid = 0, CmifDomainRequestType_SendMessage = 1, CmifDomainRequestType_Close = 2, } CmifDomainRequestType; typedef struct CmifInHeader { u32 magic; u32 version; u32 command_id; u32 token; } CmifInHeader; typedef struct CmifOutHeader { u32 magic; u32 version; Result result; u32 token; } CmifOutHeader; typedef struct CmifDomainInHeader { u8 type; u8 num_in_objects; u16 data_size; u32 object_id; u32 padding; u32 token; } CmifDomainInHeader; typedef struct CmifDomainOutHeader { u32 num_out_objects; u32 padding[3]; } CmifDomainOutHeader; typedef struct CmifRequestFormat { u32 object_id; u32 request_id; u32 context; u32 data_size; u32 server_pointer_size; u32 num_in_auto_buffers; u32 num_out_auto_buffers; u32 num_in_buffers; u32 num_out_buffers; u32 num_inout_buffers; u32 num_in_pointers; u32 num_out_pointers; u32 num_out_fixed_pointers; u32 num_objects; u32 num_handles; u32 send_pid; } CmifRequestFormat; typedef struct CmifRequest { HipcRequest hipc; void* data; u16* out_pointer_sizes; u32* objects; u32 server_pointer_size; u32 cur_in_ptr_id; } CmifRequest; typedef struct CmifResponse { void* data; u32* objects; u32* copy_handles; u32* move_handles; } CmifResponse; enum { SfBufferAttr_In = BIT(0), SfBufferAttr_Out = BIT(1), SfBufferAttr_HipcMapAlias = BIT(2), SfBufferAttr_HipcPointer = BIT(3), SfBufferAttr_FixedSize = BIT(4), SfBufferAttr_HipcAutoSelect = BIT(5), SfBufferAttr_HipcMapTransferAllowsNonSecure = BIT(6), SfBufferAttr_HipcMapTransferAllowsNonDevice = BIT(7), }; typedef struct SfBufferAttrs { u32 attr0; u32 attr1; u32 attr2; u32 attr3; u32 attr4; u32 attr5; u32 attr6; u32 attr7; } SfBufferAttrs; typedef struct SfBuffer { const void* ptr; size_t size; } SfBuffer; typedef enum SfOutHandleAttr { SfOutHandleAttr_None = 0, SfOutHandleAttr_HipcCopy = 1, SfOutHandleAttr_HipcMove = 2, } SfOutHandleAttr; typedef struct SfOutHandleAttrs { SfOutHandleAttr attr0; SfOutHandleAttr attr1; SfOutHandleAttr attr2; SfOutHandleAttr attr3; SfOutHandleAttr attr4; SfOutHandleAttr attr5; SfOutHandleAttr attr6; SfOutHandleAttr attr7; } SfOutHandleAttrs; #ifdef __cplusplus } #endif #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/sf.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sf/sf_common.hpp> #include <stratosphere/sf/sf_allocation_policies.hpp> #include <stratosphere/sf/sf_lmem_utility.hpp> #include <stratosphere/sf/sf_mem_utility.hpp> #include <stratosphere/sf/sf_exp_heap_allocator.hpp> #include <stratosphere/sf/sf_standard_allocation_policy.hpp> #include <stratosphere/sf/sf_std_allocation_policy.hpp> #include <stratosphere/sf/sf_shared_object.hpp> #include <stratosphere/sf/sf_service_object.hpp> #include <stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp> #include <stratosphere/sf/cmif/sf_cmif_inline_context.hpp> #include <stratosphere/sf/sf_fs_inline_context.hpp> #include <stratosphere/sf/sf_out.hpp> #include <stratosphere/sf/sf_native_handle.hpp> #include <stratosphere/sf/sf_buffers.hpp> #include <stratosphere/sf/impl/sf_impl_command_serialization.hpp> #include <stratosphere/sf/impl/sf_impl_autogen_interface_macros.hpp> #include <stratosphere/sf/impl/sf_impl_autogen_impl_macros.hpp> #include <stratosphere/sf/impl/sf_impl_template_base.hpp> #include <stratosphere/sf/sf_object_factory.hpp> #include <stratosphere/sf/hipc/sf_hipc_server_manager.hpp> #include <stratosphere/sf/sf_mitm_dispatch.h> ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/impl/sm_manager_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/tipc.hpp> #define AMS_SM_I_MANAGER_INTERFACE_INTERFACE_INFO(C, H) \ AMS_TIPC_METHOD_INFO(C, H, 0, Result, RegisterProcess, (os::ProcessId process_id, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac), (process_id, acid_sac, aci_sac)) \ AMS_TIPC_METHOD_INFO(C, H, 1, Result, UnregisterProcess, (os::ProcessId process_id), (process_id)) \ AMS_TIPC_METHOD_INFO(C, H, 65000, void, AtmosphereEndInitDefers, (), ()) \ AMS_TIPC_METHOD_INFO(C, H, 65001, void, AtmosphereHasMitm, (tipc::Out<bool> out, sm::ServiceName service), (out, service)) \ AMS_TIPC_METHOD_INFO(C, H, 65002, Result, AtmosphereRegisterProcess, (os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac), (process_id, program_id, override_status, acid_sac, aci_sac)) AMS_TIPC_DEFINE_INTERFACE(ams::sm::impl, IManagerInterface, AMS_SM_I_MANAGER_INTERFACE_INTERFACE_INFO) ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/impl/sm_user_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/tipc.hpp> #define AMS_SM_I_USER_INTERFACE_INTERFACE_INFO(C, H) \ AMS_TIPC_METHOD_INFO(C, H, 0, Result, RegisterClient, (const tipc::ClientProcessId client_process_id), (client_process_id)) \ AMS_TIPC_METHOD_INFO(C, H, 1, Result, GetServiceHandle, (tipc::OutMoveHandle out_h, sm::ServiceName service), (out_h, service)) \ AMS_TIPC_METHOD_INFO(C, H, 2, Result, RegisterService, (tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light), (out_h, service, max_sessions, is_light)) \ AMS_TIPC_METHOD_INFO(C, H, 3, Result, UnregisterService, (sm::ServiceName service), (service)) \ AMS_TIPC_METHOD_INFO(C, H, 4, Result, DetachClient, (const tipc::ClientProcessId client_process_id), (client_process_id)) \ AMS_TIPC_METHOD_INFO(C, H, 65000, Result, AtmosphereInstallMitm, (tipc::OutMoveHandle srv_h, tipc::OutMoveHandle qry_h, sm::ServiceName service), (srv_h, qry_h, service)) \ AMS_TIPC_METHOD_INFO(C, H, 65001, Result, AtmosphereUninstallMitm, (sm::ServiceName service), (service)) \ AMS_TIPC_METHOD_INFO(C, H, 65003, Result, AtmosphereAcknowledgeMitmSession, (tipc::Out<sm::MitmProcessInfo> client_info, tipc::OutMoveHandle fwd_h, sm::ServiceName service), (client_info, fwd_h, service)) \ AMS_TIPC_METHOD_INFO(C, H, 65004, Result, AtmosphereHasMitm, (tipc::Out<bool> out, sm::ServiceName service), (out, service)) \ AMS_TIPC_METHOD_INFO(C, H, 65005, Result, AtmosphereWaitMitm, (sm::ServiceName service), (service)) \ AMS_TIPC_METHOD_INFO(C, H, 65006, Result, AtmosphereDeclareFutureMitm, (sm::ServiceName service), (service)) \ AMS_TIPC_METHOD_INFO(C, H, 65007, Result, AtmosphereClearFutureMitm, (sm::ServiceName service), (service)) \ AMS_TIPC_METHOD_INFO(C, H, 65100, Result, AtmosphereHasService, (tipc::Out<bool> out, sm::ServiceName service), (out, service)) \ AMS_TIPC_METHOD_INFO(C, H, 65101, Result, AtmosphereWaitService, (sm::ServiceName service), (service)) AMS_TIPC_DEFINE_INTERFACE(ams::sm::impl, IUserInterface, AMS_SM_I_USER_INTERFACE_INTERFACE_INFO) ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/sm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sm/sm_types.hpp> namespace ams::sm { /* Initialization. */ Result Initialize(); Result Finalize(); /* Ordinary SM API. */ Result GetServiceHandle(os::NativeHandle *out, ServiceName name); Result RegisterService(os::NativeHandle *out, ServiceName name, size_t max_sessions, bool is_light); Result UnregisterService(ServiceName name); /* Atmosphere extensions. */ Result HasService(bool *out, ServiceName name); Result WaitService(ServiceName name); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/sm_manager_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/os.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/cfg/cfg_types.hpp> #include <stratosphere/sm/sm_types.hpp> namespace ams::sm::manager { /* Manager API. */ Result RegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus status, const void *acid, size_t acid_size, const void *aci, size_t aci_size); Result UnregisterProcess(os::ProcessId process_id); /* Atmosphere extensions. */ Result EndInitialDefers(); Result HasMitm(bool *out, ServiceName name); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/sm_mitm_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/sf/sf_mitm_config.hpp> #if AMS_SF_MITM_SUPPORTED namespace ams::sm::mitm { /* Mitm API. */ Result InstallMitm(os::NativeHandle *out_port, os::NativeHandle *out_query, ServiceName name); Result UninstallMitm(ServiceName name); Result DeclareFutureMitm(ServiceName name); Result ClearFutureMitm(ServiceName name); Result AcknowledgeSession(Service *out_service, MitmProcessInfo *out_info, ServiceName name); Result HasMitm(bool *out, ServiceName name); Result WaitMitm(ServiceName name); } #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm/sm_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ncm/ncm_ids.hpp> #include <stratosphere/cfg/cfg_types.hpp> namespace ams::sm { struct ServiceName { static constexpr size_t MaxLength = 8; char name[MaxLength]; static constexpr ServiceName Encode(const char *name, size_t name_size) { ServiceName out{}; for (size_t i = 0; i < MaxLength; i++) { if (i < name_size) { out.name[i] = name[i]; } else { out.name[i] = 0; } } return out; } static constexpr ServiceName Encode(util::string_view name) { return Encode(name.data(), name.size()); } }; static constexpr inline ServiceName InvalidServiceName = ServiceName::Encode(""); static_assert(alignof(ServiceName) == 1, "ServiceName definition!"); inline bool operator==(const ServiceName &lhs, const ServiceName &rhs) { return std::memcmp(std::addressof(lhs), std::addressof(rhs), sizeof(ServiceName)) == 0; } inline bool operator!=(const ServiceName &lhs, const ServiceName &rhs) { return !(lhs == rhs); } /* For Mitm extensions. */ struct MitmProcessInfo { os::ProcessId process_id; ncm::ProgramId program_id; cfg::OverrideStatus override_status; }; static_assert(std::is_trivial<MitmProcessInfo>::value && sizeof(MitmProcessInfo) == 0x20, "MitmProcessInfo definition!"); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sm.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/sm/sm_api.hpp> #include <stratosphere/sm/sm_mitm_api.hpp> #include <stratosphere/sm/sm_manager_api.hpp> #include <stratosphere/sm/impl/sm_user_interface.hpp> #include <stratosphere/sm/impl/sm_manager_interface.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/impl/socket_platform_types_translation.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/socket/socket_types.hpp> #include <stratosphere/socket/socket_options.hpp> #include <stratosphere/socket/socket_constants.hpp> #include <stratosphere/socket/socket_errno.hpp> namespace ams::socket::impl { #if defined(ATMOSPHERE_OS_WINDOWS) class PosixWinSockConverter { private: struct SocketData { SOCKET winsock; bool exempt; bool shutdown; constexpr SocketData() : winsock(static_cast<SOCKET>(INVALID_SOCKET)), exempt(), shutdown() { /* ... */ } }; private: os::SdkMutex m_mutex{}; SocketData m_data[MaxSocketsPerClient]{}; private: static constexpr int GetInitialIndex(SOCKET winsock) { /* The lower 2 bits of a winsock are always zero; Nintendo uses the upper bits as a hashmap index into m_data. */ return (winsock >> 2) % MaxSocketsPerClient; } public: constexpr PosixWinSockConverter() = default; s32 AcquirePosixHandle(SOCKET winsock, bool exempt = false); s32 GetShutdown(bool &shutdown, s32 posix); s32 GetSocketExempt(bool &exempt, s32 posix); SOCKET PosixToWinsockSocket(s32 posix); void ReleaseAllPosixHandles(); void ReleasePosixHandle(s32 posix); s32 SetShutdown(s32 posix, bool shutdown); s32 SetSocketExempt(s32 posix, bool exempt); s32 WinsockToPosixSocket(SOCKET winsock); }; s32 MapProtocolValue(Protocol protocol); Protocol MapProtocolValue(s32 protocol); s32 MapTypeValue(Type type); Type MapTypeValue(s32 type); s8 MapFamilyValue(Family family); Family MapFamilyValue(s8 family); s32 MapMsgFlagValue(MsgFlag flag); MsgFlag MapMsgFlagValue(s32 flag); u32 MapAddrInfoFlagValue(AddrInfoFlag flag); AddrInfoFlag MapAddrInfoFlagValue(u32 flag); u32 MapShutdownMethodValue(ShutdownMethod how); ShutdownMethod MapShutdownMethodValue(u32 how); u32 MapFcntlFlagValue(FcntlFlag flag); FcntlFlag MapFcntlFlagValue(u32 flag); s32 MapLevelValue(Level level); Level MapLevelValue(s32 level); s32 MapOptionValue(Level level, Option option); Option MapOptionValue(s32 level, s32 option); s32 MapErrnoValue(Errno error); Errno MapErrnoValue(s32 error); #endif #define AMS_SOCKET_IMPL_DECLARE_CONVERSION(AMS, PLATFORM) \ void CopyToPlatform(PLATFORM *dst, const AMS *src); \ void CopyFromPlatform(AMS *dst, const PLATFORM *src); AMS_SOCKET_IMPL_DECLARE_CONVERSION(SockAddrIn, sockaddr_in); AMS_SOCKET_IMPL_DECLARE_CONVERSION(TimeVal, timeval); AMS_SOCKET_IMPL_DECLARE_CONVERSION(Linger, linger); #undef AMS_SOCKET_IMPL_DECLARE_CONVERSION } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/socket/socket_types.hpp> #include <stratosphere/socket/socket_options.hpp> #include <stratosphere/socket/socket_errno.hpp> #include <stratosphere/socket/socket_config.hpp> namespace ams::socket { Errno GetLastError(); void SetLastError(Errno err); u32 InetHtonl(u32 host); u16 InetHtons(u16 host); u32 InetNtohl(u32 net); u16 InetNtohs(u16 net); Result Initialize(const Config &config); Result Finalize(); Result InitializeAllocatorForInternal(void *buffer, size_t size); ssize_t RecvFrom(s32 desc, void *buffer, size_t buffer_size, MsgFlag flags, SockAddr *out_address, SockLenT *out_addr_len); ssize_t Recv(s32 desc, void *buffer, size_t buffer_size, MsgFlag flags); ssize_t SendTo(s32 desc, const void *buffer, size_t buffer_size, MsgFlag flags, const SockAddr *address, SockLenT len); ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, MsgFlag flags); s32 Shutdown(s32 desc, ShutdownMethod how); s32 Socket(Family domain, Type type, Protocol protocol); s32 SocketExempt(Family domain, Type type, Protocol protocol); s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len); s32 Bind(s32 desc, const SockAddr *address, SockLenT len); s32 Connect(s32 desc, const SockAddr *address, SockLenT len); s32 GetSockName(s32 desc, SockAddr *out_address, SockLenT *out_addr_len); s32 SetSockOpt(s32 desc, Level level, Option option_name, const void *option_value, SockLenT option_size); s32 Listen(s32 desc, s32 backlog); s32 Close(s32 desc); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os.hpp> #include <stratosphere/socket/socket_constants.hpp> namespace ams::socket { constexpr ALWAYS_INLINE size_t AlignMss(size_t size) { return util::DivideUp(size, static_cast<size_t>(1500)) * static_cast<size_t>(1500); } class Config { private: u32 m_version; protected: bool m_system; bool m_smbp; void *m_memory_pool; size_t m_memory_pool_size; size_t m_allocator_pool_size; size_t m_tcp_initial_send_buffer_size; size_t m_tcp_initial_receive_buffer_size; size_t m_tcp_auto_send_buffer_size_max; size_t m_tcp_auto_receive_buffer_size_max; size_t m_udp_send_buffer_size; size_t m_udp_receive_buffer_size; int m_sb_efficiency; int m_concurrency_count_max; public: constexpr Config(void *mp, size_t mp_sz, size_t ap, size_t is, size_t ir, size_t as, size_t ar, size_t us, size_t ur, int sbe, int c) : m_version(LibraryVersion), m_system(false), m_smbp(false), m_memory_pool(mp), m_memory_pool_size(mp_sz), m_allocator_pool_size(ap), m_tcp_initial_send_buffer_size(is), m_tcp_initial_receive_buffer_size(ir), m_tcp_auto_send_buffer_size_max(as), m_tcp_auto_receive_buffer_size_max(ar), m_udp_send_buffer_size(us), m_udp_receive_buffer_size(ur), m_sb_efficiency(sbe), m_concurrency_count_max(c) { /* ... */ } constexpr u32 GetVersion() const { return m_version; } constexpr bool IsSystemClient() const { return m_system; } constexpr bool IsSmbpClient() const { return m_smbp; } constexpr void *GetMemoryPool() const { return m_memory_pool; } constexpr size_t GetMemoryPoolSize() const { return m_memory_pool_size; } constexpr size_t GetAllocatorPoolSize() const { return m_allocator_pool_size; } constexpr size_t GetTcpInitialSendBufferSize() const { return m_tcp_initial_send_buffer_size; } constexpr size_t GetTcpInitialReceiveBufferSize() const { return m_tcp_initial_receive_buffer_size; } constexpr size_t GetTcpAutoSendBufferSizeMax() const { return m_tcp_auto_send_buffer_size_max; } constexpr size_t GetTcpAutoReceiveBufferSizeMax() const { return m_tcp_auto_receive_buffer_size_max; } constexpr size_t GetUdpSendBufferSize() const { return m_udp_send_buffer_size; } constexpr size_t GetUdpReceiveBufferSize() const { return m_udp_receive_buffer_size; } constexpr int GetSocketBufferEfficiency() const { return m_sb_efficiency; } constexpr int GetConcurrencyCountMax() const { return m_concurrency_count_max; } constexpr void SetTcpInitialSendBufferSize(size_t size) { m_tcp_initial_send_buffer_size = size; } constexpr void SetTcpInitialReceiveBufferSize(size_t size) { m_tcp_initial_receive_buffer_size = size; } constexpr void SetTcpAutoSendBufferSizeMax(size_t size) { m_tcp_auto_send_buffer_size_max = size; } constexpr void SetTcpAutoReceiveBufferSizeMax(size_t size) { m_tcp_auto_receive_buffer_size_max = size; } constexpr void SetUdpSendBufferSize(size_t size) { m_udp_send_buffer_size = size; } constexpr void SetUdpReceiveBufferSize(size_t size) { m_udp_receive_buffer_size = size; } constexpr void SetSocketBufferEfficiency(int sb) { AMS_ABORT_UNLESS(1 <= sb && sb <= 8); m_sb_efficiency = sb; } constexpr void SetConcurrencyCountMax(int c) { m_concurrency_count_max = c; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_constants.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::socket { constexpr inline s32 InvalidSocket = -1; constexpr inline s32 SocketError = -1; constexpr inline u32 MaxSocketsPerClient = 0x80; constexpr inline auto DefaultTcpAutoBufferSizeMax = 192_KB; constexpr inline auto MinTransferMemorySize = (2 * DefaultTcpAutoBufferSizeMax + 128_KB); constexpr inline auto MinSocketAllocatorSize = 128_KB; constexpr inline auto MinSocketMemoryPoolSize = MinSocketAllocatorSize + MinTransferMemorySize; constexpr inline auto MinMemHeapAllocatorSize = 16_KB; constexpr inline auto MinimumSharedMbufPoolReservation = 4_KB; constexpr inline size_t MemoryPoolAlignment = 4_KB; constexpr inline auto ConcurrencyLimitMax = 14; /* TODO: Does this need to be 1 for sockets to work on lower firmware versions? */ /* Is this value actually used/checked by bsdsockets sysmodule? */ constexpr inline auto LibraryVersion = 7; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_errno.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::socket { enum class Errno : u32 { ESuccess = 0, EPerm = 1, ENoEnt = 2, ESrch = 3, EIntr = 4, EIo = 5, ENxIo = 6, E2Big = 7, ENoExec = 8, EBadf = 9, EChild = 10, EAgain = 11, EWouldBlock = EAgain, ENoMem = 12, EAcces = 13, EFault = 14, ENotBlk = 15, EBusy = 16, EExist = 17, EXDev = 18, ENoDev = 19, ENotDir = 20, EIsDir = 21, EInval = 22, ENFile = 23, EMFile = 24, ENotTy = 25, ETxtBsy = 26, EFBig = 27, ENoSpc = 28, ESPipe = 29, ERofs = 30, EMLink = 31, EPipe = 32, EDom = 33, ERange = 34, EDeadLk = 35, EDeadLock = EDeadLk, ENameTooLong = 36, ENoLck = 37, ENoSys = 38, ENotEmpty = 39, ELoop = 40, ENoMsg = 42, EIdrm = 43, EChrng = 44, EL2NSync = 45, EL3Hlt = 46, EL3Rst = 47, ELnrng = 48, EUnatch = 49, ENoCsi = 50, EL2Hlt = 51, EBade = 52, EBadr = 53, EXFull = 54, ENoAno = 55, EBadRqc = 56, EBadSsl = 57, EBFont = 59, ENoStr = 60, ENoData = 61, ETime = 62, ENoSr = 63, ENoNet = 64, ENoPkg = 65, ERemote = 66, ENoLink = 67, EAdv = 68, ESrmnt = 69, EComm = 70, EProto = 71, EMultiHop = 72, EDotDot = 73, EBadMsg = 74, EOverflow = 75, ENotUnuq = 76, EBadFd = 77, ERemChg = 78, ELibAcc = 79, ELibBad = 80, ELibScn = 81, ELibMax = 82, ELibExec = 83, EIlSeq = 84, ERestart = 85, EStrPipe = 86, EUsers = 87, ENotSock = 88, EDestAddrReq = 89, EMsgSize = 90, EPrototype = 91, ENoProtoOpt = 92, EProtoNoSupport = 93, ESocktNoSupport = 94, EOpNotSupp = 95, ENotSup = EOpNotSupp, EPfNoSupport = 96, EAfNoSupport = 97, EAddrInUse = 98, EAddrNotAvail = 99, ENetDown = 100, ENetUnreach = 101, ENetReset = 102, EConnAborted = 103, EConnReset = 104, ENoBufs = 105, EIsConn = 106, ENotConn = 107, EShutDown = 108, ETooManyRefs = 109, ETimedOut = 110, EConnRefused = 111, EHostDown = 112, EHostUnreach = 113, EAlready = 114, EInProgress = 115, EStale = 116, EUClean = 117, ENotNam = 118, ENAvail = 119, EIsNam = 120, ERemoteIo = 121, EDQuot = 122, ENoMedium = 123, EMediumType = 124, ECanceled = 125, ENoKey = 126, EKeyExpired = 127, EKeyRevoked = 128, EKeyRejected = 129, EOwnerDead = 130, ENotRecoverable = 131, ERfKill = 132, EHwPoison = 133, /* ... */ EProcLim = 156, }; enum class HErrno : s32 { Netdb_Internal = -1, Netdb_Success = 0, Host_Not_Found = 1, Try_Again = 2, No_Recovery = 3, No_Data = 4, No_Address = No_Data, }; enum class AiErrno : u32 { EAi_Success = 0, /* ... */ }; constexpr inline bool operator!(Errno e) { return e == Errno::ESuccess; } constexpr inline bool operator!(HErrno e) { return e == HErrno::Netdb_Success; } constexpr inline bool operator!(AiErrno e) { return e == AiErrno::EAi_Success; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_options.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::socket { enum class Level : s32 { Sol_Ip = 0, Sol_Icmp = 1, Sol_Tcp = 6, Sol_Udp = 17, Sol_UdpLite = 136, Sol_Socket = 0xFFFF, }; enum class Option : u32 { /* ==================================== */ So_Debug = (1 << 0), So_AcceptConn = (1 << 1), So_ReuseAddr = (1 << 2), So_KeepAlive = (1 << 3), So_DontRoute = (1 << 4), So_Broadcast = (1 << 5), So_UseLoopback = (1 << 6), So_Linger = (1 << 7), So_OobInline = (1 << 8), So_ReusePort = (1 << 9), So_SndBuf = (1 << 12) | 0x01, So_RcvBuf = (1 << 12) | 0x02, So_SndLoWat = (1 << 12) | 0x03, So_RcvLoWat = (1 << 12) | 0x04, So_SndTimeo = (1 << 12) | 0x05, So_RcvTimeo = (1 << 12) | 0x06, So_Error = (1 << 12) | 0x07, So_Type = (1 << 12) | 0x08, So_Label = (1 << 12) | 0x09, So_PeerLabel = (1 << 12) | 0x10, So_ListenQLimit = (1 << 12) | 0x11, So_ListenQLen = (1 << 12) | 0x12, So_ListenIncQLen = (1 << 12) | 0x13, So_SetFib = (1 << 12) | 0x14, So_User_Cookie = (1 << 12) | 0x15, So_Protocol = (1 << 12) | 0x16, So_Nn_Shutdown_Exempt = (1 << 16), So_Vendor = (1u << 31), So_Nn_Linger = So_Vendor | 0x01, /* ==================================== */ /* ==================================== */ Ip_Options = 1, Ip_HdrIncl = 2, Ip_Tos = 3, Ip_Ttl = 4, Ip_RecvOpts = 5, Ip_Multicast_If = 9, Ip_Multicast_Ttl = 10, Ip_Multicast_Loop = 11, Ip_Add_Membership = 12, Ip_Drop_Membership = 13, Ip_Multicast_Vif = 14, Ip_Rsvp_On = 15, Ip_Rsvp_Off = 16, Ip_Rsvp_Vif_On = 17, Ip_Rsvp_Vif_Off = 18, Ip_PortRange = 19, Ip_Faith = 22, Ip_OnesBcast = 23, Ip_BindAny = 24, Ip_RecvTtl = 65, Ip_MinTtl = 66, Ip_DontFrag = 67, Ip_RecvTos = 68, Ip_Add_Source_Membership = 70, Ip_Drop_Source_Membership = 71, Ip_Block_Source = 72, Ip_Unblock_Source = 73, /* ==================================== */ /* ==================================== */ Tcp_NoDelay = (1 << 0), Tcp_MaxSeg = (1 << 1), Tcp_NoPush = (1 << 2), Tcp_NoOpt = (1 << 3), Tcp_Md5Sig = (1 << 4), Tcp_Info = (1 << 5), Tcp_Congestion = (1 << 6), Tcp_KeepInit = (1 << 7), Tcp_KeepIdle = (1 << 8), Tcp_KeepIntvl = (1 << 9), Tcp_KeepCnt = (1 << 10), Tcp_Vendor = So_Vendor, /* ==================================== */ }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_system_config.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/socket/socket_config.hpp> namespace ams::socket { class SystemConfigDefault : public Config { public: static constexpr size_t DefaultTcpInitialSendBufferSize = 32_KB; static constexpr size_t DefaultTcpInitialReceiveBufferSize = 64_KB; static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 256_KB; static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 256_KB; static constexpr size_t DefaultUdpSendBufferSize = 9_KB; static constexpr size_t DefaultUdpReceiveBufferSize = 42240; static constexpr auto DefaultSocketBufferEfficiency = 2; static constexpr auto DefaultConcurrency = 8; static constexpr size_t DefaultAllocatorPoolSize = 128_KB; static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] { constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax)); constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax)); return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize); }(); static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] { constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize); constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize); return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize); }(); public: constexpr SystemConfigDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency) : Config(mp, mp_sz, ap, DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax, DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize, DefaultSocketBufferEfficiency, c) { /* Mark as system. */ m_system = true; } }; class SystemConfigLightDefault : public Config { public: static constexpr size_t DefaultTcpInitialSendBufferSize = 16_KB; static constexpr size_t DefaultTcpInitialReceiveBufferSize = 16_KB; static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 0_KB; static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 0_KB; static constexpr size_t DefaultUdpSendBufferSize = 9_KB; static constexpr size_t DefaultUdpReceiveBufferSize = 42240; static constexpr auto DefaultSocketBufferEfficiency = 2; static constexpr auto DefaultConcurrency = 2; static constexpr size_t DefaultAllocatorPoolSize = 64_KB; static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] { constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax)); constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax)); return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize); }(); static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] { constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize); constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize); return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize); }(); public: constexpr SystemConfigLightDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency) : Config(mp, mp_sz, ap, DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax, DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize, DefaultSocketBufferEfficiency, c) { /* Mark as system. */ m_system = true; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket/socket_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::socket { using InAddrT = u32; using InPortT = u16; using SockLenT = u32; using NfdsT = u64; using FdMask = u64; constexpr inline unsigned int FdSetSize = 0x400; template<u32 A, u32 B, u32 C, u32 D> constexpr inline InAddrT EncodeInAddr = util::ConvertToBigEndian(InAddrT{(A << 24) | (B << 16) | (C << 8) | (D << 0)}); constexpr inline InAddrT InAddr_Any = EncodeInAddr< 0, 0, 0, 0>; constexpr inline InAddrT InAddr_Broadcast = EncodeInAddr<255, 255, 255, 255>; constexpr inline InAddrT InAddr_None = EncodeInAddr<255, 255, 255, 255>; constexpr inline InAddrT InAddr_Loopback = EncodeInAddr<127, 0, 0, 1>; enum class Protocol : s32 { IpProto_Ip = 0, IpProto_Icmp = 1, IpProto_Tcp = 6, IpProto_Udp = 17, IpProto_None = 59, IpProto_UdpLite = 136, IpProto_Raw = 255, IpProto_Max = 256, }; enum class Type : u32 { Sock_Default = 0, Sock_Stream = 1, Sock_Dgram = 2, Sock_Raw = 3, Sock_SeqPacket = 5, Sock_NonBlock = 0x20000000, }; enum class Family : u8 { Af_Unspec = 0, Pf_Unspec = Af_Unspec, Af_Inet = 2, Pf_Inet = Af_Inet, Af_Route = 17, Pf_Route = Af_Route, Af_Link = 18, Pf_Link = Af_Link, Af_Inet6 = 28, Pf_Inet6 = Af_Inet6, Af_Max = 42, Pf_Max = Af_Max }; enum class MsgFlag : s32 { Msg_None = (0 << 0), Msg_Oob = (1 << 0), Msg_Peek = (1 << 1), Msg_DontRoute = (1 << 2), /* ... */ Msg_Trunc = (1 << 4), Msg_CTrunc = (1 << 5), Msg_WaitAll = (1 << 6), Msg_DontWait = (1 << 7), /* ... */ }; enum class FcntlCommand : u32 { F_GetFl = 3, F_SetFl = 4, }; enum class FcntlFlag : u32 { None = (0 << 0), O_NonBlock = (1 << 11), }; enum class ShutdownMethod : u32 { Shut_Rd = 0, Shut_Wr = 1, Shut_RdWr = 2, }; struct HostEnt { char *h_name; char **h_aliases; Family h_addrtype; int h_length; char **h_addr_list; }; struct InAddr { InAddrT s_addr; }; enum class AddrInfoFlag : u32 { Ai_None = (0 << 0), Ai_Passive = (1 << 0), Ai_CanonName = (1 << 1), Ai_NumericHost = (1 << 2), Ai_NumericServ = (1 << 3), Ai_AddrConfig = (1 << 10), }; struct SockAddr { u8 sa_len; Family sa_family; char sa_data[14]; }; struct SockAddrIn { u8 sin_len; Family sin_family; InPortT sin_port; InAddr sin_addr; u8 sin_zero[8]; }; static_assert(sizeof(SockAddr) == sizeof(SockAddrIn)); struct AddrInfo { AddrInfoFlag ai_flags; Family ai_family; Type ai_socktype; Protocol ai_protocol; SockLenT ai_addrlen; SockAddr *ai_addr; char *ai_canonname; AddrInfo *ai_next; }; struct TimeVal { long tv_sec; long tv_usec; }; struct Linger { int l_onoff; int l_linger; }; #define AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(__ENUM__) \ constexpr inline __ENUM__ operator | (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) | static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \ constexpr inline __ENUM__ operator |=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs | rhs; } \ constexpr inline __ENUM__ operator & (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) & static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \ constexpr inline __ENUM__ operator &=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs & rhs; } \ constexpr inline __ENUM__ operator ^ (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) ^ static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \ constexpr inline __ENUM__ operator ^=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs ^ rhs; } \ constexpr inline __ENUM__ operator ~ (__ENUM__ e) { return static_cast<__ENUM__>(~static_cast<std::underlying_type_t<__ENUM__>>(e)); } AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(Type) AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(AddrInfoFlag) AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(MsgFlag) AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(FcntlFlag) #undef AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS } ================================================ FILE: libraries/libstratosphere/include/stratosphere/socket.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #if !defined(ATMOSPHERE_OS_WINDOWS) #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #endif #include <stratosphere/socket/socket_types.hpp> #include <stratosphere/socket/socket_options.hpp> #include <stratosphere/socket/socket_errno.hpp> #include <stratosphere/socket/socket_constants.hpp> #include <stratosphere/socket/socket_config.hpp> #include <stratosphere/socket/socket_system_config.hpp> #include <stratosphere/socket/socket_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_api_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/spl/spl_types.hpp> namespace ams::spl::impl { constexpr inline s32 AesKeySlotMin = 16; constexpr inline s32 AesKeySlotCount = 9; constexpr inline s32 AesKeySlotMax = AesKeySlotMin + AesKeySlotCount - 1; /* Initialization. */ void Initialize(); /* General. */ Result GetConfig(u64 *out, spl::ConfigItem key); Result ModularExponentiate(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size); Result SetConfig(spl::ConfigItem key, u64 value); Result GenerateRandomBytes(void *out, size_t size); Result IsDevelopment(bool *out); Result SetBootReason(BootReasonValue boot_reason); Result GetBootReason(BootReasonValue *out); ALWAYS_INLINE bool GetConfigBool(spl::ConfigItem key) { u64 v; R_ABORT_UNLESS(::ams::spl::impl::GetConfig(std::addressof(v), key)); return v != 0; } /* Crypto. */ Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option); Result LoadAesKey(s32 keyslot, const AccessKey &access_key, const KeySource &key_source); Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source); Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option); Result ComputeCtr(void *dst, size_t dst_size, s32 keyslot, const void *src, size_t src_size, const IvCtr &iv_ctr); Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *data, size_t size); Result AllocateAesKeySlot(s32 *out_keyslot); Result DeallocateAesKeySlot(s32 keyslot); Result TestAesKeySlot(s32 *out_index, bool *out_virtual, s32 keyslot); os::SystemEvent *GetAesKeySlotAvailableEvent(); /* RSA. */ Result DecryptDeviceUniqueData(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); /* SSL */ Result DecryptAndStoreSslClientCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); Result ModularExponentiateWithSslClientCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); /* ES */ Result LoadEsDeviceKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); Result PrepareEsTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); Result PrepareCommonEsTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation); Result DecryptAndStoreDrmDeviceCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); Result ModularExponentiateWithDrmDeviceCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); Result PrepareEsArchiveKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); Result LoadPreparedAesKey(s32 keyslot, const AccessKey &access_key); Result PrepareEsUnknown2Key(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); /* FS */ Result DecryptAndStoreGcKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); Result DecryptGcMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size); Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which); Result LoadPreparedAesKey(s32 keyslot, const AccessKey &access_key); Result GetPackage2Hash(void *dst, const size_t size); /* Manu. */ Result ReencryptDeviceUniqueData(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_crypto_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_general_interface.hpp> #define AMS_SPL_I_CRYPTO_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GenerateAesKek, (sf::Out<spl::AccessKey> out_access_key, spl::KeySource key_source, u32 generation, u32 option), (out_access_key, key_source, generation, option)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, LoadAesKey, (s32 keyslot, spl::AccessKey access_key, spl::KeySource key_source), (keyslot, access_key, key_source)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GenerateAesKey, (sf::Out<spl::AesKey> out_key, spl::AccessKey access_key, spl::KeySource key_source), (out_key, access_key, key_source)) \ AMS_SF_METHOD_INFO(C, H, 14, Result, DecryptAesKey, (sf::Out<spl::AesKey> out_key, spl::KeySource key_source, u32 generation, u32 option), (out_key, key_source, generation, option)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, ComputeCtr, (const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, spl::IvCtr iv_ctr), (out_buf, keyslot, in_buf, iv_ctr)) \ AMS_SF_METHOD_INFO(C, H, 16, Result, ComputeCmac, (sf::Out<spl::Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf), (out_cmac, keyslot, in_buf)) \ AMS_SF_METHOD_INFO(C, H, 21, Result, AllocateAesKeySlot, (sf::Out<s32> out_keyslot), (out_keyslot)) \ AMS_SF_METHOD_INFO(C, H, 22, Result, DeallocateAesKeySlot, (s32 keyslot), (keyslot)) \ AMS_SF_METHOD_INFO(C, H, 23, Result, GetAesKeySlotAvailableEvent, (sf::OutCopyHandle out_hnd), (out_hnd)) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, ICryptoInterface, ::ams::spl::impl::IGeneralInterface, AMS_SPL_I_CRYPTO_INTERFACE_INTERFACE_INFO, 0xEF3598D9) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_deprecated_general_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #define AMS_SPL_I_DEPRECATED_GENERAL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetConfig, (sf::Out<u64> out, u32 which), (out, which)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, ModularExponentiate, (const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod), (out, base, exp, mod)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GenerateAesKek, (sf::Out<spl::AccessKey> out_access_key, spl::KeySource key_source, u32 generation, u32 option), (out_access_key, key_source, generation, option)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, LoadAesKey, (s32 keyslot, spl::AccessKey access_key, spl::KeySource key_source), (keyslot, access_key, key_source)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GenerateAesKey, (sf::Out<spl::AesKey> out_key, spl::AccessKey access_key, spl::KeySource key_source), (out_key, access_key, key_source)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, SetConfig, (u32 which, u64 value), (which, value)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GenerateRandomBytes, (const sf::OutPointerBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, DecryptAndStoreGcKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (src, access_key, key_source, option)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, DecryptGcMessage, (sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest), (out_size, out, base, mod, label_digest)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, IsDevelopment, (sf::Out<bool> is_dev), (is_dev)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GenerateSpecificAesKey, (sf::Out<spl::AesKey> out_key, spl::KeySource key_source, u32 generation, u32 which), (out_key, key_source, generation, which)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, DecryptDeviceUniqueData, (const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (dst, src, access_key, key_source, option)) \ AMS_SF_METHOD_INFO(C, H, 14, Result, DecryptAesKey, (sf::Out<spl::AesKey> out_key, spl::KeySource key_source, u32 generation, u32 option), (out_key, key_source, generation, option)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, ComputeCtrDeprecated, (const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, spl::IvCtr iv_ctr), (out_buf, keyslot, in_buf, iv_ctr), hos::Version_1_0_0, hos::Version_1_0_0) \ AMS_SF_METHOD_INFO(C, H, 15, Result, ComputeCtr, (const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, spl::IvCtr iv_ctr), (out_buf, keyslot, in_buf, iv_ctr), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 16, Result, ComputeCmac, (sf::Out<spl::Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf), (out_cmac, keyslot, in_buf)) \ AMS_SF_METHOD_INFO(C, H, 17, Result, LoadEsDeviceKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (src, access_key, key_source, option)) \ AMS_SF_METHOD_INFO(C, H, 18, Result, PrepareEsTitleKeyDeprecated, (sf::Out<spl::AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest), (out_access_key, base, mod, label_digest), hos::Version_1_0_0, hos::Version_2_3_0) \ AMS_SF_METHOD_INFO(C, H, 18, Result, PrepareEsTitleKey, (sf::Out<spl::AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation), (out_access_key, base, mod, label_digest, generation), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 19, Result, LoadPreparedAesKey, (s32 keyslot, spl::AccessKey access_key), (keyslot, access_key)) \ AMS_SF_METHOD_INFO(C, H, 20, Result, PrepareCommonEsTitleKeyDeprecated, (sf::Out<spl::AccessKey> out_access_key, spl::KeySource key_source), (out_access_key, key_source), hos::Version_2_0_0, hos::Version_2_3_0) \ AMS_SF_METHOD_INFO(C, H, 20, Result, PrepareCommonEsTitleKey, (sf::Out<spl::AccessKey> out_access_key, spl::KeySource key_source, u32 generation), (out_access_key, key_source, generation), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 21, Result, AllocateAesKeySlot, (sf::Out<s32> out_keyslot), (out_keyslot)) \ AMS_SF_METHOD_INFO(C, H, 22, Result, DeallocateAesKeySlot, (s32 keyslot), (keyslot)) \ AMS_SF_METHOD_INFO(C, H, 23, Result, GetAesKeySlotAvailableEvent, (sf::OutCopyHandle out_hnd), (out_hnd)) \ AMS_SF_METHOD_INFO(C, H, 24, Result, SetBootReason, (spl::BootReasonValue boot_reason), (boot_reason), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 25, Result, GetBootReason, (sf::Out<spl::BootReasonValue> out), (out), hos::Version_3_0_0) AMS_SF_DEFINE_INTERFACE(ams::spl::impl, IDeprecatedGeneralInterface, AMS_SPL_I_DEPRECATED_GENERAL_INTERFACE_INTERFACE_INFO, 0x127DDBD0) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_device_unique_data_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_crypto_interface.hpp> #define AMS_SPL_I_DEVICE_UNIQUE_DATA_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 13, Result, DecryptDeviceUniqueDataDeprecated, (const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (dst, src, access_key, key_source, option), hos::Version_Min, hos::Version_4_1_0) \ AMS_SF_METHOD_INFO(C, H, 13, Result, DecryptDeviceUniqueData, (const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source), (dst, src, access_key, key_source), hos::Version_5_0_0) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, IDeviceUniqueDataInterface, ::ams::spl::impl::ICryptoInterface, AMS_SPL_I_DEVICE_UNIQUE_DATA_INTERFACE_INTERFACE_INFO, 0xADAD1D0A) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_es_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_device_unique_data_interface.hpp> #define AMS_SPL_I_ES_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 17, Result, LoadEsDeviceKeyDeprecated, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (src, access_key, key_source, option), hos::Version_Min, hos::Version_4_1_0) \ AMS_SF_METHOD_INFO(C, H, 17, Result, LoadEsDeviceKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source), (src, access_key, key_source), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 18, Result, PrepareEsTitleKey, (sf::Out<spl::AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation), (out_access_key, base, mod, label_digest, generation)) \ AMS_SF_METHOD_INFO(C, H, 20, Result, PrepareCommonEsTitleKey, (sf::Out<spl::AccessKey> out_access_key, spl::KeySource key_source, u32 generation), (out_access_key, key_source, generation), hos::Version_2_0_0) \ AMS_SF_METHOD_INFO(C, H, 28, Result, DecryptAndStoreDrmDeviceCertKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source), (src, access_key, key_source), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 29, Result, ModularExponentiateWithDrmDeviceCertKey, (const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod), (out, base, mod), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 31, Result, PrepareEsArchiveKey, (sf::Out<spl::AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation), (out_access_key, base, mod, label_digest, generation), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 32, Result, LoadPreparedAesKey, (s32 keyslot, spl::AccessKey access_key), (keyslot, access_key), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 33, Result, PrepareEsUnknown2Key, (sf::Out<spl::AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation), (out_access_key, base, mod, label_digest, generation), hos::Version_18_0_0) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, IEsInterface, ::ams::spl::impl::IDeviceUniqueDataInterface, AMS_SPL_I_ES_INTERFACE_INTERFACE_INFO, 0x346D5001) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_fs_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_crypto_interface.hpp> #define AMS_SPL_I_FS_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 9, Result, DecryptAndStoreGcKeyDeprecated, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source, u32 option), (src, access_key, key_source, option), hos::Version_Min, hos::Version_4_1_0) \ AMS_SF_METHOD_INFO(C, H, 9, Result, DecryptAndStoreGcKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source), (src, access_key, key_source), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 10, Result, DecryptGcMessage, (sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest), (out_size, out, base, mod, label_digest)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GenerateSpecificAesKey, (sf::Out<spl::AesKey> out_key, spl::KeySource key_source, u32 generation, u32 which), (out_key, key_source, generation, which)) \ AMS_SF_METHOD_INFO(C, H, 19, Result, LoadPreparedAesKey, (s32 keyslot, spl::AccessKey access_key), (keyslot, access_key)) \ AMS_SF_METHOD_INFO(C, H, 31, Result, GetPackage2Hash, (const sf::OutPointerBuffer &dst), (dst), hos::Version_5_0_0) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, IFsInterface, ::ams::spl::impl::ICryptoInterface, AMS_SPL_I_FS_INTERFACE_INTERFACE_INFO, 0x682B3803) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_general_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #define AMS_SPL_I_GENERAL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetConfig, (sf::Out<u64> out, u32 which), (out, which)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, ModularExponentiate, (const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod), (out, base, exp, mod)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, SetConfig, (u32 which, u64 value), (which, value)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GenerateRandomBytes, (const sf::OutPointerBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, IsDevelopment, (sf::Out<bool> is_dev), (is_dev)) \ AMS_SF_METHOD_INFO(C, H, 24, Result, SetBootReason, (spl::BootReasonValue boot_reason), (boot_reason), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 25, Result, GetBootReason, (sf::Out<spl::BootReasonValue> out), (out), hos::Version_3_0_0) AMS_SF_DEFINE_INTERFACE(ams::spl::impl, IGeneralInterface, AMS_SPL_I_GENERAL_INTERFACE_INTERFACE_INFO, 0x127DDBD0) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_manu_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_device_unique_data_interface.hpp> #define AMS_SPL_I_MANU_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 30, Result, ReencryptDeviceUniqueData, (const sf::OutPointerBuffer &out, const sf::InPointerBuffer &src, spl::AccessKey access_key_dec, spl::KeySource source_dec, spl::AccessKey access_key_enc, spl::KeySource source_enc, u32 option), (out, src, access_key_dec, source_dec, access_key_enc, source_enc, option)) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, IManuInterface, ::ams::spl::impl::IDeviceUniqueDataInterface, AMS_SPL_I_MANU_INTERFACE_INTERFACE_INFO, 0xF5643734) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_random_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #define AMS_SPL_I_RANDOM_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GenerateRandomBytes, (const sf::OutBuffer &out), (out)) AMS_SF_DEFINE_INTERFACE(ams::spl::impl, IRandomInterface, AMS_SPL_I_RANDOM_INTERFACE_INTERFACE_INFO, 0xBDE33ED4) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/impl/spl_ssl_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/impl/spl_device_unique_data_interface.hpp> #define AMS_SPL_I_SSL_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 26, Result, DecryptAndStoreSslClientCertKey, (const sf::InPointerBuffer &src, spl::AccessKey access_key, spl::KeySource key_source), (src, access_key, key_source), hos::Version_5_0_0) \ AMS_SF_METHOD_INFO(C, H, 27, Result, ModularExponentiateWithSslClientCertKey, (const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod), (out, base, mod), hos::Version_5_0_0) AMS_SF_DEFINE_INTERFACE_WITH_BASE(ams::spl::impl, ISslInterface, ::ams::spl::impl::IDeviceUniqueDataInterface, AMS_SPL_I_SSL_INTERFACE_INTERFACE_INFO, 0x0E1D71B7) ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/smc/spl_secure_monitor_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/spl/spl_types.hpp> namespace ams::spl::smc { /* Helpers for converting arguments. */ constexpr ALWAYS_INLINE u32 GetComputeAesMode(CipherMode mode, u32 keyslot) { return static_cast<u32>((static_cast<u32>(mode) << 4) | (keyslot & 7)); } constexpr ALWAYS_INLINE u32 GetPrepareEsDeviceUniqueKeyOption(EsDeviceUniqueKeyType type, u32 generation) { return static_cast<u32>((static_cast<u32>(type) << 6) | (generation & 0x3F)); } /* Functions. */ Result SetConfig(AsyncOperationKey *out_op, spl::ConfigItem key, const u64 *value, size_t num_qwords, const void *sign); Result GetConfig(u64 *out, size_t num_qwords, spl::ConfigItem key); Result GetResult(Result *out, AsyncOperationKey op); Result GetResultData(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op); Result ModularExponentiate(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod); Result GenerateRandomBytes(void *out, size_t size); Result GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option); Result LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source); Result ComputeAes(AsyncOperationKey *out_op, u64 dst_addr, u32 mode, const IvCtr &iv_ctr, u64 src_addr, size_t size); Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which); Result ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size); Result ReencryptDeviceUniqueData(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option); Result DecryptDeviceUniqueData(void *data, size_t size, const AccessKey &access_key, const KeySource &source, DeviceUniqueDataMode mode); Result ModularExponentiateWithStorageKey(AsyncOperationKey *out_op, const void *base, const void *mod, ModularExponentiateWithStorageKeyMode mode); Result PrepareEsDeviceUniqueKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option); Result LoadPreparedAesKey(u32 keyslot, const AccessKey &access_key); Result PrepareCommonEsTitleKey(AccessKey *out, const KeySource &source, u32 generation); /* Deprecated functions. */ Result LoadEsDeviceKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); Result DecryptDeviceUniqueData(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); Result DecryptAndStoreGcKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); /* Atmosphere functions. */ Result AtmosphereCopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size); Result AtmosphereCopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size); Result AtmosphereReadWriteRegister(uint64_t address, uint32_t mask, uint32_t value, uint32_t *out_value); Result AtmosphereGetEmummcConfig(void *out_config, void *out_paths, u32 storage_id); /* Helpers. */ ALWAYS_INLINE Result SetConfig(spl::ConfigItem key, const u64 *value, size_t num_qwords) { AsyncOperationKey dummy_op; return SetConfig(std::addressof(dummy_op), key, value, num_qwords, nullptr); } ALWAYS_INLINE Result SetConfig(spl::ConfigItem key, const u64 value) { return SetConfig(key, std::addressof(value), 1); } #if !defined(ATMOSPHERE_OS_HORIZON) void PresetInternalKey(const AesKey *key, u32 generation, bool device); #endif } ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/spl_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/spl/spl_types.hpp> namespace ams::spl { void Initialize(); void InitializeForCrypto(); void InitializeForSsl(); void InitializeForEs(); void InitializeForFs(); void InitializeForManu(); void Finalize(); Result AllocateAesKeySlot(s32 *out_slot); Result DeallocateAesKeySlot(s32 slot); Result GenerateAesKek(AccessKey *access_key, const void *key_source, size_t key_source_size, s32 generation, u32 option); Result LoadAesKey(s32 slot, const AccessKey &access_key, const void *key_source, size_t key_source_size); Result GenerateAesKey(void *dst, size_t dst_size, const AccessKey &access_key, const void *key_source, size_t key_source_size); Result GenerateSpecificAesKey(void *dst, size_t dst_size, const void *key_source, size_t key_source_size, s32 generation, u32 option); Result ComputeCtr(void *dst, size_t dst_size, s32 slot, const void *src, size_t src_size, const void *iv, size_t iv_size); Result DecryptAesKey(void *dst, size_t dst_size, const void *src, size_t src_size, s32 generation, u32 option); Result GetConfig(u64 *out, ConfigItem item); Result SetConfig(ConfigItem item, u64 v); bool IsDevelopment(); MemoryArrangement GetMemoryArrangement(); inline bool GetConfigBool(ConfigItem item) { u64 v; R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), item)); return v != 0; } inline HardwareType GetHardwareType() { u64 v; R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::HardwareType)); return static_cast<HardwareType>(v); } inline HardwareState GetHardwareState() { u64 v; R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::HardwareState)); return static_cast<HardwareState>(v); } inline RetailInteractiveDisplayState GetRetailInteractiveDisplayState() { u64 v; R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::RetailInteractiveDisplayState)); return static_cast<RetailInteractiveDisplayState>(v); } inline u64 GetDeviceIdLow() { u64 v; R_ABORT_UNLESS(::ams::spl::GetConfig(std::addressof(v), ::ams::spl::ConfigItem::DeviceId)); return v; } inline bool IsRecoveryBoot() { return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::IsRecoveryBoot); } inline bool IsDevelopmentFunctionEnabled() { return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::IsDevelopmentFunctionEnabled); } inline bool IsDisabledProgramVerification() { return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::DisableProgramVerification); } inline bool IsUsb30ForceEnabled() { return ::ams::spl::GetConfigBool(::ams::spl::ConfigItem::ExosphereForceEnableUsb30); } Result SetBootReason(BootReasonValue boot_reason); Result GetBootReason(BootReasonValue *out); inline BootReasonValue GetBootReason() { BootReasonValue br; R_ABORT_UNLESS(::ams::spl::GetBootReason(std::addressof(br))); return br; } SocType GetSocType(); Result GetPackage2Hash(void *dst, size_t dst_size); Result GenerateRandomBytes(void *out, size_t buffer_size); Result LoadPreparedAesKey(s32 slot, const AccessKey &access_key); Result PrepareCommonEsTitleKey(AccessKey *out, const void *key_source, const size_t key_source_size, int generation); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl/spl_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::spl { namespace smc { enum class FunctionId : u32 { SetConfig = 0xC3000401, GetConfig = 0xC3000002, GetResult = 0xC3000003, GetResultData = 0xC3000404, ModularExponentiate = 0xC3000E05, GenerateRandomBytes = 0xC3000006, GenerateAesKek = 0xC3000007, LoadAesKey = 0xC3000008, ComputeAes = 0xC3000009, GenerateSpecificAesKey = 0xC300000A, ComputeCmac = 0xC300040B, ReencryptDeviceUniqueData = 0xC300D60C, DecryptDeviceUniqueData = 0xC300100D, ModularExponentiateWithStorageKey = 0xC300060F, PrepareEsDeviceUniqueKey = 0xC3000610, LoadPreparedAesKey = 0xC3000011, PrepareCommonEsTitleKey = 0xC3000012, /* Deprecated functions. */ LoadEsDeviceKey = 0xC300100C, DecryptAndStoreGcKey = 0xC300100E, /* Atmosphere functions. */ AtmosphereIramCopy = 0xF0000201, AtmosphereReadWriteRegister = 0xF0000002, AtmosphereGetEmummcConfig = 0xF0000404, }; enum class Result { Success = 0, NotSupported = 1, InvalidArgument = 2, InProgress = 3, NoAsyncOperation = 4, InvalidAsyncOperation = 5, NotPermitted = 6, NotInitialized = 7, }; constexpr inline ::ams::Result ConvertResult(Result smc_result) { /* smc::Result::Success becomes ResultSuccess() directly. */ R_SUCCEED_IF(smc_result == smc::Result::Success); /* Convert to the list of known SecureMonitorErrors. */ const auto converted = R_MAKE_NAMESPACE_RESULT(::ams::spl, static_cast<u32>(smc_result)); R_UNLESS(spl::ResultSecureMonitorError::Includes(converted), spl::ResultUnexpectedSecureMonitorResult()); /* Return the error. */ R_RETURN(converted); } enum class CipherMode { CbcEncrypt = 0, CbcDecrypt = 1, Ctr = 2, }; enum class DeviceUniqueDataMode { DecryptDeviceUniqueData = 0, DecryptAndStoreGcKey = 1, DecryptAndStoreEsDeviceKey = 2, DecryptAndStoreSslKey = 3, DecryptAndStoreDrmDeviceCertKey = 4, }; enum class ModularExponentiateWithStorageKeyMode { Gc = 0, Ssl = 1, DrmDeviceCert = 2, }; enum class EsDeviceUniqueKeyType { TitleKey = 0, ArchiveKey = 1, Unknown2 = 2, }; struct AsyncOperationKey { u64 value; }; } constexpr inline size_t AesKeySize = crypto::AesEncryptor128::KeySize; constexpr inline size_t AesBlockSize = crypto::AesEncryptor128::BlockSize; enum class HardwareType { Icosa = 0, Copper = 1, Hoag = 2, Iowa = 3, Calcio = 4, Aula = 5, }; enum SocType { SocType_Erista = 0, SocType_Mariko = 1, }; enum HardwareState { HardwareState_Development = 0, HardwareState_Production = 1, }; enum MemoryArrangement { MemoryArrangement_Standard = 0, MemoryArrangement_StandardForAppletDev = 1, MemoryArrangement_StandardForSystemDev = 2, MemoryArrangement_Expanded = 3, MemoryArrangement_ExpandedForAppletDev = 4, /* Note: MemoryArrangement_Dynamic is not official. */ /* Atmosphere uses it to maintain compatibility with firmwares prior to 6.0.0, */ /* which removed the explicit retrieval of memory arrangement from PM. */ MemoryArrangement_Dynamic = 5, MemoryArrangement_Count, }; enum RetailInteractiveDisplayState { RetailInteractiveDisplayState_Disabled = 0, RetailInteractiveDisplayState_Enabled = 1, }; struct BootReasonValue { union { struct { u8 power_intr; u8 rtc_intr; u8 nv_erc; u8 boot_reason; }; u32 value; }; }; static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); enum BootReason { BootReason_Unknown = 0, BootReason_AcOk = 1, BootReason_OnKey = 2, BootReason_RtcAlarm1 = 3, BootReason_RtcAlarm2 = 4, }; #pragma pack(push, 1) struct AesKey { union { u8 data[AesKeySize]; u64 data64[AesKeySize / sizeof(u64)]; }; }; static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!"); struct IvCtr { union { u8 data[AesKeySize]; u64 data64[AesKeySize / sizeof(u64)]; }; }; static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!"); struct Cmac { union { u8 data[AesKeySize]; u64 data64[AesKeySize / sizeof(u64)]; }; }; static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!"); struct AccessKey { union { u8 data[AesKeySize]; u64 data64[AesKeySize / sizeof(u64)]; }; }; static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!"); struct KeySource { union { u8 data[AesKeySize]; u64 data64[AesKeySize / sizeof(u64)]; }; }; static_assert(alignof(AccessKey) == alignof(u8), "KeySource definition!"); #pragma pack(pop) enum class ConfigItem : u32 { /* Standard config items. */ DisableProgramVerification = 1, DramId = 2, SecurityEngineInterruptNumber = 3, FuseVersion = 4, HardwareType = 5, HardwareState = 6, IsRecoveryBoot = 7, DeviceId = 8, BootReason = 9, MemoryMode = 10, IsDevelopmentFunctionEnabled = 11, KernelConfiguration = 12, IsChargerHiZModeEnabled = 13, RetailInteractiveDisplayState = 14, RegulatorType = 15, DeviceUniqueKeyGeneration = 16, Package2Hash = 17, /* Extension config items for exosphere. */ ExosphereApiVersion = 65000, ExosphereNeedsReboot = 65001, ExosphereNeedsShutdown = 65002, ExosphereGitCommitHash = 65003, ExosphereHasRcmBugPatch = 65004, ExosphereBlankProdInfo = 65005, ExosphereAllowCalWrites = 65006, ExosphereEmummcType = 65007, ExospherePayloadAddress = 65008, ExosphereLogConfiguration = 65009, ExosphereForceEnableUsb30 = 65010, ExosphereSupportedHosVersion = 65011, ExosphereApproximateApiVersion = 65012, /* NOTE: Internal use only. */ }; } #if defined(ATMOSPHERE_OS_HORIZON) /* Extensions to libnx spl config item enum. */ constexpr inline SplConfigItem SplConfigItem_ExosphereApiVersion = static_cast<SplConfigItem>(65000); constexpr inline SplConfigItem SplConfigItem_ExosphereNeedsReboot = static_cast<SplConfigItem>(65001); constexpr inline SplConfigItem SplConfigItem_ExosphereNeedsShutdown = static_cast<SplConfigItem>(65002); constexpr inline SplConfigItem SplConfigItem_ExosphereGitCommitHash = static_cast<SplConfigItem>(65003); constexpr inline SplConfigItem SplConfigItem_ExosphereHasRcmBugPatch = static_cast<SplConfigItem>(65004); constexpr inline SplConfigItem SplConfigItem_ExosphereBlankProdInfo = static_cast<SplConfigItem>(65005); constexpr inline SplConfigItem SplConfigItem_ExosphereAllowCalWrites = static_cast<SplConfigItem>(65006); constexpr inline SplConfigItem SplConfigItem_ExosphereEmummcType = static_cast<SplConfigItem>(65007); constexpr inline SplConfigItem SplConfigItem_ExospherePayloadAddress = static_cast<SplConfigItem>(65008); constexpr inline SplConfigItem SplConfigItem_ExosphereLogConfiguration = static_cast<SplConfigItem>(65009); constexpr inline SplConfigItem SplConfigItem_ExosphereForceEnableUsb30 = static_cast<SplConfigItem>(65010); #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/spl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/spl/spl_types.hpp> #include <stratosphere/spl/spl_api.hpp> #include <stratosphere/spl/smc/spl_secure_monitor_api.hpp> #include <stratosphere/spl/impl/spl_api_impl.hpp> #include <stratosphere/spl/impl/spl_random_interface.hpp> #include <stratosphere/spl/impl/spl_deprecated_general_interface.hpp> #include <stratosphere/spl/impl/spl_general_interface.hpp> #include <stratosphere/spl/impl/spl_crypto_interface.hpp> #include <stratosphere/spl/impl/spl_device_unique_data_interface.hpp> #include <stratosphere/spl/impl/spl_ssl_interface.hpp> #include <stratosphere/spl/impl/spl_es_interface.hpp> #include <stratosphere/spl/impl/spl_manu_interface.hpp> #include <stratosphere/spl/impl/spl_fs_interface.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/sprofile/sprofile_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sprofile { struct Identifier { u8 data[7]; friend bool operator==(const Identifier &lhs, const Identifier &rhs) { return std::memcmp(lhs.data, rhs.data, sizeof(lhs.data)) == 0; } friend bool operator!=(const Identifier &lhs, const Identifier &rhs) { return !(lhs == rhs); } }; static_assert(sizeof(Identifier) == 7); static_assert(util::is_pod<Identifier>::value); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sprofile/srv/sprofile_srv_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::sprofile::srv { void Initialize(); void StartIpcServer(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/sprofile.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/sprofile/sprofile_types.hpp> #include <stratosphere/sprofile/srv/sprofile_srv_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/svc/svc_stratosphere_shims.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) namespace ams::svc { #if defined(ATMOSPHERE_ARCH_ARM64) namespace aarch64::lp64 { ALWAYS_INLINE Result SetHeapSize(::ams::svc::Address *out_address, ::ams::svc::Size size) { R_RETURN(::svcSetHeapSize(reinterpret_cast<void **>(out_address), size)); } ALWAYS_INLINE Result SetHeapSize(uintptr_t *out_address, ::ams::svc::Size size) { static_assert(sizeof(::ams::svc::Address) == sizeof(uintptr_t)); R_RETURN(::svcSetHeapSize(reinterpret_cast<void **>(out_address), size)); } ALWAYS_INLINE Result SetMemoryPermission(::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission perm) { R_RETURN(::svcSetMemoryPermission(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(perm))); } ALWAYS_INLINE Result SetMemoryAttribute(::ams::svc::Address address, ::ams::svc::Size size, uint32_t mask, uint32_t attr) { R_RETURN(::svcSetMemoryAttribute(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, mask, attr)); } ALWAYS_INLINE Result MapMemory(::ams::svc::Address dst_address, ::ams::svc::Address src_address, ::ams::svc::Size size) { R_RETURN(::svcMapMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), reinterpret_cast<void *>(static_cast<uintptr_t>(src_address)), size)); } ALWAYS_INLINE Result UnmapMemory(::ams::svc::Address dst_address, ::ams::svc::Address src_address, ::ams::svc::Size size) { R_RETURN(::svcUnmapMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), reinterpret_cast<void *>(static_cast<uintptr_t>(src_address)), size)); } ALWAYS_INLINE Result QueryMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Address address) { R_RETURN(::svcQueryMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), address)); } ALWAYS_INLINE void ExitProcess() { return ::svcExitProcess(); } ALWAYS_INLINE Result CreateThread(::ams::svc::Handle *out_handle, ::ams::svc::ThreadFunc func, ::ams::svc::Address arg, ::ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) { R_RETURN(::svcCreateThread(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(func)), reinterpret_cast<void *>(static_cast<uintptr_t>(arg)), reinterpret_cast<void *>(static_cast<uintptr_t>(stack_bottom)), priority, core_id)); } ALWAYS_INLINE Result StartThread(::ams::svc::Handle thread_handle) { R_RETURN(::svcStartThread(thread_handle)); } ALWAYS_INLINE void ExitThread() { return ::svcExitThread(); } ALWAYS_INLINE void SleepThread(int64_t ns) { return ::svcSleepThread(ns); } ALWAYS_INLINE Result GetThreadPriority(int32_t *out_priority, ::ams::svc::Handle thread_handle) { R_RETURN(::svcGetThreadPriority(out_priority, thread_handle)); } ALWAYS_INLINE Result SetThreadPriority(::ams::svc::Handle thread_handle, int32_t priority) { R_RETURN(::svcSetThreadPriority(thread_handle, priority)); } ALWAYS_INLINE Result GetThreadCoreMask(int32_t *out_core_id, uint64_t *out_affinity_mask, ::ams::svc::Handle thread_handle) { R_RETURN(::svcGetThreadCoreMask(out_core_id, out_affinity_mask, thread_handle)); } ALWAYS_INLINE Result SetThreadCoreMask(::ams::svc::Handle thread_handle, int32_t core_id, uint64_t affinity_mask) { R_RETURN(::svcSetThreadCoreMask(thread_handle, core_id, affinity_mask)); } ALWAYS_INLINE int32_t GetCurrentProcessorNumber() { return ::svcGetCurrentProcessorNumber(); } ALWAYS_INLINE Result SignalEvent(::ams::svc::Handle event_handle) { R_RETURN(::svcSignalEvent(event_handle)); } ALWAYS_INLINE Result ClearEvent(::ams::svc::Handle event_handle) { R_RETURN(::svcClearEvent(event_handle)); } ALWAYS_INLINE Result MapSharedMemory(::ams::svc::Handle shmem_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission map_perm) { R_RETURN(::svcMapSharedMemory(shmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(map_perm))); } ALWAYS_INLINE Result UnmapSharedMemory(::ams::svc::Handle shmem_handle, ::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcUnmapSharedMemory(shmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result CreateTransferMemory(::ams::svc::Handle *out_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission map_perm) { R_RETURN(::svcCreateTransferMemory(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(map_perm))); } ALWAYS_INLINE Result CloseHandle(::ams::svc::Handle handle) { R_RETURN(::svcCloseHandle(handle)); } ALWAYS_INLINE Result ResetSignal(::ams::svc::Handle handle) { R_RETURN(::svcResetSignal(handle)); } ALWAYS_INLINE Result WaitSynchronization(int32_t *out_index, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, int64_t timeout_ns) { R_RETURN(::svcWaitSynchronization(out_index, handles.GetPointerUnsafe(), num_handles, timeout_ns)); } ALWAYS_INLINE Result CancelSynchronization(::ams::svc::Handle handle) { R_RETURN(::svcCancelSynchronization(handle)); } ALWAYS_INLINE Result ArbitrateLock(::ams::svc::Handle thread_handle, ::ams::svc::Address address, uint32_t tag) { R_RETURN(::svcArbitrateLock(thread_handle, reinterpret_cast<u32 *>(static_cast<uintptr_t>(address)), tag)); } ALWAYS_INLINE Result ArbitrateUnlock(::ams::svc::Address address) { R_RETURN(::svcArbitrateUnlock(reinterpret_cast<u32 *>(static_cast<uintptr_t>(address)))); } ALWAYS_INLINE Result WaitProcessWideKeyAtomic(::ams::svc::Address address, ::ams::svc::Address cv_key, uint32_t tag, int64_t timeout_ns) { R_RETURN(::svcWaitProcessWideKeyAtomic(reinterpret_cast<u32 *>(static_cast<uintptr_t>(address)), reinterpret_cast<u32 *>(static_cast<uintptr_t>(cv_key)), tag, timeout_ns)); } ALWAYS_INLINE void SignalProcessWideKey(::ams::svc::Address cv_key, int32_t count) { return ::svcSignalProcessWideKey(reinterpret_cast<u32 *>(static_cast<uintptr_t>(cv_key)), count); } ALWAYS_INLINE int64_t GetSystemTick() { return ::svcGetSystemTick(); } ALWAYS_INLINE Result ConnectToNamedPort(::ams::svc::Handle *out_handle, ::ams::svc::UserPointer<const char *> name) { R_RETURN(::svcConnectToNamedPort(out_handle, name.GetPointerUnsafe())); } ALWAYS_INLINE Result SendSyncRequestLight(::ams::svc::Handle session_handle) { R_RETURN(::svcSendSyncRequestLight(session_handle)); } ALWAYS_INLINE Result SendSyncRequest(::ams::svc::Handle session_handle) { R_RETURN(::svcSendSyncRequest(session_handle)); } ALWAYS_INLINE Result SendSyncRequestWithUserBuffer(::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::Handle session_handle) { R_RETURN(::svcSendSyncRequestWithUserBuffer(reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, session_handle)); } ALWAYS_INLINE Result SendAsyncRequestWithUserBuffer(::ams::svc::Handle *out_event_handle, ::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::Handle session_handle) { R_RETURN(::svcSendAsyncRequestWithUserBuffer(out_event_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, session_handle)); } ALWAYS_INLINE Result GetProcessId(uint64_t *out_process_id, ::ams::svc::Handle process_handle) { R_RETURN(::svcGetProcessId(out_process_id, process_handle)); } ALWAYS_INLINE Result GetThreadId(uint64_t *out_thread_id, ::ams::svc::Handle thread_handle) { R_RETURN(::svcGetThreadId(out_thread_id, thread_handle)); } ALWAYS_INLINE void Break(::ams::svc::BreakReason break_reason, ::ams::svc::Address arg, ::ams::svc::Size size) { ::svcBreak(break_reason, arg, size); } ALWAYS_INLINE Result OutputDebugString(::ams::svc::UserPointer<const char *> debug_str, ::ams::svc::Size len) { R_RETURN(::svcOutputDebugString(debug_str.GetPointerUnsafe(), len)); } ALWAYS_INLINE void ReturnFromException(::ams::Result result) { return ::svcReturnFromException(result.GetValue()); } ALWAYS_INLINE Result GetInfo(uint64_t *out, ::ams::svc::InfoType info_type, ::ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(::svcGetInfo(out, static_cast<u32>(info_type), handle, info_subtype)); } ALWAYS_INLINE void FlushEntireDataCache() { return ::svcFlushEntireDataCache(); } ALWAYS_INLINE Result FlushDataCache(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcFlushDataCache(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result MapPhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcMapPhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result UnmapPhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcUnmapPhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result GetDebugFutureThreadInfo(::ams::svc::lp64::LastThreadContext *out_context, uint64_t *thread_id, ::ams::svc::Handle debug_handle, int64_t ns) { R_RETURN(::svcGetDebugFutureThreadInfo(reinterpret_cast<::LastThreadContext *>(out_context), thread_id, debug_handle, ns)); } ALWAYS_INLINE Result GetLastThreadInfo(::ams::svc::lp64::LastThreadContext *out_context, ::ams::svc::Address *out_tls_address, uint32_t *out_flags) { R_RETURN(::svcGetLastThreadInfo(reinterpret_cast<::LastThreadContext *>(out_context), reinterpret_cast<u64 *>(out_tls_address), out_flags)); } ALWAYS_INLINE Result GetResourceLimitLimitValue(int64_t *out_limit_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) { R_RETURN(::svcGetResourceLimitLimitValue(out_limit_value, resource_limit_handle, static_cast<::LimitableResource>(which))); } ALWAYS_INLINE Result GetResourceLimitCurrentValue(int64_t *out_current_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) { R_RETURN(::svcGetResourceLimitCurrentValue(out_current_value, resource_limit_handle, static_cast<::LimitableResource>(which))); } ALWAYS_INLINE Result SetThreadActivity(::ams::svc::Handle thread_handle, ::ams::svc::ThreadActivity thread_activity) { R_RETURN(::svcSetThreadActivity(thread_handle, static_cast<::ThreadActivity>(thread_activity))); } ALWAYS_INLINE Result GetThreadContext3(::ams::svc::UserPointer< ::ams::svc::ThreadContext *> out_context, ::ams::svc::Handle thread_handle) { R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle)); } ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) { R_RETURN(::svcWaitForAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), arb_type, value, timeout_ns)); } ALWAYS_INLINE Result SignalToAddress(::ams::svc::Address address, ::ams::svc::SignalType signal_type, int32_t value, int32_t count) { R_RETURN(::svcSignalToAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), signal_type, value, count)); } ALWAYS_INLINE void SynchronizePreemptionState() { return ::svcSynchronizePreemptionState(); } ALWAYS_INLINE Result GetResourceLimitPeakValue(int64_t *out_peak_value, ::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which) { R_RETURN(::svcGetResourceLimitPeakValue(out_peak_value, resource_limit_handle, static_cast<::LimitableResource>(which))); } ALWAYS_INLINE void KernelDebug(::ams::svc::KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return ::svcKernelDebug(kern_debug_type, arg0, arg1, arg2); } ALWAYS_INLINE void ChangeKernelTraceState(::ams::svc::KernelTraceState kern_trace_state) { return ::svcChangeKernelTraceState(kern_trace_state); } ALWAYS_INLINE Result CreateSession(::ams::svc::Handle *out_server_session_handle, ::ams::svc::Handle *out_client_session_handle, bool is_light, ::ams::svc::Address name) { R_RETURN(::svcCreateSession(out_server_session_handle, out_client_session_handle, is_light, name)); } ALWAYS_INLINE Result AcceptSession(::ams::svc::Handle *out_handle, ::ams::svc::Handle port) { R_RETURN(::svcAcceptSession(out_handle, port)); } ALWAYS_INLINE Result ReplyAndReceiveLight(::ams::svc::Handle handle) { R_RETURN(::svcReplyAndReceiveLight(handle)); } ALWAYS_INLINE Result ReplyAndReceive(int32_t *out_index, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, ::ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(::svcReplyAndReceive(out_index, handles.GetPointerUnsafe(), num_handles, reply_target, timeout_ns)); } ALWAYS_INLINE Result ReplyAndReceiveWithUserBuffer(int32_t *out_index, ::ams::svc::Address message_buffer, ::ams::svc::Size message_buffer_size, ::ams::svc::UserPointer<const ::ams::svc::Handle *> handles, int32_t num_handles, ::ams::svc::Handle reply_target, int64_t timeout_ns) { R_RETURN(::svcReplyAndReceiveWithUserBuffer(out_index, reinterpret_cast<void *>(static_cast<uintptr_t>(message_buffer)), message_buffer_size, handles.GetPointerUnsafe(), num_handles, reply_target, timeout_ns)); } ALWAYS_INLINE Result CreateEvent(::ams::svc::Handle *out_write_handle, ::ams::svc::Handle *out_read_handle) { R_RETURN(::svcCreateEvent(out_write_handle, out_read_handle)); } ALWAYS_INLINE Result MapPhysicalMemoryUnsafe(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcMapPhysicalMemoryUnsafe(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result UnmapPhysicalMemoryUnsafe(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcUnmapPhysicalMemoryUnsafe(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result SetUnsafeLimit(::ams::svc::Size limit) { R_RETURN(::svcSetUnsafeLimit(limit)); } ALWAYS_INLINE Result CreateCodeMemory(::ams::svc::Handle *out_handle, ::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcCreateCodeMemory(out_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result ControlCodeMemory(::ams::svc::Handle code_memory_handle, ::ams::svc::CodeMemoryOperation operation, uint64_t address, uint64_t size, ::ams::svc::MemoryPermission perm) { R_RETURN(::svcControlCodeMemory(code_memory_handle, static_cast<::CodeMapOperation>(operation), reinterpret_cast<void *>(address), size, static_cast<u32>(perm))); } ALWAYS_INLINE void SleepSystem() { return ::svcSleepSystem(); } ALWAYS_INLINE Result ReadWriteRegister(uint32_t *out_value, ::ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) { R_RETURN(::svcReadWriteRegister(out_value, address, mask, value)); } ALWAYS_INLINE Result SetProcessActivity(::ams::svc::Handle process_handle, ::ams::svc::ProcessActivity process_activity) { R_RETURN(::svcSetProcessActivity(process_handle, static_cast<::ProcessActivity>(process_activity))); } ALWAYS_INLINE Result CreateSharedMemory(::ams::svc::Handle *out_handle, ::ams::svc::Size size, ::ams::svc::MemoryPermission owner_perm, ::ams::svc::MemoryPermission remote_perm) { R_RETURN(::svcCreateSharedMemory(out_handle, size, static_cast<u32>(owner_perm), static_cast<u32>(remote_perm))); } ALWAYS_INLINE Result MapTransferMemory(::ams::svc::Handle trmem_handle, ::ams::svc::Address address, ::ams::svc::Size size, ::ams::svc::MemoryPermission owner_perm) { R_RETURN(::svcMapTransferMemory(trmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size, static_cast<u32>(owner_perm))); } ALWAYS_INLINE Result UnmapTransferMemory(::ams::svc::Handle trmem_handle, ::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcUnmapTransferMemory(trmem_handle, reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result CreateInterruptEvent(::ams::svc::Handle *out_read_handle, int32_t interrupt_id, ::ams::svc::InterruptType interrupt_type) { R_RETURN(::svcCreateInterruptEvent(out_read_handle, interrupt_id, static_cast<u32>(interrupt_type))); } ALWAYS_INLINE Result QueryPhysicalAddress(::ams::svc::lp64::PhysicalMemoryInfo *out_info, ::ams::svc::Address address) { R_RETURN(::svcQueryPhysicalAddress(reinterpret_cast<::PhysicalMemoryInfo *>(out_info), address)); } ALWAYS_INLINE Result QueryMemoryMapping(::ams::svc::Address *out_address, ::ams::svc::Size *out_size, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) { R_RETURN(::svcQueryMemoryMapping(reinterpret_cast<u64 *>(out_address), reinterpret_cast<u64 *>(out_size), physical_address, size)); } ALWAYS_INLINE Result LegacyQueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) { R_RETURN(::svcLegacyQueryIoMapping(reinterpret_cast<u64 *>(out_address), physical_address, size)); } ALWAYS_INLINE Result CreateDeviceAddressSpace(::ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) { R_RETURN(::svcCreateDeviceAddressSpace(out_handle, das_address, das_size)); } ALWAYS_INLINE Result AttachDeviceAddressSpace(::ams::svc::DeviceName device_name, ::ams::svc::Handle das_handle) { R_RETURN(::svcAttachDeviceAddressSpace(static_cast<u64>(device_name), das_handle)); } ALWAYS_INLINE Result DetachDeviceAddressSpace(::ams::svc::DeviceName device_name, ::ams::svc::Handle das_handle) { R_RETURN(::svcDetachDeviceAddressSpace(static_cast<u64>(device_name), das_handle)); } ALWAYS_INLINE Result MapDeviceAddressSpaceByForce(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(::svcMapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option)); } ALWAYS_INLINE Result MapDeviceAddressSpaceAligned(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address, u32 option) { R_RETURN(::svcMapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option)); } ALWAYS_INLINE Result UnmapDeviceAddressSpace(::ams::svc::Handle das_handle, ::ams::svc::Handle process_handle, uint64_t process_address, ::ams::svc::Size size, uint64_t device_address) { R_RETURN(::svcUnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address)); } ALWAYS_INLINE Result InvalidateProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(::svcInvalidateProcessDataCache(process_handle, address, size)); } ALWAYS_INLINE Result StoreProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(::svcStoreProcessDataCache(process_handle, address, size)); } ALWAYS_INLINE Result FlushProcessDataCache(::ams::svc::Handle process_handle, uint64_t address, uint64_t size) { R_RETURN(::svcFlushProcessDataCache(process_handle, address, size)); } ALWAYS_INLINE Result DebugActiveProcess(::ams::svc::Handle *out_handle, uint64_t process_id) { R_RETURN(::svcDebugActiveProcess(out_handle, process_id)); } ALWAYS_INLINE Result BreakDebugProcess(::ams::svc::Handle debug_handle) { R_RETURN(::svcBreakDebugProcess(debug_handle)); } ALWAYS_INLINE Result TerminateDebugProcess(::ams::svc::Handle debug_handle) { R_RETURN(::svcTerminateDebugProcess(debug_handle)); } ALWAYS_INLINE Result GetDebugEvent(::ams::svc::UserPointer< ::ams::svc::lp64::DebugEventInfo *> out_info, ::ams::svc::Handle debug_handle) { R_RETURN(::svcGetDebugEvent(reinterpret_cast<::DebugEventInfo *>(out_info.GetPointerUnsafe()), debug_handle)); } ALWAYS_INLINE Result ContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, ::ams::svc::UserPointer<const uint64_t *> thread_ids, int32_t num_thread_ids) { R_RETURN(::svcContinueDebugEvent(debug_handle, flags, const_cast<u64 *>(thread_ids.GetPointerUnsafe()), num_thread_ids)); } ALWAYS_INLINE Result LegacyContinueDebugEvent(::ams::svc::Handle debug_handle, uint32_t flags, uint64_t thread_id) { R_RETURN(::svcLegacyContinueDebugEvent(debug_handle, flags, thread_id)); } ALWAYS_INLINE Result GetProcessList(int32_t *out_num_processes, ::ams::svc::UserPointer<uint64_t *> out_process_ids, int32_t max_out_count) { R_RETURN(::svcGetProcessList(out_num_processes, out_process_ids.GetPointerUnsafe(), max_out_count)); } ALWAYS_INLINE Result GetThreadList(int32_t *out_num_threads, ::ams::svc::UserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ::ams::svc::Handle debug_handle) { R_RETURN(::svcGetThreadList(out_num_threads, out_thread_ids.GetPointerUnsafe(), max_out_count, debug_handle)); } ALWAYS_INLINE Result GetDebugThreadContext(::ams::svc::UserPointer< ::ams::svc::ThreadContext *> out_context, ::ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) { R_RETURN(::svcGetDebugThreadContext(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), debug_handle, thread_id, context_flags)); } ALWAYS_INLINE Result SetDebugThreadContext(::ams::svc::Handle debug_handle, uint64_t thread_id, ::ams::svc::UserPointer<const ::ams::svc::ThreadContext *> context, uint32_t context_flags) { R_RETURN(::svcSetDebugThreadContext(debug_handle, thread_id, reinterpret_cast<const ::ThreadContext *>(context.GetPointerUnsafe()), context_flags)); } ALWAYS_INLINE Result QueryDebugProcessMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Handle process_handle, ::ams::svc::Address address) { R_RETURN(::svcQueryDebugProcessMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), process_handle, address)); } ALWAYS_INLINE Result ReadDebugProcessMemory(::ams::svc::Address buffer, ::ams::svc::Handle debug_handle, ::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcReadDebugProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(buffer)), debug_handle, address, size)); } ALWAYS_INLINE Result WriteDebugProcessMemory(::ams::svc::Handle debug_handle, ::ams::svc::Address buffer, ::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcWriteDebugProcessMemory(debug_handle, reinterpret_cast<const void *>(static_cast<uintptr_t>(buffer)), address, size)); } ALWAYS_INLINE Result SetHardwareBreakPoint(::ams::svc::HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value) { R_RETURN(::svcSetHardwareBreakPoint(static_cast<u32>(name), flags, value)); } ALWAYS_INLINE Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ::ams::svc::Handle debug_handle, uint64_t thread_id, ::ams::svc::DebugThreadParam param) { R_RETURN(::svcGetDebugThreadParam(out_64, out_32, debug_handle, thread_id, static_cast<::DebugThreadParam>(param))); } ALWAYS_INLINE Result GetSystemInfo(uint64_t *out, ::ams::svc::SystemInfoType info_type, ::ams::svc::Handle handle, uint64_t info_subtype) { R_RETURN(::svcGetSystemInfo(out, static_cast<u64>(info_type), handle, info_subtype)); } ALWAYS_INLINE Result CreatePort(::ams::svc::Handle *out_server_handle, ::ams::svc::Handle *out_client_handle, int32_t max_sessions, bool is_light, ::ams::svc::Address name) { R_RETURN(::svcCreatePort(out_server_handle, out_client_handle, max_sessions, is_light, reinterpret_cast<const char *>(static_cast<uintptr_t>(name)))); } ALWAYS_INLINE Result ManageNamedPort(::ams::svc::Handle *out_server_handle, ::ams::svc::UserPointer<const char *> name, int32_t max_sessions) { R_RETURN(::svcManageNamedPort(out_server_handle, name.GetPointerUnsafe(), max_sessions)); } ALWAYS_INLINE Result ConnectToPort(::ams::svc::Handle *out_handle, ::ams::svc::Handle port) { R_RETURN(::svcConnectToPort(out_handle, port)); } ALWAYS_INLINE Result SetProcessMemoryPermission(::ams::svc::Handle process_handle, uint64_t address, uint64_t size, ::ams::svc::MemoryPermission perm) { R_RETURN(::svcSetProcessMemoryPermission(process_handle, address, size, static_cast<u32>(perm))); } ALWAYS_INLINE Result MapProcessMemory(::ams::svc::Address dst_address, ::ams::svc::Handle process_handle, uint64_t src_address, ::ams::svc::Size size) { R_RETURN(::svcMapProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), process_handle, src_address, size)); } ALWAYS_INLINE Result UnmapProcessMemory(::ams::svc::Address dst_address, ::ams::svc::Handle process_handle, uint64_t src_address, ::ams::svc::Size size) { R_RETURN(::svcUnmapProcessMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(dst_address)), process_handle, src_address, size)); } ALWAYS_INLINE Result QueryProcessMemory(::ams::svc::UserPointer< ::ams::svc::lp64::MemoryInfo *> out_memory_info, ::ams::svc::PageInfo *out_page_info, ::ams::svc::Handle process_handle, uint64_t address) { R_RETURN(::svcQueryProcessMemory(reinterpret_cast<::MemoryInfo *>(out_memory_info.GetPointerUnsafe()), reinterpret_cast<u32 *>(out_page_info), process_handle, address)); } ALWAYS_INLINE Result MapProcessCodeMemory(::ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(::svcMapProcessCodeMemory(process_handle, dst_address, src_address, size)); } ALWAYS_INLINE Result UnmapProcessCodeMemory(::ams::svc::Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size) { R_RETURN(::svcUnmapProcessCodeMemory(process_handle, dst_address, src_address, size)); } ALWAYS_INLINE Result CreateProcess(::ams::svc::Handle *out_handle, ::ams::svc::UserPointer<const ::ams::svc::lp64::CreateProcessParameter *> parameters, ::ams::svc::UserPointer<const uint32_t *> caps, int32_t num_caps) { R_RETURN(::svcCreateProcess(out_handle, parameters.GetPointerUnsafe(), caps.GetPointerUnsafe(), num_caps)); } ALWAYS_INLINE Result StartProcess(::ams::svc::Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size) { R_RETURN(::svcStartProcess(process_handle, priority, core_id, main_thread_stack_size)); } ALWAYS_INLINE Result TerminateProcess(::ams::svc::Handle process_handle) { R_RETURN(::svcTerminateProcess(process_handle)); } ALWAYS_INLINE Result GetProcessInfo(int64_t *out_info, ::ams::svc::Handle process_handle, ::ams::svc::ProcessInfoType info_type) { R_RETURN(::svcGetProcessInfo(out_info, process_handle, static_cast<::ProcessInfoType>(info_type))); } ALWAYS_INLINE Result CreateResourceLimit(::ams::svc::Handle *out_handle) { R_RETURN(::svcCreateResourceLimit(out_handle)); } ALWAYS_INLINE Result SetResourceLimitLimitValue(::ams::svc::Handle resource_limit_handle, ::ams::svc::LimitableResource which, int64_t limit_value) { R_RETURN(::svcSetResourceLimitLimitValue(resource_limit_handle, static_cast<::LimitableResource>(which), limit_value)); } ALWAYS_INLINE void CallSecureMonitor(::ams::svc::lp64::SecureMonitorArguments *args) { ::svcCallSecureMonitor(reinterpret_cast<::SecmonArgs *>(args)); } ALWAYS_INLINE Result MapInsecurePhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcMapInsecurePhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } ALWAYS_INLINE Result UnmapInsecurePhysicalMemory(::ams::svc::Address address, ::ams::svc::Size size) { R_RETURN(::svcUnmapInsecurePhysicalMemory(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), size)); } } #endif ALWAYS_INLINE bool IsKernelMesosphere() { uint64_t dummy; return R_SUCCEEDED(::ams::svc::GetInfo(std::addressof(dummy), ::ams::svc::InfoType_MesosphereMeta, ::ams::svc::InvalidHandle, ::ams::svc::MesosphereMetaInfo_KernelVersion)); } ALWAYS_INLINE bool IsKTraceEnabled() { uint64_t value = 0; return R_SUCCEEDED(::ams::svc::GetInfo(std::addressof(value), ::ams::svc::InfoType_MesosphereMeta, ::ams::svc::InvalidHandle, ::ams::svc::MesosphereMetaInfo_IsKTraceEnabled)) && value != 0; } } #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/impl/util/time_impl_util_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_posix_time.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp> namespace ams::time::impl::util { Result GetSpanBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to); bool IsLeapYear(int year); bool IsValidDate(int year, int month, int day); int GetDaysInMonth(int year, int month); int DateToDays(int year, int month, int day); void DaysToDate(int *out_year, int *out_month, int *out_day, int days); CalendarTime ToCalendarTimeInUtc(const PosixTime &posix_time); PosixTime ToPosixTimeFromUtc(const CalendarTime &calendar_time); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_posix_time.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp> namespace ams::time { Result Initialize(); Result InitializeForSystem(); Result InitializeForSystemUser(); Result Finalize(); bool IsInitialized(); bool IsValidDate(int year, int month, int day); Result GetElapsedSecondsBetween(s64 *out, const SteadyClockTimePoint &from, const SteadyClockTimePoint &to); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_calendar_time.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> namespace ams::time { struct CalendarTime { s16 year; s8 month; s8 day; s8 hour; s8 minute; s8 second; bool IsValid() const; CalendarTime &operator+=(const TimeSpan &ts); CalendarTime &operator-=(const TimeSpan &ts); friend CalendarTime operator+(const CalendarTime &lhs, const TimeSpan &rhs); friend CalendarTime operator-(const CalendarTime &lhs, const TimeSpan &rhs); friend TimeSpan operator-(const CalendarTime &lhs, const CalendarTime &rhs); constexpr friend bool operator==(const CalendarTime &lhs, const CalendarTime &rhs) { return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second; } constexpr friend bool operator!=(const CalendarTime &lhs, const CalendarTime &rhs) { return !(lhs == rhs); } constexpr friend bool operator<=(const CalendarTime &lhs, const CalendarTime &rhs) { return !(rhs < lhs); } constexpr friend bool operator>=(const CalendarTime &lhs, const CalendarTime &rhs) { return !(lhs < rhs); } constexpr friend bool operator> (const CalendarTime &lhs, const CalendarTime &rhs) { return rhs < lhs; } constexpr friend bool operator< (const CalendarTime &lhs, const CalendarTime &rhs) { if (!std::is_constant_evaluated()) { AMS_ASSERT(lhs.IsValid()); AMS_ASSERT(rhs.IsValid()); } constexpr auto ToUint64 = [](const time::CalendarTime &time) ALWAYS_INLINE_LAMBDA { return (static_cast<u64>(time.year) << 40) | (static_cast<u64>(time.month) << 32) | (static_cast<u64>(time.day) << 24) | (static_cast<u64>(time.hour) << 16) | (static_cast<u64>(time.minute) << 8) | (static_cast<u64>(time.second) << 0); }; return ToUint64(lhs) < ToUint64(rhs); } }; static_assert(sizeof(CalendarTime) == sizeof(u64)); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::time { using SourceId = util::Uuid; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_posix_time.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> namespace ams::time { struct PosixTime { s64 value; constexpr PosixTime &operator+=(const TimeSpan &ts) { this->value += ts.GetSeconds(); return *this; } constexpr PosixTime &operator-=(const TimeSpan &ts) { this->value -= ts.GetSeconds(); return *this; } constexpr friend PosixTime operator+(const PosixTime &lhs, const TimeSpan &rhs) { return { .value = lhs.value + rhs.GetSeconds() }; } constexpr friend PosixTime operator-(const PosixTime &lhs, const TimeSpan &rhs) { return { .value = lhs.value - rhs.GetSeconds() }; } constexpr friend TimeSpan operator-(const PosixTime &lhs, const PosixTime &rhs) { return TimeSpan::FromSeconds(lhs.value - rhs.value); } constexpr friend bool operator==(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value == rhs.value; } constexpr friend bool operator!=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value != rhs.value; } constexpr friend bool operator<=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value <= rhs.value; } constexpr friend bool operator>=(const PosixTime &lhs, const PosixTime &rhs) { return lhs.value >= rhs.value; } constexpr friend bool operator< (const PosixTime &lhs, const PosixTime &rhs) { return lhs.value < rhs.value; } constexpr friend bool operator> (const PosixTime &lhs, const PosixTime &rhs) { return lhs.value > rhs.value; } }; static_assert(sizeof(PosixTime) == sizeof(s64)); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_standard_network_system_clock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_system_clock_common.hpp> #include <stratosphere/time/time_posix_time.hpp> namespace ams::time { class StandardNetworkSystemClock { public: using rep = SystemClockTraits::rep; using period = SystemClockTraits::period; using duration = SystemClockTraits::duration; using time_point = SystemClockTraits::time_point; static constexpr bool is_steady = false; public: static time_point now(); static std::time_t to_time_t(const StandardUserSystemClock::time_point &t); static time_point from_time_t(std::time_t t); public: static Result GetCurrentTime(PosixTime *out); /* TODO: static Result GetSystemClockContext(SystemClockContext *out); */ }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_standard_steady_clock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp> namespace ams::time { class StandardSteadyClock { public: using rep = s64; using period = std::ratio<1>; using duration = std::chrono::duration<rep, period>; using time_point = std::chrono::time_point<StandardSteadyClock>; static constexpr bool is_steady = true; public: static time_point now(); public: static Result GetCurrentTimePoint(SteadyClockTimePoint *out); }; Result GetStandardSteadyClockCurrentTimePoint(SteadyClockTimePoint *out); TimeSpan GetStandardSteadyClockInternalOffset(); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_standard_user_system_clock.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_system_clock_common.hpp> #include <stratosphere/time/time_posix_time.hpp> namespace ams::time { class StandardUserSystemClock { public: using rep = SystemClockTraits::rep; using period = SystemClockTraits::period; using duration = SystemClockTraits::duration; using time_point = SystemClockTraits::time_point; static constexpr bool is_steady = false; public: static time_point now(); static std::time_t to_time_t(const StandardUserSystemClock::time_point &t); static time_point from_time_t(std::time_t t); public: static Result GetCurrentTime(PosixTime *out); /* TODO: static Result GetSystemClockContext(SystemClockContext *out); */ }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_steady_clock_time_point.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> namespace ams::time { struct SteadyClockTimePoint { s64 value; SourceId source_id; constexpr SteadyClockTimePoint &operator+=(const TimeSpan &ts) { this->value += ts.GetSeconds(); return *this; } constexpr SteadyClockTimePoint &operator-=(const TimeSpan &ts) { this->value -= ts.GetSeconds(); return *this; } constexpr friend SteadyClockTimePoint operator+(const SteadyClockTimePoint &lhs, const TimeSpan &rhs) { return { .value = lhs.value + rhs.GetSeconds(), .source_id = lhs.source_id }; } constexpr friend SteadyClockTimePoint operator-(const SteadyClockTimePoint &lhs, const TimeSpan &rhs) { return { .value = lhs.value - rhs.GetSeconds(), .source_id = lhs.source_id }; } constexpr friend bool operator==(const SteadyClockTimePoint &lhs, const SteadyClockTimePoint &rhs) { return lhs.value == rhs.value && lhs.source_id == rhs.source_id; } constexpr friend bool operator!=(const SteadyClockTimePoint &lhs, const SteadyClockTimePoint &rhs) { return !(lhs == rhs); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_system_clock_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_common.hpp> namespace ams::time { class SystemClockTraits { public: using rep = s64; using period = std::ratio<1>; using duration = std::chrono::duration<rep, period>; using time_point = std::chrono::time_point<SystemClockTraits>; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time/time_timezone_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/time/time_calendar_time.hpp> #include <stratosphere/time/time_posix_time.hpp> namespace ams::time { CalendarTime ToCalendarTimeInUtc(const PosixTime &posix_time); PosixTime ToPosixTimeFromUtc(const CalendarTime &calendar_time); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/time.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/time/time_common.hpp> #include <stratosphere/time/time_api.hpp> #include <stratosphere/time/time_posix_time.hpp> #include <stratosphere/time/time_calendar_time.hpp> #include <stratosphere/time/time_timezone_api.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp> #include <stratosphere/time/time_standard_steady_clock.hpp> #include <stratosphere/time/time_standard_user_system_clock.hpp> #include <stratosphere/time/time_standard_network_system_clock.hpp> #include <stratosphere/time/impl/util/time_impl_util_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> #include <stratosphere/tipc/impl/tipc_impl_command_serialization.hpp> namespace ams::tipc::impl { template<typename T> concept HasDefaultServiceCommandProcessor = requires (T &t, const MessageBuffer &message_buffer) { { t.ProcessDefaultServiceCommand(message_buffer) } -> std::same_as<Result>; }; struct SyncFunctionTraits { public: template<typename R, typename C, typename... A> static std::tuple<A...> GetArgsImpl(R(C::*)(A...)); }; template<auto F> using SyncFunctionArgsType = decltype(SyncFunctionTraits::GetArgsImpl(F)); #define AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ struct NAME##ArgumentsFunctionHolder { RETURN f ARGS; }; #define AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ using NAME##ArgumentsType = ::ams::tipc::impl::SyncFunctionArgsType<&NAME##ArgumentsFunctionHolder::f>; #define AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ , ::ams::tipc::impl::CommandMetaInfo<CMD_ID + 0x10, NAME##ArgumentsType>::InMessageTotalSize #define AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ , ::ams::tipc::impl::CommandMetaInfo<CMD_ID + 0x10, NAME##ArgumentsType>::OutMessageTotalSize #define AMS_TIPC_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO) \ class CLASSNAME : public BASECLASS { \ private: \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER) \ public: \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS) \ public: \ static constexpr size_t MaximumRequestSize = std::max<size_t>({ \ 0 \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE) \ }); \ \ static constexpr size_t MaximumResponseSize = std::max<size_t>({ \ 0 \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE) \ }); \ }; #define AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ template<typename T, typename... Args> \ concept Is##CLASSNAME##__##NAME##Impl = requires (T &t, Args &&... args) { \ { t.NAME(std::forward<Args>(args)...) } -> std::same_as<RETURN>; \ }; \ \ template<typename T, typename A> \ struct Is##CLASSNAME##__##NAME##Holder : std::false_type{}; \ \ template<typename T, typename... Args> requires std::same_as<std::tuple<Args...>, CLASSNAME::NAME##ArgumentsType> \ struct Is##CLASSNAME##__##NAME##Holder<T, std::tuple<Args...>> : std::bool_constant<Is##CLASSNAME##__##NAME##Impl<T, Args...>>{}; \ \ template<typename T> \ static constexpr inline bool Is##CLASSNAME##__##NAME = Is##CLASSNAME##__##NAME##Holder<T, CLASSNAME::NAME##ArgumentsType>::value; #define AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ Is##CLASSNAME##__##NAME<T> && #define AMS_TIPC_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS) \ \ template<typename T> \ concept Is##CLASSNAME = CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER) true; #define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ else if (constexpr u16 TipcCommandId = CMD_ID + 0x10; tag == TipcCommandId) { \ R_RETURN((this->ProcessMethodById<TipcCommandId, ImplType>(impl, message_buffer, fw_ver))); \ } #define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ if constexpr (constexpr u16 TipcCommandId = CMD_ID + 0x10; CommandId == TipcCommandId) { \ constexpr bool MinValid = VERSION_MIN == hos::Version_Min; \ constexpr bool MaxValid = VERSION_MAX == hos::Version_Max; \ if ((MinValid || VERSION_MIN <= fw_ver) && (MaxValid || fw_ver <= VERSION_MAX)) { \ R_RETURN((::ams::tipc::impl::InvokeServiceCommandImpl<TipcCommandId, &ImplType::NAME, ImplType>(impl, message_buffer))); \ } \ } #define AMS_TIPC_IMPL_IS_FIRMWARE_VERSION_ALWAYS_VALID(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ { \ constexpr bool MinValid = VERSION_MIN == hos::Version_Min; \ constexpr bool MaxValid = VERSION_MAX == hos::Version_Max; \ if (!MinValid || !MaxValid) { \ return false; \ } \ } #define AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO) \ namespace NAMESPACE { \ \ AMS_TIPC_IMPL_DEFINE_INTERFACE(BASE, INTERFACE, CMD_MACRO) \ AMS_TIPC_IMPL_DEFINE_CONCEPT(INTERFACE, CMD_MACRO) \ \ } \ \ namespace ams::tipc::impl { \ \ template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \ class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public Base, public ImplHolder { \ public: \ template<typename... Args> \ constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward<Args>(args)...) { /* ... */ } \ private: \ template<typename ImplType> \ ALWAYS_INLINE Result ProcessDefaultMethod(ImplType *impl, const MessageBuffer &message_buffer) const { \ /* Handle a default command. */ \ if constexpr (HasDefaultServiceCommandProcessor<ImplType>) { \ R_RETURN(impl->ProcessDefaultServiceCommand(message_buffer)); \ } else { \ R_THROW(tipc::ResultInvalidMethod()); \ } \ } \ \ template<u16 CommandId, typename ImplType> \ ALWAYS_INLINE Result ProcessMethodById(ImplType *impl, const MessageBuffer &message_buffer, hos::Version fw_ver) const { \ CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID) \ \ R_RETURN(this->ProcessDefaultMethod<ImplType>(impl, message_buffer)); \ } \ \ static consteval bool IsFirmwareVersionAlwaysValid() { \ CMD_MACRO(ImplType, AMS_TIPC_IMPL_IS_FIRMWARE_VERSION_ALWAYS_VALID); \ return true; \ } \ public: \ virtual Result ProcessRequest() override { \ /* Get the implementation object. */ \ auto * const impl = ImplGetter::GetImplPointer(static_cast<ImplHolder *>(this)); \ \ /* Get the implementation type. */ \ using ImplType = typename std::remove_reference<decltype(*impl)>::type; \ static_assert(::NAMESPACE::Is##INTERFACE<ImplType>); \ \ /* Get accessor to the message buffer. */ \ const MessageBuffer message_buffer(tipc::GetMessageBuffer()); \ \ /* Get decision variables. */ \ const auto tag = MessageBuffer::MessageHeader(message_buffer).GetTag(); \ const auto fw_ver = IsFirmwareVersionAlwaysValid() ? hos::Version_Current : hos::GetVersion(); \ \ /* Process against the command ids. */ \ if (false) { } \ CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST) \ else { \ R_RETURN(this->ProcessDefaultMethod<ImplType>(impl, message_buffer)); \ } \ } \ }; \ \ } #define AMS_TIPC_DEFINE_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO) \ AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, ::ams::tipc::ServiceObjectBase, CMD_MACRO) #define AMS_TIPC_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, hos::Version_Min, hos::Version_Max) #define AMS_TIPC_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, hos::Version_Max) #define AMS_TIPC_METHOD_INFO_9(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) #define AMS_TIPC_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, FUNC, ...) FUNC #define AMS_TIPC_METHOD_INFO(...) \ AMS_TIPC_METHOD_INFO_X(, ## __VA_ARGS__, AMS_TIPC_METHOD_INFO_9(__VA_ARGS__), AMS_TIPC_METHOD_INFO_8(__VA_ARGS__), AMS_TIPC_METHOD_INFO_7(__VA_ARGS__)) } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_out.hpp> #include <stratosphere/tipc/tipc_buffers.hpp> #include <stratosphere/tipc/tipc_handles.hpp> namespace ams::tipc { struct ClientProcessId { os::ProcessId value; }; static_assert(std::is_trivial<ClientProcessId>::value && sizeof(ClientProcessId) == sizeof(os::ProcessId), "ClientProcessId"); } #if defined(ATMOSPHERE_OS_HORIZON) namespace ams::tipc::impl { /* Machinery for filtering type lists. */ template<class, class> struct TupleCat; template<class... First, class... Second> struct TupleCat<std::tuple<First...>, std::tuple<Second...>> { using type = std::tuple<First..., Second...>; }; template<template <typename> typename Cond> struct TupleFilter { private: template<typename, typename> struct ImplType; template<typename Res> struct ImplType<Res, std::tuple<>> { using type = Res; }; template<typename Res, typename T, typename... Ts> struct ImplType<Res, std::tuple<T, Ts...>> { using type = typename std::conditional<Cond<T>::value, typename ImplType<typename TupleCat<Res, std::tuple<T>>::type, std::tuple<Ts...>>::type, typename ImplType<Res, std::tuple<Ts...>>::type >::type; }; public: template<typename T> using FilteredType = typename ImplType<std::tuple<>, T>::type; }; enum class ArgumentType { InData, OutData, Buffer, InHandle, OutHandle, ProcessId, }; template<typename T> constexpr inline ArgumentType GetArgumentType = [] { if constexpr (tipc::IsBuffer<T>) { return ArgumentType::Buffer; } else if constexpr (std::same_as<T, tipc::CopyHandle> || std::same_as<T, tipc::MoveHandle>) { return ArgumentType::InHandle; } else if constexpr (std::same_as<T, tipc::OutCopyHandle> || std::same_as<T, tipc::OutMoveHandle>) { return ArgumentType::OutHandle; } else if constexpr (std::is_base_of<tipc::impl::OutBaseTag, T>::value) { return ArgumentType::OutData; } else if constexpr (std::same_as<T, tipc::ClientProcessId>) { return ArgumentType::ProcessId; } else if constexpr (std::is_trivial<T>::value && !std::is_pointer<T>::value) { return ArgumentType::InData; } else if constexpr (std::is_same<T, ::ams::Result>::value) { return ArgumentType::InData; } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } }(); template<typename T, ArgumentType ArgT> struct ArgumentTypeFilter : public std::bool_constant<GetArgumentType<T> == ArgT>{}; template<typename T, typename U> struct TypeEqualityFilter : public std::bool_constant<std::is_same<T, U>::value>{}; /* Argument type filters. */ template<typename T> using InDataFilter = ArgumentTypeFilter<T, ArgumentType::InData>; template<typename T> using OutDataFilter = ArgumentTypeFilter<T, ArgumentType::OutData>; template<typename T> using BufferFilter = ArgumentTypeFilter<T, ArgumentType::Buffer>; template<typename T> using InHandleFilter = ArgumentTypeFilter<T, ArgumentType::InHandle>; template<typename T> using OutHandleFilter = ArgumentTypeFilter<T, ArgumentType::OutHandle>; template<typename T> using ProcessIdFilter = ArgumentTypeFilter<T, ArgumentType::ProcessId>; /* Handle kind filters. */ template<typename T> using InMoveHandleFilter = TypeEqualityFilter<T, tipc::MoveHandle>; template<typename T> using InCopyHandleFilter = TypeEqualityFilter<T, tipc::CopyHandle>; template<typename T> using OutMoveHandleFilter = TypeEqualityFilter<T, tipc::OutMoveHandle>; template<typename T> using OutCopyHandleFilter = TypeEqualityFilter<T, tipc::OutCopyHandle>; template<typename> struct BufferAttributeArrayGetter; template<typename ...Ts> struct BufferAttributeArrayGetter<std::tuple<Ts...>> { static constexpr std::array<u32, sizeof...(Ts)> value = { BufferAttributes<Ts>..., }; }; template<> struct BufferAttributeArrayGetter<std::tuple<>> { static constexpr std::array<u32, 0> value{}; }; template<auto Predicate> struct BufferAttributeCounter { template<size_t Size> static constexpr size_t GetCount(const std::array<u32, Size> &attributes_array) { size_t count = 0; for (size_t i = 0; i < Size; i++) { if (Predicate(attributes_array[i])) { count++; } } return count; } }; static constexpr size_t InBufferPredicate(const u32 attribute) { return (attribute & SfBufferAttr_In) && !(attribute & SfBufferAttr_Out); } static constexpr size_t OutBufferPredicate(const u32 attribute) { return !(attribute & SfBufferAttr_In) && (attribute & SfBufferAttr_Out); } template<typename> struct RawDataOffsetCalculator; template<typename... Ts> struct RawDataOffsetCalculator<std::tuple<Ts...>> { private: template<typename T> struct LayoutHelper { static_assert(GetArgumentType<T> == ArgumentType::InData, "LayoutHelper InData"); static constexpr size_t Alignment = alignof(T); static constexpr size_t Size = sizeof(T); }; template<typename T> struct LayoutHelper<Out<T>> { static_assert(GetArgumentType<T> == ArgumentType::InData, "LayoutHelper OutData"); static constexpr size_t Alignment = alignof(T); static constexpr size_t Size = sizeof(T); }; public: static constexpr std::array<size_t, sizeof...(Ts)+1> Offsets = [] { std::array<size_t, sizeof...(Ts)+1> offsets{}; offsets[0] = 0; if constexpr (sizeof...(Ts) > 0) { /* Get size, alignment for each type. */ const std::array<size_t, sizeof...(Ts)> sizes = { LayoutHelper<Ts>::Size... }; const std::array<size_t, sizeof...(Ts)> aligns = { LayoutHelper<Ts>::Alignment... }; /* We want to sort...by alignment. */ std::array<size_t, sizeof...(Ts)> map = {}; for (size_t i = 0; i < sizeof...(Ts); i++) { map[i] = i; } /* TODO: Is sorting done on parameters? */ /* Sort?(map, aligns); */ /* Iterate over sorted sizes. */ size_t cur_offset = 0; for (size_t i : map) { cur_offset = util::AlignUp(cur_offset, aligns[i]); offsets[i] = cur_offset; cur_offset += sizes[i]; } offsets[sizeof...(Ts)] = cur_offset; } return offsets; }(); }; struct ArgumentSerializationInfo { /* Type used to select from below fields. */ ArgumentType arg_type; /* Raw data indexing. */ size_t in_raw_data_index; size_t out_raw_data_index; /* Buffer indexing. */ size_t buffer_index; bool is_send_buffer; size_t send_map_alias_index; size_t recv_map_alias_index; /* Handle indexing. */ size_t in_move_handle_index; size_t in_copy_handle_index; size_t out_move_handle_index; size_t out_copy_handle_index; }; template<u16 _CommandId, typename ArgumentsTuple> struct CommandMetaInfo; template<u16 _CommandId, typename... Arguments> struct CommandMetaInfo<_CommandId, std::tuple<Arguments...>> { public: static constexpr u16 CommandId = _CommandId; using ArgsType = std::tuple<typename std::decay<Arguments>::type...>; using InDatas = TupleFilter<InDataFilter>::FilteredType<ArgsType>; using OutDatas = TupleFilter<OutDataFilter>::FilteredType<ArgsType>; using Buffers = TupleFilter<BufferFilter>::FilteredType<ArgsType>; using InHandles = TupleFilter<InHandleFilter>::FilteredType<ArgsType>; using OutHandles = TupleFilter<OutHandleFilter>::FilteredType<ArgsType>; using ProcessIds = TupleFilter<ProcessIdFilter>::FilteredType<ArgsType>; static constexpr size_t NumInDatas = std::tuple_size<InDatas>::value; static constexpr size_t NumOutDatas = std::tuple_size<OutDatas>::value; static constexpr size_t NumBuffers = std::tuple_size<Buffers>::value; static constexpr size_t NumInHandles = std::tuple_size<InHandles>::value; static constexpr size_t NumOutHandles = std::tuple_size<OutHandles>::value; static constexpr size_t NumProcessIds = std::tuple_size<ProcessIds>::value; static constexpr bool HasProcessId = NumProcessIds >= 1; static_assert(NumBuffers <= 8, "Methods must take in <= 8 Buffers"); static_assert(NumInHandles <= 8, "Methods must take in <= 8 Handles"); static_assert(NumOutHandles <= 8, "Methods must output <= 8 Handles"); static_assert(NumInHandles == 0, "In Handles not yet implemented!"); /* Buffer marshalling. */ static constexpr std::array<u32, NumBuffers> BufferAttributes = BufferAttributeArrayGetter<Buffers>::value; static constexpr size_t NumInBuffers = BufferAttributeCounter<InBufferPredicate>::GetCount(BufferAttributes); static constexpr size_t NumOutBuffers = BufferAttributeCounter<OutBufferPredicate>::GetCount(BufferAttributes); /* In/Out data marshalling. */ static constexpr std::array<size_t, NumInDatas+1> InDataOffsets = RawDataOffsetCalculator<InDatas>::Offsets; static constexpr size_t InDataSize = util::AlignUp(InDataOffsets[NumInDatas], alignof(u32)); static constexpr std::array<size_t, NumOutDatas+1> OutDataOffsets = RawDataOffsetCalculator<OutDatas>::Offsets; static constexpr size_t OutDataSize = util::AlignUp(OutDataOffsets[NumOutDatas], alignof(u32)); /* Useful because reasons. */ static constexpr size_t OutDataAlign = []() -> size_t { if constexpr (std::tuple_size<OutDatas>::value) { return alignof(typename std::tuple_element<0, OutDatas>::type); } return 0; }(); /* Handle marshalling. */ static constexpr size_t NumInMoveHandles = std::tuple_size<TupleFilter<InMoveHandleFilter>::FilteredType<InHandles>>::value; static constexpr size_t NumInCopyHandles = std::tuple_size<TupleFilter<InCopyHandleFilter>::FilteredType<InHandles>>::value; static constexpr size_t NumOutMoveHandles = std::tuple_size<TupleFilter<OutMoveHandleFilter>::FilteredType<OutHandles>>::value; static constexpr size_t NumOutCopyHandles = std::tuple_size<TupleFilter<OutCopyHandleFilter>::FilteredType<OutHandles>>::value; static_assert(NumInMoveHandles + NumInCopyHandles == NumInHandles, "NumInMoveHandles + NumInCopyHandles == NumInHandles"); static_assert(NumOutMoveHandles + NumOutCopyHandles == NumOutHandles, "NumOutMoveHandles + NumOutCopyHandles == NumOutHandles"); /* tipc-specific accessors. */ static constexpr bool HasInSpecialHeader = HasProcessId || NumInHandles > 0; static constexpr MessageBuffer::MessageHeader InMessageHeader{CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0}; static constexpr MessageBuffer::SpecialHeader InSpecialHeader{HasProcessId, NumInCopyHandles, NumInMoveHandles, HasInSpecialHeader}; static constexpr auto InMessageProcessIdIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader); static constexpr auto InMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader) + (HasProcessId ? sizeof(u64) / sizeof(u32) : 0); static constexpr auto InMessageBufferIndex = MessageBuffer::GetMapAliasDescriptorIndex(InMessageHeader, InSpecialHeader); static constexpr auto InMessageRawDataIndex = MessageBuffer::GetRawDataIndex(InMessageHeader, InSpecialHeader); static constexpr bool HasOutSpecialHeader = NumOutHandles > 0; static constexpr MessageBuffer::MessageHeader OutMessageHeader{CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0}; static constexpr MessageBuffer::SpecialHeader OutSpecialHeader{false, NumOutCopyHandles, NumOutMoveHandles, HasOutSpecialHeader}; static constexpr auto OutMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(OutMessageHeader, OutSpecialHeader); static constexpr auto OutMessageResultIndex = MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader); static constexpr auto OutMessageRawDataIndex = OutMessageResultIndex + 1; static constexpr size_t InMessageTotalSize = (InMessageRawDataIndex * sizeof(u32)) + InDataSize; static constexpr size_t OutMessageTotalSize = (OutMessageRawDataIndex * sizeof(u32)) + OutDataSize; /* Construction of argument serialization structs. */ private: template<typename> struct ArgumentSerializationInfoConstructor; template<typename ...Ts> struct ArgumentSerializationInfoConstructor<std::tuple<Ts...>> { template<typename T> static constexpr ArgumentSerializationInfo ProcessUpdate(ArgumentSerializationInfo ¤t_info) { /* Save a copy of the current state to return. */ ArgumentSerializationInfo returned_info = current_info; constexpr auto arg_type = GetArgumentType<T>; returned_info.arg_type = arg_type; if constexpr (arg_type == ArgumentType::InData) { /* New rawdata, so increment index. */ current_info.in_raw_data_index++; } else if constexpr (arg_type == ArgumentType::OutData) { /* New rawdata, so increment index. */ current_info.out_raw_data_index++; } else if constexpr (arg_type == ArgumentType::InHandle) { /* New InHandle, increment the appropriate index. */ if constexpr (std::same_as<T, tipc::MoveHandle>) { current_info.in_move_handle_index++; } else if constexpr (std::same_as<T, tipc::CopyHandle>) { current_info.in_copy_handle_index++; } else { static_assert(!std::is_same<T, T>::value, "Invalid InHandle kind"); } } else if constexpr (arg_type == ArgumentType::OutHandle) { /* New OutHandle, increment the appropriate index. */ if constexpr (std::same_as<T, tipc::OutMoveHandle>) { current_info.out_move_handle_index++; } else if constexpr (std::same_as<T, tipc::OutCopyHandle>) { current_info.out_copy_handle_index++; } else { static_assert(!std::is_same<T, T>::value, "Invalid OutHandle kind"); } } else if constexpr (arg_type == ArgumentType::Buffer) { /* New Buffer, increment the appropriate index. */ const auto attributes = BufferAttributes[current_info.buffer_index++]; if (attributes & SfBufferAttr_In) { returned_info.is_send_buffer = true; current_info.send_map_alias_index++; } else if (attributes & SfBufferAttr_Out) { returned_info.is_send_buffer = false; current_info.recv_map_alias_index++; } } else if constexpr (arg_type == ArgumentType::ProcessId) { /* Nothing needs to be done to track process ids. */ } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } return returned_info; } static constexpr std::array<ArgumentSerializationInfo, sizeof...(Ts)> ArgumentSerializationInfos = [] { ArgumentSerializationInfo current_info = {}; return std::array<ArgumentSerializationInfo, sizeof...(Ts)>{ ProcessUpdate<Ts>(current_info)... }; }(); }; public: static constexpr std::array<ArgumentSerializationInfo, std::tuple_size<ArgsType>::value> ArgumentSerializationInfos = ArgumentSerializationInfoConstructor<ArgsType>::ArgumentSerializationInfos; }; template<size_t _Size, size_t _Align, size_t OutIndex> class OutRawHolder { public: static constexpr size_t Size = _Size; static constexpr size_t Align = _Align ? _Align : alignof(u8); private: alignas(Align) u8 data[Size]; public: constexpr ALWAYS_INLINE OutRawHolder() : data() { /* ... */ } template<size_t Offset, size_t TypeSize> constexpr ALWAYS_INLINE uintptr_t GetAddress() const { static_assert(Offset <= Size, "Offset <= Size"); static_assert(TypeSize <= Size, "TypeSize <= Size"); static_assert(Offset + TypeSize <= Size, "Offset + TypeSize <= Size"); return reinterpret_cast<uintptr_t>(data + Offset); } constexpr ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const { if constexpr (Size > 0) { buffer.SetRawArray(OutIndex, data, Size); } } }; template<size_t _NumMove, size_t _NumCopy, size_t OutIndex> class OutHandleHolder { public: static constexpr size_t NumMove = _NumMove; static constexpr size_t NumCopy = _NumCopy; private: tipc::NativeHandle move_handles[NumMove]; tipc::NativeHandle copy_handles[NumCopy]; public: ALWAYS_INLINE OutHandleHolder() { /* ... */ } template<size_t Index> constexpr ALWAYS_INLINE tipc::NativeHandle *GetMoveHandlePointer() { static_assert(Index < NumMove, "Index < NumMove"); return move_handles + Index; } template<size_t Index> constexpr ALWAYS_INLINE tipc::NativeHandle *GetCopyHandlePointer() { static_assert(Index < NumCopy, "Index < NumCopy"); return copy_handles + Index; } ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const { #define _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { buffer.SetHandle(OutIndex + n, copy_handles[n]); } } while (0) _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(2); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(3); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(4); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(5); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(6); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(7); #undef _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE #define _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(n) do { if constexpr (NumMove > n) { buffer.SetHandle(OutIndex + NumCopy + n, move_handles[n]); } } while (0) _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(0); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(1); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(2); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(3); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(4); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(5); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(6); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(7); #undef _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE } }; template<size_t... Ix> struct PrintIndex; template<typename CommandMeta> class CommandProcessor { public: /* Useful defines. */ using ArgsType = typename CommandMeta::ArgsType; using OutRawHolderType = OutRawHolder<CommandMeta::OutDataSize, CommandMeta::OutDataAlign, CommandMeta::OutMessageRawDataIndex>; using OutHandleHolderType = OutHandleHolder<CommandMeta::NumOutMoveHandles, CommandMeta::NumOutCopyHandles, CommandMeta::OutMessageHandleIndex>; private: static constexpr u64 GetMessageHeaderForCheck(const MessageBuffer::MessageHeader &header) { using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>; const util::BitPack32 *data = header.GetData(); const u32 lower = data[0].Get<Value>(); const u32 upper = data[1].Get<Value>(); return static_cast<u64>(lower) | (static_cast<u64>(upper) << BITSIZEOF(u32)); } static constexpr u32 GetSpecialHeaderForCheck(const MessageBuffer::SpecialHeader &header) { using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>; return header.GetHeader()->Get<Value>(); } /* Argument deserialization. */ template<size_t Index, typename T = typename std::tuple_element<Index, ArgsType>::type> static ALWAYS_INLINE typename std::tuple_element<Index, ArgsType>::type DeserializeArgumentImpl(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index]; if constexpr (Info.arg_type == ArgumentType::InData) { /* New in rawdata. */ constexpr size_t Offset = CommandMeta::InDataOffsets[Info.in_raw_data_index]; constexpr size_t RawIndex = Offset / sizeof(u32); static_assert(Offset == RawIndex * sizeof(u32)); /* TODO: Do unaligned data exist? */ if constexpr (!std::same_as<T, bool>) { return message_buffer.GetRaw<T>(CommandMeta::InMessageRawDataIndex + RawIndex); } else { return message_buffer.GetRaw<u8>(CommandMeta::InMessageRawDataIndex + RawIndex) & 1; } } else if constexpr (Info.arg_type == ArgumentType::OutData) { /* New out rawdata. */ constexpr size_t Offset = CommandMeta::OutDataOffsets[Info.out_raw_data_index]; return T(out_raw_holder.template GetAddress<Offset, T::TypeSize>()); } else if constexpr (Info.arg_type == ArgumentType::InHandle) { /* New InHandle. */ if constexpr (std::same_as<T, tipc::MoveHandle>) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + CommandMeta::NumInCopyHandles + Info.in_move_handle_index; return T(message_buffer.GetHandle(HandleIndex)); } else if constexpr (std::same_as<T, tipc::CopyHandle>) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + Info.in_copy_handle_index; return T(message_buffer.GetHandle(HandleIndex)); } else { static_assert(!std::is_same<T, T>::value, "Invalid InHandle kind"); } } else if constexpr (Info.arg_type == ArgumentType::OutHandle) { /* New OutHandle. */ if constexpr (std::same_as<T, tipc::OutMoveHandle>) { tipc::NativeHandle * const ptr = out_handles_holder.template GetMoveHandlePointer<Info.out_move_handle_index>(); *ptr = tipc::InvalidNativeHandle; return T(ptr); } else if constexpr (std::same_as<T, tipc::OutCopyHandle>) { tipc::NativeHandle * const ptr = out_handles_holder.template GetCopyHandlePointer<Info.out_copy_handle_index>(); *ptr = tipc::InvalidNativeHandle; return T(ptr); } else { static_assert(!std::is_same<T, T>::value, "Invalid OutHandle kind"); } } else if constexpr (Info.arg_type == ArgumentType::Buffer) { /* NOTE: There are currently no tipc commands which use buffers-with-attributes */ /* If these are added (e.g., NonSecure buffers), implement checking here? */ constexpr size_t MapAliasDescriptorSize = MessageBuffer::MapAliasDescriptor::GetDataSize(); if constexpr (Info.is_send_buffer) { /* Input send buffer. */ constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + (Info.send_map_alias_index * MapAliasDescriptorSize / sizeof(util::BitPack32)); const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(descriptor.GetAddress(), descriptor.GetSize()); } else { /* Input receive buffer. */ constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + ((CommandMeta::NumInBuffers + Info.recv_map_alias_index) * MapAliasDescriptorSize / sizeof(util::BitPack32)); const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex); return T(descriptor.GetAddress(), descriptor.GetSize()); } } else if constexpr (Info.arg_type == ArgumentType::ProcessId) { return T{ os::ProcessId{ message_buffer.GetProcessId(CommandMeta::InMessageProcessIdIndex) } }; } else { static_assert(!std::is_same<T, T>::value, "Invalid ArgumentType<T>"); } } public: static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &message_buffer) { /* Validate the message header. */ constexpr auto ExpectedMessageHeader = GetMessageHeaderForCheck(CommandMeta::InMessageHeader); R_UNLESS(message_buffer.Get64(0) == ExpectedMessageHeader, tipc::ResultInvalidMessageFormat()); /* Validate the special header. */ if constexpr (CommandMeta::HasInSpecialHeader) { constexpr auto ExpectedSpecialHeader = GetSpecialHeaderForCheck(CommandMeta::InSpecialHeader); constexpr auto SpecialHeaderIndex = MessageBuffer::MessageHeader::GetDataSize() / sizeof(util::BitPack32); R_UNLESS(message_buffer.Get32(SpecialHeaderIndex) == ExpectedSpecialHeader, tipc::ResultInvalidMessageFormat()); } R_SUCCEED(); } template<size_t Ix> static ALWAYS_INLINE auto DeserializeArgument(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) { return DeserializeArgumentImpl<Ix>(message_buffer, out_raw_holder, out_handles_holder); } static ALWAYS_INLINE void SerializeResults(const MessageBuffer &message_buffer, const Result &result, const OutRawHolderType &out_raw_holder, const OutHandleHolderType &out_handles_holder) { /* Set output headers. */ message_buffer.Set(CommandMeta::OutMessageHeader); if constexpr (CommandMeta::HasOutSpecialHeader) { message_buffer.Set(CommandMeta::OutSpecialHeader); } /* Set output handles. */ out_handles_holder.CopyTo(message_buffer); /* Set output result. */ message_buffer.Set(CommandMeta::OutMessageResultIndex, result.GetValue()); /* Set output data. */ out_raw_holder.CopyTo(message_buffer); } }; struct FunctionTraits { public: template<typename R, typename C, typename... A> static std::tuple<A...> GetArgumentsImpl(R(C::*)(A...)); template<typename R, typename C, typename... A> static R GetReturnImpl(R(C::*)(A...)); }; template<u16 _CommmandId, auto ServiceCommandImpl, typename ClassType> constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { using Return = decltype(FunctionTraits::GetReturnImpl(ServiceCommandImpl)); using TrueArgumentsTuple = decltype(FunctionTraits::GetArgumentsImpl(ServiceCommandImpl)); using CommandMeta = CommandMetaInfo<_CommmandId, TrueArgumentsTuple>; using Processor = CommandProcessor<CommandMeta>; /* TODO: ValidateClassType is valid? */ constexpr bool ReturnsResult = std::is_same<Return, Result>::value; constexpr bool ReturnsVoid = std::is_same<Return, void>::value; static_assert(ReturnsResult || ReturnsVoid, "Service Commands must return Result or void."); /* Validate that the command is valid. */ R_TRY(Processor::ValidateCommandFormat(message_buffer)); /* Deserialize arguments. */ typename Processor::OutRawHolderType out_raw_holder; typename Processor::OutHandleHolderType out_handles_holder; const Result command_result = [&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { if constexpr (ReturnsResult) { R_RETURN((object->*ServiceCommandImpl)(Processor::template DeserializeArgument<Ix>(message_buffer, out_raw_holder, out_handles_holder)...)); } else { (object->*ServiceCommandImpl)(Processor::template DeserializeArgument<Ix>(message_buffer, out_raw_holder, out_handles_holder)...); R_SUCCEED(); } }(std::make_index_sequence<std::tuple_size<typename CommandMeta::ArgsType>::value>()); /* Serialize output. */ Processor::SerializeResults(message_buffer, command_result, out_raw_holder, out_handles_holder); R_SUCCEED(); } } #elif defined(ATMOSPHERE_OS_WINDOWS) namespace ams::tipc::impl { template<u16 _CommandId, typename ArgumentsTuple> struct CommandMetaInfo; template<u16 _CommandId, typename... Arguments> struct CommandMetaInfo<_CommandId, std::tuple<Arguments...>> { public: static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ }; template<typename CommandMeta> class CommandProcessor { public: static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { AMS_ABORT("TODO"); } }; template<u16 _CommmandId, auto ServiceCommandImpl, typename ClassType> ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ /* TIPC is generally a huge TODO. */ AMS_UNUSED(object, message_buffer); AMS_ABORT("TIPC serialization not currently supported on Windows."); } } #elif defined(ATMOSPHERE_OS_LINUX) namespace ams::tipc::impl { template<u16 _CommandId, typename ArgumentsTuple> struct CommandMetaInfo; template<u16 _CommandId, typename... Arguments> struct CommandMetaInfo<_CommandId, std::tuple<Arguments...>> { public: static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ }; template<typename CommandMeta> class CommandProcessor { public: static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { AMS_ABORT("TODO"); } }; template<u16 _CommmandId, auto ServiceCommandImpl, typename ClassType> ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ /* TIPC is generally a huge TODO. */ AMS_UNUSED(object, message_buffer); AMS_ABORT("TIPC serialization not currently supported on Linux."); } } #elif defined(ATMOSPHERE_OS_MACOS) namespace ams::tipc::impl { template<u16 _CommandId, typename ArgumentsTuple> struct CommandMetaInfo; template<u16 _CommandId, typename... Arguments> struct CommandMetaInfo<_CommandId, std::tuple<Arguments...>> { public: static constexpr size_t InMessageTotalSize = 0x40; /* TODO */ static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */ }; template<typename CommandMeta> class CommandProcessor { public: static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) { AMS_ABORT("TODO"); } }; template<u16 _CommmandId, auto ServiceCommandImpl, typename ClassType> ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) { /* TODO: Is some kind of emulated serialization interesting/desirable? */ /* TIPC is generally a huge TODO. */ AMS_UNUSED(object, message_buffer); AMS_ABORT("TIPC serialization not currently supported on macOS."); } } #else #error "Unknown OS for tipc Command serialization." #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include <stratosphere/tipc/impl/tipc_impl_message_api.os.horizon.hpp> #elif defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/tipc/impl/tipc_impl_message_api.os.windows.hpp> #elif defined(ATMOSPHERE_OS_LINUX) #include <stratosphere/tipc/impl/tipc_impl_message_api.os.linux.hpp> #elif defined(ATMOSPHERE_OS_MACOS) #include <stratosphere/tipc/impl/tipc_impl_message_api.os.macos.hpp> #else #error "Unknown OS for tipc message impl" #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> namespace ams::tipc::impl { inline void Reply(tipc::NativeHandle reply_target) { /* Perform the reply. */ s32 dummy; R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(dummy), nullptr, 0, reply_target, 0)) { R_CATCH(svc::ResultTimedOut) { /* Timing out is acceptable. */ } R_CATCH(svc::ResultSessionClosed) { /* It's okay if we couldn't reply to a closed session. */ } } R_END_TRY_CATCH_WITH_ABORT_UNLESS; } ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { R_RETURN(svc::CloseHandle(handle)); } ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { R_RETURN(svc::CreateSession(out_server_session_handle, out_client_session_handle, is_light, name)); } ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { R_RETURN(svc::AcceptSession(out_handle, port)); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.linux.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> namespace ams::tipc::impl { inline void Reply(tipc::NativeHandle reply_target) { AMS_UNUSED(reply_target); AMS_ABORT("TODO: tipc Linux Reply"); } ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { AMS_UNUSED(handle); AMS_ABORT("TODO: tipc Linux CloseHandle"); } ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); AMS_ABORT("TODO: tipc Linux CreateSession"); } ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { AMS_UNUSED(out_handle, port); AMS_ABORT("TODO: tipc Linux AcceptSession"); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.macos.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> namespace ams::tipc::impl { inline void Reply(tipc::NativeHandle reply_target) { AMS_UNUSED(reply_target); AMS_ABORT("TODO: tipc macOS Reply"); } ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { AMS_UNUSED(handle); AMS_ABORT("TODO: tipc macOS CloseHandle"); } ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); AMS_ABORT("TODO: tipc macOS CreateSession"); } ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { AMS_UNUSED(out_handle, port); AMS_ABORT("TODO: tipc macOS AcceptSession"); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_message_api.os.windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> namespace ams::tipc::impl { inline void Reply(tipc::NativeHandle reply_target) { AMS_UNUSED(reply_target); AMS_ABORT("TODO: tipc Windows Reply"); } ALWAYS_INLINE Result CloseHandle(tipc::NativeHandle handle) { AMS_UNUSED(handle); AMS_ABORT("TODO: tipc Windows CloseHandle"); } ALWAYS_INLINE Result CreateSession(tipc::NativeHandle *out_server_session_handle, tipc::NativeHandle *out_client_session_handle, bool is_light, uintptr_t name) { AMS_UNUSED(out_server_session_handle, out_client_session_handle, is_light, name); AMS_ABORT("TODO: tipc Windows CreateSession"); } ALWAYS_INLINE Result AcceptSession(tipc::NativeHandle *out_handle, tipc::NativeHandle port) { AMS_UNUSED(out_handle, port); AMS_ABORT("TODO: tipc Windows AcceptSession"); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_template_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::tipc::impl { template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter, typename Root> class ImplTemplateBaseT; template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter> class ImplTemplateBase : public ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface> { private: using BaseImpl = ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface>; public: using BaseImpl::BaseImpl; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_allocators.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> namespace ams::tipc { template<typename T> concept IsServiceObjectAllocator = requires (T &t) { { t.Allocate() } -> std::convertible_to<ServiceObjectBase *>; }; template<typename T, size_t N> requires IsServiceObject<T> class SingletonAllocator final { static_assert(N >= 1); private: T m_singleton; public: constexpr ALWAYS_INLINE SingletonAllocator() : m_singleton() { /* ... */ } ALWAYS_INLINE ServiceObjectBase *Allocate() { return std::addressof(m_singleton); } }; template<typename T, size_t N> requires IsServiceObject<T> class SlabAllocator final : public ServiceObjectDeleter { private: struct Entry { bool used; util::TypedStorage<T> storage; }; private: Entry m_entries[N]; os::SdkMutex m_mutex; public: constexpr ALWAYS_INLINE SlabAllocator() : m_entries(), m_mutex() { /* ... */ } T *Allocate() { std::scoped_lock lk(m_mutex); for (size_t i = 0; i < N; ++i) { if (!m_entries[i].used) { m_entries[i].used = true; return util::ConstructAt(m_entries[i].storage); } } return nullptr; } void Deallocate(ServiceObjectBase *object) { std::scoped_lock lk(m_mutex); for (size_t i = 0; i < N; ++i) { if (m_entries[i].used && GetPointer(m_entries[i].storage) == object) { util::DestroyAt(m_entries[i].storage); m_entries[i].used = false; return; } } AMS_ABORT("Failed to deallocate entry in SlabAllocator<T, N>"); } public: virtual void DeleteServiceObject(ServiceObjectBase *object) override { return this->Deallocate(object); } }; static_assert(IsServiceObjectAllocator<SlabAllocator<ServiceObjectBase, 1>>); static_assert(IsServiceObjectDeleter<SlabAllocator<ServiceObjectBase, 1>>); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_buffers.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_out.hpp> #include <stratosphere/tipc/tipc_pointer_and_size.hpp> namespace ams::tipc { namespace impl { /* Buffer utilities. */ struct BufferBaseTag{}; } namespace impl { class BufferBase : public BufferBaseTag { public: static constexpr u32 AdditionalAttributes = 0; private: const tipc::PointerAndSize m_pas; protected: constexpr ALWAYS_INLINE uintptr_t GetAddressImpl() const { return m_pas.GetAddress(); } template<typename Entry> constexpr ALWAYS_INLINE size_t GetSizeImpl() const { return m_pas.GetSize() / sizeof(Entry); } public: constexpr ALWAYS_INLINE BufferBase() : m_pas() { /* ... */ } constexpr ALWAYS_INLINE BufferBase(const tipc::PointerAndSize &pas) : m_pas(pas) { /* ... */ } constexpr ALWAYS_INLINE BufferBase(uintptr_t ptr, size_t sz) : m_pas(ptr, sz) { /* ... */ } }; class InBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_In; public: constexpr ALWAYS_INLINE InBufferBase() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE InBufferBase(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE InBufferBase(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE InBufferBase(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } }; class OutBufferBase : public BufferBase { public: using BaseType = BufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | SfBufferAttr_Out; public: constexpr ALWAYS_INLINE OutBufferBase() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE OutBufferBase(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutBufferBase(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE OutBufferBase(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE OutBufferBase(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } }; template<u32 ExtraAttributes = 0> class InBufferImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr ALWAYS_INLINE InBufferImpl() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE InBufferImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE InBufferImpl(const void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE InBufferImpl(const u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE const u8 *GetPointer() const { return reinterpret_cast<const u8 *>(this->GetAddressImpl()); } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetSizeImpl<u8>(); } }; template<u32 ExtraAttributes = 0> class OutBufferImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes | ExtraAttributes; public: constexpr ALWAYS_INLINE OutBufferImpl() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE OutBufferImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutBufferImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE OutBufferImpl(void *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE OutBufferImpl(u8 *ptr, size_t sz) : BaseType(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE u8 *GetPointer() const { return reinterpret_cast<u8 *>(this->GetAddressImpl()); } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetSizeImpl<u8>(); } }; template<typename T> struct InArrayImpl : public InBufferBase { public: using BaseType = InBufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr ALWAYS_INLINE InArrayImpl() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE InArrayImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE InArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE InArrayImpl(const T *ptr, size_t num_elements) : BaseType(reinterpret_cast<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ } ALWAYS_INLINE const T *GetPointer() const { return reinterpret_cast<const T *>(this->GetAddressImpl()); } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetSizeImpl<T>(); } ALWAYS_INLINE const T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit ALWAYS_INLINE operator Span<const T>() const { return {this->GetPointer(), this->GetSize()}; } constexpr ALWAYS_INLINE Span<const T> ToSpan() const { return {this->GetPointer(), this->GetSize()}; } }; template<typename T> struct OutArrayImpl : public OutBufferBase { public: using BaseType = OutBufferBase; static constexpr u32 AdditionalAttributes = BaseType::AdditionalAttributes; public: constexpr ALWAYS_INLINE OutArrayImpl() : BaseType() { /* ... */ } constexpr ALWAYS_INLINE OutArrayImpl(const tipc::PointerAndSize &pas) : BaseType(pas) { /* ... */ } constexpr ALWAYS_INLINE OutArrayImpl(uintptr_t ptr, size_t sz) : BaseType(ptr, sz) { /* ... */ } ALWAYS_INLINE OutArrayImpl(T *ptr, size_t num_elements) : BaseType(reinterpret_cast<uintptr_t>(ptr), num_elements * sizeof(T)) { /* ... */ } ALWAYS_INLINE T *GetPointer() const { return reinterpret_cast<T *>(this->GetAddressImpl()); } constexpr ALWAYS_INLINE size_t GetSize() const { return this->GetSizeImpl<T>(); } ALWAYS_INLINE T &operator[](size_t i) const { return this->GetPointer()[i]; } constexpr explicit ALWAYS_INLINE operator Span<T>() const { return {this->GetPointer(), this->GetSize()}; } constexpr ALWAYS_INLINE Span<T> ToSpan() const { return {this->GetPointer(), this->GetSize()}; } }; } /* Buffer Types. */ using InBuffer = typename impl::InBufferImpl<>; // using InNonSecureBuffer = typename impl::InBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonSecure>; // using InNonDeviceBuffer = typename impl::InBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonDevice>; using OutBuffer = typename impl::OutBufferImpl<>; //using OutNonSecureBuffer = typename impl::OutBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonSecure>; //using OutNonDeviceBuffer = typename impl::OutBufferImpl<SfBufferAttr_HipcMapTransferAllowsNonDevice>; template<typename T> using InArray = typename impl::InArrayImpl<T>; template<typename T> using OutArray = typename impl::OutArrayImpl<T>; /* Attribute serialization structs. */ template<typename T> concept IsBuffer = std::derived_from<T, impl::BufferBaseTag>; template<typename T> requires IsBuffer<T> constexpr inline u32 BufferAttributes = SfBufferAttr_HipcMapAlias | T::AdditionalAttributes; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_common.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/ams.hpp> #include <stratosphere/os.hpp> #include <stratosphere/sm/sm_types.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_deferral_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> #include <stratosphere/tipc/tipc_object_holder.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> namespace ams::tipc { template<typename T> concept IsResumeKey = util::is_pod<T>::value && (0 < sizeof(T) && sizeof(T) <= sizeof(uintptr_t)); template<IsResumeKey ResumeKey> static constexpr ALWAYS_INLINE uintptr_t ConvertToInternalResumeKey(ResumeKey key) { if constexpr (std::same_as<ResumeKey, uintptr_t>) { return key; } else if constexpr (sizeof(key) == sizeof(uintptr_t)) { return std::bit_cast<uintptr_t>(key); } else { uintptr_t converted = 0; std::memcpy(std::addressof(converted), std::addressof(key), sizeof(key)); return converted; } } class DeferralManagerBase; namespace impl { class DeferrableBaseTag{}; } class DeferrableBaseImpl : public impl::DeferrableBaseTag { private: DeferralManagerBase *m_deferral_manager; ObjectHolder m_object_holder; uintptr_t m_resume_key; const u32 m_message_buffer_size; u8 m_message_buffer_base[0]; public: ALWAYS_INLINE DeferrableBaseImpl(u32 mb_size) : m_deferral_manager(nullptr), m_object_holder(), m_resume_key(), m_message_buffer_size(mb_size) { /* ... */ } ~DeferrableBaseImpl(); ALWAYS_INLINE void SetDeferralManager(DeferralManagerBase *manager, tipc::NativeHandle reply_target, ServiceObjectBase *object) { m_deferral_manager = manager; m_object_holder.InitializeForDeferralManager(reply_target, object); } ALWAYS_INLINE bool TestResume(uintptr_t key) const { return m_resume_key == key; } template<IsResumeKey ResumeKey> ALWAYS_INLINE void RegisterRetry(ResumeKey key) { m_resume_key = ConvertToInternalResumeKey(key); std::memcpy(m_message_buffer_base, tipc::GetMessageBuffer(), m_message_buffer_size); } template<IsResumeKey ResumeKey, typename F> ALWAYS_INLINE Result RegisterRetryIfDeferred(ResumeKey key, F f) { ON_RESULT_INCLUDED(tipc::ResultRequestDeferred) { this->RegisterRetry(key); }; R_RETURN(f()); } template<typename PortManager> ALWAYS_INLINE void TriggerResume(PortManager *port_manager) { /* Clear resume key. */ m_resume_key = 0; /* Restore message buffer. */ std::memcpy(tipc::GetMessageBuffer(), m_message_buffer_base, m_message_buffer_size); /* Process the request. */ return port_manager->ProcessDeferredRequest(m_object_holder); } protected: static consteval size_t GetMessageBufferOffsetBase(); }; static_assert(std::is_standard_layout<DeferrableBaseImpl>::value); #define TIPC_REGISTER_RETRY_ON_RESULT_REQUEST_DEFERRED(KEY) ON_RESULT_INCLUDED(tipc::ResultRequestDeferred) { this->RegisterRetry(KEY); } template<size_t _MessageBufferRequiredSize> class DeferrableBaseImplWithBuffer : public DeferrableBaseImpl { private: static constexpr size_t MessageBufferRequiredSize = _MessageBufferRequiredSize; private: u8 m_message_buffer[MessageBufferRequiredSize]; public: DeferrableBaseImplWithBuffer(); private: static consteval size_t GetMessageBufferOffset(); }; consteval size_t DeferrableBaseImpl::GetMessageBufferOffsetBase() { return AMS_OFFSETOF(DeferrableBaseImpl, m_message_buffer_base); } template<size_t _MessageBufferRequiredSize> consteval size_t DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>::GetMessageBufferOffset() { return AMS_OFFSETOF(DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>, m_message_buffer); } template<size_t _MessageBufferRequiredSize> ALWAYS_INLINE DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>::DeferrableBaseImplWithBuffer() : DeferrableBaseImpl(MessageBufferRequiredSize) { static_assert(GetMessageBufferOffsetBase() == GetMessageBufferOffset()); static_assert(sizeof(DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>) >= sizeof(DeferrableBaseImpl) + MessageBufferRequiredSize); } template<typename Interface, size_t MaximumDefaultRequestSize = 0> class DeferrableBase : public DeferrableBaseImplWithBuffer<std::max(Interface::MaximumRequestSize, MaximumDefaultRequestSize)> { private: using BaseImpl = DeferrableBaseImplWithBuffer<std::max(Interface::MaximumRequestSize, MaximumDefaultRequestSize)>; public: using BaseImpl::BaseImpl; }; template<class T> concept IsDeferrable = std::derived_from<T, impl::DeferrableBaseTag>; class DeferralManagerBase { NON_COPYABLE(DeferralManagerBase); NON_MOVEABLE(DeferralManagerBase); private: size_t m_object_count; DeferrableBaseImpl *m_objects_base[0]; public: ALWAYS_INLINE DeferralManagerBase() : m_object_count(0) { /* ... */ } void AddObject(DeferrableBaseImpl &object, tipc::NativeHandle reply_target, ServiceObjectBase *service_object) { /* Set ourselves as the manager for the object. */ object.SetDeferralManager(this, reply_target, service_object); /* Add the object to our entries. */ m_objects_base[m_object_count++] = std::addressof(object); } void RemoveObject(DeferrableBaseImpl *object) { /* If the object is present, remove it. */ for (size_t i = 0; i < m_object_count; ++i) { if (m_objects_base[i] == object) { std::swap(m_objects_base[i], m_objects_base[--m_object_count]); break; } } } ALWAYS_INLINE bool TestResume(uintptr_t resume_key) const { /* Try to resume all entries. */ for (size_t i = 0; i < m_object_count; ++i) { if (m_objects_base[i]->TestResume(resume_key)) { return true; } } return false; } template<typename PortManager> ALWAYS_INLINE void TriggerResume(PortManager *port_manager, uintptr_t resume_key) const { /* Try to resume all entries. */ for (size_t i = 0; i < m_object_count; ++i) { if (m_objects_base[i]->TestResume(resume_key)) { m_objects_base[i]->TriggerResume(port_manager); } } } protected: static consteval size_t GetObjectPointersOffsetBase(); }; static_assert(std::is_standard_layout<DeferralManagerBase>::value); inline DeferrableBaseImpl::~DeferrableBaseImpl() { AMS_ASSUME(m_deferral_manager != nullptr); m_deferral_manager->RemoveObject(this); } template<size_t N> requires (N > 0) class DeferralManager final : public DeferralManagerBase { private: DeferrableBaseImpl *m_objects[N]; public: DeferralManager(); private: static consteval size_t GetObjectPointersOffset(); }; consteval size_t DeferralManagerBase::GetObjectPointersOffsetBase() { return AMS_OFFSETOF(DeferralManagerBase, m_objects_base); } template<size_t N> requires (N > 0) consteval size_t DeferralManager<N>::GetObjectPointersOffset() { return AMS_OFFSETOF(DeferralManager<N>, m_objects); } template<size_t N> requires (N > 0) inline DeferralManager<N>::DeferralManager() : DeferralManagerBase() { static_assert(GetObjectPointersOffset() == GetObjectPointersOffsetBase()); static_assert(sizeof(DeferralManager<N>) == sizeof(DeferralManagerBase) + N * sizeof(DeferrableBaseImpl *)); } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_out.hpp> #include <stratosphere/tipc/tipc_pointer_and_size.hpp> namespace ams::tipc { /* TODO: How do InHandles work in tipc? No examples to work off of. */ class CopyHandle { private: CopyHandle(); }; class MoveHandle { private: MoveHandle(); }; template<> class Out<CopyHandle> { private: tipc::NativeHandle * const m_ptr; public: ALWAYS_INLINE Out(tipc::NativeHandle *p) : m_ptr(p) { /* ... */ } ALWAYS_INLINE void SetValue(tipc::NativeHandle v) const { *m_ptr = v; } ALWAYS_INLINE const tipc::NativeHandle &GetValue() const { return *m_ptr; } ALWAYS_INLINE tipc::NativeHandle *GetPointer() const { return m_ptr; } /* Convenience operators. */ ALWAYS_INLINE tipc::NativeHandle &operator*() const { return *m_ptr; } ALWAYS_INLINE tipc::NativeHandle *operator->() const { return m_ptr; } }; template<> class Out<MoveHandle> { private: tipc::NativeHandle * const m_ptr; public: ALWAYS_INLINE Out(tipc::NativeHandle *p) : m_ptr(p) { /* ... */ } ALWAYS_INLINE void SetValue(tipc::NativeHandle v) const { *m_ptr = v; } ALWAYS_INLINE const tipc::NativeHandle &GetValue() const { return *m_ptr; } ALWAYS_INLINE tipc::NativeHandle *GetPointer() const { return m_ptr; } /* Convenience operators. */ ALWAYS_INLINE tipc::NativeHandle &operator*() const { return *m_ptr; } ALWAYS_INLINE tipc::NativeHandle *operator->() const { return m_ptr; } }; using OutMoveHandle = tipc::Out<tipc::MoveHandle>; using OutCopyHandle = tipc::Out<tipc::CopyHandle>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_message_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::tipc { namespace impl { template<typename HandleType> class DummyMessageBuffer { public: class MessageHeader { public: MessageHeader() { AMS_ABORT("TODO"); } MessageHeader(const DummyMessageBuffer &) { AMS_ABORT("TODO"); } u16 GetTag() const { AMS_ABORT("TODO"); } }; class SpecialHeader { public: SpecialHeader() { AMS_ABORT("TODO"); } SpecialHeader(const DummyMessageBuffer &, const MessageHeader &) { AMS_ABORT("TODO"); } bool GetHasProcessId() const { AMS_ABORT("TODO"); } s32 GetCopyHandleCount() const { AMS_ABORT("TODO"); } }; public: DummyMessageBuffer(u32 *) { AMS_ABORT("TODO"); } DummyMessageBuffer(u32 *, size_t) { AMS_ABORT("TODO"); } void SetNull() const { AMS_ABORT("TODO"); } HandleType GetHandle(s32) const { AMS_ABORT("TODO"); } template<typename T> const T &GetRaw(s32) const { AMS_ABORT("TODO"); } static s32 GetSpecialDataIndex(const MessageHeader &, const SpecialHeader &) { AMS_ABORT("TODO"); } static s32 GetRawDataIndex(const MessageHeader &, const SpecialHeader &) { AMS_ABORT("TODO"); } }; } #if defined(ATMOSPHERE_OS_HORIZON) constexpr inline auto MaximumSessionsPerPort = svc::ArgumentHandleCountMax; using NativeHandle = svc::Handle; constexpr inline NativeHandle InvalidNativeHandle = svc::InvalidHandle; using MessageBuffer = ::ams::svc::ipc::MessageBuffer; ALWAYS_INLINE u32 *GetMessageBuffer() { return svc::ipc::GetMessageBuffer(); } constexpr ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle h) { return static_cast<u32>(h); } constexpr ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32 v) { return static_cast<NativeHandle>(v); } #elif defined(ATMOSPHERE_OS_WINDOWS) /* TODO */ constexpr inline auto MaximumSessionsPerPort = 0x40; using NativeHandle = void *; constexpr inline NativeHandle InvalidNativeHandle = nullptr; using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer<NativeHandle>; ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } #elif defined(ATMOSPHERE_OS_LINUX) /* TODO */ constexpr inline auto MaximumSessionsPerPort = 0x40; using NativeHandle = s32; constexpr inline NativeHandle InvalidNativeHandle = -1; using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer<NativeHandle>; ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } #elif defined(ATMOSPHERE_OS_MACOS) /* TODO */ constexpr inline auto MaximumSessionsPerPort = 0x40; using NativeHandle = s32; constexpr inline NativeHandle InvalidNativeHandle = -1; using MessageBuffer = ::ams::tipc::impl::DummyMessageBuffer<NativeHandle>; ALWAYS_INLINE u32 *GetMessageBuffer() { AMS_ABORT("TODO"); } ALWAYS_INLINE u32 EncodeNativeHandleForMessageQueue(NativeHandle) { AMS_ABORT("TODO"); } ALWAYS_INLINE NativeHandle DecodeNativeHandleForMessageQueue(u32) { AMS_ABORT("TODO"); } #else #error "Unknown OS for tipc platform types." #endif namespace impl { } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> namespace ams::tipc { class ObjectHolder { public: enum ObjectType : u8 { ObjectType_Invalid = 0, ObjectType_Port = 1, ObjectType_Session = 2, ObjectType_Deferral = ObjectType_Invalid, }; private: tipc::NativeHandle m_handle; ObjectType m_type; bool m_managed; tipc::ServiceObjectBase *m_object; private: void InitializeImpl(ObjectType type, tipc::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { /* Validate that the object isn't already constructed. */ AMS_ASSERT(m_type == ObjectType_Invalid); /* Set all fields. */ m_handle = handle; m_type = type; m_managed = managed; m_object = object; } public: constexpr inline ObjectHolder() : m_handle(tipc::InvalidNativeHandle), m_type(ObjectType_Invalid), m_managed(false), m_object(nullptr) { /* ... */ } void InitializeAsPort(tipc::NativeHandle handle) { /* NOTE: Nintendo sets ports as managed, but this will cause a nullptr-deref if one is ever closed. */ /* This is theoretically a non-issue, as ports can't be closed, but we will set ours as unmanaged, */ /* just in case. */ this->InitializeImpl(ObjectType_Port, handle, false, nullptr); } void InitializeAsSession(tipc::NativeHandle handle, bool managed, tipc::ServiceObjectBase *object) { this->InitializeImpl(ObjectType_Session, handle, managed, object); } void InitializeForDeferralManager(tipc::NativeHandle handle, tipc::ServiceObjectBase *object) { this->InitializeImpl(ObjectType_Deferral, handle, false, object); } void Destroy() { /* Validate that the object is constructed. */ AMS_ASSERT(m_type != ObjectType_Invalid); /* If we're managed, destroy the associated object. */ if (m_managed) { if (auto * const deleter = m_object->GetDeleter(); deleter != nullptr) { deleter->DeleteServiceObject(m_object); } } /* Reset all fields. */ m_handle = tipc::InvalidNativeHandle; m_type = ObjectType_Invalid; m_managed = false; m_object = nullptr; } constexpr tipc::NativeHandle GetHandle() const { return m_handle; } constexpr ObjectType GetType() const { return m_type; } constexpr tipc::ServiceObjectBase *GetObject() const { return m_object; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/impl/tipc_impl_message_api.hpp> #include <stratosphere/tipc/tipc_service_object.hpp> #include <stratosphere/tipc/tipc_object_holder.hpp> namespace ams::tipc { /* TODO: Put this in a better header. */ constexpr inline u16 MethodId_Invalid = 0x0; constexpr inline u16 MethodId_CloseSession = 0xF; class ObjectManagerBase { protected: struct Entry { util::TypedStorage<ObjectHolder> object; os::MultiWaitHolderType multi_wait_holder; }; private: os::SdkMutex m_mutex{}; Entry *m_entries_start{}; Entry *m_entries_end{}; os::MultiWaitType *m_multi_wait{}; private: Entry *FindEntry(tipc::NativeHandle handle) { for (Entry *cur = m_entries_start; cur != m_entries_end; ++cur) { if (GetReference(cur->object).GetHandle() == handle) { return cur; } } return nullptr; } Entry *FindEntry(os::MultiWaitHolderType *holder) { for (Entry *cur = m_entries_start; cur != m_entries_end; ++cur) { if (std::addressof(cur->multi_wait_holder) == holder) { return cur; } } return nullptr; } public: constexpr ObjectManagerBase() = default; void InitializeImpl(os::MultiWaitType *multi_wait, Entry *entries, size_t max_objects) { /* Set our multi wait. */ m_multi_wait = multi_wait; /* Setup entry pointers. */ m_entries_start = entries; m_entries_end = entries + max_objects; /* Construct all entries. */ for (size_t i = 0; i < max_objects; ++i) { util::ConstructAt(m_entries_start[i].object); } } void AddObject(ObjectHolder &object) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); /* Find an empty entry. */ auto *entry = this->FindEntry(tipc::InvalidNativeHandle); AMS_ABORT_UNLESS(entry != nullptr); /* Set the entry's object. */ GetReference(entry->object) = object; /* Setup the entry's holder. */ os::InitializeMultiWaitHolder(std::addressof(entry->multi_wait_holder), object.GetHandle()); os::LinkMultiWaitHolder(m_multi_wait, std::addressof(entry->multi_wait_holder)); } void CloseObject(tipc::NativeHandle handle) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); /* Find the matching entry. */ auto *entry = this->FindEntry(handle); AMS_ABORT_UNLESS(entry != nullptr); /* Finalize the entry's holder. */ os::UnlinkMultiWaitHolder(std::addressof(entry->multi_wait_holder)); os::FinalizeMultiWaitHolder(std::addressof(entry->multi_wait_holder)); /* Destroy the object. */ GetReference(entry->object).Destroy(); } Result ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, tipc::NativeHandle reply_target, os::MultiWaitType *multi_wait) { /* Declare signaled holder for processing ahead of time. */ os::MultiWaitHolderType *signaled_holder; /* Reply and receive until we get a newly signaled target. */ Result result = os::SdkReplyAndReceive(out_holder, reply_target, multi_wait); for (signaled_holder = *out_holder; signaled_holder == nullptr; signaled_holder = *out_holder) { result = os::SdkReplyAndReceive(out_holder, tipc::InvalidNativeHandle, multi_wait); } /* Find the entry matching the signaled holder. */ if (auto *entry = this->FindEntry(signaled_holder); entry != nullptr) { /* Get the output object. */ *out_object = GetReference(entry->object); *out_holder = nullptr; R_RETURN(result); } else { R_SUCCEED(); } } void Reply(tipc::NativeHandle reply_target) { return tipc::impl::Reply(reply_target); } Result ProcessRequest(ObjectHolder &object) { /* Get the message buffer. */ const MessageBuffer message_buffer(tipc::GetMessageBuffer()); /* Get the method id. */ const auto method_id = MessageBuffer::MessageHeader(message_buffer).GetTag(); /* Process for the method id. */ { /* Ensure that if we fail, we clean up any handles that get sent our way. */ ON_RESULT_FAILURE { const MessageBuffer::MessageHeader message_header(message_buffer); const MessageBuffer::SpecialHeader special_header(message_buffer, message_header); /* Determine the offset to the start of handles. */ auto offset = message_buffer.GetSpecialDataIndex(message_header, special_header); if (special_header.GetHasProcessId()) { offset += sizeof(u64) / sizeof(u32); } /* Close all copy handles. */ for (auto i = 0; i < special_header.GetCopyHandleCount(); ++i) { tipc::impl::CloseHandle(message_buffer.GetHandle(offset)); offset += sizeof(typename std::remove_reference<decltype(message_buffer.GetHandle(offset))>::type) / sizeof(u32); } }; /* Check that the method id is valid. */ R_UNLESS(method_id != MethodId_Invalid, tipc::ResultInvalidMethod()); /* Process the request. */ if (method_id != MethodId_CloseSession) { /* Process the generic method for the object. */ R_TRY(object.GetObject()->ProcessRequest()); } else { /* Validate that the close request is of valid format. */ using CloseSessionCommandMeta = impl::CommandMetaInfo<MethodId_CloseSession, std::tuple<>>; using CloseSessionProcessor = impl::CommandProcessor<CloseSessionCommandMeta>; R_TRY(CloseSessionProcessor::ValidateCommandFormat(message_buffer)); } } /* If we were asked to close the object, do so. */ if (method_id == MethodId_CloseSession) { /* Get the object handle. */ const auto handle = object.GetHandle(); /* Close the object itself. */ this->CloseObject(handle); /* Close the object's handle. */ /* NOTE: Nintendo does not check that this succeeds. */ R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); /* Return an error to signify we closed the object. */ R_THROW(tipc::ResultSessionClosed()); } /* We successfully processed, so we don't need to clean up handles. */ R_SUCCEED(); } }; template<size_t MaxObjects> class ObjectManager : public ObjectManagerBase { private: Entry m_entries_storage[MaxObjects]{}; public: constexpr ObjectManager() = default; void Initialize(os::MultiWaitType *multi_wait) { this->InitializeImpl(multi_wait, m_entries_storage, MaxObjects); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_out.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_pointer_and_size.hpp> namespace ams::tipc { namespace impl { struct OutBaseTag{}; } template<typename> struct IsOutForceEnabled : public std::false_type{}; template<> struct IsOutForceEnabled<::ams::Result> : public std::true_type{}; template<typename T> concept OutEnabled = (std::is_trivial<T>::value || IsOutForceEnabled<T>::value) && !std::is_pointer<T>::value; template<typename T> class Out : public impl::OutBaseTag { static_assert(OutEnabled<T>); public: static constexpr size_t TypeSize = sizeof(T); private: T *m_ptr; public: constexpr Out(uintptr_t p) : m_ptr(reinterpret_cast<T *>(p)) { /* ... */ } constexpr Out(T *p) : m_ptr(p) { /* ... */ } constexpr Out(const tipc::PointerAndSize &pas) : m_ptr(reinterpret_cast<T *>(pas.GetAddress())) { /* TODO: Is AMS_ABORT_UNLESS(pas.GetSize() >= sizeof(T)); necessary? */ } ALWAYS_INLINE void SetValue(const T& value) const { *m_ptr = value; } ALWAYS_INLINE const T &GetValue() const { return *m_ptr; } ALWAYS_INLINE T *GetPointer() const { return m_ptr; } /* Convenience operators. */ ALWAYS_INLINE T &operator*() const { return *m_ptr; } ALWAYS_INLINE T *operator->() const { return m_ptr; } }; template<typename T> class Out<T *> { static_assert(!std::is_same<T, T>::value, "Invalid tipc::Out<T> (Raw Pointer)"); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_pointer_and_size.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tipc/tipc_pointer_and_size.hpp> namespace ams::tipc { class PointerAndSize { private: uintptr_t m_pointer; size_t m_size; public: constexpr PointerAndSize() : m_pointer(0), m_size(0) { /* ... */ } constexpr PointerAndSize(uintptr_t ptr, size_t sz) : m_pointer(ptr), m_size(sz) { /* ... */ } PointerAndSize(void *ptr, size_t sz) : PointerAndSize(reinterpret_cast<uintptr_t>(ptr), sz) { /* ... */ } ALWAYS_INLINE void *GetPointer() const { return reinterpret_cast<void *>(m_pointer); } constexpr ALWAYS_INLINE uintptr_t GetAddress() const { return m_pointer; } constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_service_object.hpp> #include <stratosphere/tipc/tipc_object_manager.hpp> #include <stratosphere/tipc/tipc_deferral_manager.hpp> namespace ams::tipc { template<size_t NumSessions, typename Interface, typename Impl, template<typename, size_t> typename _Allocator> struct PortMeta { static constexpr inline size_t MaxSessions = NumSessions; static constexpr bool CanDeferInvokeRequest = IsDeferrable<Impl>; using ServiceObject = tipc::ServiceObject<Interface, Impl>; using Allocator = _Allocator<ServiceObject, NumSessions>; }; struct DummyDeferralManagerBase{}; template<size_t N> struct DummyDeferralManager : public DummyDeferralManagerBase {}; namespace impl { template<size_t ThreadStackSize, bool IsDeferralSupported, size_t NumPorts, typename... PortInfos> class ServerManagerImpl { private: static_assert(NumPorts == sizeof...(PortInfos)); static constexpr inline size_t MaxSessions = (PortInfos::MaxSessions + ...); /* Verify that we have at least one port. */ static_assert(NumPorts > 0); /* Verify that it's possible to service this many sessions, with our port manager count. */ static_assert(MaxSessions <= NumPorts * MaximumSessionsPerPort); static_assert(util::IsAligned(ThreadStackSize, os::ThreadStackAlignment)); alignas(os::ThreadStackAlignment) static constinit inline u8 s_port_stacks[ThreadStackSize * (NumPorts - 1)]; template<size_t Ix> AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) static constexpr inline size_t SessionsPerPortManager = (Ix == NumPorts - 1) ? ((MaxSessions / NumPorts) + MaxSessions % NumPorts) : ((MaxSessions / NumPorts)); template<size_t Ix> AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) using PortInfo = typename std::tuple_element<Ix, std::tuple<PortInfos...>>::type; static_assert(IsDeferralSupported == (PortInfos::CanDeferInvokeRequest || ...)); template<size_t Sessions> using DeferralManagerImplType = typename std::conditional<IsDeferralSupported, DeferralManager<Sessions>, DummyDeferralManager<Sessions>>::type; using DeferralManagerBaseType = typename std::conditional<IsDeferralSupported, DeferralManagerBase, DummyDeferralManagerBase>::type; template<size_t Ix> AMS_CONCEPTS_REQUIRES_IF_SUPPORTED(Ix < NumPorts) static constexpr inline bool IsPortDeferrable = PortInfo<Ix>::CanDeferInvokeRequest; public: class PortManagerBase { public: enum MessageType : u8 { MessageType_AddSession = 0, MessageType_TriggerResume = 1, }; protected: s32 m_id; std::atomic<s32> m_num_sessions; s32 m_port_number; os::MultiWaitType m_multi_wait; os::MessageQueueType m_message_queue; os::MultiWaitHolderType m_message_queue_holder; uintptr_t m_message_queue_storage[MaxSessions]; ServerManagerImpl *m_server_manager; ObjectManagerBase *m_object_manager; DeferralManagerBaseType *m_deferral_manager; public: PortManagerBase() : m_id(), m_num_sessions(), m_port_number(), m_multi_wait(), m_message_queue(), m_message_queue_holder(), m_message_queue_storage(), m_server_manager(), m_object_manager(), m_deferral_manager() { /* Setup our message queue. */ os::InitializeMessageQueue(std::addressof(m_message_queue), m_message_queue_storage, util::size(m_message_queue_storage)); os::InitializeMultiWaitHolder(std::addressof(m_message_queue_holder), std::addressof(m_message_queue), os::MessageQueueWaitType::ForNotEmpty); } constexpr s32 GetPortIndex() const { return m_port_number; } s32 GetSessionCount() const { return m_num_sessions; } void InitializeBase(s32 id, ServerManagerImpl *sm, DeferralManagerBaseType *dm, ObjectManagerBase *om) { /* Set our id. */ m_id = id; /* Set our server manager. */ m_server_manager = sm; /* Reset our session count. */ m_num_sessions = 0; /* Initialize our multi wait. */ os::InitializeMultiWait(std::addressof(m_multi_wait)); os::LinkMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_message_queue_holder)); /* Initialize our object manager. */ m_object_manager = om; /* Initialize our deferral manager. */ m_deferral_manager = dm; } void RegisterPort(s32 index, tipc::NativeHandle port_handle) { /* Set our port number. */ m_port_number = index; /* Create an object holder for the port. */ tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsPort(port_handle); /* Register the object. */ m_object_manager->AddObject(object); } tipc::NativeHandle ProcessRequest(ObjectHolder &object) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); /* Process the request. */ const Result result = m_object_manager->ProcessRequest(object); if (R_SUCCEEDED(result)) { /* We should reply only if the request isn't deferred. */ return !IsRequestDeferred() ? object.GetHandle() : tipc::InvalidNativeHandle; } else { /* Processing failed, so note the session as closed (or close it). */ this->CloseSessionIfNecessary(object, !tipc::ResultSessionClosed::Includes(result)); /* We shouldn't reply on failure. */ return tipc::InvalidNativeHandle; } } template<bool Enable = IsDeferralSupported, typename = typename std::enable_if<Enable>::type> void ProcessDeferredRequest(ObjectHolder &object) { static_assert(Enable == IsDeferralSupported); if (const auto reply_target = this->ProcessRequest(object); reply_target != tipc::InvalidNativeHandle) { m_object_manager->Reply(reply_target); } } bool ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, tipc::NativeHandle reply_target) { /* If we don't have a reply target, clear our message buffer. */ if (reply_target == tipc::InvalidNativeHandle) { tipc::MessageBuffer(tipc::GetMessageBuffer()).SetNull(); } /* Try to reply/receive. */ const Result result = m_object_manager->ReplyAndReceive(out_holder, out_object, reply_target, std::addressof(m_multi_wait)); /* Acquire exclusive access to the server manager. */ std::scoped_lock lk(m_server_manager->GetMutex()); /* Handle the result. */ R_TRY_CATCH(result) { R_CATCH(os::ResultSessionClosedForReceive, os::ResultReceiveListBroken) { /* Close the object. */ this->CloseSession(*out_object); /* We don't have anything to process. */ return false; } } R_END_TRY_CATCH_WITH_ABORT_UNLESS; return true; } void AddSession(tipc::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { /* Create an object holder for the session. */ tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsSession(session_handle, true, service_object); /* Register the object. */ m_object_manager->AddObject(object); } void ProcessMessages() { /* While we have messages in our queue, receive and handle them. */ uintptr_t message_type, message_data; while (os::TryReceiveMessageQueue(std::addressof(message_type), std::addressof(m_message_queue))) { /* Receive the message's data. */ os::ReceiveMessageQueue(std::addressof(message_data), std::addressof(m_message_queue)); /* Handle the specific message. */ switch (static_cast<MessageType>(static_cast<typename std::underlying_type<MessageType>::type>(message_type))) { case MessageType_AddSession: { /* Get the handle from where it's packed into the message type. */ const tipc::NativeHandle session_handle = tipc::DecodeNativeHandleForMessageQueue(message_type >> BITSIZEOF(u32)); /* Allocate a service object for the port. */ auto *service_object = m_server_manager->AllocateObject(static_cast<size_t>(message_data), session_handle, *m_deferral_manager); /* Add the newly-created service object. */ this->AddSession(session_handle, service_object); } break; case MessageType_TriggerResume: if constexpr (IsDeferralSupported) { /* Perform the resume. */ this->OnTriggerResume(message_data); } break; AMS_UNREACHABLE_DEFAULT_CASE(); } } } void CloseSession(ObjectHolder &object) { /* Get the object's handle. */ const auto handle = object.GetHandle(); /* Close the object with our manager. */ m_object_manager->CloseObject(handle); /* Close the handle itself. */ R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); /* Decrement our session count. */ --m_num_sessions; } void CloseSessionIfNecessary(ObjectHolder &object, bool necessary) { if (necessary) { /* Get the object's handle. */ const auto handle = object.GetHandle(); /* Close the object with our manager. */ m_object_manager->CloseObject(handle); /* Close the handle itself. */ R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); } /* Decrement our session count. */ --m_num_sessions; } bool TestResume(uintptr_t key) { if constexpr (IsDeferralSupported) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); /* Check to see if the key corresponds to some deferred message. */ return m_deferral_manager->TestResume(key); } else { return false; } } void TriggerResume(uintptr_t key) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); /* Send the key as a message. */ os::SendMessageQueue(std::addressof(m_message_queue), static_cast<uintptr_t>(MessageType_TriggerResume)); os::SendMessageQueue(std::addressof(m_message_queue), key); } void TriggerAddSession(tipc::NativeHandle session_handle, size_t port_index) { /* Increment our session count. */ ++m_num_sessions; /* Send information about the session as a message. */ os::SendMessageQueue(std::addressof(m_message_queue), static_cast<uintptr_t>(MessageType_AddSession) | (static_cast<u64>(tipc::EncodeNativeHandleForMessageQueue(session_handle)) << BITSIZEOF(u32))); os::SendMessageQueue(std::addressof(m_message_queue), static_cast<uintptr_t>(port_index)); } private: void OnTriggerResume(uintptr_t key) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); /* Trigger the resume. */ m_deferral_manager->TriggerResume(this, key); } public: static bool IsRequestDeferred() { if constexpr (IsDeferralSupported) { /* Get the message buffer. */ const tipc::MessageBuffer message_buffer(tipc::GetMessageBuffer()); /* Parse the hipc headers. */ const tipc::MessageBuffer::MessageHeader message_header(message_buffer); const tipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); /* Determine raw data index. */ const auto raw_data_offset = message_buffer.GetRawDataIndex(message_header, special_header); /* Result is the first raw data word. */ const Result method_result = message_buffer.GetRaw<u32>(raw_data_offset); /* Check that the result is the special deferral result. */ return tipc::ResultRequestDeferred::Includes(method_result); } else { /* If deferral isn't supported, requests are never deferred. */ return false; } } }; template<typename PortInfo, size_t PortSessions> class PortManagerImpl final : public PortManagerBase { private: DeferralManagerImplType<PortSessions> m_deferral_manager_impl; tipc::ObjectManager<1 + PortSessions> m_object_manager_impl; public: PortManagerImpl() : PortManagerBase(), m_deferral_manager_impl(), m_object_manager_impl() { /* ... */ } void Initialize(s32 id, ServerManagerImpl *sm) { /* Initialize our base. */ this->InitializeBase(id, sm, std::addressof(m_deferral_manager_impl), std::addressof(m_object_manager_impl)); /* Initialize our object manager. */ m_object_manager_impl.Initialize(std::addressof(this->m_multi_wait)); } }; template<size_t Ix> using PortManager = PortManagerImpl<PortInfo<Ix>, SessionsPerPortManager<Ix>>; using PortManagerTuple = decltype([]<size_t... Ix>(std::index_sequence<Ix...>) { return std::tuple<PortManager<Ix>...>{}; }(std::make_index_sequence<NumPorts>())); using PortAllocatorTuple = std::tuple<typename PortInfos::Allocator...>; private: os::SdkRecursiveMutex m_mutex; PortManagerTuple m_port_managers; PortAllocatorTuple m_port_allocators; os::ThreadType m_port_threads[NumPorts - 1]; private: template<size_t Ix> ALWAYS_INLINE auto &GetPortManager() { return std::get<Ix>(m_port_managers); } template<size_t Ix> ALWAYS_INLINE const auto &GetPortManager() const { return std::get<Ix>(m_port_managers); } template<size_t Ix> void LoopAutoForPort() { R_ABORT_UNLESS(this->LoopProcess(this->GetPortManager<Ix>())); } template<size_t Ix> static void LoopAutoForPortThreadFunction(void *_this) { static_cast<ServerManagerImpl *>(_this)->LoopAutoForPort<Ix>(); } template<size_t Ix> void InitializePortThread(s32 priority, const char *name) { /* Create the thread. */ R_ABORT_UNLESS(os::CreateThread(m_port_threads + Ix, &LoopAutoForPortThreadFunction<Ix>, this, s_port_stacks + Ix, ThreadStackSize, priority)); /* Set the thread name pointer. */ if (name != nullptr) { os::SetThreadNamePointer(m_port_threads + Ix, name); } /* Start the thread. */ os::StartThread(m_port_threads + Ix); } public: ServerManagerImpl() : m_mutex(), m_port_managers(), m_port_allocators() { /* ... */ } os::SdkRecursiveMutex &GetMutex() { return m_mutex; } void Initialize() { /* Initialize our port managers. */ [this]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { (this->GetPortManager<Ix>().Initialize(static_cast<s32>(Ix), this), ...); }(std::make_index_sequence<NumPorts>()); } template<size_t Ix> void RegisterPort(tipc::NativeHandle port_handle) { this->GetPortManager<Ix>().RegisterPort(static_cast<s32>(Ix), port_handle); } template<size_t Ix> void RegisterPort(sm::ServiceName service_name, size_t max_sessions) { /* Register service. */ tipc::NativeHandle port_handle; R_ABORT_UNLESS(sm::RegisterService(std::addressof(port_handle), service_name, max_sessions, false)); /* Register the port handle. */ this->RegisterPort<Ix>(port_handle); } void LoopAuto() { /* If we have additional threads, create and start them. */ if constexpr (NumPorts > 1) { const auto thread_priority = os::GetThreadPriority(os::GetCurrentThread()); [thread_priority, this]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { /* Create all threads. */ (this->InitializePortThread<Ix>(thread_priority, nullptr), ...); }(std::make_index_sequence<NumPorts - 1>()); } /* Process for the last port. */ this->LoopAutoForPort<NumPorts - 1>(); } void LoopAuto(int priority, const char *name) { /* If we have additional threads, create and start them. */ if constexpr (NumPorts > 1) { [priority, name, this]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { /* Create all threads. */ (this->InitializePortThread<Ix>(priority, name), ...); }(std::make_index_sequence<NumPorts - 1>()); } /* Check current thread. */ { AMS_ASSERT(priority == os::GetThreadPriority(os::GetCurrentThread())); /* N does not do: os::SetThreadNamePointer(os::GetCurrentThread(), name); */ } /* Process for the last port. */ this->LoopAutoForPort<NumPorts - 1>(); } tipc::ServiceObjectBase *AllocateObject(size_t port_index, tipc::NativeHandle handle, DeferralManagerBaseType &deferral_manager) { /* Check that the port index is valid. */ AMS_ABORT_UNLESS(port_index < NumPorts); /* Try to allocate from each port, in turn. */ tipc::ServiceObjectBase *allocated = nullptr; [this, port_index, handle, &deferral_manager, &allocated]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { (this->TryAllocateObject<Ix>(port_index, handle, deferral_manager, allocated), ...); }(std::make_index_sequence<NumPorts>()); /* Return the allocated object. */ AMS_ABORT_UNLESS(allocated != nullptr); return allocated; } template<IsResumeKey ResumeKey> void TriggerResume(const ResumeKey &resume_key) { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(m_mutex); /* Convert to internal resume key. */ const auto internal_resume_key = ConvertToInternalResumeKey(resume_key); /* Check/trigger resume on each of our ports. */ [this, internal_resume_key]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { (this->TriggerResumeImpl<Ix>(internal_resume_key), ...); }(std::make_index_sequence<NumPorts>()); } Result AddSession(tipc::NativeHandle *out, tipc::ServiceObjectBase *object) { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(m_mutex); /* Create a handle for the session. */ tipc::NativeHandle session_handle; R_TRY(tipc::impl::CreateSession(std::addressof(session_handle), static_cast<tipc::NativeHandle *>(out), false, 0)); /* Select the best port manager. */ PortManagerBase *best_manager = nullptr; s32 best_sessions = -1; [this, &best_manager, &best_sessions]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { (this->TrySelectBetterPort<Ix>(best_manager, best_sessions), ...); }(std::make_index_sequence<NumPorts>()); /* Add the session to the least burdened manager. */ best_manager->AddSession(session_handle, object); R_SUCCEED(); } private: template<size_t Ix> requires (Ix < NumPorts) void TryAllocateObject(size_t port_index, tipc::NativeHandle handle, DeferralManagerBaseType &deferral_manager, tipc::ServiceObjectBase *&allocated) { /* Check that the port index matches. */ if (port_index == Ix) { /* Check that we haven't already allocated. */ AMS_ABORT_UNLESS(allocated == nullptr); /* Get the allocator. */ auto &allocator = std::get<Ix>(m_port_allocators); /* Allocate the object. */ auto * const new_object = allocator.Allocate(); AMS_ABORT_UNLESS(new_object != nullptr); /* If we should, set the object's deleter. */ if constexpr (IsServiceObjectDeleter<typename std::tuple_element<Ix, PortAllocatorTuple>::type>) { new_object->SetDeleter(std::addressof(allocator)); } /* If we should, set the object's deferral manager. */ if constexpr (IsPortDeferrable<Ix>) { deferral_manager.AddObject(new_object->GetImpl(), handle, new_object); } /* Set the allocated object. */ allocated = new_object; } } Result LoopProcess(PortManagerBase &port_manager) { /* Process requests forever. */ tipc::NativeHandle reply_target = tipc::InvalidNativeHandle; while (true) { /* Reply to our pending request, and wait to receive a new one. */ os::MultiWaitHolderType *signaled_holder = nullptr; tipc::ObjectHolder signaled_object{}; while (!port_manager.ReplyAndReceive(std::addressof(signaled_holder), std::addressof(signaled_object), reply_target)) { reply_target = tipc::InvalidNativeHandle; signaled_object = {}; } if (signaled_holder == nullptr) { /* A session was signaled, accessible via signaled_object. */ switch (signaled_object.GetType()) { case ObjectHolder::ObjectType_Port: { /* Try to accept a new session */ tipc::NativeHandle session_handle; if (R_SUCCEEDED(tipc::impl::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { this->TriggerAddSession(session_handle, static_cast<size_t>(port_manager.GetPortIndex())); } /* We have nothing to reply to. */ reply_target = tipc::InvalidNativeHandle; } break; case ObjectHolder::ObjectType_Session: { /* Process the request */ reply_target = port_manager.ProcessRequest(signaled_object); } break; AMS_UNREACHABLE_DEFAULT_CASE(); } } else { /* Our message queue was signaled. */ port_manager.ProcessMessages(); /* We have nothing to reply to. */ reply_target = tipc::InvalidNativeHandle; } } } void TriggerAddSession(tipc::NativeHandle session_handle, size_t port_index) { /* Acquire exclusive access to ourselves. */ std::scoped_lock lk(m_mutex); /* Select the best port manager. */ PortManagerBase *best_manager = nullptr; s32 best_sessions = -1; [this, &best_manager, &best_sessions]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA { (this->TrySelectBetterPort<Ix>(best_manager, best_sessions), ...); }(std::make_index_sequence<NumPorts>()); /* Trigger the session add on the least-burdened manager. */ best_manager->TriggerAddSession(session_handle, port_index); } template<size_t Ix> requires (Ix < NumPorts) void TrySelectBetterPort(PortManagerBase *&best_manager, s32 &best_sessions) { auto &cur_manager = this->GetPortManager<Ix>(); const auto cur_sessions = cur_manager.GetSessionCount(); /* NOTE: It's unknown how nintendo handles the case where the last manager has more sessions (to cover the remainder). */ /* Our algorithm diverges from theirs (it does not do std::min bounds capping), to accommodate remainder ports. */ /* If we learn how they handle this edge case, we can change our ways to match theirs. */ if constexpr (Ix == 0) { best_manager = std::addressof(cur_manager); best_sessions = cur_sessions; } else { static_assert(SessionsPerPortManager<Ix - 1> == SessionsPerPortManager<0>); static_assert(SessionsPerPortManager<Ix - 1> <= SessionsPerPortManager<Ix>); if (cur_sessions < best_sessions || best_sessions >= static_cast<s32>(SessionsPerPortManager<Ix - 1>)) { best_manager = std::addressof(cur_manager); best_sessions = cur_sessions; } } } template<size_t Ix> void TriggerResumeImpl(uintptr_t resume_key) { /* Get the port manager. */ auto &port_manager = this->GetPortManager<Ix>(); /* If we should, trigger a resume. */ if (port_manager.TestResume(resume_key)) { port_manager.TriggerResume(resume_key); } } }; template<size_t ThreadStackSize, typename PortInfo> class ServerManagerImpl<ThreadStackSize, false, 1, PortInfo> { private: static constexpr inline size_t NumPorts = 1; static constexpr inline size_t MaxSessions = PortInfo::MaxSessions; /* Verify that it's possible to service this many sessions, with our port manager count. */ static_assert(MaxSessions <= MaximumSessionsPerPort); public: class PortManagerBase { protected: os::MultiWaitType m_multi_wait; ObjectManagerBase *m_object_manager; public: constexpr PortManagerBase() : m_multi_wait(), m_object_manager() { /* ... */ } void InitializeBase(ObjectManagerBase *om) { /* Initialize our multi wait. */ os::InitializeMultiWait(std::addressof(m_multi_wait)); /* Initialize our object manager. */ m_object_manager = om; } void RegisterPort(tipc::NativeHandle port_handle) { /* Create an object holder for the port. */ tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsPort(port_handle); /* Register the object. */ m_object_manager->AddObject(object); } tipc::NativeHandle ProcessRequest(ObjectHolder &object) { /* Process the request. */ const Result result = m_object_manager->ProcessRequest(object); if (R_SUCCEEDED(result)) { /* We should reply only if the request isn't deferred. */ return object.GetHandle(); } else { /* Processing failed, so close the session if we need to. */ if (!tipc::ResultSessionClosed::Includes(result)) { this->CloseSession(object); } /* We shouldn't reply on failure. */ return tipc::InvalidNativeHandle; } } bool ReplyAndReceive(ObjectHolder *out_object, tipc::NativeHandle reply_target) { /* If we don't have a reply target, clear our message buffer. */ if (reply_target == tipc::InvalidNativeHandle) { tipc::MessageBuffer(tipc::GetMessageBuffer()).SetNull(); } /* Try to reply/receive. */ const Result result = [&]() ALWAYS_INLINE_LAMBDA -> Result { os::MultiWaitHolderType *signaled_holder = nullptr; ON_SCOPE_EXIT { AMS_ABORT_UNLESS(signaled_holder == nullptr); }; return m_object_manager->ReplyAndReceive(std::addressof(signaled_holder), out_object, reply_target, std::addressof(m_multi_wait)); }(); /* Handle the result. */ if (R_FAILED(result)) { /* Close the object. */ this->CloseSession(*out_object); /* We don't have anything to process. */ return false; } return true; } void AddSession(tipc::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) { /* Create an object holder for the session. */ tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsSession(session_handle, true, service_object); /* Register the object. */ m_object_manager->AddObject(object); } void CloseSession(ObjectHolder &object) { /* Get the object's handle. */ const auto handle = object.GetHandle(); /* Close the object with our manager. */ m_object_manager->CloseObject(handle); /* Close the handle itself. */ R_ABORT_UNLESS(tipc::impl::CloseHandle(handle)); } }; class PortManagerImpl final : public PortManagerBase { private: tipc::ObjectManager<1 + MaxSessions> m_object_manager_impl; public: constexpr PortManagerImpl() : PortManagerBase(), m_object_manager_impl() { /* ... */ } void Initialize() { /* Initialize our base. */ this->InitializeBase(std::addressof(m_object_manager_impl)); /* Initialize our object manager. */ m_object_manager_impl.Initialize(std::addressof(this->m_multi_wait)); } }; using PortManager = PortManagerImpl; private: PortManager m_port_manager; typename PortInfo::Allocator m_port_allocator; public: constexpr ServerManagerImpl() : m_port_manager(), m_port_allocator() { /* ... */ } void Initialize() { /* Initialize our port manager. */ m_port_manager.Initialize(); } void RegisterPort(tipc::NativeHandle port_handle) { m_port_manager.RegisterPort(port_handle); } void RegisterPort(sm::ServiceName service_name, size_t max_sessions) { /* Register service. */ tipc::NativeHandle port_handle; R_ABORT_UNLESS(sm::RegisterService(std::addressof(port_handle), service_name, max_sessions, false)); /* Register the port handle. */ this->RegisterPort(port_handle); } void LoopAuto() { /* Process for the only port. */ this->LoopProcess(m_port_manager); } tipc::ServiceObjectBase *AllocateObject() { /* Allocate the object. */ auto * const new_object = m_port_allocator.Allocate(); AMS_ABORT_UNLESS(new_object != nullptr); /* If we should, set the object's deleter. */ if constexpr (IsServiceObjectDeleter<typename PortInfo::Allocator>) { new_object->SetDeleter(std::addressof(m_port_allocator)); } return new_object; } Result AddSession(tipc::NativeHandle *out, tipc::ServiceObjectBase *object) { /* Create a handle for the session. */ tipc::NativeHandle session_handle; R_TRY(tipc::impl::CreateSession(std::addressof(session_handle), static_cast<tipc::NativeHandle *>(out), false, 0)); /* Add the session to our manager. */ m_port_manager.AddSession(session_handle, object); R_SUCCEED(); } private: void LoopProcess(PortManagerBase &port_manager) { /* Process requests forever. */ tipc::NativeHandle reply_target = tipc::InvalidNativeHandle; while (true) { /* Reply to our pending request, and wait to receive a new one. */ tipc::ObjectHolder signaled_object{}; while (!port_manager.ReplyAndReceive(std::addressof(signaled_object), reply_target)) { reply_target = tipc::InvalidNativeHandle; } /* A session was signaled, accessible via signaled_object. */ switch (signaled_object.GetType()) { case ObjectHolder::ObjectType_Port: { /* Try to accept a new session */ tipc::NativeHandle session_handle; if (R_SUCCEEDED(tipc::impl::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) { port_manager.AddSession(session_handle, this->AllocateObject()); } /* We have nothing to reply to. */ reply_target = tipc::InvalidNativeHandle; } break; case ObjectHolder::ObjectType_Session: { /* Process the request */ reply_target = port_manager.ProcessRequest(signaled_object); } break; AMS_UNREACHABLE_DEFAULT_CASE(); } } } }; } template<size_t ThreadStackSize, typename... PortInfos> using ServerManagerImpl = impl::ServerManagerImpl<ThreadStackSize, (PortInfos::CanDeferInvokeRequest || ...), sizeof...(PortInfos), PortInfos...>; template<typename... PortInfos> using ServerManager = ServerManagerImpl<os::MemoryPageSize, PortInfos...>; template<size_t ThreadStackSize, typename... PortInfos> using ServerManagerWithThreadStack = ServerManagerImpl<ThreadStackSize, PortInfos...>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> #include <stratosphere/tipc/impl/tipc_impl_template_base.hpp> namespace ams::tipc { namespace impl { template<typename Impl> class EmplacedImplHolderBaseGetter { public: using Type = Impl; }; template<typename Impl> class EmplacedImplHolder { template<typename, typename, typename, typename, typename> friend class impl::ImplTemplateBaseT; private: using Impl2 = typename EmplacedImplHolderBaseGetter<Impl>::Type; static_assert(!std::is_abstract<Impl2>::value); private: Impl2 m_impl; private: template<typename... Args> constexpr explicit EmplacedImplHolder(Args &&... args) : m_impl(std::forward<Args>(args)...) { /* ... */ } public: static constexpr Impl *GetImplPointer(EmplacedImplHolder *holder) { return std::addressof(holder->m_impl); } }; } template<typename Interface, typename Impl> class ServiceObject final : public impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>> { private: using ImplBase = impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>>; public: using ImplBase::ImplBase; constexpr Impl &GetImpl() { return *impl::EmplacedImplHolder<Impl>::GetImplPointer(this); } }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object_base.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_message_types.hpp> namespace ams::tipc { class ServiceObjectBase; class ServiceObjectDeleter { public: virtual void DeleteServiceObject(ServiceObjectBase *object) = 0; }; template<typename T> concept IsServiceObjectDeleter = std::derived_from<T, ServiceObjectDeleter>; class ServiceObjectBase { private: ServiceObjectDeleter *m_deleter; public: constexpr ALWAYS_INLINE ServiceObjectBase() : m_deleter(nullptr) { /* ... */ } ALWAYS_INLINE void SetDeleter(ServiceObjectDeleter *deleter) { m_deleter = deleter; } ALWAYS_INLINE ServiceObjectDeleter *GetDeleter() const { return m_deleter; } virtual ~ServiceObjectBase() { /* ... */ } virtual Result ProcessRequest() = 0; }; template<typename T> concept IsServiceObject = std::derived_from<T, ServiceObjectBase>; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tipc.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tipc/tipc_service_object.hpp> #include <stratosphere/tipc/tipc_allocators.hpp> #include <stratosphere/tipc/impl/tipc_impl_command_serialization.hpp> #include <stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp> #include <stratosphere/tipc/tipc_object_manager.hpp> #include <stratosphere/tipc/tipc_server_manager.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_directory_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_directory.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_DIRECTORY_ACCESSOR_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetEntryCount, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Read, (ams::sf::Out<s64> out, const ams::sf::OutMapAliasArray<fs::DirectoryEntry> &out_entries), (out, out_entries)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetPriorityForDirectory, (s32 priority), (priority)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetPriorityForDirectory, (ams::sf::Out<s32> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::tma, IDirectoryAccessor, AMS_TMA_I_DIRECTORY_ACCESSOR_INTERFACE_INFO, 0x070BADB5) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_file_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/fs/fs_file.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_FILE_ACCESSOR_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, ReadFile, (ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, ams::fs::ReadOption option), (out, offset, buffer, option)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, WriteFile, (s64 offset, const ams::sf::InNonSecureBuffer &buffer, ams::fs::WriteOption option), (offset, buffer, option)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetFileSize, (ams::sf::Out<s64> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, SetFileSize, (s64 size), (size)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, FlushFile, (), ()) \ AMS_SF_METHOD_INFO(C, H, 5, Result, SetPriorityForFile, (s32 priority), (priority)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetPriorityForFile, (ams::sf::Out<s32> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::tma, IFileAccessor, AMS_TMA_I_FILE_ACCESSOR_INTERFACE_INFO, 0x985A04E3) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_file_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tma/tma_i_directory_accessor.hpp> #include <stratosphere/tma/tma_i_file_accessor.hpp> #include <stratosphere/tma/tma_path.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_FILE_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenFile, (sf::Out<sf::SharedPointer<tma::IFileAccessor>> out, const tma::Path &path, u32 open_mode, bool case_sensitive), (out, path, open_mode, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, FileExists, (sf::Out<bool> out, const tma::Path &path, bool case_sensitive), (out, path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, DeleteFile, (const tma::Path &path, bool case_sensitive), (path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, RenameFile, (const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive), (old_path, new_path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetIOType, (sf::Out<s32> out, const tma::Path &path, bool case_sensitive), (out, path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, OpenDirectory, (sf::Out<sf::SharedPointer<tma::IDirectoryAccessor>> out, const tma::Path &path, s32 open_mode, bool case_sensitive), (out, path, open_mode, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, DirectoryExists, (sf::Out<bool> out, const tma::Path &path, bool case_sensitive), (out, path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, CreateDirectory, (const tma::Path &path, bool case_sensitive), (path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, DeleteDirectory, (const tma::Path &path, bool recursively, bool case_sensitive), (path, recursively, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, RenameDirectory, (const tma::Path &old_path, const tma::Path &new_path, bool case_sensitive), (old_path, new_path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CreateFile, (const tma::Path &path, s64 size, bool case_sensitive), (path, size, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetFileTimeStamp, (sf::Out<u64> out_create, sf::Out<u64> out_access, sf::Out<u64> out_modify, const tma::Path &path, bool case_sensitive), (out_create, out_access, out_modify, path, case_sensitive)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetCaseSensitivePath, (const tma::Path &path, const sf::OutBuffer &out), (path, out)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, GetDiskFreeSpaceExW, (sf::Out<s64> out_free, sf::Out<s64> out_total, sf::Out<s64> out_total_free, const tma::Path &path), (out_free, out_total, out_total_free, path)) AMS_SF_DEFINE_INTERFACE(ams::tma, IFileManager, AMS_TMA_I_FILE_MANAGER_INTERFACE_INFO, 0xA15AF3E1) /* Prior to system version 6.0.0, case sensitivity was not parameterized. */ #define AMS_TMA_I_DEPRECATED_FILE_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, OpenFile, (sf::Out<sf::SharedPointer<tma::IFileAccessor>> out, const tma::Path &path, u32 open_mode), (out, path, open_mode)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, FileExists, (sf::Out<bool> out, const tma::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, DeleteFile, (const tma::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, RenameFile, (const tma::Path &old_path, const tma::Path &new_path), (old_path, new_path)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetIOType, (sf::Out<s32> out, const tma::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, OpenDirectory, (sf::Out<sf::SharedPointer<tma::IDirectoryAccessor>> out, const tma::Path &path, s32 open_mode), (out, path, open_mode)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, DirectoryExists, (sf::Out<bool> out, const tma::Path &path), (out, path)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, CreateDirectory, (const tma::Path &path), (path)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, DeleteDirectory, (const tma::Path &path, bool recursively), (path, recursively)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, RenameDirectory, (const tma::Path &old_path, const tma::Path &new_path), (old_path, new_path)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, CreateFile, (const tma::Path &path, s64 size), (path, size)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetFileTimeStamp, (sf::Out<u64> out_create, sf::Out<u64> out_access, sf::Out<u64> out_modify, const tma::Path &path), (out_create, out_access, out_modify, path)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetCaseSensitivePath, (const tma::Path &path, const sf::OutBuffer &out), (path, out)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, GetDiskFreeSpaceExW, (sf::Out<s64> out_free, sf::Out<s64> out_total, sf::Out<s64> out_total_free, const tma::Path &path), (out_free, out_total, out_total_free, path)) AMS_SF_DEFINE_INTERFACE(ams::tma, IDeprecatedFileManager, AMS_TMA_I_DEPRECATED_FILE_MANAGER_INTERFACE_INFO, 0xA15AF3E1) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_htc_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_HTC_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetEnvironmentVariable, (sf::Out<s32> out_size, const sf::OutBuffer &out, const sf::InBuffer &name), (out_size, out, name)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetEnvironmentVariableLength, (sf::Out<s32> out_size, const sf::InBuffer &name), (out_size, name)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostConnectionEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetHostDisconnectionEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, GetHostConnectionEventForSystem, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetHostDisconnectionEventForSystem, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetBridgeIpAddress, (const sf::OutBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetBridgePort, (const sf::OutBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, SetCradleAttached, (bool attached), (attached)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, GetBridgeSubnetMask, (const sf::OutBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, GetBridgeMacAddress, (const sf::OutBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetWorkingDirectoryPath, (const sf::OutBuffer &out, s32 max_len), (out, max_len)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, GetWorkingDirectoryPathSize, (sf::Out<s32> out_size), (out_size)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, RunOnHostStart, (sf::Out<u32> out_id, sf::OutCopyHandle out, const sf::InBuffer &args), (out_id, out, args)) \ AMS_SF_METHOD_INFO(C, H, 14, Result, RunOnHostResults, (sf::Out<s32> out_result, u32 id), (out_result, id)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, SetBridgeIpAddress, (const sf::InBuffer &arg), (arg)) \ AMS_SF_METHOD_INFO(C, H, 16, Result, SetBridgeSubnetMask, (const sf::InBuffer &arg), (arg)) \ AMS_SF_METHOD_INFO(C, H, 17, Result, SetBridgePort, (const sf::InBuffer &arg), (arg)) AMS_SF_DEFINE_INTERFACE(ams::tma, IHtcManager, AMS_TMA_I_HTC_MANAGER_INTERFACE_INFO, 0x8591F069) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_htcs_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htcs/htcs_types.hpp> #include <stratosphere/tma/tma_i_socket.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_HTCS_MANAGER_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Socket, (sf::Out<s32> out_err, sf::Out<s32> out_sock), (out_err, out_sock)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Close, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc), (out_err, out_res, desc)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Connect, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc, const htcs::SockAddrHtcs &address), (out_err, out_res, desc, address)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, Bind, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc, const htcs::SockAddrHtcs &address), (out_err, out_res, desc, address)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, Listen, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc, s32 backlog_count), (out_err, out_res, desc, backlog_count)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, Accept, (sf::Out<s32> out_err, sf::Out<s32> out_res, sf::Out<htcs::SockAddrHtcs> out_address, s32 desc), (out_err, out_res, out_address, desc)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, Recv, (sf::Out<s32> out_err, sf::Out<s64> out_size, const sf::OutBuffer &buffer, s32 desc, s32 flags), (out_err, out_size, buffer, desc, flags)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, Send, (sf::Out<s32> out_err, sf::Out<s64> out_size, s32 desc, const sf::InBuffer &buffer, s32 flags), (out_err, out_size, desc, buffer, flags)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, Shutdown, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc, s32 how), (out_err, out_res, desc, how)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, Fcntl, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 desc, s32 command, s32 value), (out_err, out_res, desc, command, value)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, GetPeerNameAny, (sf::Out<htcs::HtcsPeerName> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, GetDefaultHostName, (sf::Out<htcs::HtcsPeerName> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, CreateSocketOld, (sf::Out<s32> out_err, sf::Out<sf::SharedPointer<tma::ISocket>> out), (out_err, out)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, CreateSocket, (sf::Out<s32> out_err, sf::Out<sf::SharedPointer<tma::ISocket>> out, bool enable_disconnection_emulation), (out_err, out, enable_disconnection_emulation)) \ AMS_SF_METHOD_INFO(C, H, 100, Result, RegisterProcessId, (const sf::ClientProcessId &client_pid), (client_pid)) \ AMS_SF_METHOD_INFO(C, H, 101, Result, MonitorManager, (const sf::ClientProcessId &client_pid), (client_pid)) \ AMS_SF_METHOD_INFO(C, H, 130, Result, StartSelect, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, const sf::InMapAliasArray<s32> &read_handles, const sf::InMapAliasArray<s32> &write_handles, const sf::InMapAliasArray<s32> &exception_handles, s64 tv_sec, s64 tv_usec), (out_task_id, out_event, read_handles, write_handles, exception_handles, tv_sec, tv_usec)) \ AMS_SF_METHOD_INFO(C, H, 131, Result, EndSelect, (sf::Out<s32> out_err, sf::Out<s32> out_count, const sf::OutMapAliasArray<s32> &read_handles, const sf::OutMapAliasArray<s32> &write_handles, const sf::OutMapAliasArray<s32> &exception_handles, u32 task_id), (out_err, out_count, read_handles, write_handles, exception_handles, task_id)) AMS_SF_DEFINE_INTERFACE(ams::tma, IHtcsManager, AMS_TMA_I_HTCS_MANAGER_INTERFACE_INFO, 0x91ECD04F) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_i_socket.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/htcs/htcs_types.hpp> #include <stratosphere/tma/tma_i_socket.hpp> /* NOTE: Minimum firmware version not enforced for any commands. */ #define AMS_TMA_I_SOCKET_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Close, (sf::Out<s32> out_err, sf::Out<s32> out_res), (out_err, out_res)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Connect, (sf::Out<s32> out_err, sf::Out<s32> out_res, const htcs::SockAddrHtcs &address), (out_err, out_res, address)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, Bind, (sf::Out<s32> out_err, sf::Out<s32> out_res, const htcs::SockAddrHtcs &address), (out_err, out_res, address)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, Listen, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 backlog_count), (out_err, out_res, backlog_count)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, Accept, (sf::Out<s32> out_err, sf::Out<sf::SharedPointer<tma::ISocket>> out, sf::Out<htcs::SockAddrHtcs> out_address), (out_err, out, out_address)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, Recv, (sf::Out<s32> out_err, sf::Out<s64> out_size, const sf::OutAutoSelectBuffer &buffer, s32 flags), (out_err, out_size, buffer, flags)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, Send, (sf::Out<s32> out_err, sf::Out<s64> out_size, const sf::InAutoSelectBuffer &buffer, s32 flags), (out_err, out_size, buffer, flags)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, Shutdown, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 how), (out_err, out_res, how)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, Fcntl, (sf::Out<s32> out_err, sf::Out<s32> out_res, s32 command, s32 value), (out_err, out_res, command, value)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, AcceptStart, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event), (out_task_id, out_event)) \ AMS_SF_METHOD_INFO(C, H, 10, Result, AcceptResults, (sf::Out<s32> out_err, sf::Out<sf::SharedPointer<tma::ISocket>> out, sf::Out<htcs::SockAddrHtcs> out_address, u32 task_id), (out_err, out, out_address, task_id)) \ AMS_SF_METHOD_INFO(C, H, 11, Result, RecvStart, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, s32 mem_size, s32 flags), (out_task_id, out_event, mem_size, flags)) \ AMS_SF_METHOD_INFO(C, H, 12, Result, RecvResults, (sf::Out<s32> out_err, sf::Out<s64> out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id), (out_err, out_size, buffer, task_id)) \ AMS_SF_METHOD_INFO(C, H, 13, Result, RecvLargeStart, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, s32 unaligned_size_start, s32 unaligned_size_end, s64 aligned_size, sf::CopyHandle &&mem_handle, s32 flags), (out_task_id, out_event, unaligned_size_start, unaligned_size_end, aligned_size, std::move(mem_handle), flags)) \ AMS_SF_METHOD_INFO(C, H, 14, Result, SendStartOld, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, const sf::InAutoSelectBuffer &buffer, s32 flags), (out_task_id, out_event, buffer, flags)) \ AMS_SF_METHOD_INFO(C, H, 15, Result, SendLargeStart, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, const sf::InAutoSelectBuffer &start_buffer, const sf::InAutoSelectBuffer &end_buffer, sf::CopyHandle &&mem_handle, s64 aligned_size, s32 flags), (out_task_id, out_event, start_buffer, end_buffer, std::move(mem_handle), aligned_size, flags)) \ AMS_SF_METHOD_INFO(C, H, 16, Result, SendResults, (sf::Out<s32> out_err, sf::Out<s64> out_size, u32 task_id), (out_err, out_size, task_id)) \ AMS_SF_METHOD_INFO(C, H, 17, Result, StartSend, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, sf::Out<s64> out_max_size, s64 size, s32 flags), (out_task_id, out_event, out_max_size, size, flags)) \ AMS_SF_METHOD_INFO(C, H, 18, Result, ContinueSendOld, (sf::Out<s64> out_size, sf::Out<bool> out_wait, const sf::InAutoSelectBuffer &buffer, u32 task_id), (out_size, out_wait, buffer, task_id)) \ AMS_SF_METHOD_INFO(C, H, 19, Result, EndSend, (sf::Out<s32> out_err, sf::Out<s64> out_size, u32 task_id), (out_err, out_size, task_id)) \ AMS_SF_METHOD_INFO(C, H, 20, Result, StartRecv, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, s64 size, s32 flags), (out_task_id, out_event, size, flags)) \ AMS_SF_METHOD_INFO(C, H, 21, Result, EndRecv, (sf::Out<s32> out_err, sf::Out<s64> out_size, const sf::OutAutoSelectBuffer &buffer, u32 task_id), (out_err, out_size, buffer, task_id)) \ AMS_SF_METHOD_INFO(C, H, 22, Result, SendStart, (sf::Out<u32> out_task_id, sf::OutCopyHandle out_event, const sf::InNonSecureAutoSelectBuffer &buffer, s32 flags), (out_task_id, out_event, buffer, flags)) \ AMS_SF_METHOD_INFO(C, H, 23, Result, ContinueSend, (sf::Out<s64> out_size, sf::Out<bool> out_wait, const sf::InNonSecureAutoSelectBuffer &buffer, u32 task_id), (out_size, out_wait, buffer, task_id)) \ AMS_SF_METHOD_INFO(C, H, 130, Result, GetPrimitive, (sf::Out<s32> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::tma, ISocket, AMS_TMA_I_SOCKET_INTERFACE_INFO, 0x34CFC7C1) ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma/tma_path.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_common.hpp> #include <stratosphere/fs/fs_directory.hpp> #include <stratosphere/sf/sf_buffer_tags.hpp> namespace ams::tma { struct Path : ams::sf::LargeData { char str[fs::EntryNameLengthMax + 1]; static constexpr Path Encode(const char *p) { Path path = {}; for (size_t i = 0; i < sizeof(path) - 1; i++) { path.str[i] = p[i]; if (p[i] == '\x00') { break; } } return path; } static constexpr size_t GetLength(const Path &path) { size_t len = 0; for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) { len++; } return len; } }; static_assert(util::is_pod<Path>::value && sizeof(Path) == fs::EntryNameLengthMax + 1); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/tma.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/tma/tma_i_htc_manager.hpp> #include <stratosphere/tma/tma_i_htcs_manager.hpp> #include <stratosphere/tma/tma_i_file_manager.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/updater/updater_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/updater/updater_types.hpp> #include <stratosphere/spl/spl_types.hpp> namespace ams::updater { /* Public API. */ BootImageUpdateType GetBootImageUpdateType(int boot_image_update_type); BootImageUpdateType GetBootImageUpdateType(spl::HardwareType hw_type); Result GetBootImagePackageId(ncm::SystemDataId *out_data_id, BootModeType mode, void *work_buffer, size_t work_buffer_size); Result MarkVerifyingRequired(BootModeType mode, void *work_buffer, size_t work_buffer_size); Result MarkVerified(BootModeType mode, void *work_buffer, size_t work_buffer_size); Result UpdateBootImagesFromPackage(ncm::SystemDataId boot_image_package_id, BootModeType mode, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); Result VerifyBootImagesAndRepairIfNeeded(bool *out_repaired_normal, bool *out_repaired_safe, void *work_buffer, size_t work_buffer_size, BootImageUpdateType boot_image_update_type); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/updater/updater_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::updater { /* Types. */ enum class BootImageUpdateType { Erista, Mariko, }; enum class BootModeType { Normal, Safe, }; struct VerificationState { bool needs_verify_normal; bool needs_verify_safe; }; /* Convenience size definitions. */ constexpr size_t BctSize = 0x4000; constexpr size_t EksSize = 0x4000; constexpr size_t EksEntrySize = 0x200; constexpr size_t EksBlobSize = 0xB0; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/updater.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/updater/updater_types.hpp> #include <stratosphere/updater/updater_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/ds/usb_i_ds_endpoint.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_types.hpp> #include <stratosphere/usb/usb_device_types.hpp> #define AMS_USB_I_DS_ENDPOINT_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, PostBufferAsync, (sf::Out<u32> out_urb_id, u64 address, u32 size), (out_urb_id, address, size)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, Cancel, (), ()) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetCompletionEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetUrbReport, (sf::Out<usb::UrbReport> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, Stall, (), ()) \ AMS_SF_METHOD_INFO(C, H, 5, Result, SetZlt, (bool zlt), (zlt)) /* TODO: Deprecated interface? */ AMS_SF_DEFINE_INTERFACE(ams::usb::ds, IDsEndpoint, AMS_USB_I_DS_ENDPOINT_INTERFACE_INFO, 0x107E43A4) ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/ds/usb_i_ds_interface.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_types.hpp> #include <stratosphere/usb/usb_device_types.hpp> #include <stratosphere/usb/ds/usb_i_ds_endpoint.hpp> #define AMS_USB_I_DS_INTERFACE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, RegisterEndpoint, (u8 endpoint_address, sf::Out<sf::SharedPointer<usb::ds::IDsEndpoint>> out), (endpoint_address, out)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, GetSetupEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetSetupPacket, (const sf::OutBuffer &out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, CtrlInAsync, (sf::Out<u32> out_urb_id, u64 address, u32 size), (out_urb_id, address, size)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, CtrlOutAsync, (sf::Out<u32> out_urb_id, u64 address, u32 size), (out_urb_id, address, size)) \ AMS_SF_METHOD_INFO(C, H, 5, Result, GetCtrlInCompletionEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, GetCtrlInUrbReport, (sf::Out<usb::UrbReport> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, GetCtrlOutCompletionEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, GetCtrlOutUrbReport, (sf::Out<usb::UrbReport> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, CtrlStall, (), ()) \ AMS_SF_METHOD_INFO(C, H, 10, Result, AppendConfigurationData, (u8 bInterfaceNumber, usb::UsbDeviceSpeed device_speed, const sf::InBuffer &data), (bInterfaceNumber, device_speed, data)) \ AMS_SF_METHOD_INFO(C, H, 65000, Result, Enable, (), ()) \ AMS_SF_METHOD_INFO(C, H, 65001, Result, Disable, (), ()) /* TODO: Deprecated interface? */ AMS_SF_DEFINE_INTERFACE(ams::usb::ds, IDsInterface, AMS_USB_I_DS_INTERFACE_INTERFACE_INFO, 0x5632AFB2) ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/ds/usb_i_ds_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_types.hpp> #include <stratosphere/usb/usb_device_types.hpp> #include <stratosphere/usb/ds/usb_i_ds_interface.hpp> #define AMS_USB_I_DS_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, Bind, (usb::ComplexId complex_id, sf::CopyHandle &&process_h), (complex_id, std::move(process_h))) \ AMS_SF_METHOD_INFO(C, H, 1, Result, RegisterInterface, (sf::Out<sf::SharedPointer<usb::ds::IDsInterface>> out, u8 bInterfaceNumber), (out, bInterfaceNumber)) \ AMS_SF_METHOD_INFO(C, H, 2, Result, GetStateChangeEvent, (sf::OutCopyHandle out), (out)) \ AMS_SF_METHOD_INFO(C, H, 3, Result, GetState, (sf::Out<usb::UsbState> out), (out)) \ AMS_SF_METHOD_INFO(C, H, 4, Result, ClearDeviceData, (), ()) \ AMS_SF_METHOD_INFO(C, H, 5, Result, AddUsbStringDescriptor, (sf::Out<u8> out, const sf::InBuffer &desc), (out, desc)) \ AMS_SF_METHOD_INFO(C, H, 6, Result, DeleteUsbStringDescriptor, (u8 index), (index)) \ AMS_SF_METHOD_INFO(C, H, 7, Result, SetUsbDeviceDescriptor, (const sf::InBuffer &desc, usb::UsbDeviceSpeed speed), (desc, speed)) \ AMS_SF_METHOD_INFO(C, H, 8, Result, SetBinaryObjectStore, (const sf::InBuffer &bos), (bos)) \ AMS_SF_METHOD_INFO(C, H, 9, Result, Enable, (), ()) \ AMS_SF_METHOD_INFO(C, H, 10, Result, Disable, (), ()) /* TODO: Deprecated interface? */ AMS_SF_DEFINE_INTERFACE(ams::usb::ds, IDsService, AMS_USB_I_DS_SERVICE_INTERFACE_INFO, 0x306DB3C1) #define AMS_USB_I_DS_ROOT_SESSION_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 0, Result, GetService, (sf::Out<sf::SharedPointer<usb::ds::IDsService>> out), (out)) AMS_SF_DEFINE_INTERFACE(ams::usb::ds, IDsRootSession, AMS_USB_I_DS_ROOT_SESSION_INTERFACE_INFO, 0x2EC38748) ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/usb_device.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_system_event.hpp> #include <stratosphere/sf/sf_lmem_utility.hpp> #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_device_types.hpp> #include <stratosphere/usb/ds/usb_i_ds_service.hpp> namespace ams::usb { class DsInterface; class DsEndpoint; class DsClient { friend class DsInterface; friend class DsEndpoint; private: /* NOTE: Nintendo uses a UnitHeap here on newer firmware versions. */ /* For now, we'll use an ExpHeap and do it the old way. */ sf::ExpHeapAllocator m_allocator{}; u8 m_heap_buffer[32_KB]; lmem::HeapHandle m_heap_handle{}; sf::SharedPointer<ds::IDsRootSession> m_root_session{}; sf::SharedPointer<ds::IDsService> m_ds_service{}; bool m_is_initialized{false}; std::atomic<int> m_reference_count{0}; os::SystemEventType m_state_change_event{}; DsInterface *m_interfaces[DsLimitMaxInterfacesPerConfigurationCount]{}; bool m_is_enabled{false}; public: DsClient() = default; ~DsClient() { /* ... */ } public: Result Initialize(ComplexId complex_id); Result Finalize(); bool IsInitialized(); Result EnableDevice(); Result DisableDevice(); os::SystemEventType *GetStateChangeEvent(); Result GetState(UsbState *out); Result ClearDeviceData(); Result AddUsbStringDescriptor(u8 *out_index, UsbStringDescriptor *desc); Result DeleteUsbStringDescriptor(u8 index); Result SetUsbDeviceDescriptor(UsbDeviceDescriptor *desc, UsbDeviceSpeed speed); Result SetBinaryObjectStore(u8 *data, int size); private: Result AddInterface(DsInterface *intf, sf::SharedPointer<ds::IDsInterface> *out_srv, uint8_t bInterfaceNumber); Result DeleteInterface(uint8_t bInterfaceNumber); }; class DsInterface { friend class DsEndpoint; private: DsClient *m_client; sf::SharedPointer<ds::IDsInterface> m_interface; bool m_is_initialized; std::atomic<int> m_reference_count; os::SystemEventType m_setup_event; os::SystemEventType m_ctrl_in_completion_event; os::SystemEventType m_ctrl_out_completion_event; UrbReport m_report; u8 m_interface_num; DsEndpoint *m_endpoints[UsbLimitMaxEndpointsCount]; public: DsInterface() : m_client(nullptr), m_is_initialized(false), m_reference_count(0) { /* ... */ } ~DsInterface() { /* ... */ } public: Result Initialize(DsClient *client, u8 bInterfaceNumber); Result Finalize(); Result AppendConfigurationData(UsbDeviceSpeed speed, void *data, u32 size); bool IsInitialized(); os::SystemEventType *GetSetupEvent(); Result GetSetupPacket(UsbCtrlRequest *out); Result Enable(); Result Disable(); Result CtrlRead(u32 *out_transferred, void *dst, u32 size); Result CtrlWrite(u32 *out_transferred, void *dst, u32 size); Result CtrlDone(); Result CtrlStall(); private: Result AddEndpoint(DsEndpoint *ep, u8 bEndpointAddress, sf::SharedPointer<ds::IDsEndpoint> *out); Result DeleteEndpoint(u8 bEndpointAddress); Result CtrlIn(u32 *out_transferred, void *dst, u32 size); Result CtrlOut(u32 *out_transferred, void *dst, u32 size); }; class DsEndpoint { private: bool m_is_initialized; bool m_is_new_format; std::atomic<int> m_reference_count; DsInterface *m_interface; sf::SharedPointer<ds::IDsEndpoint> m_endpoint; u8 m_address; os::SystemEventType m_completion_event; os::SystemEventType m_unknown_event; public: DsEndpoint() : m_is_initialized(false), m_is_new_format(false), m_reference_count(0) { /* ... */ } public: Result Initialize(DsInterface *interface, u8 bEndpointAddress); Result Finalize(); bool IsInitialized(); Result PostBuffer(u32 *out_transferred, void *buf, u32 size); Result PostBufferAsync(u32 *out_urb_id, void *buf, u32 size); os::SystemEventType *GetCompletionEvent(); Result GetUrbReport(UrbReport *out); Result Cancel(); Result SetZeroLengthTransfer(bool zlt); }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/usb_device_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_types.hpp> namespace ams::usb { constexpr inline u8 InterfaceNumberAuto = DsLimitMaxInterfacesPerConfigurationCount; constexpr inline u8 EndpointAddressAutoIn = UsbEndpointAddressMask_DirDevicetoHost; constexpr inline u8 EndpointAddressAutoOut = UsbEndpointAddressMask_DirHostToDevice; enum UrbStatus { UrbStatus_Invalid = 0, UrbStatus_Pending = 1, UrbStatus_Running = 2, UrbStatus_Finished = 3, UrbStatus_Cancelled = 4, UrbStatus_Failed = 5, }; struct UrbReport { struct Report { u32 id; u32 requested_size; u32 transferred_size; UrbStatus status; } reports[DsLimitRingSize]; u32 count; }; enum DsString { DsString_Max = 0x20, }; struct DsVidPidBcd { uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; char manufacturer[DsString_Max]; char product[DsString_Max]; char serial_number[DsString_Max]; }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/usb_limits.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/dd/dd_device_address_space_common.hpp> namespace ams::usb { constexpr inline int HwLimitDmaBufferAlignmentSize = dd::DeviceAddressSpaceMemoryRegionAlignment; constexpr inline int HwLimitDataCacheLineSize = 0x40; constexpr inline int HwLimitMaxPortCount = 0x4; constexpr inline int UsbLimitMaxEndpointsCount = 0x20; constexpr inline int UsbLimitMaxEndpointPairCount = 0x10; constexpr inline int DsLimitMaxConfigurationsPerDeviceCount = 1; constexpr inline int DsLimitMaxInterfacesPerConfigurationCount = 4; constexpr inline int DsLimitMaxNameSize = 0x40; constexpr inline int DsLimitRingSize = 8; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb/usb_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/usb/usb_limits.hpp> namespace ams::usb { constexpr ALWAYS_INLINE bool IsDmaAligned(u64 address) { return util::IsAligned(address, static_cast<u64>(HwLimitDmaBufferAlignmentSize)); } enum ComplexId { ComplexId_Tegra21x = 2, }; enum UsbDescriptorType { UsbDescriptorType_Device = 1, UsbDescriptorType_Config = 2, UsbDescriptorType_String = 3, UsbDescriptorType_Interface = 4, UsbDescriptorType_Endpoint = 5, UsbDescriptorType_DeviceQualifier = 6, UsbDescriptorType_OtherSpeedConfig = 7, UsbDescriptorType_InterfacePower = 8, UsbDescriptorType_Otg = 9, UsbDescriptorType_Debug = 10, UsbDescriptorType_InterfaceAssociation = 11, UsbDescriptorType_Bos = 15, UsbDescriptorType_DeviceCapability = 16, UsbDescriptorType_Hid = 33, UsbDescriptorType_Report = 34, UsbDescriptorType_Physical = 35, UsbDescriptorType_Hub = 41, UsbDescriptorType_EndpointCompanion = 48, UsbDescriptorType_IsocEndpointCompanion = 49, }; struct UsbDescriptorHeader { uint8_t bLength; uint8_t bDescriptorType; } PACKED; struct UsbInterfaceDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bInterfaceNumber; uint8_t bAlternateSetting; uint8_t bNumEndpoints; uint8_t bInterfaceClass; uint8_t bInterfaceSubClass; uint8_t bInterfaceProtocol; uint8_t iInterface; } PACKED; struct UsbEndpointDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bEndpointAddress; uint8_t bmAttributes; uint16_t wMaxPacketSize; uint8_t bInterval; } PACKED; struct UsbDeviceDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; } PACKED; struct UsbConfigDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t wTotalLength; uint8_t bNumInterfaces; uint8_t bConfigurationValue; uint8_t iConfiguration; uint8_t bmAttributes; uint8_t bMaxPower; } PACKED; struct UsbEndpointCompanionDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bMaxBurst; uint8_t bmAttributes; uint16_t wBytesPerInterval; } PACKED; struct UsbStringDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t wData[DsLimitMaxNameSize]; } PACKED; struct UsbCtrlRequest { uint8_t bmRequestType; uint8_t bRequest; uint16_t wValue; uint16_t wIndex; uint16_t wLength; } PACKED; enum UsbState { UsbState_Detached = 0, UsbState_Attached = 1, UsbState_Powered = 2, UsbState_Default = 3, UsbState_Address = 4, UsbState_Configured = 5, UsbState_Suspended = 6, }; enum UsbDescriptorSize { UsbDescriptorSize_Interface = sizeof(UsbInterfaceDescriptor), UsbDescriptorSize_Endpoint = sizeof(UsbEndpointDescriptor), UsbDescriptorSize_Device = sizeof(UsbDeviceDescriptor), UsbDescriptorSize_Config = sizeof(UsbConfigDescriptor), UsbDescriptorSize_EndpointCompanion = sizeof(UsbEndpointCompanionDescriptor), }; enum UsbDeviceSpeed { UsbDeviceSpeed_Invalid = 0, UsbDeviceSpeed_Low = 1, UsbDeviceSpeed_Full = 2, UsbDeviceSpeed_High = 3, UsbDeviceSpeed_Super = 4, UsbDeviceSpeed_SuperPlus = 5, }; enum UsbEndpointAddressMask { UsbEndpointAddressMask_EndpointNumber = (0xF << 0), UsbEndpointAddressMask_Dir = (0x1 << 7), UsbEndpointAddressMask_DirHostToDevice = (0x0 << 7), UsbEndpointAddressMask_DirDevicetoHost = (0x1 << 7), }; enum UsbEndpointAttributeMask { UsbEndpointAttributeMask_XferType = (0x3 << 0), UsbEndpointAttributeMask_XferTypeControl = (0x0 << 0), UsbEndpointAttributeMask_XferTypeIsoc = (0x1 << 0), UsbEndpointAttributeMask_XferTypeBulk = (0x2 << 0), UsbEndpointAttributeMask_XferTypeInt = (0x3 << 0), }; enum UsbEndpointDirection { UsbEndpointDirection_Invalid = 0, UsbEndpointDirection_ToDevice = 1, UsbEndpointDirection_ToHost = 2, UsbEndpointDirection_Control = 3, }; constexpr inline u8 UsbGetEndpointNumber(const UsbEndpointDescriptor *desc) { return desc->bEndpointAddress & UsbEndpointAddressMask_EndpointNumber; } constexpr inline bool UsbEndpointIsHostToDevice(const UsbEndpointDescriptor *desc) { return (desc->bEndpointAddress & UsbEndpointAddressMask_Dir) == UsbEndpointAddressMask_DirHostToDevice; } constexpr inline bool UsbEndpointIsDeviceToHost(const UsbEndpointDescriptor *desc) { return (desc->bEndpointAddress & UsbEndpointAddressMask_Dir) == UsbEndpointAddressMask_DirDevicetoHost; } constexpr inline u8 UsbGetEndpointAddress(u8 number, UsbEndpointDirection dir) { u8 val = static_cast<u8>(number & UsbEndpointAddressMask_EndpointNumber); if (dir == UsbEndpointDirection_ToHost) { val |= UsbEndpointAddressMask_DirDevicetoHost; } else { val |= UsbEndpointAddressMask_DirHostToDevice; } return val; } constexpr inline UsbEndpointDirection GetUsbEndpointDirection(const UsbEndpointDescriptor *desc) { if (UsbEndpointIsDeviceToHost(desc)) { return UsbEndpointDirection_ToHost; } else { return UsbEndpointDirection_ToDevice; } } constexpr inline bool UsbEndpointIsValid(const UsbEndpointDescriptor *desc) { return desc != nullptr && desc->bLength >= UsbDescriptorSize_Endpoint && desc->bEndpointAddress != 0; } constexpr inline void UsbMarkEndpointInvalid(UsbEndpointDescriptor *desc) { desc->bLength = 0; desc->bEndpointAddress = 0; } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/usb.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/usb/usb_limits.hpp> #include <stratosphere/usb/usb_types.hpp> #include <stratosphere/usb/usb_device_types.hpp> #include <stratosphere/usb/usb_device.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/util/util_compression.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::util { /* Compression utilities. */ int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); /* Decompression utilities. */ int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/util/util_ini.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/fs/fs_file.hpp> namespace ams::fs::fsa { class IFile; } namespace ams::util::ini { /* Ini handler type. */ using Handler = int (*)(void *user_ctx, const char *section, const char *name, const char *value); /* Utilities for dealing with INI file configuration. */ int ParseString(const char *ini_str, void *user_ctx, Handler h); int ParseFile(fs::FileHandle file, void *user_ctx, Handler h); int ParseFile(fs::fsa::IFile *file, void *user_ctx, Handler h); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/util/util_lock_free_atomic_type.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_memory_fence_api.hpp> namespace ams::util { template<typename T> struct LockFreeAtomicType { volatile u32 _counter; T _value[2]; }; template<typename T> void StoreToLockFreeAtomicType(LockFreeAtomicType<T> *p, const T &value) { /* Get the current counter. */ auto counter = p->_counter; /* Increment the counter. */ ++counter; /* Store the updated value. */ p->_value[counter % 2] = value; /* Fence memory. */ os::FenceMemoryStoreStore(); /* Set the updated counter. */ p->_counter = counter; } template<typename T> T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T> *p) { while (true) { /* Get the counter. */ auto counter = p->_counter; /* Get the value. */ auto value = p->_value[counter % 2]; /* Fence memory. */ os::FenceMemoryLoadLoad(); /* Check that the counter matches. */ if (counter == p->_counter) { return value; } } } } ================================================ FILE: libraries/libstratosphere/include/stratosphere/util/util_singleton_traits.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/os/os_sdk_mutex.hpp> #define AMS_SINGLETON_TRAITS(_CLASSNAME_) \ private: \ NON_COPYABLE(_CLASSNAME_); \ NON_MOVEABLE(_CLASSNAME_); \ private: \ _CLASSNAME_ (); \ public: \ static _CLASSNAME_ &GetInstance() { \ AMS_FUNCTION_LOCAL_STATIC(_CLASSNAME_, s_singleton_instance); \ \ return s_singleton_instance; \ } #define AMS_CONSTINIT_SINGLETON_TRAITS(_CLASSNAME_) \ private: \ NON_COPYABLE(_CLASSNAME_); \ NON_MOVEABLE(_CLASSNAME_); \ private: \ constexpr _CLASSNAME_ () = default; \ public: \ static _CLASSNAME_ &GetInstance() { \ /* Declare singleton instance variables. */ \ AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(_CLASSNAME_, s_singleton_instance); \ return s_singleton_instance; \ } ================================================ FILE: libraries/libstratosphere/include/stratosphere/util/util_uuid_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::util { /* Nintendo provides UUID generation following RFC 4122. */ /* By default, UUIDs are generated as version 4 (random). */ Uuid GenerateUuid(); Uuid GenerateUuidVersion5(const void *sha1_hash); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/util/util_uuid_api.hpp> #include <stratosphere/util/util_compression.hpp> #include <stratosphere/util/util_ini.hpp> #include <stratosphere/util/util_singleton_traits.hpp> #include <stratosphere/util/util_lock_free_atomic_type.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/vi/vi_layer_stack.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::vi { enum LayerStack { LayerStack_Default = 0, LayerStack_Lcd = 1, LayerStack_Screenshot = 2, LayerStack_Recording = 3, LayerStack_LastFrame = 4, LayerStack_Arbitrary = 5, LayerStack_ApplicationForDebug = 6, LayerStack_Null = 10, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/vi.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/vi/vi_layer_stack.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/wec/wec_api.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/wec/wec_types.hpp> namespace ams::wec { void Initialize(); void ClearWakeEvents(); void WecRestoreForExitSuspend(); void SetWakeEventLevel(wec::WakeEvent event, wec::WakeEventLevel level); void SetWakeEventEnabled(wec::WakeEvent event, bool en); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/wec/wec_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include <stratosphere/wec/wec_wake_event.board.nintendo_nx.hpp> #else #include <stratosphere/wec/wec_wake_event.generic.hpp> #endif namespace ams::wec { enum WakeEventLevel { WakeEventLevel_Low = 0, WakeEventLevel_High = 1, WakeEventLevel_Auto = 2, }; } ================================================ FILE: libraries/libstratosphere/include/stratosphere/wec/wec_wake_event.board.nintendo_nx.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::wec { enum WakeEvent { WakeEvent_PexWakeN = 0x00, WakeEvent_GpioPortA6 = 0x01, WakeEvent_QspiCsN = 0x02, WakeEvent_Spi2Mosi = 0x03, WakeEvent_ExtconDetS = 0x04, WakeEvent_McuIrq = 0x05, WakeEvent_Uart2Cts = 0x06, WakeEvent_Uart3Cts = 0x07, WakeEvent_WifiWakeAp = 0x08, WakeEvent_AoTag2Pmc = 0x09, WakeEvent_ExtconDetU = 0x0A, WakeEvent_NfcInt = 0x0B, WakeEvent_Gen1I2cSda = 0x0C, WakeEvent_Gen2I2cSda = 0x0D, WakeEvent_CradleIrq = 0x0E, WakeEvent_GpioPortK6 = 0x0F, WakeEvent_RtcIrq = 0x10, WakeEvent_Sdmmc1Dat1 = 0x11, WakeEvent_Sdmmc2Dat1 = 0x12, WakeEvent_HdmiCec = 0x13, WakeEvent_Gen3I2cSda = 0x14, WakeEvent_GpioPortL1 = 0x15, WakeEvent_Clk_32kOut = 0x16, WakeEvent_PwrI2cSda = 0x17, WakeEvent_ButtonPowerOn = 0x18, WakeEvent_ButtonVolUp = 0x19, WakeEvent_ButtonVolDown = 0x1A, WakeEvent_ButtonSlideSw = 0x1B, WakeEvent_ButtonHome = 0x1C, /* ... */ WakeEvent_AlsProxInt = 0x20, WakeEvent_TempAlert = 0x21, WakeEvent_Bq24190Irq = 0x22, WakeEvent_SdCd = 0x23, WakeEvent_GpioPortZ2 = 0x24, /* ... */ WakeEvent_Utmip0 = 0x27, WakeEvent_Utmip1 = 0x28, WakeEvent_Utmip2 = 0x29, WakeEvent_Utmip3 = 0x2A, WakeEvent_Uhsic = 0x2B, WakeEvent_Wake2PmcXusbSystem = 0x2C, WakeEvent_Sdmmc3Dat1 = 0x2D, WakeEvent_Sdmmc4Dat1 = 0x2E, WakeEvent_CamI2cScl = 0x2F, WakeEvent_CamI2cSda = 0x30, WakeEvent_GpioPortZ5 = 0x31, WakeEvent_DpHpd0 = 0x32, WakeEvent_PwrIntN = 0x33, WakeEvent_BtWakeAp = 0x34, WakeEvent_HdmiIntDpHpd = 0x35, WakeEvent_UsbVbusEn0 = 0x36, WakeEvent_UsbVbusEn1 = 0x37, WakeEvent_LcdRst = 0x38, WakeEvent_LcdGpio1 = 0x39, WakeEvent_LcdGpio2 = 0x3A, WakeEvent_Uart4Cts = 0x3B, WakeEvent_ModemWakeAp = 0x3D, WakeEvent_TouchInt = 0x3E, WakeEvent_MotionInt = 0x3F, WakeEvent_Count = 0x40, }; constexpr inline WakeEvent WakeEvent_None = static_cast<WakeEvent>(-1); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/wec/wec_wake_event.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> namespace ams::wec { enum WakeEvent { WakeEvent_Debug = 0, WakeEvent_Count = 1, }; constexpr inline WakeEvent WakeEvent_None = static_cast<WakeEvent>(-1); } ================================================ FILE: libraries/libstratosphere/include/stratosphere/wec.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere/wec/wec_types.hpp> #include <stratosphere/wec/wec_api.hpp> ================================================ FILE: libraries/libstratosphere/include/stratosphere/windows.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef NOMINMAX #define NOMINMAX #endif #include <Windows.h> /* Collides with StandardUserSystemClock. */ #ifdef GetCurrentTime ALWAYS_INLINE auto WindowsGetCurrentTime() { return GetCurrentTime(); } #undef GetCurrentTime #endif /* Collides with several things. */ #ifdef FillMemory ALWAYS_INLINE auto WindowsFillMemory(PVOID p, SIZE_T l, BYTE v) { return FillMemory(p, l, v); } #undef FillMemory /* Should be provided by winerror.h, but isn't. */ #if !defined(ERROR_SPACES_NOT_ENOUGH_DRIVES) #define ERROR_SPACES_NOT_ENOUGH_DRIVES ((DWORD)0x80E7000Bu) #endif #endif ================================================ FILE: libraries/libstratosphere/include/stratosphere.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once /* Ensure that on windows we use lean-windows headers. */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif /* libvapours (pulls in util, svc, results). */ #include <vapours.hpp> /* Libstratosphere diagnostics. */ #include <stratosphere/diag.hpp> /* Libstratosphere definitions. */ #include <stratosphere/ams/impl/ams_system_thread_definitions.hpp> /* Libstratosphere-only utility. */ #include <stratosphere/util.hpp> /* Sadly required shims. */ #include <stratosphere/svc/svc_stratosphere_shims.hpp> /* Critical modules with no dependencies. */ #include <stratosphere/ams.hpp> #include <stratosphere/os.hpp> #include <stratosphere/dd.hpp> #include <stratosphere/lmem.hpp> #include <stratosphere/mem.hpp> /* Pull in all ID definitions from NCM. */ #include <stratosphere/ncm/ncm_ids.hpp> /* At this point, just include the rest alphabetically. */ /* TODO: Figure out optimal order. */ #include <stratosphere/boot2.hpp> #include <stratosphere/cal.hpp> #include <stratosphere/capsrv.hpp> #include <stratosphere/cfg.hpp> #include <stratosphere/clkrst.hpp> #include <stratosphere/cs.hpp> #include <stratosphere/ddsf.hpp> #include <stratosphere/dmnt.hpp> #include <stratosphere/erpt.hpp> #include <stratosphere/err.hpp> #include <stratosphere/fatal.hpp> #include <stratosphere/gc.hpp> #include <stratosphere/gpio.hpp> #include <stratosphere/hid.hpp> #include <stratosphere/hos.hpp> #include <stratosphere/htc.hpp> #include <stratosphere/htcfs.hpp> #include <stratosphere/htclow.hpp> #include <stratosphere/htcs.hpp> #include <stratosphere/i2c.hpp> #include <stratosphere/init.hpp> #include <stratosphere/kvdb.hpp> #include <stratosphere/ldr.hpp> #include <stratosphere/lr.hpp> #include <stratosphere/lm.hpp> #include <stratosphere/mitm.hpp> #include <stratosphere/ncm.hpp> #include <stratosphere/nim.hpp> #include <stratosphere/ns.hpp> #include <stratosphere/nsd.hpp> #include <stratosphere/osdbg.hpp> #include <stratosphere/patcher.hpp> #include <stratosphere/pcv.hpp> #include <stratosphere/pgl.hpp> #include <stratosphere/pinmux.hpp> #include <stratosphere/powctl.hpp> #include <stratosphere/psc.hpp> #include <stratosphere/pm.hpp> #include <stratosphere/pwm.hpp> #include <stratosphere/regulator.hpp> #include <stratosphere/ro.hpp> #include <stratosphere/settings.hpp> #include <stratosphere/scs.hpp> #include <stratosphere/sf.hpp> #include <stratosphere/sm.hpp> #include <stratosphere/socket.hpp> #include <stratosphere/spl.hpp> #include <stratosphere/sprofile.hpp> #include <stratosphere/time.hpp> #include <stratosphere/tipc.hpp> #include <stratosphere/tma.hpp> #include <stratosphere/updater.hpp> #include <stratosphere/usb.hpp> #include <stratosphere/wec.hpp> /* Include FS last. */ #include <stratosphere/fs.hpp> #include <stratosphere/fssrv.hpp> #include <stratosphere/fssystem.hpp> /* External modules that we're including. */ #include <stratosphere/rapidjson.hpp> ================================================ FILE: libraries/libstratosphere/libstratosphere.mk ================================================ #--------------------------------------------------------------------------------- # pull in common atmosphere configuration #--------------------------------------------------------------------------------- THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST))) CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE))) include $(CURRENT_DIRECTORY)/../config/common.mk ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) #--------------------------------------------------------------------------------- # pull in switch rules #--------------------------------------------------------------------------------- ifeq ($(strip $(DEVKITPRO)),) $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro") endif include $(DEVKITPRO)/libnx/switch_rules endif #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- ifeq ($(strip $(ATMOSPHERE_COMPILER_NAME)),gcc) PRECOMPILED_HEADERS := include/stratosphere.hpp else PRECOMPILED_HEADERS := endif ifeq ($(ATMOSPHERE_BUILD_FOR_DEBUGGING),1) ATMOSPHERE_OPTIMIZATION_FLAG := -Os else ATMOSPHERE_OPTIMIZATION_FLAG := -O2 endif DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE SETTINGS := $(ATMOSPHERE_SETTINGS) $(ATMOSPHERE_OPTIMIZATION_FLAG) -Wextra -Werror -Wno-missing-field-initializers -flto -Wno-error=unused-result CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) -Wl,-Map,$(notdir $*.map) else LDFLAGS := -Wl,-Map,$(notdir $*.map) endif SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source) SOURCES += $(call UNFILTERED_SOURCE_DIRS,source/os) ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) LIBS := -lnx else LIBS := endif #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) LIBDIRS := $(PORTLIBS) $(LIBNX) $(ATMOSPHERE_LIBDIRS) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours else LIBDIRS := $(ATMOSPHERE_LIBDIRS) $(ATMOSPHERE_LIBRARIES_DIR)/libvapours endif #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(__RECURSIVE__),1) #--------------------------------------------------------------------------------- export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c) CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp) SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- ifeq ($(strip $(CPPFILES)),) #--------------------------------------------------------------------------------- export LD := $(CC) #--------------------------------------------------------------------------------- else #--------------------------------------------------------------------------------- export LD := $(CXX) #--------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------- export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch) export OFILES := $(OFILES_BIN) $(OFILES_SRC) export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I. #--------------------------------------------------------------------------------- .PHONY: clean all all: $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(SOURCES) $(INCLUDES) $(GCH_DIRS) $(CPPFILES) $(CFILES) $(SFILES) @$(MAKE) __RECURSIVE__=1 OUTPUT=$(CURDIR)/$(ATMOSPHERE_LIBRARY_DIR)/$(TARGET).a \ DEPSDIR=$(CURDIR)/$(ATMOSPHERE_BUILD_DIR) \ --no-print-directory -C $(ATMOSPHERE_BUILD_DIR) \ -f $(THIS_MAKEFILE) #--------------------------------------------------------------------------------- clean: @echo clean $(ATMOSPHERE_BUILD_NAME) ... @rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_OUT_DIR) @rm -fr $(foreach hdr,$(GCH_DIRS),$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) @for i in $(GCH_DIRS); do [ -d $$i ] && rmdir $$i 2>/dev/null || true; done $(ATMOSPHERE_LIBRARY_DIR) $(ATMOSPHERE_BUILD_DIR) $(GCH_DIRS): @[ -d $@ ] || mkdir -p $@ #--------------------------------------------------------------------------------- else GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER)) DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr))))) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT) : result_get_name.o $(filter-out result_get_name.o, $(OFILES)) $(filter-out result_get_name.o, $(OFILES)) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) ams_environment_weak.os.horizon.o: CXXFLAGS += -fno-lto hos_version_api_weak_for_unit_test.o: CXXFLAGS += -fno-lto pm_info_api_weak.o: CXXFLAGS += -fno-lto hos_stratosphere_api.o: CXXFLAGS += -fno-lto init_operator_new.o: CXXFLAGS += -fno-lto init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto result_get_name.o: CXXFLAGS += -fno-lto crypto_sha256_generator.o: CXXFLAGS += -fno-lto spl_secure_monitor_api.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include fs_id_string_impl.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include ifeq ($(ATMOSPHERE_OS_NAME),windows) # Audit builds fail when these have lto disabled. # Noting 10/29/24: # In member function '__ct ': # internal compiler error: in binds_to_current_def_p, at symtab.cc:2589 os_%.o: CXXFLAGS += -fno-lto fssystem_%.o: CXXFLAGS += -fno-lto fssrv_%.o: CXXFLAGS += -fno-lto fs_%.o: CXXFLAGS += -fno-lto endif #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -include $(DEPENDS) #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- ================================================ FILE: libraries/libstratosphere/source/ams/ams_bpc.os.horizon.c ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define NX_SERVICE_ASSUME_NON_DOMAIN #include "../service_guard.h" #include "ams_bpc.os.horizon.h" static Service g_amsBpcSrv; NX_GENERATE_SERVICE_GUARD(amsBpc); Result _amsBpcInitialize(void) { Handle h; Result rc = svcConnectToNamedPort(&h, "bpc:ams"); /* TODO: ams:bpc */ while (R_VALUE(rc) == KERNELRESULT(NotFound)) { svcSleepThread(50000000ul); rc = svcConnectToNamedPort(&h, "bpc:ams"); } if (R_SUCCEEDED(rc)) serviceCreate(&g_amsBpcSrv, h); return rc; } void _amsBpcCleanup(void) { serviceClose(&g_amsBpcSrv); } Service *amsBpcGetServiceSession(void) { return &g_amsBpcSrv; } Result amsBpcRebootToFatalError(void *ctx) { /* Note: this takes in an sts::ams::FatalErrorContext. */ /* static_assert(sizeof() == 0x450) is done at type definition. */ return serviceDispatch(&g_amsBpcSrv, 65000, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, .buffers = { { ctx, 0x450 } }, ); } Result amsBpcSetRebootPayload(const void *src, size_t src_size) { return serviceDispatch(&g_amsBpcSrv, 65001, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, .buffers = { { src, src_size } }, ); } ================================================ FILE: libraries/libstratosphere/source/ams/ams_bpc.os.horizon.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <switch.h> #ifdef __cplusplus extern "C" { #endif Result amsBpcInitialize(void); void amsBpcExit(void); Service *amsBpcGetServiceSession(void); Result amsBpcRebootToFatalError(void *ctx); Result amsBpcSetRebootPayload(const void *src, size_t src_size); #ifdef __cplusplus } #endif ================================================ FILE: libraries/libstratosphere/source/ams/ams_emummc_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::emummc { namespace { /* Convenience Definitions. */ constexpr u32 StorageMagic = util::FourCC<'E','F','S','0'>::Code; constexpr size_t MaxDirLen = 0x7F; /* Types. */ struct BaseConfig { u32 magic; u32 type; u32 id; u32 fs_version; }; struct PartitionConfig { u64 start_sector; }; struct FileConfig { char path[MaxDirLen + 1]; }; struct ExosphereConfig { BaseConfig base_cfg; union { PartitionConfig partition_cfg; FileConfig file_cfg; }; char emu_dir_path[MaxDirLen + 1]; }; enum Storage : u32 { Storage_Emmc, Storage_Sd, Storage_SdFile, Storage_Count, }; /* Globals. */ constinit os::SdkMutex g_lock; constinit ExosphereConfig g_exo_config = {}; constinit bool g_is_emummc; constinit bool g_has_cached; /* Helpers. */ void CacheValues() { std::scoped_lock lk(g_lock); if (g_has_cached) { return; } /* Retrieve and cache values. */ { alignas(os::MemoryPageSize) std::byte path_storage[2 * (MaxDirLen + 1)]; struct { char file_path[MaxDirLen + 1]; char nintendo_path[MaxDirLen + 1]; } *paths = reinterpret_cast<decltype(paths)>(std::addressof(path_storage)); /* Retrieve paths from secure monitor. */ AMS_ABORT_UNLESS(spl::smc::AtmosphereGetEmummcConfig(std::addressof(g_exo_config), paths, 0) == spl::smc::Result::Success); const Storage storage = static_cast<Storage>(g_exo_config.base_cfg.type); g_is_emummc = g_exo_config.base_cfg.magic == StorageMagic && storage != Storage_Emmc; /* Format paths. */ { char tmp_path[MaxDirLen + 1]; /* Format paths. */ if (storage == Storage_SdFile) { util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->file_path); R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.file_cfg.path, sizeof(g_exo_config.file_cfg.path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); } util::TSNPrintf(tmp_path, sizeof(tmp_path), "/%s", paths->nintendo_path); R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); /* If we're emummc, implement default nintendo redirection path. */ if (g_is_emummc && std::strcmp(g_exo_config.emu_dir_path, "/") == 0) { util::TSNPrintf(tmp_path, sizeof(tmp_path), "/emummc/Nintendo_%04x", g_exo_config.base_cfg.id); R_ABORT_UNLESS(fs::PathFormatter::Normalize(g_exo_config.emu_dir_path, sizeof(g_exo_config.emu_dir_path), tmp_path, std::strlen(tmp_path) + 1, fs::PathFlags{})); } } } g_has_cached = true; } } /* Get whether emummc is active. */ bool IsActive() { CacheValues(); return g_is_emummc; } /* Get the active emummc id. */ u32 GetActiveId() { CacheValues(); return g_exo_config.base_cfg.id; } /* Get Nintendo redirection path. */ const char *GetNintendoDirPath() { CacheValues(); if (!g_is_emummc) { return nullptr; } return g_exo_config.emu_dir_path; } /* Get Emummc folderpath, NULL if not file-based. */ const char *GetFilePath() { CacheValues(); if (!g_is_emummc || g_exo_config.base_cfg.type != Storage_SdFile) { return nullptr; } return g_exo_config.file_cfg.path; } } ================================================ FILE: libraries/libstratosphere/source/ams/ams_environment.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "ams_bpc.os.horizon.h" namespace ams { namespace { #if defined(ATMOSPHERE_ARCH_ARM64) inline u64 GetPc() { u64 pc; __asm__ __volatile__ ("adr %[pc], ." : [pc]"=&r"(pc) :: ); return pc; } struct StackFrame { u64 fp; u64 lr; }; #else #error "Unknown architecture for os Horizon" #endif } void InitializeForBoot() { R_ABORT_UNLESS(amsBpcInitialize()); } void SetInitialRebootPayload(const void *src, size_t src_size) { R_ABORT_UNLESS(amsBpcSetRebootPayload(src, src_size)); } void WEAK_SYMBOL ExceptionHandler(FatalErrorContext *ctx) { R_ABORT_UNLESS(amsBpcInitialize()); R_ABORT_UNLESS(amsBpcRebootToFatalError(ctx)); while (1) { /* ... */ } } void CrashHandler(ThreadExceptionDump *ctx) { FatalErrorContext ams_ctx; /* Convert thread dump to atmosphere dump. */ { ams_ctx.magic = FatalErrorContext::Magic; ams_ctx.error_desc = ctx->error_desc; ams_ctx.program_id = os::GetCurrentProgramId().value; for (size_t i = 0; i < FatalErrorContext::NumGprs; i++) { ams_ctx.gprs[i] = ctx->cpu_gprs[i].x; } if (ams_ctx.error_desc == FatalErrorContext::DataAbortErrorDesc && ams_ctx.gprs[27] == FatalErrorContext::StdAbortMagicAddress && ams_ctx.gprs[28] == FatalErrorContext::StdAbortMagicValue) { /* Detect std::abort(). */ ams_ctx.error_desc = FatalErrorContext::StdAbortErrorDesc; } ams_ctx.fp = ctx->fp.x; ams_ctx.lr = ctx->lr.x; ams_ctx.sp = ctx->sp.x; ams_ctx.pc = ctx->pc.x; ams_ctx.pstate = ctx->pstate; ams_ctx.afsr0 = static_cast<u32>(::ams::exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION)); ams_ctx.afsr1 = static_cast<u32>(hos::GetVersion()); ams_ctx.far = ctx->far.x; ams_ctx.report_identifier = armGetSystemTick(); /* Detect stack overflow. */ if (ams_ctx.error_desc == FatalErrorContext::DataAbortErrorDesc) { svc::lp64::MemoryInfo mem_info; svc::PageInfo page_info; if (/* Check if stack pointer is in guard page. */ R_SUCCEEDED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), ams_ctx.sp)) && mem_info.state == svc::MemoryState_Free && /* Check if stack pointer fell off stack. */ R_SUCCEEDED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), ams_ctx.sp + 0x1000)) && mem_info.state == svc::MemoryState_Stack) { ams_ctx.error_desc = FatalErrorContext::StackOverflowErrorDesc; } } /* Grab module base. */ { svc::lp64::MemoryInfo mem_info; svc::PageInfo page_info; if (R_SUCCEEDED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), GetPc()))) { ams_ctx.module_base = mem_info.base_address; } else { ams_ctx.module_base = 0; } } ams_ctx.stack_trace_size = 0; u64 cur_fp = ams_ctx.fp; for (size_t i = 0; i < FatalErrorContext::MaxStackTrace; i++) { /* Validate current frame. */ if (cur_fp == 0 || (cur_fp & 0xF)) { break; } /* Read a new frame. */ StackFrame cur_frame; svc::lp64::MemoryInfo mem_info; svc::PageInfo page_info; if (R_SUCCEEDED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), cur_fp)) && (mem_info.permission & svc::MemoryPermission_Read) == svc::MemoryPermission_Read) { std::memcpy(std::addressof(cur_frame), reinterpret_cast<void *>(cur_fp), sizeof(cur_frame)); } else { break; } /* Advance to the next frame. */ ams_ctx.stack_trace[ams_ctx.stack_trace_size++] = cur_frame.lr; cur_fp = cur_frame.fp; } /* Clear unused parts of stack trace. */ for (size_t i = ams_ctx.stack_trace_size; i < FatalErrorContext::MaxStackTrace; i++) { ams_ctx.stack_trace[i] = 0; } /* Grab up to 0x100 of stack. */ { svc::lp64::MemoryInfo mem_info; svc::PageInfo page_info; if (R_SUCCEEDED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), ams_ctx.sp)) && (mem_info.permission & svc::MemoryPermission_Read) == svc::MemoryPermission_Read) { size_t copy_size = std::min(FatalErrorContext::MaxStackDumpSize, static_cast<size_t>(mem_info.base_address + mem_info.size - ams_ctx.sp)); ams_ctx.stack_dump_size = copy_size; std::memcpy(ams_ctx.stack_dump, reinterpret_cast<void *>(ams_ctx.sp), copy_size); } else { ams_ctx.stack_dump_size = 0; } } /* Grab 0x100 of tls. */ std::memcpy(ams_ctx.tls, svc::GetThreadLocalRegion(), sizeof(ams_ctx.tls)); } /* Just call the user exception handler. */ ::ams::ExceptionHandler(std::addressof(ams_ctx)); } NORETURN void AbortImpl(); } extern "C" { /* Redefine C++ exception handlers. Requires wrap linker flag. */ #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { ::ams::AbortImpl(); __builtin_unreachable(); } WRAP_ABORT_FUNC(__cxa_throw) WRAP_ABORT_FUNC(__cxa_rethrow) WRAP_ABORT_FUNC(__cxa_allocate_exception) WRAP_ABORT_FUNC(__cxa_free_exception) WRAP_ABORT_FUNC(__cxa_begin_catch) WRAP_ABORT_FUNC(__cxa_end_catch) WRAP_ABORT_FUNC(__cxa_call_unexpected) WRAP_ABORT_FUNC(__cxa_call_terminate) WRAP_ABORT_FUNC(__gxx_personality_v0) WRAP_ABORT_FUNC(_ZSt19__throw_logic_errorPKc) WRAP_ABORT_FUNC(_ZSt20__throw_length_errorPKc) WRAP_ABORT_FUNC(_ZNSt11logic_errorC2EPKc) /* TODO: We may wish to consider intentionally not defining an _Unwind_Resume wrapper. */ /* This would mean that a failure to wrap all exception functions is a linker error. */ WRAP_ABORT_FUNC(_Unwind_Resume) #undef WRAP_ABORT_FUNC } ================================================ FILE: libraries/libstratosphere/source/ams/ams_environment_weak.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> extern "C" void NORETURN __real_exit(int rc); namespace ams { WEAK_SYMBOL void *Malloc(size_t size) { return std::malloc(size); } WEAK_SYMBOL void Free(void *ptr) { return std::free(ptr); } WEAK_SYMBOL void *MallocForRapidJson(size_t size) { return std::malloc(size); } WEAK_SYMBOL void *ReallocForRapidJson(void *ptr, size_t size) { return std::realloc(ptr, size); } WEAK_SYMBOL void FreeForRapidJson(void *ptr) { return std::free(ptr); } WEAK_SYMBOL void NORETURN Exit(int rc) { __real_exit(rc); __builtin_unreachable(); } NOINLINE NORETURN void AbortImpl() { #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) /* Just perform a data abort. */ register u64 addr __asm__("x27") = FatalErrorContext::StdAbortMagicAddress; register u64 val __asm__("x28") = FatalErrorContext::StdAbortMagicValue; while (true) { __asm__ __volatile__ ( "str %[val], [%[addr]]" : : [val]"r"(val), [addr]"r"(addr) ); } #else /* What should be done here? */ AMS_INFINITE_LOOP(); #endif __builtin_unreachable(); } } extern "C" { /* Redefine abort to trigger these handlers. */ void abort(); /* Redefine C++ exception handlers. Requires wrap linker flag. */ #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { ::ams::AbortImpl(); __builtin_unreachable(); } WRAP_ABORT_FUNC(__cxa_pure_virtual) #undef WRAP_ABORT_FUNC void NORETURN __wrap_exit(int rc) { ::ams::Exit(rc); __builtin_unreachable(); } } /* Custom abort handler, so that std::abort will trigger these. */ void abort() { ams::AbortImpl(); __builtin_unreachable(); } ================================================ FILE: libraries/libstratosphere/source/ams/ams_environment_weak.os.linux.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams { namespace os { void Initialize(); } void *Malloc(size_t size) { return std::malloc(size); } void Free(void *ptr) { return std::free(ptr); } void *MallocForRapidJson(size_t size) { return std::malloc(size); } void *ReallocForRapidJson(void *ptr, size_t size) { return std::realloc(ptr, size); } void FreeForRapidJson(void *ptr) { return std::free(ptr); } NORETURN void AbortImpl() { std::abort(); } } extern "C" { /* Redefine C++ exception handlers. Requires wrap linker flag. */ #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } WRAP_ABORT_FUNC(__cxa_pure_virtual) #undef WRAP_ABORT_FUNC } ================================================ FILE: libraries/libstratosphere/source/ams/ams_environment_weak.os.macos.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams { namespace os { void Initialize(); } void *Malloc(size_t size) { return std::malloc(size); } void Free(void *ptr) { return std::free(ptr); } void *MallocForRapidJson(size_t size) { return std::malloc(size); } void *ReallocForRapidJson(void *ptr, size_t size) { return std::realloc(ptr, size); } void FreeForRapidJson(void *ptr) { return std::free(ptr); } NORETURN void AbortImpl() { std::abort(); } } extern "C" { /* Redefine C++ exception handlers. Requires wrap linker flag. */ #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } WRAP_ABORT_FUNC(__cxa_pure_virtual) #undef WRAP_ABORT_FUNC } ================================================ FILE: libraries/libstratosphere/source/ams/ams_environment_weak.os.windows.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> extern "C" char **__real___p__acmdln(void); extern "C" _invalid_parameter_handler __real__set_invalid_parameter_handler(_invalid_parameter_handler); namespace ams { namespace os { void Initialize(); } void *Malloc(size_t size) { return std::malloc(size); } void Free(void *ptr) { return std::free(ptr); } void *MallocForRapidJson(size_t size) { return std::malloc(size); } void *ReallocForRapidJson(void *ptr, size_t size) { return std::realloc(ptr, size); } void FreeForRapidJson(void *ptr) { return std::free(ptr); } NORETURN void AbortImpl() { std::abort(); } } extern "C" { /* Redefine C++ exception handlers. Requires wrap linker flag. */ #define WRAP_ABORT_FUNC(func) void NORETURN __wrap_##func(void) { std::abort(); __builtin_unreachable(); } WRAP_ABORT_FUNC(__cxa_pure_virtual) #undef WRAP_ABORT_FUNC /* On windows, mingw may attempt to call malloc before we've initialized globals to set up the command line. */ /* We perform some critical init here, to make that work. */ char **__wrap___p__acmdln(void) { ::ams::os::Initialize(); return __real___p__acmdln(); } /* On some mingw gcc versions, acmdln isn't used, so we need to hook a different part of crt init. */ _invalid_parameter_handler __wrap__set_invalid_parameter_handler(_invalid_parameter_handler handler) { ::ams::os::Initialize(); return __real__set_invalid_parameter_handler(handler); } } ================================================ FILE: libraries/libstratosphere/source/ams/ams_exosphere_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::exosphere { ApiInfo GetApiInfo() { u64 exosphere_cfg; if (R_FAILED(spl::impl::GetConfig(std::addressof(exosphere_cfg), spl::ConfigItem::ExosphereApiVersion))) { R_ABORT_UNLESS(exosphere::ResultNotPresent()); } return ApiInfo{ util::BitPack64{exosphere_cfg} }; } #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) void ForceRebootToRcm() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 1)); } void ForceRebootToIramPayload() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 2)); } void ForceRebootToFatalError() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 3)); } void ForceRebootByPmic() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 4)); } void ForceShutdown() { R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsShutdown, 1)); } void CopyToIram(uintptr_t iram_dst, const void *dram_src, size_t size) { spl::smc::AtmosphereCopyToIram(iram_dst, dram_src, size); } void CopyFromIram(void *dram_dst, uintptr_t iram_src, size_t size) { spl::smc::AtmosphereCopyFromIram(dram_dst, iram_src, size); } namespace { inline u64 GetU64ConfigItem(spl::ConfigItem cfg) { u64 tmp; R_ABORT_UNLESS(spl::smc::ConvertResult(spl::smc::GetConfig(std::addressof(tmp), 1, cfg))); return tmp; } inline bool GetBooleanConfigItem(spl::ConfigItem cfg) { return GetU64ConfigItem(cfg) != 0; } } bool IsRcmBugPatched() { return spl::impl::GetConfigBool(spl::ConfigItem::ExosphereHasRcmBugPatch); } bool ShouldBlankProdInfo() { return spl::impl::GetConfigBool(spl::ConfigItem::ExosphereBlankProdInfo); } bool ShouldAllowWritesToProdInfo() { return spl::impl::GetConfigBool(spl::ConfigItem::ExosphereAllowCalWrites); } u64 GetDeviceId() { u64 device_id; R_ABORT_UNLESS(spl::impl::GetConfig(std::addressof(device_id), spl::ConfigItem::DeviceId)); return device_id; } #endif } ================================================ FILE: libraries/libstratosphere/source/boot2/boot2_api.board.nintendo_nx.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::boot2 { namespace { /* Launch lists. */ /* psc, bus, pcv is the minimal set of required programs to get SD card. */ /* bus depends on pcie, and pcv depends on settings. */ constexpr const ncm::SystemProgramId PreSdCardLaunchPrograms[] = { ncm::SystemProgramId::Psc, /* psc */ ncm::SystemProgramId::Pcie, /* pcie */ ncm::SystemProgramId::Bus, /* bus */ ncm::SystemProgramId::Settings, /* settings */ ncm::SystemProgramId::Pcv, /* pcv */ ncm::SystemProgramId::Usb, /* usb */ }; constexpr size_t NumPreSdCardLaunchPrograms = util::size(PreSdCardLaunchPrograms); constexpr const ncm::SystemProgramId AdditionalLaunchPrograms[] = { ncm::SystemProgramId::Omm, /* omm */ ncm::SystemProgramId::Am, /* am */ ncm::SystemProgramId::NvServices, /* nvservices */ ncm::SystemProgramId::NvnFlinger, /* nvnflinger */ ncm::SystemProgramId::Vi, /* vi */ ncm::SystemProgramId::Pgl, /* pgl */ ncm::SystemProgramId::Ns, /* ns */ //ncm::SystemProgramId::LogManager, /* lm */ ncm::SystemProgramId::Ppc, /* ppc */ ncm::SystemProgramId::Ptm, /* ptm */ ncm::SystemProgramId::Hid, /* hid */ ncm::SystemProgramId::Audio, /* audio */ ncm::SystemProgramId::Lbl, /* lbl */ ncm::SystemProgramId::Wlan, /* wlan */ ncm::SystemProgramId::Bluetooth, /* bluetooth */ ncm::SystemProgramId::BsdSockets, /* bsdsockets */ ncm::SystemProgramId::Eth, /* eth */ ncm::SystemProgramId::Nifm, /* nifm */ ncm::SystemProgramId::Ldn, /* ldn */ ncm::SystemProgramId::Account, /* account */ ncm::SystemProgramId::Friends, /* friends */ ncm::SystemProgramId::Nfc, /* nfc */ ncm::SystemProgramId::JpegDec, /* jpegdec */ ncm::SystemProgramId::CapSrv, /* capsrv */ ncm::SystemProgramId::Ssl, /* ssl */ ncm::SystemProgramId::Nim, /* nim */ ncm::SystemProgramId::Bcat, /* bcat */ ncm::SystemProgramId::Erpt, /* erpt */ ncm::SystemProgramId::Es, /* es */ ncm::SystemProgramId::Pctl, /* pctl */ ncm::SystemProgramId::Btm, /* btm */ ncm::SystemProgramId::Eupld, /* eupld */ ncm::SystemProgramId::Glue, /* glue */ /* ncm::SystemProgramId::Eclct, */ /* eclct */ /* Skip launching error collection in Atmosphere to lessen telemetry. */ ncm::SystemProgramId::Npns, /* npns */ ncm::SystemProgramId::Fatal, /* fatal */ ncm::SystemProgramId::Ro, /* ro */ ncm::SystemProgramId::Profiler, /* profiler */ ncm::SystemProgramId::Sdb, /* sdb */ ncm::SystemProgramId::Olsc, /* olsc */ ncm::SystemProgramId::Ngc, /* ngc */ ncm::SystemProgramId::Ngct, /* ngct */ }; constexpr size_t NumAdditionalLaunchPrograms = util::size(AdditionalLaunchPrograms); constexpr const ncm::SystemProgramId AdditionalMaintenanceLaunchPrograms[] = { ncm::SystemProgramId::Omm, /* omm */ ncm::SystemProgramId::Am, /* am */ ncm::SystemProgramId::NvServices, /* nvservices */ ncm::SystemProgramId::NvnFlinger, /* nvnflinger */ ncm::SystemProgramId::Vi, /* vi */ ncm::SystemProgramId::Pgl, /* pgl */ ncm::SystemProgramId::Ns, /* ns */ //ncm::SystemProgramId::LogManager, /* lm */ ncm::SystemProgramId::Ppc, /* ppc */ ncm::SystemProgramId::Ptm, /* ptm */ ncm::SystemProgramId::Hid, /* hid */ ncm::SystemProgramId::Audio, /* audio */ ncm::SystemProgramId::Lbl, /* lbl */ ncm::SystemProgramId::Wlan, /* wlan */ ncm::SystemProgramId::Bluetooth, /* bluetooth */ ncm::SystemProgramId::BsdSockets, /* bsdsockets */ ncm::SystemProgramId::Eth, /* eth */ ncm::SystemProgramId::Nifm, /* nifm */ ncm::SystemProgramId::Ldn, /* ldn */ ncm::SystemProgramId::Account, /* account */ ncm::SystemProgramId::Nfc, /* nfc */ ncm::SystemProgramId::JpegDec, /* jpegdec */ ncm::SystemProgramId::CapSrv, /* capsrv */ ncm::SystemProgramId::Ssl, /* ssl */ ncm::SystemProgramId::Nim, /* nim */ ncm::SystemProgramId::Erpt, /* erpt */ ncm::SystemProgramId::Es, /* es */ ncm::SystemProgramId::Pctl, /* pctl */ ncm::SystemProgramId::Btm, /* btm */ ncm::SystemProgramId::Glue, /* glue */ /* ncm::SystemProgramId::Eclct, */ /* eclct */ /* Skip launching error collection in Atmosphere to lessen telemetry. */ ncm::SystemProgramId::Fatal, /* fatal */ ncm::SystemProgramId::Ro, /* ro */ ncm::SystemProgramId::Profiler, /* profiler */ ncm::SystemProgramId::Sdb, /* sdb */ ncm::SystemProgramId::Olsc, /* olsc */ ncm::SystemProgramId::Ngc, /* ngc */ ncm::SystemProgramId::Ngct, /* ngct */ }; constexpr size_t NumAdditionalMaintenanceLaunchPrograms = util::size(AdditionalMaintenanceLaunchPrograms); /* Helpers. */ inline bool IsHexadecimal(const char *str) { while (*str) { if (!std::isxdigit(static_cast<unsigned char>(*(str++)))) { return false; } } return true; } inline bool IsNewLine(char c) { return c == '\r' || c == '\n'; } inline bool IsAllowedLaunchProgram(const ncm::ProgramLocation &loc) { if (loc.program_id == ncm::SystemProgramId::Pgl) { return hos::GetVersion() >= hos::Version_10_0_0; } return true; } void LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags) { os::ProcessId process_id = os::InvalidProcessId; /* Only launch the process if we're allowed to. */ if (IsAllowedLaunchProgram(loc)) { /* Launch, lightly validate result. */ { const auto launch_result = pm::shell::LaunchProgram(std::addressof(process_id), loc, launch_flags); AMS_ABORT_UNLESS(!(svc::ResultOutOfResource::Includes(launch_result))); AMS_ABORT_UNLESS(!(svc::ResultOutOfMemory::Includes(launch_result))); AMS_ABORT_UNLESS(!(svc::ResultLimitReached::Includes(launch_result))); } if (out_process_id) { *out_process_id = process_id; } } } void LaunchList(const ncm::SystemProgramId *launch_list, size_t num_entries) { for (size_t i = 0; i < num_entries; i++) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(launch_list[i], ncm::StorageId::BuiltInSystem), 0); } } bool GetGpioPadLow(DeviceCode device_code) { gpio::GpioPadSession button{}; if (R_FAILED(gpio::OpenSession(std::addressof(button), device_code))) { return false; } /* Ensure we close even on early return. */ ON_SCOPE_EXIT { gpio::CloseSession(std::addressof(button)); }; /* Set direction input. */ gpio::SetDirection(std::addressof(button), gpio::Direction_Input); return gpio::GetValue(std::addressof(button)) == gpio::GpioValue_Low; } bool IsForceMaintenance() { u8 force_maintenance = 1; settings::fwdbg::GetSettingsItemValue(std::addressof(force_maintenance), sizeof(force_maintenance), "boot", "force_maintenance"); return force_maintenance != 0; } bool IsHtcEnabled() { u8 enable_htc = 0; settings::fwdbg::GetSettingsItemValue(std::addressof(enable_htc), sizeof(enable_htc), "atmosphere", "enable_htc"); return enable_htc != 0; } bool IsStandaloneGdbstubEnabled() { u8 enable_gdbstub = 0; settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub"); return enable_gdbstub != 0; } bool IsAtmosphereLogManagerEnabled() { /* If htc is enabled, ams log manager is enabled. */ if (IsHtcEnabled()) { return true; } u8 enable_ams_lm = 0; settings::fwdbg::GetSettingsItemValue(std::addressof(enable_ams_lm), sizeof(enable_ams_lm), "atmosphere", "enable_log_manager"); return enable_ams_lm != 0; } bool IsMaintenanceMode() { /* Contact set:sys, retrieve boot!force_maintenance. */ if (IsForceMaintenance()) { return true; } /* Contact GPIO, read plus/minus buttons. */ { return GetGpioPadLow(gpio::DeviceCode_ButtonVolUp) && GetGpioPadLow(gpio::DeviceCode_ButtonVolDn); } } template<typename F> void IterateOverFlaggedProgramsOnSdCard(F f) { /* Validate that the contents directory exists. */ fs::DirectoryHandle contents_dir; if (R_FAILED(fs::OpenDirectory(std::addressof(contents_dir), "sdmc:/atmosphere/contents", fs::OpenDirectoryMode_Directory))) { return; } ON_SCOPE_EXIT { fs::CloseDirectory(contents_dir); }; /* Iterate over entries in the contents directory */ fs::DirectoryEntry entry; s64 count; while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), std::addressof(entry), contents_dir, 1)) && count == 1) { /* Check that the subdirectory can be converted to a program id. */ if (std::strlen(entry.name) == 2 * sizeof(ncm::ProgramId) && IsHexadecimal(entry.name)) { /* Check if we've already launched the program. */ ncm::ProgramId program_id{std::strtoul(entry.name, nullptr, 16)}; /* Check if the program is flagged. */ if (!cfg::HasContentSpecificFlag(program_id, "boot2")) { continue; } /* Call the iteration callback. */ f(program_id); } } } void DetectAndDeclareFutureMitms() { IterateOverFlaggedProgramsOnSdCard([](ncm::ProgramId program_id) { /* When we find a flagged program, check if it has a mitm list. */ char mitm_list[0x400]; size_t mitm_list_size = 0; /* Read the mitm list off the SD card. */ { char path[fs::EntryNameLengthMax]; util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016" PRIx64 "/mitm.lst", static_cast<u64>(program_id)); fs::FileHandle f; if (R_FAILED(fs::OpenFile(std::addressof(f), path, fs::OpenMode_Read))) { return; } ON_SCOPE_EXIT { fs::CloseFile(f); }; R_ABORT_UNLESS(fs::ReadFile(std::addressof(mitm_list_size), f, 0, mitm_list, sizeof(mitm_list))); } /* Validate read size. */ if (mitm_list_size > sizeof(mitm_list) || mitm_list_size == 0) { return; } /* Iterate over the contents of the file. */ /* We expect one service name per non-empty line, 1-8 characters. */ size_t offset = 0; while (offset < mitm_list_size) { /* Continue to the start of the next name. */ while (IsNewLine(mitm_list[offset])) { offset++; } if (offset >= mitm_list_size) { break; } /* Get the length of the current name. */ size_t name_len; for (name_len = 0; name_len <= sizeof(sm::ServiceName) && offset + name_len < mitm_list_size; name_len++) { if (IsNewLine(mitm_list[offset + name_len])) { break; } } /* Allow empty lines. */ if (name_len == 0) { continue; } /* Don't allow invalid lines. */ AMS_ABORT_UNLESS(name_len <= sizeof(sm::ServiceName)); /* Declare the service. */ R_ABORT_UNLESS(sm::mitm::DeclareFutureMitm(sm::ServiceName::Encode(mitm_list + offset, name_len))); /* Advance to the next line. */ offset += name_len; } }); } void LaunchFlaggedProgramsOnSdCard() { IterateOverFlaggedProgramsOnSdCard([](ncm::ProgramId program_id) { /* Check if we've already launched the program. */ if (pm::info::HasLaunchedBootProgram(program_id)) { return; } /* Launch the program. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(program_id, ncm::StorageId::None), 0); }); } bool IsUsbRequiredToMountSdCard() { return hos::GetVersion() >= hos::Version_9_0_0; } } /* Boot2 API. */ void LaunchPreSdCardBootProgramsAndBoot2() { /* This code is normally run by PM. */ /* Wait until fs.mitm has installed itself. We want this to happen as early as possible. */ R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("fsp-srv"))); /* Launch programs required to mount the SD card. */ /* psc, bus, pcv (and usb on newer firmwares) is the minimal set of required programs. */ /* bus depends on pcie, and pcv depends on settings. */ { /* Launch psc. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Psc, ncm::StorageId::BuiltInSystem), 0); /* Launch pcie. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Pcie, ncm::StorageId::BuiltInSystem), 0); /* Launch bus. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Bus, ncm::StorageId::BuiltInSystem), 0); /* Launch settings. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Settings, ncm::StorageId::BuiltInSystem), 0); /* NOTE: Here we work around a race condition in the boot process by ensuring that settings initializes its db. */ { /* Connect to set:sys. */ R_ABORT_UNLESS(::setsysInitialize()); ON_SCOPE_EXIT { ::setsysExit(); }; /* Retrieve setting from the database. */ u8 force_maintenance = 0; settings::fwdbg::GetSettingsItemValue(std::addressof(force_maintenance), sizeof(force_maintenance), "boot", "force_maintenance"); } /* Launch pcv. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Pcv, ncm::StorageId::BuiltInSystem), 0); /* On 9.0.0+, FS depends on the USB sysmodule having been launched in order to mount the SD card. */ if (IsUsbRequiredToMountSdCard()) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Usb, ncm::StorageId::BuiltInSystem), 0); } } /* Wait for the SD card required services to be ready. */ cfg::WaitSdCardRequiredServicesReady(); /* Wait for other atmosphere mitm modules to initialize. */ R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("set:sys"))); if (spl::GetSocType() == spl::SocType_Erista) { if (hos::GetVersion() >= hos::Version_2_0_0) { R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc"))); } else { R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc:c"))); } } /* Launch Atmosphere boot2, using NcmStorageId_None to force SD card boot. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Boot2, ncm::StorageId::None), 0); } void LaunchPostSdCardBootPrograms() { /* This code is normally run by boot2. */ /* Launch the usb system module, if we haven't already. */ if (!IsUsbRequiredToMountSdCard()) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Usb, ncm::StorageId::BuiltInSystem), 0); } /* Activate the system fs content storage. */ R_ABORT_UNLESS(ncm::ActivateFsContentStorage(fs::ContentStorageId::System)); /* Find out whether we are maintenance mode. */ const bool maintenance = IsMaintenanceMode(); if (maintenance) { pm::bm::SetMaintenanceBoot(); } /* Check for and forward declare non-atmosphere mitm modules. */ DetectAndDeclareFutureMitms(); /* Decide whether to launch tma or htc. */ if (IsHtcEnabled()) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0); } else if (IsStandaloneGdbstubEnabled()) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0); } else { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0); } /* Decide whether to launch atmosphere or nintendo's log manager. */ if (IsAtmosphereLogManagerEnabled()) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::AtmosphereProgramId::AtmosphereLogManager, ncm::StorageId::None), 0); } else { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::LogManager, ncm::StorageId::BuiltInSystem), 0); } /* Launch additional programs. */ if (maintenance) { LaunchList(AdditionalMaintenanceLaunchPrograms, NumAdditionalMaintenanceLaunchPrograms); /* Starting in 7.0.0, npns is launched during maintenance boot. */ if (hos::GetVersion() >= hos::Version_7_0_0) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Npns, ncm::StorageId::BuiltInSystem), 0); } } else { LaunchList(AdditionalLaunchPrograms, NumAdditionalLaunchPrograms); } /* Prior to 12.0.0, boot2 was responsible for launching grc and migration. */ if (hos::GetVersion() < hos::Version_12_0_0) { LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Grc, ncm::StorageId::BuiltInSystem), 0); LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Migration, ncm::StorageId::BuiltInSystem), 0); } /* Launch atmosphere's applet memory service program. */ LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::AtmosphereProgramId::AtmosphereMemlet, ncm::StorageId::None), 0); /* Launch user programs off of the SD. */ LaunchFlaggedProgramsOnSdCard(); } } ================================================ FILE: libraries/libstratosphere/source/cal/cal_battery_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "cal_fs_utils.hpp" namespace ams::cal { namespace { constexpr inline s64 BatteryLotOffset = 0x2CE0; constexpr inline size_t BatteryLotSize = 0x20; constexpr inline s64 BatteryVersionOffset = 0x4310; constexpr inline size_t BatteryVersionSize = 0x10; constexpr inline size_t BatteryVendorSizeMax = 0x18; } Result GetBatteryVersion(u8 *out) { /* Read the battery version. */ u8 battery_version[BatteryVersionSize]; R_TRY(cal::impl::ReadCalibrationBlock(BatteryVersionOffset, battery_version, sizeof(battery_version))); /* Write the output. */ *out = battery_version[0]; R_SUCCEED(); } Result GetBatteryVendor(size_t *out_vendor_size, void *dst, size_t dst_size) { /* Read the battery lot. */ char battery_lot[BatteryLotSize]; R_TRY(cal::impl::ReadCalibrationBlock(BatteryLotOffset, battery_lot, sizeof(battery_lot))); /* Copy output. */ *out_vendor_size = static_cast<size_t>(util::Strlcpy(static_cast<char *>(dst), battery_lot, std::min(dst_size, BatteryVendorSizeMax))); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/cal/cal_crc_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "cal_crc_utils.hpp" namespace ams::cal::impl { namespace { constexpr inline const u16 CrcTable[0x10] = { 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 }; } u16 CalculateCrc16(const void *data, size_t size) { AMS_ASSERT(data != nullptr); u16 crc = 0x55AA; const u8 *data_u8 = static_cast<const u8 *>(data); for (size_t i = 0; i < size; ++i) { crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 0) & 0xF]); crc = (crc >> 4) ^ (CrcTable[crc & 0xF]) ^ (CrcTable[(data_u8[i] >> 4) & 0xF]); } return crc; } Result ValidateCalibrationCrc(const void *data, size_t size) { AMS_ASSERT(data != nullptr); AMS_ASSERT(size >= sizeof(u16)); const u16 crc = *reinterpret_cast<const u16 *>(reinterpret_cast<uintptr_t>(data) + size - sizeof(u16)); R_UNLESS(CalculateCrc16(data, size - sizeof(u16)) == crc, cal::ResultCalibrationDataCrcError()); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/cal/cal_crc_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::cal::impl { u16 CalculateCrc16(const void *data, size_t size); Result ValidateCalibrationCrc(const void *data, size_t size); } ================================================ FILE: libraries/libstratosphere/source/cal/cal_fs_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "cal_crc_utils.hpp" #include "cal_fs_utils.hpp" namespace ams::cal::impl { Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size) { /* Open the calibration binary partition. */ std::unique_ptr<fs::IStorage> storage; R_TRY(fs::OpenBisPartition(std::addressof(storage), fs::BisPartitionId::CalibrationBinary)); /* Read data from the partition. */ R_TRY(storage->Read(offset, dst, block_size)); /* Validate the crc. */ R_TRY(ValidateCalibrationCrc(dst, block_size)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/cal/cal_fs_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::cal::impl { Result ReadCalibrationBlock(s64 offset, void *dst, size_t block_size); } ================================================ FILE: libraries/libstratosphere/source/capsrv/capsrv_screen_shot_control_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::capsrv { Result InitializeScreenShotControl() { #if defined(ATMOSPHERE_OS_HORIZON) R_RETURN(::capsscInitialize()); #else AMS_ABORT("TODO"); #endif } void FinalizeScreenShotControl() { #if defined(ATMOSPHERE_OS_HORIZON) return ::capsscExit(); #else AMS_ABORT("TODO"); #endif } Result CaptureJpegScreenshot(u64 *out_size, void *dst, size_t dst_size, vi::LayerStack layer_stack, TimeSpan timeout) { #if defined(ATMOSPHERE_OS_HORIZON) R_RETURN(::capsscCaptureJpegScreenShot(out_size, dst, dst_size, static_cast<::ViLayerStack>(layer_stack), timeout.GetNanoSeconds())); #else AMS_UNUSED(out_size, dst, dst_size, layer_stack, timeout); AMS_ABORT("TODO"); #endif } Result OpenRawScreenShotReadStreamForDevelop(size_t *out_data_size, s32 *out_width, s32 *out_height, vi::LayerStack layer_stack, TimeSpan timeout) { #if defined(ATMOSPHERE_OS_HORIZON) u64 data_size, width, height; R_TRY(::capsscOpenRawScreenShotReadStream(std::addressof(data_size), std::addressof(width), std::addressof(height), static_cast<::ViLayerStack>(layer_stack), timeout.GetNanoSeconds())); *out_data_size = static_cast<size_t>(data_size); *out_width = static_cast<s32>(width); *out_height = static_cast<s32>(height); R_SUCCEED(); #else AMS_UNUSED(out_data_size, out_width, out_height, layer_stack, timeout); AMS_ABORT("TODO"); #endif } Result ReadRawScreenShotReadStreamForDevelop(size_t *out_read_size, void *dst, size_t dst_size, std::ptrdiff_t offset) { #if defined(ATMOSPHERE_OS_HORIZON) u64 read_size; R_TRY(::capsscReadRawScreenShotReadStream(std::addressof(read_size), dst, dst_size, static_cast<u64>(offset))); *out_read_size = static_cast<size_t>(read_size); R_SUCCEED(); #else AMS_UNUSED(out_read_size, dst, dst_size, offset); AMS_ABORT("TODO"); #endif } void CloseRawScreenShotReadStreamForDevelop() { #if defined(ATMOSPHERE_OS_HORIZON) ::capsscCloseRawScreenShotReadStream(); #else AMS_UNUSED(); AMS_ABORT("TODO"); #endif } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/capsrv_server_decoder_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv/decodersrv_decoder_server_object.hpp" namespace ams::capsrv::server { namespace { bool g_initialized = false; } Result InitializeForDecoderServer() { /* Ensure we initialize only once. */ AMS_ABORT_UNLESS(!g_initialized); /* Clear work memory. */ std::memset(std::addressof(g_work_memory), 0, sizeof(g_work_memory)); /* Initialize the decoder server. */ R_ABORT_UNLESS(g_decoder_control_server_manager.Initialize()); /* Start the server. */ g_decoder_control_server_manager.StartServer(); /* We're initialized. */ g_initialized = true; R_SUCCEED(); } void FinalizeForDecoderServer() { /* Ensure we don't finalize when uninitialized. */ AMS_ABORT_UNLESS(g_initialized); /* Finalize the server. */ g_decoder_control_server_manager.Finalize(); /* Mark uninitialized. */ g_initialized = false; } void DecoderControlServerThreadFunction(void *) { /* We need to be initialized. */ AMS_ABORT_UNLESS(g_initialized); /* Run the server. */ g_decoder_control_server_manager.RunServer(); } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_control_server_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv_decoder_server_object.hpp" namespace ams::capsrv::server { Result DecoderControlServerManager::Initialize() { /* Create the objects. */ m_service_holder.emplace(); m_server_manager_holder.emplace(); /* Register the service. */ R_ABORT_UNLESS((m_server_manager_holder->RegisterObjectForServer(m_service_holder->GetShared(), ServiceName, MaxSessions))); /* Initialize the idle event, we're idle initially. */ os::InitializeEvent(std::addressof(m_idle_event), true, os::EventClearMode_ManualClear); R_SUCCEED(); } void DecoderControlServerManager::Finalize() { /* Check that the server is idle. */ AMS_ASSERT(os::TryWaitEvent(std::addressof(m_idle_event))); /* Destroy the server. */ os::FinalizeEvent(std::addressof(m_idle_event)); m_server_manager_holder = util::nullopt; m_service_holder = util::nullopt; } void DecoderControlServerManager::StartServer() { m_server_manager_holder->ResumeProcessing(); } void DecoderControlServerManager::StopServer() { /* Request the server stop, and wait until it does. */ m_server_manager_holder->RequestStopProcessing(); os::WaitEvent(std::addressof(m_idle_event)); } void DecoderControlServerManager::RunServer() { /* Ensure that we are allowed to run. */ AMS_ABORT_UNLESS(os::TryWaitEvent(std::addressof(m_idle_event))); /* Clear the event. */ os::ClearEvent(std::addressof(m_idle_event)); /* Process forever. */ m_server_manager_holder->LoopProcess(); /* Signal that we're idle again. */ os::SignalEvent(std::addressof(m_idle_event)); } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_control_server_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "decodersrv_decoder_control_service.hpp" namespace ams::capsrv::server { class DecoderControlServerManager { public: /* NOTE: Nintendo only allows one session. */ static constexpr inline size_t NumServers = 1; static constexpr inline size_t MaxSessions = 2; static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("caps:dc"); using ServiceHolderType = ams::sf::UnmanagedServiceObject<capsrv::sf::IDecoderControlService, DecoderControlService>; using ServerOptions = ams::sf::hipc::DefaultServerManagerOptions; using ServerManager = ams::sf::hipc::ServerManager<NumServers, ServerOptions, MaxSessions>; private: util::optional<ServiceHolderType> m_service_holder; util::optional<ServerManager> m_server_manager_holder; os::EventType m_idle_event; public: constexpr DecoderControlServerManager() : m_service_holder(), m_server_manager_holder(), m_idle_event{} { /* ... */ } Result Initialize(); void Finalize(); void StartServer(); void StopServer(); void RunServer(); }; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_control_service.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv_decoder_server_object.hpp" #include "../jpeg/decodersrv_software_jpeg_decoder.hpp" #include "../jpeg/decodersrv_software_jpeg_shrinker.hpp" namespace ams::capsrv::server { namespace { constexpr const int JpegShrinkQualities[] = { 98, 95, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0 }; Result DecodeJpegImpl(void *dst, size_t dst_size, const void *src_jpeg, size_t src_jpeg_size, u32 width, u32 height, const ScreenShotDecodeOption &option, void *work, size_t work_size) { /* Clear the work memory. */ std::memset(work, 0, work_size); ON_SCOPE_EXIT { std::memset(work, 0, work_size); }; /* Clear the output memory. */ std::memset(dst, 0, dst_size); auto clear_guard = SCOPE_GUARD { std::memset(dst, 0, dst_size); }; /* Validate parameters. */ R_UNLESS(util::IsAligned(width, 0x10), capsrv::ResultAlbumOutOfRange()); R_UNLESS(util::IsAligned(height, 0x4), capsrv::ResultAlbumOutOfRange()); R_UNLESS(dst != nullptr, capsrv::ResultAlbumReadBufferShortage()); R_UNLESS(dst_size >= 4 * width * height, capsrv::ResultAlbumReadBufferShortage()); R_UNLESS(src_jpeg != nullptr, capsrv::ResultAlbumInvalidFileData()); R_UNLESS(src_jpeg_size != 0, capsrv::ResultAlbumInvalidFileData()); /* Create the input. */ const jpeg::SoftwareJpegDecoderInput decode_input = { .jpeg = src_jpeg, .jpeg_size = src_jpeg_size, .width = width, .height = height, .fancy_upsampling = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableFancyUpsampling), .block_smoothing = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableBlockSmoothing), }; /* Create the output. */ s32 out_width = 0, out_height = 0; jpeg::SoftwareJpegDecoderOutput decode_output = { .out_width = std::addressof(out_width), .out_height = std::addressof(out_height), .dst = dst, .dst_size = dst_size, }; /* Decode the jpeg. */ R_TRY(jpeg::SoftwareJpegDecoder::DecodeRgba8(decode_output, decode_input, work, work_size)); /* We succeeded, so we shouldn't clear the output memory. */ clear_guard.Cancel(); R_SUCCEED(); } Result ShrinkJpegImpl(u64 *out_size, void *dst, size_t dst_size, const void *src_jpeg, size_t src_jpeg_size, u32 width, u32 height, const ScreenShotDecodeOption &option, void *work, size_t work_size) { /* Validate parameters. */ R_UNLESS(util::IsAligned(width, 0x10), capsrv::ResultAlbumOutOfRange()); R_UNLESS(util::IsAligned(height, 0x4), capsrv::ResultAlbumOutOfRange()); R_UNLESS(dst != nullptr, capsrv::ResultInternalJpegOutBufferShortage()); R_UNLESS(dst_size != 0, capsrv::ResultAlbumReadBufferShortage()); R_UNLESS(src_jpeg != nullptr, capsrv::ResultAlbumInvalidFileData()); R_UNLESS(src_jpeg_size != 0, capsrv::ResultAlbumInvalidFileData()); /* Create the input. */ const jpeg::SoftwareJpegShrinkerInput shrink_input = { .jpeg = src_jpeg, .jpeg_size = src_jpeg_size, .width = width, .height = height, .fancy_upsampling = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableFancyUpsampling), .block_smoothing = option.HasJpegDecoderFlag(ScreenShotDecoderFlag_EnableBlockSmoothing), }; /* Create the output. */ u64 shrunk_size = 0; s32 shrunk_width = 0, shrunk_height = 0; jpeg::SoftwareJpegShrinkerOutput shrink_output = { .out_size = std::addressof(shrunk_size), .out_width = std::addressof(shrunk_width), .out_height = std::addressof(shrunk_height), .dst = dst, .dst_size = dst_size, }; /* Try to shrink the jpeg at various quality levels. */ for (auto quality : JpegShrinkQualities) { /* Shrink at the current quality. */ R_TRY_CATCH(jpeg::SoftwareJpegShrinker::ShrinkRgba8(shrink_output, shrink_input, quality, work, work_size)) { /* If the output buffer isn't large enough to fit the output, we should try at a lower quality. */ R_CATCH(capsrv::ResultInternalJpegOutBufferShortage) { continue; } /* Nintendo doesn't catch this result, but our lack of work buffer use makes me think this may be necessary. */ R_CATCH(capsrv::ResultInternalJpegWorkMemoryShortage) { continue; } } R_END_TRY_CATCH; /* Write the output size. */ *out_size = shrunk_size; R_SUCCEED(); } /* Nintendo aborts if no quality succeeds. */ AMS_ABORT("ShrinkJpeg should succeed before this point\n"); } } Result DecoderControlService::DecodeJpeg(const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const ScreenShotDecodeOption &option) { /* Get the work buffer. */ void *work = g_work_memory.jpeg_decoder_memory; size_t work_size = sizeof(g_work_memory.jpeg_decoder_memory); /* Call the decoder implementation. */ R_RETURN(DecodeJpegImpl(out.GetPointer(), out.GetSize(), in.GetPointer(), in.GetSize(), width, height, option, work, work_size)); } Result DecoderControlService::ShrinkJpeg(ams::sf::Out<u64> out_size, const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const capsrv::ScreenShotDecodeOption &option) { /* Get the work buffer. */ void *work = g_work_memory.jpeg_decoder_memory; size_t work_size = sizeof(g_work_memory.jpeg_decoder_memory); /* Call the shrink implementation. */ R_RETURN(ShrinkJpegImpl(out_size.GetPointer(), out.GetPointer(), out.GetSize(), in.GetPointer(), in.GetSize(), width, height, option, work, work_size)); } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_control_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #define AMS_CAPSRV_DECODER_CONTROL_SERVICE_INTERFACE_INFO(C, H) \ AMS_SF_METHOD_INFO(C, H, 3001, Result, DecodeJpeg, (const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const capsrv::ScreenShotDecodeOption &option), (out, in, width, height, option)) \ AMS_SF_METHOD_INFO(C, H, 4001, Result, ShrinkJpeg, (ams::sf::Out<u64> out_size, const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const capsrv::ScreenShotDecodeOption &option), (out_size, out, in, width, height, option)) AMS_SF_DEFINE_INTERFACE(ams::capsrv::sf, IDecoderControlService, AMS_CAPSRV_DECODER_CONTROL_SERVICE_INTERFACE_INFO, 0xD168E90B) namespace ams::capsrv::server { class DecoderControlService final { public: Result DecodeJpeg(const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const ScreenShotDecodeOption &option); Result ShrinkJpeg(ams::sf::Out<u64> out_size, const ams::sf::OutNonSecureBuffer &out, const ams::sf::InBuffer &in, u32 width, u32 height, const capsrv::ScreenShotDecodeOption &option); }; static_assert(capsrv::sf::IsIDecoderControlService<DecoderControlService>); } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_server_object.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv_decoder_server_object.hpp" namespace ams::capsrv::server { /* Instantiate the decoder server globals in a single TU. */ DecoderWorkMemory g_work_memory; DecoderControlServerManager g_decoder_control_server_manager; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_server_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "decodersrv_decoder_work_memory.hpp" #include "decodersrv_decoder_control_server_manager.hpp" namespace ams::capsrv::server { extern DecoderWorkMemory g_work_memory; extern DecoderControlServerManager g_decoder_control_server_manager; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/decodersrv/decodersrv_decoder_work_memory.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::capsrv::server { struct DecoderWorkMemory { alignas(os::MemoryPageSize) u8 jpeg_decoder_memory[SoftwareJpegDecoderWorkMemorySize]; }; static_assert(sizeof(DecoderWorkMemory) == SoftwareJpegDecoderWorkMemorySize); static_assert(alignof(DecoderWorkMemory) == os::MemoryPageSize); static_assert(util::is_pod<DecoderWorkMemory>::value); } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/capsrv_server_jpeg_error_handler.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <csetjmp> #include "capsrv_server_jpeg_library_types.hpp" namespace ams::capsrv::server::jpeg { struct JpegErrorHandler : public JpegLibraryType::jpeg_error_mgr { public: std::jmp_buf jmp_buf; Result result; public: static void HandleError(JpegLibraryType::jpeg_common_struct *common) { /* Retrieve the handler. */ JpegErrorHandler *handler = reinterpret_cast<JpegErrorHandler *>(common->err); /* Set the result. */ handler->result = GetResult(handler->msg_code, handler->msg_parm.i[0]); /* Return to the caller. */ longjmp(handler->jmp_buf, -1); } static Result GetResult(int msg_code, int msg_param) { /* NOTE: Nintendo uses msg_param for error codes that we never trigger. */ /* TODO: Fully support all J_MESSAGE_CODEs that Nintendo handles? */ AMS_UNUSED(msg_param); switch (msg_code) { case JpegLibraryType::J_MESSAGE_CODE::JERR_BUFFER_SIZE: case JpegLibraryType::J_MESSAGE_CODE::JERR_NO_BACKING_STORE: case JpegLibraryType::J_MESSAGE_CODE::JERR_OUT_OF_MEMORY: case JpegLibraryType::J_MESSAGE_CODE::JERR_TFILE_CREATE: case JpegLibraryType::J_MESSAGE_CODE::JERR_TFILE_READ: case JpegLibraryType::J_MESSAGE_CODE::JERR_TFILE_SEEK: case JpegLibraryType::J_MESSAGE_CODE::JERR_TFILE_WRITE: R_THROW(capsrv::ResultInternalJpegWorkMemoryShortage()); default: R_THROW(capsrv::ResultInternalJpegEncoderError()); } } }; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/capsrv_server_jpeg_library_types.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <jpeglib.h> #include <jerror.h> namespace ams::capsrv::server::jpeg { class JpegLibraryType { public: using jpeg_common_struct = ::jpeg_common_struct; using jpeg_compress_struct = ::jpeg_compress_struct; using jpeg_decompress_struct = ::jpeg_decompress_struct; using jpeg_error_mgr = ::jpeg_error_mgr; using jpeg_destination_mgr = ::jpeg_destination_mgr; using j_common_ptr = ::j_common_ptr; using j_compress_ptr = ::j_compress_ptr; using boolean = ::boolean; using JOCTET = ::JOCTET; using JDIMENSION = ::JDIMENSION; using JSAMPARRAY = ::JSAMPARRAY; using JSAMPROW = ::JSAMPROW; using J_COLOR_SPACE = ::J_COLOR_SPACE; using J_DCT_METHOD = ::J_DCT_METHOD; using J_MESSAGE_CODE = ::J_MESSAGE_CODE; }; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/decodersrv_software_jpeg_decoder.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv_software_jpeg_decoder.hpp" #include "capsrv_server_jpeg_library_types.hpp" #include "capsrv_server_jpeg_error_handler.hpp" namespace ams::capsrv::server::jpeg { #define CAPSRV_ABORT_UNLESS(expr) do { \ const bool __capsrv_assert_res = (expr); \ AMS_ASSERT(__capsrv_assert_res); \ AMS_ABORT_UNLESS(__capsrv_assert_res); \ } while (0) #define CAPSRV_ASSERT(expr) do { \ const bool __capsrv_assert_res = (expr); \ AMS_ASSERT(__capsrv_assert_res); \ R_UNLESS(__capsrv_assert_res, capsrv::ResultAlbumError()); \ } while (0) namespace { constexpr s32 ImageSizeHorizonalUnit = 0x10; constexpr s32 ImageSizeVerticalUnit = 0x4; constexpr s32 RgbColorComponentCount = 3; constexpr s32 RgbaColorComponentCount = 4; Result GetRgbBufferSize(size_t *out_size, size_t *out_stride, s32 width, size_t work_size) { /* Calculate the space we need and verify we have enough. */ const size_t rgb_width = util::AlignUp(static_cast<size_t>(width), ImageSizeHorizonalUnit); const size_t rgb_stride = rgb_width * RgbColorComponentCount; const size_t rgb_size = rgb_stride * ImageSizeVerticalUnit; R_UNLESS(work_size >= rgb_size, capsrv::ResultInternalJpegWorkMemoryShortage()); /* Return the output to the caller. */ *out_size = rgb_size; *out_stride = rgb_stride; R_SUCCEED(); } } Result SoftwareJpegDecoder::DecodeRgba8(SoftwareJpegDecoderOutput &output, const SoftwareJpegDecoderInput &input, void *work, size_t work_size) { CAPSRV_ABORT_UNLESS(util::IsAligned(input.width, ImageSizeHorizonalUnit)); CAPSRV_ABORT_UNLESS(util::IsAligned(input.height, ImageSizeVerticalUnit)); CAPSRV_ABORT_UNLESS(output.dst != nullptr); CAPSRV_ABORT_UNLESS(output.dst_size >= static_cast<size_t>(RgbaColorComponentCount * input.width * input.height)); CAPSRV_ABORT_UNLESS(output.out_width != nullptr); CAPSRV_ABORT_UNLESS(output.out_height != nullptr); /* Determine work buffer extents. */ char *work_start = static_cast<char *>(work); char *work_end = work_start + work_size; /* Determine the buffer extents for our linebuffers. */ u8 *rgb_buffer = static_cast<u8 *>(static_cast<void *>(work_start)); size_t rgb_buffer_size; size_t rgb_buffer_stride; R_TRY(GetRgbBufferSize(std::addressof(rgb_buffer_size), std::addressof(rgb_buffer_stride), input.width, work_size)); /* The start of the workbuffer is reserved for linebuffer space. */ work_start += rgb_buffer_size; /* Create our decompression structure. */ JpegLibraryType::jpeg_decompress_struct cinfo = {}; /* Here nintendo creates a work buffer structure containing work_start + work_size. */ /* This seems to be a custom patch for/to libjpeg-turbo. */ /* It would be desirable for us to mimic this, because it gives Nintendo strong */ /* fixed memory usage guarantees. */ /* TODO: Determine if it is feasible for us to recreate this ourselves, */ /* Either by adding support to the devkitPro libjpeg-turbo portlib or otherwise. */ AMS_UNUSED(work_end); /* Create our error manager. */ JpegErrorHandler jerr = { .result = ResultSuccess(), }; jerr.error_exit = JpegErrorHandler::HandleError, /* Link our error manager to our decompression structure. */ cinfo.err = jpeg_std_error(std::addressof(jerr)); /* Use setjmp, so that on error our handler will longjmp to return an error result. */ if (setjmp(jerr.jmp_buf) == 0) { /* Create our decompressor. */ jpeg_create_decompress(std::addressof(cinfo)); ON_SCOPE_EXIT { jpeg_destroy_decompress(std::addressof(cinfo)); }; /* Setup our memory reader, ensure the header is correct. */ jpeg_mem_src(std::addressof(cinfo), const_cast<unsigned char *>(static_cast<const unsigned char *>(input.jpeg)), input.jpeg_size); R_UNLESS(jpeg_read_header(std::addressof(cinfo), true) == JPEG_HEADER_OK, capsrv::ResultAlbumInvalidFileData()); /* Ensure width and height are correct. */ R_UNLESS(cinfo.image_width == input.width, capsrv::ResultAlbumInvalidFileData()); R_UNLESS(cinfo.image_height == input.height, capsrv::ResultAlbumInvalidFileData()); /* Set output parameters. */ cinfo.out_color_space = JpegLibraryType::J_COLOR_SPACE::JCS_RGB; cinfo.dct_method = JpegLibraryType::J_DCT_METHOD::JDCT_ISLOW; cinfo.do_fancy_upsampling = input.fancy_upsampling; cinfo.do_block_smoothing = input.block_smoothing; /* Start decompression. */ R_UNLESS(jpeg_start_decompress(std::addressof(cinfo)) == TRUE, capsrv::ResultAlbumInvalidFileData()); /* Check the parameters. */ CAPSRV_ASSERT(cinfo.output_width == input.width); CAPSRV_ASSERT(cinfo.output_height == input.height); CAPSRV_ASSERT(cinfo.out_color_components == RgbColorComponentCount); CAPSRV_ASSERT(cinfo.output_components == RgbColorComponentCount); /* Parse the scanlines. */ { /* Convert our destination to a writable u8 buffer. */ u8 *dst = static_cast<u8 *>(output.dst); /* Create our linebuffer structure. */ JpegLibraryType::JSAMPROW linebuffers[ImageSizeVerticalUnit] = {}; for (int i = 0; i < ImageSizeVerticalUnit; i++) { linebuffers[i] = rgb_buffer + rgb_buffer_stride * i; } /* While we still have scanlines, parse! */ while (cinfo.output_scanline < input.height) { /* Decode scanlines. */ int num_scanlines = jpeg_read_scanlines(std::addressof(cinfo), linebuffers, ImageSizeVerticalUnit); CAPSRV_ASSERT(num_scanlines <= ImageSizeVerticalUnit); /* Write out line by line. */ for (s32 i = 0; i < num_scanlines; i++) { const u8 *src = linebuffers[i]; for (s32 j = 0; j < static_cast<s32>(input.width); j++) { /* Write the output. */ /* First R, */ *(dst++) = *(src++); /* Then G, */ *(dst++) = *(src++); /* Then B, */ *(dst++) = *(src++); /* Then A. */ *(dst++) = 0xFF; } } } } /* Finish the decompression. */ R_UNLESS(jpeg_finish_decompress(std::addressof(cinfo)) == TRUE, capsrv::ResultAlbumInvalidFileData()); } else { /* Some unknown error was caught by our handler. */ R_THROW(capsrv::ResultAlbumInvalidFileData()); } /* Write the size we decoded to output. */ *output.out_width = static_cast<s32>(cinfo.output_width); *output.out_width = static_cast<s32>(cinfo.output_height); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/decodersrv_software_jpeg_decoder.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::capsrv::server::jpeg { struct SoftwareJpegDecoderInput { const void *jpeg; size_t jpeg_size; u32 width; u32 height; bool fancy_upsampling; bool block_smoothing; }; struct SoftwareJpegDecoderOutput { s32 *out_width; s32 *out_height; void *dst; size_t dst_size; }; class SoftwareJpegDecoder { public: static Result DecodeRgba8(SoftwareJpegDecoderOutput &output, const SoftwareJpegDecoderInput &input, void *work, size_t work_size); }; } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/decodersrv_software_jpeg_shrinker.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "decodersrv_software_jpeg_shrinker.hpp" #include "capsrv_server_jpeg_library_types.hpp" #include "capsrv_server_jpeg_error_handler.hpp" namespace ams::capsrv::server::jpeg { #define CAPSRV_ABORT_UNLESS(expr) do { \ const bool __capsrv_assert_res = (expr); \ AMS_ASSERT(__capsrv_assert_res); \ AMS_ABORT_UNLESS(__capsrv_assert_res); \ } while (0) #define CAPSRV_ASSERT(expr) do { \ const bool __capsrv_assert_res = (expr); \ AMS_ASSERT(__capsrv_assert_res); \ R_UNLESS(__capsrv_assert_res, capsrv::ResultAlbumError()); \ } while (0) namespace { constexpr s32 ImageSizeHorizonalUnit = 0x10; constexpr s32 ImageSizeVerticalUnitDecode = 0x4; constexpr s32 ImageSizeVerticalUnitEncode = 0x8; constexpr s32 RgbColorComponentCount = 3; constexpr s32 RgbaColorComponentCount = 4; Result GetRgbBufferSize(size_t *out_size, size_t *out_stride, s32 width, size_t work_size) { /* Calculate the space we need and verify we have enough. */ const size_t rgb_width = util::AlignUp(static_cast<size_t>(width), ImageSizeHorizonalUnit); const size_t rgb_stride = rgb_width * RgbColorComponentCount; const size_t rgb_size = rgb_stride * ImageSizeVerticalUnitEncode; R_UNLESS(work_size >= rgb_size, capsrv::ResultInternalJpegWorkMemoryShortage()); /* Return the output to the caller. */ *out_size = rgb_size; *out_stride = rgb_stride; R_SUCCEED(); } void SetupEncodingParameter(JpegLibraryType::jpeg_compress_struct *cinfo, const SoftwareJpegShrinkerInput &input, int quality) { /* Set parameters. */ cinfo->image_width = static_cast<JpegLibraryType::JDIMENSION>(input.width / 2); cinfo->image_height = static_cast<JpegLibraryType::JDIMENSION>(input.height / 2); cinfo->input_components = RgbColorComponentCount; cinfo->in_color_space = JpegLibraryType::J_COLOR_SPACE::JCS_RGB; /* Set defaults/color space. */ jpeg_set_defaults(cinfo); jpeg_set_colorspace(cinfo, JpegLibraryType::J_COLOR_SPACE::JCS_YCbCr); /* Configure sampling. */ /* libjpeg-turbo doesn't actually have this field, as of now. */ /* cinfo->do_fancy_downsampling = false; */ cinfo->comp_info[0].h_samp_factor = 2; cinfo->comp_info[0].v_samp_factor = 1; cinfo->comp_info[1].h_samp_factor = 1; cinfo->comp_info[1].v_samp_factor = 1; cinfo->comp_info[2].h_samp_factor = 1; cinfo->comp_info[2].v_samp_factor = 1; /* Set the quality. */ jpeg_set_quality(cinfo, quality, true); /* Configure remaining parameters. */ cinfo->dct_method = JpegLibraryType::J_DCT_METHOD::JDCT_ISLOW; cinfo->optimize_coding = false; cinfo->write_JFIF_header = true; } } Result SoftwareJpegShrinker::ShrinkRgba8(SoftwareJpegShrinkerOutput &output, const SoftwareJpegShrinkerInput &input, int quality, void *work, size_t work_size) { CAPSRV_ABORT_UNLESS(util::IsAligned(input.width, ImageSizeHorizonalUnit)); CAPSRV_ABORT_UNLESS(util::IsAligned(input.height, ImageSizeVerticalUnitDecode)); const u32 shrunk_width = input.width / 2; const u32 shrunk_height = input.height / 2; CAPSRV_ABORT_UNLESS(util::IsAligned(shrunk_width, ImageSizeHorizonalUnit)); CAPSRV_ABORT_UNLESS(output.dst != nullptr); CAPSRV_ABORT_UNLESS(output.out_width != nullptr); CAPSRV_ABORT_UNLESS(output.out_height != nullptr); /* Determine work buffer extents. */ char *work_start = static_cast<char *>(work); char *work_end = work_start + work_size; /* Determine the buffer extents for our linebuffers. */ u8 *rgb_buffer = static_cast<u8 *>(static_cast<void *>(work_start)); size_t rgb_buffer_size; size_t rgb_buffer_stride; R_TRY(GetRgbBufferSize(std::addressof(rgb_buffer_size), std::addressof(rgb_buffer_stride), input.width, work_size)); /* The start of the workbuffer is reserved for linebuffer space. */ work_start += rgb_buffer_size; /* Create our compression structures. */ JpegLibraryType::jpeg_decompress_struct dcinfo = {}; JpegLibraryType::jpeg_compress_struct ecinfo = {}; /* Here nintendo creates a work buffer structure containing work_start + work_size. */ /* This seems to be a custom patch for/to libjpeg-turbo. */ /* It would be desirable for us to mimic this, because it gives Nintendo strong */ /* fixed memory usage guarantees. */ /* TODO: Determine if it is feasible for us to recreate this ourselves, */ /* Either by adding support to the devkitPro libjpeg-turbo portlib or otherwise. */ AMS_UNUSED(work_end); /* Create our error managers. */ JpegErrorHandler jerr_dc = { .result = ResultSuccess(), }; JpegErrorHandler jerr_ec = { .result = ResultSuccess(), }; jerr_dc.error_exit = JpegErrorHandler::HandleError, jerr_ec.error_exit = JpegErrorHandler::HandleError, /* Link our error managers to our compression structures. */ dcinfo.err = jpeg_std_error(std::addressof(jerr_dc)); ecinfo.err = jpeg_std_error(std::addressof(jerr_ec)); /* Use setjmp, so that on error our handler will longjmp to return an error result. */ if (setjmp(jerr_ec.jmp_buf) == 0) { if (setjmp(jerr_dc.jmp_buf) == 0) { /* Create our decompressor. */ jpeg_create_decompress(std::addressof(dcinfo)); ON_SCOPE_EXIT { jpeg_destroy_decompress(std::addressof(dcinfo)); }; /* Setup our memory reader, ensure the header is correct. */ jpeg_mem_src(std::addressof(dcinfo), const_cast<unsigned char *>(static_cast<const unsigned char *>(input.jpeg)), input.jpeg_size); R_UNLESS(jpeg_read_header(std::addressof(dcinfo), true) == JPEG_HEADER_OK, capsrv::ResultAlbumInvalidFileData()); /* Ensure width and height are correct. */ R_UNLESS(dcinfo.image_width == input.width, capsrv::ResultAlbumInvalidFileData()); R_UNLESS(dcinfo.image_height == input.height, capsrv::ResultAlbumInvalidFileData()); /* Set output parameters. */ dcinfo.out_color_space = JpegLibraryType::J_COLOR_SPACE::JCS_RGB; dcinfo.dct_method = JpegLibraryType::J_DCT_METHOD::JDCT_ISLOW; dcinfo.do_fancy_upsampling = input.fancy_upsampling; dcinfo.do_block_smoothing = input.block_smoothing; dcinfo.scale_num = 1; dcinfo.scale_denom = 2; /* Start decompression. */ R_UNLESS(jpeg_start_decompress(std::addressof(dcinfo)) == TRUE, capsrv::ResultAlbumInvalidFileData()); /* Check the parameters. */ CAPSRV_ASSERT(dcinfo.output_width == shrunk_width); CAPSRV_ASSERT(dcinfo.output_height == shrunk_height); CAPSRV_ASSERT(dcinfo.out_color_components == RgbColorComponentCount); CAPSRV_ASSERT(dcinfo.output_components == RgbColorComponentCount); /* Create our compressor. */ jpeg_create_compress(std::addressof(ecinfo)); ON_SCOPE_EXIT { jpeg_destroy_compress(std::addressof(ecinfo)); }; /* Setup our memory writer. */ unsigned long out_size = static_cast<unsigned long>(output.dst_size); jpeg_mem_dest(std::addressof(ecinfo), reinterpret_cast<unsigned char **>(std::addressof(output.dst)), std::addressof(out_size)); /* Setup the encoding parameters. */ SetupEncodingParameter(std::addressof(ecinfo), input, quality); /* Start compression. */ jpeg_start_compress(std::addressof(ecinfo), true); /* Parse the scanlines. */ { /* Create our linebuffer structure. */ JpegLibraryType::JSAMPROW linebuffers[ImageSizeVerticalUnitEncode] = {}; for (int i = 0; i < ImageSizeVerticalUnitEncode; i++) { linebuffers[i] = rgb_buffer + rgb_buffer_stride * i; } /* While we still have scanlines, parse! */ while (dcinfo.output_scanline < shrunk_height) { /* Determine remaining scanlines. */ const auto remaining_scanlines = shrunk_height - dcinfo.output_scanline; const auto cur_max_scanlines = std::min<s32>(remaining_scanlines, ImageSizeVerticalUnitEncode); /* If we have scanlines to decode, try to do so. */ auto writable_scanlines = 0; while (writable_scanlines < cur_max_scanlines) { const auto decoded = jpeg_read_scanlines(std::addressof(dcinfo), linebuffers + writable_scanlines, ImageSizeVerticalUnitDecode); CAPSRV_ASSERT(decoded <= ImageSizeVerticalUnitDecode / 2); writable_scanlines += decoded; } /* If we have scanlines to write, try to do so. */ jpeg_write_scanlines(std::addressof(ecinfo), linebuffers, writable_scanlines); } } /* Finish the decompression. */ R_UNLESS(jpeg_finish_decompress(std::addressof(dcinfo)) == TRUE, capsrv::ResultAlbumInvalidFileData()); /* Finish the compression. */ jpeg_finish_compress(std::addressof(ecinfo)); /* Set the output size. */ *output.out_size = out_size; } else { /* Some unknown error was caught by our handler. */ R_THROW(capsrv::ResultAlbumInvalidFileData()); } } else { /* Return the encoding result. */ R_THROW(jerr_ec.result); } /* Write the size we decoded to output. */ *output.out_width = static_cast<s32>(dcinfo.output_width); *output.out_width = static_cast<s32>(dcinfo.output_height); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/capsrv/server/jpeg/decodersrv_software_jpeg_shrinker.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::capsrv::server::jpeg { struct SoftwareJpegShrinkerInput { const void *jpeg; size_t jpeg_size; u32 width; u32 height; bool fancy_upsampling; bool block_smoothing; }; struct SoftwareJpegShrinkerOutput { u64 *out_size; s32 *out_width; s32 *out_height; void *dst; size_t dst_size; }; class SoftwareJpegShrinker { public: static Result ShrinkRgba8(SoftwareJpegShrinkerOutput &output, const SoftwareJpegShrinkerInput &input, int quality, void *work, size_t work_size); }; } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_flags.board.nintendo_nx.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { namespace { std::atomic<u32> g_flag_mount_count; /* Helper. */ void GetFlagMountName(char *dst) { util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#flag%08x", g_flag_mount_count.fetch_add(1)); } bool HasFlagFile(const char *flag_path) { /* All flags are not present until the SD card is. */ if (!IsSdCardInitialized()) { return false; } /* Mount the SD card. */ char mount_name[fs::MountNameLengthMax + 1]; GetFlagMountName(mount_name); if (R_FAILED(fs::MountSdCard(mount_name))) { return false; } ON_SCOPE_EXIT { fs::Unmount(mount_name); }; /* Check if the entry exists. */ char full_path[fs::EntryNameLengthMax + 1]; util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); bool has_file; if (R_FAILED(fs::HasFile(std::addressof(has_file), full_path))) { return false; } return has_file; } Result DeleteFlagFile(const char *flag_path) { /* We need the SD card to be available to delete anything. */ AMS_ABORT_UNLESS(IsSdCardInitialized()); /* Mount the sd card. */ char mount_name[fs::MountNameLengthMax + 1]; GetFlagMountName(mount_name); R_TRY(fs::MountSdCard(mount_name)); ON_SCOPE_EXIT { fs::Unmount(mount_name); }; /* Get the flag path. */ char full_path[fs::EntryNameLengthMax + 1]; util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, flag_path[0] == '/' ? flag_path + 1 : flag_path); /* Delete the file. */ R_TRY(fs::DeleteFile(full_path)); return ResultSuccess(); } } /* Flag utilities. */ bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag) { return HasContentSpecificFlag(process_info.program_id, flag) || (process_info.override_status.IsHbl() && HasHblFlag(flag)); } bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag) { char content_flag[fs::EntryNameLengthMax + 1]; util::SNPrintf(content_flag, sizeof(content_flag) - 1, "/atmosphere/contents/%016" PRIx64 "/flags/%s.flag", program_id.value, flag); return HasFlagFile(content_flag); } bool HasGlobalFlag(const char *flag) { char global_flag[fs::EntryNameLengthMax + 1]; util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); return HasFlagFile(global_flag); } bool HasHblFlag(const char *flag) { char hbl_flag[0x100]; util::SNPrintf(hbl_flag, sizeof(hbl_flag) - 1, "hbl_%s", flag); return HasGlobalFlag(hbl_flag); } Result DeleteGlobalFlag(const char *flag) { char global_flag[fs::EntryNameLengthMax + 1]; util::SNPrintf(global_flag, sizeof(global_flag) - 1, "/atmosphere/flags/%s.flag", flag); return DeleteFlagFile(global_flag); } } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_flags.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include "cfg_flags.board.nintendo_nx.inc" #else #include "cfg_flags.generic.inc" #endif ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_flags.generic.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { /* Flag utilities. */ bool HasFlag(const sm::MitmProcessInfo &process_info, const char *flag) { AMS_UNUSED(process_info, flag); return false; } bool HasContentSpecificFlag(ncm::ProgramId program_id, const char *flag) { AMS_UNUSED(program_id, flag); return false; } bool HasGlobalFlag(const char *flag) { AMS_UNUSED(flag); return false; } bool HasHblFlag(const char *flag) { AMS_UNUSED(flag); return false; } Result DeleteGlobalFlag(const char *flag) { AMS_UNUSED(flag); return false; } } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_override.board.nintendo_nx.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { namespace { /* Types. */ struct OverrideKey { u64 key_combination; bool override_by_default; }; struct ProgramOverrideKey { OverrideKey override_key; ncm::ProgramId program_id; }; constexpr ProgramOverrideKey InvalidProgramOverrideKey = {}; constexpr ProgramOverrideKey DefaultAppletPhotoViewerOverrideKey = { .override_key = { .key_combination = HidNpadButton_R, .override_by_default = true, }, .program_id = ncm::SystemAppletId::PhotoViewer, }; constexpr size_t MaxProgramOverrideKeys = 8; struct HblOverrideConfig { ProgramOverrideKey program_configs[MaxProgramOverrideKeys]; impl::OverrideStatusFlag program_as_flags[MaxProgramOverrideKeys]; OverrideKey override_any_app_key; impl::OverrideStatusFlag override_any_app_as_flag; bool override_any_app; }; struct ContentSpecificOverrideConfig { OverrideKey override_key; OverrideKey cheat_enable_key; OverrideLocale locale; }; /* Override globals. */ OverrideKey g_default_override_key = { .key_combination = HidNpadButton_L, .override_by_default = true, }; OverrideKey g_default_cheat_enable_key = { .key_combination = HidNpadButton_L, .override_by_default = true, }; HblOverrideConfig g_hbl_override_config = { .program_configs = { DefaultAppletPhotoViewerOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, InvalidProgramOverrideKey, }, .program_as_flags = { impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, impl::OverrideStatusFlag_AddressSpace64Bit, }, .override_any_app_key = { .key_combination = HidNpadButton_R, .override_by_default = false, }, .override_any_app_as_flag = impl::OverrideStatusFlag_AddressSpace64Bit, .override_any_app = true, }; char g_hbl_sd_path[0x100] = "/atmosphere/hbl.nsp"; /* Helpers. */ OverrideKey ParseOverrideKey(const char *value) { OverrideKey cfg = {}; /* Parse on by default. */ if (value[0] == '!') { cfg.override_by_default = true; value++; } /* Parse key combination. */ if (strcasecmp(value, "A") == 0) { cfg.key_combination = HidNpadButton_A; } else if (strcasecmp(value, "B") == 0) { cfg.key_combination = HidNpadButton_B; } else if (strcasecmp(value, "X") == 0) { cfg.key_combination = HidNpadButton_X; } else if (strcasecmp(value, "Y") == 0) { cfg.key_combination = HidNpadButton_Y; } else if (strcasecmp(value, "LS") == 0) { cfg.key_combination = HidNpadButton_StickL; } else if (strcasecmp(value, "RS") == 0) { cfg.key_combination = HidNpadButton_StickR; } else if (strcasecmp(value, "L") == 0) { cfg.key_combination = HidNpadButton_L; } else if (strcasecmp(value, "R") == 0) { cfg.key_combination = HidNpadButton_R; } else if (strcasecmp(value, "ZL") == 0) { cfg.key_combination = HidNpadButton_ZL; } else if (strcasecmp(value, "ZR") == 0) { cfg.key_combination = HidNpadButton_ZR; } else if (strcasecmp(value, "PLUS") == 0) { cfg.key_combination = HidNpadButton_Plus; } else if (strcasecmp(value, "MINUS") == 0) { cfg.key_combination = HidNpadButton_Minus; } else if (strcasecmp(value, "DLEFT") == 0) { cfg.key_combination = HidNpadButton_Left; } else if (strcasecmp(value, "DUP") == 0) { cfg.key_combination = HidNpadButton_Up; } else if (strcasecmp(value, "DRIGHT") == 0) { cfg.key_combination = HidNpadButton_Right; } else if (strcasecmp(value, "DDOWN") == 0) { cfg.key_combination = HidNpadButton_Down; } else if (strcasecmp(value, "SL") == 0) { cfg.key_combination = HidNpadButton_AnySL; } else if (strcasecmp(value, "SR") == 0) { cfg.key_combination = HidNpadButton_AnySR; } return cfg; } impl::OverrideStatusFlag ParseOverrideAddressSpace(const char *value) { if (strcasecmp(value, "39_bit") == 0 || strcasecmp(value, "39") == 0) { return impl::OverrideStatusFlag_AddressSpace64Bit; } else if (strcasecmp(value, "36_bit") == 0 || strcasecmp(value, "36") == 0) { return impl::OverrideStatusFlag_AddressSpace64BitDeprecated; } else if (strcasecmp(value, "32_bit") == 0 || strcasecmp(value, "32") == 0) { return impl::OverrideStatusFlag_AddressSpace32Bit; } else if (strcasecmp(value, "32_bit_without_alias") == 0 || strcasecmp(value, "32_bit_no_alias") == 0 || strcasecmp(value, "32_without_alias") == 0 || strcasecmp(value, "32_no_alias") || strcasecmp(value, "32_bit_without_map") == 0 || strcasecmp(value, "32_bit_no_map") == 0 || strcasecmp(value, "32_without_map") == 0 || strcasecmp(value, "32_no_map") == 0) { return impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias; } else { /* Default to 39-bit. */ return impl::OverrideStatusFlag_AddressSpace64Bit; } } inline void SetHblSpecificProgramId(size_t i, const char *value) { g_hbl_override_config.program_configs[i].program_id = {strtoul(value, nullptr, 16)}; } inline void SetHblSpecificOverrideKey(size_t i, const char *value) { g_hbl_override_config.program_configs[i].override_key = ParseOverrideKey(value); } inline void SetHblSpecificAddressSpace(size_t i, const char *value) { g_hbl_override_config.program_as_flags[i] = ParseOverrideAddressSpace(value); } int OverrideConfigIniHandler(void *user, const char *section, const char *name, const char *value) { AMS_UNUSED(user); /* Taken and modified, with love, from Rajkosto's implementation. */ if (strcasecmp(section, "hbl_config") == 0) { if (strcasecmp(name, "program_id") == 0 || strcasecmp(name, "program_id_0") == 0) { SetHblSpecificProgramId(0, value); } else if (strcasecmp(name, "program_id_1") == 0) { SetHblSpecificProgramId(1, value); } else if (strcasecmp(name, "program_id_2") == 0) { SetHblSpecificProgramId(2, value); } else if (strcasecmp(name, "program_id_3") == 0) { SetHblSpecificProgramId(3, value); } else if (strcasecmp(name, "program_id_4") == 0) { SetHblSpecificProgramId(4, value); } else if (strcasecmp(name, "program_id_5") == 0) { SetHblSpecificProgramId(5, value); } else if (strcasecmp(name, "program_id_6") == 0) { SetHblSpecificProgramId(6, value); } else if (strcasecmp(name, "program_id_7") == 0) { SetHblSpecificProgramId(7, value); } else if (strcasecmp(name, "override_key") == 0 || strcasecmp(name, "override_key_0") == 0) { SetHblSpecificOverrideKey(0, value); } else if (strcasecmp(name, "override_key_1") == 0) { SetHblSpecificOverrideKey(1, value); } else if (strcasecmp(name, "override_key_2") == 0) { SetHblSpecificOverrideKey(2, value); } else if (strcasecmp(name, "override_key_3") == 0) { SetHblSpecificOverrideKey(3, value); } else if (strcasecmp(name, "override_key_4") == 0) { SetHblSpecificOverrideKey(4, value); } else if (strcasecmp(name, "override_key_5") == 0) { SetHblSpecificOverrideKey(5, value); } else if (strcasecmp(name, "override_key_6") == 0) { SetHblSpecificOverrideKey(6, value); } else if (strcasecmp(name, "override_key_7") == 0) { SetHblSpecificOverrideKey(7, value); } else if (strcasecmp(name, "override_address_space") == 0 || strcasecmp(name, "override_address_space_0") == 0) { SetHblSpecificAddressSpace(0, value); } else if (strcasecmp(name, "override_address_space_1") == 0) { SetHblSpecificAddressSpace(1, value); } else if (strcasecmp(name, "override_address_space_2") == 0) { SetHblSpecificAddressSpace(2, value); } else if (strcasecmp(name, "override_address_space_3") == 0) { SetHblSpecificAddressSpace(3, value); } else if (strcasecmp(name, "override_address_space_4") == 0) { SetHblSpecificAddressSpace(4, value); } else if (strcasecmp(name, "override_address_space_5") == 0) { SetHblSpecificAddressSpace(5, value); } else if (strcasecmp(name, "override_address_space_6") == 0) { SetHblSpecificAddressSpace(6, value); } else if (strcasecmp(name, "override_address_space_7") == 0) { SetHblSpecificAddressSpace(7, value); } else if (strcasecmp(name, "override_any_app") == 0) { if (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0) { g_hbl_override_config.override_any_app = true; } else if (strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { g_hbl_override_config.override_any_app = false; } else { /* I guess we default to not changing the value? */ } } else if (strcasecmp(name, "override_any_app_key") == 0) { g_hbl_override_config.override_any_app_key = ParseOverrideKey(value); } else if (strcasecmp(name, "override_any_app_address_space") == 0) { g_hbl_override_config.override_any_app_as_flag = ParseOverrideAddressSpace(value); } else if (strcasecmp(name, "path") == 0) { while (*value == '/' || *value == '\\') { value++; } util::SNPrintf(g_hbl_sd_path, sizeof(g_hbl_sd_path) - 1, "/%s", value); g_hbl_sd_path[sizeof(g_hbl_sd_path) - 1] = '\0'; for (size_t i = 0; i < sizeof(g_hbl_sd_path); i++) { if (g_hbl_sd_path[i] == '\\') { g_hbl_sd_path[i] = '/'; } } } } else if (strcasecmp(section, "default_config") == 0) { if (strcasecmp(name, "override_key") == 0) { g_default_override_key = ParseOverrideKey(value); } else if (strcasecmp(name, "cheat_enable_key") == 0) { g_default_cheat_enable_key = ParseOverrideKey(value); } } else { return 0; } return 1; } int ContentSpecificIniHandler(void *user, const char *section, const char *name, const char *value) { ContentSpecificOverrideConfig *config = reinterpret_cast<ContentSpecificOverrideConfig *>(user); if (strcasecmp(section, "override_config") == 0) { if (strcasecmp(name, "override_key") == 0) { config->override_key = ParseOverrideKey(value); } else if (strcasecmp(name, "cheat_enable_key") == 0) { config->cheat_enable_key = ParseOverrideKey(value); } else if (strcasecmp(name, "override_language") == 0) { config->locale.language_code = settings::LanguageCode::Encode(value); } else if (strcasecmp(name, "override_region") == 0) { if (strcasecmp(value, "jpn") == 0) { config->locale.region_code = settings::RegionCode_Japan; } else if (strcasecmp(value, "usa") == 0) { config->locale.region_code = settings::RegionCode_America; } else if (strcasecmp(value, "eur") == 0) { config->locale.region_code = settings::RegionCode_Europe; } else if (strcasecmp(value, "aus") == 0) { config->locale.region_code = settings::RegionCode_Australia; } else if (strcasecmp(value, "chn") == 0) { config->locale.region_code = settings::RegionCode_China; } else if (strcasecmp(value, "kor") == 0) { config->locale.region_code = settings::RegionCode_Korea; } else if (strcasecmp(value, "twn") == 0) { config->locale.region_code = settings::RegionCode_Taiwan; } } } else { return 0; } return 1; } constexpr inline bool IsOverrideMatch(const OverrideStatus &status, const OverrideKey &cfg) { bool keys_triggered = ((status.keys_held & cfg.key_combination) != 0); return (cfg.override_by_default ^ keys_triggered); } inline bool IsAnySpecificHblProgramId(ncm::ProgramId program_id) { for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { if (program_id == g_hbl_override_config.program_configs[i].program_id) { return true; } } return false; } inline bool IsSpecificHblProgramId(size_t i, ncm::ProgramId program_id) { return program_id == g_hbl_override_config.program_configs[i].program_id; } inline bool IsAnyApplicationHblProgramId(ncm::ProgramId program_id) { return g_hbl_override_config.override_any_app && ncm::IsApplicationId(program_id) && !IsAnySpecificHblProgramId(program_id); } std::atomic<u32> g_ini_mount_count; void GetIniMountName(char *dst) { util::SNPrintf(dst, fs::MountNameLengthMax + 1, "#ini%08x", g_ini_mount_count.fetch_add(1)); } void ParseIniFile(util::ini::Handler handler, const char *path, void *user_ctx) { /* Mount the SD card. */ char mount_name[fs::MountNameLengthMax + 1]; GetIniMountName(mount_name); if (R_FAILED(fs::MountSdCard(mount_name))) { return; } ON_SCOPE_EXIT { fs::Unmount(mount_name); }; /* Open the file. */ fs::FileHandle file; { char full_path[fs::EntryNameLengthMax + 1]; util::SNPrintf(full_path, sizeof(full_path), "%s:/%s", mount_name, path[0] == '/' ? path + 1 : path); if (R_FAILED(fs::OpenFile(std::addressof(file), full_path, fs::OpenMode_Read))) { return; } } ON_SCOPE_EXIT { fs::CloseFile(file); }; /* Parse the config. */ util::ini::ParseFile(file, user_ctx, handler); } void RefreshOverrideConfiguration() { ParseIniFile(OverrideConfigIniHandler, "/atmosphere/config/override_config.ini", nullptr); } ContentSpecificOverrideConfig GetContentOverrideConfig(ncm::ProgramId program_id) { char path[fs::EntryNameLengthMax + 1]; util::SNPrintf(path, sizeof(path), "/atmosphere/contents/%016" PRIx64 "/config.ini", program_id.value); ContentSpecificOverrideConfig config = { .override_key = g_default_override_key, .cheat_enable_key = g_default_cheat_enable_key, }; std::memset(std::addressof(config.locale), 0xCC, sizeof(config.locale)); ParseIniFile(ContentSpecificIniHandler, path, std::addressof(config)); return config; } } OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id) { OverrideStatus status = {}; /* If the SD card isn't initialized, we can't override. */ if (!IsSdCardInitialized()) { return status; } /* For system modules and anything launched before the home menu, always override. */ if (program_id < ncm::SystemAppletId::Start || !pm::info::HasLaunchedBootProgram(ncm::SystemAppletId::Qlaunch)) { status.SetProgramSpecific(); return status; } /* Unconditionally refresh override_config.ini contents. */ RefreshOverrideConfiguration(); /* If we can't read the key state, don't override anything. */ if (R_FAILED(hid::GetKeysHeld(std::addressof(status.keys_held)))) { return status; } /* Detect Hbl. */ if (IsAnyApplicationHblProgramId(program_id) && IsOverrideMatch(status, g_hbl_override_config.override_any_app_key)) { status.SetHbl(); status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; status.flags |= g_hbl_override_config.override_any_app_as_flag; } for (size_t i = 0; i < MaxProgramOverrideKeys; i++) { if (IsSpecificHblProgramId(i, program_id) && IsOverrideMatch(status, g_hbl_override_config.program_configs[i].override_key)) { status.SetHbl(); status.flags &= ~impl::OverrideStatusFlag_AddressSpaceMask; status.flags |= g_hbl_override_config.program_as_flags[i]; } } /* Detect content specific keys. */ const auto content_cfg = GetContentOverrideConfig(program_id); if (IsOverrideMatch(status, content_cfg.override_key)) { status.SetProgramSpecific(); } /* Only allow cheat enable if not HBL. */ if (!status.IsHbl() && IsOverrideMatch(status, content_cfg.cheat_enable_key)) { status.SetCheatEnabled(); } return status; } OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { return GetContentOverrideConfig(program_id).locale; } /* HBL Configuration utilities. */ const char *GetHblPath() { return g_hbl_sd_path; } } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_override.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include "cfg_override.board.nintendo_nx.inc" #else #include "cfg_override.generic.inc" #endif ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_override.generic.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { OverrideStatus CaptureOverrideStatus(ncm::ProgramId program_id) { AMS_UNUSED(program_id); AMS_ABORT("TODO: How should this work?"); } OverrideLocale GetOverrideLocale(ncm::ProgramId program_id) { AMS_UNUSED(program_id); AMS_ABORT("TODO: How should this work?"); } /* HBL Configuration utilities. */ const char *GetHblPath() { AMS_ABORT("TODO: How should this work?"); } } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_sd_card.board.nintendo_nx.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { namespace { /* Convenience definitions. */ constexpr sm::ServiceName RequiredServicesForSdCardAccess[] = { sm::ServiceName::Encode("pcv"), sm::ServiceName::Encode("gpio"), sm::ServiceName::Encode("pinmux"), sm::ServiceName::Encode("psc:m"), }; constexpr size_t NumRequiredServicesForSdCardAccess = util::size(RequiredServicesForSdCardAccess); /* SD card globals. */ constinit os::SdkMutex g_sd_card_lock; constinit bool g_sd_card_initialized = false; constinit FsFileSystem g_sd_card_filesystem = {}; /* SD card helpers. */ Result CheckSdCardServicesReady() { for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { bool service_present = false; R_TRY(sm::HasService(std::addressof(service_present), RequiredServicesForSdCardAccess[i])); if (!service_present) { return fs::ResultSdCardNotPresent(); } } return ResultSuccess(); } void WaitSdCardServicesReadyImpl() { for (size_t i = 0; i < NumRequiredServicesForSdCardAccess; i++) { R_ABORT_UNLESS(sm::WaitService(RequiredServicesForSdCardAccess[i])); } } Result TryInitializeSdCard() { R_TRY(CheckSdCardServicesReady()); R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); g_sd_card_initialized = true; return ResultSuccess(); } void InitializeSdCard() { WaitSdCardServicesReadyImpl(); R_ABORT_UNLESS(fsOpenSdCardFileSystem(std::addressof(g_sd_card_filesystem))); g_sd_card_initialized = true; } } /* SD card utilities. */ bool IsSdCardRequiredServicesReady() { return R_SUCCEEDED(CheckSdCardServicesReady()); } void WaitSdCardRequiredServicesReady() { WaitSdCardServicesReadyImpl(); } bool IsSdCardInitialized() { std::scoped_lock lk(g_sd_card_lock); if (!g_sd_card_initialized) { if (R_SUCCEEDED(TryInitializeSdCard())) { g_sd_card_initialized = true; } } return g_sd_card_initialized; } void WaitSdCardInitialized() { std::scoped_lock lk(g_sd_card_lock); InitializeSdCard(); } } ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_sd_card.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #include "cfg_sd_card.board.nintendo_nx.inc" #else #include "cfg_sd_card.generic.inc" #endif ================================================ FILE: libraries/libstratosphere/source/cfg/cfg_sd_card.generic.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cfg { bool IsSdCardRequiredServicesReady() { return true; } void WaitSdCardRequiredServicesReady() { /* ... */ } bool IsSdCardInitialized() { return true; } void WaitSdCardInitialized() { /* ... */ } } ================================================ FILE: libraries/libstratosphere/source/crypto/crypto_csrng.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "../spl/impl/spl_ctr_drbg.hpp" #include <sys/random.h> namespace ams::crypto { namespace { using Drbg = ::ams::spl::impl::CtrDrbg<crypto::AesEncryptor128, crypto::AesEncryptor128::KeySize, false>; constinit util::TypedStorage<Drbg> g_drbg = {}; bool InitializeCsrng() { u8 seed[Drbg::SeedSize]; AMS_ABORT_UNLESS(::getentropy(seed, sizeof(seed)) == 0); util::ConstructAt(g_drbg); util::GetReference(g_drbg).Initialize(seed, sizeof(seed), nullptr, 0, nullptr, 0); return true; } } void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) { AMS_FUNCTION_LOCAL_STATIC(bool, s_initialized, InitializeCsrng()); AMS_ABORT_UNLESS(s_initialized); AMS_ASSERT(dst_size <= Drbg::RequestSizeMax); if (!util::GetReference(g_drbg).Generate(dst, dst_size, nullptr, 0)) { /* Reseed, if needed. */ { u8 seed[Drbg::SeedSize]; AMS_ABORT_UNLESS(::getentropy(seed, sizeof(seed)) == 0); util::GetReference(g_drbg).Reseed(seed, sizeof(seed), nullptr, 0); } util::GetReference(g_drbg).Generate(dst, dst_size, nullptr, 0); } } } ================================================ FILE: libraries/libstratosphere/source/crypto/crypto_csrng.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::crypto { namespace { constinit bool g_initialized = false; constinit os::SdkMutex g_lock; void InitializeCsrng() { AMS_ASSERT(!g_initialized); R_ABORT_UNLESS(sm::Initialize()); R_ABORT_UNLESS(::csrngInitialize()); } } void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) { if (AMS_UNLIKELY(!g_initialized)) { std::scoped_lock lk(g_lock); if (AMS_LIKELY(!g_initialized)) { InitializeCsrng(); g_initialized = true; } } R_ABORT_UNLESS(::csrngGetRandomBytes(dst, dst_size)); } } ================================================ FILE: libraries/libstratosphere/source/crypto/crypto_csrng.os.windows.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/windows.hpp> #include <ntstatus.h> #include <bcrypt.h> namespace ams::crypto { void GenerateCryptographicallyRandomBytes(void *dst, size_t dst_size) { const auto status = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(dst), dst_size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); AMS_ABORT_UNLESS(status == STATUS_SUCCESS); } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_audio_server.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cs { void InitializeAudioServer() { /* TODO: Support audio server. */ } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_command_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::cs { struct CommandDataTakeScreenShot { vi::LayerStack layer_stack; u8 *buffer; size_t buffer_size; }; Result DoGetFirmwareVersionCommand(settings::system::FirmwareVersion *out); template<typename SendHeader, typename SendData> Result DoTakeScreenShotCommand(const CommandDataTakeScreenShot ¶ms, SendHeader send_header, SendData send_data); } ================================================ FILE: libraries/libstratosphere/source/cs/cs_command_impl.inc ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ namespace ams::cs { namespace { template<typename SendData> void SendEmptyData(const CommandDataTakeScreenShot ¶ms, size_t remaining_size, SendData send_data) { /* Clear the data buffer. */ std::memset(params.buffer, 0, params.buffer_size); /* Send data until the end. */ while (remaining_size > 0) { /* Send as much as we can. */ const auto cur_size = std::min(remaining_size, params.buffer_size); send_data(params.buffer, cur_size); /* Advance. */ remaining_size -= cur_size; } } } Result DoGetFirmwareVersionCommand(settings::system::FirmwareVersion *out) { settings::system::GetFirmwareVersion(out); return ResultSuccess(); } template<typename SendHeader, typename SendData> Result DoTakeScreenShotCommand(const CommandDataTakeScreenShot ¶ms, SendHeader send_header, SendData send_data) { /* Initialize screenshot control. */ R_TRY(capsrv::InitializeScreenShotControl()); /* Finalize screenshot control when we're done. */ ON_SCOPE_EXIT { capsrv::FinalizeScreenShotControl(); }; /* Open screenshot read stream. */ size_t data_size; s32 width, height; R_TRY(capsrv::OpenRawScreenShotReadStreamForDevelop(std::addressof(data_size), std::addressof(width), std::addressof(height), params.layer_stack, TimeSpan::FromSeconds(10))); /* Close the screenshot stream when we're done. */ ON_SCOPE_EXIT { capsrv::CloseRawScreenShotReadStreamForDevelop(); }; /* Send the header. */ send_header(static_cast<s32>(data_size), width, height); /* Read and send data. */ size_t total_read_size = 0; auto data_guard = SCOPE_GUARD { SendEmptyData(params, data_size - total_read_size, send_data); }; while (total_read_size < data_size) { /* Read data from the stream. */ size_t read_size; R_TRY(capsrv::ReadRawScreenShotReadStreamForDevelop(std::addressof(read_size), params.buffer, params.buffer_size, total_read_size)); /* Send the data that was read. */ send_data(params.buffer, read_size); /* Advance. */ total_read_size += read_size; } data_guard.Cancel(); return ResultSuccess(); } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_command_processor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "cs_command_impl.hpp" /* Include command implementations. */ #include "cs_command_impl.inc" namespace ams::cs { namespace { struct ResponseFirmwareVersion { ResponseHeader header; settings::system::FirmwareVersion firmware_version; }; struct ResponseTakeScreenShot { ResponseHeader header; s32 data_size; s32 width; s32 height; }; constinit u8 g_data[0x1000]; } bool CommandProcessor::ProcessCommand(const CommandHeader &header, const u8 *body, s32 socket) { switch (header.command) { case Command_GetFirmwareVersion: SendFirmwareVersion(socket, header); break; case Command_TakeScreenShot: this->TakeScreenShot(header, socket, vi::LayerStack_ApplicationForDebug); break; case Command_TakeForegroundScreenShot: this->TakeScreenShot(header, socket, vi::LayerStack_LastFrame); break; /* TODO: Command support. */ default: scs::CommandProcessor::ProcessCommand(header, body, socket); break; } return true; } void CommandProcessor::SendFirmwareVersion(s32 socket, const CommandHeader &header) { /* Build the response. */ ResponseFirmwareVersion response = { .header = { .id = header.id, .response = Response_FirmwareVersion, .body_size = sizeof(response) - sizeof(response.header), }, .firmware_version = {}, }; /* Get the firmware version. */ const Result result = DoGetFirmwareVersionCommand(std::addressof(response.firmware_version)); if (R_SUCCEEDED(result)) { /* Send the response. */ auto lk = MakeSendGuardBlock(); Send(socket, std::addressof(response), sizeof(response)); } else { SendErrorResult(socket, header, result); } } void CommandProcessor::TakeScreenShot(const CommandHeader &header, s32 socket, vi::LayerStack layer_stack) { /* Create the command data. */ const CommandDataTakeScreenShot params = { .layer_stack = layer_stack, .buffer = g_data, .buffer_size = sizeof(g_data), }; /* Take the screenshot. */ Result result; { /* Acquire the send lock. */ auto lk = MakeSendGuardBlock(); /* Perform the command. */ result = DoTakeScreenShotCommand(params, [&](s32 data_size, s32 width, s32 height) { /* Use global buffer for response. */ ResponseTakeScreenShot *response = reinterpret_cast<ResponseTakeScreenShot *>(g_data); /* Set response header. */ *response = { .header = { .id = header.id, .response = Response_ScreenShot, .body_size = static_cast<u32>(sizeof(data_size) + sizeof(width) + sizeof(height) + data_size), }, .data_size = data_size, .width = width, .height = height, }; /* Send data. */ Send(socket, response, sizeof(*response)); }, [&](u8 *data, size_t data_size) { /* Send data. */ Send(socket, data, data_size); }); } /* Handle the error case. */ if (R_FAILED(result)) { SendErrorResult(socket, header, result); } } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_hid_server.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cs { void InitializeHidServer() { /* TODO: Support hid redirection server. */ } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_remote_video_server.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cs { void InitializeRemoteVideoServer() { /* TODO: Support remote video server. */ } } ================================================ FILE: libraries/libstratosphere/source/cs/cs_target_io_server.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::cs { void InitializeTargetIoServer() { /* Launch target io server. */ os::ProcessId process_id; static_cast<void>(scs::LaunchProgram(std::addressof(process_id), ncm::ProgramLocation::Make(ncm::SystemProgramId::DevServer, ncm::StorageId::None), nullptr, 0, 0)); } } ================================================ FILE: libraries/libstratosphere/source/dd/dd_device_address_space.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/dd_device_address_space_impl.hpp" namespace ams::dd { Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 address, u64 size) { /* Check pre-conditions. */ AMS_ASSERT(util::IsAligned(address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); AMS_ASSERT(size > 0); /* Ensure we leave in a consistent state. */ auto state_guard = SCOPE_GUARD { das->state = DeviceAddressSpaceType::State_NotInitialized; }; /* Create the address space. */ DeviceAddressSpaceHandle handle; R_TRY(impl::DeviceAddressSpaceImpl::Create(std::addressof(handle), address, size)); /* Set the values in the das. */ das->device_handle = handle; das->is_handle_managed = true; das->state = DeviceAddressSpaceType::State_Initialized; /* We succeeded. */ state_guard.Cancel(); R_SUCCEED(); } Result CreateDeviceAddressSpace(DeviceAddressSpaceType *das, u64 size) { R_RETURN(CreateDeviceAddressSpace(das, 0, size)); } void DestroyDeviceAddressSpace(DeviceAddressSpaceType *das) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); /* Destroy the handle. */ if (das->is_handle_managed) { impl::DeviceAddressSpaceImpl::Close(das->device_handle); } das->device_handle = 0; das->is_handle_managed = false; das->state = DeviceAddressSpaceType::State_NotInitialized; } void AttachDeviceAddressSpaceHandle(DeviceAddressSpaceType *das, DeviceAddressSpaceHandle handle, bool managed) { /* Check pre-conditions. */ AMS_ASSERT(handle != os::InvalidNativeHandle); das->device_handle = handle; das->is_handle_managed = managed; das->state = DeviceAddressSpaceType::State_Initialized; } DeviceAddressSpaceHandle GetDeviceAddressSpaceHandle(DeviceAddressSpaceType *das) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); return das->device_handle; } Result MapDeviceAddressSpaceAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); AMS_ASSERT(process_address + size > process_address); AMS_ASSERT(device_address + size > device_address); AMS_ASSERT(size > 0); AMS_ASSERT((process_address & (4_MB - 1)) == (device_address & (4_MB - 1))); R_RETURN(impl::DeviceAddressSpaceImpl::MapAligned(das->device_handle, process_handle, process_address, size, device_address, device_perm)); } Result MapDeviceAddressSpaceNotAligned(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address, MemoryPermission device_perm) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); AMS_ASSERT(process_address + size > process_address); AMS_ASSERT(device_address + size > device_address); AMS_ASSERT(size > 0); R_RETURN(impl::DeviceAddressSpaceImpl::MapNotAligned(das->device_handle, process_handle, process_address, size, device_address, device_perm)); } void UnmapDeviceAddressSpace(DeviceAddressSpaceType *das, ProcessHandle process_handle, u64 process_address, size_t size, DeviceVirtualAddress device_address) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); AMS_ASSERT(util::IsAligned(process_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(device_address, os::MemoryPageSize)); AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize)); AMS_ASSERT(process_address + size > process_address); AMS_ASSERT(device_address + size > device_address); AMS_ASSERT(size > 0); return impl::DeviceAddressSpaceImpl::Unmap(das->device_handle, process_handle, process_address, size, device_address); } Result AttachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); R_RETURN(impl::DeviceAddressSpaceImpl::Attach(das, device_name)); } void DetachDeviceAddressSpace(DeviceAddressSpaceType *das, DeviceName device_name) { /* Check pre-conditions. */ AMS_ASSERT(das->state == DeviceAddressSpaceType::State_Initialized); return impl::DeviceAddressSpaceImpl::Detach(das, device_name); } } ================================================ FILE: libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.generic.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::dd::impl { class DeviceAddressSpaceImplByWindows { public: static Result Create(DeviceAddressSpaceHandle *, u64, u64) { R_THROW(dd::ResultNotSupported()); } static void Close(DeviceAddressSpaceHandle) { /* ... */ } static Result MapAligned(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress, dd::MemoryPermission) { R_THROW(dd::ResultNotSupported()); } static Result MapNotAligned(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress, dd::MemoryPermission) { R_THROW(dd::ResultNotSupported()); } static void Unmap(DeviceAddressSpaceHandle, ProcessHandle, u64, size_t, DeviceVirtualAddress) { /* ... */ } static Result Attach(DeviceAddressSpaceType *, DeviceName) { R_THROW(dd::ResultNotSupported()); } static void Detach(DeviceAddressSpaceType *, DeviceName) { /* ... */ } }; using DeviceAddressSpaceImpl = DeviceAddressSpaceImplByWindows; } ================================================ FILE: libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #if defined(ATMOSPHERE_OS_HORIZON) #include "dd_device_address_space_impl.os.horizon.hpp" #else #include "dd_device_address_space_impl.generic.hpp" #endif ================================================ FILE: libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "dd_device_address_space_impl.os.horizon.hpp" namespace ams::dd::impl { static_assert(static_cast<int>(dd::MemoryPermission_None) == static_cast<int>(svc::MemoryPermission_None)); static_assert(static_cast<int>(dd::MemoryPermission_ReadOnly) == static_cast<int>(svc::MemoryPermission_Read)); static_assert(static_cast<int>(dd::MemoryPermission_WriteOnly) == static_cast<int>(svc::MemoryPermission_Write)); static_assert(static_cast<int>(dd::MemoryPermission_ReadWrite) == static_cast<int>(svc::MemoryPermission_ReadWrite)); Result DeviceAddressSpaceImplByHorizon::Create(DeviceAddressSpaceHandle *out, u64 address, u64 size) { /* Create the space. */ svc::Handle handle; R_TRY_CATCH(svc::CreateDeviceAddressSpace(std::addressof(handle), address, size)) { R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) } R_END_TRY_CATCH_WITH_ABORT_UNLESS; *out = static_cast<DeviceAddressSpaceHandle>(handle); R_SUCCEED(); } void DeviceAddressSpaceImplByHorizon::Close(DeviceAddressSpaceHandle handle) { const auto svc_handle = svc::Handle(handle); if (svc_handle == svc::PseudoHandle::CurrentThread || svc_handle == svc::PseudoHandle::CurrentProcess) { return; } R_ABORT_UNLESS(svc::CloseHandle(svc_handle)); } Result DeviceAddressSpaceImplByHorizon::MapAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm) { /* Check alignment. */ AMS_ABORT_UNLESS((process_address & (4_MB - 1)) == (device_address & (4_MB - 1))); R_TRY_CATCH(svc::MapDeviceAddressSpaceAligned(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, svc::MapDeviceAddressSpaceOption::Encode(static_cast<svc::MemoryPermission>(device_perm), svc::MapDeviceAddressSpaceFlag_None))) { R_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) R_CONVERT(svc::ResultInvalidCurrentMemory, dd::ResultInvalidMemoryState()) } R_END_TRY_CATCH_WITH_ABORT_UNLESS; R_SUCCEED(); } Result DeviceAddressSpaceImplByHorizon::MapNotAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm) { R_TRY_CATCH(svc::MapDeviceAddressSpaceByForce(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address, svc::MapDeviceAddressSpaceOption::Encode(static_cast<svc::MemoryPermission>(device_perm), svc::MapDeviceAddressSpaceFlag_None))) { R_CONVERT(svc::ResultInvalidHandle, dd::ResultInvalidHandle()) R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) R_CONVERT(svc::ResultOutOfResource, dd::ResultOutOfResource()) R_CONVERT(svc::ResultInvalidCurrentMemory, dd::ResultInvalidMemoryState()) } R_END_TRY_CATCH_WITH_ABORT_UNLESS; R_SUCCEED(); } void DeviceAddressSpaceImplByHorizon::Unmap(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address) { R_ABORT_UNLESS(svc::UnmapDeviceAddressSpace(svc::Handle(handle), svc::Handle(process_handle), process_address, process_size, device_address)); } Result DeviceAddressSpaceImplByHorizon::Attach(DeviceAddressSpaceType *das, DeviceName device_name) { R_TRY_CATCH(svc::AttachDeviceAddressSpace(static_cast<svc::DeviceName>(device_name), svc::Handle(das->device_handle))) { R_CONVERT(svc::ResultOutOfMemory, dd::ResultOutOfMemory()) } R_END_TRY_CATCH_WITH_ABORT_UNLESS; R_SUCCEED(); } void DeviceAddressSpaceImplByHorizon::Detach(DeviceAddressSpaceType *das, DeviceName device_name) { R_ABORT_UNLESS(svc::DetachDeviceAddressSpace(static_cast<svc::DeviceName>(device_name), svc::Handle(das->device_handle))); } } ================================================ FILE: libraries/libstratosphere/source/dd/impl/dd_device_address_space_impl.os.horizon.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::dd::impl { class DeviceAddressSpaceImplByHorizon { public: static Result Create(DeviceAddressSpaceHandle *out, u64 address, u64 size); static void Close(DeviceAddressSpaceHandle handle); static Result MapAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm); static Result MapNotAligned(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address, dd::MemoryPermission device_perm); static void Unmap(DeviceAddressSpaceHandle handle, ProcessHandle process_handle, u64 process_address, size_t process_size, DeviceVirtualAddress device_address); static Result Attach(DeviceAddressSpaceType *das, DeviceName device_name); static void Detach(DeviceAddressSpaceType *das, DeviceName device_name); }; using DeviceAddressSpaceImpl = DeviceAddressSpaceImplByHorizon; } ================================================ FILE: libraries/libstratosphere/source/ddsf/ddsf_device_code_entry_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::ddsf { Result DeviceCodeEntryManager::Add(DeviceCode device_code, IDevice *device) { /* Check pre-conditions. */ AMS_ASSERT(device != nullptr); AMS_ASSERT(device->IsDriverAttached()); /* Acquire exclusive access to the manager. */ std::scoped_lock lk(m_entry_list_lock); /* Check that we don't already have an entry with the code. */ for (const auto &holder : m_entry_list) { AMS_ASSERT(holder.IsConstructed()); AMS_ASSERT(holder.Get().GetDeviceCode() != device_code); AMS_UNUSED(holder); } /* Allocate memory for a new device code entry holder. */ void *holder_storage = m_memory_resource->Allocate(sizeof(DeviceCodeEntryHolder)); R_UNLESS(holder_storage != nullptr, ddsf::ResultOutOfResource()); /* Initialize the new holder. */ auto *holder = std::construct_at(static_cast<DeviceCodeEntryHolder *>(holder_storage)); holder->Construct(device_code, device); /* Link the new holder. */ holder->AddTo(m_entry_list); R_SUCCEED(); } bool DeviceCodeEntryManager::Remove(DeviceCode device_code) { /* Acquire exclusive access to the manager. */ std::scoped_lock lk(m_entry_list_lock); /* Find and erase the entry. */ bool erased = false; for (auto it = m_entry_list.begin(); it != m_entry_list.end(); /* ... */) { /* Get the current entry, and advance the iterator. */ DeviceCodeEntryHolder *cur = std::addressof(*(it++)); /* If the entry matches the device code, remove it. */ AMS_ASSERT(cur->IsConstructed()); if (cur->Get().GetDeviceCode() == device_code) { /* Destroy and deallocate the holder. */ cur->Destroy(); std::destroy_at(cur); m_memory_resource->Deallocate(cur, sizeof(*cur)); erased = true; } } return erased; } Result DeviceCodeEntryManager::FindDeviceCodeEntry(DeviceCodeEntry **out, DeviceCode device_code) { /* Check arguments. */ AMS_ASSERT(out != nullptr); R_UNLESS(out != nullptr, ddsf::ResultInvalidArgument()); /* Find the device. */ bool found = false; this->ForEachEntry([&](DeviceCodeEntry &entry) -> bool { if (entry.GetDeviceCode() == device_code) { found = true; *out = std::addressof(entry); return false; } return true; }); /* Check that we found the device. */ R_UNLESS(found, ddsf::ResultDeviceCodeNotFound()); R_SUCCEED(); } Result DeviceCodeEntryManager::FindDeviceCodeEntry(const DeviceCodeEntry **out, DeviceCode device_code) const { /* Check arguments. */ AMS_ASSERT(out != nullptr); R_UNLESS(out != nullptr, ddsf::ResultInvalidArgument()); /* Find the device. */ bool found = false; this->ForEachEntry([&](const DeviceCodeEntry &entry) -> bool { if (entry.GetDeviceCode() == device_code) { found = true; *out = std::addressof(entry); return false; } return true; }); /* Check that we found the device. */ R_UNLESS(found, ddsf::ResultDeviceCodeNotFound()); R_SUCCEED(); } Result DeviceCodeEntryManager::FindDevice(IDevice **out, DeviceCode device_code) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); /* Find the entry. */ DeviceCodeEntry *entry; R_TRY(this->FindDeviceCodeEntry(std::addressof(entry), device_code)); /* Set the output. */ if (out != nullptr) { *out = std::addressof(entry->GetDevice()); } R_SUCCEED(); } Result DeviceCodeEntryManager::FindDevice(const IDevice **out, DeviceCode device_code) const { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); /* Find the entry. */ const DeviceCodeEntry *entry; R_TRY(this->FindDeviceCodeEntry(std::addressof(entry), device_code)); /* Set the output. */ if (out != nullptr) { *out = std::addressof(entry->GetDevice()); } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::ddsf { namespace { enum class LoopControlCommand { None = 0, Register = 1, Unregister = 2, Terminate = 3, }; } struct EventHandlerManager::LoopControlCommandParameters { LoopControlCommand command; IEventHandler *target; LoopControlCommandParameters() : command(LoopControlCommand::None), target(nullptr) { /* ... */ } LoopControlCommandParameters(LoopControlCommand c, IEventHandler *t) : command(c), target(t) { /* ... */ } }; void EventHandlerManager::Initialize() { /* Check that we're not already initialized. */ if (m_is_initialized) { return; } /* Initialize multi wait/holder. */ os::InitializeMultiWait(std::addressof(m_multi_wait)); os::InitializeMultiWaitHolder(std::addressof(m_loop_control_event_holder), m_loop_control_event.GetBase()); os::LinkMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_loop_control_event_holder)); m_is_initialized = true; } void EventHandlerManager::Finalize() { /* Check that we're initialized and not looping. */ AMS_ASSERT(!m_is_looping); AMS_ASSERT(m_is_initialized); if (!m_is_initialized) { return; } /* Finalize multi wait/holder. */ os::UnlinkMultiWaitHolder(std::addressof(m_loop_control_event_holder)); os::FinalizeMultiWaitHolder(std::addressof(m_loop_control_event_holder)); os::FinalizeMultiWait(std::addressof(m_multi_wait)); m_is_initialized = false; } void EventHandlerManager::ProcessControlCommand(LoopControlCommandParameters *params) { /* Check pre-conditions. */ AMS_ASSERT(m_is_initialized); AMS_ASSERT(params != nullptr); /* Acquire exclusive access. */ std::scoped_lock lk(m_loop_control_lock); /* If we're processing for the loop thread, we can directly handle. */ if (!m_is_looping || this->IsRunningOnLoopThread()) { this->ProcessControlCommandImpl(params); } else { /* Otherwise, signal to the loop thread. */ m_loop_control_command_params = params; m_loop_control_event.Signal(); m_loop_control_command_done_event.Wait(); } } void EventHandlerManager::ProcessControlCommandImpl(LoopControlCommandParameters *params) { /* Check pre-conditions. */ AMS_ASSERT(m_loop_control_lock.IsLockedByCurrentThread() || !m_loop_control_lock.TryLock()); AMS_ASSERT(params != nullptr); AMS_ASSERT(params->target != nullptr); /* Process the command. */ switch (params->command) { case LoopControlCommand::Register: params->target->Link(std::addressof(m_multi_wait)); break; case LoopControlCommand::Unregister: params->target->Unlink(); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } void EventHandlerManager::RegisterHandler(IEventHandler *handler) { /* Check that the handler is valid. */ AMS_ASSERT(handler != nullptr); AMS_ASSERT(handler->IsInitialized()); /* Send registration command. */ LoopControlCommandParameters params(LoopControlCommand::Register, handler); return this->ProcessControlCommand(std::addressof(params)); } void EventHandlerManager::UnregisterHandler(IEventHandler *handler) { /* Check that the handler is valid. */ AMS_ASSERT(handler != nullptr); AMS_ASSERT(handler->IsInitialized()); /* Send registration command. */ LoopControlCommandParameters params(LoopControlCommand::Unregister, handler); return this->ProcessControlCommand(std::addressof(params)); } void EventHandlerManager::WaitLoopEnter() { /* Acquire exclusive access. */ std::scoped_lock lk(m_loop_control_lock); /* Wait until we're looping. */ while (!m_is_looping) { m_is_looping_cv.Wait(m_loop_control_lock); } } void EventHandlerManager::WaitLoopExit() { /* Acquire exclusive access. */ std::scoped_lock lk(m_loop_control_lock); /* Wait until we're not looping. */ while (m_is_looping) { m_is_looping_cv.Wait(m_loop_control_lock); } } void EventHandlerManager::RequestStop() { /* Check that we're looping and not the loop thread. */ AMS_ASSERT(m_is_looping); AMS_ASSERT(!this->IsRunningOnLoopThread()); if (m_is_looping) { /* Acquire exclusive access. */ std::scoped_lock lk(m_loop_control_lock); /* Signal to the loop thread. */ LoopControlCommandParameters params(LoopControlCommand::Terminate, nullptr); m_loop_control_command_params = std::addressof(params); m_loop_control_event.Signal(); m_loop_control_command_done_event.Wait(); } } void EventHandlerManager::LoopAuto() { /* Check that we're not already looping. */ AMS_ASSERT(!m_is_looping); /* Begin looping with the current thread. */ m_loop_thread = os::GetCurrentThread(); m_is_looping = true; m_is_looping_cv.Broadcast(); /* Whenever we're done looping, clean up. */ ON_SCOPE_EXIT { m_loop_thread = nullptr; m_is_looping = false; m_is_looping_cv.Broadcast(); }; /* Loop until we're asked to stop. */ bool should_terminate = false; while (!should_terminate) { /* Wait for a holder to be signaled. */ os::MultiWaitHolderType *event_holder = os::WaitAny(std::addressof(m_multi_wait)); AMS_ASSERT(event_holder != nullptr); /* Check if we have a request to handle. */ if (event_holder == std::addressof(m_loop_control_event_holder)) { /* Check that the request hasn't already been handled. */ if (m_loop_control_event.TryWait()) { /* Handle the request. */ AMS_ASSERT(m_loop_control_command_params != nullptr); switch (m_loop_control_command_params->command) { case LoopControlCommand::Register: case LoopControlCommand::Unregister: this->ProcessControlCommandImpl(m_loop_control_command_params); break; case LoopControlCommand::Terminate: should_terminate = true; break; AMS_UNREACHABLE_DEFAULT_CASE(); } /* Clear the request, and signal that it's done. */ m_loop_control_command_params = nullptr; m_loop_control_command_done_event.Signal(); } } else { /* Handle the event. */ IEventHandler::ToEventHandler(event_holder).HandleEvent(); } } } } ================================================ FILE: libraries/libstratosphere/source/ddsf/ddsf_memory_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::ddsf { namespace { constinit ams::MemoryResource *g_memory_resource = nullptr; constinit ams::MemoryResource *g_device_code_entry_holder_memory_resource = nullptr; } void SetMemoryResource(ams::MemoryResource *mr) { AMS_ASSERT(g_memory_resource == nullptr); g_memory_resource = mr; AMS_ASSERT(g_memory_resource != nullptr); } ams::MemoryResource *GetMemoryResource() { AMS_ASSERT(g_memory_resource != nullptr); return g_memory_resource; } void SetDeviceCodeEntryHolderMemoryResource(ams::MemoryResource *mr) { AMS_ASSERT(g_device_code_entry_holder_memory_resource == nullptr); g_device_code_entry_holder_memory_resource = mr; AMS_ASSERT(g_device_code_entry_holder_memory_resource != nullptr); } ams::MemoryResource *GetDeviceCodeEntryHolderMemoryResource() { AMS_ASSERT(g_device_code_entry_holder_memory_resource != nullptr); return g_device_code_entry_holder_memory_resource; } } ================================================ FILE: libraries/libstratosphere/source/ddsf/ddsf_session_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::ddsf { Result OpenSession(IDevice *device, ISession *session, AccessMode access_mode) { /* Check pre-conditions. */ AMS_ASSERT(device != nullptr); AMS_ASSERT(session != nullptr); AMS_ASSERT(!session->IsOpen()); /* Attack the session to the device. */ session->AttachDevice(device, access_mode); auto session_guard = SCOPE_GUARD { session->DetachDevice(); }; /* Attach the device to the session. */ R_TRY(device->AttachSession(session)); /* We succeeded. */ session_guard.Cancel(); R_SUCCEED(); } void CloseSession(ISession *session) { /* Check pre-conditions. */ AMS_ASSERT(session != nullptr); /* Detach the device from the session. */ session->GetDevice().DetachSession(session); /* Detach the session from the device. */ session->DetachDevice(); } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_abort_observer.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/diag_abort_observer_manager.hpp" namespace ams::diag { namespace impl { constinit bool g_enable_default_abort_observer = true; } namespace { template<typename Holder, typename Observer> void InitializeAbortObserverHolderImpl(Holder *holder, Observer observer) { holder->observer = observer; holder->next = nullptr; holder->is_registered = false; } } void InitializeAbortObserverHolder(AbortObserverHolder *holder, AbortObserver observer) { InitializeAbortObserverHolderImpl(holder, observer); } void RegisterAbortObserver(AbortObserverHolder *holder) { impl::GetAbortObserverManager()->RegisterObserver(holder); } void UnregisterAbortObserver(AbortObserverHolder *holder) { impl::GetAbortObserverManager()->UnregisterObserver(holder); } void EnableDefaultAbortObserver(bool en) { ::ams::diag::impl::g_enable_default_abort_observer = en; } void InitializeSdkAbortObserverHolder(SdkAbortObserverHolder *holder, SdkAbortObserver observer) { InitializeAbortObserverHolderImpl(holder, observer); } void RegisterSdkAbortObserver(SdkAbortObserverHolder *holder) { impl::GetSdkAbortObserverManager()->RegisterObserver(holder); } void UnregisterSdkAbortObserver(SdkAbortObserverHolder *holder) { impl::GetSdkAbortObserverManager()->UnregisterObserver(holder); } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_assertion_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/diag_get_all_backtrace.hpp" #include "impl/diag_invoke_abort.hpp" namespace ams::diag { namespace { inline NORETURN void AbortWithValue(u64 debug) { #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) /* Just perform a data abort. */ register u64 addr __asm__("x27") = FatalErrorContext::StdAbortMagicAddress; register u64 val __asm__("x28") = FatalErrorContext::StdAbortMagicValue; while (true) { __asm__ __volatile__ ( "mov x0, %[debug]\n" "str %[val], [%[addr]]\n" : : [debug]"r"(debug), [val]"r"(val), [addr]"r"(addr) : "x0" ); } #else AMS_UNUSED(debug); std::abort(); #endif __builtin_unreachable(); } constinit os::SdkMutex g_assert_mutex; constinit os::SdkMutex g_abort_mutex; void PrepareAbort() { #if defined(ATMOSPHERE_OS_HORIZON) { /* Get the thread local region. */ auto * const tlr = svc::GetThreadLocalRegion(); /* Clear disable count. */ tlr->disable_count = 0; /* If we need to, unpin. */ if (tlr->interrupt_flag) { svc::SynchronizePreemptionState(); } } #endif } AbortReason ToAbortReason(AssertionType type) { switch (type) { case AssertionType_Audit: return AbortReason_Audit; case AssertionType_Assert: return AbortReason_Assert; default: return AbortReason_Abort; } } AssertionFailureOperation DefaultAssertionFailureHandler(const AssertionInfo &) { return AssertionFailureOperation_Abort; } constinit AssertionFailureHandler g_assertion_failure_handler = &DefaultAssertionFailureHandler; void ExecuteAssertionFailureOperation(AssertionFailureOperation operation, const AssertionInfo &info) { switch (operation) { case AssertionFailureOperation_Continue: break; case AssertionFailureOperation_Abort: { const AbortInfo abort_info = { ToAbortReason(info.type), info.message, info.expr, info.func, info.file, info.line, }; ::ams::diag::impl::InvokeAbortObserver(abort_info); AbortWithValue(0); } break; AMS_UNREACHABLE_DEFAULT_CASE(); } } void InvokeAssertionFailureHandler(const AssertionInfo &info) { const auto operation = g_assertion_failure_handler(info); ExecuteAssertionFailureOperation(operation, info); } } NOINLINE void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { /* Prepare to abort. */ PrepareAbort(); /* Acquire exclusive assert rights. */ if (g_assert_mutex.IsLockedByCurrentThread()) { AbortWithValue(0); } std::scoped_lock lk(g_assert_mutex); /* Create the assertion info. */ std::va_list vl; va_start(vl, format); const ::ams::diag::LogMessage message = { format, std::addressof(vl) }; const AssertionInfo info = { type, std::addressof(message), expr, func, file, line, }; InvokeAssertionFailureHandler(info); va_end(vl); } void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { return OnAssertionFailure(type, expr, func, file, line, ""); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { const Result res = ResultSuccess(); std::va_list vl{}; VAbortImpl(expr, func, file, line, std::addressof(res), nullptr, "", vl); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *fmt, ...) { const Result res = ResultSuccess(); std::va_list vl; va_start(vl, fmt); VAbortImpl(expr, func, file, line, std::addressof(res), nullptr, fmt, vl); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); VAbortImpl(expr, func, file, line, result, nullptr, fmt, vl); } NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exc_info, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); VAbortImpl(expr, func, file, line, result, exc_info, fmt, vl); } NORETURN NOINLINE void VAbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exc_info, const char *fmt, std::va_list vl) { /* Prepare to abort. */ PrepareAbort(); /* Acquire exclusive abort rights. */ if (g_abort_mutex.IsLockedByCurrentThread()) { AbortWithValue(result->GetValue()); } std::scoped_lock lk(g_abort_mutex); /* Set the abort impl return address. */ impl::SetAbortImplReturnAddress(reinterpret_cast<uintptr_t>(__builtin_return_address(0))); /* Create abort info. */ std::va_list cvl; va_copy(cvl, vl); const diag::LogMessage message = { fmt, std::addressof(cvl) }; const AbortInfo abort_info = { AbortReason_Abort, std::addressof(message), expr, func, file, line, }; const SdkAbortInfo sdk_abort_info = { abort_info, *result, exc_info }; /* Invoke observers. */ ::ams::diag::impl::InvokeAbortObserver(abort_info); ::ams::diag::impl::InvokeSdkAbortObserver(sdk_abort_info); /* Abort. */ AbortWithValue(result->GetValue()); } } namespace ams::impl { NORETURN NOINLINE void UnexpectedDefaultImpl(const char *func, const char *file, int line) { /* Create abort info. */ std::va_list vl{}; const ::ams::diag::LogMessage message = { "" , std::addressof(vl) }; const ::ams::diag::AbortInfo abort_info = { ::ams::diag::AbortReason_UnexpectedDefault, std::addressof(message), "", func, file, line, }; /* Invoke observers. */ ::ams::diag::impl::InvokeAbortObserver(abort_info); /* Abort. */ ::ams::diag::AbortWithValue(0); } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* ams::diag::impl::FatalErrorByResultForNx(Result value) */ .section .text._ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE, "ax", %progbits .global _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE .type _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE, %function .balign 0x10 _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE: /* Save x27/x28. */ stp x27, x28, [sp, #-0x10]! stp x0, xzr, [sp, #-0x10]! /* Inline ams::diag::impl::PrepareAbort() */ mrs x27, tpidrro_el0 strh wzr, [x27, #0x100] ldrh w27, [x27, #0x102] cbz w27, 0f svc #0x36 0: /* Restore the value from stack. */ ldr x0, [sp] add sp, sp, #0x10 /* Put magic std::abort values into x27/x28. */ mov x28, #0xcafe movk x28, #0xdead, lsl#16 movk x28, #0xf00d, lsl#32 movk x28, #0xa55a, lsl#48 mov x27, #8 /* Abort */ 1: str x28, [x27] nop b 1b ================================================ FILE: libraries/libstratosphere/source/diag/diag_backtrace.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/diag_get_all_backtrace.hpp" namespace ams::diag { size_t GetBacktrace(uintptr_t *out, size_t out_size) { /* Validate pre-conditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(out_size > 0); /* Create the backtrace object. */ ::ams::diag::Backtrace bt{}; bt.Step(); /* Get the backtrace. */ return ::ams::diag::impl::GetAllBacktrace(out, out_size, bt); } #if defined(ATMOSPHERE_OS_HORIZON) size_t GetBacktrace(uintptr_t *out, size_t out_size, uintptr_t fp, uintptr_t sp, uintptr_t pc) { /* Validate pre-conditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(out_size > 0); /* Create the backtrace object. */ ::ams::diag::Backtrace bt{fp, sp, pc}; bt.Step(); /* Get the backtrace. */ return ::ams::diag::impl::GetAllBacktrace(out, out_size, bt); } #endif } ================================================ FILE: libraries/libstratosphere/source/diag/diag_log.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_log_impl.hpp" namespace ams::diag::impl { void CallAllLogObserver(const LogMetaData &meta, const LogBody &body); namespace { struct CallPrintDebugString { void operator()(const LogMetaData &meta, const char *msg, size_t size, bool head, bool tail) { const LogBody body = { .message = msg, .message_size = size, .is_head = head, .is_tail = tail }; CallAllLogObserver(meta, body); } }; } void LogImpl(const LogMetaData &meta, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); VLogImpl(meta, fmt, vl); va_end(vl); } void VLogImpl(const LogMetaData &meta, const char *fmt, std::va_list vl) { #if defined(ATMOSPHERE_OS_HORIZON) /* Print to stack buffer. */ char msg_buffer[DebugPrintBufferLength]; /* TODO: VFormatString using utf-8 printer. */ const size_t len = util::VSNPrintf(msg_buffer, sizeof(msg_buffer), fmt, vl); #else /* Print to allocated buffer. */ std::va_list cvl; va_copy(cvl, vl); const auto out_len = util::TVSNPrintf(nullptr, 0, fmt, cvl) + 1; va_end(cvl); char *msg_buffer = static_cast<char *>(std::malloc(out_len)); AMS_ABORT_UNLESS(msg_buffer != nullptr); ON_SCOPE_EXIT { std::free(msg_buffer); }; /* TODO: VFormatString using utf-8 printer. */ const size_t len = util::TVSNPrintf(msg_buffer, out_len, fmt, vl); #endif /* Call log observer. */ CallPrintDebugString()(meta, msg_buffer, len, true, true); } void PutImpl(const LogMetaData &meta, const char *msg, size_t msg_size) { CallPrintDebugString()(meta, msg, msg_size, true, true); } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_log_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag { namespace impl { constexpr inline size_t DebugPrintBufferLength = 0x100; } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_log_observer.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_log_impl.hpp" #include "impl/diag_observer_manager.hpp" #include "impl/diag_print_debug_string.hpp" namespace ams::diag { namespace impl { namespace { constexpr inline size_t DecorationStringLengthMax = 0x61; constexpr inline const char *EscapeSequencesForSeverity[] = { "\x1B[90m", /* Dark Gray (Trace) */ nullptr, /* None (Info) */ "\x1B[33m", /* Yellow (Warn) */ "\x1B[31m", /* Red (Error) */ "\x1B[41m\x1B[37m", /* White-on-red (Fatal) */ }; constexpr inline const char EscapeSequenceReset[] = "\x1B[0m"; constexpr inline size_t PrintBufferLength = DecorationStringLengthMax + impl::DebugPrintBufferLength + 1; constinit os::SdkMutex g_print_buffer_mutex; constinit char g_print_buffer[PrintBufferLength]; inline void GetCurrentTime(int *h, int *m, int *s, int *ms) { /* Get the current time. */ const auto cur_time = os::GetSystemTick().ToTimeSpan(); /* Extract fields. */ const s64 hours = cur_time.GetHours(); const s64 minutes = cur_time.GetMinutes(); const s64 seconds = cur_time.GetSeconds(); const s64 milliseconds = cur_time.GetMilliSeconds(); /* Set out fields. */ *h = static_cast<int>(hours); *m = static_cast<int>(minutes - hours * 60); *s = static_cast<int>(seconds - minutes * 60); *ms = static_cast<int>(milliseconds - seconds * 1000); } void TentativeDefaultLogObserver(const LogMetaData &meta, const LogBody &body, void *) { /* Acquire access to the print buffer */ std::scoped_lock lk(g_print_buffer_mutex); /* Get the escape sequence. */ const char *escape = nullptr; if (LogSeverity_Trace <= meta.severity && meta.severity <= LogSeverity_Fatal) { escape = EscapeSequencesForSeverity[meta.severity]; } /* Declare message variables. */ const char *msg = nullptr; size_t msg_size = 0; /* Handle structured logs. */ const bool structured = meta.module_name != nullptr && std::strlen(meta.module_name) >= 2; if (escape || structured) { /* Insert timestamp, if head. */ if (structured && body.is_head) { /* Get current timestamp. */ int hours, minutes, seconds, milliseconds; GetCurrentTime(std::addressof(hours), std::addressof(minutes), std::addressof(seconds), std::addressof(milliseconds)); /* Print the timestamp/header. */ msg_size += util::SNPrintf(g_print_buffer + msg_size, PrintBufferLength - msg_size, "%s%d:%02d:%02d.%03d [%-5.63s] ", escape ? escape : "", hours, minutes, seconds, milliseconds, meta.module_name[0] == '$' ? meta.module_name + 1 : meta.module_name + 0); AMS_AUDIT(msg_size <= DecorationStringLengthMax); } else if (escape) { msg_size += util::SNPrintf(g_print_buffer + msg_size, PrintBufferLength - msg_size, "%s", escape); } /* Determine maximum remaining size. */ const size_t max_msg_size = PrintBufferLength - msg_size - (escape ? sizeof(EscapeSequenceReset) - 1 : 0); /* Determine printable size. */ size_t printable_size = std::min<size_t>(body.message_size, max_msg_size); /* Determine newline status. */ bool new_line = false; if (body.message_size > 0 && body.message[body.message_size - 1] == '\n') { --printable_size; new_line = true; } /* Print the messsage. */ msg_size += util::SNPrintf(g_print_buffer + msg_size, PrintBufferLength - msg_size, "%.*s%s%s", static_cast<int>(printable_size), body.message, escape ? EscapeSequenceReset : "", new_line ? "\n" : ""); /* Set the message. */ msg = g_print_buffer; } else { /* Use the body's message directly. */ msg = body.message; msg_size = body.message_size; } /* Print the string. */ impl::PrintDebugString(msg, msg_size); } struct LogObserverContext { const LogMetaData &meta; const LogBody &body; }; using LogObserverManager = ObserverManagerWithDefaultHolder<LogObserverHolder, LogObserverContext>; constinit LogObserverManager g_log_observer_manager(::ams::diag::InitializeLogObserverHolder, TentativeDefaultLogObserver, nullptr); } void CallAllLogObserver(const LogMetaData &meta, const LogBody &body) { /* Create context. */ const LogObserverContext context = { .meta = meta, .body = body }; /* Invoke the log observer. */ g_log_observer_manager.InvokeAllObserver(context, [] (const LogObserverHolder &holder, const LogObserverContext &context) { holder.log_observer(context.meta, context.body, holder.arg); }); } void ReplaceDefaultLogObserver(LogObserver observer) { /* Get the default observer. */ auto *default_holder = std::addressof(g_log_observer_manager.GetDefaultObserverHolder()); /* Unregister, replace, and re-register. */ UnregisterLogObserver(default_holder); InitializeLogObserverHolder(default_holder, observer, nullptr); RegisterLogObserver(default_holder); } void ResetDefaultLogObserver() { /* Restore the default observer. */ ReplaceDefaultLogObserver(TentativeDefaultLogObserver); } } void RegisterLogObserver(LogObserverHolder *holder) { impl::g_log_observer_manager.RegisterObserver(holder); } void UnregisterLogObserver(LogObserverHolder *holder) { impl::g_log_observer_manager.UnregisterObserver(holder); } } ================================================ FILE: libraries/libstratosphere/source/diag/diag_symbol.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/diag_symbol_impl.hpp" namespace ams::diag { uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) { AMS_ASSERT(dst != nullptr); AMS_ASSERT(dst_size > 0); AMS_ASSERT(address > 0); return ::ams::diag::impl::GetSymbolNameImpl(dst, dst_size, address); } size_t GetSymbolSize(uintptr_t address) { AMS_ASSERT(address > 0); return ::ams::diag::impl::GetSymbolSizeImpl(address); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_abort_observer_manager.hpp" namespace ams::diag::impl { AbortObserverManager *GetAbortObserverManager() { AMS_FUNCTION_LOCAL_STATIC(AbortObserverManager, s_manager); return std::addressof(s_manager); } SdkAbortObserverManager *GetSdkAbortObserverManager() { AMS_FUNCTION_LOCAL_STATIC(SdkAbortObserverManager, s_manager); return std::addressof(s_manager); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "diag_observer_manager.hpp" namespace ams::diag::impl { using AbortObserverManager = ObserverManager<AbortObserverHolder, const AbortInfo &>; using SdkAbortObserverManager = ObserverManager<SdkAbortObserverHolder, const SdkAbortInfo &>; AbortObserverManager *GetAbortObserverManager(); SdkAbortObserverManager *GetSdkAbortObserverManager(); } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #if defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/windows.hpp> #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) #include <fcntl.h> #include <unistd.h> #endif namespace ams::diag::impl { namespace { #if defined(ATMOSPHERE_ARCH_X64) struct StackFrame { u64 fp; /* rbp */ u64 lr; /* rip */ }; #elif defined(ATMOSPHERE_ARCH_X86) struct StackFrame { u32 fp; /* ebp */ u32 lr; /* eip */ } #elif defined(ATMOSPHERE_ARCH_ARM64) struct StackFrame { u64 fp; u64 lr; }; #elif defined(ATMOSPHERE_ARCH_ARM) struct StackFrame { u32 fp; u32 lr; } #else #error "Unknown architecture for generic backtrace." #endif bool TryRead(os::NativeHandle native_handle, void *dst, size_t size, const void *address) { #if defined(ATMOSPHERE_OS_WINDOWS) return ::ReadProcessMemory(native_handle, address, dst, size, nullptr); #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) s32 ret; do { ret = ::write(native_handle, address, size); } while (ret < 0 && errno == EINTR); if (ret < 0) { return false; } std::memcpy(dst, address, size); return true; #else #error "Unknown OS for Backtrace native handle" #endif } } NOINLINE void Backtrace::Initialize() { /* Clear our size. */ m_index = 0; m_size = 0; /* Get the base frame pointer. */ const void *cur_fp = __builtin_frame_address(0); /* Try to read stack frames, until we run out. */ #if defined(ATMOSPHERE_OS_WINDOWS) const os::NativeHandle native_handle = ::GetCurrentProcess(); #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) os::NativeHandle pipe_handles[2]; s32 nret; do { nret = ::pipe(pipe_handles); } while (nret < 0 && errno == EINTR); if (nret < 0) { return; } do { nret = ::fcntl(pipe_handles[0], F_SETFL, O_NONBLOCK); } while (nret < 0 && errno == EINTR); if (nret < 0) { return; } do { nret = ::fcntl(pipe_handles[1], F_SETFL, O_NONBLOCK); } while (nret < 0 && errno == EINTR); if (nret < 0) { return; } ON_SCOPE_EXIT { do { nret = ::close(pipe_handles[0]); } while (nret < 0 && errno == EINTR); do { nret = ::close(pipe_handles[1]); } while (nret < 0 && errno == EINTR); }; const os::NativeHandle native_handle = pipe_handles[1]; if (native_handle < 0) { return; } #else #error "Unknown OS for Backtrace native handle" #endif StackFrame frame; while (m_size < BacktraceEntryCountMax) { /* Clear the frame. */ frame = {}; /* Read the next frame. */ if (!TryRead(native_handle, std::addressof(frame), sizeof(frame), cur_fp)) { break; } /* Add the return address. */ m_backtrace_addresses[m_size++] = reinterpret_cast<void *>(frame.lr); /* Set the next fp. */ cur_fp = reinterpret_cast<const void *>(frame.fp); } } bool Backtrace::Step() { return (++m_index) < m_size; } uintptr_t Backtrace::GetStackPointer() const { return 0; } uintptr_t Backtrace::GetReturnAddress() const { return reinterpret_cast<uintptr_t>(m_backtrace_addresses[m_index]); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::diag::impl { namespace { uintptr_t GetAddressValue(uintptr_t address) { if (address == 0) { return 0; } if (!util::IsAligned(address, alignof(uintptr_t))) { return 0; } return *reinterpret_cast<uintptr_t *>(address); } template<typename T, size_t N> svc::MemoryInfo *GetMemoryInfoPointer(T (&arr)[N]) { /* Check that there's enough space. */ static_assert(sizeof(T) * N <= sizeof(svc::MemoryInfo)); static_assert(alignof(T) >= alignof(svc::MemoryInfo)); return reinterpret_cast<svc::MemoryInfo *>(std::addressof(arr[0])); } bool IsValidLinkRegisterValue(uintptr_t lr, svc::MemoryInfo *info) { /* Ensure the memory info is valid. */ Result query_res; if (!(info->base_address <= lr && lr < info->base_address + info->size) && ({ svc::PageInfo page_info; query_res = svc::QueryMemory(info, std::addressof(page_info), lr); R_FAILED(query_res); })) { AMS_SDK_LOG("Failed to get backtrace. Query memory failed. (lr: %p, result: %03d-%04d)\n", reinterpret_cast<void *>(lr), query_res.GetModule(), query_res.GetDescription()); return false; } /* Check that lr is valid. */ if (lr == 0) { return false; } if (!util::IsAligned(lr, sizeof(u32))) { AMS_SDK_LOG("Failed to get backtrace. The link register alignment is invalid. (lr: %p)\n", reinterpret_cast<void *>(lr)); return false; } /* Check that the lr points to code. */ if (info->permission != svc::MemoryPermission_ReadExecute) { AMS_SDK_LOG("Failed to get backtrace. The link register points out of the code. (lr: %p)\n", reinterpret_cast<void *>(lr)); return false; } return true; } void GetNormalStackInfo(Backtrace::StackInfo *out) { if (void * const fiber = nullptr /* TODO: os::GetCurrentFiber() */; fiber == nullptr) { /* Get thread. */ auto * const thread = os::GetCurrentThread(); out->stack_top = reinterpret_cast<uintptr_t>(thread->stack); out->stack_bottom = reinterpret_cast<uintptr_t>(thread->stack) + thread->stack_size; } else { /* TODO: Fiber. */ } } bool GetExceptionStackInfo(Backtrace::StackInfo *out, uintptr_t sp) { /* Get the current stack info. */ uintptr_t cur_stack = 0; size_t cur_stack_size = 0; os::GetCurrentStackInfo(std::addressof(cur_stack), std::addressof(cur_stack_size)); /* Get the thread's stack info. */ uintptr_t thread_stack = 0; size_t thread_stack_size = 0; os::GetThreadStackInfo(std::addressof(thread_stack), std::addressof(thread_stack_size), os::GetCurrentThread()); /* If the current stack is the thread stack, exception stack isn't being used. */ if (cur_stack == thread_stack) { AMS_ASSERT(cur_stack_size == thread_stack_size); return false; } /* Check if the stack pointer is contained in the current stack. */ if (!(cur_stack <= sp && sp < cur_stack + cur_stack_size)) { return false; } /* Set the output. */ out->stack_top = cur_stack; out->stack_bottom = cur_stack + cur_stack_size; return true; } } NOINLINE void Backtrace::Initialize() { /* Get the stack pointer/frame pointer. */ uintptr_t fp, sp; __asm__ __volatile__( #if defined(ATMOSPHERE_ARCH_ARM64) "mov %[fp], fp\n" "mov %[sp], sp\n" #elif defined(ATMOSPHERE_ARCH_ARM) "mov %[fp], x29\n" "mov %[sp], sp\n" #else #error "Unknown architecture for Horizon fp/sp retrieval." #endif : [fp]"=&r"(fp), [sp]"=&r"(sp) : : "memory" ); /* Set our stack info. */ this->SetStackInfo(fp, sp); /* Step, to get our first lr. */ this->Step(); } void Backtrace::Initialize(uintptr_t fp, uintptr_t sp, uintptr_t pc) { /* Set our initial lr. */ m_lr = pc; /* Set our stack info. */ this->SetStackInfo(fp, sp); } bool Backtrace::Step() { /* We can't step without a frame pointer. */ if (m_fp == 0) { if (m_current_stack_info != std::addressof(m_normal_stack_info)) { AMS_SDK_LOG("Failed to get backtrace. The frame pointer is null.\n"); } return false; } /* The frame pointer needs to be aligned. */ if (!util::IsAligned(m_fp, sizeof(uintptr_t))) { AMS_SDK_LOG("Failed to get backtrace. The frame pointer alignment is invalid. (fp: %p)\n", reinterpret_cast<void *>(m_fp)); return false; } /* Ensure our current stack info is good. */ if (!(m_current_stack_info->stack_top <= m_fp && m_fp < m_current_stack_info->stack_bottom)) { if (m_current_stack_info != std::addressof(m_exception_stack_info) || !(m_normal_stack_info.stack_top <= m_fp && m_fp < m_normal_stack_info.stack_bottom)) { AMS_SDK_LOG("Failed to get backtrace. The frame pointer points out of the stack. (fp: %p, stack: %p-%p)\n", reinterpret_cast<void *>(m_fp), reinterpret_cast<void *>(m_current_stack_info->stack_top), reinterpret_cast<void *>(m_current_stack_info->stack_bottom)); return false; } m_current_stack_info = std::addressof(m_normal_stack_info); } else if (m_fp <= m_prev_fp) { AMS_SDK_LOG("Failed to get backtrace. The frame pointer is rewinding. (fp: %p, prev fp: %p, stack: %p-%p)\n", reinterpret_cast<void *>(m_fp), reinterpret_cast<void *>(m_prev_fp), reinterpret_cast<void *>(m_current_stack_info->stack_top), reinterpret_cast<void *>(m_current_stack_info->stack_bottom)); return false; } /* Update our previous fp. */ m_prev_fp = m_fp; /* Read lr/fp. */ m_lr = GetAddressValue(m_fp + sizeof(m_fp)); m_fp = GetAddressValue(m_fp); /* Check that lr is valid. */ if (IsValidLinkRegisterValue(m_lr, GetMemoryInfoPointer(m_memory_info_buffer))) { return true; } else { m_lr = 0; return false; } } uintptr_t Backtrace::GetStackPointer() const { if (m_fp != 0) { return m_fp - sizeof(m_fp); } else { return m_current_stack_info->stack_bottom - sizeof(m_fp); } } uintptr_t Backtrace::GetReturnAddress() const { return m_lr; } void Backtrace::SetStackInfo(uintptr_t fp, uintptr_t sp) { /* Get the normal stack info. */ GetNormalStackInfo(std::addressof(m_normal_stack_info)); /* Get the exception stack info. */ if (GetExceptionStackInfo(std::addressof(m_exception_stack_info), sp)) { m_current_stack_info = std::addressof(m_exception_stack_info); } else { m_current_stack_info = std::addressof(m_normal_stack_info); } /* Set our frame pointer. */ m_fp = fp; } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_dump_stack_trace.hpp" #if defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/windows.hpp> #endif namespace ams::diag::impl { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_DEBUGGING) namespace { constexpr const char *ToString(AbortReason reason) { switch (reason) { case AbortReason_Audit: return "Auditing Assertion Failure"; case AbortReason_Assert: return "Assertion Failure"; case AbortReason_UnexpectedDefault: return "Unexpected Default"; case AbortReason_Abort: default: return "Abort"; } } void DefaultPrinter(const AbortInfo &info) { /* Get the thread name. */ const char *thread_name; if (auto *cur_thread = os::GetCurrentThread(); cur_thread != nullptr) { thread_name = os::GetThreadNamePointer(cur_thread); } else { thread_name = "unknown"; } #if defined(ATMOSPHERE_OS_HORIZON) { u64 process_id = 0; u64 thread_id = 0; svc::GetProcessId(std::addressof(process_id), svc::PseudoHandle::CurrentProcess); svc::GetThreadId(std::addressof(thread_id), svc::PseudoHandle::CurrentThread); AMS_SDK_LOG("%s: '%s' in %s, process=0x%02" PRIX64 ", thread=%" PRIu64 " (%s)\n%s:%d\n", ToString(info.reason), info.expr, info.func, process_id, thread_id, thread_name, info.file, info.line); } #elif defined(ATMOSPHERE_OS_WINDOWS) { DWORD process_id = ::GetCurrentProcessId(); DWORD thread_id = ::GetCurrentThreadId(); AMS_SDK_LOG("%s: '%s' in %s, process=0x%" PRIX64 ", thread=%" PRIu64 " (%s)\n%s:%d\n", ToString(info.reason), info.expr, info.func, static_cast<u64>(process_id), static_cast<u64>(thread_id), thread_name, info.file, info.line); } #else { AMS_SDK_LOG("%s: '%s' in %s, thread=%s\n%s:%d\n", ToString(info.reason), info.expr, info.func, thread_name, info.file, info.line); } #endif AMS_SDK_VLOG(info.message->fmt, *(info.message->vl)); AMS_SDK_LOG("\n"); TentativeDumpStackTrace(); } } #endif void DefaultAbortObserver(const AbortInfo &info) { #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) DefaultPrinter(info); #else AMS_UNUSED(info); #endif } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { void TentativeDumpStackTrace(); } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_dump_stack_trace.hpp" namespace ams::diag::impl { void TentativeDumpStackTrace() { AMS_SDK_LOG("----------------Stack Trace----------------\n"); { /* Get the backtrace. */ constexpr size_t MaxBackTraceSize = 0x40; uintptr_t backtrace[MaxBackTraceSize]; const size_t num_items = ::ams::diag::GetBacktrace(backtrace, MaxBackTraceSize); /* Print each item. */ for (size_t i = 0; i < num_items; ++i) { char symbol_name[0x200]; if (const uintptr_t symbol_base = ::ams::diag::GetSymbolName(symbol_name, sizeof(symbol_name), backtrace[i] - 1); symbol_base != 0) { AMS_SDK_LOG("0x%016" PRIX64 " [ %s+0x%" PRIX64 " ]\n", static_cast<u64>(backtrace[i]), symbol_name, static_cast<u64>(backtrace[i] - symbol_base)); } else { AMS_SDK_LOG("0x%016" PRIX64 " [ unknown ]\n", static_cast<u64>(backtrace[i])); } } } AMS_SDK_LOG("-------------------------------------------\n"); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_dump_stack_trace.hpp" namespace ams::diag::impl { void TentativeDumpStackTrace() { /* TODO */ } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::diag::impl { namespace { constinit uintptr_t g_abort_impl_return_address = std::numeric_limits<uintptr_t>::max(); } void SetAbortImplReturnAddress(uintptr_t address) { g_abort_impl_return_address = address; } size_t GetAllBacktrace(uintptr_t *out, size_t out_size, ::ams::diag::Backtrace &bt) { size_t count = 0; do { /* Check that we can write another return address. */ if (count >= out_size) { break; } /* Get the current return address. */ const uintptr_t ret_addr = bt.GetReturnAddress(); /* If it's abort impl, reset the trace we're writing. */ if (ret_addr == g_abort_impl_return_address) { count = 0; } /* Set the output pointer. */ out[count++] = ret_addr; } while (bt.Step()); /* Return the number of addresses written. */ return count; } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { void SetAbortImplReturnAddress(uintptr_t address); size_t GetAllBacktrace(uintptr_t *out, size_t out_size, ::ams::diag::Backtrace &bt); } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_invoke_abort.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { void InvokeAbortObserver(const AbortInfo &info); void InvokeSdkAbortObserver(const SdkAbortInfo &info); } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_abort_observer_manager.hpp" #include "diag_invoke_abort.hpp" namespace ams::diag::impl { extern bool g_enable_default_abort_observer; void DefaultAbortObserver(const AbortInfo &info); void InvokeAbortObserver(const AbortInfo &info) { if (g_enable_default_abort_observer) { DefaultAbortObserver(info); } GetAbortObserverManager()->InvokeAllObserver(info); } void InvokeSdkAbortObserver(const SdkAbortInfo &info) { GetSdkAbortObserverManager()->InvokeAllObserver(info); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_abort_observer_manager.hpp" #include "diag_invoke_abort.hpp" namespace ams::diag::impl { extern bool g_enable_default_abort_observer; void DefaultAbortObserver(const AbortInfo &info); void InvokeAbortObserver(const AbortInfo &info) { if (g_enable_default_abort_observer) { DefaultAbortObserver(info); } GetAbortObserverManager()->InvokeAllObserver(info); } void InvokeSdkAbortObserver(const SdkAbortInfo &info) { GetSdkAbortObserverManager()->InvokeAllObserver(info); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_module_impl.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::diag::impl { namespace { constexpr inline uintptr_t ModulePathLengthOffset = 4; constexpr inline uintptr_t ModulePathOffset = 8; } uintptr_t GetModuleInfoForHorizon(const char **out_path, size_t *out_path_length, size_t *out_module_size, uintptr_t address) { /* Check for null address. */ if (address == 0) { return 0; } /* Get module info. */ ro::impl::ExceptionInfo exception_info; if (!ro::impl::GetExceptionInfo(std::addressof(exception_info), address)) { return 0; } /* Locate the path in the first non-read-execute segment. */ svc::MemoryInfo mem_info; svc::PageInfo page_info; auto cur_address = exception_info.module_address; while (cur_address < exception_info.module_address + exception_info.module_size) { if (R_FAILED(svc::QueryMemory(std::addressof(mem_info), std::addressof(page_info), cur_address))) { return 0; } if (mem_info.permission != svc::MemoryPermission_ReadExecute) { break; } cur_address += mem_info.size; } /* Set output info. */ *out_path = reinterpret_cast<const char *>(cur_address + ModulePathOffset); *out_path_length = *reinterpret_cast<const u32 *>(cur_address + ModulePathLengthOffset); *out_module_size = exception_info.module_size; return exception_info.module_address; } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_observer_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { template<typename Holder, typename Context> class ObserverManager { NON_COPYABLE(ObserverManager); NON_MOVEABLE(ObserverManager); private: Holder *m_observer_list_head; Holder **m_observer_list_tail; os::ReaderWriterLock m_lock; public: constexpr ObserverManager() : m_observer_list_head(nullptr), m_observer_list_tail(std::addressof(m_observer_list_head)), m_lock() { /* ... */ } constexpr ~ObserverManager() { if (std::is_constant_evaluated()) { this->UnregisterAllObserverLocked(); } else { this->UnregisterAllObserver(); } } void RegisterObserver(Holder *holder) { /* Acquire a write hold on our lock. */ std::scoped_lock lk(m_lock); this->RegisterObserverLocked(holder); } void UnregisterObserver(Holder *holder) { /* Acquire a write hold on our lock. */ std::scoped_lock lk(m_lock); /* Check that we can unregister. */ AMS_ASSERT(holder->is_registered); /* Remove the holder. */ if (m_observer_list_head == holder) { m_observer_list_head = holder->next; if (m_observer_list_tail == std::addressof(holder->next)) { m_observer_list_tail = std::addressof(m_observer_list_head); } } else { for (auto *cur = m_observer_list_head; cur != nullptr; cur = cur->next) { if (cur->next == holder) { cur->next = holder->next; if (m_observer_list_tail == std::addressof(holder->next)) { m_observer_list_tail = std::addressof(cur->next); } break; } } } /* Set unregistered. */ holder->next = nullptr; } void UnregisterAllObserver() { /* Acquire a write hold on our lock. */ std::scoped_lock lk(m_lock); this->UnregisterAllObserverLocked(); } void InvokeAllObserver(const Context &context) { /* Use the holder's observer. */ InvokeAllObserver(context, [] (const Holder &holder, const Context &context) { holder.observer(context); }); } template<typename Observer> void InvokeAllObserver(const Context &context, Observer observer) { /* Acquire a read hold on our lock. */ std::shared_lock lk(m_lock); /* Invoke all observers. */ for (const auto *holder = m_observer_list_head; holder != nullptr; holder = holder->next) { observer(*holder, context); } } protected: constexpr void RegisterObserverLocked(Holder *holder) { /* Check that we can register. */ AMS_ASSERT(!holder->is_registered); /* Insert the holder. */ *m_observer_list_tail = holder; m_observer_list_tail = std::addressof(holder->next); /* Set registered. */ holder->next = nullptr; holder->is_registered = true; } constexpr void UnregisterAllObserverLocked() { /* Unregister all observers. */ for (auto *holder = m_observer_list_head; holder != nullptr; holder = holder->next) { holder->is_registered = false; } /* Reset head/fail. */ m_observer_list_head = nullptr; m_observer_list_tail = std::addressof(m_observer_list_head); } }; template<typename Holder, typename Context> class ObserverManagerWithDefaultHolder : public ObserverManager<Holder, Context> { private: Holder m_default_holder; public: template<typename Initializer, typename... Args> constexpr ObserverManagerWithDefaultHolder(Initializer initializer, Args &&... args) : ObserverManager<Holder, Context>(), m_default_holder{} { /* Initialize the default observer. */ initializer(std::addressof(m_default_holder), std::forward<Args>(args)...); /* Register the default observer. */ if (std::is_constant_evaluated()) { this->RegisterObserverLocked(std::addressof(m_default_holder)); } else { this->RegisterObserver(std::addressof(m_default_holder)); } } Holder &GetDefaultObserverHolder() { return m_default_holder; } const Holder &GetDefaulObservertHolder() const { return m_default_holder; } }; } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_print_debug_string.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { void PrintDebugString(const char *msg, size_t size); inline void PrintDebugString(const char *msg) { AMS_AUDIT(msg != nullptr); PrintDebugString(msg, std::strlen(msg)); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_print_debug_string.hpp" namespace ams::diag::impl { void PrintDebugString(const char *msg, size_t size) { AMS_AUDIT(msg != nullptr || size == 0); if (size != 0) { svc::OutputDebugString(msg, size); } } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.linux.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_print_debug_string.hpp" namespace ams::diag::impl { NOINLINE void PrintDebugString(const char *msg, size_t size) { AMS_AUDIT(msg != nullptr || size == 0); if (size == 0) { return; } /* TODO: Printf? */ printf("%s", msg); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.macos.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_print_debug_string.hpp" namespace ams::diag::impl { NOINLINE void PrintDebugString(const char *msg, size_t size) { AMS_AUDIT(msg != nullptr || size == 0); if (size == 0) { return; } /* TODO: Printf? */ printf("%s", msg); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_print_debug_string.os.windows.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_print_debug_string.hpp" namespace ams::diag::impl { NOINLINE void PrintDebugString(const char *msg, size_t size) { AMS_AUDIT(msg != nullptr || size == 0); if (size == 0) { return; } /* TODO: OutputDebugString? Printf? */ printf("%s", msg); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_process.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> /* TODO: Rename, if we change to e.g. use amsMain? */ extern "C" int main(int argc, char **argv); namespace ams::diag::impl { uintptr_t GetModuleInfoForHorizon(const char **out_path, size_t *out_path_length, size_t *out_module_size, uintptr_t address); namespace { const char *GetLastCharacterPointer(const char *str, size_t len, char c) { for (const char *last = str + len - 1; last >= str; --last) { if (*last == c) { return last; } } return nullptr; } void GetFileNameWithoutExtension(const char **out, size_t *out_size, const char *path, size_t path_length) { const auto last_sep1 = GetLastCharacterPointer(path, path_length, '\\'); const auto last_sep2 = GetLastCharacterPointer(path, path_length, '/'); const auto ext = GetLastCharacterPointer(path, path_length, '.'); /* Handle last-separator. */ if (last_sep1 && last_sep2) { if (last_sep1 > last_sep2) { *out = last_sep1 + 1; } else { *out = last_sep2 + 1; } } else if (last_sep1) { *out = last_sep1 + 1; } else if (last_sep2) { *out = last_sep2 + 1; } else { *out = path; } /* Handle extension. */ if (ext && ext >= *out) { *out_size = ext - *out; } else { *out_size = (path + path_length) - *out; } } constinit const char *g_process_name = nullptr; constinit size_t g_process_name_size = 0; constinit os::SdkMutex g_process_name_lock; constinit bool g_got_process_name = false; void EnsureProcessNameCached() { /* Ensure process name. */ if (AMS_UNLIKELY(!g_got_process_name)) { std::scoped_lock lk(g_process_name_lock); if (AMS_LIKELY(!g_got_process_name)) { const char *path; size_t path_length; size_t module_size; if (GetModuleInfoForHorizon(std::addressof(path), std::addressof(path_length), std::addressof(module_size), reinterpret_cast<uintptr_t>(main)) != 0) { GetFileNameWithoutExtension(std::addressof(g_process_name), std::addressof(g_process_name_size), path, path_length); AMS_ASSERT(g_process_name_size == 0 || util::VerifyUtf8String(g_process_name, g_process_name_size)); } else { g_process_name = ""; g_process_name_size = 0; } g_got_process_name = true; } } } } void GetProcessNamePointer(const char **out, size_t *out_size) { /* Ensure process name is cached. */ EnsureProcessNameCached(); /* Get cached process name. */ *out = g_process_name; *out_size = g_process_name_size; } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_symbol_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::diag::impl { uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address); size_t GetSymbolSizeImpl(uintptr_t address); } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_symbol_impl.hpp" #define PACKAGE "stratosphere" #define PACKAGE_VERSION STRINGIFY(ATMOSPHERE_RELEASE_VERSION_MAJOR.ATMOSPHERE_RELEASE_VERSION_MINOR.ATMOSPHERE_RELEASE_VERSION_MICRO) #if defined(ATMOSPHERE_OS_LINUX) #include <bfd.h> #include <unistd.h> #include <dlfcn.h> #include <link.h> extern "C" char __init_array_start; #endif #include <cxxabi.h> namespace ams::diag::impl { namespace { class BfdHelper { private: bfd *m_handle; asymbol **m_symbol; size_t m_num_symbol; size_t m_num_func_symbol; const char *m_module_name; uintptr_t m_module_address; size_t m_module_size; private: BfdHelper() : m_handle(nullptr), m_symbol(nullptr), m_module_name(nullptr) { /* Get the current executable name. */ char exe_path[4_KB] = {}; GetExecutablePath(exe_path, sizeof(exe_path)); /* Open bfd. */ bfd *b = ::bfd_openr(exe_path, 0); if (b == nullptr) { return; } auto bfd_guard = SCOPE_GUARD { ::bfd_close(b); }; /* Check the format. */ if (!::bfd_check_format(b, bfd_object)) { return; } /* Verify the file has symbols. */ if ((bfd_get_file_flags(b) & HAS_SYMS) == 0) { return; } /* Read the symbols. */ unsigned int _; void *symbol_table; s64 num_symbols = bfd_read_minisymbols(b, false, std::addressof(symbol_table), std::addressof(_)); if (num_symbols == 0) { num_symbols = bfd_read_minisymbols(b, true, std::addressof(symbol_table), std::addressof(_)); if (num_symbols < 0) { return; } } /* We successfully got the symbol table. */ bfd_guard.Cancel(); m_handle = b; m_symbol = reinterpret_cast<asymbol **>(symbol_table); m_num_symbol = static_cast<size_t>(num_symbols); /* Sort the symbol table. */ std::sort(m_symbol + 0, m_symbol + m_num_symbol, [] (asymbol *lhs, asymbol *rhs) { const bool l_func = (lhs->flags & BSF_FUNCTION); const bool r_func = (rhs->flags & BSF_FUNCTION); if (l_func == r_func) { return bfd_asymbol_value(lhs) < bfd_asymbol_value(rhs); } else { return l_func; } }); /* Determine number of function symbols. */ m_num_func_symbol = 0; for (size_t i = 0; i < m_num_symbol; ++i) { if ((m_symbol[i]->flags & BSF_FUNCTION) == 0) { m_num_func_symbol = i; break; } } for (int i = std::strlen(exe_path) - 1; i >= 0; --i) { if (exe_path[i] == '/' || exe_path[i] == '\\') { m_module_name = strdup(exe_path + i + 1); break; } } /* Get our module base/size. */ #if defined(ATMOSPHERE_OS_LINUX) { m_module_address = _r_debug.r_map->l_addr; m_module_size = reinterpret_cast<uintptr_t>(std::addressof(__init_array_start)) - m_module_address; } #endif } ~BfdHelper() { if (m_symbol != nullptr) { std::free(m_symbol); } if (m_handle != nullptr) { ::bfd_close(m_handle); } } public: static BfdHelper &GetInstance() { AMS_FUNCTION_LOCAL_STATIC(BfdHelper, s_bfd_helper_instance); return s_bfd_helper_instance; } private: size_t GetSymbolSizeImpl(asymbol **symbol) const { /* Do our best to guess. */ const auto vma = bfd_asymbol_value(*symbol); if (symbol != m_symbol + m_num_func_symbol - 1) { return bfd_asymbol_value(*(symbol + 1)) - vma; } else { const auto *sec = (*symbol)->section; return (sec->vma + sec->size) - vma; } } std::ptrdiff_t GetSymbolAddressDisplacement(uintptr_t address) const { std::ptrdiff_t displacement = 0; if (m_module_address <= address && address < m_module_address + m_module_size) { displacement = m_module_address; } return displacement; } asymbol **GetBestSymbol(uintptr_t address) const { /* Adjust the symbol address. */ address -= this->GetSymbolAddressDisplacement(address); asymbol **best_symbol = std::lower_bound(m_symbol + 0, m_symbol + m_num_func_symbol, address, [](asymbol *lhs, uintptr_t rhs) { return bfd_asymbol_value(lhs) < rhs; }); if (best_symbol == m_symbol + m_num_func_symbol) { return nullptr; } if (bfd_asymbol_value(*best_symbol) != address && best_symbol > m_symbol) { --best_symbol; } const auto vma = bfd_asymbol_value(*best_symbol); const auto end = vma + this->GetSymbolSizeImpl(best_symbol); if (vma <= address && address < end) { return best_symbol; } else { return nullptr; } } public: uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) const { /* Get the symbol. */ auto **symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } /* Print the symbol. */ const char *name = bfd_asymbol_name(*symbol); int cpp_name_status = 0; if (char *demangled = abi::__cxa_demangle(name, nullptr, 0, std::addressof(cpp_name_status)); cpp_name_status == 0) { AMS_ASSERT(demangled != nullptr); util::TSNPrintf(dst, dst_size, "%s", demangled); std::free(demangled); } else { util::TSNPrintf(dst, dst_size, "%s", name); } return bfd_asymbol_value(*symbol) + this->GetSymbolAddressDisplacement(address); } size_t GetSymbolSize(uintptr_t address) const { /* Get the symbol. */ auto **symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } return this->GetSymbolSizeImpl(symbol); } private: static void GetExecutablePath(char *dst, size_t dst_size) { #if defined(ATMOSPHERE_OS_LINUX) { if (::readlink("/proc/self/exe", dst, dst_size) == -1) { dst[0] = 0; return; } } #else #error "Unknown OS for BfdHelper GetExecutablePath" #endif } }; } uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { return BfdHelper::GetInstance().GetSymbolName(dst, dst_size, address); } size_t GetSymbolSizeImpl(uintptr_t address) { return BfdHelper::GetInstance().GetSymbolSize(address); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_symbol_impl.hpp" namespace ams::diag::impl { uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { AMS_UNUSED(dst, dst_size, address); AMS_ABORT("TODO"); } size_t GetSymbolSizeImpl(uintptr_t address) { AMS_UNUSED(address); AMS_ABORT("TODO"); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.macos.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "diag_symbol_impl.hpp" #include <unistd.h> #include <mach-o/dyld.h> #include <mach-o/loader.h> #include <mach-o/nlist.h> #include <mach-o/stab.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/param.h> #include <sys/mman.h> #include <cxxabi.h> extern "C" { void __module_offset_helper() { /* ... */ } } namespace ams::diag::impl { namespace { class CurrentExecutableHelper { private: struct SymbolInfo { uintptr_t address; const char *name; }; private: os::NativeHandle m_fd; void *m_file_map; size_t m_file_size; SymbolInfo *m_symbols; size_t m_num_symbol; const char *m_module_name; uintptr_t m_module_address; size_t m_module_size; uintptr_t m_module_displacement; private: CurrentExecutableHelper() : m_fd(-1), m_file_map(nullptr), m_file_size(0), m_symbols(nullptr), m_num_symbol(0), m_module_name(nullptr), m_module_address(0), m_module_size(0), m_module_displacement(0) { /* Get the current executable name. */ char exe_path[4_KB] = {}; GetExecutablePath(exe_path, sizeof(exe_path)); /* Open the current executable. */ os::NativeHandle fd; do { fd = ::open(exe_path, O_RDONLY); } while (fd < 0 && errno == EINTR); if (fd < 0) { return; } ON_SCOPE_EXIT { if (fd >= 0) { s32 ret; do { ret = ::close(fd); } while (ret < 0 && errno == EINTR); } }; /* Get the file size. */ struct stat st; if (fstat(fd, std::addressof(st)) < 0) { return; } /* Check that the file can be mapped. */ const size_t exe_size = st.st_size; if (exe_size == 0) { return; } /* Map the executable. */ void *exe_map = mmap(nullptr, exe_size, PROT_READ, MAP_PRIVATE, fd, 0); if (exe_map == MAP_FAILED) { return; } ON_SCOPE_EXIT { if (exe_map != nullptr) { munmap(exe_map, exe_size); } }; /* Get the file's u32 magic. */ const uintptr_t exe_start = reinterpret_cast<uintptr_t>(exe_map); const u32 magic = *reinterpret_cast<const u32 *>(exe_start); /* Get/parse the mach header. */ u32 ncmds; bool is_64; if (magic == MH_MAGIC) { const auto *header = reinterpret_cast<const struct mach_header *>(exe_start); ncmds = header->ncmds; is_64 = false; } else if (magic == MH_MAGIC_64) { const auto *header = reinterpret_cast<const struct mach_header_64 *>(exe_start); ncmds = header->ncmds; is_64 = true; } else { return; } /* Find the symbol load command. */ const auto *lc = reinterpret_cast<const struct load_command *>(exe_start + (is_64 ? sizeof(struct mach_header_64) : sizeof(struct mach_header))); for (u32 i = 0; i < ncmds; ++i) { /* If we encounter the symbol table, parse it. */ if (lc->cmd == LC_SYMTAB) { if (is_64) { this->ParseSymbolTable<struct nlist_64>(exe_start, reinterpret_cast<const struct symtab_command *>(lc)); } else { this->ParseSymbolTable<struct nlist>(exe_start, reinterpret_cast<const struct symtab_command *>(lc)); } break; } else if (lc->cmd == LC_SEGMENT) { const auto *sc = reinterpret_cast<const struct segment_command *>(lc); if (std::strcmp(sc->segname, "__TEXT") == 0) { AMS_ASSERT(m_module_address == 0); m_module_address = sc->vmaddr; m_module_size = sc->vmsize; AMS_ASSERT(m_module_address != 0); } } else if (lc->cmd == LC_SEGMENT_64) { const auto *sc = reinterpret_cast<const struct segment_command_64 *>(lc); if (std::strcmp(sc->segname, "__TEXT") == 0) { AMS_ASSERT(m_module_address == 0); m_module_address = sc->vmaddr; m_module_size = sc->vmsize; AMS_ASSERT(m_module_address != 0); } } /* Advance to the next load command. */ lc = reinterpret_cast<const struct load_command *>(reinterpret_cast<uintptr_t>(lc) + lc->cmdsize); } for (size_t i = 0; i < m_num_symbol; ++i) { if (std::strcmp(m_symbols[i].name, "___module_offset_helper") == 0) { m_module_displacement = reinterpret_cast<uintptr_t>(&__module_offset_helper) - m_symbols[i].address; break; } } if (m_module_address > 0 && m_module_size > 0 && m_num_symbol > 0) { std::swap(m_fd, fd); std::swap(m_file_map, exe_map); m_file_size = exe_size; } } ~CurrentExecutableHelper() { if (m_file_map != nullptr) { munmap(m_file_map, m_file_size); } if (m_fd >= 0) { s32 ret; do { ret = ::close(m_fd); } while (ret < 0 && errno == EINTR); } } public: static CurrentExecutableHelper &GetInstance() { AMS_FUNCTION_LOCAL_STATIC(CurrentExecutableHelper, s_current_executable_helper_instance); return s_current_executable_helper_instance; } private: template<typename NlistType> void ParseSymbolTable(uintptr_t exe_start, const struct symtab_command *c) { /* Check pre-conditions. */ AMS_ASSERT(m_fd == -1); AMS_ASSERT(m_file_map == nullptr); AMS_ASSERT(m_symbols == nullptr); /* Get the strtab/symtab. */ const auto *symtab = reinterpret_cast<const NlistType *>(exe_start + c->symoff); const char *strtab = reinterpret_cast<const char *>(exe_start + c->stroff); /* Determine the number of functions. */ size_t funcs = 0; for (size_t i = 0; i < c->nsyms; ++i) { if (symtab[i].n_type != N_FUN || symtab[i].n_sect == NO_SECT) { continue; } ++funcs; } /* Allocate functions. */ m_symbols = reinterpret_cast<SymbolInfo *>(std::malloc(sizeof(SymbolInfo) * funcs)); if (m_symbols == nullptr) { return; } /* Set all symbols. */ m_num_symbol = 0; for (size_t i = 0; i < c->nsyms; ++i) { if (symtab[i].n_type != N_FUN || symtab[i].n_sect == NO_SECT) { continue; } m_symbols[m_num_symbol].address = symtab[i].n_value; m_symbols[m_num_symbol].name = strtab + symtab[i].n_un.n_strx; ++m_num_symbol; } AMS_ASSERT(m_num_symbol == funcs); /* Sort the symbols. */ std::sort(m_symbols + 0, m_symbols + m_num_symbol, [] (const SymbolInfo &lhs, const SymbolInfo &rhs) { return lhs.address < rhs.address; }); } size_t GetSymbolSizeImpl(const SymbolInfo *symbol) const { /* Do our best to guess. */ if (symbol != m_symbols + m_num_symbol - 1) { return (symbol + 1)->address - symbol->address; } else if (m_module_address + m_module_size >= symbol->address) { return m_module_address + m_module_size - symbol->address; } else { return 0; } } const SymbolInfo *GetBestSymbol(uintptr_t address) const { address -= m_module_displacement; const SymbolInfo *best_symbol = std::lower_bound(m_symbols + 0, m_symbols + m_num_symbol, address, [](const SymbolInfo &lhs, uintptr_t rhs) { return lhs.address < rhs; }); if (best_symbol == m_symbols + m_num_symbol) { return nullptr; } if (best_symbol->address != address && best_symbol > m_symbols) { --best_symbol; } const auto vma = best_symbol->address; const auto end = vma + this->GetSymbolSizeImpl(best_symbol); if (vma <= address && address < end) { return best_symbol; } else { return nullptr; } } public: uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) const { if (m_fd < 0) { return 0; } /* Get the symbol. */ const auto *symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } /* Print the symbol. */ const char *name = symbol->name; int cpp_name_status = 0; if (char *demangled = abi::__cxa_demangle(name, nullptr, 0, std::addressof(cpp_name_status)); cpp_name_status == 0) { AMS_ASSERT(demangled != nullptr); util::TSNPrintf(dst, dst_size, "%s", demangled); std::free(demangled); } else { util::TSNPrintf(dst, dst_size, "%s", name); } return symbol->address + m_module_displacement; } size_t GetSymbolSize(uintptr_t address) const { if (m_fd < 0) { return 0; } /* Get the symbol. */ const auto *symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } return this->GetSymbolSizeImpl(symbol); } private: static void GetExecutablePath(char *dst, size_t dst_size) { u32 len = dst_size; if (_NSGetExecutablePath(dst, std::addressof(len)) != 0) { dst[0] = 0; return; } } }; } uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { return CurrentExecutableHelper::GetInstance().GetSymbolName(dst, dst_size, address); } size_t GetSymbolSizeImpl(uintptr_t address) { return CurrentExecutableHelper::GetInstance().GetSymbolSize(address); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.windows.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/windows.hpp> #include "diag_symbol_impl.hpp" #include <cxxabi.h> extern "C" { void __module_offset_helper() { /* ... */ } } namespace ams::diag::impl { namespace { class CurrentExecutableHelper { private: struct SymbolInfo { uintptr_t address; const char *name; }; private: os::NativeHandle m_file_handle; os::NativeHandle m_map_handle; void *m_file_map; size_t m_file_size; SymbolInfo *m_symbols; size_t m_num_symbol; uintptr_t m_module_address; size_t m_module_size; uintptr_t m_module_displacement; private: CurrentExecutableHelper() : m_file_handle(INVALID_HANDLE_VALUE), m_map_handle(INVALID_HANDLE_VALUE), m_file_map(nullptr), m_file_size(0), m_symbols(nullptr), m_num_symbol(0), m_module_address(0), m_module_size(0), m_module_displacement(0) { /* Open the current executable. */ auto exe_handle = OpenExecutableFile(); if (exe_handle == INVALID_HANDLE_VALUE) { return; } ON_SCOPE_EXIT { if (exe_handle != INVALID_HANDLE_VALUE) { ::CloseHandle(exe_handle); } }; /* Get the exe size. */ LARGE_INTEGER exe_size_li; if (::GetFileSizeEx(exe_handle, std::addressof(exe_size_li)) == 0) { return; } /* Check the exe size. */ s64 exe_size = exe_size_li.QuadPart; if (exe_size == 0) { return; } /* Create a file mapping. */ auto map_handle = ::CreateFileMappingW(exe_handle, nullptr, PAGE_READONLY, 0, 0, nullptr); if (map_handle == INVALID_HANDLE_VALUE) { return; } ON_SCOPE_EXIT { if (map_handle != INVALID_HANDLE_VALUE) { ::CloseHandle(map_handle); } }; /* Map the file. */ void *exe_map = ::MapViewOfFile(map_handle, FILE_MAP_READ, 0, 0, 0); if (exe_map == nullptr) { return; } ON_SCOPE_EXIT { if (exe_map != nullptr) { ::UnmapViewOfFile(exe_map); } }; /* Get/parse the DOS header. */ const uintptr_t exe_start = reinterpret_cast<uintptr_t>(exe_map); const auto *dos_header = reinterpret_cast<const IMAGE_DOS_HEADER *>(exe_start); if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { return; } /* Set up the nt headers. */ const auto *nt32 = reinterpret_cast<const IMAGE_NT_HEADERS32 *>(exe_start + dos_header->e_lfanew); const auto *nt64 = reinterpret_cast<const IMAGE_NT_HEADERS64 *>(exe_start + dos_header->e_lfanew); if (nt32->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 || nt32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) { nt32 = nullptr; } else { nt64 = nullptr; } #define EXE_NT_HEADER(x) ((nt64 != nullptr) ? nt64->x : nt32->x) if (EXE_NT_HEADER(Signature) != IMAGE_NT_SIGNATURE) { return; } /* Check that the optional header is really present. */ if (EXE_NT_HEADER(FileHeader.SizeOfOptionalHeader) < sizeof(IMAGE_OPTIONAL_HEADER32)) { return; } /* Get sections. */ const auto *sec = nt64 != nullptr ? IMAGE_FIRST_SECTION(nt64) : IMAGE_FIRST_SECTION(nt32); /* Get the symbol table. */ const auto *symtab = reinterpret_cast<const IMAGE_SYMBOL *>(exe_start + EXE_NT_HEADER(FileHeader.PointerToSymbolTable)); const size_t nsym = EXE_NT_HEADER(FileHeader.NumberOfSymbols); const char *strtab = reinterpret_cast<const char *>(symtab + nsym); /* Find the section containing our code. */ int text_section = -1; for (size_t i = 0; i < nsym; ++i) { if (ISFCN(symtab[i].Type)) { const char *name = symtab[i].N.Name.Short == 0 ? strtab + symtab[i].N.Name.Long : reinterpret_cast<const char *>(symtab[i].N.ShortName); if (std::strcmp(name, "__module_offset_helper") == 0) { AMS_ASSERT(text_section == -1); AMS_ASSERT(m_module_displacement == 0); m_module_displacement = reinterpret_cast<uintptr_t>(&__module_offset_helper) - symtab[i].Value; text_section = symtab[i].SectionNumber; AMS_ASSERT(m_module_displacement != 0); AMS_ASSERT(text_section != -1); break; } } } /* Determine the number of functions. */ size_t funcs = 0; for (size_t i = 0; i < nsym; ++i) { if (ISFCN(symtab[i].Type) && symtab[i].SectionNumber == text_section) { ++funcs; } } /* Allocate functions. */ m_symbols = reinterpret_cast<SymbolInfo *>(std::malloc(sizeof(SymbolInfo) * funcs)); if (m_symbols == nullptr) { return; } /* Set all symbols. */ m_num_symbol = 0; for (size_t i = 0; i < nsym; ++i) { if (ISFCN(symtab[i].Type) && symtab[i].SectionNumber == text_section) { m_symbols[m_num_symbol].address = symtab[i].Value; m_symbols[m_num_symbol].name = symtab[i].N.Name.Short == 0 ? strtab + symtab[i].N.Name.Long : reinterpret_cast<const char *>(symtab[i].N.ShortName); ++m_num_symbol; } } AMS_ASSERT(m_num_symbol == funcs); /* Sort the symbols. */ std::sort(m_symbols + 0, m_symbols + m_num_symbol, [] (const SymbolInfo &lhs, const SymbolInfo &rhs) { return lhs.address < rhs.address; }); m_module_address = 0; m_module_size = sec[text_section - 1].Misc.VirtualSize; if (m_module_displacement != 0 && m_module_size > 0 && m_num_symbol > 0) { std::swap(m_file_handle, exe_handle); std::swap(m_map_handle, map_handle); std::swap(m_file_map, exe_map); m_file_size = exe_size; } } ~CurrentExecutableHelper() { if (m_file_map != nullptr) { ::UnmapViewOfFile(m_file_map); } if (m_map_handle != nullptr) { ::CloseHandle(m_map_handle); } if (m_file_handle != nullptr) { ::CloseHandle(m_file_handle); } } public: static CurrentExecutableHelper &GetInstance() { AMS_FUNCTION_LOCAL_STATIC(CurrentExecutableHelper, s_current_executable_helper_instance); return s_current_executable_helper_instance; } private: size_t GetSymbolSizeImpl(const SymbolInfo *symbol) const { /* Do our best to guess. */ if (symbol != m_symbols + m_num_symbol - 1) { return (symbol + 1)->address - symbol->address; } else if (m_module_address + m_module_size >= symbol->address) { return m_module_address + m_module_size - symbol->address; } else { return 0; } } const SymbolInfo *GetBestSymbol(uintptr_t address) const { address -= m_module_displacement; const SymbolInfo *best_symbol = std::lower_bound(m_symbols + 0, m_symbols + m_num_symbol, address, [](const SymbolInfo &lhs, uintptr_t rhs) { return lhs.address < rhs; }); if (best_symbol == m_symbols + m_num_symbol) { return nullptr; } if (best_symbol->address != address && best_symbol > m_symbols) { --best_symbol; } const auto vma = best_symbol->address; const auto end = vma + this->GetSymbolSizeImpl(best_symbol); if (vma <= address && address < end) { return best_symbol; } else { return nullptr; } } public: uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) const { if (m_file_handle == INVALID_HANDLE_VALUE) { return 0; } /* Get the symbol. */ const auto *symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } /* Print the symbol. */ const char *name = symbol->name; int cpp_name_status = 0; if (char *demangled = abi::__cxa_demangle(name, nullptr, 0, std::addressof(cpp_name_status)); cpp_name_status == 0) { AMS_ASSERT(demangled != nullptr); util::TSNPrintf(dst, dst_size, "%s", demangled); std::free(demangled); } else { util::TSNPrintf(dst, dst_size, "%s", name); } return symbol->address + m_module_displacement; } size_t GetSymbolSize(uintptr_t address) const { if (m_file_handle == INVALID_HANDLE_VALUE) { return 0; } /* Get the symbol. */ const auto *symbol = this->GetBestSymbol(address); if (symbol == nullptr) { return 0; } return this->GetSymbolSizeImpl(symbol); } private: static os::NativeHandle OpenExecutableFile() { /* Get the module file name. */ wchar_t module_file_name[0x1000]; if (::GetModuleFileNameW(0, module_file_name, util::size(module_file_name)) == 0) { return INVALID_HANDLE_VALUE; } return ::CreateFileW(module_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); } }; } uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { return CurrentExecutableHelper::GetInstance().GetSymbolName(dst, dst_size, address); } size_t GetSymbolSizeImpl(uintptr_t address) { return CurrentExecutableHelper::GetInstance().GetSymbolSize(address); } } ================================================ FILE: libraries/libstratosphere/source/diag/impl/diag_utf8_util.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::diag::impl { namespace { bool IsHeadOfCharacter(u8 c) { return (c & 0xC0) != 0x80; } size_t GetCharacterSize(u8 c) { if ((c & 0x80) == 0) { return 1; } else if ((c & 0xE0) == 0xC0) { return 2; } else if ((c & 0xF0) == 0xE0) { return 3; } else if ((c & 0xF8) == 0xF0) { return 4; } return 0; } const char *FindLastCharacterPointer(const char *str, size_t len) { /* Find the head of the last character. */ const char *cur; for (cur = str + len - 1; cur >= str && !IsHeadOfCharacter(*reinterpret_cast<const u8 *>(cur)); --cur) { /* ... */ } /* Return the last character. */ if (AMS_LIKELY(cur >= str)) { return cur; } else { return nullptr; } } } int GetValidSizeAsUtf8String(const char *str, size_t len) { /* Check pre-condition. */ AMS_ASSERT(str != nullptr); /* Check if we have no data. */ if (len == 0) { return 0; } /* Get the last character pointer. */ const auto *last_char_ptr = FindLastCharacterPointer(str, len); if (last_char_ptr == nullptr) { return -1; } /* Get sizes. */ const size_t actual_size = (str + len) - last_char_ptr; const size_t last_char_size = GetCharacterSize(*reinterpret_cast<const u8 *>(last_char_ptr)); if (last_char_size == 0) { return -1; } else if (actual_size >= last_char_size) { if (actual_size == last_char_size) { return len; } else { return -1; } } else if (actual_size >= len) { AMS_ASSERT(actual_size == len); return -1; } else { return static_cast<int>(len - actual_size); } } } ================================================ FILE: libraries/libstratosphere/source/dmnt/dmntcht.h ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <switch.h> #ifdef __cplusplus extern "C" { #endif typedef struct { u64 base; u64 size; } DmntMemoryRegionExtents; typedef struct { u64 process_id; u64 title_id; DmntMemoryRegionExtents main_nso_extents; DmntMemoryRegionExtents heap_extents; DmntMemoryRegionExtents alias_extents; DmntMemoryRegionExtents address_space_extents; u8 main_nso_build_id[0x20]; } DmntCheatProcessMetadata; typedef struct { char readable_name[0x40]; uint32_t num_opcodes; uint32_t opcodes[0x100]; } DmntCheatDefinition; typedef struct { bool enabled; uint32_t cheat_id; DmntCheatDefinition definition; } DmntCheatEntry; typedef struct { u64 value; u8 width; } DmntFrozenAddressValue; typedef struct { u64 address; DmntFrozenAddressValue value; } DmntFrozenAddressEntry; Result dmntchtInitialize(void); void dmntchtExit(void); Service* dmntchtGetServiceSession(void); Result dmntchtHasCheatProcess(bool *out); Result dmntchtGetCheatProcessEvent(Event *event); Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata); Result dmntchtForceOpenCheatProcess(void); Result dmntchtForceCloseCheatProcess(void); Result dmntchtGetCheatProcessMappingCount(u64 *out_count); Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count); Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size); Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size); Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address); Result dmntchtPauseCheatProcess(void); Result dmntchtResumeCheatProcess(void); Result dmntchtGetCheatCount(u64 *out_count); Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count); Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id); Result dmntchtToggleCheat(u32 cheat_id); Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id); Result dmntchtRemoveCheat(u32 cheat_id); Result dmntchtReadStaticRegister(u64 *out, u8 which); Result dmntchtWriteStaticRegister(u8 which, u64 value); Result dmntchtResetStaticRegisters(); Result dmntchtSetMasterCheat(DmntCheatDefinition *cheat); Result dmntchtGetFrozenAddressCount(u64 *out_count); Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count); Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address); Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value); Result dmntchtDisableFrozenAddress(u64 address); #ifdef __cplusplus } #endif ================================================ FILE: libraries/libstratosphere/source/dmnt/dmntcht.os.horizon.c ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define NX_SERVICE_ASSUME_NON_DOMAIN #include "../service_guard.h" #include "dmntcht.h" static Service g_dmntchtSrv; NX_GENERATE_SERVICE_GUARD(dmntcht); Result _dmntchtInitialize(void) { return smGetService(&g_dmntchtSrv, "dmnt:cht"); } void _dmntchtCleanup(void) { serviceClose(&g_dmntchtSrv); } Service* dmntchtGetServiceSession(void) { return &g_dmntchtSrv; } Result dmntchtHasCheatProcess(bool *out) { u8 tmp; Result rc = serviceDispatchOut(&g_dmntchtSrv, 65000, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp & 1; return rc; } Result dmntchtGetCheatProcessEvent(Event *event) { Handle evt_handle; Result rc = serviceDispatch(&g_dmntchtSrv, 65001, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, .out_handles = &evt_handle, ); if (R_SUCCEEDED(rc)) { eventLoadRemote(event, evt_handle, true); } return rc; } Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) { return serviceDispatchOut(&g_dmntchtSrv, 65002, *out_metadata); } static Result _dmntchtCmdVoid(Service* srv, u32 cmd_id) { return serviceDispatch(srv, cmd_id); } Result dmntchtForceOpenCheatProcess(void) { return _dmntchtCmdVoid(&g_dmntchtSrv, 65003); } Result dmntchtPauseCheatProcess(void) { return _dmntchtCmdVoid(&g_dmntchtSrv, 65004); } Result dmntchtResumeCheatProcess(void) { return _dmntchtCmdVoid(&g_dmntchtSrv, 65005); } Result dmntchtForceCloseCheatProcess(void) { return _dmntchtCmdVoid(&g_dmntchtSrv, 65006); } static Result _dmntchtGetCount(u64 *out_count, u32 cmd_id) { return serviceDispatchOut(&g_dmntchtSrv, cmd_id, *out_count); } static Result _dmntchtGetEntries(void *buffer, u64 buffer_size, u64 offset, u64 *out_count, u32 cmd_id) { return serviceDispatchInOut(&g_dmntchtSrv, cmd_id, offset, *out_count, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, .buffers = { { buffer, buffer_size } }, ); } static Result _dmntchtCmdInU32NoOut(u32 in, u32 cmd_id) { return serviceDispatchIn(&g_dmntchtSrv, cmd_id, in); } Result dmntchtGetCheatProcessMappingCount(u64 *out_count) { return _dmntchtGetCount(out_count, 65100); } Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) { return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65101); } Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) { const struct { u64 address; u64 size; } in = { address, size }; return serviceDispatchIn(&g_dmntchtSrv, 65102, in, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, .buffers = { { buffer, size } }, ); } Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) { const struct { u64 address; u64 size; } in = { address, size }; return serviceDispatchIn(&g_dmntchtSrv, 65103, in, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, .buffers = { { buffer, size } }, ); } Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){ return serviceDispatchInOut(&g_dmntchtSrv, 65104, address, *mem_info); } Result dmntchtGetCheatCount(u64 *out_count) { return _dmntchtGetCount(out_count, 65200); } Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65201); } Result dmntchtGetCheatById(DmntCheatEntry *out, u32 cheat_id) { return serviceDispatchIn(&g_dmntchtSrv, 65202, cheat_id, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, .buffers = { { out, sizeof(*out) } }, ); } Result dmntchtToggleCheat(u32 cheat_id) { return _dmntchtCmdInU32NoOut(cheat_id, 65203); } Result dmntchtAddCheat(DmntCheatDefinition *cheat_def, bool enabled, u32 *out_cheat_id) { const u8 in = enabled != 0; return serviceDispatchInOut(&g_dmntchtSrv, 65204, in, *out_cheat_id, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, .buffers = { { cheat_def, sizeof(*cheat_def) } }, ); } Result dmntchtRemoveCheat(u32 cheat_id) { return _dmntchtCmdInU32NoOut(cheat_id, 65205); } Result dmntchtReadStaticRegister(u64 *out, u8 which) { return serviceDispatchInOut(&g_dmntchtSrv, 65206, which, *out); } Result dmntchtWriteStaticRegister(u8 which, u64 value) { const struct { u64 which; u64 value; } in = { which, value }; return serviceDispatchIn(&g_dmntchtSrv, 65207, in); } Result dmntchtResetStaticRegisters() { return _dmntchtCmdVoid(&g_dmntchtSrv, 65208); } Result dmntchtSetMasterCheat(DmntCheatDefinition *cheat_def) { return serviceDispatch(&g_dmntchtSrv, 65209, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, .buffers = { { cheat_def, sizeof(*cheat_def) } }, ); } Result dmntchtGetFrozenAddressCount(u64 *out_count) { return _dmntchtGetCount(out_count, 65300); } Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65301); } Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) { return serviceDispatchInOut(&g_dmntchtSrv, 65302, address, *out); } Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { const struct { u64 address; u64 width; } in = { address, width }; return serviceDispatchInOut(&g_dmntchtSrv, 65303, in, *out_value); } Result dmntchtDisableFrozenAddress(u64 address) { return serviceDispatchIn(&g_dmntchtSrv, 65304, address); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_allocator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { extern lmem::HeapHandle g_heap_handle; class Allocator { public: void *operator new(size_t sz) noexcept { return lmem::AllocateFromExpHeap(g_heap_handle, sz); } void *operator new(size_t sz, size_t algn) noexcept { return lmem::AllocateFromExpHeap(g_heap_handle, sz, static_cast<s32>(algn)); } void *operator new[](size_t sz) noexcept { return lmem::AllocateFromExpHeap(g_heap_handle, sz); } void *operator new[](size_t sz, size_t algn) noexcept { return lmem::AllocateFromExpHeap(g_heap_handle, sz, static_cast<s32>(algn)); } void operator delete(void *p) noexcept { lmem::FreeToExpHeap(g_heap_handle, p); } void operator delete[](void *p) noexcept { lmem::FreeToExpHeap(g_heap_handle, p); } }; inline void *Allocate(size_t sz) { return lmem::AllocateFromExpHeap(g_heap_handle, sz); } inline void *AllocateWithAlign(size_t sz, size_t align) { return lmem::AllocateFromExpHeap(g_heap_handle, sz, align); } inline void Deallocate(void *p) { return lmem::FreeToExpHeap(g_heap_handle, p); } inline void DeallocateWithSize(void *p, size_t size) { AMS_UNUSED(size); return lmem::FreeToExpHeap(g_heap_handle, p); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_attachment_impl.hpp" #include "erpt_srv_attachment.hpp" namespace ams::erpt::srv { AttachmentFileName Attachment::FileName(AttachmentId attachment_id) { char uuid_str[AttachmentFileNameLength]; attachment_id.uuid.ToString(uuid_str, sizeof(uuid_str)); AttachmentFileName attachment_name; util::SNPrintf(attachment_name.name, sizeof(attachment_name.name), "%s:/%s.att", ReportStoragePath, uuid_str); return attachment_name; } Attachment::Attachment(JournalRecord<AttachmentInfo> *r) : m_record(r) { m_record->AddReference(); } Attachment::~Attachment() { this->CloseStream(); if (m_record->RemoveReference()) { if (R_FAILED(this->DeleteStream(this->FileName().name))) { /* TODO: Log failure? */ } delete m_record; } } AttachmentFileName Attachment::FileName() const { return FileName(m_record->m_info.attachment_id); } Result Attachment::Open(AttachmentOpenType type) { switch (type) { case AttachmentOpenType_Create: R_RETURN(this->OpenStream(this->FileName().name, StreamMode_Write, AttachmentStreamBufferSize)); case AttachmentOpenType_Read: R_RETURN(this->OpenStream(this->FileName().name, StreamMode_Read, AttachmentStreamBufferSize)); default: R_THROW(erpt::ResultInvalidArgument()); } } Result Attachment::Read(u32 *out_read_count, u8 *dst, u32 dst_size) { R_RETURN(this->ReadStream(out_read_count, dst, dst_size)); } Result Attachment::Delete() { R_RETURN(this->DeleteStream(this->FileName().name)); } void Attachment::Close() { return this->CloseStream(); } Result Attachment::GetFlags(AttachmentFlagSet *out) const { *out = m_record->m_info.flags; R_SUCCEED(); } Result Attachment::SetFlags(AttachmentFlagSet flags) { if (((~m_record->m_info.flags) & flags).IsAnySet()) { m_record->m_info.flags |= flags; R_RETURN(Journal::Commit()); } R_SUCCEED(); } Result Attachment::GetSize(s64 *out) const { R_RETURN(this->GetStreamSize(out)); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_stream.hpp" #include "erpt_srv_journal.hpp" namespace ams::erpt::srv { enum AttachmentOpenType { AttachmentOpenType_Create = 0, AttachmentOpenType_Read = 1, }; constexpr inline u32 AttachmentStreamBufferSize = 1_KB; class Attachment : public Allocator, public Stream { private: JournalRecord<AttachmentInfo> *m_record; private: AttachmentFileName FileName() const; public: static AttachmentFileName FileName(AttachmentId attachment_id); public: explicit Attachment(JournalRecord<AttachmentInfo> *r); ~Attachment(); Result Open(AttachmentOpenType type); Result Read(u32 *out_read_count, u8 *dst, u32 dst_size); Result Delete(); void Close(); Result GetFlags(AttachmentFlagSet *out) const; Result SetFlags(AttachmentFlagSet flags); Result GetSize(s64 *out) const; template<typename T> Result Write(T val) { R_RETURN(this->WriteStream(reinterpret_cast<const u8 *>(std::addressof(val)), sizeof(val))); } template<typename T> Result Write(const T *buf, u32 buffer_size) { R_RETURN(this->WriteStream(reinterpret_cast<const u8 *>(buf), buffer_size)); } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_attachment_impl.hpp" #include "erpt_srv_attachment.hpp" namespace ams::erpt::srv { AttachmentImpl::AttachmentImpl() : m_attachment(nullptr) { /* ... */ } AttachmentImpl::~AttachmentImpl() { R_ABORT_UNLESS(this->Close()); } Result AttachmentImpl::Open(const AttachmentId &attachment_id) { R_UNLESS(m_attachment == nullptr, erpt::ResultAlreadyInitialized()); JournalRecord<AttachmentInfo> *record = Journal::Retrieve(attachment_id); R_UNLESS(record != nullptr, erpt::ResultNotFound()); m_attachment = new Attachment(record); R_UNLESS(m_attachment != nullptr, erpt::ResultOutOfMemory()); auto attachment_guard = SCOPE_GUARD { delete m_attachment; m_attachment = nullptr; }; R_TRY(m_attachment->Open(AttachmentOpenType_Read)); attachment_guard.Cancel(); R_SUCCEED(); } Result AttachmentImpl::Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) { R_UNLESS(m_attachment != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_attachment->Read(out_count.GetPointer(), static_cast<u8 *>(out_buffer.GetPointer()), static_cast<u32>(out_buffer.GetSize()))); } Result AttachmentImpl::SetFlags(AttachmentFlagSet flags) { R_UNLESS(m_attachment != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_attachment->SetFlags(flags)); } Result AttachmentImpl::GetFlags(ams::sf::Out<AttachmentFlagSet> out) { R_UNLESS(m_attachment != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_attachment->GetFlags(out.GetPointer())); } Result AttachmentImpl::Close() { if (m_attachment != nullptr) { m_attachment->Close(); delete m_attachment; m_attachment = nullptr; } R_SUCCEED(); } Result AttachmentImpl::GetSize(ams::sf::Out<s64> out) { R_UNLESS(m_attachment != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_attachment->GetSize(out.GetPointer())); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_attachment_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class Attachment; class AttachmentImpl { private: Attachment *m_attachment; public: AttachmentImpl(); ~AttachmentImpl(); public: Result Open(const AttachmentId &attachment_id); Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer); Result SetFlags(AttachmentFlagSet flags); Result GetFlags(ams::sf::Out<AttachmentFlagSet> out); Result Close(); Result GetSize(ams::sf::Out<s64> out); }; static_assert(erpt::sf::IsIAttachment<AttachmentImpl>); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_cipher.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_cipher.hpp" namespace ams::erpt::srv { constinit u8 Cipher::s_key[crypto::Aes128CtrEncryptor::KeySize + crypto::Aes128CtrEncryptor::IvSize + crypto::Aes128CtrEncryptor::BlockSize]; constinit bool Cipher::s_need_to_store_cipher = false; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_cipher.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_formatter.hpp" #include "erpt_srv_keys.hpp" namespace ams::erpt::srv { class Cipher : private Formatter { private: static constexpr u32 RsaKeySize = 0x100; static constexpr u32 SaltSize = 0x20; static u8 s_key[crypto::Aes128CtrEncryptor::KeySize + crypto::Aes128CtrEncryptor::IvSize + crypto::Aes128CtrEncryptor::BlockSize]; static bool s_need_to_store_cipher; struct Header { u32 magic; u32 field_type; u32 element_count; u32 reserved; u8 data[0]; }; static_assert(sizeof(Header) == 0x10); static constexpr u32 HeaderMagic = util::FourCC<'C', 'R', 'P', 'T'>::Code; private: template<typename T> static Result EncryptArray(Report *report, FieldId field_id, T *arr, u32 arr_size) { const u32 data_size = util::AlignUp(arr_size * sizeof(T), crypto::Aes128CtrEncryptor::BlockSize); Header *hdr = reinterpret_cast<Header *>(AllocateWithAlign(sizeof(Header) + data_size, crypto::Aes128CtrEncryptor::BlockSize)); R_UNLESS(hdr != nullptr, erpt::ResultOutOfMemory()); ON_SCOPE_EXIT { Deallocate(hdr); }; hdr->magic = HeaderMagic; hdr->field_type = static_cast<u32>(ConvertFieldToType(field_id)); hdr->element_count = arr_size; hdr->reserved = 0; std::memset(hdr->data, 0, data_size); std::memcpy(hdr->data, arr, arr_size * sizeof(T)); crypto::EncryptAes128Ctr(hdr->data, data_size, s_key, crypto::Aes128CtrEncryptor::KeySize, s_key + crypto::Aes128CtrEncryptor::KeySize, crypto::Aes128CtrEncryptor::IvSize, hdr->data, data_size); ON_SCOPE_EXIT { std::memset(hdr, 0, sizeof(hdr) + data_size); s_need_to_store_cipher = true; }; R_RETURN(Formatter::AddField(report, field_id, reinterpret_cast<u8 *>(hdr), sizeof(hdr) + data_size)); } public: static Result Begin(Report *report, u32 record_count) { s_need_to_store_cipher = false; crypto::GenerateCryptographicallyRandomBytes(s_key, sizeof(s_key)); R_RETURN(Formatter::Begin(report, record_count + 1)); } static Result End(Report *report) { u8 cipher[RsaKeySize] = {}; if (s_need_to_store_cipher) { u8 salt[SaltSize]; crypto::RsaOaepEncryptor<RsaKeySize, crypto::Sha256Generator> oaep; crypto::GenerateCryptographicallyRandomBytes(salt, sizeof(salt)); oaep.Initialize(GetPublicKeyModulus(), GetPublicKeyModulusSize(), GetPublicKeyExponent(), GetPublicKeyExponentSize()); oaep.Encrypt(cipher, sizeof(cipher), s_key, sizeof(s_key), salt, sizeof(salt)); } R_TRY(Formatter::AddField(report, FieldId_CipherKey, cipher, s_need_to_store_cipher ? sizeof(cipher) : 1)); std::memset(s_key, 0, sizeof(s_key)); R_RETURN(Formatter::End(report)); } static Result AddField(Report *report, FieldId field_id, bool value) { R_RETURN(Formatter::AddField(report, field_id, value)); } template<typename T> static Result AddField(Report *report, FieldId field_id, T value) { R_RETURN(Formatter::AddField<T>(report, field_id, value)); } static Result AddField(Report *report, FieldId field_id, char *str, u32 len) { if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) { R_RETURN(EncryptArray<char>(report, field_id, str, len)); } else { R_RETURN(Formatter::AddField(report, field_id, str, len)); } } static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) { if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) { R_RETURN(EncryptArray<u8>(report, field_id, bin, len)); } else { R_RETURN(Formatter::AddField(report, field_id, bin, len)); } } template<typename T> static Result AddField(Report *report, FieldId field_id, T *arr, u32 len) { if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) { R_RETURN(EncryptArray<T>(report, field_id, arr, len)); } else { R_RETURN(Formatter::AddField<T>(report, field_id, arr, len)); } } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_context.hpp" #include "erpt_srv_cipher.hpp" #include "erpt_srv_context_record.hpp" #include "erpt_srv_report.hpp" namespace ams::erpt::srv { namespace { using ContextList = util::IntrusiveListBaseTraits<Context>::ListType; constinit ContextList g_category_list; } Context::Context(CategoryId cat) : m_category(cat) { g_category_list.push_front(*this); } Context::~Context() { g_category_list.erase(g_category_list.iterator_to(*this)); } Result Context::AddCategoryToReport(Report *report) { if (m_record != nullptr) { const auto *entry = m_record->GetContextEntryPtr(); for (u32 i = 0; i < entry->field_count; i++) { auto *field = std::addressof(entry->fields[i]); u8 *arr_buf = entry->array_buffer; switch (field->type) { case FieldType_Bool: R_TRY(Cipher::AddField(report, field->id, field->value_bool)); break; case FieldType_NumericU8: R_TRY(Cipher::AddField(report, field->id, field->value_u8)); break; case FieldType_NumericU16: R_TRY(Cipher::AddField(report, field->id, field->value_u16)); break; case FieldType_NumericU32: R_TRY(Cipher::AddField(report, field->id, field->value_u32)); break; case FieldType_NumericU64: R_TRY(Cipher::AddField(report, field->id, field->value_u64)); break; case FieldType_NumericI8: R_TRY(Cipher::AddField(report, field->id, field->value_i8)); break; case FieldType_NumericI16: R_TRY(Cipher::AddField(report, field->id, field->value_i16)); break; case FieldType_NumericI32: R_TRY(Cipher::AddField(report, field->id, field->value_i32)); break; case FieldType_NumericI64: R_TRY(Cipher::AddField(report, field->id, field->value_i64)); break; case FieldType_String: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast<char *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(char))); break; case FieldType_U8Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u8 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u8))); break; case FieldType_U32Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u32 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u32))); break; case FieldType_U64Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< u64 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(u64))); break; case FieldType_I8Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s8 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s8))); break; case FieldType_I32Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s32 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s32))); break; case FieldType_I64Array: R_TRY(Cipher::AddField(report, field->id, reinterpret_cast< s64 *>(arr_buf + field->value_array.start_idx), field->value_array.size / sizeof(s64))); break; default: R_THROW(erpt::ResultInvalidArgument()); } } } R_SUCCEED(); } Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) { auto record = std::make_unique<ContextRecord>(); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_TRY(record->Initialize(entry, data, data_size)); R_RETURN(SubmitContextRecord(std::move(record))); } Result Context::SubmitContextRecord(std::unique_ptr<ContextRecord> record) { auto it = util::range::find_if(g_category_list, [&](const Context &cur) { return cur.m_category == record->GetContextEntryPtr()->category; }); R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound()); it->m_record = std::move(record); R_SUCCEED(); } Result Context::WriteContextsToReport(Report *report) { R_TRY(report->Open(ReportOpenType_Create)); ON_SCOPE_EXIT { report->Close(); }; R_TRY(Cipher::Begin(report, ContextRecord::GetRecordCount())); for (auto it = g_category_list.begin(); it != g_category_list.end(); it++) { R_TRY(it->AddCategoryToReport(report)); } R_RETURN(Cipher::End(report)); } Result Context::ClearContext(CategoryId cat) { /* Make an empty record for the category. */ auto record = std::make_unique<ContextRecord>(cat); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Submit the context record. */ R_RETURN(SubmitContextRecord(std::move(record))); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_cipher.hpp" namespace ams::erpt::srv { class ContextRecord; class Report; class Context : public Allocator, public util::IntrusiveListBaseNode<Context> { private: const CategoryId m_category; std::unique_ptr<ContextRecord> m_record; public: Context(CategoryId cat); ~Context(); Result AddCategoryToReport(Report *report); public: static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size); static Result SubmitContextRecord(std::unique_ptr<ContextRecord> record); static Result WriteContextsToReport(Report *report); static Result ClearContext(CategoryId cat); }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_context_impl.hpp" #include "erpt_srv_manager_impl.hpp" #include "erpt_srv_context.hpp" #include "erpt_srv_reporter.hpp" #include "erpt_srv_journal.hpp" #include "erpt_srv_forced_shutdown.hpp" namespace ams::erpt::srv { namespace { ContextEntry MakeContextEntry(const CategoryEntry &cat_entry, Span<const FieldEntry> field_entries) { /* Check pre-conditions. */ AMS_ASSERT(cat_entry.field_count <= field_entries.size()); /* Make the entry. */ ContextEntry entry = {}; entry.version = 0; entry.category = cat_entry.category; entry.field_count = cat_entry.field_count; for (size_t i = 0; i < cat_entry.field_count; ++i) { entry.fields[i] = field_entries[i]; } return entry; } Result SubmitMultipleContextImpl(Span<const CategoryEntry> category_entries, Span<const FieldEntry> field_entries, Span<const u8> array_buf) { /* Iterate over all category entries. */ size_t field_entry_offset = 0; size_t array_buf_offset = 0; for (const auto &category_entry : category_entries) { /* Check that the category is valid. */ R_UNLESS(erpt::srv::IsValidCategory(category_entry.category), erpt::ResultInvalidArgument()); /* Check that there aren't too many fields for the category. */ R_UNLESS(category_entry.field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); /* Check that there isn't too much data in the array buf. */ R_UNLESS(category_entry.array_buffer_count <= ArrayBufferSizeMax, erpt::ResultInvalidArgument()); /* Check that the fields/data fit into the provided buffer. */ R_UNLESS(category_entry.field_count + field_entry_offset <= field_entries.size(), erpt::ResultInvalidArgument()); R_UNLESS(category_entry.array_buffer_count + array_buf_offset <= array_buf.size_bytes(), erpt::ResultInvalidArgument()); /* Make the entry. */ const auto ctx_entry = MakeContextEntry(category_entry, field_entries.subspan(field_entry_offset, category_entry.field_count)); R_TRY(Context::SubmitContext(std::addressof(ctx_entry), array_buf.data() + array_buf_offset, category_entry.array_buffer_count)); /* Advance. */ field_entry_offset += category_entry.field_count; array_buf_offset += category_entry.array_buffer_count; } /* We succeeded. */ R_SUCCEED(); } } Result ContextImpl::SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer) { const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize()); const u32 data_size = static_cast<u32>(data_buffer.GetSize()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(data_size <= ArrayBufferSizeMax, erpt::ResultInvalidArgument()); SubmitContextForForcedShutdownDetection(ctx, data, data_size); R_RETURN(Context::SubmitContext(ctx, data, data_size)); } Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags) { const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer()); const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize()); const u32 data_size = static_cast<u32>(data_buffer.GetSize()); const u32 meta_size = static_cast<u32>(meta_buffer.GetSize()); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument()); R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0, flags, nullptr)); ManagerImpl::NotifyAll(); R_SUCCEED(); } Result ContextImpl::CreateReportV1(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result) { R_RETURN(this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, result, erpt::srv::MakeNoCreateReportOptionFlags())); } Result ContextImpl::CreateReportV0(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) { R_RETURN(this->CreateReportV1(report_type, ctx_buffer, data_buffer, meta_buffer, ResultSuccess())); } Result ContextImpl::SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) { Reporter::SetInitialLaunchSettingsCompletionTime(time_point); R_SUCCEED(); } Result ContextImpl::ClearInitialLaunchSettingsCompletionTime() { Reporter::ClearInitialLaunchSettingsCompletionTime(); R_SUCCEED(); } Result ContextImpl::UpdatePowerOnTime() { /* NOTE: Prior to 12.0.0, this set the power on time, but now erpt does it during initialization. */ R_SUCCEED(); } Result ContextImpl::UpdateAwakeTime() { /* NOTE: Prior to 12.0.0, this set the power on time, but now erpt does it during initialization. */ R_SUCCEED(); } Result ContextImpl::CreateReportWithAdditionalContext(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags, const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer) { /* Submit the additional context. */ R_TRY(SubmitMultipleContextImpl(category_entries.ToSpan(), field_entries.ToSpan(), MakeSpan<const u8>(array_buffer.GetPointer(), array_buffer.GetSize()))); /* Clear the additional context when we're done. */ ON_SCOPE_EXIT { const auto category_span = category_entries.ToSpan(); for (const auto &entry : category_span) { if (erpt::srv::IsValidCategory(entry.category)) { static_cast<void>(Context::ClearContext(entry.category)); } } }; /* Create the report. */ R_TRY(this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, result, flags)); /* We succeeded. */ R_SUCCEED(); } Result ContextImpl::SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer) { R_UNLESS(ctx_entry.category_count <= CategoriesPerMultipleCategoryContext, erpt::ResultInvalidArgument()); const u8 *str = reinterpret_cast<const u8 *>(str_buffer.GetPointer()); const u32 str_size = static_cast<u32>(str_buffer.GetSize()); u32 total_field_count = 0, total_arr_count = 0; for (u32 i = 0; i < ctx_entry.category_count; i++) { ContextEntry entry = { .version = ctx_entry.version, .field_count = ctx_entry.field_counts[i], .category = ctx_entry.categories[i], }; R_UNLESS(entry.field_count <= erpt::FieldsPerContext, erpt::ResultInvalidArgument()); R_UNLESS(entry.field_count + total_field_count <= erpt::FieldsPerMultipleCategoryContext, erpt::ResultInvalidArgument()); R_UNLESS(ctx_entry.array_buf_counts[i] <= ArrayBufferSizeMax, erpt::ResultInvalidArgument()); R_UNLESS(ctx_entry.array_buf_counts[i] + total_arr_count <= str_size, erpt::ResultInvalidArgument()); std::memcpy(entry.fields, ctx_entry.fields + total_field_count, entry.field_count * sizeof(FieldEntry)); R_TRY(Context::SubmitContext(std::addressof(entry), str + total_arr_count, ctx_entry.array_buf_counts[i])); total_field_count += entry.field_count; total_arr_count += ctx_entry.array_buf_counts[i]; } R_SUCCEED(); } Result ContextImpl::SubmitMultipleContext(const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer) { R_RETURN(SubmitMultipleContextImpl(category_entries.ToSpan(), field_entries.ToSpan(), MakeSpan<const u8>(array_buffer.GetPointer(), array_buffer.GetSize()))); } Result ContextImpl::UpdateApplicationLaunchTime() { Reporter::UpdateApplicationLaunchTime(); R_SUCCEED(); } Result ContextImpl::ClearApplicationLaunchTime() { Reporter::ClearApplicationLaunchTime(); R_SUCCEED(); } Result ContextImpl::RegisterRunningApplicationInfo(ncm::ApplicationId app_id, ncm::ProgramId program_id) { Reporter::RegisterRunningApplicationInfo(app_id, program_id); R_SUCCEED(); } Result ContextImpl::UnregisterRunningApplicationInfo() { Reporter::UnregisterRunningApplicationInfo(); R_SUCCEED(); } Result ContextImpl::SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) { const char *name = reinterpret_cast<const char *>(attachment_name.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(attachment_data.GetPointer()); const u32 name_size = static_cast<u32>(attachment_name.GetSize()); const u32 data_size = static_cast<u32>(attachment_data.GetSize()); R_UNLESS(data != nullptr, erpt::ResultInvalidArgument()); R_UNLESS(data_size <= AttachmentSizeMax, erpt::ResultInvalidArgument()); R_UNLESS(name != nullptr, erpt::ResultInvalidArgument()); R_UNLESS(name_size <= AttachmentNameSizeMax, erpt::ResultInvalidArgument()); char name_safe[AttachmentNameSizeMax]; util::Strlcpy(name_safe, name, sizeof(name_safe)); R_RETURN(JournalForAttachments::SubmitAttachment(out.GetPointer(), name_safe, data, data_size)); } Result ContextImpl::SubmitAttachmentWithLz4Compression(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data) { /* TODO: Implement LZ4 compression on attachments. */ R_RETURN(this->SubmitAttachment(out, attachment_name, attachment_data)); } Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags) { const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize()); const u32 data_size = static_cast<u32>(data_buffer.GetSize()); const AttachmentId *attachments = reinterpret_cast<const AttachmentId *>(attachment_ids_buffer.GetPointer()); const u32 num_attachments = attachment_ids_buffer.GetSize() / sizeof(*attachments); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument()); R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, nullptr, attachments, num_attachments, flags, nullptr)); ManagerImpl::NotifyAll(); R_SUCCEED(); } Result ContextImpl::CreateReportWithAttachmentsDeprecated2(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result) { R_RETURN(this->CreateReportWithAttachments(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, result, erpt::srv::MakeNoCreateReportOptionFlags())); } Result ContextImpl::CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) { R_RETURN(this->CreateReportWithAttachmentsDeprecated2(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, ResultSuccess())); } Result ContextImpl::CreateReportWithSpecifiedReprotId(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags, const ReportId &report_id) { const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer()); const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer()); const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer()); const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize()); const u32 data_size = static_cast<u32>(data_buffer.GetSize()); const u32 meta_size = static_cast<u32>(meta_buffer.GetSize()); const AttachmentId *attachments = reinterpret_cast<const AttachmentId *>(attachment_ids_buffer.GetPointer()); const u32 num_attachments = attachment_ids_buffer.GetSize() / sizeof(*attachments); R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument()); R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument()); R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument()); R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, meta_size != 0 ? meta : nullptr, attachments, num_attachments, flags, std::addressof(report_id))); ManagerImpl::NotifyAll(); R_SUCCEED(); } Result ContextImpl::RegisterRunningApplet(ncm::ProgramId program_id) { R_RETURN(Reporter::RegisterRunningApplet(program_id)); } Result ContextImpl::UnregisterRunningApplet(ncm::ProgramId program_id) { R_RETURN(Reporter::UnregisterRunningApplet(program_id)); } Result ContextImpl::UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration) { R_RETURN(Reporter::UpdateAppletSuspendedDuration(program_id, duration)); } Result ContextImpl::InvalidateForcedShutdownDetection() { /* NOTE: Nintendo does not check the result here. */ static_cast<void>(erpt::srv::InvalidateForcedShutdownDetection()); R_SUCCEED(); } Result ContextImpl::WaitForReportCreation() { /* This function currently does nothing. Maybe it only waits on Ounce? */ R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class ContextImpl { public: Result SubmitContext(const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer); Result CreateReportV0(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer); Result SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point); Result ClearInitialLaunchSettingsCompletionTime(); Result UpdatePowerOnTime(); Result UpdateAwakeTime(); Result CreateReportWithAdditionalContext(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags, const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer); Result SubmitMultipleCategoryContext(const MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer); Result SubmitMultipleContext(const ams::sf::InMapAliasArray<erpt::CategoryEntry> &category_entries, const ams::sf::InMapAliasArray<erpt::FieldEntry> &field_entries, const ams::sf::InBuffer &array_buffer); Result UpdateApplicationLaunchTime(); Result RegisterRunningApplicationInfo(ncm::ApplicationId app_id, ncm::ProgramId program_id); Result ClearApplicationLaunchTime(); Result UnregisterRunningApplicationInfo(); Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data); Result CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer); Result CreateReportWithAttachmentsDeprecated2(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result); Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags); Result CreateReportV1(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result); Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags); Result SubmitAttachmentWithLz4Compression(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data); Result CreateReportWithSpecifiedReprotId(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, const ams::sf::InBuffer &attachment_data, Result result, erpt::CreateReportOptionFlagSet flags, const ReportId &report_id); Result RegisterRunningApplet(ncm::ProgramId program_id); Result UnregisterRunningApplet(ncm::ProgramId program_id); Result UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration); Result InvalidateForcedShutdownDetection(); Result WaitForReportCreation(); }; static_assert(erpt::sf::IsIContext<ContextImpl>); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_context_record.hpp" namespace ams::erpt::srv { constinit u32 ContextRecord::s_record_count = 0; namespace { bool IsArrayFieldType(FieldType type) { return type == FieldType_String || type == FieldType_U8Array || type == FieldType_U32Array || type == FieldType_U64Array || type == FieldType_I32Array || type == FieldType_I64Array; } } ContextRecord::ContextRecord() { m_ctx = {}; } ContextRecord::ContextRecord(CategoryId category, u32 array_buf_size) { m_ctx = { .category = category, .array_buffer = static_cast<u8 *>(Allocate(array_buf_size)), }; if (m_ctx.array_buffer != nullptr) { m_ctx.array_buffer_size = array_buf_size; m_ctx.array_free_count = array_buf_size; } } ContextRecord::~ContextRecord() { if (m_ctx.array_buffer != nullptr) { Deallocate(m_ctx.array_buffer); } AMS_ABORT_UNLESS(s_record_count >= m_ctx.field_count); s_record_count -= m_ctx.field_count; } Result ContextRecord::Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size) { R_UNLESS(data_size <= ArrayBufferSizeMax, erpt::ResultInvalidArgument()); m_ctx.version = ctx_ptr->version; m_ctx.field_count = ctx_ptr->field_count; m_ctx.category = ctx_ptr->category; m_ctx.array_buffer = nullptr; m_ctx.array_buffer_size = data_size; m_ctx.array_free_count = 0; auto guard = SCOPE_GUARD { m_ctx.field_count = 0; }; R_UNLESS(m_ctx.field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); R_UNLESS(FindCategoryIndex(m_ctx.category).has_value(), erpt::ResultInvalidArgument()); for (u32 i = 0; i < m_ctx.field_count; i++) { m_ctx.fields[i] = ctx_ptr->fields[i]; R_UNLESS(FindFieldIndex(m_ctx.fields[i].id).has_value(), erpt::ResultInvalidArgument()); R_UNLESS(0 <= m_ctx.fields[i].type && m_ctx.fields[i].type < FieldType_Count, erpt::ResultInvalidArgument()); R_UNLESS(m_ctx.fields[i].type == ConvertFieldToType(m_ctx.fields[i].id), erpt::ResultFieldTypeMismatch()); R_UNLESS(m_ctx.category == ConvertFieldToCategory(m_ctx.fields[i].id), erpt::ResultFieldCategoryMismatch()); if (IsArrayFieldType(m_ctx.fields[i].type)) { const u32 start_idx = m_ctx.fields[i].value_array.start_idx; const u32 size = m_ctx.fields[i].value_array.size; const u32 end_idx = start_idx + size; R_UNLESS(start_idx <= data_size, erpt::ResultInvalidArgument()); R_UNLESS(size <= data_size, erpt::ResultInvalidArgument()); R_UNLESS(end_idx <= data_size, erpt::ResultInvalidArgument()); R_UNLESS(size <= ArrayFieldSizeMax, erpt::ResultInvalidArgument()); } } if (data_size > 0) { /* If array buffer isn't nullptr, we'll leak memory here, so verify that it is. */ AMS_ABORT_UNLESS(m_ctx.array_buffer == nullptr); m_ctx.array_buffer = static_cast<u8 *>(AllocateWithAlign(data_size, alignof(u64))); R_UNLESS(m_ctx.array_buffer != nullptr, erpt::ResultOutOfMemory()); std::memcpy(m_ctx.array_buffer, data, data_size); } guard.Cancel(); s_record_count += m_ctx.field_count; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, bool value_bool) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = FieldType_Bool; field.value_bool = value_bool; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, u32 value_u32) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = FieldType_NumericU32; field.value_u32 = value_u32; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, u64 value_u64) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = FieldType_NumericU64; field.value_u64 = value_u64; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, s32 value_i32) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = FieldType_NumericI32; field.value_i32 = value_i32; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, s64 value_i64) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = FieldType_NumericI64; field.value_i64 = value_i64; R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, const void *arr, u32 size, FieldType type) { R_UNLESS(m_ctx.field_count < FieldsPerContext, erpt::ResultOutOfFieldSpace()); R_UNLESS(size <= m_ctx.array_free_count, erpt::ResultOutOfArraySpace()); const u32 start_idx = m_ctx.array_buffer_size - m_ctx.array_free_count; m_ctx.array_free_count -= size; s_record_count++; auto &field = m_ctx.fields[m_ctx.field_count++]; field.id = field_id; field.type = type; field.value_array = { .start_idx = start_idx, .size = size, }; std::memcpy(m_ctx.array_buffer + start_idx, arr, size); R_SUCCEED(); } Result ContextRecord::Add(FieldId field_id, const char *str, u32 str_size) { R_RETURN(this->Add(field_id, str, str_size, FieldType_String)); } Result ContextRecord::Add(FieldId field_id, const u8 *data, u32 size) { R_RETURN(this->Add(field_id, data, size, FieldType_U8Array)); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_context_record.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" namespace ams::erpt::srv { class Context; class ContextRecord : public Allocator { private: static u32 s_record_count; public: static u32 GetRecordCount() { return s_record_count; } private: ContextEntry m_ctx; private: Result Add(FieldId field_id, const void *arr, u32 size, FieldType type); public: ContextRecord(); explicit ContextRecord(CategoryId category, u32 array_buf_size = ArrayBufferSizeDefault); ~ContextRecord(); const ContextEntry *GetContextEntryPtr() const { return std::addressof(m_ctx); } Result Initialize(const ContextEntry *ctx_ptr, const u8 *data, u32 data_size); Result Add(FieldId field_id, bool value_bool); Result Add(FieldId field_id, u32 value_u32); Result Add(FieldId field_id, u64 value_u64); Result Add(FieldId field_id, s32 value_i32); Result Add(FieldId field_id, s64 value_i64); Result Add(FieldId field_id, const char *str, u32 str_size); Result Add(FieldId field_id, const u8 *data, u32 size); }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_forced_shutdown.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_forced_shutdown.hpp" #include "erpt_srv_context.hpp" #include "erpt_srv_context_record.hpp" #include "erpt_srv_reporter.hpp" #include "erpt_srv_stream.hpp" namespace ams::erpt::srv { namespace { constexpr u32 ForcedShutdownContextBufferSize = 1_KB; constexpr u32 ForcedShutdownContextVersion = 1; struct ForcedShutdownContextHeader { u32 version; u32 num_contexts; }; static_assert(sizeof(ForcedShutdownContextHeader) == 8); struct ForcedShutdownContextEntry { u32 version; CategoryId category; u32 field_count; u32 array_buffer_size; }; static_assert(sizeof(ForcedShutdownContextEntry) == 16); os::Event g_forced_shutdown_update_event(os::EventClearMode_ManualClear); constinit ContextEntry g_forced_shutdown_contexts[] = { { .category = CategoryId_RunningApplicationInfo, }, { .category = CategoryId_RunningAppletInfo, }, { .category = CategoryId_FocusedAppletHistoryInfo, }, }; bool IsForceShutdownDetected() { fs::DirectoryEntryType entry_type; return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), ForcedShutdownContextFileName)); } Result CreateForcedShutdownContext() { /* Create the context. */ { /* Create the stream. */ Stream stream; R_TRY(stream.OpenStream(ForcedShutdownContextFileName, StreamMode_Write, 0)); /* Write a context header. */ const ForcedShutdownContextHeader header = { .version = ForcedShutdownContextVersion, .num_contexts = 0, }; R_TRY(stream.WriteStream(reinterpret_cast<const u8 *>(std::addressof(header)), sizeof(header))); } /* Commit the context. */ R_TRY(Stream::CommitStream()); R_SUCCEED(); } Result CreateReportForForcedShutdown() { /* Create a new context record. */ /* NOTE: Nintendo does not check that this allocation succeeds. */ auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfo); /* Create error code for the report. */ char error_code_str[err::ErrorCode::StringLengthMax]; err::GetErrorCodeString(error_code_str, sizeof(error_code_str), err::ConvertResultToErrorCode(err::ResultForcedShutdownDetected())); /* Add error code to the context. */ R_TRY(record->Add(FieldId_ErrorCode, error_code_str, std::strlen(error_code_str))); /* Create report. */ R_TRY(Reporter::CreateReport(ReportType_Invisible, ResultSuccess(), std::move(record), nullptr, nullptr, 0, erpt::srv::MakeNoCreateReportOptionFlags(), nullptr)); R_SUCCEED(); } Result LoadForcedShutdownContext() { /* Create the stream to read the context. */ Stream stream; R_TRY(stream.OpenStream(ForcedShutdownContextFileName, StreamMode_Read, ForcedShutdownContextBufferSize)); /* Read the header. */ u32 read_size; ForcedShutdownContextHeader header; R_TRY(stream.ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(header)), sizeof(header))); /* Validate the header. */ R_SUCCEED_IF(read_size != sizeof(header)); R_SUCCEED_IF(ForcedShutdownContextVersion); R_SUCCEED_IF(header.num_contexts == 0); /* Read out the contexts. */ for (u32 i = 0; i < header.num_contexts; ++i) { /* Read the context entry header. */ ForcedShutdownContextEntry entry_header; R_TRY(stream.ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(entry_header)), sizeof(entry_header))); if (read_size != sizeof(entry_header)) { break; } if (entry_header.field_count == 0) { continue; } /* Read the saved data into a context entry. */ ContextEntry ctx = { .version = entry_header.version, .field_count = entry_header.field_count, .category = entry_header.category, }; /* Check that the field count is valid. */ AMS_ABORT_UNLESS(entry_header.field_count <= util::size(ctx.fields)); /* Read the fields. */ R_TRY(stream.ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(ctx.fields)), entry_header.field_count * sizeof(ctx.fields[0]))); if (read_size != entry_header.field_count * sizeof(ctx.fields[0])) { break; } /* Allocate an array buffer. */ u8 *array_buffer = static_cast<u8 *>(Allocate(entry_header.array_buffer_size)); if (array_buffer == nullptr) { break; } ON_SCOPE_EXIT { Deallocate(array_buffer); }; /* Read the array buffer data. */ R_TRY(stream.ReadStream(std::addressof(read_size), array_buffer, entry_header.array_buffer_size)); if (read_size != entry_header.array_buffer_size) { break; } /* Create a record for the context. */ auto record = std::make_unique<ContextRecord>(); if (record == nullptr) { break; } /* Initialize the record. */ R_TRY(record->Initialize(std::addressof(ctx), array_buffer, entry_header.array_buffer_size)); /* Submit the record. */ R_TRY(Context::SubmitContextRecord(std::move(record))); } R_SUCCEED(); } u32 GetForcedShutdownContextCount() { u32 count = 0; for (const auto &ctx : g_forced_shutdown_contexts) { if (ctx.field_count != 0) { ++count; } } return count; } Result SaveForcedShutdownContextImpl() { /* Save context to file. */ { /* Create the stream to write the context. */ Stream stream; R_TRY(stream.OpenStream(ForcedShutdownContextFileName, StreamMode_Write, ForcedShutdownContextBufferSize)); /* Write a context header. */ const ForcedShutdownContextHeader header = { .version = ForcedShutdownContextVersion, .num_contexts = GetForcedShutdownContextCount(), }; R_TRY(stream.WriteStream(reinterpret_cast<const u8 *>(std::addressof(header)), sizeof(header))); /* Write each context. */ for (const auto &ctx : g_forced_shutdown_contexts) { /* If the context has no fields, continue. */ if (ctx.field_count == 0) { continue; } /* Write a context entry header. */ const ForcedShutdownContextEntry entry_header = { .version = ctx.version, .category = ctx.category, .field_count = ctx.field_count, .array_buffer_size = ctx.array_buffer_size, }; R_TRY(stream.WriteStream(reinterpret_cast<const u8 *>(std::addressof(entry_header)), sizeof(entry_header))); /* Write all fields. */ for (u32 i = 0; i < ctx.field_count; ++i) { R_TRY(stream.WriteStream(reinterpret_cast<const u8 *>(ctx.fields + i), sizeof(ctx.fields[0]))); } /* Write the array buffer. */ R_TRY(stream.WriteStream(ctx.array_buffer, ctx.array_buffer_size)); } } /* Commit the context. */ R_TRY(Stream::CommitStream()); R_SUCCEED(); } } os::Event *GetForcedShutdownUpdateEvent() { return std::addressof(g_forced_shutdown_update_event); } void InitializeForcedShutdownDetection() { /* Check if the forced shutdown context exists; if it doesn't, we should create an empty one. */ if (!IsForceShutdownDetected()) { /* NOTE: Nintendo does not check result here. */ static_cast<void>(CreateForcedShutdownContext()); return; } /* Load the forced shutdown context. */ /* NOTE: Nintendo does not check that this succeeds. */ static_cast<void>(LoadForcedShutdownContext()); /* Create report for the forced shutdown. */ /* NOTE: Nintendo does not check that this succeeds. */ static_cast<void>(CreateReportForForcedShutdown()); /* Clear the forced shutdown categories. */ /* NOTE: Nintendo does not check that this succeeds. */ static_cast<void>(Context::ClearContext(CategoryId_RunningApplicationInfo)); static_cast<void>(Context::ClearContext(CategoryId_RunningAppletInfo)); static_cast<void>(Context::ClearContext(CategoryId_FocusedAppletHistoryInfo)); /* Save the forced shutdown context. */ /* NOTE: Nintendo does not check that this succeeds. */ static_cast<void>(SaveForcedShutdownContext()); } void FinalizeForcedShutdownDetection() { /* Try to delete the context. */ const Result result = Stream::DeleteStream(ForcedShutdownContextFileName); if (!fs::ResultPathNotFound::Includes(result)) { /* We must have succeeded, if the file existed. */ R_ABORT_UNLESS(result); /* Commit the deletion. */ R_ABORT_UNLESS(Stream::CommitStream()); } } void SaveForcedShutdownContext() { /* NOTE: Nintendo does not check that saving the report succeeds. */ static_cast<void>(SaveForcedShutdownContextImpl()); } void SubmitContextForForcedShutdownDetection(const ContextEntry *entry, const u8 *data, u32 data_size) { /* If the context entry matches one of our tracked categories, update our stored category. */ for (auto &ctx : g_forced_shutdown_contexts) { /* Check for a match. */ if (ctx.category != entry->category) { continue; } /* If we have an existing array buffer, free it. */ if (ctx.array_buffer != nullptr) { Deallocate(ctx.array_buffer); ctx.array_buffer = nullptr; ctx.array_buffer_size = 0; ctx.array_free_count = 0; } /* Copy in the context. */ ctx = *entry; /* Add the submitted data. */ if (data != nullptr && data_size > 0) { /* Allocate new array buffer. */ ctx.array_buffer = static_cast<u8 *>(Allocate(data_size)); if (ctx.array_buffer == nullptr) { /* We failed to allocate; this is okay, but clear our field count. */ ctx.field_count = 0; break; } /* Copy in the data. */ std::memcpy(ctx.array_buffer, data, data_size); /* Set buffer extents. */ ctx.array_buffer_size = data_size; ctx.array_free_count = 0; } else { ctx.array_buffer = nullptr; ctx.array_buffer_size = 0; ctx.array_free_count = 0; } /* Signal, to notify that we had an update. */ g_forced_shutdown_update_event.Signal(); /* We're done processing, since we found a match. */ break; } } Result InvalidateForcedShutdownDetection() { /* Delete the forced shutdown context. */ R_TRY(Stream::DeleteStream(ForcedShutdownContextFileName)); /* Commit the deletion. */ R_TRY(Stream::CommitStream()); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_forced_shutdown.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { os::Event *GetForcedShutdownUpdateEvent(); void InitializeForcedShutdownDetection(); void FinalizeForcedShutdownDetection(); void SaveForcedShutdownContext(); void SubmitContextForForcedShutdownDetection(const ContextEntry *entry, const u8 *data, u32 data_size); Result InvalidateForcedShutdownDetection(); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_formatter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_report.hpp" namespace ams::erpt::srv { class Formatter { private: enum ElementSize { ElementSize_16 = 16, ElementSize_32 = 32, ElementSize_256 = 256, ElementSize_16384 = 16384, }; private: static ValueTypeTag GetTag(s8) { return ValueTypeTag::I8; } static ValueTypeTag GetTag(s16) { return ValueTypeTag::I16; } static ValueTypeTag GetTag(s32) { return ValueTypeTag::I32; } static ValueTypeTag GetTag(s64) { return ValueTypeTag::I64; } static ValueTypeTag GetTag(u8) { return ValueTypeTag::U8; } static ValueTypeTag GetTag(u16) { return ValueTypeTag::U16; } static ValueTypeTag GetTag(u32) { return ValueTypeTag::U32; } static ValueTypeTag GetTag(u64) { return ValueTypeTag::U64; } static Result AddStringValue(Report *report, const char *str, u32 len) { const u32 str_len = str != nullptr ? static_cast<u32>(strnlen(str, len)) : 0; if (str_len < ElementSize_32) { R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixStr) | str_len))); } else if (str_len < ElementSize_256) { R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str8))); R_TRY(report->Write(static_cast<u8>(str_len))); } else { R_UNLESS(str_len < ElementSize_16384, erpt::ResultFormatterError()); R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Str16))); u16 be_str_len; util::StoreBigEndian(std::addressof(be_str_len), static_cast<u16>(str_len)); R_TRY(report->Write(be_str_len)); } R_TRY(report->Write(str, str_len)); R_SUCCEED(); } static Result AddId(Report *report, FieldId field_id) { static_assert(MaxFieldStringSize < ElementSize_256); const auto index = FindFieldIndex(field_id); AMS_ASSERT(index.has_value()); R_TRY(AddStringValue(report, FieldString[index.value()], strnlen(FieldString[index.value()], MaxFieldStringSize))); R_SUCCEED(); } template<typename T> static Result AddValue(Report *report, T value) { const u8 tag = static_cast<u8>(GetTag(value)); T big_endian_value; util::StoreBigEndian(std::addressof(big_endian_value), value); R_TRY(report->Write(tag)); R_TRY(report->Write(reinterpret_cast<u8 *>(std::addressof(big_endian_value)), sizeof(big_endian_value))); R_SUCCEED(); } template<typename T> static Result AddValueArray(Report *report, T *arr, u32 arr_size) { if (arr_size < ElementSize_16) { R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixArray) | arr_size))); } else { R_UNLESS(arr_size < ElementSize_16384, erpt::ResultFormatterError()); u16 be_arr_size; util::StoreBigEndian(std::addressof(be_arr_size), static_cast<u16>(arr_size)); R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Array16))); R_TRY(report->Write(be_arr_size)); } for (u32 i = 0; i < arr_size; i++) { R_TRY(AddValue(report, arr[i])); } R_SUCCEED(); } template<typename T> static Result AddIdValuePair(Report *report, FieldId field_id, T value) { R_TRY(AddId(report, field_id)); R_TRY(AddValue(report, value)); R_SUCCEED(); } template<typename T> static Result AddIdValueArray(Report *report, FieldId field_id, T *arr, u32 arr_size) { R_TRY(AddId(report, field_id)); R_TRY(AddValueArray(report, arr, arr_size)); R_SUCCEED(); } public: static Result Begin(Report *report, u32 record_count) { if (record_count < ElementSize_16) { R_TRY(report->Write(static_cast<u8>(static_cast<u8>(ValueTypeTag::FixMap) | record_count))); } else { R_UNLESS(record_count < ElementSize_16384, erpt::ResultFormatterError()); u16 be_count; util::StoreBigEndian(std::addressof(be_count), static_cast<u16>(record_count)); R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Map16))); R_TRY(report->Write(be_count)); } R_SUCCEED(); } static Result End(Report *report) { AMS_UNUSED(report); R_SUCCEED(); } template<typename T> static Result AddField(Report *report, FieldId field_id, T value) { R_RETURN(AddIdValuePair<T>(report, field_id, value)); } template<typename T> static Result AddField(Report *report, FieldId field_id, T *arr, u32 arr_size) { R_RETURN(AddIdValueArray(report, field_id, arr, arr_size)); } static Result AddField(Report *report, FieldId field_id, bool value) { R_TRY(AddId(report, field_id)); R_TRY(report->Write(static_cast<u8>(value ? ValueTypeTag::True : ValueTypeTag::False))); R_SUCCEED(); } static Result AddField(Report *report, FieldId field_id, char *str, u32 len) { R_TRY(AddId(report, field_id)); R_TRY(AddStringValue(report, str, len)); R_SUCCEED(); } static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) { R_TRY(AddId(report, field_id)); if (len < ElementSize_256) { R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Bin8))); R_TRY(report->Write(static_cast<u8>(len))); } else { R_UNLESS(len < ElementSize_16384, erpt::ResultFormatterError()); R_TRY(report->Write(static_cast<u8>(ValueTypeTag::Bin16))); u16 be_len; util::StoreBigEndian(std::addressof(be_len), static_cast<u16>(len)); R_TRY(report->Write(be_len)); } R_TRY(report->Write(bin, len)); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { Result SubmitFsInfo(); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_fs_info.os.horizon.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_fs_info.hpp" #include "erpt_srv_context_record.hpp" #include "erpt_srv_context.hpp" namespace ams::erpt::srv { namespace { Result SubmitMmcDetailInfo() { /* Submit the mmc cid. */ { u8 mmc_cid[fs::MmcCidSize] = {}; if (R_SUCCEEDED(fs::GetMmcCid(mmc_cid, sizeof(mmc_cid)))) { /* Clear the serial number from the cid. */ fs::ClearMmcCidSerialNumber(mmc_cid); /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDTypeInfo, sizeof(mmc_cid)); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add the cid. */ R_ABORT_UNLESS(record->Add(FieldId_NANDType, mmc_cid, sizeof(mmc_cid))); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } /* Submit the mmc speed mode. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDSpeedModeInfo, 0x20); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Get the speed mode. */ fs::MmcSpeedMode speed_mode{}; const auto res = fs::GetMmcSpeedMode(std::addressof(speed_mode)); if (R_SUCCEEDED(res)) { const char *speed_mode_name = "None"; switch (speed_mode) { case fs::MmcSpeedMode_Identification: speed_mode_name = "Identification"; break; case fs::MmcSpeedMode_LegacySpeed: speed_mode_name = "LegacySpeed"; break; case fs::MmcSpeedMode_HighSpeed: speed_mode_name = "HighSpeed"; break; case fs::MmcSpeedMode_Hs200: speed_mode_name = "Hs200"; break; case fs::MmcSpeedMode_Hs400: speed_mode_name = "Hs400"; break; case fs::MmcSpeedMode_Unknown: speed_mode_name = "Unknown"; break; default: speed_mode_name = "UnDefined"; break; } R_ABORT_UNLESS(record->Add(FieldId_NANDSpeedMode, speed_mode_name, std::strlen(speed_mode_name))); } else { /* Getting speed mode failed, so add the result. */ char res_str[0x20]; util::SNPrintf(res_str, sizeof(res_str), "0x%08X", res.GetValue()); R_ABORT_UNLESS(record->Add(FieldId_NANDSpeedMode, res_str, std::strlen(res_str))); } /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } /* Submit the mmc extended csd. */ { u8 mmc_csd[fs::MmcExtendedCsdSize] = {}; if (R_SUCCEEDED(fs::GetMmcExtendedCsd(mmc_csd, sizeof(mmc_csd)))) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDExtendedCsd, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields from the csd. */ R_ABORT_UNLESS(record->Add(FieldId_NANDPreEolInfo, static_cast<u32>(mmc_csd[fs::MmcExtendedCsdOffsetReEolInfo]))); R_ABORT_UNLESS(record->Add(FieldId_NANDDeviceLifeTimeEstTypA, static_cast<u32>(mmc_csd[fs::MmcExtendedCsdOffsetDeviceLifeTimeEstTypA]))); R_ABORT_UNLESS(record->Add(FieldId_NANDDeviceLifeTimeEstTypB, static_cast<u32>(mmc_csd[fs::MmcExtendedCsdOffsetDeviceLifeTimeEstTypB]))); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } /* Submit the mmc patrol count. */ { u32 count = 0; if (R_SUCCEEDED(fs::GetMmcPatrolCount(std::addressof(count)))) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDPatrolInfo, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add the count. */ R_ABORT_UNLESS(record->Add(FieldId_NANDPatrolCount, count)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } R_SUCCEED(); } Result SubmitMmcErrorInfo() { /* Get the mmc error info. */ fs::StorageErrorInfo sei = {}; char log_buffer[erpt::ArrayBufferSizeDefault] = {}; size_t log_size = 0; if (R_SUCCEEDED(fs::GetAndClearMmcErrorInfo(std::addressof(sei), std::addressof(log_size), log_buffer, sizeof(log_buffer)))) { /* Submit the error info. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDErrorInfo, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_NANDNumActivationFailures, sei.num_activation_failures)); R_ABORT_UNLESS(record->Add(FieldId_NANDNumActivationErrorCorrections, sei.num_activation_error_corrections)); R_ABORT_UNLESS(record->Add(FieldId_NANDNumReadWriteFailures, sei.num_read_write_failures)); R_ABORT_UNLESS(record->Add(FieldId_NANDNumReadWriteErrorCorrections, sei.num_read_write_error_corrections)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } /* If we have a log, submit it. */ if (log_size > 0) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_NANDDriverLog, log_size); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_NANDErrorLog, log_buffer, log_size)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } R_SUCCEED(); } Result SubmitSdCardDetailInfo() { /* Submit the sd card cid. */ { u8 sd_cid[fs::SdCardCidSize] = {}; if (R_SUCCEEDED(fs::GetSdCardCid(sd_cid, sizeof(sd_cid)))) { /* Clear the serial number from the cid. */ fs::ClearSdCardCidSerialNumber(sd_cid); /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_MicroSDTypeInfo, sizeof(sd_cid)); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add the cid. */ R_ABORT_UNLESS(record->Add(FieldId_MicroSDType, sd_cid, sizeof(sd_cid))); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } /* Submit the sd card speed mode. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_MicroSDSpeedModeInfo, 0x20); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Get the speed mode. */ fs::SdCardSpeedMode speed_mode{}; const auto res = fs::GetSdCardSpeedMode(std::addressof(speed_mode)); if (R_SUCCEEDED(res)) { const char *speed_mode_name = "None"; switch (speed_mode) { case fs::SdCardSpeedMode_Identification: speed_mode_name = "Identification"; break; case fs::SdCardSpeedMode_DefaultSpeed: speed_mode_name = "DefaultSpeed"; break; case fs::SdCardSpeedMode_HighSpeed: speed_mode_name = "HighSpeed"; break; case fs::SdCardSpeedMode_Sdr12: speed_mode_name = "Sdr12"; break; case fs::SdCardSpeedMode_Sdr25: speed_mode_name = "Sdr25"; break; case fs::SdCardSpeedMode_Sdr50: speed_mode_name = "Sdr50"; break; case fs::SdCardSpeedMode_Sdr104: speed_mode_name = "Sdr104"; break; case fs::SdCardSpeedMode_Ddr50: speed_mode_name = "Ddr50"; break; case fs::SdCardSpeedMode_Unknown: speed_mode_name = "Unknown"; break; default: speed_mode_name = "UnDefined"; break; } R_ABORT_UNLESS(record->Add(FieldId_MicroSDSpeedMode, speed_mode_name, std::strlen(speed_mode_name))); } else { /* Getting speed mode failed, so add the result. */ char res_str[0x20]; util::SNPrintf(res_str, sizeof(res_str), "0x%08X", res.GetValue()); R_ABORT_UNLESS(record->Add(FieldId_MicroSDSpeedMode, res_str, std::strlen(res_str))); } /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } /* Submit the area sizes. */ { s64 user_area_size = 0; s64 prot_area_size = 0; const Result res_user = fs::GetSdCardUserAreaSize(std::addressof(user_area_size)); const Result res_prot = fs::GetSdCardProtectedAreaSize(std::addressof(prot_area_size)); if (R_SUCCEEDED(res_user) || R_SUCCEEDED(res_prot)) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_SdCardSizeSpec, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add sizes. */ if (R_SUCCEEDED(res_user)) { R_ABORT_UNLESS(record->Add(FieldId_SdCardUserAreaSize, user_area_size)); } if (R_SUCCEEDED(res_prot)) { R_ABORT_UNLESS(record->Add(FieldId_SdCardProtectedAreaSize, prot_area_size)); } /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } R_SUCCEED(); } Result SubmitSdCardErrorInfo() { /* Get the sd card error info. */ fs::StorageErrorInfo sei = {}; char log_buffer[erpt::ArrayBufferSizeDefault] = {}; size_t log_size = 0; if (R_SUCCEEDED(fs::GetAndClearSdCardErrorInfo(std::addressof(sei), std::addressof(log_size), log_buffer, sizeof(log_buffer)))) { /* Submit the error info. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_SdCardErrorInfo, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_SdCardNumActivationFailures, sei.num_activation_failures)); R_ABORT_UNLESS(record->Add(FieldId_SdCardNumActivationErrorCorrections, sei.num_activation_error_corrections)); R_ABORT_UNLESS(record->Add(FieldId_SdCardNumReadWriteFailures, sei.num_read_write_failures)); R_ABORT_UNLESS(record->Add(FieldId_SdCardNumReadWriteErrorCorrections, sei.num_read_write_error_corrections)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } /* If we have a log, submit it. */ if (log_size > 0) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_SdCardDriverLog, log_size); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_SdCardErrorLog, log_buffer, log_size)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } R_SUCCEED(); } Result SubmitGameCardDetailInfo() { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_GameCardCIDInfo, fs::GameCardCidSize + fs::GameCardDeviceIdSize); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add the game card cid. */ { u8 gc_cid[fs::GameCardCidSize] = {}; if (fs::IsGameCardInserted() && R_SUCCEEDED(fs::GetGameCardCid(gc_cid, sizeof(gc_cid)))) { /* Add the cid. */ R_ABORT_UNLESS(record->Add(FieldId_GameCardCID, gc_cid, sizeof(gc_cid))); } } /* Add the game card device id. */ { u8 gc_device_id[fs::GameCardDeviceIdSize] = {}; if (fs::IsGameCardInserted() && R_SUCCEEDED(fs::GetGameCardDeviceId(gc_device_id, sizeof(gc_device_id)))) { /* Add the cid. */ R_ABORT_UNLESS(record->Add(FieldId_GameCardDeviceId, gc_device_id, sizeof(gc_device_id))); } } /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); R_SUCCEED(); } Result SubmitGameCardErrorInfo() { /* Get the game card error info. */ fs::GameCardErrorReportInfo ei = {}; if (R_SUCCEEDED(fs::GetGameCardErrorReportInfo(std::addressof(ei)))) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_GameCardErrorInfo, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_GameCardCrcErrorCount, static_cast<u32>(ei.game_card_crc_error_num))); R_ABORT_UNLESS(record->Add(FieldId_GameCardAsicCrcErrorCount, static_cast<u32>(ei.asic_crc_error_num))); R_ABORT_UNLESS(record->Add(FieldId_GameCardRefreshCount, static_cast<u32>(ei.refresh_num))); R_ABORT_UNLESS(record->Add(FieldId_GameCardReadRetryCount, static_cast<u32>(ei.retry_limit_out_num))); R_ABORT_UNLESS(record->Add(FieldId_GameCardTimeoutRetryErrorCount, static_cast<u32>(ei.timeout_retry_num))); R_ABORT_UNLESS(record->Add(FieldId_GameCardInsertionCount, static_cast<u32>(ei.insertion_count))); R_ABORT_UNLESS(record->Add(FieldId_GameCardRemovalCount, static_cast<u32>(ei.removal_count))); R_ABORT_UNLESS(record->Add(FieldId_GameCardAsicInitializeCount, ei.initialize_count)); R_ABORT_UNLESS(record->Add(FieldId_GameCardAsicReinitializeCount, ei.asic_reinitialize_num)); R_ABORT_UNLESS(record->Add(FieldId_GameCardAsicReinitializeFailureCount, ei.asic_reinitialize_failure_num)); R_ABORT_UNLESS(record->Add(FieldId_GameCardAsicReinitializeFailureDetail, ei.asic_reinitialize_failure_detail)); R_ABORT_UNLESS(record->Add(FieldId_GameCardRefreshSuccessCount, ei.refresh_succeeded_count)); R_ABORT_UNLESS(record->Add(FieldId_GameCardAwakenCount, ei.awaken_count)); R_ABORT_UNLESS(record->Add(FieldId_GameCardAwakenFailureCount, ei.awaken_failure_num)); R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromInsert, ei.read_count_from_insert)); R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address)); R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } R_SUCCEED(); } Result SubmitFileSystemErrorInfo() { /* Get the fsp error info. */ fs::FileSystemProxyErrorInfo ei = {}; if (R_SUCCEEDED(fs::GetAndClearFileSystemProxyErrorInfo(std::addressof(ei)))) { /* Submit FsProxyErrorInfo. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_FsProxyErrorInfo, fat::FatErrorNameMaxLength); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_FsRemountForDataCorruptCount, ei.rom_fs_remount_for_data_corruption_count)); R_ABORT_UNLESS(record->Add(FieldId_FsRemountForDataCorruptRetryOutCount, ei.rom_fs_unrecoverable_data_corruption_by_remount_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsError, ei.fat_fs_error.error)); R_ABORT_UNLESS(record->Add(FieldId_FatFsExtraError, ei.fat_fs_error.extra_error)); R_ABORT_UNLESS(record->Add(FieldId_FatFsErrorDrive, ei.fat_fs_error.drive_id)); R_ABORT_UNLESS(record->Add(FieldId_FatFsErrorName, ei.fat_fs_error.name, fat::FatErrorNameMaxLength)); R_ABORT_UNLESS(record->Add(FieldId_FsRecoveredByInvalidateCacheCount, ei.rom_fs_recovered_by_invalidate_cache_count)); R_ABORT_UNLESS(record->Add(FieldId_FsSaveDataIndexCount, ei.save_data_index_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemFilePeakOpenCount, ei.bis_system_fat_report_info_1.open_file_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemDirectoryPeakOpenCount, ei.bis_system_fat_report_info_1.open_directory_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserFilePeakOpenCount, ei.bis_user_fat_report_info_1.open_file_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserDirectoryPeakOpenCount, ei.bis_user_fat_report_info_1.open_directory_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsSdCardFilePeakOpenCount, ei.sd_card_fat_report_info_1.open_file_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsSdCardDirectoryPeakOpenCount, ei.sd_card_fat_report_info_1.open_directory_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemUniqueFileEntryPeakOpenCount, ei.bis_system_fat_report_info_2.open_unique_file_entry_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemUniqueDirectoryEntryPeakOpenCount, ei.bis_system_fat_report_info_2.open_unique_directory_entry_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserUniqueFileEntryPeakOpenCount, ei.bis_user_fat_report_info_2.open_unique_file_entry_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserUniqueDirectoryEntryPeakOpenCount, ei.bis_user_fat_report_info_2.open_unique_directory_entry_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsSdCardUniqueFileEntryPeakOpenCount, ei.sd_card_fat_report_info_2.open_unique_file_entry_peak_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsSdCardUniqueDirectoryEntryPeakOpenCount, ei.sd_card_fat_report_info_2.open_unique_directory_entry_peak_count)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } /* Submit FsProxyErrorInfo2. */ { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_FsProxyErrorInfo2, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_FsDeepRetryStartCount, ei.rom_fs_deep_retry_start_count)); R_ABORT_UNLESS(record->Add(FieldId_FsUnrecoverableByGameCardAccessFailedCount, ei.rom_fs_unrecoverable_by_game_card_access_failed_count)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemFatSafeControlResult, static_cast<u8>(ei.bis_system_fat_safe_info.result))); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemFatErrorNumber, ei.bis_system_fat_safe_info.error_number)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisSystemFatSafeErrorNumber, ei.bis_system_fat_safe_info.safe_error_number)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserFatSafeControlResult, static_cast<u8>(ei.bis_user_fat_safe_info.result))); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserFatErrorNumber, ei.bis_user_fat_safe_info.error_number)); R_ABORT_UNLESS(record->Add(FieldId_FatFsBisUserFatSafeErrorNumber, ei.bis_user_fat_safe_info.safe_error_number)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } } R_SUCCEED(); } Result SubmitMemoryReportInfo() { /* Get the memory report info. */ fs::MemoryReportInfo mri = {}; if (R_SUCCEEDED(fs::GetAndClearMemoryReportInfo(std::addressof(mri)))) { /* Create a record. */ auto record = std::make_unique<ContextRecord>(CategoryId_FsMemoryInfo, 0); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Add fields. */ R_ABORT_UNLESS(record->Add(FieldId_FsPooledBufferPeakFreeSize, mri.pooled_buffer_peak_free_size)); R_ABORT_UNLESS(record->Add(FieldId_FsPooledBufferRetriedCount, mri.pooled_buffer_retried_count)); R_ABORT_UNLESS(record->Add(FieldId_FsPooledBufferReduceAllocationCount, mri.pooled_buffer_reduce_allocation_count)); R_ABORT_UNLESS(record->Add(FieldId_FsBufferManagerPeakFreeSize, mri.buffer_manager_peak_free_size)); R_ABORT_UNLESS(record->Add(FieldId_FsBufferManagerRetriedCount, mri.buffer_manager_retried_count)); R_ABORT_UNLESS(record->Add(FieldId_FsExpHeapPeakFreeSize, mri.exp_heap_peak_free_size)); R_ABORT_UNLESS(record->Add(FieldId_FsBufferPoolPeakFreeSize, mri.buffer_pool_peak_free_size)); R_ABORT_UNLESS(record->Add(FieldId_FsPatrolReadAllocateBufferSuccessCount, mri.patrol_read_allocate_buffer_success_count)); R_ABORT_UNLESS(record->Add(FieldId_FsPatrolReadAllocateBufferFailureCount, mri.patrol_read_allocate_buffer_failure_count)); R_ABORT_UNLESS(record->Add(FieldId_FsBufferManagerPeakTotalAllocatableSize, mri.buffer_manager_peak_total_allocatable_size)); R_ABORT_UNLESS(record->Add(FieldId_FsBufferPoolMaxAllocateSize, mri.buffer_pool_max_allocate_size)); R_ABORT_UNLESS(record->Add(FieldId_FsPooledBufferFailedIdealAllocationCountOnAsyncAccess, mri.pooled_buffer_failed_ideal_allocation_count_on_async_access)); /* Submit the record. */ R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record))); } R_SUCCEED(); } } Result SubmitFsInfo() { /* Temporarily disable auto-abort. */ fs::ScopedAutoAbortDisabler aad; /* Submit various FS info. */ R_TRY(SubmitMmcDetailInfo()); R_TRY(SubmitMmcErrorInfo()); R_TRY(SubmitSdCardDetailInfo()); R_TRY(SubmitSdCardErrorInfo()); R_TRY(SubmitGameCardDetailInfo()); R_TRY(SubmitGameCardErrorInfo()); R_TRY(SubmitFileSystemErrorInfo()); R_TRY(SubmitMemoryReportInfo()); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_journal.hpp" namespace ams::erpt::srv { void Journal::CleanupAttachments() { return JournalForAttachments::CleanupAttachments(); } void Journal::CleanupReports() { return JournalForReports::CleanupReports(); } Result Journal::Commit() { /* Open the stream. */ Stream stream; R_TRY(stream.OpenStream(JournalFileName, StreamMode_Write, JournalStreamBufferSize)); /* Commit the reports. */ R_TRY(JournalForReports::CommitJournal(std::addressof(stream))); /* Commit the meta. */ R_TRY(JournalForMeta::CommitJournal(std::addressof(stream))); /* Commit the attachments. */ R_TRY(JournalForAttachments::CommitJournal(std::addressof(stream))); /* Close and commit the stream. */ stream.CloseStream(); R_TRY(stream.CommitStream()); R_SUCCEED(); } Result Journal::Delete(ReportId report_id) { R_RETURN(JournalForReports::DeleteReport(report_id)); } Result Journal::GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id) { R_RETURN(JournalForAttachments::GetAttachmentList(out_count, out_infos, max_out_infos, report_id)); } util::Uuid Journal::GetJournalId() { return JournalForMeta::GetJournalId(); } s64 Journal::GetMaxReportSize() { return JournalForReports::GetMaxReportSize(); } Result Journal::GetReportList(ReportList *out, ReportType type_filter) { R_RETURN(JournalForReports::GetReportList(out, type_filter)); } u32 Journal::GetStoredReportCount(ReportType type) { return JournalForReports::GetStoredReportCount(type); } u32 Journal::GetTransmittedCount(ReportType type) { return JournalForMeta::GetTransmittedCount(type); } u32 Journal::GetUntransmittedCount(ReportType type) { return JournalForMeta::GetUntransmittedCount(type); } u32 Journal::GetUsedStorage() { return JournalForReports::GetUsedStorage() + JournalForAttachments::GetUsedStorage(); } Result Journal::Restore() { /* Open the stream. */ Stream stream; R_TRY(stream.OpenStream(JournalFileName, StreamMode_Read, JournalStreamBufferSize)); /* Restore the reports. */ R_TRY(JournalForReports::RestoreJournal(std::addressof(stream))); /* Restore the meta. */ R_TRY(JournalForMeta::RestoreJournal(std::addressof(stream))); /* Restore the attachments. */ R_TRY(JournalForAttachments::RestoreJournal(std::addressof(stream))); R_SUCCEED(); } JournalRecord<ReportInfo> *Journal::Retrieve(ReportId report_id) { return JournalForReports::RetrieveRecord(report_id); } JournalRecord<AttachmentInfo> *Journal::Retrieve(AttachmentId attachment_id) { return JournalForAttachments::RetrieveRecord(attachment_id); } Result Journal::Store(JournalRecord<ReportInfo> *record) { R_RETURN(JournalForReports::StoreRecord(record)); } Result Journal::Store(JournalRecord<AttachmentInfo> *record) { R_RETURN(JournalForAttachments::StoreRecord(record)); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_ref_count.hpp" #include "erpt_srv_journal_record.hpp" #include "erpt_srv_stream.hpp" namespace ams::erpt::srv { constexpr inline s32 JournalVersion = 1; constexpr inline u32 JournalStreamBufferSize = 4_KB; struct JournalMeta { s32 version; u32 transmitted_count[ReportType_Count]; u32 untransmitted_count[ReportType_Count]; util::Uuid journal_id; u32 reserved[4]; }; static_assert(sizeof(JournalMeta) == 0x34); class JournalForMeta { private: static JournalMeta s_journal_meta; public: static void InitializeJournal(); static Result CommitJournal(Stream *stream); static Result RestoreJournal(Stream *stream); static u32 GetTransmittedCount(ReportType type); static u32 GetUntransmittedCount(ReportType type); static void IncrementCount(bool transmitted, ReportType type); static util::Uuid GetJournalId(); }; class JournalForReports { private: using RecordListType = util::IntrusiveListBaseTraits<JournalRecord<ReportInfo>>::ListType; static RecordListType s_record_list; static u32 s_record_count; static u32 s_record_count_by_type[ReportType_Count]; static u32 s_used_storage; private: static void EraseReportImpl(JournalRecord<ReportInfo> *record, bool increment_count, bool force_delete_attachments); public: static void CleanupReports(); static Result CommitJournal(Stream *stream); static Result DeleteReport(ReportId report_id); static Result DeleteReportWithAttachments(); static s64 GetMaxReportSize(); static Result GetReportList(ReportList *out, ReportType type_filter); static u32 GetStoredReportCount(ReportType type); static u32 GetUsedStorage(); static Result RestoreJournal(Stream *stream); static JournalRecord<ReportInfo> *RetrieveRecord(ReportId report_id); static Result StoreRecord(JournalRecord<ReportInfo> *record); }; class JournalForAttachments { private: using AttachmentListType = util::IntrusiveListBaseTraits<JournalRecord<AttachmentInfo>>::ListType; static AttachmentListType s_attachment_list; static u32 s_attachment_count; static u32 s_used_storage; public: static void CleanupAttachments(); static Result CommitJournal(Stream *stream); static Result DeleteAttachments(ReportId report_id); static Result GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id); static u32 GetUsedStorage(); static Result RestoreJournal(Stream *stream); static JournalRecord<AttachmentInfo> *RetrieveRecord(AttachmentId attachment_id); static Result SetOwner(AttachmentId attachment_id, ReportId report_id); static Result StoreRecord(JournalRecord<AttachmentInfo> *record); static Result SubmitAttachment(AttachmentId *out, char *name, const u8 *data, u32 data_size); }; class Journal { public: static void CleanupAttachments(); static void CleanupReports(); static Result Commit(); static Result Delete(ReportId report_id); static Result GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id); static util::Uuid GetJournalId(); static s64 GetMaxReportSize(); static Result GetReportList(ReportList *out, ReportType type_filter); static u32 GetStoredReportCount(ReportType type); static u32 GetTransmittedCount(ReportType type); static u32 GetUntransmittedCount(ReportType type); static u32 GetUsedStorage(); static Result Restore(); static JournalRecord<ReportInfo> *Retrieve(ReportId report_id); static JournalRecord<AttachmentInfo> *Retrieve(AttachmentId attachment_id); static Result Store(JournalRecord<ReportInfo> *record); static Result Store(JournalRecord<AttachmentInfo> *record); }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_attachments.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_journal.hpp" #include "erpt_srv_attachment.hpp" namespace ams::erpt::srv { constinit util::IntrusiveListBaseTraits<JournalRecord<AttachmentInfo>>::ListType JournalForAttachments::s_attachment_list; constinit u32 JournalForAttachments::s_attachment_count = 0; constinit u32 JournalForAttachments::s_used_storage = 0; namespace { constexpr inline u32 AttachmentUsedStorageMax = 4_MB; } void JournalForAttachments::CleanupAttachments() { for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); /* ... */) { auto *record = std::addressof(*it); it = s_attachment_list.erase(s_attachment_list.iterator_to(*record)); if (record->RemoveReference()) { if (R_FAILED(Stream::DeleteStream(Attachment::FileName(record->m_info.attachment_id).name))) { /* TODO: Log failure? */ } delete record; } } AMS_ASSERT(s_attachment_list.empty()); s_attachment_count = 0; s_used_storage = 0; } Result JournalForAttachments::CommitJournal(Stream *stream) { R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_attachment_count)), sizeof(s_attachment_count))); for (auto it = s_attachment_list.crbegin(); it != s_attachment_list.crend(); it++) { R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(it->m_info)), sizeof(it->m_info))); } R_SUCCEED(); } Result JournalForAttachments::DeleteAttachments(ReportId report_id) { for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); /* ... */) { auto *record = std::addressof(*it); if (record->m_info.owner_report_id == report_id) { /* Erase from the list. */ it = s_attachment_list.erase(s_attachment_list.iterator_to(*record)); /* Update storage tracking counts. */ --s_attachment_count; s_used_storage -= static_cast<u32>(record->m_info.attachment_size); /* Delete the object, if we should. */ if (record->RemoveReference()) { const auto delete_res = Stream::DeleteStream(Attachment::FileName(record->m_info.attachment_id).name); R_ASSERT(delete_res); AMS_UNUSED(delete_res); delete record; } } else { /* Not attached, just advance. */ it++; } } R_SUCCEED(); } Result JournalForAttachments::GetAttachmentList(u32 *out_count, AttachmentInfo *out_infos, size_t max_out_infos, ReportId report_id) { if (hos::GetVersion() >= hos::Version_20_0_0) { /* TODO: What define gives a minimum of 10? */ R_UNLESS(max_out_infos >= 10, erpt::ResultInvalidArgument()); } u32 count = 0; for (auto it = s_attachment_list.cbegin(); it != s_attachment_list.cend() && count < max_out_infos; it++) { if (report_id == it->m_info.owner_report_id) { out_infos[count++] = it->m_info; } } *out_count = count; R_SUCCEED(); } u32 JournalForAttachments::GetUsedStorage() { return s_used_storage; } Result JournalForAttachments::RestoreJournal(Stream *stream) { /* Clear the used storage. */ s_used_storage = 0; /* Read the count from storage. */ u32 read_size; u32 count; R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(count)), sizeof(count))); R_UNLESS(read_size == sizeof(count), erpt::ResultCorruptJournal()); R_UNLESS(count <= AttachmentCountMax, erpt::ResultCorruptJournal()); /* If we fail in the middle of reading reports, we want to do cleanup. */ auto cleanup_guard = SCOPE_GUARD { CleanupAttachments(); }; AttachmentInfo info; for (u32 i = 0; i < count; i++) { R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(info)), sizeof(info))); R_UNLESS(read_size == sizeof(info), erpt::ResultCorruptJournal()); auto *record = new JournalRecord<AttachmentInfo>(info); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); auto record_guard = SCOPE_GUARD { delete record; }; if (R_FAILED(Stream::GetStreamSize(std::addressof(record->m_info.attachment_size), Attachment::FileName(record->m_info.attachment_id).name))) { continue; } if (record->m_info.flags.Test<AttachmentFlag::HasOwner>() && JournalForReports::RetrieveRecord(record->m_info.owner_report_id) != nullptr) { record_guard.Cancel(); R_TRY(StoreRecord(record)); } else { /* If the attachment has no owner (or we deleted the report), delete the file associated with it. */ const auto delete_res = Stream::DeleteStream(Attachment::FileName(record->m_info.attachment_id).name); R_ASSERT(delete_res); AMS_UNUSED(delete_res); } } cleanup_guard.Cancel(); R_SUCCEED(); } JournalRecord<AttachmentInfo> *JournalForAttachments::RetrieveRecord(AttachmentId attachment_id) { for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) { if (auto *record = std::addressof(*it); record->m_info.attachment_id == attachment_id) { return record; } } return nullptr; } Result JournalForAttachments::SetOwner(AttachmentId attachment_id, ReportId report_id) { for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) { auto *record = std::addressof(*it); if (record->m_info.attachment_id == attachment_id) { R_UNLESS(!record->m_info.flags.Test<AttachmentFlag::HasOwner>(), erpt::ResultAlreadyOwned()); record->m_info.owner_report_id = report_id; record->m_info.flags.Set<AttachmentFlag::HasOwner>(); R_SUCCEED(); } } R_THROW(erpt::ResultInvalidArgument()); } Result JournalForAttachments::StoreRecord(JournalRecord<AttachmentInfo> *record) { /* Check if the record already exists. */ for (auto it = s_attachment_list.begin(); it != s_attachment_list.end(); it++) { R_UNLESS(it->m_info.attachment_id != record->m_info.attachment_id, erpt::ResultAlreadyExists()); } /* Add a reference to the new record. */ record->AddReference(); /* Push the record into the list. */ s_attachment_list.push_front(*record); s_attachment_count++; s_used_storage += static_cast<u32>(record->m_info.attachment_size); R_SUCCEED(); } Result JournalForAttachments::SubmitAttachment(AttachmentId *out, char *name, const u8 *data, u32 data_size) { R_UNLESS(data_size > 0, erpt::ResultInvalidArgument()); R_UNLESS(data_size < AttachmentSizeMax, erpt::ResultInvalidArgument()); const auto name_len = std::strlen(name); R_UNLESS(name_len < AttachmentNameSizeMax, erpt::ResultInvalidArgument()); /* Ensure that we have free space. */ while (s_used_storage > AttachmentUsedStorageMax) { R_TRY(JournalForReports::DeleteReportWithAttachments()); } AttachmentInfo info; info.attachment_id.uuid = util::GenerateUuid(); info.flags = erpt::srv::MakeNoAttachmentFlags(); info.attachment_size = data_size; util::Strlcpy(info.attachment_name, name, sizeof(info.attachment_name)); auto *record = new JournalRecord<AttachmentInfo>(info); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); record->AddReference(); ON_SCOPE_EXIT { if (record->RemoveReference()) { delete record; } }; { auto attachment = std::make_unique<Attachment>(record); R_UNLESS(attachment != nullptr, erpt::ResultOutOfMemory()); R_TRY(attachment->Open(AttachmentOpenType_Create)); ON_SCOPE_EXIT { attachment->Close(); }; R_TRY(attachment->Write(data, data_size)); R_TRY(StoreRecord(record)); } *out = info.attachment_id; R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_meta.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_journal.hpp" namespace ams::erpt::srv { constinit JournalMeta JournalForMeta::s_journal_meta = {}; void JournalForMeta::InitializeJournal() { std::memset(std::addressof(s_journal_meta), 0, sizeof(s_journal_meta)); s_journal_meta.journal_id = util::GenerateUuid(); s_journal_meta.version = JournalVersion; } Result JournalForMeta::CommitJournal(Stream *stream) { R_RETURN(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_journal_meta)), sizeof(s_journal_meta))); } Result JournalForMeta::RestoreJournal(Stream *stream) { u32 size; if (R_FAILED(stream->ReadStream(std::addressof(size), reinterpret_cast<u8 *>(std::addressof(s_journal_meta)), sizeof(s_journal_meta))) || size != sizeof(s_journal_meta)) { InitializeJournal(); } R_SUCCEED(); } u32 JournalForMeta::GetTransmittedCount(ReportType type) { if (ReportType_Start <= type && type < ReportType_End) { return s_journal_meta.transmitted_count[type]; } else { return 0; } } u32 JournalForMeta::GetUntransmittedCount(ReportType type) { if (ReportType_Start <= type && type < ReportType_End) { return s_journal_meta.untransmitted_count[type]; } else { return 0; } } void JournalForMeta::IncrementCount(bool transmitted, ReportType type) { if (ReportType_Start <= type && type < ReportType_End) { if (transmitted) { s_journal_meta.transmitted_count[type]++; } else { s_journal_meta.untransmitted_count[type]++; } } } util::Uuid JournalForMeta::GetJournalId() { return s_journal_meta.journal_id; } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_for_reports.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_journal.hpp" #include "erpt_srv_report.hpp" namespace ams::erpt::srv { constinit util::IntrusiveListBaseTraits<JournalRecord<ReportInfo>>::ListType JournalForReports::s_record_list; constinit u32 JournalForReports::s_record_count = 0; constinit u32 JournalForReports::s_record_count_by_type[ReportType_Count] = {}; constinit u32 JournalForReports::s_used_storage = 0; void JournalForReports::CleanupReports() { for (auto it = s_record_list.begin(); it != s_record_list.end(); /* ... */) { auto *record = std::addressof(*it); it = s_record_list.erase(s_record_list.iterator_to(*record)); if (record->RemoveReference()) { if (R_FAILED(Stream::DeleteStream(Report::FileName(record->m_info.id, false).name))) { /* TODO: Log failure? */ } delete record; } } AMS_ASSERT(s_record_list.empty()); s_record_count = 0; s_used_storage = 0; std::memset(s_record_count_by_type, 0, sizeof(s_record_count_by_type)); } Result JournalForReports::CommitJournal(Stream *stream) { R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(s_record_count)), sizeof(s_record_count))); for (auto it = s_record_list.crbegin(); it != s_record_list.crend(); it++) { R_TRY(stream->WriteStream(reinterpret_cast<const u8 *>(std::addressof(it->m_info)), sizeof(it->m_info))); } R_SUCCEED(); } void JournalForReports::EraseReportImpl(JournalRecord<ReportInfo> *record, bool increment_count, bool force_delete_attachments) { /* Erase from the list. */ s_record_list.erase(s_record_list.iterator_to(*record)); /* Update storage tracking counts. */ --s_record_count; --s_record_count_by_type[record->m_info.type]; s_used_storage -= static_cast<u32>(record->m_info.report_size); /* If we should increment count, do so. */ if (increment_count) { JournalForMeta::IncrementCount(record->m_info.flags.Test<ReportFlag::Transmitted>(), record->m_info.type); } /* Delete any attachments. */ if (force_delete_attachments || record->m_info.flags.Test<ReportFlag::HasAttachment>()) { static_cast<void>(JournalForAttachments::DeleteAttachments(record->m_info.id)); } /* Delete the object, if we should. */ if (record->RemoveReference()) { const auto delete_res = Stream::DeleteStream(Report::FileName(record->m_info.id, false).name); R_ASSERT(delete_res); AMS_UNUSED(delete_res); delete record; } } Result JournalForReports::DeleteReport(ReportId report_id) { for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) { auto *record = std::addressof(*it); if (record->m_info.id == report_id) { EraseReportImpl(record, false, false); R_SUCCEED(); } } R_THROW(erpt::ResultInvalidArgument()); } Result JournalForReports::DeleteReportWithAttachments() { for (auto it = s_record_list.rbegin(); it != s_record_list.rend(); it++) { auto *record = std::addressof(*it); if (record->m_info.flags.Test<ReportFlag::HasAttachment>()) { EraseReportImpl(record, true, true); R_SUCCEED(); } } R_THROW(erpt::ResultNotFound()); } s64 JournalForReports::GetMaxReportSize() { s64 max_size = 0; for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) { max_size = std::max(max_size, it->m_info.report_size); } return max_size; } Result JournalForReports::GetReportList(ReportList *out, ReportType type_filter) { u32 count = 0; for (auto it = s_record_list.cbegin(); it != s_record_list.cend() && count < util::size(out->reports); it++) { if (type_filter == ReportType_Any || type_filter == it->m_info.type) { out->reports[count++] = it->m_info; } } out->report_count = count; R_SUCCEED(); } u32 JournalForReports::GetStoredReportCount(ReportType type) { if (ReportType_Start <= type && type < ReportType_End) { return s_record_count_by_type[type]; } else { return 0; } } u32 JournalForReports::GetUsedStorage() { return s_used_storage; } Result JournalForReports::RestoreJournal(Stream *stream) { /* Clear the used storage. */ s_used_storage = 0; /* Read the count from storage. */ u32 read_size; u32 count; R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(count)), sizeof(count))); R_UNLESS(read_size == sizeof(count), erpt::ResultCorruptJournal()); R_UNLESS(count <= ReportCountMax, erpt::ResultCorruptJournal()); /* If we fail in the middle of reading reports, we want to do cleanup. */ auto cleanup_guard = SCOPE_GUARD { CleanupReports(); }; ReportInfo info; for (u32 i = 0; i < count; i++) { R_TRY(stream->ReadStream(std::addressof(read_size), reinterpret_cast<u8 *>(std::addressof(info)), sizeof(info))); R_UNLESS(read_size == sizeof(info), erpt::ResultCorruptJournal()); R_UNLESS(ReportType_Start <= info.type, erpt::ResultCorruptJournal()); R_UNLESS(info.type < ReportType_End, erpt::ResultCorruptJournal()); auto *record = new JournalRecord<ReportInfo>(info); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* NOTE: Nintendo does not ensure that the newly allocated record does not leak in the failure case. */ /* We will ensure it is freed if we early error. */ auto record_guard = SCOPE_GUARD { delete record; }; if (record->m_info.report_size == 0) { R_UNLESS(R_SUCCEEDED(Stream::GetStreamSize(std::addressof(record->m_info.report_size), Report::FileName(record->m_info.id, false).name)), erpt::ResultCorruptJournal()); } record_guard.Cancel(); R_TRY(StoreRecord(record)); } cleanup_guard.Cancel(); R_SUCCEED(); } JournalRecord<ReportInfo> *JournalForReports::RetrieveRecord(ReportId report_id) { for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) { if (auto *record = std::addressof(*it); record->m_info.id == report_id) { return record; } } return nullptr; } Result JournalForReports::StoreRecord(JournalRecord<ReportInfo> *record) { /* Check if the record already exists. */ for (auto it = s_record_list.begin(); it != s_record_list.end(); it++) { R_UNLESS(it->m_info.id != record->m_info.id, erpt::ResultAlreadyExists()); } /* Delete an older report if we need to. */ if (s_record_count >= ReportCountMax) { /* Nintendo deletes the oldest report from the type with the most reports. */ /* This is an approximation of FIFO. */ ReportType most_used_type = record->m_info.type; u32 most_used_count = s_record_count_by_type[most_used_type]; for (int i = ReportType_Start; i < ReportType_End; i++) { if (s_record_count_by_type[i] > most_used_count) { most_used_type = static_cast<ReportType>(i); most_used_count = s_record_count_by_type[i]; } } for (auto it = s_record_list.rbegin(); it != s_record_list.rend(); it++) { if (it->m_info.type != most_used_type) { continue; } EraseReportImpl(std::addressof(*it), true, false); break; } } AMS_ASSERT(s_record_count < ReportCountMax); /* Add a reference to the new record. */ record->AddReference(); /* Push the record into the list. */ s_record_list.push_front(*record); s_record_count++; s_record_count_by_type[record->m_info.type]++; s_used_storage += static_cast<u32>(record->m_info.report_size); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_journal_record.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_ref_count.hpp" namespace ams::erpt::srv { template<typename Info> class JournalRecord : public Allocator, public RefCount, public util::IntrusiveListBaseNode<JournalRecord<Info>> { public: Info m_info; JournalRecord() { std::memset(std::addressof(m_info), 0, sizeof(m_info)); } explicit JournalRecord(Info info) : m_info(info) { /* ... */ } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_keys.hpp" namespace ams::erpt::srv { namespace { constexpr const u8 PublicKeyModulusProduction[] = { 0x00, 0xAB, 0xB6, 0x6C, 0x43, 0x86, 0xDF, 0x52, 0x5F, 0xB9, 0xD3, 0x61, 0xEB, 0xFB, 0x16, 0x2B, 0x44, 0xE1, 0x1F, 0xDD, 0x81, 0xFA, 0x20, 0x48, 0x7B, 0xDB, 0x17, 0x9F, 0x9A, 0x92, 0x1E, 0x0A, 0x80, 0xD1, 0x1A, 0x4F, 0xD7, 0x49, 0xFE, 0xBA, 0x65, 0xE4, 0x61, 0x08, 0x26, 0x43, 0x7B, 0x4A, 0x16, 0x59, 0x60, 0xD1, 0xE0, 0x42, 0x0A, 0x26, 0x54, 0xC4, 0xC7, 0x2A, 0xE3, 0x17, 0x1F, 0x8E, 0x35, 0x79, 0xC0, 0x1B, 0xA1, 0xF8, 0x6F, 0x5C, 0xDC, 0x05, 0x2D, 0x90, 0x75, 0xD5, 0x98, 0x7E, 0x5A, 0x07, 0x3F, 0x4E, 0x78, 0xF1, 0x69, 0x2F, 0xE9, 0x2E, 0x50, 0x01, 0x9F, 0xCE, 0x35, 0xC8, 0x4D, 0x65, 0x23, 0xA8, 0x9F, 0xC3, 0x3C, 0x4A, 0xF2, 0x29, 0x4D, 0x10, 0x03, 0x1C, 0xB4, 0x0E, 0x64, 0xB6, 0xDD, 0xB2, 0x74, 0xE3, 0x32, 0x84, 0x25, 0x99, 0xEA, 0xE1, 0x6C, 0x78, 0x24, 0xF2, 0xB0, 0xD2, 0x2C, 0xA5, 0x1A, 0x70, 0xA6, 0x49, 0x08, 0x73, 0x8A, 0x74, 0x3A, 0x12, 0x0E, 0x1B, 0x68, 0xD1, 0x6A, 0x6C, 0x3F, 0x2C, 0x2C, 0x53, 0xD5, 0xCE, 0x5A, 0x07, 0xA2, 0xB9, 0x2E, 0x0A, 0x77, 0x51, 0x4B, 0xD2, 0x8E, 0x4F, 0xA3, 0xA8, 0x56, 0x99, 0x6F, 0x63, 0xBC, 0x23, 0x04, 0x6E, 0x71, 0x57, 0x7C, 0xFD, 0x84, 0xA7, 0xF8, 0x8D, 0x7F, 0xD6, 0xA0, 0x6E, 0x92, 0xBC, 0xCC, 0x28, 0x82, 0x60, 0xE9, 0x78, 0xC1, 0x31, 0x82, 0x4F, 0xF8, 0xC5, 0xDB, 0xB6, 0x6B, 0xF9, 0x62, 0x95, 0xD3, 0xC8, 0x63, 0x59, 0x53, 0x3F, 0x82, 0xEB, 0x06, 0xA7, 0xB8, 0x55, 0xEC, 0x9E, 0x33, 0x04, 0xCF, 0x5E, 0x42, 0x32, 0x09, 0x26, 0xFF, 0xB4, 0x5E, 0xBD, 0xD7, 0xA8, 0x6B, 0x2C, 0xF5, 0x68, 0x86, 0xCD, 0x8A, 0x13, 0xF3, 0x1C, 0x5F, 0xE6, 0x4F, 0xFC, 0xD1, 0x07, 0x28, 0x5C, 0x2D, 0xA7, 0xF7 }; constexpr const u8 PublicKeyModulusDevelopment[] = { 0x00, 0xAE, 0x7D, 0x6C, 0xD0, 0xC3, 0x13, 0x61, 0x01, 0x9D, 0x1B, 0x55, 0xA0, 0xE5, 0xF4, 0x3D, 0x56, 0x7D, 0xCA, 0x0E, 0x49, 0xFB, 0x82, 0x08, 0x06, 0x33, 0xB6, 0x37, 0xB3, 0x4A, 0x3F, 0x57, 0x39, 0x05, 0x84, 0x18, 0x3D, 0x82, 0xD8, 0x8F, 0xBC, 0xF3, 0xE1, 0x66, 0xEE, 0xD2, 0x80, 0x43, 0xF8, 0xA7, 0xB7, 0x5E, 0x5B, 0x5C, 0xF9, 0x9D, 0x7F, 0xE9, 0x6C, 0x93, 0x8A, 0x65, 0xBB, 0xD1, 0xDD, 0x56, 0xFF, 0x7C, 0x9D, 0x24, 0x66, 0x09, 0x84, 0x21, 0x2C, 0x7F, 0x0A, 0xB8, 0x31, 0x42, 0x29, 0xE6, 0xD3, 0x20, 0x76, 0xA1, 0x1F, 0x7E, 0x59, 0x5B, 0x7C, 0xF6, 0xC6, 0x02, 0xDB, 0xC9, 0x1B, 0xB9, 0x24, 0x99, 0xAD, 0x0F, 0x7B, 0x0D, 0x8E, 0x7E, 0x01, 0xFE, 0x95, 0xCE, 0x9B, 0xB5, 0x09, 0xC5, 0xF5, 0xA5, 0x6A, 0x82, 0xF6, 0x57, 0xF8, 0x06, 0x72, 0xAE, 0x73, 0x71, 0xD1, 0x09, 0x2B, 0xE2, 0x84, 0x0D, 0x66, 0x39, 0xB6, 0x21, 0x8B, 0x35, 0xE4, 0xDF, 0x90, 0x36, 0xE1, 0x3F, 0xC0, 0x9F, 0xF8, 0x85, 0x03, 0xD6, 0xCA, 0xBB, 0x1A, 0x62, 0x2D, 0xE5, 0x03, 0xF6, 0x47, 0x00, 0x6E, 0x98, 0x5A, 0x1C, 0x51, 0x94, 0x47, 0xF6, 0x83, 0x0C, 0x25, 0xBD, 0xBE, 0xBD, 0x6A, 0x35, 0xC0, 0xAB, 0x65, 0xF8, 0x01, 0xF4, 0xC3, 0x2A, 0xA3, 0xBC, 0xD7, 0xD9, 0xF7, 0x2A, 0x98, 0x27, 0xE1, 0x3F, 0x9A, 0xCF, 0xDF, 0xB1, 0x30, 0x82, 0xA4, 0xAA, 0x78, 0xCA, 0xC8, 0xB8, 0x34, 0xFA, 0xA7, 0x75, 0x23, 0xC9, 0x9C, 0x11, 0x68, 0x7E, 0x0F, 0x80, 0x8F, 0x90, 0xA6, 0xDE, 0x2B, 0x47, 0x5B, 0x94, 0x6F, 0xB9, 0x67, 0x4C, 0xC1, 0xAE, 0x50, 0x8F, 0xD8, 0xE3, 0xD1, 0xF2, 0x92, 0x54, 0x4C, 0x25, 0x02, 0x5B, 0x31, 0x65, 0x5E, 0x41, 0x81, 0x34, 0xF4, 0xF1, 0x34, 0xE7, 0x64, 0x7A, 0xC1 }; constexpr const u8 PublicKeyExponent[] = { 0x01, 0x00, 0x01 }; bool IsProductionModeImpl() { bool is_prod = true; if (settings::fwdbg::GetSettingsItemValue(std::addressof(is_prod), sizeof(is_prod), "erpt", "production_mode") != sizeof(is_prod)) { return true; } return is_prod; } bool IsProductionMode() { AMS_FUNCTION_LOCAL_STATIC(bool, s_is_prod_mode, IsProductionModeImpl()); return s_is_prod_mode; } } const u8 *GetPublicKeyModulus() { return IsProductionMode() ? PublicKeyModulusProduction : PublicKeyModulusDevelopment; } size_t GetPublicKeyModulusSize() { return IsProductionMode() ? sizeof(PublicKeyModulusProduction) : sizeof(PublicKeyModulusDevelopment); } const u8 *GetPublicKeyExponent() { return PublicKeyExponent; } size_t GetPublicKeyExponentSize() { return sizeof(PublicKeyExponent); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_keys.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { const u8 *GetPublicKeyModulus(); size_t GetPublicKeyModulusSize(); const u8 *GetPublicKeyExponent(); size_t GetPublicKeyExponentSize(); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_context_record.hpp" #include "erpt_srv_context.hpp" #include "erpt_srv_reporter.hpp" #include "erpt_srv_journal.hpp" #include "erpt_srv_service.hpp" #include "erpt_srv_forced_shutdown.hpp" namespace ams::erpt::srv { constinit lmem::HeapHandle g_heap_handle; constinit ams::sf::ExpHeapAllocator g_sf_allocator = {}; namespace { constexpr fs::SystemSaveDataId SystemSaveDataId = 0x80000000000000D1; constexpr u32 SystemSaveDataFlags = fs::SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData; constexpr s64 SystemSaveDataSize = 11_MB; constexpr s64 SystemSaveDataJournalSize = 2720_KB; constinit bool g_automatic_report_cleanup_enabled = true; Result ExtendSystemSaveData() { s64 cur_journal_size; s64 cur_savedata_size; R_TRY(fs::GetSaveDataJournalSize(std::addressof(cur_journal_size), SystemSaveDataId)); R_TRY(fs::GetSaveDataAvailableSize(std::addressof(cur_savedata_size), SystemSaveDataId)); if (cur_journal_size < SystemSaveDataJournalSize || cur_savedata_size < SystemSaveDataSize) { if (hos::GetVersion() >= hos::Version_3_0_0) { R_TRY(fs::ExtendSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize)); } } R_SUCCEED(); } Result MountSystemSaveData() { fs::DisableAutoSaveDataCreation(); /* Extend the system save data. */ /* NOTE: Nintendo used to not check the result of this; they do now, but . */ static_cast<void>(ExtendSystemSaveData()); R_TRY_CATCH(fs::MountSystemSaveData(ReportStoragePath, SystemSaveDataId)) { R_CATCH(fs::ResultTargetNotFound) { R_TRY(fs::CreateSystemSaveData(SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize, SystemSaveDataFlags)); R_TRY(fs::MountSystemSaveData(ReportStoragePath, SystemSaveDataId)); } } R_END_TRY_CATCH; R_SUCCEED(); } } Result Initialize(u8 *mem, size_t mem_size) { R_ABORT_UNLESS(time::Initialize()); g_heap_handle = lmem::CreateExpHeap(mem, mem_size, lmem::CreateOption_ThreadSafe); AMS_ABORT_UNLESS(g_heap_handle != nullptr); fs::InitializeForSystem(); fs::SetAllocator(Allocate, DeallocateWithSize); fs::SetEnabledAutoAbort(false); R_ABORT_UNLESS(fs::MountSdCardErrorReportDirectoryForAtmosphere(ReportOnSdStoragePath)); if (g_automatic_report_cleanup_enabled) { constexpr s64 MinimumReportCountForCleanup = 1000; s64 report_count = MinimumReportCountForCleanup; fs::DirectoryHandle dir; if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(dir), ReportOnSdStorageRootDirectoryPath, fs::OpenDirectoryMode_All))) { ON_SCOPE_EXIT { fs::CloseDirectory(dir); }; if (R_FAILED(fs::GetDirectoryEntryCount(std::addressof(report_count), dir))) { report_count = MinimumReportCountForCleanup; } } if (report_count >= MinimumReportCountForCleanup) { static_cast<void>(fs::CleanDirectoryRecursively(ReportOnSdStorageRootDirectoryPath)); } } R_ABORT_UNLESS(MountSystemSaveData()); g_sf_allocator.Attach(g_heap_handle); for (const auto category_id : CategoryIndexToCategoryIdMap) { Context *ctx = new Context(category_id); AMS_ABORT_UNLESS(ctx != nullptr); } if (R_FAILED(Journal::Restore())) { /* TODO: Nintendo deletes system savedata when this fails. Should we?. */ } Reporter::UpdatePowerOnTime(); Reporter::UpdateAwakeTime(); R_SUCCEED(); } Result InitializeAndStartService() { /* Initialize forced shutdown detection. */ /* NOTE: Nintendo does not check error code here. */ InitializeForcedShutdownDetection(); R_RETURN(InitializeService()); } Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) { R_RETURN(Reporter::SetSerialNumberAndOsVersion(sn, sn_len, os, os_len, os_priv, os_priv_len)); } Result SetProductModel(const char *model, u32 model_len) { /* NOTE: Nintendo does not check that this allocation succeeds. */ auto record = std::make_unique<ContextRecord>(CategoryId_ProductModelInfo); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_TRY(record->Add(FieldId_ProductModel, model, model_len)); R_TRY(Context::SubmitContextRecord(std::move(record))); R_SUCCEED(); } Result SetRegionSetting(const char *region, u32 region_len) { /* NOTE: Nintendo does not check that this allocation succeeds. */ auto record = std::make_unique<ContextRecord>(CategoryId_RegionSettingInfo); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); R_TRY(record->Add(FieldId_RegionSetting, region, region_len)); R_TRY(Context::SubmitContextRecord(std::move(record))); R_SUCCEED(); } Result SetRedirectNewReportsToSdCard(bool redirect) { Reporter::SetRedirectNewReportsToSdCard(redirect); R_SUCCEED(); } Result SetEnabledAutomaticReportCleanup(bool en) { g_automatic_report_cleanup_enabled = en; R_SUCCEED(); } void Wait() { /* Get the update event. */ os::Event *event = GetForcedShutdownUpdateEvent(); /* Forever wait, saving any updates. */ while (true) { event->Wait(); event->Clear(); SaveForcedShutdownContext(); } } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_manager_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_manager_impl.hpp" #include "erpt_srv_journal.hpp" namespace ams::erpt::srv { namespace { using ManagerList = util::IntrusiveListBaseTraits<ManagerImpl>::ListType; constinit ManagerList g_manager_list; } ManagerImpl::ManagerImpl() : m_system_event(os::EventClearMode_AutoClear, true) { g_manager_list.push_front(*this); } ManagerImpl::~ManagerImpl() { g_manager_list.erase(g_manager_list.iterator_to(*this)); } void ManagerImpl::NotifyOne() { m_system_event.Signal(); } void ManagerImpl::NotifyAll() { for (auto &manager : g_manager_list) { manager.NotifyOne(); } } Result ManagerImpl::GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter) { R_UNLESS(out_list.GetSize() == sizeof(ReportList), erpt::ResultInvalidArgument()); R_RETURN(Journal::GetReportList(reinterpret_cast<ReportList *>(out_list.GetPointer()), type_filter)); } Result ManagerImpl::GetEvent(ams::sf::OutCopyHandle out) { out.SetValue(m_system_event.GetReadableHandle(), false); R_SUCCEED(); } Result ManagerImpl::CleanupReports() { Journal::CleanupReports(); Journal::CleanupAttachments(); R_RETURN(Journal::Commit()); } Result ManagerImpl::DeleteReport(const ReportId &report_id) { R_TRY(Journal::Delete(report_id)); R_RETURN(Journal::Commit()); } Result ManagerImpl::GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out) { StorageUsageStatistics stats = {}; stats.journal_uuid = Journal::GetJournalId(); stats.used_storage_size = Journal::GetUsedStorage(); stats.max_report_size = Journal::GetMaxReportSize(); for (int i = ReportType_Start; i < ReportType_End; i++) { const auto type = static_cast<ReportType>(i); stats.report_count[i] = Journal::GetStoredReportCount(type); stats.transmitted_count[i] = Journal::GetTransmittedCount(type); stats.untransmitted_count[i] = Journal::GetUntransmittedCount(type); } out.SetValue(stats); R_SUCCEED(); } Result ManagerImpl::GetAttachmentListDeprecated(const ams::sf::OutBuffer &out_list, const ReportId &report_id) { R_UNLESS(out_list.GetSize() == sizeof(AttachmentList), erpt::ResultInvalidArgument()); auto *attachment_list = reinterpret_cast<AttachmentList *>(out_list.GetPointer()); R_RETURN(Journal::GetAttachmentList(std::addressof(attachment_list->attachment_count), attachment_list->attachments, util::size(attachment_list->attachments), report_id)); } Result ManagerImpl::GetAttachmentList(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const ReportId &report_id) { R_RETURN(Journal::GetAttachmentList(out_count.GetPointer(), reinterpret_cast<AttachmentInfo *>(out_buf.GetPointer()), out_buf.GetSize() / sizeof(AttachmentInfo), report_id)); } Result ManagerImpl::GetReportSizeMax(ams::sf::Out<u32> out) { /* TODO: Where is this size defined? */ constexpr size_t ReportSizeMax = 0x3FF4F; *out = ReportSizeMax; R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_manager_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class ManagerImpl : public util::IntrusiveListBaseNode<ManagerImpl> { private: os::SystemEvent m_system_event; public: ManagerImpl(); ~ManagerImpl(); private: void NotifyOne(); public: static void NotifyAll(); public: Result GetReportList(const ams::sf::OutBuffer &out_list, ReportType type_filter); Result GetEvent(ams::sf::OutCopyHandle out); Result CleanupReports(); Result DeleteReport(const ReportId &report_id); Result GetStorageUsageStatistics(ams::sf::Out<StorageUsageStatistics> out); Result GetAttachmentListDeprecated(const ams::sf::OutBuffer &out_buf, const ReportId &report_id); Result GetAttachmentList(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buf, const ReportId &report_id); Result GetReportSizeMax(ams::sf::Out<u32> out); }; static_assert(erpt::sf::IsIManager<ManagerImpl>); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_ref_count.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class RefCount { private: static constexpr u32 MaxReferenceCount = 1000; std::atomic<u32> m_ref_count; public: RefCount() : m_ref_count(0) { /* ... */ } void AddReference() { const auto prev = m_ref_count.fetch_add(1); AMS_ABORT_UNLESS(prev <= MaxReferenceCount); } bool RemoveReference() { auto prev = m_ref_count.fetch_sub(1); AMS_ABORT_UNLESS(prev != 0); return prev == 1; } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_report.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_report_impl.hpp" #include "erpt_srv_report.hpp" namespace ams::erpt::srv { ReportFileName Report::FileName(ReportId report_id, bool redirect_to_sd) { ReportFileName report_name; util::SNPrintf(report_name.name, sizeof(report_name.name), "%s:/%08x-%04x-%04x-%02x%02x-%04x%08x", (redirect_to_sd ? ReportOnSdStoragePath : ReportStoragePath), report_id.uuid_data.time_low, report_id.uuid_data.time_mid, report_id.uuid_data.time_high_and_version, report_id.uuid_data.clock_high, report_id.uuid_data.clock_low, static_cast<u32>((report_id.uuid_data.node >> BITSIZEOF(u32)) & 0x0000FFFF), static_cast<u32>((report_id.uuid_data.node >> 0) & 0xFFFFFFFF)); return report_name; } Report::Report(JournalRecord<ReportInfo> *r, bool redirect_to_sd) : m_record(r), m_redirect_to_sd_card(redirect_to_sd) { m_record->AddReference(); } Report::~Report() { this->CloseStream(); if (m_record->RemoveReference()) { if (R_FAILED(this->DeleteStream(this->FileName().name))) { /* TODO: Log failure? */ } delete m_record; } } ReportFileName Report::FileName() const { return FileName(m_record->m_info.id, m_redirect_to_sd_card); } Result Report::Open(ReportOpenType type) { switch (type) { case ReportOpenType_Create: R_RETURN(this->OpenStream(this->FileName().name, StreamMode_Write, ReportStreamBufferSize)); case ReportOpenType_Read: R_RETURN(this->OpenStream(this->FileName().name, StreamMode_Read, ReportStreamBufferSize)); default: R_THROW(erpt::ResultInvalidArgument()); } } Result Report::Read(u32 *out_read_count, u8 *dst, u32 dst_size) { R_RETURN(this->ReadStream(out_read_count, dst, dst_size)); } Result Report::Delete() { R_RETURN(this->DeleteStream(this->FileName().name)); } void Report::Close() { return this->CloseStream(); } Result Report::GetFlags(ReportFlagSet *out) const { *out = m_record->m_info.flags; R_SUCCEED(); } Result Report::SetFlags(ReportFlagSet flags) { if (((~m_record->m_info.flags) & flags).IsAnySet()) { m_record->m_info.flags |= flags; R_RETURN(Journal::Commit()); } R_SUCCEED(); } Result Report::GetSize(s64 *out) const { R_RETURN(this->GetStreamSize(out)); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_report.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_stream.hpp" #include "erpt_srv_journal.hpp" namespace ams::erpt::srv { enum ReportOpenType { ReportOpenType_Create = 0, ReportOpenType_Read = 1, }; constexpr inline u32 ReportStreamBufferSize = 1_KB; class Report : public Allocator, public Stream { private: JournalRecord<ReportInfo> *m_record; bool m_redirect_to_sd_card; private: ReportFileName FileName() const; public: static ReportFileName FileName(ReportId report_id, bool redirect_to_sd); public: explicit Report(JournalRecord<ReportInfo> *r, bool redirect_to_sd); ~Report(); Result Open(ReportOpenType type); Result Read(u32 *out_read_count, u8 *dst, u32 dst_size); Result Delete(); void Close(); Result GetFlags(ReportFlagSet *out) const; Result SetFlags(ReportFlagSet flags); Result GetSize(s64 *out) const; template<typename T> Result Write(T val) { R_RETURN(this->WriteStream(reinterpret_cast<const u8 *>(std::addressof(val)), sizeof(val))); } template<typename T> Result Write(const T *buf, u32 buffer_size) { R_RETURN(this->WriteStream(reinterpret_cast<const u8 *>(buf), buffer_size)); } }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_report_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_report_impl.hpp" #include "erpt_srv_report.hpp" namespace ams::erpt::srv { ReportImpl::ReportImpl() : m_report(nullptr) { /* ... */ } ReportImpl::~ReportImpl() { R_ABORT_UNLESS(this->Close()); } Result ReportImpl::Open(const ReportId &report_id) { R_UNLESS(m_report == nullptr, erpt::ResultAlreadyInitialized()); JournalRecord<ReportInfo> *record = Journal::Retrieve(report_id); R_UNLESS(record != nullptr, erpt::ResultNotFound()); m_report = new Report(record, false); R_UNLESS(m_report != nullptr, erpt::ResultOutOfMemory()); auto report_guard = SCOPE_GUARD { delete m_report; m_report = nullptr; }; R_TRY(m_report->Open(ReportOpenType_Read)); report_guard.Cancel(); R_SUCCEED(); } Result ReportImpl::Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer) { R_UNLESS(m_report != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_report->Read(out_count.GetPointer(), static_cast<u8 *>(out_buffer.GetPointer()), static_cast<u32>(out_buffer.GetSize()))); } Result ReportImpl::SetFlags(ReportFlagSet flags) { R_UNLESS(m_report != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_report->SetFlags(flags)); } Result ReportImpl::GetFlags(ams::sf::Out<ReportFlagSet> out) { R_UNLESS(m_report != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_report->GetFlags(out.GetPointer())); } Result ReportImpl::Close() { if (m_report != nullptr) { m_report->Close(); delete m_report; m_report = nullptr; } R_SUCCEED(); } Result ReportImpl::GetSize(ams::sf::Out<s64> out) { R_UNLESS(m_report != nullptr, erpt::ResultNotInitialized()); R_RETURN(m_report->GetSize(out.GetPointer())); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_report_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class Report; class ReportImpl { private: Report *m_report; public: ReportImpl(); ~ReportImpl(); public: Result Open(const ReportId &report_id); Result Read(ams::sf::Out<u32> out_count, const ams::sf::OutBuffer &out_buffer); Result SetFlags(ReportFlagSet flags); Result GetFlags(ams::sf::Out<ReportFlagSet> out); Result Close(); Result GetSize(ams::sf::Out<s64> out); }; static_assert(erpt::sf::IsIReport<ReportImpl>); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_reporter.hpp" #include "erpt_srv_report.hpp" #include "erpt_srv_journal.hpp" #include "erpt_srv_context_record.hpp" #include "erpt_srv_context.hpp" #include "erpt_srv_fs_info.hpp" namespace ams::erpt::srv { constinit bool Reporter::s_redirect_new_reports = true; constinit char Reporter::s_serial_number[24] = "Unknown"; constinit char Reporter::s_os_version[24] = "Unknown"; constinit char Reporter::s_private_os_version[96] = "Unknown"; constinit util::optional<os::Tick> Reporter::s_application_launch_time; constinit util::optional<os::Tick> Reporter::s_awake_time; constinit util::optional<os::Tick> Reporter::s_power_on_time; constinit util::optional<time::SteadyClockTimePoint> Reporter::s_initial_launch_settings_completion_time; namespace { class AppletActiveTimeInfoList { private: struct AppletActiveTimeInfo { ncm::ProgramId program_id; os::Tick register_tick; TimeSpan suspended_duration; }; static constexpr AppletActiveTimeInfo InvalidAppletActiveTimeInfo = { ncm::InvalidProgramId, os::Tick{}, TimeSpan::FromNanoSeconds(0) }; private: std::array<AppletActiveTimeInfo, 8> m_list; ncm::ApplicationId m_running_app_id; ncm::ProgramId m_running_app_program_id; public: constexpr AppletActiveTimeInfoList() : m_list{InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo, InvalidAppletActiveTimeInfo}, m_running_app_id{ncm::InvalidApplicationId}, m_running_app_program_id{ncm::InvalidProgramId} { m_list.fill(InvalidAppletActiveTimeInfo); } public: void Register(ncm::ProgramId program_id) { /* Find an unused entry. */ auto entry = util::range::find_if(m_list, [](const AppletActiveTimeInfo &info) { return info.program_id == ncm::InvalidProgramId; }); AMS_ASSERT(entry != m_list.end()); /* Create the entry. */ *entry = { program_id, os::GetSystemTick(), TimeSpan::FromNanoSeconds(0) }; } void Unregister(ncm::ProgramId program_id) { /* Find a matching entry. */ auto entry = util::range::find_if(m_list, [&](const AppletActiveTimeInfo &info) { return info.program_id == program_id; }); AMS_ASSERT(entry != m_list.end()); /* Clear the entry. */ *entry = InvalidAppletActiveTimeInfo; } void RegisterApplicationInfo(ncm::ApplicationId app_id, ncm::ProgramId program_id) { /* Set the running application info. */ m_running_app_id = app_id; m_running_app_program_id = program_id; } void UnregisterApplicationInfo() { m_running_app_id = ncm::InvalidApplicationId; m_running_app_program_id = ncm::InvalidProgramId; } util::optional<os::Tick> GetApplicationStartTick() { /* If we have a running application, try to find a matching entry. */ if (m_running_app_id != ncm::InvalidApplicationId) { /* NOTE: This seems to be a Nintendo bug? They are comparing the running app id to the info's program id, */ /* instead of the running app program id. Granted, these should usually be the same, but I think this code */ /* is literally incorrect. */ const auto entry = util::range::find_if(m_list, [&](const AppletActiveTimeInfo &info) { return info.program_id == m_running_app_id; }); if (entry != m_list.end()) { return entry->register_tick; } } return util::nullopt; } void UpdateSuspendedDuration(ncm::ProgramId program_id, TimeSpan suspended_duration) { /* Find a matching entry. */ auto entry = util::range::find_if(m_list, [&](const AppletActiveTimeInfo &info) { return info.program_id == program_id; }); AMS_ASSERT(entry != m_list.end()); /* Set the suspended duration. */ entry->suspended_duration = suspended_duration; } util::optional<TimeSpan> GetActiveDuration(ncm::ProgramId program_id) const { /* Try to find a matching entry. */ const auto entry = util::range::find_if(m_list, [&](const AppletActiveTimeInfo &info) { return info.program_id == program_id; }); if (entry != m_list.end()) { return (os::GetSystemTick() - entry->register_tick).ToTimeSpan() - entry->suspended_duration; } else { return util::nullopt; } } }; constinit AppletActiveTimeInfoList g_applet_active_time_info_list; #if defined(ATMOSPHERE_OS_HORIZON) Result PullErrorContext(size_t *out_total_size, size_t *out_size, void *dst, size_t dst_size, const err::ContextDescriptor &descriptor, Result result) { s32 unk0; u32 total_size, size; R_TRY(::ectxrPullContext(std::addressof(unk0), std::addressof(total_size), std::addressof(size), dst, dst_size, descriptor.value, result.GetValue())); *out_total_size = total_size; *out_size = size; R_SUCCEED(); } void SubmitErrorContext(ContextRecord *record, Result result) { /* Only support submitting context on 11.x. */ if (hos::GetVersion() < hos::Version_11_0_0) { return; } /* Get the context descriptor. */ const auto descriptor = err::GetContextDescriptorFromResult(result); if (descriptor == err::InvalidContextDescriptor) { return; } /* Pull the error context. */ u8 error_context[0x200]; size_t error_context_total_size; size_t error_context_size; if (R_FAILED(PullErrorContext(std::addressof(error_context_total_size), std::addressof(error_context_size), error_context, util::size(error_context), descriptor, result))) { return; } /* Set the total size. */ if (error_context_total_size == 0) { return; } static_cast<void>(record->Add(FieldId_ErrorContextTotalSize, error_context_total_size)); /* Set the context. */ if (error_context_size == 0) { return; } static_cast<void>(record->Add(FieldId_ErrorContextSize, error_context_size)); static_cast<void>(record->Add(FieldId_ErrorContext, error_context, error_context_size)); } void SubmitResourceLimitContexts() { /* Create and populate the record. */ auto record = std::make_unique<ContextRecord>(CategoryId_ResourceLimitInfo); if (record == nullptr) { return; } u64 reslimit_handle_value; if (R_FAILED(svc::GetInfo(std::addressof(reslimit_handle_value), svc::InfoType_ResourceLimit, svc::InvalidHandle, 0))) { return; } const auto handle = static_cast<svc::Handle>(reslimit_handle_value); ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(handle)); }; #define ADD_RESOURCE(__RESOURCE__) \ do { \ s64 limit_value; \ if (R_FAILED(svc::GetResourceLimitLimitValue(std::addressof(limit_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ return; \ } \ if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Limit, limit_value))) { \ return; \ } \ \ s64 peak_value; \ if (R_FAILED(svc::GetResourceLimitPeakValue(std::addressof(peak_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ return; \ } \ if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Peak, peak_value))) { \ return; \ } \ } while (0) ADD_RESOURCE(PhysicalMemory); ADD_RESOURCE(ThreadCount); ADD_RESOURCE(EventCount); ADD_RESOURCE(TransferMemoryCount); ADD_RESOURCE(SessionCount); #undef ADD_RESOURCE static_cast<void>(Context::SubmitContextRecord(std::move(record))); } #else void SubmitErrorContext(ContextRecord *record, Result result) { AMS_UNUSED(record, result); } #endif Result ValidateCreateReportContext(const ContextEntry *ctx) { R_UNLESS(ctx->category == CategoryId_ErrorInfo, erpt::ResultRequiredContextMissing()); R_UNLESS(ctx->field_count <= FieldsPerContext, erpt::ResultInvalidArgument()); const bool found_error_code = util::range::any_of(MakeSpan(ctx->fields, ctx->field_count), [] (const FieldEntry &entry) { return entry.id == FieldId_ErrorCode; }); R_UNLESS(found_error_code, erpt::ResultRequiredFieldMissing()); R_SUCCEED(); } Result SubmitReportDefaults(const ContextEntry *ctx) { AMS_ASSERT(ctx->category == CategoryId_ErrorInfo); auto record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoDefaults); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); bool found_abort_flag = false, found_syslog_flag = false; for (u32 i = 0; i < ctx->field_count; i++) { if (ctx->fields[i].id == FieldId_AbortFlag) { found_abort_flag = true; } if (ctx->fields[i].id == FieldId_HasSyslogFlag) { found_syslog_flag = true; } if (found_abort_flag && found_syslog_flag) { break; } } if (!found_abort_flag) { static_cast<void>(record->Add(FieldId_AbortFlag, false)); } if (!found_syslog_flag) { static_cast<void>(record->Add(FieldId_HasSyslogFlag, true)); } R_TRY(Context::SubmitContextRecord(std::move(record))); R_SUCCEED(); } void SaveSyslogReportIfRequired(const ContextEntry *ctx, const ReportId &report_id) { bool needs_save_syslog = true; for (u32 i = 0; i < ctx->field_count; i++) { static_assert(FieldIndexToTypeMap[*FindFieldIndex(FieldId_HasSyslogFlag)] == FieldType_Bool); if (ctx->fields[i].id == FieldId_HasSyslogFlag && !ctx->fields[i].value_bool) { needs_save_syslog = false; break; } } if (needs_save_syslog) { /* Here nintendo sends a report to srepo:u (vtable offset 0xE8) with data report_id. */ /* We will not send report ids to srepo:u. */ AMS_UNUSED(report_id); } } void SubmitAppletActiveDurationForCrashReport(const ContextEntry *error_info_ctx, const void *data, u32 data_size, ContextRecord *error_info_auto_record) { /* Check pre-conditions. */ AMS_ASSERT(error_info_ctx != nullptr); AMS_ASSERT(error_info_ctx->category == CategoryId_ErrorInfo); AMS_ASSERT(data != nullptr); AMS_ASSERT(error_info_auto_record != nullptr); /* Find the program id entry. */ const auto fields_span = MakeSpan(error_info_ctx->fields, error_info_ctx->field_count); const auto program_id_entry = util::range::find_if(fields_span, [](const FieldEntry &entry) { return entry.id == FieldId_ProgramId; }); if (program_id_entry == fields_span.end()) { return; } /* Check that the report has abort flag set. */ AMS_ASSERT(util::range::any_of(fields_span, [](const FieldEntry &entry) { return entry.id == FieldId_AbortFlag && entry.value_bool; })); /* Check that the program id's value is a string. */ AMS_ASSERT(program_id_entry->type == FieldType_String); /* Check that the program id's length is valid/in bounds. */ const auto program_id_ofs = program_id_entry->value_array.start_idx; const auto program_id_len = program_id_entry->value_array.size; AMS_ASSERT(16 <= program_id_len && program_id_len <= 17); AMS_ASSERT(program_id_ofs + program_id_len <= data_size); AMS_UNUSED(data_size); /* Get the program id string. */ char program_id_str[17]; std::memcpy(program_id_str, static_cast<const u8 *>(data) + program_id_ofs, std::min<size_t>(program_id_len, sizeof(program_id_str))); program_id_str[sizeof(program_id_str) - 1] = '\x00'; /* Convert the string to an integer. */ char *end_ptr = nullptr; const ncm::ProgramId program_id = { std::strtoull(program_id_str, std::addressof(end_ptr), 16) }; AMS_ASSERT(*end_ptr == '\x00'); /* Get the active duration. */ const auto active_duration = g_applet_active_time_info_list.GetActiveDuration(program_id); if (!active_duration.has_value()) { return; } /* Add the active applet time. */ const auto result = error_info_auto_record->Add(FieldId_AppletTotalActiveTime, (*active_duration).GetSeconds()); R_ASSERT(result); } Result LinkAttachments(const ReportId &report_id, const AttachmentId *attachments, u32 num_attachments) { for (u32 i = 0; i < num_attachments; i++) { R_TRY(JournalForAttachments::SetOwner(attachments[i], report_id)); } R_SUCCEED(); } Result CreateReportFile(const ReportId &report_id, ReportType type, const ReportMetaData *meta, u32 num_attachments, const time::PosixTime ×tamp_user, const time::PosixTime ×tamp_network, bool redirect_new_reports) { /* Define journal record deleter. */ struct JournalRecordDeleter { void operator()(JournalRecord<ReportInfo> *record) { if (record != nullptr) { if (record->RemoveReference()) { delete record; } } } }; /* Make a journal record. */ auto record = std::unique_ptr<JournalRecord<ReportInfo>, JournalRecordDeleter>{new JournalRecord<ReportInfo>, JournalRecordDeleter{}}; R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); record->AddReference(); record->m_info.type = type; record->m_info.id = report_id; record->m_info.flags = erpt::srv::MakeNoReportFlags(); record->m_info.timestamp_user = timestamp_user; record->m_info.timestamp_network = timestamp_network; if (meta != nullptr) { record->m_info.meta_data = *meta; } if (num_attachments > 0) { record->m_info.flags.Set<ReportFlag::HasAttachment>(); } auto report = std::make_unique<Report>(record.get(), redirect_new_reports); R_UNLESS(report != nullptr, erpt::ResultOutOfMemory()); auto report_guard = SCOPE_GUARD { const auto delete_res = report->Delete(); R_ASSERT(delete_res); AMS_UNUSED(delete_res); }; R_TRY(Context::WriteContextsToReport(report.get())); R_TRY(report->GetSize(std::addressof(record->m_info.report_size))); if (!redirect_new_reports) { /* If we're not redirecting new reports, then we want to store the report in the journal. */ R_TRY(Journal::Store(record.get())); } else { /* If we are redirecting new reports, we don't want to store the report in the journal. */ /* We should take this opportunity to delete any attachments associated with the report. */ R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id)); } R_TRY(Journal::Commit()); report_guard.Cancel(); R_SUCCEED(); } } Result Reporter::RegisterRunningApplet(ncm::ProgramId program_id) { g_applet_active_time_info_list.Register(program_id); R_SUCCEED(); } Result Reporter::UnregisterRunningApplet(ncm::ProgramId program_id) { g_applet_active_time_info_list.Unregister(program_id); R_SUCCEED(); } Result Reporter::UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpan duration) { g_applet_active_time_info_list.UpdateSuspendedDuration(program_id, duration); R_SUCCEED(); } void Reporter::RegisterRunningApplicationInfo(ncm::ApplicationId app_id, ncm::ProgramId program_id) { g_applet_active_time_info_list.RegisterApplicationInfo(app_id, program_id); } void Reporter::UnregisterRunningApplicationInfo() { g_applet_active_time_info_list.UnregisterApplicationInfo(); } Result Reporter::CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags, const ReportId *specified_report_id) { /* Create a context record for the report. */ auto record = std::make_unique<ContextRecord>(); R_UNLESS(record != nullptr, erpt::ResultOutOfMemory()); /* Initialize the record. */ R_TRY(record->Initialize(ctx, data, data_size)); /* Create the report. */ R_RETURN(CreateReport(type, ctx_result, std::move(record), meta, attachments, num_attachments, flags, specified_report_id)); } Result Reporter::CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags, const ReportId *specified_report_id) { /* Clear the automatic categories, when we're done with our report. */ ON_SCOPE_EXIT { static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo)); static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto)); static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoDefaults)); }; /* Get the context entry pointer. */ const ContextEntry *ctx = record->GetContextEntryPtr(); /* Validate the context. */ R_TRY(ValidateCreateReportContext(ctx)); /* Submit report defaults. */ R_TRY(SubmitReportDefaults(ctx)); /* Generate report id. */ const ReportId report_id = specified_report_id ? *specified_report_id : ReportId{ .uuid = util::GenerateUuid() }; /* Get posix timestamps. */ time::PosixTime timestamp_user; time::PosixTime timestamp_network; R_TRY(time::StandardUserSystemClock::GetCurrentTime(std::addressof(timestamp_user))); if (R_FAILED(time::StandardNetworkSystemClock::GetCurrentTime(std::addressof(timestamp_network)))) { timestamp_network = {}; } /* Save syslog report, if required. */ SaveSyslogReportIfRequired(ctx, report_id); /* Submit report contexts. */ R_TRY(SubmitReportContexts(report_id, type, ctx_result, std::move(record), timestamp_user, timestamp_network, flags)); /* Link attachments to the report. */ R_TRY(LinkAttachments(report_id, attachments, num_attachments)); /* Create the report file. */ R_TRY(CreateReportFile(report_id, type, meta, num_attachments, timestamp_user, timestamp_network, s_redirect_new_reports)); R_SUCCEED(); } Result Reporter::SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime ×tamp_user, const time::PosixTime ×tamp_network, erpt::CreateReportOptionFlagSet flags) { /* Create automatic record. */ auto auto_record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto, 0x300); R_UNLESS(auto_record != nullptr, erpt::ResultOutOfMemory()); /* Handle error context. */ if (R_FAILED(ctx_result)) { SubmitErrorContext(auto_record.get(), ctx_result); } /* Collect unique report fields. */ char identifier_str[0x40]; report_id.uuid.ToString(identifier_str, sizeof(identifier_str)); const auto occurrence_tick = os::GetSystemTick(); const s64 steady_clock_internal_offset_seconds = (hos::GetVersion() >= hos::Version_5_0_0) ? time::GetStandardSteadyClockInternalOffset().GetSeconds() : 0; time::SteadyClockTimePoint steady_clock_current_timepoint; R_ABORT_UNLESS(time::GetStandardSteadyClockCurrentTimePoint(std::addressof(steady_clock_current_timepoint))); /* Add automatic fields. */ static_cast<void>(auto_record->Add(FieldId_OsVersion, s_os_version, util::Strnlen(s_os_version, sizeof(s_os_version)))); static_cast<void>(auto_record->Add(FieldId_PrivateOsVersion, s_private_os_version, util::Strnlen(s_private_os_version, sizeof(s_private_os_version)))); static_cast<void>(auto_record->Add(FieldId_SerialNumber, s_serial_number, util::Strnlen(s_serial_number, sizeof(s_serial_number)))); static_cast<void>(auto_record->Add(FieldId_ReportIdentifier, identifier_str, util::Strnlen(identifier_str, sizeof(identifier_str)))); static_cast<void>(auto_record->Add(FieldId_OccurrenceTimestamp, timestamp_user.value)); static_cast<void>(auto_record->Add(FieldId_OccurrenceTimestampNet, timestamp_network.value)); static_cast<void>(auto_record->Add(FieldId_ReportVisibilityFlag, type == ReportType_Visible)); static_cast<void>(auto_record->Add(FieldId_OccurrenceTick, occurrence_tick.GetInt64Value())); static_cast<void>(auto_record->Add(FieldId_SteadyClockInternalOffset, steady_clock_internal_offset_seconds)); static_cast<void>(auto_record->Add(FieldId_SteadyClockCurrentTimePointValue, steady_clock_current_timepoint.value)); static_cast<void>(auto_record->Add(FieldId_ElapsedTimeSincePowerOn, (occurrence_tick - *s_power_on_time).ToTimeSpan().GetSeconds())); static_cast<void>(auto_record->Add(FieldId_ElapsedTimeSinceLastAwake, (occurrence_tick - *s_awake_time).ToTimeSpan().GetSeconds())); if (s_initial_launch_settings_completion_time) { s64 elapsed_seconds; if (R_SUCCEEDED(time::GetElapsedSecondsBetween(std::addressof(elapsed_seconds), *s_initial_launch_settings_completion_time, steady_clock_current_timepoint))) { static_cast<void>(auto_record->Add(FieldId_ElapsedTimeSinceInitialLaunch, elapsed_seconds)); } } if (hos::GetVersion() >= hos::Version_21_0_0) { if (auto start_tick = g_applet_active_time_info_list.GetApplicationStartTick(); start_tick.has_value()) { static_cast<void>(auto_record->Add(FieldId_ApplicationAliveTime, (occurrence_tick - *start_tick).ToTimeSpan().GetSeconds())); } } else if (s_application_launch_time) { static_cast<void>(auto_record->Add(FieldId_ApplicationAliveTime, (occurrence_tick - *s_application_launch_time).ToTimeSpan().GetSeconds())); } /* Submit applet active duration information. */ { const auto *error_info_ctx = record->GetContextEntryPtr(); SubmitAppletActiveDurationForCrashReport(error_info_ctx, error_info_ctx->array_buffer, error_info_ctx->array_buffer_size - error_info_ctx->array_free_count, auto_record.get()); } /* Submit the auto record. */ R_TRY(Context::SubmitContextRecord(std::move(auto_record))); /* Submit the info record. */ R_TRY(Context::SubmitContextRecord(std::move(record))); /* Submit context for resource limits. */ #if defined(ATMOSPHERE_OS_HORIZON) SubmitResourceLimitContexts(); #endif /* If we should, submit fs info. */ #if defined(ATMOSPHERE_OS_HORIZON) if (hos::GetVersion() >= hos::Version_17_0_0 && flags.Test<CreateReportOptionFlag::SubmitFsInfo>()) { /* NOTE: Nintendo ignores the result of this call. */ static_cast<void>(SubmitFsInfo()); } #else AMS_UNUSED(flags); #endif R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_reporter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "erpt_srv_context_record.hpp" namespace ams::erpt::srv { class Reporter { private: static bool s_redirect_new_reports; static char s_serial_number[24]; static char s_os_version[24]; static char s_private_os_version[96]; static util::optional<os::Tick> s_application_launch_time; static util::optional<os::Tick> s_awake_time; static util::optional<os::Tick> s_power_on_time; static util::optional<time::SteadyClockTimePoint> s_initial_launch_settings_completion_time; public: static void ClearApplicationLaunchTime() { s_application_launch_time = util::nullopt; } static void ClearInitialLaunchSettingsCompletionTime() { s_initial_launch_settings_completion_time = util::nullopt; } static void SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time) { s_initial_launch_settings_completion_time = time; } static void UpdateApplicationLaunchTime() { s_application_launch_time = os::GetSystemTick(); } static void UpdateAwakeTime() { s_awake_time = os::GetSystemTick(); } static void UpdatePowerOnTime() { s_power_on_time = os::GetSystemTick(); } static Result SetSerialNumberAndOsVersion(const char *sn, u32 sn_len, const char *os, u32 os_len, const char *os_priv, u32 os_priv_len) { R_UNLESS(sn_len <= sizeof(s_serial_number), erpt::ResultInvalidArgument()); R_UNLESS(os_len <= sizeof(s_os_version), erpt::ResultInvalidArgument()); R_UNLESS(os_priv_len <= sizeof(s_private_os_version), erpt::ResultInvalidArgument()); std::memcpy(s_serial_number, sn, sn_len); std::memcpy(s_os_version, os, os_len); std::memcpy(s_private_os_version, os_priv, os_priv_len); R_SUCCEED(); } static Result RegisterRunningApplet(ncm::ProgramId program_id); static Result UnregisterRunningApplet(ncm::ProgramId program_id); static Result UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpan duration); static void RegisterRunningApplicationInfo(ncm::ApplicationId app_id, ncm::ProgramId program_id); static void UnregisterRunningApplicationInfo(); static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; } private: static Result SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &user_timestamp, const time::PosixTime &network_timestamp, erpt::CreateReportOptionFlagSet flags); public: static Result CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags, const ReportId *specified_report_id); static Result CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags, const ReportId *specified_report_id); }; } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_service.hpp" #include "erpt_srv_context_impl.hpp" #include "erpt_srv_session_impl.hpp" #include "erpt_srv_stream.hpp" #include "erpt_srv_forced_shutdown.hpp" namespace ams::erpt::srv { extern ams::sf::ExpHeapAllocator g_sf_allocator; namespace { struct ErrorReportServerOptions { static constexpr size_t PointerBufferSize = 0; static constexpr size_t MaxDomains = 64; static constexpr size_t MaxDomainObjects = 2 * ReportCountMax + 5 + 2; static constexpr bool CanDeferInvokeRequest = false; static constexpr bool CanManageMitmServers = false; }; constexpr inline size_t ErrorReportNumServers = 2; constexpr inline size_t ErrorReportReportSessions = 5; constexpr inline size_t ErrorReportContextSessions = 10; constexpr inline size_t ErrorReportMaxSessions = ErrorReportReportSessions + ErrorReportContextSessions; constexpr inline sm::ServiceName ErrorReportContextServiceName = sm::ServiceName::Encode("erpt:c"); constexpr inline sm::ServiceName ErrorReportReportServiceName = sm::ServiceName::Encode("erpt:r"); alignas(os::ThreadStackAlignment) constinit u8 g_server_thread_stack[16_KB]; enum PortIndex { PortIndex_Report, PortIndex_Context, }; class ErrorReportServiceManager : public ams::sf::hipc::ServerManager<ErrorReportNumServers, ErrorReportServerOptions, ErrorReportMaxSessions> { private: os::ThreadType m_thread; ams::sf::UnmanagedServiceObject<erpt::sf::IContext, erpt::srv::ContextImpl> m_context_session_object; private: static void ThreadFunction(void *_this) { reinterpret_cast<ErrorReportServiceManager *>(_this)->SetupAndLoopProcess(); } void SetupAndLoopProcess(); virtual Result OnNeedsToAccept(int port_index, Server *server) override { switch (port_index) { case PortIndex_Report: { auto intf = ams::sf::ObjectFactory<ams::sf::ExpHeapAllocator::Policy>::CreateSharedEmplaced<erpt::sf::ISession, erpt::srv::SessionImpl>(std::addressof(g_sf_allocator)); AMS_ABORT_UNLESS(intf != nullptr); R_RETURN(this->AcceptImpl(server, intf)); } case PortIndex_Context: R_RETURN(AcceptImpl(server, m_context_session_object.GetShared())); default: R_THROW(erpt::ResultNotSupported()); } } public: Result Initialize() { R_ABORT_UNLESS(this->RegisterServer(PortIndex_Context, ErrorReportContextServiceName, ErrorReportContextSessions)); R_ABORT_UNLESS(this->RegisterServer(PortIndex_Report, ErrorReportReportServiceName, ErrorReportReportSessions)); this->ResumeProcessing(); R_ABORT_UNLESS(os::CreateThread(std::addressof(m_thread), ThreadFunction, this, g_server_thread_stack, sizeof(g_server_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(erpt, IpcServer))); os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(erpt, IpcServer)); os::StartThread(std::addressof(m_thread)); R_SUCCEED(); } void Wait() { os::WaitThread(std::addressof(m_thread)); } }; void ErrorReportServiceManager::SetupAndLoopProcess() { const psc::PmModuleId dependencies[] = { psc::PmModuleId_Fs }; psc::PmModule pm_module; psc::PmState pm_state; psc::PmFlagSet pm_flags; os::MultiWaitHolderType module_event_holder; R_ABORT_UNLESS(pm_module.Initialize(psc::PmModuleId_Erpt, dependencies, util::size(dependencies), os::EventClearMode_ManualClear)); os::InitializeMultiWaitHolder(std::addressof(module_event_holder), pm_module.GetEventPointer()->GetBase()); os::SetMultiWaitHolderUserData(std::addressof(module_event_holder), static_cast<uintptr_t>(psc::PmModuleId_Erpt)); this->AddUserMultiWaitHolder(std::addressof(module_event_holder)); while (true) { /* NOTE: Nintendo checks the user holder data to determine what's signaled, we will prefer to just check the address. */ auto *signaled_holder = this->WaitSignaled(); if (signaled_holder != std::addressof(module_event_holder)) { R_ABORT_UNLESS(this->Process(signaled_holder)); } else { pm_module.GetEventPointer()->Clear(); if (R_SUCCEEDED(pm_module.GetRequest(std::addressof(pm_state), std::addressof(pm_flags)))) { switch (pm_state) { case psc::PmState_FullAwake: case psc::PmState_MinimumAwake: Stream::EnableFsAccess(true); break; case psc::PmState_ShutdownReady: FinalizeForcedShutdownDetection(); [[fallthrough]]; case psc::PmState_SleepReady: Stream::EnableFsAccess(false); break; default: break; } R_ABORT_UNLESS(pm_module.Acknowledge(pm_state, ResultSuccess())); } else { AMS_ASSERT(false); } this->AddUserMultiWaitHolder(signaled_holder); } } } constinit util::TypedStorage<ErrorReportServiceManager> g_erpt_server_manager = {}; } Result InitializeService() { util::ConstructAt(g_erpt_server_manager); R_RETURN(util::GetReference(g_erpt_server_manager).Initialize()); } void WaitService() { return util::GetReference(g_erpt_server_manager).Wait(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_service.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { Result InitializeService(); void WaitService(); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_session_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_session_impl.hpp" #include "erpt_srv_report_impl.hpp" #include "erpt_srv_manager_impl.hpp" #include "erpt_srv_attachment_impl.hpp" namespace ams::erpt::srv { extern ams::sf::ExpHeapAllocator g_sf_allocator; namespace { template<typename Interface, typename Impl> ALWAYS_INLINE Result OpenInterface(ams::sf::Out<ams::sf::SharedPointer<Interface>> &out) { /* Create an interface holder. */ auto intf = ams::sf::ObjectFactory<ams::sf::ExpHeapAllocator::Policy>::CreateSharedEmplaced<Interface, Impl>(std::addressof(g_sf_allocator)); R_UNLESS(intf != nullptr, erpt::ResultOutOfMemory()); /* Return it. */ out.SetValue(intf); R_SUCCEED(); } } Result SessionImpl::OpenReport(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IReport>> out) { R_RETURN((OpenInterface<erpt::sf::IReport, ReportImpl>(out))); } Result SessionImpl::OpenManager(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IManager>> out) { R_RETURN((OpenInterface<erpt::sf::IManager, ManagerImpl>(out))); } Result SessionImpl::OpenAttachment(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IAttachment>> out) { R_RETURN((OpenInterface<erpt::sf::IAttachment, AttachmentImpl>(out))); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_session_impl.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { class SessionImpl { public: Result OpenReport(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IReport>> out); Result OpenManager(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IManager>> out); Result OpenAttachment(ams::sf::Out<ams::sf::SharedPointer<erpt::sf::IAttachment>> out); }; static_assert(erpt::sf::IsISession<SessionImpl>); } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "erpt_srv_allocator.hpp" #include "erpt_srv_stream.hpp" namespace ams::erpt::srv { constinit bool Stream::s_can_access_fs = true; constinit os::SdkMutex Stream::s_fs_commit_mutex; void Stream::EnableFsAccess(bool en) { s_can_access_fs = en; } Result Stream::DeleteStream(const char *path) { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); R_RETURN(fs::DeleteFile(path)); } Result Stream::CommitStream() { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); std::scoped_lock lk(s_fs_commit_mutex); const auto commit_res = fs::CommitSaveData(ReportStoragePath); R_ASSERT(commit_res); AMS_UNUSED(commit_res); R_SUCCEED(); } Result Stream::GetStreamSize(s64 *out, const char *path) { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); fs::FileHandle file; R_TRY(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read)); ON_SCOPE_EXIT { fs::CloseFile(file); }; R_RETURN(fs::GetFileSize(out, file)); } Stream::Stream() : m_buffer_size(0), m_file_position(0), m_buffer_count(0), m_buffer(nullptr), m_stream_mode(StreamMode_Invalid), m_initialized(false) { /* ... */ } Stream::~Stream() { this->CloseStream(); AMS_ASSERT(!s_fs_commit_mutex.IsLockedByCurrentThread()); } Result Stream::OpenStream(const char *path, StreamMode mode, u32 buffer_size) { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); R_UNLESS(!m_initialized, erpt::ResultAlreadyInitialized()); auto lock_guard = SCOPE_GUARD { if (s_fs_commit_mutex.IsLockedByCurrentThread()) { s_fs_commit_mutex.Unlock(); } }; if (mode == StreamMode_Write) { s_fs_commit_mutex.Lock(); while (true) { R_TRY_CATCH(fs::OpenFile(std::addressof(m_file_handle), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend)) { R_CATCH(fs::ResultPathNotFound) { R_TRY(fs::CreateFile(path, 0)); continue; } } R_END_TRY_CATCH; break; } R_TRY(fs::SetFileSize(m_file_handle, 0)); } else { R_UNLESS(mode == StreamMode_Read, erpt::ResultInvalidArgument()); R_TRY(fs::OpenFile(std::addressof(m_file_handle), path, fs::OpenMode_Read)); } auto file_guard = SCOPE_GUARD { fs::CloseFile(m_file_handle); }; std::strncpy(m_file_name, path, sizeof(m_file_name)); m_file_name[sizeof(m_file_name) - 1] = '\x00'; if (buffer_size > 0) { m_buffer = reinterpret_cast<u8 *>(Allocate(buffer_size)); AMS_ASSERT(m_buffer != nullptr); } else { m_buffer = nullptr; } m_buffer_size = m_buffer != nullptr ? buffer_size : 0; m_buffer_count = 0; m_buffer_position = 0; m_file_position = 0; m_stream_mode = mode; m_initialized = true; file_guard.Cancel(); lock_guard.Cancel(); R_SUCCEED(); } Result Stream::ReadStream(u32 *out, u8 *dst, u32 dst_size) { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); R_UNLESS(m_initialized, erpt::ResultNotInitialized()); R_UNLESS(m_stream_mode == StreamMode_Read, erpt::ResultNotInitialized()); R_UNLESS(out != nullptr, erpt::ResultInvalidArgument()); R_UNLESS(dst != nullptr, erpt::ResultInvalidArgument()); size_t fs_read_size; u32 read_count = 0; ON_SCOPE_EXIT { *out = read_count; }; if (m_buffer != nullptr) { while (dst_size > 0) { if (u32 cur = std::min<u32>(m_buffer_count - m_buffer_position, dst_size); cur > 0) { std::memcpy(dst, m_buffer + m_buffer_position, cur); m_buffer_position += cur; dst += cur; dst_size -= cur; read_count += cur; } else { R_TRY(fs::ReadFile(std::addressof(fs_read_size), m_file_handle, m_file_position, m_buffer, m_buffer_size)); m_buffer_position = 0; m_file_position += static_cast<u32>(fs_read_size); m_buffer_count = static_cast<u32>(fs_read_size); if (m_buffer_count == 0) { break; } } } } else { R_TRY(fs::ReadFile(std::addressof(fs_read_size), m_file_handle, m_file_position, dst, dst_size)); m_file_position += static_cast<u32>(fs_read_size); read_count = static_cast<u32>(fs_read_size); } R_SUCCEED(); } Result Stream::WriteStream(const u8 *src, u32 src_size) { R_UNLESS(s_can_access_fs, erpt::ResultInvalidPowerState()); R_UNLESS(m_initialized, erpt::ResultNotInitialized()); R_UNLESS(m_stream_mode == StreamMode_Write, erpt::ResultNotInitialized()); R_UNLESS(src != nullptr || src_size == 0, erpt::ResultInvalidArgument()); if (m_buffer != nullptr) { while (src_size > 0) { if (u32 cur = std::min<u32>(m_buffer_size - m_buffer_count, src_size); cur > 0) { std::memcpy(m_buffer + m_buffer_count, src, cur); m_buffer_count += cur; src += cur; src_size -= cur; } if (m_buffer_count == m_buffer_size) { R_TRY(this->Flush()); } } } else { R_TRY(fs::WriteFile(m_file_handle, m_file_position, src, src_size, fs::WriteOption::None)); m_file_position += src_size; } R_SUCCEED(); } void Stream::CloseStream() { if (m_initialized) { if (s_can_access_fs) { if (m_stream_mode == StreamMode_Write) { const auto self_flush_res = this->Flush(); R_ASSERT(self_flush_res); AMS_UNUSED(self_flush_res); const auto file_flush_res = fs::FlushFile(m_file_handle); R_ASSERT(file_flush_res); AMS_UNUSED(file_flush_res); } fs::CloseFile(m_file_handle); } if (m_buffer != nullptr) { Deallocate(m_buffer); } m_initialized = false; if (s_fs_commit_mutex.IsLockedByCurrentThread()) { s_fs_commit_mutex.Unlock(); } } } Result Stream::GetStreamSize(s64 *out) const { R_RETURN(GetStreamSize(out, m_file_name)); } Result Stream::Flush() { AMS_ASSERT(s_fs_commit_mutex.IsLockedByCurrentThread()); R_SUCCEED_IF(m_buffer_count == 0); R_TRY(fs::WriteFile(m_file_handle, m_file_position, m_buffer, m_buffer_count, fs::WriteOption::None)); m_file_position += m_buffer_count; m_buffer_count = 0; R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/erpt/srv/erpt_srv_stream.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::erpt::srv { enum StreamMode { StreamMode_Write = 0, StreamMode_Read = 1, StreamMode_Invalid = 2, }; class Stream { private: static bool s_can_access_fs; static os::SdkMutex s_fs_commit_mutex; private: u32 m_buffer_size; u32 m_file_position; u32 m_buffer_position; u32 m_buffer_count; u8 *m_buffer; StreamMode m_stream_mode; bool m_initialized; fs::FileHandle m_file_handle; char m_file_name[ReportFileNameLength]; public: Stream(); ~Stream(); Result OpenStream(const char *path, StreamMode mode, u32 buffer_size); Result ReadStream(u32 *out, u8 *dst, u32 dst_size); Result WriteStream(const u8 *src, u32 src_size); void CloseStream(); Result GetStreamSize(s64 *out) const; private: Result Flush(); public: static void EnableFsAccess(bool en); static Result DeleteStream(const char *path); static Result CommitStream(); static Result GetStreamSize(s64 *out, const char *path); }; } ================================================ FILE: libraries/libstratosphere/source/err/err_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/err_string_util.hpp" namespace ams::err { namespace impl { namespace { constexpr int ErrorCodeCategoryPlatformPrefixForResultModule = 2000; ALWAYS_INLINE ErrorCode ConvertResultToErrorCode(const Result &result) { return { .category = static_cast<ErrorCodeCategory>(ErrorCodeCategoryPlatformPrefixForResultModule + result.GetModule()), .number = static_cast<ErrorCodeNumber>(result.GetDescription()), }; } [[maybe_unused]] ALWAYS_INLINE Result ConvertErrorCodeToResult(const ErrorCode &error_code) { const auto result_value = ::ams::result::impl::ResultTraits::MakeValue(error_code.category - ErrorCodeCategoryPlatformPrefixForResultModule, error_code.number); return ::ams::result::impl::MakeResult(result_value); } } } ErrorCode ConvertResultToErrorCode(const Result &result) { AMS_ASSERT(R_FAILED(result)); return ::ams::err::impl::ConvertResultToErrorCode(result); } void GetErrorCodeString(char *dst, size_t dst_size, ErrorCode error_code) { AMS_ASSERT(dst != nullptr); AMS_ASSERT(dst_size >= static_cast<size_t>(ErrorCode::StringLengthMax)); AMS_ASSERT(error_code.IsValid()); return ::ams::err::impl::MakeErrorCodeString(dst, dst_size, error_code); } } ================================================ FILE: libraries/libstratosphere/source/err/impl/err_string_util.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "err_string_util.hpp" namespace ams::err::impl { void MakeErrorCodeString(char *dst, size_t dst_size, ErrorCode error_code) { const auto len = util::TSNPrintf(dst, dst_size, "%04d-%04d", error_code.category, error_code.number); AMS_ASSERT(static_cast<size_t>(len) < dst_size); AMS_UNUSED(len); } } ================================================ FILE: libraries/libstratosphere/source/err/impl/err_string_util.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::err::impl { void MakeErrorCodeString(char *dst, size_t dst_size, ErrorCode error_code); } ================================================ FILE: libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { s64 HierarchicalRomFileTable::QueryDirectoryEntryBucketStorageSize(StorageSizeType count) { return DirectoryEntryMapTable::QueryBucketStorageSize(count); } s64 HierarchicalRomFileTable::QueryDirectoryEntrySize(StorageSizeType aux_size) { return DirectoryEntryMapTable::QueryEntrySize(aux_size); } s64 HierarchicalRomFileTable::QueryFileEntryBucketStorageSize(StorageSizeType count) { return FileEntryMapTable::QueryBucketStorageSize(count); } s64 HierarchicalRomFileTable::QueryFileEntrySize(StorageSizeType aux_size) { return FileEntryMapTable::QueryEntrySize(aux_size); } Result HierarchicalRomFileTable::Format(SubStorage dir_bucket, SubStorage file_bucket) { s64 dir_bucket_size; R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size))); R_TRY(DirectoryEntryMapTable::Format(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size))); s64 file_bucket_size; R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size))); R_TRY(FileEntryMapTable::Format(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size))); R_SUCCEED(); } HierarchicalRomFileTable::HierarchicalRomFileTable() { /* ... */ } Result HierarchicalRomFileTable::Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry) { s64 dir_bucket_size; R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size))); R_TRY(m_dir_table.Initialize(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry)); s64 file_bucket_size; R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size))); R_TRY(m_file_table.Initialize(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry)); R_SUCCEED(); } void HierarchicalRomFileTable::Finalize() { m_dir_table.Finalize(); m_file_table.Finalize(); } Result HierarchicalRomFileTable::CreateRootDirectory() { Position root_pos = RootPosition; EntryKey root_key = {}; root_key.key.parent = root_pos; RomDirectoryEntry root_entry = { .next = InvalidPosition, .dir = InvalidPosition, .file = InvalidPosition, }; R_RETURN(m_dir_table.Add(std::addressof(root_pos), root_key, root_entry)); } Result HierarchicalRomFileTable::CreateDirectory(RomDirectoryId *out, const RomPathChar *path) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey new_key = {}; R_TRY(this->FindDirectoryRecursive(std::addressof(new_key), std::addressof(parent_entry), path)); R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists())); RomDirectoryEntry new_entry = { .next = InvalidPosition, .dir = InvalidPosition, .file = InvalidPosition, }; Position new_pos = 0; R_TRY_CATCH(m_dir_table.Add(std::addressof(new_pos), new_key, new_entry)) { R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull()) } R_END_TRY_CATCH; *out = PositionToDirectoryId(new_pos); if (parent_entry.dir == InvalidPosition) { parent_entry.dir = new_pos; R_TRY(m_dir_table.SetByPosition(new_key.key.parent, parent_entry)); } else { Position cur_pos = parent_entry.dir; while (true) { RomEntryKey cur_key = {}; RomDirectoryEntry cur_entry = {}; R_TRY(m_dir_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos)); if (cur_entry.next == InvalidPosition) { cur_entry.next = new_pos; R_TRY(m_dir_table.SetByPosition(cur_pos, cur_entry)); break; } cur_pos = cur_entry.next; } } R_SUCCEED(); } Result HierarchicalRomFileTable::CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey new_key = {}; R_TRY(this->FindFileRecursive(std::addressof(new_key), std::addressof(parent_entry), path)); R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists())); RomFileEntry new_entry = { .next = InvalidPosition, .info = info, }; Position new_pos = 0; R_TRY_CATCH(m_file_table.Add(std::addressof(new_pos), new_key, new_entry)) { R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull()) } R_END_TRY_CATCH; *out = PositionToFileId(new_pos); if (parent_entry.file == InvalidPosition) { parent_entry.file = new_pos; R_TRY(m_dir_table.SetByPosition(new_key.key.parent, parent_entry)); } else { Position cur_pos = parent_entry.file; while (true) { RomEntryKey cur_key = {}; RomFileEntry cur_entry = {}; R_TRY(m_file_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos)); if (cur_entry.next == InvalidPosition) { cur_entry.next = new_pos; R_TRY(m_file_table.SetByPosition(cur_pos, cur_entry)); break; } cur_pos = cur_entry.next; } } R_SUCCEED(); } Result HierarchicalRomFileTable::ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey key = {}; R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path)); Position pos = 0; RomDirectoryEntry entry = {}; R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); *out = PositionToDirectoryId(pos); R_SUCCEED(); } Result HierarchicalRomFileTable::ConvertPathToFileId(RomFileId *out, const RomPathChar *path) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey key = {}; R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path)); Position pos = 0; RomFileEntry entry = {}; R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key)); *out = PositionToFileId(pos); R_SUCCEED(); } Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const RomPathChar *path) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey key = {}; R_TRY(this->FindFileRecursive(std::addressof(key), std::addressof(parent_entry), path)); R_RETURN(this->OpenFile(out, key)); } Result HierarchicalRomFileTable::OpenFile(FileInfo *out, RomFileId id) { AMS_ASSERT(out != nullptr); RomFileEntry entry = {}; R_TRY(this->GetFileEntry(std::addressof(entry), id)); *out = entry.info; R_SUCCEED(); } Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const RomPathChar *path) { AMS_ASSERT(out != nullptr); AMS_ASSERT(path != nullptr); RomDirectoryEntry parent_entry = {}; EntryKey key = {}; R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path)); R_RETURN(this->FindOpen(out, key)); } Result HierarchicalRomFileTable::FindOpen(FindPosition *out, RomDirectoryId id) { AMS_ASSERT(out != nullptr); out->next_dir = InvalidPosition; out->next_file = InvalidPosition; RomDirectoryEntry entry = {}; R_TRY(this->GetDirectoryEntry(std::addressof(entry), id)); out->next_dir = entry.dir; out->next_file = entry.file; R_SUCCEED(); } Result HierarchicalRomFileTable::FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length) { AMS_ASSERT(out != nullptr); AMS_ASSERT(find != nullptr); AMS_ASSERT(length > RomPathTool::MaxPathLength); AMS_UNUSED(length); R_UNLESS(find->next_dir != InvalidPosition, fs::ResultDbmFindFinished()); RomEntryKey key = {}; RomDirectoryEntry entry = {}; size_t aux_size = 0; R_TRY(m_dir_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_dir)); AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength); out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator; find->next_dir = entry.next; R_SUCCEED(); } Result HierarchicalRomFileTable::FindNextFile(RomPathChar *out, FindPosition *find, size_t length) { AMS_ASSERT(out != nullptr); AMS_ASSERT(find != nullptr); AMS_ASSERT(length > RomPathTool::MaxPathLength); AMS_UNUSED(length); R_UNLESS(find->next_file != InvalidPosition, fs::ResultDbmFindFinished()); RomEntryKey key = {}; RomFileEntry entry = {}; size_t aux_size = 0; R_TRY(m_file_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_file)); AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength); out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator; find->next_file = entry.next; R_SUCCEED(); } Result HierarchicalRomFileTable::QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size) { AMS_ASSERT(out_dir_entry_size != nullptr); AMS_ASSERT(out_file_entry_size != nullptr); *out_dir_entry_size = m_dir_table.GetTotalEntrySize(); *out_file_entry_size = m_file_table.GetTotalEntrySize(); R_SUCCEED(); } Result HierarchicalRomFileTable::GetParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_dir_key != nullptr); AMS_ASSERT(out_dir_entry != nullptr); AMS_ASSERT(path != nullptr); RomEntryKey p_key = {}; RomDirectoryEntry p_entry = {}; R_TRY(m_dir_table.GetByPosition(std::addressof(p_key), std::addressof(p_entry), pos)); out_dir_key->key = p_key; R_TRY(RomPathTool::GetParentDirectoryName(std::addressof(out_dir_key->name), name, path)); R_TRY(this->GetDirectoryEntry(out_pos, out_dir_entry, *out_dir_key)); R_SUCCEED(); } Result HierarchicalRomFileTable::FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_dir_key != nullptr); AMS_ASSERT(out_dir_entry != nullptr); AMS_ASSERT(parser != nullptr); AMS_ASSERT(path != nullptr); Position dir_pos = RootPosition; EntryKey dir_key = {}; RomDirectoryEntry dir_entry = {}; dir_key.key.parent = RootPosition; R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name))); R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)); Position parent_pos = dir_pos; while (!parser->IsParseFinished()) { EntryKey old_key = dir_key; R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name))); if (dir_key.name.IsCurrentDirectory()) { dir_key = old_key; continue; } else if (dir_key.name.IsParentDirectory()) { R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable()); R_TRY(this->GetParent(std::addressof(parent_pos), std::addressof(dir_key), std::addressof(dir_entry), dir_key.key.parent, dir_key.name, path)); } else { dir_key.key.parent = parent_pos; R_TRY_CATCH(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)) { R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultDbmNotFound()) } R_END_TRY_CATCH; parent_pos = dir_pos; } } *out_pos = parent_pos; *out_dir_key = dir_key; *out_dir_entry = dir_entry; R_SUCCEED(); } Result HierarchicalRomFileTable::FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path) { AMS_ASSERT(out_key != nullptr); AMS_ASSERT(out_dir_entry != nullptr); AMS_ASSERT(path != nullptr); RomPathTool::PathParser parser; R_TRY(parser.Initialize(path)); EntryKey parent_key = {}; Position parent_pos = 0; R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), std::addressof(parent_key), out_dir_entry, std::addressof(parser), path)); if (is_dir) { RomPathTool::RomEntryName name = {}; R_TRY(parser.GetAsDirectoryName(std::addressof(name))); if (name.IsCurrentDirectory()) { *out_key = parent_key; if (out_key->key.parent != RootPosition) { Position pos = 0; R_TRY(this->GetParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path)); } } else if (name.IsParentDirectory()) { R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable()); Position pos = 0; RomDirectoryEntry cur_entry = {}; R_TRY(this->GetParent(std::addressof(pos), out_key, std::addressof(cur_entry), parent_key.key.parent, parent_key.name, path)); if (out_key->key.parent != RootPosition) { R_TRY(this->GetParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path)); } } else { out_key->name = name; out_key->key.parent = out_key->name.IsRootDirectory() ? RootPosition : parent_pos; } } else { { RomPathTool::RomEntryName name = {}; R_TRY(parser.GetAsDirectoryName(std::addressof(name))); R_UNLESS(!name.IsParentDirectory() || parent_pos != RootPosition, fs::ResultDirectoryUnobtainable()); } R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation()); out_key->key.parent = parent_pos; R_TRY(parser.GetAsFileName(std::addressof(out_key->name))); } R_SUCCEED(); } Result HierarchicalRomFileTable::FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) { AMS_ASSERT(out_key != nullptr); AMS_ASSERT(out_dir_entry != nullptr); AMS_ASSERT(path != nullptr); R_RETURN(this->FindPathRecursive(out_key, out_dir_entry, true, path)); } Result HierarchicalRomFileTable::FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) { AMS_ASSERT(out_key != nullptr); AMS_ASSERT(out_dir_entry != nullptr); AMS_ASSERT(path != nullptr); R_RETURN(this->FindPathRecursive(out_key, out_dir_entry, false, path)); } Result HierarchicalRomFileTable::CheckSameEntryExists(const EntryKey &key, Result if_exists) { /* Check dir */ { Position pos = InvalidPosition; RomDirectoryEntry entry = {}; const Result get_res = m_dir_table.Get(std::addressof(pos), std::addressof(entry), key); if (!fs::ResultDbmKeyNotFound::Includes(get_res)) { R_TRY(get_res); R_THROW(if_exists); } } /* Check file */ { Position pos = InvalidPosition; RomFileEntry entry = {}; const Result get_res = m_file_table.Get(std::addressof(pos), std::addressof(entry), key); if (!fs::ResultDbmKeyNotFound::Includes(get_res)) { R_TRY(get_res); R_THROW(if_exists); } } R_SUCCEED(); } Result HierarchicalRomFileTable::GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_entry != nullptr); const Result dir_res = m_dir_table.Get(out_pos, out_entry, key); R_UNLESS(R_FAILED(dir_res), dir_res); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res); Position pos = 0; RomFileEntry entry = {}; const Result file_res = m_file_table.Get(std::addressof(pos), std::addressof(entry), key); R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation()); R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound()); R_RETURN(file_res); } Result HierarchicalRomFileTable::GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) { AMS_ASSERT(out_entry != nullptr); Position pos = DirectoryIdToPosition(id); RomEntryKey key = {}; const Result dir_res = m_dir_table.GetByPosition(std::addressof(key), out_entry, pos); R_UNLESS(R_FAILED(dir_res), dir_res); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res); RomFileEntry entry = {}; const Result file_res = m_file_table.GetByPosition(std::addressof(key), std::addressof(entry), pos); R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation()); R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound()); R_RETURN(file_res); } Result HierarchicalRomFileTable::GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) { AMS_ASSERT(out_pos != nullptr); AMS_ASSERT(out_entry != nullptr); const Result file_res = m_file_table.Get(out_pos, out_entry, key); R_UNLESS(R_FAILED(file_res), file_res); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res); Position pos = 0; RomDirectoryEntry entry = {}; const Result dir_res = m_dir_table.Get(std::addressof(pos), std::addressof(entry), key); R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation()); R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound()); R_RETURN(dir_res); } Result HierarchicalRomFileTable::GetFileEntry(RomFileEntry *out_entry, RomFileId id) { AMS_ASSERT(out_entry != nullptr); Position pos = FileIdToPosition(id); RomEntryKey key = {}; const Result file_res = m_file_table.GetByPosition(std::addressof(key), out_entry, pos); R_UNLESS(R_FAILED(file_res), file_res); R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res); RomDirectoryEntry entry = {}; const Result dir_res = m_dir_table.GetByPosition(std::addressof(key), std::addressof(entry), pos); R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation()); R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound()); R_RETURN(dir_res); } Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const EntryKey &key) { AMS_ASSERT(out != nullptr); Position pos = 0; RomFileEntry entry = {}; R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key)); *out = entry.info; R_SUCCEED(); } Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const EntryKey &key) { AMS_ASSERT(out != nullptr); out->next_dir = InvalidPosition; out->next_file = InvalidPosition; Position pos = 0; RomDirectoryEntry entry = {}; R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key)); out->next_dir = entry.dir; out->next_file = entry.file; R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs::RomPathTool { Result PathParser::Initialize(const RomPathChar *path) { AMS_ASSERT(path != nullptr); /* Require paths start with a separator, and skip repeated separators. */ R_UNLESS(RomPathTool::IsSeparator(path[0]), fs::ResultDbmInvalidPathFormat()); while (RomPathTool::IsSeparator(path[1])) { ++path; } m_prev_path_start = path; m_prev_path_end = path; m_next_path = path + 1; R_SUCCEED(); } void PathParser::Finalize() { m_prev_path_start = nullptr; m_prev_path_end = nullptr; m_next_path = nullptr; m_finished = false; } bool PathParser::IsParseFinished() const { return m_finished; } bool PathParser::IsDirectoryPath() const { AMS_ASSERT(m_next_path != nullptr); if (RomPathTool::IsNullTerminator(m_next_path[0]) && RomPathTool::IsSeparator(m_next_path[-1])) { return true; } if (RomPathTool::IsCurrentDirectory(m_next_path)) { return true; } return RomPathTool::IsParentDirectory(m_next_path); } Result PathParser::GetNextDirectoryName(RomEntryName *out) { AMS_ASSERT(m_prev_path_start != nullptr); AMS_ASSERT(m_prev_path_end != nullptr); AMS_ASSERT(m_next_path != nullptr); AMS_ASSERT(out != nullptr); /* Get as directory name. */ R_TRY(this->GetAsDirectoryName(out)); /* Parse the next path. */ const RomPathChar *cur = m_next_path; size_t name_len; for (name_len = 0; !RomPathTool::IsSeparator(cur[name_len]); ++name_len) { if (RomPathTool::IsNullTerminator(cur[name_len])) { m_finished = true; m_prev_path_start = m_next_path; m_next_path = cur + name_len; m_prev_path_end = cur + name_len; R_SUCCEED(); } } /* Advance past separators. */ m_prev_path_start = m_next_path; m_prev_path_end = cur + name_len; for (m_next_path = m_prev_path_end + 1; RomPathTool::IsSeparator(m_next_path[0]); ++m_next_path) { /* ... */ } /* Check if we're finished. */ if (RomPathTool::IsNullTerminator(m_next_path[0])) { m_finished = true; } R_SUCCEED(); } Result PathParser::GetAsDirectoryName(RomEntryName *out) const { AMS_ASSERT(out != nullptr); AMS_ASSERT(m_prev_path_start != nullptr); AMS_ASSERT(m_prev_path_end != nullptr); AMS_ASSERT(m_next_path != nullptr); AMS_ASSERT(m_prev_path_start <= m_prev_path_end); const size_t len = m_prev_path_end - m_prev_path_start; R_UNLESS(len <= MaxPathLength, fs::ResultDbmDirectoryNameTooLong()); out->Initialize(m_prev_path_start, len); R_SUCCEED(); } Result PathParser::GetAsFileName(RomEntryName *out) const { AMS_ASSERT(out != nullptr); AMS_ASSERT(m_prev_path_start != nullptr); AMS_ASSERT(m_prev_path_end != nullptr); AMS_ASSERT(m_next_path != nullptr); AMS_ASSERT(m_prev_path_start <= m_prev_path_end); const size_t len = m_prev_path_end - m_prev_path_start; R_UNLESS(len <= MaxPathLength, fs::ResultDbmFileNameTooLong()); out->Initialize(m_prev_path_start, len); R_SUCCEED(); } Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) { AMS_ASSERT(out != nullptr); AMS_ASSERT(p != nullptr); const RomPathChar *start = cur.begin(); const RomPathChar *end = cur.end() - 1; s32 depth = 1; if (cur.IsParentDirectory()) { ++depth; } if (start > p) { size_t len = 0; for (const RomPathChar *head = start - 1; head >= p; --head) { if (RomPathTool::IsSeparator(*head)) { if (IsCurrentDirectory(head + 1, len)) { ++depth; } if (IsParentDirectory(head + 1, len)) { depth += 2; } if (depth == 0) { start = head + 1; break; } do { --head; } while (head > p && RomPathTool::IsSeparator(*head)); end = head; len = 0; --depth; } ++len; } R_UNLESS(depth == 0, fs::ResultDirectoryUnobtainable()); } if (end <= p) { out->Initialize(p, 0); } else { out->Initialize(start, end - start + 1); } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/common/fs_file_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { Result FileStorage::UpdateSize() { R_SUCCEED_IF(m_size != InvalidSize); R_RETURN(m_base_file->GetSize(std::addressof(m_size))); } Result FileStorage::Read(s64 offset, void *buffer, size_t size) { /* Immediately succeed if there's nothing to read. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); size_t read_size; R_RETURN(m_base_file->Read(std::addressof(read_size), offset, buffer, size)); } Result FileStorage::Write(s64 offset, const void *buffer, size_t size) { /* Immediately succeed if there's nothing to write. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(m_base_file->Write(offset, buffer, size, fs::WriteOption())); } Result FileStorage::Flush() { R_RETURN(m_base_file->Flush()); } Result FileStorage::GetSize(s64 *out_size) { R_TRY(this->UpdateSize()); *out_size = m_size; R_SUCCEED(); } Result FileStorage::SetSize(s64 size) { m_size = InvalidSize; R_RETURN(m_base_file->SetSize(size)); } Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { switch (op_id) { case OperationId::Invalidate: R_RETURN(m_base_file->OperateRange(OperationId::Invalidate, offset, size)); case OperationId::QueryRange: if (size == 0) { R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); reinterpret_cast<QueryRangeInfo *>(dst)->Clear(); R_SUCCEED(); } R_TRY(this->UpdateSize()); R_TRY(IStorage::CheckOffsetAndSize(offset, size)); R_RETURN(m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); default: R_THROW(fs::ResultUnsupportedOperateRangeForFileStorage()); } } Result FileStorageBasedFileSystem::Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode) { /* Open the file. */ std::unique_ptr<fs::fsa::IFile> base_file; R_TRY(base_file_system->OpenFile(std::addressof(base_file), path, mode)); /* Set the file. */ this->SetFile(std::move(base_file)); m_base_file_system = std::move(base_file_system); R_SUCCEED(); } Result FileHandleStorage::UpdateSize() { R_SUCCEED_IF(m_size != InvalidSize); R_RETURN(GetFileSize(std::addressof(m_size), m_handle)); } Result FileHandleStorage::Read(s64 offset, void *buffer, size_t size) { /* Lock the mutex. */ std::scoped_lock lk(m_mutex); /* Immediately succeed if there's nothing to read. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(ReadFile(m_handle, offset, buffer, size, fs::ReadOption())); } Result FileHandleStorage::Write(s64 offset, const void *buffer, size_t size) { /* Lock the mutex. */ std::scoped_lock lk(m_mutex); /* Immediately succeed if there's nothing to write. */ R_SUCCEED_IF(size == 0); /* Validate buffer. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure our size is valid. */ R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); R_RETURN(WriteFile(m_handle, offset, buffer, size, fs::WriteOption())); } Result FileHandleStorage::Flush() { R_RETURN(FlushFile(m_handle)); } Result FileHandleStorage::GetSize(s64 *out_size) { R_TRY(this->UpdateSize()); *out_size = m_size; R_SUCCEED(); } Result FileHandleStorage::SetSize(s64 size) { m_size = InvalidSize; R_RETURN(SetFileSize(m_handle, size)); } Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { AMS_UNUSED(src, src_size); switch (op_id) { case OperationId::QueryRange: /* Validate buffer and size. */ R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); R_RETURN(QueryRange(static_cast<QueryRangeInfo *>(dst), m_handle, offset, size)); default: R_THROW(fs::ResultUnsupportedOperateRangeForFileHandleStorage()); } } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_access_log.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/fs_file_system_proxy_service_object.hpp" #include "fsa/fs_user_mount_table.hpp" #include "fsa/fs_directory_accessor.hpp" #include "fsa/fs_file_accessor.hpp" #include "fsa/fs_filesystem_accessor.hpp" #define AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION "ams_version: " STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MAJOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MINOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MICRO) /* TODO: Other specs? */ #define AMS_FS_IMPL_ACCESS_LOG_SPEC "spec: NX" namespace ams::fs { /* Forward declare priority getter. */ fs::PriorityRaw GetPriorityRawOnCurrentThreadInternal(); namespace { constinit u32 g_global_access_log_mode = fs::AccessLogMode_None; constinit u32 g_local_access_log_target = fs::impl::AccessLogTarget_None; constinit std::atomic_bool g_access_log_initialized = false; constinit os::SdkMutex g_access_log_initialization_mutex; void SetLocalAccessLogImpl(bool enabled) { if (enabled) { g_local_access_log_target |= fs::impl::AccessLogTarget_Application; } else { g_local_access_log_target &= ~fs::impl::AccessLogTarget_Application; } } } Result GetGlobalAccessLogMode(u32 *out) { const auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->GetGlobalAccessLogMode(out)); R_SUCCEED(); } Result SetGlobalAccessLogMode(u32 mode) { const auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->SetGlobalAccessLogMode(mode)); R_SUCCEED(); } void SetLocalAccessLog(bool enabled) { SetLocalAccessLogImpl(enabled); } void SetLocalApplicationAccessLog(bool enabled) { SetLocalAccessLogImpl(enabled); } void SetLocalSystemAccessLogForDebug(bool enabled) { #if defined(AMS_BUILD_FOR_DEBUGGING) if (enabled) { g_local_access_log_target |= (fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System); } else { g_local_access_log_target &= ~(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System); } #else AMS_UNUSED(enabled); #endif } } namespace ams::fs::impl { #define ADD_ENUM_CASE(v) case v: return #v const char *IdString::ToValueString(int id) { const int len = util::SNPrintf(m_buffer, sizeof(m_buffer), "%d", id); AMS_ASSERT(static_cast<size_t>(len) < sizeof(m_buffer)); AMS_UNUSED(len); return m_buffer; } template<> const char *IdString::ToString<fs::Priority>(fs::Priority id) { switch (id) { case fs::Priority_Realtime: return "Realtime"; case fs::Priority_Normal: return "Normal"; case fs::Priority_Low: return "Low"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::PriorityRaw>(fs::PriorityRaw id) { switch (id) { case fs::PriorityRaw_Realtime: return "Realtime"; case fs::PriorityRaw_Normal: return "Normal"; case fs::PriorityRaw_Low: return "Low"; case fs::PriorityRaw_Background: return "Realtime"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::ContentStorageId>(fs::ContentStorageId id) { switch (id) { using enum fs::ContentStorageId; ADD_ENUM_CASE(User); ADD_ENUM_CASE(System); ADD_ENUM_CASE(SdCard); ADD_ENUM_CASE(System0); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::SaveDataSpaceId>(fs::SaveDataSpaceId id) { switch (id) { using enum fs::SaveDataSpaceId; ADD_ENUM_CASE(System); ADD_ENUM_CASE(User); ADD_ENUM_CASE(SdSystem); ADD_ENUM_CASE(ProperSystem); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::ContentType>(fs::ContentType id) { switch (id) { case fs::ContentType_Meta: return "Meta"; case fs::ContentType_Control: return "Control"; case fs::ContentType_Manual: return "Manual"; case fs::ContentType_Logo: return "Logo"; case fs::ContentType_Data: return "Data"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::MountHostOption>(fs::MountHostOption id) { if (id == MountHostOption::PseudoCaseSensitive) { return "MountHostOptionFlag_PseudoCaseSensitive"; } else { return ToValueString(static_cast<int>(id._value)); } } template<> const char *IdString::ToString<fs::BisPartitionId>(fs::BisPartitionId id) { switch (id) { using enum fs::BisPartitionId; ADD_ENUM_CASE(BootPartition1Root); ADD_ENUM_CASE(BootPartition2Root); ADD_ENUM_CASE(UserDataRoot); ADD_ENUM_CASE(BootConfigAndPackage2Part1); ADD_ENUM_CASE(BootConfigAndPackage2Part2); ADD_ENUM_CASE(BootConfigAndPackage2Part3); ADD_ENUM_CASE(BootConfigAndPackage2Part4); ADD_ENUM_CASE(BootConfigAndPackage2Part5); ADD_ENUM_CASE(BootConfigAndPackage2Part6); ADD_ENUM_CASE(CalibrationBinary); ADD_ENUM_CASE(CalibrationFile); ADD_ENUM_CASE(SafeMode); ADD_ENUM_CASE(User); ADD_ENUM_CASE(System); ADD_ENUM_CASE(SystemProperEncryption); ADD_ENUM_CASE(SystemProperPartition); ADD_ENUM_CASE(DeviceTreeBlob); ADD_ENUM_CASE(System0); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::DirectoryEntryType>(fs::DirectoryEntryType type) { switch (type) { case fs::DirectoryEntryType_Directory: return "Directory"; case fs::DirectoryEntryType_File: return "File"; default: return ToValueString(static_cast<int>(type)); } } template<> const char *IdString::ToString<fs::GameCardPartition>(fs::GameCardPartition id) { switch (id) { using enum fs::GameCardPartition; ADD_ENUM_CASE(Update); ADD_ENUM_CASE(Normal); ADD_ENUM_CASE(Secure); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaHeader::ContentType>(fssystem::NcaHeader::ContentType id) { switch (id) { using enum fssystem::NcaHeader::ContentType; ADD_ENUM_CASE(Program); ADD_ENUM_CASE(Meta); ADD_ENUM_CASE(Control); ADD_ENUM_CASE(Manual); ADD_ENUM_CASE(Data); ADD_ENUM_CASE(PublicData); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaHeader::DistributionType>(fssystem::NcaHeader::DistributionType id) { switch (id) { using enum fssystem::NcaHeader::DistributionType; ADD_ENUM_CASE(Download); ADD_ENUM_CASE(GameCard); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaHeader::EncryptionType>(fssystem::NcaHeader::EncryptionType id) { switch (id) { using enum fssystem::NcaHeader::EncryptionType; ADD_ENUM_CASE(Auto); ADD_ENUM_CASE(None); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaHeader::DecryptionKey>(fssystem::NcaHeader::DecryptionKey id) { switch (id) { using enum fssystem::NcaHeader::DecryptionKey; case DecryptionKey_AesXts1: return "AesXts1"; case DecryptionKey_AesXts2: return "AesXts2"; case DecryptionKey_AesCtr: return "AesCtr"; case DecryptionKey_AesCtrEx: return "AesCtrEx"; case DecryptionKey_AesCtrHw: return "AesCtrHw"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaFsHeader::FsType>(fssystem::NcaFsHeader::FsType id) { switch (id) { using enum fssystem::NcaFsHeader::FsType; ADD_ENUM_CASE(RomFs); ADD_ENUM_CASE(PartitionFs); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaFsHeader::EncryptionType>(fssystem::NcaFsHeader::EncryptionType id) { switch (id) { using enum fssystem::NcaFsHeader::EncryptionType; ADD_ENUM_CASE(Auto); ADD_ENUM_CASE(None); ADD_ENUM_CASE(AesXts); ADD_ENUM_CASE(AesCtr); ADD_ENUM_CASE(AesCtrEx); ADD_ENUM_CASE(AesCtrSkipLayerHash); ADD_ENUM_CASE(AesCtrExSkipLayerHash); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaFsHeader::HashType>(fssystem::NcaFsHeader::HashType id) { switch (id) { using enum fssystem::NcaFsHeader::HashType; ADD_ENUM_CASE(Auto); ADD_ENUM_CASE(None); ADD_ENUM_CASE(HierarchicalSha256Hash); ADD_ENUM_CASE(HierarchicalIntegrityHash); ADD_ENUM_CASE(AutoSha3); ADD_ENUM_CASE(HierarchicalSha3256Hash); ADD_ENUM_CASE(HierarchicalIntegritySha3Hash); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssystem::NcaFsHeader::MetaDataHashType>(fssystem::NcaFsHeader::MetaDataHashType id) { switch (id) { using enum fssystem::NcaFsHeader::MetaDataHashType; ADD_ENUM_CASE(None); ADD_ENUM_CASE(HierarchicalIntegrity); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<gc::impl::MemoryCapacity>(gc::impl::MemoryCapacity id) { switch (id) { using enum gc::impl::MemoryCapacity; case MemoryCapacity_1GB: return "1GB"; case MemoryCapacity_2GB: return "2GB"; case MemoryCapacity_4GB: return "4GB"; case MemoryCapacity_8GB: return "8GB"; case MemoryCapacity_16GB: return "16GB"; case MemoryCapacity_32GB: return "32GB"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<gc::impl::SelSec>(gc::impl::SelSec id) { switch (id) { using enum gc::impl::SelSec; case SelSec_T1: return "T1"; case SelSec_T2: return "T2"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<gc::impl::KekIndex>(gc::impl::KekIndex id) { switch (id) { using enum gc::impl::KekIndex; case KekIndex_Version0: return "Version0"; case KekIndex_VersionForDev: return "VersionForDev"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<gc::impl::AccessControl1ClockRate>(gc::impl::AccessControl1ClockRate id) { switch (id) { using enum gc::impl::AccessControl1ClockRate; case AccessControl1ClockRate_25MHz: return "25 MHz"; case AccessControl1ClockRate_50MHz: return "50 MHz"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<gc::impl::FwVersion>(gc::impl::FwVersion id) { switch (id) { using enum gc::impl::FwVersion; case FwVersion_ForDev: return "ForDev"; case FwVersion_1_0_0: return "1.0.0"; case FwVersion_4_0_0: return "4.0.0"; case FwVersion_9_0_0: return "9.0.0"; case FwVersion_11_0_0: return "11.0.0"; case FwVersion_12_0_0: return "12.0.0"; default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fs::GameCardCompatibilityType>(fs::GameCardCompatibilityType id) { switch (id) { using enum fs::GameCardCompatibilityType; ADD_ENUM_CASE(Normal); ADD_ENUM_CASE(Terra); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssrv::impl::AccessControlBits::Bits>(fssrv::impl::AccessControlBits::Bits id) { switch (id) { using enum fssrv::impl::AccessControlBits::Bits; ADD_ENUM_CASE(ApplicationInfo); ADD_ENUM_CASE(BootModeControl); ADD_ENUM_CASE(Calibration); ADD_ENUM_CASE(SystemSaveData); ADD_ENUM_CASE(GameCard); ADD_ENUM_CASE(SaveDataBackUp); ADD_ENUM_CASE(SaveDataManagement); ADD_ENUM_CASE(BisAllRaw); ADD_ENUM_CASE(GameCardRaw); ADD_ENUM_CASE(GameCardPrivate); ADD_ENUM_CASE(SetTime); ADD_ENUM_CASE(ContentManager); ADD_ENUM_CASE(ImageManager); ADD_ENUM_CASE(CreateSaveData); ADD_ENUM_CASE(SystemSaveDataManagement); ADD_ENUM_CASE(BisFileSystem); ADD_ENUM_CASE(SystemUpdate); ADD_ENUM_CASE(SaveDataMeta); ADD_ENUM_CASE(DeviceSaveData); ADD_ENUM_CASE(SettingsControl); ADD_ENUM_CASE(SystemData); ADD_ENUM_CASE(SdCard); ADD_ENUM_CASE(Host); ADD_ENUM_CASE(FillBis); ADD_ENUM_CASE(CorruptSaveData); ADD_ENUM_CASE(SaveDataForDebug); ADD_ENUM_CASE(FormatSdCard); ADD_ENUM_CASE(GetRightsId); ADD_ENUM_CASE(RegisterExternalKey); ADD_ENUM_CASE(RegisterUpdatePartition); ADD_ENUM_CASE(SaveDataTransfer); ADD_ENUM_CASE(DeviceDetection); ADD_ENUM_CASE(AccessFailureResolution); ADD_ENUM_CASE(SaveDataTransferVersion2); ADD_ENUM_CASE(RegisterProgramIndexMapInfo); ADD_ENUM_CASE(CreateOwnSaveData); ADD_ENUM_CASE(MoveCacheStorage); ADD_ENUM_CASE(Debug); ADD_ENUM_CASE(FullPermission); default: return ToValueString(util::CountTrailingZeros(util::ToUnderlying(id))); } } template<> const char *IdString::ToString<fssrv::impl::AccessControl::AccessibilityType>(fssrv::impl::AccessControl::AccessibilityType id) { switch (id) { using enum fssrv::impl::AccessControl::AccessibilityType; ADD_ENUM_CASE(MountLogo); ADD_ENUM_CASE(MountContentMeta); ADD_ENUM_CASE(MountContentControl); ADD_ENUM_CASE(MountContentManual); ADD_ENUM_CASE(MountContentData); ADD_ENUM_CASE(MountApplicationPackage); ADD_ENUM_CASE(MountSaveDataStorage); ADD_ENUM_CASE(MountContentStorage); ADD_ENUM_CASE(MountImageAndVideoStorage); ADD_ENUM_CASE(MountCloudBackupWorkStorage); ADD_ENUM_CASE(MountCustomStorage); ADD_ENUM_CASE(MountBisCalibrationFile); ADD_ENUM_CASE(MountBisSafeMode); ADD_ENUM_CASE(MountBisUser); ADD_ENUM_CASE(MountBisSystem); ADD_ENUM_CASE(MountBisSystemProperEncryption); ADD_ENUM_CASE(MountBisSystemProperPartition); ADD_ENUM_CASE(MountSdCard); ADD_ENUM_CASE(MountGameCard); ADD_ENUM_CASE(MountDeviceSaveData); ADD_ENUM_CASE(MountSystemSaveData); ADD_ENUM_CASE(MountOthersSaveData); ADD_ENUM_CASE(MountOthersSystemSaveData); ADD_ENUM_CASE(OpenBisPartitionBootPartition1Root); ADD_ENUM_CASE(OpenBisPartitionBootPartition2Root); ADD_ENUM_CASE(OpenBisPartitionUserDataRoot); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part1); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part2); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part3); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part4); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part5); ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part6); ADD_ENUM_CASE(OpenBisPartitionCalibrationBinary); ADD_ENUM_CASE(OpenBisPartitionCalibrationFile); ADD_ENUM_CASE(OpenBisPartitionSafeMode); ADD_ENUM_CASE(OpenBisPartitionUser); ADD_ENUM_CASE(OpenBisPartitionSystem); ADD_ENUM_CASE(OpenBisPartitionSystemProperEncryption); ADD_ENUM_CASE(OpenBisPartitionSystemProperPartition); ADD_ENUM_CASE(OpenSdCardStorage); ADD_ENUM_CASE(OpenGameCardStorage); ADD_ENUM_CASE(MountSystemDataPrivate); ADD_ENUM_CASE(MountHost); ADD_ENUM_CASE(MountRegisteredUpdatePartition); ADD_ENUM_CASE(MountSaveDataInternalStorage); ADD_ENUM_CASE(MountTemporaryDirectory); ADD_ENUM_CASE(MountAllBaseFileSystem); ADD_ENUM_CASE(NotMount); default: return ToValueString(static_cast<int>(id)); } } template<> const char *IdString::ToString<fssrv::impl::AccessControl::OperationType>(fssrv::impl::AccessControl::OperationType id) { switch (id) { using enum fssrv::impl::AccessControl::OperationType; ADD_ENUM_CASE(InvalidateBisCache); ADD_ENUM_CASE(EraseMmc); ADD_ENUM_CASE(GetGameCardDeviceCertificate); ADD_ENUM_CASE(GetGameCardIdSet); ADD_ENUM_CASE(FinalizeGameCardDriver); ADD_ENUM_CASE(GetGameCardAsicInfo); ADD_ENUM_CASE(CreateSaveData); ADD_ENUM_CASE(DeleteSaveData); ADD_ENUM_CASE(CreateSystemSaveData); ADD_ENUM_CASE(CreateOthersSystemSaveData); ADD_ENUM_CASE(DeleteSystemSaveData); ADD_ENUM_CASE(OpenSaveDataInfoReader); ADD_ENUM_CASE(OpenSaveDataInfoReaderForSystem); ADD_ENUM_CASE(OpenSaveDataInfoReaderForInternal); ADD_ENUM_CASE(OpenSaveDataMetaFile); ADD_ENUM_CASE(SetCurrentPosixTime); ADD_ENUM_CASE(ReadSaveDataFileSystemExtraData); ADD_ENUM_CASE(SetGlobalAccessLogMode); ADD_ENUM_CASE(SetSpeedEmulationMode); ADD_ENUM_CASE(Debug); ADD_ENUM_CASE(FillBis); ADD_ENUM_CASE(CorruptSaveData); ADD_ENUM_CASE(CorruptSystemSaveData); ADD_ENUM_CASE(VerifySaveData); ADD_ENUM_CASE(DebugSaveData); ADD_ENUM_CASE(FormatSdCard); ADD_ENUM_CASE(GetRightsId); ADD_ENUM_CASE(RegisterExternalKey); ADD_ENUM_CASE(SetEncryptionSeed); ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataTimeStamp); ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataFlags); ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataCommitId); ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataAll); ADD_ENUM_CASE(ExtendSaveData); ADD_ENUM_CASE(ExtendSystemSaveData); ADD_ENUM_CASE(ExtendOthersSystemSaveData); ADD_ENUM_CASE(RegisterUpdatePartition); ADD_ENUM_CASE(OpenSaveDataTransferManager); ADD_ENUM_CASE(OpenSaveDataTransferManagerVersion2); ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepair); ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepairTool); ADD_ENUM_CASE(OpenSaveDataTransferProhibiter); ADD_ENUM_CASE(OpenSaveDataMover); ADD_ENUM_CASE(OpenBisWiper); ADD_ENUM_CASE(ListAccessibleSaveDataOwnerId); ADD_ENUM_CASE(ControlMmcPatrol); ADD_ENUM_CASE(OverrideSaveDataTransferTokenSignVerificationKey); ADD_ENUM_CASE(OpenSdCardDetectionEventNotifier); ADD_ENUM_CASE(OpenGameCardDetectionEventNotifier); ADD_ENUM_CASE(OpenSystemDataUpdateEventNotifier); ADD_ENUM_CASE(NotifySystemDataUpdateEvent); ADD_ENUM_CASE(OpenAccessFailureDetectionEventNotifier); ADD_ENUM_CASE(GetAccessFailureDetectionEvent); ADD_ENUM_CASE(IsAccessFailureDetected); ADD_ENUM_CASE(ResolveAccessFailure); ADD_ENUM_CASE(AbandonAccessFailure); ADD_ENUM_CASE(QuerySaveDataInternalStorageTotalSize); ADD_ENUM_CASE(GetSaveDataCommitId); ADD_ENUM_CASE(SetSdCardAccessibility); ADD_ENUM_CASE(SimulateDevice); ADD_ENUM_CASE(CreateSaveDataWithHashSalt); ADD_ENUM_CASE(RegisterProgramIndexMapInfo); ADD_ENUM_CASE(ChallengeCardExistence); ADD_ENUM_CASE(CreateOwnSaveData); ADD_ENUM_CASE(DeleteOwnSaveData); ADD_ENUM_CASE(ReadOwnSaveDataFileSystemExtraData); ADD_ENUM_CASE(ExtendOwnSaveData); ADD_ENUM_CASE(OpenOwnSaveDataTransferProhibiter); ADD_ENUM_CASE(FindOwnSaveDataWithFilter); ADD_ENUM_CASE(OpenSaveDataTransferManagerForRepair); ADD_ENUM_CASE(SetDebugConfiguration); ADD_ENUM_CASE(OpenDataStorageByPath); default: return ToValueString(static_cast<int>(id)); } } namespace { class AccessLogPrinterCallbackManager { private: AccessLogPrinterCallback m_callback; public: constexpr AccessLogPrinterCallbackManager() : m_callback(nullptr) { /* ... */ } constexpr bool IsRegisteredCallback() const { return m_callback != nullptr; } constexpr void RegisterCallback(AccessLogPrinterCallback c) { AMS_ASSERT(m_callback == nullptr); m_callback = c; } constexpr int InvokeCallback(char *buf, size_t size) const { AMS_ASSERT(m_callback != nullptr); return m_callback(buf, size); } }; constinit AccessLogPrinterCallbackManager g_access_log_manager_printer_callback_manager; ALWAYS_INLINE AccessLogPrinterCallbackManager &GetStartAccessLogPrinterCallbackManager() { return g_access_log_manager_printer_callback_manager; } const char *GetPriorityRawName(fs::impl::IdString &id_string) { return id_string.ToString(fs::GetPriorityRawOnCurrentThreadInternal()); } Result OutputAccessLogToSdCardImpl(const char *log, size_t size) { const auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->OutputAccessLogToSdCard(sf::InBuffer(log, size))); R_SUCCEED(); } void OutputAccessLogToSdCard(const char *format, std::va_list vl) { if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) { /* Create a buffer to hold the log's input string. */ int log_buffer_size = 1_KB; auto log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size); while (true) { if (log_buffer == nullptr) { return; } const auto size = util::VSNPrintf(log_buffer.get(), log_buffer_size, format, vl); if (size < log_buffer_size) { break; } log_buffer_size = size + 1; log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size); } /* Output. */ static_cast<void>(OutputAccessLogToSdCardImpl(log_buffer.get(), log_buffer_size - 1)); } } void OutputAccessLogImpl(const char *log, size_t size) { if ((g_global_access_log_mode & AccessLogMode_Log) != 0) { /* TODO: Support logging. */ } else if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) { static_cast<void>(OutputAccessLogToSdCardImpl(log, size - 1)); } } void OutputAccessLog(Result result, const char *priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *format, std::va_list vl) { /* Create a buffer to hold the log's input string. */ int str_buffer_size = 1_KB; auto str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size); while (true) { if (str_buffer == nullptr) { return; } const auto size = util::VSNPrintf(str_buffer.get(), str_buffer_size, format, vl); if (size < str_buffer_size) { break; } str_buffer_size = size + 1; str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size); } /* Create a buffer to hold the log. */ int log_buffer_size = 0; decltype(str_buffer) log_buffer; { /* Declare format string. */ constexpr const char FormatString[] = "FS_ACCESS { " "start: %9" PRId64 ", " "end: %9" PRId64 ", " "result: 0x%08" PRIX32 ", " "handle: 0x%p, " "priority: %s, " "function: \"%s\"" "%s" " }\n"; /* Convert the timing to ms. */ const s64 start_ms = start.ToTimeSpan().GetMilliSeconds(); const s64 end_ms = end.ToTimeSpan().GetMilliSeconds(); /* Print the log. */ int try_size = std::max<int>(str_buffer_size + sizeof(FormatString) + 0x100, 1_KB); while (true) { log_buffer = fs::impl::MakeUnique<char[]>(try_size); if (log_buffer == nullptr) { return; } log_buffer_size = 1 + util::SNPrintf(log_buffer.get(), try_size, FormatString, start_ms, end_ms, result.GetValue(), handle, priority, name, str_buffer.get()); if (log_buffer_size <= try_size) { break; } try_size = log_buffer_size; } } OutputAccessLogImpl(log_buffer.get(), log_buffer_size); } void GetProgramIndexForAccessLog(u32 *out_index, u32 *out_count) { if (hos::GetVersion() >= hos::Version_7_0_0) { /* Use libnx bindings if available. */ const auto fsp = impl::GetFileSystemProxyServiceObject(); R_ABORT_UNLESS(fsp->GetProgramIndexForAccessLog(out_index, out_count)); } else { /* Use hardcoded defaults. */ *out_index = 0; *out_count = 0; } } void OutputAccessLogStart() { /* Get the program index. */ u32 program_index = 0, program_count = 0; GetProgramIndexForAccessLog(std::addressof(program_index), std::addressof(program_count)); /* Print the log buffer. */ if (program_count < 2) { constexpr const char StartLog[] = "FS_ACCESS: { " AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", " AMS_FS_IMPL_ACCESS_LOG_SPEC " }\n"; OutputAccessLogImpl(StartLog, sizeof(StartLog)); } else { constexpr const char StartLog[] = "FS_ACCESS: { " AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", " AMS_FS_IMPL_ACCESS_LOG_SPEC ", " "program_index: %d" " }\n"; char log_buffer[0x80]; const int len = 1 + util::SNPrintf(log_buffer, sizeof(log_buffer), StartLog, static_cast<int>(program_index)); if (static_cast<size_t>(len) <= sizeof(log_buffer)) { OutputAccessLogImpl(log_buffer, len); } } } [[maybe_unused]] void OutputAccessLogStartForSystem() { constexpr const char StartLog[] = "FS_ACCESS: { " AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", " AMS_FS_IMPL_ACCESS_LOG_SPEC ", " "for_system: true" " }\n"; OutputAccessLogImpl(StartLog, sizeof(StartLog)); } void OutputAccessLogStartGeneratedByCallback() { /* Get the manager. */ const auto &manager = GetStartAccessLogPrinterCallbackManager(); if (manager.IsRegisteredCallback()) { /* Invoke the callback. */ char log_buffer[0x80]; const int len = 1 + manager.InvokeCallback(log_buffer, sizeof(log_buffer)); /* Print, if we fit. */ if (static_cast<size_t>(len) <= sizeof(log_buffer)) { OutputAccessLogImpl(log_buffer, len); } } } } bool IsEnabledAccessLog(u32 target) { /* If we don't need to log to the target, return false. */ if ((g_local_access_log_target & target) == 0) { return false; } /* Ensure we've initialized. */ if (!g_access_log_initialized) { std::scoped_lock lk(g_access_log_initialization_mutex); if (!g_access_log_initialized) { #if defined (AMS_BUILD_FOR_DEBUGGING) if ((g_local_access_log_target & fs::impl::AccessLogTarget_System) != 0) { g_global_access_log_mode = AccessLogMode_Log; OutputAccessLogStartForSystem(); OutputAccessLogStartGeneratedByCallback(); } else #endif { AMS_FS_R_ABORT_UNLESS(GetGlobalAccessLogMode(std::addressof(g_global_access_log_mode))); if (g_global_access_log_mode != AccessLogMode_None) { OutputAccessLogStart(); OutputAccessLogStartGeneratedByCallback(); } } g_access_log_initialized = true; } } return g_global_access_log_mode != AccessLogMode_None; } bool IsEnabledAccessLog() { return IsEnabledAccessLog(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System); } void RegisterStartAccessLogPrinterCallback(AccessLogPrinterCallback callback) { GetStartAccessLogPrinterCallbackManager().RegisterCallback(callback); } void OutputAccessLog(Result result, fs::Priority priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); OutputAccessLog(result, fs::impl::IdString().ToString(priority), start, end, name, handle, fmt, vl); va_end(vl); } void OutputAccessLog(Result result, fs::PriorityRaw priority_raw, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...){ std::va_list vl; va_start(vl, fmt); OutputAccessLog(result, fs::impl::IdString().ToString(priority_raw), start, end, name, handle, fmt, vl); va_end(vl); } void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl); va_end(vl); } void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl); va_end(vl); } void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::impl::IdentifyAccessLogHandle handle, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl); va_end(vl); } void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle, fmt, vl); va_end(vl); } void OutputAccessLogToOnlySdCard(const char *fmt, ...) { std::va_list vl; va_start(vl, fmt); OutputAccessLogToSdCard(fmt, vl); va_end(vl); } void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) { if (R_FAILED(result)) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl); va_end(vl); } } void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) { if (R_FAILED(result)) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl); va_end(vl); } } void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) { if (R_FAILED(result)) { std::va_list vl; va_start(vl, fmt); fs::impl::IdString id_string; OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle, fmt, vl); va_end(vl); } } bool IsEnabledHandleAccessLog(fs::FileHandle handle) { /* Get the file accessor. */ impl::FileAccessor *accessor = reinterpret_cast<impl::FileAccessor *>(handle.handle); if (accessor == nullptr) { return true; } /* Check the parent. */ if (auto *parent = accessor->GetParent(); parent != nullptr) { return parent->IsEnabledAccessLog(); } else { return false; } } bool IsEnabledHandleAccessLog(fs::DirectoryHandle handle) { /* Get the file accessor. */ impl::DirectoryAccessor *accessor = reinterpret_cast<impl::DirectoryAccessor *>(handle.handle); if (accessor == nullptr) { return true; } /* Check the parent. */ if (auto *parent = accessor->GetParent(); parent != nullptr) { return parent->IsEnabledAccessLog(); } else { return false; } } bool IsEnabledHandleAccessLog(fs::impl::IdentifyAccessLogHandle handle) { AMS_UNUSED(handle); return true; } bool IsEnabledHandleAccessLog(const void *handle) { if (handle == nullptr) { return true; } /* We should never receive non-null here. */ AMS_ASSERT(handle == nullptr); return false; } bool IsEnabledFileSystemAccessorAccessLog(const char *mount_name) { /* Get the accessor. */ impl::FileSystemAccessor *accessor = nullptr; if (R_FAILED(impl::Find(std::addressof(accessor), mount_name))) { return true; } return accessor->IsEnabledAccessLog(); } void EnableFileSystemAccessorAccessLog(const char *mount_name) { /* Get the accessor. */ impl::FileSystemAccessor *accessor = nullptr; AMS_FS_R_ABORT_UNLESS(impl::Find(std::addressof(accessor), mount_name)); accessor->SetAccessLogEnabled(true); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_remote_file_system_proxy.hpp" #include "fs_remote_file_system_proxy_for_loader.hpp" #include "impl/fs_library.hpp" namespace ams::fs { #if defined(ATMOSPHERE_OS_HORIZON) namespace { alignas(0x10) constinit std::byte g_fsp_service_object_buffer[0x80] = {}; alignas(0x10) constinit std::byte g_fsp_ldr_service_object_buffer[0x80] = {}; constinit bool g_use_static_fsp_service_object_buffer = false; constinit bool g_use_static_fsp_ldr_service_object_buffer = false; class HipcClientAllocator { public: using Policy = sf::StatelessAllocationPolicy<HipcClientAllocator>; public: constexpr HipcClientAllocator() = default; void *Allocate(size_t size) { if (g_use_static_fsp_service_object_buffer) { return std::addressof(g_fsp_service_object_buffer); } else if (g_use_static_fsp_ldr_service_object_buffer) { return std::addressof(g_fsp_ldr_service_object_buffer); } else { return ::ams::fs::impl::Allocate(size); } } void Deallocate(void *ptr, size_t size) { if (ptr == std::addressof(g_fsp_service_object_buffer)) { return; } else if (ptr == std::addressof(g_fsp_ldr_service_object_buffer)) { return; } else { return ::ams::fs::impl::Deallocate(ptr, size); } } }; enum class FileSystemProxySessionSetting { SystemNormal = 0, Application = 1, SystemMulti = 2, }; constexpr ALWAYS_INLINE int GetSessionCount(FileSystemProxySessionSetting setting) { switch (setting) { case FileSystemProxySessionSetting::Application: return 3; case FileSystemProxySessionSetting::SystemNormal: return 1; case FileSystemProxySessionSetting::SystemMulti: return 2; AMS_UNREACHABLE_DEFAULT_CASE(); } } constinit bool g_is_fsp_object_initialized = false; constinit FileSystemProxySessionSetting g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal; /* TODO: SessionResourceManager */ } #endif namespace { constinit sf::SharedPointer<fssrv::sf::IFileSystemProxy> g_fsp_service_object; sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObjectImpl() { /* Ensure the library is initialized. */ ::ams::fs::impl::InitializeFileSystemLibrary(); sf::SharedPointer<fssrv::sf::IFileSystemProxy> fsp_object; #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON) /* Try to use the custom object. */ fsp_object = g_fsp_service_object; /* If we don't have one, create a remote object. */ if (fsp_object == nullptr) { /* Make our next allocation use our static reserved buffer for the service object. */ g_use_static_fsp_service_object_buffer = true; ON_SCOPE_EXIT { g_use_static_fsp_service_object_buffer = false; }; using ObjectFactory = sf::ObjectFactory<HipcClientAllocator::Policy>; /* Create the object. */ fsp_object = ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystemProxy, RemoteFileSystemProxy>(GetSessionCount(g_fsp_session_setting)); AMS_ABORT_UNLESS(fsp_object != nullptr); /* Set the current process. */ const auto scp_res = fsp_object->SetCurrentProcess({}); R_ASSERT(scp_res); AMS_UNUSED(scp_res); } #else /* On non-horizon, use the system object. */ fsp_object = fssrv::impl::GetFileSystemProxyServiceObject(); AMS_ABORT_UNLESS(fsp_object != nullptr); /* Set the current process. */ fsp_object->SetCurrentProcess({}); #endif /* Return the object. */ return fsp_object; } sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObjectImpl() { /* Ensure the library is initialized. */ ::ams::fs::impl::InitializeFileSystemLibrary(); sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> fsp_ldr_object; #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON) /* Make our next allocation use our static reserved buffer for the service object. */ g_use_static_fsp_ldr_service_object_buffer = true; ON_SCOPE_EXIT { g_use_static_fsp_ldr_service_object_buffer = false; }; using ObjectFactory = sf::ObjectFactory<HipcClientAllocator::Policy>; /* Create the object. */ fsp_ldr_object = ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystemProxyForLoader, RemoteFileSystemProxyForLoader>(); AMS_ABORT_UNLESS(fsp_ldr_object != nullptr); #else /* On non-horizon, use the system object. */ fsp_ldr_object = fssrv::impl::GetFileSystemProxyForLoaderServiceObject(); AMS_ABORT_UNLESS(fsp_ldr_object != nullptr); #endif /* Return the object. */ return fsp_ldr_object; } } namespace impl { sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObject() { AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer<fssrv::sf::IFileSystemProxy>, s_fsp_service_object, GetFileSystemProxyServiceObjectImpl()); return s_fsp_service_object; } sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject() { AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader>, s_fsp_ldr_service_object, GetFileSystemProxyForLoaderServiceObjectImpl()); return s_fsp_ldr_service_object; } } void InitializeForHostTool() { #if !defined(ATMOSPHERE_OS_HORIZON) AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); R_ABORT_UNLESS(::ams::fs::MountHostRoot()); #endif } void InitializeForSystem() { #if defined(ATMOSPHERE_OS_HORIZON) AMS_ABORT_UNLESS(!g_is_fsp_object_initialized); AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal); g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal; /* Nintendo doesn't do this, but we have to for timing reasons. */ AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); #endif } void InitializeWithMultiSessionForSystem() { #if defined(ATMOSPHERE_OS_HORIZON) AMS_ABORT_UNLESS(!g_is_fsp_object_initialized); AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal); g_fsp_session_setting = FileSystemProxySessionSetting::SystemMulti; /* Nintendo doesn't do this, but we have to for timing reasons. */ AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr); #endif } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_application.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { Result MountApplicationPackage(const char *name, const char *common_path) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Validate the path. */ R_UNLESS(common_path != nullptr, fs::ResultInvalidPath()); /* Convert the path for ipc. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), common_path)); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, fs::ContentAttributes_None, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package)); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInApplicationA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(name, common_path))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_bis.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace { class BisCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { private: const BisPartitionId m_id; public: explicit BisCommonMountNameGenerator(BisPartitionId i) : m_id(i) { /* ... */ } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ const char *bis_mount_name = GetBisMountName(m_id); const size_t needed_size = util::Strnlen(bis_mount_name, MountNameLengthMax) + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, "%s:", bis_mount_name); AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1); AMS_UNUSED(size); R_SUCCEED(); } }; } namespace impl { Result MountBisImpl(const char *name, BisPartitionId id, const char *root_path) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountNameAllowingReserved(name)); /* Convert the path for ipc. */ /* NOTE: Nintendo ignores the root_path here. */ fssrv::sf::FspPath sf_path; sf_path.str[0] = '\x00'; AMS_UNUSED(root_path); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenBisFileSystem(std::addressof(fs), sf_path, static_cast<u32>(id))); /* Allocate a new mountname generator. */ auto generator = std::make_unique<BisCommonMountNameGenerator>(id); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInBisA()); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInBisB()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(name, id, root_path))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result SetBisRootForHostImpl(BisPartitionId id, const char *root_path) { AMS_UNUSED(id, root_path); AMS_ABORT("TODO"); } } const char *GetBisMountName(BisPartitionId id) { switch (id) { case BisPartitionId::CalibrationFile: return impl::BisCalibrationFilePartitionMountName; case BisPartitionId::SafeMode: return impl::BisSafeModePartitionMountName; case BisPartitionId::User: return impl::BisUserPartitionMountName; case BisPartitionId::System: return impl::BisSystemPartitionMountName; AMS_UNREACHABLE_DEFAULT_CASE(); } } Result MountBis(BisPartitionId id, const char *root_path) { R_RETURN(impl::MountBisImpl(GetBisMountName(id), id, root_path)); } Result MountBis(const char *name, BisPartitionId id) { R_RETURN(impl::MountBisImpl(name, id, nullptr)); } void SetBisRootForHost(BisPartitionId id, const char *root_path) { R_ABORT_UNLESS(impl::SetBisRootForHostImpl(id, root_path)); } Result OpenBisPartition(std::unique_ptr<fs::IStorage> *out, BisPartitionId id) { /* Open the partition. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IStorage> s; AMS_FS_R_TRY(fsp->OpenBisStorage(std::addressof(s), static_cast<u32>(id))); /* Allocate a new storage wrapper. */ auto storage = std::make_unique<impl::StorageServiceObjectAdapter<fssrv::sf::IStorage>>(std::move(s)); AMS_FS_R_UNLESS(storage != nullptr, fs::ResultAllocationMemoryFailedInBisC()); *out = std::move(storage); R_SUCCEED(); } Result InvalidateBisCache() { auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_ABORT_UNLESS(fsp->InvalidateBisCache()); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_code.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace { constinit os::SdkMutex g_mount_stratosphere_romfs_lock; constinit bool g_mounted_stratosphere_romfs = false; constinit util::TypedStorage<FileHandleStorage> g_stratosphere_romfs_storage = {}; constinit util::TypedStorage<RomFsFileSystem> g_stratosphere_romfs_fs = {}; Result EnsureStratosphereRomfsMounted() { std::scoped_lock lk(g_mount_stratosphere_romfs_lock); if (AMS_UNLIKELY(!g_mounted_stratosphere_romfs)) { /* Mount the SD card. */ R_TRY(fs::MountSdCard("#strat-romfs-sd")); auto sd_guard = SCOPE_GUARD { fs::Unmount("#strat-romfs-sd"); }; /* Open sd:/atmosphere/stratosphere.romfs. */ fs::FileHandle stratosphere_romfs_file; R_TRY(fs::OpenFile(std::addressof(stratosphere_romfs_file), "#strat-romfs-sd:/atmosphere/stratosphere.romfs", fs::OpenMode_Read)); /* Setup the storage. */ /* NOTE: This owns the file, and so on failure it will be closed appropriately. */ auto storage_guard = util::ConstructAtGuarded(g_stratosphere_romfs_storage, stratosphere_romfs_file, true); /* Create the filesystem. */ auto fs_guard = util::ConstructAtGuarded(g_stratosphere_romfs_fs); /* Initialize the filesystem. */ R_TRY(GetReference(g_stratosphere_romfs_fs).Initialize(GetPointer(g_stratosphere_romfs_storage), nullptr, 0, false)); /* We succeeded, and so stratosphere.romfs is mounted. */ fs_guard.Cancel(); storage_guard.Cancel(); sd_guard.Cancel(); g_mounted_stratosphere_romfs = true; } R_SUCCEED(); } fsa::IFileSystem &GetStratosphereRomFsFileSystem() { /* Ensure that stratosphere.romfs is mounted. */ /* NOTE: Abort is used here to ensure that atmosphere's filesystem is structurally valid. */ R_ABORT_UNLESS(EnsureStratosphereRomfsMounted()); return GetReference(g_stratosphere_romfs_fs); } Result OpenCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { /* Print a path suitable for the remote service. */ fssrv::sf::Path sf_path; R_TRY(FormatToFspPath(std::addressof(sf_path), "%s", path)); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyForLoaderServiceObject(); R_TRY(fsp->SetCurrentProcess({})); sf::SharedPointer<fssrv::sf::IFileSystem> fs; if (hos::GetVersion() >= hos::Version_20_0_0) { R_TRY(fsp->OpenCodeFileSystem(std::addressof(fs), ams::sf::OutBuffer(out_verification_data, sizeof(*out_verification_data)), attr, program_id, storage_id)); } else { R_TRY(fsp->OpenCodeFileSystemDeprecated4(std::addressof(fs), ams::sf::OutBuffer(out_verification_data, sizeof(*out_verification_data)), sf_path, attr, program_id)); } /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); *out = std::move(fsa); R_SUCCEED(); } Result OpenPackageFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, const fssrv::sf::FspPath &path) { /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), path, fs::ContentAttributes_None, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package)); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); *out = std::move(fsa); R_SUCCEED(); } Result OpenSdCardCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, ncm::ProgramId program_id) { /* Ensure we don't access the SD card too early. */ R_UNLESS(cfg::IsSdCardInitialized(), fs::ResultSdCardNotPresent()); /* Print a path to the program's package. */ fssrv::sf::Path sf_path; R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/atmosphere/contents/%016" PRIx64 "/exefs.nsp", impl::SdCardFileSystemMountName, program_id.value)); R_RETURN(OpenPackageFileSystemImpl(out, sf_path)); } Result OpenStratosphereCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, ncm::ProgramId program_id) { /* Ensure we don't access the SD card too early. */ R_UNLESS(cfg::IsSdCardInitialized(), fs::ResultSdCardNotPresent()); /* Open the program's package. */ std::unique_ptr<fsa::IFile> package_file; { /* Get the stratosphere.romfs filesystem. */ auto &romfs_fs = GetStratosphereRomFsFileSystem(); /* Print a path to the program's package. */ fs::Path path; R_TRY(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs.nsp", program_id.value)); R_TRY(path.Normalize(fs::PathFlags{})); /* Open the package within stratosphere.romfs. */ R_TRY(romfs_fs.OpenFile(std::addressof(package_file), path, fs::OpenMode_Read)); } /* Create a file storage for the program's package. */ auto package_storage = fs::AllocateShared<FileStorage>(std::move(package_file)); R_UNLESS(package_storage != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); /* Create a partition filesystem. */ auto package_fs = std::make_unique<fssystem::PartitionFileSystem>(); R_UNLESS(package_fs != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); /* Initialize the partition filesystem. */ R_TRY(package_fs->Initialize(package_storage)); *out = std::move(package_fs); R_SUCCEED(); } Result OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { /* If we can open an sd card code fs, use it. */ R_SUCCEED_IF(R_SUCCEEDED(OpenSdCardCodeFileSystemImpl(out, program_id))); /* If we can open a stratosphere code fs, use it. */ R_SUCCEED_IF(R_SUCCEEDED(OpenStratosphereCodeFileSystemImpl(out, program_id))); /* Otherwise, fall back to a normal code fs. */ R_RETURN(OpenCodeFileSystemImpl(out_verification_data, out, path, attr, program_id, storage_id)); } Result OpenHblCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out) { /* Get the HBL path. */ const char *hbl_path = cfg::GetHblPath(); /* Print a path to the hbl package. */ fssrv::sf::Path sf_path; R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/%s", impl::SdCardFileSystemMountName, hbl_path[0] == '/' ? hbl_path + 1 : hbl_path)); R_RETURN(OpenPackageFileSystemImpl(out, sf_path)); } Result OpenSdCardFileSystemImpl(std::shared_ptr<fsa::IFileSystem> *out) { /* Open the SD card filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ auto fsa = fs::AllocateShared<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); *out = std::move(fsa); R_SUCCEED(); } class OpenFileOnlyFileSystem : public fsa::IFileSystem, public impl::Newable { private: virtual Result DoCommit() override final { R_SUCCEED(); } virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { AMS_UNUSED(out_dir, path, mode); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { AMS_UNUSED(out, path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { AMS_UNUSED(path, size, flags); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoDeleteFile(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoCreateDirectory(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoDeleteDirectory(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { AMS_UNUSED(out, path); R_THROW(fs::ResultUnsupportedOperation()); } virtual Result DoCommitProvisionally(s64 counter) override final { AMS_UNUSED(counter); R_THROW(fs::ResultUnsupportedOperation()); } }; class SdCardRedirectionCodeFileSystem : public OpenFileOnlyFileSystem { private: util::optional<ReadOnlyFileSystem> m_sd_content_fs; ReadOnlyFileSystem m_code_fs; bool m_is_redirect; public: SdCardRedirectionCodeFileSystem(std::unique_ptr<fsa::IFileSystem> &&code, ncm::ProgramId program_id, bool redirect) : m_code_fs(std::move(code)), m_is_redirect(redirect) { if (!cfg::IsSdCardInitialized()) { return; } /* Open an SD card filesystem. */ std::shared_ptr<fsa::IFileSystem> sd_fs; if (R_FAILED(OpenSdCardFileSystemImpl(std::addressof(sd_fs)))) { return; } /* Create a redirection filesystem to the relevant content folder. */ auto subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(sd_fs)); if (subdir_fs == nullptr) { return; } fs::Path path; R_ABORT_UNLESS(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs", program_id.value)); R_ABORT_UNLESS(path.Normalize(fs::PathFlags{})); R_ABORT_UNLESS(subdir_fs->Initialize(path)); m_sd_content_fs.emplace(std::move(subdir_fs)); } private: bool IsFileStubbed(const fs::Path &path) { /* If we don't have an sd content fs, nothing is stubbed. */ if (!m_sd_content_fs) { return false; } /* Create a path representing the stub. */ fs::Path stub_path; if (R_FAILED(stub_path.InitializeWithFormat("%s.stub", path.GetString()))) { return false; } if (R_FAILED(stub_path.Normalize(fs::PathFlags{}))) { return false; } /* Query whether we have the file. */ bool has_file; if (R_FAILED(fssystem::HasFile(std::addressof(has_file), std::addressof(*m_sd_content_fs), stub_path))) { return false; } return has_file; } virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final { /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); /* If we support redirection, we'd like to prefer a file from the sd card. */ if (m_is_redirect) { R_SUCCEED_IF(R_SUCCEEDED(m_sd_content_fs->OpenFile(out_file, path, mode))); } /* Otherwise, check if the file is stubbed. */ R_UNLESS(!this->IsFileStubbed(path), fs::ResultPathNotFound()); /* Open a file from the base code fs. */ R_RETURN(m_code_fs.OpenFile(out_file, path, mode)); } }; class AtmosphereCodeFileSystem : public OpenFileOnlyFileSystem { private: util::optional<SdCardRedirectionCodeFileSystem> m_code_fs; util::optional<ReadOnlyFileSystem> m_hbl_fs; ncm::ProgramId m_program_id; ncm::StorageId m_storage_id; bool m_initialized; public: AtmosphereCodeFileSystem() : m_initialized(false) { /* ... */ } Result Initialize(CodeVerificationData *out_verification_data, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id, bool is_hbl, bool is_specific) { AMS_ABORT_UNLESS(!m_initialized); /* If we're hbl, we need to open a hbl fs. */ if (is_hbl) { std::unique_ptr<fsa::IFileSystem> fsa; R_TRY(OpenHblCodeFileSystemImpl(std::addressof(fsa))); m_hbl_fs.emplace(std::move(fsa)); } /* Open the code filesystem. */ std::unique_ptr<fsa::IFileSystem> fsa; R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out_verification_data, std::addressof(fsa), path, attr, program_id, storage_id)); m_code_fs.emplace(std::move(fsa), program_id, is_specific); m_program_id = program_id; m_storage_id = storage_id; m_initialized = true; R_SUCCEED(); } private: virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final { /* Ensure that we're initialized. */ R_UNLESS(m_initialized, fs::ResultNotInitialized()); /* Only allow opening files with mode = read. */ R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); /* First, check if there's an external code. */ { fsa::IFileSystem *ecs = fssystem::GetExternalCodeFileSystem(m_program_id); if (ecs != nullptr) { R_RETURN(ecs->OpenFile(out_file, path, mode)); } } /* If we're hbl, open from the hbl fs. */ if (m_hbl_fs) { R_RETURN(m_hbl_fs->OpenFile(out_file, path, mode)); } /* If we're not hbl, fall back to our code filesystem. */ R_RETURN(m_code_fs->OpenFile(out_file, path, mode)); } }; } Result MountCode(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { auto mount_impl = [=]() -> Result { /* Clear the output. */ std::memset(out, 0, sizeof(*out)); /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Validate the path isn't null. */ R_UNLESS(path != nullptr, fs::ResultInvalidPath()); /* Open the code file system. */ std::unique_ptr<fsa::IFileSystem> fsa; R_TRY(OpenCodeFileSystemImpl(out, std::addressof(fsa), path, attr, program_id, storage_id)); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id, bool is_hbl, bool is_specific) { auto mount_impl = [=]() -> Result { /* Clear the output. */ std::memset(out, 0, sizeof(*out)); /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Validate the path isn't null. */ R_UNLESS(path != nullptr, fs::ResultInvalidPath()); /* Create an AtmosphereCodeFileSystem. */ auto ams_code_fs = std::make_unique<AtmosphereCodeFileSystem>(); R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); /* Initialize the code file system. */ R_TRY(ams_code_fs->Initialize(out, path, attr, program_id, storage_id, is_hbl, is_specific)); /* Register. */ R_RETURN(fsa::Register(name, std::move(ams_code_fs))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { auto mount_impl = [=]() -> Result { /* Clear the output. */ std::memset(out, 0, sizeof(*out)); /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Validate the path isn't null. */ R_UNLESS(path != nullptr, fs::ResultInvalidPath()); /* Open the code file system. */ std::unique_ptr<fsa::IFileSystem> fsa; R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out, std::addressof(fsa), path, attr, program_id, storage_id)); /* Create a wrapper fs. */ auto wrap_fsa = std::make_unique<SdCardRedirectionCodeFileSystem>(std::move(fsa), program_id, false); R_UNLESS(wrap_fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(wrap_fsa))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_content.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { namespace { impl::FileSystemProxyType ConvertToFileSystemProxyType(ContentType content_type) { switch (content_type) { case ContentType_Control: return impl::FileSystemProxyType_Control; case ContentType_Manual: return impl::FileSystemProxyType_Manual; case ContentType_Meta: return impl::FileSystemProxyType_Meta; case ContentType_Data: return impl::FileSystemProxyType_Data; AMS_UNREACHABLE_DEFAULT_CASE(); } } Result MountContentImpl(const char *name, const char *path, fs::ContentAttributes attr, u64 id, ContentType type) { /* Validate the mount name. */ R_TRY(impl::CheckMountNameAllowingReserved(name)); /* Validate the path. */ R_UNLESS(path != nullptr, fs::ResultInvalidPath()); /* Convert the path for fsp. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, attr, id, ConvertToFileSystemProxyType(type))); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInContentA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); } } Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ContentType content_type) { auto mount_impl = [=]() -> Result { /* This API only supports mounting Meta content. */ R_UNLESS(content_type == ContentType_Meta, fs::ResultInvalidArgument()); R_RETURN(MountContentImpl(name, path, attr, ncm::InvalidProgramId.value, content_type)); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(name, path, content_type))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId id, ContentType content_type) { auto mount_impl = [=]() -> Result { R_RETURN(MountContentImpl(name, path, attr, id.value, content_type)); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(name, path, id, content_type))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::DataId id, ContentType content_type) { auto mount_impl = [=]() -> Result { R_RETURN(MountContentImpl(name, path, attr, id.value, content_type)); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(name, path, id, content_type))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_content_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace { class ContentStorageCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { private: const ContentStorageId id; public: explicit ContentStorageCommonMountNameGenerator(ContentStorageId i) : id(i) { /* ... */ } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ const size_t needed_size = util::Strnlen(GetContentStorageMountName(id), MountNameLengthMax) + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, "%s:", GetContentStorageMountName(id)); AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1); AMS_UNUSED(size); R_SUCCEED(); } }; } const char *GetContentStorageMountName(ContentStorageId id) { switch (id) { case ContentStorageId::System: return impl::ContentStorageSystemMountName; case ContentStorageId::User: return impl::ContentStorageUserMountName; case ContentStorageId::SdCard: return impl::ContentStorageSdCardMountName; AMS_UNREACHABLE_DEFAULT_CASE(); } } Result MountContentStorage(ContentStorageId id) { R_RETURN(MountContentStorage(GetContentStorageMountName(id), id)); } Result MountContentStorage(const char *name, ContentStorageId id) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountNameAllowingReserved(name)); /* It can take some time for the system partition to be ready (if it's on the SD card). */ /* Thus, we will retry up to 10 times, waiting one second each time. */ constexpr size_t MaxRetries = 10; constexpr auto RetryInterval = TimeSpan::FromSeconds(1); /* Mount the content storage */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; for (size_t i = 0; i < MaxRetries; i++) { /* Try to open the filesystem. */ R_TRY_CATCH(fsp->OpenContentStorageFileSystem(std::addressof(fs), static_cast<u32>(id))) { R_CATCH(fs::ResultSystemPartitionNotReady) { if (i < MaxRetries - 1) { os::SleepThread(RetryInterval); continue; } else { R_THROW(fs::ResultSystemPartitionNotReady()); } } } R_END_TRY_CATCH; /* The filesystem was opened successfully. */ break; } /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInContentStorageA()); /* Allocate a new mountname generator. */ auto generator = std::make_unique<ContentStorageCommonMountNameGenerator>(id); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInContentStorageB()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(name, id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_context.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constinit bool g_auto_abort_enabled = true; /* NOTE: This generates a global constructor. */ os::SdkThreadLocalStorage g_context_tls; } void SetEnabledAutoAbort(bool enabled) { g_auto_abort_enabled = enabled; } AbortSpecifier DefaultResultHandler(Result result) { AMS_UNUSED(result); if (g_auto_abort_enabled) { return AbortSpecifier::Default; } else { return AbortSpecifier::Return; } } AbortSpecifier AlwaysReturnResultHandler(Result result) { AMS_UNUSED(result); return AbortSpecifier::Return; } constinit FsContext g_default_context(DefaultResultHandler); constinit FsContext g_always_return_context(AlwaysReturnResultHandler); void SetDefaultFsContextResultHandler(const ResultHandler handler) { if (handler == nullptr) { g_default_context.SetHandler(DefaultResultHandler); } else { g_default_context.SetHandler(handler); } } const FsContext *GetCurrentThreadFsContext() { const FsContext *context = reinterpret_cast<const FsContext *>(g_context_tls.GetValue()); if (context == nullptr) { context = std::addressof(g_default_context); } return context; } void SetCurrentThreadFsContext(const FsContext *context) { g_context_tls.SetValue(reinterpret_cast<uintptr_t>(context)); } ScopedAutoAbortDisabler::ScopedAutoAbortDisabler() : m_prev_context(GetCurrentThreadFsContext()) { SetCurrentThreadFsContext(std::addressof(g_always_return_context)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_data.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs::impl { namespace { Result OpenDataStorageByDataIdImpl(sf::SharedPointer<fssrv::sf::IStorage> *out, ncm::DataId data_id, ncm::StorageId storage_id) { auto fsp = impl::GetFileSystemProxyServiceObject(); R_TRY_CATCH(fsp->OpenDataStorageByDataId(out, data_id, static_cast<u8>(storage_id))) { R_CONVERT(ncm::ResultContentMetaNotFound, fs::ResultTargetNotFound()); } R_END_TRY_CATCH; R_SUCCEED(); } Result OpenDataStorageByDataId(std::unique_ptr<ams::fs::IStorage> *out, ncm::DataId data_id, ncm::StorageId storage_id) { /* Open storage. */ sf::SharedPointer<fssrv::sf::IStorage> s; AMS_FS_R_TRY(OpenDataStorageByDataIdImpl(std::addressof(s), data_id, storage_id)); auto storage = std::make_unique<impl::StorageServiceObjectAdapter<fssrv::sf::IStorage>>(std::move(s)); R_UNLESS(storage != nullptr, fs::ResultAllocationMemoryFailedInDataA()); *out = std::move(storage); R_SUCCEED(); } Result MountDataImpl(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_cache, bool use_data_cache, bool use_path_cache) { std::unique_ptr<fs::IStorage> storage; R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id)); auto fs = std::make_unique<RomFsFileSystem>(); R_UNLESS(fs != nullptr, fs::ResultAllocationMemoryFailedInDataB()); R_TRY(fs->Initialize(std::move(storage), cache_buffer, cache_size, use_cache)); R_RETURN(fsa::Register(name, std::move(fs), nullptr, use_data_cache, use_path_cache, false)); } } Result QueryMountDataCacheSize(size_t *out, ncm::DataId data_id, ncm::StorageId storage_id) { AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); std::unique_ptr<fs::IStorage> storage; AMS_FS_R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id)); size_t size = 0; AMS_FS_R_TRY(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(size), storage.get())); constexpr size_t MinimumCacheSize = 32; *out = std::max(size, MinimumCacheSize); R_SUCCEED(); } Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id) { /* Validate the mount name. */ AMS_FS_R_TRY(impl::CheckMountName(name)); R_RETURN(MountDataImpl(name, data_id, storage_id, nullptr, 0, false, false, false)); } Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size) { /* Validate the mount name. */ AMS_FS_R_TRY(impl::CheckMountName(name)); AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); R_RETURN(MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, false, false)); } Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache) { /* Validate the mount name. */ AMS_FS_R_TRY(impl::CheckMountName(name)); AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument()); R_RETURN(MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, use_data_cache, use_path_cache)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_device_save_data.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { namespace { constexpr inline SaveDataSpaceId DeviceSaveDataSpaceId = SaveDataSpaceId::User; Result MountDeviceSaveDataImpl(const char *name, const SaveDataAttribute &attribute) { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenSaveDataFileSystem(std::addressof(fs), static_cast<u8>(DeviceSaveDataSpaceId), attribute)); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInDeviceSaveDataA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); } } Result MountDeviceSaveData(const char *name) { const auto attr = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId); /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name)); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountDeviceSaveData(const char *name, const ncm::ApplicationId application_id) { const auto attr = SaveDataAttribute::Make(application_id, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId); /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(name, application_id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_error_info.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result GetAndClearFileSystemProxyErrorInfo(FileSystemProxyErrorInfo *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Get the error info. */ AMS_FS_R_TRY(fsp->GetAndClearErrorInfo(out)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_file_path_hash.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { constexpr inline size_t FilePathHashSize = 4; struct FilePathHash : public Newable { u8 data[FilePathHashSize]; }; static_assert(util::is_pod<FilePathHash>::value); inline bool operator==(const FilePathHash &lhs, const FilePathHash &rhs) { return std::memcmp(lhs.data, rhs.data, FilePathHashSize) == 0; } inline bool operator!=(const FilePathHash &lhs, const FilePathHash &rhs) { return !(lhs == rhs); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_filesystem_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "fsa/fs_filesystem_accessor.hpp" namespace ams::fs { Result EnsureDirectory(const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Set up the true sub path. */ fs::Path sub_fs_path; R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); /* Use the system implementation. */ R_RETURN(fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path)); } Result EnsureParentDirectory(const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Set up the true sub path. */ fs::Path sub_fs_path; R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); /* Convert the path to the parent directory path. */ R_TRY(sub_fs_path.RemoveChild()); /* Use the system implementation. */ R_RETURN(fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path)); } Result HasFile(bool *out, const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Set up the true sub path. */ fs::Path sub_fs_path; R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); R_RETURN(fssystem::HasFile(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path)); } Result HasDirectory(bool *out, const char *path) { /* Get the filesystem accessor and sub path. */ impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Set up the true sub path. */ fs::Path sub_fs_path; R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path)); R_RETURN(fssystem::HasDirectory(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_game_card.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { namespace { const char *GetGameCardMountNameSuffix(GameCardPartition which) { switch (which) { case GameCardPartition::Update: return impl::GameCardFileSystemMountNameUpdateSuffix; case GameCardPartition::Normal: return impl::GameCardFileSystemMountNameNormalSuffix; case GameCardPartition::Secure: return impl::GameCardFileSystemMountNameSecureSuffix; AMS_UNREACHABLE_DEFAULT_CASE(); } } class GameCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { private: const GameCardHandle m_handle; const GameCardPartition m_partition; public: explicit GameCardCommonMountNameGenerator(GameCardHandle h, GameCardPartition p) : m_handle(h), m_partition(p) { /* ... */ } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ const size_t needed_size = util::Strnlen(impl::GameCardFileSystemMountName, MountNameLengthMax) + util::Strnlen(GetGameCardMountNameSuffix(m_partition), MountNameLengthMax) + sizeof(GameCardHandle) * 2 + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, "%s%s%08x:", impl::GameCardFileSystemMountName, GetGameCardMountNameSuffix(m_partition), m_handle); AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1); AMS_UNUSED(size); R_SUCCEED(); } }; } Result GetGameCardHandle(GameCardHandle *out) { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the handle. */ u32 handle; AMS_FS_R_TRY(device_operator->GetGameCardHandle(std::addressof(handle))); *out = handle; R_SUCCEED(); } Result MountGameCardPartition(const char *name, GameCardHandle handle, GameCardPartition partition) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountNameAllowingReserved(name)); /* Open the gamecard filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenGameCardFileSystem(std::addressof(fs), static_cast<u32>(handle), static_cast<u32>(partition))); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInGameCardC()); /* Allocate a new mountname generator. */ auto generator = std::make_unique<GameCardCommonMountNameGenerator>(handle, partition); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInGameCardD()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(name, handle, partition))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } bool IsGameCardInserted() { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_ABORT_UNLESS(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get insertion status. */ bool inserted; AMS_FS_R_ABORT_UNLESS(device_operator->IsGameCardInserted(std::addressof(inserted))); return inserted; } Result GetGameCardCid(void *dst, size_t size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(size >= sizeof(gc::GameCardIdSet), fs::ResultInvalidSize()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the id set. */ gc::GameCardIdSet gc_id_set; AMS_FS_R_TRY(device_operator->GetGameCardIdSet(sf::OutBuffer(std::addressof(gc_id_set), sizeof(gc_id_set)), static_cast<s64>(sizeof(gc_id_set)))); /* Copy the id set to output. */ std::memcpy(dst, std::addressof(gc_id_set), sizeof(gc_id_set)); R_SUCCEED(); } Result GetGameCardDeviceId(void *dst, size_t size) { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the cid. */ AMS_FS_R_TRY(device_operator->GetGameCardDeviceId(sf::OutBuffer(dst, size), static_cast<s64>(size))); R_SUCCEED(); } Result GetGameCardErrorReportInfo(GameCardErrorReportInfo *out) { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the error report info. */ AMS_FS_R_TRY(device_operator->GetGameCardErrorReportInfo(out)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_host.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { namespace { class HostRootCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { public: explicit HostRootCommonMountNameGenerator() { /* ... */ } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ constexpr size_t RequiredNameBufferSizeSize = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + 1; AMS_ASSERT(dst_size >= RequiredNameBufferSizeSize); AMS_UNUSED(RequiredNameBufferSizeSize); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":"); AMS_ASSERT(static_cast<size_t>(size) == RequiredNameBufferSizeSize - 1); AMS_UNUSED(size); R_SUCCEED(); } }; class HostCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { private: char m_path[fs::EntryNameLengthMax + 1]; public: HostCommonMountNameGenerator(const char *path) { util::Strlcpy<char>(m_path, path, sizeof(m_path)); } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ const size_t required_size = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + util::Strnlen<char>(m_path, sizeof(m_path)) + 1; /* @Host:%s */ R_UNLESS(dst_size >= required_size, fs::ResultTooLongPath()); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":%s", m_path); AMS_ASSERT(static_cast<size_t>(size) == required_size - 1); AMS_UNUSED(size); R_SUCCEED(); } }; Result OpenHostFileSystemImpl(std::unique_ptr<fs::fsa::IFileSystem> *out, const fssrv::sf::FspPath &path, const MountHostOption &option) { /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; if (option != MountHostOption::None) { R_TRY(fsp->OpenHostFileSystemWithOption(std::addressof(fs), path, option._value)); } else { R_TRY(fsp->OpenHostFileSystem(std::addressof(fs), path)); } /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInHostA()); /* Set the output. */ *out = std::move(fsa); R_SUCCEED(); } Result PreMountHost(std::unique_ptr<fs::HostCommonMountNameGenerator> *out, const char *name, const char *path) { /* Check pre-conditions. */ AMS_ASSERT(out != nullptr); /* Check the mount name. */ R_TRY(impl::CheckMountName(name)); /* Check that path is valid. */ R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Create a new HostCommonMountNameGenerator. */ *out = std::make_unique<HostCommonMountNameGenerator>(path); R_UNLESS(out->get() != nullptr, fs::ResultAllocationMemoryFailedInHostB()); R_SUCCEED(); } } namespace impl { Result OpenHostFileSystem(std::unique_ptr<fs::fsa::IFileSystem> *out, const char *name, const char *path, const fs::MountHostOption &option) { /* Validate arguments. */ R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); R_UNLESS(name != nullptr, fs::ResultNullptrArgument()); R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Check mount name isn't windows path or reserved. */ R_UNLESS(!fs::IsWindowsDrive(name), fs::ResultInvalidMountName()); R_UNLESS(!fs::impl::IsReservedMountName(name), fs::ResultInvalidMountName()); /* Convert the path for fsp. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); /* Ensure that the path doesn't correspond to the root. */ if (sf_path.str[0] == 0) { sf_path.str[0] = '.'; sf_path.str[1] = 0; } /* Open the host file system. */ R_RETURN(OpenHostFileSystemImpl(out, sf_path, option)); } } Result MountHost(const char *name, const char *root_path) { /* Pre-mount host. */ std::unique_ptr<fs::HostCommonMountNameGenerator> generator; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); /* Open the filesystem. */ std::unique_ptr<fs::fsa::IFileSystem> fsa; R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, MountHostOption::None), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); /* Declare registration helper. */ auto register_impl = [&]() -> Result { /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); }; /* Mount the filesystem. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountHost(const char *name, const char *root_path, const MountHostOption &option) { /* Pre-mount host. */ std::unique_ptr<fs::HostCommonMountNameGenerator> generator; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); /* Open the filesystem. */ std::unique_ptr<fs::fsa::IFileSystem> fsa; R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, option), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); /* Declare registration helper. */ auto register_impl = [&]() -> Result { /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); }; /* Mount the filesystem. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountHostRoot() { /* Create host root path. */ fssrv::sf::FspPath sf_path; sf_path.str[0] = 0; /* Open the filesystem. */ std::unique_ptr<fs::fsa::IFileSystem> fsa; R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, MountHostOption::None), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT())); /* Declare registration helper. */ auto register_impl = [&]() -> Result { /* Allocate a new mountname generator. */ auto generator = std::make_unique<HostRootCommonMountNameGenerator>(); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInHostC()); /* Register. */ R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator))); }; /* Mount the filesystem. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT())); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName); R_SUCCEED(); } Result MountHostRoot(const MountHostOption &option) { /* Create host root path. */ fssrv::sf::FspPath sf_path; sf_path.str[0] = 0; /* Open the filesystem. */ std::unique_ptr<fs::fsa::IFileSystem> fsa; R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, option), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option))); /* Declare registration helper. */ auto register_impl = [&]() -> Result { /* Allocate a new mountname generator. */ auto generator = std::make_unique<HostRootCommonMountNameGenerator>(); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInHostC()); /* Register. */ R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator))); }; /* Mount the filesystem. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName); R_SUCCEED(); } void UnmountHostRoot() { return Unmount(impl::HostRootFileSystemMountName); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_image_directory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result MountImageDirectory(const char *name, ImageDirectoryId id) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Open the image directory. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenImageDirectoryFileSystem(std::addressof(fs), static_cast<u32>(id))); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInImageDirectoryA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); }; /* Perform the mount. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(name, id))); /* Enable access logging. */ AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_memory_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constinit bool g_used_default_allocator = false; void *DefaultAllocate(size_t size) { g_used_default_allocator = true; return ams::Malloc(size); } void DefaultDeallocate(void *ptr, size_t size) { AMS_UNUSED(size); ams::Free(ptr); } constinit os::SdkMutex g_mutex; constinit AllocateFunction g_allocate_func = DefaultAllocate; constinit DeallocateFunction g_deallocate_func = DefaultDeallocate; constexpr size_t RequiredAlignment = alignof(u64); Result SetAllocatorImpl(AllocateFunction allocator, DeallocateFunction deallocator) { /* Ensure SetAllocator is used correctly. */ R_UNLESS(g_allocate_func == DefaultAllocate, fs::ResultAllocatorAlreadyRegistered()); R_UNLESS(g_deallocate_func == DefaultDeallocate, fs::ResultAllocatorAlreadyRegistered()); R_UNLESS(allocator != nullptr, fs::ResultNullptrArgument()); R_UNLESS(deallocator != nullptr, fs::ResultNullptrArgument()); R_UNLESS(!g_used_default_allocator, fs::ResultDefaultAllocatorUsed()); /* Set allocators. */ g_allocate_func = allocator; g_deallocate_func = deallocator; R_SUCCEED(); } } void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator) { R_ABORT_UNLESS(SetAllocatorImpl(allocator, deallocator)); } namespace impl { void LockAllocatorMutex() { g_mutex.Lock(); } void UnlockAllocatorMutex() { g_mutex.Unlock(); } void *AllocateUnsafe(size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_mutex.IsLockedByCurrentThread()); /* Allocate. */ void * const ptr = g_allocate_func(size); /* Check alignment. */ if (AMS_UNLIKELY(!util::IsAligned(reinterpret_cast<uintptr_t>(ptr), RequiredAlignment))) { R_ABORT_UNLESS(fs::ResultAllocatorAlignmentViolation()); } /* Return allocated pointer. */ return ptr; } void DeallocateUnsafe(void *ptr, size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_mutex.IsLockedByCurrentThread()); /* Deallocate the pointer. */ g_deallocate_func(ptr, size); } void *Allocate(size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_allocate_func != nullptr); /* Lock the allocator. */ std::scoped_lock lk(g_mutex); return AllocateUnsafe(size); } void Deallocate(void *ptr, size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_deallocate_func != nullptr); /* If the pointer is non-null, deallocate it. */ if (ptr != nullptr) { /* Lock the allocator. */ std::scoped_lock lk(g_mutex); DeallocateUnsafe(ptr, size); } } } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_memory_report_info.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result GetAndClearMemoryReportInfo(MemoryReportInfo *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Get the memory report info. */ AMS_FS_R_TRY(fsp->GetAndClearMemoryReportInfo(out)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_mmc.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result GetMmcCid(void *dst, size_t size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the cid. */ AMS_FS_R_TRY(device_operator->GetMmcCid(sf::OutBuffer(dst, size), static_cast<s64>(size))); R_SUCCEED(); } Result GetMmcSpeedMode(MmcSpeedMode *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the speed mode. */ s64 speed_mode = 0; AMS_FS_R_TRY(device_operator->GetMmcSpeedMode(std::addressof(speed_mode))); *out = static_cast<MmcSpeedMode>(speed_mode); R_SUCCEED(); } Result GetMmcPatrolCount(u32 *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the patrol count. */ AMS_FS_R_TRY(device_operator->GetMmcPatrolCount(out)); R_SUCCEED(); } Result GetAndClearMmcErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out_sei != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(out_log_size != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(out_log_buffer != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the error info. */ s64 log_size = 0; AMS_FS_R_TRY(device_operator->GetAndClearMmcErrorInfo(out_sei, std::addressof(log_size), sf::OutBuffer(out_log_buffer, log_buffer_size), static_cast<s64>(log_buffer_size))); *out_log_size = static_cast<size_t>(log_size); R_SUCCEED(); } Result GetMmcExtendedCsd(void *dst, size_t size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the csd. */ AMS_FS_R_TRY(device_operator->GetMmcExtendedCsd(sf::OutBuffer(dst, size), static_cast<s64>(size))); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_priority.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constexpr bool IsValidPriority(fs::Priority priority) { return priority == Priority_Low || priority == Priority_Normal || priority == Priority_Realtime; } constexpr bool IsValidPriorityRaw(fs::PriorityRaw priority_raw) { return priority_raw == PriorityRaw_Background || priority_raw == PriorityRaw_Low || priority_raw == PriorityRaw_Normal || priority_raw == PriorityRaw_Realtime; } fs::PriorityRaw ConvertPriorityToPriorityRaw(fs::Priority priority) { AMS_ASSERT(IsValidPriority(priority)); switch (priority) { case Priority_Low: return PriorityRaw_Low; case Priority_Normal: return PriorityRaw_Normal; case Priority_Realtime: return PriorityRaw_Realtime; AMS_UNREACHABLE_DEFAULT_CASE(); } } fs::Priority ConvertPriorityRawToPriority(fs::PriorityRaw priority_raw) { AMS_ASSERT(IsValidPriorityRaw(priority_raw)); switch (priority_raw) { case PriorityRaw_Background: return Priority_Low; case PriorityRaw_Low: return Priority_Low; case PriorityRaw_Normal: return Priority_Normal; case PriorityRaw_Realtime: return Priority_Realtime; AMS_UNREACHABLE_DEFAULT_CASE(); } } void UpdateTlsIoPriority(os::ThreadType *thread, u8 tls_io) { sf::SetFsInlineContext(thread, (tls_io & impl::TlsIoPriorityMask) | (sf::GetFsInlineContext(thread) & ~impl::TlsIoPriorityMask)); } Result GetPriorityRawImpl(fs::PriorityRaw *out, os::ThreadType *thread) { /* Validate arguments. */ R_UNLESS(thread != nullptr, fs::ResultNullptrArgument()); /* Get the raw priority. */ PriorityRaw priority_raw; R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread))); /* Set output. */ *out = priority_raw; R_SUCCEED(); } Result GetPriorityImpl(fs::Priority *out, os::ThreadType *thread) { /* Validate arguments. */ R_UNLESS(thread != nullptr, fs::ResultNullptrArgument()); /* Get the raw priority. */ PriorityRaw priority_raw; R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread))); /* Set output. */ *out = ConvertPriorityRawToPriority(priority_raw); R_SUCCEED(); } Result SetPriorityRawImpl(os::ThreadType *thread, fs::PriorityRaw priority_raw) { /* Validate arguments. */ R_UNLESS(thread != nullptr, fs::ResultNullptrArgument()); R_UNLESS(IsValidPriorityRaw(priority_raw), fs::ResultInvalidArgument()); /* Convert to tls io. */ u8 tls_io; R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), priority_raw)); /* Update the priority. */ UpdateTlsIoPriority(thread, tls_io); R_SUCCEED(); } Result SetPriorityImpl(os::ThreadType *thread, fs::Priority priority) { /* Validate arguments. */ R_UNLESS(thread != nullptr, fs::ResultNullptrArgument()); R_UNLESS(IsValidPriority(priority), fs::ResultInvalidArgument()); /* Convert to tls io. */ u8 tls_io; R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), ConvertPriorityToPriorityRaw(priority))); /* Update the priority. */ UpdateTlsIoPriority(thread, tls_io); R_SUCCEED(); } } Priority GetPriorityOnCurrentThread() { fs::Priority priority; AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); return priority; } Priority GetPriority(os::ThreadType *thread) { fs::Priority priority; AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); return priority; } PriorityRaw GetPriorityRawOnCurrentThread() { fs::PriorityRaw priority_raw; AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); return priority_raw; } PriorityRaw GetPriorityRawOnCurrentThreadInternal() { fs::PriorityRaw priority_raw; R_ABORT_UNLESS(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread())); return priority_raw; } PriorityRaw GetPriorityRaw(os::ThreadType *thread) { fs::PriorityRaw priority_raw; AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); return priority_raw; } void SetPriorityOnCurrentThread(Priority priority) { AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); } void SetPriority(os::ThreadType *thread, Priority priority) { AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); } void SetPriorityRawOnCurrentThread(PriorityRaw priority_raw) { AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); } void SetPriorityRaw(os::ThreadType *thread, PriorityRaw priority_raw) { AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{}))); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_program_id.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fs/fs_rights_id.hpp> #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { Result GetProgramId(ncm::ProgramId *out, const char *path, fs::ContentAttributes attr) { AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Convert the path for fsp. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->GetProgramId(out, sf_path, attr)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_remote_file_system_proxy.hpp" #include "fs_remote_file_system_proxy_for_loader.hpp" #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) extern "C" { extern u32 __nx_fs_num_sessions; } #endif namespace ams::fs { #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) RemoteFileSystemProxy::RemoteFileSystemProxy(int session_count) { /* Ensure we can connect to sm. */ R_ABORT_UNLESS(sm::Initialize()); ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); }; /* Initialize libnx. */ __nx_fs_num_sessions = static_cast<u32>(session_count); R_ABORT_UNLESS(::fsInitialize()); } RemoteFileSystemProxy::~RemoteFileSystemProxy() { ::fsExit(); } RemoteFileSystemProxyForLoader::RemoteFileSystemProxyForLoader() { /* Ensure we can connect to sm. */ R_ABORT_UNLESS(sm::Initialize()); ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); }; R_ABORT_UNLESS(::fsldrInitialize()); } RemoteFileSystemProxyForLoader::~RemoteFileSystemProxyForLoader() { ::fsldrExit(); } #endif } ================================================ FILE: libraries/libstratosphere/source/fs/fs_remote_file_system_proxy.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp" #include "impl/fs_remote_event_notifier.hpp" #include "impl/fs_remote_device_operator.hpp" namespace ams::fs { #if defined(ATMOSPHERE_OS_HORIZON) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" class RemoteFileSystemProxy { NON_COPYABLE(RemoteFileSystemProxy); NON_MOVEABLE(RemoteFileSystemProxy); private: using ObjectFactory = fssrv::impl::FileSystemObjectFactory; public: RemoteFileSystemProxy(int session_count); ~RemoteFileSystemProxy(); public: /* Command interface */ Result OpenFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 type) { AMS_ABORT("TODO"); } Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { /* Libnx does this for us automatically. */ AMS_UNUSED(client_pid); R_SUCCEED(); } Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { AMS_ABORT("TODO"); } Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type) { AMS_ABORT("TODO"); } Result OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type) { R_RETURN(this->OpenFileSystemWithId(out, path, fs::ContentAttributes_None, program_id, type)); } Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type) { ::FsFileSystem fs; R_TRY(fsOpenFileSystemWithId(std::addressof(fs), program_id, static_cast<::FsFileSystemType>(type), path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id) { AMS_ABORT("TODO"); } Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id) { AMS_ABORT("TODO"); } Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id) { FsStorage s; R_TRY(fsOpenBisStorage(std::addressof(s), static_cast<::FsBisPartitionId>(id))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IStorage, fssrv::impl::RemoteStorage>(s)); R_SUCCEED(); } Result InvalidateBisCache() { AMS_ABORT("TODO"); } Result OpenHostFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result OpenSdCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { ::FsFileSystem fs; R_TRY(fsOpenSdCardFileSystem(std::addressof(fs))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result FormatSdCardFileSystem() { AMS_ABORT("TODO"); } Result DeleteSaveDataFileSystem(u64 save_data_id) { AMS_UNUSED(save_data_id); AMS_ABORT("TODO: libnx binding"); } Result CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info) { AMS_ABORT("TODO"); } Result CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info) { static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); static_assert(sizeof(creation_info) == sizeof(::FsSaveDataCreationInfo)); R_RETURN(fsCreateSaveDataFileSystemBySystemSaveDataId(reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)), reinterpret_cast<const ::FsSaveDataCreationInfo *>(std::addressof(creation_info)))); } Result RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids) { AMS_ABORT("TODO"); } Result DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id) { R_RETURN(fsDeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<::FsSaveDataSpaceId>(indexer_space_id), save_data_id)); } Result FormatSdCardDryRun() { AMS_ABORT("TODO"); } Result IsExFatSupported(ams::sf::Out<bool> out) { AMS_ABORT("TODO"); } Result DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute) { static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute)); R_RETURN(fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)))); } Result OpenGameCardStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 handle, u32 partition) { AMS_ABORT("TODO"); } Result OpenGameCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 handle, u32 partition) { ::FsFileSystem fs; const ::FsGameCardHandle _hnd = {handle}; R_TRY(fsOpenGameCardFileSystem(std::addressof(fs), std::addressof(_hnd), static_cast<::FsGameCardPartition>(partition))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size) { R_RETURN(::fsExtendSaveDataFileSystem(static_cast<::FsSaveDataSpaceId>(space_id), save_data_id, available_size, journal_size)); } Result DeleteCacheStorage(u16 index) { AMS_ABORT("TODO"); } Result GetCacheStorageSize(ams::sf::Out<s64> out_size, ams::sf::Out<s64> out_journal_size, u16 index) { AMS_ABORT("TODO"); } Result CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt) { AMS_ABORT("TODO"); } Result OpenHostFileSystemWithOption(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 option) { AMS_ABORT("TODO"); } Result OpenSaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { ::FsFileSystem fs; R_TRY(fsOpenSaveDataFileSystem(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { ::FsFileSystem fs; R_TRY(fsOpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenReadOnlySaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { AMS_ABORT("TODO"); } Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id) { R_RETURN(fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id)); } Result ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id) { R_RETURN(fsReadSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), save_data_id)); } Result WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer) { R_RETURN(fsWriteSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id)); } /* ... */ Result OpenImageDirectoryFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) { ::FsFileSystem fs; R_TRY(fsOpenImageDirectoryFileSystem(std::addressof(fs), static_cast<::FsImageDirectoryId>(id))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } /* ... */ Result OpenContentStorageFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) { ::FsFileSystem fs; R_TRY(fsOpenContentStorageFileSystem(std::addressof(fs), static_cast<::FsContentStorageId>(id))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } /* ... */ Result OpenDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) { AMS_ABORT("TODO"); } Result OpenDataStorageByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::ProgramId program_id) { AMS_ABORT("TODO"); } Result OpenDataStorageByDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id) { ::FsStorage s; R_TRY(fsOpenDataStorageByDataId(std::addressof(s), data_id.value, static_cast<::NcmStorageId>(storage_id))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IStorage, fssrv::impl::RemoteStorage>(s)); R_SUCCEED(); } Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) { AMS_ABORT("TODO"); } Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index) { AMS_ABORT("TODO"); } Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index) { AMS_ABORT("TODO"); } Result OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type) { AMS_ABORT("TODO"); } Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type) { AMS_ABORT("TODO"); } Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out) { ::FsDeviceOperator d; R_TRY(fsOpenDeviceOperator(std::addressof(d))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IDeviceOperator, impl::RemoteDeviceOperator>(d)); R_SUCCEED(); } Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { ::FsEventNotifier e; R_TRY(fsOpenSdCardDetectionEventNotifier(std::addressof(e))); out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IEventNotifier, impl::RemoteEventNotifier>(e)); R_SUCCEED(); } Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { AMS_ABORT("TODO"); } Result OpenSystemDataUpdateEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { AMS_ABORT("TODO"); } Result NotifySystemDataUpdateEvent() { AMS_ABORT("TODO"); } /* ... */ Result SetCurrentPosixTime(s64 posix_time) { AMS_ABORT("TODO"); } /* ... */ Result GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id) { AMS_ABORT("TODO"); } Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key) { AMS_ABORT("TODO"); } Result UnregisterAllExternalKey() { AMS_ABORT("TODO"); } Result GetProgramId(ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) { static_assert(sizeof(ncm::ProgramId) == sizeof(u64)); R_RETURN(fsGetProgramId(reinterpret_cast<u64 *>(out.GetPointer()), path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)))); } Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path) { static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); R_RETURN(fsGetRightsIdByPath(path.str, reinterpret_cast<::FsRightsId *>(out.GetPointer()))); } Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path) { R_RETURN(this->GetRightsIdAndKeyGenerationByPath(out, out_key_generation, path, fs::ContentAttributes_None)) } Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) { static_assert(sizeof(RightsId) == sizeof(::FsRightsId)); R_RETURN(fsGetRightsIdAndKeyGenerationByPath(path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), out_key_generation.GetPointer(), reinterpret_cast<::FsRightsId *>(out.GetPointer()))); } Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference) { AMS_ABORT("TODO"); } Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id) { AMS_ABORT("TODO"); } Result VerifySaveDataFileSystemBySaveDataSpaceId() { AMS_ABORT("TODO"); } Result CorruptSaveDataFileSystemBySaveDataSpaceId() { AMS_ABORT("TODO"); } Result QuerySaveDataInternalStorageTotalSize() { AMS_ABORT("TODO"); } Result GetSaveDataCommitId() { AMS_ABORT("TODO"); } Result UnregisterExternalKey(const fs::RightsId &rights_id) { AMS_ABORT("TODO"); } Result SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed) { AMS_ABORT("TODO"); } Result SetSdCardAccessibility(bool accessible) { AMS_ABORT("TODO"); } Result IsSdCardAccessible(ams::sf::Out<bool> out) { AMS_ABORT("TODO"); } Result IsSignedSystemPartitionOnSdCardValid(ams::sf::Out<bool> out) { R_RETURN(fsIsSignedSystemPartitionOnSdCardValid(out.GetPointer())); } Result OpenAccessFailureDetectionEventNotifier() { AMS_ABORT("TODO"); } /* ... */ Result GetAndClearErrorInfo(ams::sf::Out<fs::FileSystemProxyErrorInfo> out) { static_assert(sizeof(fs::FileSystemProxyErrorInfo) == sizeof(::FsFileSystemProxyErrorInfo)); R_RETURN(::fsGetAndClearErrorInfo(reinterpret_cast<::FsFileSystemProxyErrorInfo *>(out.GetPointer()))); } Result RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count) { AMS_ABORT("TODO"); } Result SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result SetSaveDataSize(s64 size, s64 journal_size) { AMS_ABORT("TODO"); } Result SetSaveDataRootPath(const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result DisableAutoSaveDataCreation() { R_RETURN(::fsDisableAutoSaveDataCreation()); } Result SetGlobalAccessLogMode(u32 mode) { R_RETURN(::fsSetGlobalAccessLogMode(mode)); } Result GetGlobalAccessLogMode(sf::Out<u32> out) { R_RETURN(::fsGetGlobalAccessLogMode(out.GetPointer())); } Result OutputAccessLogToSdCard(const ams::sf::InBuffer &buf) { R_RETURN(::fsOutputAccessLogToSdCard(reinterpret_cast<const char *>(buf.GetPointer()), buf.GetSize())); } Result RegisterUpdatePartition() { AMS_ABORT("TODO"); } Result OpenRegisteredUpdatePartition(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { AMS_ABORT("TODO"); } Result GetAndClearMemoryReportInfo(ams::sf::Out<fs::MemoryReportInfo> out) { static_assert(sizeof(fs::MemoryReportInfo) == sizeof(::FsMemoryReportInfo)); R_RETURN(::fsGetAndClearMemoryReportInfo(reinterpret_cast<::FsMemoryReportInfo *>(out.GetPointer()))); } /* ... */ Result GetProgramIndexForAccessLog(ams::sf::Out<u32> out_idx, ams::sf::Out<u32> out_count) { R_RETURN(::fsGetProgramIndexForAccessLog(out_idx.GetPointer(), out_count.GetPointer())); } Result GetFsStackUsage(ams::sf::Out<u32> out, u32 type) { AMS_ABORT("TODO"); } Result UnsetSaveDataRootPath() { AMS_ABORT("TODO"); } Result OutputMultiProgramTagAccessLog() { AMS_ABORT("TODO"); } Result FlushAccessLogOnSdCard() { AMS_ABORT("TODO"); } Result OutputApplicationInfoAccessLog() { AMS_ABORT("TODO"); } Result RegisterDebugConfiguration(u32 key, s64 value) { AMS_ABORT("TODO"); } Result UnregisterDebugConfiguration(u32 key) { AMS_ABORT("TODO"); } Result OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf) { AMS_ABORT("TODO"); } Result CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset) { AMS_ABORT("TODO"); } /* ... */ }; static_assert(fssrv::sf::IsIFileSystemProxy<RemoteFileSystemProxy>); #pragma GCC diagnostic pop #endif } ================================================ FILE: libraries/libstratosphere/source/fs/fs_remote_file_system_proxy_for_loader.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp" namespace ams::fs { #if defined(ATMOSPHERE_OS_HORIZON) class RemoteFileSystemProxyForLoader { NON_COPYABLE(RemoteFileSystemProxyForLoader); NON_MOVEABLE(RemoteFileSystemProxyForLoader); private: using ObjectFactory = fssrv::impl::FileSystemObjectFactory; public: RemoteFileSystemProxyForLoader(); ~RemoteFileSystemProxyForLoader(); public: Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) { ::FsCodeInfo dummy; ::FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(std::addressof(dummy), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(fs::ContentAttributes_None)), std::addressof(fs))); out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) { ::FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(fs::ContentAttributes_None)), std::addressof(fs))); out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { ::FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs))); out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenCodeFileSystemDeprecated4(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { ::FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs))); out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { ::FsFileSystem fs; R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, static_cast<::NcmStorageId>(static_cast<u8>(storage_id)), nullptr, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs))); out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs)); R_SUCCEED(); } Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) { R_RETURN(fsldrIsArchivedProgram(process_id, out.GetPointer())); } Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { /* Libnx does this for us automatically. */ AMS_UNUSED(client_pid); R_SUCCEED(); } }; static_assert(fssrv::sf::IsIFileSystemProxyForLoader<RemoteFileSystemProxyForLoader>); #endif } ================================================ FILE: libraries/libstratosphere/source/fs/fs_result_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constinit bool g_handled_by_application = false; } void SetResultHandledByApplication(bool application) { g_handled_by_application = application; } namespace impl { bool IsAbortNeeded(Result result) { /* If the result succeeded, we never need to abort. */ if (R_SUCCEEDED(result)) { return false; } /* Get the abort specifier from current context. */ switch (GetCurrentThreadFsContext()->HandleResult(result)) { case AbortSpecifier::Default: if (g_handled_by_application) { return !fs::ResultHandledByAllProcess::Includes(result); } else { return !(fs::ResultHandledByAllProcess::Includes(result) || fs::ResultHandledBySystemProcess::Includes(result)); } case AbortSpecifier::Abort: return true; case AbortSpecifier::Return: return false; AMS_UNREACHABLE_DEFAULT_CASE(); } } void LogResultErrorMessage(Result result) { /* TODO: log specific results */ AMS_UNUSED(result); } void LogErrorMessage(Result result, const char *function) { /* If the result succeeded, there's nothing to log. */ if (R_SUCCEEDED(result)) { return; } /* TODO: Actually log stuff. */ AMS_UNUSED(function); } } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_rights_id.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fs/fs_rights_id.hpp> #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { Result GetRightsId(RightsId *out, const char *path, fs::ContentAttributes attr) { /* If possible, prefer the non-removed functionality. */ if (hos::GetVersion() >= hos::Version_3_0_0) { u8 dummy_key_generation; R_RETURN(GetRightsId(out, std::addressof(dummy_key_generation), path, attr)); } AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Convert the path for fsp. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->GetRightsIdByPath(out, sf_path)); R_SUCCEED(); } Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path, fs::ContentAttributes attr) { AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(out_key_generation != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); /* Convert the path for fsp. */ fssrv::sf::FspPath sf_path; R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path)); auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->GetRightsIdAndKeyGenerationByPath(out, out_key_generation, sf_path, attr)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { Result ConvertNcaCorruptedResult(Result res) { AMS_ASSERT(fs::ResultNcaCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultInvalidNcaFileSystemType, fs::ResultInvalidRomNcaFileSystemType()) R_CONVERT(fs::ResultInvalidAcidFileSize, fs::ResultInvalidRomAcidFileSize()) R_CONVERT(fs::ResultInvalidAcidSize, fs::ResultInvalidRomAcidSize()) R_CONVERT(fs::ResultInvalidAcid, fs::ResultInvalidRomAcid()) R_CONVERT(fs::ResultAcidVerificationFailed, fs::ResultRomAcidVerificationFailed()) R_CONVERT(fs::ResultInvalidNcaSignature, fs::ResultInvalidRomNcaSignature()) R_CONVERT(fs::ResultNcaHeaderSignature1VerificationFailed, fs::ResultRomNcaHeaderSignature1VerificationFailed()) R_CONVERT(fs::ResultNcaHeaderSignature2VerificationFailed, fs::ResultRomNcaHeaderSignature2VerificationFailed()) R_CONVERT(fs::ResultNcaFsHeaderHashVerificationFailed, fs::ResultRomNcaFsHeaderHashVerificationFailed()) R_CONVERT(fs::ResultInvalidNcaKeyIndex, fs::ResultInvalidRomNcaKeyIndex()) R_CONVERT(fs::ResultInvalidNcaFsHeaderHashType, fs::ResultInvalidRomNcaFsHeaderHashType()) R_CONVERT(fs::ResultInvalidNcaFsHeaderEncryptionType, fs::ResultInvalidRomNcaFsHeaderEncryptionType()) R_CONVERT(fs::ResultInvalidHierarchicalSha256BlockSize, fs::ResultInvalidRomHierarchicalSha256BlockSize()) R_CONVERT(fs::ResultInvalidHierarchicalSha256LayerCount, fs::ResultInvalidRomHierarchicalSha256LayerCount()) R_CONVERT(fs::ResultHierarchicalSha256BaseStorageTooLarge, fs::ResultRomHierarchicalSha256BaseStorageTooLarge()) R_CONVERT(fs::ResultHierarchicalSha256HashVerificationFailed, fs::ResultRomHierarchicalSha256HashVerificationFailed()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultNcaCorrupted()); } Result ConvertIntegrityVerificationStorageCorruptedResult(Result res) { AMS_ASSERT(fs::ResultIntegrityVerificationStorageCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultIncorrectIntegrityVerificationMagic, fs::ResultIncorrectRomIntegrityVerificationMagic()) R_CONVERT(fs::ResultInvalidZeroHash, fs::ResultInvalidRomZeroHash()) R_CONVERT(fs::ResultNonRealDataVerificationFailed, fs::ResultRomNonRealDataVerificationFailed()) R_CONVERT(fs::ResultInvalidHierarchicalIntegrityVerificationLayerCount, fs::ResultInvalidRomHierarchicalIntegrityVerificationLayerCount()) R_CONVERT(fs::ResultClearedRealDataVerificationFailed, fs::ResultClearedRomRealDataVerificationFailed()) R_CONVERT(fs::ResultUnclearedRealDataVerificationFailed, fs::ResultUnclearedRomRealDataVerificationFailed()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultIntegrityVerificationStorageCorrupted()); } Result ConvertBuiltInStorageCorruptedResult(Result res) { AMS_ASSERT(fs::ResultBuiltInStorageCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultGptHeaderVerificationFailed, fs::ResultRomGptHeaderVerificationFailed()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultBuiltInStorageCorrupted()); } Result ConvertPartitionFileSystemCorruptedResult(Result res) { AMS_ASSERT(fs::ResultPartitionFileSystemCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultInvalidSha256PartitionHashTarget, fs::ResultInvalidRomSha256PartitionHashTarget()) R_CONVERT(fs::ResultSha256PartitionHashVerificationFailed, fs::ResultRomSha256PartitionHashVerificationFailed()) R_CONVERT(fs::ResultPartitionSignatureVerificationFailed, fs::ResultRomPartitionSignatureVerificationFailed()) R_CONVERT(fs::ResultSha256PartitionSignatureVerificationFailed, fs::ResultRomSha256PartitionSignatureVerificationFailed()) R_CONVERT(fs::ResultInvalidPartitionEntryOffset, fs::ResultInvalidRomPartitionEntryOffset()) R_CONVERT(fs::ResultInvalidSha256PartitionMetaDataSize, fs::ResultInvalidRomSha256PartitionMetaDataSize()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultPartitionFileSystemCorrupted()); } Result ConvertFatFileSystemCorruptedResult(Result res) { AMS_ASSERT(fs::ResultFatFileSystemCorrupted::Includes(res)); R_RETURN(res); } Result ConvertHostFileSystemCorruptedResult(Result res) { AMS_ASSERT(fs::ResultHostFileSystemCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultHostEntryCorrupted, fs::ResultRomHostEntryCorrupted()) R_CONVERT(fs::ResultHostFileDataCorrupted, fs::ResultRomHostFileDataCorrupted()) R_CONVERT(fs::ResultHostFileCorrupted, fs::ResultRomHostFileCorrupted()) R_CONVERT(fs::ResultInvalidHostHandle, fs::ResultInvalidRomHostHandle()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultHostFileSystemCorrupted()); } Result ConvertDatabaseCorruptedResult(Result res) { AMS_ASSERT(fs::ResultDatabaseCorrupted::Includes(res)); R_TRY_CATCH(res) { R_CONVERT(fs::ResultInvalidAllocationTableBlock, fs::ResultInvalidRomAllocationTableBlock()) R_CONVERT(fs::ResultInvalidKeyValueListElementIndex, fs::ResultInvalidRomKeyValueListElementIndex()) R_CATCH_ALL() { /* ... */ } } R_END_TRY_CATCH; AMS_ASSERT(false); R_THROW(fs::ResultDatabaseCorrupted()); } Result ConvertRomFsResult(Result res) { R_TRY_CATCH(res) { R_CONVERT(fs::ResultUnsupportedVersion, fs::ResultUnsupportedRomVersion()) R_CONVERT(fs::ResultNcaCorrupted, ConvertNcaCorruptedResult(res)) R_CONVERT(fs::ResultIntegrityVerificationStorageCorrupted, ConvertIntegrityVerificationStorageCorruptedResult(res)) R_CONVERT(fs::ResultBuiltInStorageCorrupted, ConvertBuiltInStorageCorruptedResult(res)) R_CONVERT(fs::ResultPartitionFileSystemCorrupted, ConvertPartitionFileSystemCorruptedResult(res)) R_CONVERT(fs::ResultFatFileSystemCorrupted, ConvertFatFileSystemCorruptedResult(res)) R_CONVERT(fs::ResultHostFileSystemCorrupted, ConvertHostFileSystemCorruptedResult(res)) R_CONVERT(fs::ResultDatabaseCorrupted, ConvertDatabaseCorruptedResult(res)) R_CONVERT(fs::ResultNotFound, fs::ResultPathNotFound()) R_CONVERT(fs::ResultPermissionDenied, fs::ResultTargetLocked()) R_CONVERT(fs::ResultIncompatiblePath, fs::ResultPathNotFound()) } R_END_TRY_CATCH; R_SUCCEED(); } Result ReadFile(IStorage *storage, s64 offset, void *buffer, size_t size) { AMS_ASSERT(storage != nullptr); AMS_ASSERT(offset >= 0); AMS_ASSERT(buffer != nullptr || size == 0); R_RETURN(ConvertRomFsResult(storage->Read(offset, buffer, size))); } Result ReadFileHeader(IStorage *storage, RomFileSystemInformation *out) { AMS_ASSERT(storage != nullptr); AMS_ASSERT(out != nullptr); R_RETURN(ReadFile(storage, 0, out, sizeof(*out))); } constexpr size_t CalculateRequiredWorkingMemorySize(const RomFileSystemInformation &header) { const size_t needed_size = header.directory_bucket_size + header.directory_entry_size + header.file_bucket_size + header.file_entry_size; return util::AlignUp(needed_size, 8); } class RomFsFile : public fsa::IFile, public impl::Newable { private: RomFsFileSystem *m_parent; s64 m_start; s64 m_end; public: RomFsFile(RomFsFileSystem *p, s64 s, s64 e) : m_parent(p), m_start(s), m_end(e) { /* ... */ } virtual ~RomFsFile() { /* ... */ } Result VerifyArguments(size_t *out, s64 offset, void *buf, size_t size, const fs::ReadOption &option) { R_TRY(DryRead(out, offset, size, option, fs::OpenMode_Read)); AMS_ASSERT(this->GetStorage() != nullptr); AMS_ASSERT(offset >= 0); AMS_ASSERT(buf != nullptr || size == 0); AMS_UNUSED(buf); R_SUCCEED(); } Result ConvertResult(Result res) const { R_RETURN(ConvertRomFsResult(res)); } s64 GetOffset() const { return m_start; } s64 GetSize() const { return m_end - m_start; } IStorage *GetStorage() { return m_parent->GetBaseStorage(); } public: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override { size_t read_size = 0; R_TRY(this->VerifyArguments(std::addressof(read_size), offset, buffer, size, option)); R_TRY(this->ConvertResult(this->GetStorage()->Read(offset + m_start, buffer, size))); *out = read_size; R_SUCCEED(); } virtual Result DoGetSize(s64 *out) override { *out = this->GetSize(); R_SUCCEED(); } virtual Result DoFlush() override { R_SUCCEED(); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override { AMS_UNUSED(offset, buffer, size, option); R_THROW(fs::ResultUnsupportedWriteForRomFsFile()); } virtual Result DoSetSize(s64 size) override { AMS_UNUSED(size); R_THROW(fs::ResultUnsupportedWriteForRomFsFile()); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override { switch (op_id) { case OperationId::Invalidate: R_RETURN(this->GetStorage()->OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max())); case OperationId::QueryRange: { R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); R_UNLESS(this->GetSize() >= offset, fs::ResultOutOfRange()); auto operate_size = size; if (offset + operate_size > this->GetSize() || offset + operate_size < offset) { operate_size = this->GetSize() - offset; } R_RETURN(this->GetStorage()->OperateRange(dst, dst_size, op_id, m_start + offset, operate_size, src, src_size)); } default: R_THROW(fs::ResultUnsupportedOperateRangeForRomFsFile()); } } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { AMS_ABORT(); } }; class RomFsDirectory : public fsa::IDirectory, public impl::Newable { private: using FindPosition = RomFsFileSystem::RomFileTable::FindPosition; private: RomFsFileSystem *m_parent; FindPosition m_current_find; FindPosition m_first_find; fs::OpenDirectoryMode m_mode; public: RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : m_parent(p), m_current_find(f), m_first_find(f), m_mode(m) { /* ... */ } virtual ~RomFsDirectory() override { /* ... */ } public: virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override { R_RETURN(this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries)); } virtual Result DoGetEntryCount(s64 *out) override { FindPosition find = m_first_find; R_RETURN(this->ReadInternal(out, std::addressof(find), nullptr, 0)); } private: Result ReadInternal(s64 *out_count, FindPosition *find, DirectoryEntry *out_entries, s64 max_entries) { AMS_ASSERT(out_count != nullptr); AMS_ASSERT(find != nullptr); constexpr size_t NameBufferSize = fs::EntryNameLengthMax + 1; char *name_buf = static_cast<char *>(::ams::fs::impl::Allocate(NameBufferSize)); R_UNLESS(name_buf != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemE()); ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(name_buf, NameBufferSize); }; s32 i = 0; if (m_mode & fs::OpenDirectoryMode_Directory) { while (i < max_entries || out_entries == nullptr) { R_TRY_CATCH(m_parent->GetRomFileTable()->FindNextDirectory(name_buf, find, NameBufferSize)) { R_CATCH(fs::ResultDbmFindFinished) { break; } } R_END_TRY_CATCH; if (out_entries) { const size_t name_len = util::Strnlen(name_buf, NameBufferSize); R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath()); std::memcpy(out_entries[i].name, name_buf, name_len); out_entries[i].name[name_len] = '\x00'; out_entries[i].type = fs::DirectoryEntryType_Directory; out_entries[i].file_size = 0; } i++; } } if (m_mode & fs::OpenDirectoryMode_File) { while (i < max_entries || out_entries == nullptr) { auto file_pos = find->next_file; R_TRY_CATCH(m_parent->GetRomFileTable()->FindNextFile(name_buf, find, NameBufferSize)) { R_CATCH(fs::ResultDbmFindFinished) { break; } } R_END_TRY_CATCH; if (out_entries) { const size_t name_len = util::Strnlen(name_buf, NameBufferSize); R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath()); std::memcpy(out_entries[i].name, name_buf, name_len); out_entries[i].name[name_len] = '\x00'; out_entries[i].type = fs::DirectoryEntryType_File; RomFsFileSystem::RomFileTable::FileInfo file_info; R_TRY(m_parent->GetRomFileTable()->OpenFile(std::addressof(file_info), m_parent->GetRomFileTable()->PositionToFileId(file_pos))); out_entries[i].file_size = file_info.size.Get(); } i++; } } *out_count = i; R_SUCCEED(); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override { AMS_ABORT(); } }; } RomFsFileSystem::RomFsFileSystem() : m_base_storage() { /* ... */ } RomFsFileSystem::~RomFsFileSystem() { /* ... */ } Result RomFsFileSystem::GetRequiredWorkingMemorySize(size_t *out, IStorage *storage) { RomFileSystemInformation header; R_TRY(ReadFileHeader(storage, std::addressof(header))); *out = CalculateRequiredWorkingMemorySize(header); R_SUCCEED(); } Result RomFsFileSystem::Initialize(IStorage *base, void *work, size_t work_size, bool use_cache) { AMS_ABORT_UNLESS(!use_cache || work != nullptr); AMS_ABORT_UNLESS(base != nullptr); /* Read the header. */ RomFileSystemInformation header; R_TRY(ReadFileHeader(base, std::addressof(header))); /* Set up our storages. */ if (use_cache) { const size_t needed_size = CalculateRequiredWorkingMemorySize(header); R_UNLESS(work_size >= needed_size, fs::ResultPreconditionViolation()); u8 *buf = static_cast<u8 *>(work); auto dir_bucket_buf = buf; buf += header.directory_bucket_size; auto dir_entry_buf = buf; buf += header.directory_entry_size; auto file_bucket_buf = buf; buf += header.file_bucket_size; auto file_entry_buf = buf; buf += header.file_entry_size; R_TRY(ReadFile(base, header.directory_bucket_offset, dir_bucket_buf, header.directory_bucket_size)); R_TRY(ReadFile(base, header.directory_entry_offset, dir_entry_buf, header.directory_entry_size)); R_TRY(ReadFile(base, header.file_bucket_offset, file_bucket_buf, header.file_bucket_size)); R_TRY(ReadFile(base, header.file_entry_offset, file_entry_buf, header.file_entry_size)); m_dir_bucket_storage.reset(new MemoryStorage(dir_bucket_buf, header.directory_bucket_size)); m_dir_entry_storage.reset(new MemoryStorage(dir_entry_buf, header.directory_entry_size)); m_file_bucket_storage.reset(new MemoryStorage(file_bucket_buf, header.file_bucket_size)); m_file_entry_storage.reset(new MemoryStorage(file_entry_buf, header.file_entry_size)); } else { m_dir_bucket_storage.reset(new SubStorage(base, header.directory_bucket_offset, header.directory_bucket_size)); m_dir_entry_storage.reset(new SubStorage(base, header.directory_entry_offset, header.directory_entry_size)); m_file_bucket_storage.reset(new SubStorage(base, header.file_bucket_offset, header.file_bucket_size)); m_file_entry_storage.reset(new SubStorage(base, header.file_entry_offset, header.file_entry_size)); } /* Ensure we allocated storages successfully. */ R_UNLESS(m_dir_bucket_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA()); R_UNLESS(m_dir_entry_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA()); R_UNLESS(m_file_bucket_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA()); R_UNLESS(m_file_entry_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA()); /* Initialize the rom table. */ { SubStorage db(m_dir_bucket_storage.get(), 0, header.directory_bucket_size); SubStorage de(m_dir_entry_storage.get(), 0, header.directory_entry_size); SubStorage fb(m_file_bucket_storage.get(), 0, header.file_bucket_size); SubStorage fe(m_file_entry_storage.get(), 0, header.file_entry_size); R_TRY(m_rom_file_table.Initialize(db, de, fb, fe)); } /* Set members. */ m_entry_size = header.body_offset; m_base_storage = base; R_SUCCEED(); } Result RomFsFileSystem::Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache) { m_unique_storage = std::move(base); R_RETURN(this->Initialize(m_unique_storage.get(), work, work_size, use_cache)); } Result RomFsFileSystem::GetFileInfo(RomFileTable::FileInfo *out, const char *path) { R_TRY_CATCH(m_rom_file_table.OpenFile(out, path)) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()); R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound()); } R_END_TRY_CATCH; R_SUCCEED(); } IStorage *RomFsFileSystem::GetBaseStorage() { return m_base_storage; } RomFsFileSystem::RomFileTable *RomFsFileSystem::GetRomFileTable() { return std::addressof(m_rom_file_table); } Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const char *path) { AMS_ABORT_UNLESS(out != nullptr); AMS_ABORT_UNLESS(path != nullptr); RomFileTable::FileInfo info; R_TRY(this->GetFileInfo(std::addressof(info), path)); *out = m_entry_size + info.offset.Get(); R_SUCCEED(); } Result RomFsFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) { AMS_UNUSED(path, size, flags); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoDeleteFile(const fs::Path &path) { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoCreateDirectory(const fs::Path &path) { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoDeleteDirectory(const fs::Path &path) { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) { AMS_UNUSED(old_path, new_path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) { HierarchicalRomFileTable::FindPosition find_pos; R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find_pos), path.GetString())) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) R_CATCH(fs::ResultDbmInvalidOperation) { *out = fs::DirectoryEntryType_File; R_SUCCEED(); } } R_END_TRY_CATCH; *out = fs::DirectoryEntryType_Directory; R_SUCCEED(); } Result RomFsFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) { AMS_ASSERT(out_file != nullptr); R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode()); RomFileTable::FileInfo file_info{}; R_TRY(this->GetFileInfo(std::addressof(file_info), path.GetString())); auto file = std::make_unique<RomFsFile>(this, m_entry_size + file_info.offset.Get(), m_entry_size + file_info.offset.Get() + file_info.size.Get()); R_UNLESS(file != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemB()); *out_file = std::move(file); R_SUCCEED(); } Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) { AMS_ASSERT(out_dir != nullptr); RomFileTable::FindPosition find; R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path.GetString())) { R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound()) R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound()) } R_END_TRY_CATCH; auto dir = std::make_unique<RomFsDirectory>(this, find, mode); R_UNLESS(dir != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemC()); *out_dir = std::move(dir); R_SUCCEED(); } Result RomFsFileSystem::DoCommit() { R_SUCCEED(); } Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(path); *out = 0; R_SUCCEED(); } Result RomFsFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) { AMS_UNUSED(out, path); R_THROW(fs::ResultUnsupportedGetTotalSpaceSizeForRomFsFileSystem()); } Result RomFsFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) { AMS_UNUSED(path); R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem()); } Result RomFsFileSystem::DoCommitProvisionally(s64 counter) { AMS_UNUSED(counter); R_THROW(fs::ResultUnsupportedCommitProvisionallyForRomFsFileSystem()); } Result RomFsFileSystem::DoRollback() { R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_save_data_management.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace impl { Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataId id) { auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraData(sf::OutBuffer(out, sizeof(*out)), id)); R_SUCCEED(); } Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataSpaceId space_id, SaveDataId id) { auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(sf::OutBuffer(out, sizeof(*out)), static_cast<u8>(space_id), id)); R_SUCCEED(); } Result WriteSaveDataFileSystemExtraData(SaveDataSpaceId space_id, SaveDataId id, const SaveDataExtraData &extra_data) { auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_TRY(fsp->WriteSaveDataFileSystemExtraData(id, static_cast<u8>(space_id), sf::InBuffer(std::addressof(extra_data), sizeof(extra_data)))); R_SUCCEED(); } } void DisableAutoSaveDataCreation() { auto fsp = impl::GetFileSystemProxyServiceObject(); AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation()); } Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) { auto create_impl = [=]() -> Result { const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, save_id); const SaveDataCreationInfo info = { .size = size, .journal_size = journal_size, .block_size = DefaultSaveDataBlockSize, .owner_id = owner_id, .flags = flags, .space_id = space_id, .pseudo = false, }; auto fsp = impl::GetFileSystemProxyServiceObject(); R_RETURN(fsp->CreateSaveDataFileSystemBySystemSaveDataId(attribute, info)); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(create_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(space_id, save_id, user_id, owner_id, size, journal_size, flags))); R_SUCCEED(); } Result CreateSystemSaveData(SystemSaveDataId save_id, s64 size, s64 journal_size, u32 flags) { R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, InvalidUserId, 0, size, journal_size, flags)); } Result CreateSystemSaveData(SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) { R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, InvalidUserId, owner_id, size, journal_size, flags)); } Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) { R_RETURN(CreateSystemSaveData(space_id, save_id, InvalidUserId, owner_id, size, journal_size, flags)); } Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, s64 size, s64 journal_size, u32 flags) { R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, user_id, 0, size, journal_size, flags)); } Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) { R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, user_id, owner_id, size, journal_size, flags)); } Result DeleteSaveData(SaveDataId id) { auto delete_impl = [=]() -> Result { auto fsp = impl::GetFileSystemProxyServiceObject(); R_RETURN(fsp->DeleteSaveDataFileSystem(id)); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, id)); R_SUCCEED(); } Result DeleteSaveData(SaveDataSpaceId space_id, SaveDataId id) { auto delete_impl = [=]() -> Result { auto fsp = impl::GetFileSystemProxyServiceObject(); R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<u8>(space_id), id)); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(space_id, id))); R_SUCCEED(); } Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) { auto delete_impl = [=]() -> Result { const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); auto fsp = impl::GetFileSystemProxyServiceObject(); R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataAttribute(static_cast<u8>(space_id), attribute)); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(space_id, id, user_id))); R_SUCCEED(); } Result GetSaveDataFlags(u32 *out, SaveDataId id) { SaveDataExtraData extra_data; R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id)); *out = extra_data.flags; R_SUCCEED(); } Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id) { SaveDataExtraData extra_data; R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), space_id, id)); *out = extra_data.flags; R_SUCCEED(); } Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags) { SaveDataExtraData extra_data; R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), space_id, id)); extra_data.flags = flags; R_RETURN(impl::WriteSaveDataFileSystemExtraData(space_id, id, extra_data)); } Result GetSaveDataAvailableSize(s64 *out, SaveDataId id) { SaveDataExtraData extra_data; R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id)); *out = extra_data.available_size; R_SUCCEED(); } Result GetSaveDataJournalSize(s64 *out, SaveDataId id) { SaveDataExtraData extra_data; R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id)); *out = extra_data.journal_size; R_SUCCEED(); } Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size) { auto extend_impl = [=]() -> Result { auto fsp = impl::GetFileSystemProxyServiceObject(); R_RETURN(fsp->ExtendSaveDataFileSystem(static_cast<u8>(space_id), id, available_size, journal_size)); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(extend_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(space_id, id, available_size, journal_size))); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_scoped_setter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs { template<typename T> class ScopedSetter { NON_COPYABLE(ScopedSetter); private: T *m_ptr; T m_value; public: constexpr ALWAYS_INLINE ScopedSetter(T &p, T v) : m_ptr(std::addressof(p)), m_value(v) { /* ... */ } ALWAYS_INLINE ~ScopedSetter() { if (m_ptr) { *m_ptr = m_value; } } ALWAYS_INLINE ScopedSetter(ScopedSetter &&rhs) { m_ptr = rhs.m_ptr; m_value = rhs.m_value; rhs.Reset(); } ALWAYS_INLINE ScopedSetter &operator=(ScopedSetter &&rhs) { m_ptr = rhs.m_ptr; m_value = rhs.m_value; rhs.Reset(); return *this; } ALWAYS_INLINE void Set(T v) { m_value = v; } private: ALWAYS_INLINE void Reset() { m_ptr = nullptr; } }; template<typename T> ALWAYS_INLINE ScopedSetter<T> MakeScopedSetter(T &p, T v) { return ScopedSetter<T>(p, v); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_sd_card.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" #include "impl/fs_event_notifier_service_object_adapter.hpp" namespace ams::fs { namespace { constexpr inline const char AtmosphereErrorReportDirectory[] = "/atmosphere/erpt_reports"; /* NOTE: Nintendo does not attach a generator to a mounted SD card filesystem. */ /* However, it is desirable for homebrew to be able to access SD via common path. */ class SdCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable { public: explicit SdCardCommonMountNameGenerator() { /* ... */ } virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override { /* Determine how much space we need. */ const size_t needed_size = util::Strnlen(impl::SdCardFileSystemMountName, MountNameLengthMax) + 2; AMS_ABORT_UNLESS(dst_size >= needed_size); /* Generate the name. */ const auto size = util::SNPrintf(dst, dst_size, "%s:", impl::SdCardFileSystemMountName); AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1); AMS_UNUSED(size); R_SUCCEED(); } }; } Result MountSdCard(const char *name) { /* Validate the mount name. */ AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::CheckMountNameAllowingReserved(name), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name)); /* Open the SD card filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSdCardA()); /* Allocate a new mountname generator. */ /* NOTE: Nintendo does not attach a generator. */ auto generator = std::make_unique<SdCardCommonMountNameGenerator>(); R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInSdCardA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator))); } Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name) { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Open the SD card filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs))); /* Allocate a new filesystem wrapper. */ auto fsa = fs::AllocateShared<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSdCardA()); /* Ensure that the error report directory exists. */ constexpr fs::Path fs_path = fs::MakeConstantPath(AtmosphereErrorReportDirectory); R_TRY(fssystem::EnsureDirectory(fsa.get(), fs_path)); /* Create a subdirectory filesystem. */ auto subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(fsa)); R_UNLESS(subdir_fs != nullptr, fs::ResultAllocationMemoryFailedInSdCardA()); R_TRY(subdir_fs->Initialize(fs_path)); /* Register. */ R_RETURN(fsa::Register(name, std::move(subdir_fs))); } Result OpenSdCardDetectionEventNotifier(std::unique_ptr<IEventNotifier> *out) { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Try to open an event notifier. */ sf::SharedPointer<fssrv::sf::IEventNotifier> notifier; AMS_FS_R_TRY(fsp->OpenSdCardDetectionEventNotifier(std::addressof(notifier))); /* Create an event notifier adapter. */ auto adapter = std::make_unique<impl::EventNotifierObjectAdapter>(std::move(notifier)); AMS_FS_R_UNLESS(adapter != nullptr, fs::ResultAllocationMemoryFailedInSdCardB()); *out = std::move(adapter); R_SUCCEED(); } bool IsSdCardInserted() { auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_ABORT_UNLESS(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get insertion status. */ bool inserted; AMS_FS_R_ABORT_UNLESS(device_operator->IsSdCardInserted(std::addressof(inserted))); return inserted; } Result GetSdCardSpeedMode(SdCardSpeedMode *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the speed mode. */ s64 speed_mode = 0; AMS_FS_R_TRY(device_operator->GetSdCardSpeedMode(std::addressof(speed_mode))); *out = static_cast<SdCardSpeedMode>(speed_mode); R_SUCCEED(); } Result GetSdCardCid(void *dst, size_t size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the cid. */ AMS_FS_R_TRY(device_operator->GetSdCardCid(sf::OutBuffer(dst, size), static_cast<s64>(size))); R_SUCCEED(); } Result GetSdCardUserAreaSize(s64 *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the size. */ AMS_FS_R_TRY(device_operator->GetSdCardUserAreaSize(out)); R_SUCCEED(); } Result GetSdCardProtectedAreaSize(s64 *out) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the size. */ AMS_FS_R_TRY(device_operator->GetSdCardProtectedAreaSize(out)); R_SUCCEED(); } Result GetAndClearSdCardErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) { /* Check pre-conditions. */ AMS_FS_R_UNLESS(out_sei != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(out_log_size != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(out_log_buffer != nullptr, fs::ResultNullptrArgument()); auto fsp = impl::GetFileSystemProxyServiceObject(); /* Open a device operator. */ sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator; AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator))); /* Get the error info. */ s64 log_size = 0; AMS_FS_R_TRY(device_operator->GetAndClearSdCardErrorInfo(out_sei, std::addressof(log_size), sf::OutBuffer(out_log_buffer, log_buffer_size), static_cast<s64>(log_buffer_size))); *out_log_size = static_cast<size_t>(log_size); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_signed_system_partition.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_filesystem_accessor.hpp" #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" namespace ams::fs { namespace { Result GetSignedSystemPartitionOnSdCardValid(char *out, impl::FileSystemAccessor *accessor) { R_TRY_CATCH(accessor->QueryEntry(out, sizeof(*out), nullptr, 0, fsa::QueryId::IsSignedSystemPartitionOnSdCardValid, "/")) { /* If querying isn't supported, then the partition isn't valid. */ R_CATCH(fs::ResultUnsupportedOperation) { *out = false; } } R_END_TRY_CATCH_WITH_ABORT_UNLESS; R_SUCCEED(); } } bool IsSignedSystemPartitionOnSdCardValid(const char *system_root_path) { /* Get the accessor for the system filesystem. */ impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_ABORT_UNLESS(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), system_root_path)); char is_valid; AMS_FS_R_ABORT_UNLESS(GetSignedSystemPartitionOnSdCardValid(std::addressof(is_valid), accessor)); return is_valid; } bool IsSignedSystemPartitionOnSdCardValidDeprecated() { /* Ensure we only call with correct version. */ auto version = hos::GetVersion(); AMS_ABORT_UNLESS(hos::Version_4_0_0 <= version && version < hos::Version_8_0_0); /* Check that the partition is valid. */ auto fsp = impl::GetFileSystemProxyServiceObject(); bool is_valid; AMS_FS_R_ABORT_UNLESS(fsp->IsSignedSystemPartitionOnSdCardValid(std::addressof(is_valid))); return is_valid; } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_system_data.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" namespace ams::fs { Result QueryMountSystemDataCacheSize(size_t *out, ncm::SystemDataId data_id) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(impl::QueryMountDataCacheSize(out, data_id, ncm::StorageId::BuiltInSystem), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(data_id, out))); R_SUCCEED(); } Result MountSystemData(const char *name, ncm::SystemDataId data_id) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id))); AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } Result MountSystemData(const char *name, ncm::SystemDataId data_id, void *cache_buffer, size_t cache_size) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem, cache_buffer, cache_size), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id))); AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fs_system_save_data.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fsa/fs_mount_utils.hpp" #include "impl/fs_file_system_proxy_service_object.hpp" #include "impl/fs_file_system_service_object_adapter.hpp" namespace ams::fs { Result MountSystemSaveData(const char *name, SystemSaveDataId id) { R_RETURN(MountSystemSaveData(name, id, InvalidUserId)); } Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id) { R_RETURN(MountSystemSaveData(name, space_id, id, InvalidUserId)); } Result MountSystemSaveData(const char *name, SystemSaveDataId id, UserId user_id) { R_RETURN(MountSystemSaveData(name, SaveDataSpaceId::System, id, user_id)); } Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) { auto mount_impl = [=]() -> Result { /* Validate the mount name. */ R_TRY(impl::CheckMountName(name)); /* Create the attribute. */ const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id); /* Open the filesystem. */ auto fsp = impl::GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystem> fs; R_TRY(fsp->OpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<u8>(space_id), attribute)); /* Allocate a new filesystem wrapper. */ auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs)); R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSystemSaveDataA()); /* Register. */ R_RETURN(fsa::Register(name, std::move(fsa))); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(name, space_id, id, user_id))); AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_directory_accessor.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs::impl { DirectoryAccessor::DirectoryAccessor(std::unique_ptr<fsa::IDirectory>&& d, FileSystemAccessor &p) : m_impl(std::move(d)), m_parent(p) { /* ... */ } DirectoryAccessor::~DirectoryAccessor() { m_impl.reset(); m_parent.NotifyCloseDirectory(this); } Result DirectoryAccessor::Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { R_RETURN(m_impl->Read(out_count, out_entries, max_entries)); } Result DirectoryAccessor::GetEntryCount(s64 *out) { R_RETURN(m_impl->GetEntryCount(out)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { class FileSystemAccessor; class DirectoryAccessor : public util::IntrusiveListBaseNode<DirectoryAccessor>, public Newable { NON_COPYABLE(DirectoryAccessor); private: std::unique_ptr<fsa::IDirectory> m_impl; FileSystemAccessor &m_parent; public: DirectoryAccessor(std::unique_ptr<fsa::IDirectory>&& d, FileSystemAccessor &p); ~DirectoryAccessor(); Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries); Result GetEntryCount(s64 *out); FileSystemAccessor *GetParent() const { return std::addressof(m_parent); } }; } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_file_accessor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "../fs_scoped_setter.hpp" #include "../fs_file_path_hash.hpp" #include "fs_file_accessor.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs::impl { FileAccessor::FileAccessor(std::unique_ptr<fsa::IFile>&& f, FileSystemAccessor *p, OpenMode mode) : m_impl(std::move(f)), m_parent(p), m_write_state(WriteState::None), m_write_result(ResultSuccess()), m_open_mode(mode) { /* ... */ } FileAccessor::~FileAccessor() { /* Ensure that all files are flushed. */ if (R_SUCCEEDED(m_write_result)) { AMS_FS_ABORT_UNLESS_WITH_RESULT(m_write_state != WriteState::NeedsFlush, fs::ResultNeedFlush()); } m_impl.reset(); if (m_parent != nullptr) { m_parent->NotifyCloseFile(this); } } Result FileAccessor::ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache) { /* TODO */ AMS_UNUSED(out, offset, buf, size, option, use_path_cache, use_data_cache); AMS_ABORT(); } Result FileAccessor::ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) { R_RETURN(m_impl->Read(out, offset, buf, size, option)); } Result FileAccessor::Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) { /* Get a handle to this file for use in logging. */ FileHandle handle = { this }; /* Fail after a write fails. */ R_UNLESS(R_SUCCEEDED(m_write_result), AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(m_write_result, handle, "ReadFile", AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_FILE(out, offset, size))); /* TODO: Support cache. */ const bool use_path_cache = m_parent != nullptr && m_file_path_hash != nullptr; const bool use_data_cache = /* TODO */false && m_parent != nullptr && m_parent->IsFileDataCacheAttachable(); if (use_path_cache && use_data_cache && false) { /* TODO */ R_RETURN(this->ReadWithCacheAccessLog(out, offset, buf, size, option, use_path_cache, use_data_cache)); } else { R_RETURN(AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(this->ReadWithoutCacheAccessLog(out, offset, buf, size, option), handle, "ReadFile", AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_FILE(out, offset, size))); } } Result FileAccessor::Write(s64 offset, const void *buf, size_t size, const WriteOption &option) { /* Fail after a write fails. */ R_TRY(m_write_result); auto setter = MakeScopedSetter(m_write_state, WriteState::Failed); if (m_file_path_hash != nullptr && /* TODO */ false) { /* TODO */ AMS_ABORT(); } else { R_TRY(this->UpdateLastResult(m_impl->Write(offset, buf, size, option))); } setter.Set(option.HasFlushFlag() ? WriteState::None : WriteState::NeedsFlush); R_SUCCEED(); } Result FileAccessor::Flush() { /* Fail after a write fails. */ R_TRY(m_write_result); auto setter = MakeScopedSetter(m_write_state, WriteState::Failed); R_TRY(this->UpdateLastResult(m_impl->Flush())); setter.Set(WriteState::None); R_SUCCEED(); } Result FileAccessor::SetSize(s64 size) { /* Fail after a write fails. */ R_TRY(m_write_result); const WriteState old_write_state = m_write_state; auto setter = MakeScopedSetter(m_write_state, WriteState::Failed); R_TRY(this->UpdateLastResult(m_impl->SetSize(size))); if (m_file_path_hash != nullptr) { /* TODO: invalidate path cache */ } setter.Set(old_write_state); R_SUCCEED(); } Result FileAccessor::GetSize(s64 *out) { /* Fail after a write fails. */ R_TRY(m_write_result); R_RETURN(m_impl->GetSize(out)); } Result FileAccessor::OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size) { R_RETURN(m_impl->OperateRange(dst, dst_size, operation, offset, size, src, src_size)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_file_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { struct FilePathHash; class FileSystemAccessor; enum class WriteState { None, NeedsFlush, Failed, }; class FileAccessor : public util::IntrusiveListBaseNode<FileAccessor>, public Newable { NON_COPYABLE(FileAccessor); private: std::unique_ptr<fsa::IFile> m_impl; FileSystemAccessor * const m_parent; WriteState m_write_state; Result m_write_result; const OpenMode m_open_mode; std::unique_ptr<FilePathHash> m_file_path_hash; s32 m_path_hash_index; public: FileAccessor(std::unique_ptr<fsa::IFile>&& f, FileSystemAccessor *p, OpenMode mode); ~FileAccessor(); Result Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option); Result Write(s64 offset, const void *buf, size_t size, const WriteOption &option); Result Flush(); Result SetSize(s64 size); Result GetSize(s64 *out); Result OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size); OpenMode GetOpenMode() const { return m_open_mode; } WriteState GetWriteState() const { return m_write_state; } FileSystemAccessor *GetParent() const { return m_parent; } void SetFilePathHash(std::unique_ptr<FilePathHash>&& file_path_hash, s32 index); Result ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option); private: Result ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache); ALWAYS_INLINE Result UpdateLastResult(Result r) { if (!fs::ResultNotEnoughFreeSpace::Includes(r)) { m_write_result = r; } R_RETURN(r); } }; } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_file_accessor.hpp" #include "fs_directory_accessor.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs::impl { namespace { template<typename List, typename Iter> void Remove(List &list, Iter *desired) { for (auto it = list.cbegin(); it != list.cend(); ++it) { if (it.operator->() == desired) { list.erase(it); return; } } /* This should never happen. */ AMS_ABORT(); } Result SetMountName(char *dst, const char *name) { R_UNLESS(name[0] != 0, fs::ResultInvalidMountName()); const size_t n_len = util::Strlcpy<char>(dst, name, MountNameLengthMax + 1); R_UNLESS(n_len <= MountNameLengthMax, fs::ResultInvalidMountName()); R_SUCCEED(); } template<typename List> Result ValidateNoOpenWriteModeFiles(List &list) { for (auto it = list.cbegin(); it != list.cend(); it++) { R_UNLESS((it->GetOpenMode() & OpenMode_Write) == 0, fs::ResultWriteModeFileNotClosed()); } R_SUCCEED(); } } FileSystemAccessor::FileSystemAccessor(const char *n, std::unique_ptr<fsa::IFileSystem> &&fs, std::unique_ptr<fsa::ICommonMountNameGenerator> &&generator) : m_impl(std::move(fs)), m_open_list_lock(), m_mount_name_generator(std::move(generator)), m_access_log_enabled(false), m_data_cache_attachable(false), m_path_cache_attachable(false), m_path_cache_attached(false), m_multi_commit_supported(false), m_path_flags() { R_ABORT_UNLESS(SetMountName(m_name.str, n)); if (std::strcmp(m_name.str, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME) == 0) { m_path_flags.AllowWindowsPath(); } } FileSystemAccessor::~FileSystemAccessor() { std::scoped_lock lk(m_open_list_lock); /* TODO: Iterate over list entries. */ if (!m_open_file_list.empty()) { R_ABORT_UNLESS(fs::ResultFileNotClosed()); } if (!m_open_dir_list.empty()) { R_ABORT_UNLESS(fs::ResultDirectoryNotClosed()); } if (m_path_cache_attached) { /* TODO: Invalidate path cache */ } } Result FileSystemAccessor::GetCommonMountName(char *dst, size_t dst_size) const { R_UNLESS(m_mount_name_generator != nullptr, fs::ResultPreconditionViolation()); R_RETURN(m_mount_name_generator->GenerateCommonMountName(dst, dst_size)); } std::shared_ptr<fssrv::impl::FileSystemInterfaceAdapter> FileSystemAccessor::GetMultiCommitTarget() { if (m_multi_commit_supported) { AMS_ABORT("TODO: Support multi commit"); } return nullptr; } void FileSystemAccessor::NotifyCloseFile(FileAccessor *f) { std::scoped_lock lk(m_open_list_lock); Remove(m_open_file_list, f); } void FileSystemAccessor::NotifyCloseDirectory(DirectoryAccessor *d) { std::scoped_lock lk(m_open_list_lock); Remove(m_open_dir_list, d); } Result FileSystemAccessor::SetUpPath(fs::Path *out, const char *p) { /* Initialize the path appropriately. */ bool normalized; size_t len; if (R_SUCCEEDED(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(len), p, m_path_flags)) && normalized) { /* We can use the input buffer directly. */ R_TRY(out->SetShallowBuffer(p)); } else { /* Initialize with appropriate slash replacement. */ if (m_path_flags.IsWindowsPathAllowed()) { R_TRY(out->InitializeWithReplaceForwardSlashes(p)); } else { R_TRY(out->InitializeWithReplaceBackslash(p)); } /* Ensure we're normalized. */ R_TRY(out->Normalize(m_path_flags)); } /* Check the path isn't too long. */ R_UNLESS(out->GetLength() <= fs::EntryNameLengthMax, fs::ResultTooLongPath()); R_SUCCEED(); } Result FileSystemAccessor::CreateFile(const char *path, s64 size, int option) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); if (m_path_cache_attached) { /* TODO: Path cache */ R_TRY(m_impl->CreateFile(normalized_path, size, option)); } else { R_TRY(m_impl->CreateFile(normalized_path, size, option)); } R_SUCCEED(); } Result FileSystemAccessor::DeleteFile(const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->DeleteFile(normalized_path)); } Result FileSystemAccessor::CreateDirectory(const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->CreateDirectory(normalized_path)); } Result FileSystemAccessor::DeleteDirectory(const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->DeleteDirectory(normalized_path)); } Result FileSystemAccessor::DeleteDirectoryRecursively(const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->DeleteDirectoryRecursively(normalized_path)); } Result FileSystemAccessor::RenameFile(const char *old_path, const char *new_path) { /* Create path. */ fs::Path normalized_old_path; fs::Path normalized_new_path; R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path)); R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path)); if (m_path_cache_attached) { /* TODO: Path cache */ R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path)); } else { R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path)); } R_SUCCEED(); } Result FileSystemAccessor::RenameDirectory(const char *old_path, const char *new_path) { /* Create path. */ fs::Path normalized_old_path; fs::Path normalized_new_path; R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path)); R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path)); if (m_path_cache_attached) { /* TODO: Path cache */ R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path)); } else { R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path)); } R_SUCCEED(); } Result FileSystemAccessor::GetEntryType(DirectoryEntryType *out, const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->GetEntryType(out, normalized_path)); } Result FileSystemAccessor::OpenFile(std::unique_ptr<FileAccessor> *out_file, const char *path, OpenMode mode) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); std::unique_ptr<fsa::IFile> file; R_TRY(m_impl->OpenFile(std::addressof(file), normalized_path, mode)); auto accessor = new FileAccessor(std::move(file), this, mode); R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInFileSystemAccessorA()); { std::scoped_lock lk(m_open_list_lock); m_open_file_list.push_back(*accessor); } if (m_path_cache_attached) { if (mode & OpenMode_AllowAppend) { /* TODO: Append Path cache */ } else { /* TODO: Non-append path cache */ } } out_file->reset(accessor); R_SUCCEED(); } Result FileSystemAccessor::OpenDirectory(std::unique_ptr<DirectoryAccessor> *out_dir, const char *path, OpenDirectoryMode mode) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); std::unique_ptr<fsa::IDirectory> dir; R_TRY(m_impl->OpenDirectory(std::addressof(dir), normalized_path, mode)); auto accessor = new DirectoryAccessor(std::move(dir), *this); R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInFileSystemAccessorB()); { std::scoped_lock lk(m_open_list_lock); m_open_dir_list.push_back(*accessor); } out_dir->reset(accessor); R_SUCCEED(); } Result FileSystemAccessor::Commit() { { std::scoped_lock lk(m_open_list_lock); R_ABORT_UNLESS(ValidateNoOpenWriteModeFiles(m_open_file_list)); } R_RETURN(m_impl->Commit()); } Result FileSystemAccessor::GetFreeSpaceSize(s64 *out, const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->GetFreeSpaceSize(out, normalized_path)); } Result FileSystemAccessor::GetTotalSpaceSize(s64 *out, const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->GetTotalSpaceSize(out, normalized_path)); } Result FileSystemAccessor::CleanDirectoryRecursively(const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->CleanDirectoryRecursively(normalized_path)); } Result FileSystemAccessor::GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->GetFileTimeStampRaw(out, normalized_path)); } Result FileSystemAccessor::QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { /* Create path. */ fs::Path normalized_path; R_TRY(this->SetUpPath(std::addressof(normalized_path), path)); R_RETURN(m_impl->QueryEntry(dst, dst_size, src, src_size, query, normalized_path)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "fs_mount_name.hpp" namespace ams::fs::impl { class FileAccessor; class DirectoryAccessor; class FileSystemAccessor : public util::IntrusiveListBaseNode<FileSystemAccessor>, public Newable { NON_COPYABLE(FileSystemAccessor); friend class FileAccessor; friend class DirectoryAccessor; private: using FileList = util::IntrusiveListBaseTraits<FileAccessor>::ListType; using DirList = util::IntrusiveListBaseTraits<DirectoryAccessor>::ListType; private: MountName m_name; std::unique_ptr<fsa::IFileSystem> m_impl; FileList m_open_file_list; DirList m_open_dir_list; os::SdkMutex m_open_list_lock; std::unique_ptr<fsa::ICommonMountNameGenerator> m_mount_name_generator; bool m_access_log_enabled; bool m_data_cache_attachable; bool m_path_cache_attachable; bool m_path_cache_attached; bool m_multi_commit_supported; PathFlags m_path_flags; public: FileSystemAccessor(const char *name, std::unique_ptr<fsa::IFileSystem> &&fs, std::unique_ptr<fsa::ICommonMountNameGenerator> &&generator = nullptr); virtual ~FileSystemAccessor(); Result CreateFile(const char *path, s64 size, int option); Result DeleteFile(const char *path); Result CreateDirectory(const char *path); Result DeleteDirectory(const char *path); Result DeleteDirectoryRecursively(const char *path); Result RenameFile(const char *old_path, const char *new_path); Result RenameDirectory(const char *old_path, const char *new_path); Result GetEntryType(DirectoryEntryType *out, const char *path); Result OpenFile(std::unique_ptr<FileAccessor> *out_file, const char *path, OpenMode mode); Result OpenDirectory(std::unique_ptr<DirectoryAccessor> *out_dir, const char *path, OpenDirectoryMode mode); Result Commit(); Result GetFreeSpaceSize(s64 *out, const char *path); Result GetTotalSpaceSize(s64 *out, const char *path); Result CleanDirectoryRecursively(const char *path); Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path); Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path); const char *GetName() const { return m_name.str; } Result GetCommonMountName(char *dst, size_t dst_size) const; void SetAccessLogEnabled(bool en) { m_access_log_enabled = en; } void SetFileDataCacheAttachable(bool en) { m_data_cache_attachable = en; } void SetPathBasedFileDataCacheAttachable(bool en) { m_path_cache_attachable = en; } void SetMultiCommitSupported(bool en) { m_multi_commit_supported = en; } bool IsEnabledAccessLog() const { return m_access_log_enabled; } bool IsFileDataCacheAttachable() const { return m_data_cache_attachable; } bool IsPathBasedFileDataCacheAttachable() const { return m_path_cache_attachable; } void AttachPathBasedFileDataCache() { if (this->IsPathBasedFileDataCacheAttachable()) { m_path_cache_attached = true; } } void DetachPathBasedFileDataCache() { m_path_cache_attached = false; } std::shared_ptr<fssrv::impl::FileSystemInterfaceAdapter> GetMultiCommitTarget(); fsa::IFileSystem *GetRawFileSystemUnsafe() { return m_impl.get(); } private: void NotifyCloseFile(FileAccessor *f); void NotifyCloseDirectory(DirectoryAccessor *d); public: Result SetUpPath(fs::Path *out, const char *p); }; } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_mount_name.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs { struct MountName { char str[MountNameLengthMax + 1]; }; static_assert(util::is_pod<MountName>::value); } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_mount_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_mount_table.hpp" namespace ams::fs::impl { namespace { bool MatchesName(const FileSystemAccessor &accessor, const char *name) { return std::strncmp(accessor.GetName(), name, sizeof(MountName)) == 0; } } bool MountTable::CanAcceptMountName(const char *name) { for (const auto &fs : m_fs_list) { if (MatchesName(fs, name)) { return false; } } return true; } Result MountTable::Mount(std::unique_ptr<FileSystemAccessor> &&fs) { std::scoped_lock lk(m_mutex); R_UNLESS(this->CanAcceptMountName(fs->GetName()), fs::ResultMountNameAlreadyExists()); m_fs_list.push_back(*fs.release()); R_SUCCEED(); } Result MountTable::Find(FileSystemAccessor **out, const char *name) { std::scoped_lock lk(m_mutex); for (auto &fs : m_fs_list) { if (MatchesName(fs, name)) { *out = std::addressof(fs); R_SUCCEED(); } } R_THROW(fs::ResultNotMounted()); } void MountTable::Unmount(const char *name) { std::scoped_lock lk(m_mutex); for (auto it = m_fs_list.cbegin(); it != m_fs_list.cend(); it++) { if (MatchesName(*it, name)) { auto p = std::addressof(*it); m_fs_list.erase(it); delete p; return; } } R_ABORT_UNLESS(fs::ResultNotMounted()); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_mount_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "fs_filesystem_accessor.hpp" namespace ams::fs::impl { class MountTable : public Newable { NON_COPYABLE(MountTable); NON_MOVEABLE(MountTable); private: using FileSystemList = util::IntrusiveListBaseTraits<FileSystemAccessor>::ListType; private: FileSystemList m_fs_list; os::SdkMutex m_mutex; public: constexpr MountTable() : m_fs_list(), m_mutex() { /* ... */ } private: bool CanAcceptMountName(const char *name); public: Result Mount(std::unique_ptr<FileSystemAccessor> &&fs); Result Find(FileSystemAccessor **out, const char *name); void Unmount(const char *name); }; } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_mount_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_filesystem_accessor.hpp" #include "fs_mount_utils.hpp" #include "fs_user_mount_table.hpp" namespace ams::fs::impl { namespace { const char *FindMountNameDriveSeparator(const char *path) { for (const char *cur = path; cur < path + MountNameLengthMax + 1 && *cur != StringTraits::NullTerminator; ++cur) { if (*cur == StringTraits::DriveSeparator) { return cur; } } return nullptr; } constexpr bool IsHostRootPath(const char *path) { #if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) return fs::IsWindowsDrive(path) || fs::IsUncPath(path); #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) return fs::IsPathAbsolute(path); #else #error "Unknown OS for host path identification" #endif } Result GetMountNameAndSubPath(MountName *out_mount_name, const char **out_sub_path, const char *path) { /* Handle the Host-path case. */ if (IsHostRootPath(path)) { std::strncpy(out_mount_name->str, HostRootFileSystemMountName, MountNameLengthMax); out_mount_name->str[MountNameLengthMax] = '\x00'; *out_sub_path = path; R_SUCCEED(); } /* Locate the drive separator. */ const char *drive_separator = FindMountNameDriveSeparator(path); R_UNLESS(drive_separator != nullptr, fs::ResultInvalidMountName()); /* Ensure the mount name isn't too long. */ const size_t len = drive_separator - path; R_UNLESS(0 < len, fs::ResultInvalidMountName()); R_UNLESS(len <= MountNameLengthMax, fs::ResultInvalidMountName()); /* Ensure the result sub-path is valid. */ const char *sub_path = drive_separator + 1; const auto starts_with_dir = (sub_path[0] == StringTraits::DirectorySeparator) || (sub_path[0] == StringTraits::AlternateDirectorySeparator); R_UNLESS(starts_with_dir, fs::ResultInvalidPathFormat()); /* Set output. */ std::memcpy(out_mount_name->str, path, len); out_mount_name->str[len] = StringTraits::NullTerminator; *out_sub_path = sub_path; R_SUCCEED(); } } bool IsValidMountName(const char *name) { if (name[0] == StringTraits::NullTerminator) { return false; } if ((('a' <= name[0] && name[0] <= 'z') || ('A' <= name[0] && name[0] <= 'Z')) && name[1] == StringTraits::NullTerminator) { return false; } size_t len = 0; for (const char *cur = name; *cur != StringTraits::NullTerminator; ++cur) { if (*cur == StringTraits::DriveSeparator || *cur == StringTraits::DirectorySeparator) { return false; } if ((++len) > MountNameLengthMax) { return false; } } return util::VerifyUtf8String(name, len); } bool IsReservedMountName(const char *name) { return name[0] == ReservedMountNamePrefixCharacter; } Result CheckMountName(const char *name) { R_TRY(CheckMountNameAllowingReserved(name)); R_UNLESS(!impl::IsReservedMountName(name), fs::ResultInvalidMountName()); R_SUCCEED(); } Result CheckMountNameAllowingReserved(const char *name) { R_UNLESS(name != nullptr, fs::ResultInvalidMountName()); R_UNLESS(impl::IsValidMountName(name), fs::ResultInvalidMountName()); R_SUCCEED(); } Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path) { R_UNLESS(out_accessor != nullptr, fs::ResultUnexpectedInFindFileSystemA()); R_UNLESS(out_sub_path != nullptr, fs::ResultUnexpectedInFindFileSystemA()); R_UNLESS(path != nullptr, fs::ResultNullptrArgument()); R_UNLESS(strncmp(path, HostRootFileSystemMountName, util::Strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultNotMounted()); MountName mount_name; R_TRY(GetMountNameAndSubPath(std::addressof(mount_name), out_sub_path, path)); R_RETURN(impl::Find(out_accessor, mount_name.str)); } Result Unmount(const char *name) { impl::FileSystemAccessor *accessor; R_TRY(impl::Find(std::addressof(accessor), name)); if (accessor->IsFileDataCacheAttachable()) { /* TODO: Data cache purge */ } impl::Unregister(name); R_SUCCEED(); } } namespace ams::fs { Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src) { /* Ensure neither argument is nullptr. */ AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); AMS_FS_R_UNLESS(src != nullptr, fs::ResultNullptrArgument()); /* Get the mount name and sub path for the path. */ MountName mount_name; const char *sub_path; AMS_FS_R_TRY(impl::GetMountNameAndSubPath(std::addressof(mount_name), std::addressof(sub_path), src)); impl::FileSystemAccessor *accessor; AMS_FS_R_TRY(impl::Find(std::addressof(accessor), mount_name.str)); AMS_FS_R_TRY(accessor->GetCommonMountName(dst, dst_size)); const auto mount_name_len = util::Strnlen(dst, dst_size); const auto common_path_len = util::SNPrintf(dst + mount_name_len, dst_size - mount_name_len, "%s", sub_path); AMS_FS_R_UNLESS(static_cast<size_t>(common_path_len) < dst_size - mount_name_len, fs::ResultTooLongPath()); R_SUCCEED(); } void Unmount(const char *mount_name) { AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG_UNMOUNT(impl::Unmount(mount_name), mount_name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_mount_utils.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { class FileSystemAccessor; Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path); bool IsWindowsDrive(const char *name); bool IsReservedMountName(const char *name); bool IsValidMountName(const char *name); Result CheckMountName(const char *name); Result CheckMountNameAllowingReserved(const char *name); } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_registrar.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_filesystem_accessor.hpp" #include "fs_user_mount_table.hpp" namespace ams::fs::fsa { Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs) { auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs)); R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterA()); R_RETURN(impl::Register(std::move(accessor))); } Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator) { auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs), std::move(generator)); R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterB()); R_RETURN(impl::Register(std::move(accessor))); } Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator, bool use_data_cache, bool use_path_cache, bool support_multi_commit) { auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs), std::move(generator)); R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterB()); accessor->SetFileDataCacheAttachable(use_data_cache); accessor->SetPathBasedFileDataCacheAttachable(use_path_cache); accessor->SetMultiCommitSupported(support_multi_commit); R_RETURN(impl::Register(std::move(accessor))); } void Unregister(const char *name) { impl::Unregister(name); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_directory.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_directory_accessor.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs { namespace { ALWAYS_INLINE impl::DirectoryAccessor *Get(DirectoryHandle handle) { return reinterpret_cast<impl::DirectoryAccessor *>(handle.handle); } } Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Read(out_count, out_entries, max_entries), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_DIRECTORY(out_count, max_entries))); R_SUCCEED(); } Result GetDirectoryEntryCount(s64 *out, DirectoryHandle handle) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->GetEntryCount(out), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_DIRECTORY_ENTRY_COUNT(out))); R_SUCCEED(); } void CloseDirectory(DirectoryHandle handle) { static_cast<void>(AMS_FS_IMPL_ACCESS_LOG((delete Get(handle), ResultSuccess()), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_file.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_file_accessor.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs { namespace { ALWAYS_INLINE impl::FileAccessor *Get(FileHandle handle) { return reinterpret_cast<impl::FileAccessor *>(handle.handle); } Result ReadFileImpl(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { R_TRY(Get(handle)->Read(out, offset, buffer, size, option)); R_SUCCEED(); } } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { size_t read_size; AMS_FS_R_TRY(ReadFileImpl(std::addressof(read_size), handle, offset, buffer, size, option)); AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange()); R_SUCCEED(); } Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) { size_t read_size; AMS_FS_R_TRY(ReadFileImpl(std::addressof(read_size), handle, offset, buffer, size, ReadOption())); AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange()); R_SUCCEED(); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) { AMS_FS_R_TRY(ReadFileImpl(out, handle, offset, buffer, size, option)); R_SUCCEED(); } Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) { AMS_FS_R_TRY(ReadFileImpl(out, handle, offset, buffer, size, ReadOption())); R_SUCCEED(); } Result GetFileSize(s64 *out, FileHandle handle) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->GetSize(out), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_FILE_SIZE(out))); R_SUCCEED(); } Result FlushFile(FileHandle handle) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Flush(), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); R_SUCCEED(); } Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Write(offset, buffer, size, option), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE(option), offset, size)); R_SUCCEED(); } Result SetFileSize(FileHandle handle, s64 size) { AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->SetSize(size), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, size)); R_SUCCEED(); } int GetFileOpenMode(FileHandle handle) { const int mode = Get(handle)->GetOpenMode(); static_cast<void>(AMS_FS_IMPL_ACCESS_LOG(ResultSuccess(), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE, static_cast<u32>(mode))); return mode; } void CloseFile(FileHandle handle) { static_cast<void>(AMS_FS_IMPL_ACCESS_LOG((delete Get(handle), ResultSuccess()), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE)); } Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size) { AMS_FS_R_TRY(Get(handle)->OperateRange(out, sizeof(*out), OperationId::QueryRange, offset, size, nullptr, 0)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_filesystem.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_filesystem_accessor.hpp" #include "fs_file_accessor.hpp" #include "fs_directory_accessor.hpp" #include "fs_mount_utils.hpp" #include "fs_user_mount_table.hpp" namespace ams::fs { Result CreateFile(const char *path, s64 size) { R_RETURN(CreateFile(path, size, 0)); } Result CreateFile(const char* path, s64 size, int option) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CreateFile(sub_path, size, option), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE, path, size)); R_SUCCEED(); } Result DeleteFile(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteFile(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); R_SUCCEED(); } Result CreateDirectory(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CreateDirectory(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); R_SUCCEED(); } Result DeleteDirectory(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteDirectory(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); R_SUCCEED(); } Result DeleteDirectoryRecursively(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteDirectoryRecursively(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); R_SUCCEED(); } Result RenameFile(const char *old_path, const char *new_path) { impl::FileSystemAccessor *old_accessor; impl::FileSystemAccessor *new_accessor; const char *old_sub_path; const char *new_sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); auto rename_impl = [=]() -> Result { R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem()); R_TRY(old_accessor->RenameFile(old_sub_path, new_sub_path)); R_SUCCEED(); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(rename_impl(), nullptr, old_accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); R_SUCCEED(); } Result RenameDirectory(const char *old_path, const char *new_path) { impl::FileSystemAccessor *old_accessor; impl::FileSystemAccessor *new_accessor; const char *old_sub_path; const char *new_sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); auto rename_impl = [=]() -> Result { R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem()); R_TRY(old_accessor->RenameDirectory(old_sub_path, new_sub_path)); R_SUCCEED(); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(rename_impl(), nullptr, old_accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path)); R_SUCCEED(); } Result GetEntryType(DirectoryEntryType *out, const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->GetEntryType(out, sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_ENTRY_TYPE(out, path))); R_SUCCEED(); } Result OpenFile(FileHandle *out_file, const char *path, int mode) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode))); std::unique_ptr<impl::FileAccessor> file_accessor; auto open_impl = [&]() -> Result { R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument()); R_TRY(accessor->OpenFile(std::addressof(file_accessor), sub_path, static_cast<OpenMode>(mode))); R_SUCCEED(); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(open_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode))); out_file->handle = file_accessor.release(); R_SUCCEED(); } Result OpenDirectory(DirectoryHandle *out_dir, const char *path, int mode) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode))); std::unique_ptr<impl::DirectoryAccessor> dir_accessor; auto open_impl = [&]() -> Result { R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument()); R_TRY(accessor->OpenDirectory(std::addressof(dir_accessor), sub_path, static_cast<OpenDirectoryMode>(mode))); R_SUCCEED(); }; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(open_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode))); out_dir->handle = dir_accessor.release(); R_SUCCEED(); } Result CleanDirectoryRecursively(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CleanDirectoryRecursively(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path)); R_SUCCEED(); } Result GetFreeSpaceSize(s64 *out, const char *path) { /* Find the filesystem without access logging. */ impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Get the total space size. */ AMS_FS_R_TRY(accessor->GetFreeSpaceSize(out, sub_path)); R_SUCCEED(); } Result GetTotalSpaceSize(s64 *out, const char *path) { /* Find the filesystem without access logging. */ impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); /* Get the total space size. */ AMS_FS_R_TRY(accessor->GetTotalSpaceSize(out, sub_path)); R_SUCCEED(); } Result SetConcatenationFileAttribute(const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); AMS_FS_R_TRY(accessor->QueryEntry(nullptr, 0, nullptr, 0, fsa::QueryId::SetConcatenationFileAttribute, sub_path)); R_SUCCEED(); } Result OpenFile(FileHandle *out, std::unique_ptr<fsa::IFile> &&file, int mode) { AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument()); auto file_accessor = std::make_unique<impl::FileAccessor>(std::move(file), nullptr, static_cast<OpenMode>(mode)); AMS_FS_R_UNLESS(file_accessor != nullptr, fs::ResultAllocationMemoryFailedNew()); out->handle = file_accessor.release(); R_SUCCEED(); } namespace { Result CommitImpl(const char *mount_name, const char *func_name) { impl::FileSystemAccessor *accessor{}; AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::Find(std::addressof(accessor), mount_name), AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name)); AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(accessor->Commit(), nullptr, accessor, func_name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name)); R_SUCCEED(); } } Result Commit(const char *mount_name) { R_RETURN(CommitImpl(mount_name, AMS_CURRENT_FUNCTION_NAME)); } Result CommitSaveData(const char *mount_name) { R_RETURN(CommitImpl(mount_name, AMS_CURRENT_FUNCTION_NAME)); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_filesystem_for_debug.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_filesystem_accessor.hpp" #include "fs_file_accessor.hpp" #include "fs_directory_accessor.hpp" #include "fs_mount_utils.hpp" #include "fs_user_mount_table.hpp" namespace ams::fs { namespace impl { Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path) { impl::FileSystemAccessor *accessor; const char *sub_path; R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); R_TRY(accessor->GetFileTimeStampRaw(out, sub_path)); R_SUCCEED(); } } Result GetFileTimeStamp(FileTimeStamp *out, const char *path) { fs::FileTimeStampRaw raw; AMS_FS_R_TRY(impl::GetFileTimeStampRawForDebug(std::addressof(raw), path)); static_assert(sizeof(raw) == sizeof(*out)); std::memcpy(out, std::addressof(raw), sizeof(raw)); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fs_user_mount_table.hpp" #include "fs_mount_table.hpp" #include "fs_filesystem_accessor.hpp" namespace ams::fs::impl { namespace { constinit MountTable g_mount_table; } Result Register(std::unique_ptr<FileSystemAccessor> &&fs) { R_RETURN(g_mount_table.Mount(std::move(fs))); } Result Find(FileSystemAccessor **out, const char *name) { R_RETURN(g_mount_table.Find(out, name)); } void Unregister(const char *name) { g_mount_table.Unmount(name); } } ================================================ FILE: libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { class FileSystemAccessor; Result Register(std::unique_ptr<FileSystemAccessor> &&fs); Result Find(FileSystemAccessor **out, const char *name); void Unregister(const char *name); } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_event_notifier_service_object_adapter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { class EventNotifierObjectAdapter final : public ::ams::fs::IEventNotifier, public ::ams::fs::impl::Newable { private: sf::SharedPointer<fssrv::sf::IEventNotifier> m_object; public: EventNotifierObjectAdapter(sf::SharedPointer<fssrv::sf::IEventNotifier> &&obj) : m_object(obj) { /* ... */ } virtual ~EventNotifierObjectAdapter() { /* ... */ } private: virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) override { /* Get the handle. */ sf::NativeHandle handle; AMS_FS_R_TRY(m_object->GetEventHandle(std::addressof(handle))); /* Create the system event. */ os::AttachReadableHandleToSystemEvent(out, handle.GetOsHandle(), handle.IsManaged(), clear_mode); handle.Detach(); R_SUCCEED(); } }; } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_file_system_proxy_service_object.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObject(); sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(); } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_file_system_service_object_adapter.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { class FileServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFile { NON_COPYABLE(FileServiceObjectAdapter); NON_MOVEABLE(FileServiceObjectAdapter); private: sf::SharedPointer<fssrv::sf::IFile> m_x; public: explicit FileServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IFile> &&o) : m_x(o) { /* ... */} virtual ~FileServiceObjectAdapter() { /* ... */ } public: virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final { s64 read_size = 0; R_TRY(m_x->Read(std::addressof(read_size), offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size), option)); *out = static_cast<size_t>(read_size); R_SUCCEED(); } virtual Result DoGetSize(s64 *out) override final { R_RETURN(m_x->GetSize(out)); } virtual Result DoFlush() override final { R_RETURN(m_x->Flush()); } virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final { R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size), option)); } virtual Result DoSetSize(s64 size) override final { R_RETURN(m_x->SetSize(size)); } virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final { switch (op_id) { case OperationId::Invalidate: { fs::QueryRangeInfo dummy_range_info; R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast<s32>(op_id), offset, size)); } case OperationId::QueryRange: { R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize()); R_RETURN(m_x->OperateRange(reinterpret_cast<fs::QueryRangeInfo *>(dst), static_cast<s32>(op_id), offset, size)); } default: { R_RETURN(m_x->OperateRangeWithBuffer(sf::OutNonSecureBuffer(dst, dst_size), sf::InNonSecureBuffer(src, src_size), static_cast<s32>(op_id), offset, size)); } } } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { AMS_ABORT("Invalid GetDomainObjectId call"); } }; class DirectoryServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IDirectory { NON_COPYABLE(DirectoryServiceObjectAdapter); NON_MOVEABLE(DirectoryServiceObjectAdapter); private: sf::SharedPointer<fssrv::sf::IDirectory> m_x; public: explicit DirectoryServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IDirectory> &&o) : m_x(o) { /* ... */} virtual ~DirectoryServiceObjectAdapter() { /* ... */ } public: virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final { R_RETURN(m_x->Read(out_count, sf::OutBuffer(out_entries, max_entries * sizeof(*out_entries)))); } virtual Result DoGetEntryCount(s64 *out) override final { R_RETURN(m_x->GetEntryCount(out)); } public: virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final { AMS_ABORT("Invalid GetDomainObjectId call"); } }; class FileSystemServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFileSystem { NON_COPYABLE(FileSystemServiceObjectAdapter); NON_MOVEABLE(FileSystemServiceObjectAdapter); private: sf::SharedPointer<fssrv::sf::IFileSystem> m_x; public: explicit FileSystemServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IFileSystem> &&o) : m_x(o) { /* ... */} virtual ~FileSystemServiceObjectAdapter() { /* ... */ } sf::SharedPointer<fssrv::sf::IFileSystem> GetFileSystem() const { return m_x; } private: static Result GetPathForServiceObject(fssrv::sf::Path *out, const fs::Path &path) { const size_t len = util::Strlcpy<char>(out->str, path.GetString(), sizeof(out->str)); R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath()); R_SUCCEED(); } private: virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); /* Open the file. */ sf::SharedPointer<fssrv::sf::IFile> file; R_TRY(m_x->OpenFile(std::addressof(file), fsp_path, mode)); /* Create the output fsa file. */ out_file->reset(new FileServiceObjectAdapter(std::move(file))); R_UNLESS(out_file != nullptr, fs::ResultAllocationMemoryFailedNew()); R_SUCCEED(); } virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); /* Open the directory. */ sf::SharedPointer<fssrv::sf::IDirectory> dir; R_TRY(m_x->OpenDirectory(std::addressof(dir), fsp_path, mode)); /* Create the output fsa directory. */ out_dir->reset(new DirectoryServiceObjectAdapter(std::move(dir))); R_UNLESS(out_dir != nullptr, fs::ResultAllocationMemoryFailedNew()); R_SUCCEED(); } virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->GetEntryType(out, fsp_path)); } virtual Result DoCommit() override final { R_RETURN(m_x->Commit()); } virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->CreateFile(fsp_path, size, flags)); } virtual Result DoDeleteFile(const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->DeleteFile(fsp_path)); } virtual Result DoCreateDirectory(const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->CreateDirectory(fsp_path)); } virtual Result DoDeleteDirectory(const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->DeleteDirectory(fsp_path)); } virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->DeleteDirectoryRecursively(fsp_path)); } virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final { /* Convert the path. */ fssrv::sf::Path fsp_old_path; fssrv::sf::Path fsp_new_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path)); R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path)); R_RETURN(m_x->RenameFile(fsp_old_path, fsp_new_path)); } virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final { /* Convert the path. */ fssrv::sf::Path fsp_old_path; fssrv::sf::Path fsp_new_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path)); R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path)); R_RETURN(m_x->RenameDirectory(fsp_old_path, fsp_new_path)); } virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->CleanDirectoryRecursively(fsp_path)); } virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->GetFreeSpaceSize(out, fsp_path)); } virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->GetTotalSpaceSize(out, fsp_path)); } virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override final { /* Convert the path. */ fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->GetFileTimeStampRaw(out, fsp_path)); } virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override { fssrv::sf::Path fsp_path; R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path)); R_RETURN(m_x->QueryEntry(sf::OutNonSecureBuffer(dst, dst_size), sf::InNonSecureBuffer(src, src_size), static_cast<s32>(query), fsp_path)); } }; } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_hash_generator_factory_selector.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs::impl { namespace { constinit fssystem::ShaHashGeneratorFactorySelector g_sha_hash_generator_factory_selector; } fssystem::IHash256GeneratorFactorySelector *GetNcaHashGeneratorFactorySelector() { return std::addressof(g_sha_hash_generator_factory_selector); } fssystem::IHash256GeneratorFactorySelector *GetSaveDataHashGeneratorFactorySelector() { return std::addressof(g_sha_hash_generator_factory_selector); } } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_id_string_impl.os.generic.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <exosphere/pkg1.hpp> namespace ams::fs::impl { #define ADD_ENUM_CASE(v) case v: return #v template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) { static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_21_0_0); switch (id) { using enum pkg1::KeyGeneration; case KeyGeneration_1_0_0: return "1.0.0-2.3.0"; case KeyGeneration_3_0_0: return "3.0.0"; case KeyGeneration_3_0_1: return "3.0.1-3.0.2"; case KeyGeneration_4_0_0: return "4.0.0-4.1.0"; case KeyGeneration_5_0_0: return "5.0.0-5.1.0"; case KeyGeneration_6_0_0: return "6.0.0-6.1.0"; case KeyGeneration_6_2_0: return "6.2.0"; case KeyGeneration_7_0_0: return "7.0.0-8.0.1"; case KeyGeneration_8_1_0: return "8.1.0-8.1.1"; case KeyGeneration_9_0_0: return "9.0.0-9.0.1"; case KeyGeneration_9_1_0: return "9.1.0-12.0.3"; case KeyGeneration_12_1_0: return "12.1.0"; case KeyGeneration_13_0_0: return "13.0.0-13.2.1"; case KeyGeneration_14_0_0: return "14.0.0-14.1.2"; case KeyGeneration_15_0_0: return "15.0.0-15.0.1"; case KeyGeneration_16_0_0: return "16.0.0-16.0.3"; case KeyGeneration_17_0_0: return "17.0.0-17.0.1"; case KeyGeneration_18_0_0: return "18.0.0-18.1.0"; case KeyGeneration_19_0_0: return "19.0.0-19.0.1"; case KeyGeneration_20_0_0: return "20.0.0-20.5.0"; case KeyGeneration_21_0_0: return "21.0.0-"; default: return "Unknown"; } } } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_library.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "fs_library.hpp" #include "fs_file_system_service_object_adapter.hpp" #include "../../fssrv/impl/fssrv_allocator_for_service_framework.hpp" namespace ams::fs::impl { #if !defined(ATMOSPHERE_OS_HORIZON) namespace { constexpr size_t SystemHeapSize = 8_MB; alignas(os::MemoryPageSize) constinit u8 g_system_heap[SystemHeapSize]; ALWAYS_INLINE auto &GetSystemHeapAllocator() { AMS_FUNCTION_LOCAL_STATIC(mem::StandardAllocator, s_system_heap_allocator, g_system_heap, sizeof(g_system_heap)); return s_system_heap_allocator; } constinit util::optional<fssrv::MemoryResourceFromStandardAllocator> g_system_heap_memory_resource; void *AllocateForSystem(size_t size) { return g_system_heap_memory_resource->Allocate(size); } void DeallocateForSystem(void *p, size_t size) { return g_system_heap_memory_resource->Deallocate(p, size); } [[maybe_unused]] constexpr size_t BufferPoolSize = 6_MB; [[maybe_unused]] constexpr size_t DeviceBufferSize = 8_MB; [[maybe_unused]] constexpr size_t DeviceWorkBufferSize = os::MemoryPageSize; [[maybe_unused]] constexpr size_t BufferManagerHeapSize = 14_MB; constexpr size_t DeviceWorkBufferRequiredSize = 0x140; static_assert(util::IsAligned(BufferManagerHeapSize, os::MemoryBlockUnitSize)); //alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize]; alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize]; alignas(os::MemoryPageSize) u8 g_device_work_buffer[DeviceWorkBufferSize]; //alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize]; // //alignas(os::MemoryPageSize) u8 g_buffer_manager_work_buffer[64_KB]; /* TODO: Other work buffers. */ /* TODO: Implement pooled threads. */ // constexpr int PooledThreadCount = 12; // constexpr size_t PooledThreadStackSize = 32_KB; // fssystem::PooledThread g_pooled_threads[PooledThreadCount]; /* FileSystem creators. */ constinit util::optional<fssrv::fscreator::LocalFileSystemCreator> g_local_fs_creator; constinit util::optional<fssrv::fscreator::SubDirectoryFileSystemCreator> g_subdir_fs_creator; constinit fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {}; Result InitializeFileSystemLibraryImpl() { /* Set system allocator. */ fssystem::InitializeAllocator(::ams::fs::impl::Allocate, ::ams::fs::impl::Deallocate); fssystem::InitializeAllocatorForSystem(::ams::fs::impl::AllocateForSystem, ::ams::fs::impl::DeallocateForSystem); /* TODO: Many things. */ g_system_heap_memory_resource.emplace(std::addressof(GetSystemHeapAllocator())); fssystem::InitializeBufferPool(reinterpret_cast<char *>(g_device_buffer), DeviceBufferSize, reinterpret_cast<char *>(g_device_work_buffer), DeviceWorkBufferRequiredSize); /* Setup fscreators/interfaces. */ g_local_fs_creator.emplace(true); g_subdir_fs_creator.emplace(); g_fs_creator_interfaces.local_fs_creator = std::addressof(*g_local_fs_creator); g_fs_creator_interfaces.subdir_fs_creator = std::addressof(*g_subdir_fs_creator); /* Initialize fssrv. */ const fssrv::FileSystemProxyConfiguration config = { .m_fs_creator_interfaces = std::addressof(g_fs_creator_interfaces), .m_base_storage_service_impl = nullptr /* TODO */, .m_base_file_system_service_impl = nullptr /* TODO */, .m_nca_file_system_service_impl = nullptr /* TODO */, .m_save_data_file_system_service_impl = nullptr /* TODO */, .m_access_failure_management_service_impl = nullptr /* TODO */, .m_time_service_impl = nullptr /* TODO */, .m_status_report_service_impl = nullptr /* TODO */, .m_program_registry_service_impl = nullptr /* TODO */, .m_access_log_service_impl = nullptr /* TODO */, .m_debug_configuration_service_impl = nullptr /* TODO */, }; fssrv::InitializeForFileSystemProxy(config); R_SUCCEED(); } class FileSystemLibraryInitializer { public: FileSystemLibraryInitializer() { R_ABORT_UNLESS(InitializeFileSystemLibraryImpl()); } }; } #endif void InitializeFileSystemLibrary() { #if !defined(ATMOSPHERE_OS_HORIZON) AMS_FUNCTION_LOCAL_STATIC(FileSystemLibraryInitializer, s_library_initializer); AMS_UNUSED(s_library_initializer); #endif } } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_library.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { void InitializeFileSystemLibrary(); } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_remote_device_operator.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { #if defined(ATMOSPHERE_OS_HORIZON) class RemoteDeviceOperator { private: ::FsDeviceOperator m_operator; public: RemoteDeviceOperator(::FsDeviceOperator &o) : m_operator(o) { /* ... */ } virtual ~RemoteDeviceOperator() { fsDeviceOperatorClose(std::addressof(m_operator)); } public: Result IsSdCardInserted(ams::sf::Out<bool> out) { R_RETURN(fsDeviceOperatorIsSdCardInserted(std::addressof(m_operator), out.GetPointer())); } Result GetSdCardSpeedMode(ams::sf::Out<s64> out) { R_RETURN(fsDeviceOperatorGetSdCardSpeedMode(std::addressof(m_operator), out.GetPointer())); } Result GetSdCardCid(ams::sf::OutBuffer out, s64 size) { R_RETURN(fsDeviceOperatorGetSdCardCid(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size)); } Result GetSdCardUserAreaSize(ams::sf::Out<s64> out) { R_RETURN(fsDeviceOperatorGetSdCardUserAreaSize(std::addressof(m_operator), out.GetPointer())); } Result GetSdCardProtectedAreaSize(ams::sf::Out<s64> out) { R_RETURN(fsDeviceOperatorGetSdCardProtectedAreaSize(std::addressof(m_operator), out.GetPointer())); } Result GetAndClearSdCardErrorInfo(ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size) { static_assert(sizeof(::FsStorageErrorInfo) == sizeof(fs::StorageErrorInfo)); R_RETURN(fsDeviceOperatorGetAndClearSdCardErrorInfo(std::addressof(m_operator), reinterpret_cast<::FsStorageErrorInfo *>(out_sei.GetPointer()), out_size.GetPointer(), out_buf.GetPointer(), out_buf.GetSize(), size)); } Result GetMmcCid(ams::sf::OutBuffer out, s64 size) { R_RETURN(fsDeviceOperatorGetMmcCid(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size)); } Result GetMmcSpeedMode(ams::sf::Out<s64> out) { R_RETURN(fsDeviceOperatorGetMmcSpeedMode(std::addressof(m_operator), out.GetPointer())); } Result GetMmcPatrolCount(ams::sf::Out<u32> out) { R_RETURN(fsDeviceOperatorGetMmcPatrolCount(std::addressof(m_operator), out.GetPointer())); } Result GetAndClearMmcErrorInfo(ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size) { static_assert(sizeof(::FsStorageErrorInfo) == sizeof(fs::StorageErrorInfo)); R_RETURN(fsDeviceOperatorGetAndClearMmcErrorInfo(std::addressof(m_operator), reinterpret_cast<::FsStorageErrorInfo *>(out_sei.GetPointer()), out_size.GetPointer(), out_buf.GetPointer(), out_buf.GetSize(), size)); } Result GetMmcExtendedCsd(ams::sf::OutBuffer out, s64 size) { R_RETURN(fsDeviceOperatorGetMmcExtendedCsd(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size)); } Result IsGameCardInserted(ams::sf::Out<bool> out) { R_RETURN(fsDeviceOperatorIsGameCardInserted(std::addressof(m_operator), out.GetPointer())); } Result GetGameCardHandle(ams::sf::Out<u32> out) { static_assert(sizeof(::FsGameCardHandle) == sizeof(u32)); R_RETURN(fsDeviceOperatorGetGameCardHandle(std::addressof(m_operator), reinterpret_cast<::FsGameCardHandle *>(out.GetPointer()))); } Result GetGameCardIdSet(ams::sf::OutBuffer out, s64 size) { R_RETURN(fsDeviceOperatorGetGameCardIdSet(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size)); } Result GetGameCardErrorReportInfo(ams::sf::Out<fs::GameCardErrorReportInfo> out) { static_assert(sizeof(::FsGameCardErrorReportInfo) == sizeof(fs::GameCardErrorReportInfo)); R_RETURN(fsDeviceOperatorGetGameCardErrorReportInfo(std::addressof(m_operator), reinterpret_cast<::FsGameCardErrorReportInfo *>(out.GetPointer()))); } Result GetGameCardDeviceId(ams::sf::OutBuffer out, s64 size) { R_RETURN(fsDeviceOperatorGetGameCardDeviceId(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size)); } }; static_assert(fssrv::sf::IsIDeviceOperator<RemoteDeviceOperator>); #endif } ================================================ FILE: libraries/libstratosphere/source/fs/impl/fs_remote_event_notifier.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fs::impl { #if defined(ATMOSPHERE_OS_HORIZON) class RemoteEventNotifier { private: ::FsEventNotifier m_notifier; public: RemoteEventNotifier(::FsEventNotifier &n) : m_notifier(n) { /* ... */ } virtual ~RemoteEventNotifier() { fsEventNotifierClose(std::addressof(m_notifier)); } public: Result GetEventHandle(ams::sf::OutCopyHandle out) { ::Event e; R_TRY(fsEventNotifierGetEventHandle(std::addressof(m_notifier), std::addressof(e), false)); out.SetValue(e.revent, true); R_SUCCEED(); } }; static_assert(fssrv::sf::IsIEventNotifier<RemoteEventNotifier>); #endif } ================================================ FILE: libraries/libstratosphere/source/fs/tests/fs_path_formatter_tests.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1; consteval PathFlags DecodeFlags(const char *desc) { PathFlags flags{}; while (*desc) { switch (*(desc++)) { case 'B': flags.AllowBackslash(); break; case 'E': flags.AllowEmptyPath(); break; case 'M': flags.AllowMountName(); break; case 'R': flags.AllowRelativePath(); break; case 'W': flags.AllowWindowsPath(); break; case 'C': flags.AllowAllCharacters(); break; AMS_UNREACHABLE_DEFAULT_CASE(); } } return flags; } consteval size_t Strlen(const char *p) { size_t len = 0; while (p[len] != StringTraits::NullTerminator) { ++len; } return len; } //#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) template<u32 Expected, u32 Actual> struct Print { constexpr Print() { if (std::is_constant_evaluated()) { __builtin_unreachable(); } } }; template<u32 E = 0, u32 A = 0, size_t N = 0> consteval void PrintResultMismatchImpl(u32 e, u32 a) { if constexpr (N == 32) { Print<E, A>{}; } else { const bool is_e = (e & (1 << N)) != 0; const bool is_a = (a & (1 << N)) != 0; if (is_e) { if (is_a) { PrintResultMismatchImpl<E | (1 << N), A | (1 << N), N + 1>(e, a); } else { PrintResultMismatchImpl<E | (1 << N), A | (0 << N), N + 1>(e, a); } } else { if (is_a) { PrintResultMismatchImpl<E | (0 << N), A | (1 << N), N + 1>(e, a); } else { PrintResultMismatchImpl<E | (0 << N), A | (0 << N), N + 1>(e, a); } } } } consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) { PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription()); } template<size_t Index, char Expected, char Actual> struct PrintMismatchChar { constexpr PrintMismatchChar() { if (std::is_constant_evaluated()) { __builtin_unreachable(); } } }; template<size_t Ix, char Expected, size_t C = 0> consteval void PrintCharacterMismatch(char c) { if (c == static_cast<char>(C)) { PrintMismatchChar<Ix, Expected, static_cast<char>(C)>{}; return; } if constexpr (C < std::numeric_limits<unsigned char>::max()) { PrintCharacterMismatch<Ix, Expected, C + 1>(c); } } template<size_t Ix, char C = 0> consteval void PrintCharacterMismatch(char c, char c2) { if (c == static_cast<char>(C)) { PrintCharacterMismatch<Ix, static_cast<char>(C)>(c2); return; } if constexpr (C < std::numeric_limits<unsigned char>::max()) { PrintCharacterMismatch<Ix, C + 1>(c, c2); } } template<size_t Ix = 0> consteval void PrintCharacterMismatch(size_t ix, char c, char c2) { if (Ix == ix) { PrintCharacterMismatch<Ix>(c, c2); return; } if constexpr (Ix <= DefaultPathBufferSize) { PrintCharacterMismatch<Ix + 1>(ix, c, c2); } } #endif consteval bool TestNormalizedImpl(const char *path, const PathFlags &flags, size_t buffer_size, const char *normalized, Result expected_result) { /* Allocate a buffer to normalize into. */ char *buffer = new char[buffer_size]; ON_SCOPE_EXIT { delete[] buffer; }; buffer[buffer_size - 1] = '\xcc'; /* Perform normalization. */ const Result actual_result = PathFormatter::Normalize(buffer, buffer_size, path, Strlen(path) + 1, flags); /* Check that the expected result matches the actual. */ if (actual_result.GetValue() != expected_result.GetValue()) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); #endif return false; } /* Check that the expected string matches the actual. */ for (size_t i = 0; i < buffer_size; ++i) { if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) { if (buffer[i] != normalized[i]) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintCharacterMismatch(i, normalized[i], buffer[i]); #endif return false; } } if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) { break; } } return true; } struct NormalizeTestData { const char *path; const char *flag_desc; const char *normalized; Result result; size_t buffer_size = DefaultPathBufferSize; }; template<size_t N, size_t Ix = 0> consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (!TestNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.buffer_size, test.normalized, test.result)) { return false; } if constexpr (Ix < N) { return DoNormalizeTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestNormalizeEmptyPath() { constexpr NormalizeTestData Tests[] = { { "", "", "", fs::ResultInvalidPathFormat() }, { "", "E", "", ResultSuccess() }, { "/aa/bb/../cc", "E", "/aa/cc", ResultSuccess() }, }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeEmptyPath()); consteval bool TestNormalizeMountName() { constexpr NormalizeTestData Tests[] = { { "mount:/aa/bb", "", "", fs::ResultInvalidPathFormat() }, { "mount:/aa/bb", "W", "", fs::ResultInvalidPathFormat() }, { "mount:/aa/bb", "M", "mount:/aa/bb", ResultSuccess() }, { "mount:/aa/./bb", "M", "mount:/aa/bb", ResultSuccess() }, { "mount:\\aa\\bb", "M", "mount:", fs::ResultInvalidPathFormat() }, { "m:/aa/bb", "M", "", fs::ResultInvalidPathFormat() }, { "mo>unt:/aa/bb", "M", "", fs::ResultInvalidCharacter() }, { "moun?t:/aa/bb", "M", "", fs::ResultInvalidCharacter() }, { "mo&unt:/aa/bb", "M", "mo&unt:/aa/bb", ResultSuccess() }, { "/aa/./bb", "M", "/aa/bb", ResultSuccess() }, { "mount/aa/./bb", "M", "", fs::ResultInvalidPathFormat() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeMountName()); consteval bool TestNormalizeWindowsPath() { constexpr NormalizeTestData Tests[] = { { "c:/aa/bb", "", "", fs::ResultInvalidPathFormat() }, { "c:\\aa\\bb", "", "", fs::ResultInvalidCharacter() }, { "\\\\host\\share", "", "", fs::ResultInvalidCharacter() }, { "\\\\.\\c:\\", "", "", fs::ResultInvalidCharacter() }, { "\\\\.\\c:/aa/bb/.", "", "", fs::ResultInvalidCharacter() }, { "\\\\?\\c:\\", "", "", fs::ResultInvalidCharacter() }, { "mount:\\\\host\\share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() }, { "mount:\\\\host/share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() }, { "c:\\aa\\..\\..\\..\\bb", "W", "c:/bb", ResultSuccess() }, { "mount:/\\\\aa\\..\\bb", "MW", "mount:", fs::ResultInvalidPathFormat() }, { "mount:/c:\\aa\\..\\bb", "MW", "mount:c:/bb", ResultSuccess() }, { "mount:/aa/bb", "MW", "mount:/aa/bb", ResultSuccess() }, { "/mount:/aa/bb", "MW", "/", fs::ResultInvalidCharacter() }, { "/mount:/aa/bb", "W", "/", fs::ResultInvalidCharacter() }, { "a:aa/../bb", "MW", "a:aa/bb", ResultSuccess() }, { "a:aa\\..\\bb", "MW", "a:aa/bb", ResultSuccess() }, { "/a:aa\\..\\bb", "W", "/", fs::ResultInvalidCharacter() }, { "\\\\?\\c:\\.\\aa", "W", "\\\\?\\c:/aa", ResultSuccess() }, { "\\\\.\\c:\\.\\aa", "W", "\\\\.\\c:/aa", ResultSuccess() }, { "\\\\.\\mount:\\.\\aa", "W", "\\\\./", fs::ResultInvalidCharacter() }, { "\\\\./.\\aa", "W", "\\\\./aa", ResultSuccess() }, { "\\\\/aa", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\\\aa", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\", "W", "/", ResultSuccess() }, { "\\\\host\\share", "W", "\\\\host\\share/", ResultSuccess() }, { "\\\\host\\share\\path", "W", "\\\\host\\share/path", ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", "\\\\host\\share/path/aa/cc", ResultSuccess() }, { "\\\\host\\", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\ho$st\\share\\path", "W", "", fs::ResultInvalidCharacter() }, { "\\\\host:\\share\\path", "W", "", fs::ResultInvalidCharacter() }, { "\\\\..\\share\\path", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\host\\s:hare\\path", "W", "", fs::ResultInvalidCharacter() }, { "\\\\host\\.\\path", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\host\\..\\path", "W", "", fs::ResultInvalidPathFormat() }, { "\\\\host\\sha:re", "W", "", fs::ResultInvalidCharacter() }, { ".\\\\host\\share", "RW", "..\\\\host\\share/", ResultSuccess() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeWindowsPath()); consteval bool TestNormalizeRelativePath() { constexpr NormalizeTestData Tests[] = { { "./aa/bb", "", "", fs::ResultInvalidPathFormat() }, { "./aa/bb/../cc", "R", "./aa/cc", ResultSuccess() }, { ".\\aa/bb/../cc", "R", "..", fs::ResultInvalidCharacter() }, { ".", "R", ".", ResultSuccess() }, { "../aa/bb", "R", "", fs::ResultDirectoryUnobtainable() }, { "/aa/./bb", "R", "/aa/bb", ResultSuccess() }, { "mount:./aa/bb", "MR", "mount:./aa/bb", ResultSuccess() }, { "mount:./aa/./bb", "MR", "mount:./aa/bb", ResultSuccess() }, { "mount:./aa/bb", "M", "mount:", fs::ResultInvalidPathFormat() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeRelativePath()); consteval bool TestNormalizeBackslash() { constexpr NormalizeTestData Tests[] = { { "\\aa\\bb\\..\\cc", "", "", fs::ResultInvalidPathFormat() }, { "\\aa\\bb\\..\\cc", "B", "", fs::ResultInvalidPathFormat() }, { "/aa\\bb\\..\\cc", "", "", fs::ResultInvalidCharacter() }, { "/aa\\bb\\..\\cc", "B", "/cc", ResultSuccess() }, { "/aa\\bb\\cc", "", "", fs::ResultInvalidCharacter() }, { "/aa\\bb\\cc", "B", "/aa\\bb\\cc", ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\cc", "W", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\cc", "WB", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() }, { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", "", fs::ResultInvalidCharacter() }, { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", "/aa", ResultSuccess() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeBackslash()); consteval bool TestNormalizeAllowAllChars() { constexpr NormalizeTestData Tests[] = { { "/aa/b:b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b*b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b?b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b<b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b>b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b|b/cc", "", "/aa/", fs::ResultInvalidCharacter() }, { "/aa/b:b/cc", "C", "/aa/b:b/cc", ResultSuccess() }, { "/aa/b*b/cc", "C", "/aa/b*b/cc", ResultSuccess() }, { "/aa/b?b/cc", "C", "/aa/b?b/cc", ResultSuccess() }, { "/aa/b<b/cc", "C", "/aa/b<b/cc", ResultSuccess() }, { "/aa/b>b/cc", "C", "/aa/b>b/cc", ResultSuccess() }, { "/aa/b|b/cc", "C", "/aa/b|b/cc", ResultSuccess() }, { "/aa/b'b/cc", "", "/aa/b'b/cc", ResultSuccess() }, { "/aa/b\"b/cc", "", "/aa/b\"b/cc", ResultSuccess() }, { "/aa/b(b/cc", "", "/aa/b(b/cc", ResultSuccess() }, { "/aa/b)b/cc", "", "/aa/b)b/cc", ResultSuccess() }, { "/aa/b'b/cc", "C", "/aa/b'b/cc", ResultSuccess() }, { "/aa/b\"b/cc", "C", "/aa/b\"b/cc", ResultSuccess() }, { "/aa/b(b/cc", "C", "/aa/b(b/cc", ResultSuccess() }, { "/aa/b)b/cc", "C", "/aa/b)b/cc", ResultSuccess() }, { "mount:/aa/b<b/cc", "MC", "mount:/aa/b<b/cc", ResultSuccess() }, { "mo>unt:/aa/bb/cc", "MC", "", fs::ResultInvalidCharacter() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeAllowAllChars()); consteval bool TestNormalizeAll() { constexpr NormalizeTestData Tests[] = { { "mount:./aa/bb", "WRM", "mount:./aa/bb", ResultSuccess() }, { "mount:./aa/bb\\cc/dd", "WRM", "mount:./aa/bb/cc/dd", ResultSuccess() }, { "mount:./aa/bb\\cc/dd", "WRMB", "mount:./aa/bb/cc/dd", ResultSuccess() }, { "mount:./.c:/aa/bb", "RM", "mount:./", fs::ResultInvalidCharacter() }, { "mount:.c:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() }, { "mount:./cc:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() }, { "mount:./\\\\host\\share/aa/bb", "MW", "mount:", fs::ResultInvalidPathFormat() }, { "mount:./\\\\host\\share/aa/bb", "WRM", "mount:.\\\\host\\share/aa/bb", ResultSuccess() }, { "mount:.\\\\host\\share/aa/bb", "WRM", "mount:..\\\\host\\share/aa/bb", ResultSuccess() }, { "mount:..\\\\host\\share/aa/bb", "WRM", "mount:.", fs::ResultDirectoryUnobtainable() }, { ".\\\\host\\share/aa/bb", "WRM", "..\\\\host\\share/aa/bb", ResultSuccess() }, { "..\\\\host\\share/aa/bb", "WRM", ".", fs::ResultDirectoryUnobtainable() }, { "mount:\\\\host\\share/aa/bb", "MW", "mount:\\\\host\\share/aa/bb", ResultSuccess() }, { "mount:\\aa\\bb", "BM", "mount:", fs::ResultInvalidPathFormat() }, { "mount:/aa\\bb", "BM", "mount:/aa\\bb", ResultSuccess() }, { ".//aa/bb", "RW", "./aa/bb", ResultSuccess() }, { "./aa/bb", "R", "./aa/bb", ResultSuccess() }, { "./c:/aa/bb", "RW", "./", fs::ResultInvalidCharacter() }, { "mount:./aa/b:b\\cc/dd", "WRMBC", "mount:./aa/b:b/cc/dd", ResultSuccess() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeAll()); consteval bool TestNormalizeSmallBuffer() { constexpr NormalizeTestData Tests[] = { { "/aa/bb", "M", "", fs::ResultTooLongPath(), 1}, { "mount:/aa/bb", "MR", "", fs::ResultTooLongPath(), 6 }, { "mount:/aa/bb", "MR", "mount:", fs::ResultTooLongPath(), 7 }, { "aa/bb", "MR", "./", fs::ResultTooLongPath(), 3 }, { "\\\\host\\share", "W", "\\\\host\\share", fs::ResultTooLongPath(), 13 } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizeSmallBuffer()); consteval bool TestIsNormalizedImpl(const char *path, const PathFlags &flags, bool expected_normalized, size_t expected_size, Result expected_result) { /* Perform normalization checking. */ bool actual_normalized; size_t actual_size; const Result actual_result = PathFormatter::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, flags); /* Check that the expected result matches the actual. */ if (actual_result.GetValue() != expected_result.GetValue()) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); #endif return false; } /* Check that the expected output matches the actual. */ if (R_SUCCEEDED(expected_result)) { if (expected_normalized != actual_normalized) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatchImpl(static_cast<u32>(expected_normalized), static_cast<u32>(actual_normalized)); #endif return false; } if (expected_normalized) { if (expected_size != actual_size) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatchImpl(static_cast<u32>(expected_size), static_cast<u32>(actual_size)); #endif return false; } } } return true; } struct IsNormalizedTestData { const char *path; const char *flag_desc; bool normalized; size_t len; Result result; }; template<size_t N, size_t Ix = 0> consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (!TestIsNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.normalized, test.len, test.result)) { return false; } if constexpr (Ix < N) { return DoIsNormalizedTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestIsNormalizedEmptyPath() { constexpr IsNormalizedTestData Tests[] = { { "", "", false, 0, fs::ResultInvalidPathFormat() }, { "", "E", true, 0, ResultSuccess() }, { "/aa/bb/../cc", "E", false, 0, ResultSuccess() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedEmptyPath()); consteval bool TestIsNormalizedMountName() { constexpr IsNormalizedTestData Tests[] = { { "mount:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, { "mount:/aa/bb", "W", false, 0, fs::ResultInvalidPathFormat() }, { "mount:/aa/bb", "M", true, 12, ResultSuccess() }, { "mount:/aa/./bb", "M", false, 6, ResultSuccess() }, { "mount:\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, { "m:/aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() }, { "mo>unt:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() }, { "moun?t:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() }, { "mo&unt:/aa/bb", "M", true, 13, ResultSuccess() }, { "/aa/./bb", "M", false, 0, ResultSuccess() }, { "mount/aa/./bb", "M", false, 0, fs::ResultInvalidPathFormat() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedMountName()); consteval bool TestIsNormalizedWindowsPath() { constexpr IsNormalizedTestData Tests[] = { { "c:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, { "c:\\aa\\bb", "", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\host\\share", "", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\.\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\.\\c:/aa/bb/.", "", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\?\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() }, { "mount:\\\\host\\share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, { "mount:\\\\host/share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() }, { "c:\\aa\\..\\..\\..\\bb", "W", false, 0, ResultSuccess() }, { "mount:/\\\\aa\\..\\bb", "MW", false, 0, ResultSuccess() }, { "mount:/c:\\aa\\..\\bb", "MW", false, 0, ResultSuccess() }, { "mount:/aa/bb", "MW", true, 12, ResultSuccess() }, { "/mount:/aa/bb", "MW", false, 0, fs::ResultInvalidCharacter() }, { "/mount:/aa/bb", "W", false, 0, fs::ResultInvalidCharacter() }, { "a:aa/../bb", "MW", false, 8, ResultSuccess() }, { "a:aa\\..\\bb", "MW", false, 0, ResultSuccess() }, { "/a:aa\\..\\bb", "W", false, 0, ResultSuccess() }, { "\\\\?\\c:\\.\\aa", "W", false, 0, ResultSuccess() }, { "\\\\.\\c:\\.\\aa", "W", false, 0, ResultSuccess() }, { "\\\\.\\mount:\\.\\aa", "W", false, 0, ResultSuccess() }, { "\\\\./.\\aa", "W", false, 0, ResultSuccess() }, { "\\\\/aa", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\\\aa", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\", "W", false, 0, ResultSuccess() }, { "\\\\host\\share", "W", false, 0, ResultSuccess() }, { "\\\\host\\share\\path", "W", false, 0, ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", false, 0, ResultSuccess() }, { "\\\\host\\", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\ho$st\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() }, { "\\\\host:\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() }, { "\\\\..\\share\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\host\\s:hare\\path", "W", false, 0, fs::ResultInvalidCharacter() }, { "\\\\host\\.\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\host\\..\\path", "W", false, 0, fs::ResultInvalidPathFormat() }, { "\\\\host\\sha:re", "W", false, 0, fs::ResultInvalidCharacter() }, { ".\\\\host\\share", "RW", false, 0, ResultSuccess() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedWindowsPath()); consteval bool TestIsNormalizedRelativePath() { constexpr IsNormalizedTestData Tests[] = { { "./aa/bb", "", false, 0, fs::ResultInvalidPathFormat() }, { "./aa/bb/../cc", "R", false, 1, ResultSuccess() }, { ".\\aa/bb/../cc", "R", false, 0, ResultSuccess() }, { ".", "R", true, 1, ResultSuccess() }, { "../aa/bb", "R", false, 0, fs::ResultDirectoryUnobtainable() }, { "/aa/./bb", "R", false, 0, ResultSuccess() }, { "mount:./aa/bb", "MR", true, 13, ResultSuccess() }, { "mount:./aa/./bb", "MR", false, 7, ResultSuccess() }, { "mount:./aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedRelativePath()); consteval bool TestIsNormalizedBackslash() { constexpr IsNormalizedTestData Tests[] = { { "\\aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidPathFormat() }, { "\\aa\\bb\\..\\cc", "B", false, 0, fs::ResultInvalidPathFormat() }, { "/aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa\\bb\\..\\cc", "B", false, 0, ResultSuccess() }, { "/aa\\bb\\cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa\\bb\\cc", "B", true, 9, ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\cc", "W", false, 0, ResultSuccess() }, { "\\\\host\\share\\path\\aa\\bb\\cc", "WB", false, 0, ResultSuccess() }, { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", false, 0, ResultSuccess() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedBackslash()); consteval bool TestIsNormalizedAllowAllCharacters() { constexpr IsNormalizedTestData Tests[] = { { "/aa/b:b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b*b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b?b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b<b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b>b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b|b/cc", "", false, 0, fs::ResultInvalidCharacter() }, { "/aa/b:b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b*b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b?b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b<b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b>b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b|b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b'b/cc", "", true, 10, ResultSuccess() }, { "/aa/b\"b/cc", "", true, 10, ResultSuccess() }, { "/aa/b(b/cc", "", true, 10, ResultSuccess() }, { "/aa/b)b/cc", "", true, 10, ResultSuccess() }, { "/aa/b'b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b\"b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b(b/cc", "C", true, 10, ResultSuccess() }, { "/aa/b)b/cc", "C", true, 10, ResultSuccess() }, { "mount:/aa/b<b/cc", "MC", true, 16, ResultSuccess() }, { "mo>unt:/aa/bb/cc", "MC", false, 0, fs::ResultInvalidCharacter() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedAllowAllCharacters()); consteval bool TestIsNormalizedAll() { constexpr IsNormalizedTestData Tests[] = { { "mount:./aa/bb", "WRM", true, 13, ResultSuccess() }, { "mount:./aa/bb\\cc/dd", "WRM", false, 0, ResultSuccess() }, { "mount:./aa/bb\\cc/dd", "WRMB", true, 19, ResultSuccess() }, { "mount:./.c:/aa/bb", "RM", false, 0, fs::ResultInvalidCharacter() }, { "mount:.c:/aa/bb", "WRM", false, 0, ResultSuccess() }, { "mount:./cc:/aa/bb", "WRM", false, 0, fs::ResultInvalidCharacter() }, { "mount:./\\\\host\\share/aa/bb", "MW", false, 0, fs::ResultInvalidPathFormat() }, { "mount:./\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, { "mount:.\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, { "mount:..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, { ".\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, { "..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() }, { "mount:\\\\host\\share/aa/bb", "MW", true, 24, ResultSuccess() }, { "mount:\\aa\\bb", "BM", false, 0, fs::ResultInvalidPathFormat() }, { "mount:/aa\\bb", "BM", true, 12, ResultSuccess() }, { ".//aa/bb", "RW", false, 1, ResultSuccess() }, { "./aa/bb", "R", true, 7, ResultSuccess() }, { "./c:/aa/bb", "RW", false, 0, fs::ResultInvalidCharacter() }, { "mount:./aa/b:b\\cc/dd", "WRMBC", true, 20, ResultSuccess() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalizedAll()); } } ================================================ FILE: libraries/libstratosphere/source/fs/tests/fs_path_normalizer_tests.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1; //#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) template<u32 Expected, u32 Actual> struct Print { constexpr Print() { if (std::is_constant_evaluated()) { __builtin_unreachable(); } } }; template<u32 E = 0, u32 A = 0, size_t N = 0> consteval void PrintResultMismatchImpl(u32 e, u32 a) { if constexpr (N == 32) { Print<E, A>{}; } else { const bool is_e = (e & (1 << N)) != 0; const bool is_a = (a & (1 << N)) != 0; if (is_e) { if (is_a) { PrintResultMismatchImpl<E | (1 << N), A | (1 << N), N + 1>(e, a); } else { PrintResultMismatchImpl<E | (1 << N), A | (0 << N), N + 1>(e, a); } } else { if (is_a) { PrintResultMismatchImpl<E | (0 << N), A | (1 << N), N + 1>(e, a); } else { PrintResultMismatchImpl<E | (0 << N), A | (0 << N), N + 1>(e, a); } } } } consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) { PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription()); } template<size_t Index, char Expected, char Actual> struct PrintMismatchChar { constexpr PrintMismatchChar() { if (std::is_constant_evaluated()) { __builtin_unreachable(); } } }; template<size_t Ix, char Expected, size_t C = 0> consteval void PrintCharacterMismatch(char c) { if (c == static_cast<char>(C)) { PrintMismatchChar<Ix, Expected, static_cast<char>(C)>{}; return; } if constexpr (C < std::numeric_limits<unsigned char>::max()) { PrintCharacterMismatch<Ix, Expected, C + 1>(c); } } template<size_t Ix, char C = 0> consteval void PrintCharacterMismatch(char c, char c2) { if (c == static_cast<char>(C)) { PrintCharacterMismatch<Ix, static_cast<char>(C)>(c2); return; } if constexpr (C < std::numeric_limits<unsigned char>::max()) { PrintCharacterMismatch<Ix, C + 1>(c, c2); } } template<size_t Ix = 0> consteval void PrintCharacterMismatch(size_t ix, char c, char c2) { if (Ix == ix) { PrintCharacterMismatch<Ix>(c, c2); return; } if constexpr (Ix <= DefaultPathBufferSize) { PrintCharacterMismatch<Ix + 1>(ix, c, c2); } } #endif consteval bool TestNormalizeImpl(const char *path, size_t buffer_size, const char *normalized, bool windows_path, bool drive_relative, bool all_chars, size_t expected_length, Result expected_result) { /* Allocate a buffer to normalize into. */ char *buffer = new char[buffer_size]; ON_SCOPE_EXIT { delete[] buffer; }; buffer[buffer_size - 1] = '\xcc'; /* Perform normalization. */ size_t actual_length; const Result actual_result = PathNormalizer::Normalize(buffer, std::addressof(actual_length), path, buffer_size, windows_path, drive_relative, all_chars); /* Check that the expected result matches the actual. */ if (actual_result.GetValue() != expected_result.GetValue()) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); #endif return false; } /* Check that the expected string matches the actual. */ for (size_t i = 0; i < buffer_size; ++i) { if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) { if (buffer[i] != normalized[i]) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintCharacterMismatch(i, normalized[i], buffer[i]); #endif return false; } } if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) { break; } } /* Check that the expected length matches the actual. */ if (R_SUCCEEDED(expected_result) || fs::ResultTooLongPath::Includes(expected_result)) { if (expected_length != actual_length) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatchImpl(static_cast<u32>(expected_length), static_cast<u32>(actual_length)); #endif return false; } } return true; } struct NormalizeTestData { const char *path; bool windows; bool rel; bool allow_all; const char *normalized; size_t len; Result result; }; template<size_t N, size_t Ix = 0> consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (!TestNormalizeImpl(test.path, DefaultPathBufferSize, test.normalized, test.windows, test.rel, test.allow_all, test.len, test.result)) { return false; } if constexpr (Ix < N) { return DoNormalizeTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestNormalized() { constexpr NormalizeTestData Tests[] = { { "/aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() }, { "aa/bb/c/", false, false, false, "", 0, fs::ResultInvalidPathFormat() }, { "aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() }, { "mount:a/b", false, true, false, "/", 0, fs::ResultInvalidCharacter() }, { "mo|unt:a/b", false, true, true, "/mo|unt:a/b", 11, ResultSuccess() }, { "/aa/bb/../..", true, false, false, "/", 1, ResultSuccess() }, { "/aa/bb/../../..", true, false, false, "/", 1, ResultSuccess() }, { "/aa/bb/../../..", false, false, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() }, { "aa/bb/../../..", true, true, false, "/", 1, ResultSuccess() }, { "aa/bb/../../..", false, true, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() }, { "mount:a/b", false, true, true, "/mount:a/b", 10, ResultSuccess() }, { "/a|/bb/cc", false, false, true, "/a|/bb/cc", 9, ResultSuccess() }, { "/>a/bb/cc", false, false, true, "/>a/bb/cc", 9, ResultSuccess() }, { "/aa/.</cc", false, false, true, "/aa/.</cc", 9, ResultSuccess() }, { "/aa/..</cc", false, false, true, "/aa/..</cc", 10, ResultSuccess() }, { "", false, false, false, "", 0, fs::ResultInvalidPathFormat() }, { "/", false, false, false, "/", 1, ResultSuccess() }, { "/.", false, false, false, "/", 1, ResultSuccess() }, { "/./", false, false, false, "/", 1, ResultSuccess() }, { "/..", false, false, false, "/", 0, fs::ResultDirectoryUnobtainable() }, { "//.", false, false, false, "/", 1, ResultSuccess() }, { "/ ..", false, false, false, "/ ..", 4, ResultSuccess() }, { "/.. /", false, false, false, "/.. ", 4, ResultSuccess() }, { "/. /.", false, false, false, "/. ", 3, ResultSuccess() }, { "/aa/bb/cc/dd/./.././../..", false, false, false, "/aa", 3, ResultSuccess() }, { "/aa/bb/cc/dd/./.././../../..", false, false, false, "/", 1, ResultSuccess() }, { "/./aa/./bb/./cc/./dd/.", false, false, false, "/aa/bb/cc/dd", 12, ResultSuccess() }, { "/aa\\bb/cc", false, false, false, "/aa\\bb/cc", 9, ResultSuccess() }, { "/aa\\bb/cc", false, false, false, "/aa\\bb/cc", 9, ResultSuccess() }, { "/a|/bb/cc", false, false, false, "/", 0, fs::ResultInvalidCharacter() }, { "/>a/bb/cc", false, false, false, "/", 0, fs::ResultInvalidCharacter() }, { "/aa/.</cc", false, false, false, "/aa/", 0, fs::ResultInvalidCharacter() }, { "/aa/..</cc", false, false, false, "/aa/", 0, fs::ResultInvalidCharacter() }, { "\\\\aa/bb/cc", false, false, false, "", 0, fs::ResultInvalidPathFormat() }, { "\\\\aa\\bb\\cc", false, false, false, "", 0, fs::ResultInvalidPathFormat() }, { "/aa/bb/..\\cc", false, false, false, "/aa/cc", 6, ResultSuccess() }, { "/aa/bb\\..\\cc", false, false, false, "/aa/cc", 6, ResultSuccess() }, { "/aa/bb\\..", false, false, false, "/aa", 3, ResultSuccess() }, { "/aa\\bb/../cc", false, false, false, "/cc", 3, ResultSuccess() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalized()); struct NormalizeTestDataSmallBuffer { const char *path; size_t buffer_size; const char *normalized; size_t len; Result result; }; template<size_t N, size_t Ix = 0> consteval bool DoNormalizeTests(const NormalizeTestDataSmallBuffer (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (!TestNormalizeImpl(test.path, test.buffer_size, test.normalized, false, false, false, test.len, test.result)) { return false; } if constexpr (Ix < N) { return DoNormalizeTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestNormalizedSmallBuffer() { constexpr NormalizeTestDataSmallBuffer Tests[] = { { "/aa/bb/cc/", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, { "/aa/bb/cc/", 8, "/aa/bb/", 7, fs::ResultTooLongPath() }, { "/aa/bb/cc/", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, { "/aa/bb/cc/", 10, "/aa/bb/cc", 9, ResultSuccess() }, { "/aa/bb/cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, { "/aa/bb/cc", 10, "/aa/bb/cc", 9, ResultSuccess() }, { "/./aa/./bb/./cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, { "/./aa/./bb/./cc", 10, "/aa/bb/cc", 9, ResultSuccess() }, { "/aa/bb/cc/../../..", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() }, { "/aa/bb/cc/../../..", 10, "/aa/bb/cc", 9, fs::ResultTooLongPath() }, { "/aa/bb/.", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, { "/aa/bb/./", 7, "/aa/bb", 6, fs::ResultTooLongPath() }, { "/aa/bb/..", 8, "/aa", 3, ResultSuccess() }, { "/aa/bb", 1, "", 0, fs::ResultTooLongPath() }, { "/aa/bb", 2, "/", 1, fs::ResultTooLongPath() }, { "/aa/bb", 3, "/a", 2, fs::ResultTooLongPath() }, { "aa/bb", 1, "", 0, fs::ResultInvalidPathFormat() } }; return DoNormalizeTests(Tests); } static_assert(TestNormalizedSmallBuffer()); consteval bool TestIsNormalizedImpl(const char *path, bool allow_all, bool expected_normalized, size_t expected_size, Result expected_result) { /* Perform normalization checking. */ bool actual_normalized; size_t actual_size = 0; const Result actual_result = PathNormalizer::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, allow_all); /* Check that the expected result matches the actual. */ if (actual_result.GetValue() != expected_result.GetValue()) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue()); #endif return false; } if (expected_size != actual_size) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatchImpl(static_cast<u32>(expected_size), static_cast<u32>(actual_size)); #endif return false; } /* Check that the expected output matches the actual. */ if (R_SUCCEEDED(expected_result)) { if (expected_normalized != actual_normalized) { #if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING) PrintResultMismatchImpl(static_cast<u32>(expected_normalized), static_cast<u32>(actual_normalized)); #endif return false; } } return true; } struct IsNormalizedTestData { const char *path; bool allow_all; bool normalized; size_t len; Result result; }; template<size_t N, size_t Ix = 0> consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (!TestIsNormalizedImpl(test.path, test.allow_all, test.normalized, test.len, test.result)) { return false; } if constexpr (Ix < N) { return DoIsNormalizedTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestIsNormalized() { constexpr IsNormalizedTestData Tests[] = { { "/aa/bb/c/", false, false, 9, ResultSuccess() }, { "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() }, { "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() }, { "mount:a/b", false, false, 0, fs::ResultInvalidPathFormat() }, { "mo|unt:a/b", true, false, 0, fs::ResultInvalidPathFormat() }, { "/aa/bb/../..", false, false, 0, ResultSuccess() }, { "/aa/bb/../../..", false, false, 0, ResultSuccess() }, { "/aa/bb/../../..", false, false, 0, ResultSuccess() }, { "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() }, { "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() }, { "mount:a/b", true, false, 0, fs::ResultInvalidPathFormat() }, { "/a|/bb/cc", true, true, 9, ResultSuccess() }, { "/>a/bb/cc", true, true, 9, ResultSuccess() }, { "/aa/.</cc", true, true, 9, ResultSuccess() }, { "/aa/..</cc", true, true, 10, ResultSuccess() }, { "", false, false, 0, fs::ResultInvalidPathFormat() }, { "/", false, true, 1, ResultSuccess() }, { "/.", false, false, 2, ResultSuccess() }, { "/./", false, false, 0, ResultSuccess() }, { "/..", false, false, 3, ResultSuccess() }, { "//.", false, false, 0, ResultSuccess() }, { "/ ..", false, true, 4, ResultSuccess() }, { "/.. /", false, false, 5, ResultSuccess() }, { "/. /.", false, false, 5, ResultSuccess() }, { "/aa/bb/cc/dd/./.././../..", false, false, 0, ResultSuccess() }, { "/aa/bb/cc/dd/./.././../../..", false, false, 0, ResultSuccess() }, { "/./aa/./bb/./cc/./dd/.", false, false, 0, ResultSuccess() }, { "/aa\\bb/cc", false, true, 9, ResultSuccess() }, { "/aa\\bb/cc", false, true, 9, ResultSuccess() }, { "/a|/bb/cc", false, false, 0, fs::ResultInvalidCharacter() }, { "/>a/bb/cc", false, false, 0, fs::ResultInvalidCharacter() }, { "/aa/.</cc", false, false, 0, fs::ResultInvalidCharacter() }, { "/aa/..</cc", false, false, 0, fs::ResultInvalidCharacter() }, { "\\\\aa/bb/cc", false, false, 0, fs::ResultInvalidPathFormat() }, { "\\\\aa\\bb\\cc", false, false, 0, fs::ResultInvalidPathFormat() }, { "/aa/bb/..\\cc", false, true, 12, ResultSuccess() }, { "/aa/bb\\..\\cc", false, true, 12, ResultSuccess() }, { "/aa/bb\\..", false, true, 9, ResultSuccess() }, { "/aa\\bb/../cc", false, false, 0, ResultSuccess() } }; return DoIsNormalizedTests(Tests); } static_assert(TestIsNormalized()); } } ================================================ FILE: libraries/libstratosphere/source/fs/tests/fs_path_utility_tests.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fs { namespace { struct IsSubPathTestData { const char *lhs; const char *rhs; bool is_sub_path; }; template<size_t N, size_t Ix = 0> consteval bool DoIsSubPathTests(const IsSubPathTestData (&tests)[N]) { if constexpr (Ix >= N) { return true; } const auto &test = tests[Ix]; if (::ams::fs::IsSubPath(test.lhs, test.rhs) != test.is_sub_path) { return false; } if constexpr (Ix < N) { return DoIsSubPathTests<N, Ix + 1>(tests); } else { AMS_ASSUME(false); } } consteval bool TestIsSubPath() { constexpr IsSubPathTestData Tests[] = { { "//a/b", "/a", false }, { "/a", "//a/b", false }, { "//a/b", "\\\\a", false }, { "//a/b", "//a", true }, { "/", "/a", true }, { "/a", "/", true }, { "/", "/", false }, { "", "", false }, { "/", "", true }, { "/", "mount:/a", false }, { "mount:/", "mount:/", false }, { "mount:/a/b", "mount:/a/b", false }, { "mount:/a/b", "mount:/a/b/c", true }, { "/a/b", "/a/b/c", true }, { "/a/b/c", "/a/b", true }, { "/a/b", "/a/b", false }, { "/a/b", "/a/b\\c", false } }; return DoIsSubPathTests(Tests); } static_assert(TestIsSubPath()); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fscreator/fssrv_local_file_system_creator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv::fscreator { Result LocalFileSystemCreator::Create(std::shared_ptr<fs::fsa::IFileSystem> *out, const fs::Path &path, bool case_sensitive, bool ensure_root, Result on_path_not_found) { /* Check that we're configured for development. */ R_UNLESS(m_is_development, fs::ResultPermissionDeniedForCreateHostFileSystem()); /* Allocate a local filesystem. */ auto local_fs = fs::AllocateShared<fssystem::LocalFileSystem>(); R_UNLESS(local_fs != nullptr, fs::ResultAllocationMemoryFailedInLocalFileSystemCreatorA()); /* If we're supposed to make sure the root path exists, do so. */ if (ensure_root) { /* Sanity check that the path will be possible to create. */ AMS_ASSERT(!path.IsEmpty()); /* Initialize the local fs with an empty path. */ fs::Path empty_path; R_TRY(empty_path.InitializeAsEmpty()); R_TRY(local_fs->Initialize(empty_path, fssystem::PathCaseSensitiveMode_CaseInsensitive)); /* Ensure the directory exists. */ if (const Result ensure_result = fssystem::EnsureDirectory(local_fs.get(), path); R_FAILED(ensure_result)) { if (R_SUCCEEDED(on_path_not_found)) { R_THROW(ensure_result); } else { R_THROW(on_path_not_found); } } } /* Initialize the local filesystem. */ R_TRY_CATCH(local_fs->Initialize(path, case_sensitive ? fssystem::PathCaseSensitiveMode_CaseSensitive : fssystem::PathCaseSensitiveMode_CaseInsensitive)) { R_CATCH(fs::ResultPathNotFound) { if (R_SUCCEEDED(on_path_not_found)) { R_THROW(R_CURRENT_RESULT); } else { R_THROW(on_path_not_found); } } } R_END_TRY_CATCH; /* Set the output fs. */ *out = std::move(local_fs); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fscreator/fssrv_partition_file_system_creator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv::fscreator { Result PartitionFileSystemCreator::Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) { /* Allocate a filesystem. */ std::shared_ptr fs = fssystem::AllocateShared<fssystem::PartitionFileSystem>(); R_UNLESS(fs != nullptr, fs::ResultAllocationMemoryFailedInPartitionFileSystemCreatorA()); /* Initialize the filesystem. */ R_TRY(fs->Initialize(std::move(storage))); /* Set the output. */ *out = std::move(fs); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fscreator/fssrv_rom_file_system_creator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv::fscreator { namespace { class RomFileSystemWithBuffer : public ::ams::fssystem::RomFsFileSystem { private: void *m_meta_cache_buffer; size_t m_meta_cache_buffer_size; MemoryResource *m_allocator; public: explicit RomFileSystemWithBuffer(MemoryResource *mr) : m_meta_cache_buffer(nullptr), m_allocator(mr) { /* ... */ } ~RomFileSystemWithBuffer() { if (m_meta_cache_buffer != nullptr) { m_allocator->Deallocate(m_meta_cache_buffer, m_meta_cache_buffer_size); } } Result Initialize(std::shared_ptr<fs::IStorage> storage) { /* Check if the buffer is eligible for cache. */ size_t buffer_size = 0; if (R_FAILED(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(buffer_size), storage.get())) || buffer_size == 0 || buffer_size >= 128_KB) { R_RETURN(RomFsFileSystem::Initialize(std::move(storage), nullptr, 0, false)); } /* Allocate a buffer. */ m_meta_cache_buffer = m_allocator->Allocate(buffer_size); if (m_meta_cache_buffer == nullptr) { R_RETURN(RomFsFileSystem::Initialize(std::move(storage), nullptr, 0, false)); } /* Initialize with cache buffer. */ m_meta_cache_buffer_size = buffer_size; R_RETURN(RomFsFileSystem::Initialize(std::move(storage), m_meta_cache_buffer, m_meta_cache_buffer_size, true)); } }; } Result RomFileSystemCreator::Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::IStorage> storage) { /* Allocate a filesystem. */ std::shared_ptr fs = fssystem::AllocateShared<RomFileSystemWithBuffer>(m_allocator); R_UNLESS(fs != nullptr, fs::ResultAllocationMemoryFailedInRomFileSystemCreatorA()); /* Initialize the filesystem. */ R_TRY(fs->Initialize(std::move(storage))); /* Set the output. */ *out = std::move(fs); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fscreator/fssrv_storage_on_nca_creator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv::fscreator { Result StorageOnNcaCreator::Create(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index) { /* Create a fs driver. */ fssystem::NcaFileSystemDriver nca_fs_driver(nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); /* Open the storage. */ std::shared_ptr<fs::IStorage> storage; std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter; R_TRY(nca_fs_driver.OpenStorage(std::addressof(storage), std::addressof(splitter), out_header_reader, index)); /* Set the out storage. */ *out = std::move(storage); *out_splitter = std::move(splitter); R_SUCCEED(); } Result StorageOnNcaCreator::CreateWithPatch(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index) { /* Create a fs driver. */ fssystem::NcaFileSystemDriver nca_fs_driver(original_nca_reader, current_nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); /* Open the storage. */ std::shared_ptr<fs::IStorage> storage; std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter; R_TRY(nca_fs_driver.OpenStorage(std::addressof(storage), std::addressof(splitter), out_header_reader, index)); /* Set the out storage. */ *out = std::move(storage); *out_splitter = std::move(splitter); R_SUCCEED(); } Result StorageOnNcaCreator::CreateNcaReader(std::shared_ptr<fssystem::NcaReader> *out, std::shared_ptr<fs::IStorage> storage) { /* Create a reader. */ std::shared_ptr reader = fssystem::AllocateShared<fssystem::NcaReader>(); R_UNLESS(reader != nullptr, fs::ResultAllocationMemoryFailedInStorageOnNcaCreatorB()); /* Initialize the reader. */ R_TRY(reader->Initialize(std::move(storage), m_nca_crypto_cfg, m_nca_compression_cfg, m_hash_generator_factory_selector)); /* Set the output. */ *out = std::move(reader); R_SUCCEED(); } #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) Result StorageOnNcaCreator::CreateWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index) { /* Create a fs driver. */ fssystem::NcaFileSystemDriver nca_fs_driver(nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); /* Open the storage. */ std::shared_ptr<fs::IStorage> storage; std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter; R_TRY(nca_fs_driver.OpenStorageWithContext(std::addressof(storage), std::addressof(splitter), out_header_reader, index, static_cast<fssystem::NcaFileSystemDriver::StorageContext *>(ctx))); /* Set the out storage. */ *out = std::move(storage); *out_splitter = std::move(splitter); R_SUCCEED(); } Result StorageOnNcaCreator::CreateWithPatchWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index) { /* Create a fs driver. */ fssystem::NcaFileSystemDriver nca_fs_driver(original_nca_reader, current_nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); /* Open the storage. */ std::shared_ptr<fs::IStorage> storage; std::shared_ptr<fssystem::IAsynchronousAccessSplitter> splitter; R_TRY(nca_fs_driver.OpenStorageWithContext(std::addressof(storage), std::addressof(splitter), out_header_reader, index, static_cast<fssystem::NcaFileSystemDriver::StorageContext *>(ctx))); /* Set the out storage. */ *out = std::move(storage); *out_splitter = std::move(splitter); R_SUCCEED(); } Result StorageOnNcaCreator::CreateByRawStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader) { /* Create a fs driver. */ fssystem::NcaFileSystemDriver nca_fs_driver(nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); /* Open the storage. */ auto *storage_ctx = static_cast<fssystem::NcaFileSystemDriver::StorageContext *>(ctx); R_TRY(nca_fs_driver.CreateStorageByRawStorage(out, header_reader, std::move(raw_storage), storage_ctx)); /* Update the splitter. */ if (storage_ctx->compressed_storage != nullptr) { *out_splitter = storage_ctx->compressed_storage; } R_SUCCEED(); } #endif } ================================================ FILE: libraries/libstratosphere/source/fssrv/fscreator/fssrv_subdirectory_file_system_creator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv::fscreator { Result SubDirectoryFileSystemCreator::Create(std::shared_ptr<fs::fsa::IFileSystem> *out, std::shared_ptr<fs::fsa::IFileSystem> base_fs, const fs::Path &path) { /* Verify that we can the directory on the base filesystem. */ { std::unique_ptr<fs::fsa::IDirectory> sub_dir; R_TRY(base_fs->OpenDirectory(std::addressof(sub_dir), path, fs::OpenDirectoryMode_Directory)); } /* Allocate a SubDirectoryFileSystem. */ auto sub_dir_fs = fs::AllocateShared<fssystem::SubDirectoryFileSystem>(std::move(base_fs)); R_UNLESS(sub_dir_fs != nullptr, fs::ResultAllocationMemoryFailedInSubDirectoryFileSystemCreatorA()); /* Initialize the new filesystem. */ R_TRY(sub_dir_fs->Initialize(path)); /* Return the new filesystem. */ *out = std::move(sub_dir_fs); R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_access_control.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv { namespace { constinit bool g_is_debug_flag_enabled = false; } bool IsDebugFlagEnabled() { return g_is_debug_flag_enabled; } void SetDebugFlagEnabled(bool en) { /* Set global debug flag. */ g_is_debug_flag_enabled = en; } namespace impl { namespace { constexpr u8 LatestFsAccessControlInfoVersion = 1; } AccessControl::AccessControl(const void *data, s64 data_size, const void *desc, s64 desc_size) : AccessControl(data, data_size, desc, desc_size, g_is_debug_flag_enabled ? AllFlagBitsMask : DebugFlagDisableMask) { /* ... */ } AccessControl::AccessControl(const void *fac_data, s64 data_size, const void *fac_desc, s64 desc_size, u64 flag_mask) { /* If either our data or descriptor is null, give no permissions. */ if (fac_data == nullptr || fac_desc == nullptr) { m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None)); return; } /* Check that data/desc are big enough. */ AMS_ABORT_UNLESS(data_size >= static_cast<s64>(sizeof(AccessControlDataHeader))); AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor))); /* Copy in the data/descriptor. */ AccessControlDataHeader data = {}; AccessControlDescriptor desc = {}; std::memcpy(std::addressof(data), fac_data, sizeof(data)); std::memcpy(std::addressof(desc), fac_desc, sizeof(desc)); /* If we don't know how to parse the descriptors, don't. */ if (data.version != desc.version || data.version < LatestFsAccessControlInfoVersion) { m_flag_bits.emplace(util::ToUnderlying(AccessControlBits::Bits::None)); return; } /* Restrict the descriptor's flag bits. */ desc.flag_bits &= flag_mask; /* Create our flag bits. */ m_flag_bits.emplace(data.flag_bits & desc.flag_bits); /* Further check sizes. */ AMS_ABORT_UNLESS(data_size >= data.content_owner_infos_offset + data.content_owner_infos_size); AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64))); /* Read out the content data owner infos. */ uintptr_t data_start = reinterpret_cast<uintptr_t>(fac_data); uintptr_t desc_start = reinterpret_cast<uintptr_t>(fac_desc); if (data.content_owner_infos_size > 0) { /* Get the count. */ const u32 num_content_owner_infos = util::LoadLittleEndian<u32>(reinterpret_cast<u32 *>(data_start + data.content_owner_infos_offset)); /* Validate the id range. */ uintptr_t id_start = data_start + data.content_owner_infos_offset + sizeof(u32); uintptr_t id_end = id_start + sizeof(u64) * num_content_owner_infos; AMS_ABORT_UNLESS(id_end == data_start + data.content_owner_infos_offset + data.content_owner_infos_size); for (u32 i = 0; i < num_content_owner_infos; ++i) { /* Read the id. */ const u64 id = util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(id_start + i * sizeof(u64))); /* Check that the descriptor allows it. */ bool allowed = false; if (desc.content_owner_id_count != 0) { for (u8 n = 0; n < desc.content_owner_id_count; ++n) { if (id == util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(desc_start + sizeof(AccessControlDescriptor) + n * sizeof(u64)))) { allowed = true; break; } } } else if ((desc.content_owner_id_min == 0 && desc.content_owner_id_max == 0) || (desc.content_owner_id_min <= id && id <= desc.content_owner_id_max)) { allowed = true; } /* If the id is allowed, create it. */ if (allowed) { if (auto *info = new ContentOwnerInfo(id); info != nullptr) { m_content_owner_infos.push_front(*info); } } } } /* Read out the save data owner infos. */ AMS_ABORT_UNLESS(data_size >= data.save_data_owner_infos_offset + data.save_data_owner_infos_size); AMS_ABORT_UNLESS(desc_size >= static_cast<s64>(sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + desc.save_data_owner_id_count * sizeof(u64))); if (data.save_data_owner_infos_size > 0) { /* Get the count. */ const u32 num_save_data_owner_infos = util::LoadLittleEndian<u32>(reinterpret_cast<u32 *>(data_start + data.save_data_owner_infos_offset)); /* Get accessibility region.*/ uintptr_t accessibility_start = data_start + data.save_data_owner_infos_offset + sizeof(u32); /* Validate the id range. */ uintptr_t id_start = accessibility_start + util::AlignUp(num_save_data_owner_infos * sizeof(Accessibility), alignof(u32)); uintptr_t id_end = id_start + sizeof(u64) * num_save_data_owner_infos; AMS_ABORT_UNLESS(id_end == data_start + data.save_data_owner_infos_offset + data.save_data_owner_infos_size); for (u32 i = 0; i < num_save_data_owner_infos; ++i) { /* Read the accessibility/id. */ static_assert(sizeof(Accessibility) == 1); const Accessibility accessibility = *reinterpret_cast<Accessibility *>(accessibility_start + i * sizeof(Accessibility)); const u64 id = util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(id_start + i * sizeof(u64))); /* Check that the descriptor allows it. */ bool allowed = false; if (desc.save_data_owner_id_count != 0) { for (u8 n = 0; n < desc.save_data_owner_id_count; ++n) { if (id == util::LoadLittleEndian<u64>(reinterpret_cast<u64 *>(desc_start + sizeof(AccessControlDescriptor) + desc.content_owner_id_count * sizeof(u64) + n * sizeof(u64)))) { allowed = true; break; } } } else if ((desc.save_data_owner_id_min == 0 && desc.save_data_owner_id_max == 0) || (desc.save_data_owner_id_min <= id && id <= desc.save_data_owner_id_max)) { allowed = true; } /* If the id is allowed, create it. */ if (allowed) { if (auto *info = new SaveDataOwnerInfo(id, accessibility); info != nullptr) { m_save_data_owner_infos.push_front(*info); } } } } } AccessControl::~AccessControl() { /* Delete all content owner infos. */ while (!m_content_owner_infos.empty()) { auto *info = std::addressof(*m_content_owner_infos.rbegin()); m_content_owner_infos.erase(m_content_owner_infos.iterator_to(*info)); delete info; } /* Delete all save data owner infos. */ while (!m_save_data_owner_infos.empty()) { auto *info = std::addressof(*m_save_data_owner_infos.rbegin()); m_save_data_owner_infos.erase(m_save_data_owner_infos.iterator_to(*info)); delete info; } } bool AccessControl::HasContentOwnerId(u64 owner_id) const { /* Check if we have a matching id. */ for (const auto &info : m_content_owner_infos) { if (info.GetId() == owner_id) { return true; } } return false; } Accessibility AccessControl::GetAccessibilitySaveDataOwnedBy(u64 owner_id) const { /* Find a matching save data owner. */ for (const auto &info : m_save_data_owner_infos) { if (info.GetId() == owner_id) { return info.GetAccessibility(); } } /* Default to no accessibility. */ return Accessibility::MakeAccessibility(false, false); } void AccessControl::ListContentOwnerId(s32 *out_count, u64 *out_owner_ids, s32 offset, s32 count) const { /* If we have nothing to read, just give the count. */ if (count == 0) { *out_count = m_content_owner_infos.size(); return; } /* Read out the ids. */ s32 read_offset = 0; s32 read_count = 0; if (out_owner_ids != nullptr) { auto *cur_out = out_owner_ids; for (const auto &info : m_content_owner_infos) { /* Skip until we get to the desired offset. */ if (read_offset < offset) { ++read_offset; continue; } /* Set the output value. */ *cur_out = info.GetId(); ++cur_out; ++read_count; /* If we've read as many as we can, finish. */ if (read_count == count) { break; } } } /* Set the out value. */ *out_count = read_count; } void AccessControl::ListSaveDataOwnedId(s32 *out_count, ncm::ApplicationId *out_owner_ids, s32 offset, s32 count) const { /* If we have nothing to read, just give the count. */ if (count == 0) { *out_count = m_save_data_owner_infos.size(); return; } /* Read out the ids. */ s32 read_offset = 0; s32 read_count = 0; if (out_owner_ids != nullptr) { auto *cur_out = out_owner_ids; for (const auto &info : m_save_data_owner_infos) { /* Skip until we get to the desired offset. */ if (read_offset < offset) { ++read_offset; continue; } /* Set the output value. */ cur_out->value = info.GetId(); ++cur_out; ++read_count; /* If we've read as many as we can, finish. */ if (read_count == count) { break; } } } /* Set the out value. */ *out_count = read_count; } Accessibility AccessControl::GetAccessibilityFor(AccessibilityType type) const { switch (type) { using enum AccessibilityType; case MountLogo: return Accessibility::MakeAccessibility(m_flag_bits->CanMountLogoRead(), false); case MountContentMeta: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentMetaRead(), false); case MountContentControl: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentControlRead(), false); case MountContentManual: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentManualRead(), false); case MountContentData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentDataRead(), false); case MountApplicationPackage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountApplicationPackageRead(), false); case MountSaveDataStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSaveDataStorageRead(), m_flag_bits->CanMountSaveDataStorageWrite()); case MountContentStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentStorageRead(), m_flag_bits->CanMountContentStorageWrite()); case MountImageAndVideoStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountImageAndVideoStorageRead(), m_flag_bits->CanMountImageAndVideoStorageWrite()); case MountCloudBackupWorkStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCloudBackupWorkStorageRead(), m_flag_bits->CanMountCloudBackupWorkStorageWrite()); case MountCustomStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanMountCustomStorage0Read(), m_flag_bits->CanMountCustomStorage0Write()); case MountBisCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisCalibrationFileRead(), m_flag_bits->CanMountBisCalibrationFileWrite()); case MountBisSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSafeModeRead(), m_flag_bits->CanMountBisSafeModeWrite()); case MountBisUser: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisUserRead(), m_flag_bits->CanMountBisUserWrite()); case MountBisSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemRead(), m_flag_bits->CanMountBisSystemWrite()); case MountBisSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperEncryptionRead(), m_flag_bits->CanMountBisSystemProperEncryptionWrite()); case MountBisSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemProperPartitionRead(), m_flag_bits->CanMountBisSystemProperPartitionWrite()); case MountSdCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSdCardRead(), m_flag_bits->CanMountSdCardWrite()); case MountGameCard: return Accessibility::MakeAccessibility(m_flag_bits->CanMountGameCardRead(), false); case MountDeviceSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountDeviceSaveDataRead(), m_flag_bits->CanMountDeviceSaveDataWrite()); case MountSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemSaveDataRead(), m_flag_bits->CanMountSystemSaveDataWrite()); case MountOthersSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSaveDataRead(), m_flag_bits->CanMountOthersSaveDataWrite()); case MountOthersSystemSaveData: return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSystemSaveDataRead(), m_flag_bits->CanMountOthersSystemSaveDataWrite()); case OpenBisPartitionBootPartition1Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition1RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition1RootWrite()); case OpenBisPartitionBootPartition2Root: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootPartition2RootRead(), m_flag_bits->CanOpenBisPartitionBootPartition2RootWrite()); case OpenBisPartitionUserDataRoot: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserDataRootRead(), m_flag_bits->CanOpenBisPartitionUserDataRootWrite()); case OpenBisPartitionBootConfigAndPackage2Part1: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Write()); case OpenBisPartitionBootConfigAndPackage2Part2: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Write()); case OpenBisPartitionBootConfigAndPackage2Part3: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Write()); case OpenBisPartitionBootConfigAndPackage2Part4: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Write()); case OpenBisPartitionBootConfigAndPackage2Part5: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Write()); case OpenBisPartitionBootConfigAndPackage2Part6: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Read(), m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Write()); case OpenBisPartitionCalibrationBinary: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationBinaryRead(), m_flag_bits->CanOpenBisPartitionCalibrationBinaryWrite()); case OpenBisPartitionCalibrationFile: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionCalibrationFileRead(), m_flag_bits->CanOpenBisPartitionCalibrationFileWrite()); case OpenBisPartitionSafeMode: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSafeModeRead(), m_flag_bits->CanOpenBisPartitionSafeModeWrite()); case OpenBisPartitionUser: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserRead(), m_flag_bits->CanOpenBisPartitionUserWrite()); case OpenBisPartitionSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemRead(), m_flag_bits->CanOpenBisPartitionSystemWrite()); case OpenBisPartitionSystemProperEncryption: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperEncryptionRead(), m_flag_bits->CanOpenBisPartitionSystemProperEncryptionWrite()); case OpenBisPartitionSystemProperPartition: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemProperPartitionRead(), m_flag_bits->CanOpenBisPartitionSystemProperPartitionWrite()); case OpenSdCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSdCardStorageRead(), m_flag_bits->CanOpenSdCardStorageWrite()); case OpenGameCardStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenGameCardStorageRead(), m_flag_bits->CanOpenGameCardStorageWrite()); case MountSystemDataPrivate: return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemDataPrivateRead(), false); case MountHost: return Accessibility::MakeAccessibility(m_flag_bits->CanMountHostRead(), m_flag_bits->CanMountHostWrite()); case MountRegisteredUpdatePartition: return Accessibility::MakeAccessibility(m_flag_bits->CanMountRegisteredUpdatePartitionRead() && g_is_debug_flag_enabled, false); case MountSaveDataInternalStorage: return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSaveDataInternalStorageRead(), m_flag_bits->CanOpenSaveDataInternalStorageWrite()); case MountTemporaryDirectory: return Accessibility::MakeAccessibility(m_flag_bits->CanMountTemporaryDirectoryRead(), m_flag_bits->CanMountTemporaryDirectoryWrite()); case MountAllBaseFileSystem: return Accessibility::MakeAccessibility(m_flag_bits->CanMountAllBaseFileSystemRead(), m_flag_bits->CanMountAllBaseFileSystemWrite()); case NotMount: return Accessibility::MakeAccessibility(false, false); AMS_UNREACHABLE_DEFAULT_CASE(); } } bool AccessControl::CanCall(OperationType type) const { switch (type) { using enum OperationType; case InvalidateBisCache: return m_flag_bits->CanInvalidateBisCache(); case EraseMmc: return m_flag_bits->CanEraseMmc(); case GetGameCardDeviceCertificate: return m_flag_bits->CanGetGameCardDeviceCertificate(); case GetGameCardIdSet: return m_flag_bits->CanGetGameCardIdSet(); case FinalizeGameCardDriver: return m_flag_bits->CanFinalizeGameCardDriver(); case GetGameCardAsicInfo: return m_flag_bits->CanGetGameCardAsicInfo(); case CreateSaveData: return m_flag_bits->CanCreateSaveData(); case DeleteSaveData: return m_flag_bits->CanDeleteSaveData(); case CreateSystemSaveData: return m_flag_bits->CanCreateSystemSaveData(); case CreateOthersSystemSaveData: return m_flag_bits->CanCreateOthersSystemSaveData(); case DeleteSystemSaveData: return m_flag_bits->CanDeleteSystemSaveData(); case OpenSaveDataInfoReader: return m_flag_bits->CanOpenSaveDataInfoReader(); case OpenSaveDataInfoReaderForSystem: return m_flag_bits->CanOpenSaveDataInfoReaderForSystem(); case OpenSaveDataInfoReaderForInternal: return m_flag_bits->CanOpenSaveDataInfoReaderForInternal(); case OpenSaveDataMetaFile: return m_flag_bits->CanOpenSaveDataMetaFile(); case SetCurrentPosixTime: return m_flag_bits->CanSetCurrentPosixTime(); case ReadSaveDataFileSystemExtraData: return m_flag_bits->CanReadSaveDataFileSystemExtraData(); case SetGlobalAccessLogMode: return m_flag_bits->CanSetGlobalAccessLogMode(); case SetSpeedEmulationMode: return m_flag_bits->CanSetSpeedEmulationMode(); case FillBis: return m_flag_bits->CanFillBis(); case CorruptSaveData: return m_flag_bits->CanCorruptSaveData(); case CorruptSystemSaveData: return m_flag_bits->CanCorruptSystemSaveData(); case VerifySaveData: return m_flag_bits->CanVerifySaveData(); case DebugSaveData: return m_flag_bits->CanDebugSaveData(); case FormatSdCard: return m_flag_bits->CanFormatSdCard(); case GetRightsId: return m_flag_bits->CanGetRightsId(); case RegisterExternalKey: return m_flag_bits->CanRegisterExternalKey(); case SetEncryptionSeed: return m_flag_bits->CanSetEncryptionSeed(); case WriteSaveDataFileSystemExtraDataTimeStamp: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataTimeStamp(); case WriteSaveDataFileSystemExtraDataFlags: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataFlags(); case WriteSaveDataFileSystemExtraDataCommitId: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataCommitId(); case WriteSaveDataFileSystemExtraDataAll: return m_flag_bits->CanWriteSaveDataFileSystemExtraDataAll(); case ExtendSaveData: return m_flag_bits->CanExtendSaveData(); case ExtendSystemSaveData: return m_flag_bits->CanExtendSystemSaveData(); case ExtendOthersSystemSaveData: return m_flag_bits->CanExtendOthersSystemSaveData(); case RegisterUpdatePartition: return m_flag_bits->CanRegisterUpdatePartition() && g_is_debug_flag_enabled; case OpenSaveDataTransferManager: return m_flag_bits->CanOpenSaveDataTransferManager(); case OpenSaveDataTransferManagerVersion2: return m_flag_bits->CanOpenSaveDataTransferManagerVersion2(); case OpenSaveDataTransferManagerForSaveDataRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepair(); case OpenSaveDataTransferManagerForSaveDataRepairTool: return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepairTool(); case OpenSaveDataTransferProhibiter: return m_flag_bits->CanOpenSaveDataTransferProhibiter(); case OpenSaveDataMover: return m_flag_bits->CanOpenSaveDataMover(); case OpenBisWiper: return m_flag_bits->CanOpenBisWiper(); case ListAccessibleSaveDataOwnerId: return m_flag_bits->CanListAccessibleSaveDataOwnerId(); case ControlMmcPatrol: return m_flag_bits->CanControlMmcPatrol(); case OverrideSaveDataTransferTokenSignVerificationKey: return m_flag_bits->CanOverrideSaveDataTransferTokenSignVerificationKey(); case OpenSdCardDetectionEventNotifier: return m_flag_bits->CanOpenSdCardDetectionEventNotifier(); case OpenGameCardDetectionEventNotifier: return m_flag_bits->CanOpenGameCardDetectionEventNotifier(); case OpenSystemDataUpdateEventNotifier: return m_flag_bits->CanOpenSystemDataUpdateEventNotifier(); case NotifySystemDataUpdateEvent: return m_flag_bits->CanNotifySystemDataUpdateEvent(); case OpenAccessFailureDetectionEventNotifier: return m_flag_bits->CanOpenAccessFailureDetectionEventNotifier(); case GetAccessFailureDetectionEvent: return m_flag_bits->CanGetAccessFailureDetectionEvent(); case IsAccessFailureDetected: return m_flag_bits->CanIsAccessFailureDetected(); case ResolveAccessFailure: return m_flag_bits->CanResolveAccessFailure(); case AbandonAccessFailure: return m_flag_bits->CanAbandonAccessFailure(); case QuerySaveDataInternalStorageTotalSize: return m_flag_bits->CanQuerySaveDataInternalStorageTotalSize(); case GetSaveDataCommitId: return m_flag_bits->CanGetSaveDataCommitId(); case SetSdCardAccessibility: return m_flag_bits->CanSetSdCardAccessibility(); case SimulateDevice: return m_flag_bits->CanSimulateDevice(); case CreateSaveDataWithHashSalt: return m_flag_bits->CanCreateSaveDataWithHashSalt(); case RegisterProgramIndexMapInfo: return m_flag_bits->CanRegisterProgramIndexMapInfo(); case ChallengeCardExistence: return m_flag_bits->CanChallengeCardExistence(); case CreateOwnSaveData: return m_flag_bits->CanCreateOwnSaveData(); case DeleteOwnSaveData: return m_flag_bits->CanDeleteOwnSaveData(); case ReadOwnSaveDataFileSystemExtraData: return m_flag_bits->CanReadOwnSaveDataFileSystemExtraData(); case ExtendOwnSaveData: return m_flag_bits->CanExtendOwnSaveData(); case OpenOwnSaveDataTransferProhibiter: return m_flag_bits->CanOpenOwnSaveDataTransferProhibiter(); case FindOwnSaveDataWithFilter: return m_flag_bits->CanFindOwnSaveDataWithFilter(); case OpenSaveDataTransferManagerForRepair: return m_flag_bits->CanOpenSaveDataTransferManagerForRepair(); case SetDebugConfiguration: return m_flag_bits->CanSetDebugConfiguration(); case OpenDataStorageByPath: return m_flag_bits->CanOpenDataStorageByPath(); AMS_UNREACHABLE_DEFAULT_CASE(); } } } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_deferred_process_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fssrv { using NotifyProcessDeferredFunction = void (*)(u64 process_id); struct DeferredProcessEntryForDeviceError : public util::IntrusiveListBaseNode<DeferredProcessEntryForDeviceError>, public fs::impl::Newable { os::MultiWaitHolderType *process_holder; u64 process_id; }; class DeferredProcessQueueForDeviceError { NON_COPYABLE(DeferredProcessQueueForDeviceError); NON_MOVEABLE(DeferredProcessQueueForDeviceError); private: using EntryList = util::IntrusiveListBaseTraits<DeferredProcessEntryForDeviceError>::ListType; private: EntryList m_list{}; os::SdkMutex m_mutex{}; public: constexpr DeferredProcessQueueForDeviceError() = default; }; class DeferredProcessEntryForPriority : public util::IntrusiveListBaseNode<DeferredProcessEntryForPriority>, public fs::impl::Newable { private: os::MultiWaitHolderType *m_process_holder; FileSystemProxyServerSessionType m_session_type; }; class DeferredProcessQueueForPriority { NON_COPYABLE(DeferredProcessQueueForPriority); NON_MOVEABLE(DeferredProcessQueueForPriority); private: using EntryList = util::IntrusiveListBaseTraits<DeferredProcessEntryForPriority>::ListType; private: EntryList m_list{}; os::SdkRecursiveMutex m_mutex{}; os::SdkConditionVariable m_cv{}; public: constexpr DeferredProcessQueueForPriority() = default; }; template<typename ServerManager, NotifyProcessDeferredFunction NotifyProcessDeferred> class DeferredProcessManager { NON_COPYABLE(DeferredProcessManager); NON_MOVEABLE(DeferredProcessManager); private: DeferredProcessQueueForDeviceError m_queue_for_device_error{}; os::SdkMutex m_invoke_mutex_for_device_error{}; DeferredProcessQueueForPriority m_queue_for_priority{}; std::atomic_bool m_is_invoke_deferred_process_event_linked{}; os::EventType m_invoke_event{}; os::MultiWaitHolderType m_invoke_event_holder{}; bool m_initialized{false}; public: constexpr DeferredProcessManager() = default; void Initialize() { /* Check pre-conditions. */ AMS_ASSERT(!m_initialized); os::InitializeEvent(std::addressof(m_invoke_event), false, os::EventClearMode_ManualClear); os::InitializeMultiWaitHolder(std::addressof(m_invoke_event_holder), std::addressof(m_invoke_event)); m_initialized = true; } }; } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_api.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fs/impl/fs_service_name.hpp> #include "fssrv_deferred_process_manager.hpp" namespace ams::fssrv { namespace { struct FileSystemProxyServerOptions { static constexpr size_t PointerBufferSize = 0x800; static constexpr size_t MaxDomains = 0x40; static constexpr size_t MaxDomainObjects = 0x4000; static constexpr bool CanDeferInvokeRequest = true; static constexpr bool CanManageMitmServers = false; }; enum PortIndex { PortIndex_FileSystemProxy, PortIndex_ProgramRegistry, PortIndex_FileSystemProxyForLoader, PortIndex_Count, }; constexpr size_t FileSystemProxyMaxSessions = 59; constexpr size_t ProgramRegistryMaxSessions = 1; constexpr size_t FileSystemProxyForLoaderMaxSessions = 1; constexpr size_t NumSessions = FileSystemProxyMaxSessions + ProgramRegistryMaxSessions + FileSystemProxyForLoaderMaxSessions; constinit os::SemaphoreType g_semaphore_for_file_system_proxy_for_loader = {}; constinit os::SemaphoreType g_semaphore_for_program_registry = {}; class FileSystemProxyServerManager final : public ams::sf::hipc::ServerManager<PortIndex_Count, FileSystemProxyServerOptions, NumSessions> { private: virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override { switch (port_index) { case PortIndex_FileSystemProxy: { R_RETURN(this->AcceptImpl(server, impl::GetFileSystemProxyServiceObject())); } case PortIndex_ProgramRegistry: { if (os::TryAcquireSemaphore(std::addressof(g_semaphore_for_program_registry))) { ON_RESULT_FAILURE { os::ReleaseSemaphore(std::addressof(g_semaphore_for_program_registry)); }; R_RETURN(this->AcceptImpl(server, impl::GetProgramRegistryServiceObject())); } else { R_RETURN(this->AcceptImpl(server, impl::GetInvalidProgramRegistryServiceObject())); } } case PortIndex_FileSystemProxyForLoader: { if (os::TryAcquireSemaphore(std::addressof(g_semaphore_for_file_system_proxy_for_loader))) { ON_RESULT_FAILURE { os::ReleaseSemaphore(std::addressof(g_semaphore_for_file_system_proxy_for_loader)); }; R_RETURN(this->AcceptImpl(server, impl::GetFileSystemProxyForLoaderServiceObject())); } else { R_RETURN(this->AcceptImpl(server, impl::GetInvalidFileSystemProxyForLoaderServiceObject())); } } AMS_UNREACHABLE_DEFAULT_CASE(); } } }; constinit util::TypedStorage<FileSystemProxyServerManager> g_server_manager_storage = {}; constinit FileSystemProxyServerManager *g_server_manager = nullptr; constinit os::BarrierType g_server_loop_barrier = {}; constinit os::EventType g_resume_wait_event = {}; constinit bool g_is_suspended = false; void TemporaryNotifyProcessDeferred(u64) { /* TODO */ } constinit DeferredProcessManager<FileSystemProxyServerManager, TemporaryNotifyProcessDeferred> g_deferred_process_manager; } void InitializeForFileSystemProxy(const FileSystemProxyConfiguration &config) { /* TODO FS-REIMPL */ AMS_UNUSED(config); } void InitializeFileSystemProxyServer(int threads) { /* Initialize synchronization primitives. */ os::InitializeBarrier(std::addressof(g_server_loop_barrier), threads + 1); os::InitializeEvent(std::addressof(g_resume_wait_event), false, os::EventClearMode_ManualClear); g_is_suspended = false; os::InitializeSemaphore(std::addressof(g_semaphore_for_file_system_proxy_for_loader), 1, 1); os::InitializeSemaphore(std::addressof(g_semaphore_for_program_registry), 1, 1); /* Initialize deferred process manager. */ g_deferred_process_manager.Initialize(); /* Create the server and register our services. */ AMS_ASSERT(g_server_manager == nullptr); g_server_manager = util::ConstructAt(g_server_manager_storage); /* TODO: Manager handler. */ R_ABORT_UNLESS(g_server_manager->RegisterServer(PortIndex_FileSystemProxy, fs::impl::FileSystemProxyServiceName, FileSystemProxyMaxSessions)); R_ABORT_UNLESS(g_server_manager->RegisterServer(PortIndex_ProgramRegistry, fs::impl::ProgramRegistryServiceName, ProgramRegistryMaxSessions)); R_ABORT_UNLESS(g_server_manager->RegisterServer(PortIndex_FileSystemProxyForLoader, fs::impl::FileSystemProxyForLoaderServiceName, FileSystemProxyForLoaderMaxSessions)); /* Enable processing on server. */ g_server_manager->ResumeProcessing(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_file_system_proxy_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "impl/fssrv_allocator_for_service_framework.hpp" #include "impl/fssrv_program_info.hpp" namespace ams::fssrv { FileSystemProxyImpl::FileSystemProxyImpl() { /* TODO: Set core impl. */ m_process_id = os::InvalidProcessId.value; } FileSystemProxyImpl::~FileSystemProxyImpl() { /* ... */ } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" Result FileSystemProxyImpl::OpenFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::FileSystemProxyImpl::SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { /* Set current process. */ m_process_id = client_pid.GetValue().value; /* TODO: Allocate NcaFileSystemService. */ /* TODO: Allocate SaveDataFileSystemService. */ R_SUCCEED(); } Result FileSystemProxyImpl::OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::InvalidateBisCache() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenHostFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path) { /* Invoke the modern API from the legacy API. */ R_RETURN(this->OpenHostFileSystemWithOption(out, path, fs::MountHostOption::None._value)); } Result FileSystemProxyImpl::OpenSdCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::FormatSdCardFileSystem() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::DeleteSaveDataFileSystem(u64 save_data_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::FormatSdCardDryRun() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::IsExFatSupported(ams::sf::Out<bool> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenGameCardStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 handle, u32 partition) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenGameCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 handle, u32 partition) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::DeleteCacheStorage(u16 index) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetCacheStorageSize(ams::sf::Out<s64> out_size, ams::sf::Out<s64> out_journal_size, u16 index) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenHostFileSystemWithOption(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 _option) { /* TODO: GetProgramInfo */ /* TODO: GetAccessibility. */ /* TODO: Check Accessibility CanRead/CanWrite */ /* Convert the path. */ fs::Path normalized_path; #if defined(ATMOSPHERE_OS_WINDOWS) R_TRY(normalized_path.Initialize(path.str)); #else if (path.str[0] == '/' && path.str[1] == '/') { R_TRY(normalized_path.Initialize(path.str)); } else { R_TRY(normalized_path.InitializeWithReplaceUnc(path.str)); } #endif /* Normalize the path. */ fs::PathFlags path_flags; path_flags.AllowWindowsPath(); path_flags.AllowRelativePath(); path_flags.AllowEmptyPath(); R_TRY(normalized_path.Normalize(path_flags)); /* Parse option. */ const fs::MountHostOption option{ _option }; /* TODO: FileSystemProxyCoreImpl::OpenHostFileSystem */ /* TODO: use creator interfaces */ std::shared_ptr<fs::fsa::IFileSystem> fs; { fssrv::fscreator::LocalFileSystemCreator local_fs_creator(true); R_TRY(static_cast<fscreator::ILocalFileSystemCreator &>(local_fs_creator).Create(std::addressof(fs), normalized_path, option.HasPseudoCaseSensitiveFlag())); } /* Determine path flags for the result fs. */ fs::PathFlags host_path_flags; if (path.str[0] == 0) { host_path_flags.AllowWindowsPath(); } /* Create an interface adapter. */ auto sf_fs = impl::FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, impl::FileSystemInterfaceAdapter>(std::move(fs), host_path_flags, false); R_UNLESS(sf_fs != nullptr, fs::ResultAllocationMemoryFailedInFileSystemProxyImplA()); /* Set the output. */ *out = std::move(sf_fs); R_SUCCEED(); } Result FileSystemProxyImpl::OpenSaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenReadOnlySaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer) { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::OpenImageDirectoryFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::OpenContentStorageFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::OpenDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataStorageByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::ProgramId program_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataStorageByDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenSystemDataUpdateEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::NotifySystemDataUpdateEvent() { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::SetCurrentPosixTime(s64 posix_time) { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::UnregisterAllExternalKey() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetProgramId(ams::sf::Out<ncm::ProgramId> out_program_id, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::VerifySaveDataFileSystemBySaveDataSpaceId() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::CorruptSaveDataFileSystemBySaveDataSpaceId() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::QuerySaveDataInternalStorageTotalSize() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetSaveDataCommitId() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::UnregisterExternalKey(const fs::RightsId &rights_id) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetSdCardAccessibility(bool accessible) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::IsSdCardAccessible(ams::sf::Out<bool> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::IsSignedSystemPartitionOnSdCardValid(ams::sf::Out<bool> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenAccessFailureDetectionEventNotifier() { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::GetAndClearErrorInfo(ams::sf::Out<fs::FileSystemProxyErrorInfo> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetSaveDataSize(s64 size, s64 journal_size) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetSaveDataRootPath(const fssrv::sf::FspPath &path) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::DisableAutoSaveDataCreation() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::SetGlobalAccessLogMode(u32 mode) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetGlobalAccessLogMode(ams::sf::Out<u32> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OutputAccessLogToSdCard(const ams::sf::InBuffer &buf) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::RegisterUpdatePartition() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OpenRegisteredUpdatePartition(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetAndClearMemoryReportInfo(ams::sf::Out<fs::MemoryReportInfo> out) { AMS_ABORT("TODO"); } /* ... */ Result FileSystemProxyImpl::GetProgramIndexForAccessLog(ams::sf::Out<u32> out_idx, ams::sf::Out<u32> out_count) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::GetFsStackUsage(ams::sf::Out<u32> out, u32 type) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::UnsetSaveDataRootPath() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OutputMultiProgramTagAccessLog() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::FlushAccessLogOnSdCard() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OutputApplicationInfoAccessLog() { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::RegisterDebugConfiguration(u32 key, s64 value) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::UnregisterDebugConfiguration(u32 key) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf) { AMS_ABORT("TODO"); } Result FileSystemProxyImpl::CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset) { AMS_ABORT("TODO"); } /* ... */ #pragma GCC diagnostic pop Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, path, program_id); } Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, out_verif, path, program_id); } Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, out_verif, path, attr, program_id); } Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated4(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, out_verif, path, attr, program_id); } Result FileSystemProxyImpl::OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) { AMS_ABORT("TODO"); AMS_UNUSED(out_fs, out_verif, attr, program_id, storage_id); } Result FileSystemProxyImpl::IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) { AMS_ABORT("TODO"); AMS_UNUSED(out, process_id); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "impl/fssrv_allocator_for_service_framework.hpp" #include "fssrv_retry_utility.hpp" namespace ams::fssrv::impl { namespace { constexpr const char *RootDirectory = "/"; } FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr<fs::fsa::IFile> &&file, FileSystemInterfaceAdapter *parent, bool allow_all) : m_parent_filesystem(parent, true), m_base_file(std::move(file)), m_allow_all_operations(allow_all) { /* ... */ } Result FileInterfaceAdapter::Read(ams::sf::Out<s64> out, s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size, fs::ReadOption option) { /* Check pre-conditions. */ R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); R_UNLESS(0 <= size, fs::ResultInvalidSize()); R_UNLESS(size <= static_cast<s64>(buffer.GetSize()), fs::ResultInvalidSize()); /* Read the data, retrying on corruption. */ size_t read_size = 0; R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_file->Read(std::addressof(read_size), offset, buffer.GetPointer(), static_cast<size_t>(size), option)); })); /* Set the output size. */ *out = read_size; R_SUCCEED(); } Result FileInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size, fs::WriteOption option) { /* Check pre-conditions. */ R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); R_UNLESS(0 <= size, fs::ResultInvalidSize()); R_UNLESS(size <= static_cast<s64>(buffer.GetSize()), fs::ResultInvalidSize()); /* Temporarily increase our thread's priority. */ fssystem::ScopedThreadPriorityChangerByAccessPriority cp(fssystem::ScopedThreadPriorityChangerByAccessPriority::AccessMode::Write); R_RETURN(m_base_file->Write(offset, buffer.GetPointer(), size, option)); } Result FileInterfaceAdapter::Flush() { R_RETURN(m_base_file->Flush()); } Result FileInterfaceAdapter::SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_RETURN(m_base_file->SetSize(size)); } Result FileInterfaceAdapter::GetSize(ams::sf::Out<s64> out) { /* Get the size, retrying on corruption. */ R_RETURN(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_file->GetSize(out.GetPointer())); })); } Result FileInterfaceAdapter::OperateRange(ams::sf::Out<fs::FileQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) { /* N includes this redundant check, so we will too. */ R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument()); /* Clear the range info. */ out->Clear(); if (op_id == static_cast<s32>(fs::OperationId::QueryRange)) { fs::FileQueryRangeInfo info; R_TRY(m_base_file->OperateRange(std::addressof(info), sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0)); out->Merge(info); } else if (op_id == static_cast<s32>(fs::OperationId::Invalidate)) { R_TRY(m_base_file->OperateRange(nullptr, 0, fs::OperationId::Invalidate, offset, size, nullptr, 0)); } R_SUCCEED(); } Result FileInterfaceAdapter::OperateRangeWithBuffer(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 op_id, s64 offset, s64 size) { /* Check that we have permission to perform the operation. */ switch (static_cast<fs::OperationId>(op_id)) { using enum fs::OperationId; case QueryUnpreparedRange: case QueryLazyLoadCompletionRate: case SetLazyLoadPriority: /* Lazy load/unprepared operations are always allowed to be performed with buffer. */ break; default: R_UNLESS(m_allow_all_operations, fs::ResultPermissionDenied()); } /* Perform the operation. */ R_RETURN(m_base_file->OperateRange(out_buf.GetPointer(), out_buf.GetSize(), static_cast<fs::OperationId>(op_id), offset, size, in_buf.GetPointer(), in_buf.GetSize())); } DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr<fs::fsa::IDirectory> &&dir, FileSystemInterfaceAdapter *parent, bool allow_all) : m_parent_filesystem(parent, true), m_base_dir(std::move(dir)), m_allow_all_operations(allow_all) { /* ... */ } Result DirectoryInterfaceAdapter::Read(ams::sf::Out<s64> out, const ams::sf::OutBuffer &out_entries) { /* Get the maximum number of entries we can read into the buffer. */ const s64 max_num_entries = out_entries.GetSize() / sizeof(fs::DirectoryEntry); R_UNLESS(max_num_entries >= 0, fs::ResultInvalidSize()); /* Get the size, retrying on corruption. */ s64 num_read = 0; R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_dir->Read(std::addressof(num_read), reinterpret_cast<fs::DirectoryEntry *>(out_entries.GetPointer()), max_num_entries)); })); /* Set the output. */ *out = num_read; R_SUCCEED(); } Result DirectoryInterfaceAdapter::GetEntryCount(ams::sf::Out<s64> out) { R_RETURN(m_base_dir->GetEntryCount(out.GetPointer())); } Result FileSystemInterfaceAdapter::SetUpPath(fs::Path *out, const fssrv::sf::Path &sf_path) { /* Initialize the fs path. */ if (m_path_flags.IsWindowsPathAllowed()) { R_TRY(out->InitializeWithReplaceUnc(sf_path.str)); } else { R_TRY(out->Initialize(sf_path.str)); } /* Ensure the path is normalized. */ R_RETURN(out->Normalize(m_path_flags)); } Result FileSystemInterfaceAdapter::CreateFile(const fssrv::sf::Path &path, s64 size, s32 option) { /* Check pre-conditions. */ R_UNLESS(size >= 0, fs::ResultInvalidSize()); /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->CreateFile(fs_path, size, option)); } Result FileSystemInterfaceAdapter::DeleteFile(const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->DeleteFile(fs_path)); } Result FileSystemInterfaceAdapter::CreateDirectory(const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); /* Sanity check that the directory isn't the root. */ R_UNLESS(fs_path != RootDirectory, fs::ResultPathAlreadyExists()); R_RETURN(m_base_fs->CreateDirectory(fs_path)); } Result FileSystemInterfaceAdapter::DeleteDirectory(const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); /* Sanity check that the directory isn't the root. */ R_UNLESS(fs_path != RootDirectory, fs::ResultDirectoryNotDeletable()); R_RETURN(m_base_fs->DeleteDirectory(fs_path)); } Result FileSystemInterfaceAdapter::DeleteDirectoryRecursively(const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); /* Sanity check that the directory isn't the root. */ R_UNLESS(fs_path != RootDirectory, fs::ResultDirectoryNotDeletable()); R_RETURN(m_base_fs->DeleteDirectoryRecursively(fs_path)); } Result FileSystemInterfaceAdapter::RenameFile(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { /* Normalize the input paths. */ fs::Path fs_old_path; fs::Path fs_new_path; R_TRY(this->SetUpPath(std::addressof(fs_old_path), old_path)); R_TRY(this->SetUpPath(std::addressof(fs_new_path), new_path)); R_RETURN(m_base_fs->RenameFile(fs_old_path, fs_new_path)); } Result FileSystemInterfaceAdapter::RenameDirectory(const fssrv::sf::Path &old_path, const fssrv::sf::Path &new_path) { /* Normalize the input paths. */ fs::Path fs_old_path; fs::Path fs_new_path; R_TRY(this->SetUpPath(std::addressof(fs_old_path), old_path)); R_TRY(this->SetUpPath(std::addressof(fs_new_path), new_path)); R_UNLESS(!fs::IsSubPath(fs_old_path.GetString(), fs_new_path.GetString()), fs::ResultDirectoryNotRenamable()); R_RETURN(m_base_fs->RenameDirectory(fs_old_path, fs_new_path)); } Result FileSystemInterfaceAdapter::GetEntryType(ams::sf::Out<u32> out, const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); static_assert(sizeof(*out.GetPointer()) == sizeof(fs::DirectoryEntryType)); R_RETURN(m_base_fs->GetEntryType(reinterpret_cast<fs::DirectoryEntryType *>(out.GetPointer()), fs_path)); } Result FileSystemInterfaceAdapter::OpenFile(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFile>> out, const fssrv::sf::Path &path, u32 mode) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); /* Open the file, retrying on corruption. */ std::unique_ptr<fs::fsa::IFile> file; R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->OpenFile(std::addressof(file), fs_path, static_cast<fs::OpenMode>(mode))); })); /* If we're a mitm interface, we should preserve the resulting target object id. */ if (m_is_mitm_interface) { /* TODO: This is a hack to get the mitm API to work. Better solution? */ const auto target_object_id = file->GetDomainObjectId(); ams::sf::SharedPointer<fssrv::sf::IFile> file_intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IFile, FileInterfaceAdapter>(std::move(file), this, m_allow_all_operations); R_UNLESS(file_intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(file_intf), target_object_id); } else { ams::sf::SharedPointer<fssrv::sf::IFile> file_intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IFile, FileInterfaceAdapter>(std::move(file), this, m_allow_all_operations); R_UNLESS(file_intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(file_intf)); } R_SUCCEED(); } Result FileSystemInterfaceAdapter::OpenDirectory(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDirectory>> out, const fssrv::sf::Path &path, u32 mode) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); /* Open the directory, retrying on corruption. */ std::unique_ptr<fs::fsa::IDirectory> dir; R_TRY(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->OpenDirectory(std::addressof(dir), fs_path, static_cast<fs::OpenDirectoryMode>(mode))); })); /* If we're a mitm interface, we should preserve the resulting target object id. */ if (m_is_mitm_interface) { /* TODO: This is a hack to get the mitm API to work. Better solution? */ const auto target_object_id = dir->GetDomainObjectId(); ams::sf::SharedPointer<fssrv::sf::IDirectory> dir_intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IDirectory, DirectoryInterfaceAdapter>(std::move(dir), this, m_allow_all_operations); R_UNLESS(dir_intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(dir_intf), target_object_id); } else { ams::sf::SharedPointer<fssrv::sf::IDirectory> dir_intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IDirectory, DirectoryInterfaceAdapter>(std::move(dir), this, m_allow_all_operations); R_UNLESS(dir_intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(dir_intf)); } R_SUCCEED(); } Result FileSystemInterfaceAdapter::Commit() { R_RETURN(m_base_fs->Commit()); } Result FileSystemInterfaceAdapter::GetFreeSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->GetFreeSpaceSize(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::GetTotalSpaceSize(ams::sf::Out<s64> out, const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->GetTotalSpaceSize(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::CleanDirectoryRecursively(const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->CleanDirectoryRecursively(fs_path)); } Result FileSystemInterfaceAdapter::GetFileTimeStampRaw(ams::sf::Out<fs::FileTimeStampRaw> out, const fssrv::sf::Path &path) { /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); R_RETURN(m_base_fs->GetFileTimeStampRaw(out.GetPointer(), fs_path)); } Result FileSystemInterfaceAdapter::QueryEntry(const ams::sf::OutNonSecureBuffer &out_buf, const ams::sf::InNonSecureBuffer &in_buf, s32 query_id, const fssrv::sf::Path &path) { /* Check that we have permission to perform the operation. */ switch (static_cast<fs::fsa::QueryId>(query_id)) { using enum fs::fsa::QueryId; case SetConcatenationFileAttribute: case IsSignedSystemPartitionOnSdCardValid: case QueryUnpreparedFileInformation: /* Only certain operations are unconditionally allowable. */ break; default: R_UNLESS(m_allow_all_operations, fs::ResultPermissionDenied()); } /* Normalize the input path. */ fs::Path fs_path; R_TRY(this->SetUpPath(std::addressof(fs_path), path)); char *dst = reinterpret_cast<char *>(out_buf.GetPointer()); const char *src = reinterpret_cast<const char *>(in_buf.GetPointer()); R_RETURN(m_base_fs->QueryEntry(dst, out_buf.GetSize(), src, in_buf.GetSize(), static_cast<fs::fsa::QueryId>(query_id), fs_path)); } #if defined(ATMOSPHERE_OS_HORIZON) Result RemoteFileSystem::OpenFile(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFile>> out, const fssrv::sf::Path &path, u32 mode) { FsFile f; R_TRY(fsFsOpenFile(std::addressof(m_base_fs), path.str, mode, std::addressof(f))); auto intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IFile, RemoteFile>(f); R_UNLESS(intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(intf)); R_SUCCEED(); } Result RemoteFileSystem::OpenDirectory(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDirectory>> out, const fssrv::sf::Path &path, u32 mode) { FsDir d; R_TRY(fsFsOpenDirectory(std::addressof(m_base_fs), path.str, mode, std::addressof(d))); auto intf = FileSystemObjectFactory::CreateSharedEmplaced<fssrv::sf::IDirectory, RemoteDirectory>(d); R_UNLESS(intf != nullptr, fs::ResultAllocationMemoryFailedInFileSystemInterfaceAdapterA()); out.SetValue(std::move(intf)); R_SUCCEED(); } #endif } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_memory_resource_from_exp_heap.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv { namespace { size_t GetUsedSize(void *p) { const auto block_head = reinterpret_cast<const lmem::impl::ExpHeapMemoryBlockHead *>(reinterpret_cast<uintptr_t>(p) - sizeof(lmem::impl::ExpHeapMemoryBlockHead)); return block_head->block_size + ((block_head->attributes >> 8) & 0x7F) + sizeof(lmem::impl::ExpHeapMemoryBlockHead); } } void PeakCheckableMemoryResourceFromExpHeap::OnAllocate(void *p, size_t size) { AMS_UNUSED(size); if (p != nullptr) { m_current_free_size = GetUsedSize(p); m_peak_free_size = std::min(m_peak_free_size, m_current_free_size); } } void PeakCheckableMemoryResourceFromExpHeap::OnDeallocate(void *p, size_t size) { AMS_UNUSED(size); if (p != nullptr) { m_current_free_size += GetUsedSize(p); } } void *PeakCheckableMemoryResourceFromExpHeap::AllocateImpl(size_t size, size_t align) { std::scoped_lock lk(m_mutex); void *p = lmem::AllocateFromExpHeap(m_heap_handle, size, static_cast<s32>(align)); this->OnAllocate(p, size); return p; } void PeakCheckableMemoryResourceFromExpHeap::DeallocateImpl(void *p, size_t size, size_t align) { AMS_UNUSED(align); std::scoped_lock lk(m_mutex); this->OnDeallocate(p, size); lmem::FreeToExpHeap(m_heap_handle, p); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_memory_resource_from_standard_allocator.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv { MemoryResourceFromStandardAllocator::MemoryResourceFromStandardAllocator(mem::StandardAllocator *allocator) : m_allocator(allocator), m_mutex() { m_current_free_size = m_allocator->GetTotalFreeSize(); this->ClearPeak(); } void MemoryResourceFromStandardAllocator::ClearPeak() { std::scoped_lock lk(m_mutex); m_peak_free_size = m_current_free_size; m_peak_allocated_size = 0; } void *MemoryResourceFromStandardAllocator::AllocateImpl(size_t size, size_t align) { std::scoped_lock lk(m_mutex); void *p = m_allocator->Allocate(size, align); if (p != nullptr) { m_current_free_size -= m_allocator->GetSizeOf(p); m_peak_free_size = std::min(m_peak_free_size, m_current_free_size); } m_peak_allocated_size = std::max(m_peak_allocated_size, size); return p; } void MemoryResourceFromStandardAllocator::DeallocateImpl(void *p, size_t size, size_t align) { AMS_UNUSED(size, align); std::scoped_lock lk(m_mutex); m_current_free_size += m_allocator->GetSizeOf(p); m_allocator->Free(p); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_nca_crypto_configuration.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssrv { namespace { constexpr inline const u8 HeaderSign1KeyModulusDev[fssystem::NcaCryptoConfiguration::Header1SignatureKeyGenerationMax + 1][fssystem::NcaCryptoConfiguration::Rsa2048KeyModulusSize] = { { 0xD8, 0xF1, 0x18, 0xEF, 0x32, 0x72, 0x4C, 0xA7, 0x47, 0x4C, 0xB9, 0xEA, 0xB3, 0x04, 0xA8, 0xA4, 0xAC, 0x99, 0x08, 0x08, 0x04, 0xBF, 0x68, 0x57, 0xB8, 0x43, 0x94, 0x2B, 0xC7, 0xB9, 0x66, 0x49, 0x85, 0xE5, 0x8A, 0x9B, 0xC1, 0x00, 0x9A, 0x6A, 0x8D, 0xD0, 0xEF, 0xCE, 0xFF, 0x86, 0xC8, 0x5C, 0x5D, 0xE9, 0x53, 0x7B, 0x19, 0x2A, 0xA8, 0xC0, 0x22, 0xD1, 0xF3, 0x22, 0x0A, 0x50, 0xF2, 0x2B, 0x65, 0x05, 0x1B, 0x9E, 0xEC, 0x61, 0xB5, 0x63, 0xA3, 0x6F, 0x3B, 0xBA, 0x63, 0x3A, 0x53, 0xF4, 0x49, 0x2F, 0xCF, 0x03, 0xCC, 0xD7, 0x50, 0x82, 0x1B, 0x29, 0x4F, 0x08, 0xDE, 0x1B, 0x6D, 0x47, 0x4F, 0xA8, 0xB6, 0x6A, 0x26, 0xA0, 0x83, 0x3F, 0x1A, 0xAF, 0x83, 0x8F, 0x0E, 0x17, 0x3F, 0xFE, 0x44, 0x1C, 0x56, 0x94, 0x2E, 0x49, 0x83, 0x83, 0x03, 0xE9, 0xB6, 0xAD, 0xD5, 0xDE, 0xE3, 0x2D, 0xA1, 0xD9, 0x66, 0x20, 0x5D, 0x1F, 0x5E, 0x96, 0x5D, 0x5B, 0x55, 0x0D, 0xD4, 0xB4, 0x77, 0x6E, 0xAE, 0x1B, 0x69, 0xF3, 0xA6, 0x61, 0x0E, 0x51, 0x62, 0x39, 0x28, 0x63, 0x75, 0x76, 0xBF, 0xB0, 0xD2, 0x22, 0xEF, 0x98, 0x25, 0x02, 0x05, 0xC0, 0xD7, 0x6A, 0x06, 0x2C, 0xA5, 0xD8, 0x5A, 0x9D, 0x7A, 0xA4, 0x21, 0x55, 0x9F, 0xF9, 0x3E, 0xBF, 0x16, 0xF6, 0x07, 0xC2, 0xB9, 0x6E, 0x87, 0x9E, 0xB5, 0x1C, 0xBE, 0x97, 0xFA, 0x82, 0x7E, 0xED, 0x30, 0xD4, 0x66, 0x3F, 0xDE, 0xD8, 0x1B, 0x4B, 0x15, 0xD9, 0xFB, 0x2F, 0x50, 0xF0, 0x9D, 0x1D, 0x52, 0x4C, 0x1C, 0x4D, 0x8D, 0xAE, 0x85, 0x1E, 0xEA, 0x7F, 0x86, 0xF3, 0x0B, 0x7B, 0x87, 0x81, 0x98, 0x23, 0x80, 0x63, 0x4F, 0x2F, 0xB0, 0x62, 0xCC, 0x6E, 0xD2, 0x46, 0x13, 0x65, 0x2B, 0xD6, 0x44, 0x33, 0x59, 0xB5, 0x8F, 0xB9, 0x4A, 0xA9 }, { 0x9A, 0xBC, 0x88, 0xBD, 0x0A, 0xBE, 0xD7, 0x0C, 0x9B, 0x42, 0x75, 0x65, 0x38, 0x5E, 0xD1, 0x01, 0xCD, 0x12, 0xAE, 0xEA, 0xE9, 0x4B, 0xDB, 0xB4, 0x5E, 0x36, 0x10, 0x96, 0xDA, 0x3D, 0x2E, 0x66, 0xD3, 0x99, 0x13, 0x8A, 0xBE, 0x67, 0x41, 0xC8, 0x93, 0xD9, 0x3E, 0x42, 0xCE, 0x34, 0xCE, 0x96, 0xFA, 0x0B, 0x23, 0xCC, 0x2C, 0xDF, 0x07, 0x3F, 0x3B, 0x24, 0x4B, 0x12, 0x67, 0x3A, 0x29, 0x36, 0xA3, 0xAA, 0x06, 0xF0, 0x65, 0xA5, 0x85, 0xBA, 0xFD, 0x12, 0xEC, 0xF1, 0x60, 0x67, 0xF0, 0x8F, 0xD3, 0x5B, 0x01, 0x1B, 0x1E, 0x84, 0xA3, 0x5C, 0x65, 0x36, 0xF9, 0x23, 0x7E, 0xF3, 0x26, 0x38, 0x64, 0x98, 0xBA, 0xE4, 0x19, 0x91, 0x4C, 0x02, 0xCF, 0xC9, 0x6D, 0x86, 0xEC, 0x1D, 0x41, 0x69, 0xDD, 0x56, 0xEA, 0x5C, 0xA3, 0x2A, 0x58, 0xB4, 0x39, 0xCC, 0x40, 0x31, 0xFD, 0xFB, 0x42, 0x74, 0xF8, 0xEC, 0xEA, 0x00, 0xF0, 0xD9, 0x28, 0xEA, 0xFA, 0x2D, 0x00, 0xE1, 0x43, 0x53, 0xC6, 0x32, 0xF4, 0xA2, 0x07, 0xD4, 0x5F, 0xD4, 0xCB, 0xAC, 0xCA, 0xFF, 0xDF, 0x84, 0xD2, 0x86, 0x14, 0x3C, 0xDE, 0x22, 0x75, 0xA5, 0x73, 0xFF, 0x68, 0x07, 0x4A, 0xF9, 0x7C, 0x2C, 0xCC, 0xDE, 0x45, 0xB6, 0x54, 0x82, 0x90, 0x36, 0x1F, 0x2C, 0x51, 0x96, 0xC5, 0x0A, 0x53, 0x5B, 0xF0, 0x8B, 0x4A, 0xAA, 0x3B, 0x68, 0x97, 0x19, 0x17, 0x1F, 0x01, 0xB8, 0xED, 0xB9, 0x9A, 0x5E, 0x08, 0xC5, 0x20, 0x1E, 0x6A, 0x09, 0xF0, 0xE9, 0x73, 0xA3, 0xBE, 0x10, 0x06, 0x02, 0xE9, 0xFB, 0x85, 0xFA, 0x5F, 0x01, 0xAC, 0x60, 0xE0, 0xED, 0x7D, 0xB9, 0x49, 0xA8, 0x9E, 0x98, 0x7D, 0x91, 0x40, 0x05, 0xCF, 0xF9, 0x1A, 0xFC, 0x40, 0x22, 0xA8, 0x96, 0x5B, 0xB0, 0xDC, 0x7A, 0xF5, 0xB7, 0xE9, 0x91, 0x4C, 0x49 } }; constexpr inline const u8 HeaderSign1KeyModulusProd[fssystem::NcaCryptoConfiguration::Header1SignatureKeyGenerationMax + 1][fssystem::NcaCryptoConfiguration::Rsa2048KeyModulusSize] = { { 0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F, 0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58, 0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16, 0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2, 0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF, 0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67, 0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26, 0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C, 0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE, 0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86, 0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35, 0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B, 0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29, 0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40, 0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81, 0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03 }, { 0xAD, 0xE3, 0xE1, 0xFA, 0x04, 0x35, 0xE5, 0xB6, 0xDD, 0x49, 0xEA, 0x89, 0x29, 0xB1, 0xFF, 0xB6, 0x43, 0xDF, 0xCA, 0x96, 0xA0, 0x4A, 0x13, 0xDF, 0x43, 0xD9, 0x94, 0x97, 0x96, 0x43, 0x65, 0x48, 0x70, 0x58, 0x33, 0xA2, 0x7D, 0x35, 0x7B, 0x96, 0x74, 0x5E, 0x0B, 0x5C, 0x32, 0x18, 0x14, 0x24, 0xC2, 0x58, 0xB3, 0x6C, 0x22, 0x7A, 0xA1, 0xB7, 0xCB, 0x90, 0xA7, 0xA3, 0xF9, 0x7D, 0x45, 0x16, 0xA5, 0xC8, 0xED, 0x8F, 0xAD, 0x39, 0x5E, 0x9E, 0x4B, 0x51, 0x68, 0x7D, 0xF8, 0x0C, 0x35, 0xC6, 0x3F, 0x91, 0xAE, 0x44, 0xA5, 0x92, 0x30, 0x0D, 0x46, 0xF8, 0x40, 0xFF, 0xD0, 0xFF, 0x06, 0xD2, 0x1C, 0x7F, 0x96, 0x18, 0xDC, 0xB7, 0x1D, 0x66, 0x3E, 0xD1, 0x73, 0xBC, 0x15, 0x8A, 0x2F, 0x94, 0xF3, 0x00, 0xC1, 0x83, 0xF1, 0xCD, 0xD7, 0x81, 0x88, 0xAB, 0xDF, 0x8C, 0xEF, 0x97, 0xDD, 0x1B, 0x17, 0x5F, 0x58, 0xF6, 0x9A, 0xE9, 0xE8, 0xC2, 0x2F, 0x38, 0x15, 0xF5, 0x21, 0x07, 0xF8, 0x37, 0x90, 0x5D, 0x2E, 0x02, 0x40, 0x24, 0x15, 0x0D, 0x25, 0xB7, 0x26, 0x5D, 0x09, 0xCC, 0x4C, 0xF4, 0xF2, 0x1B, 0x94, 0x70, 0x5A, 0x9E, 0xEE, 0xED, 0x77, 0x77, 0xD4, 0x51, 0x99, 0xF5, 0xDC, 0x76, 0x1E, 0xE3, 0x6C, 0x8C, 0xD1, 0x12, 0xD4, 0x57, 0xD1, 0xB6, 0x83, 0xE4, 0xE4, 0xFE, 0xDA, 0xE9, 0xB4, 0x3B, 0x33, 0xE5, 0x37, 0x8A, 0xDF, 0xB5, 0x7F, 0x89, 0xF1, 0x9B, 0x9E, 0xB0, 0x15, 0xB2, 0x3A, 0xFE, 0xEA, 0x61, 0x84, 0x5B, 0x7D, 0x4B, 0x23, 0x12, 0x0B, 0x83, 0x12, 0xF2, 0x22, 0x6B, 0xB9, 0x22, 0x96, 0x4B, 0x26, 0x0B, 0x63, 0x5E, 0x96, 0x57, 0x52, 0xA3, 0x67, 0x64, 0x22, 0xCA, 0xD0, 0x56, 0x3E, 0x74, 0xB5, 0x98, 0x1F, 0x0D, 0xF8, 0xB3, 0x34, 0xE6, 0x98, 0x68, 0x5A, 0xAD } }; constexpr inline const ::ams::fssystem::NcaCryptoConfiguration DefaultNcaCryptoConfigurationDev = { /* Header1 Signature Key Moduli */ { HeaderSign1KeyModulusDev[0], HeaderSign1KeyModulusDev[1] }, /* Header 1 Signature Key Public Exponent */ { 0x01, 0x00, 0x01 }, /* Key Area Encryption Key Sources */ { /* Application */ { 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D }, /* Ocean */ { 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82 }, /* System */ { 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A }, }, /* Header Encryption Key Source */ { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A }, /* Encrypted Header Encryption Key */ { { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0 }, { 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 } }, /* Key Generation Function */ nullptr, /* Decrypt Aes Xts Eternal Function */ nullptr, /* Encrypt Aes Xts Eternal Function */ nullptr, /* Decrypt Aes Ctr Function */ nullptr, /* Decrypt Aes Ctr External Function */ nullptr, /* Verify Sign1 Function */ nullptr, /* Plaintext Header Available */ false, /* Software Key Available */ true, }; constexpr inline const ::ams::fssystem::NcaCryptoConfiguration DefaultNcaCryptoConfigurationProd = { /* Header1 Signature Key Moduli */ { HeaderSign1KeyModulusProd[0], HeaderSign1KeyModulusProd[1] }, /* Header 1 Signature Key Public Exponent */ { 0x01, 0x00, 0x01 }, /* Key Area Encryption Key Sources */ { /* Application */ { 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D }, /* Ocean */ { 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82 }, /* System */ { 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A }, }, /* Header Encryption Key Source */ { 0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A }, /* Encrypted Header Encryption Key */ { { 0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0 }, { 0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2 } }, /* Key Generation Function */ nullptr, /* Decrypt Aes Xts Eternal Function */ nullptr, /* Encrypt Aes Xts Eternal Function */ nullptr, /* Decrypt Aes Ctr Function */ nullptr, /* Decrypt Aes Ctr External Function */ nullptr, /* Verify Sign1 Function */ nullptr, /* Plaintext Header Available */ false, /* Software Key Available */ true, }; } const ::ams::fssystem::NcaCryptoConfiguration *GetDefaultNcaCryptoConfiguration(bool prod) { return prod ? std::addressof(DefaultNcaCryptoConfigurationProd) : std::addressof(DefaultNcaCryptoConfigurationDev); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_program_registry_impl.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/fssrv_program_info.hpp" namespace ams::fssrv { namespace { constinit ProgramRegistryServiceImpl *g_impl = nullptr; } ProgramRegistryImpl::ProgramRegistryImpl() : m_process_id(os::InvalidProcessId.value) { /* ... */ } ProgramRegistryImpl::~ProgramRegistryImpl() { /* ... */ } void ProgramRegistryImpl::Initialize(ProgramRegistryServiceImpl *service) { /* Check pre-conditions. */ AMS_ASSERT(service != nullptr); AMS_ASSERT(g_impl == nullptr); /* Set the global service. */ g_impl = service; } Result ProgramRegistryImpl::RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const ams::sf::InBuffer &data, s64 data_size, const ams::sf::InBuffer &desc, s64 desc_size) { /* Check pre-conditions. */ AMS_ASSERT(g_impl != nullptr); /* Check that we're allowed to register. */ R_UNLESS(fssrv::impl::IsInitialProgram(m_process_id), fs::ResultPermissionDenied()); /* Check buffer sizes. */ R_UNLESS(data.GetSize() >= static_cast<size_t>(data_size), fs::ResultInvalidSize()); R_UNLESS(desc.GetSize() >= static_cast<size_t>(desc_size), fs::ResultInvalidSize()); /* Register the program. */ R_RETURN(g_impl->RegisterProgramInfo(process_id, program_id, storage_id, data.GetPointer(), data_size, desc.GetPointer(), desc_size)); } Result ProgramRegistryImpl::UnregisterProgram(u64 process_id) { /* Check pre-conditions. */ AMS_ASSERT(g_impl != nullptr); /* Check that we're allowed to register. */ R_UNLESS(fssrv::impl::IsInitialProgram(m_process_id), fs::ResultPermissionDenied()); /* Unregister the program. */ R_RETURN(g_impl->UnregisterProgramInfo(process_id)); } Result ProgramRegistryImpl::SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) { /* Set our process id. */ m_process_id = client_pid.GetValue().value; R_SUCCEED(); } Result ProgramRegistryImpl::SetEnabledProgramVerification(bool en) { /* TODO: How to deal with this backwards compat? */ AMS_ABORT("TODO: SetEnabledProgramVerification"); AMS_UNUSED(en); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_program_registry_service.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "impl/fssrv_program_info.hpp" #include "impl/fssrv_program_registry_manager.hpp" namespace ams::fssrv { Result ProgramRegistryServiceImpl::RegisterProgramInfo(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size) { R_RETURN(m_registry_manager->RegisterProgram(process_id, program_id, storage_id, data, data_size, desc, desc_size)); } Result ProgramRegistryServiceImpl::UnregisterProgramInfo(u64 process_id) { R_RETURN(m_registry_manager->UnregisterProgram(process_id)); } Result ProgramRegistryServiceImpl::ResetProgramIndexMapInfo(const fs::ProgramIndexMapInfo *infos, int count) { R_RETURN(m_index_map_info_manager->Reset(infos, count)); } Result ProgramRegistryServiceImpl::GetProgramInfo(std::shared_ptr<impl::ProgramInfo> *out, u64 process_id) { R_RETURN(m_registry_manager->GetProgramInfo(out, process_id)); } Result ProgramRegistryServiceImpl::GetProgramInfoByProgramId(std::shared_ptr<impl::ProgramInfo> *out, u64 program_id) { R_RETURN(m_registry_manager->GetProgramInfoByProgramId(out, program_id)); } size_t ProgramRegistryServiceImpl::GetProgramIndexMapInfoCount() { return m_index_map_info_manager->GetProgramCount(); } util::optional<fs::ProgramIndexMapInfo> ProgramRegistryServiceImpl::GetProgramIndexMapInfo(const ncm::ProgramId &program_id) { return m_index_map_info_manager->Get(program_id); } ncm::ProgramId ProgramRegistryServiceImpl::GetProgramIdByIndex(const ncm::ProgramId &program_id, u8 index) { return m_index_map_info_manager->GetProgramId(program_id, index); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_retry_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fssrv::impl { template<typename F> ALWAYS_INLINE Result RetryFinitelyForDataCorrupted(F f) { /* All official uses of this retry once, for two tries total. */ constexpr auto MaxTryCount = 2; /* Perform the operation, retrying on fs::ResultDataCorrupted. */ auto tries = 0; while (true) { /* Try to perform the operation. */ const auto rc = f(); /* If we should, retry. */ if (fs::ResultDataCorrupted::Includes(rc)) { if ((++tries) < MaxTryCount) { continue; } } /* Ensure the current attempt succeeded. */ R_TRY(rc); /* Return success. */ R_SUCCEED(); } } } ================================================ FILE: libraries/libstratosphere/source/fssrv/fssrv_storage_interface_adapter.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include <stratosphere/fssrv/fssrv_interface_adapters.hpp> #include "fssrv_retry_utility.hpp" namespace ams::fssrv::impl { Result StorageInterfaceAdapter::Read(s64 offset, const ams::sf::OutNonSecureBuffer &buffer, s64 size) { /* Check pre-conditions. */ R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); R_UNLESS(0 <= size, fs::ResultInvalidSize()); R_UNLESS(size <= static_cast<s64>(buffer.GetSize()), fs::ResultInvalidSize()); R_RETURN(RetryFinitelyForDataCorrupted([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_storage->Read(offset, buffer.GetPointer(), size)); })); } Result StorageInterfaceAdapter::Write(s64 offset, const ams::sf::InNonSecureBuffer &buffer, s64 size) { /* Check pre-conditions. */ R_UNLESS(0 <= offset, fs::ResultInvalidOffset()); R_UNLESS(0 <= size, fs::ResultInvalidSize()); R_UNLESS(size <= static_cast<s64>(buffer.GetSize()), fs::ResultInvalidSize()); /* Temporarily increase our thread's priority. */ fssystem::ScopedThreadPriorityChangerByAccessPriority cp(fssystem::ScopedThreadPriorityChangerByAccessPriority::AccessMode::Write); R_RETURN(m_base_storage->Write(offset, buffer.GetPointer(), size)); } Result StorageInterfaceAdapter::Flush() { R_RETURN(m_base_storage->Flush()); } Result StorageInterfaceAdapter::SetSize(s64 size) { R_UNLESS(size >= 0, fs::ResultInvalidSize()); R_RETURN(m_base_storage->SetSize(size)); } Result StorageInterfaceAdapter::GetSize(ams::sf::Out<s64> out) { R_RETURN(m_base_storage->GetSize(out.GetPointer())); } Result StorageInterfaceAdapter::OperateRange(ams::sf::Out<fs::StorageQueryRangeInfo> out, s32 op_id, s64 offset, s64 size) { /* N includes this redundant check, so we will too. */ R_UNLESS(out.GetPointer() != nullptr, fs::ResultNullptrArgument()); /* Clear the range info. */ out->Clear(); if (op_id == static_cast<s32>(fs::OperationId::QueryRange)) { fs::FileQueryRangeInfo info; R_TRY(m_base_storage->OperateRange(std::addressof(info), sizeof(info), fs::OperationId::QueryRange, offset, size, nullptr, 0)); out->Merge(info); } else if (op_id == static_cast<s32>(fs::OperationId::Invalidate)) { R_TRY(m_base_storage->OperateRange(nullptr, 0, fs::OperationId::Invalidate, offset, size, nullptr, 0)); } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_allocator_for_service_framework.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fssrv::impl { class AllocatorForServiceFramework { public: using Policy = ams::sf::StatelessAllocationPolicy<AllocatorForServiceFramework>; void *Allocate(size_t size) { return fs::impl::Allocate(size); } void Deallocate(void *ptr, size_t size) { return fs::impl::Deallocate(ptr, size); } }; using FileSystemObjectFactory = ams::sf::ObjectFactory<AllocatorForServiceFramework::Policy>; } ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_file_system_proxy_service_object.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fssrv_allocator_for_service_framework.hpp" namespace ams::fssrv::impl { namespace { using FileSystemProxyServiceFactory = ams::sf::ObjectFactory<AllocatorForServiceFramework::Policy>; using ProgramRegistryServiceFactory = ams::sf::ObjectFactory<AllocatorForServiceFramework::Policy>; using FileSystemProxyForLoaderServiceFactory = ams::sf::ObjectFactory<AllocatorForServiceFramework::Policy>; } ams::sf::EmplacedRef<fssrv::sf::IFileSystemProxy, fssrv::FileSystemProxyImpl> GetFileSystemProxyServiceObject() { return FileSystemProxyServiceFactory::CreateSharedEmplaced<fssrv::sf::IFileSystemProxy, fssrv::FileSystemProxyImpl>(); } ams::sf::SharedPointer<fssrv::sf::IProgramRegistry> GetProgramRegistryServiceObject() { return ProgramRegistryServiceFactory::CreateSharedEmplaced<fssrv::sf::IProgramRegistry, fssrv::ProgramRegistryImpl>(); } ams::sf::SharedPointer<fssrv::sf::IProgramRegistry> GetInvalidProgramRegistryServiceObject() { return ProgramRegistryServiceFactory::CreateSharedEmplaced<fssrv::sf::IProgramRegistry, fssrv::InvalidProgramRegistryImpl>(); } ams::sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject() { return FileSystemProxyForLoaderServiceFactory ::CreateSharedEmplaced<fssrv::sf::IFileSystemProxyForLoader, fssrv::FileSystemProxyImpl>(); } ams::sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetInvalidFileSystemProxyForLoaderServiceObject() { return FileSystemProxyForLoaderServiceFactory ::CreateSharedEmplaced<fssrv::sf::IFileSystemProxyForLoader, fssrv::InvalidFileSystemProxyImplForLoader>(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_program_registry_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fssrv_program_registry_manager.hpp" namespace ams::fssrv::impl { Result ProgramRegistryManager::RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size) { /* Allocate a new node. */ std::unique_ptr<ProgramInfoNode> new_node(new ProgramInfoNode()); R_UNLESS(new_node != nullptr, fs::ResultAllocationMemoryFailedInProgramRegistryManagerA()); /* Create a new program info. */ { /* Allocate the new info. */ auto new_info = fssystem::AllocateShared<ProgramInfo>(process_id, program_id, storage_id, data, data_size, desc, desc_size); R_UNLESS(new_info != nullptr, fs::ResultAllocationMemoryFailedInProgramRegistryManagerA()); /* Set the info in the node. */ new_node->program_info = std::move(new_info); } /* Acquire exclusive access to the registry. */ std::scoped_lock lk(m_mutex); /* Check that the process isn't already in the registry. */ for (const auto &node : m_program_info_list) { R_UNLESS(!node.program_info->Contains(process_id), fs::ResultInvalidArgument()); } /* Add the node to the registry. */ m_program_info_list.push_back(*new_node.release()); R_SUCCEED(); } Result ProgramRegistryManager::UnregisterProgram(u64 process_id) { /* Acquire exclusive access to the registry. */ std::scoped_lock lk(m_mutex); /* Try to find and remove the process's node. */ for (auto &node : m_program_info_list) { if (node.program_info->Contains(process_id)) { m_program_info_list.erase(m_program_info_list.iterator_to(node)); delete std::addressof(node); R_SUCCEED(); } } /* We couldn't find/unregister the process's node. */ R_THROW(fs::ResultInvalidArgument()); } Result ProgramRegistryManager::GetProgramInfo(std::shared_ptr<ProgramInfo> *out, u64 process_id) { /* Acquire exclusive access to the registry. */ std::scoped_lock lk(m_mutex); /* Check if we're getting permissions for an initial program. */ if (IsInitialProgram(process_id)) { *out = ProgramInfo::GetProgramInfoForInitialProcess(); R_SUCCEED(); } /* Find a matching node. */ for (const auto &node : m_program_info_list) { if (node.program_info->Contains(process_id)) { *out = node.program_info; R_SUCCEED(); } } /* We didn't find the program info. */ R_THROW(fs::ResultProgramInfoNotFound()); } Result ProgramRegistryManager::GetProgramInfoByProgramId(std::shared_ptr<ProgramInfo> *out, u64 program_id) { /* Acquire exclusive access to the registry. */ std::scoped_lock lk(m_mutex); /* Find a matching node. */ for (const auto &node : m_program_info_list) { if (node.program_info->GetProgramIdValue() == program_id) { *out = node.program_info; R_SUCCEED(); } } /* We didn't find the program info. */ R_THROW(fs::ResultProgramInfoNotFound()); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_program_registry_manager.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> #include "fssrv_program_info.hpp" namespace ams::fssrv::impl { class ProgramRegistryManager { NON_COPYABLE(ProgramRegistryManager); NON_MOVEABLE(ProgramRegistryManager); private: using ProgramInfoList = util::IntrusiveListBaseTraits<ProgramInfoNode>::ListType; private: ProgramInfoList m_program_info_list{}; os::SdkMutex m_mutex{}; public: constexpr ProgramRegistryManager() = default; Result RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size); Result UnregisterProgram(u64 process_id); Result GetProgramInfo(std::shared_ptr<ProgramInfo> *out, u64 process_id); Result GetProgramInfoByProgramId(std::shared_ptr<ProgramInfo> *out, u64 program_id); }; } AMS_FSSYSTEM_ENABLE_PIMPL(::ams::fssrv::impl::ProgramRegistryManager); ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_utility.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fssrv_utility.hpp" #if defined(ATMOSPHERE_OS_WINDOWS) #include <stratosphere/windows.hpp> #elif defined(ATMOSPHERE_OS_LINUX) #include <unistd.h> #elif defined(ATMOSPHERE_OS_MACOS) #include <unistd.h> #include <mach-o/dyld.h> #include <sys/param.h> #endif namespace ams::fssystem { class PathOnExecutionDirectory { private: char m_path[fs::EntryNameLengthMax + 1]; public: PathOnExecutionDirectory() { #if defined(ATMOSPHERE_OS_WINDOWS) { /* Get the module file name. */ wchar_t module_file_name[fs::EntryNameLengthMax + 1]; if (::GetModuleFileNameW(0, module_file_name, util::size(module_file_name)) == 0) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA()); } /* Split the path. */ wchar_t drive_name[3]; wchar_t dir_name[fs::EntryNameLengthMax + 1]; ::_wsplitpath_s(module_file_name, drive_name, util::size(drive_name), dir_name, util::size(dir_name), nullptr, 0, nullptr, 0); /* Print the drive and directory. */ wchar_t path[fs::EntryNameLengthMax + 1]; ::swprintf_s(path, util::size(path), L"%s%s", drive_name, dir_name); /* Convert to utf-8. */ const auto res = ::WideCharToMultiByte(CP_UTF8, 0, path, -1, m_path, util::size(m_path), nullptr, nullptr); if (res == 0) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } } #elif defined(ATMOSPHERE_OS_LINUX) { char full_path[PATH_MAX] = {}; if (::readlink("/proc/self/exe", full_path, sizeof(full_path)) == -1) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA()); } const int len = std::strlen(full_path); if (len >= static_cast<int>(sizeof(m_path))) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } std::memcpy(m_path, full_path, len + 1); for (int i = len - 1; i >= 0; --i) { if (m_path[i] == '/') { m_path[i + 1] = 0; break; } } } #elif defined(ATMOSPHERE_OS_MACOS) { char full_path[MAXPATHLEN] = {}; uint32_t size = sizeof(full_path); if (_NSGetExecutablePath(full_path, std::addressof(size)) != 0) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryA()); } const int len = std::strlen(full_path); if (len >= static_cast<int>(sizeof(m_path))) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } std::memcpy(m_path, full_path, len + 1); for (int i = len - 1; i >= 0; --i) { if (m_path[i] == '/') { m_path[i + 1] = 0; break; } } } #else AMS_ABORT("TODO: Unknown OS for PathOnExecutionDirectory"); #endif const auto len = std::strlen(m_path); if (m_path[len - 1] != '/' && m_path[len - 1] != '\\') { if (len + 1 >= sizeof(m_path)) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } m_path[len] = '/'; m_path[len + 1] = 0; } } const char *Get() const { return m_path; } }; class PathOnWorkingDirectory { private: char m_path[fs::EntryNameLengthMax + 1]; public: PathOnWorkingDirectory() { #if defined(ATMOSPHERE_OS_WINDOWS) { /* Get the current directory. */ wchar_t current_directory[fs::EntryNameLengthMax + 1]; if (::GetCurrentDirectoryW(util::size(current_directory), current_directory) == 0) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } /* Convert to utf-8. */ const auto res = ::WideCharToMultiByte(CP_UTF8, 0, current_directory, -1, m_path, util::size(m_path), nullptr, nullptr); if (res == 0) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } } #elif defined(ATMOSPHERE_OS_LINUX) { char full_path[PATH_MAX] = {}; if (::getcwd(full_path, sizeof(full_path)) == nullptr) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } const int len = std::strlen(full_path); if (len >= static_cast<int>(sizeof(m_path))) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } std::memcpy(m_path, full_path, len + 1); } #elif defined(ATMOSPHERE_OS_MACOS) { char full_path[MAXPATHLEN] = {}; if (::getcwd(full_path, sizeof(full_path)) == nullptr) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } const int len = std::strlen(full_path); if (len >= static_cast<int>(sizeof(m_path))) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } std::memcpy(m_path, full_path, len + 1); } #else AMS_ABORT("TODO: Unknown OS for PathOnWorkingDirectory"); #endif const auto len = std::strlen(m_path); if (m_path[len - 1] != '/' && m_path[len - 1] != '\\') { if (len + 1 >= sizeof(m_path)) { AMS_FS_R_ABORT_UNLESS(fs::ResultUnexpectedInPathOnExecutionDirectoryB()); } m_path[len] = '/'; m_path[len + 1] = 0; } } const char *Get() const { return m_path; } }; } namespace ams::fssrv::impl { const char *GetExecutionDirectoryPath() { AMS_FUNCTION_LOCAL_STATIC(fssystem::PathOnExecutionDirectory, s_path_on_execution_directory); return s_path_on_execution_directory.Get(); } const char *GetWorkingDirectoryPath() { AMS_FUNCTION_LOCAL_STATIC(fssystem::PathOnWorkingDirectory, s_path_on_working_directory); return s_path_on_working_directory.Get(); } } ================================================ FILE: libraries/libstratosphere/source/fssrv/impl/fssrv_utility.hpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <stratosphere.hpp> namespace ams::fssrv::impl { const char *GetExecutionDirectoryPath(); const char *GetWorkingDirectoryPath(); } ================================================ FILE: libraries/libstratosphere/source/fssystem/buffers/fssystem_buffer_manager_utils.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem::buffers { namespace { /* TODO: os::SdkThreadLocalStorage g_buffer_manager_context_tls_slot; */ class ThreadLocalStorageWrapper { private: os::TlsSlot m_tls_slot; public: ThreadLocalStorageWrapper() { R_ABORT_UNLESS(os::AllocateTlsSlot(std::addressof(m_tls_slot), nullptr)); } ~ThreadLocalStorageWrapper() { os::FreeTlsSlot(m_tls_slot); } void SetValue(uintptr_t value) { os::SetTlsValue(m_tls_slot, value); } uintptr_t GetValue() const { return os::GetTlsValue(m_tls_slot); } os::TlsSlot GetTlsSlot() const { return m_tls_slot; } } g_buffer_manager_context_tls_slot; } void RegisterBufferManagerContext(const BufferManagerContext *context) { g_buffer_manager_context_tls_slot.SetValue(reinterpret_cast<uintptr_t>(context)); } BufferManagerContext *GetBufferManagerContext() { return reinterpret_cast<BufferManagerContext *>(g_buffer_manager_context_tls_slot.GetValue()); } void EnableBlockingBufferManagerAllocation() { if (auto context = GetBufferManagerContext(); context != nullptr) { context->SetNeedBlocking(true); } } } ================================================ FILE: libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buddy_heap.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { FileSystemBuddyHeap::PageEntry *FileSystemBuddyHeap::PageList::PopFront() { AMS_ASSERT(m_entry_count > 0); /* Get the first entry. */ auto page_entry = m_first_page_entry; /* Advance our list. */ m_first_page_entry = page_entry->next; page_entry->next = nullptr; /* Decrement our count. */ --m_entry_count; AMS_ASSERT(m_entry_count >= 0); /* If this was our last page, clear our last entry. */ if (m_entry_count == 0) { m_last_page_entry = nullptr; } return page_entry; } void FileSystemBuddyHeap::PageList::PushBack(PageEntry *page_entry) { AMS_ASSERT(page_entry != nullptr); /* If we're empty, we want to set the first page entry. */ if (this->IsEmpty()) { m_first_page_entry = page_entry; } else { /* We're not empty, so push the page to the back. */ AMS_ASSERT(m_last_page_entry != page_entry); m_last_page_entry->next = page_entry; } /* Set our last page entry to be this one, and link it to the list. */ m_last_page_entry = page_entry; m_last_page_entry->next = nullptr; /* Increment our entry count. */ ++m_entry_count; AMS_ASSERT(m_entry_count > 0); } bool FileSystemBuddyHeap::PageList::Remove(PageEntry *page_entry) { AMS_ASSERT(page_entry != nullptr); /* If we're empty, we can't remove the page list. */ if (this->IsEmpty()) { return false; } /* We're going to loop over all pages to find this one, then unlink it. */ PageEntry *prev_entry = nullptr; PageEntry *cur_entry = m_first_page_entry; while (true) { /* Check if we found the page. */ if (cur_entry == page_entry) { if (cur_entry == m_first_page_entry) { /* If it's the first page, we just set our first. */ m_first_page_entry = cur_entry->next; } else if (cur_entry == m_last_page_entry) { /* If it's the last page, we set our last. */ m_last_page_entry = prev_entry; m_last_page_entry->next = nullptr; } else { /* If it's in the middle, we just unlink. */ prev_entry->next = cur_entry->next; } /* Unlink this entry's next. */ cur_entry->next = nullptr; /* Update our entry count. */ --m_entry_count; AMS_ASSERT(m_entry_count >= 0); return true; } /* If we have no next page, we can't remove. */ if (cur_entry->next == nullptr) { return false; } /* Advance to the next item in the list. */ prev_entry = cur_entry; cur_entry = cur_entry->next; } } Result FileSystemBuddyHeap::Initialize(uintptr_t address, size_t size, size_t block_size, s32 order_max) { /* Ensure our preconditions. */ AMS_ASSERT(m_free_lists == nullptr); AMS_ASSERT(address != 0); AMS_ASSERT(util::IsAligned(address, BufferAlignment)); AMS_ASSERT(block_size >= BlockSizeMin); AMS_ASSERT(util::IsPowerOfTwo(block_size)); AMS_ASSERT(size >= block_size); AMS_ASSERT(order_max > 0); AMS_ASSERT(order_max < OrderUpperLimit); /* Set up our basic member variables */ m_block_size = block_size; m_order_max = order_max; m_heap_start = address; m_heap_size = (size / m_block_size) * m_block_size; m_total_free_size = 0; /* Determine page sizes. */ const auto max_page_size = m_block_size << m_order_max; const auto max_page_count = util::AlignUp(m_heap_size, max_page_size) / max_page_size; AMS_ASSERT(max_page_count > 0); /* Setup the free lists. */ if (m_external_free_lists != nullptr) { AMS_ASSERT(m_internal_free_lists == nullptr); m_free_lists = m_external_free_lists; } else { m_internal_free_lists.reset(new PageList[m_order_max + 1]); m_free_lists = m_internal_free_lists.get(); R_UNLESS(m_free_lists != nullptr, fs::ResultAllocationMemoryFailedInFileSystemBuddyHeapA()); } /* All but the last page region should go to the max order. */ for (size_t i = 0; i < max_page_count - 1; i++) { auto page_entry = this->GetPageEntryFromAddress(m_heap_start + i * max_page_size); m_free_lists[m_order_max].PushBack(page_entry); } m_total_free_size += m_free_lists[m_order_max].GetSize() * this->GetBytesFromOrder(m_order_max); /* Allocate remaining space to smaller orders as possible. */ { auto remaining = m_heap_size - (max_page_count - 1) * max_page_size; auto cur_address = m_heap_start + (max_page_count - 1) * max_page_size; AMS_ASSERT(util::IsAligned(remaining, m_block_size)); do { /* Determine what order we can use. */ auto order = GetOrderFromBytes(remaining + 1); if (order < 0) { AMS_ASSERT(GetOrderFromBytes(remaining) == m_order_max); order = m_order_max + 1; } AMS_ASSERT(0 < order); AMS_ASSERT(order <= m_order_max + 1); /* Add to the correct free list. */ m_free_lists[order - 1].PushBack(GetPageEntryFromAddress(cur_address)); m_total_free_size += GetBytesFromOrder(order - 1); /* Move on to the next order. */ const auto page_size = GetBytesFromOrder(order - 1); cur_address += page_size; remaining -= page_size; } while (m_block_size <= remaining); } R_SUCCEED(); } void FileSystemBuddyHeap::Finalize() { AMS_ASSERT(m_free_lists != nullptr); m_free_lists = nullptr; m_external_free_lists = nullptr; m_internal_free_lists.reset(); } void *FileSystemBuddyHeap::AllocateByOrder(s32 order) { AMS_ASSERT(m_free_lists != nullptr); AMS_ASSERT(order >= 0); AMS_ASSERT(order <= this->GetOrderMax()); /* Get the page entry. */ if (const auto page_entry = this->GetFreePageEntry(order); page_entry != nullptr) { /* Ensure we're allocating an unlinked page. */ AMS_ASSERT(page_entry->next == nullptr); /* Return the address for this entry. */ return reinterpret_cast<void *>(this->GetAddressFromPageEntry(*page_entry)); } else { return nullptr; } } void FileSystemBuddyHeap::Free(void *ptr, s32 order) { AMS_ASSERT(m_free_lists != nullptr); AMS_ASSERT(order >= 0); AMS_ASSERT(order <= this->GetOrderMax()); /* Allow free(nullptr) */ if (ptr == nullptr) { return; } /* Ensure the pointer is block aligned. */ AMS_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(ptr) - m_heap_start, this->GetBlockSize())); /* Get the page entry. */ auto page_entry = this->GetPageEntryFromAddress(reinterpret_cast<uintptr_t>(ptr)); AMS_ASSERT(this->IsAlignedToOrder(page_entry, order)); /* Reinsert into the free lists. */ this->JoinBuddies(page_entry, order); } size_t FileSystemBuddyHeap::GetTotalFreeSize() const { AMS_ASSERT(m_free_lists != nullptr); return m_total_free_size; } size_t FileSystemBuddyHeap::GetAllocatableSizeMax() const { AMS_ASSERT(m_free_lists != nullptr); /* The maximum allocatable size is a chunk from the biggest non-empty order. */ for (s32 order = this->GetOrderMax(); order >= 0; --order) { if (!m_free_lists[order].IsEmpty()) { return this->GetBytesFromOrder(order); } } /* If all orders are empty, then we can't allocate anything. */ return 0; } void FileSystemBuddyHeap::Dump() const { AMS_ASSERT(m_free_lists != nullptr); /* TODO: Support logging metrics. */ } void FileSystemBuddyHeap::DivideBuddies(PageEntry *page_entry, s32 required_order, s32 chosen_order) { AMS_ASSERT(page_entry != nullptr); AMS_ASSERT(required_order >= 0); AMS_ASSERT(chosen_order >= required_order); AMS_ASSERT(chosen_order <= this->GetOrderMax()); /* Start at the end of the entry. */ auto address = this->GetAddressFromPageEntry(*page_entry) + this->GetBytesFromOrder(chosen_order); for (auto order = chosen_order; order > required_order; --order) { /* For each order, subtract that order's size from the address to get the start of a new block. */ address -= this->GetBytesFromOrder(order - 1); auto divided_entry = this->GetPageEntryFromAddress(address); /* Push back to the list. */ m_free_lists[order - 1].PushBack(divided_entry); m_total_free_size += this->GetBytesFromOrder(order - 1); } } void FileSystemBuddyHeap::JoinBuddies(PageEntry *page_entry, s32 order) { AMS_ASSERT(page_entry != nullptr); AMS_ASSERT(order >= 0); AMS_ASSERT(order <= this->GetOrderMax()); auto cur_entry = page_entry; auto cur_order = order; while (cur_order < this->GetOrderMax()) { /* Get the buddy page. */ const auto buddy_entry = this->GetBuddy(cur_entry, cur_order); /* Check whether the buddy is in the relevant free list. */ if (buddy_entry != nullptr && m_free_lists[cur_order].Remove(buddy_entry)) { m_total_free_size -= GetBytesFromOrder(cur_order); /* Ensure we coalesce with the correct buddy when page is aligned */ if (!this->IsAlignedToOrder(cur_entry, cur_order + 1)) { cur_entry = buddy_entry; } ++cur_order; } else { /* Buddy isn't in the free list, so we can't coalesce. */ break; } } /* Insert the coalesced entry into the free list. */ m_free_lists[cur_order].PushBack(cur_entry); m_total_free_size += this->GetBytesFromOrder(cur_order); } FileSystemBuddyHeap::PageEntry *FileSystemBuddyHeap::GetBuddy(PageEntry *page_entry, s32 order) { AMS_ASSERT(page_entry != nullptr); AMS_ASSERT(order >= 0); AMS_ASSERT(order <= this->GetOrderMax()); const auto address = this->GetAddressFromPageEntry(*page_entry); const auto offset = this->GetBlockCountFromOrder(order) * this->GetBlockSize(); if (this->IsAlignedToOrder(page_entry, order + 1)) { /* If the page entry is aligned to the next order, return the buddy block to the right of the current entry. */ return (address + offset < m_heap_start + m_heap_size) ? GetPageEntryFromAddress(address + offset) : nullptr; } else { /* If the page entry isn't aligned, return the buddy block to the left of the current entry. */ return (m_heap_start <= address - offset) ? GetPageEntryFromAddress(address - offset) : nullptr; } } FileSystemBuddyHeap::PageEntry *FileSystemBuddyHeap::GetFreePageEntry(s32 order) { AMS_ASSERT(order >= 0); AMS_ASSERT(order <= this->GetOrderMax()); /* Try orders from low to high until we find a free page entry. */ for (auto cur_order = order; cur_order <= this->GetOrderMax(); cur_order++) { if (auto &free_list = m_free_lists[cur_order]; !free_list.IsEmpty()) { /* The current list isn't empty, so grab an entry from it. */ PageEntry *page_entry = free_list.PopFront(); AMS_ASSERT(page_entry != nullptr); /* Update size bookkeeping. */ m_total_free_size -= GetBytesFromOrder(cur_order); /* If we allocated more memory than needed, free the unneeded portion. */ this->DivideBuddies(page_entry, order, cur_order); AMS_ASSERT(page_entry->next == nullptr); /* Return the newly-divided entry. */ return page_entry; } } /* We failed to find a free page. */ return nullptr; } s32 FileSystemBuddyHeap::GetOrderFromBlockCount(s32 block_count) const { AMS_ASSERT(block_count >= 0); /* Return the first order with a big enough block count. */ for (s32 order = 0; order <= this->GetOrderMax(); ++order) { if (block_count <= this->GetBlockCountFromOrder(order)) { return order; } } return -1; } } ================================================ FILE: libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buffer_manager.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { Result FileSystemBufferManager::CacheHandleTable::Initialize(s32 max_cache_count) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries == nullptr); AMS_ASSERT(m_internal_entry_buffer == nullptr); /* If we don't have an external buffer, try to allocate an internal one. */ if (m_external_entry_buffer == nullptr) { m_entry_buffer_size = sizeof(Entry) * max_cache_count; m_internal_entry_buffer = fs::impl::MakeUnique<char[]>(m_entry_buffer_size); } /* We need to have at least one entry buffer. */ R_UNLESS(m_internal_entry_buffer != nullptr || m_external_entry_buffer != nullptr, fs::ResultAllocationMemoryFailedInFileSystemBufferManagerA()); /* Set entries. */ m_entries = reinterpret_cast<Entry *>(m_external_entry_buffer != nullptr ? m_external_entry_buffer : m_internal_entry_buffer.get()); m_entry_count = 0; m_entry_count_max = max_cache_count; AMS_ASSERT(m_entries != nullptr); m_cache_count_min = max_cache_count / 16; m_cache_size_min = m_cache_count_min * 0x100; R_SUCCEED(); } void FileSystemBufferManager::CacheHandleTable::Finalize() { if (m_entries != nullptr) { AMS_ASSERT(m_entry_count == 0); if (m_external_attr_info_buffer == nullptr) { auto it = m_attr_list.begin(); while (it != m_attr_list.end()) { const auto attr_info = std::addressof(*it); it = m_attr_list.erase(it); delete attr_info; } } m_internal_entry_buffer.reset(); m_external_entry_buffer = nullptr; m_entry_buffer_size = 0; m_entries = nullptr; m_total_cache_size = 0; } } bool FileSystemBufferManager::CacheHandleTable::Register(CacheHandle *out, uintptr_t address, size_t size, const BufferAttribute &attr) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); AMS_ASSERT(out != nullptr); /* Get the entry. */ auto entry = this->AcquireEntry(address, size, attr); /* If we don't have an entry, we can't register. */ if (entry == nullptr) { return false; } /* Get the attr info. If we have one, increment. */ if (const auto attr_info = this->FindAttrInfo(attr); attr_info != nullptr) { attr_info->IncrementCacheCount(); attr_info->AddCacheSize(size); } else { /* Make a new attr info and add it to the list. */ AttrInfo *new_info = nullptr; if (m_external_attr_info_buffer == nullptr) { new_info = new AttrInfo(attr.GetLevel(), 1, size); } else if (0 <= attr.GetLevel() && attr.GetLevel() < m_external_attr_info_count) { void *buffer = m_external_attr_info_buffer + attr.GetLevel() * sizeof(AttrInfo); new_info = std::construct_at(reinterpret_cast<AttrInfo *>(buffer), attr.GetLevel(), 1, size); } /* If we failed to make a new attr info, we can't register. */ if (new_info == nullptr) { this->ReleaseEntry(entry); return false; } m_attr_list.push_back(*new_info); } m_total_cache_size += size; *out = entry->GetHandle(); return true; } bool FileSystemBufferManager::CacheHandleTable::Unregister(uintptr_t *out_address, size_t *out_size, CacheHandle handle) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); AMS_ASSERT(out_address != nullptr); AMS_ASSERT(out_size != nullptr); /* Find the lower bound for the entry. */ const auto entry = std::lower_bound(m_entries, m_entries + m_entry_count, handle, [](const Entry &entry, CacheHandle handle) { return entry.GetHandle() < handle; }); /* If the entry is a match, unregister it. */ if (entry != m_entries + m_entry_count && entry->GetHandle() == handle) { this->UnregisterCore(out_address, out_size, entry); return true; } else { return false; } } bool FileSystemBufferManager::CacheHandleTable::UnregisterOldest(uintptr_t *out_address, size_t *out_size, const BufferAttribute &attr, size_t required_size) { AMS_UNUSED(attr, required_size); /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); AMS_ASSERT(out_address != nullptr); AMS_ASSERT(out_size != nullptr); /* If we have no entries, we can't unregister any. */ if (m_entry_count == 0) { return false; } const auto CanUnregister = [this](const Entry &entry) { const auto attr_info = this->FindAttrInfo(entry.GetBufferAttribute()); AMS_ASSERT(attr_info != nullptr); const auto ccm = this->GetCacheCountMin(entry.GetBufferAttribute()); const auto csm = this->GetCacheSizeMin(entry.GetBufferAttribute()); return ccm < attr_info->GetCacheCount() && csm + entry.GetSize() <= attr_info->GetCacheSize(); }; /* Find an entry, falling back to the first entry. */ auto entry = std::find_if(m_entries, m_entries + m_entry_count, CanUnregister); if (entry == m_entries + m_entry_count) { entry = m_entries; } AMS_ASSERT(entry != m_entries + m_entry_count); this->UnregisterCore(out_address, out_size, entry); return true; } void FileSystemBufferManager::CacheHandleTable::UnregisterCore(uintptr_t *out_address, size_t *out_size, Entry *entry) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); AMS_ASSERT(out_address != nullptr); AMS_ASSERT(out_size != nullptr); AMS_ASSERT(entry != nullptr); /* Get the attribute info. */ const auto attr_info = this->FindAttrInfo(entry->GetBufferAttribute()); AMS_ASSERT(attr_info != nullptr); AMS_ASSERT(attr_info->GetCacheCount() > 0); AMS_ASSERT(attr_info->GetCacheSize() >= entry->GetSize()); /* Release from the attr info. */ attr_info->DecrementCacheCount(); attr_info->SubtractCacheSize(entry->GetSize()); /* Release from cached size. */ AMS_ASSERT(m_total_cache_size >= entry->GetSize()); m_total_cache_size -= entry->GetSize(); /* Release the entry. */ *out_address = entry->GetAddress(); *out_size = entry->GetSize(); this->ReleaseEntry(entry); } FileSystemBufferManager::CacheHandle FileSystemBufferManager::CacheHandleTable::PublishCacheHandle() { AMS_ASSERT(m_entries != nullptr); return (++m_current_handle); } size_t FileSystemBufferManager::CacheHandleTable::GetTotalCacheSize() const { return m_total_cache_size; } FileSystemBufferManager::CacheHandleTable::Entry *FileSystemBufferManager::CacheHandleTable::AcquireEntry(uintptr_t address, size_t size, const BufferAttribute &attr) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); Entry *entry = nullptr; if (m_entry_count < m_entry_count_max) { entry = m_entries + m_entry_count; entry->Initialize(this->PublishCacheHandle(), address, size, attr); ++m_entry_count; AMS_ASSERT(m_entry_count == 1 || (entry-1)->GetHandle() < entry->GetHandle()); } return entry; } void FileSystemBufferManager::CacheHandleTable::ReleaseEntry(Entry *entry) { /* Validate pre-conditions. */ AMS_ASSERT(m_entries != nullptr); AMS_ASSERT(entry != nullptr); /* Ensure the entry is valid. */ { const auto entry_buffer = m_external_entry_buffer != nullptr ? m_external_entry_buffer : m_internal_entry_buffer.get(); AMS_ASSERT(static_cast<void *>(entry_buffer) <= static_cast<void *>(entry)); AMS_ASSERT(static_cast<void *>(entry) < static_cast<void *>(entry_buffer + m_entry_buffer_size)); AMS_UNUSED(entry_buffer); } /* Copy the entries back by one. */ std::memmove(entry, entry + 1, sizeof(Entry) * (m_entry_count - ((entry + 1) - m_entries))); /* Decrement our entry count. */ --m_entry_count; } FileSystemBufferManager::CacheHandleTable::AttrInfo *FileSystemBufferManager::CacheHandleTable::FindAttrInfo(const BufferAttribute &attr) { const auto it = std::find_if(m_attr_list.begin(), m_attr_list.end(), [&attr](const AttrInfo &info) { return attr.GetLevel() == info.GetLevel(); }); return it != m_attr_list.end() ? std::addressof(*it) : nullptr; } const fs::IBufferManager::MemoryRange FileSystemBufferManager::AllocateBufferImpl(size_t size, const BufferAttribute &attr) { /* Get/sanity check the required order. */ fs::IBufferManager::MemoryRange range = {}; const auto order = m_buddy_heap.GetOrderFromBytes(size); AMS_ASSERT(order >= 0); while (true) { /* Try to allocate a buffer at the desired order. */ if (auto address = m_buddy_heap.AllocateByOrder(order); address != 0) { /* Check that we allocated enough. */ const auto allocated_size = m_buddy_heap.GetBytesFromOrder(order); AMS_ASSERT(size <= allocated_size); /* Set up the range extents. */ range.first = reinterpret_cast<uintptr_t>(address); range.second = allocated_size; /* Update our peak tracking variables. */ const size_t free_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = std::min(m_peak_free_size, free_size); const size_t total_allocatable_size = free_size + m_cache_handle_table.GetTotalCacheSize(); m_peak_total_allocatable_size = std::min(m_peak_total_allocatable_size, total_allocatable_size); break; } /* We failed, to we'll need to deallocate something and retry. */ ++m_retried_count; /* Deallocate a buffer. */ uintptr_t deallocate_address = 0; size_t deallocate_size = 0; if (m_cache_handle_table.UnregisterOldest(std::addressof(deallocate_address), std::addressof(deallocate_size), attr, size)) { this->DeallocateBufferImpl(deallocate_address, deallocate_size); } else { break; } } /* Return the range we allocated. */ return range; } void FileSystemBufferManager::DeallocateBufferImpl(uintptr_t address, size_t size) { AMS_ASSERT(util::IsPowerOfTwo(size)); m_buddy_heap.Free(reinterpret_cast<void *>(address), m_buddy_heap.GetOrderFromBytes(size)); } FileSystemBufferManager::CacheHandle FileSystemBufferManager::RegisterCacheImpl(uintptr_t address, size_t size, const BufferAttribute &attr) { CacheHandle handle = 0; while (true) { /* Try to register the handle. */ if (m_cache_handle_table.Register(std::addressof(handle), address, size, attr)) { break; } /* Deallocate a buffer. */ uintptr_t deallocate_address = 0; size_t deallocate_size = 0; ++m_retried_count; if (m_cache_handle_table.UnregisterOldest(std::addressof(deallocate_address), std::addressof(deallocate_size), attr)) { this->DeallocateBufferImpl(deallocate_address, deallocate_size); } else { this->DeallocateBufferImpl(address, size); handle = m_cache_handle_table.PublishCacheHandle(); break; } } return handle; } const fs::IBufferManager::MemoryRange FileSystemBufferManager::AcquireCacheImpl(CacheHandle handle) { fs::IBufferManager::MemoryRange range = {}; if (m_cache_handle_table.Unregister(std::addressof(range.first), std::addressof(range.second), handle)) { const size_t total_allocatable_size = m_buddy_heap.GetTotalFreeSize() + m_cache_handle_table.GetTotalCacheSize(); m_peak_total_allocatable_size = std::min(m_peak_total_allocatable_size, total_allocatable_size); } else { range.first = 0; range.second = 0; } return range; } size_t FileSystemBufferManager::GetFreeSizeImpl() const { return m_buddy_heap.GetTotalFreeSize(); } size_t FileSystemBufferManager::GetTotalAllocatableSizeImpl() const { return this->GetFreeSizeImpl() + m_cache_handle_table.GetTotalCacheSize(); } size_t FileSystemBufferManager::GetFreeSizePeakImpl() const { return m_peak_free_size; } size_t FileSystemBufferManager::GetTotalAllocatableSizePeakImpl() const { return m_peak_total_allocatable_size; } size_t FileSystemBufferManager::GetRetriedCountImpl() const { return m_retried_count; } void FileSystemBufferManager::ClearPeakImpl() { m_peak_free_size = this->GetFreeSizeImpl(); m_peak_total_allocatable_size = this->GetTotalAllocatableSizeImpl(); m_retried_count = 0; } const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAllocateBuffer(size_t size, const BufferAttribute &attr) { std::scoped_lock lk(m_mutex); return this->AllocateBufferImpl(size, attr); } void FileSystemBufferManager::DoDeallocateBuffer(uintptr_t address, size_t size) { std::scoped_lock lk(m_mutex); return this->DeallocateBufferImpl(address, size); } FileSystemBufferManager::CacheHandle FileSystemBufferManager::DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) { std::scoped_lock lk(m_mutex); return this->RegisterCacheImpl(address, size, attr); } const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAcquireCache(CacheHandle handle) { std::scoped_lock lk(m_mutex); return this->AcquireCacheImpl(handle); } size_t FileSystemBufferManager::DoGetTotalSize() const { return m_total_size; } size_t FileSystemBufferManager::DoGetFreeSize() const { std::scoped_lock lk(m_mutex); return this->GetFreeSizeImpl(); } size_t FileSystemBufferManager::DoGetTotalAllocatableSize() const { std::scoped_lock lk(m_mutex); return this->GetTotalAllocatableSizeImpl(); } size_t FileSystemBufferManager::DoGetFreeSizePeak() const { std::scoped_lock lk(m_mutex); return this->GetFreeSizePeakImpl(); } size_t FileSystemBufferManager::DoGetTotalAllocatableSizePeak() const { std::scoped_lock lk(m_mutex); return this->GetTotalAllocatableSizePeakImpl(); } size_t FileSystemBufferManager::DoGetRetriedCount() const { std::scoped_lock lk(m_mutex); return this->GetRetriedCountImpl(); } void FileSystemBufferManager::DoClearPeak() { std::scoped_lock lk(m_mutex); return this->ClearPeakImpl(); } } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp ================================================ [File too large to display: 15.8 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_aes_ctr_storage.cpp ================================================ [File too large to display: 7.6 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_aes_ctr_storage_external.cpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_aes_xts_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { template<fs::PointerToStorage BasePointer> void AesXtsStorage<BasePointer>::MakeAesXtsIv(void *dst, size_t dst_size, s64 offset, size_t block_size) { AMS_ASSERT(dst != nullptr); AMS_ASSERT(dst_size == IvSize); AMS_ASSERT(offset >= 0); AMS_UNUSED(dst_size); const uintptr_t out_addr = reinterpret_cast<uintptr_t>(dst); util::StoreBigEndian<s64>(reinterpret_cast<s64 *>(out_addr + sizeof(s64)), offset / block_size); } template<fs::PointerToStorage BasePointer> AesXtsStorage<BasePointer>::AesXtsStorage(BasePointer base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size) : m_base_storage(std::move(base)), m_block_size(block_size), m_mutex() { AMS_ASSERT(m_base_storage != nullptr); AMS_ASSERT(key1 != nullptr); AMS_ASSERT(key2 != nullptr); AMS_ASSERT(iv != nullptr); AMS_ASSERT(key_size == KeySize); AMS_ASSERT(iv_size == IvSize); AMS_ASSERT(util::IsAligned(m_block_size, AesBlockSize)); AMS_UNUSED(key_size, iv_size); std::memcpy(m_key[0], key1, KeySize); std::memcpy(m_key[1], key2, KeySize); std::memcpy(m_iv, iv, IvSize); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::Read(s64 offset, void *buffer, size_t size) { /* Allow zero-size reads. */ R_SUCCEED_IF(size == 0); /* Ensure buffer is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* We can only read at block aligned offsets. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); /* Read the data. */ R_TRY(m_base_storage->Read(offset, buffer, size)); /* Prepare to decrypt the data, with temporarily increased priority. */ ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative); /* Setup the counter. */ char ctr[IvSize]; std::memcpy(ctr, m_iv, IvSize); AddCounter(ctr, IvSize, offset / m_block_size); /* Handle any unaligned data before the start. */ size_t processed_size = 0; if ((offset % m_block_size) != 0) { /* Determine the size of the pre-data read. */ const size_t skip_size = static_cast<size_t>(offset - util::AlignDown(offset, m_block_size)); const size_t data_size = std::min(size, m_block_size - skip_size); /* Decrypt into a pooled buffer. */ { PooledBuffer tmp_buf(m_block_size, m_block_size); AMS_ASSERT(tmp_buf.GetSize() >= m_block_size); std::memset(tmp_buf.GetBuffer(), 0, skip_size); std::memcpy(tmp_buf.GetBuffer() + skip_size, buffer, data_size); const size_t dec_size = crypto::DecryptAes128Xts(tmp_buf.GetBuffer(), m_block_size, m_key[0], m_key[1], KeySize, ctr, IvSize, tmp_buf.GetBuffer(), m_block_size); R_UNLESS(dec_size == m_block_size, fs::ResultUnexpectedInAesXtsStorageA()); std::memcpy(buffer, tmp_buf.GetBuffer() + skip_size, data_size); } AddCounter(ctr, IvSize, 1); processed_size += data_size; AMS_ASSERT(processed_size == std::min(size, m_block_size - skip_size)); } /* Decrypt aligned chunks. */ char *cur = static_cast<char *>(buffer) + processed_size; size_t remaining = size - processed_size; while (remaining > 0) { const size_t cur_size = std::min(m_block_size, remaining); const size_t dec_size = crypto::DecryptAes128Xts(cur, cur_size, m_key[0], m_key[1], KeySize, ctr, IvSize, cur, cur_size); R_UNLESS(cur_size == dec_size, fs::ResultUnexpectedInAesXtsStorageA()); remaining -= cur_size; cur += cur_size; AddCounter(ctr, IvSize, 1); } R_SUCCEED(); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::Write(s64 offset, const void *buffer, size_t size) { /* Allow zero-size writes. */ R_SUCCEED_IF(size == 0); /* Ensure buffer is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* We can only read at block aligned offsets. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); /* Get a pooled buffer. */ PooledBuffer pooled_buffer; const bool use_work_buffer = !IsDeviceAddress(buffer); if (use_work_buffer) { pooled_buffer.Allocate(size, m_block_size); } /* Setup the counter. */ char ctr[IvSize]; std::memcpy(ctr, m_iv, IvSize); AddCounter(ctr, IvSize, offset / m_block_size); /* Handle any unaligned data before the start. */ size_t processed_size = 0; if ((offset % m_block_size) != 0) { /* Determine the size of the pre-data read. */ const size_t skip_size = static_cast<size_t>(offset - util::AlignDown(offset, m_block_size)); const size_t data_size = std::min(size, m_block_size - skip_size); /* Create an encryptor. */ /* NOTE: This is completely unnecessary, because crypto::EncryptAes128Xts is used below. */ /* However, Nintendo does it, so we will too. */ crypto::Aes128XtsEncryptor xts; xts.Initialize(m_key[0], m_key[1], KeySize, ctr, IvSize); /* Encrypt into a pooled buffer. */ { /* NOTE: Nintendo allocates a second pooled buffer here despite having one already allocated above. */ PooledBuffer tmp_buf(m_block_size, m_block_size); AMS_ASSERT(tmp_buf.GetSize() >= m_block_size); std::memset(tmp_buf.GetBuffer(), 0, skip_size); std::memcpy(tmp_buf.GetBuffer() + skip_size, buffer, data_size); const size_t enc_size = crypto::EncryptAes128Xts(tmp_buf.GetBuffer(), m_block_size, m_key[0], m_key[1], KeySize, ctr, IvSize, tmp_buf.GetBuffer(), m_block_size); R_UNLESS(enc_size == m_block_size, fs::ResultUnexpectedInAesXtsStorageA()); R_TRY(m_base_storage->Write(offset, tmp_buf.GetBuffer() + skip_size, data_size)); } AddCounter(ctr, IvSize, 1); processed_size += data_size; AMS_ASSERT(processed_size == std::min(size, m_block_size - skip_size)); } /* Encrypt aligned chunks. */ size_t remaining = size - processed_size; s64 cur_offset = offset + processed_size; while (remaining > 0) { /* Determine data we're writing and where. */ const size_t write_size = use_work_buffer ? std::min(pooled_buffer.GetSize(), remaining) : remaining; /* Encrypt the data, with temporarily increased priority. */ { ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative); size_t remaining_write = write_size; size_t encrypt_offset = 0; while (remaining_write > 0) { const size_t cur_size = std::min(remaining_write, m_block_size); const void *src = static_cast<const char *>(buffer) + processed_size + encrypt_offset; void *dst = use_work_buffer ? pooled_buffer.GetBuffer() + encrypt_offset : const_cast<void *>(src); const size_t enc_size = crypto::EncryptAes128Xts(dst, cur_size, m_key[0], m_key[1], KeySize, ctr, IvSize, src, cur_size); R_UNLESS(enc_size == cur_size, fs::ResultUnexpectedInAesXtsStorageA()); AddCounter(ctr, IvSize, 1); encrypt_offset += cur_size; remaining_write -= cur_size; } } /* Write the encrypted data. */ const void *write_buf = use_work_buffer ? pooled_buffer.GetBuffer() : static_cast<const char *>(buffer) + processed_size; R_TRY(m_base_storage->Write(cur_offset, write_buf, write_size)); /* Advance. */ cur_offset += write_size; processed_size += write_size; remaining -= write_size; } R_SUCCEED(); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::Flush() { R_RETURN(m_base_storage->Flush()); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::SetSize(s64 size) { R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultUnexpectedInAesXtsStorageA()); R_RETURN(m_base_storage->SetSize(size)); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::GetSize(s64 *out) { R_RETURN(m_base_storage->GetSize(out)); } template<fs::PointerToStorage BasePointer> Result AesXtsStorage<BasePointer>::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { /* Unless invalidating cache, check the arguments. */ if (op_id != fs::OperationId::Invalidate) { /* Handle the zero size case. */ R_SUCCEED_IF(size == 0); /* Ensure alignment. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); } R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } template class AesXtsStorage<fs::IStorage *>; template class AesXtsStorage<std::shared_ptr<fs::IStorage>>; } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_aes_xts_storage_external.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { template<fs::PointerToStorage BasePointer> AesXtsStorageExternal<BasePointer>::AesXtsStorageExternal(BasePointer bs, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size, CryptAesXtsFunction ef, CryptAesXtsFunction df) : m_base_storage(std::move(bs)), m_block_size(block_size), m_encrypt_function(ef), m_decrypt_function(df) { AMS_ASSERT(key_size == KeySize); AMS_ASSERT(iv_size == IvSize); AMS_UNUSED(key_size, iv_size); if (key1 != nullptr) { std::memcpy(m_key[0], key1, KeySize); } if (key2 != nullptr) { std::memcpy(m_key[1], key2, KeySize); } std::memcpy(m_iv, iv, IvSize); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::Read(s64 offset, void *buffer, size_t size) { /* Allow zero size. */ R_SUCCEED_IF(size == 0); /* Ensure buffer is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure we can decrypt. */ R_UNLESS(m_decrypt_function != nullptr, fs::ResultNullptrArgument()); /* We can only read at block aligned offsets. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); /* Read the data. */ R_TRY(m_base_storage->Read(offset, buffer, size)); /* Temporarily increase our thread priority. */ ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative); /* Setup the counter. */ char ctr[IvSize]; std::memcpy(ctr, m_iv, IvSize); AddCounter(ctr, IvSize, offset / m_block_size); /* Handle any unaligned data before the start. */ size_t processed_size = 0; if ((offset % m_block_size) != 0) { /* Determine the size of the pre-data read. */ const size_t skip_size = static_cast<size_t>(offset - util::AlignDown(offset, m_block_size)); const size_t data_size = std::min(size, m_block_size - skip_size); /* Decrypt into a pooled buffer. */ { PooledBuffer tmp_buf(m_block_size, m_block_size); AMS_ASSERT(tmp_buf.GetSize() >= m_block_size); std::memset(tmp_buf.GetBuffer(), 0, skip_size); std::memcpy(tmp_buf.GetBuffer() + skip_size, buffer, data_size); /* Decrypt. */ R_TRY(m_decrypt_function(tmp_buf.GetBuffer(), m_block_size, m_key[0], m_key[1], KeySize, ctr, IvSize, tmp_buf.GetBuffer(), m_block_size)); std::memcpy(buffer, tmp_buf.GetBuffer() + skip_size, data_size); } AddCounter(ctr, IvSize, 1); processed_size += data_size; AMS_ASSERT(processed_size == std::min(size, m_block_size - skip_size)); } /* Decrypt aligned chunks. */ char *cur = static_cast<char *>(buffer) + processed_size; size_t remaining = size - processed_size; while (remaining > 0) { const size_t cur_size = std::min(m_block_size, remaining); R_TRY(m_decrypt_function(cur, cur_size, m_key[0], m_key[1], KeySize, ctr, IvSize, cur, cur_size)); remaining -= cur_size; cur += cur_size; AddCounter(ctr, IvSize, 1); } R_SUCCEED(); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::Write(s64 offset, const void *buffer, size_t size) { /* Allow zero-size writes. */ R_SUCCEED_IF(size == 0); /* Ensure buffer is valid. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Ensure we can encrypt. */ R_UNLESS(m_encrypt_function != nullptr, fs::ResultNullptrArgument()); /* We can only write at block aligned offsets. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); /* Get a pooled buffer. */ PooledBuffer pooled_buffer; const bool use_work_buffer = !IsDeviceAddress(buffer); if (use_work_buffer) { pooled_buffer.Allocate(size, m_block_size); } /* Setup the counter. */ char ctr[IvSize]; std::memcpy(ctr, m_iv, IvSize); AddCounter(ctr, IvSize, offset / m_block_size); /* Handle any unaligned data before the start. */ size_t processed_size = 0; if ((offset % m_block_size) != 0) { /* Determine the size of the pre-data read. */ const size_t skip_size = static_cast<size_t>(offset - util::AlignDown(offset, m_block_size)); const size_t data_size = std::min(size, m_block_size - skip_size); /* Encrypt into a pooled buffer. */ { /* NOTE: Nintendo allocates a second pooled buffer here despite having one already allocated above. */ PooledBuffer tmp_buf(m_block_size, m_block_size); AMS_ASSERT(tmp_buf.GetSize() >= m_block_size); std::memset(tmp_buf.GetBuffer(), 0, skip_size); std::memcpy(tmp_buf.GetBuffer() + skip_size, buffer, data_size); R_TRY(m_encrypt_function(tmp_buf.GetBuffer(), m_block_size, m_key[0], m_key[1], KeySize, ctr, IvSize, tmp_buf.GetBuffer(), m_block_size)); R_TRY(m_base_storage->Write(offset, tmp_buf.GetBuffer() + skip_size, data_size)); } AddCounter(ctr, IvSize, 1); processed_size += data_size; AMS_ASSERT(processed_size == std::min(size, m_block_size - skip_size)); } /* Encrypt aligned chunks. */ size_t remaining = size - processed_size; s64 cur_offset = offset + processed_size; while (remaining > 0) { /* Determine data we're writing and where. */ const size_t write_size = use_work_buffer ? std::min(pooled_buffer.GetSize(), remaining) : remaining; /* Encrypt the data, with temporarily increased priority. */ { ScopedThreadPriorityChanger cp(+1, ScopedThreadPriorityChanger::Mode::Relative); size_t remaining_write = write_size; size_t encrypt_offset = 0; while (remaining_write > 0) { const size_t cur_size = std::min(remaining_write, m_block_size); const void *src = static_cast<const char *>(buffer) + processed_size + encrypt_offset; void *dst = use_work_buffer ? pooled_buffer.GetBuffer() + encrypt_offset : const_cast<void *>(src); R_TRY(m_encrypt_function(dst, cur_size, m_key[0], m_key[1], KeySize, ctr, IvSize, src, cur_size)); AddCounter(ctr, IvSize, 1); encrypt_offset += cur_size; remaining_write -= cur_size; } } /* Write the encrypted data. */ const void *write_buf = use_work_buffer ? pooled_buffer.GetBuffer() : static_cast<const char *>(buffer) + processed_size; R_TRY(m_base_storage->Write(cur_offset, write_buf, write_size)); /* Advance. */ cur_offset += write_size; processed_size += write_size; remaining -= write_size; } R_SUCCEED(); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { /* Unless invalidating cache, check the arguments. */ if (op_id != fs::OperationId::Invalidate) { /* Handle the zero size case. */ R_SUCCEED_IF(size == 0); /* Ensure alignment. */ R_UNLESS(util::IsAligned(offset, AesBlockSize), fs::ResultInvalidArgument()); R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultInvalidArgument()); } R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::GetSize(s64 *out) { R_RETURN(m_base_storage->GetSize(out)); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::Flush() { R_RETURN(m_base_storage->Flush()); } template<fs::PointerToStorage BasePointer> Result AesXtsStorageExternal<BasePointer>::SetSize(s64 size) { R_UNLESS(util::IsAligned(size, AesBlockSize), fs::ResultUnexpectedInAesXtsStorageA()); R_RETURN(m_base_storage->SetSize(size)); } template class AesXtsStorageExternal<fs::IStorage *>; template class AesXtsStorageExternal<std::shared_ptr<fs::IStorage>>; } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp ================================================ [File too large to display: 11.1 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_allocator_utility.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { namespace { constexpr bool UseDefaultAllocators = false; constinit bool g_used_default_allocator = false; void *DefaultAllocate(size_t size) { g_used_default_allocator = true; return ams::Malloc(size); } void DefaultDeallocate(void *ptr, size_t size) { AMS_UNUSED(size); ams::Free(ptr); } constinit os::SdkMutex g_allocate_mutex; constinit os::SdkMutex g_allocate_mutex_for_system; constinit AllocateFunction g_allocate_func = UseDefaultAllocators ? DefaultAllocate : nullptr; constinit DeallocateFunction g_deallocate_func = UseDefaultAllocators ? DefaultDeallocate : nullptr; constinit AllocateFunction g_allocate_func_for_system = nullptr; constinit DeallocateFunction g_deallocate_func_for_system = nullptr; void *AllocateUnsafe(size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_allocate_mutex.IsLockedByCurrentThread()); AMS_ASSERT(g_allocate_func != nullptr); /* Allocate memory. */ return g_allocate_func(size); } void DeallocateUnsafe(void *ptr, size_t size) { /* Check pre-conditions. */ AMS_ASSERT(g_allocate_mutex.IsLockedByCurrentThread()); AMS_ASSERT(g_deallocate_func != nullptr); /* Deallocate the pointer. */ g_deallocate_func(ptr, size); } } namespace impl { /* Normal allocator set. */ template<> void *AllocatorFunctionSet<false>::Allocate(size_t size) { return ::ams::fssystem::Allocate(size); } template<> void *AllocatorFunctionSet<false>::AllocateUnsafe(size_t size) { return ::ams::fssystem::AllocateUnsafe(size); } template<> void AllocatorFunctionSet<false>::Deallocate(void *ptr, size_t size) { return ::ams::fssystem::Deallocate(ptr, size); } template<> void AllocatorFunctionSet<false>::DeallocateUnsafe(void *ptr, size_t size) { return ::ams::fssystem::DeallocateUnsafe(ptr, size); } template<> void AllocatorFunctionSet<false>::LockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex.Lock(); } template<> void AllocatorFunctionSet<false>::UnlockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex.Unlock(); } /* System allocator set. */ template<> void *AllocatorFunctionSet<true>::AllocateUnsafe(size_t size) { /* Check pre-conditions. */ AMS_ASSERT(::ams::fssystem::g_allocate_mutex_for_system.IsLockedByCurrentThread()); AMS_ASSERT(::ams::fssystem::g_allocate_func_for_system != nullptr); /* Allocate memory. */ return g_allocate_func_for_system(size); } template<> void AllocatorFunctionSet<true>::DeallocateUnsafe(void *ptr, size_t size) { /* Check pre-conditions. */ AMS_ASSERT(::ams::fssystem::g_allocate_mutex_for_system.IsLockedByCurrentThread()); AMS_ASSERT(::ams::fssystem::g_deallocate_func_for_system != nullptr); /* Deallocate the pointer. */ ::ams::fssystem::g_deallocate_func_for_system(ptr, size); } template<> void *AllocatorFunctionSet<true>::Allocate(size_t size) { std::scoped_lock lk(::ams::fssystem::g_allocate_mutex_for_system); return ::ams::fssystem::impl::AllocatorFunctionSet<true>::AllocateUnsafe(size); } template<> void AllocatorFunctionSet<true>::Deallocate(void *ptr, size_t size) { std::scoped_lock lk(::ams::fssystem::g_allocate_mutex_for_system); return ::ams::fssystem::impl::AllocatorFunctionSet<true>::DeallocateUnsafe(ptr, size); } template<> void AllocatorFunctionSet<true>::LockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex_for_system.Lock(); } template<> void AllocatorFunctionSet<true>::UnlockAllocatorMutex() { ::ams::fssystem::g_allocate_mutex_for_system.Unlock(); } } void *Allocate(size_t size) { std::scoped_lock lk(g_allocate_mutex); return AllocateUnsafe(size); } void Deallocate(void *ptr, size_t size) { std::scoped_lock lk(g_allocate_mutex); return DeallocateUnsafe(ptr, size); } void InitializeAllocator(AllocateFunction allocate_func, DeallocateFunction deallocate_func) { /* Check pre-conditions. */ AMS_ASSERT(allocate_func != nullptr); AMS_ASSERT(deallocate_func != nullptr); /* Check that we can initialize. */ if constexpr (UseDefaultAllocators) { AMS_ASSERT(g_used_default_allocator == false); } else { AMS_ASSERT(g_allocate_func == nullptr); AMS_ASSERT(g_deallocate_func == nullptr); } /* Set the allocator functions. */ g_allocate_func = allocate_func; g_deallocate_func = deallocate_func; } void InitializeAllocatorForSystem(AllocateFunction allocate_func, DeallocateFunction deallocate_func) { /* Check pre-conditions. */ AMS_ASSERT(allocate_func != nullptr); AMS_ASSERT(deallocate_func != nullptr); /* Check that we can initialize. */ AMS_ASSERT(g_allocate_func_for_system == nullptr); AMS_ASSERT(g_deallocate_func_for_system == nullptr); /* Set the system allocator functions. */ g_allocate_func_for_system = allocate_func; g_deallocate_func_for_system = deallocate_func; } } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_block_cache_buffered_storage.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { BlockCacheBufferedStorage::BlockCacheBufferedStorage() : m_mutex(), m_data_storage(), m_last_result(ResultSuccess()), m_data_size(), m_verification_block_size(), m_verification_block_shift(), m_flags(), m_buffer_level(-1), m_block_cache_manager() { /* ... */ } BlockCacheBufferedStorage::~BlockCacheBufferedStorage() { this->Finalize(); } Result BlockCacheBufferedStorage::Initialize(fs::IBufferManager *bm, os::SdkRecursiveMutex *mtx, IStorage *data, s64 data_size, size_t verif_block_size, s32 max_cache_entries, bool is_real_data, s8 buffer_level, bool is_keep_burst_mode, bool is_writable) { /* Validate preconditions. */ AMS_ASSERT(data != nullptr); AMS_ASSERT(bm != nullptr); AMS_ASSERT(mtx != nullptr); AMS_ASSERT(m_mutex == nullptr); AMS_ASSERT(m_data_storage == nullptr); AMS_ASSERT(max_cache_entries > 0); /* Initialize our manager. */ R_TRY(m_block_cache_manager.Initialize(bm, max_cache_entries)); /* Set members. */ m_mutex = mtx; m_data_storage = data; m_data_size = data_size; m_verification_block_size = verif_block_size; m_last_result = ResultSuccess(); m_flags = 0; m_buffer_level = buffer_level; m_is_writable = is_writable; /* Calculate block shift. */ m_verification_block_shift = ILog2(static_cast<u32>(verif_block_size)); AMS_ASSERT(static_cast<size_t>(UINT64_C(1) << m_verification_block_shift) == m_verification_block_size); /* Set burst mode. */ this->SetKeepBurstMode(is_keep_burst_mode); /* Set real data cache. */ this->SetRealDataCache(is_real_data); R_SUCCEED(); } void BlockCacheBufferedStorage::Finalize() { if (m_block_cache_manager.IsInitialized()) { /* Invalidate all cache entries. */ static_cast<void>(this->InvalidateAllCacheEntries()); /* Finalize our block cache manager. */ m_block_cache_manager.Finalize(); /* Clear members. */ m_mutex = nullptr; m_data_storage = nullptr; m_data_size = 0; m_verification_block_size = 0; m_verification_block_shift = 0; } } Result BlockCacheBufferedStorage::Read(s64 offset, void *buffer, size_t size) { /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Succeed if zero-size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Determine the extents to read. */ s64 read_offset = offset; size_t read_size = size; R_UNLESS(read_offset < m_data_size, fs::ResultInvalidOffset()); if (static_cast<s64>(read_offset + read_size) > m_data_size) { read_size = static_cast<size_t>(m_data_size - read_offset); } /* Determine the aligned range to read. */ const size_t block_alignment = m_verification_block_size; s64 aligned_offset = util::AlignDown(read_offset, block_alignment); s64 aligned_offset_end = util::AlignUp(read_offset + read_size, block_alignment); AMS_ASSERT(0 <= aligned_offset && aligned_offset_end <= static_cast<s64>(util::AlignUp(m_data_size, block_alignment))); /* Try to read using cache. */ char *dst = static_cast<char *>(buffer); { /* Determine if we can do bulk reads. */ constexpr s64 BulkReadSizeMax = 2_MB; const bool bulk_read_enabled = (read_offset != aligned_offset || static_cast<s64>(read_offset + read_size) != aligned_offset_end) && aligned_offset_end - aligned_offset <= BulkReadSizeMax; /* Read the head cache. */ CacheEntry head_entry = {}; MemoryRange head_range = {}; bool head_cache_needed = true; R_TRY(this->ReadHeadCache(std::addressof(head_range), std::addressof(head_entry), std::addressof(head_cache_needed), std::addressof(read_offset), std::addressof(aligned_offset), aligned_offset_end, std::addressof(dst), std::addressof(read_size))); /* We may be done after reading the head cache, so check if we are. */ R_SUCCEED_IF(aligned_offset >= aligned_offset_end); /* Ensure we destroy the head buffer. */ auto head_guard = SCOPE_GUARD { m_block_cache_manager.ReleaseCacheEntry(std::addressof(head_entry), head_range); }; /* Read the tail cache. */ CacheEntry tail_entry = {}; MemoryRange tail_range = {}; bool tail_cache_needed = true; R_TRY(this->ReadTailCache(std::addressof(tail_range), std::addressof(tail_entry), std::addressof(tail_cache_needed), read_offset, aligned_offset, std::addressof(aligned_offset_end), dst, std::addressof(read_size))); /* We may be done after reading the tail cache, so check if we are. */ R_SUCCEED_IF(aligned_offset >= aligned_offset_end); /* Ensure that we destroy the tail buffer. */ auto tail_guard = SCOPE_GUARD { m_block_cache_manager.ReleaseCacheEntry(std::addressof(tail_entry), tail_range); }; /* Try to do a bulk read. */ if (bulk_read_enabled) { /* The bulk read will destroy our head/tail buffers. */ head_guard.Cancel(); tail_guard.Cancel(); do { /* Do the bulk read. If we fail due to pooled buffer allocation failing, fall back to the normal read codepath. */ R_TRY_CATCH(this->BulkRead(read_offset, dst, read_size, std::addressof(head_range), std::addressof(tail_range), std::addressof(head_entry), std::addressof(tail_entry), head_cache_needed, tail_cache_needed)) { R_CATCH(fs::ResultAllocationPooledBufferNotEnoughSize) { break; } } R_END_TRY_CATCH; /* Se successfully did a bulk read, so we're done. */ R_SUCCEED(); } while (0); } } /* Read the data using non-bulk reads. */ while (aligned_offset < aligned_offset_end) { /* Ensure that there is data for us to read. */ AMS_ASSERT(read_size > 0); /* If conditions allow us to, read in burst mode. This doesn't use the cache. */ if (this->IsEnabledKeepBurstMode() && read_offset == aligned_offset && (block_alignment * 2 <= read_size)) { const size_t aligned_size = util::AlignDown(read_size, block_alignment); /* Flush the entries. */ R_TRY(this->UpdateLastResult(this->FlushRangeCacheEntries(read_offset, aligned_size, false))); /* Read the data. */ R_TRY(this->UpdateLastResult(m_data_storage->Read(read_offset, dst, aligned_size))); /* Advance. */ dst += aligned_size; read_offset += aligned_size; read_size -= aligned_size; aligned_offset += aligned_size; } else { /* Get the buffer associated with what we're reading. */ CacheEntry entry; MemoryRange range; R_TRY(this->UpdateLastResult(this->GetAssociateBuffer(std::addressof(range), std::addressof(entry), aligned_offset, static_cast<size_t>(aligned_offset_end - aligned_offset), true))); /* Determine where to read data into, and ensure that our entry is aligned. */ char *src = reinterpret_cast<char *>(range.first); AMS_ASSERT(util::IsAligned(entry.range.size, block_alignment)); /* If the entry isn't cached, read the data. */ if (!entry.is_cached) { if (const Result result = m_data_storage->Read(entry.range.offset, src, entry.range.size); R_FAILED(result)) { m_block_cache_manager.ReleaseCacheEntry(std::addressof(entry), range); R_RETURN(this->UpdateLastResult(result)); } entry.is_cached = true; } /* Validate the entry extents. */ AMS_ASSERT(static_cast<s64>(entry.range.offset) <= aligned_offset); AMS_ASSERT(aligned_offset < entry.range.GetEndOffset()); AMS_ASSERT(aligned_offset <= read_offset); /* Copy the data. */ { /* Determine where and how much to copy. */ const s64 buffer_offset = read_offset - entry.range.offset; const size_t copy_size = std::min(read_size, static_cast<size_t>(entry.range.GetEndOffset() - read_offset)); /* Actually copy the data. */ std::memcpy(dst, src + buffer_offset, copy_size); /* Advance. */ dst += copy_size; read_offset += copy_size; read_size -= copy_size; } /* Release the cache entry. */ R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(range, std::addressof(entry)))); aligned_offset = entry.range.GetEndOffset(); } } /* Ensure that we read all the data. */ AMS_ASSERT(read_size == 0); R_SUCCEED(); } Result BlockCacheBufferedStorage::Write(s64 offset, const void *buffer, size_t size) { /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Succeed if zero-size. */ R_SUCCEED_IF(size == 0); /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); /* Determine the extents to read. */ R_UNLESS(offset < m_data_size, fs::ResultInvalidOffset()); if (static_cast<s64>(offset + size) > m_data_size) { size = static_cast<size_t>(m_data_size - offset); } /* The actual extents may be zero-size, so succeed if that's the case. */ R_SUCCEED_IF(size == 0); /* Determine the aligned range to read. */ const size_t block_alignment = m_verification_block_size; s64 aligned_offset = util::AlignDown(offset, block_alignment); const s64 aligned_offset_end = util::AlignUp(offset + size, block_alignment); AMS_ASSERT(0 <= aligned_offset && aligned_offset_end <= static_cast<s64>(util::AlignUp(m_data_size, block_alignment))); /* Write the data. */ const u8 *src = static_cast<const u8 *>(buffer); while (aligned_offset < aligned_offset_end) { /* If conditions allow us to, write in burst mode. This doesn't use the cache. */ if (this->IsEnabledKeepBurstMode() && offset == aligned_offset && (block_alignment * 2 <= size)) { const size_t aligned_size = util::AlignDown(size, block_alignment); /* Flush the entries. */ R_TRY(this->UpdateLastResult(this->FlushRangeCacheEntries(offset, aligned_size, true))); /* Read the data. */ R_TRY(this->UpdateLastResult(m_data_storage->Write(offset, src, aligned_size))); /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); /* Advance. */ src += aligned_size; offset += aligned_size; size -= aligned_size; aligned_offset += aligned_size; } else { /* Get the buffer associated with what we're writing. */ CacheEntry entry; MemoryRange range; R_TRY(this->UpdateLastResult(this->GetAssociateBuffer(std::addressof(range), std::addressof(entry), aligned_offset, static_cast<size_t>(aligned_offset_end - aligned_offset), true))); /* Determine where to write data into. */ char *dst = reinterpret_cast<char *>(range.first); /* If the entry isn't cached and we're writing a partial entry, read in the entry. */ if (!entry.is_cached && ((offset != entry.range.offset) || (offset + size < static_cast<size_t>(entry.range.GetEndOffset())))) { if (Result result = m_data_storage->Read(entry.range.offset, dst, entry.range.size); R_FAILED(result)) { m_block_cache_manager.ReleaseCacheEntry(std::addressof(entry), range); R_RETURN(this->UpdateLastResult(result)); } } entry.is_cached = true; /* Validate the entry extents. */ AMS_ASSERT(static_cast<s64>(entry.range.offset) <= aligned_offset); AMS_ASSERT(aligned_offset < entry.range.GetEndOffset()); AMS_ASSERT(aligned_offset <= offset); /* Copy the data. */ { /* Determine where and how much to copy. */ const s64 buffer_offset = offset - entry.range.offset; const size_t copy_size = std::min(size, static_cast<size_t>(entry.range.GetEndOffset() - offset)); /* Actually copy the data. */ std::memcpy(dst + buffer_offset, src, copy_size); /* Advance. */ src += copy_size; offset += copy_size; size -= copy_size; } /* Set the entry as write-back. */ entry.is_write_back = true; /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); /* Store the associated buffer. */ CacheIndex index; R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(std::addressof(index), range, std::addressof(entry)))); /* Set the after aligned offset. */ aligned_offset = entry.range.GetEndOffset(); /* If we need to, flush the cache entry. */ if (index >= 0 && IsEnabledKeepBurstMode() && offset == aligned_offset && (block_alignment * 2 <= size)) { R_TRY(this->UpdateLastResult(this->FlushCacheEntry(index, false))); } } } /* Ensure that didn't end up in a failure state. */ R_TRY(m_last_result); R_SUCCEED(); } Result BlockCacheBufferedStorage::GetSize(s64 *out) { /* Validate pre-conditions. */ AMS_ASSERT(out != nullptr); AMS_ASSERT(m_data_storage != nullptr); /* Set the size. */ *out = m_data_size; R_SUCCEED(); } Result BlockCacheBufferedStorage::Flush() { /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Flush all cache entries. */ R_TRY(this->UpdateLastResult(this->FlushAllCacheEntries())); /* Flush the data storage. */ R_TRY(this->UpdateLastResult(m_data_storage->Flush())); /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); R_SUCCEED(); } Result BlockCacheBufferedStorage::OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { AMS_UNUSED(src, src_size); /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); switch (op_id) { case fs::OperationId::FillZero: { R_RETURN(this->FillZeroImpl(offset, size)); } case fs::OperationId::DestroySignature: { R_RETURN(this->DestroySignatureImpl(offset, size)); } case fs::OperationId::Invalidate: { R_UNLESS(!m_is_writable, fs::ResultUnsupportedOperateRangeForWritableBlockCacheBufferedStorage()); R_RETURN(this->InvalidateImpl()); } case fs::OperationId::QueryRange: { R_RETURN(this->QueryRangeImpl(dst, dst_size, offset, size)); } default: R_THROW(fs::ResultUnsupportedOperateRangeForBlockCacheBufferedStorage()); } } Result BlockCacheBufferedStorage::Commit() { /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Flush all cache entries. */ R_TRY(this->UpdateLastResult(this->FlushAllCacheEntries())); R_SUCCEED(); } Result BlockCacheBufferedStorage::OnRollback() { /* Validate pre-conditions. */ AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Release all valid entries back to the buffer manager. */ const auto max_cache_entry_count = m_block_cache_manager.GetCount(); for (auto index = 0; index < max_cache_entry_count; index++) { if (const auto &entry = m_block_cache_manager[index]; entry.is_valid) { m_block_cache_manager.InvalidateCacheEntry(index); } } R_SUCCEED(); } Result BlockCacheBufferedStorage::FillZeroImpl(s64 offset, s64 size) { /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Get our storage size. */ s64 storage_size = 0; R_TRY(this->UpdateLastResult(m_data_storage->GetSize(std::addressof(storage_size)))); /* Check the access range. */ R_UNLESS(0 <= offset && offset < storage_size, fs::ResultInvalidOffset()); /* Determine the extents to data signature for. */ auto start_offset = util::AlignDown(offset, m_verification_block_size); auto end_offset = util::AlignUp(std::min(offset + size, storage_size), m_verification_block_size); /* Flush the entries. */ R_TRY(this->UpdateLastResult(this->FlushRangeCacheEntries(offset, size, true))); /* Handle any data before or after the aligned range. */ if (start_offset < offset || offset + size < end_offset) { /* Allocate a work buffer. */ std::unique_ptr<char[], fs::impl::Deleter> work = fs::impl::MakeUnique<char[]>(m_verification_block_size); R_UNLESS(work != nullptr, fs::ResultAllocationMemoryFailedInBlockCacheBufferedStorageB()); /* Handle data before the aligned range. */ if (start_offset < offset) { /* Read the block. */ R_TRY(this->UpdateLastResult(m_data_storage->Read(start_offset, work.get(), m_verification_block_size))); /* Determine the partial extents to clear. */ const auto clear_offset = static_cast<size_t>(offset - start_offset); const auto clear_size = static_cast<size_t>(std::min(static_cast<s64>(m_verification_block_size - clear_offset), size)); /* Clear the partial block. */ std::memset(work.get() + clear_offset, 0, clear_size); /* Write the partially cleared block. */ R_TRY(this->UpdateLastResult(m_data_storage->Write(start_offset, work.get(), m_verification_block_size))); /* Update the start offset. */ start_offset += m_verification_block_size; /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); } /* Handle data after the aligned range. */ if (start_offset < offset + size && offset + size < end_offset) { /* Read the block. */ const auto last_offset = end_offset - m_verification_block_size; R_TRY(this->UpdateLastResult(m_data_storage->Read(last_offset, work.get(), m_verification_block_size))); /* Clear the partial block. */ const auto clear_size = static_cast<size_t>((offset + size) - last_offset); std::memset(work.get(), 0, clear_size); /* Write the partially cleared block. */ R_TRY(this->UpdateLastResult(m_data_storage->Write(last_offset, work.get(), m_verification_block_size))); /* Update the end offset. */ end_offset -= m_verification_block_size; /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); } } /* We're done if there's no data to clear. */ R_SUCCEED_IF(start_offset == end_offset); /* Clear the signature for the aligned range. */ R_TRY(this->UpdateLastResult(m_data_storage->OperateRange(fs::OperationId::FillZero, start_offset, end_offset - start_offset))); /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); R_SUCCEED(); } Result BlockCacheBufferedStorage::DestroySignatureImpl(s64 offset, s64 size) { /* Ensure we aren't already in a failed state. */ R_TRY(m_last_result); /* Get our storage size. */ s64 storage_size = 0; R_TRY(this->UpdateLastResult(m_data_storage->GetSize(std::addressof(storage_size)))); /* Check the access range. */ R_UNLESS(0 <= offset && offset < storage_size, fs::ResultInvalidOffset()); /* Determine the extents to clear signature for. */ const auto start_offset = util::AlignUp(offset, m_verification_block_size); const auto end_offset = util::AlignDown(std::min(offset + size, storage_size), m_verification_block_size); /* Flush the entries. */ R_TRY(this->UpdateLastResult(this->FlushRangeCacheEntries(offset, size, true))); /* Clear the signature for the aligned range. */ R_TRY(this->UpdateLastResult(m_data_storage->OperateRange(fs::OperationId::DestroySignature, start_offset, end_offset - start_offset))); /* Set blocking buffer manager allocations. */ buffers::EnableBlockingBufferManagerAllocation(); R_SUCCEED(); } Result BlockCacheBufferedStorage::InvalidateImpl() { /* Invalidate cache entries. */ { std::scoped_lock lk(*m_mutex); m_block_cache_manager.Invalidate(); } /* Invalidate the aligned range. */ { Result result = m_data_storage->OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max()); AMS_ASSERT(!fs::ResultBufferAllocationFailed::Includes(result)); R_TRY(result); } /* Clear our last result if we should. */ if (fs::ResultIntegrityVerificationStorageCorrupted::Includes(m_last_result)) { m_last_result = ResultSuccess(); } R_SUCCEED(); } Result BlockCacheBufferedStorage::QueryRangeImpl(void *dst, size_t dst_size, s64 offset, s64 size) { /* Get our storage size. */ s64 storage_size = 0; R_TRY(this->GetSize(std::addressof(storage_size))); /* Determine the extents we can actually query. */ const auto actual_size = std::min(size, storage_size - offset); const auto aligned_offset = util::AlignDown(offset, m_verification_block_size); const auto aligned_offset_end = util::AlignUp(offset + actual_size, m_verification_block_size); const auto aligned_size = aligned_offset_end - aligned_offset; /* Query the aligned range. */ R_TRY(this->UpdateLastResult(m_data_storage->OperateRange(dst, dst_size, fs::OperationId::QueryRange, aligned_offset, aligned_size, nullptr, 0))); R_SUCCEED(); } Result BlockCacheBufferedStorage::GetAssociateBuffer(MemoryRange *out_range, CacheEntry *out_entry, s64 offset, size_t ideal_size, bool is_allocate_for_write) { AMS_UNUSED(is_allocate_for_write); /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); AMS_ASSERT(out_range != nullptr); AMS_ASSERT(out_entry != nullptr); /* Lock our mutex. */ std::scoped_lock lk(*m_mutex); /* Get the maximum cache entry count. */ const CacheIndex max_cache_entry_count = m_block_cache_manager.GetCount(); /* Locate the index of the cache entry, if present. */ CacheIndex index; size_t actual_size = ideal_size; for (index = 0; index < max_cache_entry_count; ++index) { if (const auto &entry = m_block_cache_manager[index]; entry.IsAllocated()) { if (entry.range.IsIncluded(offset)) { break; } if (offset <= entry.range.offset && entry.range.offset < static_cast<s64>(offset + actual_size)) { actual_size = static_cast<s64>(entry.range.offset - offset); } } } /* Clear the out range. */ out_range->first = 0; out_range->second = 0; /* If we located an entry, use it. */ if (index != max_cache_entry_count) { m_block_cache_manager.AcquireCacheEntry(out_entry, out_range, index); actual_size = out_entry->range.size - (offset - out_entry->range.offset); } /* If we don't have an out entry, allocate one. */ if (out_range->first == 0) { /* Ensure that the allocatable size is above a threshold. */ const auto size_threshold = m_block_cache_manager.GetAllocator()->GetTotalSize() / 8; if (m_block_cache_manager.GetAllocator()->GetTotalAllocatableSize() < size_threshold) { R_TRY(this->FlushAllCacheEntries()); } /* Decide in advance on a block alignment. */ const size_t block_alignment = m_verification_block_size; /* Ensure that the size we request is valid. */ { AMS_ASSERT(actual_size >= 1); actual_size = std::min(actual_size, block_alignment * 2); } AMS_ASSERT(actual_size >= block_alignment); /* Allocate a buffer. */ R_TRY(buffers::AllocateBufferUsingBufferManagerContext(out_range, m_block_cache_manager.GetAllocator(), actual_size, fs::IBufferManager::BufferAttribute(m_buffer_level), [=](const MemoryRange &buffer) { return buffer.first != 0 && block_alignment <= buffer.second; }, AMS_CURRENT_FUNCTION_NAME)); /* Ensure our size is accurate. */ actual_size = std::min(actual_size, out_range->second); /* Set the output entry. */ out_entry->is_valid = true; out_entry->is_write_back = false; out_entry->is_cached = false; out_entry->is_flushing = false; out_entry->handle = 0; out_entry->memory_address = 0; out_entry->memory_size = 0; out_entry->range.offset = offset; out_entry->range.size = actual_size; out_entry->lru_counter = 0; } /* Check that we ended up with a coherent out range. */ AMS_ASSERT(out_range->second >= out_entry->range.size); R_SUCCEED(); } Result BlockCacheBufferedStorage::StoreOrDestroyBuffer(CacheIndex *out, const MemoryRange &range, CacheEntry *entry) { /* Validate pre-conditions. */ AMS_ASSERT(out != nullptr); /* Lock our mutex. */ std::scoped_lock lk(*m_mutex); /* In the event that we fail, release our buffer. */ ON_RESULT_FAILURE { m_block_cache_manager.ReleaseCacheEntry(entry, range); }; /* If the entry is write-back, ensure we don't exceed certain dirtiness thresholds. */ if (entry->is_write_back) { R_TRY(this->ControlDirtiness()); } /* Get unused cache entry index. */ CacheIndex empty_index, lru_index; m_block_cache_manager.GetEmptyCacheEntryIndex(std::addressof(empty_index), std::addressof(lru_index)); /* If all entries are valid, we need to invalidate one. */ if (empty_index == BlockCacheManager::InvalidCacheIndex) { /* Invalidate the lease recently used entry. */ empty_index = lru_index; /* Get the entry to invalidate, sanity check that we can invalidate it. */ const CacheEntry &entry_to_invalidate = m_block_cache_manager[empty_index]; AMS_ASSERT(entry_to_invalidate.is_valid); AMS_ASSERT(!entry_to_invalidate.is_flushing); AMS_UNUSED(entry_to_invalidate); /* Invalidate the entry. */ R_TRY(this->FlushCacheEntry(empty_index, true)); /* Check that the entry was invalidated successfully. */ AMS_ASSERT(!entry_to_invalidate.is_valid); AMS_ASSERT(!entry_to_invalidate.is_flushing); } /* Store the entry. */ if (m_block_cache_manager.SetCacheEntry(empty_index, *entry, range, fs::IBufferManager::BufferAttribute(m_buffer_level))) { *out = empty_index; } else { *out = BlockCacheManager::InvalidCacheIndex; } R_SUCCEED(); } Result BlockCacheBufferedStorage::FlushCacheEntry(CacheIndex index, bool invalidate) { /* Lock our mutex. */ std::scoped_lock lk(*m_mutex); /* Get the entry, sanity check that the entry's state allows for flush. */ auto &entry = m_block_cache_manager[index]; AMS_ASSERT(entry.is_valid); AMS_ASSERT(!entry.is_flushing); /* If we're not write back (i.e. an invalidate is happening), just release the buffer. */ if (!entry.is_write_back) { AMS_ASSERT(invalidate); m_block_cache_manager.InvalidateCacheEntry(index); R_SUCCEED(); } /* Note that we've started flushing, while we process. */ m_block_cache_manager.SetFlushing(index, true); ON_SCOPE_EXIT { m_block_cache_manager.SetFlushing(index, false); }; /* Create and check our memory range. */ MemoryRange memory_range = fs::IBufferManager::MakeMemoryRange(entry.memory_address, entry.memory_size); AMS_ASSERT(memory_range.first != 0); AMS_ASSERT(memory_range.second >= entry.range.size); /* Validate the entry's offset. */ AMS_ASSERT(entry.range.offset >= 0); AMS_ASSERT(entry.range.offset < m_data_size); AMS_ASSERT(util::IsAligned(entry.range.offset, m_verification_block_size)); /* Write back the data. */ Result result = ResultSuccess(); size_t write_size = entry.range.size; if (R_SUCCEEDED(m_last_result)) { /* Set blocking buffer manager allocations. */ result = m_data_storage->Write(entry.range.offset, reinterpret_cast<const void *>(memory_range.first), write_size); /* Check the result. */ AMS_ASSERT(!fs::ResultBufferAllocationFailed::Includes(result)); } else { result = m_last_result; } /* Set that we're not write-back. */ m_block_cache_manager.SetWriteBack(index, false); /* If we're invalidating, release the buffer. Otherwise, register the flushed data. */ if (invalidate) { m_block_cache_manager.ReleaseCacheEntry(index, memory_range); } else { AMS_ASSERT(entry.is_valid); m_block_cache_manager.RegisterCacheEntry(index, memory_range, fs::IBufferManager::BufferAttribute(m_buffer_level)); } /* Try to succeed. */ R_TRY(result); /* We succeeded. */ R_SUCCEED(); } Result BlockCacheBufferedStorage::FlushRangeCacheEntries(s64 offset, s64 size, bool invalidate) { /* Validate pre-conditions. */ AMS_ASSERT(m_data_storage != nullptr); AMS_ASSERT(m_block_cache_manager.IsInitialized()); /* Iterate over all entries that fall within the range. */ Result result = ResultSuccess(); const auto max_cache_entry_count = m_block_cache_manager.GetCount(); for (auto i = 0; i < max_cache_entry_count; ++i) { auto &entry = m_block_cache_manager[i]; if (entry.is_valid && (entry.is_write_back || invalidate) && (entry.range.offset < (offset + size)) && (offset < entry.range.GetEndOffset())) { const auto cur_result = this->FlushCacheEntry(i, invalidate); if (R_FAILED(cur_result) && R_SUCCEEDED(result)) { result = cur_result; } } } /* Try to succeed. */ R_TRY(result); /* We succeeded. */ R_SUCCEED(); } Result BlockCacheBufferedStorage::FlushAllCacheEntries() { R_TRY(this->FlushRangeCacheEntries(0, std::numeric_limits<s64>::max(), false)); R_SUCCEED(); } Result BlockCacheBufferedStorage::InvalidateAllCacheEntries() { R_TRY(this->FlushRangeCacheEntries(0, std::numeric_limits<s64>::max(), true)); R_SUCCEED(); } Result BlockCacheBufferedStorage::ControlDirtiness() { /* Get and validate the max cache entry count. */ const auto max_cache_entry_count = m_block_cache_manager.GetCount(); AMS_ASSERT(max_cache_entry_count > 0); /* Get size metrics from the buffer manager. */ const auto total_size = m_block_cache_manager.GetAllocator()->GetTotalSize(); const auto allocatable_size = m_block_cache_manager.GetAllocator()->GetTotalAllocatableSize(); /* If we have enough allocatable space, we don't need to do anything. */ R_SUCCEED_IF(allocatable_size >= total_size / 4); /* Iterate over all entries (up to the threshold) and flush the least recently used dirty entry. */ constexpr auto Threshold = 2; for (int n = 0; n < Threshold; ++n) { auto flushed_index = BlockCacheManager::InvalidCacheIndex; for (auto index = 0; index < max_cache_entry_count; ++index) { if (auto &entry = m_block_cache_manager[index]; entry.is_valid && entry.is_write_back) { if (flushed_index == BlockCacheManager::InvalidCacheIndex || m_block_cache_manager[flushed_index].lru_counter < entry.lru_counter) { flushed_index = index; } } } /* If we can't flush anything, break. */ if (flushed_index == BlockCacheManager::InvalidCacheIndex) { break; } R_TRY(this->FlushCacheEntry(flushed_index, false)); } R_SUCCEED(); } Result BlockCacheBufferedStorage::UpdateLastResult(Result result) { /* Update the last result. */ if (R_FAILED(result) && !fs::ResultBufferAllocationFailed::Includes(result) && R_SUCCEEDED(m_last_result)) { m_last_result = result; } /* Try to succeed with the result. */ R_TRY(result); /* We succeeded. */ R_SUCCEED(); } Result BlockCacheBufferedStorage::ReadHeadCache(MemoryRange *out_range, CacheEntry *out_entry, bool *out_cache_needed, s64 *offset, s64 *aligned_offset, s64 aligned_offset_end, char **buffer, size_t *size) { /* Valdiate pre-conditions. */ AMS_ASSERT(out_range != nullptr); AMS_ASSERT(out_entry != nullptr); AMS_ASSERT(out_cache_needed != nullptr); AMS_ASSERT(offset != nullptr); AMS_ASSERT(aligned_offset != nullptr); AMS_ASSERT(buffer != nullptr); AMS_ASSERT(*buffer != nullptr); AMS_ASSERT(size != nullptr); AMS_ASSERT(*aligned_offset < aligned_offset_end); /* Iterate over the region. */ CacheEntry entry = {}; MemoryRange memory_range = {}; *out_cache_needed = true; while (*aligned_offset < aligned_offset_end) { /* Get the associated buffer for the offset. */ R_TRY(this->UpdateLastResult(this->GetAssociateBuffer(std::addressof(memory_range), std::addressof(entry), *aligned_offset, m_verification_block_size, true))); /* If the entry isn't cached, we're done. */ if (!entry.is_cached) { break; } /* Set cache not needed. */ *out_cache_needed = false; /* Determine the size to copy. */ const s64 buffer_offset = *offset - entry.range.offset; const size_t copy_size = std::min(*size, static_cast<size_t>(entry.range.GetEndOffset() - *offset)); /* Copy data from the entry. */ std::memcpy(*buffer, reinterpret_cast<const void *>(memory_range.first + buffer_offset), copy_size); /* Advance. */ *buffer += copy_size; *offset += copy_size; *size -= copy_size; *aligned_offset = entry.range.GetEndOffset(); /* Handle the buffer. */ R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(memory_range, std::addressof(entry)))); } /* Set the output entry. */ *out_entry = entry; *out_range = memory_range; R_SUCCEED(); } Result BlockCacheBufferedStorage::ReadTailCache(MemoryRange *out_range, CacheEntry *out_entry, bool *out_cache_needed, s64 offset, s64 aligned_offset, s64 *aligned_offset_end, char *buffer, size_t *size) { /* Valdiate pre-conditions. */ AMS_ASSERT(out_range != nullptr); AMS_ASSERT(out_entry != nullptr); AMS_ASSERT(out_cache_needed != nullptr); AMS_ASSERT(aligned_offset_end != nullptr); AMS_ASSERT(buffer != nullptr); AMS_ASSERT(size != nullptr); AMS_ASSERT(aligned_offset < *aligned_offset_end); /* Iterate over the region. */ CacheEntry entry = {}; MemoryRange memory_range = {}; *out_cache_needed = true; while (aligned_offset < *aligned_offset_end) { /* Get the associated buffer for the offset. */ R_TRY(this->UpdateLastResult(this->GetAssociateBuffer(std::addressof(memory_range), std::addressof(entry), *aligned_offset_end - m_verification_block_size, m_verification_block_size, true))); /* If the entry isn't cached, we're done. */ if (!entry.is_cached) { break; } /* Set cache not needed. */ *out_cache_needed = false; /* Determine the size to copy. */ const s64 buffer_offset = std::max(static_cast<s64>(0), offset - entry.range.offset); const size_t copy_size = std::min(*size, static_cast<size_t>(offset + *size - entry.range.offset)); /* Copy data from the entry. */ std::memcpy(buffer + *size - copy_size, reinterpret_cast<const void *>(memory_range.first + buffer_offset), copy_size); /* Advance. */ *size -= copy_size; *aligned_offset_end = entry.range.offset; /* Handle the buffer. */ R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(memory_range, std::addressof(entry)))); } /* Set the output entry. */ *out_entry = entry; *out_range = memory_range; R_SUCCEED(); } Result BlockCacheBufferedStorage::BulkRead(s64 offset, void *buffer, size_t size, MemoryRange *range_head, MemoryRange *range_tail, CacheEntry *entry_head, CacheEntry *entry_tail, bool head_cache_needed, bool tail_cache_needed) { /* Validate pre-conditions. */ AMS_ASSERT(buffer != nullptr); AMS_ASSERT(range_head != nullptr); AMS_ASSERT(range_tail != nullptr); AMS_ASSERT(entry_head != nullptr); AMS_ASSERT(entry_tail != nullptr); /* Determine bulk read offsets. */ const s64 read_offset = offset; const size_t read_size = size; const s64 aligned_offset = util::AlignDown(read_offset, m_verification_block_size); const s64 aligned_offset_end = util::AlignUp(read_offset + read_size, m_verification_block_size); char *dst = static_cast<char *>(buffer); /* Prepare to do our reads. */ auto head_guard = SCOPE_GUARD { m_block_cache_manager.ReleaseCacheEntry(entry_head, *range_head); }; auto tail_guard = SCOPE_GUARD { m_block_cache_manager.ReleaseCacheEntry(entry_tail, *range_tail); }; /* Flush the entries. */ R_TRY(this->UpdateLastResult(this->FlushRangeCacheEntries(aligned_offset, aligned_offset_end - aligned_offset, false))); /* Determine the buffer to read into. */ PooledBuffer pooled_buffer; const size_t buffer_size = static_cast<size_t>(aligned_offset_end - aligned_offset); char *read_buffer = nullptr; if (read_offset == aligned_offset && read_size == buffer_size) { read_buffer = dst; } else if (tail_cache_needed && entry_tail->range.offset == aligned_offset && entry_tail->range.size == buffer_size) { read_buffer = reinterpret_cast<char *>(range_tail->first); } else if (head_cache_needed && entry_head->range.offset == aligned_offset && entry_head->range.size == buffer_size) { read_buffer = reinterpret_cast<char *>(range_head->first); } else { pooled_buffer.AllocateParticularlyLarge(buffer_size, 1); R_UNLESS(pooled_buffer.GetSize() >= buffer_size, fs::ResultAllocationPooledBufferNotEnoughSize()); read_buffer = pooled_buffer.GetBuffer(); } /* Read the data. */ R_TRY(m_data_storage->Read(aligned_offset, read_buffer, buffer_size)); /* Copy the data out. */ if (dst != read_buffer) { std::memcpy(dst, read_buffer + read_offset - aligned_offset, read_size); } /* Create a helper to populate our caches. */ const auto PopulateCacheFromPooledBuffer = [&](CacheEntry *entry, MemoryRange *range) { AMS_ASSERT(entry != nullptr); AMS_ASSERT(range != nullptr); if (aligned_offset <= entry->range.offset && entry->range.GetEndOffset() <= static_cast<s64>(aligned_offset + buffer_size)) { AMS_ASSERT(!entry->is_cached); if (reinterpret_cast<void *>(range->first) != read_buffer) { std::memcpy(reinterpret_cast<void *>(range->first), read_buffer + entry->range.offset - aligned_offset, entry->range.size); } entry->is_cached = true; } }; /* Populate tail cache if needed. */ if (tail_cache_needed) { PopulateCacheFromPooledBuffer(entry_tail, range_tail); } /* Populate head cache if needed. */ if (head_cache_needed) { PopulateCacheFromPooledBuffer(entry_head, range_head); } /* If both entries are cached, one may contain the other; in that case, we need only the larger entry. */ if (entry_head->is_cached && entry_tail->is_cached) { if (entry_tail->range.offset <= entry_head->range.offset && entry_head->range.GetEndOffset() <= entry_tail->range.GetEndOffset()) { entry_head->is_cached = false; } else if (entry_head->range.offset <= entry_tail->range.offset && entry_tail->range.GetEndOffset() <= entry_head->range.GetEndOffset()) { entry_tail->is_cached = false; } } /* Destroy the tail cache. */ tail_guard.Cancel(); if (entry_tail->is_cached) { R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(*range_tail, entry_tail))); } else { m_block_cache_manager.ReleaseCacheEntry(entry_tail, *range_tail); } /* Destroy the head cache. */ head_guard.Cancel(); if (entry_head->is_cached) { R_TRY(this->UpdateLastResult(this->StoreOrDestroyBuffer(*range_head, entry_head))); } else { m_block_cache_manager.ReleaseCacheEntry(entry_head, *range_head); } R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_bucket_tree.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> namespace ams::fssystem { namespace { using Node = impl::BucketTreeNode<const s64 *>; static_assert(sizeof(Node) == sizeof(BucketTree::NodeHeader)); static_assert(util::is_pod<Node>::value); constexpr inline s32 NodeHeaderSize = sizeof(BucketTree::NodeHeader); class StorageNode { private: class Offset { public: using difference_type = s64; private: s64 m_offset; s32 m_stride; public: constexpr Offset(s64 offset, s32 stride) : m_offset(offset), m_stride(stride) { /* ... */ } constexpr Offset &operator++() { m_offset += m_stride; return *this; } constexpr Offset operator++(int) { Offset ret(*this); m_offset += m_stride; return ret; } constexpr Offset &operator--() { m_offset -= m_stride; return *this; } constexpr Offset operator--(int) { Offset ret(*this); m_offset -= m_stride; return ret; } constexpr difference_type operator-(const Offset &rhs) const { return (m_offset - rhs.m_offset) / m_stride; } constexpr Offset operator+(difference_type ofs) const { return Offset(m_offset + ofs * m_stride, m_stride); } constexpr Offset operator-(difference_type ofs) const { return Offset(m_offset - ofs * m_stride, m_stride); } constexpr Offset &operator+=(difference_type ofs) { m_offset += ofs * m_stride; return *this; } constexpr Offset &operator-=(difference_type ofs) { m_offset -= ofs * m_stride; return *this; } constexpr bool operator==(const Offset &rhs) const { return m_offset == rhs.m_offset; } constexpr bool operator!=(const Offset &rhs) const { return m_offset != rhs.m_offset; } constexpr s64 Get() const { return m_offset; } }; private: const Offset m_start; const s32 m_count; s32 m_index; public: StorageNode(size_t size, s32 count) : m_start(NodeHeaderSize, static_cast<s32>(size)), m_count(count), m_index(-1) { /* ... */ } StorageNode(s64 ofs, size_t size, s32 count) : m_start(NodeHeaderSize + ofs, static_cast<s32>(size)), m_count(count), m_index(-1) { /* ... */ } s32 GetIndex() const { return m_index; } void Find(const char *buffer, s64 virtual_address) { s32 end = m_count; auto pos = m_start; while (end > 0) { auto half = end / 2; auto mid = pos + half; s64 offset = 0; std::memcpy(std::addressof(offset), buffer + mid.Get(), sizeof(s64)); if (offset <= virtual_address) { pos = mid + 1; end -= half + 1; } else { end = half; } } m_index = static_cast<s32>(pos - m_start) - 1; } Result Find(fs::SubStorage &storage, s64 virtual_address) { s32 end = m_count; auto pos = m_start; while (end > 0) { auto half = end / 2; auto mid = pos + half; s64 offset = 0; R_TRY(storage.Read(mid.Get(), std::addressof(offset), sizeof(s64))); if (offset <= virtual_address) { pos = mid + 1; end -= half + 1; } else { end = half; } } m_index = static_cast<s32>(pos - m_start) - 1; R_SUCCEED(); } }; } void BucketTree::Header::Format(s32 entry_count) { AMS_ASSERT(entry_count >= 0); this->magic = Magic; this->version = Version; this->entry_count = entry_count; this->reserved = 0; } Result BucketTree::Header::Verify() const { R_UNLESS(this->magic == Magic, fs::ResultInvalidBucketTreeSignature()); R_UNLESS(this->entry_count >= 0, fs::ResultInvalidBucketTreeEntryCount()); R_UNLESS(this->version <= Version, fs::ResultUnsupportedVersion()); R_SUCCEED(); } Result BucketTree::NodeHeader::Verify(s32 node_index, size_t node_size, size_t entry_size) const { R_UNLESS(this->index == node_index, fs::ResultInvalidBucketTreeNodeIndex()); R_UNLESS(entry_size != 0 && node_size >= entry_size + NodeHeaderSize, fs::ResultInvalidSize()); const size_t max_entry_count = (node_size - NodeHeaderSize) / entry_size; R_UNLESS(this->count > 0 && static_cast<size_t>(this->count) <= max_entry_count, fs::ResultInvalidBucketTreeNodeEntryCount()); R_UNLESS(this->offset >= 0, fs::ResultInvalidBucketTreeNodeOffset()); R_SUCCEED(); } Result BucketTree::Initialize(IAllocator *allocator, fs::SubStorage node_storage, fs::SubStorage entry_storage, size_t node_size, size_t entry_size, s32 entry_count) { /* Validate preconditions. */ AMS_ASSERT(allocator != nullptr); AMS_ASSERT(entry_size >= sizeof(s64)); AMS_ASSERT(node_size >= entry_size + sizeof(NodeHeader)); AMS_ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); AMS_ASSERT(util::IsPowerOfTwo(node_size)); AMS_ASSERT(!this->IsInitialized()); /* Ensure valid entry count. */ R_UNLESS(entry_count > 0, fs::ResultInvalidArgument()); /* Allocate node. */ R_UNLESS(m_node_l1.Allocate(allocator, node_size), fs::ResultBufferAllocationFailed()); ON_RESULT_FAILURE { m_node_l1.Free(node_size); }; /* Read node. */ R_TRY(node_storage.Read(0, m_node_l1.Get(), node_size)); /* Verify node. */ R_TRY(m_node_l1->Verify(0, node_size, sizeof(s64))); /* Validate offsets. */ const auto offset_count = GetOffsetCount(node_size); const auto entry_set_count = GetEntrySetCount(node_size, entry_size, entry_count); const auto * const node = m_node_l1.Get<Node>(); s64 start_offset; if (offset_count < entry_set_count && node->GetCount() < offset_count) { start_offset = *node->GetEnd(); } else { start_offset = *node->GetBegin(); } const auto end_offset = node->GetEndOffset(); R_UNLESS(0 <= start_offset && start_offset <= node->GetBeginOffset(), fs::ResultInvalidBucketTreeEntryOffset()); R_UNLESS(start_offset < end_offset, fs::ResultInvalidBucketTreeEntryOffset()); /* Set member variables. */ m_node_storage = node_storage; m_entry_storage = entry_storage; m_node_size = node_size; m_entry_size = entry_size; m_entry_count = entry_count; m_offset_count = offset_count; m_entry_set_count = entry_set_count; m_offset_cache.offsets.start_offset = start_offset; m_offset_cache.offsets.end_offset = end_offset; m_offset_cache.is_initialized = true; /* We succeeded. */ R_SUCCEED(); } void BucketTree::Initialize(size_t node_size, s64 end_offset) { AMS_ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); AMS_ASSERT(util::IsPowerOfTwo(node_size)); AMS_ASSERT(end_offset > 0); AMS_ASSERT(!this->IsInitialized()); m_node_size = node_size; m_offset_cache.offsets.start_offset = 0; m_offset_cache.offsets.end_offset = end_offset; m_offset_cache.is_initialized = true; } void BucketTree::Finalize() { if (this->IsInitialized()) { m_node_storage = fs::SubStorage(); m_entry_storage = fs::SubStorage(); m_node_l1.Free(m_node_size); m_node_size = 0; m_entry_size = 0; m_entry_count = 0; m_offset_count = 0; m_entry_set_count = 0; m_offset_cache.offsets.start_offset = 0; m_offset_cache.offsets.end_offset = 0; m_offset_cache.is_initialized = false; } } Result BucketTree::Find(Visitor *visitor, s64 virtual_address) { AMS_ASSERT(visitor != nullptr); AMS_ASSERT(this->IsInitialized()); R_UNLESS(virtual_address >= 0, fs::ResultInvalidOffset()); R_UNLESS(!this->IsEmpty(), fs::ResultOutOfRange()); BucketTree::Offsets offsets; R_TRY(this->GetOffsets(std::addressof(offsets))); R_TRY(visitor->Initialize(this, offsets)); R_RETURN(visitor->Find(virtual_address)); } Result BucketTree::InvalidateCache() { /* Invalidate the node storage cache. */ R_TRY(m_node_storage.OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max())); /* Invalidate the entry storage cache. */ R_TRY(m_entry_storage.OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max())); /* Reset our offsets. */ m_offset_cache.is_initialized = false; R_SUCCEED(); } Result BucketTree::EnsureOffsetCache() { /* If we already have an offset cache, we're good. */ R_SUCCEED_IF(m_offset_cache.is_initialized); /* Acquire exclusive right to edit the offset cache. */ std::scoped_lock lk(m_offset_cache.mutex); /* Check again, to be sure. */ R_SUCCEED_IF(m_offset_cache.is_initialized); /* Read/verify L1. */ R_TRY(m_node_storage.Read(0, m_node_l1.Get(), m_node_size)); R_TRY(m_node_l1->Verify(0, m_node_size, sizeof(s64))); /* Get the node. */ auto * const node = m_node_l1.Get<Node>(); s64 start_offset; if (m_offset_count < m_entry_set_count && node->GetCount() < m_offset_count) { start_offset = *node->GetEnd(); } else { start_offset = *node->GetBegin(); } const auto end_offset = node->GetEndOffset(); R_UNLESS(0 <= start_offset && start_offset <= node->GetBeginOffset(), fs::ResultInvalidBucketTreeEntryOffset()); R_UNLESS(start_offset < end_offset, fs::ResultInvalidBucketTreeEntryOffset()); m_offset_cache.offsets.start_offset = start_offset; m_offset_cache.offsets.end_offset = end_offset; m_offset_cache.is_initialized = true; R_SUCCEED(); } Result BucketTree::Visitor::Initialize(const BucketTree *tree, const BucketTree::Offsets &offsets) { AMS_ASSERT(tree != nullptr); AMS_ASSERT(m_tree == nullptr || m_tree == tree); if (m_entry == nullptr) { m_entry = tree->GetAllocator()->Allocate(tree->m_entry_size); R_UNLESS(m_entry != nullptr, fs::ResultBufferAllocationFailed()); m_tree = tree; m_offsets = offsets; } R_SUCCEED(); } Result BucketTree::Visitor::MoveNext() { R_UNLESS(this->IsValid(), fs::ResultOutOfRange()); /* Invalidate our index, and read the header for the next index. */ auto entry_index = m_entry_index + 1; if (entry_index == m_entry_set.info.count) { const auto entry_set_index = m_entry_set.info.index + 1; R_UNLESS(entry_set_index < m_entry_set_count, fs::ResultOutOfRange()); m_entry_index = -1; const auto end = m_entry_set.info.end; const auto entry_set_size = m_tree->m_node_size; const auto entry_set_offset = entry_set_index * static_cast<s64>(entry_set_size); R_TRY(m_tree->m_entry_storage.Read(entry_set_offset, std::addressof(m_entry_set), sizeof(EntrySetHeader))); R_TRY(m_entry_set.header.Verify(entry_set_index, entry_set_size, m_tree->m_entry_size)); R_UNLESS(m_entry_set.info.start == end && m_entry_set.info.start < m_entry_set.info.end, fs::ResultInvalidBucketTreeEntrySetOffset()); entry_index = 0; } else { m_entry_index = -1; } /* Read the new entry. */ const auto entry_size = m_tree->m_entry_size; const auto entry_offset = impl::GetBucketTreeEntryOffset(m_entry_set.info.index, m_tree->m_node_size, entry_size, entry_index); R_TRY(m_tree->m_entry_storage.Read(entry_offset, m_entry, entry_size)); /* Note that we changed index. */ m_entry_index = entry_index; R_SUCCEED(); } Result BucketTree::Visitor::MovePrevious() { R_UNLESS(this->IsValid(), fs::ResultOutOfRange()); /* Invalidate our index, and read the heasder for the previous index. */ auto entry_index = m_entry_index; if (entry_index == 0) { R_UNLESS(m_entry_set.info.index > 0, fs::ResultOutOfRange()); m_entry_index = -1; const auto start = m_entry_set.info.start; const auto entry_set_size = m_tree->m_node_size; const auto entry_set_index = m_entry_set.info.index - 1; const auto entry_set_offset = entry_set_index * static_cast<s64>(entry_set_size); R_TRY(m_tree->m_entry_storage.Read(entry_set_offset, std::addressof(m_entry_set), sizeof(EntrySetHeader))); R_TRY(m_entry_set.header.Verify(entry_set_index, entry_set_size, m_tree->m_entry_size)); R_UNLESS(m_entry_set.info.end == start && m_entry_set.info.start < m_entry_set.info.end, fs::ResultInvalidBucketTreeEntrySetOffset()); entry_index = m_entry_set.info.count; } else { m_entry_index = -1; } --entry_index; /* Read the new entry. */ const auto entry_size = m_tree->m_entry_size; const auto entry_offset = impl::GetBucketTreeEntryOffset(m_entry_set.info.index, m_tree->m_node_size, entry_size, entry_index); R_TRY(m_tree->m_entry_storage.Read(entry_offset, m_entry, entry_size)); /* Note that we changed index. */ m_entry_index = entry_index; R_SUCCEED(); } Result BucketTree::Visitor::Find(s64 virtual_address) { AMS_ASSERT(m_tree != nullptr); /* Get the node. */ const auto * const node = m_tree->m_node_l1.Get<Node>(); R_UNLESS(virtual_address < node->GetEndOffset(), fs::ResultOutOfRange()); /* Get the entry set index. */ s32 entry_set_index = -1; if (m_tree->IsExistOffsetL2OnL1() && virtual_address < node->GetBeginOffset()) { const auto start = node->GetEnd(); const auto end = node->GetBegin() + m_tree->m_offset_count; auto pos = std::upper_bound(start, end, virtual_address); R_UNLESS(start < pos, fs::ResultOutOfRange()); --pos; entry_set_index = static_cast<s32>(pos - start); } else { const auto start = node->GetBegin(); const auto end = node->GetEnd(); auto pos = std::upper_bound(start, end, virtual_address); R_UNLESS(start < pos, fs::ResultOutOfRange()); --pos; if (m_tree->IsExistL2()) { const auto node_index = static_cast<s32>(pos - start); R_UNLESS(0 <= node_index && node_index < m_tree->m_offset_count, fs::ResultInvalidBucketTreeNodeOffset()); R_TRY(this->FindEntrySet(std::addressof(entry_set_index), virtual_address, node_index)); } else { entry_set_index = static_cast<s32>(pos - start); } } /* Validate the entry set index. */ R_UNLESS(0 <= entry_set_index && entry_set_index < m_tree->m_entry_set_count, fs::ResultInvalidBucketTreeNodeOffset()); /* Find the entry. */ R_TRY(this->FindEntry(virtual_address, entry_set_index)); /* Set count. */ m_entry_set_count = m_tree->m_entry_set_count; R_SUCCEED(); } Result BucketTree::Visitor::FindEntrySet(s32 *out_index, s64 virtual_address, s32 node_index) { const auto node_size = m_tree->m_node_size; PooledBuffer pool(node_size, 1); if (node_size <= pool.GetSize()) { R_RETURN(this->FindEntrySetWithBuffer(out_index, virtual_address, node_index, pool.GetBuffer())); } else { pool.Deallocate(); R_RETURN(this->FindEntrySetWithoutBuffer(out_index, virtual_address, node_index)); } } Result BucketTree::Visitor::FindEntrySetWithBuffer(s32 *out_index, s64 virtual_address, s32 node_index, char *buffer) { /* Calculate node extents. */ const auto node_size = m_tree->m_node_size; const auto node_offset = (node_index + 1) * static_cast<s64>(node_size); fs::SubStorage &storage = m_tree->m_node_storage; /* Read the node. */ R_TRY(storage.Read(node_offset, buffer, node_size)); /* Validate the header. */ NodeHeader header; std::memcpy(std::addressof(header), buffer, NodeHeaderSize); R_TRY(header.Verify(node_index, node_size, sizeof(s64))); /* Create the node, and find. */ StorageNode node(sizeof(s64), header.count); node.Find(buffer, virtual_address); R_UNLESS(node.GetIndex() >= 0, fs::ResultInvalidBucketTreeVirtualOffset()); /* Return the index. */ *out_index = m_tree->GetEntrySetIndex(header.index, node.GetIndex()); R_SUCCEED(); } Result BucketTree::Visitor::FindEntrySetWithoutBuffer(s32 *out_index, s64 virtual_address, s32 node_index) { /* Calculate node extents. */ const auto node_size = m_tree->m_node_size; const auto node_offset = (node_index + 1) * static_cast<s64>(node_size); fs::SubStorage &storage = m_tree->m_node_storage; /* Read and validate the header. */ NodeHeader header; R_TRY(storage.Read(node_offset, std::addressof(header), NodeHeaderSize)); R_TRY(header.Verify(node_index, node_size, sizeof(s64))); /* Create the node, and find. */ StorageNode node(node_offset, sizeof(s64), header.count); R_TRY(node.Find(storage, virtual_address)); R_UNLESS(node.GetIndex() >= 0, fs::ResultOutOfRange()); /* Return the index. */ *out_index = m_tree->GetEntrySetIndex(header.index, node.GetIndex()); R_SUCCEED(); } Result BucketTree::Visitor::FindEntry(s64 virtual_address, s32 entry_set_index) { const auto entry_set_size = m_tree->m_node_size; PooledBuffer pool(entry_set_size, 1); if (entry_set_size <= pool.GetSize()) { R_RETURN(this->FindEntryWithBuffer(virtual_address, entry_set_index, pool.GetBuffer())); } else { pool.Deallocate(); R_RETURN(this->FindEntryWithoutBuffer(virtual_address, entry_set_index)); } } Result BucketTree::Visitor::FindEntryWithBuffer(s64 virtual_address, s32 entry_set_index, char *buffer) { /* Calculate entry set extents. */ const auto entry_size = m_tree->m_entry_size; const auto entry_set_size = m_tree->m_node_size; const auto entry_set_offset = entry_set_index * static_cast<s64>(entry_set_size); fs::SubStorage &storage = m_tree->m_entry_storage; /* Read the entry set. */ R_TRY(storage.Read(entry_set_offset, buffer, entry_set_size)); /* Validate the entry_set. */ EntrySetHeader entry_set; std::memcpy(std::addressof(entry_set), buffer, sizeof(EntrySetHeader)); R_TRY(entry_set.header.Verify(entry_set_index, entry_set_size, entry_size)); /* Create the node, and find. */ StorageNode node(entry_size, entry_set.info.count); node.Find(buffer, virtual_address); R_UNLESS(node.GetIndex() >= 0, fs::ResultOutOfRange()); /* Copy the data into entry. */ const auto entry_index = node.GetIndex(); const auto entry_offset = impl::GetBucketTreeEntryOffset(0, entry_size, entry_index); std::memcpy(m_entry, buffer + entry_offset, entry_size); /* Set our entry set/index. */ m_entry_set = entry_set; m_entry_index = entry_index; R_SUCCEED(); } Result BucketTree::Visitor::FindEntryWithoutBuffer(s64 virtual_address, s32 entry_set_index) { /* Calculate entry set extents. */ const auto entry_size = m_tree->m_entry_size; const auto entry_set_size = m_tree->m_node_size; const auto entry_set_offset = entry_set_index * static_cast<s64>(entry_set_size); fs::SubStorage &storage = m_tree->m_entry_storage; /* Read and validate the entry_set. */ EntrySetHeader entry_set; R_TRY(storage.Read(entry_set_offset, std::addressof(entry_set), sizeof(EntrySetHeader))); R_TRY(entry_set.header.Verify(entry_set_index, entry_set_size, entry_size)); /* Create the node, and find. */ StorageNode node(entry_set_offset, entry_size, entry_set.info.count); R_TRY(node.Find(storage, virtual_address)); R_UNLESS(node.GetIndex() >= 0, fs::ResultOutOfRange()); /* Copy the data into entry. */ const auto entry_index = node.GetIndex(); const auto entry_offset = impl::GetBucketTreeEntryOffset(entry_set_offset, entry_size, entry_index); R_TRY(storage.Read(entry_offset, m_entry, entry_size)); /* Set our entry set/index. */ m_entry_set = entry_set; m_entry_index = entry_index; R_SUCCEED(); } } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_buffered_storage.cpp ================================================ [File too large to display: 42.1 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_compression_configuration.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp ================================================ /* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "fssystem_key_slot_cache.hpp" namespace ams::fssystem { namespace { constexpr inline const size_t KeySize = crypto::AesDecryptor128::KeySize; constexpr inline const size_t NxAcidSignatureKeyGenerationMax = 1; constexpr inline const size_t NxAcidSignatureKeyModulusSize = NcaCryptoConfiguration::Rsa2048KeyModulusSize; constexpr inline const u8 NxAcidSignatureKeyModulusDev[NxAcidSignatureKeyGenerationMax + 1][NxAcidSignatureKeyModulusSize] = { { 0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89, 0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87, 0x81, 0x25, 0xF4, 0x30, 0xBC, 0x53, 0x08, 0x68, 0xA2, 0x48, 0x49, 0x8C, 0x3F, 0x38, 0x40, 0x9C, 0xC4, 0x26, 0xF4, 0x79, 0xE2, 0xA1, 0x85, 0xF5, 0x5C, 0x7F, 0x58, 0xBA, 0xA6, 0x1C, 0xA0, 0x8B, 0x84, 0x16, 0x14, 0x6F, 0x85, 0xD9, 0x7C, 0xE1, 0x3C, 0x67, 0x22, 0x1E, 0xFB, 0xD8, 0xA7, 0xA5, 0x9A, 0xBF, 0xEC, 0x0E, 0xCF, 0x96, 0x7E, 0x85, 0xC2, 0x1D, 0x49, 0x5D, 0x54, 0x26, 0xCB, 0x32, 0x7C, 0xF6, 0xBB, 0x58, 0x03, 0x80, 0x2B, 0x5D, 0xF7, 0xFB, 0xD1, 0x9D, 0xC7, 0xC6, 0x2E, 0x53, 0xC0, 0x6F, 0x39, 0x2C, 0x1F, 0xA9, 0x92, 0xF2, 0x4D, 0x7D, 0x4E, 0x74, 0xFF, 0xE4, 0xEF, 0xE4, 0x7C, 0x3D, 0x34, 0x2A, 0x71, 0xA4, 0x97, 0x59, 0xFF, 0x4F, 0xA2, 0xF4, 0x66, 0x78, 0xD8, 0xBA, 0x99, 0xE3, 0xE6, 0xDB, 0x54, 0xB9, 0xE9, 0x54, 0xA1, 0x70, 0xFC, 0x05, 0x1F, 0x11, 0x67, 0x4B, 0x26, 0x8C, 0x0C, 0x3E, 0x03, 0xD2, 0xA3, 0x55, 0x5C, 0x7D, 0xC0, 0x5D, 0x9D, 0xFF, 0x13, 0x2F, 0xFD, 0x19, 0xBF, 0xED, 0x44, 0xC3, 0x8C, 0xA7, 0x28, 0xCB, 0xE5, 0xE0, 0xB1, 0xA7, 0x9C, 0x33, 0x8D, 0xB8, 0x6E, 0xDE, 0x87, 0x18, 0x22, 0x60, 0xC4, 0xAE, 0xF2, 0x87, 0x9F, 0xCE, 0x09, 0x5C, 0xB5, 0x99, 0xA5, 0x9F, 0x49, 0xF2, 0xD7, 0x58, 0xFA, 0xF9, 0xC0, 0x25, 0x7D, 0xD6, 0xCB, 0xF3, 0xD8, 0x6C, 0xA2, 0x69, 0x91, 0x68, 0x73, 0xB1, 0x94, 0x6F, 0xA3, 0xF3, 0xB9, 0x7D, 0xF8, 0xE0, 0x72, 0x9E, 0x93, 0x7B, 0x7A, 0xA2, 0x57, 0x60, 0xB7, 0x5B, 0xA9, 0x84, 0xAE, 0x64, 0x88, 0x69 }, { 0xBC, 0xA5, 0x6A, 0x7E, 0xEA, 0x38, 0x34, 0x62, 0xA6, 0x10, 0x18, 0x3C, 0xE1, 0x63, 0x7B, 0xF0, 0xD3, 0x08, 0x8C, 0xF5, 0xC5, 0xC4, 0xC7, 0x93, 0xE9, 0xD9, 0xE6, 0x32, 0xF3, 0xA0, 0xF6, 0x6E, 0x8A, 0x98, 0x76, 0x47, 0x33, 0x47, 0x65, 0x02, 0x70, 0xDC, 0x86, 0x5F, 0x3D, 0x61, 0x5A, 0x70, 0xBC, 0x5A, 0xCA, 0xCA, 0x50, 0xAD, 0x61, 0x7E, 0xC9, 0xEC, 0x27, 0xFF, 0xE8, 0x64, 0x42, 0x9A, 0xEE, 0xBE, 0xC3, 0xD1, 0x0B, 0xC0, 0xE9, 0xBF, 0x83, 0x8D, 0xC0, 0x0C, 0xD8, 0x00, 0x5B, 0x76, 0x90, 0xD2, 0x4B, 0x30, 0x84, 0x35, 0x8B, 0x1E, 0x20, 0xB7, 0xE4, 0xDC, 0x63, 0xE5, 0xDF, 0xCD, 0x00, 0x5F, 0x81, 0x5F, 0x67, 0xC5, 0x8B, 0xDF, 0xFC, 0xE1, 0x37, 0x5F, 0x07, 0xD9, 0xDE, 0x4F, 0xE6, 0x7B, 0xF1, 0xFB, 0xA1, 0x5A, 0x71, 0x40, 0xFE, 0xBA, 0x1E, 0xAE, 0x13, 0x22, 0xD2, 0xFE, 0x37, 0xA2, 0xB6, 0x8B, 0xAB, 0xEB, 0x84, 0x81, 0x4E, 0x7C, 0x1E, 0x02, 0xD1, 0xFB, 0xD7, 0x5D, 0x11, 0x84, 0x64, 0xD2, 0x4D, 0xBB, 0x50, 0x00, 0x67, 0x54, 0xE2, 0x77, 0x89, 0xBA, 0x0B, 0xE7, 0x05, 0x57, 0x9A, 0x22, 0x5A, 0xEC, 0x76, 0x1C, 0xFD, 0xE8, 0xA8, 0x18, 0x16, 0x41, 0x65, 0x03, 0xFA, 0xC4, 0xA6, 0x31, 0x5C, 0x1A, 0x7F, 0xAB, 0x11, 0xC8, 0x4A, 0x99, 0xB9, 0xE6, 0xCF, 0x62, 0x21, 0xA6, 0x72, 0x47, 0xDB, 0xBA, 0x96, 0x26, 0x4E, 0x2E, 0xD4, 0x8C, 0x46, 0xD6, 0xA7, 0x1A, 0x6C, 0x32, 0xA7, 0xDF, 0x85, 0x1C, 0x03, 0xC3, 0x6D, 0xA9, 0xE9, 0x68, 0xF4, 0x17, 0x1E, 0xB2, 0x70, 0x2A, 0xA1, 0xE5, 0xE1, 0xF3, 0x8F, 0x6F, 0x63, 0xAC, 0xEB, 0x72, 0x0B, 0x4C, 0x4A, 0x36, 0x3C, 0x60, 0x91, 0x9F, 0x6E, 0x1C, 0x71, 0xEA, 0xD0, 0x78, 0x78, 0xA0, 0x2E, 0xC6, 0x32, 0x6B } }; constexpr inline const u8 NxAcidSignatureKeyModulusProd[NxAcidSignatureKeyGenerationMax + 1][NxAcidSignatureKeyModulusSize] = { { 0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D, 0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50, 0x2E, 0xFC, 0x9D, 0x94, 0x76, 0xD6, 0x4C, 0xD8, 0xFF, 0x10, 0xFA, 0x5E, 0x93, 0x0A, 0xB4, 0x57, 0xAC, 0x51, 0xC7, 0x16, 0x66, 0xF4, 0x1A, 0x54, 0xC2, 0xC5, 0x04, 0x3D, 0x1B, 0xFE, 0x30, 0x20, 0x8A, 0xAC, 0x6F, 0x6F, 0xF5, 0xC7, 0xB6, 0x68, 0xB8, 0xC9, 0x40, 0x6B, 0x42, 0xAD, 0x11, 0x21, 0xE7, 0x8B, 0xE9, 0x75, 0x01, 0x86, 0xE4, 0x48, 0x9B, 0x0A, 0x0A, 0xF8, 0x7F, 0xE8, 0x87, 0xF2, 0x82, 0x01, 0xE6, 0xA3, 0x0F, 0xE4, 0x66, 0xAE, 0x83, 0x3F, 0x4E, 0x9F, 0x5E, 0x01, 0x30, 0xA4, 0x00, 0xB9, 0x9A, 0xAE, 0x5F, 0x03, 0xCC, 0x18, 0x60, 0xE5, 0xEF, 0x3B, 0x5E, 0x15, 0x16, 0xFE, 0x1C, 0x82, 0x78, 0xB5, 0x2F, 0x47, 0x7C, 0x06, 0x66, 0x88, 0x5D, 0x35, 0xA2, 0x67, 0x20, 0x10, 0xE7, 0x6C, 0x43, 0x68, 0xD3, 0xE4, 0x5A, 0x68, 0x2A, 0x5A, 0xE2, 0x6D, 0x73, 0xB0, 0x31, 0x53, 0x1C, 0x20, 0x09, 0x44, 0xF5, 0x1A, 0x9D, 0x22, 0xBE, 0x12, 0xA1, 0x77, 0x11, 0xE2, 0xA1, 0xCD, 0x40, 0x9A, 0xA2, 0x8B, 0x60, 0x9B, 0xEF, 0xA0, 0xD3, 0x48, 0x63, 0xA2, 0xF8, 0xA3, 0x2C, 0x08, 0x56, 0x52, 0x2E, 0x60, 0x19, 0x67, 0x5A, 0xA7, 0x9F, 0xDC, 0x3F, 0x3F, 0x69, 0x2B, 0x31, 0x6A, 0xB7, 0x88, 0x4A, 0x14, 0x84, 0x80, 0x33, 0x3C, 0x9D, 0x44, 0xB7, 0x3F, 0x4C, 0xE1, 0x75, 0xEA, 0x37, 0xEA, 0xE8, 0x1E, 0x7C, 0x77, 0xB7, 0xC6, 0x1A, 0xA2, 0xF0, 0x9F, 0x10, 0x61, 0xCD, 0x7B, 0x5B, 0x32, 0x4C, 0x37, 0xEF, 0xB1, 0x71, 0x68, 0x53, 0x0A, 0xED, 0x51, 0x7D, 0x35, 0x22, 0xFD }, { 0xE7, 0xAA, 0x25, 0xC8, 0x01, 0xA5, 0x14, 0x6B, 0x01, 0x60, 0x3E, 0xD9, 0x96, 0x5A, 0xBF, 0x90, 0xAC, 0xA7, 0xFD, 0x9B, 0x5B, 0xBD, 0x8A, 0x26, 0xB0, 0xCB, 0x20, 0x28, 0x9A, 0x72, 0x12, 0xF5, 0x20, 0x65, 0xB3, 0xB9, 0x84, 0x58, 0x1F, 0x27, 0xBC, 0x7C, 0xA2, 0xC9, 0x9E, 0x18, 0x95, 0xCF, 0xC2, 0x73, 0x2E, 0x74, 0x8C, 0x66, 0xE5, 0x9E, 0x79, 0x2B, 0xB8, 0x07, 0x0C, 0xB0, 0x4E, 0x8E, 0xAB, 0x85, 0x21, 0x42, 0xC4, 0xC5, 0x6D, 0x88, 0x9C, 0xDB, 0x15, 0x95, 0x3F, 0x80, 0xDB, 0x7A, 0x9A, 0x7D, 0x41, 0x56, 0x25, 0x17, 0x18, 0x42, 0x4D, 0x8C, 0xAC, 0xA5, 0x7B, 0xDB, 0x42, 0x5D, 0x59, 0x35, 0x45, 0x5D, 0x8A, 0x02, 0xB5, 0x70, 0xC0, 0x72, 0x35, 0x46, 0xD0, 0x1D, 0x60, 0x01, 0x4A, 0xCC, 0x1C, 0x46, 0xD3, 0xD6, 0x35, 0x52, 0xD6, 0xE1, 0xF8, 0x3B, 0x5D, 0xEA, 0xDD, 0xB8, 0xFE, 0x7D, 0x50, 0xCB, 0x35, 0x23, 0x67, 0x8B, 0xB6, 0xE4, 0x74, 0xD2, 0x60, 0xFC, 0xFD, 0x43, 0xBF, 0x91, 0x08, 0x81, 0xC5, 0x4F, 0x5D, 0x16, 0x9A, 0xC4, 0x9A, 0xC6, 0xF6, 0xF3, 0xE1, 0xF6, 0x5C, 0x07, 0xAA, 0x71, 0x6C, 0x13, 0xA4, 0xB1, 0xB3, 0x66, 0xBF, 0x90, 0x4C, 0x3D, 0xA2, 0xC4, 0x0B, 0xB8, 0x3D, 0x7A, 0x8C, 0x19, 0xFA, 0xFF, 0x6B, 0xB9, 0x1F, 0x02, 0xCC, 0xB6, 0xD3, 0x0C, 0x7D, 0x19, 0x1F, 0x47, 0xF9, 0xC7, 0x40, 0x01, 0xFA, 0x46, 0xEA, 0x0B, 0xD4, 0x02, 0xE0, 0x3D, 0x30, 0x9A, 0x1A, 0x0F, 0xEA, 0xA7, 0x66, 0x55, 0xF7, 0xCB, 0x28, 0xE2, 0xBB, 0x99, 0xE4, 0x83, 0xC3, 0x43, 0x03, 0xEE, 0xDC, 0x1F, 0x02, 0x23, 0xDD, 0xD1, 0x2D, 0x39, 0xA4, 0x65, 0x75, 0x03, 0xEF, 0x37, 0x9C, 0x06, 0xD6, 0xFA, 0xA1, 0x15, 0xF0, 0xDB, 0x17, 0x47, 0x26, 0x4F, 0x49, 0x03 } }; static_assert(sizeof(NxAcidSignatureKeyModulusProd) == sizeof(NxAcidSignatureKeyModulusDev)); constexpr inline const u8 AcidSignatureKeyPublicExponent[] = { 0x01, 0x00, 0x01 }; NcaCryptoConfiguration g_nca_crypto_configuration_dev; NcaCryptoConfiguration g_nca_crypto_configuration_prod; constexpr inline s32 KeySlotCacheEntryCount = 3; constinit KeySlotCache g_key_slot_cache; constinit util::optional<KeySlotCacheEntry> g_key_slot_cache_entry[KeySlotCacheEntryCount]; spl::AccessKey &GetNcaKekAccessKey(s32 key_type) { AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_nca_kek_access_key_array[KeyAreaEncryptionKeyCount]); AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_nca_header_kek_access_key); AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_invalid_nca_kek_access_key); if (key_type > static_cast<s32>(KeyType::NcaHeaderKey2) || IsInvalidKeyTypeValue(key_type)) { return s_invalid_nca_kek_access_key; } else if (key_type == static_cast<s32>(KeyType::NcaHeaderKey1) || key_type == static_cast<s32>(KeyType::NcaHeaderKey2)) { return s_nca_header_kek_access_key; } else { return s_nca_kek_access_key_array[key_type]; } } void GenerateNcaKey(void *dst, size_t dst_size, const void *src, size_t src_size, s32 key_type) { R_ABORT_UNLESS(spl::GenerateAesKey(dst, dst_size, GetNcaKekAccessKey(key_type), src, src_size)); } void ComputeCtr(void *dst, size_t dst_size, int key_slot_idx, const void *src, size_t src_size, const void *iv, size_t iv_size) { if (dst == src) { /* If the destination and source are the same, we'll use an intermediate buffer. */ constexpr size_t MinimumSizeToRequireLocking = 256_KB; constexpr size_t MinimumWorkBufferSize = 16_KB; /* If the request is large enough, acquire a lock to prevent too many large requests in flight simultaneously. */ static constinit os::SdkMutex s_large_work_buffer_mutex; util::optional<std::scoped_lock<os::SdkMutex>> lk = util::nullopt; if (dst_size >= MinimumSizeToRequireLocking) { lk.emplace(s_large_work_buffer_mutex); } /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; pooled_buffer.AllocateParticularlyLarge(dst_size, MinimumWorkBufferSize); /* Copy the iv locally. */ AMS_ASSERT(iv_size == crypto::Aes128CtrEncryptor::IvSize); u8 work_iv[crypto::Aes128CtrEncryptor::IvSize]; std::memcpy(work_iv, iv, sizeof(work_iv)); /* Process all data. */ size_t processed = 0; while (processed < dst_size) { /* Determine the currently processable size. */ const size_t cur_size = std::min<size_t>(dst_size - processed, pooled_buffer.GetSize()); /* Process. */ R_ABORT_UNLESS(spl::ComputeCtr(pooled_buffer.GetBuffer(), cur_size, key_slot_idx, static_cast<const u8 *>(src) + processed, cur_size, work_iv, sizeof(work_iv))); /* Copy to dst. */ std::memcpy(static_cast<u8 *>(dst) + processed, pooled_buffer.GetBuffer(), cur_size); /* Advance. */ processed += cur_size; /* Increment the counter. */ fssystem::AddCounter(work_iv, sizeof(work_iv), cur_size / crypto::Aes128CtrEncryptor::BlockSize); } } else { /* If the destination and source are different, we can just call ComputeCtr directly. */ R_ABORT_UNLESS(spl::ComputeCtr(dst, dst_size, key_slot_idx, src, src_size, iv, iv_size)); } } void DecryptAesCtr(void *dst, size_t dst_size, u8 key_index, u8 key_generation, const void *enc_key, size_t enc_key_size, const void *iv, size_t iv_size, const void *src, size_t src_size) { std::unique_ptr<KeySlotCacheAccessor> accessor; const s32 key_type = GetKeyTypeValue(key_index, key_generation); R_TRY_CATCH(g_key_slot_cache.Find(std::addressof(accessor), enc_key, enc_key_size, key_type)) { R_CATCH(fs::ResultTargetNotFound) { R_ABORT_UNLESS(g_key_slot_cache.AllocateHighPriority(std::addressof(accessor), enc_key, enc_key_size, key_type)); R_ABORT_UNLESS(spl::LoadAesKey(accessor->GetKeySlotIndex(), GetNcaKekAccessKey(key_type), enc_key, enc_key_size)); } } R_END_TRY_CATCH_WITH_ABORT_UNLESS; ComputeCtr(dst, dst_size, accessor->GetKeySlotIndex(), src, src_size, iv, iv_size); } void DecryptAesCtrForPreparedKey(void *dst, size_t dst_size, u8 key_index, u8 key_generation, const void *enc_key, size_t enc_key_size, const void *iv, size_t iv_size, const void *src, size_t src_size) { std::unique_ptr<KeySlotCacheAccessor> accessor; AMS_UNUSED(key_index, key_generation); const s32 key_type = static_cast<s32>(KeyType::NcaExternalKey); R_TRY_CATCH(g_key_slot_cache.Find(std::addressof(accessor), enc_key, enc_key_size, key_type)) { R_CATCH(fs::ResultTargetNotFound) { R_ABORT_UNLESS(g_key_slot_cache.AllocateHighPriority(std::addressof(accessor), enc_key, enc_key_size, key_type)); spl::AccessKey access_key; AMS_ABORT_UNLESS(enc_key_size == sizeof(access_key)); std::memcpy(std::addressof(access_key), enc_key, sizeof(access_key)); R_ABORT_UNLESS(spl::LoadPreparedAesKey(accessor->GetKeySlotIndex(), access_key)); } } R_END_TRY_CATCH_WITH_ABORT_UNLESS; ComputeCtr(dst, dst_size, accessor->GetKeySlotIndex(), src, src_size, iv, iv_size); } bool VerifySign1Prod(const void *sig, size_t sig_size, const void *data, size_t data_size, u8 generation) { const u8 *mod = g_nca_crypto_configuration_prod.header_1_sign_key_moduli[generation]; const size_t mod_size = NcaCryptoConfiguration::Rsa2048KeyModulusSize; const u8 *exp = g_nca_crypto_configuration_prod.header_1_sign_key_public_exponent; const size_t exp_size = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize; return crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, data, data_size); } bool VerifySign1Dev(const void *sig, size_t sig_size, const void *data, size_t data_size, u8 generation) { const u8 *mod = g_nca_crypto_configuration_dev.header_1_sign_key_moduli[generation]; const size_t mod_size = NcaCryptoConfiguration::Rsa2048KeyModulusSize; const u8 *exp = g_nca_crypto_configuration_dev.header_1_sign_key_public_exponent; const size_t exp_size = NcaCryptoConfiguration::Rsa2048KeyPublicExponentSize; return crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, data, data_size); } } const ::ams::fssystem::NcaCryptoConfiguration *GetNcaCryptoConfiguration(bool prod) { /* Decide which configuration to use. */ NcaCryptoConfiguration * const cfg = prod ? std::addressof(g_nca_crypto_configuration_prod) : std::addressof(g_nca_crypto_configuration_dev); std::memcpy(cfg, fssrv::GetDefaultNcaCryptoConfiguration(prod), sizeof(NcaCryptoConfiguration)); /* Set the key generation functions. */ cfg->generate_key = GenerateNcaKey; cfg->decrypt_aes_xts_external = nullptr; cfg->encrypt_aes_xts_external = nullptr; cfg->decrypt_aes_ctr = DecryptAesCtr; cfg->decrypt_aes_ctr_external = DecryptAesCtrForPreparedKey; cfg->verify_sign1 = prod ? VerifySign1Prod : VerifySign1Dev; cfg->is_plaintext_header_available = !prod; cfg->is_available_sw_key = true; /* TODO: Should this default to false for host tools with api to set explicitly? */ #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) cfg->is_unsigned_header_available_for_host_tool = true; #endif return cfg; } void SetUpKekAccessKeys(bool prod) { /* Get the crypto configuration. */ const NcaCryptoConfiguration *nca_crypto_cfg = GetNcaCryptoConfiguration(prod); /* Setup the nca keys. */ { constexpr s32 Option = 0; /* Setup the key area encryption keys. */ for (u8 i = 0; i < NcaCryptoConfiguration::KeyGenerationMax; ++i) { /* NOTE: Nintendo allows these to fail, since the loop tries key generations past the maximum known. */ static_cast<void>(spl::GenerateAesKek(std::addressof(GetNcaKekAccessKey(GetKeyTypeValue(0, i))), nca_crypto_cfg->key_area_encryption_key_source[0], KeySize, i, Option)); static_cast<void>(spl::GenerateAesKek(std::addressof(GetNcaKekAccessKey(GetKeyTypeValue(1, i))), nca_crypto_cfg->key_area_encryption_key_source[1], KeySize, i, Option)); static_cast<void>(spl::GenerateAesKek(std::addressof(GetNcaKekAccessKey(GetKeyTypeValue(2, i))), nca_crypto_cfg->key_area_encryption_key_source[2], KeySize, i, Option)); } /* Setup the header encryption key. */ R_ABORT_UNLESS(spl::GenerateAesKek(std::addressof(GetNcaKekAccessKey(static_cast<s32>(KeyType::NcaHeaderKey1))), nca_crypto_cfg->header_encryption_key_source, KeySize, 0, Option)); } /* TODO FS-REIMPL: Save stuff. */ /* Setup the keyslot cache. */ for (s32 i = 0; i < KeySlotCacheEntryCount; i++) { s32 slot_index = -1; R_ABORT_UNLESS(spl::AllocateAesKeySlot(std::addressof(slot_index))); g_key_slot_cache_entry[i].emplace(slot_index); g_key_slot_cache.AddEntry(std::addressof(g_key_slot_cache_entry[i].value())); } } void InvalidateHardwareAesKey() { constexpr u8 InvalidKey[KeySize] = {}; for (s32 i = 0; i < KeySlotCacheEntryCount; ++i) { std::unique_ptr<KeySlotCacheAccessor> accessor; R_ABORT_UNLESS(g_key_slot_cache.AllocateHighPriority(std::addressof(accessor), InvalidKey, KeySize, -1 - i)); } } bool IsValidSignatureKeyGeneration(ncm::ContentMetaPlatform platform, size_t key_generation) { switch (platform) { case ncm::ContentMetaPlatform::Nx: return key_generation <= NxAcidSignatureKeyGenerationMax; AMS_UNREACHABLE_DEFAULT_CASE(); } } const u8 *GetAcidSignatureKeyModulus(ncm::ContentMetaPlatform platform, bool prod, size_t key_generation, bool unk_unused) { AMS_ASSERT(IsValidSignatureKeyGeneration(platform, key_generation)); AMS_UNUSED(unk_unused); switch (platform) { case ncm::ContentMetaPlatform::Nx: { const size_t used_keygen = (key_generation % (NxAcidSignatureKeyGenerationMax + 1)); return prod ? NxAcidSignatureKeyModulusProd[used_keygen] : NxAcidSignatureKeyModulusDev[used_keygen]; } AMS_UNREACHABLE_DEFAULT_CASE(); } } size_t GetAcidSignatureKeyModulusSize(ncm::ContentMetaPlatform platform, bool unk_unused) { AMS_UNUSED(unk_unused); switch (platform) { case ncm::ContentMetaPlatform::Nx: return NxAcidSignatureKeyModulusSize; AMS_UNREACHABLE_DEFAULT_CASE(); } } const u8 *GetAcidSignatureKeyPublicExponent() { return AcidSignatureKeyPublicExponent; } } ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_directory_savedata_filesystem.cpp ================================================ [File too large to display: 14.8 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_external_code.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_file_system_proxy_api.cpp ================================================ [File too large to display: 13.7 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp ================================================ [File too large to display: 16.0 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_hierarchical_sha256_storage.cpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_hierarchical_sha256_storage.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_indirect_storage.cpp ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_integrity_romfs_storage.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_integrity_verification_storage.cpp ================================================ [File too large to display: 21.7 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_local_file_system.cpp ================================================ [File too large to display: 79.8 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_lru_list_cache.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_memory_resource_buffer_hold_storage.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp ================================================ [File too large to display: 71.3 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_nca_header.cpp ================================================ [File too large to display: 1020 B] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp ================================================ [File too large to display: 24.1 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_partition_file_system.cpp ================================================ [File too large to display: 21.3 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_partition_file_system_meta.cpp ================================================ [File too large to display: 9.0 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_pooled_buffer.cpp ================================================ [File too large to display: 9.9 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_read_only_block_cache_storage.hpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp ================================================ [File too large to display: 18.7 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_service_context.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_sparse_storage.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_speed_emulation_configuration.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_thread_priority_changer.cpp ================================================ [File too large to display: 948 B] ================================================ FILE: libraries/libstratosphere/source/fssystem/fssystem_utility.cpp ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libstratosphere/source/gc/impl/gc_embedded_data_holder.cpp ================================================ [File too large to display: 16.8 KB] ================================================ FILE: libraries/libstratosphere/source/gc/impl/gc_gc_crypto.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/gpio_driver_api.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_driver_impl.cpp ================================================ [File too large to display: 12.7 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_driver_impl.hpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config.cpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config.hpp ================================================ [File too large to display: 949 B] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config_aula.inc ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config_calcio.inc ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config_hoag.inc ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config_icosa.inc ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_config_iowa.inc ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_wake_pin_config_aula.inc ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_wake_pin_config_calcio.inc ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_wake_pin_config_hoag.inc ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_wake_pin_config_icosa.inc ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_initial_wake_pin_config_iowa.inc ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_internal_pad_map_combination.inc ================================================ [File too large to display: 10.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_register_accessor.hpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_suspend_handler.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_suspend_handler.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_tegra_pad.hpp ================================================ [File too large to display: 24.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/board/nintendo/nx/impl/gpio_wake_pin_config.hpp ================================================ [File too large to display: 863 B] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/gpio_driver_client_api.cpp ================================================ [File too large to display: 877 B] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/gpio_driver_service_api.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/gpio_pad.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/gpio_pad_api.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/impl/gpio_driver_core.cpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/impl/gpio_driver_core.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/driver/impl/gpio_pad_session_impl.cpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/gpio_client_api.cpp ================================================ [File too large to display: 6.7 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/server/gpio_server_api.cpp ================================================ [File too large to display: 983 B] ================================================ FILE: libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/gpio/server/gpio_server_pad_session_impl.hpp ================================================ [File too large to display: 6.8 KB] ================================================ FILE: libraries/libstratosphere/source/hid/hid_api.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/hos/hos_stratosphere_api.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/hos/hos_version_api.cpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/hos/hos_version_api_private.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/hos/hos_version_api_weak_for_unit_test.cpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/htc/server/driver/htc_driver_manager.hpp ================================================ [File too large to display: 974 B] ================================================ FILE: libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.cpp ================================================ [File too large to display: 7.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/driver/htc_htclow_driver.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/driver/htc_i_driver.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htc_service_object.cpp ================================================ [File too large to display: 6.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htc_service_object.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htcmisc_hipc_server.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp ================================================ [File too large to display: 8.5 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htcmisc_manager.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_htcmisc_manager.hpp ================================================ [File too large to display: 873 B] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_observer.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_observer.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/htc_power_state_control.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_server.cpp ================================================ [File too large to display: 6.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_server.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.cpp ================================================ [File too large to display: 9.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_tasks.hpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp ================================================ [File too large to display: 18.0 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp ================================================ [File too large to display: 14.1 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_id_free_list.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_queue.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_task_table.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/htc/server/rpc/htc_rpc_tasks.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/htc_tenv.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/htc_tenv_service.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/htc_tenv_service.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/htc_tenv_service_manager.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/impl/htc_tenv_allocator.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/impl/htc_tenv_allocator.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/impl/htc_tenv_definition_file_info.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/impl/htc_tenv_impl.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/htc/tenv/impl/htc_tenv_impl.hpp ================================================ [File too large to display: 769 B] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_cache_manager.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_client.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_client.hpp ================================================ [File too large to display: 6.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp ================================================ [File too large to display: 56.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp ================================================ [File too large to display: 6.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_directory_service_object.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_file_service_object.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_file_service_object.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.cpp ================================================ [File too large to display: 8.7 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_file_system_service_object.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp ================================================ [File too large to display: 10.8 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_result.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_result_utils.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_working_directory.cpp ================================================ [File too large to display: 980 B] ================================================ FILE: libraries/libstratosphere/source/htcfs/htcfs_working_directory.hpp ================================================ [File too large to display: 810 B] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_packet_factory.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_send_buffer.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp ================================================ [File too large to display: 17.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service_channels.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_settings_holder.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_settings_holder.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state.hpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_json.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_json.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.hpp ================================================ [File too large to display: 869 B] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_driver_manager.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_driver_manager.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_driver_memory_management.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_driver_memory_management.hpp ================================================ [File too large to display: 940 B] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_i_driver.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_discovery_manager.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_discovery_manager.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_discovery_util.cpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_discovery_util.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_driver.cpp ================================================ [File too large to display: 10.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_socket_driver.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_usb_driver.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_usb_driver.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp ================================================ [File too large to display: 20.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_channel.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_channel.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_default_channel_config.hpp ================================================ [File too large to display: 997 B] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_listener.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_listener.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_manager.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_manager.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_manager_holder.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_manager_impl.cpp ================================================ [File too large to display: 7.2 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_manager_impl.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_packet.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_packet_factory.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_packet_factory.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_worker.cpp ================================================ [File too large to display: 7.2 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/htclow_worker.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux.cpp ================================================ [File too large to display: 15.1 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux.hpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp ================================================ [File too large to display: 15.8 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl_map.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl_map.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_global_send_buffer.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_global_send_buffer.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_ring_buffer.cpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_ring_buffer.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp ================================================ [File too large to display: 6.2 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.cpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/htclow/mux/htclow_mux_task_manager.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/client/htcs_session.hpp ================================================ [File too large to display: 865 B] ================================================ FILE: libraries/libstratosphere/source/htcs/client/htcs_session.os.horizon.cpp ================================================ [File too large to display: 17.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/client/htcs_session.os.windows.cpp ================================================ [File too large to display: 1009 B] ================================================ FILE: libraries/libstratosphere/source/htcs/client/htcs_virtual_socket_collection.cpp ================================================ [File too large to display: 27.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/client/htcs_virtual_socket_collection.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/htcs_socket.cpp ================================================ [File too large to display: 27.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_impl.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_impl.hpp ================================================ [File too large to display: 807 B] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_manager.cpp ================================================ [File too large to display: 14.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_manager.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_manager_holder.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.cpp ================================================ [File too large to display: 8.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_manager_impl.hpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_monitor.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_monitor.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_service.cpp ================================================ [File too large to display: 15.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_service.hpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_util.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/htcs_util.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_data_channel_manager.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_accept_task.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_bind_task.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_close_task.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_connect_task.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_fcntl_task.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_listen_task.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_receive_small_task.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_receive_task.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_select_task.cpp ================================================ [File too large to display: 7.3 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_send_small_task.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_send_task.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_shutdown_task.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_signaling_task.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_socket_task.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/impl/rpc/htcs_rpc_tasks.hpp ================================================ [File too large to display: 19.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_hipc_server.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_manager_service_object.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_manager_service_object_deprecated.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_service_object_allocator.hpp ================================================ [File too large to display: 951 B] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.cpp ================================================ [File too large to display: 14.2 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_socket_service_object.hpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/htcs/server/htcs_socket_service_object_deprecated.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_bus_device_map.inc ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/i2c_driver_api.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_bus_accessor.cpp ================================================ [File too large to display: 35.6 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_bus_accessor.hpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_bus_manager.hpp ================================================ [File too large to display: 985 B] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_device_property_manager.hpp ================================================ [File too large to display: 968 B] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_i2c_registers.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/board/nintendo/nx/impl/i2c_i_allocator.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/i2c_driver_bus_api.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/i2c_driver_client_api.cpp ================================================ [File too large to display: 875 B] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/i2c_driver_service_api.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/impl/i2c_driver_core.cpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/impl/i2c_driver_core.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/driver/impl/i2c_i2c_session_impl.cpp ================================================ [File too large to display: 7.9 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/i2c_client_api.cpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/i2c_command_list_formatter.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/impl/i2c_command_list_format.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/server/i2c_server_api.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/server/i2c_server_manager_impl.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/server/i2c_server_manager_impl.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/i2c/server/i2c_server_session_impl.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/init/init_libnx_shim.os.horizon.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/init/init_malloc.cpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/init/init_operator_new.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/init/init_system_module.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/kvdb/kvdb_archive.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libstratosphere/source/kvdb/kvdb_file_key_value_store.cpp ================================================ [File too large to display: 11.3 KB] ================================================ FILE: libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.c ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/ldr/ldr_ams.os.horizon.h ================================================ [File too large to display: 731 B] ================================================ FILE: libraries/libstratosphere/source/ldr/ldr_pm_api.os.horizon.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/ldr/ldr_shell_api.os.horizon.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/lm/impl/lm_log_data_chunk.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/lm/impl/lm_log_packet_header.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/lm/impl/lm_log_packet_transmitter.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/lm/impl/lm_log_packet_transmitter_base.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/lm/impl/lm_log_packet_transmitter_base.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/lm/lm_api.cpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/lm_remote_log_service.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/lm/lm_remote_log_service.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/lm/lm_service_name.hpp ================================================ [File too large to display: 894 B] ================================================ FILE: libraries/libstratosphere/source/lm/sf/lm_i_log_getter.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/sf/lm_i_log_service.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_custom_sink_buffer.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_event_log_transmitter.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_event_log_transmitter.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp ================================================ [File too large to display: 5.9 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_buffer.cpp ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_buffer.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_getter.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_getter.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_getter_impl.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_getter_impl.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.cpp ================================================ [File too large to display: 9.8 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_packet_parser.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_server_proxy.cpp ================================================ [File too large to display: 7.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_server_proxy.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_service_impl.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_log_service_impl.hpp ================================================ [File too large to display: 977 B] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_logger_impl.cpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_logger_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.cpp ================================================ [File too large to display: 12.7 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_sd_card_logger.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_time_util.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/lm/srv/lm_time_util.hpp ================================================ [File too large to display: 744 B] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_common_heap.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.cpp ================================================ [File too large to display: 28.5 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_exp_heap.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.cpp ================================================ [File too large to display: 9.9 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/impl/lmem_impl_unit_heap.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/lmem_common.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/lmem_exp_heap.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/lmem/lmem_unit_heap.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp ================================================ [File too large to display: 8.6 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_api.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp ================================================ [File too large to display: 9.6 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_redirector.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_redirector.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_resolver_impl_base.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_resolver_manager_factory.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_location_resolver_manager_impl.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.cpp ================================================ [File too large to display: 7.6 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_redirect_only_location_resolver_impl.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_registered_data.hpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.cpp ================================================ [File too large to display: 6.4 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_registered_location_resolver_impl.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_remote_location_resolver_impl.hpp ================================================ [File too large to display: 6.7 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_remote_location_resolver_manager_impl.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/lr/lr_remote_registered_location_resolver_impl.hpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_cached_heap.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_central_heap.cpp ================================================ [File too large to display: 15.2 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_platform.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.cpp ================================================ [File too large to display: 21.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_cache.hpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.cpp ================================================ [File too large to display: 60.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.hpp ================================================ [File too large to display: 19.8 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_static.hpp ================================================ [File too large to display: 9.8 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/mem_impl_platform.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.horizon.cpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.linux.cpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.macos.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/mem/impl/mem_impl_platform.os.windows.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libstratosphere/source/mem/mem_standard_allocator.cpp ================================================ [File too large to display: 12.1 KB] ================================================ FILE: libraries/libstratosphere/source/mitm/mitm_pm.os.horizon.c ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/mitm/mitm_pm.os.horizon.h ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/mitm/mitm_pm_api.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_api.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_id_utils.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_info_utils.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_management_utils.cpp ================================================ [File too large to display: 8.4 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_manager_factory.cpp ================================================ [File too large to display: 1011 B] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_manager_factory.hpp ================================================ [File too large to display: 806 B] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_manager_impl.cpp ================================================ [File too large to display: 56.1 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta.cpp ================================================ [File too large to display: 19.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta_database_impl.cpp ================================================ [File too large to display: 21.5 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta_database_impl.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta_database_impl_base.hpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta_type.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_meta_utils.cpp ================================================ [File too large to display: 12.5 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_storage_impl.cpp ================================================ [File too large to display: 35.7 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_storage_impl.hpp ================================================ [File too large to display: 6.8 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_content_storage_impl_base.hpp ================================================ [File too large to display: 6.3 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_extended_data_mapper.hpp ================================================ [File too large to display: 17.2 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_file_mapper_file.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_fs_utils.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_fs_utils.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_host_content_storage_impl.cpp ================================================ [File too large to display: 9.5 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_host_content_storage_impl.hpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_install_task_base.cpp ================================================ [File too large to display: 55.2 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_install_task_data.cpp ================================================ [File too large to display: 14.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_integrated_content_meta_database_impl.cpp ================================================ [File too large to display: 18.4 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_integrated_content_storage_impl.cpp ================================================ [File too large to display: 12.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_make_path.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_memory_report.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_on_memory_content_meta_database_impl.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_on_memory_content_meta_database_impl.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_package_install_task.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_package_install_task_base.cpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_package_system_downgrade_task.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_package_system_update_task.cpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp ================================================ [File too large to display: 9.5 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_placeholder_accessor.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.cpp ================================================ [File too large to display: 12.0 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.hpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_registered_host_content.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp ================================================ [File too large to display: 13.0 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_storage_utils.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/ncm/ncm_submission_package_install_task.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/nim/nim_network_install_manager_api.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/nsd/impl/device/nsd_device.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_address_space_allocator.cpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_address_space_allocator.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_address_space_allocator_forbidden_region.hpp ================================================ [File too large to display: 803 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.generic.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_address_space_allocator_impl.os.horizon.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager.hpp ================================================ [File too large to display: 910 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.horizon.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.linux.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.macos.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager_impl.os.windows.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_aslr_space_manager_types.hpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_cache_impl.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_cache_impl.os.horizon.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_cache_impl.os.linux.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_cache_impl.os.macos.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_cache_impl.os.windows.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_debug_impl.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_disable_counter.os.horizon.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.hpp ================================================ [File too large to display: 881 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.horizon.hpp ================================================ [File too large to display: 786 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.linux.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.macos.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock.os.windows.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_giant_lock_types.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_initialize.os.horizon.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_initialize.os.linux.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_initialize.os.macos.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_initialize.os.windows.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.hpp ================================================ [File too large to display: 931 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_insecure_memory_impl.os.horizon.cpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp ================================================ [File too large to display: 5.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.cpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.horizon.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.cpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.linux.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.cpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.macos.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_inter_process_event_impl.os.windows.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_busy_mutex_impl.os.horizon.hpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.os.horizon.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.os.windows.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_condition_variable_impl.pthread.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.horizon.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.os.windows.hpp ================================================ [File too large to display: 787 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_critical_section_impl.pthread.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_light_event_impl.os.generic.hpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_light_event_impl.os.horizon.hpp ================================================ [File too large to display: 13.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.horizon.hpp ================================================ [File too large to display: 9.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.linux.hpp ================================================ [File too large to display: 722 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.macos.hpp ================================================ [File too large to display: 722 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_internal_rw_busy_mutex_impl.os.windows.hpp ================================================ [File too large to display: 722 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_impl.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.horizon.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.horizon.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.linux.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.macos.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_interrupt_event_target_impl.os.windows.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_io_region_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_io_region_impl.os.horizon.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_io_region_impl.os.windows.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_attribute_impl.hpp ================================================ [File too large to display: 794 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_attribute_impl.os.horizon.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_attribute_impl.os.linux.cpp ================================================ [File too large to display: 874 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_attribute_impl.os.macos.cpp ================================================ [File too large to display: 874 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_attribute_impl.os.windows.cpp ================================================ [File too large to display: 874 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager.cpp ================================================ [File too large to display: 7.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager.hpp ================================================ [File too large to display: 914 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager_impl.os.horizon.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager_impl.os.linux.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager_impl.os.macos.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager_impl.os.windows.hpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_heap_manager_types.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_permission_impl.hpp ================================================ [File too large to display: 796 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_permission_impl.os.horizon.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_permission_impl.os.linux.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_permission_impl.os.macos.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_memory_permission_impl.os.windows.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_message_queue_helper.hpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_base.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_impl.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_event.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_inter_process_event.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.cpp ================================================ [File too large to display: 963 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_message_queue.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_native_handle.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_semaphore.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_thread.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_timer_event.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp ================================================ [File too large to display: 11.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_object_list.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.linux.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.macos.hpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.windows.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_mutex_impl.hpp ================================================ [File too large to display: 818 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_native_handle_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.horizon.hpp ================================================ [File too large to display: 960 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.linux.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.macos.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_native_handle_impl.os.windows.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_code_memory_impl.os.horizon.cpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_handle_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.horizon.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.linux.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.macos.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_handle_impl.os.windows.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_memory_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_process_memory_impl.os.horizon.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_random_impl.hpp ================================================ [File too large to display: 756 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_random_impl.os.horizon.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_random_impl.os.linux.cpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_random_impl.os.macos.cpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_random_impl.os.windows.cpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_resource_manager.cpp ================================================ [File too large to display: 837 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_resource_manager.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager.hpp ================================================ [File too large to display: 849 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.cpp ================================================ [File too large to display: 943 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.horizon.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.linux.cpp ================================================ [File too large to display: 962 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.macos.cpp ================================================ [File too large to display: 962 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rng_manager_impl.os.windows.cpp ================================================ [File too large to display: 962 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rw_lock_impl.hpp ================================================ [File too large to display: 8.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.cpp ================================================ [File too large to display: 10.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.generic.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.horizon.cpp ================================================ [File too large to display: 16.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_rw_lock_target_impl.os.horizon.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_shared_memory_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_shared_memory_impl.os.horizon.cpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager.hpp ================================================ [File too large to display: 870 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.horizon.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.linux.hpp ================================================ [File too large to display: 979 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.macos.hpp ================================================ [File too large to display: 979 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager_impl.os.windows.hpp ================================================ [File too large to display: 983 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_stack_guard_manager_types.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager.cpp ================================================ [File too large to display: 10.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.cpp ================================================ [File too large to display: 9.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.horizon.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.cpp ================================================ [File too large to display: 9.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.os.windows.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.cpp ================================================ [File too large to display: 759 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_impl.pthread.inc ================================================ [File too large to display: 12.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_thread_manager_types.hpp ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager_impl.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager_impl.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.horizon.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager_impl.os.windows.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tick_manager_impl.std_chrono.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.horizon.cpp ================================================ [File too large to display: 993 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.horizon.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.linux.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.macos.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timeout_helper_impl.os.windows.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timer_event_helper.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_timer_event_helper.hpp ================================================ [File too large to display: 972 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tls_manager.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tls_manager.hpp ================================================ [File too large to display: 898 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_tls_manager_types.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_transfer_memory_impl.os.horizon.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_unsafe_memory_impl.hpp ================================================ [File too large to display: 927 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_unsafe_memory_impl.os.horizon.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_utility.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_utility.hpp ================================================ [File too large to display: 738 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager.cpp ================================================ [File too large to display: 14.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager.hpp ================================================ [File too large to display: 852 B] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.horizon.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.linux.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.macos.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager_impl.os.windows.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/impl/os_vamm_manager_types.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_argument.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_barrier.cpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_busy_mutex.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_cache.cpp ================================================ [File too large to display: 928 B] ================================================ FILE: libraries/libstratosphere/source/os/os_condition_variable.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_debug.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_event.cpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_insecure_memory.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_interrupt_event.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_io_region.cpp ================================================ [File too large to display: 6.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_light_event.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_light_message_queue.cpp ================================================ [File too large to display: 11.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_light_semaphore.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_memory_attribute.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_memory_heap.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_memory_permission.cpp ================================================ [File too large to display: 893 B] ================================================ FILE: libraries/libstratosphere/source/os/os_message_queue.cpp ================================================ [File too large to display: 11.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_multiple_wait.cpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_mutex.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_native_handle_api.cpp ================================================ [File too large to display: 896 B] ================================================ FILE: libraries/libstratosphere/source/os/os_process_code_memory.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_process_handle_api.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_process_memory.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_random.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_rw_busy_mutex.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_rw_lock.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_sdk_condition_variable.cpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_sdk_mutex.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_sdk_recursive_mutex.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_sdk_reply_and_receive.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_sdk_thread_local_storage_api.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_semaphore.cpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_shared_memory.cpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_system_event.cpp ================================================ [File too large to display: 6.8 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_thread.cpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_thread_local_storage_api.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_tick.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_timer_event.cpp ================================================ [File too large to display: 9.3 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_transfer_memory.cpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_unsafe_memory.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/os/os_virtual_address_memory.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.generic.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.cpp ================================================ [File too large to display: 8.2 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_info.os.horizon.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_local_region.os.horizon.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_local_region.os.horizon.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/impl/osdbg_types.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/osdbg/osdbg_thread.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/patcher/patcher_api.cpp ================================================ [File too large to display: 12.0 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/pgl_remote_event_observer.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/pgl_shell_api.cpp ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_api.cpp ================================================ [File too large to display: 7.9 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp ================================================ [File too large to display: 20.9 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.cpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_host_utils.cpp ================================================ [File too large to display: 15.8 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_host_utils.hpp ================================================ [File too large to display: 889 B] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: libraries/libstratosphere/source/pgl/srv/pgl_srv_tipc_utils.hpp ================================================ [File too large to display: 776 B] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_board_driver_api.hpp ================================================ [File too large to display: 872 B] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_drive_pad_characters.inc ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_drive_pad_config.inc ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_drive_pad_config_hoag.inc ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_pad_config_aula.inc ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_pad_config_calcio.inc ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_pad_config_hoag.inc ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_pad_config_icosa.inc ================================================ [File too large to display: 10.1 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_initial_pad_config_iowa.inc ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_pad_characters.inc ================================================ [File too large to display: 9.1 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_pad_index.hpp ================================================ [File too large to display: 14.0 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.cpp ================================================ [File too large to display: 24.4 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/board/nintendo/nx/pinmux_platform_pads.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/pinmux_driver_api.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/pinmux/driver/pinmux_select_board_impl.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_ams.os.horizon.c ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_ams.os.horizon.h ================================================ [File too large to display: 833 B] ================================================ FILE: libraries/libstratosphere/source/pm/pm_boot_mode_api.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_dmnt_api.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_info_api.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_info_api_weak.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/pm/pm_shell_api.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/driver/impl/powctl_charger_parameters.board.nintendo_nx.inc ================================================ [File too large to display: 10.1 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.cpp ================================================ [File too large to display: 18.6 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_battery_driver.hpp ================================================ [File too large to display: 9.0 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_board_impl.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_board_impl.hpp ================================================ [File too large to display: 846 B] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_bq24193_driver.cpp ================================================ [File too large to display: 15.9 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_bq24193_driver.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.cpp ================================================ [File too large to display: 14.4 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_charger_driver.hpp ================================================ [File too large to display: 10.3 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_interrupt_event_handler.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_interrupt_event_handler.hpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_max17050_custom_parameters.inc ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_max17050_driver.cpp ================================================ [File too large to display: 29.6 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_max17050_driver.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/board/nintendo/nx/powctl_retry_helper.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/powctl_device_management.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/powctl_device_management.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/powctl_i_power_control_driver.hpp ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/impl/powctl_select_board_driver.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/powctl_battery_api.cpp ================================================ [File too large to display: 18.5 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/powctl_charger_api.cpp ================================================ [File too large to display: 12.7 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/powctl_driver_api.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/powctl/powctl_session_api.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/psc/psc_pm_module.os.horizon.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/psc/psc_remote_pm_module.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/board/nintendo/nx/impl/pwm_impl_pwm_driver_api.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/board/nintendo/nx/impl/pwm_impl_pwm_driver_api.hpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/board/nintendo/nx/impl/pwm_pwm_driver_impl.cpp ================================================ [File too large to display: 9.2 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/board/nintendo/nx/impl/pwm_pwm_driver_impl.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/board/nintendo/nx/pwm_driver_api.cpp ================================================ [File too large to display: 910 B] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/impl/pwm_channel_session_impl.cpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/impl/pwm_channel_session_impl.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/impl/pwm_driver_core.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/impl/pwm_driver_core.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/pwm_driver_channel_api.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/pwm_driver_client_api.cpp ================================================ [File too large to display: 875 B] ================================================ FILE: libraries/libstratosphere/source/pwm/driver/pwm_driver_service_api.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/pwm_api.cpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/server/pwm_server_api.cpp ================================================ [File too large to display: 978 B] ================================================ FILE: libraries/libstratosphere/source/pwm/server/pwm_server_channel_session_impl.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/server/pwm_server_manager_impl.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libstratosphere/source/pwm/server/pwm_server_manager_impl.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/ro/impl/ro_ro_exception_info.os.horizon.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/scs/scs_command_processor.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/scs/scs_server_manager.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/scs/scs_shell.cpp ================================================ [File too large to display: 14.6 KB] ================================================ FILE: libraries/libstratosphere/source/scs/scs_shell_server.cpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libstratosphere/source/scs/scs_tenv.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/service_guard.h ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_configuration_id_impl.hpp ================================================ [File too large to display: 787 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_error_report_impl.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_error_report_impl.hpp ================================================ [File too large to display: 765 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_firmware_version_impl.hpp ================================================ [File too large to display: 784 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_key_value_store.cpp ================================================ [File too large to display: 63.5 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_key_value_store.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_platform_region_impl.hpp ================================================ [File too large to display: 753 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_product_model_impl.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_product_model_impl.hpp ================================================ [File too large to display: 751 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_region_impl.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_region_impl.hpp ================================================ [File too large to display: 749 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_serial_number_impl.hpp ================================================ [File too large to display: 844 B] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_spl.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_spl.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_static_object.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_system_data.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_system_data.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_system_save_data.cpp ================================================ [File too large to display: 17.8 KB] ================================================ FILE: libraries/libstratosphere/source/settings/impl/settings_system_save_data.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/settings/settings_configuration_id.cpp ================================================ [File too large to display: 880 B] ================================================ FILE: libraries/libstratosphere/source/settings/settings_error_report.cpp ================================================ [File too large to display: 997 B] ================================================ FILE: libraries/libstratosphere/source/settings/settings_firmware_version.cpp ================================================ [File too large to display: 876 B] ================================================ FILE: libraries/libstratosphere/source/settings/settings_fwdbg_api.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/settings/settings_platform_region.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/settings/settings_product_model.cpp ================================================ [File too large to display: 945 B] ================================================ FILE: libraries/libstratosphere/source/settings/settings_region.cpp ================================================ [File too large to display: 981 B] ================================================ FILE: libraries/libstratosphere/source/settings/settings_serial_number.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_manager.cpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: libraries/libstratosphere/source/sf/cmif/sf_cmif_domain_service_object.cpp ================================================ [File too large to display: 12.0 KB] ================================================ FILE: libraries/libstratosphere/source/sf/cmif/sf_cmif_inline_context.cpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/sf/cmif/sf_cmif_service_dispatch.cpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: libraries/libstratosphere/source/sf/cmif/sf_cmif_service_object_holder.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.horizon.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_mitm_query_api.hpp ================================================ [File too large to display: 868 B] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_server_domain_session_manager.cpp ================================================ [File too large to display: 10.5 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp ================================================ [File too large to display: 7.8 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp ================================================ [File too large to display: 16.0 KB] ================================================ FILE: libraries/libstratosphere/source/sf/hipc/sf_i_hipc_manager.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/sf/sf_default_allocation_policy.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libstratosphere/source/sf/sf_interface_id_for_debug_enforcement.os.horizon.cpp ================================================ [File too large to display: 9.2 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_ams.os.horizon.c ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_ams.os.horizon.h ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_api.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_manager_api.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_mitm_api.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_utils.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/sm/sm_utils.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/sm/smm_ams.os.horizon.c ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/sm/smm_ams.os.horizon.h ================================================ [File too large to display: 670 B] ================================================ FILE: libraries/libstratosphere/source/socket/impl/socket_allocator.hpp ================================================ [File too large to display: 866 B] ================================================ FILE: libraries/libstratosphere/source/socket/impl/socket_api.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/socket/impl/socket_api.os.horizon.cpp ================================================ [File too large to display: 19.0 KB] ================================================ FILE: libraries/libstratosphere/source/socket/impl/socket_api.os.windows.cpp ================================================ [File too large to display: 28.9 KB] ================================================ FILE: libraries/libstratosphere/source/socket/impl/socket_platform_types_translation.os.windows.cpp ================================================ [File too large to display: 36.3 KB] ================================================ FILE: libraries/libstratosphere/source/socket/socket_api.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libstratosphere/source/spl/impl/spl_api_impl.cpp ================================================ [File too large to display: 42.2 KB] ================================================ FILE: libraries/libstratosphere/source/spl/impl/spl_ctr_drbg.hpp ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libstratosphere/source/spl/impl/spl_device_address_mapper.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/spl/impl/spl_key_slot_cache.hpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.os.generic.cpp ================================================ [File too large to display: 23.8 KB] ================================================ FILE: libraries/libstratosphere/source/spl/smc/spl_secure_monitor_api.os.horizon.cpp ================================================ [File too large to display: 13.8 KB] ================================================ FILE: libraries/libstratosphere/source/spl/spl_api.os.generic.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libstratosphere/source/spl/spl_api.os.horizon.cpp ================================================ [File too large to display: 10.1 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp ================================================ [File too large to display: 1009 B] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_controller_for_debug.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_importer.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_reader.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_profile_update_observer.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_bg_agent.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_for_system_process.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_i_service_getter.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_controller_for_debug_impl.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_controller_for_debug_impl.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer.hpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer_impl.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_importer_impl.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp ================================================ [File too large to display: 21.1 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_reader_impl.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_reader_impl.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_getter.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libstratosphere/source/sprofile/srv/sprofile_srv_types.hpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libstratosphere/source/time/impl/util/time_impl_util_api.cpp ================================================ [File too large to display: 8.7 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_api.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_calendar_time.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_standard_network_system_clock.cpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_standard_steady_clock.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_standard_user_system_clock.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/time/time_timezone_api.cpp ================================================ [File too large to display: 963 B] ================================================ FILE: libraries/libstratosphere/source/updater/updater_api.cpp ================================================ [File too large to display: 29.2 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_bis_management.cpp ================================================ [File too large to display: 10.3 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_bis_management.hpp ================================================ [File too large to display: 9.5 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_bis_save.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_bis_save.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_files.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_files.hpp ================================================ [File too large to display: 935 B] ================================================ FILE: libraries/libstratosphere/source/updater/updater_paths.cpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: libraries/libstratosphere/source/updater/updater_paths.hpp ================================================ [File too large to display: 994 B] ================================================ FILE: libraries/libstratosphere/source/usb/impl/usb_util.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_device.cpp ================================================ [File too large to display: 27.7 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_endpoint.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_interface.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_interface.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_root_session.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_root_session.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_service.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: libraries/libstratosphere/source/usb/usb_remote_ds_service.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libstratosphere/source/util/ini.c ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libstratosphere/source/util/ini.h ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libstratosphere/source/util/lz4.c ================================================ [File too large to display: 104.3 KB] ================================================ FILE: libraries/libstratosphere/source/util/lz4.h ================================================ [File too large to display: 40.3 KB] ================================================ FILE: libraries/libstratosphere/source/util/util_compression.cpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libstratosphere/source/util/util_ini.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: libraries/libstratosphere/source/util/util_uuid_api.cpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libstratosphere/source/wec/wec_api.cpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libstratosphere/stratosphere.specs ================================================ [File too large to display: 139 B] ================================================ FILE: libraries/libvapours/include/vapours/allocator.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/ams/ams_api_version.h ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/ams/ams_fatal_error_context.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/ams/ams_target_firmware.h ================================================ [File too large to display: 12.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/ams_version.h ================================================ [File too large to display: 719 B] ================================================ FILE: libraries/libvapours/include/vapours/assert.hpp ================================================ [File too large to display: 6.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/common.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/compiler.hpp ================================================ [File too large to display: 891 B] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_128_cmac_generator.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_cbc_encryptor_decryptor.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_ccm_encryptor_decryptor.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_ctr_encryptor_decryptor.hpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_decryptor.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_encryptor.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_gcm_encryptor.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_aes_xts_encryptor_decryptor.hpp ================================================ [File too large to display: 6.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_cbc_decryptor.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_cbc_encryptor.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_ccm_decryptor.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_ccm_encryptor.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_cmac_generator.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_csrng.hpp ================================================ [File too large to display: 841 B] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_ctr_decryptor.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_ctr_encryptor.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_gcm_encryptor.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_hmac_generator.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_hmac_sha1_generator.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_hmac_sha256_generator.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_md5_generator.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_memory_clear.hpp ================================================ [File too large to display: 812 B] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_memory_compare.hpp ================================================ [File too large to display: 835 B] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_calculator.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_oaep_decryptor.hpp ================================================ [File too large to display: 5.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_oaep_encryptor.hpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_oaep_sha256_decoder.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_oaep_sha256_decryptor.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_oaep_sha256_encryptor.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_pkcs1_sha256_verifier.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_pkcs1_verifier.hpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_rsa_pss_verifier.hpp ================================================ [File too large to display: 7.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_sha1_generator.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_sha256_generator.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_sha3_generator.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_xts_decryptor.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/crypto_xts_encryptor.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_aes_impl.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_bignum.hpp ================================================ [File too large to display: 7.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_block_cipher.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_cbc_mac_impl.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_cbc_mode_impl.hpp ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_ccm_mode_impl.hpp ================================================ [File too large to display: 11.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_cmac_impl.hpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_ctr_mode_impl.hpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_gcm_mode_impl.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_hash_function.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_hmac_impl.hpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_md5_impl.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_oaep_impl.hpp ================================================ [File too large to display: 6.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pkcs1_impl.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_rsa_pss_impl.hpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_sha1_impl.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_sha256_impl_constexpr.hpp ================================================ [File too large to display: 12.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_sha3_impl.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto/impl/crypto_xts_mode_impl.hpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/crypto.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/dd/dd_cache.hpp ================================================ [File too large to display: 870 B] ================================================ FILE: libraries/libvapours/include/vapours/dd/dd_common_types.hpp ================================================ [File too large to display: 969 B] ================================================ FILE: libraries/libvapours/include/vapours/dd/dd_io_mapping.hpp ================================================ [File too large to display: 996 B] ================================================ FILE: libraries/libvapours/include/vapours/dd.hpp ================================================ [File too large to display: 858 B] ================================================ FILE: libraries/libvapours/include/vapours/defines.hpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/device_code.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/freebsd/tree.hpp ================================================ [File too large to display: 21.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/impl/compiler_impl.clang.hpp ================================================ [File too large to display: 1003 B] ================================================ FILE: libraries/libvapours/include/vapours/impl/compiler_impl.gcc.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/includes.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/literals.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/reg.hpp ================================================ [File too large to display: 20.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/cal_results.hpp ================================================ [File too large to display: 816 B] ================================================ FILE: libraries/libvapours/include/vapours/results/capsrv_results.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/creport_results.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/cs_results.hpp ================================================ [File too large to display: 907 B] ================================================ FILE: libraries/libvapours/include/vapours/results/dd_results.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/ddsf_results.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/debug_results.hpp ================================================ [File too large to display: 912 B] ================================================ FILE: libraries/libvapours/include/vapours/results/dmnt_results.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/erpt_results.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/err_results.hpp ================================================ [File too large to display: 934 B] ================================================ FILE: libraries/libvapours/include/vapours/results/exosphere_results.hpp ================================================ [File too large to display: 995 B] ================================================ FILE: libraries/libvapours/include/vapours/results/fatal_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/fs_results.hpp ================================================ [File too large to display: 47.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/gpio_results.hpp ================================================ [File too large to display: 1009 B] ================================================ FILE: libraries/libvapours/include/vapours/results/hipc_results.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/htc_results.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/htcfs_results.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/htclow_results.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/htcs_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/i2c_results.hpp ================================================ [File too large to display: 1008 B] ================================================ FILE: libraries/libvapours/include/vapours/results/kvdb_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/loader_results.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/lr_results.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/ncm_results.hpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/nim_results.hpp ================================================ [File too large to display: 826 B] ================================================ FILE: libraries/libvapours/include/vapours/results/ns_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/os_results.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/osdbg_results.hpp ================================================ [File too large to display: 885 B] ================================================ FILE: libraries/libvapours/include/vapours/results/pcv_results.hpp ================================================ [File too large to display: 818 B] ================================================ FILE: libraries/libvapours/include/vapours/results/pgl_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/pm_results.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/powctl_results.hpp ================================================ [File too large to display: 976 B] ================================================ FILE: libraries/libvapours/include/vapours/results/psc_results.hpp ================================================ [File too large to display: 871 B] ================================================ FILE: libraries/libvapours/include/vapours/results/pwm_results.hpp ================================================ [File too large to display: 818 B] ================================================ FILE: libraries/libvapours/include/vapours/results/results_common.hpp ================================================ [File too large to display: 30.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/ro_results.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/scs_results.hpp ================================================ [File too large to display: 879 B] ================================================ FILE: libraries/libvapours/include/vapours/results/sdmmc_results.hpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/settings_results.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/sf_results.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/sm_results.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/socket_results.hpp ================================================ [File too large to display: 834 B] ================================================ FILE: libraries/libvapours/include/vapours/results/spl_results.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/sprofile_results.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/svc_results.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/time_results.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/tipc_results.hpp ================================================ [File too large to display: 977 B] ================================================ FILE: libraries/libvapours/include/vapours/results/tma_results.hpp ================================================ [File too large to display: 808 B] ================================================ FILE: libraries/libvapours/include/vapours/results/updater_results.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/usb_results.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/results/vi_results.hpp ================================================ [File too large to display: 922 B] ================================================ FILE: libraries/libvapours/include/vapours/results.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc/sdmmc_common.hpp ================================================ [File too large to display: 3.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc/sdmmc_gc_asic.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc/sdmmc_mmc.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc/sdmmc_sd_card.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/sdmmc.hpp ================================================ [File too large to display: 1011 B] ================================================ FILE: libraries/libvapours/include/vapours/span.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/arch/arm/svc_thread_local_region.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/arch/arm64/svc_thread_local_region.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/board/generic/svc_device_name.hpp ================================================ [File too large to display: 854 B] ================================================ FILE: libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_device_name.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_hardware_constants.hpp ================================================ [File too large to display: 798 B] ================================================ FILE: libraries/libvapours/include/vapours/svc/board/nintendo/nx/svc_io_pool_type.hpp ================================================ [File too large to display: 870 B] ================================================ FILE: libraries/libvapours/include/vapours/svc/board/qemu/virt/svc_hardware_constants.hpp ================================================ [File too large to display: 796 B] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_code_generator.hpp ================================================ [File too large to display: 13.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_common.hpp ================================================ [File too large to display: 6.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_kernel_svc_wrapper.hpp ================================================ [File too large to display: 31.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout.hpp ================================================ [File too large to display: 16.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_layout_conversion.hpp ================================================ [File too large to display: 28.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_meta_code.hpp ================================================ [File too large to display: 10.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/impl/svc_codegen_impl_parameter.hpp ================================================ [File too large to display: 6.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/codegen/svc_codegen_kernel_svc_wrapper.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/ipc/svc_message_buffer.hpp ================================================ [File too large to display: 27.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_codegen.hpp ================================================ [File too large to display: 891 B] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_common.hpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_definition_macro.hpp ================================================ [File too large to display: 41.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_definitions.hpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_memory_map.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_select_device_name.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_select_hardware_constants.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_select_io_pool_type.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_select_thread_local_region.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_tick.hpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types_base.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types_common.hpp ================================================ [File too large to display: 22.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types_dd.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types_dmnt.hpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_types_priv.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc/svc_version.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/svc.hpp ================================================ [File too large to display: 993 B] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_ahb_arbc.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_apb_misc.hpp ================================================ [File too large to display: 7.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_avp_cache.hpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_clkrst.hpp ================================================ [File too large to display: 29.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_emc.hpp ================================================ [File too large to display: 36.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_evp.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_flow_ctlr.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_i2c.hpp ================================================ [File too large to display: 8.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_i2s.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_ictlr.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_mc.hpp ================================================ [File too large to display: 38.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_mipi_cal.hpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_mselect.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_pg_up.hpp ================================================ [File too large to display: 932 B] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_pinmux.hpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_pmc.hpp ================================================ [File too large to display: 32.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_pwm.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_sb.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_sysctr0.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra/tegra_timer.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/tegra.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/timespan.hpp ================================================ [File too large to display: 7.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/types.hpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/arch/arm64/util_atomic.hpp ================================================ [File too large to display: 27.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/arch/generic/util_atomic.hpp ================================================ [File too large to display: 11.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/impl/util_available_index_finder.hpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/impl/util_enable_copy_move.hpp ================================================ [File too large to display: 7.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_aligned_buffer.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_alignment.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_atomic.hpp ================================================ [File too large to display: 872 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_bitflagset.hpp ================================================ [File too large to display: 9.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_bitpack.hpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_bitset.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_bitutil.hpp ================================================ [File too large to display: 10.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_bounded_map.hpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_character_encoding.hpp ================================================ [File too large to display: 7.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_endian.hpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_enum.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_exchange.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_fixed_map.hpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_fixed_set.hpp ================================================ [File too large to display: 1005 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_fixed_tree.hpp ================================================ [File too large to display: 40.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_format_string.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_fourcc.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_function_local_static.hpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_i_function.hpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_in_place.hpp ================================================ [File too large to display: 808 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_int_util.hpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_intrusive_list.hpp ================================================ [File too large to display: 24.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp ================================================ [File too large to display: 24.6 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_mutex_utils.hpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_optional.hpp ================================================ [File too large to display: 36.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_overlap.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_parent_of_member.hpp ================================================ [File too large to display: 9.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_pointer_util.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_range.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_scope_guard.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_size.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_specialization_of.hpp ================================================ [File too large to display: 993 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_string_util.hpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_string_view.hpp ================================================ [File too large to display: 16.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_timer.hpp ================================================ [File too large to display: 798 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_tinymt.hpp ================================================ [File too large to display: 9.7 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_type_traits.hpp ================================================ [File too large to display: 13.3 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_typed_storage.hpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_utf8_string_util.hpp ================================================ [File too large to display: 863 B] ================================================ FILE: libraries/libvapours/include/vapours/util/util_uuid.hpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: libraries/libvapours/include/vapours/util/util_variadic.hpp ================================================ [File too large to display: 7.4 KB] ================================================ FILE: libraries/libvapours/include/vapours/util.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: libraries/libvapours/include/vapours.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_aes_cbc_encryptor_decryptor.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_aes_ctr_encryptor_decryptor.cpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_hmac_sha1_generator.cpp ================================================ [File too large to display: 966 B] ================================================ FILE: libraries/libvapours/source/crypto/crypto_hmac_sha256_generator.cpp ================================================ [File too large to display: 970 B] ================================================ FILE: libraries/libvapours/source/crypto/crypto_md5_generator.cpp ================================================ [File too large to display: 902 B] ================================================ FILE: libraries/libvapours/source/crypto/crypto_memory_clear.cpp ================================================ [File too large to display: 885 B] ================================================ FILE: libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_memory_compare.arch.arm64.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_memory_compare.arch.generic.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/source/crypto/crypto_sha1_generator.cpp ================================================ [File too large to display: 904 B] ================================================ FILE: libraries/libvapours/source/crypto/crypto_sha256_generator.cpp ================================================ [File too large to display: 910 B] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.arm64.cpp ================================================ [File too large to display: 19.0 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.cpp ================================================ [File too large to display: 24.3 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_aes_impl.arch.x64.hpp ================================================ [File too large to display: 863 B] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_bignum.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_bignum_operations.cpp ================================================ [File too large to display: 16.4 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_bignum_operations_asm.arch.arm64.s ================================================ [File too large to display: 7.3 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_cbc_mac_impl.arch.generic.cpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_cbc_mac_impl.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.arm64.cpp ================================================ [File too large to display: 25.6 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_ctr_mode_impl.arch.x64.cpp ================================================ [File too large to display: 13.4 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_gcm_mode_impl.arch.arm64.cpp ================================================ [File too large to display: 10.9 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_md5_impl.cpp ================================================ [File too large to display: 9.3 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.arm64.cpp ================================================ [File too large to display: 8.9 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_sha1_impl.arch.generic.cpp ================================================ [File too large to display: 7.3 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.arm64.cpp ================================================ [File too large to display: 15.6 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_sha256_impl.arch.generic.cpp ================================================ [File too large to display: 9.2 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_sha3_impl.cpp ================================================ [File too large to display: 8.5 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_update_impl.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_xts_mode_impl.arch.arm64.cpp ================================================ [File too large to display: 52.6 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_xts_mode_impl.arch.generic.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: libraries/libvapours/source/crypto/impl/crypto_xts_mode_impl.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: libraries/libvapours/source/dd/dd_cache.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: libraries/libvapours/source/dd/dd_io_mapping.os.horizon.cpp ================================================ [File too large to display: 8.2 KB] ================================================ FILE: libraries/libvapours/source/dd/impl/dd_cache_impl.os.horizon.hpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: libraries/libvapours/source/dd/impl/dd_cache_impl.os.linux.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libvapours/source/dd/impl/dd_cache_impl.os.macos.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libvapours/source/dd/impl/dd_cache_impl.os.windows.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/source/dd/impl/dd_select_cache_impl.hpp ================================================ [File too large to display: 1023 B] ================================================ FILE: libraries/libvapours/source/result/result_get_name.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_base_device_accessor.cpp ================================================ [File too large to display: 23.2 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_base_device_accessor.hpp ================================================ [File too large to display: 19.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.board.nintendo_nx.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.pcv.board.nintendo_nx.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.pcv.board.nintendo_nx.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.reg.board.nintendo_nx.cpp ================================================ [File too large to display: 18.8 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_clock_reset_controller.reg.board.nintendo_nx.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp ================================================ [File too large to display: 12.6 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.cpp ================================================ [File too large to display: 11.9 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_gc_asic_device_accessor.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_i_device_accessor.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_i_host_controller.hpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.cpp ================================================ [File too large to display: 43.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_io_impl.board.nintendo_nx.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp ================================================ [File too large to display: 26.9 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.hpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.board.nintendo_nx.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_gc_asic0.hpp ================================================ [File too large to display: 1004 B] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.board.nintendo_nx.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_mmc0.hpp ================================================ [File too large to display: 985 B] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.board.nintendo_nx.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.hpp ================================================ [File too large to display: 1004 B] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.cpp ================================================ [File too large to display: 41.0 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.hpp ================================================ [File too large to display: 8.8 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.cpp ================================================ [File too large to display: 47.8 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp ================================================ [File too large to display: 7.2 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_registers.hpp ================================================ [File too large to display: 12.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sdmmc_controller.board.nintendo_nx.cpp ================================================ [File too large to display: 55.3 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_sdmmc_controller.board.nintendo_nx.hpp ================================================ [File too large to display: 29.2 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_select_sdmmc_controller.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_timer.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/impl/sdmmc_timer.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/sdmmc_common.cpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/sdmmc_gc_asic.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/sdmmc_mmc.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: libraries/libvapours/source/sdmmc/sdmmc_sd_card.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: libraries/libvapours/source/test/test_intrusive_red_black_tree.cpp ================================================ [File too large to display: 7.8 KB] ================================================ FILE: libraries/libvapours/source/util/util_format_string.cpp ================================================ [File too large to display: 19.7 KB] ================================================ FILE: libraries/libvapours/source/util/util_utf8_string_util.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: mesosphere/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: mesosphere/build_mesosphere.py ================================================ [File too large to display: 2.8 KB] ================================================ FILE: mesosphere/kernel/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: mesosphere/kernel/kernel.ld ================================================ [File too large to display: 4.8 KB] ================================================ FILE: mesosphere/kernel/kernel.mk ================================================ [File too large to display: 4.6 KB] ================================================ FILE: mesosphere/kernel/kernel.specs ================================================ [File too large to display: 208 B] ================================================ FILE: mesosphere/kernel/source/arch/arm64/exception_vectors.s ================================================ [File too large to display: 4.1 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp ================================================ [File too large to display: 42.3 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/init/start.s ================================================ [File too large to display: 19.6 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/kern_exception_handlers_asm.s ================================================ [File too large to display: 25.5 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/kern_k_scheduler_asm.s ================================================ [File too large to display: 10.7 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/kern_k_thread_context_asm.s ================================================ [File too large to display: 4.2 KB] ================================================ FILE: mesosphere/kernel/source/arch/arm64/svc/kern_svc_tables_asm.s ================================================ [File too large to display: 1.2 KB] ================================================ FILE: mesosphere/kernel/source/kern_kernel_instantiations.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: mesosphere/kernel/source/libc/arch/arm64/asmdefs.h ================================================ [File too large to display: 619 B] ================================================ FILE: mesosphere/kernel/source/libc/arch/arm64/memcmp.arch.arm64.s ================================================ [File too large to display: 3.1 KB] ================================================ FILE: mesosphere/kernel/source/libc/arch/arm64/memcpy.arch.arm64.s ================================================ [File too large to display: 6.3 KB] ================================================ FILE: mesosphere/kernel/source/libc/arch/arm64/memset.arch.arm64.s ================================================ [File too large to display: 3.8 KB] ================================================ FILE: mesosphere/kernel/source/libc/kern_env.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: mesosphere/kernel/source/libc/kern_libc_config.arch.arm64.h ================================================ [File too large to display: 940 B] ================================================ FILE: mesosphere/kernel/source/libc/kern_libc_config.h ================================================ [File too large to display: 789 B] ================================================ FILE: mesosphere/kernel/source/libc/kern_libc_generic.c ================================================ [File too large to display: 15.9 KB] ================================================ FILE: mesosphere/kernel_ldr/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: mesosphere/kernel_ldr/kernel_ldr.ld ================================================ [File too large to display: 4.6 KB] ================================================ FILE: mesosphere/kernel_ldr/kernel_ldr.mk ================================================ [File too large to display: 4.6 KB] ================================================ FILE: mesosphere/kernel_ldr/kernel_ldr.specs ================================================ [File too large to display: 212 B] ================================================ FILE: mesosphere/kernel_ldr/source/arch/arm64/exceptions.s ================================================ [File too large to display: 4.2 KB] ================================================ FILE: mesosphere/kernel_ldr/source/arch/arm64/kern_init_loader_asm.s ================================================ [File too large to display: 1.7 KB] ================================================ FILE: mesosphere/kernel_ldr/source/arch/arm64/start.s ================================================ [File too large to display: 4.8 KB] ================================================ FILE: mesosphere/kernel_ldr/source/board/nintendo/nx/kern_init_loader_board_setup.cpp ================================================ [File too large to display: 818 B] ================================================ FILE: mesosphere/kernel_ldr/source/kern_init_loader.cpp ================================================ [File too large to display: 17.1 KB] ================================================ FILE: mesosphere/kernel_ldr/source/kern_init_loader_asm.hpp ================================================ [File too large to display: 973 B] ================================================ FILE: mesosphere/kernel_ldr/source/kern_init_loader_board_default_setup.arch.arm64.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: mesosphere/kernel_ldr/source/kern_init_loader_board_setup.hpp ================================================ [File too large to display: 843 B] ================================================ FILE: mesosphere/kernel_ldr/source/kern_loader_panic.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: mesosphere/kernel_ldr/source/libc/kern_libc_config.arch.arm64.h ================================================ [File too large to display: 940 B] ================================================ FILE: mesosphere/kernel_ldr/source/libc/kern_libc_config.h ================================================ [File too large to display: 789 B] ================================================ FILE: mesosphere/kernel_ldr/source/libc/kern_libc_generic.c ================================================ [File too large to display: 15.9 KB] ================================================ FILE: mesosphere/mesosphere.mk ================================================ [File too large to display: 2.6 KB] ================================================ FILE: stratosphere/LogManager/LogManager.json ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/LogManager/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/LogManager/source/lm_main.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/LogManager/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/TioServer/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/TioServer/TioServer.json ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server.cpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server.hpp ================================================ [File too large to display: 789 B] ================================================ FILE: stratosphere/TioServer/source/tio_file_server_htcs_server.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server_htcs_server.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server_packet.hpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server_processor.cpp ================================================ [File too large to display: 33.7 KB] ================================================ FILE: stratosphere/TioServer/source/tio_file_server_processor.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/TioServer/source/tio_main.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/TioServer/source/tio_sd_card_observer.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/TioServer/source/tio_sd_card_observer.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/TioServer/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/ams_mitm/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/ams_mitm/ams_mitm.json ================================================ [File too large to display: 3.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp ================================================ [File too large to display: 10.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_initialization.cpp ================================================ [File too large to display: 12.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_initialization.hpp ================================================ [File too large to display: 786 B] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_main.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_module.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_module_management.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_module_management.hpp ================================================ [File too large to display: 759 B] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.cpp ================================================ [File too large to display: 31.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/amsmitm_prodinfo_utils.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_module.cpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_module.hpp ================================================ [File too large to display: 831 B] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.cpp ================================================ [File too large to display: 6.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.cpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.hpp ================================================ [File too large to display: 827 B] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_debug.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_debug.hpp ================================================ [File too large to display: 844 B] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_host_redirection.cpp ================================================ [File too large to display: 16.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_host_redirection.hpp ================================================ [File too large to display: 848 B] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_module.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_module.hpp ================================================ [File too large to display: 855 B] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.cpp ================================================ [File too large to display: 10.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/dnsmitm_resolver_impl.hpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_addrinfo.cpp ================================================ [File too large to display: 16.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_hostent.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_in_addr.cpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_ints.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_4.cpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_sockaddrin_6.cpp ================================================ [File too large to display: 4.6 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/serializer/serializer_impls_string.cpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h ================================================ [File too large to display: 894 B] ================================================ FILE: stratosphere/ams_mitm/source/dns_mitm/socket_allocator.hpp ================================================ [File too large to display: 810 B] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.cpp ================================================ [File too large to display: 20.8 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fs_mitm_service.hpp ================================================ [File too large to display: 6.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fs_shim.c ================================================ [File too large to display: 3.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fs_shim.h ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.cpp ================================================ [File too large to display: 12.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp ================================================ [File too large to display: 7.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.cpp ================================================ [File too large to display: 4.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_calibration_binary_storage.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.cpp ================================================ [File too large to display: 18.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_layered_romfs_storage.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_module.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_module.hpp ================================================ [File too large to display: 836 B] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_readonly_layered_filesystem.hpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp ================================================ [File too large to display: 49.9 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.hpp ================================================ [File too large to display: 13.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_save_utils.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/fsmitm_save_utils.hpp ================================================ [File too large to display: 916 B] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/memlet/memlet.c ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/memlet/memlet.h ================================================ [File too large to display: 927 B] ================================================ FILE: stratosphere/ams_mitm/source/fs_mitm/memlet/service_guard.h ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/mitm_pm/mitm_pm_module.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/ams_mitm/source/mitm_pm/mitm_pm_module.hpp ================================================ [File too large to display: 836 B] ================================================ FILE: stratosphere/ams_mitm/source/mitm_pm/mitm_pm_service.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/mitm_pm/mitm_pm_service.hpp ================================================ [File too large to display: 946 B] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_am_mitm_service.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_am_mitm_service.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_shim.c ================================================ [File too large to display: 4.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_shim.h ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_web_mitm_service.cpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/ns_web_mitm_service.hpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/nsmitm_module.cpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/ns_mitm/nsmitm_module.hpp ================================================ [File too large to display: 848 B] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/set_mitm_service.cpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/set_mitm_service.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/set_shim.c ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/set_shim.h ================================================ [File too large to display: 368 B] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setmitm_module.cpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setmitm_module.hpp ================================================ [File too large to display: 841 B] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.cpp ================================================ [File too large to display: 12.5 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setsys_mitm_service.hpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setsys_shim.c ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/setsys_shim.h ================================================ [File too large to display: 508 B] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/settings_fwdbg_api_override.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.cpp ================================================ [File too large to display: 20.2 KB] ================================================ FILE: stratosphere/ams_mitm/source/set_mitm/settings_sd_kvs.hpp ================================================ [File too large to display: 999 B] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_apply_manager.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_apply_manager.hpp ================================================ [File too large to display: 990 B] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_async_impl.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_async_impl.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_async_thread_allocator.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_async_thread_allocator.hpp ================================================ [File too large to display: 806 B] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.cpp ================================================ [File too large to display: 12.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_fs_utils.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_module.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_module.hpp ================================================ [File too large to display: 846 B] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_service.cpp ================================================ [File too large to display: 22.8 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_service.hpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_thread_allocator.cpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/ams_mitm/source/sysupdater/sysupdater_thread_allocator.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/ams_mitm/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/boot/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/boot/boot.json ================================================ [File too large to display: 5.3 KB] ================================================ FILE: stratosphere/boot/source/api_overrides/pcv_clkrst_api_for_boot.board.nintendo_nx.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: stratosphere/boot/source/api_overrides/regulator_api_for_boot.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_driver.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_icon_charging.inc ================================================ [File too large to display: 26.2 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_icon_charging_red.inc ================================================ [File too large to display: 26.3 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_icon_low.inc ================================================ [File too large to display: 18.0 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_icons.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: stratosphere/boot/source/boot_battery_icons.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/boot/source/boot_boot_reason.cpp ================================================ [File too large to display: 3.2 KB] ================================================ FILE: stratosphere/boot/source/boot_boot_reason.hpp ================================================ [File too large to display: 802 B] ================================================ FILE: stratosphere/boot/source/boot_change_voltage.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/boot/source/boot_change_voltage.hpp ================================================ [File too large to display: 740 B] ================================================ FILE: stratosphere/boot/source/boot_charger_driver.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: stratosphere/boot/source/boot_check_battery.cpp ================================================ [File too large to display: 23.1 KB] ================================================ FILE: stratosphere/boot/source/boot_check_battery.hpp ================================================ [File too large to display: 734 B] ================================================ FILE: stratosphere/boot/source/boot_check_clock.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: stratosphere/boot/source/boot_check_clock.hpp ================================================ [File too large to display: 726 B] ================================================ FILE: stratosphere/boot/source/boot_clock_initial_configuration.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/boot/source/boot_clock_initial_configuration.hpp ================================================ [File too large to display: 744 B] ================================================ FILE: stratosphere/boot/source/boot_display.cpp ================================================ [File too large to display: 33.2 KB] ================================================ FILE: stratosphere/boot/source/boot_display.hpp ================================================ [File too large to display: 939 B] ================================================ FILE: stratosphere/boot/source/boot_display_config.inc ================================================ [File too large to display: 38.8 KB] ================================================ FILE: stratosphere/boot/source/boot_driver_management.cpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/boot/source/boot_driver_management.hpp ================================================ [File too large to display: 831 B] ================================================ FILE: stratosphere/boot/source/boot_fan_enable.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/boot/source/boot_fan_enable.hpp ================================================ [File too large to display: 734 B] ================================================ FILE: stratosphere/boot/source/boot_i2c_utils.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: stratosphere/boot/source/boot_i2c_utils.hpp ================================================ [File too large to display: 1.0 KB] ================================================ FILE: stratosphere/boot/source/boot_main.cpp ================================================ [File too large to display: 6.8 KB] ================================================ FILE: stratosphere/boot/source/boot_pinmux_initial_configuration.cpp ================================================ [File too large to display: 958 B] ================================================ FILE: stratosphere/boot/source/boot_pinmux_initial_configuration.hpp ================================================ [File too large to display: 745 B] ================================================ FILE: stratosphere/boot/source/boot_pmic_driver.cpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: stratosphere/boot/source/boot_pmic_driver.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/boot/source/boot_power_utils.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: stratosphere/boot/source/boot_power_utils.hpp ================================================ [File too large to display: 916 B] ================================================ FILE: stratosphere/boot/source/boot_registers_di.hpp ================================================ [File too large to display: 11.5 KB] ================================================ FILE: stratosphere/boot/source/boot_repair_boot_images.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/boot/source/boot_repair_boot_images.hpp ================================================ [File too large to display: 740 B] ================================================ FILE: stratosphere/boot/source/boot_rtc_driver.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/boot/source/boot_rtc_driver.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/boot/source/boot_splash_screen.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/boot/source/boot_splash_screen.hpp ================================================ [File too large to display: 732 B] ================================================ FILE: stratosphere/boot/source/boot_splash_screen_notext.inc ================================================ [File too large to display: 424.2 KB] ================================================ FILE: stratosphere/boot/source/boot_splash_screen_text.inc ================================================ [File too large to display: 708.4 KB] ================================================ FILE: stratosphere/boot/system_module.mk ================================================ [File too large to display: 5.3 KB] ================================================ FILE: stratosphere/boot2/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/boot2/boot2.json ================================================ [File too large to display: 3.0 KB] ================================================ FILE: stratosphere/boot2/source/boot2_main.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/boot2/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/creport/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/creport/creport.json ================================================ [File too large to display: 4.1 KB] ================================================ FILE: stratosphere/creport/source/creport_crash_report.cpp ================================================ [File too large to display: 19.5 KB] ================================================ FILE: stratosphere/creport/source/creport_crash_report.hpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: stratosphere/creport/source/creport_main.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: stratosphere/creport/source/creport_modules.cpp ================================================ [File too large to display: 18.0 KB] ================================================ FILE: stratosphere/creport/source/creport_modules.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: stratosphere/creport/source/creport_scoped_file.cpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: stratosphere/creport/source/creport_scoped_file.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: stratosphere/creport/source/creport_threads.cpp ================================================ [File too large to display: 12.9 KB] ================================================ FILE: stratosphere/creport/source/creport_threads.hpp ================================================ [File too large to display: 4.4 KB] ================================================ FILE: stratosphere/creport/source/creport_utils.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/creport/source/creport_utils.hpp ================================================ [File too large to display: 791 B] ================================================ FILE: stratosphere/creport/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/cs/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/cs/cs.json ================================================ [File too large to display: 2.8 KB] ================================================ FILE: stratosphere/cs/source/cs_main.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: stratosphere/cs/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/dmnt/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/dmnt/dmnt.json ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/dmnt_cheat_service.cpp ================================================ [File too large to display: 7.3 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/dmnt_cheat_service.hpp ================================================ [File too large to display: 8.6 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.cpp ================================================ [File too large to display: 56.1 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_api.hpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.cpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_debug_events_manager.hpp ================================================ [File too large to display: 823 B] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp ================================================ [File too large to display: 75.5 KB] ================================================ FILE: stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.hpp ================================================ [File too large to display: 11.2 KB] ================================================ FILE: stratosphere/dmnt/source/dmnt_main.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: stratosphere/dmnt/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/dmnt.gen2/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/dmnt.gen2/dmnt.gen2.json ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_breakpoint_manager.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_breakpoint_manager.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_breakpoint_manager_base.cpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_breakpoint_manager_base.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_debug_log.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_debug_log.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_debug_process.cpp ================================================ [File too large to display: 23.7 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_debug_process.hpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_io.cpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_packet_io.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_server.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_server.hpp ================================================ [File too large to display: 734 B] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.cpp ================================================ [File too large to display: 108.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_server_impl.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_gdb_signal.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_hardware_breakpoint.cpp ================================================ [File too large to display: 10.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_hardware_breakpoint.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_hardware_watchpoint.cpp ================================================ [File too large to display: 6.3 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_hardware_watchpoint.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_main.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_module_definition.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_software_breakpoint.cpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_software_breakpoint.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_layer.cpp ================================================ [File too large to display: 7.5 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_layer.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_receive_buffer.cpp ================================================ [File too large to display: 4.0 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_receive_buffer.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_session.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: stratosphere/dmnt.gen2/source/dmnt2_transport_session.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: stratosphere/dmnt.gen2/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/eclct.stub/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/eclct.stub/eclct.stub.json ================================================ [File too large to display: 3.8 KB] ================================================ FILE: stratosphere/eclct.stub/source/eclct_stub.cpp ================================================ [File too large to display: 898 B] ================================================ FILE: stratosphere/eclct.stub/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/erpt/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/erpt/erpt.json ================================================ [File too large to display: 2.8 KB] ================================================ FILE: stratosphere/erpt/source/erpt_main.cpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: stratosphere/erpt/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/fatal/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/fatal/fatal.json ================================================ [File too large to display: 3.6 KB] ================================================ FILE: stratosphere/fatal/source/fatal_ams_logo.inc ================================================ [File too large to display: 165.9 KB] ================================================ FILE: stratosphere/fatal/source/fatal_config.cpp ================================================ [File too large to display: 5.6 KB] ================================================ FILE: stratosphere/fatal/source/fatal_config.hpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/fatal/source/fatal_debug.cpp ================================================ [File too large to display: 13.1 KB] ================================================ FILE: stratosphere/fatal/source/fatal_debug.hpp ================================================ [File too large to display: 791 B] ================================================ FILE: stratosphere/fatal/source/fatal_event_manager.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/fatal/source/fatal_event_manager.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/fatal/source/fatal_font.cpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: stratosphere/fatal/source/fatal_font.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/fatal/source/fatal_main.cpp ================================================ [File too large to display: 7.2 KB] ================================================ FILE: stratosphere/fatal/source/fatal_repair.cpp ================================================ [File too large to display: 4.2 KB] ================================================ FILE: stratosphere/fatal/source/fatal_repair.hpp ================================================ [File too large to display: 739 B] ================================================ FILE: stratosphere/fatal/source/fatal_scoped_file.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: stratosphere/fatal/source/fatal_scoped_file.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: stratosphere/fatal/source/fatal_service.cpp ================================================ [File too large to display: 8.7 KB] ================================================ FILE: stratosphere/fatal/source/fatal_service.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/fatal/source/fatal_service_for_self.hpp ================================================ [File too large to display: 758 B] ================================================ FILE: stratosphere/fatal/source/fatal_task.cpp ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_clock.cpp ================================================ [File too large to display: 2.8 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_clock.hpp ================================================ [File too large to display: 763 B] ================================================ FILE: stratosphere/fatal/source/fatal_task_error_report.cpp ================================================ [File too large to display: 9.2 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_error_report.hpp ================================================ [File too large to display: 763 B] ================================================ FILE: stratosphere/fatal/source/fatal_task_power.cpp ================================================ [File too large to display: 8.9 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_power.hpp ================================================ [File too large to display: 891 B] ================================================ FILE: stratosphere/fatal/source/fatal_task_screen.cpp ================================================ [File too large to display: 25.3 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_screen.hpp ================================================ [File too large to display: 821 B] ================================================ FILE: stratosphere/fatal/source/fatal_task_sound.cpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: stratosphere/fatal/source/fatal_task_sound.hpp ================================================ [File too large to display: 761 B] ================================================ FILE: stratosphere/fatal/source/stb_truetype.h ================================================ [File too large to display: 187.2 KB] ================================================ FILE: stratosphere/fatal/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/fs/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/fs/fs.json ================================================ [File too large to display: 2.8 KB] ================================================ FILE: stratosphere/fs/source/fs_main.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/fs/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/htc/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/htc/htc.json ================================================ [File too large to display: 3.0 KB] ================================================ FILE: stratosphere/htc/source/htc_main.cpp ================================================ [File too large to display: 8.9 KB] ================================================ FILE: stratosphere/htc/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/jpegdec/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/jpegdec/jpegdec.json ================================================ [File too large to display: 3.1 KB] ================================================ FILE: stratosphere/jpegdec/source/jpegdec_environment.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/jpegdec/source/jpegdec_main.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: stratosphere/jpegdec/source/jpegdec_memory_management.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/jpegdec/source/jpegdec_memory_management.hpp ================================================ [File too large to display: 724 B] ================================================ FILE: stratosphere/jpegdec/system_module.mk ================================================ [File too large to display: 5.7 KB] ================================================ FILE: stratosphere/loader/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/loader/loader.json ================================================ [File too large to display: 4.1 KB] ================================================ FILE: stratosphere/loader/source/ldr_argument_store.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: stratosphere/loader/source/ldr_argument_store.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: stratosphere/loader/source/ldr_capabilities.cpp ================================================ [File too large to display: 20.1 KB] ================================================ FILE: stratosphere/loader/source/ldr_capabilities.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/loader/source/ldr_content_management.cpp ================================================ [File too large to display: 7.0 KB] ================================================ FILE: stratosphere/loader/source/ldr_content_management.hpp ================================================ [File too large to display: 6.6 KB] ================================================ FILE: stratosphere/loader/source/ldr_development_manager.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: stratosphere/loader/source/ldr_development_manager.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/loader/source/ldr_embedded_usb_patches.inc ================================================ [File too large to display: 5.6 KB] ================================================ FILE: stratosphere/loader/source/ldr_launch_record.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: stratosphere/loader/source/ldr_launch_record.hpp ================================================ [File too large to display: 850 B] ================================================ FILE: stratosphere/loader/source/ldr_loader_service.cpp ================================================ [File too large to display: 5.2 KB] ================================================ FILE: stratosphere/loader/source/ldr_loader_service.hpp ================================================ [File too large to display: 5.1 KB] ================================================ FILE: stratosphere/loader/source/ldr_main.cpp ================================================ [File too large to display: 5.8 KB] ================================================ FILE: stratosphere/loader/source/ldr_meta.cpp ================================================ [File too large to display: 18.7 KB] ================================================ FILE: stratosphere/loader/source/ldr_meta.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: stratosphere/loader/source/ldr_patcher.cpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: stratosphere/loader/source/ldr_patcher.hpp ================================================ [File too large to display: 983 B] ================================================ FILE: stratosphere/loader/source/ldr_process_creation.cpp ================================================ [File too large to display: 42.6 KB] ================================================ FILE: stratosphere/loader/source/ldr_process_creation.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/loader/source/ldr_ro_manager.cpp ================================================ [File too large to display: 5.5 KB] ================================================ FILE: stratosphere/loader/source/ldr_ro_manager.hpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/loader/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/memlet/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/memlet/memlet.json ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/memlet/source/memlet_main.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/memlet/source/memlet_service.cpp ================================================ [File too large to display: 2.4 KB] ================================================ FILE: stratosphere/memlet/source/memlet_service.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/memlet/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/ncm/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/ncm/ncm.json ================================================ [File too large to display: 3.5 KB] ================================================ FILE: stratosphere/ncm/source/ncm_main.cpp ================================================ [File too large to display: 10.6 KB] ================================================ FILE: stratosphere/ncm/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/pgl/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/pgl/pgl.json ================================================ [File too large to display: 2.7 KB] ================================================ FILE: stratosphere/pgl/source/pgl_main.cpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/pgl/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/pm/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/pm/pm.json ================================================ [File too large to display: 3.6 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_attributes.hpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_info.cpp ================================================ [File too large to display: 4.8 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_info.hpp ================================================ [File too large to display: 7.8 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_manager.cpp ================================================ [File too large to display: 19.9 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_manager.hpp ================================================ [File too large to display: 2.2 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_tracker.cpp ================================================ [File too large to display: 8.1 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_process_tracker.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_spec.cpp ================================================ [File too large to display: 25.8 KB] ================================================ FILE: stratosphere/pm/source/impl/pm_spec.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/pm/source/pm_boot_mode_service.cpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/pm/source/pm_boot_mode_service.hpp ================================================ [File too large to display: 994 B] ================================================ FILE: stratosphere/pm/source/pm_debug_monitor_service.cpp ================================================ [File too large to display: 3.7 KB] ================================================ FILE: stratosphere/pm/source/pm_debug_monitor_service.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/pm/source/pm_info_service.cpp ================================================ [File too large to display: 2.5 KB] ================================================ FILE: stratosphere/pm/source/pm_info_service.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/pm/source/pm_main.cpp ================================================ [File too large to display: 11.2 KB] ================================================ FILE: stratosphere/pm/source/pm_shell_service.cpp ================================================ [File too large to display: 3.3 KB] ================================================ FILE: stratosphere/pm/source/pm_shell_service.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/pm/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/ro/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/ro/ro.json ================================================ [File too large to display: 2.9 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_nro_utils.cpp ================================================ [File too large to display: 3.5 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_nro_utils.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_nrr_utils.cpp ================================================ [File too large to display: 16.4 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_nrr_utils.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_patcher.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_patcher.hpp ================================================ [File too large to display: 842 B] ================================================ FILE: stratosphere/ro/source/impl/ro_random.cpp ================================================ [File too large to display: 997 B] ================================================ FILE: stratosphere/ro/source/impl/ro_random.hpp ================================================ [File too large to display: 746 B] ================================================ FILE: stratosphere/ro/source/impl/ro_service_impl.cpp ================================================ [File too large to display: 26.9 KB] ================================================ FILE: stratosphere/ro/source/impl/ro_service_impl.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/ro/source/ro_debug_monitor_service.cpp ================================================ [File too large to display: 1.1 KB] ================================================ FILE: stratosphere/ro/source/ro_debug_monitor_service.hpp ================================================ [File too large to display: 971 B] ================================================ FILE: stratosphere/ro/source/ro_main.cpp ================================================ [File too large to display: 6.0 KB] ================================================ FILE: stratosphere/ro/source/ro_ro_service.cpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: stratosphere/ro/source/ro_ro_service.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: stratosphere/ro/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/sm/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/sm/sm.json ================================================ [File too large to display: 3.8 KB] ================================================ FILE: stratosphere/sm/source/impl/sm_service_manager.cpp ================================================ [File too large to display: 36.3 KB] ================================================ FILE: stratosphere/sm/source/impl/sm_service_manager.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/sm/source/sm_main.cpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: stratosphere/sm/source/sm_manager_service.hpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: stratosphere/sm/source/sm_tipc_server.cpp ================================================ [File too large to display: 3.0 KB] ================================================ FILE: stratosphere/sm/source/sm_tipc_server.hpp ================================================ [File too large to display: 768 B] ================================================ FILE: stratosphere/sm/source/sm_user_service.cpp ================================================ [File too large to display: 10.8 KB] ================================================ FILE: stratosphere/sm/source/sm_user_service.hpp ================================================ [File too large to display: 5.4 KB] ================================================ FILE: stratosphere/sm/source/sm_wait_list.hpp ================================================ [File too large to display: 755 B] ================================================ FILE: stratosphere/sm/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/spl/Makefile ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/spl/source/spl_crypto_service.hpp ================================================ [File too large to display: 3.1 KB] ================================================ FILE: stratosphere/spl/source/spl_deprecated_service.hpp ================================================ [File too large to display: 7.7 KB] ================================================ FILE: stratosphere/spl/source/spl_device_unique_data_service.hpp ================================================ [File too large to display: 1.8 KB] ================================================ FILE: stratosphere/spl/source/spl_es_service.hpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: stratosphere/spl/source/spl_fs_service.hpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: stratosphere/spl/source/spl_general_service.hpp ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/spl/source/spl_main.cpp ================================================ [File too large to display: 9.3 KB] ================================================ FILE: stratosphere/spl/source/spl_manu_service.hpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: stratosphere/spl/source/spl_random_service.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: stratosphere/spl/source/spl_secure_monitor_manager.cpp ================================================ [File too large to display: 9.8 KB] ================================================ FILE: stratosphere/spl/source/spl_secure_monitor_manager.hpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/spl/source/spl_ssl_service.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: stratosphere/spl/spl.json ================================================ [File too large to display: 2.3 KB] ================================================ FILE: stratosphere/spl/system_module.mk ================================================ [File too large to display: 5.0 KB] ================================================ FILE: stratosphere/stratosphere.mk ================================================ [File too large to display: 1.3 KB] ================================================ FILE: tests/Licensing/Catch2-LICENSE.txt ================================================ [File too large to display: 1.3 KB] ================================================ FILE: tests/TestFs/Makefile ================================================ [File too large to display: 2.3 KB] ================================================ FILE: tests/TestFs/source/test.cpp ================================================ [File too large to display: 51.8 KB] ================================================ FILE: tests/TestFs/unit_test.mk ================================================ [File too large to display: 5.9 KB] ================================================ FILE: tests/TestOsEvents/Makefile ================================================ [File too large to display: 2.3 KB] ================================================ FILE: tests/TestOsEvents/source/test.cpp ================================================ [File too large to display: 23.0 KB] ================================================ FILE: tests/TestOsEvents/unit_test.mk ================================================ [File too large to display: 5.9 KB] ================================================ FILE: tests/TestSocket/Makefile ================================================ [File too large to display: 2.3 KB] ================================================ FILE: tests/TestSocket/source/test.cpp ================================================ [File too large to display: 6.3 KB] ================================================ FILE: tests/TestSocket/unit_test.mk ================================================ [File too large to display: 5.9 KB] ================================================ FILE: tests/TestStack/Makefile ================================================ [File too large to display: 2.3 KB] ================================================ FILE: tests/TestStack/source/test.cpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: tests/TestStack/unit_test.mk ================================================ [File too large to display: 5.9 KB] ================================================ FILE: tests/TestSvc/Makefile ================================================ [File too large to display: 4.0 KB] ================================================ FILE: tests/TestSvc/TestSvc.json ================================================ [File too large to display: 5.4 KB] ================================================ FILE: tests/TestSvc/TestSvc.npdm.json ================================================ [File too large to display: 5.8 KB] ================================================ FILE: tests/TestSvc/source/doctest.h ================================================ [File too large to display: 292.4 KB] ================================================ FILE: tests/TestSvc/source/test_main.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: tests/TestSvc/source/test_preemption_priority.cpp ================================================ [File too large to display: 4.1 KB] ================================================ FILE: tests/TestSvc/source/test_set_heap_size.cpp ================================================ [File too large to display: 6.1 KB] ================================================ FILE: tests/TestSvc/source/test_set_memory_permission.cpp ================================================ [File too large to display: 8.9 KB] ================================================ FILE: tests/TestSvc/source/test_sleep_thread.cpp ================================================ [File too large to display: 10.5 KB] ================================================ FILE: tests/TestSvc/source/test_thread_creation.arch.arm64.s ================================================ [File too large to display: 1.6 KB] ================================================ FILE: tests/TestSvc/source/test_thread_creation.cpp ================================================ [File too large to display: 2.6 KB] ================================================ FILE: tests/TestSvc/source/test_thread_pinning.cpp ================================================ [File too large to display: 946 B] ================================================ FILE: tests/TestSvc/source/util_check_memory.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: tests/TestSvc/source/util_common.hpp ================================================ [File too large to display: 3.6 KB] ================================================ FILE: tests/TestSvc/source/util_scoped_heap.hpp ================================================ [File too large to display: 1.5 KB] ================================================ FILE: tests/TestSvc/source/util_test_framework.hpp ================================================ [File too large to display: 891 B] ================================================ FILE: thermosphere/.gitignore ================================================ [File too large to display: 4 B] ================================================ FILE: thermosphere/Makefile ================================================ [File too large to display: 5.6 KB] ================================================ FILE: thermosphere/README.md ================================================ [File too large to display: 141 B] ================================================ FILE: thermosphere/linker.ld ================================================ [File too large to display: 1021 B] ================================================ FILE: thermosphere/linker.specs ================================================ [File too large to display: 146 B] ================================================ FILE: thermosphere/src/exceptions.c ================================================ [File too large to display: 2.9 KB] ================================================ FILE: thermosphere/src/exceptions.h ================================================ [File too large to display: 6.7 KB] ================================================ FILE: thermosphere/src/main.c ================================================ [File too large to display: 4.0 KB] ================================================ FILE: thermosphere/src/regs.h ================================================ [File too large to display: 2.1 KB] ================================================ FILE: thermosphere/src/start.s ================================================ [File too large to display: 7.6 KB] ================================================ FILE: troposphere/Makefile ================================================ [File too large to display: 218 B] ================================================ FILE: troposphere/daybreak/Makefile ================================================ [File too large to display: 9.0 KB] ================================================ FILE: troposphere/daybreak/nanovg/.gitignore ================================================ [File too large to display: 766 B] ================================================ FILE: troposphere/daybreak/nanovg/.gitrepo ================================================ [File too large to display: 423 B] ================================================ FILE: troposphere/daybreak/nanovg/LICENSE ================================================ [File too large to display: 881 B] ================================================ FILE: troposphere/daybreak/nanovg/Makefile ================================================ [File too large to display: 6.7 KB] ================================================ FILE: troposphere/daybreak/nanovg/README.md ================================================ [File too large to display: 730 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/dk_renderer.hpp ================================================ [File too large to display: 6.1 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/fontstash.h ================================================ [File too large to display: 52.5 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CApplication.h ================================================ [File too large to display: 923 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CCmdMemRing.h ================================================ [File too large to display: 1.9 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CDescriptorSet.h ================================================ [File too large to display: 2.4 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CExternalImage.h ================================================ [File too large to display: 867 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CIntrusiveList.h ================================================ [File too large to display: 2.9 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CIntrusiveTree.h ================================================ [File too large to display: 6.2 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CMemPool.h ================================================ [File too large to display: 3.5 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/CShader.h ================================================ [File too large to display: 573 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/FileLoader.h ================================================ [File too large to display: 298 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/framework/common.h ================================================ [File too large to display: 197 B] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/nanovg_gl_utils.h ================================================ [File too large to display: 4.9 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/stb_image.h ================================================ [File too large to display: 222.1 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg/stb_truetype.h ================================================ [File too large to display: 191.1 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg.h ================================================ [File too large to display: 28.3 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg_dk.h ================================================ [File too large to display: 16.8 KB] ================================================ FILE: troposphere/daybreak/nanovg/include/nanovg_gl.h ================================================ [File too large to display: 51.0 KB] ================================================ FILE: troposphere/daybreak/nanovg/shaders/fill_aa_fsh.glsl ================================================ [File too large to display: 2.3 KB] ================================================ FILE: troposphere/daybreak/nanovg/shaders/fill_fsh.glsl ================================================ [File too large to display: 2.1 KB] ================================================ FILE: troposphere/daybreak/nanovg/shaders/fill_vsh.glsl ================================================ [File too large to display: 391 B] ================================================ FILE: troposphere/daybreak/nanovg/source/dk_renderer.cpp ================================================ [File too large to display: 22.0 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/CApplication.cpp ================================================ [File too large to display: 2.0 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/CExternalImage.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/CIntrusiveTree.cpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/CMemPool.cpp ================================================ [File too large to display: 4.5 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/CShader.cpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/FileLoader.cpp ================================================ [File too large to display: 590 B] ================================================ FILE: troposphere/daybreak/nanovg/source/framework/LICENSE ================================================ [File too large to display: 848 B] ================================================ FILE: troposphere/daybreak/nanovg/source/nanovg.c ================================================ [File too large to display: 75.4 KB] ================================================ FILE: troposphere/daybreak/source/ams_su.c ================================================ [File too large to display: 4.4 KB] ================================================ FILE: troposphere/daybreak/source/ams_su.h ================================================ [File too large to display: 1.6 KB] ================================================ FILE: troposphere/daybreak/source/assert.hpp ================================================ [File too large to display: 781 B] ================================================ FILE: troposphere/daybreak/source/main.cpp ================================================ [File too large to display: 9.6 KB] ================================================ FILE: troposphere/daybreak/source/service_guard.h ================================================ [File too large to display: 1.4 KB] ================================================ FILE: troposphere/daybreak/source/ui.cpp ================================================ [File too large to display: 52.4 KB] ================================================ FILE: troposphere/daybreak/source/ui.hpp ================================================ [File too large to display: 9.4 KB] ================================================ FILE: troposphere/daybreak/source/ui_util.cpp ================================================ [File too large to display: 8.3 KB] ================================================ FILE: troposphere/daybreak/source/ui_util.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: troposphere/haze/Makefile ================================================ [File too large to display: 8.8 KB] ================================================ FILE: troposphere/haze/include/haze/assert.hpp ================================================ [File too large to display: 1.3 KB] ================================================ FILE: troposphere/haze/include/haze/async_usb_server.hpp ================================================ [File too large to display: 1.6 KB] ================================================ FILE: troposphere/haze/include/haze/common.hpp ================================================ [File too large to display: 1.2 KB] ================================================ FILE: troposphere/haze/include/haze/console_main_loop.hpp ================================================ [File too large to display: 10.2 KB] ================================================ FILE: troposphere/haze/include/haze/device_properties.hpp ================================================ [File too large to display: 780 B] ================================================ FILE: troposphere/haze/include/haze/event_reactor.hpp ================================================ [File too large to display: 1.9 KB] ================================================ FILE: troposphere/haze/include/haze/file_system_proxy.hpp ================================================ [File too large to display: 5.0 KB] ================================================ FILE: troposphere/haze/include/haze/ptp.hpp ================================================ [File too large to display: 28.4 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_data_builder.hpp ================================================ [File too large to display: 6.1 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_data_parser.hpp ================================================ [File too large to display: 3.9 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_object_database.hpp ================================================ [File too large to display: 4.3 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_object_heap.hpp ================================================ [File too large to display: 4.9 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_responder.hpp ================================================ [File too large to display: 3.4 KB] ================================================ FILE: troposphere/haze/include/haze/ptp_responder_types.hpp ================================================ [File too large to display: 6.5 KB] ================================================ FILE: troposphere/haze/include/haze/results.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: troposphere/haze/include/haze/usb_session.hpp ================================================ [File too large to display: 1.7 KB] ================================================ FILE: troposphere/haze/include/haze.hpp ================================================ [File too large to display: 989 B] ================================================ FILE: troposphere/haze/source/async_usb_server.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: troposphere/haze/source/console_fsh.glsl ================================================ [File too large to display: 376 B] ================================================ FILE: troposphere/haze/source/console_vsh.glsl ================================================ [File too large to display: 979 B] ================================================ FILE: troposphere/haze/source/device_properties.cpp ================================================ [File too large to display: 1.4 KB] ================================================ FILE: troposphere/haze/source/event_reactor.cpp ================================================ [File too large to display: 2.7 KB] ================================================ FILE: troposphere/haze/source/gpu_console.c ================================================ [File too large to display: 18.2 KB] ================================================ FILE: troposphere/haze/source/main.cpp ================================================ [File too large to display: 967 B] ================================================ FILE: troposphere/haze/source/ptp_object_database.cpp ================================================ [File too large to display: 5.3 KB] ================================================ FILE: troposphere/haze/source/ptp_object_heap.cpp ================================================ [File too large to display: 2.1 KB] ================================================ FILE: troposphere/haze/source/ptp_responder.cpp ================================================ [File too large to display: 8.0 KB] ================================================ FILE: troposphere/haze/source/ptp_responder_android_operations.cpp ================================================ [File too large to display: 8.1 KB] ================================================ FILE: troposphere/haze/source/ptp_responder_mtp_operations.cpp ================================================ [File too large to display: 16.9 KB] ================================================ FILE: troposphere/haze/source/ptp_responder_ptp_operations.cpp ================================================ [File too large to display: 20.9 KB] ================================================ FILE: troposphere/haze/source/usb_session.cpp ================================================ [File too large to display: 12.6 KB] ================================================ FILE: troposphere/reboot_to_payload/Makefile ================================================ [File too large to display: 6.8 KB] ================================================ FILE: troposphere/reboot_to_payload/source/ams_bpc.c ================================================ [File too large to display: 1.3 KB] ================================================ FILE: troposphere/reboot_to_payload/source/ams_bpc.h ================================================ [File too large to display: 891 B] ================================================ FILE: troposphere/reboot_to_payload/source/main.c ================================================ [File too large to display: 2.3 KB] ================================================ FILE: troposphere/reboot_to_payload/source/service_guard.h ================================================ [File too large to display: 1.4 KB] ================================================ FILE: utilities/erpt.py ================================================ [File too large to display: 16.4 KB] ================================================ FILE: utilities/insert_splash_screen.py ================================================ [File too large to display: 1.3 KB] ================================================ FILE: utilities/nxo64.py ================================================ [File too large to display: 38.4 KB]